From 00b9de9c249f51f09c19aa41cbbb3e3eb4eea807 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 24 Jun 2009 17:53:33 +0900 Subject: serial: sh-sci: Move SCSCR_INIT in to platform data. This moves all of the SCSCR_INIT definitions in to the platform data, for future consolidation. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 7 ++++++- drivers/serial/sh-sci.h | 32 -------------------------------- 2 files changed, 6 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 66f52674ca0c..3a13e58e9c5d 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -79,6 +79,9 @@ struct sci_port { struct timer_list break_timer; int break_flag; + /* SCSCR initialization */ + unsigned int scscr; + #ifdef CONFIG_HAVE_CLK /* Interface clock */ struct clk *iclk; @@ -928,6 +931,7 @@ static void sci_shutdown(struct uart_port *port) static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct sci_port *s = to_sci_port(port); unsigned int status, baud, smr_val; int t = -1; @@ -972,7 +976,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_init_pins(port, termios->c_cflag); sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0); - sci_out(port, SCSCR, SCSCR_INIT(port)); + sci_out(port, SCSCR, s->scscr); if ((termios->c_cflag & CREAD) != 0) sci_start_rx(port, 0); @@ -1097,6 +1101,7 @@ static void __devinit sci_init_single(struct platform_device *dev, sci_port->port.mapbase = p->mapbase; sci_port->port.membase = p->membase; + sci_port->scscr = p->scscr; sci_port->port.irq = p->irqs[SCIx_TXI_IRQ]; sci_port->port.flags = p->flags; sci_port->port.dev = &dev->dev; diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 38072c15b845..4aa0ac8e67dd 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -15,7 +15,6 @@ defined(CONFIG_CPU_SUBTYPE_SH7709) # define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ # define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) # define SCIF0 0xA4400000 # define SCIF2 0xA4410000 @@ -23,15 +22,8 @@ # define IRDA_SCIF SCIF0 # define SCPCR 0xA4000116 # define SCPDR 0xA4000136 - -/* Set the clock source, - * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input - * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output - */ -# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) -# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define PORT_PTCR 0xA405011EUL # define PORT_PVCR 0xA4050122UL # define SCIF_ORER 0x0200 /* overrun error bit */ @@ -39,7 +31,6 @@ # define SCSPTR1 0xFFE0001C /* 8 bit SCIF */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ @@ -49,39 +40,31 @@ # define SCSPTR1 0xffe0001c /* 8 bit SCI */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ - 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ - 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) #elif defined(CONFIG_CPU_SUBTYPE_SH7760) # define SCSPTR0 0xfe600024 /* 16 bit SCIF */ # define SCSPTR1 0xfe610024 /* 16 bit SCIF */ # define SCSPTR2 0xfe620024 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) # define SCSPTR0 0xA4400000 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ # define PACR 0xa4050100 # define PBCR 0xa4050102 -# define SCSCR_INIT(port) 0x3B #elif defined(CONFIG_CPU_SUBTYPE_SH7343) # define SCSPTR0 0xffe00010 /* 16 bit SCIF */ # define SCSPTR1 0xffe10010 /* 16 bit SCIF */ # define SCSPTR2 0xffe20010 /* 16 bit SCIF */ # define SCSPTR3 0xffe30010 /* 16 bit SCIF */ -# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7722) # define PADR 0xA4050120 # define PSDR 0xA405013e # define PWDR 0xA4050166 # define PSCR 0xA405011E # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7366) # define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */ # define SCSPTR0 SCPDR0 # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7723) # define SCSPTR0 0xa4050160 # define SCSPTR1 0xa405013e @@ -90,45 +73,34 @@ # define SCSPTR4 0xa4050128 # define SCSPTR5 0xa4050128 # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7724) # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) -# define SCIF_BASE_ADDR 0x01030000 -# define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR # define SCIF_PTR2_OFFS 0x0000020 # define SCIF_LSR2_OFFS 0x0000024 # define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */ # define SCLSR2 ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_H83007) || defined(CONFIG_H83068) -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) #elif defined(CONFIG_H8S2678) -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) #elif defined(CONFIG_CPU_SUBTYPE_SH7763) # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ # define SCSPTR1 0xffe08024 /* 16 bit SCIF */ # define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7770) # define SCSPTR0 0xff923020 /* 16 bit SCIF */ # define SCSPTR1 0xff924020 /* 16 bit SCIF */ # define SCSPTR2 0xff925020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7780) # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ # define SCSPTR1 0xffe10024 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* Overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SH7786) # define SCSPTR0 0xffea0024 /* 16 bit SCIF */ @@ -138,7 +110,6 @@ # define SCSPTR4 0xffee0024 /* 16 bit SCIF */ # define SCSPTR5 0xffef0024 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* Overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ defined(CONFIG_CPU_SUBTYPE_SH7203) || \ defined(CONFIG_CPU_SUBTYPE_SH7206) || \ @@ -153,20 +124,17 @@ # define SCSPTR6 0xfffeB020 /* 16 bit SCIF */ # define SCSPTR7 0xfffeB820 /* 16 bit SCIF */ # endif -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SH7619) # define SCSPTR0 0xf8400020 /* 16 bit SCIF */ # define SCSPTR1 0xf8410020 /* 16 bit SCIF */ # define SCSPTR2 0xf8420020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_CPU_SUBTYPE_SHX3) # define SCSPTR0 0xffc30020 /* 16 bit SCIF */ # define SCSPTR1 0xffc40020 /* 16 bit SCIF */ # define SCSPTR2 0xffc50020 /* 16 bit SCIF */ # define SCSPTR3 0xffc60020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* Overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #else # error CPU subtype not defined #endif -- cgit v1.2.3 From 26c92f3728d738aaa7e4859d5581323cd68096dd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 24 Jun 2009 18:23:52 +0900 Subject: serial: sh-sci: Move SCBRR calculation algo in to platform data. This permits each port to select its own SCBRR calculation algorithm, rather than having it all ifdef'ed in the header. There are presently only 5 different variations that all parts fall under. Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/sh2/setup-sh7619.c | 3 ++ arch/sh/kernel/cpu/sh2a/setup-mxg.c | 1 + arch/sh/kernel/cpu/sh2a/setup-sh7201.c | 8 +++++ arch/sh/kernel/cpu/sh2a/setup-sh7203.c | 4 +++ arch/sh/kernel/cpu/sh2a/setup-sh7206.c | 4 +++ arch/sh/kernel/cpu/sh3/setup-sh7705.c | 2 ++ arch/sh/kernel/cpu/sh3/setup-sh770x.c | 3 ++ arch/sh/kernel/cpu/sh3/setup-sh7710.c | 2 ++ arch/sh/kernel/cpu/sh3/setup-sh7720.c | 2 ++ arch/sh/kernel/cpu/sh4/setup-sh4-202.c | 1 + arch/sh/kernel/cpu/sh4/setup-sh7750.c | 2 ++ arch/sh/kernel/cpu/sh4/setup-sh7760.c | 4 +++ arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 4 +++ arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 1 + arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 3 ++ arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 6 ++++ arch/sh/kernel/cpu/sh4a/setup-sh7724.c | 6 ++++ arch/sh/kernel/cpu/sh4a/setup-sh7763.c | 3 ++ arch/sh/kernel/cpu/sh4a/setup-sh7770.c | 10 ++++++ arch/sh/kernel/cpu/sh4a/setup-sh7780.c | 2 ++ arch/sh/kernel/cpu/sh4a/setup-sh7785.c | 6 ++++ arch/sh/kernel/cpu/sh4a/setup-sh7786.c | 6 ++++ arch/sh/kernel/cpu/sh4a/setup-shx3.c | 4 +++ arch/sh/kernel/cpu/sh5/setup-sh5.c | 1 + drivers/serial/sh-sci.c | 27 ++++++++++++++-- drivers/serial/sh-sci.h | 56 ---------------------------------- include/linux/serial_sci.h | 9 ++++++ 27 files changed, 122 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c index ace016b17036..86acede777b9 100644 --- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -64,18 +64,21 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xf8400000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 88, 88, 88, 88 }, }, { .mapbase = 0xf8410000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 92, 92, 92, 92 }, }, { .mapbase = 0xf8420000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 96, 96, 96, 96 }, }, { diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c index 7ec658ce14f8..b2c3bcc01190 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c +++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c @@ -212,6 +212,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xff804000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 220, 220, 220, 220 }, }, { diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c index 2a2ac222f9c7..8d44917ce50b 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c @@ -182,48 +182,56 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xfffe8000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 180, 180, 180, 180 } }, { .mapbase = 0xfffe8800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 184, 184, 184, 184 } }, { .mapbase = 0xfffe9000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 188, 188, 188, 188 } }, { .mapbase = 0xfffe9800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 192, 192, 192, 192 } }, { .mapbase = 0xfffea000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 196, 196, 196, 196 } }, { .mapbase = 0xfffea800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 200, 200, 200, 200 } }, { .mapbase = 0xfffeb000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 204, 204, 204, 204 } }, { .mapbase = 0xfffeb800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 208, 208, 208, 208 } }, { diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c index 2c9f3ababfd7..a78d2a219f3b 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c @@ -178,24 +178,28 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xfffe8000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 192, 192, 192, 192 }, }, { .mapbase = 0xfffe8800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 196, 196, 196, 196 }, }, { .mapbase = 0xfffe9000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 200, 200, 200, 200 }, }, { .mapbase = 0xfffe9800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 204, 204, 204, 204 }, }, { diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c index 5a47987f3902..68b93ed44cc2 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c @@ -138,24 +138,28 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xfffe8000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 240, 240, 240, 240 }, }, { .mapbase = 0xfffe8800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 244, 244, 244, 244 }, }, { .mapbase = 0xfffe9000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 248, 248, 248, 248 }, }, { .mapbase = 0xfffe9800, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 252, 252, 252, 252 }, }, { diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c index 28de53b281f3..27d03d836056 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c @@ -73,12 +73,14 @@ static struct plat_sci_port sci_platform_data[] = { .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TIE | SCSCR_RIE | SCSCR_TE | SCSCR_RE | SCSCR_CKE1 | SCSCR_CKE0, + .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIF, .irqs = { 56, 56, 56 }, }, { .mapbase = 0xa4400000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TIE | SCSCR_RIE | SCSCR_TE | SCSCR_RE, + .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIF, .irqs = { 52, 52, 52 }, }, { diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c index 50ac42836dc7..83c9a5a39685 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c @@ -111,6 +111,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xfffffe80, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TE | SCSCR_RE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCI, .irqs = { 23, 23, 23, 0 }, }, @@ -121,6 +122,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4000150, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TE | SCSCR_RE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 56, 56, 56, 56 }, }, @@ -131,6 +133,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4000140, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TE | SCSCR_RE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_IRDA, .irqs = { 52, 52, 52, 52 }, }, diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c index 007627ecb7c8..9a60ffd34a9f 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c @@ -102,6 +102,7 @@ static struct plat_sci_port sci_platform_data[] = { .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TE | SCSCR_RE | SCSCR_REIE | SCSCR_CKE1 | SCSCR_CKE0, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 52, 52, 52, 52 }, }, { @@ -109,6 +110,7 @@ static struct plat_sci_port sci_platform_data[] = { .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TE | SCSCR_RE | SCSCR_REIE | SCSCR_CKE1 | SCSCR_CKE0, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 56, 56, 56, 56 }, }, { diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c index 1fc3d9089199..48d50a65db32 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c @@ -53,12 +53,14 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4430000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIF, .irqs = { 80, 80, 80, 80 }, }, { .mapbase = 0xa4438000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIF, .irqs = { 81, 81, 81, 81 }, }, { diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c index 9aa6fa3ca4e6..ec2104b49ef7 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c @@ -20,6 +20,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe80000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 40, 41, 43, 42 }, }, { diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index 2159c439dce9..51a945e0d72c 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -41,6 +41,7 @@ static struct plat_sci_port sci_platform_data = { .flags = UPF_BOOT_AUTOCONF, .type = PORT_SCI, .scscr = SCSCR_TE | SCSCR_RE, + .scbrr_algo_id = SCBRR_ALGO_2, .irqs = { 23, 23, 23, 0 }, }; @@ -55,6 +56,7 @@ static struct plat_sci_port scif_platform_data = { .mapbase = 0xffe80000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_TE | SCSCR_RE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 40, 40, 40, 40 }, }; diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 74b5e994724d..cee660fe1d90 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c @@ -131,24 +131,28 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xfe600000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 52, 53, 55, 54 }, }, { .mapbase = 0xfe610000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 72, 73, 75, 74 }, }, { .mapbase = 0xfe620000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 76, 77, 79, 78 }, }, { .mapbase = 0xfe480000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCI, .irqs = { 80, 81, 82, 0 }, }, { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c index 09fb5814d925..fbae06b1c98d 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c @@ -270,6 +270,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 80, 80, 80, 80 }, .clk = "scif0", @@ -277,6 +278,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe10000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 81, 81, 81, 81 }, .clk = "scif1", @@ -284,6 +286,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe20000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 82, 82, 82, 82 }, .clk = "scif2", @@ -291,6 +294,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe30000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 83, 83, 83, 83 }, .clk = "scif3", diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c index 307777cf04cc..d4ee429032b1 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c @@ -281,6 +281,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 80, 80, 80, 80 }, .clk = "scif0", diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index ffc69bc95932..f7b0551bf104 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -306,6 +306,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 80, 80, 80, 80 }, .clk = "scif0", @@ -313,6 +314,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe10000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 81, 81, 81, 81 }, .clk = "scif1", @@ -320,6 +322,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe20000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 82, 82, 82, 82 }, .clk = "scif2", diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index 6ce331a8f1bd..bb4837b9dcf4 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -322,6 +322,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 80, 80, 80, 80 }, .clk = "scif0", @@ -329,6 +330,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe10000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 81, 81, 81, 81 }, .clk = "scif1", @@ -336,6 +338,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe20000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 82, 82, 82, 82 }, .clk = "scif2", @@ -343,6 +346,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4e30000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_3, .type = PORT_SCIFA, .irqs = { 56, 56, 56, 56 }, .clk = "scif3", @@ -350,6 +354,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4e40000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_3, .type = PORT_SCIFA, .irqs = { 88, 88, 88, 88 }, .clk = "scif4", @@ -357,6 +362,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4e50000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_3, .type = PORT_SCIFA, .irqs = { 109, 109, 109, 109 }, .clk = "scif5", diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index 4bf03c1ec8d6..c934b78e5658 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -29,6 +29,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 80, 80, 80, 80 }, .clk = "scif0", @@ -36,6 +37,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe10000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 81, 81, 81, 81 }, .clk = "scif1", @@ -43,6 +45,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe20000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 82, 82, 82, 82 }, .clk = "scif2", @@ -50,6 +53,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4e30000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_3, .type = PORT_SCIFA, .irqs = { 56, 56, 56, 56 }, .clk = "scif3", @@ -57,6 +61,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4e40000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_3, .type = PORT_SCIFA, .irqs = { 88, 88, 88, 88 }, .clk = "scif4", @@ -64,6 +69,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xa4e50000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_3, .type = PORT_SCIFA, .irqs = { 109, 109, 109, 109 }, .clk = "scif5", diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c index 76339c6da01e..ab02771ee888 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c @@ -41,18 +41,21 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 40, 40, 40, 40 }, }, { .mapbase = 0xffe08000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 76, 76, 76, 76 }, }, { .mapbase = 0xffe10000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 104, 104, 104, 104 }, }, { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c index 07a41ff20504..746f4fb9ccf0 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c @@ -19,60 +19,70 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xff923000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 61, 61, 61, 61 }, }, { .mapbase = 0xff924000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 62, 62, 62, 62 }, }, { .mapbase = 0xff925000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 63, 63, 63, 63 }, }, { .mapbase = 0xff926000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 64, 64, 64, 64 }, }, { .mapbase = 0xff927000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 65, 65, 65, 65 }, }, { .mapbase = 0xff928000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 66, 66, 66, 66 }, }, { .mapbase = 0xff929000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 67, 67, 67, 67 }, }, { .mapbase = 0xff92a000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 68, 68, 68, 68 }, }, { .mapbase = 0xff92b000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 69, 69, 69, 69 }, }, { .mapbase = 0xff92c000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 70, 70, 70, 70 }, }, { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index 2b355b67a33d..bcd411eb9cb0 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -221,12 +221,14 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffe00000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 40, 40, 40, 40 }, }, { .mapbase = 0xffe10000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 76, 76, 76, 76 }, }, { diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c index acd4b1d1b813..3ae2e2071009 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -203,6 +203,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffea0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 40, 40, 40, 40 }, .clk = "scif_fck", @@ -210,6 +211,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffeb0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 44, 44, 44, 44 }, .clk = "scif_fck", @@ -217,6 +219,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffec0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 60, 60, 60, 60 }, .clk = "scif_fck", @@ -224,6 +227,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffed0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 61, 61, 61, 61 }, .clk = "scif_fck", @@ -231,6 +235,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffee0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 62, 62, 62, 62 }, .clk = "scif_fck", @@ -238,6 +243,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffef0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 63, 63, 63, 63 }, .clk = "scif_fck", diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c index 347ce88de570..8b7ea4bd965d 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c @@ -28,6 +28,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffea0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 40, 41, 43, 42 }, }, @@ -38,30 +39,35 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffeb0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 44, 44, 44, 44 }, }, { .mapbase = 0xffec0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 50, 50, 50, 50 }, }, { .mapbase = 0xffed0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 51, 51, 51, 51 }, }, { .mapbase = 0xffee0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 52, 52, 52, 52 }, }, { .mapbase = 0xffef0000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1, + .scbrr_algo_id = SCBRR_ALGO_1, .type = PORT_SCIF, .irqs = { 53, 53, 53, 53 }, }, { diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c index eef94934f542..4a26cc304139 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c @@ -20,24 +20,28 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = 0xffc30000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 40, 41, 43, 42 }, }, { .mapbase = 0xffc40000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 44, 45, 47, 46 }, }, { .mapbase = 0xffc50000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 48, 49, 51, 50 }, }, { .mapbase = 0xffc60000, .flags = UPF_BOOT_AUTOCONF, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 52, 53, 55, 54 }, }, { diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c index 26fa10c560de..72aa86ec7446 100644 --- a/arch/sh/kernel/cpu/sh5/setup-sh5.c +++ b/arch/sh/kernel/cpu/sh5/setup-sh5.c @@ -21,6 +21,7 @@ static struct plat_sci_port sci_platform_data[] = { .mapbase = PHYS_PERIPHERAL_BLOCK + 0x01030000, .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .scbrr_algo_id = SCBRR_ALGO_2, .type = PORT_SCIF, .irqs = { 39, 40, 42, 0 }, }, { diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 3a13e58e9c5d..386fb878680c 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -82,6 +82,9 @@ struct sci_port { /* SCSCR initialization */ unsigned int scscr; + /* SCBRR calculation algo */ + unsigned int scbrr_algo_id; + #ifdef CONFIG_HAVE_CLK /* Interface clock */ struct clk *iclk; @@ -928,6 +931,27 @@ static void sci_shutdown(struct uart_port *port) s->disable(port); } +static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, + unsigned long freq) +{ + switch (algo_id) { + case SCBRR_ALGO_1: + return ((freq + 16 * bps) / (16 * bps) - 1); + case SCBRR_ALGO_2: + return ((freq + 16 * bps) / (32 * bps) - 1); + case SCBRR_ALGO_3: + return (((freq * 2) + 16 * bps) / (16 * bps) - 1); + case SCBRR_ALGO_4: + return (((freq * 2) + 16 * bps) / (32 * bps) - 1); + case SCBRR_ALGO_5: + return (((freq * 1000 / 32) / bps) - 1); + } + + /* Warn, but use a safe default */ + WARN_ON(1); + return ((freq + 16 * bps) / (32 * bps) - 1); +} + static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { @@ -937,7 +961,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); if (likely(baud)) - t = SCBRR_VALUE(baud, port->uartclk); + t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk); do { status = sci_in(port, SCxSR); @@ -1108,7 +1132,6 @@ static void __devinit sci_init_single(struct platform_device *dev, sci_port->type = sci_port->port.type = p->type; memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); - } #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 4aa0ac8e67dd..81104777a0a6 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -713,59 +713,3 @@ static inline int sci_rxd_in(struct uart_port *port) return 1; } #endif - -/* - * Values for the BitRate Register (SCBRR) - * - * The values are actually divisors for a frequency which can - * be internal to the SH3 (14.7456MHz) or derived from an external - * clock source. This driver assumes the internal clock is used; - * to support using an external clock source, config options or - * possibly command-line options would need to be added. - * - * Also, to support speeds below 2400 (why?) the lower 2 bits of - * the SCSMR register would also need to be set to non-zero values. - * - * -- Greg Banks 27Feb2000 - * - * Answer: The SCBRR register is only eight bits, and the value in - * it gets larger with lower baud rates. At around 2400 (depending on - * the peripherial module clock) you run out of bits. However the - * lower two bits of SCSMR allow the module clock to be divided down, - * scaling the value which is needed in SCBRR. - * - * -- Stuart Menefy - 23 May 2000 - * - * I meant, why would anyone bother with bitrates below 2400. - * - * -- Greg Banks - 7Jul2000 - * - * You "speedist"! How will I use my 110bps ASR-33 teletype with paper - * tape reader as a console! - * - * -- Mitch Davis - 15 Jul 2000 - */ - -#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) -#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ - defined(CONFIG_CPU_SUBTYPE_SH7724) -static inline int scbrr_calc(struct uart_port *port, int bps, int clk) -{ - if (port->type == PORT_SCIF) - return (clk+16*bps)/(32*bps)-1; - else - return ((clk*2)+16*bps)/(16*bps)-1; -} -#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk) -#elif defined(__H8300H__) || defined(__H8300S__) -#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1) -#else /* Generic SH */ -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) -#endif diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index f722a2275add..ff856b5bd276 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -7,6 +7,14 @@ * Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts) */ +enum { + SCBRR_ALGO_1, /* ((clk + 16 * bps) / (16 * bps) - 1) */ + SCBRR_ALGO_2, /* ((clk + 16 * bps) / (32 * bps) - 1) */ + SCBRR_ALGO_3, /* (((clk * 2) + 16 * bps) / (16 * bps) - 1) */ + SCBRR_ALGO_4, /* (((clk * 2) + 16 * bps) / (32 * bps) - 1) */ + SCBRR_ALGO_5, /* (((clk * 1000 / 32) / bps) - 1) */ +}; + #define SCSCR_TIE (1 << 7) #define SCSCR_RIE (1 << 6) #define SCSCR_TE (1 << 5) @@ -36,6 +44,7 @@ struct plat_sci_port { upf_t flags; /* UPF_* flags */ char *clk; /* clock string */ + unsigned int scbrr_algo_id; /* SCBRR calculation algo */ unsigned int scscr; /* SCSCR initialization */ }; -- cgit v1.2.3 From 706622c920232bc79ca20eaca252d3eb9103ae96 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 24 Jun 2009 19:40:54 +0900 Subject: serial: sh-sci: Kill off unused register accessors. Several of these registers are defined but never used, kill them off in the interest of increased sanity. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 81104777a0a6..5366e780aaeb 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -82,7 +82,6 @@ # define SCIF_PTR2_OFFS 0x0000020 # define SCIF_LSR2_OFFS 0x0000024 # define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */ -# define SCLSR2 ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */ #elif defined(CONFIG_H83007) || defined(CONFIG_H83068) # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) #elif defined(CONFIG_H8S2678) @@ -367,8 +366,6 @@ SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) SCIF_FNS(SCSCR, 0x08, 16) -SCIF_FNS(SCTDSR, 0x0c, 8) -SCIF_FNS(SCFER, 0x10, 16) SCIF_FNS(SCxSR, 0x14, 16) SCIF_FNS(SCFCR, 0x18, 16) SCIF_FNS(SCFDR, 0x1c, 16) @@ -384,8 +381,6 @@ SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8) SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16) SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8) SCIx_FNS(SCSPTR, 0, 0, 0, 0) -SCIF_FNS(SCTDSR, 0x0c, 8) -SCIF_FNS(SCFER, 0x10, 16) SCIF_FNS(SCFCR, 0x18, 16) SCIF_FNS(SCFDR, 0x1c, 16) SCIF_FNS(SCLSR, 0x24, 16) @@ -411,7 +406,6 @@ SCIF_FNS(SCLSR, 0, 0, 0x28, 16) #elif defined(CONFIG_CPU_SUBTYPE_SH7763) SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) -SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) -- cgit v1.2.3 From 8e6986149129acc6528a7231350c31ce3e3dadc5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 24 Jun 2009 19:44:32 +0900 Subject: serial: sh-sci: Convert from old SCSR control flags to common defines. Many of these flags were duplicated, and as we now need this visibility to set them from the platform code, we can just use the linux/serial_sci.h variants instead. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 22 +++++++++++----------- drivers/serial/sh-sci.h | 26 -------------------------- 2 files changed, 11 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 386fb878680c..403b01b382e2 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -376,9 +376,9 @@ static void sci_transmit_chars(struct uart_port *port) if (!(status & SCxSR_TDxE(port))) { ctrl = sci_in(port, SCSCR); if (uart_circ_empty(xmit)) - ctrl &= ~SCI_CTRL_FLAGS_TIE; + ctrl &= ~SCSCR_TIE; else - ctrl |= SCI_CTRL_FLAGS_TIE; + ctrl |= SCSCR_TIE; sci_out(port, SCSCR, ctrl); return; } @@ -420,7 +420,7 @@ static void sci_transmit_chars(struct uart_port *port) sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); } - ctrl |= SCI_CTRL_FLAGS_TIE; + ctrl |= SCSCR_TIE; sci_out(port, SCSCR, ctrl); } } @@ -721,16 +721,16 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) scr_status = sci_in(port, SCSCR); /* Tx Interrupt */ - if ((ssr_status & 0x0020) && (scr_status & SCI_CTRL_FLAGS_TIE)) + if ((ssr_status & 0x0020) && (scr_status & SCSCR_TIE)) ret = sci_tx_interrupt(irq, ptr); /* Rx Interrupt */ - if ((ssr_status & 0x0002) && (scr_status & SCI_CTRL_FLAGS_RIE)) + if ((ssr_status & 0x0002) && (scr_status & SCSCR_RIE)) ret = sci_rx_interrupt(irq, ptr); /* Error Interrupt */ - if ((ssr_status & 0x0080) && (scr_status & SCI_CTRL_FLAGS_REIE)) + if ((ssr_status & 0x0080) && (scr_status & SCSCR_REIE)) ret = sci_er_interrupt(irq, ptr); /* Break Interrupt */ - if ((ssr_status & 0x0010) && (scr_status & SCI_CTRL_FLAGS_REIE)) + if ((ssr_status & 0x0010) && (scr_status & SCSCR_REIE)) ret = sci_br_interrupt(irq, ptr); return ret; @@ -861,7 +861,7 @@ static void sci_start_tx(struct uart_port *port) /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); - ctrl |= SCI_CTRL_FLAGS_TIE; + ctrl |= SCSCR_TIE; sci_out(port, SCSCR, ctrl); } @@ -871,7 +871,7 @@ static void sci_stop_tx(struct uart_port *port) /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); - ctrl &= ~SCI_CTRL_FLAGS_TIE; + ctrl &= ~SCSCR_TIE; sci_out(port, SCSCR, ctrl); } @@ -881,7 +881,7 @@ static void sci_start_rx(struct uart_port *port, unsigned int tty_start) /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); - ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; + ctrl |= SCSCR_RIE | SCSCR_REIE; sci_out(port, SCSCR, ctrl); } @@ -891,7 +891,7 @@ static void sci_stop_rx(struct uart_port *port) /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ ctrl = sci_in(port, SCSCR); - ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); + ctrl &= ~(SCSCR_RIE | SCSCR_REIE); sci_out(port, SCSCR, ctrl); } diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 5366e780aaeb..def626307c33 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -138,32 +138,6 @@ # error CPU subtype not defined #endif -/* SCSCR */ -#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ -#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ -#define SCI_CTRL_FLAGS_TE 0x20 /* all */ -#define SCI_CTRL_FLAGS_RE 0x10 /* all */ -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \ - defined(CONFIG_CPU_SUBTYPE_SH7091) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7722) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) || \ - defined(CONFIG_CPU_SUBTYPE_SHX3) -#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */ -#else -#define SCI_CTRL_FLAGS_REIE 0 -#endif -/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ -/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ - /* SCxSR SCI */ #define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ #define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -- cgit v1.2.3 From f8e53553f452dcbf67cb89c8cba63a1cd6eb4cc0 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 24 Jun 2009 19:54:48 +0900 Subject: serial: sh-sci: Kill off more unused defines. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index def626307c33..1b2ce1546979 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -18,8 +18,6 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) # define SCIF0 0xA4400000 # define SCIF2 0xA4410000 -# define SCSMR_Ir 0xA44A0000 -# define IRDA_SCIF SCIF0 # define SCPCR 0xA4000116 # define SCPDR 0xA4000136 #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ @@ -80,7 +78,6 @@ # define SCIF_ORER 0x0001 /* overrun error bit */ #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) # define SCIF_PTR2_OFFS 0x0000020 -# define SCIF_LSR2_OFFS 0x0000024 # define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */ #elif defined(CONFIG_H83007) || defined(CONFIG_H83068) # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) @@ -210,23 +207,11 @@ /* SCFCR */ #define SCFCR_RFRST 0x0002 #define SCFCR_TFRST 0x0004 -#define SCFCR_TCRST 0x4000 #define SCFCR_MCE 0x0008 #define SCI_MAJOR 204 #define SCI_MINOR_START 8 -/* Generic serial flags */ -#define SCI_RX_THROTTLE 0x0000001 - -#define SCI_MAGIC 0xbabeface - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define SCI_EVENT_WRITE_WAKEUP 0 - #define SCI_IN(size, offset) \ if ((size) == 8) { \ return ioread8(port->membase + (offset)); \ -- cgit v1.2.3 From fb27cfbcbd2865b0e731c4aae47df71778da805e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 25 Aug 2010 12:19:53 -0700 Subject: xenfs/xenbus: report partial reads/writes correctly copy_(to|from)_user return the number of uncopied bytes, so a successful return is 0, and any non-zero result indicates some degree of failure. Reported-by: "Jun Zhu (Intern)" Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/xenbus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index 9d5b519d2e4c..d2a905826804 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -142,7 +142,7 @@ static ssize_t xenbus_file_read(struct file *filp, i += sz - ret; rb->cons += sz - ret; - if (ret != sz) { + if (ret != 0) { if (i == 0) i = -EFAULT; goto out; @@ -453,7 +453,7 @@ static ssize_t xenbus_file_write(struct file *filp, ret = copy_from_user(u->u.buffer + u->len, ubuf, len); - if (ret == len) { + if (ret != 0) { rc = -EFAULT; goto out; } -- cgit v1.2.3 From 6d6df2e412297b8047c407b3abcd045a67c96744 Mon Sep 17 00:00:00 2001 From: Diego Ongaro Date: Wed, 1 Sep 2010 09:18:54 -0700 Subject: xenbus: allow any xenbus command over /proc/xen/xenbus When xenstored is in another domain, we need to be able to send any command over xenbus. This doesn't pose a security problem because its up to xenstored to determine whether a given client is allowed to use a particular command anyway. From linux-2.5.18-xen.hg 68d582b0ad05. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/xenbus.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index d2a905826804..46cf4048e60e 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -486,21 +486,6 @@ static ssize_t xenbus_file_write(struct file *filp, msg_type = u->u.msg.type; switch (msg_type) { - case XS_TRANSACTION_START: - case XS_TRANSACTION_END: - case XS_DIRECTORY: - case XS_READ: - case XS_GET_PERMS: - case XS_RELEASE: - case XS_GET_DOMAIN_PATH: - case XS_WRITE: - case XS_MKDIR: - case XS_RM: - case XS_SET_PERMS: - /* Send out a transaction */ - ret = xenbus_write_transaction(msg_type, u); - break; - case XS_WATCH: case XS_UNWATCH: /* (Un)Ask for some path to be watched for changes */ @@ -508,7 +493,8 @@ static ssize_t xenbus_file_write(struct file *filp, break; default: - ret = -EINVAL; + /* Send out a transaction */ + ret = xenbus_write_transaction(msg_type, u); break; } if (ret != 0) -- cgit v1.2.3 From 76ce7618f9a24f7b13958c67f7d5ccfcdab71475 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Tue, 7 Sep 2010 11:42:18 -0400 Subject: xenbus: add missing wakeup in concurrent read/write If an application has a dedicated read thread watching xenbus and another thread writes an XS_WATCH message that generates a synthetic "OK" reply, this reply will be enqueued in the buffer without waking up the reader. This can cause a deadlock in the application if it then waits for the read thread to receive the queued message. Signed-off-by: Daniel De Graaf commit e752969f502a511e83f841aa01d6cd332e6d85a0 Author: Daniel De Graaf Date: Tue Sep 7 11:21:52 2010 -0400 xenbus: fix deadlock in concurrent read/write If an application has a dedicated read thread watching xenbus and another thread writes an XS_WATCH message that generates a synthetic "OK" reply, this reply will be enqueued in the buffer without waking up the reader. Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/xenbus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index 46cf4048e60e..c4c7db8363e7 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -405,6 +405,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) mutex_lock(&u->reply_mutex); rc = queue_reply(&u->read_buffers, &reply, sizeof(reply)); + wake_up(&u->read_waitq); mutex_unlock(&u->reply_mutex); } -- cgit v1.2.3 From 7808121b9a1e44ef12fecd49fa6c268f27a150fc Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Wed, 8 Sep 2010 18:10:42 -0400 Subject: xenbus: avoid zero returns from read() It is possible to get a zero return from read() in instances where the queue is not empty but has no elements with data to deliver to the user. Since a zero return from read is an error indicator, resume waiting or return -EAGAIN (for a nonblocking fd) in this case. Signed-off-by: Daniel De Graaf Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/xenbus.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index c4c7db8363e7..55791dd1105f 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -120,6 +120,7 @@ static ssize_t xenbus_file_read(struct file *filp, int ret; mutex_lock(&u->reply_mutex); +again: while (list_empty(&u->read_buffers)) { mutex_unlock(&u->reply_mutex); if (filp->f_flags & O_NONBLOCK) @@ -158,6 +159,8 @@ static ssize_t xenbus_file_read(struct file *filp, struct read_buffer, list); } } + if (i == 0) + goto again; out: mutex_unlock(&u->reply_mutex); -- cgit v1.2.3 From 803711afdbea5c6a6dd2b46eca76097f6d50fb53 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 25 Oct 2010 21:11:15 +0200 Subject: PNP: Compile all pnp built-in stuff in one module namespace This is cleanup mostly, nothing urgent. I came up with it when looking at dynamic debug which can enable pr_debug messages at runtime or boot param for a specific module. Advantages: - Any pnp code can make use of the moduleparam.h interface, the modules will show up as pnp.param. - Passing pnp.ddebug as kernel boot param will enable all pnp debug messages with my previous patch and CONFIG_DYNAMIC_DEBUG enabled. Signed-off-by: Thomas Renninger Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pnp/Makefile | 6 ++++-- drivers/pnp/isapnp/Makefile | 6 +++--- drivers/pnp/pnpacpi/Makefile | 3 ++- drivers/pnp/pnpbios/Makefile | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile index 8de3775ec242..bfba893cb321 100644 --- a/drivers/pnp/Makefile +++ b/drivers/pnp/Makefile @@ -2,11 +2,13 @@ # Makefile for the Linux Plug-and-Play Support. # -obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o +obj-y := pnp.o + +pnp-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o obj-$(CONFIG_PNPACPI) += pnpacpi/ obj-$(CONFIG_PNPBIOS) += pnpbios/ obj-$(CONFIG_ISAPNP) += isapnp/ # pnp_system_init goes after pnpacpi/pnpbios init -obj-y += system.o +pnp-y += system.o diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile index cac18bbfb817..6e607aa33aa3 100644 --- a/drivers/pnp/isapnp/Makefile +++ b/drivers/pnp/isapnp/Makefile @@ -1,7 +1,7 @@ # # Makefile for the kernel ISAPNP driver. # +obj-y += pnp.o +pnp-y := core.o compat.o -isapnp-proc-$(CONFIG_PROC_FS) = proc.o - -obj-y := core.o compat.o $(isapnp-proc-y) +pnp-$(CONFIG_PROC_FS) += proc.o diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile index 905326fcca85..40c93da18252 100644 --- a/drivers/pnp/pnpacpi/Makefile +++ b/drivers/pnp/pnpacpi/Makefile @@ -1,5 +1,6 @@ # # Makefile for the kernel PNPACPI driver. # +obj-y += pnp.o -obj-y := core.o rsparser.o +pnp-y := core.o rsparser.o diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile index 3cd3ed760605..240b0ffb83ca 100644 --- a/drivers/pnp/pnpbios/Makefile +++ b/drivers/pnp/pnpbios/Makefile @@ -1,7 +1,8 @@ # # Makefile for the kernel PNPBIOS driver. # +obj-y := pnp.o -pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o +pnp-y := core.o bioscalls.o rsparser.o -obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y) +pnp-$(CONFIG_PNPBIOS_PROC_FS) += proc.o -- cgit v1.2.3 From cdefba03e44bd3b3311a3849a81ec7030dfa1519 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 25 Oct 2010 21:11:16 +0200 Subject: PNP: Set up pnp_debug via module and not via boot param. Cleanup only, no functional change (pnp.debug can be enabled and disabled at runtime, but that's not a real enhancement). This one depends on another PNP cleanup patch: PNP: Compile all pnp built-in stuff in one module namespace Signed-off-by: Thomas Renninger Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pnp/core.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 88b3cde52596..9801918b2726 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -218,10 +218,5 @@ subsys_initcall(pnp_init); int pnp_debug; #if defined(CONFIG_PNP_DEBUG_MESSAGES) -static int __init pnp_debug_setup(char *__unused) -{ - pnp_debug = 1; - return 1; -} -__setup("pnp.debug", pnp_debug_setup); +module_param_named(debug, pnp_debug, int, 0644); #endif -- cgit v1.2.3 From 78501eac34f372bfbeb4e1d9de688c13efa916f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 12:18:21 +0100 Subject: drm/i915/ringbuffer: Drop the redundant dev from the vfunc interface The ringbuffer keeps a pointer to the parent device, so we can use that instead of passing around the pointer on the stack. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +- drivers/gpu/drm/i915/i915_dma.c | 10 +- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 8 +- drivers/gpu/drm/i915/i915_gem.c | 55 +++-- drivers/gpu/drm/i915/i915_irq.c | 12 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 378 +++++++++++++++----------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 76 +++---- 8 files changed, 247 insertions(+), 298 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1f4f3ceb63c7..c1b04b6056da 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -296,7 +296,7 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring)); + dev_priv->render_ring.get_seqno(&dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -356,7 +356,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) atomic_read(&dev_priv->irq_received)); if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring)); + dev_priv->render_ring.get_seqno(&dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7a26f4dd21ae..8a171394a9cf 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -131,9 +131,9 @@ static int i915_dma_cleanup(struct drm_device * dev) drm_irq_uninstall(dev); mutex_lock(&dev->struct_mutex); - intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); - intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); - intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring); + intel_cleanup_ring_buffer(&dev_priv->render_ring); + intel_cleanup_ring_buffer(&dev_priv->bsd_ring); + intel_cleanup_ring_buffer(&dev_priv->blt_ring); mutex_unlock(&dev->struct_mutex); /* Clear the HWS virtual address at teardown */ @@ -221,7 +221,7 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG_DRIVER("hw status page @ %p\n", ring->status_page.page_addr); if (ring->status_page.gfx_addr != 0) - intel_ring_setup_status_page(dev, ring); + intel_ring_setup_status_page(ring); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); @@ -567,7 +567,7 @@ static int i915_quiescent(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); - return intel_wait_ring_buffer(dev, &dev_priv->render_ring, + return intel_wait_ring_buffer(&dev_priv->render_ring, dev_priv->render_ring.size - 8); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3467dd420760..82c19ab3e1e2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -473,7 +473,7 @@ int i915_reset(struct drm_device *dev, u8 flags) !dev_priv->mm.suspended) { struct intel_ring_buffer *ring = &dev_priv->render_ring; dev_priv->mm.suspended = 0; - ring->init(dev, ring); + ring->init(ring); mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); drm_irq_install(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2c2c19b6285e..6fb225f6b2c8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1219,10 +1219,10 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define I915_VERBOSE 0 #define BEGIN_LP_RING(n) do { \ - drm_i915_private_t *dev_priv__ = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ - intel_ring_begin(dev, &dev_priv__->render_ring, (n)); \ + intel_ring_begin(&dev_priv__->render_ring, (n)); \ } while (0) @@ -1230,7 +1230,7 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ - intel_ring_emit(dev, &dev_priv__->render_ring, x); \ + intel_ring_emit(&dev_priv__->render_ring, x); \ } while (0) #define ADVANCE_LP_RING() do { \ @@ -1238,7 +1238,7 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, if (I915_VERBOSE) \ DRM_DEBUG("ADVANCE_LP_RING %x\n", \ dev_priv__->render_ring.tail); \ - intel_ring_advance(dev, &dev_priv__->render_ring); \ + intel_ring_advance(&dev_priv__->render_ring); \ } while(0) /** diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8eb8453208b5..97bf7c87d857 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1703,7 +1703,7 @@ i915_add_request(struct drm_device *dev, return 0; } - seqno = ring->add_request(dev, ring, 0); + seqno = ring->add_request(ring, 0); ring->outstanding_lazy_request = false; request->seqno = seqno; @@ -1745,8 +1745,7 @@ i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) if (INTEL_INFO(dev)->gen >= 4) flush_domains |= I915_GEM_DOMAIN_SAMPLER; - ring->flush(dev, ring, - I915_GEM_DOMAIN_COMMAND, flush_domains); + ring->flush(ring, I915_GEM_DOMAIN_COMMAND, flush_domains); } static inline void @@ -1853,7 +1852,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, WARN_ON(i915_verify_lists(dev)); - seqno = ring->get_seqno(dev, ring); + seqno = ring->get_seqno(ring); while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -1894,7 +1893,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, if (unlikely (dev_priv->trace_irq_seqno && i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) { - ring->user_irq_put(dev, ring); + ring->user_irq_put(ring); dev_priv->trace_irq_seqno = 0; } @@ -1971,7 +1970,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, } BUG_ON(seqno == dev_priv->next_seqno); - if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { + if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) { if (HAS_PCH_SPLIT(dev)) ier = I915_READ(DEIER) | I915_READ(GTIER); else @@ -1986,19 +1985,17 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, trace_i915_gem_request_wait_begin(dev, seqno); ring->waiting_gem_seqno = seqno; - ring->user_irq_get(dev, ring); + ring->user_irq_get(ring); if (interruptible) ret = wait_event_interruptible(ring->irq_queue, - i915_seqno_passed( - ring->get_seqno(dev, ring), seqno) + i915_seqno_passed(ring->get_seqno(ring), seqno) || atomic_read(&dev_priv->mm.wedged)); else wait_event(ring->irq_queue, - i915_seqno_passed( - ring->get_seqno(dev, ring), seqno) + i915_seqno_passed(ring->get_seqno(ring), seqno) || atomic_read(&dev_priv->mm.wedged)); - ring->user_irq_put(dev, ring); + ring->user_irq_put(ring); ring->waiting_gem_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); @@ -2008,7 +2005,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (ret && ret != -ERESTARTSYS) DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n", - __func__, ret, seqno, ring->get_seqno(dev, ring), + __func__, ret, seqno, ring->get_seqno(ring), dev_priv->next_seqno); /* Directly dispatch request retiring. While we have the work queue @@ -2040,7 +2037,7 @@ i915_gem_flush_ring(struct drm_device *dev, uint32_t invalidate_domains, uint32_t flush_domains) { - ring->flush(dev, ring, invalidate_domains, flush_domains); + ring->flush(ring, invalidate_domains, flush_domains); i915_gem_process_flushing_list(dev, flush_domains, ring); } @@ -3532,17 +3529,17 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) return 0; ret = 0; - if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { + if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) { /* And wait for the seqno passing without holding any locks and * causing extra latency for others. This is safe as the irq * generation is designed to be run atomically and so is * lockless. */ - ring->user_irq_get(dev, ring); + ring->user_irq_get(ring); ret = wait_event_interruptible(ring->irq_queue, - i915_seqno_passed(ring->get_seqno(dev, ring), seqno) + i915_seqno_passed(ring->get_seqno(ring), seqno) || atomic_read(&dev_priv->mm.wedged)); - ring->user_irq_put(dev, ring); + ring->user_irq_put(ring); if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) ret = -EIO; @@ -3829,17 +3826,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, else flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, - MI_WAIT_FOR_EVENT | flip_mask); - intel_ring_emit(dev, ring, MI_NOOP); - intel_ring_advance(dev, ring); + intel_ring_begin(ring, 2); + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); } } /* Exec the batchbuffer */ - ret = ring->dispatch_gem_execbuffer(dev, ring, args, - cliprects, exec_offset); + ret = ring->dispatch_execbuffer(ring, args, cliprects, exec_offset); if (ret) { DRM_ERROR("dispatch failed %d\n", ret); goto err; @@ -4520,9 +4515,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev) return 0; cleanup_bsd_ring: - intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); + intel_cleanup_ring_buffer(&dev_priv->bsd_ring); cleanup_render_ring: - intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + intel_cleanup_ring_buffer(&dev_priv->render_ring); cleanup_pipe_control: if (HAS_PIPE_CONTROL(dev)) i915_gem_cleanup_pipe_control(dev); @@ -4534,9 +4529,9 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); - intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); - intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring); + intel_cleanup_ring_buffer(&dev_priv->render_ring); + intel_cleanup_ring_buffer(&dev_priv->bsd_ring); + intel_cleanup_ring_buffer(&dev_priv->blt_ring); if (HAS_PIPE_CONTROL(dev)) i915_gem_cleanup_pipe_control(dev); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 729fd0c91d7b..852a2d848bf4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -297,7 +297,7 @@ static void notify_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 seqno = ring->get_seqno(dev, ring); + u32 seqno = ring->get_seqno(ring); ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); wake_up_all(&ring->irq_queue); @@ -586,7 +586,7 @@ static void i915_capture_error_state(struct drm_device *dev) DRM_DEBUG_DRIVER("generating error event\n"); error->seqno = - dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring); + dev_priv->render_ring.get_seqno(&dev_priv->render_ring); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); error->pipeastat = I915_READ(PIPEASTAT); @@ -1117,7 +1117,7 @@ void i915_trace_irq_get(struct drm_device *dev, u32 seqno) struct intel_ring_buffer *render_ring = &dev_priv->render_ring; if (dev_priv->trace_irq_seqno == 0) - render_ring->user_irq_get(dev, render_ring); + render_ring->user_irq_get(render_ring); dev_priv->trace_irq_seqno = seqno; } @@ -1141,10 +1141,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - render_ring->user_irq_get(dev, render_ring); + render_ring->user_irq_get(render_ring); DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - render_ring->user_irq_put(dev, render_ring); + render_ring->user_irq_put(render_ring); if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", @@ -1338,7 +1338,7 @@ void i915_hangcheck_elapsed(unsigned long data) /* If all work is done then ACTHD clearly hasn't advanced. */ if (list_empty(&dev_priv->render_ring.request_list) || - i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring), + i915_seqno_passed(dev_priv->render_ring.get_seqno(&dev_priv->render_ring), i915_get_tail_request(dev)->seqno)) { bool missed_wakeup = false; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 09f2dc353ae2..d6eba661105f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -49,11 +49,11 @@ static u32 i915_gem_get_seqno(struct drm_device *dev) } static void -render_ring_flush(struct drm_device *dev, - struct intel_ring_buffer *ring, +render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 cmd; @@ -112,43 +112,39 @@ render_ring_flush(struct drm_device *dev, #if WATCH_EXEC DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); #endif - intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, cmd); - intel_ring_emit(dev, ring, MI_NOOP); - intel_ring_advance(dev, ring); + intel_ring_begin(ring, 2); + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); } } -static void ring_write_tail(struct drm_device *dev, - struct intel_ring_buffer *ring, +static void ring_write_tail(struct intel_ring_buffer *ring, u32 value) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = ring->dev->dev_private; I915_WRITE_TAIL(ring, value); } -u32 intel_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring) +u32 intel_ring_get_active_head(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ? + drm_i915_private_t *dev_priv = ring->dev->dev_private; + u32 acthd_reg = INTEL_INFO(ring->dev)->gen >= 4 ? RING_ACTHD(ring->mmio_base) : ACTHD; return I915_READ(acthd_reg); } -static int init_ring_common(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int init_ring_common(struct intel_ring_buffer *ring) { + drm_i915_private_t *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_object *obj_priv = to_intel_bo(ring->gem_object); u32 head; - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; - obj_priv = to_intel_bo(ring->gem_object); /* Stop the ring if it's running. */ I915_WRITE_CTL(ring, 0); I915_WRITE_HEAD(ring, 0); - ring->write_tail(dev, ring, 0); + ring->write_tail(ring, 0); /* Initialize the ring. */ I915_WRITE_START(ring, obj_priv->gtt_offset); @@ -192,8 +188,8 @@ static int init_ring_common(struct drm_device *dev, return -EIO; } - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_kernel_lost_context(dev); + if (!drm_core_check_feature(ring->dev, DRIVER_MODESET)) + i915_kernel_lost_context(ring->dev); else { ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; @@ -204,29 +200,29 @@ static int init_ring_common(struct drm_device *dev, return 0; } -static int init_render_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int init_render_ring(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - int ret = init_ring_common(dev, ring); - int mode; + struct drm_device *dev = ring->dev; + int ret = init_ring_common(ring); if (INTEL_INFO(dev)->gen > 3) { - mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; + drm_i915_private_t *dev_priv = dev->dev_private; + int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; if (IS_GEN6(dev)) mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; I915_WRITE(MI_MODE, mode); } + return ret; } -#define PIPE_CONTROL_FLUSH(addr) \ +#define PIPE_CONTROL_FLUSH(ring__, addr__) \ do { \ - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ + intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ PIPE_CONTROL_DEPTH_STALL | 2); \ - OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ - OUT_RING(0); \ - OUT_RING(0); \ + intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT); \ + intel_ring_emit(ring__, 0); \ + intel_ring_emit(ring__, 0); \ } while (0) /** @@ -238,26 +234,26 @@ do { \ * Returned sequence numbers are nonzero on success. */ static u32 -render_ring_add_request(struct drm_device *dev, - struct intel_ring_buffer *ring, +render_ring_add_request(struct intel_ring_buffer *ring, u32 flush_domains) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 seqno; seqno = i915_gem_get_seqno(dev); if (IS_GEN6(dev)) { - BEGIN_LP_RING(6); - OUT_RING(GFX_OP_PIPE_CONTROL | 3); - OUT_RING(PIPE_CONTROL_QW_WRITE | + intel_ring_begin(ring, 6); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3); + intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | PIPE_CONTROL_NOTIFY); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - OUT_RING(0); - ADVANCE_LP_RING(); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); } else if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; @@ -266,46 +262,46 @@ render_ring_add_request(struct drm_device *dev, * PIPE_NOTIFY buffers out to memory before requesting * an interrupt. */ - BEGIN_LP_RING(32); - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + intel_ring_begin(ring, 32); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - PIPE_CONTROL_FLUSH(scratch_addr); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(scratch_addr); + PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); + PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); + PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); + PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_FLUSH(ring, scratch_addr); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | PIPE_CONTROL_NOTIFY); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - ADVANCE_LP_RING(); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); } else { - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(seqno); + intel_ring_begin(ring, 4); + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); } return seqno; } static u32 -render_ring_get_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +render_ring_get_seqno(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; if (HAS_PIPE_CONTROL(dev)) return ((volatile u32 *)(dev_priv->seqno_page))[0]; @@ -314,9 +310,9 @@ render_ring_get_seqno(struct drm_device *dev, } static void -render_ring_get_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) +render_ring_get_user_irq(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; @@ -331,9 +327,9 @@ render_ring_get_user_irq(struct drm_device *dev, } static void -render_ring_put_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) +render_ring_put_user_irq(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; @@ -348,56 +344,41 @@ render_ring_put_user_irq(struct drm_device *dev, spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -void intel_ring_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) +void intel_ring_setup_status_page(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - if (IS_GEN6(dev)) { - I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base), - ring->status_page.gfx_addr); - I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */ - } else { - I915_WRITE(RING_HWS_PGA(ring->mmio_base), - ring->status_page.gfx_addr); - I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */ - } - + drm_i915_private_t *dev_priv = ring->dev->dev_private; + u32 mmio = IS_GEN6(ring->dev) ? + RING_HWS_PGA_GEN6(ring->mmio_base) : + RING_HWS_PGA(ring->mmio_base); + I915_WRITE(mmio, (u32)ring->status_page.gfx_addr); + POSTING_READ(mmio); } static void -bsd_ring_flush(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) -{ - intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, MI_FLUSH); - intel_ring_emit(dev, ring, MI_NOOP); - intel_ring_advance(dev, ring); -} - -static int init_bsd_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) +bsd_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { - return init_ring_common(dev, ring); + intel_ring_begin(ring, 2); + intel_ring_emit(ring, MI_FLUSH); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); } static u32 -ring_add_request(struct drm_device *dev, - struct intel_ring_buffer *ring, +ring_add_request(struct intel_ring_buffer *ring, u32 flush_domains) { u32 seqno; - seqno = i915_gem_get_seqno(dev); + seqno = i915_gem_get_seqno(ring->dev); - intel_ring_begin(dev, ring, 4); - intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(dev, ring, - I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(dev, ring, seqno); - intel_ring_emit(dev, ring, MI_USER_INTERRUPT); - intel_ring_advance(dev, ring); + intel_ring_begin(ring, 4); + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); @@ -405,53 +386,55 @@ ring_add_request(struct drm_device *dev, } static void -bsd_ring_get_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) +bsd_ring_get_user_irq(struct intel_ring_buffer *ring) { /* do nothing */ } static void -bsd_ring_put_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) +bsd_ring_put_user_irq(struct intel_ring_buffer *ring) { /* do nothing */ } static u32 -ring_status_page_get_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +ring_status_page_get_seqno(struct intel_ring_buffer *ring) { return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } static int -ring_dispatch_gem_execbuffer(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) +ring_dispatch_execbuffer(struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { uint32_t exec_start; + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | - (2 << 6) | MI_BATCH_NON_SECURE_I965); - intel_ring_emit(dev, ring, exec_start); - intel_ring_advance(dev, ring); + + intel_ring_begin(ring, 2); + intel_ring_emit(ring, + MI_BATCH_BUFFER_START | + (2 << 6) | + MI_BATCH_NON_SECURE_I965); + intel_ring_emit(ring, exec_start); + intel_ring_advance(ring); + return 0; } static int -render_ring_dispatch_gem_execbuffer(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) +render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; int i = 0, count; uint32_t exec_start, exec_len; + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; @@ -468,46 +451,44 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, } if (IS_I830(dev) || IS_845G(dev)) { - intel_ring_begin(dev, ring, 4); - intel_ring_emit(dev, ring, MI_BATCH_BUFFER); - intel_ring_emit(dev, ring, - exec_start | MI_BATCH_NON_SECURE); - intel_ring_emit(dev, ring, exec_start + exec_len - 4); - intel_ring_emit(dev, ring, 0); + intel_ring_begin(ring, 4); + intel_ring_emit(ring, MI_BATCH_BUFFER); + intel_ring_emit(ring, exec_start | MI_BATCH_NON_SECURE); + intel_ring_emit(ring, exec_start + exec_len - 4); + intel_ring_emit(ring, 0); } else { - intel_ring_begin(dev, ring, 2); + intel_ring_begin(ring, 2); if (INTEL_INFO(dev)->gen >= 4) { - intel_ring_emit(dev, ring, + intel_ring_emit(ring, MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); - intel_ring_emit(dev, ring, exec_start); + intel_ring_emit(ring, exec_start); } else { - intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START + intel_ring_emit(ring, MI_BATCH_BUFFER_START | (2 << 6)); - intel_ring_emit(dev, ring, exec_start | + intel_ring_emit(ring, exec_start | MI_BATCH_NON_SECURE); } } - intel_ring_advance(dev, ring); + intel_ring_advance(ring); } if (IS_G4X(dev) || IS_GEN5(dev)) { - intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, MI_FLUSH | + intel_ring_begin(ring, 2); + intel_ring_emit(ring, MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP ); - intel_ring_emit(dev, ring, MI_NOOP); - intel_ring_advance(dev, ring); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); } /* XXX breadcrumb */ return 0; } -static void cleanup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) +static void cleanup_status_page(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; @@ -524,9 +505,9 @@ static void cleanup_status_page(struct drm_device *dev, memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); } -static int init_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int init_status_page(struct intel_ring_buffer *ring) { + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; @@ -555,7 +536,7 @@ static int init_status_page(struct drm_device *dev, ring->status_page.obj = obj; memset(ring->status_page.page_addr, 0, PAGE_SIZE); - intel_ring_setup_status_page(dev, ring); + intel_ring_setup_status_page(ring); DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", ring->name, ring->status_page.gfx_addr); @@ -583,7 +564,7 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->gpu_write_list); if (I915_NEED_GFX_HWS(dev)) { - ret = init_status_page(dev, ring); + ret = init_status_page(ring); if (ret) return ret; } @@ -616,7 +597,7 @@ int intel_init_ring_buffer(struct drm_device *dev, } ring->virtual_start = ring->map.handle; - ret = ring->init(dev, ring); + ret = ring->init(ring); if (ret) goto err_unmap; @@ -639,33 +620,32 @@ err_unref: drm_gem_object_unreference(obj); ring->gem_object = NULL; err_hws: - cleanup_status_page(dev, ring); + cleanup_status_page(ring); return ret; } -void intel_cleanup_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) +void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) { if (ring->gem_object == NULL) return; - drm_core_ioremapfree(&ring->map, dev); + drm_core_ioremapfree(&ring->map, ring->dev); i915_gem_object_unpin(ring->gem_object); drm_gem_object_unreference(ring->gem_object); ring->gem_object = NULL; - cleanup_status_page(dev, ring); + + cleanup_status_page(ring); } -static int intel_wrap_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) { unsigned int *virt; int rem; rem = ring->size - ring->tail; if (ring->space < rem) { - int ret = intel_wait_ring_buffer(dev, ring, rem); + int ret = intel_wait_ring_buffer(ring, rem); if (ret) return ret; } @@ -683,11 +663,11 @@ static int intel_wrap_ring_buffer(struct drm_device *dev, return 0; } -int intel_wait_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring, int n) +int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) { - unsigned long end; + struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long end; trace_i915_ring_wait_begin (dev); end = jiffies + 3 * HZ; @@ -697,7 +677,7 @@ int intel_wait_ring_buffer(struct drm_device *dev, if (ring->space < 0) ring->space += ring->size; if (ring->space >= n) { - trace_i915_ring_wait_end (dev); + trace_i915_ring_wait_end(dev); return 0; } @@ -713,24 +693,24 @@ int intel_wait_ring_buffer(struct drm_device *dev, return -EBUSY; } -void intel_ring_begin(struct drm_device *dev, - struct intel_ring_buffer *ring, +void intel_ring_begin(struct intel_ring_buffer *ring, int num_dwords) { int n = 4*num_dwords; + if (unlikely(ring->tail + n > ring->size)) - intel_wrap_ring_buffer(dev, ring); + intel_wrap_ring_buffer(ring); + if (unlikely(ring->space < n)) - intel_wait_ring_buffer(dev, ring, n); + intel_wait_ring_buffer(ring, n); ring->space -= n; } -void intel_ring_advance(struct drm_device *dev, - struct intel_ring_buffer *ring) +void intel_ring_advance(struct intel_ring_buffer *ring) { ring->tail &= ring->size - 1; - ring->write_tail(dev, ring, ring->tail); + ring->write_tail(ring, ring->tail); } static const struct intel_ring_buffer render_ring = { @@ -745,7 +725,7 @@ static const struct intel_ring_buffer render_ring = { .get_seqno = render_ring_get_seqno, .user_irq_get = render_ring_get_user_irq, .user_irq_put = render_ring_put_user_irq, - .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer, + .dispatch_execbuffer = render_ring_dispatch_execbuffer, }; /* ring buffer for bit-stream decoder */ @@ -755,22 +735,21 @@ static const struct intel_ring_buffer bsd_ring = { .id = RING_BSD, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, - .init = init_bsd_ring, + .init = init_ring_common, .write_tail = ring_write_tail, .flush = bsd_ring_flush, .add_request = ring_add_request, .get_seqno = ring_status_page_get_seqno, .user_irq_get = bsd_ring_get_user_irq, .user_irq_put = bsd_ring_put_user_irq, - .dispatch_gem_execbuffer = ring_dispatch_gem_execbuffer, + .dispatch_execbuffer = ring_dispatch_execbuffer, }; -static void gen6_bsd_ring_write_tail(struct drm_device *dev, - struct intel_ring_buffer *ring, +static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, u32 value) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = ring->dev->dev_private; /* Every tail move must follow the sequence below */ I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL, @@ -789,36 +768,33 @@ static void gen6_bsd_ring_write_tail(struct drm_device *dev, GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE); } -static void gen6_ring_flush(struct drm_device *dev, - struct intel_ring_buffer *ring, +static void gen6_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { - intel_ring_begin(dev, ring, 4); - intel_ring_emit(dev, ring, MI_FLUSH_DW); - intel_ring_emit(dev, ring, 0); - intel_ring_emit(dev, ring, 0); - intel_ring_emit(dev, ring, 0); - intel_ring_advance(dev, ring); + intel_ring_begin(ring, 4); + intel_ring_emit(ring, MI_FLUSH_DW); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); } static int -gen6_ring_dispatch_gem_execbuffer(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) +gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { uint32_t exec_start; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - intel_ring_begin(dev, ring, 2); - intel_ring_emit(dev, ring, - MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); + intel_ring_begin(ring, 2); + intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); /* bit0-7 is the length on GEN6+ */ - intel_ring_emit(dev, ring, exec_start); - intel_ring_advance(dev, ring); + intel_ring_emit(ring, exec_start); + intel_ring_advance(ring); return 0; } @@ -829,27 +805,25 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .id = RING_BSD, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, - .init = init_bsd_ring, + .init = init_ring_common, .write_tail = gen6_bsd_ring_write_tail, .flush = gen6_ring_flush, .add_request = ring_add_request, .get_seqno = ring_status_page_get_seqno, .user_irq_get = bsd_ring_get_user_irq, .user_irq_put = bsd_ring_put_user_irq, - .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer, + .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, }; /* Blitter support (SandyBridge+) */ static void -blt_ring_get_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) +blt_ring_get_user_irq(struct intel_ring_buffer *ring) { /* do nothing */ } static void -blt_ring_put_user_irq(struct drm_device *dev, - struct intel_ring_buffer *ring) +blt_ring_put_user_irq(struct intel_ring_buffer *ring) { /* do nothing */ } @@ -866,7 +840,7 @@ static const struct intel_ring_buffer gen6_blt_ring = { .get_seqno = ring_status_page_get_seqno, .user_irq_get = blt_ring_get_user_irq, .user_irq_put = blt_ring_put_user_irq, - .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer, + .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, }; int intel_init_render_ring_buffer(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a05aff0e5764..ba4a393e6d16 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -2,7 +2,7 @@ #define _INTEL_RINGBUFFER_H_ struct intel_hw_status_page { - void *page_addr; + u32 __iomem *page_addr; unsigned int gfx_addr; struct drm_gem_object *obj; }; @@ -38,31 +38,23 @@ struct intel_ring_buffer { u32 irq_gem_seqno; /* last seq seem at irq time */ u32 waiting_gem_seqno; int user_irq_refcount; - void (*user_irq_get)(struct drm_device *dev, - struct intel_ring_buffer *ring); - void (*user_irq_put)(struct drm_device *dev, - struct intel_ring_buffer *ring); + void (*user_irq_get)(struct intel_ring_buffer *ring); + void (*user_irq_put)(struct intel_ring_buffer *ring); - int (*init)(struct drm_device *dev, - struct intel_ring_buffer *ring); + int (*init)(struct intel_ring_buffer *ring); - void (*write_tail)(struct drm_device *dev, - struct intel_ring_buffer *ring, + void (*write_tail)(struct intel_ring_buffer *ring, u32 value); - void (*flush)(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains); - u32 (*add_request)(struct drm_device *dev, - struct intel_ring_buffer *ring, - u32 flush_domains); - u32 (*get_seqno)(struct drm_device *dev, - struct intel_ring_buffer *ring); - int (*dispatch_gem_execbuffer)(struct drm_device *dev, - struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset); + void (*flush)(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains); + u32 (*add_request)(struct intel_ring_buffer *ring, + u32 flush_domains); + u32 (*get_seqno)(struct intel_ring_buffer *ring); + int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset); /** * List of objects currently involved in rendering from the @@ -102,43 +94,31 @@ struct intel_ring_buffer { static inline u32 intel_read_status_page(struct intel_ring_buffer *ring, - int reg) + int reg) { - u32 *regs = ring->status_page.page_addr; - return regs[reg]; + return ioread32(ring->status_page.page_addr + reg); } -int intel_init_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring); -void intel_cleanup_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring); -int intel_wait_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring, int n); -void intel_ring_begin(struct drm_device *dev, - struct intel_ring_buffer *ring, int n); - -static inline void intel_ring_emit(struct drm_device *dev, - struct intel_ring_buffer *ring, - unsigned int data) +void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); +int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); +void intel_ring_begin(struct intel_ring_buffer *ring, int n); + +static inline void intel_ring_emit(struct intel_ring_buffer *ring, + u32 data) { - unsigned int *virt = ring->virtual_start + ring->tail; - *virt = data; + iowrite32(data, ring->virtual_start + ring->tail); ring->tail += 4; } -void intel_ring_advance(struct drm_device *dev, - struct intel_ring_buffer *ring); +void intel_ring_advance(struct intel_ring_buffer *ring); -u32 intel_ring_get_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring); +u32 intel_ring_get_seqno(struct intel_ring_buffer *ring); int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); int intel_init_blt_ring_buffer(struct drm_device *dev); -u32 intel_ring_get_active_head(struct drm_device *dev, - struct intel_ring_buffer *ring); -void intel_ring_setup_status_page(struct drm_device *dev, - struct intel_ring_buffer *ring); +u32 intel_ring_get_active_head(struct intel_ring_buffer *ring); +void intel_ring_setup_status_page(struct intel_ring_buffer *ring); #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.2.3 From e1f99ce6cac3b6a95551642be5ddb5d9c46bea76 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 12:45:26 +0100 Subject: drm/i915: Propagate errors from writing to ringbuffer Preparing the ringbuffer for adding new commands can fail (a timeout whilst waiting for the GPU to catch up and free some space). So check for any potential error before overwriting HEAD with new commands, and propagate that error back to the user where possible. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 119 ++++++++++---------- drivers/gpu/drm/i915/i915_drv.h | 28 +---- drivers/gpu/drm/i915/i915_gem.c | 5 +- drivers/gpu/drm/i915/i915_irq.c | 13 ++- drivers/gpu/drm/i915/intel_display.c | 51 +++++---- drivers/gpu/drm/i915/intel_overlay.c | 30 ++++- drivers/gpu/drm/i915/intel_ringbuffer.c | 189 ++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +- 8 files changed, 244 insertions(+), 195 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8a171394a9cf..02daf4e5c8e6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -263,7 +263,7 @@ static int i915_dma_init(struct drm_device *dev, void *data, * instruction detected will be given a size of zero, which is a * signal to abort the rest of the buffer. */ -static int do_validate_cmd(int cmd) +static int validate_cmd(int cmd) { switch (((cmd >> 29) & 0x7)) { case 0x0: @@ -321,40 +321,27 @@ static int do_validate_cmd(int cmd) return 0; } -static int validate_cmd(int cmd) -{ - int ret = do_validate_cmd(cmd); - -/* printk("validate_cmd( %x ): %d\n", cmd, ret); */ - - return ret; -} - static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) { drm_i915_private_t *dev_priv = dev->dev_private; - int i; + int i, ret; if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8) return -EINVAL; - BEGIN_LP_RING((dwords+1)&~1); - for (i = 0; i < dwords;) { - int cmd, sz; - - cmd = buffer[i]; - - if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords) + int sz = validate_cmd(buffer[i]); + if (sz == 0 || i + sz > dwords) return -EINVAL; - - OUT_RING(cmd); - - while (++i, --sz) { - OUT_RING(buffer[i]); - } + i += sz; } + ret = BEGIN_LP_RING((dwords+1)&~1); + if (ret) + return ret; + + for (i = 0; i < dwords; i++) + OUT_RING(buffer[i]); if (dwords & 1) OUT_RING(0); @@ -368,7 +355,9 @@ i915_emit_box(struct drm_device *dev, struct drm_clip_rect *boxes, int i, int DR1, int DR4) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_clip_rect box = boxes[i]; + int ret; if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { DRM_ERROR("Bad box %d,%d..%d,%d\n", @@ -377,22 +366,27 @@ i915_emit_box(struct drm_device *dev, } if (INTEL_INFO(dev)->gen >= 4) { - BEGIN_LP_RING(4); + ret = BEGIN_LP_RING(4); + if (ret) + return ret; + OUT_RING(GFX_OP_DRAWRECT_INFO_I965); OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); OUT_RING(DR4); - ADVANCE_LP_RING(); } else { - BEGIN_LP_RING(6); + ret = BEGIN_LP_RING(6); + if (ret) + return ret; + OUT_RING(GFX_OP_DRAWRECT_INFO); OUT_RING(DR1); OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); OUT_RING(DR4); OUT_RING(0); - ADVANCE_LP_RING(); } + ADVANCE_LP_RING(); return 0; } @@ -412,12 +406,13 @@ static void i915_emit_breadcrumb(struct drm_device *dev) if (master_priv->sarea_priv) master_priv->sarea_priv->last_enqueue = dev_priv->counter; - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); - OUT_RING(0); - ADVANCE_LP_RING(); + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); + } } static int i915_dispatch_cmdbuffer(struct drm_device * dev, @@ -458,8 +453,9 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, drm_i915_batchbuffer_t * batch, struct drm_clip_rect *cliprects) { + struct drm_i915_private *dev_priv = dev->dev_private; int nbox = batch->num_cliprects; - int i = 0, count; + int i, count, ret; if ((batch->start | batch->used) & 0x7) { DRM_ERROR("alignment"); @@ -469,17 +465,19 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, i915_kernel_lost_context(dev); count = nbox ? nbox : 1; - for (i = 0; i < count; i++) { if (i < nbox) { - int ret = i915_emit_box(dev, cliprects, i, - batch->DR1, batch->DR4); + ret = i915_emit_box(dev, cliprects, i, + batch->DR1, batch->DR4); if (ret) return ret; } if (!IS_I830(dev) && !IS_845G(dev)) { - BEGIN_LP_RING(2); + ret = BEGIN_LP_RING(2); + if (ret) + return ret; + if (INTEL_INFO(dev)->gen >= 4) { OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); OUT_RING(batch->start); @@ -487,26 +485,29 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); OUT_RING(batch->start | MI_BATCH_NON_SECURE); } - ADVANCE_LP_RING(); } else { - BEGIN_LP_RING(4); + ret = BEGIN_LP_RING(4); + if (ret) + return ret; + OUT_RING(MI_BATCH_BUFFER); OUT_RING(batch->start | MI_BATCH_NON_SECURE); OUT_RING(batch->start + batch->used - 4); OUT_RING(0); - ADVANCE_LP_RING(); } + ADVANCE_LP_RING(); } if (IS_G4X(dev) || IS_GEN5(dev)) { - BEGIN_LP_RING(2); - OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + if (BEGIN_LP_RING(2) == 0) { + OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } } - i915_emit_breadcrumb(dev); + i915_emit_breadcrumb(dev); return 0; } @@ -515,6 +516,7 @@ static int i915_dispatch_flip(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + int ret; if (!master_priv->sarea_priv) return -EINVAL; @@ -526,12 +528,13 @@ static int i915_dispatch_flip(struct drm_device * dev) i915_kernel_lost_context(dev); - BEGIN_LP_RING(2); + ret = BEGIN_LP_RING(10); + if (ret) + return ret; + OUT_RING(MI_FLUSH | MI_READ_FLUSH); OUT_RING(0); - ADVANCE_LP_RING(); - BEGIN_LP_RING(6); OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); OUT_RING(0); if (dev_priv->current_page == 0) { @@ -542,21 +545,21 @@ static int i915_dispatch_flip(struct drm_device * dev) dev_priv->current_page = 0; } OUT_RING(0); - ADVANCE_LP_RING(); - BEGIN_LP_RING(2); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); OUT_RING(0); + ADVANCE_LP_RING(); master_priv->sarea_priv->last_enqueue = dev_priv->counter++; - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); - OUT_RING(0); - ADVANCE_LP_RING(); + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->counter); + OUT_RING(0); + ADVANCE_LP_RING(); + } master_priv->sarea_priv->pf_current_page = dev_priv->current_page; return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6fb225f6b2c8..c241468c632e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1216,30 +1216,14 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \ I915_DEBUG_WRITE)) -#define I915_VERBOSE 0 +#define BEGIN_LP_RING(n) \ + intel_ring_begin(&dev_priv->render_ring, (n)) -#define BEGIN_LP_RING(n) do { \ - drm_i915_private_t *dev_priv__ = dev->dev_private; \ - if (I915_VERBOSE) \ - DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ - intel_ring_begin(&dev_priv__->render_ring, (n)); \ -} while (0) - - -#define OUT_RING(x) do { \ - drm_i915_private_t *dev_priv__ = dev->dev_private; \ - if (I915_VERBOSE) \ - DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ - intel_ring_emit(&dev_priv__->render_ring, x); \ -} while (0) +#define OUT_RING(x) \ + intel_ring_emit(&dev_priv->render_ring, x) -#define ADVANCE_LP_RING() do { \ - drm_i915_private_t *dev_priv__ = dev->dev_private; \ - if (I915_VERBOSE) \ - DRM_DEBUG("ADVANCE_LP_RING %x\n", \ - dev_priv__->render_ring.tail); \ - intel_ring_advance(&dev_priv__->render_ring); \ -} while(0) +#define ADVANCE_LP_RING() \ + intel_ring_advance(&dev_priv->render_ring) /** * Reads a dword out of the status page, which is written to from the command diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 97bf7c87d857..00e901483ba5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3826,7 +3826,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, else flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - intel_ring_begin(ring, 2); + ret = intel_ring_begin(ring, 2); + if (ret) + goto err; + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 852a2d848bf4..8acdd6d857d3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1101,12 +1101,13 @@ static int i915_emit_irq(struct drm_device * dev) if (master_priv->sarea_priv) master_priv->sarea_priv->last_enqueue = dev_priv->counter; - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(dev_priv->counter); - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(dev_priv->counter); + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } return dev_priv->counter; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 990f065374b2..eb4c725e3069 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5090,22 +5090,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_objs; - /* Block clients from rendering to the new back buffer until - * the flip occurs and the object is no longer visible. - */ - atomic_add(1 << intel_crtc->plane, - &to_intel_bo(work->old_fb_obj)->pending_flip); - - work->pending_flip_obj = obj; - obj_priv = to_intel_bo(obj); - if (IS_GEN3(dev) || IS_GEN2(dev)) { u32 flip_mask; /* Can't queue multiple flips, so wait for the previous * one to finish before executing the next. */ - BEGIN_LP_RING(2); + ret = BEGIN_LP_RING(2); + if (ret) + goto cleanup_objs; + if (intel_crtc->plane) flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; else @@ -5115,13 +5109,25 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, ADVANCE_LP_RING(); } + work->pending_flip_obj = obj; + obj_priv = to_intel_bo(obj); + work->enable_stall_check = true; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; - BEGIN_LP_RING(4); - switch(INTEL_INFO(dev)->gen) { + ret = BEGIN_LP_RING(4); + if (ret) + goto cleanup_objs; + + /* Block clients from rendering to the new back buffer until + * the flip occurs and the object is no longer visible. + */ + atomic_add(1 << intel_crtc->plane, + &to_intel_bo(work->old_fb_obj)->pending_flip); + + switch (INTEL_INFO(dev)->gen) { case 2: OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); @@ -5850,16 +5856,17 @@ void intel_init_clock_gating(struct drm_device *dev) struct drm_i915_gem_object *obj_priv; obj_priv = to_intel_bo(dev_priv->renderctx); if (obj_priv) { - BEGIN_LP_RING(4); - OUT_RING(MI_SET_CONTEXT); - OUT_RING(obj_priv->gtt_offset | - MI_MM_SPACE_GTT | - MI_SAVE_EXT_STATE_EN | - MI_RESTORE_EXT_STATE_EN | - MI_RESTORE_INHIBIT); - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); - ADVANCE_LP_RING(); + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_SET_CONTEXT); + OUT_RING(obj_priv->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); + } } } else DRM_DEBUG_KMS("Failed to allocate render context." diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index afb96d25219a..78fa6a249964 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -289,6 +289,7 @@ i830_deactivate_pipe_a(struct drm_device *dev) static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_request *request; int pipe_a_quirk = 0; int ret; @@ -308,7 +309,12 @@ static int intel_overlay_on(struct intel_overlay *overlay) goto out; } - BEGIN_LP_RING(4); + ret = BEGIN_LP_RING(4); + if (ret) { + kfree(request); + goto out; + } + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); OUT_RING(overlay->flip_addr | OFC_UPDATE); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); @@ -332,6 +338,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, struct drm_i915_gem_request *request; u32 flip_addr = overlay->flip_addr; u32 tmp; + int ret; BUG_ON(!overlay->active); @@ -347,7 +354,11 @@ static int intel_overlay_continue(struct intel_overlay *overlay, if (tmp & (1 << 17)) DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); - BEGIN_LP_RING(2); + ret = BEGIN_LP_RING(2); + if (ret) { + kfree(request); + return ret; + } OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(flip_addr); ADVANCE_LP_RING(); @@ -389,8 +400,10 @@ static int intel_overlay_off(struct intel_overlay *overlay, bool interruptible) { struct drm_device *dev = overlay->dev; + struct drm_i915_private *dev_priv = dev->dev_private; u32 flip_addr = overlay->flip_addr; struct drm_i915_gem_request *request; + int ret; BUG_ON(!overlay->active); @@ -404,7 +417,11 @@ static int intel_overlay_off(struct intel_overlay *overlay, * of the hw. Do it in both cases */ flip_addr |= OFC_UPDATE; - BEGIN_LP_RING(6); + ret = BEGIN_LP_RING(6); + if (ret) { + kfree(request); + return ret; + } /* wait for overlay to go idle */ OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(flip_addr); @@ -467,7 +484,12 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) if (request == NULL) return -ENOMEM; - BEGIN_LP_RING(2); + ret = BEGIN_LP_RING(2); + if (ret) { + kfree(request); + return ret; + } + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_NOOP); ADVANCE_LP_RING(); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d6eba661105f..6fe42c1f4ea9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -112,10 +112,11 @@ render_ring_flush(struct intel_ring_buffer *ring, #if WATCH_EXEC DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); #endif - intel_ring_begin(ring, 2); - intel_ring_emit(ring, cmd); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 2) == 0) { + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } } } @@ -244,16 +245,17 @@ render_ring_add_request(struct intel_ring_buffer *ring, seqno = i915_gem_get_seqno(dev); if (IS_GEN6(dev)) { - intel_ring_begin(ring, 6); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3); - intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 6) == 0) { + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3); + intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | + PIPE_CONTROL_NOTIFY); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + } } else if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; @@ -262,38 +264,40 @@ render_ring_add_request(struct intel_ring_buffer *ring, * PIPE_NOTIFY buffers out to memory before requesting * an interrupt. */ - intel_ring_begin(ring, 32); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 32) == 0) { + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + } } else { - intel_ring_begin(ring, 4); - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); + if (intel_ring_begin(ring, 4) == 0) { + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); + } } return seqno; } @@ -359,10 +363,11 @@ bsd_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { - intel_ring_begin(ring, 2); - intel_ring_emit(ring, MI_FLUSH); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 2) == 0) { + intel_ring_emit(ring, MI_FLUSH); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } } static u32 @@ -373,12 +378,13 @@ ring_add_request(struct intel_ring_buffer *ring, seqno = i915_gem_get_seqno(ring->dev); - intel_ring_begin(ring, 4); - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 4) == 0) { + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); + } DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); @@ -409,10 +415,14 @@ ring_dispatch_execbuffer(struct intel_ring_buffer *ring, uint64_t exec_offset) { uint32_t exec_start; + int ret; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - intel_ring_begin(ring, 2); + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + intel_ring_emit(ring, MI_BATCH_BUFFER_START | (2 << 6) | @@ -432,8 +442,8 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; - int i = 0, count; uint32_t exec_start, exec_len; + int i, count, ret; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; @@ -441,23 +451,28 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1); count = nbox ? nbox : 1; - for (i = 0; i < count; i++) { if (i < nbox) { - int ret = i915_emit_box(dev, cliprects, i, - exec->DR1, exec->DR4); + ret = i915_emit_box(dev, cliprects, i, + exec->DR1, exec->DR4); if (ret) return ret; } if (IS_I830(dev) || IS_845G(dev)) { - intel_ring_begin(ring, 4); + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; + intel_ring_emit(ring, MI_BATCH_BUFFER); intel_ring_emit(ring, exec_start | MI_BATCH_NON_SECURE); intel_ring_emit(ring, exec_start + exec_len - 4); intel_ring_emit(ring, 0); } else { - intel_ring_begin(ring, 2); + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + if (INTEL_INFO(dev)->gen >= 4) { intel_ring_emit(ring, MI_BATCH_BUFFER_START | (2 << 6) @@ -474,12 +489,13 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, } if (IS_G4X(dev) || IS_GEN5(dev)) { - intel_ring_begin(ring, 2); - intel_ring_emit(ring, MI_FLUSH | - MI_NO_WRITE_FLUSH | - MI_INVALIDATE_ISP ); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 2) == 0) { + intel_ring_emit(ring, MI_FLUSH | + MI_NO_WRITE_FLUSH | + MI_INVALIDATE_ISP ); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } } /* XXX breadcrumb */ @@ -693,18 +709,26 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) return -EBUSY; } -void intel_ring_begin(struct intel_ring_buffer *ring, - int num_dwords) +int intel_ring_begin(struct intel_ring_buffer *ring, + int num_dwords) { int n = 4*num_dwords; + int ret; - if (unlikely(ring->tail + n > ring->size)) - intel_wrap_ring_buffer(ring); + if (unlikely(ring->tail + n > ring->size)) { + ret = intel_wrap_ring_buffer(ring); + if (unlikely(ret)) + return ret; + } - if (unlikely(ring->space < n)) - intel_wait_ring_buffer(ring, n); + if (unlikely(ring->space < n)) { + ret = intel_wait_ring_buffer(ring, n); + if (unlikely(ret)) + return ret; + } ring->space -= n; + return 0; } void intel_ring_advance(struct intel_ring_buffer *ring) @@ -772,12 +796,13 @@ static void gen6_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { - intel_ring_begin(ring, 4); - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); + if (intel_ring_begin(ring, 4) == 0) { + intel_ring_emit(ring, MI_FLUSH_DW); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + } } static int @@ -787,10 +812,14 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, uint64_t exec_offset) { uint32_t exec_start; + int ret; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - intel_ring_begin(ring, 2); + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); /* bit0-7 is the length on GEN6+ */ intel_ring_emit(ring, exec_start); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index ba4a393e6d16..35ece2b87b02 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -100,8 +100,8 @@ intel_read_status_page(struct intel_ring_buffer *ring, } void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); -int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); -void intel_ring_begin(struct intel_ring_buffer *ring, int n); +int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); +int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); static inline void intel_ring_emit(struct intel_ring_buffer *ring, u32 data) -- cgit v1.2.3 From 7e318e18f248416a3d32a1649a9b4538e7f8b0eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 13:43:39 +0100 Subject: drm/i915: Move object to GPU domains after dispatching execbuffer In the event that we fail to dispatch the execbuffer, for example if there is insufficient space on the ring, we were leaving the objects in an inconsistent state. Notably they were marked as being in the GPU write domain, but were not added to the ring or any list. This would lead to inevitable oops: [ 1010.522940] [drm:i915_gem_do_execbuffer] *ERROR* dispatch failed -16 [ 1010.523055] BUG: unable to handle kernel NULL pointer dereference at 0000000000000088 [ 1010.523097] IP: [] i915_gem_flush_ring+0x26/0x140 [ 1010.523120] PGD 14cf2f067 PUD 14ce04067 PMD 0 [ 1010.523140] Oops: 0000 [#1] SMP [ 1010.523154] last sysfs file: /sys/devices/virtual/vc/vcsa2/uevent [ 1010.523173] CPU 0 [ 1010.523183] Pid: 716, comm: X Not tainted 2.6.36+ #34 LosLunas CRB/SandyBridge Platform [ 1010.523206] RIP: 0010:[] [] i915_gem_flush_ring+0x26/0x140 [ 1010.523233] RSP: 0018:ffff88014bf97cd8 EFLAGS: 00010296 [ 1010.523249] RAX: ffff88014e2d1808 RBX: 0000000000000000 RCX: 0000000000000000 [ 1010.523270] RDX: 0000000000000002 RSI: 0000000000000000 RDI: 0000000000000000 [ 1010.523290] RBP: ffff88014e2d1000 R08: 0000000000000002 R09: 00000000400c645f [ 1010.523311] R10: 0000000000000001 R11: 0000000000000246 R12: 0000000000000002 [ 1010.523331] R13: ffff88014e29a000 R14: 00000000000000c8 R15: ffffffff8162eb28 [ 1010.523352] FS: 00007fc62379d700(0000) GS:ffff88001fc00000(0000) knlGS:0000000000000000 [ 1010.523375] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1010.523392] CR2: 0000000000000088 CR3: 000000014bf87000 CR4: 00000000000406f0 [ 1010.523412] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 1010.523433] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 1010.523454] Process X (pid: 716, threadinfo ffff88014bf96000, task ffff88014cc1ee40) [ 1010.523475] Stack: [ 1010.523483] ffff88014d5199c0 0000000000000200 0000000000000000 ffff88014bcc6400 [ 1010.523509] <0> 0000000000000000 0000000000000001 ffff88014e29a000 ffff88014bcc6400 [ 1010.523537] <0> ffffffff8162eb28 ffffffff8122faa8 ffff88014e29a000 ffff88014bcc6400 [ 1010.523568] Call Trace: [ 1010.523578] [] ? i915_gem_object_flush_gpu_write_domain+0x48/0x80 [ 1010.523601] [] ? i915_gem_object_set_to_gtt_domain+0x2e/0xb0 [ 1010.523623] [] ? i915_gem_set_domain_ioctl+0xdb/0x1f0 [ 1010.523644] [] ? drm_ioctl+0x3d1/0x460 [ 1010.523660] [] ? i915_gem_set_domain_ioctl+0x0/0x1f0 [ 1010.523682] [] ? vma_prio_tree_insert+0x28/0x120 [ 1010.523701] [] ? vma_link+0x99/0xf0 [ 1010.523717] [] ? mmap_region+0x1ed/0x4f0 [ 1010.523734] [] ? do_vfs_ioctl+0x9f/0x580 [ 1010.523750] [] ? sys_ioctl+0x49/0x80 [ 1010.523767] [] ? system_call_fastpath+0x16/0x1b [ 1010.523785] Code: 00 00 00 00 00 41 57 89 ce 41 56 41 55 41 54 45 89 c4 55 48 89 fd 53 48 89 d3 44 89 c2 48 89 df 4c 8d b3 c8 00 00 00 48 83 ec 18 93 88 00 00 00 48 8b 83 c8 00 00 00 4c 8b bd 30 03 00 00 48 [ 1010.523946] RIP [] i915_gem_flush_ring+0x26/0x140 [ 1010.523966] RSP [ 1010.523977] CR2: 0000000000000088 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 68 ++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 00e901483ba5..580244c1e793 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3085,9 +3085,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t invalidate_domains = 0; uint32_t flush_domains = 0; - uint32_t old_read_domains; - - intel_mark_busy(dev, obj); /* * If the object isn't moving to a new write domain, @@ -3095,8 +3092,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, */ if (obj->pending_write_domain == 0) obj->pending_read_domains |= obj->read_domains; - else - obj_priv->dirty = 1; /* * Flush the current write domain if @@ -3118,8 +3113,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); - old_read_domains = obj->read_domains; - /* The actual obj->write_domain will be updated with * pending_write_domain after we emit the accumulated flush for all * of our domain changes in execbuffers (which clears objects' @@ -3128,7 +3121,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, */ if (flush_domains == 0 && obj->pending_write_domain == 0) obj->pending_write_domain = obj->write_domain; - obj->read_domains = obj->pending_read_domains; dev->invalidate_domains |= invalidate_domains; dev->flush_domains |= flush_domains; @@ -3136,10 +3128,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, dev_priv->mm.flush_rings |= obj_priv->ring->id; if (invalidate_domains & I915_GEM_GPU_DOMAINS) dev_priv->mm.flush_rings |= ring->id; - - trace_i915_gem_object_change_domain(obj, - old_read_domains, - obj->write_domain); } /** @@ -3602,7 +3590,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object **object_list = NULL; struct drm_gem_object *batch_obj; - struct drm_i915_gem_object *obj_priv; struct drm_clip_rect *cliprects = NULL; struct drm_i915_gem_request *request = NULL; int ret, i, flips; @@ -3697,6 +3684,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Look up object handles */ for (i = 0; i < args->buffer_count; i++) { + struct drm_i915_gem_object *obj_priv; + object_list[i] = drm_gem_object_lookup(dev, file, exec_list[i].handle); if (object_list[i] == NULL) { @@ -3761,13 +3750,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev->invalidate_domains = 0; dev->flush_domains = 0; dev_priv->mm.flush_rings = 0; - - for (i = 0; i < args->buffer_count; i++) { - struct drm_gem_object *obj = object_list[i]; - - /* Compute new gpu domains and update invalidate/flush */ - i915_gem_object_set_to_gpu_domain(obj, ring); - } + for (i = 0; i < args->buffer_count; i++) + i915_gem_object_set_to_gpu_domain(object_list[i], ring); if (dev->invalidate_domains | dev->flush_domains) { #if WATCH_EXEC @@ -3782,15 +3766,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev_priv->mm.flush_rings); } - for (i = 0; i < args->buffer_count; i++) { - struct drm_gem_object *obj = object_list[i]; - uint32_t old_write_domain = obj->write_domain; - obj->write_domain = obj->pending_write_domain; - trace_i915_gem_object_change_domain(obj, - obj->read_domains, - old_write_domain); - } - #if WATCH_COHERENCY for (i = 0; i < args->buffer_count; i++) { i915_gem_object_check_coherency(object_list[i], @@ -3843,30 +3818,41 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - /* - * Ensure that the commands in the batch buffer are - * finished before the interrupt fires - */ - i915_retire_commands(dev, ring); - for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; + obj->read_domains = obj->pending_read_domains; + obj->write_domain = obj->pending_write_domain; + i915_gem_object_move_to_active(obj, ring); - if (obj->write_domain) - list_move_tail(&to_intel_bo(obj)->gpu_write_list, + if (obj->write_domain) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + obj_priv->dirty = 1; + list_move_tail(&obj_priv->gpu_write_list, &ring->gpu_write_list); + intel_mark_busy(dev, obj); + } + + trace_i915_gem_object_change_domain(obj, + obj->read_domains, + obj->write_domain); } + /* + * Ensure that the commands in the batch buffer are + * finished before the interrupt fires + */ + i915_retire_commands(dev, ring); + i915_add_request(dev, file, request, ring); request = NULL; err: for (i = 0; i < args->buffer_count; i++) { - if (object_list[i]) { - obj_priv = to_intel_bo(object_list[i]); - obj_priv->in_execbuffer = false; - } + if (object_list[i] == NULL) + break; + + to_intel_bo(object_list[i])->in_execbuffer = false; drm_gem_object_unreference(object_list[i]); } -- cgit v1.2.3 From 893eead092f14e42cac054a394a86e3c6e016b68 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 14:44:35 +0100 Subject: drm/i915: Fix hangcheck to handle multiple rings Currently, we believe the GPU is idle if just the RENDER ring is idle. This is obviously wrong if we only using either the BLT or the BSD rings and so masking genuine hangs. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 74 +++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8acdd6d857d3..23b28528c642 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1307,12 +1307,29 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } -static struct drm_i915_gem_request * -i915_get_tail_request(struct drm_device *dev) +static u32 +ring_last_seqno(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - return list_entry(dev_priv->render_ring.request_list.prev, - struct drm_i915_gem_request, list); + return list_entry(ring->request_list.prev, + struct drm_i915_gem_request, list)->seqno; +} + +static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) +{ + if (list_empty(&ring->request_list) || + i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) { + /* Issue a wake-up to catch stuck h/w. */ + if (ring->waiting_gem_seqno && waitqueue_active(&ring->irq_queue)) { + DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n", + ring->name, + ring->waiting_gem_seqno, + ring->get_seqno(ring)); + wake_up_all(&ring->irq_queue); + *err = true; + } + return true; + } + return false; } /** @@ -1326,6 +1343,17 @@ void i915_hangcheck_elapsed(unsigned long data) struct drm_device *dev = (struct drm_device *)data; drm_i915_private_t *dev_priv = dev->dev_private; uint32_t acthd, instdone, instdone1; + bool err = false; + + /* If all work is done then ACTHD clearly hasn't advanced. */ + if (i915_hangcheck_ring_idle(&dev_priv->render_ring, &err) && + i915_hangcheck_ring_idle(&dev_priv->bsd_ring, &err) && + i915_hangcheck_ring_idle(&dev_priv->blt_ring, &err)) { + dev_priv->hangcheck_count = 0; + if (err) + goto repeat; + return; + } if (INTEL_INFO(dev)->gen < 4) { acthd = I915_READ(ACTHD); @@ -1337,38 +1365,6 @@ void i915_hangcheck_elapsed(unsigned long data) instdone1 = I915_READ(INSTDONE1); } - /* If all work is done then ACTHD clearly hasn't advanced. */ - if (list_empty(&dev_priv->render_ring.request_list) || - i915_seqno_passed(dev_priv->render_ring.get_seqno(&dev_priv->render_ring), - i915_get_tail_request(dev)->seqno)) { - bool missed_wakeup = false; - - dev_priv->hangcheck_count = 0; - - /* Issue a wake-up to catch stuck h/w. */ - if (dev_priv->render_ring.waiting_gem_seqno && - waitqueue_active(&dev_priv->render_ring.irq_queue)) { - wake_up_all(&dev_priv->render_ring.irq_queue); - missed_wakeup = true; - } - - if (dev_priv->bsd_ring.waiting_gem_seqno && - waitqueue_active(&dev_priv->bsd_ring.irq_queue)) { - wake_up_all(&dev_priv->bsd_ring.irq_queue); - missed_wakeup = true; - } - - if (dev_priv->blt_ring.waiting_gem_seqno && - waitqueue_active(&dev_priv->blt_ring.irq_queue)) { - wake_up_all(&dev_priv->blt_ring.irq_queue); - missed_wakeup = true; - } - - if (missed_wakeup) - DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n"); - return; - } - if (dev_priv->last_acthd == acthd && dev_priv->last_instdone == instdone && dev_priv->last_instdone1 == instdone1) { @@ -1385,7 +1381,7 @@ void i915_hangcheck_elapsed(unsigned long data) if (tmp & RING_WAIT) { I915_WRITE(PRB0_CTL, tmp); POSTING_READ(PRB0_CTL); - goto out; + goto repeat; } } @@ -1400,7 +1396,7 @@ void i915_hangcheck_elapsed(unsigned long data) dev_priv->last_instdone1 = instdone1; } -out: +repeat: /* Reset timer case chip hangs without another request being added */ mod_timer(&dev_priv->hangcheck_timer, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); -- cgit v1.2.3 From c2c347a9eeda1b9b69c8fc393fd933747fbb2e11 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 15:11:53 +0100 Subject: drm/i915/debugfs: Include info for the other rings The render ring is not alone any more! And the other rings are just as troublesome... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 134 ++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 2 files changed, 94 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c1b04b6056da..c5aa6bee3abb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -48,6 +48,12 @@ enum { DEFERRED_FREE_LIST, }; +enum { + RENDER_RING, + BSD_RING, + BLT_RING, +}; + static const char *yesno(int v) { return v ? "yes" : "no"; @@ -265,21 +271,51 @@ static int i915_gem_request_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_request *gem_request; - int ret; + int ret, count; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - seq_printf(m, "Request:\n"); - list_for_each_entry(gem_request, &dev_priv->render_ring.request_list, - list) { - seq_printf(m, " %d @ %d\n", - gem_request->seqno, - (int) (jiffies - gem_request->emitted_jiffies)); + count = 0; + if (!list_empty(&dev_priv->render_ring.request_list)) { + seq_printf(m, "Render requests:\n"); + list_for_each_entry(gem_request, + &dev_priv->render_ring.request_list, + list) { + seq_printf(m, " %d @ %d\n", + gem_request->seqno, + (int) (jiffies - gem_request->emitted_jiffies)); + } + count++; + } + if (!list_empty(&dev_priv->bsd_ring.request_list)) { + seq_printf(m, "BSD requests:\n"); + list_for_each_entry(gem_request, + &dev_priv->bsd_ring.request_list, + list) { + seq_printf(m, " %d @ %d\n", + gem_request->seqno, + (int) (jiffies - gem_request->emitted_jiffies)); + } + count++; + } + if (!list_empty(&dev_priv->blt_ring.request_list)) { + seq_printf(m, "BLT requests:\n"); + list_for_each_entry(gem_request, + &dev_priv->blt_ring.request_list, + list) { + seq_printf(m, " %d @ %d\n", + gem_request->seqno, + (int) (jiffies - gem_request->emitted_jiffies)); + } + count++; } mutex_unlock(&dev->struct_mutex); + if (count == 0) + seq_printf(m, "No requests\n"); + return 0; } @@ -354,11 +390,17 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } seq_printf(m, "Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - if (dev_priv->render_ring.status_page.page_addr != NULL) { - seq_printf(m, "Current sequence: %d\n", + if (dev_priv->render_ring.get_seqno) { + seq_printf(m, "Current sequence (render): %d\n", dev_priv->render_ring.get_seqno(&dev_priv->render_ring)); - } else { - seq_printf(m, "Current sequence: hws uninitialized\n"); + } + if (dev_priv->bsd_ring.get_seqno) { + seq_printf(m, "Current sequence (BSD): %d\n", + dev_priv->bsd_ring.get_seqno(&dev_priv->bsd_ring)); + } + if (dev_priv->blt_ring.get_seqno) { + seq_printf(m, "Current sequence (BLT): %d\n", + dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring)); } seq_printf(m, "Waiter sequence: %d\n", dev_priv->mm.waiting_gem_seqno); @@ -385,24 +427,12 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_gem_object *obj = dev_priv->fence_regs[i].obj; - if (obj == NULL) { - seq_printf(m, "Fenced object[%2d] = unused\n", i); - } else { - struct drm_i915_gem_object *obj_priv; - - obj_priv = to_intel_bo(obj); - seq_printf(m, "Fenced object[%2d] = %p: %s " - "%08x %08zx %08x %s %08x %08x %d", - i, obj, get_pin_flag(obj_priv), - obj_priv->gtt_offset, - obj->size, obj_priv->stride, - get_tiling_flag(obj_priv), - obj->read_domains, obj->write_domain, - obj_priv->last_rendering_seqno); - if (obj->name) - seq_printf(m, " (name: %d)", obj->name); - seq_printf(m, "\n"); - } + seq_printf(m, "Fenced object[%2d] = ", i); + if (obj == NULL) + seq_printf(m, "unused"); + else + describe_obj(m, to_intel_bo(obj)); + seq_printf(m, "\n"); } mutex_unlock(&dev->struct_mutex); @@ -477,19 +507,27 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; int ret; + switch ((uintptr_t)node->info_ent->data) { + case RENDER_RING: ring = &dev_priv->render_ring; break; + case BSD_RING: ring = &dev_priv->bsd_ring; break; + case BLT_RING: ring = &dev_priv->blt_ring; break; + default: return -EINVAL; + } + ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - if (!dev_priv->render_ring.gem_object) { + if (!ring->gem_object) { seq_printf(m, "No ringbuffer setup\n"); } else { - u8 *virt = dev_priv->render_ring.virtual_start; + u8 *virt = ring->virtual_start; uint32_t off; - for (off = 0; off < dev_priv->render_ring.size; off += 4) { + for (off = 0; off < ring->size; off += 4) { uint32_t *ptr = (uint32_t *)(virt + off); seq_printf(m, "%08x : %08x\n", off, *ptr); } @@ -504,15 +542,25 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - unsigned int head, tail; + struct intel_ring_buffer *ring; + + switch ((uintptr_t)node->info_ent->data) { + case RENDER_RING: ring = &dev_priv->render_ring; break; + case BSD_RING: ring = &dev_priv->bsd_ring; break; + case BLT_RING: ring = &dev_priv->blt_ring; break; + default: return -EINVAL; + } - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; + if (ring->size == 0) + return 0; - seq_printf(m, "RingHead : %08x\n", head); - seq_printf(m, "RingTail : %08x\n", tail); - seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size); - seq_printf(m, "Acthd : %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD)); + seq_printf(m, "Ring %s:\n", ring->name); + seq_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR); + seq_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR); + seq_printf(m, " Size : %08x\n", ring->size); + seq_printf(m, " Active : %08x\n", intel_ring_get_active_head(ring)); + seq_printf(m, " Control : %08x\n", I915_READ_CTL(ring)); + seq_printf(m, " Start : %08x\n", I915_READ_START(ring)); return 0; } @@ -1029,8 +1077,12 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, {"i915_gem_interrupt", i915_interrupt_info, 0}, {"i915_gem_hws", i915_hws_info, 0}, - {"i915_ringbuffer_data", i915_ringbuffer_data, 0}, - {"i915_ringbuffer_info", i915_ringbuffer_info, 0}, + {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RENDER_RING}, + {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RENDER_RING}, + {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BSD_RING}, + {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BSD_RING}, + {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BLT_RING}, + {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BLT_RING}, {"i915_batchbuffers", i915_batchbuffer_info, 0}, {"i915_error_state", i915_error_state, 0}, {"i915_rstdby_delays", i915_rstdby_delays, 0}, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 35ece2b87b02..84f6919de8e0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -25,7 +25,6 @@ struct intel_ring_buffer { RING_BLT = 0x4, } id; u32 mmio_base; - unsigned long size; void *virtual_start; struct drm_device *dev; struct drm_gem_object *gem_object; @@ -33,6 +32,7 @@ struct intel_ring_buffer { unsigned int head; unsigned int tail; int space; + int size; struct intel_hw_status_page status_page; u32 irq_gem_seqno; /* last seq seem at irq time */ -- cgit v1.2.3 From b2223497b44a4701d1be873d1e9453d7f720043b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 15:27:33 +0100 Subject: drm/i915: Remove the confusing global waiting/irq seqno Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 44 ++++++++++++++------------------- drivers/gpu/drm/i915/i915_drv.h | 10 -------- drivers/gpu/drm/i915/i915_gem.c | 4 +-- drivers/gpu/drm/i915/i915_irq.c | 6 ++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +-- 5 files changed, 26 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c5aa6bee3abb..beb3de7921b5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -319,6 +319,19 @@ static int i915_gem_request_info(struct seq_file *m, void *data) return 0; } +static void i915_ring_seqno_info(struct seq_file *m, + struct intel_ring_buffer *ring) +{ + if (ring->get_seqno) { + seq_printf(m, "Current sequence (%s): %d\n", + ring->name, ring->get_seqno(ring)); + seq_printf(m, "Waiter sequence (%s): %d\n", + ring->name, ring->waiting_seqno); + seq_printf(m, "IRQ sequence (%s): %d\n", + ring->name, ring->irq_seqno); + } +} + static int i915_gem_seqno_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -330,15 +343,9 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) if (ret) return ret; - if (dev_priv->render_ring.status_page.page_addr != NULL) { - seq_printf(m, "Current sequence: %d\n", - dev_priv->render_ring.get_seqno(&dev_priv->render_ring)); - } else { - seq_printf(m, "Current sequence: hws uninitialized\n"); - } - seq_printf(m, "Waiter sequence: %d\n", - dev_priv->mm.waiting_gem_seqno); - seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno); + i915_ring_seqno_info(m, &dev_priv->render_ring); + i915_ring_seqno_info(m, &dev_priv->bsd_ring); + i915_ring_seqno_info(m, &dev_priv->blt_ring); mutex_unlock(&dev->struct_mutex); @@ -390,22 +397,9 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } seq_printf(m, "Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - if (dev_priv->render_ring.get_seqno) { - seq_printf(m, "Current sequence (render): %d\n", - dev_priv->render_ring.get_seqno(&dev_priv->render_ring)); - } - if (dev_priv->bsd_ring.get_seqno) { - seq_printf(m, "Current sequence (BSD): %d\n", - dev_priv->bsd_ring.get_seqno(&dev_priv->bsd_ring)); - } - if (dev_priv->blt_ring.get_seqno) { - seq_printf(m, "Current sequence (BLT): %d\n", - dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring)); - } - seq_printf(m, "Waiter sequence: %d\n", - dev_priv->mm.waiting_gem_seqno); - seq_printf(m, "IRQ sequence: %d\n", - dev_priv->mm.irq_gem_seqno); + i915_ring_seqno_info(m, &dev_priv->render_ring); + i915_ring_seqno_info(m, &dev_priv->bsd_ring); + i915_ring_seqno_info(m, &dev_priv->blt_ring); mutex_unlock(&dev->struct_mutex); return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c241468c632e..2af8e1604b44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -608,16 +608,6 @@ typedef struct drm_i915_private { */ struct delayed_work retire_work; - /** - * Waiting sequence number, if any - */ - uint32_t waiting_gem_seqno; - - /** - * Last seq seen at irq time - */ - uint32_t irq_gem_seqno; - /** * Flag if the X Server, and thus DRM, is not currently in * control of the device. diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 580244c1e793..74f5525d156f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1984,7 +1984,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, trace_i915_gem_request_wait_begin(dev, seqno); - ring->waiting_gem_seqno = seqno; + ring->waiting_seqno = seqno; ring->user_irq_get(ring); if (interruptible) ret = wait_event_interruptible(ring->irq_queue, @@ -1996,7 +1996,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, || atomic_read(&dev_priv->mm.wedged)); ring->user_irq_put(ring); - ring->waiting_gem_seqno = 0; + ring->waiting_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 23b28528c642..29cbcb33b92c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -298,7 +298,7 @@ static void notify_ring(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; u32 seqno = ring->get_seqno(ring); - ring->irq_gem_seqno = seqno; + ring->irq_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); wake_up_all(&ring->irq_queue); dev_priv->hangcheck_count = 0; @@ -1319,10 +1319,10 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) if (list_empty(&ring->request_list) || i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) { /* Issue a wake-up to catch stuck h/w. */ - if (ring->waiting_gem_seqno && waitqueue_active(&ring->irq_queue)) { + if (ring->waiting_seqno && waitqueue_active(&ring->irq_queue)) { DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n", ring->name, - ring->waiting_gem_seqno, + ring->waiting_seqno, ring->get_seqno(ring)); wake_up_all(&ring->irq_queue); *err = true; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 84f6919de8e0..7ad9e94220b4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -35,8 +35,8 @@ struct intel_ring_buffer { int size; struct intel_hw_status_page status_page; - u32 irq_gem_seqno; /* last seq seem at irq time */ - u32 waiting_gem_seqno; + u32 irq_seqno; /* last seq seem at irq time */ + u32 waiting_seqno; int user_irq_refcount; void (*user_irq_get)(struct intel_ring_buffer *ring); void (*user_irq_put)(struct intel_ring_buffer *ring); -- cgit v1.2.3 From 3cce469cab880ef8990d2d16d745bf85443fc998 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 16:11:02 +0100 Subject: drm/i915: Propagate error from failing to queue a request Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 8 +- drivers/gpu/drm/i915/i915_gem.c | 36 ++++++--- drivers/gpu/drm/i915/intel_overlay.c | 20 +++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 128 +++++++++++++++++--------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +- 5 files changed, 111 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2af8e1604b44..f168e82c10aa 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1041,10 +1041,10 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end); int i915_gpu_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev); -uint32_t i915_add_request(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring); +int i915_add_request(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_i915_gem_request *request, + struct intel_ring_buffer *ring); int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 74f5525d156f..d0aaf97ac6e0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1683,7 +1683,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, } } -uint32_t +int i915_add_request(struct drm_device *dev, struct drm_file *file, struct drm_i915_gem_request *request, @@ -1693,17 +1693,17 @@ i915_add_request(struct drm_device *dev, struct drm_i915_file_private *file_priv = NULL; uint32_t seqno; int was_empty; + int ret; + + BUG_ON(request == NULL); if (file != NULL) file_priv = file->driver_priv; - if (request == NULL) { - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return 0; - } + ret = ring->add_request(ring, &seqno); + if (ret) + return ret; - seqno = ring->add_request(ring, 0); ring->outstanding_lazy_request = false; request->seqno = seqno; @@ -1727,7 +1727,7 @@ i915_add_request(struct drm_device *dev, queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); } - return seqno; + return 0; } /** @@ -1964,9 +1964,19 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, return -EAGAIN; if (ring->outstanding_lazy_request) { - seqno = i915_add_request(dev, NULL, NULL, ring); - if (seqno == 0) + struct drm_i915_gem_request *request; + + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) return -ENOMEM; + + ret = i915_add_request(dev, NULL, request, ring); + if (ret) { + kfree(request); + return ret; + } + + seqno = request->seqno; } BUG_ON(seqno == dev_priv->next_seqno); @@ -3844,8 +3854,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ i915_retire_commands(dev, ring); - i915_add_request(dev, file, request, ring); - request = NULL; + if (i915_add_request(dev, file, request, ring)) + ring->outstanding_lazy_request = true; + else + request = NULL; err: for (i = 0; i < args->buffer_count; i++) { diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 78fa6a249964..2d4a6968cd76 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -221,11 +221,12 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, int ret; BUG_ON(overlay->last_flip_req); - overlay->last_flip_req = - i915_add_request(dev, NULL, request, &dev_priv->render_ring); - if (overlay->last_flip_req == 0) - return -ENOMEM; - + ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring); + if (ret) { + kfree(request); + return ret; + } + overlay->last_flip_req = request->seqno; overlay->flip_tail = tail; ret = i915_do_wait_request(dev, overlay->last_flip_req, true, @@ -363,8 +364,13 @@ static int intel_overlay_continue(struct intel_overlay *overlay, OUT_RING(flip_addr); ADVANCE_LP_RING(); - overlay->last_flip_req = - i915_add_request(dev, NULL, request, &dev_priv->render_ring); + ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring); + if (ret) { + kfree(request); + return ret; + } + + overlay->last_flip_req = request->seqno; return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6fe42c1f4ea9..4803b32f308f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -234,28 +234,28 @@ do { \ * * Returned sequence numbers are nonzero on success. */ -static u32 +static int render_ring_add_request(struct intel_ring_buffer *ring, - u32 flush_domains) + u32 *result) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 seqno; - - seqno = i915_gem_get_seqno(dev); + u32 seqno = i915_gem_get_seqno(dev); + int ret; if (IS_GEN6(dev)) { - if (intel_ring_begin(ring, 6) == 0) { - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3); - intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); - } + ret = intel_ring_begin(ring, 6); + if (ret) + return ret; + + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3); + intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | + PIPE_CONTROL_NOTIFY); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); } else if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; @@ -264,42 +264,47 @@ render_ring_add_request(struct intel_ring_buffer *ring, * PIPE_NOTIFY buffers out to memory before requesting * an interrupt. */ - if (intel_ring_begin(ring, 32) == 0) { - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); - } + ret = intel_ring_begin(ring, 32); + if (ret) + return ret; + + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); } else { - if (intel_ring_begin(ring, 4) == 0) { - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); - } + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + + intel_ring_emit(ring, MI_USER_INTERRUPT); } - return seqno; + + intel_ring_advance(ring); + *result = seqno; + return 0; } static u32 @@ -370,25 +375,28 @@ bsd_ring_flush(struct intel_ring_buffer *ring, } } -static u32 +static int ring_add_request(struct intel_ring_buffer *ring, - u32 flush_domains) + u32 *result) { u32 seqno; + int ret; + + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; seqno = i915_gem_get_seqno(ring->dev); - if (intel_ring_begin(ring, 4) == 0) { - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); - } + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); - - return seqno; + *result = seqno; + return 0; } static void diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 7ad9e94220b4..acd23374fe89 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -48,8 +48,8 @@ struct intel_ring_buffer { void (*flush)(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains); - u32 (*add_request)(struct intel_ring_buffer *ring, - u32 flush_domains); + int (*add_request)(struct intel_ring_buffer *ring, + u32 *seqno); u32 (*get_seqno)(struct intel_ring_buffer *ring); int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, struct drm_i915_gem_execbuffer2 *exec, -- cgit v1.2.3 From d935cc61d466f6cc7514032835f4fc379cb7e2ca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 16 Sep 2010 15:13:11 +0200 Subject: drm_mm: add support for range-restricted fair-lru scans Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/drm_mm.c | 40 +++++++++++++++++++++++++++++++++++++++- include/drm/drm_mm.h | 7 +++++++ 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index a6bfc302ed90..c59515ba7e69 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -392,9 +392,35 @@ void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, mm->scanned_blocks = 0; mm->scan_hit_start = 0; mm->scan_hit_size = 0; + mm->scan_check_range = 0; } EXPORT_SYMBOL(drm_mm_init_scan); +/** + * Initializa lru scanning. + * + * This simply sets up the scanning routines with the parameters for the desired + * hole. This version is for range-restricted scans. + * + * Warning: As long as the scan list is non-empty, no other operations than + * adding/removing nodes to/from the scan list are allowed. + */ +void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size, + unsigned alignment, + unsigned long start, + unsigned long end) +{ + mm->scan_alignment = alignment; + mm->scan_size = size; + mm->scanned_blocks = 0; + mm->scan_hit_start = 0; + mm->scan_hit_size = 0; + mm->scan_start = start; + mm->scan_end = end; + mm->scan_check_range = 1; +} +EXPORT_SYMBOL(drm_mm_init_scan_with_range); + /** * Add a node to the scan list that might be freed to make space for the desired * hole. @@ -406,6 +432,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) struct drm_mm *mm = node->mm; struct list_head *prev_free, *next_free; struct drm_mm_node *prev_node, *next_node; + unsigned long adj_start; + unsigned long adj_end; mm->scanned_blocks++; @@ -452,7 +480,17 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) node->free_stack.prev = prev_free; node->free_stack.next = next_free; - if (check_free_hole(node->start, node->start + node->size, + if (mm->scan_check_range) { + adj_start = node->start < mm->scan_start ? + mm->scan_start : node->start; + adj_end = node->start + node->size > mm->scan_end ? + mm->scan_end : node->start + node->size; + } else { + adj_start = node->start; + adj_end = node->start + node->size; + } + + if (check_free_hole(adj_start , adj_end, mm->scan_size, mm->scan_alignment)) { mm->scan_hit_start = node->start; mm->scan_hit_size = node->size; diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index bf01531193d5..e39177778601 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -62,11 +62,14 @@ struct drm_mm { struct list_head unused_nodes; int num_unused; spinlock_t unused_lock; + unsigned int scan_check_range : 1; unsigned scan_alignment; unsigned long scan_size; unsigned long scan_hit_start; unsigned scan_hit_size; unsigned scanned_blocks; + unsigned long scan_start; + unsigned long scan_end; }; /* @@ -145,6 +148,10 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, unsigned alignment); +void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size, + unsigned alignment, + unsigned long start, + unsigned long end); int drm_mm_scan_add_block(struct drm_mm_node *node); int drm_mm_scan_remove_block(struct drm_mm_node *node); -- cgit v1.2.3 From a6e0aa421406dc4cfd736c6d07d26ed39ab4f7bc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 16 Sep 2010 15:45:15 +0200 Subject: drm/i915: range-restricted eviction support Add a mappable parameter to i915_gem_evict_something to distinguish the two cases (non-restricted vs. mappable gtt allocations). No functional changes because the mappable limit is set to the end of the gtt currently. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 5 ++++- drivers/gpu/drm/i915/i915_gem.c | 10 ++++++---- drivers/gpu/drm/i915/i915_gem_evict.c | 24 +++++++++++++++++++----- 3 files changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f168e82c10aa..dc0a21a3489b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -535,6 +535,8 @@ typedef struct drm_i915_private { struct drm_mm vram; /** Memory allocator for GTT */ struct drm_mm gtt_space; + /** End of mappable part of GTT */ + unsigned long gtt_mappable_end; struct io_mapping *gtt_mapping; int gtt_mtrr; @@ -1067,7 +1069,8 @@ void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); /* i915_gem_evict.c */ -int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment); +int i915_gem_evict_something(struct drm_device *dev, int min_size, + unsigned alignment, bool mappable); int i915_gem_evict_everything(struct drm_device *dev); int i915_gem_evict_inactive(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d0aaf97ac6e0..254eb0c46aeb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -187,6 +187,7 @@ int i915_gem_do_init(struct drm_device *dev, end - start); dev_priv->mm.gtt_total = end - start; + dev_priv->mm.gtt_mappable_end = end; return 0; } @@ -413,7 +414,8 @@ i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) struct drm_device *dev = obj->dev; ret = i915_gem_evict_something(dev, obj->size, - i915_gem_get_gtt_alignment(obj)); + i915_gem_get_gtt_alignment(obj), + false); if (ret) return ret; @@ -2672,7 +2674,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ - ret = i915_gem_evict_something(dev, obj->size, alignment); + ret = i915_gem_evict_something(dev, obj->size, alignment, true); if (ret) return ret; @@ -2687,7 +2689,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ ret = i915_gem_evict_something(dev, obj->size, - alignment); + alignment, true); if (ret) { /* now try to shrink everyone else */ if (gfpmask) { @@ -2717,7 +2719,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; - ret = i915_gem_evict_something(dev, obj->size, alignment); + ret = i915_gem_evict_something(dev, obj->size, alignment, true); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 43a4013f53fa..3a4215f31652 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -41,7 +41,8 @@ mark_free(struct drm_i915_gem_object *obj_priv, } int -i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment) +i915_gem_evict_something(struct drm_device *dev, int min_size, + unsigned alignment, bool mappable) { drm_i915_private_t *dev_priv = dev->dev_private; struct list_head eviction_list, unwind_list; @@ -51,9 +52,17 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen i915_gem_retire_requests(dev); /* Re-check for free space after retiring requests */ - if (drm_mm_search_free(&dev_priv->mm.gtt_space, - min_size, alignment, 0)) - return 0; + if (mappable) { + if (drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, + min_size, alignment, 0, + dev_priv->mm.gtt_mappable_end, + 0)) + return 0; + } else { + if (drm_mm_search_free(&dev_priv->mm.gtt_space, + min_size, alignment, 0)) + return 0; + } /* * The goal is to evict objects and amalgamate space in LRU order. @@ -79,7 +88,12 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen */ INIT_LIST_HEAD(&unwind_list); - drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); + if (mappable) + drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size, + alignment, 0, + dev_priv->mm.gtt_mappable_end); + else + drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); /* First see if there is a large enough contiguous idle region... */ list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) { -- cgit v1.2.3 From 920afa77ced7124c8bb7d0c4839885618a3b4a54 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 16 Sep 2010 17:54:23 +0200 Subject: drm/i915: range-restricted bind_to_gtt Like before add a parameter mappable (also to gem_object_pin) and set it depending upon the context. Only bos that are brought into the gtt due to an execbuffer call can be put into the unmappable part of the gtt, everything else (especially pinned objects) need to be put into the mappable part of the gtt. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gem.c | 63 +++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_display.c | 6 ++-- drivers/gpu/drm/i915/intel_overlay.c | 4 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +-- 5 files changed, 53 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dc0a21a3489b..263bb0506247 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1012,7 +1012,8 @@ int i915_gem_init_object(struct drm_gem_object *obj); struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); -int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment); +int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, + bool mappable); void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_release_mmap(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 254eb0c46aeb..ef14546fc08d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -51,7 +51,7 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, bool interruptible); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, - unsigned alignment); + unsigned alignment, bool mappable); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -1031,7 +1031,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, else if (obj_priv->tiling_mode == I915_TILING_NONE && obj_priv->gtt_space && obj->write_domain != I915_GEM_DOMAIN_CPU) { - ret = i915_gem_object_pin(obj, 0); + ret = i915_gem_object_pin(obj, 0, true); if (ret) goto out; @@ -1256,7 +1256,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Now bind it into the GTT if needed */ mutex_lock(&dev->struct_mutex); if (!obj_priv->gtt_space) { - ret = i915_gem_object_bind_to_gtt(obj, 0); + ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto unlock; @@ -1506,7 +1506,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, * initial fault faster and any subsequent flushing possible). */ if (!obj_priv->agp_mem) { - ret = i915_gem_object_bind_to_gtt(obj, 0); + ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto out; } @@ -2635,7 +2635,9 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, * Finds free space in the GTT aperture and binds the object there. */ static int -i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) +i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, + unsigned alignment, + bool mappable) { struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2659,22 +2661,42 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ - if (obj->size > dev_priv->mm.gtt_total) { + if (obj->size > + (mappable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } search_free: - free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, - obj->size, alignment, 0); - if (free_space != NULL) - obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size, - alignment); + if (mappable) + free_space = + drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, + obj->size, alignment, 0, + dev_priv->mm.gtt_mappable_end, + 0); + else + free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, + obj->size, alignment, 0); + + if (free_space != NULL) { + if (mappable) + obj_priv->gtt_space = + drm_mm_get_block_range_generic(free_space, + obj->size, + alignment, 0, + dev_priv->mm.gtt_mappable_end, + 0); + else + obj_priv->gtt_space = + drm_mm_get_block(free_space, obj->size, + alignment); + } if (obj_priv->gtt_space == NULL) { /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ - ret = i915_gem_evict_something(dev, obj->size, alignment, true); + ret = i915_gem_evict_something(dev, obj->size, alignment, + mappable); if (ret) return ret; @@ -2689,7 +2711,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ ret = i915_gem_evict_something(dev, obj->size, - alignment, true); + alignment, mappable); if (ret) { /* now try to shrink everyone else */ if (gfpmask) { @@ -2719,7 +2741,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; - ret = i915_gem_evict_something(dev, obj->size, alignment, true); + ret = i915_gem_evict_something(dev, obj->size, alignment, + mappable); if (ret) return ret; @@ -3456,7 +3479,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev, break; } - ret = i915_gem_object_pin(&obj->base, entry->alignment); + ret = i915_gem_object_pin(&obj->base, + entry->alignment, true); if (ret) break; @@ -4026,7 +4050,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, } int -i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) +i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, + bool mappable) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4051,7 +4076,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) } if (obj_priv->gtt_space == NULL) { - ret = i915_gem_object_bind_to_gtt(obj, alignment); + ret = i915_gem_object_bind_to_gtt(obj, alignment, mappable); if (ret) return ret; } @@ -4133,7 +4158,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, obj_priv->user_pin_count++; obj_priv->pin_filp = file_priv; if (obj_priv->user_pin_count == 1) { - ret = i915_gem_object_pin(obj, args->alignment); + ret = i915_gem_object_pin(obj, args->alignment, true); if (ret) goto out; } @@ -4445,7 +4470,7 @@ i915_gem_init_pipe_control(struct drm_device *dev) obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - ret = i915_gem_object_pin(obj, 4096); + ret = i915_gem_object_pin(obj, 4096, true); if (ret) goto err_unref; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb4c725e3069..c9c4c707cf1a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1461,7 +1461,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, BUG(); } - ret = i915_gem_object_pin(obj, alignment); + ret = i915_gem_object_pin(obj, alignment, true); if (ret) return ret; @@ -4353,7 +4353,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { - ret = i915_gem_object_pin(bo, PAGE_SIZE); + ret = i915_gem_object_pin(bo, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin cursor bo\n"); goto fail_locked; @@ -5517,7 +5517,7 @@ intel_alloc_context_page(struct drm_device *dev) } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(ctx, 4096); + ret = i915_gem_object_pin(ctx, 4096, true); if (ret) { DRM_ERROR("failed to pin power context: %d\n", ret); goto err_unref; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 2d4a6968cd76..beda2016eb16 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -781,7 +781,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) return ret; - ret = i915_gem_object_pin(new_bo, PAGE_SIZE); + ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true); if (ret != 0) return ret; @@ -1423,7 +1423,7 @@ void intel_setup_overlay(struct drm_device *dev) } overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; } else { - ret = i915_gem_object_pin(reg_bo, PAGE_SIZE); + ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin overlay register bo\n"); goto out_free_bo; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4803b32f308f..8eaa60cc5d25 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -546,7 +546,7 @@ static int init_status_page(struct intel_ring_buffer *ring) obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - ret = i915_gem_object_pin(obj, 4096); + ret = i915_gem_object_pin(obj, 4096, true); if (ret != 0) { goto err_unref; } @@ -602,7 +602,7 @@ int intel_init_ring_buffer(struct drm_device *dev, ring->gem_object = obj; - ret = i915_gem_object_pin(obj, PAGE_SIZE); + ret = i915_gem_object_pin(obj, PAGE_SIZE, true); if (ret) goto err_unref; -- cgit v1.2.3 From 16e809acc167c3ede231cafcdab1be93bab3e429 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 16 Sep 2010 19:37:04 +0200 Subject: drm/i915: unbind unmappable objects on fault/pin In i915_gem_object_pin obviously unbind only if mappable is true. This is the last part to enable gtt_mappable_end != gtt_size, which the next patch will do. v2: Fences on g33/pineview only work in the mappable part of the gtt. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ef14546fc08d..7b0680714101 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -260,6 +260,16 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, return 0; } +static bool +i915_gem_object_cpu_accessible(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + return obj->gtt_space == NULL || + obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; +} + static inline int fast_shmem_read(struct page **pages, loff_t page_base, int page_offset, @@ -1255,6 +1265,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Now bind it into the GTT if needed */ mutex_lock(&dev->struct_mutex); + if (!i915_gem_object_cpu_accessible(obj_priv)) + i915_gem_object_unbind(obj); + if (!obj_priv->gtt_space) { ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) @@ -3465,11 +3478,15 @@ i915_gem_execbuffer_pin(struct drm_device *dev, ret = 0; for (i = 0; i < count; i++) { struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; - struct drm_i915_gem_object *obj= to_intel_bo(object_list[i]); + struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); bool need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; + /* g33/pnv can't fence buffers in the unmappable part */ + bool need_mappable = + entry->relocation_count ? true : need_fence; + /* Check fence reg constraints and rebind if necessary */ if (need_fence && !i915_gem_object_fence_offset_ok(&obj->base, @@ -3480,7 +3497,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev, } ret = i915_gem_object_pin(&obj->base, - entry->alignment, true); + entry->alignment, + need_mappable); if (ret) break; @@ -4064,7 +4082,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, if (obj_priv->gtt_space != NULL) { if (alignment == 0) alignment = i915_gem_get_gtt_alignment(obj); - if (obj_priv->gtt_offset & (alignment - 1)) { + if (obj_priv->gtt_offset & (alignment - 1) || + (mappable && !i915_gem_object_cpu_accessible(obj_priv))) { WARN(obj_priv->pin_count, "bo is already pinned with incorrect alignment:" " offset=%x, req.alignment=%x\n", -- cgit v1.2.3 From 53984635a659e360f206a81ada4ae813152d72f1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Sep 2010 23:44:24 +0200 Subject: drm/i915: use the complete gtt At least the part that's currently enabled by the BIOS. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 14 +++++++++----- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 5 +++-- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 02daf4e5c8e6..1bd37e34c77e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1195,13 +1195,17 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) return can_switch; } -static int i915_load_modeset_init(struct drm_device *dev, - unsigned long prealloc_size, - unsigned long agp_size) +static int i915_load_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long prealloc_size, gtt_size, mappable_size; int ret = 0; + prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; + gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; + mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + gtt_size -= PAGE_SIZE; + /* Basic memrange allocator for stolen space (aka mm.vram) */ drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size); @@ -1214,7 +1218,7 @@ static int i915_load_modeset_init(struct drm_device *dev, * at the last page of the aperture. One page should be enough to * keep any prefetching inside of the aperture. */ - i915_gem_do_init(dev, prealloc_size, agp_size - 4096); + i915_gem_do_init(dev, prealloc_size, mappable_size, gtt_size); mutex_lock(&dev->struct_mutex); ret = i915_gem_init_ringbuffer(dev); @@ -2056,7 +2060,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_detect_pch(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = i915_load_modeset_init(dev, prealloc_size, agp_size); + ret = i915_load_modeset_init(dev); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); goto out_workqueue_free; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 263bb0506247..296ed38b292f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1041,7 +1041,7 @@ int i915_gem_object_set_domain(struct drm_gem_object *obj, int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, - unsigned long end); + unsigned long mappable_end, unsigned long end); int i915_gpu_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev); int i915_add_request(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7b0680714101..6d9971f0ed92 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -173,6 +173,7 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) int i915_gem_do_init(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -187,7 +188,7 @@ int i915_gem_do_init(struct drm_device *dev, end - start); dev_priv->mm.gtt_total = end - start; - dev_priv->mm.gtt_mappable_end = end; + dev_priv->mm.gtt_mappable_end = mappable_end; return 0; } @@ -200,7 +201,7 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, int ret; mutex_lock(&dev->struct_mutex); - ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end); + ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end, args->gtt_end); mutex_unlock(&dev->struct_mutex); return ret; -- cgit v1.2.3 From b3eafc5af02a799650757f2c5b2b0d4835dd0a5f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 23 Sep 2010 20:04:17 +0200 Subject: intel-gtt: save PGETBL_CTL later in the setup process ... and switch to a more classical store-reg-on-suspend, restore-on-resume way of doing things. Obviously this is just preparation for the future, the code is not there at all, yet. This is needed because the next patch adjusts this register and everything in it (not just the pagetable address) needs to be restored on resume. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 6b6760ea2435..fd3e94f8ab51 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -95,7 +95,7 @@ static struct _intel_private { u8 __iomem *registers; phys_addr_t gtt_bus_addr; phys_addr_t gma_bus_addr; - phys_addr_t pte_bus_addr; + u32 PGETBL_save; u32 __iomem *gtt; /* I915G */ int num_dcache_entries; union { @@ -755,6 +755,11 @@ static int intel_gtt_init(void) intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); intel_private.base.gtt_total_entries = intel_gtt_total_entries(); + /* save the PGETBL reg for resume */ + intel_private.PGETBL_save = + readl(intel_private.registers+I810_PGETBL_CTL) + & ~I810_PGETBL_ENABLED; + dev_info(&intel_private.bridge_dev->dev, "detected gtt size: %dK total, %dK mappable\n", intel_private.base.gtt_total_entries * 4, @@ -891,7 +896,7 @@ static void intel_enable_gtt(void) gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); - writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED, + writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ } @@ -908,8 +913,6 @@ static int i830_setup(void) return -ENOMEM; intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; - intel_private.pte_bus_addr = - readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; intel_i830_setup_flush(); @@ -1265,9 +1268,6 @@ static int i9xx_setup(void) intel_private.gtt_bus_addr = reg_addr + gtt_offset; } - intel_private.pte_bus_addr = - readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; - intel_i9xx_setup_flush(); return 0; -- cgit v1.2.3 From 201728429d6cf336cfd7483fcd1bce47291b2901 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Sep 2010 18:25:59 +0200 Subject: intel-gtt: maximize ggtt size on platforms that support this On VT-d supporting platforms the GGTT is allocated in a stolen mem section separate from graphcis stolen mem. The GMCH register contains a bitfield specifying the size of that region. Docs suggest that this region can only be used for GGTT and PPGTT. Hence ensure that the PPGTT is disabled and use the complete area for the GGTT. Unfortunately the graphics core on G33/Pineview can't cope with really large GTTs and the BIOS usually enables the maximum of 512MB. So don't bother with maximizing the GTT on these platforms. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.h | 14 +++++-- drivers/char/agp/intel-gtt.c | 96 ++++++++++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 90539df02504..010e3defd6c3 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -75,6 +75,8 @@ #define I810_GMS_DISABLE 0x00000000 #define I810_PGETBL_CTL 0x2020 #define I810_PGETBL_ENABLED 0x00000001 +/* Note: PGETBL_CTL2 has a different offset on G33. */ +#define I965_PGETBL_CTL2 0x20c4 #define I965_PGETBL_SIZE_MASK 0x0000000e #define I965_PGETBL_SIZE_512KB (0 << 1) #define I965_PGETBL_SIZE_256KB (1 << 1) @@ -82,9 +84,15 @@ #define I965_PGETBL_SIZE_1MB (3 << 1) #define I965_PGETBL_SIZE_2MB (4 << 1) #define I965_PGETBL_SIZE_1_5MB (5 << 1) -#define G33_PGETBL_SIZE_MASK (3 << 8) -#define G33_PGETBL_SIZE_1M (1 << 8) -#define G33_PGETBL_SIZE_2M (2 << 8) +#define G33_GMCH_SIZE_MASK (3 << 8) +#define G33_GMCH_SIZE_1M (1 << 8) +#define G33_GMCH_SIZE_2M (2 << 8) +#define G4x_GMCH_SIZE_MASK (0xf << 8) +#define G4x_GMCH_SIZE_1M (0x1 << 8) +#define G4x_GMCH_SIZE_2M (0x3 << 8) +#define G4x_GMCH_SIZE_VT_1M (0x9 << 8) +#define G4x_GMCH_SIZE_VT_1_5M (0xa << 8) +#define G4x_GMCH_SIZE_VT_2M (0xc << 8) #define I810_DRAM_CTL 0x3000 #define I810_DRAM_ROW_0 0x00000001 diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index fd3e94f8ab51..5dc1f5db55a7 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -642,41 +642,85 @@ static unsigned int intel_gtt_stolen_entries(void) return stolen_entries; } -static unsigned int intel_gtt_total_entries(void) +static void i965_adjust_pgetbl_size(unsigned int size_flag) +{ + u32 pgetbl_ctl, pgetbl_ctl2; + + /* ensure that ppgtt is disabled */ + pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2); + pgetbl_ctl2 &= ~I810_PGETBL_ENABLED; + writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2); + + /* write the new ggtt size */ + pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); + pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK; + pgetbl_ctl |= size_flag; + writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL); +} + +static unsigned int i965_gtt_total_entries(void) { int size; + u32 pgetbl_ctl; + u16 gmch_ctl; - if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) { - u32 pgetbl_ctl; - pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctl); - switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { - case I965_PGETBL_SIZE_128KB: - size = KB(128); - break; - case I965_PGETBL_SIZE_256KB: - size = KB(256); - break; - case I965_PGETBL_SIZE_512KB: - size = KB(512); - break; - case I965_PGETBL_SIZE_1MB: - size = KB(1024); + if (INTEL_GTT_GEN == 5) { + switch (gmch_ctl & G4x_GMCH_SIZE_MASK) { + case G4x_GMCH_SIZE_1M: + case G4x_GMCH_SIZE_VT_1M: + i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB); break; - case I965_PGETBL_SIZE_2MB: - size = KB(2048); + case G4x_GMCH_SIZE_VT_1_5M: + i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB); break; - case I965_PGETBL_SIZE_1_5MB: - size = KB(1024 + 512); + case G4x_GMCH_SIZE_2M: + case G4x_GMCH_SIZE_VT_2M: + i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB); break; - default: - dev_info(&intel_private.pcidev->dev, - "unknown page table size, assuming 512KB\n"); - size = KB(512); } + } - return size/4; - } else if (INTEL_GTT_GEN == 6) { + pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); + + switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { + case I965_PGETBL_SIZE_128KB: + size = KB(128); + break; + case I965_PGETBL_SIZE_256KB: + size = KB(256); + break; + case I965_PGETBL_SIZE_512KB: + size = KB(512); + break; + /* GTT pagetable sizes bigger than 512KB are not possible on G33! */ + case I965_PGETBL_SIZE_1MB: + size = KB(1024); + break; + case I965_PGETBL_SIZE_2MB: + size = KB(2048); + break; + case I965_PGETBL_SIZE_1_5MB: + size = KB(1024 + 512); + break; + default: + dev_info(&intel_private.pcidev->dev, + "unknown page table size, assuming 512KB\n"); + size = KB(512); + } + + return size/4; +} + +static unsigned int intel_gtt_total_entries(void) +{ + int size; + + if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) + return i965_gtt_total_entries(); + else if (INTEL_GTT_GEN == 6) { u16 snb_gmch_ctl; pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); -- cgit v1.2.3 From ec57d2602a985b54b53e53098f74fdefc24723af Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 30 Sep 2010 23:42:15 +0200 Subject: drm/i915: add mappable to gem_object_bind tracepoint This way we can make some more educated guesses as to why exactly we can't use 2G apertures to their full potential ;) Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_trace.h | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6d9971f0ed92..bb5435ba01aa 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2775,7 +2775,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); obj_priv->gtt_offset = obj_priv->gtt_space->start; - trace_i915_gem_object_bind(obj, obj_priv->gtt_offset); + trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, mappable); return 0; } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index fea97a21cc14..0b1049ff72a3 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -35,22 +35,25 @@ TRACE_EVENT(i915_gem_object_create, TRACE_EVENT(i915_gem_object_bind, - TP_PROTO(struct drm_gem_object *obj, u32 gtt_offset), + TP_PROTO(struct drm_gem_object *obj, u32 gtt_offset, bool mappable), - TP_ARGS(obj, gtt_offset), + TP_ARGS(obj, gtt_offset, mappable), TP_STRUCT__entry( __field(struct drm_gem_object *, obj) __field(u32, gtt_offset) + __field(bool, mappable) ), TP_fast_assign( __entry->obj = obj; __entry->gtt_offset = gtt_offset; + __entry->mappable = mappable; ), - TP_printk("obj=%p, gtt_offset=%08x", - __entry->obj, __entry->gtt_offset) + TP_printk("obj=%p, gtt_offset=%08x%s", + __entry->obj, __entry->gtt_offset, + __entry->mappable ? ", mappable" : "") ); TRACE_EVENT(i915_gem_object_change_domain, -- cgit v1.2.3 From fb7d516af11837126eb1e4a44ab0653bf9b57702 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 1 Oct 2010 22:05:20 +0200 Subject: drm/i915: add accounting for mappable objects in gtt v2 More precisely: For those that _need_ to be mappable. Also add two BUG_ONs in fault and pin to check the consistency of the mappable flag. Changes in v2: - Add tracking of gtt mappable space (to notice mappable/unmappable balancing issues). - Improve the mappable working set tracking by tracking fault and pin separately. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++ drivers/gpu/drm/i915/i915_drv.h | 12 +++++ drivers/gpu/drm/i915/i915_gem.c | 93 +++++++++++++++++++++++++++++++------ 3 files changed, 98 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index beb3de7921b5..2e5961139326 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -131,6 +131,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) seq_printf(m, " (fence: %d)", obj->fence_reg); if (obj->gtt_space != NULL) seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset); + if (obj->pin_mappable || obj->fault_mappable) + seq_printf(m, " (mappable)"); if (obj->ring != NULL) seq_printf(m, " (%s)", obj->ring->name); } @@ -207,6 +209,10 @@ static int i915_gem_object_info(struct seq_file *m, void* data) seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory); seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count); seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory); + seq_printf(m, "%u mappable objects in gtt\n", dev_priv->mm.gtt_mappable_count); + seq_printf(m, "%zu mappable gtt bytes\n", dev_priv->mm.gtt_mappable_memory); + seq_printf(m, "%zu mappable gtt used bytes\n", dev_priv->mm.mappable_gtt_used); + seq_printf(m, "%zu mappable gtt total\n", dev_priv->mm.mappable_gtt_total); seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count); seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory); seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 296ed38b292f..cdae5d189165 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -643,9 +643,13 @@ typedef struct drm_i915_private { size_t object_memory; size_t pin_memory; size_t gtt_memory; + size_t gtt_mappable_memory; + size_t mappable_gtt_used; + size_t mappable_gtt_total; size_t gtt_total; u32 object_count; u32 pin_count; + u32 gtt_mappable_count; u32 gtt_count; } mm; struct sdvo_device_mapping sdvo_mappings[2]; @@ -775,6 +779,14 @@ struct drm_i915_gem_object { unsigned int pin_count : 4; #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf + /** + * Whether the current gtt mapping needs to be mappable (and isn't just + * mappable by accident). Track pin and fault separate for a more + * accurate mappable working set. + */ + unsigned int fault_mappable : 1; + unsigned int pin_mappable : 1; + /** AGP memory structure for our GTT binding. */ DRM_AGP_MEM *agp_mem; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bb5435ba01aa..2eceb24bf54b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -84,31 +84,83 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, } static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv, - size_t size) + struct drm_gem_object *obj) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.gtt_count++; - dev_priv->mm.gtt_memory += size; + dev_priv->mm.gtt_memory += obj->size; + if (obj_priv->gtt_offset < dev_priv->mm.gtt_mappable_end) { + dev_priv->mm.mappable_gtt_used += + min_t(size_t, obj->size, + dev_priv->mm.gtt_mappable_end + - obj_priv->gtt_offset); + } } static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, - size_t size) + struct drm_gem_object *obj) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.gtt_count--; - dev_priv->mm.gtt_memory -= size; + dev_priv->mm.gtt_memory -= obj->size; + if (obj_priv->gtt_offset < dev_priv->mm.gtt_mappable_end) { + dev_priv->mm.mappable_gtt_used -= + min_t(size_t, obj->size, + dev_priv->mm.gtt_mappable_end + - obj_priv->gtt_offset); + } +} + +/** + * Update the mappable working set counters. Call _only_ when there is a change + * in one of (pin|fault)_mappable and update *_mappable _before_ calling. + * @mappable: new state the changed mappable flag (either pin_ or fault_). + */ +static void +i915_gem_info_update_mappable(struct drm_i915_private *dev_priv, + struct drm_gem_object *obj, + bool mappable) +{ + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + + if (mappable) { + if (obj_priv->pin_mappable && obj_priv->fault_mappable) + /* Combined state was already mappable. */ + return; + dev_priv->mm.gtt_mappable_count++; + dev_priv->mm.gtt_mappable_memory += obj->size; + } else { + if (obj_priv->pin_mappable || obj_priv->fault_mappable) + /* Combined state still mappable. */ + return; + dev_priv->mm.gtt_mappable_count--; + dev_priv->mm.gtt_mappable_memory -= obj->size; + } } static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv, - size_t size) + struct drm_gem_object *obj, + bool mappable) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.pin_count++; - dev_priv->mm.pin_memory += size; + dev_priv->mm.pin_memory += obj->size; + if (mappable) { + obj_priv->pin_mappable = true; + i915_gem_info_update_mappable(dev_priv, obj, true); + } } static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv, - size_t size) + struct drm_gem_object *obj) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.pin_count--; - dev_priv->mm.pin_memory -= size; + dev_priv->mm.pin_memory -= obj->size; + if (obj_priv->pin_mappable) { + obj_priv->pin_mappable = false; + i915_gem_info_update_mappable(dev_priv, obj, false); + } } int @@ -188,6 +240,7 @@ int i915_gem_do_init(struct drm_device *dev, end - start); dev_priv->mm.gtt_total = end - start; + dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; dev_priv->mm.gtt_mappable_end = mappable_end; return 0; @@ -1266,6 +1319,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Now bind it into the GTT if needed */ mutex_lock(&dev->struct_mutex); + BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable); if (!i915_gem_object_cpu_accessible(obj_priv)) i915_gem_object_unbind(obj); @@ -1279,6 +1333,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) goto unlock; } + if (!obj_priv->fault_mappable) { + obj_priv->fault_mappable = true; + i915_gem_info_update_mappable(dev_priv, obj, true); + } + /* Need a new fence register? */ if (obj_priv->tiling_mode != I915_TILING_NONE) { ret = i915_gem_object_get_fence_reg(obj, true); @@ -1396,11 +1455,17 @@ void i915_gem_release_mmap(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); if (dev->dev_mapping) unmap_mapping_range(dev->dev_mapping, obj_priv->mmap_offset, obj->size, 1); + + if (obj_priv->fault_mappable) { + obj_priv->fault_mappable = false; + i915_gem_info_update_mappable(dev_priv, obj, false); + } } static void @@ -2177,7 +2242,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) i915_gem_object_put_pages(obj); BUG_ON(obj_priv->pages_refcount); - i915_gem_info_remove_gtt(dev_priv, obj->size); + i915_gem_info_remove_gtt(dev_priv, obj); list_del_init(&obj_priv->mm_list); drm_mm_put_block(obj_priv->gtt_space); @@ -2763,9 +2828,11 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, goto search_free; } + obj_priv->gtt_offset = obj_priv->gtt_space->start; + /* keep track of bounds object by adding it to the inactive list */ list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_add_gtt(dev_priv, obj->size); + i915_gem_info_add_gtt(dev_priv, obj); /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in @@ -2774,7 +2841,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS); BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); - obj_priv->gtt_offset = obj_priv->gtt_space->start; trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, mappable); return 0; @@ -4107,11 +4173,12 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, * remove it from the inactive list */ if (obj_priv->pin_count == 1) { - i915_gem_info_add_pin(dev_priv, obj->size); + i915_gem_info_add_pin(dev_priv, obj, mappable); if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list); } + BUG_ON(!obj_priv->pin_mappable && mappable); WARN_ON(i915_verify_lists(dev)); return 0; @@ -4137,7 +4204,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_remove_pin(dev_priv, obj->size); + i915_gem_info_remove_pin(dev_priv, obj); } WARN_ON(i915_verify_lists(dev)); } -- cgit v1.2.3 From da761a6edf5c12ba2e7566c5e6bc98899d46ff12 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 17:37:08 +0100 Subject: drm/i915: Bail early if we try to mmap an object too large to be mapped. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2eceb24bf54b..19ceb8cd0922 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1258,6 +1258,7 @@ int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_mmap *args = data; struct drm_gem_object *obj; loff_t offset; @@ -1270,6 +1271,11 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOENT; + if (obj->size > dev_priv->mm.gtt_mappable_end) { + drm_gem_object_unreference_unlocked(obj); + return -E2BIG; + } + offset = args->offset; down_write(¤t->mm->mmap_sem); @@ -1547,6 +1553,7 @@ int i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_mmap_gtt *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; @@ -1566,6 +1573,11 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, } obj_priv = to_intel_bo(obj); + if (obj->size > dev_priv->mm.gtt_mappable_end) { + ret = -E2BIG; + goto unlock; + } + if (obj_priv->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to mmap a purgeable buffer\n"); ret = -EINVAL; -- cgit v1.2.3 From 71e9339c3389de6a685ecb26261a81b8a583aa1c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 18:46:52 +0100 Subject: drm/i915: Use the agp_size determined from the GTT This is the same value as before, but it just makes the code slightly more readable to use the local variable than converting the aperture size into bytes every time. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1bd37e34c77e..d8def48242c8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1920,6 +1920,16 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_GEN2(dev)) dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); + dev_priv->mm.gtt = intel_gtt_get(); + if (!dev_priv->mm.gtt) { + DRM_ERROR("Failed to initialize GTT\n"); + ret = -ENODEV; + goto out_iomapfree; + } + + prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; + agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + dev_priv->regs = ioremap(base, size); if (!dev_priv->regs) { DRM_ERROR("failed to map registers\n"); @@ -1928,8 +1938,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } dev_priv->mm.gtt_mapping = - io_mapping_create_wc(dev->agp->base, - dev->agp->agp_info.aper_size * 1024*1024); + io_mapping_create_wc(dev->agp->base, agp_size); if (dev_priv->mm.gtt_mapping == NULL) { ret = -EIO; goto out_rmmap; @@ -1941,24 +1950,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) * MTRR if present. Even if a UC MTRR isn't present. */ dev_priv->mm.gtt_mtrr = mtrr_add(dev->agp->base, - dev->agp->agp_info.aper_size * - 1024 * 1024, + agp_size, MTRR_TYPE_WRCOMB, 1); if (dev_priv->mm.gtt_mtrr < 0) { DRM_INFO("MTRR allocation failed. Graphics " "performance may suffer.\n"); } - dev_priv->mm.gtt = intel_gtt_get(); - if (!dev_priv->mm.gtt) { - DRM_ERROR("Failed to initialize GTT\n"); - ret = -ENODEV; - goto out_iomapfree; - } - - prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; - agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - /* The i915 workqueue is primarily used for batched retirement of * requests (and thus managing bo) once the task has been completed * by the GPU. i915_gem_retire_requests() is called directly when we -- cgit v1.2.3 From f406839f094ef24bb201c9574fdb9ce8e799a975 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Oct 2010 20:36:41 +0100 Subject: drm/i915: Capture ERROR register on Sandybridge hangs This holds error state from the main graphics arbiter mainly involving the DMA engine and address translation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 18 +++++++++++------- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 4 files changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2e5961139326..4fc1e05b769f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -615,6 +615,9 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); + if (INTEL_INFO(dev)->gen >= 6) { + seq_printf(m, "ERROR: 0x%08x\n", error->error); + } seq_printf(m, "EIR: 0x%08x\n", error->eir); seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cdae5d189165..895f9173de58 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -142,6 +142,7 @@ struct sdvo_device_mapping { struct drm_i915_error_state { u32 eir; u32 pgtbl_er; + u32 error; /* gen6+ */ u32 pipeastat; u32 pipebstat; u32 ipeir; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 29cbcb33b92c..2a29497a4694 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -592,13 +592,11 @@ static void i915_capture_error_state(struct drm_device *dev) error->pipeastat = I915_READ(PIPEASTAT); error->pipebstat = I915_READ(PIPEBSTAT); error->instpm = I915_READ(INSTPM); - if (INTEL_INFO(dev)->gen < 4) { - error->ipeir = I915_READ(IPEIR); - error->ipehr = I915_READ(IPEHR); - error->instdone = I915_READ(INSTDONE); - error->acthd = I915_READ(ACTHD); - error->bbaddr = 0; - } else { + error->error = 0; + if (INTEL_INFO(dev)->gen >= 6) { + error->error = I915_READ(ERROR_GEN6); + } + if (INTEL_INFO(dev)->gen >= 4) { error->ipeir = I915_READ(IPEIR_I965); error->ipehr = I915_READ(IPEHR_I965); error->instdone = I915_READ(INSTDONE_I965); @@ -606,6 +604,12 @@ static void i915_capture_error_state(struct drm_device *dev) error->instdone1 = I915_READ(INSTDONE1); error->acthd = I915_READ(ACTHD_I965); error->bbaddr = I915_READ64(BB_ADDR); + } else { + error->ipeir = I915_READ(IPEIR); + error->ipehr = I915_READ(IPEHR); + error->instdone = I915_READ(INSTDONE); + error->acthd = I915_READ(ACTHD); + error->bbaddr = 0; } bbaddr = i915_ringbuffer_last_batch(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 25ed911a3112..fc161196da21 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -306,6 +306,8 @@ #define NOPID 0x02094 #define HWSTAM 0x02098 +#define ERROR_GEN6 0x040a0 + #define MI_MODE 0x0209c # define VS_TIMER_DISPATCH (1 << 6) # define MI_FLUSH_ENABLE (1 << 11) -- cgit v1.2.3 From b4ce0f85159f77f208a62930f67b4e548576a5a3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 11:26:06 +0100 Subject: drm/i915: Use pci_iomap for remapping the MMIO registers. Play safe and use the common routines which take care of the cachability of the memory when setting up the iomapping for the PCI registers. Whilst they should be cacheable for the current generations, actually honouring what the device requires is a better long term strategy. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index d8def48242c8..f8827c23a668 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1888,7 +1888,6 @@ EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv; - resource_size_t base, size; int ret = 0, mmio_bar; uint32_t agp_size, prealloc_size; /* i915 has 4 more counters */ @@ -1906,11 +1905,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->dev = dev; dev_priv->info = (struct intel_device_info *) flags; - /* Add register map (needed for suspend/resume) */ - mmio_bar = IS_GEN2(dev) ? 1 : 0; - base = pci_resource_start(dev->pdev, mmio_bar); - size = pci_resource_len(dev->pdev, mmio_bar); - if (i915_get_bridge_dev(dev)) { ret = -EIO; goto free_priv; @@ -1920,6 +1914,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_GEN2(dev)) dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); + mmio_bar = IS_GEN2(dev) ? 1 : 0; + dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0); + if (!dev_priv->regs) { + DRM_ERROR("failed to map registers\n"); + ret = -EIO; + goto put_bridge; + } + dev_priv->mm.gtt = intel_gtt_get(); if (!dev_priv->mm.gtt) { DRM_ERROR("Failed to initialize GTT\n"); @@ -1930,13 +1932,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - dev_priv->regs = ioremap(base, size); - if (!dev_priv->regs) { - DRM_ERROR("failed to map registers\n"); - ret = -EIO; - goto put_bridge; - } - dev_priv->mm.gtt_mapping = io_mapping_create_wc(dev->agp->base, agp_size); if (dev_priv->mm.gtt_mapping == NULL) { -- cgit v1.2.3 From 176f28ebf4303b4f7e3a5bd8be7842a8bbecd9c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 11:18:07 +0100 Subject: drm/i915/ringbuffer: Check that we setup the ringbuffer Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8eaa60cc5d25..e88214ef24b1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -176,9 +176,10 @@ static int init_ring_common(struct intel_ring_buffer *ring) ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) | RING_NO_REPORT | RING_VALID); - head = I915_READ_HEAD(ring) & HEAD_ADDR; /* If the head is still not zero, the ring is dead */ - if (head != 0) { + if ((I915_READ_CTL(ring) & RING_VALID) == 0 || + I915_READ_START(ring) != obj_priv->gtt_offset || + (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) { DRM_ERROR("%s initialization failed " "ctl %08x head %08x tail %08x start %08x\n", ring->name, -- cgit v1.2.3 From 17250b71553680bc6e927497aa619ab06ab1015b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 12:51:39 +0100 Subject: drm/i915: Make the inactive object shrinker per-device Eliminate the racy device unload by embedding a shrinker into each device. Smaller, simpler code. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 3 + drivers/gpu/drm/i915/i915_drv.c | 3 - drivers/gpu/drm/i915/i915_drv.h | 12 +-- drivers/gpu/drm/i915/i915_gem.c | 179 ++++++++++++---------------------------- 4 files changed, 56 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f8827c23a668..dddca007912a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2096,6 +2096,9 @@ int i915_driver_unload(struct drm_device *dev) i915_mch_dev = NULL; spin_unlock(&mchdev_lock); + if (dev_priv->mm.inactive_shrinker.shrink) + unregister_shrinker(&dev_priv->mm.inactive_shrinker); + mutex_lock(&dev->struct_mutex); ret = i915_gpu_idle(dev); if (ret) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 82c19ab3e1e2..d22aab94d645 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -660,8 +660,6 @@ static int __init i915_init(void) driver.num_ioctls = i915_max_ioctl; - i915_gem_shrinker_init(); - /* * If CONFIG_DRM_I915_KMS is set, default to KMS unless * explicitly disabled with the module pararmeter. @@ -693,7 +691,6 @@ static int __init i915_init(void) static void __exit i915_exit(void) { - i915_gem_shrinker_exit(); drm_exit(&driver); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 895f9173de58..29e8b7962edf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -542,14 +542,7 @@ typedef struct drm_i915_private { struct io_mapping *gtt_mapping; int gtt_mtrr; - /** - * Membership on list of all loaded devices, used to evict - * inactive buffers under memory pressure. - * - * Modifications should only be done whilst holding the - * shrink_list_lock spinlock. - */ - struct list_head shrink_list; + struct shrinker inactive_shrinker; /** * List of objects currently involved in rendering. @@ -1079,9 +1072,6 @@ void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); -void i915_gem_shrinker_init(void); -void i915_gem_shrinker_exit(void); - /* i915_gem_evict.c */ int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment, bool mappable); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 19ceb8cd0922..1af7285ca162 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -65,8 +65,10 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, static void i915_gem_object_put_pages(struct drm_gem_object *obj); -static LIST_HEAD(shrink_list); -static DEFINE_SPINLOCK(shrink_list_lock); +static int i915_gem_inactive_shrink(struct shrinker *shrinker, + int nr_to_scan, + gfp_t gfp_mask); + /* some bookkeeping */ static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, @@ -4765,9 +4767,6 @@ i915_gem_load(struct drm_device *dev) INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); init_completion(&dev_priv->error_completion); - spin_lock(&shrink_list_lock); - list_add(&dev_priv->mm.shrink_list, &shrink_list); - spin_unlock(&shrink_list_lock); /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { @@ -4810,6 +4809,10 @@ i915_gem_load(struct drm_device *dev) } i915_gem_detect_bit_6_swizzle(dev); init_waitqueue_head(&dev_priv->pending_flip_queue); + + dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink; + dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS; + register_shrinker(&dev_priv->mm.inactive_shrinker); } /* @@ -5022,152 +5025,74 @@ i915_gpu_is_active(struct drm_device *dev) int lists_empty; lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list) && - list_empty(&dev_priv->bsd_ring.active_list) && - list_empty(&dev_priv->blt_ring.active_list); + list_empty(&dev_priv->mm.active_list); return !lists_empty; } static int -i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) +i915_gem_inactive_shrink(struct shrinker *shrinker, + int nr_to_scan, + gfp_t gfp_mask) { - drm_i915_private_t *dev_priv, *next_dev; - struct drm_i915_gem_object *obj_priv, *next_obj; - int cnt = 0; - int would_deadlock = 1; + struct drm_i915_private *dev_priv = + container_of(shrinker, + struct drm_i915_private, + mm.inactive_shrinker); + struct drm_device *dev = dev_priv->dev; + struct drm_i915_gem_object *obj, *next; + int cnt; + + if (!mutex_trylock(&dev->struct_mutex)) + return nr_to_scan ? 0 : -1; /* "fast-path" to count number of available objects */ if (nr_to_scan == 0) { - spin_lock(&shrink_list_lock); - list_for_each_entry(dev_priv, &shrink_list, mm.shrink_list) { - struct drm_device *dev = dev_priv->dev; - - if (mutex_trylock(&dev->struct_mutex)) { - list_for_each_entry(obj_priv, - &dev_priv->mm.inactive_list, - mm_list) - cnt++; - mutex_unlock(&dev->struct_mutex); - } - } - spin_unlock(&shrink_list_lock); - - return (cnt / 100) * sysctl_vfs_cache_pressure; + cnt = 0; + list_for_each_entry(obj, + &dev_priv->mm.inactive_list, + mm_list) + cnt++; + mutex_unlock(&dev->struct_mutex); + return cnt / 100 * sysctl_vfs_cache_pressure; } - spin_lock(&shrink_list_lock); - rescan: /* first scan for clean buffers */ - list_for_each_entry_safe(dev_priv, next_dev, - &shrink_list, mm.shrink_list) { - struct drm_device *dev = dev_priv->dev; - - if (! mutex_trylock(&dev->struct_mutex)) - continue; - - spin_unlock(&shrink_list_lock); - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev); - list_for_each_entry_safe(obj_priv, next_obj, - &dev_priv->mm.inactive_list, - mm_list) { - if (i915_gem_object_is_purgeable(obj_priv)) { - i915_gem_object_unbind(&obj_priv->base); - if (--nr_to_scan <= 0) - break; - } + list_for_each_entry_safe(obj, next, + &dev_priv->mm.inactive_list, + mm_list) { + if (i915_gem_object_is_purgeable(obj)) { + i915_gem_object_unbind(&obj->base); + if (--nr_to_scan == 0) + break; } - - spin_lock(&shrink_list_lock); - mutex_unlock(&dev->struct_mutex); - - would_deadlock = 0; - - if (nr_to_scan <= 0) - break; } /* second pass, evict/count anything still on the inactive list */ - list_for_each_entry_safe(dev_priv, next_dev, - &shrink_list, mm.shrink_list) { - struct drm_device *dev = dev_priv->dev; - - if (! mutex_trylock(&dev->struct_mutex)) - continue; - - spin_unlock(&shrink_list_lock); - - list_for_each_entry_safe(obj_priv, next_obj, - &dev_priv->mm.inactive_list, - mm_list) { - if (nr_to_scan > 0) { - i915_gem_object_unbind(&obj_priv->base); - nr_to_scan--; - } else - cnt++; - } - - spin_lock(&shrink_list_lock); - mutex_unlock(&dev->struct_mutex); - - would_deadlock = 0; - } - - if (nr_to_scan) { - int active = 0; - + cnt = 0; + list_for_each_entry_safe(obj, next, + &dev_priv->mm.inactive_list, + mm_list) { + if (nr_to_scan) { + i915_gem_object_unbind(&obj->base); + nr_to_scan--; + } else + cnt++; + } + + if (nr_to_scan && i915_gpu_is_active(dev)) { /* * We are desperate for pages, so as a last resort, wait * for the GPU to finish and discard whatever we can. * This has a dramatic impact to reduce the number of * OOM-killer events whilst running the GPU aggressively. */ - list_for_each_entry(dev_priv, &shrink_list, mm.shrink_list) { - struct drm_device *dev = dev_priv->dev; - - if (!mutex_trylock(&dev->struct_mutex)) - continue; - - spin_unlock(&shrink_list_lock); - - if (i915_gpu_is_active(dev)) { - i915_gpu_idle(dev); - active++; - } - - spin_lock(&shrink_list_lock); - mutex_unlock(&dev->struct_mutex); - } - - if (active) + if (i915_gpu_idle(dev) == 0) goto rescan; } - - spin_unlock(&shrink_list_lock); - - if (would_deadlock) - return -1; - else if (cnt > 0) - return (cnt / 100) * sysctl_vfs_cache_pressure; - else - return 0; -} - -static struct shrinker shrinker = { - .shrink = i915_gem_shrink, - .seeks = DEFAULT_SEEKS, -}; - -__init void -i915_gem_shrinker_init(void) -{ - register_shrinker(&shrinker); -} - -__exit void -i915_gem_shrinker_exit(void) -{ - unregister_shrinker(&shrinker); + mutex_unlock(&dev->struct_mutex); + return cnt / 100 * sysctl_vfs_cache_pressure; } -- cgit v1.2.3 From 39a01d1fb63cf8ebc1a8cf436f5c0ba9657b55c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 13:03:06 +0100 Subject: drm/i915: Remove mmap_offset Since we rarely use the mmap_offset and it is easily computable from the obj->map_list.hash, remove it. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 5 ----- drivers/gpu/drm/i915/i915_gem.c | 46 ++++++++++------------------------------- 2 files changed, 11 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 29e8b7962edf..1f7e8b3c8df0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -796,11 +796,6 @@ struct drm_i915_gem_object { /* Which ring is refering to is this object */ struct intel_ring_buffer *ring; - /** - * Fake offset for use by mmap(2) - */ - uint64_t mmap_offset; - /** Breadcrumb of last rendering to the buffer. */ uint32_t last_rendering_seqno; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1af7285ca162..4ade4e243379 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1392,7 +1392,6 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_gem_mm *mm = dev->mm_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_map_list *list; struct drm_local_map *map; int ret = 0; @@ -1431,16 +1430,13 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) goto out_free_mm; } - /* By now we should be all set, any drm_mmap request on the offset - * below will get to our mmap & fault handler */ - obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT; - return 0; out_free_mm: drm_mm_put_block(list->file_offset_node); out_free_list: kfree(list->map); + list->map = NULL; return ret; } @@ -1466,9 +1462,10 @@ i915_gem_release_mmap(struct drm_gem_object *obj) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - if (dev->dev_mapping) + if (unlikely(obj->map_list.map && dev->dev_mapping)) unmap_mapping_range(dev->dev_mapping, - obj_priv->mmap_offset, obj->size, 1); + (loff_t)obj->map_list.hash.key<size, 1); if (obj_priv->fault_mappable) { obj_priv->fault_mappable = false; @@ -1480,24 +1477,13 @@ static void i915_gem_free_mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_gem_mm *mm = dev->mm_private; - struct drm_map_list *list; + struct drm_map_list *list = &obj->map_list; - list = &obj->map_list; drm_ht_remove_item(&mm->offset_hash, &list->hash); - - if (list->file_offset_node) { - drm_mm_put_block(list->file_offset_node); - list->file_offset_node = NULL; - } - - if (list->map) { - kfree(list->map); - list->map = NULL; - } - - obj_priv->mmap_offset = 0; + drm_mm_put_block(list->file_offset_node); + kfree(list->map); + list->map = NULL; } /** @@ -1586,23 +1572,13 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, goto out; } - if (!obj_priv->mmap_offset) { + if (!obj->map_list.map) { ret = i915_gem_create_mmap_offset(obj); if (ret) goto out; } - args->offset = obj_priv->mmap_offset; - - /* - * Pull it into the GTT so that we have a page list (makes the - * initial fault faster and any subsequent flushing possible). - */ - if (!obj_priv->agp_mem) { - ret = i915_gem_object_bind_to_gtt(obj, 0, true); - if (ret) - goto out; - } + args->offset = (u64)obj->map_list.hash.key << PAGE_SHIFT; out: drm_gem_object_unreference(obj); @@ -4477,7 +4453,7 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj) return; } - if (obj_priv->mmap_offset) + if (obj->map_list.map) i915_gem_free_mmap_offset(obj); drm_gem_object_release(obj); -- cgit v1.2.3 From e5281ccd2e0049e2b9e8ce82449630d25082372d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 13:45:36 +0100 Subject: drm/i915: Eliminate nested get/put pages By using read_cache_page() for individual pages during pwrite/pread we can eliminate an unnecessary large allocation (and immediate free) of obj->pages. Also this eliminates any potential nesting of get/put pages, simplifying the code and preparing the path for greater things. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 9 - drivers/gpu/drm/i915/i915_gem.c | 358 ++++++++++++++++++---------------------- 2 files changed, 163 insertions(+), 204 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1f7e8b3c8df0..3df8a624ddc9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -747,15 +747,6 @@ struct drm_i915_gem_object { */ unsigned int madv : 2; - /** - * Refcount for the pages array. With the current locking scheme, there - * are at most two concurrent users: Binding a bo to the gtt and - * pwrite/pread using physical addresses. So two bits for a maximum - * of two users are enough. - */ - unsigned int pages_refcount : 2; -#define DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT 0x3 - /** * Current tiling mode for the object. */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4ade4e243379..abe6d901f95b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -58,13 +58,6 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *o struct drm_file *file_priv); static void i915_gem_free_object_tail(struct drm_gem_object *obj); -static int -i915_gem_object_get_pages(struct drm_gem_object *obj, - gfp_t gfpmask); - -static void -i915_gem_object_put_pages(struct drm_gem_object *obj); - static int i915_gem_inactive_shrink(struct shrinker *shrinker, int nr_to_scan, gfp_t gfp_mask); @@ -326,22 +319,6 @@ i915_gem_object_cpu_accessible(struct drm_i915_gem_object *obj) obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; } -static inline int -fast_shmem_read(struct page **pages, - loff_t page_base, int page_offset, - char __user *data, - int length) -{ - char *vaddr; - int ret; - - vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]); - ret = __copy_to_user_inatomic(data, vaddr + page_offset, length); - kunmap_atomic(vaddr); - - return ret; -} - static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj) { drm_i915_private_t *dev_priv = obj->dev->dev_private; @@ -429,8 +406,9 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, struct drm_file *file_priv) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; ssize_t remain; - loff_t offset, page_base; + loff_t offset; char __user *user_data; int page_offset, page_length; @@ -441,21 +419,34 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, offset = args->offset; while (remain > 0) { + struct page *page; + char *vaddr; + int ret; + /* Operation in this page * - * page_base = page offset within aperture * page_offset = offset within page * page_length = bytes to copy for this page */ - page_base = (offset & ~(PAGE_SIZE-1)); page_offset = offset & (PAGE_SIZE-1); page_length = remain; if ((page_offset + remain) > PAGE_SIZE) page_length = PAGE_SIZE - page_offset; - if (fast_shmem_read(obj_priv->pages, - page_base, page_offset, - user_data, page_length)) + page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, + GFP_HIGHUSER | __GFP_RECLAIMABLE); + if (IS_ERR(page)) + return PTR_ERR(page); + + vaddr = kmap_atomic(page); + ret = __copy_to_user_inatomic(user_data, + vaddr + page_offset, + page_length); + kunmap_atomic(vaddr); + + mark_page_accessed(page); + page_cache_release(page); + if (ret) return -EFAULT; remain -= page_length; @@ -466,31 +457,6 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, return 0; } -static int -i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) -{ - int ret; - - ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN); - - /* If we've insufficient memory to map in the pages, attempt - * to make some space by throwing out some old buffers. - */ - if (ret == -ENOMEM) { - struct drm_device *dev = obj->dev; - - ret = i915_gem_evict_something(dev, obj->size, - i915_gem_get_gtt_alignment(obj), - false); - if (ret) - return ret; - - ret = i915_gem_object_get_pages(obj, 0); - } - - return ret; -} - /** * This is the fallback shmem pread path, which allocates temporary storage * in kernel space to copy_to_user into outside of the struct_mutex, so we @@ -502,14 +468,15 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pread *args, struct drm_file *file_priv) { + struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct mm_struct *mm = current->mm; struct page **user_pages; ssize_t remain; loff_t offset, pinned_pages, i; loff_t first_data_page, last_data_page, num_pages; - int shmem_page_index, shmem_page_offset; - int data_page_index, data_page_offset; + int shmem_page_offset; + int data_page_index, data_page_offset; int page_length; int ret; uint64_t data_ptr = args->data_ptr; @@ -552,15 +519,15 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, offset = args->offset; while (remain > 0) { + struct page *page; + /* Operation in this page * - * shmem_page_index = page number within shmem file * shmem_page_offset = offset within page in shmem file * data_page_index = page number in get_user_pages return * data_page_offset = offset with data_page_index page. * page_length = bytes to copy for this page */ - shmem_page_index = offset / PAGE_SIZE; shmem_page_offset = offset & ~PAGE_MASK; data_page_index = data_ptr / PAGE_SIZE - first_data_page; data_page_offset = data_ptr & ~PAGE_MASK; @@ -571,8 +538,13 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, if ((data_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - data_page_offset; + page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, + GFP_HIGHUSER | __GFP_RECLAIMABLE); + if (IS_ERR(page)) + return PTR_ERR(page); + if (do_bit17_swizzling) { - slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], + slow_shmem_bit17_copy(page, shmem_page_offset, user_pages[data_page_index], data_page_offset, @@ -581,11 +553,14 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, } else { slow_shmem_copy(user_pages[data_page_index], data_page_offset, - obj_priv->pages[shmem_page_index], + page, shmem_page_offset, page_length); } + mark_page_accessed(page); + page_cache_release(page); + remain -= page_length; data_ptr += page_length; offset += page_length; @@ -594,6 +569,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, out: for (i = 0; i < pinned_pages; i++) { SetPageDirty(user_pages[i]); + mark_page_accessed(user_pages[i]); page_cache_release(user_pages[i]); } drm_free_large(user_pages); @@ -649,15 +625,11 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, goto out; } - ret = i915_gem_object_get_pages_or_evict(obj); - if (ret) - goto out; - ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset, args->size); if (ret) - goto out_put; + goto out; ret = -EFAULT; if (!i915_gem_object_needs_bit17_swizzle(obj)) @@ -665,8 +637,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, if (ret == -EFAULT) ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv); -out_put: - i915_gem_object_put_pages(obj); out: drm_gem_object_unreference(obj); unlock: @@ -718,22 +688,6 @@ slow_kernel_write(struct io_mapping *mapping, io_mapping_unmap(dst_vaddr); } -static inline int -fast_shmem_write(struct page **pages, - loff_t page_base, int page_offset, - char __user *data, - int length) -{ - char *vaddr; - int ret; - - vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]); - ret = __copy_from_user_inatomic(vaddr + page_offset, data, length); - kunmap_atomic(vaddr); - - return ret; -} - /** * This is the fast pwrite path, where we copy the data directly from the * user into the GTT, uncached. @@ -890,9 +844,10 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv) { + struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); ssize_t remain; - loff_t offset, page_base; + loff_t offset; char __user *user_data; int page_offset, page_length; @@ -904,21 +859,40 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, obj_priv->dirty = 1; while (remain > 0) { + struct page *page; + char *vaddr; + int ret; + /* Operation in this page * - * page_base = page offset within aperture * page_offset = offset within page * page_length = bytes to copy for this page */ - page_base = (offset & ~(PAGE_SIZE-1)); page_offset = offset & (PAGE_SIZE-1); page_length = remain; if ((page_offset + remain) > PAGE_SIZE) page_length = PAGE_SIZE - page_offset; - if (fast_shmem_write(obj_priv->pages, - page_base, page_offset, - user_data, page_length)) + page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, + GFP_HIGHUSER | __GFP_RECLAIMABLE); + if (IS_ERR(page)) + return PTR_ERR(page); + + vaddr = kmap_atomic(page, KM_USER0); + ret = __copy_from_user_inatomic(vaddr + page_offset, + user_data, + page_length); + kunmap_atomic(vaddr, KM_USER0); + + set_page_dirty(page); + mark_page_accessed(page); + page_cache_release(page); + + /* If we get a fault while copying data, then (presumably) our + * source page isn't available. Return the error and we'll + * retry in the slow path. + */ + if (ret) return -EFAULT; remain -= page_length; @@ -941,13 +915,14 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv) { + struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct mm_struct *mm = current->mm; struct page **user_pages; ssize_t remain; loff_t offset, pinned_pages, i; loff_t first_data_page, last_data_page, num_pages; - int shmem_page_index, shmem_page_offset; + int shmem_page_offset; int data_page_index, data_page_offset; int page_length; int ret; @@ -990,15 +965,15 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, obj_priv->dirty = 1; while (remain > 0) { + struct page *page; + /* Operation in this page * - * shmem_page_index = page number within shmem file * shmem_page_offset = offset within page in shmem file * data_page_index = page number in get_user_pages return * data_page_offset = offset with data_page_index page. * page_length = bytes to copy for this page */ - shmem_page_index = offset / PAGE_SIZE; shmem_page_offset = offset & ~PAGE_MASK; data_page_index = data_ptr / PAGE_SIZE - first_data_page; data_page_offset = data_ptr & ~PAGE_MASK; @@ -1009,21 +984,32 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, if ((data_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - data_page_offset; + page = read_cache_page_gfp(mapping, offset >> PAGE_SHIFT, + GFP_HIGHUSER | __GFP_RECLAIMABLE); + if (IS_ERR(page)) { + ret = PTR_ERR(page); + goto out; + } + if (do_bit17_swizzling) { - slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], + slow_shmem_bit17_copy(page, shmem_page_offset, user_pages[data_page_index], data_page_offset, page_length, 0); } else { - slow_shmem_copy(obj_priv->pages[shmem_page_index], + slow_shmem_copy(page, shmem_page_offset, user_pages[data_page_index], data_page_offset, page_length); } + set_page_dirty(page); + mark_page_accessed(page); + page_cache_release(page); + remain -= page_length; data_ptr += page_length; offset += page_length; @@ -1112,22 +1098,15 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, out_unpin: i915_gem_object_unpin(obj); } else { - ret = i915_gem_object_get_pages_or_evict(obj); - if (ret) - goto out; - ret = i915_gem_object_set_to_cpu_domain(obj, 1); if (ret) - goto out_put; + goto out; ret = -EFAULT; if (!i915_gem_object_needs_bit17_swizzle(obj)) ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file); if (ret == -EFAULT) ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file); - -out_put: - i915_gem_object_put_pages(obj); } out: @@ -1587,19 +1566,62 @@ unlock: return ret; } +static int +i915_gem_object_get_pages_gtt(struct drm_gem_object *obj, + gfp_t gfpmask) +{ + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + int page_count, i; + struct address_space *mapping; + struct inode *inode; + struct page *page; + + /* Get the list of pages out of our struct file. They'll be pinned + * at this point until we release them. + */ + page_count = obj->size / PAGE_SIZE; + BUG_ON(obj_priv->pages != NULL); + obj_priv->pages = drm_malloc_ab(page_count, sizeof(struct page *)); + if (obj_priv->pages == NULL) + return -ENOMEM; + + inode = obj->filp->f_path.dentry->d_inode; + mapping = inode->i_mapping; + for (i = 0; i < page_count; i++) { + page = read_cache_page_gfp(mapping, i, + GFP_HIGHUSER | + __GFP_COLD | + __GFP_RECLAIMABLE | + gfpmask); + if (IS_ERR(page)) + goto err_pages; + + obj_priv->pages[i] = page; + } + + if (obj_priv->tiling_mode != I915_TILING_NONE) + i915_gem_object_do_bit_17_swizzle(obj); + + return 0; + +err_pages: + while (i--) + page_cache_release(obj_priv->pages[i]); + + drm_free_large(obj_priv->pages); + obj_priv->pages = NULL; + return PTR_ERR(page); +} + static void -i915_gem_object_put_pages(struct drm_gem_object *obj) +i915_gem_object_put_pages_gtt(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int page_count = obj->size / PAGE_SIZE; int i; - BUG_ON(obj_priv->pages_refcount == 0); BUG_ON(obj_priv->madv == __I915_MADV_PURGED); - if (--obj_priv->pages_refcount != 0) - return; - if (obj_priv->tiling_mode != I915_TILING_NONE) i915_gem_object_save_bit_17_swizzle(obj); @@ -2229,8 +2251,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) drm_unbind_agp(obj_priv->agp_mem); drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); - i915_gem_object_put_pages(obj); - BUG_ON(obj_priv->pages_refcount); + i915_gem_object_put_pages_gtt(obj); i915_gem_info_remove_gtt(dev_priv, obj); list_del_init(&obj_priv->mm_list); @@ -2290,62 +2311,6 @@ i915_gpu_idle(struct drm_device *dev) return 0; } -static int -i915_gem_object_get_pages(struct drm_gem_object *obj, - gfp_t gfpmask) -{ - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - int page_count, i; - struct address_space *mapping; - struct inode *inode; - struct page *page; - - BUG_ON(obj_priv->pages_refcount - == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT); - - if (obj_priv->pages_refcount++ != 0) - return 0; - - /* Get the list of pages out of our struct file. They'll be pinned - * at this point until we release them. - */ - page_count = obj->size / PAGE_SIZE; - BUG_ON(obj_priv->pages != NULL); - obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *)); - if (obj_priv->pages == NULL) { - obj_priv->pages_refcount--; - return -ENOMEM; - } - - inode = obj->filp->f_path.dentry->d_inode; - mapping = inode->i_mapping; - for (i = 0; i < page_count; i++) { - page = read_cache_page_gfp(mapping, i, - GFP_HIGHUSER | - __GFP_COLD | - __GFP_RECLAIMABLE | - gfpmask); - if (IS_ERR(page)) - goto err_pages; - - obj_priv->pages[i] = page; - } - - if (obj_priv->tiling_mode != I915_TILING_NONE) - i915_gem_object_do_bit_17_swizzle(obj); - - return 0; - -err_pages: - while (i--) - page_cache_release(obj_priv->pages[i]); - - drm_free_large(obj_priv->pages); - obj_priv->pages = NULL; - obj_priv->pages_refcount--; - return PTR_ERR(page); -} - static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) { struct drm_gem_object *obj = reg->obj; @@ -2772,7 +2737,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, goto search_free; } - ret = i915_gem_object_get_pages(obj, gfpmask); + ret = i915_gem_object_get_pages_gtt(obj, gfpmask); if (ret) { drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; @@ -2806,7 +2771,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, obj_priv->gtt_space->start, obj_priv->agp_type); if (obj_priv->agp_mem == NULL) { - i915_gem_object_put_pages(obj); + i915_gem_object_put_pages_gtt(obj); drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; @@ -4860,33 +4825,35 @@ void i915_gem_free_all_phys_object(struct drm_device *dev) void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_gem_object *obj) { - struct drm_i915_gem_object *obj_priv; + struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + char *vaddr; int i; - int ret; int page_count; - obj_priv = to_intel_bo(obj); if (!obj_priv->phys_obj) return; - - ret = i915_gem_object_get_pages(obj, 0); - if (ret) - goto out; + vaddr = obj_priv->phys_obj->handle->vaddr; page_count = obj->size / PAGE_SIZE; for (i = 0; i < page_count; i++) { - char *dst = kmap_atomic(obj_priv->pages[i]); - char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); - - memcpy(dst, src, PAGE_SIZE); - kunmap_atomic(dst); + struct page *page = read_cache_page_gfp(mapping, i, + GFP_HIGHUSER | __GFP_RECLAIMABLE); + if (!IS_ERR(page)) { + char *dst = kmap_atomic(page); + memcpy(dst, vaddr + i*PAGE_SIZE, PAGE_SIZE); + kunmap_atomic(dst); + + drm_clflush_pages(&page, 1); + + set_page_dirty(page); + mark_page_accessed(page); + page_cache_release(page); + } } - drm_clflush_pages(obj_priv->pages, page_count); drm_agp_chipset_flush(dev); - i915_gem_object_put_pages(obj); -out: obj_priv->phys_obj->cur_obj = NULL; obj_priv->phys_obj = NULL; } @@ -4897,6 +4864,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, int id, int align) { + struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; int ret = 0; @@ -4920,7 +4888,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, obj->size, align); if (ret) { DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size); - goto out; + return ret; } } @@ -4928,27 +4896,27 @@ i915_gem_attach_phys_object(struct drm_device *dev, obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; obj_priv->phys_obj->cur_obj = obj; - ret = i915_gem_object_get_pages(obj, 0); - if (ret) { - DRM_ERROR("failed to get page list\n"); - goto out; - } - page_count = obj->size / PAGE_SIZE; for (i = 0; i < page_count; i++) { - char *src = kmap_atomic(obj_priv->pages[i]); - char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); + struct page *page; + char *dst, *src; + + page = read_cache_page_gfp(mapping, i, + GFP_HIGHUSER | __GFP_RECLAIMABLE); + if (IS_ERR(page)) + return PTR_ERR(page); + src = kmap_atomic(obj_priv->pages[i]); + dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); memcpy(dst, src, PAGE_SIZE); kunmap_atomic(src); - } - i915_gem_object_put_pages(obj); + mark_page_accessed(page); + page_cache_release(page); + } return 0; -out: - return ret; } static int -- cgit v1.2.3 From 4a684a4117abd756291969336af454e8a958802f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 14:44:08 +0100 Subject: drm/i915: Kill GTT mappings when moving from GTT domain In order to force a page-fault on a GTT mapping after we start using it from the GPU and so enforce correct CPU/GPU synchronisation, we need to invalidate the mapping. Pointed out by Owain G. Ainsworth. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index abe6d901f95b..d4d8f888db85 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1314,12 +1314,12 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto unlock; - - ret = i915_gem_object_set_to_gtt_domain(obj, write); - if (ret) - goto unlock; } + ret = i915_gem_object_set_to_gtt_domain(obj, write); + if (ret) + goto unlock; + if (!obj_priv->fault_mappable) { obj_priv->fault_mappable = true; i915_gem_info_update_mappable(dev_priv, obj, true); @@ -2859,6 +2859,8 @@ i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj) * to it immediately go to main memory as far as we know, so there's * no chipset flush. It also doesn't land in render cache. */ + i915_gem_release_mmap(obj); + old_write_domain = obj->write_domain; obj->write_domain = 0; @@ -3183,6 +3185,10 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); + /* blow away mappings if mapped through GTT */ + if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT) + i915_gem_release_mmap(obj); + /* The actual obj->write_domain will be updated with * pending_write_domain after we emit the accumulated flush for all * of our domain changes in execbuffers (which clears objects' -- cgit v1.2.3 From bbe2e11a4b683ead070ad5823cdf756e1525b903 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 22:35:07 +0100 Subject: drm/i915: Do not return -1 from shrinker when nr_to_scan == 0 The error code is only expected during the actual pruning and not during the first measurement (nr_to_scan == 0) pass. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d4d8f888db85..7569b77fb403 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4994,7 +4994,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, int cnt; if (!mutex_trylock(&dev->struct_mutex)) - return nr_to_scan ? 0 : -1; + return 0; /* "fast-path" to count number of available objects */ if (nr_to_scan == 0) { -- cgit v1.2.3 From b0438a1b71955c425c304a2a483765ef24841766 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Fri, 29 Oct 2010 11:41:42 +0200 Subject: telephony: fix return value If copy_from_user fails, the return value gets overwritten. Signed-off-by: Nicolas Kaiser Signed-off-by: Jiri Kosina --- drivers/telephony/ixj.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 0d236f4bb8c2..2d1280a7a52b 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -6581,7 +6581,8 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar case IXJCTL_SET_FILTER: if (copy_from_user(&jf, argp, sizeof(jf))) retval = -EFAULT; - retval = ixj_init_filter(j, &jf); + else + retval = ixj_init_filter(j, &jf); break; case IXJCTL_SET_FILTER_RAW: if (copy_from_user(&jfr, argp, sizeof(jfr))) -- cgit v1.2.3 From 7465378fd7c681f6cf2b74b3494c4f0991d8c8ac Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 10:41:23 +0100 Subject: drm/i915: Convert BUG_ON(pin_count) from an impossible condition Also spotted by Dan Carpenter. obj->pin_count is unsigned so the BUG_ON(obj->pin_count<0) will never trigger. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7569b77fb403..08f57aedaf51 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4128,12 +4128,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, return ret; } - obj_priv->pin_count++; - - /* If the object is not active and not pending a flush, - * remove it from the inactive list - */ - if (obj_priv->pin_count == 1) { + if (obj_priv->pin_count++ == 0) { i915_gem_info_add_pin(dev_priv, obj, mappable); if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, @@ -4153,15 +4148,10 @@ i915_gem_object_unpin(struct drm_gem_object *obj) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); WARN_ON(i915_verify_lists(dev)); - obj_priv->pin_count--; - BUG_ON(obj_priv->pin_count < 0); + BUG_ON(obj_priv->pin_count == 0); BUG_ON(obj_priv->gtt_space == NULL); - /* If the object is no longer pinned, and is - * neither active nor being flushed, then stick it on - * the inactive list - */ - if (obj_priv->pin_count == 0) { + if (--obj_priv->pin_count == 0) { if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); -- cgit v1.2.3 From a00b10c360b35d6431a94cbf130a4e162870d661 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Sep 2010 21:15:47 +0100 Subject: drm/i915: Only enforce fence limits inside the GTT. So long as we adhere to the fence registers rules for alignment and no overlaps (including with unfenced accesses to linear memory) and account for the tiled access in our size allocation, we do not have to allocate the full fenced region for the object. This allows us to fight the bloat tiling imposed on pre-i965 chipsets and frees up RAM for real use. [Inside the GTT we still suffer the additional alignment constraints, so it doesn't magic allow us to render larger scenes without stalls -- we need the expanded GTT and fence pipelining to overcome those...] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +- drivers/gpu/drm/i915/i915_dma.c | 3 + drivers/gpu/drm/i915/i915_drv.h | 8 +- drivers/gpu/drm/i915/i915_gem.c | 290 +++++++++++++++++--------------- drivers/gpu/drm/i915/i915_gem_tiling.c | 32 ++-- drivers/gpu/drm/i915/intel_display.c | 7 +- drivers/gpu/drm/i915/intel_overlay.c | 4 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +- include/drm/i915_drm.h | 1 + 9 files changed, 197 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4fc1e05b769f..ba2af4e046ed 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -130,7 +130,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) if (obj->fence_reg != I915_FENCE_REG_NONE) seq_printf(m, " (fence: %d)", obj->fence_reg); if (obj->gtt_space != NULL) - seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset); + seq_printf(m, " (gtt offset: %08x, size: %08x)", + obj->gtt_offset, (unsigned int)obj->gtt_space->size); if (obj->pin_mappable || obj->fault_mappable) seq_printf(m, " (mappable)"); if (obj->ring != NULL) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index dddca007912a..00d8fb3e989f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -770,6 +770,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_BLT: value = HAS_BLT(dev); break; + case I915_PARAM_HAS_RELAXED_FENCING: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3df8a624ddc9..7aa7f8abf892 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -746,6 +746,8 @@ struct drm_i915_gem_object { * Advice: are the backing pages purgeable? */ unsigned int madv : 2; + unsigned int fenceable : 1; + unsigned int mappable : 1; /** * Current tiling mode for the object. @@ -1005,7 +1007,7 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, - bool mappable); + bool mappable, bool need_fence); void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_release_mmap(struct drm_gem_object *obj); @@ -1068,10 +1070,6 @@ int i915_gem_evict_inactive(struct drm_device *dev); void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj); void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj); -bool i915_tiling_ok(struct drm_device *dev, int stride, int size, - int tiling_mode); -bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, - int tiling_mode); /* i915_gem_debug.c */ void i915_gem_dump_object(struct drm_gem_object *obj, int len, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 08f57aedaf51..07ad1e354084 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -36,7 +36,8 @@ #include #include -static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); +static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv); +static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv); static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, bool pipelined); @@ -51,7 +52,9 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, bool interruptible); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, - unsigned alignment, bool mappable); + unsigned alignment, + bool mappable, + bool need_fence); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -79,30 +82,26 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, } static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv, - struct drm_gem_object *obj) + struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.gtt_count++; - dev_priv->mm.gtt_memory += obj->size; - if (obj_priv->gtt_offset < dev_priv->mm.gtt_mappable_end) { + dev_priv->mm.gtt_memory += obj->gtt_space->size; + if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) { dev_priv->mm.mappable_gtt_used += - min_t(size_t, obj->size, - dev_priv->mm.gtt_mappable_end - - obj_priv->gtt_offset); + min_t(size_t, obj->gtt_space->size, + dev_priv->mm.gtt_mappable_end - obj->gtt_offset); } } static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, - struct drm_gem_object *obj) + struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.gtt_count--; - dev_priv->mm.gtt_memory -= obj->size; - if (obj_priv->gtt_offset < dev_priv->mm.gtt_mappable_end) { + dev_priv->mm.gtt_memory -= obj->gtt_space->size; + if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) { dev_priv->mm.mappable_gtt_used -= - min_t(size_t, obj->size, - dev_priv->mm.gtt_mappable_end - - obj_priv->gtt_offset); + min_t(size_t, obj->gtt_space->size, + dev_priv->mm.gtt_mappable_end - obj->gtt_offset); } } @@ -113,47 +112,43 @@ static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, */ static void i915_gem_info_update_mappable(struct drm_i915_private *dev_priv, - struct drm_gem_object *obj, + struct drm_i915_gem_object *obj, bool mappable) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - if (mappable) { - if (obj_priv->pin_mappable && obj_priv->fault_mappable) + if (obj->pin_mappable && obj->fault_mappable) /* Combined state was already mappable. */ return; dev_priv->mm.gtt_mappable_count++; - dev_priv->mm.gtt_mappable_memory += obj->size; + dev_priv->mm.gtt_mappable_memory += obj->gtt_space->size; } else { - if (obj_priv->pin_mappable || obj_priv->fault_mappable) + if (obj->pin_mappable || obj->fault_mappable) /* Combined state still mappable. */ return; dev_priv->mm.gtt_mappable_count--; - dev_priv->mm.gtt_mappable_memory -= obj->size; + dev_priv->mm.gtt_mappable_memory -= obj->gtt_space->size; } } static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv, - struct drm_gem_object *obj, + struct drm_i915_gem_object *obj, bool mappable) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.pin_count++; - dev_priv->mm.pin_memory += obj->size; + dev_priv->mm.pin_memory += obj->gtt_space->size; if (mappable) { - obj_priv->pin_mappable = true; + obj->pin_mappable = true; i915_gem_info_update_mappable(dev_priv, obj, true); } } static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv, - struct drm_gem_object *obj) + struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.pin_count--; - dev_priv->mm.pin_memory -= obj->size; - if (obj_priv->pin_mappable) { - obj_priv->pin_mappable = false; + dev_priv->mm.pin_memory -= obj->gtt_space->size; + if (obj->pin_mappable) { + obj->pin_mappable = false; i915_gem_info_update_mappable(dev_priv, obj, false); } } @@ -309,16 +304,6 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, return 0; } -static bool -i915_gem_object_cpu_accessible(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - return obj->gtt_space == NULL || - obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; -} - static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj) { drm_i915_private_t *dev_priv = obj->dev->dev_private; @@ -1083,7 +1068,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, else if (obj_priv->tiling_mode == I915_TILING_NONE && obj_priv->gtt_space && obj->write_domain != I915_GEM_DOMAIN_CPU) { - ret = i915_gem_object_pin(obj, 0, true); + ret = i915_gem_object_pin(obj, 0, true, false); if (ret) goto out; @@ -1307,11 +1292,19 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Now bind it into the GTT if needed */ mutex_lock(&dev->struct_mutex); BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable); - if (!i915_gem_object_cpu_accessible(obj_priv)) - i915_gem_object_unbind(obj); + + if (obj_priv->gtt_space) { + if (!obj_priv->mappable || + (obj_priv->tiling_mode && !obj_priv->fenceable)) { + ret = i915_gem_object_unbind(obj); + if (ret) + goto unlock; + } + } if (!obj_priv->gtt_space) { - ret = i915_gem_object_bind_to_gtt(obj, 0, true); + ret = i915_gem_object_bind_to_gtt(obj, 0, + true, obj_priv->tiling_mode); if (ret) goto unlock; } @@ -1322,7 +1315,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!obj_priv->fault_mappable) { obj_priv->fault_mappable = true; - i915_gem_info_update_mappable(dev_priv, obj, true); + i915_gem_info_update_mappable(dev_priv, obj_priv, true); } /* Need a new fence register? */ @@ -1448,7 +1441,7 @@ i915_gem_release_mmap(struct drm_gem_object *obj) if (obj_priv->fault_mappable) { obj_priv->fault_mappable = false; - i915_gem_info_update_mappable(dev_priv, obj, false); + i915_gem_info_update_mappable(dev_priv, obj_priv, false); } } @@ -1473,32 +1466,51 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj) * potential fence register mapping if needed. */ static uint32_t -i915_gem_get_gtt_alignment(struct drm_gem_object *obj) +i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv) { - struct drm_device *dev = obj->dev; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - int start, i; + struct drm_device *dev = obj_priv->base.dev; /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ - if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE) + if (INTEL_INFO(dev)->gen >= 4 || + obj_priv->tiling_mode == I915_TILING_NONE) return 4096; + /* + * Previous chips need to be aligned to the size of the smallest + * fence register that can contain the object. + */ + return i915_gem_get_gtt_size(obj_priv); +} + +static uint32_t +i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) +{ + struct drm_device *dev = obj_priv->base.dev; + uint32_t size; + + /* + * Minimum alignment is 4k (GTT page size), but might be greater + * if a fence register is needed for the object. + */ + if (INTEL_INFO(dev)->gen >= 4) + return obj_priv->base.size; + /* * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. */ if (INTEL_INFO(dev)->gen == 3) - start = 1024*1024; + size = 1024*1024; else - start = 512*1024; + size = 512*1024; - for (i = start; i < obj->size; i <<= 1) - ; + while (size < obj_priv->base.size) + size <<= 1; - return i; + return size; } /** @@ -2253,8 +2265,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj) i915_gem_object_put_pages_gtt(obj); - i915_gem_info_remove_gtt(dev_priv, obj); + i915_gem_info_remove_gtt(dev_priv, obj_priv); list_del_init(&obj_priv->mm_list); + obj_priv->fenceable = true; + obj_priv->mappable = true; drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; @@ -2311,16 +2325,16 @@ i915_gpu_idle(struct drm_device *dev) return 0; } -static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) +static void sandybridge_write_fence_reg(struct drm_gem_object *obj) { - struct drm_gem_object *obj = reg->obj; struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + u32 size = i915_gem_get_gtt_size(obj_priv); int regnum = obj_priv->fence_reg; uint64_t val; - val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & + val = (uint64_t)((obj_priv->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj_priv->gtt_offset & 0xfffff000; val |= (uint64_t)((obj_priv->stride / 128) - 1) << @@ -2333,16 +2347,16 @@ static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg) I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val); } -static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) +static void i965_write_fence_reg(struct drm_gem_object *obj) { - struct drm_gem_object *obj = reg->obj; struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + u32 size = i915_gem_get_gtt_size(obj_priv); int regnum = obj_priv->fence_reg; uint64_t val; - val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & + val = (uint64_t)((obj_priv->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj_priv->gtt_offset & 0xfffff000; val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; @@ -2353,21 +2367,20 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val); } -static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) +static void i915_write_fence_reg(struct drm_gem_object *obj) { - struct drm_gem_object *obj = reg->obj; struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - int regnum = obj_priv->fence_reg; + u32 size = i915_gem_get_gtt_size(obj_priv); + uint32_t fence_reg, val, pitch_val; int tile_width; - uint32_t fence_reg, val; - uint32_t pitch_val; if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || - (obj_priv->gtt_offset & (obj->size - 1))) { - WARN(1, "%s: object 0x%08x not 1M or size (0x%zx) aligned\n", - __func__, obj_priv->gtt_offset, obj->size); + (obj_priv->gtt_offset & (size - 1))) { + WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n", + __func__, obj_priv->gtt_offset, obj_priv->fenceable, size, + obj_priv->gtt_space->start, obj_priv->gtt_space->size); return; } @@ -2390,23 +2403,24 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) val = obj_priv->gtt_offset; if (obj_priv->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I915_FENCE_SIZE_BITS(obj->size); + val |= I915_FENCE_SIZE_BITS(size); val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; - if (regnum < 8) - fence_reg = FENCE_REG_830_0 + (regnum * 4); + fence_reg = obj_priv->fence_reg; + if (fence_reg < 8) + fence_reg = FENCE_REG_830_0 + fence_reg * 4; else - fence_reg = FENCE_REG_945_8 + ((regnum - 8) * 4); + fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; I915_WRITE(fence_reg, val); } -static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) +static void i830_write_fence_reg(struct drm_gem_object *obj) { - struct drm_gem_object *obj = reg->obj; struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + u32 size = i915_gem_get_gtt_size(obj_priv); int regnum = obj_priv->fence_reg; uint32_t val; uint32_t pitch_val; @@ -2426,7 +2440,7 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) val = obj_priv->gtt_offset; if (obj_priv->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; - fence_size_bits = I830_FENCE_SIZE_BITS(obj->size); + fence_size_bits = I830_FENCE_SIZE_BITS(size); WARN_ON(fence_size_bits & ~0x00000f00); val |= fence_size_bits; val |= pitch_val << I830_FENCE_PITCH_SHIFT; @@ -2438,10 +2452,9 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) static int i915_find_fence_reg(struct drm_device *dev, bool interruptible) { - struct drm_i915_fence_reg *reg = NULL; - struct drm_i915_gem_object *obj_priv = NULL; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_gem_object *obj = NULL; + struct drm_i915_fence_reg *reg; + struct drm_i915_gem_object *obj_priv = NULL; int i, avail, ret; /* First try to find a free reg */ @@ -2460,33 +2473,31 @@ static int i915_find_fence_reg(struct drm_device *dev, return -ENOSPC; /* None available, try to steal one or wait for a user to finish */ - i = I915_FENCE_REG_NONE; + avail = I915_FENCE_REG_NONE; list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { - obj = reg->obj; - obj_priv = to_intel_bo(obj); - + obj_priv = to_intel_bo(reg->obj); if (obj_priv->pin_count) continue; /* found one! */ - i = obj_priv->fence_reg; + avail = obj_priv->fence_reg; break; } - BUG_ON(i == I915_FENCE_REG_NONE); + BUG_ON(avail == I915_FENCE_REG_NONE); /* We only have a reference on obj from the active list. put_fence_reg * might drop that one, causing a use-after-free in it. So hold a * private reference to obj like the other callers of put_fence_reg * (set_tiling ioctl) do. */ - drm_gem_object_reference(obj); - ret = i915_gem_object_put_fence_reg(obj, interruptible); - drm_gem_object_unreference(obj); + drm_gem_object_reference(&obj_priv->base); + ret = i915_gem_object_put_fence_reg(&obj_priv->base, interruptible); + drm_gem_object_unreference(&obj_priv->base); if (ret != 0) return ret; - return i; + return avail; } /** @@ -2551,22 +2562,23 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, switch (INTEL_INFO(dev)->gen) { case 6: - sandybridge_write_fence_reg(reg); + sandybridge_write_fence_reg(obj); break; case 5: case 4: - i965_write_fence_reg(reg); + i965_write_fence_reg(obj); break; case 3: - i915_write_fence_reg(reg); + i915_write_fence_reg(obj); break; case 2: - i830_write_fence_reg(reg); + i830_write_fence_reg(obj); break; } - trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg, - obj_priv->tiling_mode); + trace_i915_gem_object_get_fence(obj, + obj_priv->fence_reg, + obj_priv->tiling_mode); return 0; } @@ -2671,13 +2683,15 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment, - bool mappable) + bool mappable, + bool need_fence) { struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_mm_node *free_space; - gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; + gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; + u32 size, fence_size, fence_alignment; int ret; if (obj_priv->madv != I915_MADV_WILLNEED) { @@ -2685,13 +2699,18 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, return -EINVAL; } + fence_size = i915_gem_get_gtt_size(obj_priv); + fence_alignment = i915_gem_get_gtt_alignment(obj_priv); + if (alignment == 0) - alignment = i915_gem_get_gtt_alignment(obj); - if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) { + alignment = need_fence ? fence_alignment : 4096; + if (need_fence && alignment & (fence_alignment - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); return -EINVAL; } + size = need_fence ? fence_size : obj->size; + /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ @@ -2705,32 +2724,29 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, if (mappable) free_space = drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, - obj->size, alignment, 0, + size, alignment, 0, dev_priv->mm.gtt_mappable_end, 0); else free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, - obj->size, alignment, 0); + size, alignment, 0); if (free_space != NULL) { if (mappable) obj_priv->gtt_space = drm_mm_get_block_range_generic(free_space, - obj->size, - alignment, 0, + size, alignment, 0, dev_priv->mm.gtt_mappable_end, 0); else obj_priv->gtt_space = - drm_mm_get_block(free_space, obj->size, - alignment); + drm_mm_get_block(free_space, size, alignment); } if (obj_priv->gtt_space == NULL) { /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ - ret = i915_gem_evict_something(dev, obj->size, alignment, - mappable); + ret = i915_gem_evict_something(dev, size, alignment, mappable); if (ret) return ret; @@ -2744,7 +2760,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ - ret = i915_gem_evict_something(dev, obj->size, + ret = i915_gem_evict_something(dev, size, alignment, mappable); if (ret) { /* now try to shrink everyone else */ @@ -2775,8 +2791,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; - ret = i915_gem_evict_something(dev, obj->size, alignment, - mappable); + ret = i915_gem_evict_something(dev, size, + alignment, mappable); if (ret) return ret; @@ -2787,7 +2803,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, /* keep track of bounds object by adding it to the inactive list */ list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_add_gtt(dev_priv, obj); + i915_gem_info_add_gtt(dev_priv, obj_priv); /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in @@ -2798,6 +2814,13 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, mappable); + obj_priv->fenceable = + obj_priv->gtt_space->size == fence_size && + (obj_priv->gtt_space->start & (fence_alignment -1)) == 0; + + obj_priv->mappable = + obj_priv->gtt_offset + obj->size <= dev_priv->mm.gtt_mappable_end; + return 0; } @@ -3516,9 +3539,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev, entry->relocation_count ? true : need_fence; /* Check fence reg constraints and rebind if necessary */ - if (need_fence && - !i915_gem_object_fence_offset_ok(&obj->base, - obj->tiling_mode)) { + if ((need_fence && !obj->fenceable) || + (need_mappable && !obj->mappable)) { ret = i915_gem_object_unbind(&obj->base); if (ret) break; @@ -3526,7 +3548,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev, ret = i915_gem_object_pin(&obj->base, entry->alignment, - need_mappable); + need_mappable, + need_fence); if (ret) break; @@ -4097,7 +4120,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, - bool mappable) + bool mappable, bool need_fence) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4108,14 +4131,15 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, WARN_ON(i915_verify_lists(dev)); if (obj_priv->gtt_space != NULL) { - if (alignment == 0) - alignment = i915_gem_get_gtt_alignment(obj); - if (obj_priv->gtt_offset & (alignment - 1) || - (mappable && !i915_gem_object_cpu_accessible(obj_priv))) { + if ((alignment && obj_priv->gtt_offset & (alignment - 1)) || + (need_fence && !obj_priv->fenceable) || + (mappable && !obj_priv->mappable)) { WARN(obj_priv->pin_count, "bo is already pinned with incorrect alignment:" - " offset=%x, req.alignment=%x\n", - obj_priv->gtt_offset, alignment); + " offset=%x, req.alignment=%x, need_fence=%d, fenceable=%d, mappable=%d, cpu_accessible=%d\n", + obj_priv->gtt_offset, alignment, + need_fence, obj_priv->fenceable, + mappable, obj_priv->mappable); ret = i915_gem_object_unbind(obj); if (ret) return ret; @@ -4123,13 +4147,14 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, } if (obj_priv->gtt_space == NULL) { - ret = i915_gem_object_bind_to_gtt(obj, alignment, mappable); + ret = i915_gem_object_bind_to_gtt(obj, alignment, + mappable, need_fence); if (ret) return ret; } if (obj_priv->pin_count++ == 0) { - i915_gem_info_add_pin(dev_priv, obj, mappable); + i915_gem_info_add_pin(dev_priv, obj_priv, mappable); if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list); @@ -4155,7 +4180,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_remove_pin(dev_priv, obj); + i915_gem_info_remove_pin(dev_priv, obj_priv); } WARN_ON(i915_verify_lists(dev)); } @@ -4196,7 +4221,8 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, obj_priv->user_pin_count++; obj_priv->pin_filp = file_priv; if (obj_priv->user_pin_count == 1) { - ret = i915_gem_object_pin(obj, args->alignment, true); + ret = i915_gem_object_pin(obj, args->alignment, + true, obj_priv->tiling_mode); if (ret) goto out; } @@ -4389,6 +4415,8 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->gpu_write_list); obj->madv = I915_MADV_WILLNEED; + obj->fenceable = true; + obj->mappable = true; return &obj->base; } @@ -4508,7 +4536,7 @@ i915_gem_init_pipe_control(struct drm_device *dev) obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - ret = i915_gem_object_pin(obj, 4096, true); + ret = i915_gem_object_pin(obj, 4096, true, false); if (ret) goto err_unref; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index af352de70be1..0597a737ebad 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -181,7 +181,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } /* Check pitch constriants for all chips & tiling formats */ -bool +static bool i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) { int tile_width; @@ -232,25 +232,35 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) return true; } -bool -i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) +/* Is the current GTT allocation valid for the change in tiling? */ +static bool +i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode) { - struct drm_device *dev = obj->dev; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - - if (obj_priv->gtt_space == NULL) - return true; + u32 size; if (tiling_mode == I915_TILING_NONE) return true; - if (INTEL_INFO(dev)->gen >= 4) + if (INTEL_INFO(obj->dev)->gen >= 4) return true; - if (obj_priv->gtt_offset & (obj->size - 1)) + /* + * Previous chips need to be aligned to the size of the smallest + * fence register that can contain the object. + */ + if (INTEL_INFO(obj->dev)->gen == 3) + size = 1024*1024; + else + size = 512*1024; + + while (size < obj_priv->base.size) + size <<= 1; + + if (obj_priv->gtt_offset & (size - 1)) return false; - if (IS_GEN3(dev)) { + if (INTEL_INFO(obj->dev)->gen == 3) { if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) return false; } else { @@ -331,7 +341,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, * tiling mode. Otherwise we can just leave it alone, but * need to ensure that any fence register is cleared. */ - if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) + if (!i915_gem_object_fence_ok(obj, args->tiling_mode)) ret = i915_gem_object_unbind(obj); else if (obj_priv->fence_reg != I915_FENCE_REG_NONE) ret = i915_gem_object_put_fence_reg(obj, true); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c9c4c707cf1a..4954af23b7c8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1461,7 +1461,8 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, BUG(); } - ret = i915_gem_object_pin(obj, alignment, true); + ret = i915_gem_object_pin(obj, alignment, + !pipelined, obj_priv->tiling_mode); if (ret) return ret; @@ -4353,7 +4354,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { - ret = i915_gem_object_pin(bo, PAGE_SIZE, true); + ret = i915_gem_object_pin(bo, PAGE_SIZE, true, false); if (ret) { DRM_ERROR("failed to pin cursor bo\n"); goto fail_locked; @@ -5517,7 +5518,7 @@ intel_alloc_context_page(struct drm_device *dev) } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(ctx, 4096, true); + ret = i915_gem_object_pin(ctx, 4096, false, false); if (ret) { DRM_ERROR("failed to pin power context: %d\n", ret); goto err_unref; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index beda2016eb16..e62e1b3d243f 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -781,7 +781,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) return ret; - ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true); + ret = i915_gem_object_pin(new_bo, PAGE_SIZE, false, false); if (ret != 0) return ret; @@ -1423,7 +1423,7 @@ void intel_setup_overlay(struct drm_device *dev) } overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; } else { - ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true); + ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false); if (ret) { DRM_ERROR("failed to pin overlay register bo\n"); goto out_free_bo; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e88214ef24b1..632a98e0ba5c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -547,7 +547,7 @@ static int init_status_page(struct intel_ring_buffer *ring) obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - ret = i915_gem_object_pin(obj, 4096, true); + ret = i915_gem_object_pin(obj, 4096, true, false); if (ret != 0) { goto err_unref; } @@ -603,7 +603,7 @@ int intel_init_ring_buffer(struct drm_device *dev, ring->gem_object = obj; - ret = i915_gem_object_pin(obj, PAGE_SIZE, true); + ret = i915_gem_object_pin(obj, PAGE_SIZE, true, false); if (ret) goto err_unref; diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 8c641bed9bbd..b20dbb2d7174 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -287,6 +287,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_EXECBUF2 9 #define I915_PARAM_HAS_BSD 10 #define I915_PARAM_HAS_BLT 11 +#define I915_PARAM_HAS_RELAXED_FENCING 12 typedef struct drm_i915_getparam { int param; -- cgit v1.2.3 From 872d860c85e30cdc97e7c91723257f4fcf04d5e9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Oct 2010 23:43:30 +0100 Subject: drm/i915: Remove the duplicate domain-change tracepoint for GPU flush Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 07ad1e354084..936ddd83f8a2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2847,22 +2847,16 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, bool pipelined) { struct drm_device *dev = obj->dev; - uint32_t old_write_domain; if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) return 0; /* Queue the GPU write cache flushing we need. */ - old_write_domain = obj->write_domain; i915_gem_flush_ring(dev, NULL, to_intel_bo(obj)->ring, 0, obj->write_domain); BUG_ON(obj->write_domain); - trace_i915_gem_object_change_domain(obj, - obj->read_domains, - old_write_domain); - if (pipelined) return 0; -- cgit v1.2.3 From 33626e6a08669b1a5834e76363dcd5c8733a4278 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 16:18:36 +0100 Subject: drm/i915/ringbuffer: Disable the ringbuffer on cleanup. It should be idle on cleanup anyway... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 632a98e0ba5c..0f1693981ee6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -651,9 +651,17 @@ err_hws: void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) { + struct drm_i915_private *dev_priv; + int ret; + if (ring->gem_object == NULL) return; + /* Disable the ring buffer. The ring must be idle at this point */ + dev_priv = ring->dev->dev_private; + ret = intel_wait_ring_buffer(ring, ring->size - 8); + I915_WRITE_CTL(ring, 0); + drm_core_ioremapfree(&ring->map, ring->dev); i915_gem_object_unpin(ring->gem_object); -- cgit v1.2.3 From 1d8f38f4e7146d22f7fbc94eef0508bd75463f54 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 19:00:51 +0100 Subject: drm/i915: Record BLT engine error state Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 19 +++++++++++++------ drivers/gpu/drm/i915/i915_drv.h | 7 ++++++- drivers/gpu/drm/i915/i915_irq.c | 7 +++++++ drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 4 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ba2af4e046ed..70eec5aceabe 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -616,21 +616,28 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); + seq_printf(m, "EIR: 0x%08x\n", error->eir); + seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); if (INTEL_INFO(dev)->gen >= 6) { seq_printf(m, "ERROR: 0x%08x\n", error->error); + seq_printf(m, "Blitter command stream:\n"); + seq_printf(m, " ACTHD: 0x%08x\n", error->bcs_acthd); + seq_printf(m, " IPEHR: 0x%08x\n", error->bcs_ipehr); + seq_printf(m, " IPEIR: 0x%08x\n", error->bcs_ipeir); + seq_printf(m, " INSTDONE: 0x%08x\n", error->bcs_instdone); + seq_printf(m, " seqno: 0x%08x\n", error->bcs_seqno); } - seq_printf(m, "EIR: 0x%08x\n", error->eir); - seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); - seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); + seq_printf(m, "Render command stream:\n"); + seq_printf(m, " ACTHD: 0x%08x\n", error->acthd); seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir); seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr); seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone); - seq_printf(m, " ACTHD: 0x%08x\n", error->acthd); if (INTEL_INFO(dev)->gen >= 4) { - seq_printf(m, " INSTPS: 0x%08x\n", error->instps); seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); + seq_printf(m, " INSTPS: 0x%08x\n", error->instps); } - seq_printf(m, "seqno: 0x%08x\n", error->seqno); + seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); + seq_printf(m, " seqno: 0x%08x\n", error->seqno); if (error->active_bo_count) { seq_printf(m, "Buffers [%d]:\n", error->active_bo_count); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7aa7f8abf892..05bff9e6a9cb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -142,13 +142,18 @@ struct sdvo_device_mapping { struct drm_i915_error_state { u32 eir; u32 pgtbl_er; - u32 error; /* gen6+ */ u32 pipeastat; u32 pipebstat; u32 ipeir; u32 ipehr; u32 instdone; u32 acthd; + u32 error; /* gen6+ */ + u32 bcs_acthd; /* gen6+ blt engine */ + u32 bcs_ipehr; + u32 bcs_ipeir; + u32 bcs_instdone; + u32 bcs_seqno; u32 instpm; u32 instps; u32 instdone1; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2a29497a4694..4ff39dee7f1c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -595,6 +595,13 @@ static void i915_capture_error_state(struct drm_device *dev) error->error = 0; if (INTEL_INFO(dev)->gen >= 6) { error->error = I915_READ(ERROR_GEN6); + error->bcs_acthd = I915_READ(BCS_ACTHD); + error->bcs_ipehr = I915_READ(BCS_IPEHR); + error->bcs_ipeir = I915_READ(BCS_IPEIR); + error->bcs_instdone = I915_READ(BCS_INSTDONE); + error->bcs_seqno = 0; + if (dev_priv->blt_ring.get_seqno) + error->bcs_seqno = dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring); } if (INTEL_INFO(dev)->gen >= 4) { error->ipeir = I915_READ(IPEIR_I965); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fc161196da21..b173e5b77f96 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -305,6 +305,10 @@ #define INSTDONE 0x02090 #define NOPID 0x02094 #define HWSTAM 0x02098 +#define BCS_INSTDONE 0x2206C +#define BCS_IPEIR 0x22064 +#define BCS_IPEHR 0x22068 +#define BCS_ACTHD 0x22074 #define ERROR_GEN6 0x040a0 -- cgit v1.2.3 From c584fe47e4d92934c10e5d7f932ee042587dbcff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 18:15:52 +0100 Subject: drm/i915/ringbuffer: Remove duplicate initialisation of ring control Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 0f1693981ee6..4d00da97905f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -578,7 +578,6 @@ err: int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; struct drm_gem_object *obj; int ret; @@ -626,16 +625,7 @@ int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto err_unmap; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_kernel_lost_context(dev); - else { - ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; - ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->size; - } - return ret; + return 0; err_unmap: drm_core_ioremapfree(&ring->map, dev); -- cgit v1.2.3 From e380f60b22eddec7825224b8d788572c82b63161 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 18:11:26 +0100 Subject: agp/intel: Sandybridge doesn't require GMCH enabling Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 5dc1f5db55a7..9c86dac41da7 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -922,10 +922,11 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, writel(addr | pte_flags, intel_private.gtt + entry); } -static void intel_enable_gtt(void) +static bool intel_enable_gtt(void) { u32 gma_addr; u16 gmch_ctrl; + u8 __iomem *reg; if (INTEL_GTT_GEN == 2) pci_read_config_dword(intel_private.pcidev, I810_GMADDR, @@ -936,13 +937,34 @@ static void intel_enable_gtt(void) intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); - pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); + if (INTEL_GTT_GEN >= 6) + return true; + + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); + pci_write_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, gmch_ctrl); - writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED, - intel_private.registers+I810_PGETBL_CTL); - readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); + if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { + dev_err(&intel_private.pcidev->dev, + "failed to enable the GTT: GMCH_CTRL=%x\n", + gmch_ctrl); + return false; + } + + reg = intel_private.registers+I810_PGETBL_CTL; + writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED, reg); + if ((readl(reg) & I810_PGETBL_ENABLED) == 0) { + dev_err(&intel_private.pcidev->dev, + "failed to enable the GTT: PGETBL=%x [expected %x|1]\n", + readl(reg), intel_private.PGETBL_save); + return false; + } + + return true; } static int i830_setup(void) @@ -981,7 +1003,8 @@ static int intel_fake_agp_configure(void) { int i; - intel_enable_gtt(); + if (!intel_enable_gtt()) + return -EIO; agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; -- cgit v1.2.3 From 4066c0ae13a8388b9f2a29cad60da330b578eff2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 21:00:54 +0100 Subject: drm/i915/debugfs: Display the contents of the BLT and BSD status pages Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 70eec5aceabe..58cf60d89f68 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -445,10 +445,18 @@ static int i915_hws_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int i; + struct intel_ring_buffer *ring; volatile u32 *hws; + int i; + + switch ((uintptr_t)node->info_ent->data) { + case RENDER_RING: ring = &dev_priv->render_ring; break; + case BSD_RING: ring = &dev_priv->bsd_ring; break; + case BLT_RING: ring = &dev_priv->blt_ring; break; + default: return -EINVAL; + } - hws = (volatile u32 *)dev_priv->render_ring.status_page.page_addr; + hws = (volatile u32 *)ring->status_page.page_addr; if (hws == NULL) return 0; @@ -1087,7 +1095,9 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_seqno", i915_gem_seqno_info, 0}, {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, {"i915_gem_interrupt", i915_interrupt_info, 0}, - {"i915_gem_hws", i915_hws_info, 0}, + {"i915_gem_hws", i915_hws_info, 0, (void *)RENDER_RING}, + {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BLT_RING}, + {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)BSD_RING}, {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RENDER_RING}, {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RENDER_RING}, {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BSD_RING}, -- cgit v1.2.3 From 6dda569fe0fb71a03e2a2e815761796f98232cdb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 21:02:18 +0100 Subject: drm/i915: Switch to using pci_iounmap in conjunction with pci_iomap After switching the MMIO registers to use pci_iomap, remember to dispose of the mapping with pci_iounmap (for symmetry). Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 00d8fb3e989f..eee88cfcb3aa 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2082,7 +2082,7 @@ out_workqueue_free: out_iomapfree: io_mapping_free(dev_priv->mm.gtt_mapping); out_rmmap: - iounmap(dev_priv->regs); + pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: pci_dev_put(dev_priv->bridge_dev); free_priv: @@ -2168,7 +2168,7 @@ int i915_driver_unload(struct drm_device *dev) } if (dev_priv->regs != NULL) - iounmap(dev_priv->regs); + pci_iounmap(dev->pdev, dev_priv->regs); intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); -- cgit v1.2.3 From f4e0b29bf23687ac16dc476bd90cd4d8b0eacd5c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 21:06:16 +0100 Subject: drm/i915: Check if the GPU hung whilst waiting for the ring to clear Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4d00da97905f..2e72d3a0740f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -711,6 +711,8 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) } msleep(1); + if (atomic_read(&dev_priv->mm.wedged)) + return -EAGAIN; } while (!time_after(jiffies, end)); trace_i915_ring_wait_end (dev); return -EBUSY; -- cgit v1.2.3 From 6aa56062eaba67adfb247cded244fd877329588d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 21:44:37 +0100 Subject: drm/i915/ringbuffer: Use the HEAD auto-reporting mechanism My Sandybridge only reports 0 for the ring buffer registers, causing it to hang as soon as we exhaust the available ring. As a workaround, take advantage of our huge ring buffers and use the auto-reporting mechanism to update the status page with the HEAD location every 64 KiB. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2e72d3a0740f..390aa21edbe4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -174,7 +174,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) - | RING_NO_REPORT | RING_VALID); + | RING_REPORT_64K | RING_VALID); /* If the head is still not zero, the ring is dead */ if ((I915_READ_CTL(ring) & RING_VALID) == 0 || @@ -691,6 +691,17 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; unsigned long end; + u32 head; + + head = intel_read_status_page(ring, 4); + if (head) { + ring->head = head & HEAD_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->size; + if (ring->space >= n) + return 0; + } trace_i915_ring_wait_begin (dev); end = jiffies + 3 * HZ; -- cgit v1.2.3 From add354ddf62beac55ca3ba64835dd703a0649867 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Oct 2010 19:00:51 +0100 Subject: drm/i915: Record BSD engine error state Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 6 ++++++ drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_irq.c | 9 +++++++++ drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 4 files changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 58cf60d89f68..56f7ced16f1a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -634,6 +634,12 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, " IPEIR: 0x%08x\n", error->bcs_ipeir); seq_printf(m, " INSTDONE: 0x%08x\n", error->bcs_instdone); seq_printf(m, " seqno: 0x%08x\n", error->bcs_seqno); + seq_printf(m, "Video (BSD) command stream:\n"); + seq_printf(m, " ACTHD: 0x%08x\n", error->vcs_acthd); + seq_printf(m, " IPEHR: 0x%08x\n", error->vcs_ipehr); + seq_printf(m, " IPEIR: 0x%08x\n", error->vcs_ipeir); + seq_printf(m, " INSTDONE: 0x%08x\n", error->vcs_instdone); + seq_printf(m, " seqno: 0x%08x\n", error->vcs_seqno); } seq_printf(m, "Render command stream:\n"); seq_printf(m, " ACTHD: 0x%08x\n", error->acthd); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 05bff9e6a9cb..ec582b6d2113 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -154,6 +154,11 @@ struct drm_i915_error_state { u32 bcs_ipeir; u32 bcs_instdone; u32 bcs_seqno; + u32 vcs_acthd; /* gen6+ bsd engine */ + u32 vcs_ipehr; + u32 vcs_ipeir; + u32 vcs_instdone; + u32 vcs_seqno; u32 instpm; u32 instps; u32 instdone1; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4ff39dee7f1c..90c071d37748 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -595,6 +595,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->error = 0; if (INTEL_INFO(dev)->gen >= 6) { error->error = I915_READ(ERROR_GEN6); + error->bcs_acthd = I915_READ(BCS_ACTHD); error->bcs_ipehr = I915_READ(BCS_IPEHR); error->bcs_ipeir = I915_READ(BCS_IPEIR); @@ -602,6 +603,14 @@ static void i915_capture_error_state(struct drm_device *dev) error->bcs_seqno = 0; if (dev_priv->blt_ring.get_seqno) error->bcs_seqno = dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring); + + error->vcs_acthd = I915_READ(VCS_ACTHD); + error->vcs_ipehr = I915_READ(VCS_IPEHR); + error->vcs_ipeir = I915_READ(VCS_IPEIR); + error->vcs_instdone = I915_READ(VCS_INSTDONE); + error->vcs_seqno = 0; + if (dev_priv->bsd_ring.get_seqno) + error->vcs_seqno = dev_priv->bsd_ring.get_seqno(&dev_priv->bsd_ring); } if (INTEL_INFO(dev)->gen >= 4) { error->ipeir = I915_READ(IPEIR_I965); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b173e5b77f96..c79d4ba4fb12 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -305,6 +305,10 @@ #define INSTDONE 0x02090 #define NOPID 0x02094 #define HWSTAM 0x02098 +#define VCS_INSTDONE 0x1206C +#define VCS_IPEIR 0x12064 +#define VCS_IPEHR 0x12068 +#define VCS_ACTHD 0x12074 #define BCS_INSTDONE 0x2206C #define BCS_IPEIR 0x22064 #define BCS_IPEHR 0x22068 -- cgit v1.2.3 From 2e44f765dfd3a8592c2d6b6005be061eccdee137 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 07:44:45 -0700 Subject: beceem: add module information Add description and version information to the driver. Make USB device table exported as alias so device will be autoloaded. Get rid of useless noise message on boot. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 25 +++++++++++-------------- drivers/staging/bcm/InterfaceInit.c | 13 +++++++------ 2 files changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index bc2969821421..4d7d8cd4bf43 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -1,5 +1,9 @@ #include "headers.h" +#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver" +#define DRV_VERSION "5.2.7.3P1" +#define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc" + static INT bcm_notify_event(struct notifier_block *nb, ULONG event, PVOID dev) { struct net_device *ndev = (struct net_device*)dev; @@ -236,29 +240,22 @@ void bcm_unregister_networkdev(PMINI_ADAPTER Adapter) static int bcm_init(void) { - int result; - result = InterfaceInitialize(); - if(result) - { - printk("Initialisation failed for usbbcm"); - } - else - { - printk("Initialised usbbcm"); - } - return result; + printk(KERN_INFO "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO "%s\n", DRV_COPYRIGHT); + + return InterfaceInitialize(); } static void bcm_exit(void) { - printk("%s %s Calling InterfaceExit\n",__FILE__, __FUNCTION__); InterfaceExit(); - printk("%s %s InterfaceExit returned\n",__FILE__, __FUNCTION__); } module_init(bcm_init); module_exit(bcm_exit); -MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE ("GPL"); diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 824f9a45007a..e6d1dc0d3e43 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -2,12 +2,14 @@ static struct usb_device_id InterfaceUsbtable[] = { { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, - {} + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, + + { } }; +MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) { @@ -865,4 +867,3 @@ INT InterfaceExit(void) usb_deregister(&usbbcm_driver); return status; } -MODULE_LICENSE ("GPL"); -- cgit v1.2.3 From 91d29ee1a82fedcd7d1bbf24007b31a49c47e90a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 07:51:47 -0700 Subject: beceem: remove ifdef's There were a lot of ifdef's for driver options which have no configuration options. Choose the current value and remove the ifdef. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmchar.c | 6 - drivers/staging/bcm/Bcmnet.c | 22 --- drivers/staging/bcm/DDRInit.c | 2 - drivers/staging/bcm/Debug.h | 13 -- drivers/staging/bcm/InterfaceDld.c | 2 - drivers/staging/bcm/InterfaceInit.h | 4 - drivers/staging/bcm/InterfaceIsr.c | 2 - drivers/staging/bcm/InterfaceMisc.c | 2 - drivers/staging/bcm/InterfaceTx.c | 2 - drivers/staging/bcm/Macros.h | 5 - drivers/staging/bcm/Misc.c | 198 -------------------- drivers/staging/bcm/Prototypes.h | 5 - drivers/staging/bcm/Transmit.c | 116 ------------ drivers/staging/bcm/cntrl_SignalingInterface.h | 249 ------------------------- drivers/staging/bcm/headers.h | 28 --- drivers/staging/bcm/led_control.c | 7 - drivers/staging/bcm/nvm.c | 18 -- drivers/staging/bcm/nvm.h | 9 - 18 files changed, 690 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 77fdfe24d999..01f961d9c70c 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -329,9 +329,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } if( -#if !defined(BCM_SHM_INTERFACE) (((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) || -#endif ((ULONG)sRdmBuffer.Register & 0x3) ) { @@ -385,10 +383,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) break; } if( -#if !defined(BCM_SHM_INTERFACE) (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) || -#endif ((ULONG)sWrmBuffer.Register & 0x3) ) { @@ -823,7 +819,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) bcm_kfree(pvBuffer); break; } -#ifndef BCM_SHM_INTERFACE case IOCTL_BCM_BUFFER_DOWNLOAD_START: { INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock) ; @@ -999,7 +994,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) up(&Adapter->NVMRdmWrmLock); break; } -#endif case IOCTL_BE_BUCKET_SIZE: Adapter->BEBucketSize = *(PULONG)arg; Status = STATUS_SUCCESS; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 4d7d8cd4bf43..3262aff8dd4a 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -50,9 +50,6 @@ static struct notifier_block bcm_notifier_block = struct net_device *gblpnetdev; /***************************************************************************************/ /* proto-type of lower function */ -#ifdef BCM_SHM_INTERFACE -const char *bcmVirtDeviceName="bcmeth"; -#endif static INT bcm_open(struct net_device *dev) { @@ -155,7 +152,6 @@ int register_networkdev(PMINI_ADAPTER Adapter) Adapter->dev->hard_header_len = ETH_HLEN + LEADER_SIZE; #endif -#ifndef BCM_SHM_INTERFACE Adapter->dev->mtu = MTU_SIZE; /* 1400 Bytes */ /* Read the MAC Address from EEPROM */ ReadMacAddressFromNVM(Adapter); @@ -176,24 +172,6 @@ int register_networkdev(PMINI_ADAPTER Adapter) Adapter->bNetdeviceNotifierRegistered = TRUE; } -#else - - Adapter->dev->mtu = CPE_MTU_SIZE; - -#if 0 - //for CPE - harcode the virtual mac address - Adapter->dev->dev_addr[0] = MII_WIMAX_MACADDRESS[0]; - Adapter->dev->dev_addr[1] = MII_WIMAX_MACADDRESS[1]; - Adapter->dev->dev_addr[2] = MII_WIMAX_MACADDRESS[2]; - Adapter->dev->dev_addr[3] = MII_WIMAX_MACADDRESS[3]; - Adapter->dev->dev_addr[4] = MII_WIMAX_MACADDRESS[4]; - Adapter->dev->dev_addr[5] = MII_WIMAX_MACADDRESS[5]; -#else - ReadMacAddressFromNVM(Adapter); -#endif - strcpy(Adapter->dev->name, bcmVirtDeviceName); //Copy the device name - -#endif result = register_netdev(Adapter->dev); if (!result) diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c index 8907e211d483..454eb8d8992b 100644 --- a/drivers/staging/bcm/DDRInit.c +++ b/drivers/staging/bcm/DDRInit.c @@ -1,6 +1,5 @@ #include "headers.h" -#ifndef BCM_SHM_INTERFACE #define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00 @@ -1298,5 +1297,4 @@ int download_ddr_settings(PMINI_ADAPTER Adapter) return retval; } -#endif diff --git a/drivers/staging/bcm/Debug.h b/drivers/staging/bcm/Debug.h index 3d788b59ab57..b384115cab3a 100644 --- a/drivers/staging/bcm/Debug.h +++ b/drivers/staging/bcm/Debug.h @@ -21,19 +21,6 @@ typedef enum _BASE_TYPE int bcm_print_buffer( UINT debug_level, const char *function_name, char *file_name, int line_number, unsigned char *buffer, int bufferlen, BASE_TYPE base); -#ifdef BCM_SHM_INTERFACE -#define CPE_VIRTUAL_ERROR_CODE_BASE_ADDR (0xBFC02E00 + 0x4C) -// ERROR codes for debugging -extern unsigned char u32ErrorCounter ; -#define ERROR_DEVICE_REMOVED 0x1 -#define ERROR_LEADER_LENGTH_ZERO 0x2 -#define ERROR_LEADER_LENGTH_CORRUPTED 0x3 -#define ERROR_NO_SKBUFF 0x4 - -#define ERROR_DL_MODULE 0xaa000000 -extern void CPE_ERROR_LOG(unsigned int module,unsigned int code); - -#endif diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c index 60c0f29f3eef..62770e042e51 100644 --- a/drivers/staging/bcm/InterfaceDld.c +++ b/drivers/staging/bcm/InterfaceDld.c @@ -1,6 +1,5 @@ #include "headers.h" -#ifndef BCM_SHM_INTERFACE int InterfaceFileDownload( PVOID arg, struct file *flp, @@ -506,5 +505,4 @@ error: return status; } -#endif diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h index e7a96e5c5c50..a11af81d74d9 100644 --- a/drivers/staging/bcm/InterfaceInit.h +++ b/drivers/staging/bcm/InterfaceInit.h @@ -19,16 +19,12 @@ INT InterfaceInitialize(void); INT InterfaceExit(void); -#ifndef BCM_SHM_INTERFACE INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter); INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter); VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter); -#else -INT InterfaceAdapterInit(PMINI_ADAPTER Adapter); -#endif #if 0 diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c index f928fe4d564d..c1f8e7aa05f7 100644 --- a/drivers/staging/bcm/InterfaceIsr.c +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -1,6 +1,5 @@ #include "headers.h" -#ifndef BCM_SHM_INTERFACE static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) { @@ -199,5 +198,4 @@ void InterfaceDisableInterrupt(PMINI_ADAPTER Adapter) } -#endif diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c index 8fc893b37fe4..2d98b7e846c2 100644 --- a/drivers/staging/bcm/InterfaceMisc.c +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -1,6 +1,5 @@ #include "headers.h" -#ifndef BCM_SHM_INTERFACE PS_INTERFACE_ADAPTER InterfaceAdapterGet(PMINI_ADAPTER psAdapter) @@ -287,4 +286,3 @@ VOID putUsbSuspend(struct work_struct *work) } -#endif diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c index 771f7b34d2ec..826ed93c9b56 100644 --- a/drivers/staging/bcm/InterfaceTx.c +++ b/drivers/staging/bcm/InterfaceTx.c @@ -1,6 +1,5 @@ #include "headers.h" -#ifndef BCM_SHM_INTERFACE /* Function: InterfaceTxDataPacket @@ -255,5 +254,4 @@ int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len) return TransmitTcb(psIntfAdapter, pTcb, data, len); } -#endif diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h index 0241234605f1..5485f574b917 100644 --- a/drivers/staging/bcm/Macros.h +++ b/drivers/staging/bcm/Macros.h @@ -300,12 +300,7 @@ typedef enum _E_PHS_DSC_ACTION /* Idle Mode Related Registers */ #define DEBUG_INTERRUPT_GENERATOR_REGISTOR 0x0F00007C -#ifdef BCM_SHM_INTERFACE -#define SW_ABORT_IDLEMODE_LOC 0xbfc02f9c -#define CPE_VIRTUAL_MAILBOX_REG 0xBFC02E58 -#else #define SW_ABORT_IDLEMODE_LOC 0x0FF01FFC -#endif #define SW_ABORT_IDLEMODE_PATTERN 0xd0ea1d1e #define DEVICE_INT_OUT_EP_REG0 0x0F011870 diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 22550f745917..cedeb8c3723e 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -157,9 +157,7 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) //Free the PHS Interface PhsCleanup(&Adapter->stBCMPhsContext); -#ifndef BCM_SHM_INTERFACE BcmDeAllocFlashCSStructure(Adapter); -#endif bcm_kfree (Adapter); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "<========\n"); @@ -489,9 +487,6 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**index_wr_txcntrlpkt); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, TX_CONTROL,DBG_LVL_ALL, "Calling transmit_packets"); atomic_set(&Adapter->TxPktAvail, 1); -#ifdef BCM_SHM_INTERFACE - virtual_mail_box_interrupt(); -#endif wake_up(&Adapter->tx_packet_wait_queue); } else @@ -787,12 +782,10 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter) down(&Adapter->rdmwrmsync); Adapter->bPreparingForLowPowerMode = TRUE; up(&Adapter->rdmwrmsync); -#ifndef BCM_SHM_INTERFACE //Killing all URBS. if(Adapter->bDoSuspend == TRUE) Bcm_kill_all_URBs((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter)); -#endif } else { @@ -811,9 +804,7 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"fail to send the Idle mode Request \n"); Adapter->bPreparingForLowPowerMode = FALSE; -#ifndef BCM_SHM_INTERFACE StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter)); -#endif } do_gettimeofday(&tv); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "IdleMode Msg submitter to Q :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000); @@ -985,7 +976,6 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter) { int retval = STATUS_SUCCESS; -#ifndef BCM_SHM_INTERFACE PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); PS_INTERFACE_ADAPTER psIntfAdapter = NULL; unsigned int value = 0, uiResetValue = 0; @@ -1006,11 +996,9 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter) wrmalt(ps_adapter, SYS_CFG, &value, sizeof(value)); } -#ifndef BCM_SHM_INTERFACE //killing all submitted URBs. psIntfAdapter->psAdapter->StopAllXaction = TRUE ; Bcm_kill_all_URBs(psIntfAdapter); -#endif /* Reset the UMA-B Device */ if(ps_adapter->chip_id >= T3LPB) { @@ -1111,7 +1099,6 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter) err_exit : psIntfAdapter->psAdapter->StopAllXaction = FALSE ; -#endif return retval; } @@ -1148,9 +1135,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) UINT status = STATUS_SUCCESS; UINT value = 0; -#ifdef BCM_SHM_INTERFACE - unsigned char *pConfigFileAddr = (unsigned char *)CPE_MACXVI_CFG_ADDR; -#endif /* * Create the threads first and then download the * Firm/DDR Settings.. @@ -1169,7 +1153,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) return status; } -#ifndef BCM_SHM_INTERFACE if(ps_adapter->chip_id >= T3LPB) { rdmalt(ps_adapter, SYS_CFG, &value, sizeof (value)); @@ -1299,61 +1282,12 @@ OUT: wake_up(&ps_adapter->LEDInfo.notify_led_event); } -#else - - ps_adapter->bDDRInitDone = TRUE; - //Initializing the NVM. - BcmInitNVM(ps_adapter); - - //Propagating the cal param from Flash to DDR - value = 0; - wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value)); - wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value)); - - if(ps_adapter->eNVMType == NVM_FLASH) - { - status = PropagateCalParamsFromFlashToMemory(ps_adapter); - if(status) - { - printk("\nPropogation of Cal param from flash to DDR failed ..\n" ); - } - } - - //Copy config file param to DDR. - memcpy(pConfigFileAddr,ps_adapter->pstargetparams, sizeof(STARGETPARAMS)); - - if(register_networkdev(ps_adapter)) - { - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Netdevice failed. Cleanup needs to be performed."); - return -EIO; - } - - - status = InitLedSettings (ps_adapter); - if(status) - { - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_PRINTK, 0, 0,"INIT LED FAILED\n"); - return status; - } - - - if(register_control_device_interface(ps_adapter) < 0) - { - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Control Device failed. Cleanup needs to be performed."); - return -EIO; - } - - ps_adapter->fw_download_done = TRUE; -#endif return status; } int bcm_parse_target_params(PMINI_ADAPTER Adapter) { -#ifdef BCM_SHM_INTERFACE - extern void read_cfg_file(PMINI_ADAPTER Adapter); -#endif struct file *flp=NULL; mm_segment_t oldfs={0}; char *buff = NULL; @@ -1401,10 +1335,6 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter) memcpy(Adapter->pstargetparams, buff, sizeof(STARGETPARAMS)); bcm_kfree (buff); beceem_parse_target_struct(Adapter); -#ifdef BCM_SHM_INTERFACE - read_cfg_file(Adapter); - -#endif return STATUS_SUCCESS; } @@ -1640,81 +1570,21 @@ int rdm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize) { INT uiRetVal =0; -#ifndef BCM_SHM_INTERFACE uiRetVal = Adapter->interface_rdm(Adapter->pvInterfaceAdapter, uiAddress, pucBuff, sSize); if(uiRetVal < 0) return uiRetVal; -#else - int indx; - uiRetVal = STATUS_SUCCESS; - if(uiAddress & 0x10000000) { - // DDR Memory Access - uiAddress |= CACHE_ADDRESS_MASK; - memcpy(pucBuff,(unsigned char *)uiAddress ,sSize); - } - else { - // Register, SPRAM, Flash - uiAddress |= UNCACHE_ADDRESS_MASK; - if ((uiAddress & FLASH_ADDR_MASK) == (FLASH_CONTIGIOUS_START_ADDR_BCS350 & FLASH_ADDR_MASK)) - { - #if defined(FLASH_DIRECT_ACCESS) - memcpy(pucBuff,(unsigned char *)uiAddress ,sSize); - #else - printk("\nInvalid GSPI ACCESS :Addr :%#X", uiAddress); - uiRetVal = STATUS_FAILURE; - #endif - } - else if(((unsigned int )uiAddress & 0x3) || - ((unsigned int )pucBuff & 0x3) || - ((unsigned int )sSize & 0x3)) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"rdmalt :unalligned register access uiAddress = %x,pucBuff = %x size = %x\n",(unsigned int )uiAddress,(unsigned int )pucBuff,(unsigned int )sSize); - uiRetVal = STATUS_FAILURE; - } - else { - for (indx=0;indxinterface_wrm(Adapter->pvInterfaceAdapter, uiAddress, pucBuff, sSize); -#else - int indx; - if(uiAddress & 0x10000000) { - // DDR Memory Access - uiAddress |= CACHE_ADDRESS_MASK; - memcpy((unsigned char *)(uiAddress),pucBuff,sSize); - } - else { - // Register, SPRAM, Flash - uiAddress |= UNCACHE_ADDRESS_MASK; - - if(((unsigned int )uiAddress & 0x3) || - ((unsigned int )pucBuff & 0x3) || - ((unsigned int )sSize & 0x3)) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"wrmalt: unalligned register access uiAddress = %x,pucBuff = %x size = %x\n",(unsigned int )uiAddress,(unsigned int )pucBuff,(unsigned int )sSize); - iRetVal = STATUS_FAILURE; - } - else { - for (indx=0;indxbPreparingForLowPowerMode = TRUE; up(&Adapter->rdmwrmsync); //Killing all URBS. -#ifndef BCM_SHM_INTERFACE if(Adapter->bDoSuspend == TRUE) Bcm_kill_all_URBs((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter)); -#endif } else { @@ -1943,9 +1811,7 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL,"fail to send the Idle mode Request \n"); Adapter->bPreparingForLowPowerMode = FALSE; -#ifndef BCM_SHM_INTERFACE StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter)); -#endif } } @@ -2077,11 +1943,7 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter) if(!atomic_read (&Adapter->uiMBupdate)) return; -#ifdef BCM_SHM_INTERFACE - if(rdmalt(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS)<0) -#else if(rdmaltWithLock(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS)<0) -#endif { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed\n"); return; @@ -2179,65 +2041,5 @@ void beceem_protocol_reset (PMINI_ADAPTER Adapter) -#ifdef BCM_SHM_INTERFACE - - -#define GET_GTB_DIFF(start, end) \ -( (start) < (end) )? ( (end) - (start) ) : ( ~0x0 - ( (start) - (end)) +1 ) - -void usdelay ( unsigned int a) { - unsigned int start= *(unsigned int *)0xaf8051b4; - unsigned int end = start+1; - unsigned int diff = 0; - - while(1) { - end = *(unsigned int *)0xaf8051b4; - diff = (GET_GTB_DIFF(start,end))/80; - if (diff >= a) - break; - } -} -void read_cfg_file(PMINI_ADAPTER Adapter) { - - - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Config File Version = 0x%x \n",Adapter->pstargetparams->m_u32CfgVersion ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Center Frequency = 0x%x \n",Adapter->pstargetparams->m_u32CenterFrequency ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band A Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandAScan ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band B Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandBScan ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band C Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandCScan ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ERTPS Options = 0x%x \n",Adapter->pstargetparams->m_u32ErtpsOptions ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PHS Enable = 0x%x \n",Adapter->pstargetparams->m_u32PHSEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Handoff Enable = 0x%x \n",Adapter->pstargetparams->m_u32HoEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HO Reserved1 = 0x%x \n",Adapter->pstargetparams->m_u32HoReserved1 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HO Reserved2 = 0x%x \n",Adapter->pstargetparams->m_u32HoReserved2 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MIMO Enable = 0x%x \n",Adapter->pstargetparams->m_u32MimoEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PKMv2 Enable = 0x%x \n",Adapter->pstargetparams->m_u32SecurityEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Powersaving Modes Enable = 0x%x \n",Adapter->pstargetparams->m_u32PowerSavingModesEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Power Saving Mode Options = 0x%x \n",Adapter->pstargetparams->m_u32PowerSavingModeOptions ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ARQ Enable = 0x%x \n",Adapter->pstargetparams->m_u32ArqEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Harq Enable = 0x%x \n",Adapter->pstargetparams->m_u32HarqEnable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"EEPROM Flag = 0x%x \n",Adapter->pstargetparams->m_u32EEPROMFlag ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Customize = 0x%x \n",Adapter->pstargetparams->m_u32Customize ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Bandwidth = 0x%x \n",Adapter->pstargetparams->m_u32ConfigBW ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ShutDown Timer Value = 0x%x \n",Adapter->pstargetparams->m_u32ShutDownInitThresholdTimer ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RadioParameter = 0x%x \n",Adapter->pstargetparams->m_u32RadioParameter ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter1 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter1 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter2 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter2 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter3 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter3 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"m_u32TestOptions = 0x%x \n",Adapter->pstargetparams->m_u32TestOptions ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MaxMACDataperDLFrame = 0x%x \n",Adapter->pstargetparams->m_u32MaxMACDataperDLFrame ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MaxMACDataperULFrame = 0x%x \n",Adapter->pstargetparams->m_u32MaxMACDataperULFrame ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Corr2MacFlags = 0x%x \n",Adapter->pstargetparams->m_u32Corr2MacFlags ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig1 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig1 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig2 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig2 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig3 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig3 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig4 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig4 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig5 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig5 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig6 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig6 ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Segmented PUSC Enable = 0x%x \n",Adapter->pstargetparams->m_u32SegmentedPUSCenable ); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BamcEnable = 0x%x \n",Adapter->pstargetparams->m_u32BandAMCEnable ); -} - -#endif diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index 70ec8bcafd1e..82738be3ed48 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -309,11 +309,6 @@ INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned VOID putUsbSuspend(struct work_struct *work); BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios); -#ifdef BCM_SHM_INTERFACE -INT beceem_virtual_device_init(void); -VOID virtual_mail_box_interrupt(void); -INT beceem_virtual_device_exit(void); -#endif #endif diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 12f9e13457db..597786a06785 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -146,18 +146,6 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n", (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec); -#ifdef BCM_SHM_INTERFACE - spin_lock(&Adapter->txtransmitlock); - if(Adapter->txtransmit_running == 0) - { - Adapter->txtransmit_running = 1; - calltransmit = 1; - } - else - calltransmit = 0; - - spin_unlock(&Adapter->txtransmitlock); -#endif if(calltransmit == 1) transmit_packets(Adapter); else @@ -165,9 +153,6 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */ if(!atomic_read(&Adapter->TxPktAvail)) { atomic_set(&Adapter->TxPktAvail, 1); -#ifdef BCM_SHM_INTERFACE - virtual_mail_box_interrupt(); -#endif wake_up(&Adapter->tx_packet_wait_queue); } } @@ -224,44 +209,8 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**PLength); if(Adapter->device_removed) return 0; -#ifndef BCM_SHM_INTERFACE Adapter->interface_transmit(Adapter->pvInterfaceAdapter, pControlPacket, (PLeader->PLength + LEADER_SIZE)); -#else - tx_pkts_to_firmware(pControlPacket,(PLeader->PLength + LEADER_SIZE),1); - - if(PLeader->Status==IDLE_MESSAGE) - { - if(((CONTROL_MESSAGE*)PLeader)->szData[0] == GO_TO_IDLE_MODE_PAYLOAD && - ((CONTROL_MESSAGE*)PLeader)->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Idle Mode Ack Sent to the Device\n"); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Host Entering into Idle Mode\n"); - do_gettimeofday(&tv); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "IdleMode Msg sent to f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000); - if(Adapter->bDoSuspend != TRUE) - { - Adapter->IdleMode = TRUE; - Adapter->bPreparingForLowPowerMode = FALSE ; - } - } - } - if((PLeader->Status == LINK_UP_CONTROL_REQ) && - ((PUCHAR)pControlPacket)[sizeof(LEADER)] == LINK_UP_ACK && - ((PUCHAR)pControlPacket)[sizeof(LEADER)+1] == - LINK_SHUTDOWN_REQ_FROM_FIRMWARE && - ((PUCHAR)pControlPacket)[sizeof(LEADER)+2] == SHUTDOWN_ACK_FROM_DRIVER) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Shut Down ACK Sent and Host entering Shut State \n"); - if(Adapter->bDoSuspend != TRUE) - { - Adapter->bShutStatus = TRUE; - Adapter->bPreparingForLowPowerMode = FALSE; - Adapter->bTriedToWakeUpFromlowPowerMode = FALSE; - } - - } -#endif ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_packets++; ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_bytes+= @@ -282,9 +231,6 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**len = %d", Packet->len); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid); -#ifndef BCM_SHM_INTERFACE status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter, Packet->data, (Leader.PLength + LEADER_SIZE)); -#else - status = tx_pkts_to_firmware(Packet,Packet->len,0); -#endif if(status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n"); @@ -376,9 +318,6 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; atomic_add(Leader.PLength, &Adapter->GoodTxByteCount); atomic_inc(&Adapter->TxTotalPacketCount); -#ifdef GDMA_INTERFACE - dontfree = 1; -#endif } atomic_dec(&Adapter->CurrNumFreeTxDesc); @@ -393,23 +332,11 @@ errExit: Adapter->PackInfo[QueueIndex].NumOfPacketsSent++; atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount); -#ifdef BCM_SHM_INTERFACE - if(atomic_read(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount) < 0) - { - atomic_set(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount, 0); - } -#endif Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength; } -#ifdef GDMA_INTERFACE - if(!dontfree){ bcm_kfree_skb(Packet); - } -#else - bcm_kfree_skb(Packet); -#endif return status; } @@ -420,9 +347,7 @@ Transmit thread int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ ) { -#ifndef BCM_SHM_INTERFACE int status = 0; -#endif UINT calltransmit = 1; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Entring to wait for signal from the interrupt service thread!Adapter = %p",Adapter); @@ -437,9 +362,7 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ atomic_read(&Adapter->CurrNumFreeTxDesc)) && (Adapter->device_removed == FALSE))) || (1 == Adapter->downloadDDR) || kthread_should_stop() -#ifndef BCM_SHM_INTERFACE || (TRUE == Adapter->bEndPointHalted) -#endif , msecs_to_jiffies(10)); } else{ @@ -449,9 +372,7 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ atomic_read(&Adapter->CurrNumFreeTxDesc)) && (Adapter->device_removed == FALSE))) || (1 == Adapter->downloadDDR) || kthread_should_stop() -#ifndef BCM_SHM_INTERFACE || (TRUE == Adapter->bEndPointHalted) -#endif ); } @@ -462,7 +383,6 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ return 0; } -#ifndef BCM_SHM_INTERFACE if(Adapter->downloadDDR == 1) { @@ -489,7 +409,6 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ update_per_sf_desc_cnts(Adapter); } } -#endif if( atomic_read(&Adapter->CurrNumFreeTxDesc) && Adapter->LinkStatus == SYNC_UP_REQUEST && @@ -507,17 +426,6 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ wake_up(&Adapter->process_rx_cntrlpkt); } -#ifdef BCM_SHM_INTERFACE - spin_lock_bh(&Adapter->txtransmitlock); - if(Adapter->txtransmit_running == 0) - { - Adapter->txtransmit_running = 1; - calltransmit = 1; - } - else - calltransmit = 0; - spin_unlock_bh(&Adapter->txtransmitlock); -#endif if(calltransmit) transmit_packets(Adapter); @@ -527,29 +435,5 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ return 0; } -#ifdef BCM_SHM_INTERFACE -extern PMINI_ADAPTER psAdaptertest; -void virtual_mail_box_interrupt(void) -{ - -#ifndef GDMA_INTERFACE - PUINT ptr = (PUINT)CPE_VIRTUAL_MAILBOX_REG; - UINT intval = (UINT)((*ptr & 0xFF00) >> 8); - if (intval != 0) - { - atomic_set(&psAdaptertest->CurrNumFreeTxDesc, intval); - atomic_set (&psAdaptertest->uiMBupdate, TRUE); - - //make it to 0 - *ptr = *ptr & 0xffff00ff; - } -#endif -} -unsigned int total_tx_pkts_pending(void) -{ - return atomic_read(&psAdaptertest->TotalPacketCount); -} - -#endif diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h index 4cbe30022248..7c47af7729f6 100644 --- a/drivers/staging/bcm/cntrl_SignalingInterface.h +++ b/drivers/staging/bcm/cntrl_SignalingInterface.h @@ -2,19 +2,6 @@ #define CNTRL_SIGNALING_INTERFACE_ -#ifdef BECEEM_TARGET - -#include -#include -#include -#include -#include -using namespace Beceem; -#ifdef ENABLE_CORRIGENDUM2_UPDATE -extern B_UINT32 g_u32Corr2MacFlags; -#endif - -#else #define DSA_REQ 11 @@ -28,7 +15,6 @@ extern B_UINT32 g_u32Corr2MacFlags; #define DSD_ACK 19 #define MAX_CLASSIFIERS_IN_SF 4 -#endif #define MAX_STRING_LEN 20 #define MAX_PHS_LENGTHS 255 @@ -57,37 +43,7 @@ extern B_UINT32 g_u32Corr2MacFlags; ////////////////////////structure Definitions/////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// \brief class cCPacketClassificationRule -#ifdef BECEEM_TARGET -class CCPacketClassificationRuleSI{ - public: - /// \brief Constructor for the class - CCPacketClassificationRuleSI(): - u8ClassifierRulePriority(mClassifierRulePriority), - u8IPTypeOfServiceLength(mIPTypeOfService), - u8Protocol(mProtocol), - u8IPMaskedSourceAddressLength(0), - u8IPDestinationAddressLength(0), - u8ProtocolSourcePortRangeLength(0), - u8ProtocolDestPortRangeLength(0), - u8EthernetDestMacAddressLength(0), - u8EthernetSourceMACAddressLength(0), - u8EthertypeLength(0), - u16UserPriority(mUserPriority), - u16VLANID(mVLANID), - u8AssociatedPHSI(mAssociatedPHSI), - u16PacketClassificationRuleIndex(mPacketClassifierRuleIndex), - u8VendorSpecificClassifierParamLength(mVendorSpecificClassifierParamLength), - u8IPv6FlowLableLength(mIPv6FlowLableLength), - u8ClassifierActionRule(mClassifierActionRule) - - {} - void Reset() - { - CCPacketClassificationRuleSI(); - } -#else struct _stCPacketClassificationRuleSI{ -#endif /** 16bit UserPriority Of The Service Flow*/ B_UINT16 u16UserPriority; @@ -145,29 +101,10 @@ struct _stCPacketClassificationRuleSI{ B_UINT8 u8ClassifierActionRule; B_UINT16 u16ValidityBitMap; }; -#ifndef BECEEM_TARGET typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI,stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI; -#endif /// \brief class CPhsRuleSI -#ifdef BECEEM_TARGET -class CPhsRuleSI{ - public: - /// \brief Constructor for the class - CPhsRuleSI(): - u8PHSI(mPHSI), - u8PHSFLength(0), - u8PHSMLength(0), - u8PHSS(mPHSS), - u8PHSV(mPHSV), - u8VendorSpecificPHSParamsLength(mVendorSpecificPHSParamLength){} - void Reset() - { - CPhsRuleSI(); - } -#else typedef struct _stPhsRuleSI { -#endif /** 8bit PHS Index Of The Service Flow*/ B_UINT8 u8PHSI; /** PHSF Length Of The Service Flow*/ @@ -188,31 +125,11 @@ typedef struct _stPhsRuleSI { B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH]; B_UINT8 u8Padding[2]; -#ifdef BECEEM_TARGET -}; -#else }stPhsRuleSI,*pstPhsRuleSI; typedef stPhsRuleSI CPhsRuleSI; -#endif /// \brief structure cConvergenceSLTypes -#ifdef BECEEM_TARGET -class CConvergenceSLTypes{ - public: - /// \brief Constructor for the class - CConvergenceSLTypes(): - u8ClassfierDSCAction(mClassifierDSCAction), - u8PhsDSCAction (mPhsDSCAction) - {} - void Reset() - { - CConvergenceSLTypes(); - cCPacketClassificationRule.Reset(); - cPhsRule.Reset(); - } -#else struct _stConvergenceSLTypes{ -#endif /** 8bit Phs Classfier Action Of The Service Flow*/ B_UINT8 u8ClassfierDSCAction; /** 8bit Phs DSC Action Of The Service Flow*/ @@ -220,111 +137,15 @@ struct _stConvergenceSLTypes{ /** 16bit Padding */ B_UINT8 u8Padding[2]; /// \brief class cCPacketClassificationRule -#ifdef BECEEM_TARGET - CCPacketClassificationRuleSI cCPacketClassificationRule; -#else stCPacketClassificationRuleSI cCPacketClassificationRule; -#endif /// \brief class CPhsRuleSI -#ifdef BECEEM_TARGET - CPhsRuleSI cPhsRule; -#else struct _stPhsRuleSI cPhsRule; -#endif }; -#ifndef BECEEM_TARGET typedef struct _stConvergenceSLTypes stConvergenceSLTypes,CConvergenceSLTypes, *pstConvergenceSLTypes; -#endif /// \brief structure CServiceFlowParamSI -#ifdef BECEEM_TARGET -class CServiceFlowParamSI{ - public: - /// \brief Constructor for the class - CServiceFlowParamSI(): - u32SFID(mSFid), - u16CID(mCid), - u8ServiceClassNameLength(mServiceClassNameLength), - u8MBSService(mMBSService), - u8QosParamSet(mQosParamSetType), - u8TrafficPriority(mTrafficPriority), - u32MaxSustainedTrafficRate(mMaximumSustainedTrafficRate), - u32MaxTrafficBurst(mMaximumTrafficBurst), - u32MinReservedTrafficRate(mMinimumReservedTrafficRate), - u8ServiceFlowSchedulingType(mServiceFlowSchedulingType), - u8RequesttransmissionPolicy(mRequestTransmissionPolicy), - u32ToleratedJitter(mToleratedJitter), - u32MaximumLatency(mMaximumLatency), - u8FixedLengthVSVariableLengthSDUIndicator - (mFixedLengthVSVariableLength), - u8SDUSize(mSDUSize), - u16TargetSAID(mTargetSAID), - u8ARQEnable(mARQEnable), - u16ARQWindowSize(mARQWindowSize), - u16ARQBlockLifeTime(mARQBlockLifeTime), - u16ARQSyncLossTimeOut(mARQSyncLossTimeOut), - u8ARQDeliverInOrder(mARQDeliverInOrder), - u16ARQRxPurgeTimeOut(mARQRXPurgeTimeOut), - //Add ARQ BLOCK SIZE, ARQ TX and RX delay initializations here - //after we move to only CORR2 - u8RxARQAckProcessingTime(mRxARQAckProcessingTime), - u8CSSpecification(mCSSpecification), - u8TypeOfDataDeliveryService(mTypeOfDataDeliveryService), - u16SDUInterArrivalTime(mSDUInterArrivalTime), - u16TimeBase(mTimeBase), - u8PagingPreference(mPagingPreference), - u8MBSZoneIdentifierassignment(mMBSZoneIdentifierassignmentLength), - u8TrafficIndicationPreference(mTrafficIndicationPreference), - u8GlobalServicesClassNameLength(mGlobalServicesClassNameLength), - u8SNFeedbackEnabled(mSNFeedbackEnabled), - u8FSNSize(mFSNSize), - u8CIDAllocation4activeBSsLength(mCIDAllocation4activeBSsLength), - u16UnsolicitedGrantInterval(mUnsolicitedGrantInterval), - u16UnsolicitedPollingInterval(mUnsolicitedPollingInterval), - u8PDUSNExtendedSubheader4HarqReordering(mPDUSNExtendedSubheader4HarqReordering), - u8MBSContentsIDLength(mMBSContentsIDLength), - u8HARQServiceFlows(mHARQServiceFlows), - u8AuthTokenLength(mAuthTokenLength), - u8HarqChannelMappingLength(mHarqChannelMappingLength), - u8VendorSpecificQoSParamLength(mVendorSpecificQoSParamLength), - bValid(FALSE), - u8TotalClassifiers() -{ -//Remove the bolck after we move to Corr2 only code -#ifdef ENABLE_CORRIGENDUM2_UPDATE - if((g_u32Corr2MacFlags & CORR_2_DSX) || (g_u32Corr2MacFlags & CORR_2_ARQ)) - { - /* IEEE Comment #627 / MTG Comment #426 */ - u16ARQBlockSize = mARQBlockSize; - if(g_u32Corr2MacFlags & CORR_2_ARQ) { - u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelay; - if(g_u32VENDOR_TYPE == VENDOR_ALCATEL) { - u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelay_ALU; - } else { - u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelay; - } - } - else - { - u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelayCorr1; - u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelayCorr1; - } - } - else -#endif - { - u16ARQBlockSize = mARQBlockSizeCorr1; - u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelayCorr1; - u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelayCorr1; - } -} - - void ComputeMacOverhead(B_UINT8 u8SecOvrhead); - B_UINT16 GetMacOverhead() { return u16MacOverhead; } -#else typedef struct _stServiceFlowParamSI{ -#endif //end of ifdef BECEEM_TARGET /** 32bitSFID Of The Service Flow*/ B_UINT32 u32SFID; @@ -496,35 +317,18 @@ typedef struct _stServiceFlowParamSI{ B_UINT8 bValid; /**< Validity flag */ B_UINT8 u8Padding; /**< Padding byte*/ -#ifdef BECEEM_TARGET -/** -Structure for Convergence SubLayer Types with a maximum of 4 classifiers -*/ - CConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF]; -#else /** Structure for Convergence SubLayer Types with a maximum of 4 classifiers */ stConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF]; -#endif -#ifdef BECEEM_TARGET -}; -#else } stServiceFlowParamSI, *pstServiceFlowParamSI; typedef stServiceFlowParamSI CServiceFlowParamSI; -#endif /** structure stLocalSFAddRequest */ typedef struct _stLocalSFAddRequest{ -#ifdef BECEEM_TARGET - _stLocalSFAddRequest( ) : - u8Type(0x00), eConnectionDir(0x00), - u16TID(0x0000), u16CID(0x0000), u16VCID(0x0000) - {} -#endif B_UINT8 u8Type; /**< Type*/ B_UINT8 eConnectionDir; /**< Connection direction*/ @@ -535,19 +339,9 @@ typedef struct _stLocalSFAddRequest{ /// \brief 16bitVCID B_UINT16 u16VCID; /**< 16bit VCID*/ /// \brief structure ParameterSet -#ifdef BECEEM_SIGNALLING_INTERFACE_API - CServiceFlowParamSI sfParameterSet; -#endif -#ifdef BECEEM_TARGET - CServiceFlowParamSI *psfParameterSet; -#else stServiceFlowParamSI *psfParameterSet; /**< structure ParameterSet*/ -#endif -#ifdef USING_VXWORKS - USE_DATA_MEMORY_MANAGER(); -#endif }stLocalSFAddRequest, *pstLocalSFAddRequest; @@ -555,12 +349,6 @@ typedef struct _stLocalSFAddRequest{ structure stLocalSFAddIndication */ typedef struct _stLocalSFAddIndication{ -#ifdef BECEEM_TARGET - _stLocalSFAddIndication( ) : - u8Type(0x00), eConnectionDir(0x00), - u16TID(0x0000), u16CID(0x0000), u16VCID(0x0000) - {} -#endif B_UINT8 u8Type; /**< Type*/ B_UINT8 eConnectionDir; /**< Connection Direction*/ @@ -571,37 +359,19 @@ typedef struct _stLocalSFAddIndication{ /// \brief 16bitVCID B_UINT16 u16VCID; /**< 16bitVCID*/ -#ifdef BECEEM_SIGNALLING_INTERFACE_API - CServiceFlowParamSI sfAuthorizedSet; - /// \brief structure AdmittedSet - CServiceFlowParamSI sfAdmittedSet; - /// \brief structure ActiveSet - CServiceFlowParamSI sfActiveSet; -#endif /// \brief structure AuthorizedSet -#ifdef BECEEM_TARGET - CServiceFlowParamSI *psfAuthorizedSet; - /// \brief structure AdmittedSet - CServiceFlowParamSI *psfAdmittedSet; - /// \brief structure ActiveSet - CServiceFlowParamSI *psfActiveSet; -#else /// \brief structure AuthorizedSet stServiceFlowParamSI *psfAuthorizedSet; /**< AuthorizedSet of type stServiceFlowParamSI*/ /// \brief structure AdmittedSet stServiceFlowParamSI *psfAdmittedSet; /**< AdmittedSet of type stServiceFlowParamSI*/ /// \brief structure ActiveSet stServiceFlowParamSI *psfActiveSet; /**< sfActiveSet of type stServiceFlowParamSI*/ -#endif B_UINT8 u8CC; /**< Confirmation Code*/ B_UINT8 u8Padd; /**< 8-bit Padding */ B_UINT16 u16Padd; /**< 16 bit Padding */ -#ifdef USING_VXWORKS - USE_DATA_MEMORY_MANAGER(); -#endif }stLocalSFAddIndication; @@ -619,33 +389,17 @@ typedef struct _stLocalSFAddIndication stLocalSFChangeIndication, *pstLocalSFCha structure stLocalSFDeleteRequest */ typedef struct _stLocalSFDeleteRequest{ -#ifdef BECEEM_TARGET - _stLocalSFDeleteRequest( ) : - u8Type(0x00), u8Padding(0x00), - u16TID(0x0000), u32SFID (0x00000000) - {} -#endif B_UINT8 u8Type; /**< Type*/ B_UINT8 u8Padding; /**< Padding byte*/ B_UINT16 u16TID; /**< TID*/ /// \brief 32bitSFID B_UINT32 u32SFID; /**< SFID*/ -#ifdef USING_VXWORKS - USE_DATA_MEMORY_MANAGER(); -#endif }stLocalSFDeleteRequest, *pstLocalSFDeleteRequest; /** structure stLocalSFDeleteIndication */ typedef struct stLocalSFDeleteIndication{ -#ifdef BECEEM_TARGET - stLocalSFDeleteIndication( ) : - u8Type(0x00), u8Padding(0x00), - u16TID(0x0000), u16CID(0x0000), - u16VCID(0x0000),u32SFID (0x00000000) - {} -#endif B_UINT8 u8Type; /**< Type */ B_UINT8 u8Padding; /**< Padding */ B_UINT16 u16TID; /**< TID */ @@ -658,9 +412,6 @@ typedef struct stLocalSFDeleteIndication{ /// \brief 8bit Confirmation code B_UINT8 u8ConfirmationCode; /**< Confirmation code */ B_UINT8 u8Padding1[3]; /**< 3 byte Padding */ -#ifdef USING_VXWORKS - USE_DATA_MEMORY_MANAGER(); -#endif }stLocalSFDeleteIndication; typedef struct _stIM_SFHostNotify diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index 9d4e3aca1b34..5867db5d0074 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -41,21 +41,7 @@ #endif #include #include -#ifndef BCM_SHM_INTERFACE #include -#endif -#ifdef BECEEM_TARGET - -#include -#include -#include -#include -#include -using namespace Beceem; -#ifdef ENABLE_CORRIGENDUM2_UPDATE -extern B_UINT32 g_u32Corr2MacFlags; -#endif -#endif #include "Typedefs.h" #include "Version.h" @@ -80,7 +66,6 @@ extern B_UINT32 g_u32Corr2MacFlags; #include "Queue.h" #include "vendorspecificextn.h" -#ifndef BCM_SHM_INTERFACE #include "InterfaceMacros.h" #include "InterfaceAdapter.h" @@ -89,21 +74,8 @@ extern B_UINT32 g_u32Corr2MacFlags; #include "InterfaceMisc.h" #include "InterfaceRx.h" #include "InterfaceTx.h" -#endif #include "InterfaceIdleMode.h" #include "InterfaceInit.h" -#ifdef BCM_SHM_INTERFACE -#include - -#ifdef GDMA_INTERFACE -#include "GdmaInterface.h" -#include "symphony.h" -#else -#include "virtual_interface.h" - -#endif - -#endif #endif diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c index 97adaae7dfc0..f2b6939f5178 100644 --- a/drivers/staging/bcm/led_control.c +++ b/drivers/staging/bcm/led_control.c @@ -497,12 +497,10 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread { int Status = STATUS_SUCCESS; UCHAR GPIO_Array[NUM_OF_LEDS+1]; /*Array to store GPIO numbers from EEPROM*/ -#ifndef BCM_SHM_INTERFACE UINT uiIndex = 0; UINT uiNum_of_LED_Type = 0; PUCHAR puCFGData = NULL; UCHAR bData = 0; -#endif memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1); if(!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams)) @@ -524,10 +522,6 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread *bEnableThread = FALSE; return Status; } -#ifdef BCM_SHM_INTERFACE - *bEnableThread = FALSE; - return Status ; -#else /* * CONFIG file read successfully. Deallocate the memory of * uiFileNameBufferSize @@ -578,7 +572,6 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread } if(uiNum_of_LED_Type >= NUM_OF_LEDS) *bEnableThread = FALSE; -#endif #if 0 for(uiIndex=0; uiIndexeNVMType = NVM_FLASH; -#else BcmValidateNvmType(ps_adapter); BcmInitEEPROMQueues(ps_adapter); -#endif if(ps_adapter->eNVMType == NVM_AUTODETECT) { @@ -3070,7 +3058,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) memset(Adapter->psFlashCSInfo, 0 ,sizeof(FLASH_CS_INFO)); memset(Adapter->psFlash2xCSInfo, 0 ,sizeof(FLASH2X_CS_INFO)); -#ifndef BCM_SHM_INTERFACE if(!Adapter->bDDRInitDone) { { @@ -3079,7 +3066,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) } } -#endif // Reading first 8 Bytes to get the Flash Layout // MagicNumber(4 bytes) +FlashLayoutMinorVersion(2 Bytes) +FlashLayoutMajorVersion(2 Bytes) @@ -3147,9 +3133,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) return STATUS_FAILURE; } ConvertEndianOf2XCSStructure(Adapter->psFlash2xCSInfo); -#ifndef BCM_SHM_INTERFACE BcmDumpFlash2XCSStructure(Adapter->psFlash2xCSInfo,Adapter); -#endif if((FLASH_CONTROL_STRUCT_SIGNATURE == Adapter->psFlash2xCSInfo->MagicNumber) && (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlash2xCSInfo->SCSIFirmwareVersion)) && (FLASH_SECTOR_SIZE_SIG == Adapter->psFlash2xCSInfo->FlashSectorSizeSig) && @@ -3181,9 +3165,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) Concerns: what if CS sector size does not match with this sector size ??? what is the indication of AccessBitMap in CS in flash 2.x ???? */ -#ifndef BCM_SHM_INTERFACE Adapter->ulFlashID = BcmReadFlashRDID(Adapter); -#endif Adapter->uiFlashLayoutMajorVersion = uiFlashLayoutMajorVersion; diff --git a/drivers/staging/bcm/nvm.h b/drivers/staging/bcm/nvm.h index 6ec6ca85b501..88e394520b71 100644 --- a/drivers/staging/bcm/nvm.h +++ b/drivers/staging/bcm/nvm.h @@ -323,15 +323,6 @@ typedef struct _ISO_HEADER -#ifdef BCM_SHM_INTERFACE - -#define FLASH_ADDR_MASK 0x1F000000 -extern int bcmflash_raw_read(unsigned int flash_id, unsigned int offset, unsigned char *inbuf, unsigned int len); -extern int bcmflash_raw_write(unsigned int flash_id, unsigned int offset, unsigned char *outbuf, unsigned int len); -extern int bcmflash_raw_writenoerase(unsigned int flash_id, unsigned int offset, unsigned char *outbuf, unsigned int len); - - -#endif #define FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT 0x1C000000 #define FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT 0x1F000000 -- cgit v1.2.3 From 5abe61ade9a137b35aa29919334dde7f3a30b248 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:02:08 -0700 Subject: beceem: remove version ifdef's Remove code to support older kernel API's Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Macros.h | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h index 5485f574b917..3868e5b94443 100644 --- a/drivers/staging/bcm/Macros.h +++ b/drivers/staging/bcm/Macros.h @@ -4,10 +4,6 @@ #ifndef __MACROS_H__ #define __MACROS_H__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -#define kthread_run(threadfn,data,datafmt)(struct task_struct *)kernel_thread(threadfn,data,0) -#endif - #define TX_TIMER_PERIOD 10 //10 msec #define MAX_CLASSIFIERS 100 //#define MAX_CLASSIFIERS_PER_SF 20 @@ -350,12 +346,7 @@ typedef enum ePMU_MODES HYBRID_MODE_6 = 2 }PMU_MODE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) -#define MAX_RDM_WRM_RETIRES 16 -#else #define MAX_RDM_WRM_RETIRES 1 -#endif - enum eAbortPattern { ABORT_SHUTDOWN_MODE = 1, @@ -364,27 +355,7 @@ enum eAbortPattern { ABORT_IDLE_SYNCDOWN = 3 }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - #define GET_BCM_ADAPTER(net_dev) ({\ - PMINI_ADAPTER __Adapter = NULL; \ - if (net_dev) { \ - __Adapter = (PMINI_ADAPTER)(net_dev->priv); \ - } \ - else { \ - __Adapter = NULL; \ - }__Adapter;} ) -#else - #define GET_BCM_ADAPTER(net_dev) ({\ - PMINI_ADAPTER __Adapter = NULL; \ - if (net_dev) { \ - __Adapter = (PMINI_ADAPTER)(*((unsigned long *)netdev_priv(net_dev))); \ - } \ - else { \ - __Adapter = NULL; \ - }__Adapter;}) - - -#endif +#define GET_BCM_ADAPTER(net_dev) (net_dev ? netdev_priv(net_dev) : NULL) /* Offsets used by driver in skb cb variable */ #define SKB_CB_CLASSIFICATION_OFFSET 0 -- cgit v1.2.3 From 047a5f2b503d0ba17704c9714b296cbf06ec087e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:04:18 -0700 Subject: beceem: eliminate unused USB stubs USB layer does not require these reset function stubs Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/InterfaceInit.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index e6d1dc0d3e43..958d16ad5289 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -814,25 +814,12 @@ static int InterfaceResume (struct usb_interface *intf) return 0; } -static int InterfacePreReset(struct usb_interface *intf) -{ - printk("====================>"); - return STATUS_SUCCESS; -} - -static int InterfacePostReset(struct usb_interface *intf) -{ - printk("Do Post chip reset setting here if it is required"); - return STATUS_SUCCESS; -} static struct usb_driver usbbcm_driver = { .name = "usbbcm", .probe = usbbcm_device_probe, .disconnect = usbbcm_disconnect, .suspend = InterfaceSuspend, .resume = InterfaceResume, - .pre_reset=InterfacePreReset, - .post_reset=InterfacePostReset, .id_table = InterfaceUsbtable, .supports_autosuspend = 1, }; -- cgit v1.2.3 From 2564a148d5326f1d36202e497b3dd0a17422c636 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:11:12 -0700 Subject: beceem: cleanup debug level infrastructure Add module parameter to control debug level and do code cleanup The whole debug stuff should eventually be removed. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Debug.c | 59 ++++++++++++++++----------------- drivers/staging/bcm/Debug.h | 66 +++++++++++++++---------------------- drivers/staging/bcm/InterfaceInit.c | 7 +++- 3 files changed, 61 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Debug.c b/drivers/staging/bcm/Debug.c index 2703f304756d..9f7f70ca1716 100644 --- a/drivers/staging/bcm/Debug.c +++ b/drivers/staging/bcm/Debug.c @@ -1,41 +1,40 @@ #include "headers.h" -static UINT current_debug_level=BCM_SCREAM; - -int bcm_print_buffer( UINT debug_level, const char *function_name, - char *file_name, int line_number, unsigned char *buffer, int bufferlen, enum _BASE_TYPE base) +void bcm_print_buffer(UINT debug_level, const char *function_name, + const char *file_name, int line_number, + const unsigned char *buffer, int bufferlen, + BASE_TYPE base) { + int i; static const char * const buff_dump_base[] = { "DEC", "HEX", "OCT", "BIN" }; - if(debug_level>=current_debug_level) - { - int i=0; - printk("\n%s:%s:%d:Buffer dump of size 0x%x in the %s:\n", file_name, function_name, line_number, bufferlen, buff_dump_base[1]); - for(;istDebugState.debug_level) && \ - ((Type & Adapter->stDebugState.type) && (SubType & Adapter->stDebugState.subtype[Type]))) { \ - if (dbg_level & DBG_NO_FUNC_PRINT) \ - printk (string, ##args); \ - else \ - { \ - printk ("%s:" string, __FUNCTION__, ##args); \ - printk("\n"); \ - } \ - } \ - } \ -} while (0) -#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level, buffer, bufferlen) do { \ - if ((DBG_TYPE_PRINTK == Type) && (PRINTKS_ON)) { \ - bcm_print_buffer( dbg_level, __FUNCTION__, __FILE__, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX); \ - } else if (!Adapter) \ - ; \ - else { \ - if (((dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level) && \ - ((Type & Adapter->stDebugState.type) && (SubType & Adapter->stDebugState.subtype[Type]))) { \ - if (dbg_level & DBG_NO_FUNC_PRINT) \ - bcm_print_buffer( dbg_level, NULL, NULL, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX); \ - else \ - bcm_print_buffer( dbg_level, __FUNCTION__, __FILE__, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX); \ - } \ - } \ +#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) \ + do { \ + if (DBG_TYPE_PRINTK == Type) \ + pr_info("%s:" string "\n", __func__, ##args); \ + else if (Adapter && \ + (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \ + (Type & Adapter->stDebugState.type) && \ + (SubType & Adapter->stDebugState.subtype[Type])) { \ + if (dbg_level & DBG_NO_FUNC_PRINT) \ + printk(KERN_DEBUG string, ##args); \ + else \ + printk(KERN_DEBUG "%s:" string "\n", __func__, ##args); \ + } \ } while (0) +#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level, buffer, bufferlen) do { \ + if (DBG_TYPE_PRINTK == Type || \ + (Adapter && \ + (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \ + (Type & Adapter->stDebugState.type) && \ + (SubType & Adapter->stDebugState.subtype[Type]))) \ + bcm_print_buffer(dbg_level, __func__, __FILE__, __LINE__, \ + buffer, bufferlen, BCM_BASE_TYPE_HEX); \ +} while(0) + #define BCM_SHOW_DEBUG_BITMAP(Adapter) do { \ int i; \ diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 958d16ad5289..f810bfd0b1a5 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -11,6 +11,11 @@ static struct usb_device_id InterfaceUsbtable[] = { }; MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); +static unsigned int debug_level = DBG_LVL_CURR; +module_param(debug_level, uint, 0644); +MODULE_PARM_DESC(debug_level, "Debug level (0=none,...,7=all)"); + + VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) { INT i = 0; @@ -198,7 +203,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Init default driver debug state */ - psAdapter->stDebugState.debug_level = DBG_LVL_CURR; + psAdapter->stDebugState.debug_level = debug_level; psAdapter->stDebugState.type = DBG_TYPE_INITEXIT; memset (psAdapter->stDebugState.subtype, 0, sizeof (psAdapter->stDebugState.subtype)); -- cgit v1.2.3 From 3705a843bd98b3ccb7c4b6addfc182fe805a73ed Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:14:16 -0700 Subject: beceem: remove bogus network device notifier Network device should not be messing with refcounts directly. See Documentation/networking/netdevices.txt Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 2 +- drivers/staging/bcm/Bcmnet.c | 64 ------------------------------------------- drivers/staging/bcm/Debug.c | 1 - drivers/staging/bcm/headers.h | 1 - 4 files changed, 1 insertion(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 748460e898d8..eebb77f9413e 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -600,7 +600,7 @@ struct _MINI_ADAPTER struct semaphore NVMRdmWrmLock; BOOLEAN bNetworkInterfaceRegistered; - BOOLEAN bNetdeviceNotifierRegistered; + struct device *pstCreatedClassDevice; BOOLEAN bUsbClassDriverRegistered; // BOOLEAN InterfaceUpStatus; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 3262aff8dd4a..ce975d7f221f 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -4,48 +4,6 @@ #define DRV_VERSION "5.2.7.3P1" #define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc" -static INT bcm_notify_event(struct notifier_block *nb, ULONG event, PVOID dev) -{ - struct net_device *ndev = (struct net_device*)dev; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - //PMINI_ADAPTER Adapter = (PMINI_ADAPTER)ndev->priv; - if(strncmp(ndev->name,gblpnetdev->name,5)==0) - { - switch(event) - { - case NETDEV_CHANGEADDR: - case NETDEV_GOING_DOWN: - /*ignore this */ - break; - case NETDEV_DOWN: - break; - - case NETDEV_UP: - break; - - case NETDEV_REGISTER: - /* Increment the Reference Count for "veth0" */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register RefCount: %x\n", - netdev_refcnt_read(ndev)); - dev_hold(ndev); - break; - - case NETDEV_UNREGISTER: - /* Decrement the Reference Count for "veth0" */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregister RefCnt: %x\n", - netdev_refcnt_read(ndev)); - dev_put(ndev); - break; - }; - } - return NOTIFY_DONE; -} - -/* Notifier block to receive netdevice events */ -static struct notifier_block bcm_notifier_block = -{ - .notifier_call = bcm_notify_event, -}; struct net_device *gblpnetdev; /***************************************************************************************/ @@ -156,23 +114,6 @@ int register_networkdev(PMINI_ADAPTER Adapter) /* Read the MAC Address from EEPROM */ ReadMacAddressFromNVM(Adapter); - - /* Register the notifier block for getting netdevice events */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Registering netdevice notifier\n"); - result = register_netdevice_notifier(&bcm_notifier_block); - if(result) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM Notifier Block did not get registered"); - Adapter->bNetdeviceNotifierRegistered = FALSE; - return result; - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM Notifier got Registered"); - Adapter->bNetdeviceNotifierRegistered = TRUE; - } - - result = register_netdev(Adapter->dev); if (!result) { @@ -209,11 +150,6 @@ void bcm_unregister_networkdev(PMINI_ADAPTER Adapter) if(Adapter->dev && !IS_ERR(Adapter->dev) && Adapter->bNetworkInterfaceRegistered) unregister_netdev(Adapter->dev); /* Unregister the notifier block */ - if(Adapter->bNetdeviceNotifierRegistered == TRUE) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering netdevice notifier\n"); - unregister_netdevice_notifier(&bcm_notifier_block); - } } static int bcm_init(void) diff --git a/drivers/staging/bcm/Debug.c b/drivers/staging/bcm/Debug.c index 9f7f70ca1716..b86d8456cf7d 100644 --- a/drivers/staging/bcm/Debug.c +++ b/drivers/staging/bcm/Debug.c @@ -37,4 +37,3 @@ void bcm_print_buffer(UINT debug_level, const char *function_name, printk("\n"); } } - diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index 5867db5d0074..1a9bdf697420 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From d52db0b4b34410019e1546e3ccbe761b9e4ddd76 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:18:27 -0700 Subject: beceem: eliminate network registered state variable Just use presence of pointer Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 1 - drivers/staging/bcm/Bcmnet.c | 34 +++++++--------------------------- 2 files changed, 7 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index eebb77f9413e..055ff1cb39d9 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -599,7 +599,6 @@ struct _MINI_ADAPTER struct semaphore NVMRdmWrmLock; - BOOLEAN bNetworkInterfaceRegistered; struct device *pstCreatedClassDevice; BOOLEAN bUsbClassDriverRegistered; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index ce975d7f221f..4785d25874b9 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -115,41 +115,21 @@ int register_networkdev(PMINI_ADAPTER Adapter) ReadMacAddressFromNVM(Adapter); result = register_netdev(Adapter->dev); - if (!result) - { - Adapter->bNetworkInterfaceRegistered = TRUE ; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Beceem Network device name is %s!", Adapter->dev->name); - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Network device can not be registered!"); - Adapter->bNetworkInterfaceRegistered = FALSE ; - return result; + if (!result) { + free_netdev(Adapter->dev); + Adapter->dev = NULL; } -#if 0 - Adapter->stDebugState.debug_level = DBG_LVL_CURR; - Adapter->stDebugState.type =(UINT)0xffffffff; - Adapter->stDebugState.subtype[DBG_TYPE_OTHERS] = 0xffffffff; - Adapter->stDebugState.subtype[DBG_TYPE_RX] = 0xffffffff; - Adapter->stDebugState.subtype[DBG_TYPE_TX] = 0xffffffff; - Adapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xffffffff; - - printk("-------ps_adapter->stDebugState.type=%x\n",Adapter->stDebugState.type); - printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_OTHERS]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_OTHERS]); - printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_RX]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_RX]); - printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_TX]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_TX]); -#endif - - return 0; + return result; } void bcm_unregister_networkdev(PMINI_ADAPTER Adapter) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering the Net Dev...\n"); - if(Adapter->dev && !IS_ERR(Adapter->dev) && Adapter->bNetworkInterfaceRegistered) + if(Adapter->dev) { unregister_netdev(Adapter->dev); - /* Unregister the notifier block */ + Adapter->dev = NULL; + } } static int bcm_init(void) -- cgit v1.2.3 From 2b5e625882a7130c339e4ad2ac2b8f0422f11919 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:20:11 -0700 Subject: beceem: eliminate dead code Get rid of empty header file and unused declarations Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/InterfaceInit.h | 18 ------- drivers/staging/bcm/Interfacemain.h | 10 ---- drivers/staging/bcm/cntrl_SignalingInterface.h | 5 -- drivers/staging/bcm/headers.h | 1 - drivers/staging/bcm/nvm.h | 71 -------------------------- 5 files changed, 105 deletions(-) delete mode 100644 drivers/staging/bcm/Interfacemain.h (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h index a11af81d74d9..71e629d29c79 100644 --- a/drivers/staging/bcm/InterfaceInit.h +++ b/drivers/staging/bcm/InterfaceInit.h @@ -25,23 +25,5 @@ INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter); VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter); - - -#if 0 - -ULONG InterfaceClaimAdapter(PMINI_ADAPTER Adapter); - -VOID InterfaceDDRControllerInit(PMINI_ADAPTER Adapter); - -ULONG InterfaceReset(PMINI_ADAPTER Adapter); - -ULONG InterfaceRegisterResources(PMINI_ADAPTER Adapter); - -VOID InterfaceUnRegisterResources(PMINI_ADAPTER Adapter); - -ULONG InterfaceFirmwareDownload(PMINI_ADAPTER Adapter); - -#endif - #endif diff --git a/drivers/staging/bcm/Interfacemain.h b/drivers/staging/bcm/Interfacemain.h deleted file mode 100644 index e0db563c5e0f..000000000000 --- a/drivers/staging/bcm/Interfacemain.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _MAIN_ -#define _MAIN_ -#if 0 -typedef struct _MINI_ADAPTER -{ - S_INTERFACE_ADAPTER stInterfaceAdapter; -}MINI_ADAPTER,*PMINI_ADAPTER; - -#endif -#endif diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h index 7c47af7729f6..890778450a86 100644 --- a/drivers/staging/bcm/cntrl_SignalingInterface.h +++ b/drivers/staging/bcm/cntrl_SignalingInterface.h @@ -188,11 +188,6 @@ typedef struct _stServiceFlowParamSI{ /** 16bit ARQ Purge timeout */ B_UINT16 u16ARQRxPurgeTimeOut; -#if 0 //def ENABLE_CORRIGENDUM2_UPDATE -/* IEEE Comment #627 / MTG Comment #426 */ - /// \brief Size of an ARQ block, changed from 2 bytes to 1 - B_UINT8 u8ARQBlockSize; -#endif //TODO::Remove this once we move to a new CORR2 driver /// \brief Size of an ARQ block B_UINT16 u16ARQBlockSize; diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index 1a9bdf697420..b90d8a3e879b 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -69,7 +69,6 @@ #include "InterfaceMacros.h" #include "InterfaceAdapter.h" #include "InterfaceIsr.h" -#include "Interfacemain.h" #include "InterfaceMisc.h" #include "InterfaceRx.h" #include "InterfaceTx.h" diff --git a/drivers/staging/bcm/nvm.h b/drivers/staging/bcm/nvm.h index 88e394520b71..651b5a455b32 100644 --- a/drivers/staging/bcm/nvm.h +++ b/drivers/staging/bcm/nvm.h @@ -405,76 +405,5 @@ typedef struct _ISO_HEADER #define FIELD_OFFSET_IN_HEADER(HeaderPointer,Field) ((PUCHAR)&((HeaderPointer)(NULL))->Field - (PUCHAR)(NULL)) -#if 0 -INT BeceemEEPROMBulkRead( - PMINI_ADAPTER Adapter, - PUINT pBuffer, - UINT uiOffset, - UINT uiNumBytes); - - -INT BeceemFlashBulkRead( - PMINI_ADAPTER Adapter, - PUINT pBuffer, - UINT uiOffset, - UINT uiNumBytes); - -UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter); - -UINT BcmGetFlashSize(PMINI_ADAPTER Adapter); - -UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter); - - - -INT BeceemFlashBulkWrite( - PMINI_ADAPTER Adapter, - PUINT pBuffer, - UINT uiOffset, - UINT uiNumBytes, - BOOLEAN bVerify); - -INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter); - -INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter); - - -INT BeceemEEPROMBulkWrite( - PMINI_ADAPTER Adapter, - PUCHAR pBuffer, - UINT uiOffset, - UINT uiNumBytes, - BOOLEAN bVerify); - - -INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData); - -NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter); - -INT BeceemNVMRead( - PMINI_ADAPTER Adapter, - PUINT pBuffer, - UINT uiOffset, - UINT uiNumBytes); - -INT BeceemNVMWrite( - PMINI_ADAPTER Adapter, - PUINT pBuffer, - UINT uiOffset, - UINT uiNumBytes, - BOOLEAN bVerify); - -INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter); - -INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize); - -INT BcmInitNVM(PMINI_ADAPTER Adapter); - -VOID BcmValidateNvmType(PMINI_ADAPTER Adapter); - -VOID BcmGetFlashCSInfo(PMINI_ADAPTER Adapter); - -#endif - #endif -- cgit v1.2.3 From 92bc60580e55d18494a23ba8ae642a464ebfd7a6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 08:22:10 -0700 Subject: beceem: get rid of OS dependent data structure The only part of this structure still used was the network device stats, and in recent kernel these are available in network device itself. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 14 ++----------- drivers/staging/bcm/Bcmnet.c | 33 ++++++++++++++----------------- drivers/staging/bcm/HandleControlPacket.c | 3 --- drivers/staging/bcm/Misc.c | 16 ++------------- drivers/staging/bcm/Qos.c | 10 ++++------ drivers/staging/bcm/Transmit.c | 3 --- 6 files changed, 23 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 055ff1cb39d9..9c9dff3e0daa 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -43,17 +43,6 @@ typedef struct _BCM_CB BCM_CB,*PBCM_CB; typedef BCM_CB BCM_RCB, *PBCM_RCB; typedef BCM_CB BCM_TCB, *PBCM_TCB; -/* This is to be stored in the "pvOsDepData" of ADAPTER */ -typedef struct LINUX_DEP_DATA -{ - struct net_device *virtualdev; /* Our Interface (veth0) */ - struct net_device *actualdev; /* True Interface (eth0) */ - struct net_device_stats netstats; /* Net statistics */ - struct fasync_struct *async_queue; /* For asynchronus notification */ - -} LINUX_DEP_DATA, *PLINUX_DEP_DATA; - - struct _LEADER { USHORT Vcid; @@ -429,7 +418,7 @@ Driver adapter data structure struct _MINI_ADAPTER { struct _MINI_ADAPTER *next; - PVOID pvOsDepData; + CHAR *caDsxReqResp; atomic_t ApplicationRunning; volatile INT CtrlQueueLen; @@ -629,6 +618,7 @@ struct _MINI_ADAPTER struct semaphore LowPowerModeSync; ULONG liDrainCalculated; UINT gpioBitMap; + S_BCM_DEBUG_STATE stDebugState; }; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 4785d25874b9..670a7a4df364 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -44,24 +44,21 @@ static INT bcm_close(struct net_device *dev) static struct net_device_stats *bcm_get_stats(struct net_device *dev) { - PLINUX_DEP_DATA pLinuxData=NULL; - PMINI_ADAPTER Adapter = NULL ;// gpadapter ; - Adapter = GET_BCM_ADAPTER(dev); - pLinuxData = (PLINUX_DEP_DATA)(Adapter->pvOsDepData); - - //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Dev = %p, pLinuxData = %p", dev, pLinuxData); - pLinuxData->netstats.rx_packets=atomic_read(&Adapter->RxRollOverCount)*64*1024+Adapter->PrevNumRecvDescs; - pLinuxData->netstats.rx_bytes=atomic_read(&Adapter->GoodRxByteCount)+atomic_read(&Adapter->BadRxByteCount); - pLinuxData->netstats.rx_dropped=atomic_read(&Adapter->RxPacketDroppedCount); - pLinuxData->netstats.rx_errors=atomic_read(&Adapter->RxPacketDroppedCount); - pLinuxData->netstats.rx_length_errors=0; - pLinuxData->netstats.rx_frame_errors=0; - pLinuxData->netstats.rx_crc_errors=0; - pLinuxData->netstats.tx_bytes=atomic_read(&Adapter->GoodTxByteCount); - pLinuxData->netstats.tx_packets=atomic_read(&Adapter->TxTotalPacketCount); - pLinuxData->netstats.tx_dropped=atomic_read(&Adapter->TxDroppedPacketCount); - - return &(pLinuxData->netstats); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + struct net_device_stats* netstats = &dev->stats; + + netstats->rx_packets = atomic_read(&Adapter->RxRollOverCount)*64*1024 + + Adapter->PrevNumRecvDescs; + netstats->rx_bytes = atomic_read(&Adapter->GoodRxByteCount) + + atomic_read(&Adapter->BadRxByteCount); + + netstats->rx_dropped = atomic_read(&Adapter->RxPacketDroppedCount); + netstats->rx_errors = atomic_read(&Adapter->RxPacketDroppedCount); + netstats->tx_bytes = atomic_read(&Adapter->GoodTxByteCount); + netstats->tx_packets = atomic_read(&Adapter->TxTotalPacketCount); + netstats->tx_dropped = atomic_read(&Adapter->TxDroppedPacketCount); + + return netstats; } /** @ingroup init_functions diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c index 7b2ec28a4bc1..5dd88f98caa8 100644 --- a/drivers/staging/bcm/HandleControlPacket.c +++ b/drivers/staging/bcm/HandleControlPacket.c @@ -185,9 +185,6 @@ int control_packet_handler (PMINI_ADAPTER Adapter /**< pointer to adapter obje { DEQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail); // Adapter->RxControlHead=ctrl_packet->next; - ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.rx_packets++; - ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.rx_bytes+= - ((PLEADER)ctrl_packet->data)->PLength; } #if 0 //Idle mode debug profiling... if(*(PUSHORT)ctrl_packet->data == IDLE_MODE_STATUS) diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index cedeb8c3723e..351a8aee88fe 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -60,15 +60,6 @@ InitAdapter(PMINI_ADAPTER psAdapter) //init_waitqueue_head(&psAdapter->device_wake_queue); psAdapter->fw_download_done=FALSE; - psAdapter->pvOsDepData = (PLINUX_DEP_DATA) kmalloc(sizeof(LINUX_DEP_DATA), - GFP_KERNEL); - - if(psAdapter->pvOsDepData == NULL) - { - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Linux Specific Data allocation failed"); - return -ENOMEM; - } - memset(psAdapter->pvOsDepData, 0, sizeof(LINUX_DEP_DATA)); default_wimax_protocol_initialize(psAdapter); for (i=0;itxctlpacket[count]); } FreeAdapterDsxBuffer(Adapter); - if(Adapter->pvOsDepData) - bcm_kfree (Adapter->pvOsDepData); + if(Adapter->pvInterfaceAdapter) bcm_kfree(Adapter->pvInterfaceAdapter); @@ -1969,9 +1959,7 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter) void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex) { struct sk_buff* PacketToDrop=NULL; - struct net_device_stats* netstats=NULL; - - netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats; + struct net_device_stats* netstats = &Adapter->dev->stats; spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 75b2b879633f..a86a38c33f2e 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -362,18 +362,18 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/** Index %d",iIndex); if(iIndex == HiPriority) - return; + return; if(!Adapter || (iIndex < 0) || (iIndex > HiPriority)) return; /* To Store the netdevice statistic */ - netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats; + netstats = &Adapter->dev->stats; spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock); @@ -431,11 +431,9 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) INT iQIndex; UINT uiTotalPacketLength; struct sk_buff* PacketToDrop=NULL; - struct net_device_stats* netstats=NULL; + struct net_device_stats* netstats=&Adapter->dev->stats; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>"); - /* To Store the netdevice statistic */ - netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats; // down(&Adapter->data_packet_queue_lock); for(iQIndex=LowPriority; iQIndexinterface_transmit(Adapter->pvInterfaceAdapter, pControlPacket, (PLeader->PLength + LEADER_SIZE)); - ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_packets++; - ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_bytes+= - PLeader->PLength; atomic_dec(&Adapter->CurrNumFreeTxDesc); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<========="); return STATUS_SUCCESS; -- cgit v1.2.3 From 0ad008fcbc39572ab7078975cdf7e902fbc39ce6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 16:44:07 -0700 Subject: beceem: cleanup network device setup Change how network device is setup: * set pointer to device object so sysfs has eth0/device symlink * set network device type * eliminate all the compatiablity with older kernels. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 73 +++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 670a7a4df364..b4e729b57e67 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -11,8 +11,8 @@ struct net_device *gblpnetdev; static INT bcm_open(struct net_device *dev) { - PMINI_ADAPTER Adapter = NULL ; //(PMINI_ADAPTER)dev->priv; - Adapter = GET_BCM_ADAPTER(dev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "======>"); if(Adapter->fw_download_done==FALSE) return -EINVAL; @@ -30,8 +30,8 @@ static INT bcm_open(struct net_device *dev) static INT bcm_close(struct net_device *dev) { - PMINI_ADAPTER Adapter = NULL ;//gpadapter ; - Adapter = GET_BCM_ADAPTER(dev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=====>"); Adapter->if_up=0; if(!netif_queue_stopped(dev)) { @@ -60,12 +60,12 @@ static struct net_device_stats *bcm_get_stats(struct net_device *dev) return netstats; } + /** @ingroup init_functions Register other driver entry points with the kernel */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -static struct net_device_ops bcmNetDevOps = { +static const struct net_device_ops bcmNetDevOps = { .ndo_open = bcm_open, .ndo_stop = bcm_close, .ndo_get_stats = bcm_get_stats, @@ -74,47 +74,44 @@ static struct net_device_ops bcmNetDevOps = { .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; -#endif + +static struct device_type wimax_type = { + .name = "wimax", +}; int register_networkdev(PMINI_ADAPTER Adapter) { - int result=0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - void **temp = NULL; /* actually we're *allocating* the device in alloc_etherdev */ -#endif - Adapter->dev = alloc_etherdev(sizeof(PMINI_ADAPTER)); - if(!Adapter->dev) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "ERR: No Dev"); + struct net_device *net; + PMINI_ADAPTER *temp; + PS_INTERFACE_ADAPTER psIntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *uintf = psIntfAdapter->interface; + int result; + + net = alloc_etherdev(sizeof(PMINI_ADAPTER)); + if(!net) { + pr_notice("bcmnet: no memory for device\n"); return -ENOMEM; } - gblpnetdev = Adapter->dev; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - Adapter->dev->priv = Adapter; -#else - temp = netdev_priv(Adapter->dev); - *temp = (void *)Adapter; -#endif - //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "init adapterptr: %x %x\n", (UINT)Adapter, temp); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) - Adapter->dev->netdev_ops = &bcmNetDevOps; -#else - Adapter->dev->open = bcm_open; - Adapter->dev->stop = bcm_close; - Adapter->dev->get_stats = bcm_get_stats; - Adapter->dev->hard_start_xmit = bcm_transmit; - Adapter->dev->hard_header_len = ETH_HLEN + LEADER_SIZE; -#endif - - Adapter->dev->mtu = MTU_SIZE; /* 1400 Bytes */ + + Adapter->dev = net; /* FIXME - only allows one adapter! */ + temp = netdev_priv(net); + *temp = Adapter; + + net->netdev_ops = &bcmNetDevOps; + net->mtu = MTU_SIZE; /* 1400 Bytes */ + + SET_NETDEV_DEV(net, &uintf->dev); + SET_NETDEV_DEVTYPE(net, &wimax_type); + /* Read the MAC Address from EEPROM */ ReadMacAddressFromNVM(Adapter); - result = register_netdev(Adapter->dev); - if (!result) { - free_netdev(Adapter->dev); + result = register_netdev(net); + if (result == 0) + gblpnetdev = Adapter->dev = net; + else { Adapter->dev = NULL; + free_netdev(net); } return result; -- cgit v1.2.3 From bf01ca1b35ff26a4c16c22b9ce7554f0d3a45ba7 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 30 Oct 2010 15:32:32 +0200 Subject: VIA Chrome camera: remove duplicate includes The VIA Chrome integrated camera controller driver includes both 'linux/pci.h' and 'linux/device.h' twice. This gets rid of the duplicates. Signed-off-by: Jesper Juhl Acked-by: Jonathan Corbet Signed-off-by: Jiri Kosina --- drivers/media/video/via-camera.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 02a21bccae18..6f52818d5917 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -13,14 +13,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include -- cgit v1.2.3 From ff75b9bc489710ff223bc0d805bf3b862dc347ea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 30 Oct 2010 22:52:31 +0100 Subject: drm/i915: Fix typo from e5281ccd in i915_gem_attach_phys_object() Accessing the uninitialised obj->pages instead of the local page lead to an OOPs. Reported-by: Xavier Chantry Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 936ddd83f8a2..e3fc333e2e57 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4925,7 +4925,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, if (IS_ERR(page)) return PTR_ERR(page); - src = kmap_atomic(obj_priv->pages[i]); + src = kmap_atomic(page); dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); memcpy(dst, src, PAGE_SIZE); kunmap_atomic(src); -- cgit v1.2.3 From 5eac3ab45955b32f3a9d89e633918c4d6f133dfa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 Oct 2010 08:49:47 +0000 Subject: drm/i915: Evict just the purgeable GTT entries on the first pass Take two passes to evict everything whilst searching for sufficient free space to bind the batchbuffer. After searching for sufficient free space using LRU eviction, evict everything that is purgeable and try again. Only then if there is insufficient free space (or the GTT is too badly fragmented) evict everything from the aperture and try one last time. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_gem.c | 19 ++++++++-------- drivers/gpu/drm/i915/i915_gem_evict.c | 42 +++++++++++------------------------ 3 files changed, 25 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ec582b6d2113..54e5b2fa5fd4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1073,8 +1073,8 @@ void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); /* i915_gem_evict.c */ int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment, bool mappable); -int i915_gem_evict_everything(struct drm_device *dev); -int i915_gem_evict_inactive(struct drm_device *dev); +int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only); +int i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e3fc333e2e57..c8e516d3f8bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3519,7 +3519,8 @@ i915_gem_execbuffer_pin(struct drm_device *dev, int ret, i, retry; /* attempt to pin all of the buffers into the GTT */ - for (retry = 0; retry < 2; retry++) { + retry = 0; + do { ret = 0; for (i = 0; i < count; i++) { struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; @@ -3567,18 +3568,18 @@ i915_gem_execbuffer_pin(struct drm_device *dev, while (i--) i915_gem_object_unpin(object_list[i]); - if (ret == 0) - break; - - if (ret != -ENOSPC || retry) + if (ret != -ENOSPC || retry > 1) return ret; - ret = i915_gem_evict_everything(dev); + /* First attempt, just clear anything that is purgeable. + * Second attempt, clear the entire GTT. + */ + ret = i915_gem_evict_everything(dev, retry == 0); if (ret) return ret; - } - return 0; + retry++; + } while (1); } /* Throttle our rendering by waiting until the ring has completed our requests @@ -4484,7 +4485,7 @@ i915_gem_idle(struct drm_device *dev) /* Under UMS, be paranoid and evict. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = i915_gem_evict_inactive(dev); + ret = i915_gem_evict_inactive(dev, false); if (ret) { mutex_unlock(&dev->struct_mutex); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 3a4215f31652..a2609c5542fd 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -42,7 +42,7 @@ mark_free(struct drm_i915_gem_object *obj_priv, int i915_gem_evict_something(struct drm_device *dev, int min_size, - unsigned alignment, bool mappable) + unsigned alignment, bool mappable) { drm_i915_private_t *dev_priv = dev->dev_private; struct list_head eviction_list, unwind_list; @@ -54,7 +54,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, /* Re-check for free space after retiring requests */ if (mappable) { if (drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, - min_size, alignment, 0, + min_size, alignment, 0, dev_priv->mm.gtt_mappable_end, 0)) return 0; @@ -171,7 +171,7 @@ found: } int -i915_gem_evict_everything(struct drm_device *dev) +i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; @@ -192,38 +192,22 @@ i915_gem_evict_everything(struct drm_device *dev) BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); - ret = i915_gem_evict_inactive(dev); - if (ret) - return ret; - - lists_empty = (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list) && - list_empty(&dev_priv->bsd_ring.active_list) && - list_empty(&dev_priv->blt_ring.active_list)); - BUG_ON(!lists_empty); - - return 0; + return i915_gem_evict_inactive(dev, purgeable_only); } /** Unbinds all inactive objects. */ int -i915_gem_evict_inactive(struct drm_device *dev) +i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only) { drm_i915_private_t *dev_priv = dev->dev_private; - - while (!list_empty(&dev_priv->mm.inactive_list)) { - struct drm_gem_object *obj; - int ret; - - obj = &list_first_entry(&dev_priv->mm.inactive_list, - struct drm_i915_gem_object, - mm_list)->base; - - ret = i915_gem_object_unbind(obj); - if (ret != 0) { - DRM_ERROR("Error unbinding object: %d\n", ret); - return ret; + struct drm_i915_gem_object *obj, *next; + + list_for_each_entry_safe(obj, next, + &dev_priv->mm.inactive_list, mm_list) { + if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) { + int ret = i915_gem_object_unbind(&obj->base); + if (ret) + return ret; } } -- cgit v1.2.3 From 100519e2f1c20286158746f92f27c3aa14f5a893 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 Oct 2010 10:37:02 +0000 Subject: agp/intel: the GMCH is always enabled for integrated processor graphics ... and trying to set the bit is ineffectual. Fixes the regression from e380f60 which detected that we were trying to do undefined operations on the I830_GMCH_CTRL. Reported-by: Alexey Fisher Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9c86dac41da7..f800e9cfc368 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -73,6 +73,7 @@ struct intel_gtt_driver { unsigned int is_g33 : 1; unsigned int is_pineview : 1; unsigned int is_ironlake : 1; + unsigned int has_pgtbl_enable : 1; unsigned int dma_mask_size : 8; /* Chipset specific GTT setup */ int (*setup)(void); @@ -113,6 +114,7 @@ static struct _intel_private { #define IS_G33 intel_private.driver->is_g33 #define IS_PINEVIEW intel_private.driver->is_pineview #define IS_IRONLAKE intel_private.driver->is_ironlake +#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable static void intel_agp_free_sglist(struct agp_memory *mem) { @@ -803,6 +805,9 @@ static int intel_gtt_init(void) intel_private.PGETBL_save = readl(intel_private.registers+I810_PGETBL_CTL) & ~I810_PGETBL_ENABLED; + /* we only ever restore the register when enabling the PGTBL... */ + if (HAS_PGTBL_EN) + intel_private.PGETBL_save |= I810_PGETBL_ENABLED; dev_info(&intel_private.bridge_dev->dev, "detected gtt size: %dK total, %dK mappable\n", @@ -925,7 +930,6 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, static bool intel_enable_gtt(void) { u32 gma_addr; - u16 gmch_ctrl; u8 __iomem *reg; if (INTEL_GTT_GEN == 2) @@ -940,26 +944,30 @@ static bool intel_enable_gtt(void) if (INTEL_GTT_GEN >= 6) return true; - pci_read_config_word(intel_private.bridge_dev, - I830_GMCH_CTRL, &gmch_ctrl); - gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(intel_private.bridge_dev, - I830_GMCH_CTRL, gmch_ctrl); + if (INTEL_GTT_GEN == 2) { + u16 gmch_ctrl; - pci_read_config_word(intel_private.bridge_dev, - I830_GMCH_CTRL, &gmch_ctrl); - if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { - dev_err(&intel_private.pcidev->dev, - "failed to enable the GTT: GMCH_CTRL=%x\n", - gmch_ctrl); - return false; + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); + gmch_ctrl |= I830_GMCH_ENABLED; + pci_write_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, gmch_ctrl); + + pci_read_config_word(intel_private.bridge_dev, + I830_GMCH_CTRL, &gmch_ctrl); + if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { + dev_err(&intel_private.pcidev->dev, + "failed to enable the GTT: GMCH_CTRL=%x\n", + gmch_ctrl); + return false; + } } reg = intel_private.registers+I810_PGETBL_CTL; - writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED, reg); - if ((readl(reg) & I810_PGETBL_ENABLED) == 0) { + writel(intel_private.PGETBL_save, reg); + if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) { dev_err(&intel_private.pcidev->dev, - "failed to enable the GTT: PGETBL=%x [expected %x|1]\n", + "failed to enable the GTT: PGETBL=%x [expected %x]\n", readl(reg), intel_private.PGETBL_save); return false; } @@ -1395,6 +1403,7 @@ static const struct intel_gtt_driver i81x_gtt_driver = { }; static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, + .has_pgtbl_enable = 1, .setup = i830_setup, .cleanup = i830_cleanup, .write_entry = i830_write_entry, @@ -1404,6 +1413,7 @@ static const struct intel_gtt_driver i8xx_gtt_driver = { }; static const struct intel_gtt_driver i915_gtt_driver = { .gen = 3, + .has_pgtbl_enable = 1, .setup = i9xx_setup, .cleanup = i9xx_cleanup, /* i945 is the last gpu to need phys mem (for overlay and cursors). */ @@ -1434,6 +1444,7 @@ static const struct intel_gtt_driver pineview_gtt_driver = { }; static const struct intel_gtt_driver i965_gtt_driver = { .gen = 4, + .has_pgtbl_enable = 1, .setup = i9xx_setup, .cleanup = i9xx_cleanup, .write_entry = i965_write_entry, -- cgit v1.2.3 From 4b6ba8aacbb3185703b797286547d0f8f3859b02 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 26 Oct 2010 15:07:13 -0700 Subject: of/net: Move of_get_mac_address() to a common source file. There are two identical implementations of of_get_mac_address(), one each in arch/powerpc/kernel/prom_parse.c and arch/microblaze/kernel/prom_parse.c. Move this function to a new common file of_net.{c,h} and adjust all the callers to include the new header. Signed-off-by: David Daney [grant.likely@secretlab.ca: protect header with #ifdef] Signed-off-by: Grant Likely --- arch/microblaze/include/asm/prom.h | 3 --- arch/microblaze/kernel/prom_parse.c | 38 ----------------------------- arch/powerpc/include/asm/prom.h | 3 --- arch/powerpc/kernel/prom_parse.c | 38 ----------------------------- arch/powerpc/sysdev/mv64x60_dev.c | 1 + arch/powerpc/sysdev/tsi108_dev.c | 1 + drivers/net/fs_enet/fs_enet-main.c | 1 + drivers/net/gianfar.c | 1 + drivers/net/ucc_geth.c | 1 + drivers/net/xilinx_emaclite.c | 1 + drivers/of/Kconfig | 4 ++++ drivers/of/Makefile | 1 + drivers/of/of_net.c | 48 +++++++++++++++++++++++++++++++++++++ include/linux/of_net.h | 15 ++++++++++++ 14 files changed, 74 insertions(+), 82 deletions(-) create mode 100644 drivers/of/of_net.c create mode 100644 include/linux/of_net.h (limited to 'drivers') diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index bdc38312ae4a..2e72af078b05 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -64,9 +64,6 @@ extern void kdump_move_device_tree(void); /* CPU OF node matching */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); -/* Get the MAC address */ -extern const void *of_get_mac_address(struct device_node *np); - /** * of_irq_map_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index 99d9b61cccb5..9ae24f4b882b 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -110,41 +110,3 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, cells = prop ? *(u32 *)prop : of_n_size_cells(dn); *size = of_read_number(dma_window, cells); } - -/** - * Search the device tree for the best MAC address to use. 'mac-address' is - * checked first, because that is supposed to contain to "most recent" MAC - * address. If that isn't set, then 'local-mac-address' is checked next, - * because that is the default address. If that isn't set, then the obsolete - * 'address' is checked, just in case we're using an old device tree. - * - * Note that the 'address' property is supposed to contain a virtual address of - * the register set, but some DTS files have redefined that property to be the - * MAC address. - * - * All-zero MAC addresses are rejected, because those could be properties that - * exist in the device tree, but were not set by U-Boot. For example, the - * DTS could define 'mac-address' and 'local-mac-address', with zero MAC - * addresses. Some older U-Boots only initialized 'local-mac-address'. In - * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists - * but is all zeros. -*/ -const void *of_get_mac_address(struct device_node *np) -{ - struct property *pp; - - pp = of_find_property(np, "mac-address", NULL); - if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) - return pp->value; - - pp = of_find_property(np, "local-mac-address", NULL); - if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) - return pp->value; - - pp = of_find_property(np, "address", NULL); - if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) - return pp->value; - - return NULL; -} -EXPORT_SYMBOL(of_get_mac_address); diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index ae26f2efd089..98264bf0a433 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -63,9 +63,6 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); /* cache lookup */ struct device_node *of_find_next_cache_node(struct device_node *np); -/* Get the MAC address */ -extern const void *of_get_mac_address(struct device_node *np); - #ifdef CONFIG_NUMA extern int of_node_to_nid(struct device_node *device); #else diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 88334af038e5..c2b7a07cc3d3 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -117,41 +117,3 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, cells = prop ? *(u32 *)prop : of_n_size_cells(dn); *size = of_read_number(dma_window, cells); } - -/** - * Search the device tree for the best MAC address to use. 'mac-address' is - * checked first, because that is supposed to contain to "most recent" MAC - * address. If that isn't set, then 'local-mac-address' is checked next, - * because that is the default address. If that isn't set, then the obsolete - * 'address' is checked, just in case we're using an old device tree. - * - * Note that the 'address' property is supposed to contain a virtual address of - * the register set, but some DTS files have redefined that property to be the - * MAC address. - * - * All-zero MAC addresses are rejected, because those could be properties that - * exist in the device tree, but were not set by U-Boot. For example, the - * DTS could define 'mac-address' and 'local-mac-address', with zero MAC - * addresses. Some older U-Boots only initialized 'local-mac-address'. In - * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists - * but is all zeros. -*/ -const void *of_get_mac_address(struct device_node *np) -{ - struct property *pp; - - pp = of_find_property(np, "mac-address", NULL); - if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) - return pp->value; - - pp = of_find_property(np, "local-mac-address", NULL); - if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) - return pp->value; - - pp = of_find_property(np, "address", NULL); - if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) - return pp->value; - - return NULL; -} -EXPORT_SYMBOL(of_get_mac_address); diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c index 1398bc454999..feaee402e2d6 100644 --- a/arch/powerpc/sysdev/mv64x60_dev.c +++ b/arch/powerpc/sysdev/mv64x60_dev.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c index d4d15aaf18fa..c2d675b6392c 100644 --- a/arch/powerpc/sysdev/tsi108_dev.c +++ b/arch/powerpc/sysdev/tsi108_dev.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index d684f187de57..7a1f3d0ffa78 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 49e4ce1246a7..f860072e2f68 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -95,6 +95,7 @@ #include #include #include +#include #include "gianfar.h" #include "fsl_pq_mdio.h" diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a4c3f5708246..f7e370fd8ddc 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 14f0955eca68..2a34b22ea26a 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define DRIVER_NAME "xilinx_emaclite" diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index aa675ebd8eb3..e4b93a0a15d2 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -49,6 +49,10 @@ config OF_I2C help OpenFirmware I2C accessors +config OF_NET + depends on NETDEVICES + def_bool y + config OF_SPI def_tristate SPI depends on SPI && !SPARC diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 7888155bea08..3ab21a0a4907 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o +obj-$(CONFIG_OF_NET) += of_net.o obj-$(CONFIG_OF_SPI) += of_spi.o obj-$(CONFIG_OF_MDIO) += of_mdio.o diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c new file mode 100644 index 000000000000..86f334a2769c --- /dev/null +++ b/drivers/of/of_net.c @@ -0,0 +1,48 @@ +/* + * OF helpers for network devices. + * + * This file is released under the GPLv2 + * + * Initially copied out of arch/powerpc/kernel/prom_parse.c + */ +#include +#include +#include + +/** + * Search the device tree for the best MAC address to use. 'mac-address' is + * checked first, because that is supposed to contain to "most recent" MAC + * address. If that isn't set, then 'local-mac-address' is checked next, + * because that is the default address. If that isn't set, then the obsolete + * 'address' is checked, just in case we're using an old device tree. + * + * Note that the 'address' property is supposed to contain a virtual address of + * the register set, but some DTS files have redefined that property to be the + * MAC address. + * + * All-zero MAC addresses are rejected, because those could be properties that + * exist in the device tree, but were not set by U-Boot. For example, the + * DTS could define 'mac-address' and 'local-mac-address', with zero MAC + * addresses. Some older U-Boots only initialized 'local-mac-address'. In + * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists + * but is all zeros. +*/ +const void *of_get_mac_address(struct device_node *np) +{ + struct property *pp; + + pp = of_find_property(np, "mac-address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + pp = of_find_property(np, "local-mac-address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + pp = of_find_property(np, "address", NULL); + if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) + return pp->value; + + return NULL; +} +EXPORT_SYMBOL(of_get_mac_address); diff --git a/include/linux/of_net.h b/include/linux/of_net.h new file mode 100644 index 000000000000..e913081fb52a --- /dev/null +++ b/include/linux/of_net.h @@ -0,0 +1,15 @@ +/* + * OF helpers for network devices. + * + * This file is released under the GPLv2 + */ + +#ifndef __LINUX_OF_NET_H +#define __LINUX_OF_NET_H + +#ifdef CONFIG_OF_NET +#include +extern const void *of_get_mac_address(struct device_node *np); +#endif + +#endif /* __LINUX_OF_NET_H */ -- cgit v1.2.3 From e5c652603680404683fd1f262b511340545179a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Nov 2010 11:35:28 +0000 Subject: drm/i915/debugfs: Report ring in error state Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 62 ++++++++++++++++++++----------------- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 1 + 3 files changed, 36 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 56f7ced16f1a..9cb6061bf9d5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -32,6 +32,7 @@ #include "drmP.h" #include "drm.h" #include "intel_drv.h" +#include "intel_ringbuffer.h" #include "i915_drm.h" #include "i915_drv.h" @@ -48,12 +49,6 @@ enum { DEFERRED_FREE_LIST, }; -enum { - RENDER_RING, - BSD_RING, - BLT_RING, -}; - static const char *yesno(int v) { return v ? "yes" : "no"; @@ -450,9 +445,9 @@ static int i915_hws_info(struct seq_file *m, void *data) int i; switch ((uintptr_t)node->info_ent->data) { - case RENDER_RING: ring = &dev_priv->render_ring; break; - case BSD_RING: ring = &dev_priv->bsd_ring; break; - case BLT_RING: ring = &dev_priv->blt_ring; break; + case RING_RENDER: ring = &dev_priv->render_ring; break; + case RING_BSD: ring = &dev_priv->bsd_ring; break; + case RING_BLT: ring = &dev_priv->blt_ring; break; default: return -EINVAL; } @@ -520,9 +515,9 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) int ret; switch ((uintptr_t)node->info_ent->data) { - case RENDER_RING: ring = &dev_priv->render_ring; break; - case BSD_RING: ring = &dev_priv->bsd_ring; break; - case BLT_RING: ring = &dev_priv->blt_ring; break; + case RING_RENDER: ring = &dev_priv->render_ring; break; + case RING_BSD: ring = &dev_priv->bsd_ring; break; + case RING_BLT: ring = &dev_priv->blt_ring; break; default: return -EINVAL; } @@ -554,9 +549,9 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) struct intel_ring_buffer *ring; switch ((uintptr_t)node->info_ent->data) { - case RENDER_RING: ring = &dev_priv->render_ring; break; - case BSD_RING: ring = &dev_priv->bsd_ring; break; - case BLT_RING: ring = &dev_priv->blt_ring; break; + case RING_RENDER: ring = &dev_priv->render_ring; break; + case RING_BSD: ring = &dev_priv->bsd_ring; break; + case RING_BLT: ring = &dev_priv->blt_ring; break; default: return -EINVAL; } @@ -574,6 +569,16 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) return 0; } +static const char *ring_str(int ring) +{ + switch (ring) { + case RING_RENDER: return "render"; + case RING_BSD: return "bsd"; + case RING_BLT: return "blt"; + default: return ""; + } +} + static const char *pin_flag(int pinned) { if (pinned > 0) @@ -630,14 +635,14 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, "ERROR: 0x%08x\n", error->error); seq_printf(m, "Blitter command stream:\n"); seq_printf(m, " ACTHD: 0x%08x\n", error->bcs_acthd); - seq_printf(m, " IPEHR: 0x%08x\n", error->bcs_ipehr); seq_printf(m, " IPEIR: 0x%08x\n", error->bcs_ipeir); + seq_printf(m, " IPEHR: 0x%08x\n", error->bcs_ipehr); seq_printf(m, " INSTDONE: 0x%08x\n", error->bcs_instdone); seq_printf(m, " seqno: 0x%08x\n", error->bcs_seqno); seq_printf(m, "Video (BSD) command stream:\n"); seq_printf(m, " ACTHD: 0x%08x\n", error->vcs_acthd); - seq_printf(m, " IPEHR: 0x%08x\n", error->vcs_ipehr); seq_printf(m, " IPEIR: 0x%08x\n", error->vcs_ipeir); + seq_printf(m, " IPEHR: 0x%08x\n", error->vcs_ipehr); seq_printf(m, " INSTDONE: 0x%08x\n", error->vcs_instdone); seq_printf(m, " seqno: 0x%08x\n", error->vcs_seqno); } @@ -657,7 +662,7 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, "Buffers [%d]:\n", error->active_bo_count); for (i = 0; i < error->active_bo_count; i++) { - seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s", + seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s %s", error->active_bo[i].gtt_offset, error->active_bo[i].size, error->active_bo[i].read_domains, @@ -666,7 +671,8 @@ static int i915_error_state(struct seq_file *m, void *unused) pin_flag(error->active_bo[i].pinned), tiling_flag(error->active_bo[i].tiling), dirty_flag(error->active_bo[i].dirty), - purgeable_flag(error->active_bo[i].purgeable)); + purgeable_flag(error->active_bo[i].purgeable), + ring_str(error->active_bo[i].ring)); if (error->active_bo[i].name) seq_printf(m, " (name: %d)", error->active_bo[i].name); @@ -1101,15 +1107,15 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_seqno", i915_gem_seqno_info, 0}, {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, {"i915_gem_interrupt", i915_interrupt_info, 0}, - {"i915_gem_hws", i915_hws_info, 0, (void *)RENDER_RING}, - {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BLT_RING}, - {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)BSD_RING}, - {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RENDER_RING}, - {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RENDER_RING}, - {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BSD_RING}, - {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BSD_RING}, - {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BLT_RING}, - {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BLT_RING}, + {"i915_gem_hws", i915_hws_info, 0, (void *)RING_RENDER}, + {"i915_gem_hws_blt", i915_hws_info, 0, (void *)RING_BLT}, + {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)RING_BSD}, + {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_RENDER}, + {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_RENDER}, + {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BSD}, + {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BSD}, + {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BLT}, + {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BLT}, {"i915_batchbuffers", i915_batchbuffer_info, 0}, {"i915_error_state", i915_error_state, 0}, {"i915_rstdby_delays", i915_rstdby_delays, 0}, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 54e5b2fa5fd4..3f8786049cb6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -182,6 +182,7 @@ struct drm_i915_error_state { u32 tiling:2; u32 dirty:1; u32 purgeable:1; + u32 ring:4; } *active_bo; u32 active_bo_count; struct intel_overlay_error_state *overlay; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 90c071d37748..3ec631f1129d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -728,6 +728,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->active_bo[i].tiling = obj_priv->tiling_mode; error->active_bo[i].dirty = obj_priv->dirty; error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED; + error->active_bo[i].ring = obj_priv->ring->id; if (++i == count) break; -- cgit v1.2.3 From 13b2928933919c5344716d49620a52493a243f8c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Nov 2010 12:22:48 +0000 Subject: drm/i915: Apply big hammer to serialise buffer access between rings Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 75 ++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c8e516d3f8bc..c797d2b9b233 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3189,7 +3189,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, * write domain */ if (obj->write_domain && - obj->write_domain != obj->pending_read_domains) { + (obj->write_domain != obj->pending_read_domains || + obj_priv->ring != ring)) { flush_domains |= obj->write_domain; invalidate_domains |= obj->pending_read_domains & ~obj->write_domain; @@ -3582,6 +3583,52 @@ i915_gem_execbuffer_pin(struct drm_device *dev, } while (1); } +static int +i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, + struct drm_file *file, + struct intel_ring_buffer *ring, + struct drm_gem_object **objects, + int count) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret, i; + + /* Zero the global flush/invalidate flags. These + * will be modified as new domains are computed + * for each object + */ + dev->invalidate_domains = 0; + dev->flush_domains = 0; + dev_priv->mm.flush_rings = 0; + for (i = 0; i < count; i++) + i915_gem_object_set_to_gpu_domain(objects[i], ring); + + if (dev->invalidate_domains | dev->flush_domains) { +#if WATCH_EXEC + DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", + __func__, + dev->invalidate_domains, + dev->flush_domains); +#endif + i915_gem_flush(dev, file, + dev->invalidate_domains, + dev->flush_domains, + dev_priv->mm.flush_rings); + } + + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = to_intel_bo(objects[i]); + /* XXX replace with semaphores */ + if (obj->ring && ring != obj->ring) { + ret = i915_gem_object_wait_rendering(&obj->base, true); + if (ret) + return ret; + } + } + + return 0; +} + /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * @@ -3843,28 +3890,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - /* Zero the global flush/invalidate flags. These - * will be modified as new domains are computed - * for each object - */ - dev->invalidate_domains = 0; - dev->flush_domains = 0; - dev_priv->mm.flush_rings = 0; - for (i = 0; i < args->buffer_count; i++) - i915_gem_object_set_to_gpu_domain(object_list[i], ring); - - if (dev->invalidate_domains | dev->flush_domains) { -#if WATCH_EXEC - DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", - __func__, - dev->invalidate_domains, - dev->flush_domains); -#endif - i915_gem_flush(dev, file, - dev->invalidate_domains, - dev->flush_domains, - dev_priv->mm.flush_rings); - } + ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring, + object_list, args->buffer_count); + if (ret) + goto err; #if WATCH_COHERENCY for (i = 0; i < args->buffer_count; i++) { -- cgit v1.2.3 From 0f8c6d7ca9257d6a01671ab69b897860d3ae9bc0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Nov 2010 12:38:44 +0000 Subject: drm/i915: Move the invalidate|flush information out of the device struct ... and into a local structure scoped for the single function in which it is used. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_gem.c | 45 +++++++++++++++++++++-------------------- include/drm/drmP.h | 2 -- 3 files changed, 23 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3f8786049cb6..a0063f82fa33 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -642,8 +642,6 @@ typedef struct drm_i915_private { /* storage for physical objects */ struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; - uint32_t flush_rings; - /* accounting, useful for userland debugging */ size_t object_memory; size_t pin_memory; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c797d2b9b233..ffea847c8a0d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -36,6 +36,12 @@ #include #include +struct change_domains { + uint32_t invalidate_domains; + uint32_t flush_domains; + uint32_t flush_rings; +}; + static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv); static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv); @@ -3167,10 +3173,9 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) */ static void i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + struct change_domains *cd) { - struct drm_device *dev = obj->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t invalidate_domains = 0; uint32_t flush_domains = 0; @@ -3216,12 +3221,12 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, if (flush_domains == 0 && obj->pending_write_domain == 0) obj->pending_write_domain = obj->write_domain; - dev->invalidate_domains |= invalidate_domains; - dev->flush_domains |= flush_domains; + cd->invalidate_domains |= invalidate_domains; + cd->flush_domains |= flush_domains; if (flush_domains & I915_GEM_GPU_DOMAINS) - dev_priv->mm.flush_rings |= obj_priv->ring->id; + cd->flush_rings |= obj_priv->ring->id; if (invalidate_domains & I915_GEM_GPU_DOMAINS) - dev_priv->mm.flush_rings |= ring->id; + cd->flush_rings |= ring->id; } /** @@ -3590,30 +3595,26 @@ i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, struct drm_gem_object **objects, int count) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct change_domains cd; int ret, i; - /* Zero the global flush/invalidate flags. These - * will be modified as new domains are computed - * for each object - */ - dev->invalidate_domains = 0; - dev->flush_domains = 0; - dev_priv->mm.flush_rings = 0; + cd.invalidate_domains = 0; + cd.flush_domains = 0; + cd.flush_rings = 0; for (i = 0; i < count; i++) - i915_gem_object_set_to_gpu_domain(objects[i], ring); + i915_gem_object_set_to_gpu_domain(objects[i], ring, &cd); - if (dev->invalidate_domains | dev->flush_domains) { + if (cd.invalidate_domains | cd.flush_domains) { #if WATCH_EXEC DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", __func__, - dev->invalidate_domains, - dev->flush_domains); + cd.invalidate_domains, + cd.flush_domains); #endif i915_gem_flush(dev, file, - dev->invalidate_domains, - dev->flush_domains, - dev_priv->mm.flush_rings); + cd.invalidate_domains, + cd.flush_domains, + cd.flush_rings); } for (i = 0; i < count; i++) { diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 274eaaa15c36..d4bc0f5cab8f 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1041,8 +1041,6 @@ struct drm_device { /*@{ */ spinlock_t object_name_lock; struct idr object_name_idr; - uint32_t invalidate_domains; /* domains pending invalidation */ - uint32_t flush_domains; /* domains pending flush */ /*@} */ }; -- cgit v1.2.3 From c5113e3c111b03c8eaf3fb0ef39e33dc25171adc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 21:26:06 -0700 Subject: beceem: use kernel print_hex_dump function No longer need special hex dump routine Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Debug.c | 39 --------------------------------------- drivers/staging/bcm/Debug.h | 25 +++++++------------------ drivers/staging/bcm/Makefile | 2 +- 3 files changed, 8 insertions(+), 58 deletions(-) delete mode 100644 drivers/staging/bcm/Debug.c (limited to 'drivers') diff --git a/drivers/staging/bcm/Debug.c b/drivers/staging/bcm/Debug.c deleted file mode 100644 index b86d8456cf7d..000000000000 --- a/drivers/staging/bcm/Debug.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "headers.h" - -void bcm_print_buffer(UINT debug_level, const char *function_name, - const char *file_name, int line_number, - const unsigned char *buffer, int bufferlen, - BASE_TYPE base) -{ - int i; - static const char * const buff_dump_base[] = { - "DEC", "HEX", "OCT", "BIN" - }; - - if(debug_level < BCM_SCREAM) - return; - - printk("\n" KERN_DEBUG "%s:%s:%d:Buffer dump of size 0x%x in the %s:\n", - file_name, function_name, line_number, bufferlen, buff_dump_base[1]); - - for(i = 0; i < bufferlen;i++) { - if(i && !(i%16) ) - printk("\n"); - switch(base) { - case BCM_BASE_TYPE_DEC: - printk("%03d ", buffer[i]); - break; - case BCM_BASE_TYPE_OCT: - printk("%0x03o ", buffer[i]); - break; - case BCM_BASE_TYPE_BIN: - printk("%02x ", buffer[i]); - break; - case BCM_BASE_TYPE_HEX: - default: - printk("%02X ", buffer[i]); - break; - } - printk("\n"); - } -} diff --git a/drivers/staging/bcm/Debug.h b/drivers/staging/bcm/Debug.h index 58e46a601dec..3138729cf34f 100644 --- a/drivers/staging/bcm/Debug.h +++ b/drivers/staging/bcm/Debug.h @@ -9,19 +9,6 @@ #include #define NONE 0xFFFF -typedef enum _BASE_TYPE -{ - BCM_BASE_TYPE_DEC, - BCM_BASE_TYPE_OCT, - BCM_BASE_TYPE_BIN, - BCM_BASE_TYPE_HEX, - BCM_BASE_TYPE_NONE, -} BASE_TYPE, *PBASE_TYPE; - -void bcm_print_buffer(UINT debug_level, const char *function_name, - const char *file_name, int line_number, - const unsigned char *buffer, int bufferlen, BASE_TYPE base); - //-------------------------------------------------------------------------------- @@ -231,7 +218,7 @@ typedef struct _S_BCM_DEBUG_STATE { #define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) \ do { \ if (DBG_TYPE_PRINTK == Type) \ - pr_info("%s:" string "\n", __func__, ##args); \ + pr_info("%s:" string, __func__, ##args); \ else if (Adapter && \ (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \ (Type & Adapter->stDebugState.type) && \ @@ -239,7 +226,7 @@ typedef struct _S_BCM_DEBUG_STATE { if (dbg_level & DBG_NO_FUNC_PRINT) \ printk(KERN_DEBUG string, ##args); \ else \ - printk(KERN_DEBUG "%s:" string "\n", __func__, ##args); \ + printk(KERN_DEBUG "%s:" string, __func__, ##args); \ } \ } while (0) @@ -248,9 +235,11 @@ typedef struct _S_BCM_DEBUG_STATE { (Adapter && \ (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \ (Type & Adapter->stDebugState.type) && \ - (SubType & Adapter->stDebugState.subtype[Type]))) \ - bcm_print_buffer(dbg_level, __func__, __FILE__, __LINE__, \ - buffer, bufferlen, BCM_BASE_TYPE_HEX); \ + (SubType & Adapter->stDebugState.subtype[Type]))) { \ + printk(KERN_DEBUG "%s:\n", __func__); \ + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, \ + 16, 1, buffer, bufferlen, false); \ + } \ } while(0) diff --git a/drivers/staging/bcm/Makefile b/drivers/staging/bcm/Makefile index c3ae25af670a..6f6fcee8e4a9 100644 --- a/drivers/staging/bcm/Makefile +++ b/drivers/staging/bcm/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_BCM_WIMAX) += bcm_wimax.o bcm_wimax-y := InterfaceDld.o InterfaceIdleMode.o InterfaceInit.o InterfaceRx.o \ InterfaceIsr.o InterfaceMisc.o InterfaceTx.o \ - Arp.o CmHost.o Debug.o IPv6Protocol.o Qos.o Transmit.o\ + Arp.o CmHost.o IPv6Protocol.o Qos.o Transmit.o\ Bcmnet.o DDRInit.o HandleControlPacket.o\ LeakyBucket.o Misc.o sort.o Bcmchar.o hostmibs.o PHSModule.o\ Osal_Misc.o led_control.o nvm.o vendorspecificextn.o -- cgit v1.2.3 From 082e889b475c46e71be6e779f15ab095f888e03f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 09:35:21 -0400 Subject: beceem: remove OS wrapper library Use native kernel functions for kmalloc/kfree directly Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Arp.c | 2 +- drivers/staging/bcm/Bcmchar.c | 68 ++++++++-------- drivers/staging/bcm/CmHost.c | 24 +++--- drivers/staging/bcm/HandleControlPacket.c | 4 +- drivers/staging/bcm/InterfaceDld.c | 24 +++--- drivers/staging/bcm/InterfaceInit.c | 2 +- drivers/staging/bcm/InterfaceRx.c | 2 +- drivers/staging/bcm/Makefile | 2 +- drivers/staging/bcm/Misc.c | 51 ++++-------- drivers/staging/bcm/Osal_Misc.c | 27 ------ drivers/staging/bcm/PHSModule.c | 131 ++++++++++-------------------- drivers/staging/bcm/Prototypes.h | 4 - drivers/staging/bcm/Qos.c | 4 +- drivers/staging/bcm/Transmit.c | 8 +- drivers/staging/bcm/headers.h | 1 - drivers/staging/bcm/hostmibs.c | 4 +- drivers/staging/bcm/led_control.c | 7 +- drivers/staging/bcm/nvm.c | 105 +++++++++++------------- drivers/staging/bcm/osal_misc.h | 49 ----------- 19 files changed, 180 insertions(+), 339 deletions(-) delete mode 100644 drivers/staging/bcm/Osal_Misc.c delete mode 100644 drivers/staging/bcm/osal_misc.h (limited to 'drivers') diff --git a/drivers/staging/bcm/Arp.c b/drivers/staging/bcm/Arp.c index d60d8593d2ef..7cb25b30b5c1 100644 --- a/drivers/staging/bcm/Arp.c +++ b/drivers/staging/bcm/Arp.c @@ -50,7 +50,7 @@ reply_to_arp_request(struct sk_buff *skb) { if(memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN)) { - bcm_kfree_skb(skb); + dev_kfree_skb(skb); return; } } diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 01f961d9c70c..f9979a87c42b 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -93,7 +93,7 @@ static int bcm_char_release(struct inode *inode, struct file *filp) /*Stop Queuing the control response Packets*/ atomic_dec(&Adapter->ApplicationRunning); - bcm_kfree(pTarang); + kfree(pTarang); /* remove this filp from the asynchronously notified filp's */ filp->private_data = NULL; @@ -141,12 +141,12 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l PktLen = Packet->len; if(copy_to_user(buf, Packet->data, PktLen)) { - bcm_kfree_skb(Packet); + dev_kfree_skb(Packet); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nReturning from copy to user failure \n"); return -EFAULT; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read %d Bytes From Adapter packet = 0x%p by process %d!\n", PktLen, Packet, current->pid); - bcm_kfree_skb(Packet); + dev_kfree_skb(Packet); } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "<====\n"); @@ -239,7 +239,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (PUINT)temp_buff, Bufflen); if(Status != STATUS_SUCCESS) { - bcm_kfree(temp_buff); + kfree(temp_buff); return Status; } if(copy_to_user(IoBuffer.OutputBuffer, @@ -247,7 +247,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { Status = -EFAULT; } - bcm_kfree(temp_buff); + kfree(temp_buff); break; } case IOCTL_BCM_REGISTER_WRITE_PRIVATE: @@ -344,7 +344,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (PUINT)temp_buff, IoBuffer.OutputLength); if(Status != STATUS_SUCCESS) { - bcm_kfree(temp_buff); + kfree(temp_buff); return Status; } if(copy_to_user(IoBuffer.OutputBuffer, @@ -352,7 +352,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { Status = -EFAULT; } - bcm_kfree(temp_buff); + kfree(temp_buff); break; } case IOCTL_BCM_REGISTER_WRITE: @@ -796,7 +796,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) IoBuffer.InputLength)) { Status = -EFAULT; - bcm_kfree(pvBuffer); + kfree(pvBuffer); break; } @@ -816,7 +816,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer); cntrlEnd: up(&Adapter->LowPowerModeSync); - bcm_kfree(pvBuffer); + kfree(pvBuffer); break; } case IOCTL_BCM_BUFFER_DOWNLOAD_START: @@ -924,7 +924,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status != STATUS_SUCCESS) up(&Adapter->fw_download_sema); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n"); - bcm_kfree(psFwInfo); + kfree(psFwInfo); break; } case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: @@ -1193,11 +1193,11 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) sizeof(S_MIBS_HOST_STATS_MIBS))) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy to user failed\n"); - bcm_kfree(temp_buff); + kfree(temp_buff); return -EFAULT; } - bcm_kfree(temp_buff); + kfree(temp_buff); break; } @@ -1246,7 +1246,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) /* Get WrmBuffer structure */ if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) { - bcm_kfree(pvBuffer); + kfree(pvBuffer); Status = -EFAULT; break; } @@ -1256,7 +1256,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 || ((ULONG)pBulkBuffer->Register & 0x3)) { - bcm_kfree(pvBuffer); + kfree(pvBuffer); BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,"WRM Done On invalid Address : %x Access Denied.\n",(int)pBulkBuffer->Register); Status = -EINVAL; break; @@ -1271,7 +1271,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (uiTempVar == EEPROM_REJECT_REG_4)) && (cmd == IOCTL_BCM_REGISTER_WRITE)) { - bcm_kfree(pvBuffer); + kfree(pvBuffer); BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,"EEPROM Access Denied, not in VSG Mode\n"); Status = -EFAULT; break; @@ -1287,7 +1287,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n"); } - bcm_kfree(pvBuffer); + kfree(pvBuffer); break; } @@ -1486,7 +1486,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) stNVMReadWrite.uiNumBytes)) { Status = -EFAULT; - bcm_kfree(pReadData); + kfree(pReadData); break; } @@ -1501,7 +1501,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n"); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadData); + kfree(pReadData); return -EACCES; } @@ -1512,13 +1512,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status != STATUS_SUCCESS) { - bcm_kfree(pReadData); + kfree(pReadData); return Status; } if(copy_to_user(stNVMReadWrite.pBuffer, pReadData, (UINT)stNVMReadWrite.uiNumBytes)) { - bcm_kfree(pReadData); + kfree(pReadData); Status = -EFAULT; } } @@ -1533,7 +1533,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n"); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadData); + kfree(pReadData); return -EACCES; } @@ -1561,7 +1561,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"DSD Sig is present neither in Flash nor User provided Input.."); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadData); + kfree(pReadData); return Status; } @@ -1570,7 +1570,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"DSD Sig is present neither in Flash nor User provided Input.."); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadData); + kfree(pReadData); return Status; } } @@ -1587,7 +1587,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status != STATUS_SUCCESS) { - bcm_kfree(pReadData); + kfree(pReadData); return Status; } } @@ -1595,7 +1595,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n",(tv1.tv_sec - tv0.tv_sec)*1000 +(tv1.tv_usec - tv0.tv_usec)/1000); - bcm_kfree(pReadData); + kfree(pReadData); Status = STATUS_SUCCESS; } break; @@ -1666,7 +1666,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n"); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadBuff); + kfree(pReadBuff); return -EACCES; } @@ -1706,7 +1706,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadBuff); + kfree(pReadBuff); } break ; @@ -1799,7 +1799,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n"); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pWriteBuff); + kfree(pWriteBuff); return -EACCES; } @@ -1838,7 +1838,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } while(NOB > 0); BcmFlash2xWriteSig(Adapter,sFlash2xWrite.Section); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pWriteBuff); + kfree(pWriteBuff); } break ; case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP : @@ -1874,7 +1874,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n"); up(&Adapter->NVMRdmWrmLock); - bcm_kfree(psFlash2xBitMap); + kfree(psFlash2xBitMap); return -EACCES; } @@ -1884,10 +1884,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x bitMap failed"); - bcm_kfree(psFlash2xBitMap); + kfree(psFlash2xBitMap); return -EFAULT; } - bcm_kfree(psFlash2xBitMap); + kfree(psFlash2xBitMap); } break ; case IOCTL_BCM_SET_ACTIVE_SECTION : @@ -2214,7 +2214,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (Adapter->bPreparingForLowPowerMode ==TRUE)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n"); - bcm_kfree(pReadBuff); + kfree(pReadBuff); up(&Adapter->NVMRdmWrmLock); return -EACCES; } @@ -2254,7 +2254,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } Adapter->bFlashRawRead = FALSE ; up(&Adapter->NVMRdmWrmLock); - bcm_kfree(pReadBuff); + kfree(pReadBuff); break ; } diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 6f388a374ddc..dadfff00f837 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -985,7 +985,7 @@ static VOID CopyToAdapter( register PMINI_ADAPTER Adapter, /**PackInfo[uiSearchRuleIndex].pstSFIndication) { - bcm_kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication); + kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication); Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = NULL; } Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = pstAddIndication; @@ -1844,7 +1844,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *p (*puBufferLength) = sizeof(stLocalSFAddIndication); *(stLocalSFAddIndication *)pvBuffer = *pstAddIndication; - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); return 1; } @@ -1931,7 +1931,7 @@ static inline stLocalSFAddIndicationAlt BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================"); return pstAddIndicationDest; failed_restore_sf_param: - bcm_kfree(pstAddIndicationDest); + kfree(pstAddIndicationDest); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "<=====" ); return NULL; } @@ -2049,7 +2049,7 @@ INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter) { if(Adapter->caDsxReqResp) { - bcm_kfree(Adapter->caDsxReqResp); + kfree(Adapter->caDsxReqResp); } return 0; @@ -2102,7 +2102,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**u16VCID)); CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp); - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); } break; case DSA_RSP: @@ -2169,7 +2169,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**PackInfo[uiSearchRuleIndex].bActive=FALSE; Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE; Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0; - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); } else if(psfLocalSet->bValid && (pstAddIndication->u8CC == 0)) @@ -2218,13 +2218,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**PackInfo[uiSearchRuleIndex].bActive=FALSE; Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE; Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0; - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); } } else { BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSA ACK did not get valid SFID"); - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); return FALSE; } } @@ -2239,7 +2239,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_RSP; CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp); - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); } break; case DSC_RSP: @@ -2312,13 +2312,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**u8CC == 6) { deleteSFBySfid(Adapter,uiSearchRuleIndex); - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); } } else { BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSC ACK did not get valid SFID"); - bcm_kfree(pstAddIndication); + kfree(pstAddIndication); return FALSE; } } @@ -2355,7 +2355,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**RxAppControlQueuelock); wake_up(&Adapter->process_read_wait_queue); - bcm_kfree_skb(skb); + dev_kfree_skb(skb); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "After wake_up_interruptible"); } @@ -231,7 +231,7 @@ INT flushAllAppQ(void) { PacketToDrop=pTarang->RxAppControlHead; DEQUEUEPACKET(pTarang->RxAppControlHead,pTarang->RxAppControlTail); - bcm_kfree_skb(PacketToDrop); + dev_kfree_skb(PacketToDrop); } pTarang->AppCtrlQueueLen = 0; //dropped contrl packet statistics also should be reset. diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c index 62770e042e51..e640b75e7dc4 100644 --- a/drivers/staging/bcm/InterfaceDld.c +++ b/drivers/staging/bcm/InterfaceDld.c @@ -48,7 +48,7 @@ int InterfaceFileDownload( PVOID arg, on_chip_loc+=MAX_TRANSFER_CTRL_BYTE_USB; }/* End of for(;;)*/ - bcm_kfree(buff); + kfree(buff); return errno; } @@ -69,8 +69,8 @@ int InterfaceFileReadbackFromChip( PVOID arg, buff_readback=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA); if(!buff || !buff_readback) { - bcm_kfree(buff); - bcm_kfree(buff_readback); + kfree(buff); + kfree(buff_readback); return -ENOMEM; } @@ -137,8 +137,8 @@ int InterfaceFileReadbackFromChip( PVOID arg, on_chip_loc+=MAX_TRANSFER_CTRL_BYTE_USB; }/* End of while(1)*/ exit: - bcm_kfree(buff); - bcm_kfree(buff_readback); + kfree(buff); + kfree(buff_readback); return Status; } @@ -164,7 +164,7 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter, psFwInfo->pvMappedFirmwareAddress, psFwInfo->u32FirmwareLength); if(retval) { - bcm_kfree (Adapter->pstargetparams); + kfree(Adapter->pstargetparams); Adapter->pstargetparams = NULL; return -EFAULT; } @@ -261,7 +261,7 @@ static int bcm_download_buffer(PMINI_ADAPTER Adapter, u32FirmwareLength -= len; mappedbuffer +=len; } - bcm_kfree(buff); + kfree(buff); return retval; } #endif @@ -313,7 +313,7 @@ static int bcm_buffer_readback(PMINI_ADAPTER Adapter, GFP_KERNEL); if(NULL == readbackbuff) { - bcm_kfree(buff); + kfree(buff); return -ENOMEM; } while (u32FirmwareLength && !retval) @@ -343,8 +343,8 @@ static int bcm_buffer_readback(PMINI_ADAPTER Adapter, u32FirmwareLength -= len; mappedbuffer +=len; }/* end of while (u32FirmwareLength && !retval) */ - bcm_kfree(buff); - bcm_kfree(readbackbuff); + kfree(buff); + kfree(readbackbuff); return retval; } #endif @@ -416,7 +416,7 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo) } } error: - bcm_kfree(buff); + kfree(buff); return retval; } @@ -479,7 +479,7 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter, u32FirmwareLength -= len; mappedbuffer +=len; }/* end of while (u32FirmwareLength && !retval) */ - bcm_kfree(readbackbuff); + kfree(readbackbuff); return retval; } diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index f810bfd0b1a5..014b06bfbc9f 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -55,7 +55,7 @@ VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) { if (psIntfAdapter->asUsbRcb[i].urb != NULL) { - bcm_kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer); + kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer); usb_free_urb(psIntfAdapter->asUsbRcb[i].urb); psIntfAdapter->asUsbRcb[i].urb = NULL; } diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c index 6fee9684f2ef..128aa91f7434 100644 --- a/drivers/staging/bcm/InterfaceRx.c +++ b/drivers/staging/bcm/InterfaceRx.c @@ -173,7 +173,7 @@ static void read_bulk_callback(struct urb *urb) else { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB..."); - bcm_kfree_skb(skb); + dev_kfree_skb(skb); } atomic_inc(&Adapter->GoodRxPktCount); for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++) diff --git a/drivers/staging/bcm/Makefile b/drivers/staging/bcm/Makefile index 6f6fcee8e4a9..0050206b0fc1 100644 --- a/drivers/staging/bcm/Makefile +++ b/drivers/staging/bcm/Makefile @@ -9,4 +9,4 @@ bcm_wimax-y := InterfaceDld.o InterfaceIdleMode.o InterfaceInit.o InterfaceRx.o Arp.o CmHost.o IPv6Protocol.o Qos.o Transmit.o\ Bcmnet.o DDRInit.o HandleControlPacket.o\ LeakyBucket.o Misc.o sort.o Bcmchar.o hostmibs.o PHSModule.o\ - Osal_Misc.o led_control.o nvm.o vendorspecificextn.o + led_control.o nvm.o vendorspecificextn.o diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 351a8aee88fe..a5ce9593dcff 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -132,24 +132,24 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) free_netdev(Adapter->dev); if(Adapter->pstargetparams != NULL) { - bcm_kfree(Adapter->pstargetparams); + kfree(Adapter->pstargetparams); } for (count =0;count < MAX_CNTRL_PKTS;count++) { if(Adapter->txctlpacket[count]) - bcm_kfree(Adapter->txctlpacket[count]); + kfree(Adapter->txctlpacket[count]); } FreeAdapterDsxBuffer(Adapter); if(Adapter->pvInterfaceAdapter) - bcm_kfree(Adapter->pvInterfaceAdapter); + kfree(Adapter->pvInterfaceAdapter); //Free the PHS Interface PhsCleanup(&Adapter->stBCMPhsContext); BcmDeAllocFlashCSStructure(Adapter); - bcm_kfree (Adapter); + kfree(Adapter); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "<========\n"); } @@ -259,25 +259,6 @@ exit_download: return errorno; } - -void bcm_kfree_skb(struct sk_buff *skb) -{ - if(skb) - { - kfree_skb(skb); - } - skb = NULL ; -} - -VOID bcm_kfree(VOID *ptr) -{ - if(ptr) - { - kfree(ptr); - } - ptr = NULL ; -} - /** @ingroup ctrl_pkt_functions This function copies the contents of given buffer @@ -579,7 +560,7 @@ __inline VOID LinkMessage(PMINI_ADAPTER Adapter) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Calling CopyBufferToControlPacket"); CopyBufferToControlPacket(Adapter, pstLinkRequest); - bcm_kfree(pstLinkRequest); + kfree(pstLinkRequest); } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "LinkMessage <====="); return; @@ -1292,14 +1273,14 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter) if((Adapter->pstargetparams = kmalloc(sizeof(STARGETPARAMS), GFP_KERNEL)) == NULL) { - bcm_kfree(buff); + kfree(buff); return -ENOMEM; } flp=open_firmware_file(Adapter, CFG_FILE); if(!flp) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "NOT ABLE TO OPEN THE %s FILE \n", CFG_FILE); - bcm_kfree(buff); - bcm_kfree(Adapter->pstargetparams); + kfree(buff); + kfree(Adapter->pstargetparams); Adapter->pstargetparams = NULL; return -ENOENT; } @@ -1310,8 +1291,8 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter) if(len != sizeof(STARGETPARAMS)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"Mismatch in Target Param Structure!\n"); - bcm_kfree(buff); - bcm_kfree(Adapter->pstargetparams); + kfree(buff); + kfree(Adapter->pstargetparams); Adapter->pstargetparams = NULL; filp_close(flp, current->files); return -ENOENT; @@ -1323,7 +1304,7 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter) * Values in Adapter->pstargetparams are in network byte order */ memcpy(Adapter->pstargetparams, buff, sizeof(STARGETPARAMS)); - bcm_kfree (buff); + kfree (buff); beceem_parse_target_struct(Adapter); return STATUS_SUCCESS; } @@ -1478,7 +1459,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress) if(status != STATUS_SUCCESS) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "wrm Failed..\n"); - bcm_kfree(pucmacaddr); + kfree(pucmacaddr); pucmacaddr = NULL; goto OUT; } @@ -1488,7 +1469,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress) if(status != STATUS_SUCCESS) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm Failed..\n"); - bcm_kfree(pucmacaddr); + kfree(pucmacaddr); pucmacaddr = NULL; goto OUT; } @@ -1522,7 +1503,7 @@ INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter) puMacAddr[4] == 0xFF && puMacAddr[5] == 0xFF)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Invalid Mac Address\n"); - bcm_kfree(puMacAddr); + kfree(puMacAddr); return STATUS_FAILURE; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "The Mac Address received is: \n"); @@ -1532,7 +1513,7 @@ INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%02x ", Adapter->dev->dev_addr[i]); } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"\n"); - bcm_kfree(puMacAddr); + kfree(puMacAddr); } return STATUS_SUCCESS; } @@ -1980,7 +1961,7 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex) Adapter->PackInfo[iQIndex].uiDroppedCountBytes += PacketToDrop->len; Adapter->PackInfo[iQIndex].uiDroppedCountPackets++; - bcm_kfree_skb(PacketToDrop); + dev_kfree_skb(PacketToDrop); atomic_dec(&Adapter->TotalPacketCount); atomic_inc(&Adapter->TxDroppedPacketCount); diff --git a/drivers/staging/bcm/Osal_Misc.c b/drivers/staging/bcm/Osal_Misc.c deleted file mode 100644 index feefd20a5291..000000000000 --- a/drivers/staging/bcm/Osal_Misc.c +++ /dev/null @@ -1,27 +0,0 @@ - /*++ - - Copyright (c) Beceem Communications Inc. - - Module Name: - WIN_Misc.c - - Abstract: - Implements the Miscelanneous OS Construts - Linked Lists - Dispatcher Objects(Events,Semaphores,Spin Locks and the like) - Files - - Revision History: - Who When What - -------- -------- ---------------------------------------------- - Name Date Created/reviewed/modified - Rajeev 24/1/08 Created - Notes: - - --*/ -#include "headers.h" - -bool OsalMemCompare(void *dest, void *src, UINT len) -{ - return (memcmp(src, dest, len)); -} diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c index 8a38cf43e795..e0456b291d6c 100644 --- a/drivers/staging/bcm/PHSModule.c +++ b/drivers/staging/bcm/PHSModule.c @@ -120,15 +120,15 @@ int PHSTransmit(PMINI_ADAPTER Adapter, if(newPacket == NULL) return STATUS_FAILURE; - bcm_kfree_skb(Packet); + dev_kfree_skb(Packet); *pPacket = Packet = newPacket; pucPHSPktHdrInBuf = Packet->data + BytesToRemove; } numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen+PHSI_LEN); - OsalMemMove(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN); - OsalMemMove(Packet->data + numBytesCompressed, Packet->data, BytesToRemove); + memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN); + memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove); skb_pull(Packet, numBytesCompressed); return STATUS_SUCCESS; @@ -223,7 +223,7 @@ int PHSRecieve(PMINI_ADAPTER Adapter, } } - OsalMemMove(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen); + memcpy(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen); } return STATUS_SUCCESS; @@ -270,15 +270,9 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter) return -EINVAL; pPhsdeviceExtension->pstServiceFlowPhsRulesTable = - (S_SERVICEFLOW_TABLE*)OsalMemAlloc(sizeof(S_SERVICEFLOW_TABLE), - PHS_MEM_TAG); + kzalloc(sizeof(S_SERVICEFLOW_TABLE), GFP_KERNEL); - if(pPhsdeviceExtension->pstServiceFlowPhsRulesTable) - { - OsalZeroMemory(pPhsdeviceExtension->pstServiceFlowPhsRulesTable, - sizeof(S_SERVICEFLOW_TABLE)); - } - else + if(!pPhsdeviceExtension->pstServiceFlowPhsRulesTable) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed"); return -ENOMEM; @@ -288,14 +282,8 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter) for(i=0;istSFList[i]; - sServiceFlow.pstClassifierTable = (S_CLASSIFIER_TABLE*)OsalMemAlloc( - sizeof(S_CLASSIFIER_TABLE), PHS_MEM_TAG); - if(sServiceFlow.pstClassifierTable) - { - OsalZeroMemory(sServiceFlow.pstClassifierTable,sizeof(S_CLASSIFIER_TABLE)); - pstServiceFlowTable->stSFList[i].pstClassifierTable = sServiceFlow.pstClassifierTable; - } - else + sServiceFlow.pstClassifierTable = kzalloc(sizeof(S_CLASSIFIER_TABLE), GFP_KERNEL); + if(!sServiceFlow.pstClassifierTable) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed"); free_phs_serviceflow_rules(pPhsdeviceExtension-> @@ -305,9 +293,7 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter) } } - - pPhsdeviceExtension->CompressedTxBuffer = - OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG); + pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL); if(pPhsdeviceExtension->CompressedTxBuffer == NULL) { @@ -317,12 +303,11 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter) return -ENOMEM; } - pPhsdeviceExtension->UnCompressedRxBuffer = - OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG); + pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL); if(pPhsdeviceExtension->UnCompressedRxBuffer == NULL) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed"); - OsalMemFree(pPhsdeviceExtension->CompressedTxBuffer,PHS_BUFFER_SIZE); + kfree(pPhsdeviceExtension->CompressedTxBuffer); free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable); pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL; return -ENOMEM; @@ -343,16 +328,11 @@ int PhsCleanup(IN PPHS_DEVICE_EXTENSION pPHSDeviceExt) pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL; } - if(pPHSDeviceExt->CompressedTxBuffer) - { - OsalMemFree(pPHSDeviceExt->CompressedTxBuffer,PHS_BUFFER_SIZE); - pPHSDeviceExt->CompressedTxBuffer = NULL; - } - if(pPHSDeviceExt->UnCompressedRxBuffer) - { - OsalMemFree(pPHSDeviceExt->UnCompressedRxBuffer,PHS_BUFFER_SIZE); - pPHSDeviceExt->UnCompressedRxBuffer = NULL; - } + kfree(pPHSDeviceExt->CompressedTxBuffer); + pPHSDeviceExt->CompressedTxBuffer = NULL; + + kfree(pPHSDeviceExt->UnCompressedRxBuffer); + pPHSDeviceExt->UnCompressedRxBuffer = NULL; return 0; } @@ -478,20 +458,12 @@ ULONG PhsDeletePHSRule(IN void* pvContext,IN B_UINT16 uiVcid,IN B_UINT8 u8PHSI) { if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) { - if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex] - .pstPhsRule->u8PHSI == u8PHSI) - { - if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule - ->u8RefCnt) - pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule - ->u8RefCnt--; - if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex] - .pstPhsRule->u8RefCnt) - OsalMemFree(pstClassifierRulesTable - ->stActivePhsRulesList[nClsidIndex].pstPhsRule, - sizeof(S_PHS_RULE)); - OsalZeroMemory(&pstClassifierRulesTable - ->stActivePhsRulesList[nClsidIndex], + if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) { + if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--; + if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule); + memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY)); } } @@ -548,10 +520,10 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16 if(pstClassifierEntry->pstPhsRule->u8RefCnt) pstClassifierEntry->pstPhsRule->u8RefCnt--; if(0==pstClassifierEntry->pstPhsRule->u8RefCnt) - OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE)); + kfree(pstClassifierEntry->pstPhsRule); } - OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY)); + memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY)); } nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable, @@ -559,10 +531,8 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16 if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) { - if(pstClassifierEntry->pstPhsRule) - //Delete the classifier entry - OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE)); - OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY)); + kfree(pstClassifierEntry->pstPhsRule); + memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY)); } } return lStatus; @@ -619,14 +589,11 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid) .pstPhsRule->u8RefCnt--; if(0==pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex] .pstPhsRule->u8RefCnt) - OsalMemFree(pstClassifierRulesTable - ->stActivePhsRulesList[nClsidIndex].pstPhsRule, - sizeof(S_PHS_RULE)); + kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule); pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex] .pstPhsRule = NULL; } - OsalZeroMemory(&pstClassifierRulesTable - ->stActivePhsRulesList[nClsidIndex],sizeof(S_CLASSIFIER_ENTRY)); + memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY)); if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule) { if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex] @@ -635,15 +602,12 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid) .pstPhsRule->u8RefCnt--; if(0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex] .pstPhsRule->u8RefCnt) - OsalMemFree(pstClassifierRulesTable - ->stOldPhsRulesList[nClsidIndex].pstPhsRule, - sizeof(S_PHS_RULE)); + kfree(pstClassifierRulesTable + ->stOldPhsRulesList[nClsidIndex].pstPhsRule); pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex] .pstPhsRule = NULL; } - OsalZeroMemory(&pstClassifierRulesTable - ->stOldPhsRulesList[nClsidIndex], - sizeof(S_CLASSIFIER_ENTRY)); + memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY)); } } pstServiceFlowEntry->bUsed = FALSE; @@ -876,8 +840,7 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable) ->u8RefCnt--; if(0==pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule ->u8RefCnt) - OsalMemFree(pstClassifierRulesTable->stActivePhsRulesList[j]. - pstPhsRule, sizeof(S_PHS_RULE)); + kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule); pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL; } if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule) @@ -888,19 +851,18 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable) ->u8RefCnt--; if(0==pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule ->u8RefCnt) - OsalMemFree(pstClassifierRulesTable->stOldPhsRulesList[j] - .pstPhsRule,sizeof(S_PHS_RULE)); + kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule); pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL; } } - OsalMemFree(pstClassifierRulesTable,sizeof(S_CLASSIFIER_TABLE)); + kfree(pstClassifierRulesTable); stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL; } } } - OsalMemFree(psServiceFlowRulesTable,sizeof(S_SERVICEFLOW_TABLE)); - psServiceFlowRulesTable = NULL; + kfree(psServiceFlowRulesTable); + psServiceFlowRulesTable = NULL; } @@ -1102,7 +1064,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid, if(psPhsRule->u8PHSFLength) { //update PHSF - OsalMemMove(pstClassifierEntry->pstPhsRule->u8PHSF, + memcpy(pstClassifierEntry->pstPhsRule->u8PHSF, psPhsRule->u8PHSF , MAX_PHS_LENGTHS); } if(psPhsRule->u8PHSFLength) @@ -1114,7 +1076,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid, if(psPhsRule->u8PHSMLength) { //update PHSM - OsalMemMove(pstClassifierEntry->pstPhsRule->u8PHSM, + memcpy(pstClassifierEntry->pstPhsRule->u8PHSM, psPhsRule->u8PHSM, MAX_PHS_LENGTHS); } if(psPhsRule->u8PHSMLength) @@ -1234,8 +1196,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId, { if(psClassifierRules->pstPhsRule == NULL) { - psClassifierRules->pstPhsRule = (S_PHS_RULE*)OsalMemAlloc - (sizeof(S_PHS_RULE),PHS_MEM_TAG); + psClassifierRules->pstPhsRule = kmalloc(sizeof(S_PHS_RULE),GFP_KERNEL); if(NULL == psClassifierRules->pstPhsRule) return ERR_PHSRULE_MEMALLOC_FAIL; @@ -1247,7 +1208,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId, psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule; /* Update The PHS rule */ - OsalMemMove(psClassifierRules->pstPhsRule, + memcpy(psClassifierRules->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE)); } else @@ -1289,13 +1250,13 @@ UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, //Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId if(FALSE == bPHSRuleOrphaned) { - pstClassifierEntry->pstPhsRule = (S_PHS_RULE*)OsalMemAlloc(sizeof(S_PHS_RULE),PHS_MEM_TAG); + pstClassifierEntry->pstPhsRule = kmalloc(sizeof(S_PHS_RULE), GFP_KERNEL); if(NULL == pstClassifierEntry->pstPhsRule) { return ERR_PHSRULE_MEMALLOC_FAIL; } } - OsalMemMove(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE)); + memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE)); } else @@ -1304,14 +1265,8 @@ UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule"); if(bPHSRuleOrphaned) { - if(pstClassifierEntry->pstPhsRule) - { - //Just Free the PHS Rule as Ref Count is Zero - OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE)); + kfree(pstClassifierEntry->pstPhsRule); pstClassifierEntry->pstPhsRule = NULL; - - } - } pstClassifierEntry->pstPhsRule = pstAddPhsRule; diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index 82738be3ed48..286ea46cd996 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -11,10 +11,6 @@ VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer); VOID IdleModeResponse(PMINI_ADAPTER Adapter,PUINT puiBuffer); -void bcm_kfree_skb(struct sk_buff *skb); -VOID bcm_kfree(VOID *ptr); - - VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**PackInfo[iIndex].uiDroppedCountBytes += PacketToDrop->len; Adapter->PackInfo[iIndex].uiDroppedCountPackets++; - bcm_kfree_skb(PacketToDrop); + dev_kfree_skb(PacketToDrop); } @@ -455,7 +455,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) Adapter->PackInfo[iQIndex].LastTxQueue); /* Free the skb */ - bcm_kfree_skb(PacketToDrop); + dev_kfree_skb(PacketToDrop); /// update current bytes and packets count Adapter->PackInfo[iQIndex].uiCurrentBytesOnHost -= uiTotalPacketLength; diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 9848a6a95fb7..9932d71a6fe0 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -117,7 +117,7 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Invalid queue index, dropping pkt\n"); - bcm_kfree_skb(skb); + dev_kfree_skb(skb); } return STATUS_SUCCESS; } @@ -125,7 +125,7 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */ if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) { atomic_inc(&Adapter->TxDroppedPacketCount); - bcm_kfree_skb(skb); + dev_kfree_skb(skb); return STATUS_SUCCESS; } @@ -159,7 +159,7 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<===="); } else - bcm_kfree_skb(skb); + dev_kfree_skb(skb); return STATUS_SUCCESS; } @@ -333,7 +333,7 @@ errExit: } - bcm_kfree_skb(Packet); + dev_kfree_skb(Packet); return status; } diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index b90d8a3e879b..d4a200329bab 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -58,7 +58,6 @@ #include "Debug.h" #include "HostMibs.h" #include "IPv6ProtocolHdr.h" -#include "osal_misc.h" #include "PHSModule.h" #include "Protocol.h" #include "Prototypes.h" diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index e9da513b3c24..0d75ff7add75 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -54,7 +54,7 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, { if(Adapter->PackInfo[nSfIndex].bValid) { - OsalMemMove((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE)); + memcpy((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE)); } else { @@ -83,7 +83,7 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, pstHostMibs->astPhsRulesTable[nPhsTableIndex].ulSFID = Adapter->PackInfo[nSfIndex].ulSFID; - OsalMemMove(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI, + memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI, &pstPhsRule->u8PHSI, sizeof(S_PHS_RULE)); nPhsTableIndex++; diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c index f2b6939f5178..79c7bd74804d 100644 --- a/drivers/staging/bcm/led_control.c +++ b/drivers/staging/bcm/led_control.c @@ -293,7 +293,7 @@ static INT ValidateDSDParamsChecksum( BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X",ulParamOffset, usParamLen); - puBuffer = OsalMemAlloc(usParamLen,"!MEM"); + puBuffer = kmalloc(usParamLen, GFP_KERNEL); if(!puBuffer) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum Allocation failed"); @@ -341,10 +341,7 @@ static INT ValidateDSDParamsChecksum( } exit: - if(puBuffer) - { - OsalMemFree(puBuffer, usParamLen); - } + kfree(puBuffer); return Status; } diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index 95716f596e6c..4a0205334749 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -228,7 +228,7 @@ INT ReadBeceemEEPROM( PMINI_ADAPTER Adapter, ReadBeceemEEPROMBulk(Adapter, uiTempOffset + MAX_RW_SIZE, (PUINT)&uiData[4], 4); } - OsalMemMove( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4); + memcpy( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4); return STATUS_SUCCESS; } /* ReadBeceemEEPROM() */ @@ -476,7 +476,7 @@ INT BeceemEEPROMBulkRead( ReadBeceemEEPROMBulk(Adapter,uiTempOffset,(PUINT)&uiData[0],4); if(uiBytesRemaining >= (MAX_RW_SIZE - uiExtraBytes)) { - OsalMemMove(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes); + memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes); uiBytesRemaining -= (MAX_RW_SIZE - uiExtraBytes); uiIndex += (MAX_RW_SIZE - uiExtraBytes); @@ -484,7 +484,7 @@ INT BeceemEEPROMBulkRead( } else { - OsalMemMove(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining); + memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining); uiIndex += uiBytesRemaining; uiOffset += uiBytesRemaining; uiBytesRemaining = 0; @@ -508,7 +508,7 @@ INT BeceemEEPROMBulkRead( * We read 4 Dwords of data */ if(0 == ReadBeceemEEPROMBulk(Adapter,uiOffset,&uiData[0],4)) { - OsalMemMove(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE); + memcpy(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE); uiOffset += MAX_RW_SIZE; uiBytesRemaining -= MAX_RW_SIZE; uiIndex += MAX_RW_SIZE; @@ -523,7 +523,7 @@ INT BeceemEEPROMBulkRead( { if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0])) { - OsalMemMove(pcBuff+uiIndex,&uiData[0],4); + memcpy(pcBuff+uiIndex,&uiData[0],4); uiOffset += 4; uiBytesRemaining -= 4; uiIndex +=4; @@ -540,7 +540,7 @@ INT BeceemEEPROMBulkRead( pCharBuff += uiIndex; if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0])) { - OsalMemMove(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested. + memcpy(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested. uiBytesRemaining = 0; } else @@ -973,7 +973,7 @@ static INT flashWrite( // need not write 0xFFFFFFFF because write requires an erase and erase will // make whole sector 0xFFFFFFFF. // - if (!OsalMemCompare(pData, uiErasePattern, MAX_RW_SIZE)) + if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE)) { return 0; } @@ -1138,7 +1138,7 @@ static INT flashWriteStatus( // need not write 0xFFFFFFFF because write requires an erase and erase will // make whole sector 0xFFFFFFFF. // - if (!OsalMemCompare(pData,uiErasePattern,MAX_RW_SIZE)) + if (!memcmp(pData,uiErasePattern,MAX_RW_SIZE)) { return 0; } @@ -1377,12 +1377,9 @@ INT BeceemFlashBulkWrite( uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1); uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize; - //pTempBuff = OsalMemAlloc(MAX_SECTOR_SIZE,'!MVN'); - pTempBuff = OsalMemAlloc(Adapter->uiSectorSize ,"!MVN"); + pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL); if(NULL == pTempBuff) - { goto BeceemFlashBulkWrite_EXIT; - } // // check if the data to be written is overlapped accross sectors // @@ -1448,13 +1445,13 @@ INT BeceemFlashBulkWrite( if(uiNumSectTobeRead > 1) { - OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)); + memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)); pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr))); uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)); } else { - OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes); + memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes); } if(IsFlash2x(Adapter)) @@ -1503,7 +1500,7 @@ INT BeceemFlashBulkWrite( } else { - if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE)) + if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE)) { if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex,&pTempBuff[uiIndex])) { @@ -1541,10 +1538,8 @@ BeceemFlashBulkWrite_EXIT: { BcmRestoreBlockProtectStatus(Adapter,ulStatus); } - if(pTempBuff) - { - OsalMemFree(pTempBuff,Adapter->uiSectorSize); - } + + kfree(pTempBuff); Adapter->SelectedChip = RESET_CHIP_SELECT; return Status; @@ -1599,14 +1594,10 @@ static INT BeceemFlashBulkWriteStatus( uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1); uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize; - - -// pTempBuff = OsalMemAlloc(MAX_SECTOR_SIZE,'!MVN'); - pTempBuff = OsalMemAlloc(Adapter->uiSectorSize,"!MVN"); + pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL); if(NULL == pTempBuff) - { goto BeceemFlashBulkWriteStatus_EXIT; - } + // // check if the data to be written is overlapped accross sectors // @@ -1662,13 +1653,13 @@ static INT BeceemFlashBulkWriteStatus( if(uiNumSectTobeRead > 1) { - OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)); + memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)); pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr))); uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)); } else { - OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes); + memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes); } if(IsFlash2x(Adapter)) @@ -1716,7 +1707,7 @@ static INT BeceemFlashBulkWriteStatus( if(STATUS_SUCCESS == BeceemFlashBulkRead(Adapter,(PUINT)ucReadBk,uiOffsetFromSectStart+uiIndex,MAX_RW_SIZE)) { - if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE)) + if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE)) { Status = STATUS_FAILURE; goto BeceemFlashBulkWriteStatus_EXIT; @@ -1747,10 +1738,8 @@ BeceemFlashBulkWriteStatus_EXIT: { BcmRestoreBlockProtectStatus(Adapter,ulStatus); } - if(pTempBuff) - { - OsalMemFree(pTempBuff,Adapter->uiSectorSize); - } + + kfree(pTempBuff); Adapter->SelectedChip = RESET_CHIP_SELECT; return Status; @@ -1771,7 +1760,7 @@ BeceemFlashBulkWriteStatus_EXIT: INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter) { - PCHAR pBuff = OsalMemAlloc(BUFFER_4K,"3MVN"); + PCHAR pBuff = kmalloc(BUFFER_4K, GFP_KERNEL); UINT uiEepromSize = 0; UINT uiIndex = 0; UINT uiBytesToCopy = 0; @@ -1787,14 +1776,14 @@ INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter) if(0 != BeceemEEPROMBulkRead(Adapter,&uiEepromSize,EEPROM_SIZE_OFFSET,4)) { - OsalMemFree(pBuff,BUFFER_4K); + kfree(pBuff); return -1; } uiEepromSize >>= 16; if(uiEepromSize > 1024*1024) { - OsalMemFree(pBuff,BUFFER_4K); + kfree(pBuff); return -1; } @@ -1820,7 +1809,7 @@ INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter) wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-4,&value, sizeof(value)); value = 0xbeadbead; wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-8,&value, sizeof(value)); - OsalMemFree(pBuff,MAX_RW_SIZE); + kfree(pBuff); return Status; @@ -1873,7 +1862,7 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter) return -1; } - pBuff = OsalMemAlloc(uiEepromSize, 0); + pBuff = kmalloc(uiEepromSize, GFP_KERNEL); if ( pBuff == NULL ) { @@ -1882,7 +1871,7 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter) if(0 != BeceemNVMRead(Adapter,(PUINT)pBuff,uiCalStartAddr, uiEepromSize)) { - OsalMemFree(pBuff, 0); + kfree(pBuff); return -1; } @@ -1905,7 +1894,7 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter) uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize); } - OsalMemFree(pBuff, 0); + kfree(pBuff); return Status; } @@ -1947,14 +1936,14 @@ static INT BeceemEEPROMReadBackandVerify( {// for the requests more than or equal to MAX_RW_SIZE bytes, use bulk read function to make the access faster. BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE); - if(OsalMemCompare(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE)) + if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE)) { // re-write BeceemEEPROMBulkWrite(Adapter,(PUCHAR)(pBuffer+uiIndex),uiOffset,MAX_RW_SIZE,FALSE); mdelay(3); BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE); - if(OsalMemCompare(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE)) + if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE)) { return -1; } @@ -1986,7 +1975,7 @@ static INT BeceemEEPROMReadBackandVerify( else { // Handle the reads less than 4 bytes... uiData = 0; - OsalMemMove(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes); + memcpy(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes); BeceemEEPROMBulkRead(Adapter,&uiRdbk,uiOffset,4); if(memcmp(&uiData, &uiRdbk, uiNumBytes)) @@ -2186,7 +2175,7 @@ INT BeceemEEPROMBulkWrite( if(uiBytesToCopy >= (16 -uiExtraBytes)) { - OsalMemMove((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes); + memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes); if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) ) return STATUS_FAILURE; @@ -2197,7 +2186,7 @@ INT BeceemEEPROMBulkWrite( } else { - OsalMemMove((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy); + memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy); if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) ) return STATUS_FAILURE; @@ -2233,7 +2222,7 @@ INT BeceemEEPROMBulkWrite( // To program non 16byte aligned data, read 16byte and then update. // BeceemEEPROMBulkRead(Adapter,&uiData[0],uiOffset,16); - OsalMemMove(&uiData[0],pBuffer+uiIndex,uiBytesToCopy); + memcpy(&uiData[0],pBuffer+uiIndex,uiBytesToCopy); if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiOffset ) ) @@ -2763,7 +2752,7 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter) if(psAdapter->psFlash2xCSInfo == NULL) { BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate memory for Flash 2.x"); - bcm_kfree(psAdapter->psFlashCSInfo); + kfree(psAdapter->psFlashCSInfo); return -ENOMEM; } @@ -2771,8 +2760,8 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter) if(psAdapter->psFlash2xVendorInfo == NULL) { BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate Vendor Info Memory for Flash 2.x"); - bcm_kfree(psAdapter->psFlashCSInfo); - bcm_kfree(psAdapter->psFlash2xCSInfo); + kfree(psAdapter->psFlashCSInfo); + kfree(psAdapter->psFlash2xCSInfo); return -ENOMEM; } @@ -2786,9 +2775,9 @@ INT BcmDeAllocFlashCSStructure(PMINI_ADAPTER psAdapter) BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0," Adapter structure point is NULL"); return -EINVAL; } - bcm_kfree(psAdapter->psFlashCSInfo); - bcm_kfree(psAdapter->psFlash2xCSInfo); - bcm_kfree(psAdapter->psFlash2xVendorInfo); + kfree(psAdapter->psFlashCSInfo); + kfree(psAdapter->psFlash2xCSInfo); + kfree(psAdapter->psFlash2xVendorInfo); return STATUS_SUCCESS ; } @@ -4570,7 +4559,7 @@ INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut) } - bcm_kfree(Buff); + kfree(Buff); return Status; } @@ -4936,7 +4925,7 @@ INT BcmCopySection(PMINI_ADAPTER Adapter, BytesToBeCopied = numOfBytes; } }while(numOfBytes > 0) ; - bcm_kfree(pBuff); + kfree(pBuff); Adapter->bHeaderChangeAllowed = FALSE ; return Status; } @@ -5006,7 +4995,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset) //Replace Buffer content with Header memcpy(pBuff +offsetToProtect,pTempBuff,HeaderSizeToProtect); - bcm_kfree(pTempBuff); + kfree(pTempBuff); } if(bHasHeader && Adapter->bSigCorrupted) { @@ -5525,11 +5514,11 @@ INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) else { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header"); - bcm_kfree(pBuff); + kfree(pBuff); return STATUS_FAILURE; } - bcm_kfree(pBuff); + kfree(pBuff); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature"); return STATUS_SUCCESS ; } @@ -5575,14 +5564,14 @@ INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) else { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header"); - bcm_kfree(pBuff); + kfree(pBuff); return STATUS_FAILURE; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature"); BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,pBuff,MAX_RW_SIZE); - bcm_kfree(pBuff); + kfree(pBuff); return STATUS_SUCCESS ; } diff --git a/drivers/staging/bcm/osal_misc.h b/drivers/staging/bcm/osal_misc.h deleted file mode 100644 index ff4adde17cd8..000000000000 --- a/drivers/staging/bcm/osal_misc.h +++ /dev/null @@ -1,49 +0,0 @@ - /*++ - - Copyright (c) Beceem Communications Inc. - - Module Name: - OSAL_Misc.h - - Abstract: - Provides the OS Abstracted macros to access: - Linked Lists - Dispatcher Objects(Events,Semaphores,Spin Locks and the like) - Files - - - Revision History: - Who When What - -------- -------- ---------------------------------------------- - Name Date Created/reviewed/modified - Rajeev 24/1/08 Created - Notes: - - --*/ -#ifndef _OSAL_MISC_H_ -#define _OSAL_MISC_H_ -//OSAL Macros -//OSAL Primitives -typedef PUCHAR POSAL_NW_PACKET ; //Nw packets - - -#define OsalMemAlloc(n,t) kmalloc(n,GFP_KERNEL) - -#define OsalMemFree(x,n) bcm_kfree(x) - -#define OsalMemMove(dest, src, len) \ -{ \ - memcpy(dest,src, len); \ -} - -#define OsalZeroMemory(pDest, Len) \ -{ \ - memset(pDest,0,Len); \ -} - -//#define OsalMemSet(pSrc,Char,Len) memset(pSrc,Char,Len) - -bool OsalMemCompare(void *dest, void *src, UINT len); - -#endif - -- cgit v1.2.3 From de85f9858969f50467bf39ee992ef871ae2492d3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 17:02:39 -0700 Subject: beceem: name threads with device name This is the convention used by Intel Wimax Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Misc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index a5ce9593dcff..eca75dbffe35 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -156,10 +156,12 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) int create_worker_threads(PMINI_ADAPTER psAdapter) { + const char *name = psAdapter->dev->name; + BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Init Threads..."); // Rx Control Packets Processing psAdapter->control_packet_handler = kthread_run((int (*)(void *)) - control_packet_handler, psAdapter, "CtrlPktHdlr"); + control_packet_handler, psAdapter, "%s-rx", name); if(IS_ERR(psAdapter->control_packet_handler)) { BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success\n"); @@ -167,7 +169,7 @@ int create_worker_threads(PMINI_ADAPTER psAdapter) } // Tx Thread psAdapter->transmit_packet_thread = kthread_run((int (*)(void *)) - tx_pkt_handler, psAdapter, "TxPktThread"); + tx_pkt_handler, psAdapter, "%s-tx", name); if(IS_ERR (psAdapter->transmit_packet_thread)) { BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success"); -- cgit v1.2.3 From 71e253b1699fb777be68cb1028a90e21ea6ff8d8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 09:49:30 -0400 Subject: beceem: make transmit thread interruptible Kernel complains loudly if thread does long uninterruptible sleep. Also, dont wake up every 10ms even if no data present (wastes power). Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Transmit.c | 195 +++++++++++++---------------------------- 1 file changed, 61 insertions(+), 134 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 9932d71a6fe0..1f69625f241e 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -39,7 +39,7 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53 * Function - bcm_transmit() * * Description - This is the main transmit function for our virtual -* interface(veth0). It handles the ARP packets. It +* interface(eth0). It handles the ARP packets. It * clones this packet and then Queue it to a suitable * Queue. Then calls the transmit_packet(). * @@ -50,118 +50,59 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53 * *********************************************************************/ -INT bcm_transmit(struct sk_buff *skb, /**< skb */ - struct net_device *dev /**< net device pointer */ - ) +netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) { - PMINI_ADAPTER Adapter = NULL; - USHORT qindex=0; - struct timeval tv; - UINT pkt_type = 0; - UINT calltransmit = 0; - - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + SHORT qindex; - memset(&tv, 0, sizeof(tv)); - /* Check for valid parameters */ - if(skb == NULL || dev==NULL) - { - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n"); - return -EINVAL; - } - - Adapter = GET_BCM_ADAPTER(dev); - if(!Adapter) - { - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n"); - return -EINVAL; - } - if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus) - { - if(!netif_queue_stopped(dev)) { - netif_carrier_off(dev); - netif_stop_queue(dev); - } - return STATUS_FAILURE; - } - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len); + if (Adapter->device_removed || !Adapter->LinkUpStatus) + goto drop; - /*Add Ethernet CS check here*/ - if(Adapter->TransferMode == IP_PACKET_ONLY_MODE ) - { - pkt_type = ntohs(*(PUSHORT)(skb->data + 12)); - /* Get the queue index where the packet is to be queued */ - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index....."); + if (Adapter->TransferMode != IP_PACKET_ONLY_MODE ) + goto drop; - qindex = GetPacketQueueIndex(Adapter,skb); + qindex = GetPacketQueueIndex(Adapter, skb); - if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex) - { - if(pkt_type == ETH_ARP_FRAME) - { - /* - Reply directly to ARP request packet - ARP Spoofing only if NO ETH CS rule matches for it - */ - BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x", + if (INVALID_QUEUE_INDEX==qindex) { + if (ntohs(eth_hdr(skb)->h_proto) != ETH_ARP_FRAME) + goto drop; - (*(PUCHAR)(skb->data + 21))); + /* + Reply directly to ARP request packet + ARP Spoofing only if NO ETH CS rule matches for it + */ + reply_to_arp_request(skb); + return NETDEV_TX_OK; + } - reply_to_arp_request(skb); + if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) + return NETDEV_TX_BUSY; - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n"); + /* Now Enqueue the packet */ + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, + "bcm_transmit Enqueueing the Packet To Queue %d",qindex); + spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); + Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; + Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; - } - else - { - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, - "Invalid queue index, dropping pkt\n"); + *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies; + ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, + Adapter->PackInfo[qindex].LastTxQueue, skb); + atomic_inc(&Adapter->TotalPacketCount); + spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); - dev_kfree_skb(skb); - } - return STATUS_SUCCESS; - } + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n"); - if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) - { - atomic_inc(&Adapter->TxDroppedPacketCount); - dev_kfree_skb(skb); - return STATUS_SUCCESS; - } - - /* Now Enqueue the packet */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex); - spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); - Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; - Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; - - *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies; - ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, - Adapter->PackInfo[qindex].LastTxQueue, skb); - atomic_inc(&Adapter->TotalPacketCount); - spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); - do_gettimeofday(&tv); - - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n"); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n", - (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec); - - if(calltransmit == 1) - transmit_packets(Adapter); - else - { - if(!atomic_read(&Adapter->TxPktAvail)) - { - atomic_set(&Adapter->TxPktAvail, 1); - wake_up(&Adapter->tx_packet_wait_queue); - } - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<===="); + /* FIXME - this is racy and incorrect, replace with work queue */ + if (!atomic_read(&Adapter->TxPktAvail)) { + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); } - else - dev_kfree_skb(skb); + return NETDEV_TX_OK; - return STATUS_SUCCESS; + drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; } @@ -337,6 +278,13 @@ errExit: return status; } +static int tx_pending(PMINI_ADAPTER Adapter) +{ + return (atomic_read(&Adapter->TxPktAvail) + && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc)) + || Adapter->device_removed || (1 == Adapter->downloadDDR); +} + /** @ingroup tx_functions Transmit thread @@ -346,40 +294,17 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ { int status = 0; - UINT calltransmit = 1; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Entring to wait for signal from the interrupt service thread!Adapter = %p",Adapter); - - - while(1) - { - if(Adapter->LinkUpStatus){ + while(! kthread_should_stop()) { + /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */ + if(Adapter->LinkUpStatus) wait_event_timeout(Adapter->tx_packet_wait_queue, - ((atomic_read(&Adapter->TxPktAvail) && - (MINIMUM_PENDING_DESCRIPTORS < - atomic_read(&Adapter->CurrNumFreeTxDesc)) && - (Adapter->device_removed == FALSE))) || - (1 == Adapter->downloadDDR) || kthread_should_stop() - || (TRUE == Adapter->bEndPointHalted) - , msecs_to_jiffies(10)); - } - else{ - wait_event(Adapter->tx_packet_wait_queue, - ((atomic_read(&Adapter->TxPktAvail) && - (MINIMUM_PENDING_DESCRIPTORS < - atomic_read(&Adapter->CurrNumFreeTxDesc)) && - (Adapter->device_removed == FALSE))) || - (1 == Adapter->downloadDDR) || kthread_should_stop() - || (TRUE == Adapter->bEndPointHalted) - ); - } - - if(kthread_should_stop() || Adapter->device_removed) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n"); - Adapter->transmit_packet_thread = NULL; - return 0; - } + tx_pending(Adapter), msecs_to_jiffies(10)); + else + wait_event_interruptible(Adapter->tx_packet_wait_queue, + tx_pending(Adapter)); + if (Adapter->device_removed) + break; if(Adapter->downloadDDR == 1) { @@ -424,11 +349,13 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ } - if(calltransmit) - transmit_packets(Adapter); + transmit_packets(Adapter); atomic_set(&Adapter->TxPktAvail, 0); } + + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n"); + Adapter->transmit_packet_thread = NULL; return 0; } -- cgit v1.2.3 From d21d6dde0280f0897ce6de1948bfaa5633867b28 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 17:12:37 -0700 Subject: beceem: add ethtool support This adds basic ethtool support to get driver info and settings Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 47 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index b4e729b57e67..f0549912c9ec 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -1,7 +1,8 @@ #include "headers.h" -#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver" +#define DRV_NAME "beceem" #define DRV_VERSION "5.2.7.3P1" +#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver" #define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc" @@ -79,6 +80,49 @@ static struct device_type wimax_type = { .name = "wimax", }; +static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void bcm_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + PS_INTERFACE_ADAPTER psIntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u", + Adapter->uiFlashLayoutMajorVersion, + Adapter->uiFlashLayoutMinorVersion); + + usb_make_path(udev, info->bus_info, sizeof(info->bus_info)); +} + +static u32 bcm_get_link(struct net_device *dev) +{ + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + + return Adapter->LinkUpStatus; +} + +static const struct ethtool_ops bcm_ethtool_ops = { + .get_settings = bcm_get_settings, + .get_drvinfo = bcm_get_drvinfo, + .get_link = bcm_get_link, +}; + int register_networkdev(PMINI_ADAPTER Adapter) { struct net_device *net; @@ -98,6 +142,7 @@ int register_networkdev(PMINI_ADAPTER Adapter) *temp = Adapter; net->netdev_ops = &bcmNetDevOps; + net->ethtool_ops = &bcm_ethtool_ops; net->mtu = MTU_SIZE; /* 1400 Bytes */ SET_NETDEV_DEV(net, &uintf->dev); -- cgit v1.2.3 From 9c6e9aa830071a442fb72ab05c15e2b2609636e3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 17:13:52 -0700 Subject: beceem: remove dead code Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/InterfaceTx.c | 44 --------------------------------------- drivers/staging/bcm/InterfaceTx.h | 6 ------ 2 files changed, 50 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c index 826ed93c9b56..e51db83d629e 100644 --- a/drivers/staging/bcm/InterfaceTx.c +++ b/drivers/staging/bcm/InterfaceTx.c @@ -1,49 +1,5 @@ #include "headers.h" - -/* -Function: InterfaceTxDataPacket - -Description: This is the hardware specific Function for Transmitting - data packet to the device. - -Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context - PVOID Packet - Packet Containing the data to be transmitted - USHORT usVcid - VCID on which data packet is to be sent - - -Return: BCM_STATUS_SUCCESS - If Tx was successful. - Other - If an error occured. -*/ - -ULONG InterfaceTxDataPacket(PMINI_ADAPTER Adapter,PVOID Packet,USHORT usVcid) -{ - ULONG Status = 0; - return Status; -} - -/* -Function: InterfaceTxControlPacket - -Description: This is the hardware specific Function for Transmitting - control packet to the device. - -Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context - PVOID pvBuffer - Buffer containg control packet - UINT uiBufferLength - Buffer Length - -Return: BCM_STATUS_SUCCESS - If control packet transmit was successful. - Other - If an error occured. -*/ - -ULONG InterfaceTxControlPacket(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT uiBufferLength) -{ - ULONG Status = 0; - - - - return Status; -} /*this is transmit call-back(BULK OUT)*/ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) { diff --git a/drivers/staging/bcm/InterfaceTx.h b/drivers/staging/bcm/InterfaceTx.h index 053f631e2042..273147577c17 100644 --- a/drivers/staging/bcm/InterfaceTx.h +++ b/drivers/staging/bcm/InterfaceTx.h @@ -3,11 +3,5 @@ INT InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len); - -ULONG InterfaceTxDataPacket(PMINI_ADAPTER Adapter,PVOID Packet,USHORT usVcid); - -ULONG InterfaceTxControlPacket(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT uiBufferLength); - - #endif -- cgit v1.2.3 From d7affd0f58c9f68441b4ce631d07fad2e6a448db Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 17:15:06 -0700 Subject: beceem: reduce transmit queue len Reduce transmit queue length to avoid excess buffering Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 3 ++- drivers/staging/bcm/Macros.h | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index f0549912c9ec..c77c1d1e6157 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -143,7 +143,8 @@ int register_networkdev(PMINI_ADAPTER Adapter) net->netdev_ops = &bcmNetDevOps; net->ethtool_ops = &bcm_ethtool_ops; - net->mtu = MTU_SIZE; /* 1400 Bytes */ + net->mtu = MTU_SIZE; /* 1400 Bytes */ + net->tx_queue_len = TX_QLEN; SET_NETDEV_DEV(net, &uintf->dev); SET_NETDEV_DEVTYPE(net, &wimax_type); diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h index 3868e5b94443..338b61d5c133 100644 --- a/drivers/staging/bcm/Macros.h +++ b/drivers/staging/bcm/Macros.h @@ -13,10 +13,9 @@ #define MAX_DATA_PKTS 200 #define MAX_ETH_SIZE 1536 #define MAX_CNTL_PKT_SIZE 2048 -/* TIMER RELATED */ -#define JIFFIES_2_QUADPART() (ULONG)(jiffies * 10000) // jiffies(1msec) to Quadpart(100nsec) #define MTU_SIZE 1400 +#define TX_QLEN 5 #define MAC_ADDR_REGISTER 0xbf60d000 -- cgit v1.2.3 From 2515ab628f227b0711393993fe3228e167cc988f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Oct 2010 21:39:54 -0700 Subject: beceem: Add proper carrier and link management Start with carrier off. Don't track up/down status in driver private flag. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 1 - drivers/staging/bcm/Bcmnet.c | 3 +-- drivers/staging/bcm/InterfaceRx.c | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 9c9dff3e0daa..c679b71848ac 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -498,7 +498,6 @@ struct _MINI_ADAPTER int irq; unsigned long chip_id; unsigned int bFlashBoot; - unsigned int if_up; // spinlock_t sleeper_lock; atomic_t rdm_wrm_access; atomic_t tx_rx_access; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index c77c1d1e6157..9518e388b054 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -17,7 +17,6 @@ static INT bcm_open(struct net_device *dev) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "======>"); if(Adapter->fw_download_done==FALSE) return -EINVAL; - Adapter->if_up=1; if(Adapter->LinkUpStatus == 1){ if(netif_queue_stopped(Adapter->dev)){ netif_carrier_on(Adapter->dev); @@ -34,7 +33,6 @@ static INT bcm_close(struct net_device *dev) PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=====>"); - Adapter->if_up=0; if(!netif_queue_stopped(dev)) { netif_carrier_off(dev); netif_stop_queue(dev); @@ -145,6 +143,7 @@ int register_networkdev(PMINI_ADAPTER Adapter) net->ethtool_ops = &bcm_ethtool_ops; net->mtu = MTU_SIZE; /* 1400 Bytes */ net->tx_queue_len = TX_QLEN; + netif_carrier_off(net); SET_NETDEV_DEV(net, &uintf->dev); SET_NETDEV_DEVTYPE(net, &wimax_type); diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c index 128aa91f7434..ab33895bfe56 100644 --- a/drivers/staging/bcm/InterfaceRx.c +++ b/drivers/staging/bcm/InterfaceRx.c @@ -148,7 +148,7 @@ static void read_bulk_callback(struct urb *urb) atomic_add(pLeader->PLength, &Adapter->GoodRxByteCount); BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt of len :0x%X", pLeader->PLength); - if(Adapter->if_up) + if(netif_running(Adapter->dev)) { /* Moving ahead by ETH_HLEN to the data ptr as received from FW */ skb_pull(skb, ETH_HLEN); -- cgit v1.2.3 From e614e28eac1afcdc3d1275f3e1478aa3e5acc500 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 09:52:14 -0400 Subject: beceem: remove indirection to Adapter structure Allocate Adapter structure as part of network device. Signed-off-by: Stephen Hemminber --- drivers/staging/bcm/Adapter.h | 1 + drivers/staging/bcm/Bcmnet.c | 22 +------------------ drivers/staging/bcm/InterfaceInit.c | 43 ++++++++++++++++--------------------- drivers/staging/bcm/InterfaceMisc.c | 11 ---------- drivers/staging/bcm/InterfaceMisc.h | 3 --- drivers/staging/bcm/Macros.h | 1 - drivers/staging/bcm/Misc.c | 33 ++++++++++++++-------------- drivers/staging/bcm/headers.h | 6 ++++++ 8 files changed, 43 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index c679b71848ac..a411c03f5c71 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -623,6 +623,7 @@ struct _MINI_ADAPTER }; typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER; +#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev) typedef struct _DEVICE_EXTENSION { diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 9518e388b054..1f35cd3c2872 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -1,11 +1,5 @@ #include "headers.h" -#define DRV_NAME "beceem" -#define DRV_VERSION "5.2.7.3P1" -#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver" -#define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc" - - struct net_device *gblpnetdev; /***************************************************************************************/ /* proto-type of lower function */ @@ -123,29 +117,15 @@ static const struct ethtool_ops bcm_ethtool_ops = { int register_networkdev(PMINI_ADAPTER Adapter) { - struct net_device *net; - PMINI_ADAPTER *temp; - PS_INTERFACE_ADAPTER psIntfAdapter = Adapter->pvInterfaceAdapter; - struct usb_interface *uintf = psIntfAdapter->interface; + struct net_device *net = Adapter->dev; int result; - net = alloc_etherdev(sizeof(PMINI_ADAPTER)); - if(!net) { - pr_notice("bcmnet: no memory for device\n"); - return -ENOMEM; - } - - Adapter->dev = net; /* FIXME - only allows one adapter! */ - temp = netdev_priv(net); - *temp = Adapter; - net->netdev_ops = &bcmNetDevOps; net->ethtool_ops = &bcm_ethtool_ops; net->mtu = MTU_SIZE; /* 1400 Bytes */ net->tx_queue_len = TX_QLEN; netif_carrier_off(net); - SET_NETDEV_DEV(net, &uintf->dev); SET_NETDEV_DEVTYPE(net, &wimax_type); /* Read the MAC Address from EEPROM */ diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 014b06bfbc9f..e700fc768aed 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -182,30 +182,27 @@ static struct usb_class_driver usbbcm_class = { static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int retval =0 ; - PMINI_ADAPTER psAdapter = NULL; - PS_INTERFACE_ADAPTER psIntfAdapter = NULL; - struct usb_device *udev = NULL; - -// BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Usbbcm probe!!"); - if((intf == NULL) || (id == NULL)) - { - // BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "intf or id is NULL"); - return -EINVAL; - } - - /* Allocate Adapter structure */ - if((psAdapter = kzalloc(sizeof(MINI_ADAPTER), GFP_KERNEL)) == NULL) - { - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Out of memory"); + struct usb_device *udev = interface_to_usbdev (intf); + int retval; + PMINI_ADAPTER psAdapter; + PS_INTERFACE_ADAPTER psIntfAdapter; + struct net_device *ndev; + + ndev = alloc_etherdev(sizeof(MINI_ADAPTER)); + if(ndev == NULL) { + dev_err(&udev->dev, DRV_NAME ": no memory for device\n"); return -ENOMEM; } + SET_NETDEV_DEV(ndev, &intf->dev); + + psAdapter = netdev_priv(ndev); + psAdapter->dev = ndev; + /* Init default driver debug state */ psAdapter->stDebugState.debug_level = debug_level; psAdapter->stDebugState.type = DBG_TYPE_INITEXIT; - memset (psAdapter->stDebugState.subtype, 0, sizeof (psAdapter->stDebugState.subtype)); /* Technically, one can start using BCM_DEBUG_PRINT after this point. * However, realize that by default the Type/Subtype bitmaps are all zero now; @@ -224,22 +221,21 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) retval = InitAdapter(psAdapter); if(retval) { - BCM_DEBUG_PRINT (psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InitAdapter Failed\n"); + dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n"); AdapterFree(psAdapter); return retval; } /* Allocate interface adapter structure */ - if((psAdapter->pvInterfaceAdapter = - kmalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL)) == NULL) + psIntfAdapter = kzalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL); + if (psIntfAdapter == NULL) { - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Out of memory"); + dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n"); AdapterFree (psAdapter); return -ENOMEM; } - memset(psAdapter->pvInterfaceAdapter, 0, sizeof(S_INTERFACE_ADAPTER)); - psIntfAdapter = InterfaceAdapterGet(psAdapter); + psAdapter->pvInterfaceAdapter = psIntfAdapter; psIntfAdapter->psAdapter = psAdapter; /* Store usb interface in Interface Adapter */ @@ -276,7 +272,6 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) } } - udev = interface_to_usbdev (intf); /* Check whether the USB-Device Supports remote Wake-Up */ if(USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) { diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c index 2d98b7e846c2..6ee5dbb6154a 100644 --- a/drivers/staging/bcm/InterfaceMisc.c +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -1,16 +1,5 @@ #include "headers.h" - -PS_INTERFACE_ADAPTER -InterfaceAdapterGet(PMINI_ADAPTER psAdapter) -{ - if(psAdapter == NULL) - { - return NULL; - } - return (PS_INTERFACE_ADAPTER)(psAdapter->pvInterfaceAdapter); -} - INT InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter, UINT addr, diff --git a/drivers/staging/bcm/InterfaceMisc.h b/drivers/staging/bcm/InterfaceMisc.h index 74c81d45cff4..6c9e39bf9889 100644 --- a/drivers/staging/bcm/InterfaceMisc.h +++ b/drivers/staging/bcm/InterfaceMisc.h @@ -1,9 +1,6 @@ #ifndef __INTERFACE_MISC_H #define __INTERFACE_MISC_H -PS_INTERFACE_ADAPTER -InterfaceAdapterGet(PMINI_ADAPTER psAdapter); - INT InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter, UINT addr, diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h index 338b61d5c133..14df2f86b14e 100644 --- a/drivers/staging/bcm/Macros.h +++ b/drivers/staging/bcm/Macros.h @@ -354,7 +354,6 @@ enum eAbortPattern { ABORT_IDLE_SYNCDOWN = 3 }; -#define GET_BCM_ADAPTER(net_dev) (net_dev ? netdev_priv(net_dev) : NULL) /* Offsets used by driver in skb cb variable */ #define SKB_CB_CLASSIFICATION_OFFSET 0 diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index eca75dbffe35..ae9e88cf51fd 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -108,7 +108,7 @@ InitAdapter(PMINI_ADAPTER psAdapter) VOID AdapterFree(PMINI_ADAPTER Adapter) { - INT count = 0; + int count; beceem_protocol_reset(Adapter); @@ -116,41 +116,40 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) if(Adapter->control_packet_handler && !IS_ERR(Adapter->control_packet_handler)) kthread_stop (Adapter->control_packet_handler); + if(Adapter->transmit_packet_thread && !IS_ERR(Adapter->transmit_packet_thread)) - kthread_stop (Adapter->transmit_packet_thread); - wake_up(&Adapter->process_read_wait_queue); + kthread_stop (Adapter->transmit_packet_thread); + + wake_up(&Adapter->process_read_wait_queue); + if(Adapter->LEDInfo.led_thread_running & (BCM_LED_THREAD_RUNNING_ACTIVELY | BCM_LED_THREAD_RUNNING_INACTIVELY)) kthread_stop (Adapter->LEDInfo.led_cntrl_threadid); + bcm_unregister_networkdev(Adapter); + + /* FIXME: use proper wait_event and refcounting */ while(atomic_read(&Adapter->ApplicationRunning)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Waiting for Application to close.. %d\n",atomic_read(&Adapter->ApplicationRunning)); msleep(100); } unregister_control_device_interface(Adapter); - if(Adapter->dev && !IS_ERR(Adapter->dev)) - free_netdev(Adapter->dev); - if(Adapter->pstargetparams != NULL) - { - kfree(Adapter->pstargetparams); - } + + kfree(Adapter->pstargetparams); + for (count =0;count < MAX_CNTRL_PKTS;count++) - { - if(Adapter->txctlpacket[count]) - kfree(Adapter->txctlpacket[count]); - } + kfree(Adapter->txctlpacket[count]); + FreeAdapterDsxBuffer(Adapter); - if(Adapter->pvInterfaceAdapter) - kfree(Adapter->pvInterfaceAdapter); + kfree(Adapter->pvInterfaceAdapter); //Free the PHS Interface PhsCleanup(&Adapter->stBCMPhsContext); BcmDeAllocFlashCSStructure(Adapter); - kfree(Adapter); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "<========\n"); + free_netdev(Adapter->dev); } diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index d4a200329bab..0fdee9528617 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -74,5 +74,11 @@ #include "InterfaceIdleMode.h" #include "InterfaceInit.h" +#define DRV_NAME "beceem" +#define DEV_NAME "tarang" +#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver" +#define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc" +#define DRV_VERSION VER_FILEVERSION_STR +#define PFX DRV_NAME " " #endif -- cgit v1.2.3 From 6ba8fe77ddd3a25daa8409333295b90c26a43bae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 31 Oct 2010 23:43:55 -0400 Subject: beceem: print better message on bad ioctl Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmchar.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index f9979a87c42b..5dbd96aab54e 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -2355,10 +2355,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) break; default: - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "wrong input %x",cmd); - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In default ioctl %d\n", cmd); - Status = STATUS_FAILURE; - + pr_info(DRV_NAME ": unknown ioctl cmd=%#x\n", cmd); + Status = STATUS_FAILURE; break; } return Status; -- cgit v1.2.3 From 7441698fe9eb0eb473cf1699d9cd8dd06dfeaf77 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 09:53:58 -0400 Subject: beceem: remove ARP spoofing Linux support NOARP flag, so the whole Arp spoofing routines are not needed. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Arp.c | 94 ------------------------------------------ drivers/staging/bcm/Bcmnet.c | 3 ++ drivers/staging/bcm/Makefile | 2 +- drivers/staging/bcm/Transmit.c | 15 ++----- 4 files changed, 7 insertions(+), 107 deletions(-) delete mode 100644 drivers/staging/bcm/Arp.c (limited to 'drivers') diff --git a/drivers/staging/bcm/Arp.c b/drivers/staging/bcm/Arp.c deleted file mode 100644 index 7cb25b30b5c1..000000000000 --- a/drivers/staging/bcm/Arp.c +++ /dev/null @@ -1,94 +0,0 @@ - -/* - * File Name: Arp.c - * Abstract: This file contains the routines for handling ARP PACKETS - */ -#include "headers.h" -#define ARP_PKT_SIZE 60 - -/* ========================================================================= - * Function - reply_to_arp_request() - * - * Description - When this host tries to broadcast ARP request packet through - * the virtual interface (veth0), reply directly to upper layer. - * This function allocates a new skb for ARP reply packet, - * fills in the fields of the packet and then sends it to - * upper layer. - * - * Parameters - skb: Pointer to sk_buff structure of the ARP request pkt. - * - * Returns - None - * =========================================================================*/ - -VOID -reply_to_arp_request(struct sk_buff *skb) -{ - PMINI_ADAPTER Adapter; - struct ArpHeader *pArpHdr = NULL; - struct ethhdr *pethhdr = NULL; - UCHAR uiIPHdr[4]; - /* Check for valid skb */ - if(skb == NULL) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Invalid skb: Cannot reply to ARP request\n"); - return; - } - - - Adapter = GET_BCM_ADAPTER(skb->dev); - /* Print the ARP Request Packet */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "ARP Packet Dump :"); - BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, (PUCHAR)(skb->data), skb->len); - - /* - * Extract the Ethernet Header and Arp Payload including Header - */ - pethhdr = (struct ethhdr *)skb->data; - pArpHdr = (struct ArpHeader *)(skb->data+ETH_HLEN); - - if(Adapter->bETHCSEnabled) - { - if(memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN)) - { - dev_kfree_skb(skb); - return; - } - } - - // Set the Ethernet Header First. - memcpy(pethhdr->h_dest, pethhdr->h_source, ETH_ALEN); - if(!memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN)) - { - pethhdr->h_source[5]++; - } - - /* Set the reply to ARP Reply */ - pArpHdr->arp.ar_op = ntohs(ARPOP_REPLY); - - /* Set the HW Address properly */ - memcpy(pArpHdr->ar_sha, pethhdr->h_source, ETH_ALEN); - memcpy(pArpHdr->ar_tha, pethhdr->h_dest, ETH_ALEN); - - // Swapping the IP Adddress - memcpy(uiIPHdr,pArpHdr->ar_sip,4); - memcpy(pArpHdr->ar_sip,pArpHdr->ar_tip,4); - memcpy(pArpHdr->ar_tip,uiIPHdr,4); - - /* Print the ARP Reply Packet */ - - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "ARP REPLY PACKET: "); - - /* Send the Packet to upper layer */ - BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, (PUCHAR)(skb->data), skb->len); - - skb->protocol = eth_type_trans(skb,skb->dev); - skb->pkt_type = PACKET_HOST; - -// skb->mac.raw=skb->data+LEADER_SIZE; - skb_set_mac_header (skb, LEADER_SIZE); - netif_rx(skb); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "<=============\n"); - return; -} - - diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 1f35cd3c2872..908711d0447d 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -124,6 +124,9 @@ int register_networkdev(PMINI_ADAPTER Adapter) net->ethtool_ops = &bcm_ethtool_ops; net->mtu = MTU_SIZE; /* 1400 Bytes */ net->tx_queue_len = TX_QLEN; + net->flags |= IFF_NOARP; + net->flags &= ~(IFF_BROADCAST|IFF_MULTICAST); + netif_carrier_off(net); SET_NETDEV_DEVTYPE(net, &wimax_type); diff --git a/drivers/staging/bcm/Makefile b/drivers/staging/bcm/Makefile index 0050206b0fc1..652b7f87737c 100644 --- a/drivers/staging/bcm/Makefile +++ b/drivers/staging/bcm/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_BCM_WIMAX) += bcm_wimax.o bcm_wimax-y := InterfaceDld.o InterfaceIdleMode.o InterfaceInit.o InterfaceRx.o \ InterfaceIsr.o InterfaceMisc.o InterfaceTx.o \ - Arp.o CmHost.o IPv6Protocol.o Qos.o Transmit.o\ + CmHost.o IPv6Protocol.o Qos.o Transmit.o\ Bcmnet.o DDRInit.o HandleControlPacket.o\ LeakyBucket.o Misc.o sort.o Bcmchar.o hostmibs.o PHSModule.o\ led_control.o nvm.o vendorspecificextn.o diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 1f69625f241e..4b94d822578c 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -6,7 +6,7 @@ digraph transmit1 { node[shape=box] edge[weight=5;color=red] -bcm_transmit->reply_to_arp_request[label="ARP"] + bcm_transmit->GetPacketQueueIndex[label="IP Packet"] GetPacketQueueIndex->IpVersion4[label="IPV4"] GetPacketQueueIndex->IpVersion6[label="IPV6"] @@ -63,17 +63,8 @@ netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) qindex = GetPacketQueueIndex(Adapter, skb); - if (INVALID_QUEUE_INDEX==qindex) { - if (ntohs(eth_hdr(skb)->h_proto) != ETH_ARP_FRAME) - goto drop; - - /* - Reply directly to ARP request packet - ARP Spoofing only if NO ETH CS rule matches for it - */ - reply_to_arp_request(skb); - return NETDEV_TX_OK; - } + if (INVALID_QUEUE_INDEX==qindex) + goto drop; if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) return NETDEV_TX_BUSY; -- cgit v1.2.3 From 26a0e39ac8ed1f38b31baeb901bc76501466d34e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 31 Oct 2010 23:47:35 -0400 Subject: beceem: fold unregister_netdevice into AdapterFree The function unregister_netdevice only called unregister_netdev. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 9 --------- drivers/staging/bcm/Misc.c | 2 +- drivers/staging/bcm/Prototypes.h | 2 -- 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 908711d0447d..e3575ad65e91 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -145,15 +145,6 @@ int register_networkdev(PMINI_ADAPTER Adapter) return result; } -void bcm_unregister_networkdev(PMINI_ADAPTER Adapter) -{ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering the Net Dev...\n"); - if(Adapter->dev) { - unregister_netdev(Adapter->dev); - Adapter->dev = NULL; - } -} - static int bcm_init(void) { printk(KERN_INFO "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index ae9e88cf51fd..b982c7a6e9f2 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -125,7 +125,7 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) if(Adapter->LEDInfo.led_thread_running & (BCM_LED_THREAD_RUNNING_ACTIVELY | BCM_LED_THREAD_RUNNING_INACTIVELY)) kthread_stop (Adapter->LEDInfo.led_cntrl_threadid); - bcm_unregister_networkdev(Adapter); + unregister_netdev(Adapter->dev); /* FIXME: use proper wait_event and refcounting */ while(atomic_read(&Adapter->ApplicationRunning)) diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index 286ea46cd996..8ca6b9eb4e34 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -122,8 +122,6 @@ void doPowerAutoCorrection(PMINI_ADAPTER psAdapter); int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo); -void bcm_unregister_networkdev(PMINI_ADAPTER Adapter); - int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid); void CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter, -- cgit v1.2.3 From 20f48653fcf51f6d1246b5f3f86b40ed779385b2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 31 Oct 2010 23:52:36 -0400 Subject: beceem: get rid of unnecessary inline usage Many routines were tagged with inline_ but GCC does a better job of deciding this. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/CmHost.c | 16 +++++++++------- drivers/staging/bcm/InterfaceInit.c | 2 +- drivers/staging/bcm/InterfaceTx.c | 4 ++-- drivers/staging/bcm/LeakyBucket.c | 35 +++++------------------------------ drivers/staging/bcm/Misc.c | 7 +++---- 5 files changed, 20 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index dadfff00f837..1c3ca1e49fee 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -28,7 +28,7 @@ typedef enum _E_CLASSIFIER_ACTION * Returns - Queue index for this SFID(If matched) Else Invalid Queue Index(If Not matched) ************************************************************/ -__inline INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid) +INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid) { INT iIndex=0; for(iIndex=(NO_OF_QUEUES-1); iIndex>=0; iIndex--) @@ -47,18 +47,20 @@ __inline INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid) * Returns - Queue index for the free SFID * Else returns Invalid Index. ****************************************************************/ -__inline INT SearchFreeSfid(PMINI_ADAPTER Adapter) +static INT SearchFreeSfid(PMINI_ADAPTER Adapter) { UINT uiIndex=0; + for(uiIndex=0; uiIndex < (NO_OF_QUEUES-1); uiIndex++) if(Adapter->PackInfo[uiIndex].ulSFID==0) return uiIndex; return NO_OF_QUEUES+1; } -__inline int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid) +int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid) { - int iIndex=0; + int iIndex=0; + for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--) if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid) return iIndex; @@ -76,7 +78,7 @@ Input parameters: PMINI_ADAPTER Adapter - Adapter Context Return: int :Classifier table index of matching entry */ -__inline int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16 uiClassifierID) +static int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16 uiClassifierID) { unsigned int uiClassifierIndex = 0; for(uiClassifierIndex=0;uiClassifierIndexurb; diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c index cae382313ce9..9c73862d5120 100644 --- a/drivers/staging/bcm/LeakyBucket.c +++ b/drivers/staging/bcm/LeakyBucket.c @@ -75,7 +75,7 @@ static VOID UpdateTokenCount(register PMINI_ADAPTER Adapter) * Returns - The number of bytes allowed for transmission. * ***********************************************************************/ -static __inline ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF) +static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>"); /* Validate the parameters */ @@ -107,38 +107,14 @@ static __inline ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF) return 0; } -static __inline void RemovePacketFromQueue(PacketInfo *pPackInfo , struct sk_buff *Packet) -{ - struct sk_buff *psQueueCurrent=NULL, *psLastQueueNode=NULL; - psQueueCurrent = pPackInfo->FirstTxQueue; - while(psQueueCurrent) - { - if(Packet == psQueueCurrent) - { - if(psQueueCurrent == pPackInfo->FirstTxQueue) - { - pPackInfo->FirstTxQueue=psQueueCurrent->next; - if(psQueueCurrent==pPackInfo->LastTxQueue) - pPackInfo->LastTxQueue=NULL; - } - else - { - psLastQueueNode->next=psQueueCurrent->next; - } - break; - } - psLastQueueNode = psQueueCurrent; - psQueueCurrent=psQueueCurrent->next; - } -} /** @ingroup tx_functions This function despatches packet from the specified queue. @return Zero(success) or Negative value(failure) */ -static __inline INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**"); @@ -943,8 +943,7 @@ VOID DumpPackInfo(PMINI_ADAPTER Adapter) } - -__inline int reset_card_proc(PMINI_ADAPTER ps_adapter) +int reset_card_proc(PMINI_ADAPTER ps_adapter) { int retval = STATUS_SUCCESS; @@ -1074,7 +1073,7 @@ err_exit : return retval; } -__inline int run_card_proc(PMINI_ADAPTER ps_adapter ) +int run_card_proc(PMINI_ADAPTER ps_adapter ) { unsigned int value=0; { -- cgit v1.2.3 From 937110581650eaa517f045fb7b86b9828ba693ad Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 31 Oct 2010 23:55:21 -0400 Subject: beceem: support multiple queues Current kernels have multi-queue support which can be used by this device. This has the advantage that a single type of traffic will not block other types. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 66 +++++++++++++++++++++++++++++++++++++ drivers/staging/bcm/InterfaceInit.c | 2 +- drivers/staging/bcm/Prototypes.h | 14 +++----- drivers/staging/bcm/Qos.c | 30 ----------------- drivers/staging/bcm/Transmit.c | 61 ---------------------------------- 5 files changed, 72 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index e3575ad65e91..5b466174a580 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -54,6 +54,71 @@ static struct net_device_stats *bcm_get_stats(struct net_device *dev) return netstats; } +static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + return ClassifyPacket(netdev_priv(dev), skb); +} + + +/******************************************************************* +* Function - bcm_transmit() +* +* Description - This is the main transmit function for our virtual +* interface(eth0). It handles the ARP packets. It +* clones this packet and then Queue it to a suitable +* Queue. Then calls the transmit_packet(). +* +* Parameter - skb - Pointer to the socket buffer structure +* dev - Pointer to the virtual net device structure +* +*********************************************************************/ + +static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) +{ + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + u16 qindex = skb_get_queue_mapping(skb); + + if (Adapter->device_removed || !Adapter->LinkUpStatus) + goto drop; + + if (Adapter->TransferMode != IP_PACKET_ONLY_MODE ) + goto drop; + + if (INVALID_QUEUE_INDEX==qindex) + goto drop; + + if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) + return NETDEV_TX_BUSY; + + /* Now Enqueue the packet */ + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, + "bcm_transmit Enqueueing the Packet To Queue %d",qindex); + spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); + Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; + Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; + + *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies; + ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, + Adapter->PackInfo[qindex].LastTxQueue, skb); + atomic_inc(&Adapter->TotalPacketCount); + spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); + + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n"); + + /* FIXME - this is racy and incorrect, replace with work queue */ + if (!atomic_read(&Adapter->TxPktAvail)) { + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); + } + return NETDEV_TX_OK; + + drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + + + /** @ingroup init_functions Register other driver entry points with the kernel @@ -66,6 +131,7 @@ static const struct net_device_ops bcmNetDevOps = { .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_select_queue = bcm_select_queue, }; static struct device_type wimax_type = { diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 14866e9c8cd2..845ced1670ee 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -188,7 +188,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) PS_INTERFACE_ADAPTER psIntfAdapter; struct net_device *ndev; - ndev = alloc_etherdev(sizeof(MINI_ADAPTER)); + ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES); if(ndev == NULL) { dev_err(&udev->dev, DRV_NAME ": no memory for device\n"); return -ENOMEM; diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index 8ca6b9eb4e34..a4b57bb07fa1 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -46,13 +46,12 @@ VOID PruneQueueAllSF(PMINI_ADAPTER Adapter); INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid); -USHORT GetPacketQueueIndex(PMINI_ADAPTER Adapter, /**"); - - if(NULL==Adapter || NULL==Packet) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "Got NULL Values<======"); - return -1; - } - - usIndex = ClassifyPacket(Adapter,Packet); - - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "Got Queue Index %x",usIndex); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "GetPacketQueueIndex <=============="); - return usIndex; -} VOID PruneQueueAllSF(PMINI_ADAPTER Adapter) { diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 4b94d822578c..734bbbd14e22 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -35,67 +35,6 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53 #include "headers.h" -/******************************************************************* -* Function - bcm_transmit() -* -* Description - This is the main transmit function for our virtual -* interface(eth0). It handles the ARP packets. It -* clones this packet and then Queue it to a suitable -* Queue. Then calls the transmit_packet(). -* -* Parameter - skb - Pointer to the socket buffer structure -* dev - Pointer to the virtual net device structure -* -* Returns - zero (success) or -ve value (failure) -* -*********************************************************************/ - -netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) -{ - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); - SHORT qindex; - - if (Adapter->device_removed || !Adapter->LinkUpStatus) - goto drop; - - if (Adapter->TransferMode != IP_PACKET_ONLY_MODE ) - goto drop; - - qindex = GetPacketQueueIndex(Adapter, skb); - - if (INVALID_QUEUE_INDEX==qindex) - goto drop; - - if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) - return NETDEV_TX_BUSY; - - /* Now Enqueue the packet */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, - "bcm_transmit Enqueueing the Packet To Queue %d",qindex); - spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); - Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; - Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; - - *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies; - ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, - Adapter->PackInfo[qindex].LastTxQueue, skb); - atomic_inc(&Adapter->TotalPacketCount); - spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); - - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n"); - - /* FIXME - this is racy and incorrect, replace with work queue */ - if (!atomic_read(&Adapter->TxPktAvail)) { - atomic_set(&Adapter->TxPktAvail, 1); - wake_up(&Adapter->tx_packet_wait_queue); - } - return NETDEV_TX_OK; - - drop: - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - /** @ingroup ctrl_pkt_functions -- cgit v1.2.3 From 3644c1a2f12b15e1c8bfb9ebfaacbd177011a72d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 00:03:03 -0400 Subject: beceem: remove dead code Remove commented out with '#if 0' Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 44 +---- drivers/staging/bcm/Bcmchar.c | 35 ---- drivers/staging/bcm/CmHost.c | 60 ------ drivers/staging/bcm/DDRInit.c | 11 -- drivers/staging/bcm/HandleControlPacket.c | 23 --- drivers/staging/bcm/InterfaceDld.c | 104 ---------- drivers/staging/bcm/InterfaceIdleMode.c | 8 - drivers/staging/bcm/InterfaceInit.c | 26 --- drivers/staging/bcm/InterfaceRx.c | 6 - drivers/staging/bcm/InterfaceTx.c | 9 - drivers/staging/bcm/LeakyBucket.c | 3 - drivers/staging/bcm/Misc.c | 60 ------ drivers/staging/bcm/Qos.c | 9 - drivers/staging/bcm/led_control.c | 111 ----------- drivers/staging/bcm/nvm.c | 314 ------------------------------ 15 files changed, 1 insertion(+), 822 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index a411c03f5c71..9f8954bfd5bd 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -7,42 +7,6 @@ #define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256 #include "Debug.h" -typedef struct _LIST_ENTRY{ - struct _LIST_ENTRY *next; - struct _LIST_ENTRY *prev; -} LIST_ENTRY, *PLIST_ENTRY; - -typedef struct _BCM_LIST_ENTRY { - - LIST_ENTRY Link; - -} BCM_LIST_ENTRY, *PBCM_LIST_ENTRY; - -typedef enum _RCB_STATUS -{ - DRIVER_PROCESSED=1, - APPLICATION_PROCESSED -} RCB_STATUS, *PRCB_STATUS; - -#define fFILLED 1 -#define fEMPTY 0 - -struct _BCM_CB -{ - // The network packet that this RCB is receiving - PVOID pv_packet; - // Describes the length of the packet . - UINT ui_packet_length; - // Pointer to the first buffer in the packet (only one buffer for Rx) - PUCHAR buffer; - atomic_t status; - UINT filled; -} __attribute__((packed)); -typedef struct _BCM_CB BCM_CB,*PBCM_CB; - -typedef BCM_CB BCM_RCB, *PBCM_RCB; -typedef BCM_CB BCM_TCB, *PBCM_TCB; - struct _LEADER { USHORT Vcid; @@ -555,7 +519,7 @@ struct _MINI_ADAPTER unsigned int usIdleModePattern; //BOOLEAN bTriedToWakeUpFromShutdown; BOOLEAN bLinkDownRequested; - unsigned int check_for_hang; + int downloadDDR; PHS_DEVICE_EXTENSION stBCMPhsContext; S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo; @@ -625,12 +589,6 @@ typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER; #define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev) -typedef struct _DEVICE_EXTENSION -{ - PMINI_ADAPTER pAdapt; -}DEVICE_EXTENSION,*PDEVICE_EXTENSION; - - struct _ETH_HEADER_STRUC { UCHAR au8DestinationAddress[6]; UCHAR au8SourceAddress[6]; diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 5dbd96aab54e..6c9db7227ca2 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -1207,10 +1207,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Adapter->usIdleModePattern = ABORT_IDLE_MODE; Adapter->bWakeUpDevice = TRUE; wake_up(&Adapter->process_rx_cntrlpkt); - #if 0 - Adapter->bTriedToWakeUpFromlowPowerMode = TRUE; - InterfaceAbortIdlemode (Adapter, Adapter->usIdleModePattern); - #endif } Status = STATUS_SUCCESS; break; @@ -1750,14 +1746,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.offset :%d" ,sFlash2xWrite.offset); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.numOfBytes :%x" ,sFlash2xWrite.numOfBytes); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.bVerify :%x\n" ,sFlash2xWrite.bVerify); - #if 0 - if((sFlash2xWrite.Section == ISO_IMAGE1) ||(sFlash2xWrite.Section == ISO_IMAGE2) || - (sFlash2xWrite.Section == DSD0) || (sFlash2xWrite.Section == DSD1) || (sFlash2xWrite.Section == DSD2)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"ISO/DSD Image write is not allowed.... "); - return STATUS_FAILURE ; - } - #endif if((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) && (sFlash2xWrite.Section != VSA2) ) { @@ -1940,29 +1928,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Adapter->bAllDSDWriteAllow = FALSE ; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called"); - #if 0 - SECTION_TYPE section = 0 ; - - - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION Called"); - Status = copy_from_user((PCHAR)&IoBuffer, (PCHAR)arg, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy of IOCTL BUFFER failed"); - return -EFAULT; - } - Status = copy_from_user((PCHAR)section,(PCHAR)&IoBuffer, sizeof(INT)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy of section type failed failed"); - return -EFAULT; - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Read Section :%d", section); - if(section == DSD) - Adapter->ulFlashCalStart = Adapter->uiActiveDSDOffsetAtFwDld ; - else - Status = STATUS_FAILURE ; - #endif Status = STATUS_SUCCESS ; } break ; diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 1c3ca1e49fee..d0bfdbbeee3f 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -1063,12 +1063,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) pstAddIndication->sfAuthorizedSet.u32MaxTrafficBurst); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X", pstAddIndication->sfAuthorizedSet.u32MinReservedTrafficRate); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinimumTolerableTrafficRate : 0x%X", - pstAddIndication->sfAuthorizedSet.u32MinimumTolerableTrafficRate); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32RequesttransmissionPolicy : 0x%X", - pstAddIndication->sfAuthorizedSet.u32RequesttransmissionPolicy); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength : 0x%X", pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParamLength); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam : 0x%X", @@ -1116,13 +1110,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) pstAddIndication->sfAuthorizedSet.u8PagingPreference); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UnsolicitedPollingInterval : 0x%X", pstAddIndication->sfAuthorizedSet.u16UnsolicitedPollingInterval); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignmentLength : 0x%X", - pstAddIndication->sfAuthorizedSet.MBSZoneIdentifierassignmentLength); - for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++) - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignment : 0x%X", - pstAddIndication->sfAuthorizedSet.MBSZoneIdentifierassignment[uiLoopIndex]); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "sfAuthorizedSet.u8HARQChannelMapping %x %x %x ", *(unsigned int*)pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping, @@ -1160,11 +1147,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0], psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1], psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]); -#if 0 - - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u8ProtocolLength :0x%X ", - psfCSType->cCPacketClassificationRule.u8ProtocolLength); -#endif for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++) BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol : 0x%02X ", @@ -1280,14 +1262,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) pstAddIndication->sfAdmittedSet.u8QosParamSet); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority : 0x%02X", pstAddIndication->sfAdmittedSet.u8TrafficPriority); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MaxSustainedTrafficRate : 0x%02X", - ntohl(pstAddIndication->sfAdmittedSet.u32MaxSustainedTrafficRate)); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MinimumTolerableTrafficRate : 0x%X", - pstAddIndication->sfAdmittedSet.u32MinimumTolerableTrafficRate); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32RequesttransmissionPolicy : 0x%X", - pstAddIndication->sfAdmittedSet.u32RequesttransmissionPolicy); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst : 0x%X", pstAddIndication->sfAdmittedSet.u32MaxTrafficBurst); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X", @@ -1341,13 +1315,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) pstAddIndication->sfAdmittedSet.u16TimeBase); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8PagingPreference : 0x%X", pstAddIndication->sfAdmittedSet.u8PagingPreference); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignmentLength : 0x%X", - pstAddIndication->sfAdmittedSet.MBSZoneIdentifierassignmentLength); - for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++) - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "MBSZoneIdentifierassignment : 0x%X", - pstAddIndication->sfAdmittedSet.MBSZoneIdentifierassignment[uiLoopIndex]); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference : 0x%02X", @@ -1380,11 +1347,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0], psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1], psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]); -#if 0 - - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolLength :0x%02X ", - psfCSType->cCPacketClassificationRule.u8ProtocolLength); -#endif for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++) BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", psfCSType->cCPacketClassificationRule.u8Protocol); @@ -1499,20 +1461,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) pstAddIndication->sfActiveSet.u8QosParamSet); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority : 0x%02X", pstAddIndication->sfActiveSet.u8TrafficPriority); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MaxSustainedTrafficRate : 0x%02X", - ntohl(pstAddIndication->sfActiveSet.u32MaxSustainedTrafficRate)); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst : 0x%X", pstAddIndication->sfActiveSet.u32MaxTrafficBurst); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X", pstAddIndication->sfActiveSet.u32MinReservedTrafficRate); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32MinimumTolerableTrafficRate : 0x%X", - pstAddIndication->sfActiveSet.u32MinimumTolerableTrafficRate); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "u32RequesttransmissionPolicy : 0x%X", - pstAddIndication->sfActiveSet.u32RequesttransmissionPolicy); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength : 0x%02X", pstAddIndication->sfActiveSet.u8VendorSpecificQoSParamLength); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam : 0x%02X", @@ -1560,13 +1512,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) pstAddIndication->sfActiveSet.u16TimeBase); BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8PagingPreference : 0x%X", pstAddIndication->sfActiveSet.u8PagingPreference); -#if 0 - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " MBSZoneIdentifierassignmentLength : 0x%X", - pstAddIndication->sfActiveSet.MBSZoneIdentifierassignmentLength); - for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++) - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " MBSZoneIdentifierassignment : 0x%X", - pstAddIndication->sfActiveSet.MBSZoneIdentifierassignment[uiLoopIndex]); -#endif BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TrafficIndicationPreference : 0x%X", @@ -1599,11 +1544,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0], psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1], psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]); -#if 0 - - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " u8ProtocolLength :0x%X ", - psfCSType->cCPacketClassificationRule.u8ProtocolLength); -#endif for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++) BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8Protocol : 0x%X ", psfCSType->cCPacketClassificationRule.u8Protocol); diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c index 454eb8d8992b..411f02a6b6ea 100644 --- a/drivers/staging/bcm/DDRInit.c +++ b/drivers/staging/bcm/DDRInit.c @@ -187,17 +187,6 @@ static DDR_SET_NODE asDPLL_266MHZ[] = { {0x0f000840,0x0FFF1B00}, {0x0f000870,0x00000002} }; -#if 0 -static DDR_SET_NODE asDPLL_800MHZ[] = { - {0x0f000810,0x00000F95}, - {0x0f000810,0x00000F95}, - {0x0f000810,0x00000F95}, - {0x0f000820,0x03F1365B}, - {0x0f000840,0x0FFF0000}, - {0x0f000880,0x000003DD}, - {0x0f000860,0x00000000} - }; -#endif #define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11 //index for 0x0F007000 static DDR_SET_NODE asT3B_DDRSetting133MHz[] = {// # DPLL Clock Setting diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c index 8cfccaa3803a..2d4dbcc215e3 100644 --- a/drivers/staging/bcm/HandleControlPacket.c +++ b/drivers/staging/bcm/HandleControlPacket.c @@ -186,29 +186,6 @@ int control_packet_handler (PMINI_ADAPTER Adapter /**< pointer to adapter obje DEQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail); // Adapter->RxControlHead=ctrl_packet->next; } - #if 0 //Idle mode debug profiling... - if(*(PUSHORT)ctrl_packet->data == IDLE_MODE_STATUS) - { - puiBuffer = (PUINT)(ctrl_packet->data +sizeof(USHORT)); - if((ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD)) - { - memset(&tv, 0, sizeof(tv)); - do_gettimeofday(&tv); - if((ntohl(*(puiBuffer+1)) == 0)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "IdleMode Wake-up Msg from f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000); - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "IdleMode req Msg from f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000); - } - } - else if((ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "GOT IDLE_MODE_SF_UPDATE MSG at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000); - } - } - #endif spin_unlock_irqrestore (&Adapter->control_queue_lock, flags); handle_rx_control_packet(Adapter, ctrl_packet); diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c index e640b75e7dc4..1fc36a15f187 100644 --- a/drivers/staging/bcm/InterfaceDld.c +++ b/drivers/staging/bcm/InterfaceDld.c @@ -230,41 +230,6 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter, return retval; } -#if 0 -static int bcm_download_buffer(PMINI_ADAPTER Adapter, - unsigned char *mappedbuffer, unsigned int u32FirmwareLength, - unsigned long u32StartingAddress) -{ - char *buff=NULL; - unsigned int len = 0; - int retval = STATUS_SUCCESS; - buff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); - - len = u32FirmwareLength; - - while(u32FirmwareLength) - { - len = MIN_VAL (u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB); - if(STATUS_SUCCESS != (retval = copy_from_user(buff, - (unsigned char *)mappedbuffer, len))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "copy_from_user failed\n"); - break; - } - retval = wrm (Adapter, u32StartingAddress, buff, len); - if(retval) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "wrm failed\n"); - break; - } - u32StartingAddress += len; - u32FirmwareLength -= len; - mappedbuffer +=len; - } - kfree(buff); - return retval; -} -#endif static int bcm_compare_buff_contents(unsigned char *readbackbuff, unsigned char *buff,unsigned int len) { @@ -296,58 +261,6 @@ static int bcm_compare_buff_contents(unsigned char *readbackbuff, } return retval; } -#if 0 -static int bcm_buffer_readback(PMINI_ADAPTER Adapter, - unsigned char *mappedbuffer, unsigned int u32FirmwareLength, - unsigned long u32StartingAddress) -{ - unsigned char *buff = NULL; - unsigned char *readbackbuff = NULL; - unsigned int len = u32FirmwareLength; - int retval = STATUS_SUCCESS; - - buff=(unsigned char *)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); - if(NULL == buff) - return -ENOMEM; - readbackbuff = (unsigned char *)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, - GFP_KERNEL); - if(NULL == readbackbuff) - { - kfree(buff); - return -ENOMEM; - } - while (u32FirmwareLength && !retval) - { - len = MIN_VAL (u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB); - - /* read from the appl buff and then read from the target, compare */ - if(STATUS_SUCCESS != (retval = copy_from_user(buff, - (unsigned char *)mappedbuffer, len))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "copy_from_user failed\n"); - break; - } - retval = rdm (Adapter, u32StartingAddress, readbackbuff, len); - if(retval) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "rdm failed\n"); - break; - } - - if (STATUS_SUCCESS != - (retval = bcm_compare_buff_contents (readbackbuff, buff, len))) - { - break; - } - u32StartingAddress += len; - u32FirmwareLength -= len; - mappedbuffer +=len; - }/* end of while (u32FirmwareLength && !retval) */ - kfree(buff); - kfree(readbackbuff); - return retval; -} -#endif int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo) { int retval = STATUS_SUCCESS; @@ -388,23 +301,6 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo) goto error ; } - #if 0 - retval = bcm_download_buffer(Adapter, - (unsigned char *)psFwInfo->pvMappedFirmwareAddress, - psFwInfo->u32FirmwareLength, psFwInfo->u32StartingAddress); - if(retval != STATUS_SUCCESS) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "User space buffer download fails...."); - } - retval = bcm_buffer_readback (Adapter, - (unsigned char *)psFwInfo->pvMappedFirmwareAddress, - psFwInfo->u32FirmwareLength, psFwInfo->u32StartingAddress); - - if(retval != STATUS_SUCCESS) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "read back verifier failed ...."); - } - #endif retval = buffDnldVerify(Adapter, buff, psFwInfo->u32FirmwareLength, diff --git a/drivers/staging/bcm/InterfaceIdleMode.c b/drivers/staging/bcm/InterfaceIdleMode.c index 0750382733ff..3a7780be7fe4 100644 --- a/drivers/staging/bcm/InterfaceIdleMode.c +++ b/drivers/staging/bcm/InterfaceIdleMode.c @@ -98,14 +98,6 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer) Adapter->bTriedToWakeUpFromlowPowerMode = FALSE; wake_up(&Adapter->lowpower_mode_wait_queue); - #if 0 - if(Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"LED Thread is Running. Hence Setting the LED Event as IDLEMODE_EXIT"); - Adapter->DriverState = IDLEMODE_EXIT; - wake_up(&Adapter->LEDInfo.notify_led_event); - } - #endif } else diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 845ced1670ee..dddf34bb7c8b 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -419,32 +419,6 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) return 0; } -#if 0 -static void print_usb_interface_desc(struct usb_interface_descriptor *usb_intf_desc) -{ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "**************** INTERFACE DESCRIPTOR *********************"); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bLength: %x", usb_intf_desc->bLength); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bDescriptorType: %x", usb_intf_desc->bDescriptorType); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceNumber: %x", usb_intf_desc->bInterfaceNumber); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bAlternateSetting: %x", usb_intf_desc->bAlternateSetting); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bNumEndpoints: %x", usb_intf_desc->bNumEndpoints); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceClass: %x", usb_intf_desc->bInterfaceClass); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceSubClass: %x", usb_intf_desc->bInterfaceSubClass); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceProtocol: %x", usb_intf_desc->bInterfaceProtocol); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "iInterface :%x\n",usb_intf_desc->iInterface); -} -static void print_usb_endpoint_descriptor(struct usb_endpoint_descriptor *usb_ep_desc) -{ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "**************** ENDPOINT DESCRIPTOR *********************"); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bLength :%x ", usb_ep_desc->bLength); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bDescriptorType :%x ", usb_ep_desc->bDescriptorType); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bEndpointAddress :%x ", usb_ep_desc->bEndpointAddress); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bmAttributes :%x ", usb_ep_desc->bmAttributes); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "wMaxPacketSize :%x ",usb_ep_desc->wMaxPacketSize); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterval :%x ",usb_ep_desc->bInterval); -} - -#endif static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) { diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c index ab33895bfe56..6f1ed78c975b 100644 --- a/drivers/staging/bcm/InterfaceRx.c +++ b/drivers/staging/bcm/InterfaceRx.c @@ -39,12 +39,6 @@ static void read_bulk_callback(struct urb *urb) PLEADER pLeader = urb->transfer_buffer; - #if 0 - int *puiBuffer = NULL; - struct timeval tv; - memset(&tv, 0, sizeof(tv)); - do_gettimeofday(&tv); - #endif if((Adapter->device_removed == TRUE) || (TRUE == Adapter->bEndPointHalted) || diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c index b53848b6fc00..a3dadf19538b 100644 --- a/drivers/staging/bcm/InterfaceTx.c +++ b/drivers/staging/bcm/InterfaceTx.c @@ -9,10 +9,6 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) PMINI_ADAPTER psAdapter = psIntfAdapter->psAdapter ; BOOLEAN bpowerDownMsg = FALSE ; PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); -#if 0 - struct timeval tv; - UINT time_ms = 0; -#endif if(urb->status != STATUS_SUCCESS) { if(urb->status == -EPIPE) @@ -33,11 +29,6 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) if(TRUE == psAdapter->bPreparingForLowPowerMode) { - #if 0 - do_gettimeofday(&tv); - time_ms = tv.tv_sec *1000 + tv.tv_usec/1000; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, " %s Idle Mode ACK_Sent got from device at time :0x%x", __FUNCTION__, time_ms); - #endif if(((pControlMsg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) && (pControlMsg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE))) diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c index 9c73862d5120..f9e8f2bb06d3 100644 --- a/drivers/staging/bcm/LeakyBucket.c +++ b/drivers/staging/bcm/LeakyBucket.c @@ -183,9 +183,6 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF) return ; } -#if 0 - PruneQueue(Adapter,(psSF-Adapter->PackInfo)); -#endif spin_lock_bh(&psSF->SFQueueLock); QueuePacket=psSF->FirstTxQueue; diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index dfc4f3fff2b2..0ada848fe1e1 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -365,13 +365,6 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**LEDInfo.bIdleMode_tx_from_host = TRUE; -#if 0 - if(STATUS_SUCCESS != InterfaceIdleModeWakeup(Adapter)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Idle Mode Wake up Failed\n"); - return STATUS_FAILURE; - } -#endif Adapter->bWakeUpDevice = TRUE; wake_up(&Adapter->process_rx_cntrlpkt); @@ -1220,12 +1213,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) goto OUT; } } -#if 0 - else if(psAdapter->eNVMType == NVM_EEPROM) - { - PropagateCalParamsFromEEPROMToMemory(); - } -#endif /* Download Firmare */ if ((status = BcmFileDownload( ps_adapter, BIN_FILE, FIRMWARE_BEGIN_ADDR))) @@ -1405,16 +1392,6 @@ VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter) if (psAdapter->bIsAutoCorrectEnabled && (psAdapter->chip_id >= T3LPB)) { //If reporting mode is enable, switch PMU to PMC - #if 0 - if(reporting_mode == FALSE) - { - psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN; - psAdapter->bDoSuspend = TRUE; - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"PMU selected ...."); - - } - else - #endif { psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING; psAdapter->bDoSuspend =FALSE; @@ -1481,43 +1458,6 @@ OUT: } #endif -#if 0 -INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter) -{ - unsigned char *puMacAddr = NULL; - int i =0; - - puMacAddr = ReadMacAddrEEPROM(Adapter,0x200); - if(!puMacAddr) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Couldn't retrieve the Mac Address\n"); - return STATUS_FAILURE; - } - else - { - if((puMacAddr[0] == 0x0 && puMacAddr[1] == 0x0 && - puMacAddr[2] == 0x0 && puMacAddr[3] == 0x0 && - puMacAddr[4] == 0x0 && puMacAddr[5] == 0x0) || - (puMacAddr[0] == 0xFF && puMacAddr[1] == 0xFF && - puMacAddr[2] == 0xFF && puMacAddr[3] == 0xFF && - puMacAddr[4] == 0xFF && puMacAddr[5] == 0xFF)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Invalid Mac Address\n"); - kfree(puMacAddr); - return STATUS_FAILURE; - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "The Mac Address received is: \n"); - memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE); - for(i=0;idev->dev_addr[i]); - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"\n"); - kfree(puMacAddr); - } - return STATUS_SUCCESS; -} -#endif static void convertEndian(B_UINT8 rwFlag, PUINT puiBuffer, UINT uiByteCount) { diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index f85a5a85ad5c..7e8013c105a2 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -254,15 +254,6 @@ USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru //if protocol is not TCP or UDP then no need of comparing source port and destination port if(iphd->protocol!=TCP && iphd->protocol!=UDP) break; -#if 0 - //check if memory is available of src and Dest port - if(ETH_AND_IP_HEADER_LEN + L4_SRC_PORT_LEN + L4_DEST_PORT_LEN > Packet->len) - { - //This is not an erroneous condition and pkt will be checked for next classification. - bClassificationSucceed = FALSE; - break; - } -#endif //******************Checking Transport Layer Header field if present *****************// BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x", (iphd->protocol==UDP)?xprt_hdr->uhdr.source:xprt_hdr->thdr.source); diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c index 79c7bd74804d..a21d219f428c 100644 --- a/drivers/staging/bcm/led_control.c +++ b/drivers/staging/bcm/led_control.c @@ -116,44 +116,7 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx, while((Adapter->device_removed == FALSE)) { - #if 0 - if(0 == num_of_time_tx && 0 == num_of_time_rx) - { - timeout = 1000; - Status = wait_event_interruptible_timeout(Adapter->LEDInfo.notify_led_event, - currdriverstate!= Adapter->DriverState || kthread_should_stop(), - msecs_to_jiffies (timeout)); - if(kthread_should_stop()) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Led thread got signal to exit..hence exiting"); - Adapter->LEDInfo.led_thread_running= BCM_LED_THREAD_DISABLED; - return EVENT_SIGNALED; - } - if(Status) - return EVENT_SIGNALED; - - } - #endif - timeout = 50; - #if 0 - /*Turn on LED if Tx is high bandwidth*/ - if(num_of_time_tx > MAX_NUM_OF_BLINKS) - { - TURN_ON_LED(1< MAX_NUM_OF_BLINKS) - { - TURN_ON_LED(1<= NUM_OF_LEDS) *bEnableThread = FALSE; -#if 0 - for(uiIndex=0; uiIndexLEDInfo.LEDState[uiIndex].LED_Type); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_On_State = %x\n", uiIndex, - Adapter->LEDInfo.LEDState[uiIndex].LED_On_State); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_Blink_State = %x\n", uiIndex, - Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].GPIO_Num = %x\n", uiIndex, - Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num); - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: Polarity = %d\n", - Adapter->LEDInfo.BitPolarty); -#endif return Status; } //-------------------------------------------------------------------------- @@ -711,20 +659,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter) TURN_OFF_LED(1<device_removed) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"Device removed hence exiting from Led Thread.."); - return ; //-ENODEV; - } - #endif - #if 0 - if((GPIO_num != DISABLE_GPIO_NUM) && - ((currdriverstate != FW_DOWNLOAD) && - (currdriverstate != NORMAL_OPERATION) && - (currdriverstate != IDLEMODE_EXIT))) - TURN_OFF_LED(1<DriverState; - #if 0 - LedGpioInit(Adapter); - Adapter->LEDInfo.bLedInitDone = TRUE; - #endif BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate); if(GPIO_num != DISABLE_GPIO_NUM) @@ -758,13 +688,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter) { //BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: FW_DN_DONE called\n"); currdriverstate = FW_DOWNLOAD; - #if 0 - if(Adapter->LEDInfo.bLedInitDone == FALSE) - { - LedGpioInit(Adapter); - Adapter->LEDInfo.bLedInitDone = TRUE; - } - #endif BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate); if(GPIO_num != DISABLE_GPIO_NUM) @@ -786,12 +709,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter) break; case SHUTDOWN_EXIT: - #if 0 - if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN) - { - LedGpioInit(Adapter); - } - #endif //no break, continue to NO_NETWORK_ENTRY state as well. case NO_NETWORK_ENTRY: @@ -865,34 +782,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter) break; case IDLEMODE_EXIT: { -#if 0 - UCHAR GPIO_num_tx = DISABLE_GPIO_NUM; - UCHAR GPIO_num_rx = DISABLE_GPIO_NUM; - UCHAR uiTxLedIndex = 0; - UCHAR uiRxLedIndex = 0; - - currdriverstate = IDLEMODE_EXIT; - if(DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN == Adapter->ulPowerSaveMode) - { - LedGpioInit(Adapter); - } - BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx, &GPIO_num_rx, &uiTxLedIndex,&uiRxLedIndex,currdriverstate); - - Adapter->LEDInfo.bIdle_led_off = FALSE; - - if((GPIO_num_tx == DISABLE_GPIO_NUM) && (GPIO_num_rx == DISABLE_GPIO_NUM)) - { - GPIO_num = DISABLE_GPIO_NUM ; - } - else - { - timeout = 50; - if(Adapter->LEDInfo.bIdleMode_tx_from_host) - LED_Blink(Adapter, 1<> 14) & 1) == 1) - { - // EEPROM_SPI_Q_STATUS1_REG will be cleared only if write back to that. - value = (0x1 << 14); - wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value)); - udelay(1000); - uiRetries--; - if(uiRetries == 0) - { - return FALSE; - } - value = 0; - rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); - } - return TRUE; - - -} - - -//----------------------------------------------------------------------------- -// Procedure: ReadBeceemEEPROMBulk -// -// Description: This routine reads 16Byte data from EEPROM -// -// Arguments: -// Adapter - ptr to Adapter object instance -// dwAddress - EEPROM Offset to read the data from. -// pdwData - Pointer to double word where data needs to be stored in. -// -// Returns: -// OSAL_STATUS_CODE: -//----------------------------------------------------------------------------- - -INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,DWORD dwAddress, DWORD *pdwData) -{ - DWORD dwRetries = 16; - DWORD dwIndex = 0; - UINT value, tmpVal; - - - value = 0; - rdmalt (Adapter, 0x0f003008, &value, sizeof(value)); - - //read 0x0f003020 untill bit 1 of 0x0f003008 is set. - while(((value >> 1) & 1) == 0) - { - - rdmalt (Adapter, 0x0f003020, &tmpVal, sizeof(tmpVal)); - dwRetries--; - if(dwRetries == 0) - { - return -1; - } - value = 0; - rdmalt (Adapter, 0x0f003008, &value, sizeof(value)); - } - - value = dwAddress | 0xfb000000; - wrmalt (Adapter, 0x0f003018, &value, sizeof(value)); - - udelay(1000); - value = 0; - for(dwIndex = 0;dwIndex < 4 ; dwIndex++) - { - value = 0; - rdmalt (Adapter, 0x0f003020, &value, sizeof(value)); - pdwData[dwIndex] = value; - - value = 0; - rdmalt (Adapter, 0x0f003020, &value, sizeof(value)); - pdwData[dwIndex] |= (value << 8); - - value = 0; - rdmalt (Adapter, 0x0f003020, &value, sizeof(value)); - pdwData[dwIndex] |= (value << 16); - - value = 0; - rdmalt (Adapter, 0x0f003020, &value, sizeof(value)); - pdwData[dwIndex] |= (value << 24); - - } - return 0; -} - -//----------------------------------------------------------------------------- -// Procedure: ReadBeceemEEPROM -// -// Description: This routine reads 4Byte data from EEPROM -// -// Arguments: -// Adapter - ptr to Adapter object instance -// dwAddress - EEPROM Offset to read the data from. -// pdwData - Pointer to double word where data needs to be stored in. -// -// Returns: -// OSAL_STATUS_CODE: -//----------------------------------------------------------------------------- - -INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,DWORD dwAddress, DWORD *pdwData) -{ - - DWORD dwReadValue = 0; - DWORD dwRetries = 16, dwCompleteWord = 0; - UINT value, tmpVal; - - rdmalt(Adapter, 0x0f003008, &value, sizeof(value)); - while (((value >> 1) & 1) == 0) { - rdmalt(Adapter, 0x0f003020, &tmpVal, sizeof(tmpVal)); - - if (dwRetries == 0) { - return -1; - } - rdmalt(Adapter, 0x0f003008, &value, sizeof(value)); - } - - - //wrm (0x0f003018, 0xNbXXXXXX) // N is the number of bytes u want to read (0 means 1, f means 16, b is the opcode for page read) - // Follow it up by N executions of rdm(0x0f003020) to read the rxed bytes from rx queue. - dwAddress |= 0x3b000000; - wrmalt(Adapter, 0x0f003018,&dwAddress,4); - mdelay(10); - rdmalt(Adapter, 0x0f003020,&dwReadValue,4); - dwCompleteWord=dwReadValue; - rdmalt(Adapter, 0x0f003020,&dwReadValue,4); - dwCompleteWord|=(dwReadValue<<8); - rdmalt(Adapter, 0x0f003020,&dwReadValue,4); - dwCompleteWord|=(dwReadValue<<16); - rdmalt(Adapter, 0x0f003020,&dwReadValue,4); - dwCompleteWord|=(dwReadValue<<24); - - *pdwData = dwCompleteWord; - - return 0; -} -#endif INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter) { @@ -655,14 +493,6 @@ INT BeceemFlashBulkRead( UINT BcmGetFlashSize(PMINI_ADAPTER Adapter) { -#if 0 - if(Adapter->bDDRInitDone) - { - return rdm(Adapter,FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT|FLASH_SIZE_ADDR); - } - - return rdm(Adapter,FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT|FLASH_SIZE_ADDR); -#endif if(IsFlash2x(Adapter)) return (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER)); else @@ -733,60 +563,6 @@ UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter) return 0; } -#if 0 -/***********************************************************************************/ -// -// WriteBeceemEEPROM: Writes 4 byte data to EEPROM offset. -// -// uiEEPROMOffset - Offset to be written to. -// uiData - Data to be written. -// -/***********************************************************************************/ - -INT WriteBeceemEEPROM(PMINI_ADAPTER Adapter,UINT uiEEPROMOffset, UINT uiData) -{ - INT Status = 0; - ULONG ulRdBk = 0; - ULONG ulRetryCount = 3; - UINT value; - - if(uiEEPROMOffset > EEPROM_END) - { - - return -1; - } - - uiData = htonl(uiData); - while(ulRetryCount--) - { - value = 0x06000000; - wrmalt(Adapter, 0x0F003018,&value, sizeof(value));//flush the EEPROM FIFO. - wrmalt(Adapter, 0x0F00301C,&uiData, sizeof(uiData)); - value = 0x3A000000 | uiEEPROMOffset; - wrmalt(Adapter, 0x0F003018,&value, sizeof(value)); - __udelay(100000); - //read back and verify. - Status = ReadBeceemEEPROM(Adapter,uiEEPROMOffset,(UINT *)&ulRdBk); - if(Status == 0) - { - if(ulRdBk == uiData) - { - return Status; - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WriteBeceemEEPROM: Readback does not match\n"); - } - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WriteBeceemEEPROM: Readback failed\n"); - } - } - - return 0; -} -#endif //----------------------------------------------------------------------------- // Procedure: FlashSectorErase @@ -1353,15 +1129,6 @@ INT BeceemFlashBulkWrite( UINT uiTemp = 0; UINT index = 0; UINT uiPartOffset = 0; - #if 0 - struct timeval tv1 = {0}; - struct timeval tv2 = {0}; - - struct timeval tr = {0}; - struct timeval te = {0}; - struct timeval tw = {0}; - struct timeval twv = {0}; - #endif #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS) Status = bcmflash_raw_write((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE),( unsigned char *)pBuffer,uiNumBytes); @@ -1396,7 +1163,6 @@ INT BeceemFlashBulkWrite( uiNumSectTobeRead++; } } - #if 1 //Check whether Requested sector is writable or not in case of flash2x write. But if write call is // for DSD calibration, allow it without checking of sector permission @@ -1417,7 +1183,6 @@ INT BeceemFlashBulkWrite( index = index + 1 ; } } - #endif Adapter->SelectedChip = RESET_CHIP_SELECT; while(uiNumSectTobeRead) { @@ -1689,21 +1454,6 @@ static INT BeceemFlashBulkWriteStatus( { for(uiIndex = 0;uiIndex < Adapter->uiSectorSize;uiIndex += MAX_RW_SIZE) { -#if 0 - if(0 == BeceemFlashBulkRead(Adapter,uiReadBk,uiOffsetFromSectStart+uiIndex + Adapter->ulFlashCalStart ,MAX_RW_SIZE)) - { - for(uiReadIndex = 0;uiReadIndex < 4; uiReadIndex++) - { - if(*((PUINT)&pTempBuff[uiIndex+uiReadIndex*4]) != uiReadBk[uiReadIndex]) - { - Status = -1; - goto BeceemFlashBulkWriteStatus_EXIT; - - } - } - - } -#endif if(STATUS_SUCCESS == BeceemFlashBulkRead(Adapter,(PUINT)ucReadBk,uiOffsetFromSectStart+uiIndex,MAX_RW_SIZE)) { @@ -3158,15 +2908,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) Adapter->uiFlashLayoutMajorVersion = uiFlashLayoutMajorVersion; - #if 0 - if(FLASH_PART_SST25VF080B == Adapter->ulFlashID) - { - // - // 1MB flash has been selected. we have to use 64K as sector size no matter what is kept in FLASH_CS. - // - Adapter->uiSectorSize = 0x10000; - } - #endif return STATUS_SUCCESS ; } @@ -4837,20 +4578,6 @@ INT BcmCopySection(PMINI_ADAPTER Adapter, return -EINVAL; } - #if 0 - else - { - if((SrcSection == VSA0) || (SrcSection == VSA1) || (SrcSection == VSA2)) - { - if((DstSection != VSA0) && (DstSection != VSA1) && (DstSection != VSA2)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Source and Destion secton is not of same type"); - return -EINVAL; - } - } - - } - #endif //if offset zero means have to copy complete secton if(numOfBytes == 0) @@ -4950,14 +4677,6 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset) UINT uiSectAlignAddr = 0; UINT sig = 0; - #if 0 - //if Chenges in Header is allowed, Return back - if(Adapter->bHeaderChangeAllowed == TRUE) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Header Change is allowed"); - return STATUS_SUCCESS ; - } - #endif //making the offset sector alligned uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1); @@ -5336,39 +5055,6 @@ INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter, return Status; } -#if 0 -UINT getNumOfSubSectionWithWRPermisson(PMINI_ADAPTER Adapter, SECTION_TYPE secType) -{ - - UINT numOfWRSubSec = 0; - switch(secType) - { - case ISO : - if(IsSectionWritable(Adapter,ISO_IMAGE1)) - numOfWRSubSec = numOfWRSubSec + 1; - if(IsSectionWritable(Adapter,ISO_IMAGE2)) - numOfWRSubSec = numOfWRSubSec + 1; - break; - - case DSD : - if(IsSectionWritable(Adapter,DSD2)) - numOfWRSubSec = numOfWRSubSec + 1; - if(IsSectionWritable(Adapter,DSD1)) - numOfWRSubSec = numOfWRSubSec + 1; - if(IsSectionWritable(Adapter,DSD0)) - numOfWRSubSec = numOfWRSubSec + 1; - break ; - - case VSA : - //for VSA Add code Here - default : - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Invalid secton<%d> is passed", secType);\ - numOfWRSubSec = 0; - - } - return numOfWRSubSec; -} -#endif BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section) { -- cgit v1.2.3 From 0980f2e8144ea0021a09be41176b736d76ca3db7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 00:04:52 -0400 Subject: beceem: reserve one queue for bit-bucket This preserves the semantics of the original driver (unclassified packets are dropped), but does it in a clean way; and fixes crash when packet is sent to offline device. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/InterfaceInit.c | 3 ++- drivers/staging/bcm/Macros.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index dddf34bb7c8b..801ba65e9785 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -188,7 +188,8 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) PS_INTERFACE_ADAPTER psIntfAdapter; struct net_device *ndev; - ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES); + /* Reserve one extra queue for the bit-bucket */ + ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1); if(ndev == NULL) { dev_err(&udev->dev, DRV_NAME ": no memory for device\n"); return -ENOMEM; diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h index 14df2f86b14e..f2fd60286a4c 100644 --- a/drivers/staging/bcm/Macros.h +++ b/drivers/staging/bcm/Macros.h @@ -261,7 +261,7 @@ typedef enum _E_PHS_DSC_ACTION #define FIRMWARE_BEGIN_ADDR 0xBFC00000 -#define INVALID_QUEUE_INDEX (USHORT)-1 +#define INVALID_QUEUE_INDEX (NO_OF_QUEUES+1) #define INVALID_PID (pid_t)-1 #define DDR_80_MHZ 0 -- cgit v1.2.3 From c5ebe2278ba600ff48663ec84c6e7f34d291503f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 08:42:44 -0400 Subject: beceem: fix printf format strings Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/LeakyBucket.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c index f9e8f2bb06d3..669acc8d088b 100644 --- a/drivers/staging/bcm/LeakyBucket.c +++ b/drivers/staging/bcm/LeakyBucket.c @@ -82,7 +82,7 @@ static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF) if(NULL == Adapter || (psSF < Adapter->PackInfo && (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority])) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %ld\n", Adapter, (psSF-Adapter->PackInfo)); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo)); return 0; } @@ -94,14 +94,14 @@ static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF) } else { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %ld Available %u\n", + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n", psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount); psSF->uiPendedLast = 1; } } else { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %ld not valid\n", psSF-Adapter->PackInfo); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo); } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <==="); return 0; @@ -164,7 +164,7 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF) int iPacketLen=0; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%ld ====>", (psSF-Adapter->PackInfo)); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo)); if((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount))//Get data packet { if(!psSF->ucDirection ) @@ -212,7 +212,7 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF) } else { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %ld\n", psSF-Adapter->PackInfo); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n", psSF->uiCurrentTokenCount, iPacketLen); //this part indicates that becuase of non-availability of the tokens -- cgit v1.2.3 From ada692b09f4707a8e06b087b1546d9f5b3f2d37d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 09:26:47 -0400 Subject: beceem: fix character device ioctl Sparse caught several places where ioctl interface was incorrectly using user memory. Fix all the ioctl cases for casting and __user annotation. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmchar.c | 796 ++++++++++++++------------------------- drivers/staging/bcm/HostMibs.h | 7 - drivers/staging/bcm/Prototypes.h | 6 +- drivers/staging/bcm/headers.h | 1 - drivers/staging/bcm/hostmibs.c | 24 +- 5 files changed, 282 insertions(+), 552 deletions(-) delete mode 100644 drivers/staging/bcm/HostMibs.h (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 6c9db7227ca2..3a1b9903bf07 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -102,11 +102,11 @@ static int bcm_char_release(struct inode *inode, struct file *filp) static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos) { - PPER_TARANG_DATA pTarang = (PPER_TARANG_DATA)filp->private_data; + PPER_TARANG_DATA pTarang = filp->private_data; PMINI_ADAPTER Adapter = pTarang->Adapter; - struct sk_buff* Packet = NULL; - UINT PktLen = 0; - int wait_ret_val=0; + struct sk_buff* Packet = NULL; + ssize_t PktLen = 0; + int wait_ret_val=0; wait_ret_val = wait_event_interruptible(Adapter->process_read_wait_queue, (pTarang->RxAppControlHead || Adapter->device_removed)); @@ -145,7 +145,9 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nReturning from copy to user failure \n"); return -EFAULT; } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read %d Bytes From Adapter packet = 0x%p by process %d!\n", PktLen, Packet, current->pid); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Read %zd Bytes From Adapter packet = %p by process %d!\n", + PktLen, Packet, current->pid); dev_kfree_skb(Packet); } @@ -155,15 +157,12 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { - PPER_TARANG_DATA pTarang = (PPER_TARANG_DATA)filp->private_data; - void __user *argp = (void __user *)argp; + PPER_TARANG_DATA pTarang = filp->private_data; + void __user *argp = (void __user *)arg; PMINI_ADAPTER Adapter = pTarang->Adapter; INT Status = STATUS_FAILURE; - IOCTL_BUFFER IoBuffer={}; -#ifndef BCM_SHM_INTERFACE - int timeout = 0; -#endif - + int timeout = 0; + IOCTL_BUFFER IoBuffer; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", cmd, arg); @@ -204,49 +203,40 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status = vendorextnIoctl(Adapter, cmd, arg); if(Status != CONTINUE_COMMON_PATH ) - { return Status; - } switch(cmd){ // Rdms for Swin Idle... case IOCTL_BCM_REGISTER_READ_PRIVATE: { RDM_BUFFER sRdmBuffer = {0}; - PCHAR temp_buff = NULL; - UINT Bufflen = 0; + PCHAR temp_buff; + UINT Bufflen; + /* Copy Ioctl Buffer structure */ - if(copy_from_user((PCHAR)&IoBuffer, argp, - sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sRdmBuffer)) + return -EINVAL; + if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; + + /* FIXME: need to restrict BuffLen */ Bufflen = IoBuffer.OutputLength + (4 - IoBuffer.OutputLength%4)%4; - temp_buff = (PCHAR)kmalloc(Bufflen, GFP_KERNEL); + temp_buff = kmalloc(Bufflen, GFP_KERNEL); if(!temp_buff) - { - return STATUS_FAILURE; - } - if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, - IoBuffer.InputLength)) - { - Status = -EFAULT; - break; - } + return -ENOMEM; + Status = rdmalt(Adapter, (UINT)sRdmBuffer.Register, (PUINT)temp_buff, Bufflen); - if(Status != STATUS_SUCCESS) - { - kfree(temp_buff); - return Status; - } - if(copy_to_user(IoBuffer.OutputBuffer, - (PCHAR)temp_buff, (UINT)IoBuffer.OutputLength)) + if(Status == STATUS_SUCCESS) { - Status = -EFAULT; + if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength)) + Status = -EFAULT; } + kfree(temp_buff); break; } @@ -256,19 +246,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) UINT uiTempVar=0; /* Copy Ioctl Buffer structure */ - if(copy_from_user(&IoBuffer, argp, - sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sWrmBuffer)) + return -EINVAL; + /* Get WrmBuffer structure */ - if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, - IoBuffer.InputLength)) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; + uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; if(!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && ((uiTempVar == EEPROM_REJECT_REG_1)|| @@ -277,8 +264,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (uiTempVar == EEPROM_REJECT_REG_4))) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n"); - Status = -EFAULT; - break; + return -EFAULT; } Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register, (PUINT)sWrmBuffer.Data, sizeof(ULONG)); @@ -305,53 +291,38 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (Adapter->bPreparingForLowPowerMode ==TRUE)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Rdms\n"); - Status = -EACCES; - break; + return -EACCES; } /* Copy Ioctl Buffer structure */ - if(copy_from_user(&IoBuffer, argp, - sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sRdmBuffer)) + return -EINVAL; + + if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; - temp_buff = (PCHAR)kmalloc(IoBuffer.OutputLength, GFP_KERNEL); + /* FIXME: don't trust user supplied length */ + temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL); if(!temp_buff) - { return STATUS_FAILURE; - } - if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, - IoBuffer.InputLength)) - { - Status = -EFAULT; - break; - } - if( - (((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) || - ((ULONG)sRdmBuffer.Register & 0x3) - ) + if((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) || + ((ULONG)sRdmBuffer.Register & 0x3)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "RDM Done On invalid Address : %x Access Denied.\n", (int)sRdmBuffer.Register); - Status = -EINVAL; - break; + return -EINVAL; } uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK; Status = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, (PUINT)temp_buff, IoBuffer.OutputLength); - if(Status != STATUS_SUCCESS) - { - kfree(temp_buff); - return Status; - } - if(copy_to_user(IoBuffer.OutputBuffer, - (PCHAR)temp_buff, (UINT)IoBuffer.OutputLength)) - { - Status = -EFAULT; - } + if(Status == STATUS_SUCCESS) + if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength)) + Status = -EFAULT; + kfree(temp_buff); break; } @@ -365,34 +336,28 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (Adapter->bPreparingForLowPowerMode ==TRUE)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Wrms\n"); - Status = -EACCES; - break; + return -EACCES; } + /* Copy Ioctl Buffer structure */ - if(copy_from_user((PCHAR)&IoBuffer, argp, - sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sWrmBuffer)) + return -EINVAL; + /* Get WrmBuffer structure */ - if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, - IoBuffer.InputLength)) - { - Status = -EFAULT; - break; - } - if( + if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; - (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) || - ((ULONG)sWrmBuffer.Register & 0x3) - ) + if( (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) || + ((ULONG)sWrmBuffer.Register & 0x3) ) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)sWrmBuffer.Register); - Status = -EINVAL; - break; + return -EINVAL; } + uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; if(!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && ((uiTempVar == EEPROM_REJECT_REG_1)|| @@ -402,8 +367,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (cmd == IOCTL_BCM_REGISTER_WRITE)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n"); - Status = -EFAULT; - break; + return -EFAULT; } Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register, @@ -432,19 +396,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) (Adapter->bPreparingForLowPowerMode ==TRUE)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"GPIO Can't be set/clear in Low power Mode"); - Status = -EACCES; - break; + return -EACCES; } if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } + return -EFAULT; + if (IoBuffer.InputLength > sizeof(gpio_info)) + return -EINVAL; if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) - { - Status = -EFAULT; - break; - } + return -EFAULT; uiBit = gpio_info.uiGpioNumber; uiOperation = gpio_info.uiGpioValue; @@ -513,8 +472,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) break; case BCM_LED_THREAD_STATE_CHANGE_REQ: { - - USER_THREAD_REQ threadReq = {0}; + USER_THREAD_REQ threadReq = { 0 }; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"User made LED thread InActive"); if((Adapter->IdleMode == TRUE) || @@ -525,21 +483,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status = -EACCES; break; } - Status =copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status); - Status = -EFAULT; - break; - } - Status= copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the InputBuffer from user space err:%d",Status); - Status = -EFAULT; - break; - } + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(threadReq)) + return -EINVAL; + + if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; + //if LED thread is running(Actively or Inactively) set it state to make inactive if(Adapter->LEDInfo.led_thread_running) { @@ -568,19 +521,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if((Adapter->IdleMode == TRUE) || (Adapter->bShutStatus ==TRUE) || (Adapter->bPreparingForLowPowerMode ==TRUE)) - { - Status = -EACCES; - break; - } - if(copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER))) { - Status = -EFAULT; - break; - } - if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) - { - Status = -EFAULT; - break; - } + return -EACCES; + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + if (IoBuffer.InputLength > sizeof(gpio_info)) + return -EINVAL; + if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; uiBit = gpio_info.uiGpioNumber; //Set the gpio output register Status = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, @@ -604,25 +551,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if((Adapter->IdleMode == TRUE) || (Adapter->bShutStatus ==TRUE) || (Adapter->bPreparingForLowPowerMode ==TRUE)) - { - Status = -EINVAL; - break; - } - Status = copy_from_user( (PCHAR)&IoBuffer, argp, sizeof( IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status); - Status = -EFAULT; - break; - } + return -EINVAL; + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + if (IoBuffer.InputLength > sizeof(gpio_multi_info)) + return -EINVAL; + if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; - Status = copy_from_user( &gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer Contents from user space err:%d",Status); - Status = -EFAULT; - break; - } if(IsReqGpioIsLedInNVM(Adapter,pgpio_multi_info[WIMAX_IDX].uiGPIOMask)== FALSE) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",pgpio_multi_info[WIMAX_IDX].uiGPIOMask,Adapter->gpioBitMap); @@ -682,7 +618,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying Content to IOBufer for user space err:%d",Status); - Status = -EFAULT; break; } } @@ -696,25 +631,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if((Adapter->IdleMode == TRUE) || (Adapter->bShutStatus ==TRUE) || (Adapter->bPreparingForLowPowerMode ==TRUE)) - { - Status = -EINVAL; - break; - } - Status = copy_from_user(&IoBuffer, argp, sizeof( IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status); - Status = -EFAULT; - break; - } + return -EINVAL; - Status = copy_from_user( &gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer Contents from user space err:%d",Status); - Status = -EFAULT; - break; - } + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + if (IoBuffer.InputLength > sizeof(gpio_multi_mode)) + return -EINVAL; + if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; Status = rdmaltWithLock( Adapter, ( UINT) GPIO_MODE_REGISTER, ( PUINT) ucResetValue, sizeof( UINT)); if( STATUS_SUCCESS != Status) @@ -765,7 +689,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying Content to IOBufer for user space err:%d",Status); - Status = -EFAULT; break; } } @@ -779,21 +702,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) case IOCTL_IDLE_REQ: { PVOID pvBuffer=NULL; + /* Copy Ioctl Buffer structure */ - if(copy_from_user(&IoBuffer, argp, - sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } - pvBuffer=kmalloc(IoBuffer.InputLength, GFP_KERNEL); + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + /* FIXME: don't accept any length from user */ + pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL); if(!pvBuffer) - { return -ENOMEM; - } - if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, - IoBuffer.InputLength)) + if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) { Status = -EFAULT; kfree(pvBuffer); @@ -839,7 +758,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status = reset_card_proc(Adapter); if(Status) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "reset_card_proc Failed!\n"); + pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name); up(&Adapter->fw_download_sema); up(&Adapter->NVMRdmWrmLock); break; @@ -857,7 +776,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } case IOCTL_BCM_BUFFER_DOWNLOAD: { - FIRMWARE_INFO *psFwInfo=NULL; + FIRMWARE_INFO *psFwInfo = NULL; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid); do{ if(!down_trylock(&Adapter->fw_download_sema)) @@ -866,29 +785,23 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status=-EINVAL; break; } + /* Copy Ioctl Buffer structure */ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n"); - Status = -EFAULT; - break; - } + return -EFAULT; + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Length for FW DLD is : %lx\n", IoBuffer.InputLength); - psFwInfo=kmalloc(sizeof(*psFwInfo), GFP_KERNEL); + + if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO)) + return -EINVAL; + + psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL); if(!psFwInfo) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Failed to allocate buffer!!!!\n"); - Status = -ENOMEM; - break; - } - if(copy_from_user(psFwInfo, IoBuffer.InputBuffer, - IoBuffer.InputLength)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_from_user 2 failed\n"); - Status = -EFAULT; - break; - } + return -ENOMEM; + + if(copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; if(!psFwInfo->pvMappedFirmwareAddress || (psFwInfo->u32FirmwareLength == 0)) @@ -941,7 +854,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Adapter->bBinDownloaded=TRUE; Adapter->bCfgDownloaded=TRUE; atomic_set(&Adapter->CurrNumFreeTxDesc, 0); - atomic_set(&Adapter->RxRollOverCount, 0); + Adapter->CurrNumRecvDescs=0; Adapter->downloadDDR = 0; @@ -1038,22 +951,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) break; case IOCTL_GET_PACK_INFO: - if(copy_to_user(argp, &Adapter->PackInfo, - sizeof(PacketInfo)*NO_OF_QUEUES)) - { - Status = -EFAULT; - break; - } + if(copy_to_user(argp, &Adapter->PackInfo, sizeof(PacketInfo)*NO_OF_QUEUES)) + return -EFAULT; Status = STATUS_SUCCESS; break; case IOCTL_BCM_SWITCH_TRANSFER_MODE: { UINT uiData = 0; if(copy_from_user(&uiData, argp, sizeof(UINT))) - { - Status = -EFAULT; - break; - } + return -EFAULT; + if(uiData) /* Allow All Packets */ { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n"); @@ -1072,22 +979,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { /* Copy Ioctl Buffer structure */ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } - if(copy_to_user(IoBuffer.OutputBuffer, - VER_FILEVERSION_STR, (UINT)IoBuffer.OutputLength)) - { - Status = -EFAULT; - break; - } + return -EFAULT; + + if(copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, IoBuffer.OutputLength)) + return -EFAULT; Status = STATUS_SUCCESS; break; } case IOCTL_BCM_GET_CURRENT_STATUS: { - LINK_STATE *plink_state = NULL; + LINK_STATE link_state; + /* Copy Ioctl Buffer structure */ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) { @@ -1095,12 +997,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status = -EFAULT; break; } - plink_state = (LINK_STATE*)arg; - plink_state->bIdleMode = (UCHAR)Adapter->IdleMode; - plink_state->bShutdownMode = Adapter->bShutStatus; - plink_state->ucLinkStatus = (UCHAR)Adapter->LinkStatus; - if(copy_to_user(IoBuffer.OutputBuffer, - (PUCHAR)plink_state, (UINT)IoBuffer.OutputLength)) + + + memset(&link_state, 0, sizeof(link_state)); + link_state.bIdleMode = Adapter->IdleMode; + link_state.bShutdownMode = Adapter->bShutStatus; + link_state.ucLinkStatus = Adapter->LinkStatus; + + if (copy_to_user(IoBuffer.OutputBuffer, &link_state, + min_t(size_t, sizeof(link_state), IoBuffer.OutputLength))) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n"); Status = -EFAULT; @@ -1112,17 +1017,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) case IOCTL_BCM_SET_MAC_TRACING: { UINT tracing_flag; + /* copy ioctl Buffer structure */ - if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } - if(copy_from_user(&tracing_flag, IoBuffer.InputBuffer,sizeof(UINT))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if(copy_from_user(&tracing_flag,IoBuffer.InputBuffer,sizeof(UINT))) + return -EFAULT; + if (tracing_flag) Adapter->pTarangs->MacTracingEnabled = TRUE; else @@ -1132,70 +1034,51 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) case IOCTL_BCM_GET_DSX_INDICATION: { ULONG ulSFId=0; - if(copy_from_user((PCHAR)&IoBuffer, argp, - sizeof(IOCTL_BUFFER))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Invalid IO buffer!!!" ); - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + if(IoBuffer.OutputLength < sizeof(stLocalSFAddIndicationAlt)) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Mismatch req: %lx needed is =0x%zx!!!", - IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt)); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, + "Mismatch req: %lx needed is =0x%zx!!!", + IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt)); return -EINVAL; } - if(copy_from_user(&ulSFId, IoBuffer.InputBuffer, - sizeof(ulSFId))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Invalid SFID!!! %lu", ulSFId ); - Status = -EFAULT; - break; - } + + if(copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId))) + return -EFAULT; + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Get DSX Data SF ID is =%lx\n", ulSFId ); - get_dsx_sf_data_to_application(Adapter, ulSFId, - IoBuffer.OutputBuffer); + get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer); Status=STATUS_SUCCESS; } break; case IOCTL_BCM_GET_HOST_MIBS: { - PCHAR temp_buff; + PVOID temp_buff; if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_from user for IoBuff failed\n"); - Status = -EFAULT; - break; - } + return -EFAULT; if(IoBuffer.OutputLength != sizeof(S_MIBS_HOST_STATS_MIBS)) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Length Check failed %lu %zd\n", IoBuffer.OutputLength, - sizeof(S_MIBS_HOST_STATS_MIBS)); - return -EINVAL; + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, + "Length Check failed %lu %zd\n", + IoBuffer.OutputLength, sizeof(S_MIBS_HOST_STATS_MIBS)); + return -EINVAL; } - temp_buff = (PCHAR)kmalloc(IoBuffer.OutputLength, GFP_KERNEL); - + /* FIXME: HOST_STATS are too big for kmalloc (122048)! */ + temp_buff = kzalloc(sizeof(S_MIBS_HOST_STATS_MIBS), GFP_KERNEL); if(!temp_buff) - { return STATUS_FAILURE; - } - - Status = ProcessGetHostMibs(Adapter, - (PUCHAR)temp_buff, IoBuffer.OutputLength); - Status = GetDroppedAppCntrlPktMibs((PVOID)temp_buff, - (PPER_TARANG_DATA)filp->private_data); + Status = ProcessGetHostMibs(Adapter, temp_buff); + GetDroppedAppCntrlPktMibs(temp_buff, pTarang); - if(copy_to_user(IoBuffer.OutputBuffer,(PCHAR)temp_buff, - sizeof(S_MIBS_HOST_STATS_MIBS))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy to user failed\n"); - kfree(temp_buff); - return -EFAULT; - } + if (Status != STATUS_FAILURE) + if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(S_MIBS_HOST_STATS_MIBS))) + Status = -EFAULT; kfree(temp_buff); break; @@ -1225,22 +1108,18 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) Status = -EACCES; break; } + /* Copy Ioctl Buffer structure */ - if(copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; - pvBuffer=kmalloc(IoBuffer.InputLength, GFP_KERNEL); + /* FIXME: restrict length */ + pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL); if(!pvBuffer) - { return -ENOMEM; - break; - } /* Get WrmBuffer structure */ - if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) + if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) { kfree(pvBuffer); Status = -EFAULT; @@ -1288,25 +1167,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } case IOCTL_BCM_GET_NVM_SIZE: - { - if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - //IOLog("failed NVM first"); - Status = -EFAULT; - break; - } + return -EFAULT; + if(Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH ) { - if(copy_to_user(IoBuffer.OutputBuffer, - (unsigned char *)&Adapter->uiNVMDSDSize, (UINT)sizeof(UINT))) - { - Status = -EFAULT; - return Status; - } + if(copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, sizeof(UINT))) + return -EFAULT; } - Status = STATUS_SUCCESS ; - } break; case IOCTL_BCM_CAL_INIT : @@ -1315,38 +1183,26 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) UINT uiSectorSize = 0 ; if(Adapter->eNVMType == NVM_FLASH) { - Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy From User space failed. status :%d", Status); + if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) return -EFAULT; - } - uiSectorSize = *((PUINT)(IoBuffer.InputBuffer)); /* FIXME: unchecked __user access */ + + if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, sizeof(UINT))) + return -EFAULT; + if((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE)) { - - Status = copy_to_user(IoBuffer.OutputBuffer, - (unsigned char *)&Adapter->uiSectorSize , - (UINT)sizeof(UINT)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Coping the sector size to use space failed. status:%d",Status); - return -EFAULT; - } + if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize, + sizeof(UINT))) + return -EFAULT; } else { if(IsFlash2x(Adapter)) { - Status = copy_to_user(IoBuffer.OutputBuffer, - (unsigned char *)&Adapter->uiSectorSize , - (UINT)sizeof(UINT)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Coping the sector size to use space failed. status:%d",Status); - return -EFAULT; - } - + if (copy_to_user(IoBuffer.OutputBuffer, + &Adapter->uiSectorSize , + sizeof(UINT))) + return -EFAULT; } else { @@ -1370,25 +1226,19 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } break; case IOCTL_BCM_SET_DEBUG : +#ifdef DEBUG { USER_BCM_DBG_STATE sUserDebugState; // BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Entered the ioctl %x \n", IOCTL_BCM_SET_DEBUG ); BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In SET_DEBUG ioctl\n"); - Status = copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy from user failed\n"); - Status = -EFAULT; - break; - } - Status = copy_from_user(&sUserDebugState,IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE)); - if(Status) - { - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IoBuffer.InputBuffer failed"); + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + + if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE))) return -EFAULT; - } + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ", sUserDebugState.OnOff, sUserDebugState.Type); @@ -1411,15 +1261,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) BCM_SHOW_DEBUG_BITMAP(Adapter); } +#endif break; case IOCTL_BCM_NVM_READ: case IOCTL_BCM_NVM_WRITE: { - - NVM_READWRITE stNVMReadWrite = {}; + NVM_READWRITE stNVMReadWrite; PUCHAR pReadData = NULL; - void __user * pBuffertobeCopied = NULL; - ULONG ulDSDMagicNumInUsrBuff = 0 ; + ULONG ulDSDMagicNumInUsrBuff = 0; struct timeval tv0, tv1; memset(&tv0,0,sizeof(struct timeval)); memset(&tv1,0,sizeof(struct timeval)); @@ -1444,21 +1293,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) /* Copy Ioctl Buffer structure */ if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copy_from_user failed\n"); - Status = -EFAULT; - break; - } - if(IOCTL_BCM_NVM_READ == cmd) - pBuffertobeCopied = IoBuffer.OutputBuffer; - else - pBuffertobeCopied = IoBuffer.InputBuffer; + return -EFAULT; - if(copy_from_user(&stNVMReadWrite, pBuffertobeCopied,sizeof(NVM_READWRITE))) - { - Status = -EFAULT; - break; - } + if(copy_from_user(&stNVMReadWrite, + (IOCTL_BCM_NVM_READ == cmd) ? IoBuffer.OutputBuffer : IoBuffer.InputBuffer, + sizeof(NVM_READWRITE))) + return -EFAULT; // // Deny the access if the offset crosses the cal area limit. @@ -1471,13 +1311,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) break; } - pReadData =(PCHAR)kmalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL); - + pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL); if(!pReadData) return -ENOMEM; - memset(pReadData,0,stNVMReadWrite.uiNumBytes); - if(copy_from_user(pReadData, stNVMReadWrite.pBuffer, stNVMReadWrite.uiNumBytes)) { @@ -1511,8 +1348,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) kfree(pReadData); return Status; } - if(copy_to_user(stNVMReadWrite.pBuffer, - pReadData, (UINT)stNVMReadWrite.uiNumBytes)) + if(copy_to_user(stNVMReadWrite.pBuffer,pReadData, stNVMReadWrite.uiNumBytes)) { kfree(pReadData); Status = -EFAULT; @@ -1604,7 +1440,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) UINT BuffSize = 0; UINT ReadBytes = 0; UINT ReadOffset = 0; - char __user *OutPutBuff = NULL; + void __user *OutPutBuff; if(IsFlash2x(Adapter) != TRUE) { @@ -1613,20 +1449,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called"); - Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) return -EFAULT; - } //Reading FLASH 2.x READ structure - Status = copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,sizeof(FLASH2X_READWRITE)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of Input Buffer failed"); + if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,sizeof(FLASH2X_READWRITE))) return -EFAULT; - } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.Section :%x" ,sFlash2xRead.Section); @@ -1690,7 +1518,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Copy to use failed with status :%d", Status); - Status = -EFAULT; break; } NOB = NOB - ReadBytes; @@ -1709,8 +1536,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) case IOCTL_BCM_FLASH2X_SECTION_WRITE : { FLASH2X_READWRITE sFlash2xWrite = {0}; - PUCHAR pWriteBuff = NULL; - void __user *InputAddr = NULL; + PUCHAR pWriteBuff; + void __user *InputAddr; UINT NOB = 0; UINT BuffSize = 0; UINT WriteOffset = 0; @@ -1727,20 +1554,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " IOCTL_BCM_FLASH2X_SECTION_WRITE Called"); - Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) return -EFAULT; - } //Reading FLASH 2.x READ structure - Status = copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Reading of output Buffer from IOCTL buffer fails"); + if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE))) return -EFAULT; - } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.Section :%x" ,sFlash2xWrite.Section); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.offset :%d" ,sFlash2xWrite.offset); @@ -1765,12 +1584,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) else BuffSize = NOB ; - pWriteBuff = (PCHAR)kmalloc(BuffSize, GFP_KERNEL); + pWriteBuff = kmalloc(BuffSize, GFP_KERNEL); if(pWriteBuff == NULL) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for Flash 2.x Read Structure"); return -ENOMEM; - } + //extracting the remainder of the given offset. WriteBytes = Adapter->uiSectorSize ; @@ -1798,7 +1615,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy to user failed with status :%d", Status); - Status = -EFAULT; break ; } BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pWriteBuff,WriteBytes); @@ -1832,22 +1648,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP : { - PFLASH2X_BITMAP psFlash2xBitMap = NULL ; + PFLASH2X_BITMAP psFlash2xBitMap; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called"); - Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) return -EFAULT; - } + if(IoBuffer.OutputLength != sizeof(FLASH2X_BITMAP)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Structure size mismatch Lib :0x%lx Driver :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH2X_BITMAP)); - break; - } + return -EINVAL; - psFlash2xBitMap = (PFLASH2X_BITMAP)kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL); + psFlash2xBitMap = kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL); if(psFlash2xBitMap == NULL) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory is not available"); @@ -1868,13 +1678,9 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap); up(&Adapter->NVMRdmWrmLock); - Status = copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x bitMap failed"); - kfree(psFlash2xBitMap); - return -EFAULT; - } + if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP))) + Status = -EFAULT; + kfree(psFlash2xBitMap); } break ; @@ -1893,14 +1699,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return -EFAULT; + return Status; } Status = copy_from_user(&eFlash2xSectionVal,IoBuffer.InputBuffer, sizeof(INT)); if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed"); - return -EFAULT; + return Status; } down(&Adapter->NVMRdmWrmLock); @@ -1948,14 +1754,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status); - return -EFAULT; + return Status; } - Status = copy_from_user(&sCopySectStrut,IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION)); + Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION)); if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status); - return -EFAULT; + return Status; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Destination SEction :%x", sCopySectStrut.DstSection); @@ -2026,7 +1832,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - Status = -EFAULT; break; } if(Adapter->eNVMType != NVM_FLASH) @@ -2039,35 +1844,18 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { if(IoBuffer.OutputLength < sizeof(FLASH2X_CS_INFO)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Passed buffer size:0x%lX is insufficient for the CS structure.. \nRequired size :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH2X_CS_INFO)); - Status = -EINVAL; - break; - } + return -EINVAL; - Status = copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x cs info failed"); - Status = -EFAULT; - break; - } + if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO))) + return -EFAULT; } else { if(IoBuffer.OutputLength < sizeof(FLASH_CS_INFO)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Passed buffer size:0x%lX is insufficient for the CS structure.. Required size :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH_CS_INFO)); - Status = -EINVAL; - break; - } - Status = copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash CS info failed"); - Status = -EFAULT; - break; - } + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO))) + return -EFAULT; } } @@ -2089,13 +1877,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return -EFAULT; + return Status; } - Status = copy_from_user(&eFlash2xSectionVal,IoBuffer.InputBuffer, sizeof(INT)); + Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT)); if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed"); - return -EFAULT; + return Status; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Read Section :%d", eFlash2xSectionVal); @@ -2125,13 +1913,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) case IOCTL_BCM_NVM_RAW_READ : { - NVM_READWRITE stNVMRead = {}; + NVM_READWRITE stNVMRead; INT NOB ; INT BuffSize ; INT ReadOffset = 0; UINT ReadBytes = 0 ; - PUCHAR pReadBuff = NULL ; - char __user *OutPutBuff = NULL ; + PUCHAR pReadBuff; + void __user *OutPutBuff; if(Adapter->eNVMType != NVM_FLASH) { @@ -2148,10 +1936,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) } if(copy_from_user(&stNVMRead, IoBuffer.OutputBuffer,sizeof(NVM_READWRITE))) - { - Status = -EFAULT; - break; - } + return -EFAULT; NOB = stNVMRead.uiNumBytes; //In Raw-Read max Buff size : 64MB @@ -2161,11 +1946,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) else BuffSize = NOB ; - ReadOffset = stNVMRead.uiOffset ; + ReadOffset = stNVMRead.uiOffset; OutPutBuff = stNVMRead.pBuffer; - - pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL); + pReadBuff = kzalloc(BuffSize , GFP_KERNEL); if(pReadBuff == NULL) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for Flash 2.x Read Structure"); @@ -2200,13 +1984,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) break; } - BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pReadBuff, ReadBytes); + BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pReadBuff,ReadBytes); Status = copy_to_user(OutPutBuff, pReadBuff,ReadBytes); if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy to use failed with status :%d", Status); - Status = -EFAULT; break; } NOB = NOB - ReadBytes; @@ -2232,7 +2015,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"copy of Ioctl buffer is failed from user space"); - Status = -EFAULT; break; } @@ -2240,7 +2022,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) if(Status) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"copy of control bit mask failed from user space"); - Status = -EFAULT; break; } BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask); @@ -2259,66 +2040,41 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) DevInfo.u32NVMType = Adapter->eNVMType; DevInfo.u32InterfaceType = BCM_USB; - Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - Status = -EFAULT; - break; - } + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + if(IoBuffer.OutputLength < sizeof(DevInfo)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"User Passed buffer length is less than actural buffer size"); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"user passed buffer size :0x%lX, expected size :0x%zx",IoBuffer.OutputLength, sizeof(DevInfo)); - Status = -EINVAL; - break; - } - Status = copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copying Dev info structure to user space buffer failed"); - Status = -EFAULT; - break; - } + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo))) + return -EFAULT; } break ; case IOCTL_BCM_TIME_SINCE_NET_ENTRY: { ST_TIME_ELAPSED stTimeElapsedSinceNetEntry = {0}; - struct timeval tv = {0} ; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_BCM_TIME_SINCE_NET_ENTRY called"); - Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - Status = -EFAULT; - break; - } + if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER))) + return -EFAULT; + if(IoBuffer.OutputLength < sizeof(ST_TIME_ELAPSED)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"User Passed buffer length:0x%lx is less than expected buff size :0x%zX",IoBuffer.OutputLength,sizeof(ST_TIME_ELAPSED)); - Status = -EINVAL; - break; - } + return -EINVAL; - //stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = Adapter->liTimeSinceLastNetEntry; - do_gettimeofday(&tv); - stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = tv.tv_sec - Adapter->liTimeSinceLastNetEntry; + stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = get_seconds() - Adapter->liTimeSinceLastNetEntry; - Status = copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED)); - if(Status) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copying ST_TIME_ELAPSED structure to user space buffer failed"); - Status = -EFAULT; - break; - } + if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED))) + return -EFAULT; } break; + case IOCTL_CLOSE_NOTIFICATION: + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_CLOSE_NOTIFICATION"); + break; + default: pr_info(DRV_NAME ": unknown ioctl cmd=%#x\n", cmd); Status = STATUS_FAILURE; diff --git a/drivers/staging/bcm/HostMibs.h b/drivers/staging/bcm/HostMibs.h deleted file mode 100644 index 28a578311378..000000000000 --- a/drivers/staging/bcm/HostMibs.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _HOST_MIBS_H -#define _HOST_MIBS_H - -INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, - PVOID ioBuffer, - ULONG inputBufferLength); -#endif diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index a4b57bb07fa1..c9e1d61efe5f 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -108,10 +108,8 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter); void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer); -int ProcessGetHostMibs(PMINI_ADAPTER Adapter, PVOID ioBuffer, - ULONG inputBufferLength); - -int GetDroppedAppCntrlPktMibs(PVOID ioBuffer, PPER_TARANG_DATA pTarang); +int ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *buf); +void GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *ioBuffer, PPER_TARANG_DATA pTarang); void beceem_parse_target_struct(PMINI_ADAPTER Adapter); void doPowerAutoCorrection(PMINI_ADAPTER psAdapter); diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index 0fdee9528617..473f11eebf7c 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -56,7 +56,6 @@ #include "CmHost.h" #include "DDRInit.h" #include "Debug.h" -#include "HostMibs.h" #include "IPv6ProtocolHdr.h" #include "PHSModule.h" #include "Protocol.h" diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index 0d75ff7add75..144590037b24 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -10,12 +10,8 @@ */ #include "headers.h" -INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, - PVOID ioBuffer, - ULONG inputBufferLength) +INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs) { - - S_MIBS_HOST_STATS_MIBS *pstHostMibs = NULL; S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL; S_PHS_RULE *pstPhsRule = NULL; S_CLASSIFIER_TABLE *pstClassifierTable = NULL; @@ -30,15 +26,6 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, return STATUS_FAILURE; } - if(ioBuffer == NULL) - { - return -EINVAL; - } - memset(ioBuffer,0,sizeof(S_MIBS_HOST_STATS_MIBS)); - - pstHostMibs = (S_MIBS_HOST_STATS_MIBS *)ioBuffer; - - //Copy the classifier Table for(nClassifierIndex=0; nClassifierIndex < MAX_CLASSIFIERS; nClassifierIndex++) @@ -115,13 +102,10 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, } -INT GetDroppedAppCntrlPktMibs(PVOID ioBuffer, PPER_TARANG_DATA pTarang) +VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, const PPER_TARANG_DATA pTarang) { - S_MIBS_HOST_STATS_MIBS *pstHostMibs = (S_MIBS_HOST_STATS_MIBS *)ioBuffer; - - memcpy((PVOID)&(pstHostMibs->stDroppedAppCntrlMsgs),(PVOID)&(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); - - return STATUS_SUCCESS ; + memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs), + &(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); } -- cgit v1.2.3 From 032100f65295d594fc0481e840efe8b6c1e398af Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 10:03:29 -0400 Subject: beceem: remove unnecessary usb class Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 2 +- drivers/staging/bcm/InterfaceInit.c | 63 +------------------------------------ 2 files changed, 2 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 9f8954bfd5bd..69cac5c7f78f 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -553,7 +553,7 @@ struct _MINI_ADAPTER struct semaphore NVMRdmWrmLock; struct device *pstCreatedClassDevice; - BOOLEAN bUsbClassDriverRegistered; + // BOOLEAN InterfaceUpStatus; PFLASH2X_CS_INFO psFlash2xCSInfo; PFLASH_CS_INFO psFlashCSInfo ; diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 801ba65e9785..6d62a50a2f48 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -63,29 +63,6 @@ VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) AdapterFree(psIntfAdapter->psAdapter); } - - -static int usbbcm_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int usbbcm_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static ssize_t usbbcm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t usbbcm_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos) -{ - return 0; -} - - VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) { ULONG ulReg = 0; @@ -164,21 +141,6 @@ VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) } -static struct file_operations usbbcm_fops = { - .open = usbbcm_open, - .release = usbbcm_release, - .read = usbbcm_read, - .write = usbbcm_write, - .owner = THIS_MODULE, - .llseek = no_llseek, -}; - -static struct usb_class_driver usbbcm_class = { - .name = "usbbcm", - .fops = &usbbcm_fops, - .minor_base = BCM_USB_MINOR_BASE, -}; - static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -259,8 +221,6 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_set_intfdata(intf, NULL); udev = interface_to_usbdev (intf); usb_put_dev(udev); - if(psAdapter->bUsbClassDriverRegistered == TRUE) - usb_deregister_dev (intf, &usbbcm_class); InterfaceAdapterFree(psIntfAdapter); return retval ; } @@ -339,10 +299,8 @@ static void usbbcm_disconnect (struct usb_interface *intf) InterfaceAdapterFree(psIntfAdapter); udev = interface_to_usbdev (intf); usb_put_dev(udev); - usb_deregister_dev (intf, &usbbcm_class); } - static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter) { int i = 0; @@ -701,18 +659,6 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) } } usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter); - retval = usb_register_dev(psIntfAdapter->interface, &usbbcm_class); - if(retval) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "usb register dev failed = %d", retval); - psIntfAdapter->psAdapter->bUsbClassDriverRegistered = FALSE; - return retval; - } - else - { - psIntfAdapter->psAdapter->bUsbClassDriverRegistered = TRUE; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "usb dev registered"); - } psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload; psIntfAdapter->psAdapter->bcm_file_readback_from_chip = @@ -734,14 +680,7 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) } - retval = device_run(psIntfAdapter); - if(retval) - { - return retval; - } - - - return 0; + return device_run(psIntfAdapter); } static int InterfaceSuspend (struct usb_interface *intf, pm_message_t message) -- cgit v1.2.3 From 957ea3b57056e79c945d8bc39fd6eeb3c2a7ed9e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 10:05:34 -0400 Subject: beceem: remove problematic debug print messages Not worth bothering to change printf format of messages which are basically noise. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/CmHost.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index d0bfdbbeee3f..c8d73d524852 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -1648,12 +1648,8 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet return 0; } ulAddrSFParamSet = ntohl(ulAddrSFParamSet); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " RestoreSFParam: Total Words of DSX Message To Read: 0x%zx From Target At : 0x%lx ", - nBytesToRead/sizeof(ULONG),ulAddrSFParamSet); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "sizeof(stServiceFlowParamSI) = %zx", sizeof(stServiceFlowParamSI)); //Read out the SF Param Set At the indicated Location - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "nBytesToRead = %x", nBytesToRead); if(rdm(Adapter, ulAddrSFParamSet, (PUCHAR)pucDestBuffer, nBytesToRead) < 0) return STATUS_FAILURE; @@ -1670,9 +1666,6 @@ static ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG ulAdd { return 0; } - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " StoreSFParam: Total Words of DSX Message To Write: 0x%zX To Target At : 0x%lX ",(nBytesToWrite/sizeof(ULONG)),ulAddrSFParamSet); - - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "WRM with %x bytes",nBytesToWrite); uiRetVal = wrm(Adapter,ulAddrSFParamSet,(PUCHAR)pucSrcBuffer, nBytesToWrite); if(uiRetVal < 0) { -- cgit v1.2.3 From 5afb5145a13ac26f3c7ab273140a83958bc038f0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 10:07:20 -0400 Subject: beceem: remove useless debug function entry messages Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 5b466174a580..9e3b872621be 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -8,7 +8,6 @@ static INT bcm_open(struct net_device *dev) { PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "======>"); if(Adapter->fw_download_done==FALSE) return -EINVAL; if(Adapter->LinkUpStatus == 1){ @@ -18,7 +17,6 @@ static INT bcm_open(struct net_device *dev) } } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "<======"); return 0; } @@ -26,12 +24,10 @@ static INT bcm_close(struct net_device *dev) { PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=====>"); if(!netif_queue_stopped(dev)) { netif_carrier_off(dev); netif_stop_queue(dev); } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"<====="); return 0; } -- cgit v1.2.3 From 46c3790eb523931a803bb3c28c5bf8bbfc8acf48 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 10:16:29 -0400 Subject: beceem: convert to kernel coding style Change indentation etc, to conform to acceptable kernel style Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 57 +++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 9e3b872621be..3525f5cf5358 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -1,34 +1,31 @@ #include "headers.h" struct net_device *gblpnetdev; -/***************************************************************************************/ -/* proto-type of lower function */ static INT bcm_open(struct net_device *dev) { - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + + if (Adapter->fw_download_done == FALSE) + return -EINVAL; - if(Adapter->fw_download_done==FALSE) - return -EINVAL; - if(Adapter->LinkUpStatus == 1){ - if(netif_queue_stopped(Adapter->dev)){ + if (Adapter->LinkUpStatus == 1) { + if (netif_queue_stopped(Adapter->dev)) { netif_carrier_on(Adapter->dev); netif_start_queue(Adapter->dev); } } - return 0; + return 0; } static INT bcm_close(struct net_device *dev) { - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); - - if(!netif_queue_stopped(dev)) { + if (!netif_queue_stopped(dev)) { netif_carrier_off(dev); - netif_stop_queue(dev); + netif_stop_queue(dev); } - return 0; + return 0; } static struct net_device_stats *bcm_get_stats(struct net_device *dev) @@ -55,52 +52,52 @@ static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb) return ClassifyPacket(netdev_priv(dev), skb); } - /******************************************************************* * Function - bcm_transmit() * * Description - This is the main transmit function for our virtual -* interface(eth0). It handles the ARP packets. It -* clones this packet and then Queue it to a suitable -* Queue. Then calls the transmit_packet(). +* interface(eth0). It handles the ARP packets. It +* clones this packet and then Queue it to a suitable +* Queue. Then calls the transmit_packet(). * * Parameter - skb - Pointer to the socket buffer structure -* dev - Pointer to the virtual net device structure +* dev - Pointer to the virtual net device structure * *********************************************************************/ static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) { - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); u16 qindex = skb_get_queue_mapping(skb); if (Adapter->device_removed || !Adapter->LinkUpStatus) goto drop; - if (Adapter->TransferMode != IP_PACKET_ONLY_MODE ) + if (Adapter->TransferMode != IP_PACKET_ONLY_MODE) goto drop; - if (INVALID_QUEUE_INDEX==qindex) + if (INVALID_QUEUE_INDEX == qindex) goto drop; - if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) + if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= + SF_MAX_ALLOWED_PACKETS_TO_BACKUP) return NETDEV_TX_BUSY; /* Now Enqueue the packet */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, - "bcm_transmit Enqueueing the Packet To Queue %d",qindex); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, + "bcm_transmit Enqueueing the Packet To Queue %d", + qindex); + spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; - *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies; + *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies; ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, Adapter->PackInfo[qindex].LastTxQueue, skb); atomic_inc(&Adapter->TotalPacketCount); spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n"); - /* FIXME - this is racy and incorrect, replace with work queue */ if (!atomic_read(&Adapter->TxPktAvail)) { atomic_set(&Adapter->TxPktAvail, 1); @@ -182,12 +179,12 @@ int register_networkdev(PMINI_ADAPTER Adapter) struct net_device *net = Adapter->dev; int result; - net->netdev_ops = &bcmNetDevOps; + net->netdev_ops = &bcmNetDevOps; net->ethtool_ops = &bcm_ethtool_ops; - net->mtu = MTU_SIZE; /* 1400 Bytes */ + net->mtu = MTU_SIZE; /* 1400 Bytes */ net->tx_queue_len = TX_QLEN; net->flags |= IFF_NOARP; - net->flags &= ~(IFF_BROADCAST|IFF_MULTICAST); + net->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); netif_carrier_off(net); -- cgit v1.2.3 From 9e0a3169a34ba5fd04bde058a63fa0a36f2d7ed3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 10:17:54 -0400 Subject: beceem: create class on module installation First step to supporting multiple devices, create device class when module is initialized. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmchar.c | 62 ++++++++++++------------------------- drivers/staging/bcm/InterfaceInit.c | 14 +++++---- 2 files changed, 28 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 3a1b9903bf07..1a255609aeda 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -12,7 +12,7 @@ * * Returns - Zero(Success) ****************************************************************/ -static struct class *bcm_class = NULL; + static int bcm_char_open(struct inode *inode, struct file * filp) { PMINI_ADAPTER Adapter = NULL; @@ -2093,59 +2093,37 @@ static struct file_operations bcm_fops = { .llseek = no_llseek, }; +extern struct class *bcm_class; int register_control_device_interface(PMINI_ADAPTER Adapter) { + if(Adapter->major>0) - return Adapter->major; - Adapter->major = register_chrdev(0, "tarang", &bcm_fops); - if(Adapter->major < 0) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "register_chrdev:Failed to registering WiMax control char device!"); - return Adapter->major; - } - - bcm_class = NULL; - bcm_class = class_create (THIS_MODULE, "tarang"); - if(IS_ERR (bcm_class)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unable to create class\n"); - unregister_chrdev(Adapter->major, "tarang"); - Adapter->major = 0; - return -ENODEV; + return Adapter->major; + + Adapter->major = register_chrdev(0, DEV_NAME, &bcm_fops); + if(Adapter->major < 0) { + pr_err(DRV_NAME ": could not created character device\n"); + return Adapter->major; } + Adapter->pstCreatedClassDevice = device_create (bcm_class, NULL, - MKDEV(Adapter->major, 0), -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) - NULL , -#endif - "tarang"); + MKDEV(Adapter->major, 0), Adapter, + DEV_NAME); - if(IS_ERR(Adapter->pstCreatedClassDevice)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "class device did not get created : %ld", PTR_ERR(Adapter->pstCreatedClassDevice) ); + if(IS_ERR(Adapter->pstCreatedClassDevice)) { + pr_err(DRV_NAME ": class device create failed\n"); + unregister_chrdev(Adapter->major, DEV_NAME); + return PTR_ERR(Adapter->pstCreatedClassDevice); } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Got Major No: %d", Adapter->major); - return 0; + + return 0; } void unregister_control_device_interface(PMINI_ADAPTER Adapter) { - if(Adapter->major > 0) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "destroying class device"); + if(Adapter->major > 0) { device_destroy (bcm_class, MKDEV(Adapter->major, 0)); + unregister_chrdev(Adapter->major, DEV_NAME); } - if(!IS_ERR(bcm_class)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "destroying created class "); - class_destroy (bcm_class); - bcm_class = NULL; - } - if(Adapter->major > 0) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"unregistering character interface"); - unregister_chrdev(Adapter->major, "tarang"); - } - } diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 6d62a50a2f48..161141d14565 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -738,6 +738,7 @@ static struct usb_driver usbbcm_driver = { .supports_autosuspend = 1, }; +struct class *bcm_class; /* Function: InterfaceInitialize @@ -755,16 +756,17 @@ Return: BCM_STATUS_SUCCESS - If Initialization of the */ INT InterfaceInitialize(void) { -// BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Registering Usb driver!!"); + bcm_class = class_create(THIS_MODULE, DRV_NAME); + if (IS_ERR(bcm_class)) { + printk(KERN_ERR DRV_NAME ": could not create class\n"); + return PTR_ERR(bcm_class); + } return usb_register(&usbbcm_driver); } INT InterfaceExit(void) { - //PMINI_ADAPTER psAdapter = NULL; - int status = 0; - - //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Deregistering Usb driver!!"); + class_destroy (bcm_class); usb_deregister(&usbbcm_driver); - return status; + return 0; } -- cgit v1.2.3 From 3349d95b3f8c3becb9e6dbe0be978bf663174fef Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 11:12:56 -0400 Subject: beceem: clean up adapter structure Remove dead fields, change fields that only have true/false to boolean; and rearrange to save space. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 54 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 69cac5c7f78f..c2161036d5ac 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -384,17 +384,18 @@ struct _MINI_ADAPTER struct _MINI_ADAPTER *next; CHAR *caDsxReqResp; - atomic_t ApplicationRunning; + atomic_t ApplicationRunning; volatile INT CtrlQueueLen; - atomic_t AppCtrlQueueLen; - BOOLEAN AppCtrlQueueOverFlow; - atomic_t CurrentApplicationCount; - atomic_t RegisteredApplicationCount; - BOOLEAN TimerActive; - ULONG StatisticsPointer; + atomic_t AppCtrlQueueLen; + BOOLEAN AppCtrlQueueOverFlow; + atomic_t CurrentApplicationCount; + atomic_t RegisteredApplicationCount; + BOOLEAN LinkUpStatus; + BOOLEAN TimerActive; + u32 StatisticsPointer; struct sk_buff *RxControlHead; struct sk_buff *RxControlTail; -// spinlock_t RxControlQueuelock; + struct semaphore RxAppControlQueuelock; struct semaphore fw_download_sema; @@ -421,14 +422,14 @@ struct _MINI_ADAPTER atomic_t GoodTxByteCount; atomic_t TxTotalPacketCount; atomic_t TxDroppedPacketCount; - ULONG LinkUpStatus; - BOOLEAN TransferMode; + UINT u32TotalDSD; PacketInfo PackInfo[NO_OF_QUEUES]; S_CLASSIFIER_RULE astClassifierTable[MAX_CLASSIFIERS]; + BOOLEAN TransferMode; /*************** qos ******************/ - UINT bETHCSEnabled; + BOOLEAN bETHCSEnabled; ULONG BEBucketSize; ULONG rtPSBucketSize; @@ -444,8 +445,6 @@ struct _MINI_ADAPTER atomic_t process_waiting; BOOLEAN fw_download_done; - unsigned int ctrlpkt_present; - BOOLEAN packets_given_to_all; char *txctlpacket[MAX_CNTRL_PKTS]; atomic_t cntrlpktCnt ; atomic_t index_app_read_cntrlpkt; @@ -455,33 +454,30 @@ struct _MINI_ADAPTER struct semaphore rdmwrmsync; STTARGETDSXBUFFER astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS]; - ULONG ulFreeTargetBufferCnt; + ULONG ulFreeTargetBufferCnt; ULONG ulCurrentTargetBuffer; ULONG ulTotalTargetBuffersAvailable; - unsigned int timeout; - int irq; + unsigned long chip_id; - unsigned int bFlashBoot; -// spinlock_t sleeper_lock; - atomic_t rdm_wrm_access; - atomic_t tx_rx_access; + wait_queue_head_t lowpower_mode_wait_queue; - atomic_t bAbortedByHost; - BOOLEAN bBinDownloaded; - BOOLEAN bCfgDownloaded; - USHORT usBestEffortQueueIndex; - BOOLEAN bSyncUpRequestSent; -// struct semaphore data_packet_queue_lock; + + BOOLEAN bFlashBoot; + BOOLEAN bBinDownloaded; + BOOLEAN bCfgDownloaded; + BOOLEAN bSyncUpRequestSent; + USHORT usBestEffortQueueIndex; + wait_queue_head_t ioctl_fw_dnld_wait_queue; BOOLEAN waiting_to_fw_download_done; pid_t fw_download_process_pid; PSTARGETPARAMS pstargetparams; BOOLEAN device_removed; BOOLEAN DeviceAccess; - INT DDRSetting; + BOOLEAN bIsAutoCorrectEnabled; BOOLEAN bDDRInitDone; + INT DDRSetting; ULONG ulPowerSaveMode; - BOOLEAN bIsAutoCorrectEnabled; spinlock_t txtransmitlock; B_UINT8 txtransmit_running; /* Thread for control packet handling */ @@ -525,7 +521,7 @@ struct _MINI_ADAPTER S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo; uint8_t ucaPHSPktRestoreBuf[2048]; uint8_t bPHSEnabled; - int AutoFirmDld; + BOOLEAN AutoFirmDld; BOOLEAN bMipsConfig; BOOLEAN bDPLLConfig; UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; -- cgit v1.2.3 From e39e3be66eed17f27a9de322e5220d33e70a90a6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 11:14:29 -0400 Subject: beceem: change format of debug message Statistic point is now u32 (like it has to be). Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 0ada848fe1e1..11e78eccb2ee 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -574,8 +574,8 @@ VOID LinkMessage(PMINI_ADAPTER Adapter) VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s====>",__FUNCTION__); - Adapter->StatisticsPointer = ntohl(*(PULONG)pvBuffer); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %lx", Adapter->StatisticsPointer); + Adapter->StatisticsPointer = ntohl(*(__be32 *)pvBuffer); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %x", (UINT)Adapter->StatisticsPointer); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s <====",__FUNCTION__); return; } -- cgit v1.2.3 From 4fd64dd0c1b9317ffe6fdaf3de788e14df880d8d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:12:31 -0400 Subject: beceem: add network device message level control Provide standard interface to control verbosity of debug messages Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 3 +- drivers/staging/bcm/Bcmnet.c | 66 +++++++++++++++++++++++++++++-------- drivers/staging/bcm/CmHost.c | 4 ++- drivers/staging/bcm/InterfaceInit.c | 7 +--- drivers/staging/bcm/Misc.c | 18 +++++----- 5 files changed, 67 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index c2161036d5ac..e5aaec508bf9 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -382,6 +382,8 @@ Driver adapter data structure struct _MINI_ADAPTER { struct _MINI_ADAPTER *next; + struct net_device *dev; + u32 msg_enable; CHAR *caDsxReqResp; atomic_t ApplicationRunning; @@ -437,7 +439,6 @@ struct _MINI_ADAPTER BOOLEAN AutoLinkUp; BOOLEAN AutoSyncup; - struct net_device *dev; int major; int minor; wait_queue_head_t tx_packet_wait_queue; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 3525f5cf5358..641f3c88a2d9 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -1,19 +1,35 @@ #include "headers.h" +static int debug = -1; +module_param(debug, uint, 0600); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +static const u32 default_msg = + NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK + | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; + struct net_device *gblpnetdev; static INT bcm_open(struct net_device *dev) { PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); - if (Adapter->fw_download_done == FALSE) - return -EINVAL; + if (Adapter->fw_download_done == FALSE) { + pr_notice(DRV_NAME "%s: link up failed (download in progress)\n", + dev->name); + return -EBUSY; + } + + if (netif_msg_ifup(Adapter)) + pr_info(DRV_NAME "%s: enabling interface\n", dev->name); + + if (Adapter->LinkUpStatus) { + if (netif_msg_link(Adapter)) + pr_info(DRV_NAME "%s: link up\n", dev->name); - if (Adapter->LinkUpStatus == 1) { - if (netif_queue_stopped(Adapter->dev)) { - netif_carrier_on(Adapter->dev); - netif_start_queue(Adapter->dev); - } + netif_carrier_on(Adapter->dev); + netif_start_queue(Adapter->dev); } return 0; @@ -21,10 +37,14 @@ static INT bcm_open(struct net_device *dev) static INT bcm_close(struct net_device *dev) { - if (!netif_queue_stopped(dev)) { - netif_carrier_off(dev); - netif_stop_queue(dev); - } + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + + if (netif_msg_ifdown(Adapter)) + pr_info(DRV_NAME "%s: disabling interface\n", dev->name); + + netif_carrier_off(dev); + netif_stop_queue(dev); + return 0; } @@ -70,6 +90,7 @@ static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); u16 qindex = skb_get_queue_mapping(skb); + if (Adapter->device_removed || !Adapter->LinkUpStatus) goto drop; @@ -84,9 +105,9 @@ static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; /* Now Enqueue the packet */ - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, - "bcm_transmit Enqueueing the Packet To Queue %d", - qindex); + if (netif_msg_tx_queued(Adapter)) + pr_info(DRV_NAME "%s: enqueueing packet to queue %d\n", + dev->name, qindex); spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; @@ -168,10 +189,26 @@ static u32 bcm_get_link(struct net_device *dev) return Adapter->LinkUpStatus; } +static u32 bcm_get_msglevel (struct net_device *dev) +{ + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + + return Adapter->msg_enable; +} + +static void bcm_set_msglevel (struct net_device *dev, u32 level) +{ + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); + + Adapter->msg_enable = level; +} + static const struct ethtool_ops bcm_ethtool_ops = { .get_settings = bcm_get_settings, .get_drvinfo = bcm_get_drvinfo, .get_link = bcm_get_link, + .get_msglevel = bcm_get_msglevel, + .set_msglevel = bcm_set_msglevel, }; int register_networkdev(PMINI_ADAPTER Adapter) @@ -185,6 +222,7 @@ int register_networkdev(PMINI_ADAPTER Adapter) net->tx_queue_len = TX_QLEN; net->flags |= IFF_NOARP; net->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + Adapter->msg_enable = netif_msg_init(debug, default_msg); netif_carrier_off(net); diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index c8d73d524852..e19f7936d6f0 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -2135,8 +2135,10 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**LinkUpStatus) { netif_carrier_on(Adapter->dev); - netif_start_queue(Adapter->dev); + netif_start_queue(Adapter->dev); Adapter->LinkUpStatus = 1; + if (netif_msg_link(Adapter)) + pr_info(DRV_NAME "%s: link up\n", Adapter->dev->name); do_gettimeofday(&tv); atomic_set(&Adapter->TxPktAvail, 1); diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 161141d14565..3529ea517dab 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -11,11 +11,6 @@ static struct usb_device_id InterfaceUsbtable[] = { }; MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); -static unsigned int debug_level = DBG_LVL_CURR; -module_param(debug_level, uint, 0644); -MODULE_PARM_DESC(debug_level, "Debug level (0=none,...,7=all)"); - - VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) { INT i = 0; @@ -164,7 +159,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Init default driver debug state */ - psAdapter->stDebugState.debug_level = debug_level; + psAdapter->stDebugState.debug_level = DBG_LVL_CURR; psAdapter->stDebugState.type = DBG_TYPE_INITEXIT; /* Technically, one can start using BCM_DEBUG_PRINT after this point. diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 11e78eccb2ee..1b29744e4cab 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -1913,13 +1913,13 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex) void beceem_protocol_reset (PMINI_ADAPTER Adapter) { - int i =0; + int i; - if(NULL != Adapter->dev) - { - netif_carrier_off(Adapter->dev); - netif_stop_queue(Adapter->dev); - } + if (netif_msg_link(Adapter)) + pr_notice(DRV_NAME "%s: protocol reset\n", Adapter->dev->name); + + netif_carrier_off(Adapter->dev); + netif_stop_queue(Adapter->dev); Adapter->IdleMode = FALSE; Adapter->LinkUpStatus = FALSE; @@ -1937,14 +1937,14 @@ void beceem_protocol_reset (PMINI_ADAPTER Adapter) Adapter->TimerActive = FALSE; memset(Adapter->astFragmentedPktClassifierTable, 0, - sizeof(S_FRAGMENTED_PACKET_INFO) * - MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES); + sizeof(S_FRAGMENTED_PACKET_INFO) * MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES); for(i = 0;iPackInfo[i],0,sizeof(S_MIBS_SERVICEFLOW_TABLE)); + memset(&Adapter->PackInfo[i].stMibsExtServiceFlowTable, + 0, sizeof(S_MIBS_EXTSERVICEFLOW_PARAMETERS)); } } -- cgit v1.2.3 From 2d08748ae53bf07fe6fcaf4f3d40449b471ce351 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:14:01 -0400 Subject: beceem: module initialization Get rid of boot messages and put in correct place. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 22 -------- drivers/staging/bcm/InterfaceInit.c | 105 ++++++++++++++---------------------- drivers/staging/bcm/InterfaceMisc.c | 14 +---- drivers/staging/bcm/Misc.c | 86 ++++++++++++----------------- drivers/staging/bcm/Prototypes.h | 2 - 5 files changed, 75 insertions(+), 154 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 641f3c88a2d9..bf3a04dca234 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -241,25 +241,3 @@ int register_networkdev(PMINI_ADAPTER Adapter) return result; } - -static int bcm_init(void) -{ - printk(KERN_INFO "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); - printk(KERN_INFO "%s\n", DRV_COPYRIGHT); - - return InterfaceInitialize(); -} - - -static void bcm_exit(void) -{ - InterfaceExit(); -} - -module_init(bcm_init); -module_exit(bcm_exit); - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_LICENSE ("GPL"); - diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 3529ea517dab..43e5c9cea717 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -338,13 +338,11 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter); if(status != STATUS_SUCCESS) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "InitCardAndDownloadFirmware failed.\n"); + pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n"); return status; } if(TRUE == psIntfAdapter->psAdapter->fw_download_done) { - - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Sending first interrupt URB down......"); if(StartInterruptUrb(psIntfAdapter)) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB"); @@ -357,16 +355,11 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ); if(value == 0) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Mailbox Interrupt has not reached to Driver.."); - } - else - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Got the mailbox interrupt ...Registering control interface...\n "); - } + pr_err(DRV_NAME ": Mailbox Interrupt has not reached to Driver..\n"); + if(register_control_device_interface(psIntfAdapter->psAdapter) < 0) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Register Control Device failed..."); + pr_err(DRV_NAME ": Register Control Device failed...\n"); return -EIO; } } @@ -460,20 +453,9 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) UINT uiData = 0; /* Store the usb dev into interface adapter */ - psIntfAdapter->udev = usb_get_dev(interface_to_usbdev( - psIntfAdapter->interface)); - - if((psIntfAdapter->udev->speed == USB_SPEED_HIGH)) - { - psIntfAdapter->bHighSpeedDevice = TRUE ; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "MODEM IS CONFIGURED TO HIGH_SPEED "); - } - else - { - psIntfAdapter->bHighSpeedDevice = FALSE ; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "MODEM IS CONFIGURED TO FULL_SPEED "); - } + psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); + psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH); psIntfAdapter->psAdapter->interface_rdm = BcmRDM; psIntfAdapter->psAdapter->interface_wrm = BcmWRM; @@ -482,28 +464,27 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n"); return STATUS_FAILURE; } - if(0xbece3200==(psIntfAdapter->psAdapter->chip_id&~(0xF0))) - { - psIntfAdapter->psAdapter->chip_id=(psIntfAdapter->psAdapter->chip_id&~(0xF0)); - } - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "First RDM Chip ID 0x%lx\n", psIntfAdapter->psAdapter->chip_id); + if(0xbece3200==(psIntfAdapter->psAdapter->chip_id&~(0xF0))) + psIntfAdapter->psAdapter->chip_id &= ~0xF0; - iface_desc = psIntfAdapter->interface->cur_altsetting; - //print_usb_interface_desc(&(iface_desc->desc)); + dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n", + psIntfAdapter->psAdapter->chip_id); + + iface_desc = psIntfAdapter->interface->cur_altsetting; if(psIntfAdapter->psAdapter->chip_id == T3B) { - // //T3B device will have EEPROM,check if EEPROM is proper and BCM16 can be done or not. // BeceemEEPROMBulkRead(psIntfAdapter->psAdapter,&uiData,0x0,4); if(uiData == BECM) - { bBcm16 = TRUE; - } - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Number of Altsetting aviailable for This Modem 0x%x\n", psIntfAdapter->interface->num_altsetting); + + dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n", + psIntfAdapter->interface->num_altsetting); + if(bBcm16 == TRUE) { //selecting alternate setting one as a default setting for High Speed modem. @@ -574,12 +555,10 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) } iface_desc = psIntfAdapter->interface->cur_altsetting; - //print_usb_interface_desc(&(iface_desc->desc)); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Current number of endpoints :%x \n", iface_desc->desc.bNumEndpoints); - for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) + + for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) { - endpoint = &iface_desc->endpoint[value].desc; - //print_usb_endpoint_descriptor(endpoint); + endpoint = &iface_desc->endpoint[value].desc; if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) { @@ -612,10 +591,10 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->sIntrIn.int_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!psIntfAdapter->sIntrIn.int_in_buffer) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Could not allocate interrupt_in_buffer"); + dev_err(&psIntfAdapter->udev->dev, + "could not allocate interrupt_in_buffer\n"); return -EINVAL; } - //psIntfAdapter->sIntrIn.int_in_pipe = } if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) @@ -646,10 +625,11 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size, GFP_KERNEL); if (!psIntfAdapter->sIntrOut.int_out_buffer) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Could not allocate interrupt_out_buffer"); - return -EINVAL; - } + { + dev_err(&psIntfAdapter->udev->dev, + "could not allocate interrupt_out_buffer\n"); + return -EINVAL; + } } } } @@ -681,8 +661,7 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) static int InterfaceSuspend (struct usb_interface *intf, pm_message_t message) { PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=================================\n"); - //Bcm_kill_all_URBs(psIntfAdapter); + psIntfAdapter->bSuspended = TRUE; if(TRUE == psIntfAdapter->bPreparingForBusSuspend) @@ -735,33 +714,31 @@ static struct usb_driver usbbcm_driver = { struct class *bcm_class; -/* -Function: InterfaceInitialize -Description: This is the hardware specific initialization Function. - Registering the driver with NDIS , other device specific NDIS - and hardware initializations are done here. - -Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context - - -Return: BCM_STATUS_SUCCESS - If Initialization of the - HW Interface was successful. - Other - If an error occured. -*/ -INT InterfaceInitialize(void) +static __init int bcm_init(void) { + printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO "%s\n", DRV_COPYRIGHT); + bcm_class = class_create(THIS_MODULE, DRV_NAME); if (IS_ERR(bcm_class)) { printk(KERN_ERR DRV_NAME ": could not create class\n"); return PTR_ERR(bcm_class); } + return usb_register(&usbbcm_driver); } -INT InterfaceExit(void) +static __exit void bcm_exit(void) { class_destroy (bcm_class); + usb_deregister(&usbbcm_driver); - return 0; } + +module_init(bcm_init); +module_exit(bcm_exit); + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE ("GPL"); diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c index 6ee5dbb6154a..b7d6e7a414a9 100644 --- a/drivers/staging/bcm/InterfaceMisc.c +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -224,9 +224,7 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter) } /* Cancel All submitted TX URB's */ - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cancelling All Submitted TX Urbs \n"); - - for(i = 0; i < MAXIMUM_USB_TCB; i++) + for(i = 0; i < MAXIMUM_USB_TCB; i++) { tempUrb = psIntfAdapter->asUsbTcb[i].urb; if(tempUrb) @@ -236,9 +234,6 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter) } } - - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cancelling All submitted Rx Urbs \n"); - for(i = 0; i < MAXIMUM_USB_RCB; i++) { tempUrb = psIntfAdapter->asUsbRcb[i].urb; @@ -249,16 +244,11 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter) } } - atomic_set(&psIntfAdapter->uNumTcbUsed, 0); atomic_set(&psIntfAdapter->uCurrTcb, 0); atomic_set(&psIntfAdapter->uNumRcbUsed, 0); atomic_set(&psIntfAdapter->uCurrRcb, 0); - - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "TCB: used- %d cur-%d\n", atomic_read(&psIntfAdapter->uNumTcbUsed), atomic_read(&psIntfAdapter->uCurrTcb)); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "RCB: used- %d cur-%d\n", atomic_read(&psIntfAdapter->uNumRcbUsed), atomic_read(&psIntfAdapter->uCurrRcb)); - } VOID putUsbSuspend(struct work_struct *work) @@ -270,8 +260,6 @@ VOID putUsbSuspend(struct work_struct *work) if(psIntfAdapter->bSuspended == FALSE) usb_autopm_put_interface(intf); - else - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Interface Resumed Completely\n"); } diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 1b29744e4cab..7f3a936529c5 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -152,34 +152,30 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) free_netdev(Adapter->dev); } - -int create_worker_threads(PMINI_ADAPTER psAdapter) +static int create_worker_threads(PMINI_ADAPTER psAdapter) { - const char *name = psAdapter->dev->name; - - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Init Threads..."); // Rx Control Packets Processing psAdapter->control_packet_handler = kthread_run((int (*)(void *)) - control_packet_handler, psAdapter, "%s-rx", name); + control_packet_handler, psAdapter, "%s-rx", DRV_NAME); if(IS_ERR(psAdapter->control_packet_handler)) { - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success\n"); + pr_notice(DRV_NAME ": could not create control thread\n"); return PTR_ERR(psAdapter->control_packet_handler); } + // Tx Thread psAdapter->transmit_packet_thread = kthread_run((int (*)(void *)) - tx_pkt_handler, psAdapter, "%s-tx", name); + tx_pkt_handler, psAdapter, "%s-tx", DRV_NAME); if(IS_ERR (psAdapter->transmit_packet_thread)) { - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success"); + pr_notice(DRV_NAME ": could not creat transmit thread\n"); kthread_stop(psAdapter->control_packet_handler); return PTR_ERR(psAdapter->transmit_packet_thread); } return 0; } - -static inline struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path) +static struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path) { struct file *flp=NULL; mm_segment_t oldfs; @@ -189,19 +185,13 @@ static inline struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path) set_fs(oldfs); if(IS_ERR(flp)) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Unable To Open File %s, err %lx", - path, PTR_ERR(flp)); - flp = NULL; - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Got file descriptor pointer of %s!", - path); + pr_err(DRV_NAME "Unable To Open File %s, err %ld", + path, PTR_ERR(flp)); + flp = NULL; } - if(Adapter->device_removed) - { - flp = NULL; - } + + if(Adapter->device_removed) + flp = NULL; return flp; } @@ -254,9 +244,7 @@ exit_download: if(flp && !(IS_ERR(flp))) filp_close(flp, current->files); set_fs(oldfs); - do_gettimeofday(&tv); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "file download done at %lx", ((tv.tv_sec * 1000) + - (tv.tv_usec/1000))); + return errorno; } @@ -1104,11 +1092,10 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) * Firm/DDR Settings.. */ - if((status = create_worker_threads(ps_adapter))<0) - { - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Cannot create thread"); + status = create_worker_threads(ps_adapter); + if (status<0) return status; - } + /* * For Downloading the Firm, parse the cfg file first. */ @@ -1134,7 +1121,7 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) status = ddr_init(ps_adapter); if(status) { - BCM_DEBUG_PRINT (ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "ddr_init Failed\n"); + pr_err(DRV_NAME "ddr_init Failed\n"); return status; } @@ -1148,7 +1135,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Error downloading CFG file"); goto OUT; } - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "CFG file downloaded"); if(register_networkdev(ps_adapter)) { @@ -1221,7 +1207,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) goto OUT; } - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "BIN file downloaded"); status = run_card_proc(ps_adapter); if(status) { @@ -1302,22 +1287,23 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter) if(ntohl(Adapter->pstargetparams->m_u32PhyParameter2) & AUTO_SYNC_DISABLE) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoSyncup is Disabled\n"); + pr_info(DRV_NAME ": AutoSyncup is Disabled\n"); Adapter->AutoSyncup = FALSE; } else { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoSyncup is Enabled\n"); + pr_info(DRV_NAME ": AutoSyncup is Enabled\n"); Adapter->AutoSyncup = TRUE; } + if(ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_LINKUP_ENABLE) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Enabling autolink up"); + pr_info(DRV_NAME ": Enabling autolink up"); Adapter->AutoLinkUp = TRUE; } else { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Disabling autolink up"); + pr_info(DRV_NAME ": Disabling autolink up"); Adapter->AutoLinkUp = FALSE; } // Setting the DDR Setting.. @@ -1326,51 +1312,46 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter) Adapter->ulPowerSaveMode = (ntohl(Adapter->pstargetparams->HostDrvrConfig6)>>12)&0x0F; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT,DBG_LVL_ALL, "Power Save Mode: %lx\n", - Adapter->ulPowerSaveMode); + pr_info(DRV_NAME ": DDR Setting: %x\n", Adapter->DDRSetting); + pr_info(DRV_NAME ": Power Save Mode: %lx\n", Adapter->ulPowerSaveMode); if(ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_FIRM_DOWNLOAD) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Enabling Auto Firmware Download\n"); + pr_info(DRV_NAME ": Enabling Auto Firmware Download\n"); Adapter->AutoFirmDld = TRUE; } else { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Disabling Auto Firmware Download\n"); + pr_info(DRV_NAME ": Disabling Auto Firmware Download\n"); Adapter->AutoFirmDld = FALSE; } uiHostDrvrCfg6 = ntohl(Adapter->pstargetparams->HostDrvrConfig6); Adapter->bMipsConfig = (uiHostDrvrCfg6>>20)&0x01; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"MIPSConfig : 0x%X\n",Adapter->bMipsConfig); + pr_info(DRV_NAME ": MIPSConfig : 0x%X\n",Adapter->bMipsConfig); //used for backward compatibility. Adapter->bDPLLConfig = (uiHostDrvrCfg6>>19)&0x01; Adapter->PmuMode= (uiHostDrvrCfg6 >> 24 ) & 0x03; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "PMU MODE: %x", Adapter->PmuMode); + pr_info(DRV_NAME ": PMU MODE: %x", Adapter->PmuMode); if((uiHostDrvrCfg6 >> HOST_BUS_SUSPEND_BIT ) & (0x01)) { Adapter->bDoSuspend = TRUE; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Making DoSuspend TRUE as per configFile"); + pr_info(DRV_NAME ": Making DoSuspend TRUE as per configFile"); } uiEEPROMFlag = ntohl(Adapter->pstargetparams->m_u32EEPROMFlag); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "uiEEPROMFlag : 0x%X\n",uiEEPROMFlag); + pr_info(DRV_NAME ": uiEEPROMFlag : 0x%X\n",uiEEPROMFlag); Adapter->eNVMType = (NVM_TYPE)((uiEEPROMFlag>>4)&0x3); - Adapter->bStatusWrite = (uiEEPROMFlag>>6)&0x1; - //printk(("bStatusWrite : 0x%X\n", Adapter->bStatusWrite)); Adapter->uiSectorSizeInCFG = 1024*(0xFFFF & ntohl(Adapter->pstargetparams->HostDrvrConfig4)); - //printk(("uiSectorSize : 0x%X\n", Adapter->uiSectorSizeInCFG)); Adapter->bSectorSizeOverride =(bool) ((ntohl(Adapter->pstargetparams->HostDrvrConfig4))>>16)&0x1; - //printk(MP_INIT,("bSectorSizeOverride : 0x%X\n",Adapter->bSectorSizeOverride)); if(ntohl(Adapter->pstargetparams->m_u32PowerSavingModeOptions) &0x01) Adapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE; - //autocorrection part + if(Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) doPowerAutoCorrection(Adapter); @@ -1378,7 +1359,7 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter) VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter) { - UINT reporting_mode = 0; + UINT reporting_mode; reporting_mode = ntohl(psAdapter->pstargetparams->m_u32PowerSavingModeOptions) &0x02 ; psAdapter->bIsAutoCorrectEnabled = !((char)(psAdapter->ulPowerSaveMode >> 3) & 0x1); @@ -1395,7 +1376,6 @@ VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter) { psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING; psAdapter->bDoSuspend =FALSE; - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"PMC selected.."); } diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index c9e1d61efe5f..920e9882ccd1 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -74,8 +74,6 @@ VOID AdapterFree(PMINI_ADAPTER Adapter); INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter); -int create_worker_threads(PMINI_ADAPTER psAdapter); - int tx_pkt_handler(PMINI_ADAPTER Adapter); int reset_card_proc(PMINI_ADAPTER Adapter ); -- cgit v1.2.3 From e4d46254da76106e48b7cadc59fb410291e2da4b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 11:39:05 -0400 Subject: beceem: use get_seconds for elapsed time get_seconds is lower overhead and fine if all driver wants to do is keep track of seconds. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/CmHost.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index e19f7936d6f0..949aaa3b3191 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -2053,7 +2053,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**u16VCID)); uiSearchRuleIndex=SearchFreeSfid(Adapter); @@ -2139,12 +2139,9 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**LinkUpStatus = 1; if (netif_msg_link(Adapter)) pr_info(DRV_NAME "%s: link up\n", Adapter->dev->name); - do_gettimeofday(&tv); - atomic_set(&Adapter->TxPktAvail, 1); wake_up(&Adapter->tx_packet_wait_queue); - Adapter->liTimeSinceLastNetEntry = tv.tv_sec; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============Tx Service Flow Created!"); + Adapter->liTimeSinceLastNetEntry = get_seconds(); } } } -- cgit v1.2.3 From 9ec4475bf10bb2c30cd5e927bc453aa307f58123 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:18:36 -0400 Subject: beceem: debug message format changes Add more debug messages and make them similar to other drivers Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 12 ++++++------ drivers/staging/bcm/CmHost.c | 2 +- drivers/staging/bcm/InterfaceIsr.c | 4 ++++ drivers/staging/bcm/InterfaceRx.c | 9 ++++++--- drivers/staging/bcm/InterfaceTx.c | 4 ++++ drivers/staging/bcm/Misc.c | 2 +- drivers/staging/bcm/Qos.c | 7 +++++-- 7 files changed, 27 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index bf3a04dca234..fbaf73a2e42c 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -16,17 +16,17 @@ static INT bcm_open(struct net_device *dev) PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); if (Adapter->fw_download_done == FALSE) { - pr_notice(DRV_NAME "%s: link up failed (download in progress)\n", - dev->name); + pr_notice(PFX "%s: link up failed (download in progress)\n", + dev->name); return -EBUSY; } if (netif_msg_ifup(Adapter)) - pr_info(DRV_NAME "%s: enabling interface\n", dev->name); + pr_info(PFX "%s: enabling interface\n", dev->name); if (Adapter->LinkUpStatus) { if (netif_msg_link(Adapter)) - pr_info(DRV_NAME "%s: link up\n", dev->name); + pr_info(PFX "%s: link up\n", dev->name); netif_carrier_on(Adapter->dev); netif_start_queue(Adapter->dev); @@ -40,7 +40,7 @@ static INT bcm_close(struct net_device *dev) PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); if (netif_msg_ifdown(Adapter)) - pr_info(DRV_NAME "%s: disabling interface\n", dev->name); + pr_info(PFX "%s: disabling interface\n", dev->name); netif_carrier_off(dev); netif_stop_queue(dev); @@ -106,7 +106,7 @@ static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) /* Now Enqueue the packet */ if (netif_msg_tx_queued(Adapter)) - pr_info(DRV_NAME "%s: enqueueing packet to queue %d\n", + pr_info(PFX "%s: enqueueing packet to queue %d\n", dev->name, qindex); spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 949aaa3b3191..1aa962fedb91 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -2138,7 +2138,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter, /**dev); Adapter->LinkUpStatus = 1; if (netif_msg_link(Adapter)) - pr_info(DRV_NAME "%s: link up\n", Adapter->dev->name); + pr_info(PFX "%s: link up\n", Adapter->dev->name); atomic_set(&Adapter->TxPktAvail, 1); wake_up(&Adapter->tx_packet_wait_queue); Adapter->liTimeSinceLastNetEntry = get_seconds(); diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c index c1f8e7aa05f7..2d26e2ed38d9 100644 --- a/drivers/staging/bcm/InterfaceIsr.c +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -7,6 +7,10 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)urb->context; PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter ; + if (netif_msg_intr(Adapter)) + pr_info(PFX "%s: interrupt status %d\n", + Adapter->dev->name, status); + if(Adapter->device_removed == TRUE) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Device has Got Removed."); diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c index 6f1ed78c975b..07326a97c4a2 100644 --- a/drivers/staging/bcm/InterfaceRx.c +++ b/drivers/staging/bcm/InterfaceRx.c @@ -38,7 +38,9 @@ static void read_bulk_callback(struct urb *urb) PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter; PLEADER pLeader = urb->transfer_buffer; - + if (unlikely(netif_msg_rx_status(Adapter))) + pr_info(PFX "%s: rx urb status %d length %d\n", + Adapter->dev->name, urb->status, urb->actual_length); if((Adapter->device_removed == TRUE) || (TRUE == Adapter->bEndPointHalted) || @@ -83,8 +85,9 @@ static void read_bulk_callback(struct urb *urb) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status,pLeader->PLength,pLeader->Vcid); if(MAX_CNTL_PKT_SIZE < pLeader->PLength) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Corrupted leader length...%d\n", - pLeader->PLength); + if (netif_msg_rx_err(Adapter)) + pr_info(PFX "%s: corrupted leader length...%d\n", + Adapter->dev->name, pLeader->PLength); atomic_inc(&Adapter->RxPacketDroppedCount); atomic_add(pLeader->PLength, &Adapter->BadRxByteCount); atomic_dec(&psIntfAdapter->uNumRcbUsed); diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c index a3dadf19538b..f434b899a0d0 100644 --- a/drivers/staging/bcm/InterfaceTx.c +++ b/drivers/staging/bcm/InterfaceTx.c @@ -9,6 +9,10 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) PMINI_ADAPTER psAdapter = psIntfAdapter->psAdapter ; BOOLEAN bpowerDownMsg = FALSE ; PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if (unlikely(netif_msg_tx_done(Adapter))) + pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, urb->status); + if(urb->status != STATUS_SUCCESS) { if(urb->status == -EPIPE) diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 7f3a936529c5..8212af3ecf90 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -1896,7 +1896,7 @@ void beceem_protocol_reset (PMINI_ADAPTER Adapter) int i; if (netif_msg_link(Adapter)) - pr_notice(DRV_NAME "%s: protocol reset\n", Adapter->dev->name); + pr_notice(PFX "%s: protocol reset\n", Adapter->dev->name); netif_carrier_off(Adapter->dev); netif_stop_queue(Adapter->dev); diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 7e8013c105a2..21b611c68d37 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -356,8 +356,11 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**tx_dropped++; + if (netif_msg_tx_err(Adapter)) + pr_info(PFX "%s: tx queue %d overlimit\n", + Adapter->dev->name, iIndex); + + netstats->tx_dropped++; atomic_inc(&Adapter->TxDroppedPacketCount); DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue, Adapter->PackInfo[iIndex].LastTxQueue); -- cgit v1.2.3 From 1da9badcf02dd6532df9bde8fc05648e74982f2c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 11:58:01 -0400 Subject: beceem: allow multicast/broadcast Even though wimax isn't really a broadcast medium, pretend it is. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index fbaf73a2e42c..82270c18c6ac 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -221,7 +221,6 @@ int register_networkdev(PMINI_ADAPTER Adapter) net->mtu = MTU_SIZE; /* 1400 Bytes */ net->tx_queue_len = TX_QLEN; net->flags |= IFF_NOARP; - net->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); Adapter->msg_enable = netif_msg_init(debug, default_msg); netif_carrier_off(net); -- cgit v1.2.3 From ac1b1ae7f84dcde6d6fefc7f8ca27c4e5bd92c22 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:20:09 -0400 Subject: beceem: transmit code cleanup Eliminate global variable in transmit path The Leader can be on the stack, and get rid of unnecessary timeval. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Transmit.c | 63 +++++++++++------------------------------- 1 file changed, 16 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 734bbbd14e22..b924a6a4dd78 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -41,19 +41,10 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53 This function dispatches control packet to the h/w interface @return zero(success) or -ve value(failure) */ -INT SendControlPacket(PMINI_ADAPTER Adapter, /**"); - - PLeader=(PLEADER)pControlPacket; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx"); if(!pControlPacket || !Adapter) { @@ -87,27 +78,21 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**len > MAX_DEVICE_DESC_SIZE) { status = STATUS_FAILURE; @@ -141,15 +126,10 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**cb) + SKB_CB_TCPACK_OFFSET )) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n"); + if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET )) Leader.Status = LEADER_STATUS_TCP_ACK; - } else - { Leader.Status = LEADER_STATUS; - } if(Adapter->PackInfo[QueueIndex].bEthCSSupport) { @@ -165,35 +145,26 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**data, &Leader, LEADER_SIZE); } - else { Leader.PLength = Packet->len - ETH_HLEN; memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE); } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid); - status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter, Packet->data, (Leader.PLength + LEADER_SIZE)); if(status) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n"); + ++Adapter->dev->stats.tx_errors; + if (netif_msg_tx_err(Adapter)) + pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name, + status); } else { Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; - atomic_add(Leader.PLength, &Adapter->GoodTxByteCount); - atomic_inc(&Adapter->TxTotalPacketCount); - } - - atomic_dec(&Adapter->CurrNumFreeTxDesc); - -errExit: - - if(STATUS_SUCCESS == status) - { + Adapter->dev->stats.tx_bytes += Leader.PLength; + ++Adapter->dev->stats.tx_packets; Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3; Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len); Adapter->PackInfo[QueueIndex].uiSentPackets++; @@ -203,6 +174,9 @@ errExit: Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength; } + atomic_dec(&Adapter->CurrNumFreeTxDesc); + +errExit: dev_kfree_skb(Packet); return status; @@ -238,11 +212,10 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ if(Adapter->downloadDDR == 1) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n"); Adapter->downloadDDR +=1; status = download_ddr_settings(Adapter); if(status) - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n"); + pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status); continue; } @@ -278,7 +251,6 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ wake_up(&Adapter->process_rx_cntrlpkt); } - transmit_packets(Adapter); atomic_set(&Adapter->TxPktAvail, 0); @@ -288,6 +260,3 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/ Adapter->transmit_packet_thread = NULL; return 0; } - - - -- cgit v1.2.3 From 45400554923867c8479621e55a76e0612192dafb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:21:32 -0400 Subject: beceem: remove unused code to dump header Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/PHSModule.c | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c index e0456b291d6c..44ddb59c2ecc 100644 --- a/drivers/staging/bcm/PHSModule.c +++ b/drivers/staging/bcm/PHSModule.c @@ -3,8 +3,6 @@ #define IN #define OUT -void DumpDataPacketHeader(PUCHAR pPkt); - /* Function: PHSTransmit @@ -81,8 +79,6 @@ int PHSTransmit(PMINI_ADAPTER Adapter, { - //DumpDataPacketHeader(pucPHSPktHdrInBuf); - // Step 2 Supress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf. // Suppress only if IP Header and PHS Enabled For the Service Flow if(((usPacketType == ETHERNET_FRAMETYPE_IPV4) || @@ -229,17 +225,6 @@ int PHSRecieve(PMINI_ADAPTER Adapter, return STATUS_SUCCESS; } -void DumpDataPacketHeader(PUCHAR pPkt) -{ - struct iphdr *iphd = (struct iphdr*)pPkt; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Phs Send/Recieve : IP Packet Hdr \n"); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"TOS : %x \n",iphd->tos); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Src IP : %x \n",iphd->saddr); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Dest IP : %x \n \n",iphd->daddr); - -} - void DumpFullPacket(UCHAR *pBuf,UINT nPktLen) { PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); @@ -1300,22 +1285,6 @@ BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable } } -static void DumpBuffer(PVOID BuffVAddress, int xferSize) -{ - int i; - int iPrintLength; - PUCHAR temp=(PUCHAR)BuffVAddress; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - iPrintLength=(xferSize<32?xferSize:32); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n"); - - for (i=0;i < iPrintLength;i++) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "%x|",temp[i]); - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n"); -} - - void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension) { int i,j,k,l; -- cgit v1.2.3 From 9dd47ee7dd535649a2c32d509631c7a3d793f2e1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:24:00 -0400 Subject: beceem: make local functions static Use namespace tool from kernel scripts to identify dead code and functions that should be static. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/CmHost.c | 5 +- drivers/staging/bcm/CmHost.h | 3 - drivers/staging/bcm/HandleControlPacket.c | 3 +- drivers/staging/bcm/IPv6Protocol.c | 10 +- drivers/staging/bcm/IPv6ProtocolHdr.h | 3 - drivers/staging/bcm/InterfaceIdleMode.c | 12 +-- drivers/staging/bcm/InterfaceIdleMode.h | 2 - drivers/staging/bcm/InterfaceInit.c | 8 +- drivers/staging/bcm/InterfaceInit.h | 4 - drivers/staging/bcm/InterfaceIsr.c | 36 ------- drivers/staging/bcm/Misc.c | 52 +++------ drivers/staging/bcm/PHSModule.c | 72 ++++++++++--- drivers/staging/bcm/PHSModule.h | 45 -------- drivers/staging/bcm/Prototypes.h | 86 +-------------- drivers/staging/bcm/Qos.c | 30 ++++-- drivers/staging/bcm/nvm.c | 173 ++++++++++++------------------ 16 files changed, 178 insertions(+), 366 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 1aa962fedb91..553da135c828 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -15,6 +15,7 @@ typedef enum _E_CLASSIFIER_ACTION eDeleteClassifier }E_CLASSIFIER_ACTION; +static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid); /************************************************************ * Function - SearchSfid @@ -108,7 +109,7 @@ static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/ return MAX_CLASSIFIERS+1; } -VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex) +static VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex) { //deleting all the packet held in the SF flush_queue(Adapter,uiSearchRuleIndex); @@ -1923,7 +1924,7 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter) return 1; } -ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid) +static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid) { ULONG ulTargetDSXBufferAddress; ULONG ulTargetDsxBufferIndexToUse,ulMaxTry; diff --git a/drivers/staging/bcm/CmHost.h b/drivers/staging/bcm/CmHost.h index 847782c3765b..8f689769b4ba 100644 --- a/drivers/staging/bcm/CmHost.h +++ b/drivers/staging/bcm/CmHost.h @@ -150,8 +150,6 @@ typedef struct stLocalSFChangeIndicationAlt{ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *puBufferLength); -ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid); - INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter); INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter); @@ -159,7 +157,6 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter); BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer); -VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex); #pragma pack (pop) diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c index 2d4dbcc215e3..e7afa56c0dcf 100644 --- a/drivers/staging/bcm/HandleControlPacket.c +++ b/drivers/staging/bcm/HandleControlPacket.c @@ -11,8 +11,7 @@ When a control packet is received, analyze the Enqueue the control packet for Application. @return None */ -VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**psAdapter); } -VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) +static VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) { ULONG ulReg = 0; @@ -441,7 +443,7 @@ static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descrip return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd)); } -INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) +static INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) { struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h index 71e629d29c79..3b8e17b619ba 100644 --- a/drivers/staging/bcm/InterfaceInit.h +++ b/drivers/staging/bcm/InterfaceInit.h @@ -19,11 +19,7 @@ INT InterfaceInitialize(void); INT InterfaceExit(void); -INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter); - INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter); -VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter); - #endif diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c index 2d26e2ed38d9..423464765e59 100644 --- a/drivers/staging/bcm/InterfaceIsr.c +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -167,39 +167,3 @@ INT StartInterruptUrb(PS_INTERFACE_ADAPTER psIntfAdapter) return status; } -/* -Function: InterfaceEnableInterrupt - -Description: This is the hardware specific Function for configuring - and enabling the interrupts on the device. - -Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context - - -Return: BCM_STATUS_SUCCESS - If configuring the interrupts was successful. - Other - If an error occured. -*/ - -void InterfaceEnableInterrupt(PMINI_ADAPTER Adapter) -{ - -} - -/* -Function: InterfaceDisableInterrupt - -Description: This is the hardware specific Function for disabling the interrupts on the device. - -Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context - - -Return: BCM_STATUS_SUCCESS - If disabling the interrupts was successful. - Other - If an error occured. -*/ - -void InterfaceDisableInterrupt(PMINI_ADAPTER Adapter) -{ - -} - - diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 8212af3ecf90..2f849b2a1275 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -1,5 +1,12 @@ #include "headers.h" +static int BcmFileDownload(PMINI_ADAPTER Adapter, const char *path, + unsigned int loc); +static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter); +static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer); +static int bcm_parse_target_params(PMINI_ADAPTER Adapter); +static void beceem_protocol_reset (PMINI_ADAPTER Adapter); + static VOID default_wimax_protocol_initialize(PMINI_ADAPTER Adapter) { @@ -175,7 +182,7 @@ static int create_worker_threads(PMINI_ADAPTER psAdapter) return 0; } -static struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path) +static struct file *open_firmware_file(PMINI_ADAPTER Adapter, const char *path) { struct file *flp=NULL; mm_segment_t oldfs; @@ -197,8 +204,8 @@ static struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path) } -int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */ - char *path, /**< path to image file */ +static int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */ + const char *path, /**< path to image file */ unsigned int loc /**< Download Address on the chip*/ ) { @@ -478,18 +485,6 @@ static VOID SendStatisticsPointerRequest(PMINI_ADAPTER Adapter, #endif -void SendLinkDown(PMINI_ADAPTER Adapter) -{ - LINK_REQUEST stLinkDownRequest; - memset(&stLinkDownRequest, 0, sizeof(LINK_REQUEST)); - stLinkDownRequest.Leader.Status=LINK_UP_CONTROL_REQ; - stLinkDownRequest.Leader.PLength=sizeof(ULONG);//minimum 4 bytes - stLinkDownRequest.szData[0]=LINK_DOWN_REQ_PAYLOAD; - Adapter->bLinkDownRequested = TRUE; - - CopyBufferToControlPacket(Adapter,&stLinkDownRequest); -} - /****************************************************************** * Function - LinkMessage() * @@ -1229,7 +1224,7 @@ OUT: } -int bcm_parse_target_params(PMINI_ADAPTER Adapter) +static int bcm_parse_target_params(PMINI_ADAPTER Adapter) { struct file *flp=NULL; mm_segment_t oldfs={0}; @@ -1357,7 +1352,7 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter) } -VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter) +static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter) { UINT reporting_mode; @@ -1496,26 +1491,7 @@ int rdmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size) return uiRetVal; } -int rdmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize) -{ - INT status = STATUS_SUCCESS ; - down(&Adapter->rdmwrmsync); - - if((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus ==TRUE) || - (Adapter->bPreparingForLowPowerMode ==TRUE)) - { - status = -EACCES; - goto exit; - } - - status = rdm(Adapter, uiAddress, pucBuff, sSize); - -exit: - up(&Adapter->rdmwrmsync); - return status ; -} int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize) { INT status = STATUS_SUCCESS ; @@ -1707,7 +1683,7 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter) } -void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer) +static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer) { B_UINT32 uiResetValue = 0; @@ -1891,7 +1867,7 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex) } -void beceem_protocol_reset (PMINI_ADAPTER Adapter) +static void beceem_protocol_reset (PMINI_ADAPTER Adapter) { int i; diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c index 44ddb59c2ecc..d1ca1912a74b 100644 --- a/drivers/staging/bcm/PHSModule.c +++ b/drivers/staging/bcm/PHSModule.c @@ -1,5 +1,51 @@ #include "headers.h" +static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI); + +static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI); + +static UINT CreateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI); + +static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI); + +static BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule); + +static BOOLEAN DerefPhsRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule); + +static UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry); + +static UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule); + +static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable); + +static int phs_compress(S_PHS_RULE *phs_members,unsigned char *in_buf, + unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size ); + + +static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer, + unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size ); + +static int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\ + S_PHS_RULE *phs_rules,UINT *header_size); + + +static ULONG PhsCompress(void* pvContext, + B_UINT16 uiVcid, + B_UINT16 uiClsId, + void *pvInputBuffer, + void *pvOutputBuffer, + UINT *pOldHeaderSize, + UINT *pNewHeaderSize ); + +static ULONG PhsDeCompress(void* pvContext, + B_UINT16 uiVcid, + void *pvInputBuffer, + void *pvOutputBuffer, + UINT *pInHeaderSize, + UINT *pOutHeaderSize); + + + #define IN #define OUT @@ -798,7 +844,7 @@ ULONG PhsDeCompress(IN void* pvContext, // Does not return any value. //----------------------------------------------------------------------------- -void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable) +static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable) { int i,j; PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); @@ -852,7 +898,7 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable) -BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule) +static BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule) { if(psPhsRule) { @@ -935,9 +981,9 @@ UINT GetClassifierEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable, return PHS_INVALID_TABLE_INDEX; } -UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable, - IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, - OUT S_PHS_RULE **ppstPhsRule) +static UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable, + IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, + OUT S_PHS_RULE **ppstPhsRule) { int i; S_CLASSIFIER_ENTRY *pstClassifierRule = NULL; @@ -1094,7 +1140,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid, return uiStatus; } -UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId, +static UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId, S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule, E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI) { @@ -1205,7 +1251,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId, } -UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, +static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, IN S_CLASSIFIER_ENTRY *pstClassifierEntry, S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule, B_UINT8 u8AssociatedPHSI) @@ -1266,7 +1312,7 @@ UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, } -BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule) +static BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule) { if(pstPhsRule==NULL) return FALSE; @@ -1444,8 +1490,8 @@ int phs_decompress(unsigned char *in_buf,unsigned char *out_buf, // size-The number of bytes copied into the output buffer i.e dynamic fields // 0 -If PHS rule is NULL.If PHSV field is not set.If the verification fails. //----------------------------------------------------------------------------- -int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf - ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size) +static int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf + ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size) { unsigned char *old_addr = out_buf; int supress = 0; @@ -1505,9 +1551,9 @@ int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf // 0 -Packet has failed the verification. //----------------------------------------------------------------------------- - int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer, - unsigned char *phsf,unsigned char *phsm,unsigned int phss, - unsigned int phsv,UINT* new_header_size) +static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer, + unsigned char *phsf,unsigned char *phsm,unsigned int phss, + unsigned int phsv,UINT* new_header_size) { unsigned int size=0; int bit,i=0; diff --git a/drivers/staging/bcm/PHSModule.h b/drivers/staging/bcm/PHSModule.h index bf2b5763252c..0dd05a7c55d9 100644 --- a/drivers/staging/bcm/PHSModule.h +++ b/drivers/staging/bcm/PHSModule.h @@ -27,19 +27,6 @@ void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension); int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter); -void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable); - -int phs_compress(S_PHS_RULE *phs_members,unsigned char *in_buf, - unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size ); - - -int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer, - unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size ); - -int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\ - S_PHS_RULE *phs_rules,UINT *header_size); - - int PhsCleanup(PPHS_DEVICE_EXTENSION pPHSDeviceExt); //Utility Functions @@ -52,42 +39,10 @@ ULONG PhsDeleteClassifierRule(void* pvContext, B_UINT16 uiVcid ,B_UINT16 uiClsI ULONG PhsDeleteSFRules(void* pvContext,B_UINT16 uiVcid) ; -ULONG PhsCompress(void* pvContext, - B_UINT16 uiVcid, - B_UINT16 uiClsId, - void *pvInputBuffer, - void *pvOutputBuffer, - UINT *pOldHeaderSize, - UINT *pNewHeaderSize ); - -ULONG PhsDeCompress(void* pvContext, - B_UINT16 uiVcid, - void *pvInputBuffer, - void *pvOutputBuffer, - UINT *pInHeaderSize, - UINT *pOutHeaderSize); - - BOOLEAN ValidatePHSRule(S_PHS_RULE *psPhsRule); -BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule); - UINT GetServiceFlowEntry(S_SERVICEFLOW_TABLE *psServiceFlowTable,B_UINT16 uiVcid,S_SERVICEFLOW_ENTRY **ppstServiceFlowEntry); -UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry); - -UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule); - - -UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI); - -UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI); - -UINT CreateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI); - -UINT UpdateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI); - -BOOLEAN DerefPhsRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule); void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension); diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index 920e9882ccd1..c27fce875be7 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -1,19 +1,12 @@ #ifndef _PROTOTYPES_H_ #define _PROTOTYPES_H_ -int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */ - char *path, /**< path to image file */ - unsigned int loc /**< Download Address on the chip*/ - ); VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter, PUCHAR pucBuffer); VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer); VOID IdleModeResponse(PMINI_ADAPTER Adapter,PUINT puiBuffer); -VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, /**data))->au8SourceAddress); @@ -802,9 +808,11 @@ BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_ return bClassificationSucceed; } -void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo) +static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload, + PS_ETHCS_PKT_INFO pstEthCsPktInfo) { USHORT u16Etype = ntohs(((ETH_HEADER_STRUC*)pvEthPayload)->u16Etype); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n",u16Etype); if(u16Etype > 0x5dc) { diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index 4f1b35a68b7f..5c10769abb55 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -1,6 +1,56 @@ #include "headers.h" #define DWORD unsigned int + +static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset); +static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter); +static INT BcmGetActiveISO(PMINI_ADAPTER Adapter); +static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter); +static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter); +static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize); + +static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter); +static INT BcmGetNvmSize(PMINI_ADAPTER Adapter); +static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter); +static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter); + +static INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal); + +static B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset); +static INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section); +static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section); + +static INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd); +static INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd); +static INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso); +static INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso); + +static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal); +static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal); +static INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiSectAlignAddr); +static INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter, PUINT pBuff, + FLASH2X_SECTION_VAL eFlash2xSectionVal, + UINT uiOffset, UINT uiNumBytes); +static FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter); +static FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter); + +static INT BeceemFlashBulkRead( + PMINI_ADAPTER Adapter, + PUINT pBuffer, + UINT uiOffset, + UINT uiNumBytes); + +static INT BeceemFlashBulkWrite( + PMINI_ADAPTER Adapter, + PUINT pBuffer, + UINT uiOffset, + UINT uiNumBytes, + BOOLEAN bVerify); + +static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter); + +static INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData, UINT dwNumData); + // Procedure: ReadEEPROMStatusRegister // // Description: Reads the standard EEPROM Status Register. @@ -409,7 +459,7 @@ INT BeceemEEPROMBulkRead( // - if failed. //----------------------------------------------------------------------------- -INT BeceemFlashBulkRead( +static INT BeceemFlashBulkRead( PMINI_ADAPTER Adapter, PUINT pBuffer, UINT uiOffset, @@ -491,7 +541,7 @@ INT BeceemFlashBulkRead( // //----------------------------------------------------------------------------- -UINT BcmGetFlashSize(PMINI_ADAPTER Adapter) +static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter) { if(IsFlash2x(Adapter)) return (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER)); @@ -514,7 +564,7 @@ UINT BcmGetFlashSize(PMINI_ADAPTER Adapter) // //----------------------------------------------------------------------------- -UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter) +static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter) { UINT uiData = 0; UINT uiIndex = 0; @@ -1108,7 +1158,7 @@ static ULONG BcmFlashUnProtectBlock(PMINI_ADAPTER Adapter,UINT uiOffset, UINT ui // //----------------------------------------------------------------------------- -INT BeceemFlashBulkWrite( +static INT BeceemFlashBulkWrite( PMINI_ADAPTER Adapter, PUINT pBuffer, UINT uiOffset, @@ -1613,11 +1663,8 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter) } pBuff = kmalloc(uiEepromSize, GFP_KERNEL); - if ( pBuff == NULL ) - { return -1; - } if(0 != BeceemNVMRead(Adapter,(PUINT)pBuff,uiCalStartAddr, uiEepromSize)) { @@ -2274,7 +2321,7 @@ INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize) // //----------------------------------------------------------------------------- -UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize) +static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize) { UINT uiSectorSize = 0; UINT uiSectorSig = 0; @@ -2411,7 +2458,7 @@ INT BcmInitNVM(PMINI_ADAPTER ps_adapter) */ /***************************************************************************/ -INT BcmGetNvmSize(PMINI_ADAPTER Adapter) +static INT BcmGetNvmSize(PMINI_ADAPTER Adapter) { if(Adapter->eNVMType == NVM_EEPROM) { @@ -2435,7 +2482,7 @@ INT BcmGetNvmSize(PMINI_ADAPTER Adapter) // Returns: // //----------------------------------------------------------------------------- -VOID BcmValidateNvmType(PMINI_ADAPTER Adapter) +static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter) { // @@ -2681,7 +2728,7 @@ static INT ConvertEndianOfCSStructure(PFLASH_CS_INFO psFlashCSInfo) return STATUS_SUCCESS; } -INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section) +static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section) { return ( Adapter->uiVendorExtnFlag && (Adapter->psFlash2xVendorInfo->VendorSection[section].AccessFlags & FLASH2X_SECTION_PRESENT) && @@ -2779,7 +2826,7 @@ static VOID UpdateVendorInfo(PMINI_ADAPTER Adapter) // //----------------------------------------------------------------------------- -INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) +static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) { //FLASH_CS_INFO sFlashCsInfo = {0}; @@ -2926,7 +2973,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter) // //----------------------------------------------------------------------------- -NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter) +static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter) { UINT uiData = 0; @@ -3280,39 +3327,6 @@ INT BcmFlash2xBulkWrite( } -/** -* ReadDSDHeader : Read the DSD map for the DSD Section val provided in Argument. -* @Adapter : Beceem Private Data Structure -* @psDSDHeader :Pointer of the buffer where header has to be read -* @dsd :value of the Dyanmic DSD like DSD0 of DSD1 or DSD2 -* -* Return Value:- -* if suceeds return STATUS_SUCCESS or negative error code. -**/ -INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTION_VAL dsd) -{ - INT Status = STATUS_SUCCESS; - - Status =BcmFlash2xBulkRead(Adapter, - (PUINT)psDSDHeader, - dsd, - Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader, - sizeof(DSD_HEADER)); - if(Status == STATUS_SUCCESS) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageMagicNumber :0X%x", ntohl(psDSDHeader->DSDImageMagicNumber)); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageSize :0X%x ",ntohl(psDSDHeader->DSDImageSize)); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageCRC :0X%x",ntohl(psDSDHeader->DSDImageCRC)); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImagePriority :0X%x",ntohl(psDSDHeader->DSDImagePriority)); - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"DSD Header read is failed with status :%d", Status); - } - - return Status; -} - /** * BcmGetActiveDSD : Set the Active DSD in Adapter Structure which has to be dumped in DDR * @Adapter :-Drivers private Data Structure @@ -3321,7 +3335,7 @@ INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTIO * Return STATUS_SUCESS if get sucess in setting the right DSD else negaive error code * **/ -INT BcmGetActiveDSD(PMINI_ADAPTER Adapter) +static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter) { FLASH2X_SECTION_VAL uiHighestPriDSD = 0 ; @@ -3359,39 +3373,6 @@ INT BcmGetActiveDSD(PMINI_ADAPTER Adapter) return STATUS_SUCCESS; } -/** -* ReadISOUnReservedBytes : Read the ISO map for the ISO Section val provided in Argument. -* @Adapter : Driver Private Data Structure -* @psISOHeader :Pointer of the location where header has to be read -* @IsoImage :value of the Dyanmic ISO like ISO_IMAGE1 of ISO_IMAGE2 -* -* Return Value:- -* if suceeds return STATUS_SUCCESS or negative error code. -**/ - -INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTION_VAL IsoImage) -{ - INT Status = STATUS_SUCCESS; - - Status = BcmFlash2xBulkRead(Adapter, - (PUINT)psISOHeader, - IsoImage, - 0, - sizeof(ISO_HEADER)); - - if(Status == STATUS_SUCCESS) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageMagicNumber :0X%x", ntohl(psISOHeader->ISOImageMagicNumber)); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageSize :0X%x ",ntohl(psISOHeader->ISOImageSize)); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageCRC :0X%x",ntohl(psISOHeader->ISOImageCRC)); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImagePriority :0X%x",ntohl(psISOHeader->ISOImagePriority)); - } - else - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "ISO Header Read failed"); - } - return Status; -} /** * BcmGetActiveISO :- Set the Active ISO in Adapter Data Structue @@ -3403,7 +3384,7 @@ INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTIO * **/ -INT BcmGetActiveISO(PMINI_ADAPTER Adapter) +static INT BcmGetActiveISO(PMINI_ADAPTER Adapter) { INT HighestPriISO = 0 ; @@ -4501,7 +4482,7 @@ Return Value:- Success :- Base Address of the Flash **/ -INT GetFlashBaseAddr(PMINI_ADAPTER Adapter) +static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter) { UINT uiBaseAddr = 0; @@ -4734,29 +4715,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset) return STATUS_SUCCESS ; } -INT BcmMakeFlashCSActive(PMINI_ADAPTER Adapter, UINT offset) -{ - UINT GPIOConfig = 0 ; - - - if(Adapter->bFlashRawRead == FALSE) - { - //Applicable for Flash2.x - if(IsFlash2x(Adapter) == FALSE) - return STATUS_SUCCESS; - } - if(offset/FLASH_PART_SIZE) - { - //bit[14..12] -> will select make Active CS1, CS2 or CS3 - // Select CS1, CS2 and CS3 (CS0 is dedicated pin) - rdmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4); - GPIOConfig |= (7 << 12); - wrmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4); - } - - return STATUS_SUCCESS ; -} /** BcmDoChipSelect : This will selcet the appropriate chip for writing. @Adapater :- Bcm Driver Private Data Structure @@ -4764,7 +4723,7 @@ BcmDoChipSelect : This will selcet the appropriate chip for writing. OutPut:- Select the Appropriate chip and retrn status Sucess **/ -INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset) +static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset) { UINT FlashConfig = 0; INT ChipNum = 0; @@ -5136,7 +5095,7 @@ INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section) return Status ; } -INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) +static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) { PUCHAR pBuff = NULL; @@ -5209,7 +5168,7 @@ INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) return STATUS_SUCCESS ; } -INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) +static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal) { PUCHAR pBuff = NULL; -- cgit v1.2.3 From 429a5908fe3bc4d9ca2512b94cd10b69d50bf91f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:27:20 -0400 Subject: beceem: off by one on queue index The driver allocates 18 queues (0..16) are for traffic, and 17 is a bit bucket. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h index f2fd60286a4c..feb351578c8b 100644 --- a/drivers/staging/bcm/Macros.h +++ b/drivers/staging/bcm/Macros.h @@ -261,7 +261,7 @@ typedef enum _E_PHS_DSC_ACTION #define FIRMWARE_BEGIN_ADDR 0xBFC00000 -#define INVALID_QUEUE_INDEX (NO_OF_QUEUES+1) +#define INVALID_QUEUE_INDEX NO_OF_QUEUES #define INVALID_PID (pid_t)-1 #define DDR_80_MHZ 0 -- cgit v1.2.3 From b5ebd85b2bcc0c0a2171e4cc74c61debdc903ddf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 12:28:39 -0400 Subject: beceem: do classification even if device is offline Since classification and queue control are separate, allow classification even if device is down now; this avoids races on startup/shutdown. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Qos.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 54e9a490e6f9..e4d5a67c8c6b 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -524,12 +524,6 @@ USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb) for(uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--) { - if (Adapter->device_removed) - { - bClassificationSucceed = FALSE; - break; - } - if(bClassificationSucceed) break; //Iterate through all classifiers which are already in order of priority -- cgit v1.2.3 From cacd92222dd4e04424fa532cf1a222e67c30709b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 13:34:35 -0400 Subject: beceem: statistics and transmit queue changes Use standard network statistics variables and routines. Transmit counters are per queue, and skb mapping is already in skb and does not need to be recomputed. Move SearchVcId to only place it is used. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 9 --------- drivers/staging/bcm/Bcmnet.c | 20 -------------------- drivers/staging/bcm/CmHost.c | 12 ------------ drivers/staging/bcm/InterfaceRx.c | 21 ++++++++++++++++----- drivers/staging/bcm/Misc.c | 2 -- drivers/staging/bcm/Prototypes.h | 2 -- drivers/staging/bcm/Qos.c | 13 +++++++------ drivers/staging/bcm/Transmit.c | 21 ++++++++++----------- drivers/staging/bcm/hostmibs.c | 7 ++----- drivers/staging/bcm/led_control.c | 10 ++++++---- 10 files changed, 41 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index e5aaec508bf9..5e97cbeb58ec 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -414,17 +414,8 @@ struct _MINI_ADAPTER // this to keep track of the Tx and Rx MailBox Registers. atomic_t CurrNumFreeTxDesc; // to keep track the no of byte recieved - atomic_t RxRollOverCount; USHORT PrevNumRecvDescs; USHORT CurrNumRecvDescs; - atomic_t GoodRxByteCount; - atomic_t GoodRxPktCount; - atomic_t BadRxByteCount; - atomic_t RxPacketDroppedCount; - atomic_t GoodTxByteCount; - atomic_t TxTotalPacketCount; - atomic_t TxDroppedPacketCount; - UINT u32TotalDSD; PacketInfo PackInfo[NO_OF_QUEUES]; S_CLASSIFIER_RULE astClassifierTable[MAX_CLASSIFIERS]; diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 82270c18c6ac..eb224a9dafab 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -48,25 +48,6 @@ static INT bcm_close(struct net_device *dev) return 0; } -static struct net_device_stats *bcm_get_stats(struct net_device *dev) -{ - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev); - struct net_device_stats* netstats = &dev->stats; - - netstats->rx_packets = atomic_read(&Adapter->RxRollOverCount)*64*1024 - + Adapter->PrevNumRecvDescs; - netstats->rx_bytes = atomic_read(&Adapter->GoodRxByteCount) - + atomic_read(&Adapter->BadRxByteCount); - - netstats->rx_dropped = atomic_read(&Adapter->RxPacketDroppedCount); - netstats->rx_errors = atomic_read(&Adapter->RxPacketDroppedCount); - netstats->tx_bytes = atomic_read(&Adapter->GoodTxByteCount); - netstats->tx_packets = atomic_read(&Adapter->TxTotalPacketCount); - netstats->tx_dropped = atomic_read(&Adapter->TxDroppedPacketCount); - - return netstats; -} - static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb) { return ClassifyPacket(netdev_priv(dev), skb); @@ -140,7 +121,6 @@ Register other driver entry points with the kernel static const struct net_device_ops bcmNetDevOps = { .ndo_open = bcm_open, .ndo_stop = bcm_close, - .ndo_get_stats = bcm_get_stats, .ndo_start_xmit = bcm_transmit, .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 553da135c828..38b64e69d81a 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -58,18 +58,6 @@ static INT SearchFreeSfid(PMINI_ADAPTER Adapter) return NO_OF_QUEUES+1; } -int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid) -{ - int iIndex=0; - - for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--) - if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid) - return iIndex; - return NO_OF_QUEUES+1; - -} - - /* Function: SearchClsid Description: This routinue would search Classifier having specified ClassifierID as input parameter diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c index 07326a97c4a2..533f8ebe0f84 100644 --- a/drivers/staging/bcm/InterfaceRx.c +++ b/drivers/staging/bcm/InterfaceRx.c @@ -1,5 +1,15 @@ #include "headers.h" -extern int SearchVcid(PMINI_ADAPTER , unsigned short); + +static int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid) +{ + int iIndex=0; + + for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--) + if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid) + return iIndex; + return NO_OF_QUEUES+1; + +} static PUSB_RCB @@ -88,8 +98,7 @@ static void read_bulk_callback(struct urb *urb) if (netif_msg_rx_err(Adapter)) pr_info(PFX "%s: corrupted leader length...%d\n", Adapter->dev->name, pLeader->PLength); - atomic_inc(&Adapter->RxPacketDroppedCount); - atomic_add(pLeader->PLength, &Adapter->BadRxByteCount); + ++Adapter->dev->stats.rx_dropped; atomic_dec(&psIntfAdapter->uNumRcbUsed); return; } @@ -142,7 +151,6 @@ static void read_bulk_callback(struct urb *urb) skb_put (skb, pLeader->PLength + ETH_HLEN); Adapter->PackInfo[QueueIndex].uiTotalRxBytes+=pLeader->PLength; Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes+= pLeader->PLength; - atomic_add(pLeader->PLength, &Adapter->GoodRxByteCount); BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt of len :0x%X", pLeader->PLength); if(netif_running(Adapter->dev)) @@ -172,7 +180,10 @@ static void read_bulk_callback(struct urb *urb) BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB..."); dev_kfree_skb(skb); } - atomic_inc(&Adapter->GoodRxPktCount); + + ++Adapter->dev->stats.rx_packets; + Adapter->dev->stats.rx_bytes += pLeader->PLength; + for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++) { if((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 2f849b2a1275..c1d73a70f9e4 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -1859,8 +1859,6 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex) dev_kfree_skb(PacketToDrop); atomic_dec(&Adapter->TotalPacketCount); - atomic_inc(&Adapter->TxDroppedPacketCount); - } } spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index c27fce875be7..ba0444e70577 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -93,8 +93,6 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter); int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo); -int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid); - void CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter, CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex); diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index e4d5a67c8c6b..88ec3b20742d 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -359,12 +359,13 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex) if(PacketToDrop) { + struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iIndex); if (netif_msg_tx_err(Adapter)) pr_info(PFX "%s: tx queue %d overlimit\n", Adapter->dev->name, iIndex); - netstats->tx_dropped++; - atomic_inc(&Adapter->TxDroppedPacketCount); + txq->tx_dropped++; + DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue, Adapter->PackInfo[iIndex].LastTxQueue); /// update current bytes and packets count @@ -397,14 +398,15 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) { INT iQIndex; UINT uiTotalPacketLength; - struct sk_buff* PacketToDrop=NULL; - struct net_device_stats* netstats=&Adapter->dev->stats; + struct sk_buff* PacketToDrop=NULL; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>"); // down(&Adapter->data_packet_queue_lock); for(iQIndex=LowPriority; iQIndexdev, iQIndex); + spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); while(Adapter->PackInfo[iQIndex].FirstTxQueue) { @@ -412,8 +414,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) if(PacketToDrop) { uiTotalPacketLength = PacketToDrop->len; - netstats->tx_dropped++; - atomic_inc(&Adapter->TxDroppedPacketCount); + txq->tx_dropped++; } else uiTotalPacketLength = 0; diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index b924a6a4dd78..972e6ab6fae6 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -90,7 +90,7 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid) int status=0; BOOLEAN bHeaderSupressionEnabled = FALSE; B_UINT16 uiClassifierRuleID; - int QueueIndex = NO_OF_QUEUES + 1; + u16 QueueIndex = skb_get_queue_mapping(Packet); LEADER Leader={0}; if(Packet->len > MAX_DEVICE_DESC_SIZE) @@ -101,14 +101,10 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid) /* Get the Classifier Rule ID */ uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET); - QueueIndex = SearchVcid( Adapter,Vcid); - if(QueueIndex < NO_OF_QUEUES) - { - bHeaderSupressionEnabled = - Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled; - bHeaderSupressionEnabled = - bHeaderSupressionEnabled & Adapter->bPHSEnabled; - } + + bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled + & Adapter->bPHSEnabled; + if(Adapter->device_removed) { status = STATUS_FAILURE; @@ -162,9 +158,12 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid) } else { + struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, QueueIndex); Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; - Adapter->dev->stats.tx_bytes += Leader.PLength; - ++Adapter->dev->stats.tx_packets; + + txq->tx_bytes += Leader.PLength; + ++txq->tx_packets; + Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3; Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len); Adapter->PackInfo[QueueIndex].uiSentPackets++; diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index 144590037b24..c13ea5c9a2aa 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -82,12 +82,9 @@ INT ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMi } - //copy other Host Statistics parameters - pstHostMibs->stHostInfo.GoodTransmits = - atomic_read(&Adapter->TxTotalPacketCount); - pstHostMibs->stHostInfo.GoodReceives = - atomic_read(&Adapter->GoodRxPktCount); + pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets; + pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets; pstHostMibs->stHostInfo.CurrNumFreeDesc = atomic_read(&Adapter->CurrNumFreeTxDesc); pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize; diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c index a21d219f428c..16e939fa15d6 100644 --- a/drivers/staging/bcm/led_control.c +++ b/drivers/staging/bcm/led_control.c @@ -108,8 +108,9 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx, ulong timeout = 0; /*Read initial value of packets sent/received */ - Initial_num_of_packts_tx = atomic_read(&Adapter->TxTotalPacketCount); - Initial_num_of_packts_rx = atomic_read(&Adapter->GoodRxPktCount); + Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets; + Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets; + /*Scale the rate of transfer to no of blinks.*/ num_of_time_tx= ScaleRateofTransfer((ULONG)rate_of_transfer_tx); num_of_time_rx= ScaleRateofTransfer((ULONG)rate_of_transfer_rx); @@ -212,9 +213,10 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx, * Read the Tx & Rx packets transmission after 1 second and * calculate rate of transfer */ - Final_num_of_packts_tx = atomic_read(&Adapter->TxTotalPacketCount); + Final_num_of_packts_tx = Adapter->dev->stats.tx_packets; + Final_num_of_packts_rx = Adapter->dev->stats.rx_packets; + rate_of_transfer_tx = Final_num_of_packts_tx - Initial_num_of_packts_tx; - Final_num_of_packts_rx = atomic_read(&Adapter->GoodRxPktCount); rate_of_transfer_rx = Final_num_of_packts_rx - Initial_num_of_packts_rx; /*Read initial value of packets sent/received */ -- cgit v1.2.3 From 78afa9990fdbbf01227104300a657be3f3caa167 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 13:54:21 -0400 Subject: beceem: fix definition of VLAN header type Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Protocol.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Protocol.h b/drivers/staging/bcm/Protocol.h index 00f1cc12356a..b8a4009bdf0c 100644 --- a/drivers/staging/bcm/Protocol.h +++ b/drivers/staging/bcm/Protocol.h @@ -85,10 +85,10 @@ typedef struct _ETH_CS_ETH2_FRAME ETH_HEADER_STRUC EThHdr; } __attribute__((packed)) ETH_CS_ETH2_FRAME; +#define ETHERNET_FRAMETYPE_IPV4 ntohs(0x0800) +#define ETHERNET_FRAMETYPE_IPV6 ntohs(0x86dd) +#define ETHERNET_FRAMETYPE_802QVLAN ntohs(0x8100) -#define ETHERNET_FRAMETYPE_IPV4 ntohs(0x0800) -#define ETHERNET_FRAMETYPE_IPV6 ntohs(0x86dd) -#define ETHERNET_FRAMETYPE_802QVLAN 0x8100 //Per SF CS Specification Encodings typedef enum _E_SERVICEFLOW_CS_SPEC_ { -- cgit v1.2.3 From 5cf084f44ac24189ef3373010da49e26d651aa06 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 13:57:35 -0400 Subject: beceem: eliminate unused bcm_jiffies Unused, unneeded, and bogus. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Adapter.h | 1 - drivers/staging/bcm/LeakyBucket.c | 24 +++--------------------- drivers/staging/bcm/Qos.c | 1 - drivers/staging/bcm/Transmit.c | 6 ------ 4 files changed, 3 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 5e97cbeb58ec..62f9135d4d40 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -404,7 +404,6 @@ struct _MINI_ADAPTER PPER_TARANG_DATA pTarangs; spinlock_t control_queue_lock; wait_queue_head_t process_read_wait_queue; - ULONG bcm_jiffies; /* Store Jiffies value */ // the pointer to the first packet we have queued in send // deserialized miniport support variables diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c index 669acc8d088b..f4cf41c0e46b 100644 --- a/drivers/staging/bcm/LeakyBucket.c +++ b/drivers/staging/bcm/LeakyBucket.c @@ -172,10 +172,8 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount "); if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Device is in Idle Mode..Hence blocking Data Packets..\n"); - return; - } + return; /* in idle mode */ + // Check for Free Descriptors if(atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS) { @@ -262,17 +260,6 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF) } } } - - if(Status != STATUS_SUCCESS) //Tx of data packet to device Failed - { - if(Adapter->bcm_jiffies == 0) - Adapter->bcm_jiffies = jiffies; - } - else - { - Adapter->bcm_jiffies = 0; - } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<====="); } @@ -359,12 +346,7 @@ VOID transmit_packets(PMINI_ADAPTER Adapter) if(exit_flag == TRUE ) break ; }/* end of inner while loop */ - if(Adapter->bcm_jiffies == 0 && - atomic_read(&Adapter->TotalPacketCount) != 0 && - uiPrevTotalCount == atomic_read(&Adapter->TotalPacketCount)) - { - Adapter->bcm_jiffies = jiffies; - } + update_per_cid_rx (Adapter); Adapter->txtransmit_running = 0; BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======"); diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 88ec3b20742d..8ce4536e6e28 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -384,7 +384,6 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex) Adapter->PackInfo[iIndex].uiDroppedCountPackets); atomic_dec(&Adapter->TotalPacketCount); - Adapter->bcm_jiffies = jiffies; } spin_unlock_bh(&Adapter->PackInfo[iIndex].SFQueueLock); diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 972e6ab6fae6..652ba27407af 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -55,12 +55,6 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, char *pControlPacket) ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1)) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET"); - if(Adapter->bcm_jiffies == 0) - { - Adapter->bcm_jiffies = jiffies; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu", - Adapter->bcm_jiffies); - } return STATUS_FAILURE; } -- cgit v1.2.3 From 9c5d77009db6ff09d02a7b0a99a70c0dfd3af6c6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 13:59:01 -0400 Subject: beceem: don't overrun user buffer on read Serious bug in original code, if app reads 10 bytes but 20 byte msg received memory would get overwritten. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmchar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index 1a255609aeda..8089d19e6c1b 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -139,7 +139,7 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l if(Packet) { PktLen = Packet->len; - if(copy_to_user(buf, Packet->data, PktLen)) + if(copy_to_user(buf, Packet->data, min_t(size_t, PktLen, size))) { dev_kfree_skb(Packet); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nReturning from copy to user failure \n"); -- cgit v1.2.3 From 4ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 14:06:24 -0400 Subject: beceem: change startup messages Change the regsister/unregister routines to generate better messages, and control arrival of new frames when USB device is unplugged. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/Bcmnet.c | 52 ++++++++++++++++++++++++------------- drivers/staging/bcm/InterfaceInit.c | 32 +++++++++++------------ drivers/staging/bcm/Misc.c | 2 +- drivers/staging/bcm/Prototypes.h | 1 + drivers/staging/bcm/nvm.c | 32 +++-------------------- 5 files changed, 56 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index eb224a9dafab..a6ce2396c791 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -1,14 +1,5 @@ #include "headers.h" -static int debug = -1; -module_param(debug, uint, 0600); -MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); - -static const u32 default_msg = - NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK - | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR - | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; - struct net_device *gblpnetdev; static INT bcm_open(struct net_device *dev) @@ -194,6 +185,10 @@ static const struct ethtool_ops bcm_ethtool_ops = { int register_networkdev(PMINI_ADAPTER Adapter) { struct net_device *net = Adapter->dev; + PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *udev = IntfAdapter->interface; + struct usb_device *xdev = IntfAdapter->udev; + int result; net->netdev_ops = &bcmNetDevOps; @@ -201,22 +196,43 @@ int register_networkdev(PMINI_ADAPTER Adapter) net->mtu = MTU_SIZE; /* 1400 Bytes */ net->tx_queue_len = TX_QLEN; net->flags |= IFF_NOARP; - Adapter->msg_enable = netif_msg_init(debug, default_msg); netif_carrier_off(net); SET_NETDEV_DEVTYPE(net, &wimax_type); /* Read the MAC Address from EEPROM */ - ReadMacAddressFromNVM(Adapter); + result = ReadMacAddressFromNVM(Adapter); + if (result != STATUS_SUCCESS) { + dev_err(&udev->dev, + PFX "Error in Reading the mac Address: %d", result); + return -EIO; + } result = register_netdev(net); - if (result == 0) - gblpnetdev = Adapter->dev = net; - else { - Adapter->dev = NULL; - free_netdev(net); - } + if (result) + return result; + + gblpnetdev = Adapter->dev; - return result; + if (netif_msg_probe(Adapter)) + dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n", + net->name, xdev->bus->bus_name, xdev->devpath, + net->dev_addr); + + return 0; +} + +void unregister_networkdev(PMINI_ADAPTER Adapter) +{ + struct net_device *net = Adapter->dev; + PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *udev = IntfAdapter->interface; + struct usb_device *xdev = IntfAdapter->udev; + + if (netif_msg_probe(Adapter)) + dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n", + net->name, xdev->bus->bus_name, xdev->devpath); + + unregister_netdev(Adapter->dev); } diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index a64092e940cc..8a26a3ef5bd3 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -11,6 +11,15 @@ static struct usb_device_id InterfaceUsbtable[] = { }; MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); +static int debug = -1; +module_param(debug, uint, 0600); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +static const u32 default_msg = + NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK + | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; + static INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter); static VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) @@ -158,6 +167,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) psAdapter = netdev_priv(ndev); psAdapter->dev = ndev; + psAdapter->msg_enable = netif_msg_init(debug, default_msg); /* Init default driver debug state */ @@ -269,32 +279,22 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) static void usbbcm_disconnect (struct usb_interface *intf) { - PS_INTERFACE_ADAPTER psIntfAdapter = NULL; - PMINI_ADAPTER psAdapter = NULL; - struct usb_device *udev = NULL; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); + PMINI_ADAPTER psAdapter; + struct usb_device *udev = interface_to_usbdev (intf); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Usb disconnected"); - if(intf == NULL) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "intf pointer is NULL"); - return; - } - psIntfAdapter = usb_get_intfdata(intf); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p",psIntfAdapter); if(psIntfAdapter == NULL) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapter pointer is NULL"); return; - } + psAdapter = psIntfAdapter->psAdapter; + netif_device_detach(psAdapter->dev); + if(psAdapter->bDoSuspend) intf->needs_remote_wakeup = 0; psAdapter->device_removed = TRUE ; usb_set_intfdata(intf, NULL); InterfaceAdapterFree(psIntfAdapter); - udev = interface_to_usbdev (intf); usb_put_dev(udev); } diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index c1d73a70f9e4..82d9f86821ca 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -132,7 +132,7 @@ VOID AdapterFree(PMINI_ADAPTER Adapter) if(Adapter->LEDInfo.led_thread_running & (BCM_LED_THREAD_RUNNING_ACTIVELY | BCM_LED_THREAD_RUNNING_INACTIVELY)) kthread_stop (Adapter->LEDInfo.led_cntrl_threadid); - unregister_netdev(Adapter->dev); + unregister_networkdev(Adapter); /* FIXME: use proper wait_event and refcounting */ while(atomic_read(&Adapter->ApplicationRunning)) diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index ba0444e70577..b80b806c90a3 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -52,6 +52,7 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Modem MAC Addr :"); - BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_PRINTK, 0, DBG_LVL_ALL,&Adapter->dev->dev_addr[0],MAC_ADDRESS_SIZE); - for(i=0;idev->dev_addr[i] == 0x00) - AllZeroMac++; - if(Adapter->dev->dev_addr[i] == 0xFF) - AllFFMac++; - - } - //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\n"); - if(AllZeroMac == MAC_ADDRESS_SIZE) - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Warning :: MAC Address has all 00's"); - if(AllFFMac == MAC_ADDRESS_SIZE) - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Warning :: MAC Address has all FF's"); + if(Status == STATUS_SUCCESS) + memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE); return Status; - } //----------------------------------------------------------------------------- -- cgit v1.2.3 From 349fa79498df313c70e2a4b7c16688be0a91dd0b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 14:09:05 -0400 Subject: beceem: dump control packet information Add control packet information is useful for debugging. Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/HandleControlPacket.c | 6 ++++-- drivers/staging/bcm/Transmit.c | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c index e7afa56c0dcf..2b1e9e17e11c 100644 --- a/drivers/staging/bcm/HandleControlPacket.c +++ b/drivers/staging/bcm/HandleControlPacket.c @@ -19,8 +19,10 @@ static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb) CHAR cntrl_msg_mask_bit = 0; BOOLEAN drop_pkt_flag = TRUE ; USHORT usStatus = *(PUSHORT)(skb->data); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "=====>"); - /* Get the Leader field */ + + if (netif_msg_pktdata(Adapter)) + print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE, + 16, 1, skb->data, skb->len, 0); switch(usStatus) { diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 652ba27407af..0f7000960d50 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -65,6 +65,11 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, char *pControlPacket) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength); if(Adapter->device_removed) return 0; + + if (netif_msg_pktdata(Adapter)) + print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE, + 16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0); + Adapter->interface_transmit(Adapter->pvInterfaceAdapter, pControlPacket, (PLeader->PLength + LEADER_SIZE)); -- cgit v1.2.3 From 2932af344a86cb1bd84ca8cc217ee016e8fb5255 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 1 Nov 2010 14:18:16 -0400 Subject: beceem: update TODO list Signed-off-by: Stephen Hemminger --- drivers/staging/bcm/TODO | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/TODO b/drivers/staging/bcm/TODO index 366634be5fe1..cd3e9f2ed87a 100644 --- a/drivers/staging/bcm/TODO +++ b/drivers/staging/bcm/TODO @@ -1,15 +1,22 @@ +This driver is barely functional in its current state. + +BIG: + - existing API is (/dev/tarang) should be replaced + Is it possible to use same API as Intel Wimax stack and + have same user level components. + - Qos and queue model is non-standard and inflexible. + Use existing TC Qos? + TODO: + - support more than one board - eliminate global variables + - remove developer debug BCM_DEBUG() macros + add a limited number of messages through netif_msg() - fix non-standard kernel style - - sparse warnings - checkpatch warnings - - remove compatiablity code for older kernels - - remove #ifdef's - - fix bogus device nameing and reference counting (see bcm_notify_event) - - fix use of file I/O to load config - - request firmware - - update to current network device API - - merge some files together + - use request firmware + - fix use of file I/O to load config with better API + - merge some files together? - cleanup/eliminate debug messages - - integrate with existing Wimax stack? + -- cgit v1.2.3 From 04561c5aa243c98cae93cde27e05740df787e692 Mon Sep 17 00:00:00 2001 From: Ignaz Forster Date: Mon, 1 Nov 2010 15:13:37 -0400 Subject: HID: Add Force Feedback support for EMS Trio Linker Plus II The device has connections for GameCube, PlayStation 2 and Dreamcast controllers, however Force Feedback is only supported for PS2 and GC controllers. When using a PS2 controller it may be necessary to press the "Analog" button to enable support for both motors (this behavior is identical to the Windows driver, I have found no way to avoid that). Signed-off-by: Ignaz Forster Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 10 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-emsff.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 3 + 5 files changed, 177 insertions(+) create mode 100644 drivers/hid/hid-emsff.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 3052e2969ad0..3d9a95f28aea 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -150,6 +150,16 @@ config DRAGONRISE_FF Say Y here if you want to enable force feedback support for DragonRise Inc. game controllers. +config HID_EMS_FF + tristate "EMS Production Inc. force feedback support" + depends on USB_HID + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to enable force feedback support for devices by + EMS Production Ltd. + Currently the following devices are known to be supported: + - Trio Linker Plus II + config HID_EGALAX tristate "eGalax multi-touch panel" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index c335605b9200..86192f67d7c2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o +obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_EGALAX) += hid-egalax.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7832b6e2478b..b3393e17b375 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1301,6 +1301,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, + { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c new file mode 100644 index 000000000000..c61b192d7cff --- /dev/null +++ b/drivers/hid/hid-emsff.c @@ -0,0 +1,162 @@ +/* + * Force feedback support for EMS Trio Linker Plus II + * + * Copyright (c) 2010 Ignaz Forster + */ + +/* + * 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 "hid-ids.h" +#include "usbhid/usbhid.h" + +struct emsff_device { + struct hid_report *report; +}; + +static int emsff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct emsff_device *emsff = data; + int weak, strong; + + weak = effect->u.rumble.weak_magnitude; + strong = effect->u.rumble.strong_magnitude; + + dbg_hid("called with 0x%04x 0x%04x\n", strong, weak); + + weak = weak * 0xff / 0xffff; + strong = strong * 0xff / 0xffff; + + emsff->report->field[0]->value[1] = weak; + emsff->report->field[0]->value[2] = strong; + + dbg_hid("running with 0x%02x 0x%02x\n", strong, weak); + usbhid_submit_report(hid, emsff->report, USB_DIR_OUT); + + return 0; +} + +static int emsff_init(struct hid_device *hid) +{ + struct emsff_device *emsff; + struct hid_report *report; + struct hid_input *hidinput = list_first_entry(&hid->inputs, + struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int error; + + if (list_empty(report_list)) { + dev_err(&hid->dev, "no output reports found\n"); + return -ENODEV; + } + + report = list_first_entry(report_list, struct hid_report, list); + if (report->maxfield < 1) { + dev_err(&hid->dev, "no fields in the report\n"); + return -ENODEV; + } + + if (report->field[0]->report_count < 7) { + dev_err(&hid->dev, "not enough values in the field\n"); + return -ENODEV; + } + + emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL); + if (!emsff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, emsff, emsff_play); + if (error) { + kfree(emsff); + return error; + } + + emsff->report = report; + emsff->report->field[0]->value[0] = 0x01; + emsff->report->field[0]->value[1] = 0x00; + emsff->report->field[0]->value[2] = 0x00; + emsff->report->field[0]->value[3] = 0x00; + emsff->report->field[0]->value[4] = 0x00; + emsff->report->field[0]->value[5] = 0x00; + emsff->report->field[0]->value[6] = 0x00; + usbhid_submit_report(hid, emsff->report, USB_DIR_OUT); + + dev_info(&hid->dev, "force feedback for EMS based devices by " + "Ignaz Forster \n"); + + return 0; +} + +static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + dev_err(&hdev->dev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + dev_err(&hdev->dev, "hw start failed\n"); + goto err; + } + + emsff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id ems_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_EMS, 0x118) }, + { } +}; +MODULE_DEVICE_TABLE(hid, ems_devices); + +static struct hid_driver ems_driver = { + .name = "hkems", + .id_table = ems_devices, + .probe = ems_probe, +}; + +static int ems_init(void) +{ + return hid_register_driver(&ems_driver); +} + +static void ems_exit(void) +{ + hid_unregister_driver(&ems_driver); +} + +module_init(ems_init); +module_exit(ems_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3ee999d33004..68114dbcd895 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -203,6 +203,9 @@ #define USB_VENDOR_ID_ELO 0x04E7 #define USB_DEVICE_ID_ELO_TS2700 0x0020 +#define USB_VENDOR_ID_EMS 0x2006 +#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 + #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 -- cgit v1.2.3 From b595076a180a56d1bb170e6eceda6eb9d76f4cd3 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 1 Nov 2010 15:38:34 -0400 Subject: tree-wide: fix comment/printk typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "gadget", "through", "command", "maintain", "maintain", "controller", "address", "between", "initiali[zs]e", "instead", "function", "select", "already", "equal", "access", "management", "hierarchy", "registration", "interest", "relative", "memory", "offset", "already", Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- Documentation/DocBook/mtdnand.tmpl | 2 +- Documentation/cgroups/cgroup_event_listener.c | 2 +- Documentation/cgroups/memcg_test.txt | 2 +- Documentation/kprobes.txt | 2 +- Documentation/kvm/api.txt | 2 +- Documentation/networking/caif/spi_porting.txt | 2 +- Documentation/powerpc/booting-without-of.txt | 2 +- Documentation/scsi/ChangeLog.lpfc | 2 +- Documentation/timers/timer_stats.txt | 2 +- arch/arm/common/it8152.c | 2 +- arch/arm/common/vic.c | 2 +- arch/arm/mach-at91/board-ecbat91.c | 6 +++--- arch/arm/mach-bcmring/csp/chipc/chipcHw.c | 2 +- arch/arm/mach-bcmring/csp/dmac/dmacHw.c | 2 +- arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c | 2 +- arch/arm/mach-bcmring/csp/tmr/tmrHw.c | 2 +- arch/arm/mach-bcmring/dma.c | 2 +- arch/arm/mach-bcmring/include/csp/dmacHw.h | 2 +- arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h | 2 +- arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h | 2 +- arch/arm/mach-gemini/include/mach/hardware.h | 2 +- arch/arm/mach-msm/io.c | 2 +- arch/arm/mach-omap2/cpuidle34xx.c | 2 +- arch/arm/mach-omap2/serial.c | 2 +- arch/arm/mach-pxa/mxm8x10.c | 2 +- arch/arm/mach-s3c64xx/dma.c | 2 +- arch/arm/mach-spear3xx/spear300.c | 4 ++-- arch/arm/mach-spear3xx/spear310.c | 2 +- arch/arm/mach-spear3xx/spear320.c | 2 +- arch/arm/mach-spear3xx/spear3xx.c | 6 +++--- arch/arm/mach-spear6xx/spear6xx.c | 4 ++-- arch/arm/mach-u300/Kconfig | 2 +- arch/arm/mach-u300/include/mach/coh901318.h | 4 ++-- arch/arm/plat-mxc/include/mach/irqs.h | 2 +- arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 +- arch/blackfin/mach-bf518/include/mach/defBF51x_base.h | 2 +- arch/blackfin/mach-bf527/include/mach/defBF52x_base.h | 2 +- arch/blackfin/mach-bf537/include/mach/defBF534.h | 2 +- arch/blackfin/mach-bf538/include/mach/defBF539.h | 2 +- arch/cris/arch-v32/lib/nand_init.S | 2 +- arch/cris/include/asm/etraxgpio.h | 2 +- arch/h8300/Kconfig.debug | 2 +- arch/ia64/kvm/mmio.c | 2 +- arch/mips/alchemy/common/power.c | 2 +- arch/mips/include/asm/mach-powertv/ioremap.h | 2 +- arch/mips/jz4740/board-qi_lb60.c | 4 ++-- arch/mips/jz4740/gpio.c | 2 +- arch/mips/mti-malta/malta-memory.c | 2 +- arch/mips/pci/pcie-octeon.c | 2 +- arch/mips/powertv/memory.c | 2 +- arch/mips/txx9/generic/pci.c | 2 +- arch/powerpc/include/asm/8xx_immap.h | 4 ++-- arch/powerpc/oprofile/op_model_cell.c | 2 +- arch/powerpc/platforms/83xx/suspend-asm.S | 6 +++--- arch/powerpc/platforms/ps3/device-init.c | 4 ++-- arch/powerpc/platforms/ps3/interrupt.c | 2 +- arch/sh/mm/cache-sh5.c | 2 +- arch/sparc/kernel/traps_64.c | 2 +- arch/x86/include/asm/pgalloc.h | 2 +- arch/x86/include/asm/processor.h | 2 +- arch/x86/kernel/amd_iommu.c | 4 ++-- arch/x86/kernel/early_printk_mrst.c | 2 +- arch/x86/kernel/head_32.S | 2 +- block/cfq-iosched.c | 2 +- drivers/acpi/acpica/acobject.h | 2 +- drivers/ata/libata-core.c | 4 ++-- drivers/ata/sata_vsc.c | 2 +- drivers/atm/idt77252.h | 2 +- drivers/atm/iphase.c | 4 ++-- drivers/base/power/main.c | 2 +- drivers/dma/intel_mid_dma.c | 6 +++--- drivers/edac/amd8131_edac.h | 2 +- drivers/edac/cell_edac.c | 4 ++-- drivers/edac/edac_core.h | 2 +- drivers/edac/ppc4xx_edac.c | 6 +++--- drivers/gpu/drm/radeon/atombios.h | 2 +- drivers/i2c/busses/i2c-nomadik.c | 4 ++-- drivers/infiniband/hw/cxgb3/cxio_wr.h | 2 +- drivers/infiniband/hw/qib/qib_iba7322.c | 2 +- drivers/input/touchscreen/Kconfig | 2 +- drivers/isdn/gigaset/bas-gigaset.c | 4 ++-- drivers/isdn/gigaset/ser-gigaset.c | 4 ++-- drivers/isdn/gigaset/usb-gigaset.c | 4 ++-- drivers/isdn/hardware/mISDN/ipac.h | 4 ++-- drivers/isdn/hardware/mISDN/isar.h | 2 +- drivers/isdn/hisax/isar.c | 4 ++-- drivers/media/video/cx25840/cx25840-ir.c | 2 +- drivers/media/video/davinci/vpif.h | 2 +- drivers/media/video/davinci/vpss.c | 2 +- drivers/media/video/omap/omap_vout.c | 2 +- drivers/media/video/saa7164/saa7164-core.c | 4 ++-- drivers/media/video/sn9c102/sn9c102_sensor.h | 2 +- drivers/media/video/zoran/zoran.h | 2 +- drivers/message/fusion/lsi/mpi_log_sas.h | 2 +- drivers/message/fusion/mptbase.c | 2 +- drivers/message/fusion/mptsas.c | 2 +- drivers/message/i2o/i2o_block.c | 2 +- drivers/misc/arm-charlcd.c | 2 +- drivers/mmc/card/block.c | 2 +- drivers/mmc/host/Kconfig | 2 +- drivers/mmc/host/au1xmmc.c | 2 +- drivers/mmc/host/sdricoh_cs.c | 4 ++-- drivers/mtd/nand/nand_base.c | 2 +- drivers/net/bnx2x/bnx2x_main.c | 2 +- drivers/net/bnx2x/bnx2x_reg.h | 2 +- drivers/net/bonding/bond_3ad.c | 6 +++--- drivers/net/chelsio/subr.c | 2 +- drivers/net/cxgb3/mc5.c | 2 +- drivers/net/cxgb3/t3_hw.c | 2 +- drivers/net/e1000/e1000_hw.h | 2 +- drivers/net/e1000/e1000_main.c | 2 +- drivers/net/e1000e/82571.c | 2 +- drivers/net/e1000e/ich8lan.c | 2 +- drivers/net/e1000e/phy.c | 2 +- drivers/net/eepro.c | 2 +- drivers/net/irda/donauboe.h | 2 +- drivers/net/ixgbe/ixgbe_82599.c | 4 ++-- drivers/net/ll_temac_main.c | 2 +- drivers/net/sis900.c | 2 +- drivers/net/tehuti.c | 6 +++--- drivers/net/tun.c | 2 +- drivers/net/vxge/vxge-traffic.h | 2 +- drivers/net/wan/dscc4.c | 2 +- drivers/net/wimax/i2400m/driver.c | 2 +- drivers/net/wimax/i2400m/i2400m.h | 2 +- drivers/net/wireless/ath/ath5k/reg.h | 6 +++--- drivers/net/wireless/b43/phy_g.c | 2 +- drivers/net/wireless/b43legacy/phy.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/prism54/islpci_dev.c | 6 +++--- drivers/net/wireless/prism54/islpci_eth.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/wl3501_cs.c | 2 +- drivers/pcmcia/m32r_cfc.h | 2 +- drivers/pcmcia/m32r_pcc.h | 2 +- drivers/pcmcia/m8xx_pcmcia.c | 2 +- drivers/platform/x86/thinkpad_acpi.c | 2 +- drivers/power/s3c_adc_battery.c | 4 ++-- drivers/s390/net/lcs.c | 2 +- drivers/s390/scsi/zfcp_cfdc.c | 2 +- drivers/scsi/a100u2w.c | 2 +- drivers/scsi/aacraid/commsup.c | 2 +- drivers/scsi/aic7xxx_old/aic7xxx.seq | 2 +- drivers/scsi/aic94xx/aic94xx_reg_def.h | 4 ++-- drivers/scsi/aic94xx/aic94xx_seq.c | 6 +++--- drivers/scsi/bfa/bfa_fcpim.c | 2 +- drivers/scsi/bfa/bfa_fcs_lport.c | 2 +- drivers/scsi/dc395x.c | 8 ++++---- drivers/scsi/libfc/fc_fcp.c | 2 +- drivers/scsi/lpfc/lpfc_attr.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 2 +- drivers/scsi/megaraid.h | 2 +- drivers/scsi/pm8001/pm8001_init.c | 2 +- drivers/scsi/scsi_netlink.c | 2 +- drivers/scsi/sym53c8xx_2/sym_glue.c | 2 +- drivers/spi/atmel_spi.c | 4 ++-- drivers/spi/spidev.c | 2 +- drivers/staging/stradis/stradis.c | 2 +- drivers/usb/gadget/imx_udc.c | 2 +- drivers/usb/host/imx21-hcd.c | 2 +- drivers/usb/host/oxu210hp-hcd.c | 2 +- drivers/usb/misc/adutux.c | 2 +- drivers/usb/misc/iowarrior.c | 2 +- drivers/usb/misc/ldusb.c | 2 +- drivers/usb/musb/musb_gadget.c | 4 ++-- drivers/usb/wusbcore/wa-rpipe.c | 2 +- drivers/video/sstfb.c | 2 +- fs/ext4/ext4.h | 2 +- fs/ext4/extents.c | 4 ++-- fs/ext4/inode.c | 4 ++-- fs/ocfs2/inode.c | 2 +- fs/ocfs2/suballoc.c | 2 +- fs/xfs/linux-2.6/xfs_super.c | 2 +- include/acpi/actbl1.h | 2 +- include/linux/cgroup.h | 2 +- include/linux/firewire-cdev.h | 2 +- include/linux/mfd/core.h | 2 +- include/net/sctp/user.h | 4 ++-- include/scsi/fc/fc_fcp.h | 4 ++-- kernel/debug/kdb/kdb_main.c | 2 +- kernel/kexec.c | 2 +- kernel/power/swap.c | 2 +- kernel/sched.c | 2 +- kernel/sysctl_binary.c | 2 +- kernel/time/clocksource.c | 2 +- kernel/trace/trace_entries.h | 2 +- lib/nlattr.c | 2 +- lib/swiotlb.c | 2 +- mm/percpu.c | 2 +- mm/sparse-vmemmap.c | 2 +- net/core/dev.c | 2 +- net/decnet/dn_dev.c | 2 +- net/ipv4/tcp_output.c | 2 +- scripts/kconfig/confdata.c | 2 +- scripts/mod/modpost.c | 2 +- security/apparmor/include/match.h | 2 +- sound/core/init.c | 2 +- sound/core/pcm_native.c | 2 +- sound/isa/opl3sa2.c | 2 +- sound/pci/ca0106/ca0106.h | 2 +- sound/pci/emu10k1/emu10k1x.c | 2 +- sound/pci/emu10k1/p16v.h | 2 +- sound/pci/es1968.c | 2 +- sound/pci/rme9652/hdspm.c | 6 +++--- sound/soc/codecs/max98088.c | 2 +- sound/soc/s3c24xx/smdk_spdif.c | 6 +++--- 207 files changed, 261 insertions(+), 261 deletions(-) (limited to 'drivers') diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index 020ac80d4682..620eb3f6a90a 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -250,7 +250,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd) Device ready function If the hardware interface has the ready busy pin of the NAND chip connected to a - GPIO or other accesible I/O pin, this function is used to read back the state of the + GPIO or other accessible I/O pin, this function is used to read back the state of the pin. The function has no arguments and should return 0, if the device is busy (R/B pin is low) and 1, if the device is ready (R/B pin is high). If the hardware interface does not give access to the ready busy pin, then diff --git a/Documentation/cgroups/cgroup_event_listener.c b/Documentation/cgroups/cgroup_event_listener.c index 8c2bfc4a6358..3e082f96dc12 100644 --- a/Documentation/cgroups/cgroup_event_listener.c +++ b/Documentation/cgroups/cgroup_event_listener.c @@ -91,7 +91,7 @@ int main(int argc, char **argv) if (ret == -1) { perror("cgroup.event_control " - "is not accessable any more"); + "is not accessible any more"); break; } diff --git a/Documentation/cgroups/memcg_test.txt b/Documentation/cgroups/memcg_test.txt index b7eececfb195..fc8fa97a09ac 100644 --- a/Documentation/cgroups/memcg_test.txt +++ b/Documentation/cgroups/memcg_test.txt @@ -398,7 +398,7 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y. written to move_charge_at_immigrate. 9.10 Memory thresholds - Memory controler implements memory thresholds using cgroups notification + Memory controller implements memory thresholds using cgroups notification API. You can use Documentation/cgroups/cgroup_event_listener.c to test it. diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 741fe66d6eca..0cfb00fd86ff 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -598,7 +598,7 @@ a 5-byte jump instruction. So there are several limitations. a) The instructions in DCR must be relocatable. b) The instructions in DCR must not include a call instruction. c) JTPR must not be targeted by any jump or call instruction. -d) DCR must not straddle the border betweeen functions. +d) DCR must not straddle the border between functions. Anyway, these limitations are checked by the in-kernel instruction decoder, so you don't need to worry about that. diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index b336266bea5e..50713e37c695 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt @@ -874,7 +874,7 @@ Possible values are: - KVM_MP_STATE_HALTED: the vcpu has executed a HLT instruction and is waiting for an interrupt - KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector - accesible via KVM_GET_VCPU_EVENTS) + accessible via KVM_GET_VCPU_EVENTS) This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel irqchip, the multiprocessing state must be maintained by userspace. diff --git a/Documentation/networking/caif/spi_porting.txt b/Documentation/networking/caif/spi_porting.txt index 61d7c9247453..0cb8cb9098f4 100644 --- a/Documentation/networking/caif/spi_porting.txt +++ b/Documentation/networking/caif/spi_porting.txt @@ -32,7 +32,7 @@ the physical hardware, both with regard to SPI and to GPIOs. This function is called by the CAIF SPI interface to give you a chance to set up your hardware to be ready to receive a stream of data from the master. The xfer structure contains - both physical and logical adresses, as well as the total length + both physical and logical addresses, as well as the total length of the transfer in both directions.The dev parameter can be used to map to different CAIF SPI slave devices. diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 302db5da49b3..1c6660d2d7f5 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1098,7 +1098,7 @@ supported currently at the toplevel. * an arbitrary array of bytes */ - childnode@addresss { /* define a child node named "childnode" + childnode@address { /* define a child node named "childnode" * whose unit name is "childnode at * address" */ diff --git a/Documentation/scsi/ChangeLog.lpfc b/Documentation/scsi/ChangeLog.lpfc index 337c924cc81f..5e83769c6aa9 100644 --- a/Documentation/scsi/ChangeLog.lpfc +++ b/Documentation/scsi/ChangeLog.lpfc @@ -573,7 +573,7 @@ Changes from 20041018 to 20041123 * Backround nodev_timeout processing to DPC This enables us to unblock (stop dev_loss_tmo) when appopriate. * Fix array discovery with multiple luns. The max_luns was 0 at - the time the host structure was intialized. lpfc_cfg_params + the time the host structure was initialized. lpfc_cfg_params then set the max_luns to the correct value afterwards. * Remove unused define LPFC_MAX_LUN and set the default value of lpfc_max_lun parameter to 512. diff --git a/Documentation/timers/timer_stats.txt b/Documentation/timers/timer_stats.txt index 9bd00fc2e823..8abd40b22b7f 100644 --- a/Documentation/timers/timer_stats.txt +++ b/Documentation/timers/timer_stats.txt @@ -19,7 +19,7 @@ Linux system over a sample period: - the pid of the task(process) which initialized the timer - the name of the process which initialized the timer -- the function where the timer was intialized +- the function where the timer was initialized - the callback function which is associated to the timer - the number of events (callbacks) diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index 1bec96e85196..60dc077ea7cc 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -236,7 +236,7 @@ static struct resource it8152_mem = { /* * The following functions are needed for DMA bouncing. - * ITE8152 chip can addrees up to 64MByte, so all the devices + * ITE8152 chip can address up to 64MByte, so all the devices * connected to ITE8152 (PCI and USB) should have limited DMA window */ diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index ba65f6eedca6..cb660bc54d7a 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -70,7 +70,7 @@ static inline struct vic_device *to_vic(struct sys_device *sys) * vic_init2 - common initialisation code * @base: Base of the VIC. * - * Common initialisation code for registeration + * Common initialisation code for registration * and resume. */ static void vic_init2(void __iomem *base) diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c index 7b58c948a957..de2fd04e7c8a 100644 --- a/arch/arm/mach-at91/board-ecbat91.c +++ b/arch/arm/mach-at91/board-ecbat91.c @@ -128,17 +128,17 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = { .platform_data = &my_flash0_platform, #endif }, - { /* User accessable spi - cs1 (250KHz) */ + { /* User accessible spi - cs1 (250KHz) */ .modalias = "spi-cs1", .chip_select = 1, .max_speed_hz = 250 * 1000, }, - { /* User accessable spi - cs2 (1MHz) */ + { /* User accessible spi - cs2 (1MHz) */ .modalias = "spi-cs2", .chip_select = 2, .max_speed_hz = 1 * 1000 * 1000, }, - { /* User accessable spi - cs3 (10MHz) */ + { /* User accessible spi - cs3 (10MHz) */ .modalias = "spi-cs3", .chip_select = 3, .max_speed_hz = 10 * 1000 * 1000, diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c index b3a61d860c65..96273ff34956 100644 --- a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c +++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c @@ -757,7 +757,7 @@ static int chipcHw_divide(int num, int denom) t = t << 1; } - /* Intialize the result */ + /* Initialize the result */ r = 0; do { diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c index 7b9bac2d79a5..6b9be2e98e51 100644 --- a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c +++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c @@ -893,7 +893,7 @@ int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration */ /****************************************************************************/ uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */ - dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controler attribute of type dmacHw_CONTROLLER_ATTRIB_e */ + dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controller attribute of type dmacHw_CONTROLLER_ATTRIB_e */ ) { dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle); diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c index ff7b436d0935..77f84b40dda9 100644 --- a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c +++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c @@ -316,7 +316,7 @@ static void DisplayDescRing(void *pDescriptor, /* [ IN ] Descriptor buffer */ /** * @brief Check if DMA channel is the flow controller * -* @return 1 : If DMA is a flow controler +* @return 1 : If DMA is a flow controller * 0 : Peripheral is the flow controller * * @note diff --git a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c index 5c1c9a0e5ed2..16225e43f3c3 100644 --- a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c +++ b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c @@ -558,7 +558,7 @@ static int tmrHw_divide(int num, int denom) t = t << 1; } - /* Intialize the result */ + /* Initialize the result */ r = 0; do { diff --git a/arch/arm/mach-bcmring/dma.c b/arch/arm/mach-bcmring/dma.c index 77eb35c89cd0..8d1baf3f4683 100644 --- a/arch/arm/mach-bcmring/dma.c +++ b/arch/arm/mach-bcmring/dma.c @@ -671,7 +671,7 @@ static int ConfigChannel(DMA_Handle_t handle) /****************************************************************************/ /** -* Intializes all of the data structures associated with the DMA. +* Initializes all of the data structures associated with the DMA. * @return * >= 0 - Initialization was successfull. * diff --git a/arch/arm/mach-bcmring/include/csp/dmacHw.h b/arch/arm/mach-bcmring/include/csp/dmacHw.h index 5d510130a25f..6c8da2b9fc1f 100644 --- a/arch/arm/mach-bcmring/include/csp/dmacHw.h +++ b/arch/arm/mach-bcmring/include/csp/dmacHw.h @@ -590,7 +590,7 @@ void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */ /****************************************************************************/ uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */ - dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controler attribute of type dmacHw_CONTROLLER_ATTRIB_e */ + dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controller attribute of type dmacHw_CONTROLLER_ATTRIB_e */ ); #endif /* _DMACHW_H */ diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h index cbf334d1c761..d67e2f8c22de 100644 --- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h +++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h @@ -28,7 +28,7 @@ /* Data type for DMA Link List Item */ typedef struct { - uint32_t sar; /* Source Adress Register. + uint32_t sar; /* Source Address Register. Address must be aligned to CTLx.SRC_TR_WIDTH. */ uint32_t dar; /* Destination Address Register. Address must be aligned to CTLx.DST_TR_WIDTH. */ diff --git a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h index 891cea87e333..f1ecf96f2da5 100644 --- a/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h +++ b/arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h @@ -35,7 +35,7 @@ typedef struct { /* Data type representing DMA channel registers */ typedef struct { - dmacHw_REG64_t ChannelSar; /* Source Adress Register. 64 bits (upper 32 bits are reserved) + dmacHw_REG64_t ChannelSar; /* Source Address Register. 64 bits (upper 32 bits are reserved) Address must be aligned to CTLx.SRC_TR_WIDTH. */ dmacHw_REG64_t ChannelDar; /* Destination Address Register.64 bits (upper 32 bits are reserved) diff --git a/arch/arm/mach-gemini/include/mach/hardware.h b/arch/arm/mach-gemini/include/mach/hardware.h index 213a4fcfeb1c..8c950e1d06be 100644 --- a/arch/arm/mach-gemini/include/mach/hardware.h +++ b/arch/arm/mach-gemini/include/mach/hardware.h @@ -33,7 +33,7 @@ #define GEMINI_LPC_HOST_BASE 0x47000000 #define GEMINI_LPC_IO_BASE 0x47800000 #define GEMINI_INTERRUPT_BASE 0x48000000 -/* TODO: Different interrupt controlers when SMP +/* TODO: Different interrupt controllers when SMP * #define GEMINI_INTERRUPT0_BASE 0x48000000 * #define GEMINI_INTERRUPT1_BASE 0x49000000 */ diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index d36b61074146..7f8d15d56834 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -153,7 +153,7 @@ __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) { if (mtype == MT_DEVICE) { /* The peripherals in the 88000000 - D0000000 range - * are only accessable by type MT_DEVICE_NONSHARED. + * are only accessible by type MT_DEVICE_NONSHARED. * Adjust mtype as necessary to make this "just work." */ if ((phys_addr >= 0x88000000) && (phys_addr < 0xD0000000)) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 0d50b45d041c..1e6fe6d11aee 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -252,7 +252,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, * FIXME: we currently manage device-specific idle states * for PER and CORE in combination with CPU-specific * idle states. This is wrong, and device-specific - * idle managment needs to be separated out into + * idle management needs to be separated out into * its own code. */ diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index becf0e38ef7e..db79ac68ed97 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -843,7 +843,7 @@ void __init omap_serial_init_port(int port) } /** - * omap_serial_init() - intialize all supported serial ports + * omap_serial_init() - initialize all supported serial ports * * Initializes all available UARTs as serial ports. Platforms * can call this function when they want to have default behaviour diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c index 462167ac05f9..cdf7f41e2bb3 100644 --- a/arch/arm/mach-pxa/mxm8x10.c +++ b/arch/arm/mach-pxa/mxm8x10.c @@ -337,7 +337,7 @@ void __init mxm_8x10_mmc_init(void) } #endif -/* USB Open Host Controler Interface */ +/* USB Open Host Controller Interface */ static struct pxaohci_platform_data mxm_8x10_ohci_platform_data = { .port_mode = PMM_NPS_MODE, .flags = ENABLE_PORT_ALL diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c index e7d03ab41d80..372ea6855454 100644 --- a/arch/arm/mach-s3c64xx/dma.c +++ b/arch/arm/mach-s3c64xx/dma.c @@ -740,7 +740,7 @@ static int __init s3c64xx_dma_init(void) /* Set all DMA configuration to be DMA, not SDMA */ writel(0xffffff, S3C_SYSREG(0x110)); - /* Register standard DMA controlers */ + /* Register standard DMA controllers */ s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000); s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000); diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index 3560f8c1e723..5aa2d54ebfaa 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -371,7 +371,7 @@ struct pmx_driver pmx_driver = { }; /* Add spear300 specific devices here */ -/* arm gpio1 device registeration */ +/* arm gpio1 device registration */ static struct pl061_platform_data gpio1_plat_data = { .gpio_base = 8, .irq_base = SPEAR_GPIO1_INT_BASE, @@ -451,7 +451,7 @@ void __init spear300_init(void) /* call spear3xx family common init function */ spear3xx_init(); - /* shared irq registeration */ + /* shared irq registration */ shirq_ras1.regs.base = ioremap(SPEAR300_TELECOM_BASE, SPEAR300_TELECOM_REG_SIZE); if (shirq_ras1.regs.base) { diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index 96a1ab824bac..53b41b52d7ee 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -266,7 +266,7 @@ void __init spear310_init(void) /* call spear3xx family common init function */ spear3xx_init(); - /* shared irq registeration */ + /* shared irq registration */ base = ioremap(SPEAR310_SOC_CONFIG_BASE, SPEAR310_SOC_CONFIG_SIZE); if (base) { /* shirq 1 */ diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index 6a1219549369..88b465284c36 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -519,7 +519,7 @@ void __init spear320_init(void) /* call spear3xx family common init function */ spear3xx_init(); - /* shared irq registeration */ + /* shared irq registration */ base = ioremap(SPEAR320_SOC_CONFIG_BASE, SPEAR320_SOC_CONFIG_SIZE); if (base) { /* shirq 1 */ diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index e87313aeae20..52f553c8c46d 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -22,7 +22,7 @@ #include /* Add spear3xx machines common devices here */ -/* gpio device registeration */ +/* gpio device registration */ static struct pl061_platform_data gpio_plat_data = { .gpio_base = 0, .irq_base = SPEAR_GPIO_INT_BASE, @@ -41,7 +41,7 @@ struct amba_device gpio_device = { .irq = {IRQ_BASIC_GPIO, NO_IRQ}, }; -/* uart device registeration */ +/* uart device registration */ struct amba_device uart_device = { .dev = { .init_name = "uart", @@ -543,6 +543,6 @@ void spear_pmx_init(struct pmx_driver *pmx_driver, uint base, uint size) pmx_fail: if (ret) - printk(KERN_ERR "padmux: registeration failed. err no: %d\n", + printk(KERN_ERR "padmux: registration failed. err no: %d\n", ret); } diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c index baf6bcc3169c..f2fe14e8471d 100644 --- a/arch/arm/mach-spear6xx/spear6xx.c +++ b/arch/arm/mach-spear6xx/spear6xx.c @@ -23,7 +23,7 @@ #include /* Add spear6xx machines common devices here */ -/* uart device registeration */ +/* uart device registration */ struct amba_device uart_device[] = { { .dev = { @@ -50,7 +50,7 @@ struct amba_device uart_device[] = { } }; -/* gpio device registeration */ +/* gpio device registration */ static struct pl061_platform_data gpio_plat_data[] = { { .gpio_base = 0, diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig index 801b21e7f677..32a7b0f7e9f7 100644 --- a/arch/arm/mach-u300/Kconfig +++ b/arch/arm/mach-u300/Kconfig @@ -64,7 +64,7 @@ config MACH_U300_DUAL_RAM bool "Dual RAM" help Select this if you want support for Dual RAM phones. - This is two RAM memorys on different EMIFs. + This is two RAM memories on different EMIFs. endchoice config U300_DEBUG diff --git a/arch/arm/mach-u300/include/mach/coh901318.h b/arch/arm/mach-u300/include/mach/coh901318.h index 193da2df732c..6193aaa47794 100644 --- a/arch/arm/mach-u300/include/mach/coh901318.h +++ b/arch/arm/mach-u300/include/mach/coh901318.h @@ -24,7 +24,7 @@ * @src_addr: transfer source address * @dst_addr: transfer destination address * @link_addr: physical address to next lli - * @virt_link_addr: virtual addres of next lli (only used by pool_free) + * @virt_link_addr: virtual address of next lli (only used by pool_free) * @phy_this: physical address of current lli (only used by pool_free) */ struct coh901318_lli { @@ -90,7 +90,7 @@ struct powersave { * struct coh901318_platform - platform arch structure * @chans_slave: specifying dma slave channels * @chans_memcpy: specifying dma memcpy channels - * @access_memory_state: requesting DMA memeory access (on / off) + * @access_memory_state: requesting DMA memory access (on / off) * @chan_conf: dma channel configurations * @max_channels: max number of dma chanenls */ diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h index 86781f7b0c0c..664c453babbe 100644 --- a/arch/arm/plat-mxc/include/mach/irqs.h +++ b/arch/arm/plat-mxc/include/mach/irqs.h @@ -66,7 +66,7 @@ extern int imx_irq_set_priority(unsigned char irq, unsigned char prio); /* all normal IRQs can be FIQs */ #define FIQ_START 0 -/* switch betwean IRQ and FIQ */ +/* switch between IRQ and FIQ */ extern int mxc_set_irq_fiq(unsigned int irq, unsigned int type); #endif /* __ASM_ARCH_MXC_IRQS_H__ */ diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 7eaa8edf3b14..79ac24ceb54d 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -339,7 +339,7 @@ struct omap_hwmod_omap2_prcm { /** * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data * @clkctrl_reg: PRCM address of the clock control register - * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM + * @rstctrl_reg: address of the XXX_RSTCTRL register located in the PRM * @submodule_wkdep_bit: bit shift of the WKDEP range */ struct omap_hwmod_omap4_prcm { diff --git a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h index 5f84913dcd91..750f4d803845 100644 --- a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h +++ b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h @@ -1197,7 +1197,7 @@ #define SADD_LEN 0x0002 /* Slave Address Length */ #define STDVAL 0x0004 /* Slave Transmit Data Valid */ #define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */ -#define GEN 0x0010 /* General Call Adrress Matching Enabled */ +#define GEN 0x0010 /* General Call Address Matching Enabled */ /* TWI_SLAVE_STAT Masks */ #define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */ diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h index 09475034c6a1..e3ab78ef9001 100644 --- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h +++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h @@ -1206,7 +1206,7 @@ #define SADD_LEN 0x0002 /* Slave Address Length */ #define STDVAL 0x0004 /* Slave Transmit Data Valid */ #define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */ -#define GEN 0x0010 /* General Call Adrress Matching Enabled */ +#define GEN 0x0010 /* General Call Address Matching Enabled */ /* TWI_SLAVE_STAT Masks */ #define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */ diff --git a/arch/blackfin/mach-bf537/include/mach/defBF534.h b/arch/blackfin/mach-bf537/include/mach/defBF534.h index 0323e6bacdae..042064b2b44a 100644 --- a/arch/blackfin/mach-bf537/include/mach/defBF534.h +++ b/arch/blackfin/mach-bf537/include/mach/defBF534.h @@ -1523,7 +1523,7 @@ #define SADD_LEN 0x0002 /* Slave Address Length */ #define STDVAL 0x0004 /* Slave Transmit Data Valid */ #define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */ -#define GEN 0x0010 /* General Call Adrress Matching Enabled */ +#define GEN 0x0010 /* General Call Address Matching Enabled */ /* TWI_SLAVE_STAT Masks */ #define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */ diff --git a/arch/blackfin/mach-bf538/include/mach/defBF539.h b/arch/blackfin/mach-bf538/include/mach/defBF539.h index 7a8ac5f44204..d85d128c97ca 100644 --- a/arch/blackfin/mach-bf538/include/mach/defBF539.h +++ b/arch/blackfin/mach-bf538/include/mach/defBF539.h @@ -2185,7 +2185,7 @@ #define SADD_LEN 0x0002 /* Slave Address Length */ #define STDVAL 0x0004 /* Slave Transmit Data Valid */ #define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */ -#define GEN 0x0010 /* General Call Adrress Matching Enabled */ +#define GEN 0x0010 /* General Call Address Matching Enabled */ /* TWIx_SLAVE_STAT Masks */ #define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */ diff --git a/arch/cris/arch-v32/lib/nand_init.S b/arch/cris/arch-v32/lib/nand_init.S index e705f5cce969..d671fed451c9 100644 --- a/arch/cris/arch-v32/lib/nand_init.S +++ b/arch/cris/arch-v32/lib/nand_init.S @@ -139,7 +139,7 @@ copy_nand_to_ram: lsrq 8, $r4 move.b $r4, [$r1] ; Row address lsrq 8, $r4 - move.b $r4, [$r1] ; Row adddress + move.b $r4, [$r1] ; Row address moveq 20, $r4 2: bne 2b subq 1, $r4 diff --git a/arch/cris/include/asm/etraxgpio.h b/arch/cris/include/asm/etraxgpio.h index d474818a537e..461c089db765 100644 --- a/arch/cris/include/asm/etraxgpio.h +++ b/arch/cris/include/asm/etraxgpio.h @@ -1,5 +1,5 @@ /* - * The following devices are accessable using this driver using + * The following devices are accessible using this driver using * GPIO_MAJOR (120) and a couple of minor numbers. * * For ETRAX 100LX (CONFIG_ETRAX_ARCH_V10): diff --git a/arch/h8300/Kconfig.debug b/arch/h8300/Kconfig.debug index ee671c3f2c74..e8d1b236ad8c 100644 --- a/arch/h8300/Kconfig.debug +++ b/arch/h8300/Kconfig.debug @@ -48,7 +48,7 @@ config DEFAULT_CMDLINE builtin kernel commandline enabled. config KERNEL_COMMAND - string "Buildin commmand string" + string "Buildin command string" depends on DEFAULT_CMDLINE help builtin kernel commandline strings. diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c index fb8f9f59a1ed..f1e17d3d6cd9 100644 --- a/arch/ia64/kvm/mmio.c +++ b/arch/ia64/kvm/mmio.c @@ -130,7 +130,7 @@ static void mmio_access(struct kvm_vcpu *vcpu, u64 src_pa, u64 *dest, local_irq_save(psr); - /*Intercept the acces for PIB range*/ + /*Intercept the access for PIB range*/ if (iot == GPFN_PIB) { if (!dir) lsapic_write(vcpu, src_pa, s, *dest); diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index e5916a516e58..647e518c90bc 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c @@ -130,7 +130,7 @@ static void restore_core_regs(void) au_writel(sleep_usb[1], USBD_ENABLE); au_sync(); #else - /* enable accces to OTG memory */ + /* enable access to OTG memory */ au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); au_sync(); diff --git a/arch/mips/include/asm/mach-powertv/ioremap.h b/arch/mips/include/asm/mach-powertv/ioremap.h index 076f2eeaa575..c86ef094ec37 100644 --- a/arch/mips/include/asm/mach-powertv/ioremap.h +++ b/arch/mips/include/asm/mach-powertv/ioremap.h @@ -88,7 +88,7 @@ static inline dma_addr_t _dma_to_phys_offset_raw(dma_addr_t dma) } /* These are not portable and should not be used in drivers. Drivers should - * be using ioremap() and friends to map physical addreses to virtual + * be using ioremap() and friends to map physical addresses to virtual * addresses and dma_map*() and friends to map virtual addresses into DMA * addresses and back. */ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 5742bb4d78f4..de4433c5a771 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -65,7 +65,7 @@ static struct nand_ecclayout qi_lb60_ecclayout_1gb = { /* Early prototypes of the QI LB60 had only 1GB of NAND. * In order to support these devices aswell the partition and ecc layout is - * initalized depending on the NAND size */ + * initialized depending on the NAND size */ static struct mtd_partition qi_lb60_partitions_1gb[] = { { .name = "NAND BOOT partition", @@ -464,7 +464,7 @@ static int __init qi_lb60_board_setup(void) board_gpio_setup(); if (qi_lb60_init_platform_devices()) - panic("Failed to initalize platform devices\n"); + panic("Failed to initialize platform devices\n"); return 0; } diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c index 38f60f35156c..88e6aeda5bf1 100644 --- a/arch/mips/jz4740/gpio.c +++ b/arch/mips/jz4740/gpio.c @@ -546,7 +546,7 @@ static int __init jz4740_gpio_init(void) for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i) jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i); - printk(KERN_INFO "JZ4740 GPIO initalized\n"); + printk(KERN_INFO "JZ4740 GPIO initialized\n"); return 0; } diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c index b27419c84919..a96d281f9221 100644 --- a/arch/mips/mti-malta/malta-memory.c +++ b/arch/mips/mti-malta/malta-memory.c @@ -43,7 +43,7 @@ static struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; static char *mtypes[3] = { "Dont use memory", "YAMON PROM memory", - "Free memmory", + "Free memory", }; #endif diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 385f035b24e4..0583c463e5f1 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -900,7 +900,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Writes. */ mem_access_subid.s.row = 0; - /* PCIe Adddress Bits <63:34>. */ + /* PCIe Address Bits <63:34>. */ mem_access_subid.s.ba = 0; /* diff --git a/arch/mips/powertv/memory.c b/arch/mips/powertv/memory.c index 73880ad29bc2..fb3d29660c42 100644 --- a/arch/mips/powertv/memory.c +++ b/arch/mips/powertv/memory.c @@ -57,7 +57,7 @@ unsigned long ptv_memsize; /* - * struct low_mem_reserved - Items in low memmory that are reserved + * struct low_mem_reserved - Items in low memory that are reserved * @start: Physical address of item * @size: Size, in bytes, of this item * @is_aliased: True if this is RAM aliased from another location. If false, diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 9a0be810cafa..96e69a00ffc8 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c @@ -107,7 +107,7 @@ int txx9_pci_mem_high __initdata; /* * allocate pci_controller and resources. - * mem_base, io_base: physical addresss. 0 for auto assignment. + * mem_base, io_base: physical address. 0 for auto assignment. * mem_size and io_size means max size on auto assignment. * pcic must be &txx9_primary_pcic or NULL. */ diff --git a/arch/powerpc/include/asm/8xx_immap.h b/arch/powerpc/include/asm/8xx_immap.h index 4b0e15206006..6b6dc20b0beb 100644 --- a/arch/powerpc/include/asm/8xx_immap.h +++ b/arch/powerpc/include/asm/8xx_immap.h @@ -93,7 +93,7 @@ typedef struct mem_ctlr { } memctl8xx_t; /*----------------------------------------------------------------------- - * BR - Memory Controler: Base Register 16-9 + * BR - Memory Controller: Base Register 16-9 */ #define BR_BA_MSK 0xffff8000 /* Base Address Mask */ #define BR_AT_MSK 0x00007000 /* Address Type Mask */ @@ -110,7 +110,7 @@ typedef struct mem_ctlr { #define BR_V 0x00000001 /* Bank Valid */ /*----------------------------------------------------------------------- - * OR - Memory Controler: Option Register 16-11 + * OR - Memory Controller: Option Register 16-11 */ #define OR_AM_MSK 0xffff8000 /* Address Mask Mask */ #define OR_ATM_MSK 0x00007000 /* Address Type Mask Mask */ diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index 7fd90d02d8c6..c4d2b7167568 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -1469,7 +1469,7 @@ static int cell_global_start(struct op_counter_config *ctr) * The pm_interval register is setup to write the SPU PC value into the * trace buffer at the maximum rate possible. The trace buffer is configured * to store the PCs, wrapping when it is full. The performance counter is - * intialized to the max hardware count minus the number of events, N, between + * initialized to the max hardware count minus the number of events, N, between * samples. Once the N events have occured, a HW counter overflow occurs * causing the generation of a HW counter interrupt which also stops the * writing of the SPU PC values to the trace buffer. Hence the last PC diff --git a/arch/powerpc/platforms/83xx/suspend-asm.S b/arch/powerpc/platforms/83xx/suspend-asm.S index 1930543c98d3..3d1ecd211776 100644 --- a/arch/powerpc/platforms/83xx/suspend-asm.S +++ b/arch/powerpc/platforms/83xx/suspend-asm.S @@ -231,7 +231,7 @@ _GLOBAL(mpc83xx_enter_deep_sleep) ori r4, r4, 0x002a mtspr SPRN_DBAT0L, r4 lis r8, TMP_VIRT_IMMR@h - ori r4, r8, 0x001e /* 1 MByte accessable from Kernel Space only */ + ori r4, r8, 0x001e /* 1 MByte accessible from Kernel Space only */ mtspr SPRN_DBAT0U, r4 isync @@ -241,7 +241,7 @@ _GLOBAL(mpc83xx_enter_deep_sleep) ori r4, r4, 0x002a mtspr SPRN_DBAT1L, r4 lis r9, (TMP_VIRT_IMMR + 0x01000000)@h - ori r4, r9, 0x001e /* 1 MByte accessable from Kernel Space only */ + ori r4, r9, 0x001e /* 1 MByte accessible from Kernel Space only */ mtspr SPRN_DBAT1U, r4 isync @@ -253,7 +253,7 @@ _GLOBAL(mpc83xx_enter_deep_sleep) li r4, 0x0002 mtspr SPRN_DBAT2L, r4 lis r4, KERNELBASE@h - ori r4, r4, 0x001e /* 1 MByte accessable from Kernel Space only */ + ori r4, r4, 0x001e /* 1 MByte accessible from Kernel Space only */ mtspr SPRN_DBAT2U, r4 isync diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index b341018326df..6c4b5837fc8a 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -566,10 +566,10 @@ static int ps3_setup_dynamic_device(const struct ps3_repository_device *repo) case PS3_DEV_TYPE_STOR_DISK: result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK); - /* Some devices are not accessable from the Other OS lpar. */ + /* Some devices are not accessible from the Other OS lpar. */ if (result == -ENODEV) { result = 0; - pr_debug("%s:%u: not accessable\n", __func__, + pr_debug("%s:%u: not accessible\n", __func__, __LINE__); } diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 59d9712d7364..92290ff4761a 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -44,7 +44,7 @@ * @lock: * @ipi_debug_brk_mask: * - * The HV mantains per SMT thread mappings of HV outlet to HV plug on + * The HV maintains per SMT thread mappings of HV outlet to HV plug on * behalf of the guest. These mappings are implemented as 256 bit guest * supplied bitmaps indexed by plug number. The addresses of the bitmaps * are registered with the HV through lv1_configure_irq_state_bitmap(). diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index eb4cc4ec7952..d1bffbcd9d52 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -568,7 +568,7 @@ static void sh5_flush_dcache_page(void *page) } /* - * Flush the range [start,end] of kernel virtual adddress space from + * Flush the range [start,end] of kernel virtual address space from * the I-cache. The corresponding range must be purged from the * D-cache also because the SH-5 doesn't have cache snooping between * the caches. The addresses will be visible through the superpage diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 42ad2ba85010..1e9770936c3b 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -622,7 +622,7 @@ static const char CHAFSR_PERR_msg[] = static const char CHAFSR_IERR_msg[] = "Internal processor error"; static const char CHAFSR_ISAP_msg[] = - "System request parity error on incoming addresss"; + "System request parity error on incoming address"; static const char CHAFSR_UCU_msg[] = "Uncorrectable E-cache ECC error for ifetch/data"; static const char CHAFSR_UCC_msg[] = diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h index 271de94c3810..b4389a468fb6 100644 --- a/arch/x86/include/asm/pgalloc.h +++ b/arch/x86/include/asm/pgalloc.h @@ -92,7 +92,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) extern void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd); static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, - unsigned long adddress) + unsigned long address) { ___pmd_free_tlb(tlb, pmd); } diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index cae9c3cb95cf..c3e6d9a3de65 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -902,7 +902,7 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); /* * The below -8 is to reserve 8 bytes on top of the ring0 stack. * This is necessary to guarantee that the entire "struct pt_regs" - * is accessable even if the CPU haven't stored the SS/ESP registers + * is accessible even if the CPU haven't stored the SS/ESP registers * on the stack (interrupt gate does not save these registers * when switching to the same priv ring). * Therefore beware: accessing the ss/esp fields of the diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index d2fdb0826df2..57ca77787220 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1086,7 +1086,7 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom, dma_dom->aperture_size += APERTURE_RANGE_SIZE; - /* Intialize the exclusion range if necessary */ + /* Initialize the exclusion range if necessary */ for_each_iommu(iommu) { if (iommu->exclusion_start && iommu->exclusion_start >= dma_dom->aperture[index]->offset @@ -1353,7 +1353,7 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom) /* * Allocates a new protection domain usable for the dma_ops functions. - * It also intializes the page table and the address allocator data + * It also initializes the page table and the address allocator data * structures required for the dma_ops interface */ static struct dma_ops_domain *dma_ops_domain_alloc(void) diff --git a/arch/x86/kernel/early_printk_mrst.c b/arch/x86/kernel/early_printk_mrst.c index 65df603622b2..25bfdbb5b130 100644 --- a/arch/x86/kernel/early_printk_mrst.c +++ b/arch/x86/kernel/early_printk_mrst.c @@ -103,7 +103,7 @@ struct dw_spi_reg { static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0; static u32 *pclk_spi0; -/* Always contains an accessable address, start with 0 */ +/* Always contains an accessible address, start with 0 */ static struct dw_spi_reg *pspi; static struct kmsg_dumper dw_dumper; diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index bcece91dd311..8e09aa3aa6d6 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -124,7 +124,7 @@ ENTRY(startup_32) movsl movl pa(boot_params) + NEW_CL_POINTER,%esi andl %esi,%esi - jz 1f # No comand line + jz 1f # No command line movl $pa(boot_command_line),%edi movl $(COMMAND_LINE_SIZE/4),%ecx rep diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 4cd59b0d7c15..78ee4b1d4e85 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1030,7 +1030,7 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) /* * Add group onto cgroup list. It might happen that bdi->dev is - * not initiliazed yet. Initialize this new group without major + * not initialized yet. Initialize this new group without major * and minor info and this info will be filled in once a new thread * comes for IO. See code above. */ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index bdbfaf22bd14..962a3ccff6fd 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -93,7 +93,7 @@ #define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */ #define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */ -#define AOPOBJ_DATA_VALID 0x04 /* Object is intialized and data is valid */ +#define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */ #define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */ #define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */ #define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f77c67d267c..5b0295a923a7 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2240,7 +2240,7 @@ int ata_dev_configure(struct ata_device *dev) if (id[ATA_ID_CFA_KEY_MGMT] & 1) ata_dev_printk(dev, KERN_WARNING, "supports DRM functions and may " - "not be fully accessable.\n"); + "not be fully accessible.\n"); snprintf(revbuf, 7, "CFA"); } else { snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); @@ -2248,7 +2248,7 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_tpm(id)) ata_dev_printk(dev, KERN_WARNING, "supports DRM functions and may " - "not be fully accessable.\n"); + "not be fully accessible.\n"); } dev->n_sectors = ata_id_n_sectors(id); diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index b777176ff494..e079cf29ed5d 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -370,7 +370,7 @@ static int __devinit vsc_sata_init_one(struct pci_dev *pdev, if (pci_resource_len(pdev, 0) == 0) return -ENODEV; - /* map IO regions and intialize host accordingly */ + /* map IO regions and initialize host accordingly */ rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h index 5042bb2dab15..f53a43ae2bbe 100644 --- a/drivers/atm/idt77252.h +++ b/drivers/atm/idt77252.h @@ -572,7 +572,7 @@ struct idt77252_dev #define SAR_STAT_TSQF 0x00001000 /* Transmit Status Queue full */ #define SAR_STAT_TMROF 0x00000800 /* Timer overflow */ #define SAR_STAT_PHYI 0x00000400 /* PHY device Interrupt flag */ -#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Comand Busy Flag */ +#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Command Busy Flag */ #define SAR_STAT_FBQ3A 0x00000100 /* Free Buffer Queue 3 Attention */ #define SAR_STAT_FBQ2A 0x00000080 /* Free Buffer Queue 2 Attention */ #define SAR_STAT_RSQF 0x00000040 /* Receive Status Queue full */ diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 9309d4724e13..ad8e207784d4 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2063,7 +2063,7 @@ static int tx_init(struct atm_dev *dev) - UBR Table size is 4K - UBR wait queue is 4K since the table and wait queues are contiguous, all the bytes - can be initialized by one memeset. + can be initialized by one memeset. */ vcsize_sel = 0; @@ -2089,7 +2089,7 @@ static int tx_init(struct atm_dev *dev) - ABR Table size is 2K - ABR wait queue is 2K since the table and wait queues are contiguous, all the bytes - can be intialized by one memeset. + can be initialized by one memeset. */ i = ABR_SCHED_TABLE * iadev->memSize; writew((i >> 11) & 0xffff, iadev->seg_reg+ABR_SBPTR_BASE); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 31b526661ec4..c5356ef7e54e 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -8,7 +8,7 @@ * * * The driver model core calls device_pm_add() when a device is registered. - * This will intialize the embedded device_pm_info object in the device + * This will initialize the embedded device_pm_info object in the device * and add it to the list of power-controlled devices. sysfs entries for * controlling device power management will also be added. * diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 338bc4eed1f3..da8b7f161cdb 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1060,8 +1060,8 @@ static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data) * mid_setup_dma - Setup the DMA controller * @pdev: Controller PCI device structure * - * Initilize the DMA controller, channels, registers with DMA engine, - * ISR. Initilize DMA controller channels. + * Initialize the DMA controller, channels, registers with DMA engine, + * ISR. Initialize DMA controller channels. */ static int mid_setup_dma(struct pci_dev *pdev) { @@ -1219,7 +1219,7 @@ static void middma_shutdown(struct pci_dev *pdev) * @pdev: Controller PCI device structure * @id: pci device id structure * - * Initilize the PCI device, map BARs, query driver data. + * Initialize the PCI device, map BARs, query driver data. * Call setup_dma to complete contoller and chan initilzation */ static int __devinit intel_mid_dma_probe(struct pci_dev *pdev, diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h index 60e0d1c72dee..6f8b07131ec4 100644 --- a/drivers/edac/amd8131_edac.h +++ b/drivers/edac/amd8131_edac.h @@ -99,7 +99,7 @@ struct amd8131_dev_info { /* * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC - * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are + * Controller, and ATCA-6101 has two AMD8131 chipsets, so there are * four PCIX Bridges on ATCA-6101 altogether. * * These PCIX Bridges share the same PCI Device ID and are all of diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index c973004c002c..db1df59ae2b6 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -47,7 +47,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar) offset = address & ~PAGE_MASK; syndrome = (ar & 0x000000001fe00000ul) >> 21; - /* TODO: Decoding of the error addresss */ + /* TODO: Decoding of the error address */ edac_mc_handle_ce(mci, csrow->first_page + pfn, offset, syndrome, 0, chan, ""); } @@ -68,7 +68,7 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar) pfn = address >> PAGE_SHIFT; offset = address & ~PAGE_MASK; - /* TODO: Decoding of the error addresss */ + /* TODO: Decoding of the error address */ edac_mc_handle_ue(mci, csrow->first_page + pfn, offset, 0, ""); } diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index d7ca43a828bd..035eaaf2d906 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -258,7 +258,7 @@ enum scrub_type { * for single channel are 64 bits, for dual channel 128 * bits. * - * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memmory. + * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory. * Motherboards commonly drive two chip-select pins to * a memory stick. A single-ranked stick, will occupy * only one of those rows. The other will be unused. diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 070cea41b661..b9f0c20df1aa 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -873,7 +873,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1) } /** - * ppc4xx_edac_init_csrows - intialize driver instance rows + * ppc4xx_edac_init_csrows - initialize driver instance rows * @mci: A pointer to the EDAC memory controller instance * associated with the ibm,sdram-4xx-ddr2 controller for which * the csrows (i.e. banks/ranks) are being initialized. @@ -881,7 +881,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1) * currently set for the controller, from which bank width * and memory typ information is derived. * - * This routine intializes the virtual "chip select rows" associated + * This routine initializes the virtual "chip select rows" associated * with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2 * controller bank/rank is mapped to a row. * @@ -992,7 +992,7 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) } /** - * ppc4xx_edac_mc_init - intialize driver instance + * ppc4xx_edac_mc_init - initialize driver instance * @mci: A pointer to the EDAC memory controller instance being * initialized. * @op: A pointer to the OpenFirmware device tree node associated diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index fe359a239df3..4707cbdb35cd 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -1314,7 +1314,7 @@ typedef struct _GET_ENGINE_CLOCK_PARAMETERS typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS { USHORT usPrescale; //Ratio between Engine clock and I2C clock - USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID + USHORT usVRAMAddress; //Address in Frame Buffer where to pace raw EDID USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte UCHAR ucSlaveAddr; //Read from which slave diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index c9fffd0389fe..2bd3469b3071 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -434,7 +434,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controler has timedout, re-init the h/w */ + /* controller has timedout, re-init the h/w */ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); (void) init_hw(dev); status = -ETIMEDOUT; @@ -498,7 +498,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controler has timedout, re-init the h/w */ + /* controller has timedout, re-init the h/w */ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); (void) init_hw(dev); status = -ETIMEDOUT; diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 4bb997aa39d0..83d2e19d31ae 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -689,7 +689,7 @@ struct t3_swrq { * A T3 WQ implements both the SQ and RQ. */ struct t3_wq { - union t3_wr *queue; /* DMA accessable memory */ + union t3_wr *queue; /* DMA accessible memory */ dma_addr_t dma_addr; /* DMA address for HW */ DEFINE_DMA_UNMAP_ADDR(mapping); /* unmap kruft */ u32 error; /* 1 once we go to ERROR */ diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 584d443b5335..ead2627c06a8 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -314,7 +314,7 @@ MODULE_PARM_DESC(txselect, \ #define krp_serdesctrl KREG_IBPORT_IDX(IBSerdesCtrl) /* - * Per-context kernel registers. Acess only with qib_read_kreg_ctxt() + * Per-context kernel registers. Access only with qib_read_kreg_ctxt() * or qib_write_kreg_ctxt() */ #define krc_rcvhdraddr KREG_IDX(RcvHdrAddr0) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 06ea8da95c62..6675bd7dde19 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -610,7 +610,7 @@ config TOUCHSCREEN_USB_ZYTRONIC config TOUCHSCREEN_USB_ETT_TC45USB default y - bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED + bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_NEXIO diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 178942a2ee61..8a3c5cfc4fea 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2318,7 +2318,7 @@ static int gigaset_probe(struct usb_interface *interface, __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode, GIGASET_MODULENAME); if (!cs) @@ -2576,7 +2576,7 @@ static int __init bas_gigaset_init(void) { int result; - /* allocate memory for our driver state and intialize it */ + /* allocate memory for our driver state and initialize it */ driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &gigops, THIS_MODULE); diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index d151dcbf770d..0ef09d0eb96b 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -513,7 +513,7 @@ gigaset_tty_open(struct tty_struct *tty) return -ENODEV; } - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); if (!cs) goto error; @@ -771,7 +771,7 @@ static int __init ser_gigaset_init(void) return rc; } - /* allocate memory for our driver state and intialize it */ + /* allocate memory for our driver state and initialize it */ driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &ops, THIS_MODULE); diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 4a66338f4e7d..5e3300d8a2a5 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -695,7 +695,7 @@ static int gigaset_probe(struct usb_interface *interface, dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); if (!cs) return -ENODEV; @@ -894,7 +894,7 @@ static int __init usb_gigaset_init(void) { int result; - /* allocate memory for our driver state and intialize it */ + /* allocate memory for our driver state and initialize it */ driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &ops, THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h index 74a6ccf9065c..8121e046b739 100644 --- a/drivers/isdn/hardware/mISDN/ipac.h +++ b/drivers/isdn/hardware/mISDN/ipac.h @@ -29,7 +29,7 @@ struct isac_hw { u32 type; u32 off; /* offset to isac regs */ char *name; - spinlock_t *hwlock; /* lock HW acccess */ + spinlock_t *hwlock; /* lock HW access */ read_reg_func *read_reg; write_reg_func *write_reg; fifo_func *read_fifo; @@ -70,7 +70,7 @@ struct ipac_hw { struct hscx_hw hscx[2]; char *name; void *hw; - spinlock_t *hwlock; /* lock HW acccess */ + spinlock_t *hwlock; /* lock HW access */ struct module *owner; u32 type; read_reg_func *read_reg; diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h index 4a134acd44d0..9962bdf699c7 100644 --- a/drivers/isdn/hardware/mISDN/isar.h +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -44,7 +44,7 @@ struct isar_ch { struct isar_hw { struct isar_ch ch[2]; void *hw; - spinlock_t *hwlock; /* lock HW acccess */ + spinlock_t *hwlock; /* lock HW access */ char *name; struct module *owner; read_reg_func *read_reg; diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 40b914bded8c..2e72227bd071 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1427,8 +1427,8 @@ modeisar(struct BCState *bcs, int mode, int bc) &bcs->hw.isar.reg->Flags)) bcs->hw.isar.dpath = 1; else { - printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n"); - debugl1(cs, "isar modeisar analog funktions only with DP1"); + printk(KERN_WARNING"isar modeisar analog functions only with DP1\n"); + debugl1(cs, "isar modeisar analog functions only with DP1"); return(1); } break; diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c index 97a4e9b25fe4..a9d83b5d0e49 100644 --- a/drivers/media/video/cx25840/cx25840-ir.c +++ b/drivers/media/video/cx25840/cx25840-ir.c @@ -261,7 +261,7 @@ static u16 ns_to_pulse_width_count(u32 ns, u16 divider) u32 rem; /* - * The 2 lsb's of the pulse width timer count are not accessable, hence + * The 2 lsb's of the pulse width timer count are not accessible, hence * the (1 << 2) */ n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */ diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index 188841b476e0..ebd5c4338ebb 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -33,7 +33,7 @@ extern spinlock_t vpif_lock; #define regr(reg) readl((reg) + vpif_base) #define regw(value, reg) writel(value, (reg + vpif_base)) -/* Register Addresss Offsets */ +/* Register Address Offsets */ #define VPIF_PID (0x0000) #define VPIF_CH0_CTRL (0x0004) #define VPIF_CH1_CTRL (0x0008) diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c index 7918680917d0..3e5cf27ec2b2 100644 --- a/drivers/media/video/davinci/vpss.c +++ b/drivers/media/video/davinci/vpss.c @@ -85,7 +85,7 @@ enum vpss_platform_type { /* * vpss operations. Depends on platform. Not all functions are available * on all platforms. The api, first check if a functio is available before - * invoking it. In the probe, the function ptrs are intialized based on + * invoking it. In the probe, the function ptrs are initialized based on * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. */ struct vpss_hw_ops { diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 15f8793e325b..21d7c0d8f51f 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -1286,7 +1286,7 @@ static int omap_vout_release(struct file *file) videobuf_mmap_free(q); /* Even if apply changes fails we should continue - freeing allocated memeory */ + freeing allocated memory */ if (vout->streaming) { u32 mask = 0; diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index e1bac5051460..cdd8e348a543 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c @@ -653,8 +653,8 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) goto out; } - /* Check that the hardware is accessable. If the status bytes are - * 0xFF then the device is not accessable, the the IRQ belongs + /* Check that the hardware is accessible. If the status bytes are + * 0xFF then the device is not accessible, the the IRQ belongs * to another driver. * 4 x u32 interrupt registers. */ diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h index 494957b10bac..7f38549715b6 100644 --- a/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h @@ -147,7 +147,7 @@ enum sn9c102_i2c_interface { struct sn9c102_sensor { char name[32], /* sensor name */ - maintainer[64]; /* name of the mantainer */ + maintainer[64]; /* name of the maintainer */ enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */ diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index 37fe16181e3c..1f04438695dd 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -95,7 +95,7 @@ struct zoran_params { int quality; /* Measure for quality of compressed images. * Scales linearly with the size of the compressed images. - * Must be beetween 0 and 100, 100 is a compression + * Must be between 0 and 100, 100 is a compression * ratio of 1:4 */ int odd_even; /* Which field should come first ??? */ diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index 691620dbedd2..8b04810df469 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -268,7 +268,7 @@ /* Compatibility Error : IR Disabled */ #define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030) -/* Compatibility Error : Inquiry Comand failed */ +/* Compatibility Error : Inquiry Command failed */ #define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031) /* Compatibility Error : Device not direct access device */ #define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 3e57b61ca446..3358c0af3466 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -7977,7 +7977,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) NULL, /* 2Eh */ NULL, /* 2Fh */ "Compatibility Error: IR Disabled", /* 30h */ - "Compatibility Error: Inquiry Comand Failed", /* 31h */ + "Compatibility Error: Inquiry Command Failed", /* 31h */ "Compatibility Error: Device not Direct Access " "Device ", /* 32h */ "Compatibility Error: Removable Device Found", /* 33h */ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 83a5115f0251..5651f77a8cc1 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1146,7 +1146,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, * * This function will delete scheduled target reset from the list and * try to send next target reset. This will be called from completion - * context of any Task managment command. + * context of any Task management command. */ void diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index f87a9d405a5e..ae7cad185898 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -309,7 +309,7 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq) * @ireq: I2O block request * @mptr: message body pointer * - * Builds the SG list and map it to be accessable by the controller. + * Builds the SG list and map it to be accessible by the controller. * * Returns 0 on failure or 1 on success. */ diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c index 9e3879ef58f2..fe8616a8d287 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/misc/arm-charlcd.c @@ -313,7 +313,7 @@ static int __init charlcd_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work); schedule_delayed_work(&lcd->init_work, 0); - dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n", + dev_info(&pdev->dev, "initialized ARM character LCD at %08x\n", lcd->phybase); return 0; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 217f82037fc1..bfc8a8ae55df 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -257,7 +257,7 @@ static u32 get_card_status(struct mmc_card *card, struct request *req) cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) - printk(KERN_ERR "%s: error %d sending status comand", + printk(KERN_ERR "%s: error %d sending status command", req->rq_disk->disk_name, err); return cmd.resp[0]; } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d618e8673996..c99a1fcd97f6 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -462,7 +462,7 @@ config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE) help - This selects the MMC Host Interface controler (MMCIF). + This selects the MMC Host Interface controller (MMCIF). This driver supports MMCIF in sh7724/sh7757/sh7372. diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 41e5a60493ad..ef72e874ca36 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -192,7 +192,7 @@ static inline void SEND_STOP(struct au1xmmc_host *host) au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host)); au_sync(); - /* Send the stop commmand */ + /* Send the stop command */ au_writel(STOP_CMD, HOST_CMD(host)); } diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index f472c2714eb8..bbc298fd2a15 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -446,7 +446,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, mmc->max_seg_size = 1024 * 512; mmc->max_blk_size = 512; - /* reset the controler */ + /* reset the controller */ if (sdricoh_reset(host)) { dev_dbg(dev, "could not reset\n"); result = -EIO; @@ -478,7 +478,7 @@ static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev) dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device" " %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]); - /* search pci cardbus bridge that contains the mmc controler */ + /* search pci cardbus bridge that contains the mmc controller */ /* the io region is already claimed by yenta_socket... */ while ((pci_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1f75a1b1f7c3..31bf376b82a0 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -821,7 +821,7 @@ retry: * * Wait for command done. This is a helper function for nand_wait used when * we are in interrupt context. May happen when in panic and trying to write - * an oops trough mtdoops. + * an oops through mtdoops. */ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, unsigned long timeo) diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index e9ad16f00b56..4a6f0eac8b12 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -4947,7 +4947,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code) memset(&ilt_cli, 0, sizeof(struct ilt_client_info)); memset(&ilt, 0, sizeof(struct bnx2x_ilt)); - /* initalize dummy TM client */ + /* initialize dummy TM client */ ilt_cli.start = 0; ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1; ilt_cli.client_num = ILT_CLIENT_TM; diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 1cefe489a955..245220af9feb 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -1604,7 +1604,7 @@ (~misc_registers_sw_timer_cfg_4.sw_timer_cfg_4[1] ) is set */ #define MISC_REG_SW_TIMER_RELOAD_VAL_4 0xa2fc /* [RW 32] the value of the counter for sw timers1-8. there are 8 addresses - in this register. addres 0 - timer 1; address 1 - timer 2, ... address 7 - + in this register. address 0 - timer 1; address 1 - timer 2, ... address 7 - timer 8 */ #define MISC_REG_SW_TIMER_VAL 0xa5c0 /* [RW 1] Set by the MCP to remember if one or more of the drivers is/are diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 881914bc4e9c..106718c1be5b 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -840,7 +840,7 @@ static int ad_lacpdu_send(struct port *port) lacpdu_header = (struct lacpdu_header *)skb_put(skb, length); memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); - /* Note: source addres is set to be the member's PERMANENT address, + /* Note: source address is set to be the member's PERMANENT address, because we use it to identify loopback lacpdus in receive. */ memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU; @@ -881,7 +881,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) marker_header = (struct bond_marker_header *)skb_put(skb, length); memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); - /* Note: source addres is set to be the member's PERMANENT address, + /* Note: source address is set to be the member's PERMANENT address, because we use it to identify loopback MARKERs in receive. */ memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); marker_header->hdr.h_proto = PKT_TYPE_LACPDU; @@ -1916,7 +1916,7 @@ int bond_3ad_bind_slave(struct slave *slave) return -1; } - //check that the slave has not been intialized yet. + //check that the slave has not been initialized yet. if (SLAVE_AD_INFO(slave).port.slave != slave) { // port initialization diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 63ebf76d2390..8a43c7e19701 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -556,7 +556,7 @@ struct chelsio_vpd_t { #define EEPROM_MAX_POLL 4 /* - * Read SEEPROM. A zero is written to the flag register when the addres is + * Read SEEPROM. A zero is written to the flag register when the address is * written to the Control register. The hardware device will set the flag to a * one when 4B have been transferred to the Data register. */ diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c index a8766fb2f9ab..e13b7fe9d082 100644 --- a/drivers/net/cxgb3/mc5.c +++ b/drivers/net/cxgb3/mc5.c @@ -318,7 +318,7 @@ static void mc5_dbgi_mode_disable(const struct mc5 *mc5) /* * Initialization that requires the OS and protocol layers to already - * be intialized goes here. + * be initialized goes here. */ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, unsigned int nroutes) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 3a6adf0b3e9d..0b197043bc34 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -607,7 +607,7 @@ struct t3_vpd { * * Read a 32-bit word from a location in VPD EEPROM using the card's PCI * VPD ROM capability. A zero is written to the flag bit when the - * addres is written to the control register. The hardware device will + * address is written to the control register. The hardware device will * set the flag to 1 when 4 bytes have been read into the data register. */ int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index ecd9f6c6bcd5..5e820f4e68b9 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -41,7 +41,7 @@ struct e1000_hw; struct e1000_hw_stats; /* Enumerated types specific to the e1000 hardware */ -/* Media Access Controlers */ +/* Media Access Controllers */ typedef enum { e1000_undefined = 0, e1000_82542_rev2_0, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4686c3983fc3..1b8a43a29c01 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2194,7 +2194,7 @@ static void e1000_set_rx_mode(struct net_device *netdev) * addresses take precedence to avoid disabling unicast filtering * when possible. * - * RAR 0 is used for the station MAC adddress + * RAR 0 is used for the station MAC address * if there are not 14 addresses, go ahead and clear the filters */ i = 1; diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 7236f1a53ba0..a655beb69320 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -300,7 +300,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) /* * Ensure that the inter-port SWSM.SMBI lock bit is clear before - * first NVM or PHY acess. This should be done for single-port + * first NVM or PHY access. This should be done for single-port * devices, and for one port only on dual-port devices so that * for those devices we can still use the SMBI lock to synchronize * inter-port accesses to the PHY & NVM. diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index e3374d9a2472..38c84ba3e3c1 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -321,7 +321,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) } /* - * Reset the PHY before any acccess to it. Doing so, ensures that + * Reset the PHY before any access to it. Doing so, ensures that * the PHY is in a known good state before we read/write PHY registers. * The generic reset is sufficient here, because we haven't determined * the PHY type yet. diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 3d3dc0c82355..b9bff5ba009f 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2976,7 +2976,7 @@ s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data) } /** - * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page + * e1000_get_phy_addr_for_hv_page - Get PHY address based on page * @page: page to be accessed **/ static u32 e1000_get_phy_addr_for_hv_page(u32 page) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 7c826319ee5a..dbaec546c428 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1760,7 +1760,7 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(mem, int, NULL, 0); module_param(autodetect, int, 0); -MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)"); +MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)"); MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)"); MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)"); diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h index 4dc39e5f0156..77fcf4459161 100644 --- a/drivers/net/irda/donauboe.h +++ b/drivers/net/irda/donauboe.h @@ -30,7 +30,7 @@ * or the type-DO IR port. * * IrDA chip set list from Toshiba Computer Engineering Corp. - * model method maker controler Version + * model method maker controller Version * Portege 320CT FIR,SIR Toshiba Oboe(Triangle) * Portege 3010CT FIR,SIR Toshiba Oboe(Sydney) * Portege 3015CT FIR,SIR Toshiba Oboe(Sydney) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 0bd8fbb5bfd0..05e6b8cafb39 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1078,7 +1078,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) /* * The defaults in the HW for RX PB 1-7 are not zero and so should be - * intialized to zero for non DCB mode otherwise actual total RX PB + * initialized to zero for non DCB mode otherwise actual total RX PB * would be bigger than programmed and filter space would run into * the PB 0 region. */ @@ -1169,7 +1169,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) /* * The defaults in the HW for RX PB 1-7 are not zero and so should be - * intialized to zero for non DCB mode otherwise actual total RX PB + * initialized to zero for non DCB mode otherwise actual total RX PB * would be bigger than programmed and filter space would run into * the PB 0 region. */ diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 9f8e7027b0b3..661ed1ff4c2e 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -238,7 +238,7 @@ static int temac_dma_bd_init(struct net_device *ndev) goto out; } /* allocate the tx and rx ring buffer descriptors. */ - /* returns a virtual addres and a physical address. */ + /* returns a virtual address and a physical address. */ lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, sizeof(*lp->tx_bd_v) * TX_BD_NUM, &lp->tx_bd_p, GFP_KERNEL); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 581836867098..5976d1d51df1 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -36,7 +36,7 @@ Rev 1.07.06 Nov. 7 2000 Jeff Garzik some bug fix and cleaning Rev 1.07.05 Nov. 6 2000 metapirat contribute media type select by ifconfig Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support - Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaround rule + Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalizer workaround rule Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1 Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring Rev 1.06.04 Feb. 11 2000 Jeff Garzik softnet and init for kernel 2.4 diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8b3dc1eb4015..474652a2f70d 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -12,7 +12,7 @@ /* * RX HW/SW interaction overview * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * There are 2 types of RX communication channels betwean driver and NIC. + * There are 2 types of RX communication channels between driver and NIC. * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds * info about buffer's location, size and ID. An ID field is used to identify a @@ -821,7 +821,7 @@ static void bdx_setmulti(struct net_device *ndev) } /* use PMF to accept first MAC_MCST_NUM (15) addresses */ - /* TBD: sort addreses and write them in ascending order + /* TBD: sort addresses and write them in ascending order * into RX_MAC_MCST regs. we skip this phase now and accept ALL * multicast frames throu IMF */ /* accept the rest of addresses throu IMF */ @@ -1346,7 +1346,7 @@ static void print_rxfd(struct rxf_desc *rxfd) /* * TX HW/SW interaction overview * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * There are 2 types of TX communication channels betwean driver and NIC. + * There are 2 types of TX communication channels between driver and NIC. * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets * 2) TX Data Fifo - TXD - holds descriptors of full buffers. * diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 55f3a3e667a9..e625f9530cf9 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1309,7 +1309,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, break; case SIOCGIFHWADDR: - /* Get hw addres */ + /* Get hw address */ memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); ifr.ifr_hwaddr.sa_family = tun->dev->type; if (copy_to_user(argp, &ifr, ifreq_len)) diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 9890d4d596d0..654295816a39 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -1695,7 +1695,7 @@ struct vxge_hw_device_stats_sw_err { * struct vxge_hw_device_stats - Contains HW per-device statistics, * including hw. * @devh: HW device handle. - * @dma_addr: DMA addres of the %hw_info. Given to device to fill-in the stats. + * @dma_addr: DMA address of the %hw_info. Given to device to fill-in the stats. * @hw_info_dmah: DMA handle used to map hw statistics onto the device memory * space. * @hw_info_dma_acch: One more DMA handle used subsequently to free the diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index d45b08d1dbc9..94ff9b02e28e 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -125,7 +125,7 @@ static u32 dscc4_pci_config_store[16]; /* Module parameters */ MODULE_AUTHOR("Maintainer: Francois Romieu "); -MODULE_DESCRIPTION("Siemens PEB20534 PCI Controler"); +MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller"); MODULE_LICENSE("GPL"); module_param(debug, int, 0); MODULE_PARM_DESC(debug,"Enable/disable extra messages"); diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index cdedab46ba21..bcb483fdc4d9 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -280,7 +280,7 @@ int i2400m_check_mac_addr(struct i2400m *i2400m) result); goto error; } - /* Extract MAC addresss */ + /* Extract MAC address */ ddi = (void *) skb->data; BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address)); d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n", diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 59ac7705e76e..8cde3a52d225 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -698,7 +698,7 @@ enum i2400m_bm_cmd_flags { * @I2400M_BRI_MAC_REINIT: We need to reinitialize the boot * rom after reading the MAC address. This is quite a dirty hack, * if you ask me -- the device requires the bootrom to be - * intialized after reading the MAC address. + * initialized after reading the MAC address. */ enum i2400m_bri { I2400M_BRI_SOFT = 1 << 1, diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index ca79ecd832fd..2a246d13b520 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -1063,7 +1063,7 @@ /* * EEPROM command register */ -#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ +#define AR5K_EEPROM_CMD 0x6008 /* Register Address */ #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ @@ -1083,7 +1083,7 @@ /* * EEPROM config register */ -#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ +#define AR5K_EEPROM_CFG 0x6010 /* Register Address */ #define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ #define AR5K_EEPROM_CFG_SIZE_AUTO 0 #define AR5K_EEPROM_CFG_SIZE_4KBIT 1 @@ -1125,7 +1125,7 @@ * Second station id register (Upper 16 bits of MAC address + PCU settings) */ #define AR5K_STA_ID1 0x8004 /* Register Address */ -#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC address */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 0dc33b65e86b..be4828167012 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -1919,7 +1919,7 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); } -/* Intialize B/G PHY power control */ +/* Initialize B/G PHY power control */ static void b43_phy_init_pctl(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 35033dd342ce..28e477d01587 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -153,7 +153,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) phy->calibrated = 1; } -/* intialize B PHY power control +/* initialize B PHY power control * as described in http://bcm-specs.sipsolutions.net/InitPowerControl */ static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 7c7f7dcb1b1e..972b738c0e4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -107,7 +107,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, /* * XXX: The MAC address in the command buffer is often changed from * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC adress + * written to the command buffer often is not the same MAC address * read from the command buffer when the command returns. This * issue has not yet been resolved and this debugging is left to * observe the problem. diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 2c8cc954d1b6..ec2c75d77cea 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -630,7 +630,7 @@ islpci_alloc_memory(islpci_private *priv) printk(KERN_DEBUG "islpci_alloc_memory\n"); #endif - /* remap the PCI device base address to accessable */ + /* remap the PCI device base address to accessible */ if (!(priv->device_base = ioremap(pci_resource_start(priv->pdev, 0), ISL38XX_PCI_MEM_SIZE))) { @@ -709,7 +709,7 @@ islpci_alloc_memory(islpci_private *priv) PCI_DMA_FROMDEVICE); if (!priv->pci_map_rx_address[counter]) { /* error mapping the buffer to device - accessable memory address */ + accessible memory address */ printk(KERN_ERR "failed to map skb DMA'able\n"); goto out_free; } @@ -773,7 +773,7 @@ islpci_free_memory(islpci_private *priv) priv->data_low_rx[counter] = NULL; } - /* Free the acces control list and the WPA list */ + /* Free the access control list and the WPA list */ prism54_acl_clean(&priv->acl); prism54_wpa_bss_ie_clean(priv); mgt_clean(priv); diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 2fc52bc2d7dd..d44f8e20cce0 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv) MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); if (unlikely(!priv->pci_map_rx_address[index])) { - /* error mapping the buffer to device accessable memory address */ + /* error mapping the buffer to device accessible memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c3c206a97d54..a7d3f4c3ee0d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -274,7 +274,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, intf->beacon = entry; /* - * The MAC adddress must be configured after the device + * The MAC address must be configured after the device * has been initialized. Otherwise the device can reset * the MAC registers. * The BSSID address must only be configured in AP mode, diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index ee82df62e646..3e5befe4d03b 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -192,7 +192,7 @@ static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) } /* - * Get Ethernet MAC addresss. + * Get Ethernet MAC address. * * WARNING: We switch to FPAGE0 and switc back again. * Making sure there is no other WL function beening called by ISR. diff --git a/drivers/pcmcia/m32r_cfc.h b/drivers/pcmcia/m32r_cfc.h index 8146e3bee2e8..f558e1adf954 100644 --- a/drivers/pcmcia/m32r_cfc.h +++ b/drivers/pcmcia/m32r_cfc.h @@ -9,7 +9,7 @@ #endif /* - * M32R PC Card Controler + * M32R PC Card Controller */ #define M32R_PCC0_BASE 0x00ef7000 #define M32R_PCC1_BASE 0x00ef7020 diff --git a/drivers/pcmcia/m32r_pcc.h b/drivers/pcmcia/m32r_pcc.h index e4fffe417ba9..f95c58563bc8 100644 --- a/drivers/pcmcia/m32r_pcc.h +++ b/drivers/pcmcia/m32r_pcc.h @@ -5,7 +5,7 @@ #define M32R_MAX_PCC 2 /* - * M32R PC Card Controler + * M32R PC Card Controller */ #define M32R_PCC0_BASE 0x00ef7000 #define M32R_PCC1_BASE 0x00ef7020 diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 99d4f23cb435..0db482771fb5 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1198,7 +1198,7 @@ static int __init m8xx_probe(struct platform_device *ofdev, out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16)); - /* intialize the fixed memory windows */ + /* initialize the fixed memory windows */ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) { for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) { diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 2d61186ad5a2..304333faf441 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -7193,7 +7193,7 @@ static struct ibm_struct volume_driver_data = { * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) * * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at - * boot. Apparently the EC does not intialize it, so unless ACPI DSDT + * boot. Apparently the EC does not initialize it, so unless ACPI DSDT * does so, its initial value is meaningless (0x07). * * For firmware bugs, refer to: diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index fe16b482e912..4a8ae3935b3b 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c @@ -1,5 +1,5 @@ /* - * iPAQ h1930/h1940/rx1950 battery controler driver + * iPAQ h1930/h1940/rx1950 battery controller driver * Copyright (c) Vasily Khoruzhick * Based on h1940_battery.c by Arnaud Patard * @@ -427,5 +427,5 @@ static void __exit s3c_adc_bat_exit(void) module_exit(s3c_adc_bat_exit); MODULE_AUTHOR("Vasily Khoruzhick "); -MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controler driver"); +MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 0f19d540b655..122382dc4684 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -840,7 +840,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) } /** - * Emit buffer of a lan comand. + * Emit buffer of a lan command. */ static void lcs_lancmd_timeout(unsigned long data) diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index d692e229ecba..4c09d03bcb32 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -317,7 +317,7 @@ static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) /** * zfcp_cfdc_port_denied - Process "access denied" for port - * @port: The port where the acces has been denied + * @port: The port where the access has been denied * @qual: The FSF status qualifier for the access denied FSF status */ void zfcp_cfdc_port_denied(struct zfcp_port *port, diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index dbbc601948e5..7cb575654e40 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -416,7 +416,7 @@ static u8 orc_load_firmware(struct orc_host * host) /* Go back and check they match */ outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */ - bios_addr -= 0x1000; /* Reset the BIOS adddress */ + bios_addr -= 0x1000; /* Reset the BIOS address */ for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */ i < 0x1000; /* Firmware code size = 4K */ i++, bios_addr++) { diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index afc9aeba5edb..060ac4bd5a14 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -91,7 +91,7 @@ void aac_fib_map_free(struct aac_dev *dev) * aac_fib_setup - setup the fibs * @dev: Adapter to set up * - * Allocate the PCI space for the fibs, map it and then intialise the + * Allocate the PCI space for the fibs, map it and then initialise the * fib area, the unmapped fib data and also the free list */ diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq index 5997e7c3a191..1565be9ebd49 100644 --- a/drivers/scsi/aic7xxx_old/aic7xxx.seq +++ b/drivers/scsi/aic7xxx_old/aic7xxx.seq @@ -1178,7 +1178,7 @@ notFound: /* * Retrieve an SCB by SCBID first searching the disconnected list falling * back to DMA'ing the SCB down from the host. This routine assumes that - * ARG_1 is the SCBID of interrest and that SINDEX is the position in the + * ARG_1 is the SCBID of interest and that SINDEX is the position in the * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, * we go directly to the host for the SCB. */ diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index 28aaf349c111..40273a747d29 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -1689,7 +1689,7 @@ #define PHY_START_CAL 0x01 /* - * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC) + * HST_PCIX2 Registers, Address Range: (0x00-0xFC) */ #define PCIX_REG_BASE_ADR 0xB8040000 @@ -1802,7 +1802,7 @@ #define PCIC_TP_CTRL 0xFC /* - * EXSI Registers, Addresss Range: (0x00-0xFC) + * EXSI Registers, Address Range: (0x00-0xFC) */ #define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index 74374618010c..390168f62a13 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -797,7 +797,7 @@ static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) int j; /* Start from Page 1 of Mode 0 and 1. */ moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; - /* All the fields of page 1 can be intialized to 0. */ + /* All the fields of page 1 can be initialized to 0. */ for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); } @@ -938,7 +938,7 @@ static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) asd_write_reg_dword(asd_ha, SCBPRO, 0); asd_write_reg_dword(asd_ha, CSEQCON, 0); - /* Intialize CSEQ Mode 11 Interrupt Vectors. + /* Initialize CSEQ Mode 11 Interrupt Vectors. * The addresses are 16 bit wide and in dword units. * The values of their macros are in byte units. * Thus we have to divide by 4. */ @@ -961,7 +961,7 @@ static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); for (i = 0; i < 8; i++) { - /* Intialize Mode n Link m Interrupt Enable. */ + /* Initialize Mode n Link m Interrupt Enable. */ asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); /* Initialize Mode n Request Mailbox. */ asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 33c8dd51f474..aabbf3d3b394 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -2092,7 +2092,7 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_ABORT: /** - * IO is alraedy being cleaned up implicitly + * IO is already being cleaned up implicitly */ ioim->io_cbfn = __bfa_cb_ioim_abort; break; diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index b522bf30247a..b7aa23a3b1e8 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -5742,7 +5742,7 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status) switch (status) { case BFA_STATUS_OK: /* - * Initialiaze the V-Port fields + * Initialize the V-Port fields */ __vport_fcid(vport) = bfa_lps_get_pid(vport->lps); vport->vport_stats.fdisc_accepts++; diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 54f50b07dac7..31bbfb244bc4 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -3795,7 +3795,7 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, * adapter_add_device - Adds the device instance to the adaptor instance. * * @acb: The adapter device to be updated - * @dcb: A newly created and intialised device instance to add. + * @dcb: A newly created and initialised device instance to add. **/ static void adapter_add_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) @@ -4497,7 +4497,7 @@ static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb) * init_adapter - Grab the resource for the card, setup the adapter * information, set the card into a known state, create the various * tables etc etc. This basically gets all adapter information all up - * to date, intialised and gets the chip in sync with it. + * to date, initialised and gets the chip in sync with it. * * @host: This hosts adapter structure * @io_port: The base I/O port @@ -4788,7 +4788,7 @@ static void banner_display(void) * that it finds in the system. The pci_dev strcuture indicates which * instance we are being called from. * - * @dev: The PCI device to intialize. + * @dev: The PCI device to initialize. * @id: Looks like a pointer to the entry in our pci device table * that was actually matched by the PCI subsystem. * @@ -4859,7 +4859,7 @@ fail: * dc395x_remove_one - Called to remove a single instance of the * adapter. * - * @dev: The PCI device to intialize. + * @dev: The PCI device to initialize. **/ static void __devexit dc395x_remove_one(struct pci_dev *dev) { diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index c797f6b48f05..54a6ec8e131d 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1212,7 +1212,7 @@ static void fc_lun_reset_send(unsigned long data) /** * fc_lun_reset() - Send a LUN RESET command to a device * and wait for the reply - * @lport: The local port to sent the comand on + * @lport: The local port to sent the command on * @fsp: The FCP packet that identifies the LUN to be reset * @id: The SCSI command ID * @lun: The LUN ID to be reset diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index f681eea57730..0e4abb96d68e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1339,7 +1339,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ } /** - * lpfc_param_init - Intializes a cfg attribute + * lpfc_param_init - Initializes a cfg attribute * * Description: * Macro that given an attr e.g. hba_queue_depth expands diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a345dde16c86..2a6866e63aae 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -2614,7 +2614,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) if (unlikely(!fcf_record)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2554 Could not allocate memmory for " + "2554 Could not allocate memory for " "fcf record\n"); rc = -ENODEV; goto out; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 0d1e187b005d..c5614cfcc6e9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -9619,7 +9619,7 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) * lpfc_sli4_queue_free - free a queue structure and associated memory * @queue: The queue structure to free. * - * This function frees a queue structure and the DMAable memeory used for + * This function frees a queue structure and the DMAable memory used for * the host resident queue. This function must be called after destroying the * queue on the HBA. **/ diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 2b4a048cadf1..deb24ad1b8d2 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -13,7 +13,7 @@ */ /* - * Comand coalescing - This feature allows the driver to be able to combine + * Command coalescing - This feature allows the driver to be able to combine * two or more commands and issue as one command in order to boost I/O * performance. Useful if the nature of the I/O is sequential. It is not very * useful for random natured I/Os. diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index f8c86b28f03f..b95285f3383f 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -603,7 +603,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) #endif intx: - /* intialize the INT-X interrupt */ + /* initialize the INT-X interrupt */ rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost)); return rc; diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index d53e6503c6d5..a2ed201885ae 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -477,7 +477,7 @@ EXPORT_SYMBOL_GPL(scsi_nl_remove_driver); /** - * scsi_netlink_init - Called by SCSI subsystem to intialize + * scsi_netlink_init - Called by SCSI subsystem to initialize * the SCSI transport netlink interface * **/ diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 8b955b534a36..4afa81ad2caa 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1864,7 +1864,7 @@ static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev) * * This routine is similar to sym_set_workarounds(), except * that, at this point, we already know that the device was - * successfully intialized at least once before, and so most + * successfully initialized at least once before, and so most * of the steps taken there are un-needed here. */ static void sym2_reset_workarounds(struct pci_dev *pdev) diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 154529aacc03..49596a18f953 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -341,9 +341,9 @@ static void atmel_spi_next_message(struct spi_master *master) /* * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma: * - The buffer is either valid for CPU access, else NULL - * - If the buffer is valid, so is its DMA addresss + * - If the buffer is valid, so is its DMA address * - * This driver manages the dma addresss unless message->is_dma_mapped. + * This driver manages the dma address unless message->is_dma_mapped. */ static int atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 4e6245e67995..603428213d21 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -38,7 +38,7 @@ /* - * This supports acccess to SPI devices using normal userspace I/O calls. + * This supports access to SPI devices using normal userspace I/O calls. * Note that while traditional UNIX/POSIX I/O semantics are half duplex, * and often mask message boundaries, full SPI support requires full duplex * transfers. There are several kinds of internal message boundaries to diff --git a/drivers/staging/stradis/stradis.c b/drivers/staging/stradis/stradis.c index a057824e7ebc..dd3874b78263 100644 --- a/drivers/staging/stradis/stradis.c +++ b/drivers/staging/stradis/stradis.c @@ -745,7 +745,7 @@ static void set_out_format(struct saa7146 *saa, int mode) } } -/* Intialize bitmangler to map from a byte value to the mangled word that +/* Initialize bitmangler to map from a byte value to the mangled word that * must be output to program the Xilinx part through the DEBI port. * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0 * transfer FPGA code, init IBM chip, transfer IBM microcode diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index ed0266462c57..1f8084d59a43 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1316,7 +1316,7 @@ static struct imx_udc_struct controller = { }; /******************************************************************************* - * USB gadged driver functions + * USB gadget driver functions ******************************************************************************* */ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index e49b75a78000..f90d003f2302 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1658,7 +1658,7 @@ static int imx21_hc_reset(struct usb_hcd *hcd) spin_lock_irqsave(&imx21->lock, flags); - /* Reset the Host controler modules */ + /* Reset the Host controller modules */ writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH | USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC, imx21->regs + USBOTG_RST_CTRL); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 32149be4ad8e..e0cb12b573f9 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3094,7 +3094,7 @@ static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf) /* Some boards (mostly VIA?) report bogus overcurrent indications, * causing massive log spam unless we completely ignore them. It - * may be relevant that VIA VT8235 controlers, where PORT_POWER is + * may be relevant that VIA VT8235 controllers, where PORT_POWER is * always set, seem to clear PORT_OCC and PORT_CSC when writing to * PORT_POWER; that's surprising, but maybe within-spec. */ diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 44f8b9225054..a6afd15f6a46 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -717,7 +717,7 @@ static int adu_probe(struct usb_interface *interface, goto exit; } - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "Out of memory\n"); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 375664198776..7a10e48b78f9 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -768,7 +768,7 @@ static int iowarrior_probe(struct usb_interface *interface, int i; int retval = -ENOMEM; - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "Out of memory\n"); diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index edffef642337..eefb8275bb7e 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -642,7 +642,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * int i; int retval = -ENOMEM; - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 5d815049cbaa..1cbeaa17ffff 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1636,7 +1636,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb) struct musb_hw_ep *hw_ep; unsigned count = 0; - /* intialize endpoint list just once */ + /* initialize endpoint list just once */ INIT_LIST_HEAD(&(musb->g.ep_list)); for (epnum = 0, hw_ep = musb->endpoints; @@ -1715,7 +1715,7 @@ void musb_gadget_cleanup(struct musb *musb) * * -EINVAL something went wrong (not driver) * -EBUSY another gadget is already using the controller - * -ENOMEM no memeory to perform the operation + * -ENOMEM no memory to perform the operation * * @param driver the gadget driver * @param bind the driver's bind function diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index c7b1d8108de9..8cb9d80207fa 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -49,7 +49,7 @@ * * USB Stack port number 4 (1 based) * WUSB code port index 3 (0 based) - * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub) + * USB Address 5 (2 based -- 0 is for default, 1 for root hub) * * Now, because we don't use the concept as default address exactly * like the (wired) USB code does, we need to kind of skip it. So we diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index dee64c3b1e67..2ab704118c44 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -536,7 +536,7 @@ static int sstfb_set_par(struct fb_info *info) fbiinit2 = sst_read(FBIINIT2); fbiinit3 = sst_read(FBIINIT3); - /* everything is reset. we enable fbiinit2/3 remap : dac acces ok */ + /* everything is reset. we enable fbiinit2/3 remap : dac access ok */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8b5dd6369f82..47162de0b957 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -577,7 +577,7 @@ struct ext4_mount_options { #endif }; -/* Max physical block we can addres w/o extents */ +/* Max physical block we can address w/o extents */ #define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF /* diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 0554c48cb1fd..966ecb0d8f86 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2825,14 +2825,14 @@ fix_extent_len: * to an uninitialized extent. * * Writing to an uninitized extent may result in splitting the uninitialized - * extent into multiple /intialized unintialized extents (up to three) + * extent into multiple /initialized uninitialized extents (up to three) * There are three possibilities: * a> There is no split required: Entire extent should be uninitialized * b> Splits in two extents: Write is happening at either end of the extent * c> Splits in three extents: Somone is writing in middle of the extent * * One of more index blocks maybe needed if the extent tree grow after - * the unintialized extent split. To prevent ENOSPC occur at the IO + * the uninitialized extent split. To prevent ENOSPC occur at the IO * complete, we need to split the uninitialized extent before DIO submit * the IO. The uninitialized extent called at this time will be split * into three uninitialized extent(at most). After IO complete, the part diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 191616470466..4bc84b8adb7f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3740,9 +3740,9 @@ retry: * preallocated extents, and those write extend the file, no need to * fall back to buffered IO. * - * For holes, we fallocate those blocks, mark them as unintialized + * For holes, we fallocate those blocks, mark them as uninitialized * If those blocks were preallocated, we mark sure they are splited, but - * still keep the range to write as unintialized. + * still keep the range to write as uninitialized. * * The unwrritten extents will be converted to written when DIO is completed. * For async direct IO, since the IO may still pending when return, we diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index f935fd6600dd..4068c6c4c6f6 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -434,7 +434,7 @@ static int ocfs2_read_locked_inode(struct inode *inode, * #1 and #2 can be simply solved by never taking the lock * here for system files (which are the only type we read * during mount). It's a heavier approach, but our main - * concern is user-accesible files anyway. + * concern is user-accessible files anyway. * * #3 works itself out because we'll eventually take the * cluster lock before trusting anything anyway. diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 5fed60de7630..71998d4d61d5 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -1916,7 +1916,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, if (res->sr_bg_blkno) { /* Attempt to short-circuit the usual search mechanism * by jumping straight to the most recently used - * allocation group. This helps us mantain some + * allocation group. This helps us maintain some * contiguousness across allocations. */ status = ocfs2_search_one_group(ac, handle, bits_wanted, min_bits, res, &bits_left); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 9f3a78fe6ae4..7465a7ffc4fd 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -938,7 +938,7 @@ out_reclaim: * Slab object creation initialisation for the XFS inode. * This covers only the idempotent fields in the XFS inode; * all other fields need to be initialised on allocation - * from the slab. This avoids the need to repeatedly intialise + * from the slab. This avoids the need to repeatedly initialise * fields in the xfs inode that left in the initialise state * when freeing the inode. */ diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index c637b75b9f3f..cd77aa75c962 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -119,7 +119,7 @@ struct acpi_whea_header { struct acpi_table_bert { struct acpi_table_header header; /* Common ACPI table header */ u32 region_length; /* Length of the boot error region */ - u64 address; /* Physical addresss of the error region */ + u64 address; /* Physical address of the error region */ }; /* Boot Error Region (not a subtable, pointed to by Address field above) */ diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index ed4ba111bc8d..ce104e33cd22 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -564,7 +564,7 @@ struct cgroup_iter { /* * To iterate across the tasks in a cgroup: * - * 1) call cgroup_iter_start to intialize an iterator + * 1) call cgroup_iter_start to initialize an iterator * * 2) call cgroup_iter_next() to retrieve member tasks until it * returns NULL or until you want to end the iteration diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 68c642d8843d..59ea406be7f6 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h @@ -273,7 +273,7 @@ struct fw_cdev_event_iso_interrupt { * @closure: See &fw_cdev_event_common; * set by %FW_CDEV_CREATE_ISO_CONTEXT ioctl * @type: %FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL - * @completed: Offset into the receive buffer; data before this offest is valid + * @completed: Offset into the receive buffer; data before this offset is valid * * This event is sent in multichannel contexts (context type * %FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL) for &fw_cdev_iso_packet buffer diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index cb93d80aa642..5582ab3d3e48 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -39,7 +39,7 @@ struct mfd_cell { size_t data_size; /* - * This resources can be specified relatievly to the parent device. + * This resources can be specified relatively to the parent device. * For accessing device you should use resources from device */ int num_resources; diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 2b2769c5ca9f..2a128c8c2718 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -99,8 +99,8 @@ typedef __s32 sctp_assoc_t; #define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */ /* Options 104-106 are deprecated and removed. Do not use this space */ #define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */ -#define SCTP_GET_PEER_ADDRS 108 /* Get all peer addresss. */ -#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local addresss. */ +#define SCTP_GET_PEER_ADDRS 108 /* Get all peer address. */ +#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local address. */ #define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 8e9b222251c2..8a143ca79878 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h @@ -46,7 +46,7 @@ */ struct fcp_cmnd { __u8 fc_lun[8]; /* logical unit number */ - __u8 fc_cmdref; /* commmand reference number */ + __u8 fc_cmdref; /* command reference number */ __u8 fc_pri_ta; /* priority and task attribute */ __u8 fc_tm_flags; /* task management flags */ __u8 fc_flags; /* additional len & flags */ @@ -58,7 +58,7 @@ struct fcp_cmnd { struct fcp_cmnd32 { __u8 fc_lun[8]; /* logical unit number */ - __u8 fc_cmdref; /* commmand reference number */ + __u8 fc_cmdref; /* command reference number */ __u8 fc_pri_ta; /* priority and task attribute */ __u8 fc_tm_flags; /* task management flags */ __u8 fc_flags; /* additional len & flags */ diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 37755d621924..7242cc71bb7e 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -2913,7 +2913,7 @@ static void __init kdb_cmd_init(void) } } -/* Intialize kdb_printf, breakpoint tables and kdb state */ +/* Initialize kdb_printf, breakpoint tables and kdb state */ void __init kdb_init(int lvl) { static int kdb_init_lvl = KDB_NOT_INITIALIZED; diff --git a/kernel/kexec.c b/kernel/kexec.c index b55045bc7563..ec19b92c7ebd 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -163,7 +163,7 @@ static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, * just verifies it is an address we can use. * * Since the kernel does everything in page size chunks ensure - * the destination addreses are page aligned. Too many + * the destination addresses are page aligned. Too many * special cases crop of when we don't do this. The most * insidious is getting overlapping destination addresses * simply because addresses are changed to page size diff --git a/kernel/power/swap.c b/kernel/power/swap.c index a0e4a86ccf94..cd09c22de03d 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -865,7 +865,7 @@ out_finish: /** * swsusp_read - read the hibernation image. * @flags_p: flags passed by the "frozen" kernel in the image header should - * be written into this memeory location + * be written into this memory location */ int swsusp_read(unsigned int *flags_p) diff --git a/kernel/sched.c b/kernel/sched.c index aa14a56f9d03..554c0d6c489e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2568,7 +2568,7 @@ out: * try_to_wake_up_local - try to wake up a local task with rq lock held * @p: the thread to be awakened * - * Put @p on the run-queue if it's not alredy there. The caller must + * Put @p on the run-queue if it's not already there. The caller must * ensure that this_rq() is locked, @p is bound to this_rq() and not * the current task. this_rq() stays locked over invocation. */ diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index 1357c5786064..d9c5fe4ff1b2 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -1193,7 +1193,7 @@ static ssize_t bin_dn_node_address(struct file *file, buf[result] = '\0'; - /* Convert the decnet addresss to binary */ + /* Convert the decnet address to binary */ result = -EIO; nodep = strchr(buf, '.') + 1; if (!nodep) diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index c18d7efa1b4b..ddbbaf2950ef 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -678,7 +678,7 @@ EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) { - /* Intialize mult/shift and max_idle_ns */ + /* Initialize mult/shift and max_idle_ns */ __clocksource_updatefreq_scale(cs, scale, freq); /* Add clocksource to the clcoksource list */ diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index e3dfecaf13e6..6cf223764be8 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -53,7 +53,7 @@ */ /* - * Function trace entry - function address and parent function addres: + * Function trace entry - function address and parent function address: */ FTRACE_ENTRY(function, ftrace_entry, diff --git a/lib/nlattr.c b/lib/nlattr.c index c4706eb98d3d..18d158df6f0e 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -167,7 +167,7 @@ nla_policy_len(const struct nla_policy *p, int n) * @policy: validation policy * * Parses a stream of attributes and stores a pointer to each attribute in - * the tb array accessable via the attribute type. Attributes with a type + * the tb array accessible via the attribute type. Attributes with a type * exceeding maxtype will be silently ignored for backwards compatibility * reasons. policy may be set to NULL if no validation is required. * diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 7c06ee51a29a..c47bbe11b804 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -60,7 +60,7 @@ int swiotlb_force; static char *io_tlb_start, *io_tlb_end; /* - * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and + * The number of IO TLB blocks (in groups of 64) between io_tlb_start and * io_tlb_end. This is command line adjustable via setup_io_tlb_npages. */ static unsigned long io_tlb_nslabs; diff --git a/mm/percpu.c b/mm/percpu.c index efe816856a9d..f715d01d5ba3 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -258,7 +258,7 @@ static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk, /* * (Un)populated page region iterators. Iterate over (un)populated - * page regions betwen @start and @end in @chunk. @rs and @re should + * page regions between @start and @end in @chunk. @rs and @re should * be integer variables and will be set to start and end page index of * the current region. */ diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index 29d6cbffb283..64b984091edb 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c @@ -9,7 +9,7 @@ * * However, virtual mappings need a page table and TLBs. Many Linux * architectures already map their physical space using 1-1 mappings - * via TLBs. For those arches the virtual memmory map is essentially + * via TLBs. For those arches the virtual memory map is essentially * for free if we use the same page size as the 1-1 mappings. In that * case the overhead consists of a few additional pages that are * allocated to create a view of memory for vmemmap. diff --git a/net/core/dev.c b/net/core/dev.c index 35dfb8318483..89204e8c0e14 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6096,7 +6096,7 @@ static void __net_exit default_device_exit(struct net *net) static void __net_exit default_device_exit_batch(struct list_head *net_list) { /* At exit all network devices most be removed from a network - * namespace. Do this in the reverse order of registeration. + * namespace. Do this in the reverse order of registration. * Do this across as many network namespaces as possible to * improve batching efficiency. */ diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 4c409b46aa35..9b73e0b03e34 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -1112,7 +1112,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err) /* * This processes a device up event. We only start up * the loopback device & ethernet devices with correct - * MAC addreses automatically. Others must be started + * MAC addresses automatically. Others must be started * specifically. * * FIXME: How should we configure the loopback address ? If we could dispense diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 05b1ecf36763..e96152207164 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1336,7 +1336,7 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp, return 0; } -/* Intialize TSO state of a skb. +/* Initialize TSO state of a skb. * This must be invoked the first time we consider transmitting * SKB onto the wire. */ diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 9df80114b47b..c06f1503aa8b 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -946,7 +946,7 @@ static void randomize_choice_values(struct symbol *csym) int cnt, def; /* - * If choice is mod then we may have more items slected + * If choice is mod then we may have more items selected * and if no then no-one. * In both cases stop. */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 33122ca04e7c..6619ed8843f9 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1614,7 +1614,7 @@ static void section_rel(const char *modname, struct elf_info *elf, * A module includes a number of sections that are discarded * either when loaded or when used as built-in. * For loaded modules all functions marked __init and all data - * marked __initdata will be discarded when the module has been intialized. + * marked __initdata will be discarded when the module has been initialized. * Likewise for modules used built-in the sections marked __exit * are discarded because __exit marked function are supposed to be called * only when a module is unloaded which never happens for built-in modules. diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index 734a6d35112c..e00c3c7c96be 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -27,7 +27,7 @@ * The format used for transition tables is based on the GNU flex table * file format (--tables-file option; see Table File Format in the flex * info pages and the flex sources for documentation). The magic number - * used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because + * used in the header is 0x1B5E783D instead of 0xF13C57B1 though, because * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used * slightly differently (see the apparmor-parser package). */ diff --git a/sound/core/init.c b/sound/core/init.c index 57b792e2439a..3e65da21a08c 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -642,7 +642,7 @@ static struct device_attribute card_number_attrs = * external accesses. Thus, you should call this function at the end * of the initialization of the card. * - * Returns zero otherwise a negative error code if the registrain failed. + * Returns zero otherwise a negative error code if the registration failed. */ int snd_card_register(struct snd_card *card) { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8bc7cb3db330..8e022fc70f55 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -985,7 +985,7 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) if (push) snd_pcm_update_hw_ptr(substream); /* The jiffies check in snd_pcm_update_hw_ptr*() is done by - * a delta betwen the current jiffies, this gives a large enough + * a delta between the current jiffies, this gives a large enough * delta, effectively to skip the check once. */ substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000; diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 265abcce9dba..9b915e27b5bd 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -264,7 +264,7 @@ static int __devinit snd_opl3sa2_detect(struct snd_card *card) snd_printd("OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1); return -ENODEV; } - /* try if the MIC register is accesible */ + /* try if the MIC register is accessible */ tmp = snd_opl3sa2_read(chip, OPL3SA2_MIC); snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x8a); if (((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC)) & 0x9f) != 0x8a) { diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index f19c11077255..fc53b9bca26d 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -188,7 +188,7 @@ #define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */ /* PTR[5:0], Default: 0x0 */ #define PLAYBACK_UNKNOWN3 0x03 /* Not used ?? */ -#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */ +#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */ /* DMA[31:0], Default: 0x0 */ #define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */ /* SIZE[31:16], Default: 0x0 */ diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index df47f738098d..0c701e4ec8a5 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -114,7 +114,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard."); */ #define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */ #define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */ -#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */ +#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */ #define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size */ #define PLAYBACK_POINTER 0x06 /* Playback period pointer. Sample currently in DAC */ #define PLAYBACK_UNKNOWN1 0x07 diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h index 153214940336..00f4817533b1 100644 --- a/sound/pci/emu10k1/p16v.h +++ b/sound/pci/emu10k1/p16v.h @@ -96,7 +96,7 @@ #define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */ #define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */ #define PLAYBACK_UNKNOWN3 0x03 /* Not used */ -#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */ +#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */ #define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */ #define PLAYBACK_POINTER 0x06 /* Playback period pointer. Used with PLAYBACK_LIST_PTR to determine buffer position currently in DAC */ #define PLAYBACK_FIFO_END_ADDRESS 0x07 /* Playback FIFO end address */ diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 23a58f0d6cb9..7c17f45d876d 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -220,7 +220,7 @@ MODULE_PARM_DESC(joystick, "Enable joystick."); #define RINGB_EN_2CODEC 0x0020 #define RINGB_SING_BIT_DUAL 0x0040 -/* ****Port Adresses**** */ +/* ****Port Addresses**** */ /* Write & Read */ #define ESM_INDEX 0x02 diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 0c98ef9156d8..f5eadfc0672a 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -487,7 +487,7 @@ struct hdspm { struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; - /* full mixer accessable over mixer ioctl or hwdep-device */ + /* full mixer accessible over mixer ioctl or hwdep-device */ struct hdspm_mixer *mixer; }; @@ -550,7 +550,7 @@ static inline int HDSPM_bit2freq(int n) return bit2freq_tab[n]; } -/* Write/read to/from HDSPM with Adresses in Bytes +/* Write/read to/from HDSPM with Addresses in Bytes not words but only 32Bit writes are allowed */ static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg, @@ -2908,7 +2908,7 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm /* Channel playback mixer as default control Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, - thats too * big for any alsamixer they are accesible via special + thats too * big for any alsamixer they are accessible via special IOCTL on hwdep and the mixer 2dimensional mixer control */ diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index bc22ee93a75d..43316a70be05 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1953,7 +1953,7 @@ static int max98088_probe(struct snd_soc_codec *codec) return ret; } - /* initalize private data */ + /* initialize private data */ max98088->sysclk = (unsigned)-1; max98088->eq_textcnt = 0; diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c index f31d22ad7c88..11c88b13dd2e 100644 --- a/sound/soc/s3c24xx/smdk_spdif.c +++ b/sound/soc/s3c24xx/smdk_spdif.c @@ -61,7 +61,7 @@ static int set_audio_clock_heirachy(struct platform_device *pdev) goto out3; } - /* Set audio clock heirachy for S/PDIF */ + /* Set audio clock hierarchy for S/PDIF */ clk_set_parent(mout_epll, fout_epll); clk_set_parent(sclk_audio0, mout_epll); clk_set_parent(sclk_spdif, sclk_audio0); @@ -79,7 +79,7 @@ out1: /* We should haved to set clock directly on this part because of clock * scheme of Samsudng SoCs did not support to set rates from abstrct - * clock of it's heirachy. + * clock of it's hierarchy. */ static int set_audio_clock_rate(unsigned long epll_rate, unsigned long audio_rate) @@ -197,7 +197,7 @@ static int __init smdk_init(void) if (ret) goto err1; - /* Set audio clock heirachy manually */ + /* Set audio clock hierarchy manually */ ret = set_audio_clock_heirachy(smdk_snd_spdif_device); if (ret) goto err1; -- cgit v1.2.3 From 328fc1325f144027f4a8269b11e9f8dcf1edcb97 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Nov 2010 10:00:34 +0000 Subject: Revert "drm/i915: add MMIO debug output" We can use mmiotrace instead of our own debug printks. This reverts commit be282fd48e7492812402a22d73a348c44bf95b63. Conflicts: drivers/gpu/drm/i915/i915_drv.h --- drivers/gpu/drm/i915/i915_drv.h | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a0063f82fa33..81ee20c2d24e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -287,9 +287,6 @@ typedef struct drm_i915_private { int front_offset; int current_page; int page_flipping; -#define I915_DEBUG_READ (1<<0) -#define I915_DEBUG_WRITE (1<<1) - unsigned long debug_flags; wait_queue_head_t irq_queue; atomic_t irq_received; @@ -1172,26 +1169,8 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) -static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg) -{ - u32 val; - - val = readl(dev_priv->regs + reg); - if (dev_priv->debug_flags & I915_DEBUG_READ) - printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg); - return val; -} - -static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, - u32 val) -{ - writel(val, dev_priv->regs + reg); - if (dev_priv->debug_flags & I915_DEBUG_WRITE) - printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg); -} - -#define I915_READ(reg) i915_read(dev_priv, (reg)) -#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val)) +#define I915_READ(reg) readl(dev_priv->regs + (reg)) +#define I915_WRITE(reg, val) writel(val, dev_priv->regs + (reg)) #define I915_READ16(reg) readw(dev_priv->regs + (reg)) #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) #define I915_READ8(reg) readb(dev_priv->regs + (reg)) @@ -1201,11 +1180,6 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, #define POSTING_READ(reg) (void)I915_READ(reg) #define POSTING_READ16(reg) (void)I915_READ16(reg) -#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \ - I915_DEBUG_WRITE) -#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \ - I915_DEBUG_WRITE)) - #define BEGIN_LP_RING(n) \ intel_ring_begin(&dev_priv->render_ring, (n)) -- cgit v1.2.3 From d110852513148a7ec44fad4e036455aeb816d713 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 2 Nov 2010 17:30:46 +0800 Subject: agp/intel: fix cache control for sandybridge This is broken from 97ef1bdd0bc75bce7b2058e9c432b6c277dcf4d3. Let's set the correct bit for LLC+MLC and LLC only. Signed-off-by: Zhenyu Wang Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index f800e9cfc368..c51efe6f2c7f 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1291,11 +1291,11 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry, if (type_mask == AGP_USER_UNCACHED_MEMORY) pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { - pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; + pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; if (gfdt) pte_flags |= GEN6_PTE_GFDT; } else { /* set 'normal'/'cached' to LLC by default */ - pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; + pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; if (gfdt) pte_flags |= GEN6_PTE_GFDT; } -- cgit v1.2.3 From 897ef192514a6b0fc10a0ce3fe7e7aa0de09bc52 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 2 Nov 2010 17:30:47 +0800 Subject: agp/intel: restore cache behavior on sandybridge This restores cache behavior for default AGP_USER_MEMORY as uncached, and leave default AGP_USER_CACHED_MEMORY as LLC only. I've seen different cache behavior on one sandybridge desktop CPU vs. another mobile CPU. Until we figure out how to detect the real cache config, restore back to the original behavior now. Signed-off-by: Zhenyu Wang Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index c51efe6f2c7f..fc1637c32cb1 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1288,7 +1288,7 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry, unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; u32 pte_flags; - if (type_mask == AGP_USER_UNCACHED_MEMORY) + if (type_mask == AGP_USER_MEMORY) pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; -- cgit v1.2.3 From 8d19215be8254f4f75e9c5a0d28345947b0382db Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Tue, 2 Nov 2010 16:31:01 +0800 Subject: drm/i915: SNB BLT workaround On some stepping of SNB cpu, the first command to be parsed in BLT command streamer should be MI_BATCHBUFFER_START otherwise the GPU may hang. Signed-off-by: Zou Nan hai [ickle: rebased for -next] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 123 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 + 2 files changed, 123 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 390aa21edbe4..a0702b6fb631 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -658,6 +658,9 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) drm_gem_object_unreference(ring->gem_object); ring->gem_object = NULL; + if (ring->cleanup) + ring->cleanup(ring); + cleanup_status_page(ring); } @@ -877,19 +880,133 @@ blt_ring_put_user_irq(struct intel_ring_buffer *ring) /* do nothing */ } + +/* Workaround for some stepping of SNB, + * each time when BLT engine ring tail moved, + * the first command in the ring to be parsed + * should be MI_BATCH_BUFFER_START + */ +#define NEED_BLT_WORKAROUND(dev) \ + (IS_GEN6(dev) && (dev->pdev->revision < 8)) + +static inline struct drm_i915_gem_object * +to_blt_workaround(struct intel_ring_buffer *ring) +{ + return ring->private; +} + +static int blt_ring_init(struct intel_ring_buffer *ring) +{ + if (NEED_BLT_WORKAROUND(ring->dev)) { + struct drm_i915_gem_object *obj; + u32 __iomem *ptr; + int ret; + + obj = to_intel_bo(i915_gem_alloc_object(ring->dev, 4096)); + if (obj == NULL) + return -ENOMEM; + + ret = i915_gem_object_pin(&obj->base, 4096, true, false); + if (ret) { + drm_gem_object_unreference(&obj->base); + return ret; + } + + ptr = kmap(obj->pages[0]); + iowrite32(MI_BATCH_BUFFER_END, ptr); + iowrite32(MI_NOOP, ptr+1); + kunmap(obj->pages[0]); + + ret = i915_gem_object_set_to_gtt_domain(&obj->base, false); + if (ret) { + i915_gem_object_unpin(&obj->base); + drm_gem_object_unreference(&obj->base); + return ret; + } + + ring->private = obj; + } + + return init_ring_common(ring); +} + +static int blt_ring_begin(struct intel_ring_buffer *ring, + int num_dwords) +{ + if (ring->private) { + int ret = intel_ring_begin(ring, num_dwords+2); + if (ret) + return ret; + + intel_ring_emit(ring, MI_BATCH_BUFFER_START); + intel_ring_emit(ring, to_blt_workaround(ring)->gtt_offset); + + return 0; + } else + return intel_ring_begin(ring, 4); +} + +static void blt_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + if (blt_ring_begin(ring, 4) == 0) { + intel_ring_emit(ring, MI_FLUSH_DW); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + } +} + +static int +blt_ring_add_request(struct intel_ring_buffer *ring, + u32 *result) +{ + u32 seqno; + int ret; + + ret = blt_ring_begin(ring, 4); + if (ret) + return ret; + + seqno = i915_gem_get_seqno(ring->dev); + + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); + + DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); + *result = seqno; + return 0; +} + +static void blt_ring_cleanup(struct intel_ring_buffer *ring) +{ + if (!ring->private) + return; + + i915_gem_object_unpin(ring->private); + drm_gem_object_unreference(ring->private); + ring->private = NULL; +} + static const struct intel_ring_buffer gen6_blt_ring = { .name = "blt ring", .id = RING_BLT, .mmio_base = BLT_RING_BASE, .size = 32 * PAGE_SIZE, - .init = init_ring_common, + .init = blt_ring_init, .write_tail = ring_write_tail, - .flush = gen6_ring_flush, - .add_request = ring_add_request, + .flush = blt_ring_flush, + .add_request = blt_ring_add_request, .get_seqno = ring_status_page_get_seqno, .user_irq_get = blt_ring_get_user_irq, .user_irq_put = blt_ring_put_user_irq, .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, + .cleanup = blt_ring_cleanup, }; int intel_init_render_ring_buffer(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index acd23374fe89..68043f1a186e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -55,6 +55,7 @@ struct intel_ring_buffer { struct drm_i915_gem_execbuffer2 *exec, struct drm_clip_rect *cliprects, uint64_t exec_offset); + void (*cleanup)(struct intel_ring_buffer *ring); /** * List of objects currently involved in rendering from the @@ -90,6 +91,8 @@ struct intel_ring_buffer { wait_queue_head_t irq_queue; drm_local_map_t map; + + void *private; }; static inline u32 -- cgit v1.2.3 From 27153f72d04bcd83b3a66e219418a21d6269553b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Nov 2010 11:17:23 +0000 Subject: drm/i915: Drop the iomem accessors when writing to the kmapped blt batch I presumed that we would be writing to the batch through the GTT having bound it, so I converted it to use iomem. Even later as I spotted that we didn't even move the batch to the GTT (now an issue since we default to uncached memory on SNB) I still didn't realise that using iomem for kmapped memory was incorrect. Fix it. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a0702b6fb631..85071570e1f9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -899,7 +899,7 @@ static int blt_ring_init(struct intel_ring_buffer *ring) { if (NEED_BLT_WORKAROUND(ring->dev)) { struct drm_i915_gem_object *obj; - u32 __iomem *ptr; + u32 *ptr; int ret; obj = to_intel_bo(i915_gem_alloc_object(ring->dev, 4096)); @@ -913,8 +913,8 @@ static int blt_ring_init(struct intel_ring_buffer *ring) } ptr = kmap(obj->pages[0]); - iowrite32(MI_BATCH_BUFFER_END, ptr); - iowrite32(MI_NOOP, ptr+1); + *ptr++ = MI_BATCH_BUFFER_END; + *ptr++ = MI_NOOP; kunmap(obj->pages[0]); ret = i915_gem_object_set_to_gtt_domain(&obj->base, false); -- cgit v1.2.3 From de7fd0fc989727d657d40f6ddf2fb99639bd6262 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Wed, 27 Oct 2010 23:11:10 +0000 Subject: Kconfig: typo: boad -> board Signed-off-by: Michael Witten Signed-off-by: Jiri Kosina --- drivers/input/serio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 6256233d2bfb..44a351cdc641 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -230,7 +230,7 @@ config SERIO_PS2MULT tristate "TQC PS/2 multiplexer" help Say Y here if you have the PS/2 line multiplexer like the one - present on TQC boads. + present on TQC boards. To compile this driver as a module, choose M here: the module will be called ps2mult. -- cgit v1.2.3 From 085ce2643713830cf772c12c1a16da9d0ba83f36 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 3 Nov 2010 09:27:53 +0000 Subject: drm/i915: Ensure that if we ever try to pin+fence it is mappable. When merging Daniel's full-gtt patches I had a set of tweaks which I thought I had undone. I was half right... Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=31286 Reported-by: jinjin.wang@intel.com Reported-by: Alexey Fisher Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 1 + drivers/gpu/drm/i915/intel_display.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5bd86033a88e..12dae003c011 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4151,6 +4151,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, int ret; BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); + BUG_ON(need_fence && !mappable); WARN_ON(i915_verify_lists(dev)); if (obj_priv->gtt_space != NULL) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 33c178c8d6dd..a33d9a2c7429 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1462,7 +1462,8 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, } ret = i915_gem_object_pin(obj, alignment, - !pipelined, obj_priv->tiling_mode); + !pipelined || obj_priv->tiling_mode, + obj_priv->tiling_mode); if (ret) return ret; -- cgit v1.2.3 From 8d814961234fda66f01bb0505f166537913d745c Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 16 Oct 2010 15:19:24 +0200 Subject: drivers: scsi: fix typo in comment Signed-off-by: Andrea Gelmini Signed-off-by: Jiri Kosina --- drivers/scsi/aic94xx/aic94xx_scb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index c43698b1cb64..29593275201a 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -867,7 +867,7 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, * resources they have with this SCB, and then call this one at the * end of their timeout function. To do this, one should initialize * the ascb->timer.{function, data, expires} prior to calling the post - * funcion. The timer is started by the post function. + * function. The timer is started by the post function. */ void asd_ascb_timedout(unsigned long data) { -- cgit v1.2.3 From 99b9f758bbc904f22faffcf4d83205f4a5e7bc0c Mon Sep 17 00:00:00 2001 From: "Edgar (gimli) Hucek" Date: Wed, 3 Nov 2010 10:36:18 -0400 Subject: HID: add MacBookAir 3,1 and 3,2 support This patch add support for the MacBookAir3,1 and MacBookAir3,2 to the hid driver. Signed-off-by: Edgar (gimli) Hucek Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- drivers/hid/hid-core.c | 12 ++++++++++++ drivers/hid/hid-ids.h | 6 ++++++ 3 files changed, 60 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index eaeca564a8d3..6c52203cdbdf 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -59,6 +59,27 @@ struct apple_key_translation { u8 flags; }; +static const struct apple_key_translation macbookair_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_EJECTCD, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + static const struct apple_key_translation apple_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -157,10 +178,15 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, if (fnmode) { int do_translate; - trans = apple_find_translation((hid->product < 0x21d || - hid->product >= 0x300) ? - powerbook_fn_keys : apple_fn_keys, - usage->code); + if(hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) { + trans = apple_find_translation(macbookair_fn_keys, usage->code); + } else if (hid->product < 0x21d || hid->product >= 0x300) { + trans = apple_find_translation(powerbook_fn_keys, usage->code); + } else { + trans = apple_find_translation(apple_fn_keys, usage->code); + } + if (trans) { if (test_bit(usage->code, asc->pressed_fn)) do_translate = 1; @@ -440,6 +466,18 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b3393e17b375..53ac909e2fff 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1276,6 +1276,12 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, @@ -1757,6 +1763,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 68114dbcd895..104b9f9a4c0b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -97,6 +97,12 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b -- cgit v1.2.3 From a4bc6926d05b60bf70aab2db2c6715e15118cbdc Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 3 Nov 2010 10:42:02 -0400 Subject: HID: make translation table selection more clear Reshuffle the code a little bit so that the translation table selection is more obvious and there is only one place performing the actual translation using the selected table. Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 6c52203cdbdf..8aa71750a23c 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -167,7 +167,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, struct hid_usage *usage, __s32 value) { struct apple_sc *asc = hid_get_drvdata(hid); - const struct apple_key_translation *trans; + const struct apple_key_translation *trans, *table; if (usage->code == KEY_FN) { asc->fn_on = !!value; @@ -178,14 +178,15 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, if (fnmode) { int do_translate; - if(hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && - hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) { - trans = apple_find_translation(macbookair_fn_keys, usage->code); - } else if (hid->product < 0x21d || hid->product >= 0x300) { - trans = apple_find_translation(powerbook_fn_keys, usage->code); - } else { - trans = apple_find_translation(apple_fn_keys, usage->code); - } + if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) + table = macbookair_fn_keys; + else if (hid->product < 0x21d || hid->product >= 0x300) + table = powerbook_fn_keys; + else + table = apple_fn_keys; + + trans = apple_find_translation (table, usage->code); if (trans) { if (test_bit(usage->code, asc->pressed_fn)) -- cgit v1.2.3 From 818f2a3cc34b0673dccd4188ce4a1862d9d90127 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Nov 2010 17:04:29 +0100 Subject: drm/i915: revert pageflip/mappable related abi breakage In a00b10c360b35d6431a "Only enforce fence limits inside the GTT" Chris Wilson implemented an optimization to only pin framebuffers as mappable for crtc_set_base (but not for pageflips). This breaks the abi, eg: A double buffering mesa client might leave the last framebuffer in unmappable space on close. A subsequent glReadPix by a frontbuffer rendering client then goes boom. My pretty anal mappable/unmappable consistency checking detected this, see https://bugs.freedesktop.org/show_bug.cgi?id=31286 Chris Wilson tried to fix this in 085ce2643713830cf772c by pinning tiled framebuffers into mappable space. This a) renders the original optimization of not forcing framebuffers for pageflipping clients into mappable pointless because all our scanout buffers are tiled by default. b) doesn't solve the problem for untiled framebuffers. So kill this. Emperically it's no gain anyway because framebuffers are being reused by the ddx and hence there's no chance for them to get constanly bounced between mappable and unmappable. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f1e4eca44866..a2cd579eb9b2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1461,8 +1461,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, BUG(); } - ret = i915_gem_object_pin(obj, alignment, - !pipelined || obj_priv->tiling_mode, + ret = i915_gem_object_pin(obj, alignment, true, obj_priv->tiling_mode); if (ret) return ret; -- cgit v1.2.3 From 75e9e9158f38e5cb21eff23b30bafa6f32e0a606 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Nov 2010 17:11:09 +0100 Subject: drm/i915: kill mappable/fenceable disdinction a00b10c360b35d6431a "Only enforce fence limits inside the GTT" also added a fenceable/mappable disdinction when binding/pinning buffers. This only complicates the code with no pratical gain: - In execbuffer this matters on for g33/pineview, as this is the only chip that needs fences and has an unmappable gtt area. But fences are only possible in the mappable part of the gtt, so need_fence implies need_mappable. And need_mappable is only set independantly with relocations which implies (for sane userspace) that the buffer is untiled. - The overlay code is only really used on i8xx, which doesn't have unmappable gtt. And it doesn't support tiled buffers, currently. - For all other buffers it's a bug to pass in a tiled bo. In short, this disdinction doesn't have any practical gain. I've also reverted mapping the overlay and context pages as possibly unmappable. It's not worth being overtly clever here, all the big gains from unmappable are for execbuf bos. Also add a comment for a clever optimization that confused me while reading the original patch by Chris Wilson. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 10 ++-- drivers/gpu/drm/i915/i915_gem.c | 84 ++++++++++++++++----------------- drivers/gpu/drm/i915/intel_display.c | 7 ++- drivers/gpu/drm/i915/intel_overlay.c | 4 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +-- 5 files changed, 56 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 48d0aefec1f8..621234265454 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -752,8 +752,6 @@ struct drm_i915_gem_object { * Advice: are the backing pages purgeable? */ unsigned int madv : 2; - unsigned int fenceable : 1; - unsigned int mappable : 1; /** * Current tiling mode for the object. @@ -772,6 +770,12 @@ struct drm_i915_gem_object { unsigned int pin_count : 4; #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf + /** + * Is the object at the current location in the gtt mappable and + * fenceable? Used to avoid costly recalculations. + */ + unsigned int map_and_fenceable : 1; + /** * Whether the current gtt mapping needs to be mappable (and isn't just * mappable by accident). Track pin and fault separate for a more @@ -1013,7 +1017,7 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, - bool mappable, bool need_fence); + bool map_and_fenceable); void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_release_mmap(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 12dae003c011..47c665eeaf17 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -59,8 +59,7 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, bool interruptible); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment, - bool mappable, - bool need_fence); + bool map_and_fenceable); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -1074,7 +1073,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, else if (obj_priv->tiling_mode == I915_TILING_NONE && obj_priv->gtt_space && obj->write_domain != I915_GEM_DOMAIN_CPU) { - ret = i915_gem_object_pin(obj, 0, true, false); + ret = i915_gem_object_pin(obj, 0, true); if (ret) goto out; @@ -1300,8 +1299,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable); if (obj_priv->gtt_space) { - if (!obj_priv->mappable || - (obj_priv->tiling_mode && !obj_priv->fenceable)) { + if (!obj_priv->map_and_fenceable) { ret = i915_gem_object_unbind(obj); if (ret) goto unlock; @@ -1309,8 +1307,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } if (!obj_priv->gtt_space) { - ret = i915_gem_object_bind_to_gtt(obj, 0, - true, obj_priv->tiling_mode); + ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto unlock; } @@ -2273,8 +2270,8 @@ i915_gem_object_unbind(struct drm_gem_object *obj) i915_gem_info_remove_gtt(dev_priv, obj_priv); list_del_init(&obj_priv->mm_list); - obj_priv->fenceable = true; - obj_priv->mappable = true; + /* Avoid an unnecessary call to unbind on rebind. */ + obj_priv->map_and_fenceable = true; drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; @@ -2383,7 +2380,7 @@ static void i915_write_fence_reg(struct drm_gem_object *obj) if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || (obj_priv->gtt_offset & (size - 1))) { WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n", - __func__, obj_priv->gtt_offset, obj_priv->fenceable, size, + __func__, obj_priv->gtt_offset, obj_priv->map_and_fenceable, size, obj_priv->gtt_space->start, obj_priv->gtt_space->size); return; } @@ -2687,8 +2684,7 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment, - bool mappable, - bool need_fence) + bool map_and_fenceable) { struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2696,6 +2692,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, struct drm_mm_node *free_space; gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; u32 size, fence_size, fence_alignment; + bool mappable, fenceable; int ret; if (obj_priv->madv != I915_MADV_WILLNEED) { @@ -2707,25 +2704,25 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, fence_alignment = i915_gem_get_gtt_alignment(obj_priv); if (alignment == 0) - alignment = need_fence ? fence_alignment : 4096; - if (need_fence && alignment & (fence_alignment - 1)) { + alignment = map_and_fenceable ? fence_alignment : 4096; + if (map_and_fenceable && alignment & (fence_alignment - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); return -EINVAL; } - size = need_fence ? fence_size : obj->size; + size = map_and_fenceable ? fence_size : obj->size; /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ if (obj->size > - (mappable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { + (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } search_free: - if (mappable) + if (map_and_fenceable) free_space = drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, size, alignment, 0, @@ -2736,7 +2733,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, size, alignment, 0); if (free_space != NULL) { - if (mappable) + if (map_and_fenceable) obj_priv->gtt_space = drm_mm_get_block_range_generic(free_space, size, alignment, 0, @@ -2750,7 +2747,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ - ret = i915_gem_evict_something(dev, size, alignment, mappable); + ret = i915_gem_evict_something(dev, size, alignment, + map_and_fenceable); if (ret) return ret; @@ -2765,7 +2763,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ ret = i915_gem_evict_something(dev, size, - alignment, mappable); + alignment, + map_and_fenceable); if (ret) { /* now try to shrink everyone else */ if (gfpmask) { @@ -2796,7 +2795,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, obj_priv->gtt_space = NULL; ret = i915_gem_evict_something(dev, size, - alignment, mappable); + alignment, map_and_fenceable); if (ret) return ret; @@ -2816,15 +2815,17 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS); BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); - trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, mappable); + trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, map_and_fenceable); - obj_priv->fenceable = + fenceable = obj_priv->gtt_space->size == fence_size && (obj_priv->gtt_space->start & (fence_alignment -1)) == 0; - obj_priv->mappable = + mappable = obj_priv->gtt_offset + obj->size <= dev_priv->mm.gtt_mappable_end; + obj_priv->map_and_fenceable = mappable && fenceable; + return 0; } @@ -3538,8 +3539,7 @@ i915_gem_execbuffer_pin(struct drm_device *dev, entry->relocation_count ? true : need_fence; /* Check fence reg constraints and rebind if necessary */ - if ((need_fence && !obj->fenceable) || - (need_mappable && !obj->mappable)) { + if (need_mappable && !obj->map_and_fenceable) { ret = i915_gem_object_unbind(&obj->base); if (ret) break; @@ -3547,8 +3547,7 @@ i915_gem_execbuffer_pin(struct drm_device *dev, ret = i915_gem_object_pin(&obj->base, entry->alignment, - need_mappable, - need_fence); + need_mappable); if (ret) break; @@ -4143,7 +4142,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, - bool mappable, bool need_fence) + bool map_and_fenceable) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4151,19 +4150,19 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, int ret; BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); - BUG_ON(need_fence && !mappable); + BUG_ON(map_and_fenceable && !map_and_fenceable); WARN_ON(i915_verify_lists(dev)); if (obj_priv->gtt_space != NULL) { if ((alignment && obj_priv->gtt_offset & (alignment - 1)) || - (need_fence && !obj_priv->fenceable) || - (mappable && !obj_priv->mappable)) { + (map_and_fenceable && !obj_priv->map_and_fenceable)) { WARN(obj_priv->pin_count, "bo is already pinned with incorrect alignment:" - " offset=%x, req.alignment=%x, need_fence=%d, fenceable=%d, mappable=%d, cpu_accessible=%d\n", + " offset=%x, req.alignment=%x, req.map_and_fenceable=%d," + " obj->map_and_fenceable=%d\n", obj_priv->gtt_offset, alignment, - need_fence, obj_priv->fenceable, - mappable, obj_priv->mappable); + map_and_fenceable, + obj_priv->map_and_fenceable); ret = i915_gem_object_unbind(obj); if (ret) return ret; @@ -4172,18 +4171,18 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, if (obj_priv->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment, - mappable, need_fence); + map_and_fenceable); if (ret) return ret; } if (obj_priv->pin_count++ == 0) { - i915_gem_info_add_pin(dev_priv, obj_priv, mappable); + i915_gem_info_add_pin(dev_priv, obj_priv, map_and_fenceable); if (!obj_priv->active) list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list); } - BUG_ON(!obj_priv->pin_mappable && mappable); + BUG_ON(!obj_priv->pin_mappable && map_and_fenceable); WARN_ON(i915_verify_lists(dev)); return 0; @@ -4245,8 +4244,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, obj_priv->user_pin_count++; obj_priv->pin_filp = file_priv; if (obj_priv->user_pin_count == 1) { - ret = i915_gem_object_pin(obj, args->alignment, - true, obj_priv->tiling_mode); + ret = i915_gem_object_pin(obj, args->alignment, true); if (ret) goto out; } @@ -4439,8 +4437,8 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->gpu_write_list); obj->madv = I915_MADV_WILLNEED; - obj->fenceable = true; - obj->mappable = true; + /* Avoid an unnecessary call to unbind on the first bind. */ + obj->map_and_fenceable = true; return &obj->base; } @@ -4560,7 +4558,7 @@ i915_gem_init_pipe_control(struct drm_device *dev) obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - ret = i915_gem_object_pin(obj, 4096, true, false); + ret = i915_gem_object_pin(obj, 4096, true); if (ret) goto err_unref; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a2cd579eb9b2..77b34942dc91 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1461,8 +1461,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, BUG(); } - ret = i915_gem_object_pin(obj, alignment, true, - obj_priv->tiling_mode); + ret = i915_gem_object_pin(obj, alignment, true); if (ret) return ret; @@ -4367,7 +4366,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { - ret = i915_gem_object_pin(bo, PAGE_SIZE, true, false); + ret = i915_gem_object_pin(bo, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin cursor bo\n"); goto fail_locked; @@ -5531,7 +5530,7 @@ intel_alloc_context_page(struct drm_device *dev) } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(ctx, 4096, false, false); + ret = i915_gem_object_pin(ctx, 4096, true); if (ret) { DRM_ERROR("failed to pin power context: %d\n", ret); goto err_unref; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 659f8349a15c..ec8ffaccbbdb 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -781,7 +781,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) return ret; - ret = i915_gem_object_pin(new_bo, PAGE_SIZE, false, false); + ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true); if (ret != 0) return ret; @@ -1425,7 +1425,7 @@ void intel_setup_overlay(struct drm_device *dev) } overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; } else { - ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true, false); + ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin overlay register bo\n"); goto out_free_bo; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 85071570e1f9..78a5061a58f6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -547,7 +547,7 @@ static int init_status_page(struct intel_ring_buffer *ring) obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - ret = i915_gem_object_pin(obj, 4096, true, false); + ret = i915_gem_object_pin(obj, 4096, true); if (ret != 0) { goto err_unref; } @@ -602,7 +602,7 @@ int intel_init_ring_buffer(struct drm_device *dev, ring->gem_object = obj; - ret = i915_gem_object_pin(obj, PAGE_SIZE, true, false); + ret = i915_gem_object_pin(obj, PAGE_SIZE, true); if (ret) goto err_unref; @@ -906,7 +906,7 @@ static int blt_ring_init(struct intel_ring_buffer *ring) if (obj == NULL) return -ENOMEM; - ret = i915_gem_object_pin(&obj->base, 4096, true, false); + ret = i915_gem_object_pin(&obj->base, 4096, true); if (ret) { drm_gem_object_unreference(&obj->base); return ret; -- cgit v1.2.3 From 98e2d5a802518694465368406c5f1b020f4df998 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Thu, 4 Nov 2010 22:37:15 -0400 Subject: solo6x10: Spaces to tabs Signed-off-by: Ben Collins --- drivers/staging/solo6x10/solo6010-enc.c | 4 ++-- drivers/staging/solo6x10/solo6010-g723.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/solo6010-enc.c b/drivers/staging/solo6x10/solo6010-enc.c index a6cf0a8a3f20..42314a1e3250 100644 --- a/drivers/staging/solo6x10/solo6010-enc.c +++ b/drivers/staging/solo6x10/solo6010-enc.c @@ -145,8 +145,8 @@ int solo_osd_print(struct solo_enc_dev *solo_enc) solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR(solo_dev) + (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE); - reg |= (1 << solo_enc->ch); - solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); + reg |= (1 << solo_enc->ch); + solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); kfree(buf); diff --git a/drivers/staging/solo6x10/solo6010-g723.c b/drivers/staging/solo6x10/solo6010-g723.c index 82fbcb845878..63a1b5b64b56 100644 --- a/drivers/staging/solo6x10/solo6010-g723.c +++ b/drivers/staging/solo6x10/solo6010-g723.c @@ -158,7 +158,7 @@ static int snd_solo_pcm_close(struct snd_pcm_substream *ss) snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; kfree(solo_pcm); - return 0; + return 0; } static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) @@ -197,7 +197,7 @@ static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss) { - return 0; + return 0; } static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) @@ -271,7 +271,7 @@ static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol, value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch); - return 0; + return 0; } static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, @@ -279,15 +279,15 @@ static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, { struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol); u8 ch = value->id.numid - 1; - u8 old_val; + u8 old_val; - old_val = tw28_get_audio_gain(solo_dev, ch); + old_val = tw28_get_audio_gain(solo_dev, ch); if (old_val == value->value.integer.value[0]) return 0; tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]); - return 1; + return 1; } static struct snd_kcontrol_new snd_solo_capture_volume = { @@ -368,7 +368,7 @@ int solo_g723_init(struct solo6010_dev *solo_dev) strcpy(card->mixername, "SOLO-6010"); kctl = snd_solo_capture_volume; kctl.count = solo_dev->nr_chans; - ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); + ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); if (ret < 0) return ret; -- cgit v1.2.3 From 1194cf4308d786c69b808ec3aa8704d01d130e94 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Thu, 4 Nov 2010 22:42:25 -0400 Subject: solo6x10: Update TODO Signed-off-by: Ben Collins --- drivers/staging/solo6x10/TODO | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/solo6x10/TODO index e6a2ee226743..82439d38ba74 100644 --- a/drivers/staging/solo6x10/TODO +++ b/drivers/staging/solo6x10/TODO @@ -1,7 +1,5 @@ TODO (staging => main): - * checkpatch.pl (haven't run it yet) - * Lindent (should be clean, but check) * Motion detection flags need to be moved to v4l2 * Some private CIDs need to be moved to v4l2 @@ -17,12 +15,11 @@ TODO (general): * implement a CID control for motion areas/thresholds * implement CID controls for mozaic areas * allow for higher level of interval (for < 1 fps) + * Get proper descriptor mode working in p2m * sound: - implement playback via external sound jack - implement loopback of external sound jack with incoming audio? - implement pause/resume - - check into jacking sound from tx28xx chips directly (to avoid - g.723/8khz limitations) Plase send patches to Greg Kroah-Hartman and Cc Ben Collins -- cgit v1.2.3 From f62de9be26ce2144ad0dcf292727e4f58577d401 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Thu, 4 Nov 2010 22:51:17 -0400 Subject: solo6x10: Conversion to videobuf-dma-sg (from dma-cont) Full rewrite of the P2M DMA Engine to support scatter gather and take advantage of some of the features of the hardware. This includes using repeat DMA operations and line-mode transfers (for copying OSG and video display buffers). What isn't working: For some reason, descriptor mode is not working. I've implemented a psuedo version (still has one-interrupt per DMA operation), but we would get huge improvements if we could hand off a ring of descriptors to the P2M and get back one interrupt when it was done with all of them. Documentation is very vague on this, and even the ODM example code half attempts to get it right, but comments it out of the driver because it just doesn't work *sigh* Converts all v4l2 to dma-sg. So long slow dma-contiguous, but hello more interrupts :( Signed-off-by: Ben Collins --- drivers/staging/solo6x10/Kconfig | 2 +- drivers/staging/solo6x10/solo6010-core.c | 12 +- drivers/staging/solo6x10/solo6010-disp.c | 2 +- drivers/staging/solo6x10/solo6010-gpio.c | 4 +- drivers/staging/solo6x10/solo6010-i2c.c | 8 +- drivers/staging/solo6x10/solo6010-p2m.c | 148 +++++++++-- drivers/staging/solo6x10/solo6010-v4l2-enc.c | 352 +++++++++++++++++++-------- drivers/staging/solo6x10/solo6010-v4l2.c | 182 +++++++++++--- drivers/staging/solo6x10/solo6010.h | 38 ++- 9 files changed, 554 insertions(+), 194 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig index d96398c701f8..de60ac841b7e 100644 --- a/drivers/staging/solo6x10/Kconfig +++ b/drivers/staging/solo6x10/Kconfig @@ -1,7 +1,7 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF_DMA_SG ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec codec cards. diff --git a/drivers/staging/solo6x10/solo6010-core.c b/drivers/staging/solo6x10/solo6010-core.c index 4a051cde55da..9dad749ca963 100644 --- a/drivers/staging/solo6x10/solo6010-core.c +++ b/drivers/staging/solo6x10/solo6010-core.c @@ -136,6 +136,7 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev, int ret; int sdram; u8 chip_id; + solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); if (solo_dev == NULL) return -ENOMEM; @@ -261,13 +262,18 @@ static void __devexit solo6010_pci_remove(struct pci_dev *pdev) } static struct pci_device_id solo6010_id_table[] = { + /* 6010 based cards */ {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)}, {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)}, {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)}, {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_9)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_16)}, + {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)}, + {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)}, + {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)}, + /* 6110 based cards */ + {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)}, + {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)}, + {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)}, {0,} }; diff --git a/drivers/staging/solo6x10/solo6010-disp.c b/drivers/staging/solo6x10/solo6010-disp.c index 555f024f72e7..a15151d15ea5 100644 --- a/drivers/staging/solo6x10/solo6010-disp.c +++ b/drivers/staging/solo6x10/solo6010-disp.c @@ -198,7 +198,7 @@ static void solo_motion_config(struct solo6010_dev *solo_dev) } /* Default motion settings */ - solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) | + solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, SOLO_VI_MOTION_FRAME_COUNT(3) | diff --git a/drivers/staging/solo6x10/solo6010-gpio.c b/drivers/staging/solo6x10/solo6010-gpio.c index 46f7a71edabc..8869b88dc307 100644 --- a/drivers/staging/solo6x10/solo6010-gpio.c +++ b/drivers/staging/solo6x10/solo6010-gpio.c @@ -92,8 +92,8 @@ static void solo_gpio_config(struct solo6010_dev *solo_dev) int solo_gpio_init(struct solo6010_dev *solo_dev) { - solo_gpio_config(solo_dev); - return 0; + solo_gpio_config(solo_dev); + return 0; } void solo_gpio_exit(struct solo6010_dev *solo_dev) diff --git a/drivers/staging/solo6x10/solo6010-i2c.c b/drivers/staging/solo6x10/solo6010-i2c.c index cadd5120d575..c1d4a23f4275 100644 --- a/drivers/staging/solo6x10/solo6010-i2c.c +++ b/drivers/staging/solo6x10/solo6010-i2c.c @@ -46,7 +46,7 @@ u8 solo_i2c_readbyte(struct solo6010_dev *solo_dev, int id, u8 addr, u8 off) i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2); - return data; + return data; } void solo_i2c_writebyte(struct solo6010_dev *solo_dev, int id, u8 addr, @@ -227,7 +227,7 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap, if (i == SOLO_I2C_ADAPTERS) return num; // XXX Right return value for failure? - down(&solo_dev->i2c_sem); + mutex_lock(&solo_dev->i2c_mutex); solo_dev->i2c_id = i; solo_dev->i2c_msg = msgs; solo_dev->i2c_msg_num = num; @@ -258,7 +258,7 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap, solo_dev->i2c_state = IIC_STATE_IDLE; solo_dev->i2c_id = -1; - up(&solo_dev->i2c_sem); + mutex_unlock(&solo_dev->i2c_mutex); return ret; } @@ -284,7 +284,7 @@ int solo_i2c_init(struct solo6010_dev *solo_dev) solo_dev->i2c_id = -1; solo_dev->i2c_state = IIC_STATE_IDLE; init_waitqueue_head(&solo_dev->i2c_wait); - sema_init(&solo_dev->i2c_sem, 1); + mutex_init(&solo_dev->i2c_mutex); for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c index 7ed3ed4b8f7e..a46ebf2f376a 100644 --- a/drivers/staging/solo6x10/solo6010-p2m.c +++ b/drivers/staging/solo6x10/solo6010-p2m.c @@ -18,6 +18,7 @@ */ #include +#include #include "solo6010.h" @@ -30,8 +31,9 @@ int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr, int ret; WARN_ON(!size); - WARN_ON(id >= SOLO_NR_P2M); - if (!size || id >= SOLO_NR_P2M) + BUG_ON(id >= SOLO_NR_P2M); + + if (!size) return -EINVAL; dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, @@ -47,42 +49,118 @@ int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr, int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr, dma_addr_t dma_addr, u32 ext_addr, u32 size) +{ + struct p2m_desc desc; + + solo_p2m_push_desc(&desc, wr, dma_addr, ext_addr, size, 0, 0); + + return solo_p2m_dma_desc(solo_dev, id, &desc, 1); +} + +void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, + u32 ext_addr, u32 size, int repeat, u32 ext_size) +{ + desc->ta = dma_addr; + desc->fa = ext_addr; + + desc->ext = SOLO_P2M_COPY_SIZE(size >> 2); + desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | + (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON; + + /* Ext size only matters when we're repeating */ + if (repeat) { + desc->ext |= SOLO_P2M_EXT_INC(ext_size >> 2); + desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) | + SOLO_P2M_REPEAT(repeat); + } +} + +int solo_p2m_dma_desc(struct solo6010_dev *solo_dev, u8 id, + struct p2m_desc *desc, int desc_count) { struct solo_p2m_dev *p2m_dev; - unsigned int timeout = 0; + unsigned int timeout; + int ret = 0; - WARN_ON(!size); - WARN_ON(id >= SOLO_NR_P2M); - if (!size || id >= SOLO_NR_P2M) - return -EINVAL; + BUG_ON(id >= SOLO_NR_P2M); + BUG_ON(desc_count > SOLO_NR_P2M_DESC); p2m_dev = &solo_dev->p2m_dev[id]; - down(&p2m_dev->sem); + mutex_lock(&p2m_dev->mutex); -start_dma: INIT_COMPLETION(p2m_dev->completion); p2m_dev->error = 0; - solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr); - solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr); - solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), - SOLO_P2M_COPY_SIZE(size >> 2)); - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), - SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | - (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON); + /* Setup the descriptor count and base address */ + p2m_dev->num_descs = desc_count; + p2m_dev->descs = desc; + p2m_dev->desc_idx = 0; + + /* We plug in the first descriptor here. The isr will take + * over from desc[1] after this. */ + solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc[0].ta); + solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc[0].fa); + solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc[0].ext); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc[0].ctrl); + + /* Should have all descriptors completed from one interrupt */ timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); - /* XXX Really looks to me like we will get stuck here if a - * real PCI P2M error occurs */ if (p2m_dev->error) - goto start_dma; + ret = -EIO; + else if (timeout == 0) + ret = -EAGAIN; - up(&p2m_dev->sem); + mutex_unlock(&p2m_dev->mutex); - return (timeout == 0) ? -EAGAIN : 0; + WARN_ON_ONCE(ret); + + return ret; +} + +int solo_p2m_dma_sg(struct solo6010_dev *solo_dev, u8 id, + struct p2m_desc *pdesc, int wr, + struct scatterlist *sg, u32 sg_off, + u32 ext_addr, u32 size) +{ + int i; + int idx; + + BUG_ON(id >= SOLO_NR_P2M); + + if (WARN_ON_ONCE(!size)) + return -EINVAL; + + for (i = idx = 0; i < SOLO_NR_P2M_DESC && sg && size > 0; + i++, sg = sg_next(sg)) { + struct p2m_desc *desc = &pdesc[i]; + u32 sg_len = sg_dma_len(sg); + u32 len; + + if (sg_off >= sg_len) { + sg_off -= sg_len; + continue; + } + + sg_len -= sg_off; + len = min(sg_len, size); + + solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off, + ext_addr, len, 0, 0); + + size -= len; + ext_addr += len; + idx++; + + sg_off = 0; + } + + WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC); + + return solo_p2m_dma_desc(solo_dev, id, pdesc, idx); } #ifdef SOLO_TEST_P2M @@ -152,8 +230,27 @@ static void run_p2m_test(struct solo6010_dev *solo_dev) void solo_p2m_isr(struct solo6010_dev *solo_dev, int id) { + struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; + struct p2m_desc *desc; + solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id)); - complete(&solo_dev->p2m_dev[id].completion); + + p2m_dev->desc_idx++; + + if (p2m_dev->desc_idx >= p2m_dev->num_descs) { + complete(&p2m_dev->completion); + return; + } + + /* Reset the p2m and start the next one */ + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + + desc = &p2m_dev->descs[p2m_dev->desc_idx]; + + solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->ta); + solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->fa); + solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->ext); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl); } void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status) @@ -188,16 +285,13 @@ int solo_p2m_init(struct solo6010_dev *solo_dev) for (i = 0; i < SOLO_NR_P2M; i++) { p2m_dev = &solo_dev->p2m_dev[i]; - sema_init(&p2m_dev->sem, 1); + mutex_init(&p2m_dev->mutex); init_completion(&p2m_dev->completion); - solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i), - __pa(p2m_dev->desc)); - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), SOLO_P2M_CSC_16BIT_565 | - SOLO_P2M_DMA_INTERVAL(0) | + SOLO_P2M_DMA_INTERVAL(3) | SOLO_P2M_PCI_MASTER_MODE); solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i)); } diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c index bbf3d9c4abb0..736fad6dc1fb 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2-enc.c +++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include "solo6010.h" #include "solo6010-tw28.h" @@ -47,13 +47,14 @@ struct solo_enc_fh { struct videobuf_queue vidq; struct list_head vidq_active; struct task_struct *kthread; + struct p2m_desc desc[SOLO_NR_P2M_DESC]; }; static unsigned char vid_vop_header[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x02, 0x48, 0x05, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, - 0x1f, 0x4c, 0x58, 0x10, 0x78, 0x51, 0x18, 0x3e, + 0x1f, 0x4c, 0x58, 0x10, 0x78, 0x51, 0x18, 0x3f, }; /* @@ -151,6 +152,11 @@ static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) else solo_dev->motion_mask &= ~(1 << ch); + /* Do this regardless of if we are turning on or off */ + solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, + 1 << solo_enc->ch); + solo_enc->motion_detected = 0; + solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(solo_dev->motion_mask) | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); @@ -184,7 +190,7 @@ static void solo_update_mode(struct solo_enc_dev *solo_enc) solo_enc->bw_weight <<= 2; break; default: - WARN(1, "mode is unknown"); + WARN(1, "mode is unknown\n"); } } @@ -211,11 +217,6 @@ static int solo_enc_on(struct solo_enc_fh *fh) solo_dev->enc_bw_remain -= solo_enc->bw_weight; } - fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6010_NAME "_enc"); - - if (IS_ERR(fh->kthread)) - return PTR_ERR(fh->kthread); - fh->enc_on = 1; fh->rd_idx = solo_enc->solo_dev->enc_wr_idx; @@ -279,6 +280,24 @@ static void solo_enc_off(struct solo_enc_fh *fh) solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); } +static int solo_start_fh_thread(struct solo_enc_fh *fh) +{ + struct solo_enc_dev *solo_enc = fh->enc; + + fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6010_NAME "_enc"); + + /* Oops, we had a problem */ + if (IS_ERR(fh->kthread)) { + spin_lock(&solo_enc->lock); + solo_enc_off(fh); + spin_unlock(&solo_enc->lock); + + return PTR_ERR(fh->kthread); + } + + return 0; +} + static void enc_reset_gop(struct solo6010_dev *solo_dev, u8 ch) { BUG_ON(ch >= solo_dev->nr_chans); @@ -299,22 +318,68 @@ static int enc_gop_reset(struct solo6010_dev *solo_dev, u8 ch, u8 vop) return 0; } -static int enc_get_mpeg_dma_t(struct solo6010_dev *solo_dev, dma_addr_t buf, - unsigned int off, unsigned int size) +static void enc_write_sg(struct scatterlist *sglist, void *buf, int size) +{ + struct scatterlist *sg; + u8 *src = buf; + + for (sg = sglist; sg && size > 0; sg = sg_next(sg)) { + u8 *p = sg_virt(sg); + size_t len = sg_dma_len(sg); + int i; + + for (i = 0; i < len && size; i++) + p[i] = *(src++); + } +} + +static int enc_get_mpeg_dma_sg(struct solo6010_dev *solo_dev, + struct p2m_desc *desc, + struct scatterlist *sglist, int skip, + unsigned int off, unsigned int size) +{ + int ret; + + if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) + return -EINVAL; + + if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { + return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, + desc, 0, sglist, skip, + SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); + } + + /* Buffer wrap */ + ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, + sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off, + SOLO_MP4E_EXT_SIZE(solo_dev) - off); + + ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, + sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off, + SOLO_MP4E_EXT_ADDR(solo_dev), + size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); + + return ret; +} + +static int enc_get_mpeg_dma_t(struct solo6010_dev *solo_dev, + dma_addr_t buf, unsigned int off, + unsigned int size) { int ret; if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) return -EINVAL; - if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) + if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); + } /* Buffer wrap */ ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, - SOLO_MP4E_EXT_ADDR(solo_dev) + off, - SOLO_MP4E_EXT_SIZE(solo_dev) - off); + SOLO_MP4E_EXT_ADDR(solo_dev) + off, + SOLO_MP4E_EXT_SIZE(solo_dev) - off); ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off, @@ -337,70 +402,108 @@ static int enc_get_mpeg_dma(struct solo6010_dev *solo_dev, void *buf, return ret; } -static int enc_get_jpeg_dma(struct solo6010_dev *solo_dev, dma_addr_t buf, - unsigned int off, unsigned int size) +static int enc_get_jpeg_dma_sg(struct solo6010_dev *solo_dev, + struct p2m_desc *desc, + struct scatterlist *sglist, int skip, + unsigned int off, unsigned int size) { int ret; if (off > SOLO_JPEG_EXT_SIZE(solo_dev)) return -EINVAL; - if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) - return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf, - SOLO_JPEG_EXT_ADDR(solo_dev) + off, size); + if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) { + return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, + desc, 0, sglist, skip, + SOLO_JPEG_EXT_ADDR(solo_dev) + off, size); + } /* Buffer wrap */ - ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, buf, - SOLO_JPEG_EXT_ADDR(solo_dev) + off, - SOLO_JPEG_EXT_SIZE(solo_dev) - off); + ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, + sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off, + SOLO_JPEG_EXT_SIZE(solo_dev) - off); - ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_JPEG, 0, - buf + SOLO_JPEG_EXT_SIZE(solo_dev) - off, - SOLO_JPEG_EXT_ADDR(solo_dev), - size + off - SOLO_JPEG_EXT_SIZE(solo_dev)); + ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, + sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off, + SOLO_JPEG_EXT_ADDR(solo_dev), + size + off - SOLO_JPEG_EXT_SIZE(solo_dev)); return ret; } +/* Returns true of __chk is within the first __range bytes of __off */ +#define OFF_IN_RANGE(__off, __range, __chk) \ + ((__off <= __chk) && ((__off + __range) >= __chk)) + +static void solo_jpeg_header(struct solo_enc_dev *solo_enc, + struct videobuf_dmabuf *vbuf) +{ + struct scatterlist *sg; + void *src = jpeg_header; + size_t copied = 0; + size_t to_copy = sizeof(jpeg_header); + + for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) { + size_t this_copy = min(sg_dma_len(sg), + (unsigned int)(to_copy - copied)); + u8 *p = sg_virt(sg); + + memcpy(p, src + copied, this_copy); + + if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5)) + p[(SOF0_START + 5) - copied] = + 0xff & (solo_enc->height >> 8); + if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6)) + p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height; + if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7)) + p[(SOF0_START + 7) - copied] = + 0xff & (solo_enc->width >> 8); + if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8)) + p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width; + + copied += this_copy; + } +} + static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, - struct videobuf_buffer *vb, dma_addr_t vbuf) + struct videobuf_buffer *vb, + struct videobuf_dmabuf *vbuf) { - struct solo_enc_dev *solo_enc = fh->enc; - struct solo6010_dev *solo_dev = solo_enc->solo_dev; - u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb); + struct solo6010_dev *solo_dev = fh->enc->solo_dev; + int size = enc_buf->jpeg_size; - memcpy(p, jpeg_header, sizeof(jpeg_header)); - p[SOF0_START + 5] = 0xff & (solo_enc->height >> 8); - p[SOF0_START + 6] = 0xff & solo_enc->height; - p[SOF0_START + 7] = 0xff & (solo_enc->width >> 8); - p[SOF0_START + 8] = 0xff & solo_enc->width; + /* Copy the header first (direct write) */ + solo_jpeg_header(fh->enc, vbuf); - vbuf += sizeof(jpeg_header); - vb->size = enc_buf->jpeg_size + sizeof(jpeg_header); + vb->size = size + sizeof(jpeg_header); - return enc_get_jpeg_dma(solo_dev, vbuf, enc_buf->jpeg_off, - enc_buf->jpeg_size); + /* Grab the jpeg frame */ + return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, + sizeof(jpeg_header), + enc_buf->jpeg_off, size); } static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, - struct videobuf_buffer *vb, dma_addr_t vbuf) + struct videobuf_buffer *vb, + struct videobuf_dmabuf *vbuf) { struct solo_enc_dev *solo_enc = fh->enc; struct solo6010_dev *solo_dev = solo_enc->solo_dev; struct vop_header vh; int ret; int frame_size, frame_off; + int skip = 0; if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh))) - return -1; + return -EINVAL; /* First get the hardware vop header (not real mpeg) */ ret = enc_get_mpeg_dma(solo_dev, &vh, enc_buf->off, sizeof(vh)); - if (ret) - return -1; + if (WARN_ON_ONCE(ret)) + return ret; if (WARN_ON_ONCE(vh.size > enc_buf->size)) - return -1; + return -EINVAL; vb->width = vh.hsize << 4; vb->height = vh.vsize << 4; @@ -410,9 +513,9 @@ static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, if (!enc_buf->vop) { u16 fps = solo_dev->fps * 1000; u16 interval = solo_enc->interval * 1000; - u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb); + u8 p[sizeof(vid_vop_header)]; - memcpy(p, vid_vop_header, sizeof(vid_vop_header)); + memcpy(p, vid_vop_header, sizeof(p)); if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) p[10] |= ((XVID_PAR_43_NTSC << 3) & 0x78); @@ -434,43 +537,49 @@ static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, if (vh.interlace) p[29] |= 0x20; + enc_write_sg(vbuf->sglist, p, sizeof(p)); + /* Adjust the dma buffer past this header */ vb->size += sizeof(vid_vop_header); - vbuf += sizeof(vid_vop_header); + skip = sizeof(vid_vop_header); } /* Now get the actual mpeg payload */ frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev); frame_size = enc_buf->size - sizeof(vh); - ret = enc_get_mpeg_dma_t(solo_dev, vbuf, frame_off, frame_size); - if (WARN_ON_ONCE(ret)) - return -1; - return 0; + ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, + skip, frame_off, frame_size); + WARN_ON_ONCE(ret); + + return ret; } -/* On successful return (0), leaves solo_enc->lock unlocked */ -static int solo_enc_fillbuf(struct solo_enc_fh *fh, +static void solo_enc_fillbuf(struct solo_enc_fh *fh, struct videobuf_buffer *vb) { struct solo_enc_dev *solo_enc = fh->enc; struct solo6010_dev *solo_dev = solo_enc->solo_dev; struct solo_enc_buf *enc_buf = NULL; - dma_addr_t vbuf; + struct videobuf_dmabuf *vbuf; int ret; + int error = 1; u16 idx = fh->rd_idx; while (idx != solo_dev->enc_wr_idx) { struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx]; + idx = (idx + 1) % SOLO_NR_RING_BUFS; + + if (ebuf->ch != solo_enc->ch) + continue; + if (fh->fmt == V4L2_PIX_FMT_MPEG) { - if (fh->type != ebuf->type) - continue; - if (ebuf->ch == solo_enc->ch) { + if (fh->type == ebuf->type) { enc_buf = ebuf; break; } - } else if (ebuf->ch == solo_enc->ch) { + } else { /* For mjpeg, keep reading to the newest frame */ enc_buf = ebuf; } @@ -478,48 +587,54 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh, fh->rd_idx = idx; - if (!enc_buf) - return -1; + if (WARN_ON_ONCE(!enc_buf)) + goto buf_err; if ((fh->fmt == V4L2_PIX_FMT_MPEG && vb->bsize < enc_buf->size) || (fh->fmt == V4L2_PIX_FMT_MJPEG && vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) { - return -1; + WARN_ON_ONCE(1); + goto buf_err; } - if (!(vbuf = videobuf_to_dma_contig(vb))) - return -1; - - /* Is it ok that we mess with this buffer out of lock? */ - spin_unlock(&solo_enc->lock); + if (WARN_ON_ONCE(!(vbuf = videobuf_to_dma(vb)))) + goto buf_err; if (fh->fmt == V4L2_PIX_FMT_MPEG) ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf); else ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf); - if (ret) // Ignore failures - return 0; + if (!ret) + error = 0; - list_del(&vb->queue); - vb->field_count++; - vb->ts = enc_buf->ts; - vb->state = VIDEOBUF_DONE; +buf_err: + if (error) { + vb->state = VIDEOBUF_ERROR; + } else { + vb->field_count++; + vb->ts = enc_buf->ts; + vb->state = VIDEOBUF_DONE; + } wake_up(&vb->done); - return 0; + return; } static void solo_enc_thread_try(struct solo_enc_fh *fh) { struct solo_enc_dev *solo_enc = fh->enc; + struct solo6010_dev *solo_dev = solo_enc->solo_dev; struct videobuf_buffer *vb; for (;;) { spin_lock(&solo_enc->lock); + if (fh->rd_idx == solo_dev->enc_wr_idx) + break; + if (list_empty(&fh->vidq_active)) break; @@ -529,9 +644,11 @@ static void solo_enc_thread_try(struct solo_enc_fh *fh) if (!waitqueue_active(&vb->done)) break; - /* On success, returns with solo_enc->lock unlocked */ - if (solo_enc_fillbuf(fh, vb)) - break; + list_del(&vb->queue); + + spin_unlock(&solo_enc->lock); + + solo_enc_fillbuf(fh, vb); } assert_spin_locked(&solo_enc->lock); @@ -557,7 +674,7 @@ static int solo_enc_thread(void *data) remove_wait_queue(&solo_enc->thread_wait, &wait); - return 0; + return 0; } void solo_motion_isr(struct solo6010_dev *solo_dev) @@ -669,12 +786,12 @@ void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev) static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { - *size = FRAME_BUF_SIZE; + *size = FRAME_BUF_SIZE; - if (*count < MIN_VID_BUFFERS) + if (*count < MIN_VID_BUFFERS) *count = MIN_VID_BUFFERS; - return 0; + return 0; } static int solo_enc_buf_prepare(struct videobuf_queue *vq, @@ -696,7 +813,9 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, if (vb->state == VIDEOBUF_NEEDS_INIT) { int rc = videobuf_iolock(vq, vb, NULL); if (rc < 0) { - videobuf_dma_contig_free(vq, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(vb); + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; return rc; } @@ -719,7 +838,10 @@ static void solo_enc_buf_queue(struct videobuf_queue *vq, static void solo_enc_buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - videobuf_dma_contig_free(vq, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(vb); + + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; } @@ -753,22 +875,18 @@ static int solo_enc_open(struct file *file) if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL) return -ENOMEM; - spin_lock(&solo_enc->lock); - fh->enc = solo_enc; file->private_data = fh; INIT_LIST_HEAD(&fh->vidq_active); fh->fmt = V4L2_PIX_FMT_MPEG; fh->type = SOLO_ENC_TYPE_STD; - videobuf_queue_dma_contig_init(&fh->vidq, &solo_enc_video_qops, - &solo_enc->solo_dev->pdev->dev, - &solo_enc->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct videobuf_buffer), fh); - - spin_unlock(&solo_enc->lock); + videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops, + &solo_enc->solo_dev->pdev->dev, + &solo_enc->lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct videobuf_buffer), fh); return 0; } @@ -785,7 +903,11 @@ static ssize_t solo_enc_read(struct file *file, char __user *data, spin_lock(&solo_enc->lock); ret = solo_enc_on(fh); - spin_unlock(&solo_enc->lock); + spin_unlock(&solo_enc->lock); + if (ret) + return ret; + + ret = solo_start_fh_thread(fh); if (ret) return ret; } @@ -797,10 +919,15 @@ static ssize_t solo_enc_read(struct file *file, char __user *data, static int solo_enc_release(struct file *file) { struct solo_enc_fh *fh = file->private_data; + struct solo_enc_dev *solo_enc = fh->enc; videobuf_stop(&fh->vidq); videobuf_mmap_free(&fh->vidq); + + spin_lock(&solo_enc->lock); solo_enc_off(fh); + spin_unlock(&solo_enc->lock); + kfree(fh); return 0; @@ -842,7 +969,7 @@ static int solo_enc_enum_input(struct file *file, void *priv, if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) input->std = V4L2_STD_NTSC_M; else - input->std = V4L2_STD_PAL_M; + input->std = V4L2_STD_PAL_B; if (!tw28_get_video_status(solo_dev, solo_enc->ch)) input->status = V4L2_IN_ST_NO_SIGNAL; @@ -956,7 +1083,10 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, spin_unlock(&solo_enc->lock); - return ret; + if (ret) + return ret; + + return solo_start_fh_thread(fh); } static int solo_enc_get_fmt_cap(struct file *file, void *priv, @@ -1014,6 +1144,10 @@ static int solo_enc_dqbuf(struct file *file, void *priv, spin_unlock(&solo_enc->lock); if (ret) return ret; + + ret = solo_start_fh_thread(fh); + if (ret) + return ret; } ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); @@ -1033,12 +1167,16 @@ static int solo_enc_dqbuf(struct file *file, void *priv, /* Check for key frame on mpeg data */ if (fh->fmt == V4L2_PIX_FMT_MPEG) { - struct videobuf_buffer *vb = fh->vidq.bufs[buf->index]; - u8 *p = videobuf_queue_to_vaddr(&fh->vidq, vb); - if (p[3] == 0x00) - buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - else - buf->flags |= V4L2_BUF_FLAG_PFRAME; + struct videobuf_dmabuf *vbuf = + videobuf_to_dma(fh->vidq.bufs[buf->index]); + + if (vbuf) { + u8 *p = sg_virt(vbuf->sglist); + if (p[3] == 0x00) + buf->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + buf->flags |= V4L2_BUF_FLAG_PFRAME; + } } return 0; @@ -1136,7 +1274,7 @@ static int solo_g_parm(struct file *file, void *priv, /* XXX: Shouldn't we be able to get/set this from videobuf? */ cp->readbuffers = 2; - return 0; + return 0; } static int solo_s_parm(struct file *file, void *priv, @@ -1176,7 +1314,7 @@ static int solo_s_parm(struct file *file, void *priv, spin_unlock(&solo_enc->lock); - return 0; + return 0; } static int solo_queryctrl(struct file *file, void *priv, @@ -1240,7 +1378,7 @@ static int solo_queryctrl(struct file *file, void *priv, return 0; } - return -EINVAL; + return -EINVAL; } static int solo_querymenu(struct file *file, void *priv, @@ -1350,9 +1488,9 @@ static int solo_s_ext_ctrls(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_RDS_TX_RADIO_TEXT: if (ctrl->size - 1 > OSD_TEXT_MAX) - err = -ERANGE; + err = -ERANGE; else { - err = copy_from_user(solo_enc->osd_text, + err = copy_from_user(solo_enc->osd_text, ctrl->string, OSD_TEXT_MAX); solo_enc->osd_text[OSD_TEXT_MAX] = '\0'; @@ -1459,7 +1597,7 @@ static struct video_device solo_enc_template = { .minor = -1, .release = video_device_release, - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B, .current_norm = V4L2_STD_NTSC_M, }; @@ -1505,7 +1643,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo6010_dev *solo_dev, u8 ch) atomic_set(&solo_enc->readers, 0); solo_enc->qp = SOLO_DEFAULT_QP; - solo_enc->gop = solo_dev->fps; + solo_enc->gop = solo_dev->fps; solo_enc->interval = 1; solo_enc->mode = SOLO_ENC_MODE_CIF; solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c index 9731fa02b5e8..4cf7257e1eb0 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2.c +++ b/drivers/staging/solo6x10/solo6010-v4l2.c @@ -24,14 +24,13 @@ #include #include -#include +#include #include "solo6010.h" #include "solo6010-tw28.h" #define SOLO_HW_BPL 2048 #define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED -#define SOLO_DISP_BUF_SIZE (64 * 1024) // 64k /* Image size is two fields, SOLO_HW_BPL is one horizontal line */ #define solo_vlines(__solo) (__solo->video_vsize * 2) @@ -49,6 +48,8 @@ struct solo_filehandle { spinlock_t slock; int old_write; struct list_head vidq_active; + struct p2m_desc desc[SOLO_NR_P2M_DESC]; + int desc_idx; }; unsigned video_nr = -1; @@ -96,7 +97,7 @@ static void solo_win_setup(struct solo6010_dev *solo_dev, u8 ch, SOLO_VI_WIN_EX(ex) | SOLO_VI_WIN_SCALE(scale)); - solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch), + solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch), SOLO_VI_WIN_SY(sy) | SOLO_VI_WIN_EY(ey)); } @@ -203,50 +204,146 @@ static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch) return 0; } +static void disp_reset_desc(struct solo_filehandle *fh) +{ + fh->desc_idx = 0; +} + +static int disp_flush_descs(struct solo_filehandle *fh) +{ + int ret; + + if (!fh->desc_idx) + return 0; + + ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP, + fh->desc, fh->desc_idx); + disp_reset_desc(fh); + + return ret; +} + +static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr, + u32 ext_addr, int size, int repeat, int ext_size) +{ + if (fh->desc_idx >= SOLO_NR_P2M_DESC) { + int ret = disp_flush_descs(fh); + if (ret) + return ret; + } + + solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr, + size, repeat, ext_size); + fh->desc_idx++; + + return 0; +} + static void solo_fillbuf(struct solo_filehandle *fh, struct videobuf_buffer *vb) { struct solo6010_dev *solo_dev = fh->solo_dev; - dma_addr_t vbuf; + struct videobuf_dmabuf* vbuf; unsigned int fdma_addr; - int frame_size; int error = 1; int i; + struct scatterlist* sg; + dma_addr_t sg_dma; + int sg_size_left; - if (!(vbuf = videobuf_to_dma_contig(vb))) + if (!(vbuf = videobuf_to_dma(vb))) goto finish_buf; if (erase_off(solo_dev)) { - void *p = videobuf_queue_to_vaddr(&fh->vidq, vb); - int image_size = solo_image_size(solo_dev); - for (i = 0; i < image_size; i += 2) { - ((u8 *)p)[i] = 0x80; - ((u8 *)p)[i + 1] = 0x00; + int i; + + /* Just blit to the entire sg list, ignoring size */ + for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { + void *p = sg_virt(sg); + size_t len = sg_dma_len(sg); + + for (i = 0; i < len; i += 2) { + ((u8 *)p)[i] = 0x80; + ((u8 *)p)[i + 1] = 0x00; + } } + error = 0; goto finish_buf; } - frame_size = SOLO_HW_BPL * solo_vlines(solo_dev); - fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * frame_size); + disp_reset_desc(fh); + sg = vbuf->sglist; + sg_dma = sg_dma_address(sg); + sg_size_left = sg_dma_len(sg); + + fdma_addr = SOLO_DISP_EXT_ADDR(solo_dev) + (fh->old_write * + (SOLO_HW_BPL * solo_vlines(solo_dev))); - for (i = 0; i < frame_size / SOLO_DISP_BUF_SIZE; i++) { - int j; - for (j = 0; j < (SOLO_DISP_BUF_SIZE / SOLO_HW_BPL); j++) { - if (solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_DISP, 0, - vbuf, fdma_addr + (j * SOLO_HW_BPL), - solo_bytesperline(solo_dev))) + for (i = 0; i < solo_vlines(solo_dev); i++) { + int line_len = solo_bytesperline(solo_dev); + int lines; + + if (!sg_size_left) { + sg = sg_next(sg); + if (sg == NULL) goto finish_buf; - vbuf += solo_bytesperline(solo_dev); + sg_dma = sg_dma_address(sg); + sg_size_left = sg_dma_len(sg); } - fdma_addr += SOLO_DISP_BUF_SIZE; + + /* No room for an entire line, so chunk it up */ + if (sg_size_left < line_len) { + int this_addr = fdma_addr; + + while (line_len > 0) { + int this_write; + + if (!sg_size_left) { + sg = sg_next(sg); + if (sg == NULL) + goto finish_buf; + sg_dma = sg_dma_address(sg); + sg_size_left = sg_dma_len(sg); + } + + this_write = min(sg_size_left, line_len); + + if (disp_push_desc(fh, sg_dma, this_addr, + this_write, 0, 0)) + goto finish_buf; + + line_len -= this_write; + sg_size_left -= this_write; + sg_dma += this_write; + this_addr += this_write; + } + + fdma_addr += SOLO_HW_BPL; + continue; + } + + /* Shove as many lines into a repeating descriptor as possible */ + lines = min(sg_size_left / line_len, + solo_vlines(solo_dev) - i); + + if (disp_push_desc(fh, sg_dma, fdma_addr, line_len, + lines - 1, SOLO_HW_BPL)) + goto finish_buf; + + i += lines - 1; + fdma_addr += SOLO_HW_BPL * lines; + sg_dma += lines * line_len; + sg_size_left -= lines * line_len; } - error = 0; + + error = disp_flush_descs(fh); finish_buf: if (error) { vb->state = VIDEOBUF_ERROR; } else { + vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev); vb->state = VIDEOBUF_DONE; vb->field_count++; do_gettimeofday(&vb->ts); @@ -275,7 +372,7 @@ static void solo_thread_try(struct solo_filehandle *fh) break; cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev, - SOLO_VI_STATUS0)); + SOLO_VI_STATUS0)); if (cur_write == fh->old_write) break; @@ -310,7 +407,7 @@ static int solo_thread(void *data) remove_wait_queue(&solo_dev->disp_thread_wait, &wait); - return 0; + return 0; } static int solo_start_thread(struct solo_filehandle *fh) @@ -337,12 +434,12 @@ static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, struct solo_filehandle *fh = vq->priv_data; struct solo6010_dev *solo_dev = fh->solo_dev; - *size = solo_image_size(solo_dev); + *size = solo_image_size(solo_dev); - if (*count < MIN_VID_BUFFERS) + if (*count < MIN_VID_BUFFERS) *count = MIN_VID_BUFFERS; - return 0; + return 0; } static int solo_buf_prepare(struct videobuf_queue *vq, @@ -364,7 +461,9 @@ static int solo_buf_prepare(struct videobuf_queue *vq, if (vb->state == VIDEOBUF_NEEDS_INIT) { int rc = videobuf_iolock(vq, vb, NULL); if (rc < 0) { - videobuf_dma_contig_free(vq, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(vb); + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; return rc; } @@ -388,7 +487,10 @@ static void solo_buf_queue(struct videobuf_queue *vq, static void solo_buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - videobuf_dma_contig_free(vq, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(vb); + + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; } @@ -404,7 +506,7 @@ static unsigned int solo_v4l2_poll(struct file *file, { struct solo_filehandle *fh = file->private_data; - return videobuf_poll_stream(file, &fh->vidq, wait); + return videobuf_poll_stream(file, &fh->vidq, wait); } static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma) @@ -433,11 +535,11 @@ static int solo_v4l2_open(struct file *file) return ret; } - videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops, - &solo_dev->pdev->dev, &fh->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - SOLO_DISP_PIX_FIELD, - sizeof(struct videobuf_buffer), fh); + videobuf_queue_sg_init(&fh->vidq, &solo_video_qops, + &solo_dev->pdev->dev, &fh->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + SOLO_DISP_PIX_FIELD, + sizeof(struct videobuf_buffer), fh); return 0; } @@ -530,7 +632,7 @@ static int solo_enum_input(struct file *file, void *priv, if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) input->std = V4L2_STD_NTSC_M; else - input->std = V4L2_STD_PAL_M; + input->std = V4L2_STD_PAL_B; return 0; } @@ -781,11 +883,11 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_qbuf = solo_qbuf, .vidioc_dqbuf = solo_dqbuf, .vidioc_streamon = solo_streamon, - .vidioc_streamoff = solo_streamoff, + .vidioc_streamoff = solo_streamoff, /* Controls */ .vidioc_queryctrl = solo_disp_queryctrl, - .vidioc_g_ctrl = solo_disp_g_ctrl, - .vidioc_s_ctrl = solo_disp_s_ctrl, + .vidioc_g_ctrl = solo_disp_g_ctrl, + .vidioc_s_ctrl = solo_disp_s_ctrl, }; static struct video_device solo_v4l2_template = { @@ -795,7 +897,7 @@ static struct video_device solo_v4l2_template = { .minor = -1, .release = video_device_release, - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h index dca8e3e15450..332fd79fa936 100644 --- a/drivers/staging/solo6x10/solo6010.h +++ b/drivers/staging/solo6x10/solo6010.h @@ -26,8 +26,8 @@ #include #include #include -#include #include +#include #include #include @@ -48,10 +48,14 @@ #define PCI_DEVICE_ID_NEUSOLO_4 0x4304 #define PCI_DEVICE_ID_NEUSOLO_9 0x4309 #define PCI_DEVICE_ID_NEUSOLO_16 0x4310 -/* Commell Softlogic 6010 based cards */ -#define PCI_DEVICE_ID_COMMSOLO_4 0x4E04 -#define PCI_DEVICE_ID_COMMSOLO_9 0x4E09 -#define PCI_DEVICE_ID_COMMSOLO_16 0x4E10 +/* Bluecherry Softlogic 6010 based cards */ +#define PCI_DEVICE_ID_BC_SOLO_4 0x4E04 +#define PCI_DEVICE_ID_BC_SOLO_9 0x4E09 +#define PCI_DEVICE_ID_BC_SOLO_16 0x4E10 +/* Bluecherry Softlogic 6110 based cards */ +#define PCI_DEVICE_ID_BC_6110_4 0x5304 +#define PCI_DEVICE_ID_BC_6110_8 0x5308 +#define PCI_DEVICE_ID_BC_6110_16 0x5310 #endif /* Bluecherry */ #define SOLO6010_NAME "solo6010" @@ -78,7 +82,6 @@ /* DMA Engine setup */ #define SOLO_NR_P2M 4 #define SOLO_NR_P2M_DESC 256 -#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16) /* MPEG and JPEG share the same interrupt and locks so they must be together * in the same dma channel. */ #define SOLO_P2M_DMA_ID_MP4E 0 @@ -123,11 +126,20 @@ enum SOLO_I2C_STATE { IIC_STATE_STOP }; +struct p2m_desc { + u32 ctrl; + u32 ext; + u32 ta; + u32 fa; +}; + struct solo_p2m_dev { - struct semaphore sem; + struct mutex mutex; struct completion completion; int error; - u8 desc[SOLO_P2M_DESC_SIZE]; + int num_descs; + int desc_idx; + struct p2m_desc *descs; }; #define OSD_TEXT_MAX 30 @@ -185,7 +197,7 @@ struct solo6010_dev { /* i2c related items */ struct i2c_adapter i2c_adap[SOLO_I2C_ADAPTERS]; enum SOLO_I2C_STATE i2c_state; - struct semaphore i2c_sem; + struct mutex i2c_mutex; int i2c_id; wait_queue_head_t i2c_wait; struct i2c_msg *i2c_msg; @@ -306,6 +318,14 @@ int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr, dma_addr_t dma_addr, u32 ext_addr, u32 size); int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr, void *sys_addr, u32 ext_addr, u32 size); +int solo_p2m_dma_sg(struct solo6010_dev *solo_dev, u8 id, + struct p2m_desc *pdesc, int wr, + struct scatterlist *sglist, u32 sg_off, + u32 ext_addr, u32 size); +void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, + u32 ext_addr, u32 size, int repeat, u32 ext_size); +int solo_p2m_dma_desc(struct solo6010_dev *solo_dev, u8 id, + struct p2m_desc *desc, int desc_count); /* Set the threshold for motion detection */ void solo_set_motion_threshold(struct solo6010_dev *solo_dev, u8 ch, u16 val); -- cgit v1.2.3 From 319fb3bacc517829cbd4d758f3b8969fdbde5c92 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Thu, 4 Nov 2010 23:20:31 -0400 Subject: solo6x10: Updates to videobuf-dma-sg functions for latest kernel Signed-off-by: Ben Collins --- drivers/staging/solo6x10/solo6010-v4l2-enc.c | 6 +++--- drivers/staging/solo6x10/solo6010-v4l2.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c index 736fad6dc1fb..5e2001aeb846 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2-enc.c +++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c @@ -814,7 +814,7 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, int rc = videobuf_iolock(vq, vb, NULL); if (rc < 0) { struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq, dma); + videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; return rc; @@ -840,7 +840,7 @@ static void solo_enc_buf_release(struct videobuf_queue *vq, { struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq, dma); + videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; } @@ -886,7 +886,7 @@ static int solo_enc_open(struct file *file) &solo_enc->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, - sizeof(struct videobuf_buffer), fh); + sizeof(struct videobuf_buffer), fh, NULL); return 0; } diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c index 4cf7257e1eb0..af80e6acb496 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2.c +++ b/drivers/staging/solo6x10/solo6010-v4l2.c @@ -462,7 +462,7 @@ static int solo_buf_prepare(struct videobuf_queue *vq, int rc = videobuf_iolock(vq, vb, NULL); if (rc < 0) { struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq, dma); + videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; return rc; @@ -489,7 +489,7 @@ static void solo_buf_release(struct videobuf_queue *vq, { struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq, dma); + videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; } @@ -539,7 +539,7 @@ static int solo_v4l2_open(struct file *file) &solo_dev->pdev->dev, &fh->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, SOLO_DISP_PIX_FIELD, - sizeof(struct videobuf_buffer), fh); + sizeof(struct videobuf_buffer), fh, NULL); return 0; } -- cgit v1.2.3 From 0e4de059d90c96930ab237e7d4fbb7e3814afcb6 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 5 Nov 2010 10:29:33 -0400 Subject: solo6x10: Implement working P2M descriptor more DMA We have to insert 1 dead descriptor first (all zereos), and then the real data descriptors after that. Everything uses descriptor mode now (8800 interrupts per second for display v4l2 is now down to ~96). Signed-off-by: Ben Collins --- drivers/staging/solo6x10/TODO | 1 - drivers/staging/solo6x10/solo6010-p2m.c | 69 ++++++++++++++++---------------- drivers/staging/solo6x10/solo6010-v4l2.c | 4 +- drivers/staging/solo6x10/solo6010.h | 3 -- 4 files changed, 38 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/solo6x10/TODO index 82439d38ba74..7e6c4fa130df 100644 --- a/drivers/staging/solo6x10/TODO +++ b/drivers/staging/solo6x10/TODO @@ -15,7 +15,6 @@ TODO (general): * implement a CID control for motion areas/thresholds * implement CID controls for mozaic areas * allow for higher level of interval (for < 1 fps) - * Get proper descriptor mode working in p2m * sound: - implement playback via external sound jack - implement loopback of external sound jack with incoming audio? diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c index a46ebf2f376a..9f2418093af5 100644 --- a/drivers/staging/solo6x10/solo6010-p2m.c +++ b/drivers/staging/solo6x10/solo6010-p2m.c @@ -50,11 +50,14 @@ int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr, int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr, dma_addr_t dma_addr, u32 ext_addr, u32 size) { - struct p2m_desc desc; + struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA); - solo_p2m_push_desc(&desc, wr, dma_addr, ext_addr, size, 0, 0); + if (desc == NULL) + return -ENOMEM; - return solo_p2m_dma_desc(solo_dev, id, &desc, 1); + solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0); + + return solo_p2m_dma_desc(solo_dev, id, desc, 2); } void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, @@ -81,34 +84,44 @@ int solo_p2m_dma_desc(struct solo6010_dev *solo_dev, u8 id, struct solo_p2m_dev *p2m_dev; unsigned int timeout; int ret = 0; + u32 config = 0; + dma_addr_t desc_dma = 0; BUG_ON(id >= SOLO_NR_P2M); - BUG_ON(desc_count > SOLO_NR_P2M_DESC); + BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC); p2m_dev = &solo_dev->p2m_dev[id]; mutex_lock(&p2m_dev->mutex); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + INIT_COMPLETION(p2m_dev->completion); p2m_dev->error = 0; - /* Setup the descriptor count and base address */ - p2m_dev->num_descs = desc_count; - p2m_dev->descs = desc; - p2m_dev->desc_idx = 0; - - /* We plug in the first descriptor here. The isr will take - * over from desc[1] after this. */ - solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc[0].ta); - solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc[0].fa); - solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc[0].ext); - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc[0].ctrl); + /* Enable the descriptors */ + config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id)); + desc_dma = pci_map_single(solo_dev->pdev, desc, + desc_count * sizeof(*desc), + PCI_DMA_TODEVICE); + solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma); + solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1); + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config | + SOLO_P2M_DESC_MODE); /* Should have all descriptors completed from one interrupt */ timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + /* Reset back to non-descriptor mode */ + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config); + solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0); + solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0); + pci_unmap_single(solo_dev->pdev, desc_dma, + desc_count * sizeof(*desc), + PCI_DMA_TODEVICE); + if (p2m_dev->error) ret = -EIO; else if (timeout == 0) @@ -134,9 +147,12 @@ int solo_p2m_dma_sg(struct solo6010_dev *solo_dev, u8 id, if (WARN_ON_ONCE(!size)) return -EINVAL; - for (i = idx = 0; i < SOLO_NR_P2M_DESC && sg && size > 0; + memset(pdesc, 0, sizeof(*pdesc)); + + /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */ + for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0; i++, sg = sg_next(sg)) { - struct p2m_desc *desc = &pdesc[i]; + struct p2m_desc *desc = &pdesc[idx]; u32 sg_len = sg_dma_len(sg); u32 len; @@ -231,26 +247,10 @@ static void run_p2m_test(struct solo6010_dev *solo_dev) void solo_p2m_isr(struct solo6010_dev *solo_dev, int id) { struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; - struct p2m_desc *desc; solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id)); - p2m_dev->desc_idx++; - - if (p2m_dev->desc_idx >= p2m_dev->num_descs) { - complete(&p2m_dev->completion); - return; - } - - /* Reset the p2m and start the next one */ - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); - - desc = &p2m_dev->descs[p2m_dev->desc_idx]; - - solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->ta); - solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->fa); - solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->ext); - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl); + complete(&p2m_dev->completion); } void solo_p2m_error_isr(struct solo6010_dev *solo_dev, u32 status) @@ -292,6 +292,7 @@ int solo_p2m_init(struct solo6010_dev *solo_dev) solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), SOLO_P2M_CSC_16BIT_565 | SOLO_P2M_DMA_INTERVAL(3) | + SOLO_P2M_DESC_INTR_OPT | SOLO_P2M_PCI_MASTER_MODE); solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i)); } diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c index af80e6acb496..7a9c348de565 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2.c +++ b/drivers/staging/solo6x10/solo6010-v4l2.c @@ -206,7 +206,9 @@ static int solo_v4l2_set_ch(struct solo6010_dev *solo_dev, u8 ch) static void disp_reset_desc(struct solo_filehandle *fh) { - fh->desc_idx = 0; + /* We use desc mode, which ignores desc 0 */ + memset(fh->desc, 0, sizeof(*fh->desc)); + fh->desc_idx = 1; } static int disp_flush_descs(struct solo_filehandle *fh) diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h index 332fd79fa936..9f5d2a326ae1 100644 --- a/drivers/staging/solo6x10/solo6010.h +++ b/drivers/staging/solo6x10/solo6010.h @@ -137,9 +137,6 @@ struct solo_p2m_dev { struct mutex mutex; struct completion completion; int error; - int num_descs; - int desc_idx; - struct p2m_desc *descs; }; #define OSD_TEXT_MAX 30 -- cgit v1.2.3 From 045e769ab69ce94dedbcdcfd46c2578b385c2986 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 7 Nov 2010 09:18:22 +0000 Subject: drm/i915: Handle GPU hangs during fault gracefully. Instead of killing the process, just return no page found and reschedule the process giving the GPU some time to (hopefully) recover. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 47c665eeaf17..7c91bf2bbdfd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1340,11 +1340,12 @@ unlock: mutex_unlock(&dev->struct_mutex); switch (ret) { + case -EAGAIN: + set_need_resched(); case 0: case -ERESTARTSYS: return VM_FAULT_NOPAGE; case -ENOMEM: - case -EAGAIN: return VM_FAULT_OOM; default: return VM_FAULT_SIGBUS; -- cgit v1.2.3 From ae69b42a10dafe61adb016e0e52ec1e8d1ba11b4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 7 Nov 2010 11:45:52 +0000 Subject: drm/i915/ringbuffer: Be consistent in use of ring->size when initialising Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 78a5061a58f6..9033697783b9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -173,7 +173,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) } I915_WRITE_CTL(ring, - ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) + ((ring->size - PAGE_SIZE) & RING_NR_PAGES) | RING_REPORT_64K | RING_VALID); /* If the head is still not zero, the ring is dead */ -- cgit v1.2.3 From 629e894173c9de589913cf649deaadec4b0579bd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 7 Nov 2010 11:50:02 +0000 Subject: drm/i915/ringbuffer: Ignore failure to setup the ring on Sandybridge The ring buffer registers return 0 whilst idle (for some values of idle) on early Sandybridge hw. Persevere even when all appears hopeless... Fortunately the head auto-reporting prevents most hangs. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=31370 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9033697783b9..f5d6151c953f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -180,14 +180,30 @@ static int init_ring_common(struct intel_ring_buffer *ring) if ((I915_READ_CTL(ring) & RING_VALID) == 0 || I915_READ_START(ring) != obj_priv->gtt_offset || (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) { - DRM_ERROR("%s initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); - return -EIO; + if (IS_GEN6(ring->dev) && ring->dev->pdev->revision <= 8) { + /* Early revisions of Sandybridge do not like + * revealing the contents of the ring buffer + * registers whilst idle. Fortunately, the + * auto-reporting mechanism prevents most hangs, + * but this will bite us eventually... + */ + DRM_DEBUG("%s initialization failed " + "ctl %08x head %08x tail %08x start %08x. Ignoring, hope for the best!\n", + ring->name, + I915_READ_CTL(ring), + I915_READ_HEAD(ring), + I915_READ_TAIL(ring), + I915_READ_START(ring)); + } else { + DRM_ERROR("%s initialization failed " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ_CTL(ring), + I915_READ_HEAD(ring), + I915_READ_TAIL(ring), + I915_READ_START(ring)); + return -EIO; + } } if (!drm_core_check_feature(ring->dev, DRIVER_MODESET)) -- cgit v1.2.3 From de6e2eaf2c420bb8b0d4485913ef312a5539b489 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 6 Nov 2010 14:53:32 -0700 Subject: drm/i915: Apply B-spec mandated workaround for read flushes on Ironlake. This is not known to fix any particular bugs we have, but the spec says to do it, and the BIOS hadn't already set it up on my system. Signed-off-by: Eric Anholt Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 13 +++++++++++++ drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c79d4ba4fb12..09e2a5502652 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -316,6 +316,19 @@ #define ERROR_GEN6 0x040a0 +/* GM45+ chicken bits -- debug workaround bits that may be required + * for various sorts of correct behavior. The top 16 bits of each are + * the enables for writing to the corresponding low bit. + */ +#define _3D_CHICKEN 0x02084 +#define _3D_CHICKEN2 0x0208c +/* Disables pipelining of read flushes past the SF-WIZ interface. + * Required on all Ironlake steppings according to the B-Spec, but the + * particular danger of not doing so is not specified. + */ +# define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) +#define _3D_CHICKEN3 0x02090 + #define MI_MODE 0x0209c # define VS_TIMER_DISPATCH (1 << 6) # define MI_FLUSH_ENABLE (1 << 11) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 77b34942dc91..5ab403556846 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5818,6 +5818,12 @@ void intel_init_clock_gating(struct drm_device *dev) ILK_DPFC_DIS2 | ILK_CLK_FBC); } + + if (IS_GEN5(dev)) { + I915_WRITE(_3D_CHICKEN2, + _3D_CHICKEN2_WM_READ_PIPELINED << 16 | + _3D_CHICKEN2_WM_READ_PIPELINED); + } return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; -- cgit v1.2.3 From 67e92af01cb6f7e9a5fd5c930c43cd6f6ef45929 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 6 Nov 2010 14:53:33 -0700 Subject: drm/i915: Apply display workaround required according to the B-Spec. Not known to fix any current bugs. Signed-off-by: Eric Anholt Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 09e2a5502652..61fe2619bb63 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2609,6 +2609,8 @@ #define GTIER 0x4401c #define ILK_DISPLAY_CHICKEN2 0x42004 +/* Required on all Ironlake and Sandybridge according to the B-Spec. */ +#define ILK_ELPIN_409_SELECT (1 << 25) #define ILK_DPARB_GATE (1<<22) #define ILK_VSDPFD_FULL (1<<21) #define ILK_DSPCLK_GATE 0x42020 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5ab403556846..c41dae5ade32 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5819,6 +5819,10 @@ void intel_init_clock_gating(struct drm_device *dev) ILK_CLK_FBC); } + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + if (IS_GEN5(dev)) { I915_WRITE(_3D_CHICKEN2, _3D_CHICKEN2_WM_READ_PIPELINED << 16 | -- cgit v1.2.3 From ba4f01a30480cdcd516b782f77a6e0951b83df1c Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Mon, 8 Nov 2010 17:09:41 +0800 Subject: drm/i915: trace down all the register write and read Add two tracepoints at I915_WRITE/READ for tracing down all the register write and read. Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 61 ++++++++++++++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_trace.h | 23 +++++++++++++++ 2 files changed, 76 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 621234265454..220ce53d4a9c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -32,6 +32,7 @@ #include "i915_reg.h" #include "intel_bios.h" +#include "i915_trace.h" #include "intel_ringbuffer.h" #include #include @@ -1173,14 +1174,58 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) -#define I915_READ(reg) readl(dev_priv->regs + (reg)) -#define I915_WRITE(reg, val) writel(val, dev_priv->regs + (reg)) -#define I915_READ16(reg) readw(dev_priv->regs + (reg)) -#define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) -#define I915_READ8(reg) readb(dev_priv->regs + (reg)) -#define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg)) -#define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) -#define I915_READ64(reg) readq(dev_priv->regs + (reg)) +static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg, int len) +{ + u64 val = 0; + + switch (len) { + case 8: + val = readq(dev_priv->regs + reg); + break; + case 4: + val = readl(dev_priv->regs + reg); + break; + case 2: + val = readw(dev_priv->regs + reg); + break; + case 1: + val = readb(dev_priv->regs + reg); + break; + } + trace_i915_reg_rw('R', reg, val, len); + + return val; +} + +static inline void +i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) +{ + /* Trace down the write operation before the real write */ + trace_i915_reg_rw('W', reg, val, len); + switch (len) { + case 8: + writeq(val, dev_priv->regs + reg); + break; + case 4: + writel(val, dev_priv->regs + reg); + break; + case 2: + writew(val, dev_priv->regs + reg); + break; + case 1: + writeb(val, dev_priv->regs + reg); + break; + } +} + +#define I915_READ(reg) i915_read(dev_priv, (reg), 4) +#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val), 4) +#define I915_READ16(reg) i915_read(dev_priv, (reg), 2) +#define I915_WRITE16(reg, val) i915_write(dev_priv, (reg), (val), 2) +#define I915_READ8(reg) i915_read(dev_priv, (reg), 1) +#define I915_WRITE8(reg, val) i915_write(dev_priv, (reg), (val), 1) +#define I915_WRITE64(reg, val) i915_write(dev_priv, (reg), (val), 8) +#define I915_READ64(reg) i915_read(dev_priv, (reg), 8) #define POSTING_READ(reg) (void)I915_READ(reg) #define POSTING_READ16(reg) (void)I915_READ16(reg) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 0b1049ff72a3..34ef49fd0377 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -301,6 +301,29 @@ TRACE_EVENT(i915_flip_complete, TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj) ); +TRACE_EVENT(i915_reg_rw, + TP_PROTO(int cmd, uint32_t reg, uint64_t val, int len), + + TP_ARGS(cmd, reg, val, len), + + TP_STRUCT__entry( + __field(int, cmd) + __field(uint32_t, reg) + __field(uint64_t, val) + __field(int, len) + ), + + TP_fast_assign( + __entry->cmd = cmd; + __entry->reg = reg; + __entry->val = (uint64_t)val; + __entry->len = len; + ), + + TP_printk("cmd=%c, reg=0x%x, val=0x%llx, len=%d", + __entry->cmd, __entry->reg, __entry->val, __entry->len) +); + #endif /* _I915_TRACE_H_ */ /* This part must be outside protection */ -- cgit v1.2.3 From 65e5ecb066fe54c13c8445d6acfdcdf149ad5df9 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Mon, 8 Nov 2010 09:56:37 +0000 Subject: drm/i915: Add untraced register read/write interface This will be used later to hide the frequently written registers from debug traces in order to increase the signal-to-noise. Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 220ce53d4a9c..02c35d57fbed 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1229,6 +1229,11 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) #define POSTING_READ(reg) (void)I915_READ(reg) #define POSTING_READ16(reg) (void)I915_READ16(reg) +#define I915_READ_NOTRACE(reg) readl(dev_priv->regs + (reg)) +#define I915_WRITE_NOTRACE(reg, val) writel(val, dev_priv->regs + (reg)) +#define POSTING_READ_NOTRACE(reg) (void)I915_READ_NOTRACE(reg) + + #define BEGIN_LP_RING(n) \ intel_ring_begin(&dev_priv->render_ring, (n)) -- cgit v1.2.3 From db5e4172a023cff68b3597ace8a5390b02669d27 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Mon, 8 Nov 2010 09:58:16 +0000 Subject: drm/i915: filter out the read/write of GPIO registers from debug tracing These registers are written very frequently, are timing sensitive, and not particularly relevant to any debugging, so remove the tracepoints from these. Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_i2c.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 2be4f728ed0c..8f5c0d33ea00 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -85,8 +85,9 @@ static u32 get_reserved(struct intel_gpio *gpio) /* On most chips, these bits must be preserved in software. */ if (!IS_I830(dev) && !IS_845G(dev)) - reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE | - GPIO_CLOCK_PULLUP_DISABLE); + reserved = I915_READ_NOTRACE(gpio->reg) & + (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); return reserved; } @@ -96,9 +97,9 @@ static int get_clock(void *data) struct intel_gpio *gpio = data; struct drm_i915_private *dev_priv = gpio->dev_priv; u32 reserved = get_reserved(gpio); - I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); - I915_WRITE(gpio->reg, reserved); - return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; + I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK); + I915_WRITE_NOTRACE(gpio->reg, reserved); + return (I915_READ_NOTRACE(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0; } static int get_data(void *data) @@ -106,9 +107,9 @@ static int get_data(void *data) struct intel_gpio *gpio = data; struct drm_i915_private *dev_priv = gpio->dev_priv; u32 reserved = get_reserved(gpio); - I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); - I915_WRITE(gpio->reg, reserved); - return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0; + I915_WRITE_NOTRACE(gpio->reg, reserved | GPIO_DATA_DIR_MASK); + I915_WRITE_NOTRACE(gpio->reg, reserved); + return (I915_READ_NOTRACE(gpio->reg) & GPIO_DATA_VAL_IN) != 0; } static void set_clock(void *data, int state_high) @@ -124,8 +125,8 @@ static void set_clock(void *data, int state_high) clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; - I915_WRITE(gpio->reg, reserved | clock_bits); - POSTING_READ(gpio->reg); + I915_WRITE_NOTRACE(gpio->reg, reserved | clock_bits); + POSTING_READ_NOTRACE(gpio->reg); } static void set_data(void *data, int state_high) @@ -141,8 +142,8 @@ static void set_data(void *data, int state_high) data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK; - I915_WRITE(gpio->reg, reserved | data_bits); - POSTING_READ(gpio->reg); + I915_WRITE_NOTRACE(gpio->reg, reserved | data_bits); + POSTING_READ_NOTRACE(gpio->reg); } static struct i2c_adapter * -- cgit v1.2.3 From 2b51dca79a105dea022776ea7874193239df7fbd Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 8 Nov 2010 14:44:34 +0100 Subject: floppy: replace NO_GEOM macro with a function This patch replaces the NO_GEOM macro with a proper static inline function and converts an open-coded caller in check_floppy_change() to use it. Cc: Stephen Hemminger Cc: Andrew Morton Signed-off-by: Pekka Enberg Signed-off-by: Jens Axboe --- drivers/block/floppy.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index cf04c1b234ed..709e69c6d022 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -596,6 +596,11 @@ static unsigned char fsector_t; /* sector in track */ static unsigned char in_sector_offset; /* offset within physical sector, * expressed in units of 512 bytes */ +static inline bool drive_no_geom(int drive) +{ + return !current_type[drive] && !ITYPE(UDRS->fd_device); +} + #ifndef fd_eject static inline int fd_eject(int drive) { @@ -3757,7 +3762,7 @@ static int check_floppy_change(struct gendisk *disk) if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) || test_bit(FD_VERIFY_BIT, &UDRS->flags) || test_bit(drive, &fake_change) || - (!ITYPE(UDRS->fd_device) && !current_type[drive])) + drive_no_geom(drive)) return 1; return 0; } @@ -3823,13 +3828,13 @@ static int __floppy_read_block_0(struct block_device *bdev) static int floppy_revalidate(struct gendisk *disk) { int drive = (long)disk->private_data; -#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device)) int cf; int res = 0; if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) || test_bit(FD_VERIFY_BIT, &UDRS->flags) || - test_bit(drive, &fake_change) || NO_GEOM) { + test_bit(drive, &fake_change) || + drive_no_geom(drive)) { if (WARN(atomic_read(&usage_count) == 0, "VFS: revalidate called on non-open device.\n")) return -EFAULT; @@ -3837,7 +3842,7 @@ static int floppy_revalidate(struct gendisk *disk) lock_fdc(drive, false); cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) || test_bit(FD_VERIFY_BIT, &UDRS->flags)); - if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) { + if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) { process_fd_request(); /*already done by another thread */ return 0; } @@ -3849,7 +3854,7 @@ static int floppy_revalidate(struct gendisk *disk) clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags); if (cf) UDRS->generation++; - if (NO_GEOM) { + if (drive_no_geom(drive)) { /* auto-sensing */ res = __floppy_read_block_0(opened_bdev[drive]); } else { -- cgit v1.2.3 From 5bf68592e72eb0ded154efaaf43b39aab6964fc3 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Mon, 8 Nov 2010 10:07:42 -0500 Subject: solo6x10: [P2M] Fix memory leak Signed-off-by: Ben Collins --- drivers/staging/solo6x10/solo6010-p2m.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c index 9f2418093af5..c91fc4652a00 100644 --- a/drivers/staging/solo6x10/solo6010-p2m.c +++ b/drivers/staging/solo6x10/solo6010-p2m.c @@ -51,13 +51,16 @@ int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr, dma_addr_t dma_addr, u32 ext_addr, u32 size) { struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA); + int ret; if (desc == NULL) return -ENOMEM; solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0); + ret = solo_p2m_dma_desc(solo_dev, id, desc, 2); + kfree(desc); - return solo_p2m_dma_desc(solo_dev, id, desc, 2); + return ret; } void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, -- cgit v1.2.3 From 374c479bef7ecd2b41d6dd6e24aa21d73b3afae5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 8 Nov 2010 21:07:24 +0000 Subject: drm/i915: POSTING_READs are simply flushes and so irrelevant to tracing As we use POSTING_READ to flush the write to the register before proceeding, we do not care what the return value is and similar we do not care for the read to be recorded whilst tracing register read/writes. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 8 +++++--- drivers/gpu/drm/i915/intel_i2c.c | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 02c35d57fbed..ff7593f70f0f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1226,12 +1226,14 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) #define I915_WRITE8(reg, val) i915_write(dev_priv, (reg), (val), 1) #define I915_WRITE64(reg, val) i915_write(dev_priv, (reg), (val), 8) #define I915_READ64(reg) i915_read(dev_priv, (reg), 8) -#define POSTING_READ(reg) (void)I915_READ(reg) -#define POSTING_READ16(reg) (void)I915_READ16(reg) #define I915_READ_NOTRACE(reg) readl(dev_priv->regs + (reg)) #define I915_WRITE_NOTRACE(reg, val) writel(val, dev_priv->regs + (reg)) -#define POSTING_READ_NOTRACE(reg) (void)I915_READ_NOTRACE(reg) +#define I915_READ16_NOTRACE(reg) readw(dev_priv->regs + (reg)) +#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg)) + +#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) +#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) #define BEGIN_LP_RING(n) \ diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 8f5c0d33ea00..d2d493a24e65 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -126,7 +126,7 @@ static void set_clock(void *data, int state_high) GPIO_CLOCK_VAL_MASK; I915_WRITE_NOTRACE(gpio->reg, reserved | clock_bits); - POSTING_READ_NOTRACE(gpio->reg); + POSTING_READ(gpio->reg); } static void set_data(void *data, int state_high) @@ -143,7 +143,7 @@ static void set_data(void *data, int state_high) GPIO_DATA_VAL_MASK; I915_WRITE_NOTRACE(gpio->reg, reserved | data_bits); - POSTING_READ_NOTRACE(gpio->reg); + POSTING_READ(gpio->reg); } static struct i2c_adapter * -- cgit v1.2.3 From 56e2ea346ab4c2ea159ecdec85fffc24f50c2903 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 8 Nov 2010 17:10:29 +0000 Subject: drm/i915: Fix unload after failed initialisation If modeset init failed we attempted to unload the module, before we finished setting it up and so triggered various oopses. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index eee88cfcb3aa..307bad0fcef7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1993,7 +1993,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) drm_core_check_feature(dev, DRIVER_MODESET)) { DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n"); ret = -ENODEV; - goto out_iomapfree; + goto out_workqueue_free; } dev->driver->get_vblank_counter = i915_get_vblank_counter; @@ -2016,8 +2016,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* Init HWS */ if (!I915_NEED_GFX_HWS(dev)) { ret = i915_init_phys_hws(dev); - if (ret != 0) - goto out_workqueue_free; + if (ret) + goto out_gem_unload; } if (IS_PINEVIEW(dev)) @@ -2044,11 +2044,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->trace_irq_seqno = 0; ret = drm_vblank_init(dev, I915_NUM_PIPE); - - if (ret) { - (void) i915_driver_unload(dev); - return ret; - } + if (ret) + goto out_gem_unload; /* Start out suspended */ dev_priv->mm.suspended = 1; @@ -2059,7 +2056,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ret = i915_load_modeset_init(dev); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); - goto out_workqueue_free; + goto out_gem_unload; } } @@ -2077,6 +2074,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; +out_gem_unload: + if (dev->pdev->msi_enabled) + pci_disable_msi(dev->pdev); + + intel_teardown_gmbus(dev); + intel_teardown_mchbar(dev); out_workqueue_free: destroy_workqueue(dev_priv->wq); out_iomapfree: -- cgit v1.2.3 From d0f40c5041f9c48afbd8f7fbf8a5faa9e5dbd39a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 18:51:06 -0700 Subject: Staging: intel_sst: Use pr_fmt, fix misspellings Remove leading "sst: " from format strings. Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Prefix is changed from "sst: " to "snd_intel_sst: " Add missing newlines Trim trailing spaces after newlines Fix several different misspellings Signed-off-by: Joe Perches Cc: Vinod Koul Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst.c | 50 ++--- .../staging/intel_sst/intel_sst_app_interface.c | 140 +++++++------- .../staging/intel_sst/intel_sst_drv_interface.c | 62 ++++--- drivers/staging/intel_sst/intel_sst_dsp.c | 67 +++---- drivers/staging/intel_sst/intel_sst_ipc.c | 144 ++++++++------- drivers/staging/intel_sst/intel_sst_pvt.c | 36 ++-- drivers/staging/intel_sst/intel_sst_stream.c | 18 +- .../staging/intel_sst/intel_sst_stream_encoded.c | 205 +++++++++++---------- drivers/staging/intel_sst/intelmid.c | 157 ++++++++-------- drivers/staging/intel_sst/intelmid_ctrl.c | 15 +- drivers/staging/intel_sst/intelmid_msic_control.c | 24 +-- drivers/staging/intel_sst/intelmid_pvt.c | 27 +-- drivers/staging/intel_sst/intelmid_v0_control.c | 32 ++-- drivers/staging/intel_sst/intelmid_v1_control.c | 28 +-- drivers/staging/intel_sst/intelmid_v2_control.c | 94 +++++----- 15 files changed, 566 insertions(+), 533 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c index 24d3928e7071..0ba6742d9236 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/drivers/staging/intel_sst/intel_sst.c @@ -29,6 +29,8 @@ * This file contains all init functions */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -169,17 +171,17 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, { int i, ret = 0; - pr_debug("sst: Probe for DID %x\n", pci->device); + pr_debug("Probe for DID %x\n", pci->device); mutex_lock(&drv_ctx_lock); if (sst_drv_ctx) { - pr_err("sst: Only one sst handle is supported\n"); + pr_err("Only one sst handle is supported\n"); mutex_unlock(&drv_ctx_lock); return -EBUSY; } sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL); if (!sst_drv_ctx) { - pr_err("sst: intel_sst malloc fail\n"); + pr_err("malloc fail\n"); mutex_unlock(&drv_ctx_lock); return -ENOMEM; } @@ -226,7 +228,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, spin_lock_init(&sst_drv_ctx->list_spin_lock); sst_drv_ctx->max_streams = pci_id->driver_data; - pr_debug("sst: Got drv data max stream %d\n", + pr_debug("Got drv data max stream %d\n", sst_drv_ctx->max_streams); for (i = 1; i <= sst_drv_ctx->max_streams; i++) { struct stream_info *stream = &sst_drv_ctx->streams[i]; @@ -241,18 +243,18 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, sst_drv_ctx->mmap_mem = kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL); if (sst_drv_ctx->mmap_mem) { - pr_debug("sst: Got memory %p size 0x%x\n", + pr_debug("Got memory %p size 0x%x\n", sst_drv_ctx->mmap_mem, sst_drv_ctx->mmap_len); break; } if (sst_drv_ctx->mmap_len < (SST_MMAP_STEP*PAGE_SIZE)) { - pr_err("sst: mem alloc fail...abort!!\n"); + pr_err("mem alloc fail...abort!!\n"); ret = -ENOMEM; goto free_process_reply_wq; } sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE); - pr_debug("sst:mem alloc failed...trying %d\n", + pr_debug("mem alloc failed...trying %d\n", sst_drv_ctx->mmap_len); } } @@ -260,7 +262,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, /* Init the device */ ret = pci_enable_device(pci); if (ret) { - pr_err("sst: device cant be enabled\n"); + pr_err("device cant be enabled\n"); goto do_free_mem; } sst_drv_ctx->pci = pci_dev_get(pci); @@ -273,25 +275,25 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, sst_drv_ctx->shim = pci_ioremap_bar(pci, 1); if (!sst_drv_ctx->shim) goto do_release_regions; - pr_debug("sst: SST Shim Ptr %p\n", sst_drv_ctx->shim); + pr_debug("SST Shim Ptr %p\n", sst_drv_ctx->shim); /* Shared SRAM */ sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2); if (!sst_drv_ctx->mailbox) goto do_unmap_shim; - pr_debug("sst: SRAM Ptr %p\n", sst_drv_ctx->mailbox); + pr_debug("SRAM Ptr %p\n", sst_drv_ctx->mailbox); /* IRAM */ sst_drv_ctx->iram = pci_ioremap_bar(pci, 3); if (!sst_drv_ctx->iram) goto do_unmap_sram; - pr_debug("sst:IRAM Ptr %p\n", sst_drv_ctx->iram); + pr_debug("IRAM Ptr %p\n", sst_drv_ctx->iram); /* DRAM */ sst_drv_ctx->dram = pci_ioremap_bar(pci, 4); if (!sst_drv_ctx->dram) goto do_unmap_iram; - pr_debug("sst: DRAM Ptr %p\n", sst_drv_ctx->dram); + pr_debug("DRAM Ptr %p\n", sst_drv_ctx->dram); mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_UN_INIT; @@ -301,24 +303,24 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx); if (ret) goto do_unmap_dram; - pr_debug("sst: Registered IRQ 0x%x\n", pci->irq); + pr_debug("Registered IRQ 0x%x\n", pci->irq); if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { ret = misc_register(&lpe_dev); if (ret) { - pr_err("sst: couldn't register LPE device\n"); + pr_err("couldn't register LPE device\n"); goto do_free_irq; } /*Register LPE Control as misc driver*/ ret = misc_register(&lpe_ctrl); if (ret) { - pr_err("sst: couldn't register misc driver\n"); + pr_err("couldn't register misc driver\n"); goto do_free_irq; } } sst_drv_ctx->lpe_stalled = 0; - pr_debug("sst: ...successfully done!!!\n"); + pr_debug("...successfully done!!!\n"); return ret; do_free_irq: @@ -347,7 +349,7 @@ free_mad_wq: destroy_workqueue(sst_drv_ctx->mad_wq); do_free_drv_ctx: kfree(sst_drv_ctx); - pr_err("sst: Probe failed with 0x%x\n", ret); + pr_err("Probe failed with 0x%x\n", ret); return ret; } @@ -404,7 +406,7 @@ int intel_sst_suspend(struct pci_dev *pci, pm_message_t state) { union config_status_reg csr; - pr_debug("sst: intel_sst_suspend called\n"); + pr_debug("intel_sst_suspend called\n"); if (sst_drv_ctx->pb_streams != 0 || sst_drv_ctx->cp_streams != 0) return -EPERM; @@ -434,9 +436,9 @@ int intel_sst_resume(struct pci_dev *pci) { int ret = 0; - pr_debug("sst: intel_sst_resume called\n"); + pr_debug("intel_sst_resume called\n"); if (sst_drv_ctx->sst_state != SST_SUSPENDED) { - pr_err("sst: SST is not in suspended state\n"); + pr_err("SST is not in suspended state\n"); return -EPERM; } sst_drv_ctx = pci_get_drvdata(pci); @@ -444,7 +446,7 @@ int intel_sst_resume(struct pci_dev *pci) pci_restore_state(pci); ret = pci_enable_device(pci); if (ret) - pr_err("sst: device cant be enabled\n"); + pr_err("device cant be enabled\n"); mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_UN_INIT; @@ -482,14 +484,14 @@ static int __init intel_sst_init(void) { /* Init all variables, data structure etc....*/ int ret = 0; - pr_debug("sst: INFO: ******** SST DRIVER loading.. Ver: %s\n", + pr_debug("INFO: ******** SST DRIVER loading.. Ver: %s\n", SST_DRIVER_VERSION); mutex_init(&drv_ctx_lock); /* Register with PCI */ ret = pci_register_driver(&driver); if (ret) - pr_err("sst: PCI register failed\n"); + pr_err("PCI register failed\n"); return ret; } @@ -504,7 +506,7 @@ static void __exit intel_sst_exit(void) { pci_unregister_driver(&driver); - pr_debug("sst: driver unloaded\n"); + pr_debug("driver unloaded\n"); return; } diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index 463e5cba8307..fb718d47f54b 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c @@ -27,6 +27,8 @@ * Upper layer interfaces (MAD driver, MMF) to SST driver */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -59,14 +61,14 @@ static int intel_sst_check_device(void) { int retval = 0; if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) { - pr_warn("sst: Sound card not availble\n "); + pr_warn("Sound card not available\n"); return -EIO; } if (sst_drv_ctx->sst_state == SST_SUSPENDED) { - pr_debug("sst: Resuming from Suspended state\n"); + pr_debug("Resuming from Suspended state\n"); retval = intel_sst_resume(sst_drv_ctx->pci); if (retval) { - pr_debug("sst: Resume Failed= %#x,abort\n", retval); + pr_debug("Resume Failed= %#x,abort\n", retval); return retval; } } @@ -116,7 +118,7 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr) data->pvt_id = sst_assign_pvt_id(sst_drv_ctx); data->str_id = 0; file_ptr->private_data = (void *)data; - pr_debug("sst: pvt_id handle = %d!\n", data->pvt_id); + pr_debug("pvt_id handle = %d!\n", data->pvt_id); } else { retval = -EUSERS; mutex_unlock(&sst_drv_ctx->stream_lock); @@ -145,7 +147,7 @@ int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr) mutex_lock(&sst_drv_ctx->stream_lock); if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) { sst_drv_ctx->am_cnt++; - pr_debug("sst: AM handle opened...\n"); + pr_debug("AM handle opened...\n"); file_ptr->private_data = NULL; } else retval = -EACCES; @@ -167,7 +169,7 @@ int intel_sst_release(struct inode *i_node, struct file *file_ptr) { struct ioctl_pvt_data *data = file_ptr->private_data; - pr_debug("sst: Release called, closing app handle\n"); + pr_debug("Release called, closing app handle\n"); mutex_lock(&sst_drv_ctx->stream_lock); sst_drv_ctx->encoded_cnt--; sst_drv_ctx->stream_cnt--; @@ -183,7 +185,7 @@ int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr) mutex_lock(&sst_drv_ctx->stream_lock); sst_drv_ctx->am_cnt--; mutex_unlock(&sst_drv_ctx->stream_lock); - pr_debug("sst: AM handle closed\n"); + pr_debug("AM handle closed\n"); return 0; } @@ -209,7 +211,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma) return -EINVAL; length = vma->vm_end - vma->vm_start; - pr_debug("sst: called for stream %d length 0x%x\n", str_id, length); + pr_debug("called for stream %d length 0x%x\n", str_id, length); if (length > sst_drv_ctx->mmap_len) return -ENOMEM; @@ -232,7 +234,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma) else sst_drv_ctx->streams[str_id].mmapped = true; - pr_debug("sst: mmap ret 0x%x\n", retval); + pr_debug("mmap ret 0x%x\n", retval); return retval; } @@ -245,7 +247,7 @@ static int intel_sst_mmap_play_capture(u32 str_id, struct stream_info *stream; struct snd_sst_mmap_buff_entry *buf_entry; - pr_debug("sst:called for str_id %d\n", str_id); + pr_debug("called for str_id %d\n", str_id); retval = sst_validate_strid(str_id); if (retval) return -EINVAL; @@ -262,7 +264,7 @@ static int intel_sst_mmap_play_capture(u32 str_id, stream->curr_bytes = 0; stream->cumm_bytes = 0; - pr_debug("sst:new buffers count %d status %d\n", + pr_debug("new buffers count %d status %d\n", mmap_buf->entries, stream->status); buf_entry = mmap_buf->buff; for (i = 0; i < mmap_buf->entries; i++) { @@ -291,13 +293,13 @@ static int intel_sst_mmap_play_capture(u32 str_id, stream->status = STREAM_RUNNING; if (stream->ops == STREAM_OPS_PLAYBACK) { if (sst_play_frame(str_id) < 0) { - pr_warn("sst: play frames fail\n"); + pr_warn("play frames fail\n"); mutex_unlock(&stream->lock); return -EIO; } } else if (stream->ops == STREAM_OPS_CAPTURE) { if (sst_capture_frame(str_id) < 0) { - pr_warn("sst: capture frame fail\n"); + pr_warn("capture frame fail\n"); mutex_unlock(&stream->lock); return -EIO; } @@ -313,7 +315,7 @@ static int intel_sst_mmap_play_capture(u32 str_id, if (retval >= 0) retval = stream->cumm_bytes; - pr_debug("sst:end of play/rec ioctl bytes = %d!!\n", retval); + pr_debug("end of play/rec ioctl bytes = %d!!\n", retval); return retval; } @@ -335,7 +337,7 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id) if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) { /* stream is not started yet */ - pr_debug("sst: Stream isn't in started state %d, prev %d\n", + pr_debug("Stream isn't in started state %d, prev %d\n", stream->status, stream->prev); } else if ((stream->status == STREAM_RUNNING || stream->status == STREAM_PAUSED) && @@ -344,13 +346,13 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id) if (stream->ops == STREAM_OPS_PLAYBACK || stream->ops == STREAM_OPS_PLAYBACK_DRM) { if (sst_play_frame(str_id) < 0) { - pr_warn("sst: play frames failed\n"); + pr_warn("play frames failed\n"); mutex_unlock(&stream->lock); return -EIO; } } else if (stream->ops == STREAM_OPS_CAPTURE) { if (sst_capture_frame(str_id) < 0) { - pr_warn("sst: capture frames failed\n "); + pr_warn("capture frames failed\n"); mutex_unlock(&stream->lock); return -EIO; } @@ -365,7 +367,7 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id) retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk); if (retval) { stream->status = STREAM_INIT; - pr_debug("sst: wait returned error...\n"); + pr_debug("wait returned error...\n"); } return retval; } @@ -463,7 +465,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream, if (((unsigned long)iovec[index].iov_base + iovec[index].iov_len) < ((unsigned long)iovec[index].iov_base)) { - pr_debug("sst: Buffer overflows"); + pr_debug("Buffer overflows\n"); kfree(stream_bufs); return -EINVAL; } @@ -476,7 +478,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream, } copied_size += size; - pr_debug("sst: copied_size - %lx\n", copied_size); + pr_debug("copied_size - %lx\n", copied_size); if ((copied_size >= mmap_len) || (stream->sg_index == nr_segs)) { add_to_list = 1; @@ -506,7 +508,7 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream, int retval = 0; /* copy sent buffers */ - pr_debug("sst: capture stream copying to user now...\n"); + pr_debug("capture stream copying to user now...\n"); list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) { if (kbufs->in_use == true) { /* copy to user */ @@ -526,7 +528,7 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream, } } } - pr_debug("sst: end of cap copy\n"); + pr_debug("end of cap copy\n"); return retval; } @@ -578,7 +580,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf, return -EINVAL; stream = &sst_drv_ctx->streams[str_id]; if (stream->mmapped == true) { - pr_warn("sst: user write and stream is mapped"); + pr_warn("user write and stream is mapped\n"); return -EIO; } if (!count) @@ -586,7 +588,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf, stream->curr_bytes = 0; stream->cumm_bytes = 0; /* copy user buf details */ - pr_debug("sst: new buffers %p, copy size %d, status %d\n" , + pr_debug("new buffers %p, copy size %d, status %d\n" , buf, (int) count, (int) stream->status); stream->buf_type = SST_BUF_USER_STATIC; @@ -606,7 +608,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf, stream->cur_ptr = NULL; if (retval >= 0) retval = stream->cumm_bytes; - pr_debug("sst: end of play/rec bytes = %d!!\n", retval); + pr_debug("end of play/rec bytes = %d!!\n", retval); return retval; } @@ -627,7 +629,7 @@ int intel_sst_write(struct file *file_ptr, const char __user *buf, int str_id = data->str_id; struct stream_info *stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst: called for %d\n", str_id); + pr_debug("called for %d\n", str_id); if (stream->status == STREAM_UN_INIT || stream->status == STREAM_DECODE) { return -EBADRQC; @@ -653,12 +655,12 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, int str_id = data->str_id; struct stream_info *stream; - pr_debug("sst: entry - %ld\n", nr_segs); + pr_debug("entry - %ld\n", nr_segs); if (is_sync_kiocb(kiocb) == false) return -EINVAL; - pr_debug("sst: called for str_id %d\n", str_id); + pr_debug("called for str_id %d\n", str_id); retval = sst_validate_strid(str_id); if (retval) return -EINVAL; @@ -671,7 +673,7 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, } stream->curr_bytes = 0; stream->cumm_bytes = 0; - pr_debug("sst: new segs %ld, offset %d, status %d\n" , + pr_debug("new segs %ld, offset %d, status %d\n" , nr_segs, (int) offset, (int) stream->status); stream->buf_type = SST_BUF_USER_STATIC; do { @@ -686,7 +688,7 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov, stream->cur_ptr = NULL; if (retval >= 0) retval = stream->cumm_bytes; - pr_debug("sst: end of play/rec bytes = %d!!\n", retval); + pr_debug("end of play/rec bytes = %d!!\n", retval); return retval; } @@ -707,7 +709,7 @@ int intel_sst_read(struct file *file_ptr, char __user *buf, int str_id = data->str_id; struct stream_info *stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst: called for %d\n", str_id); + pr_debug("called for %d\n", str_id); if (stream->status == STREAM_UN_INIT || stream->status == STREAM_DECODE) return -EBADRQC; @@ -732,14 +734,14 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, int str_id = data->str_id; struct stream_info *stream; - pr_debug("sst: entry - %ld\n", nr_segs); + pr_debug("entry - %ld\n", nr_segs); if (is_sync_kiocb(kiocb) == false) { - pr_debug("sst: aio_read from user space is not allowed\n"); + pr_debug("aio_read from user space is not allowed\n"); return -EINVAL; } - pr_debug("sst: called for str_id %d\n", str_id); + pr_debug("called for str_id %d\n", str_id); retval = sst_validate_strid(str_id); if (retval) return -EINVAL; @@ -752,7 +754,7 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, stream->curr_bytes = 0; stream->cumm_bytes = 0; - pr_debug("sst: new segs %ld, offset %d, status %d\n" , + pr_debug("new segs %ld, offset %d, status %d\n" , nr_segs, (int) offset, (int) stream->status); stream->buf_type = SST_BUF_USER_STATIC; do { @@ -767,34 +769,34 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov, stream->cur_ptr = NULL; if (retval >= 0) retval = stream->cumm_bytes; - pr_debug("sst: end of play/rec bytes = %d!!\n", retval); + pr_debug("end of play/rec bytes = %d!!\n", retval); return retval; } /* sst_print_stream_params - prints the stream parameters (debug fn)*/ static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm) { - pr_debug("sst: codec params:result =%d\n", + pr_debug("codec params:result = %d\n", get_prm->codec_params.result); - pr_debug("sst: codec params:stream = %d\n", + pr_debug("codec params:stream = %d\n", get_prm->codec_params.stream_id); - pr_debug("sst: codec params:codec = %d\n", + pr_debug("codec params:codec = %d\n", get_prm->codec_params.codec); - pr_debug("sst: codec params:ops = %d\n", + pr_debug("codec params:ops = %d\n", get_prm->codec_params.ops); - pr_debug("sst: codec params:stream_type= %d\n", + pr_debug("codec params:stream_type = %d\n", get_prm->codec_params.stream_type); - pr_debug("sst: pcmparams:sfreq= %d\n", + pr_debug("pcmparams:sfreq = %d\n", get_prm->pcm_params.sfreq); - pr_debug("sst: pcmparams:num_chan= %d\n", + pr_debug("pcmparams:num_chan = %d\n", get_prm->pcm_params.num_chan); - pr_debug("sst: pcmparams:pcm_wd_sz= %d\n", + pr_debug("pcmparams:pcm_wd_sz = %d\n", get_prm->pcm_params.pcm_wd_sz); return; } /** - * intel_sst_ioctl - recieves the device ioctl's + * intel_sst_ioctl - receives the device ioctl's * @file_ptr:pointer to file * @cmd:Ioctl cmd * @arg:data @@ -820,7 +822,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) switch (_IOC_NR(cmd)) { case _IOC_NR(SNDRV_SST_STREAM_PAUSE): - pr_debug("sst: IOCTL_PAUSE recieved for %d!\n", str_id); + pr_debug("IOCTL_PAUSE received for %d!\n", str_id); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -829,7 +831,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) break; case _IOC_NR(SNDRV_SST_STREAM_RESUME): - pr_debug("sst: SNDRV_SST_IOCTL_RESUME recieved!\n"); + pr_debug("SNDRV_SST_IOCTL_RESUME received!\n"); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -840,7 +842,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): { struct snd_sst_params *str_param = (struct snd_sst_params *)arg; - pr_debug("sst: IOCTL_SET_PARAMS recieved!\n"); + pr_debug("IOCTL_SET_PARAMS received!\n"); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -864,7 +866,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) retval = -EINVAL; } } else { - pr_debug("sst: SET_STREAM_PARAMS recieved!\n"); + pr_debug("SET_STREAM_PARAMS received!\n"); /* allocated set params only */ retval = sst_set_stream_param(str_id, str_param); /* Block the call for reply */ @@ -887,21 +889,21 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_SET_VOL): { struct snd_sst_vol *set_vol; struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg; - pr_debug("sst: SET_VOLUME recieved for %d!\n", + pr_debug("SET_VOLUME received for %d!\n", rec_vol->stream_id); if (minor == STREAM_MODULE && rec_vol->stream_id == 0) { - pr_debug("sst: invalid operation!\n"); + pr_debug("invalid operation!\n"); retval = -EPERM; break; } set_vol = kzalloc(sizeof(*set_vol), GFP_ATOMIC); if (!set_vol) { - pr_debug("sst: mem allocation failed\n"); + pr_debug("mem allocation failed\n"); retval = -ENOMEM; break; } if (copy_from_user(set_vol, rec_vol, sizeof(*set_vol))) { - pr_debug("sst: copy failed\n"); + pr_debug("copy failed\n"); retval = -EFAULT; break; } @@ -912,10 +914,10 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_GET_VOL): { struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg; struct snd_sst_vol get_vol; - pr_debug("sst: IOCTL_GET_VOLUME recieved for stream = %d!\n", + pr_debug("IOCTL_GET_VOLUME received for stream = %d!\n", rec_vol->stream_id); if (minor == STREAM_MODULE && rec_vol->stream_id == 0) { - pr_debug("sst: invalid operation!\n"); + pr_debug("invalid operation!\n"); retval = -EPERM; break; } @@ -925,7 +927,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) retval = -EIO; break; } - pr_debug("sst: id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n", + pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n", get_vol.stream_id, get_vol.volume, get_vol.ramp_duration, get_vol.ramp_type); if (copy_to_user((struct snd_sst_vol *)arg, @@ -940,7 +942,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_MUTE): { struct snd_sst_mute *set_mute; struct snd_sst_vol *rec_mute = (struct snd_sst_vol *)arg; - pr_debug("sst: SNDRV_SST_SET_VOLUME recieved for %d!\n", + pr_debug("SNDRV_SST_SET_VOLUME received for %d!\n", rec_mute->stream_id); if (minor == STREAM_MODULE && rec_mute->stream_id == 0) { retval = -EPERM; @@ -962,7 +964,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): { struct snd_sst_get_stream_params get_params; - pr_debug("sst: IOCTL_GET_PARAMS recieved!\n"); + pr_debug("IOCTL_GET_PARAMS received!\n"); if (minor != 0) { retval = -EBADRQC; break; @@ -984,7 +986,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_MMAP_PLAY): case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): - pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n"); + pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE received!\n"); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -994,7 +996,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) break; case _IOC_NR(SNDRV_SST_STREAM_DROP): - pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n"); + pr_debug("SNDRV_SST_IOCTL_DROP received!\n"); if (minor != STREAM_MODULE) { retval = -EINVAL; break; @@ -1007,7 +1009,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) struct snd_sst_tstamp tstamp = {0}; unsigned long long time, freq, mod; - pr_debug("sst: SNDRV_SST_STREAM_GET_TSTAMP recieved!\n"); + pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n"); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -1028,7 +1030,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_STREAM_START):{ struct stream_info *stream; - pr_debug("sst: SNDRV_SST_STREAM_START recieved!\n"); + pr_debug("SNDRV_SST_STREAM_START received!\n"); if (minor != STREAM_MODULE) { retval = -EINVAL; break; @@ -1067,7 +1069,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { struct snd_sst_target_device *target_device; - pr_debug("sst: SET_TARGET_DEVICE recieved!\n"); + pr_debug("SET_TARGET_DEVICE received!\n"); target_device = (struct snd_sst_target_device *)arg; BUG_ON(!target_device); if (minor != AM_MODULE) { @@ -1082,7 +1084,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) struct snd_sst_driver_info *info = (struct snd_sst_driver_info *)arg; - pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n"); + pr_debug("SNDRV_SST_DRIVER_INFO received\n"); info->version = SST_VERSION_NUM; /* hard coding, shud get sumhow later */ info->active_pcm_streams = sst_drv_ctx->stream_cnt - @@ -1102,7 +1104,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries], obuf_temp[param->obufs->entries]; - pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n"); + pr_debug("SNDRV_SST_STREAM_DECODE received\n"); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -1155,7 +1157,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) } case _IOC_NR(SNDRV_SST_STREAM_DRAIN): - pr_debug("sst: SNDRV_SST_STREAM_DRAIN recived\n"); + pr_debug("SNDRV_SST_STREAM_DRAIN received\n"); if (minor != STREAM_MODULE) { retval = -EINVAL; break; @@ -1167,7 +1169,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) unsigned long long *bytes = (unsigned long long *)arg; struct snd_sst_tstamp tstamp = {0}; - pr_debug("sst: STREAM_BYTES_DECODED recieved!\n"); + pr_debug("STREAM_BYTES_DECODED received!\n"); if (minor != STREAM_MODULE) { retval = -EINVAL; break; @@ -1184,7 +1186,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_FW_INFO): { struct snd_sst_fw_info *fw_info; - pr_debug("sst: SNDRV_SST_FW_INFO recived\n"); + pr_debug("SNDRV_SST_FW_INFO received\n"); fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC); if (!fw_info) { @@ -1210,7 +1212,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) default: retval = -EINVAL; } - pr_debug("sst: intel_sst_ioctl:complete ret code = %d\n", retval); + pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval); return retval; } diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index 669e298016f2..5b10ddf60092 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -26,6 +26,8 @@ * Upper layer interfaces (MAD driver, MMF) to SST driver */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -52,10 +54,10 @@ int sst_download_fw(void) name = SST_FW_FILENAME_MRST; else name = SST_FW_FILENAME_MFLD; - pr_debug("sst: Downloading %s FW now...\n", name); + pr_debug("Downloading %s FW now...\n", name); retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev); if (retval) { - pr_err("sst: request fw failed %d\n", retval); + pr_err("request fw failed %d\n", retval); return retval; } sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID; @@ -66,7 +68,7 @@ int sst_download_fw(void) retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]); if (retval) - pr_err("sst: fw download failed %d\n" , retval); + pr_err("fw download failed %d\n" , retval); end_restore: release_firmware(fw_sst); sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT; @@ -90,7 +92,7 @@ int sst_stalled(void) retry--; } - pr_debug("sst: in Stalled State\n"); + pr_debug("in Stalled State\n"); return retval; } @@ -138,23 +140,23 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param, retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops, str_param->codec, str_param->device_type); if (retval < 0) { - pr_err("sst: sst_alloc_stream failed %d\n", retval); + pr_err("sst_alloc_stream failed %d\n", retval); return retval; } - pr_debug("sst: Stream allocated %d\n", retval); + pr_debug("Stream allocated %d\n", retval); str_id = retval; str_info = &sst_drv_ctx->streams[str_id]; /* Block the call for reply */ retval = sst_wait_interruptible_timeout(sst_drv_ctx, &str_info->ctrl_blk, SST_BLOCK_TIMEOUT); if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) { - pr_debug("sst: FW alloc failed retval %d, ret_code %d\n", + pr_debug("FW alloc failed retval %d, ret_code %d\n", retval, str_info->ctrl_blk.ret_code); str_id = -str_info->ctrl_blk.ret_code; /*return error*/ *lib_dnld = str_info->ctrl_blk.data; sst_clean_stream(str_info); } else - pr_debug("sst: FW Stream allocated sucess\n"); + pr_debug("FW Stream allocated success\n"); return str_id; /*will ret either error (in above if) or correct str id*/ } @@ -196,14 +198,14 @@ int sst_get_stream(struct snd_sst_params *str_param) /* codec download is required */ struct snd_sst_alloc_response *response; - pr_debug("sst: Codec is required.... trying that\n"); + pr_debug("Codec is required.... trying that\n"); if (lib_dnld == NULL) { - pr_err("sst: lib download null!!! abort\n"); + pr_err("lib download null!!! abort\n"); return -EIO; } i = sst_get_block_stream(sst_drv_ctx); response = sst_drv_ctx->alloc_block[i].ops_block.data; - pr_debug("sst: alloc block allocated = %d\n", i); + pr_debug("alloc block allocated = %d\n", i); if (i < 0) { kfree(lib_dnld); return -ENOMEM; @@ -213,15 +215,15 @@ int sst_get_stream(struct snd_sst_params *str_param) sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; if (!retval) { - pr_debug("sst: codec was downloaded sucesfully\n"); + pr_debug("codec was downloaded successfully\n"); retval = sst_get_stream_allocated(str_param, &lib_dnld); if (retval <= 0) goto err; - pr_debug("sst: Alloc done stream id %d\n", retval); + pr_debug("Alloc done stream id %d\n", retval); } else { - pr_debug("sst: codec download failed\n"); + pr_debug("codec download failed\n"); retval = -EIO; goto err; } @@ -279,10 +281,10 @@ void sst_process_mad_ops(struct work_struct *work) retval = sst_start_stream(mad_ops->stream_id); break; case SST_SND_STREAM_PROCESS: - pr_debug("sst: play/capt frames...\n"); + pr_debug("play/capt frames...\n"); break; default: - pr_err("sst: wrong control_ops reported\n"); + pr_err(" wrong control_ops reported\n"); } return; } @@ -301,19 +303,19 @@ int sst_control_set(int control_element, void *value) if (sst_drv_ctx->sst_state == SST_SUSPENDED) { /*LPE is suspended, resume it before proceding*/ - pr_debug("sst: Resuming from Suspended state\n"); + pr_debug("Resuming from Suspended state\n"); retval = intel_sst_resume(sst_drv_ctx->pci); if (retval) { - pr_err("sst: Resume Failed = %#x, abort\n", retval); + pr_err("Resume Failed = %#x, abort\n", retval); return retval; } } if (sst_drv_ctx->sst_state == SST_UN_INIT) { /* FW is not downloaded */ - pr_debug("sst: DSP Downloading FW now...\n"); + pr_debug("DSP Downloading FW now...\n"); retval = sst_download_fw(); if (retval) { - pr_err("sst: FW download fail %x, abort\n", retval); + pr_err("FW download fail %x, abort\n", retval); return retval; } if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID && @@ -361,7 +363,7 @@ int sst_control_set(int control_element, void *value) struct pcm_stream_info *str_info; struct stream_info *stream; - pr_debug("sst: stream init called\n"); + pr_debug("stream init called\n"); str_info = (struct pcm_stream_info *)value; str_id = str_info->str_id; retval = sst_validate_strid(str_id); @@ -369,7 +371,7 @@ int sst_control_set(int control_element, void *value) break; stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst: setting the period ptrs\n"); + pr_debug("setting the period ptrs\n"); stream->pcm_substream = str_info->mad_substream; stream->period_elapsed = str_info->period_elapsed; stream->sfreq = str_info->sfreq; @@ -398,14 +400,14 @@ int sst_control_set(int control_element, void *value) +(str_id * sizeof(fw_tstamp))), sizeof(fw_tstamp)); - pr_debug("sst: Pointer Query on strid = %d ops %d\n", + pr_debug("Pointer Query on strid = %d ops %d\n", str_id, stream->ops); if (stream->ops == STREAM_OPS_PLAYBACK) stream_info->buffer_ptr = fw_tstamp.samples_rendered; else stream_info->buffer_ptr = fw_tstamp.samples_processed; - pr_debug("sst: Samples rendered = %llu, buffer ptr %llu\n", + pr_debug("Samples rendered = %llu, buffer ptr %llu\n", fw_tstamp.samples_rendered, stream_info->buffer_ptr); break; } @@ -417,7 +419,7 @@ int sst_control_set(int control_element, void *value) } default: /* Illegal case */ - pr_warn("sst: illegal req\n"); + pr_warn("illegal req\n"); return -EINVAL; } @@ -439,12 +441,12 @@ struct intel_sst_card_ops sst_pmic_ops = { int register_sst_card(struct intel_sst_card_ops *card) { if (!sst_drv_ctx) { - pr_err("sst: No SST driver register card reject\n"); + pr_err("No SST driver register card reject\n"); return -ENODEV; } if (!card || !card->module_name) { - pr_err("sst: Null Pointer Passed\n"); + pr_err("Null Pointer Passed\n"); return -EINVAL; } if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) { @@ -460,13 +462,13 @@ int register_sst_card(struct intel_sst_card_ops *card) sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT; return 0; } else { - pr_err("sst: strcmp fail %s\n", card->module_name); + pr_err("strcmp fail %s\n", card->module_name); return -EINVAL; } } else { /* already registered a driver */ - pr_err("sst: Repeat for registeration..denied\n"); + pr_err("Repeat for registration..denied\n"); return -EBADRQC; } return 0; @@ -486,7 +488,7 @@ void unregister_sst_card(struct intel_sst_card_ops *card) /* unreg */ sst_pmic_ops.module_name = ""; sst_drv_ctx->pmic_state = SND_MAD_UN_INIT; - pr_debug("sst: Unregistered %s\n", card->module_name); + pr_debug("Unregistered %s\n", card->module_name); } return; } diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c index d80a6ee2deb8..d1b0537cf4b8 100644 --- a/drivers/staging/intel_sst/intel_sst_dsp.c +++ b/drivers/staging/intel_sst/intel_sst_dsp.c @@ -29,6 +29,9 @@ * This file contains all dsp controlling functions like firmware download, * setting/resetting dsp cores, etc */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -47,7 +50,7 @@ static int intel_sst_reset_dsp_mrst(void) { union config_status_reg csr; - pr_debug("sst: Resetting the DSP in mrst\n"); + pr_debug("Resetting the DSP in mrst\n"); csr.full = 0x3a2; sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); @@ -68,7 +71,7 @@ static int intel_sst_reset_dsp_medfield(void) { union config_status_reg csr; - pr_debug("sst: Resetting the DSP in medfield\n"); + pr_debug("Resetting the DSP in medfield\n"); csr.full = 0x048303E2; sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); @@ -90,7 +93,7 @@ static int sst_start_mrst(void) csr.part.run_stall = 0; csr.part.sst_reset = 0; csr.part.strb_cntr_rst = 1; - pr_debug("sst: Setting SST to execute_mrst 0x%x\n", csr.full); + pr_debug("Setting SST to execute_mrst 0x%x\n", csr.full); sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); return 0; @@ -111,7 +114,7 @@ static int sst_start_medfield(void) sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); csr.full = 0x04830061; sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); - pr_debug("sst: Starting the DSP_medfld\n"); + pr_debug("Starting the DSP_medfld\n"); return 0; } @@ -130,16 +133,16 @@ static int sst_parse_module(struct fw_module_header *module) u32 count; void __iomem *ram; - pr_debug("sst: module sign %s size %x blocks %x type %x\n", + pr_debug("module sign %s size %x blocks %x type %x\n", module->signature, module->mod_size, module->blocks, module->type); - pr_debug("sst: module entrypoint 0x%x\n", module->entry_point); + pr_debug("module entrypoint 0x%x\n", module->entry_point); block = (void *)module + sizeof(*module); for (count = 0; count < module->blocks; count++) { if (block->size <= 0) { - pr_err("sst: block size invalid\n"); + pr_err("block size invalid\n"); return -EINVAL; } switch (block->type) { @@ -150,7 +153,7 @@ static int sst_parse_module(struct fw_module_header *module) ram = sst_drv_ctx->dram; break; default: - pr_err("sst: wrong ram type0x%x in block0x%x\n", + pr_err("wrong ram type0x%x in block0x%x\n", block->type, count); return -EINVAL; } @@ -184,10 +187,10 @@ static int sst_parse_fw_image(const struct firmware *sst_fw) if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) || (sst_fw->size != header->file_size + sizeof(*header))) { /* Invalid FW signature */ - pr_err("sst: InvalidFW sign/filesize mismatch\n"); + pr_err("Invalid FW sign/filesize mismatch\n"); return -EINVAL; } - pr_debug("sst: header sign=%s size=%x modules=%x fmt=%x size=%x\n", + pr_debug("header sign=%s size=%x modules=%x fmt=%x size=%x\n", header->signature, header->file_size, header->modules, header->file_format, sizeof(*header)); module = (void *)sst_fw->data + sizeof(*header); @@ -214,7 +217,7 @@ int sst_load_fw(const struct firmware *fw, void *context) { int ret_val; - pr_debug("sst: load_fw called\n"); + pr_debug("load_fw called\n"); BUG_ON(!fw); if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) @@ -239,7 +242,7 @@ int sst_load_fw(const struct firmware *fw, void *context) if (ret_val) return ret_val; - pr_debug("sst: fw loaded successful!!!\n"); + pr_debug("fw loaded successful!!!\n"); return ret_val; } @@ -261,7 +264,7 @@ static int sst_download_library(const struct firmware *fw_lib, pvt_id = sst_assign_pvt_id(sst_drv_ctx); i = sst_get_block_stream(sst_drv_ctx); - pr_debug("sst: alloc block allocated = %d, pvt_id %d\n", i, pvt_id); + pr_debug("alloc block allocated = %d, pvt_id %d\n", i, pvt_id); if (i < 0) { kfree(msg); return -ENOMEM; @@ -281,11 +284,11 @@ static int sst_download_library(const struct firmware *fw_lib, if (retval) { /* error */ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; - pr_err("sst: Prep codec downloaded failed %d\n", + pr_err("Prep codec downloaded failed %d\n", retval); return -EIO; } - pr_debug("sst: FW responded, ready for download now...\n"); + pr_debug("FW responded, ready for download now...\n"); /* downloading on success */ mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_FW_LOADED; @@ -325,7 +328,7 @@ static int sst_download_library(const struct firmware *fw_lib, list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); spin_unlock(&sst_drv_ctx->list_spin_lock); sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - pr_debug("sst: Waiting for FW response Download complete\n"); + pr_debug("Waiting for FW response Download complete\n"); sst_drv_ctx->alloc_block[i].ops_block.condition = false; retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]); if (retval) { @@ -337,7 +340,7 @@ static int sst_download_library(const struct firmware *fw_lib, return -EIO; } - pr_debug("sst: FW sucess on Download complete\n"); + pr_debug("FW success on Download complete\n"); sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT; mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_FW_RUNNING; @@ -360,14 +363,14 @@ static int sst_validate_library(const struct firmware *fw_lib, header = (struct fw_header *)fw_lib->data; if (header->modules != 1) { - pr_err("sst: Module no mismatch found\n "); + pr_err("Module no mismatch found\n"); err = -EINVAL; goto exit; } module = (void *)fw_lib->data + sizeof(*header); *entry_point = module->entry_point; - pr_debug("sst: Module entry point 0x%x\n", *entry_point); - pr_debug("sst: Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n", + pr_debug("Module entry point 0x%x\n", *entry_point); + pr_debug("Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n", module->signature, module->mod_size, module->blocks, module->type); @@ -381,20 +384,20 @@ static int sst_validate_library(const struct firmware *fw_lib, dsize += block->size; break; default: - pr_err("sst: Invalid block type for 0x%x\n", n_blk); + pr_err("Invalid block type for 0x%x\n", n_blk); err = -EINVAL; goto exit; } block = (void *)block + sizeof(*block) + block->size; } if (isize > slot->iram_size || dsize > slot->dram_size) { - pr_err("sst: library exceeds size allocated\n"); + pr_err("library exceeds size allocated\n"); err = -EINVAL; goto exit; } else - pr_debug("sst: Library is safe for download...\n"); + pr_debug("Library is safe for download...\n"); - pr_debug("sst: iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n", + pr_debug("iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n", isize, dsize, slot->iram_size, slot->dram_size); exit: return err; @@ -414,15 +417,15 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops) memset(buf, 0, sizeof(buf)); - pr_debug("sst: Lib Type 0x%x, Slot 0x%x, ops 0x%x\n", + pr_debug("Lib Type 0x%x, Slot 0x%x, ops 0x%x\n", lib->lib_info.lib_type, lib->slot_info.slot_num, ops); - pr_debug("sst: Version 0x%x, name %s, caps 0x%x media type 0x%x\n", + pr_debug("Version 0x%x, name %s, caps 0x%x media type 0x%x\n", lib->lib_info.lib_version, lib->lib_info.lib_name, lib->lib_info.lib_caps, lib->lib_info.media_type); - pr_debug("sst: IRAM Size 0x%x, offset 0x%x\n", + pr_debug("IRAM Size 0x%x, offset 0x%x\n", lib->slot_info.iram_size, lib->slot_info.iram_offset); - pr_debug("sst: DRAM Size 0x%x, offset 0x%x\n", + pr_debug("DRAM Size 0x%x, offset 0x%x\n", lib->slot_info.dram_size, lib->slot_info.dram_offset); switch (lib->lib_info.lib_type) { @@ -442,7 +445,7 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops) type = "wma9_"; break; default: - pr_err("sst: Invalid codec type\n"); + pr_err("Invalid codec type\n"); error = -EINVAL; goto wake; } @@ -458,11 +461,11 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops) lib->slot_info.slot_num); len += snprintf(buf + len, sizeof(buf) - len, ".bin"); - pr_debug("sst: Requesting %s\n", buf); + pr_debug("Requesting %s\n", buf); error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev); if (error) { - pr_err("sst: library load failed %d\n", error); + pr_err("library load failed %d\n", error); goto wake; } error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point); @@ -476,7 +479,7 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops) goto wake_free; /* lib is downloaded and init send alloc again */ - pr_debug("sst: Library is downloaded now...\n"); + pr_debug("Library is downloaded now...\n"); wake_free: /* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */ release_firmware(fw_lib); diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c index 39c67fa0bd0c..993c5333e906 100644 --- a/drivers/staging/intel_sst/intel_sst_ipc.c +++ b/drivers/staging/intel_sst/intel_sst_ipc.c @@ -26,6 +26,8 @@ * This file defines all ipc functions */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -75,16 +77,16 @@ void sst_post_message(struct work_struct *work) /*To check if LPE is in stalled state.*/ retval = sst_stalled(); if (retval < 0) { - pr_err("sst: in stalled state\n"); + pr_err("in stalled state\n"); return; } - pr_debug("sst: post message called\n"); + pr_debug("post message called\n"); spin_lock(&sst_drv_ctx->list_spin_lock); /* check list */ if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { /* list is empty, mask imr */ - pr_debug("sst: Empty msg queue... masking\n"); + pr_debug("Empty msg queue... masking\n"); imr.full = readl(sst_drv_ctx->shim + SST_IMRX); imr.part.done_interrupt = 1; /* dummy register for shim workaround */ @@ -97,7 +99,7 @@ void sst_post_message(struct work_struct *work) header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX); if (header.part.busy) { /* busy, unmask */ - pr_debug("sst: Busy not free... unmasking\n"); + pr_debug("Busy not free... unmasking\n"); imr.full = readl(sst_drv_ctx->shim + SST_IMRX); imr.part.done_interrupt = 0; /* dummy register for shim workaround */ @@ -109,8 +111,8 @@ void sst_post_message(struct work_struct *work) msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, struct ipc_post, node); list_del(&msg->node); - pr_debug("sst: Post message: header = %x\n", msg->header.full); - pr_debug("sst: size: = %x\n", msg->header.part.data); + pr_debug("Post message: header = %x\n", msg->header.full); + pr_debug("size: = %x\n", msg->header.part.data); if (msg->header.part.large) memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, msg->mailbox_data, msg->header.part.data); @@ -166,13 +168,13 @@ int process_fw_init(struct sst_ipc_msg_wq *msg) (struct ipc_header_fw_init *)msg->mailbox; int retval = 0; - pr_debug("sst: *** FW Init msg came***\n"); + pr_debug("*** FW Init msg came***\n"); if (init->result) { mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_ERROR; mutex_unlock(&sst_drv_ctx->sst_lock); - pr_debug("sst: FW Init failed, Error %x\n", init->result); - pr_err("sst: FW Init failed, Error %x\n", init->result); + pr_debug("FW Init failed, Error %x\n", init->result); + pr_err("FW Init failed, Error %x\n", init->result); retval = -init->result; return retval; } @@ -181,11 +183,11 @@ int process_fw_init(struct sst_ipc_msg_wq *msg) mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_FW_RUNNING; mutex_unlock(&sst_drv_ctx->sst_lock); - pr_debug("sst: FW Version %x.%x\n", + pr_debug("FW Version %x.%x\n", init->fw_version.major, init->fw_version.minor); - pr_debug("sst: Build No %x Type %x\n", + pr_debug("Build No %x Type %x\n", init->fw_version.build, init->fw_version.type); - pr_debug("sst: Build date %s Time %s\n", + pr_debug(" Build date %s Time %s\n", init->build_info.date, init->build_info.time); sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL); return retval; @@ -204,19 +206,19 @@ void sst_process_message(struct work_struct *work) container_of(work, struct sst_ipc_msg_wq, wq); int str_id = msg->header.part.str_id; - pr_debug("sst: IPC process for %x\n", msg->header.full); + pr_debug("IPC process for %x\n", msg->header.full); /* based on msg in list call respective handler */ switch (msg->header.part.msg_id) { case IPC_SST_BUF_UNDER_RUN: case IPC_SST_BUF_OVER_RUN: if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n", str_id); + pr_err("stream id %d invalid\n", str_id); break; } - pr_err("sst: Buffer under/overrun for%d\n", + pr_err("Buffer under/overrun for %d\n", msg->header.part.str_id); - pr_err("sst: Got Underrun & not to send data...ignore\n"); + pr_err("Got Underrun & not to send data...ignore\n"); break; case IPC_SST_GET_PLAY_FRAMES: @@ -224,35 +226,35 @@ void sst_process_message(struct work_struct *work) struct stream_info *stream ; if (sst_validate_strid(str_id)) { - pr_err("sst: strid %d invalid\n", str_id); + pr_err("strid %d invalid\n", str_id); break; } /* call sst_play_frame */ stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst: sst_play_frames for %d\n", + pr_debug("sst_play_frames for %d\n", msg->header.part.str_id); mutex_lock(&sst_drv_ctx->streams[str_id].lock); sst_play_frame(msg->header.part.str_id); mutex_unlock(&sst_drv_ctx->streams[str_id].lock); break; } else - pr_err("sst: sst_play_frames for Penwell!!\n"); + pr_err("sst_play_frames for Penwell!!\n"); case IPC_SST_GET_CAPT_FRAMES: if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { struct stream_info *stream; /* call sst_capture_frame */ if (sst_validate_strid(str_id)) { - pr_err("sst: str id %d invalid\n", str_id); + pr_err("str id %d invalid\n", str_id); break; } stream = &sst_drv_ctx->streams[str_id]; - pr_debug("sst: sst_capture_frames for %d\n", + pr_debug("sst_capture_frames for %d\n", msg->header.part.str_id); mutex_lock(&stream->lock); if (stream->mmapped == false && stream->src == SST_DRV) { - pr_debug("sst: waking up block for copy.\n"); + pr_debug("waking up block for copy.\n"); stream->data_blk.ret_code = 0; stream->data_blk.condition = true; stream->data_blk.on = false; @@ -261,11 +263,11 @@ void sst_process_message(struct work_struct *work) sst_capture_frame(msg->header.part.str_id); mutex_unlock(&stream->lock); } else - pr_err("sst: sst_play_frames for Penwell!!\n"); + pr_err("sst_play_frames for Penwell!!\n"); break; case IPC_IA_PRINT_STRING: - pr_debug("sst: been asked to print something by fw\n"); + pr_debug("been asked to print something by fw\n"); /* TBD */ break; @@ -277,12 +279,12 @@ void sst_process_message(struct work_struct *work) case IPC_SST_STREAM_PROCESS_FATAL_ERR: if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n", str_id); + pr_err("stream id %d invalid\n", str_id); break; } - pr_err("sst: codec fatal error %x stream %d...\n", + pr_err("codec fatal error %x stream %d...\n", msg->header.full, msg->header.part.str_id); - pr_err("sst: Dropping the stream\n"); + pr_err("Dropping the stream\n"); sst_drop_stream(msg->header.part.str_id); break; case IPC_IA_LPE_GETTING_STALLED: @@ -293,7 +295,7 @@ void sst_process_message(struct work_struct *work) break; default: /* Illegal case */ - pr_err("sst: Unhandled msg %x header %x\n", + pr_err("Unhandled msg %x header %x\n", msg->header.part.msg_id, msg->header.full); } sst_clear_interrupt(); @@ -322,7 +324,7 @@ void sst_process_reply(struct work_struct *work) if (!msg->header.part.data) { sst_drv_ctx->tgt_dev_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); sst_drv_ctx->tgt_dev_blk.ret_code = -msg->header.part.data; @@ -340,7 +342,7 @@ void sst_process_reply(struct work_struct *work) int major = fw_info->fw_version.major; int minor = fw_info->fw_version.minor; int build = fw_info->fw_version.build; - pr_debug("sst: Msg succedded %x\n", + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n", major, minor, build); @@ -349,13 +351,13 @@ void sst_process_reply(struct work_struct *work) sizeof(struct snd_sst_fw_info)); sst_drv_ctx->fw_info_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); sst_drv_ctx->fw_info_blk.ret_code = -msg->header.part.data; } if (sst_drv_ctx->fw_info_blk.on == true) { - pr_debug("sst: Memcopy succedded\n"); + pr_debug("Memcopy succeeded\n"); sst_drv_ctx->fw_info_blk.on = false; sst_drv_ctx->fw_info_blk.condition = true; wake_up(&sst_drv_ctx->wait_queue); @@ -364,11 +366,11 @@ void sst_process_reply(struct work_struct *work) } case IPC_IA_SET_STREAM_MUTE: if (!msg->header.part.data) { - pr_debug("sst: Msg succedded %x\n", + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); sst_drv_ctx->mute_info_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); sst_drv_ctx->mute_info_blk.ret_code = -msg->header.part.data; @@ -382,11 +384,11 @@ void sst_process_reply(struct work_struct *work) break; case IPC_IA_SET_STREAM_VOL: if (!msg->header.part.data) { - pr_debug("sst: Msg succedded %x\n", + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); sst_drv_ctx->vol_info_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); sst_drv_ctx->vol_info_blk.ret_code = @@ -402,15 +404,15 @@ void sst_process_reply(struct work_struct *work) break; case IPC_IA_GET_STREAM_VOL: if (msg->header.part.large) { - pr_debug("sst: Large Msg Received Successfully\n"); - pr_debug("sst: Msg succedded %x\n", + pr_debug("Large Msg Received Successfully\n"); + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); memcpy_fromio(sst_drv_ctx->vol_info_blk.data, (void *) msg->mailbox, sizeof(struct snd_sst_vol)); sst_drv_ctx->vol_info_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err("Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); sst_drv_ctx->vol_info_blk.ret_code = -msg->header.part.data; @@ -424,18 +426,18 @@ void sst_process_reply(struct work_struct *work) case IPC_IA_GET_STREAM_PARAMS: if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n", str_id); + pr_err("stream id %d invalid\n", str_id); break; } str_info = &sst_drv_ctx->streams[str_id]; if (msg->header.part.large) { - pr_debug("sst: Get stream large success\n"); + pr_debug("Get stream large success\n"); memcpy_fromio(str_info->ctrl_blk.data, ((void *)(msg->mailbox)), sizeof(struct snd_sst_fw_get_stream_params)); str_info->ctrl_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err("Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); str_info->ctrl_blk.ret_code = -msg->header.part.data; } @@ -447,19 +449,19 @@ void sst_process_reply(struct work_struct *work) break; case IPC_IA_DECODE_FRAMES: if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n", str_id); + pr_err("stream id %d invalid\n", str_id); break; } str_info = &sst_drv_ctx->streams[str_id]; if (msg->header.part.large) { - pr_debug("sst: Msg succedded %x\n", + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); memcpy_fromio(str_info->data_blk.data, ((void *)(msg->mailbox)), sizeof(struct snd_sst_decode_info)); str_info->data_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err("Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); str_info->data_blk.ret_code = -msg->header.part.data; } @@ -471,17 +473,17 @@ void sst_process_reply(struct work_struct *work) break; case IPC_IA_DRAIN_STREAM: if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n", str_id); + pr_err("stream id %d invalid\n", str_id); break; } str_info = &sst_drv_ctx->streams[str_id]; if (!msg->header.part.data) { - pr_debug("sst: Msg succedded %x\n", + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); str_info->ctrl_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); str_info->ctrl_blk.ret_code = -msg->header.part.data; @@ -496,7 +498,7 @@ void sst_process_reply(struct work_struct *work) case IPC_IA_DROP_STREAM: if (sst_validate_strid(str_id)) { - pr_err("sst: str id %d invalid\n", str_id); + pr_err("str id %d invalid\n", str_id); break; } str_info = &sst_drv_ctx->streams[str_id]; @@ -504,12 +506,12 @@ void sst_process_reply(struct work_struct *work) struct snd_sst_drop_response *drop_resp = (struct snd_sst_drop_response *)msg->mailbox; - pr_debug("sst: Drop ret bytes %x\n", drop_resp->bytes); + pr_debug("Drop ret bytes %x\n", drop_resp->bytes); str_info->curr_bytes = drop_resp->bytes; str_info->ctrl_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); str_info->ctrl_blk.ret_code = -msg->header.part.data; } @@ -521,10 +523,10 @@ void sst_process_reply(struct work_struct *work) break; case IPC_IA_ENABLE_RX_TIME_SLOT: if (!msg->header.part.data) { - pr_debug("sst: RX_TIME_SLOT success\n"); + pr_debug("RX_TIME_SLOT success\n"); sst_drv_ctx->hs_info_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); sst_drv_ctx->hs_info_blk.ret_code = @@ -541,17 +543,17 @@ void sst_process_reply(struct work_struct *work) case IPC_IA_SET_STREAM_PARAMS: str_info = &sst_drv_ctx->streams[str_id]; if (!msg->header.part.data) { - pr_debug("sst: Msg succedded %x\n", + pr_debug("Msg succeeded %x\n", msg->header.part.msg_id); str_info->ctrl_blk.ret_code = 0; } else { - pr_err("sst: Msg %x reply error %x\n", + pr_err(" Msg %x reply error %x\n", msg->header.part.msg_id, msg->header.part.data); str_info->ctrl_blk.ret_code = -msg->header.part.data; } if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n", str_id); + pr_err(" stream id %d invalid\n", str_id); break; } @@ -564,9 +566,9 @@ void sst_process_reply(struct work_struct *work) case IPC_IA_FREE_STREAM: if (!msg->header.part.data) { - pr_debug("sst: Stream %d freed\n", str_id); + pr_debug("Stream %d freed\n", str_id); } else { - pr_err("sst: Free for %d ret error %x\n", + pr_err("Free for %d ret error %x\n", str_id, msg->header.part.data); } break; @@ -575,7 +577,7 @@ void sst_process_reply(struct work_struct *work) struct snd_sst_alloc_response *resp = (struct snd_sst_alloc_response *)msg->mailbox; if (resp->str_type.result) - pr_err("sst: error alloc stream = %x\n", + pr_err("error alloc stream = %x\n", resp->str_type.result); sst_alloc_stream_response(str_id, resp); break; @@ -584,21 +586,21 @@ void sst_process_reply(struct work_struct *work) case IPC_IA_PLAY_FRAMES: case IPC_IA_CAPT_FRAMES: if (sst_validate_strid(str_id)) { - pr_err("sst: stream id %d invalid\n" , str_id); + pr_err("stream id %d invalid\n", str_id); break; } - pr_debug("sst: Ack for play/capt frames recived\n"); + pr_debug("Ack for play/capt frames received\n"); break; case IPC_IA_PREP_LIB_DNLD: { struct snd_sst_str_type *str_type = (struct snd_sst_str_type *)msg->mailbox; - pr_debug("sst: Prep Lib download %x\n", + pr_debug("Prep Lib download %x\n", msg->header.part.msg_id); if (str_type->result) - pr_err("sst: Prep lib download %x\n", str_type->result); + pr_err("Prep lib download %x\n", str_type->result); else - pr_debug("sst: Can download codec now...\n"); + pr_debug("Can download codec now...\n"); sst_wake_up_alloc_block(sst_drv_ctx, str_id, str_type->result, NULL); break; @@ -609,12 +611,12 @@ void sst_process_reply(struct work_struct *work) (struct snd_sst_lib_download_info *)msg->mailbox; int retval = resp->result; - pr_debug("sst: Lib downloaded %x\n", msg->header.part.msg_id); + pr_debug("Lib downloaded %x\n", msg->header.part.msg_id); if (resp->result) { - pr_err("sst: err in lib dload %x\n", resp->result); + pr_err("err in lib dload %x\n", resp->result); } else { - pr_debug("sst: Codec download complete...\n"); - pr_debug("sst: codec Type %d Ver %d Built %s: %s\n", + pr_debug("Codec download complete...\n"); + pr_debug("codec Type %d Ver %d Built %s: %s\n", resp->dload_lib.lib_info.lib_type, resp->dload_lib.lib_info.lib_version, resp->dload_lib.lib_info.b_date, @@ -639,17 +641,17 @@ void sst_process_reply(struct work_struct *work) case IPC_IA_GET_FW_BUILD_INF: { struct sst_fw_build_info *build = (struct sst_fw_build_info *)msg->mailbox; - pr_debug("sst: Build date:%sTime:%s", build->date, build->time); + pr_debug("Build date:%sTime:%s", build->date, build->time); break; } case IPC_IA_SET_PMIC_TYPE: break; case IPC_IA_START_STREAM: - pr_debug("sst: reply for START STREAM %x\n", msg->header.full); + pr_debug("reply for START STREAM %x\n", msg->header.full); break; default: /* Illegal case */ - pr_err("sst: process reply:default = %x\n", msg->header.full); + pr_err("process reply:default = %x\n", msg->header.full); } sst_clear_interrupt(); return; diff --git a/drivers/staging/intel_sst/intel_sst_pvt.c b/drivers/staging/intel_sst/intel_sst_pvt.c index 6487e192bf93..01f8c3b1cf74 100644 --- a/drivers/staging/intel_sst/intel_sst_pvt.c +++ b/drivers/staging/intel_sst/intel_sst_pvt.c @@ -29,6 +29,8 @@ * This file contains all private functions */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -60,7 +62,7 @@ int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx) } } if (i == MAX_ACTIVE_STREAM) { - pr_err("sst: max alloc_stream reached"); + pr_err("max alloc_stream reached\n"); i = -EBUSY; /* active stream limit reached */ } return i; @@ -84,14 +86,14 @@ int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, block->condition)) { /* event wake */ if (block->ret_code < 0) { - pr_err("sst: stream failed %d\n", block->ret_code); + pr_err("stream failed %d\n", block->ret_code); retval = -EBUSY; } else { - pr_debug("sst: event up\n"); + pr_debug("event up\n"); retval = 0; } } else { - pr_err("sst: signal interrupted\n"); + pr_err("signal interrupted\n"); retval = -EINTR; } return retval; @@ -115,18 +117,18 @@ int sst_wait_interruptible_timeout( { int retval = 0; - pr_debug("sst: sst_wait_interruptible_timeout - waiting....\n"); + pr_debug("sst_wait_interruptible_timeout - waiting....\n"); if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue, block->condition, msecs_to_jiffies(timeout))) { if (block->ret_code < 0) - pr_err("sst: stream failed %d\n", block->ret_code); + pr_err("stream failed %d\n", block->ret_code); else - pr_debug("sst: event up\n"); + pr_debug("event up\n"); retval = block->ret_code; } else { block->on = false; - pr_err("sst: timeout occured...\n"); + pr_err("timeout occurred...\n"); /*setting firmware state as uninit so that the firmware will get re-downloaded on next request this is because firmare not responding for 5 sec @@ -156,18 +158,18 @@ int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, /* NOTE: Observed that FW processes the alloc msg and replies even before the alloc thread has finished execution */ - pr_debug("sst: waiting for %x, condition %x\n", + pr_debug("waiting for %x, condition %x\n", block->sst_id, block->ops_block.condition); if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue, block->ops_block.condition, msecs_to_jiffies(SST_BLOCK_TIMEOUT))) { /* event wake */ - pr_debug("sst: Event wake %x\n", block->ops_block.condition); - pr_debug("sst: message ret: %d\n", block->ops_block.ret_code); + pr_debug("Event wake %x\n", block->ops_block.condition); + pr_debug("message ret: %d\n", block->ops_block.ret_code); retval = block->ops_block.ret_code; } else { block->ops_block.on = false; - pr_err("sst: Wait timed-out %x\n", block->ops_block.condition); + pr_err("Wait timed-out %x\n", block->ops_block.condition); /* settign firmware state as uninit so that the firmware will get redownloaded on next request this is because firmare not responding for 5 sec @@ -192,14 +194,14 @@ int sst_create_large_msg(struct ipc_post **arg) msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); if (!msg) { - pr_err("sst: kzalloc msg failed\n"); + pr_err("kzalloc msg failed\n"); return -ENOMEM; } msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); if (!msg->mailbox_data) { kfree(msg); - pr_err("sst: kzalloc mailbox_data failed"); + pr_err("kzalloc mailbox_data failed"); return -ENOMEM; }; *arg = msg; @@ -219,7 +221,7 @@ int sst_create_short_msg(struct ipc_post **arg) msg = kzalloc(sizeof(*msg), GFP_ATOMIC); if (!msg) { - pr_err("sst: kzalloc msg failed\n"); + pr_err("kzalloc msg failed\n"); return -ENOMEM; } msg->mailbox_data = NULL; @@ -290,10 +292,10 @@ int sst_enable_rx_timeslot(int status) struct ipc_post *msg = NULL; if (sst_create_short_msg(&msg)) { - pr_err("sst: mem allocation failed\n"); + pr_err("mem allocation failed\n"); return -ENOMEM; } - pr_debug("sst: ipc message sending: ENABLE_RX_TIME_SLOT\n"); + pr_debug("ipc message sending: ENABLE_RX_TIME_SLOT\n"); sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0); msg->header.part.data = status; sst_drv_ctx->hs_info_blk.condition = false; diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c index b2c4b7067da0..8f6e1005371d 100644 --- a/drivers/staging/intel_sst/intel_sst_stream.c +++ b/drivers/staging/intel_sst/intel_sst_stream.c @@ -26,6 +26,8 @@ * This file contains the stream operations of SST driver */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -46,7 +48,7 @@ int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot) { if (device >= MAX_NUM_STREAMS) { - pr_debug("sst: device type invalid %d\n", device); + pr_debug("device type invalid %d\n", device); return -EINVAL; } if (sst_drv_ctx->streams[device].status == STREAM_UN_INIT) { @@ -71,15 +73,15 @@ int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot) else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4) *pcm_slot = 0x0F; else { - pr_debug("sst: No condition satisfied.. ret err\n"); + pr_debug("No condition satisfied.. ret err\n"); return -EINVAL; } } else { - pr_debug("sst: this stream state is not uni-init, is %d\n", + pr_debug("this stream state is not uni-init, is %d\n", sst_drv_ctx->streams[device].status); return -EBADRQC; } - pr_debug("sst: returning slot %x\n", *pcm_slot); + pr_debug("returning slot %x\n", *pcm_slot); return 0; } /** @@ -96,7 +98,7 @@ static unsigned int get_mrst_stream_id(void) if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT) return i; } - pr_debug("sst: Didnt find empty stream for mrst\n"); + pr_debug("Didnt find empty stream for mrst\n"); return -EBUSY; } @@ -305,7 +307,7 @@ int sst_pause_stream(int str_id) if (str_info->prev == STREAM_UN_INIT) return -EBADRQC; if (str_info->ctrl_blk.on == true) { - pr_err("SST ERR: control path is in use\n "); + pr_err("SST ERR: control path is in use\n"); return -EINVAL; } if (sst_create_short_msg(&msg)) @@ -333,7 +335,7 @@ int sst_pause_stream(int str_id) } } else { retval = -EBADRQC; - pr_err("SST ERR:BADQRC for stream\n "); + pr_err("SST ERR: BADQRC for stream\n"); } return retval; @@ -468,7 +470,7 @@ int sst_drop_stream(int str_id) } } else { retval = -EBADRQC; - pr_err("SST ERR:BADQRC for stream\n"); + pr_err("SST ERR: BADQRC for stream\n"); } return retval; } diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c index fbae39fda5c0..d4e94f1ec830 100644 --- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c +++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c @@ -26,6 +26,8 @@ * This file contains the stream operations of SST driver */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -53,7 +55,7 @@ int sst_get_stream_params(int str_id, struct stream_info *str_info; struct snd_sst_fw_get_stream_params *fw_params; - pr_debug("sst: get_stream for %d\n", str_id); + pr_debug("get_stream for %d\n", str_id); retval = sst_validate_strid(str_id); if (retval) return retval; @@ -61,16 +63,16 @@ int sst_get_stream_params(int str_id, str_info = &sst_drv_ctx->streams[str_id]; if (str_info->status != STREAM_UN_INIT) { if (str_info->ctrl_blk.on == true) { - pr_err("sst: control path in use\n"); + pr_err("control path in use\n"); return -EINVAL; } if (sst_create_short_msg(&msg)) { - pr_err("sst: message creation failed\n"); + pr_err("message creation failed\n"); return -ENOMEM; } fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC); if (!fw_params) { - pr_err("sst: mem allcoation failed\n "); + pr_err("mem allocation failed\n"); kfree(msg); return -ENOMEM; } @@ -104,7 +106,7 @@ int sst_get_stream_params(int str_id, get_params->codec_params.stream_type = str_info->str_type; kfree(fw_params); } else { - pr_debug("sst: Stream is not in the init state\n"); + pr_debug("Stream is not in the init state\n"); } return retval; } @@ -125,17 +127,17 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param) BUG_ON(!str_param); if (sst_drv_ctx->streams[str_id].ops != str_param->ops) { - pr_err("sst: Invalid operation\n"); + pr_err("Invalid operation\n"); return -EINVAL; } retval = sst_validate_strid(str_id); if (retval) return retval; - pr_debug("sst: set_stream for %d\n", str_id); + pr_debug("set_stream for %d\n", str_id); str_info = &sst_drv_ctx->streams[str_id]; if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) { if (str_info->ctrl_blk.on == true) { - pr_err("sst: control path in use\n"); + pr_err("control path in use\n"); return -EAGAIN; } if (sst_create_large_msg(&msg)) @@ -163,7 +165,7 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param) } } else { retval = -EBADRQC; - pr_err("sst: BADQRC for stream\n"); + pr_err("BADQRC for stream\n"); } return retval; } @@ -183,7 +185,7 @@ int sst_get_vol(struct snd_sst_vol *get_vol) struct snd_sst_vol *fw_get_vol; int str_id = get_vol->stream_id; - pr_debug("sst: get vol called\n"); + pr_debug("get vol called\n"); if (sst_create_short_msg(&msg)) return -ENOMEM; @@ -195,7 +197,7 @@ int sst_get_vol(struct snd_sst_vol *get_vol) sst_drv_ctx->vol_info_blk.on = true; fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC); if (!fw_get_vol) { - pr_err("sst: mem allocation failed\n"); + pr_err("mem allocation failed\n"); kfree(msg); return -ENOMEM; } @@ -209,10 +211,10 @@ int sst_get_vol(struct snd_sst_vol *get_vol) if (retval) retval = -EIO; else { - pr_debug("sst: stream id %d\n", fw_get_vol->stream_id); - pr_debug("sst: volume %d\n", fw_get_vol->volume); - pr_debug("sst: ramp duration %d\n", fw_get_vol->ramp_duration); - pr_debug("sst: ramp_type %d\n", fw_get_vol->ramp_type); + pr_debug("stream id %d\n", fw_get_vol->stream_id); + pr_debug("volume %d\n", fw_get_vol->volume); + pr_debug("ramp duration %d\n", fw_get_vol->ramp_duration); + pr_debug("ramp_type %d\n", fw_get_vol->ramp_type); memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol)); } return retval; @@ -231,10 +233,10 @@ int sst_set_vol(struct snd_sst_vol *set_vol) int retval = 0; struct ipc_post *msg = NULL; - pr_debug("sst: set vol called\n"); + pr_debug("set vol called\n"); if (sst_create_large_msg(&msg)) { - pr_err("sst: message creation failed\n"); + pr_err("message creation failed\n"); return -ENOMEM; } sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1, @@ -254,7 +256,7 @@ int sst_set_vol(struct snd_sst_vol *set_vol) retval = sst_wait_interruptible_timeout(sst_drv_ctx, &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT); if (retval) { - pr_err("sst: error in set_vol = %d\n", retval); + pr_err("error in set_vol = %d\n", retval); retval = -EIO; } return retval; @@ -273,10 +275,10 @@ int sst_set_mute(struct snd_sst_mute *set_mute) int retval = 0; struct ipc_post *msg = NULL; - pr_debug("sst: set mute called\n"); + pr_debug("set mute called\n"); if (sst_create_large_msg(&msg)) { - pr_err("sst: message creation failed\n"); + pr_err("message creation failed\n"); return -ENOMEM; } sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1, @@ -297,7 +299,7 @@ int sst_set_mute(struct snd_sst_mute *set_mute) retval = sst_wait_interruptible_timeout(sst_drv_ctx, &sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT); if (retval) { - pr_err("sst: error in set_mute = %d\n", retval); + pr_err("error in set_mute = %d\n", retval); retval = -EIO; } return retval; @@ -358,20 +360,20 @@ int sst_parse_target(struct snd_sst_slot_info *slot) slot->device_type == SND_SST_DEVICE_PCM) { retval = sst_activate_target(slot); if (retval) - pr_err("sst: SST_Activate_target_fail\n"); + pr_err("SST_Activate_target_fail\n"); else - pr_err("sst: SST_Activate_target_pass\n"); + pr_err("SST_Activate_target_pass\n"); return retval; } else if (slot->action == SND_SST_PORT_PREPARE && slot->device_type == SND_SST_DEVICE_PCM) { retval = sst_prepare_target(slot); if (retval) - pr_err("sst: SST_prepare_target_fail\n"); + pr_err("SST_prepare_target_fail\n"); else - pr_err("sst: SST_prepare_target_pass\n"); + pr_err("SST_prepare_target_pass\n"); return retval; } else { - pr_err("sst: slot_action : %d, device_type: %d\n", + pr_err("slot_action : %d, device_type: %d\n", slot->action, slot->device_type); return retval; } @@ -383,7 +385,7 @@ int sst_send_target(struct snd_sst_target_device *target) struct ipc_post *msg; if (sst_create_large_msg(&msg)) { - pr_err("sst: message creation failed\n"); + pr_err("message creation failed\n"); return -ENOMEM; } sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0); @@ -399,11 +401,11 @@ int sst_send_target(struct snd_sst_target_device *target) list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list); spin_unlock(&sst_drv_ctx->list_spin_lock); sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); - pr_debug("sst: message sent- waiting\n"); + pr_debug("message sent- waiting\n"); retval = sst_wait_interruptible_timeout(sst_drv_ctx, &sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT); if (retval) - pr_err("sst: target device ipc failed = 0x%x\n", retval); + pr_err("target device ipc failed = 0x%x\n", retval); return retval; } @@ -439,7 +441,7 @@ int sst_target_device_validate(struct snd_sst_target_device *target) goto err; } else { err: - pr_err("sst: i/p params incorrect\n"); + pr_err("i/p params incorrect\n"); return -EINVAL; } } @@ -460,15 +462,15 @@ int sst_target_device_select(struct snd_sst_target_device *target) { int retval, i, prepare_count = 0; - pr_debug("sst: Target Device Select\n"); + pr_debug("Target Device Select\n"); if (target->device_route < 0 || target->device_route > 2) { - pr_err("sst: device route is invalid\n"); + pr_err("device route is invalid\n"); return -EINVAL; } if (target->device_route != 0) { - pr_err("sst: Unsupported config\n"); + pr_err("Unsupported config\n"); return -EIO; } retval = sst_target_device_validate(target); @@ -480,18 +482,18 @@ int sst_target_device_select(struct snd_sst_target_device *target) return retval; for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) { if (target->devices[i].action == SND_SST_PORT_ACTIVATE) { - pr_debug("sst: activate called in %d\n", i); + pr_debug("activate called in %d\n", i); retval = sst_parse_target(&target->devices[i]); if (retval) return retval; } else if (target->devices[i].action == SND_SST_PORT_PREPARE) { - pr_debug("sst: PREPARE in %d, Forwading\n", i); + pr_debug("PREPARE in %d, Forwarding\n", i); retval = sst_parse_target(&target->devices[i]); if (retval) { - pr_err("sst: Parse Target fail %d", retval); + pr_err("Parse Target fail %d\n", retval); return retval; } - pr_debug("sst: Parse Target successful %d", retval); + pr_debug("Parse Target successful %d\n", retval); if (target->devices[i].device_type == SND_SST_DEVICE_PCM) prepare_count++; @@ -512,11 +514,11 @@ static inline int sst_get_RAR(struct RAR_buffer *buffers, int count) rar_status = rar_handle_to_bus(buffers, count); if (count != rar_status) { - pr_err("sst: The rar CALL Failed"); + pr_err("The rar CALL Failed"); retval = -EIO; } if (buffers->info.type != RAR_TYPE_AUDIO) { - pr_err("sst: Invalid RAR type\n"); + pr_err("Invalid RAR type\n"); return -EINVAL; } return retval; @@ -539,10 +541,10 @@ static int sst_create_sg_list(struct stream_info *stream, if (kbufs->in_use == false) { #ifdef CONFIG_MRST_RAR_HANDLER if (stream->ops == STREAM_OPS_PLAYBACK_DRM) { - pr_debug("sst: DRM playback handling\n"); + pr_debug("DRM playback handling\n"); rar_buffers.info.handle = (__u32)kbufs->addr; rar_buffers.info.size = kbufs->size; - pr_debug("sst: rar handle 0x%x size=0x%x", + pr_debug("rar handle 0x%x size=0x%x\n", rar_buffers.info.handle, rar_buffers.info.size); retval = sst_get_RAR(&rar_buffers, 1); @@ -552,7 +554,7 @@ static int sst_create_sg_list(struct stream_info *stream, sg_list->addr[i].addr = rar_buffers.bus_address; /* rar_buffers.info.size; */ sg_list->addr[i].size = (__u32)kbufs->size; - pr_debug("sst: phyaddr[%d] 0x%x Size:0x%x\n" + pr_debug("phyaddr[%d] 0x%x Size:0x%x\n" , i, sg_list->addr[i].addr, sg_list->addr[i].size); } @@ -562,7 +564,7 @@ static int sst_create_sg_list(struct stream_info *stream, virt_to_phys((void *) kbufs->addr + kbufs->offset); sg_list->addr[i].size = kbufs->size; - pr_debug("sst: phyaddr[%d]:0x%x Size:0x%x\n" + pr_debug("phyaddr[%d]:0x%x Size:0x%x\n" , i , sg_list->addr[i].addr, kbufs->size); } stream->curr_bytes += sg_list->addr[i].size; @@ -574,7 +576,7 @@ static int sst_create_sg_list(struct stream_info *stream, } sg_list->num_entries = i; - pr_debug("sst:sg list entries = %d\n", sg_list->num_entries); + pr_debug("sg list entries = %d\n", sg_list->num_entries); return i; } @@ -595,7 +597,7 @@ int sst_play_frame(int str_id) struct sst_stream_bufs *kbufs = NULL, *_kbufs; struct stream_info *stream; - pr_debug("sst: play frame for %d\n", str_id); + pr_debug("play frame for %d\n", str_id); retval = sst_validate_strid(str_id); if (retval) return retval; @@ -615,14 +617,14 @@ int sst_play_frame(int str_id) stream->curr_bytes = 0; if (list_empty(&stream->bufs)) { /* no user buffer available */ - pr_debug("sst: Null buffer stream status %d\n", stream->status); + pr_debug("Null buffer stream status %d\n", stream->status); stream->prev = stream->status; stream->status = STREAM_INIT; - pr_debug("sst:new stream status = %d\n", stream->status); + pr_debug("new stream status = %d\n", stream->status); if (stream->need_draining == true) { - pr_debug("sst:draining stream\n"); + pr_debug("draining stream\n"); if (sst_create_short_msg(&msg)) { - pr_err("sst: mem alloc failed\n"); + pr_err("mem allocation failed\n"); return -ENOMEM; } sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM, @@ -633,7 +635,7 @@ int sst_play_frame(int str_id) spin_unlock(&sst_drv_ctx->list_spin_lock); sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); } else if (stream->data_blk.on == true) { - pr_debug("sst:user list empty.. wake\n"); + pr_debug("user list empty.. wake\n"); /* unblock */ stream->data_blk.ret_code = 0; stream->data_blk.condition = true; @@ -678,7 +680,7 @@ int sst_capture_frame(int str_id) struct stream_info *stream; - pr_debug("sst:capture frame for %d\n", str_id); + pr_debug("capture frame for %d\n", str_id); retval = sst_validate_strid(str_id); if (retval) return retval; @@ -688,19 +690,19 @@ int sst_capture_frame(int str_id) if (kbufs->in_use == true) { list_del(&kbufs->node); kfree(kbufs); - pr_debug("sst:del node\n"); + pr_debug("del node\n"); } } if (list_empty(&stream->bufs)) { /* no user buffer available */ - pr_debug("sst:Null buffer!!!!stream status %d\n", + pr_debug("Null buffer!!!!stream status %d\n", stream->status); stream->prev = stream->status; stream->status = STREAM_INIT; - pr_debug("sst:new stream status = %d\n", + pr_debug("new stream status = %d\n", stream->status); if (stream->data_blk.on == true) { - pr_debug("sst:user list empty.. wake\n"); + pr_debug("user list empty.. wake\n"); /* unblock */ stream->data_blk.ret_code = 0; stream->data_blk.condition = true; @@ -731,7 +733,7 @@ int sst_capture_frame(int str_id) stream->cumm_bytes += stream->curr_bytes; stream->curr_bytes = 0; - pr_debug("sst:Cum bytes = %d\n", stream->cumm_bytes); + pr_debug("Cum bytes = %d\n", stream->cumm_bytes); return 0; } @@ -743,7 +745,7 @@ static unsigned int calculate_min_size(struct snd_sst_buffs *bufs) if (bufs->buff_entry[i].size < min_val) min_val = bufs->buff_entry[i].size; } - pr_debug("sst:min_val = %d\n", min_val); + pr_debug("min_val = %d\n", min_val); return min_val; } @@ -754,7 +756,7 @@ static unsigned int calculate_max_size(struct snd_sst_buffs *bufs) if (bufs->buff_entry[i].size > max_val) max_val = bufs->buff_entry[i].size; } - pr_debug("sst:max_val = %d\n", max_val); + pr_debug("max_val = %d\n", max_val); return max_val; } @@ -773,7 +775,7 @@ static int sst_allocate_decode_buf(struct stream_info *str_info, if (dbufs->ibufs->entries == dbufs->obufs->entries) return 0; else { - pr_err("sst: RAR entries dont match\n"); + pr_err("RAR entries dont match\n"); return -EINVAL; } } else @@ -783,26 +785,26 @@ static int sst_allocate_decode_buf(struct stream_info *str_info, } #endif if (!str_info->decode_ibuf) { - pr_debug("sst:no i/p buffers, trying full size\n"); + pr_debug("no i/p buffers, trying full size\n"); str_info->decode_isize = cum_input_given; str_info->decode_ibuf = kzalloc(str_info->decode_isize, GFP_KERNEL); str_info->idecode_alloc = str_info->decode_isize; } if (!str_info->decode_ibuf) { - pr_debug("sst:buff alloc failed, try max size\n"); + pr_debug("buff alloc failed, try max size\n"); str_info->decode_isize = calculate_max_size(dbufs->ibufs); str_info->decode_ibuf = kzalloc( str_info->decode_isize, GFP_KERNEL); str_info->idecode_alloc = str_info->decode_isize; } if (!str_info->decode_ibuf) { - pr_debug("sst:buff alloc failed, try min size\n"); + pr_debug("buff alloc failed, try min size\n"); str_info->decode_isize = calculate_min_size(dbufs->ibufs); str_info->decode_ibuf = kzalloc(str_info->decode_isize, GFP_KERNEL); if (!str_info->decode_ibuf) { - pr_err("sst: mem allocation failed\n"); + pr_err("mem allocation failed\n"); return -ENOMEM; } str_info->idecode_alloc = str_info->decode_isize; @@ -820,7 +822,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info, struct ipc_post *msg = NULL; int retval = 0; - pr_debug("SST DBGsst_set_mute:called\n"); + pr_debug("SST DBG:sst_set_mute:called\n"); if (str_info->decode_ibuf_type == SST_BUF_RAR) { #ifdef CONFIG_MRST_RAR_HANDLER @@ -857,7 +859,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info, dec_info->input_bytes_consumed = 0; dec_info->output_bytes_produced = 0; if (sst_create_large_msg(&msg)) { - pr_err("sst: message creation failed\n"); + pr_err("message creation failed\n"); return -ENOMEM; } @@ -894,7 +896,7 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info, dbufs->ibufs->buff_entry[i].buffer, sizeof(__u32)); if (retval) { - pr_err("sst:cpy from user fail\n"); + pr_err("cpy from user fail\n"); return -EAGAIN; } rar_buffers.info.type = dbufs->ibufs->type; @@ -931,7 +933,7 @@ static int sst_prepare_input_buffers(struct stream_info *str_info, { int i, cpy_size, retval = 0; - pr_debug("sst:input_index = %d, input entries = %d\n", + pr_debug("input_index = %d, input entries = %d\n", *input_index, dbufs->ibufs->entries); for (i = *input_index; i < dbufs->ibufs->entries; i++) { #ifdef CONFIG_MRST_RAR_HANDLER @@ -939,7 +941,7 @@ static int sst_prepare_input_buffers(struct stream_info *str_info, dbufs, input_index, in_copied, input_index_valid_size, new_entry_flag); if (retval) { - pr_err("sst: In prepare input buffers for RAR\n"); + pr_err("In prepare input buffers for RAR\n"); return -EIO; } #endif @@ -947,10 +949,10 @@ static int sst_prepare_input_buffers(struct stream_info *str_info, if (*input_index_valid_size == 0) *input_index_valid_size = dbufs->ibufs->buff_entry[i].size; - pr_debug("sst:inout addr = %p, size = %d\n", + pr_debug("inout addr = %p, size = %d\n", dbufs->ibufs->buff_entry[i].buffer, *input_index_valid_size); - pr_debug("sst:decode_isize = %d, in_copied %d\n", + pr_debug("decode_isize = %d, in_copied %d\n", str_info->decode_isize, *in_copied); if (*input_index_valid_size <= (str_info->decode_isize - *in_copied)) @@ -958,12 +960,12 @@ static int sst_prepare_input_buffers(struct stream_info *str_info, else cpy_size = str_info->decode_isize - *in_copied; - pr_debug("sst:cpy size = %d\n", cpy_size); + pr_debug("cpy size = %d\n", cpy_size); if (!dbufs->ibufs->buff_entry[i].buffer) { - pr_err("sst: i/p buffer is null\n"); + pr_err("i/p buffer is null\n"); return -EINVAL; } - pr_debug("sst:Try copy To %p, From %p, size %d\n", + pr_debug("Try copy To %p, From %p, size %d\n", str_info->decode_ibuf + *in_copied, dbufs->ibufs->buff_entry[i].buffer, cpy_size); @@ -972,22 +974,22 @@ static int sst_prepare_input_buffers(struct stream_info *str_info, (void *) dbufs->ibufs->buff_entry[i].buffer, cpy_size); if (retval) { - pr_err("sst: copy from user failed\n"); + pr_err("copy from user failed\n"); return -EIO; } *in_copied += cpy_size; *input_index_valid_size -= cpy_size; - pr_debug("sst:in buff size = %d, in_copied = %d\n", + pr_debug("in buff size = %d, in_copied = %d\n", *input_index_valid_size, *in_copied); if (*input_index_valid_size != 0) { - pr_debug("sst:more input buffers left\n"); + pr_debug("more input buffers left\n"); dbufs->ibufs->buff_entry[i].buffer += cpy_size; break; } if (*in_copied == str_info->decode_isize && *input_index_valid_size == 0 && (i+1) <= dbufs->ibufs->entries) { - pr_debug("sst:all input buffers copied\n"); + pr_debug("all input buffers copied\n"); *new_entry_flag = true; *input_index = i + 1; break; @@ -1005,23 +1007,23 @@ static int sst_prepare_output_buffers(struct stream_info *str_info, { int i, cpy_size, retval = 0; - pr_debug("sst:output_index = %d, output entries = %d\n", + pr_debug("output_index = %d, output entries = %d\n", *output_index, dbufs->obufs->entries); for (i = *output_index; i < dbufs->obufs->entries; i++) { *output_index = i; - pr_debug("sst:output addr = %p, size = %d\n", + pr_debug("output addr = %p, size = %d\n", dbufs->obufs->buff_entry[i].buffer, dbufs->obufs->buff_entry[i].size); - pr_debug("sst:output_size = %d, out_copied = %d\n", + pr_debug("output_size = %d, out_copied = %d\n", output_size, *out_copied); if (dbufs->obufs->buff_entry[i].size < (output_size - *out_copied)) cpy_size = dbufs->obufs->buff_entry[i].size; else cpy_size = output_size - *out_copied; - pr_debug("sst:cpy size = %d\n", cpy_size); - pr_debug("sst:Try copy To: %p, From %p, size %d\n", + pr_debug("cpy size = %d\n", cpy_size); + pr_debug("Try copy To: %p, From %p, size %d\n", dbufs->obufs->buff_entry[i].buffer, sst_drv_ctx->mmap_mem + *out_copied, cpy_size); @@ -1029,13 +1031,13 @@ static int sst_prepare_output_buffers(struct stream_info *str_info, sst_drv_ctx->mmap_mem + *out_copied, cpy_size); if (retval) { - pr_err("sst: copy to user failed\n"); + pr_err("copy to user failed\n"); return -EIO; } else - pr_debug("sst:copy to user passed\n"); + pr_debug("copy to user passed\n"); *out_copied += cpy_size; dbufs->obufs->buff_entry[i].size -= cpy_size; - pr_debug("sst:o/p buff size %d, out_copied %d\n", + pr_debug("o/p buff size %d, out_copied %d\n", dbufs->obufs->buff_entry[i].size, *out_copied); if (dbufs->obufs->buff_entry[i].size != 0) { *output_index = i; @@ -1073,7 +1075,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) unsigned long long input_bytes, output_bytes; sst_drv_ctx->scard_ops->power_down_pmic(); - pr_debug("sst: Powering_down_PMIC...\n"); + pr_debug("Powering_down_PMIC...\n"); retval = sst_validate_strid(str_id); if (retval) @@ -1081,7 +1083,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) str_info = &sst_drv_ctx->streams[str_id]; if (str_info->status != STREAM_INIT) { - pr_err("sst: invalid stream state = %d\n", + pr_err("invalid stream state = %d\n", str_info->status); return -EINVAL; } @@ -1098,7 +1100,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) retval = sst_allocate_decode_buf(str_info, dbufs, cum_input_given, cum_output_given); if (retval) { - pr_err("sst: mem allocation failed, abort!!!\n"); + pr_err("mem allocation failed, abort!!!\n"); retval = -ENOMEM; goto finish; } @@ -1114,7 +1116,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) dbufs, &input_index, &in_copied, &input_index_valid_size, &new_entry_flag); if (retval) { - pr_err("sst: prepare in buffers failed\n"); + pr_err("prepare in buffers failed\n"); goto finish; } @@ -1145,8 +1147,8 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) str_info->decode_osize = dbufs->obufs-> buff_entry[output_index].size; str_info->decode_obuf_type = dbufs->obufs->type; - pr_debug("sst:DRM handling\n"); - pr_debug("o/p_add=0x%lu Size=0x%x", + pr_debug("DRM handling\n"); + pr_debug("o/p_add=0x%lu Size=0x%x\n", (unsigned long) str_info->decode_obuf, str_info->decode_osize); } else { @@ -1160,7 +1162,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { if (str_info->decode_isize > in_copied) { str_info->decode_isize = in_copied; - pr_debug("sst:i/p size = %d\n", + pr_debug("i/p size = %d\n", str_info->decode_isize); } } @@ -1168,20 +1170,19 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) retval = sst_send_decode_mess(str_id, str_info, &dec_info); if (retval || dec_info.input_bytes_consumed == 0) { - pr_err( - "SST ERR: mess failed or no input consumed\n"); + pr_err("SST ERR: mess failed or no input consumed\n"); goto finish; } input_bytes = dec_info.input_bytes_consumed; output_bytes = dec_info.output_bytes_produced; - pr_debug("sst:in_copied=%d, con=%lld, prod=%lld\n", + pr_debug("in_copied=%d, con=%lld, prod=%lld\n", in_copied, input_bytes, output_bytes); if (dbufs->obufs->type == SST_BUF_RAR) { output_index += 1; if (output_index == dbufs->obufs->entries) { copy_in_done = true; - pr_debug("sst:all i/p cpy done\n"); + pr_debug("all i/p cpy done\n"); } total_output += output_bytes; } else { @@ -1190,14 +1191,14 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) retval = sst_prepare_output_buffers(str_info, dbufs, &output_index, output_size, &out_copied); if (retval) { - pr_err("sst:prep out buff fail\n"); + pr_err("prep out buff fail\n"); goto finish; } if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) { if (in_copied != input_bytes) { int bytes_left = in_copied - input_bytes; - pr_debug("sst:bytes %d\n", + pr_debug("bytes %d\n", bytes_left); if (new_entry_flag == true) input_index--; @@ -1237,7 +1238,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) total_output += out_copied; if (str_info->decode_osize != out_copied) { str_info->decode_osize -= out_copied; - pr_debug("sst:output size modified = %d\n", + pr_debug("output size modified = %d\n", str_info->decode_osize); } } @@ -1251,16 +1252,16 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs) } else { if (total_output == cum_output_given) { copy_out_done = true; - pr_debug("sst:all o/p cpy done\n"); + pr_debug("all o/p cpy done\n"); } if (total_input == cum_input_given) { copy_in_done = true; - pr_debug("sst:all i/p cpy done\n"); + pr_debug("all i/p cpy done\n"); } } - pr_debug("sst:copy_out = %d, copy_in = %d\n", + pr_debug("copy_out = %d, copy_in = %d\n", copy_out_done, copy_in_done); } diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c index 4c0264ceaa88..47b91e500c3c 100644 --- a/drivers/staging/intel_sst/intelmid.c +++ b/drivers/staging/intel_sst/intelmid.c @@ -24,6 +24,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ALSA driver for Intel MID sound card chipset */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -118,7 +121,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - pr_debug("sst: Trigger Start\n"); + pr_debug("Trigger Start\n"); ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_START, &stream->stream_info.str_id); if (ret_val) @@ -128,7 +131,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, stream->stream_status = RUNNING; break; case SNDRV_PCM_TRIGGER_STOP: - pr_debug("sst: in stop\n"); + pr_debug("in stop\n"); ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP, &stream->stream_info.str_id); if (ret_val) @@ -136,7 +139,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, stream->stream_status = DROPPED; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("sst: in pause\n"); + pr_debug("in pause\n"); ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_PAUSE, &stream->stream_info.str_id); if (ret_val) @@ -144,7 +147,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, stream->stream_status = PAUSED; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("sst: in pause release\n"); + pr_debug("in pause release\n"); ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_RESUME, &stream->stream_info.str_id); if (ret_val) @@ -170,17 +173,17 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream) int ret_val = 0; struct snd_intelmad *intelmaddata; - pr_debug("sst: pcm_prepare called\n"); + pr_debug("pcm_prepare called\n"); WARN_ON(!substream); stream = substream->runtime->private_data; intelmaddata = snd_pcm_substream_chip(substream); - pr_debug("sst: pb cnt = %d cap cnt = %d\n",\ + pr_debug("pb cnt = %d cap cnt = %d\n",\ intelmaddata->playback_cnt, intelmaddata->capture_cnt); if (stream->stream_info.str_id) { - pr_debug("sst: Prepare called for already set stream\n"); + pr_debug("Prepare called for already set stream\n"); ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP, &stream->stream_info.str_id); return ret_val; @@ -197,7 +200,7 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream) /* return back the stream id */ snprintf(substream->pcm->id, sizeof(substream->pcm->id), "%d", stream->stream_info.str_id); - pr_debug("sst: stream id to user = %s\n", + pr_debug("stream id to user = %s\n", substream->pcm->id); ret_val = snd_intelmad_init_stream(substream); @@ -212,7 +215,7 @@ static int snd_intelmad_hw_params(struct snd_pcm_substream *substream, { int ret_val; - pr_debug("sst: snd_intelmad_hw_params called\n"); + pr_debug("snd_intelmad_hw_params called\n"); ret_val = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); memset(substream->runtime->dma_area, 0, @@ -223,7 +226,7 @@ static int snd_intelmad_hw_params(struct snd_pcm_substream *substream, static int snd_intelmad_hw_free(struct snd_pcm_substream *substream) { - pr_debug("sst: snd_intelmad_hw_free called\n"); + pr_debug("snd_intelmad_hw_free called\n"); return snd_pcm_lib_free_pages(substream); } @@ -253,12 +256,12 @@ static snd_pcm_uframes_t snd_intelmad_pcm_pointer ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_BUFFER_POINTER, &stream->stream_info); if (ret_val) { - pr_err("sst: error code = 0x%x\n", ret_val); + pr_err("error code = 0x%x\n", ret_val); return ret_val; } - pr_debug("sst: samples reported out 0x%llx\n", + pr_debug("samples reported out 0x%llx\n", stream->stream_info.buffer_ptr); - pr_debug("sst: Frame bits:: %d period_count :: %d\n", + pr_debug("Frame bits:: %d period_count :: %d\n", (int)substream->runtime->frame_bits, (int)substream->runtime->period_size); @@ -283,10 +286,10 @@ static int snd_intelmad_close(struct snd_pcm_substream *substream) stream = substream->runtime->private_data; - pr_debug("sst: snd_intelmad_close called\n"); + pr_debug("snd_intelmad_close called\n"); intelmaddata = snd_pcm_substream_chip(substream); - pr_debug("sst: str id = %d\n", stream->stream_info.str_id); + pr_debug("str id = %d\n", stream->stream_info.str_id); if (stream->stream_info.str_id) { /* SST API to actually stop/free the stream */ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_FREE, @@ -296,7 +299,7 @@ static int snd_intelmad_close(struct snd_pcm_substream *substream) else intelmaddata->capture_cnt--; } - pr_debug("sst: snd_intelmad_close : pb cnt = %d cap cnt = %d\n", + pr_debug("snd_intelmad_close : pb cnt = %d cap cnt = %d\n", intelmaddata->playback_cnt, intelmaddata->capture_cnt); kfree(substream->runtime->private_data); return ret_val; @@ -319,7 +322,7 @@ static int snd_intelmad_open(struct snd_pcm_substream *substream, WARN_ON(!substream); - pr_debug("sst: snd_intelmad_open called\n"); + pr_debug("snd_intelmad_open called\n"); intelmaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; @@ -456,17 +459,17 @@ void sst_mad_send_jack_report(struct snd_jack *jack, { if (!jack) { - pr_debug("sst: MAD error jack empty\n"); + pr_debug("MAD error jack empty\n"); } else { - pr_debug("sst: MAD send jack report for = %d!!!\n", status); - pr_debug("sst: MAD send jack report %d\n", jack->type); + pr_debug("MAD send jack report for = %d!!!\n", status); + pr_debug("MAD send jack report %d\n", jack->type); snd_jack_report(jack, status); /*button pressed and released */ if (buttonpressevent) snd_jack_report(jack, 0); - pr_debug("sst: MAD sending jack report Done !!!\n"); + pr_debug("MAD sending jack report Done !!!\n"); } @@ -490,7 +493,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) if (intsts & 0x4) { if (!(intelmid_audio_interrupt_enable)) { - pr_debug("sst: Audio interrupt enable\n"); + pr_debug("Audio interrupt enable\n"); sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1); @@ -500,7 +503,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) } /* send headphone detect */ - pr_debug("sst: MAD headphone %d\n", intsts & 0x4); + pr_debug("MAD headphone %d\n", intsts & 0x4); jack = &intelmaddata->jack[0].jack; present = !(intelmaddata->jack[0].jack_status); intelmaddata->jack[0].jack_status = present; @@ -510,7 +513,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) if (intsts & 0x2) { /* send short push */ - pr_debug("sst: MAD short push %d\n", intsts & 0x2); + pr_debug("MAD short push %d\n", intsts & 0x2); jack = &intelmaddata->jack[2].jack; present = 1; jack_event_flag = 1; @@ -518,7 +521,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) } if (intsts & 0x1) { /* send long push */ - pr_debug("sst: MAD long push %d\n", intsts & 0x1); + pr_debug("MAD long push %d\n", intsts & 0x1); jack = &intelmaddata->jack[3].jack; present = 1; jack_event_flag = 1; @@ -526,7 +529,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) } if (intsts & 0x8) { if (!(intelmid_audio_interrupt_enable)) { - pr_debug("sst: Audio interrupt enable\n"); + pr_debug("Audio interrupt enable\n"); sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3); sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1); @@ -535,7 +538,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata) intelmaddata->jack[1].jack_status = 0; } /* send headset detect */ - pr_debug("sst: MAD headset = %d\n", intsts & 0x8); + pr_debug("MAD headset = %d\n", intsts & 0x8); jack = &intelmaddata->jack[1].jack; present = !(intelmaddata->jack[1].jack_status); intelmaddata->jack[1].jack_status = present; @@ -558,10 +561,10 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) scard_ops = intelmaddata->sstdrv_ops->scard_ops; - pr_debug("sst: previous value: %x\n", intelmaddata->jack_prev_state); + pr_debug("previous value: %x\n", intelmaddata->jack_prev_state); if (!(intelmid_audio_interrupt_enable)) { - pr_debug("sst: Audio interrupt enable\n"); + pr_debug("Audio interrupt enable\n"); intelmaddata->jack_prev_state = 0xC0; intelmid_audio_interrupt_enable = 1; } @@ -572,12 +575,12 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) sc_access_read.reg_addr = 0x201; sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); value = (sc_access_read.value); - pr_debug("sst: value returned = 0x%x\n", value); + pr_debug("value returned = 0x%x\n", value); } if (jack_prev_state == 0xc0 && value == 0x40) { /*headset detected. */ - pr_debug("sst: MAD headset inserted\n"); + pr_debug("MAD headset inserted\n"); jack = &intelmaddata->jack[1].jack; present = 1; jack_event_flag = 1; @@ -587,7 +590,7 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) if (jack_prev_state == 0xc0 && value == 0x00) { /* headphone detected. */ - pr_debug("sst: MAD headphone inserted\n"); + pr_debug("MAD headphone inserted\n"); jack = &intelmaddata->jack[0].jack; present = 1; jack_event_flag = 1; @@ -596,9 +599,9 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) if (jack_prev_state == 0x40 && value == 0xc0) { /*headset removed*/ - pr_debug("sst: Jack headset status %d\n", + pr_debug("Jack headset status %d\n", intelmaddata->jack[1].jack_status); - pr_debug("sst: MAD headset removed\n"); + pr_debug("MAD headset removed\n"); jack = &intelmaddata->jack[1].jack; present = 0; jack_event_flag = 1; @@ -607,9 +610,9 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) if (jack_prev_state == 0x00 && value == 0xc0) { /* headphone detected. */ - pr_debug("sst: Jack headphone status %d\n", + pr_debug("Jack headphone status %d\n", intelmaddata->jack[0].jack_status); - pr_debug("sst: headphone removed\n"); + pr_debug("headphone removed\n"); jack = &intelmaddata->jack[0].jack; present = 0; jack_event_flag = 1; @@ -618,7 +621,7 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) if (jack_prev_state == 0x40 && value == 0x00) { /*button pressed*/ do_gettimeofday(&intelmaddata->jack[1].buttonpressed); - pr_debug("sst: MAD button press detected n"); + pr_debug("MAD button press detected\n"); } @@ -628,19 +631,19 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata) do_gettimeofday( &intelmaddata->jack[1].buttonreleased); /*button pressed */ - pr_debug("sst: Button Released detected\n"); + pr_debug("Button Released detected\n"); timediff = intelmaddata->jack[1]. buttonreleased.tv_sec - intelmaddata-> jack[1].buttonpressed.tv_sec; buttonpressflag = 1; if (timediff > 1) { - pr_debug("sst: long press detected\n"); + pr_debug("long press detected\n"); /* send headphone detect/undetect */ jack = &intelmaddata->jack[3].jack; present = 1; jack_event_flag = 1; } else { - pr_debug("sst: short press detected\n"); + pr_debug("short press detected\n"); /* send headphone detect/undetect */ jack = &intelmaddata->jack[2].jack; present = 1; @@ -667,24 +670,24 @@ void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata) sc_access_read.reg_addr = 0x132; sst_sc_reg_access(&sc_access_read, PMIC_READ, 1); value = (sc_access_read.value); - pr_debug("sst: value returned = 0x%x\n", value); + pr_debug("value returned = 0x%x\n", value); } if (intsts & 0x1) { - pr_debug("sst: headset detected\n"); + pr_debug("headset detected\n"); /* send headset detect/undetect */ jack = &intelmaddata->jack[1].jack; present = (value == 0x1) ? 1 : 0; jack_event_flag = 1; } if (intsts & 0x2) { - pr_debug("sst: headphone detected\n"); + pr_debug("headphone detected\n"); /* send headphone detect/undetect */ jack = &intelmaddata->jack[0].jack; present = (value == 0x2) ? 1 : 0; jack_event_flag = 1; } if (intsts & 0x4) { - pr_debug("sst: short push detected\n"); + pr_debug("short push detected\n"); /* send short push */ jack = &intelmaddata->jack[2].jack; present = 1; @@ -692,7 +695,7 @@ void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata) buttonpressflag = 1; } if (intsts & 0x8) { - pr_debug("sst: long push detected\n"); + pr_debug("long push detected\n"); /* send long push */ jack = &intelmaddata->jack[3].jack; present = 1; @@ -738,12 +741,12 @@ static int __devinit snd_intelmad_register_irq( u32 regbase = AUDINT_BASE, regsize = 8; char *drv_name; - pr_debug("sst: irq reg done, regbase 0x%x, regsize 0x%x\n", + pr_debug("irq reg done, regbase 0x%x, regsize 0x%x\n", regbase, regsize); intelmaddata->int_base = ioremap_nocache(regbase, regsize); if (!intelmaddata->int_base) - pr_err("sst: Mapping of cache failed\n"); - pr_debug("sst: irq = 0x%x\n", intelmaddata->irq); + pr_err("Mapping of cache failed\n"); + pr_debug("irq = 0x%x\n", intelmaddata->irq); if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) drv_name = DRIVER_NAME_MFLD; else @@ -753,7 +756,7 @@ static int __devinit snd_intelmad_register_irq( IRQF_SHARED, drv_name, intelmaddata); if (ret_val) - pr_err("sst: cannot register IRQ\n"); + pr_err("cannot register IRQ\n"); return ret_val; } @@ -775,10 +778,10 @@ static int __devinit snd_intelmad_sst_register( if (ret_val) return ret_val; sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0)); - pr_debug("sst: orginal n extrated vendor id = 0x%x %d\n", + pr_debug("orginal n extrated vendor id = 0x%x %d\n", vendor_addr.value, sst_card_vendor_id); if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) { - pr_err("sst: vendor card not supported!!\n"); + pr_err("vendor card not supported!!\n"); return -EIO; } } else @@ -801,7 +804,7 @@ static int __devinit snd_intelmad_sst_register( /* registering with SST driver to get access to SST APIs to use */ ret_val = register_sst_card(intelmaddata->sstdrv_ops); if (ret_val) { - pr_err("sst: sst card registration failed\n"); + pr_err("sst card registration failed\n"); return ret_val; } @@ -832,7 +835,7 @@ static int __devinit snd_intelmad_pcm_new(struct snd_card *card, char name[32] = INTEL_MAD; struct snd_pcm_ops *pb_ops = NULL, *cap_ops = NULL; - pr_debug("sst: called for pb %d, cp %d, idx %d\n", pb, cap, index); + pr_debug("called for pb %d, cp %d, idx %d\n", pb, cap, index); ret_val = snd_pcm_new(card, name, index, pb, cap, &pcm); if (ret_val) return ret_val; @@ -878,7 +881,7 @@ static int __devinit snd_intelmad_pcm(struct snd_card *card, WARN_ON(!card); WARN_ON(!intelmaddata); - pr_debug("sst: snd_intelmad_pcm called\n"); + pr_debug("snd_intelmad_pcm called\n"); ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 1, 0); if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) return ret_val; @@ -903,7 +906,7 @@ static int snd_intelmad_jack(struct snd_intelmad *intelmaddata) struct snd_jack *jack; int retval; - pr_debug("sst: snd_intelmad_jack called\n"); + pr_debug("snd_intelmad_jack called\n"); jack = &intelmaddata->jack[0].jack; retval = snd_jack_new(intelmaddata->card, "Headphone", SND_JACK_HEADPHONE, &jack); @@ -982,9 +985,9 @@ static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata) ret_val = snd_ctl_add(card, snd_ctl_new1(&controls[idx], intelmaddata)); - pr_debug("sst: mixer[idx]=%d added\n", idx); + pr_debug("mixer[idx]=%d added\n", idx); if (ret_val) { - pr_err("sst: in adding of control index = %d\n", idx); + pr_err("in adding of control index = %d\n", idx); break; } } @@ -999,7 +1002,7 @@ static int snd_intelmad_dev_free(struct snd_device *device) intelmaddata = device->device_data; - pr_debug("sst: snd_intelmad_dev_free called\n"); + pr_debug("snd_intelmad_dev_free called\n"); snd_card_free(intelmaddata->card); /*genl_unregister_family(&audio_event_genl_family);*/ unregister_sst_card(intelmaddata->sstdrv_ops); @@ -1040,23 +1043,23 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev) const struct platform_device_id *id = platform_get_device_id(pdev); unsigned int cpu_id = (unsigned int)id->driver_data; - pr_debug("sst: probe for %s cpu_id %d\n", pdev->name, cpu_id); + pr_debug("probe for %s cpu_id %d\n", pdev->name, cpu_id); if (!strcmp(pdev->name, DRIVER_NAME_MRST)) - pr_debug("sst: detected MRST\n"); + pr_debug("detected MRST\n"); else if (!strcmp(pdev->name, DRIVER_NAME_MFLD)) - pr_debug("sst: detected MFLD\n"); + pr_debug("detected MFLD\n"); else { - pr_err("sst: detected unknown device abort!!\n"); + pr_err("detected unknown device abort!!\n"); return -EIO; } if ((cpu_id < CPU_CHIP_LINCROFT) || (cpu_id > CPU_CHIP_PENWELL)) { - pr_err("sst: detected unknown cpu_id abort!!\n"); + pr_err("detected unknown cpu_id abort!!\n"); return -EIO; } /* allocate memory for saving internal context and working */ intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL); if (!intelmaddata) { - pr_debug("sst: mem alloctn fail\n"); + pr_debug("mem alloctn fail\n"); return -ENOMEM; } @@ -1064,7 +1067,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev) intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops), GFP_KERNEL); if (!intelmaddata->sstdrv_ops) { - pr_err("sst: mem allocation for ops fail\n"); + pr_err("mem allocation for ops fail\n"); kfree(intelmaddata); return -ENOMEM; } @@ -1073,7 +1076,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev) /* create a card instance with ALSA framework */ ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card); if (ret_val) { - pr_err("sst: snd_card_create fail\n"); + pr_err("snd_card_create fail\n"); goto free_allocs; } @@ -1092,7 +1095,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev) /* registering with LPE driver to get access to SST APIs to use */ ret_val = snd_intelmad_sst_register(intelmaddata); if (ret_val) { - pr_err("sst: snd_intelmad_sst_register failed\n"); + pr_err("snd_intelmad_sst_register failed\n"); goto free_allocs; } @@ -1100,19 +1103,19 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev) ret_val = snd_intelmad_pcm(card, intelmaddata); if (ret_val) { - pr_err("sst: snd_intelmad_pcm failed\n"); + pr_err("snd_intelmad_pcm failed\n"); goto free_allocs; } ret_val = snd_intelmad_mixer(intelmaddata); if (ret_val) { - pr_err("sst: snd_intelmad_mixer failed\n"); + pr_err("snd_intelmad_mixer failed\n"); goto free_allocs; } ret_val = snd_intelmad_jack(intelmaddata); if (ret_val) { - pr_err("sst: snd_intelmad_jack failed\n"); + pr_err("snd_intelmad_jack failed\n"); goto free_allocs; } @@ -1126,31 +1129,31 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev) ret_val = snd_intelmad_register_irq(intelmaddata); if (ret_val) { - pr_err("sst: snd_intelmad_register_irq fail\n"); + pr_err("snd_intelmad_register_irq fail\n"); goto free_allocs; } /* internal function call to register device with ALSA */ ret_val = snd_intelmad_create(intelmaddata, card); if (ret_val) { - pr_err("sst: snd_intelmad_create failed\n"); + pr_err("snd_intelmad_create failed\n"); goto free_allocs; } card->private_data = &intelmaddata; snd_card_set_dev(card, &pdev->dev); ret_val = snd_card_register(card); if (ret_val) { - pr_err("sst: snd_card_register failed\n"); + pr_err("snd_card_register failed\n"); goto free_allocs; } - pr_debug("sst:snd_intelmad_probe complete\n"); + pr_debug("snd_intelmad_probe complete\n"); return ret_val; free_mad_jack_wq: destroy_workqueue(intelmaddata->mad_jack_wq); free_allocs: - pr_err("sst: probe failed\n"); + pr_err("probe failed\n"); snd_card_free(card); kfree(intelmaddata->sstdrv_ops); kfree(intelmaddata); @@ -1200,7 +1203,7 @@ static struct platform_driver snd_intelmad_driver = { */ static int __init alsa_card_intelmad_init(void) { - pr_debug("sst: mad_init called\n"); + pr_debug("mad_init called\n"); return platform_driver_register(&snd_intelmad_driver); } @@ -1211,7 +1214,7 @@ static int __init alsa_card_intelmad_init(void) */ static void __exit alsa_card_intelmad_exit(void) { - pr_debug("sst:mad_exit called\n"); + pr_debug("mad_exit called\n"); return platform_driver_unregister(&snd_intelmad_driver); } diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c index 03b4ece02f91..0d9135715c74 100644 --- a/drivers/staging/intel_sst/intelmid_ctrl.c +++ b/drivers/staging/intel_sst/intelmid_ctrl.c @@ -24,6 +24,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ALSA driver handling mixer controls for Intel MAD chipset */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "jack.h" @@ -216,7 +219,7 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol, struct snd_intelmad *intelmaddata; struct snd_pmic_ops *scard_ops; - pr_debug("sst: snd_intelmad_volume_get called\n"); + pr_debug("snd_intelmad_volume_get called\n"); WARN_ON(!uval); WARN_ON(!kcontrol); @@ -273,7 +276,7 @@ static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol, struct snd_intelmad *intelmaddata; struct snd_pmic_ops *scard_ops; - pr_debug("sst: Mute_get called\n"); + pr_debug("Mute_get called\n"); WARN_ON(!uval); WARN_ON(!kcontrol); @@ -332,7 +335,7 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol, struct snd_intelmad *intelmaddata; struct snd_pmic_ops *scard_ops; - pr_debug("sst: volume set called:%ld %ld\n", + pr_debug("volume set called:%ld %ld\n", uval->value.integer.value[0], uval->value.integer.value[1]); @@ -387,7 +390,7 @@ static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol, struct snd_intelmad *intelmaddata; struct snd_pmic_ops *scard_ops; - pr_debug("sst: snd_intelmad_mute_set called\n"); + pr_debug("snd_intelmad_mute_set called\n"); WARN_ON(!uval); WARN_ON(!kcontrol); @@ -455,7 +458,7 @@ static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol, { struct snd_intelmad *intelmaddata; struct snd_pmic_ops *scard_ops; - pr_debug("sst: device_get called\n"); + pr_debug("device_get called\n"); WARN_ON(!uval); WARN_ON(!kcontrol); @@ -492,7 +495,7 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, struct snd_pmic_ops *scard_ops; int ret_val = 0, vendor, status; - pr_debug("sst: snd_intelmad_device_set called\n"); + pr_debug("snd_intelmad_device_set called\n"); WARN_ON(!uval); WARN_ON(!kcontrol); diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c index 4d1755efceef..da093ed0cd88 100644 --- a/drivers/staging/intel_sst/intelmid_msic_control.c +++ b/drivers/staging/intel_sst/intelmid_msic_control.c @@ -24,6 +24,8 @@ * This file contains the control operations of msic vendors */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "intel_sst.h" @@ -83,7 +85,7 @@ static int msic_init_card(void) snd_msic_ops.cap_on = 0; snd_msic_ops.input_dev_id = DMIC; /*def dev*/ snd_msic_ops.output_dev_id = STEREO_HEADPHONE; - pr_debug("sst: msic init complete!!\n"); + pr_debug("msic init complete!!\n"); return 0; } @@ -173,7 +175,7 @@ static int msic_power_up_pb(unsigned int device) return retval; } - pr_debug("sst: powering up pb.... Device %d\n", device); + pr_debug("powering up pb.... Device %d\n", device); sst_sc_reg_access(sc_access1, PMIC_WRITE, 4); switch (device) { case SND_SST_DEVICE_HEADSET: @@ -205,7 +207,7 @@ static int msic_power_up_pb(unsigned int device) break; default: - pr_warn("sst: Wrong Device %d, selected %d\n", + pr_warn("Wrong Device %d, selected %d\n", device, snd_msic_ops.output_dev_id); } return sst_sc_reg_access(sc_access_pcm2, PMIC_READ_MODIFY, 1); @@ -268,7 +270,7 @@ static int msic_power_up_cp(unsigned int device) return retval; } - pr_debug("sst: powering up cp....%d\n", snd_msic_ops.input_dev_id); + pr_debug("powering up cp....%d\n", snd_msic_ops.input_dev_id); sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1); snd_msic_ops.cap_on = 1; if (snd_msic_ops.input_dev_id == AMIC) @@ -283,7 +285,7 @@ static int msic_power_down(void) { int retval = 0; - pr_debug("sst: powering dn msic\n"); + pr_debug("powering dn msic\n"); snd_msic_ops.pb_on = 0; snd_msic_ops.cap_on = 0; return retval; @@ -293,7 +295,7 @@ static int msic_power_down_pb(void) { int retval = 0; - pr_debug("sst: powering dn pb....\n"); + pr_debug("powering dn pb....\n"); snd_msic_ops.pb_on = 0; return retval; } @@ -302,7 +304,7 @@ static int msic_power_down_cp(void) { int retval = 0; - pr_debug("sst: powering dn cp....\n"); + pr_debug("powering dn cp....\n"); snd_msic_ops.cap_on = 0; return retval; } @@ -311,7 +313,7 @@ static int msic_set_selected_output_dev(u8 value) { int retval = 0; - pr_debug("sst: msic set selected output:%d\n", value); + pr_debug("msic set selected output:%d\n", value); snd_msic_ops.output_dev_id = value; if (snd_msic_ops.pb_on) msic_power_up_pb(SND_SST_DEVICE_HEADSET); @@ -330,15 +332,15 @@ static int msic_set_selected_input_dev(u8 value) }; int retval = 0; - pr_debug("sst: msic_set_selected_input_dev:%d\n", value); + pr_debug("msic_set_selected_input_dev:%d\n", value); snd_msic_ops.input_dev_id = value; switch (value) { case AMIC: - pr_debug("sst: Selecting AMIC1\n"); + pr_debug("Selecting AMIC1\n"); retval = sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 1); break; case DMIC: - pr_debug("sst: Selecting DMIC1\n"); + pr_debug("Selecting DMIC1\n"); retval = sst_sc_reg_access(sc_access_dmic, PMIC_WRITE, 1); break; default: diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c index 9ed9475ccc7b..4f9bdf364dca 100644 --- a/drivers/staging/intel_sst/intelmid_pvt.c +++ b/drivers/staging/intel_sst/intelmid_pvt.c @@ -23,6 +23,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ALSA driver for Intel MID sound card chipset - holding private functions */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -50,7 +53,7 @@ void period_elapsed(void *mad_substream) if (stream->stream_status != RUNNING) return; - pr_debug("sst: calling period elapsed\n"); + pr_debug("calling period elapsed\n"); snd_pcm_period_elapsed(substream); return; } @@ -76,8 +79,8 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream) param.uc.pcm_params.period_count = substream->runtime->period_size; param.uc.pcm_params.ring_buffer_addr = virt_to_phys(substream->runtime->dma_area); - pr_debug("sst: period_cnt = %d\n", param.uc.pcm_params.period_count); - pr_debug("sst: sfreq= %d, wd_sz = %d\n", + pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count); + pr_debug("sfreq= %d, wd_sz = %d\n", param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz); str_params.sparams = param; @@ -85,16 +88,16 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { str_params.ops = STREAM_OPS_PLAYBACK; - pr_debug("sst: Playbck stream,Device %d\n", stream->device); + pr_debug("Playbck stream,Device %d\n", stream->device); } else { str_params.ops = STREAM_OPS_CAPTURE; stream->device = SND_SST_DEVICE_CAPTURE; - pr_debug("sst: Capture stream,Device %d\n", stream->device); + pr_debug("Capture stream,Device %d\n", stream->device); } str_params.device_type = stream->device; ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC, &str_params); - pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n", + pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); if (ret_val < 0) return ret_val; @@ -102,7 +105,7 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream) stream->stream_info.str_id = ret_val; stream->stream_status = INIT; stream->stream_info.buffer_ptr = 0; - pr_debug("sst: str id : %d\n", stream->stream_info.str_id); + pr_debug("str id : %d\n", stream->stream_info.str_id); return ret_val; } @@ -113,7 +116,7 @@ int snd_intelmad_init_stream(struct snd_pcm_substream *substream) struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream); int ret_val; - pr_debug("sst: setting buffer ptr param\n"); + pr_debug("setting buffer ptr param\n"); stream->stream_info.period_elapsed = period_elapsed; stream->stream_info.mad_substream = substream; stream->stream_info.buffer_ptr = 0; @@ -121,7 +124,7 @@ int snd_intelmad_init_stream(struct snd_pcm_substream *substream) ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT, &stream->stream_info); if (ret_val) - pr_err("sst: control_set ret error %d\n", ret_val); + pr_err("control_set ret error %d\n", ret_val); return ret_val; } @@ -146,7 +149,7 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access, retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, sc_access[i].value); if (retval) { - pr_err("sst: IPC write failed!!! %d\n", retval); + pr_err("IPC write failed!!! %d\n", retval); return retval; } } @@ -155,7 +158,7 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access, retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, &(sc_access[i].value)); if (retval) { - pr_err("sst: IPC read failed!!!!!%d\n", retval); + pr_err("IPC read failed!!!!!%d\n", retval); return retval; } } @@ -165,7 +168,7 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access, sc_access[i].reg_addr, sc_access[i].value, sc_access[i].mask); if (retval) { - pr_err("sst: IPC Modify failed!!!%d\n", retval); + pr_err("IPC Modify failed!!!%d\n", retval); return retval; } } diff --git a/drivers/staging/intel_sst/intelmid_v0_control.c b/drivers/staging/intel_sst/intelmid_v0_control.c index f586d62ac9af..7859225e3d60 100644 --- a/drivers/staging/intel_sst/intelmid_v0_control.c +++ b/drivers/staging/intel_sst/intelmid_v0_control.c @@ -26,6 +26,8 @@ * This file contains the control operations of vendor 1 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "intel_sst.h" @@ -151,7 +153,7 @@ static int fs_power_up_pb(unsigned int port) if (retval) return retval; - pr_debug("sst: in fs power up pb\n"); + pr_debug("in fs power up pb\n"); return fs_enable_audiodac(UNMUTE); } @@ -173,7 +175,7 @@ static int fs_power_down_pb(void) if (retval) return retval; - pr_debug("sst: in fsl power down pb\n"); + pr_debug("in fsl power down pb\n"); return fs_enable_audiodac(UNMUTE); } @@ -380,7 +382,7 @@ static int fs_set_pcm_audio_params(int sfreq, int word_size, int num_channel) sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); } - pr_debug("sst: sfreq:%d,Register value = %x\n", sfreq, config1); + pr_debug("sfreq:%d,Register value = %x\n", sfreq, config1); if (word_size == 24) { sc_access[0].reg_addr = AUDIOPORT1; @@ -438,18 +440,18 @@ static int fs_set_selected_input_dev(u8 value) switch (value) { case AMIC: - pr_debug("sst: Selecting amic not supported in mono cfg\n"); + pr_debug("Selecting amic not supported in mono cfg\n"); return sst_sc_reg_access(sc_access_mic, PMIC_READ_MODIFY, 2); break; case HS_MIC: - pr_debug("sst: Selecting hsmic\n"); + pr_debug("Selecting hsmic\n"); return sst_sc_reg_access(sc_access_hsmic, PMIC_READ_MODIFY, 2); break; case DMIC: - pr_debug("sst: Selecting dmic\n"); + pr_debug("Selecting dmic\n"); return sst_sc_reg_access(sc_access_dmic, PMIC_READ_MODIFY, 2); break; @@ -505,7 +507,7 @@ static int fs_set_mute(int dev_id, u8 value) return retval; - pr_debug("sst: dev_id:0x%x value:0x%x\n", dev_id, value); + pr_debug("dev_id:0x%x value:0x%x\n", dev_id, value); switch (dev_id) { case PMIC_SND_DMIC_MUTE: sc_access[0].reg_addr = MICCTRL; @@ -606,7 +608,7 @@ static int fs_set_vol(int dev_id, int value) switch (dev_id) { case PMIC_SND_LEFT_PB_VOL: - pr_debug("sst: PMIC_SND_LEFT_PB_VOL:%d\n", value); + pr_debug("PMIC_SND_LEFT_PB_VOL:%d\n", value); sc_access[0].value = sc_access[1].value = value; sc_access[0].reg_addr = AUD16; sc_access[1].reg_addr = AUD15; @@ -616,7 +618,7 @@ static int fs_set_vol(int dev_id, int value) break; case PMIC_SND_RIGHT_PB_VOL: - pr_debug("sst: PMIC_SND_RIGHT_PB_VOL:%d\n", value); + pr_debug("PMIC_SND_RIGHT_PB_VOL:%d\n", value); sc_access[0].value = sc_access[1].value = value; sc_access[0].reg_addr = AUD17; sc_access[1].reg_addr = AUD15; @@ -629,7 +631,7 @@ static int fs_set_vol(int dev_id, int value) reg_num = 2; break; case PMIC_SND_CAPTURE_VOL: - pr_debug("sst: PMIC_SND_CAPTURE_VOL:%d\n", value); + pr_debug("PMIC_SND_CAPTURE_VOL:%d\n", value); sc_access[0].reg_addr = MICLICTRL1; sc_access[1].reg_addr = MICLICTRL2; sc_access[2].reg_addr = DMICCTRL1; @@ -726,17 +728,17 @@ static int fs_get_vol(int dev_id, int *value) switch (dev_id) { case PMIC_SND_CAPTURE_VOL: - pr_debug("sst: PMIC_SND_CAPTURE_VOL\n"); + pr_debug("PMIC_SND_CAPTURE_VOL\n"); sc_access.reg_addr = MICLICTRL1; mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0); break; case PMIC_SND_LEFT_PB_VOL: - pr_debug("sst: PMIC_SND_LEFT_PB_VOL\n"); + pr_debug("PMIC_SND_LEFT_PB_VOL\n"); sc_access.reg_addr = AUD16; mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0); break; case PMIC_SND_RIGHT_PB_VOL: - pr_debug("sst: PMIC_SND_RT_PB_VOL\n"); + pr_debug("PMIC_SND_RT_PB_VOL\n"); sc_access.reg_addr = AUD17; mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0); break; @@ -745,9 +747,9 @@ static int fs_get_vol(int dev_id, int *value) } retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - pr_debug("sst: value read = 0x%x\n", sc_access.value); + pr_debug("value read = 0x%x\n", sc_access.value); *value = (int) (sc_access.value & mask); - pr_debug("sst: value returned = 0x%x\n", *value); + pr_debug("value returned = 0x%x\n", *value); return retval; } diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c index 9de86b2f6b08..62a932bf809a 100644 --- a/drivers/staging/intel_sst/intelmid_v1_control.c +++ b/drivers/staging/intel_sst/intelmid_v1_control.c @@ -25,6 +25,8 @@ * This file contains the control operations of vendor 2 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -150,11 +152,11 @@ static int mx_init_capture_card(void) retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 8); if (0 != retval) { /* pmic communication fails */ - pr_debug("sst: pmic commn failed\n"); + pr_debug("pmic commn failed\n"); return retval; } - pr_debug("sst: Capture configuration complete!!\n"); + pr_debug("Capture configuration complete!!\n"); return 0; } @@ -174,11 +176,11 @@ static int mx_init_playback_card(void) retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 9); if (0 != retval) { /* pmic communication fails */ - pr_debug("sst: pmic commn failed\n"); + pr_debug("pmic commn failed\n"); return retval; } - pr_debug("sst: Playback configuration complete!!\n"); + pr_debug("Playback configuration complete!!\n"); return 0; } @@ -204,7 +206,7 @@ static int mx_enable_audiodac(int value) retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); if (retval) return retval; - pr_debug("sst: mute status = %d", snd_pmic_ops_mx.mute_status); + pr_debug("mute status = %d\n", snd_pmic_ops_mx.mute_status); if (snd_pmic_ops_mx.mute_status == MUTE || snd_pmic_ops_mx.master_mute == MUTE) return retval; @@ -412,7 +414,7 @@ static int mx_set_pcm_voice_params(void) if (retval) return retval; } - pr_debug("sst: SST DBG mx_set_pcm_voice_params called\n"); + pr_debug("SST DBG:mx_set_pcm_voice_params called\n"); return sst_sc_reg_access(sc_access, PMIC_WRITE, 44); } @@ -529,7 +531,7 @@ static int mx_set_selected_output_dev(u8 dev_id) return retval; } - pr_debug("sst: mx_set_selected_output_dev dev_id:0x%x\n", dev_id); + pr_debug("mx_set_selected_output_dev dev_id:0x%x\n", dev_id); snd_pmic_ops_mx.output_dev_id = dev_id; switch (dev_id) { case STEREO_HEADPHONE: @@ -549,7 +551,7 @@ static int mx_set_selected_output_dev(u8 dev_id) num_reg = 1; break; case RECEIVER: - pr_debug("sst: RECEIVER Koski selected\n"); + pr_debug("RECEIVER Koski selected\n"); /* configuration - AS enable, receiver enable */ sc_access[0].reg_addr = 0xFF; @@ -559,7 +561,7 @@ static int mx_set_selected_output_dev(u8 dev_id) num_reg = 1; break; default: - pr_err("sst: Not a valid output dev\n"); + pr_err("Not a valid output dev\n"); return 0; } return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg); @@ -598,7 +600,7 @@ static int mx_set_selected_input_dev(u8 dev_id) return retval; } snd_pmic_ops_mx.input_dev_id = dev_id; - pr_debug("sst: mx_set_selected_input_dev dev_id:0x%x\n", dev_id); + pr_debug("mx_set_selected_input_dev dev_id:0x%x\n", dev_id); switch (dev_id) { case AMIC: @@ -646,7 +648,7 @@ static int mx_set_mute(int dev_id, u8 value) } - pr_debug("sst: set_mute dev_id:0x%x , value:%d\n", dev_id, value); + pr_debug("set_mute dev_id:0x%x , value:%d\n", dev_id, value); switch (dev_id) { case PMIC_SND_DMIC_MUTE: @@ -760,7 +762,7 @@ static int mx_set_vol(int dev_id, int value) if (retval) return retval; } - pr_debug("sst: set_vol dev_id:0x%x ,value:%d\n", dev_id, value); + pr_debug("set_vol dev_id:0x%x ,value:%d\n", dev_id, value); switch (dev_id) { case PMIC_SND_RECEIVER_VOL: return 0; @@ -875,7 +877,7 @@ static int mx_get_vol(int dev_id, int *value) if (retval) return retval; *value = -(sc_access.value & mask); - pr_debug("sst: get volume value extracted %d\n", *value); + pr_debug("get volume value extracted %d\n", *value); return retval; } diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c index 3a7de769842a..81cb9d70870b 100644 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ b/drivers/staging/intel_sst/intelmid_v2_control.c @@ -26,6 +26,8 @@ * This file contains the control operations of vendor 3 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "intel_sst.h" @@ -120,7 +122,7 @@ static int nc_init_card(void) snd_pmic_ops_nc.master_mute = UNMUTE; snd_pmic_ops_nc.mute_status = UNMUTE; sst_sc_reg_access(sc_access, PMIC_WRITE, 26); - pr_debug("sst: init complete!!\n"); + pr_debug("init complete!!\n"); return 0; } @@ -169,7 +171,7 @@ static int nc_power_up_pb(unsigned int port) nc_enable_audiodac(MUTE); msleep(30); - pr_debug("sst: powering up pb....\n"); + pr_debug("powering up pb....\n"); sc_access[0].reg_addr = VAUDIOCNT; sc_access[0].value = 0x27; @@ -222,7 +224,7 @@ static int nc_power_up_cp(unsigned int port) return retval; - pr_debug("sst: powering up cp....\n"); + pr_debug("powering up cp....\n"); if (port == 0xFF) return 0; @@ -275,7 +277,7 @@ static int nc_power_down(void) nc_enable_audiodac(MUTE); - pr_debug("sst: powering dn nc_power_down ....\n"); + pr_debug("powering dn nc_power_down ....\n"); msleep(30); @@ -324,7 +326,7 @@ static int nc_power_down_pb(void) if (retval) return retval; - pr_debug("sst: powering dn pb....\n"); + pr_debug("powering dn pb....\n"); nc_enable_audiodac(MUTE); @@ -370,7 +372,7 @@ static int nc_power_down_cp(void) if (retval) return retval; - pr_debug("sst: powering dn cp....\n"); + pr_debug("powering dn cp....\n"); return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); } @@ -400,7 +402,7 @@ static int nc_set_pcm_voice_params(void) return retval; sst_sc_reg_access(sc_access, PMIC_WRITE, 14); - pr_debug("sst: Voice parameters set successfully!!\n"); + pr_debug("Voice parameters set successfully!!\n"); return 0; } @@ -451,20 +453,20 @@ static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel) sc_access.value = 0x07; sc_access.reg_addr = RMUTE; - pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_access.value); + pr_debug("RIGHT_HP_MUTE value%d\n", sc_access.value); sc_access.mask = MASK2; sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); } else { sc_access.value = 0x00; sc_access.reg_addr = RMUTE; - pr_debug("sst: RIGHT_HP_MUTE value %d\n", sc_access.value); + pr_debug("RIGHT_HP_MUTE value %d\n", sc_access.value); sc_access.mask = MASK2; sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); } - pr_debug("sst: word_size = %d\n", word_size); + pr_debug("word_size = %d\n", word_size); if (word_size == 24) { sc_access.reg_addr = AUDIOPORT2; @@ -477,7 +479,7 @@ static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel) } sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1); - pr_debug("sst: word_size = %d\n", word_size); + pr_debug("word_size = %d\n", word_size); sc_access.reg_addr = AUDIOPORT1; sc_access.mask = MASK5|MASK4|MASK1|MASK0; if (word_size == 16) @@ -508,7 +510,7 @@ static int nc_set_selected_output_dev(u8 value) retval = nc_init_card(); if (retval) return retval; - pr_debug("sst: nc set selected output:%d\n", value); + pr_debug("nc set selected output:%d\n", value); switch (value) { case STEREO_HEADPHONE: retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2); @@ -517,7 +519,7 @@ static int nc_set_selected_output_dev(u8 value) retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 2); break; default: - pr_err("sst: rcvd illegal request: %d\n", value); + pr_err("rcvd illegal request: %d\n", value); return -EINVAL; } return retval; @@ -541,7 +543,7 @@ static int nc_audio_init(void) }; sst_sc_reg_access(sc_access, PMIC_WRITE, 12); - pr_debug("sst: Audio Init successfully!!\n"); + pr_debug("Audio Init successfully!!\n"); /*set output device */ nc_set_selected_output_dev(snd_pmic_ops_nc.output_dev_id); @@ -549,13 +551,13 @@ static int nc_audio_init(void) if (snd_pmic_ops_nc.num_channel == 1) { sc_acces.value = 0x07; sc_acces.reg_addr = RMUTE; - pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value); + pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value); sc_acces.mask = MASK2; sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); } else { sc_acces.value = 0x00; sc_acces.reg_addr = RMUTE; - pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value); + pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value); sc_acces.mask = MASK2; sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1); } @@ -629,11 +631,11 @@ static int nc_set_mute(int dev_id, u8 value) if (retval) return retval; - pr_debug("sst: set device id::%d, value %d\n", dev_id, value); + pr_debug("set device id::%d, value %d\n", dev_id, value); switch (dev_id) { case PMIC_SND_MUTE_ALL: - pr_debug("sst: PMIC_SND_MUTE_ALL value %d\n", value); + pr_debug("PMIC_SND_MUTE_ALL value %d\n", value); snd_pmic_ops_nc.mute_status = value; snd_pmic_ops_nc.master_mute = value; if (value == UNMUTE) { @@ -669,7 +671,7 @@ static int nc_set_mute(int dev_id, u8 value) } break; case PMIC_SND_HP_MIC_MUTE: - pr_debug("sst: PMIC_SND_HPMIC_MUTE value %d\n", value); + pr_debug("PMIC_SND_HPMIC_MUTE value %d\n", value); if (value == UNMUTE) { /* unmute the system, set the 6th bit to one */ sc_access[0].value = 0x00; @@ -682,7 +684,7 @@ static int nc_set_mute(int dev_id, u8 value) retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); break; case PMIC_SND_AMIC_MUTE: - pr_debug("sst: PMIC_SND_AMIC_MUTE value %d\n", value); + pr_debug("PMIC_SND_AMIC_MUTE value %d\n", value); if (value == UNMUTE) { /* unmute the system, set the 6th bit to one */ sc_access[0].value = 0x00; @@ -696,7 +698,7 @@ static int nc_set_mute(int dev_id, u8 value) break; case PMIC_SND_DMIC_MUTE: - pr_debug("sst: INPUT_MUTE_DMIC value%d\n", value); + pr_debug("INPUT_MUTE_DMIC value%d\n", value); if (value == UNMUTE) { /* unmute the system, set the 6th bit to one */ sc_access[1].value = 0x00; @@ -724,13 +726,13 @@ static int nc_set_mute(int dev_id, u8 value) if (dev_id == PMIC_SND_LEFT_HP_MUTE) { sc_access[0].reg_addr = LMUTE; - pr_debug("sst: LEFT_HP_MUTE value %d\n", + pr_debug("LEFT_HP_MUTE value %d\n", sc_access[0].value); } else { if (snd_pmic_ops_nc.num_channel == 1) sc_access[0].value = 0x04; sc_access[0].reg_addr = RMUTE; - pr_debug("sst: RIGHT_HP_MUTE value %d\n", + pr_debug("RIGHT_HP_MUTE value %d\n", sc_access[0].value); } sc_access[0].mask = MASK2; @@ -743,7 +745,7 @@ static int nc_set_mute(int dev_id, u8 value) else sc_access[0].value = 0x03; sc_access[0].reg_addr = LMUTE; - pr_debug("sst: SPEAKER_MUTE %d\n", sc_access[0].value); + pr_debug("SPEAKER_MUTE %d\n", sc_access[0].value); sc_access[0].mask = MASK1; retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); break; @@ -764,10 +766,10 @@ static int nc_set_vol(int dev_id, int value) if (retval) return retval; - pr_debug("sst: set volume:%d\n", dev_id); + pr_debug("set volume:%d\n", dev_id); switch (dev_id) { case PMIC_SND_CAPTURE_VOL: - pr_debug("sst: PMIC_SND_CAPTURE_VOL:value::%d\n", value); + pr_debug("PMIC_SND_CAPTURE_VOL:value::%d\n", value); sc_access[0].value = sc_access[1].value = sc_access[2].value = -value; sc_access[0].mask = sc_access[1].mask = sc_access[2].mask = @@ -779,7 +781,7 @@ static int nc_set_vol(int dev_id, int value) break; case PMIC_SND_LEFT_PB_VOL: - pr_debug("sst: PMIC_SND_LEFT_HP_VOL %d\n", value); + pr_debug("PMIC_SND_LEFT_HP_VOL %d\n", value); sc_access[0].value = -value; sc_access[0].reg_addr = AUDIOLVOL; sc_access[0].mask = @@ -788,7 +790,7 @@ static int nc_set_vol(int dev_id, int value) break; case PMIC_SND_RIGHT_PB_VOL: - pr_debug("sst: PMIC_SND_RIGHT_HP_VOL value %d\n", value); + pr_debug("PMIC_SND_RIGHT_HP_VOL value %d\n", value); if (snd_pmic_ops_nc.num_channel == 1) { sc_access[0].value = 0x04; sc_access[0].reg_addr = RMUTE; @@ -821,11 +823,11 @@ static int nc_set_selected_input_dev(u8 value) return retval; snd_pmic_ops_nc.input_dev_id = value; - pr_debug("sst: nc set selected input:%d\n", value); + pr_debug("nc set selected input:%d\n", value); switch (value) { case AMIC: - pr_debug("sst: Selecting AMIC\n"); + pr_debug("Selecting AMIC\n"); sc_access[0].reg_addr = 0x107; sc_access[0].value = 0x40; sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0; @@ -842,7 +844,7 @@ static int nc_set_selected_input_dev(u8 value) break; case HS_MIC: - pr_debug("sst: Selecting HS_MIC\n"); + pr_debug("Selecting HS_MIC\n"); sc_access[0].reg_addr = 0x107; sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0; sc_access[0].value = 0x10; @@ -859,7 +861,7 @@ static int nc_set_selected_input_dev(u8 value) break; case DMIC: - pr_debug("sst: DMIC\n"); + pr_debug("DMIC\n"); sc_access[0].reg_addr = 0x107; sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0; sc_access[0].value = 0x0B; @@ -890,23 +892,23 @@ static int nc_get_mute(int dev_id, u8 *value) if (retval) return retval; - pr_debug("sst: get mute::%d\n", dev_id); + pr_debug("get mute::%d\n", dev_id); switch (dev_id) { case PMIC_SND_AMIC_MUTE: - pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC1\n"); + pr_debug("PMIC_SND_INPUT_MUTE_MIC1\n"); sc_access.reg_addr = LILSEL; mask = MASK6; break; case PMIC_SND_HP_MIC_MUTE: - pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC2\n"); + pr_debug("PMIC_SND_INPUT_MUTE_MIC2\n"); sc_access.reg_addr = LIRSEL; mask = MASK6; break; case PMIC_SND_LEFT_HP_MUTE: case PMIC_SND_RIGHT_HP_MUTE: mask = MASK2; - pr_debug("sst: PMIC_SN_LEFT/RIGHT_HP_MUTE\n"); + pr_debug("PMIC_SN_LEFT/RIGHT_HP_MUTE\n"); if (dev_id == PMIC_SND_RIGHT_HP_MUTE) sc_access.reg_addr = RMUTE; else @@ -914,12 +916,12 @@ static int nc_get_mute(int dev_id, u8 *value) break; case PMIC_SND_LEFT_SPEAKER_MUTE: - pr_debug("sst: PMIC_MONO_EARPIECE_MUTE\n"); + pr_debug("PMIC_MONO_EARPIECE_MUTE\n"); sc_access.reg_addr = RMUTE; mask = MASK1; break; case PMIC_SND_DMIC_MUTE: - pr_debug("sst: PMIC_SND_INPUT_MUTE_DMIC\n"); + pr_debug("PMIC_SND_INPUT_MUTE_DMIC\n"); sc_access.reg_addr = 0x105; mask = MASK6; break; @@ -928,16 +930,16 @@ static int nc_get_mute(int dev_id, u8 *value) } retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - pr_debug("sst: reg value = %d\n", sc_access.value); + pr_debug("reg value = %d\n", sc_access.value); if (retval) return retval; *value = (sc_access.value) & mask; - pr_debug("sst: masked value = %d\n", *value); + pr_debug("masked value = %d\n", *value); if (*value) *value = 0; else *value = 1; - pr_debug("sst: value returned = 0x%x\n", *value); + pr_debug("value returned = 0x%x\n", *value); return retval; } @@ -953,19 +955,19 @@ static int nc_get_vol(int dev_id, int *value) switch (dev_id) { case PMIC_SND_CAPTURE_VOL: - pr_debug("sst: PMIC_SND_INPUT_CAPTURE_VOL\n"); + pr_debug("PMIC_SND_INPUT_CAPTURE_VOL\n"); sc_access.reg_addr = LILSEL; mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); break; case PMIC_SND_RIGHT_PB_VOL: - pr_debug("sst: GET_VOLUME_PMIC_LEFT_HP_VOL\n"); + pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n"); sc_access.reg_addr = AUDIOLVOL; mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); break; case PMIC_SND_LEFT_PB_VOL: - pr_debug("sst: GET_VOLUME_PMIC_RIGHT_HP_VOL\n"); + pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n"); sc_access.reg_addr = AUDIORVOL; mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6); break; @@ -975,9 +977,9 @@ static int nc_get_vol(int dev_id, int *value) } retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1); - pr_debug("sst: value read = 0x%x\n", sc_access.value); + pr_debug("value read = 0x%x\n", sc_access.value); *value = -((sc_access.value) & mask); - pr_debug("sst: get vol value returned = %d\n", *value); + pr_debug("get vol value returned = %d\n", *value); return retval; } -- cgit v1.2.3 From dec34f85c62845a4d190a45aa5b5e9dd96797880 Mon Sep 17 00:00:00 2001 From: Tracey Dent Date: Fri, 22 Oct 2010 17:30:28 -0400 Subject: Staging: msm: Makefile: replace the use of -objs with -y Changed -objs to -y in Makefile. Signed-off-by: Tracey Dent Signed-off-by: Greg Kroah-Hartman --- drivers/staging/msm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/msm/Makefile b/drivers/staging/msm/Makefile index bb3606faf20e..07a89ecfcc2b 100644 --- a/drivers/staging/msm/Makefile +++ b/drivers/staging/msm/Makefile @@ -41,11 +41,11 @@ obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o # MDDI -msm_mddi-objs := mddi.o mddihost.o mddihosti.o +msm_mddi-y := mddi.o mddihost.o mddihosti.o obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o # External MDDI -msm_mddi_ext-objs := mddihost_e.o mddi_ext.o +msm_mddi_ext-y := mddihost_e.o mddi_ext.o obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o # TVEnc -- cgit v1.2.3 From c4fb2bab7dea7780452e57166bd00cdfa9dba6ef Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 26 Oct 2010 21:57:52 +0200 Subject: Staging: trivial: fix typos concerning "configure" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/rtd520.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 60ebfc3c75fd..aa8aeeee043f 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -753,7 +753,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; struct pci_dev *pcidev; int ret; - resource_size_t physLas0; /* configuation */ + resource_size_t physLas0; /* configuration */ resource_size_t physLas1; /* data area */ resource_size_t physLcfg; /* PLX9080 */ #ifdef USE_DMA -- cgit v1.2.3 From af02b584bc0e1f46cf1477ad54ae18ec3842b6f4 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 26 Oct 2010 21:57:53 +0200 Subject: Staging: trivial: fix typos concerning "controller" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/addi-data/addi_common.c | 4 ++-- drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c | 2 +- drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c | 2 +- drivers/staging/rtl8192u/r8192U_core.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 93d7c056741d..76f2483871a7 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -2710,10 +2710,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) } else { outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); } - /* Enable the interrupt for the controler */ + /* Enable the interrupt for the controller */ dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); - printk("\nEnable the interrupt for the controler"); + printk("\nEnable the interrupt for the controller"); } printk("\nRead Eeprom"); i_EepromReadMainHeader(io_addr[0], this_board->pc_EepromChip, diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c index 912bc0fc54bf..a76ed2553fb4 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c @@ -225,7 +225,7 @@ int i_APCI1710_Reset(struct comedi_device *dev) devpriv->s_BoardInfos.b_BoardVersion = 1; - /* Enable the interrupt for the controler */ + /* Enable the interrupt for the controller */ dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38); outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index b943a06e70dc..a93e2349ad3a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -3011,7 +3011,7 @@ int i_APCI3200_Reset(struct comedi_device *dev) outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); - /* Enable the interrupt for the controler */ + /* Enable the interrupt for the controller */ dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); outl(0, devpriv->i_IobaseAddon); /* Resets the output */ diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 494f180acc26..4cc7b418c91e 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -1507,7 +1507,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb) { // // Handle HW Beacon: - // We had transfer our beacon frame to host controler at this moment. + // We had transfer our beacon frame to host controller at this moment. // // // Caution: -- cgit v1.2.3 From fc2347e2023221ef04c6d9ce84019aa8c7e0ad6d Mon Sep 17 00:00:00 2001 From: Atul Sowani Date: Wed, 3 Nov 2010 18:40:56 +0530 Subject: Staging: xgifb: change obsolete pci_find_device() with pci_get_device() Replaced obsolete pci_find_device() calls with pci_get_device() calls. This is recommended in pci.txt filei in PCI Documentation. Signed-off-by: Atul Sowani Acked-by: Arnaud Patard Signed-off-by: Greg Kroah-Hartman --- drivers/staging/xgifb/XGI_main_26.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 4f73d095c3ac..36ec45b84fca 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -472,9 +472,11 @@ unsigned char XGIfb_query_north_bridge_space(struct xgi_hw_device_info *pXGIhw_e break; } - pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); - if (pdev) + pdev = pci_get_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); + if (pdev) { valid_pdev = 1; + pci_dev_put(pdev); + } } if (!valid_pdev) { -- cgit v1.2.3 From 78fd115e21087133be74bc6dd7a9bc1969aea8f8 Mon Sep 17 00:00:00 2001 From: Ramesh Agarwal Date: Fri, 22 Oct 2010 14:00:20 +0100 Subject: Staging: add Synaptics TM1217 Touchscreen Controller driver This is submitted as a staging driver because there is a more generic driver "on the way" for all these devices and has been for some time. The intent is that as soon as the general drivers are in the mainstream this one will get any leftovers integrated and then be dumped. Until this unspecified future data at least people can actually use their hardware. As its interface is simply input layer we can do that without pain. Some clean up by Alan Cox - Extract gpio support and IRQ support more sanely - Tidying Signed-off-by: Ramesh Agarwal [avoid deference NULL ts if kzalloc fails] [finger_touched may be used uninitialized] [fix missing sync which confused twm] Signed-off-by: Hong Liu Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/cptm1217/Kconfig | 11 + drivers/staging/cptm1217/Makefile | 2 + drivers/staging/cptm1217/TODO | 5 + drivers/staging/cptm1217/clearpad_tm1217.c | 675 +++++++++++++++++++++++++++++ drivers/staging/cptm1217/cp_tm1217.h | 9 + 7 files changed, 705 insertions(+) create mode 100644 drivers/staging/cptm1217/Kconfig create mode 100644 drivers/staging/cptm1217/Makefile create mode 100644 drivers/staging/cptm1217/TODO create mode 100644 drivers/staging/cptm1217/clearpad_tm1217.c create mode 100644 drivers/staging/cptm1217/cp_tm1217.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 5eafdf435550..2c478c476edd 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -175,5 +175,7 @@ source "drivers/staging/intel_sst/Kconfig" source "drivers/staging/speakup/Kconfig" +source "drivers/staging/cptm1217/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a97a955c094b..74d0b4cc7a0a 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_BCM_WIMAX) += bcm/ obj-$(CONFIG_FT1000) += ft1000/ obj-$(CONFIG_SND_INTEL_SST) += intel_sst/ obj-$(CONFIG_SPEAKUP) += speakup/ +obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ diff --git a/drivers/staging/cptm1217/Kconfig b/drivers/staging/cptm1217/Kconfig new file mode 100644 index 000000000000..f90545d78f93 --- /dev/null +++ b/drivers/staging/cptm1217/Kconfig @@ -0,0 +1,11 @@ +config TOUCHSCREEN_CLEARPAD_TM1217 + tristate "Synaptics Clearpad TM1217" + depends on I2C + depends on GPIOLIB + help + Say Y here if you have a Synaptics Clearpad TM1217 Controller + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called clearpad_tm1217. diff --git a/drivers/staging/cptm1217/Makefile b/drivers/staging/cptm1217/Makefile new file mode 100644 index 000000000000..8961fafa80e7 --- /dev/null +++ b/drivers/staging/cptm1217/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += clearpad_tm1217.o + diff --git a/drivers/staging/cptm1217/TODO b/drivers/staging/cptm1217/TODO new file mode 100644 index 000000000000..303922465e4d --- /dev/null +++ b/drivers/staging/cptm1217/TODO @@ -0,0 +1,5 @@ +- Wait for the official upstream general clearpad drivers as promised over + the past few months +- Merge any device support needed from this driver into it +- Delete this driver + diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c new file mode 100644 index 000000000000..269503f9516f --- /dev/null +++ b/drivers/staging/cptm1217/clearpad_tm1217.c @@ -0,0 +1,675 @@ +/* + * clearpad_tm1217.c - Touch Screen driver for Synaptics Clearpad + * TM1217 controller + * + * Copyright (C) 2008 Intel Corp + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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; ifnot, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * Questions/Comments/Bug fixes to Ramesh Agarwal (ramesh.agarwal@intel.com) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cp_tm1217.h" + +#define CPTM1217_DEVICE_NAME "cptm1217" +#define CPTM1217_DRIVER_NAME CPTM1217_DEVICE_NAME + +#define MAX_TOUCH_SUPPORTED 2 +#define TOUCH_SUPPORTED 1 +#define SAMPLING_FREQ 80 /* Frequency in HZ */ +#define DELAY_BTWIN_SAMPLE (1000 / SAMPLING_FREQ) +#define WAIT_FOR_RESPONSE 5 /* 5msec just works */ +#define MAX_RETRIES 5 /* As above */ +#define INCREMENTAL_DELAY 5 /* As above */ + +/* Regster Definitions */ +#define TMA1217_DEV_STATUS 0x13 /* Device Status */ +#define TMA1217_INT_STATUS 0x14 /* Interrupt Status */ + +/* Controller can detect upto 2 possible finger touches. + * Each finger touch provides 12 bit X Y co-ordinates, the values are split + * across 2 registers, and an 8 bit Z value */ +#define TMA1217_FINGER_STATE 0x18 /* Finger State */ +#define TMA1217_FINGER1_X_HIGHER8 0x19 /* Higher 8 bit of X coordinate */ +#define TMA1217_FINGER1_Y_HIGHER8 0x1A /* Higher 8 bit of Y coordinate */ +#define TMA1217_FINGER1_XY_LOWER4 0x1B /* Lower 4 bits of X and Y */ +#define TMA1217_FINGER1_Z_VALUE 0x1D /* 8 bit Z value for finger 1 */ +#define TMA1217_FINGER2_X_HIGHER8 0x1E /* Higher 8 bit of X coordinate */ +#define TMA1217_FINGER2_Y_HIGHER8 0x1F /* Higher 8 bit of Y coordinate */ +#define TMA1217_FINGER2_XY_LOWER4 0x20 /* Lower 4 bits of X and Y */ +#define TMA1217_FINGER2_Z_VALUE 0x22 /* 8 bit Z value for finger 2 */ +#define TMA1217_DEVICE_CTRL 0x23 /* Device Control */ +#define TMA1217_INTERRUPT_ENABLE 0x24 /* Interrupt Enable */ +#define TMA1217_REPORT_MODE 0x2B /* Reporting Mode */ +#define TMA1217_MAX_X_LOWER8 0x31 /* Bit 0-7 for Max X */ +#define TMA1217_MAX_X_HIGHER4 0x32 /* Bit 8-11 for Max X */ +#define TMA1217_MAX_Y_LOWER8 0x33 /* Bit 0-7 for Max Y */ +#define TMA1217_MAX_Y_HIGHER4 0x34 /* Bit 8-11 for Max Y */ +#define TMA1217_DEVICE_CMD_RESET 0x67 /* Device CMD reg for reset */ +#define TMA1217_DEVICE_CMD_REZERO 0x69 /* Device CMD reg for rezero */ + +#define TMA1217_MANUFACTURER_ID 0x73 /* Manufacturer Id */ +#define TMA1217_PRODUCT_FAMILY 0x75 /* Product Family */ +#define TMA1217_FIRMWARE_REVISION 0x76 /* Firmware Revision */ +#define TMA1217_SERIAL_NO_HIGH 0x7C /* Bit 8-15 of device serial no. */ +#define TMA1217_SERIAL_NO_LOW 0x7D /* Bit 0-7 of device serial no. */ +#define TMA1217_PRODUCT_ID_START 0x7E /* Start address for 10 byte ID */ +#define TMA1217_DEVICE_CAPABILITY 0x8B /* Reporting capability */ + + +/* + * The touch position structure. + */ +struct touch_state { + int x; + int y; + bool button; +}; + +/* Device Specific info given by the controller */ +struct cp_dev_info { + u16 maxX; + u16 maxY; +}; + +/* Vendor related info given by the controller */ +struct cp_vendor_info { + u8 vendor_id; + u8 product_family; + u8 firmware_rev; + u16 serial_no; +}; + +/* + * Private structure to store the device details + */ +struct cp_tm1217_device { + struct i2c_client *client; + struct device *dev; + struct cp_vendor_info vinfo; + struct cp_dev_info dinfo; + struct input_dev_info { + char phys[32]; + char name[128]; + struct input_dev *input; + struct touch_state touch; + } cp_input_info[MAX_TOUCH_SUPPORTED]; + + int thread_running; + struct mutex thread_mutex; + + int gpio; +}; + + +/* The following functions are used to read/write registers on the device + * as per the RMI prorocol. Technically, a page select should be written + * before doing read/write but since the register offsets are below 0xFF + * we can use the default value of page which is 0x00 + */ +static int cp_tm1217_read(struct cp_tm1217_device *ts, + u8 *req, int size) +{ + int i, retval; + + /* Send the address */ + retval = i2c_master_send(ts->client, &req[0], 1); + if (retval != 1) { + dev_err(ts->dev, "cp_tm1217: I2C send failed\n"); + return retval; + } + msleep(WAIT_FOR_RESPONSE); + for (i = 0; i < MAX_RETRIES; i++) { + retval = i2c_master_recv(ts->client, &req[1], size); + if (retval == size) { + break; + } else { + msleep(INCREMENTAL_DELAY); + dev_dbg(ts->dev, "cp_tm1217: Retry count is %d\n", i); + } + } + if (retval != size) + dev_err(ts->dev, "cp_tm1217: Read from device failed\n"); + + return retval; +} + +static int cp_tm1217_write(struct cp_tm1217_device *ts, + u8 *req, int size) +{ + int retval; + + /* Send the address and the data to be written */ + retval = i2c_master_send(ts->client, &req[0], size + 1); + if (retval != size + 1) { + dev_err(ts->dev, "cp_tm1217: I2C write failed: %d\n", retval); + return retval; + } + /* Wait for the write to complete. TBD why this is required */ + msleep(WAIT_FOR_RESPONSE); + + return size; +} + +static int cp_tm1217_mask_interrupt(struct cp_tm1217_device *ts) +{ + u8 req[2]; + int retval; + + req[0] = TMA1217_INTERRUPT_ENABLE; + req[1] = 0x0; + retval = cp_tm1217_write(ts, req, 1); + if (retval != 1) + return -EIO; + + return 0; +} + +static int cp_tm1217_unmask_interrupt(struct cp_tm1217_device *ts) +{ + u8 req[2]; + int retval; + + req[0] = TMA1217_INTERRUPT_ENABLE; + req[1] = 0xa; + retval = cp_tm1217_write(ts, req, 1); + if (retval != 1) + return -EIO; + + return 0; +} + +static void process_touch(struct cp_tm1217_device *ts, int index) +{ + int retval; + struct input_dev_info *input_info = + (struct input_dev_info *)&ts->cp_input_info[index]; + u8 xy_data[6]; + + if (index == 0) + xy_data[0] = TMA1217_FINGER1_X_HIGHER8; + else + xy_data[0] = TMA1217_FINGER2_X_HIGHER8; + + retval = cp_tm1217_read(ts, xy_data, 5); + if (retval < 5) { + dev_err(ts->dev, "cp_tm1217: XY read from device failed\n"); + return; + } + + /* Note: Currently not using the Z values but may be requried in + the future. */ + input_info->touch.x = (xy_data[1] << 4) + | (xy_data[3] & 0x0F); + input_info->touch.y = (xy_data[2] << 4) + | ((xy_data[3] & 0xF0) >> 4); + input_report_abs(input_info->input, ABS_X, input_info->touch.x); + input_report_abs(input_info->input, ABS_Y, input_info->touch.y); + input_sync(input_info->input); +} + +static void cp_tm1217_get_data(struct cp_tm1217_device *ts) +{ + u8 req[2]; + int retval, i, finger_touched = 0; + + do { + req[0] = TMA1217_FINGER_STATE; + retval = cp_tm1217_read(ts, req, 1); + if (retval != 1) { + dev_err(ts->dev, + "cp_tm1217: Read from device failed\n"); + continue; + } + finger_touched = 0; + /* Start sampling until the pressure is below + threshold */ + for (i = 0; i < TOUCH_SUPPORTED; i++) { + if (req[1] & 0x3) { + finger_touched++; + if (ts->cp_input_info[i].touch.button == 0) { + /* send the button touch event */ + input_report_key( + ts->cp_input_info[i].input, + BTN_TOUCH, 1); + ts->cp_input_info[i].touch.button = 1; + } + process_touch(ts, i); + } else { + if (ts->cp_input_info[i].touch.button == 1) { + /* send the button release event */ + input_report_key( + ts->cp_input_info[i].input, + BTN_TOUCH, 0); + input_sync(ts->cp_input_info[i].input); + ts->cp_input_info[i].touch.button = 0; + } + } + req[1] = req[1] >> 2; + } + msleep(DELAY_BTWIN_SAMPLE); + } while (finger_touched > 0); +} + +static irqreturn_t cp_tm1217_sample_thread(int irq, void *handle) +{ + struct cp_tm1217_device *ts = (struct cp_tm1217_device *) handle; + u8 req[2]; + int retval; + + /* Chedk if another thread is already running */ + mutex_lock(&ts->thread_mutex); + if (ts->thread_running == 1) { + mutex_unlock(&ts->thread_mutex); + return IRQ_HANDLED; + } else { + ts->thread_running = 1; + mutex_unlock(&ts->thread_mutex); + } + + /* Mask the interrupts */ + retval = cp_tm1217_mask_interrupt(ts); + + /* Read the Interrupt Status register to find the cause of the + Interrupt */ + req[0] = TMA1217_INT_STATUS; + retval = cp_tm1217_read(ts, req, 1); + if (retval != 1) + goto exit_thread; + + if (!(req[1] & 0x8)) + goto exit_thread; + + cp_tm1217_get_data(ts); + +exit_thread: + /* Unmask the interrupts before going to sleep */ + retval = cp_tm1217_unmask_interrupt(ts); + + mutex_lock(&ts->thread_mutex); + ts->thread_running = 0; + mutex_unlock(&ts->thread_mutex); + + return IRQ_HANDLED; +} + +static int cp_tm1217_init_data(struct cp_tm1217_device *ts) +{ + int retval; + u8 req[2]; + + /* Read the vendor id/ fw revision etc. Ignoring return check as this + is non critical info */ + req[0] = TMA1217_MANUFACTURER_ID; + retval = cp_tm1217_read(ts, req, 1); + ts->vinfo.vendor_id = req[1]; + + req[0] = TMA1217_PRODUCT_FAMILY; + retval = cp_tm1217_read(ts, req, 1); + ts->vinfo.product_family = req[1]; + + req[0] = TMA1217_FIRMWARE_REVISION; + retval = cp_tm1217_read(ts, req, 1); + ts->vinfo.firmware_rev = req[1]; + + req[0] = TMA1217_SERIAL_NO_HIGH; + retval = cp_tm1217_read(ts, req, 1); + ts->vinfo.serial_no = (req[1] << 8); + + req[0] = TMA1217_SERIAL_NO_LOW; + retval = cp_tm1217_read(ts, req, 1); + ts->vinfo.serial_no = ts->vinfo.serial_no | req[1]; + + req[0] = TMA1217_MAX_X_HIGHER4; + retval = cp_tm1217_read(ts, req, 1); + ts->dinfo.maxX = (req[1] & 0xF) << 8; + + req[0] = TMA1217_MAX_X_LOWER8; + retval = cp_tm1217_read(ts, req, 1); + ts->dinfo.maxX = ts->dinfo.maxX | req[1]; + + req[0] = TMA1217_MAX_Y_HIGHER4; + retval = cp_tm1217_read(ts, req, 1); + ts->dinfo.maxY = (req[1] & 0xF) << 8; + + req[0] = TMA1217_MAX_Y_LOWER8; + retval = cp_tm1217_read(ts, req, 1); + ts->dinfo.maxY = ts->dinfo.maxY | req[1]; + + return 0; + +} + +/* + * Set up a GPIO for use as the interrupt. We can't simply do this at + * boot time because the GPIO drivers themselves may not be around at + * boot/firmware set up time to do the work. Instead defer it to driver + * detection. + */ + +static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts) +{ + int retval; + + /* Hook up the irq handler */ + retval = gpio_request(ts->gpio, "cp_tm1217_touch"); + if (retval < 0) { + dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n", + retval); + return retval; + } + + retval = gpio_direction_input(ts->gpio); + if (retval < 0) { + dev_err(ts->dev, + "cp_tm1217: GPIO direction configuration failed, error %d\n", + retval); + gpio_free(ts->gpio); + return retval; + } + + retval = gpio_to_irq(ts->gpio); + if (retval < 0) { + dev_err(ts->dev, "cp_tm1217: GPIO to IRQ failedi," + " error %d\n", retval); + gpio_free(ts->gpio); + } + dev_dbg(ts->dev, + "cp_tm1217: Got IRQ number is %d for GPIO %d\n", + retval, ts->gpio); + return retval; +} + +static int cp_tm1217_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cp_tm1217_device *ts; + struct input_dev *input_dev; + struct input_dev_info *input_info; + struct cp_tm1217_platform_data *pdata; + u8 req[2]; + int i, retval; + + /* No pdata is fine - we then use "normal" IRQ mode */ + + pdata = client->dev.platform_data; + + ts = kzalloc(sizeof(struct cp_tm1217_device), GFP_KERNEL); + if (!ts) { + dev_err(&client->dev, + "cp_tm1217: Private Device Struct alloc failed\n"); + return -ENOMEM; + } + + ts->client = client; + ts->dev = &client->dev; + i2c_set_clientdata(client, ts); + + ts->thread_running = 0; + mutex_init(&ts->thread_mutex); + + /* Reset the Controller */ + req[0] = TMA1217_DEVICE_CMD_RESET; + req[1] = 0x1; + retval = cp_tm1217_write(ts, req, 1); + if (retval != 1) { + dev_err(ts->dev, "cp_tm1217: Controller reset failed\n"); + kfree(ts); + return -EIO; + } + + /* Clear up the interrupt status from reset. */ + req[0] = TMA1217_INT_STATUS; + retval = cp_tm1217_read(ts, req, 1); + + /* Mask all the interrupts */ + retval = cp_tm1217_mask_interrupt(ts); + + /* Read the controller information */ + cp_tm1217_init_data(ts); + + /* The following code will register multiple event devices when + multi-pointer is enabled, the code has not been tested + with MPX */ + for (i = 0; i < TOUCH_SUPPORTED; i++) { + input_dev = input_allocate_device(); + if (input_dev == NULL) { + kfree(ts); + dev_err(ts->dev, + "cp_tm1217:Input Device Struct alloc failed\n"); + return -ENOMEM; + } + input_info = &ts->cp_input_info[i]; + snprintf(input_info->name, sizeof(input_info->name), + "cp_tm1217_touchscreen_%d", i); + input_dev->name = input_info->name; + snprintf(input_info->phys, sizeof(input_info->phys), + "%s/input%d", dev_name(&client->dev), i); + + input_dev->phys = input_info->phys; + input_dev->id.bustype = BUS_I2C; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, ts->dinfo.maxX, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, ts->dinfo.maxY, 0, 0); + + retval = input_register_device(input_dev); + if (retval) { + dev_err(ts->dev, + "Input dev registration failed for %s\n", + input_dev->name); + goto fail; + } + input_info->input = input_dev; + } + + /* Setup the reporting mode to send an interrupt only when + finger arrives or departs. */ + req[0] = TMA1217_REPORT_MODE; + req[1] = 0x02; + retval = cp_tm1217_write(ts, req, 1); + + /* Setup the device to no sleep mode for now and make it configured */ + req[0] = TMA1217_DEVICE_CTRL; + req[1] = 0x84; + retval = cp_tm1217_write(ts, req, 1); + + /* Check for the status of the device */ + req[0] = TMA1217_DEV_STATUS; + retval = cp_tm1217_read(ts, req, 1); + if (req[1] != 0) { + dev_err(ts->dev, + "cp_tm1217: Device Status 0x%x != 0: config failed\n", + req[1]); + + retval = -EIO; + goto fail; + } + + if (pdata && pdata->gpio) { + ts->gpio = pdata->gpio; + retval = cp_tm1217_setup_gpio_irq(ts); + } else + retval = client->irq; + + if (retval < 0) { + dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n", + retval); + goto fail; + } + + client->irq = retval; + + + retval = request_threaded_irq(client->irq, + NULL, cp_tm1217_sample_thread, + IRQF_TRIGGER_FALLING, "cp_tm1217_touch", ts); + if (retval < 0) { + dev_err(ts->dev, "cp_tm1217: Request IRQ error %d\n", retval); + goto fail_gpio; + } + + /* Unmask the interrupts */ + retval = cp_tm1217_unmask_interrupt(ts); + if (retval == 0) + return 0; + + free_irq(client->irq, ts); +fail_gpio: + if (ts->gpio) + gpio_free(ts->gpio); +fail: + /* Clean up before returning failure */ + for (i = 0; i < TOUCH_SUPPORTED; i++) { + if (ts->cp_input_info[i].input) { + input_unregister_device(ts->cp_input_info[i].input); + input_free_device(ts->cp_input_info[i].input); + } + } + kfree(ts); + return retval; + +} + +/* + * cp_tm1217 suspend + * + */ +static int cp_tm1217_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct cp_tm1217_device *ts = i2c_get_clientdata(client); + u8 req[2]; + int retval; + + /* Put the controller to sleep */ + req[0] = TMA1217_DEVICE_CTRL; + retval = cp_tm1217_read(ts, req, 1); + req[1] = (req[1] & 0xF8) | 0x1; + retval = cp_tm1217_write(ts, req, 1); + + if (device_may_wakeup(&client->dev)) + enable_irq_wake(client->irq); + + return 0; +} + +/* + * cp_tm1217_resume + * + */ +static int cp_tm1217_resume(struct i2c_client *client) +{ + struct cp_tm1217_device *ts = i2c_get_clientdata(client); + u8 req[2]; + int retval; + + /* Take the controller out of sleep */ + req[0] = TMA1217_DEVICE_CTRL; + retval = cp_tm1217_read(ts, req, 1); + req[1] = (req[1] & 0xF8) | 0x4; + retval = cp_tm1217_write(ts, req, 1); + + /* Restore the register settings sinc the power to the + could have been cut off */ + + /* Setup the reporting mode to send an interrupt only when + finger arrives or departs. */ + req[0] = TMA1217_REPORT_MODE; + req[1] = 0x02; + retval = cp_tm1217_write(ts, req, 1); + + /* Setup the device to no sleep mode for now and make it configured */ + req[0] = TMA1217_DEVICE_CTRL; + req[1] = 0x84; + retval = cp_tm1217_write(ts, req, 1); + + /* Setup the interrupt mask */ + retval = cp_tm1217_unmask_interrupt(ts); + + if (device_may_wakeup(&client->dev)) + disable_irq_wake(client->irq); + + return 0; +} + +/* + * cp_tm1217_remove + * + */ +static int cp_tm1217_remove(struct i2c_client *client) +{ + struct cp_tm1217_device *ts = i2c_get_clientdata(client); + int i; + + free_irq(client->irq, ts); + if (ts->gpio) + gpio_free(ts->gpio); + for (i = 0; i < TOUCH_SUPPORTED; i++) + input_unregister_device(ts->cp_input_info[i].input); + kfree(ts); + return 0; +} + +static struct i2c_device_id cp_tm1217_idtable[] = { + { CPTM1217_DEVICE_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, cp_tm1217_idtable); + +static struct i2c_driver cp_tm1217_driver = { + .driver = { + .owner = THIS_MODULE, + .name = CPTM1217_DRIVER_NAME, + }, + .id_table = cp_tm1217_idtable, + .probe = cp_tm1217_probe, + .remove = cp_tm1217_remove, + .suspend = cp_tm1217_suspend, + .resume = cp_tm1217_resume, +}; + +static int __init clearpad_tm1217_init(void) +{ + return i2c_add_driver(&cp_tm1217_driver); +} + +static void __exit clearpad_tm1217_exit(void) +{ + i2c_del_driver(&cp_tm1217_driver); +} + +module_init(clearpad_tm1217_init); +module_exit(clearpad_tm1217_exit); + +MODULE_AUTHOR("Ramesh Agarwal "); +MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/cptm1217/cp_tm1217.h b/drivers/staging/cptm1217/cp_tm1217.h new file mode 100644 index 000000000000..a0ce31db53f8 --- /dev/null +++ b/drivers/staging/cptm1217/cp_tm1217.h @@ -0,0 +1,9 @@ +#ifndef __LINUX_I2C_CP_TM1217_H +#define __LINUX_I2C_CP_TM1217_H + +struct cp_tm1217_platform_data +{ + int gpio; /* If not set uses the IRQ resource 0 */ +}; + +#endif -- cgit v1.2.3 From eba499d3e376983f4d521bac05bf7e9a634ace2f Mon Sep 17 00:00:00 2001 From: Naveen Kumar Gaddipati Date: Tue, 2 Nov 2010 17:38:45 +0530 Subject: Staging: add Synaptics RMI4 touchpad driver support Added the Synaptics RMI4 touchpad driver support. Acked-by: Linus Walleij Signed-off-by: Naveen Kumar Gaddipati Cc: Dmitry Torokhov Cc: Alan Cox Cc: Christopher Heiny Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/ste_rmi4/Kconfig | 9 + drivers/staging/ste_rmi4/Makefile | 4 + drivers/staging/ste_rmi4/TODO | 7 + drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c | 1179 +++++++++++++++++++++++++ drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h | 50 ++ 7 files changed, 1252 insertions(+) create mode 100644 drivers/staging/ste_rmi4/Kconfig create mode 100644 drivers/staging/ste_rmi4/Makefile create mode 100644 drivers/staging/ste_rmi4/TODO create mode 100644 drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c create mode 100644 drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 2c478c476edd..49aee27b296d 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -177,5 +177,7 @@ source "drivers/staging/speakup/Kconfig" source "drivers/staging/cptm1217/Kconfig" +source "drivers/staging/ste_rmi4/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 74d0b4cc7a0a..20c5641b6cd7 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -69,3 +69,4 @@ obj-$(CONFIG_FT1000) += ft1000/ obj-$(CONFIG_SND_INTEL_SST) += intel_sst/ obj-$(CONFIG_SPEAKUP) += speakup/ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ diff --git a/drivers/staging/ste_rmi4/Kconfig b/drivers/staging/ste_rmi4/Kconfig new file mode 100644 index 000000000000..95fd5a915f0a --- /dev/null +++ b/drivers/staging/ste_rmi4/Kconfig @@ -0,0 +1,9 @@ +config TOUCHSCREEN_SYNAPTICS_I2C_RMI4 + tristate "Synaptics i2c rmi4 touchscreen" + depends on I2C + help + Say Y here if you have a Synaptics RMI4 and + want to enable support for the built-in touchscreen. + + To compile this driver as a module, choose M here: the + module will be called synaptics_rmi4_ts. diff --git a/drivers/staging/ste_rmi4/Makefile b/drivers/staging/ste_rmi4/Makefile new file mode 100644 index 000000000000..6cce2ed187ef --- /dev/null +++ b/drivers/staging/ste_rmi4/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the RMI4 touchscreen driver. +# +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o diff --git a/drivers/staging/ste_rmi4/TODO b/drivers/staging/ste_rmi4/TODO new file mode 100644 index 000000000000..9be2437da85f --- /dev/null +++ b/drivers/staging/ste_rmi4/TODO @@ -0,0 +1,7 @@ +TODO +---- + +Wait for the official upstream synaptics rmi4 clearpad drivers as promised over the past few months +Merge any device support needed from this driver into it +Delete this driver + diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c new file mode 100644 index 000000000000..e8f047e86a32 --- /dev/null +++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c @@ -0,0 +1,1179 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver. + * Copyright (c) 2007-2010, Synaptics Incorporated + * + * Author: Js HA for ST-Ericsson + * Author: Naveen Kumar G for ST-Ericsson + * Copyright 2010 (c) ST-Ericsson AB + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * 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. + * + * 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 "synaptics_i2c_rmi4.h" + +/* TODO: for multiple device support will need a per-device mutex */ +#define DRIVER_NAME "synaptics_rmi4_i2c" + +#define MAX_ERROR_REPORT 6 +#define MAX_TOUCH_MAJOR 15 +#define MAX_RETRY_COUNT 5 +#define STD_QUERY_LEN 21 +#define PAGE_LEN 2 +#define DATA_BUF_LEN 32 +#define BUF_LEN 37 +#define QUERY_LEN 9 +#define DATA_LEN 12 +#define HAS_TAP 0x01 +#define HAS_PALMDETECT 0x01 +#define HAS_ROTATE 0x02 +#define HAS_TAPANDHOLD 0x02 +#define HAS_DOUBLETAP 0x04 +#define HAS_EARLYTAP 0x08 +#define HAS_RELEASE 0x08 +#define HAS_FLICK 0x10 +#define HAS_PRESS 0x20 +#define HAS_PINCH 0x40 + +#define MASK_16BIT 0xFFFF +#define MASK_8BIT 0xFF +#define MASK_7BIT 0x7F +#define MASK_5BIT 0x1F +#define MASK_4BIT 0x0F +#define MASK_3BIT 0x07 +#define MASK_2BIT 0x03 +#define TOUCHPAD_CTRL_INTR 0x8 +#define PDT_START_SCAN_LOCATION (0x00E9) +#define PDT_END_SCAN_LOCATION (0x000A) +#define PDT_ENTRY_SIZE (0x0006) +#define RMI4_NUMBER_OF_MAX_FINGERS (8) +#define SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM (0x11) +#define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01) + +/** + * struct synaptics_rmi4_fn_desc - contains the funtion descriptor information + * @query_base_addr: base address for query + * @cmd_base_addr: base address for command + * @ctrl_base_addr: base address for control + * @data_base_addr: base address for data + * @intr_src_count: count for the interrupt source + * @fn_number: function number + * + * This structure is used to gives the function descriptor information + * of the particular functionality. + */ +struct synaptics_rmi4_fn_desc { + unsigned char query_base_addr; + unsigned char cmd_base_addr; + unsigned char ctrl_base_addr; + unsigned char data_base_addr; + unsigned char intr_src_count; + unsigned char fn_number; +}; + +/** + * struct synaptics_rmi4_fn - contains the funtion information + * @fn_number: function number + * @num_of_data_sources: number of data sources + * @num_of_data_points: number of fingers touched + * @size_of_data_register_block: data register block size + * @index_to_intr_reg: index for interrupt register + * @intr_mask: interrupt mask value + * @fn_desc: variable for function descriptor structure + * @link: linked list for function descriptors + * + * This structure gives information about the number of data sources and + * the number of data registers associated with the function. + */ +struct synaptics_rmi4_fn { + unsigned char fn_number; + unsigned char num_of_data_sources; + unsigned char num_of_data_points; + unsigned char size_of_data_register_block; + unsigned char index_to_intr_reg; + unsigned char intr_mask; + struct synaptics_rmi4_fn_desc fn_desc; + struct list_head link; +}; + +/** + * struct synaptics_rmi4_device_info - contains the rmi4 device information + * @version_major: protocol major version number + * @version_minor: protocol minor version number + * @manufacturer_id: manufacturer identification byte + * @product_props: product properties information + * @product_info: product info array + * @date_code: device manufacture date + * @tester_id: tester id array + * @serial_number: serial number for that device + * @product_id_string: product id for the device + * @support_fn_list: linked list for device information + * + * This structure gives information about the number of data sources and + * the number of data registers associated with the function. + */ +struct synaptics_rmi4_device_info { + unsigned int version_major; + unsigned int version_minor; + unsigned char manufacturer_id; + unsigned char product_props; + unsigned char product_info[2]; + unsigned char date_code[3]; + unsigned short tester_id; + unsigned short serial_number; + unsigned char product_id_string[11]; + struct list_head support_fn_list; +}; + +/** + * struct synaptics_rmi4_data - contains the rmi4 device data + * @rmi4_mod_info: structure variable for rmi4 device info + * @input_dev: pointer for input device + * @i2c_client: pointer for i2c client + * @board: constant pointer for touch platform data + * @fn_list_mutex: mutex for funtion list + * @rmi4_page_mutex: mutex for rmi4 page + * @current_page: variable for integer + * @number_of_interrupt_register: interrupt registers count + * @fn01_ctrl_base_addr: control base address for fn01 + * @fn01_query_base_addr: query base address for fn01 + * @fn01_data_base_addr: data base address for fn01 + * @sensor_max_x: sensor maximum x value + * @sensor_max_y: sensor maximum y value + * @regulator: pointer to the regulator structure + * @wait: wait queue structure variable + * @touch_stopped: flag to stop the thread function + * + * This structure gives the device data information. + */ +struct synaptics_rmi4_data { + struct synaptics_rmi4_device_info rmi4_mod_info; + struct input_dev *input_dev; + struct i2c_client *i2c_client; + const struct synaptics_rmi4_platform_data *board; + struct mutex fn_list_mutex; + struct mutex rmi4_page_mutex; + int current_page; + unsigned int number_of_interrupt_register; + unsigned short fn01_ctrl_base_addr; + unsigned short fn01_query_base_addr; + unsigned short fn01_data_base_addr; + int sensor_max_x; + int sensor_max_y; + struct regulator *regulator; + wait_queue_head_t wait; + bool touch_stopped; +}; + +/** + * synaptics_rmi4_set_page() - sets the page + * @pdata: pointer to synaptics_rmi4_data structure + * @address: set the address of the page + * + * This function is used to set the page and returns integer. + */ +static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *pdata, + unsigned int address) +{ + unsigned char txbuf[PAGE_LEN]; + int retval; + unsigned int page; + struct i2c_client *i2c = pdata->i2c_client; + + page = ((address >> 8) & MASK_8BIT); + if (page != pdata->current_page) { + txbuf[0] = MASK_8BIT; + txbuf[1] = page; + retval = i2c_master_send(i2c, txbuf, PAGE_LEN); + if (retval != PAGE_LEN) + dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval); + else + pdata->current_page = page; + } else + retval = PAGE_LEN; + return retval; +} +/** + * synaptics_rmi4_i2c_block_read() - read the block of data + * @pdata: pointer to synaptics_rmi4_data structure + * @address: read the block of data from this offset + * @valp: pointer to a buffer containing the data to be read + * @size: number of bytes to read + * + * This function is to read the block of data and returns integer. + */ +static int synaptics_rmi4_i2c_block_read(struct synaptics_rmi4_data *pdata, + unsigned short address, + unsigned char *valp, int size) +{ + int retval = 0; + int retry_count = 0; + int index; + struct i2c_client *i2c = pdata->i2c_client; + + mutex_lock(&(pdata->rmi4_page_mutex)); + retval = synaptics_rmi4_set_page(pdata, address); + if (retval != PAGE_LEN) + goto exit; + index = address & MASK_8BIT; +retry: + retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp); + if (retval != size) { + if (++retry_count == MAX_RETRY_COUNT) + dev_err(&i2c->dev, + "%s:address 0x%04x size %d failed:%d\n", + __func__, address, size, retval); + else { + synaptics_rmi4_set_page(pdata, address); + goto retry; + } + } +exit: + mutex_unlock(&(pdata->rmi4_page_mutex)); + return retval; +} + +/** + * synaptics_rmi4_i2c_byte_write() - write the single byte data + * @pdata: pointer to synaptics_rmi4_data structure + * @address: write the block of data from this offset + * @data: data to be write + * + * This function is to write the single byte data and returns integer. + */ +static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata, + unsigned short address, + unsigned char data) +{ + unsigned char txbuf[2]; + int retval = 0; + struct i2c_client *i2c = pdata->i2c_client; + + /* Can't have anyone else changing the page behind our backs */ + mutex_lock(&(pdata->rmi4_page_mutex)); + + retval = synaptics_rmi4_set_page(pdata, address); + if (retval != PAGE_LEN) + goto exit; + txbuf[0] = address & MASK_8BIT; + txbuf[1] = data; + retval = i2c_master_send(pdata->i2c_client, txbuf, 2); + /* Add in retry on writes only in certian error return values */ + if (retval != 2) { + dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval); + retval = -EIO; + } else + retval = 1; +exit: + mutex_unlock(&(pdata->rmi4_page_mutex)); + return retval; +} + +/** + * synpatics_rmi4_touchpad_report() - reports for the rmi4 touchpad device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn structure + * + * This function calls to reports for the rmi4 touchpad device + */ +static int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi) +{ + /* number of touch points - fingers down in this case */ + int touch_count = 0; + int finger; + int fingers_supported; + int finger_registers; + int reg; + int finger_shift; + int finger_status; + int retval; + unsigned short data_base_addr; + unsigned short data_offset; + unsigned char data_reg_blk_size; + unsigned char values[2]; + unsigned char data[DATA_LEN]; + int x[RMI4_NUMBER_OF_MAX_FINGERS]; + int y[RMI4_NUMBER_OF_MAX_FINGERS]; + int wx[RMI4_NUMBER_OF_MAX_FINGERS]; + int wy[RMI4_NUMBER_OF_MAX_FINGERS]; + struct i2c_client *client = pdata->i2c_client; + + /* get 2D sensor finger data */ + /* + * First get the finger status field - the size of the finger status + * field is determined by the number of finger supporte - 2 bits per + * finger, so the number of registers to read is: + * registerCount = ceil(numberOfFingers/4). + * Read the required number of registers and check each 2 bit field to + * determine if a finger is down: + * 00 = finger not present, + * 01 = finger present and data accurate, + * 10 = finger present but data may not be accurate, + * 11 = reserved for product use. + */ + fingers_supported = rfi->num_of_data_points; + finger_registers = (fingers_supported + 3)/4; + data_base_addr = rfi->fn_desc.data_base_addr; + retval = synaptics_rmi4_i2c_block_read(pdata, data_base_addr, values, + finger_registers); + if (retval != finger_registers) { + dev_err(&client->dev, "%s:read status registers failed\n", + __func__); + return 0; + } + /* + * For each finger present, read the proper number of registers + * to get absolute data. + */ + data_reg_blk_size = rfi->size_of_data_register_block; + for (finger = 0; finger < fingers_supported; finger++) { + /* determine which data byte the finger status is in */ + reg = finger/4; + /* bit shift to get finger's status */ + finger_shift = (finger % 4) * 2; + finger_status = (values[reg] >> finger_shift) & 3; + /* + * if finger status indicates a finger is present then + * read the finger data and report it + */ + if (finger_status == 1 || finger_status == 2) { + /* Read the finger data */ + data_offset = data_base_addr + + ((finger * data_reg_blk_size) + + finger_registers); + retval = synaptics_rmi4_i2c_block_read(pdata, + data_offset, data, + data_reg_blk_size); + if (retval != data_reg_blk_size) { + printk(KERN_ERR "%s:read data failed\n", + __func__); + return 0; + } else { + x[touch_count] = + (data[0] << 4) | (data[2] & MASK_4BIT); + y[touch_count] = + (data[1] << 4) | + ((data[2] >> 4) & MASK_4BIT); + wy[touch_count] = + (data[3] >> 4) & MASK_4BIT; + wx[touch_count] = + (data[3] & MASK_4BIT); + + if (pdata->board->x_flip) + x[touch_count] = + pdata->sensor_max_x - + x[touch_count]; + if (pdata->board->y_flip) + y[touch_count] = + pdata->sensor_max_y - + y[touch_count]; + } + /* number of active touch points */ + touch_count++; + } + } + + /* report to input subsystem */ + if (touch_count) { + for (finger = 0; finger < touch_count; finger++) { + input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, + max(wx[finger] , wy[finger])); + input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, + x[finger]); + input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, + y[finger]); + input_mt_sync(pdata->input_dev); + } + } else + input_mt_sync(pdata->input_dev); + + /* sync after groups of events */ + input_sync(pdata->input_dev); + /* return the number of touch points */ + return touch_count; +} + +/** + * synaptics_rmi4_report_device() - reports the rmi4 device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn + * + * This function is used to call the report function of the rmi4 device. + */ +static int synaptics_rmi4_report_device(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi) +{ + int touch = 0; + struct i2c_client *client = pdata->i2c_client; + static int num_error_reports; + if (rfi->fn_number != SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) { + num_error_reports++; + if (num_error_reports < MAX_ERROR_REPORT) + dev_err(&client->dev, "%s:report not supported\n", + __func__); + } else + touch = synpatics_rmi4_touchpad_report(pdata, rfi); + return touch; +} +/** + * synaptics_rmi4_sensor_report() - reports to input subsystem + * @pdata: pointer to synaptics_rmi4_data structure + * + * This function is used to reads in all data sources and reports + * them to the input subsystem. + */ +static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *pdata) +{ + unsigned char intr_status[4]; + /* number of touch points - fingers or buttons */ + int touch = 0; + unsigned int retval; + struct synaptics_rmi4_fn *rfi; + struct synaptics_rmi4_device_info *rmi; + struct i2c_client *client = pdata->i2c_client; + + /* + * Get the interrupt status from the function $01 + * control register+1 to find which source(s) were interrupting + * so we can read the data from the source(s) (2D sensor, buttons..) + */ + retval = synaptics_rmi4_i2c_block_read(pdata, + pdata->fn01_data_base_addr + 1, + intr_status, + pdata->number_of_interrupt_register); + if (retval != pdata->number_of_interrupt_register) { + dev_err(&client->dev, + "could not read interrupt status registers\n"); + return 0; + } + /* + * check each function that has data sources and if the interrupt for + * that triggered then call that RMI4 functions report() function to + * gather data and report it to the input subsystem + */ + rmi = &(pdata->rmi4_mod_info); + list_for_each_entry(rfi, &rmi->support_fn_list, link) { + if (rfi->num_of_data_sources) { + if (intr_status[rfi->index_to_intr_reg] & + rfi->intr_mask) + touch = synaptics_rmi4_report_device(pdata, + rfi); + } + } + /* return the number of touch points */ + return touch; +} + +/** + * synaptics_rmi4_irq() - thread function for rmi4 attention line + * @irq: irq value + * @data: void pointer + * + * This function is interrupt thread function. It just notifies the + * application layer that attention is required. + */ +static irqreturn_t synaptics_rmi4_irq(int irq, void *data) +{ + struct synaptics_rmi4_data *pdata = data; + int touch_count; + do { + touch_count = synaptics_rmi4_sensor_report(pdata); + if (touch_count) + wait_event_timeout(pdata->wait, pdata->touch_stopped, + msecs_to_jiffies(1)); + else + break; + } while (!pdata->touch_stopped); + return IRQ_HANDLED; +} + +/** + * synpatics_rmi4_touchpad_detect() - detects the rmi4 touchpad device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn structure + * @fd: pointer to synaptics_rmi4_fn_desc structure + * @interruptcount: count the number of interrupts + * + * This function calls to detects the rmi4 touchpad device + */ +static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi, + struct synaptics_rmi4_fn_desc *fd, + unsigned int interruptcount) +{ + unsigned char queries[QUERY_LEN]; + unsigned short intr_offset; + unsigned char abs_data_size; + unsigned char abs_data_blk_size; + unsigned char egr_0, egr_1; + unsigned int all_data_blk_size; + int has_pinch, has_flick, has_tap; + int has_tapandhold, has_doubletap; + int has_earlytap, has_press; + int has_palmdetect, has_rotate; + int has_rel; + int i; + int retval; + struct i2c_client *client = pdata->i2c_client; + + rfi->fn_desc.query_base_addr = fd->query_base_addr; + rfi->fn_desc.data_base_addr = fd->data_base_addr; + rfi->fn_desc.intr_src_count = fd->intr_src_count; + rfi->fn_desc.fn_number = fd->fn_number; + rfi->fn_number = fd->fn_number; + rfi->num_of_data_sources = fd->intr_src_count; + rfi->fn_desc.ctrl_base_addr = fd->ctrl_base_addr; + rfi->fn_desc.cmd_base_addr = fd->cmd_base_addr; + + /* + * need to get number of fingers supported, data size, etc. + * to be used when getting data since the number of registers to + * read depends on the number of fingers supported and data size. + */ + retval = synaptics_rmi4_i2c_block_read(pdata, fd->query_base_addr, + queries, + sizeof(queries)); + if (retval != sizeof(queries)) { + dev_err(&client->dev, "%s:read function query registers\n", + __func__); + return retval; + } + /* + * 2D data sources have only 3 bits for the number of fingers + * supported - so the encoding is a bit wierd. + */ + if ((queries[1] & MASK_3BIT) <= 4) + /* add 1 since zero based */ + rfi->num_of_data_points = (queries[1] & MASK_3BIT) + 1; + else { + /* + * a value of 5 is up to 10 fingers - 6 and 7 are reserved + * (shouldn't get these i int retval;n a normal 2D source). + */ + if ((queries[1] & MASK_3BIT) == 5) + rfi->num_of_data_points = 10; + } + /* Need to get interrupt info for handling interrupts */ + rfi->index_to_intr_reg = (interruptcount + 7)/8; + if (rfi->index_to_intr_reg != 0) + rfi->index_to_intr_reg -= 1; + /* + * loop through interrupts for each source in fn $11 + * and or in a bit to the interrupt mask for each. + */ + intr_offset = interruptcount % 8; + rfi->intr_mask = 0; + for (i = intr_offset; + i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++) + rfi->intr_mask |= 1 << i; + + /* Size of just the absolute data for one finger */ + abs_data_size = queries[5] & MASK_2BIT; + /* One each for X and Y, one for LSB for X & Y, one for W, one for Z */ + abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0)); + rfi->size_of_data_register_block = abs_data_blk_size; + + /* + * need to determine the size of data to read - this depends on + * conditions such as whether Relative data is reported and if Gesture + * data is reported. + */ + egr_0 = queries[7]; + egr_1 = queries[8]; + + /* + * Get info about what EGR data is supported, whether it has + * Relative data supported, etc. + */ + has_pinch = egr_0 & HAS_PINCH; + has_flick = egr_0 & HAS_FLICK; + has_tap = egr_0 & HAS_TAP; + has_earlytap = egr_0 & HAS_EARLYTAP; + has_press = egr_0 & HAS_PRESS; + has_rotate = egr_1 & HAS_ROTATE; + has_rel = queries[1] & HAS_RELEASE; + has_tapandhold = egr_0 & HAS_TAPANDHOLD; + has_doubletap = egr_0 & HAS_DOUBLETAP; + has_palmdetect = egr_1 & HAS_PALMDETECT; + + /* + * Size of all data including finger status, absolute data for each + * finger, relative data and EGR data + */ + all_data_blk_size = + /* finger status, four fingers per register */ + ((rfi->num_of_data_points + 3) / 4) + + /* absolute data, per finger times number of fingers */ + (abs_data_blk_size * rfi->num_of_data_points) + + /* + * two relative registers (if relative is being reported) + */ + 2 * has_rel + + /* + * F11_2D_data8 is only present if the egr_0 + * register is non-zero. + */ + !!(egr_0) + + /* + * F11_2D_data9 is only present if either egr_0 or + * egr_1 registers are non-zero. + */ + (egr_0 || egr_1) + + /* + * F11_2D_data10 is only present if EGR_PINCH or EGR_FLICK of + * egr_0 reports as 1. + */ + !!(has_pinch | has_flick) + + /* + * F11_2D_data11 and F11_2D_data12 are only present if + * EGR_FLICK of egr_0 reports as 1. + */ + 2 * !!(has_flick); + return retval; +} + +/** + * synpatics_rmi4_touchpad_config() - confiures the rmi4 touchpad device + * @pdata: pointer to synaptics_rmi4_data structure + * @rfi: pointer to synaptics_rmi4_fn structure + * + * This function calls to confiures the rmi4 touchpad device + */ +int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata, + struct synaptics_rmi4_fn *rfi) +{ + /* + * For the data source - print info and do any + * source specific configuration. + */ + unsigned char data[BUF_LEN]; + int retval = 0; + struct i2c_client *client = pdata->i2c_client; + + /* Get and print some info about the data source... */ + /* To Query 2D devices we need to read from the address obtained + * from the function descriptor stored in the RMI function info. + */ + retval = synaptics_rmi4_i2c_block_read(pdata, + rfi->fn_desc.query_base_addr, + data, QUERY_LEN); + if (retval != QUERY_LEN) + dev_err(&client->dev, "%s:read query registers failed\n", + __func__); + else { + retval = synaptics_rmi4_i2c_block_read(pdata, + rfi->fn_desc.ctrl_base_addr, + data, DATA_BUF_LEN); + if (retval != DATA_BUF_LEN) { + dev_err(&client->dev, + "%s:read control registers failed\n", + __func__); + return retval; + } + /* Store these for use later*/ + pdata->sensor_max_x = ((data[6] & MASK_8BIT) << 0) | + ((data[7] & MASK_4BIT) << 8); + pdata->sensor_max_y = ((data[8] & MASK_5BIT) << 0) | + ((data[9] & MASK_4BIT) << 8); + } + return retval; +} + +/** + * synaptics_rmi4_i2c_query_device() - query the rmi4 device + * @pdata: pointer to synaptics_rmi4_data structure + * + * This function is used to query the rmi4 device. + */ +static int synaptics_rmi4_i2c_query_device(struct synaptics_rmi4_data *pdata) +{ + int i; + int retval; + unsigned char std_queries[STD_QUERY_LEN]; + unsigned char intr_count = 0; + int data_sources = 0; + unsigned int ctrl_offset; + struct synaptics_rmi4_fn *rfi; + struct synaptics_rmi4_fn_desc rmi_fd; + struct synaptics_rmi4_device_info *rmi; + struct i2c_client *client = pdata->i2c_client; + + /* + * init the physical drivers RMI module + * info list of functions + */ + INIT_LIST_HEAD(&pdata->rmi4_mod_info.support_fn_list); + + /* + * Read the Page Descriptor Table to determine what functions + * are present + */ + for (i = PDT_START_SCAN_LOCATION; i > PDT_END_SCAN_LOCATION; + i -= PDT_ENTRY_SIZE) { + retval = synaptics_rmi4_i2c_block_read(pdata, i, + (unsigned char *)&rmi_fd, + sizeof(rmi_fd)); + if (retval != sizeof(rmi_fd)) { + /* failed to read next PDT entry */ + dev_err(&client->dev, "%s: read error\n", __func__); + return -EIO; + } + rfi = NULL; + if (rmi_fd.fn_number) { + switch (rmi_fd.fn_number & MASK_8BIT) { + case SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM: + pdata->fn01_query_base_addr = + rmi_fd.query_base_addr; + pdata->fn01_ctrl_base_addr = + rmi_fd.ctrl_base_addr; + pdata->fn01_data_base_addr = + rmi_fd.data_base_addr; + break; + case SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM: + if (rmi_fd.intr_src_count) { + rfi = kmalloc(sizeof(*rfi), + GFP_KERNEL); + if (!rfi) { + dev_err(&client->dev, + "%s:kmalloc failed\n", + __func__); + return -ENOMEM; + } + retval = synpatics_rmi4_touchpad_detect + (pdata, rfi, + &rmi_fd, + intr_count); + if (retval < 0) + return retval; + } + break; + } + /* interrupt count for next iteration */ + intr_count += (rmi_fd.intr_src_count & MASK_3BIT); + /* + * We only want to add functions to the list + * that have data associated with them. + */ + if (rfi && rmi_fd.intr_src_count) { + /* link this function info to the RMI module */ + mutex_lock(&(pdata->fn_list_mutex)); + list_add_tail(&rfi->link, + &pdata->rmi4_mod_info.support_fn_list); + mutex_unlock(&(pdata->fn_list_mutex)); + } + } else { + /* + * A zero in the function number + * signals the end of the PDT + */ + dev_dbg(&client->dev, + "%s:end of PDT\n", __func__); + break; + } + } + /* + * calculate the interrupt register count - used in the + * ISR to read the correct number of interrupt registers + */ + pdata->number_of_interrupt_register = (intr_count + 7) / 8; + /* + * Function $01 will be used to query the product properties, + * and product ID so we had to read the PDT above first to get + * the Fn $01 query address and prior to filling in the product + * info. NOTE: Even an unflashed device will still have FN $01. + */ + + /* Load up the standard queries and get the RMI4 module info */ + retval = synaptics_rmi4_i2c_block_read(pdata, + pdata->fn01_query_base_addr, + std_queries, + sizeof(std_queries)); + if (retval != sizeof(std_queries)) { + dev_err(&client->dev, "%s:Failed reading queries\n", + __func__); + return -EIO; + } + + /* Currently supported RMI version is 4.0 */ + pdata->rmi4_mod_info.version_major = 4; + pdata->rmi4_mod_info.version_minor = 0; + /* + * get manufacturer id, product_props, product info, + * date code, tester id, serial num and product id (name) + */ + pdata->rmi4_mod_info.manufacturer_id = std_queries[0]; + pdata->rmi4_mod_info.product_props = std_queries[1]; + pdata->rmi4_mod_info.product_info[0] = std_queries[2]; + pdata->rmi4_mod_info.product_info[1] = std_queries[3]; + /* year - 2001-2032 */ + pdata->rmi4_mod_info.date_code[0] = std_queries[4] & MASK_5BIT; + /* month - 1-12 */ + pdata->rmi4_mod_info.date_code[1] = std_queries[5] & MASK_4BIT; + /* day - 1-31 */ + pdata->rmi4_mod_info.date_code[2] = std_queries[6] & MASK_5BIT; + pdata->rmi4_mod_info.tester_id = ((std_queries[7] & MASK_7BIT) << 8) | + (std_queries[8] & MASK_7BIT); + pdata->rmi4_mod_info.serial_number = + ((std_queries[9] & MASK_7BIT) << 8) | + (std_queries[10] & MASK_7BIT); + memcpy(pdata->rmi4_mod_info.product_id_string, &std_queries[11], 10); + + /* Check if this is a Synaptics device - report if not. */ + if (pdata->rmi4_mod_info.manufacturer_id != 1) + dev_err(&client->dev, "%s: non-Synaptics mfg id:%d\n", + __func__, pdata->rmi4_mod_info.manufacturer_id); + + list_for_each_entry(rfi, &pdata->rmi4_mod_info.support_fn_list, link) + data_sources += rfi->num_of_data_sources; + if (data_sources) { + rmi = &(pdata->rmi4_mod_info); + list_for_each_entry(rfi, &rmi->support_fn_list, link) { + if (rfi->num_of_data_sources) { + if (rfi->fn_number == + SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) { + retval = synpatics_rmi4_touchpad_config + (pdata, rfi); + if (retval < 0) + return retval; + } else + dev_err(&client->dev, + "%s:fn_number not supported\n", + __func__); + /* + * Turn on interrupts for this + * function's data sources. + */ + ctrl_offset = pdata->fn01_ctrl_base_addr + 1 + + rfi->index_to_intr_reg; + retval = synaptics_rmi4_i2c_byte_write(pdata, + ctrl_offset, + rfi->intr_mask); + if (retval < 0) + return retval; + } + } + } + return 0; +} + +/** + * synaptics_rmi4_probe() - Initialze the i2c-client touchscreen driver + * @i2c: i2c client structure pointer + * @id:i2c device id pointer + * + * This function will allocate and initialize the instance + * data and request the irq and set the instance data as the clients + * platform data then register the physical driver which will do a scan of + * the rmi4 Physical Device Table and enumerate any rmi4 functions that + * have data sources associated with them. + */ +static int __devinit synaptics_rmi4_probe + (struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + int retval; + unsigned char intr_status[4]; + struct synaptics_rmi4_data *rmi4_data; + const struct synaptics_rmi4_platform_data *platformdata = + client->dev.platform_data; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "i2c smbus byte data not supported\n"); + return -EIO; + } + + if (!platformdata) { + dev_err(&client->dev, "%s: no platform data\n", __func__); + return -EINVAL; + } + + /* Allocate and initialize the instance data for this client */ + rmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data) * 2, + GFP_KERNEL); + if (!rmi4_data) { + dev_err(&client->dev, "%s: no memory allocated\n", __func__); + return -ENOMEM; + } + + rmi4_data->input_dev = input_allocate_device(); + if (rmi4_data->input_dev == NULL) { + dev_err(&client->dev, "%s:input device alloc failed\n", + __func__); + retval = -ENOMEM; + goto err_input; + } + + dev_set_name(&client->dev, platformdata->name); + + if (platformdata->regulator_en) { + rmi4_data->regulator = regulator_get(&client->dev, "v-touch"); + if (IS_ERR(rmi4_data->regulator)) { + dev_err(&client->dev, "%s:get regulator failed\n", + __func__); + retval = PTR_ERR(rmi4_data->regulator); + goto err_regulator; + } + regulator_enable(rmi4_data->regulator); + } + + init_waitqueue_head(&rmi4_data->wait); + /* + * Copy i2c_client pointer into RTID's i2c_client pointer for + * later use in rmi4_read, rmi4_write, etc. + */ + rmi4_data->i2c_client = client; + /* So we set the page correctly the first time */ + rmi4_data->current_page = MASK_16BIT; + rmi4_data->board = platformdata; + rmi4_data->touch_stopped = false; + + /* init the mutexes for maintain the lists */ + mutex_init(&(rmi4_data->fn_list_mutex)); + mutex_init(&(rmi4_data->rmi4_page_mutex)); + + /* + * Register physical driver - this will call the detect function that + * will then scan the device and determine the supported + * rmi4 functions. + */ + retval = synaptics_rmi4_i2c_query_device(rmi4_data); + if (retval) { + dev_err(&client->dev, "%s: rmi4 query device failed\n", + __func__); + goto err_query_dev; + } + + /* Store the instance data in the i2c_client */ + i2c_set_clientdata(client, rmi4_data); + + /*initialize the input device parameters */ + rmi4_data->input_dev->name = DRIVER_NAME; + rmi4_data->input_dev->phys = "Synaptics_Clearpad"; + rmi4_data->input_dev->id.bustype = BUS_I2C; + rmi4_data->input_dev->dev.parent = &client->dev; + input_set_drvdata(rmi4_data->input_dev, rmi4_data); + + /* Initialize the function handlers for rmi4 */ + set_bit(EV_SYN, rmi4_data->input_dev->evbit); + set_bit(EV_KEY, rmi4_data->input_dev->evbit); + set_bit(EV_ABS, rmi4_data->input_dev->evbit); + + input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_X, 0, + rmi4_data->sensor_max_x, 0, 0); + input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_Y, 0, + rmi4_data->sensor_max_y, 0, 0); + input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0, + MAX_TOUCH_MAJOR, 0, 0); + + retval = input_register_device(rmi4_data->input_dev); + if (retval) { + dev_err(&client->dev, "%s:input register failed\n", __func__); + goto err_input_register; + } + + /* Clear interrupts */ + synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, intr_status, + rmi4_data->number_of_interrupt_register); + retval = request_threaded_irq(platformdata->irq_number, NULL, + synaptics_rmi4_irq, + platformdata->irq_type, + platformdata->name, rmi4_data); + if (retval) { + dev_err(&client->dev, "%s:Unable to get attn irq %d\n", + __func__, platformdata->irq_number); + goto err_request_irq; + } + + return retval; + +err_request_irq: + free_irq(platformdata->irq_number, rmi4_data); + input_unregister_device(rmi4_data->input_dev); +err_input_register: + i2c_set_clientdata(client, NULL); +err_query_dev: + if (platformdata->regulator_en) { + regulator_disable(rmi4_data->regulator); + regulator_put(rmi4_data->regulator); + } +err_regulator: + input_free_device(rmi4_data->input_dev); + rmi4_data->input_dev = NULL; +err_input: + kfree(rmi4_data); + + return retval; +} +/** + * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver + * @client: i2c client structure pointer + * + * This funtion uses to remove the i2c-client + * touchscreen driver and returns integer. + */ +static int __devexit synaptics_rmi4_remove(struct i2c_client *client) +{ + struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + rmi4_data->touch_stopped = true; + wake_up(&rmi4_data->wait); + free_irq(pdata->irq_number, rmi4_data); + input_unregister_device(rmi4_data->input_dev); + if (pdata->regulator_en) { + regulator_disable(rmi4_data->regulator); + regulator_put(rmi4_data->regulator); + } + kfree(rmi4_data); + + return 0; +} + +#ifdef CONFIG_PM +/** + * synaptics_rmi4_suspend() - suspend the touch screen controller + * @dev: pointer to device structure + * + * This funtion is used to suspend the + * touch panel controller and returns integer + */ +static int synaptics_rmi4_suspend(struct device *dev) +{ + /* Touch sleep mode */ + int retval; + unsigned char intr_status; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + rmi4_data->touch_stopped = true; + disable_irq(pdata->irq_number); + + retval = synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, + &intr_status, + rmi4_data->number_of_interrupt_register); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_byte_write(rmi4_data, + rmi4_data->fn01_ctrl_base_addr + 1, + (intr_status & ~TOUCHPAD_CTRL_INTR)); + if (retval < 0) + return retval; + + if (pdata->regulator_en) + regulator_disable(rmi4_data->regulator); + + return 0; +} +/** + * synaptics_rmi4_resume() - resume the touch screen controller + * @dev: pointer to device structure + * + * This funtion is used to resume the touch panel + * controller and returns integer. + */ +static int synaptics_rmi4_resume(struct device *dev) +{ + int retval; + unsigned char intr_status; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + if (pdata->regulator_en) + regulator_enable(rmi4_data->regulator); + + enable_irq(pdata->irq_number); + rmi4_data->touch_stopped = false; + + retval = synaptics_rmi4_i2c_block_read(rmi4_data, + rmi4_data->fn01_data_base_addr + 1, + &intr_status, + rmi4_data->number_of_interrupt_register); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_byte_write(rmi4_data, + rmi4_data->fn01_ctrl_base_addr + 1, + (intr_status | TOUCHPAD_CTRL_INTR)); + if (retval < 0) + return retval; + + return 0; +} + +static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = { + .suspend = synaptics_rmi4_suspend, + .resume = synaptics_rmi4_resume, +}; +#endif + +static const struct i2c_device_id synaptics_rmi4_id_table[] = { + { DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); + +static struct i2c_driver synaptics_rmi4_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &synaptics_rmi4_dev_pm_ops, +#endif + }, + .probe = synaptics_rmi4_probe, + .remove = __devexit_p(synaptics_rmi4_remove), + .id_table = synaptics_rmi4_id_table, +}; +/** + * synaptics_rmi4_init() - Initialize the touchscreen driver + * + * This funtion uses to initializes the synaptics + * touchscreen driver and returns integer. + */ +static int __init synaptics_rmi4_init(void) +{ + return i2c_add_driver(&synaptics_rmi4_driver); +} +/** + * synaptics_rmi4_exit() - De-initialize the touchscreen driver + * + * This funtion uses to de-initialize the synaptics + * touchscreen driver and returns none. + */ +static void __exit synaptics_rmi4_exit(void) +{ + i2c_del_driver(&synaptics_rmi4_driver); +} + + +module_init(synaptics_rmi4_init); +module_exit(synaptics_rmi4_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("naveen.gaddipati@stericsson.com, js.ha@stericsson.com"); +MODULE_DESCRIPTION("synaptics rmi4 i2c touch Driver"); +MODULE_ALIAS("i2c:synaptics_rmi4_ts"); diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h new file mode 100644 index 000000000000..820ae275fa2b --- /dev/null +++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h @@ -0,0 +1,50 @@ +/** + * + * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver. + * Copyright (c) 2007-2010, Synaptics Incorporated + * + * Author: Js HA for ST-Ericsson + * Author: Naveen Kumar G for ST-Ericsson + * Copyright 2010 (c) ST-Ericsson AB + */ +/* + * This file is licensed under the GPL2 license. + * + *############################################################################# + * GPL + * + * 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. + * + * 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. + * + *############################################################################# + */ + +#ifndef _SYNAPTICS_RMI4_H_INCLUDED_ +#define _SYNAPTICS_RMI4_H_INCLUDED_ + +/** + * struct synaptics_rmi4_platform_data - contains the rmi4 platform data + * @irq_number: irq number + * @irq_type: irq type + * @x flip: x flip flag + * @y flip: y flip flag + * @regulator_en: regulator enable flag + * + * This structure gives platform data for rmi4. + */ +struct synaptics_rmi4_platform_data { + const char *name; + int irq_number; + int irq_type; + bool x_flip; + bool y_flip; + bool regulator_en; +}; + +#endif -- cgit v1.2.3 From e38b67c7cd3d2e377868e4c8ff4772f14ec7c45b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 25 Oct 2010 23:43:14 +0200 Subject: Staging: batman-adv: Remove useless braces 77099f0afe94928b5b0066a7efa5fa9f81696b54 added changes to vis.c which trigger a checkpatch.pl warning about braces which are not necessary anymore. WARNING: braces {} are not necessary for any arm of this statement + if (entry->primary) [...] + else { [...] Signed-off-by: Sven Eckelmann Cc: Andy Shevchenko Cc: Marek Lindner Cc: Simon Wunderlich Cc: Andrew Lunn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/vis.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index 3d2c1bccf2e6..4473cc8ed6b0 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -135,9 +135,8 @@ static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list) hlist_for_each_entry(entry, pos, if_list, list) { if (entry->primary) len += sprintf(buff + len, "PRIMARY, "); - else { + else len += sprintf(buff + len, "SEC %pM, ", entry->addr); - } } return len; -- cgit v1.2.3 From 53b6b34dfaa0263128d1e03bed0ba6fb40df88f8 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 26 Oct 2010 09:17:04 -0700 Subject: staging: brcm80211: Purge unused lines from bcmdefs.h/wlc_pub.h Purge unused lines Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmdefs.h | 56 ++--------------------------- drivers/staging/brcm80211/sys/wlc_pub.h | 4 +-- 2 files changed, 4 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h index dc52e9dbb8b5..ae6a65a64714 100644 --- a/drivers/staging/brcm80211/include/bcmdefs.h +++ b/drivers/staging/brcm80211/include/bcmdefs.h @@ -42,9 +42,6 @@ #define BCMFASTPATH #endif -/* Put some library data/code into ROM to reduce RAM requirements */ -#define BCMROMFN(_fn) _fn - /* Bus types */ #define SI_BUS 0 /* SOC Interconnect */ #define PCI_BUS 1 /* PCI target */ @@ -54,35 +51,10 @@ #define SPI_BUS 6 /* gSPI target */ #define RPC_BUS 7 /* RPC target */ -/* Allows size optimization for single-bus image */ -#ifdef BCMBUSTYPE -#define BUSTYPE(bus) (BCMBUSTYPE) -#else #define BUSTYPE(bus) (bus) -#endif - -/* Allows size optimization for single-backplane image */ -#ifdef BCMCHIPTYPE -#define CHIPTYPE(bus) (BCMCHIPTYPE) -#else #define CHIPTYPE(bus) (bus) -#endif - -/* Allows size optimization for SPROM support */ -#define SPROMBUS (PCI_BUS) - -/* Allows size optimization for single-chip image */ -#ifdef BCMCHIPID -#define CHIPID(chip) (BCMCHIPID) -#else #define CHIPID(chip) (chip) -#endif - -#ifdef BCMCHIPREV -#define CHIPREV(rev) (BCMCHIPREV) -#else #define CHIPREV(rev) (rev) -#endif /* Defines for DMA Address Width - Shared between OSL and HNDDMA */ #define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ @@ -146,31 +118,11 @@ typedef struct { #define BCMEXTRAHDROOM 172 -/* Headroom required for dongle-to-host communication. Packets allocated - * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should - * leave this much room in front for low-level message headers which may - * be needed to get across the dongle bus to the host. (These messages - * don't go over the network, so room for the full WL header above would - * be a waste.). -*/ -#define BCMDONGLEHDRSZ 12 -#define BCMDONGLEPADSZ 16 - -#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) - #ifdef BCMDBG - -#define BCMDBG_ERR - #ifndef BCMDBG_ASSERT #define BCMDBG_ASSERT -#endif /* BCMDBG_ASSERT */ - -#endif /* BCMDBG */ - -#if defined(BCMDBG_ASSERT) -#define BCMASSERT_SUPPORT -#endif +#endif /* BCMDBG_ASSERT */ +#endif /* BCMDBG */ /* Macros for doing definition and get/set of bitfields * Usage example, e.g. a three-bit field (bits 4-6): @@ -190,10 +142,6 @@ typedef struct { (((val) & (~(field ## _M << field ## _S))) | \ ((unsigned)(bits) << field ## _S)) -/* define BCMSMALL to remove misc features for memory-constrained environments */ -#define BCMSPACE -#define bcmspace true /* if (bcmspace) code is retained */ - /* Max. nvram variable table size */ #define MAXSZ_NVRAM_VARS 4096 diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index a6a8c33483c9..a392436c4d45 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -437,9 +437,9 @@ struct wlc_if; #define EDCF_ENAB(pub) (WME_ENAB(pub)) #define QOS_ENAB(pub) (WME_ENAB(pub) || N_ENAB(pub)) -#define MONITOR_ENAB(wlc) (bcmspace && (wlc)->monitor) +#define MONITOR_ENAB(wlc) ((wlc)->monitor) -#define PROMISC_ENAB(wlc) (bcmspace && (wlc)->promisc) +#define PROMISC_ENAB(wlc) ((wlc)->promisc) extern void wlc_pkttag_info_move(wlc_pub_t *pub, void *pkt_from, void *pkt_to); -- cgit v1.2.3 From ded6d25baa6bb0b3a41fa50a0427258c5d09ea7f Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 26 Oct 2010 09:17:05 -0700 Subject: staging: brcm80211: Purge unused includes from d11.h Purge unused #includes from d11.h Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/d11.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/d11.h b/drivers/staging/brcm80211/include/d11.h index c07548c70e30..f52714165cc9 100644 --- a/drivers/staging/brcm80211/include/d11.h +++ b/drivers/staging/brcm80211/include/d11.h @@ -17,12 +17,9 @@ #ifndef _D11_H #define _D11_H -#include #include -#include #include #include -#include /* This marks the start of a packed structure section. */ #include -- cgit v1.2.3 From a52ba66cf2e06dc7b9ad655b74324e81f756dbd3 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 26 Oct 2010 09:17:06 -0700 Subject: staging: brcm80211: Move #includes out of d11.h Move #includes out of d11.h and into .c files Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/d11.h | 4 ---- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 3 +++ drivers/staging/brcm80211/phy/wlc_phy_lcn.c | 4 ++++ drivers/staging/brcm80211/phy/wlc_phy_n.c | 4 ++++ drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c | 2 ++ drivers/staging/brcm80211/phy/wlc_phytbl_n.c | 2 ++ drivers/staging/brcm80211/sys/wl_mac80211.c | 2 ++ drivers/staging/brcm80211/sys/wlc_alloc.c | 2 ++ drivers/staging/brcm80211/sys/wlc_ampdu.c | 1 + drivers/staging/brcm80211/sys/wlc_antsel.c | 3 +++ drivers/staging/brcm80211/sys/wlc_bmac.c | 1 + drivers/staging/brcm80211/sys/wlc_channel.c | 2 ++ drivers/staging/brcm80211/sys/wlc_event.c | 2 ++ drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 ++ drivers/staging/brcm80211/sys/wlc_rate.c | 2 ++ drivers/staging/brcm80211/sys/wlc_stf.c | 2 ++ 16 files changed, 34 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/d11.h b/drivers/staging/brcm80211/include/d11.h index f52714165cc9..be2d4970407c 100644 --- a/drivers/staging/brcm80211/include/d11.h +++ b/drivers/staging/brcm80211/include/d11.h @@ -17,10 +17,6 @@ #ifndef _D11_H #define _D11_H -#include -#include -#include - /* This marks the start of a packed structure section. */ #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index 8287261120f4..c1882e2b291f 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c index 3d3112ed4e20..4efd8623e715 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c @@ -24,6 +24,10 @@ #include #include +#include +#include +#include + #include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_n.c b/drivers/staging/brcm80211/phy/wlc_phy_n.c index 950008f122b1..36f73e8adb64 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_n.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_n.c @@ -25,6 +25,10 @@ #include #include +#include +#include +#include + #include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c b/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c index 6ce9e5d96830..fd155a0a22ef 100644 --- a/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c +++ b/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c @@ -15,6 +15,8 @@ */ #include +#include +#include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phytbl_n.c b/drivers/staging/brcm80211/phy/wlc_phytbl_n.c index 7cc2c563c727..257c0bba4e54 100644 --- a/drivers/staging/brcm80211/phy/wlc_phytbl_n.c +++ b/drivers/staging/brcm80211/phy/wlc_phytbl_n.c @@ -16,6 +16,8 @@ #include +#include +#include #include #include diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index d060377629ac..d182b0233c9b 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 2dc89f9c2635..dc1fe2448d70 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index a4e49f3c1363..7a8340bd80dd 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index 5ff8831d2fa8..eac5b21d5df5 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -26,6 +26,9 @@ #include #include +#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index b70f9d099233..5045b8c68300 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -42,6 +42,7 @@ #include #include #include +#include /* BMAC_NOTE: a WLC_HIGH compile include of wlc.h adds in more structures and type * dependencies. Need to include these to files to allow a clean include of wlc.h * with WLC_HIGH defined. diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index 509280337e34..e786d990639e 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c index 7e1bf0e2ecdd..87181c111056 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.c +++ b/drivers/staging/brcm80211/sys/wlc_event.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index feaffcc64ec6..f64177436a62 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_rate.c b/drivers/staging/brcm80211/sys/wlc_rate.c index d2d72568756d..5b216b0bd9a4 100644 --- a/drivers/staging/brcm80211/sys/wlc_rate.c +++ b/drivers/staging/brcm80211/sys/wlc_rate.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c index 4728ad90e295..2d02ae7bdd8b 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.c +++ b/drivers/staging/brcm80211/sys/wlc_stf.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include -- cgit v1.2.3 From c6ac24e90a3f6a3cf25e3b1e4d8957032acf70a6 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 26 Oct 2010 11:55:23 -0700 Subject: staging: brcm80211: Purge linuxver.h and redistribute #includes as required Linuxver.h only included other .h files. Delete it and move #includes to .c's as needed. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh.c | 1 + drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 3 +- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 1 + .../brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c | 1 + drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 1 + drivers/staging/brcm80211/brcmfmac/dhd_common.c | 1 + .../staging/brcm80211/brcmfmac/dhd_custom_gpio.c | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 1 - .../staging/brcm80211/brcmfmac/dhd_linux_sched.c | 1 - drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 1 + drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 1 - drivers/staging/brcm80211/brcmfmac/wl_iw.c | 2 +- drivers/staging/brcm80211/include/linux_osl.h | 4 --- drivers/staging/brcm80211/include/linuxver.h | 38 ---------------------- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 3 +- drivers/staging/brcm80211/phy/wlc_phy_lcn.c | 2 +- drivers/staging/brcm80211/phy/wlc_phy_n.c | 2 +- drivers/staging/brcm80211/sys/wl_mac80211.c | 4 ++- drivers/staging/brcm80211/sys/wlc_alloc.c | 3 +- drivers/staging/brcm80211/sys/wlc_ampdu.c | 2 -- drivers/staging/brcm80211/sys/wlc_antsel.c | 3 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 4 ++- drivers/staging/brcm80211/sys/wlc_channel.c | 3 +- drivers/staging/brcm80211/sys/wlc_event.c | 3 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 1 - drivers/staging/brcm80211/sys/wlc_phy_shim.c | 3 +- drivers/staging/brcm80211/sys/wlc_rate.c | 2 +- drivers/staging/brcm80211/sys/wlc_stf.c | 2 +- drivers/staging/brcm80211/util/aiutils.c | 6 +++- drivers/staging/brcm80211/util/bcmotp.c | 3 +- drivers/staging/brcm80211/util/bcmsrom.c | 3 +- drivers/staging/brcm80211/util/bcmutils.c | 5 +-- drivers/staging/brcm80211/util/bcmwifi.c | 3 ++ drivers/staging/brcm80211/util/hnddma.c | 3 +- drivers/staging/brcm80211/util/hndpmu.c | 6 +++- drivers/staging/brcm80211/util/linux_osl.c | 5 ++- drivers/staging/brcm80211/util/nicpci.c | 2 +- drivers/staging/brcm80211/util/sbutils.c | 3 ++ drivers/staging/brcm80211/util/siutils.c | 6 +++- 39 files changed, 66 insertions(+), 74 deletions(-) delete mode 100644 drivers/staging/brcm80211/include/linuxver.h (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c index 4c613da3553a..3f79637f9e3c 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c @@ -16,6 +16,7 @@ /* ****************** BCMSDH Interface Functions *************************** */ #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index 9028cd01d9d0..59eaf71040b2 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -20,8 +20,7 @@ #define __UNDEF_NO_VERSION__ -#include - +#include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index f6c9c4541813..7d3d7cc74948 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c index ae7b566b11d7..b9f91fa86104 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c @@ -15,6 +15,7 @@ */ #include #include /* request_irq() */ +#include #include #include #include /* SDIO Specs */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c index bcbaac9bcdcc..0d14f6c1fcfa 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c @@ -15,6 +15,7 @@ */ #include +#include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c index 703188fc28ec..f7ffea69233c 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c index f647034f36d6..bb3c7b8c4b98 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c @@ -14,7 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index bbbe7c5f7492..797bff3be416 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c index bf8df9801030..c66f1c2941e2 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c @@ -16,7 +16,6 @@ #include #include #include -#include int setScheduler(struct task_struct *p, int policy, struct sched_param *param) { diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index b2281d9dfdcf..66884d47e834 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index 3f29488d9c72..21fe38fa736e 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index 979a494fda59..3e053fe56c79 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index c9c860b6e474..b13ae7614042 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -299,10 +299,6 @@ extern int osl_error(int bcmerror); #define W_SM(r, v) (*(r) = (v)) #define BZERO_SM(r, len) memset((r), '\0', (len)) -#ifdef BRCM_FULLMAC -#include /* use current 2.4.x calling conventions */ -#endif - /* packet primitives */ #define PKTGET(osh, len, send) osl_pktget((osh), (len)) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) diff --git a/drivers/staging/brcm80211/include/linuxver.h b/drivers/staging/brcm80211/include/linuxver.h deleted file mode 100644 index dc721413ee29..000000000000 --- a/drivers/staging/brcm80211/include/linuxver.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _linuxver_h_ -#define _linuxver_h_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef IP_TOS -#include - -#endif /* _linuxver_h_ */ diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index c1882e2b291f..9e6bbcdf8b6f 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -20,7 +20,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c index 4efd8623e715..1fde9d5701b0 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_n.c b/drivers/staging/brcm80211/phy/wlc_phy_n.c index 36f73e8adb64..3e1ab579c086 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_n.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_n.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index d182b0233c9b..a2e21dc34444 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -21,7 +21,9 @@ #include #include #include -#include +#include +#include +#include #include #define WLC_MAXBSSCFG 1 /* single BSS configs */ diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index dc1fe2448d70..8240d4ba962e 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -17,7 +17,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 7a8340bd80dd..5a3acf852efa 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -16,8 +16,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index eac5b21d5df5..3a1c1e9e7131 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -19,7 +19,8 @@ #ifdef WLANTSEL #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 5045b8c68300..a92a68fb4604 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -20,7 +20,9 @@ #include #include -#include +#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index e786d990639e..c7f416188093 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -19,7 +19,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c index 87181c111056..88418a293181 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.c +++ b/drivers/staging/brcm80211/sys/wlc_event.c @@ -16,7 +16,8 @@ #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index f64177436a62..c434f786594f 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_phy_shim.c b/drivers/staging/brcm80211/sys/wlc_phy_shim.c index bf8e2e1a15f6..45d583b1a271 100644 --- a/drivers/staging/brcm80211/sys/wlc_phy_shim.c +++ b/drivers/staging/brcm80211/sys/wlc_phy_shim.c @@ -24,7 +24,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_rate.c b/drivers/staging/brcm80211/sys/wlc_rate.c index 5b216b0bd9a4..e1199b236f5f 100644 --- a/drivers/staging/brcm80211/sys/wlc_rate.c +++ b/drivers/staging/brcm80211/sys/wlc_rate.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c index 2d02ae7bdd8b..7bf326fc015b 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.c +++ b/drivers/staging/brcm80211/sys/wlc_stf.c @@ -15,8 +15,8 @@ */ #include +#include #include -#include #include #include #include diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c index 75a7e3a5c009..1d4e3729ad61 100644 --- a/drivers/staging/brcm80211/util/aiutils.c +++ b/drivers/staging/brcm80211/util/aiutils.c @@ -17,8 +17,12 @@ #include #include #include +#ifdef BRCM_FULLMAC +#include +#endif #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c index c909832c7ee1..9b1e6d961a72 100644 --- a/drivers/staging/brcm80211/util/bcmotp.c +++ b/drivers/staging/brcm80211/util/bcmotp.c @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 1282ef7eb922..4f3d3ca1af79 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -17,7 +17,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 9789ea45ecd6..869d34c420d2 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -19,8 +19,10 @@ #include #include #include +#include +#include +#include #include -#include #include #include #include @@ -30,7 +32,6 @@ #include #include - /* copy a buffer into a pkt buffer chain */ uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf) { diff --git a/drivers/staging/brcm80211/util/bcmwifi.c b/drivers/staging/brcm80211/util/bcmwifi.c index 1bb6c78eece7..2e472e00adc3 100644 --- a/drivers/staging/brcm80211/util/bcmwifi.c +++ b/drivers/staging/brcm80211/util/bcmwifi.c @@ -15,6 +15,9 @@ */ #include #include +#ifdef BRCM_FULLMAC +#include +#endif #include #include #include diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index fe503e7de563..b4dcb05705b3 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -16,7 +16,8 @@ #include #include -#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/hndpmu.c b/drivers/staging/brcm80211/util/hndpmu.c index a8f3306c1d2b..6fb256bc5549 100644 --- a/drivers/staging/brcm80211/util/hndpmu.c +++ b/drivers/staging/brcm80211/util/hndpmu.c @@ -15,7 +15,11 @@ */ #include #include -#include +#include +#include +#ifdef BRCM_FULLMAC +#include +#endif #include #include #include diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 2bb5b8722df6..effe043f1962 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -20,7 +20,10 @@ #include #endif /* mips */ #include -#include +#include +#include +#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/nicpci.c b/drivers/staging/brcm80211/util/nicpci.c index 23f86dd7b159..169a4287ee63 100644 --- a/drivers/staging/brcm80211/util/nicpci.c +++ b/drivers/staging/brcm80211/util/nicpci.c @@ -15,7 +15,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/sbutils.c b/drivers/staging/brcm80211/util/sbutils.c index e4c0baba553d..82767e266e97 100644 --- a/drivers/staging/brcm80211/util/sbutils.c +++ b/drivers/staging/brcm80211/util/sbutils.c @@ -16,6 +16,9 @@ #include #include +#ifdef BRCM_FULLMAC +#include +#endif #include #include #include diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index f3ea7e1a7aef..3b99293307ea 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -17,8 +17,12 @@ #include #include #include +#ifdef BRCM_FULLMAC +#include +#endif #include -#include +#include +#include #include #include #include -- cgit v1.2.3 From 7f7c3dbb3f6d8624109ee30ad5a8f6b23f0a72f4 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 26 Oct 2010 15:23:09 -0700 Subject: staging: brcm80211: Move #include from bcmutils.h out to .c files Part of effort to move #includes out of .h files and unwind the include mess. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh.c | 2 +- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 2 +- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c | 1 + drivers/staging/brcm80211/include/bcmutils.h | 1 - drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c | 1 + drivers/staging/brcm80211/phy/wlc_phytbl_n.c | 1 + drivers/staging/brcm80211/sys/wlc_event.c | 1 + drivers/staging/brcm80211/sys/wlc_phy_shim.c | 2 +- drivers/staging/brcm80211/util/bcmwifi.c | 1 + 9 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c index 3f79637f9e3c..6738983e2d5c 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c @@ -20,10 +20,10 @@ #include #include #include +#include #include #include #include -#include #include /* BRCM API for SDIO clients (such as wl, dhd) */ diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 7d3d7cc74948..039f114130d2 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include /* SDIO Device and Protocol Specs */ #include /* SDIO Host Controller Specification */ #include /* bcmsdh to/from specific controller APIs */ diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c index b9f91fa86104..14f73fd28760 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c @@ -17,6 +17,7 @@ #include /* request_irq() */ #include #include +#include #include #include /* SDIO Specs */ #include /* bcmsdh to/from specific controller APIs */ diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h index b53315981be0..7f1d33481ee8 100644 --- a/drivers/staging/brcm80211/include/bcmutils.h +++ b/drivers/staging/brcm80211/include/bcmutils.h @@ -30,7 +30,6 @@ }; /* ** driver-only section ** */ -#include #define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ diff --git a/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c b/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c index fd155a0a22ef..330b88152b65 100644 --- a/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c +++ b/drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phytbl_n.c b/drivers/staging/brcm80211/phy/wlc_phytbl_n.c index 257c0bba4e54..a9fc193721ef 100644 --- a/drivers/staging/brcm80211/phy/wlc_phytbl_n.c +++ b/drivers/staging/brcm80211/phy/wlc_phytbl_n.c @@ -18,6 +18,7 @@ #include #include +#include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c index 88418a293181..4b0a59896bec 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.c +++ b/drivers/staging/brcm80211/sys/wlc_event.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_phy_shim.c b/drivers/staging/brcm80211/sys/wlc_phy_shim.c index 45d583b1a271..900c505ced34 100644 --- a/drivers/staging/brcm80211/sys/wlc_phy_shim.c +++ b/drivers/staging/brcm80211/sys/wlc_phy_shim.c @@ -26,8 +26,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/drivers/staging/brcm80211/util/bcmwifi.c b/drivers/staging/brcm80211/util/bcmwifi.c index 2e472e00adc3..81e54bd7a554 100644 --- a/drivers/staging/brcm80211/util/bcmwifi.c +++ b/drivers/staging/brcm80211/util/bcmwifi.c @@ -18,6 +18,7 @@ #ifdef BRCM_FULLMAC #include #endif +#include #include #include #include -- cgit v1.2.3 From eb8160364f007c668c423614e262b9b7fc7b2c74 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 26 Oct 2010 18:37:24 -0700 Subject: staging: brcm80211: Separate fullmac vs softmac defs in shared file wlioctl.h is shared by fullmac and softmac but mostly fullmac. Separate out fullmac to purge extranous code in softmac and possibly as a step towards it own file. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/wlioctl.h | 12 ++++++++++++ drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 ++ 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/wlioctl.h b/drivers/staging/brcm80211/include/wlioctl.h index 96866fb8898c..81863e0cab1e 100644 --- a/drivers/staging/brcm80211/include/wlioctl.h +++ b/drivers/staging/brcm80211/include/wlioctl.h @@ -33,6 +33,7 @@ #define BWL_DEFAULT_PACKING #include +#ifdef BRCM_FULLMAC /* Legacy structure to help keep backward compatible wl tool and tray app */ #define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ @@ -148,12 +149,14 @@ typedef struct wl_bss_info { /* Add new fields here */ /* variable length Information Elements */ } wl_bss_info_t; +#endif /* BRCM_FULLMAC */ typedef struct wlc_ssid { u32 SSID_len; unsigned char SSID[32]; } wlc_ssid_t; +#ifdef BRCM_FULLMAC typedef struct chan_scandata { u8 txpower; u8 pad; @@ -308,6 +311,7 @@ typedef struct wl_probe_params { struct ether_addr bssid; struct ether_addr mac; } wl_probe_params_t; +#endif /* BRCM_FULLMAC */ #define WL_NUMRATES 16 /* max # of rates in a rateset */ typedef struct wl_rateset { @@ -315,6 +319,7 @@ typedef struct wl_rateset { u8 rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ } wl_rateset_t; +#ifdef BRCM_FULLMAC typedef struct wl_rateset_args { u32 count; /* # rates in this set */ u8 rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ @@ -352,6 +357,8 @@ typedef struct wl_join_params { } wl_join_params_t; #define WL_JOIN_PARAMS_FIXED_SIZE (sizeof(wl_join_params_t) - sizeof(chanspec_t)) +#endif /* BRCM_FULLMAC */ + /* defines used by the nrate iovar */ #define NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ #define NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ @@ -391,6 +398,7 @@ typedef struct { #define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ +#ifdef BRCM_FULLMAC #define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ #define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ @@ -428,8 +436,11 @@ typedef struct { cca_congest_t secs[1]; /* Data */ } cca_congest_channel_req_t; +#endif /* BRCM_FULLMAC */ + #define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ +#ifdef BRCM_FULLMAC typedef struct wl_country { char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in * the Country IE @@ -516,6 +527,7 @@ typedef struct wl_rm_rep { wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ } wl_rm_rep_t; #define WL_RM_REP_FIXED_LEN 8 +#endif /* BRCM_FULLMAC */ /* Enumerate crypto algorithms */ #define CRYPTO_ALGO_OFF 0 diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index c434f786594f..01b8110afd1c 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -1781,8 +1781,10 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, ASSERT(sizeof(struct dot11_bcn_prb) == DOT11_BCN_PRB_LEN); ASSERT(sizeof(tx_status_t) == TXSTATUS_LEN); ASSERT(sizeof(ht_cap_ie_t) == HT_CAP_IE_LEN); +#ifdef BRCM_FULLMAC ASSERT(offsetof(wl_scan_params_t, channel_list) == WL_SCAN_PARAMS_FIXED_SIZE); +#endif ASSERT(IS_ALIGNED(offsetof(wsec_key_t, data), sizeof(u32))); ASSERT(ISPOWEROF2(MA_WINDOW_SZ)); -- cgit v1.2.3 From 4766ae6ce7c5098a26136241576cd8a287d20484 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Wed, 27 Oct 2010 15:47:53 -0700 Subject: staging: brcm80211: purge epivers.h Purge include/epivers.h moving individual lines to where they are needed and delete unused refs. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/epivers.h | 44 ---------------------------- drivers/staging/brcm80211/sys/wl_mac80211.c | 11 ++++--- drivers/staging/brcm80211/sys/wlc_mac80211.c | 3 +- 3 files changed, 7 insertions(+), 51 deletions(-) delete mode 100644 drivers/staging/brcm80211/include/epivers.h (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/epivers.h b/drivers/staging/brcm80211/include/epivers.h deleted file mode 100644 index 2e6b5190ad6c..000000000000 --- a/drivers/staging/brcm80211/include/epivers.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _epivers_h_ -#define _epivers_h_ - -#define EPI_MAJOR_VERSION 5 - -#define EPI_MINOR_VERSION 75 - -#define EPI_RC_NUMBER 11 - -#define EPI_INCREMENTAL_NUMBER 0 - -#define EPI_BUILD_NUMBER 1 - -#define EPI_VERSION { 5, 75, 11, 0 } - -#ifdef BCMSDIO -/* EPI_VERSION_NUM must match FW version */ -#define EPI_VERSION_NUM 0x054b0c00 -#else -#define EPI_VERSION_NUM 0x054b0b00 -#endif - -#define EPI_VERSION_DEV 5.75.11 - -/* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "5.75.11" - -#endif /* _epivers_h_ */ diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index a2e21dc34444..d951d330a1c8 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -29,7 +29,6 @@ #include #include -#include #ifndef WLC_HIGH_ONLY #include #endif @@ -894,8 +893,8 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, wl_release_fw(wl); #endif if (!wl->wlc) { - printf("%s: %s wlc_attach() failed with code %d\n", - KBUILD_MODNAME, EPI_VERSION_STR, err); + printf("%s: wlc_attach() failed with code %d\n", + KBUILD_MODNAME, err); goto fail; } wl->pub = wlc_pub(wl->wlc); @@ -962,10 +961,10 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, } #ifndef WLC_HIGH_ONLY WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver " - EPI_VERSION_STR " (" PHY_VERSION_STR ")", unit)); + " (" PHY_VERSION_STR ")", unit)); #else - WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver " - EPI_VERSION_STR, unit)); + WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 Splitmac MAC80211 Driver " + , unit)); #endif #ifdef BCMDBG diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 01b8110afd1c..e7a4bcb1c65a 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -136,6 +135,8 @@ uint wl_msg_level = #define SCAN_IN_PROGRESS(x) 0 +#define EPI_VERSION_NUM 0x054b0b00 + #ifdef BCMDBG /* pointer to most recently allocated wl/wlc */ static wlc_info_t *wlc_info_dbg = (wlc_info_t *) (NULL); -- cgit v1.2.3 From 8fb6b18884703d447af4c5ed1eeec02b489aa54b Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Mon, 1 Nov 2010 17:10:15 -0700 Subject: staging: brcm80211: Remove abstraction layer for dma alignment Directly align buffers instead of abstracting it. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 2 -- drivers/staging/brcm80211/util/linux_osl.c | 7 +------ 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index b13ae7614042..e6d2f30c63ca 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -91,8 +91,6 @@ typedef struct { #define BUS_SWAP32(v) (v) -#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() -extern uint osl_dma_consistent_align(void); extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align, uint *tot, unsigned long *pap); diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index effe043f1962..01851e56b157 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -285,11 +285,6 @@ uint osl_pci_slot(osl_t *osh) return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); } -uint osl_dma_consistent_align(void) -{ - return PAGE_SIZE; -} - void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits, uint *alloced, unsigned long *pap) { @@ -297,7 +292,7 @@ void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits, if (align_bits) { u16 align = (1 << align_bits); - if (!IS_ALIGNED(DMA_CONSISTENT_ALIGN, align)) + if (!IS_ALIGNED(PAGE_SIZE, align)) size += align; *alloced = size; } -- cgit v1.2.3 From 683ab518a19fe55de9b9f682c94f672951315fe2 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Mon, 1 Nov 2010 17:10:16 -0700 Subject: staging: brcm80211: Remove dead code from osl.h Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index e6d2f30c63ca..62afbe88f793 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -18,12 +18,6 @@ #define _linux_osl_h_ -/* Linux Kernel: File Operations: start */ -extern void *osl_os_open_image(char *filename); -extern int osl_os_get_image_block(char *buf, int len, void *image); -extern void osl_os_close_image(void *image); -/* Linux Kernel: File Operations: end */ - extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); extern void osl_detach(osl_t *osh); @@ -269,22 +263,6 @@ extern int osl_error(int bcmerror); #define OSL_CACHED(va) ((void *)va) #endif /* mips */ -#if defined(mips) -#define OSL_GETCYCLES(x) ((x) = read_c0_count() * 2) -#elif defined(__i386__) -#define OSL_GETCYCLES(x) rdtscl((x)) -#else -#define OSL_GETCYCLES(x) ((x) = 0) -#endif /* defined(mips) */ - -/* dereference an address that may cause a bus exception */ -#ifdef mips -#define BUSPROBE(val, addr) get_dbe((val), (addr)) -#include -#else -#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) -#endif /* mips */ - /* map/unmap physical to virtual I/O */ #if !defined(CONFIG_MMC_MSM7X00A) #define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) -- cgit v1.2.3 From 9014378bf42912533299d37f14677f9dfa21268a Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Mon, 1 Nov 2010 17:10:17 -0700 Subject: staging: brcm80211: Remove OSL_ERROR entry point Get rid of generic OSL_ERROR and error code translation to the only place that needs it: dhd. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 52 +++++++++++++++++- drivers/staging/brcm80211/include/linux_osl.h | 3 -- drivers/staging/brcm80211/util/linux_osl.c | 73 -------------------------- 3 files changed, 51 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 797bff3be416..ba6fdc6133db 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1620,6 +1620,51 @@ static int dhd_ethtool(dhd_info_t *dhd, void *uaddr) return 0; } +static s16 linuxbcmerrormap[] = { 0, /* 0 */ + -EINVAL, /* BCME_ERROR */ + -EINVAL, /* BCME_BADARG */ + -EINVAL, /* BCME_BADOPTION */ + -EINVAL, /* BCME_NOTUP */ + -EINVAL, /* BCME_NOTDOWN */ + -EINVAL, /* BCME_NOTAP */ + -EINVAL, /* BCME_NOTSTA */ + -EINVAL, /* BCME_BADKEYIDX */ + -EINVAL, /* BCME_RADIOOFF */ + -EINVAL, /* BCME_NOTBANDLOCKED */ + -EINVAL, /* BCME_NOCLK */ + -EINVAL, /* BCME_BADRATESET */ + -EINVAL, /* BCME_BADBAND */ + -E2BIG, /* BCME_BUFTOOSHORT */ + -E2BIG, /* BCME_BUFTOOLONG */ + -EBUSY, /* BCME_BUSY */ + -EINVAL, /* BCME_NOTASSOCIATED */ + -EINVAL, /* BCME_BADSSIDLEN */ + -EINVAL, /* BCME_OUTOFRANGECHAN */ + -EINVAL, /* BCME_BADCHAN */ + -EFAULT, /* BCME_BADADDR */ + -ENOMEM, /* BCME_NORESOURCE */ + -EOPNOTSUPP, /* BCME_UNSUPPORTED */ + -EMSGSIZE, /* BCME_BADLENGTH */ + -EINVAL, /* BCME_NOTREADY */ + -EPERM, /* BCME_NOTPERMITTED */ + -ENOMEM, /* BCME_NOMEM */ + -EINVAL, /* BCME_ASSOCIATED */ + -ERANGE, /* BCME_RANGE */ + -EINVAL, /* BCME_NOTFOUND */ + -EINVAL, /* BCME_WME_NOT_ENABLED */ + -EINVAL, /* BCME_TSPEC_NOTFOUND */ + -EINVAL, /* BCME_ACM_NOTSUPPORTED */ + -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ + -EIO, /* BCME_SDIO_ERROR */ + -ENODEV, /* BCME_DONGLE_DOWN */ + -EINVAL, /* BCME_VERSION */ + -EIO, /* BCME_TXFAIL */ + -EIO, /* BCME_RXFAIL */ + -EINVAL, /* BCME_NODEVICE */ + -EINVAL, /* BCME_NMODE_DISABLED */ + -ENODATA, /* BCME_NONRESIDENT */ +}; + static int dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) { dhd_info_t *dhd = *(dhd_info_t **) netdev_priv(net); @@ -1741,7 +1786,12 @@ done: if (buf) kfree(buf); - return OSL_ERROR(bcmerror); + if (bcmerror > 0) + bcmerror = 0; + else if (bcmerror < BCME_LAST) + bcmerror = BCME_ERROR; + + return linuxbcmerrormap[-bcmerror]; } static int dhd_stop(struct net_device *net) diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 62afbe88f793..c398f7908447 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -134,9 +134,6 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op #endif -#define OSL_ERROR(bcmerror) osl_error(bcmerror) -extern int osl_error(int bcmerror); - /* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ #define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 01851e56b157..3255b31b88eb 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -46,74 +46,6 @@ struct osl_info { /* Global ASSERT type flag */ u32 g_assert_type; -#ifdef BRCM_FULLMAC -static s16 linuxbcmerrormap[] = { 0, /* 0 */ - -EINVAL, /* BCME_ERROR */ - -EINVAL, /* BCME_BADARG */ - -EINVAL, /* BCME_BADOPTION */ - -EINVAL, /* BCME_NOTUP */ - -EINVAL, /* BCME_NOTDOWN */ - -EINVAL, /* BCME_NOTAP */ - -EINVAL, /* BCME_NOTSTA */ - -EINVAL, /* BCME_BADKEYIDX */ - -EINVAL, /* BCME_RADIOOFF */ - -EINVAL, /* BCME_NOTBANDLOCKED */ - -EINVAL, /* BCME_NOCLK */ - -EINVAL, /* BCME_BADRATESET */ - -EINVAL, /* BCME_BADBAND */ - -E2BIG, /* BCME_BUFTOOSHORT */ - -E2BIG, /* BCME_BUFTOOLONG */ - -EBUSY, /* BCME_BUSY */ - -EINVAL, /* BCME_NOTASSOCIATED */ - -EINVAL, /* BCME_BADSSIDLEN */ - -EINVAL, /* BCME_OUTOFRANGECHAN */ - -EINVAL, /* BCME_BADCHAN */ - -EFAULT, /* BCME_BADADDR */ - -ENOMEM, /* BCME_NORESOURCE */ - -EOPNOTSUPP, /* BCME_UNSUPPORTED */ - -EMSGSIZE, /* BCME_BADLENGTH */ - -EINVAL, /* BCME_NOTREADY */ - -EPERM, /* BCME_NOTPERMITTED */ - -ENOMEM, /* BCME_NOMEM */ - -EINVAL, /* BCME_ASSOCIATED */ - -ERANGE, /* BCME_RANGE */ - -EINVAL, /* BCME_NOTFOUND */ - -EINVAL, /* BCME_WME_NOT_ENABLED */ - -EINVAL, /* BCME_TSPEC_NOTFOUND */ - -EINVAL, /* BCME_ACM_NOTSUPPORTED */ - -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ - -EIO, /* BCME_SDIO_ERROR */ - -ENODEV, /* BCME_DONGLE_DOWN */ - -EINVAL, /* BCME_VERSION */ - -EIO, /* BCME_TXFAIL */ - -EIO, /* BCME_RXFAIL */ - -EINVAL, /* BCME_NODEVICE */ - -EINVAL, /* BCME_NMODE_DISABLED */ - -ENODATA, /* BCME_NONRESIDENT */ - -/* When an new error code is added to bcmutils.h, add os - * spcecific error translation here as well - */ -/* check if BCME_LAST changed since the last time this function was updated */ -#if BCME_LAST != -42 -#error "You need to add a OS error translation in the linuxbcmerrormap \ - for new error code defined in bcmutils.h" -#endif -}; - -/* translate bcmerrors into linux errors */ -int osl_error(int bcmerror) -{ - if (bcmerror > 0) - bcmerror = 0; - else if (bcmerror < BCME_LAST) - bcmerror = BCME_ERROR; - - /* Array bounds covered by ASSERT in osl_attach */ - return linuxbcmerrormap[-bcmerror]; -} -#endif /* BRCM_FULLMAC */ - osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) { osl_t *osh; @@ -123,11 +55,6 @@ osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) bzero(osh, sizeof(osl_t)); -#ifdef BRCM_FULLMAC - /* Check that error map has the right number of entries in it */ - ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(linuxbcmerrormap) - 1)); -#endif /* BRCM_FULLMAC */ - osh->magic = OS_HANDLE_MAGIC; osh->failed = 0; osh->pdev = pdev; -- cgit v1.2.3 From a28792e78669dc1bb984dd7798f0bccda741acbb Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Mon, 1 Nov 2010 17:10:18 -0700 Subject: staging: brcm80211: Remove cruft from wlioctl.h Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/wlioctl.h | 329 +--------------------------- 1 file changed, 6 insertions(+), 323 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/wlioctl.h b/drivers/staging/brcm80211/include/wlioctl.h index 81863e0cab1e..45e02e5293eb 100644 --- a/drivers/staging/brcm80211/include/wlioctl.h +++ b/drivers/staging/brcm80211/include/wlioctl.h @@ -34,82 +34,8 @@ #include #ifdef BRCM_FULLMAC -/* Legacy structure to help keep backward compatible wl tool and tray app */ -#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ - -typedef struct wl_bss_info_107 { - u32 version; /* version field */ - u32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - u16 beacon_period; /* units are Kusec */ - u16 capability; /* Capability information */ - u8 SSID_len; - u8 SSID[32]; - struct { - uint count; /* # rates in this set */ - u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - u8 channel; /* Channel no. */ - u16 atim_window; /* units are Kusec */ - u8 dtim_period; /* DTIM period */ - s16 RSSI; /* receive signal strength (in dBm) */ - s8 phy_noise; /* noise (in dBm) */ - u32 ie_length; /* byte length of Information Elements */ - /* variable length Information Elements */ -} wl_bss_info_107_t; - -/* - * Per-BSS information structure. - */ - -#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in wl_scan_results_t) - */ -typedef struct wl_bss_info_108 { - u32 version; /* version field */ - u32 length; /* byte length of data in this record, - * starting at version and including IEs - */ - struct ether_addr BSSID; - u16 beacon_period; /* units are Kusec */ - u16 capability; /* Capability information */ - u8 SSID_len; - u8 SSID[32]; - struct { - uint count; /* # rates in this set */ - u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ - } rateset; /* supported rates */ - chanspec_t chanspec; /* chanspec for bss */ - u16 atim_window; /* units are Kusec */ - u8 dtim_period; /* DTIM period */ - s16 RSSI; /* receive signal strength (in dBm) */ - s8 phy_noise; /* noise (in dBm) */ - - u8 n_cap; /* BSS is 802.11N Capable */ - u32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ - u8 ctl_ch; /* 802.11N BSS control channel number */ - u32 reserved32[1]; /* Reserved for expansion of BSS properties */ - u8 flags; /* flags */ - u8 reserved[3]; /* Reserved for expansion of BSS properties */ - u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ - - u16 ie_offset; /* offset at which IEs start, from beginning */ - u32 ie_length; /* byte length of Information Elements */ - /* Add new fields here */ - /* variable length Information Elements */ -} wl_bss_info_108_t; - -#ifdef BRCM_FULLMAC #define WL_BSS_INFO_VERSION 108 /* current ver of wl_bss_info struct */ -#else -#define WL_BSS_INFO_VERSION 109 /* current ver of wl_bss_info struct */ -#endif /* BSS info structure * Applications MUST CHECK ie_offset field and length field to access IEs and @@ -633,27 +559,6 @@ typedef struct wl_led_info { u8 activehi; } wl_led_info_t; -/* flags */ -#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ - -/* srom read/write struct passed through ioctl */ -typedef struct { - uint byteoff; /* byte offset */ - uint nbytes; /* number of bytes */ - u16 buf[1]; -} srom_rw_t; - -/* similar cis (srom or otp) struct [iovar: may not be aligned] */ -typedef struct { - u32 source; /* cis source */ - u32 byteoff; /* byte offset */ - u32 nbytes; /* number of bytes */ - /* data follows here */ -} cis_rw_t; - -#define WLC_CIS_DEFAULT 0 /* built-in default */ -#define WLC_CIS_SROM 1 /* source is sprom */ -#define WLC_CIS_OTP 2 /* source is otp */ /* R_REG and W_REG struct passed through ioctl */ typedef struct { @@ -663,102 +568,14 @@ typedef struct { uint band; /* band (optional) */ } rw_reg_t; -/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ -/* PCL - Power Control Loop */ -/* current gain setting is replaced by user input */ -#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ -#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ -/* current gain setting is maintained */ -#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ - -typedef struct { - u16 auto_ctrl; /* WL_ATTEN_XX */ - u16 bb; /* Baseband attenuation */ - u16 radio; /* Radio attenuation */ - u16 txctl1; /* Radio TX_CTL1 value */ -} atten_t; - -/* Per-AC retry parameters */ -struct wme_tx_params_s { - u8 short_retry; - u8 short_fallback; - u8 long_retry; - u8 long_fallback; - u16 max_rate; /* In units of 512 Kbps */ -}; - -typedef struct wme_tx_params_s wme_tx_params_t; - -#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) - -/* defines used by poweridx iovar - it controls power in a-band */ -/* current gain setting is maintained */ -#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ -#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ -#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ -#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ -/* value >= 0 causes - * - input to be set to that value - * - PCL to be off - */ - -/* Used to get specific link/ac parameters */ -typedef struct { - int ac; - u8 val; - struct ether_addr ea; -} link_val_t; - -#define BCM_MAC_STATUS_INDICATION (0x40010200L) - -typedef struct { - u16 ver; /* version of this struct */ - u16 len; /* length in bytes of this structure */ - u16 cap; /* sta's advertised capabilities */ - u32 flags; /* flags defined below */ - u32 idle; /* time since data pkt rx'd from sta */ - struct ether_addr ea; /* Station address */ - wl_rateset_t rateset; /* rateset in use */ - u32 in; /* seconds elapsed since associated */ - u32 listen_interval_inms; /* Min Listen interval in ms for this STA */ - u32 tx_pkts; /* # of packets transmitted */ - u32 tx_failures; /* # of packets failed */ - u32 rx_ucast_pkts; /* # of unicast packets received */ - u32 rx_mcast_pkts; /* # of multicast packets received */ - u32 tx_rate; /* Rate of last successful tx frame */ - u32 rx_rate; /* Rate of last successful rx frame */ - u32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ - u32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ -} sta_info_t; - -#define WL_OLD_STAINFO_SIZE offsetof(sta_info_t, tx_pkts) - -#define WL_STA_VER 3 - -/* Flags for sta_info_t indicating properties of STA */ -#define WL_STA_BRCM 0x1 /* Running a Broadcom driver */ -#define WL_STA_WME 0x2 /* WMM association */ -#define WL_STA_ABCAP 0x4 -#define WL_STA_AUTHE 0x8 /* Authenticated */ -#define WL_STA_ASSOC 0x10 /* Associated */ -#define WL_STA_AUTHO 0x20 /* Authorized */ -#define WL_STA_WDS 0x40 /* Wireless Distribution System */ -#define WL_STA_WDS_LINKUP 0x80 /* WDS traffic/probes flowing properly */ -#define WL_STA_PS 0x100 /* STA is in power save mode from AP's viewpoint */ -#define WL_STA_APSD_BE 0x200 /* APSD delv/trigger for AC_BE is default enabled */ -#define WL_STA_APSD_BK 0x400 /* APSD delv/trigger for AC_BK is default enabled */ -#define WL_STA_APSD_VI 0x800 /* APSD delv/trigger for AC_VI is default enabled */ -#define WL_STA_APSD_VO 0x1000 /* APSD delv/trigger for AC_VO is default enabled */ -#define WL_STA_N_CAP 0x2000 /* STA 802.11n capable */ -#define WL_STA_SCBSTATS 0x4000 /* Per STA debug stats */ - -#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ +#ifdef BRCM_FULLMAC /* Used to get specific STA parameters */ typedef struct { u32 val; struct ether_addr ea; } scb_val_t; +#endif /* BRCM_FULLMAC */ /* channel encoding */ typedef struct channel_info { @@ -782,6 +599,7 @@ typedef struct get_pktcnt { uint rx_ocast_good_pkt; /* unicast packets destined for others */ } get_pktcnt_t; +#ifdef BRCM_FULLMAC /* Linux network driver ioctl encoding */ typedef struct wl_ioctl { uint cmd; /* common ioctl definition */ @@ -791,11 +609,8 @@ typedef struct wl_ioctl { uint used; /* bytes read or written (optional) */ uint needed; /* bytes needed (optional) */ } wl_ioctl_t; +#endif /* BRCM_FULLMAC */ -/* reference to wl_ioctl_t struct used by usermode driver */ -#define ioctl_subtype set /* subtype param */ -#define ioctl_pid used /* pid param */ -#define ioctl_status needed /* status param */ /* * Structure for passing hardware and software @@ -822,45 +637,11 @@ typedef struct wlc_rev_info { #define WL_REV_INFO_LEGACY_LENGTH 48 -#define WL_BRAND_MAX 10 -typedef struct wl_instance_info { - uint instance; - char brand[WL_BRAND_MAX]; -} wl_instance_info_t; - -/* structure to change size of tx fifo */ -typedef struct wl_txfifo_sz { - u16 magic; - u16 fifo; - u16 size; -} wl_txfifo_sz_t; -/* magic pattern used for mismatch driver and wl */ -#define WL_TXFIFO_SZ_MAGIC 0xa5a5 - -/* Transfer info about an IOVar from the driver */ -/* Max supported IOV name size in bytes, + 1 for nul termination */ -#define WLC_IOV_NAME_LEN 30 -typedef struct wlc_iov_trx_s { - u8 module; - u8 type; - char name[WLC_IOV_NAME_LEN]; -} wlc_iov_trx_t; - -/* check this magic number */ -#define WLC_IOCTL_MAGIC 0x14e46c77 - -#define PROC_ENTRY_NAME "brcm_debug" -/* bump this number if you change the ioctl interface */ -#define WLC_IOCTL_VERSION 1 - #ifdef BRCM_FULLMAC -#define WLC_IOCTL_MAXLEN 8192 -#else -#define WLC_IOCTL_MAXLEN 3072 /* max length ioctl buffer required */ -#endif #define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ #define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ -#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ +#define WLC_IOCTL_MAXLEN 8192 +#endif /* common ioctl definitions */ #define WLC_GET_MAGIC 0 @@ -1411,23 +1192,6 @@ typedef struct { #define WL_TX_POWER_MCS40_FIRST 28 #define WL_TX_POWER_MCS40_NUM 17 -typedef struct { - u32 flags; - chanspec_t chanspec; /* txpwr report for this channel */ - chanspec_t local_chanspec; /* channel on which we are associated */ - u8 local_max; /* local max according to the AP */ - u8 local_constraint; /* local constraint according to the AP */ - s8 antgain[2]; /* Ant gain for each band - from SROM */ - u8 rf_cores; /* count of RF Cores being reported */ - u8 est_Pout[4]; /* Latest tx power out estimate per RF - * chain without adjustment - */ - u8 est_Pout_cck; /* Latest CCK tx power out estimate */ - u8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ - u8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ - u8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ - u8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ -} tx_power_legacy2_t; #define WL_TX_POWER_RATES 101 #define WL_TX_POWER_CCK_FIRST 0 @@ -1860,63 +1624,6 @@ struct ampdu_retry_tid { u8 retry; /* retry value */ }; -/* structure for addts arguments */ -/* For ioctls that take a list of TSPEC */ -struct tslist { - int count; /* number of tspecs */ - struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ -}; - -/* structure for addts/delts arguments */ -typedef struct tspec_arg { - u16 version; /* see definition of TSPEC_ARG_VERSION */ - u16 length; /* length of entire structure */ - uint flag; /* bit field */ - /* TSPEC Arguments */ - struct tsinfo_arg tsinfo; /* TS Info bit field */ - u16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ - u16 max_msdu_size; /* Maximum MSDU Size (bytes) */ - uint min_srv_interval; /* Minimum Service Interval (us) */ - uint max_srv_interval; /* Maximum Service Interval (us) */ - uint inactivity_interval; /* Inactivity Interval (us) */ - uint suspension_interval; /* Suspension Interval (us) */ - uint srv_start_time; /* Service Start Time (us) */ - uint min_data_rate; /* Minimum Data Rate (bps) */ - uint mean_data_rate; /* Mean Data Rate (bps) */ - uint peak_data_rate; /* Peak Data Rate (bps) */ - uint max_burst_size; /* Maximum Burst Size (bytes) */ - uint delay_bound; /* Delay Bound (us) */ - uint min_phy_rate; /* Minimum PHY Rate (bps) */ - u16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ - u16 medium_time; /* Medium Time (32 us/s periods) */ - u8 dialog_token; /* dialog token */ -} tspec_arg_t; - -/* tspec arg for desired station */ -typedef struct tspec_per_sta_arg { - struct ether_addr ea; - struct tspec_arg ts; -} tspec_per_sta_arg_t; - -/* structure for max bandwidth for each access category */ -typedef struct wme_max_bandwidth { - u32 ac[AC_COUNT]; /* max bandwidth for each access category */ -} wme_max_bandwidth_t; - -#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) - -/* current version of wl_tspec_arg_t struct */ -#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ -#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ -#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ -#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ - -/* define for flag */ -#define TSPEC_PENDING 0 /* TSPEC pending */ -#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ -#define TSPEC_REJECTED 2 /* TSPEC rejected */ -#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ -#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ /* Software feature flag defines used by wlfeatureflag */ #define WL_SWFL_NOHWRADIO 0x0004 @@ -1925,16 +1632,6 @@ typedef struct wme_max_bandwidth { #define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ -/* - * Dongle pattern matching filter. - */ - -/* Packet filter types. Currently, only pattern matching is supported. */ -typedef enum wl_pkt_filter_type { - WL_PKT_FILTER_TYPE_PATTERN_MATCH /* Pattern matching filter */ -} wl_pkt_filter_type_t; - -#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t /* Pattern matching filter. Specifies an offset within received packets to * start matching, the pattern to match, the size of the pattern, and a bitmask @@ -1969,20 +1666,6 @@ typedef struct wl_pkt_filter_enable { u32 enable; /* Enable/disable bool */ } wl_pkt_filter_enable_t; -/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ -typedef struct wl_pkt_filter_list { - u32 num; /* Number of installed packet filters */ - wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ -} wl_pkt_filter_list_t; - -#define WL_PKT_FILTER_LIST_FIXED_LEN offsetof(wl_pkt_filter_list_t, filter) - -/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ -typedef struct wl_pkt_filter_stats { - u32 num_pkts_matched; /* # filter matches for specified filter id */ - u32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ - u32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ -} wl_pkt_filter_stats_t; #define WLC_RSSI_INVALID 0 /* invalid RSSI value */ -- cgit v1.2.3 From 2578f7edf895fd4aad278134452cde1dc1b2fef5 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Sat, 30 Oct 2010 00:10:29 +0200 Subject: Staging: brcm80211: simplify expression Simplify: ((a && b) || !a) => (b || !a) Signed-off-by: Nicolas Kaiser Cc: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index e7a4bcb1c65a..f3e8e3c24276 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -669,7 +669,7 @@ bool wlc_ps_check(wlc_info_t *wlc) * may be either true or false due to the low level override. */ wake = STAY_AWAKE(wlc); - wake_ok = (wake && ((tmp & MCTL_WAKE) != 0)) || !wake; + wake_ok = ((tmp & MCTL_WAKE) != 0) || !wake; #endif if (hps && !wake_ok) { WL_ERROR(("wl%d: wake not sync, sw %d maccontrol 0x%x\n", wlc->pub->unit, wake, tmp)); -- cgit v1.2.3 From df0d8bb8daa1e8c3c2afcf93c46ef0294c78ac26 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Wed, 3 Nov 2010 19:53:58 -0700 Subject: staging: brcm80211: Remove 'failed' field from osh Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/util/linux_osl.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 3255b31b88eb..d6cca69814cf 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -39,7 +39,6 @@ struct osl_info { osl_pubinfo_t pub; uint magic; void *pdev; - uint failed; uint bustype; }; @@ -56,7 +55,6 @@ osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) bzero(osh, sizeof(osl_t)); osh->magic = OS_HANDLE_MAGIC; - osh->failed = 0; osh->pdev = pdev; osh->pub.pkttag = pkttag; osh->bustype = bustype; -- cgit v1.2.3 From 997dd24fe9aadf6e0b3652580e7c79372ccb600c Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Wed, 3 Nov 2010 19:53:59 -0700 Subject: staging: brcm80211: Remove pkttag from osl Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 6 +++--- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 2 +- drivers/staging/brcm80211/include/linux_osl.h | 10 +--------- drivers/staging/brcm80211/include/osl.h | 2 -- drivers/staging/brcm80211/sys/wl_mac80211.c | 3 +-- drivers/staging/brcm80211/sys/wlc_pub.h | 4 ---- drivers/staging/brcm80211/util/linux_osl.c | 10 +--------- 7 files changed, 7 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index 59eaf71040b2..be33696b8f74 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -188,7 +188,7 @@ int bcmsdh_probe(struct device *dev) } #endif /* defined(OOB_INTR_ONLY) */ /* allocate SDIO Host Controller state info */ - osh = osl_attach(dev, PCI_BUS, false); + osh = osl_attach(dev, PCI_BUS); if (!osh) { SDLX_MSG(("%s: osl_attach failed\n", __func__)); goto err; @@ -384,7 +384,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __func__)); - osh = osl_attach(pdev, PCI_BUS, false); + osh = osl_attach(pdev, PCI_BUS); if (!osh) { SDLX_MSG(("%s: osl_attach failed\n", __func__)); goto err; @@ -419,7 +419,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ /* allocate SDIO Host Controller state info */ - osh = osl_attach(pdev, PCI_BUS, false); + osh = osl_attach(pdev, PCI_BUS); if (!osh) { SDLX_MSG(("%s: osl_attach failed\n", __func__)); goto err; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index ba6fdc6133db..794dc13cf1a5 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1865,7 +1865,7 @@ static int dhd_open(struct net_device *net) osl_t *dhd_osl_attach(void *pdev, uint bustype) { - return osl_attach(pdev, bustype, true); + return osl_attach(pdev, bustype); } void dhd_osl_detach(osl_t *osh) diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index c398f7908447..586e652e75c7 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -18,7 +18,7 @@ #define _linux_osl_h_ -extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); +extern osl_t *osl_attach(void *pdev, uint bustype); extern void osl_detach(osl_t *osh); extern u32 g_assert_type; @@ -56,7 +56,6 @@ extern uint osl_pci_slot(osl_t *osh); /* Pkttag flag should be part of public information */ typedef struct { - bool pkttag; uint pktalloced; /* Number of allocated packet buffers */ bool mmbus; /* Bus supports memory-mapped register accesses */ pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ @@ -285,7 +284,6 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len)) #define PKTPUSH(skb, bytes) skb_push((struct sk_buff *)(skb), (bytes)) #define PKTPULL(skb, bytes) skb_pull((struct sk_buff *)(skb), (bytes)) -#define PKTTAG(skb) ((void *)(((struct sk_buff *)(skb))->cb)) #define PKTALLOCED(osh) (((osl_pubinfo_t *)(osh))->pktalloced) #define PKTSETPOOL(osh, skb, x, y) do {} while (0) #define PKTPOOL(osh, skb) false @@ -301,9 +299,6 @@ osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb) { struct sk_buff *nskb; - if (osh->pkttag) - bzero((void *)skb->cb, OSL_PKTTAG_SZ); - for (nskb = skb; nskb; nskb = nskb->next) osh->pktalloced++; @@ -317,9 +312,6 @@ osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt) { struct sk_buff *nskb; - if (osh->pkttag) - bzero(((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) osh->pktalloced--; diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index c0ebb3d97220..bcb56aa5dc96 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -21,8 +21,6 @@ typedef struct osl_info osl_t; typedef struct osl_dmainfo osldma_t; -#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ - /* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ typedef void (*pktfree_cb_fn_t) (void *ctx, void *pkt, unsigned int status); diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index d951d330a1c8..cb5dba95fc86 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -789,8 +789,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, return NULL; } - /* Requires pkttag feature */ - osh = osl_attach(btparam, bustype, true); + osh = osl_attach(btparam, bustype); ASSERT(osh); #ifdef WLC_HIGH_ONLY diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index a392436c4d45..f6ac5e99cf31 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -441,10 +441,6 @@ struct wlc_if; #define PROMISC_ENAB(wlc) ((wlc)->promisc) -extern void wlc_pkttag_info_move(wlc_pub_t *pub, void *pkt_from, void *pkt_to); - -#define WLPKTTAGSCB(p) (WLPKTTAG(p)->_scb) - #define WLC_PREC_COUNT 16 /* Max precedence level implemented */ /* pri is PKTPRIO encoded in the packet. This maps the Packet priority to diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index d6cca69814cf..7211f8a383ff 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -45,7 +45,7 @@ struct osl_info { /* Global ASSERT type flag */ u32 g_assert_type; -osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) +osl_t *osl_attach(void *pdev, uint bustype) { osl_t *osh; @@ -56,7 +56,6 @@ osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) osh->magic = OS_HANDLE_MAGIC; osh->pdev = pdev; - osh->pub.pkttag = pkttag; osh->bustype = bustype; switch (bustype) { @@ -77,12 +76,6 @@ osl_t *osl_attach(void *pdev, uint bustype, bool pkttag) break; } -#if defined(BCMDBG) && !defined(BRCM_FULLMAC) - if (pkttag) { - struct sk_buff *skb; - ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb)); - } -#endif return osh; } @@ -95,7 +88,6 @@ void osl_detach(osl_t *osh) kfree(osh); } -/* Return a new packet. zero out pkttag */ void *BCMFASTPATH osl_pktget(osl_t *osh, uint len) { struct sk_buff *skb; -- cgit v1.2.3 From 69ec303a99ff68cfb5dbc6cefb043e53b6ba8945 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 5 Nov 2010 19:20:16 -0700 Subject: staging: brcm80211: migrate #includes from headers into .c files. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_alloc.c | 2 ++ drivers/staging/brcm80211/sys/wlc_ampdu.c | 2 ++ drivers/staging/brcm80211/sys/wlc_antsel.c | 1 + drivers/staging/brcm80211/sys/wlc_bmac.c | 2 ++ drivers/staging/brcm80211/sys/wlc_channel.c | 2 ++ drivers/staging/brcm80211/sys/wlc_event.c | 1 + drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 ++ drivers/staging/brcm80211/sys/wlc_mac80211.h | 6 ------ drivers/staging/brcm80211/sys/wlc_phy_shim.c | 2 ++ drivers/staging/brcm80211/sys/wlc_stf.c | 2 ++ 10 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 8240d4ba962e..8001dca44918 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -27,8 +27,10 @@ #include #include #include +#include #include #include +#include static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid); diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 5a3acf852efa..0bd7069dc331 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #ifdef WLC_HIGH_ONLY #include diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index 3a1c1e9e7131..ecc35de77004 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index a92a68fb4604..fc5201d5171a 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -51,6 +51,7 @@ * At some point we may be able to skip the include of wlc.h and instead just * define a stub wlc_info and band struct to allow rpc calls to get the rpc handle. */ +#include #include #include #include @@ -72,6 +73,7 @@ #include #include +#include #define TIMER_INTERVAL_WATCHDOG_BMAC 1000 /* watchdog timer, in unit of ms */ diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index c7f416188093..2fcdbc72c837 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -28,10 +28,12 @@ #include #include #include +#include #include #include #include #include +#include typedef struct wlc_cm_band { u8 locale_flags; /* locale_info_t flags */ diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c index 4b0a59896bec..e4ab077bf87f 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.c +++ b/drivers/staging/brcm80211/sys/wlc_event.c @@ -36,6 +36,7 @@ #ifdef MSGTRACE #include #endif +#include /* Local prototypes */ static void wlc_timer_cb(void *arg); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index f3e8e3c24276..a9fa48a14c5d 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,7 @@ #endif /* WLC_HIGH_ONLY */ #include #include +#include #ifdef WLC_HIGH_ONLY #undef R_REG diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 6a77591234b7..a3c6fb884990 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -17,19 +17,13 @@ #ifndef _wlc_h_ #define _wlc_h_ -#include - -#include #include -#include #include #include #ifdef WLC_SPLIT #include #endif - #include - #include #define MA_WINDOW_SZ 8 /* moving average window size */ diff --git a/drivers/staging/brcm80211/sys/wlc_phy_shim.c b/drivers/staging/brcm80211/sys/wlc_phy_shim.c index 900c505ced34..201ecdb319cd 100644 --- a/drivers/staging/brcm80211/sys/wlc_phy_shim.c +++ b/drivers/staging/brcm80211/sys/wlc_phy_shim.c @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -54,6 +55,7 @@ #include #include #include +#include /* PHY SHIM module specific state */ struct wlc_phy_shim_info { diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c index 7bf326fc015b..2bca0526b44c 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.c +++ b/drivers/staging/brcm80211/sys/wlc_stf.c @@ -33,11 +33,13 @@ #include #include #include +#include #include #include #include #include #include +#include #define WLC_STF_SS_STBC_RX(wlc) (WLCISNPHY(wlc->band) && \ NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6)) -- cgit v1.2.3 From d4fcdc68564f49cbb4fdaf9b0ebfb5c3d02c81d3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 7 Nov 2010 17:20:37 +0000 Subject: Staging: brcmfmac: Fix MAC header lookup on 64-bit architectures Fix direct use of sk_buff::mac_header which is an offset rather than a pointer on 64-bit architectures. Signed-off-by: Ben Hutchings Cc: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 794dc13cf1a5..d7ad3e44dd78 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1189,7 +1189,7 @@ void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) /* Process special event packets and then discard them */ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) dhd_wl_host_event(dhd, &ifidx, - skb->mac_header, + skb_mac_header(skb), &event, &data); ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); -- cgit v1.2.3 From 3b785a8cfc6ac1bc837b0a1424056b6a4a1e544e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:10:02 +0100 Subject: Staging: brcm80211: Remove unnecessary casts of void ptr returning alloc function return values The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/staging/brcm80211/ Signed-off-by: Jesper Juhl Cc: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 23 +++++++++++------------ drivers/staging/brcm80211/brcmfmac/wl_iw.c | 7 ++----- 2 files changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index 21fe38fa736e..6433a9241b4e 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -704,7 +704,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action) if (ssid && ssid->SSID_len) params_size += sizeof(struct wlc_ssid); - params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); + params = kzalloc(params_size, GFP_KERNEL); if (unlikely(!params)) return -ENOMEM; memset(params, 0, params_size); @@ -2793,53 +2793,52 @@ static void wl_init_eloop_handler(struct wl_event_loop *el) static s32 wl_init_priv_mem(struct wl_priv *wl) { - wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); + wl->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); if (unlikely(!wl->scan_results)) { WL_ERR(("Scan results alloc failed\n")); goto init_priv_mem_out; } - wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL); + wl->conf = kzalloc(sizeof(*wl->conf), GFP_KERNEL); if (unlikely(!wl->conf)) { WL_ERR(("wl_conf alloc failed\n")); goto init_priv_mem_out; } - wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL); + wl->profile = kzalloc(sizeof(*wl->profile), GFP_KERNEL); if (unlikely(!wl->profile)) { WL_ERR(("wl_profile alloc failed\n")); goto init_priv_mem_out; } - wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + wl->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); if (unlikely(!wl->bss_info)) { WL_ERR(("Bss information alloc failed\n")); goto init_priv_mem_out; } - wl->scan_req_int = - (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); + wl->scan_req_int = kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); if (unlikely(!wl->scan_req_int)) { WL_ERR(("Scan req alloc failed\n")); goto init_priv_mem_out; } - wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); + wl->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); if (unlikely(!wl->ioctl_buf)) { WL_ERR(("Ioctl buf alloc failed\n")); goto init_priv_mem_out; } - wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + wl->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (unlikely(!wl->extra_buf)) { WL_ERR(("Extra buf alloc failed\n")); goto init_priv_mem_out; } - wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL); + wl->iscan = kzalloc(sizeof(*wl->iscan), GFP_KERNEL); if (unlikely(!wl->iscan)) { WL_ERR(("Iscan buf alloc failed\n")); goto init_priv_mem_out; } - wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL); + wl->fw = kzalloc(sizeof(*wl->fw), GFP_KERNEL); if (unlikely(!wl->fw)) { WL_ERR(("fw object alloc failed\n")); goto init_priv_mem_out; } - wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); + wl->pmk_list = kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); if (unlikely(!wl->pmk_list)) { WL_ERR(("pmk list alloc failed\n")); goto init_priv_mem_out; diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index 3e053fe56c79..d583b9d65d35 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -3690,8 +3690,7 @@ int wl_iw_attach(struct net_device *dev, void *dhdp) return -ENOMEM; memset(iscan, 0, sizeof(iscan_info_t)); - iscan->iscan_ex_params_p = - (wl_iscan_params_t *) kmalloc(params_size, GFP_KERNEL); + iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL); if (!iscan->iscan_ex_params_p) return -ENOMEM; iscan->iscan_ex_param_size = params_size; @@ -3723,9 +3722,7 @@ int wl_iw_attach(struct net_device *dev, void *dhdp) priv_dev = dev; MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub); #endif - g_scan = NULL; - - g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL); + g_scan = kmalloc(G_SCAN_RESULTS, GFP_KERNEL); if (!g_scan) return -ENOMEM; -- cgit v1.2.3 From 61a4295b492f96878b4b47d577a173568530ecff Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 27 Oct 2010 21:43:46 -0400 Subject: staging: iio: adis16350: add missing reference to temp offset We declare this attr but never link it in to the attr list. Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16350_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16350_core.c b/drivers/staging/iio/imu/adis16350_core.c index 97c1ec8594ce..cf7176bc766b 100644 --- a/drivers/staging/iio/imu/adis16350_core.c +++ b/drivers/staging/iio/imu/adis16350_core.c @@ -570,6 +570,7 @@ static struct attribute *adis16350_attributes[] = { &iio_dev_attr_temp_y_raw.dev_attr.attr, &iio_dev_attr_temp_z_raw.dev_attr.attr, &iio_const_attr_temp_scale.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, &iio_dev_attr_in1_raw.dev_attr.attr, &iio_const_attr_in1_scale.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, -- cgit v1.2.3 From f733d02ab61787239d1ca05c30f6f393275a7899 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 27 Oct 2010 21:43:47 -0400 Subject: staging: iio: gyro: make sure grep can find the ADIS16265 support Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/Kconfig | 7 +++++-- drivers/staging/iio/gyro/adis16260_core.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index c4043610c0df..d1dde82dbc9e 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -4,10 +4,13 @@ comment "Digital gyroscope sensors" config ADIS16260 - tristate "Analog Devices ADIS16260/5 Digital Gyroscope Sensor SPI driver" + tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver" depends on SPI select IIO_TRIGGER if IIO_RING_BUFFER select IIO_SW_RING if IIO_RING_BUFFER help - Say yes here to build support for Analog Devices adis16260/5 + Say yes here to build support for Analog Devices ADIS16260 ADIS16265 programmable digital gyroscope sensor. + + This driver can also be built as a module. If so, the module + will be called adis16260. diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 7d7716e5857c..8190c0fe0bea 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -1,5 +1,5 @@ /* - * ADIS16260 Programmable Digital Gyroscope Sensor Driver + * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver * * Copyright 2010 Analog Devices Inc. * -- cgit v1.2.3 From 6f125f17945a65e0bed37a4dfd7e5397a2c7a886 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 27 Oct 2010 21:43:48 -0400 Subject: staging: iio: add ADI info to TODO Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/TODO | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index 898cba1c939f..d1ad35e24abb 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -61,6 +61,10 @@ necessitate a header that is also visible from arch board files. (avoided at the moment to keep the driver set contained in staging). +ADI Drivers: +CC the device-drivers-devel@blackfin.uclinux.org mailing list when +e-mailing the normal IIO list (see below). + Documentation 1) Lots of cleanup and expansion. 2) Some device require indvidual docs. -- cgit v1.2.3 From f7fe1d1dd5a512a44f0ada40ff7f120664e2e082 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:43:49 -0400 Subject: staging: iio: new adis16201 driver IIO driver for dual Axis Accelerometer/inclinometer adis16201 parts. Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/accel/Kconfig | 9 + drivers/staging/iio/accel/Makefile | 4 + drivers/staging/iio/accel/adis16201.h | 150 ++++++ drivers/staging/iio/accel/adis16201_core.c | 659 ++++++++++++++++++++++++++ drivers/staging/iio/accel/adis16201_ring.c | 218 +++++++++ drivers/staging/iio/accel/adis16201_trigger.c | 122 +++++ 6 files changed, 1162 insertions(+) create mode 100644 drivers/staging/iio/accel/adis16201.h create mode 100644 drivers/staging/iio/accel/adis16201_core.c create mode 100644 drivers/staging/iio/accel/adis16201_ring.c create mode 100644 drivers/staging/iio/accel/adis16201_trigger.c (limited to 'drivers') diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 5926c03be1a5..0b87557a554e 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -3,6 +3,15 @@ # comment "Accelerometers" +config ADIS16201 + tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" + depends on SPI + select IIO_TRIGGER if IIO_RING_BUFFER + select IIO_SW_RING if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices adis16201 dual-axis + digital inclinometer and accelerometer. + config ADIS16209 tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" depends on SPI diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index ff84703a16f6..4a22a013cff8 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -2,6 +2,10 @@ # Makefile for industrial I/O accelerometer drivers # +adis16201-y := adis16201_core.o +adis16201-$(CONFIG_IIO_RING_BUFFER) += adis16201_ring.o adis16201_trigger.o +obj-$(CONFIG_ADIS16201) += adis16201.o + adis16209-y := adis16209_core.o adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o obj-$(CONFIG_ADIS16209) += adis16209.o diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h new file mode 100644 index 000000000000..c9bf22c13428 --- /dev/null +++ b/drivers/staging/iio/accel/adis16201.h @@ -0,0 +1,150 @@ +#ifndef SPI_ADIS16201_H_ +#define SPI_ADIS16201_H_ + +#define ADIS16201_STARTUP_DELAY 220 /* ms */ + +#define ADIS16201_READ_REG(a) a +#define ADIS16201_WRITE_REG(a) ((a) | 0x80) + +#define ADIS16201_FLASH_CNT 0x00 /* Flash memory write count */ +#define ADIS16201_SUPPLY_OUT 0x02 /* Output, power supply */ +#define ADIS16201_XACCL_OUT 0x04 /* Output, x-axis accelerometer */ +#define ADIS16201_YACCL_OUT 0x06 /* Output, y-axis accelerometer */ +#define ADIS16201_AUX_ADC 0x08 /* Output, auxiliary ADC input */ +#define ADIS16201_TEMP_OUT 0x0A /* Output, temperature */ +#define ADIS16201_XINCL_OUT 0x0C /* Output, x-axis inclination */ +#define ADIS16201_YINCL_OUT 0x0E /* Output, y-axis inclination */ +#define ADIS16201_XACCL_OFFS 0x10 /* Calibration, x-axis acceleration offset */ +#define ADIS16201_YACCL_OFFS 0x12 /* Calibration, y-axis acceleration offset */ +#define ADIS16201_XACCL_SCALE 0x14 /* x-axis acceleration scale factor */ +#define ADIS16201_YACCL_SCALE 0x16 /* y-axis acceleration scale factor */ +#define ADIS16201_XINCL_OFFS 0x18 /* Calibration, x-axis inclination offset */ +#define ADIS16201_YINCL_OFFS 0x1A /* Calibration, y-axis inclination offset */ +#define ADIS16201_XINCL_SCALE 0x1C /* x-axis inclination scale factor */ +#define ADIS16201_YINCL_SCALE 0x1E /* y-axis inclination scale factor */ +#define ADIS16201_ALM_MAG1 0x20 /* Alarm 1 amplitude threshold */ +#define ADIS16201_ALM_MAG2 0x22 /* Alarm 2 amplitude threshold */ +#define ADIS16201_ALM_SMPL1 0x24 /* Alarm 1, sample period */ +#define ADIS16201_ALM_SMPL2 0x26 /* Alarm 2, sample period */ +#define ADIS16201_ALM_CTRL 0x28 /* Alarm control */ +#define ADIS16201_AUX_DAC 0x30 /* Auxiliary DAC data */ +#define ADIS16201_GPIO_CTRL 0x32 /* General-purpose digital input/output control */ +#define ADIS16201_MSC_CTRL 0x34 /* Miscellaneous control */ +#define ADIS16201_SMPL_PRD 0x36 /* Internal sample period (rate) control */ +#define ADIS16201_AVG_CNT 0x38 /* Operation, filter configuration */ +#define ADIS16201_SLP_CNT 0x3A /* Operation, sleep mode control */ +#define ADIS16201_DIAG_STAT 0x3C /* Diagnostics, system status register */ +#define ADIS16201_GLOB_CMD 0x3E /* Operation, system command register */ + +#define ADIS16201_OUTPUTS 7 + +/* MSC_CTRL */ +#define ADIS16201_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */ +#define ADIS16201_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16201_MSC_CTRL_ACTIVE_HIGH (1 << 1) /* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 (1 << 0) /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ + +/* DIAG_STAT */ +#define ADIS16201_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16201_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16201_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */ +#define ADIS16201_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */ +#define ADIS16201_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */ +#define ADIS16201_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 3.15 V */ + +/* GLOB_CMD */ +#define ADIS16201_GLOB_CMD_SW_RESET (1<<7) +#define ADIS16201_GLOB_CMD_FACTORY_CAL (1<<1) + +#define ADIS16201_MAX_TX 14 +#define ADIS16201_MAX_RX 14 + +#define ADIS16201_ERROR_ACTIVE (1<<14) + +/** + * struct adis16201_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16201_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; + +int adis16201_set_irq(struct device *dev, bool enable); + +#ifdef CONFIG_IIO_RING_BUFFER +enum adis16201_scan { + ADIS16201_SCAN_SUPPLY, + ADIS16201_SCAN_ACC_X, + ADIS16201_SCAN_ACC_Y, + ADIS16201_SCAN_AUX_ADC, + ADIS16201_SCAN_TEMP, + ADIS16201_SCAN_INCLI_X, + ADIS16201_SCAN_INCLI_Y, +}; + +void adis16201_remove_trigger(struct iio_dev *indio_dev); +int adis16201_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16201_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + +int adis16201_configure_ring(struct iio_dev *indio_dev); +void adis16201_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16201_initialize_ring(struct iio_ring_buffer *ring); +void adis16201_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16201_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16201_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16201_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16201_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16201_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16201_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16201_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16201_H_ */ diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c new file mode 100644 index 000000000000..79b785a0013a --- /dev/null +++ b/drivers/staging/iio/accel/adis16201_core.c @@ -0,0 +1,659 @@ +/* + * ADIS16201 Programmable Digital Vibration Sensor driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "accel.h" +#include "inclinometer.h" +#include "../gyro/gyro.h" +#include "../adc/adc.h" + +#include "adis16201.h" + +#define DRIVER_NAME "adis16201" + +static int adis16201_check_status(struct device *dev); + +/** + * adis16201_spi_write_reg_8() - write single byte to a register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the register to be written + * @val: the value to write + **/ +static int adis16201_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16201_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16201_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16201_spi_write_reg_16() - write 2 bytes to a pair of registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: value to be written + **/ +static int adis16201_spi_write_reg_16(struct device *dev, + u8 lower_reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16201_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, { + .tx_buf = st->tx + 2, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16201_WRITE_REG(lower_reg_address); + st->tx[1] = value & 0xFF; + st->tx[2] = ADIS16201_WRITE_REG(lower_reg_address + 1); + st->tx[3] = (value >> 8) & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16201_spi_read_reg_16() - read 2 bytes from a 16-bit register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: somewhere to pass back the value read + **/ +static int adis16201_spi_read_reg_16(struct device *dev, + u8 lower_reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16201_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + .delay_usecs = 20, + }, { + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + .delay_usecs = 20, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16201_READ_REG(lower_reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + lower_reg_address); + goto error_ret; + } + *val = (st->rx[0] << 8) | st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t adis16201_read_12bit_unsigned(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis16201_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + if (val & ADIS16201_ERROR_ACTIVE) { + ret = adis16201_check_status(dev); + if (ret) + return ret; + } + + return sprintf(buf, "%u\n", val & 0x0FFF); +} + +static ssize_t adis16201_read_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + ssize_t ret; + u16 val; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + + ret = adis16201_spi_read_reg_16(dev, ADIS16201_TEMP_OUT, (u16 *)&val); + if (ret) + goto error_ret; + + if (val & ADIS16201_ERROR_ACTIVE) { + ret = adis16201_check_status(dev); + if (ret) + goto error_ret; + } + + val &= 0xFFF; + ret = sprintf(buf, "%d\n", val); + +error_ret: + mutex_unlock(&indio_dev->mlock); + return ret; +} + +static ssize_t adis16201_read_9bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s16 val = 0; + ssize_t ret; + + mutex_lock(&indio_dev->mlock); + + ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (!ret) { + if (val & ADIS16201_ERROR_ACTIVE) { + ret = adis16201_check_status(dev); + if (ret) + goto error_ret; + } + val = ((s16)(val << 7) >> 7); + ret = sprintf(buf, "%d\n", val); + } + +error_ret: + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16201_read_12bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s16 val = 0; + ssize_t ret; + + mutex_lock(&indio_dev->mlock); + + ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (!ret) { + if (val & ADIS16201_ERROR_ACTIVE) { + ret = adis16201_check_status(dev); + if (ret) + goto error_ret; + } + + val = ((s16)(val << 4) >> 4); + ret = sprintf(buf, "%d\n", val); + } + +error_ret: + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16201_read_14bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s16 val = 0; + ssize_t ret; + + mutex_lock(&indio_dev->mlock); + + ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (!ret) { + if (val & ADIS16201_ERROR_ACTIVE) { + ret = adis16201_check_status(dev); + if (ret) + goto error_ret; + } + + val = ((s16)(val << 2) >> 2); + ret = sprintf(buf, "%d\n", val); + } + +error_ret: + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16201_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = adis16201_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int adis16201_reset(struct device *dev) +{ + int ret; + ret = adis16201_spi_write_reg_8(dev, + ADIS16201_GLOB_CMD, + ADIS16201_GLOB_CMD_SW_RESET); + if (ret) + dev_err(dev, "problem resetting device"); + + return ret; +} + +static ssize_t adis16201_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -EINVAL; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return adis16201_reset(dev); + } + return -EINVAL; +} + +int adis16201_set_irq(struct device *dev, bool enable) +{ + int ret = 0; + u16 msc; + + ret = adis16201_spi_read_reg_16(dev, ADIS16201_MSC_CTRL, &msc); + if (ret) + goto error_ret; + + msc |= ADIS16201_MSC_CTRL_ACTIVE_HIGH; + msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_DIO1; + if (enable) + msc |= ADIS16201_MSC_CTRL_DATA_RDY_EN; + else + msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_EN; + + ret = adis16201_spi_write_reg_16(dev, ADIS16201_MSC_CTRL, msc); + +error_ret: + return ret; +} + +static int adis16201_check_status(struct device *dev) +{ + u16 status; + int ret; + + ret = adis16201_spi_read_reg_16(dev, ADIS16201_DIAG_STAT, &status); + if (ret < 0) { + dev_err(dev, "Reading status failed\n"); + goto error_ret; + } + ret = status & 0xF; + if (ret) + ret = -EFAULT; + + if (status & ADIS16201_DIAG_STAT_SPI_FAIL) + dev_err(dev, "SPI failure\n"); + if (status & ADIS16201_DIAG_STAT_FLASH_UPT) + dev_err(dev, "Flash update failed\n"); + if (status & ADIS16201_DIAG_STAT_POWER_HIGH) + dev_err(dev, "Power supply above 3.625V\n"); + if (status & ADIS16201_DIAG_STAT_POWER_LOW) + dev_err(dev, "Power supply below 3.15V\n"); + +error_ret: + return ret; +} + +static int adis16201_self_test(struct device *dev) +{ + int ret; + ret = adis16201_spi_write_reg_16(dev, + ADIS16201_MSC_CTRL, + ADIS16201_MSC_CTRL_SELF_TEST_EN); + if (ret) { + dev_err(dev, "problem starting self test"); + goto err_ret; + } + + ret = adis16201_check_status(dev); + +err_ret: + return ret; +} + +static int adis16201_initial_setup(struct adis16201_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* Disable IRQ */ + ret = adis16201_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + /* Do self test */ + ret = adis16201_self_test(dev); + if (ret) { + dev_err(dev, "self test failure"); + goto err_ret; + } + + /* Read status register to check the result */ + ret = adis16201_check_status(dev); + if (ret) { + adis16201_reset(dev); + dev_err(dev, "device not playing ball -> reset"); + msleep(ADIS16201_STARTUP_DELAY); + ret = adis16201_check_status(dev); + if (ret) { + dev_err(dev, "giving up"); + goto err_ret; + } + } + + printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n", + st->us->chip_select, st->us->irq); + +err_ret: + return ret; +} + +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16201_read_12bit_unsigned, + ADIS16201_SUPPLY_OUT); +static IIO_CONST_ATTR(in0_supply_scale, "0.00122"); +static IIO_DEV_ATTR_IN_RAW(1, adis16201_read_12bit_unsigned, + ADIS16201_AUX_ADC); +static IIO_CONST_ATTR(in1_scale, "0.00061"); + +static IIO_DEV_ATTR_ACCEL_X(adis16201_read_14bit_signed, + ADIS16201_XACCL_OUT); +static IIO_DEV_ATTR_ACCEL_Y(adis16201_read_14bit_signed, + ADIS16201_YACCL_OUT); +static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, + adis16201_read_12bit_signed, + adis16201_write_16bit, + ADIS16201_XACCL_OFFS); +static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, + adis16201_read_12bit_signed, + adis16201_write_16bit, + ADIS16201_YACCL_OFFS); +static IIO_CONST_ATTR(accel_scale, "0.4625"); + +static IIO_DEV_ATTR_INCLI_X(adis16201_read_14bit_signed, + ADIS16201_XINCL_OUT); +static IIO_DEV_ATTR_INCLI_Y(adis16201_read_14bit_signed, + ADIS16201_YINCL_OUT); +static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO, + adis16201_read_9bit_signed, + adis16201_write_16bit, + ADIS16201_XACCL_OFFS); +static IIO_DEV_ATTR_INCLI_Y_OFFSET(S_IWUSR | S_IRUGO, + adis16201_read_9bit_signed, + adis16201_write_16bit, + ADIS16201_YACCL_OFFS); +static IIO_CONST_ATTR(incli_scale, "0.1"); + +static IIO_DEV_ATTR_TEMP_RAW(adis16201_read_temp); +static IIO_CONST_ATTR(temp_offset, "25"); +static IIO_CONST_ATTR(temp_scale, "-0.47"); + +static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16201_write_reset, 0); + +static IIO_CONST_ATTR(name, "adis16201"); + +static struct attribute *adis16201_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16201_event_attribute_group = { + .attrs = adis16201_event_attributes, +}; + +static struct attribute *adis16201_attributes[] = { + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, + &iio_dev_attr_accel_x_raw.dev_attr.attr, + &iio_dev_attr_accel_y_raw.dev_attr.attr, + &iio_dev_attr_accel_x_offset.dev_attr.attr, + &iio_dev_attr_accel_y_offset.dev_attr.attr, + &iio_const_attr_accel_scale.dev_attr.attr, + &iio_dev_attr_incli_x_raw.dev_attr.attr, + &iio_dev_attr_incli_y_raw.dev_attr.attr, + &iio_dev_attr_incli_x_offset.dev_attr.attr, + &iio_dev_attr_incli_y_offset.dev_attr.attr, + &iio_const_attr_incli_scale.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16201_attribute_group = { + .attrs = adis16201_attributes, +}; + +static int __devinit adis16201_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16201_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16201_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16201_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16201_event_attribute_group; + st->indio_dev->attrs = &adis16201_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis16201_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16201_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16201"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16201_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = adis16201_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + adis16201_remove_trigger(st->indio_dev); +error_unregister_line: + if (spi->irq) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16201_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16201_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int adis16201_remove(struct spi_device *spi) +{ + struct adis16201_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + adis16201_remove_trigger(indio_dev); + if (spi->irq) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16201_uninitialize_ring(indio_dev->ring); + iio_device_unregister(indio_dev); + adis16201_unconfigure_ring(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} + +static struct spi_driver adis16201_driver = { + .driver = { + .name = "adis16201", + .owner = THIS_MODULE, + }, + .probe = adis16201_probe, + .remove = __devexit_p(adis16201_remove), +}; + +static __init int adis16201_init(void) +{ + return spi_register_driver(&adis16201_driver); +} +module_init(adis16201_init); + +static __exit void adis16201_exit(void) +{ + spi_unregister_driver(&adis16201_driver); +} +module_exit(adis16201_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16201 Programmable Digital Vibration Sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c new file mode 100644 index 000000000000..e6870a2721f1 --- /dev/null +++ b/drivers/staging/iio/accel/adis16201_ring.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_sw.h" +#include "accel.h" +#include "../trigger.h" +#include "adis16201.h" + +static IIO_SCAN_EL_C(in_supply, ADIS16201_SCAN_SUPPLY, ADIS16201_SUPPLY_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16); +static IIO_SCAN_EL_C(accel_x, ADIS16201_SCAN_ACC_X, ADIS16201_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16201_SCAN_ACC_Y, ADIS16201_YACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16); +static IIO_SCAN_EL_C(in0, ADIS16201_SCAN_AUX_ADC, ADIS16201_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16); +static IIO_SCAN_EL_C(temp, ADIS16201_SCAN_TEMP, ADIS16201_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16); +static IIO_SCAN_EL_C(incli_x, ADIS16201_SCAN_INCLI_X, + ADIS16201_XINCL_OUT, NULL); +static IIO_SCAN_EL_C(incli_y, ADIS16201_SCAN_INCLI_Y, + ADIS16201_YINCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16); +static IIO_SCAN_EL_TIMESTAMP(7); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); + +static struct attribute *adis16201_scan_el_attrs[] = { + &iio_scan_el_in_supply.dev_attr.attr, + &iio_const_attr_in_supply_index.dev_attr.attr, + &iio_const_attr_in_supply_type.dev_attr.attr, + &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, + &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_const_attr_in0_type.dev_attr.attr, + &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, + &iio_scan_el_incli_x.dev_attr.attr, + &iio_const_attr_incli_x_index.dev_attr.attr, + &iio_scan_el_incli_y.dev_attr.attr, + &iio_const_attr_incli_y_index.dev_attr.attr, + &iio_const_attr_incli_type.dev_attr.attr, + &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group adis16201_scan_el_group = { + .attrs = adis16201_scan_el_attrs, + .name = "scan_elements", +}; + +/** + * adis16201_poll_func_th() top half interrupt handler called by trigger + * @private_data: iio_dev + **/ +static void adis16201_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct adis16201_state *st = iio_dev_get_devdata(indio_dev); + st->last_timestamp = time; + schedule_work(&st->work_trigger_to_ring); +} + +/** + * adis16201_read_ring_data() read data registers which will be placed into ring + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read + **/ +static int adis16201_read_ring_data(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16201_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[ADIS16201_OUTPUTS + 1]; + int ret; + int i; + + mutex_lock(&st->buf_lock); + + spi_message_init(&msg); + + memset(xfers, 0, sizeof(xfers)); + for (i = 0; i <= ADIS16201_OUTPUTS; i++) { + xfers[i].bits_per_word = 8; + xfers[i].cs_change = 1; + xfers[i].len = 2; + xfers[i].delay_usecs = 20; + xfers[i].tx_buf = st->tx + 2 * i; + st->tx[2 * i] = ADIS16201_READ_REG(ADIS16201_SUPPLY_OUT + 2 * i); + st->tx[2 * i + 1] = 0; + if (i >= 1) + xfers[i].rx_buf = rx + 2 * (i - 1); + spi_message_add_tail(&xfers[i], &msg); + } + + ret = spi_sync(st->us, &msg); + if (ret) + dev_err(&st->us->dev, "problem when burst reading"); + + mutex_unlock(&st->buf_lock); + + return ret; +} + +/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device + * specific to be rolled into the core. + */ +static void adis16201_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct adis16201_state *st + = container_of(work_s, struct adis16201_state, + work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; + + int i = 0; + s16 *data; + size_t datasize = ring->access.get_bytes_per_datum(ring); + + data = kmalloc(datasize, GFP_KERNEL); + if (data == NULL) { + dev_err(&st->us->dev, "memory alloc failed in ring bh"); + return; + } + + if (ring->scan_count) + if (adis16201_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) + for (; i < ring->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (ring->scan_timestamp) + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; + + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} + +void adis16201_unconfigure_ring(struct iio_dev *indio_dev) +{ + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} + +int adis16201_configure_ring(struct iio_dev *indio_dev) +{ + int ret = 0; + struct adis16201_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring; + INIT_WORK(&st->work_trigger_to_ring, adis16201_trigger_bh_to_ring); + + ring = iio_sw_rb_allocate(indio_dev); + if (!ring) { + ret = -ENOMEM; + return ret; + } + indio_dev->ring = ring; + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&ring->access); + ring->bpe = 2; + ring->scan_el_attrs = &adis16201_scan_el_group; + ring->scan_timestamp = true; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; + ring->owner = THIS_MODULE; + + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in_supply.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in0.number); + iio_scan_mask_set(ring, iio_scan_el_incli_x.number); + iio_scan_mask_set(ring, iio_scan_el_incli_y.number); + + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16201_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; + +error_iio_sw_rb_free: + iio_sw_rb_free(indio_dev->ring); + return ret; +} + +int adis16201_initialize_ring(struct iio_ring_buffer *ring) +{ + return iio_ring_buffer_register(ring, 0); +} + +void adis16201_uninitialize_ring(struct iio_ring_buffer *ring) +{ + iio_ring_buffer_unregister(ring); +} diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c new file mode 100644 index 000000000000..8a9cea1986e7 --- /dev/null +++ b/drivers/staging/iio/accel/adis16201_trigger.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../trigger.h" +#include "adis16201.h" + +/** + * adis16201_data_rdy_trig_poll() the event handler for the data rdy trig + **/ +static int adis16201_data_rdy_trig_poll(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adis16201_state *st = iio_dev_get_devdata(dev_info); + struct iio_trigger *trig = st->trig; + + iio_trigger_poll(trig, timestamp); + + return IRQ_HANDLED; +} + +IIO_EVENT_SH(data_rdy_trig, &adis16201_data_rdy_trig_poll); + +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static struct attribute *adis16201_trigger_attrs[] = { + &dev_attr_name.attr, + NULL, +}; + +static const struct attribute_group adis16201_trigger_attr_group = { + .attrs = adis16201_trigger_attrs, +}; + +/** + * adis16201_data_rdy_trigger_set_state() set datardy interrupt state + **/ +static int adis16201_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct adis16201_state *st = trig->private_data; + struct iio_dev *indio_dev = st->indio_dev; + int ret = 0; + + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); + ret = adis16201_set_irq(&st->indio_dev->dev, state); + if (state == false) { + iio_remove_event_from_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0] + ->ev_list); + flush_scheduled_work(); + } else { + iio_add_event_to_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0]->ev_list); + } + return ret; +} + +/** + * adis16201_trig_try_reen() try renabling irq for data rdy trigger + * @trig: the datardy trigger + **/ +static int adis16201_trig_try_reen(struct iio_trigger *trig) +{ + struct adis16201_state *st = trig->private_data; + enable_irq(st->us->irq); + return 0; +} + +int adis16201_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct adis16201_state *st = indio_dev->dev_data; + + st->trig = iio_allocate_trigger(); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16201-dev%d", + indio_dev->id); + if (!st->trig->name) { + ret = -ENOMEM; + goto error_free_trig; + } + st->trig->dev.parent = &st->us->dev; + st->trig->owner = THIS_MODULE; + st->trig->private_data = st; + st->trig->set_trigger_state = &adis16201_data_rdy_trigger_set_state; + st->trig->try_reenable = &adis16201_trig_try_reen; + st->trig->control_attrs = &adis16201_trigger_attr_group; + ret = iio_trigger_register(st->trig); + + /* select default trigger */ + indio_dev->trig = st->trig; + if (ret) + goto error_free_trig_name; + + return 0; + +error_free_trig_name: + kfree(st->trig->name); +error_free_trig: + iio_free_trigger(st->trig); + + return ret; +} + +void adis16201_remove_trigger(struct iio_dev *indio_dev) +{ + struct adis16201_state *state = indio_dev->dev_data; + + iio_trigger_unregister(state->trig); + kfree(state->trig->name); + iio_free_trigger(state->trig); +} -- cgit v1.2.3 From f11ba4f5774957415aa15eea7c8c8717126907ee Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:43:50 -0400 Subject: staging: iio: new adis16203 driver IIO driver for Programmable 360 Degrees Inclinometer adis16203 parts. Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/accel/Kconfig | 9 + drivers/staging/iio/accel/Makefile | 4 + drivers/staging/iio/accel/adis16203.h | 143 +++++++ drivers/staging/iio/accel/adis16203_core.c | 568 ++++++++++++++++++++++++++ drivers/staging/iio/accel/adis16203_ring.c | 211 ++++++++++ drivers/staging/iio/accel/adis16203_trigger.c | 122 ++++++ 6 files changed, 1057 insertions(+) create mode 100644 drivers/staging/iio/accel/adis16203.h create mode 100644 drivers/staging/iio/accel/adis16203_core.c create mode 100644 drivers/staging/iio/accel/adis16203_ring.c create mode 100644 drivers/staging/iio/accel/adis16203_trigger.c (limited to 'drivers') diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 0b87557a554e..cc057c640e64 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -12,6 +12,15 @@ config ADIS16201 Say yes here to build support for Analog Devices adis16201 dual-axis digital inclinometer and accelerometer. +config ADIS16203 + tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer" + depends on SPI + select IIO_TRIGGER if IIO_RING_BUFFER + select IIO_SW_RING if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices adis16203 Programmable + 360 Degrees Inclinometer. + config ADIS16209 tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" depends on SPI diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 4a22a013cff8..76cc92fed23d 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -6,6 +6,10 @@ adis16201-y := adis16201_core.o adis16201-$(CONFIG_IIO_RING_BUFFER) += adis16201_ring.o adis16201_trigger.o obj-$(CONFIG_ADIS16201) += adis16201.o +adis16203-y := adis16203_core.o +adis16203-$(CONFIG_IIO_RING_BUFFER) += adis16203_ring.o adis16203_trigger.o +obj-$(CONFIG_ADIS16203) += adis16203.o + adis16209-y := adis16209_core.o adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o obj-$(CONFIG_ADIS16209) += adis16209.o diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h new file mode 100644 index 000000000000..b39323eac9e3 --- /dev/null +++ b/drivers/staging/iio/accel/adis16203.h @@ -0,0 +1,143 @@ +#ifndef SPI_ADIS16203_H_ +#define SPI_ADIS16203_H_ + +#define ADIS16203_STARTUP_DELAY 220 /* ms */ + +#define ADIS16203_READ_REG(a) a +#define ADIS16203_WRITE_REG(a) ((a) | 0x80) + +#define ADIS16203_FLASH_CNT 0x00 /* Flash memory write count */ +#define ADIS16203_SUPPLY_OUT 0x02 /* Output, power supply */ +#define ADIS16203_AUX_ADC 0x08 /* Output, auxiliary ADC input */ +#define ADIS16203_TEMP_OUT 0x0A /* Output, temperature */ +#define ADIS16203_XINCL_OUT 0x0C /* Output, x-axis inclination */ +#define ADIS16203_YINCL_OUT 0x0E /* Output, y-axis inclination */ +#define ADIS16203_INCL_NULL 0x18 /* Incline null calibration */ +#define ADIS16203_ALM_MAG1 0x20 /* Alarm 1 amplitude threshold */ +#define ADIS16203_ALM_MAG2 0x22 /* Alarm 2 amplitude threshold */ +#define ADIS16203_ALM_SMPL1 0x24 /* Alarm 1, sample period */ +#define ADIS16203_ALM_SMPL2 0x26 /* Alarm 2, sample period */ +#define ADIS16203_ALM_CTRL 0x28 /* Alarm control */ +#define ADIS16203_AUX_DAC 0x30 /* Auxiliary DAC data */ +#define ADIS16203_GPIO_CTRL 0x32 /* General-purpose digital input/output control */ +#define ADIS16203_MSC_CTRL 0x34 /* Miscellaneous control */ +#define ADIS16203_SMPL_PRD 0x36 /* Internal sample period (rate) control */ +#define ADIS16203_AVG_CNT 0x38 /* Operation, filter configuration */ +#define ADIS16203_SLP_CNT 0x3A /* Operation, sleep mode control */ +#define ADIS16203_DIAG_STAT 0x3C /* Diagnostics, system status register */ +#define ADIS16203_GLOB_CMD 0x3E /* Operation, system command register */ + +#define ADIS16203_OUTPUTS 5 + +/* MSC_CTRL */ +#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */ +#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN (1 << 9) /* Reverses rotation of both inclination outputs */ +#define ADIS16203_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */ +#define ADIS16203_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16203_MSC_CTRL_ACTIVE_HIGH (1 << 1) /* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1 (1 << 0) /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ + +/* DIAG_STAT */ +#define ADIS16203_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16203_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16203_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag */ +#define ADIS16203_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */ +#define ADIS16203_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */ +#define ADIS16203_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */ +#define ADIS16203_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 3.15 V */ + +/* GLOB_CMD */ +#define ADIS16203_GLOB_CMD_SW_RESET (1<<7) +#define ADIS16203_GLOB_CMD_CLEAR_STAT (1<<4) +#define ADIS16203_GLOB_CMD_FACTORY_CAL (1<<1) + +#define ADIS16203_MAX_TX 12 +#define ADIS16203_MAX_RX 10 + +#define ADIS16203_ERROR_ACTIVE (1<<14) + +/** + * struct adis16203_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16203_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; + +int adis16203_set_irq(struct device *dev, bool enable); + +#ifdef CONFIG_IIO_RING_BUFFER +enum adis16203_scan { + ADIS16203_SCAN_SUPPLY, + ADIS16203_SCAN_AUX_ADC, + ADIS16203_SCAN_TEMP, + ADIS16203_SCAN_INCLI_X, + ADIS16203_SCAN_INCLI_Y, +}; + +void adis16203_remove_trigger(struct iio_dev *indio_dev); +int adis16203_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16203_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + +int adis16203_configure_ring(struct iio_dev *indio_dev); +void adis16203_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16203_initialize_ring(struct iio_ring_buffer *ring); +void adis16203_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16203_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16203_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16203_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16203_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16203_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16203_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16203_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16203_H_ */ diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c new file mode 100644 index 000000000000..b57f19087a93 --- /dev/null +++ b/drivers/staging/iio/accel/adis16203_core.c @@ -0,0 +1,568 @@ +/* + * ADIS16203 Programmable Digital Vibration Sensor driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "accel.h" +#include "inclinometer.h" +#include "../gyro/gyro.h" +#include "../adc/adc.h" + +#include "adis16203.h" + +#define DRIVER_NAME "adis16203" + +static int adis16203_check_status(struct device *dev); + +/** + * adis16203_spi_write_reg_8() - write single byte to a register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the register to be written + * @val: the value to write + **/ +static int adis16203_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16203_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16203_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16203_spi_write_reg_16() - write 2 bytes to a pair of registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: value to be written + **/ +static int adis16203_spi_write_reg_16(struct device *dev, + u8 lower_reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16203_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, { + .tx_buf = st->tx + 2, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16203_WRITE_REG(lower_reg_address); + st->tx[1] = value & 0xFF; + st->tx[2] = ADIS16203_WRITE_REG(lower_reg_address + 1); + st->tx[3] = (value >> 8) & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16203_spi_read_reg_16() - read 2 bytes from a 16-bit register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: somewhere to pass back the value read + **/ +static int adis16203_spi_read_reg_16(struct device *dev, + u8 lower_reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16203_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + .delay_usecs = 20, + }, { + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + .delay_usecs = 20, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16203_READ_REG(lower_reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + lower_reg_address); + goto error_ret; + } + *val = (st->rx[0] << 8) | st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t adis16203_read_12bit_unsigned(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis16203_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + if (val & ADIS16203_ERROR_ACTIVE) + adis16203_check_status(dev); + + return sprintf(buf, "%u\n", val & 0x0FFF); +} + +static ssize_t adis16203_read_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + ssize_t ret; + u16 val; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + + ret = adis16203_spi_read_reg_16(dev, ADIS16203_TEMP_OUT, (u16 *)&val); + if (ret) + goto error_ret; + + if (val & ADIS16203_ERROR_ACTIVE) + adis16203_check_status(dev); + + val &= 0xFFF; + ret = sprintf(buf, "%d\n", val); + +error_ret: + mutex_unlock(&indio_dev->mlock); + return ret; +} + +static ssize_t adis16203_read_14bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s16 val = 0; + ssize_t ret; + + mutex_lock(&indio_dev->mlock); + + ret = adis16203_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (!ret) { + if (val & ADIS16203_ERROR_ACTIVE) + adis16203_check_status(dev); + + val = ((s16)(val << 2) >> 2); + ret = sprintf(buf, "%d\n", val); + } + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16203_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = adis16203_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int adis16203_reset(struct device *dev) +{ + int ret; + ret = adis16203_spi_write_reg_8(dev, + ADIS16203_GLOB_CMD, + ADIS16203_GLOB_CMD_SW_RESET); + if (ret) + dev_err(dev, "problem resetting device"); + + return ret; +} + +static ssize_t adis16203_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -EINVAL; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return adis16203_reset(dev); + } + return -EINVAL; +} + +int adis16203_set_irq(struct device *dev, bool enable) +{ + int ret = 0; + u16 msc; + + ret = adis16203_spi_read_reg_16(dev, ADIS16203_MSC_CTRL, &msc); + if (ret) + goto error_ret; + + msc |= ADIS16203_MSC_CTRL_ACTIVE_HIGH; + msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_DIO1; + if (enable) + msc |= ADIS16203_MSC_CTRL_DATA_RDY_EN; + else + msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_EN; + + ret = adis16203_spi_write_reg_16(dev, ADIS16203_MSC_CTRL, msc); + +error_ret: + return ret; +} + +static int adis16203_check_status(struct device *dev) +{ + u16 status; + int ret; + + ret = adis16203_spi_read_reg_16(dev, ADIS16203_DIAG_STAT, &status); + if (ret < 0) { + dev_err(dev, "Reading status failed\n"); + goto error_ret; + } + ret = status & 0x1F; + + if (status & ADIS16203_DIAG_STAT_SELFTEST_FAIL) + dev_err(dev, "Self test failure\n"); + if (status & ADIS16203_DIAG_STAT_SPI_FAIL) + dev_err(dev, "SPI failure\n"); + if (status & ADIS16203_DIAG_STAT_FLASH_UPT) + dev_err(dev, "Flash update failed\n"); + if (status & ADIS16203_DIAG_STAT_POWER_HIGH) + dev_err(dev, "Power supply above 3.625V\n"); + if (status & ADIS16203_DIAG_STAT_POWER_LOW) + dev_err(dev, "Power supply below 3.15V\n"); + +error_ret: + return ret; +} + +static int adis16203_self_test(struct device *dev) +{ + int ret; + ret = adis16203_spi_write_reg_16(dev, + ADIS16203_MSC_CTRL, + ADIS16203_MSC_CTRL_SELF_TEST_EN); + if (ret) { + dev_err(dev, "problem starting self test"); + goto err_ret; + } + + adis16203_check_status(dev); + +err_ret: + return ret; +} + +static int adis16203_initial_setup(struct adis16203_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* Disable IRQ */ + ret = adis16203_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + /* Do self test */ + ret = adis16203_self_test(dev); + if (ret) { + dev_err(dev, "self test failure"); + goto err_ret; + } + + /* Read status register to check the result */ + ret = adis16203_check_status(dev); + if (ret) { + adis16203_reset(dev); + dev_err(dev, "device not playing ball -> reset"); + msleep(ADIS16203_STARTUP_DELAY); + ret = adis16203_check_status(dev); + if (ret) { + dev_err(dev, "giving up"); + goto err_ret; + } + } + + printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n", + st->us->chip_select, st->us->irq); + +err_ret: + return ret; +} + +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16203_read_12bit_unsigned, + ADIS16203_SUPPLY_OUT); +static IIO_CONST_ATTR(in0_supply_scale, "0.00122"); +static IIO_DEV_ATTR_IN_RAW(1, adis16203_read_12bit_unsigned, + ADIS16203_AUX_ADC); +static IIO_CONST_ATTR(in1_scale, "0.00061"); + +static IIO_DEV_ATTR_INCLI_X(adis16203_read_14bit_signed, + ADIS16203_XINCL_OUT); +static IIO_DEV_ATTR_INCLI_Y(adis16203_read_14bit_signed, + ADIS16203_YINCL_OUT); +static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO, + adis16203_read_14bit_signed, + adis16203_write_16bit, + ADIS16203_INCL_NULL); +static IIO_CONST_ATTR(incli_scale, "0.025"); + +static IIO_DEV_ATTR_TEMP_RAW(adis16203_read_temp); +static IIO_CONST_ATTR(temp_offset, "25"); +static IIO_CONST_ATTR(temp_scale, "-0.47"); + +static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16203_write_reset, 0); + +static IIO_CONST_ATTR(name, "adis16203"); + +static struct attribute *adis16203_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16203_event_attribute_group = { + .attrs = adis16203_event_attributes, +}; + +static struct attribute *adis16203_attributes[] = { + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, + &iio_dev_attr_incli_x_raw.dev_attr.attr, + &iio_dev_attr_incli_y_raw.dev_attr.attr, + &iio_dev_attr_incli_x_offset.dev_attr.attr, + &iio_const_attr_incli_scale.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16203_attribute_group = { + .attrs = adis16203_attributes, +}; + +static int __devinit adis16203_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16203_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16203_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16203_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16203_event_attribute_group; + st->indio_dev->attrs = &adis16203_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis16203_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16203_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16203"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16203_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = adis16203_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + adis16203_remove_trigger(st->indio_dev); +error_unregister_line: + if (spi->irq) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16203_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16203_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int adis16203_remove(struct spi_device *spi) +{ + struct adis16203_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + adis16203_remove_trigger(indio_dev); + if (spi->irq) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16203_uninitialize_ring(indio_dev->ring); + iio_device_unregister(indio_dev); + adis16203_unconfigure_ring(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} + +static struct spi_driver adis16203_driver = { + .driver = { + .name = "adis16203", + .owner = THIS_MODULE, + }, + .probe = adis16203_probe, + .remove = __devexit_p(adis16203_remove), +}; + +static __init int adis16203_init(void) +{ + return spi_register_driver(&adis16203_driver); +} +module_init(adis16203_init); + +static __exit void adis16203_exit(void) +{ + spi_unregister_driver(&adis16203_driver); +} +module_exit(adis16203_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable Digital Vibration Sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c new file mode 100644 index 000000000000..3d774f7efa25 --- /dev/null +++ b/drivers/staging/iio/accel/adis16203_ring.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_sw.h" +#include "accel.h" +#include "../trigger.h" +#include "adis16203.h" + +static IIO_SCAN_EL_C(in_supply, ADIS16203_SCAN_SUPPLY, ADIS16203_SUPPLY_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16); +static IIO_SCAN_EL_C(in0, ADIS16203_SCAN_AUX_ADC, ADIS16203_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16); +static IIO_SCAN_EL_C(temp, ADIS16203_SCAN_TEMP, ADIS16203_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16); +static IIO_SCAN_EL_C(incli_x, ADIS16203_SCAN_INCLI_X, + ADIS16203_XINCL_OUT, NULL); +static IIO_SCAN_EL_C(incli_y, ADIS16203_SCAN_INCLI_Y, + ADIS16203_YINCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16); +static IIO_SCAN_EL_TIMESTAMP(5); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); + +static struct attribute *adis16203_scan_el_attrs[] = { + &iio_scan_el_in_supply.dev_attr.attr, + &iio_const_attr_in_supply_index.dev_attr.attr, + &iio_const_attr_in_supply_type.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_const_attr_in0_type.dev_attr.attr, + &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, + &iio_scan_el_incli_x.dev_attr.attr, + &iio_const_attr_incli_x_index.dev_attr.attr, + &iio_scan_el_incli_y.dev_attr.attr, + &iio_const_attr_incli_y_index.dev_attr.attr, + &iio_const_attr_incli_type.dev_attr.attr, + &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group adis16203_scan_el_group = { + .attrs = adis16203_scan_el_attrs, + .name = "scan_elements", +}; + +/** + * adis16203_poll_func_th() top half interrupt handler called by trigger + * @private_data: iio_dev + **/ +static void adis16203_poll_func_th(struct iio_dev *indio_dev, s64 timestamp) +{ + struct adis16203_state *st = iio_dev_get_devdata(indio_dev); + st->last_timestamp = timestamp; + schedule_work(&st->work_trigger_to_ring); +} + +/** + * adis16203_read_ring_data() read data registers which will be placed into ring + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read + **/ +static int adis16203_read_ring_data(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16203_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[ADIS16203_OUTPUTS + 1]; + int ret; + int i; + + mutex_lock(&st->buf_lock); + + spi_message_init(&msg); + + memset(xfers, 0, sizeof(xfers)); + for (i = 0; i <= ADIS16203_OUTPUTS; i++) { + xfers[i].bits_per_word = 8; + xfers[i].cs_change = 1; + xfers[i].len = 2; + xfers[i].delay_usecs = 20; + xfers[i].tx_buf = st->tx + 2 * i; + if (i < 1) /* SUPPLY_OUT: 0x02, AUX_ADC: 0x08 */ + st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i); + else + st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i + 6); + st->tx[2 * i + 1] = 0; + if (i >= 1) + xfers[i].rx_buf = rx + 2 * (i - 1); + spi_message_add_tail(&xfers[i], &msg); + } + + ret = spi_sync(st->us, &msg); + if (ret) + dev_err(&st->us->dev, "problem when burst reading"); + + mutex_unlock(&st->buf_lock); + + return ret; +} + +/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device + * specific to be rolled into the core. + */ +static void adis16203_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct adis16203_state *st + = container_of(work_s, struct adis16203_state, + work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; + + int i = 0; + s16 *data; + size_t datasize = ring->access.get_bytes_per_datum(ring); + + data = kmalloc(datasize, GFP_KERNEL); + if (data == NULL) { + dev_err(&st->us->dev, "memory alloc failed in ring bh"); + return; + } + + if (ring->scan_count) + if (adis16203_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) + for (; i < ring->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (ring->scan_timestamp) + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; + + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} + +void adis16203_unconfigure_ring(struct iio_dev *indio_dev) +{ + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} + +int adis16203_configure_ring(struct iio_dev *indio_dev) +{ + int ret = 0; + struct adis16203_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring; + INIT_WORK(&st->work_trigger_to_ring, adis16203_trigger_bh_to_ring); + + ring = iio_sw_rb_allocate(indio_dev); + if (!ring) { + ret = -ENOMEM; + return ret; + } + indio_dev->ring = ring; + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&ring->access); + ring->bpe = 2; + ring->scan_el_attrs = &adis16203_scan_el_group; + ring->scan_timestamp = true; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; + ring->owner = THIS_MODULE; + + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in_supply.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in0.number); + iio_scan_mask_set(ring, iio_scan_el_incli_x.number); + iio_scan_mask_set(ring, iio_scan_el_incli_y.number); + + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16203_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; + +error_iio_sw_rb_free: + iio_sw_rb_free(indio_dev->ring); + return ret; +} + +int adis16203_initialize_ring(struct iio_ring_buffer *ring) +{ + return iio_ring_buffer_register(ring, 0); +} + +void adis16203_uninitialize_ring(struct iio_ring_buffer *ring) +{ + iio_ring_buffer_unregister(ring); +} diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c new file mode 100644 index 000000000000..50be51c25dc2 --- /dev/null +++ b/drivers/staging/iio/accel/adis16203_trigger.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../trigger.h" +#include "adis16203.h" + +/** + * adis16203_data_rdy_trig_poll() the event handler for the data rdy trig + **/ +static int adis16203_data_rdy_trig_poll(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adis16203_state *st = iio_dev_get_devdata(dev_info); + struct iio_trigger *trig = st->trig; + + iio_trigger_poll(trig, timestamp); + + return IRQ_HANDLED; +} + +IIO_EVENT_SH(data_rdy_trig, &adis16203_data_rdy_trig_poll); + +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static struct attribute *adis16203_trigger_attrs[] = { + &dev_attr_name.attr, + NULL, +}; + +static const struct attribute_group adis16203_trigger_attr_group = { + .attrs = adis16203_trigger_attrs, +}; + +/** + * adis16203_data_rdy_trigger_set_state() set datardy interrupt state + **/ +static int adis16203_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct adis16203_state *st = trig->private_data; + struct iio_dev *indio_dev = st->indio_dev; + int ret = 0; + + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); + ret = adis16203_set_irq(&st->indio_dev->dev, state); + if (state == false) { + iio_remove_event_from_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0] + ->ev_list); + flush_scheduled_work(); + } else { + iio_add_event_to_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0]->ev_list); + } + return ret; +} + +/** + * adis16203_trig_try_reen() try renabling irq for data rdy trigger + * @trig: the datardy trigger + **/ +static int adis16203_trig_try_reen(struct iio_trigger *trig) +{ + struct adis16203_state *st = trig->private_data; + enable_irq(st->us->irq); + return 0; +} + +int adis16203_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct adis16203_state *st = indio_dev->dev_data; + + st->trig = iio_allocate_trigger(); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16203-dev%d", + indio_dev->id); + if (!st->trig->name) { + ret = -ENOMEM; + goto error_free_trig; + } + st->trig->dev.parent = &st->us->dev; + st->trig->owner = THIS_MODULE; + st->trig->private_data = st; + st->trig->set_trigger_state = &adis16203_data_rdy_trigger_set_state; + st->trig->try_reenable = &adis16203_trig_try_reen; + st->trig->control_attrs = &adis16203_trigger_attr_group; + ret = iio_trigger_register(st->trig); + + /* select default trigger */ + indio_dev->trig = st->trig; + if (ret) + goto error_free_trig_name; + + return 0; + +error_free_trig_name: + kfree(st->trig->name); +error_free_trig: + iio_free_trigger(st->trig); + + return ret; +} + +void adis16203_remove_trigger(struct iio_dev *indio_dev) +{ + struct adis16203_state *state = indio_dev->dev_data; + + iio_trigger_unregister(state->trig); + kfree(state->trig->name); + iio_free_trigger(state->trig); +} -- cgit v1.2.3 From bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:43:51 -0400 Subject: staging: iio: new adis16204 driver IIO driver for Programmable High-g Digital Impact Sensor and Recorder. Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/accel/Kconfig | 9 + drivers/staging/iio/accel/Makefile | 4 + drivers/staging/iio/accel/accel.h | 20 + drivers/staging/iio/accel/adis16204.h | 151 +++++++ drivers/staging/iio/accel/adis16204_core.c | 613 ++++++++++++++++++++++++++ drivers/staging/iio/accel/adis16204_ring.c | 206 +++++++++ drivers/staging/iio/accel/adis16204_trigger.c | 122 +++++ 7 files changed, 1125 insertions(+) create mode 100644 drivers/staging/iio/accel/adis16204.h create mode 100644 drivers/staging/iio/accel/adis16204_core.c create mode 100644 drivers/staging/iio/accel/adis16204_ring.c create mode 100644 drivers/staging/iio/accel/adis16204_trigger.c (limited to 'drivers') diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index cc057c640e64..a34f1d3e673c 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -21,6 +21,15 @@ config ADIS16203 Say yes here to build support for Analog Devices adis16203 Programmable 360 Degrees Inclinometer. +config ADIS16204 + tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder" + depends on SPI + select IIO_TRIGGER if IIO_RING_BUFFER + select IIO_SW_RING if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices adis16204 Programmable + High-g Digital Impact Sensor and Recorder. + config ADIS16209 tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" depends on SPI diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 76cc92fed23d..1b2a6d3ddafa 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -10,6 +10,10 @@ adis16203-y := adis16203_core.o adis16203-$(CONFIG_IIO_RING_BUFFER) += adis16203_ring.o adis16203_trigger.o obj-$(CONFIG_ADIS16203) += adis16203.o +adis16204-y := adis16204_core.o +adis16204-$(CONFIG_IIO_RING_BUFFER) += adis16204_ring.o adis16204_trigger.o +obj-$(CONFIG_ADIS16204) += adis16204.o + adis16209-y := adis16209_core.o adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o obj-$(CONFIG_ADIS16209) += adis16209.o diff --git a/drivers/staging/iio/accel/accel.h b/drivers/staging/iio/accel/accel.h index f5f61b2497aa..50651f835cea 100644 --- a/drivers/staging/iio/accel/accel.h +++ b/drivers/staging/iio/accel/accel.h @@ -65,3 +65,23 @@ #define IIO_DEV_ATTR_ACCEL_Z(_show, _addr) \ IIO_DEVICE_ATTR(accel_z_raw, S_IRUGO, _show, NULL, _addr) +#define IIO_DEV_ATTR_ACCEL_XY(_show, _addr) \ + IIO_DEVICE_ATTR(accel_xy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ACCEL_PEAK(_show, _addr) \ + IIO_DEVICE_ATTR(accel_peak, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ACCEL_XPEAK(_show, _addr) \ + IIO_DEVICE_ATTR(accel_xpeak, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ACCEL_YPEAK(_show, _addr) \ + IIO_DEVICE_ATTR(accel_ypeak, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ACCEL_ZPEAK(_show, _addr) \ + IIO_DEVICE_ATTR(accel_zpeak, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ACCEL_XYPEAK(_show, _addr) \ + IIO_DEVICE_ATTR(accel_xypeak, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ACCEL_XYZPEAK(_show, _addr) \ + IIO_DEVICE_ATTR(accel_xyzpeak, S_IRUGO, _show, NULL, _addr) diff --git a/drivers/staging/iio/accel/adis16204.h b/drivers/staging/iio/accel/adis16204.h new file mode 100644 index 000000000000..e9ed7cb048cf --- /dev/null +++ b/drivers/staging/iio/accel/adis16204.h @@ -0,0 +1,151 @@ +#ifndef SPI_ADIS16204_H_ +#define SPI_ADIS16204_H_ + +#define ADIS16204_STARTUP_DELAY 220 /* ms */ + +#define ADIS16204_READ_REG(a) a +#define ADIS16204_WRITE_REG(a) ((a) | 0x80) + +#define ADIS16204_FLASH_CNT 0x00 /* Flash memory write count */ +#define ADIS16204_SUPPLY_OUT 0x02 /* Output, power supply */ +#define ADIS16204_XACCL_OUT 0x04 /* Output, x-axis accelerometer */ +#define ADIS16204_YACCL_OUT 0x06 /* Output, y-axis accelerometer */ +#define ADIS16204_AUX_ADC 0x08 /* Output, auxiliary ADC input */ +#define ADIS16204_TEMP_OUT 0x0A /* Output, temperature */ +#define ADIS16204_X_PEAK_OUT 0x0C /* Twos complement */ +#define ADIS16204_Y_PEAK_OUT 0x0E /* Twos complement */ +#define ADIS16204_XACCL_NULL 0x10 /* Calibration, x-axis acceleration offset null */ +#define ADIS16204_YACCL_NULL 0x12 /* Calibration, y-axis acceleration offset null */ +#define ADIS16204_XACCL_SCALE 0x14 /* X-axis scale factor calibration register */ +#define ADIS16204_YACCL_SCALE 0x16 /* Y-axis scale factor calibration register */ +#define ADIS16204_XY_RSS_OUT 0x18 /* XY combined acceleration (RSS) */ +#define ADIS16204_XY_PEAK_OUT 0x1A /* Peak, XY combined output (RSS) */ +#define ADIS16204_CAP_BUF_1 0x1C /* Capture buffer output register 1 */ +#define ADIS16204_CAP_BUF_2 0x1E /* Capture buffer output register 2 */ +#define ADIS16204_ALM_MAG1 0x20 /* Alarm 1 amplitude threshold */ +#define ADIS16204_ALM_MAG2 0x22 /* Alarm 2 amplitude threshold */ +#define ADIS16204_ALM_CTRL 0x28 /* Alarm control */ +#define ADIS16204_CAPT_PNTR 0x2A /* Capture register address pointer */ +#define ADIS16204_AUX_DAC 0x30 /* Auxiliary DAC data */ +#define ADIS16204_GPIO_CTRL 0x32 /* General-purpose digital input/output control */ +#define ADIS16204_MSC_CTRL 0x34 /* Miscellaneous control */ +#define ADIS16204_SMPL_PRD 0x36 /* Internal sample period (rate) control */ +#define ADIS16204_AVG_CNT 0x38 /* Operation, filter configuration */ +#define ADIS16204_SLP_CNT 0x3A /* Operation, sleep mode control */ +#define ADIS16204_DIAG_STAT 0x3C /* Diagnostics, system status register */ +#define ADIS16204_GLOB_CMD 0x3E /* Operation, system command register */ + +#define ADIS16204_OUTPUTS 5 + +/* MSC_CTRL */ +#define ADIS16204_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */ +#define ADIS16204_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */ +#define ADIS16204_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16204_MSC_CTRL_ACTIVE_HIGH (1 << 1) /* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16204_MSC_CTRL_DATA_RDY_DIO2 (1 << 0) /* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ + +/* DIAG_STAT */ +#define ADIS16204_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16204_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16204_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag: 1 = error condition, + 0 = normal operation */ +#define ADIS16204_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */ +#define ADIS16204_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */ +#define ADIS16204_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */ +#define ADIS16204_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 2.975 V */ + +/* GLOB_CMD */ +#define ADIS16204_GLOB_CMD_SW_RESET (1<<7) +#define ADIS16204_GLOB_CMD_CLEAR_STAT (1<<4) +#define ADIS16204_GLOB_CMD_FACTORY_CAL (1<<1) + +#define ADIS16204_MAX_TX 24 +#define ADIS16204_MAX_RX 24 + +#define ADIS16204_ERROR_ACTIVE (1<<14) + +/** + * struct adis16204_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16204_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; + +int adis16204_set_irq(struct device *dev, bool enable); + +#ifdef CONFIG_IIO_RING_BUFFER +enum adis16204_scan { + ADIS16204_SCAN_SUPPLY, + ADIS16204_SCAN_ACC_X, + ADIS16204_SCAN_ACC_Y, + ADIS16204_SCAN_AUX_ADC, + ADIS16204_SCAN_TEMP, +}; + +void adis16204_remove_trigger(struct iio_dev *indio_dev); +int adis16204_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16204_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + +int adis16204_configure_ring(struct iio_dev *indio_dev); +void adis16204_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16204_initialize_ring(struct iio_ring_buffer *ring); +void adis16204_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16204_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16204_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16204_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16204_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16204_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16204_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16204_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16204_H_ */ diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c new file mode 100644 index 000000000000..cc15e40726fc --- /dev/null +++ b/drivers/staging/iio/accel/adis16204_core.c @@ -0,0 +1,613 @@ +/* + * ADIS16204 Programmable High-g Digital Impact Sensor and Recorder + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "accel.h" +#include "../gyro/gyro.h" +#include "../adc/adc.h" + +#include "adis16204.h" + +#define DRIVER_NAME "adis16204" + +static int adis16204_check_status(struct device *dev); + +/** + * adis16204_spi_write_reg_8() - write single byte to a register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the register to be written + * @val: the value to write + **/ +static int adis16204_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16204_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16204_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16204_spi_write_reg_16() - write 2 bytes to a pair of registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: value to be written + **/ +static int adis16204_spi_write_reg_16(struct device *dev, + u8 lower_reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16204_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, { + .tx_buf = st->tx + 2, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16204_WRITE_REG(lower_reg_address); + st->tx[1] = value & 0xFF; + st->tx[2] = ADIS16204_WRITE_REG(lower_reg_address + 1); + st->tx[3] = (value >> 8) & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16204_spi_read_reg_16() - read 2 bytes from a 16-bit register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: somewhere to pass back the value read + **/ +static int adis16204_spi_read_reg_16(struct device *dev, + u8 lower_reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16204_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + .delay_usecs = 20, + }, { + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + .delay_usecs = 20, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16204_READ_REG(lower_reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + lower_reg_address); + goto error_ret; + } + *val = (st->rx[0] << 8) | st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t adis16204_read_12bit_unsigned(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis16204_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + if (val & ADIS16204_ERROR_ACTIVE) + adis16204_check_status(dev); + + return sprintf(buf, "%u\n", val & 0x0FFF); +} + +static ssize_t adis16204_read_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + ssize_t ret; + u16 val; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + + ret = adis16204_spi_read_reg_16(dev, ADIS16204_TEMP_OUT, (u16 *)&val); + if (ret) + goto error_ret; + + if (val & ADIS16204_ERROR_ACTIVE) + adis16204_check_status(dev); + + val &= 0xFFF; + ret = sprintf(buf, "%d\n", val); + +error_ret: + mutex_unlock(&indio_dev->mlock); + return ret; +} + +static ssize_t adis16204_read_12bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s16 val = 0; + ssize_t ret; + + mutex_lock(&indio_dev->mlock); + + ret = adis16204_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (!ret) { + if (val & ADIS16204_ERROR_ACTIVE) + adis16204_check_status(dev); + + val = ((s16)(val << 4) >> 4); + ret = sprintf(buf, "%d\n", val); + } + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16204_read_14bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s16 val = 0; + ssize_t ret; + + mutex_lock(&indio_dev->mlock); + + ret = adis16204_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (!ret) { + if (val & ADIS16204_ERROR_ACTIVE) + adis16204_check_status(dev); + + val = ((s16)(val << 2) >> 2); + ret = sprintf(buf, "%d\n", val); + } + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16204_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = adis16204_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int adis16204_reset(struct device *dev) +{ + int ret; + ret = adis16204_spi_write_reg_8(dev, + ADIS16204_GLOB_CMD, + ADIS16204_GLOB_CMD_SW_RESET); + if (ret) + dev_err(dev, "problem resetting device"); + + return ret; +} + +static ssize_t adis16204_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -EINVAL; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return adis16204_reset(dev); + } + return -EINVAL; +} + +int adis16204_set_irq(struct device *dev, bool enable) +{ + int ret = 0; + u16 msc; + + ret = adis16204_spi_read_reg_16(dev, ADIS16204_MSC_CTRL, &msc); + if (ret) + goto error_ret; + + msc |= ADIS16204_MSC_CTRL_ACTIVE_HIGH; + msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_DIO2; + if (enable) + msc |= ADIS16204_MSC_CTRL_DATA_RDY_EN; + else + msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_EN; + + ret = adis16204_spi_write_reg_16(dev, ADIS16204_MSC_CTRL, msc); + +error_ret: + return ret; +} + +static int adis16204_check_status(struct device *dev) +{ + u16 status; + int ret; + + ret = adis16204_spi_read_reg_16(dev, ADIS16204_DIAG_STAT, &status); + if (ret < 0) { + dev_err(dev, "Reading status failed\n"); + goto error_ret; + } + ret = status & 0x1F; + + if (status & ADIS16204_DIAG_STAT_SELFTEST_FAIL) + dev_err(dev, "Self test failure\n"); + if (status & ADIS16204_DIAG_STAT_SPI_FAIL) + dev_err(dev, "SPI failure\n"); + if (status & ADIS16204_DIAG_STAT_FLASH_UPT) + dev_err(dev, "Flash update failed\n"); + if (status & ADIS16204_DIAG_STAT_POWER_HIGH) + dev_err(dev, "Power supply above 3.625V\n"); + if (status & ADIS16204_DIAG_STAT_POWER_LOW) + dev_err(dev, "Power supply below 2.975V\n"); + +error_ret: + return ret; +} + +static int adis16204_self_test(struct device *dev) +{ + int ret; + ret = adis16204_spi_write_reg_16(dev, + ADIS16204_MSC_CTRL, + ADIS16204_MSC_CTRL_SELF_TEST_EN); + if (ret) { + dev_err(dev, "problem starting self test"); + goto err_ret; + } + + adis16204_check_status(dev); + +err_ret: + return ret; +} + +static int adis16204_initial_setup(struct adis16204_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* Disable IRQ */ + ret = adis16204_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + /* Do self test */ + ret = adis16204_self_test(dev); + if (ret) { + dev_err(dev, "self test failure"); + goto err_ret; + } + + /* Read status register to check the result */ + ret = adis16204_check_status(dev); + if (ret) { + adis16204_reset(dev); + dev_err(dev, "device not playing ball -> reset"); + msleep(ADIS16204_STARTUP_DELAY); + ret = adis16204_check_status(dev); + if (ret) { + dev_err(dev, "giving up"); + goto err_ret; + } + } + + printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n", + st->us->chip_select, st->us->irq); + +err_ret: + return ret; +} + +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16204_read_12bit_unsigned, + ADIS16204_SUPPLY_OUT); +static IIO_CONST_ATTR(in0_supply_scale, "0.00122"); +static IIO_DEV_ATTR_IN_RAW(1, adis16204_read_12bit_unsigned, + ADIS16204_AUX_ADC); +static IIO_CONST_ATTR(in1_scale, "0.00061"); + +static IIO_DEV_ATTR_ACCEL_X(adis16204_read_14bit_signed, + ADIS16204_XACCL_OUT); +static IIO_DEV_ATTR_ACCEL_Y(adis16204_read_14bit_signed, + ADIS16204_YACCL_OUT); +static IIO_DEV_ATTR_ACCEL_XY(adis16204_read_14bit_signed, + ADIS16204_XY_RSS_OUT); +static IIO_DEV_ATTR_ACCEL_XPEAK(adis16204_read_14bit_signed, + ADIS16204_X_PEAK_OUT); +static IIO_DEV_ATTR_ACCEL_YPEAK(adis16204_read_14bit_signed, + ADIS16204_Y_PEAK_OUT); +static IIO_DEV_ATTR_ACCEL_XYPEAK(adis16204_read_14bit_signed, + ADIS16204_XY_PEAK_OUT); +static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, + adis16204_read_12bit_signed, + adis16204_write_16bit, + ADIS16204_XACCL_NULL); +static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, + adis16204_read_12bit_signed, + adis16204_write_16bit, + ADIS16204_YACCL_NULL); +static IIO_CONST_ATTR(accel_x_scale, "0.017125"); +static IIO_CONST_ATTR(accel_y_scale, "0.008407"); +static IIO_CONST_ATTR(accel_xy_scale, "0.017125"); + +static IIO_DEV_ATTR_TEMP_RAW(adis16204_read_temp); +static IIO_CONST_ATTR(temp_offset, "25"); +static IIO_CONST_ATTR(temp_scale, "-0.47"); + +static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16204_write_reset, 0); + +static IIO_CONST_ATTR(name, "adis16204"); + +static struct attribute *adis16204_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16204_event_attribute_group = { + .attrs = adis16204_event_attributes, +}; + +static struct attribute *adis16204_attributes[] = { + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_const_attr_in1_scale.dev_attr.attr, + &iio_dev_attr_accel_x_raw.dev_attr.attr, + &iio_dev_attr_accel_y_raw.dev_attr.attr, + &iio_dev_attr_accel_xy.dev_attr.attr, + &iio_dev_attr_accel_xpeak.dev_attr.attr, + &iio_dev_attr_accel_ypeak.dev_attr.attr, + &iio_dev_attr_accel_xypeak.dev_attr.attr, + &iio_dev_attr_accel_x_offset.dev_attr.attr, + &iio_dev_attr_accel_y_offset.dev_attr.attr, + &iio_const_attr_accel_x_scale.dev_attr.attr, + &iio_const_attr_accel_y_scale.dev_attr.attr, + &iio_const_attr_accel_xy_scale.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16204_attribute_group = { + .attrs = adis16204_attributes, +}; + +static int __devinit adis16204_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16204_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16204_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16204_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16204_event_attribute_group; + st->indio_dev->attrs = &adis16204_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis16204_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16204_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16204"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16204_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = adis16204_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + adis16204_remove_trigger(st->indio_dev); +error_unregister_line: + if (spi->irq) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16204_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16204_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int adis16204_remove(struct spi_device *spi) +{ + struct adis16204_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + adis16204_remove_trigger(indio_dev); + if (spi->irq) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16204_uninitialize_ring(indio_dev->ring); + iio_device_unregister(indio_dev); + adis16204_unconfigure_ring(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} + +static struct spi_driver adis16204_driver = { + .driver = { + .name = "adis16204", + .owner = THIS_MODULE, + }, + .probe = adis16204_probe, + .remove = __devexit_p(adis16204_remove), +}; + +static __init int adis16204_init(void) +{ + return spi_register_driver(&adis16204_driver); +} +module_init(adis16204_init); + +static __exit void adis16204_exit(void) +{ + spi_unregister_driver(&adis16204_driver); +} +module_exit(adis16204_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c new file mode 100644 index 000000000000..420b160fe3ab --- /dev/null +++ b/drivers/staging/iio/accel/adis16204_ring.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_sw.h" +#include "accel.h" +#include "../trigger.h" +#include "adis16204.h" + +static IIO_SCAN_EL_C(in_supply, ADIS16204_SCAN_SUPPLY, ADIS16204_SUPPLY_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16); +static IIO_SCAN_EL_C(accel_x, ADIS16204_SCAN_ACC_X, ADIS16204_XACCL_OUT, NULL); +static IIO_SCAN_EL_C(accel_y, ADIS16204_SCAN_ACC_Y, ADIS16204_YACCL_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16); +static IIO_SCAN_EL_C(in0, ADIS16204_SCAN_AUX_ADC, ADIS16204_AUX_ADC, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16); +static IIO_SCAN_EL_C(temp, ADIS16204_SCAN_TEMP, ADIS16204_TEMP_OUT, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16); +static IIO_SCAN_EL_TIMESTAMP(5); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); + +static struct attribute *adis16204_scan_el_attrs[] = { + &iio_scan_el_in_supply.dev_attr.attr, + &iio_const_attr_in_supply_index.dev_attr.attr, + &iio_const_attr_in_supply_type.dev_attr.attr, + &iio_scan_el_accel_x.dev_attr.attr, + &iio_const_attr_accel_x_index.dev_attr.attr, + &iio_scan_el_accel_y.dev_attr.attr, + &iio_const_attr_accel_y_index.dev_attr.attr, + &iio_const_attr_accel_type.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_const_attr_in0_type.dev_attr.attr, + &iio_scan_el_temp.dev_attr.attr, + &iio_const_attr_temp_index.dev_attr.attr, + &iio_const_attr_temp_type.dev_attr.attr, + &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group adis16204_scan_el_group = { + .attrs = adis16204_scan_el_attrs, + .name = "scan_elements", +}; + +/** + * adis16204_poll_func_th() top half interrupt handler called by trigger + * @private_data: iio_dev + **/ +static void adis16204_poll_func_th(struct iio_dev *indio_dev, s64 timestamp) +{ + struct adis16204_state *st = iio_dev_get_devdata(indio_dev); + st->last_timestamp = timestamp; + schedule_work(&st->work_trigger_to_ring); +} + +/** + * adis16204_read_ring_data() read data registers which will be placed into ring + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read + **/ +static int adis16204_read_ring_data(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16204_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[ADIS16204_OUTPUTS + 1]; + int ret; + int i; + + mutex_lock(&st->buf_lock); + + spi_message_init(&msg); + + memset(xfers, 0, sizeof(xfers)); + for (i = 0; i <= ADIS16204_OUTPUTS; i++) { + xfers[i].bits_per_word = 8; + xfers[i].cs_change = 1; + xfers[i].len = 2; + xfers[i].delay_usecs = 20; + xfers[i].tx_buf = st->tx + 2 * i; + st->tx[2 * i] = ADIS16204_READ_REG(ADIS16204_SUPPLY_OUT + 2 * i); + st->tx[2 * i + 1] = 0; + if (i >= 1) + xfers[i].rx_buf = rx + 2 * (i - 1); + spi_message_add_tail(&xfers[i], &msg); + } + + ret = spi_sync(st->us, &msg); + if (ret) + dev_err(&st->us->dev, "problem when burst reading"); + + mutex_unlock(&st->buf_lock); + + return ret; +} + +/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device + * specific to be rolled into the core. + */ +static void adis16204_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct adis16204_state *st + = container_of(work_s, struct adis16204_state, + work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; + + int i = 0; + s16 *data; + size_t datasize = ring->access.get_bytes_per_datum(ring); + + data = kmalloc(datasize, GFP_KERNEL); + if (data == NULL) { + dev_err(&st->us->dev, "memory alloc failed in ring bh"); + return; + } + + if (ring->scan_count) + if (adis16204_read_ring_data(&st->indio_dev->dev, st->rx) >= 0) + for (; i < ring->scan_count; i++) + data[i] = be16_to_cpup( + (__be16 *)&(st->rx[i*2])); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (ring->scan_timestamp) + *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp; + + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} + +void adis16204_unconfigure_ring(struct iio_dev *indio_dev) +{ + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} + +int adis16204_configure_ring(struct iio_dev *indio_dev) +{ + int ret = 0; + struct adis16204_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring; + INIT_WORK(&st->work_trigger_to_ring, adis16204_trigger_bh_to_ring); + + ring = iio_sw_rb_allocate(indio_dev); + if (!ring) { + ret = -ENOMEM; + return ret; + } + indio_dev->ring = ring; + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&ring->access); + ring->bpe = 2; + ring->scan_el_attrs = &adis16204_scan_el_group; + ring->scan_timestamp = true; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; + ring->owner = THIS_MODULE; + + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_in_supply.number); + iio_scan_mask_set(ring, iio_scan_el_accel_x.number); + iio_scan_mask_set(ring, iio_scan_el_accel_y.number); + iio_scan_mask_set(ring, iio_scan_el_temp.number); + iio_scan_mask_set(ring, iio_scan_el_in0.number); + + ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16204_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; + +error_iio_sw_rb_free: + iio_sw_rb_free(indio_dev->ring); + return ret; +} + +int adis16204_initialize_ring(struct iio_ring_buffer *ring) +{ + return iio_ring_buffer_register(ring, 0); +} + +void adis16204_uninitialize_ring(struct iio_ring_buffer *ring) +{ + iio_ring_buffer_unregister(ring); +} diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c new file mode 100644 index 000000000000..8e9db90e51eb --- /dev/null +++ b/drivers/staging/iio/accel/adis16204_trigger.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../trigger.h" +#include "adis16204.h" + +/** + * adis16204_data_rdy_trig_poll() the event handler for the data rdy trig + **/ +static int adis16204_data_rdy_trig_poll(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adis16204_state *st = iio_dev_get_devdata(dev_info); + struct iio_trigger *trig = st->trig; + + iio_trigger_poll(trig, timestamp); + + return IRQ_HANDLED; +} + +IIO_EVENT_SH(data_rdy_trig, &adis16204_data_rdy_trig_poll); + +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static struct attribute *adis16204_trigger_attrs[] = { + &dev_attr_name.attr, + NULL, +}; + +static const struct attribute_group adis16204_trigger_attr_group = { + .attrs = adis16204_trigger_attrs, +}; + +/** + * adis16204_data_rdy_trigger_set_state() set datardy interrupt state + **/ +static int adis16204_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct adis16204_state *st = trig->private_data; + struct iio_dev *indio_dev = st->indio_dev; + int ret = 0; + + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); + ret = adis16204_set_irq(&st->indio_dev->dev, state); + if (state == false) { + iio_remove_event_from_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0] + ->ev_list); + flush_scheduled_work(); + } else { + iio_add_event_to_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0]->ev_list); + } + return ret; +} + +/** + * adis16204_trig_try_reen() try renabling irq for data rdy trigger + * @trig: the datardy trigger + **/ +static int adis16204_trig_try_reen(struct iio_trigger *trig) +{ + struct adis16204_state *st = trig->private_data; + enable_irq(st->us->irq); + return 0; +} + +int adis16204_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct adis16204_state *st = indio_dev->dev_data; + + st->trig = iio_allocate_trigger(); + st->trig->name = kasprintf(GFP_KERNEL, + "adis16204-dev%d", + indio_dev->id); + if (!st->trig->name) { + ret = -ENOMEM; + goto error_free_trig; + } + st->trig->dev.parent = &st->us->dev; + st->trig->owner = THIS_MODULE; + st->trig->private_data = st; + st->trig->set_trigger_state = &adis16204_data_rdy_trigger_set_state; + st->trig->try_reenable = &adis16204_trig_try_reen; + st->trig->control_attrs = &adis16204_trigger_attr_group; + ret = iio_trigger_register(st->trig); + + /* select default trigger */ + indio_dev->trig = st->trig; + if (ret) + goto error_free_trig_name; + + return 0; + +error_free_trig_name: + kfree(st->trig->name); +error_free_trig: + iio_free_trigger(st->trig); + + return ret; +} + +void adis16204_remove_trigger(struct iio_dev *indio_dev) +{ + struct adis16204_state *state = indio_dev->dev_data; + + iio_trigger_unregister(state->trig); + kfree(state->trig->name); + iio_free_trigger(state->trig); +} -- cgit v1.2.3 From 35f6b6b86ede34a9f8c029943842640b2ffbfa19 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:43:52 -0400 Subject: staging: iio: new ADT7316/7/8 and ADT7516/7/9 driver IIO driver for temperature sensor, ADC and DAC devices over SPI and I2C. Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/Kconfig | 1 + drivers/staging/iio/Makefile | 1 + drivers/staging/iio/addac/Kconfig | 25 + drivers/staging/iio/addac/Makefile | 7 + drivers/staging/iio/addac/adt7316-i2c.c | 170 +++ drivers/staging/iio/addac/adt7316-spi.c | 180 +++ drivers/staging/iio/addac/adt7316.c | 2402 +++++++++++++++++++++++++++++++ drivers/staging/iio/addac/adt7316.h | 33 + 8 files changed, 2819 insertions(+) create mode 100644 drivers/staging/iio/addac/Kconfig create mode 100644 drivers/staging/iio/addac/Makefile create mode 100644 drivers/staging/iio/addac/adt7316-i2c.c create mode 100644 drivers/staging/iio/addac/adt7316-spi.c create mode 100644 drivers/staging/iio/addac/adt7316.c create mode 100644 drivers/staging/iio/addac/adt7316.h (limited to 'drivers') diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index ed48815a916b..b8bb5f162540 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -42,6 +42,7 @@ config IIO_TRIGGER source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" +source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index e909674920fc..0111647b9b9a 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_IIO_SW_RING) += ring_sw.o obj-y += accel/ obj-y += adc/ +obj-y += addac/ obj-y += gyro/ obj-y += imu/ obj-y += light/ diff --git a/drivers/staging/iio/addac/Kconfig b/drivers/staging/iio/addac/Kconfig new file mode 100644 index 000000000000..9847baf02700 --- /dev/null +++ b/drivers/staging/iio/addac/Kconfig @@ -0,0 +1,25 @@ +# +# ADDAC drivers +# +comment "Analog digital bi-direction convertors" + +config ADT7316 + tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver" + help + Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318 + and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC. + +config ADT7316_SPI + tristate "support SPI bus connection" + depends on SPI && ADT7316 + default y + help + Say yes here to build SPI bus support for Analog Devices ADT7316/7/8 + and ADT7516/7/9. + +config ADT7316_I2C + tristate "support I2C bus connection" + depends on I2C && ADT7316 + help + Say yes here to build I2C bus support for Analog Devices ADT7316/7/8 + and ADT7516/7/9. diff --git a/drivers/staging/iio/addac/Makefile b/drivers/staging/iio/addac/Makefile new file mode 100644 index 000000000000..4c7686133692 --- /dev/null +++ b/drivers/staging/iio/addac/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for industrial I/O ADDAC drivers +# + +obj-$(CONFIG_ADT7316) += adt7316.o +obj-$(CONFIG_ADT7316_SPI) += adt7316-spi.o +obj-$(CONFIG_ADT7316_I2C) += adt7316-i2c.o diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c new file mode 100644 index 000000000000..52d1ea349635 --- /dev/null +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -0,0 +1,170 @@ +/* + * I2C bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature + * sensor, ADC and DAC + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include "adt7316.h" + +/* + * adt7316 register access by I2C + */ +static int adt7316_i2c_read(void *client, u8 reg, u8 *data) +{ + struct i2c_client *cl = client; + int ret = 0; + + ret = i2c_smbus_write_byte(cl, reg); + if (ret < 0) { + dev_err(&cl->dev, "I2C fail to select reg\n"); + return ret; + } + + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_err(&cl->dev, "I2C read error\n"); + return ret; + } + + return 0; +} + +static int adt7316_i2c_write(void *client, u8 reg, u8 data) +{ + struct i2c_client *cl = client; + int ret = 0; + + ret = i2c_smbus_write_byte_data(cl, reg, data); + if (ret < 0) + dev_err(&cl->dev, "I2C write error\n"); + + return ret; +} + +static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data) +{ + struct i2c_client *cl = client; + int i, ret = 0; + + if (count > ADT7316_REG_MAX_ADDR) + count = ADT7316_REG_MAX_ADDR; + + for (i = 0; i < count; i++) { + ret = adt7316_i2c_read(cl, reg, &data[i]); + if (ret < 0) { + dev_err(&cl->dev, "I2C multi read error\n"); + return ret; + } + } + + return 0; +} + +static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data) +{ + struct i2c_client *cl = client; + int i, ret = 0; + + if (count > ADT7316_REG_MAX_ADDR) + count = ADT7316_REG_MAX_ADDR; + + for (i = 0; i < count; i++) { + ret = adt7316_i2c_write(cl, reg, data[i]); + if (ret < 0) { + dev_err(&cl->dev, "I2C multi write error\n"); + return ret; + } + } + + return 0; +} + +/* + * device probe and remove + */ + +static int __devinit adt7316_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adt7316_bus bus = { + .client = client, + .irq = client->irq, + .irq_flags = IRQF_TRIGGER_LOW, + .read = adt7316_i2c_read, + .write = adt7316_i2c_write, + .multi_read = adt7316_i2c_multi_read, + .multi_write = adt7316_i2c_multi_write, + }; + + return adt7316_probe(&client->dev, &bus, id->name); +} + +static int __devexit adt7316_i2c_remove(struct i2c_client *client) +{ + return adt7316_remove(&client->dev);; +} + +static const struct i2c_device_id adt7316_i2c_id[] = { + { "adt7316", 0 }, + { "adt7317", 0 }, + { "adt7318", 0 }, + { "adt7516", 0 }, + { "adt7517", 0 }, + { "adt7519", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id); + +#ifdef CONFIG_PM +static int adt7316_i2c_suspend(struct i2c_client *client, pm_message_t message) +{ + return adt7316_disable(&client->dev); +} + +static int adt7316_i2c_resume(struct i2c_client *client) +{ + return adt7316_enable(&client->dev); +} +#else +# define adt7316_i2c_suspend NULL +# define adt7316_i2c_resume NULL +#endif + +static struct i2c_driver adt7316_driver = { + .driver = { + .name = "adt7316", + .owner = THIS_MODULE, + }, + .probe = adt7316_i2c_probe, + .remove = __devexit_p(adt7316_i2c_remove), + .suspend = adt7316_i2c_suspend, + .resume = adt7316_i2c_resume, + .id_table = adt7316_i2c_id, +}; + +static __init int adt7316_i2c_init(void) +{ + return i2c_add_driver(&adt7316_driver); +} + +static __exit void adt7316_i2c_exit(void) +{ + i2c_del_driver(&adt7316_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("I2C bus driver for Analog Devices ADT7316/7/9 and" + "ADT7516/7/8 digital temperature sensor, ADC and DAC"); +MODULE_LICENSE("GPL v2"); + +module_init(adt7316_i2c_init); +module_exit(adt7316_i2c_exit); diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c new file mode 100644 index 000000000000..369d4d01ed97 --- /dev/null +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -0,0 +1,180 @@ +/* + * API bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature + * sensor, ADC and DAC + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include + +#include "adt7316.h" + +#define ADT7316_SPI_MAX_FREQ_HZ 5000000 +#define ADT7316_SPI_CMD_READ 0x91 +#define ADT7316_SPI_CMD_WRITE 0x90 + +/* + * adt7316 register access by SPI + */ + +static int adt7316_spi_multi_read(void *client, u8 reg, u8 count, u8 *data) +{ + struct spi_device *spi_dev = client; + u8 cmd[2]; + int ret = 0; + + if (count > ADT7316_REG_MAX_ADDR) + count = ADT7316_REG_MAX_ADDR; + + cmd[0] = ADT7316_SPI_CMD_WRITE; + cmd[1] = reg; + + ret = spi_write(spi_dev, cmd, 2); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI fail to select reg\n"); + return ret; + } + + cmd[0] = ADT7316_SPI_CMD_READ; + + ret = spi_write_then_read(spi_dev, cmd, 1, data, count); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI read data error\n"); + return ret; + } + + return 0; +} + +static int adt7316_spi_multi_write(void *client, u8 reg, u8 count, u8 *data) +{ + struct spi_device *spi_dev = client; + u8 buf[ADT7316_REG_MAX_ADDR + 2]; + int i, ret = 0; + + if (count > ADT7316_REG_MAX_ADDR) + count = ADT7316_REG_MAX_ADDR; + + buf[0] = ADT7316_SPI_CMD_WRITE; + buf[1] = reg; + for (i = 0; i < count; i++) + buf[i + 2] = data[i]; + + ret = spi_write(spi_dev, buf, count + 2); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI write error\n"); + return ret; + } + + return ret; +} + +static int adt7316_spi_read(void *client, u8 reg, u8 *data) +{ + return adt7316_spi_multi_read(client, reg, 1, data); +} + +static int adt7316_spi_write(void *client, u8 reg, u8 val) +{ + return adt7316_spi_multi_write(client, reg, 1, &val); +} + +/* + * device probe and remove + */ + +static int __devinit adt7316_spi_probe(struct spi_device *spi_dev) +{ + struct adt7316_bus bus = { + .client = spi_dev, + .irq = spi_dev->irq, + .irq_flags = IRQF_TRIGGER_LOW, + .read = adt7316_spi_read, + .write = adt7316_spi_write, + .multi_read = adt7316_spi_multi_read, + .multi_write = adt7316_spi_multi_write, + }; + + /* don't exceed max specified SPI CLK frequency */ + if (spi_dev->max_speed_hz > ADT7316_SPI_MAX_FREQ_HZ) { + dev_err(&spi_dev->dev, "SPI CLK %d Hz?\n", + spi_dev->max_speed_hz); + return -EINVAL; + } + + /* switch from default I2C protocol to SPI protocol */ + adt7316_spi_write(spi_dev, 0, 0); + adt7316_spi_write(spi_dev, 0, 0); + adt7316_spi_write(spi_dev, 0, 0); + + return adt7316_probe(&spi_dev->dev, &bus, spi_dev->modalias); +} + +static int __devexit adt7316_spi_remove(struct spi_device *spi_dev) +{ + return adt7316_remove(&spi_dev->dev); +} + +static const struct spi_device_id adt7316_spi_id[] = { + { "adt7316", 0 }, + { "adt7317", 0 }, + { "adt7318", 0 }, + { "adt7516", 0 }, + { "adt7517", 0 }, + { "adt7519", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(spi, adt7316_spi_id); + +#ifdef CONFIG_PM +static int adt7316_spi_suspend(struct spi_device *spi_dev, pm_message_t message) +{ + return adt7316_disable(&spi_dev->dev); +} + +static int adt7316_spi_resume(struct spi_device *spi_dev) +{ + return adt7316_enable(&spi_dev->dev); +} +#else +# define adt7316_spi_suspend NULL +# define adt7316_spi_resume NULL +#endif + +static struct spi_driver adt7316_driver = { + .driver = { + .name = "adt7316", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = adt7316_spi_probe, + .remove = __devexit_p(adt7316_spi_remove), + .suspend = adt7316_spi_suspend, + .resume = adt7316_spi_resume, + .id_table = adt7316_spi_id, +}; + +static __init int adt7316_spi_init(void) +{ + return spi_register_driver(&adt7316_driver); +} + +static __exit void adt7316_spi_exit(void) +{ + spi_unregister_driver(&adt7316_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("SPI bus driver for Analog Devices ADT7316/7/8 and" + "ADT7516/7/9 digital temperature sensor, ADC and DAC"); +MODULE_LICENSE("GPL v2"); + +module_init(adt7316_spi_init); +module_exit(adt7316_spi_exit); diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c new file mode 100644 index 000000000000..d1b5b13629d9 --- /dev/null +++ b/drivers/staging/iio/addac/adt7316.c @@ -0,0 +1,2402 @@ +/* + * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9 + * + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "adt7316.h" + +/* + * ADT7316 registers definition + */ +#define ADT7316_INT_STAT1 0x0 +#define ADT7316_INT_STAT2 0x1 +#define ADT7316_LSB_IN_TEMP_VDD 0x3 +#define ADT7316_LSB_IN_TEMP_MASK 0x3 +#define ADT7316_LSB_VDD_MASK 0xC +#define ADT7316_LSB_VDD_OFFSET 2 +#define ADT7316_LSB_EX_TEMP_AIN 0x4 +#define ADT7316_LSB_EX_TEMP_MASK 0x3 +#define ADT7516_LSB_AIN_SHIFT 2 +#define ADT7316_AD_MSB_DATA_BASE 0x6 +#define ADT7316_AD_MSB_DATA_REGS 3 +#define ADT7516_AD_MSB_DATA_REGS 6 +#define ADT7316_MSB_VDD 0x6 +#define ADT7316_MSB_IN_TEMP 0x7 +#define ADT7316_MSB_EX_TEMP 0x8 +#define ADT7516_MSB_AIN1 0x8 +#define ADT7516_MSB_AIN2 0x9 +#define ADT7516_MSB_AIN3 0xA +#define ADT7516_MSB_AIN4 0xB +#define ADT7316_DA_DATA_BASE 0x10 +#define ADT7316_DA_MSB_DATA_REGS 4 +#define ADT7316_LSB_DAC_A 0x10 +#define ADT7316_MSB_DAC_A 0x11 +#define ADT7316_LSB_DAC_B 0x12 +#define ADT7316_MSB_DAC_B 0x13 +#define ADT7316_LSB_DAC_C 0x14 +#define ADT7316_MSB_DAC_C 0x15 +#define ADT7316_LSB_DAC_D 0x16 +#define ADT7316_MSB_DAC_D 0x17 +#define ADT7316_CONFIG1 0x18 +#define ADT7316_CONFIG2 0x19 +#define ADT7316_CONFIG3 0x1A +#define ADT7316_LDAC_CONFIG 0x1B +#define ADT7316_DAC_CONFIG 0x1C +#define ADT7316_INT_MASK1 0x1D +#define ADT7316_INT_MASK2 0x1E +#define ADT7316_IN_TEMP_OFFSET 0x1F +#define ADT7316_EX_TEMP_OFFSET 0x20 +#define ADT7316_IN_ANALOG_TEMP_OFFSET 0x21 +#define ADT7316_EX_ANALOG_TEMP_OFFSET 0x22 +#define ADT7316_VDD_HIGH 0x23 +#define ADT7316_VDD_LOW 0x24 +#define ADT7316_IN_TEMP_HIGH 0x25 +#define ADT7316_IN_TEMP_LOW 0x26 +#define ADT7316_EX_TEMP_HIGH 0x27 +#define ADT7316_EX_TEMP_LOW 0x28 +#define ADT7516_AIN2_HIGH 0x2B +#define ADT7516_AIN2_LOW 0x2C +#define ADT7516_AIN3_HIGH 0x2D +#define ADT7516_AIN3_LOW 0x2E +#define ADT7516_AIN4_HIGH 0x2F +#define ADT7516_AIN4_LOW 0x30 +#define ADT7316_DEVICE_ID 0x4D +#define ADT7316_MANUFACTURE_ID 0x4E +#define ADT7316_DEVICE_REV 0x4F +#define ADT7316_SPI_LOCK_STAT 0x7F + +/* + * ADT7316 config1 + */ +#define ADT7316_EN 0x1 +#define ADT7516_SEL_EX_TEMP 0x4 +#define ADT7516_SEL_AIN1_2_EX_TEMP_MASK 0x6 +#define ADT7516_SEL_AIN3 0x8 +#define ADT7316_INT_EN 0x20 +#define ADT7316_INT_POLARITY 0x40 +#define ADT7316_PD 0x80 + +/* + * ADT7316 config2 + */ +#define ADT7316_AD_SINGLE_CH_MASK 0x3 +#define ADT7516_AD_SINGLE_CH_MASK 0x7 +#define ADT7316_AD_SINGLE_CH_VDD 0 +#define ADT7316_AD_SINGLE_CH_IN 1 +#define ADT7316_AD_SINGLE_CH_EX 2 +#define ADT7516_AD_SINGLE_CH_AIN1 2 +#define ADT7516_AD_SINGLE_CH_AIN2 3 +#define ADT7516_AD_SINGLE_CH_AIN3 4 +#define ADT7516_AD_SINGLE_CH_AIN4 5 +#define ADT7316_AD_SINGLE_CH_MODE 0x10 +#define ADT7316_DISABLE_AVERAGING 0x20 +#define ADT7316_EN_SMBUS_TIMEOUT 0x40 +#define ADT7316_RESET 0x80 + +/* + * ADT7316 config3 + */ +#define ADT7316_ADCLK_22_5 0x1 +#define ADT7316_DA_HIGH_RESOLUTION 0x2 +#define ADT7316_DA_EN_VIA_DAC_LDCA 0x4 +#define ADT7516_AIN_IN_VREF 0x10 +#define ADT7316_EN_IN_TEMP_PROP_DACA 0x20 +#define ADT7316_EN_EX_TEMP_PROP_DACB 0x40 + +/* + * ADT7316 DAC config + */ +#define ADT7316_DA_2VREF_CH_MASK 0xF +#define ADT7316_DA_EN_MODE_MASK 0x30 +#define ADT7316_DA_EN_MODE_SINGLE 0x00 +#define ADT7316_DA_EN_MODE_AB_CD 0x10 +#define ADT7316_DA_EN_MODE_ABCD 0x20 +#define ADT7316_DA_EN_MODE_LDAC 0x30 +#define ADT7316_VREF_BYPASS_DAC_AB 0x40 +#define ADT7316_VREF_BYPASS_DAC_CD 0x80 + +/* + * ADT7316 LDAC config + */ +#define ADT7316_LDAC_EN_DA_MASK 0xF +#define ADT7316_DAC_IN_VREF 0x10 +#define ADT7516_DAC_AB_IN_VREF 0x10 +#define ADT7516_DAC_CD_IN_VREF 0x20 +#define ADT7516_DAC_IN_VREF_OFFSET 4 +#define ADT7516_DAC_IN_VREF_MASK 0x30 + +/* + * ADT7316 INT_MASK2 + */ +#define ADT7316_INT_MASK2_VDD 0x10 + +/* + * ADT7316 value masks + */ +#define ADT7316_VALUE_MASK 0xfff +#define ADT7316_T_VALUE_SIGN 0x400 +#define ADT7316_T_VALUE_FLOAT_OFFSET 2 +#define ADT7316_T_VALUE_FLOAT_MASK 0x2 + +/* + * Chip ID + */ +#define ID_ADT7316 0x1 +#define ID_ADT7317 0x2 +#define ID_ADT7318 0x3 +#define ID_ADT7516 0x11 +#define ID_ADT7517 0x12 +#define ID_ADT7519 0x14 + +#define ID_FAMILY_MASK 0xF0 +#define ID_ADT73XX 0x0 +#define ID_ADT75XX 0x10 + +/* + * struct adt7316_chip_info - chip specifc information + */ + +struct adt7316_chip_info { + const char *name; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + s64 last_timestamp; + struct adt7316_bus bus; + u16 ldac_pin; + u16 int_mask; /* 0x2f */ + u8 config1; + u8 config2; + u8 config3; + u8 dac_config; /* DAC config */ + u8 ldac_config; /* LDAC config */ + u8 dac_bits; /* 8, 10, 12 */ + u8 id; /* chip id */ +}; + +/* + * Logic interrupt mask for user application to enable + * interrupts. + */ +#define ADT7316_IN_TEMP_HIGH_INT_MASK 0x1 +#define ADT7316_IN_TEMP_LOW_INT_MASK 0x2 +#define ADT7316_EX_TEMP_HIGH_INT_MASK 0x4 +#define ADT7316_EX_TEMP_LOW_INT_MASK 0x8 +#define ADT7316_EX_TEMP_FAULT_INT_MASK 0x10 +#define ADT7516_AIN1_INT_MASK 0x4 +#define ADT7516_AIN2_INT_MASK 0x20 +#define ADT7516_AIN3_INT_MASK 0x40 +#define ADT7516_AIN4_INT_MASK 0x80 +#define ADT7316_VDD_INT_MASK 0x100 +#define ADT7316_TEMP_INT_MASK 0x1F +#define ADT7516_AIN_INT_MASK 0xE0 +#define ADT7316_TEMP_AIN_INT_MASK \ + (ADT7316_TEMP_INT_MASK | ADT7316_TEMP_INT_MASK) + +/* + * struct adt7316_chip_info - chip specifc information + */ + +struct adt7316_limit_regs { + u16 data_high; + u16 data_low; +}; + +static ssize_t adt7316_show_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN)); +} + +static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip, + int enable) +{ + u8 config1; + int ret; + + if (enable) + config1 = chip->config1 | ADT7316_EN; + else + config1 = chip->config1 & ~ADT7316_EN; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1); + if (ret) + return -EIO; + + chip->config1 = config1; + + return ret; + +} + +static ssize_t adt7316_store_enabled(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + int enable; + + if (!memcmp(buf, "1", 1)) + enable = 1; + else + enable = 0; + + if (_adt7316_store_enabled(chip, enable) < 0) + return -EIO; + else + return len; +} + +static IIO_DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, + adt7316_show_enabled, + adt7316_store_enabled, + 0); + +static ssize_t adt7316_show_select_ex_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) + return -EPERM; + + return sprintf(buf, "%d\n", !!(chip->config1 & ADT7516_SEL_EX_TEMP)); +} + +static ssize_t adt7316_store_select_ex_temp(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config1; + int ret; + + if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) + return -EPERM; + + config1 = chip->config1 & (~ADT7516_SEL_EX_TEMP); + if (!memcmp(buf, "1", 1)) + config1 |= ADT7516_SEL_EX_TEMP; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1); + if (ret) + return -EIO; + + chip->config1 = config1; + + return len; +} + +static IIO_DEVICE_ATTR(select_ex_temp, S_IRUGO | S_IWUSR, + adt7316_show_select_ex_temp, + adt7316_store_select_ex_temp, + 0); + +static ssize_t adt7316_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE) + return sprintf(buf, "single_channel\n"); + else + return sprintf(buf, "round_robin\n"); +} + +static ssize_t adt7316_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config2; + int ret; + + config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MODE); + if (!memcmp(buf, "single_channel", 14)) + config2 |= ADT7316_AD_SINGLE_CH_MODE; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2); + if (ret) + return -EIO; + + chip->config2 = config2; + + return len; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + adt7316_show_mode, + adt7316_store_mode, + 0); + +static ssize_t adt7316_show_all_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "single_channel\nround_robin\n"); +} + +static IIO_DEVICE_ATTR(all_modes, S_IRUGO, adt7316_show_all_modes, NULL, 0); + +static ssize_t adt7316_show_ad_channel(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) + return -EPERM; + + switch (chip->config2 & ADT7516_AD_SINGLE_CH_MASK) { + case ADT7316_AD_SINGLE_CH_VDD: + return sprintf(buf, "0 - VDD\n"); + case ADT7316_AD_SINGLE_CH_IN: + return sprintf(buf, "1 - Internal Temperature\n"); + case ADT7316_AD_SINGLE_CH_EX: + if (((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) && + (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) + return sprintf(buf, "2 - AIN1\n"); + else + return sprintf(buf, "2 - External Temperature\n"); + case ADT7516_AD_SINGLE_CH_AIN2: + if ((chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) + return sprintf(buf, "3 - AIN2\n"); + else + return sprintf(buf, "N/A\n"); + case ADT7516_AD_SINGLE_CH_AIN3: + if (chip->config1 & ADT7516_SEL_AIN3) + return sprintf(buf, "4 - AIN3\n"); + else + return sprintf(buf, "N/A\n"); + case ADT7516_AD_SINGLE_CH_AIN4: + return sprintf(buf, "5 - AIN4\n"); + default: + return sprintf(buf, "N/A\n"); + }; +} + +static ssize_t adt7316_store_ad_channel(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config2; + unsigned long data = 0; + int ret; + + if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) + return -EPERM; + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) { + if (data > 5) + return -EINVAL; + + config2 = chip->config2 & (~ADT7516_AD_SINGLE_CH_MASK); + } else { + if (data > 2) + return -EINVAL; + + config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MASK); + } + + + config2 |= data; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2); + if (ret) + return -EIO; + + chip->config2 = config2; + + return len; +} + +static IIO_DEVICE_ATTR(ad_channel, S_IRUGO | S_IWUSR, + adt7316_show_ad_channel, + adt7316_store_ad_channel, + 0); + +static ssize_t adt7316_show_all_ad_channels(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) + return -EPERM; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n" + "2 - External Temperature or AIN2\n" + "3 - AIN2\n4 - AIN3\n5 - AIN4\n"); + else + return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n" + "2 - External Temperature\n"); +} + +static IIO_DEVICE_ATTR(all_ad_channels, S_IRUGO, + adt7316_show_all_ad_channels, NULL, 0); + +static ssize_t adt7316_show_disable_averaging(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", + !!(chip->config2 & ADT7316_DISABLE_AVERAGING)); +} + +static ssize_t adt7316_store_disable_averaging(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config2; + int ret; + + config2 = chip->config2 & (~ADT7316_DISABLE_AVERAGING); + if (!memcmp(buf, "1", 1)) + config2 |= ADT7316_DISABLE_AVERAGING; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2); + if (ret) + return -EIO; + + chip->config2 = config2; + + return len; +} + +static IIO_DEVICE_ATTR(disable_averaging, S_IRUGO | S_IWUSR, + adt7316_show_disable_averaging, + adt7316_store_disable_averaging, + 0); + +static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", + !!(chip->config2 & ADT7316_EN_SMBUS_TIMEOUT)); +} + +static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config2; + int ret; + + config2 = chip->config2 & (~ADT7316_EN_SMBUS_TIMEOUT); + if (!memcmp(buf, "1", 1)) + config2 |= ADT7316_EN_SMBUS_TIMEOUT; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2); + if (ret) + return -EIO; + + chip->config2 = config2; + + return len; +} + +static IIO_DEVICE_ATTR(enable_smbus_timeout, S_IRUGO | S_IWUSR, + adt7316_show_enable_smbus_timeout, + adt7316_store_enable_smbus_timeout, + 0); + + +static ssize_t adt7316_store_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config2; + int ret; + + config2 = chip->config2 | ADT7316_RESET; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2); + if (ret) + return -EIO; + + return len; +} + +static IIO_DEVICE_ATTR(reset, S_IWUSR, + NULL, + adt7316_store_reset, + 0); + +static ssize_t adt7316_show_powerdown(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD)); +} + +static ssize_t adt7316_store_powerdown(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config1; + int ret; + + config1 = chip->config1 & (~ADT7316_PD); + if (!memcmp(buf, "1", 1)) + config1 |= ADT7316_PD; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1); + if (ret) + return -EIO; + + chip->config1 = config1; + + return len; +} + +static IIO_DEVICE_ATTR(powerdown, S_IRUGO | S_IWUSR, + adt7316_show_powerdown, + adt7316_store_powerdown, + 0); + +static ssize_t adt7316_show_fast_ad_clock(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5)); +} + +static ssize_t adt7316_store_fast_ad_clock(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config3; + int ret; + + config3 = chip->config3 & (~ADT7316_ADCLK_22_5); + if (!memcmp(buf, "1", 1)) + config3 |= ADT7316_ADCLK_22_5; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); + if (ret) + return -EIO; + + chip->config3 = config3; + + return len; +} + +static IIO_DEVICE_ATTR(fast_ad_clock, S_IRUGO | S_IWUSR, + adt7316_show_fast_ad_clock, + adt7316_store_fast_ad_clock, + 0); + +static ssize_t adt7316_show_da_high_resolution(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) { + if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516) + return sprintf(buf, "1 (12 bits)\n"); + else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517) + return sprintf(buf, "1 (10 bits)\n"); + } + + return sprintf(buf, "0 (8 bits)\n"); +} + +static ssize_t adt7316_store_da_high_resolution(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config3; + int ret; + + chip->dac_bits = 8; + + if (!memcmp(buf, "1", 1)) { + config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION; + if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516) + chip->dac_bits = 12; + else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517) + chip->dac_bits = 10; + } else + config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION); + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); + if (ret) + return -EIO; + + chip->config3 = config3; + + return len; +} + +static IIO_DEVICE_ATTR(da_high_resolution, S_IRUGO | S_IWUSR, + adt7316_show_da_high_resolution, + adt7316_store_da_high_resolution, + 0); + +static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) + return -EPERM; + + return sprintf(buf, "%d\n", + !!(chip->config3 & ADT7516_AIN_IN_VREF)); +} + +static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config3; + int ret; + + if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) + return -EPERM; + + if (memcmp(buf, "1", 1)) + config3 = chip->config3 & (~ADT7516_AIN_IN_VREF); + else + config3 = chip->config3 | ADT7516_AIN_IN_VREF; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); + if (ret) + return -EIO; + + chip->config3 = config3; + + return len; +} + +static IIO_DEVICE_ATTR(AIN_internal_Vref, S_IRUGO | S_IWUSR, + adt7316_show_AIN_internal_Vref, + adt7316_store_AIN_internal_Vref, + 0); + + +static ssize_t adt7316_show_enable_prop_DACA(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", + !!(chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)); +} + +static ssize_t adt7316_store_enable_prop_DACA(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config3; + int ret; + + config3 = chip->config3 & (~ADT7316_EN_IN_TEMP_PROP_DACA); + if (!memcmp(buf, "1", 1)) + config3 |= ADT7316_EN_IN_TEMP_PROP_DACA; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); + if (ret) + return -EIO; + + chip->config3 = config3; + + return len; +} + +static IIO_DEVICE_ATTR(enable_proportion_DACA, S_IRUGO | S_IWUSR, + adt7316_show_enable_prop_DACA, + adt7316_store_enable_prop_DACA, + 0); + +static ssize_t adt7316_show_enable_prop_DACB(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", + !!(chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)); +} + +static ssize_t adt7316_store_enable_prop_DACB(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config3; + int ret; + + config3 = chip->config3 & (~ADT7316_EN_EX_TEMP_PROP_DACB); + if (!memcmp(buf, "1", 1)) + config3 |= ADT7316_EN_EX_TEMP_PROP_DACB; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3); + if (ret) + return -EIO; + + chip->config3 = config3; + + return len; +} + +static IIO_DEVICE_ATTR(enable_proportion_DACB, S_IRUGO | S_IWUSR, + adt7316_show_enable_prop_DACB, + adt7316_store_enable_prop_DACB, + 0); + +static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%x\n", + chip->dac_config & ADT7316_DA_2VREF_CH_MASK); +} + +static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 dac_config; + unsigned long data = 0; + int ret; + + ret = strict_strtoul(buf, 16, &data); + if (ret || data > ADT7316_DA_2VREF_CH_MASK) + return -EINVAL; + + dac_config = chip->dac_config & (~ADT7316_DA_2VREF_CH_MASK); + dac_config |= data; + + ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config); + if (ret) + return -EIO; + + chip->dac_config = dac_config; + + return len; +} + +static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, S_IRUGO | S_IWUSR, + adt7316_show_DAC_2Vref_ch_mask, + adt7316_store_DAC_2Vref_ch_mask, + 0); + +static ssize_t adt7316_show_DAC_update_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) + return sprintf(buf, "manual\n"); + else { + switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) { + case ADT7316_DA_EN_MODE_SINGLE: + return sprintf(buf, "0 - auto at any MSB DAC writing\n"); + case ADT7316_DA_EN_MODE_AB_CD: + return sprintf(buf, "1 - auto at MSB DAC AB and CD writing\n"); + case ADT7316_DA_EN_MODE_ABCD: + return sprintf(buf, "2 - auto at MSB DAC ABCD writing\n"); + default: /* ADT7316_DA_EN_MODE_LDAC */ + return sprintf(buf, "3 - manual\n"); + }; + } +} + +static ssize_t adt7316_store_DAC_update_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 dac_config; + unsigned long data; + int ret; + + if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) + return -EPERM; + + ret = strict_strtoul(buf, 10, &data); + if (ret || data > ADT7316_DA_EN_MODE_MASK) + return -EINVAL; + + dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK); + dac_config |= data; + + ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config); + if (ret) + return -EIO; + + chip->dac_config = dac_config; + + return len; +} + +static IIO_DEVICE_ATTR(DAC_update_mode, S_IRUGO | S_IWUSR, + adt7316_show_DAC_update_mode, + adt7316_store_DAC_update_mode, + 0); + +static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) + return sprintf(buf, "0 - auto at any MSB DAC writing\n" + "1 - auto at MSB DAC AB and CD writing\n" + "2 - auto at MSB DAC ABCD writing\n" + "3 - manual\n"); + else + return sprintf(buf, "manual\n"); +} + +static IIO_DEVICE_ATTR(all_DAC_update_modes, S_IRUGO, + adt7316_show_all_DAC_update_modes, NULL, 0); + + +static ssize_t adt7316_store_update_DAC(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 ldac_config; + unsigned long data; + int ret; + + if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) { + if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) != + ADT7316_DA_EN_MODE_LDAC) + return -EPERM; + + ret = strict_strtoul(buf, 16, &data); + if (ret || data > ADT7316_LDAC_EN_DA_MASK) + return -EINVAL; + + ldac_config = chip->ldac_config & (~ADT7316_LDAC_EN_DA_MASK); + ldac_config |= data; + + ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, + ldac_config); + if (ret) + return -EIO; + } else { + gpio_set_value(chip->ldac_pin, 0); + gpio_set_value(chip->ldac_pin, 1); + } + + return len; +} + +static IIO_DEVICE_ATTR(update_DAC, S_IRUGO | S_IWUSR, + NULL, + adt7316_store_update_DAC, + 0); + +static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return -EPERM; + + return sprintf(buf, "%d\n", + !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_AB)); +} + +static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 dac_config; + int ret; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return -EPERM; + + dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB); + if (!memcmp(buf, "1", 1)) + dac_config |= ADT7316_VREF_BYPASS_DAC_AB; + + ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config); + if (ret) + return -EIO; + + chip->dac_config = dac_config; + + return len; +} + +static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, S_IRUGO | S_IWUSR, + adt7316_show_DA_AB_Vref_bypass, + adt7316_store_DA_AB_Vref_bypass, + 0); + +static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return -EPERM; + + return sprintf(buf, "%d\n", + !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_CD)); +} + +static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 dac_config; + int ret; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return -EPERM; + + dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD); + if (!memcmp(buf, "1", 1)) + dac_config |= ADT7316_VREF_BYPASS_DAC_CD; + + ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config); + if (ret) + return -EIO; + + chip->dac_config = dac_config; + + return len; +} + +static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, S_IRUGO | S_IWUSR, + adt7316_show_DA_CD_Vref_bypass, + adt7316_store_DA_CD_Vref_bypass, + 0); + +static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return sprintf(buf, "0x%x\n", + (chip->dac_config & ADT7516_DAC_IN_VREF_MASK) >> + ADT7516_DAC_IN_VREF_OFFSET); + else + return sprintf(buf, "%d\n", + !!(chip->dac_config & ADT7316_DAC_IN_VREF)); +} + +static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 ldac_config; + unsigned long data; + int ret; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) { + ret = strict_strtoul(buf, 16, &data); + if (ret || data > 3) + return -EINVAL; + + ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK); + if (data & 0x1) + ldac_config |= ADT7516_DAC_AB_IN_VREF; + else if (data & 0x2) + ldac_config |= ADT7516_DAC_CD_IN_VREF; + } else { + ret = strict_strtoul(buf, 16, &data); + if (ret) + return -EINVAL; + + ldac_config = chip->ldac_config & (~ADT7316_DAC_IN_VREF); + if (data) + ldac_config = chip->ldac_config | ADT7316_DAC_IN_VREF; + } + + ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, ldac_config); + if (ret) + return -EIO; + + chip->ldac_config = ldac_config; + + return len; +} + +static IIO_DEVICE_ATTR(DAC_internal_Vref, S_IRUGO | S_IWUSR, + adt7316_show_DAC_internal_Vref, + adt7316_store_DAC_internal_Vref, + 0); + +static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip, + int channel, char *buf) +{ + u16 data; + u8 msb, lsb; + char sign = ' '; + int ret; + + if ((chip->config2 & ADT7316_AD_SINGLE_CH_MODE) && + channel != (chip->config2 & ADT7516_AD_SINGLE_CH_MASK)) + return -EPERM; + + switch (channel) { + case ADT7316_AD_SINGLE_CH_IN: + ret = chip->bus.read(chip->bus.client, + ADT7316_LSB_IN_TEMP_VDD, &lsb); + if (ret) + return -EIO; + + ret = chip->bus.read(chip->bus.client, + ADT7316_AD_MSB_DATA_BASE + channel, &msb); + if (ret) + return -EIO; + + data = msb << ADT7316_T_VALUE_FLOAT_OFFSET; + data |= lsb & ADT7316_LSB_IN_TEMP_MASK; + break; + case ADT7316_AD_SINGLE_CH_VDD: + ret = chip->bus.read(chip->bus.client, + ADT7316_LSB_IN_TEMP_VDD, &lsb); + if (ret) + return -EIO; + + ret = chip->bus.read(chip->bus.client, + + ADT7316_AD_MSB_DATA_BASE + channel, &msb); + if (ret) + return -EIO; + + data = msb << ADT7316_T_VALUE_FLOAT_OFFSET; + data |= (lsb & ADT7316_LSB_VDD_MASK) >> ADT7316_LSB_VDD_OFFSET; + return sprintf(buf, "%d\n", data); + default: /* ex_temp and ain */ + ret = chip->bus.read(chip->bus.client, + ADT7316_LSB_EX_TEMP_AIN, &lsb); + if (ret) + return -EIO; + + ret = chip->bus.read(chip->bus.client, + ADT7316_AD_MSB_DATA_BASE + channel, &msb); + if (ret) + return -EIO; + + data = msb << ADT7316_T_VALUE_FLOAT_OFFSET; + data |= lsb & (ADT7316_LSB_EX_TEMP_MASK << + (ADT7516_LSB_AIN_SHIFT * (channel - + (ADT7316_MSB_EX_TEMP - ADT7316_AD_MSB_DATA_BASE)))); + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + return sprintf(buf, "%d\n", data); + else + break; + }; + + if (data & ADT7316_T_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (ADT7316_T_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + (data >> ADT7316_T_VALUE_FLOAT_OFFSET), + (data & ADT7316_T_VALUE_FLOAT_MASK) * 25); +} + +static ssize_t adt7316_show_VDD(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf); +} +static IIO_DEVICE_ATTR(VDD, S_IRUGO, adt7316_show_VDD, NULL, 0); + +static ssize_t adt7316_show_in_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf); +} + +static IIO_DEVICE_ATTR(in_temp, S_IRUGO, adt7316_show_in_temp, NULL, 0); + +static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf); +} + +static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0); +static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0); + +static ssize_t adt7316_show_AIN2(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf); +} +static IIO_DEVICE_ATTR(AIN2, S_IRUGO, adt7316_show_AIN2, NULL, 0); + +static ssize_t adt7316_show_AIN3(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf); +} +static IIO_DEVICE_ATTR(AIN3, S_IRUGO, adt7316_show_AIN3, NULL, 0); + +static ssize_t adt7316_show_AIN4(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf); +} +static IIO_DEVICE_ATTR(AIN4, S_IRUGO, adt7316_show_AIN4, NULL, 0); + +static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip, + int offset_addr, char *buf) +{ + int data; + u8 val; + int ret; + + ret = chip->bus.read(chip->bus.client, offset_addr, &val); + if (ret) + return -EIO; + + data = (int)val; + if (val & 0x80) + data -= 256; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip, + int offset_addr, const char *buf, size_t len) +{ + long data; + u8 val; + int ret; + + ret = strict_strtol(buf, 10, &data); + if (ret || data > 127 || data < -128) + return -EINVAL; + + if (data < 0) + data += 256; + + val = (u8)data; + + ret = chip->bus.write(chip->bus.client, offset_addr, val); + if (ret) + return -EIO; + + return len; +} + +static ssize_t adt7316_show_in_temp_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf); +} + +static ssize_t adt7316_store_in_temp_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len); +} + +static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR, + adt7316_show_in_temp_offset, + adt7316_store_in_temp_offset, 0); + +static ssize_t adt7316_show_ex_temp_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf); +} + +static ssize_t adt7316_store_ex_temp_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len); +} + +static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR, + adt7316_show_ex_temp_offset, + adt7316_store_ex_temp_offset, 0); + +static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_temp_offset(chip, + ADT7316_IN_ANALOG_TEMP_OFFSET, buf); +} + +static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_temp_offset(chip, + ADT7316_IN_ANALOG_TEMP_OFFSET, buf, len); +} + +static IIO_DEVICE_ATTR(in_analog_temp_offset, S_IRUGO | S_IWUSR, + adt7316_show_in_analog_temp_offset, + adt7316_store_in_analog_temp_offset, 0); + +static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_temp_offset(chip, + ADT7316_EX_ANALOG_TEMP_OFFSET, buf); +} + +static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_temp_offset(chip, + ADT7316_EX_ANALOG_TEMP_OFFSET, buf, len); +} + +static IIO_DEVICE_ATTR(ex_analog_temp_offset, S_IRUGO | S_IWUSR, + adt7316_show_ex_analog_temp_offset, + adt7316_store_ex_analog_temp_offset, 0); + +static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip, + int channel, char *buf) +{ + u16 data; + u8 msb, lsb, offset; + int ret; + + if (channel >= ADT7316_DA_MSB_DATA_REGS || + (channel == 0 && + (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) || + (channel == 1 && + (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB))) + return -EPERM; + + offset = chip->dac_bits - 8; + + if (chip->dac_bits > 8) { + ret = chip->bus.read(chip->bus.client, + ADT7316_DA_DATA_BASE + channel * 2, &lsb); + if (ret) + return -EIO; + } + + ret = chip->bus.read(chip->bus.client, + ADT7316_DA_DATA_BASE + 1 + channel * 2, &msb); + if (ret) + return -EIO; + + data = (msb << offset) + (lsb & ((1 << offset) - 1)); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip, + int channel, const char *buf, size_t len) +{ + u8 msb, lsb, offset; + unsigned long data; + int ret; + + if (channel >= ADT7316_DA_MSB_DATA_REGS || + (channel == 0 && + (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) || + (channel == 1 && + (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB))) + return -EPERM; + + offset = chip->dac_bits - 8; + + ret = strict_strtoul(buf, 10, &data); + if (ret || data >= (1 << chip->dac_bits)) + return -EINVAL; + + if (chip->dac_bits > 8) { + lsb = data & (1 << offset); + ret = chip->bus.write(chip->bus.client, + ADT7316_DA_DATA_BASE + channel * 2, lsb); + if (ret) + return -EIO; + } + + msb = data >> offset; + ret = chip->bus.write(chip->bus.client, + ADT7316_DA_DATA_BASE + 1 + channel * 2, msb); + if (ret) + return -EIO; + + return len; +} + +static ssize_t adt7316_show_DAC_A(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_DAC(chip, 0, buf); +} + +static ssize_t adt7316_store_DAC_A(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_DAC(chip, 0, buf, len); +} + +static IIO_DEVICE_ATTR(DAC_A, S_IRUGO | S_IWUSR, adt7316_show_DAC_A, + adt7316_store_DAC_A, 0); + +static ssize_t adt7316_show_DAC_B(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_DAC(chip, 1, buf); +} + +static ssize_t adt7316_store_DAC_B(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_DAC(chip, 1, buf, len); +} + +static IIO_DEVICE_ATTR(DAC_B, S_IRUGO | S_IWUSR, adt7316_show_DAC_B, + adt7316_store_DAC_B, 0); + +static ssize_t adt7316_show_DAC_C(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_DAC(chip, 2, buf); +} + +static ssize_t adt7316_store_DAC_C(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_DAC(chip, 2, buf, len); +} + +static IIO_DEVICE_ATTR(DAC_C, S_IRUGO | S_IWUSR, adt7316_show_DAC_C, + adt7316_store_DAC_C, 0); + +static ssize_t adt7316_show_DAC_D(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_show_DAC(chip, 3, buf); +} + +static ssize_t adt7316_store_DAC_D(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return adt7316_store_DAC(chip, 3, buf, len); +} + +static IIO_DEVICE_ATTR(DAC_D, S_IRUGO | S_IWUSR, adt7316_show_DAC_D, + adt7316_store_DAC_D, 0); + +static ssize_t adt7316_show_device_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 id; + int ret; + + ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_ID, &id); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", id); +} + +static IIO_DEVICE_ATTR(device_id, S_IRUGO, adt7316_show_device_id, NULL, 0); + +static ssize_t adt7316_show_manufactorer_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 id; + int ret; + + ret = chip->bus.read(chip->bus.client, ADT7316_MANUFACTURE_ID, &id); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", id); +} + +static IIO_DEVICE_ATTR(manufactorer_id, S_IRUGO, + adt7316_show_manufactorer_id, NULL, 0); + +static ssize_t adt7316_show_device_rev(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 rev; + int ret; + + ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_REV, &rev); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", rev); +} + +static IIO_DEVICE_ATTR(device_rev, S_IRUGO, adt7316_show_device_rev, NULL, 0); + +static ssize_t adt7316_show_bus_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 stat; + int ret; + + ret = chip->bus.read(chip->bus.client, ADT7316_SPI_LOCK_STAT, &stat); + if (ret) + return -EIO; + + if (stat) + return sprintf(buf, "spi\n"); + else + return sprintf(buf, "i2c\n"); +} + +static IIO_DEVICE_ATTR(bus_type, S_IRUGO, adt7316_show_bus_type, NULL, 0); + +static ssize_t adt7316_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, adt7316_show_name, NULL, 0); + +static struct attribute *adt7316_attributes[] = { + &iio_dev_attr_all_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_dev_attr_enabled.dev_attr.attr, + &iio_dev_attr_ad_channel.dev_attr.attr, + &iio_dev_attr_all_ad_channels.dev_attr.attr, + &iio_dev_attr_disable_averaging.dev_attr.attr, + &iio_dev_attr_enable_smbus_timeout.dev_attr.attr, + &iio_dev_attr_powerdown.dev_attr.attr, + &iio_dev_attr_fast_ad_clock.dev_attr.attr, + &iio_dev_attr_da_high_resolution.dev_attr.attr, + &iio_dev_attr_enable_proportion_DACA.dev_attr.attr, + &iio_dev_attr_enable_proportion_DACB.dev_attr.attr, + &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr, + &iio_dev_attr_DAC_update_mode.dev_attr.attr, + &iio_dev_attr_all_DAC_update_modes.dev_attr.attr, + &iio_dev_attr_update_DAC.dev_attr.attr, + &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr, + &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr, + &iio_dev_attr_DAC_internal_Vref.dev_attr.attr, + &iio_dev_attr_VDD.dev_attr.attr, + &iio_dev_attr_in_temp.dev_attr.attr, + &iio_dev_attr_ex_temp.dev_attr.attr, + &iio_dev_attr_in_temp_offset.dev_attr.attr, + &iio_dev_attr_ex_temp_offset.dev_attr.attr, + &iio_dev_attr_in_analog_temp_offset.dev_attr.attr, + &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr, + &iio_dev_attr_DAC_A.dev_attr.attr, + &iio_dev_attr_DAC_B.dev_attr.attr, + &iio_dev_attr_DAC_C.dev_attr.attr, + &iio_dev_attr_DAC_D.dev_attr.attr, + &iio_dev_attr_device_id.dev_attr.attr, + &iio_dev_attr_manufactorer_id.dev_attr.attr, + &iio_dev_attr_device_rev.dev_attr.attr, + &iio_dev_attr_bus_type.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group adt7316_attribute_group = { + .attrs = adt7316_attributes, +}; + +static struct attribute *adt7516_attributes[] = { + &iio_dev_attr_all_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_select_ex_temp.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_dev_attr_enabled.dev_attr.attr, + &iio_dev_attr_ad_channel.dev_attr.attr, + &iio_dev_attr_all_ad_channels.dev_attr.attr, + &iio_dev_attr_disable_averaging.dev_attr.attr, + &iio_dev_attr_enable_smbus_timeout.dev_attr.attr, + &iio_dev_attr_powerdown.dev_attr.attr, + &iio_dev_attr_fast_ad_clock.dev_attr.attr, + &iio_dev_attr_AIN_internal_Vref.dev_attr.attr, + &iio_dev_attr_da_high_resolution.dev_attr.attr, + &iio_dev_attr_enable_proportion_DACA.dev_attr.attr, + &iio_dev_attr_enable_proportion_DACB.dev_attr.attr, + &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr, + &iio_dev_attr_DAC_update_mode.dev_attr.attr, + &iio_dev_attr_all_DAC_update_modes.dev_attr.attr, + &iio_dev_attr_update_DAC.dev_attr.attr, + &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr, + &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr, + &iio_dev_attr_DAC_internal_Vref.dev_attr.attr, + &iio_dev_attr_VDD.dev_attr.attr, + &iio_dev_attr_in_temp.dev_attr.attr, + &iio_dev_attr_ex_temp_AIN1.dev_attr.attr, + &iio_dev_attr_AIN2.dev_attr.attr, + &iio_dev_attr_AIN3.dev_attr.attr, + &iio_dev_attr_AIN4.dev_attr.attr, + &iio_dev_attr_in_temp_offset.dev_attr.attr, + &iio_dev_attr_ex_temp_offset.dev_attr.attr, + &iio_dev_attr_in_analog_temp_offset.dev_attr.attr, + &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr, + &iio_dev_attr_DAC_A.dev_attr.attr, + &iio_dev_attr_DAC_B.dev_attr.attr, + &iio_dev_attr_DAC_C.dev_attr.attr, + &iio_dev_attr_DAC_D.dev_attr.attr, + &iio_dev_attr_device_id.dev_attr.attr, + &iio_dev_attr_manufactorer_id.dev_attr.attr, + &iio_dev_attr_device_rev.dev_attr.attr, + &iio_dev_attr_bus_type.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group adt7516_attribute_group = { + .attrs = adt7516_attributes, +}; + + +/* + * temperature bound events + */ + +#define IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_ADT7316_IN_TEMP_LOW IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_ADT7316_EX_TEMP_HIGH IIO_BUFFER_EVENT_CODE(2) +#define IIO_EVENT_CODE_ADT7316_EX_TEMP_LOW IIO_BUFFER_EVENT_CODE(3) +#define IIO_EVENT_CODE_ADT7316_EX_TEMP_FAULT IIO_BUFFER_EVENT_CODE(4) +#define IIO_EVENT_CODE_ADT7516_AIN1 IIO_BUFFER_EVENT_CODE(5) +#define IIO_EVENT_CODE_ADT7516_AIN2 IIO_BUFFER_EVENT_CODE(6) +#define IIO_EVENT_CODE_ADT7516_AIN3 IIO_BUFFER_EVENT_CODE(7) +#define IIO_EVENT_CODE_ADT7516_AIN4 IIO_BUFFER_EVENT_CODE(8) +#define IIO_EVENT_CODE_ADT7316_VDD IIO_BUFFER_EVENT_CODE(9) + +static void adt7316_interrupt_bh(struct work_struct *work_s) +{ + struct adt7316_chip_info *chip = + container_of(work_s, struct adt7316_chip_info, thresh_work); + u8 stat1, stat2; + int i, ret, count; + + ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT1, &stat1); + if (!ret) { + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + count = 8; + else + count = 5; + + for (i = 0; i < count; i++) { + if (stat1 & (1 << i)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH + i, + chip->last_timestamp); + } + } + + ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT2, &stat2); + if (!ret) { + if (stat2 & ADT7316_INT_MASK2_VDD) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7316_VDD, + chip->last_timestamp); + } + + enable_irq(chip->bus.irq); +} + +static int adt7316_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adt7316_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(adt7316, &adt7316_interrupt); + +/* + * Show mask of enabled interrupts in Hex. + */ +static ssize_t adt7316_show_int_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%x\n", chip->int_mask); +} + +/* + * Set 1 to the mask in Hex to enabled interrupts. + */ +static ssize_t adt7316_set_int_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + u8 mask; + + ret = strict_strtoul(buf, 16, &data); + if (ret || data >= ADT7316_VDD_INT_MASK + 1) + return -EINVAL; + + if (data & ADT7316_VDD_INT_MASK) + mask = 0; /* enable vdd int */ + else + mask = ADT7316_INT_MASK2_VDD; /* disable vdd int */ + + ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK2, mask); + if (!ret) { + chip->int_mask &= ~ADT7316_VDD_INT_MASK; + chip->int_mask |= data & ADT7316_VDD_INT_MASK; + } + + if (data & ADT7316_TEMP_AIN_INT_MASK) { + if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX) + /* mask in reg is opposite, set 1 to disable */ + mask = (~data) & ADT7316_TEMP_INT_MASK; + else + /* mask in reg is opposite, set 1 to disable */ + mask = (~data) & ADT7316_TEMP_AIN_INT_MASK; + } + ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK1, mask); + + chip->int_mask = mask; + + return len; +} +static inline ssize_t adt7316_show_ad_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 val; + int data; + int ret; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX && + bound_reg > ADT7316_EX_TEMP_LOW) + return -EPERM; + + ret = chip->bus.read(chip->bus.client, bound_reg, &val); + if (ret) + return -EIO; + + data = (int)val; + + if (!((chip->id & ID_FAMILY_MASK) == ID_ADT75XX && + (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)) { + if (data & 0x80) + data -= 256; + } + + return sprintf(buf, "%d\n", data); +} + +static inline ssize_t adt7316_set_ad_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + long data; + u8 val; + int ret; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX && + bound_reg > ADT7316_EX_TEMP_LOW) + return -EPERM; + + ret = strict_strtol(buf, 10, &data); + if (ret) + return -EINVAL; + + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX && + (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) { + if (data > 255 || data < 0) + return -EINVAL; + } else { + if (data > 127 || data < -128) + return -EINVAL; + + if (data < 0) + data += 256; + } + + val = (u8)data; + + ret = chip->bus.write(chip->bus.client, bound_reg, val); + if (ret) + return -EIO; + + return len; +} + +static ssize_t adt7316_show_in_temp_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7316_IN_TEMP_HIGH, buf); +} + +static inline ssize_t adt7316_set_in_temp_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7316_IN_TEMP_HIGH, buf, len); +} + +static ssize_t adt7316_show_in_temp_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7316_IN_TEMP_LOW, buf); +} + +static inline ssize_t adt7316_set_in_temp_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7316_IN_TEMP_LOW, buf, len); +} + +static ssize_t adt7316_show_ex_temp_ain1_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7316_EX_TEMP_HIGH, buf); +} + +static inline ssize_t adt7316_set_ex_temp_ain1_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7316_EX_TEMP_HIGH, buf, len); +} + +static ssize_t adt7316_show_ex_temp_ain1_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7316_EX_TEMP_LOW, buf); +} + +static inline ssize_t adt7316_set_ex_temp_ain1_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7316_EX_TEMP_LOW, buf, len); +} + +static ssize_t adt7316_show_ain2_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7516_AIN2_HIGH, buf); +} + +static inline ssize_t adt7316_set_ain2_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7516_AIN2_HIGH, buf, len); +} + +static ssize_t adt7316_show_ain2_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7516_AIN2_LOW, buf); +} + +static inline ssize_t adt7316_set_ain2_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7516_AIN2_LOW, buf, len); +} + +static ssize_t adt7316_show_ain3_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7516_AIN3_HIGH, buf); +} + +static inline ssize_t adt7316_set_ain3_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7516_AIN3_HIGH, buf, len); +} + +static ssize_t adt7316_show_ain3_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7516_AIN3_LOW, buf); +} + +static inline ssize_t adt7316_set_ain3_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7516_AIN3_LOW, buf, len); +} + +static ssize_t adt7316_show_ain4_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7516_AIN4_HIGH, buf); +} + +static inline ssize_t adt7316_set_ain4_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7516_AIN4_HIGH, buf, len); +} + +static ssize_t adt7316_show_ain4_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7316_show_ad_bound(dev, attr, + ADT7516_AIN4_LOW, buf); +} + +static inline ssize_t adt7316_set_ain4_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7316_set_ad_bound(dev, attr, + ADT7516_AIN4_LOW, buf, len); +} + +static ssize_t adt7316_show_int_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN)); +} + +static ssize_t adt7316_set_int_enabled(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + u8 config1; + int ret; + + config1 = chip->config1 & (~ADT7316_INT_EN); + if (!memcmp(buf, "1", 1)) + config1 |= ADT7316_INT_EN; + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1); + if (ret) + return -EIO; + + chip->config1 = config1; + + return len; +} + + +IIO_EVENT_ATTR_SH(int_mask, iio_event_adt7316, + adt7316_show_int_mask, adt7316_set_int_mask, 0); +IIO_EVENT_ATTR_SH(in_temp_high, iio_event_adt7316, + adt7316_show_in_temp_high, adt7316_set_in_temp_high, 0); +IIO_EVENT_ATTR_SH(in_temp_low, iio_event_adt7316, + adt7316_show_in_temp_low, adt7316_set_in_temp_low, 0); +IIO_EVENT_ATTR_SH(ex_temp_high, iio_event_adt7316, + adt7316_show_ex_temp_ain1_high, + adt7316_set_ex_temp_ain1_high, 0); +IIO_EVENT_ATTR_SH(ex_temp_low, iio_event_adt7316, + adt7316_show_ex_temp_ain1_low, + adt7316_set_ex_temp_ain1_low, 0); +IIO_EVENT_ATTR_SH(ex_temp_ain1_high, iio_event_adt7316, + adt7316_show_ex_temp_ain1_high, + adt7316_set_ex_temp_ain1_high, 0); +IIO_EVENT_ATTR_SH(ex_temp_ain1_low, iio_event_adt7316, + adt7316_show_ex_temp_ain1_low, + adt7316_set_ex_temp_ain1_low, 0); +IIO_EVENT_ATTR_SH(ain2_high, iio_event_adt7316, + adt7316_show_ain2_high, adt7316_set_ain2_high, 0); +IIO_EVENT_ATTR_SH(ain2_low, iio_event_adt7316, + adt7316_show_ain2_low, adt7316_set_ain2_low, 0); +IIO_EVENT_ATTR_SH(ain3_high, iio_event_adt7316, + adt7316_show_ain3_high, adt7316_set_ain3_high, 0); +IIO_EVENT_ATTR_SH(ain3_low, iio_event_adt7316, + adt7316_show_ain3_low, adt7316_set_ain3_low, 0); +IIO_EVENT_ATTR_SH(ain4_high, iio_event_adt7316, + adt7316_show_ain4_high, adt7316_set_ain4_high, 0); +IIO_EVENT_ATTR_SH(ain4_low, iio_event_adt7316, + adt7316_show_ain4_low, adt7316_set_ain4_low, 0); +IIO_EVENT_ATTR_SH(int_enabled, iio_event_adt7316, + adt7316_show_int_enabled, adt7316_set_int_enabled, 0); + +static struct attribute *adt7316_event_attributes[] = { + &iio_event_attr_int_mask.dev_attr.attr, + &iio_event_attr_in_temp_high.dev_attr.attr, + &iio_event_attr_in_temp_low.dev_attr.attr, + &iio_event_attr_ex_temp_high.dev_attr.attr, + &iio_event_attr_ex_temp_low.dev_attr.attr, + &iio_event_attr_int_enabled.dev_attr.attr, + NULL, +}; + +static struct attribute_group adt7316_event_attribute_group = { + .attrs = adt7316_event_attributes, +}; + +static struct attribute *adt7516_event_attributes[] = { + &iio_event_attr_int_mask.dev_attr.attr, + &iio_event_attr_in_temp_high.dev_attr.attr, + &iio_event_attr_in_temp_low.dev_attr.attr, + &iio_event_attr_ex_temp_ain1_high.dev_attr.attr, + &iio_event_attr_ex_temp_ain1_low.dev_attr.attr, + &iio_event_attr_ain2_high.dev_attr.attr, + &iio_event_attr_ain2_low.dev_attr.attr, + &iio_event_attr_ain3_high.dev_attr.attr, + &iio_event_attr_ain3_low.dev_attr.attr, + &iio_event_attr_ain4_high.dev_attr.attr, + &iio_event_attr_ain4_low.dev_attr.attr, + &iio_event_attr_int_enabled.dev_attr.attr, + NULL, +}; + +static struct attribute_group adt7516_event_attribute_group = { + .attrs = adt7516_event_attributes, +}; + +#ifdef CONFIG_PM +int adt7316_disable(struct device *dev) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return _adt7316_store_enabled(chip, 0); +} +EXPORT_SYMBOL(adt7316_disable); + +int adt7316_enable(struct device *dev) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + + return _adt7316_store_enabled(chip, 1); +} +EXPORT_SYMBOL(adt7316_enable); +#endif + +/* + * device probe and remove + */ +int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus, + const char *name) +{ + struct adt7316_chip_info *chip; + unsigned short *adt7316_platform_data = dev->platform_data; + int ret = 0; + + chip = kzalloc(sizeof(struct adt7316_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + dev_set_drvdata(dev, chip); + + chip->bus = *bus; + chip->name = name; + + if (name[4] == '3') + chip->id = ID_ADT7316 + (name[6] - '6'); + else if (name[4] == '5') + chip->id = ID_ADT7516 + (name[6] - '6'); + else + return -ENODEV; + + chip->ldac_pin = adt7316_platform_data[1]; + if (chip->ldac_pin) { + chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA; + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + chip->config1 |= ADT7516_SEL_AIN3; + } + chip->int_mask = ADT7316_TEMP_INT_MASK | ADT7316_VDD_INT_MASK; + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) + chip->int_mask |= ADT7516_AIN_INT_MASK; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + chip->indio_dev->dev.parent = dev; + if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) { + chip->indio_dev->attrs = &adt7516_attribute_group; + chip->indio_dev->event_attrs = &adt7516_event_attribute_group; + } else { + chip->indio_dev->attrs = &adt7316_attribute_group; + chip->indio_dev->event_attrs = &adt7316_event_attribute_group; + } + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + if (chip->bus.irq > 0) { + if (adt7316_platform_data[0]) + chip->bus.irq_flags = adt7316_platform_data[0]; + + ret = iio_register_interrupt_line(chip->bus.irq, + chip->indio_dev, + 0, + chip->bus.irq_flags, + chip->name); + if (ret) + goto error_unreg_dev; + + /* + * The event handler list element refer to iio_event_adt7316. + * All event attributes bind to the same event handler. + * So, only register event handler once. + */ + iio_add_event_to_list(&iio_event_adt7316, + &chip->indio_dev->interrupts[0]->ev_list); + + INIT_WORK(&chip->thresh_work, adt7316_interrupt_bh); + + if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH) + chip->config1 |= ADT7316_INT_POLARITY; + } + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1); + if (ret) { + ret = -EIO; + goto error_unreg_irq; + } + + ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3); + if (ret) { + ret = -EIO; + goto error_unreg_irq; + } + + dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n", + chip->name); + + return 0; + +error_unreg_irq: + iio_unregister_interrupt_line(chip->indio_dev, 0); +error_unreg_dev: + iio_device_unregister(chip->indio_dev); +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); + + return ret; +} +EXPORT_SYMBOL(adt7316_probe); + +int __devexit adt7316_remove(struct device *dev) +{ + + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7316_chip_info *chip = dev_info->dev_data; + struct iio_dev *indio_dev = chip->indio_dev; + + dev_set_drvdata(dev, NULL); + if (chip->bus.irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + kfree(chip); + + return 0; +} +EXPORT_SYMBOL(adt7316_remove); + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices ADT7316/7/8 and ADT7516/7/9 digital" + " temperature sensor, ADC and DAC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h new file mode 100644 index 000000000000..d34bd679bb4e --- /dev/null +++ b/drivers/staging/iio/addac/adt7316.h @@ -0,0 +1,33 @@ +/* + * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _ADT7316_H_ +#define _ADT7316_H_ + +#include + +#define ADT7316_REG_MAX_ADDR 0x3F + +struct adt7316_bus { + void *client; + int irq; + int irq_flags; + int (*read) (void *client, u8 reg, u8 *data); + int (*write) (void *client, u8 reg, u8 val); + int (*multi_read) (void *client, u8 first_reg, u8 count, u8 *data); + int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data); +}; + +#ifdef CONFIG_PM +int adt7316_disable(struct device *dev); +int adt7316_enable(struct device *dev); +#endif +int adt7316_probe(struct device *dev, struct adt7316_bus *bus, const char *name); +int adt7316_remove(struct device *dev); + +#endif -- cgit v1.2.3 From 54c5be349bf66ed0c50c2e293803057d148a4c95 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:43:53 -0400 Subject: staging: iio: adc: new driver for AD7150/1/6 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 2 + drivers/staging/iio/adc/ad7150.c | 877 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 886 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7150.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index acb67677e563..51b9cc654c86 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -27,6 +27,13 @@ config MAX1363_RING_BUFFER Say yes here to include ring buffer support in the MAX1363 ADC driver. +config AD7150 + tristate "Analog Devices ad7150/1/6 capacitive sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices capacitive sensors. + (ad7150, ad7151, ad7156) Provides direct access via sysfs. + config AD799X tristate "Analog Devices AD799x ADC driver" depends on I2C diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index b62c319bcedd..51b39aab061a 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -14,3 +14,5 @@ obj-$(CONFIG_AD799X) += ad799x.o ad7476-y := ad7476_core.o ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o obj-$(CONFIG_AD7476) += ad7476.o + +obj-$(CONFIG_AD7150) += ad7150.o diff --git a/drivers/staging/iio/adc/ad7150.c b/drivers/staging/iio/adc/ad7150.c new file mode 100644 index 000000000000..8555766109d8 --- /dev/null +++ b/drivers/staging/iio/adc/ad7150.c @@ -0,0 +1,877 @@ +/* + * AD7150 capacitive sensor driver supporting AD7150/1/6 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD7150 registers definition + */ + +#define AD7150_STATUS 0 +#define AD7150_STATUS_OUT1 (1 << 3) +#define AD7150_STATUS_OUT2 (1 << 5) +#define AD7150_CH1_DATA_HIGH 1 +#define AD7150_CH1_DATA_LOW 2 +#define AD7150_CH2_DATA_HIGH 3 +#define AD7150_CH2_DATA_LOW 4 +#define AD7150_CH1_AVG_HIGH 5 +#define AD7150_CH1_AVG_LOW 6 +#define AD7150_CH2_AVG_HIGH 7 +#define AD7150_CH2_AVG_LOW 8 +#define AD7150_CH1_SENSITIVITY 9 +#define AD7150_CH1_THR_HOLD_H 9 +#define AD7150_CH1_TIMEOUT 10 +#define AD7150_CH1_THR_HOLD_L 10 +#define AD7150_CH1_SETUP 11 +#define AD7150_CH2_SENSITIVITY 12 +#define AD7150_CH2_THR_HOLD_H 12 +#define AD7150_CH2_TIMEOUT 13 +#define AD7150_CH2_THR_HOLD_L 13 +#define AD7150_CH2_SETUP 14 +#define AD7150_CFG 15 +#define AD7150_CFG_FIX (1 << 7) +#define AD7150_PD_TIMER 16 +#define AD7150_CH1_CAPDAC 17 +#define AD7150_CH2_CAPDAC 18 +#define AD7150_SN3 19 +#define AD7150_SN2 20 +#define AD7150_SN1 21 +#define AD7150_SN0 22 +#define AD7150_ID 23 + +#define AD7150_MAX_CONV_MODE 4 + +/* + * struct ad7150_chip_info - chip specifc information + */ + +struct ad7150_chip_info { + const char *name; + struct i2c_client *client; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + bool inter; + s64 last_timestamp; + u16 ch1_threshold; /* Ch1 Threshold (in fixed threshold mode) */ + u8 ch1_sensitivity; /* Ch1 Sensitivity (in adaptive threshold mode) */ + u8 ch1_timeout; /* Ch1 Timeout (in adaptive threshold mode) */ + u8 ch1_setup; + u16 ch2_threshold; /* Ch2 Threshold (in fixed threshold mode) */ + u8 ch2_sensitivity; /* Ch1 Sensitivity (in adaptive threshold mode) */ + u8 ch2_timeout; /* Ch1 Timeout (in adaptive threshold mode) */ + u8 ch2_setup; + u8 powerdown_timer; + char threshold_mode[10]; /* adaptive/fixed threshold mode */ + int old_state; + char *conversion_mode; +}; + +struct ad7150_conversion_mode { + char *name; + u8 reg_cfg; +}; + +struct ad7150_conversion_mode ad7150_conv_mode_table[AD7150_MAX_CONV_MODE] = { + { "idle", 0 }, + { "continuous-conversion", 1 }, + { "single-conversion", 2 }, + { "power-down", 3 }, +}; + +/* + * ad7150 register access by I2C + */ + +static int ad7150_i2c_read(struct ad7150_chip_info *chip, u8 reg, u8 *data, int len) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_master_send(client, ®, 1); + if (ret < 0) { + dev_err(&client->dev, "I2C write error\n"); + return ret; + } + + ret = i2c_master_recv(client, data, len); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + return ret; +} + +static int ad7150_i2c_write(struct ad7150_chip_info *chip, u8 reg, u8 data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + u8 tx[2] = { + reg, + data, + }; + + ret = i2c_master_send(client, tx, 2); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +/* + * sysfs nodes + */ + +#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \ + IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \ + IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(_show) \ + IIO_DEVICE_ATTR(available_threshold_modes, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_THRESHOLD_MODE(_mode, _show, _store) \ + IIO_DEVICE_ATTR(threshold_mode, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_THRESHOLD(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_threshold, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_THRESHOLD(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_threshold, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_SENSITIVITY(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_sensitivity, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_SENSITIVITY(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_sensitivity, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_TIMEOUT(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_timeout, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_TIMEOUT(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_timeout, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_VALUE(_show) \ + IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CH2_VALUE(_show) \ + IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_POWERDOWN_TIMER(_mode, _show, _store) \ + IIO_DEVICE_ATTR(powerdown_timer, _mode, _show, _store, 0) + +static ssize_t ad7150_show_conversion_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i; + int len = 0; + + for (i = 0; i < AD7150_MAX_CONV_MODE; i++) + len += sprintf(buf + len, "%s\n", ad7150_conv_mode_table[i].name); + + return len; +} + +static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7150_show_conversion_modes); + +static ssize_t ad7150_show_conversion_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%s\n", chip->conversion_mode); +} + +static ssize_t ad7150_store_conversion_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + u8 cfg; + int i; + + ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1); + + for (i = 0; i < AD7150_MAX_CONV_MODE; i++) { + if (strncmp(buf, ad7150_conv_mode_table[i].name, + strlen(ad7150_conv_mode_table[i].name) - 1) == 0) { + chip->conversion_mode = ad7150_conv_mode_table[i].name; + cfg |= 0x18 | ad7150_conv_mode_table[i].reg_cfg; + ad7150_i2c_write(chip, AD7150_CFG, cfg); + return len; + } + } + + dev_err(dev, "not supported conversion mode\n"); + + return -EINVAL; +} + +static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR, + ad7150_show_conversion_mode, + ad7150_store_conversion_mode); + +static ssize_t ad7150_show_threshold_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "adaptive\nfixed\n"); +} + +static IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(ad7150_show_threshold_modes); + +static ssize_t ad7150_show_ch1_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + u8 data[2]; + + ad7150_i2c_read(chip, AD7150_CH1_DATA_HIGH, data, 2); + return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]); +} + +static IIO_DEV_ATTR_CH1_VALUE(ad7150_show_ch1_value); + +static ssize_t ad7150_show_ch2_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + u8 data[2]; + + ad7150_i2c_read(chip, AD7150_CH2_DATA_HIGH, data, 2); + return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]); +} + +static IIO_DEV_ATTR_CH2_VALUE(ad7150_show_ch2_value); + +static ssize_t ad7150_show_threshold_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%s\n", chip->threshold_mode); +} + +static ssize_t ad7150_store_threshold_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + u8 cfg; + + ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1); + + if (strncmp(buf, "fixed", 5) == 0) { + strcpy(chip->threshold_mode, "fixed"); + cfg |= AD7150_CFG_FIX; + ad7150_i2c_write(chip, AD7150_CFG, cfg); + + return len; + } else if (strncmp(buf, "adaptive", 8) == 0) { + strcpy(chip->threshold_mode, "adaptive"); + cfg &= ~AD7150_CFG_FIX; + ad7150_i2c_write(chip, AD7150_CFG, cfg); + + return len; + } + + dev_err(dev, "not supported threshold mode\n"); + return -EINVAL; +} + +static IIO_DEV_ATTR_THRESHOLD_MODE(S_IRUGO | S_IWUSR, + ad7150_show_threshold_mode, + ad7150_store_threshold_mode); + +static ssize_t ad7150_show_ch1_threshold(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch1_threshold); +} + +static ssize_t ad7150_store_ch1_threshold(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_H, data >> 8); + ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_L, data); + chip->ch1_threshold = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_THRESHOLD(S_IRUGO | S_IWUSR, + ad7150_show_ch1_threshold, + ad7150_store_ch1_threshold); + +static ssize_t ad7150_show_ch2_threshold(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch2_threshold); +} + +static ssize_t ad7150_store_ch2_threshold(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_H, data >> 8); + ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_L, data); + chip->ch2_threshold = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_THRESHOLD(S_IRUGO | S_IWUSR, + ad7150_show_ch2_threshold, + ad7150_store_ch2_threshold); + +static ssize_t ad7150_show_ch1_sensitivity(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch1_sensitivity); +} + +static ssize_t ad7150_store_ch1_sensitivity(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7150_i2c_write(chip, AD7150_CH1_SENSITIVITY, data); + chip->ch1_sensitivity = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_SENSITIVITY(S_IRUGO | S_IWUSR, + ad7150_show_ch1_sensitivity, + ad7150_store_ch1_sensitivity); + +static ssize_t ad7150_show_ch2_sensitivity(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch2_sensitivity); +} + +static ssize_t ad7150_store_ch2_sensitivity(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7150_i2c_write(chip, AD7150_CH2_SENSITIVITY, data); + chip->ch2_sensitivity = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_SENSITIVITY(S_IRUGO | S_IWUSR, + ad7150_show_ch2_sensitivity, + ad7150_store_ch2_sensitivity); + +static ssize_t ad7150_show_ch1_timeout(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch1_timeout); +} + +static ssize_t ad7150_store_ch1_timeout(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7150_i2c_write(chip, AD7150_CH1_TIMEOUT, data); + chip->ch1_timeout = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_TIMEOUT(S_IRUGO | S_IWUSR, + ad7150_show_ch1_timeout, + ad7150_store_ch1_timeout); + +static ssize_t ad7150_show_ch2_timeout(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch2_timeout); +} + +static ssize_t ad7150_store_ch2_timeout(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7150_i2c_write(chip, AD7150_CH2_TIMEOUT, data); + chip->ch2_timeout = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_TIMEOUT(S_IRUGO | S_IWUSR, + ad7150_show_ch2_timeout, + ad7150_store_ch2_timeout); + +static ssize_t ad7150_show_ch1_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->ch1_setup); +} + +static ssize_t ad7150_store_ch1_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7150_i2c_write(chip, AD7150_CH1_SETUP, data); + chip->ch1_setup = data; + return len; + } + + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR, + ad7150_show_ch1_setup, + ad7150_store_ch1_setup); + +static ssize_t ad7150_show_ch2_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->ch2_setup); +} + +static ssize_t ad7150_store_ch2_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7150_i2c_write(chip, AD7150_CH2_SETUP, data); + chip->ch2_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR, + ad7150_show_ch2_setup, + ad7150_store_ch2_setup); + +static ssize_t ad7150_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7150_show_name, NULL, 0); + +static ssize_t ad7150_show_powerdown_timer(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->powerdown_timer); +} + +static ssize_t ad7150_store_powerdown_timer(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7150_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x40)) { + chip->powerdown_timer = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_POWERDOWN_TIMER(S_IRUGO | S_IWUSR, + ad7150_show_powerdown_timer, + ad7150_store_powerdown_timer); + +static struct attribute *ad7150_attributes[] = { + &iio_dev_attr_available_threshold_modes.dev_attr.attr, + &iio_dev_attr_threshold_mode.dev_attr.attr, + &iio_dev_attr_ch1_threshold.dev_attr.attr, + &iio_dev_attr_ch2_threshold.dev_attr.attr, + &iio_dev_attr_ch1_timeout.dev_attr.attr, + &iio_dev_attr_ch2_timeout.dev_attr.attr, + &iio_dev_attr_ch1_setup.dev_attr.attr, + &iio_dev_attr_ch2_setup.dev_attr.attr, + &iio_dev_attr_ch1_sensitivity.dev_attr.attr, + &iio_dev_attr_ch2_sensitivity.dev_attr.attr, + &iio_dev_attr_powerdown_timer.dev_attr.attr, + &iio_dev_attr_ch1_value.dev_attr.attr, + &iio_dev_attr_ch2_value.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7150_attribute_group = { + .attrs = ad7150_attributes, +}; + +/* + * threshold events + */ + +#define IIO_EVENT_CODE_CH1_HIGH IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_CH1_LOW IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_CH2_HIGH IIO_BUFFER_EVENT_CODE(2) +#define IIO_EVENT_CODE_CH2_LOW IIO_BUFFER_EVENT_CODE(3) + +#define IIO_EVENT_ATTR_CH1_HIGH_SH(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(ch1_high, _evlist, _show, _store, _mask) + +#define IIO_EVENT_ATTR_CH2_HIGH_SH(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(ch2_high, _evlist, _show, _store, _mask) + +#define IIO_EVENT_ATTR_CH1_LOW_SH(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(ch1_low, _evlist, _show, _store, _mask) + +#define IIO_EVENT_ATTR_CH2_LOW_SH(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(ch2_low, _evlist, _show, _store, _mask) + +static void ad7150_interrupt_handler_bh(struct work_struct *work_s) +{ + struct ad7150_chip_info *chip = + container_of(work_s, struct ad7150_chip_info, thresh_work); + u8 int_status; + + enable_irq(chip->client->irq); + + ad7150_i2c_read(chip, AD7150_STATUS, &int_status, 1); + + if ((int_status & AD7150_STATUS_OUT1) && !(chip->old_state & AD7150_STATUS_OUT1)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_CH1_HIGH, + chip->last_timestamp); + else if ((!(int_status & AD7150_STATUS_OUT1)) && (chip->old_state & AD7150_STATUS_OUT1)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_CH1_LOW, + chip->last_timestamp); + + if ((int_status & AD7150_STATUS_OUT2) && !(chip->old_state & AD7150_STATUS_OUT2)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_CH2_HIGH, + chip->last_timestamp); + else if ((!(int_status & AD7150_STATUS_OUT2)) && (chip->old_state & AD7150_STATUS_OUT2)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_CH2_LOW, + chip->last_timestamp); +} + +static int ad7150_interrupt_handler_th(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ad7150_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(threshold, &ad7150_interrupt_handler_th); + +static ssize_t ad7150_query_out_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* + * AD7150 provides two logic output channels, which can be used as interrupt + * but the pins are not configurable + */ + return sprintf(buf, "1\n"); +} + +static ssize_t ad7150_set_out_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return len; +} + +IIO_EVENT_ATTR_CH1_HIGH_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0); +IIO_EVENT_ATTR_CH2_HIGH_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0); +IIO_EVENT_ATTR_CH1_LOW_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0); +IIO_EVENT_ATTR_CH2_LOW_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0); + +static struct attribute *ad7150_event_attributes[] = { + &iio_event_attr_ch1_high.dev_attr.attr, + &iio_event_attr_ch2_high.dev_attr.attr, + &iio_event_attr_ch1_low.dev_attr.attr, + &iio_event_attr_ch2_low.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7150_event_attribute_group = { + .attrs = ad7150_event_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit ad7150_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0, regdone = 0; + struct ad7150_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, chip); + + chip->client = client; + chip->name = id->name; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + /* Echipabilish that the iio_dev is a child of the i2c device */ + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->attrs = &ad7150_attribute_group; + chip->indio_dev->event_attrs = &ad7150_event_attribute_group; + chip->indio_dev->dev_data = (void *)(chip); + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + regdone = 1; + + if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0) { + ret = iio_register_interrupt_line(client->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "ad7150"); + if (ret) + goto error_free_dev; + + iio_add_event_to_list(iio_event_attr_ch2_low.listel, + &chip->indio_dev->interrupts[0]->ev_list); + + INIT_WORK(&chip->thresh_work, ad7150_interrupt_handler_bh); + } + + dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq); + + return 0; + +error_free_dev: + if (regdone) + iio_device_unregister(chip->indio_dev); + else + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); +error_ret: + return ret; +} + +static int __devexit ad7150_remove(struct i2c_client *client) +{ + struct ad7150_chip_info *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = chip->indio_dev; + + if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id ad7150_id[] = { + { "ad7150", 0 }, + { "ad7151", 0 }, + { "ad7156", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad7150_id); + +static struct i2c_driver ad7150_driver = { + .driver = { + .name = "ad7150", + }, + .probe = ad7150_probe, + .remove = __devexit_p(ad7150_remove), + .id_table = ad7150_id, +}; + +static __init int ad7150_init(void) +{ + return i2c_add_driver(&ad7150_driver); +} + +static __exit void ad7150_exit(void) +{ + i2c_del_driver(&ad7150_driver); +} + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ad7150/1/6 capacitive sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad7150_init); +module_exit(ad7150_exit); -- cgit v1.2.3 From a20ebd930081edaf21f354db195e7bb9820b18d8 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:43:54 -0400 Subject: staging: iio: adc: new driver for AD7152/3 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/ad7152.c | 610 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 618 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7152.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 51b9cc654c86..7f03571227a5 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -34,6 +34,13 @@ config AD7150 Say yes here to build support for Analog Devices capacitive sensors. (ad7150, ad7151, ad7156) Provides direct access via sysfs. +config AD7152 + tristate "Analog Devices ad7152/3 capacitive sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices capacitive sensors. + (ad7152, ad7153) Provides direct access via sysfs. + config AD799X tristate "Analog Devices AD799x ADC driver" depends on I2C diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 51b39aab061a..a13475412371 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -16,3 +16,4 @@ ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7150) += ad7150.o +obj-$(CONFIG_AD7152) += ad7152.o diff --git a/drivers/staging/iio/adc/ad7152.c b/drivers/staging/iio/adc/ad7152.c new file mode 100644 index 000000000000..fa7f84062307 --- /dev/null +++ b/drivers/staging/iio/adc/ad7152.c @@ -0,0 +1,610 @@ +/* + * AD7152 capacitive sensor driver supporting AD7152/3 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD7152 registers definition + */ + +#define AD7152_STATUS 0 +#define AD7152_STATUS_RDY1 (1 << 0) +#define AD7152_STATUS_RDY2 (1 << 1) +#define AD7152_CH1_DATA_HIGH 1 +#define AD7152_CH1_DATA_LOW 2 +#define AD7152_CH2_DATA_HIGH 3 +#define AD7152_CH2_DATA_LOW 4 +#define AD7152_CH1_OFFS_HIGH 5 +#define AD7152_CH1_OFFS_LOW 6 +#define AD7152_CH2_OFFS_HIGH 7 +#define AD7152_CH2_OFFS_LOW 8 +#define AD7152_CH1_GAIN_HIGH 9 +#define AD7152_CH1_GAIN_LOW 10 +#define AD7152_CH1_SETUP 11 +#define AD7152_CH2_GAIN_HIGH 12 +#define AD7152_CH2_GAIN_LOW 13 +#define AD7152_CH2_SETUP 14 +#define AD7152_CFG 15 +#define AD7152_RESEVERD 16 +#define AD7152_CAPDAC_POS 17 +#define AD7152_CAPDAC_NEG 18 +#define AD7152_CFG2 26 + +#define AD7152_MAX_CONV_MODE 6 + +/* + * struct ad7152_chip_info - chip specifc information + */ + +struct ad7152_chip_info { + const char *name; + struct i2c_client *client; + struct iio_dev *indio_dev; + u16 ch1_offset; /* Channel 1 offset calibration coefficient */ + u16 ch1_gain; /* Channel 1 gain coefficient */ + u8 ch1_setup; + u16 ch2_offset; /* Channel 2 offset calibration coefficient */ + u16 ch2_gain; /* Channel 1 gain coefficient */ + u8 ch2_setup; + u8 filter_rate_setup; /* Capacitive channel digital filter setup; conversion time/update rate setup per channel */ + char *conversion_mode; +}; + +struct ad7152_conversion_mode { + char *name; + u8 reg_cfg; +}; + +struct ad7152_conversion_mode ad7152_conv_mode_table[AD7152_MAX_CONV_MODE] = { + { "idle", 0 }, + { "continuous-conversion", 1 }, + { "single-conversion", 2 }, + { "power-down", 3 }, + { "offset-calibration", 5 }, + { "gain-calibration", 6 }, +}; + +/* + * ad7152 register access by I2C + */ + +static int ad7152_i2c_read(struct ad7152_chip_info *chip, u8 reg, u8 *data, int len) +{ + struct i2c_client *client = chip->client; + int ret; + + ret = i2c_master_send(client, ®, 1); + if (ret < 0) { + dev_err(&client->dev, "I2C write error\n"); + return ret; + } + + ret = i2c_master_recv(client, data, len); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + } + + return ret; +} + +static int ad7152_i2c_write(struct ad7152_chip_info *chip, u8 reg, u8 data) +{ + struct i2c_client *client = chip->client; + int ret; + + u8 tx[2] = { + reg, + data, + }; + + ret = i2c_master_send(client, tx, 2); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +/* + * sysfs nodes + */ + +#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \ + IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \ + IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_OFFSET(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_offset, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_OFFSET(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_offset, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_GAIN(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_gain, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_GAIN(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_gain, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH1_VALUE(_show) \ + IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CH2_VALUE(_show) \ + IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_FILTER_RATE_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(filter_rate_setup, _mode, _show, _store, 0) + +static ssize_t ad7152_show_conversion_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i; + int len = 0; + + for (i = 0; i < AD7152_MAX_CONV_MODE; i++) + len += sprintf(buf + len, "%s ", ad7152_conv_mode_table[i].name); + + len += sprintf(buf + len, "\n"); + + return len; +} + +static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7152_show_conversion_modes); + +static ssize_t ad7152_show_ch1_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + u8 data[2]; + + ad7152_i2c_read(chip, AD7152_CH1_DATA_HIGH, data, 2); + return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]); +} + +static IIO_DEV_ATTR_CH1_VALUE(ad7152_show_ch1_value); + +static ssize_t ad7152_show_ch2_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + u8 data[2]; + + ad7152_i2c_read(chip, AD7152_CH2_DATA_HIGH, data, 2); + return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]); +} + +static IIO_DEV_ATTR_CH2_VALUE(ad7152_show_ch2_value); + +static ssize_t ad7152_show_conversion_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%s\n", chip->conversion_mode); +} + +static ssize_t ad7152_store_conversion_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + u8 cfg; + int i; + + ad7152_i2c_read(chip, AD7152_CFG, &cfg, 1); + + for (i = 0; i < AD7152_MAX_CONV_MODE; i++) + if (strncmp(buf, ad7152_conv_mode_table[i].name, + strlen(ad7152_conv_mode_table[i].name) - 1) == 0) { + chip->conversion_mode = ad7152_conv_mode_table[i].name; + cfg |= 0x18 | ad7152_conv_mode_table[i].reg_cfg; + ad7152_i2c_write(chip, AD7152_CFG, cfg); + return len; + } + + dev_err(dev, "not supported conversion mode\n"); + + return -EINVAL; +} + +static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR, + ad7152_show_conversion_mode, + ad7152_store_conversion_mode); + +static ssize_t ad7152_show_ch1_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch1_offset); +} + +static ssize_t ad7152_store_ch1_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad7152_i2c_write(chip, AD7152_CH1_OFFS_HIGH, data >> 8); + ad7152_i2c_write(chip, AD7152_CH1_OFFS_LOW, data); + chip->ch1_offset = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_OFFSET(S_IRUGO | S_IWUSR, + ad7152_show_ch1_offset, + ad7152_store_ch1_offset); + +static ssize_t ad7152_show_ch2_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch2_offset); +} + +static ssize_t ad7152_store_ch2_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad7152_i2c_write(chip, AD7152_CH2_OFFS_HIGH, data >> 8); + ad7152_i2c_write(chip, AD7152_CH2_OFFS_LOW, data); + chip->ch2_offset = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_OFFSET(S_IRUGO | S_IWUSR, + ad7152_show_ch2_offset, + ad7152_store_ch2_offset); + +static ssize_t ad7152_show_ch1_gain(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch1_gain); +} + +static ssize_t ad7152_store_ch1_gain(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad7152_i2c_write(chip, AD7152_CH1_GAIN_HIGH, data >> 8); + ad7152_i2c_write(chip, AD7152_CH1_GAIN_LOW, data); + chip->ch1_gain = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_GAIN(S_IRUGO | S_IWUSR, + ad7152_show_ch1_gain, + ad7152_store_ch1_gain); + +static ssize_t ad7152_show_ch2_gain(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->ch2_gain); +} + +static ssize_t ad7152_store_ch2_gain(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad7152_i2c_write(chip, AD7152_CH2_GAIN_HIGH, data >> 8); + ad7152_i2c_write(chip, AD7152_CH2_GAIN_LOW, data); + chip->ch2_gain = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_GAIN(S_IRUGO | S_IWUSR, + ad7152_show_ch2_gain, + ad7152_store_ch2_gain); + +static ssize_t ad7152_show_ch1_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->ch1_setup); +} + +static ssize_t ad7152_store_ch1_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7152_i2c_write(chip, AD7152_CH1_SETUP, data); + chip->ch1_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR, + ad7152_show_ch1_setup, + ad7152_store_ch1_setup); + +static ssize_t ad7152_show_ch2_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->ch2_setup); +} + +static ssize_t ad7152_store_ch2_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7152_i2c_write(chip, AD7152_CH2_SETUP, data); + chip->ch2_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR, + ad7152_show_ch2_setup, + ad7152_store_ch2_setup); + +static ssize_t ad7152_show_filter_rate_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->filter_rate_setup); +} + +static ssize_t ad7152_store_filter_rate_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad7152_i2c_write(chip, AD7152_CFG2, data); + chip->filter_rate_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_FILTER_RATE_SETUP(S_IRUGO | S_IWUSR, + ad7152_show_filter_rate_setup, + ad7152_store_filter_rate_setup); + +static ssize_t ad7152_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7152_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7152_show_name, NULL, 0); + +static struct attribute *ad7152_attributes[] = { + &iio_dev_attr_available_conversion_modes.dev_attr.attr, + &iio_dev_attr_conversion_mode.dev_attr.attr, + &iio_dev_attr_ch1_gain.dev_attr.attr, + &iio_dev_attr_ch2_gain.dev_attr.attr, + &iio_dev_attr_ch1_offset.dev_attr.attr, + &iio_dev_attr_ch2_offset.dev_attr.attr, + &iio_dev_attr_ch1_value.dev_attr.attr, + &iio_dev_attr_ch2_value.dev_attr.attr, + &iio_dev_attr_ch1_setup.dev_attr.attr, + &iio_dev_attr_ch2_setup.dev_attr.attr, + &iio_dev_attr_filter_rate_setup.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7152_attribute_group = { + .attrs = ad7152_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit ad7152_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct ad7152_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, chip); + + chip->client = client; + chip->name = id->name; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + /* Echipabilish that the iio_dev is a child of the i2c device */ + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->attrs = &ad7152_attribute_group; + chip->indio_dev->dev_data = (void *)(chip); + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + dev_err(&client->dev, "%s capacitive sensor registered\n", id->name); + + return 0; + +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); +error_ret: + return ret; +} + +static int __devexit ad7152_remove(struct i2c_client *client) +{ + struct ad7152_chip_info *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = chip->indio_dev; + + if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id ad7152_id[] = { + { "ad7152", 0 }, + { "ad7153", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad7152_id); + +static struct i2c_driver ad7152_driver = { + .driver = { + .name = "ad7152", + }, + .probe = ad7152_probe, + .remove = __devexit_p(ad7152_remove), + .id_table = ad7152_id, +}; + +static __init int ad7152_init(void) +{ + return i2c_add_driver(&ad7152_driver); +} + +static __exit void ad7152_exit(void) +{ + i2c_del_driver(&ad7152_driver); +} + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ad7152/3 capacitive sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad7152_init); +module_exit(ad7152_exit); -- cgit v1.2.3 From ddaecd5ba8cc3bc68b65b01cc8dbfedcac87254e Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:43:55 -0400 Subject: staging: iio: adc: new driver for AD7291 devices Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/ad7291.c | 1039 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1047 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7291.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 7f03571227a5..fa78413f3fae 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -41,6 +41,13 @@ config AD7152 Say yes here to build support for Analog Devices capacitive sensors. (ad7152, ad7153) Provides direct access via sysfs. +config AD7291 + tristate "Analog Devices AD7291 temperature sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices AD7291 + temperature sensors. + config AD799X tristate "Analog Devices AD799x ADC driver" depends on I2C diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index a13475412371..5e99a863203a 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7150) += ad7150.o obj-$(CONFIG_AD7152) += ad7152.o +obj-$(CONFIG_AD7291) += ad7291.o diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c new file mode 100644 index 000000000000..34041a72aa52 --- /dev/null +++ b/drivers/staging/iio/adc/ad7291.c @@ -0,0 +1,1039 @@ +/* + * AD7291 digital temperature sensor driver supporting AD7291 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD7291 registers definition + */ +#define AD7291_COMMAND 0 +#define AD7291_VOLTAGE 1 +#define AD7291_T_SENSE 2 +#define AD7291_T_AVERAGE 3 +#define AD7291_VOLTAGE_LIMIT_BASE 4 +#define AD7291_VOLTAGE_LIMIT_COUNT 8 +#define AD7291_T_SENSE_HIGH 0x1c +#define AD7291_T_SENSE_LOW 0x1d +#define AD7291_T_SENSE_HYST 0x1e +#define AD7291_VOLTAGE_ALERT_STATUS 0x1f +#define AD7291_T_ALERT_STATUS 0x20 + +/* + * AD7291 command + */ +#define AD7291_AUTOCYCLE 0x1 +#define AD7291_RESET 0x2 +#define AD7291_ALART_CLEAR 0x4 +#define AD7291_ALART_POLARITY 0x8 +#define AD7291_EXT_REF 0x10 +#define AD7291_NOISE_DELAY 0x20 +#define AD7291_T_SENSE_MASK 0x40 +#define AD7291_VOLTAGE_MASK 0xff00 +#define AD7291_VOLTAGE_OFFSET 0x8 + +/* + * AD7291 value masks + */ +#define AD7291_CHANNEL_MASK 0xf000 +#define AD7291_VALUE_MASK 0xfff +#define AD7291_T_VALUE_SIGN 0x400 +#define AD7291_T_VALUE_FLOAT_OFFSET 2 +#define AD7291_T_VALUE_FLOAT_MASK 0x2 + +/* + * struct ad7291_chip_info - chip specifc information + */ + +struct ad7291_chip_info { + const char *name; + struct i2c_client *client; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + s64 last_timestamp; + u16 command; + u8 channels; /* Active voltage channels */ +}; + +/* + * struct ad7291_chip_info - chip specifc information + */ + +struct ad7291_limit_regs { + u16 data_high; + u16 data_low; + u16 hysteresis; +}; + +/* + * ad7291 register access by I2C + */ +static int ad7291_i2c_read(struct ad7291_chip_info *chip, u8 reg, u16 *data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = swab16((u16)ret); + + return 0; +} + +static int ad7291_i2c_write(struct ad7291_chip_info *chip, u8 reg, u16 data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_write_word_data(client, reg, swab16(data)); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +/* Returns negative errno, or else the number of words read. */ +static int ad7291_i2c_read_data(struct ad7291_chip_info *chip, u8 reg, u16 *data) +{ + struct i2c_client *client = chip->client; + u8 commands[4]; + int ret = 0; + int i, count; + + if (reg == AD7291_T_SENSE || reg == AD7291_T_AVERAGE) + count = 2; + else if (reg == AD7291_VOLTAGE) { + if (!chip->channels) { + dev_err(&client->dev, "No voltage channel is selected.\n"); + return -EINVAL; + } + count = 2 + chip->channels * 2; + } else { + dev_err(&client->dev, "I2C wrong data register\n"); + return -EINVAL; + } + + commands[0] = 0; + commands[1] = (chip->command >> 8) & 0xff; + commands[2] = chip->command & 0xff; + commands[3] = reg; + + ret = i2c_master_send(client, commands, 4); + if (ret < 0) { + dev_err(&client->dev, "I2C master send error\n"); + return ret; + } + + ret = i2c_master_recv(client, (u8 *)data, count); + if (ret < 0) { + dev_err(&client->dev, "I2C master receive error\n"); + return ret; + } + ret >>= 2; + + for (i = 0; i < ret; i++) + data[i] = swab16(data[i]); + + return ret; +} + +static ssize_t ad7291_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + + if (chip->command & AD7291_AUTOCYCLE) + return sprintf(buf, "autocycle\n"); + else + return sprintf(buf, "command\n"); +} + +static ssize_t ad7291_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 command; + int ret; + + command = chip->command & (~AD7291_AUTOCYCLE); + if (strcmp(buf, "autocycle")) + command |= AD7291_AUTOCYCLE; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, command); + if (ret) + return -EIO; + + chip->command = command; + + return ret; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + ad7291_show_mode, + ad7291_store_mode, + 0); + +static ssize_t ad7291_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "command\nautocycle\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7291_show_available_modes, NULL, 0); + +static ssize_t ad7291_store_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 command; + int ret; + + command = chip->command | AD7291_RESET; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, command); + if (ret) + return -EIO; + + return ret; +} + +static IIO_DEVICE_ATTR(reset, S_IWUSR, + NULL, + ad7291_store_reset, + 0); + +static ssize_t ad7291_show_ext_ref(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->command & AD7291_EXT_REF)); +} + +static ssize_t ad7291_store_ext_ref(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 command; + int ret; + + command = chip->command & (~AD7291_EXT_REF); + if (strcmp(buf, "1")) + command |= AD7291_EXT_REF; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, command); + if (ret) + return -EIO; + + chip->command = command; + + return ret; +} + +static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR, + ad7291_show_ext_ref, + ad7291_store_ext_ref, + 0); + +static ssize_t ad7291_show_noise_delay(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->command & AD7291_NOISE_DELAY)); +} + +static ssize_t ad7291_store_noise_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 command; + int ret; + + command = chip->command & (~AD7291_NOISE_DELAY); + if (strcmp(buf, "1")) + command |= AD7291_NOISE_DELAY; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, command); + if (ret) + return -EIO; + + chip->command = command; + + return ret; +} + +static IIO_DEVICE_ATTR(noise_delay, S_IRUGO | S_IWUSR, + ad7291_show_noise_delay, + ad7291_store_noise_delay, + 0); + +static ssize_t ad7291_show_t_sense(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + ret = ad7291_i2c_read_data(chip, AD7291_T_SENSE, &data); + if (ret) + return -EIO; + + if (data & AD7291_T_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (AD7291_T_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + (data >> AD7291_T_VALUE_FLOAT_OFFSET), + (data & AD7291_T_VALUE_FLOAT_MASK) * 25); +} + +static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7291_show_t_sense, NULL, 0); + +static ssize_t ad7291_show_t_average(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + ret = ad7291_i2c_read_data(chip, AD7291_T_AVERAGE, &data); + if (ret) + return -EIO; + + if (data & AD7291_T_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (AD7291_T_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + (data >> AD7291_T_VALUE_FLOAT_OFFSET), + (data & AD7291_T_VALUE_FLOAT_MASK) * 25); +} + +static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7291_show_t_average, NULL, 0); + +static ssize_t ad7291_show_voltage(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 data[AD7291_VOLTAGE_LIMIT_COUNT]; + int i, size, ret; + + ret = ad7291_i2c_read_data(chip, AD7291_VOLTAGE, data); + if (ret) + return -EIO; + + for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) { + if (chip->command & (AD7291_T_SENSE_MASK << i)) { + ret = sprintf(buf, "channel[%d]=%d\n", i, + data[i] & AD7291_VALUE_MASK); + if (ret < 0) + break; + buf += ret; + size += ret; + } + } + + return size; +} + +static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7291_show_voltage, NULL, 0); + +static ssize_t ad7291_show_channel_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%x\n", (chip->command & AD7291_VOLTAGE_MASK) >> + AD7291_VOLTAGE_OFFSET); +} + +static ssize_t ad7291_store_channel_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 command; + unsigned long data; + int i, ret; + + ret = strict_strtoul(buf, 16, &data); + if (ret || data > 0xff) + return -EINVAL; + + command = chip->command & (~AD7291_VOLTAGE_MASK); + command |= data << AD7291_VOLTAGE_OFFSET; + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, command); + if (ret) + return -EIO; + + chip->command = command; + + for (i = 0, chip->channels = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) { + if (chip->command & (AD7291_T_SENSE_MASK << i)) + chip->channels++; + } + + return ret; +} + +static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR, + ad7291_show_channel_mask, + ad7291_store_channel_mask, + 0); + +static ssize_t ad7291_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7291_show_name, NULL, 0); + +static struct attribute *ad7291_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_dev_attr_ext_ref.dev_attr.attr, + &iio_dev_attr_noise_delay.dev_attr.attr, + &iio_dev_attr_t_sense.dev_attr.attr, + &iio_dev_attr_t_average.dev_attr.attr, + &iio_dev_attr_voltage.dev_attr.attr, + &iio_dev_attr_channel_mask.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7291_attribute_group = { + .attrs = ad7291_attributes, +}; + +/* + * temperature bound events + */ + +#define IIO_EVENT_CODE_AD7291_T_SENSE_HIGH IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_AD7291_T_SENSE_LOW IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_AD7291_T_AVG_HIGH IIO_BUFFER_EVENT_CODE(2) +#define IIO_EVENT_CODE_AD7291_T_AVG_LOW IIO_BUFFER_EVENT_CODE(3) +#define IIO_EVENT_CODE_AD7291_VOLTAGE_BASE IIO_BUFFER_EVENT_CODE(4) + +static void ad7291_interrupt_bh(struct work_struct *work_s) +{ + struct ad7291_chip_info *chip = + container_of(work_s, struct ad7291_chip_info, thresh_work); + u16 t_status, v_status; + u16 command; + int i; + + if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status)) + return; + + if (ad7291_i2c_read(chip, AD7291_VOLTAGE_ALERT_STATUS, &v_status)) + return; + + if (!(t_status || v_status)) + return; + + command = chip->command | AD7291_ALART_CLEAR; + ad7291_i2c_write(chip, AD7291_COMMAND, command); + + command = chip->command & ~AD7291_ALART_CLEAR; + ad7291_i2c_write(chip, AD7291_COMMAND, command); + + enable_irq(chip->client->irq); + + for (i = 0; i < 4; i++) { + if (t_status & (1 << i)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_AD7291_T_SENSE_HIGH + i, + chip->last_timestamp); + } + + for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT*2; i++) { + if (v_status & (1 << i)) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_AD7291_VOLTAGE_BASE + i, + chip->last_timestamp); + } +} + +static int ad7291_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ad7291_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(ad7291, &ad7291_interrupt); + +static inline ssize_t ad7291_show_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + ret = ad7291_i2c_read(chip, bound_reg, &data); + if (ret) + return -EIO; + + data &= AD7291_VALUE_MASK; + if (data & AD7291_T_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (AD7291_T_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + data >> AD7291_T_VALUE_FLOAT_OFFSET, + (data & AD7291_T_VALUE_FLOAT_MASK) * 25); +} + +static inline ssize_t ad7291_set_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + long tmp1, tmp2; + u16 data; + char *pos; + int ret; + + pos = strchr(buf, '.'); + + ret = strict_strtol(buf, 10, &tmp1); + + if (ret || tmp1 > 127 || tmp1 < -128) + return -EINVAL; + + if (pos) { + len = strlen(pos); + if (len > AD7291_T_VALUE_FLOAT_OFFSET) + len = AD7291_T_VALUE_FLOAT_OFFSET; + pos[len] = 0; + ret = strict_strtol(pos, 10, &tmp2); + + if (!ret) + tmp2 = (tmp2 / 25) * 25; + } + + if (tmp1 < 0) + data = (u16)(-tmp1); + else + data = (u16)tmp1; + data = (data << AD7291_T_VALUE_FLOAT_OFFSET) | + (tmp2 & AD7291_T_VALUE_FLOAT_MASK); + if (tmp1 < 0) + /* convert positive value to supplyment */ + data = (AD7291_T_VALUE_SIGN << 1) - data; + + ret = ad7291_i2c_write(chip, bound_reg, data); + if (ret) + return -EIO; + + return ret; +} + +static ssize_t ad7291_show_t_sense_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return ad7291_show_t_bound(dev, attr, + AD7291_T_SENSE_HIGH, buf); +} + +static inline ssize_t ad7291_set_t_sense_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return ad7291_set_t_bound(dev, attr, + AD7291_T_SENSE_HIGH, buf, len); +} + +static ssize_t ad7291_show_t_sense_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return ad7291_show_t_bound(dev, attr, + AD7291_T_SENSE_LOW, buf); +} + +static inline ssize_t ad7291_set_t_sense_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return ad7291_set_t_bound(dev, attr, + AD7291_T_SENSE_LOW, buf, len); +} + +static ssize_t ad7291_show_t_sense_hyst(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return ad7291_show_t_bound(dev, attr, + AD7291_T_SENSE_HYST, buf); +} + +static inline ssize_t ad7291_set_t_sense_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return ad7291_set_t_bound(dev, attr, + AD7291_T_SENSE_HYST, buf, len); +} + +static inline ssize_t ad7291_show_v_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + u16 data; + int ret; + + if (bound_reg < AD7291_VOLTAGE_LIMIT_BASE || + bound_reg >= AD7291_VOLTAGE_LIMIT_BASE + + AD7291_VOLTAGE_LIMIT_COUNT) + return -EINVAL; + + ret = ad7291_i2c_read(chip, bound_reg, &data); + if (ret) + return -EIO; + + data &= AD7291_VALUE_MASK; + + return sprintf(buf, "%d\n", data); +} + +static inline ssize_t ad7291_set_v_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7291_chip_info *chip = dev_info->dev_data; + unsigned long value; + u16 data; + int ret; + + if (bound_reg < AD7291_VOLTAGE_LIMIT_BASE || + bound_reg >= AD7291_VOLTAGE_LIMIT_BASE + + AD7291_VOLTAGE_LIMIT_COUNT) + return -EINVAL; + + ret = strict_strtoul(buf, 10, &value); + + if (ret || value >= 4096) + return -EINVAL; + + data = (u16)value; + ret = ad7291_i2c_write(chip, bound_reg, data); + if (ret) + return -EIO; + + return ret; +} + +static int ad7291_get_voltage_limit_regs(const char *channel) +{ + int index; + + if (strlen(channel) < 3 && channel[0] != 'v') + return -EINVAL; + + index = channel[1] - '0'; + if (index >= AD7291_VOLTAGE_LIMIT_COUNT) + return -EINVAL; + + return index; +} + +static ssize_t ad7291_show_voltage_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int regs; + + regs = ad7291_get_voltage_limit_regs(attr->attr.name); + + if (regs < 0) + return regs; + + return ad7291_show_t_bound(dev, attr, regs, buf); +} + +static inline ssize_t ad7291_set_voltage_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + int regs; + + regs = ad7291_get_voltage_limit_regs(attr->attr.name); + + if (regs < 0) + return regs; + + return ad7291_set_t_bound(dev, attr, regs, buf, len); +} + +static ssize_t ad7291_show_voltage_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int regs; + + regs = ad7291_get_voltage_limit_regs(attr->attr.name); + + if (regs < 0) + return regs; + + return ad7291_show_t_bound(dev, attr, regs+1, buf); +} + +static inline ssize_t ad7291_set_voltage_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + int regs; + + regs = ad7291_get_voltage_limit_regs(attr->attr.name); + + if (regs < 0) + return regs; + + return ad7291_set_t_bound(dev, attr, regs+1, buf, len); +} + +static ssize_t ad7291_show_voltage_hyst(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int regs; + + regs = ad7291_get_voltage_limit_regs(attr->attr.name); + + if (regs < 0) + return regs; + + return ad7291_show_t_bound(dev, attr, regs+2, buf); +} + +static inline ssize_t ad7291_set_voltage_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + int regs; + + regs = ad7291_get_voltage_limit_regs(attr->attr.name); + + if (regs < 0) + return regs; + + return ad7291_set_t_bound(dev, attr, regs+2, buf, len); +} + +IIO_EVENT_ATTR_SH(t_sense_high, iio_event_ad7291, + ad7291_show_t_sense_high, ad7291_set_t_sense_high, 0); +IIO_EVENT_ATTR_SH(t_sense_low, iio_event_ad7291, + ad7291_show_t_sense_low, ad7291_set_t_sense_low, 0); +IIO_EVENT_ATTR_SH(t_sense_hyst, iio_event_ad7291, + ad7291_show_t_sense_hyst, ad7291_set_t_sense_hyst, 0); + +IIO_EVENT_ATTR_SH(v0_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v0_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v0_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v1_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v1_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v1_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v2_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v2_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v2_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v3_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v3_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v3_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v4_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v4_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v4_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v5_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v5_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v5_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v6_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v6_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v6_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); +IIO_EVENT_ATTR_SH(v7_high, iio_event_ad7291, + ad7291_show_voltage_high, ad7291_set_voltage_high, 0); +IIO_EVENT_ATTR_SH(v7_low, iio_event_ad7291, + ad7291_show_voltage_low, ad7291_set_voltage_low, 0); +IIO_EVENT_ATTR_SH(v7_hyst, iio_event_ad7291, + ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0); + +static struct attribute *ad7291_event_attributes[] = { + &iio_event_attr_t_sense_high.dev_attr.attr, + &iio_event_attr_t_sense_low.dev_attr.attr, + &iio_event_attr_t_sense_hyst.dev_attr.attr, + &iio_event_attr_v0_high.dev_attr.attr, + &iio_event_attr_v0_low.dev_attr.attr, + &iio_event_attr_v0_hyst.dev_attr.attr, + &iio_event_attr_v1_high.dev_attr.attr, + &iio_event_attr_v1_low.dev_attr.attr, + &iio_event_attr_v1_hyst.dev_attr.attr, + &iio_event_attr_v2_high.dev_attr.attr, + &iio_event_attr_v2_low.dev_attr.attr, + &iio_event_attr_v2_hyst.dev_attr.attr, + &iio_event_attr_v3_high.dev_attr.attr, + &iio_event_attr_v3_low.dev_attr.attr, + &iio_event_attr_v3_hyst.dev_attr.attr, + &iio_event_attr_v4_high.dev_attr.attr, + &iio_event_attr_v4_low.dev_attr.attr, + &iio_event_attr_v4_hyst.dev_attr.attr, + &iio_event_attr_v5_high.dev_attr.attr, + &iio_event_attr_v5_low.dev_attr.attr, + &iio_event_attr_v5_hyst.dev_attr.attr, + &iio_event_attr_v6_high.dev_attr.attr, + &iio_event_attr_v6_low.dev_attr.attr, + &iio_event_attr_v6_hyst.dev_attr.attr, + &iio_event_attr_v7_high.dev_attr.attr, + &iio_event_attr_v7_low.dev_attr.attr, + &iio_event_attr_v7_hyst.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7291_event_attribute_group = { + .attrs = ad7291_event_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit ad7291_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ad7291_chip_info *chip; + int ret = 0; + + chip = kzalloc(sizeof(struct ad7291_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, chip); + + chip->client = client; + chip->name = id->name; + chip->command = AD7291_NOISE_DELAY | AD7291_T_SENSE_MASK; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->attrs = &ad7291_attribute_group; + chip->indio_dev->event_attrs = &ad7291_event_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + if (client->irq > 0) { + ret = iio_register_interrupt_line(client->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_LOW, + chip->name); + if (ret) + goto error_unreg_dev; + + /* + * The event handler list element refer to iio_event_ad7291. + * All event attributes bind to the same event handler. + * So, only register event handler once. + */ + iio_add_event_to_list(&iio_event_ad7291, + &chip->indio_dev->interrupts[0]->ev_list); + + INIT_WORK(&chip->thresh_work, ad7291_interrupt_bh); + + /* set irq polarity low level */ + chip->command |= AD7291_ALART_POLARITY; + } + + ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command); + if (ret) { + ret = -EIO; + goto error_unreg_irq; + } + + dev_info(&client->dev, "%s temperature sensor registered.\n", + id->name); + + return 0; + +error_unreg_irq: + iio_unregister_interrupt_line(chip->indio_dev, 0); +error_unreg_dev: + iio_device_unregister(chip->indio_dev); +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit ad7291_remove(struct i2c_client *client) +{ + struct ad7291_chip_info *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = chip->indio_dev; + + if (client->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id ad7291_id[] = { + { "ad7291", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad7291_id); + +static struct i2c_driver ad7291_driver = { + .driver = { + .name = "ad7291", + }, + .probe = ad7291_probe, + .remove = __devexit_p(ad7291_remove), + .id_table = ad7291_id, +}; + +static __init int ad7291_init(void) +{ + return i2c_add_driver(&ad7291_driver); +} + +static __exit void ad7291_exit(void) +{ + i2c_del_driver(&ad7291_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices AD7291 digital" + " temperature sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad7291_init); +module_exit(ad7291_exit); -- cgit v1.2.3 From e8ada962bc2e34e964d370f721994387df7b1363 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:43:56 -0400 Subject: staging: iio: adc: new driver for AD7298 devices Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/ad7298.c | 501 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 509 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7298.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index fa78413f3fae..e6bc7faf2d28 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -48,6 +48,13 @@ config AD7291 Say yes here to build support for Analog Devices AD7291 temperature sensors. +config AD7298 + tristate "Analog Devices AD7298 temperature sensor and ADC driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD7298 + temperature sensors and ADC. + config AD799X tristate "Analog Devices AD799x ADC driver" depends on I2C diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 5e99a863203a..6c036323c3b7 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7150) += ad7150.o obj-$(CONFIG_AD7152) += ad7152.o obj-$(CONFIG_AD7291) += ad7291.o +obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/staging/iio/adc/ad7298.c b/drivers/staging/iio/adc/ad7298.c new file mode 100644 index 000000000000..1a080c977637 --- /dev/null +++ b/drivers/staging/iio/adc/ad7298.c @@ -0,0 +1,501 @@ +/* + * AD7298 digital temperature sensor driver supporting AD7298 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD7298 command + */ +#define AD7298_PD 0x1 +#define AD7298_T_AVG_MASK 0x2 +#define AD7298_EXT_REF 0x4 +#define AD7298_T_SENSE_MASK 0x20 +#define AD7298_VOLTAGE_MASK 0x3fc0 +#define AD7298_VOLTAGE_OFFSET 0x6 +#define AD7298_VOLTAGE_LIMIT_COUNT 8 +#define AD7298_REPEAT 0x40 +#define AD7298_WRITE 0x80 + +/* + * AD7298 value masks + */ +#define AD7298_CHANNEL_MASK 0xf000 +#define AD7298_VALUE_MASK 0xfff +#define AD7298_T_VALUE_SIGN 0x400 +#define AD7298_T_VALUE_FLOAT_OFFSET 2 +#define AD7298_T_VALUE_FLOAT_MASK 0x2 + +/* + * struct ad7298_chip_info - chip specifc information + */ + +struct ad7298_chip_info { + const char *name; + struct spi_device *spi_dev; + struct iio_dev *indio_dev; + u16 command; + u16 busy_pin; + u8 channels; /* Active voltage channels */ +}; + +/* + * ad7298 register access by SPI + */ +static int ad7298_spi_write(struct ad7298_chip_info *chip, u16 data) +{ + struct spi_device *spi_dev = chip->spi_dev; + int ret = 0; + + data |= AD7298_WRITE; + data = cpu_to_be16(data); + ret = spi_write(spi_dev, (u8 *)&data, sizeof(data)); + if (ret < 0) + dev_err(&spi_dev->dev, "SPI write error\n"); + + return ret; +} + +static int ad7298_spi_read(struct ad7298_chip_info *chip, u16 mask, u16 *data) +{ + struct spi_device *spi_dev = chip->spi_dev; + int ret = 0; + u8 count = chip->channels; + u16 command; + int i; + + if (mask & AD7298_T_SENSE_MASK) { + command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_VOLTAGE_MASK); + command |= AD7298_T_SENSE_MASK; + count = 1; + } else if (mask & AD7298_T_AVG_MASK) { + command = chip->command & ~AD7298_VOLTAGE_MASK; + command |= AD7298_T_SENSE_MASK | AD7298_T_AVG_MASK; + count = 2; + } else if (mask & AD7298_VOLTAGE_MASK) { + command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_T_SENSE_MASK); + count = chip->channels; + } + + ret = ad7298_spi_write(chip, chip->command); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI write command error\n"); + return ret; + } + + ret = spi_read(spi_dev, (u8 *)&command, sizeof(command)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI read error\n"); + return ret; + } + + i = 10000; + while (i && gpio_get_value(chip->busy_pin)) { + cpu_relax(); + i--; + } + if (!i) { + dev_err(&spi_dev->dev, "Always in busy convertion.\n"); + return -EBUSY; + } + + for (i = 0; i < count; i++) { + ret = spi_read(spi_dev, (u8 *)&data[i], sizeof(data[i])); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI read error\n"); + return ret; + } + *data = be16_to_cpu(data[i]); + } + + return 0; +} + +static ssize_t ad7298_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + + if (chip->command & AD7298_REPEAT) + return sprintf(buf, "repeat\n"); + else + return sprintf(buf, "normal\n"); +} + +static ssize_t ad7298_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + + if (strcmp(buf, "repeat")) + chip->command |= AD7298_REPEAT; + else + chip->command &= (~AD7298_REPEAT); + + return 1; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + ad7298_show_mode, + ad7298_store_mode, + 0); + +static ssize_t ad7298_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "normal\nrepeat\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7298_show_available_modes, NULL, 0); + +static ssize_t ad7298_store_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + u16 command; + int ret; + + command = chip->command & ~AD7298_PD; + + ret = ad7298_spi_write(chip, command); + if (ret) + return -EIO; + + command = chip->command | AD7298_PD; + + ret = ad7298_spi_write(chip, command); + if (ret) + return -EIO; + + return len; +} + +static IIO_DEVICE_ATTR(reset, S_IWUSR, + NULL, + ad7298_store_reset, + 0); + +static ssize_t ad7298_show_ext_ref(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->command & AD7298_EXT_REF)); +} + +static ssize_t ad7298_store_ext_ref(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + u16 command; + int ret; + + command = chip->command & (~AD7298_EXT_REF); + if (strcmp(buf, "1")) + command |= AD7298_EXT_REF; + + ret = ad7298_spi_write(chip, command); + if (ret) + return -EIO; + + chip->command = command; + + return len; +} + +static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR, + ad7298_show_ext_ref, + ad7298_store_ext_ref, + 0); + +static ssize_t ad7298_show_t_sense(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + ret = ad7298_spi_read(chip, AD7298_T_SENSE_MASK, &data); + if (ret) + return -EIO; + + if (data & AD7298_T_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (AD7298_T_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + (data >> AD7298_T_VALUE_FLOAT_OFFSET), + (data & AD7298_T_VALUE_FLOAT_MASK) * 25); +} + +static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7298_show_t_sense, NULL, 0); + +static ssize_t ad7298_show_t_average(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + u16 data[2]; + char sign = ' '; + int ret; + + ret = ad7298_spi_read(chip, AD7298_T_AVG_MASK, data); + if (ret) + return -EIO; + + if (data[1] & AD7298_T_VALUE_SIGN) { + /* convert supplement to positive value */ + data[1] = (AD7298_T_VALUE_SIGN << 1) - data[1]; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + (data[1] >> AD7298_T_VALUE_FLOAT_OFFSET), + (data[1] & AD7298_T_VALUE_FLOAT_MASK) * 25); +} + +static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7298_show_t_average, NULL, 0); + +static ssize_t ad7298_show_voltage(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + u16 data[AD7298_VOLTAGE_LIMIT_COUNT]; + int i, size, ret; + + ret = ad7298_spi_read(chip, AD7298_VOLTAGE_MASK, data); + if (ret) + return -EIO; + + for (i = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) { + if (chip->command & (AD7298_T_SENSE_MASK << i)) { + ret = sprintf(buf, "channel[%d]=%d\n", i, + data[i] & AD7298_VALUE_MASK); + if (ret < 0) + break; + buf += ret; + size += ret; + } + } + + return size; +} + +static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7298_show_voltage, NULL, 0); + +static ssize_t ad7298_show_channel_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%x\n", (chip->command & AD7298_VOLTAGE_MASK) >> + AD7298_VOLTAGE_OFFSET); +} + +static ssize_t ad7298_store_channel_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + unsigned long data; + int i, ret; + + ret = strict_strtoul(buf, 16, &data); + if (ret || data > 0xff) + return -EINVAL; + + chip->command &= (~AD7298_VOLTAGE_MASK); + chip->command |= data << AD7298_VOLTAGE_OFFSET; + + for (i = 0, chip->channels = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) { + if (chip->command & (AD7298_T_SENSE_MASK << i)) + chip->channels++; + } + + return ret; +} + +static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR, + ad7298_show_channel_mask, + ad7298_store_channel_mask, + 0); + +static ssize_t ad7298_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7298_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0); + +static struct attribute *ad7298_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_dev_attr_ext_ref.dev_attr.attr, + &iio_dev_attr_t_sense.dev_attr.attr, + &iio_dev_attr_t_average.dev_attr.attr, + &iio_dev_attr_voltage.dev_attr.attr, + &iio_dev_attr_channel_mask.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7298_attribute_group = { + .attrs = ad7298_attributes, +}; + +/* + * device probe and remove + */ +static int __devinit ad7298_probe(struct spi_device *spi_dev) +{ + struct ad7298_chip_info *chip; + unsigned short *pins = spi_dev->dev.platform_data; + int ret = 0; + + chip = kzalloc(sizeof(struct ad7298_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + dev_set_drvdata(&spi_dev->dev, chip); + + chip->spi_dev = spi_dev; + chip->name = spi_dev->modalias; + chip->busy_pin = pins[0]; + + ret = gpio_request(chip->busy_pin, chip->name); + if (ret) { + dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n", + chip->busy_pin); + goto error_free_chip; + } + gpio_direction_input(chip->busy_pin); + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_gpio; + } + + chip->indio_dev->dev.parent = &spi_dev->dev; + chip->indio_dev->attrs = &ad7298_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n", + chip->name); + + return 0; + +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_gpio: + gpio_free(chip->busy_pin); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit ad7298_remove(struct spi_device *spi_dev) +{ + struct ad7298_chip_info *chip = dev_get_drvdata(&spi_dev->dev); + struct iio_dev *indio_dev = chip->indio_dev; + + dev_set_drvdata(&spi_dev->dev, NULL); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + gpio_free(chip->busy_pin); + kfree(chip); + + return 0; +} + +static const struct spi_device_id ad7298_id[] = { + { "ad7298", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(spi, ad7298_id); + +static struct spi_driver ad7298_driver = { + .driver = { + .name = "ad7298", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad7298_probe, + .remove = __devexit_p(ad7298_remove), + .id_table = ad7298_id, +}; + +static __init int ad7298_init(void) +{ + return spi_register_driver(&ad7298_driver); +} + +static __exit void ad7298_exit(void) +{ + spi_unregister_driver(&ad7298_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices AD7298 digital" + " temperature sensor and ADC driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad7298_init); +module_exit(ad7298_exit); -- cgit v1.2.3 From f84c26e61eedaa9eb21fe8a238d38fffb8d3c394 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:43:57 -0400 Subject: staging: iio: adc: new driver for AD7314 devices Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/ad7314.c | 308 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7314.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index e6bc7faf2d28..4e7b6a84e84a 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -55,6 +55,13 @@ config AD7298 Say yes here to build support for Analog Devices AD7298 temperature sensors and ADC. +config AD7314 + tristate "Analog Devices AD7314 temperature sensor driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD7314 + temperature sensors. + config AD799X tristate "Analog Devices AD799x ADC driver" depends on I2C diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 6c036323c3b7..36e66f93d6f9 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_AD7150) += ad7150.o obj-$(CONFIG_AD7152) += ad7152.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o +obj-$(CONFIG_AD7314) += ad7314.o diff --git a/drivers/staging/iio/adc/ad7314.c b/drivers/staging/iio/adc/ad7314.c new file mode 100644 index 000000000000..8c17b1fe9026 --- /dev/null +++ b/drivers/staging/iio/adc/ad7314.c @@ -0,0 +1,308 @@ +/* + * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD7314 power mode + */ +#define AD7314_PD 0x2000 + +/* + * AD7314 temperature masks + */ +#define AD7314_TEMP_SIGN 0x200 +#define AD7314_TEMP_MASK 0x7FE0 +#define AD7314_TEMP_OFFSET 5 +#define AD7314_TEMP_FLOAT_OFFSET 2 +#define AD7314_TEMP_FLOAT_MASK 0x3 + +/* + * ADT7301 and ADT7302 temperature masks + */ +#define ADT7301_TEMP_SIGN 0x2000 +#define ADT7301_TEMP_MASK 0x2FFF +#define ADT7301_TEMP_FLOAT_OFFSET 5 +#define ADT7301_TEMP_FLOAT_MASK 0x1F + +/* + * struct ad7314_chip_info - chip specifc information + */ + +struct ad7314_chip_info { + const char *name; + struct spi_device *spi_dev; + struct iio_dev *indio_dev; + s64 last_timestamp; + u8 mode; +}; + +/* + * ad7314 register access by SPI + */ + +static int ad7314_spi_read(struct ad7314_chip_info *chip, u16 *data) +{ + struct spi_device *spi_dev = chip->spi_dev; + int ret = 0; + u16 value; + + ret = spi_read(spi_dev, (u8 *)&value, sizeof(value)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI read error\n"); + return ret; + } + + *data = be16_to_cpu((u16)value); + + return ret; +} + +static int ad7314_spi_write(struct ad7314_chip_info *chip, u16 data) +{ + struct spi_device *spi_dev = chip->spi_dev; + int ret = 0; + u16 value = cpu_to_be16(data); + + ret = spi_write(spi_dev, (u8 *)&value, sizeof(value)); + if (ret < 0) + dev_err(&spi_dev->dev, "SPI write error\n"); + + return ret; +} + +static ssize_t ad7314_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7314_chip_info *chip = dev_info->dev_data; + + if (chip->mode) + return sprintf(buf, "power-save\n"); + else + return sprintf(buf, "full\n"); +} + +static ssize_t ad7314_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7314_chip_info *chip = dev_info->dev_data; + u16 mode = 0; + int ret; + + if (!strcmp(buf, "full")) + mode = AD7314_PD; + + ret = ad7314_spi_write(chip, mode); + if (ret) + return -EIO; + + chip->mode = mode; + + return len; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + ad7314_show_mode, + ad7314_store_mode, + 0); + +static ssize_t ad7314_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "full\npower-save\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7314_show_available_modes, NULL, 0); + +static ssize_t ad7314_show_temperature(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7314_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + if (chip->mode) { + ret = ad7314_spi_write(chip, 0); + if (ret) + return -EIO; + } + + ret = ad7314_spi_read(chip, &data); + if (ret) + return -EIO; + + if (chip->mode) + ad7314_spi_write(chip, chip->mode); + + if (strcmp(chip->name, "ad7314")) { + data = (data & AD7314_TEMP_MASK) >> + AD7314_TEMP_OFFSET; + if (data & AD7314_TEMP_SIGN) { + data = (AD7314_TEMP_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.2d\n", sign, + data >> AD7314_TEMP_FLOAT_OFFSET, + (data & AD7314_TEMP_FLOAT_MASK) * 25); + } else { + data &= ADT7301_TEMP_MASK; + if (data & ADT7301_TEMP_SIGN) { + data = (ADT7301_TEMP_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.5d\n", sign, + data >> ADT7301_TEMP_FLOAT_OFFSET, + (data & ADT7301_TEMP_FLOAT_MASK) * 3125); + } +} + +static IIO_DEVICE_ATTR(temperature, S_IRUGO, ad7314_show_temperature, NULL, 0); + +static ssize_t ad7314_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7314_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL, 0); + +static struct attribute *ad7314_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_temperature.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7314_attribute_group = { + .attrs = ad7314_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit ad7314_probe(struct spi_device *spi_dev) +{ + struct ad7314_chip_info *chip; + int ret = 0; + + chip = kzalloc(sizeof(struct ad7314_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + dev_set_drvdata(&spi_dev->dev, chip); + + chip->spi_dev = spi_dev; + chip->name = spi_dev->modalias; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + chip->indio_dev->dev.parent = &spi_dev->dev; + chip->indio_dev->attrs = &ad7314_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + dev_info(&spi_dev->dev, "%s temperature sensor registered.\n", + chip->name); + + return 0; +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit ad7314_remove(struct spi_device *spi_dev) +{ + struct ad7314_chip_info *chip = dev_get_drvdata(&spi_dev->dev); + struct iio_dev *indio_dev = chip->indio_dev; + + dev_set_drvdata(&spi_dev->dev, NULL); + if (spi_dev->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + kfree(chip); + + return 0; +} + +static const struct spi_device_id ad7314_id[] = { + { "adt7301", 0 }, + { "adt7302", 0 }, + { "ad7314", 0 }, + {} +}; + +static struct spi_driver ad7314_driver = { + .driver = { + .name = "ad7314", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad7314_probe, + .remove = __devexit_p(ad7314_remove), + .id_table = ad7314_id, +}; + +static __init int ad7314_init(void) +{ + return spi_register_driver(&ad7314_driver); +} + +static __exit void ad7314_exit(void) +{ + spi_unregister_driver(&ad7314_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" + " temperature sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad7314_init); +module_exit(ad7314_exit); -- cgit v1.2.3 From 671d85f2aa3dadc6e221b6f6f7e087bf487275e7 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:43:58 -0400 Subject: staging: iio: adc: new driver for AD7745/6/7 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 14 +- drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/ad7745.c | 734 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 747 insertions(+), 2 deletions(-) create mode 100644 drivers/staging/iio/adc/ad7745.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 4e7b6a84e84a..34c6822ae070 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -85,9 +85,9 @@ config AD799X_RING_BUFFER config AD7476 tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver" depends on SPI - select IIO_RING_BUFFER + select IIO_RING_BUFFER select IIO_SW_RING - select IIO_TRIGGER + select IIO_TRIGGER help Say yes here to build support for Analog Devices AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495 @@ -96,3 +96,13 @@ config AD7476 To compile this driver as a module, choose M here: the module will be called ad7476. + +config AD7745 + tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices capacitive sensors. + (AD7745, AD7746, AD7747) Provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad7745. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 36e66f93d6f9..ac83bad5125a 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_AD7152) += ad7152.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7314) += ad7314.o +obj-$(CONFIG_AD7745) += ad7745.o diff --git a/drivers/staging/iio/adc/ad7745.c b/drivers/staging/iio/adc/ad7745.c new file mode 100644 index 000000000000..ab7ef8450ae2 --- /dev/null +++ b/drivers/staging/iio/adc/ad7745.c @@ -0,0 +1,734 @@ +/* + * AD774X capacitive sensor driver supporting AD7745/6/7 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD774X registers definition + */ + +#define AD774X_STATUS 0 +#define AD774X_STATUS_RDY (1 << 2) +#define AD774X_STATUS_RDYVT (1 << 1) +#define AD774X_STATUS_RDYCAP (1 << 0) +#define AD774X_CAP_DATA_HIGH 1 +#define AD774X_CAP_DATA_MID 2 +#define AD774X_CAP_DATA_LOW 3 +#define AD774X_VT_DATA_HIGH 4 +#define AD774X_VT_DATA_MID 5 +#define AD774X_VT_DATA_LOW 6 +#define AD774X_CAP_SETUP 7 +#define AD774X_VT_SETUP 8 +#define AD774X_EXEC_SETUP 9 +#define AD774X_CFG 10 +#define AD774X_CAPDACA 11 +#define AD774X_CAPDACB 12 +#define AD774X_CAPDAC_EN (1 << 7) +#define AD774X_CAP_OFFH 13 +#define AD774X_CAP_OFFL 14 +#define AD774X_CAP_GAINH 15 +#define AD774X_CAP_GAINL 16 +#define AD774X_VOLT_GAINH 17 +#define AD774X_VOLT_GAINL 18 + +#define AD774X_MAX_CONV_MODE 6 + +/* + * struct ad774x_chip_info - chip specifc information + */ + +struct ad774x_chip_info { + const char *name; + struct i2c_client *client; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + bool inter; + s64 last_timestamp; + u16 cap_offs; /* Capacitive offset */ + u16 cap_gain; /* Capacitive gain calibration */ + u16 volt_gain; /* Voltage gain calibration */ + u8 cap_setup; + u8 vt_setup; + u8 exec_setup; + + char *conversion_mode; +}; + +struct ad774x_conversion_mode { + char *name; + u8 reg_cfg; +}; + +struct ad774x_conversion_mode ad774x_conv_mode_table[AD774X_MAX_CONV_MODE] = { + { "idle", 0 }, + { "continuous-conversion", 1 }, + { "single-conversion", 2 }, + { "power-down", 3 }, + { "offset-calibration", 5 }, + { "gain-calibration", 6 }, +}; + +/* + * ad774x register access by I2C + */ + +static int ad774x_i2c_read(struct ad774x_chip_info *chip, u8 reg, u8 *data, int len) +{ + struct i2c_client *client = chip->client; + int ret; + + ret = i2c_master_send(client, ®, 1); + if (ret < 0) { + dev_err(&client->dev, "I2C write error\n"); + return ret; + } + + ret = i2c_master_recv(client, data, len); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + return ret; +} + +static int ad774x_i2c_write(struct ad774x_chip_info *chip, u8 reg, u8 data) +{ + struct i2c_client *client = chip->client; + int ret; + + u8 tx[2] = { + reg, + data, + }; + + ret = i2c_master_send(client, tx, 2); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +/* + * sysfs nodes + */ + +#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \ + IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \ + IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CAP_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(cap_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_VT_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(in0_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_EXEC_SETUP(_mode, _show, _store) \ + IIO_DEVICE_ATTR(exec_setup, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_VOLT_GAIN(_mode, _show, _store) \ + IIO_DEVICE_ATTR(in0_gain, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CAP_OFFS(_mode, _show, _store) \ + IIO_DEVICE_ATTR(cap_offs, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CAP_GAIN(_mode, _show, _store) \ + IIO_DEVICE_ATTR(cap_gain, _mode, _show, _store, 0) +#define IIO_DEV_ATTR_CAP_DATA(_show) \ + IIO_DEVICE_ATTR(cap0_raw, S_IRUGO, _show, NULL, 0) +#define IIO_DEV_ATTR_VT_DATA(_show) \ + IIO_DEVICE_ATTR(in0_raw, S_IRUGO, _show, NULL, 0) + +static ssize_t ad774x_show_conversion_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i; + int len = 0; + + for (i = 0; i < AD774X_MAX_CONV_MODE; i++) + len += sprintf(buf + len, "%s ", ad774x_conv_mode_table[i].name); + + len += sprintf(buf + len, "\n"); + + return len; +} + +static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad774x_show_conversion_modes); + +static ssize_t ad774x_show_conversion_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%s\n", chip->conversion_mode); +} + +static ssize_t ad774x_store_conversion_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + u8 cfg; + int i; + + ad774x_i2c_read(chip, AD774X_CFG, &cfg, 1); + + for (i = 0; i < AD774X_MAX_CONV_MODE; i++) { + if (strncmp(buf, ad774x_conv_mode_table[i].name, + strlen(ad774x_conv_mode_table[i].name) - 1) == 0) { + chip->conversion_mode = ad774x_conv_mode_table[i].name; + cfg |= 0x18 | ad774x_conv_mode_table[i].reg_cfg; + ad774x_i2c_write(chip, AD774X_CFG, cfg); + return len; + } + } + + dev_err(dev, "not supported conversion mode\n"); + + return -EINVAL; +} + +static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR, + ad774x_show_conversion_mode, + ad774x_store_conversion_mode); + +static ssize_t ad774x_show_dac_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + u8 data; + + ad774x_i2c_read(chip, this_attr->address, &data, 1); + + return sprintf(buf, "%02x\n", data & 0x7F); +} + +static ssize_t ad774x_store_dac_value(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if (!ret) { + ad774x_i2c_write(chip, this_attr->address, + (data ? AD774X_CAPDAC_EN : 0) | (data & 0x7F)); + return len; + } + + return -EINVAL; +} + +static IIO_DEVICE_ATTR(capdac0_raw, S_IRUGO | S_IWUSR, + ad774x_show_dac_value, + ad774x_store_dac_value, + AD774X_CAPDACA); + +static IIO_DEVICE_ATTR(capdac1_raw, S_IRUGO | S_IWUSR, + ad774x_show_dac_value, + ad774x_store_dac_value, + AD774X_CAPDACB); + +static ssize_t ad774x_show_cap_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->cap_setup); +} + +static ssize_t ad774x_store_cap_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad774x_i2c_write(chip, AD774X_CAP_SETUP, data); + chip->cap_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CAP_SETUP(S_IRUGO | S_IWUSR, + ad774x_show_cap_setup, + ad774x_store_cap_setup); + +static ssize_t ad774x_show_vt_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->vt_setup); +} + +static ssize_t ad774x_store_vt_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad774x_i2c_write(chip, AD774X_VT_SETUP, data); + chip->vt_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_VT_SETUP(S_IRUGO | S_IWUSR, + ad774x_show_vt_setup, + ad774x_store_vt_setup); + +static ssize_t ad774x_show_exec_setup(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "0x%02x\n", chip->exec_setup); +} + +static ssize_t ad774x_store_exec_setup(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x100)) { + ad774x_i2c_write(chip, AD774X_EXEC_SETUP, data); + chip->exec_setup = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_EXEC_SETUP(S_IRUGO | S_IWUSR, + ad774x_show_exec_setup, + ad774x_store_exec_setup); + +static ssize_t ad774x_show_volt_gain(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->volt_gain); +} + +static ssize_t ad774x_store_volt_gain(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad774x_i2c_write(chip, AD774X_VOLT_GAINH, data >> 8); + ad774x_i2c_write(chip, AD774X_VOLT_GAINL, data); + chip->volt_gain = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_VOLT_GAIN(S_IRUGO | S_IWUSR, + ad774x_show_volt_gain, + ad774x_store_volt_gain); + +static ssize_t ad774x_show_cap_data(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + char tmp[3]; + + ad774x_i2c_read(chip, AD774X_CAP_DATA_HIGH, tmp, 3); + data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2]; + + return sprintf(buf, "%ld\n", data); +} + +static IIO_DEV_ATTR_CAP_DATA(ad774x_show_cap_data); + +static ssize_t ad774x_show_vt_data(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + char tmp[3]; + + ad774x_i2c_read(chip, AD774X_VT_DATA_HIGH, tmp, 3); + data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2]; + + return sprintf(buf, "%ld\n", data); +} + +static IIO_DEV_ATTR_VT_DATA(ad774x_show_vt_data); + +static ssize_t ad774x_show_cap_offs(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->cap_offs); +} + +static ssize_t ad774x_store_cap_offs(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad774x_i2c_write(chip, AD774X_CAP_OFFH, data >> 8); + ad774x_i2c_write(chip, AD774X_CAP_OFFL, data); + chip->cap_offs = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CAP_OFFS(S_IRUGO | S_IWUSR, + ad774x_show_cap_offs, + ad774x_store_cap_offs); + +static ssize_t ad774x_show_cap_gain(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->cap_gain); +} + +static ssize_t ad774x_store_cap_gain(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + + if ((!ret) && (data < 0x10000)) { + ad774x_i2c_write(chip, AD774X_CAP_GAINH, data >> 8); + ad774x_i2c_write(chip, AD774X_CAP_GAINL, data); + chip->cap_gain = data; + return len; + } + + return -EINVAL; +} + +static IIO_DEV_ATTR_CAP_GAIN(S_IRUGO | S_IWUSR, + ad774x_show_cap_gain, + ad774x_store_cap_gain); + +static ssize_t ad774x_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad774x_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad774x_show_name, NULL, 0); + +static struct attribute *ad774x_attributes[] = { + &iio_dev_attr_available_conversion_modes.dev_attr.attr, + &iio_dev_attr_conversion_mode.dev_attr.attr, + &iio_dev_attr_cap_setup.dev_attr.attr, + &iio_dev_attr_in0_setup.dev_attr.attr, + &iio_dev_attr_exec_setup.dev_attr.attr, + &iio_dev_attr_cap_offs.dev_attr.attr, + &iio_dev_attr_cap_gain.dev_attr.attr, + &iio_dev_attr_in0_gain.dev_attr.attr, + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_cap0_raw.dev_attr.attr, + &iio_dev_attr_capdac0_raw.dev_attr.attr, + &iio_dev_attr_capdac1_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad774x_attribute_group = { + .attrs = ad774x_attributes, +}; + +/* + * data ready events + */ + +#define IIO_EVENT_CODE_CAP_RDY IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_VT_RDY IIO_BUFFER_EVENT_CODE(1) + +#define IIO_EVENT_ATTR_CAP_RDY_SH(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(cap_rdy, _evlist, _show, _store, _mask) + +#define IIO_EVENT_ATTR_VT_RDY_SH(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(vt_rdy, _evlist, _show, _store, _mask) + +static void ad774x_interrupt_handler_bh(struct work_struct *work_s) +{ + struct ad774x_chip_info *chip = + container_of(work_s, struct ad774x_chip_info, thresh_work); + u8 int_status; + + enable_irq(chip->client->irq); + + ad774x_i2c_read(chip, AD774X_STATUS, &int_status, 1); + + if (int_status & AD774X_STATUS_RDYCAP) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_CAP_RDY, + chip->last_timestamp); + + if (int_status & AD774X_STATUS_RDYVT) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_VT_RDY, + chip->last_timestamp); +} + +static int ad774x_interrupt_handler_th(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ad774x_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(data_rdy, &ad774x_interrupt_handler_th); + +static ssize_t ad774x_query_out_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* + * AD774X provides one /RDY pin, which can be used as interrupt + * but the pin is not configurable + */ + return sprintf(buf, "1\n"); +} + +static ssize_t ad774x_set_out_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return len; +} + +IIO_EVENT_ATTR_CAP_RDY_SH(iio_event_data_rdy, ad774x_query_out_mode, ad774x_set_out_mode, 0); +IIO_EVENT_ATTR_VT_RDY_SH(iio_event_data_rdy, ad774x_query_out_mode, ad774x_set_out_mode, 0); + +static struct attribute *ad774x_event_attributes[] = { + &iio_event_attr_cap_rdy.dev_attr.attr, + &iio_event_attr_vt_rdy.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad774x_event_attribute_group = { + .attrs = ad774x_event_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit ad774x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0, regdone = 0; + struct ad774x_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, chip); + + chip->client = client; + chip->name = id->name; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + /* Establish that the iio_dev is a child of the i2c device */ + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->attrs = &ad774x_attribute_group; + chip->indio_dev->event_attrs = &ad774x_event_attribute_group; + chip->indio_dev->dev_data = (void *)(chip); + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + regdone = 1; + + if (client->irq) { + ret = iio_register_interrupt_line(client->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + "ad774x"); + if (ret) + goto error_free_dev; + + iio_add_event_to_list(iio_event_attr_cap_rdy.listel, + &chip->indio_dev->interrupts[0]->ev_list); + + INIT_WORK(&chip->thresh_work, ad774x_interrupt_handler_bh); + } + + dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq); + + return 0; + +error_free_dev: + if (regdone) + iio_device_unregister(chip->indio_dev); + else + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); +error_ret: + return ret; +} + +static int __devexit ad774x_remove(struct i2c_client *client) +{ + struct ad774x_chip_info *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = chip->indio_dev; + + if (client->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id ad774x_id[] = { + { "ad7745", 0 }, + { "ad7746", 0 }, + { "ad7747", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad774x_id); + +static struct i2c_driver ad774x_driver = { + .driver = { + .name = "ad774x", + }, + .probe = ad774x_probe, + .remove = __devexit_p(ad774x_remove), + .id_table = ad774x_id, +}; + +static __init int ad774x_init(void) +{ + return i2c_add_driver(&ad774x_driver); +} + +static __exit void ad774x_exit(void) +{ + i2c_del_driver(&ad774x_driver); +} + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ad7745/6/7 capacitive sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad774x_init); +module_exit(ad774x_exit); -- cgit v1.2.3 From 7924425db04a6107e49312edf53c158590d52aae Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:43:59 -0400 Subject: staging: iio: adc: new driver for AD7816 devices Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/ad7816.c | 535 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 543 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7816.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 34c6822ae070..e722b26ee197 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -106,3 +106,10 @@ config AD7745 To compile this driver as a module, choose M here: the module will be called ad7745. + +config AD7816 + tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD7816/7/8 + temperature sensors and ADC. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index ac83bad5125a..b8d641cca1d2 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7314) += ad7314.o obj-$(CONFIG_AD7745) += ad7745.o +obj-$(CONFIG_AD7816) += ad7816.o diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c new file mode 100644 index 000000000000..ad7415a6b8d9 --- /dev/null +++ b/drivers/staging/iio/adc/ad7816.c @@ -0,0 +1,535 @@ +/* + * AD7816 digital temperature sensor driver supporting AD7816/7/8 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * AD7816 config masks + */ +#define AD7816_FULL 0x1 +#define AD7816_PD 0x2 +#define AD7816_CS_MASK 0x7 +#define AD7816_CS_MAX 0x4 + +/* + * AD7816 temperature masks + */ +#define AD7816_VALUE_OFFSET 6 +#define AD7816_BOUND_VALUE_BASE 0x8 +#define AD7816_BOUND_VALUE_MIN -95 +#define AD7816_BOUND_VALUE_MAX 152 +#define AD7816_TEMP_FLOAT_OFFSET 2 +#define AD7816_TEMP_FLOAT_MASK 0x3 + + +/* + * struct ad7816_chip_info - chip specifc information + */ + +struct ad7816_chip_info { + const char *name; + struct spi_device *spi_dev; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + s64 last_timestamp; + u16 rdwr_pin; + u16 convert_pin; + u16 busy_pin; + u8 oti_data[AD7816_CS_MAX+1]; + u8 channel_id; /* 0 always be temperature */ + u8 mode; +}; + +/* + * ad7816 data access by SPI + */ +static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data) +{ + struct spi_device *spi_dev = chip->spi_dev; + int ret = 0; + + gpio_set_value(chip->rdwr_pin, 1); + gpio_set_value(chip->rdwr_pin, 0); + ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI channel setting error\n"); + return ret; + } + gpio_set_value(chip->rdwr_pin, 1); + + + if (chip->mode == AD7816_PD) { /* operating mode 2 */ + gpio_set_value(chip->convert_pin, 1); + gpio_set_value(chip->convert_pin, 0); + } else { /* operating mode 1 */ + gpio_set_value(chip->convert_pin, 0); + gpio_set_value(chip->convert_pin, 1); + } + + while (gpio_get_value(chip->busy_pin)) + cpu_relax(); + + gpio_set_value(chip->rdwr_pin, 0); + gpio_set_value(chip->rdwr_pin, 1); + ret = spi_read(spi_dev, (u8 *)data, sizeof(*data)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI data read error\n"); + return ret; + } + + *data = be16_to_cpu(*data); + + return ret; +} + +static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data) +{ + struct spi_device *spi_dev = chip->spi_dev; + int ret = 0; + + gpio_set_value(chip->rdwr_pin, 1); + gpio_set_value(chip->rdwr_pin, 0); + ret = spi_write(spi_dev, &data, sizeof(data)); + if (ret < 0) + dev_err(&spi_dev->dev, "SPI oti data write error\n"); + + return ret; +} + +static ssize_t ad7816_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + + if (chip->mode) + return sprintf(buf, "power-save\n"); + else + return sprintf(buf, "full\n"); +} + +static ssize_t ad7816_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + + if (strcmp(buf, "full")) { + gpio_set_value(chip->rdwr_pin, 1); + chip->mode = AD7816_FULL; + } else { + gpio_set_value(chip->rdwr_pin, 0); + chip->mode = AD7816_PD; + } + + return len; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + ad7816_show_mode, + ad7816_store_mode, + 0); + +static ssize_t ad7816_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "full\npower-save\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7816_show_available_modes, NULL, 0); + +static ssize_t ad7816_show_channel(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", chip->channel_id); +} + +static ssize_t ad7816_store_channel(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + + if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) { + dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n", + data, chip->name); + return -EINVAL; + } else if (strcmp(chip->name, "ad7818") == 0 && data > 1) { + dev_err(&chip->spi_dev->dev, + "Invalid channel id %lu for ad7818.\n", data); + return -EINVAL; + } else if (strcmp(chip->name, "ad7816") == 0 && data > 0) { + dev_err(&chip->spi_dev->dev, + "Invalid channel id %lu for ad7816.\n", data); + return -EINVAL; + } + + chip->channel_id = data; + + return len; +} + +static IIO_DEVICE_ATTR(channel, S_IRUGO | S_IWUSR, + ad7816_show_channel, + ad7816_store_channel, + 0); + + +static ssize_t ad7816_show_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + u16 data; + s8 value; + int ret; + + ret = ad7816_spi_read(chip, &data); + if (ret) + return -EIO; + + data >>= AD7816_VALUE_OFFSET; + + if (chip->channel_id == 0) { + value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103); + data &= AD7816_TEMP_FLOAT_MASK; + if (value < 0) + data = (1 << AD7816_TEMP_FLOAT_OFFSET) - data; + return sprintf(buf, "%d.%.2d\n", value, data * 25); + } else + return sprintf(buf, "%u\n", data); +} + +static IIO_DEVICE_ATTR(value, S_IRUGO, ad7816_show_value, NULL, 0); + +static ssize_t ad7816_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7816_show_name, NULL, 0); + +static struct attribute *ad7816_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_channel.dev_attr.attr, + &iio_dev_attr_value.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7816_attribute_group = { + .attrs = ad7816_attributes, +}; + +/* + * temperature bound events + */ + +#define IIO_EVENT_CODE_AD7816_OTI IIO_BUFFER_EVENT_CODE(0) + +static void ad7816_interrupt_bh(struct work_struct *work_s) +{ + struct ad7816_chip_info *chip = + container_of(work_s, struct ad7816_chip_info, thresh_work); + + enable_irq(chip->spi_dev->irq); + + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_AD7816_OTI, + chip->last_timestamp); +} + +static int ad7816_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ad7816_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(ad7816, &ad7816_interrupt); + +static ssize_t ad7816_show_oti(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + int value; + + if (chip->channel_id > AD7816_CS_MAX) { + dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id); + return -EINVAL; + } else if (chip->channel_id == 0) { + value = AD7816_BOUND_VALUE_MIN + + (chip->oti_data[chip->channel_id] - + AD7816_BOUND_VALUE_BASE); + return sprintf(buf, "%d\n", value); + } else + return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]); +} + +static inline ssize_t ad7816_set_oti(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7816_chip_info *chip = dev_info->dev_data; + long value; + u8 data; + int ret; + + ret = strict_strtol(buf, 10, &value); + + if (chip->channel_id > AD7816_CS_MAX) { + dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id); + return -EINVAL; + } else if (chip->channel_id == 0) { + if (ret || value < AD7816_BOUND_VALUE_MIN || + value > AD7816_BOUND_VALUE_MAX) + return -EINVAL; + + data = (u8)(value - AD7816_BOUND_VALUE_MIN + + AD7816_BOUND_VALUE_BASE); + } else { + if (ret || value < AD7816_BOUND_VALUE_BASE || value > 255) + return -EINVAL; + + data = (u8)value; + } + + ret = ad7816_spi_write(chip, data); + if (ret) + return -EIO; + + chip->oti_data[chip->channel_id] = data; + + return len; +} + +IIO_EVENT_ATTR_SH(oti, iio_event_ad7816, + ad7816_show_oti, ad7816_set_oti, 0); + +static struct attribute *ad7816_event_attributes[] = { + &iio_event_attr_oti.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7816_event_attribute_group = { + .attrs = ad7816_event_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit ad7816_probe(struct spi_device *spi_dev) +{ + struct ad7816_chip_info *chip; + unsigned short *pins = spi_dev->dev.platform_data; + int ret = 0; + int i; + + if (!pins) { + dev_err(&spi_dev->dev, "No necessary GPIO platform data.\n"); + return -EINVAL; + } + + chip = kzalloc(sizeof(struct ad7816_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + dev_set_drvdata(&spi_dev->dev, chip); + + chip->spi_dev = spi_dev; + chip->name = spi_dev->modalias; + for (i = 0; i <= AD7816_CS_MAX; i++) + chip->oti_data[i] = 203; + chip->rdwr_pin = pins[0]; + chip->convert_pin = pins[1]; + chip->busy_pin = pins[2]; + + ret = gpio_request(chip->rdwr_pin, chip->name); + if (ret) { + dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n", + chip->rdwr_pin); + goto error_free_chip; + } + gpio_direction_input(chip->rdwr_pin); + ret = gpio_request(chip->convert_pin, chip->name); + if (ret) { + dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n", + chip->convert_pin); + goto error_free_gpio_rdwr; + } + gpio_direction_input(chip->convert_pin); + ret = gpio_request(chip->busy_pin, chip->name); + if (ret) { + dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n", + chip->busy_pin); + goto error_free_gpio_convert; + } + gpio_direction_input(chip->busy_pin); + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_gpio; + } + + chip->indio_dev->dev.parent = &spi_dev->dev; + chip->indio_dev->attrs = &ad7816_attribute_group; + chip->indio_dev->event_attrs = &ad7816_event_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + if (spi_dev->irq) { + /* Only low trigger is supported in ad7816/7/8 */ + ret = iio_register_interrupt_line(spi_dev->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_LOW, + chip->name); + if (ret) + goto error_unreg_dev; + + /* + * The event handler list element refer to iio_event_ad7816. + * All event attributes bind to the same event handler. + * So, only register event handler once. + */ + iio_add_event_to_list(&iio_event_ad7816, + &chip->indio_dev->interrupts[0]->ev_list); + + INIT_WORK(&chip->thresh_work, ad7816_interrupt_bh); + } + + dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n", + chip->name); + + return 0; + +error_unreg_dev: + iio_device_unregister(chip->indio_dev); +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_gpio: + gpio_free(chip->busy_pin); +error_free_gpio_convert: + gpio_free(chip->convert_pin); +error_free_gpio_rdwr: + gpio_free(chip->rdwr_pin); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit ad7816_remove(struct spi_device *spi_dev) +{ + struct ad7816_chip_info *chip = dev_get_drvdata(&spi_dev->dev); + struct iio_dev *indio_dev = chip->indio_dev; + + dev_set_drvdata(&spi_dev->dev, NULL); + if (spi_dev->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + gpio_free(chip->busy_pin); + gpio_free(chip->convert_pin); + gpio_free(chip->rdwr_pin); + kfree(chip); + + return 0; +} + +static const struct spi_device_id ad7816_id[] = { + { "ad7816", 0 }, + { "ad7817", 0 }, + { "ad7818", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(spi, ad7816_id); + +static struct spi_driver ad7816_driver = { + .driver = { + .name = "ad7816", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad7816_probe, + .remove = __devexit_p(ad7816_remove), + .id_table = ad7816_id, +}; + +static __init int ad7816_init(void) +{ + return spi_register_driver(&ad7816_driver); +} + +static __exit void ad7816_exit(void) +{ + spi_unregister_driver(&ad7816_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital" + " temperature sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(ad7816_init); +module_exit(ad7816_exit); -- cgit v1.2.3 From d7713b6c56472b41e04ebcbdfdf85df84c8e82d6 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:44:00 -0400 Subject: staging: iio: adc: new driver for ADT75 temperature sensors Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/adt75.c | 732 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 740 insertions(+) create mode 100644 drivers/staging/iio/adc/adt75.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index e722b26ee197..a7c6b818dbb7 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -113,3 +113,10 @@ config AD7816 help Say yes here to build support for Analog Devices AD7816/7/8 temperature sensors and ADC. + +config ADT75 + tristate "Analog Devices ADT75 temperature sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices ADT75 + temperature sensors. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index b8d641cca1d2..d1f1b5720cdf 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7314) += ad7314.o obj-$(CONFIG_AD7745) += ad7745.o obj-$(CONFIG_AD7816) += ad7816.o +obj-$(CONFIG_ADT75) += adt75.o diff --git a/drivers/staging/iio/adc/adt75.c b/drivers/staging/iio/adc/adt75.c new file mode 100644 index 000000000000..aff4d31eb89c --- /dev/null +++ b/drivers/staging/iio/adc/adt75.c @@ -0,0 +1,732 @@ +/* + * ADT75 digital temperature sensor driver supporting ADT75 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * ADT75 registers definition + */ + +#define ADT75_TEMPERATURE 0 +#define ADT75_CONFIG 1 +#define ADT75_T_HYST 2 +#define ADT75_T_OS 3 +#define ADT75_ONESHOT 4 + +/* + * ADT75 config + */ +#define ADT75_PD 0x1 +#define ADT75_OS_INT 0x2 +#define ADT75_OS_POLARITY 0x4 +#define ADT75_FAULT_QUEUE_MASK 0x18 +#define ADT75_FAULT_QUEUE_OFFSET 3 +#define ADT75_SMBUS_ALART 0x8 + +/* + * ADT75 masks + */ +#define ADT75_VALUE_SIGN 0x800 +#define ADT75_VALUE_OFFSET 4 +#define ADT75_VALUE_FLOAT_OFFSET 4 +#define ADT75_VALUE_FLOAT_MASK 0xF + + +/* + * struct adt75_chip_info - chip specifc information + */ + +struct adt75_chip_info { + const char *name; + struct i2c_client *client; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + s64 last_timestamp; + u8 config; +}; + +/* + * adt75 register access by I2C + */ + +static int adt75_i2c_read(struct adt75_chip_info *chip, u8 reg, u8 *data) +{ + struct i2c_client *client = chip->client; + int ret = 0, len; + + ret = i2c_smbus_write_byte(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read register address error\n"); + return ret; + } + + if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT) + len = 1; + else + len = 2; + + ret = i2c_master_recv(client, data, len); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + return ret; +} + +static int adt75_i2c_write(struct adt75_chip_info *chip, u8 reg, u8 data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT) + ret = i2c_smbus_write_byte_data(client, reg, data); + else + ret = i2c_smbus_write_word_data(client, reg, data); + + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static ssize_t adt75_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + + if (chip->config & ADT75_PD) + return sprintf(buf, "power-save\n"); + else + return sprintf(buf, "full\n"); +} + +static ssize_t adt75_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + int ret; + u8 config; + + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT75_PD; + if (!strcmp(buf, "full")) + config |= ADT75_PD; + + ret = adt75_i2c_write(chip, ADT75_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + adt75_show_mode, + adt75_store_mode, + 0); + +static ssize_t adt75_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "full\npower-down\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt75_show_available_modes, NULL, 0); + +static ssize_t adt75_show_oneshot(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + + return sprintf(buf, "%d\n", !!(chip->config & ADT75_ONESHOT)); +} + +static ssize_t adt75_store_oneshot(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + unsigned long data = 0; + int ret; + u8 config; + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + + + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT75_ONESHOT; + if (data) + config |= ADT75_ONESHOT; + + ret = adt75_i2c_write(chip, ADT75_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static IIO_DEVICE_ATTR(oneshot, S_IRUGO | S_IWUSR, + adt75_show_oneshot, + adt75_store_oneshot, + 0); + +static ssize_t adt75_show_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + if (chip->config & ADT75_PD) { + dev_err(dev, "Can't read value in power-down mode.\n"); + return -EIO; + } + + if (chip->config & ADT75_ONESHOT) { + /* write to active converter */ + ret = i2c_smbus_write_byte(chip->client, ADT75_ONESHOT); + if (ret) + return -EIO; + } + + ret = adt75_i2c_read(chip, ADT75_TEMPERATURE, (u8 *)&data); + if (ret) + return -EIO; + + data = swab16(data) >> ADT75_VALUE_OFFSET; + if (data & ADT75_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (ADT75_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.4d\n", sign, + (data >> ADT75_VALUE_FLOAT_OFFSET), + (data & ADT75_VALUE_FLOAT_MASK) * 625); +} + +static IIO_DEVICE_ATTR(value, S_IRUGO, adt75_show_value, NULL, 0); + +static ssize_t adt75_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, adt75_show_name, NULL, 0); + +static struct attribute *adt75_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_oneshot.dev_attr.attr, + &iio_dev_attr_value.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group adt75_attribute_group = { + .attrs = adt75_attributes, +}; + +/* + * temperature bound events + */ + +#define IIO_EVENT_CODE_ADT75_OTI IIO_BUFFER_EVENT_CODE(0) + +static void adt75_interrupt_bh(struct work_struct *work_s) +{ + struct adt75_chip_info *chip = + container_of(work_s, struct adt75_chip_info, thresh_work); + + enable_irq(chip->client->irq); + + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT75_OTI, + chip->last_timestamp); +} + +static int adt75_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adt75_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(adt75, &adt75_interrupt); + +static ssize_t adt75_show_oti_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + int ret; + + /* retrive ALART status */ + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + if (chip->config & ADT75_OS_INT) + return sprintf(buf, "interrupt\n"); + else + return sprintf(buf, "comparator\n"); +} + +static ssize_t adt75_set_oti_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + int ret; + u8 config; + + /* retrive ALART status */ + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT75_OS_INT; + if (strcmp(buf, "comparator") != 0) + config |= ADT75_OS_INT; + + ret = adt75_i2c_write(chip, ADT75_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static ssize_t adt75_show_available_oti_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "comparator\ninterrupt\n"); +} + +static ssize_t adt75_show_smbus_alart(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + int ret; + + /* retrive ALART status */ + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", !!(chip->config & ADT75_SMBUS_ALART)); +} + +static ssize_t adt75_set_smbus_alart(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + unsigned long data = 0; + int ret; + u8 config; + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + + /* retrive ALART status */ + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT75_SMBUS_ALART; + if (data) + config |= ADT75_SMBUS_ALART; + + ret = adt75_i2c_write(chip, ADT75_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static ssize_t adt75_show_fault_queue(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + int ret; + + /* retrive ALART status */ + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", (chip->config & ADT75_FAULT_QUEUE_MASK) >> + ADT75_FAULT_QUEUE_OFFSET); +} + +static ssize_t adt75_set_fault_queue(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + u8 config; + + ret = strict_strtoul(buf, 10, &data); + if (ret || data > 3) + return -EINVAL; + + /* retrive ALART status */ + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT75_FAULT_QUEUE_MASK; + config |= (data << ADT75_FAULT_QUEUE_OFFSET); + ret = adt75_i2c_write(chip, ADT75_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} +static inline ssize_t adt75_show_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + u16 data; + char sign = ' '; + int ret; + + ret = adt75_i2c_read(chip, bound_reg, (u8 *)&data); + if (ret) + return -EIO; + + data = swab16(data) >> ADT75_VALUE_OFFSET; + if (data & ADT75_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (ADT75_VALUE_SIGN << 1) - data; + sign = '-'; + } + + return sprintf(buf, "%c%d.%.4d\n", sign, + (data >> ADT75_VALUE_FLOAT_OFFSET), + (data & ADT75_VALUE_FLOAT_MASK) * 625); +} + +static inline ssize_t adt75_set_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt75_chip_info *chip = dev_info->dev_data; + long tmp1, tmp2; + u16 data; + char *pos; + int ret; + + pos = strchr(buf, '.'); + + ret = strict_strtol(buf, 10, &tmp1); + + if (ret || tmp1 > 127 || tmp1 < -128) + return -EINVAL; + + if (pos) { + len = strlen(pos); + if (len > ADT75_VALUE_FLOAT_OFFSET) + len = ADT75_VALUE_FLOAT_OFFSET; + pos[len] = 0; + ret = strict_strtol(pos, 10, &tmp2); + + if (!ret) + tmp2 = (tmp2 / 625) * 625; + } + + if (tmp1 < 0) + data = (u16)(-tmp1); + else + data = (u16)tmp1; + data = (data << ADT75_VALUE_FLOAT_OFFSET) | (tmp2 & ADT75_VALUE_FLOAT_MASK); + if (tmp1 < 0) + /* convert positive value to supplyment */ + data = (ADT75_VALUE_SIGN << 1) - data; + data <<= ADT75_VALUE_OFFSET; + data = swab16(data); + + ret = adt75_i2c_write(chip, bound_reg, (u8)data); + if (ret) + return -EIO; + + return ret; +} + +static ssize_t adt75_show_t_os(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt75_show_t_bound(dev, attr, + ADT75_T_OS, buf); +} + +static inline ssize_t adt75_set_t_os(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt75_set_t_bound(dev, attr, + ADT75_T_OS, buf, len); +} + +static ssize_t adt75_show_t_hyst(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt75_show_t_bound(dev, attr, + ADT75_T_HYST, buf); +} + +static inline ssize_t adt75_set_t_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt75_set_t_bound(dev, attr, + ADT75_T_HYST, buf, len); +} + +IIO_EVENT_ATTR_SH(oti_mode, iio_event_adt75, + adt75_show_oti_mode, adt75_set_oti_mode, 0); +IIO_EVENT_ATTR_SH(available_oti_modes, iio_event_adt75, + adt75_show_available_oti_modes, NULL, 0); +IIO_EVENT_ATTR_SH(smbus_alart, iio_event_adt75, + adt75_show_smbus_alart, adt75_set_smbus_alart, 0); +IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt75, + adt75_show_fault_queue, adt75_set_fault_queue, 0); +IIO_EVENT_ATTR_SH(t_os, iio_event_adt75, + adt75_show_t_os, adt75_set_t_os, 0); +IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt75, + adt75_show_t_hyst, adt75_set_t_hyst, 0); + +static struct attribute *adt75_event_attributes[] = { + &iio_event_attr_oti_mode.dev_attr.attr, + &iio_event_attr_available_oti_modes.dev_attr.attr, + &iio_event_attr_smbus_alart.dev_attr.attr, + &iio_event_attr_fault_queue.dev_attr.attr, + &iio_event_attr_t_os.dev_attr.attr, + &iio_event_attr_t_hyst.dev_attr.attr, + NULL, +}; + +static struct attribute_group adt75_event_attribute_group = { + .attrs = adt75_event_attributes, +}; + +/* + * device probe and remove + */ + +static int __devinit adt75_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adt75_chip_info *chip; + int ret = 0; + + chip = kzalloc(sizeof(struct adt75_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, chip); + + chip->client = client; + chip->name = id->name; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->attrs = &adt75_attribute_group; + chip->indio_dev->event_attrs = &adt75_event_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = 1; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + if (client->irq > 0) { + ret = iio_register_interrupt_line(client->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_LOW, + chip->name); + if (ret) + goto error_unreg_dev; + + /* + * The event handler list element refer to iio_event_adt75. + * All event attributes bind to the same event handler. + * So, only register event handler once. + */ + iio_add_event_to_list(&iio_event_adt75, + &chip->indio_dev->interrupts[0]->ev_list); + + INIT_WORK(&chip->thresh_work, adt75_interrupt_bh); + + ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config); + if (ret) { + ret = -EIO; + goto error_unreg_irq; + } + + /* set irq polarity low level */ + chip->config &= ~ADT75_OS_POLARITY; + + ret = adt75_i2c_write(chip, ADT75_CONFIG, chip->config); + if (ret) { + ret = -EIO; + goto error_unreg_irq; + } + } + + dev_info(&client->dev, "%s temperature sensor registered.\n", + id->name); + + return 0; +error_unreg_irq: + iio_unregister_interrupt_line(chip->indio_dev, 0); +error_unreg_dev: + iio_device_unregister(chip->indio_dev); +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit adt75_remove(struct i2c_client *client) +{ + struct adt75_chip_info *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = chip->indio_dev; + + if (client->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id adt75_id[] = { + { "adt75", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, adt75_id); + +static struct i2c_driver adt75_driver = { + .driver = { + .name = "adt75", + }, + .probe = adt75_probe, + .remove = __devexit_p(adt75_remove), + .id_table = adt75_id, +}; + +static __init int adt75_init(void) +{ + return i2c_add_driver(&adt75_driver); +} + +static __exit void adt75_exit(void) +{ + i2c_del_driver(&adt75_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices ADT75 digital" + " temperature sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(adt75_init); +module_exit(adt75_exit); -- cgit v1.2.3 From a5d8c6bc2f87c1c5cb69fb3a22d1ef0110a9eacc Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:44:01 -0400 Subject: staging: iio: adc: new driver for ADT7310 temperature sensors Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/adt7310.c | 952 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 960 insertions(+) create mode 100644 drivers/staging/iio/adc/adt7310.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index a7c6b818dbb7..cd355260f794 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -120,3 +120,10 @@ config ADT75 help Say yes here to build support for Analog Devices ADT75 temperature sensors. + +config ADT7310 + tristate "Analog Devices ADT7310 temperature sensor driver" + depends on SPI + help + Say yes here to build support for Analog Devices ADT7310 + temperature sensors. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index d1f1b5720cdf..6067b66f6a0b 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_AD7314) += ad7314.o obj-$(CONFIG_AD7745) += ad7745.o obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_ADT75) += adt75.o +obj-$(CONFIG_ADT7310) += adt7310.o diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c new file mode 100644 index 000000000000..771a409ee94c --- /dev/null +++ b/drivers/staging/iio/adc/adt7310.c @@ -0,0 +1,952 @@ +/* + * ADT7310 digital temperature sensor driver supporting ADT7310 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * ADT7310 registers definition + */ + +#define ADT7310_STATUS 0 +#define ADT7310_CONFIG 1 +#define ADT7310_TEMPERATURE 2 +#define ADT7310_ID 3 +#define ADT7310_T_CRIT 4 +#define ADT7310_T_HYST 5 +#define ADT7310_T_ALARM_HIGH 6 +#define ADT7310_T_ALARM_LOW 7 + +/* + * ADT7310 status + */ +#define ADT7310_STAT_T_LOW 0x10 +#define ADT7310_STAT_T_HIGH 0x20 +#define ADT7310_STAT_T_CRIT 0x40 +#define ADT7310_STAT_NOT_RDY 0x80 + +/* + * ADT7310 config + */ +#define ADT7310_FAULT_QUEUE_MASK 0x3 +#define ADT7310_CT_POLARITY 0x4 +#define ADT7310_INT_POLARITY 0x8 +#define ADT7310_EVENT_MODE 0x10 +#define ADT7310_MODE_MASK 0x60 +#define ADT7310_ONESHOT 0x20 +#define ADT7310_SPS 0x40 +#define ADT7310_PD 0x60 +#define ADT7310_RESOLUTION 0x80 + +/* + * ADT7310 masks + */ +#define ADT7310_T16_VALUE_SIGN 0x8000 +#define ADT7310_T16_VALUE_FLOAT_OFFSET 7 +#define ADT7310_T16_VALUE_FLOAT_MASK 0x7F +#define ADT7310_T13_VALUE_SIGN 0x1000 +#define ADT7310_T13_VALUE_OFFSET 3 +#define ADT7310_T13_VALUE_FLOAT_OFFSET 4 +#define ADT7310_T13_VALUE_FLOAT_MASK 0xF +#define ADT7310_T_HYST_MASK 0xF +#define ADT7310_DEVICE_ID_MASK 0x7 +#define ADT7310_MANUFACTORY_ID_MASK 0xF8 +#define ADT7310_MANUFACTORY_ID_OFFSET 3 + + +#define ADT7310_CMD_REG_MASK 0x28 +#define ADT7310_CMD_REG_OFFSET 3 +#define ADT7310_CMD_READ 0x40 +#define ADT7310_CMD_CON_READ 0x4 + +#define ADT7310_IRQS 2 + +/* + * struct adt7310_chip_info - chip specifc information + */ + +struct adt7310_chip_info { + const char *name; + struct spi_device *spi_dev; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + s64 last_timestamp; + u8 config; +}; + +/* + * adt7310 register access by SPI + */ + +static int adt7310_spi_read_word(struct adt7310_chip_info *chip, u8 reg, u16 *data) +{ + struct spi_device *spi_dev = chip->spi_dev; + u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; + int ret = 0; + + command |= ADT7310_CMD_READ; + ret = spi_write(spi_dev, &command, sizeof(command)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI write command error\n"); + return ret; + } + + ret = spi_read(spi_dev, (u8 *)data, sizeof(*data)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI read word error\n"); + return ret; + } + + *data = be16_to_cpu(*data); + + return 0; +} + +static int adt7310_spi_write_word(struct adt7310_chip_info *chip, u8 reg, u16 data) +{ + struct spi_device *spi_dev = chip->spi_dev; + u8 buf[3]; + int ret = 0; + + buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; + buf[1] = (u8)(data >> 8); + buf[2] = (u8)(data & 0xFF); + + ret = spi_write(spi_dev, buf, 3); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI write word error\n"); + return ret; + } + + return ret; +} + +static int adt7310_spi_read_byte(struct adt7310_chip_info *chip, u8 reg, u8 *data) +{ + struct spi_device *spi_dev = chip->spi_dev; + u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; + int ret = 0; + + command |= ADT7310_CMD_READ; + ret = spi_write(spi_dev, &command, sizeof(command)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI write command error\n"); + return ret; + } + + ret = spi_read(spi_dev, data, sizeof(*data)); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI read byte error\n"); + return ret; + } + + return 0; +} + +static int adt7310_spi_write_byte(struct adt7310_chip_info *chip, u8 reg, u8 data) +{ + struct spi_device *spi_dev = chip->spi_dev; + u8 buf[2]; + int ret = 0; + + buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; + buf[1] = data; + + ret = spi_write(spi_dev, buf, 2); + if (ret < 0) { + dev_err(&spi_dev->dev, "SPI write byte error\n"); + return ret; + } + + return ret; +} + +static ssize_t adt7310_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + u8 config; + + config = chip->config & ADT7310_MODE_MASK; + + switch (config) { + case ADT7310_PD: + return sprintf(buf, "power-down\n"); + case ADT7310_ONESHOT: + return sprintf(buf, "one-shot\n"); + case ADT7310_SPS: + return sprintf(buf, "sps\n"); + default: + return sprintf(buf, "full\n"); + } +} + +static ssize_t adt7310_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + u16 config; + int ret; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & (~ADT7310_MODE_MASK); + if (strcmp(buf, "power-down")) + config |= ADT7310_PD; + else if (strcmp(buf, "one-shot")) + config |= ADT7310_ONESHOT; + else if (strcmp(buf, "sps")) + config |= ADT7310_SPS; + + ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return len; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + adt7310_show_mode, + adt7310_store_mode, + 0); + +static ssize_t adt7310_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "full\none-shot\nsps\npower-down\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7310_show_available_modes, NULL, 0); + +static ssize_t adt7310_show_resolution(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + int ret; + int bits; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + if (chip->config & ADT7310_RESOLUTION) + bits = 16; + else + bits = 13; + + return sprintf(buf, "%d bits\n", bits); +} + +static ssize_t adt7310_store_resolution(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + unsigned long data; + u16 config; + int ret; + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & (~ADT7310_RESOLUTION); + if (data) + config |= ADT7310_RESOLUTION; + + ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return len; +} + +static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR, + adt7310_show_resolution, + adt7310_store_resolution, + 0); + +static ssize_t adt7310_show_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + u8 id; + int ret; + + ret = adt7310_spi_read_byte(chip, ADT7310_ID, &id); + if (ret) + return -EIO; + + return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n", + id & ADT7310_DEVICE_ID_MASK, + (id & ADT7310_MANUFACTORY_ID_MASK) >> ADT7310_MANUFACTORY_ID_OFFSET); +} + +static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR, + adt7310_show_id, + NULL, + 0); + +static ssize_t adt7310_convert_temperature(struct adt7310_chip_info *chip, + u16 data, char *buf) +{ + char sign = ' '; + + if (chip->config & ADT7310_RESOLUTION) { + if (data & ADT7310_T16_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data); + sign = '-'; + } + return sprintf(buf, "%c%d.%.7d\n", sign, + (data >> ADT7310_T16_VALUE_FLOAT_OFFSET), + (data & ADT7310_T16_VALUE_FLOAT_MASK) * 78125); + } else { + if (data & ADT7310_T13_VALUE_SIGN) { + /* convert supplement to positive value */ + data >>= ADT7310_T13_VALUE_OFFSET; + data = (ADT7310_T13_VALUE_SIGN << 1) - data; + sign = '-'; + } + return sprintf(buf, "%c%d.%.4d\n", sign, + (data >> ADT7310_T13_VALUE_FLOAT_OFFSET), + (data & ADT7310_T13_VALUE_FLOAT_MASK) * 625); + } +} + +static ssize_t adt7310_show_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + u8 status; + u16 data; + int ret, i = 0; + + do { + ret = adt7310_spi_read_byte(chip, ADT7310_STATUS, &status); + if (ret) + return -EIO; + i++; + if (i == 10000) + return -EIO; + } while (status & ADT7310_STAT_NOT_RDY); + + ret = adt7310_spi_read_word(chip, ADT7310_TEMPERATURE, &data); + if (ret) + return -EIO; + + return adt7310_convert_temperature(chip, data, buf); +} + +static IIO_DEVICE_ATTR(value, S_IRUGO, adt7310_show_value, NULL, 0); + +static ssize_t adt7310_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, adt7310_show_name, NULL, 0); + +static struct attribute *adt7310_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_resolution.dev_attr.attr, + &iio_dev_attr_id.dev_attr.attr, + &iio_dev_attr_value.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group adt7310_attribute_group = { + .attrs = adt7310_attributes, +}; + +/* + * temperature bound events + */ + +#define IIO_EVENT_CODE_ADT7310_ABOVE_ALARM IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_ADT7310_BELLOW_ALARM IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_ADT7310_ABOVE_CRIT IIO_BUFFER_EVENT_CODE(2) + +static void adt7310_interrupt_bh(struct work_struct *work_s) +{ + struct adt7310_chip_info *chip = + container_of(work_s, struct adt7310_chip_info, thresh_work); + u8 status; + + if (adt7310_spi_read_byte(chip, ADT7310_STATUS, &status)) + return; + + if (status & ADT7310_STAT_T_HIGH) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7310_ABOVE_ALARM, + chip->last_timestamp); + if (status & ADT7310_STAT_T_LOW) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7310_BELLOW_ALARM, + chip->last_timestamp); + if (status & ADT7310_STAT_T_CRIT) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7310_ABOVE_CRIT, + chip->last_timestamp); +} + +static int adt7310_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adt7310_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(adt7310, &adt7310_interrupt); +IIO_EVENT_SH(adt7310_ct, &adt7310_interrupt); + +static ssize_t adt7310_show_event_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + int ret; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + if (chip->config & ADT7310_EVENT_MODE) + return sprintf(buf, "interrupt\n"); + else + return sprintf(buf, "comparator\n"); +} + +static ssize_t adt7310_set_event_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + u16 config; + int ret; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config &= ~ADT7310_EVENT_MODE; + if (strcmp(buf, "comparator") != 0) + config |= ADT7310_EVENT_MODE; + + ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return len; +} + +static ssize_t adt7310_show_available_event_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "comparator\ninterrupt\n"); +} + +static ssize_t adt7310_show_fault_queue(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + int ret; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", chip->config & ADT7310_FAULT_QUEUE_MASK); +} + +static ssize_t adt7310_set_fault_queue(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + u8 config; + + ret = strict_strtoul(buf, 10, &data); + if (ret || data > 3) + return -EINVAL; + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT7310_FAULT_QUEUE_MASK; + config |= data; + ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return len; +} + +static inline ssize_t adt7310_show_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + u16 data; + int ret; + + ret = adt7310_spi_read_word(chip, bound_reg, &data); + if (ret) + return -EIO; + + return adt7310_convert_temperature(chip, data, buf); +} + +static inline ssize_t adt7310_set_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + long tmp1, tmp2; + u16 data; + char *pos; + int ret; + + pos = strchr(buf, '.'); + + ret = strict_strtol(buf, 10, &tmp1); + + if (ret || tmp1 > 127 || tmp1 < -128) + return -EINVAL; + + if (pos) { + len = strlen(pos); + + if (chip->config & ADT7310_RESOLUTION) { + if (len > ADT7310_T16_VALUE_FLOAT_OFFSET) + len = ADT7310_T16_VALUE_FLOAT_OFFSET; + pos[len] = 0; + ret = strict_strtol(pos, 10, &tmp2); + + if (!ret) + tmp2 = (tmp2 / 78125) * 78125; + } else { + if (len > ADT7310_T13_VALUE_FLOAT_OFFSET) + len = ADT7310_T13_VALUE_FLOAT_OFFSET; + pos[len] = 0; + ret = strict_strtol(pos, 10, &tmp2); + + if (!ret) + tmp2 = (tmp2 / 625) * 625; + } + } + + if (tmp1 < 0) + data = (u16)(-tmp1); + else + data = (u16)tmp1; + + if (chip->config & ADT7310_RESOLUTION) { + data = (data << ADT7310_T16_VALUE_FLOAT_OFFSET) | + (tmp2 & ADT7310_T16_VALUE_FLOAT_MASK); + + if (tmp1 < 0) + /* convert positive value to supplyment */ + data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data); + } else { + data = (data << ADT7310_T13_VALUE_FLOAT_OFFSET) | + (tmp2 & ADT7310_T13_VALUE_FLOAT_MASK); + + if (tmp1 < 0) + /* convert positive value to supplyment */ + data = (ADT7310_T13_VALUE_SIGN << 1) - data; + data <<= ADT7310_T13_VALUE_OFFSET; + } + + ret = adt7310_spi_write_word(chip, bound_reg, data); + if (ret) + return -EIO; + + return len; +} + +static ssize_t adt7310_show_t_alarm_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7310_show_t_bound(dev, attr, + ADT7310_T_ALARM_HIGH, buf); +} + +static inline ssize_t adt7310_set_t_alarm_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7310_set_t_bound(dev, attr, + ADT7310_T_ALARM_HIGH, buf, len); +} + +static ssize_t adt7310_show_t_alarm_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7310_show_t_bound(dev, attr, + ADT7310_T_ALARM_LOW, buf); +} + +static inline ssize_t adt7310_set_t_alarm_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7310_set_t_bound(dev, attr, + ADT7310_T_ALARM_LOW, buf, len); +} + +static ssize_t adt7310_show_t_crit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7310_show_t_bound(dev, attr, + ADT7310_T_CRIT, buf); +} + +static inline ssize_t adt7310_set_t_crit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7310_set_t_bound(dev, attr, + ADT7310_T_CRIT, buf, len); +} + +static ssize_t adt7310_show_t_hyst(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + int ret; + u8 t_hyst; + + ret = adt7310_spi_read_byte(chip, ADT7310_T_HYST, &t_hyst); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", t_hyst & ADT7310_T_HYST_MASK); +} + +static inline ssize_t adt7310_set_t_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7310_chip_info *chip = dev_info->dev_data; + int ret; + unsigned long data; + u8 t_hyst; + + ret = strict_strtol(buf, 10, &data); + + if (ret || data > ADT7310_T_HYST_MASK) + return -EINVAL; + + t_hyst = (u8)data; + + ret = adt7310_spi_write_byte(chip, ADT7310_T_HYST, t_hyst); + if (ret) + return -EIO; + + return len; +} + +IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7310, + adt7310_show_event_mode, adt7310_set_event_mode, 0); +IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7310, + adt7310_show_available_event_modes, NULL, 0); +IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt7310, + adt7310_show_fault_queue, adt7310_set_fault_queue, 0); +IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7310, + adt7310_show_t_alarm_high, adt7310_set_t_alarm_high, 0); +IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7310, + adt7310_show_t_alarm_low, adt7310_set_t_alarm_low, 0); +IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7310_ct, + adt7310_show_t_crit, adt7310_set_t_crit, 0); +IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7310, + adt7310_show_t_hyst, adt7310_set_t_hyst, 0); + +static struct attribute *adt7310_event_int_attributes[] = { + &iio_event_attr_event_mode.dev_attr.attr, + &iio_event_attr_available_event_modes.dev_attr.attr, + &iio_event_attr_fault_queue.dev_attr.attr, + &iio_event_attr_t_alarm_high.dev_attr.attr, + &iio_event_attr_t_alarm_low.dev_attr.attr, + &iio_event_attr_t_hyst.dev_attr.attr, + NULL, +}; + +static struct attribute *adt7310_event_ct_attributes[] = { + &iio_event_attr_event_mode.dev_attr.attr, + &iio_event_attr_available_event_modes.dev_attr.attr, + &iio_event_attr_fault_queue.dev_attr.attr, + &iio_event_attr_t_crit.dev_attr.attr, + &iio_event_attr_t_hyst.dev_attr.attr, + NULL, +}; + +static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = { + { + .attrs = adt7310_event_int_attributes, + }, + { + .attrs = adt7310_event_ct_attributes, + } +}; + +/* + * device probe and remove + */ + +static int __devinit adt7310_probe(struct spi_device *spi_dev) +{ + struct adt7310_chip_info *chip; + int ret = 0; + unsigned long *adt7310_platform_data = spi_dev->dev.platform_data; + unsigned long irq_flags; + + chip = kzalloc(sizeof(struct adt7310_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + dev_set_drvdata(&spi_dev->dev, chip); + + chip->spi_dev = spi_dev; + chip->name = spi_dev->modalias; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + chip->indio_dev->dev.parent = &spi_dev->dev; + chip->indio_dev->attrs = &adt7310_attribute_group; + chip->indio_dev->event_attrs = adt7310_event_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = ADT7310_IRQS; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + /* CT critcal temperature event. line 0 */ + if (spi_dev->irq) { + if (adt7310_platform_data[2]) + irq_flags = adt7310_platform_data[2]; + else + irq_flags = IRQF_TRIGGER_LOW; + ret = iio_register_interrupt_line(spi_dev->irq, + chip->indio_dev, + 0, + irq_flags, + chip->name); + if (ret) + goto error_unreg_dev; + + /* + * The event handler list element refer to iio_event_adt7310. + * All event attributes bind to the same event handler. + * One event handler can only be added to one event list. + */ + iio_add_event_to_list(&iio_event_adt7310, + &chip->indio_dev->interrupts[0]->ev_list); + } + + /* INT bound temperature alarm event. line 1 */ + if (adt7310_platform_data[0]) { + ret = iio_register_interrupt_line(adt7310_platform_data[0], + chip->indio_dev, + 1, + adt7310_platform_data[1], + chip->name); + if (ret) + goto error_unreg_ct_irq; + + /* + * The event handler list element refer to iio_event_adt7310. + * All event attributes bind to the same event handler. + * One event handler can only be added to one event list. + */ + iio_add_event_to_list(&iio_event_adt7310_ct, + &chip->indio_dev->interrupts[1]->ev_list); + } + + if (spi_dev->irq && adt7310_platform_data[0]) { + INIT_WORK(&chip->thresh_work, adt7310_interrupt_bh); + + ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); + if (ret) { + ret = -EIO; + goto error_unreg_int_irq; + } + + /* set irq polarity low level */ + chip->config &= ~ADT7310_CT_POLARITY; + + if (adt7310_platform_data[1] & IRQF_TRIGGER_HIGH) + chip->config |= ADT7310_INT_POLARITY; + else + chip->config &= ~ADT7310_INT_POLARITY; + + ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, chip->config); + if (ret) { + ret = -EIO; + goto error_unreg_int_irq; + } + } + + dev_info(&spi_dev->dev, "%s temperature sensor registered.\n", + chip->name); + + return 0; + +error_unreg_int_irq: + iio_unregister_interrupt_line(chip->indio_dev, 1); +error_unreg_ct_irq: + iio_unregister_interrupt_line(chip->indio_dev, 0); +error_unreg_dev: + iio_device_unregister(chip->indio_dev); +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit adt7310_remove(struct spi_device *spi_dev) +{ + struct adt7310_chip_info *chip = dev_get_drvdata(&spi_dev->dev); + struct iio_dev *indio_dev = chip->indio_dev; + unsigned long *adt7310_platform_data = spi_dev->dev.platform_data; + + dev_set_drvdata(&spi_dev->dev, NULL); + if (adt7310_platform_data[0]) + iio_unregister_interrupt_line(indio_dev, 1); + if (spi_dev->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + kfree(chip); + + return 0; +} + +static const struct spi_device_id adt7310_id[] = { + { "adt7310", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(spi, adt7310_id); + +static struct spi_driver adt7310_driver = { + .driver = { + .name = "adt7310", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = adt7310_probe, + .remove = __devexit_p(adt7310_remove), + .id_table = adt7310_id, +}; + +static __init int adt7310_init(void) +{ + return spi_register_driver(&adt7310_driver); +} + +static __exit void adt7310_exit(void) +{ + spi_unregister_driver(&adt7310_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices ADT7310 digital" + " temperature sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(adt7310_init); +module_exit(adt7310_exit); -- cgit v1.2.3 From 06b86a75b148e44d489a960c047a8fc6926c841d Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 27 Oct 2010 21:44:02 -0400 Subject: staging: iio: adc: new driver for ADT7410 temperature sensors Signed-off-by: Sonic Zhang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 7 + drivers/staging/iio/adc/Makefile | 1 + drivers/staging/iio/adc/adt7410.c | 915 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 923 insertions(+) create mode 100644 drivers/staging/iio/adc/adt7410.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index cd355260f794..9ca6565d2bae 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -127,3 +127,10 @@ config ADT7310 help Say yes here to build support for Analog Devices ADT7310 temperature sensors. + +config ADT7410 + tristate "Analog Devices ADT7410 temperature sensor driver" + depends on I2C + help + Say yes here to build support for Analog Devices ADT7410 + temperature sensors. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 6067b66f6a0b..a7dce6bd5f3a 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_AD7745) += ad7745.o obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_ADT75) += adt75.o obj-$(CONFIG_ADT7310) += adt7310.o +obj-$(CONFIG_ADT7410) += adt7410.o diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c new file mode 100644 index 000000000000..c345f27ec7fc --- /dev/null +++ b/drivers/staging/iio/adc/adt7410.c @@ -0,0 +1,915 @@ +/* + * ADT7410 digital temperature sensor driver supporting ADT7410 + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +/* + * ADT7410 registers definition + */ + +#define ADT7410_TEMPERATURE 0 +#define ADT7410_STATUS 2 +#define ADT7410_CONFIG 3 +#define ADT7410_T_ALARM_HIGH 4 +#define ADT7410_T_ALARM_LOW 6 +#define ADT7410_T_CRIT 8 +#define ADT7410_T_HYST 0xA +#define ADT7410_ID 0xB +#define ADT7410_RESET 0x2F + +/* + * ADT7410 status + */ +#define ADT7410_STAT_T_LOW 0x10 +#define ADT7410_STAT_T_HIGH 0x20 +#define ADT7410_STAT_T_CRIT 0x40 +#define ADT7410_STAT_NOT_RDY 0x80 + +/* + * ADT7410 config + */ +#define ADT7410_FAULT_QUEUE_MASK 0x3 +#define ADT7410_CT_POLARITY 0x4 +#define ADT7410_INT_POLARITY 0x8 +#define ADT7410_EVENT_MODE 0x10 +#define ADT7410_MODE_MASK 0x60 +#define ADT7410_ONESHOT 0x20 +#define ADT7410_SPS 0x40 +#define ADT7410_PD 0x60 +#define ADT7410_RESOLUTION 0x80 + +/* + * ADT7410 masks + */ +#define ADT7410_T16_VALUE_SIGN 0x8000 +#define ADT7410_T16_VALUE_FLOAT_OFFSET 7 +#define ADT7410_T16_VALUE_FLOAT_MASK 0x7F +#define ADT7410_T13_VALUE_SIGN 0x1000 +#define ADT7410_T13_VALUE_OFFSET 3 +#define ADT7410_T13_VALUE_FLOAT_OFFSET 4 +#define ADT7410_T13_VALUE_FLOAT_MASK 0xF +#define ADT7410_T_HYST_MASK 0xF +#define ADT7410_DEVICE_ID_MASK 0xF +#define ADT7410_MANUFACTORY_ID_MASK 0xF0 +#define ADT7410_MANUFACTORY_ID_OFFSET 4 + +#define ADT7410_IRQS 2 + +/* + * struct adt7410_chip_info - chip specifc information + */ + +struct adt7410_chip_info { + const char *name; + struct i2c_client *client; + struct iio_dev *indio_dev; + struct work_struct thresh_work; + s64 last_timestamp; + u8 config; +}; + +/* + * adt7410 register access by I2C + */ + +static int adt7410_i2c_read_word(struct adt7410_chip_info *chip, u8 reg, u16 *data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = swab16((u16)ret); + + return 0; +} + +static int adt7410_i2c_write_word(struct adt7410_chip_info *chip, u8 reg, u16 data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_write_word_data(client, reg, swab16(data)); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int adt7410_i2c_read_byte(struct adt7410_chip_info *chip, u8 reg, u8 *data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = (u8)ret; + + return 0; +} + +static int adt7410_i2c_write_byte(struct adt7410_chip_info *chip, u8 reg, u8 data) +{ + struct i2c_client *client = chip->client; + int ret = 0; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static ssize_t adt7410_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + u8 config; + + config = chip->config & ADT7410_MODE_MASK; + + switch (config) { + case ADT7410_PD: + return sprintf(buf, "power-down\n"); + case ADT7410_ONESHOT: + return sprintf(buf, "one-shot\n"); + case ADT7410_SPS: + return sprintf(buf, "sps\n"); + default: + return sprintf(buf, "full\n"); + } +} + +static ssize_t adt7410_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + u16 config; + int ret; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & (~ADT7410_MODE_MASK); + if (strcmp(buf, "power-down")) + config |= ADT7410_PD; + else if (strcmp(buf, "one-shot")) + config |= ADT7410_ONESHOT; + else if (strcmp(buf, "sps")) + config |= ADT7410_SPS; + + ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, + adt7410_show_mode, + adt7410_store_mode, + 0); + +static ssize_t adt7410_show_available_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "full\none-shot\nsps\npower-down\n"); +} + +static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7410_show_available_modes, NULL, 0); + +static ssize_t adt7410_show_resolution(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + int ret; + int bits; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + if (chip->config & ADT7410_RESOLUTION) + bits = 16; + else + bits = 13; + + return sprintf(buf, "%d bits\n", bits); +} + +static ssize_t adt7410_store_resolution(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + unsigned long data; + u16 config; + int ret; + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & (~ADT7410_RESOLUTION); + if (data) + config |= ADT7410_RESOLUTION; + + ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR, + adt7410_show_resolution, + adt7410_store_resolution, + 0); + +static ssize_t adt7410_show_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + u8 id; + int ret; + + ret = adt7410_i2c_read_byte(chip, ADT7410_ID, &id); + if (ret) + return -EIO; + + return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n", + id & ADT7410_DEVICE_ID_MASK, + (id & ADT7410_MANUFACTORY_ID_MASK) >> ADT7410_MANUFACTORY_ID_OFFSET); +} + +static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR, + adt7410_show_id, + NULL, + 0); + +static ssize_t adt7410_convert_temperature(struct adt7410_chip_info *chip, + u16 data, char *buf) +{ + char sign = ' '; + + if (chip->config & ADT7410_RESOLUTION) { + if (data & ADT7410_T16_VALUE_SIGN) { + /* convert supplement to positive value */ + data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data); + sign = '-'; + } + return sprintf(buf, "%c%d.%.7d\n", sign, + (data >> ADT7410_T16_VALUE_FLOAT_OFFSET), + (data & ADT7410_T16_VALUE_FLOAT_MASK) * 78125); + } else { + if (data & ADT7410_T13_VALUE_SIGN) { + /* convert supplement to positive value */ + data >>= ADT7410_T13_VALUE_OFFSET; + data = (ADT7410_T13_VALUE_SIGN << 1) - data; + sign = '-'; + } + return sprintf(buf, "%c%d.%.4d\n", sign, + (data >> ADT7410_T13_VALUE_FLOAT_OFFSET), + (data & ADT7410_T13_VALUE_FLOAT_MASK) * 625); + } +} + +static ssize_t adt7410_show_value(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + u8 status; + u16 data; + int ret, i = 0; + + do { + ret = adt7410_i2c_read_byte(chip, ADT7410_STATUS, &status); + if (ret) + return -EIO; + i++; + if (i == 10000) + return -EIO; + } while (status & ADT7410_STAT_NOT_RDY); + + ret = adt7410_i2c_read_word(chip, ADT7410_TEMPERATURE, &data); + if (ret) + return -EIO; + + return adt7410_convert_temperature(chip, data, buf); +} + +static IIO_DEVICE_ATTR(value, S_IRUGO, adt7410_show_value, NULL, 0); + +static ssize_t adt7410_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + return sprintf(buf, "%s\n", chip->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL, 0); + +static struct attribute *adt7410_attributes[] = { + &iio_dev_attr_available_modes.dev_attr.attr, + &iio_dev_attr_mode.dev_attr.attr, + &iio_dev_attr_resolution.dev_attr.attr, + &iio_dev_attr_id.dev_attr.attr, + &iio_dev_attr_value.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group adt7410_attribute_group = { + .attrs = adt7410_attributes, +}; + +/* + * temperature bound events + */ + +#define IIO_EVENT_CODE_ADT7410_ABOVE_ALARM IIO_BUFFER_EVENT_CODE(0) +#define IIO_EVENT_CODE_ADT7410_BELLOW_ALARM IIO_BUFFER_EVENT_CODE(1) +#define IIO_EVENT_CODE_ADT7410_ABOVE_CRIT IIO_BUFFER_EVENT_CODE(2) + +static void adt7410_interrupt_bh(struct work_struct *work_s) +{ + struct adt7410_chip_info *chip = + container_of(work_s, struct adt7410_chip_info, thresh_work); + u8 status; + + if (adt7410_i2c_read_byte(chip, ADT7410_STATUS, &status)) + return; + + enable_irq(chip->client->irq); + + if (status & ADT7410_STAT_T_HIGH) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7410_ABOVE_ALARM, + chip->last_timestamp); + if (status & ADT7410_STAT_T_LOW) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7410_BELLOW_ALARM, + chip->last_timestamp); + if (status & ADT7410_STAT_T_CRIT) + iio_push_event(chip->indio_dev, 0, + IIO_EVENT_CODE_ADT7410_ABOVE_CRIT, + chip->last_timestamp); +} + +static int adt7410_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct adt7410_chip_info *chip = dev_info->dev_data; + + chip->last_timestamp = timestamp; + schedule_work(&chip->thresh_work); + + return 0; +} + +IIO_EVENT_SH(adt7410, &adt7410_interrupt); +IIO_EVENT_SH(adt7410_ct, &adt7410_interrupt); + +static ssize_t adt7410_show_event_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + int ret; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + if (chip->config & ADT7410_EVENT_MODE) + return sprintf(buf, "interrupt\n"); + else + return sprintf(buf, "comparator\n"); +} + +static ssize_t adt7410_set_event_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + u16 config; + int ret; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config &= ~ADT7410_EVENT_MODE; + if (strcmp(buf, "comparator") != 0) + config |= ADT7410_EVENT_MODE; + + ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static ssize_t adt7410_show_available_event_modes(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "comparator\ninterrupt\n"); +} + +static ssize_t adt7410_show_fault_queue(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + int ret; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", chip->config & ADT7410_FAULT_QUEUE_MASK); +} + +static ssize_t adt7410_set_fault_queue(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + unsigned long data; + int ret; + u8 config; + + ret = strict_strtoul(buf, 10, &data); + if (ret || data > 3) + return -EINVAL; + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) + return -EIO; + + config = chip->config & ~ADT7410_FAULT_QUEUE_MASK; + config |= data; + ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config); + if (ret) + return -EIO; + + chip->config = config; + + return ret; +} + +static inline ssize_t adt7410_show_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + u16 data; + int ret; + + ret = adt7410_i2c_read_word(chip, bound_reg, &data); + if (ret) + return -EIO; + + return adt7410_convert_temperature(chip, data, buf); +} + +static inline ssize_t adt7410_set_t_bound(struct device *dev, + struct device_attribute *attr, + u8 bound_reg, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + long tmp1, tmp2; + u16 data; + char *pos; + int ret; + + pos = strchr(buf, '.'); + + ret = strict_strtol(buf, 10, &tmp1); + + if (ret || tmp1 > 127 || tmp1 < -128) + return -EINVAL; + + if (pos) { + len = strlen(pos); + + if (chip->config & ADT7410_RESOLUTION) { + if (len > ADT7410_T16_VALUE_FLOAT_OFFSET) + len = ADT7410_T16_VALUE_FLOAT_OFFSET; + pos[len] = 0; + ret = strict_strtol(pos, 10, &tmp2); + + if (!ret) + tmp2 = (tmp2 / 78125) * 78125; + } else { + if (len > ADT7410_T13_VALUE_FLOAT_OFFSET) + len = ADT7410_T13_VALUE_FLOAT_OFFSET; + pos[len] = 0; + ret = strict_strtol(pos, 10, &tmp2); + + if (!ret) + tmp2 = (tmp2 / 625) * 625; + } + } + + if (tmp1 < 0) + data = (u16)(-tmp1); + else + data = (u16)tmp1; + + if (chip->config & ADT7410_RESOLUTION) { + data = (data << ADT7410_T16_VALUE_FLOAT_OFFSET) | + (tmp2 & ADT7410_T16_VALUE_FLOAT_MASK); + + if (tmp1 < 0) + /* convert positive value to supplyment */ + data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data); + } else { + data = (data << ADT7410_T13_VALUE_FLOAT_OFFSET) | + (tmp2 & ADT7410_T13_VALUE_FLOAT_MASK); + + if (tmp1 < 0) + /* convert positive value to supplyment */ + data = (ADT7410_T13_VALUE_SIGN << 1) - data; + data <<= ADT7410_T13_VALUE_OFFSET; + } + + ret = adt7410_i2c_write_word(chip, bound_reg, data); + if (ret) + return -EIO; + + return ret; +} + +static ssize_t adt7410_show_t_alarm_high(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7410_show_t_bound(dev, attr, + ADT7410_T_ALARM_HIGH, buf); +} + +static inline ssize_t adt7410_set_t_alarm_high(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7410_set_t_bound(dev, attr, + ADT7410_T_ALARM_HIGH, buf, len); +} + +static ssize_t adt7410_show_t_alarm_low(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7410_show_t_bound(dev, attr, + ADT7410_T_ALARM_LOW, buf); +} + +static inline ssize_t adt7410_set_t_alarm_low(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7410_set_t_bound(dev, attr, + ADT7410_T_ALARM_LOW, buf, len); +} + +static ssize_t adt7410_show_t_crit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return adt7410_show_t_bound(dev, attr, + ADT7410_T_CRIT, buf); +} + +static inline ssize_t adt7410_set_t_crit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + return adt7410_set_t_bound(dev, attr, + ADT7410_T_CRIT, buf, len); +} + +static ssize_t adt7410_show_t_hyst(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + int ret; + u8 t_hyst; + + ret = adt7410_i2c_read_byte(chip, ADT7410_T_HYST, &t_hyst); + if (ret) + return -EIO; + + return sprintf(buf, "%d\n", t_hyst & ADT7410_T_HYST_MASK); +} + +static inline ssize_t adt7410_set_t_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct adt7410_chip_info *chip = dev_info->dev_data; + int ret; + unsigned long data; + u8 t_hyst; + + ret = strict_strtol(buf, 10, &data); + + if (ret || data > ADT7410_T_HYST_MASK) + return -EINVAL; + + t_hyst = (u8)data; + + ret = adt7410_i2c_write_byte(chip, ADT7410_T_HYST, t_hyst); + if (ret) + return -EIO; + + return ret; +} + +IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7410, + adt7410_show_event_mode, adt7410_set_event_mode, 0); +IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7410, + adt7410_show_available_event_modes, NULL, 0); +IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt7410, + adt7410_show_fault_queue, adt7410_set_fault_queue, 0); +IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7410, + adt7410_show_t_alarm_high, adt7410_set_t_alarm_high, 0); +IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7410, + adt7410_show_t_alarm_low, adt7410_set_t_alarm_low, 0); +IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7410_ct, + adt7410_show_t_crit, adt7410_set_t_crit, 0); +IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7410, + adt7410_show_t_hyst, adt7410_set_t_hyst, 0); + +static struct attribute *adt7410_event_int_attributes[] = { + &iio_event_attr_event_mode.dev_attr.attr, + &iio_event_attr_available_event_modes.dev_attr.attr, + &iio_event_attr_fault_queue.dev_attr.attr, + &iio_event_attr_t_alarm_high.dev_attr.attr, + &iio_event_attr_t_alarm_low.dev_attr.attr, + &iio_event_attr_t_hyst.dev_attr.attr, + NULL, +}; + +static struct attribute *adt7410_event_ct_attributes[] = { + &iio_event_attr_event_mode.dev_attr.attr, + &iio_event_attr_available_event_modes.dev_attr.attr, + &iio_event_attr_fault_queue.dev_attr.attr, + &iio_event_attr_t_crit.dev_attr.attr, + &iio_event_attr_t_hyst.dev_attr.attr, + NULL, +}; + +static struct attribute_group adt7410_event_attribute_group[ADT7410_IRQS] = { + { + .attrs = adt7410_event_int_attributes, + }, + { + .attrs = adt7410_event_ct_attributes, + } +}; + +/* + * device probe and remove + */ + +static int __devinit adt7410_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adt7410_chip_info *chip; + int ret = 0; + unsigned long *adt7410_platform_data = client->dev.platform_data; + + chip = kzalloc(sizeof(struct adt7410_chip_info), GFP_KERNEL); + + if (chip == NULL) + return -ENOMEM; + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, chip); + + chip->client = client; + chip->name = id->name; + + chip->indio_dev = iio_allocate_device(); + if (chip->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_chip; + } + + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->attrs = &adt7410_attribute_group; + chip->indio_dev->event_attrs = adt7410_event_attribute_group; + chip->indio_dev->dev_data = (void *)chip; + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->num_interrupt_lines = ADT7410_IRQS; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(chip->indio_dev); + if (ret) + goto error_free_dev; + + /* CT critcal temperature event. line 0 */ + if (client->irq) { + ret = iio_register_interrupt_line(client->irq, + chip->indio_dev, + 0, + IRQF_TRIGGER_LOW, + chip->name); + if (ret) + goto error_unreg_dev; + + /* + * The event handler list element refer to iio_event_adt7410. + * All event attributes bind to the same event handler. + * One event handler can only be added to one event list. + */ + iio_add_event_to_list(&iio_event_adt7410, + &chip->indio_dev->interrupts[0]->ev_list); + } + + /* INT bound temperature alarm event. line 1 */ + if (adt7410_platform_data[0]) { + ret = iio_register_interrupt_line(adt7410_platform_data[0], + chip->indio_dev, + 1, + adt7410_platform_data[1], + chip->name); + if (ret) + goto error_unreg_ct_irq; + + /* + * The event handler list element refer to iio_event_adt7410. + * All event attributes bind to the same event handler. + * One event handler can only be added to one event list. + */ + iio_add_event_to_list(&iio_event_adt7410_ct, + &chip->indio_dev->interrupts[1]->ev_list); + } + + if (client->irq && adt7410_platform_data[0]) { + INIT_WORK(&chip->thresh_work, adt7410_interrupt_bh); + + ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config); + if (ret) { + ret = -EIO; + goto error_unreg_int_irq; + } + + /* set irq polarity low level */ + chip->config &= ~ADT7410_CT_POLARITY; + + if (adt7410_platform_data[1] & IRQF_TRIGGER_HIGH) + chip->config |= ADT7410_INT_POLARITY; + else + chip->config &= ~ADT7410_INT_POLARITY; + + ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, chip->config); + if (ret) { + ret = -EIO; + goto error_unreg_int_irq; + } + } + + dev_info(&client->dev, "%s temperature sensor registered.\n", + id->name); + + return 0; + +error_unreg_int_irq: + iio_unregister_interrupt_line(chip->indio_dev, 1); +error_unreg_ct_irq: + iio_unregister_interrupt_line(chip->indio_dev, 0); +error_unreg_dev: + iio_device_unregister(chip->indio_dev); +error_free_dev: + iio_free_device(chip->indio_dev); +error_free_chip: + kfree(chip); + + return ret; +} + +static int __devexit adt7410_remove(struct i2c_client *client) +{ + struct adt7410_chip_info *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = chip->indio_dev; + unsigned long *adt7410_platform_data = client->dev.platform_data; + + if (adt7410_platform_data[0]) + iio_unregister_interrupt_line(indio_dev, 1); + if (client->irq) + iio_unregister_interrupt_line(indio_dev, 0); + iio_device_unregister(indio_dev); + iio_free_device(chip->indio_dev); + kfree(chip); + + return 0; +} + +static const struct i2c_device_id adt7410_id[] = { + { "adt7410", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, adt7410_id); + +static struct i2c_driver adt7410_driver = { + .driver = { + .name = "adt7410", + }, + .probe = adt7410_probe, + .remove = __devexit_p(adt7410_remove), + .id_table = adt7410_id, +}; + +static __init int adt7410_init(void) +{ + return i2c_add_driver(&adt7410_driver); +} + +static __exit void adt7410_exit(void) +{ + i2c_del_driver(&adt7410_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("Analog Devices ADT7410 digital" + " temperature sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(adt7410_init); +module_exit(adt7410_exit); -- cgit v1.2.3 From 4f0cd86d66a81fd77912504d0e0b5883c473512e Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:03 -0400 Subject: staging: iio: gyro: new driver for ADIS16251 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/Kconfig | 10 + drivers/staging/iio/gyro/Makefile | 3 + drivers/staging/iio/gyro/adis16251.h | 185 +++++++ drivers/staging/iio/gyro/adis16251_core.c | 777 ++++++++++++++++++++++++++++++ drivers/staging/iio/sysfs.h | 6 + 5 files changed, 981 insertions(+) create mode 100644 drivers/staging/iio/gyro/adis16251.h create mode 100644 drivers/staging/iio/gyro/adis16251_core.c (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index d1dde82dbc9e..c7a7d299b05c 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -14,3 +14,13 @@ config ADIS16260 This driver can also be built as a module. If so, the module will be called adis16260. + +config ADIS16251 + tristate "Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver" + depends on SPI + help + Say yes here to build support for Analog Devices adis16261 programmable + digital gyroscope sensor. + + This driver can also be built as a module. If so, the module + will be called adis16251. diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index b5f0dc01122c..8a592d8f7f72 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -5,3 +5,6 @@ adis16260-y := adis16260_core.o adis16260-$(CONFIG_IIO_RING_BUFFER) += adis16260_ring.o adis16260_trigger.o obj-$(CONFIG_ADIS16260) += adis16260.o + +adis16251-y := adis16251_core.o +obj-$(CONFIG_ADIS16251) += adis16251.o diff --git a/drivers/staging/iio/gyro/adis16251.h b/drivers/staging/iio/gyro/adis16251.h new file mode 100644 index 000000000000..999db4981413 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16251.h @@ -0,0 +1,185 @@ +#ifndef SPI_ADIS16251_H_ +#define SPI_ADIS16251_H_ + +#define ADIS16251_STARTUP_DELAY 220 /* ms */ + +#define ADIS16251_READ_REG(a) a +#define ADIS16251_WRITE_REG(a) ((a) | 0x80) + +#define ADIS16251_ENDURANCE 0x00 /* Flash memory write count */ +#define ADIS16251_SUPPLY_OUT 0x02 /* Power supply measurement */ +#define ADIS16251_GYRO_OUT 0x04 /* X-axis gyroscope output */ +#define ADIS16251_AUX_ADC 0x0A /* analog input channel measurement */ +#define ADIS16251_TEMP_OUT 0x0C /* internal temperature measurement */ +#define ADIS16251_ANGL_OUT 0x0E /* angle displacement */ +#define ADIS16251_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */ +#define ADIS16251_GYRO_SCALE 0x16 /* Calibration, scale adjustment */ +#define ADIS16251_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */ +#define ADIS16251_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */ +#define ADIS16251_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */ +#define ADIS16251_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */ +#define ADIS16251_ALM_CTRL 0x28 /* Alarm control */ +#define ADIS16251_AUX_DAC 0x30 /* Auxiliary DAC data */ +#define ADIS16251_GPIO_CTRL 0x32 /* Control, digital I/O line */ +#define ADIS16251_MSC_CTRL 0x34 /* Control, data ready, self-test settings */ +#define ADIS16251_SMPL_PRD 0x36 /* Control, internal sample rate */ +#define ADIS16251_SENS_AVG 0x38 /* Control, dynamic range, filtering */ +#define ADIS16251_SLP_CNT 0x3A /* Control, sleep mode initiation */ +#define ADIS16251_DIAG_STAT 0x3C /* Diagnostic, error flags */ +#define ADIS16251_GLOB_CMD 0x3E /* Control, global commands */ + +#define ADIS16251_ERROR_ACTIVE (1<<14) +#define ADIS16251_NEW_DATA (1<<14) + +/* MSC_CTRL */ +#define ADIS16251_MSC_CTRL_INT_SELF_TEST (1<<10) /* Internal self-test enable */ +#define ADIS16251_MSC_CTRL_NEG_SELF_TEST (1<<9) +#define ADIS16251_MSC_CTRL_POS_SELF_TEST (1<<8) +#define ADIS16251_MSC_CTRL_DATA_RDY_EN (1<<2) +#define ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) +#define ADIS16251_MSC_CTRL_DATA_RDY_DIO2 (1<<0) + +/* SMPL_PRD */ +#define ADIS16251_SMPL_PRD_TIME_BASE (1<<7) /* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */ +#define ADIS16251_SMPL_PRD_DIV_MASK 0x7F + +/* SLP_CNT */ +#define ADIS16251_SLP_CNT_POWER_OFF 0x80 + +/* DIAG_STAT */ +#define ADIS16251_DIAG_STAT_ALARM2 (1<<9) +#define ADIS16251_DIAG_STAT_ALARM1 (1<<8) +#define ADIS16251_DIAG_STAT_SELF_TEST (1<<5) +#define ADIS16251_DIAG_STAT_OVERFLOW (1<<4) +#define ADIS16251_DIAG_STAT_SPI_FAIL (1<<3) +#define ADIS16251_DIAG_STAT_FLASH_UPT (1<<2) +#define ADIS16251_DIAG_STAT_POWER_HIGH (1<<1) +#define ADIS16251_DIAG_STAT_POWER_LOW (1<<0) + +#define ADIS16251_DIAG_STAT_ERR_MASK (ADIS16261_DIAG_STAT_ALARM2 | \ + ADIS16261_DIAG_STAT_ALARM1 | \ + ADIS16261_DIAG_STAT_SELF_TEST | \ + ADIS16261_DIAG_STAT_OVERFLOW | \ + ADIS16261_DIAG_STAT_SPI_FAIL | \ + ADIS16261_DIAG_STAT_FLASH_UPT | \ + ADIS16261_DIAG_STAT_POWER_HIGH | \ + ADIS16261_DIAG_STAT_POWER_LOW) + +/* GLOB_CMD */ +#define ADIS16251_GLOB_CMD_SW_RESET (1<<7) +#define ADIS16251_GLOB_CMD_FLASH_UPD (1<<3) +#define ADIS16251_GLOB_CMD_DAC_LATCH (1<<2) +#define ADIS16251_GLOB_CMD_FAC_CALIB (1<<1) +#define ADIS16251_GLOB_CMD_AUTO_NULL (1<<0) + +#define ADIS16251_MAX_TX 24 +#define ADIS16251_MAX_RX 24 + +#define ADIS16251_SPI_SLOW (u32)(300 * 1000) +#define ADIS16251_SPI_BURST (u32)(1000 * 1000) +#define ADIS16251_SPI_FAST (u32)(2000 * 1000) + +/** + * struct adis16251_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16251_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; + +int adis16251_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val); + +int adis16251_spi_read_burst(struct device *dev, u8 *rx); + +int adis16251_spi_read_sequence(struct device *dev, + u8 *tx, u8 *rx, int num); + +int adis16251_set_irq(struct device *dev, bool enable); + +int adis16251_reset(struct device *dev); + +int adis16251_stop_device(struct device *dev); + +int adis16251_check_status(struct device *dev); + +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum adis16251_scan { + ADIS16251_SCAN_SUPPLY, + ADIS16251_SCAN_GYRO, + ADIS16251_SCAN_TEMP, + ADIS16251_SCAN_ADC_0, +}; + +void adis16251_remove_trigger(struct iio_dev *indio_dev); +int adis16251_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16251_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int adis16251_configure_ring(struct iio_dev *indio_dev); +void adis16251_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16251_initialize_ring(struct iio_ring_buffer *ring); +void adis16251_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16251_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16251_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16251_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16251_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16251_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16251_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16251_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16251_H_ */ diff --git a/drivers/staging/iio/gyro/adis16251_core.c b/drivers/staging/iio/gyro/adis16251_core.c new file mode 100644 index 000000000000..a0d400f7ee62 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16251_core.c @@ -0,0 +1,777 @@ +/* + * ADIS16251 Programmable Digital Gyroscope Sensor Driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "gyro.h" +#include "../adc/adc.h" + +#include "adis16251.h" + +#define DRIVER_NAME "adis16251" + +/* At the moment the spi framework doesn't allow global setting of cs_change. + * It's in the likely to be added comment at the top of spi.h. + * This means that use cannot be made of spi_write etc. + */ + +/** + * adis16251_spi_write_reg_8() - write single byte to a register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the register to be written + * @val: the value to write + **/ +int adis16251_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16251_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16251_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16251_spi_write_reg_16() - write 2 bytes to a pair of registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: value to be written + **/ +static int adis16251_spi_write_reg_16(struct device *dev, + u8 lower_reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16251_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, { + .tx_buf = st->tx + 2, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16251_WRITE_REG(lower_reg_address); + st->tx[1] = value & 0xFF; + st->tx[2] = ADIS16251_WRITE_REG(lower_reg_address + 1); + st->tx[3] = (value >> 8) & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +/** + * adis16251_spi_read_reg_16() - read 2 bytes from a 16-bit register + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @reg_address: the address of the lower of the two registers. Second register + * is assumed to have address one greater. + * @val: somewhere to pass back the value read + **/ +static int adis16251_spi_read_reg_16(struct device *dev, + u8 lower_reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16251_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, { + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + .cs_change = 1, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16251_READ_REG(lower_reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + st->tx[3] = 0; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + lower_reg_address); + goto error_ret; + } + *val = (st->rx[0] << 8) | st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +/** + * adis16251_spi_read_burst() - read all data registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read (min size is 24 bytes) + **/ +int adis16251_spi_read_burst(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16251_state *st = iio_dev_get_devdata(indio_dev); + u32 old_speed_hz = st->us->max_speed_hz; + int ret; + + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 2, + .cs_change = 0, + }, { + .rx_buf = rx, + .bits_per_word = 8, + .len = 24, + .cs_change = 1, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADIS16251_READ_REG(ADIS16251_GLOB_CMD); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + + st->us->max_speed_hz = min(ADIS16251_SPI_BURST, old_speed_hz); + spi_setup(st->us); + + ret = spi_sync(st->us, &msg); + if (ret) + dev_err(&st->us->dev, "problem when burst reading"); + + st->us->max_speed_hz = old_speed_hz; + spi_setup(st->us); + mutex_unlock(&st->buf_lock); + return ret; +} + +/** + * adis16251_spi_read_sequence() - read a sequence of 16-bit registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @tx: register addresses in bytes 0,2,4,6... (min size is 2*num bytes) + * @rx: somewhere to pass back the value read (min size is 2*num bytes) + **/ +int adis16251_spi_read_sequence(struct device *dev, + u8 *tx, u8 *rx, int num) +{ + struct spi_message msg; + struct spi_transfer *xfers; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16251_state *st = iio_dev_get_devdata(indio_dev); + int ret, i; + + xfers = kzalloc(num + 1, GFP_KERNEL); + if (xfers == NULL) { + dev_err(&st->us->dev, "memory alloc failed"); + ret = -ENOMEM; + goto error_ret; + } + + /* tx: |add1|addr2|addr3|...|addrN |zero| + * rx: |zero|res1 |res2 |...|resN-1|resN| */ + spi_message_init(&msg); + for (i = 0; i < num + 1; i++) { + if (i > 0) + xfers[i].rx_buf = st->rx + 2*(i - 1); + if (i < num) + xfers[i].tx_buf = st->tx + 2*i; + xfers[i].bits_per_word = 8; + xfers[i].len = 2; + xfers[i].cs_change = 1; + spi_message_add_tail(&xfers[i], &msg); + } + + mutex_lock(&st->buf_lock); + + ret = spi_sync(st->us, &msg); + if (ret) + dev_err(&st->us->dev, "problem when reading sequence"); + + mutex_unlock(&st->buf_lock); + kfree(xfers); + +error_ret: + return ret; +} + +static ssize_t adis16251_spi_read_signed(struct device *dev, + struct device_attribute *attr, + char *buf, + unsigned bits) +{ + int ret; + s16 val = 0; + unsigned shift = 16 - bits; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis16251_spi_read_reg_16(dev, this_attr->address, (u16 *)&val); + if (ret) + return ret; + + if (val & ADIS16251_ERROR_ACTIVE) + adis16251_check_status(dev); + val = ((s16)(val << shift) >> shift); + return sprintf(buf, "%d\n", val); +} + +static ssize_t adis16251_read_12bit_unsigned(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis16251_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + if (val & ADIS16251_ERROR_ACTIVE) + adis16251_check_status(dev); + + return sprintf(buf, "%u\n", val & 0x0FFF); +} + +static ssize_t adis16251_read_14bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + ssize_t ret; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16251_spi_read_signed(dev, attr, buf, 14); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16251_read_12bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + ssize_t ret; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16251_spi_read_signed(dev, attr, buf, 12); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static ssize_t adis16251_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = adis16251_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t adis16251_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret, len = 0; + u16 t; + int sps; + ret = adis16251_spi_read_reg_16(dev, + ADIS16251_SMPL_PRD, + &t); + if (ret) + return ret; + sps = (t & ADIS16251_SMPL_PRD_TIME_BASE) ? 8 : 256; + sps /= (t & ADIS16251_SMPL_PRD_DIV_MASK) + 1; + len = sprintf(buf, "%d SPS\n", sps); + return len; +} + +static ssize_t adis16251_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16251_state *st = iio_dev_get_devdata(indio_dev); + long val; + int ret; + u8 t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + + t = (256 / val); + if (t > 0) + t--; + t &= ADIS16251_SMPL_PRD_DIV_MASK; + if ((t & ADIS16251_SMPL_PRD_DIV_MASK) >= 0x0A) + st->us->max_speed_hz = ADIS16251_SPI_SLOW; + else + st->us->max_speed_hz = ADIS16251_SPI_FAST; + + ret = adis16251_spi_write_reg_8(dev, + ADIS16251_SMPL_PRD, + t); + + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +static ssize_t adis16251_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -1; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return adis16251_reset(dev); + } + return -1; +} + + + +int adis16251_set_irq(struct device *dev, bool enable) +{ + int ret; + u16 msc; + ret = adis16251_spi_read_reg_16(dev, ADIS16251_MSC_CTRL, &msc); + if (ret) + goto error_ret; + + msc |= ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH; + if (enable) + msc |= ADIS16251_MSC_CTRL_DATA_RDY_EN; + else + msc &= ~ADIS16251_MSC_CTRL_DATA_RDY_EN; + + ret = adis16251_spi_write_reg_16(dev, ADIS16251_MSC_CTRL, msc); + if (ret) + goto error_ret; + +error_ret: + return ret; +} + +int adis16251_reset(struct device *dev) +{ + int ret; + ret = adis16251_spi_write_reg_8(dev, + ADIS16251_GLOB_CMD, + ADIS16251_GLOB_CMD_SW_RESET); + if (ret) + dev_err(dev, "problem resetting device"); + + return ret; +} + +/* Power down the device */ +int adis16251_stop_device(struct device *dev) +{ + int ret; + u16 val = ADIS16251_SLP_CNT_POWER_OFF; + + ret = adis16251_spi_write_reg_16(dev, ADIS16251_SLP_CNT, val); + if (ret) + dev_err(dev, "problem with turning device off: SLP_CNT"); + + return ret; +} + +static int adis16251_self_test(struct device *dev) +{ + int ret; + + ret = adis16251_spi_write_reg_16(dev, + ADIS16251_MSC_CTRL, + ADIS16251_MSC_CTRL_INT_SELF_TEST); + if (ret) { + dev_err(dev, "problem starting self test"); + goto err_ret; + } + + adis16251_check_status(dev); + +err_ret: + return ret; +} + +int adis16251_check_status(struct device *dev) +{ + u16 status; + int ret; + + ret = adis16251_spi_read_reg_16(dev, ADIS16251_DIAG_STAT, &status); + + if (ret < 0) { + dev_err(dev, "Reading status failed\n"); + goto error_ret; + } + + if (!(status & ADIS16251_DIAG_STAT_ERR_MASK)) { + ret = 0; + goto error_ret; + } + + ret = -EFAULT; + + if (status & ADIS16251_DIAG_STAT_ALARM2) + dev_err(dev, "Alarm 2 active\n"); + if (status & ADIS16251_DIAG_STAT_ALARM1) + dev_err(dev, "Alarm 1 active\n"); + if (status & ADIS16251_DIAG_STAT_SELF_TEST) + dev_err(dev, "Self test error\n"); + if (status & ADIS16251_DIAG_STAT_OVERFLOW) + dev_err(dev, "Sensor overrange\n"); + if (status & ADIS16251_DIAG_STAT_SPI_FAIL) + dev_err(dev, "SPI failure\n"); + if (status & ADIS16251_DIAG_STAT_FLASH_UPT) + dev_err(dev, "Flash update failed\n"); + if (status & ADIS16251_DIAG_STAT_POWER_HIGH) + dev_err(dev, "Power supply above 5.25V\n"); + if (status & ADIS16251_DIAG_STAT_POWER_LOW) + dev_err(dev, "Power supply below 4.75V\n"); + +error_ret: + return ret; +} + +static int adis16251_initial_setup(struct adis16251_state *st) +{ + int ret; + u16 smp_prd; + struct device *dev = &st->indio_dev->dev; + + /* use low spi speed for init */ + st->us->max_speed_hz = ADIS16251_SPI_SLOW; + st->us->mode = SPI_MODE_3; + spi_setup(st->us); + + /* Disable IRQ */ + ret = adis16251_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + /* Do self test */ + + /* Read status register to check the result */ + ret = adis16251_check_status(dev); + if (ret) { + adis16251_reset(dev); + dev_err(dev, "device not playing ball -> reset"); + msleep(ADIS16251_STARTUP_DELAY); + ret = adis16251_check_status(dev); + if (ret) { + dev_err(dev, "giving up"); + goto err_ret; + } + } + + printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n", + st->us->chip_select, st->us->irq); + + /* use high spi speed if possible */ + ret = adis16251_spi_read_reg_16(dev, ADIS16251_SMPL_PRD, &smp_prd); + if (!ret && (smp_prd & ADIS16251_SMPL_PRD_DIV_MASK) < 0x0A) { + st->us->max_speed_hz = ADIS16251_SPI_SLOW; + spi_setup(st->us); + } + +err_ret: + return ret; +} + +static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16251_read_12bit_signed, + ADIS16251_SUPPLY_OUT); +static IIO_CONST_ATTR(in0_supply_scale, "0.0018315"); + +static IIO_DEV_ATTR_GYRO(adis16251_read_14bit_signed, + ADIS16251_GYRO_OUT); +static IIO_DEV_ATTR_GYRO_SCALE(S_IWUSR | S_IRUGO, + adis16251_read_12bit_signed, + adis16251_write_16bit, + ADIS16251_GYRO_SCALE); +static IIO_DEV_ATTR_GYRO_OFFSET(S_IWUSR | S_IRUGO, + adis16251_read_12bit_signed, + adis16251_write_16bit, + ADIS16251_GYRO_OFF); + +static IIO_DEV_ATTR_TEMP_RAW(adis16251_read_12bit_signed); +static IIO_CONST_ATTR(temp_offset, "25 K"); +static IIO_CONST_ATTR(temp_scale, "0.1453 K"); + +static IIO_DEV_ATTR_IN_NAMED_RAW(1, aux, adis16251_read_12bit_unsigned, + ADIS16251_AUX_ADC); +static IIO_CONST_ATTR(in1_aux_scale, "0.0006105"); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + adis16251_read_frequency, + adis16251_write_frequency); +static IIO_DEV_ATTR_ANGL(adis16251_read_14bit_signed, + ADIS16251_ANGL_OUT); + +static IIO_DEV_ATTR_RESET(adis16251_write_reset); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.129 ~ 256"); + +static IIO_CONST_ATTR(name, "adis16251"); + +static struct attribute *adis16251_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16251_event_attribute_group = { + .attrs = adis16251_event_attributes, +}; + +static struct attribute *adis16251_attributes[] = { + &iio_dev_attr_in0_supply_raw.dev_attr.attr, + &iio_const_attr_in0_supply_scale.dev_attr.attr, + &iio_dev_attr_gyro_raw.dev_attr.attr, + &iio_dev_attr_gyro_scale.dev_attr.attr, + &iio_dev_attr_gyro_offset.dev_attr.attr, + &iio_dev_attr_angl_raw.dev_attr.attr, + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_in1_aux_raw.dev_attr.attr, + &iio_const_attr_in1_aux_scale.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16251_attribute_group = { + .attrs = adis16251_attributes, +}; + +static int __devinit adis16251_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16251_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16251_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16251_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16251_event_attribute_group; + st->indio_dev->attrs = &adis16251_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis16251_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16251_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16251"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16251_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = adis16251_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + adis16251_remove_trigger(st->indio_dev); +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16251_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16251_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int adis16251_remove(struct spi_device *spi) +{ + int ret; + struct adis16251_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + ret = adis16251_stop_device(&(indio_dev->dev)); + if (ret) + goto err_ret; + + flush_scheduled_work(); + + adis16251_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16251_uninitialize_ring(indio_dev->ring); + adis16251_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; + +err_ret: + return ret; +} + +static struct spi_driver adis16251_driver = { + .driver = { + .name = "adis16251", + .owner = THIS_MODULE, + }, + .probe = adis16251_probe, + .remove = __devexit_p(adis16251_remove), +}; + +static __init int adis16251_init(void) +{ + return spi_register_driver(&adis16251_driver); +} +module_init(adis16251_init); + +static __exit void adis16251_exit(void) +{ + spi_unregister_driver(&adis16251_driver); +} +module_exit(adis16251_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h index ee91a95a8b95..18bdaac2509d 100644 --- a/drivers/staging/iio/sysfs.h +++ b/drivers/staging/iio/sysfs.h @@ -107,6 +107,12 @@ struct iio_const_attr { #define IIO_DEV_ATTR_NAME(_show) \ IIO_DEVICE_ATTR(name, S_IRUGO, _show, NULL, 0) +/** + * IIO_DEV_ATTR_RESET: resets the device + **/ +#define IIO_DEV_ATTR_RESET(_store) \ + IIO_DEVICE_ATTR(reset, S_IWUGO, NULL, _store, 0) + /** * IIO_CONST_ATTR_NAME - constant identifier * @_string: the name -- cgit v1.2.3 From e071f6b8e47834e9c91a299a5e773bebffe10e67 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:04 -0400 Subject: staging: iio: gyro: new driver for ADIS16060 digital output gyros Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/Kconfig | 7 + drivers/staging/iio/gyro/Makefile | 3 + drivers/staging/iio/gyro/adis16060.h | 101 ++++++++++ drivers/staging/iio/gyro/adis16060_core.c | 319 ++++++++++++++++++++++++++++++ 4 files changed, 430 insertions(+) create mode 100644 drivers/staging/iio/gyro/adis16060.h create mode 100644 drivers/staging/iio/gyro/adis16060_core.c (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index c7a7d299b05c..77c0fe84380b 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -3,6 +3,13 @@ # comment "Digital gyroscope sensors" +config ADIS16060 + tristate "Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver" + depends on SPI + help + Say yes here to build support for Analog Devices adis16060 wide bandwidth + yaw rate gyroscope with SPI. + config ADIS16260 tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver" depends on SPI diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index 8a592d8f7f72..e2c4acb608b4 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -2,6 +2,9 @@ # Makefile for digital gyroscope sensor drivers # +adis16060-y := adis16060_core.o +obj-$(CONFIG_ADIS16060) += adis16060.o + adis16260-y := adis16260_core.o adis16260-$(CONFIG_IIO_RING_BUFFER) += adis16260_ring.o adis16260_trigger.o obj-$(CONFIG_ADIS16260) += adis16260.o diff --git a/drivers/staging/iio/gyro/adis16060.h b/drivers/staging/iio/gyro/adis16060.h new file mode 100644 index 000000000000..5c00e5385ee0 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16060.h @@ -0,0 +1,101 @@ +#ifndef SPI_ADIS16060_H_ +#define SPI_ADIS16060_H_ + +#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */ +#define ADIS16060_SUPPLY_OUT 0x10 /* Measure Temperature */ +#define ADIS16060_AIN2 0x80 /* Measure AIN2 */ +#define ADIS16060_AIN1 0x40 /* Measure AIN1 */ +#define ADIS16060_TEMP_OUT 0x22 /* Set Positive Self-Test and Output for Angular Rate */ +#define ADIS16060_ANGL_OUT 0x21 /* Set Negative Self-Test and Output for Angular Rate */ + +#define ADIS16060_MAX_TX 3 +#define ADIS16060_MAX_RX 3 + +/** + * struct adis16060_state - device instance specific data + * @us_w: actual spi_device to write data + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16060_state { + struct spi_device *us_w; + struct spi_device *us_r; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; + +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum adis16060_scan { + ADIS16060_SCAN_GYRO, + ADIS16060_SCAN_TEMP, + ADIS16060_SCAN_ADC_1, + ADIS16060_SCAN_ADC_2, +}; + +void adis16060_remove_trigger(struct iio_dev *indio_dev); +int adis16060_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16060_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int adis16060_configure_ring(struct iio_dev *indio_dev); +void adis16060_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16060_initialize_ring(struct iio_ring_buffer *ring); +void adis16060_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16060_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16060_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16060_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16060_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16060_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16060_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16060_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16060_H_ */ diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c new file mode 100644 index 000000000000..fc48aca04bd3 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -0,0 +1,319 @@ +/* + * ADIS16060 Wide Bandwidth Yaw Rate Gyroscope with SPI driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "gyro.h" +#include "../adc/adc.h" + +#include "adis16060.h" + +#define DRIVER_NAME "adis16060" + +struct adis16060_state *adis16060_st; + +int adis16060_spi_write(struct device *dev, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16060_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = 0; + st->tx[1] = 0; + st->tx[2] = val; /* The last 8 bits clocked in are latched */ + + ret = spi_write(st->us_w, st->tx, 3); + mutex_unlock(&st->buf_lock); + + return ret; +} + +int adis16060_spi_read(struct device *dev, + u16 *val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16060_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + + ret = spi_read(st->us_r, st->rx, 3); + + /* The internal successive approximation ADC begins the conversion process + * on the falling edge of MSEL1 and starts to place data MSB first on the + * DOUT line at the 6th falling edge of SCLK + */ + if (ret == 0) + *val = ((st->rx[0] & 0x3) << 12) | (st->rx[1] << 4) | ((st->rx[2] >> 4) & 0xF); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static ssize_t adis16060_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + u16 val; + ssize_t ret; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16060_spi_read(dev, &val); + mutex_unlock(&indio_dev->mlock); + + if (ret == 0) + return sprintf(buf, "%d\n", val); + else + return ret; +} + +static ssize_t adis16060_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + int ret; + long val; + + ret = strict_strtol(buf, 16, &val); + if (ret) + goto error_ret; + ret = adis16060_spi_write(dev, val); + +error_ret: + return ret ? ret : len; +} + +#define IIO_DEV_ATTR_IN(_show) \ + IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0) + +#define IIO_DEV_ATTR_OUT(_store) \ + IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0) + +static IIO_DEV_ATTR_IN(adis16060_read); +static IIO_DEV_ATTR_OUT(adis16060_write); + +static IIO_CONST_ATTR(name, "adis16060"); + +static struct attribute *adis16060_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16060_event_attribute_group = { + .attrs = adis16060_event_attributes, +}; + +static struct attribute *adis16060_attributes[] = { + &iio_dev_attr_in.dev_attr.attr, + &iio_dev_attr_out.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16060_attribute_group = { + .attrs = adis16060_attributes, +}; + +static int __devinit adis16060_r_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16060_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16060_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16060_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us_r = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16060_event_attribute_group; + st->indio_dev->attrs = &adis16060_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis16060_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16060_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16060"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16060_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + adis16060_st = st; + return 0; + +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16060_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16060_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int adis16060_r_remove(struct spi_device *spi) +{ + struct adis16060_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + adis16060_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16060_uninitialize_ring(indio_dev->ring); + adis16060_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} + +static int __devinit adis16060_w_probe(struct spi_device *spi) +{ + int ret; + struct adis16060_state *st = adis16060_st; + if (!st) { + ret = -ENODEV; + goto error_ret; + } + spi_set_drvdata(spi, st); + st->us_w = spi; + return 0; + +error_ret: + return ret; +} + +static int adis16060_w_remove(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver adis16060_r_driver = { + .driver = { + .name = "adis16060_r", + .owner = THIS_MODULE, + }, + .probe = adis16060_r_probe, + .remove = __devexit_p(adis16060_r_remove), +}; + +static struct spi_driver adis16060_w_driver = { + .driver = { + .name = "adis16060_w", + .owner = THIS_MODULE, + }, + .probe = adis16060_w_probe, + .remove = __devexit_p(adis16060_w_remove), +}; + +static __init int adis16060_init(void) +{ + int ret; + + ret = spi_register_driver(&adis16060_r_driver); + if (ret < 0) + return ret; + + ret = spi_register_driver(&adis16060_w_driver); + if (ret < 0) { + spi_unregister_driver(&adis16060_r_driver); + return ret; + } + + return 0; +} +module_init(adis16060_init); + +static __exit void adis16060_exit(void) +{ + spi_unregister_driver(&adis16060_w_driver); + spi_unregister_driver(&adis16060_r_driver); +} +module_exit(adis16060_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 1b2f99e1ae79b6039340571312ebbe0551d39c16 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:05 -0400 Subject: staging: iio: gyro: new driver for ADIS16080 digital output gyros Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/Kconfig | 7 + drivers/staging/iio/gyro/Makefile | 3 + drivers/staging/iio/gyro/adis16080.h | 102 +++++++++++ drivers/staging/iio/gyro/adis16080_core.c | 271 ++++++++++++++++++++++++++++++ 4 files changed, 383 insertions(+) create mode 100644 drivers/staging/iio/gyro/adis16080.h create mode 100644 drivers/staging/iio/gyro/adis16080_core.c (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index 77c0fe84380b..f219c948c85a 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -10,6 +10,13 @@ config ADIS16060 Say yes here to build support for Analog Devices adis16060 wide bandwidth yaw rate gyroscope with SPI. +config ADIS16080 + tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver" + depends on SPI + help + Say yes here to build support for Analog Devices adis16080/100 Yaw Rate + Gyroscope with SPI. + config ADIS16260 tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver" depends on SPI diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index e2c4acb608b4..747823f016df 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -5,6 +5,9 @@ adis16060-y := adis16060_core.o obj-$(CONFIG_ADIS16060) += adis16060.o +adis16080-y := adis16080_core.o +obj-$(CONFIG_ADIS16080) += adis16080.o + adis16260-y := adis16260_core.o adis16260-$(CONFIG_IIO_RING_BUFFER) += adis16260_ring.o adis16260_trigger.o obj-$(CONFIG_ADIS16260) += adis16260.o diff --git a/drivers/staging/iio/gyro/adis16080.h b/drivers/staging/iio/gyro/adis16080.h new file mode 100644 index 000000000000..3fcbe67f7c31 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16080.h @@ -0,0 +1,102 @@ +#ifndef SPI_ADIS16080_H_ +#define SPI_ADIS16080_H_ + +#define ADIS16080_DIN_CODE 4 /* Output data format setting. 0: Twos complement. 1: Offset binary. */ +#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */ +#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */ +#define ADIS16080_DIN_AIN1 (2 << 10) +#define ADIS16080_DIN_AIN2 (3 << 10) +#define ADIS16080_DIN_WRITE (1 << 15) /* 1: Write contents on DIN to control register. + * 0: No changes to control register. + */ + +#define ADIS16080_MAX_TX 2 +#define ADIS16080_MAX_RX 2 + +/** + * struct adis16080_state - device instance specific data + * @us: actual spi_device to write data + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16080_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; + +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum adis16080_scan { + ADIS16080_SCAN_GYRO, + ADIS16080_SCAN_TEMP, + ADIS16080_SCAN_ADC_1, + ADIS16080_SCAN_ADC_2, +}; + +void adis16080_remove_trigger(struct iio_dev *indio_dev); +int adis16080_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16080_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int adis16080_configure_ring(struct iio_dev *indio_dev); +void adis16080_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16080_initialize_ring(struct iio_ring_buffer *ring); +void adis16080_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16080_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16080_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16080_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16080_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16080_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16080_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16080_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16080_H_ */ diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c new file mode 100644 index 000000000000..0efb768db7d3 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -0,0 +1,271 @@ +/* + * ADIS16080/100 Yaw Rate Gyroscope with SPI driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "gyro.h" +#include "../adc/adc.h" + +#include "adis16080.h" + +#define DRIVER_NAME "adis16080" + +struct adis16080_state *adis16080_st; + +int adis16080_spi_write(struct device *dev, + u16 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16080_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = val >> 8; + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +int adis16080_spi_read(struct device *dev, + u16 *val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16080_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + + ret = spi_read(st->us, st->rx, 2); + + if (ret == 0) + *val = ((st->rx[0] & 0xF) << 8) | st->rx[1]; + mutex_unlock(&st->buf_lock); + + return ret; +} + +static ssize_t adis16080_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + u16 val; + ssize_t ret; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16080_spi_read(dev, &val); + mutex_unlock(&indio_dev->mlock); + + if (ret == 0) + return sprintf(buf, "%d\n", val); + else + return ret; +} + +static ssize_t adis16080_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + int ret; + long val; + + ret = strict_strtol(buf, 16, &val); + if (ret) + goto error_ret; + ret = adis16080_spi_write(dev, val); + +error_ret: + return ret ? ret : len; +} + +#define IIO_DEV_ATTR_IN(_show) \ + IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0) + +#define IIO_DEV_ATTR_OUT(_store) \ + IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0) + +static IIO_DEV_ATTR_IN(adis16080_read); +static IIO_DEV_ATTR_OUT(adis16080_write); + +static IIO_CONST_ATTR(name, "adis16080"); + +static struct attribute *adis16080_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16080_event_attribute_group = { + .attrs = adis16080_event_attributes, +}; + +static struct attribute *adis16080_attributes[] = { + &iio_dev_attr_in.dev_attr.attr, + &iio_dev_attr_out.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16080_attribute_group = { + .attrs = adis16080_attributes, +}; + +static int __devinit adis16080_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16080_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16080_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16080_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16080_event_attribute_group; + st->indio_dev->attrs = &adis16080_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis16080_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16080_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16080"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16080_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + adis16080_st = st; + return 0; + +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16080_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16080_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int adis16080_remove(struct spi_device *spi) +{ + struct adis16080_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + adis16080_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16080_uninitialize_ring(indio_dev->ring); + adis16080_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} + +static struct spi_driver adis16080_driver = { + .driver = { + .name = "adis16080", + .owner = THIS_MODULE, + }, + .probe = adis16080_probe, + .remove = __devexit_p(adis16080_remove), +}; + +static __init int adis16080_init(void) +{ + return spi_register_driver(&adis16080_driver); +} +module_init(adis16080_init); + +static __exit void adis16080_exit(void) +{ + spi_unregister_driver(&adis16080_driver); +} +module_exit(adis16080_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 7a83f60d7bdf619cb7a37b5e0f6c128a91c6ecd0 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:06 -0400 Subject: staging: iio: gyro: new driver for ADIS16130 digital output gyros Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/Kconfig | 7 + drivers/staging/iio/gyro/Makefile | 3 + drivers/staging/iio/gyro/adis16130.h | 108 +++++++++++ drivers/staging/iio/gyro/adis16130_core.c | 313 ++++++++++++++++++++++++++++++ 4 files changed, 431 insertions(+) create mode 100644 drivers/staging/iio/gyro/adis16130.h create mode 100644 drivers/staging/iio/gyro/adis16130_core.c (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index f219c948c85a..236f15fdbfc9 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig @@ -17,6 +17,13 @@ config ADIS16080 Say yes here to build support for Analog Devices adis16080/100 Yaw Rate Gyroscope with SPI. +config ADIS16130 + tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver" + depends on SPI + help + Say yes here to build support for Analog Devices ADIS16130 High Precision + Angular Rate Sensor driver. + config ADIS16260 tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver" depends on SPI diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile index 747823f016df..2764c15025a5 100644 --- a/drivers/staging/iio/gyro/Makefile +++ b/drivers/staging/iio/gyro/Makefile @@ -8,6 +8,9 @@ obj-$(CONFIG_ADIS16060) += adis16060.o adis16080-y := adis16080_core.o obj-$(CONFIG_ADIS16080) += adis16080.o +adis16130-y := adis16130_core.o +obj-$(CONFIG_ADIS16130) += adis16130.o + adis16260-y := adis16260_core.o adis16260-$(CONFIG_IIO_RING_BUFFER) += adis16260_ring.o adis16260_trigger.o obj-$(CONFIG_ADIS16260) += adis16260.o diff --git a/drivers/staging/iio/gyro/adis16130.h b/drivers/staging/iio/gyro/adis16130.h new file mode 100644 index 000000000000..ab80ef6a8961 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16130.h @@ -0,0 +1,108 @@ +#ifndef SPI_ADIS16130_H_ +#define SPI_ADIS16130_H_ + +#define ADIS16130_CON 0x0 +#define ADIS16130_CON_RD (1 << 6) +#define ADIS16130_IOP 0x1 +#define ADIS16130_IOP_ALL_RDY (1 << 3) /* 1 = data-ready signal low when unread data on all channels; */ +#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */ +#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */ +#define ADIS16130_TEMPDATA 0xA /* Temperature output */ +#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */ +#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */ +#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */ +#define ADIS16130_TEMPCS_EN (1 << 3) +#define ADIS16130_RATECONV 0x30 +#define ADIS16130_TEMPCONV 0x32 +#define ADIS16130_MODE 0x38 +#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */ + +#define ADIS16130_MAX_TX 4 +#define ADIS16130_MAX_RX 4 + +/** + * struct adis16130_state - device instance specific data + * @us: actual spi_device to write data + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct adis16130_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + u32 mode; /* 1: 24bits mode 0:16bits mode */ + struct mutex buf_lock; +}; + +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum adis16130_scan { + ADIS16130_SCAN_GYRO, + ADIS16130_SCAN_TEMP, +}; + +void adis16130_remove_trigger(struct iio_dev *indio_dev); +int adis16130_probe_trigger(struct iio_dev *indio_dev); + +ssize_t adis16130_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int adis16130_configure_ring(struct iio_dev *indio_dev); +void adis16130_unconfigure_ring(struct iio_dev *indio_dev); + +int adis16130_initialize_ring(struct iio_ring_buffer *ring); +void adis16130_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void adis16130_remove_trigger(struct iio_dev *indio_dev) +{ +} + +static inline int adis16130_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +adis16130_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int adis16130_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void adis16130_unconfigure_ring(struct iio_dev *indio_dev) +{ +} + +static inline int adis16130_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} + +static inline void adis16130_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} + +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* SPI_ADIS16130_H_ */ diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c new file mode 100644 index 000000000000..49ffc7b26e8a --- /dev/null +++ b/drivers/staging/iio/gyro/adis16130_core.c @@ -0,0 +1,313 @@ +/* + * ADIS16130 Digital Output, High Precision Angular Rate Sensor driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "gyro.h" +#include "../adc/adc.h" + +#include "adis16130.h" + +#define DRIVER_NAME "adis16130" + +struct adis16130_state *adis16130_st; + +int adis16130_spi_write(struct device *dev, u8 reg_addr, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16130_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = reg_addr; + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +int adis16130_spi_read(struct device *dev, u8 reg_addr, + u32 *val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16130_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + + st->tx[0] = ADIS16130_CON_RD | reg_addr; + if (st->mode) + ret = spi_read(st->us, st->rx, 4); + else + ret = spi_read(st->us, st->rx, 3); + + if (ret == 0) { + if (st->mode) + *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3]; + else + *val = (st->rx[1] << 8) | st->rx[2]; + } + + mutex_unlock(&st->buf_lock); + + return ret; +} + +static ssize_t adis16130_gyro_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + u32 val; + ssize_t ret; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16130_spi_read(dev, ADIS16130_RATEDATA, &val); + mutex_unlock(&indio_dev->mlock); + + if (ret == 0) + return sprintf(buf, "%d\n", val); + else + return ret; +} + +static ssize_t adis16130_temp_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + u32 val; + ssize_t ret; + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16130_spi_read(dev, ADIS16130_TEMPDATA, &val); + mutex_unlock(&indio_dev->mlock); + + if (ret == 0) + return sprintf(buf, "%d\n", val); + else + return ret; +} + +static ssize_t adis16130_bitsmode_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16130_state *st = iio_dev_get_devdata(indio_dev); + + return sprintf(buf, "%d\n", st->mode); +} + +static ssize_t adis16130_bitsmode_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + int ret; + long val; + + ret = strict_strtol(buf, 16, &val); + if (ret) + goto error_ret; + ret = adis16130_spi_write(dev, ADIS16130_MODE, !!val); + +error_ret: + return ret ? ret : len; +} + +static IIO_DEV_ATTR_TEMP_RAW(adis16130_temp_read); + +static IIO_CONST_ATTR(name, "adis16130"); + +static IIO_DEV_ATTR_GYRO(adis16130_gyro_read, + ADIS16130_RATEDATA); + +#define IIO_DEV_ATTR_BITS_MODE(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bits_mode, _mode, _show, _store, _addr) + +static IIO_DEV_ATTR_BITS_MODE(S_IWUSR | S_IRUGO, adis16130_bitsmode_read, adis16130_bitsmode_write, + ADIS16130_MODE); + +static struct attribute *adis16130_event_attributes[] = { + NULL +}; + +static struct attribute_group adis16130_event_attribute_group = { + .attrs = adis16130_event_attributes, +}; + +static struct attribute *adis16130_attributes[] = { + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_gyro_raw.dev_attr.attr, + &iio_dev_attr_bits_mode.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16130_attribute_group = { + .attrs = adis16130_attributes, +}; + +static int __devinit adis16130_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct adis16130_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADIS16130_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADIS16130_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &adis16130_event_attribute_group; + st->indio_dev->attrs = &adis16130_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + st->mode = 1; + + ret = adis16130_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = adis16130_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_RISING, + "adis16130"); + if (ret) + goto error_uninitialize_ring; + + ret = adis16130_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + adis16130_st = st; + return 0; + +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + adis16130_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + adis16130_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int adis16130_remove(struct spi_device *spi) +{ + struct adis16130_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + adis16130_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + adis16130_uninitialize_ring(indio_dev->ring); + adis16130_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} + +static struct spi_driver adis16130_driver = { + .driver = { + .name = "adis16130", + .owner = THIS_MODULE, + }, + .probe = adis16130_probe, + .remove = __devexit_p(adis16130_remove), +}; + +static __init int adis16130_init(void) +{ + return spi_register_driver(&adis16130_driver); +} +module_init(adis16130_init); + +static __exit void adis16130_exit(void) +{ + spi_unregister_driver(&adis16130_driver); +} +module_exit(adis16130_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate Sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6790e29fef61b20b213bd1cf5a025dc3412a4765 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:07 -0400 Subject: staging: iio: dac: new driver for AD5624R devices This is used to convert digital streams into voltages. Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/Kconfig | 1 + drivers/staging/iio/Makefile | 1 + drivers/staging/iio/dac/Kconfig | 11 ++ drivers/staging/iio/dac/Makefile | 5 + drivers/staging/iio/dac/ad5624r.h | 21 +++ drivers/staging/iio/dac/ad5624r_spi.c | 313 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/dac/dac.h | 6 + 7 files changed, 358 insertions(+) create mode 100644 drivers/staging/iio/dac/Kconfig create mode 100644 drivers/staging/iio/dac/Makefile create mode 100644 drivers/staging/iio/dac/ad5624r.h create mode 100644 drivers/staging/iio/dac/ad5624r_spi.c create mode 100644 drivers/staging/iio/dac/dac.h (limited to 'drivers') diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index b8bb5f162540..773c30128ee7 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -43,6 +43,7 @@ config IIO_TRIGGER source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" +source "drivers/staging/iio/dac/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 0111647b9b9a..15eba01805bf 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_IIO_SW_RING) += ring_sw.o obj-y += accel/ obj-y += adc/ obj-y += addac/ +obj-y += dac/ obj-y += gyro/ obj-y += imu/ obj-y += light/ diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig new file mode 100644 index 000000000000..583df785fd25 --- /dev/null +++ b/drivers/staging/iio/dac/Kconfig @@ -0,0 +1,11 @@ +# +# DAC drivers +# +comment "Digital to analog convertors" + +config AD5624R_SPI + tristate "Analog Devices AD5624/44/64R DAC spi driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD5624R, AD5644R and + AD5664R convertors (DAC). This driver uses the common SPI interface. diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile new file mode 100644 index 000000000000..7ddf05d5f1b4 --- /dev/null +++ b/drivers/staging/iio/dac/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for industrial I/O DAC drivers +# + +obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h new file mode 100644 index 000000000000..ce518be652b7 --- /dev/null +++ b/drivers/staging/iio/dac/ad5624r.h @@ -0,0 +1,21 @@ +#ifndef SPI_AD5624R_H_ +#define SPI_AD5624R_H_ + +#define AD5624R_DAC_CHANNELS 4 + +#define AD5624R_ADDR_DAC0 0x0 +#define AD5624R_ADDR_DAC1 0x1 +#define AD5624R_ADDR_DAC2 0x2 +#define AD5624R_ADDR_DAC3 0x3 +#define AD5624R_ADDR_ALL_DAC 0x7 + +#define AD5624R_CMD_WRITE_INPUT_N 0x0 +#define AD5624R_CMD_UPDATE_DAC_N 0x1 +#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 +#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3 +#define AD5624R_CMD_POWERDOWN_DAC 0x4 +#define AD5624R_CMD_RESET 0x5 +#define AD5624R_CMD_LDAC_SETUP 0x6 +#define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7 + +#endif diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c new file mode 100644 index 000000000000..705ff505bf25 --- /dev/null +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -0,0 +1,313 @@ +/* + * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "dac.h" +#include "ad5624r.h" + +/** + * struct ad5624r_state - device related storage + * @indio_dev: associated industrial IO device + * @us: spi device + **/ +struct ad5624r_state { + struct iio_dev *indio_dev; + struct spi_device *us; + int data_len; + int ldac_mode; + int dac_power_mode[AD5624R_DAC_CHANNELS]; + int internal_ref; +}; + +static int ad5624r_spi_write(struct spi_device *spi, u8 cmd, u8 addr, u16 val, u8 len) +{ + struct spi_transfer t; + struct spi_message m; + u32 data; + u8 msg[3]; + + /* + * The input shift register is 24 bits wide. The first two bits are don't care bits. + * The next three are the command bits, C2 to C0, followed by the 3-bit DAC address, + * A2 to A0, and then the 16-, 14-, 12-bit data-word. The data-word comprises the 16-, + * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, for the AD5664R, + * AD5644R, and AD5624R, respectively. + */ + data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len)); + msg[0] = data >> 16; + msg[1] = data >> 8; + msg[2] = data; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + t.tx_buf = &msg[0]; + t.len = 3; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} + +static ssize_t ad5624r_write_dac(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + long readin; + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = strict_strtol(buf, 10, &readin); + if (ret) + return ret; + + ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, + this_attr->address, readin, st->data_len); + return ret ? ret : len; +} + +static ssize_t ad5624r_read_ldac_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + + return sprintf(buf, "%x\n", st->ldac_mode); +} + +static ssize_t ad5624r_write_ldac_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + long readin; + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + + ret = strict_strtol(buf, 16, &readin); + if (ret) + return ret; + + ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0, readin & 0xF, 16); + st->ldac_mode = readin & 0xF; + + return ret ? ret : len; +} + +static ssize_t ad5624r_read_dac_power_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + return sprintf(buf, "%d\n", st->dac_power_mode[this_attr->address]); +} + +static ssize_t ad5624r_write_dac_power_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + long readin; + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = strict_strtol(buf, 10, &readin); + if (ret) + return ret; + + ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0, + ((readin & 0x3) << 4) | (1 << this_attr->address), 16); + + st->dac_power_mode[this_attr->address] = readin & 0x3; + + return ret ? ret : len; +} + +static ssize_t ad5624r_read_internal_ref_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + + return sprintf(buf, "%d\n", st->internal_ref); +} + +static ssize_t ad5624r_write_internal_ref_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + long readin; + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5624r_state *st = indio_dev->dev_data; + + ret = strict_strtol(buf, 10, &readin); + if (ret) + return ret; + + ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!readin, 16); + + st->internal_ref = !!readin; + + return ret ? ret : len; +} + +static IIO_DEV_ATTR_DAC(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); +static IIO_DEV_ATTR_DAC(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); +static IIO_DEV_ATTR_DAC(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); +static IIO_DEV_ATTR_DAC(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); + +static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode, + ad5624r_write_ldac_mode, 0); +static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR, ad5624r_read_internal_ref_mode, + ad5624r_write_internal_ref_mode, 0); + +#define IIO_DEV_ATTR_DAC_POWER_MODE(_num, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dac_power_mode_##_num, S_IRUGO | S_IWUSR, _show, _store, _addr) + +static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 0); +static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 1); +static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 2); +static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 3); + +static struct attribute *ad5624r_attributes[] = { + &iio_dev_attr_dac_0.dev_attr.attr, + &iio_dev_attr_dac_1.dev_attr.attr, + &iio_dev_attr_dac_2.dev_attr.attr, + &iio_dev_attr_dac_3.dev_attr.attr, + &iio_dev_attr_dac_power_mode_0.dev_attr.attr, + &iio_dev_attr_dac_power_mode_1.dev_attr.attr, + &iio_dev_attr_dac_power_mode_2.dev_attr.attr, + &iio_dev_attr_dac_power_mode_3.dev_attr.attr, + &iio_dev_attr_ldac_mode.dev_attr.attr, + &iio_dev_attr_internal_ref.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad5624r_attribute_group = { + .attrs = ad5624r_attributes, +}; + +static int __devinit ad5624r_probe(struct spi_device *spi) +{ + + struct ad5624r_state *st; + int ret = 0; + char *chip_name = spi->dev.platform_data; + + if (!chip_name) + return -ENODEV; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + if (strcmp(chip_name, "ad5624r") == 0) + st->data_len = 12; + else if (strcmp(chip_name, "ad5644r") == 0) + st->data_len = 14; + else if (strcmp(chip_name, "ad5664r") == 0) + st->data_len = 16; + else { + dev_err(&spi->dev, "not supported chip type\n"); + ret = -EINVAL; + goto error_ret; + } + + st->us = spi; + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 0; + st->indio_dev->event_attrs = NULL; + + st->indio_dev->attrs = &ad5624r_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_free_dev; + + spi->mode = SPI_MODE_0; + spi_setup(spi); + + return 0; + +error_free_dev: + iio_free_device(st->indio_dev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad5624r_remove(struct spi_device *spi) +{ + struct ad5624r_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->indio_dev); + kfree(st); + + return 0; +} + +static struct spi_driver ad5624r_driver = { + .driver = { + .name = "ad5624r", + .owner = THIS_MODULE, + }, + .probe = ad5624r_probe, + .remove = __devexit_p(ad5624r_remove), +}; + +static __init int ad5624r_spi_init(void) +{ + return spi_register_driver(&ad5624r_driver); +} +module_init(ad5624r_spi_init); + +static __exit void ad5624r_spi_exit(void) +{ + spi_unregister_driver(&ad5624r_driver); +} +module_exit(ad5624r_spi_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h new file mode 100644 index 000000000000..55005eec1214 --- /dev/null +++ b/drivers/staging/iio/dac/dac.h @@ -0,0 +1,6 @@ +/* + * dac.h - sysfs attributes associated with DACs + */ + +#define IIO_DEV_ATTR_DAC(_num, _store, _addr) \ + IIO_DEVICE_ATTR(dac_##_num, S_IWUSR, NULL, _store, _addr) -- cgit v1.2.3 From da6fcbdf764cbc8f539333a725411183a4253cfa Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 Oct 2010 21:44:08 -0400 Subject: staging: iio: dds: new driver for AD5930/2 devices This is the initial driver in the new Direct Digital Synthesis section. Signed-off-by: Cliff Cai Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/Kconfig | 1 + drivers/staging/iio/Makefile | 1 + drivers/staging/iio/dds/Kconfig | 11 +++ drivers/staging/iio/dds/Makefile | 5 ++ drivers/staging/iio/dds/ad5930.c | 170 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+) create mode 100644 drivers/staging/iio/dds/Kconfig create mode 100644 drivers/staging/iio/dds/Makefile create mode 100644 drivers/staging/iio/dds/ad5930.c (limited to 'drivers') diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 773c30128ee7..5e5bc475f299 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -44,6 +44,7 @@ source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/dac/Kconfig" +source "drivers/staging/iio/dds/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 15eba01805bf..766a5d1a8373 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -13,6 +13,7 @@ obj-y += accel/ obj-y += adc/ obj-y += addac/ obj-y += dac/ +obj-y += dds/ obj-y += gyro/ obj-y += imu/ obj-y += light/ diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig new file mode 100644 index 000000000000..d32bebc63fb9 --- /dev/null +++ b/drivers/staging/iio/dds/Kconfig @@ -0,0 +1,11 @@ +# +# Direct Digital Synthesis drivers +# +comment "Direct Digital Synthesis" + +config AD5930 + tristate "Analog Devices ad5930/5932 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + ad5930/ad5932, provides direct access via sysfs. diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile new file mode 100644 index 000000000000..110f28916c73 --- /dev/null +++ b/drivers/staging/iio/dds/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Direct Digital Synthesis drivers +# + +obj-$(CONFIG_AD5930) += ad5930.o diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c new file mode 100644 index 000000000000..f80039c5d539 --- /dev/null +++ b/drivers/staging/iio/dds/ad5930.c @@ -0,0 +1,170 @@ +/* + * Driver for ADI Direct Digital Synthesis ad5930 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad5930" + +#define value_mask (u16)0xf000 +#define addr_shift 12 + +/* Register format: 4 bits addr + 12 bits value */ +struct ad5903_config { + u16 control; + u16 incnum; + u16 frqdelt[2]; + u16 incitvl; + u16 buritvl; + u16 strtfrq[2]; +}; + +struct ad5930_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; +}; + +static ssize_t ad5930_set_parameter(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + struct ad5903_config *config = (struct ad5903_config *)buf; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad5930_state *st = idev->dev_data; + + config->control = (config->control & ~value_mask); + config->incnum = (config->control & ~value_mask) | (1 << addr_shift); + config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift); + config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift; + config->incitvl = (config->control & ~value_mask) | 4 << addr_shift; + config->buritvl = (config->control & ~value_mask) | 8 << addr_shift; + config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift; + config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift; + + xfer.len = len; + xfer.tx_buf = config; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0); + +static struct attribute *ad5930_attributes[] = { + &iio_dev_attr_dds.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad5930_attribute_group = { + .name = DRV_NAME, + .attrs = ad5930_attributes, +}; + +static int __devinit ad5930_probe(struct spi_device *spi) +{ + struct ad5930_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad5930_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + spi->max_speed_hz = 2000000; + spi->mode = SPI_MODE_3; + spi->bits_per_word = 16; + spi_setup(spi); + + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad5930_remove(struct spi_device *spi) +{ + struct ad5930_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad5930_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad5930_probe, + .remove = __devexit_p(ad5930_remove), +}; + +static __init int ad5930_spi_init(void) +{ + return spi_register_driver(&ad5930_driver); +} +module_init(ad5930_spi_init); + +static __exit void ad5930_spi_exit(void) +{ + spi_unregister_driver(&ad5930_driver); +} +module_exit(ad5930_spi_exit); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad5930 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 4a8e6c33e88b09a3fdef022d1711dc13ce8cb7db Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 Oct 2010 21:44:09 -0400 Subject: staging: iio: dds: new driver for AD9832/3/4/5 devices Signed-off-by: Cliff Cai Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 7 ++ drivers/staging/iio/dds/Makefile | 1 + drivers/staging/iio/dds/ad9832.c | 266 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 drivers/staging/iio/dds/ad9832.c (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index d32bebc63fb9..c9fae1d0a81a 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -9,3 +9,10 @@ config AD5930 help Say yes here to build support for Analog Devices DDS chip ad5930/ad5932, provides direct access via sysfs. + +config AD9832 + tristate "Analog Devices ad9832/3/4/5 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + ad9832/3/4/5, provides direct access via sysfs. diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile index 110f28916c73..d0f17f064dc5 100644 --- a/drivers/staging/iio/dds/Makefile +++ b/drivers/staging/iio/dds/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_AD5930) += ad5930.o +obj-$(CONFIG_AD9832) += ad9832.o diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c new file mode 100644 index 000000000000..a4bb0482ed5b --- /dev/null +++ b/drivers/staging/iio/dds/ad9832.c @@ -0,0 +1,266 @@ +/* + * Driver for ADI Direct Digital Synthesis ad9832 + * + * Copyright (c) 2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad9832" + +#define value_mask (u16)0xf000 +#define cmd_shift 12 +#define add_shift 8 +#define AD9832_SYNC (1 << 13) +#define AD9832_SELSRC (1 << 12) +#define AD9832_SLEEP (1 << 13) +#define AD9832_RESET (1 << 12) +#define AD9832_CLR (1 << 11) + +#define ADD_FREQ0LL 0x0 +#define ADD_FREQ0HL 0x1 +#define ADD_FREQ0LM 0x2 +#define ADD_FREQ0HM 0x3 +#define ADD_FREQ1LL 0x4 +#define ADD_FREQ1HL 0x5 +#define ADD_FREQ1LM 0x6 +#define ADD_FREQ1HM 0x7 +#define ADD_PHASE0L 0x8 +#define ADD_PHASE0H 0x9 +#define ADD_PHASE1L 0xa +#define ADD_PHASE1H 0xb +#define ADD_PHASE2L 0xc +#define ADD_PHASE2H 0xd +#define ADD_PHASE3L 0xe +#define ADD_PHASE3H 0xf + +#define CMD_PHA8BITSW 0x1 +#define CMD_PHA16BITSW 0x0 +#define CMD_FRE8BITSW 0x3 +#define CMD_FRE16BITSW 0x2 +#define CMD_SELBITSCTL 0x6 + +struct ad9832_setting { + u16 freq0[4]; + u16 freq1[4]; + u16 phase0[2]; + u16 phase1[2]; + u16 phase2[2]; + u16 phase3[2]; +}; + +struct ad9832_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; +}; + +static ssize_t ad9832_set_parameter(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + struct ad9832_setting config; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad9832_state *st = idev->dev_data; + + config.freq0[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LL << add_shift | buf[0]); + config.freq0[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HL << add_shift | buf[1]); + config.freq0[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LM << add_shift | buf[2]); + config.freq0[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HM << add_shift | buf[3]); + config.freq1[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LL << add_shift | buf[4]); + config.freq1[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HL << add_shift | buf[5]); + config.freq1[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LM << add_shift | buf[6]); + config.freq1[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HM << add_shift | buf[7]); + + config.phase0[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE0L << add_shift | buf[9]); + config.phase0[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE0H << add_shift | buf[10]); + config.phase1[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE1L << add_shift | buf[11]); + config.phase1[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE1H << add_shift | buf[12]); + config.phase2[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE2L << add_shift | buf[13]); + config.phase2[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE2H << add_shift | buf[14]); + config.phase3[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE3L << add_shift | buf[15]); + config.phase3[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE3H << add_shift | buf[16]); + + xfer.len = 2 * len; + xfer.tx_buf = &config; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9832_set_parameter, 0); + +static struct attribute *ad9832_attributes[] = { + &iio_dev_attr_dds.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad9832_attribute_group = { + .name = DRV_NAME, + .attrs = ad9832_attributes, +}; + +static void ad9832_init(struct ad9832_state *st) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + u16 config = 0; + + config = 0x3 << 14 | AD9832_SLEEP | AD9832_RESET | AD9832_CLR; + + mutex_lock(&st->lock); + + xfer.len = 2; + xfer.tx_buf = &config; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + config = 0x2 << 14 | AD9832_SYNC | AD9832_SELSRC; + xfer.len = 2; + xfer.tx_buf = &config; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + config = CMD_SELBITSCTL << cmd_shift; + xfer.len = 2; + xfer.tx_buf = &config; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + config = 0x3 << 14; + + mutex_lock(&st->lock); + + xfer.len = 2; + xfer.tx_buf = &config; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + + +} + +static int __devinit ad9832_probe(struct spi_device *spi) +{ + struct ad9832_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad9832_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + spi->max_speed_hz = 2000000; + spi->mode = SPI_MODE_3; + spi->bits_per_word = 16; + spi_setup(spi); + ad9832_init(st); + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad9832_remove(struct spi_device *spi) +{ + struct ad9832_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad9832_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9832_probe, + .remove = __devexit_p(ad9832_remove), +}; + +static __init int ad9832_spi_init(void) +{ + return spi_register_driver(&ad9832_driver); +} +module_init(ad9832_spi_init); + +static __exit void ad9832_spi_exit(void) +{ + spi_unregister_driver(&ad9832_driver); +} +module_exit(ad9832_spi_exit); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9832 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a82ab27aa758e4b02f130d86be5c2fedf29c0c0a Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 Oct 2010 21:44:10 -0400 Subject: staging: iio: dds: new driver for AD9850/1 devices Signed-off-by: Cliff Cai Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 7 ++ drivers/staging/iio/dds/Makefile | 1 + drivers/staging/iio/dds/ad9850.c | 156 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 drivers/staging/iio/dds/ad9850.c (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index c9fae1d0a81a..d42bc4cb228d 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -16,3 +16,10 @@ config AD9832 help Say yes here to build support for Analog Devices DDS chip ad9832/3/4/5, provides direct access via sysfs. + +config AD9850 + tristate "Analog Devices ad9850/1 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + ad9850/1, provides direct access via sysfs. diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile index d0f17f064dc5..791db7411cb0 100644 --- a/drivers/staging/iio/dds/Makefile +++ b/drivers/staging/iio/dds/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_AD5930) += ad5930.o obj-$(CONFIG_AD9832) += ad9832.o +obj-$(CONFIG_AD9850) += ad9850.o diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c new file mode 100644 index 000000000000..b259bfeaf5aa --- /dev/null +++ b/drivers/staging/iio/dds/ad9850.c @@ -0,0 +1,156 @@ +/* + * Driver for ADI Direct Digital Synthesis ad9850 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad9850" + +#define value_mask (u16)0xf000 +#define addr_shift 12 + +/* Register format: 4 bits addr + 12 bits value */ +struct ad9850_config { + u8 control[5]; +}; + +struct ad9850_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; +}; + +static ssize_t ad9850_set_parameter(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + struct ad9850_config *config = (struct ad9850_config *)buf; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad9850_state *st = idev->dev_data; + + xfer.len = len; + xfer.tx_buf = config; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0); + +static struct attribute *ad9850_attributes[] = { + &iio_dev_attr_dds.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad9850_attribute_group = { + .name = DRV_NAME, + .attrs = ad9850_attributes, +}; + +static int __devinit ad9850_probe(struct spi_device *spi) +{ + struct ad9850_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad9850_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + spi->max_speed_hz = 2000000; + spi->mode = SPI_MODE_3; + spi->bits_per_word = 16; + spi_setup(spi); + + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad9850_remove(struct spi_device *spi) +{ + struct ad9850_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad9850_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9850_probe, + .remove = __devexit_p(ad9850_remove), +}; + +static __init int ad9850_spi_init(void) +{ + return spi_register_driver(&ad9850_driver); +} +module_init(ad9850_spi_init); + +static __exit void ad9850_spi_exit(void) +{ + spi_unregister_driver(&ad9850_driver); +} +module_exit(ad9850_spi_exit); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9850 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a886689f6c36ccad01d9600a92029f80a2a6279f Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 Oct 2010 21:44:11 -0400 Subject: staging: iio: dds: new driver for AD9852/4 devices Signed-off-by: Cliff Cai Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 7 + drivers/staging/iio/dds/Makefile | 1 + drivers/staging/iio/dds/ad9852.c | 314 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 322 insertions(+) create mode 100644 drivers/staging/iio/dds/ad9852.c (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index d42bc4cb228d..dee31eb3d73c 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -23,3 +23,10 @@ config AD9850 help Say yes here to build support for Analog Devices DDS chip ad9850/1, provides direct access via sysfs. + +config AD9852 + tristate "Analog Devices ad9852/4 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + ad9852/4, provides direct access via sysfs. diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile index 791db7411cb0..e344e8dced95 100644 --- a/drivers/staging/iio/dds/Makefile +++ b/drivers/staging/iio/dds/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_AD5930) += ad5930.o obj-$(CONFIG_AD9832) += ad9832.o obj-$(CONFIG_AD9850) += ad9850.o +obj-$(CONFIG_AD9852) += ad9852.o diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c new file mode 100644 index 000000000000..0a41d25583af --- /dev/null +++ b/drivers/staging/iio/dds/ad9852.c @@ -0,0 +1,314 @@ +/* + * Driver for ADI Direct Digital Synthesis ad9852 + * + * Copyright (c) 2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad9852" + +#define addr_phaad1 0x0 +#define addr_phaad2 0x1 +#define addr_fretu1 0x2 +#define addr_fretu2 0x3 +#define addr_delfre 0x4 +#define addr_updclk 0x5 +#define addr_ramclk 0x6 +#define addr_contrl 0x7 +#define addr_optskm 0x8 +#define addr_optskr 0xa +#define addr_dacctl 0xb + +#define COMPPD (1 << 4) +#define REFMULT2 (1 << 2) +#define BYPPLL (1 << 5) +#define PLLRANG (1 << 6) +#define IEUPCLK (1) +#define OSKEN (1 << 5) + +#define read_bit (1 << 7) + +/* Register format: 1 byte addr + value */ +struct ad9852_config { + u8 phajst0[3]; + u8 phajst1[3]; + u8 fretun1[6]; + u8 fretun2[6]; + u8 dltafre[6]; + u8 updtclk[5]; + u8 ramprat[4]; + u8 control[5]; + u8 outpskm[3]; + u8 outpskr[2]; + u8 daccntl[3]; +}; + +struct ad9852_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; +}; + +static ssize_t ad9852_set_parameter(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + struct ad9852_config *config = (struct ad9852_config *)buf; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad9852_state *st = idev->dev_data; + + xfer.len = 3; + xfer.tx_buf = &config->phajst0[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 3; + xfer.tx_buf = &config->phajst1[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 6; + xfer.tx_buf = &config->fretun1[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 6; + xfer.tx_buf = &config->fretun2[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 6; + xfer.tx_buf = &config->dltafre[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->updtclk[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 4; + xfer.tx_buf = &config->ramprat[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->control[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 3; + xfer.tx_buf = &config->outpskm[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 2; + xfer.tx_buf = &config->outpskr[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 3; + xfer.tx_buf = &config->daccntl[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0); + +static void ad9852_init(struct ad9852_state *st) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + u8 config[5]; + + config[0] = addr_contrl; + config[1] = COMPPD; + config[2] = REFMULT2 | BYPPLL | PLLRANG; + config[3] = IEUPCLK; + config[4] = OSKEN; + + mutex_lock(&st->lock); + + xfer.len = 5; + xfer.tx_buf = &config; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + +error_ret: + mutex_unlock(&st->lock); + + + +} + +static struct attribute *ad9852_attributes[] = { + &iio_dev_attr_dds.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad9852_attribute_group = { + .name = DRV_NAME, + .attrs = ad9852_attributes, +}; + +static int __devinit ad9852_probe(struct spi_device *spi) +{ + struct ad9852_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad9852_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + spi->max_speed_hz = 2000000; + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + ad9852_init(st); + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad9852_remove(struct spi_device *spi) +{ + struct ad9852_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad9852_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9852_probe, + .remove = __devexit_p(ad9852_remove), +}; + +static __init int ad9852_spi_init(void) +{ + return spi_register_driver(&ad9852_driver); +} +module_init(ad9852_spi_init); + +static __exit void ad9852_spi_exit(void) +{ + spi_unregister_driver(&ad9852_driver); +} +module_exit(ad9852_spi_exit); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9852 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2996a2dc38c58f96432a28fdd7f81ccfd692637d Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 Oct 2010 21:44:12 -0400 Subject: staging: iio: dds: new driver for AD9910 devices Signed-off-by: Cliff Cai Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 7 + drivers/staging/iio/dds/Makefile | 1 + drivers/staging/iio/dds/ad9910.c | 454 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 462 insertions(+) create mode 100644 drivers/staging/iio/dds/ad9910.c (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index dee31eb3d73c..518d0c118083 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -30,3 +30,10 @@ config AD9852 help Say yes here to build support for Analog Devices DDS chip ad9852/4, provides direct access via sysfs. + +config AD9910 + tristate "Analog Devices ad9910 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + ad9910, provides direct access via sysfs. diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile index e344e8dced95..d249b8125be3 100644 --- a/drivers/staging/iio/dds/Makefile +++ b/drivers/staging/iio/dds/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_AD5930) += ad5930.o obj-$(CONFIG_AD9832) += ad9832.o obj-$(CONFIG_AD9850) += ad9850.o obj-$(CONFIG_AD9852) += ad9852.o +obj-$(CONFIG_AD9910) += ad9910.o diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c new file mode 100644 index 000000000000..c59b40794768 --- /dev/null +++ b/drivers/staging/iio/dds/ad9910.c @@ -0,0 +1,454 @@ +/* + * Driver for ADI Direct Digital Synthesis ad9910 + * + * Copyright (c) 2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad9910" + +#define CFR1 0x0 +#define CFR2 0x1 +#define CFR3 0x2 + +#define AUXDAC 0x3 +#define IOUPD 0x4 +#define FTW 0x7 +#define POW 0x8 +#define ASF 0x9 +#define MULTC 0x0A +#define DIG_RAMPL 0x0B +#define DIG_RAMPS 0x0C +#define DIG_RAMPR 0x0D +#define SIN_TONEP0 0x0E +#define SIN_TONEP1 0x0F +#define SIN_TONEP2 0x10 +#define SIN_TONEP3 0x11 +#define SIN_TONEP4 0x12 +#define SIN_TONEP5 0x13 +#define SIN_TONEP6 0x14 +#define SIN_TONEP7 0x15 + +#define RAM_ENABLE (1 << 7) + +#define MANUAL_OSK (1 << 7) +#define INVSIC (1 << 6) +#define DDS_SINEOP (1) + +#define AUTO_OSK (1) +#define OSKEN (1 << 1) +#define LOAD_ARR (1 << 2) +#define CLR_PHA (1 << 3) +#define CLR_DIG (1 << 4) +#define ACLR_PHA (1 << 5) +#define ACLR_DIG (1 << 6) +#define LOAD_LRR (1 << 7) + +#define LSB_FST (1) +#define SDIO_IPT (1 << 1) +#define EXT_PWD (1 << 3) +#define ADAC_PWD (1 << 4) +#define REFCLK_PWD (1 << 5) +#define DAC_PWD (1 << 6) +#define DIG_PWD (1 << 7) + +#define ENA_AMP (1) +#define READ_FTW (1) +#define DIGR_LOW (1 << 1) +#define DIGR_HIGH (1 << 2) +#define DIGR_ENA (1 << 3) +#define SYNCCLK_ENA (1 << 6) +#define ITER_IOUPD (1 << 7) + +#define TX_ENA (1 << 1) +#define PDCLK_INV (1 << 2) +#define PDCLK_ENB (1 << 3) + +#define PARA_ENA (1 << 4) +#define SYNC_DIS (1 << 5) +#define DATA_ASS (1 << 6) +#define MATCH_ENA (1 << 7) + +#define PLL_ENA (1) +#define PFD_RST (1 << 2) +#define REFCLK_RST (1 << 6) +#define REFCLK_BYP (1 << 7) + +/* Register format: 1 byte addr + value */ +struct ad9910_config { + u8 auxdac[5]; + u8 ioupd[5]; + u8 ftw[5]; + u8 pow[3]; + u8 asf[5]; + u8 multc[5]; + u8 dig_rampl[9]; + u8 dig_ramps[9]; + u8 dig_rampr[5]; + u8 sin_tonep0[9]; + u8 sin_tonep1[9]; + u8 sin_tonep2[9]; + u8 sin_tonep3[9]; + u8 sin_tonep4[9]; + u8 sin_tonep5[9]; + u8 sin_tonep6[9]; + u8 sin_tonep7[9]; +}; + +struct ad9910_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; +}; + +static ssize_t ad9910_set_parameter(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + struct ad9910_config *config = (struct ad9910_config *)buf; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad9910_state *st = idev->dev_data; + + xfer.len = 5; + xfer.tx_buf = &config->auxdac[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->ioupd[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->ftw[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 3; + xfer.tx_buf = &config->pow[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->asf[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->multc[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 9; + xfer.tx_buf = &config->dig_rampl[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 9; + xfer.tx_buf = &config->dig_ramps[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->dig_rampr[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep0[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep1[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep2[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep3[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep4[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep5[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep6[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + xfer.len = 9; + xfer.tx_buf = &config->sin_tonep7[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0); + +static void ad9910_init(struct ad9910_state *st) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + u8 cfr[5]; + + cfr[0] = CFR1; + cfr[1] = 0; + cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP; + cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR; + cfr[4] = 0; + + mutex_lock(&st->lock); + + xfer.len = 5; + xfer.tx_buf = 𝔠 + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + cfr[0] = CFR2; + cfr[1] = ENA_AMP; + cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD; + cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB; + cfr[4] = PARA_ENA; + + mutex_lock(&st->lock); + + xfer.len = 5; + xfer.tx_buf = 𝔠 + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + cfr[0] = CFR3; + cfr[1] = PLL_ENA; + cfr[2] = 0; + cfr[3] = REFCLK_RST | REFCLK_BYP; + cfr[4] = 0; + + mutex_lock(&st->lock); + + xfer.len = 5; + xfer.tx_buf = 𝔠 + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + +error_ret: + mutex_unlock(&st->lock); + + + +} + +static struct attribute *ad9910_attributes[] = { + &iio_dev_attr_dds.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad9910_attribute_group = { + .name = DRV_NAME, + .attrs = ad9910_attributes, +}; + +static int __devinit ad9910_probe(struct spi_device *spi) +{ + struct ad9910_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad9910_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + spi->max_speed_hz = 2000000; + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + ad9910_init(st); + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad9910_remove(struct spi_device *spi) +{ + struct ad9910_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad9910_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9910_probe, + .remove = __devexit_p(ad9910_remove), +}; + +static __init int ad9910_spi_init(void) +{ + return spi_register_driver(&ad9910_driver); +} +module_init(ad9910_spi_init); + +static __exit void ad9910_spi_exit(void) +{ + spi_unregister_driver(&ad9910_driver); +} +module_exit(ad9910_spi_exit); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9910 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 0152a0585281a03d734f38effcfe9515874b7d48 Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Wed, 27 Oct 2010 21:44:13 -0400 Subject: staging: iio: dds: new driver for AD9951 devices Signed-off-by: Cliff Cai Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 7 ++ drivers/staging/iio/dds/Makefile | 1 + drivers/staging/iio/dds/ad9951.c | 254 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 drivers/staging/iio/dds/ad9951.c (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index 518d0c118083..d045ed69ad38 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -37,3 +37,10 @@ config AD9910 help Say yes here to build support for Analog Devices DDS chip ad9910, provides direct access via sysfs. + +config AD9951 + tristate "Analog Devices ad9951 driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + ad9951, provides direct access via sysfs. diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile index d249b8125be3..6f274acb0fcf 100644 --- a/drivers/staging/iio/dds/Makefile +++ b/drivers/staging/iio/dds/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_AD9832) += ad9832.o obj-$(CONFIG_AD9850) += ad9850.o obj-$(CONFIG_AD9852) += ad9852.o obj-$(CONFIG_AD9910) += ad9910.o +obj-$(CONFIG_AD9951) += ad9951.o diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c new file mode 100644 index 000000000000..bc3befff167a --- /dev/null +++ b/drivers/staging/iio/dds/ad9951.c @@ -0,0 +1,254 @@ +/* + * Driver for ADI Direct Digital Synthesis ad9951 + * + * Copyright (c) 2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad9951" + +#define CFR1 0x0 +#define CFR2 0x1 + +#define AUTO_OSK (1) +#define OSKEN (1 << 1) +#define LOAD_ARR (1 << 2) + +#define AUTO_SYNC (1 << 7) + +#define LSB_FST (1) +#define SDIO_IPT (1 << 1) +#define CLR_PHA (1 << 2) +#define SINE_OPT (1 << 4) +#define ACLR_PHA (1 << 5) + +#define VCO_RANGE (1 << 2) + +#define CRS_OPT (1 << 1) +#define HMANU_SYNC (1 << 2) +#define HSPD_SYNC (1 << 3) + +/* Register format: 1 byte addr + value */ +struct ad9951_config { + u8 asf[3]; + u8 arr[2]; + u8 ftw0[5]; + u8 ftw1[3]; +}; + +struct ad9951_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; +}; + +static ssize_t ad9951_set_parameter(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + struct ad9951_config *config = (struct ad9951_config *)buf; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad9951_state *st = idev->dev_data; + + xfer.len = 3; + xfer.tx_buf = &config->asf[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 2; + xfer.tx_buf = &config->arr[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 5; + xfer.tx_buf = &config->ftw0[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + xfer.len = 3; + xfer.tx_buf = &config->ftw1[0]; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0); + +static void ad9951_init(struct ad9951_state *st) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + u8 cfr[5]; + + cfr[0] = CFR1; + cfr[1] = 0; + cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA; + cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR; + cfr[4] = 0; + + mutex_lock(&st->lock); + + xfer.len = 5; + xfer.tx_buf = 𝔠 + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + + cfr[0] = CFR2; + cfr[1] = VCO_RANGE; + cfr[2] = HSPD_SYNC; + cfr[3] = 0; + + mutex_lock(&st->lock); + + xfer.len = 4; + xfer.tx_buf = 𝔠 + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + +error_ret: + mutex_unlock(&st->lock); + + + +} + +static struct attribute *ad9951_attributes[] = { + &iio_dev_attr_dds.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad9951_attribute_group = { + .name = DRV_NAME, + .attrs = ad9951_attributes, +}; + +static int __devinit ad9951_probe(struct spi_device *spi) +{ + struct ad9951_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad9951_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + spi->max_speed_hz = 2000000; + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + ad9951_init(st); + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad9951_remove(struct spi_device *spi) +{ + struct ad9951_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad9951_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad9951_probe, + .remove = __devexit_p(ad9951_remove), +}; + +static __init int ad9951_spi_init(void) +{ + return spi_register_driver(&ad9951_driver); +} +module_init(ad9951_spi_init); + +static __exit void ad9951_spi_exit(void) +{ + spi_unregister_driver(&ad9951_driver); +} +module_exit(ad9951_spi_exit); + +MODULE_AUTHOR("Cliff Cai"); +MODULE_DESCRIPTION("Analog Devices ad9951 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 09434ef7c2eedca448d2701ffce229b5ccade64f Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:14 -0400 Subject: staging: iio: meter: new driver for ADE7753/6 devices This also kicks off the new meter subsection. Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/Kconfig | 2 +- drivers/staging/iio/Makefile | 3 +- drivers/staging/iio/meter/Kconfig | 11 + drivers/staging/iio/meter/Makefile | 5 + drivers/staging/iio/meter/ade7753.c | 730 ++++++++++++++++++++++++++++++++++++ drivers/staging/iio/meter/ade7753.h | 140 +++++++ drivers/staging/iio/meter/meter.h | 396 +++++++++++++++++++ 7 files changed, 1285 insertions(+), 2 deletions(-) create mode 100644 drivers/staging/iio/meter/Kconfig create mode 100644 drivers/staging/iio/meter/Makefile create mode 100644 drivers/staging/iio/meter/ade7753.c create mode 100644 drivers/staging/iio/meter/ade7753.h create mode 100644 drivers/staging/iio/meter/meter.h (limited to 'drivers') diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 5e5bc475f299..ffe8912bd7ab 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -49,7 +49,7 @@ source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" source "drivers/staging/iio/magnetometer/Kconfig" - +source "drivers/staging/iio/meter/Kconfig" source "drivers/staging/iio/trigger/Kconfig" endif # IIO diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 766a5d1a8373..5b449a15e5aa 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -17,5 +17,6 @@ obj-y += dds/ obj-y += gyro/ obj-y += imu/ obj-y += light/ -obj-y += trigger/ obj-y += magnetometer/ +obj-y += meter/ +obj-y += trigger/ diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig new file mode 100644 index 000000000000..0c09c39b63ec --- /dev/null +++ b/drivers/staging/iio/meter/Kconfig @@ -0,0 +1,11 @@ +# +# IIO meter drivers configuration +# +comment "Active energy metering IC" + +config ADE7753 + tristate "Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver" + depends on SPI + help + Say yes here to build support for Analog Devices ADE7753 Single-Phase Multifunction + Metering IC with di/dt Sensor Interface. diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile new file mode 100644 index 000000000000..b4eac385848d --- /dev/null +++ b/drivers/staging/iio/meter/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for metering ic drivers +# + +obj-$(CONFIG_ADE7753) += ade7753.o diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c new file mode 100644 index 000000000000..e72afbd2b841 --- /dev/null +++ b/drivers/staging/iio/meter/ade7753.c @@ -0,0 +1,730 @@ +/* + * ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface Driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "meter.h" +#include "ade7753.h" + +int ade7753_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7753_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7753_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7753_spi_write_reg_16(struct device *dev, + u8 reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7753_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 3, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7753_WRITE_REG(reg_address); + st->tx[1] = (value >> 8) & 0xFF; + st->tx[2] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7753_spi_read_reg_8(struct device *dev, + u8 reg_address, + u8 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7753_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7753_READ_REG(reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7753_spi_read_reg_16(struct device *dev, + u8 reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7753_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 3, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7753_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 8) | st->rx[2]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7753_spi_read_reg_24(struct device *dev, + u8 reg_address, + u32 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7753_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 4, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7753_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + st->tx[3] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t ade7753_read_8bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u8 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7753_spi_read_reg_8(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7753_read_16bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7753_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7753_read_24bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u32 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7753_spi_read_reg_24(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val & 0xFFFFFF); +} + +static ssize_t ade7753_write_8bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7753_spi_write_reg_8(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7753_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7753_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int ade7753_reset(struct device *dev) +{ + int ret; + u16 val; + ade7753_spi_read_reg_16(dev, + ADE7753_MODE, + &val); + val |= 1 << 6; /* Software Chip Reset */ + ret = ade7753_spi_write_reg_16(dev, + ADE7753_MODE, + val); + + return ret; +} + +static ssize_t ade7753_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -1; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return ade7753_reset(dev); + } + return -1; +} + +static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY); +static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY); +static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY); +static IIO_DEV_ATTR_LVAENERGY(ade7753_read_24bit, ADE7753_LVAENERGY); +static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_CFDEN); +static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_CFNUM); +static IIO_DEV_ATTR_CHKSUM(ade7753_read_8bit, ADE7753_CHKSUM); +static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_PHCAL); +static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_APOS); +static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_SAGCYC); +static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_SAGLVL); +static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_LINECYC); +static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_WDIV); +static IIO_DEV_ATTR_IRMS(S_IWUSR | S_IRUGO, + ade7753_read_24bit, + NULL, + ADE7753_IRMS); +static IIO_DEV_ATTR_VRMS(S_IRUGO, + ade7753_read_24bit, + NULL, + ADE7753_VRMS); +static IIO_DEV_ATTR_IRMSOS(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_IRMSOS); +static IIO_DEV_ATTR_VRMSOS(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_VRMSOS); +static IIO_DEV_ATTR_WGAIN(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_WGAIN); +static IIO_DEV_ATTR_VAGAIN(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_VAGAIN); +static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO, + ade7753_read_16bit, + ade7753_write_16bit, + ADE7753_GAIN); +static IIO_DEV_ATTR_IPKLVL(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_IPKLVL); +static IIO_DEV_ATTR_VPKLVL(S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_VPKLVL); +static IIO_DEV_ATTR_IPEAK(S_IRUGO, + ade7753_read_24bit, + NULL, + ADE7753_IPEAK); +static IIO_DEV_ATTR_VPEAK(S_IRUGO, + ade7753_read_24bit, + NULL, + ADE7753_VPEAK); +static IIO_DEV_ATTR_VPERIOD(S_IRUGO, + ade7753_read_16bit, + NULL, + ADE7753_PERIOD); +static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_CH1OS); +static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_CH2OS); + +static int ade7753_set_irq(struct device *dev, bool enable) +{ + int ret; + u8 irqen; + ret = ade7753_spi_read_reg_8(dev, ADE7753_IRQEN, &irqen); + if (ret) + goto error_ret; + + if (enable) + irqen |= 1 << 3; /* Enables an interrupt when a data is + present in the waveform register */ + else + irqen &= ~(1 << 3); + + ret = ade7753_spi_write_reg_8(dev, ADE7753_IRQEN, irqen); + if (ret) + goto error_ret; + +error_ret: + return ret; +} + +/* Power down the device */ +int ade7753_stop_device(struct device *dev) +{ + int ret; + u16 val; + ade7753_spi_read_reg_16(dev, + ADE7753_MODE, + &val); + val |= 1 << 4; /* AD converters can be turned off */ + ret = ade7753_spi_write_reg_16(dev, + ADE7753_MODE, + val); + + return ret; +} + +static int ade7753_initial_setup(struct ade7753_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* use low spi speed for init */ + st->us->mode = SPI_MODE_3; + spi_setup(st->us); + + /* Disable IRQ */ + ret = ade7753_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + ade7753_reset(dev); + msleep(ADE7753_STARTUP_DELAY); + +err_ret: + return ret; +} + +static ssize_t ade7753_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret, len = 0; + u8 t; + int sps; + ret = ade7753_spi_read_reg_8(dev, + ADE7753_MODE, + &t); + if (ret) + return ret; + + t = (t >> 11) & 0x3; + sps = 27900 / (1 + t); + + len = sprintf(buf, "%d SPS\n", sps); + return len; +} + +static ssize_t ade7753_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7753_state *st = iio_dev_get_devdata(indio_dev); + unsigned long val; + int ret; + u16 reg, t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + + t = (27900 / val); + if (t > 0) + t--; + + if (t > 1) + st->us->max_speed_hz = ADE7753_SPI_SLOW; + else + st->us->max_speed_hz = ADE7753_SPI_FAST; + + ret = ade7753_spi_read_reg_16(dev, + ADE7753_MODE, + ®); + if (ret) + goto out; + + reg &= ~(3 << 11); + reg |= t << 11; + + ret = ade7753_spi_write_reg_16(dev, + ADE7753_MODE, + reg); + +out: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} +static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit); +static IIO_CONST_ATTR(temp_offset, "-25 C"); +static IIO_CONST_ATTR(temp_scale, "0.67 C"); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ade7753_read_frequency, + ade7753_write_frequency); + +static IIO_DEV_ATTR_RESET(ade7753_write_reset); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500"); + +static IIO_CONST_ATTR(name, "ade7753"); + +static struct attribute *ade7753_event_attributes[] = { + NULL +}; + +static struct attribute_group ade7753_event_attribute_group = { + .attrs = ade7753_event_attributes, +}; + +static struct attribute *ade7753_attributes[] = { + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_phcal.dev_attr.attr, + &iio_dev_attr_cfden.dev_attr.attr, + &iio_dev_attr_aenergy.dev_attr.attr, + &iio_dev_attr_laenergy.dev_attr.attr, + &iio_dev_attr_vaenergy.dev_attr.attr, + &iio_dev_attr_lvaenergy.dev_attr.attr, + &iio_dev_attr_cfnum.dev_attr.attr, + &iio_dev_attr_apos.dev_attr.attr, + &iio_dev_attr_sagcyc.dev_attr.attr, + &iio_dev_attr_saglvl.dev_attr.attr, + &iio_dev_attr_linecyc.dev_attr.attr, + &iio_dev_attr_chksum.dev_attr.attr, + &iio_dev_attr_pga_gain.dev_attr.attr, + &iio_dev_attr_wgain.dev_attr.attr, + &iio_dev_attr_choff_1.dev_attr.attr, + &iio_dev_attr_choff_2.dev_attr.attr, + &iio_dev_attr_wdiv.dev_attr.attr, + &iio_dev_attr_irms.dev_attr.attr, + &iio_dev_attr_vrms.dev_attr.attr, + &iio_dev_attr_irmsos.dev_attr.attr, + &iio_dev_attr_vrmsos.dev_attr.attr, + &iio_dev_attr_vagain.dev_attr.attr, + &iio_dev_attr_ipklvl.dev_attr.attr, + &iio_dev_attr_vpklvl.dev_attr.attr, + &iio_dev_attr_ipeak.dev_attr.attr, + &iio_dev_attr_vpeak.dev_attr.attr, + &iio_dev_attr_vperiod.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ade7753_attribute_group = { + .attrs = ade7753_attributes, +}; + +static int __devinit ade7753_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct ade7753_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADE7753_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADE7753_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &ade7753_event_attribute_group; + st->indio_dev->attrs = &ade7753_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ade7753_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = ade7753_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + "ade7753"); + if (ret) + goto error_uninitialize_ring; + + ret = ade7753_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = ade7753_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + ade7753_remove_trigger(st->indio_dev); +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + ade7753_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + ade7753_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int ade7753_remove(struct spi_device *spi) +{ + int ret; + struct ade7753_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + ret = ade7753_stop_device(&(indio_dev->dev)); + if (ret) + goto err_ret; + + flush_scheduled_work(); + + ade7753_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + ade7753_uninitialize_ring(indio_dev->ring); + ade7753_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; + +err_ret: + return ret; +} + +static struct spi_driver ade7753_driver = { + .driver = { + .name = "ade7753", + .owner = THIS_MODULE, + }, + .probe = ade7753_probe, + .remove = __devexit_p(ade7753_remove), +}; + +static __init int ade7753_init(void) +{ + return spi_register_driver(&ade7753_driver); +} +module_init(ade7753_init); + +static __exit void ade7753_exit(void) +{ + spi_unregister_driver(&ade7753_driver); +} +module_exit(ade7753_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7753.h b/drivers/staging/iio/meter/ade7753.h new file mode 100644 index 000000000000..a3722b8c90fa --- /dev/null +++ b/drivers/staging/iio/meter/ade7753.h @@ -0,0 +1,140 @@ +#ifndef _ADE7753_H +#define _ADE7753_H + +#define ADE7753_WAVEFORM 0x01 +#define ADE7753_AENERGY 0x02 +#define ADE7753_RAENERGY 0x03 +#define ADE7753_LAENERGY 0x04 +#define ADE7753_VAENERGY 0x05 +#define ADE7753_RVAENERGY 0x06 +#define ADE7753_LVAENERGY 0x07 +#define ADE7753_LVARENERGY 0x08 +#define ADE7753_MODE 0x09 +#define ADE7753_IRQEN 0x0A +#define ADE7753_STATUS 0x0B +#define ADE7753_RSTSTATUS 0x0C +#define ADE7753_CH1OS 0x0D +#define ADE7753_CH2OS 0x0E +#define ADE7753_GAIN 0x0F +#define ADE7753_PHCAL 0x10 +#define ADE7753_APOS 0x11 +#define ADE7753_WGAIN 0x12 +#define ADE7753_WDIV 0x13 +#define ADE7753_CFNUM 0x14 +#define ADE7753_CFDEN 0x15 +#define ADE7753_IRMS 0x16 +#define ADE7753_VRMS 0x17 +#define ADE7753_IRMSOS 0x18 +#define ADE7753_VRMSOS 0x19 +#define ADE7753_VAGAIN 0x1A +#define ADE7753_VADIV 0x1B +#define ADE7753_LINECYC 0x1C +#define ADE7753_ZXTOUT 0x1D +#define ADE7753_SAGCYC 0x1E +#define ADE7753_SAGLVL 0x1F +#define ADE7753_IPKLVL 0x20 +#define ADE7753_VPKLVL 0x21 +#define ADE7753_IPEAK 0x22 +#define ADE7753_RSTIPEAK 0x23 +#define ADE7753_VPEAK 0x24 +#define ADE7753_RSTVPEAK 0x25 +#define ADE7753_TEMP 0x26 +#define ADE7753_PERIOD 0x27 +#define ADE7753_TMODE 0x3D +#define ADE7753_CHKSUM 0x3E +#define ADE7753_DIEREV 0x3F + +#define ADE7753_READ_REG(a) a +#define ADE7753_WRITE_REG(a) ((a) | 0x80) + +#define ADE7753_MAX_TX 4 +#define ADE7753_MAX_RX 4 +#define ADE7753_STARTUP_DELAY 1 + +#define ADE7753_SPI_SLOW (u32)(300 * 1000) +#define ADE7753_SPI_BURST (u32)(1000 * 1000) +#define ADE7753_SPI_FAST (u32)(2000 * 1000) + +#define DRIVER_NAME "ade7753" + +/** + * struct ade7753_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct ade7753_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum ade7753_scan { + ADE7753_SCAN_ACTIVE_POWER, + ADE7753_SCAN_CH1, + ADE7753_SCAN_CH2, +}; + +void ade7753_remove_trigger(struct iio_dev *indio_dev); +int ade7753_probe_trigger(struct iio_dev *indio_dev); + +ssize_t ade7753_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int ade7753_configure_ring(struct iio_dev *indio_dev); +void ade7753_unconfigure_ring(struct iio_dev *indio_dev); + +int ade7753_initialize_ring(struct iio_ring_buffer *ring); +void ade7753_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void ade7753_remove_trigger(struct iio_dev *indio_dev) +{ +} +static inline int ade7753_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +ade7753_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int ade7753_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} +static inline void ade7753_unconfigure_ring(struct iio_dev *indio_dev) +{ +} +static inline int ade7753_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} +static inline void ade7753_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ + +#endif diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h new file mode 100644 index 000000000000..142c50d71fda --- /dev/null +++ b/drivers/staging/iio/meter/meter.h @@ -0,0 +1,396 @@ +#include "../sysfs.h" + +/* metering ic types of attribute */ + +#define IIO_DEV_ATTR_CURRENT_A_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(current_a_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CURRENT_B_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(current_b_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CURRENT_C_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(current_c_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VOLT_A_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(volt_a_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VOLT_B_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(volt_b_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VOLT_C_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(volt_c_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(reactive_power_a_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(reactive_power_b_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(reactive_power_c_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_a_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_b_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_c_offset, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CURRENT_A_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(current_a_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CURRENT_B_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(current_b_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CURRENT_C_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(current_c_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(apparent_power_a_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(apparent_power_b_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(apparent_power_c_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_a_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_b_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(active_power_c_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(reactive_power_a_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(reactive_power_b_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(reactive_power_c_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CURRENT_A(_show, _addr) \ + IIO_DEVICE_ATTR(current_a, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CURRENT_B(_show, _addr) \ + IIO_DEVICE_ATTR(current_b, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CURRENT_C(_show, _addr) \ + IIO_DEVICE_ATTR(current_c, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_VOLT_A(_show, _addr) \ + IIO_DEVICE_ATTR(volt_a, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_VOLT_B(_show, _addr) \ + IIO_DEVICE_ATTR(volt_b, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_VOLT_C(_show, _addr) \ + IIO_DEVICE_ATTR(volt_c, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_AENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(aenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_LENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(lenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_RAENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(raenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_LAENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(laenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_VAENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(vaenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_LVAENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(lvaenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_RVAENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(rvaenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_LVARENERGY(_show, _addr) \ + IIO_DEVICE_ATTR(lvarenergy, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CHKSUM(_show, _addr) \ + IIO_DEVICE_ATTR(chksum, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ANGLE0(_show, _addr) \ + IIO_DEVICE_ATTR(angle0, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ANGLE1(_show, _addr) \ + IIO_DEVICE_ATTR(angle1, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ANGLE2(_show, _addr) \ + IIO_DEVICE_ATTR(angle2, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_AWATTHR(_show, _addr) \ + IIO_DEVICE_ATTR(awatthr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_BWATTHR(_show, _addr) \ + IIO_DEVICE_ATTR(bwatthr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CWATTHR(_show, _addr) \ + IIO_DEVICE_ATTR(cwatthr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_AFWATTHR(_show, _addr) \ + IIO_DEVICE_ATTR(afwatthr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_BFWATTHR(_show, _addr) \ + IIO_DEVICE_ATTR(bfwatthr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CFWATTHR(_show, _addr) \ + IIO_DEVICE_ATTR(cfwatthr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_AVARHR(_show, _addr) \ + IIO_DEVICE_ATTR(avarhr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_BVARHR(_show, _addr) \ + IIO_DEVICE_ATTR(bvarhr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CVARHR(_show, _addr) \ + IIO_DEVICE_ATTR(cvarhr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_AVAHR(_show, _addr) \ + IIO_DEVICE_ATTR(avahr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_BVAHR(_show, _addr) \ + IIO_DEVICE_ATTR(bvahr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_CVAHR(_show, _addr) \ + IIO_DEVICE_ATTR(cvahr, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_IOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(ios, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_PHCAL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(phcal, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_APHCAL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(aphcal, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BPHCAL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bphcal, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CPHCAL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cphcal, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_APOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(apos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AAPOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(aapos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BAPOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bapos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CAPOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(capos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AVRMSGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(avrmsgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BVRMSGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bvrmsgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CVRMSGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cvrmsgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AIGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(aigain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BIGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bigain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CIGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cigain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_NIGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(nigain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AVGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(avgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BVGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bvgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CVGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cvgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_WGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(wgain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_WDIV(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(wdiv, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CFNUM(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cfnum, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CFDEN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cfden, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CF1DEN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cf1den, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CF2DEN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cf2den, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CF3DEN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cf3den, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_IRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(irms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vrms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AIRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(airms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BIRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(birms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CIRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cirms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_NIRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(nirms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AVRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(avrms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BVRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bvrms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CVRMS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cvrms, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_IRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(irmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vrmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AIRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(airmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BIRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(birmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CIRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cirmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_AVRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(avrmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_BVRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(bvrmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CVRMSOS(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cvrmsos, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VAGAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vagain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_PGA_GAIN(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(pga_gain, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VADIV(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vadiv, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_LINECYC(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(linecyc, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_SAGCYC(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(sagcyc, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CFCYC(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(cfcyc, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_PEAKCYC(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(peakcyc, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_SAGLVL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(saglvl, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_IPKLVL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(ipklvl, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VPKLVL(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vpklvl, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_IPEAK(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(ipeak, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_RIPEAK(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(ripeak, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VPEAK(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vpeak, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_RVPEAK(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(rvpeak, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr) + +#define IIO_DEV_ATTR_CH_OFF(_num, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(choff_##_num, _mode, _show, _store, _addr) + +/* active energy register, AENERGY, is more than half full */ +#define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask) + +/* a SAG on the line voltage */ +#define IIO_EVENT_ATTR_LINE_VOLT_SAG(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(line_volt_sag, _evlist, _show, _store, _mask) + +/* + * Indicates the end of energy accumulation over an integer number + * of half line cycles + */ +#define IIO_EVENT_ATTR_CYCEND(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(cycend, _evlist, _show, _store, _mask) + +/* on the rising and falling edge of the the voltage waveform */ +#define IIO_EVENT_ATTR_ZERO_CROSS(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(zero_cross, _evlist, _show, _store, _mask) + +/* the active energy register has overflowed */ +#define IIO_EVENT_ATTR_AENERGY_OVERFLOW(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(aenergy_overflow, _evlist, _show, _store, _mask) + +/* the apparent energy register has overflowed */ +#define IIO_EVENT_ATTR_VAENERGY_OVERFLOW(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(vaenergy_overflow, _evlist, _show, _store, _mask) + +/* the active energy register, VAENERGY, is more than half full */ +#define IIO_EVENT_ATTR_VAENERGY_HALF_FULL(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(vaenergy_half_full, _evlist, _show, _store, _mask) + +/* the power has gone from negative to positive */ +#define IIO_EVENT_ATTR_PPOS(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(ppos, _evlist, _show, _store, _mask) + +/* the power has gone from positive to negative */ +#define IIO_EVENT_ATTR_PNEG(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(pneg, _evlist, _show, _store, _mask) + +/* waveform sample from Channel 1 has exceeded the IPKLVL value */ +#define IIO_EVENT_ATTR_IPKLVL_EXC(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(ipklvl_exc, _evlist, _show, _store, _mask) + +/* waveform sample from Channel 2 has exceeded the VPKLVL value */ +#define IIO_EVENT_ATTR_VPKLVL_EXC(_evlist, _show, _store, _mask) \ + IIO_EVENT_ATTR_SH(vpklvl_exc, _evlist, _show, _store, _mask) + -- cgit v1.2.3 From 8d97a5877b85ab0a2b346c2c111a8192d336495f Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:15 -0400 Subject: staging: iio: meter: new driver for ADE7754 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/meter/Kconfig | 7 + drivers/staging/iio/meter/Makefile | 1 + drivers/staging/iio/meter/ade7754.c | 756 ++++++++++++++++++++++++++++++++++++ drivers/staging/iio/meter/ade7754.h | 161 ++++++++ 4 files changed, 925 insertions(+) create mode 100644 drivers/staging/iio/meter/ade7754.c create mode 100644 drivers/staging/iio/meter/ade7754.h (limited to 'drivers') diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig index 0c09c39b63ec..19f20f4ad52c 100644 --- a/drivers/staging/iio/meter/Kconfig +++ b/drivers/staging/iio/meter/Kconfig @@ -9,3 +9,10 @@ config ADE7753 help Say yes here to build support for Analog Devices ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface. + +config ADE7754 + tristate "Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver" + depends on SPI + help + Say yes here to build support for Analog Devices ADE7754 Polyphase + Multifunction Energy Metering IC Driver. diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile index b4eac385848d..7f65b991eb15 100644 --- a/drivers/staging/iio/meter/Makefile +++ b/drivers/staging/iio/meter/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_ADE7753) += ade7753.o +obj-$(CONFIG_ADE7754) += ade7754.o diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c new file mode 100644 index 000000000000..23dedfa7a270 --- /dev/null +++ b/drivers/staging/iio/meter/ade7754.c @@ -0,0 +1,756 @@ +/* + * ADE7754 Polyphase Multifunction Energy Metering IC Driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "meter.h" +#include "ade7754.h" + +static int ade7754_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7754_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7754_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7754_spi_write_reg_16(struct device *dev, + u8 reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7754_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 3, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7754_WRITE_REG(reg_address); + st->tx[1] = (value >> 8) & 0xFF; + st->tx[2] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7754_spi_read_reg_8(struct device *dev, + u8 reg_address, + u8 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7754_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7754_READ_REG(reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7754_spi_read_reg_16(struct device *dev, + u8 reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7754_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 3, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7754_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 8) | st->rx[2]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7754_spi_read_reg_24(struct device *dev, + u8 reg_address, + u32 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7754_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 4, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7754_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + st->tx[3] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t ade7754_read_8bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u8 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7754_spi_read_reg_8(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7754_read_16bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7754_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7754_read_24bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u32 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7754_spi_read_reg_24(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val & 0xFFFFFF); +} + +static ssize_t ade7754_write_8bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7754_spi_write_reg_8(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7754_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7754_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int ade7754_reset(struct device *dev) +{ + int ret; + u8 val; + ade7754_spi_read_reg_8(dev, + ADE7754_OPMODE, + &val); + val |= 1 << 6; /* Software Chip Reset */ + ret = ade7754_spi_write_reg_8(dev, + ADE7754_OPMODE, + val); + + return ret; +} + + +static ssize_t ade7754_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -1; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return ade7754_reset(dev); + } + return -1; +} + +static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY); +static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY); +static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY); +static IIO_DEV_ATTR_LVAENERGY(ade7754_read_24bit, ADE7754_LVAENERGY); +static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_VPEAK); +static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_VPEAK); +static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_APHCAL); +static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_BPHCAL); +static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_CPHCAL); +static IIO_DEV_ATTR_AAPOS(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_AAPOS); +static IIO_DEV_ATTR_BAPOS(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_BAPOS); +static IIO_DEV_ATTR_CAPOS(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_CAPOS); +static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_WDIV); +static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO, + ade7754_read_8bit, + ade7754_write_8bit, + ADE7754_VADIV); +static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_CFNUM); +static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_CFDEN); +static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_AAPGAIN); +static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_BAPGAIN); +static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_CAPGAIN); +static IIO_DEV_ATTR_AIRMS(S_IRUGO, + ade7754_read_24bit, + NULL, + ADE7754_AIRMS); +static IIO_DEV_ATTR_BIRMS(S_IRUGO, + ade7754_read_24bit, + NULL, + ADE7754_BIRMS); +static IIO_DEV_ATTR_CIRMS(S_IRUGO, + ade7754_read_24bit, + NULL, + ADE7754_CIRMS); +static IIO_DEV_ATTR_AVRMS(S_IRUGO, + ade7754_read_24bit, + NULL, + ADE7754_AVRMS); +static IIO_DEV_ATTR_BVRMS(S_IRUGO, + ade7754_read_24bit, + NULL, + ADE7754_BVRMS); +static IIO_DEV_ATTR_CVRMS(S_IRUGO, + ade7754_read_24bit, + NULL, + ADE7754_CVRMS); +static IIO_DEV_ATTR_AIRMSOS(S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_AIRMSOS); +static IIO_DEV_ATTR_BIRMSOS(S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_BIRMSOS); +static IIO_DEV_ATTR_CIRMSOS(S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_CIRMSOS); +static IIO_DEV_ATTR_AVRMSOS(S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_AVRMSOS); +static IIO_DEV_ATTR_BVRMSOS(S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_BVRMSOS); +static IIO_DEV_ATTR_CVRMSOS(S_IRUGO, + ade7754_read_16bit, + ade7754_write_16bit, + ADE7754_CVRMSOS); + +static int ade7754_set_irq(struct device *dev, bool enable) +{ + int ret; + u16 irqen; + ret = ade7754_spi_read_reg_16(dev, ADE7754_IRQEN, &irqen); + if (ret) + goto error_ret; + + if (enable) + irqen |= 1 << 14; /* Enables an interrupt when a data is + present in the waveform register */ + else + irqen &= ~(1 << 14); + + ret = ade7754_spi_write_reg_16(dev, ADE7754_IRQEN, irqen); + if (ret) + goto error_ret; + +error_ret: + return ret; +} + +/* Power down the device */ +static int ade7754_stop_device(struct device *dev) +{ + int ret; + u8 val; + ade7754_spi_read_reg_8(dev, + ADE7754_OPMODE, + &val); + val |= 7 << 3; /* ADE7754 powered down */ + ret = ade7754_spi_write_reg_8(dev, + ADE7754_OPMODE, + val); + + return ret; +} + +static int ade7754_initial_setup(struct ade7754_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* use low spi speed for init */ + st->us->mode = SPI_MODE_3; + spi_setup(st->us); + + /* Disable IRQ */ + ret = ade7754_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + ade7754_reset(dev); + msleep(ADE7754_STARTUP_DELAY); + +err_ret: + return ret; +} + +static ssize_t ade7754_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret, len = 0; + u8 t; + int sps; + ret = ade7754_spi_read_reg_8(dev, + ADE7754_WAVMODE, + &t); + if (ret) + return ret; + + t = (t >> 3) & 0x3; + sps = 26000 / (1 + t); + + len = sprintf(buf, "%d SPS\n", sps); + return len; +} + +static ssize_t ade7754_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7754_state *st = iio_dev_get_devdata(indio_dev); + unsigned long val; + int ret; + u8 reg, t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + + t = (26000 / val); + if (t > 0) + t--; + + if (t > 1) + st->us->max_speed_hz = ADE7754_SPI_SLOW; + else + st->us->max_speed_hz = ADE7754_SPI_FAST; + + ret = ade7754_spi_read_reg_8(dev, + ADE7754_WAVMODE, + ®); + if (ret) + goto out; + + reg &= ~(3 << 3); + reg |= t << 3; + + ret = ade7754_spi_write_reg_8(dev, + ADE7754_WAVMODE, + reg); + +out: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} +static IIO_DEV_ATTR_TEMP_RAW(ade7754_read_8bit); +static IIO_CONST_ATTR(temp_offset, "129 C"); +static IIO_CONST_ATTR(temp_scale, "4 C"); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ade7754_read_frequency, + ade7754_write_frequency); + +static IIO_DEV_ATTR_RESET(ade7754_write_reset); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000"); + +static IIO_CONST_ATTR(name, "ade7754"); + +static struct attribute *ade7754_event_attributes[] = { + NULL +}; + +static struct attribute_group ade7754_event_attribute_group = { + .attrs = ade7754_event_attributes, +}; + +static struct attribute *ade7754_attributes[] = { + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_aenergy.dev_attr.attr, + &iio_dev_attr_laenergy.dev_attr.attr, + &iio_dev_attr_vaenergy.dev_attr.attr, + &iio_dev_attr_lvaenergy.dev_attr.attr, + &iio_dev_attr_vpeak.dev_attr.attr, + &iio_dev_attr_ipeak.dev_attr.attr, + &iio_dev_attr_aphcal.dev_attr.attr, + &iio_dev_attr_bphcal.dev_attr.attr, + &iio_dev_attr_cphcal.dev_attr.attr, + &iio_dev_attr_aapos.dev_attr.attr, + &iio_dev_attr_bapos.dev_attr.attr, + &iio_dev_attr_capos.dev_attr.attr, + &iio_dev_attr_wdiv.dev_attr.attr, + &iio_dev_attr_vadiv.dev_attr.attr, + &iio_dev_attr_cfnum.dev_attr.attr, + &iio_dev_attr_cfden.dev_attr.attr, + &iio_dev_attr_active_power_a_gain.dev_attr.attr, + &iio_dev_attr_active_power_b_gain.dev_attr.attr, + &iio_dev_attr_active_power_c_gain.dev_attr.attr, + &iio_dev_attr_airms.dev_attr.attr, + &iio_dev_attr_birms.dev_attr.attr, + &iio_dev_attr_cirms.dev_attr.attr, + &iio_dev_attr_avrms.dev_attr.attr, + &iio_dev_attr_bvrms.dev_attr.attr, + &iio_dev_attr_cvrms.dev_attr.attr, + &iio_dev_attr_airmsos.dev_attr.attr, + &iio_dev_attr_birmsos.dev_attr.attr, + &iio_dev_attr_cirmsos.dev_attr.attr, + &iio_dev_attr_avrmsos.dev_attr.attr, + &iio_dev_attr_bvrmsos.dev_attr.attr, + &iio_dev_attr_cvrmsos.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ade7754_attribute_group = { + .attrs = ade7754_attributes, +}; + + + +static int __devinit ade7754_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct ade7754_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADE7754_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADE7754_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &ade7754_event_attribute_group; + st->indio_dev->attrs = &ade7754_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ade7754_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = ade7754_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + "ade7754"); + if (ret) + goto error_uninitialize_ring; + + ret = ade7754_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = ade7754_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + ade7754_remove_trigger(st->indio_dev); +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + ade7754_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + ade7754_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int ade7754_remove(struct spi_device *spi) +{ + int ret; + struct ade7754_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + ret = ade7754_stop_device(&(indio_dev->dev)); + if (ret) + goto err_ret; + + flush_scheduled_work(); + + ade7754_remove_trigger(indio_dev); + if (spi->irq) + iio_unregister_interrupt_line(indio_dev, 0); + + ade7754_uninitialize_ring(indio_dev->ring); + ade7754_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; + +err_ret: + return ret; +} + +static struct spi_driver ade7754_driver = { + .driver = { + .name = "ade7754", + .owner = THIS_MODULE, + }, + .probe = ade7754_probe, + .remove = __devexit_p(ade7754_remove), +}; + +static __init int ade7754_init(void) +{ + return spi_register_driver(&ade7754_driver); +} +module_init(ade7754_init); + +static __exit void ade7754_exit(void) +{ + spi_unregister_driver(&ade7754_driver); +} +module_exit(ade7754_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7754.h b/drivers/staging/iio/meter/ade7754.h new file mode 100644 index 000000000000..f6a3e4b926cf --- /dev/null +++ b/drivers/staging/iio/meter/ade7754.h @@ -0,0 +1,161 @@ +#ifndef _ADE7754_H +#define _ADE7754_H + +#define ADE7754_AENERGY 0x01 +#define ADE7754_RAENERGY 0x02 +#define ADE7754_LAENERGY 0x03 +#define ADE7754_VAENERGY 0x04 +#define ADE7754_RVAENERGY 0x05 +#define ADE7754_LVAENERGY 0x06 +#define ADE7754_PERIOD 0x07 +#define ADE7754_TEMP 0x08 +#define ADE7754_WFORM 0x09 +#define ADE7754_OPMODE 0x0A +#define ADE7754_MMODE 0x0B +#define ADE7754_WAVMODE 0x0C +#define ADE7754_WATMODE 0x0D +#define ADE7754_VAMODE 0x0E +#define ADE7754_IRQEN 0x0F +#define ADE7754_STATUS 0x10 +#define ADE7754_RSTATUS 0x11 +#define ADE7754_ZXTOUT 0x12 +#define ADE7754_LINCYC 0x13 +#define ADE7754_SAGCYC 0x14 +#define ADE7754_SAGLVL 0x15 +#define ADE7754_VPEAK 0x16 +#define ADE7754_IPEAK 0x17 +#define ADE7754_GAIN 0x18 +#define ADE7754_AWG 0x19 +#define ADE7754_BWG 0x1A +#define ADE7754_CWG 0x1B +#define ADE7754_AVAG 0x1C +#define ADE7754_BVAG 0x1D +#define ADE7754_CVAG 0x1E +#define ADE7754_APHCAL 0x1F +#define ADE7754_BPHCAL 0x20 +#define ADE7754_CPHCAL 0x21 +#define ADE7754_AAPOS 0x22 +#define ADE7754_BAPOS 0x23 +#define ADE7754_CAPOS 0x24 +#define ADE7754_CFNUM 0x25 +#define ADE7754_CFDEN 0x26 +#define ADE7754_WDIV 0x27 +#define ADE7754_VADIV 0x28 +#define ADE7754_AIRMS 0x29 +#define ADE7754_BIRMS 0x2A +#define ADE7754_CIRMS 0x2B +#define ADE7754_AVRMS 0x2C +#define ADE7754_BVRMS 0x2D +#define ADE7754_CVRMS 0x2E +#define ADE7754_AIRMSOS 0x2F +#define ADE7754_BIRMSOS 0x30 +#define ADE7754_CIRMSOS 0x31 +#define ADE7754_AVRMSOS 0x32 +#define ADE7754_BVRMSOS 0x33 +#define ADE7754_CVRMSOS 0x34 +#define ADE7754_AAPGAIN 0x35 +#define ADE7754_BAPGAIN 0x36 +#define ADE7754_CAPGAIN 0x37 +#define ADE7754_AVGAIN 0x38 +#define ADE7754_BVGAIN 0x39 +#define ADE7754_CVGAIN 0x3A +#define ADE7754_CHKSUM 0x3E +#define ADE7754_VERSION 0x3F + +#define ADE7754_READ_REG(a) a +#define ADE7754_WRITE_REG(a) ((a) | 0x80) + +#define ADE7754_MAX_TX 4 +#define ADE7754_MAX_RX 4 +#define ADE7754_STARTUP_DELAY 1 + +#define ADE7754_SPI_SLOW (u32)(300 * 1000) +#define ADE7754_SPI_BURST (u32)(1000 * 1000) +#define ADE7754_SPI_FAST (u32)(2000 * 1000) + +#define DRIVER_NAME "ade7754" + +/** + * struct ade7754_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct ade7754_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum ade7754_scan { + ADE7754_SCAN_PHA_V, + ADE7754_SCAN_PHB_V, + ADE7754_SCAN_PHC_V, + ADE7754_SCAN_PHA_I, + ADE7754_SCAN_PHB_I, + ADE7754_SCAN_PHC_I, +}; + +void ade7754_remove_trigger(struct iio_dev *indio_dev); +int ade7754_probe_trigger(struct iio_dev *indio_dev); + +ssize_t ade7754_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int ade7754_configure_ring(struct iio_dev *indio_dev); +void ade7754_unconfigure_ring(struct iio_dev *indio_dev); + +int ade7754_initialize_ring(struct iio_ring_buffer *ring); +void ade7754_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void ade7754_remove_trigger(struct iio_dev *indio_dev) +{ +} +static inline int ade7754_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +ade7754_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int ade7754_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} +static inline void ade7754_unconfigure_ring(struct iio_dev *indio_dev) +{ +} +static inline int ade7754_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} +static inline void ade7754_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ + +#endif -- cgit v1.2.3 From 8210cfe9bd99fd63fae0b60c40fa793b8454e381 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:16 -0400 Subject: staging: iio: meter: new driver for ADE7758 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/meter/Kconfig | 9 + drivers/staging/iio/meter/Makefile | 4 + drivers/staging/iio/meter/ade7758.h | 171 ++++++ drivers/staging/iio/meter/ade7758_core.c | 866 ++++++++++++++++++++++++++++ drivers/staging/iio/meter/ade7758_ring.c | 212 +++++++ drivers/staging/iio/meter/ade7758_trigger.c | 125 ++++ 6 files changed, 1387 insertions(+) create mode 100644 drivers/staging/iio/meter/ade7758.h create mode 100644 drivers/staging/iio/meter/ade7758_core.c create mode 100644 drivers/staging/iio/meter/ade7758_ring.c create mode 100644 drivers/staging/iio/meter/ade7758_trigger.c (limited to 'drivers') diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig index 19f20f4ad52c..be88bb81b7dc 100644 --- a/drivers/staging/iio/meter/Kconfig +++ b/drivers/staging/iio/meter/Kconfig @@ -16,3 +16,12 @@ config ADE7754 help Say yes here to build support for Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver. + +config ADE7758 + tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver" + depends on SPI + select IIO_TRIGGER if IIO_RING_BUFFER + select IIO_SW_RING if IIO_RING_BUFFER + help + Say yes here to build support for Analog Devices ADE7758 Polyphase + Multifunction Energy Metering IC with Per Phase Information Driver. diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile index 7f65b991eb15..8e1a71d249c3 100644 --- a/drivers/staging/iio/meter/Makefile +++ b/drivers/staging/iio/meter/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_ADE7753) += ade7753.o obj-$(CONFIG_ADE7754) += ade7754.o + +ade7758-y := ade7758_core.o +ade7758-$(CONFIG_IIO_RING_BUFFER) += ade7758_ring.o ade7758_trigger.o +obj-$(CONFIG_ADE7758) += ade7758.o diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h new file mode 100644 index 000000000000..df5bb7ba5a0f --- /dev/null +++ b/drivers/staging/iio/meter/ade7758.h @@ -0,0 +1,171 @@ +#ifndef _ADE7758_H +#define _ADE7758_H + +#define ADE7758_AWATTHR 0x01 +#define ADE7758_BWATTHR 0x02 +#define ADE7758_CWATTHR 0x03 +#define ADE7758_AVARHR 0x04 +#define ADE7758_BVARHR 0x05 +#define ADE7758_CVARHR 0x06 +#define ADE7758_AVAHR 0x07 +#define ADE7758_BVAHR 0x08 +#define ADE7758_CVAHR 0x09 +#define ADE7758_AIRMS 0x0A +#define ADE7758_BIRMS 0x0B +#define ADE7758_CIRMS 0x0C +#define ADE7758_AVRMS 0x0D +#define ADE7758_BVRMS 0x0E +#define ADE7758_CVRMS 0x0F +#define ADE7758_FREQ 0x10 +#define ADE7758_TEMP 0x11 +#define ADE7758_WFORM 0x12 +#define ADE7758_OPMODE 0x13 +#define ADE7758_MMODE 0x14 +#define ADE7758_WAVMODE 0x15 +#define ADE7758_COMPMODE 0x16 +#define ADE7758_LCYCMODE 0x17 +#define ADE7758_MASK 0x18 +#define ADE7758_STATUS 0x19 +#define ADE7758_RSTATUS 0x1A +#define ADE7758_ZXTOUT 0x1B +#define ADE7758_LINECYC 0x1C +#define ADE7758_SAGCYC 0x1D +#define ADE7758_SAGLVL 0x1E +#define ADE7758_VPINTLVL 0x1F +#define ADE7758_IPINTLVL 0x20 +#define ADE7758_VPEAK 0x21 +#define ADE7758_IPEAK 0x22 +#define ADE7758_GAIN 0x23 +#define ADE7758_AVRMSGAIN 0x24 +#define ADE7758_BVRMSGAIN 0x25 +#define ADE7758_CVRMSGAIN 0x26 +#define ADE7758_AIGAIN 0x27 +#define ADE7758_BIGAIN 0x28 +#define ADE7758_CIGAIN 0x29 +#define ADE7758_AWG 0x2A +#define ADE7758_BWG 0x2B +#define ADE7758_CWG 0x2C +#define ADE7758_AVARG 0x2D +#define ADE7758_BVARG 0x2E +#define ADE7758_CVARG 0x2F +#define ADE7758_AVAG 0x30 +#define ADE7758_BVAG 0x31 +#define ADE7758_CVAG 0x32 +#define ADE7758_AVRMSOS 0x33 +#define ADE7758_BVRMSOS 0x34 +#define ADE7758_CVRMSOS 0x35 +#define ADE7758_AIRMSOS 0x36 +#define ADE7758_BIRMSOS 0x37 +#define ADE7758_CIRMSOS 0x38 +#define ADE7758_AWAITOS 0x39 +#define ADE7758_BWAITOS 0x3A +#define ADE7758_CWAITOS 0x3B +#define ADE7758_AVAROS 0x3C +#define ADE7758_BVAROS 0x3D +#define ADE7758_CVAROS 0x3E +#define ADE7758_APHCAL 0x3F +#define ADE7758_BPHCAL 0x40 +#define ADE7758_CPHCAL 0x41 +#define ADE7758_WDIV 0x42 +#define ADE7758_VADIV 0x44 +#define ADE7758_VARDIV 0x43 +#define ADE7758_APCFNUM 0x45 +#define ADE7758_APCFDEN 0x46 +#define ADE7758_VARCFNUM 0x47 +#define ADE7758_VARCFDEN 0x48 +#define ADE7758_CHKSUM 0x7E +#define ADE7758_VERSION 0x7F + +#define ADE7758_READ_REG(a) a +#define ADE7758_WRITE_REG(a) ((a) | 0x80) + +#define ADE7758_MAX_TX 8 +#define ADE7758_MAX_RX 4 +#define ADE7758_STARTUP_DELAY 1 + +#define ADE7758_SPI_SLOW (u32)(300 * 1000) +#define ADE7758_SPI_BURST (u32)(1000 * 1000) +#define ADE7758_SPI_FAST (u32)(2000 * 1000) + +#define DRIVER_NAME "ade7758" + +/** + * struct ade7758_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct ade7758_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; +#ifdef CONFIG_IIO_RING_BUFFER +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum ade7758_scan { + ADE7758_SCAN_WFORM, +}; + +void ade7758_remove_trigger(struct iio_dev *indio_dev); +int ade7758_probe_trigger(struct iio_dev *indio_dev); + +ssize_t ade7758_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int ade7758_configure_ring(struct iio_dev *indio_dev); +void ade7758_unconfigure_ring(struct iio_dev *indio_dev); + +int ade7758_initialize_ring(struct iio_ring_buffer *ring); +void ade7758_uninitialize_ring(struct iio_ring_buffer *ring); +int ade7758_set_irq(struct device *dev, bool enable); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void ade7758_remove_trigger(struct iio_dev *indio_dev) +{ +} +static inline int ade7758_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +ade7758_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int ade7758_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} +static inline void ade7758_unconfigure_ring(struct iio_dev *indio_dev) +{ +} +static inline int ade7758_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} +static inline void ade7758_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ + +#endif diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c new file mode 100644 index 000000000000..b7634cb7aa4f --- /dev/null +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -0,0 +1,866 @@ +/* + * ADE7758 Polyphase Multifunction Energy Metering IC Driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "meter.h" +#include "ade7758.h" + +int ade7758_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7758_spi_write_reg_16(struct device *dev, + u8 reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 3, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_WRITE_REG(reg_address); + st->tx[1] = (value >> 8) & 0xFF; + st->tx[2] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7758_spi_write_reg_24(struct device *dev, + u8 reg_address, + u32 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 4, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_WRITE_REG(reg_address); + st->tx[1] = (value >> 16) & 0xFF; + st->tx[2] = (value >> 8) & 0xFF; + st->tx[3] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7758_spi_read_reg_8(struct device *dev, + u8 reg_address, + u8 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_READ_REG(reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7758_spi_read_reg_16(struct device *dev, + u8 reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 3, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 8) | st->rx[2]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7758_spi_read_reg_24(struct device *dev, + u8 reg_address, + u32 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 4, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + st->tx[3] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t ade7758_read_8bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u8 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7758_spi_read_reg_8(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7758_read_16bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7758_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7758_read_24bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u32 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7758_spi_read_reg_24(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val & 0xFFFFFF); +} + +static ssize_t ade7758_write_8bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7758_spi_write_reg_8(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7758_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7758_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +int ade7758_reset(struct device *dev) +{ + int ret; + u8 val; + ade7758_spi_read_reg_8(dev, + ADE7758_OPMODE, + &val); + val |= 1 << 6; /* Software Chip Reset */ + ret = ade7758_spi_write_reg_8(dev, + ADE7758_OPMODE, + val); + + return ret; +} + +static ssize_t ade7758_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -1; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return ade7758_reset(dev); + } + return -1; +} + +static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_VPEAK); +static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_VPEAK); +static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_APHCAL); +static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_BPHCAL); +static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_CPHCAL); +static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_WDIV); +static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO, + ade7758_read_8bit, + ade7758_write_8bit, + ADE7758_VADIV); +static IIO_DEV_ATTR_AIRMS(S_IRUGO, + ade7758_read_24bit, + NULL, + ADE7758_AIRMS); +static IIO_DEV_ATTR_BIRMS(S_IRUGO, + ade7758_read_24bit, + NULL, + ADE7758_BIRMS); +static IIO_DEV_ATTR_CIRMS(S_IRUGO, + ade7758_read_24bit, + NULL, + ADE7758_CIRMS); +static IIO_DEV_ATTR_AVRMS(S_IRUGO, + ade7758_read_24bit, + NULL, + ADE7758_AVRMS); +static IIO_DEV_ATTR_BVRMS(S_IRUGO, + ade7758_read_24bit, + NULL, + ADE7758_BVRMS); +static IIO_DEV_ATTR_CVRMS(S_IRUGO, + ade7758_read_24bit, + NULL, + ADE7758_CVRMS); +static IIO_DEV_ATTR_AIRMSOS(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_AIRMSOS); +static IIO_DEV_ATTR_BIRMSOS(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_BIRMSOS); +static IIO_DEV_ATTR_CIRMSOS(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_CIRMSOS); +static IIO_DEV_ATTR_AVRMSOS(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_AVRMSOS); +static IIO_DEV_ATTR_BVRMSOS(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_BVRMSOS); +static IIO_DEV_ATTR_CVRMSOS(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_CVRMSOS); +static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_AIGAIN); +static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_BIGAIN); +static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_CIGAIN); +static IIO_DEV_ATTR_AVRMSGAIN(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_AVRMSGAIN); +static IIO_DEV_ATTR_BVRMSGAIN(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_BVRMSGAIN); +static IIO_DEV_ATTR_CVRMSGAIN(S_IWUSR | S_IRUGO, + ade7758_read_16bit, + ade7758_write_16bit, + ADE7758_CVRMSGAIN); + +int ade7758_set_irq(struct device *dev, bool enable) +{ + int ret; + u32 irqen; + ret = ade7758_spi_read_reg_24(dev, ADE7758_MASK, &irqen); + if (ret) + goto error_ret; + + if (enable) + irqen |= 1 << 16; /* Enables an interrupt when a data is + present in the waveform register */ + else + irqen &= ~(1 << 16); + + ret = ade7758_spi_write_reg_24(dev, ADE7758_MASK, irqen); + if (ret) + goto error_ret; + +error_ret: + return ret; +} + +/* Power down the device */ +static int ade7758_stop_device(struct device *dev) +{ + int ret; + u8 val; + ade7758_spi_read_reg_8(dev, + ADE7758_OPMODE, + &val); + val |= 7 << 3; /* ADE7758 powered down */ + ret = ade7758_spi_write_reg_8(dev, + ADE7758_OPMODE, + val); + + return ret; +} + +static int ade7758_initial_setup(struct ade7758_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* use low spi speed for init */ + st->us->mode = SPI_MODE_3; + spi_setup(st->us); + + /* Disable IRQ */ + ret = ade7758_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + ade7758_reset(dev); + msleep(ADE7758_STARTUP_DELAY); + +err_ret: + return ret; +} + +static ssize_t ade7758_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret, len = 0; + u8 t; + int sps; + ret = ade7758_spi_read_reg_8(dev, + ADE7758_WAVMODE, + &t); + if (ret) + return ret; + + t = (t >> 5) & 0x3; + sps = 26040 / (1 << t); + + len = sprintf(buf, "%d SPS\n", sps); + return len; +} + +static ssize_t ade7758_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + unsigned long val; + int ret; + u8 reg, t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + + t = (26040 / val); + if (t > 0) + t >>= 1; + + if (t > 1) + st->us->max_speed_hz = ADE7758_SPI_SLOW; + else + st->us->max_speed_hz = ADE7758_SPI_FAST; + + ret = ade7758_spi_read_reg_8(dev, + ADE7758_WAVMODE, + ®); + if (ret) + goto out; + + reg &= ~(5 << 3); + reg |= t << 5; + + ret = ade7758_spi_write_reg_8(dev, + ADE7758_WAVMODE, + reg); + +out: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +static ssize_t ade7758_read_waveform_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret, len = 0; + u8 t; + ret = ade7758_spi_read_reg_8(dev, + ADE7758_WAVMODE, + &t); + if (ret) + return ret; + + t = (t >> 2) & 0x7; + + len = sprintf(buf, "%d\n", t); + + return len; +} + +static ssize_t ade7758_write_waveform_type(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + unsigned long val; + int ret; + u8 reg; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + if (val > 4) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + + ret = ade7758_spi_read_reg_8(dev, + ADE7758_WAVMODE, + ®); + if (ret) + goto out; + + reg &= ~(7 << 2); + reg |= val << 2; + + ret = ade7758_spi_write_reg_8(dev, + ADE7758_WAVMODE, + reg); + +out: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +static IIO_DEV_ATTR_TEMP_RAW(ade7758_read_8bit); +static IIO_CONST_ATTR(temp_offset, "129 C"); +static IIO_CONST_ATTR(temp_scale, "4 C"); + +static IIO_DEV_ATTR_AWATTHR(ade7758_read_16bit, + ADE7758_AWATTHR); +static IIO_DEV_ATTR_BWATTHR(ade7758_read_16bit, + ADE7758_BWATTHR); +static IIO_DEV_ATTR_CWATTHR(ade7758_read_16bit, + ADE7758_CWATTHR); +static IIO_DEV_ATTR_AVARHR(ade7758_read_16bit, + ADE7758_AVARHR); +static IIO_DEV_ATTR_BVARHR(ade7758_read_16bit, + ADE7758_BVARHR); +static IIO_DEV_ATTR_CVARHR(ade7758_read_16bit, + ADE7758_CVARHR); +static IIO_DEV_ATTR_AVAHR(ade7758_read_16bit, + ADE7758_AVAHR); +static IIO_DEV_ATTR_BVAHR(ade7758_read_16bit, + ADE7758_BVAHR); +static IIO_DEV_ATTR_CVAHR(ade7758_read_16bit, + ADE7758_CVAHR); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ade7758_read_frequency, + ade7758_write_frequency); + +/** + * IIO_DEV_ATTR_WAVEFORM_TYPE - set the type of waveform. + * @_mode: sysfs file mode/permissions + * @_show: output method for the attribute + * @_store: input method for the attribute + **/ +#define IIO_DEV_ATTR_WAVEFORM_TYPE(_mode, _show, _store) \ + IIO_DEVICE_ATTR(waveform_type, _mode, _show, _store, 0) + +static IIO_DEV_ATTR_WAVEFORM_TYPE(S_IWUSR | S_IRUGO, + ade7758_read_waveform_type, + ade7758_write_waveform_type); + +static IIO_DEV_ATTR_RESET(ade7758_write_reset); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000"); + +static IIO_CONST_ATTR(name, "ade7758"); + +static struct attribute *ade7758_event_attributes[] = { + NULL +}; + +static struct attribute_group ade7758_event_attribute_group = { + .attrs = ade7758_event_attributes, +}; + +static struct attribute *ade7758_attributes[] = { + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_dev_attr_waveform_type.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_awatthr.dev_attr.attr, + &iio_dev_attr_bwatthr.dev_attr.attr, + &iio_dev_attr_cwatthr.dev_attr.attr, + &iio_dev_attr_avarhr.dev_attr.attr, + &iio_dev_attr_bvarhr.dev_attr.attr, + &iio_dev_attr_cvarhr.dev_attr.attr, + &iio_dev_attr_avahr.dev_attr.attr, + &iio_dev_attr_bvahr.dev_attr.attr, + &iio_dev_attr_cvahr.dev_attr.attr, + &iio_dev_attr_vpeak.dev_attr.attr, + &iio_dev_attr_ipeak.dev_attr.attr, + &iio_dev_attr_aphcal.dev_attr.attr, + &iio_dev_attr_bphcal.dev_attr.attr, + &iio_dev_attr_cphcal.dev_attr.attr, + &iio_dev_attr_wdiv.dev_attr.attr, + &iio_dev_attr_vadiv.dev_attr.attr, + &iio_dev_attr_airms.dev_attr.attr, + &iio_dev_attr_birms.dev_attr.attr, + &iio_dev_attr_cirms.dev_attr.attr, + &iio_dev_attr_avrms.dev_attr.attr, + &iio_dev_attr_bvrms.dev_attr.attr, + &iio_dev_attr_cvrms.dev_attr.attr, + &iio_dev_attr_aigain.dev_attr.attr, + &iio_dev_attr_bigain.dev_attr.attr, + &iio_dev_attr_cigain.dev_attr.attr, + &iio_dev_attr_avrmsgain.dev_attr.attr, + &iio_dev_attr_bvrmsgain.dev_attr.attr, + &iio_dev_attr_cvrmsgain.dev_attr.attr, + &iio_dev_attr_airmsos.dev_attr.attr, + &iio_dev_attr_birmsos.dev_attr.attr, + &iio_dev_attr_cirmsos.dev_attr.attr, + &iio_dev_attr_avrmsos.dev_attr.attr, + &iio_dev_attr_bvrmsos.dev_attr.attr, + &iio_dev_attr_cvrmsos.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ade7758_attribute_group = { + .attrs = ade7758_attributes, +}; + + + +static int __devinit ade7758_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct ade7758_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADE7758_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADE7758_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &ade7758_event_attribute_group; + st->indio_dev->attrs = &ade7758_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ade7758_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = ade7758_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + "ade7758"); + if (ret) + goto error_uninitialize_ring; + + ret = ade7758_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = ade7758_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + ade7758_remove_trigger(st->indio_dev); +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + ade7758_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + ade7758_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int ade7758_remove(struct spi_device *spi) +{ + int ret; + struct ade7758_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + ret = ade7758_stop_device(&(indio_dev->dev)); + if (ret) + goto err_ret; + + flush_scheduled_work(); + + ade7758_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + ade7758_uninitialize_ring(indio_dev->ring); + iio_device_unregister(indio_dev); + ade7758_unconfigure_ring(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; + +err_ret: + return ret; +} + +static struct spi_driver ade7758_driver = { + .driver = { + .name = "ade7758", + .owner = THIS_MODULE, + }, + .probe = ade7758_probe, + .remove = __devexit_p(ade7758_remove), +}; + +static __init int ade7758_init(void) +{ + return spi_register_driver(&ade7758_driver); +} +module_init(ade7758_init); + +static __exit void ade7758_exit(void) +{ + spi_unregister_driver(&ade7758_driver); +} +module_exit(ade7758_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7758 Polyphase Multifunction Energy Metering IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c new file mode 100644 index 000000000000..274b4a07808c --- /dev/null +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_sw.h" +#include "../accel/accel.h" +#include "../trigger.h" +#include "ade7758.h" + +/** + * combine_8_to_32() utility function to munge to u8s into u32 + **/ +static inline u32 combine_8_to_32(u8 lower, u8 mid, u8 upper) +{ + u32 _lower = lower; + u32 _mid = mid; + u32 _upper = upper; + + return _lower | (_mid << 8) | (_upper << 16); +} + +static IIO_SCAN_EL_C(wform, ADE7758_SCAN_WFORM, ADE7758_WFORM, NULL); +static IIO_CONST_ATTR_SCAN_EL_TYPE(wform, s, 24, 32); +static IIO_SCAN_EL_TIMESTAMP(1); +static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64); + +static struct attribute *ade7758_scan_el_attrs[] = { + &iio_scan_el_wform.dev_attr.attr, + &iio_const_attr_wform_index.dev_attr.attr, + &iio_const_attr_wform_type.dev_attr.attr, + &iio_scan_el_timestamp.dev_attr.attr, + &iio_const_attr_timestamp_index.dev_attr.attr, + &iio_const_attr_timestamp_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ade7758_scan_el_group = { + .attrs = ade7758_scan_el_attrs, + .name = "scan_elements", +}; + +/** + * ade7758_poll_func_th() top half interrupt handler called by trigger + * @private_data: iio_dev + **/ +static void ade7758_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + st->last_timestamp = time; + schedule_work(&st->work_trigger_to_ring); + /* Indicate that this interrupt is being handled */ + + /* Technically this is trigger related, but without this + * handler running there is currently no way for the interrupt + * to clear. + */ +} + +/** + * ade7758_spi_read_burst() - read all data registers + * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @rx: somewhere to pass back the value read (min size is 24 bytes) + **/ +static int ade7758_spi_read_burst(struct device *dev, u8 *rx) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7758_state *st = iio_dev_get_devdata(indio_dev); + int ret; + + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = rx, + .bits_per_word = 8, + .len = 4, + }, { + .tx_buf = st->tx + 4, + .rx_buf = rx, + .bits_per_word = 8, + .len = 4, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7758_READ_REG(ADE7758_RSTATUS); + st->tx[1] = 0; + st->tx[2] = 0; + st->tx[3] = 0; + st->tx[4] = ADE7758_READ_REG(ADE7758_WFORM); + st->tx[5] = 0; + st->tx[6] = 0; + st->tx[7] = 0; + + spi_message_init(&msg); + spi_message_add_tail(&xfers[0], &msg); + spi_message_add_tail(&xfers[1], &msg); + ret = spi_sync(st->us, &msg); + if (ret) + dev_err(&st->us->dev, "problem when reading WFORM value\n"); + + mutex_unlock(&st->buf_lock); + + return ret; +} + +/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device + * specific to be rolled into the core. + */ +static void ade7758_trigger_bh_to_ring(struct work_struct *work_s) +{ + struct ade7758_state *st + = container_of(work_s, struct ade7758_state, + work_trigger_to_ring); + struct iio_ring_buffer *ring = st->indio_dev->ring; + + int i = 0; + s32 *data; + size_t datasize = ring->access.get_bytes_per_datum(ring); + + data = kmalloc(datasize, GFP_KERNEL); + if (data == NULL) { + dev_err(&st->us->dev, "memory alloc failed in ring bh"); + return; + } + + if (ring->scan_count) + if (ade7758_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) + for (; i < ring->scan_count; i++) + data[i] = combine_8_to_32(st->rx[i*2+2], + st->rx[i*2+1], + st->rx[i*2]); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (ring->scan_timestamp) + *((s64 *) + (((u32)data + 4 * ring->scan_count + 4) & ~0x7)) = + st->last_timestamp; + + ring->access.store_to(ring, + (u8 *)data, + st->last_timestamp); + + iio_trigger_notify_done(st->indio_dev->trig); + kfree(data); + + return; +} + +void ade7758_unconfigure_ring(struct iio_dev *indio_dev) +{ + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} + +int ade7758_configure_ring(struct iio_dev *indio_dev) +{ + int ret = 0; + struct ade7758_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring; + INIT_WORK(&st->work_trigger_to_ring, ade7758_trigger_bh_to_ring); + + ring = iio_sw_rb_allocate(indio_dev); + if (!ring) { + ret = -ENOMEM; + return ret; + } + indio_dev->ring = ring; + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&ring->access); + ring->bpe = 4; + ring->scan_el_attrs = &ade7758_scan_el_group; + ring->scan_timestamp = true; + ring->preenable = &iio_sw_ring_preenable; + ring->postenable = &iio_triggered_ring_postenable; + ring->predisable = &iio_triggered_ring_predisable; + ring->owner = THIS_MODULE; + + /* Set default scan mode */ + iio_scan_mask_set(ring, iio_scan_el_wform.number); + + ret = iio_alloc_pollfunc(indio_dev, NULL, &ade7758_poll_func_th); + if (ret) + goto error_iio_sw_rb_free; + + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; + +error_iio_sw_rb_free: + iio_sw_rb_free(indio_dev->ring); + return ret; +} + +int ade7758_initialize_ring(struct iio_ring_buffer *ring) +{ + return iio_ring_buffer_register(ring, 0); +} + +void ade7758_uninitialize_ring(struct iio_ring_buffer *ring) +{ + iio_ring_buffer_unregister(ring); +} diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c new file mode 100644 index 000000000000..60abca0c28ff --- /dev/null +++ b/drivers/staging/iio/meter/ade7758_trigger.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../trigger.h" +#include "ade7758.h" + +/** + * ade7758_data_rdy_trig_poll() the event handler for the data rdy trig + **/ +static int ade7758_data_rdy_trig_poll(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ade7758_state *st = iio_dev_get_devdata(dev_info); + struct iio_trigger *trig = st->trig; + + iio_trigger_poll(trig, timestamp); + + return IRQ_HANDLED; +} + +IIO_EVENT_SH(data_rdy_trig, &ade7758_data_rdy_trig_poll); + +static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static struct attribute *ade7758_trigger_attrs[] = { + &dev_attr_name.attr, + NULL, +}; + +static const struct attribute_group ade7758_trigger_attr_group = { + .attrs = ade7758_trigger_attrs, +}; + +/** + * ade7758_data_rdy_trigger_set_state() set datardy interrupt state + **/ +static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct ade7758_state *st = trig->private_data; + struct iio_dev *indio_dev = st->indio_dev; + int ret = 0; + + dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); + ret = ade7758_set_irq(&st->indio_dev->dev, state); + if (state == false) { + iio_remove_event_from_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0] + ->ev_list); + /* possible quirk with handler currently worked around + by ensuring the work queue is empty */ + flush_scheduled_work(); + } else { + iio_add_event_to_list(&iio_event_data_rdy_trig, + &indio_dev->interrupts[0]->ev_list); + } + return ret; +} + +/** + * ade7758_trig_try_reen() try renabling irq for data rdy trigger + * @trig: the datardy trigger + **/ +static int ade7758_trig_try_reen(struct iio_trigger *trig) +{ + struct ade7758_state *st = trig->private_data; + enable_irq(st->us->irq); + /* irq reenabled so success! */ + return 0; +} + +int ade7758_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct ade7758_state *st = indio_dev->dev_data; + + st->trig = iio_allocate_trigger(); + st->trig->name = kasprintf(GFP_KERNEL, + "ade7758-dev%d", + indio_dev->id); + if (!st->trig->name) { + ret = -ENOMEM; + goto error_free_trig; + } + st->trig->dev.parent = &st->us->dev; + st->trig->owner = THIS_MODULE; + st->trig->private_data = st; + st->trig->set_trigger_state = &ade7758_data_rdy_trigger_set_state; + st->trig->try_reenable = &ade7758_trig_try_reen; + st->trig->control_attrs = &ade7758_trigger_attr_group; + ret = iio_trigger_register(st->trig); + + /* select default trigger */ + indio_dev->trig = st->trig; + if (ret) + goto error_free_trig_name; + + return 0; + +error_free_trig_name: + kfree(st->trig->name); +error_free_trig: + iio_free_trigger(st->trig); + + return ret; +} + +void ade7758_remove_trigger(struct iio_dev *indio_dev) +{ + struct ade7758_state *state = indio_dev->dev_data; + + iio_trigger_unregister(state->trig); + kfree(state->trig->name); + iio_free_trigger(state->trig); +} -- cgit v1.2.3 From 2919fa54ef643364eab69bfff5a72e4aa50d3e39 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:17 -0400 Subject: staging: iio: meter: new driver for ADE7759 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/meter/Kconfig | 7 + drivers/staging/iio/meter/Makefile | 2 + drivers/staging/iio/meter/ade7759.c | 670 ++++++++++++++++++++++++++++++++++++ drivers/staging/iio/meter/ade7759.h | 122 +++++++ 4 files changed, 801 insertions(+) create mode 100644 drivers/staging/iio/meter/ade7759.c create mode 100644 drivers/staging/iio/meter/ade7759.h (limited to 'drivers') diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig index be88bb81b7dc..ebc253eafdeb 100644 --- a/drivers/staging/iio/meter/Kconfig +++ b/drivers/staging/iio/meter/Kconfig @@ -25,3 +25,10 @@ config ADE7758 help Say yes here to build support for Analog Devices ADE7758 Polyphase Multifunction Energy Metering IC with Per Phase Information Driver. + +config ADE7759 + tristate "Analog Devices ADE7759 Active Energy Metering IC Driver" + depends on SPI + help + Say yes here to build support for Analog Devices ADE7758 Active Energy + Metering IC with di/dt Sensor Interface. diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile index 8e1a71d249c3..85e30213af34 100644 --- a/drivers/staging/iio/meter/Makefile +++ b/drivers/staging/iio/meter/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_ADE7754) += ade7754.o ade7758-y := ade7758_core.o ade7758-$(CONFIG_IIO_RING_BUFFER) += ade7758_ring.o ade7758_trigger.o obj-$(CONFIG_ADE7758) += ade7758.o + +obj-$(CONFIG_ADE7759) += ade7759.o diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c new file mode 100644 index 000000000000..fafc3c1e5aaa --- /dev/null +++ b/drivers/staging/iio/meter/ade7759.c @@ -0,0 +1,670 @@ +/* + * ADE7759 Active Energy Metering IC with di/dt Sensor Interface Driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "meter.h" +#include "ade7759.h" + +int ade7759_spi_write_reg_8(struct device *dev, + u8 reg_address, + u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7759_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7759_WRITE_REG(reg_address); + st->tx[1] = val; + + ret = spi_write(st->us, st->tx, 2); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7759_spi_write_reg_16(struct device *dev, + u8 reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7759_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 3, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7759_WRITE_REG(reg_address); + st->tx[1] = (value >> 8) & 0xFF; + st->tx[2] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7759_spi_read_reg_8(struct device *dev, + u8 reg_address, + u8 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7759_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 2, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7759_READ_REG(reg_address); + st->tx[1] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = st->rx[1]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7759_spi_read_reg_16(struct device *dev, + u8 reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7759_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 3, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7759_READ_REG(reg_address); + st->tx[1] = 0; + st->tx[2] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[1] << 8) | st->rx[2]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7759_spi_read_reg_40(struct device *dev, + u8 reg_address, + u64 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7759_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .rx_buf = st->rx, + .bits_per_word = 8, + .len = 6, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7759_READ_REG(reg_address); + memset(&st->tx[1], 0 , 5); + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->us, &msg); + if (ret) { + dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = ((u64)st->rx[1] << 32) | (st->rx[2] << 24) | + (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static ssize_t ade7759_read_8bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u8 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7759_spi_read_reg_8(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7759_read_16bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7759_spi_read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7759_read_40bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u64 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = ade7759_spi_read_reg_40(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%llu\n", val); +} + +static ssize_t ade7759_write_8bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7759_spi_write_reg_8(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7759_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = ade7759_spi_write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int ade7759_reset(struct device *dev) +{ + int ret; + u16 val; + ade7759_spi_read_reg_16(dev, + ADE7759_MODE, + &val); + val |= 1 << 6; /* Software Chip Reset */ + ret = ade7759_spi_write_reg_16(dev, + ADE7759_MODE, + val); + + return ret; +} + +static ssize_t ade7759_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -1; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return ade7759_reset(dev); + } + return -1; +} + +static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY); +static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO, + ade7759_read_16bit, + ade7759_write_16bit, + ADE7759_CFDEN); +static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_CFNUM); +static IIO_DEV_ATTR_CHKSUM(ade7759_read_8bit, ADE7759_CHKSUM); +static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO, + ade7759_read_16bit, + ade7759_write_16bit, + ADE7759_PHCAL); +static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO, + ade7759_read_16bit, + ade7759_write_16bit, + ADE7759_APOS); +static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_SAGCYC); +static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_SAGLVL); +static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_LINECYC); +static IIO_DEV_ATTR_LENERGY(ade7759_read_40bit, ADE7759_LENERGY); +static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_GAIN); +static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(S_IWUSR | S_IRUGO, + ade7759_read_16bit, + ade7759_write_16bit, + ADE7759_APGAIN); +static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_CH1OS); +static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_CH2OS); + +static int ade7759_set_irq(struct device *dev, bool enable) +{ + int ret; + u8 irqen; + ret = ade7759_spi_read_reg_8(dev, ADE7759_IRQEN, &irqen); + if (ret) + goto error_ret; + + if (enable) + irqen |= 1 << 3; /* Enables an interrupt when a data is + present in the waveform register */ + else + irqen &= ~(1 << 3); + + ret = ade7759_spi_write_reg_8(dev, ADE7759_IRQEN, irqen); + if (ret) + goto error_ret; + +error_ret: + return ret; +} + +/* Power down the device */ +int ade7759_stop_device(struct device *dev) +{ + int ret; + u16 val; + ade7759_spi_read_reg_16(dev, + ADE7759_MODE, + &val); + val |= 1 << 4; /* AD converters can be turned off */ + ret = ade7759_spi_write_reg_16(dev, + ADE7759_MODE, + val); + + return ret; +} + +static int ade7759_initial_setup(struct ade7759_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* use low spi speed for init */ + st->us->mode = SPI_MODE_3; + spi_setup(st->us); + + /* Disable IRQ */ + ret = ade7759_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + ade7759_reset(dev); + msleep(ADE7759_STARTUP_DELAY); + +err_ret: + return ret; +} + +static ssize_t ade7759_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret, len = 0; + u16 t; + int sps; + ret = ade7759_spi_read_reg_16(dev, + ADE7759_MODE, + &t); + if (ret) + return ret; + + t = (t >> 3) & 0x3; + sps = 27900 / (1 + t); + + len = sprintf(buf, "%d SPS\n", sps); + return len; +} + +static ssize_t ade7759_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7759_state *st = iio_dev_get_devdata(indio_dev); + unsigned long val; + int ret; + u16 reg, t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + + t = (27900 / val); + if (t > 0) + t--; + + if (t > 1) + st->us->max_speed_hz = ADE7759_SPI_SLOW; + else + st->us->max_speed_hz = ADE7759_SPI_FAST; + + ret = ade7759_spi_read_reg_16(dev, + ADE7759_MODE, + ®); + if (ret) + goto out; + + reg &= ~(3 << 13); + reg |= t << 13; + + ret = ade7759_spi_write_reg_16(dev, + ADE7759_MODE, + reg); + +out: + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} +static IIO_DEV_ATTR_TEMP_RAW(ade7759_read_8bit); +static IIO_CONST_ATTR(temp_offset, "70 C"); +static IIO_CONST_ATTR(temp_scale, "1 C"); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ade7759_read_frequency, + ade7759_write_frequency); + +static IIO_DEV_ATTR_RESET(ade7759_write_reset); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500"); + +static IIO_CONST_ATTR(name, "ade7759"); + +static struct attribute *ade7759_event_attributes[] = { + NULL +}; + +static struct attribute_group ade7759_event_attribute_group = { + .attrs = ade7759_event_attributes, +}; + +static struct attribute *ade7759_attributes[] = { + &iio_dev_attr_temp_raw.dev_attr.attr, + &iio_const_attr_temp_offset.dev_attr.attr, + &iio_const_attr_temp_scale.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_phcal.dev_attr.attr, + &iio_dev_attr_cfden.dev_attr.attr, + &iio_dev_attr_aenergy.dev_attr.attr, + &iio_dev_attr_cfnum.dev_attr.attr, + &iio_dev_attr_apos.dev_attr.attr, + &iio_dev_attr_sagcyc.dev_attr.attr, + &iio_dev_attr_saglvl.dev_attr.attr, + &iio_dev_attr_linecyc.dev_attr.attr, + &iio_dev_attr_lenergy.dev_attr.attr, + &iio_dev_attr_chksum.dev_attr.attr, + &iio_dev_attr_pga_gain.dev_attr.attr, + &iio_dev_attr_active_power_gain.dev_attr.attr, + &iio_dev_attr_choff_1.dev_attr.attr, + &iio_dev_attr_choff_2.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ade7759_attribute_group = { + .attrs = ade7759_attributes, +}; + +static int __devinit ade7759_probe(struct spi_device *spi) +{ + int ret, regdone = 0; + struct ade7759_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + goto error_ret; + } + /* this is only used for removal purposes */ + spi_set_drvdata(spi, st); + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADE7759_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADE7759_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + st->us = spi; + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &ade7759_event_attribute_group; + st->indio_dev->attrs = &ade7759_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ade7759_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = ade7759_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (spi->irq) { + ret = iio_register_interrupt_line(spi->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + "ade7759"); + if (ret) + goto error_uninitialize_ring; + + ret = ade7759_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + + /* Get the device into a sane initial state */ + ret = ade7759_initial_setup(st); + if (ret) + goto error_remove_trigger; + return 0; + +error_remove_trigger: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + ade7759_remove_trigger(st->indio_dev); +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + ade7759_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + ade7759_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +/* fixme, confirm ordering in this function */ +static int ade7759_remove(struct spi_device *spi) +{ + int ret; + struct ade7759_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + ret = ade7759_stop_device(&(indio_dev->dev)); + if (ret) + goto err_ret; + + flush_scheduled_work(); + + ade7759_remove_trigger(indio_dev); + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) + iio_unregister_interrupt_line(indio_dev, 0); + + ade7759_uninitialize_ring(indio_dev->ring); + ade7759_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; + +err_ret: + return ret; +} + +static struct spi_driver ade7759_driver = { + .driver = { + .name = "ade7759", + .owner = THIS_MODULE, + }, + .probe = ade7759_probe, + .remove = __devexit_p(ade7759_remove), +}; + +static __init int ade7759_init(void) +{ + return spi_register_driver(&ade7759_driver); +} +module_init(ade7759_init); + +static __exit void ade7759_exit(void) +{ + spi_unregister_driver(&ade7759_driver); +} +module_exit(ade7759_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7759 Active Energy Metering IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7759.h b/drivers/staging/iio/meter/ade7759.h new file mode 100644 index 000000000000..813dea2676a9 --- /dev/null +++ b/drivers/staging/iio/meter/ade7759.h @@ -0,0 +1,122 @@ +#ifndef _ADE7759_H +#define _ADE7759_H + +#define ADE7759_WAVEFORM 0x01 +#define ADE7759_AENERGY 0x02 +#define ADE7759_RSTENERGY 0x03 +#define ADE7759_STATUS 0x04 +#define ADE7759_RSTSTATUS 0x05 +#define ADE7759_MODE 0x06 +#define ADE7759_CFDEN 0x07 +#define ADE7759_CH1OS 0x08 +#define ADE7759_CH2OS 0x09 +#define ADE7759_GAIN 0x0A +#define ADE7759_APGAIN 0x0B +#define ADE7759_PHCAL 0x0C +#define ADE7759_APOS 0x0D +#define ADE7759_ZXTOUT 0x0E +#define ADE7759_SAGCYC 0x0F +#define ADE7759_IRQEN 0x10 +#define ADE7759_SAGLVL 0x11 +#define ADE7759_TEMP 0x12 +#define ADE7759_LINECYC 0x13 +#define ADE7759_LENERGY 0x14 +#define ADE7759_CFNUM 0x15 +#define ADE7759_CHKSUM 0x1E +#define ADE7759_DIEREV 0x1F + +#define ADE7759_READ_REG(a) a +#define ADE7759_WRITE_REG(a) ((a) | 0x80) + +#define ADE7759_MAX_TX 6 +#define ADE7759_MAX_RX 6 +#define ADE7759_STARTUP_DELAY 1 + +#define ADE7759_SPI_SLOW (u32)(300 * 1000) +#define ADE7759_SPI_BURST (u32)(1000 * 1000) +#define ADE7759_SPI_FAST (u32)(2000 * 1000) + +#define DRIVER_NAME "ade7759" + +/** + * struct ade7759_state - device instance specific data + * @us: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct ade7759_state { + struct spi_device *us; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + struct mutex buf_lock; +}; +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum ade7759_scan { + ADE7759_SCAN_ACTIVE_POWER, + ADE7759_SCAN_CH1_CH2, + ADE7759_SCAN_CH1, + ADE7759_SCAN_CH2, +}; + +void ade7759_remove_trigger(struct iio_dev *indio_dev); +int ade7759_probe_trigger(struct iio_dev *indio_dev); + +ssize_t ade7759_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int ade7759_configure_ring(struct iio_dev *indio_dev); +void ade7759_unconfigure_ring(struct iio_dev *indio_dev); + +int ade7759_initialize_ring(struct iio_ring_buffer *ring); +void ade7759_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void ade7759_remove_trigger(struct iio_dev *indio_dev) +{ +} +static inline int ade7759_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +ade7759_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static int ade7759_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} +static inline void ade7759_unconfigure_ring(struct iio_dev *indio_dev) +{ +} +static inline int ade7759_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} +static inline void ade7759_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ + +#endif -- cgit v1.2.3 From 5b264a624ebc9a082873aa06ea641cbdc760e6e1 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:18 -0400 Subject: staging: iio: meter: new driver for ADE7854/58/68/78 devices Signed-off-by: Barry Song Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/meter/Kconfig | 27 ++ drivers/staging/iio/meter/Makefile | 3 + drivers/staging/iio/meter/ade7854-i2c.c | 272 +++++++++++++ drivers/staging/iio/meter/ade7854-spi.c | 360 +++++++++++++++++ drivers/staging/iio/meter/ade7854.c | 680 ++++++++++++++++++++++++++++++++ drivers/staging/iio/meter/ade7854.h | 245 ++++++++++++ 6 files changed, 1587 insertions(+) create mode 100644 drivers/staging/iio/meter/ade7854-i2c.c create mode 100644 drivers/staging/iio/meter/ade7854-spi.c create mode 100644 drivers/staging/iio/meter/ade7854.c create mode 100644 drivers/staging/iio/meter/ade7854.h (limited to 'drivers') diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig index ebc253eafdeb..12e36e460693 100644 --- a/drivers/staging/iio/meter/Kconfig +++ b/drivers/staging/iio/meter/Kconfig @@ -32,3 +32,30 @@ config ADE7759 help Say yes here to build support for Analog Devices ADE7758 Active Energy Metering IC with di/dt Sensor Interface. + +config ADE7854 + tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver" + depends on SPI || I2C + help + Say yes here to build support for Analog Devices ADE7854/58/68/78 Polyphase + Multifunction Energy Metering IC Driver. + +config ADE7854_I2C + tristate "support I2C bus connection" + depends on ADE7854 && I2C + default y + help + Say Y here if you have ADE7854/58/68/78 hooked to an I2C bus. + + To compile this driver as a module, choose M here: the + module will be called ade7854-i2c. + +config ADE7854_SPI + tristate "support SPI bus connection" + depends on ADE7854 && SPI + default y + help + Say Y here if you have ADE7854/58/68/78 hooked to a SPI bus. + + To compile this driver as a module, choose M here: the + module will be called ade7854-spi. diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile index 85e30213af34..0cc7d5140dfe 100644 --- a/drivers/staging/iio/meter/Makefile +++ b/drivers/staging/iio/meter/Makefile @@ -10,3 +10,6 @@ ade7758-$(CONFIG_IIO_RING_BUFFER) += ade7758_ring.o ade7758_trigger.o obj-$(CONFIG_ADE7758) += ade7758.o obj-$(CONFIG_ADE7759) += ade7759.o +obj-$(CONFIG_ADE7854) += ade7854.o +obj-$(CONFIG_ADE7854_I2C) += ade7854-i2c.o +obj-$(CONFIG_ADE7854_SPI) += ade7854-spi.o diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c new file mode 100644 index 000000000000..4578e7b7f460 --- /dev/null +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -0,0 +1,272 @@ +/* + * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus) + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include "../iio.h" +#include "ade7854.h" + +static int ade7854_i2c_write_reg_8(struct device *dev, + u16 reg_address, + u8 value) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + st->tx[2] = value; + + ret = i2c_master_send(st->i2c, st->tx, 3); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_i2c_write_reg_16(struct device *dev, + u16 reg_address, + u16 value) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + st->tx[2] = (value >> 8) & 0xFF; + st->tx[3] = value & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 4); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_i2c_write_reg_24(struct device *dev, + u16 reg_address, + u32 value) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + st->tx[2] = (value >> 16) & 0xFF; + st->tx[3] = (value >> 8) & 0xFF; + st->tx[4] = value & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 5); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_i2c_write_reg_32(struct device *dev, + u16 reg_address, + u32 value) +{ + int ret; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + st->tx[2] = (value >> 24) & 0xFF; + st->tx[3] = (value >> 16) & 0xFF; + st->tx[4] = (value >> 8) & 0xFF; + st->tx[5] = value & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 6); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_i2c_read_reg_8(struct device *dev, + u16 reg_address, + u8 *val) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 2); + if (ret) + goto out; + + ret = i2c_master_recv(st->i2c, st->rx, 1); + if (ret) + goto out; + + *val = st->rx[0]; +out: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7854_i2c_read_reg_16(struct device *dev, + u16 reg_address, + u16 *val) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 2); + if (ret) + goto out; + + ret = i2c_master_recv(st->i2c, st->rx, 2); + if (ret) + goto out; + + *val = (st->rx[0] << 8) | st->rx[1]; +out: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7854_i2c_read_reg_24(struct device *dev, + u16 reg_address, + u32 *val) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 2); + if (ret) + goto out; + + ret = i2c_master_recv(st->i2c, st->rx, 3); + if (ret) + goto out; + + *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; +out: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7854_i2c_read_reg_32(struct device *dev, + u16 reg_address, + u32 *val) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + + mutex_lock(&st->buf_lock); + st->tx[0] = (reg_address >> 8) & 0xFF; + st->tx[1] = reg_address & 0xFF; + + ret = i2c_master_send(st->i2c, st->tx, 2); + if (ret) + goto out; + + ret = i2c_master_recv(st->i2c, st->rx, 3); + if (ret) + goto out; + + *val = (st->rx[0] << 24) | (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3]; +out: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int __devinit ade7854_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct ade7854_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + return ret; + } + + i2c_set_clientdata(client, st); + st->read_reg_8 = ade7854_i2c_read_reg_8; + st->read_reg_16 = ade7854_i2c_read_reg_16; + st->read_reg_24 = ade7854_i2c_read_reg_24; + st->read_reg_32 = ade7854_i2c_read_reg_32; + st->write_reg_8 = ade7854_i2c_write_reg_8; + st->write_reg_16 = ade7854_i2c_write_reg_16; + st->write_reg_24 = ade7854_i2c_write_reg_24; + st->write_reg_32 = ade7854_i2c_write_reg_32; + st->i2c = client; + st->irq = client->irq; + + ret = ade7854_probe(st, &client->dev); + if (ret) { + kfree(st); + return ret; + } + + return ret; +} + +static int __devexit ade7854_i2c_remove(struct i2c_client *client) +{ + return ade7854_remove(i2c_get_clientdata(client)); +} + +static const struct i2c_device_id ade7854_id[] = { + { "ade7854", 0 }, + { "ade7858", 0 }, + { "ade7868", 0 }, + { "ade7878", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ade7854_id); + +static struct i2c_driver ade7854_i2c_driver = { + .driver = { + .name = "ade7854", + }, + .probe = ade7854_i2c_probe, + .remove = __devexit_p(ade7854_i2c_remove), + .id_table = ade7854_id, +}; + +static __init int ade7854_i2c_init(void) +{ + return i2c_add_driver(&ade7854_i2c_driver); +} +module_init(ade7854_i2c_init); + +static __exit void ade7854_i2c_exit(void) +{ + i2c_del_driver(&ade7854_i2c_driver); +} +module_exit(ade7854_i2c_exit); + + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c new file mode 100644 index 000000000000..fe58103ed4ca --- /dev/null +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -0,0 +1,360 @@ +/* + * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (SPI Bus) + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include "../iio.h" +#include "ade7854.h" + +static int ade7854_spi_write_reg_8(struct device *dev, + u16 reg_address, + u8 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 4, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7854_WRITE_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_spi_write_reg_16(struct device *dev, + u16 reg_address, + u16 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 5, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7854_WRITE_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = (value >> 8) & 0xFF; + st->tx[4] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_spi_write_reg_24(struct device *dev, + u16 reg_address, + u32 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 6, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7854_WRITE_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = (value >> 16) & 0xFF; + st->tx[4] = (value >> 8) & 0xFF; + st->tx[5] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_spi_write_reg_32(struct device *dev, + u16 reg_address, + u32 value) +{ + int ret; + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 7, + } + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7854_WRITE_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = (value >> 24) & 0xFF; + st->tx[4] = (value >> 16) & 0xFF; + st->tx[5] = (value >> 8) & 0xFF; + st->tx[6] = value & 0xFF; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + mutex_unlock(&st->buf_lock); + + return ret; +} + +static int ade7854_spi_read_reg_8(struct device *dev, + u16 reg_address, + u8 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 4, + }, + }; + + mutex_lock(&st->buf_lock); + + st->tx[0] = ADE7854_READ_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + if (ret) { + dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = st->rx[3]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7854_spi_read_reg_16(struct device *dev, + u16 reg_address, + u16 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 5, + }, + }; + + mutex_lock(&st->buf_lock); + st->tx[0] = ADE7854_READ_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = 0; + st->tx[4] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + if (ret) { + dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[3] << 8) | st->rx[4]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7854_spi_read_reg_24(struct device *dev, + u16 reg_address, + u32 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 6, + }, + }; + + mutex_lock(&st->buf_lock); + + st->tx[0] = ADE7854_READ_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = 0; + st->tx[4] = 0; + st->tx[5] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + if (ret) { + dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int ade7854_spi_read_reg_32(struct device *dev, + u16 reg_address, + u32 *val) +{ + struct spi_message msg; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + int ret; + struct spi_transfer xfers[] = { + { + .tx_buf = st->tx, + .bits_per_word = 8, + .len = 7, + }, + }; + + mutex_lock(&st->buf_lock); + + st->tx[0] = ADE7854_READ_REG; + st->tx[1] = (reg_address >> 8) & 0xFF; + st->tx[2] = reg_address & 0xFF; + st->tx[3] = 0; + st->tx[4] = 0; + st->tx[5] = 0; + st->tx[6] = 0; + + spi_message_init(&msg); + spi_message_add_tail(xfers, &msg); + ret = spi_sync(st->spi, &msg); + if (ret) { + dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X", + reg_address); + goto error_ret; + } + *val = (st->rx[3] << 24) | (st->rx[4] << 16) | (st->rx[5] << 8) | st->rx[6]; + +error_ret: + mutex_unlock(&st->buf_lock); + return ret; +} + +static int __devinit ade7854_spi_probe(struct spi_device *spi) +{ + int ret; + struct ade7854_state *st = kzalloc(sizeof *st, GFP_KERNEL); + if (!st) { + ret = -ENOMEM; + return ret; + } + + spi_set_drvdata(spi, st); + st->read_reg_8 = ade7854_spi_read_reg_8; + st->read_reg_16 = ade7854_spi_read_reg_16; + st->read_reg_24 = ade7854_spi_read_reg_24; + st->read_reg_32 = ade7854_spi_read_reg_32; + st->write_reg_8 = ade7854_spi_write_reg_8; + st->write_reg_16 = ade7854_spi_write_reg_16; + st->write_reg_24 = ade7854_spi_write_reg_24; + st->write_reg_32 = ade7854_spi_write_reg_32; + st->irq = spi->irq; + st->spi = spi; + + ret = ade7854_probe(st, &spi->dev); + if (ret) { + kfree(st); + return ret; + } + + return 0; +} + +static int ade7854_spi_remove(struct spi_device *spi) +{ + ade7854_remove(spi_get_drvdata(spi)); + + return 0; +} + +static struct spi_driver ade7854_driver = { + .driver = { + .name = "ade7854", + .owner = THIS_MODULE, + }, + .probe = ade7854_spi_probe, + .remove = __devexit_p(ade7854_spi_remove), +}; + +static __init int ade7854_init(void) +{ + return spi_register_driver(&ade7854_driver); +} +module_init(ade7854_init); + +static __exit void ade7854_exit(void) +{ + spi_unregister_driver(&ade7854_driver); +} +module_exit(ade7854_exit); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC SPI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c new file mode 100644 index 000000000000..a13d5048cf42 --- /dev/null +++ b/drivers/staging/iio/meter/ade7854.c @@ -0,0 +1,680 @@ +/* + * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "meter.h" +#include "ade7854.h" + +static ssize_t ade7854_read_8bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u8 val = 0; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = st->read_reg_8(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7854_read_16bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u16 val = 0; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = st->read_reg_16(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7854_read_24bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u32 val = 0; + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = st->read_reg_24(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val & 0xFFFFFF); +} + +static ssize_t ade7854_read_32bit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + u32 val = 0; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + ret = st->read_reg_32(dev, this_attr->address, &val); + if (ret) + return ret; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t ade7854_write_8bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = st->write_reg_8(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7854_write_16bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = st->write_reg_16(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7854_write_24bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = st->write_reg_24(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ade7854_write_32bit(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + ret = st->write_reg_32(dev, this_attr->address, val); + +error_ret: + return ret ? ret : len; +} + +static int ade7854_reset(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + int ret; + u16 val; + + st->read_reg_16(dev, ADE7854_CONFIG, &val); + val |= 1 << 7; /* Software Chip Reset */ + ret = st->write_reg_16(dev, ADE7854_CONFIG, val); + + return ret; +} + + +static ssize_t ade7854_write_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + if (len < 1) + return -1; + switch (buf[0]) { + case '1': + case 'y': + case 'Y': + return ade7854_reset(dev); + } + return -1; +} + +static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_AIGAIN); +static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_BIGAIN); +static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_CIGAIN); +static IIO_DEV_ATTR_NIGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_NIGAIN); +static IIO_DEV_ATTR_AVGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_AVGAIN); +static IIO_DEV_ATTR_BVGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_BVGAIN); +static IIO_DEV_ATTR_CVGAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_CVGAIN); +static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_AVAGAIN); +static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_BVAGAIN); +static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_CVAGAIN); +static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_AWATTOS); +static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_BWATTOS); +static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_CWATTOS); +static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_AVARGAIN); +static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_BVARGAIN); +static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_CVARGAIN); +static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_AVAROS); +static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_BVAROS); +static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO, + ade7854_read_24bit, + ade7854_write_24bit, + ADE7854_CVAROS); +static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO, + ade7854_read_32bit, + ade7854_write_32bit, + ADE7854_VPEAK); +static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO, + ade7854_read_32bit, + ade7854_write_32bit, + ADE7854_VPEAK); +static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_APHCAL); +static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_BPHCAL); +static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_CPHCAL); +static IIO_DEV_ATTR_CF1DEN(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_CF1DEN); +static IIO_DEV_ATTR_CF2DEN(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_CF2DEN); +static IIO_DEV_ATTR_CF3DEN(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_CF3DEN); +static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_LINECYC); +static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO, + ade7854_read_8bit, + ade7854_write_8bit, + ADE7854_SAGCYC); +static IIO_DEV_ATTR_CFCYC(S_IWUSR | S_IRUGO, + ade7854_read_8bit, + ade7854_write_8bit, + ADE7854_CFCYC); +static IIO_DEV_ATTR_PEAKCYC(S_IWUSR | S_IRUGO, + ade7854_read_8bit, + ade7854_write_8bit, + ADE7854_PEAKCYC); +static IIO_DEV_ATTR_CHKSUM(ade7854_read_24bit, + ADE7854_CHECKSUM); +static IIO_DEV_ATTR_ANGLE0(ade7854_read_24bit, + ADE7854_ANGLE0); +static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit, + ADE7854_ANGLE1); +static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit, + ADE7854_ANGLE2); +static IIO_DEV_ATTR_AIRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_AIRMS); +static IIO_DEV_ATTR_BIRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_BIRMS); +static IIO_DEV_ATTR_CIRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_CIRMS); +static IIO_DEV_ATTR_NIRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_NIRMS); +static IIO_DEV_ATTR_AVRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_AVRMS); +static IIO_DEV_ATTR_BVRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_BVRMS); +static IIO_DEV_ATTR_CVRMS(S_IRUGO, + ade7854_read_24bit, + NULL, + ADE7854_CVRMS); +static IIO_DEV_ATTR_AIRMSOS(S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_AIRMSOS); +static IIO_DEV_ATTR_BIRMSOS(S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_BIRMSOS); +static IIO_DEV_ATTR_CIRMSOS(S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_CIRMSOS); +static IIO_DEV_ATTR_AVRMSOS(S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_AVRMSOS); +static IIO_DEV_ATTR_BVRMSOS(S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_BVRMSOS); +static IIO_DEV_ATTR_CVRMSOS(S_IRUGO, + ade7854_read_16bit, + ade7854_write_16bit, + ADE7854_CVRMSOS); +static IIO_DEV_ATTR_VOLT_A(ade7854_read_24bit, + ADE7854_VAWV); +static IIO_DEV_ATTR_VOLT_B(ade7854_read_24bit, + ADE7854_VBWV); +static IIO_DEV_ATTR_VOLT_C(ade7854_read_24bit, + ADE7854_VCWV); +static IIO_DEV_ATTR_CURRENT_A(ade7854_read_24bit, + ADE7854_IAWV); +static IIO_DEV_ATTR_CURRENT_B(ade7854_read_24bit, + ADE7854_IBWV); +static IIO_DEV_ATTR_CURRENT_C(ade7854_read_24bit, + ADE7854_ICWV); +static IIO_DEV_ATTR_AWATTHR(ade7854_read_32bit, + ADE7854_AWATTHR); +static IIO_DEV_ATTR_BWATTHR(ade7854_read_32bit, + ADE7854_BWATTHR); +static IIO_DEV_ATTR_CWATTHR(ade7854_read_32bit, + ADE7854_CWATTHR); +static IIO_DEV_ATTR_AFWATTHR(ade7854_read_32bit, + ADE7854_AFWATTHR); +static IIO_DEV_ATTR_BFWATTHR(ade7854_read_32bit, + ADE7854_BFWATTHR); +static IIO_DEV_ATTR_CFWATTHR(ade7854_read_32bit, + ADE7854_CFWATTHR); +static IIO_DEV_ATTR_AVARHR(ade7854_read_32bit, + ADE7854_AVARHR); +static IIO_DEV_ATTR_BVARHR(ade7854_read_32bit, + ADE7854_BVARHR); +static IIO_DEV_ATTR_CVARHR(ade7854_read_32bit, + ADE7854_CVARHR); +static IIO_DEV_ATTR_AVAHR(ade7854_read_32bit, + ADE7854_AVAHR); +static IIO_DEV_ATTR_BVAHR(ade7854_read_32bit, + ADE7854_BVAHR); +static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit, + ADE7854_CVAHR); + +static int ade7854_set_irq(struct device *dev, bool enable) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ade7854_state *st = iio_dev_get_devdata(indio_dev); + + int ret; + u32 irqen; + + ret = st->read_reg_32(dev, ADE7854_MASK0, &irqen); + if (ret) + goto error_ret; + + if (enable) + irqen |= 1 << 17; /* 1: interrupt enabled when all periodical + (at 8 kHz rate) DSP computations finish. */ + else + irqen &= ~(1 << 17); + + ret = st->write_reg_32(dev, ADE7854_MASK0, irqen); + if (ret) + goto error_ret; + +error_ret: + return ret; +} + +static int ade7854_initial_setup(struct ade7854_state *st) +{ + int ret; + struct device *dev = &st->indio_dev->dev; + + /* Disable IRQ */ + ret = ade7854_set_irq(dev, false); + if (ret) { + dev_err(dev, "disable irq failed"); + goto err_ret; + } + + ade7854_reset(dev); + msleep(ADE7854_STARTUP_DELAY); + +err_ret: + return ret; +} + +static IIO_DEV_ATTR_RESET(ade7854_write_reset); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000"); + +static IIO_CONST_ATTR(name, "ade7854"); + +static struct attribute *ade7854_event_attributes[] = { + NULL +}; + +static struct attribute_group ade7854_event_attribute_group = { + .attrs = ade7854_event_attributes, +}; + +static struct attribute *ade7854_attributes[] = { + &iio_dev_attr_aigain.dev_attr.attr, + &iio_dev_attr_bigain.dev_attr.attr, + &iio_dev_attr_cigain.dev_attr.attr, + &iio_dev_attr_nigain.dev_attr.attr, + &iio_dev_attr_avgain.dev_attr.attr, + &iio_dev_attr_bvgain.dev_attr.attr, + &iio_dev_attr_cvgain.dev_attr.attr, + &iio_dev_attr_linecyc.dev_attr.attr, + &iio_dev_attr_sagcyc.dev_attr.attr, + &iio_dev_attr_cfcyc.dev_attr.attr, + &iio_dev_attr_peakcyc.dev_attr.attr, + &iio_dev_attr_chksum.dev_attr.attr, + &iio_dev_attr_apparent_power_a_gain.dev_attr.attr, + &iio_dev_attr_apparent_power_b_gain.dev_attr.attr, + &iio_dev_attr_apparent_power_c_gain.dev_attr.attr, + &iio_dev_attr_active_power_a_offset.dev_attr.attr, + &iio_dev_attr_active_power_b_offset.dev_attr.attr, + &iio_dev_attr_active_power_c_offset.dev_attr.attr, + &iio_dev_attr_reactive_power_a_gain.dev_attr.attr, + &iio_dev_attr_reactive_power_b_gain.dev_attr.attr, + &iio_dev_attr_reactive_power_c_gain.dev_attr.attr, + &iio_dev_attr_reactive_power_a_offset.dev_attr.attr, + &iio_dev_attr_reactive_power_b_offset.dev_attr.attr, + &iio_dev_attr_reactive_power_c_offset.dev_attr.attr, + &iio_dev_attr_awatthr.dev_attr.attr, + &iio_dev_attr_bwatthr.dev_attr.attr, + &iio_dev_attr_cwatthr.dev_attr.attr, + &iio_dev_attr_afwatthr.dev_attr.attr, + &iio_dev_attr_bfwatthr.dev_attr.attr, + &iio_dev_attr_cfwatthr.dev_attr.attr, + &iio_dev_attr_avarhr.dev_attr.attr, + &iio_dev_attr_bvarhr.dev_attr.attr, + &iio_dev_attr_cvarhr.dev_attr.attr, + &iio_dev_attr_angle0.dev_attr.attr, + &iio_dev_attr_angle1.dev_attr.attr, + &iio_dev_attr_angle2.dev_attr.attr, + &iio_dev_attr_avahr.dev_attr.attr, + &iio_dev_attr_bvahr.dev_attr.attr, + &iio_dev_attr_cvahr.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_const_attr_name.dev_attr.attr, + &iio_dev_attr_vpeak.dev_attr.attr, + &iio_dev_attr_ipeak.dev_attr.attr, + &iio_dev_attr_aphcal.dev_attr.attr, + &iio_dev_attr_bphcal.dev_attr.attr, + &iio_dev_attr_cphcal.dev_attr.attr, + &iio_dev_attr_cf1den.dev_attr.attr, + &iio_dev_attr_cf2den.dev_attr.attr, + &iio_dev_attr_cf3den.dev_attr.attr, + &iio_dev_attr_airms.dev_attr.attr, + &iio_dev_attr_birms.dev_attr.attr, + &iio_dev_attr_cirms.dev_attr.attr, + &iio_dev_attr_nirms.dev_attr.attr, + &iio_dev_attr_avrms.dev_attr.attr, + &iio_dev_attr_bvrms.dev_attr.attr, + &iio_dev_attr_cvrms.dev_attr.attr, + &iio_dev_attr_airmsos.dev_attr.attr, + &iio_dev_attr_birmsos.dev_attr.attr, + &iio_dev_attr_cirmsos.dev_attr.attr, + &iio_dev_attr_avrmsos.dev_attr.attr, + &iio_dev_attr_bvrmsos.dev_attr.attr, + &iio_dev_attr_cvrmsos.dev_attr.attr, + &iio_dev_attr_volt_a.dev_attr.attr, + &iio_dev_attr_volt_b.dev_attr.attr, + &iio_dev_attr_volt_c.dev_attr.attr, + &iio_dev_attr_current_a.dev_attr.attr, + &iio_dev_attr_current_b.dev_attr.attr, + &iio_dev_attr_current_c.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ade7854_attribute_group = { + .attrs = ade7854_attributes, +}; + +int ade7854_probe(struct ade7854_state *st, struct device *dev) +{ + int ret, regdone = 0; + + /* Allocate the comms buffers */ + st->rx = kzalloc(sizeof(*st->rx)*ADE7854_MAX_RX, GFP_KERNEL); + if (st->rx == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->tx = kzalloc(sizeof(*st->tx)*ADE7854_MAX_TX, GFP_KERNEL); + if (st->tx == NULL) { + ret = -ENOMEM; + goto error_free_rx; + } + mutex_init(&st->buf_lock); + /* setup the industrialio driver allocated elements */ + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_free_tx; + } + + st->indio_dev->dev.parent = dev; + st->indio_dev->num_interrupt_lines = 1; + st->indio_dev->event_attrs = &ade7854_event_attribute_group; + st->indio_dev->attrs = &ade7854_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ade7854_configure_ring(st->indio_dev); + if (ret) + goto error_free_dev; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_unreg_ring_funcs; + regdone = 1; + + ret = ade7854_initialize_ring(st->indio_dev->ring); + if (ret) { + printk(KERN_ERR "failed to initialize the ring\n"); + goto error_unreg_ring_funcs; + } + + if (st->irq) { + ret = iio_register_interrupt_line(st->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + "ade7854"); + if (ret) + goto error_uninitialize_ring; + + ret = ade7854_probe_trigger(st->indio_dev); + if (ret) + goto error_unregister_line; + } + /* Get the device into a sane initial state */ + ret = ade7854_initial_setup(st); + if (ret) + goto error_remove_trigger; + + return 0; + +error_remove_trigger: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + ade7854_remove_trigger(st->indio_dev); +error_unregister_line: + if (st->indio_dev->modes & INDIO_RING_TRIGGERED) + iio_unregister_interrupt_line(st->indio_dev, 0); +error_uninitialize_ring: + ade7854_uninitialize_ring(st->indio_dev->ring); +error_unreg_ring_funcs: + ade7854_unconfigure_ring(st->indio_dev); +error_free_dev: + if (regdone) + iio_device_unregister(st->indio_dev); + else + iio_free_device(st->indio_dev); +error_free_tx: + kfree(st->tx); +error_free_rx: + kfree(st->rx); +error_free_st: + kfree(st); + return ret; + +} +EXPORT_SYMBOL(ade7854_probe); + +int ade7854_remove(struct ade7854_state *st) +{ + struct iio_dev *indio_dev = st->indio_dev; + + flush_scheduled_work(); + + ade7854_remove_trigger(indio_dev); + if (st->irq) + iio_unregister_interrupt_line(indio_dev, 0); + + ade7854_uninitialize_ring(indio_dev->ring); + ade7854_unconfigure_ring(indio_dev); + iio_device_unregister(indio_dev); + kfree(st->tx); + kfree(st->rx); + kfree(st); + + return 0; +} +EXPORT_SYMBOL(ade7854_remove); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h new file mode 100644 index 000000000000..47690e521ec1 --- /dev/null +++ b/drivers/staging/iio/meter/ade7854.h @@ -0,0 +1,245 @@ +#ifndef _ADE7854_H +#define _ADE7854_H + +#define ADE7854_AIGAIN 0x4380 +#define ADE7854_AVGAIN 0x4381 +#define ADE7854_BIGAIN 0x4382 +#define ADE7854_BVGAIN 0x4383 +#define ADE7854_CIGAIN 0x4384 +#define ADE7854_CVGAIN 0x4385 +#define ADE7854_NIGAIN 0x4386 +#define ADE7854_AIRMSOS 0x4387 +#define ADE7854_AVRMSOS 0x4388 +#define ADE7854_BIRMSOS 0x4389 +#define ADE7854_BVRMSOS 0x438A +#define ADE7854_CIRMSOS 0x438B +#define ADE7854_CVRMSOS 0x438C +#define ADE7854_NIRMSOS 0x438D +#define ADE7854_AVAGAIN 0x438E +#define ADE7854_BVAGAIN 0x438F +#define ADE7854_CVAGAIN 0x4390 +#define ADE7854_AWGAIN 0x4391 +#define ADE7854_AWATTOS 0x4392 +#define ADE7854_BWGAIN 0x4393 +#define ADE7854_BWATTOS 0x4394 +#define ADE7854_CWGAIN 0x4395 +#define ADE7854_CWATTOS 0x4396 +#define ADE7854_AVARGAIN 0x4397 +#define ADE7854_AVAROS 0x4398 +#define ADE7854_BVARGAIN 0x4399 +#define ADE7854_BVAROS 0x439A +#define ADE7854_CVARGAIN 0x439B +#define ADE7854_CVAROS 0x439C +#define ADE7854_AFWGAIN 0x439D +#define ADE7854_AFWATTOS 0x439E +#define ADE7854_BFWGAIN 0x439F +#define ADE7854_BFWATTOS 0x43A0 +#define ADE7854_CFWGAIN 0x43A1 +#define ADE7854_CFWATTOS 0x43A2 +#define ADE7854_AFVARGAIN 0x43A3 +#define ADE7854_AFVAROS 0x43A4 +#define ADE7854_BFVARGAIN 0x43A5 +#define ADE7854_BFVAROS 0x43A6 +#define ADE7854_CFVARGAIN 0x43A7 +#define ADE7854_CFVAROS 0x43A8 +#define ADE7854_VATHR1 0x43A9 +#define ADE7854_VATHR0 0x43AA +#define ADE7854_WTHR1 0x43AB +#define ADE7854_WTHR0 0x43AC +#define ADE7854_VARTHR1 0x43AD +#define ADE7854_VARTHR0 0x43AE +#define ADE7854_RSV 0x43AF +#define ADE7854_VANOLOAD 0x43B0 +#define ADE7854_APNOLOAD 0x43B1 +#define ADE7854_VARNOLOAD 0x43B2 +#define ADE7854_VLEVEL 0x43B3 +#define ADE7854_DICOEFF 0x43B5 +#define ADE7854_HPFDIS 0x43B6 +#define ADE7854_ISUMLVL 0x43B8 +#define ADE7854_ISUM 0x43BF +#define ADE7854_AIRMS 0x43C0 +#define ADE7854_AVRMS 0x43C1 +#define ADE7854_BIRMS 0x43C2 +#define ADE7854_BVRMS 0x43C3 +#define ADE7854_CIRMS 0x43C4 +#define ADE7854_CVRMS 0x43C5 +#define ADE7854_NIRMS 0x43C6 +#define ADE7854_RUN 0xE228 +#define ADE7854_AWATTHR 0xE400 +#define ADE7854_BWATTHR 0xE401 +#define ADE7854_CWATTHR 0xE402 +#define ADE7854_AFWATTHR 0xE403 +#define ADE7854_BFWATTHR 0xE404 +#define ADE7854_CFWATTHR 0xE405 +#define ADE7854_AVARHR 0xE406 +#define ADE7854_BVARHR 0xE407 +#define ADE7854_CVARHR 0xE408 +#define ADE7854_AFVARHR 0xE409 +#define ADE7854_BFVARHR 0xE40A +#define ADE7854_CFVARHR 0xE40B +#define ADE7854_AVAHR 0xE40C +#define ADE7854_BVAHR 0xE40D +#define ADE7854_CVAHR 0xE40E +#define ADE7854_IPEAK 0xE500 +#define ADE7854_VPEAK 0xE501 +#define ADE7854_STATUS0 0xE502 +#define ADE7854_STATUS1 0xE503 +#define ADE7854_OILVL 0xE507 +#define ADE7854_OVLVL 0xE508 +#define ADE7854_SAGLVL 0xE509 +#define ADE7854_MASK0 0xE50A +#define ADE7854_MASK1 0xE50B +#define ADE7854_IAWV 0xE50C +#define ADE7854_IBWV 0xE50D +#define ADE7854_ICWV 0xE50E +#define ADE7854_VAWV 0xE510 +#define ADE7854_VBWV 0xE511 +#define ADE7854_VCWV 0xE512 +#define ADE7854_AWATT 0xE513 +#define ADE7854_BWATT 0xE514 +#define ADE7854_CWATT 0xE515 +#define ADE7854_AVA 0xE519 +#define ADE7854_BVA 0xE51A +#define ADE7854_CVA 0xE51B +#define ADE7854_CHECKSUM 0xE51F +#define ADE7854_VNOM 0xE520 +#define ADE7854_PHSTATUS 0xE600 +#define ADE7854_ANGLE0 0xE601 +#define ADE7854_ANGLE1 0xE602 +#define ADE7854_ANGLE2 0xE603 +#define ADE7854_PERIOD 0xE607 +#define ADE7854_PHNOLOAD 0xE608 +#define ADE7854_LINECYC 0xE60C +#define ADE7854_ZXTOUT 0xE60D +#define ADE7854_COMPMODE 0xE60E +#define ADE7854_GAIN 0xE60F +#define ADE7854_CFMODE 0xE610 +#define ADE7854_CF1DEN 0xE611 +#define ADE7854_CF2DEN 0xE612 +#define ADE7854_CF3DEN 0xE613 +#define ADE7854_APHCAL 0xE614 +#define ADE7854_BPHCAL 0xE615 +#define ADE7854_CPHCAL 0xE616 +#define ADE7854_PHSIGN 0xE617 +#define ADE7854_CONFIG 0xE618 +#define ADE7854_MMODE 0xE700 +#define ADE7854_ACCMODE 0xE701 +#define ADE7854_LCYCMODE 0xE702 +#define ADE7854_PEAKCYC 0xE703 +#define ADE7854_SAGCYC 0xE704 +#define ADE7854_CFCYC 0xE705 +#define ADE7854_HSDC_CFG 0xE706 +#define ADE7854_CONFIG2 0xEC01 + +#define ADE7854_READ_REG 0x1 +#define ADE7854_WRITE_REG 0x0 + +#define ADE7854_MAX_TX 7 +#define ADE7854_MAX_RX 7 +#define ADE7854_STARTUP_DELAY 1 + +#define ADE7854_SPI_SLOW (u32)(300 * 1000) +#define ADE7854_SPI_BURST (u32)(1000 * 1000) +#define ADE7854_SPI_FAST (u32)(2000 * 1000) + +#define DRIVER_NAME "ade7854" + +/** + * struct ade7854_state - device instance specific data + * @spi: actual spi_device + * @work_trigger_to_ring: bh for triggered event handling + * @inter: used to check if new interrupt has been triggered + * @last_timestamp: passing timestamp from th to bh of interrupt handler + * @indio_dev: industrial I/O device structure + * @trig: data ready trigger registered with iio + * @tx: transmit buffer + * @rx: recieve buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct ade7854_state { + struct spi_device *spi; + struct i2c_client *i2c; + struct work_struct work_trigger_to_ring; + s64 last_timestamp; + struct iio_dev *indio_dev; + struct iio_trigger *trig; + u8 *tx; + u8 *rx; + int (*read_reg_8) (struct device *, u16, u8 *); + int (*read_reg_16) (struct device *, u16, u16 *); + int (*read_reg_24) (struct device *, u16, u32 *); + int (*read_reg_32) (struct device *, u16, u32 *); + int (*write_reg_8) (struct device *, u16, u8); + int (*write_reg_16) (struct device *, u16, u16); + int (*write_reg_24) (struct device *, u16, u32); + int (*write_reg_32) (struct device *, u16, u32); + int irq; + struct mutex buf_lock; +}; + +extern int ade7854_probe(struct ade7854_state *st, struct device *dev); +extern int ade7854_remove(struct ade7854_state *st); + +#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT) +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum ade7854_scan { + ADE7854_SCAN_PHA_V, + ADE7854_SCAN_PHB_V, + ADE7854_SCAN_PHC_V, + ADE7854_SCAN_PHA_I, + ADE7854_SCAN_PHB_I, + ADE7854_SCAN_PHC_I, +}; + +void ade7854_remove_trigger(struct iio_dev *indio_dev); +int ade7854_probe_trigger(struct iio_dev *indio_dev); + +ssize_t ade7854_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int ade7854_configure_ring(struct iio_dev *indio_dev); +void ade7854_unconfigure_ring(struct iio_dev *indio_dev); + +int ade7854_initialize_ring(struct iio_ring_buffer *ring); +void ade7854_uninitialize_ring(struct iio_ring_buffer *ring); +#else /* CONFIG_IIO_RING_BUFFER */ + +static inline void ade7854_remove_trigger(struct iio_dev *indio_dev) +{ +} +static inline int ade7854_probe_trigger(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline ssize_t +ade7854_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return 0; +} + +static inline int ade7854_configure_ring(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void ade7854_unconfigure_ring(struct iio_dev *indio_dev) +{ +} +static inline int ade7854_initialize_ring(struct iio_ring_buffer *ring) +{ + return 0; +} +static inline void ade7854_uninitialize_ring(struct iio_ring_buffer *ring) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ + +#endif -- cgit v1.2.3 From f46d9f154ac3001b90e75ca646400a13b499a49e Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 27 Oct 2010 21:44:19 -0400 Subject: staging: iio: resolver: new driver for AD2S90 devices This also kicks off the new resolver subsection. Signed-off-by: Graf Yang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/Kconfig | 1 + drivers/staging/iio/Makefile | 1 + drivers/staging/iio/resolver/Kconfig | 11 +++ drivers/staging/iio/resolver/Makefile | 5 ++ drivers/staging/iio/resolver/ad2s90.c | 159 ++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+) create mode 100644 drivers/staging/iio/resolver/Kconfig create mode 100644 drivers/staging/iio/resolver/Makefile create mode 100644 drivers/staging/iio/resolver/ad2s90.c (limited to 'drivers') diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index ffe8912bd7ab..e2ac07d86110 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -50,6 +50,7 @@ source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" source "drivers/staging/iio/magnetometer/Kconfig" source "drivers/staging/iio/meter/Kconfig" +source "drivers/staging/iio/resolver/Kconfig" source "drivers/staging/iio/trigger/Kconfig" endif # IIO diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 5b449a15e5aa..f9b5fb2fe8f1 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -19,4 +19,5 @@ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ obj-y += meter/ +obj-y += resolver/ obj-y += trigger/ diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig new file mode 100644 index 000000000000..05b15a909855 --- /dev/null +++ b/drivers/staging/iio/resolver/Kconfig @@ -0,0 +1,11 @@ +# +# Resolver/Synchro drivers +# +comment "Resolver to digital converters" + +config AD2S90 + tristate "Analog Devices ad2s90 driver" + depends on SPI + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s90, provides direct access via sysfs. diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile new file mode 100644 index 000000000000..067fa7044156 --- /dev/null +++ b/drivers/staging/iio/resolver/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Resolver/Synchro drivers +# + +obj-$(CONFIG_AD2S90) += ad2s90.o diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c new file mode 100644 index 000000000000..4143535242d9 --- /dev/null +++ b/drivers/staging/iio/resolver/ad2s90.c @@ -0,0 +1,159 @@ +/* + * ad2s90.c simple support for the ADI Resolver to Digital Converters: AD2S90 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad2s90" + +struct ad2s90_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; + u8 rx[2]; + u8 tx[2]; +}; + +static ssize_t ad2s90_show_angular(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret; + ssize_t len = 0; + u16 val; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s90_state *st = idev->dev_data; + + xfer.len = 1; + xfer.tx_buf = st->tx; + xfer.rx_buf = st->rx; + mutex_lock(&st->lock); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); + len = sprintf(buf, "%d\n", val); +error_ret: + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +#define IIO_DEV_ATTR_SIMPLE_RESOLVER(_show) \ + IIO_DEVICE_ATTR(angular, S_IRUGO, _show, NULL, 0) + +static IIO_CONST_ATTR(description, + "Low Cost, Complete 12-Bit Resolver-to-Digital Converter"); +static IIO_DEV_ATTR_SIMPLE_RESOLVER(ad2s90_show_angular); + +static struct attribute *ad2s90_attributes[] = { + &iio_const_attr_description.dev_attr.attr, + &iio_dev_attr_angular.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s90_attribute_group = { + .name = DRV_NAME, + .attrs = ad2s90_attributes, +}; + +static int __devinit ad2s90_probe(struct spi_device *spi) +{ + struct ad2s90_state *st; + int ret = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad2s90_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + + /* need 600ns between CS and the first falling edge of SCLK */ + spi->max_speed_hz = 830000; + spi->mode = SPI_MODE_3; + spi_setup(spi); + + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad2s90_remove(struct spi_device *spi) +{ + struct ad2s90_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad2s90_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad2s90_probe, + .remove = __devexit_p(ad2s90_remove), +}; + +static __init int ad2s90_spi_init(void) +{ + return spi_register_driver(&ad2s90_driver); +} +module_init(ad2s90_spi_init); + +static __exit void ad2s90_spi_exit(void) +{ + spi_unregister_driver(&ad2s90_driver); +} +module_exit(ad2s90_spi_exit); + +MODULE_AUTHOR("Graff Yang "); +MODULE_DESCRIPTION("Analog Devices AD2S90 Resolver to Digital SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From ffd7a62f0dffa92409dc769562a4997eb424a7d3 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 27 Oct 2010 21:44:20 -0400 Subject: staging: iio: resolver: new driver for AD2S1200/1205 devices Signed-off-by: Graf Yang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/resolver/Kconfig | 8 + drivers/staging/iio/resolver/Makefile | 1 + drivers/staging/iio/resolver/ad2s120x.c | 310 ++++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+) create mode 100644 drivers/staging/iio/resolver/ad2s120x.c (limited to 'drivers') diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig index 05b15a909855..32df73aeb0c5 100644 --- a/drivers/staging/iio/resolver/Kconfig +++ b/drivers/staging/iio/resolver/Kconfig @@ -9,3 +9,11 @@ config AD2S90 help Say yes here to build support for Analog Devices spi resolver to digital converters, ad2s90, provides direct access via sysfs. + +config AD2S120X + tristate "Analog Devices ad2s120x driver" + depends on SPI + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s1200 and ad2s1205, provides direct access + via sysfs. diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile index 067fa7044156..b2b3cc1ddc67 100644 --- a/drivers/staging/iio/resolver/Makefile +++ b/drivers/staging/iio/resolver/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_AD2S90) += ad2s90.o +obj-$(CONFIG_AD2S120X) += ad2s120x.o diff --git a/drivers/staging/iio/resolver/ad2s120x.c b/drivers/staging/iio/resolver/ad2s120x.c new file mode 100644 index 000000000000..8f497a23976c --- /dev/null +++ b/drivers/staging/iio/resolver/ad2s120x.c @@ -0,0 +1,310 @@ +/* + * ad2s120x.c simple support for the ADI Resolver to Digital Converters: AD2S1200/1205 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad2s120x" + +/* input pin sample and rdvel is controlled by driver */ +#define AD2S120X_PN 2 + +/* input clock on serial interface */ +#define AD2S120X_HZ 8192000 +/* clock period in nano second */ +#define AD2S120X_TSCLK (1000000000/AD2S120X_HZ) + +struct ad2s120x_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; + unsigned short sample; + unsigned short rdvel; + u8 rx[2]; + u8 tx[2]; +}; + +static ssize_t ad2s120x_show_pos_vel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret = 0; + ssize_t len = 0; + u16 pos; + s16 vel; + u8 status; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s120x_state *st = idev->dev_data; + + xfer.len = 1; + xfer.tx_buf = st->tx; + xfer.rx_buf = st->rx; + mutex_lock(&st->lock); + + gpio_set_value(st->sample, 0); + /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */ + udelay(1); + gpio_set_value(st->sample, 1); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + status = st->rx[1]; + pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); + len = sprintf(buf, "%d %c%c%c%c ", pos, + (status & 0x8) ? 'P' : 'V', + (status & 0x4) ? 'd' : '_', + (status & 0x2) ? 'l' : '_', + (status & 0x1) ? '1' : '0'); + + /* delay 18 ns */ + /* ndelay(18); */ + + gpio_set_value(st->rdvel, 0); + /* ndelay(5);*/ + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + status = st->rx[1]; + vel = (st->rx[0] & 0x80) ? 0xf000 : 0; + vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); + len += sprintf(buf + len, "%d %c%c%c%c\n", vel, + (status & 0x8) ? 'P' : 'V', + (status & 0x4) ? 'd' : '_', + (status & 0x2) ? 'l' : '_', + (status & 0x1) ? '1' : '0'); +error_ret: + gpio_set_value(st->rdvel, 1); + /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */ + udelay(1); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static ssize_t ad2s120x_show_pos(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret = 0; + ssize_t len = 0; + u16 pos; + u8 status; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s120x_state *st = idev->dev_data; + + xfer.len = 1; + xfer.tx_buf = st->tx; + xfer.rx_buf = st->rx; + mutex_lock(&st->lock); + + gpio_set_value(st->sample, 0); + /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */ + udelay(1); + gpio_set_value(st->sample, 1); + gpio_set_value(st->rdvel, 1); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + status = st->rx[1]; + pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); + len = sprintf(buf, "%d %c%c%c%c ", pos, + (status & 0x8) ? 'P' : 'V', + (status & 0x4) ? 'd' : '_', + (status & 0x2) ? 'l' : '_', + (status & 0x1) ? '1' : '0'); +error_ret: + /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */ + udelay(1); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static ssize_t ad2s120x_show_vel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + struct spi_transfer xfer; + int ret = 0; + ssize_t len = 0; + s16 vel; + u8 status; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s120x_state *st = idev->dev_data; + + xfer.len = 1; + xfer.tx_buf = st->tx; + xfer.rx_buf = st->rx; + mutex_lock(&st->lock); + + gpio_set_value(st->sample, 0); + /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */ + udelay(1); + gpio_set_value(st->sample, 1); + + gpio_set_value(st->rdvel, 0); + /* ndelay(5);*/ + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + status = st->rx[1]; + vel = (st->rx[0] & 0x80) ? 0xf000 : 0; + vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); + len += sprintf(buf + len, "%d %c%c%c%c\n", vel, + (status & 0x8) ? 'P' : 'V', + (status & 0x4) ? 'd' : '_', + (status & 0x2) ? 'l' : '_', + (status & 0x1) ? '1' : '0'); +error_ret: + gpio_set_value(st->rdvel, 1); + /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */ + udelay(1); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_CONST_ATTR(description, + "12-Bit R/D Converter with Reference Oscillator"); +static IIO_DEVICE_ATTR(pos_vel, S_IRUGO, ad2s120x_show_pos_vel, NULL, 0); +static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s120x_show_pos, NULL, 0); +static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s120x_show_vel, NULL, 0); + +static struct attribute *ad2s120x_attributes[] = { + &iio_const_attr_description.dev_attr.attr, + &iio_dev_attr_pos_vel.dev_attr.attr, + &iio_dev_attr_pos.dev_attr.attr, + &iio_dev_attr_vel.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s120x_attribute_group = { + .name = DRV_NAME, + .attrs = ad2s120x_attributes, +}; + +static int __devinit ad2s120x_probe(struct spi_device *spi) +{ + struct ad2s120x_state *st; + int pn, ret = 0; + unsigned short *pins = spi->dev.platform_data; + + for (pn = 0; pn < AD2S120X_PN; pn++) { + if (gpio_request(pins[pn], DRV_NAME)) { + pr_err("%s: request gpio pin %d failed\n", + DRV_NAME, pins[pn]); + goto error_ret; + } + gpio_direction_output(pins[pn], 1); + } + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + st->sample = pins[0]; + st->rdvel = pins[1]; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad2s120x_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + + spi->max_speed_hz = AD2S120X_HZ; + spi->mode = SPI_MODE_3; + spi_setup(spi); + + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + for (--pn; pn >= 0; pn--) + gpio_free(pins[pn]); + return ret; +} + +static int __devexit ad2s120x_remove(struct spi_device *spi) +{ + struct ad2s120x_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad2s120x_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad2s120x_probe, + .remove = __devexit_p(ad2s120x_remove), +}; + +static __init int ad2s120x_spi_init(void) +{ + return spi_register_driver(&ad2s120x_driver); +} +module_init(ad2s120x_spi_init); + +static __exit void ad2s120x_spi_exit(void) +{ + spi_unregister_driver(&ad2s120x_driver); +} +module_exit(ad2s120x_spi_exit); + +MODULE_AUTHOR("Graff Yang "); +MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 817e5c65c511d4a83686333ae75507deb4b55d5e Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 27 Oct 2010 21:44:21 -0400 Subject: staging: iio: resolver: new driver for AD2S1210 devices Signed-off-by: Graf Yang Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/resolver/Kconfig | 35 ++ drivers/staging/iio/resolver/Makefile | 1 + drivers/staging/iio/resolver/ad2s1210.c | 872 ++++++++++++++++++++++++++++++++ 3 files changed, 908 insertions(+) create mode 100644 drivers/staging/iio/resolver/ad2s1210.c (limited to 'drivers') diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig index 32df73aeb0c5..a4a363429355 100644 --- a/drivers/staging/iio/resolver/Kconfig +++ b/drivers/staging/iio/resolver/Kconfig @@ -17,3 +17,38 @@ config AD2S120X Say yes here to build support for Analog Devices spi resolver to digital converters, ad2s1200 and ad2s1205, provides direct access via sysfs. + +config AD2S1210 + tristate "Analog Devices ad2s1210 driver" + depends on SPI + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s1210, provides direct access via sysfs. + +choice + prompt "Resolution Control" + depends on AD2S1210 + default AD2S1210_GPIO_NONE + help + In normal mode, the resolution of the digital output is selected + using the RES0 and RES1 input pins. In configuration mode, the + resolution is selected by setting the RES0 and RES1 bits in the + control regsiter. When switching between normal mode and configuration + mode, there are some schemes to keep them matchs. + +config AD2S1210_GPIO_INPUT + bool "read resolution from gpio pins" + help + GPIO pins are sampling RES0 and RES1 pins, read the resolution + settings from the GPIO pins. + +config AD2S1210_GPIO_OUTPUT + bool "set gpio pins to set resolution" + help + RES0 and RES1 pins are controlled by GPIOs, setting GPIO pins to + set the resolution. + +config AD2S1210_GPIO_NONE + bool "take the responsibility by user" + +endchoice diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile index b2b3cc1ddc67..0b84a89e6cac 100644 --- a/drivers/staging/iio/resolver/Makefile +++ b/drivers/staging/iio/resolver/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_AD2S90) += ad2s90.o obj-$(CONFIG_AD2S120X) += ad2s120x.o +obj-$(CONFIG_AD2S1210) += ad2s1210.o diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c new file mode 100644 index 000000000000..34fb21aa8b07 --- /dev/null +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -0,0 +1,872 @@ +/* + * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" + +#define DRV_NAME "ad2s1210" + +#define DEF_CONTROL 0x7E + +#define MSB_IS_HIGH 0x80 +#define MSB_IS_LOW 0x7F +#define PHASE_LOCK_RANGE_44 0x20 +#define ENABLE_HYSTERESIS 0x10 +#define SET_ENRES1 0x08 +#define SET_ENRES0 0x04 +#define SET_RES1 0x02 +#define SET_RES0 0x01 + +#define SET_ENRESOLUTION (SET_ENRES1 | SET_ENRES0) +#define SET_RESOLUTION (SET_RES1 | SET_RES0) + +#define REG_POSITION 0x80 +#define REG_VELOCITY 0x82 +#define REG_LOS_THRD 0x88 +#define REG_DOS_OVR_THRD 0x89 +#define REG_DOS_MIS_THRD 0x8A +#define REG_DOS_RST_MAX_THRD 0x8B +#define REG_DOS_RST_MIN_THRD 0x8C +#define REG_LOT_HIGH_THRD 0x8D +#define REG_LOT_LOW_THRD 0x8E +#define REG_EXCIT_FREQ 0x91 +#define REG_CONTROL 0x92 +#define REG_SOFT_RESET 0xF0 +#define REG_FAULT 0xFF + +/* pin SAMPLE, A0, A1, RES0, RES1, is controlled by driver */ +#define AD2S1210_SAA 3 +#if defined(CONFIG_AD2S1210_GPIO_INPUT) || defined(CONFIG_AD2S1210_GPIO_OUTPUT) +# define AD2S1210_RES 2 +#else +# define AD2S1210_RES 0 +#endif +#define AD2S1210_PN (AD2S1210_SAA + AD2S1210_RES) + +#define AD2S1210_MIN_CLKIN 6144000 +#define AD2S1210_MAX_CLKIN 10240000 +#define AD2S1210_MIN_EXCIT 2000 +#define AD2S1210_MAX_EXCIT 20000 +#define AD2S1210_MIN_FCW 0x4 +#define AD2S1210_MAX_FCW 0x50 + +/* default input clock on serial interface */ +#define AD2S1210_DEF_CLKIN 8192000 +/* clock period in nano second */ +#define AD2S1210_DEF_TCK (1000000000/AD2S1210_DEF_CLKIN) +#define AD2S1210_DEF_EXCIT 10000 + +enum ad2s1210_mode { + MOD_POS = 0, + MOD_VEL, + MOD_RESERVED, + MOD_CONFIG, +}; + +enum ad2s1210_res { + RES_10 = 10, + RES_12 = 12, + RES_14 = 14, + RES_16 = 16, +}; + +static unsigned int resolution_value[] = { + RES_10, RES_12, RES_14, RES_16}; + +struct ad2s1210_state { + struct mutex lock; + struct iio_dev *idev; + struct spi_device *sdev; + struct spi_transfer xfer; + unsigned int hysteresis; + unsigned int old_data; + enum ad2s1210_mode mode; + enum ad2s1210_res resolution; + unsigned int fclkin; + unsigned int fexcit; + unsigned short sample; + unsigned short a0; + unsigned short a1; + unsigned short res0; + unsigned short res1; + u8 rx[3]; + u8 tx[3]; +}; + +static inline void start_sample(struct ad2s1210_state *st) +{ + gpio_set_value(st->sample, 0); +} + +static inline void stop_sample(struct ad2s1210_state *st) +{ + gpio_set_value(st->sample, 1); +} + +static inline void set_mode(enum ad2s1210_mode mode, struct ad2s1210_state *st) +{ + switch (mode) { + case MOD_POS: + gpio_set_value(st->a0, 0); + gpio_set_value(st->a1, 0); + break; + case MOD_VEL: + gpio_set_value(st->a0, 0); + gpio_set_value(st->a1, 1); + break; + case MOD_CONFIG: + gpio_set_value(st->a0, 1); + gpio_set_value(st->a1, 1); + break; + default: + /* set to reserved mode */ + gpio_set_value(st->a0, 1); + gpio_set_value(st->a1, 0); + } + st->mode = mode; +} + +/* write 1 bytes (address or data) to the chip */ +static int config_write(struct ad2s1210_state *st, + unsigned char data) +{ + struct spi_message msg; + int ret = 0; + + st->xfer.len = 1; + set_mode(MOD_CONFIG, st); + + spi_message_init(&msg); + spi_message_add_tail(&st->xfer, &msg); + st->tx[0] = data; + ret = spi_sync(st->sdev, &msg); + if (ret) + return ret; + st->old_data = 1; + return ret; +} + +/* read value from one of the registers */ +static int config_read(struct ad2s1210_state *st, + unsigned char address, + unsigned char *data) +{ + struct spi_message msg; + int ret = 0; + + st->xfer.len = 2; + set_mode(MOD_CONFIG, st); + + spi_message_init(&msg); + spi_message_add_tail(&st->xfer, &msg); + st->tx[0] = address | MSB_IS_HIGH; + st->tx[1] = REG_FAULT; + ret = spi_sync(st->sdev, &msg); + if (ret) + return ret; + *data = st->rx[1]; + st->old_data = 1; + return ret; +} + +static inline void update_frequency_control_word(struct ad2s1210_state *st) +{ + unsigned char fcw; + fcw = (unsigned char)(st->fexcit * (1 << 15) / st->fclkin); + if (fcw >= AD2S1210_MIN_FCW && fcw <= AD2S1210_MAX_FCW) { + config_write(st, REG_EXCIT_FREQ); + config_write(st, fcw); + } else + pr_err("ad2s1210: FCW out of range\n"); +} + +#if defined(CONFIG_AD2S1210_GPIO_INPUT) +static inline unsigned char read_resolution_pin(struct ad2s1210_state *st) +{ + unsigned int data; + data = (gpio_get_value(st->res0) << 1) | + gpio_get_value(st->res1); + return resolution_value[data]; +} +#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT) +static inline void set_resolution_pin(struct ad2s1210_state *st) +{ + switch (st->resolution) { + case RES_10: + gpio_set_value(st->res0, 0); + gpio_set_value(st->res1, 0); + break; + case RES_12: + gpio_set_value(st->res0, 0); + gpio_set_value(st->res1, 1); + break; + case RES_14: + gpio_set_value(st->res0, 1); + gpio_set_value(st->res1, 0); + break; + case RES_16: + gpio_set_value(st->res0, 1); + gpio_set_value(st->res1, 1); + break; + } +} +#endif + +static inline void soft_reset(struct ad2s1210_state *st) +{ + config_write(st, REG_SOFT_RESET); + config_write(st, 0x0); +} + + +/* return the OLD DATA since last spi bus write */ +static ssize_t ad2s1210_show_raw(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + int ret; + + mutex_lock(&st->lock); + if (st->old_data) { + ret = sprintf(buf, "0x%x\n", st->rx[0]); + st->old_data = 0; + } else + ret = 0; + mutex_unlock(&st->lock); + return ret; +} + +static ssize_t ad2s1210_store_raw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned long udata; + unsigned char data; + int ret; + + ret = strict_strtoul(buf, 16, &udata); + if (ret) + return -EINVAL; + data = udata & 0xff; + mutex_lock(&st->lock); + config_write(st, data); + mutex_unlock(&st->lock); + return 1; +} + +static ssize_t ad2s1210_store_softreset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + mutex_lock(&st->lock); + soft_reset(st); + mutex_unlock(&st->lock); + return len; +} + +static ssize_t ad2s1210_show_fclkin(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + return sprintf(buf, "%d\n", st->fclkin); +} + +static ssize_t ad2s1210_store_fclkin(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned long fclkin; + int ret; + + ret = strict_strtoul(buf, 10, &fclkin); + if (!ret && fclkin >= AD2S1210_MIN_CLKIN && + fclkin <= AD2S1210_MAX_CLKIN) { + mutex_lock(&st->lock); + st->fclkin = fclkin; + } else { + pr_err("ad2s1210: fclkin out of range\n"); + return -EINVAL; + } + update_frequency_control_word(st); + soft_reset(st); + mutex_unlock(&st->lock); + return len; +} + +static ssize_t ad2s1210_show_fexcit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + return sprintf(buf, "%d\n", st->fexcit); +} + +static ssize_t ad2s1210_store_fexcit(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned long fexcit; + int ret; + + ret = strict_strtoul(buf, 10, &fexcit); + if (!ret && fexcit >= AD2S1210_MIN_EXCIT && + fexcit <= AD2S1210_MAX_EXCIT) { + mutex_lock(&st->lock); + st->fexcit = fexcit; + } else { + pr_err("ad2s1210: excitation frequency out of range\n"); + return -EINVAL; + } + update_frequency_control_word(st); + soft_reset(st); + mutex_unlock(&st->lock); + return len; +} + +static ssize_t ad2s1210_show_control(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned char data; + mutex_lock(&st->lock); + config_read(st, REG_CONTROL, &data); + mutex_unlock(&st->lock); + return sprintf(buf, "0x%x\n", data); +} + +static ssize_t ad2s1210_store_control(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned long udata; + unsigned char data; + int ret; + + ret = strict_strtoul(buf, 16, &udata); + if (ret) { + ret = -EINVAL; + goto error_ret; + } + mutex_lock(&st->lock); + config_write(st, REG_CONTROL); + data = udata & MSB_IS_LOW; + config_write(st, data); + config_read(st, REG_CONTROL, &data); + if (data & MSB_IS_HIGH) { + ret = -EIO; + pr_err("ad2s1210: write control register fail\n"); + goto error_ret; + } + st->resolution = resolution_value[data & SET_RESOLUTION]; +#if defined(CONFIG_AD2S1210_GPIO_INPUT) + data = read_resolution_pin(st); + if (data != st->resolution) + pr_warning("ad2s1210: resolution settings not match\n"); +#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT) + set_resolution_pin(st); +#endif + ret = len; + if (data & ENABLE_HYSTERESIS) + st->hysteresis = 1; + else + st->hysteresis = 0; +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static ssize_t ad2s1210_show_resolution(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + return sprintf(buf, "%d\n", st->resolution); +} + +static ssize_t ad2s1210_store_resolution(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned char data; + unsigned long udata; + int ret; + + ret = strict_strtoul(buf, 10, &udata); + if (ret || udata < RES_10 || udata > RES_16) { + pr_err("ad2s1210: resolution out of range\n"); + return -EINVAL; + } + mutex_lock(&st->lock); + config_read(st, REG_CONTROL, &data); + data &= ~SET_RESOLUTION; + data |= (udata - RES_10) >> 1; + config_write(st, REG_CONTROL); + config_write(st, data & MSB_IS_LOW); + config_read(st, REG_CONTROL, &data); + if (data & MSB_IS_HIGH) { + ret = -EIO; + pr_err("ad2s1210: setting resolution fail\n"); + goto error_ret; + } + st->resolution = resolution_value[data & SET_RESOLUTION]; +#if defined(CONFIG_AD2S1210_GPIO_INPUT) + data = read_resolution_pin(st); + if (data != st->resolution) + pr_warning("ad2s1210: resolution settings not match\n"); +#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT) + set_resolution_pin(st); +#endif + ret = len; +error_ret: + mutex_unlock(&st->lock); + return ret; +} +/* read the fault register since last sample */ +static ssize_t ad2s1210_show_fault(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + ssize_t len = 0; + unsigned char data; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + + mutex_lock(&st->lock); + ret = config_read(st, REG_FAULT, &data); + + if (ret) + goto error_ret; + len = sprintf(buf, "0x%x\n", data); +error_ret: + mutex_unlock(&st->lock); + return ret ? ret : len; +} + +static ssize_t ad2s1210_clear_fault(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned char data; + + mutex_lock(&st->lock); + start_sample(st); + /* delay (2 * tck + 20) nano seconds */ + udelay(1); + stop_sample(st); + config_read(st, REG_FAULT, &data); + start_sample(st); + stop_sample(st); + mutex_unlock(&st->lock); + + return 0; +} + +static ssize_t ad2s1210_show_reg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned char data; + struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + + mutex_lock(&st->lock); + config_read(st, iattr->address, &data); + mutex_unlock(&st->lock); + return sprintf(buf, "%d\n", data); +} + +static ssize_t ad2s1210_store_reg(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + unsigned long data; + int ret; + struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + + ret = strict_strtoul(buf, 10, &data); + if (ret) + return -EINVAL; + mutex_lock(&st->lock); + config_write(st, iattr->address); + config_write(st, data & MSB_IS_LOW); + mutex_unlock(&st->lock); + return len; +} + +static ssize_t ad2s1210_show_pos(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + int ret = 0; + ssize_t len = 0; + u16 pos; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + + st->xfer.len = 2; + mutex_lock(&st->lock); + start_sample(st); + /* delay (6 * tck + 20) nano seconds */ + udelay(1); + + set_mode(MOD_POS, st); + + spi_message_init(&msg); + spi_message_add_tail(&st->xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + pos = ((((u16)(st->rx[0])) << 8) | (st->rx[1])); + if (st->hysteresis) + pos >>= 16 - st->resolution; + len = sprintf(buf, "%d\n", pos); +error_ret: + stop_sample(st); + /* delay (2 * tck + 20) nano seconds */ + udelay(1); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static ssize_t ad2s1210_show_vel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + unsigned short negative; + int ret = 0; + ssize_t len = 0; + s16 vel; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + + st->xfer.len = 2; + mutex_lock(&st->lock); + start_sample(st); + /* delay (6 * tck + 20) nano seconds */ + udelay(1); + + set_mode(MOD_VEL, st); + + spi_message_init(&msg); + spi_message_add_tail(&st->xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + negative = st->rx[0] & 0x80; + vel = ((((s16)(st->rx[0])) << 8) | (st->rx[1])); + vel >>= 16 - st->resolution; + if (negative) { + negative = (0xffff >> st->resolution) << st->resolution; + vel |= negative; + } + len = sprintf(buf, "%d\n", vel); +error_ret: + stop_sample(st); + /* delay (2 * tck + 20) nano seconds */ + udelay(1); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static ssize_t ad2s1210_show_pos_vel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_message msg; + unsigned short negative; + int ret = 0; + ssize_t len = 0; + u16 pos; + s16 vel; + struct iio_dev *idev = dev_get_drvdata(dev); + struct ad2s1210_state *st = idev->dev_data; + + st->xfer.len = 2; + mutex_lock(&st->lock); + start_sample(st); + /* delay (6 * tck + 20) nano seconds */ + udelay(1); + + set_mode(MOD_POS, st); + + spi_message_init(&msg); + spi_message_add_tail(&st->xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + pos = ((((u16)(st->rx[0])) << 8) | (st->rx[1])); + if (st->hysteresis) + pos >>= 16 - st->resolution; + len = sprintf(buf, "%d ", pos); + + st->xfer.len = 2; + set_mode(MOD_VEL, st); + spi_message_init(&msg); + spi_message_add_tail(&st->xfer, &msg); + ret = spi_sync(st->sdev, &msg); + if (ret) + goto error_ret; + negative = st->rx[0] & 0x80; + vel = ((((s16)(st->rx[0])) << 8) | (st->rx[1])); + vel >>= 16 - st->resolution; + if (negative) { + negative = (0xffff >> st->resolution) << st->resolution; + vel |= negative; + } + len += sprintf(buf + len, "%d\n", vel); +error_ret: + stop_sample(st); + /* delay (2 * tck + 20) nano seconds */ + udelay(1); + mutex_unlock(&st->lock); + + return ret ? ret : len; +} + +static IIO_CONST_ATTR(description, + "Variable Resolution, 10-Bit to 16Bit R/D\n\ +Converter with Reference Oscillator"); +static IIO_DEVICE_ATTR(raw_io, S_IRUGO | S_IWUGO, + ad2s1210_show_raw, ad2s1210_store_raw, 0); +static IIO_DEVICE_ATTR(reset, S_IWUGO, + NULL, ad2s1210_store_softreset, 0); +static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUGO, + ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); +static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUGO, + ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); +static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUGO, + ad2s1210_show_control, ad2s1210_store_control, 0); +static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUGO, + ad2s1210_show_resolution, ad2s1210_store_resolution, 0); +static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUGO, + ad2s1210_show_fault, ad2s1210_clear_fault, 0); +static IIO_DEVICE_ATTR(pos, S_IRUGO, + ad2s1210_show_pos, NULL, 0); +static IIO_DEVICE_ATTR(vel, S_IRUGO, + ad2s1210_show_vel, NULL, 0); +static IIO_DEVICE_ATTR(pos_vel, S_IRUGO, + ad2s1210_show_pos_vel, NULL, 0); +static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_LOS_THRD); +static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_OVR_THRD); +static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_MIS_THRD); +static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MAX_THRD); +static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MIN_THRD); +static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_HIGH_THRD); +static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUGO, + ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_LOW_THRD); + +static struct attribute *ad2s1210_attributes[] = { + &iio_const_attr_description.dev_attr.attr, + &iio_dev_attr_raw_io.dev_attr.attr, + &iio_dev_attr_reset.dev_attr.attr, + &iio_dev_attr_fclkin.dev_attr.attr, + &iio_dev_attr_fexcit.dev_attr.attr, + &iio_dev_attr_control.dev_attr.attr, + &iio_dev_attr_bits.dev_attr.attr, + &iio_dev_attr_fault.dev_attr.attr, + &iio_dev_attr_pos.dev_attr.attr, + &iio_dev_attr_vel.dev_attr.attr, + &iio_dev_attr_pos_vel.dev_attr.attr, + &iio_dev_attr_los_thrd.dev_attr.attr, + &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, + &iio_dev_attr_dos_mis_thrd.dev_attr.attr, + &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, + &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, + &iio_dev_attr_lot_high_thrd.dev_attr.attr, + &iio_dev_attr_lot_low_thrd.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s1210_attribute_group = { + .name = DRV_NAME, + .attrs = ad2s1210_attributes, +}; + +static int __devinit ad2s1210_initial(struct ad2s1210_state *st) +{ + unsigned char data; + int ret; + + mutex_lock(&st->lock); +#if defined(CONFIG_AD2S1210_GPIO_INPUT) + st->resolution = read_resolution_pin(st); +#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT) + set_resolution_pin(st); +#endif + + config_write(st, REG_CONTROL); + data = DEF_CONTROL & ~(SET_RESOLUTION); + data |= (st->resolution - RES_10) >> 1; + config_write(st, data); + ret = config_read(st, REG_CONTROL, &data); + if (ret) + goto error_ret; + + if (data & MSB_IS_HIGH) { + ret = -EIO; + goto error_ret; + } + + update_frequency_control_word(st); + soft_reset(st); +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static int __devinit ad2s1210_probe(struct spi_device *spi) +{ + struct ad2s1210_state *st; + int pn, ret = 0; + unsigned short *pins = spi->dev.platform_data; + + for (pn = 0; pn < AD2S1210_PN; pn++) { + if (gpio_request(pins[pn], DRV_NAME)) { + pr_err("%s: request gpio pin %d failed\n", + DRV_NAME, pins[pn]); + goto error_ret; + } + if (pn < AD2S1210_SAA) + gpio_direction_output(pins[pn], 1); + else { +#if defined(CONFIG_AD2S1210_GPIO_INPUT) + gpio_direction_input(pins[pn]); +#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT) + gpio_direction_output(pins[pn], 1); +#endif + } + } + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + spi_set_drvdata(spi, st); + + mutex_init(&st->lock); + st->sdev = spi; + st->xfer.tx_buf = st->tx; + st->xfer.rx_buf = st->rx; + st->hysteresis = 1; + st->mode = MOD_CONFIG; + st->resolution = RES_12; + st->fclkin = AD2S1210_DEF_CLKIN; + st->fexcit = AD2S1210_DEF_EXCIT; + st->sample = pins[0]; + st->a0 = pins[1]; + st->a1 = pins[2]; + st->res0 = pins[3]; + st->res1 = pins[4]; + + st->idev = iio_allocate_device(); + if (st->idev == NULL) { + ret = -ENOMEM; + goto error_free_st; + } + st->idev->dev.parent = &spi->dev; + st->idev->num_interrupt_lines = 0; + st->idev->event_attrs = NULL; + + st->idev->attrs = &ad2s1210_attribute_group; + st->idev->dev_data = (void *)(st); + st->idev->driver_module = THIS_MODULE; + st->idev->modes = INDIO_DIRECT_MODE; + + ret = iio_device_register(st->idev); + if (ret) + goto error_free_dev; + + if (spi->max_speed_hz != AD2S1210_DEF_CLKIN) + st->fclkin = spi->max_speed_hz; + spi->mode = SPI_MODE_3; + spi_setup(spi); + + ad2s1210_initial(st); + return 0; + +error_free_dev: + iio_free_device(st->idev); +error_free_st: + kfree(st); +error_ret: + for (--pn; pn >= 0; pn--) + gpio_free(pins[pn]); + return ret; +} + +static int __devexit ad2s1210_remove(struct spi_device *spi) +{ + struct ad2s1210_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->idev); + kfree(st); + + return 0; +} + +static struct spi_driver ad2s1210_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ad2s1210_probe, + .remove = __devexit_p(ad2s1210_remove), +}; + +static __init int ad2s1210_spi_init(void) +{ + return spi_register_driver(&ad2s1210_driver); +} +module_init(ad2s1210_spi_init); + +static __exit void ad2s1210_spi_exit(void) +{ + spi_unregister_driver(&ad2s1210_driver); +} +module_exit(ad2s1210_spi_exit); + +MODULE_AUTHOR("Graff Yang "); +MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From e1ffd62b8fc87e842431cc693821d7f1ac70b9de Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 27 Oct 2010 21:44:22 -0400 Subject: staging: iio: adis16209: tuning spi delay to make hardware more stable Looks like one spot was missed in the previous spi tune patch. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/accel/adis16209_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c index 033135c6f226..8eba0af98ed5 100644 --- a/drivers/staging/iio/accel/adis16209_ring.c +++ b/drivers/staging/iio/accel/adis16209_ring.c @@ -105,7 +105,7 @@ static int adis16209_read_ring_data(struct device *dev, u8 *rx) xfers[i].bits_per_word = 8; xfers[i].cs_change = 1; xfers[i].len = 2; - xfers[i].delay_usecs = 20; + xfers[i].delay_usecs = 30; xfers[i].tx_buf = st->tx + 2 * i; st->tx[2 * i] = ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i); -- cgit v1.2.3 From 8892384803af7082056fe29faef02fd0c762493e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Oct 2010 15:19:27 +0200 Subject: staging: get rid of dev_base_lock dev_base_lock was the legacy rwlock used to protect netdevice list, and is expected to vanish. We now use RTNL and RCU locking. Signed-off-by: Eric Dumazet Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlags49_h2/wl_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlags49_h2/wl_sysfs.c b/drivers/staging/wlags49_h2/wl_sysfs.c index e4c8804ac37d..9b833b30ae62 100644 --- a/drivers/staging/wlags49_h2/wl_sysfs.c +++ b/drivers/staging/wlags49_h2/wl_sysfs.c @@ -42,7 +42,7 @@ static ssize_t show_tallies(struct device *d, struct device_attribute *attr, CFG_HERMES_TALLIES_STRCT tallies; ssize_t ret = -EINVAL; - read_lock(&dev_base_lock); + rcu_read_lock(); if (dev_isalive(dev)) { wl_lock(lp, &flags); @@ -102,7 +102,7 @@ static ssize_t show_tallies(struct device *d, struct device_attribute *attr, } } - read_unlock(&dev_base_lock); + rcu_read_unlock(); return ret; } -- cgit v1.2.3 From cc8b59d41fa597bb62bdca2c200e8509bc8bec2a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 30 Oct 2010 14:08:38 -0700 Subject: Staging: solo6x10: Update WARN uses Add missing newlines. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/staging/solo6x10/solo6010-v4l2-enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c index 097e82bc7a63..2d05f3a148d0 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2-enc.c +++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c @@ -184,7 +184,7 @@ static void solo_update_mode(struct solo_enc_dev *solo_enc) solo_enc->bw_weight <<= 2; break; default: - WARN(1, "mode is unknown"); + WARN(1, "mode is unknown\n"); } } -- cgit v1.2.3 From fc4f55860254566b43e066bed0962c7cca72da84 Mon Sep 17 00:00:00 2001 From: Matias De la Puente Date: Fri, 29 Oct 2010 19:07:45 -0300 Subject: staging: vt6656: resolved checkpatch finding removed parentesis and spaces at the start of a line of a return Signed-off-by: Matias De la Puente Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c index 8de21aac1bff..a49053bd7c65 100644 --- a/drivers/staging/vt6656/card.c +++ b/drivers/staging/vt6656/card.c @@ -1092,7 +1092,7 @@ CARDbChannelSwitch ( pDevice->sMgmtObj.uCurrChannel = byNewChannel; bResult = CARDbSetMediaChannel(pDevice, byNewChannel); - return(bResult); + return bResult; } pDevice->byChannelSwitchCount = byCount; pDevice->byNewChannel = byNewChannel; -- cgit v1.2.3 From 4a499de2d13786de626c3f689022d7ec25230911 Mon Sep 17 00:00:00 2001 From: Mariano Reingart Date: Fri, 29 Oct 2010 19:15:26 -0300 Subject: staging: vt6656: resolved checkpatch finding removed a C99 '//' comment and added a space around '=' Signed-off-by: Mariano Reingart Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/rxtx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index bbdc127a987d..8f18578a5903 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -68,8 +68,7 @@ /*--------------------- Static Classes ----------------------------*/ /*--------------------- Static Variables --------------------------*/ -//static int msglevel =MSG_LEVEL_DEBUG; -static int msglevel =MSG_LEVEL_INFO; +static int msglevel = MSG_LEVEL_INFO; /*--------------------- Static Functions --------------------------*/ -- cgit v1.2.3 From 99b7bbb9b57da48f602732aaa107d7add49c842d Mon Sep 17 00:00:00 2001 From: Ariel Savini Date: Fri, 29 Oct 2010 19:19:20 -0300 Subject: staging: vt6656 resolved parenthesis not spaces removes before parenthesis Signed-off-by: Ariel Savini Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/tkip.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6656/tkip.c b/drivers/staging/vt6656/tkip.c index a6bd533f9577..0715636cb9cb 100644 --- a/drivers/staging/vt6656/tkip.c +++ b/drivers/staging/vt6656/tkip.c @@ -214,13 +214,14 @@ void TKIPvMixKey( /* Phase 1, step 2 */ for (i=0; i<8; i++) { j = 2*(i & 1); - p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536 )) % 65536; - p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536 )) % 65536; - p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536 )) % 65536; - p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536 )) % 65536; - p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536 )) % 65536; + p1k[0] = (p1k[0] + tkip_sbox((p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536)) % 65536; + p1k[1] = (p1k[1] + tkip_sbox((p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536)) % 65536; + p1k[2] = (p1k[2] + tkip_sbox((p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536)) % 65536; + p1k[3] = (p1k[3] + tkip_sbox((p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536)) % 65536; + p1k[4] = (p1k[4] + tkip_sbox((p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536)) % 65536; p1k[4] = (p1k[4] + i) % 65536; } + /* Phase 2, Step 1 */ ppk0 = p1k[0]; ppk1 = p1k[1]; @@ -230,19 +231,19 @@ void TKIPvMixKey( ppk5 = (p1k[4] + tsc2) % 65536; /* Phase2, Step 2 */ - ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536); - ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536); - ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536); - ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536); - ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536); - ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536); - - ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12])); - ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14])); - ppk2 = ppk2 + rotr1(ppk1); - ppk3 = ppk3 + rotr1(ppk2); - ppk4 = ppk4 + rotr1(ppk3); - ppk5 = ppk5 + rotr1(ppk4); + ppk0 = ppk0 + tkip_sbox((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536); + ppk1 = ppk1 + tkip_sbox((ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536); + ppk2 = ppk2 + tkip_sbox((ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536); + ppk3 = ppk3 + tkip_sbox((ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536); + ppk4 = ppk4 + tkip_sbox((ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536); + ppk5 = ppk5 + tkip_sbox((ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536); + + ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12])); + ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14])); + ppk2 = ppk2 + rotr1(ppk1); + ppk3 = ppk3 + rotr1(ppk2); + ppk4 = ppk4 + rotr1(ppk3); + ppk5 = ppk5 + rotr1(ppk4); /* Phase 2, Step 3 */ pbyRC4Key[0] = (tsc2 >> 8) % 256; -- cgit v1.2.3 From ba5c2b3ddcb7a6a0e942c7c2434f048d152f08c5 Mon Sep 17 00:00:00 2001 From: Felipe Andres Besoain Pino Date: Fri, 29 Oct 2010 19:15:58 -0300 Subject: staging: vt6656: resolved checkpatch finding removed spaces at the start of a lines. Signed-off-by: Felipe Andres Besoain Pino Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/dpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index 1f9d29636803..f4fb0c6e4eac 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -1608,8 +1608,8 @@ void RXvMngWorkItem(void *Context) } } - pDevice->bIsRxMngWorkItemQueued = FALSE; - spin_unlock_irq(&pDevice->lock); + pDevice->bIsRxMngWorkItemQueued = FALSE; + spin_unlock_irq(&pDevice->lock); } -- cgit v1.2.3 From 72ca8819f7f4ac4ddf82ab72ee614075821a3d00 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 1 Nov 2010 21:50:05 +0200 Subject: Staging: w35und: Merge wbhal_f.h to wbhal_s.h This patch merges HAL struct and function definitions into one header file. Acked-by: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mds.c | 3 +- drivers/staging/winbond/mto.c | 4 +- drivers/staging/winbond/phy_calibration.c | 4 +- drivers/staging/winbond/phy_calibration.h | 2 +- drivers/staging/winbond/reg.c | 4 +- drivers/staging/winbond/wb35reg_s.h | 74 ++++++++++++++++++++++++++++ drivers/staging/winbond/wb35tx_f.h | 1 - drivers/staging/winbond/wbhal_f.h | 81 ------------------------------- drivers/staging/winbond/wbusb.c | 5 +- 9 files changed, 90 insertions(+), 88 deletions(-) delete mode 100644 drivers/staging/winbond/wbhal_f.h (limited to 'drivers') diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 9217762b1814..2128e6e6ff5a 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -2,8 +2,9 @@ #include "mlmetxrx_f.h" #include "mto.h" #include "sysdef.h" -#include "wbhal_f.h" +#include "wbhal_s.h" #include "wblinux_f.h" +#include "wb35tx_f.h" unsigned char Mds_initial(struct wbsoft_priv *adapter) diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c index 9cd212783d61..05d12625dfcd 100644 --- a/drivers/staging/winbond/mto.c +++ b/drivers/staging/winbond/mto.c @@ -19,7 +19,9 @@ #include "sysdef.h" #include "sme_api.h" -#include "wbhal_f.h" +#include "wbhal_s.h" +#include "wb35reg_f.h" +#include "core.h" /* Declare SQ3 to rate and fragmentation threshold table */ /* Declare fragmentation thresholds table */ diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c index 2b375ba3812a..08cec74bdad7 100644 --- a/drivers/staging/winbond/phy_calibration.c +++ b/drivers/staging/winbond/phy_calibration.c @@ -12,7 +12,9 @@ /****************** INCLUDE FILES SECTION ***********************************/ #include "sysdef.h" #include "phy_calibration.h" -#include "wbhal_f.h" +#include "wbhal_s.h" +#include "wb35reg_f.h" +#include "core.h" /****************** DEBUG CONSTANT AND MACRO SECTION ************************/ diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h index 303203148839..9fcdab137cb3 100644 --- a/drivers/staging/winbond/phy_calibration.h +++ b/drivers/staging/winbond/phy_calibration.h @@ -1,7 +1,7 @@ #ifndef __WINBOND_PHY_CALIBRATION_H #define __WINBOND_PHY_CALIBRATION_H -#include "wbhal_f.h" +#include "wbhal_s.h" #define REG_AGC_CTRL1 0x1000 #define REG_AGC_CTRL2 0x1004 diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index 990f9d4bdbbd..8df05c4d26ff 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -1,5 +1,7 @@ #include "sysdef.h" -#include "wbhal_f.h" +#include "wbhal_s.h" +#include "wb35reg_f.h" +#include "core.h" /* * ==================================================== diff --git a/drivers/staging/winbond/wb35reg_s.h b/drivers/staging/winbond/wb35reg_s.h index 4eff009444b8..9d5993bfc1f4 100644 --- a/drivers/staging/winbond/wb35reg_s.h +++ b/drivers/staging/winbond/wb35reg_s.h @@ -5,6 +5,8 @@ #include #include +struct hw_data; + /* ========================================================================= * * HAL setting function @@ -168,4 +170,76 @@ struct wb35_reg { u32 SQ3_filter[MAX_SQ3_FILTER_SIZE]; u32 SQ3_index; }; + +/* ===================================================================== + * Function declaration + * ===================================================================== + */ +void hal_remove_mapping_key(struct hw_data *hw_data, u8 *mac_addr); +void hal_remove_default_key(struct hw_data *hw_data, u32 index); +unsigned char hal_set_mapping_key(struct hw_data *adapter, u8 *mac_addr, + u8 null_key, u8 wep_on, u8 *tx_tsc, + u8 *rx_tsc, u8 key_type, u8 key_len, + u8 *key_data); +unsigned char hal_set_default_key(struct hw_data *adapter, u8 index, + u8 null_key, u8 wep_on, u8 *tx_tsc, + u8 *rx_tsc, u8 key_type, u8 key_len, + u8 *key_data); +void hal_clear_all_default_key(struct hw_data *hw_data); +void hal_clear_all_group_key(struct hw_data *hw_data); +void hal_clear_all_mapping_key(struct hw_data *hw_data); +void hal_clear_all_key(struct hw_data *hw_data); +void hal_set_power_save_mode(struct hw_data *hw_data, unsigned char power_save, + unsigned char wakeup, unsigned char dtim); +void hal_get_power_save_mode(struct hw_data *hw_data, u8 *in_pwr_save); +void hal_set_slot_time(struct hw_data *hw_data, u8 type); + +#define hal_set_atim_window(_A, _ATM) + +void hal_start_bss(struct hw_data *hw_data, u8 mac_op_mode); + +/* 0:BSS STA 1:IBSS STA */ +void hal_join_request(struct hw_data *hw_data, u8 bss_type); + +void hal_stop_sync_bss(struct hw_data *hw_data); +void hal_resume_sync_bss(struct hw_data *hw_data); +void hal_set_aid(struct hw_data *hw_data, u16 aid); +void hal_set_bssid(struct hw_data *hw_data, u8 *bssid); +void hal_get_bssid(struct hw_data *hw_data, u8 *bssid); +void hal_set_listen_interval(struct hw_data *hw_data, u16 listen_interval); +void hal_set_cap_info(struct hw_data *hw_data, u16 capability_info); +void hal_set_ssid(struct hw_data *hw_data, u8 *ssid, u8 ssid_len); +void hal_start_tx0(struct hw_data *hw_data); + +#define hal_get_cwmin(_A) ((_A)->cwmin) + +void hal_set_cwmax(struct hw_data *hw_data, u16 cwin_max); + +#define hal_get_cwmax(_A) ((_A)->cwmax) + +void hal_set_rsn_wpa(struct hw_data *hw_data, u32 *rsn_ie_bitmap, + u32 *rsn_oui_type , unsigned char desired_auth_mode); +void hal_set_connect_info(struct hw_data *hw_data, unsigned char bo_connect); +u8 hal_get_est_sq3(struct hw_data *hw_data, u8 count); +void hal_descriptor_indicate(struct hw_data *hw_data, + struct wb35_descriptor *des); +u8 hal_get_antenna_number(struct hw_data *hw_data); +u32 hal_get_bss_pk_cnt(struct hw_data *hw_data); + +#define hal_get_region_from_EEPROM(_A) ((_A)->reg.EEPROMRegion) +#define hal_get_tx_buffer(_A, _B) Wb35Tx_get_tx_buffer(_A, _B) +#define hal_software_set(_A) (_A->SoftwareSet) +#define hal_driver_init_OK(_A) (_A->IsInitOK) +#define hal_rssi_boundary_high(_A) (_A->RSSI_high) +#define hal_rssi_boundary_low(_A) (_A->RSSI_low) +#define hal_scan_interval(_A) (_A->Scan_Interval) + +#define PHY_DEBUG(msg, args...) + +/* return 100ms count */ +#define hal_get_time_count(_P) (_P->time_count / 10) +#define hal_detect_error(_P) (_P->WbUsb.DetectCount) + +#define hal_ibss_disconnect(_A) (hal_stop_sync_bss(_A)) + #endif diff --git a/drivers/staging/winbond/wb35tx_f.h b/drivers/staging/winbond/wb35tx_f.h index 1d3b515f83bc..018fd35e815d 100644 --- a/drivers/staging/winbond/wb35tx_f.h +++ b/drivers/staging/winbond/wb35tx_f.h @@ -2,7 +2,6 @@ #define __WINBOND_WB35TX_F_H #include "core.h" -#include "wbhal_f.h" /* * ==================================== diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h deleted file mode 100644 index fc78c14ae583..000000000000 --- a/drivers/staging/winbond/wbhal_f.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ===================================================================== - * Device related include - * ===================================================================== -*/ -#include "wb35reg_f.h" -#include "wb35tx_f.h" -#include "wb35rx_f.h" - -#include "core.h" - -/* ===================================================================== - * Function declaration - * ===================================================================== - */ -void hal_remove_mapping_key(struct hw_data *hw_data, u8 *mac_addr); -void hal_remove_default_key(struct hw_data *hw_data, u32 index); -unsigned char hal_set_mapping_key(struct hw_data *adapter, u8 *mac_addr, - u8 null_key, u8 wep_on, u8 *tx_tsc, - u8 *rx_tsc, u8 key_type, u8 key_len, - u8 *key_data); -unsigned char hal_set_default_key(struct hw_data *adapter, u8 index, - u8 null_key, u8 wep_on, u8 *tx_tsc, - u8 *rx_tsc, u8 key_type, u8 key_len, - u8 *key_data); -void hal_clear_all_default_key(struct hw_data *hw_data); -void hal_clear_all_group_key(struct hw_data *hw_data); -void hal_clear_all_mapping_key(struct hw_data *hw_data); -void hal_clear_all_key(struct hw_data *hw_data); -void hal_set_power_save_mode(struct hw_data *hw_data, unsigned char power_save, - unsigned char wakeup, unsigned char dtim); -void hal_get_power_save_mode(struct hw_data *hw_data, u8 *in_pwr_save); -void hal_set_slot_time(struct hw_data *hw_data, u8 type); - -#define hal_set_atim_window(_A, _ATM) - -void hal_start_bss(struct hw_data *hw_data, u8 mac_op_mode); - -/* 0:BSS STA 1:IBSS STA */ -void hal_join_request(struct hw_data *hw_data, u8 bss_type); - -void hal_stop_sync_bss(struct hw_data *hw_data); -void hal_resume_sync_bss(struct hw_data *hw_data); -void hal_set_aid(struct hw_data *hw_data, u16 aid); -void hal_set_bssid(struct hw_data *hw_data, u8 *bssid); -void hal_get_bssid(struct hw_data *hw_data, u8 *bssid); -void hal_set_listen_interval(struct hw_data *hw_data, u16 listen_interval); -void hal_set_cap_info(struct hw_data *hw_data, u16 capability_info); -void hal_set_ssid(struct hw_data *hw_data, u8 *ssid, u8 ssid_len); -void hal_start_tx0(struct hw_data *hw_data); - -#define hal_get_cwmin(_A) ((_A)->cwmin) - -void hal_set_cwmax(struct hw_data *hw_data, u16 cwin_max); - -#define hal_get_cwmax(_A) ((_A)->cwmax) - -void hal_set_rsn_wpa(struct hw_data *hw_data, u32 *rsn_ie_bitmap, - u32 *rsn_oui_type , unsigned char desired_auth_mode); -void hal_set_connect_info(struct hw_data *hw_data, unsigned char bo_connect); -u8 hal_get_est_sq3(struct hw_data *hw_data, u8 count); -void hal_descriptor_indicate(struct hw_data *hw_data, - struct wb35_descriptor *des); -u8 hal_get_antenna_number(struct hw_data *hw_data); -u32 hal_get_bss_pk_cnt(struct hw_data *hw_data); - -#define hal_get_region_from_EEPROM(_A) ((_A)->reg.EEPROMRegion) -#define hal_get_tx_buffer(_A, _B) Wb35Tx_get_tx_buffer(_A, _B) -#define hal_software_set(_A) (_A->SoftwareSet) -#define hal_driver_init_OK(_A) (_A->IsInitOK) -#define hal_rssi_boundary_high(_A) (_A->RSSI_high) -#define hal_rssi_boundary_low(_A) (_A->RSSI_low) -#define hal_scan_interval(_A) (_A->Scan_Interval) - -#define PHY_DEBUG(msg, args...) - -/* return 100ms count */ -#define hal_get_time_count(_P) (_P->time_count / 10) -#define hal_detect_error(_P) (_P->WbUsb.DetectCount) - -#define hal_ibss_disconnect(_A) (hal_stop_sync_bss(_A)) diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 3f60cf7e6ec1..a053bbb39610 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -16,7 +16,10 @@ #include "mds_f.h" #include "mlmetxrx_f.h" #include "mto.h" -#include "wbhal_f.h" +#include "wbhal_s.h" +#include "wb35reg_f.h" +#include "wb35tx_f.h" +#include "wb35rx_f.h" #include "wblinux_f.h" MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver"); -- cgit v1.2.3 From b5ef076141acc223e55aa298abd2d2f5fb844874 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 1 Nov 2010 21:50:06 +0200 Subject: Staging: w35und: Rename wbhal_s.h to wbhal.h This patch renames the wbhal_s.h header file to wbhal.h now that it contains both structure and function definitions. Acked-by: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/core.h | 2 +- drivers/staging/winbond/mds.c | 2 +- drivers/staging/winbond/mds_f.h | 2 +- drivers/staging/winbond/mto.c | 2 +- drivers/staging/winbond/phy_calibration.c | 2 +- drivers/staging/winbond/phy_calibration.h | 2 +- drivers/staging/winbond/reg.c | 2 +- drivers/staging/winbond/wb35reg_f.h | 2 +- drivers/staging/winbond/wb35rx_f.h | 2 +- drivers/staging/winbond/wbhal.h | 525 ++++++++++++++++++++++++++++++ drivers/staging/winbond/wbhal_s.h | 525 ------------------------------ drivers/staging/winbond/wbusb.c | 2 +- 12 files changed, 535 insertions(+), 535 deletions(-) create mode 100644 drivers/staging/winbond/wbhal.h delete mode 100644 drivers/staging/winbond/wbhal_s.h (limited to 'drivers') diff --git a/drivers/staging/winbond/core.h b/drivers/staging/winbond/core.h index 2b87a0007319..d7b3aca5ddeb 100644 --- a/drivers/staging/winbond/core.h +++ b/drivers/staging/winbond/core.h @@ -4,7 +4,7 @@ #include #include -#include "wbhal_s.h" +#include "wbhal.h" #include "mto.h" #include "mac_structures.h" diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 2128e6e6ff5a..9ac2c874ef05 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -2,7 +2,7 @@ #include "mlmetxrx_f.h" #include "mto.h" #include "sysdef.h" -#include "wbhal_s.h" +#include "wbhal.h" #include "wblinux_f.h" #include "wb35tx_f.h" diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h index 7f68deae6d04..d902843e8aed 100644 --- a/drivers/staging/winbond/mds_f.h +++ b/drivers/staging/winbond/mds_f.h @@ -1,7 +1,7 @@ #ifndef __WINBOND_MDS_F_H #define __WINBOND_MDS_F_H -#include "wbhal_s.h" +#include "wbhal.h" #include "core.h" unsigned char Mds_initial(struct wbsoft_priv *adapter); diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c index 05d12625dfcd..1faebceceff7 100644 --- a/drivers/staging/winbond/mto.c +++ b/drivers/staging/winbond/mto.c @@ -19,7 +19,7 @@ #include "sysdef.h" #include "sme_api.h" -#include "wbhal_s.h" +#include "wbhal.h" #include "wb35reg_f.h" #include "core.h" diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c index 08cec74bdad7..0658b09c7853 100644 --- a/drivers/staging/winbond/phy_calibration.c +++ b/drivers/staging/winbond/phy_calibration.c @@ -12,7 +12,7 @@ /****************** INCLUDE FILES SECTION ***********************************/ #include "sysdef.h" #include "phy_calibration.h" -#include "wbhal_s.h" +#include "wbhal.h" #include "wb35reg_f.h" #include "core.h" diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h index 9fcdab137cb3..84f6e840a47a 100644 --- a/drivers/staging/winbond/phy_calibration.h +++ b/drivers/staging/winbond/phy_calibration.h @@ -1,7 +1,7 @@ #ifndef __WINBOND_PHY_CALIBRATION_H #define __WINBOND_PHY_CALIBRATION_H -#include "wbhal_s.h" +#include "wbhal.h" #define REG_AGC_CTRL1 0x1000 #define REG_AGC_CTRL2 0x1004 diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index 8df05c4d26ff..439d213fe951 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -1,5 +1,5 @@ #include "sysdef.h" -#include "wbhal_s.h" +#include "wbhal.h" #include "wb35reg_f.h" #include "core.h" diff --git a/drivers/staging/winbond/wb35reg_f.h b/drivers/staging/winbond/wb35reg_f.h index bf23c1084199..95dc98096845 100644 --- a/drivers/staging/winbond/wb35reg_f.h +++ b/drivers/staging/winbond/wb35reg_f.h @@ -1,7 +1,7 @@ #ifndef __WINBOND_WB35REG_F_H #define __WINBOND_WB35REG_F_H -#include "wbhal_s.h" +#include "wbhal.h" /* * ==================================== diff --git a/drivers/staging/winbond/wb35rx_f.h b/drivers/staging/winbond/wb35rx_f.h index 98acce517d90..1fdf65ea6041 100644 --- a/drivers/staging/winbond/wb35rx_f.h +++ b/drivers/staging/winbond/wb35rx_f.h @@ -2,7 +2,7 @@ #define __WINBOND_WB35RX_F_H #include -#include "wbhal_s.h" +#include "wbhal.h" //==================================== // Interface function declare diff --git a/drivers/staging/winbond/wbhal.h b/drivers/staging/winbond/wbhal.h new file mode 100644 index 000000000000..821a1b3f1301 --- /dev/null +++ b/drivers/staging/winbond/wbhal.h @@ -0,0 +1,525 @@ +#ifndef __WINBOND_WBHAL_S_H +#define __WINBOND_WBHAL_S_H + +#include +#include /* for ETH_ALEN */ + +#define HAL_LED_SET_MASK 0x001c +#define HAL_LED_SET_SHIFT 2 + +/* supported RF type */ +#define RF_MAXIM_2825 0 +#define RF_MAXIM_2827 1 +#define RF_MAXIM_2828 2 +#define RF_MAXIM_2829 3 +#define RF_MAXIM_V1 15 +#define RF_AIROHA_2230 16 +#define RF_AIROHA_7230 17 +#define RF_AIROHA_2230S 18 +#define RF_WB_242 33 +#define RF_WB_242_1 34 +#define RF_DECIDE_BY_INF 255 + +/* + * ---------------------------------------------------------------- + * The follow define connect to upper layer + * User must modify for connection between HAL and upper layer + * ---------------------------------------------------------------- + */ + +/* + * ============================== + * Common define + * ============================== + */ +/* Bit 5 */ +#define HAL_USB_MODE_BURST(_H) (_H->SoftwareSet & 0x20) + +/* Scan interval */ +#define SCAN_MAX_CHNL_TIME (50) + +/* For TxL2 Frame typr recognise */ +#define FRAME_TYPE_802_3_DATA 0 +#define FRAME_TYPE_802_11_MANAGEMENT 1 +#define FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE 2 +#define FRAME_TYPE_802_11_CONTROL 3 +#define FRAME_TYPE_802_11_DATA 4 +#define FRAME_TYPE_PROMISCUOUS 5 + +/* The follow definition is used for convert the frame------------ */ +#define DOT_11_SEQUENCE_OFFSET 22 /* Sequence control offset */ +#define DOT_3_TYPE_OFFSET 12 +#define DOT_11_MAC_HEADER_SIZE 24 +#define DOT_11_SNAP_SIZE 6 +#define DOT_11_TYPE_OFFSET 30 /* The start offset of 802.11 Frame. Type encapsulation. */ +#define DEFAULT_SIFSTIME 10 +#define DEFAULT_FRAGMENT_THRESHOLD 2346 /* No fragment */ +#define DEFAULT_MSDU_LIFE_TIME 0xffff + +#define LONG_PREAMBLE_PLUS_PLCPHEADER_TIME (144 + 48) +#define SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME (72 + 24) +#define PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION (16 + 4 + 6) +#define Tsym 4 + +/* Frame Type of Bits (2, 3)----------------------------------- */ +#define MAC_TYPE_MANAGEMENT 0x00 +#define MAC_TYPE_CONTROL 0x04 +#define MAC_TYPE_DATA 0x08 +#define MASK_FRAGMENT_NUMBER 0x000F +#define SEQUENCE_NUMBER_SHIFT 4 + +#define HAL_WOL_TYPE_WAKEUP_FRAME 0x01 +#define HAL_WOL_TYPE_MAGIC_PACKET 0x02 + +#define HAL_KEYTYPE_WEP40 0 +#define HAL_KEYTYPE_WEP104 1 +#define HAL_KEYTYPE_TKIP 2 /* 128 bit key */ +#define HAL_KEYTYPE_AES_CCMP 3 /* 128 bit key */ + +/* For VM state */ +enum { + VM_STOP = 0, + VM_RUNNING, + VM_COMPLETED +}; + +/* + * ================================ + * Normal Key table format + * ================================ + */ + +/* The order of KEY index is MAPPING_KEY_START_INDEX > GROUP_KEY_START_INDEX */ +#define MAX_KEY_TABLE 24 /* 24 entry for storing key data */ +#define GROUP_KEY_START_INDEX 4 +#define MAPPING_KEY_START_INDEX 8 + +/* + * ========================================= + * Descriptor + * ========================================= + */ +#define MAX_DESCRIPTOR_BUFFER_INDEX 8 /* Have to multiple of 2 */ +#define FLAG_ERROR_TX_MASK 0x000000bf +#define FLAG_ERROR_RX_MASK 0x0000083f + +#define FLAG_BAND_RX_MASK 0x10000000 /* Bit 28 */ + +struct R00_descriptor { + union { + u32 value; +#ifdef _BIG_ENDIAN_ + struct { + u32 R00_packet_or_buffer_status:1; + u32 R00_packet_in_fifo:1; + u32 R00_RESERVED:2; + u32 R00_receive_byte_count:12; + u32 R00_receive_time_index:16; + }; +#else + struct { + u32 R00_receive_time_index:16; + u32 R00_receive_byte_count:12; + u32 R00_RESERVED:2; + u32 R00_packet_in_fifo:1; + u32 R00_packet_or_buffer_status:1; + }; +#endif + }; +}; + +struct T00_descriptor { + union { + u32 value; +#ifdef _BIG_ENDIAN_ + struct { + u32 T00_first_mpdu:1; /* for hardware use */ + u32 T00_last_mpdu:1; /* for hardware use */ + u32 T00_IsLastMpdu:1;/* 0:not 1:Yes for software used */ + u32 T00_IgnoreResult:1;/* The same mechanism with T00 setting. */ + u32 T00_RESERVED_ID:2;/* 3 bit ID reserved */ + u32 T00_tx_packet_id:4; + u32 T00_RESERVED:4; + u32 T00_header_length:6; + u32 T00_frame_length:12; + }; +#else + struct { + u32 T00_frame_length:12; + u32 T00_header_length:6; + u32 T00_RESERVED:4; + u32 T00_tx_packet_id:4; + u32 T00_RESERVED_ID:2; /* 3 bit ID reserved */ + u32 T00_IgnoreResult:1; /* The same mechanism with T00 setting. */ + u32 T00_IsLastMpdu:1; /* 0:not 1:Yes for software used */ + u32 T00_last_mpdu:1; /* for hardware use */ + u32 T00_first_mpdu:1; /* for hardware use */ + }; +#endif + }; +}; + +struct R01_descriptor { + union { + u32 value; +#ifdef _BIG_ENDIAN_ + struct { + u32 R01_RESERVED:3; + u32 R01_mod_type:1; + u32 R01_pre_type:1; + u32 R01_data_rate:3; + u32 R01_AGC_state:8; + u32 R01_LNA_state:2; + u32 R01_decryption_method:2; + u32 R01_mic_error:1; + u32 R01_replay:1; + u32 R01_broadcast_frame:1; + u32 R01_multicast_frame:1; + u32 R01_directed_frame:1; + u32 R01_receive_frame_antenna_selection:1; + u32 R01_frame_receive_during_atim_window:1; + u32 R01_protocol_version_error:1; + u32 R01_authentication_frame_icv_error:1; + u32 R01_null_key_to_authentication_frame:1; + u32 R01_icv_error:1; + u32 R01_crc_error:1; + }; +#else + struct { + u32 R01_crc_error:1; + u32 R01_icv_error:1; + u32 R01_null_key_to_authentication_frame:1; + u32 R01_authentication_frame_icv_error:1; + u32 R01_protocol_version_error:1; + u32 R01_frame_receive_during_atim_window:1; + u32 R01_receive_frame_antenna_selection:1; + u32 R01_directed_frame:1; + u32 R01_multicast_frame:1; + u32 R01_broadcast_frame:1; + u32 R01_replay:1; + u32 R01_mic_error:1; + u32 R01_decryption_method:2; + u32 R01_LNA_state:2; + u32 R01_AGC_state:8; + u32 R01_data_rate:3; + u32 R01_pre_type:1; + u32 R01_mod_type:1; + u32 R01_RESERVED:3; + }; +#endif + }; +}; + +struct T01_descriptor { + union { + u32 value; +#ifdef _BIG_ENDIAN_ + struct { + u32 T01_rts_cts_duration:16; + u32 T01_fall_back_rate:3; + u32 T01_add_rts:1; + u32 T01_add_cts:1; + u32 T01_modulation_type:1; + u32 T01_plcp_header_length:1; + u32 T01_transmit_rate:3; + u32 T01_wep_id:2; + u32 T01_add_challenge_text:1; + u32 T01_inhibit_crc:1; + u32 T01_loop_back_wep_mode:1; + u32 T01_retry_abort_ebable:1; + }; +#else + struct { + u32 T01_retry_abort_ebable:1; + u32 T01_loop_back_wep_mode:1; + u32 T01_inhibit_crc:1; + u32 T01_add_challenge_text:1; + u32 T01_wep_id:2; + u32 T01_transmit_rate:3; + u32 T01_plcp_header_length:1; + u32 T01_modulation_type:1; + u32 T01_add_cts:1; + u32 T01_add_rts:1; + u32 T01_fall_back_rate:3; + u32 T01_rts_cts_duration:16; + }; +#endif + }; +}; + +struct T02_descriptor { + union { + u32 value; +#ifdef _BIG_ENDIAN_ + struct { + u32 T02_IsLastMpdu:1; /* The same mechanism with T00 setting */ + u32 T02_IgnoreResult:1; /* The same mechanism with T00 setting. */ + u32 T02_RESERVED_ID:2; /* The same mechanism with T00 setting */ + u32 T02_Tx_PktID:4; + u32 T02_MPDU_Cnt:4; + u32 T02_RTS_Cnt:4; + u32 T02_RESERVED:7; + u32 T02_transmit_complete:1; + u32 T02_transmit_abort_due_to_TBTT:1; + u32 T02_effective_transmission_rate:1; + u32 T02_transmit_without_encryption_due_to_wep_on_false:1; + u32 T02_discard_due_to_null_wep_key:1; + u32 T02_RESERVED_1:1; + u32 T02_out_of_MaxTxMSDULiftTime:1; + u32 T02_transmit_abort:1; + u32 T02_transmit_fail:1; + }; +#else + struct { + u32 T02_transmit_fail:1; + u32 T02_transmit_abort:1; + u32 T02_out_of_MaxTxMSDULiftTime:1; + u32 T02_RESERVED_1:1; + u32 T02_discard_due_to_null_wep_key:1; + u32 T02_transmit_without_encryption_due_to_wep_on_false:1; + u32 T02_effective_transmission_rate:1; + u32 T02_transmit_abort_due_to_TBTT:1; + u32 T02_transmit_complete:1; + u32 T02_RESERVED:7; + u32 T02_RTS_Cnt:4; + u32 T02_MPDU_Cnt:4; + u32 T02_Tx_PktID:4; + u32 T02_RESERVED_ID:2; /* The same mechanism with T00 setting */ + u32 T02_IgnoreResult:1; /* The same mechanism with T00 setting. */ + u32 T02_IsLastMpdu:1; /* The same mechanism with T00 setting */ + }; +#endif + }; +}; + +struct wb35_descriptor { /* Skip length = 8 DWORD */ + /* ID for descriptor ---, The field doesn't be cleard in the operation of Descriptor definition */ + u8 Descriptor_ID; + /* ----------------------The above region doesn't be cleared by DESCRIPTOR_RESET------ */ + u8 RESERVED[3]; + + u16 FragmentThreshold; + u8 InternalUsed; /* Only can be used by operation of descriptor definition */ + u8 Type; /* 0: 802.3 1:802.11 data frame 2:802.11 management frame */ + + u8 PreambleMode;/* 0: short 1:long */ + u8 TxRate; + u8 FragmentCount; + u8 EapFix; /* For speed up key install */ + + /* For R00 and T00 ------------------------------ */ + union { + struct R00_descriptor R00; + struct T00_descriptor T00; + }; + + /* For R01 and T01 ------------------------------ */ + union { + struct R01_descriptor R01; + struct T01_descriptor T01; + }; + + /* For R02 and T02 ------------------------------ */ + union { + u32 R02; + struct T02_descriptor T02; + }; + + /* For R03 and T03 ------------------------------ */ + /* For software used */ + union { + u32 R03; + u32 T03; + struct { + u8 buffer_number; + u8 buffer_start_index; + u16 buffer_total_size; + }; + }; + + /* For storing the buffer */ + u16 buffer_size[MAX_DESCRIPTOR_BUFFER_INDEX]; + void *buffer_address[MAX_DESCRIPTOR_BUFFER_INDEX]; +}; + + +#define DEFAULT_NULL_PACKET_COUNT 180000 /* 180 seconds */ + +#define MAX_TXVGA_EEPROM 9 /* How many word(u16) of EEPROM will be used for TxVGA */ +#define MAX_RF_PARAMETER 32 + +struct txvga_for_50 { + u8 ChanNo; + u8 TxVgaValue; +}; + +/* + * ============================================== + * Device related include + * ============================================== + */ + +#include "wbusb_s.h" +#include "wb35reg_s.h" +#include "wb35tx_s.h" +#include "wb35rx_s.h" + +/* For Hal using ============================================ */ +struct hw_data { + /* For compatible with 33 */ + u32 revision; + u32 BB3c_cal; /* The value for Tx calibration comes from EEPROM */ + u32 BB54_cal; /* The value for Rx calibration comes from EEPROM */ + + /* For surprise remove */ + u32 SurpriseRemove; /* 0: Normal 1: Surprise remove */ + u8 IsKeyPreSet; + u8 CalOneTime; + + u8 VCO_trim; + + u32 FragCount; + u32 DMAFix; /* V1_DMA_FIX The variable can be removed if driver want to save mem space for V2. */ + + /* + * =============================================== + * Definition for MAC address + * =============================================== + */ + u8 PermanentMacAddress[ETH_ALEN + 2]; /* The Ethernet addr that are stored in EEPROM. + 2 to 8-byte alignment */ + u8 CurrentMacAddress[ETH_ALEN + 2]; /* The Enthernet addr that are in used. + 2 to 8-byte alignment */ + + /* + * ========================================= + * Definition for 802.11 + * ========================================= + */ + u8 *bssid_pointer; /* Used by hal_get_bssid for return value */ + u8 bssid[8]; /* Only 6 byte will be used. 8 byte is required for read buffer */ + u8 ssid[32]; /* maximum ssid length is 32 byte */ + + u16 AID; + u8 ssid_length; + u8 Channel; + + u16 ListenInterval; + u16 CapabilityInformation; + + u16 BeaconPeriod; + u16 ProbeDelay; + + u8 bss_type;/* 0: IBSS_NET or 1:ESS_NET */ + u8 preamble;/* 0: short preamble, 1: long preamble */ + u8 slot_time_select; /* 9 or 20 value */ + u8 phy_type; /* Phy select */ + + u32 phy_para[MAX_RF_PARAMETER]; + u32 phy_number; + + u32 CurrentRadioSw; /* 0:On 1:Off */ + u32 CurrentRadioHw; /* 0:On 1:Off */ + + u8 *power_save_point; /* Used by hal_get_power_save_mode for return value */ + u8 cwmin; + u8 desired_power_save; + u8 dtim; /* Is running dtim */ + u8 mapping_key_replace_index; /* In Key table, the next index be replaced */ + + u16 MaxReceiveLifeTime; + u16 FragmentThreshold; + u16 FragmentThreshold_tmp; + u16 cwmax; + + u8 Key_slot[MAX_KEY_TABLE][8]; /* Ownership record for key slot. For Alignment */ + u32 Key_content[MAX_KEY_TABLE][12]; /* 10DW for each entry + 2 for burst command (Off and On valid bit) */ + u8 CurrentDefaultKeyIndex; + u32 CurrentDefaultKeyLength; + + /* + * ================================================== + * Variable for each module + * ================================================== + */ + struct wb_usb WbUsb; /* Need WbUsb.h */ + struct wb35_reg reg; /* Need Wb35Reg.h */ + struct wb35_tx Wb35Tx; /* Need Wb35Tx.h */ + struct wb35_rx Wb35Rx; /* Need Wb35Rx.h */ + + struct timer_list LEDTimer; /* For LED */ + + u32 LEDpoint; /* For LED */ + + u32 dto_tx_retry_count; + u32 dto_tx_frag_count; + u32 rx_ok_count[13]; /* index=0: total rx ok */ + u32 rx_err_count[13]; /* index=0: total rx err */ + + /* for Tx debug */ + u32 tx_TBTT_start_count; + u32 tx_ETR_count; + u32 tx_WepOn_false_count; + u32 tx_Null_key_count; + u32 tx_retry_count[8]; + + u8 PowerIndexFromEEPROM; /* For 2412MHz */ + u8 power_index; + u8 IsWaitJoinComplete; /* TRUE: set join request */ + u8 band; + + u16 SoftwareSet; + u16 Reserved_s; + + u32 IsInitOK; /* 0: Driver starting 1: Driver init OK */ + + /* For Phy calibration */ + s32 iq_rsdl_gain_tx_d2; + s32 iq_rsdl_phase_tx_d2; + u32 txvga_setting_for_cal; + + u8 TxVgaSettingInEEPROM[(((MAX_TXVGA_EEPROM * 2) + 3) & ~0x03)]; /* For EEPROM value */ + u8 TxVgaFor24[16]; /* Max is 14, 2 for alignment */ + struct txvga_for_50 TxVgaFor50[36]; /* 35 channels in 5G. 35x2 = 70 byte. 2 for alignments */ + + u16 Scan_Interval; + u16 RESERVED6; + + /* LED control */ + u32 LED_control; + /* + * LED_control 4 byte: Gray_Led_1[3] Gray_Led_0[2] Led[1] Led[0] + * Gray_Led + * For Led gray setting + * Led + * 0: normal control, + * LED behavior will decide by EEPROM setting + * 1: Turn off specific LED + * 2: Always on specific LED + * 3: slow blinking specific LED + * 4: fast blinking specific LED + * 5: WPS led control is set. Led0 is Red, Led1 id Green + * + * Led[1] is parameter for WPS LED mode + * 1:InProgress + * 2: Error + * 3: Session overlap + * 4: Success control + */ + u32 LED_LinkOn; /* Turn LED on control */ + u32 LED_Scanning; /* Let LED in scan process control */ + u32 LED_Blinking; /* Temp variable for shining */ + u32 RxByteCountLast; + u32 TxByteCountLast; + + atomic_t SurpriseRemoveCount; + + /* For global timer */ + u32 time_count; /* TICK_TIME_100ms 1 = 100ms */ + + /* For error recover */ + u32 HwStop; + + /* For avoid AP disconnect */ + u32 NullPacketCount; +}; + +#endif diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal_s.h deleted file mode 100644 index 821a1b3f1301..000000000000 --- a/drivers/staging/winbond/wbhal_s.h +++ /dev/null @@ -1,525 +0,0 @@ -#ifndef __WINBOND_WBHAL_S_H -#define __WINBOND_WBHAL_S_H - -#include -#include /* for ETH_ALEN */ - -#define HAL_LED_SET_MASK 0x001c -#define HAL_LED_SET_SHIFT 2 - -/* supported RF type */ -#define RF_MAXIM_2825 0 -#define RF_MAXIM_2827 1 -#define RF_MAXIM_2828 2 -#define RF_MAXIM_2829 3 -#define RF_MAXIM_V1 15 -#define RF_AIROHA_2230 16 -#define RF_AIROHA_7230 17 -#define RF_AIROHA_2230S 18 -#define RF_WB_242 33 -#define RF_WB_242_1 34 -#define RF_DECIDE_BY_INF 255 - -/* - * ---------------------------------------------------------------- - * The follow define connect to upper layer - * User must modify for connection between HAL and upper layer - * ---------------------------------------------------------------- - */ - -/* - * ============================== - * Common define - * ============================== - */ -/* Bit 5 */ -#define HAL_USB_MODE_BURST(_H) (_H->SoftwareSet & 0x20) - -/* Scan interval */ -#define SCAN_MAX_CHNL_TIME (50) - -/* For TxL2 Frame typr recognise */ -#define FRAME_TYPE_802_3_DATA 0 -#define FRAME_TYPE_802_11_MANAGEMENT 1 -#define FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE 2 -#define FRAME_TYPE_802_11_CONTROL 3 -#define FRAME_TYPE_802_11_DATA 4 -#define FRAME_TYPE_PROMISCUOUS 5 - -/* The follow definition is used for convert the frame------------ */ -#define DOT_11_SEQUENCE_OFFSET 22 /* Sequence control offset */ -#define DOT_3_TYPE_OFFSET 12 -#define DOT_11_MAC_HEADER_SIZE 24 -#define DOT_11_SNAP_SIZE 6 -#define DOT_11_TYPE_OFFSET 30 /* The start offset of 802.11 Frame. Type encapsulation. */ -#define DEFAULT_SIFSTIME 10 -#define DEFAULT_FRAGMENT_THRESHOLD 2346 /* No fragment */ -#define DEFAULT_MSDU_LIFE_TIME 0xffff - -#define LONG_PREAMBLE_PLUS_PLCPHEADER_TIME (144 + 48) -#define SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME (72 + 24) -#define PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION (16 + 4 + 6) -#define Tsym 4 - -/* Frame Type of Bits (2, 3)----------------------------------- */ -#define MAC_TYPE_MANAGEMENT 0x00 -#define MAC_TYPE_CONTROL 0x04 -#define MAC_TYPE_DATA 0x08 -#define MASK_FRAGMENT_NUMBER 0x000F -#define SEQUENCE_NUMBER_SHIFT 4 - -#define HAL_WOL_TYPE_WAKEUP_FRAME 0x01 -#define HAL_WOL_TYPE_MAGIC_PACKET 0x02 - -#define HAL_KEYTYPE_WEP40 0 -#define HAL_KEYTYPE_WEP104 1 -#define HAL_KEYTYPE_TKIP 2 /* 128 bit key */ -#define HAL_KEYTYPE_AES_CCMP 3 /* 128 bit key */ - -/* For VM state */ -enum { - VM_STOP = 0, - VM_RUNNING, - VM_COMPLETED -}; - -/* - * ================================ - * Normal Key table format - * ================================ - */ - -/* The order of KEY index is MAPPING_KEY_START_INDEX > GROUP_KEY_START_INDEX */ -#define MAX_KEY_TABLE 24 /* 24 entry for storing key data */ -#define GROUP_KEY_START_INDEX 4 -#define MAPPING_KEY_START_INDEX 8 - -/* - * ========================================= - * Descriptor - * ========================================= - */ -#define MAX_DESCRIPTOR_BUFFER_INDEX 8 /* Have to multiple of 2 */ -#define FLAG_ERROR_TX_MASK 0x000000bf -#define FLAG_ERROR_RX_MASK 0x0000083f - -#define FLAG_BAND_RX_MASK 0x10000000 /* Bit 28 */ - -struct R00_descriptor { - union { - u32 value; -#ifdef _BIG_ENDIAN_ - struct { - u32 R00_packet_or_buffer_status:1; - u32 R00_packet_in_fifo:1; - u32 R00_RESERVED:2; - u32 R00_receive_byte_count:12; - u32 R00_receive_time_index:16; - }; -#else - struct { - u32 R00_receive_time_index:16; - u32 R00_receive_byte_count:12; - u32 R00_RESERVED:2; - u32 R00_packet_in_fifo:1; - u32 R00_packet_or_buffer_status:1; - }; -#endif - }; -}; - -struct T00_descriptor { - union { - u32 value; -#ifdef _BIG_ENDIAN_ - struct { - u32 T00_first_mpdu:1; /* for hardware use */ - u32 T00_last_mpdu:1; /* for hardware use */ - u32 T00_IsLastMpdu:1;/* 0:not 1:Yes for software used */ - u32 T00_IgnoreResult:1;/* The same mechanism with T00 setting. */ - u32 T00_RESERVED_ID:2;/* 3 bit ID reserved */ - u32 T00_tx_packet_id:4; - u32 T00_RESERVED:4; - u32 T00_header_length:6; - u32 T00_frame_length:12; - }; -#else - struct { - u32 T00_frame_length:12; - u32 T00_header_length:6; - u32 T00_RESERVED:4; - u32 T00_tx_packet_id:4; - u32 T00_RESERVED_ID:2; /* 3 bit ID reserved */ - u32 T00_IgnoreResult:1; /* The same mechanism with T00 setting. */ - u32 T00_IsLastMpdu:1; /* 0:not 1:Yes for software used */ - u32 T00_last_mpdu:1; /* for hardware use */ - u32 T00_first_mpdu:1; /* for hardware use */ - }; -#endif - }; -}; - -struct R01_descriptor { - union { - u32 value; -#ifdef _BIG_ENDIAN_ - struct { - u32 R01_RESERVED:3; - u32 R01_mod_type:1; - u32 R01_pre_type:1; - u32 R01_data_rate:3; - u32 R01_AGC_state:8; - u32 R01_LNA_state:2; - u32 R01_decryption_method:2; - u32 R01_mic_error:1; - u32 R01_replay:1; - u32 R01_broadcast_frame:1; - u32 R01_multicast_frame:1; - u32 R01_directed_frame:1; - u32 R01_receive_frame_antenna_selection:1; - u32 R01_frame_receive_during_atim_window:1; - u32 R01_protocol_version_error:1; - u32 R01_authentication_frame_icv_error:1; - u32 R01_null_key_to_authentication_frame:1; - u32 R01_icv_error:1; - u32 R01_crc_error:1; - }; -#else - struct { - u32 R01_crc_error:1; - u32 R01_icv_error:1; - u32 R01_null_key_to_authentication_frame:1; - u32 R01_authentication_frame_icv_error:1; - u32 R01_protocol_version_error:1; - u32 R01_frame_receive_during_atim_window:1; - u32 R01_receive_frame_antenna_selection:1; - u32 R01_directed_frame:1; - u32 R01_multicast_frame:1; - u32 R01_broadcast_frame:1; - u32 R01_replay:1; - u32 R01_mic_error:1; - u32 R01_decryption_method:2; - u32 R01_LNA_state:2; - u32 R01_AGC_state:8; - u32 R01_data_rate:3; - u32 R01_pre_type:1; - u32 R01_mod_type:1; - u32 R01_RESERVED:3; - }; -#endif - }; -}; - -struct T01_descriptor { - union { - u32 value; -#ifdef _BIG_ENDIAN_ - struct { - u32 T01_rts_cts_duration:16; - u32 T01_fall_back_rate:3; - u32 T01_add_rts:1; - u32 T01_add_cts:1; - u32 T01_modulation_type:1; - u32 T01_plcp_header_length:1; - u32 T01_transmit_rate:3; - u32 T01_wep_id:2; - u32 T01_add_challenge_text:1; - u32 T01_inhibit_crc:1; - u32 T01_loop_back_wep_mode:1; - u32 T01_retry_abort_ebable:1; - }; -#else - struct { - u32 T01_retry_abort_ebable:1; - u32 T01_loop_back_wep_mode:1; - u32 T01_inhibit_crc:1; - u32 T01_add_challenge_text:1; - u32 T01_wep_id:2; - u32 T01_transmit_rate:3; - u32 T01_plcp_header_length:1; - u32 T01_modulation_type:1; - u32 T01_add_cts:1; - u32 T01_add_rts:1; - u32 T01_fall_back_rate:3; - u32 T01_rts_cts_duration:16; - }; -#endif - }; -}; - -struct T02_descriptor { - union { - u32 value; -#ifdef _BIG_ENDIAN_ - struct { - u32 T02_IsLastMpdu:1; /* The same mechanism with T00 setting */ - u32 T02_IgnoreResult:1; /* The same mechanism with T00 setting. */ - u32 T02_RESERVED_ID:2; /* The same mechanism with T00 setting */ - u32 T02_Tx_PktID:4; - u32 T02_MPDU_Cnt:4; - u32 T02_RTS_Cnt:4; - u32 T02_RESERVED:7; - u32 T02_transmit_complete:1; - u32 T02_transmit_abort_due_to_TBTT:1; - u32 T02_effective_transmission_rate:1; - u32 T02_transmit_without_encryption_due_to_wep_on_false:1; - u32 T02_discard_due_to_null_wep_key:1; - u32 T02_RESERVED_1:1; - u32 T02_out_of_MaxTxMSDULiftTime:1; - u32 T02_transmit_abort:1; - u32 T02_transmit_fail:1; - }; -#else - struct { - u32 T02_transmit_fail:1; - u32 T02_transmit_abort:1; - u32 T02_out_of_MaxTxMSDULiftTime:1; - u32 T02_RESERVED_1:1; - u32 T02_discard_due_to_null_wep_key:1; - u32 T02_transmit_without_encryption_due_to_wep_on_false:1; - u32 T02_effective_transmission_rate:1; - u32 T02_transmit_abort_due_to_TBTT:1; - u32 T02_transmit_complete:1; - u32 T02_RESERVED:7; - u32 T02_RTS_Cnt:4; - u32 T02_MPDU_Cnt:4; - u32 T02_Tx_PktID:4; - u32 T02_RESERVED_ID:2; /* The same mechanism with T00 setting */ - u32 T02_IgnoreResult:1; /* The same mechanism with T00 setting. */ - u32 T02_IsLastMpdu:1; /* The same mechanism with T00 setting */ - }; -#endif - }; -}; - -struct wb35_descriptor { /* Skip length = 8 DWORD */ - /* ID for descriptor ---, The field doesn't be cleard in the operation of Descriptor definition */ - u8 Descriptor_ID; - /* ----------------------The above region doesn't be cleared by DESCRIPTOR_RESET------ */ - u8 RESERVED[3]; - - u16 FragmentThreshold; - u8 InternalUsed; /* Only can be used by operation of descriptor definition */ - u8 Type; /* 0: 802.3 1:802.11 data frame 2:802.11 management frame */ - - u8 PreambleMode;/* 0: short 1:long */ - u8 TxRate; - u8 FragmentCount; - u8 EapFix; /* For speed up key install */ - - /* For R00 and T00 ------------------------------ */ - union { - struct R00_descriptor R00; - struct T00_descriptor T00; - }; - - /* For R01 and T01 ------------------------------ */ - union { - struct R01_descriptor R01; - struct T01_descriptor T01; - }; - - /* For R02 and T02 ------------------------------ */ - union { - u32 R02; - struct T02_descriptor T02; - }; - - /* For R03 and T03 ------------------------------ */ - /* For software used */ - union { - u32 R03; - u32 T03; - struct { - u8 buffer_number; - u8 buffer_start_index; - u16 buffer_total_size; - }; - }; - - /* For storing the buffer */ - u16 buffer_size[MAX_DESCRIPTOR_BUFFER_INDEX]; - void *buffer_address[MAX_DESCRIPTOR_BUFFER_INDEX]; -}; - - -#define DEFAULT_NULL_PACKET_COUNT 180000 /* 180 seconds */ - -#define MAX_TXVGA_EEPROM 9 /* How many word(u16) of EEPROM will be used for TxVGA */ -#define MAX_RF_PARAMETER 32 - -struct txvga_for_50 { - u8 ChanNo; - u8 TxVgaValue; -}; - -/* - * ============================================== - * Device related include - * ============================================== - */ - -#include "wbusb_s.h" -#include "wb35reg_s.h" -#include "wb35tx_s.h" -#include "wb35rx_s.h" - -/* For Hal using ============================================ */ -struct hw_data { - /* For compatible with 33 */ - u32 revision; - u32 BB3c_cal; /* The value for Tx calibration comes from EEPROM */ - u32 BB54_cal; /* The value for Rx calibration comes from EEPROM */ - - /* For surprise remove */ - u32 SurpriseRemove; /* 0: Normal 1: Surprise remove */ - u8 IsKeyPreSet; - u8 CalOneTime; - - u8 VCO_trim; - - u32 FragCount; - u32 DMAFix; /* V1_DMA_FIX The variable can be removed if driver want to save mem space for V2. */ - - /* - * =============================================== - * Definition for MAC address - * =============================================== - */ - u8 PermanentMacAddress[ETH_ALEN + 2]; /* The Ethernet addr that are stored in EEPROM. + 2 to 8-byte alignment */ - u8 CurrentMacAddress[ETH_ALEN + 2]; /* The Enthernet addr that are in used. + 2 to 8-byte alignment */ - - /* - * ========================================= - * Definition for 802.11 - * ========================================= - */ - u8 *bssid_pointer; /* Used by hal_get_bssid for return value */ - u8 bssid[8]; /* Only 6 byte will be used. 8 byte is required for read buffer */ - u8 ssid[32]; /* maximum ssid length is 32 byte */ - - u16 AID; - u8 ssid_length; - u8 Channel; - - u16 ListenInterval; - u16 CapabilityInformation; - - u16 BeaconPeriod; - u16 ProbeDelay; - - u8 bss_type;/* 0: IBSS_NET or 1:ESS_NET */ - u8 preamble;/* 0: short preamble, 1: long preamble */ - u8 slot_time_select; /* 9 or 20 value */ - u8 phy_type; /* Phy select */ - - u32 phy_para[MAX_RF_PARAMETER]; - u32 phy_number; - - u32 CurrentRadioSw; /* 0:On 1:Off */ - u32 CurrentRadioHw; /* 0:On 1:Off */ - - u8 *power_save_point; /* Used by hal_get_power_save_mode for return value */ - u8 cwmin; - u8 desired_power_save; - u8 dtim; /* Is running dtim */ - u8 mapping_key_replace_index; /* In Key table, the next index be replaced */ - - u16 MaxReceiveLifeTime; - u16 FragmentThreshold; - u16 FragmentThreshold_tmp; - u16 cwmax; - - u8 Key_slot[MAX_KEY_TABLE][8]; /* Ownership record for key slot. For Alignment */ - u32 Key_content[MAX_KEY_TABLE][12]; /* 10DW for each entry + 2 for burst command (Off and On valid bit) */ - u8 CurrentDefaultKeyIndex; - u32 CurrentDefaultKeyLength; - - /* - * ================================================== - * Variable for each module - * ================================================== - */ - struct wb_usb WbUsb; /* Need WbUsb.h */ - struct wb35_reg reg; /* Need Wb35Reg.h */ - struct wb35_tx Wb35Tx; /* Need Wb35Tx.h */ - struct wb35_rx Wb35Rx; /* Need Wb35Rx.h */ - - struct timer_list LEDTimer; /* For LED */ - - u32 LEDpoint; /* For LED */ - - u32 dto_tx_retry_count; - u32 dto_tx_frag_count; - u32 rx_ok_count[13]; /* index=0: total rx ok */ - u32 rx_err_count[13]; /* index=0: total rx err */ - - /* for Tx debug */ - u32 tx_TBTT_start_count; - u32 tx_ETR_count; - u32 tx_WepOn_false_count; - u32 tx_Null_key_count; - u32 tx_retry_count[8]; - - u8 PowerIndexFromEEPROM; /* For 2412MHz */ - u8 power_index; - u8 IsWaitJoinComplete; /* TRUE: set join request */ - u8 band; - - u16 SoftwareSet; - u16 Reserved_s; - - u32 IsInitOK; /* 0: Driver starting 1: Driver init OK */ - - /* For Phy calibration */ - s32 iq_rsdl_gain_tx_d2; - s32 iq_rsdl_phase_tx_d2; - u32 txvga_setting_for_cal; - - u8 TxVgaSettingInEEPROM[(((MAX_TXVGA_EEPROM * 2) + 3) & ~0x03)]; /* For EEPROM value */ - u8 TxVgaFor24[16]; /* Max is 14, 2 for alignment */ - struct txvga_for_50 TxVgaFor50[36]; /* 35 channels in 5G. 35x2 = 70 byte. 2 for alignments */ - - u16 Scan_Interval; - u16 RESERVED6; - - /* LED control */ - u32 LED_control; - /* - * LED_control 4 byte: Gray_Led_1[3] Gray_Led_0[2] Led[1] Led[0] - * Gray_Led - * For Led gray setting - * Led - * 0: normal control, - * LED behavior will decide by EEPROM setting - * 1: Turn off specific LED - * 2: Always on specific LED - * 3: slow blinking specific LED - * 4: fast blinking specific LED - * 5: WPS led control is set. Led0 is Red, Led1 id Green - * - * Led[1] is parameter for WPS LED mode - * 1:InProgress - * 2: Error - * 3: Session overlap - * 4: Success control - */ - u32 LED_LinkOn; /* Turn LED on control */ - u32 LED_Scanning; /* Let LED in scan process control */ - u32 LED_Blinking; /* Temp variable for shining */ - u32 RxByteCountLast; - u32 TxByteCountLast; - - atomic_t SurpriseRemoveCount; - - /* For global timer */ - u32 time_count; /* TICK_TIME_100ms 1 = 100ms */ - - /* For error recover */ - u32 HwStop; - - /* For avoid AP disconnect */ - u32 NullPacketCount; -}; - -#endif diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index a053bbb39610..df055abf5c42 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -16,7 +16,7 @@ #include "mds_f.h" #include "mlmetxrx_f.h" #include "mto.h" -#include "wbhal_s.h" +#include "wbhal.h" #include "wb35reg_f.h" #include "wb35tx_f.h" #include "wb35rx_f.h" -- cgit v1.2.3 From 9dd5f271441bbe85578c2b7841820d8bca26096c Mon Sep 17 00:00:00 2001 From: Mauro Schilman Date: Mon, 1 Nov 2010 14:12:05 -0300 Subject: Staging: frontier: fix space and * coding style issues in alphatrack.c This is a patch to the alphatrack.c file that fixes up a space warning and a space after '*' warning found by the checkpatch.pl tool Signed-off-by: Mauro Schilman Signed-off-by: Greg Kroah-Hartman --- drivers/staging/frontier/alphatrack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c index ef7fbf8b069a..2babb034a254 100644 --- a/drivers/staging/frontier/alphatrack.c +++ b/drivers/staging/frontier/alphatrack.c @@ -89,7 +89,7 @@ static int debug = ALPHATRACK_DEBUG; /* Use our own dbg macro */ #define dbg_info(dev, format, arg...) do \ - { if (debug) dev_info(dev , format , ## arg); } while (0) + { if (debug) dev_info(dev , format , ## arg); } while (0) #define alphatrack_ocmd_info(dev, cmd, format, arg...) @@ -769,7 +769,7 @@ static int usb_alphatrack_probe(struct usb_interface *intf, } dev->write_buffer = - kmalloc(sizeof(struct alphatrack_ocmd) * true_size, GFP_KERNEL); + kmalloc(true_size * sizeof(struct alphatrack_ocmd), GFP_KERNEL); if (!dev->write_buffer) { dev_err(&intf->dev, "Couldn't allocate write_buffer\n"); -- cgit v1.2.3 From 6112063d804aa0afc8d4462b22e36fc259393b64 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 1 Nov 2010 22:29:28 +0200 Subject: Staging: w35und: Kill empty Mds_Destroy function The Mds_Destroy() function doesn't do anything so kill it. Acked-by: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mds.c | 5 ----- drivers/staging/winbond/mds_f.h | 1 - drivers/staging/winbond/wbusb.c | 2 -- 3 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 9ac2c874ef05..90f2cc019d3b 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -18,11 +18,6 @@ Mds_initial(struct wbsoft_priv *adapter) return hal_get_tx_buffer(&adapter->sHwData, &pMds->pTxBuffer); } -void -Mds_Destroy(struct wbsoft_priv *adapter) -{ -} - static void Mds_DurationSet(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *buffer) { struct T00_descriptor *pT00; diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h index d902843e8aed..ce8be079e957 100644 --- a/drivers/staging/winbond/mds_f.h +++ b/drivers/staging/winbond/mds_f.h @@ -5,7 +5,6 @@ #include "core.h" unsigned char Mds_initial(struct wbsoft_priv *adapter); -void Mds_Destroy(struct wbsoft_priv *adapter); void Mds_Tx(struct wbsoft_priv *adapter); void Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pt02); void Mds_MpduProcess(struct wbsoft_priv *adapter, struct wb35_descriptor *prxdes); diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index df055abf5c42..82040f457a03 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -863,8 +863,6 @@ static void hal_halt(struct hw_data *pHwData) static void wb35_hw_halt(struct wbsoft_priv *adapter) { - Mds_Destroy(adapter); - /* Turn off Rx and Tx hardware ability */ hal_stop(&adapter->sHwData); #ifdef _PE_USB_INI_DUMP_ -- cgit v1.2.3 From 4d0d302257d3d0eccf371aab49c74b41797bebc3 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 1 Nov 2010 22:29:29 +0200 Subject: Staging: w35und: Kill struct hwdata ->NullPacketCount This patch kills the NullPacketCount member of struct hwdata. It's not used for anything so it's safe to remove it. Acked-by: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wbhal.h | 6 ------ drivers/staging/winbond/wbusb.c | 9 --------- 2 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/wbhal.h b/drivers/staging/winbond/wbhal.h index 821a1b3f1301..6f4cd76e7be2 100644 --- a/drivers/staging/winbond/wbhal.h +++ b/drivers/staging/winbond/wbhal.h @@ -342,9 +342,6 @@ struct wb35_descriptor { /* Skip length = 8 DWORD */ void *buffer_address[MAX_DESCRIPTOR_BUFFER_INDEX]; }; - -#define DEFAULT_NULL_PACKET_COUNT 180000 /* 180 seconds */ - #define MAX_TXVGA_EEPROM 9 /* How many word(u16) of EEPROM will be used for TxVGA */ #define MAX_RF_PARAMETER 32 @@ -517,9 +514,6 @@ struct hw_data { /* For error recover */ u32 HwStop; - - /* For avoid AP disconnect */ - u32 NullPacketCount; }; #endif diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 82040f457a03..dcb6d5b63d76 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -611,15 +611,6 @@ static void hal_led_control(unsigned long data) } break; } - - /* Active send null packet to avoid AP disconnect */ - if (pHwData->LED_LinkOn) { - pHwData->NullPacketCount += TimeInterval; - if (pHwData->NullPacketCount >= - DEFAULT_NULL_PACKET_COUNT) { - pHwData->NullPacketCount = 0; - } - } } pHwData->time_count += TimeInterval; -- cgit v1.2.3 From 87cb9a6310bc5183de196b25ef6adfda3080a744 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 1 Nov 2010 22:29:30 +0200 Subject: Staging: w35und: Kill struct hwdata ->HwStop This patch kills the ->HwStop member of struct hwdata. It's a read-only variable that's always zero so it's safe to remove it. Acked-by: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wb35rx.c | 4 ++-- drivers/staging/winbond/wb35tx.c | 8 ++++---- drivers/staging/winbond/wbhal.h | 3 --- 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c index 448514aada44..5af271f2de9c 100644 --- a/drivers/staging/winbond/wb35rx.c +++ b/drivers/staging/winbond/wb35rx.c @@ -174,7 +174,7 @@ static void Wb35Rx_Complete(struct urb *urb) /* The IRP is completed */ pWb35Rx->EP3vm_state = VM_COMPLETED; - if (pHwData->SurpriseRemove || pHwData->HwStop) /* Must be here, or RxBufferId is invalid */ + if (pHwData->SurpriseRemove) /* Must be here, or RxBufferId is invalid */ goto error; if (pWb35Rx->rx_halt) @@ -239,7 +239,7 @@ static void Wb35Rx(struct ieee80211_hw *hw) u32 RxBufferId; /* Issuing URB */ - if (pHwData->SurpriseRemove || pHwData->HwStop) + if (pHwData->SurpriseRemove) goto error; if (pWb35Rx->rx_halt) diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c index 2a9d05557678..fd52554e46f8 100644 --- a/drivers/staging/winbond/wb35tx.c +++ b/drivers/staging/winbond/wb35tx.c @@ -41,7 +41,7 @@ static void Wb35Tx_complete(struct urb * pUrb) pWb35Tx->TxSendIndex++; pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER; - if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove + if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove goto error; if (pWb35Tx->tx_halt) @@ -74,7 +74,7 @@ static void Wb35Tx(struct wbsoft_priv *adapter) u32 SendIndex; - if (pHwData->SurpriseRemove || pHwData->HwStop) + if (pHwData->SurpriseRemove) goto cleanup; if (pWb35Tx->tx_halt) @@ -222,7 +222,7 @@ static void Wb35Tx_EP2VM_complete(struct urb * pUrb) pWb35Tx->EP2VM_status = pUrb->status; // For Linux 2.4. Interrupt will always trigger - if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove + if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove goto error; if (pWb35Tx->tx_halt) @@ -263,7 +263,7 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; int retv; - if (pHwData->SurpriseRemove || pHwData->HwStop) + if (pHwData->SurpriseRemove) goto error; if (pWb35Tx->tx_halt) diff --git a/drivers/staging/winbond/wbhal.h b/drivers/staging/winbond/wbhal.h index 6f4cd76e7be2..1c91588fc5b3 100644 --- a/drivers/staging/winbond/wbhal.h +++ b/drivers/staging/winbond/wbhal.h @@ -511,9 +511,6 @@ struct hw_data { /* For global timer */ u32 time_count; /* TICK_TIME_100ms 1 = 100ms */ - - /* For error recover */ - u32 HwStop; }; #endif -- cgit v1.2.3 From 4d26d7e6ba3fffd224560acd586526bf2f2f4f73 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Mon, 1 Nov 2010 22:29:31 +0200 Subject: Staging: w35und: Kill struct hwdata ->SurpriseRemoveCount This patch kills the ->SurpriseRemoveCount member of struct hwdata. It's not used at all so it's safe to remove it. Acked-by: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wbhal.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/wbhal.h b/drivers/staging/winbond/wbhal.h index 1c91588fc5b3..dcf3b213b4f1 100644 --- a/drivers/staging/winbond/wbhal.h +++ b/drivers/staging/winbond/wbhal.h @@ -507,8 +507,6 @@ struct hw_data { u32 RxByteCountLast; u32 TxByteCountLast; - atomic_t SurpriseRemoveCount; - /* For global timer */ u32 time_count; /* TICK_TIME_100ms 1 = 100ms */ }; -- cgit v1.2.3 From eb21c1587ac3272d58592e775dc55af6266f7403 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 13:44:08 +0100 Subject: staging: ft1000: Use memset instead looping with for. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 5b89ee2a2971..bc6aaf4e23b6 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -874,10 +874,7 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev) pInfo->fCondResetPend = 0; pInfo->usbboot = 0; pInfo->dspalive = 0; - for (i=0;i<32 ;i++ ) - { - pInfo->tempbuf[i] = 0; - } + memset(&pInfo->tempbuf[0], 0, sizeof(pInfo->tempbuf)); INIT_LIST_HEAD(&pInfo->prov_list); -- cgit v1.2.3 From 019bd3f825a7fc438b1e9ce7d145b03f13102aee Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 13:44:09 +0100 Subject: staging: ft1000: Remove dead code. Remove functions which was used nowhere. Also remove dead variables used by this functions. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 199 ------------------------- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 1 - drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 3 - 3 files changed, 203 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index bc6aaf4e23b6..5a9edfb1bd1f 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -45,33 +45,6 @@ static unsigned long gCardIndex; #define MAX_RCV_LOOP 100 -/**************************************************************** - * ft1000_control_complete - ****************************************************************/ -static void ft1000_control_complete(struct urb *urb) -{ - struct ft1000_device *ft1000dev = (struct ft1000_device *)urb->context; - - //DEBUG("FT1000_CONTROL_COMPLETE ENTERED\n"); - if (ft1000dev == NULL ) - { - DEBUG("NULL ft1000dev, failure\n"); - return ; - } - else if ( ft1000dev->dev == NULL ) - { - DEBUG("NULL ft1000dev->dev, failure\n"); - return ; - } - - if(waitqueue_active(&ft1000dev->control_wait)) - { - wake_up(&ft1000dev->control_wait); - } - - //DEBUG("FT1000_CONTROL_COMPLETE RETURNED\n"); -} - //--------------------------------------------------------------------------- // Function: ft1000_control // @@ -1023,178 +996,6 @@ static void ft1000_usb_transmit_complete(struct urb *urb) //DEBUG("Return from ft1000_usb_transmit_complete\n"); } - -/**************************************************************** - * ft1000_control - ****************************************************************/ -static int ft1000_read_fifo_reg(struct ft1000_device *ft1000dev,unsigned int pipe, - u8 request, - u8 requesttype, - u16 value, - u16 index, - void *data, - u16 size, - int timeout) -{ - u16 ret; - - DECLARE_WAITQUEUE(wait, current); - struct urb *urb; - struct usb_ctrlrequest *dr; - int status; - - if (ft1000dev == NULL ) - { - DEBUG("NULL ft1000dev, failure\n"); - return STATUS_FAILURE; - } - else if ( ft1000dev->dev == NULL ) - { - DEBUG("NULL ft1000dev->dev, failure\n"); - return STATUS_FAILURE; - } - - spin_lock(&ft1000dev->device_lock); - - if(in_interrupt()) - { - spin_unlock(&ft1000dev->device_lock); - return -EBUSY; - } - - urb = usb_alloc_urb(0, GFP_KERNEL); - dr = kmalloc(sizeof(struct usb_ctrlrequest), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - - if(!urb || !dr) - { - kfree(dr); - usb_free_urb(urb); - spin_unlock(&ft1000dev->device_lock); - return -ENOMEM; - } - - - - dr->bRequestType = requesttype; - dr->bRequest = request; - dr->wValue = value; - dr->wIndex = index; - dr->wLength = size; - - usb_fill_control_urb(urb, ft1000dev->dev, pipe, (char*)dr, (void*)data, size, (void *)ft1000_control_complete, (void*)ft1000dev); - - - init_waitqueue_head(&ft1000dev->control_wait); - - set_current_state(TASK_INTERRUPTIBLE); - - add_wait_queue(&ft1000dev->control_wait, &wait); - - - - - status = usb_submit_urb(urb, GFP_KERNEL); - - if(status) - { - usb_free_urb(urb); - kfree(dr); - remove_wait_queue(&ft1000dev->control_wait, &wait); - spin_unlock(&ft1000dev->device_lock); - return status; - } - - if(urb->status == -EINPROGRESS) - { - while(timeout && urb->status == -EINPROGRESS) - { - status = timeout = schedule_timeout(timeout); - } - } - else - { - status = 1; - } - - remove_wait_queue(&ft1000dev->control_wait, &wait); - - if(!status) - { - usb_unlink_urb(urb); - printk("ft1000 timeout\n"); - status = -ETIMEDOUT; - } - else - { - status = urb->status; - - if(urb->status) - { - printk("ft1000 control message failed (urb addr: %p) with error number: %i\n", urb, (int)status); - - usb_clear_halt(ft1000dev->dev, usb_rcvctrlpipe(ft1000dev->dev, 0)); - usb_clear_halt(ft1000dev->dev, usb_sndctrlpipe(ft1000dev->dev, 0)); - usb_unlink_urb(urb); - } - } - - - - usb_free_urb(urb); - kfree(dr); - spin_unlock(&ft1000dev->device_lock); - return ret; - - -} - -//--------------------------------------------------------------------------- -// Function: ft1000_read_fifo_len -// -// Parameters: ft1000dev - device structure -// -// -// Returns: none -// -// Description: read the fifo length register content -// -// Notes: -// -//--------------------------------------------------------------------------- -static inline u16 ft1000_read_fifo_len (struct net_device *dev) -{ - u16 temp; - u16 ret; - - struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev); - struct ft1000_device *ft1000dev = info->pFt1000Dev; -// DEBUG("ft1000_read_fifo_len: enter ft1000dev %x\n", ft1000dev); //aelias [-] reason: warning: format ???%x??? expects type ???unsigned int???, but argument 2 has type ???struct ft1000_device *??? - DEBUG("ft1000_read_fifo_len: enter ft1000dev %p\n", ft1000dev); //aelias [+] reason: up - - ret = STATUS_SUCCESS; - - ret = ft1000_read_fifo_reg(ft1000dev, - usb_rcvctrlpipe(ft1000dev->dev,0), - HARLEY_READ_REGISTER, - HARLEY_READ_OPERATION, - 0, - FT1000_REG_MAG_UFSR, - &temp, - 2, - LARGE_TIMEOUT); - - if (ret>0) - ret = STATUS_SUCCESS; - else - ret = STATUS_FAILURE; - - DEBUG("ft1000_read_fifo_len: returned %d\n", temp); - - return (temp- 16); - -} - - //--------------------------------------------------------------------------- // // Function: ft1000_copy_down_pkt diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 28f55b2030e9..4e81bdd6902a 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -84,7 +84,6 @@ static int ft1000_probe(struct usb_interface *interface, ft1000dev->dev = dev; ft1000dev->status = 0; ft1000dev->net = NULL; - spin_lock_init(&ft1000dev->device_lock); ft1000dev->tx_urb = usb_alloc_urb(0, GFP_ATOMIC); ft1000dev->rx_urb = usb_alloc_urb(0, GFP_ATOMIC); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index a9d419a98a06..503481a60d3f 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -466,12 +466,9 @@ struct ft1000_device { struct usb_device *dev; struct net_device *net; - spinlock_t device_lock; u32 status; - wait_queue_head_t control_wait; - struct urb *rx_urb; struct urb *tx_urb; -- cgit v1.2.3 From d2b07455b85d20c72e4182fe7d53d8c70838f984 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 13:44:10 +0100 Subject: staging: ft1000: Pseudo header handlig improved. Handling for pseudo header was done by directly copying data to tx buffer. This hide a functionality and make code unreadable. Use approach where fill pseudo_hdr structure first with data and then copy to beginning of buffer. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 35 +++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 5a9edfb1bd1f..90394e10ad2e 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1017,10 +1017,9 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len) struct ft1000_device *pFt1000Dev = pInfo->pFt1000Dev; - int i, count, ret; - USHORT *pTemp; - USHORT checksum; + int count, ret; u8 *t; + struct pseudo_hdr hdr; if (!pInfo->CardReady) { @@ -1044,21 +1043,21 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len) if ( count % 4) count = count + (4- (count %4) ); - pTemp = (PUSHORT)&(pFt1000Dev->tx_buf[0]); - *pTemp ++ = ntohs(count); - *pTemp ++ = 0x1020; - *pTemp ++ = 0x2010; - *pTemp ++ = 0x9100; - *pTemp ++ = 0; - *pTemp ++ = 0; - *pTemp ++ = 0; - pTemp = (PUSHORT)&(pFt1000Dev->tx_buf[0]); - checksum = *pTemp ++; - for (i=1; i<7; i++) - { - checksum ^= *pTemp ++; - } - *pTemp++ = checksum; + memset(&hdr, 0, sizeof(struct pseudo_hdr)); + + hdr.length = ntohs(count); + hdr.source = 0x10; + hdr.destination = 0x20; + hdr.portdest = 0x20; + hdr.portsrc = 0x10; + hdr.sh_str_id = 0x91; + hdr.control = 0x00; + + hdr.checksum = hdr.length ^ hdr.source ^ hdr.destination ^ + hdr.portdest ^ hdr.portsrc ^ hdr.sh_str_id ^ + hdr.control; + + memcpy(&pFt1000Dev->tx_buf[0], &hdr, sizeof(hdr)); memcpy(&(pFt1000Dev->tx_buf[sizeof(struct pseudo_hdr)]), packet, len); netif_stop_queue(netdev); -- cgit v1.2.3 From 35e9403b052ff6cad71bc5d9a075385e0c62ab96 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 14:51:44 +0100 Subject: staging: ft1000: Use specific error codes instead self defined. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 90394e10ad2e..9bb537734e84 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1025,7 +1025,7 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len) { DEBUG("ft1000_copy_down_pkt::Card Not Ready\n"); - return STATUS_FAILURE; + return -ENODEV; } @@ -1037,7 +1037,7 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len) { DEBUG("Error:ft1000_copy_down_pkt:Message Size Overflow!\n"); DEBUG("size = %d\n", count); - return STATUS_FAILURE; + return -EINVAL; } if ( count % 4) @@ -1080,25 +1080,18 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len) }*/ - ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC); - if(ret) - { + ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC); + if (ret) { DEBUG("ft1000 failed tx_urb %d\n", ret); - - return STATUS_FAILURE; - - } - else - { - //DEBUG("ft1000 sucess tx_urb %d\n", ret); - - pInfo->stats.tx_packets++; - pInfo->stats.tx_bytes += (len+14); - } + return ret; + } else { + pInfo->stats.tx_packets++; + pInfo->stats.tx_bytes += (len+14); + } //DEBUG("ft1000_copy_down_pkt() exit\n"); - return STATUS_SUCCESS; + return 0; } //--------------------------------------------------------------------------- -- cgit v1.2.3 From 3b3291e868695194096591c4a5e3e302939e4c2b Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 14:51:45 +0100 Subject: staging: ft1000: Use common return point. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 9bb537734e84..0de4a2eeb3d0 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1121,14 +1121,13 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev) if ( skb == NULL ) { DEBUG ("ft1000_hw: ft1000_start_xmit:skb == NULL!!!\n" ); - return STATUS_FAILURE; + return NETDEV_TX_OK; } if ( pFt1000Dev->status & FT1000_STATUS_CLOSING) { DEBUG("network driver is closed, return\n"); - dev_kfree_skb(skb); - return STATUS_SUCCESS; + goto err; } //DEBUG("ft1000_start_xmit 1:length of packet = %d\n", skb->len); @@ -1147,28 +1146,24 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev) { /* Drop packet is mediastate is down */ DEBUG("ft1000_hw:ft1000_start_xmit:mediastate is down\n"); - dev_kfree_skb(skb); - return STATUS_SUCCESS; + goto err; } if ( (skb->len < ENET_HEADER_SIZE) || (skb->len > ENET_MAX_SIZE) ) { /* Drop packet which has invalid size */ DEBUG("ft1000_hw:ft1000_start_xmit:invalid ethernet length\n"); - dev_kfree_skb(skb); - return STATUS_SUCCESS; + goto err; } //mbelian - if(ft1000_copy_down_pkt (dev, (pdata+ENET_HEADER_SIZE-2), skb->len - ENET_HEADER_SIZE + 2) == STATUS_FAILURE) - { - dev_kfree_skb(skb); - return STATUS_SUCCESS; - } + ft1000_copy_down_pkt(dev, (pdata+ENET_HEADER_SIZE-2), + skb->len - ENET_HEADER_SIZE + 2); - dev_kfree_skb(skb); +err: + dev_kfree_skb(skb); //DEBUG(" ft1000_start_xmit() exit\n"); - return 0; + return NETDEV_TX_OK; } //--------------------------------------------------------------------------- -- cgit v1.2.3 From d7780865164f2efe3ea2fa6f1ebdf61ecc1f2a4d Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 14:51:46 +0100 Subject: staging: ft1000: Correct return error values. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 0de4a2eeb3d0..30a847565ef4 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1306,7 +1306,7 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info) { DEBUG("network driver is closed, return\n"); //usb_kill_urb(pFt1000Dev->rx_urb); //mbelian - return STATUS_SUCCESS; + return -ENODEV; } usb_fill_bulk_urb(pFt1000Dev->rx_urb, @@ -1321,12 +1321,12 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info) if((result = usb_submit_urb(pFt1000Dev->rx_urb, GFP_ATOMIC))) { printk("ft1000_submit_rx_urb: submitting rx_urb %d failed\n", result); - return STATUS_FAILURE; + return result; } //DEBUG("ft1000_submit_rx_urb exit: result=%d\n", result); - return STATUS_SUCCESS; + return 0; } //--------------------------------------------------------------------------- -- cgit v1.2.3 From 95112cb448b5962daeee68db8ee523b71266e28b Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 2 Nov 2010 14:51:47 +0100 Subject: staging: ft1000: Check return value. Function ft1000_submit_rx_urb() could fail so add checking for return value. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 30a847565ef4..1fa1f811b017 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1347,6 +1347,7 @@ static int ft1000_open (struct net_device *dev) { struct ft1000_info *pInfo = (struct ft1000_info *)netdev_priv(dev); struct timeval tv; //mbelian + int ret; DEBUG("ft1000_open is called for card %d\n", pInfo->CardNumber); //DEBUG("ft1000_open: dev->addr=%x, dev->addr_len=%d\n", dev->addr, dev->addr_len); @@ -1364,8 +1365,9 @@ static int ft1000_open (struct net_device *dev) netif_carrier_on(dev); //mbelian - ft1000_submit_rx_urb(pInfo); - return 0; + ret = ft1000_submit_rx_urb(pInfo); + + return ret; } //--------------------------------------------------------------------------- -- cgit v1.2.3 From e2cb7da1671eb659c8edc81be9838afdd0b6b2cc Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:47 +0100 Subject: staging: ft1000: Get rid of PUCHAR typedef. PUCHAR typedef was replaces by u8 *. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 4 +- .../staging/ft1000/ft1000-usb/ft1000_download.c | 44 +++++++++++----------- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 40 ++++++++++---------- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 6 +-- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 11 +++--- 5 files changed, 52 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 87a6487531c2..cadfb62229ef 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -623,10 +623,10 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, memcpy(get_stat_data.eui64, info->eui64, EUISZ); if (info->ProgConStat != 0xFF) { - ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (PUCHAR)&ledStat, FT1000_MAG_DSP_LED_INDX); + ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); get_stat_data.LedStat = ntohs(ledStat); DEBUG("FT1000:ft1000_ChIoctl: LedStat = 0x%x\n", get_stat_data.LedStat); - ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (PUCHAR)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); + ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); get_stat_data.ConStat = ntohs(conStat); DEBUG("FT1000:ft1000_ChIoctl: ConStat = 0x%x\n", get_stat_data.ConStat); } diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 4dd456fbab9b..d7ca6ccad450 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -228,7 +228,7 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val status = ft1000_write_register (ft1000dev, FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL); } - status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); //DEBUG("get_handshake: handshake is %x\n", tempx); handshake = ntohs(handshake); //DEBUG("get_handshake: after swap, handshake is %x\n", handshake); @@ -300,10 +300,10 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected while (loopcnt < 100) { if (pft1000info->usbboot == 2) { - status = ft1000_read_dpram32 (ft1000dev, 0, (PUCHAR)&(pft1000info->tempbuf[0]), 64); + status = ft1000_read_dpram32 (ft1000dev, 0, (u8 *)&(pft1000info->tempbuf[0]), 64); for (temp=0; temp<16; temp++) DEBUG("tempbuf %d = 0x%x\n", temp, pft1000info->tempbuf[temp]); - status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); DEBUG("handshake from read_dpram16 = 0x%x\n", handshake); if (pft1000info->dspalive == pft1000info->tempbuf[6]) handshake = 0; @@ -313,7 +313,7 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected } } else { - status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1); + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); } loopcnt++; msleep(10); @@ -356,14 +356,14 @@ static USHORT get_request_type(struct ft1000_device *ft1000dev) if ( pft1000info->bootmode == 1) { - status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx); + status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); tempx = ntohl(tempx); } else { tempx = 0; - status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1); + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1); tempx |= (tempword << 16); tempx = ntohl(tempx); } @@ -383,7 +383,7 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); if ( pft1000info->bootmode == 1) { - status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx); + status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); tempx = ntohl(tempx); } else @@ -394,7 +394,7 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) } else { tempx = 0; - status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1); + status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1); } tempx |= (tempword << 16); tempx = ntohl(tempx); @@ -428,14 +428,14 @@ static long get_request_value(struct ft1000_device *ft1000dev) if ( pft1000info->bootmode == 1) { - status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&value); + status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&value); value = ntohl(value); } else { - status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 0); + status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0); value = tempword; - status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1); + status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1); value |= (tempword << 16); value = ntohl(value); } @@ -460,7 +460,7 @@ static long get_request_value_usb(struct ft1000_device *ft1000dev) } else { value = 0; - status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1); + status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1); } value |= (tempword << 16); @@ -494,7 +494,7 @@ static void put_request_value(struct ft1000_device *ft1000dev, long lvalue) ULONG status; tempx = ntohl(lvalue); - status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempx); + status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempx); @@ -602,24 +602,24 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR if (pft1000info->bootmode == 0) { if (dpram >= 0x3F4) - Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 8); + Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 8); else - Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64); + Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64); } else { for (j=0; j<10; j++) { - Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64); + Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64); if (Status == STATUS_SUCCESS) { // Work around for ASIC bit stuffing problem. if ( (tempbuffer[31] & 0xfe00) == 0xfe00) { - Status = ft1000_write_dpram32(ft1000dev, dpram+12, (PUCHAR)&tempbuffer[24], 64); + Status = ft1000_write_dpram32(ft1000dev, dpram+12, (u8 *)&tempbuffer[24], 64); } // Let's check the data written - Status = ft1000_read_dpram32 (ft1000dev, dpram, (PUCHAR)&resultbuffer[0], 64); + Status = ft1000_read_dpram32 (ft1000dev, dpram, (u8 *)&resultbuffer[0], 64); if ( (tempbuffer[31] & 0xfe00) == 0xfe00) { for (i=0; i<28; i++) @@ -633,7 +633,7 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR break; } } - Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (PUCHAR)&resultbuffer[0], 64); + Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (u8 *)&resultbuffer[0], 64); for (i=0; i<16; i++) { if (resultbuffer[i] != tempbuffer[i+24]) @@ -799,7 +799,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe ULONG image_chksum = 0; USHORT dpram = 0; - PUCHAR pbuffer; + u8 *pbuffer; struct prov_record *pprov_record; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -1066,7 +1066,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe templong = *pUsData++; templong |= (*pUsData++ << 16); - Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong); + Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong); } break; @@ -1095,7 +1095,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe templong = ntohs(*pUsFile++); temp = ntohs(*pUsFile++); templong |= (temp << 16); - Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong); + Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong); } break; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 1fa1f811b017..8333e66bef2a 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -196,7 +196,7 @@ u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRe // //--------------------------------------------------------------------------- -u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt) +u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt) { u16 ret = STATUS_SUCCESS; @@ -235,7 +235,7 @@ u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buf // Notes: // //--------------------------------------------------------------------------- -u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt) +u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt) { u16 ret = STATUS_SUCCESS; @@ -272,7 +272,7 @@ u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR bu // Notes: // //--------------------------------------------------------------------------- -u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow) +u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, u8 highlow) { u16 ret = STATUS_SUCCESS; @@ -365,7 +365,7 @@ u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT va // Notes: // //--------------------------------------------------------------------------- -u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer) +u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer) { UCHAR buf[16]; USHORT pos; @@ -414,14 +414,14 @@ u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR // Notes: // //--------------------------------------------------------------------------- -u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer) +u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer) { USHORT pos1; USHORT pos2; USHORT i; UCHAR buf[32]; UCHAR resultbuffer[32]; - PUCHAR pdata; + u8 *pdata; u16 ret = STATUS_SUCCESS; //DEBUG("fix_ft1000_write_dpram32: Entered:\n"); @@ -445,7 +445,7 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA return ret; } - ret = ft1000_read_dpram32(ft1000dev, pos1, (PUCHAR)&resultbuffer[0], 16); + ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16); if (ret == STATUS_SUCCESS) { buffer = pdata; @@ -460,8 +460,8 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA if (ret == STATUS_FAILURE) { - ret = ft1000_write_dpram32(ft1000dev, pos1, (PUCHAR)&tempbuffer[0], 16); - ret = ft1000_read_dpram32(ft1000dev, pos1, (PUCHAR)&resultbuffer[0], 16); + ret = ft1000_write_dpram32(ft1000dev, pos1, (u8 *)&tempbuffer[0], 16); + ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16); if (ret == STATUS_SUCCESS) { buffer = pdata; @@ -621,7 +621,7 @@ int dsp_reload(struct ft1000_device *ft1000dev) status = ft1000_write_register (ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL); // Let's check for FEFE - status = ft1000_read_dpram32 (ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX, (PUCHAR)&templong, 4); + status = ft1000_read_dpram32 (ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX, (u8 *)&templong, 4); DEBUG("templong (fefe) = 0x%8x\n", templong); // call codeloader @@ -1485,7 +1485,7 @@ static BOOLEAN ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int int i; u16 tempword; - ret = ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (PUCHAR)&size, FT1000_MAG_PH_LEN_INDX); + ret = ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (u8 *)&size, FT1000_MAG_PH_LEN_INDX); size = ntohs(size) + PSEUDOSZ; if (size > maxsz) { DEBUG("FT1000:ft1000_receive_cmd:Invalid command length = %d\n", size); @@ -1596,7 +1596,7 @@ static int ft1000_dsp_prov(void *arg) TempShortBuf[1] = htons (len); memcpy(&TempShortBuf[2], ppseudo_hdr, len); - status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&TempShortBuf[0], (unsigned short)(len+2)); + status = ft1000_write_dpram32 (dev, 0, (u8 *)&TempShortBuf[0], (unsigned short)(len+2)); status = ft1000_write_register (dev, FT1000_DB_DPRAM_TX, FT1000_REG_DOORBELL); list_del(&ptr->list); @@ -1815,7 +1815,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { } info->DSPInfoBlk[10] = 0x7200; info->DSPInfoBlk[11] = htons(info->DSPInfoBlklen); - status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&info->DSPInfoBlk[0], (unsigned short)(info->DSPInfoBlklen+22)); + status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPInfoBlk[0], (unsigned short)(info->DSPInfoBlklen+22)); status = ft1000_write_register (dev, FT1000_DB_DPRAM_TX, FT1000_REG_DOORBELL); info->DrvMsgPend = 0; @@ -1930,14 +1930,14 @@ int ft1000_poll(void* dev_id) { if (tempword & FT1000_DB_DPRAM_RX) { //DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_DPRAM_RX\n"); - status = ft1000_read_dpram16(dev, 0x200, (PUCHAR)&data, 0); + status = ft1000_read_dpram16(dev, 0x200, (u8 *)&data, 0); //DEBUG("ft1000_poll:FT1000_DB_DPRAM_RX:ft1000_read_dpram16:size = 0x%x\n", data); size = ntohs(data) + 16 + 2; //wai if (size % 4) { modulo = 4 - (size % 4); size = size + modulo; } - status = ft1000_read_dpram16(dev, 0x201, (PUCHAR)&portid, 1); + status = ft1000_read_dpram16(dev, 0x201, (u8 *)&portid, 1); portid &= 0xff; //DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_DPRAM_RX : portid 0x%x\n", portid); @@ -2072,7 +2072,7 @@ int ft1000_poll(void* dev_id) { status = ft1000_write_register (dev, FT1000_ASIC_RESET_REQ, FT1000_REG_DOORBELL); status = ft1000_write_register (dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL); // copy dsp session record from Adapter block - status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&info->DSPSess.Rec[0], 1024); + status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPSess.Rec[0], 1024); // Program WMARK register status = ft1000_write_register (dev, 0x600, FT1000_REG_MAG_WATERMARK); // ring doorbell to tell DSP that ASIC is out of reset @@ -2086,10 +2086,10 @@ int ft1000_poll(void* dev_id) { if (info->fAppMsgPend == 0) { // Reset ASIC and DSP - status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (PUCHAR)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX); - status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (PUCHAR)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX); - status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (PUCHAR)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX); - status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (PUCHAR)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX); + status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (u8 *)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX); + status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (u8 *)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX); + status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (u8 *)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX); + status = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (u8 *)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX); info->CardReady = 0; info->DrvErrNum = DSP_CONDRESET_INFO; DEBUG("ft1000_hw:DSP conditional reset requested\n"); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index 36cdd588fa98..dda0e33b4864 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -39,7 +39,7 @@ u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, USHORT indx, - PUCHAR buffer, u8 highlow); + u8 *buffer, u8 highlow); static int @@ -77,11 +77,11 @@ ft1000ReadProc (char *page, char **start, off_t off, int count, int *eof, if (info->ProgConStat != 0xFF) { ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_LED, - (PUCHAR) & ledStat, FT1000_MAG_DSP_LED_INDX); + (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); info->LedStat = ntohs (ledStat); ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_CON_STATE, - (PUCHAR) & conStat, FT1000_MAG_DSP_CON_STATE_INDX); + (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); info->ConStat = ntohs (conStat); do_gettimeofday (&tv); delta = (tv.tv_sec - info->ConTm); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 503481a60d3f..4996da9e2355 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -104,7 +104,6 @@ struct prov_record { #define BOOLEAN u8 #define PULONG u32 * #define PUSHORT u16 * -#define PUCHAR u8 * #define PCHAR u8 * #define UINT u32 @@ -565,12 +564,12 @@ struct dpram_blk { u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegIndx); u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx); -u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt); -u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt); -u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow); +u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt); +u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt); +u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, u8 highlow); u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow); -u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer); -u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer); +u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer); +u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer); extern void *pFileStart; extern size_t FileLength; -- cgit v1.2.3 From c8f775c88b1b84909d5d73b171a48302bf46b2f8 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:48 +0100 Subject: staging: ft1000: Get rid of UCHAR typedef. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- .../staging/ft1000/ft1000-usb/ft1000_download.c | 26 +++++++++++----------- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 6 ++--- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 11 +++++---- 3 files changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index d7ca6ccad450..d7377eba7ede 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -534,7 +534,7 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr) // // Parameters: struct ft1000_device - device structure // USHORT **pUsFile - DSP image file pointer in USHORT -// UCHAR **pUcFile - DSP image file pointer in UCHAR +// u8 **pUcFile - DSP image file pointer in u8 // long word_length - lenght of the buffer to be written // to DPRAM // @@ -546,7 +546,7 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr) // Notes: // //--------------------------------------------------------------------------- -static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length) +static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, u8 **pUcFile, long word_length) { ULONG Status = STATUS_SUCCESS; USHORT dpram; @@ -690,7 +690,7 @@ static void usb_dnld_complete (struct urb *urb) // // Parameters: struct ft1000_device - device structure // USHORT **pUsFile - DSP image file pointer in USHORT -// UCHAR **pUcFile - DSP image file pointer in UCHAR +// u8 **pUcFile - DSP image file pointer in u8 // long word_length - lenght of the buffer to be written // to DPRAM // @@ -702,7 +702,7 @@ static void usb_dnld_complete (struct urb *urb) // Notes: // //--------------------------------------------------------------------------- -static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length) +static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, u8 **pUcFile, long word_length) { ULONG Status = STATUS_SUCCESS; int byte_length; @@ -789,8 +789,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe struct drv_msg *pMailBoxData; USHORT *pUsData = NULL; USHORT *pUsFile = NULL; - UCHAR *pUcFile = NULL; - UCHAR *pBootEnd = NULL, *pCodeEnd= NULL; + u8 *pUcFile = NULL; + u8 *pBootEnd = NULL, *pCodeEnd= NULL; int imageN; long loader_code_address, loader_code_size = 0; long run_address = 0, run_size = 0; @@ -821,9 +821,9 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); pUsFile = (USHORT *)(pFileStart + pFileHdr5->loader_offset); - pUcFile = (UCHAR *)(pFileStart + pFileHdr5->loader_offset); + pUcFile = (u8 *)(pFileStart + pFileHdr5->loader_offset); - pBootEnd = (UCHAR *)(pFileStart + pFileHdr5->loader_code_end); + pBootEnd = (u8 *)(pFileStart + pFileHdr5->loader_code_end); loader_code_address = pFileHdr5->loader_code_address; loader_code_size = pFileHdr5->loader_code_size; @@ -879,7 +879,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe DEBUG("FT1000:REQUEST_DONE_BL\n"); /* Reposition ptrs to beginning of code section */ pUsFile = (USHORT *)(pBootEnd); - pUcFile = (UCHAR *)(pBootEnd); + pUcFile = (u8 *)(pBootEnd); //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile); //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile); uiState = STATE_CODE_DWNLD; @@ -989,7 +989,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe pft1000info->usbboot = 3; /* Reposition ptrs to beginning of provisioning section */ pUsFile = (USHORT *)(pFileStart + pFileHdr5->commands_offset); - pUcFile = (UCHAR *)(pFileStart + pFileHdr5->commands_offset); + pUcFile = (u8 *)(pFileStart + pFileHdr5->commands_offset); uiState = STATE_DONE_DWNLD; break; case REQUEST_CODE_SEGMENT: @@ -1119,8 +1119,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe bGoodVersion = TRUE; DEBUG("FT1000:download: bGoodVersion is TRUE\n"); pUsFile = (USHORT *)(pFileStart + pDspImageInfoV6->begin_offset); - pUcFile = (UCHAR *)(pFileStart + pDspImageInfoV6->begin_offset); - pCodeEnd = (UCHAR *)(pFileStart + pDspImageInfoV6->end_offset); + pUcFile = (u8 *)(pFileStart + pDspImageInfoV6->begin_offset); + pCodeEnd = (u8 *)(pFileStart + pDspImageInfoV6->end_offset); run_address = pDspImageInfoV6->run_address; run_size = pDspImageInfoV6->image_size; image_chksum = (ULONG)pDspImageInfoV6->checksum; @@ -1188,7 +1188,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe pprov_record->pprov_data = pbuffer; list_add_tail (&pprov_record->list, &pft1000info->prov_list); // Move to next entry if available - pUcFile = (UCHAR *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); + pUcFile = (u8 *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) { uiState = STATE_DONE_FILE; } diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 8333e66bef2a..2f195c8c9752 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -367,7 +367,7 @@ u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT va //--------------------------------------------------------------------------- u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer) { - UCHAR buf[16]; + u8 buf[16]; USHORT pos; u16 ret = STATUS_SUCCESS; @@ -419,8 +419,8 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *b USHORT pos1; USHORT pos2; USHORT i; - UCHAR buf[32]; - UCHAR resultbuffer[32]; + u8 buf[32]; + u8 resultbuffer[32]; u8 *pdata; u16 ret = STATUS_SUCCESS; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 4996da9e2355..96665a783919 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -98,7 +98,6 @@ struct prov_record { /*end of Jim*/ #define DEBUG(args...) printk(KERN_INFO args) -#define UCHAR u8 #define USHORT u16 #define ULONG u32 /* WTF ??? */ #define BOOLEAN u8 @@ -371,15 +370,15 @@ struct prov_record { -#define ISR_EMPTY (UCHAR)0x00 // no bits set in ISR +#define ISR_EMPTY (u8)0x00 // no bits set in ISR -#define ISR_DOORBELL_ACK (UCHAR)0x01 // the doorbell i sent has been recieved. +#define ISR_DOORBELL_ACK (u8)0x01 // the doorbell i sent has been recieved. -#define ISR_DOORBELL_PEND (UCHAR)0x02 // doorbell for me +#define ISR_DOORBELL_PEND (u8)0x02 // doorbell for me -#define ISR_RCV (UCHAR)0x04 // packet received with no errors +#define ISR_RCV (u8)0x04 // packet received with no errors -#define ISR_WATERMARK (UCHAR)0x08 // +#define ISR_WATERMARK (u8)0x08 // -- cgit v1.2.3 From d1674983e0fdf3a18dbc4ac7f1f0912f7b1c246e Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:49 +0100 Subject: staging: ft1000: GEt rid of PUSHORT typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 6 +++--- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 18 +++++++++--------- drivers/staging/ft1000/ft1000-usb/ft1000_hw.h | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 1 - 4 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index cadfb62229ef..6659bc77fe5b 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -656,7 +656,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, USHORT qtype; USHORT msgsz; struct pseudo_hdr *ppseudo_hdr; - PUSHORT pmsg; + u16 *pmsg; USHORT total_len; USHORT app_index; u16 status; @@ -766,8 +766,8 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, // Make sure we are within the limits of the slow queue memory limitation if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) { // Need to put sequence number plus new checksum for message - //pmsg = (PUSHORT)&dpram_command.dpram_blk.pseudohdr; - pmsg = (PUSHORT)&dpram_data->pseudohdr; + //pmsg = (u16 *)&dpram_command.dpram_blk.pseudohdr; + pmsg = (u16 *)&dpram_data->pseudohdr; ppseudo_hdr = (struct pseudo_hdr *)pmsg; total_len = msgsz+2; if (total_len & 0x1) { diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 2f195c8c9752..c964bf7fa1ea 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1209,7 +1209,7 @@ static int ft1000_copy_up_pkt (struct urb *urb) //DEBUG("ft1000_copy_up_pkt: transfer_buffer_length=%d, actual_buffer_len=%d\n", // urb->transfer_buffer_length, urb->actual_length); - chksum = (PUSHORT)ft1000dev->rx_buf; + chksum = (u16 *)ft1000dev->rx_buf; tempword = *chksum++; for (i=1; i<7; i++) @@ -1541,7 +1541,7 @@ static int ft1000_dsp_prov(void *arg) u16 i=0; struct prov_record *ptr; struct pseudo_hdr *ppseudo_hdr; - PUSHORT pmsg; + u16 *pmsg; u16 status; USHORT TempShortBuf [256]; @@ -1579,7 +1579,7 @@ static int ft1000_dsp_prov(void *arg) len = htons(len); len += PSEUDOSZ; - pmsg = (PUSHORT)ptr->pprov_data; + pmsg = (u16 *)ptr->pprov_data; ppseudo_hdr = (struct pseudo_hdr *)pmsg; // Insert slow queue sequence number ppseudo_hdr->seq_num = info->squeseqnum++; @@ -1626,7 +1626,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { struct drv_msg *pdrvmsg; u16 i; struct pseudo_hdr *ppseudo_hdr; - PUSHORT pmsg; + u16 *pmsg; u16 status; union { u8 byte[2]; @@ -1758,7 +1758,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { tempword = ntohs(pdrvmsg->length); info->DSPInfoBlklen = tempword; if (tempword < (MAX_DSP_SESS_REC-4) ) { - pmsg = (PUSHORT)&pdrvmsg->data[0]; + pmsg = (u16 *)&pdrvmsg->data[0]; for (i=0; i<((tempword+1)/2); i++) { DEBUG("FT1000:drivermsg:dsp info data = 0x%x\n", *pmsg); info->DSPInfoBlk[i+10] = *pmsg++; @@ -1790,10 +1790,10 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { // Put message into Slow Queue // Form Pseudo header - pmsg = (PUSHORT)info->DSPInfoBlk; + pmsg = (u16 *)info->DSPInfoBlk; *pmsg++ = 0; *pmsg++ = htons(info->DSPInfoBlklen+20+info->DSPInfoBlklen); - ppseudo_hdr = (struct pseudo_hdr *)(PUSHORT)&info->DSPInfoBlk[2]; + ppseudo_hdr = (struct pseudo_hdr *)(u16 *)&info->DSPInfoBlk[2]; ppseudo_hdr->length = htons(info->DSPInfoBlklen+4+info->DSPInfoBlklen); ppseudo_hdr->source = 0x10; ppseudo_hdr->destination = 0x20; @@ -1840,7 +1840,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { if ( (tempword & FT1000_DB_DPRAM_TX) == 0) { // Put message into Slow Queue // Form Pseudo header - pmsg = (PUSHORT)&tempbuffer[0]; + pmsg = (u16 *)&tempbuffer[0]; ppseudo_hdr = (struct pseudo_hdr *)pmsg; ppseudo_hdr->length = htons(0x0012); ppseudo_hdr->source = 0x10; @@ -1861,7 +1861,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { for (i=1; i<7; i++) { ppseudo_hdr->checksum ^= *pmsg++; } - pmsg = (PUSHORT)&tempbuffer[16]; + pmsg = (u16 *)&tempbuffer[16]; *pmsg++ = htons(RSP_DRV_ERR_RPT_MSG); *pmsg++ = htons(0x000e); *pmsg++ = htons(info->DSP_TIME[0]); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h index c58074131014..a2e19d25a7b5 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h @@ -4,7 +4,7 @@ #include "ft1000_usb.h" -extern u16 ft1000_read_register(struct usb_device *dev, PUSHORT Data, u8 nRegIndx); +extern u16 ft1000_read_register(struct usb_device *dev, u16 *Data, u8 nRegIndx); extern u16 ft1000_write_register(struct usb_device *dev, USHORT value, u8 nRegIndx); #endif diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 96665a783919..7ec8845ec601 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -102,7 +102,6 @@ struct prov_record { #define ULONG u32 /* WTF ??? */ #define BOOLEAN u8 #define PULONG u32 * -#define PUSHORT u16 * #define PCHAR u8 * #define UINT u32 -- cgit v1.2.3 From fc549a05e74edf9535862a4e517e63ade3908f75 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:50 +0100 Subject: staging: ft1000: Get rid of USHORT typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 8 +- .../staging/ft1000/ft1000-usb/ft1000_download.c | 114 ++++++++++----------- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 36 +++---- drivers/staging/ft1000/ft1000-usb/ft1000_hw.h | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 15 ++- 6 files changed, 88 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 6659bc77fe5b..f6b2e919b56b 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -653,12 +653,12 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, { IOCTL_DPRAM_BLK *dpram_data; //IOCTL_DPRAM_COMMAND dpram_command; - USHORT qtype; - USHORT msgsz; + u16 qtype; + u16 msgsz; struct pseudo_hdr *ppseudo_hdr; u16 *pmsg; - USHORT total_len; - USHORT app_index; + u16 total_len; + u16 app_index; u16 status; //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_SET_DPRAM called\n"); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index d7377eba7ede..d1bc53776d4b 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -126,7 +126,7 @@ struct dsp_image_info { static ULONG check_usb_db (struct ft1000_device *ft1000dev) { int loopcnt; - USHORT temp; + u16 temp; ULONG status; loopcnt = 0; @@ -190,7 +190,7 @@ static ULONG check_usb_db (struct ft1000_device *ft1000dev) // Function: get_handshake // // Parameters: struct ft1000_device - device structure -// USHORT expected_value - the handshake value expected +// u16 expected_value - the handshake value expected // // Returns: handshakevalue - success // HANDSHAKE_TIMEOUT_VALUE - failure @@ -200,9 +200,9 @@ static ULONG check_usb_db (struct ft1000_device *ft1000dev) // Notes: // //--------------------------------------------------------------------------- -static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_value) +static u16 get_handshake(struct ft1000_device *ft1000dev, u16 expected_value) { - USHORT handshake; + u16 handshake; int loopcnt; ULONG status=0; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -259,7 +259,7 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val // Function: put_handshake // // Parameters: struct ft1000_device - device structure -// USHORT handshake_value - handshake to be written +// u16 handshake_value - handshake to be written // // Returns: none // @@ -269,10 +269,10 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val // Notes: // //--------------------------------------------------------------------------- -static void put_handshake(struct ft1000_device *ft1000dev,USHORT handshake_value) +static void put_handshake(struct ft1000_device *ft1000dev,u16 handshake_value) { ULONG tempx; - USHORT tempword; + u16 tempword; ULONG status; @@ -280,18 +280,18 @@ static void put_handshake(struct ft1000_device *ft1000dev,USHORT handshake_value tempx = (ULONG)handshake_value; tempx = ntohl(tempx); - tempword = (USHORT)(tempx & 0xffff); + tempword = (u16)(tempx & 0xffff); status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 0); - tempword = (USHORT)(tempx >> 16); + tempword = (u16)(tempx >> 16); status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 1); status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL); } -static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected_value) +static u16 get_handshake_usb(struct ft1000_device *ft1000dev, u16 expected_value) { - USHORT handshake; + u16 handshake; int loopcnt; - USHORT temp; + u16 temp; ULONG status=0; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -327,7 +327,7 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected return HANDSHAKE_TIMEOUT_VALUE; } -static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_value) +static void put_handshake_usb(struct ft1000_device *ft1000dev,u16 handshake_value) { int i; @@ -346,11 +346,11 @@ static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_v // Notes: // //--------------------------------------------------------------------------- -static USHORT get_request_type(struct ft1000_device *ft1000dev) +static u16 get_request_type(struct ft1000_device *ft1000dev) { - USHORT request_type; + u16 request_type; ULONG status; - USHORT tempword; + u16 tempword; ULONG tempx; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -367,18 +367,18 @@ static USHORT get_request_type(struct ft1000_device *ft1000dev) tempx |= (tempword << 16); tempx = ntohl(tempx); } - request_type = (USHORT)tempx; + request_type = (u16)tempx; //DEBUG("get_request_type: request_type is %x\n", request_type); return request_type; } -static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) +static u16 get_request_type_usb(struct ft1000_device *ft1000dev) { - USHORT request_type; + u16 request_type; ULONG status; - USHORT tempword; + u16 tempword; ULONG tempx; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); if ( pft1000info->bootmode == 1) @@ -399,7 +399,7 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) tempx |= (tempword << 16); tempx = ntohl(tempx); } - request_type = (USHORT)tempx; + request_type = (u16)tempx; //DEBUG("get_request_type: request_type is %x\n", request_type); return request_type; @@ -421,7 +421,7 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev) static long get_request_value(struct ft1000_device *ft1000dev) { ULONG value; - USHORT tempword; + u16 tempword; ULONG status; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -450,7 +450,7 @@ static long get_request_value(struct ft1000_device *ft1000dev) static long get_request_value_usb(struct ft1000_device *ft1000dev) { ULONG value; - USHORT tempword; + u16 tempword; ULONG status; struct ft1000_info * pft1000info = netdev_priv(ft1000dev->net); @@ -516,10 +516,10 @@ static void put_request_value(struct ft1000_device *ft1000dev, long lvalue) // Notes: // //--------------------------------------------------------------------------- -static USHORT hdr_checksum(struct pseudo_hdr *pHdr) +static u16 hdr_checksum(struct pseudo_hdr *pHdr) { - USHORT *usPtr = (USHORT *)pHdr; - USHORT chksum; + u16 *usPtr = (u16 *)pHdr; + u16 chksum; chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^ @@ -533,7 +533,7 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr) // Function: write_blk // // Parameters: struct ft1000_device - device structure -// USHORT **pUsFile - DSP image file pointer in USHORT +// u16 **pUsFile - DSP image file pointer in u16 // u8 **pUcFile - DSP image file pointer in u8 // long word_length - lenght of the buffer to be written // to DPRAM @@ -546,20 +546,20 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr) // Notes: // //--------------------------------------------------------------------------- -static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, u8 **pUcFile, long word_length) +static ULONG write_blk (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) { ULONG Status = STATUS_SUCCESS; - USHORT dpram; + u16 dpram; long temp_word_length; int loopcnt, i, j; - USHORT *pTempFile; - USHORT tempword; - USHORT tempbuffer[64]; - USHORT resultbuffer[64]; + u16 *pTempFile; + u16 tempword; + u16 tempbuffer[64]; + u16 resultbuffer[64]; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length); - dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; tempword = *(*pUsFile); (*pUsFile)++; Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0); @@ -569,7 +569,7 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, u8 ** *pUcFile = *pUcFile + 4; word_length--; - tempword = (USHORT)word_length; + tempword = (u16)word_length; word_length = (word_length / 16) + 1; pTempFile = *pUsFile; temp_word_length = word_length; @@ -689,7 +689,7 @@ static void usb_dnld_complete (struct urb *urb) // Function: write_blk_fifo // // Parameters: struct ft1000_device - device structure -// USHORT **pUsFile - DSP image file pointer in USHORT +// u16 **pUsFile - DSP image file pointer in u16 // u8 **pUcFile - DSP image file pointer in u8 // long word_length - lenght of the buffer to be written // to DPRAM @@ -702,7 +702,7 @@ static void usb_dnld_complete (struct urb *urb) // Notes: // //--------------------------------------------------------------------------- -static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, u8 **pUcFile, long word_length) +static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) { ULONG Status = STATUS_SUCCESS; int byte_length; @@ -774,21 +774,21 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe { u16 Status = STATUS_SUCCESS; UINT uiState; - USHORT handshake; + u16 handshake; struct pseudo_hdr *pHdr; - USHORT usHdrLength; + u16 usHdrLength; long word_length; - USHORT request; - USHORT temp; - USHORT tempword; + u16 request; + u16 temp; + u16 tempword; struct dsp_file_hdr *pFileHdr5; struct dsp_image_info *pDspImageInfoV6 = NULL; long requested_version; BOOLEAN bGoodVersion; struct drv_msg *pMailBoxData; - USHORT *pUsData = NULL; - USHORT *pUsFile = NULL; + u16 *pUsData = NULL; + u16 *pUsFile = NULL; u8 *pUcFile = NULL; u8 *pBootEnd = NULL, *pCodeEnd= NULL; int imageN; @@ -798,7 +798,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe ULONG templong; ULONG image_chksum = 0; - USHORT dpram = 0; + u16 dpram = 0; u8 *pbuffer; struct prov_record *pprov_record; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -820,7 +820,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); - pUsFile = (USHORT *)(pFileStart + pFileHdr5->loader_offset); + pUsFile = (u16 *)(pFileStart + pFileHdr5->loader_offset); pUcFile = (u8 *)(pFileStart + pFileHdr5->loader_offset); pBootEnd = (u8 *)(pFileStart + pFileHdr5->loader_code_end); @@ -878,7 +878,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe case REQUEST_DONE_BL: DEBUG("FT1000:REQUEST_DONE_BL\n"); /* Reposition ptrs to beginning of code section */ - pUsFile = (USHORT *)(pBootEnd); + pUsFile = (u16 *)(pBootEnd); pUcFile = (u8 *)(pBootEnd); //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile); //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile); @@ -909,7 +909,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe /* * Position ASIC DPRAM auto-increment pointer. */ - dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; if (word_length & 0x1) word_length++; word_length = word_length / 2; @@ -988,7 +988,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe case REQUEST_DONE_CL: pft1000info->usbboot = 3; /* Reposition ptrs to beginning of provisioning section */ - pUsFile = (USHORT *)(pFileStart + pFileHdr5->commands_offset); + pUsFile = (u16 *)(pFileStart + pFileHdr5->commands_offset); pUcFile = (u8 *)(pFileStart + pFileHdr5->commands_offset); uiState = STATE_DONE_DWNLD; break; @@ -1027,7 +1027,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe /* * Position ASIC DPRAM auto-increment pointer. */ - dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; if (word_length & 0x1) word_length++; word_length = word_length / 2; @@ -1053,8 +1053,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe */ - pUsData = (USHORT *)&pMailBoxData->data[0]; - dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + pUsData = (u16 *)&pMailBoxData->data[0]; + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; if (word_length & 0x1) word_length++; @@ -1079,10 +1079,10 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe * Position ASIC DPRAM auto-increment pointer. */ - pUsFile = (USHORT *)(pFileStart + pFileHdr5->version_data_offset); + pUsFile = (u16 *)(pFileStart + pFileHdr5->version_data_offset); - dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC; + dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; if (word_length & 0x1) word_length++; @@ -1110,15 +1110,15 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe for (imageN = 0; imageN < pFileHdr5->nDspImages; imageN++) { - temp = (USHORT)(pDspImageInfoV6->version); + temp = (u16)(pDspImageInfoV6->version); templong = temp; - temp = (USHORT)(pDspImageInfoV6->version >> 16); + temp = (u16)(pDspImageInfoV6->version >> 16); templong |= (temp << 16); if (templong == (ULONG)requested_version) { bGoodVersion = TRUE; DEBUG("FT1000:download: bGoodVersion is TRUE\n"); - pUsFile = (USHORT *)(pFileStart + pDspImageInfoV6->begin_offset); + pUsFile = (u16 *)(pFileStart + pDspImageInfoV6->begin_offset); pUcFile = (u8 *)(pFileStart + pDspImageInfoV6->begin_offset); pCodeEnd = (u8 *)(pFileStart + pDspImageInfoV6->end_offset); run_address = pDspImageInfoV6->run_address; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index c964bf7fa1ea..709f8da12454 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -160,7 +160,7 @@ u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegInd // Notes: // //--------------------------------------------------------------------------- -u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx) +u16 ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, u16 nRegIndx) { u16 ret = STATUS_SUCCESS; @@ -196,7 +196,7 @@ u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRe // //--------------------------------------------------------------------------- -u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt) +u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt) { u16 ret = STATUS_SUCCESS; @@ -235,7 +235,7 @@ u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer // Notes: // //--------------------------------------------------------------------------- -u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt) +u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt) { u16 ret = STATUS_SUCCESS; @@ -272,7 +272,7 @@ u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffe // Notes: // //--------------------------------------------------------------------------- -u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, u8 highlow) +u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow) { u16 ret = STATUS_SUCCESS; @@ -320,7 +320,7 @@ u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer // Notes: // //--------------------------------------------------------------------------- -u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow) +u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u8 highlow) { u16 ret = STATUS_SUCCESS; @@ -365,10 +365,10 @@ u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT va // Notes: // //--------------------------------------------------------------------------- -u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer) +u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer) { u8 buf[16]; - USHORT pos; + u16 pos; u16 ret = STATUS_SUCCESS; //DEBUG("fix_ft1000_read_dpram32: indx: %d \n", indx); @@ -414,11 +414,11 @@ u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *bu // Notes: // //--------------------------------------------------------------------------- -u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer) +u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer) { - USHORT pos1; - USHORT pos2; - USHORT i; + u16 pos1; + u16 pos2; + u16 i; u8 buf[32]; u8 resultbuffer[32]; u8 *pdata; @@ -494,7 +494,7 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *b static void card_reset_dsp (struct ft1000_device *ft1000dev, BOOLEAN value) { u16 status = STATUS_SUCCESS; - USHORT tempword; + u16 tempword; status = ft1000_write_register (ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL); status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_SUP_CTRL); @@ -593,7 +593,7 @@ void CardSendCommand(struct ft1000_device *ft1000dev, void *ptempbuffer, int siz int dsp_reload(struct ft1000_device *ft1000dev) { u16 status; - USHORT tempword; + u16 tempword; ULONG templong; struct ft1000_info *pft1000info; @@ -1543,7 +1543,7 @@ static int ft1000_dsp_prov(void *arg) struct pseudo_hdr *ppseudo_hdr; u16 *pmsg; u16 status; - USHORT TempShortBuf [256]; + u16 TempShortBuf [256]; DEBUG("*** DspProv Entered\n"); @@ -1876,7 +1876,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { *pmsg++ = convert.wrd; *pmsg++ = htons(info->DrvErrNum); - CardSendCommand (dev, (unsigned char*)&tempbuffer[0], (USHORT)(0x0012 + PSEUDOSZ)); + CardSendCommand (dev, (unsigned char*)&tempbuffer[0], (u16)(0x0012 + PSEUDOSZ)); info->DrvErrNum = 0; } info->DrvMsgPend = 0; @@ -1907,9 +1907,9 @@ int ft1000_poll(void* dev_id) { u16 status; u16 size; int i; - USHORT data; - USHORT modulo; - USHORT portid; + u16 data; + u16 modulo; + u16 portid; u16 nxtph; struct dpram_blk *pdpram_blk; struct pseudo_hdr *ppseudo_hdr; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h index a2e19d25a7b5..ab9312f9f326 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.h @@ -5,6 +5,6 @@ #include "ft1000_usb.h" extern u16 ft1000_read_register(struct usb_device *dev, u16 *Data, u8 nRegIndx); -extern u16 ft1000_write_register(struct usb_device *dev, USHORT value, u8 nRegIndx); +extern u16 ft1000_write_register(struct usb_device *dev, u16 value, u8 nRegIndx); #endif diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index dda0e33b4864..f665640058ae 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -38,7 +38,7 @@ //#endif -u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, USHORT indx, +u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 7ec8845ec601..2e4868666e3d 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -98,7 +98,6 @@ struct prov_record { /*end of Jim*/ #define DEBUG(args...) printk(KERN_INFO args) -#define USHORT u16 #define ULONG u32 /* WTF ??? */ #define BOOLEAN u8 #define PULONG u32 * @@ -561,13 +560,13 @@ struct dpram_blk { } __attribute__ ((packed)); u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegIndx); -u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx); -u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt); -u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, USHORT cnt); -u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer, u8 highlow); -u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow); -u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer); -u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, u8 *buffer); +u16 ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, u16 nRegIndx); +u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt); +u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt); +u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow); +u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u8 highlow); +u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer); +u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer); extern void *pFileStart; extern size_t FileLength; -- cgit v1.2.3 From d44d76f93dafdbaeac0f1d541f3867777de65c8a Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:51 +0100 Subject: staging: ft1000: Get rid of PULONG typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 2e4868666e3d..bc0022325df2 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -100,7 +100,6 @@ struct prov_record { #define ULONG u32 /* WTF ??? */ #define BOOLEAN u8 -#define PULONG u32 * #define PCHAR u8 * #define UINT u32 -- cgit v1.2.3 From 84b7801d135ca90903df3a9170b9db5978fe8fce Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:52 +0100 Subject: staging: ft1000: Get rid of ULONG typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- .../staging/ft1000/ft1000-usb/ft1000_download.c | 52 +++++++++++----------- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 3 +- 3 files changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index d1bc53776d4b..0a2b833bfb3e 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -123,11 +123,11 @@ struct dsp_image_info { // Notes: // //--------------------------------------------------------------------------- -static ULONG check_usb_db (struct ft1000_device *ft1000dev) +static u32 check_usb_db (struct ft1000_device *ft1000dev) { int loopcnt; u16 temp; - ULONG status; + u32 status; loopcnt = 0; while (loopcnt < 10) @@ -204,7 +204,7 @@ static u16 get_handshake(struct ft1000_device *ft1000dev, u16 expected_value) { u16 handshake; int loopcnt; - ULONG status=0; + u32 status=0; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); loopcnt = 0; @@ -271,13 +271,13 @@ static u16 get_handshake(struct ft1000_device *ft1000dev, u16 expected_value) //--------------------------------------------------------------------------- static void put_handshake(struct ft1000_device *ft1000dev,u16 handshake_value) { - ULONG tempx; + u32 tempx; u16 tempword; - ULONG status; + u32 status; - tempx = (ULONG)handshake_value; + tempx = (u32)handshake_value; tempx = ntohl(tempx); tempword = (u16)(tempx & 0xffff); @@ -292,7 +292,7 @@ static u16 get_handshake_usb(struct ft1000_device *ft1000dev, u16 expected_value u16 handshake; int loopcnt; u16 temp; - ULONG status=0; + u32 status=0; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); loopcnt = 0; @@ -349,9 +349,9 @@ static void put_handshake_usb(struct ft1000_device *ft1000dev,u16 handshake_valu static u16 get_request_type(struct ft1000_device *ft1000dev) { u16 request_type; - ULONG status; + u32 status; u16 tempword; - ULONG tempx; + u32 tempx; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); if ( pft1000info->bootmode == 1) @@ -377,9 +377,9 @@ static u16 get_request_type(struct ft1000_device *ft1000dev) static u16 get_request_type_usb(struct ft1000_device *ft1000dev) { u16 request_type; - ULONG status; + u32 status; u16 tempword; - ULONG tempx; + u32 tempx; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); if ( pft1000info->bootmode == 1) { @@ -420,9 +420,9 @@ static u16 get_request_type_usb(struct ft1000_device *ft1000dev) //--------------------------------------------------------------------------- static long get_request_value(struct ft1000_device *ft1000dev) { - ULONG value; + u32 value; u16 tempword; - ULONG status; + u32 status; struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); @@ -449,9 +449,9 @@ static long get_request_value(struct ft1000_device *ft1000dev) #if 0 static long get_request_value_usb(struct ft1000_device *ft1000dev) { - ULONG value; + u32 value; u16 tempword; - ULONG status; + u32 status; struct ft1000_info * pft1000info = netdev_priv(ft1000dev->net); if (pft1000info->usbboot == 2) { @@ -490,8 +490,8 @@ static long get_request_value_usb(struct ft1000_device *ft1000dev) //--------------------------------------------------------------------------- static void put_request_value(struct ft1000_device *ft1000dev, long lvalue) { - ULONG tempx; - ULONG status; + u32 tempx; + u32 status; tempx = ntohl(lvalue); status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempx); @@ -546,9 +546,9 @@ static u16 hdr_checksum(struct pseudo_hdr *pHdr) // Notes: // //--------------------------------------------------------------------------- -static ULONG write_blk (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) +static u32 write_blk (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) { - ULONG Status = STATUS_SUCCESS; + u32 Status = STATUS_SUCCESS; u16 dpram; long temp_word_length; int loopcnt, i, j; @@ -702,9 +702,9 @@ static void usb_dnld_complete (struct urb *urb) // Notes: // //--------------------------------------------------------------------------- -static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) +static u32 write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) { - ULONG Status = STATUS_SUCCESS; + u32 Status = STATUS_SUCCESS; int byte_length; long aligncnt; @@ -770,7 +770,7 @@ static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 // Returns: status - return code //--------------------------------------------------------------------------- -u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLength) +u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLength) { u16 Status = STATUS_SUCCESS; UINT uiState; @@ -795,8 +795,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe long loader_code_address, loader_code_size = 0; long run_address = 0, run_size = 0; - ULONG templong; - ULONG image_chksum = 0; + u32 templong; + u32 image_chksum = 0; u16 dpram = 0; u8 *pbuffer; @@ -1114,7 +1114,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe templong = temp; temp = (u16)(pDspImageInfoV6->version >> 16); templong |= (temp << 16); - if (templong == (ULONG)requested_version) + if (templong == (u32)requested_version) { bGoodVersion = TRUE; DEBUG("FT1000:download: bGoodVersion is TRUE\n"); @@ -1123,7 +1123,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLe pCodeEnd = (u8 *)(pFileStart + pDspImageInfoV6->end_offset); run_address = pDspImageInfoV6->run_address; run_size = pDspImageInfoV6->image_size; - image_chksum = (ULONG)pDspImageInfoV6->checksum; + image_chksum = (u32)pDspImageInfoV6->checksum; break; } pDspImageInfoV6++; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 709f8da12454..f97826d2acc0 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -594,7 +594,7 @@ int dsp_reload(struct ft1000_device *ft1000dev) { u16 status; u16 tempword; - ULONG templong; + u32 templong; struct ft1000_info *pft1000info; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index bc0022325df2..64af71078789 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -98,7 +98,6 @@ struct prov_record { /*end of Jim*/ #define DEBUG(args...) printk(KERN_INFO args) -#define ULONG u32 /* WTF ??? */ #define BOOLEAN u8 #define PCHAR u8 * #define UINT u32 @@ -572,7 +571,7 @@ extern size_t FileLength; extern int numofmsgbuf; int ft1000_close (struct net_device *dev); -u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG FileLength); +u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLength); extern struct list_head freercvpool; extern spinlock_t free_buff_lock; // lock to arbitrate free buffer list for receive command data -- cgit v1.2.3 From 81584137d8c97ab6bd87c2b4091f6105f600e66e Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 4 Nov 2010 07:37:13 +0100 Subject: staging: ft1000: Get rid of BOOLEAN typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_download.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 4 ++-- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 7 +++---- 5 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index f6b2e919b56b..920ca52d6e4b 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -64,7 +64,7 @@ spinlock_t free_buff_lock; int numofmsgbuf = 0; // Global variable to indicate that all provisioning data is sent to DSP -//BOOLEAN fProvComplete; +//bool fProvComplete; // // Table of entry-point routines for char device diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 0a2b833bfb3e..11b7c203f098 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -785,7 +785,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng struct dsp_file_hdr *pFileHdr5; struct dsp_image_info *pDspImageInfoV6 = NULL; long requested_version; - BOOLEAN bGoodVersion; + bool bGoodVersion; struct drv_msg *pMailBoxData; u16 *pUsData = NULL; u16 *pUsFile = NULL; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index f97826d2acc0..1a517dd8e7ad 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -491,7 +491,7 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buff // // Returns: None //----------------------------------------------------------------------- -static void card_reset_dsp (struct ft1000_device *ft1000dev, BOOLEAN value) +static void card_reset_dsp (struct ft1000_device *ft1000dev, bool value) { u16 status = STATUS_SUCCESS; u16 tempword; @@ -1479,7 +1479,7 @@ static int ft1000_chkcard (struct ft1000_device *dev) { // = 1 (successful) // //--------------------------------------------------------------------------- -static BOOLEAN ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int maxsz, u16 *pnxtph) { +static bool ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int maxsz, u16 *pnxtph) { u16 size, ret; u16 *ppseudohdr; int i; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 4e81bdd6902a..41bbe991f0de 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -36,7 +36,7 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static BOOLEAN gPollingfailed = FALSE; +static bool gPollingfailed = FALSE; int ft1000_poll_thread(void *arg) { int ret = STATUS_SUCCESS; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 64af71078789..cf2c42ecdf35 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -98,7 +98,6 @@ struct prov_record { /*end of Jim*/ #define DEBUG(args...) printk(KERN_INFO args) -#define BOOLEAN u8 #define PCHAR u8 * #define UINT u32 @@ -488,9 +487,9 @@ struct ft1000_info { unsigned char usbboot; unsigned short dspalive; u16 ASIC_ID; - BOOLEAN fProvComplete; - BOOLEAN fCondResetPend; - BOOLEAN fAppMsgPend; + bool fProvComplete; + bool fCondResetPend; + bool fAppMsgPend; char *pfwimg; int fwimgsz; u16 DrvErrNum; -- cgit v1.2.3 From c613f6f50f9d98015b8640f9aeff3b0c8e07548e Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:54 +0100 Subject: staging: ft1000: Get rid of PCHAR typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 1a517dd8e7ad..b41884e60d07 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -726,7 +726,7 @@ static int ft1000_reset_card (struct net_device *dev) // Initialize DSP heartbeat area to ho ft1000_write_dpram16(ft1000dev, FT1000_MAG_HI_HO, ho_mag, FT1000_MAG_HI_HO_INDX); - ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (PCHAR)&tempword, FT1000_MAG_HI_HO_INDX); + ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (u8 *)&tempword, FT1000_MAG_HI_HO_INDX); DEBUG("ft1000_hw:ft1000_reset_card:hi_ho value = 0x%x\n", tempword); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index cf2c42ecdf35..d1477e54f828 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -98,7 +98,6 @@ struct prov_record { /*end of Jim*/ #define DEBUG(args...) printk(KERN_INFO args) -#define PCHAR u8 * #define UINT u32 #define FALSE 0 -- cgit v1.2.3 From e09f138e06d4f1ea63079e25bb55ee1dacff7933 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 3 Nov 2010 11:19:55 +0100 Subject: staging: ft1000: Get rid of UINT typedef usage. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_download.c | 6 +++--- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 11b7c203f098..e4905ad2badc 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -773,7 +773,7 @@ static u32 write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 ** u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLength) { u16 Status = STATUS_SUCCESS; - UINT uiState; + u32 uiState; u16 handshake; struct pseudo_hdr *pHdr; u16 usHdrLength; @@ -1181,14 +1181,14 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng // Get buffer for provisioning data pbuffer = kmalloc((usHdrLength + sizeof(struct pseudo_hdr)), GFP_ATOMIC); if (pbuffer) { - memcpy(pbuffer, (void *)pUcFile, (UINT)(usHdrLength + sizeof(struct pseudo_hdr))); + memcpy(pbuffer, (void *)pUcFile, (u32)(usHdrLength + sizeof(struct pseudo_hdr))); // link provisioning data pprov_record = kmalloc(sizeof(struct prov_record), GFP_ATOMIC); if (pprov_record) { pprov_record->pprov_data = pbuffer; list_add_tail (&pprov_record->list, &pft1000info->prov_list); // Move to next entry if available - pUcFile = (u8 *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); + pUcFile = (u8 *)((unsigned long)pUcFile + (u32)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) { uiState = STATE_DONE_FILE; } diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index d1477e54f828..a07db26441f1 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -98,8 +98,6 @@ struct prov_record { /*end of Jim*/ #define DEBUG(args...) printk(KERN_INFO args) -#define UINT u32 - #define FALSE 0 #define TRUE 1 -- cgit v1.2.3 From 5712dc7fc812d1bdbc5e634d389bc759d4e7550c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 3 Nov 2010 10:59:02 +0100 Subject: staging: batman-adv: Use linux/etherdevice.h address helper functions Replace custom ethernet address check functions by calls to the helpers in linux/etherdevice.h In one case where the address was tested for broadcast and multicast address, the broadcast address check can be omitted as broadcast is also a multicast address. The patch is only compile-tested. Cc: Marek Lindner Cc: Simon Wunderlich Cc: Andrew Lunn Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/main.c | 12 +----------- drivers/staging/batman-adv/main.h | 3 +-- drivers/staging/batman-adv/routing.c | 16 ++++++++-------- drivers/staging/batman-adv/soft-interface.c | 2 +- drivers/staging/batman-adv/vis.c | 4 ++-- 5 files changed, 13 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 0587940d2723..6ea64200ad16 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -149,7 +149,7 @@ void dec_module_count(void) int compare_orig(void *data1, void *data2) { - return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); + return (compare_ether_addr(data1, data2) == 0 ? 1 : 0); } /* hashfunction to choose an entry in a hash table of given size */ @@ -192,16 +192,6 @@ int is_my_mac(uint8_t *addr) } -int is_bcast(uint8_t *addr) -{ - return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff); -} - -int is_mcast(uint8_t *addr) -{ - return *addr & 0x01; -} - module_init(batman_init); module_exit(batman_exit); diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index 5e3f51681f5e..14d567d4911a 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -109,6 +109,7 @@ #include /* mutex */ #include /* needed by all modules */ #include /* netdevice */ +#include #include /* ethernet header */ #include /* poll_table */ #include /* kernel threads */ @@ -138,8 +139,6 @@ void dec_module_count(void); int compare_orig(void *data1, void *data2); int choose_orig(void *data, int32_t size); int is_my_mac(uint8_t *addr); -int is_bcast(uint8_t *addr); -int is_mcast(uint8_t *addr); #ifdef CONFIG_BATMAN_ADV_DEBUG int debug_log(struct bat_priv *bat_priv, char *fmt, ...); diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 90102631330b..d42c16559dff 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -756,11 +756,11 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) + if (!is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP; /* create a copy of the skb, if needed, to modify it. */ @@ -933,11 +933,11 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) + if (is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP; /* not for me */ @@ -1107,11 +1107,11 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) + if (is_broadcast_ether_addr(ethhdr->h_dest)) return -1; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return -1; /* not for me */ @@ -1283,11 +1283,11 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) + if (!is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP; /* ignore broadcasts sent by myself */ diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 3904db9ce7b1..820e14159dd3 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -140,7 +140,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) hna_local_add(soft_iface, ethhdr->h_source); /* ethernet packet should be broadcasted */ - if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { + if (is_multicast_ether_addr(ethhdr->h_dest)) { if (!bat_priv->primary_if) goto dropped; diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index 4473cc8ed6b0..395f1109d606 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -469,7 +469,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv, int are_target = 0; /* clients shall not broadcast. */ - if (is_bcast(vis_packet->target_orig)) + if (is_broadcast_ether_addr(vis_packet->target_orig)) return; /* Are we the target for this VIS packet? */ @@ -746,7 +746,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) ETH_ALEN); packet->ttl--; - if (is_bcast(packet->target_orig)) + if (is_broadcast_ether_addr(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); -- cgit v1.2.3 From 391a169e99c789d59ef2a6b0cb80d1c6f63238dd Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 4 Nov 2010 22:27:42 +0100 Subject: pohmelfs: remove unneeded conditionals before calls to crypto_destroy_tfm wrappers. Hi, crypto_free_hash() and crypto_free_ablkcipher() are just wrappers around crypto_free_tfm() which is itself just a wrapper around crypto_destroy_tfm(). Passing crypto_destroy_tfm() a NULL pointer is valid, so there's no reason to check for NULL first. Removing the unneeded conditionals (which is what the patch does) brings us the benefit of having to execute a few fewer test/branch instructions and also reduces object code size slightly: before: text data bss dec hex filename 8630 112 3312 12054 2f16 drivers/staging/pohmelfs/crypto.o 0000000000000cbe : cbe: 55 push %rbp cbf: 48 89 e5 mov %rsp,%rbp cc2: 53 push %rbx cc3: 48 83 ec 08 sub $0x8,%rsp cc7: e8 00 00 00 00 callq ccc ccc: 48 ff 05 00 00 00 00 incq 0x0(%rip) # cd3 cd3: 48 89 fb mov %rdi,%rbx cd6: 48 8b 7f 20 mov 0x20(%rdi),%rdi cda: 48 85 ff test %rdi,%rdi cdd: 74 0c je ceb cdf: 48 ff 05 00 00 00 00 incq 0x0(%rip) # ce6 ce6: e8 58 fa ff ff callq 743 ceb: 48 8b 7b 28 mov 0x28(%rbx),%rdi cef: 48 85 ff test %rdi,%rdi cf2: 75 09 jne cfd cf4: 48 ff 05 00 00 00 00 incq 0x0(%rip) # cfb cfb: eb 16 jmp d13 cfd: 48 89 fe mov %rdi,%rsi d00: 48 ff 05 00 00 00 00 incq 0x0(%rip) # d07 d07: e8 00 00 00 00 callq d0c d0c: 48 ff 05 00 00 00 00 incq 0x0(%rip) # d13 d13: 48 8b 7b 18 mov 0x18(%rbx),%rdi d17: e8 00 00 00 00 callq d1c d1c: 48 ff 05 00 00 00 00 incq 0x0(%rip) # d23 d23: 5e pop %rsi d24: 5b pop %rbx d25: c9 leaveq d26: c3 retq after: text data bss dec hex filename 8604 112 3296 12012 2eec drivers/staging/pohmelfs/crypto.o 0000000000000cbe : cbe: 55 push %rbp cbf: 48 89 e5 mov %rsp,%rbp cc2: 53 push %rbx cc3: 48 83 ec 08 sub $0x8,%rsp cc7: e8 00 00 00 00 callq ccc ccc: 48 ff 05 00 00 00 00 incq 0x0(%rip) # cd3 cd3: 48 89 fb mov %rdi,%rbx cd6: 48 8b 7f 20 mov 0x20(%rdi),%rdi cda: e8 64 fa ff ff callq 743 cdf: 48 8b 7b 28 mov 0x28(%rbx),%rdi ce3: 48 ff 05 00 00 00 00 incq 0x0(%rip) # cea cea: 48 89 fe mov %rdi,%rsi ced: e8 00 00 00 00 callq cf2 cf2: 48 8b 7b 18 mov 0x18(%rbx),%rdi cf6: 48 ff 05 00 00 00 00 incq 0x0(%rip) # cfd cfd: e8 00 00 00 00 callq d02 d02: 48 ff 05 00 00 00 00 incq 0x0(%rip) # d09 d09: 5e pop %rsi d0a: 5b pop %rbx d0b: c9 leaveq d0c: c3 retq Signed-off-by: Jesper Juhl Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pohmelfs/crypto.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/pohmelfs/crypto.c b/drivers/staging/pohmelfs/crypto.c index 2fdb3e01460d..6540864216c8 100644 --- a/drivers/staging/pohmelfs/crypto.c +++ b/drivers/staging/pohmelfs/crypto.c @@ -130,10 +130,8 @@ err_out_exit: void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e) { - if (e->hash) - crypto_free_hash(e->hash); - if (e->cipher) - crypto_free_ablkcipher(e->cipher); + crypto_free_hash(e->hash); + crypto_free_ablkcipher(e->cipher); kfree(e->data); } -- cgit v1.2.3 From ce36cedab3f865969653bf4360f7e364ab0937e4 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 19:56:40 +0000 Subject: staging/easycap: Remove obsolete routines The so-called bridger routine has proved unnecessary following general improvements elsewhere. The explain_() functions were a convenience during early development, but are unnecessary and inappropriate now. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 36 +- drivers/staging/easycap/easycap_debug.h | 4 +- drivers/staging/easycap/easycap_ioctl.c | 695 ++--------------------------- drivers/staging/easycap/easycap_low.c | 23 - drivers/staging/easycap/easycap_main.c | 131 +----- drivers/staging/easycap/easycap_settings.c | 4 +- drivers/staging/easycap/easycap_sound.c | 9 +- drivers/staging/easycap/easycap_testcard.c | 290 ++++++------ 8 files changed, 198 insertions(+), 994 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index f3c827eb0abe..9fb0f64d5477 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -42,12 +42,6 @@ #if (!defined(EASYCAP_H)) #define EASYCAP_H -#if defined(EASYCAP_DEBUG) -#if (9 < EASYCAP_DEBUG) -#error Debug levels 0 to 9 are okay.\ - To achieve higher levels, remove this trap manually from easycap.h -#endif -#endif /*EASYCAP_DEBUG*/ /*---------------------------------------------------------------------------*/ /* * THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED: @@ -56,21 +50,9 @@ #undef PREFER_NTSC #undef EASYCAP_TESTCARD #undef EASYCAP_TESTTONE -#undef LOCKFRAME #undef NOREADBACK #undef AUDIOTIME /*---------------------------------------------------------------------------*/ -/* - * - * DEFINE BRIDGER TO ACTIVATE THE ROUTINE FOR BRIDGING VIDEOTAPE DROPOUTS. - * - * *** UNDER DEVELOPMENT/TESTING - NOT READY YET!*** - * - */ -/*---------------------------------------------------------------------------*/ -#undef BRIDGER -/*---------------------------------------------------------------------------*/ - #include #include #include @@ -135,7 +117,7 @@ #define USB_EASYCAP_VENDOR_ID 0x05e1 #define USB_EASYCAP_PRODUCT_ID 0x0408 -#define EASYCAP_DRIVER_VERSION "0.8.21" +#define EASYCAP_DRIVER_VERSION "0.8.41" #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60" #define USB_SKEL_MINOR_BASE 192 @@ -291,8 +273,6 @@ unsigned int audio_buffer_page_many; __s16 oldaudio; #endif /*UPSAMPLE*/ -struct easycap_format easycap_format[1 + SETTINGS_MANY]; - int ilk; bool microphone; @@ -307,10 +287,6 @@ struct usb_interface *pusb_interface; struct kref kref; -struct mutex mutex_mmap_video[FRAME_BUFFER_MANY]; -struct mutex mutex_timeval0; -struct mutex mutex_timeval1; - int queued[FRAME_BUFFER_MANY]; int done[FRAME_BUFFER_MANY]; @@ -347,8 +323,6 @@ int video_idle; int video_eof; int video_junk; -int fudge; - struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY]; struct data_buffer \ field_buffer[FIELD_BUFFER_MANY][(FIELD_BUFFER_SIZE/PAGE_SIZE)]; @@ -489,11 +463,7 @@ int kill_video_urbs(struct easycap *); int field2frame(struct easycap *); int redaub(struct easycap *, void *, void *, \ int, int, __u8, __u8, bool); -void debrief(struct easycap *); -void sayreadonly(struct easycap *); void easycap_testcard(struct easycap *, int); -int explain_ioctl(__u32); -int explain_cid(__u32); int fillin_formats(void); int adjust_standard(struct easycap *, v4l2_std_id); int adjust_format(struct easycap *, __u32, __u32, __u32, \ @@ -595,7 +565,7 @@ unsigned long long int remainder; #if defined(EASYCAP_DEBUG) #define JOT(n, format, args...) do { \ - if (n <= easycap_debug) { \ + if (n <= debug) { \ printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \ } \ } while (0) @@ -603,8 +573,6 @@ unsigned long long int remainder; #define JOT(n, format, args...) do {} while (0) #endif /*EASYCAP_DEBUG*/ -#define POUT JOT(8, ":-(in file %s line %4i\n", __FILE__, __LINE__) - #define MICROSECONDS(X, Y) \ ((1000000*((long long int)(X.tv_sec - Y.tv_sec))) + \ (long long int)(X.tv_usec - Y.tv_usec)) diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h index 1d10d7ea7d68..3e9b66a66076 100644 --- a/drivers/staging/easycap/easycap_debug.h +++ b/drivers/staging/easycap/easycap_debug.h @@ -1,6 +1,6 @@ /***************************************************************************** * * -* easycap_debug.h * +* debug.h * * * *****************************************************************************/ /* @@ -24,4 +24,4 @@ * */ /*****************************************************************************/ -extern int easycap_debug; +extern int debug; diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 9a42ae02cd5d..5b038b8614d7 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -857,10 +857,8 @@ case VIDIOC_QUERYCAP: { &v4l2_capability.bus_info[0]); } if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \ - sizeof(struct v4l2_capability))) { - POUT; + sizeof(struct v4l2_capability))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -871,10 +869,8 @@ case VIDIOC_ENUMINPUT: { JOT(8, "VIDIOC_ENUMINPUT\n"); if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \ - sizeof(struct v4l2_input))) { - POUT; + sizeof(struct v4l2_input))) return -EFAULT; - } index = v4l2_input.index; memset(&v4l2_input, 0, sizeof(struct v4l2_input)); @@ -959,10 +955,8 @@ case VIDIOC_ENUMINPUT: { } if (0 != copy_to_user((void __user *)arg, &v4l2_input, \ - sizeof(struct v4l2_input))) { - POUT; + sizeof(struct v4l2_input))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -972,10 +966,8 @@ case VIDIOC_G_INPUT: { JOT(8, "VIDIOC_G_INPUT\n"); index = (__u32)peasycap->input; JOT(8, "user is told: %i\n", index); - if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) { - POUT; + if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -985,10 +977,8 @@ case VIDIOC_S_INPUT: JOT(8, "VIDIOC_S_INPUT\n"); - if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) { - POUT; + if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) return -EFAULT; - } JOT(8, "user requests input %i\n", index); @@ -1019,10 +1009,8 @@ case VIDIOC_ENUMAUDOUT: { JOT(8, "VIDIOC_ENUMAUDOUT\n"); if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \ - sizeof(struct v4l2_audioout))) { - POUT; + sizeof(struct v4l2_audioout))) return -EFAULT; - } if (0 != v4l2_audioout.index) return -EINVAL; @@ -1031,10 +1019,8 @@ case VIDIOC_ENUMAUDOUT: { strcpy(&v4l2_audioout.name[0], "Soundtrack"); if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \ - sizeof(struct v4l2_audioout))) { - POUT; + sizeof(struct v4l2_audioout))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1045,10 +1031,8 @@ case VIDIOC_QUERYCTRL: { JOT(8, "VIDIOC_QUERYCTRL\n"); if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \ - sizeof(struct v4l2_queryctrl))) { - POUT; + sizeof(struct v4l2_queryctrl))) return -EFAULT; - } i1 = 0; while (0xFFFFFFFF != easycap_control[i1].id) { @@ -1066,10 +1050,8 @@ case VIDIOC_QUERYCTRL: { return -EINVAL; } if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \ - sizeof(struct v4l2_queryctrl))) { - POUT; + sizeof(struct v4l2_queryctrl))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1085,10 +1067,8 @@ case VIDIOC_G_CTRL: { JOT(8, "VIDIOC_G_CTRL\n"); if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ - sizeof(struct v4l2_control))) { - POUT; + sizeof(struct v4l2_control))) return -EFAULT; - } switch (v4l2_control.id) { case V4L2_CID_BRIGHTNESS: { @@ -1127,15 +1107,12 @@ case VIDIOC_G_CTRL: { default: { SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \ v4l2_control.id); - explain_cid(v4l2_control.id); return -EINVAL; } } if (0 != copy_to_user((void __user *)arg, &v4l2_control, \ - sizeof(struct v4l2_control))) { - POUT; + sizeof(struct v4l2_control))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1151,10 +1128,8 @@ case VIDIOC_S_CTRL: JOT(8, "VIDIOC_S_CTRL\n"); if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ - sizeof(struct v4l2_control))) { - POUT; + sizeof(struct v4l2_control))) return -EFAULT; - } switch (v4l2_control.id) { case V4L2_CID_BRIGHTNESS: { @@ -1203,10 +1178,9 @@ case VIDIOC_S_CTRL: default: { SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \ v4l2_control.id); - explain_cid(v4l2_control.id); - return -EINVAL; - } + return -EINVAL; } + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1222,10 +1196,8 @@ case VIDIOC_ENUM_FMT: { JOT(8, "VIDIOC_ENUM_FMT\n"); if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \ - sizeof(struct v4l2_fmtdesc))) { - POUT; + sizeof(struct v4l2_fmtdesc))) return -EFAULT; - } index = v4l2_fmtdesc.index; memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc)); @@ -1282,10 +1254,8 @@ case VIDIOC_ENUM_FMT: { } } if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \ - sizeof(struct v4l2_fmtdesc))) { - POUT; + sizeof(struct v4l2_fmtdesc))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1305,15 +1275,11 @@ case VIDIOC_G_FMT: { JOT(8, "VIDIOC_G_FMT\n"); if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ - sizeof(struct v4l2_format))) { - POUT; + sizeof(struct v4l2_format))) return -EFAULT; - } - if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - POUT; + if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - } memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -1324,10 +1290,8 @@ case VIDIOC_G_FMT: { &easycap_format[peasycap->format_offset].name[0]); if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ - sizeof(struct v4l2_format))) { - POUT; + sizeof(struct v4l2_format))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1347,10 +1311,8 @@ case VIDIOC_S_FMT: { } if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ - sizeof(struct v4l2_format))) { - POUT; + sizeof(struct v4l2_format))) return -EFAULT; - } best_format = adjust_format(peasycap, \ v4l2_format.fmt.pix.width, \ @@ -1371,10 +1333,8 @@ case VIDIOC_S_FMT: { JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]); if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ - sizeof(struct v4l2_format))) { - POUT; + sizeof(struct v4l2_format))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1384,10 +1344,8 @@ case VIDIOC_CROPCAP: { JOT(8, "VIDIOC_CROPCAP\n"); if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \ - sizeof(struct v4l2_cropcap))) { - POUT; + sizeof(struct v4l2_cropcap))) return -EFAULT; - } if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); @@ -1408,10 +1366,8 @@ case VIDIOC_CROPCAP: { JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \ - sizeof(struct v4l2_cropcap))) { - POUT; + sizeof(struct v4l2_cropcap))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1444,10 +1400,8 @@ case VIDIOC_ENUMSTD: { JOT(8, "VIDIOC_ENUMSTD\n"); if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \ - sizeof(struct v4l2_standard))) { - POUT; + sizeof(struct v4l2_standard))) return -EFAULT; - } index = v4l2_standard.index; last3 = last2; last2 = last1; last1 = last0; last0 = index; @@ -1477,10 +1431,8 @@ case VIDIOC_ENUMSTD: { v4l2_standard.index = index; if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \ - sizeof(struct v4l2_standard))) { - POUT; + sizeof(struct v4l2_standard))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1491,10 +1443,8 @@ case VIDIOC_G_STD: { JOT(8, "VIDIOC_G_STD\n"); if (0 != copy_from_user(&std_id, (void __user *)arg, \ - sizeof(v4l2_std_id))) { - POUT; + sizeof(v4l2_std_id))) return -EFAULT; - } peasycap_standard = &easycap_standard[peasycap->standard_offset]; std_id = peasycap_standard->v4l2_standard.id; @@ -1503,10 +1453,8 @@ case VIDIOC_G_STD: { &peasycap_standard->v4l2_standard.name[0]); if (0 != copy_to_user((void __user *)arg, &std_id, \ - sizeof(v4l2_std_id))) { - POUT; + sizeof(v4l2_std_id))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1517,10 +1465,8 @@ case VIDIOC_S_STD: { JOT(8, "VIDIOC_S_STD\n"); if (0 != copy_from_user(&std_id, (void __user *)arg, \ - sizeof(v4l2_std_id))) { - POUT; + sizeof(v4l2_std_id))) return -EFAULT; - } rc = adjust_standard(peasycap, std_id); if (0 > rc) { @@ -1537,17 +1483,13 @@ case VIDIOC_REQBUFS: { JOT(8, "VIDIOC_REQBUFS\n"); if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \ - sizeof(struct v4l2_requestbuffers))) { - POUT; + sizeof(struct v4l2_requestbuffers))) return -EFAULT; - } if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) { - POUT; + if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) return -EINVAL; - } nbuffers = v4l2_requestbuffers.count; JOT(8, " User requests %i buffers ...\n", nbuffers); if (nbuffers < 2) @@ -1565,10 +1507,8 @@ case VIDIOC_REQBUFS: { peasycap->frame_buffer_many = nbuffers; if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \ - sizeof(struct v4l2_requestbuffers))) { - POUT; + sizeof(struct v4l2_requestbuffers))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1585,10 +1525,8 @@ case VIDIOC_QUERYBUF: { } if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ - sizeof(struct v4l2_buffer))) { - POUT; + sizeof(struct v4l2_buffer))) return -EFAULT; - } if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1620,10 +1558,8 @@ case VIDIOC_QUERYBUF: { JOT(16, " %10i=length\n", v4l2_buffer.length); if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ - sizeof(struct v4l2_buffer))) { - POUT; + sizeof(struct v4l2_buffer))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1633,10 +1569,8 @@ case VIDIOC_QBUF: { JOT(8, "VIDIOC_QBUF\n"); if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ - sizeof(struct v4l2_buffer))) { - POUT; + sizeof(struct v4l2_buffer))) return -EFAULT; - } if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1651,10 +1585,8 @@ case VIDIOC_QBUF: { peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED; if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ - sizeof(struct v4l2_buffer))) { - POUT; + sizeof(struct v4l2_buffer))) return -EFAULT; - } JOT(8, "..... user queueing frame buffer %i\n", \ (int)v4l2_buffer.index); @@ -1687,10 +1619,8 @@ case VIDIOC_DQBUF: } if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ - sizeof(struct v4l2_buffer))) { - POUT; + sizeof(struct v4l2_buffer))) return -EFAULT; - } if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1752,17 +1682,10 @@ case VIDIOC_DQBUF: timeval1 = timeval; timeval2 = timeval; dnbydt = 192000; - - if (mutex_lock_interruptible(&(peasycap->mutex_timeval0))) - return -ERESTARTSYS; peasycap->timeval0 = timeval0; - mutex_unlock(&(peasycap->mutex_timeval0)); } else { - if (mutex_lock_interruptible(&(peasycap->mutex_timeval1))) - return -ERESTARTSYS; dnbydt = peasycap->dnbydt; timeval1 = peasycap->timeval1; - mutex_unlock(&(peasycap->mutex_timeval1)); above = dnbydt * MICROSECONDS(timeval, timeval1); below = 192000; sdr = signed_div(above, below); @@ -1807,10 +1730,8 @@ case VIDIOC_DQBUF: JOT(16, " %10i=length\n", v4l2_buffer.length); if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ - sizeof(struct v4l2_buffer))) { - POUT; + sizeof(struct v4l2_buffer))) return -EFAULT; - } JOT(8, "..... user is offered frame buffer %i\n", \ peasycap->frame_read); @@ -1879,15 +1800,11 @@ case VIDIOC_G_PARM: { JOT(8, "VIDIOC_G_PARM\n"); if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \ - sizeof(struct v4l2_streamparm))) { - POUT; + sizeof(struct v4l2_streamparm))) return -EFAULT; - } - if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - POUT; + if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - } v4l2_streamparm.parm.capture.capability = 0; v4l2_streamparm.parm.capture.capturemode = 0; v4l2_streamparm.parm.capture.timeperframe.numerator = 1; @@ -1895,10 +1812,8 @@ case VIDIOC_G_PARM: { v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many; v4l2_streamparm.parm.capture.extendedmode = 0; if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \ - sizeof(struct v4l2_streamparm))) { - POUT; + sizeof(struct v4l2_streamparm))) return -EFAULT; - } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1941,8 +1856,6 @@ case VIDIOC_S_FREQUENCY: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ default: { JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); - explain_ioctl(cmd); - POUT; return -ENOIOCTLCMD; } } @@ -2147,7 +2060,6 @@ case SNDCTL_DSP_GETISPACE: { } default: { JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd); - POUT; return -ENOIOCTLCMD; } } @@ -2165,531 +2077,4 @@ long easysnd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } - -/*****************************************************************************/ -int explain_ioctl(__u32 wot) -{ -int k; -/*---------------------------------------------------------------------------*/ -/* - * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING - * SHELL SCRIPT: - * # - * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \ - * grep "^#define VIDIOC_" - | grep -v "_OLD" - | \ - * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \ - * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \ - * sed -e "s, ,,g;s, ,,g" >ioctl.tmp - * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp - * exit 0 - * # - * AND REINSTATING THE EXCISED "_OLD" CASES WERE LATER MANUALLY. - * - * THE DATA FOR THE ARRAY mess1 BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING - * SHELL SCRIPT: - * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev.h | \ - * grep "^#define VIDIOC" - | grep -v "_OLD" - | \ - * sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \ - * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \ - * sed -e "s, ,,g;s, ,,g" >ioctl.tmp - * echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp - * exit 0 - * # - */ -/*---------------------------------------------------------------------------*/ -static struct mess { - __u32 command; - char name[64]; -} mess[] = { -#if defined(VIDIOC_QUERYCAP) -{VIDIOC_QUERYCAP, "VIDIOC_QUERYCAP"}, -#endif -#if defined(VIDIOC_RESERVED) -{VIDIOC_RESERVED, "VIDIOC_RESERVED"}, -#endif -#if defined(VIDIOC_ENUM_FMT) -{VIDIOC_ENUM_FMT, "VIDIOC_ENUM_FMT"}, -#endif -#if defined(VIDIOC_G_FMT) -{VIDIOC_G_FMT, "VIDIOC_G_FMT"}, -#endif -#if defined(VIDIOC_S_FMT) -{VIDIOC_S_FMT, "VIDIOC_S_FMT"}, -#endif -#if defined(VIDIOC_REQBUFS) -{VIDIOC_REQBUFS, "VIDIOC_REQBUFS"}, -#endif -#if defined(VIDIOC_QUERYBUF) -{VIDIOC_QUERYBUF, "VIDIOC_QUERYBUF"}, -#endif -#if defined(VIDIOC_G_FBUF) -{VIDIOC_G_FBUF, "VIDIOC_G_FBUF"}, -#endif -#if defined(VIDIOC_S_FBUF) -{VIDIOC_S_FBUF, "VIDIOC_S_FBUF"}, -#endif -#if defined(VIDIOC_OVERLAY) -{VIDIOC_OVERLAY, "VIDIOC_OVERLAY"}, -#endif -#if defined(VIDIOC_QBUF) -{VIDIOC_QBUF, "VIDIOC_QBUF"}, -#endif -#if defined(VIDIOC_DQBUF) -{VIDIOC_DQBUF, "VIDIOC_DQBUF"}, -#endif -#if defined(VIDIOC_STREAMON) -{VIDIOC_STREAMON, "VIDIOC_STREAMON"}, -#endif -#if defined(VIDIOC_STREAMOFF) -{VIDIOC_STREAMOFF, "VIDIOC_STREAMOFF"}, -#endif -#if defined(VIDIOC_G_PARM) -{VIDIOC_G_PARM, "VIDIOC_G_PARM"}, -#endif -#if defined(VIDIOC_S_PARM) -{VIDIOC_S_PARM, "VIDIOC_S_PARM"}, -#endif -#if defined(VIDIOC_G_STD) -{VIDIOC_G_STD, "VIDIOC_G_STD"}, -#endif -#if defined(VIDIOC_S_STD) -{VIDIOC_S_STD, "VIDIOC_S_STD"}, -#endif -#if defined(VIDIOC_ENUMSTD) -{VIDIOC_ENUMSTD, "VIDIOC_ENUMSTD"}, -#endif -#if defined(VIDIOC_ENUMINPUT) -{VIDIOC_ENUMINPUT, "VIDIOC_ENUMINPUT"}, -#endif -#if defined(VIDIOC_G_CTRL) -{VIDIOC_G_CTRL, "VIDIOC_G_CTRL"}, -#endif -#if defined(VIDIOC_S_CTRL) -{VIDIOC_S_CTRL, "VIDIOC_S_CTRL"}, -#endif -#if defined(VIDIOC_G_TUNER) -{VIDIOC_G_TUNER, "VIDIOC_G_TUNER"}, -#endif -#if defined(VIDIOC_S_TUNER) -{VIDIOC_S_TUNER, "VIDIOC_S_TUNER"}, -#endif -#if defined(VIDIOC_G_AUDIO) -{VIDIOC_G_AUDIO, "VIDIOC_G_AUDIO"}, -#endif -#if defined(VIDIOC_S_AUDIO) -{VIDIOC_S_AUDIO, "VIDIOC_S_AUDIO"}, -#endif -#if defined(VIDIOC_QUERYCTRL) -{VIDIOC_QUERYCTRL, "VIDIOC_QUERYCTRL"}, -#endif -#if defined(VIDIOC_QUERYMENU) -{VIDIOC_QUERYMENU, "VIDIOC_QUERYMENU"}, -#endif -#if defined(VIDIOC_G_INPUT) -{VIDIOC_G_INPUT, "VIDIOC_G_INPUT"}, -#endif -#if defined(VIDIOC_S_INPUT) -{VIDIOC_S_INPUT, "VIDIOC_S_INPUT"}, -#endif -#if defined(VIDIOC_G_OUTPUT) -{VIDIOC_G_OUTPUT, "VIDIOC_G_OUTPUT"}, -#endif -#if defined(VIDIOC_S_OUTPUT) -{VIDIOC_S_OUTPUT, "VIDIOC_S_OUTPUT"}, -#endif -#if defined(VIDIOC_ENUMOUTPUT) -{VIDIOC_ENUMOUTPUT, "VIDIOC_ENUMOUTPUT"}, -#endif -#if defined(VIDIOC_G_AUDOUT) -{VIDIOC_G_AUDOUT, "VIDIOC_G_AUDOUT"}, -#endif -#if defined(VIDIOC_S_AUDOUT) -{VIDIOC_S_AUDOUT, "VIDIOC_S_AUDOUT"}, -#endif -#if defined(VIDIOC_G_MODULATOR) -{VIDIOC_G_MODULATOR, "VIDIOC_G_MODULATOR"}, -#endif -#if defined(VIDIOC_S_MODULATOR) -{VIDIOC_S_MODULATOR, "VIDIOC_S_MODULATOR"}, -#endif -#if defined(VIDIOC_G_FREQUENCY) -{VIDIOC_G_FREQUENCY, "VIDIOC_G_FREQUENCY"}, -#endif -#if defined(VIDIOC_S_FREQUENCY) -{VIDIOC_S_FREQUENCY, "VIDIOC_S_FREQUENCY"}, -#endif -#if defined(VIDIOC_CROPCAP) -{VIDIOC_CROPCAP, "VIDIOC_CROPCAP"}, -#endif -#if defined(VIDIOC_G_CROP) -{VIDIOC_G_CROP, "VIDIOC_G_CROP"}, -#endif -#if defined(VIDIOC_S_CROP) -{VIDIOC_S_CROP, "VIDIOC_S_CROP"}, -#endif -#if defined(VIDIOC_G_JPEGCOMP) -{VIDIOC_G_JPEGCOMP, "VIDIOC_G_JPEGCOMP"}, -#endif -#if defined(VIDIOC_S_JPEGCOMP) -{VIDIOC_S_JPEGCOMP, "VIDIOC_S_JPEGCOMP"}, -#endif -#if defined(VIDIOC_QUERYSTD) -{VIDIOC_QUERYSTD, "VIDIOC_QUERYSTD"}, -#endif -#if defined(VIDIOC_TRY_FMT) -{VIDIOC_TRY_FMT, "VIDIOC_TRY_FMT"}, -#endif -#if defined(VIDIOC_ENUMAUDIO) -{VIDIOC_ENUMAUDIO, "VIDIOC_ENUMAUDIO"}, -#endif -#if defined(VIDIOC_ENUMAUDOUT) -{VIDIOC_ENUMAUDOUT, "VIDIOC_ENUMAUDOUT"}, -#endif -#if defined(VIDIOC_G_PRIORITY) -{VIDIOC_G_PRIORITY, "VIDIOC_G_PRIORITY"}, -#endif -#if defined(VIDIOC_S_PRIORITY) -{VIDIOC_S_PRIORITY, "VIDIOC_S_PRIORITY"}, -#endif -#if defined(VIDIOC_G_SLICED_VBI_CAP) -{VIDIOC_G_SLICED_VBI_CAP, "VIDIOC_G_SLICED_VBI_CAP"}, -#endif -#if defined(VIDIOC_LOG_STATUS) -{VIDIOC_LOG_STATUS, "VIDIOC_LOG_STATUS"}, -#endif -#if defined(VIDIOC_G_EXT_CTRLS) -{VIDIOC_G_EXT_CTRLS, "VIDIOC_G_EXT_CTRLS"}, -#endif -#if defined(VIDIOC_S_EXT_CTRLS) -{VIDIOC_S_EXT_CTRLS, "VIDIOC_S_EXT_CTRLS"}, -#endif -#if defined(VIDIOC_TRY_EXT_CTRLS) -{VIDIOC_TRY_EXT_CTRLS, "VIDIOC_TRY_EXT_CTRLS"}, -#endif -#if defined(VIDIOC_ENUM_FRAMESIZES) -{VIDIOC_ENUM_FRAMESIZES, "VIDIOC_ENUM_FRAMESIZES"}, -#endif -#if defined(VIDIOC_ENUM_FRAMEINTERVALS) -{VIDIOC_ENUM_FRAMEINTERVALS, "VIDIOC_ENUM_FRAMEINTERVALS"}, -#endif -#if defined(VIDIOC_G_ENC_INDEX) -{VIDIOC_G_ENC_INDEX, "VIDIOC_G_ENC_INDEX"}, -#endif -#if defined(VIDIOC_ENCODER_CMD) -{VIDIOC_ENCODER_CMD, "VIDIOC_ENCODER_CMD"}, -#endif -#if defined(VIDIOC_TRY_ENCODER_CMD) -{VIDIOC_TRY_ENCODER_CMD, "VIDIOC_TRY_ENCODER_CMD"}, -#endif -#if defined(VIDIOC_G_CHIP_IDENT) -{VIDIOC_G_CHIP_IDENT, "VIDIOC_G_CHIP_IDENT"}, -#endif - -#if defined(VIDIOC_OVERLAY_OLD) -{VIDIOC_OVERLAY_OLD, "VIDIOC_OVERLAY_OLD"}, -#endif -#if defined(VIDIOC_S_PARM_OLD) -{VIDIOC_S_PARM_OLD, "VIDIOC_S_PARM_OLD"}, -#endif -#if defined(VIDIOC_S_CTRL_OLD) -{VIDIOC_S_CTRL_OLD, "VIDIOC_S_CTRL_OLD"}, -#endif -#if defined(VIDIOC_G_AUDIO_OLD) -{VIDIOC_G_AUDIO_OLD, "VIDIOC_G_AUDIO_OLD"}, -#endif -#if defined(VIDIOC_G_AUDOUT_OLD) -{VIDIOC_G_AUDOUT_OLD, "VIDIOC_G_AUDOUT_OLD"}, -#endif -#if defined(VIDIOC_CROPCAP_OLD) -{VIDIOC_CROPCAP_OLD, "VIDIOC_CROPCAP_OLD"}, -#endif -{0xFFFFFFFF, ""} -}; - -static struct mess mess1[] = \ -{ -#if defined(VIDIOCGCAP) -{VIDIOCGCAP, "VIDIOCGCAP"}, -#endif -#if defined(VIDIOCGCHAN) -{VIDIOCGCHAN, "VIDIOCGCHAN"}, -#endif -#if defined(VIDIOCSCHAN) -{VIDIOCSCHAN, "VIDIOCSCHAN"}, -#endif -#if defined(VIDIOCGTUNER) -{VIDIOCGTUNER, "VIDIOCGTUNER"}, -#endif -#if defined(VIDIOCSTUNER) -{VIDIOCSTUNER, "VIDIOCSTUNER"}, -#endif -#if defined(VIDIOCGPICT) -{VIDIOCGPICT, "VIDIOCGPICT"}, -#endif -#if defined(VIDIOCSPICT) -{VIDIOCSPICT, "VIDIOCSPICT"}, -#endif -#if defined(VIDIOCCAPTURE) -{VIDIOCCAPTURE, "VIDIOCCAPTURE"}, -#endif -#if defined(VIDIOCGWIN) -{VIDIOCGWIN, "VIDIOCGWIN"}, -#endif -#if defined(VIDIOCSWIN) -{VIDIOCSWIN, "VIDIOCSWIN"}, -#endif -#if defined(VIDIOCGFBUF) -{VIDIOCGFBUF, "VIDIOCGFBUF"}, -#endif -#if defined(VIDIOCSFBUF) -{VIDIOCSFBUF, "VIDIOCSFBUF"}, -#endif -#if defined(VIDIOCKEY) -{VIDIOCKEY, "VIDIOCKEY"}, -#endif -#if defined(VIDIOCGFREQ) -{VIDIOCGFREQ, "VIDIOCGFREQ"}, -#endif -#if defined(VIDIOCSFREQ) -{VIDIOCSFREQ, "VIDIOCSFREQ"}, -#endif -#if defined(VIDIOCGAUDIO) -{VIDIOCGAUDIO, "VIDIOCGAUDIO"}, -#endif -#if defined(VIDIOCSAUDIO) -{VIDIOCSAUDIO, "VIDIOCSAUDIO"}, -#endif -#if defined(VIDIOCSYNC) -{VIDIOCSYNC, "VIDIOCSYNC"}, -#endif -#if defined(VIDIOCMCAPTURE) -{VIDIOCMCAPTURE, "VIDIOCMCAPTURE"}, -#endif -#if defined(VIDIOCGMBUF) -{VIDIOCGMBUF, "VIDIOCGMBUF"}, -#endif -#if defined(VIDIOCGUNIT) -{VIDIOCGUNIT, "VIDIOCGUNIT"}, -#endif -#if defined(VIDIOCGCAPTURE) -{VIDIOCGCAPTURE, "VIDIOCGCAPTURE"}, -#endif -#if defined(VIDIOCSCAPTURE) -{VIDIOCSCAPTURE, "VIDIOCSCAPTURE"}, -#endif -#if defined(VIDIOCSPLAYMODE) -{VIDIOCSPLAYMODE, "VIDIOCSPLAYMODE"}, -#endif -#if defined(VIDIOCSWRITEMODE) -{VIDIOCSWRITEMODE, "VIDIOCSWRITEMODE"}, -#endif -#if defined(VIDIOCGPLAYINFO) -{VIDIOCGPLAYINFO, "VIDIOCGPLAYINFO"}, -#endif -#if defined(VIDIOCSMICROCODE) -{VIDIOCSMICROCODE, "VIDIOCSMICROCODE"}, -#endif -{0xFFFFFFFF, ""} -}; - -k = 0; -while (mess[k].name[0]) { - if (wot == mess[k].command) { - JOT(8, "ioctl 0x%08X is %s\n", \ - mess[k].command, &mess[k].name[0]); - return 0; - } - k++; -} -JOT(8, "ioctl 0x%08X is not in videodev2.h\n", wot); - -k = 0; -while (mess1[k].name[0]) { - if (wot == mess1[k].command) { - JOT(8, "ioctl 0x%08X is %s (V4L1)\n", \ - mess1[k].command, &mess1[k].name[0]); - return 0; - } - k++; -} -JOT(8, "ioctl 0x%08X is not in videodev.h\n", wot); -return -1; -} -/*****************************************************************************/ -int explain_cid(__u32 wot) -{ -int k; -/*---------------------------------------------------------------------------*/ -/* - * THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING - * SHELL SCRIPT: - * # - * cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \ - * grep "^#define V4L2_CID_" | \ - * sed -e "s,(.*$,,;p" | sed -e "N;s,\n,, " | \ - * sed -e "s/^#define / {/;s/#define /, \"/;s/$/\"},/" | \ - * sed -e "s, ,,g;s, ,,g" | grep -v "_BASE" | grep -v "MPEG" >cid.tmp - * echo "{0xFFFFFFFF,\"\"}" >>cid.tmp - * exit 0 - * # - */ -/*---------------------------------------------------------------------------*/ -static struct mess -{ -__u32 command; -char name[64]; -} mess[] = { -#if defined(V4L2_CID_USER_CLASS) -{V4L2_CID_USER_CLASS, "V4L2_CID_USER_CLASS"}, -#endif -#if defined(V4L2_CID_BRIGHTNESS) -{V4L2_CID_BRIGHTNESS, "V4L2_CID_BRIGHTNESS"}, -#endif -#if defined(V4L2_CID_CONTRAST) -{V4L2_CID_CONTRAST, "V4L2_CID_CONTRAST"}, -#endif -#if defined(V4L2_CID_SATURATION) -{V4L2_CID_SATURATION, "V4L2_CID_SATURATION"}, -#endif -#if defined(V4L2_CID_HUE) -{V4L2_CID_HUE, "V4L2_CID_HUE"}, -#endif -#if defined(V4L2_CID_AUDIO_VOLUME) -{V4L2_CID_AUDIO_VOLUME, "V4L2_CID_AUDIO_VOLUME"}, -#endif -#if defined(V4L2_CID_AUDIO_BALANCE) -{V4L2_CID_AUDIO_BALANCE, "V4L2_CID_AUDIO_BALANCE"}, -#endif -#if defined(V4L2_CID_AUDIO_BASS) -{V4L2_CID_AUDIO_BASS, "V4L2_CID_AUDIO_BASS"}, -#endif -#if defined(V4L2_CID_AUDIO_TREBLE) -{V4L2_CID_AUDIO_TREBLE, "V4L2_CID_AUDIO_TREBLE"}, -#endif -#if defined(V4L2_CID_AUDIO_MUTE) -{V4L2_CID_AUDIO_MUTE, "V4L2_CID_AUDIO_MUTE"}, -#endif -#if defined(V4L2_CID_AUDIO_LOUDNESS) -{V4L2_CID_AUDIO_LOUDNESS, "V4L2_CID_AUDIO_LOUDNESS"}, -#endif -#if defined(V4L2_CID_BLACK_LEVEL) -{V4L2_CID_BLACK_LEVEL, "V4L2_CID_BLACK_LEVEL"}, -#endif -#if defined(V4L2_CID_AUTO_WHITE_BALANCE) -{V4L2_CID_AUTO_WHITE_BALANCE, "V4L2_CID_AUTO_WHITE_BALANCE"}, -#endif -#if defined(V4L2_CID_DO_WHITE_BALANCE) -{V4L2_CID_DO_WHITE_BALANCE, "V4L2_CID_DO_WHITE_BALANCE"}, -#endif -#if defined(V4L2_CID_RED_BALANCE) -{V4L2_CID_RED_BALANCE, "V4L2_CID_RED_BALANCE"}, -#endif -#if defined(V4L2_CID_BLUE_BALANCE) -{V4L2_CID_BLUE_BALANCE, "V4L2_CID_BLUE_BALANCE"}, -#endif -#if defined(V4L2_CID_GAMMA) -{V4L2_CID_GAMMA, "V4L2_CID_GAMMA"}, -#endif -#if defined(V4L2_CID_WHITENESS) -{V4L2_CID_WHITENESS, "V4L2_CID_WHITENESS"}, -#endif -#if defined(V4L2_CID_EXPOSURE) -{V4L2_CID_EXPOSURE, "V4L2_CID_EXPOSURE"}, -#endif -#if defined(V4L2_CID_AUTOGAIN) -{V4L2_CID_AUTOGAIN, "V4L2_CID_AUTOGAIN"}, -#endif -#if defined(V4L2_CID_GAIN) -{V4L2_CID_GAIN, "V4L2_CID_GAIN"}, -#endif -#if defined(V4L2_CID_HFLIP) -{V4L2_CID_HFLIP, "V4L2_CID_HFLIP"}, -#endif -#if defined(V4L2_CID_VFLIP) -{V4L2_CID_VFLIP, "V4L2_CID_VFLIP"}, -#endif -#if defined(V4L2_CID_HCENTER) -{V4L2_CID_HCENTER, "V4L2_CID_HCENTER"}, -#endif -#if defined(V4L2_CID_VCENTER) -{V4L2_CID_VCENTER, "V4L2_CID_VCENTER"}, -#endif -#if defined(V4L2_CID_POWER_LINE_FREQUENCY) -{V4L2_CID_POWER_LINE_FREQUENCY, "V4L2_CID_POWER_LINE_FREQUENCY"}, -#endif -#if defined(V4L2_CID_HUE_AUTO) -{V4L2_CID_HUE_AUTO, "V4L2_CID_HUE_AUTO"}, -#endif -#if defined(V4L2_CID_WHITE_BALANCE_TEMPERATURE) -{V4L2_CID_WHITE_BALANCE_TEMPERATURE, "V4L2_CID_WHITE_BALANCE_TEMPERATURE"}, -#endif -#if defined(V4L2_CID_SHARPNESS) -{V4L2_CID_SHARPNESS, "V4L2_CID_SHARPNESS"}, -#endif -#if defined(V4L2_CID_BACKLIGHT_COMPENSATION) -{V4L2_CID_BACKLIGHT_COMPENSATION, "V4L2_CID_BACKLIGHT_COMPENSATION"}, -#endif -#if defined(V4L2_CID_CHROMA_AGC) -{V4L2_CID_CHROMA_AGC, "V4L2_CID_CHROMA_AGC"}, -#endif -#if defined(V4L2_CID_COLOR_KILLER) -{V4L2_CID_COLOR_KILLER, "V4L2_CID_COLOR_KILLER"}, -#endif -#if defined(V4L2_CID_LASTP1) -{V4L2_CID_LASTP1, "V4L2_CID_LASTP1"}, -#endif -#if defined(V4L2_CID_CAMERA_CLASS) -{V4L2_CID_CAMERA_CLASS, "V4L2_CID_CAMERA_CLASS"}, -#endif -#if defined(V4L2_CID_EXPOSURE_AUTO) -{V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO"}, -#endif -#if defined(V4L2_CID_EXPOSURE_ABSOLUTE) -{V4L2_CID_EXPOSURE_ABSOLUTE, "V4L2_CID_EXPOSURE_ABSOLUTE"}, -#endif -#if defined(V4L2_CID_EXPOSURE_AUTO_PRIORITY) -{V4L2_CID_EXPOSURE_AUTO_PRIORITY, "V4L2_CID_EXPOSURE_AUTO_PRIORITY"}, -#endif -#if defined(V4L2_CID_PAN_RELATIVE) -{V4L2_CID_PAN_RELATIVE, "V4L2_CID_PAN_RELATIVE"}, -#endif -#if defined(V4L2_CID_TILT_RELATIVE) -{V4L2_CID_TILT_RELATIVE, "V4L2_CID_TILT_RELATIVE"}, -#endif -#if defined(V4L2_CID_PAN_RESET) -{V4L2_CID_PAN_RESET, "V4L2_CID_PAN_RESET"}, -#endif -#if defined(V4L2_CID_TILT_RESET) -{V4L2_CID_TILT_RESET, "V4L2_CID_TILT_RESET"}, -#endif -#if defined(V4L2_CID_PAN_ABSOLUTE) -{V4L2_CID_PAN_ABSOLUTE, "V4L2_CID_PAN_ABSOLUTE"}, -#endif -#if defined(V4L2_CID_TILT_ABSOLUTE) -{V4L2_CID_TILT_ABSOLUTE, "V4L2_CID_TILT_ABSOLUTE"}, -#endif -#if defined(V4L2_CID_FOCUS_ABSOLUTE) -{V4L2_CID_FOCUS_ABSOLUTE, "V4L2_CID_FOCUS_ABSOLUTE"}, -#endif -#if defined(V4L2_CID_FOCUS_RELATIVE) -{V4L2_CID_FOCUS_RELATIVE, "V4L2_CID_FOCUS_RELATIVE"}, -#endif -#if defined(V4L2_CID_FOCUS_AUTO) -{V4L2_CID_FOCUS_AUTO, "V4L2_CID_FOCUS_AUTO"}, -#endif -{0xFFFFFFFF, ""} -}; - -k = 0; -while (mess[k].name[0]) { - if (wot == mess[k].command) { - JOT(8, "ioctl 0x%08X is %s\n", \ - mess[k].command, &mess[k].name[0]); - return 0; - } - k++; -} -JOT(8, "cid 0x%08X is not in videodev2.h\n", wot); -return -1; -} /*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index ad1fc4cc471a..709c3d98e936 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -64,45 +64,22 @@ const struct stk1160config { int reg; int set; } stk1160config[256] = { #if defined(PREFER_NTSC) -#undef OLDMARGIN -#if defined(OLDMARGIN) - {0x110, 0x0008}, -#else {0x110, 0x0014}, -#endif /*OLDMARGIN*/ - {0x111, 0x0000}, {0x112, 0x0003}, {0x113, 0x0000}, - -#if defined(OLDMARGIN) - {0x114, 0x0508}, -#else {0x114, 0x0514}, -#endif /*OLDMARGIN*/ - {0x115, 0x0005}, {0x116, 0x00F3}, {0x117, 0x0000}, #else /* ! PREFER_NTSC*/ -#if defined(OLDMARGIN) - {0x110, 0x0008}, -#else {0x110, 0x0014}, -#endif /*OLDMARGIN*/ - {0x111, 0x0000}, {0x112, 0x0020}, {0x113, 0x0000}, - -#if defined(OLDMARGIN) - {0x114, 0x0508}, -#else {0x114, 0x0514}, -#endif /*OLDMARGIN*/ - {0x115, 0x0005}, {0x116, 0x0110}, {0x117, 0x0001}, diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index 5a4bbd9b453f..5dba664475dd 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -31,8 +31,8 @@ #include "easycap.h" #include "easycap_standard.h" -int easycap_debug; -module_param(easycap_debug, int, S_IRUGO | S_IWUSR); +int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); /*---------------------------------------------------------------------------*/ /* @@ -314,8 +314,6 @@ peasycap->audio_eof = 0; do_gettimeofday(&peasycap->timeval7); -peasycap->fudge = 0; - JOT(4, "finished initialization\n"); return 0; } @@ -855,15 +853,11 @@ if (NULL == peasycap) { */ /*---------------------------------------------------------------------------*/ miss = 0; -if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0]))) - return -ERESTARTSYS; while ((peasycap->field_read == peasycap->field_fill) || \ (0 != (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) || \ (0 != (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))) { - mutex_unlock(&(peasycap->mutex_mmap_video[0])); - if (mode) return -EAGAIN; @@ -888,15 +882,11 @@ while ((peasycap->field_read == peasycap->field_fill) || \ } if (peasycap->video_eof) { JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof); - debrief(peasycap); kill_video_urbs(peasycap); return -EIO; } miss++; -if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0]))) - return -ERESTARTSYS; } -mutex_unlock(&(peasycap->mutex_mmap_video[0])); JOT(8, "first awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); @@ -925,15 +915,11 @@ JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); */ /*---------------------------------------------------------------------------*/ miss = 0; -if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0]))) - return -ERESTARTSYS; while ((peasycap->field_read == peasycap->field_fill) || \ (0 != (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) || \ (0 == (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))) { - mutex_unlock(&(peasycap->mutex_mmap_video[0])); - if (mode) return -EAGAIN; @@ -957,15 +943,11 @@ while ((peasycap->field_read == peasycap->field_fill) || \ } if (peasycap->video_eof) { JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof); - debrief(peasycap); kill_video_urbs(peasycap); return -EIO; } miss++; -if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0]))) - return -ERESTARTSYS; } -mutex_unlock(&(peasycap->mutex_mmap_video[0])); JOT(8, "second awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); @@ -2233,41 +2215,6 @@ default: { return 0; } /*****************************************************************************/ -void -debrief(struct easycap *peasycap) -{ -if ((struct usb_device *)NULL != peasycap->pusb_device) { - check_stk(peasycap->pusb_device); - check_saa(peasycap->pusb_device); - sayreadonly(peasycap); - SAY("%i=peasycap->field_fill\n", peasycap->field_fill); - SAY("%i=peasycap->field_read\n", peasycap->field_read); - SAY("%i=peasycap->frame_fill\n", peasycap->frame_fill); - SAY("%i=peasycap->frame_read\n", peasycap->frame_read); -} -return; -} -/*****************************************************************************/ -void -sayreadonly(struct easycap *peasycap) -{ -static int done; -int got00, got1F, got60, got61, got62; - -if ((!done) && ((struct usb_device *)NULL != peasycap->pusb_device)) { - done = 1; - got00 = read_saa(peasycap->pusb_device, 0x00); - got1F = read_saa(peasycap->pusb_device, 0x1F); - got60 = read_saa(peasycap->pusb_device, 0x60); - got61 = read_saa(peasycap->pusb_device, 0x61); - got62 = read_saa(peasycap->pusb_device, 0x62); - SAY("0x%02X=reg0x00 0x%02X=reg0x1F\n", got00, got1F); - SAY("0x%02X=reg0x60 0x%02X=reg0x61 0x%02X=reg0x62\n", \ - got60, got61, got62); -} -return; -} -/*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* * SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434 @@ -2355,7 +2302,6 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return retcode; } -mutex_lock(&(peasycap->mutex_mmap_video[0])); /*---------------------------------------------------------------------------*/ pbuf = peasycap->frame_buffer[k][m].pgo; if (NULL == pbuf) { @@ -2370,7 +2316,6 @@ if (NULL == page) { get_page(page); /*---------------------------------------------------------------------------*/ finish: -mutex_unlock(&(peasycap->mutex_mmap_video[0])); if (NULL == page) { SAY("ERROR: page is NULL after get_page(page)\n"); } else { @@ -2383,7 +2328,7 @@ return retcode; /*---------------------------------------------------------------------------*/ /* * ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS - * PROVIDED peasycap->video_idle IS ZER0. REGARDLESS OF THIS BEING TRUE, + * PROVIDED peasycap->video_idle IS ZERO. REGARDLESS OF THIS BEING TRUE, * IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO. * * THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP. @@ -2400,7 +2345,7 @@ return retcode; * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA - * 0 != (kount & 0x0400) => FIELD WAS SUBMITTED BY BRIDGER ROUTINE + * 0 != (kount & 0x0400) => RESERVED * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY? */ @@ -2417,10 +2362,6 @@ int videofieldamount; unsigned int override; int framestatus, framelength, frameactual, frameoffset; __u8 *pu; -#if defined(BRIDGER) -struct timeval timeval; -long long usec; -#endif /*BRIDGER*/ if (NULL == purb) { SAY("ERROR: easycap_complete(): purb is NULL\n"); @@ -2864,55 +2805,6 @@ if (purb->status) { } } /*---------------------------------------------------------------------------*/ -/* - * - * - * *** UNDER DEVELOPMENT/TESTING - NOT READY YET! *** - * - * - * - * VIDEOTAPES MAY HAVE BEEN MANUALLY PAUSED AND RESTARTED DURING RECORDING. - * THIS CAUSES LOSS OF SYNC, CONFUSING DOWNSTREAM USERSPACE PROGRAMS WHICH - * MAY INTERPRET THE INTERRUPTION AS A SYMPTOM OF LATENCY. TO OVERCOME THIS - * THE DRIVER BRIDGES THE HIATUS BY SENDING DUMMY VIDEO FRAMES AT ROUGHLY - * THE RIGHT TIME INTERVALS IN THE HOPE OF PERSUADING THE DOWNSTREAM USERSPACE - * PROGRAM TO RESUME NORMAL SERVICE WHEN THE INTERRUPTION IS OVER. - */ -/*---------------------------------------------------------------------------*/ -#if defined(BRIDGER) -do_gettimeofday(&timeval); -if (peasycap->timeval7.tv_sec) { - usec = 1000000*(timeval.tv_sec - peasycap->timeval7.tv_sec) + \ - (timeval.tv_usec - peasycap->timeval7.tv_usec); - if (usec > (peasycap->usec + peasycap->tolerate)) { - JOT(8, "bridging hiatus\n"); - peasycap->video_junk = 0; - peasycap->field_buffer[peasycap->field_fill][0].kount |= 0x0400; - - peasycap->field_read = (peasycap->field_fill)++; - - if (FIELD_BUFFER_MANY <= peasycap->field_fill) \ - peasycap->field_fill = 0; - peasycap->field_page = 0; - pfield_buffer = &peasycap->field_buffer\ - [peasycap->field_fill][peasycap->field_page]; - pfield_buffer->pto = pfield_buffer->pgo; - - JOT(8, "bumped to: %i=peasycap->field_fill %i=parity\n", \ - peasycap->field_fill, 0x00FF & pfield_buffer->kount); - JOT(8, "field buffer %i has %i bytes to be overwritten\n", \ - peasycap->field_read, videofieldamount); - JOT(8, "wakeup call to wq_video, " \ - "%i=field_read %i=field_fill %i=parity\n", \ - peasycap->field_read, peasycap->field_fill, \ - 0x00FF & \ - peasycap->field_buffer[peasycap->field_read][0].kount); - wake_up_interruptible(&(peasycap->wq_video)); - do_gettimeofday(&peasycap->timeval7); - } -} -#endif /*BRIDGER*/ -/*---------------------------------------------------------------------------*/ /* * RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS. * @@ -3152,12 +3044,6 @@ if (0 == bInterfaceNumber) { init_waitqueue_head(&(peasycap->wq_video)); init_waitqueue_head(&(peasycap->wq_audio)); - mutex_init(&(peasycap->mutex_timeval0)); - mutex_init(&(peasycap->mutex_timeval1)); - - for (k = 0; k < FRAME_BUFFER_MANY; k++) - mutex_init(&(peasycap->mutex_mmap_video[k])); - peasycap->ilk = 0; peasycap->microphone = false; @@ -3176,11 +3062,6 @@ if (0 == bInterfaceNumber) { peasycap->audio_isoc_buffer_size = -1; peasycap->frame_buffer_many = FRAME_BUFFER_MANY; - - if ((struct mutex *)NULL == &(peasycap->mutex_mmap_video[0])) { - SAY("ERROR: &(peasycap->mutex_mmap_video[%i]) is NULL\n", 0); - return -EFAULT; - } /*---------------------------------------------------------------------------*/ /* * DYNAMICALLY FILL IN THE AVAILABLE FORMATS. @@ -4308,7 +4189,7 @@ easycap_module_init(void) int result; SAY("========easycap=======\n"); -JOT(4, "begins. %i=debug\n", easycap_debug); +JOT(4, "begins. %i=debug\n", debug); SAY("version: " EASYCAP_DRIVER_VERSION "\n"); /*---------------------------------------------------------------------------*/ /* @@ -4349,6 +4230,6 @@ MODULE_AUTHOR("R.M. Thomas "); MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION); MODULE_VERSION(EASYCAP_DRIVER_VERSION); #if defined(EASYCAP_DEBUG) -MODULE_PARM_DESC(easycap_debug, "debug: 0 (default), 1, 2,..."); +MODULE_PARM_DESC(debug, "debug: 0 (default), 1, 2,..."); #endif /*EASYCAP_DEBUG*/ /*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c index 38d94051241d..67f2e4f27323 100644 --- a/drivers/staging/easycap/easycap_settings.c +++ b/drivers/staging/easycap/easycap_settings.c @@ -413,7 +413,7 @@ return n; } /*---------------------------------------------------------------------------*/ struct v4l2_queryctrl easycap_control[] = \ - {{ +{{ .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", @@ -485,5 +485,5 @@ struct v4l2_queryctrl easycap_control[] = \ { .id = 0xFFFFFFFF } - }; +}; /*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c index 63562bda738e..7be5bcf7136f 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/easycap/easycap_sound.c @@ -36,7 +36,7 @@ /*---------------------------------------------------------------------------*/ /* * ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS - * PROVIDED peasycap->audio_idle IS ZER0. REGARDLESS OF THIS BEING TRUE, + * PROVIDED peasycap->audio_idle IS ZERO. REGARDLESS OF THIS BEING TRUE, * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO. */ /*---------------------------------------------------------------------------*/ @@ -842,11 +842,7 @@ do_gettimeofday(&timeval); if (!peasycap->timeval1.tv_sec) { audio_bytes = 0; timeval1 = timeval; - - if (mutex_lock_interruptible(&(peasycap->mutex_timeval1))) - return -ERESTARTSYS; peasycap->timeval1 = timeval1; - mutex_unlock(&(peasycap->mutex_timeval1)); sdr.quotient = 192000; } else { audio_bytes += (long long int) szret; @@ -861,10 +857,7 @@ if (!peasycap->timeval1.tv_sec) { sdr.quotient = 192000; } JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient); -if (mutex_lock_interruptible(&(peasycap->mutex_timeval1))) - return -ERESTARTSYS; peasycap->dnbydt = sdr.quotient; -mutex_unlock(&(peasycap->mutex_timeval1)); JOT(8, "returning %li\n", (long int)szret); return szret; diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c index 3c2ce28fab95..700c73ec1c59 100644 --- a/drivers/staging/easycap/easycap_testcard.c +++ b/drivers/staging/easycap/easycap_testcard.c @@ -161,31 +161,31 @@ return(0); } -----------------------------------------------------------------------------*/ int tones[2048] = { - 0, 0, 502, 502, 1004, 1004, 1505, 1505, 2005, 2005, - 2503, 2503, 2998, 2998, 3491, 3491, 3980, 3980, 4466, 4466, - 4948, 4948, 5424, 5424, 5896, 5896, 6362, 6362, 6822, 6822, - 7276, 7276, 7723, 7723, 8162, 8162, 8594, 8594, 9018, 9018, - 9434, 9434, 9840, 9840, 10237, 10237, 10625, 10625, 11002, 11002, - 11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728, - 13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155, - 14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249, - 15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985, - 16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346, - 16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323, - 16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917, - 15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136, - 14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001, - 13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536, - 12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777, - 10393, 10393, 10000, 10000, 9597, 9597, 9185, 9185, 8765, 8765, - 8336, 8336, 7900, 7900, 7456, 7456, 7005, 7005, 6547, 6547, - 6083, 6083, 5614, 5614, 5139, 5139, 4659, 4659, 4175, 4175, - 3687, 3687, 3196, 3196, 2701, 2701, 2204, 2204, 1705, 1705, - 1205, 1205, 703, 703, 201, 201, -301, -301, -803, -803, - -1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294, - -3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708, - -6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988, - -8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079, +0, 0, 502, 502, 1004, 1004, 1505, 1505, 2005, 2005, +2503, 2503, 2998, 2998, 3491, 3491, 3980, 3980, 4466, 4466, +4948, 4948, 5424, 5424, 5896, 5896, 6362, 6362, 6822, 6822, +7276, 7276, 7723, 7723, 8162, 8162, 8594, 8594, 9018, 9018, +9434, 9434, 9840, 9840, 10237, 10237, 10625, 10625, 11002, 11002, +11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728, +13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155, +14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249, +15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985, +16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346, +16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323, +16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917, +15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136, +14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001, +13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536, +12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777, +10393, 10393, 10000, 10000, 9597, 9597, 9185, 9185, 8765, 8765, +8336, 8336, 7900, 7900, 7456, 7456, 7005, 7005, 6547, 6547, +6083, 6083, 5614, 5614, 5139, 5139, 4659, 4659, 4175, 4175, +3687, 3687, 3196, 3196, 2701, 2701, 2204, 2204, 1705, 1705, +1205, 1205, 703, 703, 201, 201, -301, -301, -803, -803, +-1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294, +-3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708, +-6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988, +-8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079, -10471, -10471, -10853, -10853, -11224, -11224, -11585, -11585, -11935, -11935, -12273, -12273, -12600, -12600, -12916, -12916, -13219, -13219, -13510, -13510, -13788, -13788, -14053, -14053, -14304, -14304, -14543, -14543, -14767, -14767, @@ -198,35 +198,35 @@ int tones[2048] = { -14353, -14353, -14104, -14104, -13842, -13842, -13566, -13566, -13278, -13278, -12977, -12977, -12665, -12665, -12340, -12340, -12003, -12003, -11656, -11656, -11297, -11297, -10928, -10928, -10548, -10548, -10159, -10159, -9759, -9759, - -9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634, - -7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329, - -4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900, - -2404, -2404, -1905, -1905, -1405, -1405, -904, -904, -402, -402, - 100, 100, 603, 603, 1105, 1105, 1605, 1605, 2105, 2105, - 2602, 2602, 3097, 3097, 3589, 3589, 4078, 4078, 4563, 4563, - 5043, 5043, 5519, 5519, 5990, 5990, 6455, 6455, 6914, 6914, - 7366, 7366, 7811, 7811, 8249, 8249, 8680, 8680, 9102, 9102, - 9516, 9516, 9920, 9920, 10315, 10315, 10701, 10701, 11077, 11077, - 11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791, - 13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205, - 14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286, - 15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007, - 16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353, - 16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314, - 16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892, - 15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098, - 14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948, - 13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471, - 12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701, - 10315, 10315, 9920, 9920, 9516, 9516, 9102, 9102, 8680, 8680, - 8249, 8249, 7811, 7811, 7366, 7366, 6914, 6914, 6455, 6455, - 5990, 5990, 5519, 5519, 5043, 5043, 4563, 4563, 4078, 4078, - 3589, 3589, 3097, 3097, 2602, 2602, 2105, 2105, 1605, 1605, - 1105, 1105, 603, 603, 100, 100, -402, -402, -904, -904, - -1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393, - -3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802, - -6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075, - -8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159, +-9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634, +-7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329, +-4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900, +-2404, -2404, -1905, -1905, -1405, -1405, -904, -904, -402, -402, +100, 100, 603, 603, 1105, 1105, 1605, 1605, 2105, 2105, +2602, 2602, 3097, 3097, 3589, 3589, 4078, 4078, 4563, 4563, +5043, 5043, 5519, 5519, 5990, 5990, 6455, 6455, 6914, 6914, +7366, 7366, 7811, 7811, 8249, 8249, 8680, 8680, 9102, 9102, +9516, 9516, 9920, 9920, 10315, 10315, 10701, 10701, 11077, 11077, +11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791, +13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205, +14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286, +15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007, +16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353, +16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314, +16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892, +15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098, +14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948, +13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471, +12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701, +10315, 10315, 9920, 9920, 9516, 9516, 9102, 9102, 8680, 8680, +8249, 8249, 7811, 7811, 7366, 7366, 6914, 6914, 6455, 6455, +5990, 5990, 5519, 5519, 5043, 5043, 4563, 4563, 4078, 4078, +3589, 3589, 3097, 3097, 2602, 2602, 2105, 2105, 1605, 1605, +1105, 1105, 603, 603, 100, 100, -402, -402, -904, -904, +-1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393, +-3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802, +-6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075, +-8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159, -10548, -10548, -10928, -10928, -11297, -11297, -11656, -11656, -12003, -12003, -12340, -12340, -12665, -12665, -12977, -12977, -13278, -13278, -13566, -13566, -13842, -13842, -14104, -14104, -14353, -14353, -14589, -14589, -14810, -14810, @@ -239,35 +239,35 @@ int tones[2048] = { -14304, -14304, -14053, -14053, -13788, -13788, -13510, -13510, -13219, -13219, -12916, -12916, -12600, -12600, -12273, -12273, -11935, -11935, -11585, -11585, -11224, -11224, -10853, -10853, -10471, -10471, -10079, -10079, -9679, -9679, - -9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545, - -7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234, - -4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801, - -2304, -2304, -1805, -1805, -1305, -1305, -803, -803, -301, -301, - 201, 201, 703, 703, 1205, 1205, 1705, 1705, 2204, 2204, - 2701, 2701, 3196, 3196, 3687, 3687, 4175, 4175, 4659, 4659, - 5139, 5139, 5614, 5614, 6083, 6083, 6547, 6547, 7005, 7005, - 7456, 7456, 7900, 7900, 8336, 8336, 8765, 8765, 9185, 9185, - 9597, 9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150, - 11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854, - 13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255, - 14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322, - 15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028, - 16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359, - 16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305, - 16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868, - 15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058, - 14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895, - 13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406, - 12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625, - 10237, 10237, 9840, 9840, 9434, 9434, 9018, 9018, 8594, 8594, - 8162, 8162, 7723, 7723, 7276, 7276, 6822, 6822, 6362, 6362, - 5896, 5896, 5424, 5424, 4948, 4948, 4466, 4466, 3980, 3980, - 3491, 3491, 2998, 2998, 2503, 2503, 2005, 2005, 1505, 1505, - 1004, 1004, 502, 502, 0, 0, -502, -502, -1004, -1004, - -1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491, - -3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896, - -6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162, - -8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237, +-9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545, +-7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234, +-4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801, +-2304, -2304, -1805, -1805, -1305, -1305, -803, -803, -301, -301, +201, 201, 703, 703, 1205, 1205, 1705, 1705, 2204, 2204, +2701, 2701, 3196, 3196, 3687, 3687, 4175, 4175, 4659, 4659, +5139, 5139, 5614, 5614, 6083, 6083, 6547, 6547, 7005, 7005, +7456, 7456, 7900, 7900, 8336, 8336, 8765, 8765, 9185, 9185, +9597, 9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150, +11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854, +13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255, +14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322, +15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028, +16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359, +16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305, +16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868, +15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058, +14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895, +13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406, +12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625, +10237, 10237, 9840, 9840, 9434, 9434, 9018, 9018, 8594, 8594, +8162, 8162, 7723, 7723, 7276, 7276, 6822, 6822, 6362, 6362, +5896, 5896, 5424, 5424, 4948, 4948, 4466, 4466, 3980, 3980, +3491, 3491, 2998, 2998, 2503, 2503, 2005, 2005, 1505, 1505, +1004, 1004, 502, 502, 0, 0, -502, -502, -1004, -1004, +-1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491, +-3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896, +-6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162, +-8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237, -10625, -10625, -11002, -11002, -11370, -11370, -11726, -11726, -12072, -12072, -12406, -12406, -12728, -12728, -13038, -13038, -13337, -13337, -13622, -13622, -13895, -13895, -14155, -14155, -14401, -14401, -14634, -14634, -14853, -14853, @@ -280,35 +280,35 @@ int tones[2048] = { -14255, -14255, -14001, -14001, -13733, -13733, -13452, -13452, -13159, -13159, -12854, -12854, -12536, -12536, -12207, -12207, -11866, -11866, -11513, -11513, -11150, -11150, -10777, -10777, -10393, -10393, -10000, -10000, -9597, -9597, - -9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456, - -7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139, - -4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701, - -2204, -2204, -1705, -1705, -1205, -1205, -703, -703, -201, -201, - 301, 301, 803, 803, 1305, 1305, 1805, 1805, 2304, 2304, - 2801, 2801, 3294, 3294, 3785, 3785, 4272, 4272, 4756, 4756, - 5234, 5234, 5708, 5708, 6176, 6176, 6639, 6639, 7095, 7095, - 7545, 7545, 7988, 7988, 8423, 8423, 8850, 8850, 9268, 9268, - 9679, 9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224, - 11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916, - 13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304, - 14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357, - 15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049, - 16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364, - 16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294, - 16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842, - 15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018, - 14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842, - 13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340, - 12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548, - 10159, 10159, 9759, 9759, 9351, 9351, 8934, 8934, 8509, 8509, - 8075, 8075, 7634, 7634, 7186, 7186, 6731, 6731, 6269, 6269, - 5802, 5802, 5329, 5329, 4852, 4852, 4369, 4369, 3883, 3883, - 3393, 3393, 2900, 2900, 2404, 2404, 1905, 1905, 1405, 1405, - 904, 904, 402, 402, -100, -100, -603, -603, -1105, -1105, - -1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589, - -4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990, - -6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249, - -8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315, +-9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456, +-7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139, +-4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701, +-2204, -2204, -1705, -1705, -1205, -1205, -703, -703, -201, -201, +301, 301, 803, 803, 1305, 1305, 1805, 1805, 2304, 2304, +2801, 2801, 3294, 3294, 3785, 3785, 4272, 4272, 4756, 4756, +5234, 5234, 5708, 5708, 6176, 6176, 6639, 6639, 7095, 7095, +7545, 7545, 7988, 7988, 8423, 8423, 8850, 8850, 9268, 9268, +9679, 9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224, +11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916, +13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304, +14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357, +15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049, +16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364, +16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294, +16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842, +15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018, +14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842, +13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340, +12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548, +10159, 10159, 9759, 9759, 9351, 9351, 8934, 8934, 8509, 8509, +8075, 8075, 7634, 7634, 7186, 7186, 6731, 6731, 6269, 6269, +5802, 5802, 5329, 5329, 4852, 4852, 4369, 4369, 3883, 3883, +3393, 3393, 2900, 2900, 2404, 2404, 1905, 1905, 1405, 1405, +904, 904, 402, 402, -100, -100, -603, -603, -1105, -1105, +-1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589, +-4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990, +-6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249, +-8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315, -10701, -10701, -11077, -11077, -11442, -11442, -11796, -11796, -12139, -12139, -12471, -12471, -12791, -12791, -13099, -13099, -13395, -13395, -13678, -13678, -13948, -13948, -14205, -14205, -14449, -14449, -14679, -14679, -14895, -14895, @@ -321,35 +321,35 @@ int tones[2048] = { -14205, -14205, -13948, -13948, -13678, -13678, -13395, -13395, -13099, -13099, -12791, -12791, -12471, -12471, -12139, -12139, -11796, -11796, -11442, -11442, -11077, -11077, -10701, -10701, -10315, -10315, -9920, -9920, -9516, -9516, - -9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366, - -6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043, - -4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602, - -2105, -2105, -1605, -1605, -1105, -1105, -603, -603, -100, -100, - 402, 402, 904, 904, 1405, 1405, 1905, 1905, 2404, 2404, - 2900, 2900, 3393, 3393, 3883, 3883, 4369, 4369, 4852, 4852, - 5329, 5329, 5802, 5802, 6269, 6269, 6731, 6731, 7186, 7186, - 7634, 7634, 8075, 8075, 8509, 8509, 8934, 8934, 9351, 9351, - 9759, 9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297, - 11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977, - 13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353, - 14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392, - 15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069, - 16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368, - 16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284, - 16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817, - 15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978, - 14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788, - 13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273, - 11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471, - 10079, 10079, 9679, 9679, 9268, 9268, 8850, 8850, 8423, 8423, - 7988, 7988, 7545, 7545, 7095, 7095, 6639, 6639, 6176, 6176, - 5708, 5708, 5234, 5234, 4756, 4756, 4272, 4272, 3785, 3785, - 3294, 3294, 2801, 2801, 2304, 2304, 1805, 1805, 1305, 1305, - 803, 803, 301, 301, -201, -201, -703, -703, -1205, -1205, - -1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687, - -4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083, - -6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336, - -8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393, +-9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366, +-6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043, +-4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602, +-2105, -2105, -1605, -1605, -1105, -1105, -603, -603, -100, -100, +402, 402, 904, 904, 1405, 1405, 1905, 1905, 2404, 2404, +2900, 2900, 3393, 3393, 3883, 3883, 4369, 4369, 4852, 4852, +5329, 5329, 5802, 5802, 6269, 6269, 6731, 6731, 7186, 7186, +7634, 7634, 8075, 8075, 8509, 8509, 8934, 8934, 9351, 9351, +9759, 9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297, +11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977, +13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353, +14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392, +15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069, +16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368, +16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284, +16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817, +15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978, +14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788, +13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273, +11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471, +10079, 10079, 9679, 9679, 9268, 9268, 8850, 8850, 8423, 8423, +7988, 7988, 7545, 7545, 7095, 7095, 6639, 6639, 6176, 6176, +5708, 5708, 5234, 5234, 4756, 4756, 4272, 4272, 3785, 3785, +3294, 3294, 2801, 2801, 2304, 2304, 1805, 1805, 1305, 1305, +803, 803, 301, 301, -201, -201, -703, -703, -1205, -1205, +-1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687, +-4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083, +-6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336, +-8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393, -10777, -10777, -11150, -11150, -11513, -11513, -11866, -11866, -12207, -12207, -12536, -12536, -12854, -12854, -13159, -13159, -13452, -13452, -13733, -13733, -14001, -14001, -14255, -14255, -14496, -14496, -14723, -14723, -14937, -14937, @@ -362,10 +362,10 @@ int tones[2048] = { -14155, -14155, -13895, -13895, -13622, -13622, -13337, -13337, -13038, -13038, -12728, -12728, -12406, -12406, -12072, -12072, -11726, -11726, -11370, -11370, -11002, -11002, -10625, -10625, -10237, -10237, -9840, -9840, -9434, -9434, - -9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276, - -6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948, - -4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503, - -2005, -2005, -1505, -1505, -1004, -1004, -502, -502 +-9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276, +-6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948, +-4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503, +-2005, -2005, -1505, -1505, -1004, -1004, -502, -502 }; /*****************************************************************************/ void -- cgit v1.2.3 From e68703cfe8dd2f5605c53b46fae6c9c027e7ef50 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 19:58:55 +0000 Subject: staging/easycap: Make code re-entrant In order to allow multiple EasyCAP dongles to operate simultaneously without mutual interference all static variables have been eliminated except for a persistent inventory of plugged-in dongles at module level. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 57 +- drivers/staging/easycap/easycap_debug.h | 2 +- drivers/staging/easycap/easycap_ioctl.c | 585 ++++++------ drivers/staging/easycap/easycap_low.c | 24 +- drivers/staging/easycap/easycap_main.c | 1424 ++++++++++++++-------------- drivers/staging/easycap/easycap_sound.c | 443 +++++---- drivers/staging/easycap/easycap_testcard.c | 2 +- 7 files changed, 1361 insertions(+), 1176 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 9fb0f64d5477..11ceda7dde30 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -121,7 +121,7 @@ #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60" #define USB_SKEL_MINOR_BASE 192 -#define VIDEO_DEVICE_MANY 8 +#define DONGLE_MANY 8 /*---------------------------------------------------------------------------*/ /* @@ -264,6 +264,17 @@ struct v4l2_format v4l2_format; */ /*---------------------------------------------------------------------------*/ struct easycap { +int isdongle; + +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#if defined(EASYCAP_IS_VIDEODEV_CLIENT) +struct video_device video_device; +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) +struct v4l2_device v4l2_device; +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ +#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ + unsigned int audio_pages_per_fragment; unsigned int audio_bytes_per_fragment; unsigned int audio_buffer_page_many; @@ -276,12 +287,6 @@ __s16 oldaudio; int ilk; bool microphone; -/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ -#if defined(EASYCAP_IS_VIDEODEV_CLIENT) -struct video_device *pvideo_device; -#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - struct usb_device *pusb_device; struct usb_interface *pusb_interface; @@ -306,7 +311,10 @@ int merit[180]; struct timeval timeval0; struct timeval timeval1; struct timeval timeval2; +struct timeval timeval3; +struct timeval timeval6; struct timeval timeval7; +struct timeval timeval8; long long int dnbydt; int video_interface; @@ -332,6 +340,13 @@ struct data_buffer \ struct list_head urb_video_head; struct list_head *purb_video_head; +__u8 cache[8]; +__u8 *pcache; +int video_mt; +int audio_mt; +long long audio_bytes; +__u32 isequence; + int vma_many; /*---------------------------------------------------------------------------*/ @@ -530,6 +545,7 @@ int set2to93(struct usb_device *); int regset(struct usb_device *, __u16, __u16); int regget(struct usb_device *, __u16, void *); +int isdongle(struct easycap *); /*---------------------------------------------------------------------------*/ struct signed_div_result { long long int quotient; @@ -557,20 +573,39 @@ unsigned long long int remainder; } \ } while (0) /*---------------------------------------------------------------------------*/ - +/* + * MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH + * THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE + * POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE + * IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE. BEWARE. +*/ +/*---------------------------------------------------------------------------*/ #define SAY(format, args...) do { \ - printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \ + printk(KERN_DEBUG "easycap:: %s: " \ + format, __func__, ##args); \ +} while (0) +#define SAM(format, args...) do { \ + printk(KERN_DEBUG "easycap::%i%s: " \ + format, peasycap->isdongle, __func__, ##args);\ } while (0) - #if defined(EASYCAP_DEBUG) #define JOT(n, format, args...) do { \ if (n <= debug) { \ - printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \ + printk(KERN_DEBUG "easycap:: %s: " \ + format, __func__, ##args);\ } \ } while (0) +#define JOM(n, format, args...) do { \ + if (n <= debug) { \ + printk(KERN_DEBUG "easycap::%i%s: " \ + format, peasycap->isdongle, __func__, ##args);\ + } \ +} while (0) + #else #define JOT(n, format, args...) do {} while (0) +#define JOM(n, format, args...) do {} while (0) #endif /*EASYCAP_DEBUG*/ #define MICROSECONDS(X, Y) \ diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h index 3e9b66a66076..a4dcd7dd4a89 100644 --- a/drivers/staging/easycap/easycap_debug.h +++ b/drivers/staging/easycap/easycap_debug.h @@ -1,6 +1,6 @@ /***************************************************************************** * * -* debug.h * +* easycap_debug.h * * * *****************************************************************************/ /* diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 5b038b8614d7..d91d64ad6f68 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -48,8 +48,12 @@ __u16 reg, set; int ir, rc, need; unsigned int itwas, isnow; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } peasycap_standard = &easycap_standard[0]; @@ -59,25 +63,25 @@ while (0xFFFF != peasycap_standard->mask) { peasycap_standard++; } if (0xFFFF == peasycap_standard->mask) { - SAY("ERROR: 0x%08X=std_id: standard not found\n", \ + SAM("ERROR: 0x%08X=std_id: standard not found\n", \ (unsigned int)std_id); return -EINVAL; } -SAY("user requests standard: %s\n", \ +SAM("user requests standard: %s\n", \ &(peasycap_standard->v4l2_standard.name[0])); if (peasycap->standard_offset == \ (int)(peasycap_standard - &easycap_standard[0])) { - SAY("requested standard already in effect\n"); + SAM("requested standard already in effect\n"); return 0; } peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]); peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \ peasycap_standard->v4l2_standard.frameperiod.numerator; if (!peasycap->fps) { - SAY("MISTAKE: frames-per-second is zero\n"); + SAM("MISTAKE: frames-per-second is zero\n"); return -EFAULT; } -JOT(8, "%i frames-per-second\n", peasycap->fps); +JOM(8, "%i frames-per-second\n", peasycap->fps); peasycap->usec = 1000000 / (2 * peasycap->fps); peasycap->tolerate = 1000 * (25 / peasycap->fps); @@ -94,7 +98,7 @@ case NTSC_M_JP: { reg = 0x0A; set = 0x95; ir = read_saa(peasycap->pusb_device, reg); if (0 > ir) - SAY("ERROR: cannot read SAA register 0x%02X\n", reg); + SAM("ERROR: cannot read SAA register 0x%02X\n", reg); else itwas = (unsigned int)ir; @@ -104,15 +108,15 @@ case NTSC_M_JP: { rc = write_saa(peasycap->pusb_device, reg, set); if (0 != rc) - SAY("ERROR: failed to set SAA register " \ + SAM("ERROR: failed to set SAA register " \ "0x%02X to 0x%02X for JP standard\n", reg, set); else { isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); if (0 > ir) - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "to 0x%02X\n", reg, isnow); else - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); set2to78(peasycap->pusb_device); @@ -122,7 +126,7 @@ case NTSC_M_JP: { reg = 0x0B; set = 0x48; ir = read_saa(peasycap->pusb_device, reg); if (0 > ir) - SAY("ERROR: cannot read SAA register 0x%02X\n", reg); + SAM("ERROR: cannot read SAA register 0x%02X\n", reg); else itwas = (unsigned int)ir; @@ -130,15 +134,15 @@ case NTSC_M_JP: { rc = write_saa(peasycap->pusb_device, reg, set); if (0 != rc) - SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X " \ + SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X " \ "for JP standard\n", reg, set); else { isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); if (0 > ir) - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "to 0x%02X\n", reg, isnow); else - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); set2to78(peasycap->pusb_device); @@ -176,7 +180,7 @@ default: if (need) { ir = read_saa(peasycap->pusb_device, reg); if (0 > ir) - SAY("ERROR: failed to read SAA register 0x%02X\n", reg); + SAM("ERROR: failed to read SAA register 0x%02X\n", reg); else itwas = (unsigned int)ir; @@ -184,15 +188,15 @@ if (need) { rc = write_saa(peasycap->pusb_device, reg, set); if (0 != write_saa(peasycap->pusb_device, reg, set)) { - SAY("ERROR: failed to set SAA register " \ + SAM("ERROR: failed to set SAA register " \ "0x%02X to 0x%02X for table 42\n", reg, set); } else { isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); if (0 > ir) - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "to 0x%02X\n", reg, isnow); else - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } } @@ -204,7 +208,7 @@ if (need) { reg = 0x08; ir = read_saa(peasycap->pusb_device, reg); if (0 > ir) - SAY("ERROR: failed to read SAA register 0x%02X " \ + SAM("ERROR: failed to read SAA register 0x%02X " \ "so cannot reset\n", reg); else { itwas = (unsigned int)ir; @@ -217,13 +221,13 @@ set2to78(peasycap->pusb_device); rc = write_saa(peasycap->pusb_device, reg, set); if (0 != rc) - SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); + SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); else { isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); if (0 > ir) - JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); + JOM(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); else - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } } @@ -235,7 +239,7 @@ else { reg = 0x40; ir = read_saa(peasycap->pusb_device, reg); if (0 > ir) - SAY("ERROR: failed to read SAA register 0x%02X " \ + SAM("ERROR: failed to read SAA register 0x%02X " \ "so cannot reset\n", reg); else { itwas = (unsigned int)ir; @@ -248,13 +252,13 @@ set2to78(peasycap->pusb_device); rc = write_saa(peasycap->pusb_device, reg, set); if (0 != rc) - SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); + SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); else { isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); if (0 > ir) - JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); + JOM(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); else - JOT(8, "SAA register 0x%02X changed " \ + JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } } @@ -266,7 +270,7 @@ else { reg = 0x5A; ir = read_saa(peasycap->pusb_device, reg); if (0 > ir) - SAY("ERROR: failed to read SAA register 0x%02X but continuing\n", reg); + SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg); itwas = (unsigned int)ir; if (peasycap_standard->mask & 0x0001) set = 0x0A ; @@ -276,19 +280,19 @@ if (0 > ir) set2to78(peasycap->pusb_device); if (0 != write_saa(peasycap->pusb_device, reg, set)) - SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \ + SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \ reg, set); else { isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); if (0 > ir) - JOT(8, "SAA register 0x%02X changed " + JOM(8, "SAA register 0x%02X changed " "to 0x%02X\n", reg, isnow); else - JOT(8, "SAA register 0x%02X changed " + JOM(8, "SAA register 0x%02X changed " "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } if (0 != check_saa(peasycap->pusb_device)) - SAY("ERROR: check_saa() failed\n"); + SAM("ERROR: check_saa() failed\n"); return 0; } /*****************************************************************************/ @@ -325,28 +329,28 @@ int miss, multiplier, best; char bf[5], *pc; __u32 uc; -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } p = peasycap->pusb_device; if ((struct usb_device *)NULL == p) { - SAY("ERROR: peaycap->pusb_device is NULL\n"); + SAM("ERROR: peaycap->pusb_device is NULL\n"); return -EFAULT; } pc = &bf[0]; uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0; mask = easycap_standard[peasycap->standard_offset].mask; -SAY("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \ +SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \ width, height, pc, pixelformat, field, mask); if (V4L2_FIELD_ANY == field) { field = V4L2_FIELD_INTERLACED; - SAY("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n"); + SAM("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n"); } peasycap_best_format = (struct easycap_format *)NULL; peasycap_format = &easycap_format[0]; while (0 != peasycap_format->v4l2_format.fmt.pix.width) { - JOT(16, ".> %i %i 0x%08X %ix%i\n", \ + JOM(16, ".> %i %i 0x%08X %ix%i\n", \ peasycap_format->mask & 0x01, peasycap_format->v4l2_format.fmt.pix.field, peasycap_format->v4l2_format.fmt.pix.pixelformat, @@ -365,7 +369,7 @@ while (0 != peasycap_format->v4l2_format.fmt.pix.width) { peasycap_format++; } if (0 == peasycap_format->v4l2_format.fmt.pix.width) { - SAY("cannot do: %ix%i with standard mask 0x%02X\n", \ + SAM("cannot do: %ix%i with standard mask 0x%02X\n", \ width, height, mask); peasycap_format = &easycap_format[0]; best = -1; while (0 != peasycap_format->v4l2_format.fmt.pix.width) { @@ -386,16 +390,16 @@ if (0 == peasycap_format->v4l2_format.fmt.pix.width) { peasycap_format++; } if (-1 == best) { - SAY("cannot do %ix... with standard mask 0x%02X\n", \ + SAM("cannot do %ix... with standard mask 0x%02X\n", \ width, mask); - SAY("cannot do ...x%i with standard mask 0x%02X\n", \ + SAM("cannot do ...x%i with standard mask 0x%02X\n", \ height, mask); - SAY(" %ix%i unmatched\n", width, height); + SAM(" %ix%i unmatched\n", width, height); return peasycap->format_offset; } } if ((struct easycap_format *)NULL == peasycap_best_format) { - SAY("MISTAKE: peasycap_best_format is NULL"); + SAM("MISTAKE: peasycap_best_format is NULL"); return -EINVAL; } peasycap_format = peasycap_best_format; @@ -406,10 +410,10 @@ if (true == try) /*...........................................................................*/ if (false != try) { - SAY("MISTAKE: true==try where is should be false\n"); + SAM("MISTAKE: true==try where is should be false\n"); return -EINVAL; } -SAY("actioning: %ix%i %s\n", \ +SAM("actioning: %ix%i %s\n", \ peasycap_format->v4l2_format.fmt.pix.width, \ peasycap_format->v4l2_format.fmt.pix.height, &peasycap_format->name[0]); @@ -441,7 +445,7 @@ peasycap->frame_buffer_used = peasycap->bytesperpixel * \ peasycap->width * peasycap->height; if (true == peasycap->offerfields) { - SAY("WARNING: %i=peasycap->field is untested: " \ + SAM("WARNING: %i=peasycap->field is untested: " \ "please report problems\n", peasycap->field); @@ -474,13 +478,13 @@ if (0 == (0x01 & peasycap_format->mask)) { (288 == \ peasycap_format->v4l2_format.fmt.pix.height))) { if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) { - SAY("ERROR: set_resolution() failed\n"); + SAM("ERROR: set_resolution() failed\n"); return -EINVAL; } } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \ (576 == peasycap_format->v4l2_format.fmt.pix.height)) { if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) { - SAY("ERROR: set_resolution() failed\n"); + SAM("ERROR: set_resolution() failed\n"); return -EINVAL; } } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \ @@ -491,11 +495,11 @@ if (0 == (0x01 & peasycap_format->mask)) { (240 == \ peasycap_format->v4l2_format.fmt.pix.height))) { if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) { - SAY("ERROR: set_resolution() failed\n"); + SAM("ERROR: set_resolution() failed\n"); return -EINVAL; } } else { - SAY("MISTAKE: bad format, cannot set resolution\n"); + SAM("MISTAKE: bad format, cannot set resolution\n"); return -EINVAL; } /*---------------------------------------------------------------------------*/ @@ -512,7 +516,7 @@ if (0 == (0x01 & peasycap_format->mask)) { (240 == \ peasycap_format->v4l2_format.fmt.pix.height))) { if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) { - SAY("ERROR: set_resolution() failed\n"); + SAM("ERROR: set_resolution() failed\n"); return -EINVAL; } } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \ @@ -523,11 +527,11 @@ if (0 == (0x01 & peasycap_format->mask)) { (240 == \ peasycap_format->v4l2_format.fmt.pix.height))) { if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) { - SAY("ERROR: set_resolution() failed\n"); + SAM("ERROR: set_resolution() failed\n"); return -EINVAL; } } else { - SAY("MISTAKE: bad format, cannot set resolution\n"); + SAM("MISTAKE: bad format, cannot set resolution\n"); return -EINVAL; } } @@ -543,8 +547,12 @@ int adjust_brightness(struct easycap *peasycap, int value) unsigned int mood; int i1; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } i1 = 0; @@ -559,10 +567,10 @@ while (0xFFFFFFFF != easycap_control[i1].id) { set2to78(peasycap->pusb_device); if (!write_saa(peasycap->pusb_device, 0x0A, mood)) { - SAY("adjusting brightness to 0x%02X\n", mood); + SAM("adjusting brightness to 0x%02X\n", mood); return 0; } else { - SAY("WARNING: failed to adjust brightness " \ + SAM("WARNING: failed to adjust brightness " \ "to 0x%02X\n", mood); return -ENOENT; } @@ -573,7 +581,7 @@ while (0xFFFFFFFF != easycap_control[i1].id) { } i1++; } -SAY("WARNING: failed to adjust brightness: control not found\n"); +SAM("WARNING: failed to adjust brightness: control not found\n"); return -ENOENT; } /*****************************************************************************/ @@ -582,8 +590,12 @@ int adjust_contrast(struct easycap *peasycap, int value) unsigned int mood; int i1; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } i1 = 0; @@ -598,10 +610,10 @@ while (0xFFFFFFFF != easycap_control[i1].id) { set2to78(peasycap->pusb_device); if (!write_saa(peasycap->pusb_device, 0x0B, mood)) { - SAY("adjusting contrast to 0x%02X\n", mood); + SAM("adjusting contrast to 0x%02X\n", mood); return 0; } else { - SAY("WARNING: failed to adjust contrast to " \ + SAM("WARNING: failed to adjust contrast to " \ "0x%02X\n", mood); return -ENOENT; } @@ -612,7 +624,7 @@ while (0xFFFFFFFF != easycap_control[i1].id) { } i1++; } -SAY("WARNING: failed to adjust contrast: control not found\n"); +SAM("WARNING: failed to adjust contrast: control not found\n"); return -ENOENT; } /*****************************************************************************/ @@ -621,8 +633,12 @@ int adjust_saturation(struct easycap *peasycap, int value) unsigned int mood; int i1; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } i1 = 0; @@ -637,10 +653,10 @@ while (0xFFFFFFFF != easycap_control[i1].id) { set2to78(peasycap->pusb_device); if (!write_saa(peasycap->pusb_device, 0x0C, mood)) { - SAY("adjusting saturation to 0x%02X\n", mood); + SAM("adjusting saturation to 0x%02X\n", mood); return 0; } else { - SAY("WARNING: failed to adjust saturation to " \ + SAM("WARNING: failed to adjust saturation to " \ "0x%02X\n", mood); return -ENOENT; } @@ -651,7 +667,7 @@ while (0xFFFFFFFF != easycap_control[i1].id) { } i1++; } -SAY("WARNING: failed to adjust saturation: control not found\n"); +SAM("WARNING: failed to adjust saturation: control not found\n"); return -ENOENT; } /*****************************************************************************/ @@ -660,8 +676,12 @@ int adjust_hue(struct easycap *peasycap, int value) unsigned int mood; int i1, i2; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } i1 = 0; @@ -677,10 +697,10 @@ while (0xFFFFFFFF != easycap_control[i1].id) { set2to78(peasycap->pusb_device); if (!write_saa(peasycap->pusb_device, 0x0D, mood)) { - SAY("adjusting hue to 0x%02X\n", mood); + SAM("adjusting hue to 0x%02X\n", mood); return 0; } else { - SAY("WARNING: failed to adjust hue to 0x%02X\n", mood); + SAM("WARNING: failed to adjust hue to 0x%02X\n", mood); return -ENOENT; } @@ -690,7 +710,7 @@ while (0xFFFFFFFF != easycap_control[i1].id) { } i1++; } -SAY("WARNING: failed to adjust hue: control not found\n"); +SAM("WARNING: failed to adjust hue: control not found\n"); return -ENOENT; } /*****************************************************************************/ @@ -699,8 +719,12 @@ int adjust_volume(struct easycap *peasycap, int value) __s8 mood; int i1; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } i1 = 0; @@ -714,10 +738,10 @@ while (0xFFFFFFFF != easycap_control[i1].id) { ((31 < peasycap->volume) ? 31 : \ (__s8) peasycap->volume); if (!audio_gainset(peasycap->pusb_device, mood)) { - SAY("adjusting volume to 0x%01X\n", mood); + SAM("adjusting volume to 0x%01X\n", mood); return 0; } else { - SAY("WARNING: failed to adjust volume to " \ + SAM("WARNING: failed to adjust volume to " \ "0x%1X\n", mood); return -ENOENT; } @@ -725,7 +749,7 @@ while (0xFFFFFFFF != easycap_control[i1].id) { } i1++; } -SAY("WARNING: failed to adjust volume: control not found\n"); +SAM("WARNING: failed to adjust volume: control not found\n"); return -ENOENT; } /*****************************************************************************/ @@ -744,8 +768,12 @@ int adjust_mute(struct easycap *peasycap, int value) { int i1; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } i1 = 0; @@ -756,13 +784,13 @@ while (0xFFFFFFFF != easycap_control[i1].id) { case 1: { peasycap->audio_idle = 1; peasycap->timeval0.tv_sec = 0; - SAY("adjusting mute: %i=peasycap->audio_idle\n", \ + SAM("adjusting mute: %i=peasycap->audio_idle\n", \ peasycap->audio_idle); return 0; } default: { peasycap->audio_idle = 0; - SAY("adjusting mute: %i=peasycap->audio_idle\n", \ + SAM("adjusting mute: %i=peasycap->audio_idle\n", \ peasycap->audio_idle); return 0; } @@ -771,26 +799,28 @@ while (0xFFFFFFFF != easycap_control[i1].id) { } i1++; } -SAY("WARNING: failed to adjust mute: control not found\n"); +SAM("WARNING: failed to adjust mute: control not found\n"); return -ENOENT; } - -/*--------------------------------------------------------------------------*/ +/*****************************************************************************/ static int easycap_ioctl_bkl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { static struct easycap *peasycap; static struct usb_device *p; -static __u32 isequence; +if (NULL == file) { + SAY("ERROR: file is NULL\n"); + return -ERESTARTSYS; +} peasycap = file->private_data; if (NULL == peasycap) { - SAY("ERROR: peasycap is NULL\n"); + SAY("ERROR: peasycap is NULL.\n"); return -1; } p = peasycap->pusb_device; -if ((struct usb_device *)NULL == p) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); +if (NULL == p) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } /*---------------------------------------------------------------------------*/ @@ -803,15 +833,15 @@ if ((struct usb_device *)NULL == p) { /*---------------------------------------------------------------------------*/ switch (cmd) { case VIDIOC_QUERYCAP: { - static struct v4l2_capability v4l2_capability; - static char version[16], *p1, *p2; - static int i, rc, k[3]; - static long lng; + struct v4l2_capability v4l2_capability; + char version[16], *p1, *p2; + int i, rc, k[3]; + long lng; - JOT(8, "VIDIOC_QUERYCAP\n"); + JOM(8, "VIDIOC_QUERYCAP\n"); if (16 <= strlen(EASYCAP_DRIVER_VERSION)) { - SAY("ERROR: bad driver version string\n"); return -EINVAL; + SAM("ERROR: bad driver version string\n"); return -EINVAL; } strcpy(&version[0], EASYCAP_DRIVER_VERSION); for (i = 0; i < 3; i++) @@ -826,7 +856,7 @@ case VIDIOC_QUERYCAP: { if (3 > i) { rc = (int) strict_strtol(p1, 10, &lng); if (0 != rc) { - SAY("ERROR: %i=strict_strtol(%s,.,,)\n", \ + SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \ rc, p1); return -EINVAL; } @@ -844,7 +874,7 @@ case VIDIOC_QUERYCAP: { V4L2_CAP_AUDIO | V4L2_CAP_READWRITE; v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]); - JOT(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]); + JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]); strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \ sizeof(v4l2_capability.card)); @@ -853,7 +883,7 @@ case VIDIOC_QUERYCAP: { sizeof(v4l2_capability.bus_info)) < 0) { strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \ sizeof(v4l2_capability.bus_info)); - JOT(8, "%s=v4l2_capability.bus_info\n", \ + JOM(8, "%s=v4l2_capability.bus_info\n", \ &v4l2_capability.bus_info[0]); } if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \ @@ -863,10 +893,10 @@ case VIDIOC_QUERYCAP: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUMINPUT: { - static struct v4l2_input v4l2_input; - static __u32 index; + struct v4l2_input v4l2_input; + __u32 index; - JOT(8, "VIDIOC_ENUMINPUT\n"); + JOM(8, "VIDIOC_ENUMINPUT\n"); if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \ sizeof(struct v4l2_input))) @@ -885,7 +915,7 @@ case VIDIOC_ENUMINPUT: { v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ V4L2_STD_NTSC ; v4l2_input.status = 0; - JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); break; } case 1: { @@ -897,7 +927,7 @@ case VIDIOC_ENUMINPUT: { v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ V4L2_STD_NTSC ; v4l2_input.status = 0; - JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); break; } case 2: { @@ -909,7 +939,7 @@ case VIDIOC_ENUMINPUT: { v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ V4L2_STD_NTSC ; v4l2_input.status = 0; - JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); break; } case 3: { @@ -921,7 +951,7 @@ case VIDIOC_ENUMINPUT: { v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ V4L2_STD_NTSC ; v4l2_input.status = 0; - JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); break; } case 4: { @@ -933,7 +963,7 @@ case VIDIOC_ENUMINPUT: { v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ V4L2_STD_NTSC ; v4l2_input.status = 0; - JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); break; } case 5: { @@ -945,11 +975,11 @@ case VIDIOC_ENUMINPUT: { v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \ V4L2_STD_NTSC ; v4l2_input.status = 0; - JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); break; } default: { - JOT(8, "%i=index: exhausts inputs\n", index); + JOM(8, "%i=index: exhausts inputs\n", index); return -EINVAL; } } @@ -961,11 +991,11 @@ case VIDIOC_ENUMINPUT: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_INPUT: { - static __u32 index; + __u32 index; - JOT(8, "VIDIOC_G_INPUT\n"); + JOM(8, "VIDIOC_G_INPUT\n"); index = (__u32)peasycap->input; - JOT(8, "user is told: %i\n", index); + JOM(8, "user is told: %i\n", index); if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) return -EFAULT; break; @@ -973,22 +1003,22 @@ case VIDIOC_G_INPUT: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_INPUT: { - static __u32 index; + __u32 index; - JOT(8, "VIDIOC_S_INPUT\n"); + JOM(8, "VIDIOC_S_INPUT\n"); if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) return -EFAULT; - JOT(8, "user requests input %i\n", index); + JOM(8, "user requests input %i\n", index); if ((int)index == peasycap->input) { - SAY("requested input already in effect\n"); + SAM("requested input already in effect\n"); break; } if ((0 > index) || (5 < index)) { - JOT(8, "ERROR: bad requested input: %i\n", index); + JOM(8, "ERROR: bad requested input: %i\n", index); return -EINVAL; } peasycap->input = (int)index; @@ -999,14 +1029,14 @@ case VIDIOC_S_INPUT: } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUMAUDIO: { - JOT(8, "VIDIOC_ENUMAUDIO\n"); + JOM(8, "VIDIOC_ENUMAUDIO\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUMAUDOUT: { - static struct v4l2_audioout v4l2_audioout; + struct v4l2_audioout v4l2_audioout; - JOT(8, "VIDIOC_ENUMAUDOUT\n"); + JOM(8, "VIDIOC_ENUMAUDOUT\n"); if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \ sizeof(struct v4l2_audioout))) @@ -1025,10 +1055,10 @@ case VIDIOC_ENUMAUDOUT: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QUERYCTRL: { - static int i1; - static struct v4l2_queryctrl v4l2_queryctrl; + int i1; + struct v4l2_queryctrl v4l2_queryctrl; - JOT(8, "VIDIOC_QUERYCTRL\n"); + JOM(8, "VIDIOC_QUERYCTRL\n"); if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \ sizeof(struct v4l2_queryctrl))) @@ -1037,7 +1067,7 @@ case VIDIOC_QUERYCTRL: { i1 = 0; while (0xFFFFFFFF != easycap_control[i1].id) { if (easycap_control[i1].id == v4l2_queryctrl.id) { - JOT(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \ + JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \ ".name\n", &easycap_control[i1].name[0], i1); memcpy(&v4l2_queryctrl, &easycap_control[i1], \ sizeof(struct v4l2_queryctrl)); @@ -1046,7 +1076,7 @@ case VIDIOC_QUERYCTRL: { i1++; } if (0xFFFFFFFF == easycap_control[i1].id) { - JOT(8, "%i=index: exhausts controls\n", i1); + JOM(8, "%i=index: exhausts controls\n", i1); return -EINVAL; } if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \ @@ -1056,15 +1086,15 @@ case VIDIOC_QUERYCTRL: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QUERYMENU: { - JOT(8, "VIDIOC_QUERYMENU unsupported\n"); + JOM(8, "VIDIOC_QUERYMENU unsupported\n"); return -EINVAL; break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_CTRL: { - static struct v4l2_control v4l2_control; + struct v4l2_control v4l2_control; - JOT(8, "VIDIOC_G_CTRL\n"); + JOM(8, "VIDIOC_G_CTRL\n"); if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ sizeof(struct v4l2_control))) @@ -1073,27 +1103,27 @@ case VIDIOC_G_CTRL: { switch (v4l2_control.id) { case V4L2_CID_BRIGHTNESS: { v4l2_control.value = peasycap->brightness; - JOT(8, "user enquires brightness: %i\n", v4l2_control.value); + JOM(8, "user enquires brightness: %i\n", v4l2_control.value); break; } case V4L2_CID_CONTRAST: { v4l2_control.value = peasycap->contrast; - JOT(8, "user enquires contrast: %i\n", v4l2_control.value); + JOM(8, "user enquires contrast: %i\n", v4l2_control.value); break; } case V4L2_CID_SATURATION: { v4l2_control.value = peasycap->saturation; - JOT(8, "user enquires saturation: %i\n", v4l2_control.value); + JOM(8, "user enquires saturation: %i\n", v4l2_control.value); break; } case V4L2_CID_HUE: { v4l2_control.value = peasycap->hue; - JOT(8, "user enquires hue: %i\n", v4l2_control.value); + JOM(8, "user enquires hue: %i\n", v4l2_control.value); break; } case V4L2_CID_AUDIO_VOLUME: { v4l2_control.value = peasycap->volume; - JOT(8, "user enquires volume: %i\n", v4l2_control.value); + JOM(8, "user enquires volume: %i\n", v4l2_control.value); break; } case V4L2_CID_AUDIO_MUTE: { @@ -1101,11 +1131,11 @@ case VIDIOC_G_CTRL: { v4l2_control.value = true; else v4l2_control.value = false; - JOT(8, "user enquires mute: %i\n", v4l2_control.value); + JOM(8, "user enquires mute: %i\n", v4l2_control.value); break; } default: { - SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \ + SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \ v4l2_control.id); return -EINVAL; } @@ -1118,14 +1148,14 @@ case VIDIOC_G_CTRL: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(VIDIOC_S_CTRL_OLD) case VIDIOC_S_CTRL_OLD: { - JOT(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n"); + JOM(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n"); } #endif /*VIDIOC_S_CTRL_OLD*/ case VIDIOC_S_CTRL: { - static struct v4l2_control v4l2_control; + struct v4l2_control v4l2_control; - JOT(8, "VIDIOC_S_CTRL\n"); + JOM(8, "VIDIOC_S_CTRL\n"); if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ sizeof(struct v4l2_control))) @@ -1133,31 +1163,31 @@ case VIDIOC_S_CTRL: switch (v4l2_control.id) { case V4L2_CID_BRIGHTNESS: { - JOT(8, "user requests brightness %i\n", v4l2_control.value); + JOM(8, "user requests brightness %i\n", v4l2_control.value); if (0 != adjust_brightness(peasycap, v4l2_control.value)) ; break; } case V4L2_CID_CONTRAST: { - JOT(8, "user requests contrast %i\n", v4l2_control.value); + JOM(8, "user requests contrast %i\n", v4l2_control.value); if (0 != adjust_contrast(peasycap, v4l2_control.value)) ; break; } case V4L2_CID_SATURATION: { - JOT(8, "user requests saturation %i\n", v4l2_control.value); + JOM(8, "user requests saturation %i\n", v4l2_control.value); if (0 != adjust_saturation(peasycap, v4l2_control.value)) ; break; } case V4L2_CID_HUE: { - JOT(8, "user requests hue %i\n", v4l2_control.value); + JOM(8, "user requests hue %i\n", v4l2_control.value); if (0 != adjust_hue(peasycap, v4l2_control.value)) ; break; } case V4L2_CID_AUDIO_VOLUME: { - JOT(8, "user requests volume %i\n", v4l2_control.value); + JOM(8, "user requests volume %i\n", v4l2_control.value); if (0 != adjust_volume(peasycap, v4l2_control.value)) ; break; @@ -1165,18 +1195,18 @@ case VIDIOC_S_CTRL: case V4L2_CID_AUDIO_MUTE: { int mute; - JOT(8, "user requests mute %i\n", v4l2_control.value); + JOM(8, "user requests mute %i\n", v4l2_control.value); if (true == v4l2_control.value) mute = 1; else mute = 0; if (0 != adjust_mute(peasycap, mute)) - SAY("WARNING: failed to adjust mute to %i\n", mute); + SAM("WARNING: failed to adjust mute to %i\n", mute); break; } default: { - SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \ + SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \ v4l2_control.id); return -EINVAL; } @@ -1185,15 +1215,15 @@ case VIDIOC_S_CTRL: } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_EXT_CTRLS: { - JOT(8, "VIDIOC_S_EXT_CTRLS unsupported\n"); + JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUM_FMT: { - static __u32 index; - static struct v4l2_fmtdesc v4l2_fmtdesc; + __u32 index; + struct v4l2_fmtdesc v4l2_fmtdesc; - JOT(8, "VIDIOC_ENUM_FMT\n"); + JOM(8, "VIDIOC_ENUM_FMT\n"); if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \ sizeof(struct v4l2_fmtdesc))) @@ -1210,46 +1240,46 @@ case VIDIOC_ENUM_FMT: { v4l2_fmtdesc.flags = 0; strcpy(&v4l2_fmtdesc.description[0], "uyvy"); v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY; - JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); break; } case 1: { v4l2_fmtdesc.flags = 0; strcpy(&v4l2_fmtdesc.description[0], "yuy2"); v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV; - JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); break; } case 2: { v4l2_fmtdesc.flags = 0; strcpy(&v4l2_fmtdesc.description[0], "rgb24"); v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24; - JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); break; } case 3: { v4l2_fmtdesc.flags = 0; strcpy(&v4l2_fmtdesc.description[0], "rgb32"); v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32; - JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); break; } case 4: { v4l2_fmtdesc.flags = 0; strcpy(&v4l2_fmtdesc.description[0], "bgr24"); v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24; - JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); break; } case 5: { v4l2_fmtdesc.flags = 0; strcpy(&v4l2_fmtdesc.description[0], "bgr32"); v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32; - JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); + JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); break; } default: { - JOT(8, "%i=index: exhausts formats\n", index); + JOM(8, "%i=index: exhausts formats\n", index); return -EINVAL; } } @@ -1260,19 +1290,19 @@ case VIDIOC_ENUM_FMT: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUM_FRAMESIZES: { - JOT(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n"); + JOM(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n"); return -EINVAL; } case VIDIOC_ENUM_FRAMEINTERVALS: { - JOT(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n"); + JOM(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_FMT: { - static struct v4l2_format v4l2_format; - static struct v4l2_pix_format v4l2_pix_format; + struct v4l2_format v4l2_format; + struct v4l2_pix_format v4l2_pix_format; - JOT(8, "VIDIOC_G_FMT\n"); + JOM(8, "VIDIOC_G_FMT\n"); if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ sizeof(struct v4l2_format))) @@ -1286,7 +1316,7 @@ case VIDIOC_G_FMT: { memcpy(&(v4l2_format.fmt.pix), \ &(easycap_format[peasycap->format_offset]\ .v4l2_format.fmt.pix), sizeof(v4l2_pix_format)); - JOT(8, "user is told: %s\n", \ + JOM(8, "user is told: %s\n", \ &easycap_format[peasycap->format_offset].name[0]); if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ @@ -1297,16 +1327,16 @@ case VIDIOC_G_FMT: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: { - static struct v4l2_format v4l2_format; - static struct v4l2_pix_format v4l2_pix_format; - static bool try; - static int best_format; + struct v4l2_format v4l2_format; + struct v4l2_pix_format v4l2_pix_format; + bool try; + int best_format; if (VIDIOC_TRY_FMT == cmd) { - JOT(8, "VIDIOC_TRY_FMT\n"); + JOM(8, "VIDIOC_TRY_FMT\n"); try = true; } else { - JOT(8, "VIDIOC_S_FMT\n"); + JOM(8, "VIDIOC_S_FMT\n"); try = false; } @@ -1321,7 +1351,7 @@ case VIDIOC_S_FMT: { v4l2_format.fmt.pix.field, \ try); if (0 > best_format) { - JOT(8, "WARNING: adjust_format() returned %i\n", best_format); + JOM(8, "WARNING: adjust_format() returned %i\n", best_format); return -ENOENT; } /*...........................................................................*/ @@ -1330,7 +1360,7 @@ case VIDIOC_S_FMT: { memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\ .v4l2_format.fmt.pix), sizeof(v4l2_pix_format)); - JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]); + JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]); if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ sizeof(struct v4l2_format))) @@ -1339,16 +1369,16 @@ case VIDIOC_S_FMT: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_CROPCAP: { - static struct v4l2_cropcap v4l2_cropcap; + struct v4l2_cropcap v4l2_cropcap; - JOT(8, "VIDIOC_CROPCAP\n"); + JOM(8, "VIDIOC_CROPCAP\n"); if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \ sizeof(struct v4l2_cropcap))) return -EFAULT; if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap)); v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -1363,7 +1393,7 @@ case VIDIOC_CROPCAP: { v4l2_cropcap.pixelaspect.numerator = 1; v4l2_cropcap.pixelaspect.denominator = 1; - JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); + JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \ sizeof(struct v4l2_cropcap))) @@ -1373,12 +1403,12 @@ case VIDIOC_CROPCAP: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_CROP: case VIDIOC_S_CROP: { - JOT(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n"); + JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QUERYSTD: { - JOT(8, "VIDIOC_QUERYSTD: " \ + JOM(8, "VIDIOC_QUERYSTD: " \ "EasyCAP is incapable of detecting standard\n"); return -EINVAL; break; @@ -1392,12 +1422,12 @@ case VIDIOC_QUERYSTD: { */ /*---------------------------------------------------------------------------*/ case VIDIOC_ENUMSTD: { - static int last0 = -1, last1 = -1, last2 = -1, last3 = -1; - static struct v4l2_standard v4l2_standard; - static __u32 index; - static struct easycap_standard const *peasycap_standard; + int last0 = -1, last1 = -1, last2 = -1, last3 = -1; + struct v4l2_standard v4l2_standard; + __u32 index; + struct easycap_standard const *peasycap_standard; - JOT(8, "VIDIOC_ENUMSTD\n"); + JOM(8, "VIDIOC_ENUMSTD\n"); if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \ sizeof(struct v4l2_standard))) @@ -1420,10 +1450,10 @@ case VIDIOC_ENUMSTD: { peasycap_standard++; } if (0xFFFF == peasycap_standard->mask) { - JOT(8, "%i=index: exhausts standards\n", index); + JOM(8, "%i=index: exhausts standards\n", index); return -EINVAL; } - JOT(8, "%i=index: %s\n", index, \ + JOM(8, "%i=index: %s\n", index, \ &(peasycap_standard->v4l2_standard.name[0])); memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), \ sizeof(struct v4l2_standard)); @@ -1437,10 +1467,10 @@ case VIDIOC_ENUMSTD: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_STD: { - static v4l2_std_id std_id; - static struct easycap_standard const *peasycap_standard; + v4l2_std_id std_id; + struct easycap_standard const *peasycap_standard; - JOT(8, "VIDIOC_G_STD\n"); + JOM(8, "VIDIOC_G_STD\n"); if (0 != copy_from_user(&std_id, (void __user *)arg, \ sizeof(v4l2_std_id))) @@ -1449,7 +1479,7 @@ case VIDIOC_G_STD: { peasycap_standard = &easycap_standard[peasycap->standard_offset]; std_id = peasycap_standard->v4l2_standard.id; - JOT(8, "user is told: %s\n", \ + JOM(8, "user is told: %s\n", \ &peasycap_standard->v4l2_standard.name[0]); if (0 != copy_to_user((void __user *)arg, &std_id, \ @@ -1459,10 +1489,10 @@ case VIDIOC_G_STD: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_STD: { - static v4l2_std_id std_id; - static int rc; + v4l2_std_id std_id; + int rc; - JOT(8, "VIDIOC_S_STD\n"); + JOM(8, "VIDIOC_S_STD\n"); if (0 != copy_from_user(&std_id, (void __user *)arg, \ sizeof(v4l2_std_id))) @@ -1470,17 +1500,17 @@ case VIDIOC_S_STD: { rc = adjust_standard(peasycap, std_id); if (0 > rc) { - JOT(8, "WARNING: adjust_standard() returned %i\n", rc); + JOM(8, "WARNING: adjust_standard() returned %i\n", rc); return -ENOENT; } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_REQBUFS: { - static int nbuffers; - static struct v4l2_requestbuffers v4l2_requestbuffers; + int nbuffers; + struct v4l2_requestbuffers v4l2_requestbuffers; - JOT(8, "VIDIOC_REQBUFS\n"); + JOM(8, "VIDIOC_REQBUFS\n"); if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \ sizeof(struct v4l2_requestbuffers))) @@ -1491,16 +1521,16 @@ case VIDIOC_REQBUFS: { if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) return -EINVAL; nbuffers = v4l2_requestbuffers.count; - JOT(8, " User requests %i buffers ...\n", nbuffers); + JOM(8, " User requests %i buffers ...\n", nbuffers); if (nbuffers < 2) nbuffers = 2; if (nbuffers > FRAME_BUFFER_MANY) nbuffers = FRAME_BUFFER_MANY; if (v4l2_requestbuffers.count == nbuffers) { - JOT(8, " ... agree to %i buffers\n", \ + JOM(8, " ... agree to %i buffers\n", \ nbuffers); } else { - JOT(8, " ... insist on %i buffers\n", \ + JOM(8, " ... insist on %i buffers\n", \ nbuffers); v4l2_requestbuffers.count = nbuffers; } @@ -1513,13 +1543,13 @@ case VIDIOC_REQBUFS: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QUERYBUF: { - static __u32 index; - static struct v4l2_buffer v4l2_buffer; + __u32 index; + struct v4l2_buffer v4l2_buffer; - JOT(8, "VIDIOC_QUERYBUF\n"); + JOM(8, "VIDIOC_QUERYBUF\n"); if (peasycap->video_eof) { - JOT(8, "returning -1 because %i=video_eof\n", \ + JOM(8, "returning -1 because %i=video_eof\n", \ peasycap->video_eof); return -1; } @@ -1545,17 +1575,17 @@ case VIDIOC_QUERYBUF: { v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE; v4l2_buffer.length = FRAME_BUFFER_SIZE; - JOT(16, " %10i=index\n", v4l2_buffer.index); - JOT(16, " 0x%08X=type\n", v4l2_buffer.type); - JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused); - JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags); - JOT(16, " %10i=field\n", v4l2_buffer.field); - JOT(16, " %10li=timestamp.tv_usec\n", \ + JOM(16, " %10i=index\n", v4l2_buffer.index); + JOM(16, " 0x%08X=type\n", v4l2_buffer.type); + JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); + JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); + JOM(16, " %10i=field\n", v4l2_buffer.field); + JOM(16, " %10li=timestamp.tv_usec\n", \ (long)v4l2_buffer.timestamp.tv_usec); - JOT(16, " %10i=sequence\n", v4l2_buffer.sequence); - JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory); - JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset); - JOT(16, " %10i=length\n", v4l2_buffer.length); + JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); + JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory); + JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset); + JOM(16, " %10i=length\n", v4l2_buffer.length); if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ sizeof(struct v4l2_buffer))) @@ -1564,9 +1594,9 @@ case VIDIOC_QUERYBUF: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QBUF: { - static struct v4l2_buffer v4l2_buffer; + struct v4l2_buffer v4l2_buffer; - JOT(8, "VIDIOC_QBUF\n"); + JOM(8, "VIDIOC_QBUF\n"); if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ sizeof(struct v4l2_buffer))) @@ -1588,7 +1618,7 @@ case VIDIOC_QBUF: { sizeof(struct v4l2_buffer))) return -EFAULT; - JOT(8, "..... user queueing frame buffer %i\n", \ + JOM(8, "..... user queueing frame buffer %i\n", \ (int)v4l2_buffer.index); peasycap->frame_lock = 0; @@ -1599,20 +1629,20 @@ case VIDIOC_QBUF: { case VIDIOC_DQBUF: { #if defined(AUDIOTIME) - static struct signed_div_result sdr; - static long long int above, below, dnbydt, fudge, sll; - static unsigned long long int ull; - static struct timeval timeval0; + struct signed_div_result sdr; + long long int above, below, dnbydt, fudge, sll; + unsigned long long int ull; + struct timeval timeval0; struct timeval timeval1; #endif /*AUDIOTIME*/ - static struct timeval timeval, timeval2; - static int i, j; - static struct v4l2_buffer v4l2_buffer; + struct timeval timeval, timeval2; + int i, j; + struct v4l2_buffer v4l2_buffer; - JOT(8, "VIDIOC_DQBUF\n"); + JOM(8, "VIDIOC_DQBUF\n"); if ((peasycap->video_idle) || (peasycap->video_eof)) { - JOT(8, "returning -EIO because " \ + JOM(8, "returning -EIO because " \ "%i=video_idle %i=video_eof\n", \ peasycap->video_idle, peasycap->video_eof); return -EIO; @@ -1626,7 +1656,7 @@ case VIDIOC_DQBUF: return -EINVAL; if (!peasycap->video_isoc_streaming) { - JOT(16, "returning -EIO because video urbs not streaming\n"); + JOM(16, "returning -EIO because video urbs not streaming\n"); return -EIO; } /*---------------------------------------------------------------------------*/ @@ -1645,12 +1675,12 @@ case VIDIOC_DQBUF: return -EIO; } if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) { - SAY("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \ + SAM("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \ peasycap->done[peasycap->frame_read]); } peasycap->polled = 0; - if (!(isequence % 10)) { + if (!(peasycap->isequence % 10)) { for (i = 0; i < 179; i++) peasycap->merit[i] = peasycap->merit[i+1]; peasycap->merit[179] = merit_saa(peasycap->pusb_device); @@ -1658,7 +1688,7 @@ case VIDIOC_DQBUF: for (i = 0; i < 180; i++) j += peasycap->merit[i]; if (90 < j) { - SAY("easycap driver shutting down " \ + SAM("easycap driver shutting down " \ "on condition blue\n"); peasycap->video_eof = 1; peasycap->audio_eof = 1; } @@ -1697,7 +1727,7 @@ case VIDIOC_DQBUF: timeval2.tv_usec = sdr.remainder; timeval2.tv_sec = timeval1.tv_sec + sdr.quotient; } - if (!(isequence % 500)) { + if (!(peasycap->isequence % 500)) { fudge = ((long long int)(1000000)) * \ ((long long int)(timeval.tv_sec - \ timeval2.tv_sec)) + \ @@ -1707,38 +1737,38 @@ case VIDIOC_DQBUF: sll = sdr.quotient; ull = sdr.remainder; - SAY("%5lli.%-3lli=ms timestamp fudge\n", sll, ull); + SAM("%5lli.%-3lli=ms timestamp fudge\n", sll, ull); } #endif /*AUDIOTIME*/ v4l2_buffer.timestamp = timeval2; - v4l2_buffer.sequence = isequence++; + v4l2_buffer.sequence = peasycap->isequence++; v4l2_buffer.memory = V4L2_MEMORY_MMAP; v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE; v4l2_buffer.length = FRAME_BUFFER_SIZE; - JOT(16, " %10i=index\n", v4l2_buffer.index); - JOT(16, " 0x%08X=type\n", v4l2_buffer.type); - JOT(16, " %10i=bytesused\n", v4l2_buffer.bytesused); - JOT(16, " 0x%08X=flags\n", v4l2_buffer.flags); - JOT(16, " %10i=field\n", v4l2_buffer.field); - JOT(16, " %10li=timestamp.tv_usec\n", \ + JOM(16, " %10i=index\n", v4l2_buffer.index); + JOM(16, " 0x%08X=type\n", v4l2_buffer.type); + JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); + JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); + JOM(16, " %10i=field\n", v4l2_buffer.field); + JOM(16, " %10li=timestamp.tv_usec\n", \ (long)v4l2_buffer.timestamp.tv_usec); - JOT(16, " %10i=sequence\n", v4l2_buffer.sequence); - JOT(16, " 0x%08X=memory\n", v4l2_buffer.memory); - JOT(16, " %10i=m.offset\n", v4l2_buffer.m.offset); - JOT(16, " %10i=length\n", v4l2_buffer.length); + JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); + JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory); + JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset); + JOM(16, " %10i=length\n", v4l2_buffer.length); if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ sizeof(struct v4l2_buffer))) return -EFAULT; - JOT(8, "..... user is offered frame buffer %i\n", \ + JOM(8, "..... user is offered frame buffer %i\n", \ peasycap->frame_read); peasycap->frame_lock = 1; if (peasycap->frame_read == peasycap->frame_fill) { if (peasycap->frame_lock) { - JOT(8, "ERROR: filling frame buffer " \ + JOM(8, "ERROR: filling frame buffer " \ "while offered to user\n"); } } @@ -1752,15 +1782,15 @@ case VIDIOC_DQBUF: */ /*---------------------------------------------------------------------------*/ case VIDIOC_STREAMON: { - static int i; + int i; - JOT(8, "VIDIOC_STREAMON\n"); + JOM(8, "VIDIOC_STREAMON\n"); - isequence = 0; + peasycap->isequence = 0; for (i = 0; i < 180; i++) peasycap->merit[i] = 0; if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } submit_video_urbs(peasycap); @@ -1772,10 +1802,10 @@ case VIDIOC_STREAMON: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_STREAMOFF: { - JOT(8, "VIDIOC_STREAMOFF\n"); + JOM(8, "VIDIOC_STREAMOFF\n"); if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } @@ -1787,7 +1817,7 @@ case VIDIOC_STREAMOFF: { * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE. */ /*---------------------------------------------------------------------------*/ - JOT(8, "calling wake_up on wq_video and wq_audio\n"); + JOM(8, "calling wake_up on wq_video and wq_audio\n"); wake_up_interruptible(&(peasycap->wq_video)); wake_up_interruptible(&(peasycap->wq_audio)); /*---------------------------------------------------------------------------*/ @@ -1795,9 +1825,9 @@ case VIDIOC_STREAMOFF: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_PARM: { - static struct v4l2_streamparm v4l2_streamparm; + struct v4l2_streamparm v4l2_streamparm; - JOT(8, "VIDIOC_G_PARM\n"); + JOM(8, "VIDIOC_G_PARM\n"); if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \ sizeof(struct v4l2_streamparm))) @@ -1818,44 +1848,44 @@ case VIDIOC_G_PARM: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_PARM: { - JOT(8, "VIDIOC_S_PARM unsupported\n"); + JOM(8, "VIDIOC_S_PARM unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_AUDIO: { - JOT(8, "VIDIOC_G_AUDIO unsupported\n"); + JOM(8, "VIDIOC_G_AUDIO unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_AUDIO: { - JOT(8, "VIDIOC_S_AUDIO unsupported\n"); + JOM(8, "VIDIOC_S_AUDIO unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_TUNER: { - JOT(8, "VIDIOC_S_TUNER unsupported\n"); + JOM(8, "VIDIOC_S_TUNER unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_FBUF: case VIDIOC_S_FBUF: case VIDIOC_OVERLAY: { - JOT(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n"); + JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_TUNER: { - JOT(8, "VIDIOC_G_TUNER unsupported\n"); + JOM(8, "VIDIOC_G_TUNER unsupported\n"); return -EINVAL; } case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: { - JOT(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n"); + JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n"); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ default: { - JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); + JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); return -ENOIOCTLCMD; } } @@ -1873,25 +1903,32 @@ long easycap_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } - -/*--------------------------------------------------------------------------*/ +/*****************************************************************************/ static int easysnd_ioctl_bkl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct easycap *peasycap; struct usb_device *p; +if (NULL == file) { + SAY("ERROR: file is NULL\n"); + return -ERESTARTSYS; +} peasycap = file->private_data; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL.\n"); - return -1; + return -EFAULT; } p = peasycap->pusb_device; +if (NULL == p) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -EFAULT; +} /*---------------------------------------------------------------------------*/ switch (cmd) { case SNDCTL_DSP_GETCAPS: { int caps; - JOT(8, "SNDCTL_DSP_GETCAPS\n"); + JOM(8, "SNDCTL_DSP_GETCAPS\n"); #if defined(UPSAMPLE) if (true == peasycap->microphone) @@ -1911,7 +1948,7 @@ case SNDCTL_DSP_GETCAPS: { } case SNDCTL_DSP_GETFMTS: { int incoming; - JOT(8, "SNDCTL_DSP_GETFMTS\n"); + JOM(8, "SNDCTL_DSP_GETFMTS\n"); #if defined(UPSAMPLE) if (true == peasycap->microphone) @@ -1931,10 +1968,10 @@ case SNDCTL_DSP_GETFMTS: { } case SNDCTL_DSP_SETFMT: { int incoming, outgoing; - JOT(8, "SNDCTL_DSP_SETFMT\n"); + JOM(8, "SNDCTL_DSP_SETFMT\n"); if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) return -EFAULT; - JOT(8, "........... %i=incoming\n", incoming); + JOM(8, "........... %i=incoming\n", incoming); #if defined(UPSAMPLE) if (true == peasycap->microphone) @@ -1949,9 +1986,9 @@ case SNDCTL_DSP_SETFMT: { #endif /*UPSAMPLE*/ if (incoming != outgoing) { - JOT(8, "........... %i=outgoing\n", outgoing); - JOT(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE); - JOT(8, " cf. %i=AFMT_U8\n", AFMT_U8); + JOM(8, "........... %i=outgoing\n", outgoing); + JOM(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE); + JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8); if (0 != copy_to_user((void __user *)arg, &outgoing, \ sizeof(int))) return -EFAULT; @@ -1961,10 +1998,10 @@ case SNDCTL_DSP_SETFMT: { } case SNDCTL_DSP_STEREO: { int incoming; - JOT(8, "SNDCTL_DSP_STEREO\n"); + JOM(8, "SNDCTL_DSP_STEREO\n"); if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) return -EFAULT; - JOT(8, "........... %i=incoming\n", incoming); + JOM(8, "........... %i=incoming\n", incoming); #if defined(UPSAMPLE) if (true == peasycap->microphone) @@ -1984,10 +2021,10 @@ case SNDCTL_DSP_STEREO: { } case SNDCTL_DSP_SPEED: { int incoming; - JOT(8, "SNDCTL_DSP_SPEED\n"); + JOM(8, "SNDCTL_DSP_SPEED\n"); if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) return -EFAULT; - JOT(8, "........... %i=incoming\n", incoming); + JOM(8, "........... %i=incoming\n", incoming); #if defined(UPSAMPLE) if (true == peasycap->microphone) @@ -2007,10 +2044,10 @@ case SNDCTL_DSP_SPEED: { } case SNDCTL_DSP_GETTRIGGER: { int incoming; - JOT(8, "SNDCTL_DSP_GETTRIGGER\n"); + JOM(8, "SNDCTL_DSP_GETTRIGGER\n"); if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) return -EFAULT; - JOT(8, "........... %i=incoming\n", incoming); + JOM(8, "........... %i=incoming\n", incoming); incoming = PCM_ENABLE_INPUT; if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) @@ -2019,11 +2056,11 @@ case SNDCTL_DSP_GETTRIGGER: { } case SNDCTL_DSP_SETTRIGGER: { int incoming; - JOT(8, "SNDCTL_DSP_SETTRIGGER\n"); + JOM(8, "SNDCTL_DSP_SETTRIGGER\n"); if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) return -EFAULT; - JOT(8, "........... %i=incoming\n", incoming); - JOT(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \ + JOM(8, "........... %i=incoming\n", incoming); + JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \ "0x%x=PCM_ENABLE_OUTPUT\n", \ PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT); ; @@ -2034,10 +2071,10 @@ case SNDCTL_DSP_SETTRIGGER: { } case SNDCTL_DSP_GETBLKSIZE: { int incoming; - JOT(8, "SNDCTL_DSP_GETBLKSIZE\n"); + JOM(8, "SNDCTL_DSP_GETBLKSIZE\n"); if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) return -EFAULT; - JOT(8, "........... %i=incoming\n", incoming); + JOM(8, "........... %i=incoming\n", incoming); incoming = peasycap->audio_bytes_per_fragment; if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) return -EFAULT; @@ -2046,7 +2083,7 @@ case SNDCTL_DSP_GETBLKSIZE: { case SNDCTL_DSP_GETISPACE: { struct audio_buf_info audio_buf_info; - JOT(8, "SNDCTL_DSP_GETISPACE\n"); + JOM(8, "SNDCTL_DSP_GETISPACE\n"); audio_buf_info.bytes = peasycap->audio_bytes_per_fragment; audio_buf_info.fragments = 1; @@ -2059,7 +2096,7 @@ case SNDCTL_DSP_GETISPACE: { break; } default: { - JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd); + JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd); return -ENOIOCTLCMD; } } diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index 709c3d98e936..a3be9c1e5a69 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -783,6 +783,12 @@ return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ (int)50000); } /*****************************************************************************/ +int +audio_setup(struct easycap *peasycap) +{ +struct usb_device *pusb_device; +unsigned char buffer[1]; +int rc, id1, id2; /*---------------------------------------------------------------------------*/ /* * IMPORTANT: @@ -791,20 +797,12 @@ return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT. */ /*---------------------------------------------------------------------------*/ -int -audio_setup(struct easycap *peasycap) -{ -struct usb_device *pusb_device; -static __u8 request = 0x01; -static __u8 requesttype = \ +const __u8 request = 0x01; +const __u8 requesttype = \ (__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); - -static __u16 value_unmute = 0x0200; -static __u16 index = 0x0301; - -static unsigned char buffer[1]; -static __u16 length = 1; -int rc, id1, id2; +const __u16 value_unmute = 0x0200; +const __u16 index = 0x0301; +const __u16 length = 1; if (NULL == peasycap) return -EFAULT; diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index 5dba664475dd..ff6addfa15de 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -34,6 +34,18 @@ int debug; module_param(debug, int, S_IRUGO | S_IWUSR); +/*---------------------------------------------------------------------------*/ +/* + * dongle_this IS INDISPENSIBLY static BECAUSE FUNCTION easycap_usb_probe() + * IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap + * ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN + * PROBING INTERFACES 1 AND 2. +*/ +/*---------------------------------------------------------------------------*/ + +struct easycap *peasycap_dongle[DONGLE_MANY]; +static int dongle_this; + /*---------------------------------------------------------------------------*/ /* * PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO @@ -91,8 +103,6 @@ const struct v4l2_file_operations v4l2_fops = { .mmap = easycap_mmap, }; #endif /*EASYCAP_NEEDS_V4L2_FOPS*/ -int video_device_many /*=0*/; -struct video_device *pvideo_array[VIDEO_DEVICE_MANY], *pvideo_device; #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ @@ -115,17 +125,26 @@ struct usb_class_driver easysnd_class = { .minor_base = USB_SKEL_MINOR_BASE, }; /****************************************************************************/ -/*--------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ /* - * IT IS NOT APPROPRIATE FOR easycap_open() TO SUBMIT THE VIDEO URBS HERE, - * BECAUSE THERE WILL ALWAYS BE SUBSEQUENT NEGOTIATION OF TV STANDARD AND - * FORMAT BY IOCTL AND IT IS INADVISABLE TO HAVE THE URBS RUNNING WHILE - * REGISTERS OF THE SA7113H ARE BEING MANIPULATED. - * - * THE SUBMISSION OF VIDEO URBS IS THEREFORE DELAYED UNTIL THE IOCTL COMMAND - * STREAMON IS RECEIVED. - */ -/*--------------------------------------------------------------------------*/ + * THIS ROUTINE DOES NOT DETECT MULTIPLE OCCURRENCES OF POINTER peasycap +*/ +/*---------------------------------------------------------------------------*/ +int +isdongle(struct easycap *peasycap) +{ +int k; +if ((struct easycap *)NULL == peasycap) + return -2; +for (k = 0; k < DONGLE_MANY; k++) { + if (peasycap_dongle[k] == peasycap) { + peasycap->isdongle = k; + return k; + } +} +return -1; +} +/*****************************************************************************/ /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #if defined(EASYCAP_IS_VIDEODEV_CLIENT) int @@ -140,6 +159,8 @@ easycap_open(struct inode *inode, struct file *file) { #if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) struct usb_interface *pusb_interface; +#else +struct video_device *pvideo_device; #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ struct usb_device *p; struct easycap *peasycap; @@ -149,6 +170,7 @@ JOT(4, "\n"); SAY("==========OPEN=========\n"); peasycap = (struct easycap *)NULL; +/*---------------------------------------------------------------------------*/ #if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) if ((struct inode *)NULL == inode) { SAY("ERROR: inode is NULL.\n"); @@ -162,17 +184,16 @@ if (!pusb_interface) { peasycap = usb_get_intfdata(pusb_interface); /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #else -for (i = 0; i < video_device_many; i++) { - pvideo_device = pvideo_array[i]; - if ((struct video_device *)NULL != pvideo_device) { - peasycap = (struct easycap *)video_get_drvdata(pvideo_device); - break; - } +pvideo_device = video_devdata(file); +if ((struct video_device *)NULL == pvideo_device) { + SAY("ERROR: pvideo_device is NULL.\n"); + return -EFAULT; } -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +peasycap = (struct easycap *)video_get_drvdata(pvideo_device); #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ if ((struct easycap *)NULL == peasycap) { - SAY("MISTAKE: peasycap is NULL\n"); + SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } file->private_data = peasycap; @@ -181,7 +202,7 @@ file->private_data = peasycap; * INITIALIZATION */ /*---------------------------------------------------------------------------*/ -JOT(4, "starting initialization\n"); +JOM(4, "starting initialization\n"); for (k = 0; k < FRAME_BUFFER_MANY; k++) { for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) @@ -189,40 +210,40 @@ for (k = 0; k < FRAME_BUFFER_MANY; k++) { } p = peasycap->pusb_device; if ((struct usb_device *)NULL == p) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } else { - JOT(16, "0x%08lX=peasycap->pusb_device\n", \ + JOM(16, "0x%08lX=peasycap->pusb_device\n", \ (long int)peasycap->pusb_device); } rc = wakeup_device(peasycap->pusb_device); if (0 == rc) - JOT(8, "wakeup_device() OK\n"); + JOM(8, "wakeup_device() OK\n"); else { - SAY("ERROR: wakeup_device() returned %i\n", rc); + SAM("ERROR: wakeup_device() returned %i\n", rc); return -EFAULT; } rc = setup_stk(p); peasycap->input = 0; if (0 == rc) - JOT(8, "setup_stk() OK\n"); + JOM(8, "setup_stk() OK\n"); else { - SAY("ERROR: setup_stk() returned %i\n", rc); + SAM("ERROR: setup_stk() returned %i\n", rc); return -EFAULT; } rc = setup_saa(p); if (0 == rc) - JOT(8, "setup_saa() OK\n"); + JOM(8, "setup_saa() OK\n"); else { - SAY("ERROR: setup_saa() returned %i\n", rc); + SAM("ERROR: setup_saa() returned %i\n", rc); return -EFAULT; } rc = check_saa(p); if (0 == rc) - JOT(8, "check_saa() OK\n"); + JOM(8, "check_saa() OK\n"); else if (-8 < rc) - SAY("check_saa() returned %i\n", rc); + SAM("check_saa() returned %i\n", rc); else { - SAY("ERROR: check_saa() returned %i\n", rc); + SAM("ERROR: check_saa() returned %i\n", rc); return -EFAULT; } peasycap->standard_offset = -1; @@ -231,17 +252,17 @@ peasycap->standard_offset = -1; rc = adjust_standard(peasycap, V4L2_STD_NTSC_M); if (0 == rc) - JOT(8, "adjust_standard(.,NTSC_M) OK\n"); + JOM(8, "adjust_standard(.,NTSC_M) OK\n"); else { - SAY("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc); + SAM("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc); return -EFAULT; } rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \ false); if (0 <= rc) - JOT(8, "adjust_format(.,640,480,UYVY) OK\n"); + JOM(8, "adjust_format(.,640,480,UYVY) OK\n"); else { - SAY("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc); + SAM("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc); return -EFAULT; } @@ -251,17 +272,17 @@ rc = adjust_standard(peasycap, \ (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \ V4L2_STD_PAL_I | V4L2_STD_PAL_N)); if (0 == rc) - JOT(8, "adjust_standard(.,PAL_BGHIN) OK\n"); + JOM(8, "adjust_standard(.,PAL_BGHIN) OK\n"); else { - SAY("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc); + SAM("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc); return -EFAULT; } rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \ false); if (0 <= rc) - JOT(8, "adjust_format(.,640,480,uyvy,false) OK\n"); + JOM(8, "adjust_format(.,640,480,uyvy,false) OK\n"); else { - SAY("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc); + SAM("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc); return -EFAULT; } @@ -269,39 +290,39 @@ else { /*---------------------------------------------------------------------------*/ rc = adjust_brightness(peasycap, -8192); if (0 != rc) { - SAY("ERROR: adjust_brightness(default) returned %i\n", rc); + SAM("ERROR: adjust_brightness(default) returned %i\n", rc); return -EFAULT; } rc = adjust_contrast(peasycap, -8192); if (0 != rc) { - SAY("ERROR: adjust_contrast(default) returned %i\n", rc); + SAM("ERROR: adjust_contrast(default) returned %i\n", rc); return -EFAULT; } rc = adjust_saturation(peasycap, -8192); if (0 != rc) { - SAY("ERROR: adjust_saturation(default) returned %i\n", rc); + SAM("ERROR: adjust_saturation(default) returned %i\n", rc); return -EFAULT; } rc = adjust_hue(peasycap, -8192); if (0 != rc) { - SAY("ERROR: adjust_hue(default) returned %i\n", rc); + SAM("ERROR: adjust_hue(default) returned %i\n", rc); return -EFAULT; } /*---------------------------------------------------------------------------*/ rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \ peasycap->video_altsetting_on); if (0 == rc) - JOT(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \ + JOM(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \ peasycap->video_altsetting_on); else { - SAY("ERROR: usb_set_interface() returned %i\n", rc); + SAM("ERROR: usb_set_interface() returned %i\n", rc); return -EFAULT; } rc = start_100(p); if (0 == rc) - JOT(8, "start_100() OK\n"); + JOM(8, "start_100() OK\n"); else { - SAY("ERROR: start_100() returned %i\n", rc); + SAM("ERROR: start_100() returned %i\n", rc); return -EFAULT; } peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1; @@ -314,7 +335,7 @@ peasycap->audio_eof = 0; do_gettimeofday(&peasycap->timeval7); -JOT(4, "finished initialization\n"); +JOM(4, "finished initialization\n"); return 0; } /*****************************************************************************/ @@ -324,33 +345,25 @@ submit_video_urbs(struct easycap *peasycap) struct data_urb *pdata_urb; struct urb *purb; struct list_head *plist_head; -int j, isbad, m, rc; +int j, isbad, nospc, m, rc; int isbuf; +if ((struct easycap *)NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} + if ((struct list_head *)NULL == peasycap->purb_video_head) { SAY("ERROR: peasycap->urb_video_head uninitialized\n"); return -EFAULT; } if ((struct usb_device *)NULL == peasycap->pusb_device) { SAY("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; + return -ENODEV; } if (!peasycap->video_isoc_streaming) { - - - - - - - - - JOT(4, "submission of all video urbs\n"); - if (0 != ready_saa(peasycap->pusb_device)) { - SAY("ERROR: not ready to capture after waiting " \ - "one second\n"); - SAY("..... continuing anyway\n"); - } - isbad = 0; m = 0; + JOM(4, "submission of all video urbs\n"); + isbad = 0; nospc = 0; m = 0; list_for_each(plist_head, (peasycap->purb_video_head)) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); if (NULL != pdata_urb) { @@ -387,44 +400,57 @@ if (!peasycap->video_isoc_streaming) { rc = usb_submit_urb(purb, GFP_KERNEL); if (0 != rc) { isbad++; - SAY("ERROR: usb_submit_urb() failed " \ + SAM("ERROR: usb_submit_urb() failed " \ "for urb with rc:\n"); switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); + SAM("ERROR: -ENOMEM=" \ + "usb_submit_urb()\n"); break; } case -ENODEV: { - SAY("ENODEV\n"); + SAM("ERROR: -ENODEV=" \ + "usb_submit_urb()\n"); break; } case -ENXIO: { - SAY("ENXIO\n"); + SAM("ERROR: -ENXIO=" \ + "usb_submit_urb()\n"); break; } case -EINVAL: { - SAY("EINVAL\n"); + SAM("ERROR: -EINVAL=" \ + "usb_submit_urb()\n"); break; } case -EAGAIN: { - SAY("EAGAIN\n"); + SAM("ERROR: -EAGAIN=" \ + "usb_submit_urb()\n"); break; } case -EFBIG: { - SAY("EFBIG\n"); + SAM("ERROR: -EFBIG=" \ + "usb_submit_urb()\n"); break; } case -EPIPE: { - SAY("EPIPE\n"); + SAM("ERROR: -EPIPE=" \ + "usb_submit_urb()\n"); break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); + SAM("ERROR: -EMSGSIZE=" \ + "usb_submit_urb()\n"); + break; + } + case -ENOSPC: { + nospc++; break; } default: { - SAY("unknown error code %i\n",\ - rc); + SAM("ERROR: %i=" \ + "usb_submit_urb()\n",\ + rc); break; } } @@ -432,14 +458,20 @@ if (!peasycap->video_isoc_streaming) { m++; } } else { - isbad++; + isbad++; } } else { isbad++; } } + if (nospc) { + SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); + SAM("..... possibly inadequate USB bandwidth\n"); + peasycap->video_eof = 1; + } + if (isbad) { - JOT(4, "attempting cleanup instead of submitting\n"); + JOM(4, "attempting cleanup instead of submitting\n"); list_for_each(plist_head, (peasycap->purb_video_head)) { pdata_urb = list_entry(plist_head, struct data_urb, \ list_head); @@ -452,16 +484,10 @@ if (!peasycap->video_isoc_streaming) { peasycap->video_isoc_streaming = 0; } else { peasycap->video_isoc_streaming = 1; - JOT(4, "submitted %i video urbs\n", m); + JOM(4, "submitted %i video urbs\n", m); } - - - - - - } else { - JOT(4, "already streaming video urbs\n"); + JOM(4, "already streaming video urbs\n"); } return 0; } @@ -478,12 +504,9 @@ if ((struct easycap *)NULL == peasycap) { return -EFAULT; } if (peasycap->video_isoc_streaming) { - - - if ((struct list_head *)NULL != peasycap->purb_video_head) { peasycap->video_isoc_streaming = 0; - JOT(4, "killing video urbs\n"); + JOM(4, "killing video urbs\n"); m = 0; list_for_each(plist_head, (peasycap->purb_video_head)) { pdata_urb = list_entry(plist_head, struct data_urb, \ @@ -495,13 +518,13 @@ if (peasycap->video_isoc_streaming) { } } } - JOT(4, "%i video urbs killed\n", m); + JOM(4, "%i video urbs killed\n", m); } else { - SAY("ERROR: peasycap->purb_video_head is NULL\n"); + SAM("ERROR: peasycap->purb_video_head is NULL\n"); return -EFAULT; } } else { - JOT(8, "%i=video_isoc_streaming, no video urbs killed\n", \ + JOM(8, "%i=video_isoc_streaming, no video urbs killed\n", \ peasycap->video_isoc_streaming); } return 0; @@ -532,10 +555,10 @@ if (NULL == peasycap) { return -EFAULT; } if (0 != kill_video_urbs(peasycap)) { - SAY("ERROR: kill_video_urbs() failed\n"); + SAM("ERROR: kill_video_urbs() failed\n"); return -EFAULT; } -JOT(4, "ending successfully\n"); +JOM(4, "ending successfully\n"); /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #else # @@ -548,52 +571,28 @@ return 0; /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #if defined(EASYCAP_IS_VIDEODEV_CLIENT) int -videodev_release(struct video_device *pvd) +videodev_release(struct video_device *pvideo_device) { struct easycap *peasycap; -int i, j, k; JOT(4, "\n"); -k = 0; -for (i = 0; i < video_device_many; i++) { - pvideo_device = pvideo_array[i]; - if ((struct video_device *)NULL != pvideo_device) { - if (pvd->minor == pvideo_device->minor) { - peasycap = (struct easycap *)\ - video_get_drvdata(pvideo_device); - if ((struct easycap *)NULL == peasycap) { - SAY("ERROR: peasycap is NULL\n"); - SAY("ending unsuccessfully\n"); - return -EFAULT; - } - if (0 != kill_video_urbs(peasycap)) { - SAY("ERROR: kill_video_urbs() failed\n"); - return -EFAULT; - } - JOT(4, "freeing video_device structure: " \ - "/dev/video%i\n", i); - kfree((void *)pvideo_device); - for (j = i; j < (VIDEO_DEVICE_MANY - 1); j++) - pvideo_array[j] = pvideo_array[j + 1]; - video_device_many--; k++; - break; - } - } -} -if (!k) { - SAY("ERROR: lost video_device structure for %i=minor\n", pvd->minor); - SAY("cannot free: may cause memory leak\n"); +peasycap = video_get_drvdata(pvideo_device); +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); SAY("ending unsuccessfully\n"); return -EFAULT; } - -JOT(4, "ending successfully\n"); +if (0 != kill_video_urbs(peasycap)) { + SAM("ERROR: kill_video_urbs() failed\n"); + return -EFAULT; +} +JOM(4, "ending successfully\n"); return 0; } #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ -/****************************************************************************/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +/*****************************************************************************/ /*--------------------------------------------------------------------------*/ /* * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect(). @@ -616,7 +615,7 @@ JOT(4, "\n"); peasycap = container_of(pkref, struct easycap, kref); if ((struct easycap *)NULL == peasycap) { - SAY("ERROR: peasycap is NULL: cannot perform deletions\n"); + SAM("ERROR: peasycap is NULL: cannot perform deletions\n"); return; } /*---------------------------------------------------------------------------*/ @@ -625,12 +624,12 @@ if ((struct easycap *)NULL == peasycap) { */ /*---------------------------------------------------------------------------*/ if ((struct list_head *)NULL != peasycap->purb_video_head) { - JOT(4, "freeing video urbs\n"); + JOM(4, "freeing video urbs\n"); m = 0; list_for_each(plist_head, (peasycap->purb_video_head)) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); if (NULL == pdata_urb) - JOT(4, "ERROR: pdata_urb is NULL\n"); + JOM(4, "ERROR: pdata_urb is NULL\n"); else { if ((struct urb *)NULL != pdata_urb->purb) { usb_free_urb(pdata_urb->purb); @@ -641,9 +640,9 @@ if ((struct list_head *)NULL != peasycap->purb_video_head) { } } - JOT(4, "%i video urbs freed\n", m); + JOM(4, "%i video urbs freed\n", m); /*---------------------------------------------------------------------------*/ - JOT(4, "freeing video data_urb structures.\n"); + JOM(4, "freeing video data_urb structures.\n"); m = 0; list_for_each_safe(plist_head, plist_next, peasycap->purb_video_head) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); @@ -654,14 +653,14 @@ if ((struct list_head *)NULL != peasycap->purb_video_head) { m++; } } - JOT(4, "%i video data_urb structures freed\n", m); - JOT(4, "setting peasycap->purb_video_head=NULL\n"); + JOM(4, "%i video data_urb structures freed\n", m); + JOM(4, "setting peasycap->purb_video_head=NULL\n"); peasycap->purb_video_head = (struct list_head *)NULL; } else { -JOT(4, "peasycap->purb_video_head is NULL\n"); +JOM(4, "peasycap->purb_video_head is NULL\n"); } /*---------------------------------------------------------------------------*/ -JOT(4, "freeing video isoc buffers.\n"); +JOM(4, "freeing video isoc buffers.\n"); m = 0; for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) { if ((void *)NULL != peasycap->video_isoc_buffer[k].pgo) { @@ -674,9 +673,9 @@ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) { m++; } } -JOT(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER)); +JOM(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER)); /*---------------------------------------------------------------------------*/ -JOT(4, "freeing video field buffers.\n"); +JOM(4, "freeing video field buffers.\n"); lost = 0; for (k = 0; k < FIELD_BUFFER_MANY; k++) { for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) { @@ -689,9 +688,9 @@ for (k = 0; k < FIELD_BUFFER_MANY; k++) { } } } -JOT(4, "video field buffers freed: %i pages\n", lost); +JOM(4, "video field buffers freed: %i pages\n", lost); /*---------------------------------------------------------------------------*/ -JOT(4, "freeing video frame buffers.\n"); +JOM(4, "freeing video frame buffers.\n"); lost = 0; for (k = 0; k < FRAME_BUFFER_MANY; k++) { for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) { @@ -704,19 +703,19 @@ for (k = 0; k < FRAME_BUFFER_MANY; k++) { } } } -JOT(4, "video frame buffers freed: %i pages\n", lost); +JOM(4, "video frame buffers freed: %i pages\n", lost); /*---------------------------------------------------------------------------*/ /* * FREE AUDIO. */ /*---------------------------------------------------------------------------*/ if ((struct list_head *)NULL != peasycap->purb_audio_head) { - JOT(4, "freeing audio urbs\n"); + JOM(4, "freeing audio urbs\n"); m = 0; list_for_each(plist_head, (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); if (NULL == pdata_urb) - JOT(4, "ERROR: pdata_urb is NULL\n"); + JOM(4, "ERROR: pdata_urb is NULL\n"); else { if ((struct urb *)NULL != pdata_urb->purb) { usb_free_urb(pdata_urb->purb); @@ -726,9 +725,9 @@ if ((struct list_head *)NULL != peasycap->purb_audio_head) { } } } - JOT(4, "%i audio urbs freed\n", m); + JOM(4, "%i audio urbs freed\n", m); /*---------------------------------------------------------------------------*/ - JOT(4, "freeing audio data_urb structures.\n"); + JOM(4, "freeing audio data_urb structures.\n"); m = 0; list_for_each_safe(plist_head, plist_next, peasycap->purb_audio_head) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); @@ -739,14 +738,14 @@ if ((struct list_head *)NULL != peasycap->purb_audio_head) { m++; } } -JOT(4, "%i audio data_urb structures freed\n", m); -JOT(4, "setting peasycap->purb_audio_head=NULL\n"); +JOM(4, "%i audio data_urb structures freed\n", m); +JOM(4, "setting peasycap->purb_audio_head=NULL\n"); peasycap->purb_audio_head = (struct list_head *)NULL; } else { -JOT(4, "peasycap->purb_audio_head is NULL\n"); +JOM(4, "peasycap->purb_audio_head is NULL\n"); } /*---------------------------------------------------------------------------*/ -JOT(4, "freeing audio isoc buffers.\n"); +JOM(4, "freeing audio isoc buffers.\n"); m = 0; for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { if ((void *)NULL != peasycap->audio_isoc_buffer[k].pgo) { @@ -759,10 +758,10 @@ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { m++; } } -JOT(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \ +JOM(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \ m * (0x01 << AUDIO_ISOC_ORDER)); /*---------------------------------------------------------------------------*/ -JOT(4, "freeing audio buffers.\n"); +JOM(4, "freeing audio buffers.\n"); lost = 0; for (k = 0; k < peasycap->audio_buffer_page_many; k++) { if ((void *)NULL != peasycap->audio_buffer[k].pgo) { @@ -772,9 +771,9 @@ for (k = 0; k < peasycap->audio_buffer_page_many; k++) { lost++; } } -JOT(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost); +JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost); /*---------------------------------------------------------------------------*/ -JOT(4, "freeing easycap structure.\n"); +JOM(4, "freeing easycap structure.\n"); allocation_video_urb = peasycap->allocation_video_urb; allocation_video_page = peasycap->allocation_video_page; allocation_video_struct = peasycap->allocation_video_struct; @@ -861,7 +860,7 @@ while ((peasycap->field_read == peasycap->field_fill) || \ if (mode) return -EAGAIN; - JOT(8, "first wait on wq_video, " \ + JOM(8, "first wait on wq_video, " \ "%i=field_read %i=field_fill\n", \ peasycap->field_read, peasycap->field_fill); @@ -873,25 +872,25 @@ while ((peasycap->field_read == peasycap->field_fill) || \ [peasycap->field_read][0].kount)) && \ (0 == (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))))))){ - SAY("aborted by signal\n"); + SAM("aborted by signal\n"); return -EIO; } if (peasycap->video_idle) { - JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle); + JOM(8, "%i=peasycap->video_idle\n", peasycap->video_idle); return -EIO; } if (peasycap->video_eof) { - JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof); + JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof); kill_video_urbs(peasycap); return -EIO; } miss++; } -JOT(8, "first awakening on wq_video after %i waits\n", miss); +JOM(8, "first awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); if (0 != rc) - SAY("ERROR: field2frame() returned %i\n", rc); + SAM("ERROR: field2frame() returned %i\n", rc); if (true == peasycap->offerfields) { peasycap->frame_read = peasycap->frame_fill; @@ -906,8 +905,8 @@ if (true == peasycap->offerfields) { peasycap->frame_buffer[peasycap->frame_read][0].kount = \ V4L2_FIELD_TOP; } -JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); -JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); +JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); +JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); } /*---------------------------------------------------------------------------*/ /* @@ -923,7 +922,7 @@ while ((peasycap->field_read == peasycap->field_fill) || \ if (mode) return -EAGAIN; - JOT(8, "second wait on wq_video, " \ + JOM(8, "second wait on wq_video, " \ "%i=field_read %i=field_fill\n", \ peasycap->field_read, peasycap->field_fill); msleep(1); @@ -934,25 +933,25 @@ while ((peasycap->field_read == peasycap->field_fill) || \ [peasycap->field_read][0].kount)) && \ (0 != (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))))))){ - SAY("aborted by signal\n"); + SAM("aborted by signal\n"); return -EIO; } if (peasycap->video_idle) { - JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle); + JOM(8, "%i=peasycap->video_idle\n", peasycap->video_idle); return -EIO; } if (peasycap->video_eof) { - JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof); + JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof); kill_video_urbs(peasycap); return -EIO; } miss++; } -JOT(8, "second awakening on wq_video after %i waits\n", miss); +JOM(8, "second awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); if (0 != rc) - SAY("ERROR: field2frame() returned %i\n", rc); + SAM("ERROR: field2frame() returned %i\n", rc); peasycap->frame_read = peasycap->frame_fill; peasycap->queued[peasycap->frame_read] = 0; @@ -970,8 +969,8 @@ if (0x01 & easycap_standard[peasycap->standard_offset].mask) { V4L2_FIELD_BOTTOM; } -JOT(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); -JOT(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); +JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); +JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); return 0; } @@ -992,7 +991,6 @@ return 0; int field2frame(struct easycap *peasycap) { -static struct timeval timeval0; struct timeval timeval; long long int above, below; __u32 remainder; @@ -1005,12 +1003,17 @@ int rc, bytesperpixel, multiplier, much, more, over, rump, caches; __u8 mask, margin; bool odd, isuy, decimatepixel, offerfields; -JOT(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \ +if ((struct easycap *)NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} + +JOM(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \ peasycap->field_buffer[peasycap->field_read][0].kount,\ peasycap->field_read, peasycap->frame_fill); -JOT(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); +JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); if (true == peasycap->offerfields) - JOT(8, "===== offerfields\n"); + JOM(8, "===== offerfields\n"); /*---------------------------------------------------------------------------*/ /* @@ -1018,7 +1021,7 @@ if (true == peasycap->offerfields) */ /*---------------------------------------------------------------------------*/ if (peasycap->field_read == peasycap->field_fill) { - SAY("ERROR: on entry, still filling field buffer %i\n", \ + SAM("ERROR: on entry, still filling field buffer %i\n", \ peasycap->field_read); return 0; } @@ -1037,7 +1040,7 @@ decimatepixel = peasycap->decimatepixel; if ((2 != bytesperpixel) && \ (3 != bytesperpixel) && \ (4 != bytesperpixel)) { - SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel); + SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel); return -EFAULT; } if (true == decimatepixel) @@ -1065,7 +1068,7 @@ else odd = false; if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) { - JOT(8, " initial skipping %4i bytes p.%4i\n", \ + JOM(8, " initial skipping %4i bytes p.%4i\n", \ w3/multiplier, mad); pad += (w3 / multiplier); rad -= (w3 / multiplier); } @@ -1090,7 +1093,7 @@ while (cz < wz) { rump = 0; if (much % 2) { - SAY("MISTAKE: much is odd\n"); + SAM("MISTAKE: much is odd\n"); return -EFAULT; } @@ -1127,7 +1130,7 @@ while (cz < wz) { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ } else { - SAY("MISTAKE: %i=bytesperpixel\n", \ + SAM("MISTAKE: %i=bytesperpixel\n", \ bytesperpixel); return -EFAULT; } @@ -1138,7 +1141,7 @@ while (cz < wz) { rc = redaub(peasycap, pad, pex, much, more, \ mask, margin, isuy); if (0 > rc) { - SAY("ERROR: redaub() failed\n"); + SAM("ERROR: redaub() failed\n"); return -EFAULT; } if (much % 4) { @@ -1206,7 +1209,7 @@ while (cz < wz) { rump = 0; if (much % 2) { - SAY("MISTAKE: much is odd\n"); + SAM("MISTAKE: much is odd\n"); return -EFAULT; } @@ -1243,7 +1246,7 @@ while (cz < wz) { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ } else { - SAY("MISTAKE: %i=bytesperpixel\n", \ + SAM("MISTAKE: %i=bytesperpixel\n", \ bytesperpixel); return -EFAULT; } @@ -1254,7 +1257,7 @@ while (cz < wz) { rc = redaub(peasycap, pad, pex, much, more, \ mask, margin, isuy); if (0 > rc) { - SAY("ERROR: redaub() failed\n"); + SAM("ERROR: redaub() failed\n"); return -EFAULT; } over -= much; cz += much; @@ -1307,39 +1310,39 @@ while (cz < wz) { /*---------------------------------------------------------------------------*/ c2 = (mex + 1)*PAGE_SIZE - rex; if (cz != c2) - SAY("ERROR: discrepancy %i in bytes read\n", c2 - cz); + SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz); c3 = (mad + 1)*PAGE_SIZE - rad; if (false == decimatepixel) { if (bytesperpixel * \ cz != c3) \ - SAY("ERROR: discrepancy %i in bytes written\n", \ + SAM("ERROR: discrepancy %i in bytes written\n", \ c3 - (bytesperpixel * \ cz)); } else { if (false == odd) { if (bytesperpixel * \ cz != (4 * c3)) - SAY("ERROR: discrepancy %i in bytes written\n", \ + SAM("ERROR: discrepancy %i in bytes written\n", \ (2*c3)-(bytesperpixel * \ cz)); } else { if (0 != c3) - SAY("ERROR: discrepancy %i " \ + SAM("ERROR: discrepancy %i " \ "in bytes written\n", c3); } } if (rump) - SAY("ERROR: undischarged cache at end of line in frame buffer\n"); + SAM("WORRY: undischarged cache at end of line in frame buffer\n"); -JOT(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3); -JOT(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad); +JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3); +JOM(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad); if (true == odd) - JOT(8, "+++++ field2frame(): frame buffer %i is full\n", kad); + JOM(8, "+++++ field2frame(): frame buffer %i is full\n", kad); if (peasycap->field_read == peasycap->field_fill) - SAY("WARNING: on exit, filling field buffer %i\n", \ + SAM("WARNING: on exit, filling field buffer %i\n", \ peasycap->field_read); /*---------------------------------------------------------------------------*/ /* @@ -1347,23 +1350,24 @@ if (peasycap->field_read == peasycap->field_fill) */ /*---------------------------------------------------------------------------*/ do_gettimeofday(&timeval); -if (timeval0.tv_sec) { +if (peasycap->timeval6.tv_sec) { below = ((long long int)(1000000)) * \ - ((long long int)(timeval.tv_sec - timeval0.tv_sec)) + \ - (long long int)(timeval.tv_usec - timeval0.tv_usec); + ((long long int)(timeval.tv_sec - \ + peasycap->timeval6.tv_sec)) + \ + (long long int)(timeval.tv_usec - peasycap->timeval6.tv_usec); above = (long long int)1000000; sdr = signed_div(above, below); above = sdr.quotient; remainder = (__u32)sdr.remainder; - JOT(8, "video streaming at %3lli.%03i fields per second\n", above, \ + JOM(8, "video streaming at %3lli.%03i fields per second\n", above, \ (remainder/1000)); } -timeval0 = timeval; +peasycap->timeval6 = timeval; if (caches) - JOT(8, "%i=caches\n", caches); + JOM(8, "%i=caches\n", caches); return 0; } /*****************************************************************************/ @@ -1416,7 +1420,7 @@ redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, \ __u8 mask, __u8 margin, bool isuy) { static __s32 ay[256], bu[256], rv[256], gu[256], gv[256]; -static __u8 cache[8], *pcache; +__u8 *pcache; __u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr; int bytesperpixel; bool byteswaporder, decimatepixel, last; @@ -1424,7 +1428,7 @@ int j, rump; __s32 s32; if (much % 2) { - SAY("MISTAKE: much is odd\n"); + SAM("MISTAKE: much is odd\n"); return -EFAULT; } bytesperpixel = peasycap->bytesperpixel; @@ -1457,30 +1461,31 @@ if (!bu[255]) { ay[j] = ay[16]; for (j = 236; j < 256; j++) ay[j] = ay[235]; - JOT(8, "lookup tables are prepared\n"); + JOM(8, "lookup tables are prepared\n"); } -if ((__u8 *)NULL == pcache) - pcache = &cache[0]; +pcache = peasycap->pcache; +if (NULL == pcache) + pcache = &peasycap->cache[0]; /*---------------------------------------------------------------------------*/ /* * TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER */ /*---------------------------------------------------------------------------*/ if (!pcache) { - SAY("MISTAKE: pcache is NULL\n"); + SAM("MISTAKE: pcache is NULL\n"); return -EFAULT; } -if (pcache != &cache[0]) - JOT(16, "cache has %i bytes\n", (int)(pcache - &cache[0])); -p2 = &cache[0]; -p3 = (__u8 *)pad - (int)(pcache - &cache[0]); +if (pcache != &peasycap->cache[0]) + JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0])); +p2 = &peasycap->cache[0]; +p3 = (__u8 *)pad - (int)(pcache - &peasycap->cache[0]); while (p2 < pcache) { *p3++ = *p2; p2++; } -pcache = &cache[0]; +pcache = &peasycap->cache[0]; if (p3 != pad) { - SAY("MISTAKE: pointer misalignment\n"); + SAM("MISTAKE: pointer misalignment\n"); return -EFAULT; } /*---------------------------------------------------------------------------*/ @@ -1495,7 +1500,7 @@ else v = *(p2 - 1); if (rump) - JOT(16, "%4i=much %4i=more %i=rump\n", much, more, rump); + JOM(16, "%4i=much %4i=more %i=rump\n", much, more, rump); /*---------------------------------------------------------------------------*/ switch (bytesperpixel) { @@ -1601,7 +1606,7 @@ case 3: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = r; @@ -1616,7 +1621,7 @@ case 3: break; } default: { - SAY("MISTAKE: %i=rump\n", \ + SAM("MISTAKE: %i=rump\n", \ bytesperpixel - rump); return -EFAULT; } @@ -1674,7 +1679,7 @@ case 3: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = b; @@ -1689,7 +1694,7 @@ case 3: break; } default: { - SAY("MISTAKE: %i=rump\n", \ + SAM("MISTAKE: %i=rump\n", \ bytesperpixel - rump); return -EFAULT; } @@ -1750,7 +1755,7 @@ case 3: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = r; @@ -1765,7 +1770,7 @@ case 3: break; } default: { - SAY("MISTAKE: " \ + SAM("MISTAKE: " \ "%i=rump\n", \ bytesperpixel - rump); return -EFAULT; @@ -1826,7 +1831,7 @@ case 3: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = b; @@ -1841,7 +1846,7 @@ case 3: break; } default: { - SAY("MISTAKE: " \ + SAM("MISTAKE: " \ "%i=rump\n", \ bytesperpixel - rump); return -EFAULT; @@ -1906,7 +1911,7 @@ case 4: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = r; @@ -1930,7 +1935,7 @@ case 4: break; } default: { - SAY("MISTAKE: %i=rump\n", \ + SAM("MISTAKE: %i=rump\n", \ bytesperpixel - rump); return -EFAULT; } @@ -1988,7 +1993,7 @@ case 4: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = b; @@ -2012,7 +2017,7 @@ case 4: break; } default: { - SAY("MISTAKE: %i=rump\n", \ + SAM("MISTAKE: %i=rump\n", \ bytesperpixel - rump); return -EFAULT; } @@ -2075,7 +2080,7 @@ case 4: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = r; @@ -2099,7 +2104,7 @@ case 4: break; } default: { - SAY("MISTAKE: " \ + SAM("MISTAKE: " \ "%i=rump\n", \ bytesperpixel - \ rump); @@ -2160,7 +2165,7 @@ case 4: 0 : (__u8)s32); if ((true == last) && rump) { - pcache = &cache[0]; + pcache = &peasycap->cache[0]; switch (bytesperpixel - rump) { case 1: { *p3 = b; @@ -2184,7 +2189,7 @@ case 4: break; } default: { - SAY("MISTAKE: " \ + SAM("MISTAKE: " \ "%i=rump\n", \ bytesperpixel - rump); return -EFAULT; @@ -2208,7 +2213,7 @@ case 4: break; } default: { - SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel); + SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel); return -EFAULT; } } @@ -2305,19 +2310,19 @@ if (NULL == peasycap) { /*---------------------------------------------------------------------------*/ pbuf = peasycap->frame_buffer[k][m].pgo; if (NULL == pbuf) { - SAY("ERROR: pbuf is NULL\n"); + SAM("ERROR: pbuf is NULL\n"); goto finish; } page = virt_to_page(pbuf); if (NULL == page) { - SAY("ERROR: page is NULL\n"); + SAM("ERROR: page is NULL\n"); goto finish; } get_page(page); /*---------------------------------------------------------------------------*/ finish: if (NULL == page) { - SAY("ERROR: page is NULL after get_page(page)\n"); + SAM("ERROR: page is NULL after get_page(page)\n"); } else { pvmf->page = page; retcode = VM_FAULT_MINOR; @@ -2353,7 +2358,6 @@ return retcode; void easycap_complete(struct urb *purb) { -static int mt; struct easycap *peasycap; struct data_buffer *pfield_buffer; char errbuf[16]; @@ -2379,64 +2383,64 @@ if (peasycap->video_eof) for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo) break; -JOT(16, "%2i=urb\n", i); +JOM(16, "%2i=urb\n", i); last = peasycap->video_isoc_sequence; if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && \ (0 != i)) || \ (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && \ ((last + 1) != i))) { - SAY("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i); + SAM("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i); } peasycap->video_isoc_sequence = i; if (peasycap->video_idle) { - JOT(16, "%i=video_idle %i=video_isoc_streaming\n", \ + JOM(16, "%i=video_idle %i=video_isoc_streaming\n", \ peasycap->video_idle, peasycap->video_isoc_streaming); if (peasycap->video_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAY("ERROR: while %i=video_idle, " \ + SAM("ERROR: while %i=video_idle, " \ "usb_submit_urb() failed with rc:\n", \ peasycap->video_idle); switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); + SAM("ENOMEM\n"); break; } case -ENODEV: { - SAY("ENODEV\n"); + SAM("ENODEV\n"); break; } case -ENXIO: { - SAY("ENXIO\n"); + SAM("ENXIO\n"); break; } case -EINVAL: { - SAY("EINVAL\n"); + SAM("EINVAL\n"); break; } case -EAGAIN: { - SAY("EAGAIN\n"); + SAM("EAGAIN\n"); break; } case -EFBIG: { - SAY("EFBIG\n"); + SAM("EFBIG\n"); break; } case -EPIPE: { - SAY("EPIPE\n"); + SAM("EPIPE\n"); break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); + SAM("EMSGSIZE\n"); break; } case -ENOSPC: { - SAY("ENOSPC\n"); + SAM("ENOSPC\n"); break; } default: { - SAY("0x%08X\n", rc); + SAM("0x%08X\n", rc); break; } } @@ -2447,80 +2451,80 @@ return; override = 0; /*---------------------------------------------------------------------------*/ if (FIELD_BUFFER_MANY <= peasycap->field_fill) { - SAY("ERROR: bad peasycap->field_fill\n"); + SAM("ERROR: bad peasycap->field_fill\n"); return; } if (purb->status) { if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) { - JOT(8, "urb status -ESHUTDOWN or -ENOENT\n"); + JOM(8, "urb status -ESHUTDOWN or -ENOENT\n"); return; } (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ; - SAY("ERROR: bad urb status:\n"); + SAM("ERROR: bad urb status:\n"); switch (purb->status) { case -EINPROGRESS: { - SAY("-EINPROGRESS\n"); break; + SAM("-EINPROGRESS\n"); break; } case -ENOSR: { - SAY("-ENOSR\n"); break; + SAM("-ENOSR\n"); break; } case -EPIPE: { - SAY("-EPIPE\n"); break; + SAM("-EPIPE\n"); break; } case -EOVERFLOW: { - SAY("-EOVERFLOW\n"); break; + SAM("-EOVERFLOW\n"); break; } case -EPROTO: { - SAY("-EPROTO\n"); break; + SAM("-EPROTO\n"); break; } case -EILSEQ: { - SAY("-EILSEQ\n"); break; + SAM("-EILSEQ\n"); break; } case -ETIMEDOUT: { - SAY("-ETIMEDOUT\n"); break; + SAM("-ETIMEDOUT\n"); break; } case -EMSGSIZE: { - SAY("-EMSGSIZE\n"); break; + SAM("-EMSGSIZE\n"); break; } case -EOPNOTSUPP: { - SAY("-EOPNOTSUPP\n"); break; + SAM("-EOPNOTSUPP\n"); break; } case -EPFNOSUPPORT: { - SAY("-EPFNOSUPPORT\n"); break; + SAM("-EPFNOSUPPORT\n"); break; } case -EAFNOSUPPORT: { - SAY("-EAFNOSUPPORT\n"); break; + SAM("-EAFNOSUPPORT\n"); break; } case -EADDRINUSE: { - SAY("-EADDRINUSE\n"); break; + SAM("-EADDRINUSE\n"); break; } case -EADDRNOTAVAIL: { - SAY("-EADDRNOTAVAIL\n"); break; + SAM("-EADDRNOTAVAIL\n"); break; } case -ENOBUFS: { - SAY("-ENOBUFS\n"); break; + SAM("-ENOBUFS\n"); break; } case -EISCONN: { - SAY("-EISCONN\n"); break; + SAM("-EISCONN\n"); break; } case -ENOTCONN: { - SAY("-ENOTCONN\n"); break; + SAM("-ENOTCONN\n"); break; } case -ESHUTDOWN: { - SAY("-ESHUTDOWN\n"); break; + SAM("-ESHUTDOWN\n"); break; } case -ENOENT: { - SAY("-ENOENT\n"); break; + SAM("-ENOENT\n"); break; } case -ECONNRESET: { - SAY("-ECONNRESET\n"); break; + SAM("-ECONNRESET\n"); break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + SAM("ENOSPC\n"); break; } default: { - SAY("unknown error code 0x%08X\n", purb->status); break; + SAM("unknown error code 0x%08X\n", purb->status); break; } } /*---------------------------------------------------------------------------*/ @@ -2579,7 +2583,7 @@ if (purb->status) { strcpy(&errbuf[0], "-ECONNRESET"); break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + SAM("ENOSPC\n"); break; } case -ESHUTDOWN: { strcpy(&errbuf[0], "-ESHUTDOWN"); break; @@ -2594,7 +2598,7 @@ if (purb->status) { frameactual = purb->iso_frame_desc[i].actual_length; frameoffset = purb->iso_frame_desc[i].offset; - JOT(16, "frame[%2i]:" \ + JOM(16, "frame[%2i]:" \ "%4i=status " \ "%4i=actual " \ "%4i=length " \ @@ -2608,19 +2612,20 @@ if (purb->status) { PAGE_SIZE) + \ (int)(pfield_buffer->pto - pfield_buffer->pgo); if (4 == more) - mt++; + peasycap->video_mt++; if (4 < more) { - if (mt) { - JOT(8, "%4i empty video urb frames\n", mt); - mt = 0; + if (peasycap->video_mt) { + JOM(8, "%4i empty video urb frames\n", \ + peasycap->video_mt); + peasycap->video_mt = 0; } if (FIELD_BUFFER_MANY <= peasycap->field_fill) { - SAY("ERROR: bad peasycap->field_fill\n"); + SAM("ERROR: bad peasycap->field_fill\n"); return; } if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \ peasycap->field_page) { - SAY("ERROR: bad peasycap->field_page\n"); + SAM("ERROR: bad peasycap->field_page\n"); return; } pfield_buffer = &peasycap->field_buffer\ @@ -2653,11 +2658,11 @@ if (purb->status) { peasycap->videofieldamount) { if (2 == videofieldamount - \ peasycap->\ - videofieldamount) + videofieldamount) { (peasycap->field_buffer\ [peasycap->field_fill]\ [0].kount) |= 0x0100; - else + } else (peasycap->field_buffer\ [peasycap->field_fill]\ [0].kount) |= 0x4000; @@ -2689,15 +2694,15 @@ if (purb->status) { pfield_buffer->pto = \ pfield_buffer->pgo; - JOT(8, "bumped to: %i=peasycap->" \ + JOM(8, "bumped to: %i=peasycap->" \ "field_fill %i=parity\n", \ peasycap->field_fill, \ 0x00FF & pfield_buffer->kount); - JOT(8, "field buffer %i has %i " \ + JOM(8, "field buffer %i has %i " \ "bytes fit to be read\n", \ peasycap->field_read, \ videofieldamount); - JOT(8, "wakeup call to wq_video, " \ + JOM(8, "wakeup call to wq_video, " \ "%i=field_read %i=field_fill "\ "%i=parity\n", \ peasycap->field_read, \ @@ -2710,7 +2715,7 @@ if (purb->status) { do_gettimeofday(&peasycap->timeval7); } else { peasycap->video_junk++; - JOT(8, "field buffer %i had %i " \ + JOM(8, "field buffer %i had %i " \ "bytes, now discarded\n", \ peasycap->field_fill, \ videofieldamount); @@ -2728,20 +2733,20 @@ if (purb->status) { pfield_buffer->pto = \ pfield_buffer->pgo; - JOT(8, "bumped to: %i=peasycap->" \ + JOM(8, "bumped to: %i=peasycap->" \ "field_fill %i=parity\n", \ peasycap->field_fill, \ 0x00FF & pfield_buffer->kount); } if (8 == more) { - JOT(8, "end-of-field: received " \ + JOM(8, "end-of-field: received " \ "parity byte 0x%02X\n", \ (0xFF & *pu)); if (0x40 & *pu) pfield_buffer->kount = 0x0000; else pfield_buffer->kount = 0x0001; - JOT(8, "end-of-field: 0x%02X=kount\n",\ + JOM(8, "end-of-field: 0x%02X=kount\n",\ 0xFF & pfield_buffer->kount); } } @@ -2754,12 +2759,12 @@ if (purb->status) { more -= leap; if (FIELD_BUFFER_MANY <= peasycap->field_fill) { - SAY("ERROR: bad peasycap->field_fill\n"); + SAM("ERROR: bad peasycap->field_fill\n"); return; } if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \ peasycap->field_page) { - SAY("ERROR: bad peasycap->field_page\n"); + SAM("ERROR: bad peasycap->field_page\n"); return; } pfield_buffer = &peasycap->field_buffer\ @@ -2770,7 +2775,7 @@ if (purb->status) { [peasycap->field_page]; if (PAGE_SIZE < (pfield_buffer->pto - \ pfield_buffer->pgo)) { - SAY("ERROR: bad pfield_buffer->pto\n"); + SAM("ERROR: bad pfield_buffer->pto\n"); return; } if (PAGE_SIZE == (pfield_buffer->pto - \ @@ -2778,7 +2783,7 @@ if (purb->status) { (peasycap->field_page)++; if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \ peasycap->field_page) { - JOT(16, "wrapping peasycap->" \ + JOM(16, "wrapping peasycap->" \ "field_page\n"); peasycap->field_page = 0; } @@ -2813,7 +2818,7 @@ if (purb->status) { */ /*---------------------------------------------------------------------------*/ if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) { - SAY("easycap driver shutting down on condition green\n"); + SAM("easycap driver shutting down on condition green\n"); peasycap->video_eof = 1; peasycap->audio_eof = 1; peasycap->video_junk = -VIDEO_ISOC_BUFFER_MANY; @@ -2824,38 +2829,38 @@ if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) { if (peasycap->video_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAY("ERROR: while %i=video_idle, usb_submit_urb() failed " \ + SAM("ERROR: while %i=video_idle, usb_submit_urb() failed " \ "with rc:\n", peasycap->video_idle); switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); break; + SAM("ENOMEM\n"); break; } case -ENODEV: { - SAY("ENODEV\n"); break; + SAM("ENODEV\n"); break; } case -ENXIO: { - SAY("ENXIO\n"); break; + SAM("ENXIO\n"); break; } case -EINVAL: { - SAY("EINVAL\n"); break; + SAM("EINVAL\n"); break; } case -EAGAIN: { - SAY("EAGAIN\n"); break; + SAM("EAGAIN\n"); break; } case -EFBIG: { - SAY("EFBIG\n"); break; + SAM("EFBIG\n"); break; } case -EPIPE: { - SAY("EPIPE\n"); break; + SAM("EPIPE\n"); break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); break; + SAM("EMSGSIZE\n"); break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + SAM("ENOSPC\n"); break; } default: { - SAY("0x%08X\n", rc); break; + SAM("0x%08X\n", rc); break; } } } @@ -2886,7 +2891,7 @@ struct usb_endpoint_descriptor *pepd; struct usb_interface_descriptor *pusb_interface_descriptor; struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor; struct urb *purb; -static struct easycap *peasycap /*=NULL*/; +struct easycap *peasycap; struct data_urb *pdata_urb; size_t wMaxPacketSize; int ISOCwMaxPacketSize; @@ -2896,18 +2901,18 @@ int CTRLwMaxPacketSize; __u8 bEndpointAddress; __u8 ISOCbEndpointAddress; __u8 INTbEndpointAddress; -int isin, i, j, k, m; +int isin, i, j, k, m, rc; __u8 bInterfaceNumber; __u8 bInterfaceClass; __u8 bInterfaceSubClass; void *pbuf; int okalt[8], isokalt; -int okepn[8], isokepn; -int okmps[8], isokmps; +int okepn[8]; +int okmps[8]; int maxpacketsize; -int rc; JOT(4, "\n"); +peasycap = (struct easycap *)NULL; if ((struct usb_interface *)NULL == pusb_interface) { SAY("ERROR: pusb_interface is NULL\n"); @@ -3009,40 +3014,74 @@ JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \ /* * A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED. * IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap. THIS - * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE DEVICE WAS PHYSICALLY - * UNPLUGGED. - */ + * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS + * PHYSICALLY UNPLUGGED. + * + * THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN + * INTERFACES 1 AND 2 ARE PROBED. + * + * IF TWO EasyCAPs ARE PLUGGED IN NEARLY SIMULTANEOUSLY THERE WILL + * BE TROUBLE. BEWARE. +*/ /*---------------------------------------------------------------------------*/ if (0 == bInterfaceNumber) { peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL); if (NULL == peasycap) { SAY("ERROR: Could not allocate peasycap\n"); return -ENOMEM; - } else { - peasycap->allocation_video_struct = sizeof(struct easycap); - peasycap->allocation_video_page = 0; - peasycap->allocation_video_urb = 0; - peasycap->allocation_audio_struct = 0; - peasycap->allocation_audio_page = 0; - peasycap->allocation_audio_urb = 0; } + SAM("allocated 0x%08lX=peasycap\n", (unsigned long int) peasycap); +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#if defined(EASYCAP_IS_VIDEODEV_CLIENT) + SAM("where 0x%08lX=&peasycap->video_device\n", \ + (unsigned long int) &peasycap->video_device); +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) + SAM("and 0x%08lX=&peasycap->v4l2_device\n", \ + (unsigned long int) &peasycap->v4l2_device); +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ +#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /*---------------------------------------------------------------------------*/ /* - * INITIALIZE THE NEW easycap STRUCTURE. - * NO PARAMETERS ARE SPECIFIED HERE REQUIRING THE SETTING OF REGISTERS. - * THAT IS DONE FIRST BY easycap_open() AND LATER BY easycap_ioctl(). - */ + * PERFORM URGENT INTIALIZATIONS ... +*/ /*---------------------------------------------------------------------------*/ - peasycap->pusb_device = pusb_device; - peasycap->pusb_interface = pusb_interface; - kref_init(&peasycap->kref); - JOT(8, "intf[%i]: after kref_init(..._video) " \ + JOM(8, "intf[%i]: after kref_init(..._video) " \ "%i=peasycap->kref.refcount.counter\n", \ bInterfaceNumber, peasycap->kref.refcount.counter); - init_waitqueue_head(&(peasycap->wq_video)); - init_waitqueue_head(&(peasycap->wq_audio)); + init_waitqueue_head(&peasycap->wq_video); + init_waitqueue_head(&peasycap->wq_audio); + + for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) { + if ((struct easycap *)NULL == peasycap_dongle[dongle_this]) { + peasycap_dongle[dongle_this] = peasycap; + JOM(8, "intf[%i]: peasycap-->easycap" \ + "_dongle[%i].peasycap\n", \ + bInterfaceNumber, dongle_this); + break; + } + } + if (DONGLE_MANY <= dongle_this) { + SAM("ERROR: too many dongles\n"); + return -ENOMEM; + } + + peasycap->allocation_video_struct = sizeof(struct easycap); + peasycap->allocation_video_page = 0; + peasycap->allocation_video_urb = 0; + peasycap->allocation_audio_struct = 0; + peasycap->allocation_audio_page = 0; + peasycap->allocation_audio_urb = 0; + +/*---------------------------------------------------------------------------*/ +/* + * ... AND FURTHER INITIALIZE THE STRUCTURE +*/ +/*---------------------------------------------------------------------------*/ + peasycap->pusb_device = pusb_device; + peasycap->pusb_interface = pusb_interface; peasycap->ilk = 0; peasycap->microphone = false; @@ -3062,6 +3101,8 @@ if (0 == bInterfaceNumber) { peasycap->audio_isoc_buffer_size = -1; peasycap->frame_buffer_many = FRAME_BUFFER_MANY; + + peasycap->offerfields = 0; /*---------------------------------------------------------------------------*/ /* * DYNAMICALLY FILL IN THE AVAILABLE FORMATS. @@ -3069,35 +3110,46 @@ if (0 == bInterfaceNumber) { /*---------------------------------------------------------------------------*/ rc = fillin_formats(); if (0 > rc) { - SAY("ERROR: fillin_formats() returned %i\n", rc); + SAM("ERROR: fillin_formats() returned %i\n", rc); return -EFAULT; } - JOT(4, "%i formats available\n", rc); - } else { + JOM(4, "%i formats available\n", rc); + JOM(4, "finished initialization\n"); +} else { /*---------------------------------------------------------------------------*/ - if ((struct easycap *)NULL == peasycap) { - SAY("ERROR: peasycap is NULL " \ - "when probing interface %i\n", \ - bInterfaceNumber); - return -EFAULT; - } + /* + * FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING + * THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF + * THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN + * SIMULTANEOUSLY, THERE WILL BE VERY SERIOUS TROUBLE. + */ +/*---------------------------------------------------------------------------*/ + if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) { + SAY("ERROR: bad dongle count\n"); + return -EFAULT; + } + peasycap = peasycap_dongle[dongle_this]; + JOT(8, "intf[%i]: peasycap_dongle[%i]-->peasycap\n", \ + bInterfaceNumber, dongle_this); - JOT(8, "kref_get() with %i=peasycap->kref.refcount.counter\n", \ - (int)peasycap->kref.refcount.counter); - kref_get(&peasycap->kref); + if ((struct easycap *)NULL == peasycap) { + SAY("ERROR: peasycap is NULL when probing interface %i\n", \ + bInterfaceNumber); + return -EFAULT; + } } /*---------------------------------------------------------------------------*/ if ((USB_CLASS_VIDEO == bInterfaceClass) || \ - (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) { + (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) { if (-1 == peasycap->video_interface) { peasycap->video_interface = bInterfaceNumber; - JOT(4, "setting peasycap->video_interface=%i\n", \ + JOM(4, "setting peasycap->video_interface=%i\n", \ peasycap->video_interface); } else { if (peasycap->video_interface != bInterfaceNumber) { - SAY("ERROR: attempting to reset " \ + SAM("ERROR: attempting to reset " \ "peasycap->video_interface\n"); - SAY("...... continuing with " \ + SAM("...... continuing with " \ "%i=peasycap->video_interface\n", \ peasycap->video_interface); } @@ -3106,13 +3158,13 @@ if ((USB_CLASS_VIDEO == bInterfaceClass) || \ (0x02 == bInterfaceSubClass)) { if (-1 == peasycap->audio_interface) { peasycap->audio_interface = bInterfaceNumber; - JOT(4, "setting peasycap->audio_interface=%i\n", \ + JOM(4, "setting peasycap->audio_interface=%i\n", \ peasycap->audio_interface); } else { if (peasycap->audio_interface != bInterfaceNumber) { - SAY("ERROR: attempting to reset " \ + SAM("ERROR: attempting to reset " \ "peasycap->audio_interface\n"); - SAY("...... continuing with " \ + SAM("...... continuing with " \ "%i=peasycap->audio_interface\n", \ peasycap->audio_interface); } @@ -3125,37 +3177,34 @@ if ((USB_CLASS_VIDEO == bInterfaceClass) || \ */ /*---------------------------------------------------------------------------*/ isokalt = 0; -isokepn = 0; -isokmps = 0; - for (i = 0; i < pusb_interface->num_altsetting; i++) { pusb_host_interface = &(pusb_interface->altsetting[i]); if ((struct usb_host_interface *)NULL == pusb_host_interface) { - SAY("ERROR: pusb_host_interface is NULL\n"); + SAM("ERROR: pusb_host_interface is NULL\n"); return -EFAULT; } pusb_interface_descriptor = &(pusb_host_interface->desc); if ((struct usb_interface_descriptor *)NULL == \ pusb_interface_descriptor) { - SAY("ERROR: pusb_interface_descriptor is NULL\n"); + SAM("ERROR: pusb_interface_descriptor is NULL\n"); return -EFAULT; } - JOT(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bDescriptorType); - JOT(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceNumber); - JOT(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bAlternateSetting); - JOT(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bNumEndpoints); - JOT(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceClass); - JOT(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceSubClass); - JOT(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceProtocol); - JOT(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \ + JOM(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \ bInterfaceNumber, i, pusb_interface_descriptor->iInterface); ISOCwMaxPacketSize = -1; @@ -3166,86 +3215,80 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) { INTbEndpointAddress = 0; if (0 == pusb_interface_descriptor->bNumEndpoints) - JOT(4, "intf[%i]alt[%i] has no endpoints\n", \ + JOM(4, "intf[%i]alt[%i] has no endpoints\n", \ bInterfaceNumber, i); /*---------------------------------------------------------------------------*/ for (j = 0; j < pusb_interface_descriptor->bNumEndpoints; j++) { pepd = &(pusb_host_interface->endpoint[j].desc); if ((struct usb_endpoint_descriptor *)NULL == pepd) { - SAY("ERROR: pepd is NULL.\n"); - SAY("...... skipping\n"); + SAM("ERROR: pepd is NULL.\n"); + SAM("...... skipping\n"); continue; } wMaxPacketSize = le16_to_cpu(pepd->wMaxPacketSize); bEndpointAddress = pepd->bEndpointAddress; - JOT(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \ + JOM(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \ bInterfaceNumber, i, j, \ pepd->bEndpointAddress); - JOT(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \ + JOM(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \ bInterfaceNumber, i, j, \ pepd->bmAttributes); - JOT(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \ + JOM(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \ bInterfaceNumber, i, j, \ pepd->wMaxPacketSize); - JOT(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n", + JOM(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n", bInterfaceNumber, i, j, \ pepd->bInterval); if (pepd->bEndpointAddress & USB_DIR_IN) { - JOT(4, "intf[%i]alt[%i]end[%i] is an IN endpoint\n",\ + JOM(4, "intf[%i]alt[%i]end[%i] is an IN endpoint\n",\ bInterfaceNumber, i, j); isin = 1; } else { - JOT(4, "intf[%i]alt[%i]end[%i] is an OUT endpoint\n",\ + JOM(4, "intf[%i]alt[%i]end[%i] is an OUT endpoint\n",\ bInterfaceNumber, i, j); - SAY("ERROR: OUT endpoint unexpected\n"); - SAY("...... continuing\n"); + SAM("ERROR: OUT endpoint unexpected\n"); + SAM("...... continuing\n"); isin = 0; } if ((pepd->bmAttributes & \ USB_ENDPOINT_XFERTYPE_MASK) == \ USB_ENDPOINT_XFER_ISOC) { - JOT(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\ + JOM(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\ bInterfaceNumber, i, j); if (isin) { switch (bInterfaceClass) { case USB_CLASS_VIDEO: case USB_CLASS_VENDOR_SPEC: { if (!peasycap) { - SAY("MISTAKE: " \ + SAM("MISTAKE: " \ "peasycap is NULL\n"); return -EFAULT; } if (pepd->wMaxPacketSize) { if (8 > isokalt) { okalt[isokalt] = i; - JOT(4,\ + JOM(4,\ "%i=okalt[%i]\n", \ okalt[isokalt], \ isokalt); - isokalt++; - } - if (8 > isokepn) { - okepn[isokepn] = \ + okepn[isokalt] = \ pepd->\ bEndpointAddress & \ 0x0F; - JOT(4,\ + JOM(4,\ "%i=okepn[%i]\n", \ - okepn[isokepn], \ - isokepn); - isokepn++; - } - if (8 > isokmps) { - okmps[isokmps] = \ + okepn[isokalt], \ + isokalt); + okmps[isokalt] = \ le16_to_cpu(pepd->\ wMaxPacketSize); - JOT(4,\ + JOM(4,\ "%i=okmps[%i]\n", \ - okmps[isokmps], \ - isokmps); - isokmps++; + okmps[isokalt], \ + isokalt); + isokalt++; } } else { if (-1 == peasycap->\ @@ -3253,16 +3296,16 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) { peasycap->\ video_altsetting_off =\ i; - JOT(4, "%i=video_" \ + JOM(4, "%i=video_" \ "altsetting_off " \ "<====\n", \ peasycap->\ video_altsetting_off); } else { - SAY("ERROR: peasycap" \ + SAM("ERROR: peasycap" \ "->video_altsetting_" \ "off already set\n"); - SAY("...... " \ + SAM("...... " \ "continuing with " \ "%i=peasycap->video_" \ "altsetting_off\n", \ @@ -3276,39 +3319,33 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) { if (0x02 != bInterfaceSubClass) break; if (!peasycap) { - SAY("MISTAKE: " \ + SAM("MISTAKE: " \ "peasycap is NULL\n"); return -EFAULT; } if (pepd->wMaxPacketSize) { if (8 > isokalt) { okalt[isokalt] = i ; - JOT(4,\ + JOM(4,\ "%i=okalt[%i]\n", \ okalt[isokalt], \ isokalt); - isokalt++; - } - if (8 > isokepn) { - okepn[isokepn] = \ + okepn[isokalt] = \ pepd->\ bEndpointAddress & \ 0x0F; - JOT(4,\ + JOM(4,\ "%i=okepn[%i]\n", \ - okepn[isokepn], \ - isokepn); - isokepn++; - } - if (8 > isokmps) { - okmps[isokmps] = \ + okepn[isokalt], \ + isokalt); + okmps[isokalt] = \ le16_to_cpu(pepd->\ wMaxPacketSize); - JOT(4,\ + JOM(4,\ "%i=okmps[%i]\n",\ - okmps[isokmps], \ - isokmps); - isokmps++; + okmps[isokalt], \ + isokalt); + isokalt++; } } else { if (-1 == peasycap->\ @@ -3316,16 +3353,16 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) { peasycap->\ audio_altsetting_off =\ i; - JOT(4, "%i=audio_" \ + JOM(4, "%i=audio_" \ "altsetting_off " \ "<====\n", \ peasycap->\ audio_altsetting_off); } else { - SAY("ERROR: peasycap" \ + SAM("ERROR: peasycap" \ "->audio_altsetting_" \ "off already set\n"); - SAY("...... " \ + SAM("...... " \ "continuing with " \ "%i=peasycap->\ audio_altsetting_" \ @@ -3343,19 +3380,19 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) { } else if ((pepd->bmAttributes & \ USB_ENDPOINT_XFERTYPE_MASK) ==\ USB_ENDPOINT_XFER_BULK) { - JOT(4, "intf[%i]alt[%i]end[%i] is a BULK endpoint\n",\ + JOM(4, "intf[%i]alt[%i]end[%i] is a BULK endpoint\n",\ bInterfaceNumber, i, j); } else if ((pepd->bmAttributes & \ USB_ENDPOINT_XFERTYPE_MASK) ==\ USB_ENDPOINT_XFER_INT) { - JOT(4, "intf[%i]alt[%i]end[%i] is an INT endpoint\n",\ + JOM(4, "intf[%i]alt[%i]end[%i] is an INT endpoint\n",\ bInterfaceNumber, i, j); } else { - JOT(4, "intf[%i]alt[%i]end[%i] is a CTRL endpoint\n",\ + JOM(4, "intf[%i]alt[%i]end[%i] is a CTRL endpoint\n",\ bInterfaceNumber, i, j); } if (0 == pepd->wMaxPacketSize) { - JOT(4, "intf[%i]alt[%i]end[%i] " \ + JOM(4, "intf[%i]alt[%i]end[%i] " \ "has zero packet size\n", \ bInterfaceNumber, i, j); } @@ -3366,7 +3403,7 @@ for (i = 0; i < pusb_interface->num_altsetting; i++) { * PERFORM INITIALIZATION OF THE PROBED INTERFACE */ /*---------------------------------------------------------------------------*/ -JOT(4, "initialization begins for interface %i\n", \ +JOM(4, "initialization begins for interface %i\n", \ pusb_interface_descriptor->bInterfaceNumber); switch (bInterfaceNumber) { /*---------------------------------------------------------------------------*/ @@ -3376,89 +3413,78 @@ switch (bInterfaceNumber) { /*---------------------------------------------------------------------------*/ case 0: { if (!peasycap) { - SAY("MISTAKE: peasycap is NULL\n"); + SAM("MISTAKE: peasycap is NULL\n"); return -EFAULT; } if (!isokalt) { - SAY("ERROR: no viable video_altsetting_on\n"); + SAM("ERROR: no viable video_altsetting_on\n"); return -ENOENT; } else { peasycap->video_altsetting_on = okalt[isokalt - 1]; - JOT(4, "%i=video_altsetting_on <====\n", \ + JOM(4, "%i=video_altsetting_on <====\n", \ peasycap->video_altsetting_on); } - if (!isokepn) { - SAY("ERROR: no viable video_endpointnumber\n"); - return -ENOENT; - } else { - peasycap->video_endpointnumber = okepn[isokepn - 1]; - JOT(4, "%i=video_endpointnumber\n", \ - peasycap->video_endpointnumber); - } - if (!isokmps) { - SAY("ERROR: no viable video_maxpacketsize\n"); - return -ENOENT; /*---------------------------------------------------------------------------*/ /* * DECIDE THE VIDEO STREAMING PARAMETERS */ /*---------------------------------------------------------------------------*/ + peasycap->video_endpointnumber = okepn[isokalt - 1]; + JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber); + maxpacketsize = okmps[isokalt - 1]; + if (USB_2_0_MAXPACKETSIZE > maxpacketsize) { + peasycap->video_isoc_maxframesize = maxpacketsize; } else { - maxpacketsize = okmps[isokmps - 1] - 1024; - if (USB_2_0_MAXPACKETSIZE > maxpacketsize) { - peasycap->video_isoc_maxframesize = maxpacketsize; - } else { - peasycap->video_isoc_maxframesize = \ - USB_2_0_MAXPACKETSIZE; - } - JOT(4, "%i=video_isoc_maxframesize\n", \ - peasycap->video_isoc_maxframesize); - if (0 >= peasycap->video_isoc_maxframesize) { - SAY("ERROR: bad video_isoc_maxframesize\n"); - return -ENOENT; - } - peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC; - JOT(4, "%i=video_isoc_framesperdesc\n", \ - peasycap->video_isoc_framesperdesc); - if (0 >= peasycap->video_isoc_framesperdesc) { - SAY("ERROR: bad video_isoc_framesperdesc\n"); - return -ENOENT; - } - peasycap->video_isoc_buffer_size = \ - peasycap->video_isoc_maxframesize * \ - peasycap->video_isoc_framesperdesc; - JOT(4, "%i=video_isoc_buffer_size\n", \ - peasycap->video_isoc_buffer_size); - if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \ - peasycap->video_isoc_buffer_size) { - SAY("MISTAKE: " \ - "peasycap->video_isoc_buffer_size too big\n"); - return -EFAULT; - } + peasycap->video_isoc_maxframesize = \ + USB_2_0_MAXPACKETSIZE; + } + JOM(4, "%i=video_isoc_maxframesize\n", \ + peasycap->video_isoc_maxframesize); + if (0 >= peasycap->video_isoc_maxframesize) { + SAM("ERROR: bad video_isoc_maxframesize\n"); + SAM(" possibly because port is USB 1.1\n"); + return -ENOENT; + } + peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC; + JOM(4, "%i=video_isoc_framesperdesc\n", \ + peasycap->video_isoc_framesperdesc); + if (0 >= peasycap->video_isoc_framesperdesc) { + SAM("ERROR: bad video_isoc_framesperdesc\n"); + return -ENOENT; + } + peasycap->video_isoc_buffer_size = \ + peasycap->video_isoc_maxframesize * \ + peasycap->video_isoc_framesperdesc; + JOM(4, "%i=video_isoc_buffer_size\n", \ + peasycap->video_isoc_buffer_size); + if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \ + peasycap->video_isoc_buffer_size) { + SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n"); + return -EFAULT; } /*---------------------------------------------------------------------------*/ if (-1 == peasycap->video_interface) { - SAY("MISTAKE: video_interface is unset\n"); + SAM("MISTAKE: video_interface is unset\n"); return -EFAULT; } if (-1 == peasycap->video_altsetting_on) { - SAY("MISTAKE: video_altsetting_on is unset\n"); + SAM("MISTAKE: video_altsetting_on is unset\n"); return -EFAULT; } if (-1 == peasycap->video_altsetting_off) { - SAY("MISTAKE: video_interface_off is unset\n"); + SAM("MISTAKE: video_interface_off is unset\n"); return -EFAULT; } if (-1 == peasycap->video_endpointnumber) { - SAY("MISTAKE: video_endpointnumber is unset\n"); + SAM("MISTAKE: video_endpointnumber is unset\n"); return -EFAULT; } if (-1 == peasycap->video_isoc_maxframesize) { - SAY("MISTAKE: video_isoc_maxframesize is unset\n"); + SAM("MISTAKE: video_isoc_maxframesize is unset\n"); return -EFAULT; } if (-1 == peasycap->video_isoc_buffer_size) { - SAY("MISTAKE: video_isoc_buffer_size is unset\n"); + SAM("MISTAKE: video_isoc_buffer_size is unset\n"); return -EFAULT; } /*---------------------------------------------------------------------------*/ @@ -3469,20 +3495,20 @@ case 0: { INIT_LIST_HEAD(&(peasycap->urb_video_head)); peasycap->purb_video_head = &(peasycap->urb_video_head); /*---------------------------------------------------------------------------*/ - JOT(4, "allocating %i frame buffers of size %li\n", \ + JOM(4, "allocating %i frame buffers of size %li\n", \ FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE); - JOT(4, ".... each scattered over %li pages\n", \ + JOM(4, ".... each scattered over %li pages\n", \ FRAME_BUFFER_SIZE/PAGE_SIZE); for (k = 0; k < FRAME_BUFFER_MANY; k++) { for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) { if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) - SAY("attempting to reallocate frame " \ + SAM("attempting to reallocate frame " \ " buffers\n"); else { pbuf = (void *)__get_free_page(GFP_KERNEL); if ((void *)NULL == pbuf) { - SAY("ERROR: Could not allocate frame "\ + SAM("ERROR: Could not allocate frame "\ "buffer %i page %i\n", k, m); return -ENOMEM; } else @@ -3496,23 +3522,23 @@ case 0: { peasycap->frame_fill = 0; peasycap->frame_read = 0; - JOT(4, "allocation of frame buffers done: %i pages\n", k * \ + JOM(4, "allocation of frame buffers done: %i pages\n", k * \ m); /*---------------------------------------------------------------------------*/ - JOT(4, "allocating %i field buffers of size %li\n", \ + JOM(4, "allocating %i field buffers of size %li\n", \ FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE); - JOT(4, ".... each scattered over %li pages\n", \ + JOM(4, ".... each scattered over %li pages\n", \ FIELD_BUFFER_SIZE/PAGE_SIZE); for (k = 0; k < FIELD_BUFFER_MANY; k++) { for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) { if ((void *)NULL != peasycap->field_buffer[k][m].pgo) { - SAY("ERROR: attempting to reallocate " \ + SAM("ERROR: attempting to reallocate " \ "field buffers\n"); } else { pbuf = (void *) __get_free_page(GFP_KERNEL); if ((void *)NULL == pbuf) { - SAY("ERROR: Could not allocate field" \ + SAM("ERROR: Could not allocate field" \ " buffer %i page %i\n", k, m); return -ENOMEM; } @@ -3528,18 +3554,18 @@ case 0: { peasycap->field_fill = 0; peasycap->field_page = 0; peasycap->field_read = 0; - JOT(4, "allocation of field buffers done: %i pages\n", k * \ + JOM(4, "allocation of field buffers done: %i pages\n", k * \ m); /*---------------------------------------------------------------------------*/ - JOT(4, "allocating %i isoc video buffers of size %i\n", \ + JOM(4, "allocating %i isoc video buffers of size %i\n", \ VIDEO_ISOC_BUFFER_MANY, \ peasycap->video_isoc_buffer_size); - JOT(4, ".... each occupying contiguous memory pages\n"); + JOM(4, ".... each occupying contiguous memory pages\n"); for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) { pbuf = (void *)__get_free_pages(GFP_KERNEL, VIDEO_ISOC_ORDER); if (NULL == pbuf) { - SAY("ERROR: Could not allocate isoc video buffer " \ + SAM("ERROR: Could not allocate isoc video buffer " \ "%i\n", k); return -ENOMEM; } else @@ -3551,26 +3577,26 @@ case 0: { peasycap->video_isoc_buffer_size; peasycap->video_isoc_buffer[k].kount = k; } - JOT(4, "allocation of isoc video buffers done: %i pages\n", \ + JOM(4, "allocation of isoc video buffers done: %i pages\n", \ k * (0x01 << VIDEO_ISOC_ORDER)); /*---------------------------------------------------------------------------*/ /* * ALLOCATE AND INITIALIZE MULTIPLE struct urb ... */ /*---------------------------------------------------------------------------*/ - JOT(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY); - JOT(4, "using %i=peasycap->video_isoc_framesperdesc\n", \ + JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY); + JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n", \ peasycap->video_isoc_framesperdesc); - JOT(4, "using %i=peasycap->video_isoc_maxframesize\n", \ + JOM(4, "using %i=peasycap->video_isoc_maxframesize\n", \ peasycap->video_isoc_maxframesize); - JOT(4, "using %i=peasycap->video_isoc_buffer_sizen", \ + JOM(4, "using %i=peasycap->video_isoc_buffer_sizen", \ peasycap->video_isoc_buffer_size); for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) { purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc, \ GFP_KERNEL); if (NULL == purb) { - SAY("ERROR: usb_alloc_urb returned NULL for buffer " \ + SAM("ERROR: usb_alloc_urb returned NULL for buffer " \ "%i\n", k); return -ENOMEM; } else @@ -3578,7 +3604,7 @@ case 0: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); if (NULL == pdata_urb) { - SAY("ERROR: Could not allocate struct data_urb.\n"); + SAM("ERROR: Could not allocate struct data_urb.\n"); return -ENOMEM; } else peasycap->allocation_video_struct += \ @@ -3595,30 +3621,30 @@ case 0: { */ /*---------------------------------------------------------------------------*/ if (!k) { - JOT(4, "initializing video urbs thus:\n"); - JOT(4, " purb->interval = 1;\n"); - JOT(4, " purb->dev = peasycap->pusb_device;\n"); - JOT(4, " purb->pipe = usb_rcvisocpipe" \ + JOM(4, "initializing video urbs thus:\n"); + JOM(4, " purb->interval = 1;\n"); + JOM(4, " purb->dev = peasycap->pusb_device;\n"); + JOM(4, " purb->pipe = usb_rcvisocpipe" \ "(peasycap->pusb_device,%i);\n", \ peasycap->video_endpointnumber); - JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n"); - JOT(4, " purb->transfer_buffer = peasycap->" \ + JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n"); + JOM(4, " purb->transfer_buffer = peasycap->" \ "video_isoc_buffer[.].pgo;\n"); - JOT(4, " purb->transfer_buffer_length = %i;\n", \ + JOM(4, " purb->transfer_buffer_length = %i;\n", \ peasycap->video_isoc_buffer_size); - JOT(4, " purb->complete = easycap_complete;\n"); - JOT(4, " purb->context = peasycap;\n"); - JOT(4, " purb->start_frame = 0;\n"); - JOT(4, " purb->number_of_packets = %i;\n", \ + JOM(4, " purb->complete = easycap_complete;\n"); + JOM(4, " purb->context = peasycap;\n"); + JOM(4, " purb->start_frame = 0;\n"); + JOM(4, " purb->number_of_packets = %i;\n", \ peasycap->video_isoc_framesperdesc); - JOT(4, " for (j = 0; j < %i; j++)\n", \ + JOM(4, " for (j = 0; j < %i; j++)\n", \ peasycap->video_isoc_framesperdesc); - JOT(4, " {\n"); - JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\ + JOM(4, " {\n"); + JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\ peasycap->video_isoc_maxframesize); - JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \ + JOM(4, " purb->iso_frame_desc[j].length = %i;\n", \ peasycap->video_isoc_maxframesize); - JOT(4, " }\n"); + JOM(4, " }\n"); } purb->interval = 1; @@ -3640,7 +3666,7 @@ case 0: { peasycap->video_isoc_maxframesize; } } - JOT(4, "allocation of %i struct urb done.\n", k); + JOM(4, "allocation of %i struct urb done.\n", k); /*--------------------------------------------------------------------------*/ /* * SAVE POINTER peasycap IN THIS INTERFACE. @@ -3657,48 +3683,55 @@ case 0: { err("Not able to get a minor for this device"); usb_set_intfdata(pusb_interface, NULL); return -ENODEV; - } else + } else { (peasycap->registered_video)++; - SAY("easycap attached to minor #%d\n", pusb_interface->minor); - break; -/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ -#else - pvideo_device = (struct video_device *)\ - kzalloc(sizeof(struct video_device), GFP_KERNEL); - if ((struct video_device *)NULL == pvideo_device) { - SAY("ERROR: Could not allocate structure video_device\n"); - return -ENOMEM; + SAM("easycap attached to minor #%d\n", pusb_interface->minor); + break; } - if (VIDEO_DEVICE_MANY <= video_device_many) { - SAY("ERROR: Too many /dev/videos\n"); - return -ENOMEM; +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#else +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) + if (0 != (v4l2_device_register(&(pusb_interface->dev), \ + &(peasycap->v4l2_device)))) { + SAM("v4l2_device_register() failed\n"); + return -ENODEV; + } else { + JOM(4, "registered device instance: %s\n", \ + &(peasycap->v4l2_device.name[0])); } - pvideo_array[video_device_many] = pvideo_device; video_device_many++; +/*---------------------------------------------------------------------------*/ +/* + * THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG: +*/ +/*---------------------------------------------------------------------------*/ + peasycap->video_device.v4l2_dev = (struct v4l2_device *)NULL; +/*---------------------------------------------------------------------------*/ - strcpy(&pvideo_device->name[0], "easycapdc60"); +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ + + strcpy(&peasycap->video_device.name[0], "easycapdc60"); #if defined(EASYCAP_NEEDS_V4L2_FOPS) - pvideo_device->fops = &v4l2_fops; + peasycap->video_device.fops = &v4l2_fops; #else - pvideo_device->fops = &easycap_fops; + peasycap->video_device.fops = &easycap_fops; #endif /*EASYCAP_NEEDS_V4L2_FOPS*/ - pvideo_device->minor = -1; - pvideo_device->release = (void *)(&videodev_release); + peasycap->video_device.minor = -1; + peasycap->video_device.release = (void *)(&videodev_release); - video_set_drvdata(pvideo_device, (void *)peasycap); + video_set_drvdata(&(peasycap->video_device), (void *)peasycap); - rc = video_register_device(pvideo_device, VFL_TYPE_GRABBER, -1); - if (0 != rc) { + if (0 != (video_register_device(&(peasycap->video_device), \ + VFL_TYPE_GRABBER, -1))) { err("Not able to register with videodev"); - videodev_release(pvideo_device); + videodev_release(&(peasycap->video_device)); return -ENODEV; } else { - peasycap->pvideo_device = pvideo_device; (peasycap->registered_video)++; - JOT(4, "registered with videodev: %i=minor\n", \ - pvideo_device->minor); + SAM("registered with videodev: %i=minor\n", \ + peasycap->video_device.minor); } -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ break; } /*--------------------------------------------------------------------------*/ @@ -3708,125 +3741,118 @@ case 0: { */ /*--------------------------------------------------------------------------*/ case 1: { + if (!peasycap) { + SAM("ERROR: peasycap is NULL\n"); + return -EFAULT; + } /*--------------------------------------------------------------------------*/ /* * SAVE POINTER peasycap IN INTERFACE 1 */ /*--------------------------------------------------------------------------*/ usb_set_intfdata(pusb_interface, peasycap); - JOT(4, "no initialization required for interface %i\n", \ + JOM(4, "no initialization required for interface %i\n", \ pusb_interface_descriptor->bInterfaceNumber); break; } /*--------------------------------------------------------------------------*/ case 2: { if (!peasycap) { - SAY("MISTAKE: peasycap is NULL\n"); + SAM("MISTAKE: peasycap is NULL\n"); return -EFAULT; } if (!isokalt) { - SAY("ERROR: no viable audio_altsetting_on\n"); + SAM("ERROR: no viable audio_altsetting_on\n"); return -ENOENT; } else { peasycap->audio_altsetting_on = okalt[isokalt - 1]; - JOT(4, "%i=audio_altsetting_on <====\n", \ + JOM(4, "%i=audio_altsetting_on <====\n", \ peasycap->audio_altsetting_on); } - if (!isokepn) { - SAY("ERROR: no viable audio_endpointnumber\n"); + + peasycap->audio_endpointnumber = okepn[isokalt - 1]; + JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber); + + peasycap->audio_isoc_maxframesize = okmps[isokalt - 1]; + JOM(4, "%i=audio_isoc_maxframesize\n", \ + peasycap->audio_isoc_maxframesize); + if (0 >= peasycap->audio_isoc_maxframesize) { + SAM("ERROR: bad audio_isoc_maxframesize\n"); return -ENOENT; - } else { - peasycap->audio_endpointnumber = okepn[isokepn - 1]; - JOT(4, "%i=audio_endpointnumber\n", \ - peasycap->audio_endpointnumber); } - if (!isokmps) { - SAY("ERROR: no viable audio_maxpacketsize\n"); - return -ENOENT; + if (9 == peasycap->audio_isoc_maxframesize) { + peasycap->ilk |= 0x02; + SAM("hardware is FOUR-CVBS\n"); + peasycap->microphone = true; + peasycap->audio_pages_per_fragment = 4; + } else if (256 == peasycap->audio_isoc_maxframesize) { + peasycap->ilk &= ~0x02; + SAM("hardware is CVBS+S-VIDEO\n"); + peasycap->microphone = false; + peasycap->audio_pages_per_fragment = 4; } else { - peasycap->audio_isoc_maxframesize = okmps[isokmps - 1]; - JOT(4, "%i=audio_isoc_maxframesize\n", \ - peasycap->audio_isoc_maxframesize); - if (0 >= peasycap->audio_isoc_maxframesize) { - SAY("ERROR: bad audio_isoc_maxframesize\n"); - return -ENOENT; - } - if (9 == peasycap->audio_isoc_maxframesize) { - peasycap->ilk |= 0x02; - SAY("hardware is FOUR-CVBS\n"); - peasycap->microphone = true; - peasycap->audio_pages_per_fragment = 4; - } else if (256 == peasycap->audio_isoc_maxframesize) { - peasycap->ilk &= ~0x02; - SAY("hardware is CVBS+S-VIDEO\n"); - peasycap->microphone = false; - peasycap->audio_pages_per_fragment = 4; - } else { - SAY("hardware is unidentified:\n"); - SAY("%i=audio_isoc_maxframesize\n", \ + SAM("hardware is unidentified:\n"); + SAM("%i=audio_isoc_maxframesize\n", \ peasycap->audio_isoc_maxframesize); - return -ENOENT; - } + return -ENOENT; + } - peasycap->audio_bytes_per_fragment = \ + peasycap->audio_bytes_per_fragment = \ peasycap->audio_pages_per_fragment * \ PAGE_SIZE ; - peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \ + peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \ peasycap->audio_pages_per_fragment); - JOT(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY); - JOT(4, "%6i=audio_pages_per_fragment\n", \ + JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY); + JOM(4, "%6i=audio_pages_per_fragment\n", \ peasycap->audio_pages_per_fragment); - JOT(4, "%6i=audio_bytes_per_fragment\n", \ + JOM(4, "%6i=audio_bytes_per_fragment\n", \ peasycap->audio_bytes_per_fragment); - JOT(4, "%6i=audio_buffer_page_many\n", \ + JOM(4, "%6i=audio_buffer_page_many\n", \ peasycap->audio_buffer_page_many); - peasycap->audio_isoc_framesperdesc = 128; + peasycap->audio_isoc_framesperdesc = 128; - JOT(4, "%i=audio_isoc_framesperdesc\n", \ + JOM(4, "%i=audio_isoc_framesperdesc\n", \ peasycap->audio_isoc_framesperdesc); - if (0 >= peasycap->audio_isoc_framesperdesc) { - SAY("ERROR: bad audio_isoc_framesperdesc\n"); - return -ENOENT; - } + if (0 >= peasycap->audio_isoc_framesperdesc) { + SAM("ERROR: bad audio_isoc_framesperdesc\n"); + return -ENOENT; + } - peasycap->audio_isoc_buffer_size = \ + peasycap->audio_isoc_buffer_size = \ peasycap->audio_isoc_maxframesize * \ peasycap->audio_isoc_framesperdesc; - JOT(4, "%i=audio_isoc_buffer_size\n", \ + JOM(4, "%i=audio_isoc_buffer_size\n", \ peasycap->audio_isoc_buffer_size); - if (AUDIO_ISOC_BUFFER_SIZE < \ - peasycap->audio_isoc_buffer_size) { - SAY("MISTAKE: audio_isoc_buffer_size bigger " + if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) { + SAM("MISTAKE: audio_isoc_buffer_size bigger " "than %li=AUDIO_ISOC_BUFFER_SIZE\n", \ AUDIO_ISOC_BUFFER_SIZE); - return -EFAULT; - } + return -EFAULT; } - if (-1 == peasycap->audio_interface) { - SAY("MISTAKE: audio_interface is unset\n"); + SAM("MISTAKE: audio_interface is unset\n"); return -EFAULT; } if (-1 == peasycap->audio_altsetting_on) { - SAY("MISTAKE: audio_altsetting_on is unset\n"); + SAM("MISTAKE: audio_altsetting_on is unset\n"); return -EFAULT; } if (-1 == peasycap->audio_altsetting_off) { - SAY("MISTAKE: audio_interface_off is unset\n"); + SAM("MISTAKE: audio_interface_off is unset\n"); return -EFAULT; } if (-1 == peasycap->audio_endpointnumber) { - SAY("MISTAKE: audio_endpointnumber is unset\n"); + SAM("MISTAKE: audio_endpointnumber is unset\n"); return -EFAULT; } if (-1 == peasycap->audio_isoc_maxframesize) { - SAY("MISTAKE: audio_isoc_maxframesize is unset\n"); + SAM("MISTAKE: audio_isoc_maxframesize is unset\n"); return -EFAULT; } if (-1 == peasycap->audio_isoc_buffer_size) { - SAY("MISTAKE: audio_isoc_buffer_size is unset\n"); + SAM("MISTAKE: audio_isoc_buffer_size is unset\n"); return -EFAULT; } /*---------------------------------------------------------------------------*/ @@ -3837,17 +3863,17 @@ case 2: { INIT_LIST_HEAD(&(peasycap->urb_audio_head)); peasycap->purb_audio_head = &(peasycap->urb_audio_head); - JOT(4, "allocating an audio buffer\n"); - JOT(4, ".... scattered over %i pages\n", \ + JOM(4, "allocating an audio buffer\n"); + JOM(4, ".... scattered over %i pages\n", \ peasycap->audio_buffer_page_many); for (k = 0; k < peasycap->audio_buffer_page_many; k++) { if ((void *)NULL != peasycap->audio_buffer[k].pgo) { - SAY("ERROR: attempting to reallocate audio buffers\n"); + SAM("ERROR: attempting to reallocate audio buffers\n"); } else { pbuf = (void *) __get_free_page(GFP_KERNEL); if ((void *)NULL == pbuf) { - SAY("ERROR: Could not allocate audio " \ + SAM("ERROR: Could not allocate audio " \ "buffer page %i\n", k); return -ENOMEM; } else @@ -3860,16 +3886,16 @@ case 2: { peasycap->audio_fill = 0; peasycap->audio_read = 0; - JOT(4, "allocation of audio buffer done: %i pages\n", k); + JOM(4, "allocation of audio buffer done: %i pages\n", k); /*---------------------------------------------------------------------------*/ - JOT(4, "allocating %i isoc audio buffers of size %i\n", \ + JOM(4, "allocating %i isoc audio buffers of size %i\n", \ AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size); - JOT(4, ".... each occupying contiguous memory pages\n"); + JOM(4, ".... each occupying contiguous memory pages\n"); for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER); if (NULL == pbuf) { - SAY("ERROR: Could not allocate isoc audio buffer " \ + SAM("ERROR: Could not allocate isoc audio buffer " \ "%i\n", k); return -ENOMEM; } else @@ -3881,25 +3907,25 @@ case 2: { peasycap->audio_isoc_buffer_size; peasycap->audio_isoc_buffer[k].kount = k; } - JOT(4, "allocation of isoc audio buffers done.\n"); + JOM(4, "allocation of isoc audio buffers done.\n"); /*---------------------------------------------------------------------------*/ /* * ALLOCATE AND INITIALIZE MULTIPLE struct urb ... */ /*---------------------------------------------------------------------------*/ - JOT(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY); - JOT(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \ + JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY); + JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \ peasycap->audio_isoc_framesperdesc); - JOT(4, "using %i=peasycap->audio_isoc_maxframesize\n", \ + JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n", \ peasycap->audio_isoc_maxframesize); - JOT(4, "using %i=peasycap->audio_isoc_buffer_size\n", \ + JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n", \ peasycap->audio_isoc_buffer_size); for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc, \ GFP_KERNEL); if (NULL == purb) { - SAY("ERROR: usb_alloc_urb returned NULL for buffer " \ + SAM("ERROR: usb_alloc_urb returned NULL for buffer " \ "%i\n", k); return -ENOMEM; } else @@ -3907,7 +3933,7 @@ case 2: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); if (NULL == pdata_urb) { - SAY("ERROR: Could not allocate struct data_urb.\n"); + SAM("ERROR: Could not allocate struct data_urb.\n"); return -ENOMEM; } else peasycap->allocation_audio_struct += \ @@ -3924,30 +3950,30 @@ case 2: { */ /*---------------------------------------------------------------------------*/ if (!k) { - JOT(4, "initializing audio urbs thus:\n"); - JOT(4, " purb->interval = 1;\n"); - JOT(4, " purb->dev = peasycap->pusb_device;\n"); - JOT(4, " purb->pipe = usb_rcvisocpipe(peasycap->" \ + JOM(4, "initializing audio urbs thus:\n"); + JOM(4, " purb->interval = 1;\n"); + JOM(4, " purb->dev = peasycap->pusb_device;\n"); + JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->" \ "pusb_device,%i);\n", \ peasycap->audio_endpointnumber); - JOT(4, " purb->transfer_flags = URB_ISO_ASAP;\n"); - JOT(4, " purb->transfer_buffer = " \ + JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n"); + JOM(4, " purb->transfer_buffer = " \ "peasycap->audio_isoc_buffer[.].pgo;\n"); - JOT(4, " purb->transfer_buffer_length = %i;\n", \ + JOM(4, " purb->transfer_buffer_length = %i;\n", \ peasycap->audio_isoc_buffer_size); - JOT(4, " purb->complete = easysnd_complete;\n"); - JOT(4, " purb->context = peasycap;\n"); - JOT(4, " purb->start_frame = 0;\n"); - JOT(4, " purb->number_of_packets = %i;\n", \ + JOM(4, " purb->complete = easysnd_complete;\n"); + JOM(4, " purb->context = peasycap;\n"); + JOM(4, " purb->start_frame = 0;\n"); + JOM(4, " purb->number_of_packets = %i;\n", \ peasycap->audio_isoc_framesperdesc); - JOT(4, " for (j = 0; j < %i; j++)\n", \ + JOM(4, " for (j = 0; j < %i; j++)\n", \ peasycap->audio_isoc_framesperdesc); - JOT(4, " {\n"); - JOT(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\ + JOM(4, " {\n"); + JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",\ peasycap->audio_isoc_maxframesize); - JOT(4, " purb->iso_frame_desc[j].length = %i;\n", \ + JOM(4, " purb->iso_frame_desc[j].length = %i;\n", \ peasycap->audio_isoc_maxframesize); - JOT(4, " }\n"); + JOM(4, " }\n"); } purb->interval = 1; @@ -3969,7 +3995,7 @@ case 2: { peasycap->audio_isoc_maxframesize; } } - JOT(4, "allocation of %i struct urb done.\n", k); + JOM(4, "allocation of %i struct urb done.\n", k); /*---------------------------------------------------------------------------*/ /* * SAVE POINTER peasycap IN THIS INTERFACE. @@ -3986,14 +4012,18 @@ case 2: { err("Not able to get a minor for this device."); usb_set_intfdata(pusb_interface, NULL); return -ENODEV; - } else + } else { + JOM(8, "kref_get() with %i=peasycap->kref.refcount.counter\n",\ + (int)peasycap->kref.refcount.counter); + kref_get(&peasycap->kref); (peasycap->registered_audio)++; + } /*---------------------------------------------------------------------------*/ /* * LET THE USER KNOW WHAT NODE THE AUDIO DEVICE IS ATTACHED TO. */ /*---------------------------------------------------------------------------*/ - SAY("easysnd attached to minor #%d\n", pusb_interface->minor); + SAM("easysnd attached to minor #%d\n", pusb_interface->minor); break; } /*---------------------------------------------------------------------------*/ @@ -4002,11 +4032,11 @@ case 2: { */ /*---------------------------------------------------------------------------*/ default: { - JOT(4, "ERROR: unexpected interface %i\n", bInterfaceNumber); + JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber); return -EINVAL; } } -JOT(4, "ends successfully for interface %i\n", \ +JOM(4, "ends successfully for interface %i\n", \ pusb_interface_descriptor->bInterfaceNumber); return 0; } @@ -4050,60 +4080,67 @@ bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber; minor = pusb_interface->minor; JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor); +if (1 == bInterfaceNumber) + return; + peasycap = usb_get_intfdata(pusb_interface); -if ((struct easycap *)NULL == peasycap) +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); -else { - peasycap->pusb_device = (struct usb_device *)NULL; - switch (bInterfaceNumber) { -/*---------------------------------------------------------------------------*/ - case 0: { - if ((struct list_head *)NULL != peasycap->purb_video_head) { - JOT(4, "killing video urbs\n"); - m = 0; - list_for_each(plist_head, (peasycap->purb_video_head)) - { - pdata_urb = list_entry(plist_head, \ - struct data_urb, list_head); - if ((struct data_urb *)NULL != pdata_urb) { - if ((struct urb *)NULL != \ - pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } + return; +} +/*---------------------------------------------------------------------------*/ +/* + * IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE. BEWARE. +*/ +/*---------------------------------------------------------------------------*/ +peasycap->video_eof = 1; +peasycap->audio_eof = 1; +wake_up_interruptible(&peasycap->wq_video); +wake_up_interruptible(&peasycap->wq_audio); +/*---------------------------------------------------------------------------*/ +switch (bInterfaceNumber) { +case 0: { + if ((struct list_head *)NULL != peasycap->purb_video_head) { + JOM(4, "killing video urbs\n"); + m = 0; + list_for_each(plist_head, (peasycap->purb_video_head)) { + pdata_urb = list_entry(plist_head, \ + struct data_urb, list_head); + if ((struct data_urb *)NULL != pdata_urb) { + if ((struct urb *)NULL != \ + pdata_urb->purb) { + usb_kill_urb(pdata_urb->purb); + m++; } } - JOT(4, "%i video urbs killed\n", m); - } else - SAY("ERROR: peasycap->purb_video_head is NULL\n"); - break; + } + JOM(4, "%i video urbs killed\n", m); } + break; +} /*---------------------------------------------------------------------------*/ - case 2: { - if ((struct list_head *)NULL != peasycap->purb_audio_head) { - JOT(4, "killing audio urbs\n"); - m = 0; - list_for_each(plist_head, \ - (peasycap->purb_audio_head)) { - pdata_urb = list_entry(plist_head, \ - struct data_urb, list_head); - if ((struct data_urb *)NULL != pdata_urb) { - if ((struct urb *)NULL != \ - pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } +case 2: { + if ((struct list_head *)NULL != peasycap->purb_audio_head) { + JOM(4, "killing audio urbs\n"); + m = 0; + list_for_each(plist_head, (peasycap->purb_audio_head)) { + pdata_urb = list_entry(plist_head, \ + struct data_urb, list_head); + if ((struct data_urb *)NULL != pdata_urb) { + if ((struct urb *)NULL != \ + pdata_urb->purb) { + usb_kill_urb(pdata_urb->purb); + m++; } } - JOT(4, "%i audio urbs killed\n", m); - } else - SAY("ERROR: peasycap->purb_audio_head is NULL\n"); - break; + } + JOM(4, "%i audio urbs killed\n", m); } + break; +} /*---------------------------------------------------------------------------*/ - default: - break; - } +default: + break; } /*--------------------------------------------------------------------------*/ /* @@ -4112,29 +4149,30 @@ else { /*--------------------------------------------------------------------------*/ switch (bInterfaceNumber) { case 0: { + #if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) if ((struct easycap *)NULL == peasycap) { - SAY("ERROR: peasycap has become NULL\n"); + SAM("ERROR: peasycap has become NULL\n"); } else { lock_kernel(); usb_deregister_dev(pusb_interface, &easycap_class); (peasycap->registered_video)--; - JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); + JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); unlock_kernel(); - SAY("easycap detached from minor #%d\n", minor); + SAM("easycap detached from minor #%d\n", minor); } /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #else if ((struct easycap *)NULL == peasycap) - SAY("ERROR: peasycap has become NULL\n"); + SAM("ERROR: peasycap has become NULL\n"); else { lock_kernel(); - video_unregister_device(peasycap->pvideo_device); + video_unregister_device(&peasycap->video_device); (peasycap->registered_video)--; unlock_kernel(); - JOT(4, "unregistered with videodev: %i=minor\n", \ - pvideo_device->minor); + JOM(4, "unregistered with videodev: %i=minor\n", \ + peasycap->video_device.minor); } /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ @@ -4147,10 +4185,10 @@ case 2: { if ((struct easycap *)NULL != peasycap) (peasycap->registered_audio)--; - JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); + JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); unlock_kernel(); - SAY("easysnd detached from minor #%d\n", minor); + SAM("easysnd detached from minor #%d\n", minor); break; } default: @@ -4162,24 +4200,24 @@ default: */ /*---------------------------------------------------------------------------*/ if ((struct easycap *)NULL == peasycap) { - SAY("ERROR: peasycap has become NULL\n"); - SAY("cannot call kref_put()\n"); - SAY("ending unsuccessfully: may cause memory leak\n"); + SAM("ERROR: peasycap has become NULL\n"); + SAM("cannot call kref_put()\n"); + SAM("ending unsuccessfully: may cause memory leak\n"); return; } if (!peasycap->kref.refcount.counter) { - SAY("ERROR: peasycap->kref.refcount.counter is zero " \ + SAM("ERROR: peasycap->kref.refcount.counter is zero " \ "so cannot call kref_put()\n"); - SAY("ending unsuccessfully: may cause memory leak\n"); + SAM("ending unsuccessfully: may cause memory leak\n"); return; } -JOT(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \ +JOM(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \ bInterfaceNumber, (int)peasycap->kref.refcount.counter); kref_put(&peasycap->kref, easycap_delete); -JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber); +JOM(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber); /*---------------------------------------------------------------------------*/ -JOT(4, "ends\n"); +JOM(4, "ends\n"); return; } /*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c index 7be5bcf7136f..21275973faf3 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/easycap/easycap_sound.c @@ -43,10 +43,8 @@ void easysnd_complete(struct urb *purb) { -static int mt; struct easycap *peasycap; struct data_buffer *paudio_buffer; -char errbuf[16]; __u8 *p1, *p2; __s16 s16; int i, j, more, much, leap, rc; @@ -68,46 +66,55 @@ if (NULL == peasycap) { } much = 0; - if (peasycap->audio_idle) { - JOT(16, "%i=audio_idle %i=audio_isoc_streaming\n", \ + JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n", \ peasycap->audio_idle, peasycap->audio_isoc_streaming); if (peasycap->audio_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAY("ERROR: while %i=audio_idle, " \ + if (-ENODEV != rc) + SAM("ERROR: while %i=audio_idle, " \ "usb_submit_urb() failed with rc:\n", \ peasycap->audio_idle); switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); break; + SAM("-ENOMEM\n"); + break; } case -ENODEV: { - SAY("ENODEV\n"); break; + break; } case -ENXIO: { - SAY("ENXIO\n"); break; + SAM("-ENXIO\n"); + break; } case -EINVAL: { - SAY("EINVAL\n"); break; + SAM("-EINVAL\n"); + break; } case -EAGAIN: { - SAY("EAGAIN\n"); break; + SAM("-EAGAIN\n"); + break; } case -EFBIG: { - SAY("EFBIG\n"); break; + SAM("-EFBIG\n"); + break; } case -EPIPE: { - SAY("EPIPE\n"); break; + SAM("-EPIPE\n"); + break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); break; + SAM("-EMSGSIZE\n"); + break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + SAM("-ENOSPC\n"); + break; } default: { - SAY("0x%08X\n", rc); break; + SAM("unknown error: 0x%08X\n", rc); + break; } } } @@ -116,74 +123,95 @@ return; } /*---------------------------------------------------------------------------*/ if (purb->status) { - if (-ESHUTDOWN == purb->status) { - JOT(16, "immediate return because -ESHUTDOWN=purb->status\n"); + if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) { + JOM(16, "urb status -ESHUTDOWN or -ENOENT\n"); return; } - SAY("ERROR: non-zero urb status:\n"); + SAM("ERROR: non-zero urb status:\n"); switch (purb->status) { case -EINPROGRESS: { - SAY("-EINPROGRESS\n"); break; + SAM("-EINPROGRESS\n"); + break; } case -ENOSR: { - SAY("-ENOSR\n"); break; + SAM("-ENOSR\n"); + break; } case -EPIPE: { - SAY("-EPIPE\n"); break; + SAM("-EPIPE\n"); + break; } case -EOVERFLOW: { - SAY("-EOVERFLOW\n"); break; + SAM("-EOVERFLOW\n"); + break; } case -EPROTO: { - SAY("-EPROTO\n"); break; + SAM("-EPROTO\n"); + break; } case -EILSEQ: { - SAY("-EILSEQ\n"); break; + SAM("-EILSEQ\n"); + break; } case -ETIMEDOUT: { - SAY("-ETIMEDOUT\n"); break; + SAM("-ETIMEDOUT\n"); + break; } case -EMSGSIZE: { - SAY("-EMSGSIZE\n"); break; + SAM("-EMSGSIZE\n"); + break; } case -EOPNOTSUPP: { - SAY("-EOPNOTSUPP\n"); break; + SAM("-EOPNOTSUPP\n"); + break; } case -EPFNOSUPPORT: { - SAY("-EPFNOSUPPORT\n"); break; + SAM("-EPFNOSUPPORT\n"); + break; } case -EAFNOSUPPORT: { - SAY("-EAFNOSUPPORT\n"); break; + SAM("-EAFNOSUPPORT\n"); + break; } case -EADDRINUSE: { - SAY("-EADDRINUSE\n"); break; + SAM("-EADDRINUSE\n"); + break; } case -EADDRNOTAVAIL: { - SAY("-EADDRNOTAVAIL\n"); break; + SAM("-EADDRNOTAVAIL\n"); + break; } case -ENOBUFS: { - SAY("-ENOBUFS\n"); break; + SAM("-ENOBUFS\n"); + break; } case -EISCONN: { - SAY("-EISCONN\n"); break; + SAM("-EISCONN\n"); + break; } case -ENOTCONN: { - SAY("-ENOTCONN\n"); break; + SAM("-ENOTCONN\n"); + break; } case -ESHUTDOWN: { - SAY("-ESHUTDOWN\n"); break; + SAM("-ESHUTDOWN\n"); + break; } case -ENOENT: { - SAY("-ENOENT\n"); break; + SAM("-ENOENT\n"); + break; } case -ECONNRESET: { - SAY("-ECONNRESET\n"); break; + SAM("-ECONNRESET\n"); + break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + SAM("ENOSPC\n"); + break; } default: { - SAY("unknown error code 0x%08X\n", purb->status); break; + SAM("unknown error code 0x%08X\n", purb->status); + break; } } /*---------------------------------------------------------------------------*/ @@ -196,35 +224,43 @@ if (purb->status) { if (peasycap->audio_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAY("ERROR: while %i=audio_idle, usb_submit_urb() " + SAM("ERROR: while %i=audio_idle, usb_submit_urb() " "failed with rc:\n", peasycap->audio_idle); switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); break; + SAM("-ENOMEM\n"); + break; } case -ENODEV: { - SAY("ENODEV\n"); break; + SAM("-ENODEV\n"); + break; } case -ENXIO: { - SAY("ENXIO\n"); break; + SAM("-ENXIO\n"); + break; } case -EINVAL: { - SAY("EINVAL\n"); break; + SAM("-EINVAL\n"); + break; } case -EAGAIN: { - SAY("EAGAIN\n"); break; + SAM("-EAGAIN\n"); + break; } case -EFBIG: { - SAY("EFBIG\n"); break; + SAM("-EFBIG\n"); + break; } case -EPIPE: { - SAY("EPIPE\n"); break; + SAM("-EPIPE\n"); + break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); break; + SAM("-EMSGSIZE\n"); + break; } default: { - SAY("0x%08X\n", rc); break; + SAM("0x%08X\n", rc); break; } } } @@ -243,72 +279,80 @@ oldaudio = peasycap->oldaudio; for (i = 0; i < purb->number_of_packets; i++) { switch (purb->iso_frame_desc[i].status) { case 0: { - strcpy(&errbuf[0], "OK"); break; + break; } case -ENOENT: { - strcpy(&errbuf[0], "-ENOENT"); break; + SAM("-ENOENT\n"); + break; } case -EINPROGRESS: { - strcpy(&errbuf[0], "-EINPROGRESS"); break; + SAM("-EINPROGRESS\n"); + break; } case -EPROTO: { - strcpy(&errbuf[0], "-EPROTO"); break; + SAM("-EPROTO\n"); + break; } case -EILSEQ: { - strcpy(&errbuf[0], "-EILSEQ"); break; + SAM("-EILSEQ\n"); + break; } case -ETIME: { - strcpy(&errbuf[0], "-ETIME"); break; + SAM("-ETIME\n"); + break; } case -ETIMEDOUT: { - strcpy(&errbuf[0], "-ETIMEDOUT"); break; + SAM("-ETIMEDOUT\n"); + break; } case -EPIPE: { - strcpy(&errbuf[0], "-EPIPE"); break; + SAM("-EPIPE\n"); + break; } case -ECOMM: { - strcpy(&errbuf[0], "-ECOMM"); break; + SAM("-ECOMM\n"); + break; } case -ENOSR: { - strcpy(&errbuf[0], "-ENOSR"); break; + SAM("-ENOSR\n"); + break; } case -EOVERFLOW: { - strcpy(&errbuf[0], "-EOVERFLOW"); break; + SAM("-EOVERFLOW\n"); + break; } case -EREMOTEIO: { - strcpy(&errbuf[0], "-EREMOTEIO"); break; + SAM("-EREMOTEIO\n"); + break; } case -ENODEV: { - strcpy(&errbuf[0], "-ENODEV"); break; + SAM("-ENODEV\n"); + break; } case -EXDEV: { - strcpy(&errbuf[0], "-EXDEV"); break; + SAM("-EXDEV\n"); + break; } case -EINVAL: { - strcpy(&errbuf[0], "-EINVAL"); break; + SAM("-EINVAL\n"); + break; } case -ECONNRESET: { - strcpy(&errbuf[0], "-ECONNRESET"); break; + SAM("-ECONNRESET\n"); + break; } case -ENOSPC: { - strcpy(&errbuf[0], "-ENOSPC"); break; + SAM("-ENOSPC\n"); + break; } case -ESHUTDOWN: { - strcpy(&errbuf[0], "-ESHUTDOWN"); break; + SAM("-ESHUTDOWN\n"); + break; } default: { - strcpy(&errbuf[0], "UNKNOWN"); break; - } + SAM("unknown error:0x%08X\n", purb->iso_frame_desc[i].status); + break; } - if ((!purb->iso_frame_desc[i].status) && 0) { - JOT(16, "frame[%2i]: %i=status{=%16s} " \ - "%5i=actual " \ - "%5i=length " \ - "%3i=offset\n", \ - i, purb->iso_frame_desc[i].status, &errbuf[0], - purb->iso_frame_desc[i].actual_length, - purb->iso_frame_desc[i].length, - purb->iso_frame_desc[i].offset); } if (!purb->iso_frame_desc[i].status) { more = purb->iso_frame_desc[i].actual_length; @@ -319,11 +363,12 @@ for (i = 0; i < purb->number_of_packets; i++) { #endif if (!more) - mt++; + peasycap->audio_mt++; else { - if (mt) { - JOT(16, "%4i empty audio urb frames\n", mt); - mt = 0; + if (peasycap->audio_mt) { + JOM(16, "%4i empty audio urb frames\n", \ + peasycap->audio_mt); + peasycap->audio_mt = 0; } p1 = (__u8 *)(purb->transfer_buffer + \ @@ -340,13 +385,13 @@ for (i = 0; i < purb->number_of_packets; i++) { /*---------------------------------------------------------------------------*/ while (more) { if (0 > more) { - SAY("easysnd_complete: MISTAKE: " \ + SAM("easysnd_complete: MISTAKE: " \ "more is negative\n"); return; } if (peasycap->audio_buffer_page_many <= \ peasycap->audio_fill) { - SAY("ERROR: bad " \ + SAM("ERROR: bad " \ "peasycap->audio_fill\n"); return; } @@ -355,7 +400,7 @@ for (i = 0; i < purb->number_of_packets; i++) { [peasycap->audio_fill]; if (PAGE_SIZE < (paudio_buffer->pto - \ paudio_buffer->pgo)) { - SAY("ERROR: bad paudio_buffer->pto\n"); + SAM("ERROR: bad paudio_buffer->pto\n"); return; } if (PAGE_SIZE == (paudio_buffer->pto - \ @@ -374,7 +419,7 @@ for (i = 0; i < purb->number_of_packets; i++) { peasycap->audio_fill) peasycap->audio_fill = 0; - JOT(12, "bumped peasycap->" \ + JOM(12, "bumped peasycap->" \ "audio_fill to %i\n", \ peasycap->audio_fill); @@ -387,7 +432,7 @@ for (i = 0; i < purb->number_of_packets; i++) { if (!(peasycap->audio_fill % \ peasycap->\ audio_pages_per_fragment)) { - JOT(12, "wakeup call on wq_" \ + JOM(12, "wakeup call on wq_" \ "audio, %i=frag reading %i" \ "=fragment fill\n", \ (peasycap->audio_read / \ @@ -414,7 +459,7 @@ for (i = 0; i < purb->number_of_packets; i++) { } else { #if defined(UPSAMPLE) if (much % 16) - JOT(8, "MISTAKE? much" \ + JOM(8, "MISTAKE? much" \ " is not divisible by 16\n"); if (much > (16 * \ more)) @@ -468,7 +513,7 @@ for (i = 0; i < purb->number_of_packets; i++) { } } } else { - JOT(12, "discarding audio samples because " \ + JOM(12, "discarding audio samples because " \ "%i=purb->iso_frame_desc[i].status\n", \ purb->iso_frame_desc[i].status); } @@ -486,38 +531,50 @@ peasycap->oldaudio = oldaudio; if (peasycap->audio_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAY("ERROR: while %i=audio_idle, usb_submit_urb() failed " \ + if (-ENODEV != rc) { + SAM("ERROR: while %i=audio_idle, " \ + "usb_submit_urb() failed " \ "with rc:\n", peasycap->audio_idle); + } switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); break; + SAM("-ENOMEM\n"); + break; } case -ENODEV: { - SAY("ENODEV\n"); break; + break; } case -ENXIO: { - SAY("ENXIO\n"); break; + SAM("-ENXIO\n"); + break; } case -EINVAL: { - SAY("EINVAL\n"); break; + SAM("-EINVAL\n"); + break; } case -EAGAIN: { - SAY("EAGAIN\n"); break; + SAM("-EAGAIN\n"); + break; } case -EFBIG: { - SAY("EFBIG\n"); break; + SAM("-EFBIG\n"); + break; } case -EPIPE: { - SAY("EPIPE\n"); break; + SAM("-EPIPE\n"); + break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); break; + SAM("-EMSGSIZE\n"); + break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + SAM("-ENOSPC\n"); + break; } default: { - SAY("0x%08X\n", rc); break; + SAM("unknown error: 0x%08X\n", rc); + break; } } } @@ -529,8 +586,7 @@ return; /* * THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO * STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT - * HAVE AN IOCTL INTERFACE. THE VIDEO URBS, BY CONTRAST, MUST BE SUBMITTED - * MUCH LATER: SEE COMMENTS IN FILE easycap_main.c. + * HAVE AN IOCTL INTERFACE. */ /*---------------------------------------------------------------------------*/ int @@ -540,7 +596,7 @@ struct usb_interface *pusb_interface; struct easycap *peasycap; int subminor, rc; -JOT(4, "begins.\n"); +JOT(4, "begins\n"); subminor = iminor(inode); @@ -561,56 +617,54 @@ file->private_data = peasycap; /*---------------------------------------------------------------------------*/ /* - * INITIALIZATION. + * INITIALIZATION */ /*---------------------------------------------------------------------------*/ -JOT(4, "starting initialization\n"); +JOM(4, "starting initialization\n"); if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; -} else { - JOT(16, "0x%08lX=peasycap->pusb_device\n", \ - (long int)peasycap->pusb_device); } +JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); rc = audio_setup(peasycap); if (0 <= rc) - JOT(8, "audio_setup() returned %i\n", rc); + JOM(8, "audio_setup() returned %i\n", rc); else - JOT(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc); + JOM(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc); if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device has become NULL\n"); + SAM("ERROR: peasycap->pusb_device has become NULL\n"); return -EFAULT; } rc = adjust_volume(peasycap, -8192); if (0 != rc) { - SAY("ERROR: adjust_volume(default) returned %i\n", rc); + SAM("ERROR: adjust_volume(default) returned %i\n", rc); return -EFAULT; } /*---------------------------------------------------------------------------*/ if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device has become NULL\n"); + SAM("ERROR: peasycap->pusb_device has become NULL\n"); return -EFAULT; } rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \ peasycap->audio_altsetting_on); -JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \ +JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \ peasycap->audio_altsetting_on, rc); if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device has become NULL\n"); + SAM("ERROR: peasycap->pusb_device has become NULL\n"); return -EFAULT; } rc = wakeup_device(peasycap->pusb_device); if (0 == rc) - JOT(8, "wakeup_device() returned %i\n", rc); + JOM(8, "wakeup_device() returned %i\n", rc); else - JOT(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc); + JOM(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc); if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device has become NULL\n"); + SAM("ERROR: peasycap->pusb_device has become NULL\n"); return -EFAULT; } submit_audio_urbs(peasycap); @@ -619,7 +673,7 @@ peasycap->audio_idle = 0; peasycap->timeval1.tv_sec = 0; peasycap->timeval1.tv_usec = 0; -JOT(4, "finished initialization\n"); +JOM(4, "finished initialization\n"); return 0; } /*****************************************************************************/ @@ -636,10 +690,10 @@ if (NULL == peasycap) { return -EFAULT; } if (0 != kill_audio_urbs(peasycap)) { - SAY("ERROR: kill_audio_urbs() failed\n"); + SAM("ERROR: kill_audio_urbs() failed\n"); return -EFAULT; } -JOT(4, "ending successfully\n"); +JOM(4, "ending successfully\n"); return 0; } /*****************************************************************************/ @@ -648,8 +702,7 @@ easysnd_read(struct file *file, char __user *puserspacebuffer, \ size_t kount, loff_t *poff) { struct timeval timeval; -static struct timeval timeval1; -static long long int audio_bytes, above, below, mean; +long long int above, below, mean; struct signed_div_result sdr; unsigned char *p0; long int kount1, more, rc, l0, lm; @@ -679,15 +732,15 @@ if (NULL == peasycap) { /*---------------------------------------------------------------------------*/ if ((0 > peasycap->audio_read) || \ (peasycap->audio_buffer_page_many <= peasycap->audio_read)) { - SAY("ERROR: peasycap->audio_read out of range\n"); + SAM("ERROR: peasycap->audio_read out of range\n"); return -EFAULT; } pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read]; if ((struct data_buffer *)NULL == pdata_buffer) { - SAY("ERROR: pdata_buffer is NULL\n"); + SAM("ERROR: pdata_buffer is NULL\n"); return -EFAULT; } -JOT(12, "before wait, %i=frag read %i=frag fill\n", \ +JOM(12, "before wait, %i=frag read %i=frag fill\n", \ (peasycap->audio_read / peasycap->audio_pages_per_fragment), \ (peasycap->audio_fill / peasycap->audio_pages_per_fragment)); fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment); @@ -695,7 +748,7 @@ while ((fragment == (peasycap->audio_fill / \ peasycap->audio_pages_per_fragment)) || \ (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) { if (file->f_flags & O_NONBLOCK) { - JOT(16, "returning -EAGAIN as instructed\n"); + JOM(16, "returning -EAGAIN as instructed\n"); return -EAGAIN; } rc = wait_event_interruptible(peasycap->wq_audio, \ @@ -704,50 +757,50 @@ while ((fragment == (peasycap->audio_fill / \ peasycap->audio_pages_per_fragment)) && \ (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))))); if (0 != rc) { - SAY("aborted by signal\n"); + SAM("aborted by signal\n"); return -ERESTARTSYS; } if (peasycap->audio_eof) { - JOT(8, "returning 0 because %i=audio_eof\n", \ + JOM(8, "returning 0 because %i=audio_eof\n", \ peasycap->audio_eof); kill_audio_urbs(peasycap); msleep(500); return 0; } if (peasycap->audio_idle) { - JOT(16, "returning 0 because %i=audio_idle\n", \ + JOM(16, "returning 0 because %i=audio_idle\n", \ peasycap->audio_idle); return 0; } if (!peasycap->audio_isoc_streaming) { - JOT(16, "returning 0 because audio urbs not streaming\n"); + JOM(16, "returning 0 because audio urbs not streaming\n"); return 0; } } -JOT(12, "after wait, %i=frag read %i=frag fill\n", \ +JOM(12, "after wait, %i=frag read %i=frag fill\n", \ (peasycap->audio_read / peasycap->audio_pages_per_fragment), \ (peasycap->audio_fill / peasycap->audio_pages_per_fragment)); szret = (size_t)0; while (fragment == (peasycap->audio_read / \ peasycap->audio_pages_per_fragment)) { if (NULL == pdata_buffer->pgo) { - SAY("ERROR: pdata_buffer->pgo is NULL\n"); + SAM("ERROR: pdata_buffer->pgo is NULL\n"); return -EFAULT; } if (NULL == pdata_buffer->pto) { - SAY("ERROR: pdata_buffer->pto is NULL\n"); + SAM("ERROR: pdata_buffer->pto is NULL\n"); return -EFAULT; } kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo); if (0 > kount1) { - SAY("easysnd_read: MISTAKE: kount1 is negative\n"); + SAM("easysnd_read: MISTAKE: kount1 is negative\n"); return -ERESTARTSYS; } if (!kount1) { (peasycap->audio_read)++; if (peasycap->audio_buffer_page_many <= peasycap->audio_read) peasycap->audio_read = 0; - JOT(12, "bumped peasycap->audio_read to %i\n", \ + JOM(12, "bumped peasycap->audio_read to %i\n", \ peasycap->audio_read); if (fragment != (peasycap->audio_read / \ @@ -757,30 +810,30 @@ while (fragment == (peasycap->audio_read / \ if ((0 > peasycap->audio_read) || \ (peasycap->audio_buffer_page_many <= \ peasycap->audio_read)) { - SAY("ERROR: peasycap->audio_read out of range\n"); + SAM("ERROR: peasycap->audio_read out of range\n"); return -EFAULT; } pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read]; if ((struct data_buffer *)NULL == pdata_buffer) { - SAY("ERROR: pdata_buffer is NULL\n"); + SAM("ERROR: pdata_buffer is NULL\n"); return -EFAULT; } if (NULL == pdata_buffer->pgo) { - SAY("ERROR: pdata_buffer->pgo is NULL\n"); + SAM("ERROR: pdata_buffer->pgo is NULL\n"); return -EFAULT; } if (NULL == pdata_buffer->pto) { - SAY("ERROR: pdata_buffer->pto is NULL\n"); + SAM("ERROR: pdata_buffer->pto is NULL\n"); return -EFAULT; } kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo); } - JOT(12, "ready to send %li bytes\n", (long int) kount1); - JOT(12, "still to send %li bytes\n", (long int) kount); + JOM(12, "ready to send %li bytes\n", (long int) kount1); + JOM(12, "still to send %li bytes\n", (long int) kount); more = kount1; if (more > kount) more = kount; - JOT(12, "agreed to send %li bytes from page %i\n", \ + JOM(12, "agreed to send %li bytes from page %i\n", \ more, peasycap->audio_read); if (!more) break; @@ -798,7 +851,7 @@ while (fragment == (peasycap->audio_read / \ /*---------------------------------------------------------------------------*/ rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more); if (0 != rc) { - SAY("ERROR: copy_to_user() returned %li\n", rc); + SAM("ERROR: copy_to_user() returned %li\n", rc); return -EFAULT; } *poff += (loff_t)more; @@ -807,11 +860,11 @@ while (fragment == (peasycap->audio_read / \ puserspacebuffer += more; kount -= (size_t)more; } -JOT(12, "after read, %i=frag read %i=frag fill\n", \ +JOM(12, "after read, %i=frag read %i=frag fill\n", \ (peasycap->audio_read / peasycap->audio_pages_per_fragment), \ (peasycap->audio_fill / peasycap->audio_pages_per_fragment)); if (kount < 0) { - SAY("MISTAKE: %li=kount %li=szret\n", \ + SAM("MISTAKE: %li=kount %li=szret\n", \ (long int)kount, (long int)szret); } /*---------------------------------------------------------------------------*/ @@ -827,11 +880,11 @@ if (peasycap->audio_sample) { mean = peasycap->audio_niveau; sdr = signed_div(mean, peasycap->audio_sample); - JOT(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \ + JOM(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n", \ sdr.quotient, above, peasycap->audio_sample); sdr = signed_div(above, 32768); - JOT(8, "audio dynamic range is roughly %lli\n", sdr.quotient); + JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient); } /*---------------------------------------------------------------------------*/ /* @@ -840,26 +893,27 @@ if (peasycap->audio_sample) { /*---------------------------------------------------------------------------*/ do_gettimeofday(&timeval); if (!peasycap->timeval1.tv_sec) { - audio_bytes = 0; - timeval1 = timeval; - peasycap->timeval1 = timeval1; + peasycap->audio_bytes = 0; + peasycap->timeval3 = timeval; + peasycap->timeval1 = peasycap->timeval3; sdr.quotient = 192000; } else { - audio_bytes += (long long int) szret; + peasycap->audio_bytes += (long long int) szret; below = ((long long int)(1000000)) * \ - ((long long int)(timeval.tv_sec - timeval1.tv_sec)) + \ - (long long int)(timeval.tv_usec - timeval1.tv_usec); - above = 1000000 * ((long long int) audio_bytes); + ((long long int)(timeval.tv_sec - \ + peasycap->timeval3.tv_sec)) + \ + (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec); + above = 1000000 * ((long long int) peasycap->audio_bytes); if (below) sdr = signed_div(above, below); else sdr.quotient = 192000; } -JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient); +JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient); peasycap->dnbydt = sdr.quotient; -JOT(8, "returning %li\n", (long int)szret); +JOM(8, "returning %li\n", (long int)szret); return szret; } /*****************************************************************************/ @@ -874,27 +928,31 @@ submit_audio_urbs(struct easycap *peasycap) struct data_urb *pdata_urb; struct urb *purb; struct list_head *plist_head; -int j, isbad, m, rc; +int j, isbad, nospc, m, rc; int isbuf; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if ((struct list_head *)NULL == peasycap->purb_audio_head) { - SAY("ERROR: peasycap->urb_audio_head uninitialized\n"); + SAM("ERROR: peasycap->urb_audio_head uninitialized\n"); return -EFAULT; } if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); + SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } if (!peasycap->audio_isoc_streaming) { - JOT(4, "initial submission of all audio urbs\n"); + JOM(4, "initial submission of all audio urbs\n"); rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \ peasycap->audio_altsetting_on); - JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", \ + JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", \ peasycap->audio_interface, \ peasycap->audio_altsetting_on, rc); - isbad = 0; m = 0; + isbad = 0; nospc = 0; m = 0; list_for_each(plist_head, (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); if (NULL != pdata_urb) { @@ -931,39 +989,49 @@ if (!peasycap->audio_isoc_streaming) { rc = usb_submit_urb(purb, GFP_KERNEL); if (0 != rc) { isbad++; - SAY("ERROR: usb_submit_urb() failed" \ + SAM("ERROR: usb_submit_urb() failed" \ " for urb with rc:\n"); switch (rc) { case -ENOMEM: { - SAY("ENOMEM\n"); break; + SAM("-ENOMEM\n"); + break; } case -ENODEV: { - SAY("ENODEV\n"); break; + SAM("-ENODEV\n"); + break; } case -ENXIO: { - SAY("ENXIO\n"); break; + SAM("-ENXIO\n"); + break; } case -EINVAL: { - SAY("EINVAL\n"); break; + SAM("-EINVAL\n"); + break; } case -EAGAIN: { - SAY("EAGAIN\n"); break; + SAM("-EAGAIN\n"); + break; } case -EFBIG: { - SAY("EFBIG\n"); break; + SAM("-EFBIG\n"); + break; } case -EPIPE: { - SAY("EPIPE\n"); break; + SAM("-EPIPE\n"); + break; } case -EMSGSIZE: { - SAY("EMSGSIZE\n"); break; + SAM("-EMSGSIZE\n"); + break; } case -ENOSPC: { - SAY("ENOSPC\n"); break; + nospc++; + break; } default: { - SAY("unknown error code %i\n",\ - rc); break; + SAM("unknown error code %i\n",\ + rc); + break; } } } else { @@ -976,8 +1044,13 @@ if (!peasycap->audio_isoc_streaming) { isbad++; } } + if (nospc) { + SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); + SAM("..... possibly inadequate USB bandwidth\n"); + peasycap->audio_eof = 1; + } if (isbad) { - JOT(4, "attempting cleanup instead of submitting\n"); + JOM(4, "attempting cleanup instead of submitting\n"); list_for_each(plist_head, (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, struct data_urb, \ list_head); @@ -990,10 +1063,10 @@ if (!peasycap->audio_isoc_streaming) { peasycap->audio_isoc_streaming = 0; } else { peasycap->audio_isoc_streaming = 1; - JOT(4, "submitted %i audio urbs\n", m); + JOM(4, "submitted %i audio urbs\n", m); } } else - JOT(4, "already streaming audio urbs\n"); + JOM(4, "already streaming audio urbs\n"); return 0; } @@ -1010,10 +1083,14 @@ int m; struct list_head *plist_head; struct data_urb *pdata_urb; +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} if (peasycap->audio_isoc_streaming) { if ((struct list_head *)NULL != peasycap->purb_audio_head) { peasycap->audio_isoc_streaming = 0; - JOT(4, "killing audio urbs\n"); + JOM(4, "killing audio urbs\n"); m = 0; list_for_each(plist_head, (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, struct data_urb, @@ -1025,13 +1102,13 @@ if (peasycap->audio_isoc_streaming) { } } } - JOT(4, "%i audio urbs killed\n", m); + JOM(4, "%i audio urbs killed\n", m); } else { - SAY("ERROR: peasycap->purb_audio_head is NULL\n"); + SAM("ERROR: peasycap->purb_audio_head is NULL\n"); return -EFAULT; } } else { - JOT(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \ + JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \ peasycap->audio_isoc_streaming); } return 0; diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c index 700c73ec1c59..dd98b471d5b8 100644 --- a/drivers/staging/easycap/easycap_testcard.c +++ b/drivers/staging/easycap/easycap_testcard.c @@ -157,7 +157,7 @@ for (i1 = 0; i1 <= last; i1++) printf("%6i, ", i2); printf("%6i\n};\n", i2); } } -return(0); +return 0; } -----------------------------------------------------------------------------*/ int tones[2048] = { -- cgit v1.2.3 From f36bc37a48148f31f936557b811431b98dbfe347 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:00:35 +0000 Subject: staging/easycap: Improve hardware initialization Sometimes at startup the video urbs consistently and persistently deliver bad data, each video frame (not isoc frame) containing an excess of precisely two bytes. A brute-force cure implemented here is to repeatedly reinitialize the registers of the SAA7113H chip and the STK1160 USB bridge until good behaviour is obtained. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 47 +- drivers/staging/easycap/easycap_ioctl.c | 361 ++++++++++----- drivers/staging/easycap/easycap_low.c | 675 ++++++++++++++++----------- drivers/staging/easycap/easycap_main.c | 786 ++++++++++++++++++++++++++------ drivers/staging/easycap/easycap_sound.c | 20 +- 5 files changed, 1345 insertions(+), 544 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 11ceda7dde30..20e51ddec1e1 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -42,12 +42,19 @@ #if (!defined(EASYCAP_H)) #define EASYCAP_H +/*---------------------------------------------------------------------------*/ +/* + * THESE ARE NORMALLY DEFINED + */ +/*---------------------------------------------------------------------------*/ +#define PATIENCE 500 +#undef PREFER_NTSC +#define PERSEVERE /*---------------------------------------------------------------------------*/ /* * THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED: */ /*---------------------------------------------------------------------------*/ -#undef PREFER_NTSC #undef EASYCAP_TESTCARD #undef EASYCAP_TESTTONE #undef NOREADBACK @@ -122,7 +129,7 @@ #define USB_SKEL_MINOR_BASE 192 #define DONGLE_MANY 8 - +#define INPUT_MANY 6 /*---------------------------------------------------------------------------*/ /* * DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE @@ -146,6 +153,7 @@ #if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE) #error video_isoc_buffer[.] will not be big enough #endif +#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY /*---------------------------------------------------------------------------*/ /* * VIDEO BUFFERS @@ -238,6 +246,7 @@ struct list_head list_head; void *pgo; void *pto; __u16 kount; +__u16 input; }; /*---------------------------------------------------------------------------*/ struct data_urb { @@ -256,6 +265,22 @@ __u16 mask; char name[128]; struct v4l2_format v4l2_format; }; +struct inputset { +int input; +int input_ok; +int standard_offset; +int standard_offset_ok; +int format_offset; +int format_offset_ok; +int brightness; +int brightness_ok; +int contrast; +int contrast_ok; +int saturation; +int saturation_ok; +int hue; +int hue_ok; +}; /*---------------------------------------------------------------------------*/ /* * easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256 @@ -274,7 +299,7 @@ struct v4l2_device v4l2_device; #endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - +int status; unsigned int audio_pages_per_fragment; unsigned int audio_bytes_per_fragment; unsigned int audio_buffer_page_many; @@ -302,7 +327,9 @@ int input; int polled; int standard_offset; int format_offset; +struct inputset inputset[INPUT_MANY]; +bool ntsc; int fps; int usec; int tolerate; @@ -480,6 +507,8 @@ int redaub(struct easycap *, void *, void *, \ int, int, __u8, __u8, bool); void easycap_testcard(struct easycap *, int); int fillin_formats(void); +int reset(struct easycap *); +int newinput(struct easycap *, int); int adjust_standard(struct easycap *, v4l2_std_id); int adjust_format(struct easycap *, __u32, __u32, __u32, \ int, bool); @@ -517,11 +546,11 @@ int wakeup_device(struct usb_device *); int confirm_resolution(struct usb_device *); int confirm_stream(struct usb_device *); -int setup_stk(struct usb_device *); -int setup_saa(struct usb_device *); +int setup_stk(struct usb_device *, bool); +int setup_saa(struct usb_device *, bool); int setup_vt(struct usb_device *); -int check_stk(struct usb_device *); -int check_saa(struct usb_device *); +int check_stk(struct usb_device *, bool); +int check_saa(struct usb_device *, bool); int ready_saa(struct usb_device *); int merit_saa(struct usb_device *); int check_vt(struct usb_device *); @@ -539,10 +568,6 @@ int stop_100(struct usb_device *); int write_300(struct usb_device *); int read_vt(struct usb_device *, __u16); int write_vt(struct usb_device *, __u16, __u16); - -int set2to78(struct usb_device *); -int set2to93(struct usb_device *); - int regset(struct usb_device *, __u16, __u16); int regget(struct usb_device *, __u16, void *); int isdongle(struct easycap *); diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index d91d64ad6f68..0ed37c23c7ec 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -36,6 +36,7 @@ * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE * FOLLOWING: * peasycap->standard_offset + * peasycap->inputset[peasycap->input].standard_offset * peasycap->fps * peasycap->usec * peasycap->tolerate @@ -45,8 +46,9 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) { struct easycap_standard const *peasycap_standard; __u16 reg, set; -int ir, rc, need; +int ir, rc, need, k; unsigned int itwas, isnow; +bool resubmit; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -67,7 +69,7 @@ if (0xFFFF == peasycap_standard->mask) { (unsigned int)std_id); return -EINVAL; } -SAM("user requests standard: %s\n", \ +SAM("selected standard: %s\n", \ &(peasycap_standard->v4l2_standard.name[0])); if (peasycap->standard_offset == \ (int)(peasycap_standard - &easycap_standard[0])) { @@ -75,18 +77,43 @@ if (peasycap->standard_offset == \ return 0; } peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]); +for (k = 0; k < INPUT_MANY; k++) { + if (!peasycap->inputset[k].standard_offset_ok) { + peasycap->inputset[k].standard_offset = \ + peasycap->standard_offset; + } +} +if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { + peasycap->inputset[peasycap->input].standard_offset = \ + peasycap->standard_offset; + peasycap->inputset[peasycap->input].standard_offset_ok = 1; +} else + JOM(8, "%i=peasycap->input\n", peasycap->input); peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \ peasycap_standard->v4l2_standard.frameperiod.numerator; -if (!peasycap->fps) { - SAM("MISTAKE: frames-per-second is zero\n"); - return -EFAULT; +switch (peasycap->fps) { +case 30: { + peasycap->ntsc = true; + break; +} +case 25: { + peasycap->ntsc = false; + break; +} +default: { + SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps); + return -ENOENT; +} } JOM(8, "%i frames-per-second\n", peasycap->fps); peasycap->usec = 1000000 / (2 * peasycap->fps); peasycap->tolerate = 1000 * (25 / peasycap->fps); -kill_video_urbs(peasycap); - +if (peasycap->video_isoc_streaming) { + resubmit = true; + kill_video_urbs(peasycap); +} else + resubmit = false; /*--------------------------------------------------------------------------*/ /* * SAA7113H DATASHEET PAGE 44, TABLE 42 @@ -101,11 +128,6 @@ case NTSC_M_JP: { SAM("ERROR: cannot read SAA register 0x%02X\n", reg); else itwas = (unsigned int)ir; - - - set2to78(peasycap->pusb_device); - - rc = write_saa(peasycap->pusb_device, reg, set); if (0 != rc) SAM("ERROR: failed to set SAA register " \ @@ -118,9 +140,6 @@ case NTSC_M_JP: { else JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - - set2to78(peasycap->pusb_device); - } reg = 0x0B; set = 0x48; @@ -129,9 +148,6 @@ case NTSC_M_JP: { SAM("ERROR: cannot read SAA register 0x%02X\n", reg); else itwas = (unsigned int)ir; - - set2to78(peasycap->pusb_device); - rc = write_saa(peasycap->pusb_device, reg, set); if (0 != rc) SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X " \ @@ -144,9 +160,6 @@ case NTSC_M_JP: { else JOM(8, "SAA register 0x%02X changed " \ "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - - set2to78(peasycap->pusb_device); - } /*--------------------------------------------------------------------------*/ /* @@ -183,9 +196,6 @@ if (need) { SAM("ERROR: failed to read SAA register 0x%02X\n", reg); else itwas = (unsigned int)ir; - - set2to78(peasycap->pusb_device); - rc = write_saa(peasycap->pusb_device, reg, set); if (0 != write_saa(peasycap->pusb_device, reg, set)) { SAM("ERROR: failed to set SAA register " \ @@ -216,19 +226,18 @@ else { set = itwas | 0x40 ; else set = itwas & ~0x40 ; - -set2to78(peasycap->pusb_device); - -rc = write_saa(peasycap->pusb_device, reg, set); -if (0 != rc) - SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); -else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " \ - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); + rc = write_saa(peasycap->pusb_device, reg, set); + if (0 != rc) + SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \ + reg, set); + else { + isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); + if (0 > ir) + JOM(8, "SAA register 0x%02X changed to 0x%02X\n", \ + reg, isnow); + else + JOM(8, "SAA register 0x%02X changed " \ + "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } } /*--------------------------------------------------------------------------*/ @@ -247,19 +256,18 @@ else { set = itwas | 0x80 ; else set = itwas & ~0x80 ; - -set2to78(peasycap->pusb_device); - -rc = write_saa(peasycap->pusb_device, reg, set); -if (0 != rc) - SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set); -else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " \ - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); + rc = write_saa(peasycap->pusb_device, reg, set); + if (0 != rc) + SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \ + reg, set); + else { + isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); + if (0 > ir) + JOM(8, "SAA register 0x%02X changed to 0x%02X\n", \ + reg, isnow); + else + JOM(8, "SAA register 0x%02X changed " \ + "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } } /*--------------------------------------------------------------------------*/ @@ -276,9 +284,6 @@ if (0 > ir) set = 0x0A ; else set = 0x07 ; - - set2to78(peasycap->pusb_device); - if (0 != write_saa(peasycap->pusb_device, reg, set)) SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \ reg, set); @@ -291,18 +296,20 @@ if (0 > ir) JOM(8, "SAA register 0x%02X changed " "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } - if (0 != check_saa(peasycap->pusb_device)) - SAM("ERROR: check_saa() failed\n"); +if (true == resubmit) + submit_video_urbs(peasycap); return 0; } /*****************************************************************************/ /*--------------------------------------------------------------------------*/ /* - * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL DEPENDS ON THE - * CURRENT VALUE OF peasycap->standard_offset. + * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES + * A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED. + * * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN * THIS ROUTINE UPDATES THE FOLLOWING: * peasycap->format_offset + * peasycap->inputset[peasycap->input].format_offset * peasycap->pixelformat * peasycap->field * peasycap->height @@ -325,14 +332,19 @@ int adjust_format(struct easycap *peasycap, \ struct easycap_format *peasycap_format, *peasycap_best_format; __u16 mask; struct usb_device *p; -int miss, multiplier, best; +int miss, multiplier, best, k; char bf[5], *pc; __u32 uc; +bool resubmit; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +if (0 > peasycap->standard_offset) { + JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset); + return -EBUSY; +} p = peasycap->pusb_device; if ((struct usb_device *)NULL == p) { SAM("ERROR: peaycap->pusb_device is NULL\n"); @@ -422,6 +434,23 @@ peasycap->width = peasycap_format->v4l2_format.fmt.pix.width; peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat; peasycap->field = peasycap_format->v4l2_format.fmt.pix.field; peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]); + + +for (k = 0; k < INPUT_MANY; k++) { + if (!peasycap->inputset[k].format_offset_ok) { + peasycap->inputset[k].format_offset = \ + peasycap->format_offset; + } +} +if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { + peasycap->inputset[peasycap->input].format_offset = \ + peasycap->format_offset; + peasycap->inputset[peasycap->input].format_offset_ok = 1; +} else + JOM(8, "%i=peasycap->input\n", peasycap->input); + + + peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ; if (0x0100 & peasycap_format->mask) peasycap->byteswaporder = true; @@ -461,9 +490,11 @@ if (true == peasycap->offerfields) { } - -kill_video_urbs(peasycap); - +if (peasycap->video_isoc_streaming) { + resubmit = true; + kill_video_urbs(peasycap); +} else + resubmit = false; /*---------------------------------------------------------------------------*/ /* * PAL @@ -536,16 +567,15 @@ if (0 == (0x01 & peasycap_format->mask)) { } } /*---------------------------------------------------------------------------*/ - -check_stk(peasycap->pusb_device); - +if (true == resubmit) + submit_video_urbs(peasycap); return (int)(peasycap_best_format - &easycap_format[0]); } /*****************************************************************************/ int adjust_brightness(struct easycap *peasycap, int value) { unsigned int mood; -int i1; +int i1, k; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -561,11 +591,29 @@ while (0xFFFFFFFF != easycap_control[i1].id) { if ((easycap_control[i1].minimum > value) || \ (easycap_control[i1].maximum < value)) value = easycap_control[i1].default_value; + + if ((easycap_control[i1].minimum <= peasycap->brightness) && \ + (easycap_control[i1].maximum >= \ + peasycap->brightness)) { + if (peasycap->brightness == value) { + SAM("unchanged brightness at 0x%02X\n", \ + value); + return 0; + } + } peasycap->brightness = value; + for (k = 0; k < INPUT_MANY; k++) { + if (!peasycap->inputset[k].brightness_ok) + peasycap->inputset[k].brightness = \ + peasycap->brightness; + } + if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { + peasycap->inputset[peasycap->input].brightness = \ + peasycap->brightness; + peasycap->inputset[peasycap->input].brightness_ok = 1; + } else + JOM(8, "%i=peasycap->input\n", peasycap->input); mood = 0x00FF & (unsigned int)peasycap->brightness; - - set2to78(peasycap->pusb_device); - if (!write_saa(peasycap->pusb_device, 0x0A, mood)) { SAM("adjusting brightness to 0x%02X\n", mood); return 0; @@ -574,9 +622,6 @@ while (0xFFFFFFFF != easycap_control[i1].id) { "to 0x%02X\n", mood); return -ENOENT; } - - set2to78(peasycap->pusb_device); - break; } i1++; @@ -588,7 +633,7 @@ return -ENOENT; int adjust_contrast(struct easycap *peasycap, int value) { unsigned int mood; -int i1; +int i1, k; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -604,11 +649,31 @@ while (0xFFFFFFFF != easycap_control[i1].id) { if ((easycap_control[i1].minimum > value) || \ (easycap_control[i1].maximum < value)) value = easycap_control[i1].default_value; - peasycap->contrast = value; - mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); - set2to78(peasycap->pusb_device); + + if ((easycap_control[i1].minimum <= peasycap->contrast) && \ + (easycap_control[i1].maximum >= \ + peasycap->contrast)) { + if (peasycap->contrast == value) { + SAM("unchanged contrast at 0x%02X\n", value); + return 0; + } + } + peasycap->contrast = value; + for (k = 0; k < INPUT_MANY; k++) { + if (!peasycap->inputset[k].contrast_ok) { + peasycap->inputset[k].contrast = \ + peasycap->contrast; + } + } + if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { + peasycap->inputset[peasycap->input].contrast = \ + peasycap->contrast; + peasycap->inputset[peasycap->input].contrast_ok = 1; + } else + JOM(8, "%i=peasycap->input\n", peasycap->input); + mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); if (!write_saa(peasycap->pusb_device, 0x0B, mood)) { SAM("adjusting contrast to 0x%02X\n", mood); return 0; @@ -617,9 +682,6 @@ while (0xFFFFFFFF != easycap_control[i1].id) { "0x%02X\n", mood); return -ENOENT; } - - set2to78(peasycap->pusb_device); - break; } i1++; @@ -631,7 +693,7 @@ return -ENOENT; int adjust_saturation(struct easycap *peasycap, int value) { unsigned int mood; -int i1; +int i1, k; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -647,11 +709,31 @@ while (0xFFFFFFFF != easycap_control[i1].id) { if ((easycap_control[i1].minimum > value) || \ (easycap_control[i1].maximum < value)) value = easycap_control[i1].default_value; - peasycap->saturation = value; - mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); - set2to78(peasycap->pusb_device); + if ((easycap_control[i1].minimum <= peasycap->saturation) && \ + (easycap_control[i1].maximum >= \ + peasycap->saturation)) { + if (peasycap->saturation == value) { + SAM("unchanged saturation at 0x%02X\n", \ + value); + return 0; + } + } + peasycap->saturation = value; + for (k = 0; k < INPUT_MANY; k++) { + if (!peasycap->inputset[k].saturation_ok) { + peasycap->inputset[k].saturation = \ + peasycap->saturation; + } + } + if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { + peasycap->inputset[peasycap->input].saturation = \ + peasycap->saturation; + peasycap->inputset[peasycap->input].saturation_ok = 1; + } else + JOM(8, "%i=peasycap->input\n", peasycap->input); + mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); if (!write_saa(peasycap->pusb_device, 0x0C, mood)) { SAM("adjusting saturation to 0x%02X\n", mood); return 0; @@ -661,9 +743,6 @@ while (0xFFFFFFFF != easycap_control[i1].id) { return -ENOENT; } break; - - set2to78(peasycap->pusb_device); - } i1++; } @@ -674,7 +753,7 @@ return -ENOENT; int adjust_hue(struct easycap *peasycap, int value) { unsigned int mood; -int i1, i2; +int i1, i2, k; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -690,12 +769,28 @@ while (0xFFFFFFFF != easycap_control[i1].id) { if ((easycap_control[i1].minimum > value) || \ (easycap_control[i1].maximum < value)) value = easycap_control[i1].default_value; + + if ((easycap_control[i1].minimum <= peasycap->hue) && \ + (easycap_control[i1].maximum >= \ + peasycap->hue)) { + if (peasycap->hue == value) { + SAM("unchanged hue at 0x%02X\n", value); + return 0; + } + } peasycap->hue = value; + for (k = 0; k < INPUT_MANY; k++) { + if (!peasycap->inputset[k].hue_ok) + peasycap->inputset[k].hue = peasycap->hue; + } + if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { + peasycap->inputset[peasycap->input].hue = \ + peasycap->hue; + peasycap->inputset[peasycap->input].hue_ok = 1; + } else + JOM(8, "%i=peasycap->input\n", peasycap->input); i2 = peasycap->hue - 128; mood = 0x00FF & ((int) i2); - - set2to78(peasycap->pusb_device); - if (!write_saa(peasycap->pusb_device, 0x0D, mood)) { SAM("adjusting hue to 0x%02X\n", mood); return 0; @@ -703,9 +798,6 @@ while (0xFFFFFFFF != easycap_control[i1].id) { SAM("WARNING: failed to adjust hue to 0x%02X\n", mood); return -ENOENT; } - - set2to78(peasycap->pusb_device); - break; } i1++; @@ -1004,6 +1096,7 @@ case VIDIOC_G_INPUT: { case VIDIOC_S_INPUT: { __u32 index; + int rc; JOM(8, "VIDIOC_S_INPUT\n"); @@ -1017,14 +1110,18 @@ case VIDIOC_S_INPUT: break; } - if ((0 > index) || (5 < index)) { + if ((0 > index) || (INPUT_MANY <= index)) { JOM(8, "ERROR: bad requested input: %i\n", index); return -EINVAL; } - peasycap->input = (int)index; - - select_input(peasycap->pusb_device, peasycap->input, 9); + rc = newinput(peasycap, (int)index); + if (0 == rc) { + JOM(8, "newinput(.,%i) OK\n", (int)index); + } else { + SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc); + return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1351,6 +1448,8 @@ case VIDIOC_S_FMT: { v4l2_format.fmt.pix.field, \ try); if (0 > best_format) { + if (-EBUSY == best_format) + return -EBUSY; JOM(8, "WARNING: adjust_format() returned %i\n", best_format); return -ENOENT; } @@ -1472,6 +1571,12 @@ case VIDIOC_G_STD: { JOM(8, "VIDIOC_G_STD\n"); + if (0 > peasycap->standard_offset) { + JOM(8, "%i=peasycap->standard_offset\n", \ + peasycap->standard_offset); + return -EBUSY; + } + if (0 != copy_from_user(&std_id, (void __user *)arg, \ sizeof(v4l2_std_id))) return -EFAULT; @@ -1549,9 +1654,9 @@ case VIDIOC_QUERYBUF: { JOM(8, "VIDIOC_QUERYBUF\n"); if (peasycap->video_eof) { - JOM(8, "returning -1 because %i=video_eof\n", \ + JOM(8, "returning -EIO because %i=video_eof\n", \ peasycap->video_eof); - return -1; + return -EIO; } if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ @@ -1632,12 +1737,14 @@ case VIDIOC_DQBUF: struct signed_div_result sdr; long long int above, below, dnbydt, fudge, sll; unsigned long long int ull; - struct timeval timeval0; + struct timeval timeval8; struct timeval timeval1; #endif /*AUDIOTIME*/ struct timeval timeval, timeval2; int i, j; struct v4l2_buffer v4l2_buffer; + int rcdq; + __u16 input; JOM(8, "VIDIOC_DQBUF\n"); @@ -1668,8 +1775,14 @@ case VIDIOC_DQBUF: /*---------------------------------------------------------------------------*/ if (!peasycap->polled) { - if (-EIO == easycap_dqbuf(peasycap, 0)) - return -EIO; + do { + rcdq = easycap_dqbuf(peasycap, 0); + if (-EIO == rcdq) { + JOM(8, "returning -EIO because " \ + "dqbuf() returned -EIO\n"); + return -EIO; + } + } while (0 != rcdq); } else { if (peasycap->video_eof) return -EIO; @@ -1708,11 +1821,11 @@ case VIDIOC_DQBUF: #if defined(AUDIOTIME) if (!peasycap->timeval0.tv_sec) { - timeval0 = timeval; + timeval8 = timeval; timeval1 = timeval; timeval2 = timeval; dnbydt = 192000; - peasycap->timeval0 = timeval0; + peasycap->timeval0 = timeval8; } else { dnbydt = peasycap->dnbydt; timeval1 = peasycap->timeval1; @@ -1766,21 +1879,26 @@ case VIDIOC_DQBUF: JOM(8, "..... user is offered frame buffer %i\n", \ peasycap->frame_read); peasycap->frame_lock = 1; + + input = peasycap->frame_buffer[peasycap->frame_read][0].input; + if (0x08 & input) { + JOM(8, "user is offered frame buffer %i, input %i\n", \ + peasycap->frame_read, (0x07 & input)); + } else { + JOM(8, "user is offered frame buffer %i\n", \ + peasycap->frame_read); + } + peasycap->frame_lock = 1; + JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill); if (peasycap->frame_read == peasycap->frame_fill) { if (peasycap->frame_lock) { - JOM(8, "ERROR: filling frame buffer " \ + JOM(8, "WORRY: filling frame buffer " \ "while offered to user\n"); } } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/*---------------------------------------------------------------------------*/ -/* - * AUDIO URBS HAVE ALREADY BEEN SUBMITTED WHEN THIS COMMAND IS RECEIVED; - * VIDEO URBS HAVE NOT. - */ -/*---------------------------------------------------------------------------*/ case VIDIOC_STREAMON: { int i; @@ -1839,6 +1957,20 @@ case VIDIOC_G_PARM: { v4l2_streamparm.parm.capture.capturemode = 0; v4l2_streamparm.parm.capture.timeperframe.numerator = 1; v4l2_streamparm.parm.capture.timeperframe.denominator = 30; + + if (peasycap->fps) { + v4l2_streamparm.parm.capture.timeperframe.\ + denominator = peasycap->fps; + } else { + if (true == peasycap->ntsc) { + v4l2_streamparm.parm.capture.timeperframe.\ + denominator = 30; + } else { + v4l2_streamparm.parm.capture.timeperframe.\ + denominator = 25; + } + } + v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many; v4l2_streamparm.parm.capture.extendedmode = 0; if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \ @@ -2095,6 +2227,15 @@ case SNDCTL_DSP_GETISPACE: { return -EFAULT; break; } +case 0x00005401: +case 0x00005402: +case 0x00005403: +case 0x00005404: +case 0x00005405: +case 0x00005406: { + JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd); + return -ENOIOCTLCMD; +} default: { JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd); return -ENOIOCTLCMD; diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index a3be9c1e5a69..4badef263e9e 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -42,121 +42,205 @@ #include "easycap.h" /*--------------------------------------------------------------------------*/ -const struct stk1160config { int reg; int set; } stk1160config[256] = { - {0x000, 0x0098}, - {0x002, 0x0093}, - - {0x001, 0x0003}, - {0x003, 0x0080}, - {0x00D, 0x0000}, - {0x00F, 0x0002}, - {0x018, 0x0010}, - {0x019, 0x0000}, - {0x01A, 0x0014}, - {0x01B, 0x000E}, - {0x01C, 0x0046}, - - {0x100, 0x0033}, - {0x103, 0x0000}, - {0x104, 0x0000}, - {0x105, 0x0000}, - {0x106, 0x0000}, - -#if defined(PREFER_NTSC) - - {0x110, 0x0014}, - {0x111, 0x0000}, - {0x112, 0x0003}, - {0x113, 0x0000}, - {0x114, 0x0514}, - {0x115, 0x0005}, - {0x116, 0x00F3}, - {0x117, 0x0000}, - -#else /* ! PREFER_NTSC*/ - - {0x110, 0x0014}, - {0x111, 0x0000}, - {0x112, 0x0020}, - {0x113, 0x0000}, - {0x114, 0x0514}, - {0x115, 0x0005}, - {0x116, 0x0110}, - {0x117, 0x0001}, - -#endif /* ! PREFER_NTSC*/ - - {0x202, 0x000F}, - {0x203, 0x004A}, - {0x2FF, 0x0000}, -/*---------------------------------------------------------------------------*/ - {0xFFF, 0xFFFF} - }; +const struct stk1160config { int reg; int set; } stk1160configPAL[256] = { + {0x000, 0x0098}, + {0x002, 0x0093}, + + {0x001, 0x0003}, + {0x003, 0x0080}, + {0x00D, 0x0000}, + {0x00F, 0x0002}, + {0x018, 0x0010}, + {0x019, 0x0000}, + {0x01A, 0x0014}, + {0x01B, 0x000E}, + {0x01C, 0x0046}, + + {0x100, 0x0033}, + {0x103, 0x0000}, + {0x104, 0x0000}, + {0x105, 0x0000}, + {0x106, 0x0000}, + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* + * RESOLUTION 640x480 +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + {0x110, 0x0008}, + {0x111, 0x0000}, + {0x112, 0x0020}, + {0x113, 0x0000}, + {0x114, 0x0508}, + {0x115, 0x0005}, + {0x116, 0x0110}, + {0x117, 0x0001}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + {0x202, 0x000F}, + {0x203, 0x004A}, + {0x2FF, 0x0000}, + + {0xFFF, 0xFFFF} +}; /*--------------------------------------------------------------------------*/ -const struct saa7113config { int reg; int set; } saa7113config[256] = { - {0x01, 0x08}, - {0x02, 0x80}, - {0x03, 0x33}, - {0x04, 0x00}, - {0x05, 0x00}, - {0x06, 0xE9}, - {0x07, 0x0D}, -#if defined(PREFER_NTSC) - {0x08, 0x78}, -#else - {0x08, 0x38}, -#endif /* ! PREFER_NTSC*/ - {0x09, 0x00}, - {0x0A, SAA_0A_DEFAULT}, - {0x0B, SAA_0B_DEFAULT}, - {0x0C, SAA_0C_DEFAULT}, - {0x0D, SAA_0D_DEFAULT}, - {0x0E, 0x01}, - {0x0F, 0x36}, - {0x10, 0x00}, - {0x11, 0x0C}, - {0x12, 0xE7}, - {0x13, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, -#if defined(PREFER_NTSC) - {0x40, 0x82}, +const struct stk1160config stk1160configNTSC[256] = { + {0x000, 0x0098}, + {0x002, 0x0093}, + + {0x001, 0x0003}, + {0x003, 0x0080}, + {0x00D, 0x0000}, + {0x00F, 0x0002}, + {0x018, 0x0010}, + {0x019, 0x0000}, + {0x01A, 0x0014}, + {0x01B, 0x000E}, + {0x01C, 0x0046}, + + {0x100, 0x0033}, + {0x103, 0x0000}, + {0x104, 0x0000}, + {0x105, 0x0000}, + {0x106, 0x0000}, + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* + * RESOLUTION 640x480 +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + {0x110, 0x0008}, + {0x111, 0x0000}, + {0x112, 0x0003}, + {0x113, 0x0000}, + {0x114, 0x0508}, + {0x115, 0x0005}, + {0x116, 0x00F3}, + {0x117, 0x0000}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + {0x202, 0x000F}, + {0x203, 0x004A}, + {0x2FF, 0x0000}, + + {0xFFF, 0xFFFF} +}; +/*--------------------------------------------------------------------------*/ +const struct saa7113config { int reg; int set; } saa7113configPAL[256] = { + {0x01, 0x08}, +#if defined(ANTIALIAS) + {0x02, 0xC0}, #else - {0x40, 0x02}, -#endif /* ! PREFER_NTSC*/ - {0x41, 0xFF}, - {0x42, 0xFF}, - {0x43, 0xFF}, - {0x44, 0xFF}, - {0x45, 0xFF}, - {0x46, 0xFF}, - {0x47, 0xFF}, - {0x48, 0xFF}, - {0x49, 0xFF}, - {0x4A, 0xFF}, - {0x4B, 0xFF}, - {0x4C, 0xFF}, - {0x4D, 0xFF}, - {0x4E, 0xFF}, - {0x4F, 0xFF}, - {0x50, 0xFF}, - {0x51, 0xFF}, - {0x52, 0xFF}, - {0x53, 0xFF}, - {0x54, 0xFF}, - {0x55, 0xFF}, - {0x56, 0xFF}, - {0x57, 0xFF}, - {0x58, 0x40}, - {0x59, 0x54}, -#if defined(PREFER_NTSC) - {0x5A, 0x0A}, + {0x02, 0x80}, +#endif /*ANTIALIAS*/ + {0x03, 0x33}, + {0x04, 0x00}, + {0x05, 0x00}, + {0x06, 0xE9}, + {0x07, 0x0D}, + {0x08, 0x38}, + {0x09, 0x00}, + {0x0A, SAA_0A_DEFAULT}, + {0x0B, SAA_0B_DEFAULT}, + {0x0C, SAA_0C_DEFAULT}, + {0x0D, SAA_0D_DEFAULT}, + {0x0E, 0x01}, + {0x0F, 0x36}, + {0x10, 0x00}, + {0x11, 0x0C}, + {0x12, 0xE7}, + {0x13, 0x00}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x40, 0x02}, + {0x41, 0xFF}, + {0x42, 0xFF}, + {0x43, 0xFF}, + {0x44, 0xFF}, + {0x45, 0xFF}, + {0x46, 0xFF}, + {0x47, 0xFF}, + {0x48, 0xFF}, + {0x49, 0xFF}, + {0x4A, 0xFF}, + {0x4B, 0xFF}, + {0x4C, 0xFF}, + {0x4D, 0xFF}, + {0x4E, 0xFF}, + {0x4F, 0xFF}, + {0x50, 0xFF}, + {0x51, 0xFF}, + {0x52, 0xFF}, + {0x53, 0xFF}, + {0x54, 0xFF}, + {0x55, 0xFF}, + {0x56, 0xFF}, + {0x57, 0xFF}, + {0x58, 0x40}, + {0x59, 0x54}, + {0x5A, 0x07}, + {0x5B, 0x83}, + + {0xFF, 0xFF} +}; +/*--------------------------------------------------------------------------*/ +const struct saa7113config saa7113configNTSC[256] = { + {0x01, 0x08}, +#if defined(ANTIALIAS) + {0x02, 0xC0}, #else - {0x5A, 0x07}, -#endif /* ! PREFER_NTSC*/ - {0x5B, 0x83}, - {0xFF, 0xFF} - }; + {0x02, 0x80}, +#endif /*ANTIALIAS*/ + {0x03, 0x33}, + {0x04, 0x00}, + {0x05, 0x00}, + {0x06, 0xE9}, + {0x07, 0x0D}, + {0x08, 0x78}, + {0x09, 0x00}, + {0x0A, SAA_0A_DEFAULT}, + {0x0B, SAA_0B_DEFAULT}, + {0x0C, SAA_0C_DEFAULT}, + {0x0D, SAA_0D_DEFAULT}, + {0x0E, 0x01}, + {0x0F, 0x36}, + {0x10, 0x00}, + {0x11, 0x0C}, + {0x12, 0xE7}, + {0x13, 0x00}, + {0x15, 0x00}, + {0x16, 0x00}, + {0x40, 0x82}, + {0x41, 0xFF}, + {0x42, 0xFF}, + {0x43, 0xFF}, + {0x44, 0xFF}, + {0x45, 0xFF}, + {0x46, 0xFF}, + {0x47, 0xFF}, + {0x48, 0xFF}, + {0x49, 0xFF}, + {0x4A, 0xFF}, + {0x4B, 0xFF}, + {0x4C, 0xFF}, + {0x4D, 0xFF}, + {0x4E, 0xFF}, + {0x4F, 0xFF}, + {0x50, 0xFF}, + {0x51, 0xFF}, + {0x52, 0xFF}, + {0x53, 0xFF}, + {0x54, 0xFF}, + {0x55, 0xFF}, + {0x56, 0xFF}, + {0x57, 0xFF}, + {0x58, 0x40}, + {0x59, 0x54}, + {0x5A, 0x0A}, + {0x5B, 0x83}, + + {0xFF, 0xFF} +}; /*--------------------------------------------------------------------------*/ /****************************************************************************/ @@ -213,15 +297,22 @@ return 0; } /****************************************************************************/ int -setup_stk(struct usb_device *p) +setup_stk(struct usb_device *p, bool ntsc) { int i0; i0 = 0; -while (0xFFF != stk1160config[i0].reg) { - SET(p, stk1160config[i0].reg, stk1160config[i0].set); - i0++; +if (true == ntsc) { + while (0xFFF != stk1160configNTSC[i0].reg) { + SET(p, stk1160configNTSC[i0].reg, stk1160configNTSC[i0].set); + i0++; + } +} else { + while (0xFFF != stk1160configPAL[i0].reg) { + SET(p, stk1160configPAL[i0].reg, stk1160configPAL[i0].set); + i0++; } +} write_300(p); @@ -229,19 +320,24 @@ return 0; } /****************************************************************************/ int -setup_saa(struct usb_device *p) +setup_saa(struct usb_device *p, bool ntsc) { int i0, ir; - -set2to78(p); - - i0 = 0; -while (0xFF != saa7113config[i0].reg) { - ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set); - i0++; +if (true == ntsc) { + while (0xFF != saa7113configNTSC[i0].reg) { + ir = write_saa(p, saa7113configNTSC[i0].reg, \ + saa7113configNTSC[i0].set); + i0++; + } +} else { + while (0xFF != saa7113configPAL[i0].reg) { + ir = write_saa(p, saa7113configPAL[i0].reg, \ + saa7113configPAL[i0].set); + i0++; } +} return 0; } /****************************************************************************/ @@ -353,24 +449,46 @@ return 0; */ /*--------------------------------------------------------------------------*/ int -check_saa(struct usb_device *p) +check_saa(struct usb_device *p, bool ntsc) { int i0, ir, rc; -i0 = 0; +i0 = 0; rc = 0; -while (0xFF != saa7113config[i0].reg) { - if (0x0F == saa7113config[i0].reg) { - i0++; continue; +if (true == ntsc) { + while (0xFF != saa7113configNTSC[i0].reg) { + if (0x0F == saa7113configNTSC[i0].reg) { + i0++; + continue; + } + + ir = read_saa(p, saa7113configNTSC[i0].reg); + if (ir != saa7113configNTSC[i0].set) { + SAY("SAA register 0x%02X has 0x%02X, " \ + "expected 0x%02X\n", \ + saa7113configNTSC[i0].reg, \ + ir, saa7113configNTSC[i0].set); + rc--; + } + i0++; } +} else { + while (0xFF != saa7113configPAL[i0].reg) { + if (0x0F == saa7113configPAL[i0].reg) { + i0++; + continue; + } - ir = read_saa(p, saa7113config[i0].reg); - if (ir != saa7113config[i0].set) { - SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \ - saa7113config[i0].reg, ir, saa7113config[i0].set); - rc--; + ir = read_saa(p, saa7113configPAL[i0].reg); + if (ir != saa7113configPAL[i0].set) { + SAY("SAA register 0x%02X has 0x%02X, " \ + "expected 0x%02X\n", \ + saa7113configPAL[i0].reg, \ + ir, saa7113configPAL[i0].set); + rc--; + } + i0++; } - i0++; } if (-8 > rc) return rc; @@ -393,29 +511,44 @@ else int ready_saa(struct usb_device *p) { -int j, rc; -static int max = 10; - +int j, rc, rate; +const int max = 5, marktime = PATIENCE/5; +/*--------------------------------------------------------------------------*/ +/* + * RETURNS 0 FOR INTERLACED 50 Hz + * 1 FOR NON-INTERLACED 50 Hz + * 2 FOR INTERLACED 60 Hz + * 3 FOR NON-INTERLACED 60 Hz +*/ +/*--------------------------------------------------------------------------*/ j = 0; while (max > j) { rc = read_saa(p, 0x1F); if (0 <= rc) { - if ((1 == (0x01 & rc))&&(0 == (0x40 & rc))) + if (0 == (0x40 & rc)) + break; + if (1 == (0x01 & rc)) break; } - msleep(100); j++; + msleep(marktime); + j++; } if (max == j) return -1; else { - if (0x20 & rc) + if (0x20 & rc) { + rate = 2; JOT(8, "hardware detects 60 Hz\n"); - else + } else { + rate = 0; JOT(8, "hardware detects 50 Hz\n"); + } if (0x80 & rc) JOT(8, "hardware detects interlacing\n"); - else + else { + rate++; JOT(8, "hardware detects no interlacing\n"); + } } return 0; } @@ -424,45 +557,78 @@ return 0; /* * NOTE: THE FOLLOWING ARE NOT CHECKED: * REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN - * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config[.].set) + * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config....[.].set) */ /*--------------------------------------------------------------------------*/ int -check_stk(struct usb_device *p) +check_stk(struct usb_device *p, bool ntsc) { int i0, ir; -i0 = 0; -while (0xFFF != stk1160config[i0].reg) { - if (0x000 == stk1160config[i0].reg) { - i0++; continue; - } - if (0x002 == stk1160config[i0].reg) { - i0++; continue; - } - - ir = read_stk(p, stk1160config[i0].reg); - if (0x100 == stk1160config[i0].reg) { - if ((ir != (0xFF & stk1160config[i0].set)) && \ - (ir != (0x80 | (0xFF & stk1160config[i0].set))) && \ - (0xFFFF != stk1160config[i0].set)) { - SAY("STK register 0x%03X has 0x%02X, " \ - "expected 0x%02X\n", \ - stk1160config[i0].reg, ir, \ - stk1160config[i0].set); +i0 = 0; +if (true == ntsc) { + while (0xFFF != stk1160configNTSC[i0].reg) { + if (0x000 == stk1160configNTSC[i0].reg) { + i0++; continue; + } + if (0x002 == stk1160configNTSC[i0].reg) { + i0++; continue; + } + ir = read_stk(p, stk1160configNTSC[i0].reg); + if (0x100 == stk1160configNTSC[i0].reg) { + if ((ir != (0xFF & stk1160configNTSC[i0].set)) && \ + (ir != (0x80 | (0xFF & \ + stk1160configNTSC[i0].set))) && \ + (0xFFFF != \ + stk1160configNTSC[i0].set)) { + SAY("STK register 0x%03X has 0x%02X, " \ + "expected 0x%02X\n", \ + stk1160configNTSC[i0].reg, \ + ir, stk1160configNTSC[i0].set); + } + i0++; continue; } - i0++; continue; + if ((ir != (0xFF & stk1160configNTSC[i0].set)) && \ + (0xFFFF != stk1160configNTSC[i0].set)) { + SAY("STK register 0x%03X has 0x%02X, " \ + "expected 0x%02X\n", \ + stk1160configNTSC[i0].reg, \ + ir, stk1160configNTSC[i0].set); } - - if ((ir != (0xFF & stk1160config[i0].set)) && \ - (0xFFFF != stk1160config[i0].set)) { - SAY("STK register 0x%03X has 0x%02X, " \ - "expected 0x%02X\n", \ - stk1160config[i0].reg, ir, \ - stk1160config[i0].set); + i0++; + } +} else { + while (0xFFF != stk1160configPAL[i0].reg) { + if (0x000 == stk1160configPAL[i0].reg) { + i0++; continue; + } + if (0x002 == stk1160configPAL[i0].reg) { + i0++; continue; + } + ir = read_stk(p, stk1160configPAL[i0].reg); + if (0x100 == stk1160configPAL[i0].reg) { + if ((ir != (0xFF & stk1160configPAL[i0].set)) && \ + (ir != (0x80 | (0xFF & \ + stk1160configPAL[i0].set))) && \ + (0xFFFF != \ + stk1160configPAL[i0].set)) { + SAY("STK register 0x%03X has 0x%02X, " \ + "expected 0x%02X\n", \ + stk1160configPAL[i0].reg, \ + ir, stk1160configPAL[i0].set); + } + i0++; continue; + } + if ((ir != (0xFF & stk1160configPAL[i0].set)) && \ + (0xFFFF != stk1160configPAL[i0].set)) { + SAY("STK register 0x%03X has 0x%02X, " \ + "expected 0x%02X\n", \ + stk1160configPAL[i0].reg, \ + ir, stk1160configPAL[i0].set); } - i0++; + i0++; } +} return 0; } /****************************************************************************/ @@ -489,8 +655,8 @@ igot = 0; GET(p, reg0, &igot); return igot; } -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ +/****************************************************************************/ +/*--------------------------------------------------------------------------*/ /* * HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE * @@ -511,81 +677,98 @@ return igot; int select_input(struct usb_device *p, int input, int mode) { +int ir; stop_100(p); - -msleep(20); switch (input) { case 0: case 1: { - SET(p, 0x0000, 0x0098); break; + if (0 != write_saa(p, 0x02, 0x80)) { + SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \ + input); + } + SET(p, 0x0000, 0x0098); + SET(p, 0x0002, 0x0078); + break; } case 2: { - SET(p, 0x0000, 0x0090); break; + if (0 != write_saa(p, 0x02, 0x80)) { + SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \ + input); + } + SET(p, 0x0000, 0x0090); + SET(p, 0x0002, 0x0078); + break; } case 3: { - SET(p, 0x0000, 0x0088); break; + if (0 != write_saa(p, 0x02, 0x80)) { + SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \ + input); + } + SET(p, 0x0000, 0x0088); + SET(p, 0x0002, 0x0078); + break; } case 4: { - SET(p, 0x0000, 0x0080); break; + if (0 != write_saa(p, 0x02, 0x80)) { + SAY("ERROR: failed to set SAA register 0x02 for input %i\n", \ + input); + } + SET(p, 0x0000, 0x0080); + SET(p, 0x0002, 0x0078); + break; } case 5: { if (9 != mode) mode = 7; switch (mode) { - case 7: - { + case 7: { if (0 != write_saa(p, 0x02, 0x87)) { - SAY("ERROR: failed to set SAA " \ - "register 0x02 for input " \ - "%i\n", input); + SAY("ERROR: failed to set SAA register 0x02 " \ + "for input %i\n", input); } if (0 != write_saa(p, 0x05, 0xFF)) { - SAY("ERROR: failed to set SAA " \ - "register 0x05 for input " \ - "%i\n", input); + SAY("ERROR: failed to set SAA register 0x05 " \ + "for input %i\n", input); } break; } - case 9: - { + case 9: { if (0 != write_saa(p, 0x02, 0x89)) { - SAY("ERROR: failed to set SAA " \ - "register 0x02 for input " \ - "%i\n", input); + SAY("ERROR: failed to set SAA register 0x02 " \ + "for input %i\n", input); } if (0 != write_saa(p, 0x05, 0x00)) { - SAY("ERROR: failed to set SAA " \ - "register 0x05 for input " \ - "%i\n", input); + SAY("ERROR: failed to set SAA register 0x05 " \ + "for input %i\n", input); } - break; + break; } - default: - { + default: { SAY("MISTAKE: bad mode: %i\n", mode); return -1; - } + } } if (0 != write_saa(p, 0x04, 0x00)) { - SAY("ERROR: failed to set SAA register 0x04 " \ - "for input %i\n", input); + SAY("ERROR: failed to set SAA register 0x04 for input %i\n", \ + input); } if (0 != write_saa(p, 0x09, 0x80)) { - SAY("ERROR: failed to set SAA register 0x09 " \ - "for input %i\n", input); + SAY("ERROR: failed to set SAA register 0x09 for input %i\n", \ + input); } + SET(p, 0x0002, 0x0093); break; } -default: - { +default: { SAY("ERROR: bad input: %i\n", input); return -1; } } -msleep(20); -SET(p, 0x0002, 0x0093); -msleep(20); +ir = read_stk(p, 0x00); +JOT(8, "STK register 0x00 has 0x%02X\n", ir); +ir = read_saa(p, 0x02); +JOT(8, "SAA register 0x02 has 0x%02X\n", ir); start_100(p); @@ -618,13 +801,23 @@ return 0; int start_100(struct usb_device *p) { -__u16 get0; -__u8 igot; - -GET(p, 0x0100, &igot); get0 = igot; -msleep(0x1f4); +__u16 get116, get117, get0; +__u8 igot116, igot117, igot; + +GET(p, 0x0116, &igot116); +get116 = igot116; +GET(p, 0x0117, &igot117); +get117 = igot117; +SET(p, 0x0116, 0x0000); +SET(p, 0x0117, 0x0000); + +GET(p, 0x0100, &igot); +get0 = igot; SET(p, 0x0100, (0x80 | get0)); -msleep(0x1f4); + +SET(p, 0x0116, get116); +SET(p, 0x0117, get117); + return 0; } /****************************************************************************/ @@ -634,10 +827,9 @@ stop_100(struct usb_device *p) __u16 get0; __u8 igot; -GET(p, 0x0100, &igot); get0 = igot; -msleep(0x1f4); +GET(p, 0x0100, &igot); +get0 = igot; SET(p, 0x0100, (0x7F & get0)); -msleep(0x1f4); return 0; } /****************************************************************************/ @@ -651,7 +843,7 @@ wait_i2c(struct usb_device *p) { __u16 get0; __u8 igot; -const int max = 4; +const int max = 2; int k; for (k = 0; k < max; k++) { @@ -662,7 +854,7 @@ for (k = 0; k < max; k++) { return 0; } case 0x00: { - msleep(10); + msleep(20); continue; } default: { @@ -718,27 +910,14 @@ case 0x204: case 0x205: case 0x350: case 0x351: { - if (0 != igot) { + if (0 != (0xFF & igot)) { JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \ igot, index); } break; } -case 0x114: -case 0x116: { - if ((0xFF & value) != igot) { - JOT(8, "unexpected 0x%02X != 0x%02X " \ - "for STK register 0x%03X\n", \ - igot, value, index); - } -break; -} -case 0x200: { - if (0 == igot) - break; -} default: { - if (value != igot) { + if ((0xFF & value) != (0xFF & igot)) { JOT(8, "unexpected 0x%02X != 0x%02X " \ "for STK register 0x%03X\n", \ igot, value, index); @@ -988,29 +1167,3 @@ if (0 > igot) return igot; } /*****************************************************************************/ -int -set2to78(struct usb_device *p) -{ -int ir; - -msleep(20); -ir = regset(p, 0x0002, 0x0078); -if (0 > ir) - SAY("ERROR: failed to set register 0x0002 to 0x0078\n"); -msleep(20); -return ir; -} -/*****************************************************************************/ -int -set2to93(struct usb_device *p) -{ -int ir; - -msleep(20); -ir = regset(p, 0x0002, 0x0093); -if (0 > ir) - SAY("ERROR: failed to set register 0x0002 to 0x0078\n"); -msleep(20); -return ir; -} -/*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index ff6addfa15de..b522c6eb65f6 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -30,6 +30,7 @@ #include "easycap.h" #include "easycap_standard.h" +#include "easycap_ioctl.h" int debug; module_param(debug, int, S_IRUGO | S_IWUSR); @@ -162,9 +163,8 @@ struct usb_interface *pusb_interface; #else struct video_device *pvideo_device; #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ -struct usb_device *p; struct easycap *peasycap; -int i, k, m, rc; +int rc; JOT(4, "\n"); SAY("==========OPEN=========\n"); @@ -197,19 +197,7 @@ if ((struct easycap *)NULL == peasycap) { return -EFAULT; } file->private_data = peasycap; -/*---------------------------------------------------------------------------*/ -/* - * INITIALIZATION - */ -/*---------------------------------------------------------------------------*/ -JOM(4, "starting initialization\n"); - -for (k = 0; k < FRAME_BUFFER_MANY; k++) { - for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) - memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE); -} -p = peasycap->pusb_device; -if ((struct usb_device *)NULL == p) { +if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } else { @@ -221,121 +209,398 @@ if (0 == rc) JOM(8, "wakeup_device() OK\n"); else { SAM("ERROR: wakeup_device() returned %i\n", rc); + if (-ENODEV == rc) + SAM("ERROR: wakeup_device() returned -ENODEV\n"); + else + SAM("ERROR: wakeup_device() returned %i\n", rc); + return rc; +} +peasycap->input = 0; +rc = reset(peasycap); +if (0 != rc) { + SAM("ERROR: reset() returned %i\n", rc); return -EFAULT; } -rc = setup_stk(p); peasycap->input = 0; +return 0; +} +/*****************************************************************************/ +/*---------------------------------------------------------------------------*/ +/* + * RESET THE HARDWARE TO ITS REFERENCE STATE. + * + * THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS + * A BAD VIDEO FRAME SIZE. +*/ +/*---------------------------------------------------------------------------*/ +int +reset(struct easycap *peasycap) +{ +struct easycap_standard const *peasycap_standard; +int i, rc, input, rate; +bool ntsc, other; + +if ((struct easycap *)NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return -EFAULT; +} +input = peasycap->input; + +/*---------------------------------------------------------------------------*/ +/* + * IF THE SAA7113H HAS ALREADY ACQUIRED LOCK, USE ITS HARDWARE-DETECTED + * FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR + * gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE + * A SWITCH BETWEEN PAL AND NTSC. + * + * FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO + * COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON. +*/ +/*---------------------------------------------------------------------------*/ +other = false; +if (true == peasycap->ntsc) + JOM(8, "true=peasycap->ntsc\n"); +else + JOM(8, "false=peasycap->ntsc\n"); +rate = ready_saa(peasycap->pusb_device); +if (0 > rate) { + JOM(8, "not ready to capture after %i ms ...\n", PATIENCE); + if (true == peasycap->ntsc) { + JOM(8, "... trying PAL ...\n"); ntsc = false; + } else { + JOM(8, "... trying NTSC ...\n"); ntsc = true; +} +rc = setup_stk(peasycap->pusb_device, ntsc); if (0 == rc) - JOM(8, "setup_stk() OK\n"); + JOM(4, "setup_stk() OK\n"); else { SAM("ERROR: setup_stk() returned %i\n", rc); return -EFAULT; } -rc = setup_saa(p); +rc = setup_saa(peasycap->pusb_device, ntsc); if (0 == rc) - JOM(8, "setup_saa() OK\n"); + JOM(4, "setup_saa() OK\n"); else { SAM("ERROR: setup_saa() returned %i\n", rc); return -EFAULT; } -rc = check_saa(p); -if (0 == rc) - JOM(8, "check_saa() OK\n"); -else if (-8 < rc) - SAM("check_saa() returned %i\n", rc); -else { - SAM("ERROR: check_saa() returned %i\n", rc); - return -EFAULT; +rate = ready_saa(peasycap->pusb_device); +if (0 > rate) { + JOM(8, "not ready to capture after %i ms ...\n", PATIENCE); + JOM(8, "... saa register 0x1F has 0x%02X\n", \ + read_saa(peasycap->pusb_device, 0x1F)); + ntsc = peasycap->ntsc; + } else { + JOM(8, "... success at second try: %i=rate\n", rate); + ntsc = (0 < (rate/2)) ? true : false ; + other = true; + } +} else { + JOM(8, "... success at first try: %i=rate\n", rate); + ntsc = (0 < rate/2) ? true : false ; } -peasycap->standard_offset = -1; +if (true == ntsc) + JOM(8, "true=ntsc\n"); +else + JOM(8, "false=ntsc\n"); /*---------------------------------------------------------------------------*/ -#if defined(PREFER_NTSC) -rc = adjust_standard(peasycap, V4L2_STD_NTSC_M); +rc = setup_stk(peasycap->pusb_device, ntsc); if (0 == rc) - JOM(8, "adjust_standard(.,NTSC_M) OK\n"); + JOM(4, "setup_stk() OK\n"); else { - SAM("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc); + SAM("ERROR: setup_stk() returned %i\n", rc); return -EFAULT; } -rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \ - false); -if (0 <= rc) - JOM(8, "adjust_format(.,640,480,UYVY) OK\n"); +rc = setup_saa(peasycap->pusb_device, ntsc); +if (0 == rc) + JOM(4, "setup_saa() OK\n"); else { - SAM("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc); + SAM("ERROR: setup_saa() returned %i\n", rc); return -EFAULT; } -#else +for (i = 0; i < 180; i++) + peasycap->merit[i] = 0; +peasycap->video_eof = 0; +peasycap->audio_eof = 0; +do_gettimeofday(&peasycap->timeval7); +/*---------------------------------------------------------------------------*/ +/* + * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC. + * + * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY. +*/ +/*---------------------------------------------------------------------------*/ +peasycap->input = -8192; +peasycap->standard_offset = -8192; +if (true == other) { + peasycap_standard = &easycap_standard[0]; + while (0xFFFF != peasycap_standard->mask) { + if (true == ntsc) { + if (NTSC_M == \ + peasycap_standard->v4l2_standard.index) { + peasycap->inputset[input].standard_offset = \ + peasycap_standard - \ + &easycap_standard[0]; + break; + } + } else { + if (PAL_BGHIN == \ + peasycap_standard->v4l2_standard.index) { + peasycap->inputset[input].standard_offset = \ + peasycap_standard - + &easycap_standard[0]; + break; + } + } + peasycap_standard++; + } + if (0xFFFF == peasycap_standard->mask) { + SAM("ERROR: standard not found\n"); + return -EINVAL; + } +JOM(8, "%i=peasycap->inputset[%i].standard_offset\n", \ + peasycap->inputset[input].standard_offset, input); +} +peasycap->format_offset = -8192; +peasycap->brightness = -8192; +peasycap->contrast = -8192; +peasycap->saturation = -8192; +peasycap->hue = -8192; + +rc = newinput(peasycap, input); -rc = adjust_standard(peasycap, \ - (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \ - V4L2_STD_PAL_I | V4L2_STD_PAL_N)); if (0 == rc) - JOM(8, "adjust_standard(.,PAL_BGHIN) OK\n"); + JOM(4, "restored input, standard and format\n"); else { - SAM("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc); + SAM("ERROR: newinput(.,%i) returned %i\n", rc, input); return -EFAULT; } -rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \ - false); -if (0 <= rc) - JOM(8, "adjust_format(.,640,480,uyvy,false) OK\n"); -else { - SAM("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc); +if (true == peasycap->ntsc) + JOM(8, "true=peasycap->ntsc\n"); +else + JOM(8, "false=peasycap->ntsc\n"); + +if (0 > peasycap->input) { + SAM("MISTAKE: %i=peasycap->input\n", peasycap->input); + return -ENOENT; +} +if (0 > peasycap->standard_offset) { + SAM("MISTAKE: %i=peasycap->standard_offset\n", \ + peasycap->standard_offset); + return -ENOENT; +} +if (0 > peasycap->format_offset) { + SAM("MISTAKE: %i=peasycap->format_offset\n", \ + peasycap->format_offset); + return -ENOENT; +} +if (0 > peasycap->brightness) { + SAM("MISTAKE: %i=peasycap->brightness\n", peasycap->brightness); + return -ENOENT; +} +if (0 > peasycap->contrast) { + SAM("MISTAKE: %i=peasycap->contrast\n", peasycap->contrast); + return -ENOENT; +} +if (0 > peasycap->saturation) { + SAM("MISTAKE: %i=peasycap->saturation\n", peasycap->saturation); + return -ENOENT; +} +if (0 > peasycap->hue) { + SAM("MISTAKE: %i=peasycap->hue\n", peasycap->hue); + return -ENOENT; +} +return 0; +} +/*****************************************************************************/ +/*---------------------------------------------------------------------------*/ +/* + * IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING. + * OTHERWISE: + * KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR + * _read AND _fill POINTERS. + * SELECT THE NEW INPUT. + * ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE + * ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input]. + * RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS. + * + * NOTE: + * THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL, + * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE. +*/ +/*---------------------------------------------------------------------------*/ +int +newinput(struct easycap *peasycap, int input) +{ +int rc, k, m, mood, off; +int inputnow, video_idlenow, audio_idlenow; +bool resubmit; + +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +JOM(8, "%i=input sought\n", input); -#endif /* !PREFER_NTSC*/ +if ((0 > input) &&(INPUT_MANY <= input)) + return -ENOENT; +inputnow = peasycap->input; +if (input == inputnow) + return 0; /*---------------------------------------------------------------------------*/ -rc = adjust_brightness(peasycap, -8192); -if (0 != rc) { - SAM("ERROR: adjust_brightness(default) returned %i\n", rc); - return -EFAULT; +/* + * IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS + * STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE. + * IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE + * ROUTINE. +*/ +/*---------------------------------------------------------------------------*/ +video_idlenow = peasycap->video_idle; +audio_idlenow = peasycap->audio_idle; + +peasycap->video_idle = 1; +peasycap->audio_idle = 1; +if (peasycap->video_isoc_streaming) { + resubmit = true; + kill_video_urbs(peasycap); +} else + resubmit = false; +/*---------------------------------------------------------------------------*/ +if (NULL == peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -ENODEV; } -rc = adjust_contrast(peasycap, -8192); +rc = usb_set_interface(peasycap->pusb_device, \ + peasycap->video_interface, \ + peasycap->video_altsetting_off); if (0 != rc) { - SAM("ERROR: adjust_contrast(default) returned %i\n", rc); + SAM("ERROR: usb_set_interface() returned %i\n", rc); return -EFAULT; } -rc = adjust_saturation(peasycap, -8192); +rc = stop_100(peasycap->pusb_device); if (0 != rc) { - SAM("ERROR: adjust_saturation(default) returned %i\n", rc); + SAM("ERROR: stop_100() returned %i\n", rc); return -EFAULT; } -rc = adjust_hue(peasycap, -8192); -if (0 != rc) { - SAM("ERROR: adjust_hue(default) returned %i\n", rc); - return -EFAULT; +for (k = 0; k < FIELD_BUFFER_MANY; k++) { + for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) + memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE); +} +for (k = 0; k < FRAME_BUFFER_MANY; k++) { + for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) + memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE); +} +peasycap->field_page = 0; +peasycap->field_read = 0; +peasycap->field_fill = 0; + +peasycap->frame_read = 0; +peasycap->frame_fill = 0; +for (k = 0; k < peasycap->input; k++) { + (peasycap->frame_fill)++; + if (peasycap->frame_buffer_many <= peasycap->frame_fill) + peasycap->frame_fill = 0; } +peasycap->input = input; +select_input(peasycap->pusb_device, peasycap->input, 9); /*---------------------------------------------------------------------------*/ -rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \ - peasycap->video_altsetting_on); -if (0 == rc) - JOM(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \ - peasycap->video_altsetting_on); -else { +if (input == peasycap->inputset[input].input) { + off = peasycap->inputset[input].standard_offset; + if (off != peasycap->standard_offset) { + rc = adjust_standard(peasycap, \ + easycap_standard[off].v4l2_standard.id); + if (0 != rc) { + SAM("ERROR: adjust_standard() returned %i\n", rc); + return -EFAULT; + } + JOM(8, "%i=peasycap->standard_offset\n", \ + peasycap->standard_offset); + } else { + JOM(8, "%i=peasycap->standard_offset unchanged\n", \ + peasycap->standard_offset); + } + off = peasycap->inputset[input].format_offset; + if (off != peasycap->format_offset) { + rc = adjust_format(peasycap, \ + easycap_format[off].v4l2_format.fmt.pix.width, \ + easycap_format[off].v4l2_format.fmt.pix.height, \ + easycap_format[off].v4l2_format.fmt.pix.pixelformat, \ + easycap_format[off].v4l2_format.fmt.pix.field, false); + if (0 > rc) { + SAM("ERROR: adjust_format() returned %i\n", rc); + return -EFAULT; + } + JOM(8, "%i=peasycap->format_offset\n", peasycap->format_offset); + } else { + JOM(8, "%i=peasycap->format_offset unchanged\n", \ + peasycap->format_offset); + } + mood = peasycap->inputset[input].brightness; + if (mood != peasycap->brightness) { + rc = adjust_brightness(peasycap, mood); + if (0 != rc) { + SAM("ERROR: adjust_brightness returned %i\n", rc); + return -EFAULT; + } + JOM(8, "%i=peasycap->brightness\n", peasycap->brightness); + } + mood = peasycap->inputset[input].contrast; + if (mood != peasycap->contrast) { + rc = adjust_contrast(peasycap, mood); + if (0 != rc) { + SAM("ERROR: adjust_contrast returned %i\n", rc); + return -EFAULT; + } + JOM(8, "%i=peasycap->contrast\n", peasycap->contrast); + } + mood = peasycap->inputset[input].saturation; + if (mood != peasycap->saturation) { + rc = adjust_saturation(peasycap, mood); + if (0 != rc) { + SAM("ERROR: adjust_saturation returned %i\n", rc); + return -EFAULT; + } + JOM(8, "%i=peasycap->saturation\n", peasycap->saturation); + } + mood = peasycap->inputset[input].hue; + if (mood != peasycap->hue) { + rc = adjust_hue(peasycap, mood); + if (0 != rc) { + SAM("ERROR: adjust_hue returned %i\n", rc); + return -EFAULT; + } + JOM(8, "%i=peasycap->hue\n", peasycap->hue); + } +} else { + SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input); + return -ENOENT; +} +/*---------------------------------------------------------------------------*/ +if ((struct usb_device *)NULL == peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -ENODEV; +} +rc = usb_set_interface(peasycap->pusb_device, + peasycap->video_interface, \ + peasycap->video_altsetting_on); +if (0 != rc) { SAM("ERROR: usb_set_interface() returned %i\n", rc); return -EFAULT; } -rc = start_100(p); -if (0 == rc) - JOM(8, "start_100() OK\n"); -else { +rc = start_100(peasycap->pusb_device); +if (0 != rc) { SAM("ERROR: start_100() returned %i\n", rc); return -EFAULT; } +if (true == resubmit) + submit_video_urbs(peasycap); + peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1; -peasycap->video_idle = 0; +peasycap->video_idle = video_idlenow; +peasycap->audio_idle = audio_idlenow; peasycap->video_junk = 0; -for (i = 0; i < 180; i++) - peasycap->merit[i] = 0; -peasycap->video_eof = 0; -peasycap->audio_eof = 0; - -do_gettimeofday(&peasycap->timeval7); -JOM(4, "finished initialization\n"); return 0; } /*****************************************************************************/ @@ -864,24 +1129,44 @@ while ((peasycap->field_read == peasycap->field_fill) || \ "%i=field_read %i=field_fill\n", \ peasycap->field_read, peasycap->field_fill); - msleep(1); if (0 != (wait_event_interruptible(peasycap->wq_video, \ (peasycap->video_idle || peasycap->video_eof || \ ((peasycap->field_read != peasycap->field_fill) && \ (0 == (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) && \ (0 == (0x00FF & peasycap->field_buffer\ - [peasycap->field_read][0].kount))))))){ + [peasycap->field_read][0].kount))))))) { SAM("aborted by signal\n"); return -EIO; } if (peasycap->video_idle) { - JOM(8, "%i=peasycap->video_idle\n", peasycap->video_idle); - return -EIO; + JOM(8, "%i=peasycap->video_idle ... returning -EAGAIN\n", \ + peasycap->video_idle); + return -EAGAIN; } if (peasycap->video_eof) { JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof); + #if defined(PERSEVERE) + if (1 == peasycap->status) { + JOM(8, "persevering ...\n"); + peasycap->video_eof = 0; + peasycap->audio_eof = 0; + if (0 != reset(peasycap)) { + JOM(8, " ... failed ... returning -EIO\n"); + peasycap->video_eof = 1; + peasycap->audio_eof = 1; + kill_video_urbs(peasycap); + return -EIO; + } + peasycap->status = 0; + JOM(8, " ... OK ... returning -EAGAIN\n"); + return -EAGAIN; + } + #endif /*PERSEVERE*/ + peasycap->video_eof = 1; + peasycap->audio_eof = 1; kill_video_urbs(peasycap); + JOM(8, "returning -EIO\n"); return -EIO; } miss++; @@ -925,24 +1210,44 @@ while ((peasycap->field_read == peasycap->field_fill) || \ JOM(8, "second wait on wq_video, " \ "%i=field_read %i=field_fill\n", \ peasycap->field_read, peasycap->field_fill); - msleep(1); if (0 != (wait_event_interruptible(peasycap->wq_video, \ (peasycap->video_idle || peasycap->video_eof || \ ((peasycap->field_read != peasycap->field_fill) && \ (0 == (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) && \ (0 != (0x00FF & peasycap->field_buffer\ - [peasycap->field_read][0].kount))))))){ + [peasycap->field_read][0].kount))))))) { SAM("aborted by signal\n"); return -EIO; } if (peasycap->video_idle) { - JOM(8, "%i=peasycap->video_idle\n", peasycap->video_idle); - return -EIO; + JOM(8, "%i=peasycap->video_idle ... returning -EAGAIN\n", \ + peasycap->video_idle); + return -EAGAIN; } if (peasycap->video_eof) { JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof); + #if defined(PERSEVERE) + if (1 == peasycap->status) { + JOM(8, "persevering ...\n"); + peasycap->video_eof = 0; + peasycap->audio_eof = 0; + if (0 != reset(peasycap)) { + JOM(8, " ... failed ... returning -EIO\n"); + peasycap->video_eof = 1; + peasycap->audio_eof = 1; + kill_video_urbs(peasycap); + return -EIO; + } + peasycap->status = 0; + JOM(8, " ... OK ... returning -EAGAIN\n"); + return -EAGAIN; + } + #endif /*PERSEVERE*/ + peasycap->video_eof = 1; + peasycap->audio_eof = 1; kill_video_urbs(peasycap); + JOM(8, "returning -EIO\n"); return -EIO; } miss++; @@ -1001,13 +1306,15 @@ int kex, kad, mex, mad, rex, rad, rad2; int c2, c3, w2, w3, cz, wz; int rc, bytesperpixel, multiplier, much, more, over, rump, caches; __u8 mask, margin; -bool odd, isuy, decimatepixel, offerfields; +bool odd, isuy, decimatepixel, offerfields, badinput; if ((struct easycap *)NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +badinput = false; + JOM(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \ peasycap->field_buffer[peasycap->field_read][0].kount,\ peasycap->field_read, peasycap->frame_fill); @@ -1138,6 +1445,15 @@ while (cz < wz) { if (rump) caches++; + if (true == badinput) { + JOM(8, "ERROR: 0x%02X=->field_buffer" \ + "[%i][%i].input, " \ + "0x%02X=(0x08|->input)\n", \ + peasycap->field_buffer\ + [kex][mex].input, kex, mex, \ + (0x08|peasycap->input)); + } + rc = redaub(peasycap, pad, pex, much, more, \ mask, margin, isuy); if (0 > rc) { @@ -1156,6 +1472,9 @@ while (cz < wz) { mex++; pex = peasycap->field_buffer[kex][mex].pgo; rex = PAGE_SIZE; + if (peasycap->field_buffer[kex][mex].input != \ + (0x08|peasycap->input)) + badinput = true; } pad += more; rad -= more; @@ -1254,6 +1573,15 @@ while (cz < wz) { if (rump) caches++; + if (true == badinput) { + JOM(8, "ERROR: 0x%02X=->field_buffer" \ + "[%i][%i].input, " \ + "0x%02X=(0x08|->input)\n", \ + peasycap->field_buffer\ + [kex][mex].input, kex, mex, \ + (0x08|peasycap->input)); + } + rc = redaub(peasycap, pad, pex, much, more, \ mask, margin, isuy); if (0 > rc) { @@ -1266,6 +1594,9 @@ while (cz < wz) { mex++; pex = peasycap->field_buffer[kex][mex].pgo; rex = PAGE_SIZE; + if (peasycap->field_buffer[kex][mex].input != \ + (0x08|peasycap->input)) + badinput = true; } pad += more; rad -= more; @@ -1292,6 +1623,16 @@ while (cz < wz) { mex++; pex = peasycap->field_buffer[kex][mex].pgo; rex = PAGE_SIZE; + if (peasycap->field_buffer[kex][mex].input != \ + (0x08|peasycap->input)) { + JOM(8, "ERROR: 0x%02X=->field_buffer"\ + "[%i][%i].input, " \ + "0x%02X=(0x08|->input)\n", \ + peasycap->field_buffer\ + [kex][mex].input, kex, mex, \ + (0x08|peasycap->input)); + badinput = true; + } } much = over; if (rex < much) @@ -2350,6 +2691,7 @@ return retcode; * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA + * 0 != (kount & 0x1000) => BUFFER HAS DATA FROM DISPARATE INPUTS * 0 != (kount & 0x0400) => RESERVED * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY? @@ -2363,7 +2705,7 @@ struct data_buffer *pfield_buffer; char errbuf[16]; int i, more, much, leap, rc, last; int videofieldamount; -unsigned int override; +unsigned int override, bad; int framestatus, framelength, frameactual, frameoffset; __u8 *pu; @@ -2389,7 +2731,7 @@ if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && \ (0 != i)) || \ (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && \ ((last + 1) != i))) { - SAM("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i); + JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n", last, i); } peasycap->video_isoc_sequence = i; @@ -2399,9 +2741,6 @@ if (peasycap->video_idle) { if (peasycap->video_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAM("ERROR: while %i=video_idle, " \ - "usb_submit_urb() failed with rc:\n", \ - peasycap->video_idle); switch (rc) { case -ENOMEM: { SAM("ENOMEM\n"); @@ -2444,6 +2783,11 @@ if (peasycap->video_idle) { break; } } + if (-ENODEV != rc) \ + SAM("ERROR: while %i=video_idle, " \ + "usb_submit_urb() " \ + "failed with rc:\n", \ + peasycap->video_idle); } } return; @@ -2662,6 +3006,8 @@ if (purb->status) { (peasycap->field_buffer\ [peasycap->field_fill]\ [0].kount) |= 0x0100; + peasycap->video_junk += (1 + \ + VIDEO_JUNK_TOLERATE); } else (peasycap->field_buffer\ [peasycap->field_fill]\ @@ -2673,53 +3019,74 @@ if (purb->status) { [peasycap->field_fill]\ [0].kount) |= 0x2000; } - if (!(0xFF00 & peasycap->field_buffer\ + bad = 0xFF00 & peasycap->field_buffer\ [peasycap->field_fill]\ - [0].kount)) { - (peasycap->video_junk)--; - if (-16 > peasycap->video_junk) - peasycap->video_junk = -16; - peasycap->field_read = \ + [0].kount; + if (!bad) { + (peasycap->video_junk)--; + if (-VIDEO_JUNK_TOLERATE > \ + peasycap->video_junk) \ + peasycap->video_junk =\ + -VIDEO_JUNK_TOLERATE; + peasycap->field_read = \ (peasycap->\ field_fill)++; - - if (FIELD_BUFFER_MANY <= \ - peasycap->field_fill) - peasycap->field_fill = 0; - peasycap->field_page = 0; - pfield_buffer = &peasycap->\ - field_buffer\ - [peasycap->field_fill]\ - [peasycap->field_page]; - pfield_buffer->pto = \ + if (FIELD_BUFFER_MANY <= \ + peasycap->\ + field_fill) + peasycap->\ + field_fill = 0; + peasycap->field_page = 0; + pfield_buffer = &peasycap->\ + field_buffer\ + [peasycap->\ + field_fill]\ + [peasycap->\ + field_page]; + pfield_buffer->pto = \ pfield_buffer->pgo; - - JOM(8, "bumped to: %i=peasycap->" \ - "field_fill %i=parity\n", \ - peasycap->field_fill, \ - 0x00FF & pfield_buffer->kount); - JOM(8, "field buffer %i has %i " \ - "bytes fit to be read\n", \ - peasycap->field_read, \ - videofieldamount); - JOM(8, "wakeup call to wq_video, " \ - "%i=field_read %i=field_fill "\ - "%i=parity\n", \ - peasycap->field_read, \ - peasycap->field_fill, \ - 0x00FF & peasycap->\ - field_buffer[peasycap->\ - field_read][0].kount); - wake_up_interruptible(&(peasycap->\ - wq_video)); - do_gettimeofday(&peasycap->timeval7); + JOM(8, "bumped to: %i="\ + "peasycap->" \ + "field_fill %i="\ + "parity\n", \ + peasycap->field_fill, \ + 0x00FF & \ + pfield_buffer->kount); + JOM(8, "field buffer %i has "\ + "%i bytes fit to be "\ + "read\n", \ + peasycap->field_read, \ + videofieldamount); + JOM(8, "wakeup call to "\ + "wq_video, " \ + "%i=field_read "\ + "%i=field_fill "\ + "%i=parity\n", \ + peasycap->field_read, \ + peasycap->field_fill, \ + 0x00FF & peasycap->\ + field_buffer\ + [peasycap->\ + field_read][0].kount); + wake_up_interruptible\ + (&(peasycap->\ + wq_video)); + do_gettimeofday\ + (&peasycap->timeval7); } else { peasycap->video_junk++; + if (bad & 0x0010) \ + peasycap->video_junk += \ + (1 + VIDEO_JUNK_TOLERATE/2); JOM(8, "field buffer %i had %i " \ - "bytes, now discarded\n", \ + "bytes, now discarded: "\ + "0x%04X\n", \ peasycap->field_fill, \ - videofieldamount); - + videofieldamount,\ + (0xFF00 & \ + peasycap->field_buffer\ + [peasycap->field_fill][0].\ + kount)); (peasycap->field_fill)++; if (FIELD_BUFFER_MANY <= \ @@ -2746,6 +3113,8 @@ if (purb->status) { pfield_buffer->kount = 0x0000; else pfield_buffer->kount = 0x0001; + pfield_buffer->input = 0x08 | \ + (0x07 & peasycap->input); JOM(8, "end-of-field: 0x%02X=kount\n",\ 0xFF & pfield_buffer->kount); } @@ -2819,18 +3188,19 @@ if (purb->status) { /*---------------------------------------------------------------------------*/ if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) { SAM("easycap driver shutting down on condition green\n"); + peasycap->status = 1; peasycap->video_eof = 1; + peasycap->video_junk = 0; + wake_up_interruptible(&peasycap->wq_video); +#if !defined(PERSEVERE) peasycap->audio_eof = 1; - peasycap->video_junk = -VIDEO_ISOC_BUFFER_MANY; - wake_up_interruptible(&(peasycap->wq_video)); - wake_up_interruptible(&(peasycap->wq_audio)); + wake_up_interruptible(&peasycap->wq_audio); +#endif /*PERSEVERE*/ return; } if (peasycap->video_isoc_streaming) { rc = usb_submit_urb(purb, GFP_ATOMIC); if (0 != rc) { - SAM("ERROR: while %i=video_idle, usb_submit_urb() failed " \ - "with rc:\n", peasycap->video_idle); switch (rc) { case -ENOMEM: { SAM("ENOMEM\n"); break; @@ -2863,6 +3233,11 @@ if (peasycap->video_isoc_streaming) { SAM("0x%08X\n", rc); break; } } + if (-ENODEV != rc) \ + SAM("ERROR: while %i=video_idle, " \ + "usb_submit_urb() " \ + "failed with rc:\n", \ + peasycap->video_idle); } } return; @@ -2910,6 +3285,9 @@ int okalt[8], isokalt; int okepn[8]; int okmps[8]; int maxpacketsize; +__u16 mask; +__s32 value; +struct easycap_format *peasycap_format; JOT(4, "\n"); peasycap = (struct easycap *)NULL; @@ -3056,13 +3434,14 @@ if (0 == bInterfaceNumber) { for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) { if ((struct easycap *)NULL == peasycap_dongle[dongle_this]) { - peasycap_dongle[dongle_this] = peasycap; - JOM(8, "intf[%i]: peasycap-->easycap" \ + peasycap_dongle[dongle_this] = peasycap; + JOM(8, "intf[%i]: peasycap-->easycap" \ "_dongle[%i].peasycap\n", \ bInterfaceNumber, dongle_this); break; } } + if (DONGLE_MANY <= dongle_this) { SAM("ERROR: too many dongles\n"); return -ENOMEM; @@ -3105,7 +3484,7 @@ if (0 == bInterfaceNumber) { peasycap->offerfields = 0; /*---------------------------------------------------------------------------*/ /* - * DYNAMICALLY FILL IN THE AVAILABLE FORMATS. + * DYNAMICALLY FILL IN THE AVAILABLE FORMATS ... */ /*---------------------------------------------------------------------------*/ rc = fillin_formats(); @@ -3114,6 +3493,120 @@ if (0 == bInterfaceNumber) { return -EFAULT; } JOM(4, "%i formats available\n", rc); +/*---------------------------------------------------------------------------*/ +/* + * ... AND POPULATE easycap.inputset[] +*/ +/*---------------------------------------------------------------------------*/ + for (k = 0; k < INPUT_MANY; k++) { + peasycap->inputset[k].input_ok = 0; + peasycap->inputset[k].standard_offset_ok = 0; + peasycap->inputset[k].format_offset_ok = 0; + peasycap->inputset[k].brightness_ok = 0; + peasycap->inputset[k].contrast_ok = 0; + peasycap->inputset[k].saturation_ok = 0; + peasycap->inputset[k].hue_ok = 0; + } + if (true == peasycap->ntsc) { + i = 0; + m = 0; + mask = 0; + while (0xFFFF != easycap_standard[i].mask) { + if (NTSC_M == easycap_standard[i].\ + v4l2_standard.index) { + m++; + for (k = 0; k < INPUT_MANY; k++) { + peasycap->inputset[k].\ + standard_offset = i; + } + mask = easycap_standard[i].mask; + } + i++; + } + } else { + i = 0; + m = 0; + mask = 0; + while (0xFFFF != easycap_standard[i].mask) { + if (PAL_BGHIN == easycap_standard[i].\ + v4l2_standard.index) { + m++; + for (k = 0; k < INPUT_MANY; k++) { + peasycap->inputset[k].\ + standard_offset = i; + } + mask = easycap_standard[i].mask; + } + i++; + } + } + + if (1 != m) { + SAM("MISTAKE: easycap.inputset[].standard_offset " \ + "unpopulated, %i=m\n", m); + return -ENOENT; + } + + peasycap_format = &easycap_format[0]; + i = 0; + m = 0; + while (0 != peasycap_format->v4l2_format.fmt.pix.width) { + if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ + (peasycap_format->\ + v4l2_format.fmt.pix.field == \ + V4L2_FIELD_NONE) && \ + (peasycap_format->\ + v4l2_format.fmt.pix.pixelformat == \ + V4L2_PIX_FMT_UYVY) && \ + (peasycap_format->\ + v4l2_format.fmt.pix.width == \ + 640) && \ + (peasycap_format->\ + v4l2_format.fmt.pix.height == 480)) { + m++; + for (k = 0; k < INPUT_MANY; k++) + peasycap->inputset[k].format_offset = i; + break; + } + peasycap_format++; + i++; + } + if (1 != m) { + SAM("MISTAKE: easycap.inputset[].format_offset unpopulated\n"); + return -ENOENT; + } + + i = 0; + m = 0; + while (0xFFFFFFFF != easycap_control[i].id) { + value = easycap_control[i].default_value; + if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) { + m++; + for (k = 0; k < INPUT_MANY; k++) + peasycap->inputset[k].brightness = value; + } else if (V4L2_CID_CONTRAST == easycap_control[i].id) { + m++; + for (k = 0; k < INPUT_MANY; k++) + peasycap->inputset[k].contrast = value; + } else if (V4L2_CID_SATURATION == easycap_control[i].id) { + m++; + for (k = 0; k < INPUT_MANY; k++) + peasycap->inputset[k].saturation = value; + } else if (V4L2_CID_HUE == easycap_control[i].id) { + m++; + for (k = 0; k < INPUT_MANY; k++) + peasycap->inputset[k].hue = value; + } + i++; + } + if (4 != m) { + SAM("MISTAKE: easycap.inputset[].brightness,... " \ + "underpopulated\n"); + return -ENOENT; + } + for (k = 0; k < INPUT_MANY; k++) + peasycap->inputset[k].input = k; + JOM(4, "populated easycap.inputset[]\n"); JOM(4, "finished initialization\n"); } else { /*---------------------------------------------------------------------------*/ @@ -4095,15 +4588,16 @@ if (NULL == peasycap) { /*---------------------------------------------------------------------------*/ peasycap->video_eof = 1; peasycap->audio_eof = 1; -wake_up_interruptible(&peasycap->wq_video); -wake_up_interruptible(&peasycap->wq_audio); +wake_up_interruptible(&(peasycap->wq_video)); +wake_up_interruptible(&(peasycap->wq_audio)); /*---------------------------------------------------------------------------*/ switch (bInterfaceNumber) { case 0: { if ((struct list_head *)NULL != peasycap->purb_video_head) { JOM(4, "killing video urbs\n"); m = 0; - list_for_each(plist_head, (peasycap->purb_video_head)) { + list_for_each(plist_head, (peasycap->purb_video_head)) + { pdata_urb = list_entry(plist_head, \ struct data_urb, list_head); if ((struct data_urb *)NULL != pdata_urb) { @@ -4123,7 +4617,8 @@ case 2: { if ((struct list_head *)NULL != peasycap->purb_audio_head) { JOM(4, "killing audio urbs\n"); m = 0; - list_for_each(plist_head, (peasycap->purb_audio_head)) { + list_for_each(plist_head, \ + (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, \ struct data_urb, list_head); if ((struct data_urb *)NULL != pdata_urb) { @@ -4149,7 +4644,6 @@ default: /*--------------------------------------------------------------------------*/ switch (bInterfaceNumber) { case 0: { - #if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) if ((struct easycap *)NULL == peasycap) { SAM("ERROR: peasycap has become NULL\n"); diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c index 21275973faf3..0b4b60b0a5a7 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/easycap/easycap_sound.c @@ -638,11 +638,6 @@ if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device has become NULL\n"); return -EFAULT; } -rc = adjust_volume(peasycap, -8192); -if (0 != rc) { - SAM("ERROR: adjust_volume(default) returned %i\n", rc); - return -EFAULT; -} /*---------------------------------------------------------------------------*/ if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device has become NULL\n"); @@ -653,26 +648,20 @@ rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \ JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \ peasycap->audio_altsetting_on, rc); -if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -EFAULT; -} rc = wakeup_device(peasycap->pusb_device); if (0 == rc) JOM(8, "wakeup_device() returned %i\n", rc); else - JOM(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc); + JOM(8, "ERROR: wakeup_device() returned %i\n", rc); -if ((struct usb_device *)NULL == peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -EFAULT; -} -submit_audio_urbs(peasycap); +peasycap->audio_eof = 0; peasycap->audio_idle = 0; peasycap->timeval1.tv_sec = 0; peasycap->timeval1.tv_usec = 0; +submit_audio_urbs(peasycap); + JOM(4, "finished initialization\n"); return 0; } @@ -764,7 +753,6 @@ while ((fragment == (peasycap->audio_fill / \ JOM(8, "returning 0 because %i=audio_eof\n", \ peasycap->audio_eof); kill_audio_urbs(peasycap); - msleep(500); return 0; } if (peasycap->audio_idle) { -- cgit v1.2.3 From 40b8d50ac98f8c8779aea7459f805e5a69fdb726 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:02:15 +0000 Subject: staging/easycap: Implement interlaced modes and reduced framerates Interlaced modes are requested by tvtime. Reduced framerates are preferred by some userspace programs, e.g. astronomy applications. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 16 +- drivers/staging/easycap/easycap_ioctl.c | 338 +++++++++++++++++++++++++---- drivers/staging/easycap/easycap_main.c | 78 ++++--- drivers/staging/easycap/easycap_settings.c | 268 +++++++++++++++++++---- 4 files changed, 579 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 20e51ddec1e1..7c4cf7a338c4 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -200,7 +200,17 @@ #define NTSC_M_JP 5 #define PAL_60 7 #define PAL_M 9 -#define STANDARD_MANY 10 +#define PAL_BGHIN_SLOW 10 +#define PAL_Nc_SLOW 12 +#define SECAM_SLOW 14 +#define NTSC_N_SLOW 16 +#define NTSC_N_443_SLOW 18 +#define NTSC_M_SLOW 11 +#define NTSC_443_SLOW 13 +#define NTSC_M_JP_SLOW 15 +#define PAL_60_SLOW 17 +#define PAL_M_SLOW 19 +#define STANDARD_MANY 20 /*---------------------------------------------------------------------------*/ /* * ENUMS @@ -228,7 +238,6 @@ PIXELFORMAT_MANY enum { FIELD_NONE, FIELD_INTERLACED, -FIELD_ALTERNATE, INTERLACE_MANY }; #define SETTINGS_MANY (STANDARD_MANY * \ @@ -333,6 +342,8 @@ bool ntsc; int fps; int usec; int tolerate; +int skip; +int skipped; int merit[180]; struct timeval timeval0; @@ -399,7 +410,6 @@ int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */ */ /*---------------------------------------------------------------------------*/ __u32 pixelformat; -__u32 field; int width; int height; int bytesperpixel; diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 0ed37c23c7ec..3fe13851aba0 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -40,6 +40,7 @@ * peasycap->fps * peasycap->usec * peasycap->tolerate + * peasycap->skip */ /*---------------------------------------------------------------------------*/ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) @@ -60,10 +61,18 @@ if ((struct usb_device *)NULL == peasycap->pusb_device) { } peasycap_standard = &easycap_standard[0]; while (0xFFFF != peasycap_standard->mask) { - if (std_id & peasycap_standard->v4l2_standard.id) + if (std_id == peasycap_standard->v4l2_standard.id) break; peasycap_standard++; } +if (0xFFFF == peasycap_standard->mask) { + peasycap_standard = &easycap_standard[0]; + while (0xFFFF != peasycap_standard->mask) { + if (std_id & peasycap_standard->v4l2_standard.id) + break; + peasycap_standard++; + } +} if (0xFFFF == peasycap_standard->mask) { SAM("ERROR: 0x%08X=std_id: standard not found\n", \ (unsigned int)std_id); @@ -92,10 +101,12 @@ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \ peasycap_standard->v4l2_standard.frameperiod.numerator; switch (peasycap->fps) { +case 6: case 30: { peasycap->ntsc = true; break; } +case 5: case 25: { peasycap->ntsc = false; break; @@ -106,9 +117,15 @@ default: { } } JOM(8, "%i frames-per-second\n", peasycap->fps); -peasycap->usec = 1000000 / (2 * peasycap->fps); -peasycap->tolerate = 1000 * (25 / peasycap->fps); - +if (0x8000 & peasycap_standard->mask) { + peasycap->skip = 5; + peasycap->usec = 1000000 / (2 * (5 * peasycap->fps)); + peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps)); +} else { + peasycap->skip = 0; + peasycap->usec = 1000000 / (2 * peasycap->fps); + peasycap->tolerate = 1000 * (25 / peasycap->fps); +} if (peasycap->video_isoc_streaming) { resubmit = true; kill_video_urbs(peasycap); @@ -311,7 +328,6 @@ return 0; * peasycap->format_offset * peasycap->inputset[peasycap->input].format_offset * peasycap->pixelformat - * peasycap->field * peasycap->height * peasycap->width * peasycap->bytesperpixel @@ -333,7 +349,7 @@ struct easycap_format *peasycap_format, *peasycap_best_format; __u16 mask; struct usb_device *p; int miss, multiplier, best, k; -char bf[5], *pc; +char bf[5], fo[32], *pc; __u32 uc; bool resubmit; @@ -351,13 +367,62 @@ if ((struct usb_device *)NULL == p) { return -EFAULT; } pc = &bf[0]; -uc = pixelformat; memcpy((void *)pc, (void *)(&uc), 4); bf[4] = 0; -mask = easycap_standard[peasycap->standard_offset].mask; +uc = pixelformat; +memcpy((void *)pc, (void *)(&uc), 4); +bf[4] = 0; +mask = 0xFF & easycap_standard[peasycap->standard_offset].mask; SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \ width, height, pc, pixelformat, field, mask); +switch (field) { +case V4L2_FIELD_ANY: { + strcpy(&fo[0], "V4L2_FIELD_ANY "); + break; +} +case V4L2_FIELD_NONE: { + strcpy(&fo[0], "V4L2_FIELD_NONE"); + break; +} +case V4L2_FIELD_TOP: { + strcpy(&fo[0], "V4L2_FIELD_TOP"); + break; +} +case V4L2_FIELD_BOTTOM: { + strcpy(&fo[0], "V4L2_FIELD_BOTTOM"); + break; +} +case V4L2_FIELD_INTERLACED: { + strcpy(&fo[0], "V4L2_FIELD_INTERLACED"); + break; +} +case V4L2_FIELD_SEQ_TB: { + strcpy(&fo[0], "V4L2_FIELD_SEQ_TB"); + break; +} +case V4L2_FIELD_SEQ_BT: { + strcpy(&fo[0], "V4L2_FIELD_SEQ_BT"); + break; +} +case V4L2_FIELD_ALTERNATE: { + strcpy(&fo[0], "V4L2_FIELD_ALTERNATE"); + break; +} +case V4L2_FIELD_INTERLACED_TB: { + strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB"); + break; +} +case V4L2_FIELD_INTERLACED_BT: { + strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT"); + break; +} +default: { + strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN "); + break; +} +} +SAM("sought: %s\n", &fo[0]); if (V4L2_FIELD_ANY == field) { - field = V4L2_FIELD_INTERLACED; - SAM("prefer: V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n"); + field = V4L2_FIELD_NONE; + SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n"); } peasycap_best_format = (struct easycap_format *)NULL; peasycap_format = &easycap_format[0]; @@ -369,7 +434,7 @@ while (0 != peasycap_format->v4l2_format.fmt.pix.width) { peasycap_format->v4l2_format.fmt.pix.width, peasycap_format->v4l2_format.fmt.pix.height); - if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ + if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \ (peasycap_format->v4l2_format.fmt.pix.field == field) && \ (peasycap_format->v4l2_format.fmt.pix.pixelformat == \ pixelformat) && \ @@ -385,7 +450,7 @@ if (0 == peasycap_format->v4l2_format.fmt.pix.width) { width, height, mask); peasycap_format = &easycap_format[0]; best = -1; while (0 != peasycap_format->v4l2_format.fmt.pix.width) { - if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \ + if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \ (peasycap_format->v4l2_format.fmt.pix\ .field == field) && \ (peasycap_format->v4l2_format.fmt.pix\ @@ -432,7 +497,6 @@ SAM("actioning: %ix%i %s\n", \ peasycap->height = peasycap_format->v4l2_format.fmt.pix.height; peasycap->width = peasycap_format->v4l2_format.fmt.pix.width; peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat; -peasycap->field = peasycap_format->v4l2_format.fmt.pix.field; peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]); @@ -451,11 +515,15 @@ if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { -peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ; +peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ; if (0x0100 & peasycap_format->mask) peasycap->byteswaporder = true; else peasycap->byteswaporder = false; +if (0x0200 & peasycap_format->mask) + peasycap->skip = 5; +else + peasycap->skip = 0; if (0x0800 & peasycap_format->mask) peasycap->decimatepixel = true; else @@ -472,24 +540,6 @@ peasycap->videofieldamount = multiplier * peasycap->width * \ multiplier * peasycap->height; peasycap->frame_buffer_used = peasycap->bytesperpixel * \ peasycap->width * peasycap->height; - -if (true == peasycap->offerfields) { - SAM("WARNING: %i=peasycap->field is untested: " \ - "please report problems\n", peasycap->field); - - -/* - * FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT: - * - * peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2; - * - * SO DO NOT RISK IT YET. - * - */ - - - -} if (peasycap->video_isoc_streaming) { resubmit = true; kill_video_urbs(peasycap); @@ -1386,13 +1436,191 @@ case VIDIOC_ENUM_FMT: { break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* + * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE + * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUM_FRAMESIZES: { - JOM(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n"); - return -EINVAL; + __u32 index; + struct v4l2_frmsizeenum v4l2_frmsizeenum; + + JOM(8, "VIDIOC_ENUM_FRAMESIZES\n"); + + if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \ + sizeof(struct v4l2_frmsizeenum))) + return -EFAULT; + + index = v4l2_frmsizeenum.index; + + v4l2_frmsizeenum.type = (__u32) V4L2_FRMSIZE_TYPE_DISCRETE; + + if (true == peasycap->ntsc) { + switch (index) { + case 0: { + v4l2_frmsizeenum.discrete.width = 640; + v4l2_frmsizeenum.discrete.height = 480; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 1: { + v4l2_frmsizeenum.discrete.width = 320; + v4l2_frmsizeenum.discrete.height = 240; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 2: { + v4l2_frmsizeenum.discrete.width = 720; + v4l2_frmsizeenum.discrete.height = 480; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 3: { + v4l2_frmsizeenum.discrete.width = 360; + v4l2_frmsizeenum.discrete.height = 240; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + default: { + JOM(8, "%i=index: exhausts framesizes\n", index); + return -EINVAL; + } + } + } else { + switch (index) { + case 0: { + v4l2_frmsizeenum.discrete.width = 640; + v4l2_frmsizeenum.discrete.height = 480; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 1: { + v4l2_frmsizeenum.discrete.width = 320; + v4l2_frmsizeenum.discrete.height = 240; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 2: { + v4l2_frmsizeenum.discrete.width = 704; + v4l2_frmsizeenum.discrete.height = 576; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 3: { + v4l2_frmsizeenum.discrete.width = 720; + v4l2_frmsizeenum.discrete.height = 576; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + case 4: { + v4l2_frmsizeenum.discrete.width = 360; + v4l2_frmsizeenum.discrete.height = 288; + JOM(8, "%i=index: %ix%i\n", index, \ + (int)(v4l2_frmsizeenum.\ + discrete.width), \ + (int)(v4l2_frmsizeenum.\ + discrete.height)); + break; + } + default: { + JOM(8, "%i=index: exhausts framesizes\n", index); + return -EINVAL; + } + } + } + if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \ + sizeof(struct v4l2_frmsizeenum))) + return -EFAULT; + break; } +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* + * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE + * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUM_FRAMEINTERVALS: { - JOM(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n"); - return -EINVAL; + __u32 index; + int denominator; + struct v4l2_frmivalenum v4l2_frmivalenum; + + JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n"); + + if (peasycap->fps) + denominator = peasycap->fps; + else { + if (true == peasycap->ntsc) + denominator = 30; + else + denominator = 25; + } + + if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \ + sizeof(struct v4l2_frmivalenum))) + return -EFAULT; + + index = v4l2_frmivalenum.index; + + v4l2_frmivalenum.type = (__u32) V4L2_FRMIVAL_TYPE_DISCRETE; + + switch (index) { + case 0: { + v4l2_frmivalenum.discrete.numerator = 1; + v4l2_frmivalenum.discrete.denominator = denominator; + JOM(8, "%i=index: %i/%i\n", index, \ + (int)(v4l2_frmivalenum.discrete.numerator), \ + (int)(v4l2_frmivalenum.discrete.denominator)); + break; + } + case 1: { + v4l2_frmivalenum.discrete.numerator = 1; + v4l2_frmivalenum.discrete.denominator = denominator/5; + JOM(8, "%i=index: %i/%i\n", index, \ + (int)(v4l2_frmivalenum.discrete.numerator), \ + (int)(v4l2_frmivalenum.discrete.denominator)); + break; + } + default: { + JOM(8, "%i=index: exhausts frameintervals\n", index); + return -EINVAL; + } + } + if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \ + sizeof(struct v4l2_frmivalenum))) + return -EFAULT; + break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_FMT: { @@ -1603,6 +1831,10 @@ case VIDIOC_S_STD: { sizeof(v4l2_std_id))) return -EFAULT; + JOM(8, "User requests standard: 0x%08X%08X\n", \ + (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \ + (int)(std_id & ((v4l2_std_id)0xFFFFFFFF))); + rc = adjust_standard(peasycap, std_id); if (0 > rc) { JOM(8, "WARNING: adjust_standard() returned %i\n", rc); @@ -1675,7 +1907,7 @@ case VIDIOC_QUERYBUF: { v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \ peasycap->done[index] | \ peasycap->queued[index]; - v4l2_buffer.field = peasycap->field; + v4l2_buffer.field = V4L2_FIELD_NONE; v4l2_buffer.memory = V4L2_MEMORY_MMAP; v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE; v4l2_buffer.length = FRAME_BUFFER_SIZE; @@ -1762,6 +1994,24 @@ case VIDIOC_DQBUF: if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + if (true == peasycap->offerfields) { + /*-----------------------------------------------------------*/ + /* + * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST + * V4L2_FIELD_BOTTOM + */ + /*-----------------------------------------------------------*/ + if (V4L2_FIELD_TOP == v4l2_buffer.field) + JOM(8, "user wants V4L2_FIELD_TOP\n"); + else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field) + JOM(8, "user wants V4L2_FIELD_BOTTOM\n"); + else if (V4L2_FIELD_ANY == v4l2_buffer.field) + JOM(8, "user wants V4L2_FIELD_ANY\n"); + else + JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", \ + v4l2_buffer.field); + } + if (!peasycap->video_isoc_streaming) { JOM(16, "returning -EIO because video urbs not streaming\n"); return -EIO; @@ -1811,11 +2061,10 @@ case VIDIOC_DQBUF: v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2_buffer.bytesused = peasycap->frame_buffer_used; v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; - v4l2_buffer.field = peasycap->field; - if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field) - v4l2_buffer.field = \ - 0x000F & (peasycap->\ - frame_buffer[peasycap->frame_read][0].kount); + if (true == peasycap->offerfields) + v4l2_buffer.field = V4L2_FIELD_BOTTOM; + else + v4l2_buffer.field = V4L2_FIELD_NONE; do_gettimeofday(&timeval); timeval2 = timeval; @@ -1876,10 +2125,6 @@ case VIDIOC_DQBUF: sizeof(struct v4l2_buffer))) return -EFAULT; - JOM(8, "..... user is offered frame buffer %i\n", \ - peasycap->frame_read); - peasycap->frame_lock = 1; - input = peasycap->frame_buffer[peasycap->frame_read][0].input; if (0x08 & input) { JOM(8, "user is offered frame buffer %i, input %i\n", \ @@ -1956,7 +2201,6 @@ case VIDIOC_G_PARM: { v4l2_streamparm.parm.capture.capability = 0; v4l2_streamparm.parm.capture.capturemode = 0; v4l2_streamparm.parm.capture.timeperframe.numerator = 1; - v4l2_streamparm.parm.capture.timeperframe.denominator = 30; if (peasycap->fps) { v4l2_streamparm.parm.capture.timeperframe.\ diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index b522c6eb65f6..988feee7bcbe 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -471,7 +471,7 @@ if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -ENODEV; } -rc = usb_set_interface(peasycap->pusb_device, \ +rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \ peasycap->video_altsetting_off); if (0 != rc) { @@ -1103,7 +1103,7 @@ else int easycap_dqbuf(struct easycap *peasycap, int mode) { -int miss, rc; +int ifield, miss, rc; JOT(8, "\n"); @@ -1111,16 +1111,18 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +ifield = 0; +JOM(8, "%i=ifield\n", ifield); /*---------------------------------------------------------------------------*/ /* - * WAIT FOR FIELD 0 + * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM) */ /*---------------------------------------------------------------------------*/ miss = 0; while ((peasycap->field_read == peasycap->field_fill) || \ (0 != (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) || \ - (0 != (0x00FF & peasycap->field_buffer\ + (ifield != (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))) { if (mode) return -EAGAIN; @@ -1134,7 +1136,7 @@ while ((peasycap->field_read == peasycap->field_fill) || \ ((peasycap->field_read != peasycap->field_fill) && \ (0 == (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) && \ - (0 == (0x00FF & peasycap->field_buffer\ + (ifield == (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))))))) { SAM("aborted by signal\n"); return -EIO; @@ -1176,33 +1178,20 @@ JOM(8, "first awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); if (0 != rc) SAM("ERROR: field2frame() returned %i\n", rc); - -if (true == peasycap->offerfields) { - peasycap->frame_read = peasycap->frame_fill; - (peasycap->frame_fill)++; - if (peasycap->frame_buffer_many <= peasycap->frame_fill) - peasycap->frame_fill = 0; - - if (0x01 & easycap_standard[peasycap->standard_offset].mask) { - peasycap->frame_buffer[peasycap->frame_read][0].kount = \ - V4L2_FIELD_BOTTOM; - } else { - peasycap->frame_buffer[peasycap->frame_read][0].kount = \ - V4L2_FIELD_TOP; - } -JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); -JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); -} /*---------------------------------------------------------------------------*/ /* - * WAIT FOR FIELD 1 + * WAIT FOR THE OTHER FIELD */ /*---------------------------------------------------------------------------*/ +if (ifield) + ifield = 0; +else + ifield = 1; miss = 0; while ((peasycap->field_read == peasycap->field_fill) || \ (0 != (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) || \ - (0 == (0x00FF & peasycap->field_buffer\ + (ifield != (0x00FF & peasycap->field_buffer\ [peasycap->field_read][0].kount))) { if (mode) return -EAGAIN; @@ -1215,8 +1204,9 @@ while ((peasycap->field_read == peasycap->field_fill) || \ ((peasycap->field_read != peasycap->field_fill) && \ (0 == (0xFF00 & peasycap->field_buffer\ [peasycap->field_read][0].kount)) && \ - (0 != (0x00FF & peasycap->field_buffer\ - [peasycap->field_read][0].kount))))))) { + (ifield == (0x00FF & peasycap->field_buffer\ + [peasycap->field_read][0].\ + kount))))))) { SAM("aborted by signal\n"); return -EIO; } @@ -1257,7 +1247,18 @@ JOM(8, "second awakening on wq_video after %i waits\n", miss); rc = field2frame(peasycap); if (0 != rc) SAM("ERROR: field2frame() returned %i\n", rc); - +/*---------------------------------------------------------------------------*/ +/* + * WASTE THIS FRAME +*/ +/*---------------------------------------------------------------------------*/ +if (0 != peasycap->skip) { + peasycap->skipped++; + if (peasycap->skip != peasycap->skipped) + return peasycap->skip - peasycap->skipped; + peasycap->skipped = 0; +} +/*---------------------------------------------------------------------------*/ peasycap->frame_read = peasycap->frame_fill; peasycap->queued[peasycap->frame_read] = 0; peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE; @@ -1289,8 +1290,7 @@ return 0; * odd==false IS TRANSFERRED TO THE FRAME BUFFER. * * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM - * CHOOSES THE OPTION V4L2_FIELD_ALTERNATE. NO USERSPACE PROGRAM TESTED - * TO DATE HAS DONE THIS. BUGS ARE LIKELY. + * CHOOSES THE OPTION V4L2_FIELD_INTERLACED. */ /*---------------------------------------------------------------------------*/ int @@ -1315,8 +1315,10 @@ if ((struct easycap *)NULL == peasycap) { badinput = false; -JOM(8, "===== parity %i, field buffer %i --> frame buffer %i\n", \ +JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> " \ + "frame buffer %i\n", \ peasycap->field_buffer[peasycap->field_read][0].kount,\ + peasycap->field_buffer[peasycap->field_read][0].input,\ peasycap->field_read, peasycap->frame_fill); JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); if (true == peasycap->offerfields) @@ -1374,7 +1376,7 @@ if (peasycap->field_buffer[kex][0].kount) else odd = false; -if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) { +if ((true == odd) && (false == decimatepixel)) { JOM(8, " initial skipping %4i bytes p.%4i\n", \ w3/multiplier, mad); pad += (w3 / multiplier); rad -= (w3 / multiplier); @@ -1494,7 +1496,7 @@ while (cz < wz) { * UNLESS IT IS THE LAST LINE OF AN ODD FRAME */ /*---------------------------------------------------------------------------*/ - if (((false == odd) || (cz != wz))&&(false == offerfields)) { + if ((false == odd) || (cz != wz)) { over = w3; do { if (!rad) { @@ -3162,6 +3164,15 @@ if (purb->status) { [peasycap->field_page]; pfield_buffer->pto = \ pfield_buffer->pgo; + pfield_buffer->input = 0x08 | \ + (0x07 & peasycap->input); + if ((peasycap->field_buffer[peasycap->\ + field_fill][0]).\ + input != \ + pfield_buffer->input) + (peasycap->field_buffer\ + [peasycap->field_fill]\ + [0]).kount |= 0x1000; } much = PAGE_SIZE - (int)(pfield_buffer->pto - \ @@ -3441,7 +3452,6 @@ if (0 == bInterfaceNumber) { break; } } - if (DONGLE_MANY <= dongle_this) { SAM("ERROR: too many dongles\n"); return -ENOMEM; @@ -3481,6 +3491,8 @@ if (0 == bInterfaceNumber) { peasycap->frame_buffer_many = FRAME_BUFFER_MANY; + peasycap->skip = 0; + peasycap->skipped = 0; peasycap->offerfields = 0; /*---------------------------------------------------------------------------*/ /* diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c index 67f2e4f27323..df3f17d361b1 100644 --- a/drivers/staging/easycap/easycap_settings.c +++ b/drivers/staging/easycap/easycap_settings.c @@ -33,11 +33,15 @@ * THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING: * 0 => 25 fps * 1 => 30 fps + * + * THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING: + * 0 => full framerate + * 1 => 20% framerate */ /*---------------------------------------------------------------------------*/ const struct easycap_standard easycap_standard[] = { { -.mask = 0x000F & PAL_BGHIN , +.mask = 0x00FF & PAL_BGHIN , .v4l2_standard = { .index = PAL_BGHIN, .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \ @@ -50,7 +54,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_N_443 , +.mask = 0x00FF & NTSC_N_443 , .v4l2_standard = { .index = NTSC_N_443, .id = V4L2_STD_UNKNOWN, @@ -62,7 +66,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & PAL_Nc , +.mask = 0x00FF & PAL_Nc , .v4l2_standard = { .index = PAL_Nc, .id = V4L2_STD_PAL_Nc, @@ -74,7 +78,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_N , +.mask = 0x00FF & NTSC_N , .v4l2_standard = { .index = NTSC_N, .id = V4L2_STD_UNKNOWN, @@ -86,7 +90,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & SECAM , +.mask = 0x00FF & SECAM , .v4l2_standard = { .index = SECAM, .id = V4L2_STD_SECAM, @@ -98,7 +102,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_M , +.mask = 0x00FF & NTSC_M , .v4l2_standard = { .index = NTSC_M, .id = V4L2_STD_NTSC_M, @@ -110,7 +114,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_M_JP , +.mask = 0x00FF & NTSC_M_JP , .v4l2_standard = { .index = NTSC_M_JP, .id = V4L2_STD_NTSC_M_JP, @@ -122,7 +126,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & PAL_60 , +.mask = 0x00FF & PAL_60 , .v4l2_standard = { .index = PAL_60, .id = V4L2_STD_PAL_60, @@ -134,7 +138,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & NTSC_443 , +.mask = 0x00FF & NTSC_443 , .v4l2_standard = { .index = NTSC_443, .id = V4L2_STD_NTSC_443, @@ -146,7 +150,7 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { -.mask = 0x000F & PAL_M , +.mask = 0x00FF & PAL_M , .v4l2_standard = { .index = PAL_M, .id = V4L2_STD_PAL_M, @@ -158,6 +162,128 @@ const struct easycap_standard easycap_standard[] = { }, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ { +.mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW), +.v4l2_standard = { + .index = PAL_BGHIN_SLOW, + .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \ + V4L2_STD_PAL_I | V4L2_STD_PAL_N | \ + (((v4l2_std_id)0x01) << 32)), + .name = "PAL_BGHIN_SLOW", + .frameperiod = {1, 5}, + .framelines = 625, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW), +.v4l2_standard = { + .index = NTSC_N_443_SLOW, + .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)), + .name = "NTSC_N_443_SLOW", + .frameperiod = {1, 5}, + .framelines = 480, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & PAL_Nc_SLOW), +.v4l2_standard = { + .index = PAL_Nc_SLOW, + .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)), + .name = "PAL_Nc_SLOW", + .frameperiod = {1, 5}, + .framelines = 625, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_N_SLOW), +.v4l2_standard = { + .index = NTSC_N_SLOW, + .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)), + .name = "NTSC_N_SLOW", + .frameperiod = {1, 5}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & SECAM_SLOW), +.v4l2_standard = { + .index = SECAM_SLOW, + .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)), + .name = "SECAM_SLOW", + .frameperiod = {1, 5}, + .framelines = 625, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_M_SLOW), +.v4l2_standard = { + .index = NTSC_M_SLOW, + .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)), + .name = "NTSC_M_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW), +.v4l2_standard = { + .index = NTSC_M_JP_SLOW, + .id = (V4L2_STD_NTSC_M_JP | (((v4l2_std_id)0x01) << 32)), + .name = "NTSC_M_JP_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & PAL_60_SLOW), +.v4l2_standard = { + .index = PAL_60_SLOW, + .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)), + .name = "PAL_60_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & NTSC_443_SLOW), +.v4l2_standard = { + .index = NTSC_443_SLOW, + .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)), + .name = "NTSC_443_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ +.mask = 0x8000 | (0x00FF & PAL_M_SLOW), +.v4l2_standard = { + .index = PAL_M_SLOW, + .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)), + .name = "PAL_M_SLOW", + .frameperiod = {1, 6}, + .framelines = 525, + .reserved = {0, 0, 0, 0} +} +}, +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +{ .mask = 0xFFFF } }; @@ -165,15 +291,16 @@ const struct easycap_standard easycap_standard[] = { /* * THE 16-BIT easycap_format.mask HAS MEANING: * (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS - * BITS 1-3: RESERVED FOR DIFFERENTIATING STANDARDS - * BITS 4-7: NUMBER OF BYTES PER PIXEL + * BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS + * BITS 5-7: NUMBER OF BYTES PER PIXEL * BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED * BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS - * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED - * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS - * (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS + * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED + * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS + * BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED + * (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS * IT FOLLOWS THAT: - * bytesperpixel IS ((0x00F0 & easycap_format.mask) >> 4) + * bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5) * byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask)) * * decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask)) @@ -197,65 +324,135 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) { mask1 = 0x0000; switch (i) { case PAL_BGHIN: { - mask1 = PAL_BGHIN; + mask1 = 0x1F & PAL_BGHIN; strcpy(&name1[0], "PAL_BGHIN"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case SECAM: { - mask1 = SECAM; + mask1 = 0x1F & SECAM; strcpy(&name1[0], "SECAM"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case PAL_Nc: { - mask1 = PAL_Nc; + mask1 = 0x1F & PAL_Nc; strcpy(&name1[0], "PAL_Nc"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case PAL_60: { - mask1 = PAL_60; + mask1 = 0x1F & PAL_60; strcpy(&name1[0], "PAL_60"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case PAL_M: { - mask1 = PAL_M; + mask1 = 0x1F & PAL_M; strcpy(&name1[0], "PAL_M"); colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; break; } case NTSC_M: { - mask1 = NTSC_M; + mask1 = 0x1F & NTSC_M; strcpy(&name1[0], "NTSC_M"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_443: { - mask1 = NTSC_443; + mask1 = 0x1F & NTSC_443; strcpy(&name1[0], "NTSC_443"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_M_JP: { - mask1 = NTSC_M_JP; + mask1 = 0x1F & NTSC_M_JP; strcpy(&name1[0], "NTSC_M_JP"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_N: { - mask1 = NTSC_M; + mask1 = 0x1F & NTSC_M; strcpy(&name1[0], "NTSC_N"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } case NTSC_N_443: { - mask1 = NTSC_N_443; + mask1 = 0x1F & NTSC_N_443; strcpy(&name1[0], "NTSC_N_443"); colorspace = V4L2_COLORSPACE_470_SYSTEM_M; break; } + case PAL_BGHIN_SLOW: { + mask1 = 0x001F & PAL_BGHIN_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_BGHIN_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case SECAM_SLOW: { + mask1 = 0x001F & SECAM_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "SECAM_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case PAL_Nc_SLOW: { + mask1 = 0x001F & PAL_Nc_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_Nc_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case PAL_60_SLOW: { + mask1 = 0x001F & PAL_60_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_60_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case PAL_M_SLOW: { + mask1 = 0x001F & PAL_M_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "PAL_M_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; + break; + } + case NTSC_M_SLOW: { + mask1 = 0x001F & NTSC_M_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_M_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_443_SLOW: { + mask1 = 0x001F & NTSC_443_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_443_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_M_JP_SLOW: { + mask1 = 0x001F & NTSC_M_JP_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_M_JP_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_N_SLOW: { + mask1 = 0x001F & NTSC_N_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_N_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } + case NTSC_N_443_SLOW: { + mask1 = 0x001F & NTSC_N_443_SLOW; + mask1 |= 0x0200; + strcpy(&name1[0], "NTSC_N_443_SLOW"); + colorspace = V4L2_COLORSPACE_470_SYSTEM_M; + break; + } default: return -1; } @@ -311,39 +508,39 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) { case FMT_UYVY: { strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY)); pixelformat = V4L2_PIX_FMT_UYVY; - mask3 |= (0x02 << 4); + mask3 |= (0x02 << 5); break; } case FMT_YUY2: { strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2)); pixelformat = V4L2_PIX_FMT_YUYV; - mask3 |= (0x02 << 4); + mask3 |= (0x02 << 5); mask3 |= 0x0100; break; } case FMT_RGB24: { strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24)); pixelformat = V4L2_PIX_FMT_RGB24; - mask3 |= (0x03 << 4); + mask3 |= (0x03 << 5); break; } case FMT_RGB32: { strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32)); pixelformat = V4L2_PIX_FMT_RGB32; - mask3 |= (0x04 << 4); + mask3 |= (0x04 << 5); break; } case FMT_BGR24: { strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24)); pixelformat = V4L2_PIX_FMT_BGR24; - mask3 |= (0x03 << 4); + mask3 |= (0x03 << 5); mask3 |= 0x0100; break; } case FMT_BGR32: { strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32)); pixelformat = V4L2_PIX_FMT_BGR32; - mask3 |= (0x04 << 4); + mask3 |= (0x04 << 5); mask3 |= 0x0100; break; } @@ -363,13 +560,8 @@ for (i = 0, n = 0; i < STANDARD_MANY; i++) { } case FIELD_INTERLACED: { strcpy(&name4[0], "-i"); - field = V4L2_FIELD_INTERLACED; - break; - } - case FIELD_ALTERNATE: { - strcpy(&name4[0], "-a"); mask4 |= 0x1000; - field = V4L2_FIELD_ALTERNATE; + field = V4L2_FIELD_INTERLACED; break; } default: -- cgit v1.2.3 From 849322a0f114e52d05e16fe8349843c980cff2c6 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:03:50 +0000 Subject: staging/easycap: Add option to show conspicuous indication of signal loss A new module parameter turns on the option of displaying a testcard when the analogue input signal is lost (more precisely: when the hardware detects no field/frame synchronization). This feature has been requested in the context of security cameras used at night. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 2 + drivers/staging/easycap/easycap_main.c | 71 ++++++++++++++++++++------ drivers/staging/easycap/easycap_testcard.c | 80 ++++++++++++++++++++---------- 3 files changed, 112 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 7c4cf7a338c4..e9410b74ffc4 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -154,6 +154,7 @@ #error video_isoc_buffer[.] will not be big enough #endif #define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY +#define VIDEO_LOST_TOLERATE 50 /*---------------------------------------------------------------------------*/ /* * VIDEO BUFFERS @@ -344,6 +345,7 @@ int usec; int tolerate; int skip; int skipped; +int lost[INPUT_MANY]; int merit[180]; struct timeval timeval0; diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index 988feee7bcbe..21450e83530f 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -33,7 +33,9 @@ #include "easycap_ioctl.h" int debug; +int bars; module_param(debug, int, S_IRUGO | S_IWUSR); +module_param(bars, int, S_IRUGO | S_IWUSR); /*---------------------------------------------------------------------------*/ /* @@ -868,7 +870,7 @@ return 0; void easycap_delete(struct kref *pkref) { -int k, m, lost; +int k, m, gone; int allocation_video_urb, allocation_video_page, allocation_video_struct; int allocation_audio_urb, allocation_audio_page, allocation_audio_struct; int registered_video, registered_audio; @@ -941,7 +943,7 @@ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) { JOM(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER)); /*---------------------------------------------------------------------------*/ JOM(4, "freeing video field buffers.\n"); -lost = 0; +gone = 0; for (k = 0; k < FIELD_BUFFER_MANY; k++) { for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) { if ((void *)NULL != peasycap->field_buffer[k][m].pgo) { @@ -949,14 +951,14 @@ for (k = 0; k < FIELD_BUFFER_MANY; k++) { (peasycap->field_buffer[k][m].pgo)); peasycap->field_buffer[k][m].pgo = (void *)NULL; peasycap->allocation_video_page -= 1; - lost++; + gone++; } } } -JOM(4, "video field buffers freed: %i pages\n", lost); +JOM(4, "video field buffers freed: %i pages\n", gone); /*---------------------------------------------------------------------------*/ JOM(4, "freeing video frame buffers.\n"); -lost = 0; +gone = 0; for (k = 0; k < FRAME_BUFFER_MANY; k++) { for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) { if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) { @@ -964,11 +966,11 @@ for (k = 0; k < FRAME_BUFFER_MANY; k++) { (peasycap->frame_buffer[k][m].pgo)); peasycap->frame_buffer[k][m].pgo = (void *)NULL; peasycap->allocation_video_page -= 1; - lost++; + gone++; } } } -JOM(4, "video frame buffers freed: %i pages\n", lost); +JOM(4, "video frame buffers freed: %i pages\n", gone); /*---------------------------------------------------------------------------*/ /* * FREE AUDIO. @@ -1027,16 +1029,16 @@ JOM(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \ m * (0x01 << AUDIO_ISOC_ORDER)); /*---------------------------------------------------------------------------*/ JOM(4, "freeing audio buffers.\n"); -lost = 0; +gone = 0; for (k = 0; k < peasycap->audio_buffer_page_many; k++) { if ((void *)NULL != peasycap->audio_buffer[k].pgo) { free_page((unsigned long)(peasycap->audio_buffer[k].pgo)); peasycap->audio_buffer[k].pgo = (void *)NULL; peasycap->allocation_audio_page -= 1; - lost++; + gone++; } } -JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost); +JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", gone); /*---------------------------------------------------------------------------*/ JOM(4, "freeing easycap structure.\n"); allocation_video_urb = peasycap->allocation_video_urb; @@ -1103,7 +1105,7 @@ else int easycap_dqbuf(struct easycap *peasycap, int mode) { -int ifield, miss, rc; +int input, ifield, miss, rc; JOT(8, "\n"); @@ -1114,6 +1116,36 @@ if (NULL == peasycap) { ifield = 0; JOM(8, "%i=ifield\n", ifield); /*---------------------------------------------------------------------------*/ +/* + * CHECK FOR LOST INPUT SIGNAL. + * + * FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED. + * IF INPUT 0 IS PRESENT AND LOCKED, UNPLUGGING INPUT 4 DOES NOT RESULT IN + * SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE IS FLYWHEELING + * ON INPUT 0. THE UPSHOT IS: + * + * INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK + * INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK + * INPUT 0 UNPLUGGED, INPUT 4 PLUGGED => SCREEN 0 BARS, SCREEN 4 OK + * INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS +*/ +/*---------------------------------------------------------------------------*/ +input = peasycap->input; +if (0 <= input && INPUT_MANY > input) { + rc = read_saa(peasycap->pusb_device, 0x1F); + if (0 <= rc) { + if (rc & 0x40) + peasycap->lost[input] += 1; + else + peasycap->lost[input] -= 2; + + if (0 > peasycap->lost[input]) + peasycap->lost[input] = 0; + else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input]) + peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE); + } +} +/*---------------------------------------------------------------------------*/ /* * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM) */ @@ -1304,7 +1336,7 @@ struct signed_div_result sdr; void *pex, *pad; int kex, kad, mex, mad, rex, rad, rad2; int c2, c3, w2, w3, cz, wz; -int rc, bytesperpixel, multiplier, much, more, over, rump, caches; +int rc, bytesperpixel, multiplier, much, more, over, rump, caches, input; __u8 mask, margin; bool odd, isuy, decimatepixel, offerfields, badinput; @@ -1314,6 +1346,7 @@ if ((struct easycap *)NULL == peasycap) { } badinput = false; +input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input; JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> " \ "frame buffer %i\n", \ @@ -1337,8 +1370,10 @@ if (peasycap->field_read == peasycap->field_fill) { #if defined(EASYCAP_TESTCARD) easycap_testcard(peasycap, peasycap->field_read); #else -if (0 != (0x0400 & peasycap->field_buffer[peasycap->field_read][0].kount)) - easycap_testcard(peasycap, peasycap->field_read); +if (0 <= input && INPUT_MANY > input) { + if (bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input]) + easycap_testcard(peasycap, peasycap->field_read); +} #endif /*EASYCAP_TESTCARD*/ /*---------------------------------------------------------------------------*/ @@ -3491,6 +3526,8 @@ if (0 == bInterfaceNumber) { peasycap->frame_buffer_many = FRAME_BUFFER_MANY; + for (k = 0; k < INPUT_MANY; k++) + peasycap->lost[k] = 0; peasycap->skip = 0; peasycap->skipped = 0; peasycap->offerfields = 0; @@ -4733,7 +4770,7 @@ easycap_module_init(void) int result; SAY("========easycap=======\n"); -JOT(4, "begins. %i=debug\n", debug); +JOT(4, "begins. %i=debug %i=bars\n", debug, bars); SAY("version: " EASYCAP_DRIVER_VERSION "\n"); /*---------------------------------------------------------------------------*/ /* @@ -4774,6 +4811,8 @@ MODULE_AUTHOR("R.M. Thomas "); MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION); MODULE_VERSION(EASYCAP_DRIVER_VERSION); #if defined(EASYCAP_DEBUG) -MODULE_PARM_DESC(debug, "debug: 0 (default), 1, 2,..."); +MODULE_PARM_DESC(debug, "Debug level: 0 (default),1,2,...,9"); #endif /*EASYCAP_DEBUG*/ +MODULE_PARM_DESC(bars, \ + "Testcard bars on input signal failure: 0=>no, 1=>yes(default)"); /*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c index dd98b471d5b8..e27dfe9a9ba3 100644 --- a/drivers/staging/easycap/easycap_testcard.c +++ b/drivers/staging/easycap/easycap_testcard.c @@ -29,37 +29,69 @@ #include "easycap_debug.h" /*****************************************************************************/ -#define TESTCARD_BYTESPERLINE (2 * 1440) +#define TESTCARD_BYTESPERLINE (2 * 720) void -easycap_testcard(struct easycap *peasycap, int field_fill) +easycap_testcard(struct easycap *peasycap, int field) { int total; int y, u, v, r, g, b; unsigned char uyvy[4]; - -int i1, line, k, m, n, more, much, barwidth; +int i1, line, k, m, n, more, much, barwidth, barheight; unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2; struct data_buffer *pfield_buffer; -JOT(8, "%i=field_fill\n", field_fill); - -if ((TESTCARD_BYTESPERLINE / 2) < peasycap->width) { - SAY("ERROR: image is too wide\n"); +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return; +} +JOM(8, "%i=field\n", field); +switch (peasycap->width) { +case 720: +case 360: { + barwidth = (2 * 720) / 8; + break; +} +case 704: +case 352: { + barwidth = (2 * 704) / 8; + break; +} +case 640: +case 320: { + barwidth = (2 * 640) / 8; + break; +} +default: { + SAM("ERROR: cannot set barwidth\n"); return; } -if (peasycap->width % 16) { - SAY("ERROR: indivisible image width\n"); +} +if (TESTCARD_BYTESPERLINE < barwidth) { + SAM("ERROR: barwidth is too large\n"); return; } - +switch (peasycap->height) { +case 576: +case 288: { + barheight = 576; + break; +} +case 480: +case 240: { + barheight = 480; + break; +} +default: { + SAM("ERROR: cannot set barheight\n"); + return; +} +} total = 0; -barwidth = (2 * peasycap->width) / 8; - -k = field_fill; +k = field; m = 0; n = 0; -for (line = 0; line < (peasycap->height / 2); line++) { +for (line = 0; line < (barheight / 2); line++) { for (i1 = 0; i1 < 8; i1++) { r = (i1 * 256)/8; g = (i1 * 256)/8; @@ -88,15 +120,15 @@ for (line = 0; line < (peasycap->height / 2); line++) { while (more) { if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) { - SAY("ERROR: bad m reached\n"); + SAM("ERROR: bad m reached\n"); return; } if (PAGE_SIZE < n) { - SAY("ERROR: bad n reached\n"); return; + SAM("ERROR: bad n reached\n"); return; } if (0 > more) { - SAY("ERROR: internal fault\n"); + SAM("ERROR: internal fault\n"); return; } @@ -117,10 +149,6 @@ for (line = 0; line < (peasycap->height / 2); line++) { } } } - -JOT(8, "%i=total\n", total); -if (total != peasycap->width * peasycap->height) - SAY("ERROR: wrong number of bytes written: %i\n", total); return; } /*****************************************************************************/ @@ -375,10 +403,12 @@ int i1; unsigned char *p2; struct data_buffer *paudio_buffer; -JOT(8, "%i=audio_fill\n", audio_fill); - +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return; +} +JOM(8, "%i=audio_fill\n", audio_fill); paudio_buffer = &peasycap->audio_buffer[audio_fill]; - p2 = (unsigned char *)(paudio_buffer->pgo); for (i1 = 0; i1 < PAGE_SIZE; i1 += 4, p2 += 4) { *p2 = (unsigned char) (0x00FF & tones[i1/2]); -- cgit v1.2.3 From 94155cf4195bb3be0068481dc21e8688eda2e051 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:05:51 +0000 Subject: staging/easycap: Add option to set the hardware audio gain A new module parameter adjusts the gain of the AC'97 audio chip, if one is present. Attenuation as well as amplification should be possible according to the datasheet, but attenuation seems not to work yet. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap_debug.h | 1 + drivers/staging/easycap/easycap_ioctl.c | 14 +++- drivers/staging/easycap/easycap_low.c | 120 +++++++++++++++++++++----------- drivers/staging/easycap/easycap_main.c | 8 ++- 4 files changed, 96 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h index a4dcd7dd4a89..7042fe8e31fe 100644 --- a/drivers/staging/easycap/easycap_debug.h +++ b/drivers/staging/easycap/easycap_debug.h @@ -25,3 +25,4 @@ */ /*****************************************************************************/ extern int debug; +extern int gain; diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 3fe13851aba0..7c46cb22daeb 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -873,18 +873,26 @@ i1 = 0; while (0xFFFFFFFF != easycap_control[i1].id) { if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) { if ((easycap_control[i1].minimum > value) || \ - (easycap_control[i1].maximum < value)) + (easycap_control[i1].maximum < value)) value = easycap_control[i1].default_value; + if ((easycap_control[i1].minimum <= peasycap->volume) && \ + (easycap_control[i1].maximum >= \ + peasycap->volume)) { + if (peasycap->volume == value) { + SAM("unchanged volume at 0x%02X\n", value); + return 0; + } + } peasycap->volume = value; mood = (16 > peasycap->volume) ? 16 : \ ((31 < peasycap->volume) ? 31 : \ (__s8) peasycap->volume); if (!audio_gainset(peasycap->pusb_device, mood)) { - SAM("adjusting volume to 0x%01X\n", mood); + SAM("adjusting volume to 0x%02X\n", mood); return 0; } else { SAM("WARNING: failed to adjust volume to " \ - "0x%1X\n", mood); + "0x%2X\n", mood); return -ENOENT; } break; diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index 4badef263e9e..7d778ba67ac8 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -988,9 +988,9 @@ if (NULL == peasycap) pusb_device = peasycap->pusb_device; if (NULL == pusb_device) - return -EFAULT; + return -ENODEV; -JOT(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \ +JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \ requesttype, request, \ (0x00FF & value_unmute), \ (0xFF00 & value_unmute) >> 8, \ @@ -1029,41 +1029,25 @@ if (rc != (int)length) * THE UPPER BYTE SEEMS TO HAVE NO EFFECT. */ /*--------------------------------------------------------------------------*/ - SET(pusb_device, 0x0500, 0x0094); - SET(pusb_device, 0x0500, 0x008C); - SET(pusb_device, 0x0506, 0x0001); SET(pusb_device, 0x0507, 0x0000); - id1 = read_vt(pusb_device, 0x007C); id2 = read_vt(pusb_device, 0x007E); -SAY("0x%04X:0x%04X is audio vendor id\n", id1, id2); - +SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2); /*---------------------------------------------------------------------------*/ /* -* SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0 dB. -* -* THESE COMMANDS SEEM TO BE ACCEPTED (THOUGH POSSIBLY IGNORED) EVEN WHEN -* THERE IS NO SEPARATE AUDIO CHIP PRESENT. + * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN. */ /*---------------------------------------------------------------------------*/ - -write_vt(pusb_device, 0x0002, 0x8000); -write_vt(pusb_device, 0x001C, 0x8000); - -write_vt(pusb_device, 0x000E, 0x0000); -write_vt(pusb_device, 0x0010, 0x0000); -write_vt(pusb_device, 0x0012, 0x8000); -write_vt(pusb_device, 0x0016, 0x0000); - -write_vt(pusb_device, 0x001A, 0x0404); -write_vt(pusb_device, 0x0002, 0x0000); -write_vt(pusb_device, 0x001C, 0x0000); - +if (31 < gain) + gain = 31; +if (0 > gain) + gain = 0; +if (0 != audio_gainset(pusb_device, (__s8)gain)) + SAY("ERROR: audio_gainset() failed\n"); check_vt(pusb_device); - return 0; } /*****************************************************************************/ @@ -1096,17 +1080,23 @@ if (0 > igot) if (0x8000 & igot) SAY("register 0x%02X muted\n", 0x12); +igot = read_vt(pusb_device, 0x0014); +if (0 > igot) + SAY("ERROR: failed to read VT1612A register 0x14\n"); +if (0x8000 & igot) + SAY("register 0x%02X muted\n", 0x14); + igot = read_vt(pusb_device, 0x0016); if (0 > igot) SAY("ERROR: failed to read VT1612A register 0x16\n"); if (0x8000 & igot) SAY("register 0x%02X muted\n", 0x16); -igot = read_vt(pusb_device, 0x001A); +igot = read_vt(pusb_device, 0x0018); if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x1A\n"); + SAY("ERROR: failed to read VT1612A register 0x18\n"); if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x1A); + SAY("register 0x%02X muted\n", 0x18); igot = read_vt(pusb_device, 0x001C); if (0 > igot) @@ -1118,14 +1108,18 @@ return 0; } /*****************************************************************************/ /*---------------------------------------------------------------------------*/ -/* - * NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY: - * audio_gainset(pusb_device, 0x000F); +/* NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY: + * audio_gainset(pusb_device, 0x000F); * - * IF 16 loud) - loud = 16; -u8 = 0x000F & (__u8)(loud - 16); +if ((struct usb_device *)NULL == pusb_device) + return -ENODEV; +if (0 > loud) + loud = 0; +if (31 < loud) + loud = 31; write_vt(pusb_device, 0x0002, 0x8000); +/*---------------------------------------------------------------------------*/ +igot = read_vt(pusb_device, 0x000E); +if (0 > igot) { + SAY("ERROR: failed to read VT1612A register 0x0E\n"); + mute = 0x0000; +} else + mute = 0x8000 & ((unsigned int)igot); +mute = 0; +if (16 > loud) + u8 = 0x01 | (0x001F & (((__u8)(15 - loud)) << 1)); +else + u8 = 0; + +JOT(8, "0x%04X=(mute|u8) for VT1612A register 0x0E\n", mute | u8); +write_vt(pusb_device, 0x000E, (mute | u8)); +/*---------------------------------------------------------------------------*/ +igot = read_vt(pusb_device, 0x0010); +if (0 > igot) { + SAY("ERROR: failed to read VT1612A register 0x10\n"); + mute = 0x0000; +} else + mute = 0x8000 & ((unsigned int)igot); +mute = 0; + +JOT(8, "0x%04X=(mute|u8|(u8<<8)) for VT1612A register 0x10,...0x18\n", \ + mute | u8 | (u8 << 8)); +write_vt(pusb_device, 0x0010, (mute | u8 | (u8 << 8))); +write_vt(pusb_device, 0x0012, (mute | u8 | (u8 << 8))); +write_vt(pusb_device, 0x0014, (mute | u8 | (u8 << 8))); +write_vt(pusb_device, 0x0016, (mute | u8 | (u8 << 8))); +write_vt(pusb_device, 0x0018, (mute | u8 | (u8 << 8))); +/*---------------------------------------------------------------------------*/ igot = read_vt(pusb_device, 0x001C); if (0 > igot) { SAY("ERROR: failed to read VT1612A register 0x1C\n"); mute = 0x0000; } else mute = 0x8000 & ((unsigned int)igot); +mute = 0; -JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8)); +if (16 <= loud) + u8 = 0x000F & (__u8)(loud - 16); +else + u8 = 0; -write_vt(pusb_device, 0x001C, 0x8000); +JOT(8, "0x%04X=(mute|u8|(u8<<8)) for VT1612A register 0x1C\n", \ + mute | u8 | (u8 << 8)); write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8))); +write_vt(pusb_device, 0x001A, 0x0404); write_vt(pusb_device, 0x0002, 0x0000); - return 0; } /*****************************************************************************/ @@ -1161,6 +1195,8 @@ audio_gainget(struct usb_device *pusb_device) { int igot; +if (NULL == pusb_device) + return -ENODEV; igot = read_vt(pusb_device, 0x001C); if (0 > igot) SAY("ERROR: failed to read VT1612A register 0x1C\n"); diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index 21450e83530f..ee5c8d990bdf 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -34,8 +34,10 @@ int debug; int bars; +int gain = 16; module_param(debug, int, S_IRUGO | S_IWUSR); module_param(bars, int, S_IRUGO | S_IWUSR); +module_param(gain, int, S_IRUGO | S_IWUSR); /*---------------------------------------------------------------------------*/ /* @@ -4770,7 +4772,8 @@ easycap_module_init(void) int result; SAY("========easycap=======\n"); -JOT(4, "begins. %i=debug %i=bars\n", debug, bars); +JOT(4, "begins. %i=debug %i=bars %i=gain\n", debug, bars, \ + gain); SAY("version: " EASYCAP_DRIVER_VERSION "\n"); /*---------------------------------------------------------------------------*/ /* @@ -4811,8 +4814,9 @@ MODULE_AUTHOR("R.M. Thomas "); MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION); MODULE_VERSION(EASYCAP_DRIVER_VERSION); #if defined(EASYCAP_DEBUG) -MODULE_PARM_DESC(debug, "Debug level: 0 (default),1,2,...,9"); +MODULE_PARM_DESC(debug, "Debug level: 0 (default),1,2,..."); #endif /*EASYCAP_DEBUG*/ MODULE_PARM_DESC(bars, \ "Testcard bars on input signal failure: 0=>no, 1=>yes(default)"); +MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31"); /*****************************************************************************/ -- cgit v1.2.3 From 2a87a0b9220f8e0e6f204b0f61dc6e15ad64ccd4 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:07:12 +0000 Subject: staging/easycap: Avoid compiler warning about frame size ... larger than ... Replacing some of the large automatic variables by dynamically allocated variables in the IOCTL routines gets rid of the compiler warning. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap_ioctl.c | 155 ++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 7c46cb22daeb..5e9133b29dd0 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -956,8 +956,8 @@ return -ENOENT; static int easycap_ioctl_bkl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { -static struct easycap *peasycap; -static struct usb_device *p; +struct easycap *peasycap; +struct usb_device *p; if (NULL == file) { SAY("ERROR: file is NULL\n"); @@ -974,13 +974,6 @@ if (NULL == p) { return -EFAULT; } /*---------------------------------------------------------------------------*/ -/* - * MOST OF THE VARIABLES DECLARED static IN THE case{} BLOCKS BELOW ARE SO - * DECLARED SIMPLY TO AVOID A COMPILER WARNING OF THE KIND: - * easycap_ioctl.c: warning: - * the frame size of ... bytes is larger than 1024 bytes - */ -/*---------------------------------------------------------------------------*/ switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability v4l2_capability; @@ -1247,57 +1240,67 @@ case VIDIOC_QUERYMENU: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_CTRL: { - struct v4l2_control v4l2_control; + struct v4l2_control *pv4l2_control; JOM(8, "VIDIOC_G_CTRL\n"); - - if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ - sizeof(struct v4l2_control))) + pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL); + if (!pv4l2_control) { + SAM("ERROR: out of memory\n"); + return -ENOMEM; + } + if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \ + sizeof(struct v4l2_control))) { + kfree(pv4l2_control); return -EFAULT; + } - switch (v4l2_control.id) { + switch (pv4l2_control->id) { case V4L2_CID_BRIGHTNESS: { - v4l2_control.value = peasycap->brightness; - JOM(8, "user enquires brightness: %i\n", v4l2_control.value); + pv4l2_control->value = peasycap->brightness; + JOM(8, "user enquires brightness: %i\n", pv4l2_control->value); break; } case V4L2_CID_CONTRAST: { - v4l2_control.value = peasycap->contrast; - JOM(8, "user enquires contrast: %i\n", v4l2_control.value); + pv4l2_control->value = peasycap->contrast; + JOM(8, "user enquires contrast: %i\n", pv4l2_control->value); break; } case V4L2_CID_SATURATION: { - v4l2_control.value = peasycap->saturation; - JOM(8, "user enquires saturation: %i\n", v4l2_control.value); + pv4l2_control->value = peasycap->saturation; + JOM(8, "user enquires saturation: %i\n", pv4l2_control->value); break; } case V4L2_CID_HUE: { - v4l2_control.value = peasycap->hue; - JOM(8, "user enquires hue: %i\n", v4l2_control.value); + pv4l2_control->value = peasycap->hue; + JOM(8, "user enquires hue: %i\n", pv4l2_control->value); break; } case V4L2_CID_AUDIO_VOLUME: { - v4l2_control.value = peasycap->volume; - JOM(8, "user enquires volume: %i\n", v4l2_control.value); + pv4l2_control->value = peasycap->volume; + JOM(8, "user enquires volume: %i\n", pv4l2_control->value); break; } case V4L2_CID_AUDIO_MUTE: { if (1 == peasycap->mute) - v4l2_control.value = true; + pv4l2_control->value = true; else - v4l2_control.value = false; - JOM(8, "user enquires mute: %i\n", v4l2_control.value); + pv4l2_control->value = false; + JOM(8, "user enquires mute: %i\n", pv4l2_control->value); break; } default: { SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \ - v4l2_control.id); + pv4l2_control->id); + kfree(pv4l2_control); return -EINVAL; } } - if (0 != copy_to_user((void __user *)arg, &v4l2_control, \ - sizeof(struct v4l2_control))) + if (0 != copy_to_user((void __user *)arg, pv4l2_control, \ + sizeof(struct v4l2_control))) { + kfree(pv4l2_control); return -EFAULT; + } + kfree(pv4l2_control); break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1596,8 +1599,9 @@ case VIDIOC_ENUM_FRAMEINTERVALS: { } if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \ - sizeof(struct v4l2_frmivalenum))) + sizeof(struct v4l2_frmivalenum))) { return -EFAULT; + } index = v4l2_frmivalenum.index; @@ -1632,29 +1636,50 @@ case VIDIOC_ENUM_FRAMEINTERVALS: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_FMT: { - struct v4l2_format v4l2_format; - struct v4l2_pix_format v4l2_pix_format; + struct v4l2_format *pv4l2_format; + struct v4l2_pix_format *pv4l2_pix_format; JOM(8, "VIDIOC_G_FMT\n"); - - if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ - sizeof(struct v4l2_format))) + pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL); + if (!pv4l2_format) { + SAM("ERROR: out of memory\n"); + return -ENOMEM; + } + pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL); + if (!pv4l2_pix_format) { + SAM("ERROR: out of memory\n"); + kfree(pv4l2_format); + return -ENOMEM; + } + if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \ + sizeof(struct v4l2_format))) { + kfree(pv4l2_format); + kfree(pv4l2_pix_format); return -EFAULT; + } - if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + kfree(pv4l2_format); + kfree(pv4l2_pix_format); return -EINVAL; + } - memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); - v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memcpy(&(v4l2_format.fmt.pix), \ - &(easycap_format[peasycap->format_offset]\ - .v4l2_format.fmt.pix), sizeof(v4l2_pix_format)); + memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); + pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memcpy(&pv4l2_format->fmt.pix, \ + &easycap_format[peasycap->format_offset]\ + .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format)); JOM(8, "user is told: %s\n", \ &easycap_format[peasycap->format_offset].name[0]); - if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ - sizeof(struct v4l2_format))) + if (0 != copy_to_user((void __user *)arg, pv4l2_format, \ + sizeof(struct v4l2_format))) { + kfree(pv4l2_format); + kfree(pv4l2_pix_format); return -EFAULT; + } + kfree(pv4l2_format); + kfree(pv4l2_pix_format); break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -2196,38 +2221,50 @@ case VIDIOC_STREAMOFF: { } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_PARM: { - struct v4l2_streamparm v4l2_streamparm; + struct v4l2_streamparm *pv4l2_streamparm; JOM(8, "VIDIOC_G_PARM\n"); - - if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \ - sizeof(struct v4l2_streamparm))) + pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL); + if (!pv4l2_streamparm) { + SAM("ERROR: out of memory\n"); + return -ENOMEM; + } + if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \ + sizeof(struct v4l2_streamparm))) { + kfree(pv4l2_streamparm); return -EFAULT; + } - if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + kfree(pv4l2_streamparm); return -EINVAL; - v4l2_streamparm.parm.capture.capability = 0; - v4l2_streamparm.parm.capture.capturemode = 0; - v4l2_streamparm.parm.capture.timeperframe.numerator = 1; + } + pv4l2_streamparm->parm.capture.capability = 0; + pv4l2_streamparm->parm.capture.capturemode = 0; + pv4l2_streamparm->parm.capture.timeperframe.numerator = 1; if (peasycap->fps) { - v4l2_streamparm.parm.capture.timeperframe.\ + pv4l2_streamparm->parm.capture.timeperframe.\ denominator = peasycap->fps; } else { if (true == peasycap->ntsc) { - v4l2_streamparm.parm.capture.timeperframe.\ + pv4l2_streamparm->parm.capture.timeperframe.\ denominator = 30; } else { - v4l2_streamparm.parm.capture.timeperframe.\ + pv4l2_streamparm->parm.capture.timeperframe.\ denominator = 25; } } - v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many; - v4l2_streamparm.parm.capture.extendedmode = 0; - if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \ - sizeof(struct v4l2_streamparm))) + pv4l2_streamparm->parm.capture.readbuffers = \ + peasycap->frame_buffer_many; + pv4l2_streamparm->parm.capture.extendedmode = 0; + if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \ + sizeof(struct v4l2_streamparm))) { + kfree(pv4l2_streamparm); return -EFAULT; + } + kfree(pv4l2_streamparm); break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -- cgit v1.2.3 From ae59dad4fef271222d65ac6afe2889eb12ea6ca9 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:09:19 +0000 Subject: staging/easycap: Eliminate BKL No locking is required for normal operation of the driver, but locking is needed to prevent an Oops during some hot-unplugging scenarios. The BKL is replaced here by mutex locks together with traps to detect null pointers following asynchronous device disconnection. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/Kconfig | 1 - drivers/staging/easycap/Makefile | 1 + drivers/staging/easycap/easycap.h | 16 +- drivers/staging/easycap/easycap_debug.h | 1 + drivers/staging/easycap/easycap_ioctl.c | 426 +++++++++++++++++++++++++------- drivers/staging/easycap/easycap_low.c | 55 ++++- drivers/staging/easycap/easycap_main.c | 311 ++++++++++++++++------- drivers/staging/easycap/easycap_sound.c | 76 +++++- 8 files changed, 695 insertions(+), 192 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/easycap/Kconfig index 9d5fe4ddc30a..bd96f39f2735 100644 --- a/drivers/staging/easycap/Kconfig +++ b/drivers/staging/easycap/Kconfig @@ -1,7 +1,6 @@ config EASYCAP tristate "EasyCAP USB ID 05e1:0408 support" depends on USB && VIDEO_DEV - depends on BKL # please fix ---help--- This is an integrated audio/video driver for EasyCAP cards with diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/easycap/Makefile index 8a3d911aee5d..f1f2fbebf8f6 100644 --- a/drivers/staging/easycap/Makefile +++ b/drivers/staging/easycap/Makefile @@ -10,4 +10,5 @@ ccflags-y := -Wall ccflags-y += -DEASYCAP_IS_VIDEODEV_CLIENT ccflags-y += -DEASYCAP_NEEDS_V4L2_DEVICE_H ccflags-y += -DEASYCAP_NEEDS_V4L2_FOPS +ccflags-y += -DEASYCAP_NEEDS_UNLOCKED_IOCTL diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index e9410b74ffc4..762c6cea54c3 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -251,6 +251,12 @@ INTERLACE_MANY * STRUCTURE DEFINITIONS */ /*---------------------------------------------------------------------------*/ +struct easycap_dongle { +struct easycap *peasycap; +struct mutex mutex_video; +struct mutex mutex_audio; +}; +/*---------------------------------------------------------------------------*/ struct data_buffer { struct list_head list_head; void *pgo; @@ -491,7 +497,10 @@ struct data_buffer audio_buffer[]; void easycap_complete(struct urb *); int easycap_open(struct inode *, struct file *); int easycap_release(struct inode *, struct file *); -long easycap_ioctl(struct file *, unsigned int, unsigned long); +long easycap_ioctl_noinode(struct file *, unsigned int, \ + unsigned long); +int easycap_ioctl(struct inode *, struct file *, unsigned int, \ + unsigned long); /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #if defined(EASYCAP_IS_VIDEODEV_CLIENT) @@ -538,7 +547,10 @@ void easysnd_complete(struct urb *); ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *); int easysnd_open(struct inode *, struct file *); int easysnd_release(struct inode *, struct file *); -long easysnd_ioctl(struct file *, unsigned int, unsigned long); +long easysnd_ioctl_noinode(struct file *, unsigned int, \ + unsigned long); +int easysnd_ioctl(struct inode *, struct file *, unsigned int, \ + unsigned long); unsigned int easysnd_poll(struct file *, poll_table *); void easysnd_delete(struct kref *); int submit_audio_urbs(struct easycap *); diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h index 7042fe8e31fe..518392e0d72d 100644 --- a/drivers/staging/easycap/easycap_debug.h +++ b/drivers/staging/easycap/easycap_debug.h @@ -26,3 +26,4 @@ /*****************************************************************************/ extern int debug; extern int gain; +extern struct easycap_dongle easycap_dongle[]; diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 5e9133b29dd0..2f9b3eab4898 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -953,11 +953,23 @@ SAM("WARNING: failed to adjust mute: control not found\n"); return -ENOENT; } /*****************************************************************************/ -static int easycap_ioctl_bkl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \ + (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL))) +long +easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) { + return (long)easycap_ioctl((struct inode *)NULL, file, cmd, arg); +} +#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +/*---------------------------------------------------------------------------*/ +int +easycap_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct easycap *peasycap; struct usb_device *p; +int kd; if (NULL == file) { SAY("ERROR: file is NULL\n"); @@ -973,6 +985,48 @@ if (NULL == p) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } +kd = isdongle(peasycap); +if (0 <= kd && DONGLE_MANY > kd) { + if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) { + SAY("ERROR: cannot lock easycap_dongle[%i].mutex_video\n", kd); + return -ERESTARTSYS; + } + JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd); +/*---------------------------------------------------------------------------*/ +/* + * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap, + * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. + * IF NECESSARY, BAIL OUT. +*/ +/*---------------------------------------------------------------------------*/ + if (kd != isdongle(peasycap)) + return -ERESTARTSYS; + if (NULL == file) { + SAY("ERROR: file is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } + peasycap = file->private_data; + if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } + p = peasycap->pusb_device; + if (NULL == peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } +} else { +/*---------------------------------------------------------------------------*/ +/* + * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE + * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT. +*/ +/*---------------------------------------------------------------------------*/ + return -ERESTARTSYS; +} /*---------------------------------------------------------------------------*/ switch (cmd) { case VIDIOC_QUERYCAP: { @@ -984,7 +1038,9 @@ case VIDIOC_QUERYCAP: { JOM(8, "VIDIOC_QUERYCAP\n"); if (16 <= strlen(EASYCAP_DRIVER_VERSION)) { - SAM("ERROR: bad driver version string\n"); return -EINVAL; + SAM("ERROR: bad driver version string\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -EINVAL; } strcpy(&version[0], EASYCAP_DRIVER_VERSION); for (i = 0; i < 3; i++) @@ -1001,6 +1057,7 @@ case VIDIOC_QUERYCAP: { if (0 != rc) { SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \ rc, p1); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } k[i] = (int)lng; @@ -1030,8 +1087,10 @@ case VIDIOC_QUERYCAP: { &v4l2_capability.bus_info[0]); } if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \ - sizeof(struct v4l2_capability))) + sizeof(struct v4l2_capability))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1042,8 +1101,10 @@ case VIDIOC_ENUMINPUT: { JOM(8, "VIDIOC_ENUMINPUT\n"); if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \ - sizeof(struct v4l2_input))) + sizeof(struct v4l2_input))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } index = v4l2_input.index; memset(&v4l2_input, 0, sizeof(struct v4l2_input)); @@ -1123,13 +1184,16 @@ case VIDIOC_ENUMINPUT: { } default: { JOM(8, "%i=index: exhausts inputs\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } } if (0 != copy_to_user((void __user *)arg, &v4l2_input, \ - sizeof(struct v4l2_input))) + sizeof(struct v4l2_input))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1139,8 +1203,10 @@ case VIDIOC_G_INPUT: { JOM(8, "VIDIOC_G_INPUT\n"); index = (__u32)peasycap->input; JOM(8, "user is told: %i\n", index); - if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) + if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1151,8 +1217,10 @@ case VIDIOC_S_INPUT: JOM(8, "VIDIOC_S_INPUT\n"); - if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) + if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } JOM(8, "user requests input %i\n", index); @@ -1163,6 +1231,7 @@ case VIDIOC_S_INPUT: if ((0 > index) || (INPUT_MANY <= index)) { JOM(8, "ERROR: bad requested input: %i\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } @@ -1171,6 +1240,7 @@ case VIDIOC_S_INPUT: JOM(8, "newinput(.,%i) OK\n", (int)index); } else { SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } break; @@ -1178,6 +1248,7 @@ case VIDIOC_S_INPUT: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_ENUMAUDIO: { JOM(8, "VIDIOC_ENUMAUDIO\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1187,18 +1258,24 @@ case VIDIOC_ENUMAUDOUT: { JOM(8, "VIDIOC_ENUMAUDOUT\n"); if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \ - sizeof(struct v4l2_audioout))) + sizeof(struct v4l2_audioout))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } - if (0 != v4l2_audioout.index) + if (0 != v4l2_audioout.index) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; + } memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout)); v4l2_audioout.index = 0; strcpy(&v4l2_audioout.name[0], "Soundtrack"); if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \ - sizeof(struct v4l2_audioout))) + sizeof(struct v4l2_audioout))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1209,8 +1286,10 @@ case VIDIOC_QUERYCTRL: { JOM(8, "VIDIOC_QUERYCTRL\n"); if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \ - sizeof(struct v4l2_queryctrl))) + sizeof(struct v4l2_queryctrl))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } i1 = 0; while (0xFFFFFFFF != easycap_control[i1].id) { @@ -1225,18 +1304,21 @@ case VIDIOC_QUERYCTRL: { } if (0xFFFFFFFF == easycap_control[i1].id) { JOM(8, "%i=index: exhausts controls\n", i1); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \ - sizeof(struct v4l2_queryctrl))) + sizeof(struct v4l2_queryctrl))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QUERYMENU: { JOM(8, "VIDIOC_QUERYMENU unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; - break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_CTRL: { @@ -1246,11 +1328,13 @@ case VIDIOC_G_CTRL: { pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL); if (!pv4l2_control) { SAM("ERROR: out of memory\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -ENOMEM; } if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \ sizeof(struct v4l2_control))) { kfree(pv4l2_control); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } @@ -1292,12 +1376,14 @@ case VIDIOC_G_CTRL: { SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \ pv4l2_control->id); kfree(pv4l2_control); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } } if (0 != copy_to_user((void __user *)arg, pv4l2_control, \ sizeof(struct v4l2_control))) { kfree(pv4l2_control); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } kfree(pv4l2_control); @@ -1316,8 +1402,10 @@ case VIDIOC_S_CTRL: JOM(8, "VIDIOC_S_CTRL\n"); if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \ - sizeof(struct v4l2_control))) + sizeof(struct v4l2_control))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } switch (v4l2_control.id) { case V4L2_CID_BRIGHTNESS: { @@ -1366,14 +1454,16 @@ case VIDIOC_S_CTRL: default: { SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \ v4l2_control.id); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; - } + } } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_EXT_CTRLS: { JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1384,8 +1474,10 @@ case VIDIOC_ENUM_FMT: { JOM(8, "VIDIOC_ENUM_FMT\n"); if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \ - sizeof(struct v4l2_fmtdesc))) + sizeof(struct v4l2_fmtdesc))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } index = v4l2_fmtdesc.index; memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc)); @@ -1438,12 +1530,15 @@ case VIDIOC_ENUM_FMT: { } default: { JOM(8, "%i=index: exhausts formats\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } } if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \ - sizeof(struct v4l2_fmtdesc))) + sizeof(struct v4l2_fmtdesc))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1459,8 +1554,10 @@ case VIDIOC_ENUM_FRAMESIZES: { JOM(8, "VIDIOC_ENUM_FRAMESIZES\n"); if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \ - sizeof(struct v4l2_frmsizeenum))) + sizeof(struct v4l2_frmsizeenum))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } index = v4l2_frmsizeenum.index; @@ -1510,6 +1607,7 @@ case VIDIOC_ENUM_FRAMESIZES: { } default: { JOM(8, "%i=index: exhausts framesizes\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } } @@ -1567,13 +1665,16 @@ case VIDIOC_ENUM_FRAMESIZES: { } default: { JOM(8, "%i=index: exhausts framesizes\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } } } if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \ - sizeof(struct v4l2_frmsizeenum))) + sizeof(struct v4l2_frmsizeenum))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1600,6 +1701,7 @@ case VIDIOC_ENUM_FRAMEINTERVALS: { if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \ sizeof(struct v4l2_frmivalenum))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } @@ -1626,12 +1728,15 @@ case VIDIOC_ENUM_FRAMEINTERVALS: { } default: { JOM(8, "%i=index: exhausts frameintervals\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } } if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \ - sizeof(struct v4l2_frmivalenum))) + sizeof(struct v4l2_frmivalenum))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1643,24 +1748,28 @@ case VIDIOC_G_FMT: { pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL); if (!pv4l2_format) { SAM("ERROR: out of memory\n"); - return -ENOMEM; + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ENOMEM; } pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL); if (!pv4l2_pix_format) { SAM("ERROR: out of memory\n"); kfree(pv4l2_format); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -ENOMEM; } if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \ sizeof(struct v4l2_format))) { kfree(pv4l2_format); kfree(pv4l2_pix_format); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { kfree(pv4l2_format); kfree(pv4l2_pix_format); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } @@ -1676,6 +1785,7 @@ case VIDIOC_G_FMT: { sizeof(struct v4l2_format))) { kfree(pv4l2_format); kfree(pv4l2_pix_format); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } kfree(pv4l2_format); @@ -1699,8 +1809,10 @@ case VIDIOC_S_FMT: { } if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \ - sizeof(struct v4l2_format))) + sizeof(struct v4l2_format))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } best_format = adjust_format(peasycap, \ v4l2_format.fmt.pix.width, \ @@ -1709,9 +1821,12 @@ case VIDIOC_S_FMT: { v4l2_format.fmt.pix.field, \ try); if (0 > best_format) { - if (-EBUSY == best_format) + if (-EBUSY == best_format) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EBUSY; + } JOM(8, "WARNING: adjust_format() returned %i\n", best_format); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -ENOENT; } /*...........................................................................*/ @@ -1723,8 +1838,10 @@ case VIDIOC_S_FMT: { JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]); if (0 != copy_to_user((void __user *)arg, &v4l2_format, \ - sizeof(struct v4l2_format))) + sizeof(struct v4l2_format))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1734,8 +1851,10 @@ case VIDIOC_CROPCAP: { JOM(8, "VIDIOC_CROPCAP\n"); if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \ - sizeof(struct v4l2_cropcap))) + sizeof(struct v4l2_cropcap))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); @@ -1756,20 +1875,24 @@ case VIDIOC_CROPCAP: { JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \ - sizeof(struct v4l2_cropcap))) + sizeof(struct v4l2_cropcap))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_CROP: case VIDIOC_S_CROP: { JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_QUERYSTD: { JOM(8, "VIDIOC_QUERYSTD: " \ "EasyCAP is incapable of detecting standard\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; break; } @@ -1790,8 +1913,10 @@ case VIDIOC_ENUMSTD: { JOM(8, "VIDIOC_ENUMSTD\n"); if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \ - sizeof(struct v4l2_standard))) + sizeof(struct v4l2_standard))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } index = v4l2_standard.index; last3 = last2; last2 = last1; last1 = last0; last0 = index; @@ -1811,6 +1936,7 @@ case VIDIOC_ENUMSTD: { } if (0xFFFF == peasycap_standard->mask) { JOM(8, "%i=index: exhausts standards\n", index); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } JOM(8, "%i=index: %s\n", index, \ @@ -1821,8 +1947,10 @@ case VIDIOC_ENUMSTD: { v4l2_standard.index = index; if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \ - sizeof(struct v4l2_standard))) + sizeof(struct v4l2_standard))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1835,12 +1963,15 @@ case VIDIOC_G_STD: { if (0 > peasycap->standard_offset) { JOM(8, "%i=peasycap->standard_offset\n", \ peasycap->standard_offset); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EBUSY; } if (0 != copy_from_user(&std_id, (void __user *)arg, \ - sizeof(v4l2_std_id))) + sizeof(v4l2_std_id))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } peasycap_standard = &easycap_standard[peasycap->standard_offset]; std_id = peasycap_standard->v4l2_standard.id; @@ -1849,8 +1980,10 @@ case VIDIOC_G_STD: { &peasycap_standard->v4l2_standard.name[0]); if (0 != copy_to_user((void __user *)arg, &std_id, \ - sizeof(v4l2_std_id))) + sizeof(v4l2_std_id))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1861,8 +1994,10 @@ case VIDIOC_S_STD: { JOM(8, "VIDIOC_S_STD\n"); if (0 != copy_from_user(&std_id, (void __user *)arg, \ - sizeof(v4l2_std_id))) + sizeof(v4l2_std_id))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } JOM(8, "User requests standard: 0x%08X%08X\n", \ (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \ @@ -1871,6 +2006,7 @@ case VIDIOC_S_STD: { rc = adjust_standard(peasycap, std_id); if (0 > rc) { JOM(8, "WARNING: adjust_standard() returned %i\n", rc); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -ENOENT; } break; @@ -1883,13 +2019,19 @@ case VIDIOC_REQBUFS: { JOM(8, "VIDIOC_REQBUFS\n"); if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \ - sizeof(struct v4l2_requestbuffers))) + sizeof(struct v4l2_requestbuffers))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } - if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; - if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) + } + if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; + } nbuffers = v4l2_requestbuffers.count; JOM(8, " User requests %i buffers ...\n", nbuffers); if (nbuffers < 2) @@ -1907,8 +2049,10 @@ case VIDIOC_REQBUFS: { peasycap->frame_buffer_many = nbuffers; if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \ - sizeof(struct v4l2_requestbuffers))) + sizeof(struct v4l2_requestbuffers))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1921,15 +2065,20 @@ case VIDIOC_QUERYBUF: { if (peasycap->video_eof) { JOM(8, "returning -EIO because %i=video_eof\n", \ peasycap->video_eof); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EIO; } if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ - sizeof(struct v4l2_buffer))) + sizeof(struct v4l2_buffer))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } - if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; + } index = v4l2_buffer.index; if (index < 0 || index >= peasycap->frame_buffer_many) return -EINVAL; @@ -1958,8 +2107,10 @@ case VIDIOC_QUERYBUF: { JOM(16, " %10i=length\n", v4l2_buffer.length); if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ - sizeof(struct v4l2_buffer))) + sizeof(struct v4l2_buffer))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -1969,24 +2120,34 @@ case VIDIOC_QBUF: { JOM(8, "VIDIOC_QBUF\n"); if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ - sizeof(struct v4l2_buffer))) + sizeof(struct v4l2_buffer))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } - if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; - if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) + } + if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; + } if (v4l2_buffer.index < 0 || \ - (v4l2_buffer.index >= peasycap->frame_buffer_many)) + (v4l2_buffer.index >= peasycap->frame_buffer_many)) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; + } v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED; peasycap->done[v4l2_buffer.index] = 0; peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED; if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ - sizeof(struct v4l2_buffer))) + sizeof(struct v4l2_buffer))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } JOM(8, "..... user queueing frame buffer %i\n", \ (int)v4l2_buffer.index); @@ -2017,15 +2178,20 @@ case VIDIOC_DQBUF: JOM(8, "returning -EIO because " \ "%i=video_idle %i=video_eof\n", \ peasycap->video_idle, peasycap->video_eof); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EIO; } if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \ - sizeof(struct v4l2_buffer))) + sizeof(struct v4l2_buffer))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } - if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; + } if (true == peasycap->offerfields) { /*-----------------------------------------------------------*/ @@ -2047,6 +2213,7 @@ case VIDIOC_DQBUF: if (!peasycap->video_isoc_streaming) { JOM(16, "returning -EIO because video urbs not streaming\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EIO; } /*---------------------------------------------------------------------------*/ @@ -2063,12 +2230,15 @@ case VIDIOC_DQBUF: if (-EIO == rcdq) { JOM(8, "returning -EIO because " \ "dqbuf() returned -EIO\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EIO; } } while (0 != rcdq); } else { - if (peasycap->video_eof) + if (peasycap->video_eof) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EIO; + } } if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) { SAM("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \ @@ -2155,8 +2325,10 @@ case VIDIOC_DQBUF: JOM(16, " %10i=length\n", v4l2_buffer.length); if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \ - sizeof(struct v4l2_buffer))) + sizeof(struct v4l2_buffer))) { + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; + } input = peasycap->frame_buffer[peasycap->frame_read][0].input; if (0x08 & input) { @@ -2187,6 +2359,7 @@ case VIDIOC_STREAMON: { peasycap->merit[i] = 0; if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } submit_video_urbs(peasycap); @@ -2202,6 +2375,7 @@ case VIDIOC_STREAMOFF: { if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } @@ -2227,16 +2401,19 @@ case VIDIOC_G_PARM: { pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL); if (!pv4l2_streamparm) { SAM("ERROR: out of memory\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -ENOMEM; } if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \ sizeof(struct v4l2_streamparm))) { kfree(pv4l2_streamparm); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { kfree(pv4l2_streamparm); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } pv4l2_streamparm->parm.capture.capability = 0; @@ -2262,6 +2439,7 @@ case VIDIOC_G_PARM: { if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \ sizeof(struct v4l2_streamparm))) { kfree(pv4l2_streamparm); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EFAULT; } kfree(pv4l2_streamparm); @@ -2270,21 +2448,25 @@ case VIDIOC_G_PARM: { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_PARM: { JOM(8, "VIDIOC_S_PARM unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_AUDIO: { JOM(8, "VIDIOC_G_AUDIO unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_AUDIO: { JOM(8, "VIDIOC_S_AUDIO unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_S_TUNER: { JOM(8, "VIDIOC_S_TUNER unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -2292,44 +2474,50 @@ case VIDIOC_G_FBUF: case VIDIOC_S_FBUF: case VIDIOC_OVERLAY: { JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ case VIDIOC_G_TUNER: { JOM(8, "VIDIOC_G_TUNER unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: { JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -EINVAL; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ default: { JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); + mutex_unlock(&easycap_dongle[kd].mutex_video); return -ENOIOCTLCMD; } } +mutex_unlock(&easycap_dongle[kd].mutex_video); +JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd); return 0; } - -long easycap_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file->f_dentry->d_inode; - long ret; - - lock_kernel(); - ret = easycap_ioctl_bkl(inode, file, cmd, arg); - unlock_kernel(); - - return ret; -} /*****************************************************************************/ -static int easysnd_ioctl_bkl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \ + (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL))) +long +easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) { + return (long)easysnd_ioctl((struct inode *)NULL, file, cmd, arg); +} +#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +/*---------------------------------------------------------------------------*/ +int +easysnd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct easycap *peasycap; struct usb_device *p; +int kd; if (NULL == file) { SAY("ERROR: file is NULL\n"); @@ -2345,6 +2533,48 @@ if (NULL == p) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } +kd = isdongle(peasycap); +if (0 <= kd && DONGLE_MANY > kd) { + if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) { + SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd); + return -ERESTARTSYS; + } + JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd); +/*---------------------------------------------------------------------------*/ +/* + * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap, + * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. + * IF NECESSARY, BAIL OUT. +*/ +/*---------------------------------------------------------------------------*/ + if (kd != isdongle(peasycap)) + return -ERESTARTSYS; + if (NULL == file) { + SAY("ERROR: file is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } + peasycap = file->private_data; + if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } + p = peasycap->pusb_device; + if (NULL == peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } +} else { +/*---------------------------------------------------------------------------*/ +/* + * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE + * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT. +*/ +/*---------------------------------------------------------------------------*/ + return -ERESTARTSYS; +} /*---------------------------------------------------------------------------*/ switch (cmd) { case SNDCTL_DSP_GETCAPS: { @@ -2363,8 +2593,10 @@ case SNDCTL_DSP_GETCAPS: { caps = 0x04400000; #endif /*UPSAMPLE*/ - if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) + if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case SNDCTL_DSP_GETFMTS: { @@ -2383,15 +2615,19 @@ case SNDCTL_DSP_GETFMTS: { incoming = AFMT_S16_LE; #endif /*UPSAMPLE*/ - if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) + if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case SNDCTL_DSP_SETFMT: { int incoming, outgoing; JOM(8, "SNDCTL_DSP_SETFMT\n"); - if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) + if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } JOM(8, "........... %i=incoming\n", incoming); #if defined(UPSAMPLE) @@ -2411,8 +2647,11 @@ case SNDCTL_DSP_SETFMT: { JOM(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE); JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8); if (0 != copy_to_user((void __user *)arg, &outgoing, \ - sizeof(int))) + sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EINVAL ; } break; @@ -2420,8 +2659,10 @@ case SNDCTL_DSP_SETFMT: { case SNDCTL_DSP_STEREO: { int incoming; JOM(8, "SNDCTL_DSP_STEREO\n"); - if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) + if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } JOM(8, "........... %i=incoming\n", incoming); #if defined(UPSAMPLE) @@ -2436,15 +2677,19 @@ case SNDCTL_DSP_STEREO: { incoming = 1; #endif /*UPSAMPLE*/ - if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) + if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case SNDCTL_DSP_SPEED: { int incoming; JOM(8, "SNDCTL_DSP_SPEED\n"); - if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) + if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } JOM(8, "........... %i=incoming\n", incoming); #if defined(UPSAMPLE) @@ -2459,27 +2704,35 @@ case SNDCTL_DSP_SPEED: { incoming = 48000; #endif /*UPSAMPLE*/ - if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) + if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case SNDCTL_DSP_GETTRIGGER: { int incoming; JOM(8, "SNDCTL_DSP_GETTRIGGER\n"); - if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) + if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } JOM(8, "........... %i=incoming\n", incoming); incoming = PCM_ENABLE_INPUT; - if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) + if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case SNDCTL_DSP_SETTRIGGER: { int incoming; JOM(8, "SNDCTL_DSP_SETTRIGGER\n"); - if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) + if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } JOM(8, "........... %i=incoming\n", incoming); JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \ "0x%x=PCM_ENABLE_OUTPUT\n", \ @@ -2493,12 +2746,16 @@ case SNDCTL_DSP_SETTRIGGER: { case SNDCTL_DSP_GETBLKSIZE: { int incoming; JOM(8, "SNDCTL_DSP_GETBLKSIZE\n"); - if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) + if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } JOM(8, "........... %i=incoming\n", incoming); incoming = peasycap->audio_bytes_per_fragment; - if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) + if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case SNDCTL_DSP_GETISPACE: { @@ -2512,8 +2769,10 @@ case SNDCTL_DSP_GETISPACE: { audio_buf_info.fragstotal = 0; if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \ - sizeof(int))) + sizeof(int))) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; + } break; } case 0x00005401: @@ -2523,25 +2782,16 @@ case 0x00005404: case 0x00005405: case 0x00005406: { JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -ENOIOCTLCMD; } default: { JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -ENOIOCTLCMD; } } +mutex_unlock(&easycap_dongle[kd].mutex_audio); return 0; } - -long easysnd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file->f_dentry->d_inode; - long ret; - - lock_kernel(); - ret = easysnd_ioctl_bkl(inode, file, cmd, arg); - unlock_kernel(); - - return ret; -} /*****************************************************************************/ diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index 7d778ba67ac8..b75db82bba73 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -38,8 +38,8 @@ */ /****************************************************************************/ -#include "easycap_debug.h" #include "easycap.h" +#include "easycap_debug.h" /*--------------------------------------------------------------------------*/ const struct stk1160config { int reg; int set; } stk1160configPAL[256] = { @@ -248,6 +248,9 @@ int confirm_resolution(struct usb_device *p) { __u8 get0, get1, get2, get3, get4, get5, get6, get7; + +if (NULL == p) + return -ENODEV; GET(p, 0x0110, &get0); GET(p, 0x0111, &get1); GET(p, 0x0112, &get2); @@ -288,6 +291,8 @@ confirm_stream(struct usb_device *p) __u16 get2; __u8 igot; +if (NULL == p) + return -ENODEV; GET(p, 0x0100, &igot); get2 = 0x80 & igot; if (0x80 == get2) JOT(8, "confirm_stream: OK\n"); @@ -301,6 +306,8 @@ setup_stk(struct usb_device *p, bool ntsc) { int i0; +if (NULL == p) + return -ENODEV; i0 = 0; if (true == ntsc) { while (0xFFF != stk1160configNTSC[i0].reg) { @@ -324,6 +331,8 @@ setup_saa(struct usb_device *p, bool ntsc) { int i0, ir; +if (NULL == p) + return -ENODEV; i0 = 0; if (true == ntsc) { while (0xFF != saa7113configNTSC[i0].reg) { @@ -346,6 +355,8 @@ write_000(struct usb_device *p, __u16 set2, __u16 set0) { __u8 igot0, igot2; +if (NULL == p) + return -ENODEV; GET(p, 0x0002, &igot2); GET(p, 0x0000, &igot0); SET(p, 0x0002, set2); @@ -356,6 +367,8 @@ return 0; int write_saa(struct usb_device *p, __u16 reg0, __u16 set0) { +if (NULL == p) + return -ENODEV; SET(p, 0x200, 0x00); SET(p, 0x204, reg0); SET(p, 0x205, set0); @@ -379,6 +392,8 @@ __u8 igot; __u16 got502, got503; __u16 set502, set503; +if (NULL == p) + return -ENODEV; SET(p, 0x0504, reg0); SET(p, 0x0500, 0x008B); @@ -414,6 +429,8 @@ read_vt(struct usb_device *p, __u16 reg0) __u8 igot; __u16 got502, got503; +if (NULL == p) + return -ENODEV; SET(p, 0x0504, reg0); SET(p, 0x0500, 0x008B); @@ -433,6 +450,8 @@ return (got503 << 8) | got502; int write_300(struct usb_device *p) { +if (NULL == p) + return -ENODEV; SET(p, 0x300, 0x0012); SET(p, 0x350, 0x002D); SET(p, 0x351, 0x0001); @@ -453,6 +472,8 @@ check_saa(struct usb_device *p, bool ntsc) { int i0, ir, rc; +if (NULL == p) + return -ENODEV; i0 = 0; rc = 0; if (true == ntsc) { @@ -501,6 +522,8 @@ merit_saa(struct usb_device *p) { int rc; +if (NULL == p) + return -ENODEV; rc = read_saa(p, 0x1F); if ((0 > rc) || (0x02 & rc)) return 1 ; @@ -521,6 +544,8 @@ const int max = 5, marktime = PATIENCE/5; * 3 FOR NON-INTERLACED 60 Hz */ /*--------------------------------------------------------------------------*/ +if (NULL == p) + return -ENODEV; j = 0; while (max > j) { rc = read_saa(p, 0x1F); @@ -565,6 +590,8 @@ check_stk(struct usb_device *p, bool ntsc) { int i0, ir; +if (NULL == p) + return -ENODEV; i0 = 0; if (true == ntsc) { while (0xFFF != stk1160configNTSC[i0].reg) { @@ -637,6 +664,8 @@ read_saa(struct usb_device *p, __u16 reg0) { __u8 igot; +if (NULL == p) + return -ENODEV; SET(p, 0x208, reg0); SET(p, 0x200, 0x20); if (0 != wait_i2c(p)) @@ -651,6 +680,8 @@ read_stk(struct usb_device *p, __u32 reg0) { __u8 igot; +if (NULL == p) + return -ENODEV; igot = 0; GET(p, reg0, &igot); return igot; @@ -679,6 +710,8 @@ select_input(struct usb_device *p, int input, int mode) { int ir; +if (NULL == p) + return -ENODEV; stop_100(p); switch (input) { case 0: @@ -781,6 +814,8 @@ set_resolution(struct usb_device *p, \ { __u16 u0x0111, u0x0113, u0x0115, u0x0117; +if (NULL == p) + return -ENODEV; u0x0111 = ((0xFF00 & set0) >> 8); u0x0113 = ((0xFF00 & set1) >> 8); u0x0115 = ((0xFF00 & set2) >> 8); @@ -804,6 +839,8 @@ start_100(struct usb_device *p) __u16 get116, get117, get0; __u8 igot116, igot117, igot; +if (NULL == p) + return -ENODEV; GET(p, 0x0116, &igot116); get116 = igot116; GET(p, 0x0117, &igot117); @@ -827,6 +864,8 @@ stop_100(struct usb_device *p) __u16 get0; __u8 igot; +if (NULL == p) + return -ENODEV; GET(p, 0x0100, &igot); get0 = igot; SET(p, 0x0100, (0x7F & get0)); @@ -846,6 +885,8 @@ __u8 igot; const int max = 2; int k; +if (NULL == p) + return -ENODEV; for (k = 0; k < max; k++) { GET(p, 0x0201, &igot); get0 = igot; switch (get0) { @@ -872,8 +913,7 @@ __u16 igot; int rc0, rc1; if (!pusb_device) - return -EFAULT; - + return -ENODEV; rc1 = 0; igot = 0; rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ (__u8)0x01, \ @@ -936,8 +976,7 @@ regget(struct usb_device *pusb_device, __u16 index, void *pvoid) int ir; if (!pusb_device) - return -EFAULT; - + return -ENODEV; ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \ (__u8)0x00, \ (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \ @@ -952,6 +991,8 @@ return 0xFF & ir; int wakeup_device(struct usb_device *pusb_device) { +if (!pusb_device) + return -ENODEV; return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ (__u8)USB_REQ_SET_FEATURE, \ (__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \ @@ -1056,6 +1097,8 @@ check_vt(struct usb_device *pusb_device) { int igot; +if (!pusb_device) + return -ENODEV; igot = read_vt(pusb_device, 0x0002); if (0 > igot) SAY("ERROR: failed to read VT1612A register 0x02\n"); @@ -1128,7 +1171,7 @@ int igot; __u8 u8; __u16 mute; -if ((struct usb_device *)NULL == pusb_device) +if (NULL == pusb_device) return -ENODEV; if (0 > loud) loud = 0; diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index ee5c8d990bdf..67ae755fcfac 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -45,11 +45,14 @@ module_param(gain, int, S_IRUGO | S_IWUSR); * IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap * ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN * PROBING INTERFACES 1 AND 2. + * + * IOCTL LOCKING IS DONE AT MODULE LEVEL, NOT DEVICE LEVEL. */ /*---------------------------------------------------------------------------*/ -struct easycap *peasycap_dongle[DONGLE_MANY]; +struct easycap_dongle easycap_dongle[DONGLE_MANY]; static int dongle_this; +static int dongle_done; /*---------------------------------------------------------------------------*/ /* @@ -80,7 +83,11 @@ const struct file_operations easycap_fops = { .owner = THIS_MODULE, .open = easycap_open, .release = easycap_release, - .unlocked_ioctl = easycap_ioctl, +#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL) + .unlocked_ioctl = easycap_ioctl_noinode, +#else + .ioctl = easycap_ioctl, +#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/ .poll = easycap_poll, .mmap = easycap_mmap, .llseek = no_llseek, @@ -103,7 +110,11 @@ const struct v4l2_file_operations v4l2_fops = { .owner = THIS_MODULE, .open = easycap_open_noinode, .release = easycap_release_noinode, - .unlocked_ioctl = easycap_ioctl, +#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL) + .unlocked_ioctl = easycap_ioctl_noinode, +#else + .ioctl = easycap_ioctl, +#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/ .poll = easycap_poll, .mmap = easycap_mmap, }; @@ -120,7 +131,11 @@ const struct file_operations easysnd_fops = { .owner = THIS_MODULE, .open = easysnd_open, .release = easysnd_release, - .unlocked_ioctl = easysnd_ioctl, +#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL) + .unlocked_ioctl = easysnd_ioctl_noinode, +#else + .ioctl = easysnd_ioctl, +#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/ .read = easysnd_read, .llseek = no_llseek, }; @@ -139,10 +154,10 @@ int isdongle(struct easycap *peasycap) { int k; -if ((struct easycap *)NULL == peasycap) +if (NULL == peasycap) return -2; for (k = 0; k < DONGLE_MANY; k++) { - if (peasycap_dongle[k] == peasycap) { + if (easycap_dongle[k].peasycap == peasycap) { peasycap->isdongle = k; return k; } @@ -196,11 +211,10 @@ if ((struct video_device *)NULL == pvideo_device) { peasycap = (struct easycap *)video_get_drvdata(pvideo_device); #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } -file->private_data = peasycap; if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; @@ -208,6 +222,7 @@ if (NULL == peasycap->pusb_device) { JOM(16, "0x%08lX=peasycap->pusb_device\n", \ (long int)peasycap->pusb_device); } +file->private_data = peasycap; rc = wakeup_device(peasycap->pusb_device); if (0 == rc) JOM(8, "wakeup_device() OK\n"); @@ -243,7 +258,7 @@ struct easycap_standard const *peasycap_standard; int i, rc, input, rate; bool ntsc, other; -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } @@ -251,7 +266,7 @@ input = peasycap->input; /*---------------------------------------------------------------------------*/ /* - * IF THE SAA7113H HAS ALREADY ACQUIRED LOCK, USE ITS HARDWARE-DETECTED + * IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED * FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR * gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE * A SWITCH BETWEEN PAL AND NTSC. @@ -447,7 +462,7 @@ if (NULL == peasycap) { } JOM(8, "%i=input sought\n", input); -if ((0 > input) &&(INPUT_MANY <= input)) +if (0 > input && INPUT_MANY <= input) return -ENOENT; inputnow = peasycap->input; if (input == inputnow) @@ -581,7 +596,7 @@ if (input == peasycap->inputset[input].input) { return -ENOENT; } /*---------------------------------------------------------------------------*/ -if ((struct usb_device *)NULL == peasycap->pusb_device) { +if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -ENODEV; } @@ -617,16 +632,16 @@ struct list_head *plist_head; int j, isbad, nospc, m, rc; int isbuf; -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } -if ((struct list_head *)NULL == peasycap->purb_video_head) { +if (NULL == peasycap->purb_video_head) { SAY("ERROR: peasycap->urb_video_head uninitialized\n"); return -EFAULT; } -if ((struct usb_device *)NULL == peasycap->pusb_device) { +if (NULL == peasycap->pusb_device) { SAY("ERROR: peasycap->pusb_device is NULL\n"); return -ENODEV; } @@ -768,7 +783,7 @@ int m; struct list_head *plist_head; struct data_urb *pdata_urb; -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } @@ -780,8 +795,8 @@ if (peasycap->video_isoc_streaming) { list_for_each(plist_head, (peasycap->purb_video_head)) { pdata_urb = list_entry(plist_head, struct data_urb, \ list_head); - if ((struct data_urb *)NULL != pdata_urb) { - if ((struct urb *)NULL != pdata_urb->purb) { + if (NULL != pdata_urb) { + if (NULL != pdata_urb->purb) { usb_kill_urb(pdata_urb->purb); m++; } @@ -864,15 +879,17 @@ return 0; /*****************************************************************************/ /*--------------------------------------------------------------------------*/ /* - * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect(). - * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED. - * peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL. + * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS + * PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect(). + * + * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO + * peasycap->pusb_device IS NO LONGER VALID. */ /*---------------------------------------------------------------------------*/ void easycap_delete(struct kref *pkref) { -int k, m, gone; +int k, m, gone, kd; int allocation_video_urb, allocation_video_page, allocation_video_struct; int allocation_audio_urb, allocation_audio_page, allocation_audio_struct; int registered_video, registered_audio; @@ -883,10 +900,11 @@ struct list_head *plist_head, *plist_next; JOT(4, "\n"); peasycap = container_of(pkref, struct easycap, kref); -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAM("ERROR: peasycap is NULL: cannot perform deletions\n"); return; } +kd = isdongle(peasycap); /*---------------------------------------------------------------------------*/ /* * FREE VIDEO. @@ -925,8 +943,6 @@ if ((struct list_head *)NULL != peasycap->purb_video_head) { JOM(4, "%i video data_urb structures freed\n", m); JOM(4, "setting peasycap->purb_video_head=NULL\n"); peasycap->purb_video_head = (struct list_head *)NULL; - } else { -JOM(4, "peasycap->purb_video_head is NULL\n"); } /*---------------------------------------------------------------------------*/ JOM(4, "freeing video isoc buffers.\n"); @@ -1051,15 +1067,16 @@ allocation_audio_urb = peasycap->allocation_audio_urb; allocation_audio_page = peasycap->allocation_audio_page; allocation_audio_struct = peasycap->allocation_audio_struct; registered_audio = peasycap->registered_audio; -m = 0; -if ((struct easycap *)NULL != peasycap) { - kfree(peasycap); peasycap = (struct easycap *)NULL; + +kfree(peasycap); +if (0 <= kd && DONGLE_MANY > kd) { + easycap_dongle[kd].peasycap = (struct easycap *)NULL; + JOT(4, " null-->easycap_dongle[%i].peasycap\n", kd); allocation_video_struct -= sizeof(struct easycap); - m++; +} else { + SAY("ERROR: cannot purge easycap_dongle[].peasycap"); } -JOT(4, "%i easycap structure freed\n", m); /*---------------------------------------------------------------------------*/ - SAY("%8i= video urbs after all deletions\n", allocation_video_urb); SAY("%8i= video pages after all deletions\n", allocation_video_page); SAY("%8i= video structs after all deletions\n", allocation_video_struct); @@ -1076,27 +1093,75 @@ return; unsigned int easycap_poll(struct file *file, poll_table *wait) { struct easycap *peasycap; +int rc, kd; JOT(8, "\n"); if (NULL == ((poll_table *)wait)) JOT(8, "WARNING: poll table pointer is NULL ... continuing\n"); -if (NULL == ((struct file *)file)) { +if ((struct file *)NULL == file) { SAY("ERROR: file pointer is NULL\n"); - return -EFAULT; + return -ERESTARTSYS; } peasycap = file->private_data; if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +if (NULL == peasycap->pusb_device) { + SAY("ERROR: peasycap->pusb_device is NULL\n"); + return -EFAULT; +} +/*---------------------------------------------------------------------------*/ +kd = isdongle(peasycap); +if (0 <= kd && DONGLE_MANY > kd) { + if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) { + SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd); + return -ERESTARTSYS; + } + JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd); + /*-------------------------------------------------------------------*/ + /* + * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER + * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. + * IF NECESSARY, BAIL OUT. + */ + /*-------------------------------------------------------------------*/ + if (kd != isdongle(peasycap)) + return -ERESTARTSYS; + if (NULL == file) { + SAY("ERROR: file is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } + peasycap = file->private_data; + if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } + if (NULL == peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } +} else + /*-------------------------------------------------------------------*/ + /* + * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap + * BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL + * HAVE FAILED. BAIL OUT. + */ + /*-------------------------------------------------------------------*/ + return -ERESTARTSYS; +/*---------------------------------------------------------------------------*/ +rc = easycap_dqbuf(peasycap, 0); peasycap->polled = 1; - -if (0 == easycap_dqbuf(peasycap, 0)) +mutex_unlock(&easycap_dongle[kd].mutex_video); +if (0 == rc) return POLLIN | POLLRDNORM; else return POLLERR; - } /*****************************************************************************/ /*---------------------------------------------------------------------------*/ @@ -1115,6 +1180,10 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +if (NULL == peasycap->pusb_device) { + SAY("ERROR: peasycap->pusb_device is NULL\n"); + return -EFAULT; +} ifield = 0; JOM(8, "%i=ifield\n", ifield); /*---------------------------------------------------------------------------*/ @@ -1122,9 +1191,9 @@ JOM(8, "%i=ifield\n", ifield); * CHECK FOR LOST INPUT SIGNAL. * * FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED. - * IF INPUT 0 IS PRESENT AND LOCKED, UNPLUGGING INPUT 4 DOES NOT RESULT IN - * SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE IS FLYWHEELING - * ON INPUT 0. THE UPSHOT IS: + * IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT + * RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE + * IS FLYWHEELING ON INPUT 0. THE UPSHOT IS: * * INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK * INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK @@ -1342,7 +1411,7 @@ int rc, bytesperpixel, multiplier, much, more, over, rump, caches, input; __u8 mask, margin; bool odd, isuy, decimatepixel, offerfields, badinput; -if ((struct easycap *)NULL == peasycap) { +if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } @@ -1447,13 +1516,11 @@ while (cz < wz) { much) / 2; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (1 < bytesperpixel) { - if ((rad * \ - 2) < (much * \ - bytesperpixel)) { + if (rad * 2 < much * bytesperpixel) { /* ** INJUDICIOUS ALTERATION OF THIS - ** BLOCK WILL CAUSE BREAKAGE. - ** BEWARE. + ** STATEMENT BLOCK WILL CAUSE + ** BREAKAGE. BEWARE. **/ rad2 = rad + bytesperpixel - 1; much = ((((2 * \ @@ -1483,7 +1550,6 @@ while (cz < wz) { /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (rump) caches++; - if (true == badinput) { JOM(8, "ERROR: 0x%02X=->field_buffer" \ "[%i][%i].input, " \ @@ -1492,7 +1558,6 @@ while (cz < wz) { [kex][mex].input, kex, mex, \ (0x08|peasycap->input)); } - rc = redaub(peasycap, pad, pex, much, more, \ mask, margin, isuy); if (0 > rc) { @@ -1575,12 +1640,11 @@ while (cz < wz) { much) / 4; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (1 < bytesperpixel) { - if ((rad * 4) < (much * \ - bytesperpixel)) { + if (rad * 4 < much * bytesperpixel) { /* ** INJUDICIOUS ALTERATION OF THIS - ** BLOCK WILL CAUSE BREAKAGE. - ** BEWARE. + ** STATEMENT BLOCK WILL CAUSE + ** BREAKAGE. BEWARE. **/ rad2 = rad + bytesperpixel - 1; much = ((((2 * rad2)/bytesperpixel)/2)\ @@ -1620,7 +1684,6 @@ while (cz < wz) { [kex][mex].input, kex, mex, \ (0x08|peasycap->input)); } - rc = redaub(peasycap, pad, pex, much, more, \ mask, margin, isuy); if (0 > rc) { @@ -3297,8 +3360,8 @@ return; * FIXME * * - * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS - * PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST. + * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE EasyCAP + * IS PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST. * IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops. * * THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE. @@ -3338,6 +3401,16 @@ __s32 value; struct easycap_format *peasycap_format; JOT(4, "\n"); + +if (!dongle_done) { + dongle_done = 1; + for (k = 0; k < DONGLE_MANY; k++) { + easycap_dongle[k].peasycap = (struct easycap *)NULL; + mutex_init(&easycap_dongle[k].mutex_video); + mutex_init(&easycap_dongle[k].mutex_audio); + } +} + peasycap = (struct easycap *)NULL; if ((struct usb_interface *)NULL == pusb_interface) { @@ -3481,12 +3554,20 @@ if (0 == bInterfaceNumber) { init_waitqueue_head(&peasycap->wq_audio); for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) { - if ((struct easycap *)NULL == peasycap_dongle[dongle_this]) { - peasycap_dongle[dongle_this] = peasycap; - JOM(8, "intf[%i]: peasycap-->easycap" \ + if (NULL == easycap_dongle[dongle_this].peasycap) { + if (0 == mutex_is_locked(&easycap_dongle\ + [dongle_this].mutex_video)) { + if (0 == mutex_is_locked(&easycap_dongle\ + [dongle_this].mutex_audio)) { + easycap_dongle\ + [dongle_this].peasycap = \ + peasycap; + JOM(8, "intf[%i]: peasycap-->easycap" \ "_dongle[%i].peasycap\n", \ bInterfaceNumber, dongle_this); - break; + break; + } + } } } if (DONGLE_MANY <= dongle_this) { @@ -3665,15 +3746,15 @@ if (0 == bInterfaceNumber) { * FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING * THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF * THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN - * SIMULTANEOUSLY, THERE WILL BE VERY SERIOUS TROUBLE. + * SIMULTANEOUSLY, THERE WILL BE SERIOUS TROUBLE. */ /*---------------------------------------------------------------------------*/ if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) { SAY("ERROR: bad dongle count\n"); return -EFAULT; } - peasycap = peasycap_dongle[dongle_this]; - JOT(8, "intf[%i]: peasycap_dongle[%i]-->peasycap\n", \ + peasycap = easycap_dongle[dongle_this].peasycap; + JOT(8, "intf[%i]: easycap_dongle[%i].peasycap-->peasycap\n", \ bInterfaceNumber, dongle_this); if ((struct easycap *)NULL == peasycap) { @@ -3721,6 +3802,7 @@ if ((USB_CLASS_VIDEO == bInterfaceClass) || \ */ /*---------------------------------------------------------------------------*/ isokalt = 0; + for (i = 0; i < pusb_interface->num_altsetting; i++) { pusb_host_interface = &(pusb_interface->altsetting[i]); if ((struct usb_host_interface *)NULL == pusb_host_interface) { @@ -4245,6 +4327,9 @@ case 0: { } /*---------------------------------------------------------------------------*/ /* + * FIXME + * + * * THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG: */ /*---------------------------------------------------------------------------*/ @@ -4587,9 +4672,8 @@ return 0; /*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* - * WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY - * UNPLUGGED. - * HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL. + * WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY + * UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID. */ /*---------------------------------------------------------------------------*/ void @@ -4602,7 +4686,7 @@ struct easycap *peasycap; struct list_head *plist_head; struct data_urb *pdata_urb; -int minor, m; +int minor, m, kd; JOT(4, "\n"); @@ -4691,49 +4775,75 @@ default: /*--------------------------------------------------------------------------*/ /* * DEREGISTER + * + * THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO + * IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN + * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE. */ /*--------------------------------------------------------------------------*/ +kd = isdongle(peasycap); switch (bInterfaceNumber) { case 0: { + if (0 <= kd && DONGLE_MANY > kd) { + wake_up_interruptible(&peasycap->wq_video); + JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd); + if (mutex_lock_interruptible(&easycap_dongle[kd].\ + mutex_video)) { + SAY("ERROR: cannot lock easycap_dongle[%i]." \ + "mutex_video\n", kd); + return; + } + JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd); + } else + SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd); +/*---------------------------------------------------------------------------*/ #if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) if ((struct easycap *)NULL == peasycap) { SAM("ERROR: peasycap has become NULL\n"); } else { - lock_kernel(); usb_deregister_dev(pusb_interface, &easycap_class); (peasycap->registered_video)--; - JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); - unlock_kernel(); SAM("easycap detached from minor #%d\n", minor); } /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #else - if ((struct easycap *)NULL == peasycap) - SAM("ERROR: peasycap has become NULL\n"); - else { - lock_kernel(); - video_unregister_device(&peasycap->video_device); - (peasycap->registered_video)--; - unlock_kernel(); - JOM(4, "unregistered with videodev: %i=minor\n", \ + video_unregister_device(&peasycap->video_device); + JOM(4, "unregistered with videodev: %i=minor\n", \ peasycap->video_device.minor); - } + (peasycap->registered_video)--; /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ + if (0 <= kd && DONGLE_MANY > kd) { + mutex_unlock(&easycap_dongle[kd].mutex_video); + JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd); + } break; } case 2: { - lock_kernel(); + if (0 <= kd && DONGLE_MANY > kd) { + wake_up_interruptible(&peasycap->wq_audio); + JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd); + if (mutex_lock_interruptible(&easycap_dongle[kd].\ + mutex_audio)) { + SAY("ERROR: cannot lock easycap_dongle[%i]." \ + "mutex_audio\n", kd); + return; + } + JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd); + } else + SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd); usb_deregister_dev(pusb_interface, &easysnd_class); - if ((struct easycap *)NULL != peasycap) - (peasycap->registered_audio)--; + (peasycap->registered_audio)--; JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); - unlock_kernel(); - SAM("easysnd detached from minor #%d\n", minor); + + if (0 <= kd && DONGLE_MANY > kd) { + mutex_unlock(&easycap_dongle[kd].mutex_audio); + JOM(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd); + } break; } default: @@ -4744,24 +4854,41 @@ default: * CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap */ /*---------------------------------------------------------------------------*/ -if ((struct easycap *)NULL == peasycap) { - SAM("ERROR: peasycap has become NULL\n"); - SAM("cannot call kref_put()\n"); - SAM("ending unsuccessfully: may cause memory leak\n"); - return; -} if (!peasycap->kref.refcount.counter) { - SAM("ERROR: peasycap->kref.refcount.counter is zero " \ + SAM("ERROR: peasycap->kref.refcount.counter is zero " "so cannot call kref_put()\n"); SAM("ending unsuccessfully: may cause memory leak\n"); return; } -JOM(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \ +if (0 <= kd && DONGLE_MANY > kd) { + JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd); + if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) { + SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd); + SAM("ending unsuccessfully: may cause memory leak\n"); + return; + } + JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd); + JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd); + if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) { + SAY("ERROR: cannot down easycap_dongle[%i].mutex_audio\n", kd); + mutex_unlock(&(easycap_dongle[kd].mutex_video)); + JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd); + SAM("ending unsuccessfully: may cause memory leak\n"); + return; + } + JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd); +} +JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n", \ bInterfaceNumber, (int)peasycap->kref.refcount.counter); kref_put(&peasycap->kref, easycap_delete); -JOM(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber); +JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber); +if (0 <= kd && DONGLE_MANY > kd) { + mutex_unlock(&(easycap_dongle[kd].mutex_audio)); + JOT(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd); + mutex_unlock(&easycap_dongle[kd].mutex_video); + JOT(4, "unlocked easycap_dongle[%i].mutex_video\n", kd); +} /*---------------------------------------------------------------------------*/ - JOM(4, "ends\n"); return; } diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c index 0b4b60b0a5a7..dc97516cca43 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/easycap/easycap_sound.c @@ -636,7 +636,7 @@ else if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -EFAULT; + return -ENODEV; } /*---------------------------------------------------------------------------*/ if ((struct usb_device *)NULL == peasycap->pusb_device) { @@ -695,7 +695,7 @@ long long int above, below, mean; struct signed_div_result sdr; unsigned char *p0; long int kount1, more, rc, l0, lm; -int fragment; +int fragment, kd; struct easycap *peasycap; struct data_buffer *pdata_buffer; size_t szret; @@ -713,20 +713,76 @@ size_t szret; JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff)); -peasycap = (struct easycap *)(file->private_data); +if (NULL == file) { + SAY("ERROR: file is NULL\n"); + return -ERESTARTSYS; +} +peasycap = file->private_data; if (NULL == peasycap) { SAY("ERROR in easysnd_read(): peasycap is NULL\n"); return -EFAULT; } +if (NULL == peasycap->pusb_device) { + SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n"); + return -EFAULT; +} +kd = isdongle(peasycap); +if (0 <= kd && DONGLE_MANY > kd) { + if (mutex_lock_interruptible(&(easycap_dongle[kd].mutex_audio))) { + SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd); + return -ERESTARTSYS; + } + JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd); +/*---------------------------------------------------------------------------*/ +/* + * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap, + * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. + * IF NECESSARY, BAIL OUT. +*/ +/*---------------------------------------------------------------------------*/ + if (kd != isdongle(peasycap)) + return -ERESTARTSYS; + if (NULL == file) { + SAY("ERROR: file is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } + peasycap = file->private_data; + if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } + if (NULL == peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } +} else { +/*---------------------------------------------------------------------------*/ +/* + * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE + * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT. +*/ +/*---------------------------------------------------------------------------*/ + return -ERESTARTSYS; +} /*---------------------------------------------------------------------------*/ +if (file->f_flags & O_NONBLOCK) + JOT(16, "NONBLOCK kount=%i, *poff=%i\n", (int)kount, (int)(*poff)); +else + JOT(8, "BLOCKING kount=%i, *poff=%i\n", (int)kount, (int)(*poff)); + if ((0 > peasycap->audio_read) || \ (peasycap->audio_buffer_page_many <= peasycap->audio_read)) { SAM("ERROR: peasycap->audio_read out of range\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read]; if ((struct data_buffer *)NULL == pdata_buffer) { SAM("ERROR: pdata_buffer is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } JOM(12, "before wait, %i=frag read %i=frag fill\n", \ @@ -738,6 +794,7 @@ while ((fragment == (peasycap->audio_fill / \ (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) { if (file->f_flags & O_NONBLOCK) { JOM(16, "returning -EAGAIN as instructed\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EAGAIN; } rc = wait_event_interruptible(peasycap->wq_audio, \ @@ -747,21 +804,25 @@ while ((fragment == (peasycap->audio_fill / \ (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))))); if (0 != rc) { SAM("aborted by signal\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -ERESTARTSYS; } if (peasycap->audio_eof) { JOM(8, "returning 0 because %i=audio_eof\n", \ peasycap->audio_eof); kill_audio_urbs(peasycap); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return 0; } if (peasycap->audio_idle) { JOM(16, "returning 0 because %i=audio_idle\n", \ peasycap->audio_idle); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return 0; } if (!peasycap->audio_isoc_streaming) { JOM(16, "returning 0 because audio urbs not streaming\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return 0; } } @@ -773,15 +834,18 @@ while (fragment == (peasycap->audio_read / \ peasycap->audio_pages_per_fragment)) { if (NULL == pdata_buffer->pgo) { SAM("ERROR: pdata_buffer->pgo is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } if (NULL == pdata_buffer->pto) { SAM("ERROR: pdata_buffer->pto is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo); if (0 > kount1) { SAM("easysnd_read: MISTAKE: kount1 is negative\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -ERESTARTSYS; } if (!kount1) { @@ -799,19 +863,23 @@ while (fragment == (peasycap->audio_read / \ (peasycap->audio_buffer_page_many <= \ peasycap->audio_read)) { SAM("ERROR: peasycap->audio_read out of range\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read]; if ((struct data_buffer *)NULL == pdata_buffer) { SAM("ERROR: pdata_buffer is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } if (NULL == pdata_buffer->pgo) { SAM("ERROR: pdata_buffer->pgo is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } if (NULL == pdata_buffer->pto) { SAM("ERROR: pdata_buffer->pto is NULL\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo); @@ -840,6 +908,7 @@ while (fragment == (peasycap->audio_read / \ rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more); if (0 != rc) { SAM("ERROR: copy_to_user() returned %li\n", rc); + mutex_unlock(&easycap_dongle[kd].mutex_audio); return -EFAULT; } *poff += (loff_t)more; @@ -902,6 +971,7 @@ JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient); peasycap->dnbydt = sdr.quotient; JOM(8, "returning %li\n", (long int)szret); +mutex_unlock(&easycap_dongle[kd].mutex_audio); return szret; } /*****************************************************************************/ -- cgit v1.2.3 From 268dfede46e24eef55a2ef7a10a462617936771e Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Sun, 7 Nov 2010 20:11:36 +0000 Subject: staging/easycap: Improve interface to the videodev module The changes here represent an intermediate step towards bringing the driver within the V4L2 framework. Signed-off-by: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/README | 93 ++++++++++++------ drivers/staging/easycap/easycap.h | 16 +--- drivers/staging/easycap/easycap_ioctl.c | 26 +++++- drivers/staging/easycap/easycap_main.c | 161 ++++++++++++++++++++++++++------ drivers/staging/easycap/easycap_sound.c | 63 ++++++++++++- 5 files changed, 287 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/README b/drivers/staging/easycap/README index 3775481f05e8..6b5ac0d34bd9 100644 --- a/drivers/staging/easycap/README +++ b/drivers/staging/easycap/README @@ -24,6 +24,9 @@ Two kinds of EasyCAP have this USB ID, namely: BUILD OPTIONS AND DEPENDENCIES ------------------------------ +Unless EASYCAP_DEBUG is defined during compilation it will not be possible +to select a debug level at the time of module installation. + If the parameter EASYCAP_IS_VIDEODEV_CLIENT is undefined during compilation the built module is entirely independent of the videodev module, and when the EasyCAP is physically plugged into a USB port the special files @@ -33,41 +36,54 @@ respectively. If the parameter EASYCAP_IS_VIDEODEV_CLIENT is defined during compilation the built easycap module is configured to register with the videodev module, in which case the special files created when the EasyCAP is plugged in are -/dev/video0 and /dev/easysnd0. Use of the easycap module as a client of -the videodev module has received very little testing as of June 2010. +/dev/video0 and /dev/easysnd0. + +During in-tree builds the following should should be defined whenever the +parameter EASYCAP_IS_VIDEODEV_CLIENT is defined: + +EASYCAP_NEEDS_V4L2_DEVICE_H +EASYCAP_NEEDS_V4L2_FOPS +EASYCAP_NEEDS_UNLOCKED_IOCTL + +If the build is performed out-of-tree against older kernels the parameters +to be defined depend on the kernel version in a way which will not be +discussed here. -KNOWN BUILD PROBLEMS +KNOWN RUNTIME ISSUES -------------------- -(1) Recent gcc versions may generate the message: +(1) Intentionally, this driver will not stream material which is unambiguously +identified by the hardware as copy-protected. Normal video output will be +present for about a minute but will then freeze when this situation arises. - warning: the frame size of .... bytes is larger than 1024 bytes +(2) The controls for luminance, contrast, saturation, hue and volume may not +always work properly. -This warning can be suppressed by specifying in the Makefile: +(3) Reduced-resolution S-Video seems to suffer from moire artefacts. - EXTRA_CFLAGS += -Wframe-larger-than=8192 -but it would be preferable to remove the cause of the warning. +INPUT NUMBERING +--------------- +For the EasyCAP with S-VIDEO input cable the driver regards a request for +inputs numbered 0 or 1 as referring to CVBS and a request for input +numbered 5 as referring to S-VIDEO. -KNOWN RUNTIME ISSUES --------------------- +For the EasyCAP with four CVBS inputs the driver expects to be asked for +any one of inputs numbered 1,2,3,4. If input 0 is asked for, it is +interpreted as input 1. -(1) Randomly (maybe 5 to 10% of occasions) the driver fails to produce any -output at start-up. Closing mplayer (or whatever the user program is) and -restarting it restores normal performance without any other remedial action -being necessary. The reason for this is not known. -(2) Intentionally, this driver will not stream material which is unambiguously -identified by the hardware as copy-protected. The video output will freeze -within about a minute when this situation arises. +MODULE PARAMETERS +----------------- -(3) The controls for luminance, contrast, saturation, hue and volume may not -always work properly. +Three module parameters are defined: -(4) Reduced-resolution S-Video seems to suffer from moire artefacts. No -attempt has yet been made to rememdy this. +debug the easycap module is configured at diagnostic level n (0 to 9) +gain audio gain level n (0 to 31, default is 16) +bars 0 => testcard bars when incoming video signal is lost + 1 => testcard bars when incoming video signal is lost (default) SUPPORTED TV STANDARDS AND RESOLUTIONS @@ -82,18 +98,29 @@ usable as (for example) the "norm=" parameter in the mplayer command: PAL_60, NTSC_443, PAL_M. +In addition, the driver offers "custom" pseudo-standards with a framerate +which is 20% of the usual framerate. These pseudo-standards are named: + + PAL_BGHIN_SLOW, NTSC_N_443_SLOW, + PAL_Nc_SLOW, NTSC_N_SLOW, + SECAM_SLOW, NTSC_M_SLOW, NTSC_M_JP_SLOW, + PAL_60_SLOW, NTSC_443_SLOW, + PAL_M_SLOW. + + The available picture sizes are: at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240; - at 30 frames per second: 720x480, 640x480, 360x240, 320x240; + at 30 frames per second: 720x480, 640x480, 360x240, 320x240. WHAT'S TESTED AND WHAT'S NOT ---------------------------- -This driver is known to work with mplayer, mencoder, tvtime and sufficiently -recent versions of vlc. An interface to ffmpeg is implemented, but serious -audio-video synchronization problems remain. +This driver is known to work with mplayer, mencoder, tvtime, zoneminder, +xawtv, gstreamer and sufficiently recent versions of vlc. An interface +to ffmpeg is implemented, but serious audio-video synchronization problems +remain. The driver is designed to support all the TV standards accepted by the hardware, but as yet it has actually been tested on only a few of these. @@ -101,10 +128,7 @@ hardware, but as yet it has actually been tested on only a few of these. I have been unable to test and calibrate the S-video input myself because I do not possess any equipment with S-video output. -This driver does not understand the V4L1 IOCTL commands, so programs such -as camorama are not compatible. There are reports that the driver does -work with sufficiently recent (V4L2) versions of zoneminder, but I have not -attempted to confirm this myself. +This driver does not understand the V4L1 IOCTL commands. UDEV RULES @@ -120,6 +144,17 @@ ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \ LABEL="easycap_rules_end" +MODPROBE CONFIGURATION +---------------------- + +The easycap module is in competition with the module snd-usb-audio for the +EasyCAP's audio channel, and its installation can be aided by providing a +file in directory /etc/modprobe.d with content: + +options easycap gain=16 bars=1 +install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap + + ACKNOWLEGEMENTS AND REFERENCES ------------------------------ This driver makes use of information contained in the Syntek Semicon DC-1125 diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index 762c6cea54c3..cc8e8c581ae8 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -33,6 +33,7 @@ * EASYCAP_NEEDS_USBVIDEO_H * EASYCAP_NEEDS_V4L2_DEVICE_H * EASYCAP_NEEDS_V4L2_FOPS + * EASYCAP_NEEDS_UNLOCKED_IOCTL * * IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER * OPTIONS. @@ -81,25 +82,14 @@ /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #if defined(EASYCAP_IS_VIDEODEV_CLIENT) -#if (!defined(__OLD_VIDIOC_)) -#define __OLD_VIDIOC_ -#endif /* !defined(__OLD_VIDIOC_) */ - #include - #if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) #include #endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - -#if (!defined(__OLD_VIDIOC_)) -#define __OLD_VIDIOC_ -#endif /* !defined(__OLD_VIDIOC_) */ #include - #include - #if defined(EASYCAP_NEEDS_USBVIDEO_H) #include #endif /*EASYCAP_NEEDS_USBVIDEO_H*/ @@ -110,7 +100,6 @@ #define STRINGIZE_AGAIN(x) #x #define STRINGIZE(x) STRINGIZE_AGAIN(x) - /*---------------------------------------------------------------------------*/ /* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd * @@ -305,6 +294,8 @@ int hue_ok; */ /*---------------------------------------------------------------------------*/ struct easycap { +#define TELLTALE "expectedstring" +char telltale[16]; int isdongle; /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ @@ -501,7 +492,6 @@ long easycap_ioctl_noinode(struct file *, unsigned int, \ unsigned long); int easycap_ioctl(struct inode *, struct file *, unsigned int, \ unsigned long); - /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #if defined(EASYCAP_IS_VIDEODEV_CLIENT) int easycap_open_noinode(struct file *); diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 2f9b3eab4898..447953a4e80c 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -977,9 +977,13 @@ if (NULL == file) { } peasycap = file->private_data; if (NULL == peasycap) { - SAY("ERROR: peasycap is NULL.\n"); + SAY("ERROR: peasycap is NULL\n"); return -1; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap\n"); + return -EFAULT; +} p = peasycap->pusb_device; if (NULL == p) { SAM("ERROR: peasycap->pusb_device is NULL\n"); @@ -1012,6 +1016,11 @@ if (0 <= kd && DONGLE_MANY > kd) { mutex_unlock(&easycap_dongle[kd].mutex_video); return -ERESTARTSYS; } + if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap\n"); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -EFAULT; + } p = peasycap->pusb_device; if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); @@ -2297,7 +2306,7 @@ case VIDIOC_DQBUF: ((long long int)(timeval.tv_sec - \ timeval2.tv_sec)) + \ (long long int)(timeval.tv_usec - \ - timeval2.tv_usec); + timeval2.tv_usec); sdr = signed_div(fudge, 1000); sll = sdr.quotient; ull = sdr.remainder; @@ -2317,6 +2326,8 @@ case VIDIOC_DQBUF: JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); JOM(16, " %10i=field\n", v4l2_buffer.field); + JOM(16, " %10li=timestamp.tv_sec\n", \ + (long)v4l2_buffer.timestamp.tv_sec); JOM(16, " %10li=timestamp.tv_usec\n", \ (long)v4l2_buffer.timestamp.tv_usec); JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); @@ -2528,6 +2539,10 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL.\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap\n"); + return -EFAULT; +} p = peasycap->pusb_device; if (NULL == p) { SAM("ERROR: peasycap->pusb_device is NULL\n"); @@ -2560,6 +2575,11 @@ if (0 <= kd && DONGLE_MANY > kd) { mutex_unlock(&easycap_dongle[kd].mutex_audio); return -ERESTARTSYS; } + if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap\n"); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -EFAULT; + } p = peasycap->pusb_device; if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); @@ -2795,3 +2815,5 @@ mutex_unlock(&easycap_dongle[kd].mutex_audio); return 0; } /*****************************************************************************/ + + diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index 67ae755fcfac..25e41784f4e5 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -93,16 +93,15 @@ const struct file_operations easycap_fops = { .llseek = no_llseek, }; struct vm_operations_struct easycap_vm_ops = { -.open = easycap_vma_open, -.close = easycap_vma_close, -.fault = easycap_vma_fault, + .open = easycap_vma_open, + .close = easycap_vma_close, + .fault = easycap_vma_fault, }; struct usb_class_driver easycap_class = { -.name = "usb/easycap%d", -.fops = &easycap_fops, -.minor_base = USB_SKEL_MINOR_BASE, + .name = "usb/easycap%d", + .fops = &easycap_fops, + .minor_base = USB_SKEL_MINOR_BASE, }; - /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #if defined(EASYCAP_IS_VIDEODEV_CLIENT) #if defined(EASYCAP_NEEDS_V4L2_FOPS) @@ -121,7 +120,6 @@ const struct v4l2_file_operations v4l2_fops = { #endif /*EASYCAP_NEEDS_V4L2_FOPS*/ #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - /*--------------------------------------------------------------------------*/ /* * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE @@ -147,7 +145,7 @@ struct usb_class_driver easysnd_class = { /****************************************************************************/ /*---------------------------------------------------------------------------*/ /* - * THIS ROUTINE DOES NOT DETECT MULTIPLE OCCURRENCES OF POINTER peasycap + * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap */ /*---------------------------------------------------------------------------*/ int @@ -215,6 +213,10 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; @@ -838,6 +840,10 @@ if (NULL == peasycap) { SAY("ending unsuccessfully\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} if (0 != kill_video_urbs(peasycap)) { SAM("ERROR: kill_video_urbs() failed\n"); return -EFAULT; @@ -867,6 +873,10 @@ if (NULL == peasycap) { SAY("ending unsuccessfully\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} if (0 != kill_video_urbs(peasycap)) { SAM("ERROR: kill_video_urbs() failed\n"); return -EFAULT; @@ -904,6 +914,10 @@ if (NULL == peasycap) { SAM("ERROR: peasycap is NULL: cannot perform deletions\n"); return; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return; +} kd = isdongle(peasycap); /*---------------------------------------------------------------------------*/ /* @@ -1026,8 +1040,6 @@ if ((struct list_head *)NULL != peasycap->purb_audio_head) { JOM(4, "%i audio data_urb structures freed\n", m); JOM(4, "setting peasycap->purb_audio_head=NULL\n"); peasycap->purb_audio_head = (struct list_head *)NULL; -} else { -JOM(4, "peasycap->purb_audio_head is NULL\n"); } /*---------------------------------------------------------------------------*/ JOM(4, "freeing audio isoc buffers.\n"); @@ -1108,6 +1120,10 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} if (NULL == peasycap->pusb_device) { SAY("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; @@ -1140,10 +1156,16 @@ if (0 <= kd && DONGLE_MANY > kd) { mutex_unlock(&easycap_dongle[kd].mutex_video); return -ERESTARTSYS; } + if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", \ + (unsigned long int) peasycap); + mutex_unlock(&easycap_dongle[kd].mutex_video); + return -ERESTARTSYS; + } if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); mutex_unlock(&easycap_dongle[kd].mutex_video); - return -ERESTARTSYS; + return -ERESTARTSYS; } } else /*-------------------------------------------------------------------*/ @@ -2687,11 +2709,16 @@ easycap_vma_open(struct vm_area_struct *pvma) struct easycap *peasycap; peasycap = pvma->vm_private_data; -if (NULL != peasycap) - peasycap->vma_many++; - +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return; +} +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return; +} +peasycap->vma_many++; JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many); - return; } /*****************************************************************************/ @@ -2701,10 +2728,16 @@ easycap_vma_close(struct vm_area_struct *pvma) struct easycap *peasycap; peasycap = pvma->vm_private_data; -if (NULL != peasycap) { - peasycap->vma_many--; - JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many); +if (NULL == peasycap) { + SAY("ERROR: peasycap is NULL\n"); + return; +} +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return; } +peasycap->vma_many--; +JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many); return; } /*****************************************************************************/ @@ -2820,10 +2853,12 @@ if (NULL == peasycap) { SAY("ERROR: easycap_complete(): peasycap is NULL\n"); return; } - +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return; +} if (peasycap->video_eof) return; - for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo) break; @@ -3545,6 +3580,7 @@ if (0 == bInterfaceNumber) { * PERFORM URGENT INTIALIZATIONS ... */ /*---------------------------------------------------------------------------*/ + strcpy(&peasycap->telltale[0], TELLTALE); kref_init(&peasycap->kref); JOM(8, "intf[%i]: after kref_init(..._video) " \ "%i=peasycap->kref.refcount.counter\n", \ @@ -4299,6 +4335,26 @@ case 0: { */ /*--------------------------------------------------------------------------*/ usb_set_intfdata(pusb_interface, peasycap); +/*---------------------------------------------------------------------------*/ +/* + * IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER, + * THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE + * CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH. + * BEWARE. +*/ +/*---------------------------------------------------------------------------*/ +#if defined(PREFER_NTSC) + peasycap->ntsc = true; + JOM(8, "defaulting initially to NTSC\n"); +#else + peasycap->ntsc = false; + JOM(8, "defaulting initially to PAL\n"); +#endif /*PREFER_NTSC*/ + rc = reset(peasycap); + if (0 != rc) { + SAM("ERROR: reset() returned %i\n", rc); + return -EFAULT; + } /*--------------------------------------------------------------------------*/ /* * THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY. @@ -4687,6 +4743,13 @@ struct easycap *peasycap; struct list_head *plist_head; struct data_urb *pdata_urb; int minor, m, kd; +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#if defined(EASYCAP_IS_VIDEODEV_CLIENT) +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) +struct v4l2_device *pv4l2_device; +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ +#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ JOT(4, "\n"); @@ -4717,6 +4780,38 @@ if (NULL == peasycap) { return; } /*---------------------------------------------------------------------------*/ +#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) +# +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#else +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) +/*---------------------------------------------------------------------------*/ +/* + * SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS + * BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(), + * REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE. + * TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED. +*/ +/*---------------------------------------------------------------------------*/ +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + pv4l2_device = usb_get_intfdata(pusb_interface); + if ((struct v4l2_device *)NULL == pv4l2_device) { + SAY("ERROR: pv4l2_device is NULL\n"); + return; + } + peasycap = (struct easycap *) \ + container_of(pv4l2_device, struct easycap, v4l2_device); +} +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ +# +#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +/*---------------------------------------------------------------------------*/ +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return; +} +/*---------------------------------------------------------------------------*/ /* * IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE. BEWARE. */ @@ -4806,14 +4901,28 @@ case 0: { JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber); SAM("easycap detached from minor #%d\n", minor); } -/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ #else +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) + if (!peasycap->v4l2_device.name[0]) { + SAM("ERROR: peasycap->v4l2_device.name is empty\n"); + if (0 <= kd && DONGLE_MANY > kd) + mutex_unlock(&easycap_dongle[kd].mutex_video); + return; + } + v4l2_device_disconnect(&peasycap->v4l2_device); + JOM(4, "v4l2_device_disconnect() OK\n"); + v4l2_device_unregister(&peasycap->v4l2_device); + JOM(4, "v4l2_device_unregister() OK\n"); +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ + video_unregister_device(&peasycap->video_device); - JOM(4, "unregistered with videodev: %i=minor\n", \ - peasycap->video_device.minor); + JOM(4, "intf[%i]: video_unregister_device() OK\n", bInterfaceNumber); (peasycap->registered_video)--; -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ + JOM(4, "unregistered with videodev: %i=minor\n", minor); #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ + if (0 <= kd && DONGLE_MANY > kd) { mutex_unlock(&easycap_dongle[kd].mutex_video); JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd); @@ -4941,7 +5050,7 @@ MODULE_AUTHOR("R.M. Thomas "); MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION); MODULE_VERSION(EASYCAP_DRIVER_VERSION); #if defined(EASYCAP_DEBUG) -MODULE_PARM_DESC(debug, "Debug level: 0 (default),1,2,..."); +MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9"); #endif /*EASYCAP_DEBUG*/ MODULE_PARM_DESC(bars, \ "Testcard bars on input signal failure: 0=>no, 1=>yes(default)"); diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c index dc97516cca43..24d8bb4e449e 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/easycap/easycap_sound.c @@ -64,6 +64,11 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL\n"); return; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap\n"); + return; +} + much = 0; if (peasycap->audio_idle) { @@ -595,6 +600,13 @@ easysnd_open(struct inode *inode, struct file *file) struct usb_interface *pusb_interface; struct easycap *peasycap; int subminor, rc; +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#if defined(EASYCAP_IS_VIDEODEV_CLIENT) +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) +struct v4l2_device *pv4l2_device; +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ +#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ JOT(4, "begins\n"); @@ -612,6 +624,39 @@ if (NULL == peasycap) { SAY("ending unsuccessfully\n"); return -1; } +/*---------------------------------------------------------------------------*/ +#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT)) +# +/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ +#else +#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H) +/*---------------------------------------------------------------------------*/ +/* + * SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS + * BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(), + * REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE. + * TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED. +*/ +/*---------------------------------------------------------------------------*/ +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + pv4l2_device = usb_get_intfdata(pusb_interface); + if ((struct v4l2_device *)NULL == pv4l2_device) { + SAY("ERROR: pv4l2_device is NULL\n"); + return -EFAULT; + } + peasycap = (struct easycap *) \ + container_of(pv4l2_device, struct easycap, v4l2_device); +} +#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/ +# +#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/ +/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +/*---------------------------------------------------------------------------*/ +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} +/*---------------------------------------------------------------------------*/ file->private_data = peasycap; @@ -624,7 +669,7 @@ JOM(4, "starting initialization\n"); if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; + return -ENODEV; } JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); @@ -641,7 +686,7 @@ if ((struct usb_device *)NULL == peasycap->pusb_device) { /*---------------------------------------------------------------------------*/ if ((struct usb_device *)NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -EFAULT; + return -ENODEV; } rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \ peasycap->audio_altsetting_on); @@ -678,6 +723,10 @@ if (NULL == peasycap) { SAY("ERROR: peasycap is NULL.\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} if (0 != kill_audio_urbs(peasycap)) { SAM("ERROR: kill_audio_urbs() failed\n"); return -EFAULT; @@ -722,6 +771,10 @@ if (NULL == peasycap) { SAY("ERROR in easysnd_read(): peasycap is NULL\n"); return -EFAULT; } +if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap); + return -EFAULT; +} if (NULL == peasycap->pusb_device) { SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n"); return -EFAULT; @@ -753,6 +806,12 @@ if (0 <= kd && DONGLE_MANY > kd) { mutex_unlock(&easycap_dongle[kd].mutex_audio); return -ERESTARTSYS; } + if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) { + SAY("ERROR: bad peasycap: 0x%08lX\n", \ + (unsigned long int) peasycap); + mutex_unlock(&easycap_dongle[kd].mutex_audio); + return -ERESTARTSYS; + } if (NULL == peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); mutex_unlock(&easycap_dongle[kd].mutex_audio); -- cgit v1.2.3 From a2ac9d69d69d8df88d4096903f5f76fe2de2345b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 7 Nov 2010 12:22:18 -0600 Subject: staging: r8712u: Remove unneeded local variable in _malloc in osdep_service.h header The variable 'pbuf' is not needed. Signed-off-by: Jesper Juhl Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/osdep_service.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h index d1674cd282dc..f891a1b02180 100644 --- a/drivers/staging/rtl8712/osdep_service.h +++ b/drivers/staging/rtl8712/osdep_service.h @@ -196,10 +196,7 @@ static inline void sleep_schedulable(int ms) static inline u8 *_malloc(u32 sz) { - u8 *pbuf; - - pbuf = kmalloc(sz, GFP_ATOMIC); - return pbuf; + return kmalloc(sz, GFP_ATOMIC); } static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer) -- cgit v1.2.3 From 4c510e95aef6138242ed4bc7fe29ee184bea413f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 7 Nov 2010 12:22:18 -0600 Subject: staging: r8712u: Remove extraneous variables from osdep_service.h Jesper Juhl submitted a patch to remove one extraneous variable in this file; however, there are several others. Signed-off-by: Larry Finger Reviewed-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/osdep_service.h | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h index f891a1b02180..7d62714ff412 100644 --- a/drivers/staging/rtl8712/osdep_service.h +++ b/drivers/staging/rtl8712/osdep_service.h @@ -218,34 +218,22 @@ static inline void flush_signals_thread(void) static inline u32 _RND8(u32 sz) { - u32 val; - - val = ((sz >> 3) + ((sz & 7) ? 1 : 0)) << 3; - return val; + return ((sz >> 3) + ((sz & 7) ? 1 : 0)) << 3; } static inline u32 _RND128(u32 sz) { - u32 val; - - val = ((sz >> 7) + ((sz & 127) ? 1 : 0)) << 7; - return val; + return ((sz >> 7) + ((sz & 127) ? 1 : 0)) << 7; } static inline u32 _RND256(u32 sz) { - u32 val; - - val = ((sz >> 8) + ((sz & 255) ? 1 : 0)) << 8; - return val; + return ((sz >> 8) + ((sz & 255) ? 1 : 0)) << 8; } static inline u32 _RND512(u32 sz) { - u32 val; - - val = ((sz >> 9) + ((sz & 511) ? 1 : 0)) << 9; - return val; + return ((sz >> 9) + ((sz & 511) ? 1 : 0)) << 9; } #define STRUCT_PACKED __attribute__ ((packed)) -- cgit v1.2.3 From 4eb28f7197a2cbaf7a9be778d429a5fb9bb6172e Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 15:46:54 +0200 Subject: Staging: wlan-ng: fixed coding style issues in p80211conv.c This is a patch to the p80211conv.c file that fixes a couple of coding style issues found by the checkpatch.pl tool. Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211conv.c | 45 ++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c index 83879f9a0b7d..146f3651b6f2 100644 --- a/drivers/staging/wlan-ng/p80211conv.c +++ b/drivers/staging/wlan-ng/p80211conv.c @@ -148,7 +148,8 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv, /* tack on SNAP */ e_snap = - (struct wlan_snap *) skb_push(skb, sizeof(struct wlan_snap)); + (struct wlan_snap *) skb_push(skb, + sizeof(struct wlan_snap)); e_snap->type = htons(proto); if (ethconv == WLAN_ETHCONV_8021h && p80211_stt_findproto(proto)) { @@ -161,7 +162,8 @@ int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv, /* tack on llc */ e_llc = - (struct wlan_llc *) skb_push(skb, sizeof(struct wlan_llc)); + (struct wlan_llc *) skb_push(skb, + sizeof(struct wlan_llc)); e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */ e_llc->ssap = 0xAA; e_llc->ctl = 0x03; @@ -297,10 +299,12 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) { memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); - } else if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1)) { + } else if ((WLAN_GET_FC_TODS(fc) == 0) + && (WLAN_GET_FC_FROMDS(fc) == 1)) { memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); - } else if ((WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0)) { + } else if ((WLAN_GET_FC_TODS(fc) == 1) + && (WLAN_GET_FC_FROMDS(fc) == 0)) { memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); } else { @@ -349,7 +353,8 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, e_llc = (struct wlan_llc *) (skb->data + payload_offset); e_snap = - (struct wlan_snap *) (skb->data + payload_offset + sizeof(struct wlan_llc)); + (struct wlan_snap *) (skb->data + payload_offset + + sizeof(struct wlan_llc)); /* Test for the various encodings */ if ((payload_length >= sizeof(struct wlan_ethhdr)) && @@ -372,9 +377,11 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, /* chop off the 802.11 CRC */ skb_trim(skb, skb->len - WLAN_CRC_LEN); - } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap)) - && (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa) - && (e_llc->ctl == 0x03) + } else if ((payload_length >= sizeof(struct wlan_llc) + + sizeof(struct wlan_snap)) + &&(e_llc->dsap == 0xaa) + && (e_llc->ssap == 0xaa) + && (e_llc->ctl == 0x03) && (((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0) && (ethconv == WLAN_ETHCONV_8021h) @@ -406,21 +413,25 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv, /* chop off the 802.11 CRC */ skb_trim(skb, skb->len - WLAN_CRC_LEN); - } else if ((payload_length >= sizeof(struct wlan_llc) + sizeof(struct wlan_snap)) - && (e_llc->dsap == 0xaa) && (e_llc->ssap == 0xaa) - && (e_llc->ctl == 0x03)) { + } else if ((payload_length >= sizeof(struct wlan_llc) + + sizeof(struct wlan_snap)) + &&(e_llc->dsap == 0xaa) + && (e_llc->ssap == 0xaa) + && (e_llc->ctl == 0x03)) { pr_debug("802.1h/RFC1042 len: %d\n", payload_length); - /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */ - /* build a DIXII + RFC894 */ + /* it's an 802.1h frame || (an RFC1042 && protocol not in STT) + build a DIXII + RFC894 */ /* Test for an overlength frame */ - if ((payload_length - sizeof(struct wlan_llc) - sizeof(struct wlan_snap)) - > netdev->mtu) { + if ((payload_length - sizeof(struct wlan_llc) - + sizeof(struct wlan_snap)) + > netdev->mtu) { /* A bogus length ethfrm has been sent. */ /* Is someone trying an oflow attack? */ printk(KERN_ERR "DIXII frame too large (%ld > %d)\n", - (long int)(payload_length - sizeof(struct wlan_llc) - - sizeof(struct wlan_snap)), netdev->mtu); + (long int)(payload_length - + sizeof(struct wlan_llc) - + sizeof(struct wlan_snap)), netdev->mtu); return 1; } -- cgit v1.2.3 From 5b84cc781058bb452f869d84bb24442ec51948c4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 4 Nov 2010 20:07:59 -0700 Subject: staging: Use vzalloc Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers.c | 4 +--- drivers/staging/rtl8192e/r8192E_core.c | 4 +--- drivers/staging/udlfb/udlfb.c | 5 ++--- drivers/staging/xgifb/XGI_main_26.c | 3 +-- drivers/staging/zram/zram_drv.c | 3 +-- 5 files changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 4a29ed737e3f..ef24a530278b 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -470,10 +470,8 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, struct page **pages = NULL; async->buf_page_list = - vmalloc(sizeof(struct comedi_buf_page) * n_pages); + vzalloc(sizeof(struct comedi_buf_page) * n_pages); if (async->buf_page_list) { - memset(async->buf_page_list, 0, - sizeof(struct comedi_buf_page) * n_pages); pages = vmalloc(sizeof(struct page *) * n_pages); } if (pages) { diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c index a202194b5cbb..c870014c559e 100644 --- a/drivers/staging/rtl8192e/r8192E_core.c +++ b/drivers/staging/rtl8192e/r8192E_core.c @@ -2283,9 +2283,7 @@ static void rtl8192_init_priv_variable(struct net_device* dev) IMR_TXFOVW | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); priv->AcmControl = 0; - priv->pFirmware = (rt_firmware*)vmalloc(sizeof(rt_firmware)); - if (priv->pFirmware) - memset(priv->pFirmware, 0, sizeof(rt_firmware)); + priv->pFirmware = vzalloc(sizeof(rt_firmware)); /* rx related queue */ skb_queue_head_init(&priv->rx_queue); diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c index 5969e848d297..e2283294c71a 100644 --- a/drivers/staging/udlfb/udlfb.c +++ b/drivers/staging/udlfb/udlfb.c @@ -1163,14 +1163,13 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info) * But with imperfect damage info we may send pixels over USB * that were, in fact, unchanged - wasting limited USB bandwidth */ - new_back = vmalloc(new_len); + new_back = vzalloc(new_len); if (!new_back) - dl_info("No shadow/backing buffer allcoated\n"); + dl_info("No shadow/backing buffer allocated\n"); else { if (dev->backing_buffer) vfree(dev->backing_buffer); dev->backing_buffer = new_back; - memset(dev->backing_buffer, 0, new_len); } } diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 36ec45b84fca..ee008e5a0cbc 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -2180,8 +2180,7 @@ static int XGIfb_heap_init(void) #ifndef AGPOFF if (XGIfb_queuemode == AGP_CMD_QUEUE) { - agp_info = vmalloc(sizeof(*agp_info)); - memset((void *)agp_info, 0x00, sizeof(*agp_info)); + agp_info = vzalloc(sizeof(*agp_info)); agp_copy_info(agp_info); agp_backend_acquire(); diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 8c3c057aa847..43fd6086bddf 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -533,7 +533,7 @@ int zram_init_device(struct zram *zram) } num_pages = zram->disksize >> PAGE_SHIFT; - zram->table = vmalloc(num_pages * sizeof(*zram->table)); + zram->table = vzalloc(num_pages * sizeof(*zram->table)); if (!zram->table) { pr_err("Error allocating zram address table\n"); /* To prevent accessing table entries during cleanup */ @@ -541,7 +541,6 @@ int zram_init_device(struct zram *zram) ret = -ENOMEM; goto fail; } - memset(zram->table, 0, num_pages * sizeof(*zram->table)); set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); -- cgit v1.2.3 From 4314e5a68ab014092a55d5b2b26964952a97bc85 Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 18:22:42 +0200 Subject: Staging: wlan-ng: fixed coding style issues in p80211netdev.h This is a patch to the p80211netdev.h file that fixes up warnings found by the checkpatch.pl tool. The typedefs have been left in place as they seem necessary. Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211netdev.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h index 1ec33740f10f..85884176b661 100644 --- a/drivers/staging/wlan-ng/p80211netdev.h +++ b/drivers/staging/wlan-ng/p80211netdev.h @@ -94,11 +94,11 @@ typedef struct net_device netdevice_t; #endif /*--- NSD Capabilities Flags ------------------------------*/ -#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */ -#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */ -#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */ -#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */ -#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */ +#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */ +#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */ +#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */ +#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */ +#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */ /* Received frame statistics */ typedef struct p80211_frmrx_t { -- cgit v1.2.3 From c5de2157b801b9f38c7852b4d30fea8aff0c1bbd Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 18:23:09 +0200 Subject: Staging: wlan-ng: fix coding style issues in p80211types.h This is a patch that fixes various coding style issues in p80211types.h. The typedef declarations have been kept as they seem necessary. Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h index 41a99c59c6c5..9dec8596f451 100644 --- a/drivers/staging/wlan-ng/p80211types.h +++ b/drivers/staging/wlan-ng/p80211types.h @@ -141,14 +141,14 @@ #define P80211DID_LSB_ITEM (12) #define P80211DID_LSB_INDEX (18) #define P80211DID_LSB_ISTABLE (26) -#define P80211DID_LSB_ACCESS (27) +#define P80211DID_LSB_ACCESS (27) #define P80211DID_MASK_SECTION (0x0000003fUL) #define P80211DID_MASK_GROUP (0x0000003fUL) #define P80211DID_MASK_ITEM (0x0000003fUL) #define P80211DID_MASK_INDEX (0x000000ffUL) #define P80211DID_MASK_ISTABLE (0x00000001UL) -#define P80211DID_MASK_ACCESS (0x00000003UL) +#define P80211DID_MASK_ACCESS (0x00000003UL) #define P80211DID_MK(a, m, l) ((((u32)(a)) & (m)) << (l)) -- cgit v1.2.3 From f83dfd065817ea3c7387b23afb2fd4d23fb470ff Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 18:23:44 +0200 Subject: Staging: wlan-ng: fix coding style issues in prism2mgmt.c This is a patch to prism2mgmt.c that fixes coding style issues found by checkpatch.pl. Three instances of the 80 char line limit being exceeded have been kept as is so that string literals are not split up. Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2mgmt.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index 04514a85d101..6675c8226cef 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -213,8 +213,8 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) u16 wordbuf[17]; result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CNFROAMINGMODE, - HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); + HFA384x_RID_CNFROAMINGMODE, + HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); if (result) { printk(KERN_ERR "setconfig(ROAMINGMODE) failed. result=%d\n", @@ -258,8 +258,8 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) } /* ibss options */ result = hfa384x_drvr_setconfig16(hw, - HFA384x_RID_CREATEIBSS, - HFA384x_CREATEIBSS_JOINCREATEIBSS); + HFA384x_RID_CREATEIBSS, + HFA384x_CREATEIBSS_JOINCREATEIBSS); if (result) { printk(KERN_ERR "Failed to set CREATEIBSS.\n"); msg->resultcode.data = @@ -416,7 +416,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) #define REQBASICRATE(N) \ if ((count >= N) && DOT11_RATE5_ISBASIC_GET(item->supprates[(N)-1])) { \ req->basicrate ## N .data = item->supprates[(N)-1]; \ - req->basicrate ## N .status = P80211ENUM_msgitem_status_data_ok; \ + req->basicrate ## N .status = \ + P80211ENUM_msgitem_status_data_ok; \ } REQBASICRATE(1); @@ -431,7 +432,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) #define REQSUPPRATE(N) \ if (count >= N) { \ req->supprate ## N .data = item->supprates[(N)-1]; \ - req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \ + req->supprate ## N .status = \ + P80211ENUM_msgitem_status_data_ok; \ } REQSUPPRATE(1); @@ -1102,7 +1104,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) result = hfa384x_drvr_disable(hw, 0); if (result) { pr_debug - ("failed to disable port 0 after sniffing, result=%d\n", + ("failed to disable port 0 after sniffing, result=%d\n", result); goto failed; } @@ -1137,7 +1139,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) result = hfa384x_drvr_enable(hw, 0); if (result) { pr_debug - ("failed to enable port to presniff setting, result=%d\n", + ("failed to enable port to presniff setting, result=%d\n", result); goto failed; } @@ -1161,7 +1163,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) &(hw->presniff_port_type)); if (result) { pr_debug - ("failed to read porttype, result=%d\n", + ("failed to read porttype, result=%d\n", result); goto failed; } @@ -1171,7 +1173,7 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) &(hw->presniff_wepflags)); if (result) { pr_debug - ("failed to read wepflags, result=%d\n", + ("failed to read wepflags, result=%d\n", result); goto failed; } @@ -1238,8 +1240,8 @@ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) if (result) { pr_debug - ("failed to set wepflags=0x%04x, result=%d\n", - word, result); + ("failed to set wepflags=0x%04x, result=%d\n", + word, result); goto failed; } } -- cgit v1.2.3 From 9f027eb6871335f6e16633df796263f983f08844 Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 18:24:46 +0200 Subject: Staging: asus_oled: fix coding style issue in asus_oled.c This is a patch to the asus_oled.c file that fixes up brace and enum warning found by the checkpatch.pl tool Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/asus_oled/asus_oled.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 8c95d8c2a4f4..1dda9fbf11b6 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -70,7 +70,7 @@ module_param(start_off, uint, 0644); MODULE_PARM_DESC(start_off, "Set to 1 to switch off OLED display after it is attached"); -enum oled_pack_mode{ +enum oled_pack_mode { PACK_MODE_G1, PACK_MODE_G50, PACK_MODE_LAST -- cgit v1.2.3 From 869c4b4a715af94a14ec074c0a5528a562e3322b Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 15:59:50 +0200 Subject: Staging: wlan-ng: fixed coding style issues in p80211conv.h This is a patch to the p80211conv.h file that fixes two 80 character line limit styling issues Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211conv.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/p80211conv.h b/drivers/staging/wlan-ng/p80211conv.h index eca0391c676f..ea493aa74f00 100644 --- a/drivers/staging/wlan-ng/p80211conv.h +++ b/drivers/staging/wlan-ng/p80211conv.h @@ -66,12 +66,14 @@ #define P80211_FRMMETA_MAGIC 0x802110 #define P80211SKB_FRMMETA(s) \ - (((((struct p80211_frmmeta *)((s)->cb))->magic) == P80211_FRMMETA_MAGIC) ? \ + (((((struct p80211_frmmeta *)((s)->cb))->magic) == \ + P80211_FRMMETA_MAGIC) ? \ ((struct p80211_frmmeta *)((s)->cb)) : \ (NULL)) #define P80211SKB_RXMETA(s) \ - (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((struct p80211_rxmeta *)(NULL))) + (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : \ + ((struct p80211_rxmeta *)(NULL))) struct p80211_rxmeta { struct wlandevice *wlandev; -- cgit v1.2.3 From 6f710907ff452ab67bd1161bc3f7a95f9a7e809d Mon Sep 17 00:00:00 2001 From: Johan Meiring Date: Sat, 6 Nov 2010 18:21:59 +0200 Subject: Staging: wlan-ng: fixed coding style issues in p80211netdev.c This is a patch to the p80211netdev.c file that fixes warnings that were found by the checkpatch.pl tool Signed-off-by: Johan Meiring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/p80211netdev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index aa1792c8429e..48f223e05ddd 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -301,7 +301,8 @@ static void p80211netdev_rx_bh(unsigned long arg) if (memcmp (hdr->a1, wlandev->netdev->dev_addr, ETH_ALEN) != 0) { - /* but reject anything else that isn't multicast */ + /* but reject anything else that + isn't multicast */ if (!(hdr->a1[0] & 0x01)) { dev_kfree_skb(skb); continue; @@ -770,7 +771,8 @@ int wlan_setup(wlandevice_t *wlandev, struct device *physdev) } /* Allocate and initialize the struct device */ - netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", ether_setup); + netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", + ether_setup); if (netdev == NULL) { printk(KERN_ERR "Failed to alloc netdev.\n"); wlan_free_wiphy(wiphy); -- cgit v1.2.3 From 3c9d46526db88218a311a72971efae1b4366d4c6 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 7 Nov 2010 07:37:03 +0100 Subject: Staging: Cypress WestBridge OMAP3430 Kernel Hal: Remove unneeded local variables from alloc functions In drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c the local variables 'ret_p' are not needed and should just go away. I have no way to test this code, but I believe the change is obviously correct. Please consider it. Signed-off-by: Jesper Juhl Acked-by: David Cross Signed-off-by: Greg Kroah-Hartman --- .../astoria/arch/arm/mach-omap2/cyashalomap_kernel.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c index a6780296888f..ad0c61db9937 100644 --- a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c +++ b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c @@ -2127,10 +2127,7 @@ void cy_as_hal_pll_lock_loss_handler(cy_as_hal_device_tag tag) */ void *cy_as_hal_alloc(uint32_t cnt) { - void *ret_p; - - ret_p = kmalloc(cnt, GFP_ATOMIC); - return ret_p; + return kmalloc(cnt, GFP_ATOMIC); } /* @@ -2150,10 +2147,7 @@ void cy_as_hal_free(void *mem_p) */ void *cy_as_hal_c_b_alloc(uint32_t cnt) { - void *ret_p; - - ret_p = kmalloc(cnt, GFP_ATOMIC); - return ret_p; + return kmalloc(cnt, GFP_ATOMIC); } /* -- cgit v1.2.3 From a32d4acab4a862c5cd297b73d625d813af8d4e0b Mon Sep 17 00:00:00 2001 From: Tracey Dent Date: Sat, 6 Nov 2010 14:48:48 -0400 Subject: Staging: speakup: spk_types: trival coding style issue Checkpatch.pl gives WARNING: missing space after struct definition. This patch fixes that warning that was on line 55. Signed-off-by: Tracey Dent Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/spk_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h index 840bddb64101..d36c90e30d54 100644 --- a/drivers/staging/speakup/spk_types.h +++ b/drivers/staging/speakup/spk_types.h @@ -52,7 +52,7 @@ typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch, #define COLOR_BUFFER_SIZE 160 -struct spk_highlight_color_track{ +struct spk_highlight_color_track { /* Count of each background color */ unsigned int bgcount[8]; /* Buffer for characters drawn with each background color */ -- cgit v1.2.3 From c50f7fb28400bc4829c26bb4a2d6c06a45e90b1a Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:38 -0800 Subject: staging: hv: Convert camel cased struct fields in channel_mgmt.h to lower cases staging: hv: Convert camel cased struct fields in channel_mgmt.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 302 +++++++++++++++++++------------------- drivers/staging/hv/channel_mgmt.c | 186 +++++++++++------------ drivers/staging/hv/channel_mgmt.h | 244 +++++++++++++++--------------- drivers/staging/hv/connection.c | 38 ++--- drivers/staging/hv/hv_utils.c | 12 +- drivers/staging/hv/vmbus_drv.c | 42 +++--- 6 files changed, 412 insertions(+), 412 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index 26ebc77f22b7..9fa0fe1525dc 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -74,21 +74,21 @@ static void vmbus_setevent(struct vmbus_channel *channel) { struct hv_monitor_page *monitorpage; - if (channel->OfferMsg.MonitorAllocated) { + if (channel->offermsg.monitor_allocated) { /* Each u32 represents 32 channels */ - set_bit(channel->OfferMsg.ChildRelId & 31, + set_bit(channel->offermsg.child_relid & 31, (unsigned long *) gVmbusConnection.SendInterruptPage + - (channel->OfferMsg.ChildRelId >> 5)); + (channel->offermsg.child_relid >> 5)); monitorpage = gVmbusConnection.MonitorPages; monitorpage++; /* Get the child to parent monitor page */ - set_bit(channel->MonitorBit, + set_bit(channel->monitor_bit, (unsigned long *)&monitorpage->TriggerGroup - [channel->MonitorGroup].Pending); + [channel->monitor_grp].Pending); } else { - VmbusSetEvent(channel->OfferMsg.ChildRelId); + VmbusSetEvent(channel->offermsg.child_relid); } } @@ -97,19 +97,19 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel) { struct hv_monitor_page *monitorPage; - if (Channel->OfferMsg.MonitorAllocated) { + if (Channel->offermsg.monitor_allocated) { /* Each u32 represents 32 channels */ - clear_bit(Channel->OfferMsg.ChildRelId & 31, + clear_bit(Channel->offermsg.child_relid & 31, (unsigned long *)gVmbusConnection.SendInterruptPage + - (Channel->OfferMsg.ChildRelId >> 5)); + (Channel->offermsg.child_relid >> 5)); monitorPage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages; monitorPage++; /* Get the child to parent monitor page */ - clear_bit(Channel->MonitorBit, + clear_bit(Channel->monitor_bit, (unsigned long *)&monitorPage->TriggerGroup - [Channel->MonitorGroup].Pending); + [Channel->monitor_grp].Pending); } } @@ -121,42 +121,42 @@ void vmbus_get_debug_info(struct vmbus_channel *channel, struct vmbus_channel_debug_info *debuginfo) { struct hv_monitor_page *monitorpage; - u8 monitor_group = (u8)channel->OfferMsg.MonitorId / 32; - u8 monitor_offset = (u8)channel->OfferMsg.MonitorId % 32; + u8 monitor_group = (u8)channel->offermsg.monitorid / 32; + u8 monitor_offset = (u8)channel->offermsg.monitorid % 32; /* u32 monitorBit = 1 << monitorOffset; */ - debuginfo->RelId = channel->OfferMsg.ChildRelId; - debuginfo->State = channel->State; - memcpy(&debuginfo->InterfaceType, - &channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid)); - memcpy(&debuginfo->InterfaceInstance, - &channel->OfferMsg.Offer.InterfaceInstance, + debuginfo->relid = channel->offermsg.child_relid; + debuginfo->state = channel->state; + memcpy(&debuginfo->interfacetype, + &channel->offermsg.offer.InterfaceType, sizeof(struct hv_guid)); + memcpy(&debuginfo->interface_instance, + &channel->offermsg.offer.InterfaceInstance, sizeof(struct hv_guid)); monitorpage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages; - debuginfo->MonitorId = channel->OfferMsg.MonitorId; + debuginfo->monitorid = channel->offermsg.monitorid; - debuginfo->ServerMonitorPending = + debuginfo->servermonitor_pending = monitorpage->TriggerGroup[monitor_group].Pending; - debuginfo->ServerMonitorLatency = + debuginfo->servermonitor_latency = monitorpage->Latency[monitor_group][monitor_offset]; - debuginfo->ServerMonitorConnectionId = + debuginfo->servermonitor_connectionid = monitorpage->Parameter[monitor_group] [monitor_offset].ConnectionId.u.Id; monitorpage++; - debuginfo->ClientMonitorPending = + debuginfo->clientmonitor_pending = monitorpage->TriggerGroup[monitor_group].Pending; - debuginfo->ClientMonitorLatency = + debuginfo->clientmonitor_latency = monitorpage->Latency[monitor_group][monitor_offset]; - debuginfo->ClientMonitorConnectionId = + debuginfo->clientmonitor_connectionid = monitorpage->Parameter[monitor_group] [monitor_offset].ConnectionId.u.Id; - RingBufferGetDebugInfo(&channel->Inbound, &debuginfo->Inbound); - RingBufferGetDebugInfo(&channel->Outbound, &debuginfo->Outbound); + RingBufferGetDebugInfo(&channel->inbound, &debuginfo->inbound); + RingBufferGetDebugInfo(&channel->outbound, &debuginfo->outbound); } /* @@ -176,8 +176,8 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */ /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */ - newchannel->OnChannelCallback = onchannelcallback; - newchannel->ChannelCallbackContext = context; + newchannel->onchannel_callback = onchannelcallback; + newchannel->channel_callback_context = context; /* Allocate the ring buffer */ out = osd_PageAlloc((send_ringbuffer_size + recv_ringbuffer_size) @@ -189,17 +189,17 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, in = (void *)((unsigned long)out + send_ringbuffer_size); - newchannel->RingBufferPages = out; - newchannel->RingBufferPageCount = (send_ringbuffer_size + + newchannel->ringbuffer_pages = out; + newchannel->ringbuffer_pagecount = (send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT; - ret = RingBufferInit(&newchannel->Outbound, out, send_ringbuffer_size); + ret = RingBufferInit(&newchannel->outbound, out, send_ringbuffer_size); if (ret != 0) { err = ret; goto errorout; } - ret = RingBufferInit(&newchannel->Inbound, in, recv_ringbuffer_size); + ret = RingBufferInit(&newchannel->inbound, in, recv_ringbuffer_size); if (ret != 0) { err = ret; goto errorout; @@ -210,13 +210,13 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", newchannel); - newchannel->RingBufferGpadlHandle = 0; + newchannel->ringbuffer_gpadlhandle = 0; ret = vmbus_establish_gpadl(newchannel, - newchannel->Outbound.RingBuffer, + newchannel->outbound.RingBuffer, send_ringbuffer_size + recv_ringbuffer_size, - &newchannel->RingBufferGpadlHandle); + &newchannel->ringbuffer_gpadlhandle); if (ret != 0) { err = ret; @@ -225,12 +225,12 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, DPRINT_DBG(VMBUS, "channel %p ", - newchannel, newchannel->OfferMsg.ChildRelId, - newchannel->RingBufferGpadlHandle, - newchannel->Outbound.RingBuffer, - newchannel->Outbound.RingSize, - newchannel->Inbound.RingBuffer, - newchannel->Inbound.RingSize, + newchannel, newchannel->offermsg.child_relid, + newchannel->ringbuffer_gpadlhandle, + newchannel->outbound.RingBuffer, + newchannel->outbound.RingSize, + newchannel->inbound.RingBuffer, + newchannel->inbound.RingSize, send_ringbuffer_size); /* Create and init the channel open message */ @@ -242,20 +242,20 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, goto errorout; } - openInfo->WaitEvent = osd_WaitEventCreate(); - if (!openInfo->WaitEvent) { + openInfo->waitevent = osd_WaitEventCreate(); + if (!openInfo->waitevent) { err = -ENOMEM; goto errorout; } - openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg; - openMsg->Header.MessageType = ChannelMessageOpenChannel; - openMsg->OpenId = newchannel->OfferMsg.ChildRelId; /* FIXME */ - openMsg->ChildRelId = newchannel->OfferMsg.ChildRelId; - openMsg->RingBufferGpadlHandle = newchannel->RingBufferGpadlHandle; - openMsg->DownstreamRingBufferPageOffset = send_ringbuffer_size >> + openMsg = (struct vmbus_channel_open_channel *)openInfo->msg; + openMsg->header.msgtype = CHANNELMSG_OPENCHANNEL; + openMsg->openid = newchannel->offermsg.child_relid; /* FIXME */ + openMsg->child_relid = newchannel->offermsg.child_relid; + openMsg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; + openMsg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >> PAGE_SHIFT; - openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */ + openMsg->server_contextarea_gpadlhandle = 0; /* TODO */ if (userdatalen > MAX_USER_DEFINED_BYTES) { err = -EINVAL; @@ -263,10 +263,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, } if (userdatalen) - memcpy(openMsg->UserData, userdata, userdatalen); + memcpy(openMsg->userdata, userdata, userdatalen); spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&openInfo->MsgListEntry, + list_add_tail(&openInfo->msglistentry, &gVmbusConnection.ChannelMsgList); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); @@ -280,26 +280,26 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, } /* FIXME: Need to time-out here */ - osd_WaitEventWait(openInfo->WaitEvent); + osd_WaitEventWait(openInfo->waitevent); - if (openInfo->Response.OpenResult.Status == 0) + if (openInfo->response.open_result.status == 0) DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel); else DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", - newchannel, openInfo->Response.OpenResult.Status); + newchannel, openInfo->response.open_result.status); Cleanup: spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_del(&openInfo->MsgListEntry); + list_del(&openInfo->msglistentry); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - kfree(openInfo->WaitEvent); + kfree(openInfo->waitevent); kfree(openInfo); return 0; errorout: - RingBufferCleanup(&newchannel->Outbound); - RingBufferCleanup(&newchannel->Inbound); + RingBufferCleanup(&newchannel->outbound); + RingBufferCleanup(&newchannel->inbound); osd_PageFree(out, (send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT); kfree(openInfo); @@ -322,7 +322,7 @@ static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len) for (i = 0; i < pfncount; i++) DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", - i, gpadl->Pfn[i]); + i, gpadl->pfn[i]); } /* @@ -336,18 +336,18 @@ static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl) DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d", - gpadl->ChildRelId, gpadl->RangeCount, gpadl->RangeBufLen); - for (i = 0; i < gpadl->RangeCount; i++) { - pagecount = gpadl->Range[i].ByteCount >> PAGE_SHIFT; + gpadl->child_relid, gpadl->rangecount, gpadl->range_buflen); + for (i = 0; i < gpadl->rangecount; i++) { + pagecount = gpadl->range[i].ByteCount >> PAGE_SHIFT; pagecount = (pagecount > 26) ? 26 : pagecount; DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d " - "page count %d", i, gpadl->Range[i].ByteCount, - gpadl->Range[i].ByteOffset, pagecount); + "page count %d", i, gpadl->range[i].ByteCount, + gpadl->range[i].ByteOffset, pagecount); for (j = 0; j < pagecount; j++) DPRINT_DBG(VMBUS, "%d) pfn %llu", j, - gpadl->Range[i].PfnArray[j]); + gpadl->range[i].PfnArray[j]); } } @@ -391,18 +391,18 @@ static int create_gpadl_header(void *kbuffer, u32 size, if (!msgheader) goto nomem; - INIT_LIST_HEAD(&msgheader->SubMsgList); - msgheader->MessageSize = msgsize; + INIT_LIST_HEAD(&msgheader->submsglist); + msgheader->msgsize = msgsize; gpadl_header = (struct vmbus_channel_gpadl_header *) - msgheader->Msg; - gpadl_header->RangeCount = 1; - gpadl_header->RangeBufLen = sizeof(struct gpa_range) + + msgheader->msg; + gpadl_header->rangecount = 1; + gpadl_header->range_buflen = sizeof(struct gpa_range) + pagecount * sizeof(u64); - gpadl_header->Range[0].ByteOffset = 0; - gpadl_header->Range[0].ByteCount = size; + gpadl_header->range[0].ByteOffset = 0; + gpadl_header->range[0].ByteCount = size; for (i = 0; i < pfncount; i++) - gpadl_header->Range[0].PfnArray[i] = pfn+i; + gpadl_header->range[0].PfnArray[i] = pfn+i; *msginfo = msgheader; *messagecount = 1; @@ -428,10 +428,10 @@ static int create_gpadl_header(void *kbuffer, u32 size, /* FIXME: we probably need to more if this fails */ if (!msgbody) goto nomem; - msgbody->MessageSize = msgsize; + msgbody->msgsize = msgsize; (*messagecount)++; gpadl_body = - (struct vmbus_channel_gpadl_body *)msgbody->Msg; + (struct vmbus_channel_gpadl_body *)msgbody->msg; /* * FIXME: @@ -440,11 +440,11 @@ static int create_gpadl_header(void *kbuffer, u32 size, */ /* gpadl_body->Gpadl = kbuffer; */ for (i = 0; i < pfncurr; i++) - gpadl_body->Pfn[i] = pfn + pfnsum + i; + gpadl_body->pfn[i] = pfn + pfnsum + i; /* add to msg header */ - list_add_tail(&msgbody->MsgListEntry, - &msgheader->SubMsgList); + list_add_tail(&msgbody->msglistentry, + &msgheader->submsglist); pfnsum += pfncurr; pfnleft -= pfncurr; } @@ -456,17 +456,17 @@ static int create_gpadl_header(void *kbuffer, u32 size, msgheader = kzalloc(msgsize, GFP_KERNEL); if (msgheader == NULL) goto nomem; - msgheader->MessageSize = msgsize; + msgheader->msgsize = msgsize; gpadl_header = (struct vmbus_channel_gpadl_header *) - msgheader->Msg; - gpadl_header->RangeCount = 1; - gpadl_header->RangeBufLen = sizeof(struct gpa_range) + + msgheader->msg; + gpadl_header->rangecount = 1; + gpadl_header->range_buflen = sizeof(struct gpa_range) + pagecount * sizeof(u64); - gpadl_header->Range[0].ByteOffset = 0; - gpadl_header->Range[0].ByteCount = size; + gpadl_header->range[0].ByteOffset = 0; + gpadl_header->range[0].ByteCount = size; for (i = 0; i < pagecount; i++) - gpadl_header->Range[0].PfnArray[i] = pfn+i; + gpadl_header->range[0].PfnArray[i] = pfn+i; *msginfo = msgheader; *messagecount = 1; @@ -508,21 +508,21 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, if (ret) return ret; - msginfo->WaitEvent = osd_WaitEventCreate(); - if (!msginfo->WaitEvent) { + msginfo->waitevent = osd_WaitEventCreate(); + if (!msginfo->waitevent) { ret = -ENOMEM; goto Cleanup; } - gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->Msg; - gpadlmsg->Header.MessageType = ChannelMessageGpadlHeader; - gpadlmsg->ChildRelId = channel->OfferMsg.ChildRelId; - gpadlmsg->Gpadl = next_gpadl_handle; + gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg; + gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER; + gpadlmsg->child_relid = channel->offermsg.child_relid; + gpadlmsg->gpadl = next_gpadl_handle; dump_gpadl_header(gpadlmsg); spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&msginfo->MsgListEntry, + list_add_tail(&msginfo->msglistentry, &gVmbusConnection.ChannelMsgList); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); @@ -530,9 +530,9 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, kbuffer, size, msgcount); DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd", - msginfo->MessageSize - sizeof(*msginfo)); + msginfo->msgsize - sizeof(*msginfo)); - ret = VmbusPostMessage(gpadlmsg, msginfo->MessageSize - + ret = VmbusPostMessage(gpadlmsg, msginfo->msgsize - sizeof(*msginfo)); if (ret != 0) { DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret); @@ -540,48 +540,48 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, } if (msgcount > 1) { - list_for_each(curr, &msginfo->SubMsgList) { + list_for_each(curr, &msginfo->submsglist) { /* FIXME: should this use list_entry() instead ? */ submsginfo = (struct vmbus_channel_msginfo *)curr; gpadl_body = - (struct vmbus_channel_gpadl_body *)submsginfo->Msg; + (struct vmbus_channel_gpadl_body *)submsginfo->msg; - gpadl_body->Header.MessageType = - ChannelMessageGpadlBody; - gpadl_body->Gpadl = next_gpadl_handle; + gpadl_body->header.msgtype = + CHANNELMSG_GPADL_BODY; + gpadl_body->gpadl = next_gpadl_handle; DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd", - submsginfo->MessageSize - + submsginfo->msgsize - sizeof(*submsginfo)); - dump_gpadl_body(gpadl_body, submsginfo->MessageSize - + dump_gpadl_body(gpadl_body, submsginfo->msgsize - sizeof(*submsginfo)); ret = VmbusPostMessage(gpadl_body, - submsginfo->MessageSize - + submsginfo->msgsize - sizeof(*submsginfo)); if (ret != 0) goto Cleanup; } } - osd_WaitEventWait(msginfo->WaitEvent); + osd_WaitEventWait(msginfo->waitevent); /* At this point, we received the gpadl created msg */ DPRINT_DBG(VMBUS, "Received GPADL created " "(relid %d, status %d handle %x)", - channel->OfferMsg.ChildRelId, - msginfo->Response.GpadlCreated.CreationStatus, - gpadlmsg->Gpadl); + channel->offermsg.child_relid, + msginfo->response.gpadl_created.creation_status, + gpadlmsg->gpadl); - *gpadl_handle = gpadlmsg->Gpadl; + *gpadl_handle = gpadlmsg->gpadl; Cleanup: spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_del(&msginfo->MsgListEntry); + list_del(&msginfo->msglistentry); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - kfree(msginfo->WaitEvent); + kfree(msginfo->waitevent); kfree(msginfo); return ret; } @@ -604,20 +604,20 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) if (!info) return -ENOMEM; - info->WaitEvent = osd_WaitEventCreate(); - if (!info->WaitEvent) { + info->waitevent = osd_WaitEventCreate(); + if (!info->waitevent) { kfree(info); return -ENOMEM; } - msg = (struct vmbus_channel_gpadl_teardown *)info->Msg; + msg = (struct vmbus_channel_gpadl_teardown *)info->msg; - msg->Header.MessageType = ChannelMessageGpadlTeardown; - msg->ChildRelId = channel->OfferMsg.ChildRelId; - msg->Gpadl = gpadl_handle; + msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; + msg->child_relid = channel->offermsg.child_relid; + msg->gpadl = gpadl_handle; spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&info->MsgListEntry, + list_add_tail(&info->msglistentry, &gVmbusConnection.ChannelMsgList); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); @@ -628,14 +628,14 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) /* something... */ } - osd_WaitEventWait(info->WaitEvent); + osd_WaitEventWait(info->waitevent); /* Received a torndown response */ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_del(&info->MsgListEntry); + list_del(&info->msglistentry); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); - kfree(info->WaitEvent); + kfree(info->waitevent); kfree(info); return ret; } @@ -652,7 +652,7 @@ void vmbus_close(struct vmbus_channel *channel) int ret; /* Stop callback and cancel the timer asap */ - channel->OnChannelCallback = NULL; + channel->onchannel_callback = NULL; del_timer_sync(&channel->poll_timer); /* Send a closing message */ @@ -665,9 +665,9 @@ void vmbus_close(struct vmbus_channel *channel) /* info->waitEvent = osd_WaitEventCreate(); */ - msg = (struct vmbus_channel_close_channel *)info->Msg; - msg->Header.MessageType = ChannelMessageCloseChannel; - msg->ChildRelId = channel->OfferMsg.ChildRelId; + msg = (struct vmbus_channel_close_channel *)info->msg; + msg->header.msgtype = CHANNELMSG_CLOSECHANNEL; + msg->child_relid = channel->offermsg.child_relid; ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel)); if (ret != 0) { @@ -676,17 +676,17 @@ void vmbus_close(struct vmbus_channel *channel) } /* Tear down the gpadl for the channel's ring buffer */ - if (channel->RingBufferGpadlHandle) + if (channel->ringbuffer_gpadlhandle) vmbus_teardown_gpadl(channel, - channel->RingBufferGpadlHandle); + channel->ringbuffer_gpadlhandle); /* TODO: Send a msg to release the childRelId */ /* Cleanup the ring buffers for this channel */ - RingBufferCleanup(&channel->Outbound); - RingBufferCleanup(&channel->Inbound); + RingBufferCleanup(&channel->outbound); + RingBufferCleanup(&channel->inbound); - osd_PageFree(channel->RingBufferPages, channel->RingBufferPageCount); + osd_PageFree(channel->ringbuffer_pages, channel->ringbuffer_pagecount); kfree(info); @@ -696,9 +696,9 @@ void vmbus_close(struct vmbus_channel *channel) * caller will free the channel */ - if (channel->State == CHANNEL_OPEN_STATE) { + if (channel->state == CHANNEL_OPEN_STATE) { spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_del(&channel->ListEntry); + list_del(&channel->listentry); spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); free_channel(channel); @@ -752,10 +752,10 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer, sg_set_buf(&bufferlist[2], &aligned_data, packetlen_aligned - packetlen); - ret = RingBufferWrite(&channel->Outbound, bufferlist, 3); + ret = RingBufferWrite(&channel->outbound, bufferlist, 3); /* TODO: We should determine if this is optional */ - if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound)) + if (ret == 0 && !GetRingBufferInterruptMask(&channel->outbound)) vmbus_setevent(channel); return ret; @@ -817,10 +817,10 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, sg_set_buf(&bufferlist[2], &aligned_data, packetlen_aligned - packetlen); - ret = RingBufferWrite(&channel->Outbound, bufferlist, 3); + ret = RingBufferWrite(&channel->outbound, bufferlist, 3); /* TODO: We should determine if this is optional */ - if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound)) + if (ret == 0 && !GetRingBufferInterruptMask(&channel->outbound)) vmbus_setevent(channel); return ret; @@ -886,10 +886,10 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, sg_set_buf(&bufferlist[2], &aligned_data, packetlen_aligned - packetlen); - ret = RingBufferWrite(&channel->Outbound, bufferlist, 3); + ret = RingBufferWrite(&channel->outbound, bufferlist, 3); /* TODO: We should determine if this is optional */ - if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound)) + if (ret == 0 && !GetRingBufferInterruptMask(&channel->outbound)) vmbus_setevent(channel); return ret; @@ -923,7 +923,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, spin_lock_irqsave(&channel->inbound_lock, flags); - ret = RingBufferPeek(&channel->Inbound, &desc, + ret = RingBufferPeek(&channel->inbound, &desc, sizeof(struct vmpacket_descriptor)); if (ret != 0) { spin_unlock_irqrestore(&channel->inbound_lock, flags); @@ -940,7 +940,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, DPRINT_DBG(VMBUS, "packet received on channel %p relid %d ", - channel, channel->OfferMsg.ChildRelId, desc.Type, + channel, channel->offermsg.child_relid, desc.Type, desc.Flags, desc.TransactionId, packetlen, userlen); *buffer_actual_len = userlen; @@ -956,7 +956,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, *requestid = desc.TransactionId; /* Copy over the packet to the user buffer */ - ret = RingBufferRead(&channel->Inbound, buffer, userlen, + ret = RingBufferRead(&channel->inbound, buffer, userlen, (desc.DataOffset8 << 3)); spin_unlock_irqrestore(&channel->inbound_lock, flags); @@ -983,7 +983,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, spin_lock_irqsave(&channel->inbound_lock, flags); - ret = RingBufferPeek(&channel->Inbound, &desc, + ret = RingBufferPeek(&channel->inbound, &desc, sizeof(struct vmpacket_descriptor)); if (ret != 0) { spin_unlock_irqrestore(&channel->inbound_lock, flags); @@ -999,7 +999,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, DPRINT_DBG(VMBUS, "packet received on channel %p relid %d ", - channel, channel->OfferMsg.ChildRelId, desc.Type, + channel, channel->offermsg.child_relid, desc.Type, desc.Flags, desc.TransactionId, packetlen, userlen); *buffer_actual_len = packetlen; @@ -1015,7 +1015,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, *requestid = desc.TransactionId; /* Copy over the entire packet to the user buffer */ - ret = RingBufferRead(&channel->Inbound, buffer, packetlen, 0); + ret = RingBufferRead(&channel->inbound, buffer, packetlen, 0); spin_unlock_irqrestore(&channel->inbound_lock, flags); return 0; @@ -1030,7 +1030,7 @@ void vmbus_onchannel_event(struct vmbus_channel *channel) dump_vmbus_channel(channel); /* ASSERT(Channel->OnChannelCallback); */ - channel->OnChannelCallback(channel->ChannelCallbackContext); + channel->onchannel_callback(channel->channel_callback_context); mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100)); } @@ -1042,8 +1042,8 @@ void vmbus_ontimer(unsigned long data) { struct vmbus_channel *channel = (struct vmbus_channel *)data; - if (channel->OnChannelCallback) - channel->OnChannelCallback(channel->ChannelCallbackContext); + if (channel->onchannel_callback) + channel->onchannel_callback(channel->channel_callback_context); } /* @@ -1051,7 +1051,7 @@ void vmbus_ontimer(unsigned long data) */ static void dump_vmbus_channel(struct vmbus_channel *channel) { - DPRINT_DBG(VMBUS, "Channel (%d)", channel->OfferMsg.ChildRelId); - DumpRingInfo(&channel->Outbound, "Outbound "); - DumpRingInfo(&channel->Inbound, "Inbound "); + DPRINT_DBG(VMBUS, "Channel (%d)", channel->offermsg.child_relid); + DumpRingInfo(&channel->outbound, "Outbound "); + DumpRingInfo(&channel->inbound, "Inbound "); } diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index 45dbe305afed..dbfe0f22b6d6 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -251,8 +251,8 @@ static struct vmbus_channel *alloc_channel(void) channel->poll_timer.data = (unsigned long)channel; channel->poll_timer.function = vmbus_ontimer; - channel->ControlWQ = create_workqueue("hv_vmbus_ctl"); - if (!channel->ControlWQ) { + channel->controlwq = create_workqueue("hv_vmbus_ctl"); + if (!channel->controlwq) { kfree(channel); return NULL; } @@ -268,7 +268,7 @@ static inline void release_channel(void *context) struct vmbus_channel *channel = context; DPRINT_DBG(VMBUS, "releasing channel (%p)", channel); - destroy_workqueue(channel->ControlWQ); + destroy_workqueue(channel->controlwq); DPRINT_DBG(VMBUS, "channel released (%p)", channel); kfree(channel); @@ -325,12 +325,12 @@ static void vmbus_process_offer(void *context) /* Make sure this is a new offer */ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) { - if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, - &newchannel->OfferMsg.Offer.InterfaceType, + list_for_each_entry(channel, &gVmbusConnection.ChannelList, listentry) { + if (!memcmp(&channel->offermsg.offer.InterfaceType, + &newchannel->offermsg.offer.InterfaceType, sizeof(struct hv_guid)) && - !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, - &newchannel->OfferMsg.Offer.InterfaceInstance, + !memcmp(&channel->offermsg.offer.InterfaceInstance, + &newchannel->offermsg.offer.InterfaceInstance, sizeof(struct hv_guid))) { fnew = false; break; @@ -338,14 +338,14 @@ static void vmbus_process_offer(void *context) } if (fnew) - list_add_tail(&newchannel->ListEntry, + list_add_tail(&newchannel->listentry, &gVmbusConnection.ChannelList); spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); if (!fnew) { DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", - newchannel->OfferMsg.ChildRelId); + newchannel->offermsg.child_relid); free_channel(newchannel); return; } @@ -355,27 +355,27 @@ static void vmbus_process_offer(void *context) * We need to set the DeviceObject field before calling * VmbusChildDeviceAdd() */ - newchannel->DeviceObject = VmbusChildDeviceCreate( - &newchannel->OfferMsg.Offer.InterfaceType, - &newchannel->OfferMsg.Offer.InterfaceInstance, + newchannel->device_obj = VmbusChildDeviceCreate( + &newchannel->offermsg.offer.InterfaceType, + &newchannel->offermsg.offer.InterfaceInstance, newchannel); DPRINT_DBG(VMBUS, "child device object allocated - %p", - newchannel->DeviceObject); + newchannel->device_obj); /* * Add the new device to the bus. This will kick off device-driver * binding which eventually invokes the device driver's AddDevice() * method. */ - ret = VmbusChildDeviceAdd(newchannel->DeviceObject); + ret = VmbusChildDeviceAdd(newchannel->device_obj); if (ret != 0) { DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)", - newchannel->OfferMsg.ChildRelId); + newchannel->offermsg.child_relid); spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_del(&newchannel->ListEntry); + list_del(&newchannel->listentry); spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); free_channel(newchannel); @@ -385,11 +385,11 @@ static void vmbus_process_offer(void *context) * so that when we do close the channel normally, we * can cleanup properly */ - newchannel->State = CHANNEL_OPEN_STATE; + newchannel->state = CHANNEL_OPEN_STATE; /* Open IC channels */ for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) { - if (memcmp(&newchannel->OfferMsg.Offer.InterfaceType, + if (memcmp(&newchannel->offermsg.offer.InterfaceType, &hv_cb_utils[cnt].data, sizeof(struct hv_guid)) == 0 && vmbus_open(newchannel, 2 * PAGE_SIZE, @@ -413,7 +413,7 @@ static void vmbus_process_rescind_offer(void *context) { struct vmbus_channel *channel = context; - VmbusChildDeviceRemove(channel->DeviceObject); + VmbusChildDeviceRemove(channel->device_obj); } /* @@ -434,7 +434,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) offer = (struct vmbus_channel_offer_channel *)hdr; for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) { - if (memcmp(&offer->Offer.InterfaceType, + if (memcmp(&offer->offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) { fsupported = 1; break; @@ -443,12 +443,12 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) if (!fsupported) { DPRINT_DBG(VMBUS, "Ignoring channel offer notification for " - "child relid %d", offer->ChildRelId); + "child relid %d", offer->child_relid); return; } - guidtype = &offer->Offer.InterfaceType; - guidinstance = &offer->Offer.InterfaceInstance; + guidtype = &offer->offer.InterfaceType; + guidinstance = &offer->offer.InterfaceInstance; DPRINT_INFO(VMBUS, "Channel offer notification - " "child relid %d monitor id %d allocated %d, " @@ -456,8 +456,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) "%02x%02x%02x%02x%02x%02x%02x%02x} " "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-" "%02x%02x%02x%02x%02x%02x%02x%02x}", - offer->ChildRelId, offer->MonitorId, - offer->MonitorAllocated, + offer->child_relid, offer->monitorid, + offer->monitor_allocated, guidtype->data[3], guidtype->data[2], guidtype->data[1], guidtype->data[0], guidtype->data[5], guidtype->data[4], @@ -484,13 +484,13 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) DPRINT_DBG(VMBUS, "channel object allocated - %p", newchannel); - memcpy(&newchannel->OfferMsg, offer, + memcpy(&newchannel->offermsg, offer, sizeof(struct vmbus_channel_offer_channel)); - newchannel->MonitorGroup = (u8)offer->MonitorId / 32; - newchannel->MonitorBit = (u8)offer->MonitorId % 32; + newchannel->monitor_grp = (u8)offer->monitorid / 32; + newchannel->monitor_bit = (u8)offer->monitorid % 32; /* TODO: Make sure the offer comes from our parent partition */ - osd_schedule_callback(newchannel->ControlWQ, vmbus_process_offer, + osd_schedule_callback(newchannel->controlwq, vmbus_process_offer, newchannel); } @@ -505,14 +505,14 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) struct vmbus_channel *channel; rescind = (struct vmbus_channel_rescind_offer *)hdr; - channel = GetChannelFromRelId(rescind->ChildRelId); + channel = GetChannelFromRelId(rescind->child_relid); if (channel == NULL) { DPRINT_DBG(VMBUS, "channel not found for relId %d", - rescind->ChildRelId); + rescind->child_relid); return; } - osd_schedule_callback(channel->ControlWQ, + osd_schedule_callback(channel->controlwq, vmbus_process_rescind_offer, channel); } @@ -545,7 +545,7 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr) unsigned long flags; result = (struct vmbus_channel_open_result *)hdr; - DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status); + DPRINT_DBG(VMBUS, "vmbus open result - %d", result->status); /* * Find the open msg, copy the result and signal/unblock the wait event @@ -556,17 +556,17 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr) /* FIXME: this should probably use list_entry() instead */ msginfo = (struct vmbus_channel_msginfo *)curr; requestheader = - (struct vmbus_channel_message_header *)msginfo->Msg; + (struct vmbus_channel_message_header *)msginfo->msg; - if (requestheader->MessageType == ChannelMessageOpenChannel) { + if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) { openmsg = - (struct vmbus_channel_open_channel *)msginfo->Msg; - if (openmsg->ChildRelId == result->ChildRelId && - openmsg->OpenId == result->OpenId) { - memcpy(&msginfo->Response.OpenResult, + (struct vmbus_channel_open_channel *)msginfo->msg; + if (openmsg->child_relid == result->child_relid && + openmsg->openid == result->openid) { + memcpy(&msginfo->response.open_result, result, sizeof(struct vmbus_channel_open_result)); - osd_WaitEventSet(msginfo->WaitEvent); + osd_WaitEventSet(msginfo->waitevent); break; } } @@ -592,7 +592,7 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr) gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr; DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", - gpadlcreated->CreationStatus); + gpadlcreated->creation_status); /* * Find the establish msg, copy the result and signal/unblock the wait @@ -604,19 +604,19 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr) /* FIXME: this should probably use list_entry() instead */ msginfo = (struct vmbus_channel_msginfo *)curr; requestheader = - (struct vmbus_channel_message_header *)msginfo->Msg; + (struct vmbus_channel_message_header *)msginfo->msg; - if (requestheader->MessageType == ChannelMessageGpadlHeader) { + if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) { gpadlheader = (struct vmbus_channel_gpadl_header *)requestheader; - if ((gpadlcreated->ChildRelId == - gpadlheader->ChildRelId) && - (gpadlcreated->Gpadl == gpadlheader->Gpadl)) { - memcpy(&msginfo->Response.GpadlCreated, + if ((gpadlcreated->child_relid == + gpadlheader->child_relid) && + (gpadlcreated->gpadl == gpadlheader->gpadl)) { + memcpy(&msginfo->response.gpadl_created, gpadlcreated, sizeof(struct vmbus_channel_gpadl_created)); - osd_WaitEventSet(msginfo->WaitEvent); + osd_WaitEventSet(msginfo->waitevent); break; } } @@ -652,17 +652,17 @@ static void vmbus_ongpadl_torndown( /* FIXME: this should probably use list_entry() instead */ msginfo = (struct vmbus_channel_msginfo *)curr; requestheader = - (struct vmbus_channel_message_header *)msginfo->Msg; + (struct vmbus_channel_message_header *)msginfo->msg; - if (requestheader->MessageType == ChannelMessageGpadlTeardown) { + if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) { gpadl_teardown = (struct vmbus_channel_gpadl_teardown *)requestheader; - if (gpadl_torndown->Gpadl == gpadl_teardown->Gpadl) { - memcpy(&msginfo->Response.GpadlTorndown, + if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) { + memcpy(&msginfo->response.gpadl_torndown, gpadl_torndown, sizeof(struct vmbus_channel_gpadl_torndown)); - osd_WaitEventSet(msginfo->WaitEvent); + osd_WaitEventSet(msginfo->waitevent); break; } } @@ -694,16 +694,16 @@ static void vmbus_onversion_response( /* FIXME: this should probably use list_entry() instead */ msginfo = (struct vmbus_channel_msginfo *)curr; requestheader = - (struct vmbus_channel_message_header *)msginfo->Msg; + (struct vmbus_channel_message_header *)msginfo->msg; - if (requestheader->MessageType == - ChannelMessageInitiateContact) { + if (requestheader->msgtype == + CHANNELMSG_INITIATE_CONTACT) { initiate = (struct vmbus_channel_initiate_contact *)requestheader; - memcpy(&msginfo->Response.VersionResponse, + memcpy(&msginfo->response.version_response, version_response, sizeof(struct vmbus_channel_version_response)); - osd_WaitEventSet(msginfo->WaitEvent); + osd_WaitEventSet(msginfo->waitevent); } } spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); @@ -711,24 +711,24 @@ static void vmbus_onversion_response( /* Channel message dispatch table */ static struct vmbus_channel_message_table_entry - gChannelMessageTable[ChannelMessageCount] = { - {ChannelMessageInvalid, NULL}, - {ChannelMessageOfferChannel, vmbus_onoffer}, - {ChannelMessageRescindChannelOffer, vmbus_onoffer_rescind}, - {ChannelMessageRequestOffers, NULL}, - {ChannelMessageAllOffersDelivered, vmbus_onoffers_delivered}, - {ChannelMessageOpenChannel, NULL}, - {ChannelMessageOpenChannelResult, vmbus_onopen_result}, - {ChannelMessageCloseChannel, NULL}, - {ChannelMessageGpadlHeader, NULL}, - {ChannelMessageGpadlBody, NULL}, - {ChannelMessageGpadlCreated, vmbus_ongpadl_created}, - {ChannelMessageGpadlTeardown, NULL}, - {ChannelMessageGpadlTorndown, vmbus_ongpadl_torndown}, - {ChannelMessageRelIdReleased, NULL}, - {ChannelMessageInitiateContact, NULL}, - {ChannelMessageVersionResponse, vmbus_onversion_response}, - {ChannelMessageUnload, NULL}, + gChannelMessageTable[CHANNELMSG_COUNT] = { + {CHANNELMSG_INVALID, NULL}, + {CHANNELMSG_OFFERCHANNEL, vmbus_onoffer}, + {CHANNELMSG_RESCIND_CHANNELOFFER, vmbus_onoffer_rescind}, + {CHANNELMSG_REQUESTOFFERS, NULL}, + {CHANNELMSG_ALLOFFERS_DELIVERED, vmbus_onoffers_delivered}, + {CHANNELMSG_OPENCHANNEL, NULL}, + {CHANNELMSG_OPENCHANNEL_RESULT, vmbus_onopen_result}, + {CHANNELMSG_CLOSECHANNEL, NULL}, + {CHANNELMSG_GPADL_HEADER, NULL}, + {CHANNELMSG_GPADL_BODY, NULL}, + {CHANNELMSG_GPADL_CREATED, vmbus_ongpadl_created}, + {CHANNELMSG_GPADL_TEARDOWN, NULL}, + {CHANNELMSG_GPADL_TORNDOWN, vmbus_ongpadl_torndown}, + {CHANNELMSG_RELID_RELEASED, NULL}, + {CHANNELMSG_INITIATE_CONTACT, NULL}, + {CHANNELMSG_VERSION_RESPONSE, vmbus_onversion_response}, + {CHANNELMSG_UNLOAD, NULL}, }; /* @@ -745,23 +745,23 @@ void vmbus_onmessage(void *context) hdr = (struct vmbus_channel_message_header *)msg->u.Payload; size = msg->Header.PayloadSize; - DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size); + DPRINT_DBG(VMBUS, "message type %d size %d", hdr->msgtype, size); - if (hdr->MessageType >= ChannelMessageCount) { + if (hdr->msgtype >= CHANNELMSG_COUNT) { DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", - hdr->MessageType, size); + hdr->msgtype, size); print_hex_dump_bytes("", DUMP_PREFIX_NONE, (unsigned char *)msg->u.Payload, size); kfree(msg); return; } - if (gChannelMessageTable[hdr->MessageType].messageHandler) - gChannelMessageTable[hdr->MessageType].messageHandler(hdr); + if (gChannelMessageTable[hdr->msgtype].messageHandler) + gChannelMessageTable[hdr->msgtype].messageHandler(hdr); else DPRINT_ERR(VMBUS, "Unhandled channel message type %d", - hdr->MessageType); + hdr->msgtype); /* Free the msg that was allocated in VmbusOnMsgDPC() */ kfree(msg); @@ -782,15 +782,15 @@ int vmbus_request_offers(void) if (!msginfo) return -ENOMEM; - msginfo->WaitEvent = osd_WaitEventCreate(); - if (!msginfo->WaitEvent) { + msginfo->waitevent = osd_WaitEventCreate(); + if (!msginfo->waitevent) { kfree(msginfo); return -ENOMEM; } - msg = (struct vmbus_channel_message_header *)msginfo->Msg; + msg = (struct vmbus_channel_message_header *)msginfo->msg; - msg->MessageType = ChannelMessageRequestOffers; + msg->msgtype = CHANNELMSG_REQUESTOFFERS; /*SpinlockAcquire(gVmbusConnection.channelMsgLock); INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, @@ -817,7 +817,7 @@ int vmbus_request_offers(void) Cleanup: if (msginfo) { - kfree(msginfo->WaitEvent); + kfree(msginfo->waitevent); kfree(msginfo); } @@ -837,17 +837,17 @@ void vmbus_release_unattached_channels(void) spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList, - ListEntry) { + listentry) { if (channel == start) break; - if (!channel->DeviceObject->Driver) { - list_del(&channel->ListEntry); + if (!channel->device_obj->Driver) { + list_del(&channel->listentry); DPRINT_INFO(VMBUS, "Releasing unattached device object %p", - channel->DeviceObject); + channel->device_obj); - VmbusChildDeviceRemove(channel->DeviceObject); + VmbusChildDeviceRemove(channel->device_obj); free_channel(channel); } else { if (!start) diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h index d16cc0811169..12f30aff152d 100644 --- a/drivers/staging/hv/channel_mgmt.h +++ b/drivers/staging/hv/channel_mgmt.h @@ -33,60 +33,60 @@ /* Version 1 messages */ enum vmbus_channel_message_type { - ChannelMessageInvalid = 0, - ChannelMessageOfferChannel = 1, - ChannelMessageRescindChannelOffer = 2, - ChannelMessageRequestOffers = 3, - ChannelMessageAllOffersDelivered = 4, - ChannelMessageOpenChannel = 5, - ChannelMessageOpenChannelResult = 6, - ChannelMessageCloseChannel = 7, - ChannelMessageGpadlHeader = 8, - ChannelMessageGpadlBody = 9, - ChannelMessageGpadlCreated = 10, - ChannelMessageGpadlTeardown = 11, - ChannelMessageGpadlTorndown = 12, - ChannelMessageRelIdReleased = 13, - ChannelMessageInitiateContact = 14, - ChannelMessageVersionResponse = 15, - ChannelMessageUnload = 16, + CHANNELMSG_INVALID = 0, + CHANNELMSG_OFFERCHANNEL = 1, + CHANNELMSG_RESCIND_CHANNELOFFER = 2, + CHANNELMSG_REQUESTOFFERS = 3, + CHANNELMSG_ALLOFFERS_DELIVERED = 4, + CHANNELMSG_OPENCHANNEL = 5, + CHANNELMSG_OPENCHANNEL_RESULT = 6, + CHANNELMSG_CLOSECHANNEL = 7, + CHANNELMSG_GPADL_HEADER = 8, + CHANNELMSG_GPADL_BODY = 9, + CHANNELMSG_GPADL_CREATED = 10, + CHANNELMSG_GPADL_TEARDOWN = 11, + CHANNELMSG_GPADL_TORNDOWN = 12, + CHANNELMSG_RELID_RELEASED = 13, + CHANNELMSG_INITIATE_CONTACT = 14, + CHANNELMSG_VERSION_RESPONSE = 15, + CHANNELMSG_UNLOAD = 16, #ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD - ChannelMessageViewRangeAdd = 17, - ChannelMessageViewRangeRemove = 18, + CHANNELMSG_VIEWRANGE_ADD = 17, + CHANNELMSG_VIEWRANGE_REMOVE = 18, #endif - ChannelMessageCount + CHANNELMSG_COUNT }; struct vmbus_channel_message_header { - enum vmbus_channel_message_type MessageType; - u32 Padding; + enum vmbus_channel_message_type msgtype; + u32 padding; } __attribute__((packed)); /* Query VMBus Version parameters */ struct vmbus_channel_query_vmbus_version { - struct vmbus_channel_message_header Header; - u32 Version; + struct vmbus_channel_message_header header; + u32 version; } __attribute__((packed)); /* VMBus Version Supported parameters */ struct vmbus_channel_version_supported { - struct vmbus_channel_message_header Header; - bool VersionSupported; + struct vmbus_channel_message_header header; + bool version_supported; } __attribute__((packed)); /* Offer Channel parameters */ struct vmbus_channel_offer_channel { - struct vmbus_channel_message_header Header; - struct vmbus_channel_offer Offer; - u32 ChildRelId; - u8 MonitorId; - bool MonitorAllocated; + struct vmbus_channel_message_header header; + struct vmbus_channel_offer offer; + u32 child_relid; + u8 monitorid; + bool monitor_allocated; } __attribute__((packed)); /* Rescind Offer parameters */ struct vmbus_channel_rescind_offer { - struct vmbus_channel_message_header Header; - u32 ChildRelId; + struct vmbus_channel_message_header header; + u32 child_relid; } __attribute__((packed)); /* @@ -100,43 +100,43 @@ struct vmbus_channel_rescind_offer { /* Open Channel parameters */ struct vmbus_channel_open_channel { - struct vmbus_channel_message_header Header; + struct vmbus_channel_message_header header; /* Identifies the specific VMBus channel that is being opened. */ - u32 ChildRelId; + u32 child_relid; /* ID making a particular open request at a channel offer unique. */ - u32 OpenId; + u32 openid; /* GPADL for the channel's ring buffer. */ - u32 RingBufferGpadlHandle; + u32 ringbuffer_gpadlhandle; /* GPADL for the channel's server context save area. */ - u32 ServerContextAreaGpadlHandle; + u32 server_contextarea_gpadlhandle; /* * The upstream ring buffer begins at offset zero in the memory * described by RingBufferGpadlHandle. The downstream ring buffer * follows it at this offset (in pages). */ - u32 DownstreamRingBufferPageOffset; + u32 downstream_ringbuffer_pageoffset; /* User-specific data to be passed along to the server endpoint. */ - unsigned char UserData[MAX_USER_DEFINED_BYTES]; + unsigned char userdata[MAX_USER_DEFINED_BYTES]; } __attribute__((packed)); /* Open Channel Result parameters */ struct vmbus_channel_open_result { - struct vmbus_channel_message_header Header; - u32 ChildRelId; - u32 OpenId; - u32 Status; + struct vmbus_channel_message_header header; + u32 child_relid; + u32 openid; + u32 status; } __attribute__((packed)); /* Close channel parameters; */ struct vmbus_channel_close_channel { - struct vmbus_channel_message_header Header; - u32 ChildRelId; + struct vmbus_channel_message_header header; + u32 child_relid; } __attribute__((packed)); /* Channel Message GPADL */ @@ -151,72 +151,72 @@ struct vmbus_channel_close_channel { * follow-up packet that contains more. */ struct vmbus_channel_gpadl_header { - struct vmbus_channel_message_header Header; - u32 ChildRelId; - u32 Gpadl; - u16 RangeBufLen; - u16 RangeCount; - struct gpa_range Range[0]; + struct vmbus_channel_message_header header; + u32 child_relid; + u32 gpadl; + u16 range_buflen; + u16 rangecount; + struct gpa_range range[0]; } __attribute__((packed)); /* This is the followup packet that contains more PFNs. */ struct vmbus_channel_gpadl_body { - struct vmbus_channel_message_header Header; - u32 MessageNumber; - u32 Gpadl; - u64 Pfn[0]; + struct vmbus_channel_message_header header; + u32 msgnumber; + u32 gpadl; + u64 pfn[0]; } __attribute__((packed)); struct vmbus_channel_gpadl_created { - struct vmbus_channel_message_header Header; - u32 ChildRelId; - u32 Gpadl; - u32 CreationStatus; + struct vmbus_channel_message_header header; + u32 child_relid; + u32 gpadl; + u32 creation_status; } __attribute__((packed)); struct vmbus_channel_gpadl_teardown { - struct vmbus_channel_message_header Header; - u32 ChildRelId; - u32 Gpadl; + struct vmbus_channel_message_header header; + u32 child_relid; + u32 gpadl; } __attribute__((packed)); struct vmbus_channel_gpadl_torndown { - struct vmbus_channel_message_header Header; - u32 Gpadl; + struct vmbus_channel_message_header header; + u32 gpadl; } __attribute__((packed)); #ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD struct vmbus_channel_view_range_add { - struct vmbus_channel_message_header Header; - PHYSICAL_ADDRESS ViewRangeBase; - u64 ViewRangeLength; - u32 ChildRelId; + struct vmbus_channel_message_header header; + PHYSICAL_ADDRESS viewrange_base; + u64 viewrange_length; + u32 child_relid; } __attribute__((packed)); struct vmbus_channel_view_range_remove { - struct vmbus_channel_message_header Header; - PHYSICAL_ADDRESS ViewRangeBase; - u32 ChildRelId; + struct vmbus_channel_message_header header; + PHYSICAL_ADDRESS viewrange_base; + u32 child_relid; } __attribute__((packed)); #endif struct vmbus_channel_relid_released { - struct vmbus_channel_message_header Header; - u32 ChildRelId; + struct vmbus_channel_message_header header; + u32 child_relid; } __attribute__((packed)); struct vmbus_channel_initiate_contact { - struct vmbus_channel_message_header Header; - u32 VMBusVersionRequested; - u32 Padding2; - u64 InterruptPage; - u64 MonitorPage1; - u64 MonitorPage2; + struct vmbus_channel_message_header header; + u32 vmbus_version_requested; + u32 padding2; + u64 interrupt_page; + u64 monitor_page1; + u64 monitor_page2; } __attribute__((packed)); struct vmbus_channel_version_response { - struct vmbus_channel_message_header Header; - bool VersionSupported; + struct vmbus_channel_message_header header; + bool version_supported; } __attribute__((packed)); enum vmbus_channel_state { @@ -226,54 +226,54 @@ enum vmbus_channel_state { }; struct vmbus_channel { - struct list_head ListEntry; + struct list_head listentry; - struct hv_device *DeviceObject; + struct hv_device *device_obj; struct timer_list poll_timer; /* SA-111 workaround */ - enum vmbus_channel_state State; + enum vmbus_channel_state state; - struct vmbus_channel_offer_channel OfferMsg; + struct vmbus_channel_offer_channel offermsg; /* * These are based on the OfferMsg.MonitorId. * Save it here for easy access. */ - u8 MonitorGroup; - u8 MonitorBit; + u8 monitor_grp; + u8 monitor_bit; - u32 RingBufferGpadlHandle; + u32 ringbuffer_gpadlhandle; /* Allocated memory for ring buffer */ - void *RingBufferPages; - u32 RingBufferPageCount; - struct hv_ring_buffer_info Outbound; /* send to parent */ - struct hv_ring_buffer_info Inbound; /* receive from parent */ + void *ringbuffer_pages; + u32 ringbuffer_pagecount; + struct hv_ring_buffer_info outbound; /* send to parent */ + struct hv_ring_buffer_info inbound; /* receive from parent */ spinlock_t inbound_lock; - struct workqueue_struct *ControlWQ; + struct workqueue_struct *controlwq; /* Channel callback are invoked in this workqueue context */ /* HANDLE dataWorkQueue; */ - void (*OnChannelCallback)(void *context); - void *ChannelCallbackContext; + void (*onchannel_callback)(void *context); + void *channel_callback_context; }; struct vmbus_channel_debug_info { - u32 RelId; - enum vmbus_channel_state State; - struct hv_guid InterfaceType; - struct hv_guid InterfaceInstance; - u32 MonitorId; - u32 ServerMonitorPending; - u32 ServerMonitorLatency; - u32 ServerMonitorConnectionId; - u32 ClientMonitorPending; - u32 ClientMonitorLatency; - u32 ClientMonitorConnectionId; - - struct hv_ring_buffer_debug_info Inbound; - struct hv_ring_buffer_debug_info Outbound; + u32 relid; + enum vmbus_channel_state state; + struct hv_guid interfacetype; + struct hv_guid interface_instance; + u32 monitorid; + u32 servermonitor_pending; + u32 servermonitor_latency; + u32 servermonitor_connectionid; + u32 clientmonitor_pending; + u32 clientmonitor_latency; + u32 clientmonitor_connectionid; + + struct hv_ring_buffer_debug_info inbound; + struct hv_ring_buffer_debug_info outbound; }; /* @@ -282,28 +282,28 @@ struct vmbus_channel_debug_info { */ struct vmbus_channel_msginfo { /* Bookkeeping stuff */ - struct list_head MsgListEntry; + struct list_head msglistentry; /* So far, this is only used to handle gpadl body message */ - struct list_head SubMsgList; + struct list_head submsglist; /* Synchronize the request/response if needed */ - struct osd_waitevent *WaitEvent; + struct osd_waitevent *waitevent; union { - struct vmbus_channel_version_supported VersionSupported; - struct vmbus_channel_open_result OpenResult; - struct vmbus_channel_gpadl_torndown GpadlTorndown; - struct vmbus_channel_gpadl_created GpadlCreated; - struct vmbus_channel_version_response VersionResponse; - } Response; - - u32 MessageSize; + struct vmbus_channel_version_supported version_supported; + struct vmbus_channel_open_result open_result; + struct vmbus_channel_gpadl_torndown gpadl_torndown; + struct vmbus_channel_gpadl_created gpadl_created; + struct vmbus_channel_version_response version_response; + } response; + + u32 msgsize; /* * The channel message that goes out on the "wire". * It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header */ - unsigned char Msg[0]; + unsigned char msg[0]; }; diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c index f8477072ace4..6f3f525bb84c 100644 --- a/drivers/staging/hv/connection.c +++ b/drivers/staging/hv/connection.c @@ -95,19 +95,19 @@ int VmbusConnect(void) goto Cleanup; } - msgInfo->WaitEvent = osd_WaitEventCreate(); - if (!msgInfo->WaitEvent) { + msgInfo->waitevent = osd_WaitEventCreate(); + if (!msgInfo->waitevent) { ret = -ENOMEM; goto Cleanup; } - msg = (struct vmbus_channel_initiate_contact *)msgInfo->Msg; + msg = (struct vmbus_channel_initiate_contact *)msgInfo->msg; - msg->Header.MessageType = ChannelMessageInitiateContact; - msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER; - msg->InterruptPage = virt_to_phys(gVmbusConnection.InterruptPage); - msg->MonitorPage1 = virt_to_phys(gVmbusConnection.MonitorPages); - msg->MonitorPage2 = virt_to_phys( + msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; + msg->vmbus_version_requested = VMBUS_REVISION_NUMBER; + msg->interrupt_page = virt_to_phys(gVmbusConnection.InterruptPage); + msg->monitor_page1 = virt_to_phys(gVmbusConnection.MonitorPages); + msg->monitor_page2 = virt_to_phys( (void *)((unsigned long)gVmbusConnection.MonitorPages + PAGE_SIZE)); @@ -116,30 +116,30 @@ int VmbusConnect(void) * receive the response before returning from this routine */ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); - list_add_tail(&msgInfo->MsgListEntry, + list_add_tail(&msgInfo->msglistentry, &gVmbusConnection.ChannelMsgList); spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, " "monitor1 pfn %llx,, monitor2 pfn %llx", - msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2); + msg->interrupt_page, msg->monitor_page1, msg->monitor_page2); DPRINT_DBG(VMBUS, "Sending channel initiate msg..."); ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_initiate_contact)); if (ret != 0) { - list_del(&msgInfo->MsgListEntry); + list_del(&msgInfo->msglistentry); goto Cleanup; } /* Wait for the connection response */ - osd_WaitEventWait(msgInfo->WaitEvent); + osd_WaitEventWait(msgInfo->waitevent); - list_del(&msgInfo->MsgListEntry); + list_del(&msgInfo->msglistentry); /* Check if successful */ - if (msgInfo->Response.VersionResponse.VersionSupported) { + if (msgInfo->response.version_response.version_supported) { DPRINT_INFO(VMBUS, "Vmbus connected!!"); gVmbusConnection.ConnectState = Connected; @@ -151,7 +151,7 @@ int VmbusConnect(void) goto Cleanup; } - kfree(msgInfo->WaitEvent); + kfree(msgInfo->waitevent); kfree(msgInfo); return 0; @@ -172,7 +172,7 @@ Cleanup: } if (msgInfo) { - kfree(msgInfo->WaitEvent); + kfree(msgInfo->waitevent); kfree(msgInfo); } @@ -195,7 +195,7 @@ int VmbusDisconnect(void) if (!msg) return -ENOMEM; - msg->MessageType = ChannelMessageUnload; + msg->msgtype = CHANNELMSG_UNLOAD; ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_message_header)); @@ -226,8 +226,8 @@ struct vmbus_channel *GetChannelFromRelId(u32 relId) unsigned long flags; spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); - list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) { - if (channel->OfferMsg.ChildRelId == relId) { + list_for_each_entry(channel, &gVmbusConnection.ChannelList, listentry) { + if (channel->offermsg.child_relid == relId) { foundChannel = channel; break; } diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c index 702a478d5542..6dc1c35414d2 100644 --- a/drivers/staging/hv/hv_utils.c +++ b/drivers/staging/hv/hv_utils.c @@ -271,15 +271,15 @@ static int __init init_hyperv_utils(void) if (!dmi_check_system(hv_utils_dmi_table)) return -ENODEV; - hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback = + hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback = &shutdown_onchannelcallback; hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback; - hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback = + hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback = ×ync_onchannelcallback; hv_cb_utils[HV_TIMESYNC_MSG].callback = ×ync_onchannelcallback; - hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback = + hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback = &heartbeat_onchannelcallback; hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback; @@ -290,15 +290,15 @@ static void exit_hyperv_utils(void) { printk(KERN_INFO "De-Registered HyperV Utility Driver\n"); - hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback = + hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback = &chn_cb_negotiate; hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate; - hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback = + hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback = &chn_cb_negotiate; hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate; - hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback = + hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback = &chn_cb_negotiate; hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate; } diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 0d9f3a411e72..2bbf4ecdf550 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -139,35 +139,35 @@ static void get_channel_info(struct hv_device *device, vmbus_get_debug_info(device->channel, &debug_info); - info->ChannelId = debug_info.RelId; - info->ChannelState = debug_info.State; - memcpy(&info->ChannelType, &debug_info.InterfaceType, + info->ChannelId = debug_info.relid; + info->ChannelState = debug_info.state; + memcpy(&info->ChannelType, &debug_info.interfacetype, sizeof(struct hv_guid)); - memcpy(&info->ChannelInstance, &debug_info.InterfaceInstance, + memcpy(&info->ChannelInstance, &debug_info.interface_instance, sizeof(struct hv_guid)); - info->MonitorId = debug_info.MonitorId; + info->MonitorId = debug_info.monitorid; - info->ServerMonitorPending = debug_info.ServerMonitorPending; - info->ServerMonitorLatency = debug_info.ServerMonitorLatency; - info->ServerMonitorConnectionId = debug_info.ServerMonitorConnectionId; + info->ServerMonitorPending = debug_info.servermonitor_pending; + info->ServerMonitorLatency = debug_info.servermonitor_latency; + info->ServerMonitorConnectionId = debug_info.servermonitor_connectionid; - info->ClientMonitorPending = debug_info.ClientMonitorPending; - info->ClientMonitorLatency = debug_info.ClientMonitorLatency; - info->ClientMonitorConnectionId = debug_info.ClientMonitorConnectionId; + info->ClientMonitorPending = debug_info.clientmonitor_pending; + info->ClientMonitorLatency = debug_info.clientmonitor_latency; + info->ClientMonitorConnectionId = debug_info.clientmonitor_connectionid; - info->Inbound.InterruptMask = debug_info.Inbound.CurrentInterruptMask; - info->Inbound.ReadIndex = debug_info.Inbound.CurrentReadIndex; - info->Inbound.WriteIndex = debug_info.Inbound.CurrentWriteIndex; - info->Inbound.BytesAvailToRead = debug_info.Inbound.BytesAvailToRead; - info->Inbound.BytesAvailToWrite = debug_info.Inbound.BytesAvailToWrite; + info->Inbound.InterruptMask = debug_info.inbound.CurrentInterruptMask; + info->Inbound.ReadIndex = debug_info.inbound.CurrentReadIndex; + info->Inbound.WriteIndex = debug_info.inbound.CurrentWriteIndex; + info->Inbound.BytesAvailToRead = debug_info.inbound.BytesAvailToRead; + info->Inbound.BytesAvailToWrite = debug_info.inbound.BytesAvailToWrite; - info->Outbound.InterruptMask = debug_info.Outbound.CurrentInterruptMask; - info->Outbound.ReadIndex = debug_info.Outbound.CurrentReadIndex; - info->Outbound.WriteIndex = debug_info.Outbound.CurrentWriteIndex; - info->Outbound.BytesAvailToRead = debug_info.Outbound.BytesAvailToRead; + info->Outbound.InterruptMask = debug_info.outbound.CurrentInterruptMask; + info->Outbound.ReadIndex = debug_info.outbound.CurrentReadIndex; + info->Outbound.WriteIndex = debug_info.outbound.CurrentWriteIndex; + info->Outbound.BytesAvailToRead = debug_info.outbound.BytesAvailToRead; info->Outbound.BytesAvailToWrite = - debug_info.Outbound.BytesAvailToWrite; + debug_info.outbound.BytesAvailToWrite; } /* -- cgit v1.2.3 From f6feebe073db4c97dc10f6fab54f9d4b5816886b Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:39 -0800 Subject: staging: hv: Convert camel cased struct fields in hv_api.h to lower cases staging: hv: Convert camel cased struct fields in hv_api.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 32 ++--- drivers/staging/hv/channel_mgmt.c | 6 +- drivers/staging/hv/connection.c | 4 +- drivers/staging/hv/hv.c | 120 ++++++++--------- drivers/staging/hv/hv_api.h | 274 +++++++++++++++++++------------------- drivers/staging/hv/vmbus.c | 18 +-- 6 files changed, 227 insertions(+), 227 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index 9fa0fe1525dc..7c15c4034e2d 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -43,24 +43,24 @@ static void DumpMonitorPage(struct hv_monitor_page *MonitorPage) int j = 0; DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", - MonitorPage, MonitorPage->TriggerState); + MonitorPage, MonitorPage->trigger_state); for (i = 0; i < 4; i++) DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, - MonitorPage->TriggerGroup[i].AsUINT64); + MonitorPage->trigger_group[i].as_uint64); for (i = 0; i < 4; i++) { for (j = 0; j < 32; j++) { DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, - MonitorPage->Latency[i][j]); + MonitorPage->latency[i][j]); } } for (i = 0; i < 4; i++) { for (j = 0; j < 32; j++) { DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, - MonitorPage->Parameter[i][j].ConnectionId.Asu32); + MonitorPage->parameter[i][j].connectionid.asu32); DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, - MonitorPage->Parameter[i][j].FlagNumber); + MonitorPage->parameter[i][j].flag_number); } } } @@ -84,8 +84,8 @@ static void vmbus_setevent(struct vmbus_channel *channel) monitorpage++; /* Get the child to parent monitor page */ set_bit(channel->monitor_bit, - (unsigned long *)&monitorpage->TriggerGroup - [channel->monitor_grp].Pending); + (unsigned long *)&monitorpage->trigger_group + [channel->monitor_grp].pending); } else { VmbusSetEvent(channel->offermsg.child_relid); @@ -108,7 +108,7 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel) monitorPage++; /* Get the child to parent monitor page */ clear_bit(Channel->monitor_bit, - (unsigned long *)&monitorPage->TriggerGroup + (unsigned long *)&monitorPage->trigger_group [Channel->monitor_grp].Pending); } } @@ -138,22 +138,22 @@ void vmbus_get_debug_info(struct vmbus_channel *channel, debuginfo->monitorid = channel->offermsg.monitorid; debuginfo->servermonitor_pending = - monitorpage->TriggerGroup[monitor_group].Pending; + monitorpage->trigger_group[monitor_group].pending; debuginfo->servermonitor_latency = - monitorpage->Latency[monitor_group][monitor_offset]; + monitorpage->latency[monitor_group][monitor_offset]; debuginfo->servermonitor_connectionid = - monitorpage->Parameter[monitor_group] - [monitor_offset].ConnectionId.u.Id; + monitorpage->parameter[monitor_group] + [monitor_offset].connectionid.u.id; monitorpage++; debuginfo->clientmonitor_pending = - monitorpage->TriggerGroup[monitor_group].Pending; + monitorpage->trigger_group[monitor_group].pending; debuginfo->clientmonitor_latency = - monitorpage->Latency[monitor_group][monitor_offset]; + monitorpage->latency[monitor_group][monitor_offset]; debuginfo->clientmonitor_connectionid = - monitorpage->Parameter[monitor_group] - [monitor_offset].ConnectionId.u.Id; + monitorpage->parameter[monitor_group] + [monitor_offset].connectionid.u.id; RingBufferGetDebugInfo(&channel->inbound, &debuginfo->inbound); RingBufferGetDebugInfo(&channel->outbound, &debuginfo->outbound); diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index dbfe0f22b6d6..be34e38c1a85 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -742,8 +742,8 @@ void vmbus_onmessage(void *context) struct vmbus_channel_message_header *hdr; int size; - hdr = (struct vmbus_channel_message_header *)msg->u.Payload; - size = msg->Header.PayloadSize; + hdr = (struct vmbus_channel_message_header *)msg->u.payload; + size = msg->header.payload_size; DPRINT_DBG(VMBUS, "message type %d size %d", hdr->msgtype, size); @@ -752,7 +752,7 @@ void vmbus_onmessage(void *context) "Received invalid channel message type %d size %d", hdr->msgtype, size); print_hex_dump_bytes("", DUMP_PREFIX_NONE, - (unsigned char *)msg->u.Payload, size); + (unsigned char *)msg->u.payload, size); kfree(msg); return; } diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c index 6f3f525bb84c..ba50dd8fe52d 100644 --- a/drivers/staging/hv/connection.c +++ b/drivers/staging/hv/connection.c @@ -309,8 +309,8 @@ int VmbusPostMessage(void *buffer, size_t bufferLen) { union hv_connection_id connId; - connId.Asu32 = 0; - connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID; + connId.asu32 = 0; + connId.u.id = VMBUS_MESSAGE_CONNECTION_ID; return HvPostMessage(connId, 1, buffer, bufferLen); } diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c index 86b1ddd90404..ab033277226b 100644 --- a/drivers/staging/hv/hv.c +++ b/drivers/staging/hv/hv.c @@ -50,7 +50,7 @@ static int HvQueryHypervisorPresence(void) ebx = 0; ecx = 0; edx = 0; - op = HvCpuIdFunctionVersionAndFeatures; + op = HVCPUID_VERSION_FEATURES; cpuid(op, &eax, &ebx, &ecx, &edx); return ecx & HV_PRESENT_BIT; @@ -76,7 +76,7 @@ static int HvQueryHypervisorInfo(void) ebx = 0; ecx = 0; edx = 0; - op = HvCpuIdFunctionHvVendorAndMaxFunction; + op = HVCPUID_VENDOR_MAXFUNCTION; cpuid(op, &eax, &ebx, &ecx, &edx); DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c", @@ -98,7 +98,7 @@ static int HvQueryHypervisorInfo(void) ebx = 0; ecx = 0; edx = 0; - op = HvCpuIdFunctionHvInterface; + op = HVCPUID_INTERFACE; cpuid(op, &eax, &ebx, &ecx, &edx); DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c", @@ -107,12 +107,12 @@ static int HvQueryHypervisorInfo(void) ((eax >> 16) & 0xFF), ((eax >> 24) & 0xFF)); - if (maxLeaf >= HvCpuIdFunctionMsHvVersion) { + if (maxLeaf >= HVCPUID_VERSION) { eax = 0; ebx = 0; ecx = 0; edx = 0; - op = HvCpuIdFunctionMsHvVersion; + op = HVCPUID_VERSION; cpuid(op, &eax, &ebx, &ecx, &edx); DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",\ eax, @@ -222,7 +222,7 @@ int HvInit(void) gHvContext.GuestId = HV_LINUX_GUEST_ID; /* See if the hypercall page is already set */ - rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); /* * Allocate the hypercall page memory @@ -236,16 +236,16 @@ int HvInit(void) goto Cleanup; } - hypercallMsr.Enable = 1; + hypercallMsr.enable = 1; - hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr); - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + hypercallMsr.guest_physical_address = vmalloc_to_pfn(virtAddr); + wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); /* Confirm that hypercall page did get setup. */ - hypercallMsr.AsUINT64 = 0; - rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + hypercallMsr.as_uint64 = 0; + rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); - if (!hypercallMsr.Enable) { + if (!hypercallMsr.enable) { DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); goto Cleanup; } @@ -254,7 +254,7 @@ int HvInit(void) DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx", gHvContext.HypercallPage, - (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); + (u64)hypercallMsr.guest_physical_address << PAGE_SHIFT); /* Setup the global signal event param for the signal event hypercall */ gHvContext.SignalEventBuffer = @@ -267,19 +267,19 @@ int HvInit(void) (struct hv_input_signal_event *) (ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN)); - gHvContext.SignalEventParam->ConnectionId.Asu32 = 0; - gHvContext.SignalEventParam->ConnectionId.u.Id = + gHvContext.SignalEventParam->connectionid.asu32 = 0; + gHvContext.SignalEventParam->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID; - gHvContext.SignalEventParam->FlagNumber = 0; - gHvContext.SignalEventParam->RsvdZ = 0; + gHvContext.SignalEventParam->flag_number = 0; + gHvContext.SignalEventParam->rsvdz = 0; return ret; Cleanup: if (virtAddr) { - if (hypercallMsr.Enable) { - hypercallMsr.AsUINT64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + if (hypercallMsr.enable) { + hypercallMsr.as_uint64 = 0; + wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); } vfree(virtAddr); @@ -302,8 +302,8 @@ void HvCleanup(void) gHvContext.SignalEventParam = NULL; if (gHvContext.HypercallPage) { - hypercallMsr.AsUINT64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + hypercallMsr.as_uint64 = 0; + wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); vfree(gHvContext.HypercallPage); gHvContext.HypercallPage = NULL; } @@ -337,12 +337,12 @@ u16 HvPostMessage(union hv_connection_id connectionId, alignedMsg = (struct hv_input_post_message *) (ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); - alignedMsg->ConnectionId = connectionId; - alignedMsg->MessageType = messageType; - alignedMsg->PayloadSize = payloadSize; - memcpy((void *)alignedMsg->Payload, payload, payloadSize); + alignedMsg->connectionid = connectionId; + alignedMsg->message_type = messageType; + alignedMsg->payload_size = payloadSize; + memcpy((void *)alignedMsg->payload, payload, payloadSize); - status = HvDoHypercall(HvCallPostMessage, alignedMsg, NULL) & 0xFFFF; + status = HvDoHypercall(HVCALL_POST_MESSAGE, alignedMsg, NULL) & 0xFFFF; kfree((void *)addr); @@ -359,7 +359,7 @@ u16 HvSignalEvent(void) { u16 status; - status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, + status = HvDoHypercall(HVCALL_SIGNAL_EVENT, gHvContext.SignalEventParam, NULL) & 0xFFFF; return status; } @@ -407,47 +407,47 @@ void HvSynicInit(void *irqarg) } /* Setup the Synic's message page */ - rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - simp.SimpEnabled = 1; - simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) + rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); + simp.simp_enabled = 1; + simp.base_simp_gpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) >> PAGE_SHIFT; - DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64); + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.as_uint64); - wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); + wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64); /* Setup the Synic's event page */ - rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - siefp.SiefpEnabled = 1; - siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu]) + rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); + siefp.siefp_enabled = 1; + siefp.base_siefp_gpa = virt_to_phys(gHvContext.synICEventPage[cpu]) >> PAGE_SHIFT; - DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64); + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.as_uint64); - wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); + wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); /* Setup the interception SINT. */ /* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */ - /* interceptionSint.AsUINT64); */ + /* interceptionSint.as_uint64); */ /* Setup the shared SINT. */ - rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); + rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); - sharedSint.AsUINT64 = 0; - sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */ - sharedSint.Masked = false; - sharedSint.AutoEoi = true; + sharedSint.as_uint64 = 0; + sharedSint.vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */ + sharedSint.masked = false; + sharedSint.auto_eoi = true; DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", - sharedSint.AsUINT64); + sharedSint.as_uint64); - wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); + wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); /* Enable the global synic bit */ - rdmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); - sctrl.Enable = 1; + rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); + sctrl.enable = 1; - wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); + wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); gHvContext.SynICInitialized = true; return; @@ -474,25 +474,25 @@ void HvSynicCleanup(void *arg) if (!gHvContext.SynICInitialized) return; - rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); + rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); - sharedSint.Masked = 1; + sharedSint.masked = 1; /* Need to correctly cleanup in the case of SMP!!! */ /* Disable the interrupt */ - wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); + wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); - rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - simp.SimpEnabled = 0; - simp.BaseSimpGpa = 0; + rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); + simp.simp_enabled = 0; + simp.base_simp_gpa = 0; - wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); + wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64); - rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - siefp.SiefpEnabled = 0; - siefp.BaseSiefpGpa = 0; + rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); + siefp.siefp_enabled = 0; + siefp.base_siefp_gpa = 0; - wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); + wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); osd_PageFree(gHvContext.synICMessagePage[cpu], 1); osd_PageFree(gHvContext.synICEventPage[cpu], 1); diff --git a/drivers/staging/hv/hv_api.h b/drivers/staging/hv/hv_api.h index 9eb818ee07ba..9df64724549a 100644 --- a/drivers/staging/hv/hv_api.h +++ b/drivers/staging/hv/hv_api.h @@ -510,21 +510,21 @@ /* * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent - * is set by CPUID(HvCpuIdFunctionVersionAndFeatures). + * is set by CPUID(HVCPUID_VERSION_FEATURES). */ enum hv_cpuid_function { - HvCpuIdFunctionVersionAndFeatures = 0x00000001, - HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000, - HvCpuIdFunctionHvInterface = 0x40000001, + HVCPUID_VERSION_FEATURES = 0x00000001, + HVCPUID_VENDOR_MAXFUNCTION = 0x40000000, + HVCPUID_INTERFACE = 0x40000001, /* * The remaining functions depend on the value of - * HvCpuIdFunctionInterface + * HVCPUID_INTERFACE */ - HvCpuIdFunctionMsHvVersion = 0x40000002, - HvCpuIdFunctionMsHvFeatures = 0x40000003, - HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004, - HvCpuIdFunctionMsHvImplementationLimits = 0x40000005, + HVCPUID_VERSION = 0x40000002, + HVCPUID_FEATURES = 0x40000003, + HVCPUID_ENLIGHTENMENT_INFO = 0x40000004, + HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005, }; /* Define the virtual APIC registers */ @@ -575,30 +575,30 @@ enum hv_cpuid_function { /* Define hypervisor message types. */ enum hv_message_type { - HvMessageTypeNone = 0x00000000, + HVMSG_NONE = 0x00000000, /* Memory access messages. */ - HvMessageTypeUnmappedGpa = 0x80000000, - HvMessageTypeGpaIntercept = 0x80000001, + HVMSG_UNMAPPED_GPA = 0x80000000, + HVMSG_GPA_INTERCEPT = 0x80000001, /* Timer notification messages. */ - HvMessageTimerExpired = 0x80000010, + HVMSG_TIMER_EXPIRED = 0x80000010, /* Error messages. */ - HvMessageTypeInvalidVpRegisterValue = 0x80000020, - HvMessageTypeUnrecoverableException = 0x80000021, - HvMessageTypeUnsupportedFeature = 0x80000022, + HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020, + HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021, + HVMSG_UNSUPPORTED_FEATURE = 0x80000022, /* Trace buffer complete messages. */ - HvMessageTypeEventLogBufferComplete = 0x80000040, + HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040, /* Platform-specific processor intercept messages. */ - HvMessageTypeX64IoPortIntercept = 0x80010000, - HvMessageTypeX64MsrIntercept = 0x80010001, - HvMessageTypeX64CpuidIntercept = 0x80010002, - HvMessageTypeX64ExceptionIntercept = 0x80010003, - HvMessageTypeX64ApicEoi = 0x80010004, - HvMessageTypeX64LegacyFpError = 0x80010005 + HVMSG_X64_IOPORT_INTERCEPT = 0x80010000, + HVMSG_X64_MSR_INTERCEPT = 0x80010001, + HVMSG_X64_CPUID_INTERCEPT = 0x80010002, + HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, + HVMSG_X64_APIC_EOI = 0x80010004, + HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 }; /* Define the number of synthetic interrupt sources. */ @@ -610,103 +610,103 @@ enum hv_message_type { /* Define connection identifier type. */ union hv_connection_id { - u32 Asu32; + u32 asu32; struct { - u32 Id:24; - u32 Reserved:8; + u32 id:24; + u32 reserved:8; } u; }; /* Define port identifier type. */ union hv_port_id { - u32 Asu32; + u32 asu32; struct { - u32 Id:24; - u32 Reserved:8; + u32 id:24; + u32 reserved:8; } u ; }; /* Define port type. */ enum hv_port_type { - HvPortTypeMessage = 1, - HvPortTypeEvent = 2, - HvPortTypeMonitor = 3 + HVPORT_MSG = 1, + HVPORT_EVENT = 2, + HVPORT_MONITOR = 3 }; /* Define port information structure. */ struct hv_port_info { - enum hv_port_type PortType; - u32 Padding; + enum hv_port_type port_type; + u32 padding; union { struct { - u32 TargetSint; - u32 TargetVp; - u64 RsvdZ; - } MessagePortInfo; + u32 target_sint; + u32 target_vp; + u64 rsvdz; + } message_port_info; struct { - u32 TargetSint; - u32 TargetVp; - u16 BaseFlagNumber; - u16 FlagCount; - u32 RsvdZ; - } EventPortInfo; + u32 target_sint; + u32 target_vp; + u16 base_flag_bumber; + u16 flag_count; + u32 rsvdz; + } event_port_info; struct { - u64 MonitorAddress; - u64 RsvdZ; - } MonitorPortInfo; + u64 monitor_address; + u64 rsvdz; + } monitor_port_info; }; }; struct hv_connection_info { - enum hv_port_type PortType; - u32 Padding; + enum hv_port_type port_type; + u32 padding; union { struct { - u64 RsvdZ; - } MessageConnectionInfo; + u64 rsvdz; + } message_connection_info; struct { - u64 RsvdZ; - } EventConnectionInfo; + u64 rsvdz; + } event_connection_info; struct { - u64 MonitorAddress; - } MonitorConnectionInfo; + u64 monitor_address; + } monitor_connection_info; }; }; /* Define synthetic interrupt controller message flags. */ union hv_message_flags { - u8 Asu8; + u8 asu8; struct { - u8 MessagePending:1; - u8 Reserved:7; + u8 msg_pending:1; + u8 reserved:7; }; }; /* Define synthetic interrupt controller message header. */ struct hv_message_header { - enum hv_message_type MessageType; - u8 PayloadSize; - union hv_message_flags MessageFlags; - u8 Reserved[2]; + enum hv_message_type message_type; + u8 payload_size; + union hv_message_flags message_flags; + u8 reserved[2]; union { - u64 Sender; - union hv_port_id Port; + u64 sender; + union hv_port_id port; }; }; /* Define timer message payload structure. */ struct hv_timer_message_payload { - u32 TimerIndex; - u32 Reserved; - u64 ExpirationTime; /* When the timer expired */ - u64 DeliveryTime; /* When the message was delivered */ + u32 timer_index; + u32 reserved; + u64 expiration_time; /* When the timer expired */ + u64 delivery_time; /* When the message was delivered */ }; /* Define synthetic interrupt controller message format. */ struct hv_message { - struct hv_message_header Header; + struct hv_message_header header; union { - u64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; + u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; } u ; }; @@ -715,82 +715,82 @@ struct hv_message { /* Define the synthetic interrupt message page layout. */ struct hv_message_page { - struct hv_message SintMessage[HV_SYNIC_SINT_COUNT]; + struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; }; /* Define the synthetic interrupt controller event flags format. */ union hv_synic_event_flags { - u8 Flags8[HV_EVENT_FLAGS_BYTE_COUNT]; - u32 Flags32[HV_EVENT_FLAGS_DWORD_COUNT]; + u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT]; + u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT]; }; /* Define the synthetic interrupt flags page layout. */ struct hv_synic_event_flags_page { - union hv_synic_event_flags SintEventFlags[HV_SYNIC_SINT_COUNT]; + union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT]; }; /* Define SynIC control register. */ union hv_synic_scontrol { - u64 AsUINT64; + u64 as_uint64; struct { - u64 Enable:1; - u64 Reserved:63; + u64 enable:1; + u64 reserved:63; }; }; /* Define synthetic interrupt source. */ union hv_synic_sint { - u64 AsUINT64; + u64 as_uint64; struct { - u64 Vector:8; - u64 Reserved1:8; - u64 Masked:1; - u64 AutoEoi:1; - u64 Reserved2:46; + u64 vector:8; + u64 reserved1:8; + u64 masked:1; + u64 auto_eoi:1; + u64 reserved2:46; }; }; /* Define the format of the SIMP register */ union hv_synic_simp { - u64 AsUINT64; + u64 as_uint64; struct { - u64 SimpEnabled:1; - u64 Preserved:11; - u64 BaseSimpGpa:52; + u64 simp_enabled:1; + u64 preserved:11; + u64 base_simp_gpa:52; }; }; /* Define the format of the SIEFP register */ union hv_synic_siefp { - u64 AsUINT64; + u64 as_uint64; struct { - u64 SiefpEnabled:1; - u64 Preserved:11; - u64 BaseSiefpGpa:52; + u64 siefp_enabled:1; + u64 preserved:11; + u64 base_siefp_gpa:52; }; }; /* Definitions for the monitored notification facility */ union hv_monitor_trigger_group { - u64 AsUINT64; + u64 as_uint64; struct { - u32 Pending; - u32 Armed; + u32 pending; + u32 armed; }; }; struct hv_monitor_parameter { - union hv_connection_id ConnectionId; - u16 FlagNumber; - u16 RsvdZ; + union hv_connection_id connectionid; + u16 flagnumber; + u16 rsvdz; }; union hv_monitor_trigger_state { - u32 Asu32; + u32 asu32; struct { - u32 GroupEnable:4; - u32 RsvdZ:28; + u32 group_enable:4; + u32 rsvdz:28; }; }; @@ -814,42 +814,42 @@ union hv_monitor_trigger_state { /* | 840 | Rsvd4[0] | */ /* ------------------------------------------------------ */ struct hv_monitor_page { - union hv_monitor_trigger_state TriggerState; - u32 RsvdZ1; + union hv_monitor_trigger_state trigger_state; + u32 rsvdz1; - union hv_monitor_trigger_group TriggerGroup[4]; - u64 RsvdZ2[3]; + union hv_monitor_trigger_group trigger_group[4]; + u64 rsvdz2[3]; - s32 NextCheckTime[4][32]; + s32 next_checktime[4][32]; - u16 Latency[4][32]; - u64 RsvdZ3[32]; + u16 latency[4][32]; + u64 rsvdz3[32]; - struct hv_monitor_parameter Parameter[4][32]; + struct hv_monitor_parameter parameter[4][32]; - u8 RsvdZ4[1984]; + u8 rsvdz4[1984]; }; /* Declare the various hypercall operations. */ enum hv_call_code { - HvCallPostMessage = 0x005c, - HvCallSignalEvent = 0x005d, + HVCALL_POST_MESSAGE = 0x005c, + HVCALL_SIGNAL_EVENT = 0x005d, }; /* Definition of the HvPostMessage hypercall input structure. */ struct hv_input_post_message { - union hv_connection_id ConnectionId; - u32 Reserved; - enum hv_message_type MessageType; - u32 PayloadSize; - u64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; + union hv_connection_id connectionid; + u32 reserved; + enum hv_message_type message_type; + u32 payload_size; + u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; }; /* Definition of the HvSignalEvent hypercall input structure. */ struct hv_input_signal_event { - union hv_connection_id ConnectionId; - u16 FlagNumber; - u16 RsvdZ; + union hv_connection_id connectionid; + u16 flag_number; + u16 rsvdz; }; /* @@ -859,16 +859,16 @@ struct hv_input_signal_event { /* Version info reported by guest OS's */ enum hv_guest_os_vendor { - HvGuestOsVendorMicrosoft = 0x0001 + HVGUESTOS_VENDOR_MICROSOFT = 0x0001 }; enum hv_guest_os_microsoft_ids { - HvGuestOsMicrosoftUndefined = 0x00, - HvGuestOsMicrosoftMSDOS = 0x01, - HvGuestOsMicrosoftWindows3x = 0x02, - HvGuestOsMicrosoftWindows9x = 0x03, - HvGuestOsMicrosoftWindowsNT = 0x04, - HvGuestOsMicrosoftWindowsCE = 0x05 + HVGUESTOS_MICROSOFT_UNDEFINED = 0x00, + HVGUESTOS_MICROSOFT_MSDOS = 0x01, + HVGUESTOS_MICROSOFT_WINDOWS3X = 0x02, + HVGUESTOS_MICROSOFT_WINDOWS9X = 0x03, + HVGUESTOS_MICROSOFT_WINDOWSNT = 0x04, + HVGUESTOS_MICROSOFT_WINDOWSCE = 0x05 }; /* @@ -877,14 +877,14 @@ enum hv_guest_os_microsoft_ids { #define HV_X64_MSR_GUEST_OS_ID 0x40000000 union hv_x64_msr_guest_os_id_contents { - u64 AsUINT64; + u64 as_uint64; struct { - u64 BuildNumber:16; - u64 ServiceVersion:8; /* Service Pack, etc. */ - u64 MinorVersion:8; - u64 MajorVersion:8; - u64 OsId:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */ - u64 VendorId:16; /* enum hv_guest_os_vendor */ + u64 build_number:16; + u64 service_version:8; /* Service Pack, etc. */ + u64 minor_version:8; + u64 major_version:8; + u64 os_id:8; /* enum hv_guest_os_microsoft_ids (if Vendor=MS) */ + u64 vendor_id:16; /* enum hv_guest_os_vendor */ }; }; @@ -894,11 +894,11 @@ union hv_x64_msr_guest_os_id_contents { #define HV_X64_MSR_HYPERCALL 0x40000001 union hv_x64_msr_hypercall_contents { - u64 AsUINT64; + u64 as_uint64; struct { - u64 Enable:1; - u64 Reserved:11; - u64 GuestPhysicalAddress:52; + u64 enable:1; + u64 reserved:11; + u64 guest_physical_address:52; }; }; diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index d449daf81976..7c54ca9a187b 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -153,7 +153,7 @@ static void VmbusOnMsgDPC(struct hv_driver *drv) struct hv_message *copied; while (1) { - if (msg->Header.MessageType == HvMessageTypeNone) { + if (msg->header.message_type == HVMSG_NONE) { /* no msg */ break; } else { @@ -166,18 +166,18 @@ static void VmbusOnMsgDPC(struct hv_driver *drv) (void *)copied); } - msg->Header.MessageType = HvMessageTypeNone; + msg->header.message_type = HVMSG_NONE; /* * Make sure the write to MessageType (ie set to - * HvMessageTypeNone) happens before we read the + * HVMSG_NONE) happens before we read the * MessagePending and EOMing. Otherwise, the EOMing * will not deliver any more messages since there is * no empty slot */ mb(); - if (msg->Header.MessageFlags.MessagePending) { + if (msg->header.message_flags.msg_pending) { /* * This will cause message queue rescan to * possibly deliver another msg from the @@ -212,10 +212,10 @@ static int VmbusOnISR(struct hv_driver *drv) msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; /* Check if there are actual msgs to be process */ - if (msg->Header.MessageType != HvMessageTypeNone) { + if (msg->header.message_type != HVMSG_NONE) { DPRINT_DBG(VMBUS, "received msg type %d size %d", - msg->Header.MessageType, - msg->Header.PayloadSize); + msg->header.message_type, + msg->header.payload_size); ret |= 0x1; } @@ -224,8 +224,8 @@ static int VmbusOnISR(struct hv_driver *drv) event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; /* Since we are a child, we only need to check bit 0 */ - if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0])) { - DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]); + if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { + DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]); ret |= 0x2; } -- cgit v1.2.3 From 6a0aaa185057801343e000183ef0695c2a2b75a9 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:40 -0800 Subject: staging: hv: Convert camel cased struct fields in hv.h to lower cases staging: hv: Convert camel cased struct fields in hv.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/hv.c | 95 ++++++++++++++++++++++++---------------------- drivers/staging/hv/hv.h | 20 +++++----- drivers/staging/hv/vmbus.c | 6 +-- 3 files changed, 63 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c index ab033277226b..d0e8c85afb8a 100644 --- a/drivers/staging/hv/hv.c +++ b/drivers/staging/hv/hv.c @@ -28,11 +28,11 @@ #include "vmbus_private.h" /* The one and only */ -struct hv_context gHvContext = { - .SynICInitialized = false, - .HypercallPage = NULL, - .SignalEventParam = NULL, - .SignalEventBuffer = NULL, +struct hv_context hv_context = { + .synic_initialized = false, + .hypercall_page = NULL, + .signal_event_param = NULL, + .signal_event_buffer = NULL, }; /* @@ -134,7 +134,7 @@ static u64 HvDoHypercall(u64 Control, void *Input, void *Output) u64 hvStatus = 0; u64 inputAddress = (Input) ? virt_to_phys(Input) : 0; u64 outputAddress = (Output) ? virt_to_phys(Output) : 0; - volatile void *hypercallPage = gHvContext.HypercallPage; + volatile void *hypercallPage = hv_context.hypercall_page; DPRINT_DBG(VMBUS, "Hypercall ", @@ -162,7 +162,7 @@ static u64 HvDoHypercall(u64 Control, void *Input, void *Output) u64 outputAddress = (Output) ? virt_to_phys(Output) : 0; u32 outputAddressHi = outputAddress >> 32; u32 outputAddressLo = outputAddress & 0xFFFFFFFF; - volatile void *hypercallPage = gHvContext.HypercallPage; + volatile void *hypercallPage = hv_context.hypercall_page; DPRINT_DBG(VMBUS, "Hypercall ", Control, Input, Output); @@ -192,8 +192,9 @@ int HvInit(void) union hv_x64_msr_hypercall_contents hypercallMsr; void *virtAddr = NULL; - memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS); - memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS); + memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS); + memset(hv_context.synic_message_page, 0, + sizeof(void *) * MAX_NUM_CPUS); if (!HvQueryHypervisorPresence()) { DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!"); @@ -209,17 +210,17 @@ int HvInit(void) /* * We only support running on top of Hyper-V */ - rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId); + rdmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid); - if (gHvContext.GuestId != 0) { + if (hv_context.guestid != 0) { DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", - gHvContext.GuestId); + hv_context.guestid); goto Cleanup; } /* Write our OS info */ wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); - gHvContext.GuestId = HV_LINUX_GUEST_ID; + hv_context.guestid = HV_LINUX_GUEST_ID; /* See if the hypercall page is already set */ rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); @@ -250,28 +251,29 @@ int HvInit(void) goto Cleanup; } - gHvContext.HypercallPage = virtAddr; + hv_context.hypercall_page = virtAddr; DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx", - gHvContext.HypercallPage, + hv_context.hypercall_page, (u64)hypercallMsr.guest_physical_address << PAGE_SHIFT); /* Setup the global signal event param for the signal event hypercall */ - gHvContext.SignalEventBuffer = + hv_context.signal_event_buffer = kmalloc(sizeof(struct hv_input_signal_event_buffer), GFP_KERNEL); - if (!gHvContext.SignalEventBuffer) + if (!hv_context.signal_event_buffer) goto Cleanup; - gHvContext.SignalEventParam = + hv_context.signal_event_param = (struct hv_input_signal_event *) - (ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer, + (ALIGN_UP((unsigned long) + hv_context.signal_event_buffer, HV_HYPERCALL_PARAM_ALIGN)); - gHvContext.SignalEventParam->connectionid.asu32 = 0; - gHvContext.SignalEventParam->connectionid.u.id = + hv_context.signal_event_param->connectionid.asu32 = 0; + hv_context.signal_event_param->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID; - gHvContext.SignalEventParam->flag_number = 0; - gHvContext.SignalEventParam->rsvdz = 0; + hv_context.signal_event_param->flag_number = 0; + hv_context.signal_event_param->rsvdz = 0; return ret; @@ -297,15 +299,15 @@ void HvCleanup(void) { union hv_x64_msr_hypercall_contents hypercallMsr; - kfree(gHvContext.SignalEventBuffer); - gHvContext.SignalEventBuffer = NULL; - gHvContext.SignalEventParam = NULL; + kfree(hv_context.signal_event_buffer); + hv_context.signal_event_buffer = NULL; + hv_context.signal_event_param = NULL; - if (gHvContext.HypercallPage) { + if (hv_context.hypercall_page) { hypercallMsr.as_uint64 = 0; wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); - vfree(gHvContext.HypercallPage); - gHvContext.HypercallPage = NULL; + vfree(hv_context.hypercall_page); + hv_context.hypercall_page = NULL; } } @@ -359,7 +361,8 @@ u16 HvSignalEvent(void) { u16 status; - status = HvDoHypercall(HVCALL_SIGNAL_EVENT, gHvContext.SignalEventParam, + status = HvDoHypercall(HVCALL_SIGNAL_EVENT, + hv_context.signal_event_param, NULL) & 0xFFFF; return status; } @@ -382,7 +385,7 @@ void HvSynicInit(void *irqarg) u32 irqVector = *((u32 *)(irqarg)); int cpu = smp_processor_id(); - if (!gHvContext.HypercallPage) + if (!hv_context.hypercall_page) return; /* Check the version */ @@ -390,17 +393,19 @@ void HvSynicInit(void *irqarg) DPRINT_INFO(VMBUS, "SynIC version: %llx", version); - gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); + hv_context.synic_message_page[cpu] = + (void *)get_zeroed_page(GFP_ATOMIC); - if (gHvContext.synICMessagePage[cpu] == NULL) { + if (hv_context.synic_message_page[cpu] == NULL) { DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!"); goto Cleanup; } - gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); + hv_context.synic_event_page[cpu] = + (void *)get_zeroed_page(GFP_ATOMIC); - if (gHvContext.synICEventPage[cpu] == NULL) { + if (hv_context.synic_event_page[cpu] == NULL) { DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!"); goto Cleanup; @@ -409,7 +414,7 @@ void HvSynicInit(void *irqarg) /* Setup the Synic's message page */ rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); simp.simp_enabled = 1; - simp.base_simp_gpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) + simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu]) >> PAGE_SHIFT; DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.as_uint64); @@ -419,7 +424,7 @@ void HvSynicInit(void *irqarg) /* Setup the Synic's event page */ rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); siefp.siefp_enabled = 1; - siefp.base_siefp_gpa = virt_to_phys(gHvContext.synICEventPage[cpu]) + siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu]) >> PAGE_SHIFT; DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.as_uint64); @@ -449,15 +454,15 @@ void HvSynicInit(void *irqarg) wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); - gHvContext.SynICInitialized = true; + hv_context.synic_initialized = true; return; Cleanup: - if (gHvContext.synICEventPage[cpu]) - osd_PageFree(gHvContext.synICEventPage[cpu], 1); + if (hv_context.synic_event_page[cpu]) + osd_PageFree(hv_context.synic_event_page[cpu], 1); - if (gHvContext.synICMessagePage[cpu]) - osd_PageFree(gHvContext.synICMessagePage[cpu], 1); + if (hv_context.synic_message_page[cpu]) + osd_PageFree(hv_context.synic_message_page[cpu], 1); return; } @@ -471,7 +476,7 @@ void HvSynicCleanup(void *arg) union hv_synic_siefp siefp; int cpu = smp_processor_id(); - if (!gHvContext.SynICInitialized) + if (!hv_context.synic_initialized) return; rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); @@ -494,6 +499,6 @@ void HvSynicCleanup(void *arg) wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); - osd_PageFree(gHvContext.synICMessagePage[cpu], 1); - osd_PageFree(gHvContext.synICEventPage[cpu], 1); + osd_PageFree(hv_context.synic_message_page[cpu], 1); + osd_PageFree(hv_context.synic_event_page[cpu], 1); } diff --git a/drivers/staging/hv/hv.h b/drivers/staging/hv/hv.h index 41f5ebb86e17..6e396fca1942 100644 --- a/drivers/staging/hv/hv.h +++ b/drivers/staging/hv/hv.h @@ -92,33 +92,33 @@ static const struct hv_guid VMBUS_SERVICE_ID = { struct hv_input_signal_event_buffer { - u64 Align8; - struct hv_input_signal_event Event; + u64 align8; + struct hv_input_signal_event event; }; struct hv_context { /* We only support running on top of Hyper-V * So at this point this really can only contain the Hyper-V ID */ - u64 GuestId; + u64 guestid; - void *HypercallPage; + void *hypercall_page; - bool SynICInitialized; + bool synic_initialized; /* * This is used as an input param to HvCallSignalEvent hypercall. The * input param is immutable in our usage and must be dynamic mem (vs * stack or global). */ - struct hv_input_signal_event_buffer *SignalEventBuffer; + struct hv_input_signal_event_buffer *signal_event_buffer; /* 8-bytes aligned of the buffer above */ - struct hv_input_signal_event *SignalEventParam; + struct hv_input_signal_event *signal_event_param; - void *synICMessagePage[MAX_NUM_CPUS]; - void *synICEventPage[MAX_NUM_CPUS]; + void *synic_message_page[MAX_NUM_CPUS]; + void *synic_event_page[MAX_NUM_CPUS]; }; -extern struct hv_context gHvContext; +extern struct hv_context hv_context; /* Hv Interface */ diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index 7c54ca9a187b..b1ec8762f228 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -147,7 +147,7 @@ static void VmbusOnCleanup(struct hv_driver *drv) static void VmbusOnMsgDPC(struct hv_driver *drv) { int cpu = smp_processor_id(); - void *page_addr = gHvContext.synICMessagePage[cpu]; + void *page_addr = hv_context.synic_message_page[cpu]; struct hv_message *msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; struct hv_message *copied; @@ -208,7 +208,7 @@ static int VmbusOnISR(struct hv_driver *drv) struct hv_message *msg; union hv_synic_event_flags *event; - page_addr = gHvContext.synICMessagePage[cpu]; + page_addr = hv_context.synic_message_page[cpu]; msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; /* Check if there are actual msgs to be process */ @@ -220,7 +220,7 @@ static int VmbusOnISR(struct hv_driver *drv) } /* TODO: Check if there are events to be process */ - page_addr = gHvContext.synICEventPage[cpu]; + page_addr = hv_context.synic_event_page[cpu]; event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; /* Since we are a child, we only need to check bit 0 */ -- cgit v1.2.3 From b8dfb264f4f9e55f9cf8384cb782dfe5159c413c Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:41 -0800 Subject: staging: hv: Convert camel cased local variables in hv.c to lower cases staging: hv: Convert camel cased local variables in hv.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/hv.c | 172 ++++++++++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c index d0e8c85afb8a..2fd234d711ea 100644 --- a/drivers/staging/hv/hv.c +++ b/drivers/staging/hv/hv.c @@ -65,7 +65,7 @@ static int HvQueryHypervisorInfo(void) unsigned int ebx; unsigned int ecx; unsigned int edx; - unsigned int maxLeaf; + unsigned int max_leaf; unsigned int op; /* @@ -93,7 +93,7 @@ static int HvQueryHypervisorInfo(void) ((edx >> 16) & 0xFF), ((edx >> 24) & 0xFF)); - maxLeaf = eax; + max_leaf = eax; eax = 0; ebx = 0; ecx = 0; @@ -107,7 +107,7 @@ static int HvQueryHypervisorInfo(void) ((eax >> 16) & 0xFF), ((eax >> 24) & 0xFF)); - if (maxLeaf >= HVCPUID_VERSION) { + if (max_leaf >= HVCPUID_VERSION) { eax = 0; ebx = 0; ecx = 0; @@ -122,61 +122,61 @@ static int HvQueryHypervisorInfo(void) edx >> 24, edx & 0xFFFFFF); } - return maxLeaf; + return max_leaf; } /* * HvDoHypercall - Invoke the specified hypercall */ -static u64 HvDoHypercall(u64 Control, void *Input, void *Output) +static u64 HvDoHypercall(u64 control, void *input, void *output) { #ifdef CONFIG_X86_64 - u64 hvStatus = 0; - u64 inputAddress = (Input) ? virt_to_phys(Input) : 0; - u64 outputAddress = (Output) ? virt_to_phys(Output) : 0; - volatile void *hypercallPage = hv_context.hypercall_page; + u64 hv_status = 0; + u64 input_address = (input) ? virt_to_phys(input) : 0; + u64 output_address = (output) ? virt_to_phys(output) : 0; + volatile void *hypercall_page = hv_context.hypercall_page; DPRINT_DBG(VMBUS, "Hypercall ", - Control, inputAddress, Input, - outputAddress, Output, hypercallPage); + control, input_address, input, + output_address, output, hypercall_page); - __asm__ __volatile__("mov %0, %%r8" : : "r" (outputAddress) : "r8"); - __asm__ __volatile__("call *%3" : "=a" (hvStatus) : - "c" (Control), "d" (inputAddress), - "m" (hypercallPage)); + __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8"); + __asm__ __volatile__("call *%3" : "=a" (hv_status) : + "c" (control), "d" (input_address), + "m" (hypercall_page)); - DPRINT_DBG(VMBUS, "Hypercall ", hvStatus); + DPRINT_DBG(VMBUS, "Hypercall ", hv_status); - return hvStatus; + return hv_status; #else - u32 controlHi = Control >> 32; - u32 controlLo = Control & 0xFFFFFFFF; - u32 hvStatusHi = 1; - u32 hvStatusLo = 1; - u64 inputAddress = (Input) ? virt_to_phys(Input) : 0; - u32 inputAddressHi = inputAddress >> 32; - u32 inputAddressLo = inputAddress & 0xFFFFFFFF; - u64 outputAddress = (Output) ? virt_to_phys(Output) : 0; - u32 outputAddressHi = outputAddress >> 32; - u32 outputAddressLo = outputAddress & 0xFFFFFFFF; - volatile void *hypercallPage = hv_context.hypercall_page; + u32 control_hi = control >> 32; + u32 control_lo = control & 0xFFFFFFFF; + u32 hv_status_hi = 1; + u32 hv_status_lo = 1; + u64 input_address = (input) ? virt_to_phys(input) : 0; + u32 input_address_hi = input_address >> 32; + u32 input_address_lo = input_address & 0xFFFFFFFF; + u64 output_address = (output) ? virt_to_phys(output) : 0; + u32 output_address_hi = output_address >> 32; + u32 output_address_lo = output_address & 0xFFFFFFFF; + volatile void *hypercall_page = hv_context.hypercall_page; DPRINT_DBG(VMBUS, "Hypercall ", - Control, Input, Output); + control, input, output); - __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), - "=a"(hvStatusLo) : "d" (controlHi), - "a" (controlLo), "b" (inputAddressHi), - "c" (inputAddressLo), "D"(outputAddressHi), - "S"(outputAddressLo), "m" (hypercallPage)); + __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi), + "=a"(hv_status_lo) : "d" (control_hi), + "a" (control_lo), "b" (input_address_hi), + "c" (input_address_lo), "D"(output_address_hi), + "S"(output_address_lo), "m" (hypercall_page)); DPRINT_DBG(VMBUS, "Hypercall ", - hvStatusLo | ((u64)hvStatusHi << 32)); + hv_status_lo | ((u64)hv_status_hi << 32)); - return hvStatusLo | ((u64)hvStatusHi << 32); + return hv_status_lo | ((u64)hv_status_hi << 32); #endif /* !x86_64 */ } @@ -188,9 +188,9 @@ static u64 HvDoHypercall(u64 Control, void *Input, void *Output) int HvInit(void) { int ret = 0; - int maxLeaf; - union hv_x64_msr_hypercall_contents hypercallMsr; - void *virtAddr = NULL; + int max_leaf; + union hv_x64_msr_hypercall_contents hypercall_msr; + void *virtaddr = NULL; memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS); memset(hv_context.synic_message_page, 0, @@ -204,7 +204,7 @@ int HvInit(void) DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info..."); - maxLeaf = HvQueryHypervisorInfo(); + max_leaf = HvQueryHypervisorInfo(); /* HvQueryHypervisorFeatures(maxLeaf); */ /* @@ -223,39 +223,39 @@ int HvInit(void) hv_context.guestid = HV_LINUX_GUEST_ID; /* See if the hypercall page is already set */ - rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); + rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); /* * Allocate the hypercall page memory - * virtAddr = osd_PageAlloc(1); + * virtaddr = osd_PageAlloc(1); */ - virtAddr = osd_VirtualAllocExec(PAGE_SIZE); + virtaddr = osd_VirtualAllocExec(PAGE_SIZE); - if (!virtAddr) { + if (!virtaddr) { DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!"); goto Cleanup; } - hypercallMsr.enable = 1; + hypercall_msr.enable = 1; - hypercallMsr.guest_physical_address = vmalloc_to_pfn(virtAddr); - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); + hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr); + wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); /* Confirm that hypercall page did get setup. */ - hypercallMsr.as_uint64 = 0; - rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); + hypercall_msr.as_uint64 = 0; + rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); - if (!hypercallMsr.enable) { + if (!hypercall_msr.enable) { DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); goto Cleanup; } - hv_context.hypercall_page = virtAddr; + hv_context.hypercall_page = virtaddr; DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx", hv_context.hypercall_page, - (u64)hypercallMsr.guest_physical_address << PAGE_SHIFT); + (u64)hypercall_msr.guest_physical_address << PAGE_SHIFT); /* Setup the global signal event param for the signal event hypercall */ hv_context.signal_event_buffer = @@ -278,13 +278,13 @@ int HvInit(void) return ret; Cleanup: - if (virtAddr) { - if (hypercallMsr.enable) { - hypercallMsr.as_uint64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); + if (virtaddr) { + if (hypercall_msr.enable) { + hypercall_msr.as_uint64 = 0; + wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); } - vfree(virtAddr); + vfree(virtaddr); } ret = -1; return ret; @@ -297,15 +297,15 @@ Cleanup: */ void HvCleanup(void) { - union hv_x64_msr_hypercall_contents hypercallMsr; + union hv_x64_msr_hypercall_contents hypercall_msr; kfree(hv_context.signal_event_buffer); hv_context.signal_event_buffer = NULL; hv_context.signal_event_param = NULL; if (hv_context.hypercall_page) { - hypercallMsr.as_uint64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.as_uint64); + hypercall_msr.as_uint64 = 0; + wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); vfree(hv_context.hypercall_page); hv_context.hypercall_page = NULL; } @@ -316,35 +316,35 @@ void HvCleanup(void) * * This involves a hypercall. */ -u16 HvPostMessage(union hv_connection_id connectionId, - enum hv_message_type messageType, - void *payload, size_t payloadSize) +u16 HvPostMessage(union hv_connection_id connection_id, + enum hv_message_type message_type, + void *payload, size_t payload_size) { - struct alignedInput { + struct aligned_input { u64 alignment8; struct hv_input_post_message msg; }; - struct hv_input_post_message *alignedMsg; + struct hv_input_post_message *aligned_msg; u16 status; unsigned long addr; - if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT) + if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) return -1; - addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC); + addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC); if (!addr) return -1; - alignedMsg = (struct hv_input_post_message *) + aligned_msg = (struct hv_input_post_message *) (ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); - alignedMsg->connectionid = connectionId; - alignedMsg->message_type = messageType; - alignedMsg->payload_size = payloadSize; - memcpy((void *)alignedMsg->payload, payload, payloadSize); + aligned_msg->connectionid = connection_id; + aligned_msg->message_type = message_type; + aligned_msg->payload_size = payload_size; + memcpy((void *)aligned_msg->payload, payload, payload_size); - status = HvDoHypercall(HVCALL_POST_MESSAGE, alignedMsg, NULL) & 0xFFFF; + status = HvDoHypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) & 0xFFFF; kfree((void *)addr); @@ -379,10 +379,10 @@ void HvSynicInit(void *irqarg) u64 version; union hv_synic_simp simp; union hv_synic_siefp siefp; - union hv_synic_sint sharedSint; + union hv_synic_sint shared_sint; union hv_synic_scontrol sctrl; - u32 irqVector = *((u32 *)(irqarg)); + u32 irq_vector = *((u32 *)(irqarg)); int cpu = smp_processor_id(); if (!hv_context.hypercall_page) @@ -436,17 +436,17 @@ void HvSynicInit(void *irqarg) /* interceptionSint.as_uint64); */ /* Setup the shared SINT. */ - rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); + rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); - sharedSint.as_uint64 = 0; - sharedSint.vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */ - sharedSint.masked = false; - sharedSint.auto_eoi = true; + shared_sint.as_uint64 = 0; + shared_sint.vector = irq_vector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */ + shared_sint.masked = false; + shared_sint.auto_eoi = true; DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", - sharedSint.as_uint64); + shared_sint.as_uint64); - wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); + wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); /* Enable the global synic bit */ rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); @@ -471,7 +471,7 @@ Cleanup: */ void HvSynicCleanup(void *arg) { - union hv_synic_sint sharedSint; + union hv_synic_sint shared_sint; union hv_synic_simp simp; union hv_synic_siefp siefp; int cpu = smp_processor_id(); @@ -479,13 +479,13 @@ void HvSynicCleanup(void *arg) if (!hv_context.synic_initialized) return; - rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); + rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); - sharedSint.masked = 1; + shared_sint.masked = 1; /* Need to correctly cleanup in the case of SMP!!! */ /* Disable the interrupt */ - wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.as_uint64); + wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); simp.simp_enabled = 0; -- cgit v1.2.3 From d44890c8d2a83116463c230b59b9b9d356aafe85 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:42 -0800 Subject: staging: hv: Convert camel cased functions in hv.c to lower cases staging: hv: Convert camel cased functions in hv.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/connection.c | 4 ++-- drivers/staging/hv/hv.c | 47 ++++++++++++++++++++++------------------- drivers/staging/hv/hv.h | 16 +++++++------- drivers/staging/hv/hv_api.h | 4 ++-- drivers/staging/hv/vmbus.c | 8 +++---- 5 files changed, 41 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c index ba50dd8fe52d..97321d172c91 100644 --- a/drivers/staging/hv/connection.c +++ b/drivers/staging/hv/connection.c @@ -311,7 +311,7 @@ int VmbusPostMessage(void *buffer, size_t bufferLen) connId.asu32 = 0; connId.u.id = VMBUS_MESSAGE_CONNECTION_ID; - return HvPostMessage(connId, 1, buffer, bufferLen); + return hv_post_message(connId, 1, buffer, bufferLen); } /* @@ -324,5 +324,5 @@ int VmbusSetEvent(u32 childRelId) (unsigned long *)gVmbusConnection.SendInterruptPage + (childRelId >> 5)); - return HvSignalEvent(); + return hv_signal_event(); } diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c index 2fd234d711ea..66f04d8063a6 100644 --- a/drivers/staging/hv/hv.c +++ b/drivers/staging/hv/hv.c @@ -36,9 +36,10 @@ struct hv_context hv_context = { }; /* - * HvQueryHypervisorPresence - Query the cpuid for presense of windows hypervisor + * query_hypervisor_presence + * - Query the cpuid for presense of windows hypervisor */ -static int HvQueryHypervisorPresence(void) +static int query_hypervisor_presence(void) { unsigned int eax; unsigned int ebx; @@ -57,9 +58,9 @@ static int HvQueryHypervisorPresence(void) } /* - * HvQueryHypervisorInfo - Get version info of the windows hypervisor + * query_hypervisor_info - Get version info of the windows hypervisor */ -static int HvQueryHypervisorInfo(void) +static int query_hypervisor_info(void) { unsigned int eax; unsigned int ebx; @@ -126,9 +127,9 @@ static int HvQueryHypervisorInfo(void) } /* - * HvDoHypercall - Invoke the specified hypercall + * do_hypercall- Invoke the specified hypercall */ -static u64 HvDoHypercall(u64 control, void *input, void *output) +static u64 do_hypercall(u64 control, void *input, void *output) { #ifdef CONFIG_X86_64 u64 hv_status = 0; @@ -181,11 +182,11 @@ static u64 HvDoHypercall(u64 control, void *input, void *output) } /* - * HvInit - Main initialization routine. + * hv_init - Main initialization routine. * * This routine must be called before any other routines in here are called */ -int HvInit(void) +int hv_init(void) { int ret = 0; int max_leaf; @@ -196,7 +197,7 @@ int HvInit(void) memset(hv_context.synic_message_page, 0, sizeof(void *) * MAX_NUM_CPUS); - if (!HvQueryHypervisorPresence()) { + if (!query_hypervisor_presence()) { DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!"); goto Cleanup; } @@ -204,7 +205,7 @@ int HvInit(void) DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info..."); - max_leaf = HvQueryHypervisorInfo(); + max_leaf = query_hypervisor_info(); /* HvQueryHypervisorFeatures(maxLeaf); */ /* @@ -291,11 +292,11 @@ Cleanup: } /* - * HvCleanup - Cleanup routine. + * hv_cleanup - Cleanup routine. * * This routine is called normally during driver unloading or exiting. */ -void HvCleanup(void) +void hv_cleanup(void) { union hv_x64_msr_hypercall_contents hypercall_msr; @@ -312,11 +313,11 @@ void HvCleanup(void) } /* - * HvPostMessage - Post a message using the hypervisor message IPC. + * hv_post_message - Post a message using the hypervisor message IPC. * * This involves a hypercall. */ -u16 HvPostMessage(union hv_connection_id connection_id, +u16 hv_post_message(union hv_connection_id connection_id, enum hv_message_type message_type, void *payload, size_t payload_size) { @@ -344,7 +345,8 @@ u16 HvPostMessage(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - status = HvDoHypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) & 0xFFFF; + status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) + & 0xFFFF; kfree((void *)addr); @@ -353,28 +355,29 @@ u16 HvPostMessage(union hv_connection_id connection_id, /* - * HvSignalEvent - Signal an event on the specified connection using the hypervisor event IPC. + * hv_signal_event - + * Signal an event on the specified connection using the hypervisor event IPC. * * This involves a hypercall. */ -u16 HvSignalEvent(void) +u16 hv_signal_event(void) { u16 status; - status = HvDoHypercall(HVCALL_SIGNAL_EVENT, + status = do_hypercall(HVCALL_SIGNAL_EVENT, hv_context.signal_event_param, NULL) & 0xFFFF; return status; } /* - * HvSynicInit - Initialize the Synthethic Interrupt Controller. + * hv_synic_init - Initialize the Synthethic Interrupt Controller. * * If it is already initialized by another entity (ie x2v shim), we need to * retrieve the initialized message and event pages. Otherwise, we create and * initialize the message and event pages. */ -void HvSynicInit(void *irqarg) +void hv_synic_init(void *irqarg) { u64 version; union hv_synic_simp simp; @@ -467,9 +470,9 @@ Cleanup: } /* - * HvSynicCleanup - Cleanup routine for HvSynicInit(). + * hv_synic_cleanup - Cleanup routine for hv_synic_init(). */ -void HvSynicCleanup(void *arg) +void hv_synic_cleanup(void *arg) { union hv_synic_sint shared_sint; union hv_synic_simp simp; diff --git a/drivers/staging/hv/hv.h b/drivers/staging/hv/hv.h index 6e396fca1942..829aff81bb30 100644 --- a/drivers/staging/hv/hv.h +++ b/drivers/staging/hv/hv.h @@ -123,18 +123,18 @@ extern struct hv_context hv_context; /* Hv Interface */ -extern int HvInit(void); +extern int hv_init(void); -extern void HvCleanup(void); +extern void hv_cleanup(void); -extern u16 HvPostMessage(union hv_connection_id connectionId, - enum hv_message_type messageType, - void *payload, size_t payloadSize); +extern u16 hv_post_message(union hv_connection_id connection_id, + enum hv_message_type message_type, + void *payload, size_t payload_size); -extern u16 HvSignalEvent(void); +extern u16 hv_signal_event(void); -extern void HvSynicInit(void *irqarg); +extern void hv_synic_init(void *irqarg); -extern void HvSynicCleanup(void *arg); +extern void hv_synic_cleanup(void *arg); #endif /* __HV_H__ */ diff --git a/drivers/staging/hv/hv_api.h b/drivers/staging/hv/hv_api.h index 9df64724549a..70e863ad0464 100644 --- a/drivers/staging/hv/hv_api.h +++ b/drivers/staging/hv/hv_api.h @@ -836,7 +836,7 @@ enum hv_call_code { HVCALL_SIGNAL_EVENT = 0x005d, }; -/* Definition of the HvPostMessage hypercall input structure. */ +/* Definition of the hv_post_message hypercall input structure. */ struct hv_input_post_message { union hv_connection_id connectionid; u32 reserved; @@ -845,7 +845,7 @@ struct hv_input_post_message { u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; }; -/* Definition of the HvSignalEvent hypercall input structure. */ +/* Definition of the hv_signal_event hypercall input structure. */ struct hv_input_signal_event { union hv_connection_id connectionid; u16 flag_number; diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index b1ec8762f228..e6462c6774d1 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -109,7 +109,7 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) /* strcpy(dev->name, "vmbus"); */ /* SynIC setup... */ - on_each_cpu(HvSynicInit, (void *)irqvector, 1); + on_each_cpu(hv_synic_init, (void *)irqvector, 1); /* Connect to VMBus in the root partition */ ret = VmbusConnect(); @@ -127,7 +127,7 @@ static int VmbusOnDeviceRemove(struct hv_device *dev) vmbus_release_unattached_channels(); VmbusDisconnect(); - on_each_cpu(HvSynicCleanup, NULL, 1); + on_each_cpu(hv_synic_cleanup, NULL, 1); return ret; } @@ -138,7 +138,7 @@ static void VmbusOnCleanup(struct hv_driver *drv) { /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */ - HvCleanup(); + hv_cleanup(); } /* @@ -264,7 +264,7 @@ int VmbusInitialize(struct hv_driver *drv) driver->GetChannelOffers = VmbusGetChannelOffers; /* Hypervisor initialization...setup hypercall page..etc */ - ret = HvInit(); + ret = hv_init(); if (ret != 0) DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); -- cgit v1.2.3 From d39f12866d90829e1ae0440c0203dd5a162c8cd8 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:43 -0800 Subject: staging: hv: Convert camel cased local variables in osd.c to lower cases staging: hv: Convert camel cased local variables in osd.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/osd.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c index 8c3eb278a81f..b39ec250aefd 100644 --- a/drivers/staging/hv/osd.c +++ b/drivers/staging/hv/osd.c @@ -130,9 +130,9 @@ EXPORT_SYMBOL_GPL(osd_WaitEventCreate); /** * osd_WaitEventSet() - Wake up the process - * @waitEvent: Structure to event to be woken up + * @wait_event: Structure to event to be woken up * - * @waitevent is of type &struct osd_waitevent + * @wait_event is of type &struct osd_waitevent * * Wake up the sleeping process so it can do some work. * And set condition indicator in &struct osd_waitevent to indicate @@ -140,18 +140,18 @@ EXPORT_SYMBOL_GPL(osd_WaitEventCreate); * * Only used by Network and Storage Hyper-V drivers. */ -void osd_WaitEventSet(struct osd_waitevent *waitEvent) +void osd_WaitEventSet(struct osd_waitevent *wait_event) { - waitEvent->condition = 1; - wake_up_interruptible(&waitEvent->event); + wait_event->condition = 1; + wake_up_interruptible(&wait_event->event); } EXPORT_SYMBOL_GPL(osd_WaitEventSet); /** * osd_WaitEventWait() - Wait for event till condition is true - * @waitEvent: Structure to event to be put to sleep + * @wait_event: Structure to event to be put to sleep * - * @waitevent is of type &struct osd_waitevent + * @wait_event is of type &struct osd_waitevent * * Set up the process to sleep until waitEvent->condition get true. * And set condition indicator in &struct osd_waitevent to indicate @@ -161,25 +161,25 @@ EXPORT_SYMBOL_GPL(osd_WaitEventSet); * * Mainly used by Hyper-V drivers. */ -int osd_WaitEventWait(struct osd_waitevent *waitEvent) +int osd_WaitEventWait(struct osd_waitevent *wait_event) { int ret = 0; - ret = wait_event_interruptible(waitEvent->event, - waitEvent->condition); - waitEvent->condition = 0; + ret = wait_event_interruptible(wait_event->event, + wait_event->condition); + wait_event->condition = 0; return ret; } EXPORT_SYMBOL_GPL(osd_WaitEventWait); /** * osd_WaitEventWaitEx() - Wait for event or timeout for process wakeup - * @waitEvent: Structure to event to be put to sleep - * @TimeoutInMs: Total number of Milliseconds to wait before waking up + * @wait_event: Structure to event to be put to sleep + * @timeout_in_ms: Total number of Milliseconds to wait before waking up * - * @waitevent is of type &struct osd_waitevent + * @wait_event is of type &struct osd_waitevent * Set up the process to sleep until @waitEvent->condition get true or - * @TimeoutInMs (Time out in Milliseconds) has been reached. + * @timeout_in_ms (Time out in Milliseconds) has been reached. * And set condition indicator in &struct osd_waitevent to indicate * the process is in a sleeping state. * @@ -187,14 +187,14 @@ EXPORT_SYMBOL_GPL(osd_WaitEventWait); * * Mainly used by Hyper-V drivers. */ -int osd_WaitEventWaitEx(struct osd_waitevent *waitEvent, u32 TimeoutInMs) +int osd_WaitEventWaitEx(struct osd_waitevent *wait_event, u32 timeout_in_ms) { int ret = 0; - ret = wait_event_interruptible_timeout(waitEvent->event, - waitEvent->condition, - msecs_to_jiffies(TimeoutInMs)); - waitEvent->condition = 0; + ret = wait_event_interruptible_timeout(wait_event->event, + wait_event->condition, + msecs_to_jiffies(timeout_in_ms)); + wait_event->condition = 0; return ret; } EXPORT_SYMBOL_GPL(osd_WaitEventWaitEx); -- cgit v1.2.3 From 203df82d81a331e16caee4c2346cd382fcd820d6 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:44 -0800 Subject: staging: hv: Convert camel cased functions in osd.c to lower cases staging: hv: Convert camel cased functions in osd.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 20 ++++++++++---------- drivers/staging/hv/channel_mgmt.c | 12 ++++++------ drivers/staging/hv/connection.c | 14 +++++++------- drivers/staging/hv/hv.c | 12 ++++++------ drivers/staging/hv/netvsc.c | 24 +++++++++++------------ drivers/staging/hv/osd.c | 40 +++++++++++++++++++-------------------- drivers/staging/hv/osd.h | 18 +++++++++--------- drivers/staging/hv/rndis_filter.c | 10 +++++----- drivers/staging/hv/storvsc.c | 16 ++++++++-------- 9 files changed, 83 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index 7c15c4034e2d..abc2988b4d4a 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -180,7 +180,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, newchannel->channel_callback_context = context; /* Allocate the ring buffer */ - out = osd_PageAlloc((send_ringbuffer_size + recv_ringbuffer_size) + out = osd_page_alloc((send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT); if (!out) return -ENOMEM; @@ -242,7 +242,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, goto errorout; } - openInfo->waitevent = osd_WaitEventCreate(); + openInfo->waitevent = osd_waitevent_create(); if (!openInfo->waitevent) { err = -ENOMEM; goto errorout; @@ -280,7 +280,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, } /* FIXME: Need to time-out here */ - osd_WaitEventWait(openInfo->waitevent); + osd_waitevent_wait(openInfo->waitevent); if (openInfo->response.open_result.status == 0) DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel); @@ -300,7 +300,7 @@ Cleanup: errorout: RingBufferCleanup(&newchannel->outbound); RingBufferCleanup(&newchannel->inbound); - osd_PageFree(out, (send_ringbuffer_size + recv_ringbuffer_size) + osd_page_free(out, (send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT); kfree(openInfo); return err; @@ -508,7 +508,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, if (ret) return ret; - msginfo->waitevent = osd_WaitEventCreate(); + msginfo->waitevent = osd_waitevent_create(); if (!msginfo->waitevent) { ret = -ENOMEM; goto Cleanup; @@ -565,7 +565,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, } } - osd_WaitEventWait(msginfo->waitevent); + osd_waitevent_wait(msginfo->waitevent); /* At this point, we received the gpadl created msg */ DPRINT_DBG(VMBUS, "Received GPADL created " @@ -604,7 +604,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) if (!info) return -ENOMEM; - info->waitevent = osd_WaitEventCreate(); + info->waitevent = osd_waitevent_create(); if (!info->waitevent) { kfree(info); return -ENOMEM; @@ -628,7 +628,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) /* something... */ } - osd_WaitEventWait(info->waitevent); + osd_waitevent_wait(info->waitevent); /* Received a torndown response */ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags); @@ -663,7 +663,7 @@ void vmbus_close(struct vmbus_channel *channel) if (!info) return; - /* info->waitEvent = osd_WaitEventCreate(); */ + /* info->waitEvent = osd_waitevent_create(); */ msg = (struct vmbus_channel_close_channel *)info->msg; msg->header.msgtype = CHANNELMSG_CLOSECHANNEL; @@ -686,7 +686,7 @@ void vmbus_close(struct vmbus_channel *channel) RingBufferCleanup(&channel->outbound); RingBufferCleanup(&channel->inbound); - osd_PageFree(channel->ringbuffer_pages, channel->ringbuffer_pagecount); + osd_page_free(channel->ringbuffer_pages, channel->ringbuffer_pagecount); kfree(info); diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index be34e38c1a85..ae830f2e4e3a 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -566,7 +566,7 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr) memcpy(&msginfo->response.open_result, result, sizeof(struct vmbus_channel_open_result)); - osd_WaitEventSet(msginfo->waitevent); + osd_waitevent_set(msginfo->waitevent); break; } } @@ -616,7 +616,7 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr) memcpy(&msginfo->response.gpadl_created, gpadlcreated, sizeof(struct vmbus_channel_gpadl_created)); - osd_WaitEventSet(msginfo->waitevent); + osd_waitevent_set(msginfo->waitevent); break; } } @@ -662,7 +662,7 @@ static void vmbus_ongpadl_torndown( memcpy(&msginfo->response.gpadl_torndown, gpadl_torndown, sizeof(struct vmbus_channel_gpadl_torndown)); - osd_WaitEventSet(msginfo->waitevent); + osd_waitevent_set(msginfo->waitevent); break; } } @@ -703,7 +703,7 @@ static void vmbus_onversion_response( memcpy(&msginfo->response.version_response, version_response, sizeof(struct vmbus_channel_version_response)); - osd_WaitEventSet(msginfo->waitevent); + osd_waitevent_set(msginfo->waitevent); } } spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags); @@ -782,7 +782,7 @@ int vmbus_request_offers(void) if (!msginfo) return -ENOMEM; - msginfo->waitevent = osd_WaitEventCreate(); + msginfo->waitevent = osd_waitevent_create(); if (!msginfo->waitevent) { kfree(msginfo); return -ENOMEM; @@ -808,7 +808,7 @@ int vmbus_request_offers(void) goto Cleanup; } - /* osd_WaitEventWait(msgInfo->waitEvent); */ + /* osd_waitevent_wait(msgInfo->waitEvent); */ /*SpinlockAcquire(gVmbusConnection.channelMsgLock); REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c index 97321d172c91..c2e298ff4834 100644 --- a/drivers/staging/hv/connection.c +++ b/drivers/staging/hv/connection.c @@ -66,7 +66,7 @@ int VmbusConnect(void) * Setup the vmbus event connection for channel interrupt * abstraction stuff */ - gVmbusConnection.InterruptPage = osd_PageAlloc(1); + gVmbusConnection.InterruptPage = osd_page_alloc(1); if (gVmbusConnection.InterruptPage == NULL) { ret = -1; goto Cleanup; @@ -81,7 +81,7 @@ int VmbusConnect(void) * Setup the monitor notification facility. The 1st page for * parent->child and the 2nd page for child->parent */ - gVmbusConnection.MonitorPages = osd_PageAlloc(2); + gVmbusConnection.MonitorPages = osd_page_alloc(2); if (gVmbusConnection.MonitorPages == NULL) { ret = -1; goto Cleanup; @@ -95,7 +95,7 @@ int VmbusConnect(void) goto Cleanup; } - msgInfo->waitevent = osd_WaitEventCreate(); + msgInfo->waitevent = osd_waitevent_create(); if (!msgInfo->waitevent) { ret = -ENOMEM; goto Cleanup; @@ -134,7 +134,7 @@ int VmbusConnect(void) } /* Wait for the connection response */ - osd_WaitEventWait(msgInfo->waitevent); + osd_waitevent_wait(msgInfo->waitevent); list_del(&msgInfo->msglistentry); @@ -162,12 +162,12 @@ Cleanup: destroy_workqueue(gVmbusConnection.WorkQueue); if (gVmbusConnection.InterruptPage) { - osd_PageFree(gVmbusConnection.InterruptPage, 1); + osd_page_free(gVmbusConnection.InterruptPage, 1); gVmbusConnection.InterruptPage = NULL; } if (gVmbusConnection.MonitorPages) { - osd_PageFree(gVmbusConnection.MonitorPages, 2); + osd_page_free(gVmbusConnection.MonitorPages, 2); gVmbusConnection.MonitorPages = NULL; } @@ -202,7 +202,7 @@ int VmbusDisconnect(void) if (ret != 0) goto Cleanup; - osd_PageFree(gVmbusConnection.InterruptPage, 1); + osd_page_free(gVmbusConnection.InterruptPage, 1); /* TODO: iterate thru the msg list and free up */ destroy_workqueue(gVmbusConnection.WorkQueue); diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c index 66f04d8063a6..a34d713d9c57 100644 --- a/drivers/staging/hv/hv.c +++ b/drivers/staging/hv/hv.c @@ -228,9 +228,9 @@ int hv_init(void) /* * Allocate the hypercall page memory - * virtaddr = osd_PageAlloc(1); + * virtaddr = osd_page_alloc(1); */ - virtaddr = osd_VirtualAllocExec(PAGE_SIZE); + virtaddr = osd_virtual_alloc_exec(PAGE_SIZE); if (!virtaddr) { DPRINT_ERR(VMBUS, @@ -462,10 +462,10 @@ void hv_synic_init(void *irqarg) Cleanup: if (hv_context.synic_event_page[cpu]) - osd_PageFree(hv_context.synic_event_page[cpu], 1); + osd_page_free(hv_context.synic_event_page[cpu], 1); if (hv_context.synic_message_page[cpu]) - osd_PageFree(hv_context.synic_message_page[cpu], 1); + osd_page_free(hv_context.synic_message_page[cpu], 1); return; } @@ -502,6 +502,6 @@ void hv_synic_cleanup(void *arg) wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); - osd_PageFree(hv_context.synic_message_page[cpu], 1); - osd_PageFree(hv_context.synic_event_page[cpu], 1); + osd_page_free(hv_context.synic_message_page[cpu], 1); + osd_page_free(hv_context.synic_event_page[cpu], 1); } diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index 4c2632cb19e9..8022781a9b13 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -221,7 +221,7 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */ netDevice->ReceiveBuffer = - osd_PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT); + osd_page_alloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT); if (!netDevice->ReceiveBuffer) { DPRINT_ERR(NETVSC, "unable to allocate receive buffer of size %d", @@ -249,7 +249,7 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) goto Cleanup; } - /* osd_WaitEventWait(ext->ChannelInitEvent); */ + /* osd_waitevent_wait(ext->ChannelInitEvent); */ /* Notify the NetVsp of the gpadl handle */ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer..."); @@ -274,7 +274,7 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(netDevice->ChannelInitEvent); + osd_waitevent_wait(netDevice->ChannelInitEvent); /* Check the response */ if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess) { @@ -350,7 +350,7 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */ netDevice->SendBuffer = - osd_PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT); + osd_page_alloc(netDevice->SendBufferSize >> PAGE_SHIFT); if (!netDevice->SendBuffer) { DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", netDevice->SendBufferSize); @@ -375,7 +375,7 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) goto Cleanup; } - /* osd_WaitEventWait(ext->ChannelInitEvent); */ + /* osd_waitevent_wait(ext->ChannelInitEvent); */ /* Notify the NetVsp of the gpadl handle */ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer..."); @@ -400,7 +400,7 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(netDevice->ChannelInitEvent); + osd_waitevent_wait(netDevice->ChannelInitEvent); /* Check the response */ if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess) { @@ -480,7 +480,7 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice) DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); /* Free up the receive buffer */ - osd_PageFree(NetDevice->ReceiveBuffer, + osd_page_free(NetDevice->ReceiveBuffer, NetDevice->ReceiveBufferSize >> PAGE_SHIFT); NetDevice->ReceiveBuffer = NULL; } @@ -553,7 +553,7 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice) DPRINT_INFO(NETVSC, "Freeing up send buffer..."); /* Free up the receive buffer */ - osd_PageFree(NetDevice->SendBuffer, + osd_page_free(NetDevice->SendBuffer, NetDevice->SendBufferSize >> PAGE_SHIFT); NetDevice->SendBuffer = NULL; } @@ -597,7 +597,7 @@ static int NetVscConnectToVsp(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(netDevice->ChannelInitEvent); + osd_waitevent_wait(netDevice->ChannelInitEvent); /* Now, check the response */ /* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */ @@ -651,7 +651,7 @@ static int NetVscConnectToVsp(struct hv_device *Device) * packet) since our Vmbus always set the * VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag */ - /* osd_WaitEventWait(NetVscChannel->ChannelInitEvent); */ + /* osd_waitevent_wait(NetVscChannel->ChannelInitEvent); */ /* Post the big receive buffer to NetVSP */ ret = NetVscInitializeReceiveBufferWithNetVsp(Device); @@ -710,7 +710,7 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) list_add_tail(&packet->ListEntry, &netDevice->ReceivePacketList); } - netDevice->ChannelInitEvent = osd_WaitEventCreate(); + netDevice->ChannelInitEvent = osd_waitevent_create(); if (!netDevice->ChannelInitEvent) { ret = -ENOMEM; goto Cleanup; @@ -855,7 +855,7 @@ static void NetVscOnSendCompletion(struct hv_device *Device, /* Copy the response back */ memcpy(&netDevice->ChannelInitPacket, nvspPacket, sizeof(struct nvsp_message)); - osd_WaitEventSet(netDevice->ChannelInitEvent); + osd_waitevent_set(netDevice->ChannelInitEvent); } else if (nvspPacket->Header.MessageType == NvspMessage1TypeSendRNDISPacketComplete) { /* Get the send context */ diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c index b39ec250aefd..b699ee27f07f 100644 --- a/drivers/staging/hv/osd.c +++ b/drivers/staging/hv/osd.c @@ -49,7 +49,7 @@ struct osd_callback_struct { void *data; }; -void *osd_VirtualAllocExec(unsigned int size) +void *osd_virtual_alloc_exec(unsigned int size) { #ifdef __x86_64__ return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC); @@ -60,7 +60,7 @@ void *osd_VirtualAllocExec(unsigned int size) } /** - * osd_PageAlloc() - Allocate pages + * osd_page_alloc() - Allocate pages * @count: Total number of Kernel pages you want to allocate * * Tries to allocate @count number of consecutive free kernel pages. @@ -68,7 +68,7 @@ void *osd_VirtualAllocExec(unsigned int size) * If successfull it will return pointer to the @count pages. * Mainly used by Hyper-V drivers. */ -void *osd_PageAlloc(unsigned int count) +void *osd_page_alloc(unsigned int count) { void *p; @@ -85,26 +85,26 @@ void *osd_PageAlloc(unsigned int count) /* if (p) memset(p, 0, PAGE_SIZE); */ /* return p; */ } -EXPORT_SYMBOL_GPL(osd_PageAlloc); +EXPORT_SYMBOL_GPL(osd_page_alloc); /** - * osd_PageFree() - Free pages + * osd_page_free() - Free pages * @page: Pointer to the first page to be freed * @count: Total number of Kernel pages you free * - * Frees the pages allocated by osd_PageAlloc() + * Frees the pages allocated by osd_page_alloc() * Mainly used by Hyper-V drivers. */ -void osd_PageFree(void *page, unsigned int count) +void osd_page_free(void *page, unsigned int count) { free_pages((unsigned long)page, get_order(count * PAGE_SIZE)); /*struct page* p = virt_to_page(page); __free_page(p);*/ } -EXPORT_SYMBOL_GPL(osd_PageFree); +EXPORT_SYMBOL_GPL(osd_page_free); /** - * osd_WaitEventCreate() - Create the event queue + * osd_waitevent_create() - Create the event queue * * Allocates memory for a &struct osd_waitevent. And then calls * init_waitqueue_head to set up the wait queue for the event. @@ -114,7 +114,7 @@ EXPORT_SYMBOL_GPL(osd_PageFree); * Returns pointer to &struct osd_waitevent * Mainly used by Hyper-V drivers. */ -struct osd_waitevent *osd_WaitEventCreate(void) +struct osd_waitevent *osd_waitevent_create(void) { struct osd_waitevent *wait = kmalloc(sizeof(struct osd_waitevent), GFP_KERNEL); @@ -125,11 +125,11 @@ struct osd_waitevent *osd_WaitEventCreate(void) init_waitqueue_head(&wait->event); return wait; } -EXPORT_SYMBOL_GPL(osd_WaitEventCreate); +EXPORT_SYMBOL_GPL(osd_waitevent_create); /** - * osd_WaitEventSet() - Wake up the process + * osd_waitevent_set() - Wake up the process * @wait_event: Structure to event to be woken up * * @wait_event is of type &struct osd_waitevent @@ -140,15 +140,15 @@ EXPORT_SYMBOL_GPL(osd_WaitEventCreate); * * Only used by Network and Storage Hyper-V drivers. */ -void osd_WaitEventSet(struct osd_waitevent *wait_event) +void osd_waitevent_set(struct osd_waitevent *wait_event) { wait_event->condition = 1; wake_up_interruptible(&wait_event->event); } -EXPORT_SYMBOL_GPL(osd_WaitEventSet); +EXPORT_SYMBOL_GPL(osd_waitevent_set); /** - * osd_WaitEventWait() - Wait for event till condition is true + * osd_waitevent_wait() - Wait for event till condition is true * @wait_event: Structure to event to be put to sleep * * @wait_event is of type &struct osd_waitevent @@ -161,7 +161,7 @@ EXPORT_SYMBOL_GPL(osd_WaitEventSet); * * Mainly used by Hyper-V drivers. */ -int osd_WaitEventWait(struct osd_waitevent *wait_event) +int osd_waitevent_wait(struct osd_waitevent *wait_event) { int ret = 0; @@ -170,10 +170,10 @@ int osd_WaitEventWait(struct osd_waitevent *wait_event) wait_event->condition = 0; return ret; } -EXPORT_SYMBOL_GPL(osd_WaitEventWait); +EXPORT_SYMBOL_GPL(osd_waitevent_wait); /** - * osd_WaitEventWaitEx() - Wait for event or timeout for process wakeup + * osd_waitevent_waitex() - Wait for event or timeout for process wakeup * @wait_event: Structure to event to be put to sleep * @timeout_in_ms: Total number of Milliseconds to wait before waking up * @@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(osd_WaitEventWait); * * Mainly used by Hyper-V drivers. */ -int osd_WaitEventWaitEx(struct osd_waitevent *wait_event, u32 timeout_in_ms) +int osd_waitevent_waitex(struct osd_waitevent *wait_event, u32 timeout_in_ms) { int ret = 0; @@ -197,7 +197,7 @@ int osd_WaitEventWaitEx(struct osd_waitevent *wait_event, u32 timeout_in_ms) wait_event->condition = 0; return ret; } -EXPORT_SYMBOL_GPL(osd_WaitEventWaitEx); +EXPORT_SYMBOL_GPL(osd_waitevent_waitex); static void osd_callback_work(struct work_struct *work) { diff --git a/drivers/staging/hv/osd.h b/drivers/staging/hv/osd.h index ce064e8ea644..cae126ff6b9a 100644 --- a/drivers/staging/hv/osd.h +++ b/drivers/staging/hv/osd.h @@ -50,18 +50,18 @@ struct osd_waitevent { /* Osd routines */ -extern void *osd_VirtualAllocExec(unsigned int size); +extern void *osd_virtual_alloc_exec(unsigned int size); -extern void *osd_PageAlloc(unsigned int count); -extern void osd_PageFree(void *page, unsigned int count); +extern void *osd_page_alloc(unsigned int count); +extern void osd_page_free(void *page, unsigned int count); -extern struct osd_waitevent *osd_WaitEventCreate(void); -extern void osd_WaitEventSet(struct osd_waitevent *waitEvent); -extern int osd_WaitEventWait(struct osd_waitevent *waitEvent); +extern struct osd_waitevent *osd_waitevent_create(void); +extern void osd_waitevent_set(struct osd_waitevent *wait_event); +extern int osd_waitevent_wait(struct osd_waitevent *wait_event); -/* If >0, waitEvent got signaled. If ==0, timeout. If < 0, error */ -extern int osd_WaitEventWaitEx(struct osd_waitevent *waitEvent, - u32 TimeoutInMs); +/* If >0, wait_event got signaled. If ==0, timeout. If < 0, error */ +extern int osd_waitevent_waitex(struct osd_waitevent *wait_event, + u32 timeout_in_ms); int osd_schedule_callback(struct workqueue_struct *wq, void (*func)(void *), diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index fa2141f454f0..b85c82542421 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -129,7 +129,7 @@ static struct rndis_request *GetRndisRequest(struct rndis_device *Device, if (!request) return NULL; - request->WaitEvent = osd_WaitEventCreate(); + request->WaitEvent = osd_waitevent_create(); if (!request->WaitEvent) { kfree(request); return NULL; @@ -313,7 +313,7 @@ static void RndisFilterReceiveResponse(struct rndis_device *Device, } } - osd_WaitEventSet(request->WaitEvent); + osd_waitevent_set(request->WaitEvent); } else { DPRINT_ERR(NETVSC, "no rndis request found for this response " "(id 0x%x res type 0x%x)", @@ -497,7 +497,7 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid, if (ret != 0) goto Cleanup; - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); /* Copy the response back */ queryComplete = &request->ResponseMessage.Message.QueryComplete; @@ -572,7 +572,7 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device, if (ret != 0) goto Cleanup; - ret = osd_WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/); + ret = osd_waitevent_waitex(request->WaitEvent, 2000/*2sec*/); if (!ret) { ret = -1; DPRINT_ERR(NETVSC, "timeout before we got a set response..."); @@ -665,7 +665,7 @@ static int RndisFilterInitDevice(struct rndis_device *Device) goto Cleanup; } - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); initComplete = &request->ResponseMessage.Message.InitializeComplete; status = initComplete->Status; diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 19e87f689fa0..525c8ee46f07 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -198,7 +198,7 @@ static int StorVscChannelInit(struct hv_device *Device) * channel */ memset(request, 0, sizeof(struct storvsc_request_extension)); - request->WaitEvent = osd_WaitEventCreate(); + request->WaitEvent = osd_waitevent_create(); if (!request->WaitEvent) { ret = -ENOMEM; goto nomem; @@ -224,7 +224,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); if (vstorPacket->Operation != VStorOperationCompleteIo || vstorPacket->Status != 0) { @@ -255,7 +255,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); /* TODO: Check returned version */ if (vstorPacket->Operation != VStorOperationCompleteIo || @@ -287,7 +287,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); /* TODO: Check returned version */ if (vstorPacket->Operation != VStorOperationCompleteIo || @@ -323,7 +323,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); if (vstorPacket->Operation != VStorOperationCompleteIo || vstorPacket->Status != 0) { @@ -473,7 +473,7 @@ static void StorVscOnChannelCallback(void *context) memcpy(&request->VStorPacket, packet, sizeof(struct vstor_packet)); - osd_WaitEventSet(request->WaitEvent); + osd_waitevent_set(request->WaitEvent); } else { StorVscOnReceive(device, (struct vstor_packet *)packet, @@ -622,7 +622,7 @@ int StorVscOnHostReset(struct hv_device *Device) request = &storDevice->ResetRequest; vstorPacket = &request->VStorPacket; - request->WaitEvent = osd_WaitEventCreate(); + request->WaitEvent = osd_waitevent_create(); if (!request->WaitEvent) { ret = -ENOMEM; goto Cleanup; @@ -644,7 +644,7 @@ int StorVscOnHostReset(struct hv_device *Device) } /* FIXME: Add a timeout */ - osd_WaitEventWait(request->WaitEvent); + osd_waitevent_wait(request->WaitEvent); kfree(request->WaitEvent); DPRINT_INFO(STORVSC, "host adapter reset completed"); -- cgit v1.2.3 From 82f8bd40a017716bfadcf074b4c6110ebe4c7ba6 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:45 -0800 Subject: staging: hv: Convert camel cased struct fields in ring_buffer.h to lower cases staging: hv: Convert camel cased struct fields in ring_buffer.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 10 +++---- drivers/staging/hv/ring_buffer.c | 58 +++++++++++++++++++++------------------- drivers/staging/hv/ring_buffer.h | 30 ++++++++++----------- drivers/staging/hv/vmbus_drv.c | 25 +++++++++-------- 4 files changed, 65 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index abc2988b4d4a..0e554e91f1d8 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -213,7 +213,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, newchannel->ringbuffer_gpadlhandle = 0; ret = vmbus_establish_gpadl(newchannel, - newchannel->outbound.RingBuffer, + newchannel->outbound.ring_buffer, send_ringbuffer_size + recv_ringbuffer_size, &newchannel->ringbuffer_gpadlhandle); @@ -227,10 +227,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, "size %d recv ring %p size %d, downstreamoffset %d>", newchannel, newchannel->offermsg.child_relid, newchannel->ringbuffer_gpadlhandle, - newchannel->outbound.RingBuffer, - newchannel->outbound.RingSize, - newchannel->inbound.RingBuffer, - newchannel->inbound.RingSize, + newchannel->outbound.ring_buffer, + newchannel->outbound.ring_size, + newchannel->inbound.ring_buffer, + newchannel->inbound.ring_size, send_ringbuffer_size); /* Create and init the channel open message */ diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c index d78c569ac94a..6095cc5ce711 100644 --- a/drivers/staging/hv/ring_buffer.c +++ b/drivers/staging/hv/ring_buffer.c @@ -51,11 +51,11 @@ GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write) u32 read_loc, write_loc; /* Capture the read/write indices before they changed */ - read_loc = rbi->RingBuffer->ReadIndex; - write_loc = rbi->RingBuffer->WriteIndex; + read_loc = rbi->ring_buffer->read_index; + write_loc = rbi->ring_buffer->write_index; - *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize); - *read = rbi->RingDataSize - *write; + *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->ring_datasize); + *read = rbi->ring_datasize - *write; } /*++ @@ -70,7 +70,7 @@ Description: static inline u32 GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo) { - u32 next = RingInfo->RingBuffer->WriteIndex; + u32 next = RingInfo->ring_buffer->write_index; /* ASSERT(next < RingInfo->RingDataSize); */ @@ -90,7 +90,7 @@ static inline void SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo, u32 NextWriteLocation) { - RingInfo->RingBuffer->WriteIndex = NextWriteLocation; + RingInfo->ring_buffer->write_index = NextWriteLocation; } /*++ @@ -105,7 +105,7 @@ Description: static inline u32 GetNextReadLocation(struct hv_ring_buffer_info *RingInfo) { - u32 next = RingInfo->RingBuffer->ReadIndex; + u32 next = RingInfo->ring_buffer->read_index; /* ASSERT(next < RingInfo->RingDataSize); */ @@ -125,11 +125,11 @@ Description: static inline u32 GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset) { - u32 next = RingInfo->RingBuffer->ReadIndex; + u32 next = RingInfo->ring_buffer->read_index; /* ASSERT(next < RingInfo->RingDataSize); */ next += Offset; - next %= RingInfo->RingDataSize; + next %= RingInfo->ring_datasize; return next; } @@ -146,7 +146,7 @@ Description: static inline void SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation) { - RingInfo->RingBuffer->ReadIndex = NextReadLocation; + RingInfo->ring_buffer->read_index = NextReadLocation; } @@ -162,7 +162,7 @@ Description: static inline void * GetRingBuffer(struct hv_ring_buffer_info *RingInfo) { - return (void *)RingInfo->RingBuffer->Buffer; + return (void *)RingInfo->ring_buffer->buffer; } @@ -178,7 +178,7 @@ Description: static inline u32 GetRingBufferSize(struct hv_ring_buffer_info *RingInfo) { - return RingInfo->RingDataSize; + return RingInfo->ring_datasize; } /*++ @@ -193,7 +193,7 @@ Description: static inline u64 GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo) { - return (u64)RingInfo->RingBuffer->WriteIndex << 32; + return (u64)RingInfo->ring_buffer->write_index << 32; } @@ -221,11 +221,11 @@ void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix) "avail read %u read idx %u write idx %u>>", Prefix, RingInfo, - RingInfo->RingBuffer->Buffer, + RingInfo->ring_buffer->buffer, bytesAvailToWrite, bytesAvailToRead, - RingInfo->RingBuffer->ReadIndex, - RingInfo->RingBuffer->WriteIndex); + RingInfo->ring_buffer->read_index, + RingInfo->ring_buffer->write_index); } @@ -262,16 +262,19 @@ void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo, u32 bytesAvailToWrite; u32 bytesAvailToRead; - if (RingInfo->RingBuffer) { + if (RingInfo->ring_buffer) { GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); - debug_info->BytesAvailToRead = bytesAvailToRead; - debug_info->BytesAvailToWrite = bytesAvailToWrite; - debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; - debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; - debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; + debug_info->bytes_avail_toread = bytesAvailToRead; + debug_info->bytes_avail_towrite = bytesAvailToWrite; + debug_info->current_read_index = + RingInfo->ring_buffer->read_index; + debug_info->current_write_index = + RingInfo->ring_buffer->write_index; + debug_info->current_interrupt_mask = + RingInfo->ring_buffer->interrupt_mask; } } @@ -287,7 +290,7 @@ Description: --*/ u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi) { - return rbi->RingBuffer->InterruptMask; + return rbi->ring_buffer->interrupt_mask; } /*++ @@ -306,11 +309,12 @@ int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 Buffe memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info)); - RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer; - RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0; + RingInfo->ring_buffer = (struct hv_ring_buffer *)Buffer; + RingInfo->ring_buffer->read_index = + RingInfo->ring_buffer->write_index = 0; - RingInfo->RingSize = BufferLen; - RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer); + RingInfo->ring_size = BufferLen; + RingInfo->ring_datasize = BufferLen - sizeof(struct hv_ring_buffer); spin_lock_init(&RingInfo->ring_lock); diff --git a/drivers/staging/hv/ring_buffer.h b/drivers/staging/hv/ring_buffer.h index a7f1717c6a56..bb4c5bc484be 100644 --- a/drivers/staging/hv/ring_buffer.h +++ b/drivers/staging/hv/ring_buffer.h @@ -29,18 +29,18 @@ struct hv_ring_buffer { /* Offset in bytes from the start of ring data below */ - volatile u32 WriteIndex; + volatile u32 write_index; /* Offset in bytes from the start of ring data below */ - volatile u32 ReadIndex; + volatile u32 read_index; - volatile u32 InterruptMask; + volatile u32 interrupt_mask; /* Pad it to PAGE_SIZE so that data starts on page boundary */ - u8 Reserved[4084]; + u8 reserved[4084]; /* NOTE: - * The InterruptMask field is used only for channels but since our + * The interrupt_mask field is used only for channels but since our * vmbus connection also uses this data structure and its data starts * here, we commented out this field. */ @@ -50,24 +50,24 @@ struct hv_ring_buffer { * Ring data starts here + RingDataStartOffset * !!! DO NOT place any fields below this !!! */ - u8 Buffer[0]; + u8 buffer[0]; } __attribute__((packed)); struct hv_ring_buffer_info { - struct hv_ring_buffer *RingBuffer; - u32 RingSize; /* Include the shared header */ + struct hv_ring_buffer *ring_buffer; + u32 ring_size; /* Include the shared header */ spinlock_t ring_lock; - u32 RingDataSize; /* < ringSize */ - u32 RingDataStartOffset; + u32 ring_datasize; /* < ring_size */ + u32 ring_data_startoffset; }; struct hv_ring_buffer_debug_info { - u32 CurrentInterruptMask; - u32 CurrentReadIndex; - u32 CurrentWriteIndex; - u32 BytesAvailToRead; - u32 BytesAvailToWrite; + u32 current_interrupt_mask; + u32 current_read_index; + u32 current_write_index; + u32 bytes_avail_toread; + u32 bytes_avail_towrite; }; diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 2bbf4ecdf550..096587592e23 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -156,18 +156,21 @@ static void get_channel_info(struct hv_device *device, info->ClientMonitorLatency = debug_info.clientmonitor_latency; info->ClientMonitorConnectionId = debug_info.clientmonitor_connectionid; - info->Inbound.InterruptMask = debug_info.inbound.CurrentInterruptMask; - info->Inbound.ReadIndex = debug_info.inbound.CurrentReadIndex; - info->Inbound.WriteIndex = debug_info.inbound.CurrentWriteIndex; - info->Inbound.BytesAvailToRead = debug_info.inbound.BytesAvailToRead; - info->Inbound.BytesAvailToWrite = debug_info.inbound.BytesAvailToWrite; - - info->Outbound.InterruptMask = debug_info.outbound.CurrentInterruptMask; - info->Outbound.ReadIndex = debug_info.outbound.CurrentReadIndex; - info->Outbound.WriteIndex = debug_info.outbound.CurrentWriteIndex; - info->Outbound.BytesAvailToRead = debug_info.outbound.BytesAvailToRead; + info->Inbound.InterruptMask = debug_info.inbound.current_interrupt_mask; + info->Inbound.ReadIndex = debug_info.inbound.current_read_index; + info->Inbound.WriteIndex = debug_info.inbound.current_write_index; + info->Inbound.BytesAvailToRead = debug_info.inbound.bytes_avail_toread; + info->Inbound.BytesAvailToWrite = + debug_info.inbound.bytes_avail_towrite; + + info->Outbound.InterruptMask = + debug_info.outbound.current_interrupt_mask; + info->Outbound.ReadIndex = debug_info.outbound.current_read_index; + info->Outbound.WriteIndex = debug_info.outbound.current_write_index; + info->Outbound.BytesAvailToRead = + debug_info.outbound.bytes_avail_toread; info->Outbound.BytesAvailToWrite = - debug_info.outbound.BytesAvailToWrite; + debug_info.outbound.bytes_avail_towrite; } /* -- cgit v1.2.3 From fc8c72ebfa7547c044bab48fb8bba6906123f8c7 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:46 -0800 Subject: staging: hv: Convert camel cased local variables in ring_buffer.c to lower cases staging: hv: Convert camel cased local variables in ring_buffer.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 4 +- drivers/staging/hv/ring_buffer.c | 337 ++++++++++++++++++++------------------- drivers/staging/hv/ring_buffer.h | 26 +-- 3 files changed, 185 insertions(+), 182 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index 0e554e91f1d8..97db545a516c 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -1052,6 +1052,6 @@ void vmbus_ontimer(unsigned long data) static void dump_vmbus_channel(struct vmbus_channel *channel) { DPRINT_DBG(VMBUS, "Channel (%d)", channel->offermsg.child_relid); - DumpRingInfo(&channel->outbound, "Outbound "); - DumpRingInfo(&channel->inbound, "Inbound "); + Dumpring_info(&channel->outbound, "Outbound "); + Dumpring_info(&channel->inbound, "Inbound "); } diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c index 6095cc5ce711..705d95f053fd 100644 --- a/drivers/staging/hv/ring_buffer.c +++ b/drivers/staging/hv/ring_buffer.c @@ -68,11 +68,11 @@ Description: --*/ static inline u32 -GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo) +GetNextWriteLocation(struct hv_ring_buffer_info *ring_info) { - u32 next = RingInfo->ring_buffer->write_index; + u32 next = ring_info->ring_buffer->write_index; - /* ASSERT(next < RingInfo->RingDataSize); */ + /* ASSERT(next < ring_info->RingDataSize); */ return next; } @@ -87,10 +87,10 @@ Description: --*/ static inline void -SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo, - u32 NextWriteLocation) +SetNextWriteLocation(struct hv_ring_buffer_info *ring_info, + u32 next_write_location) { - RingInfo->ring_buffer->write_index = NextWriteLocation; + ring_info->ring_buffer->write_index = next_write_location; } /*++ @@ -103,11 +103,11 @@ Description: --*/ static inline u32 -GetNextReadLocation(struct hv_ring_buffer_info *RingInfo) +GetNextReadLocation(struct hv_ring_buffer_info *ring_info) { - u32 next = RingInfo->ring_buffer->read_index; + u32 next = ring_info->ring_buffer->read_index; - /* ASSERT(next < RingInfo->RingDataSize); */ + /* ASSERT(next < ring_info->RingDataSize); */ return next; } @@ -123,13 +123,13 @@ Description: --*/ static inline u32 -GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset) +GetNextReadLocationWithOffset(struct hv_ring_buffer_info *ring_info, u32 offset) { - u32 next = RingInfo->ring_buffer->read_index; + u32 next = ring_info->ring_buffer->read_index; - /* ASSERT(next < RingInfo->RingDataSize); */ - next += Offset; - next %= RingInfo->ring_datasize; + /* ASSERT(next < ring_info->RingDataSize); */ + next += offset; + next %= ring_info->ring_datasize; return next; } @@ -144,9 +144,10 @@ Description: --*/ static inline void -SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation) +SetNextReadLocation(struct hv_ring_buffer_info *ring_info, + u32 next_read_location) { - RingInfo->ring_buffer->read_index = NextReadLocation; + ring_info->ring_buffer->read_index = next_read_location; } @@ -160,9 +161,9 @@ Description: --*/ static inline void * -GetRingBuffer(struct hv_ring_buffer_info *RingInfo) +GetRingBuffer(struct hv_ring_buffer_info *ring_info) { - return (void *)RingInfo->ring_buffer->buffer; + return (void *)ring_info->ring_buffer->buffer; } @@ -176,9 +177,9 @@ Description: --*/ static inline u32 -GetRingBufferSize(struct hv_ring_buffer_info *RingInfo) +GetRingBufferSize(struct hv_ring_buffer_info *ring_info) { - return RingInfo->ring_datasize; + return ring_info->ring_datasize; } /*++ @@ -191,41 +192,41 @@ Description: --*/ static inline u64 -GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo) +GetRingBufferIndices(struct hv_ring_buffer_info *ring_info) { - return (u64)RingInfo->ring_buffer->write_index << 32; + return (u64)ring_info->ring_buffer->write_index << 32; } /*++ Name: - DumpRingInfo() + Dumpring_info() Description: Dump out to console the ring buffer info --*/ -void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix) +void Dumpring_info(struct hv_ring_buffer_info *ring_info, char *prefix) { - u32 bytesAvailToWrite; - u32 bytesAvailToRead; + u32 bytes_avail_towrite; + u32 bytes_avail_toread; - GetRingBufferAvailBytes(RingInfo, - &bytesAvailToRead, - &bytesAvailToWrite); + GetRingBufferAvailBytes(ring_info, + &bytes_avail_toread, + &bytes_avail_towrite); DPRINT(VMBUS, DEBUG_RING_LVL, "%s <>", - Prefix, - RingInfo, - RingInfo->ring_buffer->buffer, - bytesAvailToWrite, - bytesAvailToRead, - RingInfo->ring_buffer->read_index, - RingInfo->ring_buffer->write_index); + prefix, + ring_info, + ring_info->ring_buffer->buffer, + bytes_avail_towrite, + bytes_avail_toread, + ring_info->ring_buffer->read_index, + ring_info->ring_buffer->write_index); } @@ -233,17 +234,17 @@ void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix) static u32 CopyToRingBuffer( - struct hv_ring_buffer_info *RingInfo, - u32 StartWriteOffset, - void *Src, - u32 SrcLen); + struct hv_ring_buffer_info *ring_info, + u32 start_write_offset, + void *src, + u32 srclen); static u32 CopyFromRingBuffer( - struct hv_ring_buffer_info *RingInfo, - void *Dest, - u32 DestLen, - u32 StartReadOffset); + struct hv_ring_buffer_info *ring_info, + void *dest, + u32 destlen, + u32 start_read_offset); @@ -256,25 +257,25 @@ Description: Get various debug metrics for the specified ring buffer --*/ -void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo, +void RingBufferGetDebugInfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info) { - u32 bytesAvailToWrite; - u32 bytesAvailToRead; + u32 bytes_avail_towrite; + u32 bytes_avail_toread; - if (RingInfo->ring_buffer) { - GetRingBufferAvailBytes(RingInfo, - &bytesAvailToRead, - &bytesAvailToWrite); + if (ring_info->ring_buffer) { + GetRingBufferAvailBytes(ring_info, + &bytes_avail_toread, + &bytes_avail_towrite); - debug_info->bytes_avail_toread = bytesAvailToRead; - debug_info->bytes_avail_towrite = bytesAvailToWrite; + debug_info->bytes_avail_toread = bytes_avail_toread; + debug_info->bytes_avail_towrite = bytes_avail_towrite; debug_info->current_read_index = - RingInfo->ring_buffer->read_index; + ring_info->ring_buffer->read_index; debug_info->current_write_index = - RingInfo->ring_buffer->write_index; + ring_info->ring_buffer->write_index; debug_info->current_interrupt_mask = - RingInfo->ring_buffer->interrupt_mask; + ring_info->ring_buffer->interrupt_mask; } } @@ -302,21 +303,22 @@ Description: Initialize the ring buffer --*/ -int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen) +int RingBufferInit(struct hv_ring_buffer_info *ring_info, + void *buffer, u32 buflen) { if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) return -EINVAL; - memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info)); + memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); - RingInfo->ring_buffer = (struct hv_ring_buffer *)Buffer; - RingInfo->ring_buffer->read_index = - RingInfo->ring_buffer->write_index = 0; + ring_info->ring_buffer = (struct hv_ring_buffer *)buffer; + ring_info->ring_buffer->read_index = + ring_info->ring_buffer->write_index = 0; - RingInfo->ring_size = BufferLen; - RingInfo->ring_datasize = BufferLen - sizeof(struct hv_ring_buffer); + ring_info->ring_size = buflen; + ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); - spin_lock_init(&RingInfo->ring_lock); + spin_lock_init(&ring_info->ring_lock); return 0; } @@ -330,7 +332,7 @@ Description: Cleanup the ring buffer --*/ -void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo) +void RingBufferCleanup(struct hv_ring_buffer_info *ring_info) { } @@ -343,78 +345,78 @@ Description: Write to the ring buffer --*/ -int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo, +int RingBufferWrite(struct hv_ring_buffer_info *outring_info, struct scatterlist *sglist, u32 sgcount) { int i = 0; - u32 byteAvailToWrite; - u32 byteAvailToRead; - u32 totalBytesToWrite = 0; + u32 bytes_avail_towrite; + u32 bytes_avail_toread; + u32 totalbytes_towrite = 0; struct scatterlist *sg; - volatile u32 nextWriteLocation; - u64 prevIndices = 0; + volatile u32 next_write_location; + u64 prev_indices = 0; unsigned long flags; for_each_sg(sglist, sg, sgcount, i) { - totalBytesToWrite += sg->length; + totalbytes_towrite += sg->length; } - totalBytesToWrite += sizeof(u64); + totalbytes_towrite += sizeof(u64); - spin_lock_irqsave(&OutRingInfo->ring_lock, flags); + spin_lock_irqsave(&outring_info->ring_lock, flags); - GetRingBufferAvailBytes(OutRingInfo, - &byteAvailToRead, - &byteAvailToWrite); + GetRingBufferAvailBytes(outring_info, + &bytes_avail_toread, + &bytes_avail_towrite); - DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); + DPRINT_DBG(VMBUS, "Writing %u bytes...", totalbytes_towrite); - /* DumpRingInfo(OutRingInfo, "BEFORE "); */ + /* Dumpring_info(Outring_info, "BEFORE "); */ /* If there is only room for the packet, assume it is full. */ /* Otherwise, the next time around, we think the ring buffer */ /* is empty since the read index == write index */ - if (byteAvailToWrite <= totalBytesToWrite) { + if (bytes_avail_towrite <= totalbytes_towrite) { DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer " "(needed %u, avail %u)", - totalBytesToWrite, - byteAvailToWrite); + totalbytes_towrite, + bytes_avail_towrite); - spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); + spin_unlock_irqrestore(&outring_info->ring_lock, flags); return -1; } /* Write to the ring buffer */ - nextWriteLocation = GetNextWriteLocation(OutRingInfo); + next_write_location = GetNextWriteLocation(outring_info); for_each_sg(sglist, sg, sgcount, i) { - nextWriteLocation = CopyToRingBuffer(OutRingInfo, - nextWriteLocation, + next_write_location = CopyToRingBuffer(outring_info, + next_write_location, sg_virt(sg), sg->length); } /* Set previous packet start */ - prevIndices = GetRingBufferIndices(OutRingInfo); + prev_indices = GetRingBufferIndices(outring_info); - nextWriteLocation = CopyToRingBuffer(OutRingInfo, - nextWriteLocation, - &prevIndices, + next_write_location = CopyToRingBuffer(outring_info, + next_write_location, + &prev_indices, sizeof(u64)); /* Make sure we flush all writes before updating the writeIndex */ mb(); /* Now, update the write location */ - SetNextWriteLocation(OutRingInfo, nextWriteLocation); + SetNextWriteLocation(outring_info, next_write_location); - /* DumpRingInfo(OutRingInfo, "AFTER "); */ + /* Dumpring_info(Outring_info, "AFTER "); */ - spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); + spin_unlock_irqrestore(&outring_info->ring_lock, flags); return 0; } @@ -428,41 +430,42 @@ Description: Read without advancing the read index --*/ -int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen) +int RingBufferPeek(struct hv_ring_buffer_info *Inring_info, + void *Buffer, u32 buflen) { - u32 bytesAvailToWrite; - u32 bytesAvailToRead; - u32 nextReadLocation = 0; + u32 bytes_avail_towrite; + u32 bytes_avail_toread; + u32 next_read_location = 0; unsigned long flags; - spin_lock_irqsave(&InRingInfo->ring_lock, flags); + spin_lock_irqsave(&Inring_info->ring_lock, flags); - GetRingBufferAvailBytes(InRingInfo, - &bytesAvailToRead, - &bytesAvailToWrite); + GetRingBufferAvailBytes(Inring_info, + &bytes_avail_toread, + &bytes_avail_towrite); /* Make sure there is something to read */ - if (bytesAvailToRead < BufferLen) { + if (bytes_avail_toread < buflen) { /* DPRINT_DBG(VMBUS, "got callback but not enough to read " "!!", - bytesAvailToRead, + bytes_avail_toread, BufferLen); */ - spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); + spin_unlock_irqrestore(&Inring_info->ring_lock, flags); return -1; } /* Convert to byte offset */ - nextReadLocation = GetNextReadLocation(InRingInfo); + next_read_location = GetNextReadLocation(Inring_info); - nextReadLocation = CopyFromRingBuffer(InRingInfo, + next_read_location = CopyFromRingBuffer(Inring_info, Buffer, - BufferLen, - nextReadLocation); + buflen, + next_read_location); - spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); + spin_unlock_irqrestore(&Inring_info->ring_lock, flags); return 0; } @@ -477,52 +480,52 @@ Description: Read and advance the read index --*/ -int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer, - u32 BufferLen, u32 Offset) +int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, + u32 buflen, u32 offset) { - u32 bytesAvailToWrite; - u32 bytesAvailToRead; - u32 nextReadLocation = 0; - u64 prevIndices = 0; + u32 bytes_avail_towrite; + u32 bytes_avail_toread; + u32 next_read_location = 0; + u64 prev_indices = 0; unsigned long flags; - if (BufferLen <= 0) + if (buflen <= 0) return -EINVAL; - spin_lock_irqsave(&InRingInfo->ring_lock, flags); + spin_lock_irqsave(&inring_info->ring_lock, flags); - GetRingBufferAvailBytes(InRingInfo, - &bytesAvailToRead, - &bytesAvailToWrite); + GetRingBufferAvailBytes(inring_info, + &bytes_avail_toread, + &bytes_avail_towrite); - DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); + DPRINT_DBG(VMBUS, "Reading %u bytes...", buflen); - /* DumpRingInfo(InRingInfo, "BEFORE "); */ + /* Dumpring_info(Inring_info, "BEFORE "); */ /* Make sure there is something to read */ - if (bytesAvailToRead < BufferLen) { + if (bytes_avail_toread < buflen) { DPRINT_DBG(VMBUS, "got callback but not enough to read " "!!", - bytesAvailToRead, - BufferLen); + bytes_avail_toread, + buflen); - spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); + spin_unlock_irqrestore(&inring_info->ring_lock, flags); return -1; } - nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); + next_read_location = GetNextReadLocationWithOffset(inring_info, offset); - nextReadLocation = CopyFromRingBuffer(InRingInfo, - Buffer, - BufferLen, - nextReadLocation); + next_read_location = CopyFromRingBuffer(inring_info, + buffer, + buflen, + next_read_location); - nextReadLocation = CopyFromRingBuffer(InRingInfo, - &prevIndices, + next_read_location = CopyFromRingBuffer(inring_info, + &prev_indices, sizeof(u64), - nextReadLocation); + next_read_location); /* Make sure all reads are done before we update the read index since */ /* the writer may start writing to the read area once the read index */ @@ -530,11 +533,11 @@ int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer, mb(); /* Update the read index */ - SetNextReadLocation(InRingInfo, nextReadLocation); + SetNextReadLocation(inring_info, next_read_location); - /* DumpRingInfo(InRingInfo, "AFTER "); */ + /* Dumpring_info(Inring_info, "AFTER "); */ - spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); + spin_unlock_irqrestore(&inring_info->ring_lock, flags); return 0; } @@ -552,29 +555,29 @@ Description: --*/ static u32 CopyToRingBuffer( - struct hv_ring_buffer_info *RingInfo, - u32 StartWriteOffset, - void *Src, - u32 SrcLen) + struct hv_ring_buffer_info *ring_info, + u32 start_write_offset, + void *src, + u32 srclen) { - void *ringBuffer = GetRingBuffer(RingInfo); - u32 ringBufferSize = GetRingBufferSize(RingInfo); - u32 fragLen; + void *ring_buffer = GetRingBuffer(ring_info); + u32 ring_buffer_size = GetRingBufferSize(ring_info); + u32 frag_len; /* wrap-around detected! */ - if (SrcLen > ringBufferSize - StartWriteOffset) { + if (srclen > ring_buffer_size - start_write_offset) { DPRINT_DBG(VMBUS, "wrap-around detected!"); - fragLen = ringBufferSize - StartWriteOffset; - memcpy(ringBuffer + StartWriteOffset, Src, fragLen); - memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen); + frag_len = ring_buffer_size - start_write_offset; + memcpy(ring_buffer + start_write_offset, src, frag_len); + memcpy(ring_buffer, src + frag_len, srclen - frag_len); } else - memcpy(ringBuffer + StartWriteOffset, Src, SrcLen); + memcpy(ring_buffer + start_write_offset, src, srclen); - StartWriteOffset += SrcLen; - StartWriteOffset %= ringBufferSize; + start_write_offset += srclen; + start_write_offset %= ring_buffer_size; - return StartWriteOffset; + return start_write_offset; } @@ -590,33 +593,33 @@ Description: --*/ static u32 CopyFromRingBuffer( - struct hv_ring_buffer_info *RingInfo, - void *Dest, - u32 DestLen, - u32 StartReadOffset) + struct hv_ring_buffer_info *ring_info, + void *dest, + u32 destlen, + u32 start_read_offset) { - void *ringBuffer = GetRingBuffer(RingInfo); - u32 ringBufferSize = GetRingBufferSize(RingInfo); + void *ring_buffer = GetRingBuffer(ring_info); + u32 ring_buffer_size = GetRingBufferSize(ring_info); - u32 fragLen; + u32 frag_len; /* wrap-around detected at the src */ - if (DestLen > ringBufferSize - StartReadOffset) { + if (destlen > ring_buffer_size - start_read_offset) { DPRINT_DBG(VMBUS, "src wrap-around detected!"); - fragLen = ringBufferSize - StartReadOffset; + frag_len = ring_buffer_size - start_read_offset; - memcpy(Dest, ringBuffer + StartReadOffset, fragLen); - memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen); + memcpy(dest, ring_buffer + start_read_offset, frag_len); + memcpy(dest + frag_len, ring_buffer, destlen - frag_len); } else - memcpy(Dest, ringBuffer + StartReadOffset, DestLen); + memcpy(dest, ring_buffer + start_read_offset, destlen); - StartReadOffset += DestLen; - StartReadOffset %= ringBufferSize; + start_read_offset += destlen; + start_read_offset %= ring_buffer_size; - return StartReadOffset; + return start_read_offset; } diff --git a/drivers/staging/hv/ring_buffer.h b/drivers/staging/hv/ring_buffer.h index bb4c5bc484be..f30be1fa0744 100644 --- a/drivers/staging/hv/ring_buffer.h +++ b/drivers/staging/hv/ring_buffer.h @@ -75,28 +75,28 @@ struct hv_ring_buffer_debug_info { /* Interface */ -int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, - u32 BufferLen); +int RingBufferInit(struct hv_ring_buffer_info *ring_info, void *buffer, + u32 buflen); -void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo); +void RingBufferCleanup(struct hv_ring_buffer_info *ring_info); -int RingBufferWrite(struct hv_ring_buffer_info *RingInfo, +int RingBufferWrite(struct hv_ring_buffer_info *ring_info, struct scatterlist *sglist, u32 sgcount); -int RingBufferPeek(struct hv_ring_buffer_info *RingInfo, void *Buffer, - u32 BufferLen); +int RingBufferPeek(struct hv_ring_buffer_info *ring_info, void *buffer, + u32 buflen); -int RingBufferRead(struct hv_ring_buffer_info *RingInfo, - void *Buffer, - u32 BufferLen, - u32 Offset); +int RingBufferRead(struct hv_ring_buffer_info *ring_info, + void *buffer, + u32 buflen, + u32 offset); -u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *RingInfo); +u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *ring_info); -void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix); +void Dumpring_info(struct hv_ring_buffer_info *ring_info, char *prefix); -void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo, +void RingBufferGetDebugInfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info); #endif /* _RING_BUFFER_H_ */ -- cgit v1.2.3 From 1ac586445db8e46f0007855c5c7161ff55484836 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 8 Nov 2010 14:04:47 -0800 Subject: staging: hv: Convert camel cased functions in ring_buffer.c to lower cases staging: hv: Convert camel cased functions in ring_buffer.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 40 ++++++------- drivers/staging/hv/ring_buffer.c | 123 ++++++++++++++++++++------------------- drivers/staging/hv/ring_buffer.h | 16 ++--- 3 files changed, 91 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index 97db545a516c..45a627d77b41 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -155,8 +155,8 @@ void vmbus_get_debug_info(struct vmbus_channel *channel, monitorpage->parameter[monitor_group] [monitor_offset].connectionid.u.id; - RingBufferGetDebugInfo(&channel->inbound, &debuginfo->inbound); - RingBufferGetDebugInfo(&channel->outbound, &debuginfo->outbound); + ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound); + ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound); } /* @@ -193,13 +193,13 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, newchannel->ringbuffer_pagecount = (send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT; - ret = RingBufferInit(&newchannel->outbound, out, send_ringbuffer_size); + ret = ringbuffer_init(&newchannel->outbound, out, send_ringbuffer_size); if (ret != 0) { err = ret; goto errorout; } - ret = RingBufferInit(&newchannel->inbound, in, recv_ringbuffer_size); + ret = ringbuffer_init(&newchannel->inbound, in, recv_ringbuffer_size); if (ret != 0) { err = ret; goto errorout; @@ -298,8 +298,8 @@ Cleanup: return 0; errorout: - RingBufferCleanup(&newchannel->outbound); - RingBufferCleanup(&newchannel->inbound); + ringbuffer_cleanup(&newchannel->outbound); + ringbuffer_cleanup(&newchannel->inbound); osd_page_free(out, (send_ringbuffer_size + recv_ringbuffer_size) >> PAGE_SHIFT); kfree(openInfo); @@ -683,8 +683,8 @@ void vmbus_close(struct vmbus_channel *channel) /* TODO: Send a msg to release the childRelId */ /* Cleanup the ring buffers for this channel */ - RingBufferCleanup(&channel->outbound); - RingBufferCleanup(&channel->inbound); + ringbuffer_cleanup(&channel->outbound); + ringbuffer_cleanup(&channel->inbound); osd_page_free(channel->ringbuffer_pages, channel->ringbuffer_pagecount); @@ -752,10 +752,10 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer, sg_set_buf(&bufferlist[2], &aligned_data, packetlen_aligned - packetlen); - ret = RingBufferWrite(&channel->outbound, bufferlist, 3); + ret = ringbuffer_write(&channel->outbound, bufferlist, 3); /* TODO: We should determine if this is optional */ - if (ret == 0 && !GetRingBufferInterruptMask(&channel->outbound)) + if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound)) vmbus_setevent(channel); return ret; @@ -817,10 +817,10 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, sg_set_buf(&bufferlist[2], &aligned_data, packetlen_aligned - packetlen); - ret = RingBufferWrite(&channel->outbound, bufferlist, 3); + ret = ringbuffer_write(&channel->outbound, bufferlist, 3); /* TODO: We should determine if this is optional */ - if (ret == 0 && !GetRingBufferInterruptMask(&channel->outbound)) + if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound)) vmbus_setevent(channel); return ret; @@ -886,10 +886,10 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, sg_set_buf(&bufferlist[2], &aligned_data, packetlen_aligned - packetlen); - ret = RingBufferWrite(&channel->outbound, bufferlist, 3); + ret = ringbuffer_write(&channel->outbound, bufferlist, 3); /* TODO: We should determine if this is optional */ - if (ret == 0 && !GetRingBufferInterruptMask(&channel->outbound)) + if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound)) vmbus_setevent(channel); return ret; @@ -923,7 +923,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, spin_lock_irqsave(&channel->inbound_lock, flags); - ret = RingBufferPeek(&channel->inbound, &desc, + ret = ringbuffer_peek(&channel->inbound, &desc, sizeof(struct vmpacket_descriptor)); if (ret != 0) { spin_unlock_irqrestore(&channel->inbound_lock, flags); @@ -956,7 +956,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, *requestid = desc.TransactionId; /* Copy over the packet to the user buffer */ - ret = RingBufferRead(&channel->inbound, buffer, userlen, + ret = ringbuffer_read(&channel->inbound, buffer, userlen, (desc.DataOffset8 << 3)); spin_unlock_irqrestore(&channel->inbound_lock, flags); @@ -983,7 +983,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, spin_lock_irqsave(&channel->inbound_lock, flags); - ret = RingBufferPeek(&channel->inbound, &desc, + ret = ringbuffer_peek(&channel->inbound, &desc, sizeof(struct vmpacket_descriptor)); if (ret != 0) { spin_unlock_irqrestore(&channel->inbound_lock, flags); @@ -1015,7 +1015,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, *requestid = desc.TransactionId; /* Copy over the entire packet to the user buffer */ - ret = RingBufferRead(&channel->inbound, buffer, packetlen, 0); + ret = ringbuffer_read(&channel->inbound, buffer, packetlen, 0); spin_unlock_irqrestore(&channel->inbound_lock, flags); return 0; @@ -1052,6 +1052,6 @@ void vmbus_ontimer(unsigned long data) static void dump_vmbus_channel(struct vmbus_channel *channel) { DPRINT_DBG(VMBUS, "Channel (%d)", channel->offermsg.child_relid); - Dumpring_info(&channel->outbound, "Outbound "); - Dumpring_info(&channel->inbound, "Inbound "); + dump_ring_info(&channel->outbound, "Outbound "); + dump_ring_info(&channel->inbound, "Inbound "); } diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c index 705d95f053fd..4d53392f1e60 100644 --- a/drivers/staging/hv/ring_buffer.c +++ b/drivers/staging/hv/ring_buffer.c @@ -38,7 +38,7 @@ /*++ Name: - GetRingBufferAvailBytes() + get_ringbuffer_availbytes() Description: Get number of bytes available to read and to write to @@ -46,7 +46,8 @@ Description: --*/ static inline void -GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write) +get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, + u32 *read, u32 *write) { u32 read_loc, write_loc; @@ -61,14 +62,14 @@ GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write) /*++ Name: - GetNextWriteLocation() + get_next_write_location() Description: Get the next write location for the specified ring buffer --*/ static inline u32 -GetNextWriteLocation(struct hv_ring_buffer_info *ring_info) +get_next_write_location(struct hv_ring_buffer_info *ring_info) { u32 next = ring_info->ring_buffer->write_index; @@ -80,14 +81,14 @@ GetNextWriteLocation(struct hv_ring_buffer_info *ring_info) /*++ Name: - SetNextWriteLocation() + set_next_write_location() Description: Set the next write location for the specified ring buffer --*/ static inline void -SetNextWriteLocation(struct hv_ring_buffer_info *ring_info, +set_next_write_location(struct hv_ring_buffer_info *ring_info, u32 next_write_location) { ring_info->ring_buffer->write_index = next_write_location; @@ -96,14 +97,14 @@ SetNextWriteLocation(struct hv_ring_buffer_info *ring_info, /*++ Name: - GetNextReadLocation() + get_next_read_location() Description: Get the next read location for the specified ring buffer --*/ static inline u32 -GetNextReadLocation(struct hv_ring_buffer_info *ring_info) +get_next_read_location(struct hv_ring_buffer_info *ring_info) { u32 next = ring_info->ring_buffer->read_index; @@ -115,7 +116,7 @@ GetNextReadLocation(struct hv_ring_buffer_info *ring_info) /*++ Name: - GetNextReadLocationWithOffset() + get_next_readlocation_withoffset() Description: Get the next read location + offset for the specified ring buffer. @@ -123,7 +124,8 @@ Description: --*/ static inline u32 -GetNextReadLocationWithOffset(struct hv_ring_buffer_info *ring_info, u32 offset) +get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info, + u32 offset) { u32 next = ring_info->ring_buffer->read_index; @@ -137,14 +139,14 @@ GetNextReadLocationWithOffset(struct hv_ring_buffer_info *ring_info, u32 offset) /*++ Name: - SetNextReadLocation() + set_next_read_location() Description: Set the next read location for the specified ring buffer --*/ static inline void -SetNextReadLocation(struct hv_ring_buffer_info *ring_info, +set_next_read_location(struct hv_ring_buffer_info *ring_info, u32 next_read_location) { ring_info->ring_buffer->read_index = next_read_location; @@ -154,14 +156,14 @@ SetNextReadLocation(struct hv_ring_buffer_info *ring_info, /*++ Name: - GetRingBuffer() + get_ring_buffer() Description: Get the start of the ring buffer --*/ static inline void * -GetRingBuffer(struct hv_ring_buffer_info *ring_info) +get_ring_buffer(struct hv_ring_buffer_info *ring_info) { return (void *)ring_info->ring_buffer->buffer; } @@ -170,14 +172,14 @@ GetRingBuffer(struct hv_ring_buffer_info *ring_info) /*++ Name: - GetRingBufferSize() + get_ring_buffersize() Description: Get the size of the ring buffer --*/ static inline u32 -GetRingBufferSize(struct hv_ring_buffer_info *ring_info) +get_ring_buffersize(struct hv_ring_buffer_info *ring_info) { return ring_info->ring_datasize; } @@ -185,14 +187,14 @@ GetRingBufferSize(struct hv_ring_buffer_info *ring_info) /*++ Name: - GetRingBufferIndices() + get_ring_bufferindices() Description: Get the read and write indices as u64 of the specified ring buffer --*/ static inline u64 -GetRingBufferIndices(struct hv_ring_buffer_info *ring_info) +get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) { return (u64)ring_info->ring_buffer->write_index << 32; } @@ -201,18 +203,18 @@ GetRingBufferIndices(struct hv_ring_buffer_info *ring_info) /*++ Name: - Dumpring_info() + dump_ring_info() Description: Dump out to console the ring buffer info --*/ -void Dumpring_info(struct hv_ring_buffer_info *ring_info, char *prefix) +void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix) { u32 bytes_avail_towrite; u32 bytes_avail_toread; - GetRingBufferAvailBytes(ring_info, + get_ringbuffer_availbytes(ring_info, &bytes_avail_toread, &bytes_avail_towrite); @@ -233,14 +235,14 @@ void Dumpring_info(struct hv_ring_buffer_info *ring_info, char *prefix) /* Internal routines */ static u32 -CopyToRingBuffer( +copyto_ringbuffer( struct hv_ring_buffer_info *ring_info, u32 start_write_offset, void *src, u32 srclen); static u32 -CopyFromRingBuffer( +copyfrom_ringbuffer( struct hv_ring_buffer_info *ring_info, void *dest, u32 destlen, @@ -251,20 +253,20 @@ CopyFromRingBuffer( /*++ Name: - RingBufferGetDebugInfo() + ringbuffer_get_debuginfo() Description: Get various debug metrics for the specified ring buffer --*/ -void RingBufferGetDebugInfo(struct hv_ring_buffer_info *ring_info, +void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info) { u32 bytes_avail_towrite; u32 bytes_avail_toread; if (ring_info->ring_buffer) { - GetRingBufferAvailBytes(ring_info, + get_ringbuffer_availbytes(ring_info, &bytes_avail_toread, &bytes_avail_towrite); @@ -283,13 +285,13 @@ void RingBufferGetDebugInfo(struct hv_ring_buffer_info *ring_info, /*++ Name: - GetRingBufferInterruptMask() + get_ringbuffer_interrupt_mask() Description: Get the interrupt mask for the specified ring buffer --*/ -u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi) +u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi) { return rbi->ring_buffer->interrupt_mask; } @@ -297,13 +299,13 @@ u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi) /*++ Name: - RingBufferInit() + ringbuffer_init() Description: Initialize the ring buffer --*/ -int RingBufferInit(struct hv_ring_buffer_info *ring_info, +int ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer, u32 buflen) { if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) @@ -326,26 +328,26 @@ int RingBufferInit(struct hv_ring_buffer_info *ring_info, /*++ Name: - RingBufferCleanup() + ringbuffer_cleanup() Description: Cleanup the ring buffer --*/ -void RingBufferCleanup(struct hv_ring_buffer_info *ring_info) +void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) { } /*++ Name: - RingBufferWrite() + ringbuffer_write() Description: Write to the ring buffer --*/ -int RingBufferWrite(struct hv_ring_buffer_info *outring_info, +int ringbuffer_write(struct hv_ring_buffer_info *outring_info, struct scatterlist *sglist, u32 sgcount) { int i = 0; @@ -367,7 +369,7 @@ int RingBufferWrite(struct hv_ring_buffer_info *outring_info, spin_lock_irqsave(&outring_info->ring_lock, flags); - GetRingBufferAvailBytes(outring_info, + get_ringbuffer_availbytes(outring_info, &bytes_avail_toread, &bytes_avail_towrite); @@ -390,20 +392,20 @@ int RingBufferWrite(struct hv_ring_buffer_info *outring_info, } /* Write to the ring buffer */ - next_write_location = GetNextWriteLocation(outring_info); + next_write_location = get_next_write_location(outring_info); for_each_sg(sglist, sg, sgcount, i) { - next_write_location = CopyToRingBuffer(outring_info, + next_write_location = copyto_ringbuffer(outring_info, next_write_location, sg_virt(sg), sg->length); } /* Set previous packet start */ - prev_indices = GetRingBufferIndices(outring_info); + prev_indices = get_ring_bufferindices(outring_info); - next_write_location = CopyToRingBuffer(outring_info, + next_write_location = copyto_ringbuffer(outring_info, next_write_location, &prev_indices, sizeof(u64)); @@ -412,7 +414,7 @@ int RingBufferWrite(struct hv_ring_buffer_info *outring_info, mb(); /* Now, update the write location */ - SetNextWriteLocation(outring_info, next_write_location); + set_next_write_location(outring_info, next_write_location); /* Dumpring_info(Outring_info, "AFTER "); */ @@ -424,13 +426,13 @@ int RingBufferWrite(struct hv_ring_buffer_info *outring_info, /*++ Name: - RingBufferPeek() + ringbuffer_peek() Description: Read without advancing the read index --*/ -int RingBufferPeek(struct hv_ring_buffer_info *Inring_info, +int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info, void *Buffer, u32 buflen) { u32 bytes_avail_towrite; @@ -440,7 +442,7 @@ int RingBufferPeek(struct hv_ring_buffer_info *Inring_info, spin_lock_irqsave(&Inring_info->ring_lock, flags); - GetRingBufferAvailBytes(Inring_info, + get_ringbuffer_availbytes(Inring_info, &bytes_avail_toread, &bytes_avail_towrite); @@ -458,9 +460,9 @@ int RingBufferPeek(struct hv_ring_buffer_info *Inring_info, } /* Convert to byte offset */ - next_read_location = GetNextReadLocation(Inring_info); + next_read_location = get_next_read_location(Inring_info); - next_read_location = CopyFromRingBuffer(Inring_info, + next_read_location = copyfrom_ringbuffer(Inring_info, Buffer, buflen, next_read_location); @@ -474,13 +476,13 @@ int RingBufferPeek(struct hv_ring_buffer_info *Inring_info, /*++ Name: - RingBufferRead() + ringbuffer_read() Description: Read and advance the read index --*/ -int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, +int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 offset) { u32 bytes_avail_towrite; @@ -494,7 +496,7 @@ int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, spin_lock_irqsave(&inring_info->ring_lock, flags); - GetRingBufferAvailBytes(inring_info, + get_ringbuffer_availbytes(inring_info, &bytes_avail_toread, &bytes_avail_towrite); @@ -515,14 +517,15 @@ int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, return -1; } - next_read_location = GetNextReadLocationWithOffset(inring_info, offset); + next_read_location = + get_next_readlocation_withoffset(inring_info, offset); - next_read_location = CopyFromRingBuffer(inring_info, + next_read_location = copyfrom_ringbuffer(inring_info, buffer, buflen, next_read_location); - next_read_location = CopyFromRingBuffer(inring_info, + next_read_location = copyfrom_ringbuffer(inring_info, &prev_indices, sizeof(u64), next_read_location); @@ -533,7 +536,7 @@ int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, mb(); /* Update the read index */ - SetNextReadLocation(inring_info, next_read_location); + set_next_read_location(inring_info, next_read_location); /* Dumpring_info(Inring_info, "AFTER "); */ @@ -546,7 +549,7 @@ int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, /*++ Name: - CopyToRingBuffer() + copyto_ringbuffer() Description: Helper routine to copy from source to ring buffer. @@ -554,14 +557,14 @@ Description: --*/ static u32 -CopyToRingBuffer( +copyto_ringbuffer( struct hv_ring_buffer_info *ring_info, u32 start_write_offset, void *src, u32 srclen) { - void *ring_buffer = GetRingBuffer(ring_info); - u32 ring_buffer_size = GetRingBufferSize(ring_info); + void *ring_buffer = get_ring_buffer(ring_info); + u32 ring_buffer_size = get_ring_buffersize(ring_info); u32 frag_len; /* wrap-around detected! */ @@ -584,7 +587,7 @@ CopyToRingBuffer( /*++ Name: - CopyFromRingBuffer() + copyfrom_ringbuffer() Description: Helper routine to copy to source from ring buffer. @@ -592,14 +595,14 @@ Description: --*/ static u32 -CopyFromRingBuffer( +copyfrom_ringbuffer( struct hv_ring_buffer_info *ring_info, void *dest, u32 destlen, u32 start_read_offset) { - void *ring_buffer = GetRingBuffer(ring_info); - u32 ring_buffer_size = GetRingBufferSize(ring_info); + void *ring_buffer = get_ring_buffer(ring_info); + u32 ring_buffer_size = get_ring_buffersize(ring_info); u32 frag_len; diff --git a/drivers/staging/hv/ring_buffer.h b/drivers/staging/hv/ring_buffer.h index f30be1fa0744..7bd6ecf2f015 100644 --- a/drivers/staging/hv/ring_buffer.h +++ b/drivers/staging/hv/ring_buffer.h @@ -75,28 +75,28 @@ struct hv_ring_buffer_debug_info { /* Interface */ -int RingBufferInit(struct hv_ring_buffer_info *ring_info, void *buffer, +int ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer, u32 buflen); -void RingBufferCleanup(struct hv_ring_buffer_info *ring_info); +void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); -int RingBufferWrite(struct hv_ring_buffer_info *ring_info, +int ringbuffer_write(struct hv_ring_buffer_info *ring_info, struct scatterlist *sglist, u32 sgcount); -int RingBufferPeek(struct hv_ring_buffer_info *ring_info, void *buffer, +int ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer, u32 buflen); -int RingBufferRead(struct hv_ring_buffer_info *ring_info, +int ringbuffer_read(struct hv_ring_buffer_info *ring_info, void *buffer, u32 buflen, u32 offset); -u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *ring_info); +u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *ring_info); -void Dumpring_info(struct hv_ring_buffer_info *ring_info, char *prefix); +void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix); -void RingBufferGetDebugInfo(struct hv_ring_buffer_info *ring_info, +void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info); #endif /* _RING_BUFFER_H_ */ -- cgit v1.2.3 From 6ccb5d7c62845788be9aafef26132333a07708bb Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Mon, 8 Nov 2010 13:41:46 -0800 Subject: staging: Fix typos in rt2860 Here is a patch that fixes some typos, and comments in drivers/staging/rt2860 Signed-off-by: Justin P. Mattock Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/chip/mac_pci.h | 7 ++-- drivers/staging/rt2860/chip/mac_usb.h | 5 ++- drivers/staging/rt2860/chip/rtmp_mac.h | 19 +++++----- drivers/staging/rt2860/chips/rt3090.c | 5 ++- drivers/staging/rt2860/chips/rt30xx.c | 9 +++-- drivers/staging/rt2860/mlme.h | 41 ++++++++++---------- drivers/staging/rt2860/oid.h | 13 ++++--- drivers/staging/rt2860/pci_main_dev.c | 17 +++++---- drivers/staging/rt2860/rt_linux.c | 12 +++--- drivers/staging/rt2860/rt_linux.h | 5 ++- drivers/staging/rt2860/rt_main_dev.c | 9 +++-- drivers/staging/rt2860/rt_pci_rbus.c | 7 ++-- drivers/staging/rt2860/rt_usb.c | 13 ++++--- drivers/staging/rt2860/rtmp.h | 69 +++++++++++++++++----------------- drivers/staging/rt2860/rtmp_def.h | 37 +++++++++--------- drivers/staging/rt2860/rtmp_timer.h | 13 ++++--- drivers/staging/rt2860/spectrum.h | 12 +++--- drivers/staging/rt2860/sta/assoc.c | 13 ++++--- drivers/staging/rt2860/sta/auth.c | 7 ++-- drivers/staging/rt2860/sta/connect.c | 35 ++++++++--------- drivers/staging/rt2860/sta/rtmp_data.c | 33 ++++++++-------- drivers/staging/rt2860/sta/sanity.c | 5 ++- drivers/staging/rt2860/sta/sync.c | 19 +++++----- drivers/staging/rt2860/sta/wpa.c | 5 ++- drivers/staging/rt2860/sta_ioctl.c | 25 ++++++------ drivers/staging/rt2860/usb_main_dev.c | 8 ++-- drivers/staging/rt2860/wpa.h | 5 ++- 27 files changed, 236 insertions(+), 212 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/chip/mac_pci.h b/drivers/staging/rt2860/chip/mac_pci.h index 9f25ef047f59..b8868a5b9e04 100644 --- a/drivers/staging/rt2860/chip/mac_pci.h +++ b/drivers/staging/rt2860/chip/mac_pci.h @@ -30,7 +30,8 @@ Abstract: Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix some typos --------- ---------- ---------------------------------------------- */ @@ -45,7 +46,7 @@ /* */ /* Device ID & Vendor ID related definitions, */ -/* NOTE: you should not add the new VendorID/DeviceID here unless you not sure it belongs to what chip. */ +/* NOTE: you should not add the new VendorID/DeviceID here unless you know for sure what chip it belongs too. */ /* */ #define NIC_PCI_VENDOR_ID 0x1814 #define PCIBUS_INTEL_VENDOR 0x8086 @@ -83,7 +84,7 @@ struct PACKED rt_txd { u32 SDPtr1; /*Word3 */ u32 rsv2:24; - u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition */ + u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correct position */ u32 QSEL:2; /* select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA */ u32 rsv:2; u32 TCO:1; /* */ diff --git a/drivers/staging/rt2860/chip/mac_usb.h b/drivers/staging/rt2860/chip/mac_usb.h index ed0c0b43b05e..e8158fb58648 100644 --- a/drivers/staging/rt2860/chip/mac_usb.h +++ b/drivers/staging/rt2860/chip/mac_usb.h @@ -30,7 +30,8 @@ Abstract: Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix a typo --------- ---------- ---------------------------------------------- */ @@ -93,7 +94,7 @@ struct rt_txinfo { /* Word 0 */ u32 USBDMATxPktLen:16; /*used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. */ u32 rsv:8; - u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition */ + u32 WIV:1; /* Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correct position */ u32 QSEL:2; /* select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA */ u32 SwUseLastRound:1; /* Software use. */ u32 rsv2:2; /* Software use. */ diff --git a/drivers/staging/rt2860/chip/rtmp_mac.h b/drivers/staging/rt2860/chip/rtmp_mac.h index e8f7172ce42a..3d1e4915b956 100644 --- a/drivers/staging/rt2860/chip/rtmp_mac.h +++ b/drivers/staging/rt2860/chip/rtmp_mac.h @@ -32,6 +32,7 @@ Revision History: Who When What + Justin P. Mattock 11/07/2010 Fix a comments, and typos -------- ---------- ---------------------------------------------- */ @@ -43,7 +44,7 @@ /* ================================================================================= */ /* the first 24-byte in TXD is called TXINFO and will be DMAed to MAC block through TXFIFO. */ -/* MAC block use this TXINFO to control the transmission behavior of this frame. */ +/* MAC block uses this TXINFO to control the transmission behavior of this frame. */ #define FIFO_MGMT 0 #define FIFO_HCCA 1 #define FIFO_EDCA 2 @@ -458,8 +459,8 @@ typedef union _BBP_CSR_CFG_STRUC { /* */ typedef union _RF_CSR_CFG0_STRUC { struct { - u32 RegIdAndContent:24; /* Register value to program into BBP */ - u32 bitwidth:5; /* Selected BBP register */ + u32 RegIdAndContent:24; /* Register value to program into BBP */ + u32 bitwidth:5; /* Selected BBP register */ u32 StandbyMode:1; /* 0: high when stand by 1: low when standby */ u32 Sel:1; /* 0:RF_LE0 activate 1:RF_LE1 activate */ u32 Busy:1; /* 0: idle 1: 8busy */ @@ -469,7 +470,7 @@ typedef union _RF_CSR_CFG0_STRUC { #define RF_CSR_CFG1 0x1024 typedef union _RF_CSR_CFG1_STRUC { struct { - u32 RegIdAndContent:24; /* Register value to program into BBP */ + u32 RegIdAndContent:24; /* Register value to program into BBP */ u32 RFGap:5; /* Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) */ u32 rsv:7; /* 0: idle 1: 8busy */ } field; @@ -478,7 +479,7 @@ typedef union _RF_CSR_CFG1_STRUC { #define RF_CSR_CFG2 0x1028 /* */ typedef union _RF_CSR_CFG2_STRUC { struct { - u32 RegIdAndContent:24; /* Register value to program into BBP */ + u32 RegIdAndContent:24; /* Register value to program into BBP */ u32 rsv:8; /* 0: idle 1: 8busy */ } field; u32 word; @@ -490,7 +491,7 @@ typedef union _LED_CFG_STRUC { u32 OffPeriod:8; /* blinking off period unit 1ms */ u32 SlowBlinkPeriod:6; /* slow blinking period. unit:1ms */ u32 rsv:2; - u32 RLedMode:2; /* red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on */ + u32 RLedMode:2; /* red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on */ u32 GLedMode:2; /* green Led Mode */ u32 YLedMode:2; /* yellow Led Mode */ u32 LedPolar:1; /* Led Polarity. 0: active low1: active high */ @@ -621,9 +622,9 @@ typedef union _TX_TIMEOUT_CFG_STRUC { #define TX_RTY_CFG 0x134c typedef union PACKED _TX_RTY_CFG_STRUC { struct { - u32 ShortRtyLimit:8; /* short retry limit */ - u32 LongRtyLimit:8; /*long retry limit */ - u32 LongRtyThre:12; /* Long retry threshoold */ + u32 ShortRtyLimit:8; /* short retry limit */ + u32 LongRtyLimit:8; /* long retry limit */ + u32 LongRtyThre:12; /* Long retry threshold */ u32 NonAggRtyMode:1; /* Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer */ u32 AggRtyMode:1; /* Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer */ u32 TxautoFBEnable:1; /* Tx retry PHY rate auto fallback enable */ diff --git a/drivers/staging/rt2860/chips/rt3090.c b/drivers/staging/rt2860/chips/rt3090.c index c2933c69bc04..156eb36e56f2 100644 --- a/drivers/staging/rt2860/chips/rt3090.c +++ b/drivers/staging/rt2860/chips/rt3090.c @@ -28,10 +28,11 @@ rt3090.c Abstract: - Specific funcitons and variables for RT3070 + Specific functions and variables for RT3070 Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix a typo -------- ---------- ---------------------------------------------- */ diff --git a/drivers/staging/rt2860/chips/rt30xx.c b/drivers/staging/rt2860/chips/rt30xx.c index 4367a196aeff..c8f728257197 100644 --- a/drivers/staging/rt2860/chips/rt30xx.c +++ b/drivers/staging/rt2860/chips/rt30xx.c @@ -28,10 +28,11 @@ rt30xx.c Abstract: - Specific funcitons and variables for RT30xx. + Specific functions and variables for RT30xx. Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix some typos -------- ---------- ---------------------------------------------- */ @@ -89,7 +90,7 @@ struct rt_reg_pair RT30xx_RFRegTable[] = { u8 NUM_RF_REG_PARMS = (sizeof(RT30xx_RFRegTable) / sizeof(struct rt_reg_pair)); -/* Antenna divesity use GPIO3 and EESK pin for control */ +/* Antenna diversity use GPIO3 and EESK pin for control */ /* Antenna and EEPROM access are both using EESK pin, */ /* Therefor we should avoid accessing EESK at the same time */ /* Then restore antenna after EEPROM access */ @@ -243,7 +244,7 @@ void RTMPFilterCalibration(struct rt_rtmp_adapter *pAd) break; } - /* prevent infinite loop cause driver hang. */ + /* prevent infinite loop; causes driver hang. */ if (loopcnt++ > 100) { DBGPRINT(RT_DEBUG_ERROR, ("RTMPFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", diff --git a/drivers/staging/rt2860/mlme.h b/drivers/staging/rt2860/mlme.h index 01414c3b4889..cd1ee3d7a91d 100644 --- a/drivers/staging/rt2860/mlme.h +++ b/drivers/staging/rt2860/mlme.h @@ -32,8 +32,9 @@ Revision History: Who When What -------- ---------- ------------------------------ - John Chang 2003-08-28 Created - John Chang 2004-09-06 modified for RT2600 + John Chang 2003-08-28 Created + John Chang 2004-09-06 modified for RT2600 + Justin P. Mattock 11/07/2010 Fix typos in comments */ #ifndef __MLME_H__ @@ -41,7 +42,7 @@ #include "rtmp_dot11.h" -/* maximum supported capability information - */ +/* maximum supported capability information */ /* ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot */ #define SUPPORTED_CAPABILITY_INFO 0x0533 @@ -77,7 +78,7 @@ #define CW_MAX_IN_BITS 10 /* actual CwMax = 2^CW_MAX_IN_BITS - 1 */ /* Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). */ -/* SHould not refer to this constant anymore */ +/* Should not refer to this constant anymore */ /*#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm */ #define RSSI_FOR_MID_TX_POWER -55 /* -55 db is considered mid-distance */ #define RSSI_FOR_LOW_TX_POWER -45 /* -45 db is considered very short distance and */ @@ -123,7 +124,7 @@ #define TID_MAC_HASH_INDEX(Addr, TID) (TID_MAC_HASH(Addr, TID) % HASH_TABLE_SIZE) /* LED Control */ -/* assoiation ON. one LED ON. another blinking when TX, OFF when idle */ +/* association ON. one LED ON. another blinking when TX, OFF when idle */ /* no association, both LED off */ #define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46) #define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46) @@ -284,8 +285,8 @@ struct PACKED rt_ht_capability_ie { /* 802.11n draft3 related structure definitions. */ /* 7.3.2.60 */ -#define dot11OBSSScanPassiveDwell 20 /* in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. */ -#define dot11OBSSScanActiveDwell 10 /* in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. */ +#define dot11OBSSScanPassiveDwell 20 /* in TU. min amount of time that the STA continuously scans each channel when performing an active OBSS scan. */ +#define dot11OBSSScanActiveDwell 10 /* in TU.min amount of time that the STA continuously scans each channel when performing an passive OBSS scan. */ #define dot11BSSWidthTriggerScanInterval 300 /* in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. */ #define dot11OBSSScanPassiveTotalPerChannel 200 /* in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. */ #define dot11OBSSScanActiveTotalPerChannel 20 /*in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan */ @@ -325,7 +326,7 @@ struct rt_trigger_eventa { }; /* 20/40 trigger event table */ -/* If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. */ +/* If one Event (A) is deleted or created, or if Event (B) is detected or not detected, STA should send 2040BSSCoexistence to AP. */ #define MAX_TRIGGER_EVENT 64 struct rt_trigger_event_tab { u8 EventANo; @@ -357,14 +358,14 @@ struct PACKED rt_bss_2040_intolerant_ch_report { u8 ChList[0]; }; -/* The structure for channel switch annoucement IE. This is in 802.11n D3.03 */ +/* The structure for channel switch announcement IE. This is in 802.11n D3.03 */ struct PACKED rt_cha_switch_announce_ie { u8 SwitchMode; /*channel switch mode */ u8 NewChannel; /* */ u8 SwitchCount; /* */ }; -/* The structure for channel switch annoucement IE. This is in 802.11n D3.03 */ +/* The structure for channel switch announcement IE. This is in 802.11n D3.03 */ struct PACKED rt_sec_cha_offset_ie { u8 SecondaryChannelOffset; /* 1: Secondary above, 3: Secondary below, 0: no Secondary */ }; @@ -377,7 +378,7 @@ struct rt_ht_phy_info { u8 MCSSet[16]; }; -/*This structure substracts ralink supports from all 802.11n-related features. */ +/*This structure subtracts ralink supports from all 802.11n-related features. */ /*Features not listed here but contained in 802.11n spec are not supported in rt2860. */ struct rt_ht_capability { u16 ChannelWidth:1; @@ -387,14 +388,14 @@ struct rt_ht_capability { u16 ShortGIfor40:1; /*for40MHz */ u16 TxSTBC:1; u16 RxSTBC:2; /* 2 bits */ - u16 AmsduEnable:1; /* Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n */ + u16 AmsduEnable:1; /* Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benefit of 802.11n */ u16 AmsduSize:1; /* Max receiving A-MSDU size */ u16 rsv:5; /*Substract from Addiont HT INFO IE */ u8 MaxRAmpduFactor:2; u8 MpduDensity:3; - u8 ExtChanOffset:2; /* Please not the difference with following u8 NewExtChannelOffset; from 802.11n */ + u8 ExtChanOffset:2; /* Please note the difference with following u8 NewExtChannelOffset; from 802.11n */ u8 RecomWidth:1; u16 OperaionMode:2; @@ -481,7 +482,7 @@ struct PACKED rt_ba_parm { u16 AMSDUSupported:1; /* 0: not permitted 1: permitted */ u16 BAPolicy:1; /* 1: immediately BA 0:delayed BA */ u16 TID:4; /* value of TC os TS */ - u16 BufSize:10; /* number of buffe of size 2304 octetsr */ + u16 BufSize:10; /* number of buffer of size 2304 octetsr */ }; /* 2-byte BA Starting Seq CONTROL field */ @@ -551,7 +552,7 @@ struct PACKED rt_frame_mtba_req { BASEQ_CONTROL BAStartingSeq; }; -/* Compressed format is mandantory in HT STA */ +/* Compressed format is mandatory in HT STA */ struct PACKED rt_frame_mtba { struct rt_frame_control FC; u16 Duration; @@ -647,7 +648,7 @@ struct PACKED rt_frame_ba { u8 bitmask[8]; }; -/* Radio Measuement Request Frame Format */ +/* Radio Measurement Request Frame Format */ struct PACKED rt_frame_rm_req_action { struct rt_header_802_11 Hdr; u8 Category; @@ -709,7 +710,7 @@ struct rt_edca_parm { u8 Cwmin[4]; u8 Cwmax[4]; u16 Txop[4]; /* in unit of 32-us */ - BOOLEAN bACM[4]; /* 1: Admission Control of AC_BK is mandattory */ + BOOLEAN bACM[4]; /* 1: Admission Control of AC_BK is mandatory */ }; /* QBSS LOAD information from QAP's BEACON/ProbeRsp */ @@ -757,7 +758,7 @@ struct rt_wpa_ie { struct rt_bss_entry { u8 Bssid[MAC_ADDR_LEN]; u8 Channel; - u8 CentralChannel; /*Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. */ + u8 CentralChannel; /*Store the wide-band central channel for 40MHz. used in 40MHz AP. Or this is the same as Channel. */ u8 BssType; u16 AtimWin; u16 BeaconPeriod; @@ -855,7 +856,7 @@ struct rt_state_machine { STATE_MACHINE_FUNC *TransFunc; }; -/* MLME AUX data structure that hold temporarliy settings during a connection attempt. */ +/* MLME AUX data structure that holds temporarliy settings during a connection attempt. */ /* Once this attemp succeeds, all settings will be copy to pAd->StaActive. */ /* A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of */ /* several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely */ @@ -996,7 +997,7 @@ struct PACKED rt_rtmp_tx_rate_switch { #define MAC_TABLE_ASSOC_TIMEOUT 5 /* unit: sec */ #define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE) -/* AP shall drop the sta if contine Tx fail count reach it. */ +/* AP shall drop the sta if continue Tx fail count reach it. */ #define MAC_ENTRY_LIFE_CHECK_CNT 20 /* packet cnt. */ /* Value domain of pMacEntry->Sst */ diff --git a/drivers/staging/rt2860/oid.h b/drivers/staging/rt2860/oid.h index 1704c27b2736..eaa3fe005088 100644 --- a/drivers/staging/rt2860/oid.h +++ b/drivers/staging/rt2860/oid.h @@ -32,7 +32,8 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - Name Date Modification logs + Name Date Modification logs + Justin P. Mattock 11/07/2010 Fix typos in comments */ #ifndef _OID_H_ #define _OID_H_ @@ -78,7 +79,7 @@ #define NDIS_802_11_LENGTH_RATES 8 #define NDIS_802_11_LENGTH_RATES_EX 16 #define MAC_ADDR_LENGTH 6 -/*#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc */ +/*#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination */ #define MAX_NUM_OF_CHS 54 /* 14 channels @2.4G + 12@UNII(lower/middle) + 16@HiperLAN2 + 11@UNII(upper) + 0 @Japan + 1 as NULL termination */ #define MAX_NUMBER_OF_EVENT 10 /* entry # in EVENT table */ #define MAX_NUMBER_OF_MAC 32 /* if MAX_MBSSID_NUM is 8, this value can't be larger than 211 */ @@ -610,7 +611,7 @@ struct rt_802_11_event_log { struct rt_802_11_event_table { unsigned long Num; - unsigned long Rsv; /* to align Log[] at LARGE_INEGER boundary */ + unsigned long Rsv; /* to align Log[] at LARGE_INTEGER boundary */ struct rt_802_11_event_log Log[MAX_NUMBER_OF_EVENT]; }; @@ -721,9 +722,9 @@ struct rt_802_11_tx_rates { #define AUTH_FAIL 0x4 /* Open authentication fail */ #define AUTH_FAIL_KEYS 0x5 /* Shared authentication fail */ #define ASSOC_FAIL 0x6 /* Association failed */ -#define EAP_MIC_FAILURE 0x7 /* Deauthencation because MIC failure */ -#define EAP_4WAY_TIMEOUT 0x8 /* Deauthencation on 4-way handshake timeout */ -#define EAP_GROUP_KEY_TIMEOUT 0x9 /* Deauthencation on group key handshake timeout */ +#define EAP_MIC_FAILURE 0x7 /* Deauthentication because MIC failure */ +#define EAP_4WAY_TIMEOUT 0x8 /* Deauthentication on 4-way handshake timeout */ +#define EAP_GROUP_KEY_TIMEOUT 0x9 /* Deauthentication on group key handshake timeout */ #define EAP_SUCCESS 0xa /* EAP succeed */ #define DETECT_RADAR_SIGNAL 0xb /* Radar signal occur in current channel */ #define EXTRA_INFO_MAX 0xb /* Indicate Last OID */ diff --git a/drivers/staging/rt2860/pci_main_dev.c b/drivers/staging/rt2860/pci_main_dev.c index 321facd6b0ab..c35c804a083e 100644 --- a/drivers/staging/rt2860/pci_main_dev.c +++ b/drivers/staging/rt2860/pci_main_dev.c @@ -31,7 +31,8 @@ Create and register network interface for PCI based chipsets in Linux platform. Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix typos in some comments -------- ---------- ---------------------------------------------- */ @@ -40,8 +41,8 @@ #include /* Following information will be show when you run 'modinfo' */ -/* *** If you have a solution for the bug in current version of driver, please mail to me. */ -/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** */ +/* If you have a solution for a bug in current version of driver, please e-mail me. */ +/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. */ MODULE_AUTHOR("Jett Chen "); MODULE_DESCRIPTION("RT2860/RT3090 Wireless Lan Linux Driver"); MODULE_LICENSE("GPL"); @@ -599,7 +600,7 @@ void RTMPInitPCIeLinkCtrlValue(struct rt_rtmp_adapter *pAd) DBGPRINT_RAW(RT_DEBUG_ERROR, (" AUX_CTRL = 0x%32x\n", MacValue)); - /* for RT30xx F and after, PCIe infterface, and for power solution 3 */ + /* for RT30xx F and after, PCIe interface, and for power solution 3 */ if ((IS_VERSION_AFTER_F(pAd)) && (pAd->StaCfg.PSControl.field.rt30xxPowerMode >= 2) && (pAd->StaCfg.PSControl.field.rt30xxPowerMode <= 3)) { @@ -902,7 +903,7 @@ void RTMPPCIeLinkCtrlValueRestore(struct rt_rtmp_adapter *pAd, u8 Level) Configuration); if ((Configuration != 0) && (Configuration != 0xFFFF)) { Configuration &= 0xfefc; - /* If call from interface down, restore to orginial setting. */ + /* If call from interface down, restore to original setting. */ if (Level == RESTORE_CLOSE) Configuration |= pAd->HostLnkCtrlConfiguration; else @@ -924,7 +925,7 @@ void RTMPPCIeLinkCtrlValueRestore(struct rt_rtmp_adapter *pAd, u8 Level) Configuration); if ((Configuration != 0) && (Configuration != 0xFFFF)) { Configuration &= 0xfefc; - /* If call from interface down, restore to orginial setting. */ + /* If call from interface down, restore to original setting. */ if (Level == RESTORE_CLOSE) Configuration |= pAd->RLnkCtrlConfiguration; else @@ -1106,12 +1107,12 @@ void RTMPrt3xSetPCIePowerLinkCtrl(struct rt_rtmp_adapter *pAd) if (pos != 0) pAd->HostLnkCtrlOffset = pos + PCI_EXP_LNKCTL; - /* If configurared to turn on L1. */ + /* If configured to turn on L1. */ HostConfiguration = 0; if (pAd->StaCfg.PSControl.field.rt30xxForceASPMTest == 1) { DBGPRINT(RT_DEBUG_TRACE, ("Enter,PSM : Force ASPM\n")); - /* Skip non-exist deice right away */ + /* Skip non-exist device right away */ if ((pAd->HostLnkCtrlOffset != 0)) { PCI_REG_READ_WORD(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset, diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c index abfeea11721d..e680b0d97f74 100644 --- a/drivers/staging/rt2860/rt_linux.c +++ b/drivers/staging/rt2860/rt_linux.c @@ -767,13 +767,13 @@ void send_monitor_packets(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) /* QOS */ if (pRxBlk->pHeader->FC.SubType & 0x08) { header_len += 2; - /* Data skip QOS contorl field */ + /* Data skip QOS control field */ pRxBlk->DataSize -= 2; } /* Order bit: A-Ralink or HTC+ */ if (pRxBlk->pHeader->FC.Order) { header_len += 4; - /* Data skip HTC contorl field */ + /* Data skip HTC control field */ pRxBlk->DataSize -= 4; } /* Copy Header */ @@ -1175,7 +1175,7 @@ int RtmpOSNetDevAddrSet(struct net_device *pNetDev, u8 *pMacAddr) net_dev = pNetDev; GET_PAD_FROM_NET_DEV(pAd, net_dev); - /* work-around for the SuSE due to it has it's own interface name management system. */ + /* work-around for SuSE, due to them having their own interface name management system. */ { NdisZeroMemory(pAd->StaCfg.dev_name, 16); NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, @@ -1300,7 +1300,7 @@ int RtmpOSNetDevAttach(struct net_device *pNetDev, int ret, rtnl_locked = FALSE; DBGPRINT(RT_DEBUG_TRACE, ("RtmpOSNetDevAttach()--->\n")); - /* If we need hook some callback function to the net device structrue, now do it. */ + /* If we need hook some callback function to the net device structure, now do it. */ if (pDevOpHook) { struct rt_rtmp_adapter *pAd = NULL; @@ -1351,10 +1351,10 @@ struct net_device *RtmpOSNetDevCreate(struct rt_rtmp_adapter *pAd, return NULL; } - /* find a available interface name, max 32 interfaces */ + /* find an available interface name, max 32 interfaces */ status = RtmpOSNetDevRequestName(pAd, pNetDev, pNamePrefix, devNum); if (status != NDIS_STATUS_SUCCESS) { - /* error! no any available ra name can be used! */ + /* error! no available ra name can be used! */ DBGPRINT(RT_DEBUG_ERROR, ("Assign interface name (%s with suffix 0~32) failed...\n", pNamePrefix)); diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h index 5acedf18b1ab..a449b0bb85f1 100644 --- a/drivers/staging/rt2860/rt_linux.h +++ b/drivers/staging/rt2860/rt_linux.h @@ -30,7 +30,8 @@ Abstract: Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix typo in a comment --------- ---------- ---------------------------------------------- */ @@ -726,7 +727,7 @@ void linux_pci_unmap_single(struct rt_rtmp_adapter *pAd, dma_addr_t dma_addr, #define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) /* */ -/* Sepcific Pakcet Type definition */ +/* Specific Packet Type definition */ /* */ #define RTMP_PACKET_SPECIFIC_CB_OFFSET 11 diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index ad60ceaf4b88..19e9bc6569f8 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -31,7 +31,8 @@ Create and register network interface. Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix typos in comments -------- ---------- ---------------------------------------------- */ @@ -234,7 +235,7 @@ int rt28xx_close(struct net_device *dev) RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_CLOSE); #endif /* RTMP_MAC_PCI // */ - /* If dirver doesn't wake up firmware here, */ + /* If driver doesn't wake up firmware here, */ /* NICLoadFirmware will hang forever when interface is up again. */ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { AsicForceWakeup(pAd, TRUE); @@ -310,8 +311,8 @@ int rt28xx_close(struct net_device *dev) RTMP_ASIC_INTERRUPT_DISABLE(pAd); } /* Receive packets to clear DMA index after disable interrupt. */ - /*RTMPHandleRxDoneInterrupt(pAd); */ - /* put to radio off to save power when driver unload. After radiooff, can't write /read register. So need to finish all */ + /* RTMPHandleRxDoneInterrupt(pAd); */ + /* put radio off to save power when driver unloads. After radiooff, can't write/read register, so need to finish all. */ /* register access before Radio off. */ brc = RT28xxPciAsicRadioOff(pAd, RTMP_HALT, 0); diff --git a/drivers/staging/rt2860/rt_pci_rbus.c b/drivers/staging/rt2860/rt_pci_rbus.c index 3004be6da003..e5fb67cd9a68 100644 --- a/drivers/staging/rt2860/rt_pci_rbus.c +++ b/drivers/staging/rt2860/rt_pci_rbus.c @@ -31,7 +31,8 @@ Create and register network interface. Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix a typo -------- ---------- ---------------------------------------------- */ @@ -356,7 +357,7 @@ static void mgmt_dma_done_tasklet(unsigned long data) RTMPHandleMgmtRingDmaDoneInterrupt(pAd); - /* if you use RTMP_SEM_LOCK, sometimes kernel will hang up, no any */ + /* if you use RTMP_SEM_LOCK, sometimes kernel will hang up, without any */ /* bug report output */ RTMP_INT_LOCK(&pAd->irq_lock, flags); /* @@ -787,7 +788,7 @@ IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance) } /* - * invaild or writeback cache + * invalid or writeback cache * and convert virtual address to physical address */ dma_addr_t linux_pci_map_single(struct rt_rtmp_adapter *pAd, void *ptr, diff --git a/drivers/staging/rt2860/rt_usb.c b/drivers/staging/rt2860/rt_usb.c index bcfc0f54d2aa..580a20dd6e9d 100644 --- a/drivers/staging/rt2860/rt_usb.c +++ b/drivers/staging/rt2860/rt_usb.c @@ -32,7 +32,8 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - Name Date Modification logs + Name Date Modification logs + Justin P. Mattock 11/07/2010 Fix some typos. */ @@ -279,7 +280,7 @@ static void rtusb_dataout_complete(unsigned long data) && !RTUSB_TEST_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId))) { - /* Indicate There is data avaliable */ + /* Indicate There is data available */ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); @@ -335,7 +336,7 @@ static void rtusb_null_frame_done_tasklet(unsigned long data) } /* Always call Bulk routine, even reset bulk. */ - /* The protectioon of rest bulk should be in BulkOut routine */ + /* The protection of rest bulk should be in BulkOut routine */ RTUSBKickBulkOut(pAd); } @@ -383,7 +384,7 @@ static void rtusb_rts_frame_done_tasklet(unsigned long data) RTMP_SEM_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); /* Always call Bulk routine, even reset bulk. */ - /* The protectioon of rest bulk should be in BulkOut routine */ + /* The protection of rest bulk should be in BulkOut routine */ RTUSBKickBulkOut(pAd); } @@ -427,7 +428,7 @@ static void rtusb_pspoll_frame_done_tasklet(unsigned long data) RTMP_SEM_UNLOCK(&pAd->BulkOutLock[0]); /* Always call Bulk routine, even reset bulk. */ - /* The protectioon of rest bulk should be in BulkOut routine */ + /* The protection of rest bulk should be in BulkOut routine */ RTUSBKickBulkOut(pAd); } @@ -575,7 +576,7 @@ static void rtusb_mgmt_dma_done_tasklet(unsigned long data) } else { /* Always call Bulk routine, even reset bulk. */ - /* The protectioon of rest bulk should be in BulkOut routine */ + /* The protection of rest bulk should be in BulkOut routine */ if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) { diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h index ca54e53b6603..caf466242a13 100644 --- a/drivers/staging/rt2860/rtmp.h +++ b/drivers/staging/rt2860/rtmp.h @@ -31,11 +31,12 @@ Miniport generic portion header file Revision History: - Who When What + Who When What -------- ---------- ---------------------------------------------- - Paul Lin 2002-08-01 created - James Tan 2002-09-06 modified (Revise NTCRegTable) - John Chang 2004-09-06 modified for RT2600 + Paul Lin 2002-08-01 created + James Tan 2002-09-06 modified (Revise NTCRegTable) + John Chang 2004-09-06 modified for RT2600 + Justin P. Mattock 11/07/2010 Fix some typos */ #ifndef __RTMP_H__ #define __RTMP_H__ @@ -337,7 +338,7 @@ struct rt_rtmp_sg_list { #define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) #define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE)) -/* if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required */ +/* if original Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required */ #define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \ { \ if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) { \ @@ -466,7 +467,7 @@ struct rt_rtmp_dmabuf { /* Control block (Descriptor) for all ring descriptor DMA operation, buffer must be */ /* contiguous physical memory. char stored the binding Rx packet descriptor */ /* which won't be released, driver has to wait until upper layer return the packet */ -/* before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair */ +/* before giving up this rx ring descriptor to ASIC. NDIS_BUFFER is associated pair */ /* to describe the packet buffer. For Tx, char stored the tx packet descriptor */ /* which driver should ACK upper layer when the tx is physically done or failed. */ /* */ @@ -602,7 +603,7 @@ struct rt_counter_ralink { }; struct rt_counter_drs { - /* to record the each TX rate's quality. 0 is best, the bigger the worse. */ + /* record each TX rate's quality. 0 is best, the bigger the worse. */ u16 TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; u8 PER[MAX_STEP_OF_TX_RATE_SWITCH]; u8 TxRateUpPenalty; /* extra # of second penalty due to last unstable condition */ @@ -719,7 +720,7 @@ struct rt_fragment_frame { /* Packet information for NdisQueryPacket */ /* */ struct rt_packet_info { - u32 PhysicalBufferCount; /* Physical breaks of buffer descripor chained */ + u32 PhysicalBufferCount; /* Physical breaks of buffer descriptor chained */ u32 BufferCount; /* Number of Buffer descriptor chained */ u32 TotalPacketLength; /* Self explained */ char *pFirstBuffer; /* Pointer to first buffer descriptor */ @@ -846,8 +847,8 @@ typedef enum _ABGBAND_STATE_ { /* Power save method control */ typedef union _PS_CONTROL { struct { - unsigned long EnablePSinIdle:1; /* Enable radio off when not connect to AP. radio on only when sitesurvey, */ - unsigned long EnableNewPS:1; /* Enable new Chip power save fucntion . New method can only be applied in chip version after 2872. and PCIe. */ + unsigned long EnablePSinIdle:1; /* Enable radio off when not connected to AP. radio on only when sitesurvey, */ + unsigned long EnableNewPS:1; /* Enable new Chip power save function . New method can only be applied in chip version after 2872. and PCIe. */ unsigned long rt30xxPowerMode:2; /* Power Level Mode for rt30xx chip */ unsigned long rt30xxFollowHostASPM:1; /* Card Follows Host's setting for rt30xx chip. */ unsigned long rt30xxForceASPMTest:1; /* Force enable L1 for rt30xx chip. This has higher priority than rt30xxFollowHostASPM Mode. */ @@ -1117,8 +1118,8 @@ struct rt_beacon_sync { unsigned long TimIELocationInBeacon[HW_BEACON_MAX_COUNT]; unsigned long CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT]; BOOLEAN EnableBeacon; /* trigger to enable beacon transmission. */ - u8 BeaconBitMap; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. */ - u8 DtimBitOn; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. */ + u8 BeaconBitMap; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter needs to change. */ + u8 DtimBitOn; /* NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter needs to change. */ }; #endif /* RTMP_MAC_USB // */ @@ -1211,7 +1212,7 @@ struct rt_common_config { /*BOOLEAN bAutoTxRateSwitch; */ u8 MinTxRate; /* RATE_1, RATE_2, RATE_5_5, RATE_11 */ u8 RtsRate; /* RATE_xxx */ - HTTRANSMIT_SETTING MlmeTransmit; /* MGMT frame PHY rate setting when operatin at Ht rate. */ + HTTRANSMIT_SETTING MlmeTransmit; /* MGMT frame PHY rate setting when operation at Ht rate. */ u8 MlmeRate; /* RATE_xxx, used to send MLME frames */ u8 BasicMlmeRate; /* Default Rate for sending MLME frames */ @@ -1264,7 +1265,7 @@ struct rt_common_config { struct rt_ht_capability_ie HtCapability; struct rt_add_ht_info_ie AddHTInfo; /* Useful as AP. */ /*This IE is used with channel switch announcement element when changing to a new 40MHz. */ - /*This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. */ + /*This IE is included in channel switch announcement frames 7.4.1.5, beacons, probe Rsp. */ struct rt_new_ext_chan_ie NewExtChanOffset; /*7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present */ BOOLEAN bHTProtect; @@ -1329,7 +1330,7 @@ struct rt_sta_admin_config { /* GROUP 1 - */ /* User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe */ /* the user intended configuration, but not necessary fully equal to the final */ - /* settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either */ + /* settings in ACTIVE BSS after negotiation/compromise with the BSS holder (either */ /* AP or IBSS holder). */ /* Once initialized, user configuration can only be changed via OID_xxx */ u8 BssType; /* BSS_INFRA or BSS_ADHOC */ @@ -1386,12 +1387,12 @@ struct rt_sta_admin_config { /* For WPA countermeasures */ unsigned long LastMicErrorTime; /* record last MIC error time */ - unsigned long MicErrCnt; /* Should be 0, 1, 2, then reset to zero (after disassoiciation). */ + unsigned long MicErrCnt; /* Should be 0, 1, 2, then reset to zero (after disassociation). */ BOOLEAN bBlockAssoc; /* Block associate attempt for 60 seconds after counter measure occurred. */ /* For WPA-PSK supplicant state */ WPA_STATE WpaState; /* Default is SS_NOTUSE and handled by microsoft 802.1x */ u8 ReplayCounter[8]; - u8 ANonce[32]; /* ANonce for WPA-PSK from aurhenticator */ + u8 ANonce[32]; /* ANonce for WPA-PSK from auhenticator */ u8 SNonce[32]; /* SNonce for WPA-PSK */ u8 LastSNR0; /* last received BEACON's SNR */ @@ -1423,7 +1424,7 @@ struct rt_sta_admin_config { u8 RSNIE_Len; u8 RSN_IE[MAX_LEN_OF_RSNIE]; /* The content saved here should be little-endian format. */ - unsigned long CLBusyBytes; /* Save the total bytes received durning channel load scan time */ + unsigned long CLBusyBytes; /* Save the total bytes received during channel load scan time */ u16 RPIDensity[8]; /* Array for RPI density collection */ u8 RMReqCnt; /* Number of measurement request saved. */ @@ -1489,9 +1490,9 @@ struct rt_sta_admin_config { BOOLEAN bForceTxBurst; /* 1: force enble TX PACKET BURST, 0: disable */ }; -/* This data structure keep the current active BSS/IBSS's configuration that this STA */ +/* This data structure keeps the current active BSS/IBSS's configuration that this STA */ /* had agreed upon joining the network. Which means these parameters are usually decided */ -/* by the BSS/IBSS creator instead of user configuration. Data in this data structurre */ +/* by the BSS/IBSS creator instead of user configuration. Data in this data structure */ /* is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. */ /* Normally, after SCAN or failed roaming attempts, we need to recover back to */ /* the current active settings. */ @@ -1519,7 +1520,7 @@ struct rt_mac_table_entry { /*Choose 1 from ValidAsWDS and ValidAsCLI to validize. */ BOOLEAN ValidAsCLI; /* Sta mode, set this TRUE after Linkup,too. */ BOOLEAN ValidAsWDS; /* This is WDS Entry. only for AP mode. */ - BOOLEAN ValidAsApCli; /*This is a AP-Client entry, only for AP mode which enable AP-Client functions. */ + BOOLEAN ValidAsApCli; /* This is a AP-Client entry, only for AP mode which enable AP-Client functions. */ BOOLEAN ValidAsMesh; BOOLEAN ValidAsDls; /* This is DLS Entry. only for STA mode. */ BOOLEAN isCached; @@ -1527,7 +1528,7 @@ struct rt_mac_table_entry { u8 EnqueueEapolStartTimerRunning; /* Enqueue EAPoL-Start for triggering EAP SM */ /*jan for wpa */ - /* record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB */ + /* record which entry revoke MIC Failure, if it leaves the BSS itself, AP won't update aMICFailTime MIB */ u8 CMTimerRunning; u8 apidx; /* MBSS number */ u8 RSNIE_Len; @@ -1722,7 +1723,7 @@ struct rt_rtmp_adapter { unsigned long Rt3xxRalinkLinkCtrl; /* USed for 3090F chip */ u16 DeviceID; /* Read from PCI config */ unsigned long AccessBBPFailCount; - BOOLEAN bPCIclkOff; /* flag that indicate if the PICE power status in Configuration SPace.. */ + BOOLEAN bPCIclkOff; /* flag that indicates if the PICE power status in Configuration Space.. */ BOOLEAN bPCIclkOffDisableTx; /* */ BOOLEAN brt30xxBanMcuCmd; /*when = 0xff means all commands are ok to set . */ @@ -1871,9 +1872,9 @@ struct rt_rtmp_adapter { /* ---------------------------- */ u8 RfIcType; /* RFIC_xxx */ unsigned long RfFreqOffset; /* Frequency offset for channel switching */ - struct rt_rtmp_rf_regs LatchRfRegs; /* latch th latest RF programming value since RF IC doesn't support READ */ + struct rt_rtmp_rf_regs LatchRfRegs; /* latch the latest RF programming value since RF IC doesn't support READ */ - EEPROM_ANTENNA_STRUC Antenna; /* Since ANtenna definition is different for a & g. We need to save it for future reference. */ + EEPROM_ANTENNA_STRUC Antenna; /* Since Antenna definition is different for a & g. We need to save it for future reference. */ EEPROM_NIC_CONFIG2_STRUC NicConfig2; /* This soft Rx Antenna Diversity mechanism is used only when user set */ @@ -1990,7 +1991,7 @@ struct rt_rtmp_adapter { struct rt_common_config CommonCfg; struct rt_mlme Mlme; - /* AP needs those vaiables for site survey feature. */ + /* AP needs those variables for site survey feature. */ struct rt_mlme_aux MlmeAux; /* temporary settings used during MLME state machine */ struct rt_bss_table ScanTab; /* store the latest SCAN result */ @@ -2012,7 +2013,7 @@ struct rt_rtmp_adapter { /* various Counters */ struct rt_counter_802_3 Counters8023; /* 802.3 counters */ struct rt_counter_802_11 WlanCounters; /* 802.11 MIB counters */ - struct rt_counter_ralink RalinkCounters; /* Ralink propriety counters */ + struct rt_counter_ralink RalinkCounters; /* Ralink proprietary counters */ struct rt_counter_drs DrsCounters; /* counters for Dynamic TX Rate Switching */ struct rt_private PrivateInfo; /* Private information & counters */ @@ -2024,7 +2025,7 @@ struct rt_rtmp_adapter { u16 Sequence; /* Control disconnect / connect event generation */ - /*+++Didn't used anymore */ + /*+++Not used anymore */ unsigned long LinkDownTime; /*--- */ unsigned long LastRxRate; @@ -2036,7 +2037,7 @@ struct rt_rtmp_adapter { unsigned long ExtraInfo; /* Extra information for displaying status */ unsigned long SystemErrorBitmap; /* b0: E2PROM version error */ - /*+++Didn't used anymore */ + /*+++Not used anymore */ unsigned long MacIcVersion; /* MAC/BBP serial interface issue solved after ver.D */ /*--- */ @@ -2089,7 +2090,7 @@ struct rt_rtmp_adapter { unsigned long BulkOutReq; unsigned long BulkOutComplete; unsigned long BulkOutCompleteOther; - unsigned long BulkOutCompleteCancel; /* seems not use now? */ + unsigned long BulkOutCompleteCancel; /* seems not used now? */ unsigned long BulkInReq; unsigned long BulkInComplete; unsigned long BulkInCompleteFail; @@ -2196,9 +2197,9 @@ struct rt_rx_blk { struct rt_tx_blk { u8 QueIdx; u8 TxFrameType; /* Indicate the Transmission type of the all frames in one batch */ - u8 TotalFrameNum; /* Total frame number want to send-out in one batch */ + u8 TotalFrameNum; /* Total frame number that wants to send-out in one batch */ u16 TotalFragNum; /* Total frame fragments required in one batch */ - u16 TotalFrameLen; /* Total length of all frames want to send-out in one batch */ + u16 TotalFrameLen; /* Total length of all frames that wants to send-out in one batch */ struct rt_queue_header TxPacketList; struct rt_mac_table_entry *pMacEntry; /* NULL: packet with 802.11 RA field is multicast/broadcast address */ @@ -2207,7 +2208,7 @@ struct rt_tx_blk { /* Following structure used for the characteristics of a specific packet. */ void *pPacket; u8 *pSrcBufHeader; /* Reference to the head of sk_buff->data */ - u8 *pSrcBufData; /* Reference to the sk_buff->data, will changed depends on hanlding progresss */ + u8 *pSrcBufData; /* Reference to the sk_buff->data, will change depending on the handling progresss */ u32 SrcBufLen; /* Length of packet payload which not including Layer 2 header */ u8 *pExtraLlcSnapEncap; /* NULL means no extra LLC/SNAP is required */ u8 HeaderBuf[128]; /* TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP */ @@ -2219,7 +2220,7 @@ struct rt_tx_blk { u8 apidx; /* The interface associated to this packet */ u8 Wcid; /* The MAC entry associated to this packet */ u8 UserPriority; /* priority class of packet */ - u8 FrameGap; /* what kind of IFS this packet use */ + u8 FrameGap; /* what kind of IFS does this packet use */ u8 MpduReqNum; /* number of fragments of this frame */ u8 TxRate; /* TODO: Obsoleted? Should change to MCS? */ u8 CipherAlg; /* cipher alogrithm */ diff --git a/drivers/staging/rt2860/rtmp_def.h b/drivers/staging/rt2860/rtmp_def.h index 9c54bacb845b..6ac617e7c9bb 100644 --- a/drivers/staging/rt2860/rtmp_def.h +++ b/drivers/staging/rt2860/rtmp_def.h @@ -31,10 +31,11 @@ Miniport related definition header Revision History: - Who When What + Who When What -------- ---------- ---------------------------------------------- - Paul Lin 08-01-2002 created - John Chang 08-05-2003 add definition for 11g & other drafts + Paul Lin 08-01-2002 created + John Chang 08-05-2003 add definition for 11g & other drafts + Justin P. Mattock 11/07/2010 Fix some typos */ #ifndef __RTMP_DEF_H__ #define __RTMP_DEF_H__ @@ -111,11 +112,11 @@ WMM Note: If memory of your system is not much, please reduce the definition; or when you do WMM test, the queue for low priority AC will be full, i.e. TX_RING_SIZE + MAX_PACKETS_IN_QUEUE packets for the AC will be buffered in - WLAN, maybe no any packet buffer can be got in Ethernet driver. + WLAN, maybe no packet buffers can get into the Ethernet driver. - Sometimes no packet buffer can be got in Ethernet driver, the system will + Sometimes no packet buffer can be get into the Ethernet driver, the system will send flow control packet to the sender to slow down its sending rate. - So no WMM can be saw in the air. + So no WMM can be seen in the air. */ /* @@ -125,7 +126,7 @@ And in rt_main_end.c, clConfig.clNum = RX_RING_SIZE * 3; is changed to clConfig.clNum = RX_RING_SIZE * 4; */ -/* TODO: For VxWorks the size is 256. Shall we cahnge the value as 256 for all OS????? */ +/* TODO: For VxWorks the size is 256. Shall we change the value as 256 for all OS? */ #define MAX_PACKETS_IN_QUEUE (512) /*(512) // to pass WMM A5-WPAPSK */ #define MAX_PACKETS_IN_MCAST_PS_QUEUE 32 @@ -171,7 +172,7 @@ #define fRTMP_ADAPTER_SCAN_2040 0x04000000 #define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000 -#define fRTMP_ADAPTER_START_UP 0x10000000 /*Devive already initialized and enabled Tx/Rx. */ +#define fRTMP_ADAPTER_START_UP 0x10000000 /*Device already initialized and enabled Tx/Rx. */ #define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000 #define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000 @@ -205,8 +206,8 @@ #define fRTMP_PS_SET_PCI_CLK_OFF_COMMAND 0x00000002 /* Indicate driver should disable kick off hardware to send packets from now. */ #define fRTMP_PS_DISABLE_TX 0x00000004 -/* Indicate driver should IMMEDIATELY fo to sleep after receiving AP's beacon in which doesn't indicate unicate nor multicast packets for me */ -/*. This flag is used ONLY in RTMPHandleRxDoneInterrupt routine. */ +/* Indicate driver should IMMEDIATELY go to sleep after receiving AP's beacon in which doesn't indicate unicate nor multicast packets for me */ +/* This flag is used ONLY in RTMPHandleRxDoneInterrupt routine. */ #define fRTMP_PS_GO_TO_SLEEP_NOW 0x00000008 #define fRTMP_PS_TOGGLE_L1 0x00000010 /* Use Toggle L1 mechanism for rt28xx PCIe */ @@ -303,7 +304,7 @@ /* WDS definition */ #define MAX_WDS_ENTRY 4 -#define WDS_PAIRWISE_KEY_OFFSET 60 /* WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table */ +#define WDS_PAIRWISE_KEY_OFFSET 60 /* WDS links use pairwise key#60 ~ 63 in ASIC pairwise key table */ #define WDS_DISABLE_MODE 0 #define WDS_RESTRICT_MODE 1 @@ -559,7 +560,7 @@ #define IE_ADD_HT2 53 /* 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD */ /* For 802.11n D3.03 */ -/*#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet */ +/*#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset element */ #define IE_SECONDARY_CH_OFFSET 62 /* 802.11n D3.03 Secondary Channel Offset element */ #define IE_WAPI 68 /* WAPI information element */ #define IE_2040_BSS_COEXIST 72 /* 802.11n D3.0.3 */ @@ -678,7 +679,7 @@ #define ACT_MACHINE_BASE 0 -/*Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. */ +/*Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please do not modify it by your self. */ /*Category */ #define MT2_PEER_SPECTRUM_CATE 0 #define MT2_PEER_QOS_CATE 1 @@ -748,7 +749,7 @@ #define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG) /* */ -/* STA's AUTHENTICATION state machine: states, evvents, total function # */ +/* STA's AUTHENTICATION state machine: states, events, total function # */ /* */ #define AUTH_REQ_IDLE 0 #define AUTH_WAIT_SEQ2 1 @@ -948,7 +949,7 @@ #define BLOCK_ACK 0x60 /* b6:5 = 11 */ /* */ -/* rtmp_data.c use these definition */ +/* rtmp_data.c uses this definition */ /* */ #define LENGTH_802_11 24 #define LENGTH_802_11_AND_H 30 @@ -1288,7 +1289,7 @@ #define IW_STA_LINKDOWN_EVENT_FLAG 0x0210 #define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211 #define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212 -/* if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END */ +/* if add new system event flag, please update the IW_SYS_EVENT_FLAG_END */ #define IW_SYS_EVENT_FLAG_END 0x0212 #define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1) /* For system event - end */ @@ -1305,7 +1306,7 @@ #define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307 #define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308 #define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309 -/* if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END */ +/* if add new spoof attack event flag, please update the IW_SPOOF_EVENT_FLAG_END */ #define IW_SPOOF_EVENT_FLAG_END 0x0309 #define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1) /* For spoof attack event - end */ @@ -1319,7 +1320,7 @@ #define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404 #define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405 #define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406 -/* if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END */ +/* if add new flooding attack event flag, please update the IW_FLOOD_EVENT_FLAG_END */ #define IW_FLOOD_EVENT_FLAG_END 0x0406 #define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1) /* For flooding attack - end */ diff --git a/drivers/staging/rt2860/rtmp_timer.h b/drivers/staging/rt2860/rtmp_timer.h index 28b8ac6e8352..15b628743500 100644 --- a/drivers/staging/rt2860/rtmp_timer.h +++ b/drivers/staging/rt2860/rtmp_timer.h @@ -28,13 +28,14 @@ rtmp_timer.h Abstract: - Ralink Wireless Driver timer related data structures and delcarations + Ralink Wireless Driver timer related data structures and declarations Revision History: - Who When What + Who When What -------- ---------- ---------------------------------------------- - Name Date Modification logs - Shiang Tu Aug-28-2008 init version + Name Date Modification logs + Shiang Tu Aug-28-2008 init version + Justin P. Mattock 11/07/2010 Fix a typo */ @@ -51,8 +52,8 @@ /* ----------------- Timer Related MARCO ---------------*/ /* In some os or chipset, we have a lot of timer functions and will read/write register, */ -/* it's not allowed in Linux USB sub-system to do it ( because of sleep issue when */ -/* submit to ctrl pipe). So we need a wrapper function to take care it. */ +/* it's not allowed in Linux USB sub-system to do it ( because of sleep issue when */ +/* submit to ctrl pipe). So we need a wrapper function to take care it. */ #ifdef RTMP_TIMER_TASK_SUPPORT typedef void(*RTMP_TIMER_TASK_HANDLE) (void *SystemSpecific1, diff --git a/drivers/staging/rt2860/spectrum.h b/drivers/staging/rt2860/spectrum.h index 648fd632b606..4c325ba7ba21 100644 --- a/drivers/staging/rt2860/spectrum.h +++ b/drivers/staging/rt2860/spectrum.h @@ -37,7 +37,7 @@ char RTMP_GetTxPwr(struct rt_rtmp_adapter *pAd, IN HTTRANSMIT_SETTING HTTxMode); ========================================================================== Description: Prepare Measurement request action frame and enqueue it into - management queue waiting for transmition. + management queue waiting for transmission. Parametrs: 1. the destination mac address of the frame. @@ -60,7 +60,7 @@ void MakeMeasurementReqFrame(struct rt_rtmp_adapter *pAd, ========================================================================== Description: Prepare Measurement report action frame and enqueue it into - management queue waiting for transmition. + management queue waiting for transmission. Parametrs: 1. the destination mac address of the frame. @@ -80,7 +80,7 @@ void EnqueueMeasurementRep(struct rt_rtmp_adapter *pAd, ========================================================================== Description: Prepare TPC Request action frame and enqueue it into - management queue waiting for transmition. + management queue waiting for transmission. Parametrs: 1. the destination mac address of the frame. @@ -94,7 +94,7 @@ void EnqueueTPCReq(struct rt_rtmp_adapter *pAd, u8 *pDA, u8 DialogToken); ========================================================================== Description: Prepare TPC Report action frame and enqueue it into - management queue waiting for transmition. + management queue waiting for transmission. Parametrs: 1. the destination mac address of the frame. @@ -110,7 +110,7 @@ void EnqueueTPCRep(struct rt_rtmp_adapter *pAd, ========================================================================== Description: Prepare Channel Switch Announcement action frame and enqueue it into - management queue waiting for transmition. + management queue waiting for transmission. Parametrs: 1. the destination mac address of the frame. @@ -126,7 +126,7 @@ void EnqueueChSwAnn(struct rt_rtmp_adapter *pAd, /* ========================================================================== Description: - Spectrun action frames Handler such as channel switch annoucement, + Spectrun action frames Handler such as channel switch announcement, measurement report, measurement request actions frames. Parametrs: diff --git a/drivers/staging/rt2860/sta/assoc.c b/drivers/staging/rt2860/sta/assoc.c index b7efb0b6b3f0..ab0a83bf76ef 100644 --- a/drivers/staging/rt2860/sta/assoc.c +++ b/drivers/staging/rt2860/sta/assoc.c @@ -32,7 +32,8 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - John 2004-9-3 porting from RT2500 + John 2004-9-3 porting from RT2500 + Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" @@ -277,10 +278,10 @@ void MlmeAssocReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem * u16 VarIesOffset; u16 Status; - /* Block all authentication request durning WPA block period */ + /* Block all authentication request during WPA block period */ if (pAd->StaCfg.bBlockAssoc == TRUE) { DBGPRINT(RT_DEBUG_TRACE, - ("ASSOC - Block Assoc request durning WPA block period!\n")); + ("ASSOC - Block Assoc request during WPA block period!\n")); pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; Status = MLME_STATE_MACHINE_REJECT; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, @@ -605,10 +606,10 @@ void MlmeReassocReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem u8 *pOutBuffer = NULL; u16 Status; - /* Block all authentication request durning WPA block period */ + /* Block all authentication request during WPA block period */ if (pAd->StaCfg.bBlockAssoc == TRUE) { DBGPRINT(RT_DEBUG_TRACE, - ("ASSOC - Block ReAssoc request durning WPA block period!\n")); + ("ASSOC - Block ReAssoc request during WPA block period!\n")); pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; Status = MLME_STATE_MACHINE_REJECT; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, @@ -1001,7 +1002,7 @@ void AssocPostProc(struct rt_rtmp_adapter *pAd, u8 *pAddr2, u16 CapabilityInfo, pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; - /* Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. */ + /* Some HT AP might lost WMM IE. We add WMM ourselves. because HT requires QoS on. */ if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) { pEdcaParm->bValid = TRUE; pEdcaParm->Aifsn[0] = 3; diff --git a/drivers/staging/rt2860/sta/auth.c b/drivers/staging/rt2860/sta/auth.c index 404bd220679d..a2bfafddb20e 100644 --- a/drivers/staging/rt2860/sta/auth.c +++ b/drivers/staging/rt2860/sta/auth.c @@ -32,7 +32,8 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - John 2004-9-3 porting from RT2500 + John 2004-9-3 porting from RT2500 + Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" @@ -455,10 +456,10 @@ BOOLEAN AUTH_ReqSend(struct rt_rtmp_adapter *pAd, u8 *pOutBuffer = NULL; unsigned long FrameLen = 0, tmp = 0; - /* Block all authentication request durning WPA block period */ + /* Block all authentication request during WPA block period */ if (pAd->StaCfg.bBlockAssoc == TRUE) { DBGPRINT(RT_DEBUG_TRACE, - ("%s - Block Auth request durning WPA block period!\n", + ("%s - Block Auth request during WPA block period!\n", pSMName)); pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; Status = MLME_STATE_MACHINE_REJECT; diff --git a/drivers/staging/rt2860/sta/connect.c b/drivers/staging/rt2860/sta/connect.c index c380551c0354..4b2c84e6509e 100644 --- a/drivers/staging/rt2860/sta/connect.c +++ b/drivers/staging/rt2860/sta/connect.c @@ -32,7 +32,8 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - John 2004-08-08 Major modification from RT2560 + John 2004-08-08 Major modification from RT2560 + Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" @@ -64,7 +65,7 @@ u8 CipherSuiteWpaNoneAesLen = /* The following MACRO is called after 1. starting an new IBSS, 2. successfully JOIN an IBSS, */ /* or 3. successfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS */ -/* All settings successfuly negotiated furing MLME state machines become final settings */ +/* All settings successfuly negotiated firing MLME state machines become final settings */ /* and are copied to pAd->StaActive */ #define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ { \ @@ -553,7 +554,7 @@ void CntlOidRTBssidProc(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem * NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(struct rt_bss_entry)); - /* Add SSID into MlmeAux for site surey joining hidden SSID */ + /* Add SSID into MlmeAux for site survey joining hidden SSID */ pAd->MlmeAux.SsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; NdisMoveMemory(pAd->MlmeAux.Ssid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->MlmeAux.SsidLen); @@ -666,7 +667,7 @@ void CntlOidRTBssidProc(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem * } /* Roaming is the only external request triggering CNTL state machine */ -/* despite of other "SET OID" operation. All "SET OID" related oerations */ +/* despite of other "SET OID" operation. All "SET OID" related operations */ /* happen in sequence, because no other SET OID will be sent to this device */ /* until the the previous SET operation is complete (successful o failed). */ /* So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? */ @@ -1224,7 +1225,7 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType) /* Change to AP channel */ if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) { - /* Must using 40MHz. */ + /* Must use 40MHz. */ pAd->CommonCfg.BBPCurrentBW = BW_40; AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); @@ -1259,7 +1260,7 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType) } else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) { - /* Must using 40MHz. */ + /* Must use 40MHz. */ pAd->CommonCfg.BBPCurrentBW = BW_40; AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); @@ -1343,12 +1344,12 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType) AsicSetSlotTime(pAd, TRUE); AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); - /* Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit */ + /* Call this for RTS protection for legacy rate, we will always enable RTS threshold, but normally it will not hit */ AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) { - /* Update HT protectionfor based on AP's operating mode. */ + /* Update HT protection for based on AP's operating mode. */ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) { AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2. @@ -1530,7 +1531,7 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType) /* Add BSSID to WCID search table */ AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid); - /* If WEP is enabled, add paiewise and shared key */ + /* If WEP is enabled, add pairwise and shared key */ if (((pAd->StaCfg.WpaSupplicantUP) && (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) && (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || @@ -1681,9 +1682,9 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType) pAd->Mlme.PeriodicRound = 0; pAd->Mlme.OneSecPeriodicRound = 0; pAd->bConfigChanged = FALSE; /* Reset config flag */ - pAd->ExtraInfo = GENERAL_LINK_UP; /* Update extra information to link is up */ + pAd->ExtraInfo = GENERAL_LINK_UP; /* Update extra information after link is up */ - /* Set asic auto fall back */ + /* Set basic auto fall back */ { u8 *pTable; u8 TableSize = 0; @@ -1854,8 +1855,8 @@ void LinkUp(struct rt_rtmp_adapter *pAd, u8 BssType) Note: We need more information to know it's this requst from AP. If yes! we need to do extra handling, for example, remove the WPA key. - Otherwise on 4-way handshaking will faied, since the WPA key didn't be - remove while auto reconnect. + Otherwise on 4-way handshaking will fail, since the WPA key didn't get + removed while auto reconnect. Disconnect request from AP, it means we will start afresh 4-way handshaking on WPA mode. @@ -1870,9 +1871,9 @@ void LinkDown(struct rt_rtmp_adapter *pAd, IN BOOLEAN IsReqFromAP) return; RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); - /*Comment the codes, beasue the line 2291 call the same function. */ - /*RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); */ - /* Not allow go to sleep within linkdown function. */ + /* Comment the codes, because the line 2291 call the same function. */ + /* RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); */ + /* Not allowed go to sleep within the linkdown function. */ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); if (pAd->CommonCfg.bWirelessEvent) { @@ -1970,7 +1971,7 @@ void LinkDown(struct rt_rtmp_adapter *pAd, IN BOOLEAN IsReqFromAP) /* Set LED */ RTMPSetLED(pAd, LED_LINK_DOWN); pAd->LedIndicatorStrength = 0xF0; - RTMPSetSignalLED(pAd, -100); /* Force signal strength Led to be turned off, firmware is not done it. */ + RTMPSetSignalLED(pAd, -100); /* Force signal strength Led to be turned off, firmware has not done it. */ AsicDisableSync(pAd); diff --git a/drivers/staging/rt2860/sta/rtmp_data.c b/drivers/staging/rt2860/sta/rtmp_data.c index 23879b7cd49a..d7c2012be8a5 100644 --- a/drivers/staging/rt2860/sta/rtmp_data.c +++ b/drivers/staging/rt2860/sta/rtmp_data.c @@ -31,7 +31,8 @@ Data path subroutines Revision History: - Who When What + Who When What + Justin P. Mattock 11/07/2010 Fix typos -------- ---------- ---------------------------------------------- */ #include "../rt_config.h" @@ -257,8 +258,8 @@ void STARxDataFrameAnnounce(struct rt_rtmp_adapter *pAd, && (pAd->CommonCfg.bDisableReordering == 0)) { Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); } else { - /* Determin the destination of the EAP frame */ - /* to WPA state machine or upper layer */ + /* Determine the destination of the EAP frame */ + /* to WPA state machine or upper layer */ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); } @@ -853,7 +854,7 @@ Return Value: NONE Note: - This function do early checking and classification for send-out packet. + This function does early checking and classification for send-out packet. You only can put OS-depened & STA related code in here. ======================================================================== */ @@ -943,7 +944,7 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket) DBGPRINT(RT_DEBUG_ERROR, ("STASendPacket --> pSrcBufVA == NULL !SrcBufLen=%x\n", SrcBufLen)); - /* Resourece is low, system did not allocate virtual address */ + /* Resource is low, system did not allocate virtual address */ /* return NDIS_STATUS_FAILURE directly to upper layer */ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); return NDIS_STATUS_FAILURE; @@ -979,7 +980,7 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket) DBGPRINT(RT_DEBUG_ERROR, ("STASendPacket->Cannot find pEntry(%pM) in MacTab!\n", pSrcBufVA)); - /* Resourece is low, system did not allocate virtual address */ + /* Resource is low, system did not allocate virtual address */ /* return NDIS_STATUS_FAILURE directly to upper layer */ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); return NDIS_STATUS_FAILURE; @@ -1057,9 +1058,9 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket) /* STEP 2. Check the requirement of RTS: */ /* If multiple fragment required, RTS is required only for the first fragment */ - /* if the fragment size large than RTS threshold */ + /* if the fragment size is larger than RTS threshold */ /* For RT28xx, Let ASIC send RTS/CTS */ -/* RTMP_SET_PACKET_RTS(pPacket, 0); */ + /* RTMP_SET_PACKET_RTS(pPacket, 0); */ if (NumberOfFrag > 1) RTSRequired = (pAd->CommonCfg.FragmentThreshold > @@ -1171,8 +1172,8 @@ int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket) ======================================================================== Routine Description: - This subroutine will scan through releative ring descriptor to find - out avaliable free ring descriptor and compare with request size. + This subroutine will scan through relative ring descriptor to find + out available free ring descriptor and compare with request size. Arguments: pAd Pointer to our adapter @@ -1588,7 +1589,7 @@ static inline u8 *STA_Build_ARalink_Frame_Header(struct rt_rtmp_adapter *pAd, pHeaderBufPtr += 2; pTxBlk->MpduHeaderLen += 2; } - /* padding at front of LLC header. LLC header should at 4-bytes aligment. */ + /* padding at front of LLC header. LLC header should at 4-bytes alignment. */ pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); @@ -2014,7 +2015,7 @@ void STA_Legacy_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) pHeaderBufPtr += 2; pTxBlk->MpduHeaderLen += 2; } - /* The remaining content of MPDU header should locate at 4-octets aligment */ + /* The remaining content of MPDU header should locate at 4-octets alignment */ pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); @@ -2114,7 +2115,7 @@ void STA_ARalink_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) STA_Build_ARalink_Frame_Header(pAd, pTxBlk); /* It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount */ - /* will be updated after final frame was handled. */ + /* will be updated after final frame was handled. */ RTMPWriteTxWI_Data(pAd, (struct rt_txwi *) (&pTxBlk-> HeaderBuf @@ -2291,8 +2292,8 @@ void STA_Fragment_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk pTxBlk->pExtraLlcSnapEncap, pTxBlk->pKey, 0); - /* NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust */ - /* to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. */ + /* NOTE: DON'T refer the skb->len directly after following copy. Because the length is not adjusted */ + /* to correct length, refer to pTxBlk->SrcBufLen for the packet length in following progress. */ NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); /*skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); */ @@ -2301,7 +2302,7 @@ void STA_Fragment_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; } /* */ - /* calcuate the overhead bytes that encryption algorithm may add. This */ + /* calculate the overhead bytes that encryption algorithm may add. This */ /* affects the calculate of "duration" field */ /* */ if ((pTxBlk->CipherAlg == CIPHER_WEP64) diff --git a/drivers/staging/rt2860/sta/sanity.c b/drivers/staging/rt2860/sta/sanity.c index 8f9fd19be151..0c32604f2d3f 100644 --- a/drivers/staging/rt2860/sta/sanity.c +++ b/drivers/staging/rt2860/sta/sanity.c @@ -32,7 +32,8 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 add WMM support + John Chang 2004-09-01 add WMM support + Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" @@ -118,7 +119,7 @@ BOOLEAN PeerAssocRspSanity(struct rt_rtmp_adapter *pAd, void * pMsg, unsigned lo NdisMoveMemory(pAid, &pFrame->Octet[4], 2); Length += 2; - /* Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform */ + /* Aid already swapped byte order in RTMPFrameEndianChange() for big endian platform */ *pAid = (*pAid) & 0x3fff; /* AID is low 14-bit */ /* -- get supported rates from payload and advance the pointer */ diff --git a/drivers/staging/rt2860/sta/sync.c b/drivers/staging/rt2860/sta/sync.c index 747d3c6d1851..05007d9c9b69 100644 --- a/drivers/staging/rt2860/sta/sync.c +++ b/drivers/staging/rt2860/sta/sync.c @@ -32,8 +32,9 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - John Chang 2004-09-01 modified for rt2561/2661 - Jan Lee 2006-08-01 modified for rt2860 for 802.11n + John Chang 2004-09-01 modified for rt2561/2661 + Jan Lee 2006-08-01 modified for rt2860 for 802.11n + Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" @@ -233,9 +234,9 @@ void MlmeScanReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *E RTMPSuspendMsduTransmission(pAd); /* */ - /* To prevent data lost. */ - /* Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. */ - /* And should send an NULL data with turned PSM bit off to AP, when scan progress done */ + /* To prevent data loss. */ + /* Send a NULL data with turned PSM bit on to current associated AP before SCAN progress. */ + /* And should send a NULL data with turned PSM bit off to AP, when scan progress done */ /* */ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) { @@ -750,9 +751,9 @@ void PeerBeaconAtJoinAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_el /* BEACON from desired BSS/IBSS found. We should be able to decide most */ /* BSS parameters here. */ - /* Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? */ - /* Do we need to receover back all parameters belonging to previous BSS? */ - /* A. Should be not. There's no back-door recover to previous AP. It still need */ + /* Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATION? */ + /* Do we need to recover back all parameters belonging to previous BSS? */ + /* A. Should be not. There's no back-door recover to previous AP. It still needs */ /* a new JOIN-AUTH-ASSOC sequence. */ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) { DBGPRINT(RT_DEBUG_TRACE, @@ -876,7 +877,7 @@ void PeerBeaconAtJoinAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_el pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration; pAd->MlmeAux.APRalinkIe = RalinkIe; - /* Copy AP's supported rate to MlmeAux for creating assoication request */ + /* Copy AP's supported rate to MlmeAux for creating association request */ /* Also filter out not supported rate */ pAd->MlmeAux.SupRateLen = SupRateLen; NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, diff --git a/drivers/staging/rt2860/sta/wpa.c b/drivers/staging/rt2860/sta/wpa.c index 69b8a24daa21..ff348325028b 100644 --- a/drivers/staging/rt2860/sta/wpa.c +++ b/drivers/staging/rt2860/sta/wpa.c @@ -33,7 +33,8 @@ Who When What -------- ---------- ---------------------------------------------- Jan Lee 03-07-22 Initial - Paul Lin 03-11-28 Modify for supplicant + Paul Lin 03-11-28 Modify for supplicant + Justin P. Mattock 11/07/2010 Fix typos */ #include "../rt_config.h" @@ -86,7 +87,7 @@ void RTMPReportMicError(struct rt_rtmp_adapter *pAd, struct rt_cipher_key *pWpaK /* Violate MIC error counts, MIC countermeasures kicks in */ pAd->StaCfg.MicErrCnt++; /* We shall block all reception */ - /* We shall clean all Tx ring and disassoicate from AP after next EAPOL frame */ + /* We shall clean all Tx ring and disassociate from AP after next EAPOL frame */ /* */ /* No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets */ /* if pAd->StaCfg.MicErrCnt greater than 2. */ diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c index e095a44cbc0e..5717e12a9544 100644 --- a/drivers/staging/rt2860/sta_ioctl.c +++ b/drivers/staging/rt2860/sta_ioctl.c @@ -31,10 +31,11 @@ IOCTL related subroutines Revision History: - Who When What + Who When What -------- ---------- ---------------------------------------------- - Rory Chen 01-03-2003 created - Rory Chen 02-14-2005 modify to support RT61 + Rory Chen 01-03-2003 created + Rory Chen 02-14-2005 modify to support RT61 + Justin P. Mattock 11/07/2010 Fix typos */ #include "rt_config.h" @@ -851,7 +852,7 @@ int rt_ioctl_giwscan(struct net_device *dev, /* Protocol: - it will show scanned AP's WirelessMode . + it will show scanned AP's WirelessMode. it might be 802.11a 802.11a/n @@ -875,13 +876,13 @@ int rt_ioctl_giwscan(struct net_device *dev, strcpy(iwe.u.name, "802.11a"); } else { /* - if one of non B mode rate is set supported rate . it mean G only. + if one of non B mode rate is set supported rate, it means G only. */ for (rateCnt = 0; rateCnt < pBssEntry->SupRateLen; rateCnt++) { /* - 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate , it mean G only. + 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate, it means G only. */ if (pBssEntry->SupRate[rateCnt] == 140 || pBssEntry->SupRate[rateCnt] == @@ -1417,7 +1418,7 @@ int rt_ioctl_siwencode(struct net_device *dev, if ((index >= 0) && (index < 4)) { pAdapter->StaCfg.DefaultKeyId = index; } else - /* Don't complain if only change the mode */ + /* Don't complain if the mode is only changed */ if (!(erq->flags & IW_ENCODE_MODE)) return -EINVAL; } @@ -2732,8 +2733,8 @@ int Set_NetworkType_Proc(struct rt_rtmp_adapter *pAdapter, char *arg) } if (INFRA_ON(pAdapter)) { /*BOOLEAN Cancelled; */ - /* Set the AutoReconnectSsid to prevent it reconnect to old SSID */ - /* Since calling this indicate user don't want to connect to that SSID anymore. */ + /* Set the AutoReconnectSsid to prevent it from reconnecting to the old SSID */ + /* Since calling this indicates users don't want to connect to that SSID anymore. */ pAdapter->MlmeAux.AutoReconnectSsidLen = 32; NdisZeroMemory(pAdapter->MlmeAux. AutoReconnectSsid, @@ -2766,8 +2767,8 @@ int Set_NetworkType_Proc(struct rt_rtmp_adapter *pAdapter, char *arg) LinkDown(pAdapter, FALSE); } if (ADHOC_ON(pAdapter)) { - /* Set the AutoReconnectSsid to prevent it reconnect to old SSID */ - /* Since calling this indicate user don't want to connect to that SSID anymore. */ + /* Set the AutoReconnectSsid to prevent it from reconnecting to the old SSID */ + /* Since calling this indicates users don't want to connect to that SSID anymore. */ pAdapter->MlmeAux.AutoReconnectSsidLen = 32; NdisZeroMemory(pAdapter->MlmeAux. AutoReconnectSsid, @@ -2884,7 +2885,7 @@ int Set_NetworkType_Proc(struct rt_rtmp_adapter *pAdapter, char *arg) } /* Enable Rx with promiscuous reception */ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); - /* ASIC supporsts sniffer function with replacing RSSI with timestamp. */ + /* ASIC supports sniffer function with replacing RSSI with timestamp. */ /*RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); */ /*Value |= (0x80); */ /*RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); */ diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c index ebf9074a9083..a8820d3f6b3a 100644 --- a/drivers/staging/rt2860/usb_main_dev.c +++ b/drivers/staging/rt2860/usb_main_dev.c @@ -27,8 +27,8 @@ #include "rt_config.h" /* Following information will be show when you run 'modinfo' */ -/* *** If you have a solution for the bug in current version of driver, please mail to me. */ -/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** */ +/* If you have a solution for the bug in current version of driver, please e-mail me. */ +/* Otherwise post to the forum at ralinktech's web site(www.ralinktech.com) and let all users help you. */ MODULE_AUTHOR("Paul Lin "); MODULE_DESCRIPTION("RT2870/RT3070 Wireless Lan Linux Driver"); MODULE_LICENSE("GPL"); @@ -882,8 +882,8 @@ static int __devinit rt2870_probe(IN struct usb_interface *intf, if (net_dev == NULL) goto err_out_free_radev; - /* Here are the net_device structure with usb specific parameters. */ - /* for supporting Network Manager. + /* Here are the net_device structure with usb specific parameters. + * for supporting Network Manager. * Set the sysfs physical device reference for the network logical device if set prior to registration will * cause a symlink during initialization. */ diff --git a/drivers/staging/rt2860/wpa.h b/drivers/staging/rt2860/wpa.h index 6199ae6cdcd0..116fc2caa886 100644 --- a/drivers/staging/rt2860/wpa.h +++ b/drivers/staging/rt2860/wpa.h @@ -32,13 +32,14 @@ Revision History: Who When What -------- ---------- ---------------------------------------------- - Name Date Modification logs + Name Date Modification logs + Justin P. Mattock 11/07/2010 Fix a typo */ #ifndef __WPA_H__ #define __WPA_H__ -/* EAPOL Key descripter frame format related length */ +/* EAPOL Key descriptor frame format related length */ #define LEN_KEY_DESC_NONCE 32 #define LEN_KEY_DESC_IV 16 #define LEN_KEY_DESC_RSC 8 -- cgit v1.2.3 From 60a1d01bcd348ae1c791260d2df564d9ffc1ac97 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:10:15 +0100 Subject: staging, keucr: Remove unnecessary casts of void ptr returning alloc function return values Hi, The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/staging/keucr/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/keucr/ms.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/keucr/ms.c b/drivers/staging/keucr/ms.c index d4340a9da87d..64778b1e77f5 100644 --- a/drivers/staging/keucr/ms.c +++ b/drivers/staging/keucr/ms.c @@ -347,7 +347,7 @@ int MS_LibProcessBootBlock(struct us_data *us, WORD PhyBlock, BYTE *PageData) BYTE *PageBuffer; MS_LibTypeExtdat ExtraData; - if ((PageBuffer = (BYTE *)kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL))==NULL) + if ((PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL))==NULL) return (DWORD)-1; result = (DWORD)-1; @@ -480,8 +480,8 @@ int MS_LibAllocLogicalMap(struct us_data *us) DWORD i; - us->MS_Lib.Phy2LogMap = (WORD *)kmalloc(us->MS_Lib.NumberOfPhyBlock * sizeof(WORD), GFP_KERNEL); - us->MS_Lib.Log2PhyMap = (WORD *)kmalloc(us->MS_Lib.NumberOfLogBlock * sizeof(WORD), GFP_KERNEL); + us->MS_Lib.Phy2LogMap = kmalloc(us->MS_Lib.NumberOfPhyBlock * sizeof(WORD), GFP_KERNEL); + us->MS_Lib.Log2PhyMap = kmalloc(us->MS_Lib.NumberOfLogBlock * sizeof(WORD), GFP_KERNEL); if ((us->MS_Lib.Phy2LogMap == NULL) || (us->MS_Lib.Log2PhyMap == NULL)) { @@ -610,8 +610,8 @@ int MS_LibAllocWriteBuf(struct us_data *us) { us->MS_Lib.wrtblk = (WORD)-1; - us->MS_Lib.blkpag = (BYTE *)kmalloc(us->MS_Lib.PagesPerBlock * us->MS_Lib.BytesPerSector, GFP_KERNEL); - us->MS_Lib.blkext = (MS_LibTypeExtdat *)kmalloc(us->MS_Lib.PagesPerBlock * sizeof(MS_LibTypeExtdat), GFP_KERNEL); + us->MS_Lib.blkpag = kmalloc(us->MS_Lib.PagesPerBlock * us->MS_Lib.BytesPerSector, GFP_KERNEL); + us->MS_Lib.blkext = kmalloc(us->MS_Lib.PagesPerBlock * sizeof(MS_LibTypeExtdat), GFP_KERNEL); if ((us->MS_Lib.blkpag == NULL) || (us->MS_Lib.blkext == NULL)) { -- cgit v1.2.3 From 131a14b3f0330a844f79c6b87c0fe57ec86faf62 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:10:25 +0100 Subject: staging, rt2860: Remove unnecessary casts of void ptr returning alloc function return values Hi, The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/staging/rt2860/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/common/ba_action.c | 12 ++++++------ drivers/staging/rt2860/rt_main_dev.c | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/common/ba_action.c b/drivers/staging/rt2860/common/ba_action.c index 8eef82d92621..ed8854b902d1 100644 --- a/drivers/staging/rt2860/common/ba_action.c +++ b/drivers/staging/rt2860/common/ba_action.c @@ -799,8 +799,8 @@ void BAOriSessionTearDown(struct rt_rtmp_adapter *pAd, /* force send specified TID DelBA */ struct rt_mlme_delba_req DelbaReq; struct rt_mlme_queue_elem *Elem = - (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem), - MEM_ALLOC_FLAG); + kmalloc(sizeof(struct rt_mlme_queue_elem), + MEM_ALLOC_FLAG); if (Elem != NULL) { NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem)); @@ -839,8 +839,8 @@ void BAOriSessionTearDown(struct rt_rtmp_adapter *pAd, && (pBAEntry->ORI_BA_Status == Originator_Done)) { struct rt_mlme_delba_req DelbaReq; struct rt_mlme_queue_elem *Elem = - (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem), - MEM_ALLOC_FLAG); + kmalloc(sizeof(struct rt_mlme_queue_elem), + MEM_ALLOC_FLAG); if (Elem != NULL) { NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem)); @@ -908,8 +908,8 @@ void BARecSessionTearDown(struct rt_rtmp_adapter *pAd, /* */ if (bPassive == FALSE) { struct rt_mlme_queue_elem *Elem = - (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem), - MEM_ALLOC_FLAG); + kmalloc(sizeof(struct rt_mlme_queue_elem), + MEM_ALLOC_FLAG); if (Elem != NULL) { NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); NdisZeroMemory(Elem, sizeof(struct rt_mlme_queue_elem)); diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index 19e9bc6569f8..e8648219e0b5 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -102,8 +102,8 @@ int MainVirtualIF_close(IN struct net_device *net_dev) (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) { struct rt_mlme_disassoc_req DisReq; struct rt_mlme_queue_elem *MsgElem = - (struct rt_mlme_queue_elem *)kmalloc(sizeof(struct rt_mlme_queue_elem), - MEM_ALLOC_FLAG); + kmalloc(sizeof(struct rt_mlme_queue_elem), + MEM_ALLOC_FLAG); if (MsgElem) { COPY_MAC_ADDR(DisReq.Addr, @@ -725,7 +725,8 @@ Note: int AdapterBlockAllocateMemory(void *handle, void ** ppAd) { - *ppAd = (void *)vmalloc(sizeof(struct rt_rtmp_adapter)); /*pci_alloc_consistent(pci_dev, sizeof(struct rt_rtmp_adapter), phy_addr); */ + *ppAd = vmalloc(sizeof(struct rt_rtmp_adapter)); + /* pci_alloc_consistent(pci_dev, sizeof(struct rt_rtmp_adapter), phy_addr); */ if (*ppAd) { NdisZeroMemory(*ppAd, sizeof(struct rt_rtmp_adapter)); -- cgit v1.2.3 From 3c4e9c84970e555a80a4c92a5a3d3125c63f0e12 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:09:38 +0100 Subject: staging, ath6kl: Remove unnecessary casts of void ptr returning alloc function return values Hi, The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/staging/ath6kl/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c index c307a5559362..6454a86c174c 100644 --- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c +++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c @@ -1188,7 +1188,7 @@ addHifDevice(struct sdio_func *func) HIF_DEVICE *hifdevice; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: addHifDevice\n")); AR_DEBUG_ASSERT(func != NULL); - hifdevice = (HIF_DEVICE *)kzalloc(sizeof(HIF_DEVICE), GFP_KERNEL); + hifdevice = kzalloc(sizeof(HIF_DEVICE), GFP_KERNEL); AR_DEBUG_ASSERT(hifdevice != NULL); #if HIF_USE_DMA_BOUNCE_BUFFER hifdevice->dma_buffer = kmalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL); -- cgit v1.2.3 From 5ef3df5b9fed56e64e8544e36a175354d38d0206 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:10:44 +0100 Subject: staging, wlags49_h2: Remove unnecessary casts of void ptr returning alloc function return values Hi, The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/staging/wlags49_h2/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlags49_h2/wl_profile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c index 7a1337db7aa1..a459e48c7bf0 100644 --- a/drivers/staging/wlags49_h2/wl_profile.c +++ b/drivers/staging/wlags49_h2/wl_profile.c @@ -248,7 +248,7 @@ void parse_config(struct net_device *dev) } else { DBG_TRACE(DbgInfo, "F/W image file found\n"); #define DHF_ALLOC_SIZE 96000 /* just below 96K, let's hope it suffices for now and for the future */ - cp = (char *)vmalloc(DHF_ALLOC_SIZE); + cp = vmalloc(DHF_ALLOC_SIZE); if (cp == NULL) { DBG_ERROR(DbgInfo, "error in vmalloc\n"); } else { -- cgit v1.2.3 From 0a1c62dedc6e28a1117b00c4ccb4427bc91b9f29 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:10:35 +0100 Subject: staging, spectra: Remove unnecessary casts of void ptr returning alloc function return values Hi, The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/staging/spectra/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/lld_emu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/spectra/lld_emu.c b/drivers/staging/spectra/lld_emu.c index 6733bbf8016d..095f2f0c2e5b 100644 --- a/drivers/staging/spectra/lld_emu.c +++ b/drivers/staging/spectra/lld_emu.c @@ -180,10 +180,8 @@ u16 emu_Flash_Init(void) nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); - flash_memory[0] = (u8 *)vmalloc(GLOB_LLD_PAGE_SIZE * - GLOB_LLD_BLOCKS * - GLOB_LLD_PAGES * - sizeof(u8)); + flash_memory[0] = vmalloc(GLOB_LLD_PAGE_SIZE * GLOB_LLD_BLOCKS * + GLOB_LLD_PAGES * sizeof(u8)); if (!flash_memory[0]) { printk(KERN_ERR "Fail to allocate memory " "for nand emulator!\n"); -- cgit v1.2.3 From 33d2323711059d14fd675fa7def317e560fa787e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 10 Nov 2010 13:59:09 +0000 Subject: drm/i915: Unconditionally get the fence reg when pinning scanout We use i915_gem_object_get_fence_reg() to do LRU tracking of the fence registers, so stop trying to be too clever when pinning the fb->obj. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c41dae5ade32..63770c963077 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1474,8 +1474,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * framebuffer compression. For simplicity, we always install * a fence as the cost is not that onerous. */ - if (obj_priv->fence_reg == I915_FENCE_REG_NONE && - obj_priv->tiling_mode != I915_TILING_NONE) { + if (obj_priv->tiling_mode != I915_TILING_NONE) { ret = i915_gem_object_get_fence_reg(obj, false); if (ret) goto err_unpin; -- cgit v1.2.3 From 5d97eb69bd4767ce9973360881fa6ad161510fb0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 10 Nov 2010 20:40:02 +0000 Subject: drm/i915: Only add the lazy request if we end up waiting for it. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 9 +++------ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7c91bf2bbdfd..52f5c194c50f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1664,9 +1664,7 @@ i915_gem_next_request_seqno(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - - ring->outstanding_lazy_request = true; - return dev_priv->next_seqno; + return ring->outstanding_lazy_request = dev_priv->next_seqno; } static void @@ -2072,7 +2070,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (atomic_read(&dev_priv->mm.wedged)) return -EAGAIN; - if (ring->outstanding_lazy_request) { + if (seqno == ring->outstanding_lazy_request) { struct drm_i915_gem_request *request; request = kzalloc(sizeof(*request), GFP_KERNEL); @@ -2087,7 +2085,6 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, seqno = request->seqno; } - BUG_ON(seqno == dev_priv->next_seqno); if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) { if (HAS_PCH_SPLIT(dev)) @@ -3973,7 +3970,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_retire_commands(dev, ring); if (i915_add_request(dev, file, request, ring)) - ring->outstanding_lazy_request = true; + i915_gem_next_request_seqno(dev, ring); else request = NULL; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 68043f1a186e..d73145c790bd 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -87,7 +87,7 @@ struct intel_ring_buffer { /** * Do we have some not yet emitted requests outstanding? */ - bool outstanding_lazy_request; + u32 outstanding_lazy_request; wait_queue_head_t irq_queue; drm_local_map_t map; -- cgit v1.2.3 From a10bb4fb199bd7a1dc178a6228ad749f5070e0f9 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 9 Nov 2010 18:26:34 -0600 Subject: staging: r8712u: Update TODO for sparse fixes Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/TODO | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/TODO b/drivers/staging/rtl8712/TODO index 5c888214666e..2aa5deb3af7b 100644 --- a/drivers/staging/rtl8712/TODO +++ b/drivers/staging/rtl8712/TODO @@ -3,7 +3,6 @@ TODO: - switch to use LIB80211 - switch to use MAC80211 - checkpatch.pl fixes - only a few remain -- sparse fixes - switch from large inline firmware file to use the firmware interface and add the file to the linux-firmware package. -- cgit v1.2.3 From c8b124e21dbb7f4941f292fea446ce63d92d80dd Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 10 Nov 2010 09:29:35 +0100 Subject: staging: ft1000: Check return value of kthread_run. kthread_run could fail so we will check return value. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 41bbe991f0de..dcbc97c432e5 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -175,6 +175,12 @@ static int ft1000_probe(struct usb_interface *interface, gPollingfailed = FALSE; pft1000info->pPollThread = kthread_run(ft1000_poll_thread, ft1000dev, "ft1000_poll"); + + if (IS_ERR(pft1000info->pPollThread)) { + ret = PTR_ERR(pft1000info->pPollThread); + goto err_load; + } + msleep(500); while (!pft1000info->CardReady) { -- cgit v1.2.3 From 2dab1ac81b4767095f96503a9ac093a68c6e9c95 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 10 Nov 2010 10:04:30 +0100 Subject: staging: ft1000: Create common return point. When reg_ft1000_netdev() fails created kthread isn't stopped. So add return point for stopping thread. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index dcbc97c432e5..99e333902376 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -178,15 +178,13 @@ static int ft1000_probe(struct usb_interface *interface, if (IS_ERR(pft1000info->pPollThread)) { ret = PTR_ERR(pft1000info->pPollThread); - goto err_load; + goto err_thread; } msleep(500); while (!pft1000info->CardReady) { if (gPollingfailed) { - if (pft1000info->pPollThread) - kthread_stop(pft1000info->pPollThread); ret = -EIO; goto err_load; } @@ -207,6 +205,8 @@ static int ft1000_probe(struct usb_interface *interface, return 0; err_load: + kthread_stop(pft1000info->pPollThread); +err_thread: kfree(pFileStart); err_fw: kfree(ft1000dev); -- cgit v1.2.3 From b706113f1475ce983faabf12120ac4e90d512d02 Mon Sep 17 00:00:00 2001 From: "Alejandro R. Sedeño" Date: Wed, 10 Nov 2010 01:42:01 -0500 Subject: Staging: beceem: Use 32-bit integers for hardware register values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switching to UINT because that's what the rest of this codebase uses. Signed-off-by: Alejandro R. Sedeño Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/Adapter.h | 4 ++-- drivers/staging/bcm/DDRInit.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 62f9135d4d40..32909e2938d5 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -601,8 +601,8 @@ typedef LINK_REQUEST CONTROL_MESSAGE; typedef struct _DDR_SETTING { - ULONG ulRegAddress; - ULONG ulRegValue; + UINT ulRegAddress; + UINT ulRegValue; }DDR_SETTING, *PDDR_SETTING; typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE; INT diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c index 411f02a6b6ea..1c7db81a1ee8 100644 --- a/drivers/staging/bcm/DDRInit.c +++ b/drivers/staging/bcm/DDRInit.c @@ -776,7 +776,7 @@ int ddr_init(MINI_ADAPTER *Adapter) { PDDR_SETTING psDDRSetting=NULL; ULONG RegCount=0; - ULONG value = 0; + UINT value = 0; UINT uiResetValue = 0; UINT uiClockSetting = 0; int retval = STATUS_SUCCESS; @@ -970,7 +970,7 @@ int ddr_init(MINI_ADAPTER *Adapter) { value = psDDRSetting->ulRegValue; } - retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, (PUINT)&value, sizeof(value)); + retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value, sizeof(value)); if(STATUS_SUCCESS != retval) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__); break; -- cgit v1.2.3 From 16618c20e18d60b2c8908b7758228a62a450769a Mon Sep 17 00:00:00 2001 From: "Alejandro R. Sedeño" Date: Wed, 10 Nov 2010 01:42:02 -0500 Subject: Staging: beceem: Move ZTE TU25's USB id to the beceem module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro R. Sedeño Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 2 +- drivers/staging/bcm/InterfaceInit.h | 1 + drivers/usb/serial/option.c | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 8a26a3ef5bd3..869ebabfba77 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -6,7 +6,7 @@ static struct usb_device_id InterfaceUsbtable[] = { { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, - + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) }, { } }; MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h index 3b8e17b619ba..091cf78d63a1 100644 --- a/drivers/staging/bcm/InterfaceInit.h +++ b/drivers/staging/bcm/InterfaceInit.h @@ -11,6 +11,7 @@ #define BCM_USB_PRODUCT_ID_SYM 0x15E #define BCM_USB_PRODUCT_ID_1901 0xe017 #define BCM_USB_PRODUCT_ID_226 0x0132 +#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007 #define BCM_USB_MINOR_BASE 192 diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2297fb1bcf65..b17896e58c5f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -615,7 +615,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) }, -- cgit v1.2.3 From afabbe6db368fbed0569d31d402aceb631d9f854 Mon Sep 17 00:00:00 2001 From: facugaich Date: Wed, 10 Nov 2010 10:39:33 -0300 Subject: Staging: solo6x10: Fix checkpatch errors and most warnings This patch fixes all errors and most warnings reported by checkpatch.pl for all the files in the driver. v2: Fix a typo and update the patch against the latest HEAD Signed-off-by: Facundo Gaich Signed-off-by: Greg Kroah-Hartman --- drivers/staging/solo6x10/solo6010-core.c | 30 +++---- drivers/staging/solo6x10/solo6010-disp.c | 4 +- drivers/staging/solo6x10/solo6010-enc.c | 2 +- drivers/staging/solo6x10/solo6010-g723.c | 8 +- drivers/staging/solo6x10/solo6010-i2c.c | 5 +- drivers/staging/solo6x10/solo6010-osd-font.h | 60 +++++++------- drivers/staging/solo6x10/solo6010-p2m.c | 4 +- drivers/staging/solo6x10/solo6010-tw28.c | 118 +++++++++++++-------------- drivers/staging/solo6x10/solo6010-v4l2-enc.c | 20 +++-- drivers/staging/solo6x10/solo6010-v4l2.c | 19 +++-- drivers/staging/solo6x10/solo6010.h | 4 +- 11 files changed, 142 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/solo6010-core.c b/drivers/staging/solo6x10/solo6010-core.c index 9dad749ca963..c433136f972c 100644 --- a/drivers/staging/solo6x10/solo6010-core.c +++ b/drivers/staging/solo6x10/solo6010-core.c @@ -164,21 +164,21 @@ static int __devinit solo6010_pci_probe(struct pci_dev *pdev, chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & SOLO_CHIP_ID_MASK; switch (chip_id) { - case 7: - solo_dev->nr_chans = 16; - solo_dev->nr_ext = 5; - break; - case 6: - solo_dev->nr_chans = 8; - solo_dev->nr_ext = 2; - break; - default: - dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, " - "defaulting to 4 channels\n", - chip_id); - case 5: - solo_dev->nr_chans = 4; - solo_dev->nr_ext = 1; + case 7: + solo_dev->nr_chans = 16; + solo_dev->nr_ext = 5; + break; + case 6: + solo_dev->nr_chans = 8; + solo_dev->nr_ext = 2; + break; + default: + dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, " + "defaulting to 4 channels\n", + chip_id); + case 5: + solo_dev->nr_chans = 4; + solo_dev->nr_ext = 1; } /* Disable all interrupts to start */ diff --git a/drivers/staging/solo6x10/solo6010-disp.c b/drivers/staging/solo6x10/solo6010-disp.c index a15151d15ea5..f866f8438175 100644 --- a/drivers/staging/solo6x10/solo6010-disp.c +++ b/drivers/staging/solo6x10/solo6010-disp.c @@ -203,7 +203,7 @@ static void solo_motion_config(struct solo6010_dev *solo_dev) solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, SOLO_VI_MOTION_FRAME_COUNT(3) | SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) - | //SOLO_VI_MOTION_INTR_START_STOP | + | /* SOLO_VI_MOTION_INTR_START_STOP | */ SOLO_VI_MOTION_SAMPLE_COUNT(10)); solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); @@ -264,7 +264,7 @@ void solo_disp_exit(struct solo6010_dev *solo_dev) solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0); solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0); solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0); - + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0); solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0); solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0); diff --git a/drivers/staging/solo6x10/solo6010-enc.c b/drivers/staging/solo6x10/solo6010-enc.c index 42314a1e3250..481a49277f77 100644 --- a/drivers/staging/solo6x10/solo6010-enc.c +++ b/drivers/staging/solo6x10/solo6010-enc.c @@ -22,7 +22,7 @@ #include "solo6010.h" #include "solo6010-osd-font.h" -#define CAPTURE_MAX_BANDWIDTH 32 // D1 4channel (D1 == 4) +#define CAPTURE_MAX_BANDWIDTH 32 /* D1 4channel (D1 == 4) */ #define OSG_BUFFER_SIZE 1024 #define VI_PROG_HSIZE (1280 - 16) diff --git a/drivers/staging/solo6x10/solo6010-g723.c b/drivers/staging/solo6x10/solo6010-g723.c index 63a1b5b64b56..254b46ab20c5 100644 --- a/drivers/staging/solo6x10/solo6010-g723.c +++ b/drivers/staging/solo6x10/solo6010-g723.c @@ -47,7 +47,7 @@ * is broken down to 20 * 48 byte regions (one for each channel possible) * with the rest of the page being dummy data. */ #define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) -#define IRQ_PAGES 4 // 0 - 4 +#define IRQ_PAGES 4 /* 0 - 4 */ #define PERIODS_MIN (1 << IRQ_PAGES) #define PERIODS_MAX G723_FDMA_PAGES @@ -372,10 +372,12 @@ int solo_g723_init(struct solo6010_dev *solo_dev) if (ret < 0) return ret; - if ((ret = solo_snd_pcm_init(solo_dev)) < 0) + ret = solo_snd_pcm_init(solo_dev); + if (ret < 0) goto snd_error; - if ((ret = snd_card_register(card)) < 0) + ret = snd_card_register(card); + if (ret < 0) goto snd_error; solo_g723_config(solo_dev); diff --git a/drivers/staging/solo6x10/solo6010-i2c.c b/drivers/staging/solo6x10/solo6010-i2c.c index c1d4a23f4275..60b69cd0d09d 100644 --- a/drivers/staging/solo6x10/solo6010-i2c.c +++ b/drivers/staging/solo6x10/solo6010-i2c.c @@ -225,7 +225,7 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap, } if (i == SOLO_I2C_ADAPTERS) - return num; // XXX Right return value for failure? + return num; /* XXX Right return value for failure? */ mutex_lock(&solo_dev->i2c_mutex); solo_dev->i2c_id = i; @@ -296,7 +296,8 @@ int solo_i2c_init(struct solo6010_dev *solo_dev) adap->retries = 1; adap->dev.parent = &solo_dev->pdev->dev; - if ((ret = i2c_add_adapter(adap))) { + ret = i2c_add_adapter(adap); + if (ret) { adap->algo_data = NULL; break; } diff --git a/drivers/staging/solo6x10/solo6010-osd-font.h b/drivers/staging/solo6x10/solo6010-osd-font.h index d6f565bd76cc..d72efbb3bb3d 100644 --- a/drivers/staging/solo6x10/solo6010-osd-font.h +++ b/drivers/staging/solo6x10/solo6010-osd-font.h @@ -22,7 +22,7 @@ static const unsigned int solo_osd_font[] = { 0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000, - 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, // 0 + 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */ 0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000, 0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000, 0x00000000, 0x00001038, 0x10000000, 0x00000000, @@ -54,67 +54,67 @@ static const unsigned int solo_osd_font[] = { 0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000, 0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, // 32 ! + 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32 ! */ 0x00000066, 0x66240000, 0x00000000, 0x00000000, - 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, // 34 " # + 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */ 0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000, - 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, // 36 $ % + 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */ 0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000, - 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, // 38 & ' + 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */ 0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000, - 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, // 40 ( ) + 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */ 0x00000000, 0x0000663c, 0xff3c6600, 0x00000000, - 0x00000000, 0x00001818, 0x7e181800, 0x00000000, // 42 * + + 0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */ 0x00000000, 0x00000000, 0x00000e0e, 0x0c060000, - 0x00000000, 0x00000000, 0x7e000000, 0x00000000, // 44 , - + 0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */ 0x00000000, 0x00000000, 0x00000006, 0x06000000, - 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, // 46 . / + 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */ 0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000, - 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, // 48 0 1 + 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */ 0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000, - 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, // 50 2 3 + 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */ 0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000, - 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, // 52 4 5 + 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */ 0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000, - 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, // 54 6 7 + 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */ 0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000, - 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, // 56 8 9 + 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */ 0x00000000, 0x18180000, 0x00181800, 0x00000000, - 0x00000000, 0x18180000, 0x0018180c, 0x00000000, // 58 : ; + 0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */ 0x00000060, 0x30180c06, 0x0c183060, 0x00000000, 0x00000000, 0x007e0000, 0x007e0000, 0x00000000, 0x00000006, 0x0c183060, 0x30180c06, 0x00000000, 0x0000007c, 0xc6c66030, 0x30003030, 0x00000000, 0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000, - 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, // 64 @ A + 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */ 0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000, - 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, // 66 + 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */ 0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000, - 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, // 68 + 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */ 0x000000fe, 0x0606063e, 0x06060606, 0x00000000, - 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, // 70 + 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */ 0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000, - 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, // 72 + 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */ 0x00000060, 0x60606060, 0x6066663c, 0x00000000, - 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, // 74 + 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */ 0x00000006, 0x06060606, 0x060606fe, 0x00000000, - 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, // 76 + 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */ 0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000, - 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, // 78 + 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */ 0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000, - 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, // 80 + 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */ 0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000, - 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, // 82 + 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */ 0x0000007e, 0x18181818, 0x18181818, 0x00000000, - 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, // 84 + 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */ 0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000, - 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, // 86 + 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */ 0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000, - 0x00000066, 0x66666666, 0x3c181818, 0x00000000, // 88 + 0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */ 0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000, - 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, // 90 + 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */ 0x00000002, 0x060c1830, 0x60c08000, 0x00000000, - 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, // 92 + 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */ 0x00001038, 0x6cc60000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00fe0000, 0x00001818, 0x30000000, 0x00000000, 0x00000000, diff --git a/drivers/staging/solo6x10/solo6010-p2m.c b/drivers/staging/solo6x10/solo6010-p2m.c index c91fc4652a00..956dea09348a 100644 --- a/drivers/staging/solo6x10/solo6010-p2m.c +++ b/drivers/staging/solo6x10/solo6010-p2m.c @@ -22,7 +22,7 @@ #include "solo6010.h" -// #define SOLO_TEST_P2M +/* #define SOLO_TEST_P2M */ int solo_p2m_dma(struct solo6010_dev *solo_dev, u8 id, int wr, void *sys_addr, u32 ext_addr, u32 size) @@ -244,7 +244,7 @@ static void run_p2m_test(struct solo6010_dev *solo_dev) return; } #else -#define run_p2m_test(__solo) do{}while(0) +#define run_p2m_test(__solo) do {} while (0) #endif void solo_p2m_isr(struct solo6010_dev *solo_dev, int id) diff --git a/drivers/staging/solo6x10/solo6010-tw28.c b/drivers/staging/solo6x10/solo6010-tw28.c index 0159c8392436..905a6ad23a37 100644 --- a/drivers/staging/solo6x10/solo6010-tw28.c +++ b/drivers/staging/solo6x10/solo6010-tw28.c @@ -35,107 +35,107 @@ #define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) static u8 tbl_tw2864_template[] = { - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x00 + 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x10 + 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x20 + 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x30 + 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, - 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, // 0x80 + 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, // 0x90 + 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01, - 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, // 0xa0 + 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, - 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, // 0xb0 + 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, - 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, // 0xd0 + 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, - 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, // 0xe0 + 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0 + 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, }; static u8 tbl_tw2865_ntsc_template[] = { - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x00 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x10 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x20 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, // 0x30 + 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, // 0x40 + 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */ 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 + 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, - 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70 + 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, - 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80 + 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90 + 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, - 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, // 0xa0 + 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */ 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, - 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0 + 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8, - 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 + 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, - 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0 + 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, - 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0 + 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0 + 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, }; static u8 tbl_tw2865_pal_template[] = { - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x00 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x10 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x20 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x30 + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, // 0x40 + 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */ 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 + 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, - 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70 + 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, - 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80 + 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90 + 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, - 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, // 0xa0 + 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */ 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, - 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0 + 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8, - 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 + 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, - 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0 + 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, - 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0 + 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, // 0xf0 + 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */ 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, }; @@ -181,8 +181,8 @@ static void tw_write_and_verify(struct solo6010_dev *solo_dev, u8 addr, u8 off, msleep_interruptible(1); } -// printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n", -// addr, off, val); +/* printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n", + addr, off, val); */ } static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr) @@ -217,7 +217,7 @@ static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr) for (i = 0; i < 0xff; i++) { /* Skip read only registers */ - if (i >= 0xb8 && i <= 0xc1 ) + if (i >= 0xb8 && i <= 0xc1) continue; if ((i & ~0x30) == 0x00 || (i & ~0x30) == 0x0c || @@ -302,7 +302,7 @@ static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr) for (i = 0; i < 0xff; i++) { /* Skip read only registers */ - if (i >= 0xb8 && i <= 0xc1 ) + if (i >= 0xb8 && i <= 0xc1) continue; if ((i & ~0x30) == 0x00 || (i & ~0x30) == 0x0c || @@ -334,13 +334,13 @@ static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr) }; u8 tbl_tw2815_sfr[] = { - 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, // 0x00 + 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */ 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, // 0x10 + 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */ 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00, - 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, // 0x20 + 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */ 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88, - 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, // 0x30 + 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */ }; u8 *tbl_tw2815_common; int i; @@ -459,7 +459,7 @@ static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr) for (i = 0; i < 0x0f; i++) { if (i == 0x00) - continue; // read-only + continue; /* read-only */ solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, (ch * 0x10) + i, tbl_tw2815_common[i]); @@ -597,7 +597,7 @@ int solo_tw28_init(struct solo6010_dev *solo_dev) return 0; } -/* +/* * We accessed the video status signal in the Techwell chip through * iic/i2c because the video status reported by register REG_VI_STATUS1 * (address 0x012C) of the SOLO6010 chip doesn't give the correct video @@ -751,7 +751,7 @@ int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch, rval = tw_readbyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch), TW_BRIGHTNESS_ADDR(ch)); - if (is_tw286x(solo_dev, chip_num)) + if (is_tw286x(solo_dev, chip_num)) *val = (s32)((char)rval) + 128; else *val = rval; diff --git a/drivers/staging/solo6x10/solo6010-v4l2-enc.c b/drivers/staging/solo6x10/solo6010-v4l2-enc.c index 5e2001aeb846..7bbb94097d29 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2-enc.c +++ b/drivers/staging/solo6x10/solo6010-v4l2-enc.c @@ -598,7 +598,8 @@ static void solo_enc_fillbuf(struct solo_enc_fh *fh, goto buf_err; } - if (WARN_ON_ONCE(!(vbuf = videobuf_to_dma(vb)))) + vbuf = videobuf_to_dma(vb); + if (WARN_ON_ONCE(!vbuf)) goto buf_err; if (fh->fmt == V4L2_PIX_FMT_MPEG) @@ -731,7 +732,8 @@ void solo_enc_v4l2_isr(struct solo6010_dev *solo_dev) jpeg_next = solo_reg_read(solo_dev, SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); - if ((ch = (mpeg_current >> 24) & 0x1f) >= SOLO_MAX_CHANNELS) { + ch = (mpeg_current >> 24) & 0x1f; + if (ch >= SOLO_MAX_CHANNELS) { ch -= SOLO_MAX_CHANNELS; enc_type = SOLO_ENC_TYPE_EXT; } else @@ -872,7 +874,8 @@ static int solo_enc_open(struct file *file) struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_enc_fh *fh; - if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL) + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (fh == NULL) return -ENOMEM; fh->enc = solo_enc; @@ -1042,9 +1045,8 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, if (pix->field == V4L2_FIELD_ANY) pix->field = V4L2_FIELD_INTERLACED; - else if (pix->field != V4L2_FIELD_INTERLACED) { + else if (pix->field != V4L2_FIELD_INTERLACED) pix->field = V4L2_FIELD_INTERLACED; - } /* Just set these */ pix->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -1064,7 +1066,8 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, spin_lock(&solo_enc->lock); - if ((ret = solo_enc_try_fmt_cap(file, priv, f))) { + ret = solo_enc_try_fmt_cap(file, priv, f); + if (ret) { spin_unlock(&solo_enc->lock); return ret; } @@ -1107,7 +1110,7 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, return 0; } -static int solo_enc_reqbufs(struct file *file, void *priv, +static int solo_enc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { struct solo_enc_fh *fh = priv; @@ -1388,7 +1391,8 @@ static int solo_querymenu(struct file *file, void *priv, int err; qctrl.id = qmenu->id; - if ((err = solo_queryctrl(file, priv, &qctrl))) + err = solo_queryctrl(file, priv, &qctrl); + if (err) return err; return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); diff --git a/drivers/staging/solo6x10/solo6010-v4l2.c b/drivers/staging/solo6x10/solo6010-v4l2.c index 7a9c348de565..a8491dc0e914 100644 --- a/drivers/staging/solo6x10/solo6010-v4l2.c +++ b/drivers/staging/solo6x10/solo6010-v4l2.c @@ -245,15 +245,16 @@ static void solo_fillbuf(struct solo_filehandle *fh, struct videobuf_buffer *vb) { struct solo6010_dev *solo_dev = fh->solo_dev; - struct videobuf_dmabuf* vbuf; + struct videobuf_dmabuf *vbuf; unsigned int fdma_addr; int error = 1; int i; - struct scatterlist* sg; + struct scatterlist *sg; dma_addr_t sg_dma; int sg_size_left; - if (!(vbuf = videobuf_to_dma(vb))) + vbuf = videobuf_to_dma(vb); + if (!vbuf) goto finish_buf; if (erase_off(solo_dev)) { @@ -524,7 +525,8 @@ static int solo_v4l2_open(struct file *file) struct solo_filehandle *fh; int ret; - if ((fh = kzalloc(sizeof(*fh), GFP_KERNEL)) == NULL) + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (fh == NULL) return -ENOMEM; spin_lock_init(&fh->slock); @@ -532,7 +534,8 @@ static int solo_v4l2_open(struct file *file) fh->solo_dev = solo_dev; file->private_data = fh; - if ((ret = solo_start_thread(fh))) { + ret = solo_start_thread(fh); + if (ret) { kfree(fh); return ret; } @@ -726,7 +729,7 @@ static int solo_get_fmt_cap(struct file *file, void *priv, return 0; } -static int solo_reqbufs(struct file *file, void *priv, +static int solo_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { struct solo_filehandle *fh = priv; @@ -940,13 +943,13 @@ int solo_v4l2_init(struct solo6010_dev *solo_dev) for (i = 0; i < solo_dev->nr_chans; i++) { solo_v4l2_set_ch(solo_dev, i); while (erase_off(solo_dev)) - ;// Do nothing + ;/* Do nothing */ } /* Set the default display channel */ solo_v4l2_set_ch(solo_dev, 0); while (erase_off(solo_dev)) - ;// Do nothing + ;/* Do nothing */ solo6010_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h index 9f5d2a326ae1..9c930f3a017b 100644 --- a/drivers/staging/solo6x10/solo6010.h +++ b/drivers/staging/solo6x10/solo6010.h @@ -68,7 +68,7 @@ #define SOLO6010_VER_MINOR 0 #define SOLO6010_VER_SUB 0 #define SOLO6010_VER_NUM \ - KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB) + KERNEL_VERSION(SOLO6010_VER_MAJOR, SOLO6010_VER_MINOR, SOLO6010_VER_SUB) /* * The SOLO6010 actually has 8 i2c channels, but we only use 2. @@ -221,7 +221,7 @@ struct solo6010_dev { struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS]; /* Current video settings */ - u32 video_type; + u32 video_type; u16 video_hsize, video_vsize; u16 vout_hstart, vout_vstart; u16 vin_hstart, vin_vstart; -- cgit v1.2.3 From 3701befc44eb9b0e5a0e0b7169448658919b9850 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 10 Nov 2010 21:31:38 +0100 Subject: Staging, bcm: Remove unnecessary casts of void ptr returning alloc function return values Here's a patch against a copy of linux-next that I just cloned. Don't pointlessly cast pointers returned by allocation functions that return void pointers which are implicitly converted. For drivers/staging/bcm/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/CmHost.c | 2 +- drivers/staging/bcm/InterfaceDld.c | 14 ++++++-------- drivers/staging/bcm/Misc.c | 15 ++++++--------- 3 files changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 38b64e69d81a..a685cadb778d 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -1702,7 +1702,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *p } // For DSA_REQ, only upto "psfAuthorizedSet" parameter should be accessed by driver! - pstAddIndication=(stLocalSFAddIndication *)kmalloc(sizeof(*pstAddIndication), GFP_KERNEL); + pstAddIndication=kmalloc(sizeof(*pstAddIndication), GFP_KERNEL); if(NULL==pstAddIndication) return 0; diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c index 1fc36a15f187..df64acb06126 100644 --- a/drivers/staging/bcm/InterfaceDld.c +++ b/drivers/staging/bcm/InterfaceDld.c @@ -5,15 +5,14 @@ int InterfaceFileDownload( PVOID arg, struct file *flp, unsigned int on_chip_loc) { - char *buff=NULL; // unsigned int reg=0; mm_segment_t oldfs={0}; int errno=0, len=0 /*,is_config_file = 0*/; loff_t pos=0; PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)arg; //PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter; + char *buff=kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); - buff=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); if(!buff) { return -ENOMEM; @@ -56,7 +55,7 @@ int InterfaceFileReadbackFromChip( PVOID arg, struct file *flp, unsigned int on_chip_loc) { - char *buff=NULL, *buff_readback=NULL; + char *buff, *buff_readback; unsigned int reg=0; mm_segment_t oldfs={0}; int errno=0, len=0, is_config_file = 0; @@ -65,8 +64,8 @@ int InterfaceFileReadbackFromChip( PVOID arg, INT Status = STATUS_SUCCESS; PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)arg; - buff=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA); - buff_readback=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA); + buff=kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA); + buff_readback=kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA); if(!buff || !buff_readback) { kfree(buff); @@ -287,7 +286,7 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo) else { - buff = (PUCHAR)kzalloc(psFwInfo->u32FirmwareLength,GFP_KERNEL); + buff = kzalloc(psFwInfo->u32FirmwareLength,GFP_KERNEL); if(buff==NULL) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"Failed in allocation memory"); @@ -345,11 +344,10 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter, PUCHAR mappedbuffer, UINT u32FirmwareLength, ULONG u32StartingAddress) { - PUCHAR readbackbuff = NULL; UINT len = u32FirmwareLength; INT retval = STATUS_SUCCESS; + PUCHAR readbackbuff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB,GFP_KERNEL); - readbackbuff = (PUCHAR)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB,GFP_KERNEL); if(NULL == readbackbuff) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "MEMORY ALLOCATION FAILED"); diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 82d9f86821ca..1bb6a1d97ce0 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -71,8 +71,7 @@ InitAdapter(PMINI_ADAPTER psAdapter) default_wimax_protocol_initialize(psAdapter); for (i=0;itxctlpacket[i] = (char *)kmalloc(MAX_CNTL_PKT_SIZE, - GFP_KERNEL); + psAdapter->txctlpacket[i] = kmalloc(MAX_CNTL_PKT_SIZE, GFP_KERNEL); if(!psAdapter->txctlpacket[i]) { BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No More Cntl pkts got, max got is %d", i); @@ -1228,11 +1227,11 @@ static int bcm_parse_target_params(PMINI_ADAPTER Adapter) { struct file *flp=NULL; mm_segment_t oldfs={0}; - char *buff = NULL; + char *buff; int len = 0; loff_t pos = 0; - buff=(PCHAR)kmalloc(BUFFER_1K, GFP_KERNEL); + buff=kmalloc(BUFFER_1K, GFP_KERNEL); if(!buff) { return -ENOMEM; @@ -1393,12 +1392,10 @@ static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter) #if 0 static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress) { - unsigned char *pucmacaddr = NULL; - int status = 0, i=0; - unsigned int temp =0; + int status = 0, i = 0; + unsigned int temp = 0; + unsigned char *pucmacaddr = kmalloc(MAC_ADDRESS_SIZE, GFP_KERNEL); - - pucmacaddr = (unsigned char *)kmalloc(MAC_ADDRESS_SIZE, GFP_KERNEL); if(!pucmacaddr) { BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "No Buffers to Read the EEPROM Address\n"); -- cgit v1.2.3 From 319684b1cd15f24120b9513b38a949539c0b7938 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Sat, 6 Nov 2010 21:19:22 -0400 Subject: driver core: fix whitespace in class_attr_string 869dfc875e3 addded a long line and indented with spaces. Fix. Signed-off-by: Brandon Philips Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index 9c63a5687d69..7975a52bdf5b 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -482,8 +482,8 @@ void class_interface_unregister(struct class_interface *class_intf) class_put(parent); } -ssize_t show_class_attr_string(struct class *class, struct class_attribute *attr, - char *buf) +ssize_t show_class_attr_string(struct class *class, + struct class_attribute *attr, char *buf) { struct class_attribute_string *cs; cs = container_of(attr, struct class_attribute_string, attr); -- cgit v1.2.3 From 6174c3496d43b78969d4a989e1aabfbc55acbf15 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 10 Nov 2010 17:08:26 -0800 Subject: Revert "staging: batman-adv: Use linux/etherdevice.h address helper functions" This reverts commit 5712dc7fc812d1bdbc5e634d389bc759d4e7550c. Turns out the batman maintainers didn't like the implementation of it, and the original author was going to rework it to meet their approval, and I applied it without fully realizing all of this. My fault. Cc: Marek Lindner Cc: Simon Wunderlich Cc: Andrew Lunn Cc: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/main.c | 12 +++++++++++- drivers/staging/batman-adv/main.h | 3 ++- drivers/staging/batman-adv/routing.c | 16 ++++++++-------- drivers/staging/batman-adv/soft-interface.c | 2 +- drivers/staging/batman-adv/vis.c | 4 ++-- 5 files changed, 24 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 6ea64200ad16..0587940d2723 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -149,7 +149,7 @@ void dec_module_count(void) int compare_orig(void *data1, void *data2) { - return (compare_ether_addr(data1, data2) == 0 ? 1 : 0); + return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); } /* hashfunction to choose an entry in a hash table of given size */ @@ -192,6 +192,16 @@ int is_my_mac(uint8_t *addr) } +int is_bcast(uint8_t *addr) +{ + return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff); +} + +int is_mcast(uint8_t *addr) +{ + return *addr & 0x01; +} + module_init(batman_init); module_exit(batman_exit); diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index 14d567d4911a..5e3f51681f5e 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -109,7 +109,6 @@ #include /* mutex */ #include /* needed by all modules */ #include /* netdevice */ -#include #include /* ethernet header */ #include /* poll_table */ #include /* kernel threads */ @@ -139,6 +138,8 @@ void dec_module_count(void); int compare_orig(void *data1, void *data2); int choose_orig(void *data, int32_t size); int is_my_mac(uint8_t *addr); +int is_bcast(uint8_t *addr); +int is_mcast(uint8_t *addr); #ifdef CONFIG_BATMAN_ADV_DEBUG int debug_log(struct bat_priv *bat_priv, char *fmt, ...); diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index d42c16559dff..90102631330b 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -756,11 +756,11 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ - if (!is_broadcast_ether_addr(ethhdr->h_dest)) + if (!is_bcast(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) + if (is_bcast(ethhdr->h_source)) return NET_RX_DROP; /* create a copy of the skb, if needed, to modify it. */ @@ -933,11 +933,11 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ - if (is_broadcast_ether_addr(ethhdr->h_dest)) + if (is_bcast(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) + if (is_bcast(ethhdr->h_source)) return NET_RX_DROP; /* not for me */ @@ -1107,11 +1107,11 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ - if (is_broadcast_ether_addr(ethhdr->h_dest)) + if (is_bcast(ethhdr->h_dest)) return -1; /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) + if (is_bcast(ethhdr->h_source)) return -1; /* not for me */ @@ -1283,11 +1283,11 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ - if (!is_broadcast_ether_addr(ethhdr->h_dest)) + if (!is_bcast(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) + if (is_bcast(ethhdr->h_source)) return NET_RX_DROP; /* ignore broadcasts sent by myself */ diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 820e14159dd3..3904db9ce7b1 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -140,7 +140,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) hna_local_add(soft_iface, ethhdr->h_source); /* ethernet packet should be broadcasted */ - if (is_multicast_ether_addr(ethhdr->h_dest)) { + if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { if (!bat_priv->primary_if) goto dropped; diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index 395f1109d606..4473cc8ed6b0 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -469,7 +469,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv, int are_target = 0; /* clients shall not broadcast. */ - if (is_broadcast_ether_addr(vis_packet->target_orig)) + if (is_bcast(vis_packet->target_orig)) return; /* Are we the target for this VIS packet? */ @@ -746,7 +746,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) ETH_ALEN); packet->ttl--; - if (is_broadcast_ether_addr(packet->target_orig)) + if (is_bcast(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); -- cgit v1.2.3 From 527f9e907c39f7e88abb57eaa8bccb43c8706a3d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 11 Nov 2010 01:16:58 +0000 Subject: drm/i915: Remove the global irq wait queue ... as it has been replaced by per-ring waiters. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 8 +------- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9cb6061bf9d5..4c8fae9baaad 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1022,7 +1022,6 @@ i915_wedged_write(struct file *filp, loff_t *ppos) { struct drm_device *dev = filp->private_data; - drm_i915_private_t *dev_priv = dev->dev_private; char buf[20]; int val = 1; @@ -1038,12 +1037,7 @@ i915_wedged_write(struct file *filp, } DRM_INFO("Manually setting wedged to %d\n", val); - - atomic_set(&dev_priv->mm.wedged, val); - if (val) { - wake_up_all(&dev_priv->irq_queue); - queue_work(dev_priv->wq, &dev_priv->error_work); - } + i915_handle_error(dev, val); return cnt; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ff7593f70f0f..30d7a7bc6f2e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -289,7 +289,6 @@ typedef struct drm_i915_private { int current_page; int page_flipping; - wait_queue_head_t irq_queue; atomic_t irq_received; /** Protects user_irq_refcount and irq_mask_reg */ spinlock_t user_irq_lock; @@ -915,6 +914,7 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); /* i915_irq.c */ void i915_hangcheck_elapsed(unsigned long data); +void i915_handle_error(struct drm_device *dev, bool wedged); extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_irq_wait(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3ec631f1129d..4a0664ea49b9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -891,7 +891,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) * so userspace knows something bad happened (should trigger collection * of a ring dump etc.). */ -static void i915_handle_error(struct drm_device *dev, bool wedged) +void i915_handle_error(struct drm_device *dev, bool wedged) { struct drm_i915_private *dev_priv = dev->dev_private; -- cgit v1.2.3 From 06fc8846a2c0ddcc51e6666a78fc29a8e749ca3b Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Wed, 10 Nov 2010 17:19:41 -0800 Subject: staging: brcm80211: Remove unused module parameters. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wl_mac80211.c | 48 ++++------------------------- 1 file changed, 6 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index cb5dba95fc86..4b59e073aa15 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -182,32 +182,6 @@ module_param(phymsglevel, int, 0); #endif /* WLC_HIGH_ONLY */ #endif /* BCMDBG */ -static int oneonly; -module_param(oneonly, int, 0); - -static int piomode; -module_param(piomode, int, 0); - -static int instance_base; /* Starting instance number */ -module_param(instance_base, int, 0); - -#if defined(BCMDBG) -static char *macaddr; -module_param(macaddr, charp, S_IRUGO); -#endif - -static int nompc = 1; -module_param(nompc, int, 0); - -static char name[IFNAMSIZ] = "eth%d"; -module_param_string(name, name, IFNAMSIZ, 0); - -#ifndef SRCBASE -#define SRCBASE "." -#endif - -#define WL_MAGIC 0xdeadbeef - #define HW_TO_WL(hw) (hw->priv) #define WL_TO_HW(wl) (wl->pub->ieee_hw) #ifdef WLC_HIGH_ONLY @@ -776,7 +750,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, struct ieee80211_hw *hw; u8 perm[ETH_ALEN]; - unit = wl_found + instance_base; + unit = wl_found; err = 0; if (unit < 0) { @@ -784,11 +758,6 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, return NULL; } - if (oneonly && (unit != instance_base)) { - WL_ERROR(("wl%d: wl_attach: oneonly is set, exiting\n", unit)); - return NULL; - } - osh = osl_attach(btparam, bustype); ASSERT(osh); @@ -808,7 +777,6 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, #endif ASSERT(wl); - wl->magic = WL_MAGIC; wl->osh = osh; atomic_set(&wl->callbacks, 0); @@ -842,9 +810,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, base_addr = regs; if (bustype == PCI_BUS) { - /* piomode can be overwritten by command argument */ - wl->piomode = piomode; - WL_TRACE(("PCI/%s\n", wl->piomode ? "PIO" : "DMA")); + wl->piomode = false; } else if (bustype == RPC_BUS) { /* Do nothing */ } else { @@ -911,11 +877,9 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, wl_rpc_down, NULL, NULL); #endif /* WLC_HIGH_ONLY */ - if (nompc) { - if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { - WL_ERROR(("wl%d: Error setting MPC variable to 0\n", - unit)); - } + if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { + WL_ERROR(("wl%d: Error setting MPC variable to 0\n", + unit)); } #ifdef BCMSDIO /* Set SDIO drive strength */ @@ -967,7 +931,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, #endif #ifdef BCMDBG - printf(" (Compiled in " SRCBASE " at " __TIME__ " on " __DATE__ ")"); + printf(" (Compiled at " __TIME__ " on " __DATE__ ")"); #endif /* BCMDBG */ printf("\n"); -- cgit v1.2.3 From cae5852dcaa1139b198e13ebd3aeb7f3c065f875 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Tue, 9 Nov 2010 17:17:32 +0800 Subject: drm/i915/ringbuffer: set FORCE_WAKE bit before reading ring register Before reading ring register, set FORCE_WAKE bit to prevent GT core power down to low power state, otherwise we may read stale values. Signed-off-by: Zou Nan hai [ickle: added a udelay which seemed to do the trick on my SNB] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 176 +++++++++++++++++--------------- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.h | 13 ++- 4 files changed, 106 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 30d7a7bc6f2e..ecf12f9de1e0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -876,6 +876,67 @@ enum intel_chip_family { CHIP_I965 = 0x08, }; +#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) + +#define IS_I830(dev) ((dev)->pci_device == 0x3577) +#define IS_845G(dev) ((dev)->pci_device == 0x2562) +#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x) +#define IS_I865G(dev) ((dev)->pci_device == 0x2572) +#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) +#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) +#define IS_I945G(dev) ((dev)->pci_device == 0x2772) +#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) +#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater) +#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline) +#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) +#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x) +#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001) +#define IS_PINEVIEW_M(dev) ((dev)->pci_device == 0xa011) +#define IS_PINEVIEW(dev) (INTEL_INFO(dev)->is_pineview) +#define IS_G33(dev) (INTEL_INFO(dev)->is_g33) +#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) +#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) +#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) + +#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2) +#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3) +#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4) +#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) +#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) + +#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) +#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) +#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) + +#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) +#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) + +/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte + * rows, which changed the alignment requirements and fence programming. + */ +#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ + IS_I915GM(dev))) +#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) +#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev)) +#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev)) +#define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev)) +#define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) +#define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) +/* dsparb controlled by hw only */ +#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) + +#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2) +#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) +#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) +#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6) + +#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev)) +#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev)) + +#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) +#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) +#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) + extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; @@ -1174,6 +1235,23 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) +#define I915_READ(reg) i915_read(dev_priv, (reg), 4) +#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val), 4) +#define I915_READ16(reg) i915_read(dev_priv, (reg), 2) +#define I915_WRITE16(reg, val) i915_write(dev_priv, (reg), (val), 2) +#define I915_READ8(reg) i915_read(dev_priv, (reg), 1) +#define I915_WRITE8(reg, val) i915_write(dev_priv, (reg), (val), 1) +#define I915_WRITE64(reg, val) i915_write(dev_priv, (reg), (val), 8) +#define I915_READ64(reg) i915_read(dev_priv, (reg), 8) + +#define I915_READ_NOTRACE(reg) readl(dev_priv->regs + (reg)) +#define I915_WRITE_NOTRACE(reg, val) writel(val, dev_priv->regs + (reg)) +#define I915_READ16_NOTRACE(reg) readw(dev_priv->regs + (reg)) +#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg)) + +#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) +#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) + static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg, int len) { u64 val = 0; @@ -1197,6 +1275,23 @@ static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg, int len) return val; } +/* On SNB platform, before reading ring registers forcewake bit + * must be set to prevent GT core from power down and stale values being + * returned. + */ +static inline u32 i915_safe_read(struct drm_i915_private *dev_priv, u32 reg) +{ + if (IS_GEN6(dev_priv->dev)) { + I915_WRITE_NOTRACE(FORCEWAKE, 1); + POSTING_READ(FORCEWAKE); + /* XXX How long do we really need to wait here? + * Will different registers/engines require different periods? + */ + udelay(100); + } + return I915_READ(reg); +} + static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) { @@ -1218,24 +1313,6 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) } } -#define I915_READ(reg) i915_read(dev_priv, (reg), 4) -#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val), 4) -#define I915_READ16(reg) i915_read(dev_priv, (reg), 2) -#define I915_WRITE16(reg, val) i915_write(dev_priv, (reg), (val), 2) -#define I915_READ8(reg) i915_read(dev_priv, (reg), 1) -#define I915_WRITE8(reg, val) i915_write(dev_priv, (reg), (val), 1) -#define I915_WRITE64(reg, val) i915_write(dev_priv, (reg), (val), 8) -#define I915_READ64(reg) i915_read(dev_priv, (reg), 8) - -#define I915_READ_NOTRACE(reg) readl(dev_priv->regs + (reg)) -#define I915_WRITE_NOTRACE(reg, val) writel(val, dev_priv->regs + (reg)) -#define I915_READ16_NOTRACE(reg) readw(dev_priv->regs + (reg)) -#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg)) - -#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) -#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) - - #define BEGIN_LP_RING(n) \ intel_ring_begin(&dev_priv->render_ring, (n)) @@ -1266,67 +1343,4 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) #define I915_GEM_HWS_INDEX 0x20 #define I915_BREADCRUMB_INDEX 0x21 -#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) - -#define IS_I830(dev) ((dev)->pci_device == 0x3577) -#define IS_845G(dev) ((dev)->pci_device == 0x2562) -#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x) -#define IS_I865G(dev) ((dev)->pci_device == 0x2572) -#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) -#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) -#define IS_I945G(dev) ((dev)->pci_device == 0x2772) -#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) -#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater) -#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline) -#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) -#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x) -#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001) -#define IS_PINEVIEW_M(dev) ((dev)->pci_device == 0xa011) -#define IS_PINEVIEW(dev) (INTEL_INFO(dev)->is_pineview) -#define IS_G33(dev) (INTEL_INFO(dev)->is_g33) -#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042) -#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) -#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) - -#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2) -#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3) -#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4) -#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) -#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) - -#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) -#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) -#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) - -#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) -#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) - -/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte - * rows, which changed the alignment requirements and fence programming. - */ -#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ - IS_I915GM(dev))) -#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) -#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev)) -#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev)) -#define SUPPORTS_EDP(dev) (IS_IRONLAKE_M(dev)) -#define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) -#define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) -/* dsparb controlled by hw only */ -#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev)) - -#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2) -#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) -#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) -#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6) - -#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev)) -#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev)) - -#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) -#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) -#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) - -#define PRIMARY_RINGBUFFER_SIZE (128*1024) - #endif diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 61fe2619bb63..1eca8e710b9e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3077,4 +3077,5 @@ #define EDP_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22) #define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22) +#define FORCEWAKE 0xA18C #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f5d6151c953f..99f2c96a9c70 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -708,7 +708,7 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; unsigned long end; u32 head; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d73145c790bd..2565d65a625b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -7,13 +7,18 @@ struct intel_hw_status_page { struct drm_gem_object *obj; }; -#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base)) +#define I915_RING_READ(reg) i915_safe_read(dev_priv, reg) + +#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL(ring->mmio_base)) #define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val) -#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base)) + +#define I915_READ_START(ring) I915_RING_READ(RING_START(ring->mmio_base)) #define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val) -#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base)) + +#define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD(ring->mmio_base)) #define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val) -#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base)) + +#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL(ring->mmio_base)) #define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val) struct drm_i915_gem_execbuffer2; -- cgit v1.2.3 From e74cfed521746544e6eeee84b24bd31c1e59ffe2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 9 Nov 2010 10:16:56 +0000 Subject: Revert "drm/i915/ringbuffer: Ignore failure to setup the ring on Sandybridge" This reverts commit 629e894173c9de589913cf649deaadec4b0579bd. --- drivers/gpu/drm/i915/intel_ringbuffer.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 99f2c96a9c70..1db860d7989a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -180,30 +180,14 @@ static int init_ring_common(struct intel_ring_buffer *ring) if ((I915_READ_CTL(ring) & RING_VALID) == 0 || I915_READ_START(ring) != obj_priv->gtt_offset || (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) { - if (IS_GEN6(ring->dev) && ring->dev->pdev->revision <= 8) { - /* Early revisions of Sandybridge do not like - * revealing the contents of the ring buffer - * registers whilst idle. Fortunately, the - * auto-reporting mechanism prevents most hangs, - * but this will bite us eventually... - */ - DRM_DEBUG("%s initialization failed " - "ctl %08x head %08x tail %08x start %08x. Ignoring, hope for the best!\n", - ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); - } else { - DRM_ERROR("%s initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - ring->name, - I915_READ_CTL(ring), - I915_READ_HEAD(ring), - I915_READ_TAIL(ring), - I915_READ_START(ring)); - return -EIO; - } + DRM_ERROR("%s initialization failed " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ_CTL(ring), + I915_READ_HEAD(ring), + I915_READ_TAIL(ring), + I915_READ_START(ring)); + return -EIO; } if (!drm_core_check_feature(ring->dev, DRIVER_MODESET)) -- cgit v1.2.3 From 8168bd48bb863c00747497aadf13884b2d69d287 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 11 Nov 2010 17:54:52 +0000 Subject: drm/i915: Remove the definitions for Primary Ring Buffer We only ever used the PRB0, neglecting the secondary ring buffers, and now with the advent of multiple engines with separate ring buffers we need to excise the anachronisms from our code (and be explicit about which ring we mean where). This is doubly important in light of the FORCEWAKE required to read ring buffer registers on SandyBridge. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 28 ++++++++++++++-------------- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++---- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 4 files changed, 27 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 307bad0fcef7..4cd04917868d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -106,8 +106,8 @@ void i915_kernel_lost_context(struct drm_device * dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; + ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; + ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4a0664ea49b9..21034527d3a4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -520,30 +520,30 @@ i915_get_bbaddr(struct drm_device *dev, u32 *ring) } static u32 -i915_ringbuffer_last_batch(struct drm_device *dev) +i915_ringbuffer_last_batch(struct drm_device *dev, + struct intel_ring_buffer *ring) { struct drm_i915_private *dev_priv = dev->dev_private; u32 head, bbaddr; - u32 *ring; + u32 *val; /* Locate the current position in the ringbuffer and walk back * to find the most recently dispatched batch buffer. */ bbaddr = 0; - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring = (u32 *)(dev_priv->render_ring.virtual_start + head); + head = I915_READ_HEAD(ring) & HEAD_ADDR; + val = (u32 *)(ring->virtual_start + head); - while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { - bbaddr = i915_get_bbaddr(dev, ring); + while (--val >= (u32 *)ring->virtual_start) { + bbaddr = i915_get_bbaddr(dev, val); if (bbaddr) break; } if (bbaddr == 0) { - ring = (u32 *)(dev_priv->render_ring.virtual_start - + dev_priv->render_ring.size); - while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { - bbaddr = i915_get_bbaddr(dev, ring); + val = (u32 *)(ring->virtual_start + ring->size); + while (--val >= (u32 *)ring->virtual_start) { + bbaddr = i915_get_bbaddr(dev, val); if (bbaddr) break; } @@ -628,7 +628,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->bbaddr = 0; } - bbaddr = i915_ringbuffer_last_batch(dev); + bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->render_ring); /* Grab the current batchbuffer, most likely to have crashed. */ batchbuffer[0] = NULL; @@ -1398,10 +1398,10 @@ void i915_hangcheck_elapsed(unsigned long data) * and break the hang. This should work on * all but the second generation chipsets. */ - u32 tmp = I915_READ(PRB0_CTL); + struct intel_ring_buffer *ring = &dev_priv->render_ring; + u32 tmp = I915_READ_CTL(ring); if (tmp & RING_WAIT) { - I915_WRITE(PRB0_CTL, tmp); - POSTING_READ(PRB0_CTL); + I915_WRITE_CTL(ring, tmp); goto repeat; } } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1eca8e710b9e..886c0e072490 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -256,10 +256,6 @@ * Instruction and interrupt control regs */ #define PGTBL_ER 0x02024 -#define PRB0_TAIL 0x02030 -#define PRB0_HEAD 0x02034 -#define PRB0_START 0x02038 -#define PRB0_CTL 0x0203c #define RENDER_RING_BASE 0x02000 #define BSD_RING_BASE 0x04000 #define GEN6_BSD_RING_BASE 0x12000 @@ -285,10 +281,16 @@ #define RING_INVALID 0x00000000 #define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ #define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ +#if 0 +#define PRB0_TAIL 0x02030 +#define PRB0_HEAD 0x02034 +#define PRB0_START 0x02038 +#define PRB0_CTL 0x0203c #define PRB1_TAIL 0x02040 /* 915+ only */ #define PRB1_HEAD 0x02044 /* 915+ only */ #define PRB1_START 0x02048 /* 915+ only */ #define PRB1_CTL 0x0204c /* 915+ only */ +#endif #define IPEIR_I965 0x02064 #define IPEHR_I965 0x02068 #define INSTDONE_I965 0x0206c diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 63770c963077..6a7f11ff66f5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1983,17 +1983,17 @@ static void intel_flush_display_plane(struct drm_device *dev, static void intel_clear_scanline_wait(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; u32 tmp; if (IS_GEN2(dev)) /* Can't break the hang on i8xx */ return; - tmp = I915_READ(PRB0_CTL); - if (tmp & RING_WAIT) { - I915_WRITE(PRB0_CTL, tmp); - POSTING_READ(PRB0_CTL); - } + ring = &dev_priv->render_ring; + tmp = I915_READ_CTL(ring); + if (tmp & RING_WAIT) + I915_WRITE_CTL(ring, tmp); } static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) -- cgit v1.2.3 From 731edacb7567c15f25b1fccac18a203bd432ae5e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 13 Nov 2010 11:55:16 +0100 Subject: mtd: fix bdev exclusive open bugs in block2mtd::add_device() There are two bdev exclusive open bugs. * open_bdev_exclusive() must not be called with NULL holder. Use dev as the holder. * open_by_devnum() doesn't open the bdev exclusively but block2mtd_free_device() always assumes it. Explicitly claim the bdev. The latter is rather clumsy but will be simplified with future blkdev_get/put() cleanups. - Updated to use local variable @mode to cache FMODE_* masks as suggested by Artem Bityutskiy. Signed-off-by: Tejun Heo Cc: linux-mtd@lists.infradead.org Cc: Artem Bityutskiy --- drivers/mtd/devices/block2mtd.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 2cf0cc6a4189..a9e2d3b38aeb 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -234,6 +234,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) /* FIXME: ensure that mtd->size % erase_size == 0 */ static struct block2mtd_dev *add_device(char *devname, int erase_size) { + const fmode_t mode = FMODE_READ | FMODE_WRITE; struct block_device *bdev; struct block2mtd_dev *dev; char *name; @@ -246,7 +247,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) return NULL; /* Get a handle on the device */ - bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL); + bdev = open_bdev_exclusive(devname, mode, dev); #ifndef MODULE if (IS_ERR(bdev)) { @@ -255,7 +256,15 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev_t devt = name_to_dev_t(devname); if (devt) { - bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); + bdev = open_by_devnum(devt, mode); + if (!IS_ERR(bdev)) { + int ret; + ret = bd_claim(bdev, dev); + if (ret) { + blkdev_put(bdev, mode); + bdev = ERR_PTR(ret); + } + } } } #endif -- cgit v1.2.3 From e09b457bdb7e8d23fc54dcef0930ac697d8de895 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 13 Nov 2010 11:55:17 +0100 Subject: block: simplify holder symlink handling Code to manage symlinks in /sys/block/*/{holders|slaves} are overly complex with multiple holder considerations, redundant extra references to all involved kobjects, unused generic kobject holder support and unnecessary mixup with bd_claim/release functionalities. Strip it down to what's necessary (single gendisk holder) and make it use a separate interface. This is a step for cleaning up bd_claim/release. This patch makes dm-table slightly more complex but it will be simplified again with further changes. Signed-off-by: Tejun Heo Acked-by: Neil Brown Acked-by: Mike Snitzer Cc: dm-devel@redhat.com --- drivers/md/dm-table.c | 23 +++- drivers/md/md.c | 4 +- fs/block_dev.c | 322 +++++++------------------------------------------- include/linux/fs.h | 16 ++- 4 files changed, 74 insertions(+), 291 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 90267f8d64ee..2c876ffc63df 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -328,12 +328,22 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev, bdev = open_by_devnum(dev, d->dm_dev.mode); if (IS_ERR(bdev)) return PTR_ERR(bdev); - r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md)); - if (r) + + r = bd_claim(bdev, _claim_ptr); + if (r) { blkdev_put(bdev, d->dm_dev.mode); - else - d->dm_dev.bdev = bdev; - return r; + return r; + } + + r = bd_link_disk_holder(bdev, dm_disk(md)); + if (r) { + bd_release(bdev); + blkdev_put(bdev, d->dm_dev.mode); + return r; + } + + d->dm_dev.bdev = bdev; + return 0; } /* @@ -344,7 +354,8 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md) if (!d->dm_dev.bdev) return; - bd_release_from_disk(d->dm_dev.bdev, dm_disk(md)); + bd_unlink_disk_holder(d->dm_dev.bdev); + bd_release(d->dm_dev.bdev); blkdev_put(d->dm_dev.bdev, d->dm_dev.mode); d->dm_dev.bdev = NULL; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 4e957f3140a8..c47644fca1a1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1880,7 +1880,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state"); list_add_rcu(&rdev->same_set, &mddev->disks); - bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); + bd_link_disk_holder(rdev->bdev, mddev->gendisk); /* May as well allow recovery to be retried once */ mddev->recovery_disabled = 0; @@ -1907,7 +1907,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) MD_BUG(); return; } - bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk); + bd_unlink_disk_holder(rdev->bdev); list_del_rcu(&rdev->same_set); printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); rdev->mddev = NULL; diff --git a/fs/block_dev.c b/fs/block_dev.c index 06e8ff12b97c..9329068684d2 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -426,9 +426,6 @@ static void init_once(void *foo) mutex_init(&bdev->bd_mutex); INIT_LIST_HEAD(&bdev->bd_inodes); INIT_LIST_HEAD(&bdev->bd_list); -#ifdef CONFIG_SYSFS - INIT_LIST_HEAD(&bdev->bd_holder_list); -#endif inode_init_once(&ei->vfs_inode); /* Initialize mutex for freeze. */ mutex_init(&bdev->bd_fsfreeze_mutex); @@ -881,314 +878,83 @@ void bd_release(struct block_device *bdev) EXPORT_SYMBOL(bd_release); #ifdef CONFIG_SYSFS -/* - * Functions for bd_claim_by_kobject / bd_release_from_kobject - * - * If a kobject is passed to bd_claim_by_kobject() - * and the kobject has a parent directory, - * following symlinks are created: - * o from the kobject to the claimed bdev - * o from "holders" directory of the bdev to the parent of the kobject - * bd_release_from_kobject() removes these symlinks. - * - * Example: - * If /dev/dm-0 maps to /dev/sda, kobject corresponding to - * /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then: - * /sys/block/dm-0/slaves/sda --> /sys/block/sda - * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0 - */ - static int add_symlink(struct kobject *from, struct kobject *to) { - if (!from || !to) - return 0; return sysfs_create_link(from, to, kobject_name(to)); } static void del_symlink(struct kobject *from, struct kobject *to) { - if (!from || !to) - return; sysfs_remove_link(from, kobject_name(to)); } -/* - * 'struct bd_holder' contains pointers to kobjects symlinked by - * bd_claim_by_kobject. - * It's connected to bd_holder_list which is protected by bdev->bd_sem. - */ -struct bd_holder { - struct list_head list; /* chain of holders of the bdev */ - int count; /* references from the holder */ - struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */ - struct kobject *hdev; /* e.g. "/block/dm-0" */ - struct kobject *hdir; /* e.g. "/block/sda/holders" */ - struct kobject *sdev; /* e.g. "/block/sda" */ -}; - -/* - * Get references of related kobjects at once. - * Returns 1 on success. 0 on failure. - * - * Should call bd_holder_release_dirs() after successful use. - */ -static int bd_holder_grab_dirs(struct block_device *bdev, - struct bd_holder *bo) -{ - if (!bdev || !bo) - return 0; - - bo->sdir = kobject_get(bo->sdir); - if (!bo->sdir) - return 0; - - bo->hdev = kobject_get(bo->sdir->parent); - if (!bo->hdev) - goto fail_put_sdir; - - bo->sdev = kobject_get(&part_to_dev(bdev->bd_part)->kobj); - if (!bo->sdev) - goto fail_put_hdev; - - bo->hdir = kobject_get(bdev->bd_part->holder_dir); - if (!bo->hdir) - goto fail_put_sdev; - - return 1; - -fail_put_sdev: - kobject_put(bo->sdev); -fail_put_hdev: - kobject_put(bo->hdev); -fail_put_sdir: - kobject_put(bo->sdir); - - return 0; -} - -/* Put references of related kobjects at once. */ -static void bd_holder_release_dirs(struct bd_holder *bo) -{ - kobject_put(bo->hdir); - kobject_put(bo->sdev); - kobject_put(bo->hdev); - kobject_put(bo->sdir); -} - -static struct bd_holder *alloc_bd_holder(struct kobject *kobj) -{ - struct bd_holder *bo; - - bo = kzalloc(sizeof(*bo), GFP_KERNEL); - if (!bo) - return NULL; - - bo->count = 1; - bo->sdir = kobj; - - return bo; -} - -static void free_bd_holder(struct bd_holder *bo) -{ - kfree(bo); -} - /** - * find_bd_holder - find matching struct bd_holder from the block device + * bd_link_disk_holder - create symlinks between holding disk and slave bdev + * @bdev: the claimed slave bdev + * @disk: the holding disk * - * @bdev: struct block device to be searched - * @bo: target struct bd_holder + * This functions creates the following sysfs symlinks. * - * Returns matching entry with @bo in @bdev->bd_holder_list. - * If found, increment the reference count and return the pointer. - * If not found, returns NULL. - */ -static struct bd_holder *find_bd_holder(struct block_device *bdev, - struct bd_holder *bo) -{ - struct bd_holder *tmp; - - list_for_each_entry(tmp, &bdev->bd_holder_list, list) - if (tmp->sdir == bo->sdir) { - tmp->count++; - return tmp; - } - - return NULL; -} - -/** - * add_bd_holder - create sysfs symlinks for bd_claim() relationship + * - from "slaves" directory of the holder @disk to the claimed @bdev + * - from "holders" directory of the @bdev to the holder @disk * - * @bdev: block device to be bd_claimed - * @bo: preallocated and initialized by alloc_bd_holder() + * For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is + * passed to bd_link_disk_holder(), then: * - * Add @bo to @bdev->bd_holder_list, create symlinks. + * /sys/block/dm-0/slaves/sda --> /sys/block/sda + * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0 * - * Returns 0 if symlinks are created. - * Returns -ve if something fails. - */ -static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) -{ - int err; - - if (!bo) - return -EINVAL; - - if (!bd_holder_grab_dirs(bdev, bo)) - return -EBUSY; - - err = add_symlink(bo->sdir, bo->sdev); - if (err) - return err; - - err = add_symlink(bo->hdir, bo->hdev); - if (err) { - del_symlink(bo->sdir, bo->sdev); - return err; - } - - list_add_tail(&bo->list, &bdev->bd_holder_list); - return 0; -} - -/** - * del_bd_holder - delete sysfs symlinks for bd_claim() relationship - * - * @bdev: block device to be bd_claimed - * @kobj: holder's kobject - * - * If there is matching entry with @kobj in @bdev->bd_holder_list - * and no other bd_claim() from the same kobject, - * remove the struct bd_holder from the list, delete symlinks for it. - * - * Returns a pointer to the struct bd_holder when it's removed from the list - * and ready to be freed. - * Returns NULL if matching claim isn't found or there is other bd_claim() - * by the same kobject. - */ -static struct bd_holder *del_bd_holder(struct block_device *bdev, - struct kobject *kobj) -{ - struct bd_holder *bo; - - list_for_each_entry(bo, &bdev->bd_holder_list, list) { - if (bo->sdir == kobj) { - bo->count--; - BUG_ON(bo->count < 0); - if (!bo->count) { - list_del(&bo->list); - del_symlink(bo->sdir, bo->sdev); - del_symlink(bo->hdir, bo->hdev); - bd_holder_release_dirs(bo); - return bo; - } - break; - } - } - - return NULL; -} - -/** - * bd_claim_by_kobject - bd_claim() with additional kobject signature - * - * @bdev: block device to be claimed - * @holder: holder's signature - * @kobj: holder's kobject + * The caller must have claimed @bdev before calling this function and + * ensure that both @bdev and @disk are valid during the creation and + * lifetime of these symlinks. * - * Do bd_claim() and if it succeeds, create sysfs symlinks between - * the bdev and the holder's kobject. - * Use bd_release_from_kobject() when relesing the claimed bdev. + * CONTEXT: + * Might sleep. * - * Returns 0 on success. (same as bd_claim()) - * Returns errno on failure. + * RETURNS: + * 0 on success, -errno on failure. */ -static int bd_claim_by_kobject(struct block_device *bdev, void *holder, - struct kobject *kobj) +int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) { - int err; - struct bd_holder *bo, *found; - - if (!kobj) - return -EINVAL; - - bo = alloc_bd_holder(kobj); - if (!bo) - return -ENOMEM; + int ret = 0; mutex_lock(&bdev->bd_mutex); - err = bd_claim(bdev, holder); - if (err) - goto fail; + WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk); - found = find_bd_holder(bdev, bo); - if (found) - goto fail; + /* FIXME: remove the following once add_disk() handles errors */ + if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) + goto out_unlock; - err = add_bd_holder(bdev, bo); - if (err) - bd_release(bdev); - else - bo = NULL; -fail: - mutex_unlock(&bdev->bd_mutex); - free_bd_holder(bo); - return err; -} + ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); + if (ret) + goto out_unlock; -/** - * bd_release_from_kobject - bd_release() with additional kobject signature - * - * @bdev: block device to be released - * @kobj: holder's kobject - * - * Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject(). - */ -static void bd_release_from_kobject(struct block_device *bdev, - struct kobject *kobj) -{ - if (!kobj) - return; + ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); + if (ret) { + del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); + goto out_unlock; + } - mutex_lock(&bdev->bd_mutex); - bd_release(bdev); - free_bd_holder(del_bd_holder(bdev, kobj)); + bdev->bd_holder_disk = disk; +out_unlock: mutex_unlock(&bdev->bd_mutex); + return ret; } +EXPORT_SYMBOL_GPL(bd_link_disk_holder); -/** - * bd_claim_by_disk - wrapper function for bd_claim_by_kobject() - * - * @bdev: block device to be claimed - * @holder: holder's signature - * @disk: holder's gendisk - * - * Call bd_claim_by_kobject() with getting @disk->slave_dir. - */ -int bd_claim_by_disk(struct block_device *bdev, void *holder, - struct gendisk *disk) +void bd_unlink_disk_holder(struct block_device *bdev) { - return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir)); -} -EXPORT_SYMBOL_GPL(bd_claim_by_disk); + struct gendisk *disk = bdev->bd_holder_disk; -/** - * bd_release_from_disk - wrapper function for bd_release_from_kobject() - * - * @bdev: block device to be claimed - * @disk: holder's gendisk - * - * Call bd_release_from_kobject() and put @disk->slave_dir. - */ -void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk) -{ - bd_release_from_kobject(bdev, disk->slave_dir); - kobject_put(disk->slave_dir); + bdev->bd_holder_disk = NULL; + if (!disk) + return; + + del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); + del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); } -EXPORT_SYMBOL_GPL(bd_release_from_disk); +EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); #endif /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 334d68a17108..66b7f2c5d7e9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -663,7 +663,7 @@ struct block_device { void * bd_holder; int bd_holders; #ifdef CONFIG_SYSFS - struct list_head bd_holder_list; + struct gendisk * bd_holder_disk; /* for sysfs slave linkng */ #endif struct block_device * bd_contains; unsigned bd_block_size; @@ -2042,11 +2042,17 @@ extern int blkdev_put(struct block_device *, fmode_t); extern int bd_claim(struct block_device *, void *); extern void bd_release(struct block_device *); #ifdef CONFIG_SYSFS -extern int bd_claim_by_disk(struct block_device *, void *, struct gendisk *); -extern void bd_release_from_disk(struct block_device *, struct gendisk *); +extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); +extern void bd_unlink_disk_holder(struct block_device *bdev); #else -#define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder) -#define bd_release_from_disk(bdev, disk) bd_release(bdev) +static inline int bd_link_disk_holder(struct block_device *bdev, + struct gendisk *disk) +{ + return 0; +} +static inline void bd_unlink_disk_holder(struct block_device *bdev) +{ +} #endif #endif -- cgit v1.2.3 From e525fd89d380c4a94c0d63913a1dd1a593ed25e7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 13 Nov 2010 11:55:17 +0100 Subject: block: make blkdev_get/put() handle exclusive access Over time, block layer has accumulated a set of APIs dealing with bdev open, close, claim and release. * blkdev_get/put() are the primary open and close functions. * bd_claim/release() deal with exclusive open. * open/close_bdev_exclusive() are combination of open and claim and the other way around, respectively. * bd_link/unlink_disk_holder() to create and remove holder/slave symlinks. * open_by_devnum() wraps bdget() + blkdev_get(). The interface is a bit confusing and the decoupling of open and claim makes it impossible to properly guarantee exclusive access as in-kernel open + claim sequence can disturb the existing exclusive open even before the block layer knows the current open if for another exclusive access. Reorganize the interface such that, * blkdev_get() is extended to include exclusive access management. @holder argument is added and, if is @FMODE_EXCL specified, it will gain exclusive access atomically w.r.t. other exclusive accesses. * blkdev_put() is similarly extended. It now takes @mode argument and if @FMODE_EXCL is set, it releases an exclusive access. Also, when the last exclusive claim is released, the holder/slave symlinks are removed automatically. * bd_claim/release() and close_bdev_exclusive() are no longer necessary and either made static or removed. * bd_link_disk_holder() remains the same but bd_unlink_disk_holder() is no longer necessary and removed. * open_bdev_exclusive() becomes a simple wrapper around lookup_bdev() and blkdev_get(). It also has an unexpected extra bdev_read_only() test which probably should be moved into blkdev_get(). * open_by_devnum() is modified to take @holder argument and pass it to blkdev_get(). Most of bdev open/close operations are unified into blkdev_get/put() and most exclusive accesses are tested atomically at the open time (as it should). This cleans up code and removes some, both valid and invalid, but unnecessary all the same, corner cases. open_bdev_exclusive() and open_by_devnum() can use further cleanup - rename to blkdev_get_by_path() and blkdev_get_by_devt() and drop special features. Well, let's leave them for another day. Most conversions are straight-forward. drbd conversion is a bit more involved as there was some reordering, but the logic should stay the same. Signed-off-by: Tejun Heo Acked-by: Neil Brown Acked-by: Ryusuke Konishi Acked-by: Mike Snitzer Acked-by: Philipp Reisner Cc: Peter Osterlund Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: Jan Kara Cc: Andrew Morton Cc: Andreas Dilger Cc: "Theodore Ts'o" Cc: Mark Fasheh Cc: Joel Becker Cc: Alex Elder Cc: Christoph Hellwig Cc: dm-devel@redhat.com Cc: drbd-dev@lists.linbit.com Cc: Leo Chen Cc: Scott Branden Cc: Chris Mason Cc: Steven Whitehouse Cc: Dave Kleikamp Cc: Joern Engel Cc: reiserfs-devel@vger.kernel.org Cc: Alexander Viro --- block/ioctl.c | 5 +- drivers/block/drbd/drbd_int.h | 2 - drivers/block/drbd/drbd_main.c | 7 +- drivers/block/drbd/drbd_nl.c | 103 ++++++++++----------------- drivers/block/pktcdvd.c | 22 +++--- drivers/char/raw.c | 14 ++-- drivers/md/dm-table.c | 15 +--- drivers/md/md.c | 14 +--- drivers/mtd/devices/block2mtd.c | 17 ++--- drivers/s390/block/dasd_genhd.c | 2 +- fs/block_dev.c | 149 ++++++++++++++-------------------------- fs/btrfs/volumes.c | 14 ++-- fs/ext3/super.c | 12 +--- fs/ext4/super.c | 12 +--- fs/gfs2/ops_fstype.c | 4 +- fs/jfs/jfs_logmgr.c | 17 ++--- fs/logfs/dev_bdev.c | 4 +- fs/nilfs2/super.c | 4 +- fs/ocfs2/cluster/heartbeat.c | 2 +- fs/partitions/check.c | 2 +- fs/reiserfs/journal.c | 17 ++--- fs/super.c | 14 ++-- fs/xfs/linux-2.6/xfs_super.c | 2 +- include/linux/fs.h | 14 ++-- kernel/power/swap.c | 5 +- mm/swapfile.c | 7 +- 26 files changed, 162 insertions(+), 318 deletions(-) (limited to 'drivers') diff --git a/block/ioctl.c b/block/ioctl.c index d724ceb1d465..cc46d499fd27 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -294,11 +294,12 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, return -EINVAL; if (get_user(n, (int __user *) arg)) return -EFAULT; - if (!(mode & FMODE_EXCL) && bd_claim(bdev, &bdev) < 0) + if (!(mode & FMODE_EXCL) && + blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0) return -EBUSY; ret = set_blocksize(bdev, n); if (!(mode & FMODE_EXCL)) - bd_release(bdev); + blkdev_put(bdev, mode | FMODE_EXCL); return ret; case BLKPG: ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg); diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9bdcf4393c0a..0590b9f67ec6 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -923,8 +923,6 @@ struct drbd_md { struct drbd_backing_dev { struct block_device *backing_bdev; struct block_device *md_bdev; - struct file *lo_file; - struct file *md_file; struct drbd_md md; struct disk_conf dc; /* The user provided config... */ sector_t known_size; /* last known size of that backing device */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 25c7a73c5062..7ec1a82064a9 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3361,11 +3361,8 @@ void drbd_free_bc(struct drbd_backing_dev *ldev) if (ldev == NULL) return; - bd_release(ldev->backing_bdev); - bd_release(ldev->md_bdev); - - fput(ldev->lo_file); - fput(ldev->md_file); + blkdev_put(ldev->backing_bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); + blkdev_put(ldev->md_bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); kfree(ldev); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 87925e97e613..fd0346090289 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -855,7 +855,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp sector_t max_possible_sectors; sector_t min_md_device_sectors; struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */ - struct inode *inode, *inode2; + struct block_device *bdev; struct lru_cache *resync_lru = NULL; union drbd_state ns, os; unsigned int max_seg_s; @@ -902,46 +902,40 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp } } - nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0); - if (IS_ERR(nbc->lo_file)) { + bdev = open_bdev_exclusive(nbc->dc.backing_dev, + FMODE_READ | FMODE_WRITE, mdev); + if (IS_ERR(bdev)) { dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev, - PTR_ERR(nbc->lo_file)); - nbc->lo_file = NULL; + PTR_ERR(bdev)); retcode = ERR_OPEN_DISK; goto fail; } + nbc->backing_bdev = bdev; - inode = nbc->lo_file->f_dentry->d_inode; - - if (!S_ISBLK(inode->i_mode)) { - retcode = ERR_DISK_NOT_BDEV; - goto fail; - } - - nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0); - if (IS_ERR(nbc->md_file)) { + /* + * meta_dev_idx >= 0: external fixed size, possibly multiple + * drbd sharing one meta device. TODO in that case, paranoia + * check that [md_bdev, meta_dev_idx] is not yet used by some + * other drbd minor! (if you use drbd.conf + drbdadm, that + * should check it for you already; but if you don't, or + * someone fooled it, we need to double check here) + */ + bdev = open_bdev_exclusive(nbc->dc.meta_dev, + FMODE_READ | FMODE_WRITE, + (nbc->dc.meta_dev_idx < 0) ? + (void *)mdev : (void *)drbd_m_holder); + if (IS_ERR(bdev)) { dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev, - PTR_ERR(nbc->md_file)); - nbc->md_file = NULL; + PTR_ERR(bdev)); retcode = ERR_OPEN_MD_DISK; goto fail; } + nbc->md_bdev = bdev; - inode2 = nbc->md_file->f_dentry->d_inode; - - if (!S_ISBLK(inode2->i_mode)) { - retcode = ERR_MD_NOT_BDEV; - goto fail; - } - - nbc->backing_bdev = inode->i_bdev; - if (bd_claim(nbc->backing_bdev, mdev)) { - printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n", - nbc->backing_bdev, mdev, - nbc->backing_bdev->bd_holder, - nbc->backing_bdev->bd_contains->bd_holder, - nbc->backing_bdev->bd_holders); - retcode = ERR_BDCLAIM_DISK; + if ((nbc->backing_bdev == nbc->md_bdev) != + (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL || + nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) { + retcode = ERR_MD_IDX_INVALID; goto fail; } @@ -950,28 +944,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp offsetof(struct bm_extent, lce)); if (!resync_lru) { retcode = ERR_NOMEM; - goto release_bdev_fail; - } - - /* meta_dev_idx >= 0: external fixed size, - * possibly multiple drbd sharing one meta device. - * TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is - * not yet used by some other drbd minor! - * (if you use drbd.conf + drbdadm, - * that should check it for you already; but if you don't, or someone - * fooled it, we need to double check here) */ - nbc->md_bdev = inode2->i_bdev; - if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev - : (void *) drbd_m_holder)) { - retcode = ERR_BDCLAIM_MD_DISK; - goto release_bdev_fail; - } - - if ((nbc->backing_bdev == nbc->md_bdev) != - (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL || - nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) { - retcode = ERR_MD_IDX_INVALID; - goto release_bdev2_fail; + goto fail; } /* RT - for drbd_get_max_capacity() DRBD_MD_INDEX_FLEX_INT */ @@ -982,7 +955,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp (unsigned long long) drbd_get_max_capacity(nbc), (unsigned long long) nbc->dc.disk_size); retcode = ERR_DISK_TO_SMALL; - goto release_bdev2_fail; + goto fail; } if (nbc->dc.meta_dev_idx < 0) { @@ -999,7 +972,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp dev_warn(DEV, "refusing attach: md-device too small, " "at least %llu sectors needed for this meta-disk type\n", (unsigned long long) min_md_device_sectors); - goto release_bdev2_fail; + goto fail; } /* Make sure the new disk is big enough @@ -1007,7 +980,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (drbd_get_max_capacity(nbc) < drbd_get_capacity(mdev->this_bdev)) { retcode = ERR_DISK_TO_SMALL; - goto release_bdev2_fail; + goto fail; } nbc->known_size = drbd_get_capacity(nbc->backing_bdev); @@ -1030,7 +1003,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); drbd_resume_io(mdev); if (retcode < SS_SUCCESS) - goto release_bdev2_fail; + goto fail; if (!get_ldev_if_state(mdev, D_ATTACHING)) goto force_diskless; @@ -1264,18 +1237,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp force_diskless: drbd_force_state(mdev, NS(disk, D_DISKLESS)); drbd_md_sync(mdev); - release_bdev2_fail: - if (nbc) - bd_release(nbc->md_bdev); - release_bdev_fail: - if (nbc) - bd_release(nbc->backing_bdev); fail: if (nbc) { - if (nbc->lo_file) - fput(nbc->lo_file); - if (nbc->md_file) - fput(nbc->md_file); + if (nbc->backing_bdev) + blkdev_put(nbc->backing_bdev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL); + if (nbc->md_bdev) + blkdev_put(nbc->md_bdev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL); kfree(nbc); } lc_destroy(resync_lru); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 19b3568e9326..77d70eebb6b2 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2296,15 +2296,12 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) * so bdget() can't fail. */ bdget(pd->bdev->bd_dev); - if ((ret = blkdev_get(pd->bdev, FMODE_READ))) + if ((ret = blkdev_get(pd->bdev, FMODE_READ | FMODE_EXCL, pd))) goto out; - if ((ret = bd_claim(pd->bdev, pd))) - goto out_putdev; - if ((ret = pkt_get_last_written(pd, &lba))) { printk(DRIVER_NAME": pkt_get_last_written failed\n"); - goto out_unclaim; + goto out_putdev; } set_capacity(pd->disk, lba << 2); @@ -2314,7 +2311,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) q = bdev_get_queue(pd->bdev); if (write) { if ((ret = pkt_open_write(pd))) - goto out_unclaim; + goto out_putdev; /* * Some CDRW drives can not handle writes larger than one packet, * even if the size is a multiple of the packet size. @@ -2329,23 +2326,21 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) } if ((ret = pkt_set_segment_merging(pd, q))) - goto out_unclaim; + goto out_putdev; if (write) { if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { printk(DRIVER_NAME": not enough memory for buffers\n"); ret = -ENOMEM; - goto out_unclaim; + goto out_putdev; } printk(DRIVER_NAME": %lukB available on disc\n", lba << 1); } return 0; -out_unclaim: - bd_release(pd->bdev); out_putdev: - blkdev_put(pd->bdev, FMODE_READ); + blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL); out: return ret; } @@ -2362,8 +2357,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush) pkt_lock_door(pd, 0); pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); - bd_release(pd->bdev); - blkdev_put(pd->bdev, FMODE_READ); + blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL); pkt_shrink_pktlist(pd); } @@ -2733,7 +2727,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) bdev = bdget(dev); if (!bdev) return -ENOMEM; - ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY); + ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL); if (ret) return ret; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index bfe25ea9766b..b4b9d5a47885 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -65,15 +65,12 @@ static int raw_open(struct inode *inode, struct file *filp) if (!bdev) goto out; igrab(bdev->bd_inode); - err = blkdev_get(bdev, filp->f_mode); + err = blkdev_get(bdev, filp->f_mode | FMODE_EXCL, raw_open); if (err) goto out; - err = bd_claim(bdev, raw_open); - if (err) - goto out1; err = set_blocksize(bdev, bdev_logical_block_size(bdev)); if (err) - goto out2; + goto out1; filp->f_flags |= O_DIRECT; filp->f_mapping = bdev->bd_inode->i_mapping; if (++raw_devices[minor].inuse == 1) @@ -83,10 +80,8 @@ static int raw_open(struct inode *inode, struct file *filp) mutex_unlock(&raw_mutex); return 0; -out2: - bd_release(bdev); out1: - blkdev_put(bdev, filp->f_mode); + blkdev_put(bdev, filp->f_mode | FMODE_EXCL); out: mutex_unlock(&raw_mutex); return err; @@ -110,8 +105,7 @@ static int raw_release(struct inode *inode, struct file *filp) } mutex_unlock(&raw_mutex); - bd_release(bdev); - blkdev_put(bdev, filp->f_mode); + blkdev_put(bdev, filp->f_mode | FMODE_EXCL); return 0; } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 2c876ffc63df..9e88ca0c55e9 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -325,20 +325,13 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev, BUG_ON(d->dm_dev.bdev); - bdev = open_by_devnum(dev, d->dm_dev.mode); + bdev = open_by_devnum(dev, d->dm_dev.mode | FMODE_EXCL, _claim_ptr); if (IS_ERR(bdev)) return PTR_ERR(bdev); - r = bd_claim(bdev, _claim_ptr); - if (r) { - blkdev_put(bdev, d->dm_dev.mode); - return r; - } - r = bd_link_disk_holder(bdev, dm_disk(md)); if (r) { - bd_release(bdev); - blkdev_put(bdev, d->dm_dev.mode); + blkdev_put(bdev, d->dm_dev.mode | FMODE_EXCL); return r; } @@ -354,9 +347,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md) if (!d->dm_dev.bdev) return; - bd_unlink_disk_holder(d->dm_dev.bdev); - bd_release(d->dm_dev.bdev); - blkdev_put(d->dm_dev.bdev, d->dm_dev.mode); + blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL); d->dm_dev.bdev = NULL; } diff --git a/drivers/md/md.c b/drivers/md/md.c index c47644fca1a1..6af951ffe0bb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1907,7 +1907,6 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) MD_BUG(); return; } - bd_unlink_disk_holder(rdev->bdev); list_del_rcu(&rdev->same_set); printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); rdev->mddev = NULL; @@ -1935,19 +1934,13 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); + bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, + shared ? (mdk_rdev_t *)lock_rdev : rdev); if (IS_ERR(bdev)) { printk(KERN_ERR "md: could not open %s.\n", __bdevname(dev, b)); return PTR_ERR(bdev); } - err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev); - if (err) { - printk(KERN_ERR "md: could not bd_claim %s.\n", - bdevname(bdev, b)); - blkdev_put(bdev, FMODE_READ|FMODE_WRITE); - return err; - } if (!shared) set_bit(AllReserved, &rdev->flags); rdev->bdev = bdev; @@ -1960,8 +1953,7 @@ static void unlock_rdev(mdk_rdev_t *rdev) rdev->bdev = NULL; if (!bdev) MD_BUG(); - bd_release(bdev); - blkdev_put(bdev, FMODE_READ|FMODE_WRITE); + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } void md_autodetect_dev(dev_t dev); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index a9e2d3b38aeb..aa557beb8f51 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -224,7 +224,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) if (dev->blkdev) { invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1); - close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE); + blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } kfree(dev); @@ -234,7 +234,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) /* FIXME: ensure that mtd->size % erase_size == 0 */ static struct block2mtd_dev *add_device(char *devname, int erase_size) { - const fmode_t mode = FMODE_READ | FMODE_WRITE; + const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; struct block_device *bdev; struct block2mtd_dev *dev; char *name; @@ -255,17 +255,8 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) to resolve the device name by other means. */ dev_t devt = name_to_dev_t(devname); - if (devt) { - bdev = open_by_devnum(devt, mode); - if (!IS_ERR(bdev)) { - int ret; - ret = bd_claim(bdev, dev); - if (ret) { - blkdev_put(bdev, mode); - bdev = ERR_PTR(ret); - } - } - } + if (devt) + bdev = open_by_devnum(devt, mode, dev); } #endif diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 30a1ca3d08b7..5505bc07e1e7 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -103,7 +103,7 @@ int dasd_scan_partitions(struct dasd_block *block) struct block_device *bdev; bdev = bdget_disk(block->gdp, 0); - if (!bdev || blkdev_get(bdev, FMODE_READ) < 0) + if (!bdev || blkdev_get(bdev, FMODE_READ, NULL) < 0) return -ENODEV; /* * See fs/partition/check.c:register_disk,rescan_partitions diff --git a/fs/block_dev.c b/fs/block_dev.c index 9329068684d2..fc48912354d1 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -660,7 +660,7 @@ static bool bd_may_claim(struct block_device *bdev, struct block_device *whole, else if (bdev->bd_contains == bdev) return true; /* is a whole device which isn't held */ - else if (whole->bd_holder == bd_claim) + else if (whole->bd_holder == bd_may_claim) return true; /* is a partition of a device that is being partitioned */ else if (whole->bd_holder != NULL) return false; /* is a partition of a held device */ @@ -807,10 +807,10 @@ static void __bd_claim(struct block_device *bdev, struct block_device *whole, { /* note that for a whole device bd_holders * will be incremented twice, and bd_holder will - * be set to bd_claim before being set to holder + * be set to bd_may_claim before being set to holder */ whole->bd_holders++; - whole->bd_holder = bd_claim; + whole->bd_holder = bd_may_claim; bdev->bd_holders++; bdev->bd_holder = holder; } @@ -835,37 +835,7 @@ static void bd_finish_claiming(struct block_device *bdev, __bd_abort_claiming(whole, holder); /* not actually an abort */ } -/** - * bd_claim - claim a block device - * @bdev: block device to claim - * @holder: holder trying to claim @bdev - * - * Try to claim @bdev which must have been opened successfully. - * - * CONTEXT: - * Might sleep. - * - * RETURNS: - * 0 if successful, -EBUSY if @bdev is already claimed. - */ -int bd_claim(struct block_device *bdev, void *holder) -{ - struct block_device *whole = bdev->bd_contains; - int res; - - might_sleep(); - - spin_lock(&bdev_lock); - res = bd_prepare_to_claim(bdev, whole, holder); - if (res == 0) - __bd_claim(bdev, whole, holder); - spin_unlock(&bdev_lock); - - return res; -} -EXPORT_SYMBOL(bd_claim); - -void bd_release(struct block_device *bdev) +static void bd_release(struct block_device *bdev) { spin_lock(&bdev_lock); if (!--bdev->bd_contains->bd_holders) @@ -875,8 +845,6 @@ void bd_release(struct block_device *bdev) spin_unlock(&bdev_lock); } -EXPORT_SYMBOL(bd_release); - #ifdef CONFIG_SYSFS static int add_symlink(struct kobject *from, struct kobject *to) { @@ -943,7 +911,7 @@ out_unlock: } EXPORT_SYMBOL_GPL(bd_link_disk_holder); -void bd_unlink_disk_holder(struct block_device *bdev) +static void bd_unlink_disk_holder(struct block_device *bdev) { struct gendisk *disk = bdev->bd_holder_disk; @@ -954,7 +922,9 @@ void bd_unlink_disk_holder(struct block_device *bdev) del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); } -EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); +#else +static inline void bd_unlink_disk_holder(struct block_device *bdev) +{ } #endif /* @@ -964,12 +934,12 @@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); * to be used for internal purposes. If you ever need it - reconsider * your API. */ -struct block_device *open_by_devnum(dev_t dev, fmode_t mode) +struct block_device *open_by_devnum(dev_t dev, fmode_t mode, void *holder) { struct block_device *bdev = bdget(dev); int err = -ENOMEM; if (bdev) - err = blkdev_get(bdev, mode); + err = blkdev_get(bdev, mode, holder); return err ? ERR_PTR(err) : bdev; } @@ -1235,17 +1205,37 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) return ret; } -int blkdev_get(struct block_device *bdev, fmode_t mode) +int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) { - return __blkdev_get(bdev, mode, 0); + struct block_device *whole = NULL; + int res; + + WARN_ON_ONCE((mode & FMODE_EXCL) && !holder); + + if ((mode & FMODE_EXCL) && holder) { + whole = bd_start_claiming(bdev, holder); + if (IS_ERR(whole)) { + bdput(bdev); + return PTR_ERR(whole); + } + } + + res = __blkdev_get(bdev, mode, 0); + + if (whole) { + if (res == 0) + bd_finish_claiming(bdev, whole, holder); + else + bd_abort_claiming(whole, holder); + } + + return res; } EXPORT_SYMBOL(blkdev_get); static int blkdev_open(struct inode * inode, struct file * filp) { - struct block_device *whole = NULL; struct block_device *bdev; - int res; /* * Preserve backwards compatibility and allow large file access @@ -1266,26 +1256,9 @@ static int blkdev_open(struct inode * inode, struct file * filp) if (bdev == NULL) return -ENOMEM; - if (filp->f_mode & FMODE_EXCL) { - whole = bd_start_claiming(bdev, filp); - if (IS_ERR(whole)) { - bdput(bdev); - return PTR_ERR(whole); - } - } - filp->f_mapping = bdev->bd_inode->i_mapping; - res = blkdev_get(bdev, filp->f_mode); - - if (whole) { - if (res == 0) - bd_finish_claiming(bdev, whole, filp); - else - bd_abort_claiming(whole, filp); - } - - return res; + return blkdev_get(bdev, filp->f_mode, filp); } static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) @@ -1329,6 +1302,13 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) int blkdev_put(struct block_device *bdev, fmode_t mode) { + if (mode & FMODE_EXCL) { + mutex_lock(&bdev->bd_mutex); + bd_release(bdev); + if (!bdev->bd_holders) + bd_unlink_disk_holder(bdev); + mutex_unlock(&bdev->bd_mutex); + } return __blkdev_put(bdev, mode, 0); } EXPORT_SYMBOL(blkdev_put); @@ -1336,8 +1316,7 @@ EXPORT_SYMBOL(blkdev_put); static int blkdev_close(struct inode * inode, struct file * filp) { struct block_device *bdev = I_BDEV(filp->f_mapping->host); - if (bdev->bd_holder == filp) - bd_release(bdev); + return blkdev_put(bdev, filp->f_mode); } @@ -1494,55 +1473,27 @@ EXPORT_SYMBOL(lookup_bdev); */ struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) { - struct block_device *bdev, *whole; + struct block_device *bdev; int error; bdev = lookup_bdev(path); if (IS_ERR(bdev)) return bdev; - whole = bd_start_claiming(bdev, holder); - if (IS_ERR(whole)) { - bdput(bdev); - return whole; - } - - error = blkdev_get(bdev, mode); + error = blkdev_get(bdev, mode | FMODE_EXCL, holder); if (error) - goto out_abort_claiming; + return ERR_PTR(error); - error = -EACCES; - if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) - goto out_blkdev_put; + if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) { + blkdev_put(bdev, mode); + return ERR_PTR(-EACCES); + } - bd_finish_claiming(bdev, whole, holder); return bdev; - -out_blkdev_put: - blkdev_put(bdev, mode); -out_abort_claiming: - bd_abort_claiming(whole, holder); - return ERR_PTR(error); } EXPORT_SYMBOL(open_bdev_exclusive); -/** - * close_bdev_exclusive - close a blockdevice opened by open_bdev_exclusive() - * - * @bdev: blockdevice to close - * @mode: mode, must match that used to open. - * - * This is the counterpart to open_bdev_exclusive(). - */ -void close_bdev_exclusive(struct block_device *bdev, fmode_t mode) -{ - bd_release(bdev); - blkdev_put(bdev, mode); -} - -EXPORT_SYMBOL(close_bdev_exclusive); - int __invalidate_device(struct block_device *bdev) { struct super_block *sb = get_super(bdev); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d39596224d21..f1b729d3b883 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -489,7 +489,7 @@ again: continue; if (device->bdev) { - close_bdev_exclusive(device->bdev, device->mode); + blkdev_put(device->bdev, device->mode | FMODE_EXCL); device->bdev = NULL; fs_devices->open_devices--; } @@ -523,7 +523,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) list_for_each_entry(device, &fs_devices->devices, dev_list) { if (device->bdev) { - close_bdev_exclusive(device->bdev, device->mode); + blkdev_put(device->bdev, device->mode | FMODE_EXCL); fs_devices->open_devices--; } if (device->writeable) { @@ -638,7 +638,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, error_brelse: brelse(bh); error_close: - close_bdev_exclusive(bdev, flags); + blkdev_put(bdev, flags | FMODE_EXCL); error: continue; } @@ -716,7 +716,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, brelse(bh); error_close: - close_bdev_exclusive(bdev, flags); + blkdev_put(bdev, flags | FMODE_EXCL); error: mutex_unlock(&uuid_mutex); return ret; @@ -1244,7 +1244,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) root->fs_info->fs_devices->latest_bdev = next_device->bdev; if (device->bdev) { - close_bdev_exclusive(device->bdev, device->mode); + blkdev_put(device->bdev, device->mode | FMODE_EXCL); device->bdev = NULL; device->fs_devices->open_devices--; } @@ -1287,7 +1287,7 @@ error_brelse: brelse(bh); error_close: if (bdev) - close_bdev_exclusive(bdev, FMODE_READ); + blkdev_put(bdev, FMODE_READ | FMODE_EXCL); out: mutex_unlock(&root->fs_info->volume_mutex); mutex_unlock(&uuid_mutex); @@ -1565,7 +1565,7 @@ out: mutex_unlock(&root->fs_info->volume_mutex); return ret; error: - close_bdev_exclusive(bdev, 0); + blkdev_put(bdev, FMODE_EXCL); if (seeding_dev) { mutex_unlock(&uuid_mutex); up_write(&sb->s_umount); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 2fedaf8b5012..23e7513dba9c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -347,7 +347,7 @@ static struct block_device *ext3_blkdev_get(dev_t dev, struct super_block *sb) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); + bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); if (IS_ERR(bdev)) goto fail; return bdev; @@ -364,8 +364,7 @@ fail: */ static int ext3_blkdev_put(struct block_device *bdev) { - bd_release(bdev); - return blkdev_put(bdev, FMODE_READ|FMODE_WRITE); + return blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } static int ext3_blkdev_remove(struct ext3_sb_info *sbi) @@ -2136,13 +2135,6 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, if (bdev == NULL) return NULL; - if (bd_claim(bdev, sb)) { - ext3_msg(sb, KERN_ERR, - "error: failed to claim external journal device"); - blkdev_put(bdev, FMODE_READ|FMODE_WRITE); - return NULL; - } - blocksize = sb->s_blocksize; hblock = bdev_logical_block_size(bdev); if (blocksize < hblock) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 61182fe6254e..5dd0b3e76fa8 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -647,7 +647,7 @@ static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE); + bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); if (IS_ERR(bdev)) goto fail; return bdev; @@ -663,8 +663,7 @@ fail: */ static int ext4_blkdev_put(struct block_device *bdev) { - bd_release(bdev); - return blkdev_put(bdev, FMODE_READ|FMODE_WRITE); + return blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } static int ext4_blkdev_remove(struct ext4_sb_info *sbi) @@ -3758,13 +3757,6 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, if (bdev == NULL) return NULL; - if (bd_claim(bdev, sb)) { - ext4_msg(sb, KERN_ERR, - "failed to claim external journal device"); - blkdev_put(bdev, FMODE_READ|FMODE_WRITE); - return NULL; - } - blocksize = sb->s_blocksize; hblock = bdev_logical_block_size(bdev); if (blocksize < hblock) { diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 3eb1393f7b81..c1f0763a022b 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1298,7 +1298,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, goto error_bdev; if (s->s_root) - close_bdev_exclusive(bdev, mode); + blkdev_put(bdev, mode | FMODE_EXCL); memset(&args, 0, sizeof(args)); args.ar_quota = GFS2_QUOTA_DEFAULT; @@ -1342,7 +1342,7 @@ error_super: deactivate_locked_super(s); return ERR_PTR(error); error_bdev: - close_bdev_exclusive(bdev, mode); + blkdev_put(bdev, mode | FMODE_EXCL); return ERR_PTR(error); } diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index e1b8493b9aaa..5a290f22dcc3 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1120,16 +1120,13 @@ int lmLogOpen(struct super_block *sb) * file systems to log may have n-to-1 relationship; */ - bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE); + bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, + log); if (IS_ERR(bdev)) { rc = -PTR_ERR(bdev); goto free; } - if ((rc = bd_claim(bdev, log))) { - goto close; - } - log->bdev = bdev; memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid)); @@ -1137,7 +1134,7 @@ int lmLogOpen(struct super_block *sb) * initialize log: */ if ((rc = lmLogInit(log))) - goto unclaim; + goto close; list_add(&log->journal_list, &jfs_external_logs); @@ -1163,11 +1160,8 @@ journal_found: list_del(&log->journal_list); lbmLogShutdown(log); - unclaim: - bd_release(bdev); - close: /* close external log device */ - blkdev_put(bdev, FMODE_READ|FMODE_WRITE); + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); free: /* free log descriptor */ mutex_unlock(&jfs_log_mutex); @@ -1512,8 +1506,7 @@ int lmLogClose(struct super_block *sb) bdev = log->bdev; rc = lmLogShutdown(log); - bd_release(bdev); - blkdev_put(bdev, FMODE_READ|FMODE_WRITE); + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); kfree(log); diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 92ca6fbe09bd..734b9025858e 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -300,7 +300,7 @@ static int bdev_write_sb(struct super_block *sb, struct page *page) static void bdev_put_device(struct logfs_super *s) { - close_bdev_exclusive(s->s_bdev, FMODE_READ|FMODE_WRITE); + blkdev_put(s->s_bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } static int bdev_can_write_buf(struct super_block *sb, u64 ofs) @@ -331,7 +331,7 @@ int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type, if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { int mtdnr = MINOR(bdev->bd_dev); - close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); return logfs_get_sb_mtd(p, mtdnr); } diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index f804d41ec9d3..756a6798d7c8 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1233,7 +1233,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags, } if (!s_new) - close_bdev_exclusive(sd.bdev, mode); + blkdev_put(sd.bdev, mode | FMODE_EXCL); return root_dentry; @@ -1242,7 +1242,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags, failed: if (!s_new) - close_bdev_exclusive(sd.bdev, mode); + blkdev_put(sd.bdev, mode | FMODE_EXCL); return ERR_PTR(err); } diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 52c7557f3e25..d0a2721eaceb 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1674,7 +1674,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, goto out; reg->hr_bdev = I_BDEV(filp->f_mapping->host); - ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ); + ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ, NULL); if (ret) { reg->hr_bdev = NULL; goto out; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 0a8b0ad0c7e2..2e6501d034ab 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -549,7 +549,7 @@ void register_disk(struct gendisk *disk) goto exit; bdev->bd_invalidated = 1; - err = blkdev_get(bdev, FMODE_READ); + err = blkdev_get(bdev, FMODE_READ, NULL); if (err < 0) goto exit; blkdev_put(bdev, FMODE_READ); diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 076c8b194682..b488136f5ace 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2552,8 +2552,6 @@ static int release_journal_dev(struct super_block *super, result = 0; if (journal->j_dev_bd != NULL) { - if (journal->j_dev_bd->bd_dev != super->s_dev) - bd_release(journal->j_dev_bd); result = blkdev_put(journal->j_dev_bd, journal->j_dev_mode); journal->j_dev_bd = NULL; } @@ -2571,7 +2569,7 @@ static int journal_init_dev(struct super_block *super, { int result; dev_t jdev; - fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE; + fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; char b[BDEVNAME_SIZE]; result = 0; @@ -2585,7 +2583,9 @@ static int journal_init_dev(struct super_block *super, /* there is no "jdev" option and journal is on separate device */ if ((!jdev_name || !jdev_name[0])) { - journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode); + if (jdev == super->s_dev) + blkdev_mode &= ~FMODE_EXCL; + journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode, journal); journal->j_dev_mode = blkdev_mode; if (IS_ERR(journal->j_dev_bd)) { result = PTR_ERR(journal->j_dev_bd); @@ -2594,15 +2594,8 @@ static int journal_init_dev(struct super_block *super, "cannot init journal device '%s': %i", __bdevname(jdev, b), result); return result; - } else if (jdev != super->s_dev) { - result = bd_claim(journal->j_dev_bd, journal); - if (result) { - blkdev_put(journal->j_dev_bd, blkdev_mode); - return result; - } - + } else if (jdev != super->s_dev) set_blocksize(journal->j_dev_bd, super->s_blocksize); - } return 0; } diff --git a/fs/super.c b/fs/super.c index ca696155cd9a..22374bf0ba87 100644 --- a/fs/super.c +++ b/fs/super.c @@ -801,13 +801,13 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, /* * s_umount nests inside bd_mutex during - * __invalidate_device(). close_bdev_exclusive() - * acquires bd_mutex and can't be called under - * s_umount. Drop s_umount temporarily. This is safe - * as we're holding an active reference. + * __invalidate_device(). blkdev_put() acquires + * bd_mutex and can't be called under s_umount. Drop + * s_umount temporarily. This is safe as we're + * holding an active reference. */ up_write(&s->s_umount); - close_bdev_exclusive(bdev, mode); + blkdev_put(bdev, mode | FMODE_EXCL); down_write(&s->s_umount); } else { char b[BDEVNAME_SIZE]; @@ -831,7 +831,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, error_s: error = PTR_ERR(s); error_bdev: - close_bdev_exclusive(bdev, mode); + blkdev_put(bdev, mode | FMODE_EXCL); error: return ERR_PTR(error); } @@ -862,7 +862,7 @@ void kill_block_super(struct super_block *sb) bdev->bd_super = NULL; generic_shutdown_super(sb); sync_blockdev(bdev); - close_bdev_exclusive(bdev, mode); + blkdev_put(bdev, mode | FMODE_EXCL); } EXPORT_SYMBOL(kill_block_super); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 9f3a78fe6ae4..a1a6e5ceea67 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -623,7 +623,7 @@ xfs_blkdev_put( struct block_device *bdev) { if (bdev) - close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 66b7f2c5d7e9..1a033e8ebe4c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2006,7 +2006,8 @@ extern struct block_device *bdgrab(struct block_device *bdev); extern void bd_set_size(struct block_device *, loff_t size); extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); -extern struct block_device *open_by_devnum(dev_t, fmode_t); +extern struct block_device *open_by_devnum(dev_t dev, fmode_t mode, + void *holder); extern void invalidate_bdev(struct block_device *); extern int sync_blockdev(struct block_device *bdev); extern struct super_block *freeze_bdev(struct block_device *); @@ -2037,22 +2038,16 @@ extern const struct file_operations def_fifo_fops; extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); -extern int blkdev_get(struct block_device *, fmode_t); -extern int blkdev_put(struct block_device *, fmode_t); -extern int bd_claim(struct block_device *, void *); -extern void bd_release(struct block_device *); +extern int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder); +extern int blkdev_put(struct block_device *bdev, fmode_t mode); #ifdef CONFIG_SYSFS extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); -extern void bd_unlink_disk_holder(struct block_device *bdev); #else static inline int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) { return 0; } -static inline void bd_unlink_disk_holder(struct block_device *bdev) -{ -} #endif #endif @@ -2089,7 +2084,6 @@ extern const char *__bdevname(dev_t, char *buffer); extern const char *bdevname(struct block_device *bdev, char *buffer); extern struct block_device *lookup_bdev(const char *); extern struct block_device *open_bdev_exclusive(const char *, fmode_t, void *); -extern void close_bdev_exclusive(struct block_device *, fmode_t); extern void blkdev_show(struct seq_file *,off_t); #else diff --git a/kernel/power/swap.c b/kernel/power/swap.c index a0e4a86ccf94..513a77f1a0b3 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -223,7 +223,7 @@ static int swsusp_swap_check(void) return res; root_swap = res; - res = blkdev_get(hib_resume_bdev, FMODE_WRITE); + res = blkdev_get(hib_resume_bdev, FMODE_WRITE, NULL); if (res) return res; @@ -907,7 +907,8 @@ int swsusp_check(void) { int error; - hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); + hib_resume_bdev = open_by_devnum(swsusp_resume_device, + FMODE_READ, NULL); if (!IS_ERR(hib_resume_bdev)) { set_blocksize(hib_resume_bdev, PAGE_SIZE); clear_page(swsusp_header); diff --git a/mm/swapfile.c b/mm/swapfile.c index 67ddaaf98c74..b6adcfbf6f48 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1677,7 +1677,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (S_ISBLK(inode->i_mode)) { struct block_device *bdev = I_BDEV(inode); set_blocksize(bdev, p->old_block_size); - bd_release(bdev); + blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } else { mutex_lock(&inode->i_mutex); inode->i_flags &= ~S_SWAPFILE; @@ -1939,7 +1939,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = -EINVAL; if (S_ISBLK(inode->i_mode)) { bdev = I_BDEV(inode); - error = bd_claim(bdev, sys_swapon); + error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL, + sys_swapon); if (error < 0) { bdev = NULL; error = -EINVAL; @@ -2136,7 +2137,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) bad_swap: if (bdev) { set_blocksize(bdev, p->old_block_size); - bd_release(bdev); + blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } destroy_swap_extents(p); swap_cgroup_swapoff(type); -- cgit v1.2.3 From 75f1dc0d076d1c1168f2115f1941ea627d38bd5a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 13 Nov 2010 11:55:17 +0100 Subject: block: check bdev_read_only() from blkdev_get() bdev read-only status can be queried using bdev_read_only() and may change while the device is being opened. Enforce it by checking it from blkdev_get() after open succeeds. This makes bdev_read_only() check in open_bdev_exclusive() and fsg_lun_open() unnecessary. Drop them. Signed-off-by: Tejun Heo Cc: David Brownell Cc: linux-usb@vger.kernel.org --- drivers/usb/gadget/storage_common.c | 7 ++----- fs/block_dev.c | 11 ++++++----- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 3b513bafaf2a..b015561fd602 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -543,7 +543,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) ro = curlun->initially_ro; if (!ro) { filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); - if (-EROFS == PTR_ERR(filp)) + if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES) ro = 1; } if (ro) @@ -558,10 +558,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) if (filp->f_path.dentry) inode = filp->f_path.dentry->d_inode; - if (inode && S_ISBLK(inode->i_mode)) { - if (bdev_read_only(inode->i_bdev)) - ro = 1; - } else if (!inode || !S_ISREG(inode->i_mode)) { + if (!inode || (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) { LINFO(curlun, "invalid file type: %s\n", filename); goto out; } diff --git a/fs/block_dev.c b/fs/block_dev.c index 269bfbbd10fc..606a5259f87f 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1149,6 +1149,12 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) res = __blkdev_get(bdev, mode, 0); + /* __blkdev_get() may alter read only status, check it afterwards */ + if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) { + __blkdev_put(bdev, mode, 0); + res = -EACCES; + } + if (whole) { /* finish claiming */ spin_lock(&bdev_lock); @@ -1453,11 +1459,6 @@ struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *h if (error) return ERR_PTR(error); - if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) { - blkdev_put(bdev, mode); - return ERR_PTR(-EACCES); - } - return bdev; } -- cgit v1.2.3 From d4d77629953eabd3c14f6fa5746f6b28babfc55f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 13 Nov 2010 11:55:18 +0100 Subject: block: clean up blkdev_get() wrappers and their users After recent blkdev_get() modifications, open_by_devnum() and open_bdev_exclusive() are simple wrappers around blkdev_get(). Replace them with blkdev_get_by_dev() and blkdev_get_by_path(). blkdev_get_by_dev() is identical to open_by_devnum(). blkdev_get_by_path() is slightly different in that it doesn't automatically add %FMODE_EXCL to @mode. All users are converted. Most conversions are mechanical and don't introduce any behavior difference. There are several exceptions. * btrfs now sets FMODE_EXCL in btrfs_device->mode, so there's no reason to OR it explicitly on blkdev_put(). * gfs2, nilfs2 and the generic mount_bdev() now set FMODE_EXCL in sb->s_mode. * With the above changes, sb->s_mode now always should contain FMODE_EXCL. WARN_ON_ONCE() added to kill_block_super() to detect errors. The new blkdev_get_*() functions are with proper docbook comments. While at it, add function description to blkdev_get() too. Signed-off-by: Tejun Heo Cc: Philipp Reisner Cc: Neil Brown Cc: Mike Snitzer Cc: Joern Engel Cc: Chris Mason Cc: Jan Kara Cc: "Theodore Ts'o" Cc: KONISHI Ryusuke Cc: reiserfs-devel@vger.kernel.org Cc: xfs-masters@oss.sgi.com Cc: Alexander Viro --- drivers/block/drbd/drbd_nl.c | 12 ++-- drivers/md/dm-table.c | 2 +- drivers/md/md.c | 4 +- drivers/mtd/devices/block2mtd.c | 4 +- fs/block_dev.c | 139 +++++++++++++++++++++++++++------------- fs/btrfs/volumes.c | 24 ++++--- fs/btrfs/volumes.h | 2 +- fs/ext3/super.c | 2 +- fs/ext4/super.c | 2 +- fs/gfs2/ops_fstype.c | 8 +-- fs/jfs/jfs_logmgr.c | 4 +- fs/logfs/dev_bdev.c | 3 +- fs/nilfs2/super.c | 8 +-- fs/reiserfs/journal.c | 6 +- fs/super.c | 9 +-- fs/xfs/linux-2.6/xfs_super.c | 3 +- include/linux/fs.h | 7 +- kernel/power/swap.c | 4 +- 18 files changed, 149 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index fd0346090289..650e43ba4f7c 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -902,8 +902,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp } } - bdev = open_bdev_exclusive(nbc->dc.backing_dev, - FMODE_READ | FMODE_WRITE, mdev); + bdev = blkdev_get_by_path(nbc->dc.backing_dev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev); if (IS_ERR(bdev)) { dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev, PTR_ERR(bdev)); @@ -920,10 +920,10 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp * should check it for you already; but if you don't, or * someone fooled it, we need to double check here) */ - bdev = open_bdev_exclusive(nbc->dc.meta_dev, - FMODE_READ | FMODE_WRITE, - (nbc->dc.meta_dev_idx < 0) ? - (void *)mdev : (void *)drbd_m_holder); + bdev = blkdev_get_by_path(nbc->dc.meta_dev, + FMODE_READ | FMODE_WRITE | FMODE_EXCL, + (nbc->dc.meta_dev_idx < 0) ? + (void *)mdev : (void *)drbd_m_holder); if (IS_ERR(bdev)) { dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev, PTR_ERR(bdev)); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 9e88ca0c55e9..67150c32986c 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -325,7 +325,7 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev, BUG_ON(d->dm_dev.bdev); - bdev = open_by_devnum(dev, d->dm_dev.mode | FMODE_EXCL, _claim_ptr); + bdev = blkdev_get_by_dev(dev, d->dm_dev.mode | FMODE_EXCL, _claim_ptr); if (IS_ERR(bdev)) return PTR_ERR(bdev); diff --git a/drivers/md/md.c b/drivers/md/md.c index 6af951ffe0bb..5aaa6bfbe638 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1934,8 +1934,8 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, - shared ? (mdk_rdev_t *)lock_rdev : rdev); + bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, + shared ? (mdk_rdev_t *)lock_rdev : rdev); if (IS_ERR(bdev)) { printk(KERN_ERR "md: could not open %s.\n", __bdevname(dev, b)); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index aa557beb8f51..f29a6f9df6e7 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -247,7 +247,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) return NULL; /* Get a handle on the device */ - bdev = open_bdev_exclusive(devname, mode, dev); + bdev = blkdev_get_by_path(devname, mode, dev); #ifndef MODULE if (IS_ERR(bdev)) { @@ -256,7 +256,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev_t devt = name_to_dev_t(devname); if (devt) - bdev = open_by_devnum(devt, mode, dev); + bdev = blkdev_get_by_dev(devt, mode, dev); } #endif diff --git a/fs/block_dev.c b/fs/block_dev.c index 606a5259f87f..c1c1b8c3fb99 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -854,24 +854,6 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev) { } #endif -/* - * Tries to open block device by device number. Use it ONLY if you - * really do not have anything better - i.e. when you are behind a - * truly sucky interface and all you are given is a device number. _Never_ - * to be used for internal purposes. If you ever need it - reconsider - * your API. - */ -struct block_device *open_by_devnum(dev_t dev, fmode_t mode, void *holder) -{ - struct block_device *bdev = bdget(dev); - int err = -ENOMEM; - if (bdev) - err = blkdev_get(bdev, mode, holder); - return err ? ERR_PTR(err) : bdev; -} - -EXPORT_SYMBOL(open_by_devnum); - /** * flush_disk - invalidates all buffer-cache entries on a disk * @@ -1132,6 +1114,25 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) return ret; } +/** + * blkdev_get - open a block device + * @bdev: block_device to open + * @mode: FMODE_* mask + * @holder: exclusive holder identifier + * + * Open @bdev with @mode. If @mode includes %FMODE_EXCL, @bdev is + * open with exclusive access. Specifying %FMODE_EXCL with %NULL + * @holder is invalid. Exclusive opens may nest for the same @holder. + * + * On success, the reference count of @bdev is unchanged. On failure, + * @bdev is put. + * + * CONTEXT: + * Might sleep. + * + * RETURNS: + * 0 on success, -errno on failure. + */ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) { struct block_device *whole = NULL; @@ -1186,6 +1187,80 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) } EXPORT_SYMBOL(blkdev_get); +/** + * blkdev_get_by_path - open a block device by name + * @path: path to the block device to open + * @mode: FMODE_* mask + * @holder: exclusive holder identifier + * + * Open the blockdevice described by the device file at @path. @mode + * and @holder are identical to blkdev_get(). + * + * On success, the returned block_device has reference count of one. + * + * CONTEXT: + * Might sleep. + * + * RETURNS: + * Pointer to block_device on success, ERR_PTR(-errno) on failure. + */ +struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, + void *holder) +{ + struct block_device *bdev; + int err; + + bdev = lookup_bdev(path); + if (IS_ERR(bdev)) + return bdev; + + err = blkdev_get(bdev, mode, holder); + if (err) + return ERR_PTR(err); + + return bdev; +} +EXPORT_SYMBOL(blkdev_get_by_path); + +/** + * blkdev_get_by_dev - open a block device by device number + * @dev: device number of block device to open + * @mode: FMODE_* mask + * @holder: exclusive holder identifier + * + * Open the blockdevice described by device number @dev. @mode and + * @holder are identical to blkdev_get(). + * + * Use it ONLY if you really do not have anything better - i.e. when + * you are behind a truly sucky interface and all you are given is a + * device number. _Never_ to be used for internal purposes. If you + * ever need it - reconsider your API. + * + * On success, the returned block_device has reference count of one. + * + * CONTEXT: + * Might sleep. + * + * RETURNS: + * Pointer to block_device on success, ERR_PTR(-errno) on failure. + */ +struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder) +{ + struct block_device *bdev; + int err; + + bdev = bdget(dev); + if (!bdev) + return ERR_PTR(-ENOMEM); + + err = blkdev_get(bdev, mode, holder); + if (err) + return ERR_PTR(err); + + return bdev; +} +EXPORT_SYMBOL(blkdev_get_by_dev); + static int blkdev_open(struct inode * inode, struct file * filp) { struct block_device *bdev; @@ -1436,34 +1511,6 @@ fail: } EXPORT_SYMBOL(lookup_bdev); -/** - * open_bdev_exclusive - open a block device by name and set it up for use - * - * @path: special file representing the block device - * @mode: FMODE_... combination to pass be used - * @holder: owner for exclusion - * - * Open the blockdevice described by the special file at @path, claim it - * for the @holder. - */ -struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder) -{ - struct block_device *bdev; - int error; - - bdev = lookup_bdev(path); - if (IS_ERR(bdev)) - return bdev; - - error = blkdev_get(bdev, mode | FMODE_EXCL, holder); - if (error) - return ERR_PTR(error); - - return bdev; -} - -EXPORT_SYMBOL(open_bdev_exclusive); - int __invalidate_device(struct block_device *bdev) { struct super_block *sb = get_super(bdev); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f1b729d3b883..95324e9f9280 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -489,7 +489,7 @@ again: continue; if (device->bdev) { - blkdev_put(device->bdev, device->mode | FMODE_EXCL); + blkdev_put(device->bdev, device->mode); device->bdev = NULL; fs_devices->open_devices--; } @@ -523,7 +523,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) list_for_each_entry(device, &fs_devices->devices, dev_list) { if (device->bdev) { - blkdev_put(device->bdev, device->mode | FMODE_EXCL); + blkdev_put(device->bdev, device->mode); fs_devices->open_devices--; } if (device->writeable) { @@ -580,13 +580,15 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int seeding = 1; int ret = 0; + flags |= FMODE_EXCL; + list_for_each_entry(device, head, dev_list) { if (device->bdev) continue; if (!device->name) continue; - bdev = open_bdev_exclusive(device->name, flags, holder); + bdev = blkdev_get_by_path(device->name, flags, holder); if (IS_ERR(bdev)) { printk(KERN_INFO "open %s failed\n", device->name); goto error; @@ -638,7 +640,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, error_brelse: brelse(bh); error_close: - blkdev_put(bdev, flags | FMODE_EXCL); + blkdev_put(bdev, flags); error: continue; } @@ -684,7 +686,8 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, mutex_lock(&uuid_mutex); - bdev = open_bdev_exclusive(path, flags, holder); + flags |= FMODE_EXCL; + bdev = blkdev_get_by_path(path, flags, holder); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); @@ -716,7 +719,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, brelse(bh); error_close: - blkdev_put(bdev, flags | FMODE_EXCL); + blkdev_put(bdev, flags); error: mutex_unlock(&uuid_mutex); return ret; @@ -1179,8 +1182,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) goto out; } } else { - bdev = open_bdev_exclusive(device_path, FMODE_READ, - root->fs_info->bdev_holder); + bdev = blkdev_get_by_path(device_path, FMODE_READ | FMODE_EXCL, + root->fs_info->bdev_holder); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); goto out; @@ -1244,7 +1247,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) root->fs_info->fs_devices->latest_bdev = next_device->bdev; if (device->bdev) { - blkdev_put(device->bdev, device->mode | FMODE_EXCL); + blkdev_put(device->bdev, device->mode); device->bdev = NULL; device->fs_devices->open_devices--; } @@ -1439,7 +1442,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) if ((sb->s_flags & MS_RDONLY) && !root->fs_info->fs_devices->seeding) return -EINVAL; - bdev = open_bdev_exclusive(device_path, 0, root->fs_info->bdev_holder); + bdev = blkdev_get_by_path(device_path, FMODE_EXCL, + root->fs_info->bdev_holder); if (IS_ERR(bdev)) return PTR_ERR(bdev); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 2b638b6e4eea..856e75770304 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -49,7 +49,7 @@ struct btrfs_device { struct block_device *bdev; - /* the mode sent to open_bdev_exclusive */ + /* the mode sent to blkdev_get */ fmode_t mode; char *name; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 23e7513dba9c..123720ba786d 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -347,7 +347,7 @@ static struct block_device *ext3_blkdev_get(dev_t dev, struct super_block *sb) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); + bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); if (IS_ERR(bdev)) goto fail; return bdev; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 5dd0b3e76fa8..bd63e6927219 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -647,7 +647,7 @@ static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb) struct block_device *bdev; char b[BDEVNAME_SIZE]; - bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); + bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); if (IS_ERR(bdev)) goto fail; return bdev; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c1f0763a022b..bc56ccf98ffd 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1268,7 +1268,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, { struct block_device *bdev; struct super_block *s; - fmode_t mode = FMODE_READ; + fmode_t mode = FMODE_READ | FMODE_EXCL; int error; struct gfs2_args args; struct gfs2_sbd *sdp; @@ -1276,7 +1276,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; - bdev = open_bdev_exclusive(dev_name, mode, fs_type); + bdev = blkdev_get_by_path(dev_name, mode, fs_type); if (IS_ERR(bdev)) return ERR_CAST(bdev); @@ -1298,7 +1298,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, goto error_bdev; if (s->s_root) - blkdev_put(bdev, mode | FMODE_EXCL); + blkdev_put(bdev, mode); memset(&args, 0, sizeof(args)); args.ar_quota = GFS2_QUOTA_DEFAULT; @@ -1342,7 +1342,7 @@ error_super: deactivate_locked_super(s); return ERR_PTR(error); error_bdev: - blkdev_put(bdev, mode | FMODE_EXCL); + blkdev_put(bdev, mode); return ERR_PTR(error); } diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 5a290f22dcc3..278e3fb40b71 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1120,8 +1120,8 @@ int lmLogOpen(struct super_block *sb) * file systems to log may have n-to-1 relationship; */ - bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, - log); + bdev = blkdev_get_by_dev(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, + log); if (IS_ERR(bdev)) { rc = -PTR_ERR(bdev); goto free; diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 734b9025858e..723bc5bca09a 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -325,7 +325,8 @@ int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type, { struct block_device *bdev; - bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, type); + bdev = blkdev_get_by_path(devname, FMODE_READ|FMODE_WRITE|FMODE_EXCL, + type); if (IS_ERR(bdev)) return PTR_ERR(bdev); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 756a6798d7c8..0030640e2d72 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1147,14 +1147,14 @@ nilfs_mount(struct file_system_type *fs_type, int flags, { struct nilfs_super_data sd; struct super_block *s; - fmode_t mode = FMODE_READ; + fmode_t mode = FMODE_READ | FMODE_EXCL; struct dentry *root_dentry; int err, s_new = false; if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; - sd.bdev = open_bdev_exclusive(dev_name, mode, fs_type); + sd.bdev = blkdev_get_by_path(dev_name, mode, fs_type); if (IS_ERR(sd.bdev)) return ERR_CAST(sd.bdev); @@ -1233,7 +1233,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags, } if (!s_new) - blkdev_put(sd.bdev, mode | FMODE_EXCL); + blkdev_put(sd.bdev, mode); return root_dentry; @@ -1242,7 +1242,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags, failed: if (!s_new) - blkdev_put(sd.bdev, mode | FMODE_EXCL); + blkdev_put(sd.bdev, mode); return ERR_PTR(err); } diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index b488136f5ace..e2fce519c0f2 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2585,7 +2585,8 @@ static int journal_init_dev(struct super_block *super, if ((!jdev_name || !jdev_name[0])) { if (jdev == super->s_dev) blkdev_mode &= ~FMODE_EXCL; - journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode, journal); + journal->j_dev_bd = blkdev_get_by_dev(jdev, blkdev_mode, + journal); journal->j_dev_mode = blkdev_mode; if (IS_ERR(journal->j_dev_bd)) { result = PTR_ERR(journal->j_dev_bd); @@ -2601,8 +2602,7 @@ static int journal_init_dev(struct super_block *super, } journal->j_dev_mode = blkdev_mode; - journal->j_dev_bd = open_bdev_exclusive(jdev_name, - blkdev_mode, journal); + journal->j_dev_bd = blkdev_get_by_path(jdev_name, blkdev_mode, journal); if (IS_ERR(journal->j_dev_bd)) { result = PTR_ERR(journal->j_dev_bd); journal->j_dev_bd = NULL; diff --git a/fs/super.c b/fs/super.c index 22374bf0ba87..5d9a4497849a 100644 --- a/fs/super.c +++ b/fs/super.c @@ -766,13 +766,13 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, { struct block_device *bdev; struct super_block *s; - fmode_t mode = FMODE_READ; + fmode_t mode = FMODE_READ | FMODE_EXCL; int error = 0; if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; - bdev = open_bdev_exclusive(dev_name, mode, fs_type); + bdev = blkdev_get_by_path(dev_name, mode, fs_type); if (IS_ERR(bdev)) return ERR_CAST(bdev); @@ -807,7 +807,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, * holding an active reference. */ up_write(&s->s_umount); - blkdev_put(bdev, mode | FMODE_EXCL); + blkdev_put(bdev, mode); down_write(&s->s_umount); } else { char b[BDEVNAME_SIZE]; @@ -831,7 +831,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type, error_s: error = PTR_ERR(s); error_bdev: - blkdev_put(bdev, mode | FMODE_EXCL); + blkdev_put(bdev, mode); error: return ERR_PTR(error); } @@ -862,6 +862,7 @@ void kill_block_super(struct super_block *sb) bdev->bd_super = NULL; generic_shutdown_super(sb); sync_blockdev(bdev); + WARN_ON_ONCE(!(mode & FMODE_EXCL)); blkdev_put(bdev, mode | FMODE_EXCL); } diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index a1a6e5ceea67..9209cd199c47 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -609,7 +609,8 @@ xfs_blkdev_get( { int error = 0; - *bdevp = open_bdev_exclusive(name, FMODE_READ|FMODE_WRITE, mp); + *bdevp = blkdev_get_by_path(name, FMODE_READ|FMODE_WRITE|FMODE_EXCL, + mp); if (IS_ERR(*bdevp)) { error = PTR_ERR(*bdevp); printk("XFS: Invalid device [%s], error=%d\n", name, error); diff --git a/include/linux/fs.h b/include/linux/fs.h index 1a033e8ebe4c..f48501563917 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2006,8 +2006,6 @@ extern struct block_device *bdgrab(struct block_device *bdev); extern void bd_set_size(struct block_device *, loff_t size); extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); -extern struct block_device *open_by_devnum(dev_t dev, fmode_t mode, - void *holder); extern void invalidate_bdev(struct block_device *); extern int sync_blockdev(struct block_device *bdev); extern struct super_block *freeze_bdev(struct block_device *); @@ -2039,6 +2037,10 @@ extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); extern int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder); +extern struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, + void *holder); +extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, + void *holder); extern int blkdev_put(struct block_device *bdev, fmode_t mode); #ifdef CONFIG_SYSFS extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); @@ -2083,7 +2085,6 @@ static inline void unregister_chrdev(unsigned int major, const char *name) extern const char *__bdevname(dev_t, char *buffer); extern const char *bdevname(struct block_device *bdev, char *buffer); extern struct block_device *lookup_bdev(const char *); -extern struct block_device *open_bdev_exclusive(const char *, fmode_t, void *); extern void blkdev_show(struct seq_file *,off_t); #else diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 513a77f1a0b3..b019609d1b45 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -907,8 +907,8 @@ int swsusp_check(void) { int error; - hib_resume_bdev = open_by_devnum(swsusp_resume_device, - FMODE_READ, NULL); + hib_resume_bdev = blkdev_get_by_dev(swsusp_resume_device, + FMODE_READ, NULL); if (!IS_ERR(hib_resume_bdev)) { set_blocksize(hib_resume_bdev, PAGE_SIZE); clear_page(swsusp_header); -- cgit v1.2.3 From 5e78330126e23e009502b21d1efdabd68ab91397 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 14 Nov 2010 22:32:36 +0100 Subject: drm/i915: fix relaxed tiling for gen <= 3 && !g33 g33/pineview doesn't have any alignment constrains for unfenced tiled buffers. But older chips have. Fix this. Problem introduced in a00b10c360b35d6431a94cbf130a4e162870d661. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 43 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 52f5c194c50f..f2038f6df3b0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1467,7 +1467,7 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj) * @obj: object to check * * Return the required GTT alignment for an object, taking into account - * potential fence register mapping if needed. + * potential fence register mapping. */ static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv) @@ -1489,6 +1489,41 @@ i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv) return i915_gem_get_gtt_size(obj_priv); } +/** + * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an + * unfenced object + * @obj: object to check + * + * Return the required GTT alignment for an object, only taking into account + * unfenced tiled surface requirements. + */ +static uint32_t +i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj_priv) +{ + struct drm_device *dev = obj_priv->base.dev; + int tile_height; + + /* + * Minimum alignment is 4k (GTT page size) for sane hw. + */ + if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || + obj_priv->tiling_mode == I915_TILING_NONE) + return 4096; + + /* + * Older chips need unfenced tiled buffers to be aligned to the left + * edge of an even tile row (where tile rows are counted as if the bo is + * placed in a fenced gtt region). + */ + if (IS_GEN2(dev) || + (obj_priv->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))) + tile_height = 32; + else + tile_height = 8; + + return tile_height * obj_priv->stride * 2; +} + static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) { @@ -2689,7 +2724,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_mm_node *free_space; gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; - u32 size, fence_size, fence_alignment; + u32 size, fence_size, fence_alignment, unfenced_alignment; bool mappable, fenceable; int ret; @@ -2700,9 +2735,11 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, fence_size = i915_gem_get_gtt_size(obj_priv); fence_alignment = i915_gem_get_gtt_alignment(obj_priv); + unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj_priv); if (alignment == 0) - alignment = map_and_fenceable ? fence_alignment : 4096; + alignment = map_and_fenceable ? fence_alignment : + unfenced_alignment; if (map_and_fenceable && alignment & (fence_alignment - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); return -EINVAL; -- cgit v1.2.3 From df15315899c0641412bd54b29565a70b078a6ac8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Nov 2010 05:25:58 +0000 Subject: drm/i915: Fix current tiling check for relaxed fencing As we may bind an object with the correct alignment, but with an invalid size, it may pass the current checks on whether the object may be reused with a fence. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_tiling.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 0597a737ebad..a517b48d441d 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -245,6 +245,17 @@ i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode) if (INTEL_INFO(obj->dev)->gen >= 4) return true; + if (!obj_priv->gtt_space) + return true; + + if (INTEL_INFO(obj->dev)->gen == 3) { + if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + return false; + } else { + if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) + return false; + } + /* * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. @@ -257,16 +268,11 @@ i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode) while (size < obj_priv->base.size) size <<= 1; - if (obj_priv->gtt_offset & (size - 1)) + if (obj_priv->gtt_space->size != size) return false; - if (INTEL_INFO(obj->dev)->gen == 3) { - if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) - return false; - } else { - if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) - return false; - } + if (obj_priv->gtt_offset & (size - 1)) + return false; return true; } -- cgit v1.2.3 From 149d730fac715e077a8bcceb4b27f3523b314558 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Tue, 9 Nov 2010 23:20:26 +0100 Subject: spelling fix in drivers/misc/Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonathan Neuschäfer Signed-off-by: Jiri Kosina --- drivers/misc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4d073f1e4502..1e1a4be8eb6c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -402,7 +402,7 @@ config TI_DAC7512 DAC7512 16-bit digital-to-analog converter. This driver can also be built as a module. If so, the module - will be calles ti_dac7512. + will be called ti_dac7512. config VMWARE_BALLOON tristate "VMware Balloon Driver" -- cgit v1.2.3 From 6021afcf19d8c6f5db6d11cadcfb6a22d0c28a48 Mon Sep 17 00:00:00 2001 From: "Edgar (gimli) Hucek" Date: Tue, 9 Nov 2010 17:38:42 +0100 Subject: input: bcm5974: Add support for MacBookAir3 This patch adds support for the MacBookAir3,1 and MacBookAir3,2 models. [rydberg@euromail.se: touchpad range calibration] Cc: stable@kernel.org Signed-off-by: Edgar (gimli) Hucek Signed-off-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/input/mouse/bcm5974.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index b95231763911..ee82851afe3e 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -55,6 +55,14 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 +/* MacbookAir3,2 (unibody), aka wellspring5 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f +#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240 +#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241 +/* MacbookAir3,1 (unibody), aka wellspring4 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 +#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -80,6 +88,14 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), + /* MacbookAir3,2 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS), + /* MacbookAir3,1 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), /* Terminating entry */ {} }; @@ -234,6 +250,30 @@ static const struct bcm5974_config bcm5974_config_table[] = { { DIM_X, DIM_X / SN_COORD, -4460, 5166 }, { DIM_Y, DIM_Y / SN_COORD, -75, 6700 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING4_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING4_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, + { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } + }, + { + USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4616, 5112 }, + { DIM_Y, DIM_Y / SN_COORD, -142, 5234 } + }, {} }; -- cgit v1.2.3 From e987fa357a4c585e4f43fc3e0ab15ba9e908e233 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 7 Nov 2010 23:24:44 +0100 Subject: infiniband: Only include mutex.h once in drivers/infiniband/hw/cxgb4/iw_cxgb4.h Only include the header linux/mutex.h once inside drivers/infiniband/hw/cxgb4/iw_cxgb4.h Signed-off-by: Jesper Juhl Signed-off-by: Jiri Kosina --- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 16032cdb4337..42bb5757d1b9 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -46,7 +46,6 @@ #include #include #include -#include #include -- cgit v1.2.3 From d07335e51df0c6dec202d315fc4f1f7e100eec4e Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 16 Nov 2010 12:52:38 +0100 Subject: block: Rename "block_remap" tracepoint to "block_bio_remap" to clarify the event. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Mike Snitzer Signed-off-by: Jens Axboe --- block/blk-core.c | 10 +++++----- drivers/md/dm.c | 4 ++-- include/trace/events/block.h | 6 +++--- kernel/trace/blktrace.c | 12 ++++++------ 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/block/blk-core.c b/block/blk-core.c index 4ce953f1b390..151070541e21 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -33,7 +33,7 @@ #include "blk.h" -EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap); +EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); @@ -1329,9 +1329,9 @@ static inline void blk_partition_remap(struct bio *bio) bio->bi_sector += p->start_sect; bio->bi_bdev = bdev->bd_contains; - trace_block_remap(bdev_get_queue(bio->bi_bdev), bio, - bdev->bd_dev, - bio->bi_sector - p->start_sect); + trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio, + bdev->bd_dev, + bio->bi_sector - p->start_sect); } } @@ -1500,7 +1500,7 @@ static inline void __generic_make_request(struct bio *bio) goto end_io; if (old_sector != -1) - trace_block_remap(q, bio, old_dev, old_sector); + trace_block_bio_remap(q, bio, old_dev, old_sector); old_sector = bio->bi_sector; old_dev = bio->bi_bdev->bd_dev; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 7cb1352f7e7a..0a2b5516bc21 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -990,8 +990,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, if (r == DM_MAPIO_REMAPPED) { /* the bio has been remapped so dispatch it */ - trace_block_remap(bdev_get_queue(clone->bi_bdev), clone, - tio->io->bio->bi_bdev->bd_dev, sector); + trace_block_bio_remap(bdev_get_queue(clone->bi_bdev), clone, + tio->io->bio->bi_bdev->bd_dev, sector); generic_make_request(clone); } else if (r < 0 || r == DM_MAPIO_REQUEUE) { diff --git a/include/trace/events/block.h b/include/trace/events/block.h index d8ce278515c3..b56c65dc105d 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -486,16 +486,16 @@ TRACE_EVENT(block_split, ); /** - * block_remap - map request for a partition to the raw device + * block_bio_remap - map request for a logical device to the raw device * @q: queue holding the operation * @bio: revised operation * @dev: device for the operation * @from: original sector for the operation * - * An operation for a partition on a block device has been mapped to the + * An operation for a logical device has been mapped to the * raw block device. */ -TRACE_EVENT(block_remap, +TRACE_EVENT(block_bio_remap, TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev, sector_t from), diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 7b8ec0281548..2b8e2ee7c0ef 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -887,7 +887,7 @@ static void blk_add_trace_split(void *ignore, } /** - * blk_add_trace_remap - Add a trace for a remap operation + * blk_add_trace_bio_remap - Add a trace for a bio-remap operation * @ignore: trace callback data parameter (not used) * @q: queue the io is for * @bio: the source bio @@ -899,9 +899,9 @@ static void blk_add_trace_split(void *ignore, * it spans a stripe (or similar). Add a trace for that action. * **/ -static void blk_add_trace_remap(void *ignore, - struct request_queue *q, struct bio *bio, - dev_t dev, sector_t from) +static void blk_add_trace_bio_remap(void *ignore, + struct request_queue *q, struct bio *bio, + dev_t dev, sector_t from) { struct blk_trace *bt = q->blk_trace; struct blk_io_trace_remap r; @@ -1016,7 +1016,7 @@ static void blk_register_tracepoints(void) WARN_ON(ret); ret = register_trace_block_split(blk_add_trace_split, NULL); WARN_ON(ret); - ret = register_trace_block_remap(blk_add_trace_remap, NULL); + ret = register_trace_block_bio_remap(blk_add_trace_bio_remap, NULL); WARN_ON(ret); ret = register_trace_block_rq_remap(blk_add_trace_rq_remap, NULL); WARN_ON(ret); @@ -1025,7 +1025,7 @@ static void blk_register_tracepoints(void) static void blk_unregister_tracepoints(void) { unregister_trace_block_rq_remap(blk_add_trace_rq_remap, NULL); - unregister_trace_block_remap(blk_add_trace_remap, NULL); + unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL); unregister_trace_block_split(blk_add_trace_split, NULL); unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL); unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL); -- cgit v1.2.3 From 073ef1f6e508688392580e4f35dcad9aabd1e100 Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Tue, 9 Nov 2010 21:48:49 +0100 Subject: hibernation: constify platform_hibernation_ops Patch against mainline. Changes since v1: added one hunk; no longer adding "const" qualifier to pointers in platform_hibernation_ops after seeing b4144e4f6e3b448d322095ca08af393682a69e33. Signed-off-by: Jiri Kosina --- drivers/acpi/sleep.c | 4 ++-- include/linux/suspend.h | 4 ++-- kernel/power/hibernate.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 721d93b3ceee..5149c9bf7015 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -498,7 +498,7 @@ static void acpi_pm_thaw(void) acpi_enable_all_runtime_gpes(); } -static struct platform_hibernation_ops acpi_hibernation_ops = { +static const struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, .pre_snapshot = acpi_pm_prepare, @@ -541,7 +541,7 @@ static int acpi_hibernation_begin_old(void) * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has * been requested. */ -static struct platform_hibernation_ops acpi_hibernation_ops_old = { +static const struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, .pre_snapshot = acpi_pm_pre_suspend, diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 26697514c5ec..40ead943fd6a 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -245,7 +245,7 @@ extern void swsusp_set_page_free(struct page *); extern void swsusp_unset_page_free(struct page *); extern unsigned long get_safe_page(gfp_t gfp_mask); -extern void hibernation_set_ops(struct platform_hibernation_ops *ops); +extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); extern bool system_entering_hibernation(void); #else /* CONFIG_HIBERNATION */ @@ -253,7 +253,7 @@ static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } static inline void swsusp_set_page_free(struct page *p) {} static inline void swsusp_unset_page_free(struct page *p) {} -static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {} +static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {} static inline int hibernate(void) { return -ENOSYS; } static inline bool system_entering_hibernation(void) { return false; } #endif /* CONFIG_HIBERNATION */ diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 657272e91d0a..491b81a27111 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -51,14 +51,14 @@ enum { static int hibernation_mode = HIBERNATION_SHUTDOWN; -static struct platform_hibernation_ops *hibernation_ops; +static const struct platform_hibernation_ops *hibernation_ops; /** * hibernation_set_ops - set the global hibernate operations * @ops: the hibernation operations to use in subsequent hibernation transitions */ -void hibernation_set_ops(struct platform_hibernation_ops *ops) +void hibernation_set_ops(const struct platform_hibernation_ops *ops) { if (ops && !(ops->begin && ops->end && ops->pre_snapshot && ops->prepare && ops->finish && ops->enter && ops->pre_restore -- cgit v1.2.3 From acc2472ed33fc5e72482cc3b3b846077d97c2f8b Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Tue, 16 Nov 2010 14:14:02 +0100 Subject: backlight: constify backlight_ops backlight_device_register has been expecting a const "ops" argument, and using it as such, since 9905a43b2d563e6f89e4c63c4278ada03f2ebb14. Let's make the remaining backlight_ops instances const. Inspired by hunks of the grsecurity patch, updated for newer kernels. Signed-off-by: Lionel Debroux Acked-by: Ingo Molnar Signed-off-by: Jiri Kosina --- drivers/acpi/video.c | 2 +- drivers/gpu/drm/nouveau/nouveau_backlight.c | 4 ++-- drivers/macintosh/via-pmu-backlight.c | 4 ++-- drivers/platform/x86/acer-wmi.c | 2 +- drivers/platform/x86/asus-laptop.c | 2 +- drivers/platform/x86/asus_acpi.c | 2 +- drivers/platform/x86/dell-laptop.c | 2 +- drivers/platform/x86/eeepc-laptop.c | 2 +- drivers/platform/x86/fujitsu-laptop.c | 2 +- drivers/platform/x86/sony-laptop.c | 2 +- drivers/platform/x86/thinkpad_acpi.c | 2 +- drivers/platform/x86/toshiba_acpi.c | 2 +- drivers/staging/msm/msm_fb_bl.c | 2 +- drivers/staging/olpc_dcon/olpc_dcon.c | 2 +- drivers/staging/samsung-laptop/samsung-laptop.c | 2 +- drivers/video/atmel_lcdfb.c | 2 +- drivers/video/aty/aty128fb.c | 2 +- drivers/video/aty/atyfb_base.c | 2 +- drivers/video/aty/radeon_backlight.c | 2 +- drivers/video/backlight/88pm860x_bl.c | 2 +- drivers/video/backlight/max8925_bl.c | 2 +- drivers/video/nvidia/nv_backlight.c | 2 +- drivers/video/omap2/displays/panel-taal.c | 2 +- drivers/video/riva/fbdev.c | 2 +- 24 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5cd0228d2daa..15a0fde4b32a 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -260,7 +260,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd) vd->brightness->levels[request_level]); } -static struct backlight_ops acpi_backlight_ops = { +static const struct backlight_ops acpi_backlight_ops = { .get_brightness = acpi_video_get_brightness, .update_status = acpi_video_set_brightness, }; diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 406228f4a2a0..8933e985c227 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -58,7 +58,7 @@ static int nv40_set_intensity(struct backlight_device *bd) return 0; } -static struct backlight_ops nv40_bl_ops = { +static const struct backlight_ops nv40_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = nv40_get_intensity, .update_status = nv40_set_intensity, @@ -81,7 +81,7 @@ static int nv50_set_intensity(struct backlight_device *bd) return 0; } -static struct backlight_ops nv50_bl_ops = { +static const struct backlight_ops nv50_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = nv50_get_intensity, .update_status = nv50_set_intensity, diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 1cec02f6c431..ade1e656bfb2 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -15,7 +15,7 @@ #define MAX_PMU_LEVEL 0xFF -static struct backlight_ops pmu_backlight_data; +static const struct backlight_ops pmu_backlight_data; static DEFINE_SPINLOCK(pmu_backlight_lock); static int sleeping, uses_pmu_bl; static u8 bl_curve[FB_BACKLIGHT_LEVELS]; @@ -115,7 +115,7 @@ static int pmu_backlight_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops pmu_backlight_data = { +static const struct backlight_ops pmu_backlight_data = { .get_brightness = pmu_backlight_get_brightness, .update_status = pmu_backlight_update_status, diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c8c65375bfe2..1d0b707aeafc 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -915,7 +915,7 @@ static int update_bl_status(struct backlight_device *bd) return 0; } -static struct backlight_ops acer_bl_ops = { +static const struct backlight_ops acer_bl_ops = { .get_brightness = read_brightness, .update_status = update_bl_status, }; diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 60a5a5c6b50a..3640599446fc 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -621,7 +621,7 @@ static int update_bl_status(struct backlight_device *bd) return asus_lcd_set(asus, value); } -static struct backlight_ops asusbl_ops = { +static const struct backlight_ops asusbl_ops = { .get_brightness = asus_read_brightness, .update_status = update_bl_status, }; diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index ca05aefd03bf..4633fd8532cc 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -1467,7 +1467,7 @@ static int asus_hotk_remove(struct acpi_device *device, int type) return 0; } -static struct backlight_ops asus_backlight_data = { +static const struct backlight_ops asus_backlight_data = { .get_brightness = read_brightness, .update_status = set_brightness_status, }; diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index cf8a89a0d8f5..34657f96b5a5 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -546,7 +546,7 @@ out: return buffer->output[1]; } -static struct backlight_ops dell_ops = { +static const struct backlight_ops dell_ops = { .get_brightness = dell_get_intensity, .update_status = dell_send_intensity, }; diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index b2edfdcdcb84..c062a6534590 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1115,7 +1115,7 @@ static int update_bl_status(struct backlight_device *bd) return set_brightness(bd, bd->props.brightness); } -static struct backlight_ops eeepcbl_ops = { +static const struct backlight_ops eeepcbl_ops = { .get_brightness = read_brightness, .update_status = update_bl_status, }; diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f44cd2620ff9..34d0dc590d76 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -437,7 +437,7 @@ static int bl_update_status(struct backlight_device *b) return ret; } -static struct backlight_ops fujitsubl_ops = { +static const struct backlight_ops fujitsubl_ops = { .get_brightness = bl_get_brightness, .update_status = bl_update_status, }; diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f200677851b8..f8b2fc992276 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -856,7 +856,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) } static struct backlight_device *sony_backlight_device; -static struct backlight_ops sony_backlight_ops = { +static const struct backlight_ops sony_backlight_ops = { .update_status = sony_backlight_update_status, .get_brightness = sony_backlight_get_brightness, }; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 304333faf441..efda9c54e0e2 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6109,7 +6109,7 @@ static void tpacpi_brightness_notify_change(void) BACKLIGHT_UPDATE_HOTKEY); } -static struct backlight_ops ibm_backlight_data = { +static const struct backlight_ops ibm_backlight_data = { .get_brightness = brightness_get, .update_status = brightness_update_status, }; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 06f304f46e02..81bca5a4d8aa 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -840,7 +840,7 @@ static void remove_toshiba_proc_entries(void) remove_proc_entry("version", toshiba_proc_dir); } -static struct backlight_ops toshiba_backlight_data = { +static const struct backlight_ops toshiba_backlight_data = { .get_brightness = get_lcd, .update_status = set_lcd_status, }; diff --git a/drivers/staging/msm/msm_fb_bl.c b/drivers/staging/msm/msm_fb_bl.c index 033fc9486e01..2a8077511fc0 100644 --- a/drivers/staging/msm/msm_fb_bl.c +++ b/drivers/staging/msm/msm_fb_bl.c @@ -42,7 +42,7 @@ static int msm_fb_bl_update_status(struct backlight_device *pbd) return 0; } -static struct backlight_ops msm_fb_bl_ops = { +static const struct backlight_ops msm_fb_bl_ops = { .get_brightness = msm_fb_bl_get_brightness, .update_status = msm_fb_bl_update_status, }; diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 75aa7a36307d..d40ff41774be 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -616,7 +616,7 @@ static struct device_attribute dcon_device_files[] = { __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store), }; -static struct backlight_ops dcon_bl_ops = { +static const struct backlight_ops dcon_bl_ops = { .get_brightness = dconbl_get, .update_status = dconbl_set }; diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c index eb44b60e1eb5..80eeec6d6719 100644 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ b/drivers/staging/samsung-laptop/samsung-laptop.c @@ -269,7 +269,7 @@ static int update_status(struct backlight_device *bd) return 0; } -static struct backlight_ops backlight_ops = { +static const struct backlight_ops backlight_ops = { .get_brightness = get_brightness, .update_status = update_status, }; diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 8dce25126330..bac163450216 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -111,7 +111,7 @@ static int atmel_bl_get_brightness(struct backlight_device *bl) return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); } -static struct backlight_ops atmel_lcdc_bl_ops = { +static const struct backlight_ops atmel_lcdc_bl_ops = { .update_status = atmel_bl_update_status, .get_brightness = atmel_bl_get_brightness, }; diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 34a0851bcbfa..dd9de2e80580 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1786,7 +1786,7 @@ static int aty128_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops aty128_bl_data = { +static const struct backlight_ops aty128_bl_data = { .get_brightness = aty128_bl_get_brightness, .update_status = aty128_bl_update_status, }; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 5bf91236c701..4d5c41371543 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2221,7 +2221,7 @@ static int aty_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops aty_bl_data = { +static const struct backlight_ops aty_bl_data = { .get_brightness = aty_bl_get_brightness, .update_status = aty_bl_update_status, }; diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 256966e9667d..9b811ddbce83 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -128,7 +128,7 @@ static int radeon_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops radeon_bl_data = { +static const struct backlight_ops radeon_bl_data = { .get_brightness = radeon_bl_get_brightness, .update_status = radeon_bl_update_status, }; diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 38ffc3fbcbe4..c789c46e38af 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -155,7 +155,7 @@ out: return -EINVAL; } -static struct backlight_ops pm860x_backlight_ops = { +static const struct backlight_ops pm860x_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = pm860x_backlight_update_status, .get_brightness = pm860x_backlight_get_brightness, diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index b2b2c7ba1f63..209acc105cbc 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -92,7 +92,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl) return ret; } -static struct backlight_ops max8925_backlight_ops = { +static const struct backlight_ops max8925_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = max8925_backlight_update_status, .get_brightness = max8925_backlight_get_brightness, diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 2fb552a6f32c..6aac6d1b937b 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -87,7 +87,7 @@ static int nvidia_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops nvidia_bl_ops = { +static const struct backlight_ops nvidia_bl_ops = { .get_brightness = nvidia_bl_get_brightness, .update_status = nvidia_bl_update_status, }; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index e1c765d11419..61026f96ad20 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -465,7 +465,7 @@ static int taal_bl_get_intensity(struct backlight_device *dev) return 0; } -static struct backlight_ops taal_bl_ops = { +static const struct backlight_ops taal_bl_ops = { .get_brightness = taal_bl_get_intensity, .update_status = taal_bl_update_status, }; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 618f36bec10d..da388186d617 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -331,7 +331,7 @@ static int riva_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops riva_bl_ops = { +static const struct backlight_ops riva_bl_ops = { .get_brightness = riva_bl_get_brightness, .update_status = riva_bl_update_status, }; -- cgit v1.2.3 From 2f55ac072f5344519348c0c94b3d2f4cca46847b Mon Sep 17 00:00:00 2001 From: Lionel Debroux Date: Tue, 16 Nov 2010 14:14:02 +0100 Subject: suspend: constify platform_suspend_ops While at it, fix two checkpatch errors. Several non-const struct instances constified by this patch were added after the introduction of platform_suspend_ops in checkpatch.pl's list of "should be const" structs (79404849e90a41ea2109bd0e2f7c7164b0c4ce73). Patch against mainline. Inspired by hunks of the grsecurity patch, updated for newer kernels. Signed-off-by: Lionel Debroux Acked-by: Ingo Molnar Signed-off-by: Jiri Kosina --- arch/arm/mach-at91/pm.c | 2 +- arch/arm/mach-davinci/pm.c | 2 +- arch/arm/mach-imx/pm-imx27.c | 2 +- arch/arm/mach-lpc32xx/pm.c | 2 +- arch/arm/mach-omap1/pm.c | 2 +- arch/arm/mach-omap2/pm24xx.c | 2 +- arch/arm/mach-omap2/pm34xx.c | 2 +- arch/arm/mach-omap2/pm44xx.c | 2 +- arch/arm/mach-pnx4008/pm.c | 2 +- arch/arm/mach-pxa/pm.c | 2 +- arch/arm/mach-pxa/sharpsl_pm.c | 2 +- arch/arm/mach-sa1100/pm.c | 2 +- arch/arm/plat-samsung/pm.c | 2 +- arch/avr32/mach-at32ap/pm.c | 2 +- arch/blackfin/mach-common/pm.c | 2 +- arch/mips/alchemy/devboards/pm.c | 2 +- arch/mips/jz4740/pm.c | 2 +- arch/mips/loongson/common/pm.c | 2 +- arch/powerpc/platforms/52xx/lite5200_pm.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_pm.c | 2 +- arch/powerpc/platforms/83xx/suspend.c | 2 +- arch/powerpc/platforms/pseries/suspend.c | 2 +- arch/powerpc/sysdev/fsl_pmc.c | 2 +- arch/sh/boards/mach-hp6xx/pm.c | 2 +- arch/sh/kernel/cpu/shmobile/pm.c | 2 +- drivers/acpi/sleep.c | 4 ++-- drivers/macintosh/via-pmu.c | 2 +- include/linux/suspend.h | 4 ++-- kernel/power/suspend.c | 4 ++-- 29 files changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index dafbacc25eb1..ea53f4d9b283 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -301,7 +301,7 @@ static void at91_pm_end(void) } -static struct platform_suspend_ops at91_pm_ops ={ +static const struct platform_suspend_ops at91_pm_ops = { .valid = at91_pm_valid_state, .begin = at91_pm_begin, .enter = at91_pm_enter, diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c index fab953b43dea..1bd73a04be20 100644 --- a/arch/arm/mach-davinci/pm.c +++ b/arch/arm/mach-davinci/pm.c @@ -110,7 +110,7 @@ static int davinci_pm_enter(suspend_state_t state) return ret; } -static struct platform_suspend_ops davinci_pm_ops = { +static const struct platform_suspend_ops davinci_pm_ops = { .enter = davinci_pm_enter, .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/mach-imx/pm-imx27.c b/arch/arm/mach-imx/pm-imx27.c index afc17ce0bb54..2153ca71bb82 100644 --- a/arch/arm/mach-imx/pm-imx27.c +++ b/arch/arm/mach-imx/pm-imx27.c @@ -32,7 +32,7 @@ static int mx27_suspend_enter(suspend_state_t state) return 0; } -static struct platform_suspend_ops mx27_suspend_ops = { +static const struct platform_suspend_ops mx27_suspend_ops = { .enter = mx27_suspend_enter, .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c index a6e2aed9a49f..e76d41bb7056 100644 --- a/arch/arm/mach-lpc32xx/pm.c +++ b/arch/arm/mach-lpc32xx/pm.c @@ -123,7 +123,7 @@ static int lpc32xx_pm_enter(suspend_state_t state) return 0; } -static struct platform_suspend_ops lpc32xx_pm_ops = { +static const struct platform_suspend_ops lpc32xx_pm_ops = { .valid = suspend_valid_only_mem, .enter = lpc32xx_pm_enter, }; diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index b1d3f9fade23..4cf3b67dd998 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -647,7 +647,7 @@ static struct irqaction omap_wakeup_irq = { -static struct platform_suspend_ops omap_pm_ops ={ +static const struct platform_suspend_ops omap_pm_ops = { .prepare = omap_pm_prepare, .enter = omap_pm_enter, .finish = omap_pm_finish, diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index a40457d81927..aa9764eeb941 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -326,7 +326,7 @@ static void omap2_pm_finish(void) enable_hlt(); } -static struct platform_suspend_ops omap_pm_ops = { +static const struct platform_suspend_ops omap_pm_ops = { .prepare = omap2_pm_prepare, .enter = omap2_pm_enter, .finish = omap2_pm_finish, diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 75c0cd13ad8e..4000c3c8bbd5 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -594,7 +594,7 @@ static void omap3_pm_end(void) return; } -static struct platform_suspend_ops omap_pm_ops = { +static const struct platform_suspend_ops omap_pm_ops = { .begin = omap3_pm_begin, .end = omap3_pm_end, .prepare = omap3_pm_prepare, diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 54544b4fc76b..dc8b1ef9f84c 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -75,7 +75,7 @@ static void omap4_pm_end(void) return; } -static struct platform_suspend_ops omap_pm_ops = { +static const struct platform_suspend_ops omap_pm_ops = { .begin = omap4_pm_begin, .end = omap4_pm_end, .prepare = omap4_pm_prepare, diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c index ee3c29c57ae3..f3e60a049f98 100644 --- a/arch/arm/mach-pnx4008/pm.c +++ b/arch/arm/mach-pnx4008/pm.c @@ -119,7 +119,7 @@ static int pnx4008_pm_valid(suspend_state_t state) (state == PM_SUSPEND_MEM); } -static struct platform_suspend_ops pnx4008_pm_ops = { +static const struct platform_suspend_ops pnx4008_pm_ops = { .enter = pnx4008_pm_enter, .valid = pnx4008_pm_valid, }; diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 166c15f62916..978e1b289544 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -96,7 +96,7 @@ void pxa_pm_finish(void) pxa_cpu_pm_fns->finish(); } -static struct platform_suspend_ops pxa_pm_ops = { +static const struct platform_suspend_ops pxa_pm_ops = { .valid = pxa_pm_valid, .enter = pxa_pm_enter, .prepare = pxa_pm_prepare, diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 8fed027b12dc..02874e96ec72 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -868,7 +868,7 @@ static void sharpsl_apm_get_power_status(struct apm_power_info *info) } #ifdef CONFIG_PM -static struct platform_suspend_ops sharpsl_pm_ops = { +static const struct platform_suspend_ops sharpsl_pm_ops = { .prepare = pxa_pm_prepare, .finish = pxa_pm_finish, .enter = corgi_pxa_pm_enter, diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index c83fdc80edfd..ab9fc4470d36 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -120,7 +120,7 @@ unsigned long sleep_phys_sp(void *sp) return virt_to_phys(sp); } -static struct platform_suspend_ops sa11x0_pm_ops = { +static const struct platform_suspend_ops sa11x0_pm_ops = { .enter = sa11x0_pm_enter, .valid = suspend_valid_only_mem, }; diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 27cfca597699..5bf3f2f09e74 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -355,7 +355,7 @@ static void s3c_pm_finish(void) s3c_pm_check_cleanup(); } -static struct platform_suspend_ops s3c_pm_ops = { +static const struct platform_suspend_ops s3c_pm_ops = { .enter = s3c_pm_enter, .prepare = s3c_pm_prepare, .finish = s3c_pm_finish, diff --git a/arch/avr32/mach-at32ap/pm.c b/arch/avr32/mach-at32ap/pm.c index f021edfeaab0..32d680eb6f48 100644 --- a/arch/avr32/mach-at32ap/pm.c +++ b/arch/avr32/mach-at32ap/pm.c @@ -176,7 +176,7 @@ out: return 0; } -static struct platform_suspend_ops avr32_pm_ops = { +static const struct platform_suspend_ops avr32_pm_ops = { .valid = avr32_pm_valid_state, .enter = avr32_pm_enter, }; diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c index 80884b136a0c..745af2d96553 100644 --- a/arch/blackfin/mach-common/pm.c +++ b/arch/blackfin/mach-common/pm.c @@ -233,7 +233,7 @@ static int bfin_pm_enter(suspend_state_t state) return 0; } -struct platform_suspend_ops bfin_pm_ops = { +static const struct platform_suspend_ops bfin_pm_ops = { .enter = bfin_pm_enter, .valid = bfin_pm_valid, }; diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c index 4bbd3133e451..acaf91b5e461 100644 --- a/arch/mips/alchemy/devboards/pm.c +++ b/arch/mips/alchemy/devboards/pm.c @@ -110,7 +110,7 @@ static void db1x_pm_end(void) } -static struct platform_suspend_ops db1x_pm_ops = { +static const struct platform_suspend_ops db1x_pm_ops = { .valid = suspend_valid_only_mem, .begin = db1x_pm_begin, .enter = db1x_pm_enter, diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c index a9994585424d..902d5b50124c 100644 --- a/arch/mips/jz4740/pm.c +++ b/arch/mips/jz4740/pm.c @@ -42,7 +42,7 @@ static int jz4740_pm_enter(suspend_state_t state) return 0; } -static struct platform_suspend_ops jz4740_pm_ops = { +static const struct platform_suspend_ops jz4740_pm_ops = { .valid = suspend_valid_only_mem, .enter = jz4740_pm_enter, }; diff --git a/arch/mips/loongson/common/pm.c b/arch/mips/loongson/common/pm.c index 6c1fd9001712..f55e07aee071 100644 --- a/arch/mips/loongson/common/pm.c +++ b/arch/mips/loongson/common/pm.c @@ -147,7 +147,7 @@ static int loongson_pm_valid_state(suspend_state_t state) } } -static struct platform_suspend_ops loongson_pm_ops = { +static const struct platform_suspend_ops loongson_pm_ops = { .valid = loongson_pm_valid_state, .enter = loongson_pm_enter, }; diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index 80234e5921f5..eda0fc2a3914 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -232,7 +232,7 @@ static void lite5200_pm_end(void) lite5200_pm_target_state = PM_SUSPEND_ON; } -static struct platform_suspend_ops lite5200_pm_ops = { +static const struct platform_suspend_ops lite5200_pm_ops = { .valid = lite5200_pm_valid, .begin = lite5200_pm_begin, .prepare = lite5200_pm_prepare, diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index 568cef636275..8310e8b5b57f 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -186,7 +186,7 @@ void mpc52xx_pm_finish(void) iounmap(mbar); } -static struct platform_suspend_ops mpc52xx_pm_ops = { +static const struct platform_suspend_ops mpc52xx_pm_ops = { .valid = mpc52xx_pm_valid, .prepare = mpc52xx_pm_prepare, .enter = mpc52xx_pm_enter, diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 75ae77f1af6a..fd4f2f2f19e6 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -311,7 +311,7 @@ static int mpc83xx_is_pci_agent(void) return ret; } -static struct platform_suspend_ops mpc83xx_suspend_ops = { +static const struct platform_suspend_ops mpc83xx_suspend_ops = { .valid = mpc83xx_suspend_valid, .begin = mpc83xx_suspend_begin, .enter = mpc83xx_suspend_enter, diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index ed72098bb4e3..a8ca289ff267 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -153,7 +153,7 @@ static struct sysdev_class suspend_sysdev_class = { .name = "power", }; -static struct platform_suspend_ops pseries_suspend_ops = { +static const struct platform_suspend_ops pseries_suspend_ops = { .valid = suspend_valid_only_mem, .begin = pseries_suspend_begin, .prepare_late = pseries_prepare_late, diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c index 44de8559c975..e9381bfefb21 100644 --- a/arch/powerpc/sysdev/fsl_pmc.c +++ b/arch/powerpc/sysdev/fsl_pmc.c @@ -53,7 +53,7 @@ static int pmc_suspend_valid(suspend_state_t state) return 1; } -static struct platform_suspend_ops pmc_suspend_ops = { +static const struct platform_suspend_ops pmc_suspend_ops = { .valid = pmc_suspend_valid, .enter = pmc_suspend_enter, }; diff --git a/arch/sh/boards/mach-hp6xx/pm.c b/arch/sh/boards/mach-hp6xx/pm.c index 4499a3749d40..adc9b4bba828 100644 --- a/arch/sh/boards/mach-hp6xx/pm.c +++ b/arch/sh/boards/mach-hp6xx/pm.c @@ -143,7 +143,7 @@ static int hp6x0_pm_enter(suspend_state_t state) return 0; } -static struct platform_suspend_ops hp6x0_pm_ops = { +static const struct platform_suspend_ops hp6x0_pm_ops = { .enter = hp6x0_pm_enter, .valid = suspend_valid_only_mem, }; diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index e55968712706..a6f95ae4aae7 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c @@ -141,7 +141,7 @@ static int sh_pm_enter(suspend_state_t state) return 0; } -static struct platform_suspend_ops sh_pm_ops = { +static const struct platform_suspend_ops sh_pm_ops = { .enter = sh_pm_enter, .valid = suspend_valid_only_mem, }; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 5149c9bf7015..ba1caf724a16 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -319,7 +319,7 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state) } } -static struct platform_suspend_ops acpi_suspend_ops = { +static const struct platform_suspend_ops acpi_suspend_ops = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, @@ -347,7 +347,7 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state) * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has * been requested. */ -static struct platform_suspend_ops acpi_suspend_ops_old = { +static const struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, .prepare_late = acpi_pm_pre_suspend, diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index cd29c8248386..8b021eb0d48c 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2257,7 +2257,7 @@ static int pmu_sleep_valid(suspend_state_t state) && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0); } -static struct platform_suspend_ops pmu_pm_ops = { +static const struct platform_suspend_ops pmu_pm_ops = { .enter = powerbook_sleep, .valid = pmu_sleep_valid, }; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 40ead943fd6a..f45f3ccfdfa9 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -122,7 +122,7 @@ struct platform_suspend_ops { * suspend_set_ops - set platform dependent suspend operations * @ops: The new suspend operations to set. */ -extern void suspend_set_ops(struct platform_suspend_ops *ops); +extern void suspend_set_ops(const struct platform_suspend_ops *ops); extern int suspend_valid_only_mem(suspend_state_t state); /** @@ -147,7 +147,7 @@ extern int pm_suspend(suspend_state_t state); #else /* !CONFIG_SUSPEND */ #define suspend_valid_only_mem NULL -static inline void suspend_set_ops(struct platform_suspend_ops *ops) {} +static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } #endif /* !CONFIG_SUSPEND */ diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 7335952ee473..80051bdde6f1 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -30,13 +30,13 @@ const char *const pm_states[PM_SUSPEND_MAX] = { [PM_SUSPEND_MEM] = "mem", }; -static struct platform_suspend_ops *suspend_ops; +static const struct platform_suspend_ops *suspend_ops; /** * suspend_set_ops - Set the global suspend method table. * @ops: Pointer to ops structure. */ -void suspend_set_ops(struct platform_suspend_ops *ops) +void suspend_set_ops(const struct platform_suspend_ops *ops) { mutex_lock(&pm_mutex); suspend_ops = ops; -- cgit v1.2.3 From 3143a2bf18d12545f77dafa5b9f7fee83b001223 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Nov 2010 15:55:10 +0000 Subject: drm/i915: Convert (void)I915_READ to POSTING_READ ... and so hide the flushes from tracing. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 21034527d3a4..ef3503733ebb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -70,7 +70,7 @@ ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) if ((dev_priv->gt_irq_mask_reg & mask) != 0) { dev_priv->gt_irq_mask_reg &= ~mask; I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); - (void) I915_READ(GTIMR); + POSTING_READ(GTIMR); } } @@ -80,7 +80,7 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) if ((dev_priv->gt_irq_mask_reg & mask) != mask) { dev_priv->gt_irq_mask_reg |= mask; I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); - (void) I915_READ(GTIMR); + POSTING_READ(GTIMR); } } @@ -91,7 +91,7 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) if ((dev_priv->irq_mask_reg & mask) != 0) { dev_priv->irq_mask_reg &= ~mask; I915_WRITE(DEIMR, dev_priv->irq_mask_reg); - (void) I915_READ(DEIMR); + POSTING_READ(DEIMR); } } @@ -101,7 +101,7 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) if ((dev_priv->irq_mask_reg & mask) != mask) { dev_priv->irq_mask_reg |= mask; I915_WRITE(DEIMR, dev_priv->irq_mask_reg); - (void) I915_READ(DEIMR); + POSTING_READ(DEIMR); } } @@ -111,7 +111,7 @@ i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) if ((dev_priv->irq_mask_reg & mask) != 0) { dev_priv->irq_mask_reg &= ~mask; I915_WRITE(IMR, dev_priv->irq_mask_reg); - (void) I915_READ(IMR); + POSTING_READ(IMR); } } @@ -121,7 +121,7 @@ i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) if ((dev_priv->irq_mask_reg & mask) != mask) { dev_priv->irq_mask_reg |= mask; I915_WRITE(IMR, dev_priv->irq_mask_reg); - (void) I915_READ(IMR); + POSTING_READ(IMR); } } @@ -144,7 +144,7 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) dev_priv->pipestat[pipe] |= mask; /* Enable the interrupt, clear any pending status */ I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16)); - (void) I915_READ(reg); + POSTING_READ(reg); } } @@ -156,7 +156,7 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) dev_priv->pipestat[pipe] &= ~mask; I915_WRITE(reg, dev_priv->pipestat[pipe]); - (void) I915_READ(reg); + POSTING_READ(reg); } } @@ -321,7 +321,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); - (void)I915_READ(DEIER); + POSTING_READ(DEIER); de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); @@ -386,7 +386,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) done: I915_WRITE(DEIER, de_ier); - (void)I915_READ(DEIER); + POSTING_READ(DEIER); return ret; } @@ -796,7 +796,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) printk(KERN_ERR " ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); I915_WRITE(IPEIR_I965, ipeir); - (void)I915_READ(IPEIR_I965); + POSTING_READ(IPEIR_I965); } if (eir & GM45_ERROR_PAGE_TABLE) { u32 pgtbl_err = I915_READ(PGTBL_ER); @@ -804,7 +804,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) printk(KERN_ERR " PGTBL_ER: 0x%08x\n", pgtbl_err); I915_WRITE(PGTBL_ER, pgtbl_err); - (void)I915_READ(PGTBL_ER); + POSTING_READ(PGTBL_ER); } } @@ -815,7 +815,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) printk(KERN_ERR " PGTBL_ER: 0x%08x\n", pgtbl_err); I915_WRITE(PGTBL_ER, pgtbl_err); - (void)I915_READ(PGTBL_ER); + POSTING_READ(PGTBL_ER); } } @@ -846,7 +846,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) printk(KERN_ERR " ACTHD: 0x%08x\n", I915_READ(ACTHD)); I915_WRITE(IPEIR, ipeir); - (void)I915_READ(IPEIR); + POSTING_READ(IPEIR); } else { u32 ipeir = I915_READ(IPEIR_I965); @@ -863,12 +863,12 @@ static void i915_report_and_clear_eir(struct drm_device *dev) printk(KERN_ERR " ACTHD: 0x%08x\n", I915_READ(ACTHD_I965)); I915_WRITE(IPEIR_I965, ipeir); - (void)I915_READ(IPEIR_I965); + POSTING_READ(IPEIR_I965); } } I915_WRITE(EIR, eir); - (void)I915_READ(EIR); + POSTING_READ(EIR); eir = I915_READ(EIR); if (eir) { /* @@ -1435,17 +1435,17 @@ static void ironlake_irq_preinstall(struct drm_device *dev) I915_WRITE(DEIMR, 0xffffffff); I915_WRITE(DEIER, 0x0); - (void) I915_READ(DEIER); + POSTING_READ(DEIER); /* and GT */ I915_WRITE(GTIMR, 0xffffffff); I915_WRITE(GTIER, 0x0); - (void) I915_READ(GTIER); + POSTING_READ(GTIER); /* south display irq */ I915_WRITE(SDEIMR, 0xffffffff); I915_WRITE(SDEIER, 0x0); - (void) I915_READ(SDEIER); + POSTING_READ(SDEIER); } static int ironlake_irq_postinstall(struct drm_device *dev) @@ -1464,7 +1464,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask_reg); I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); - (void) I915_READ(DEIER); + POSTING_READ(DEIER); if (IS_GEN6(dev)) { render_mask = @@ -1485,7 +1485,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) } I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); - (void) I915_READ(GTIER); + POSTING_READ(GTIER); if (HAS_PCH_CPT(dev)) { hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT | @@ -1501,7 +1501,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, dev_priv->pch_irq_mask_reg); I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg); - (void) I915_READ(SDEIER); + POSTING_READ(SDEIER); if (IS_IRONLAKE_M(dev)) { /* Clear & enable PCU event interrupts */ @@ -1537,7 +1537,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev) I915_WRITE(PIPEBSTAT, 0); I915_WRITE(IMR, 0xffffffff); I915_WRITE(IER, 0x0); - (void) I915_READ(IER); + POSTING_READ(IER); } /* @@ -1591,7 +1591,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) I915_WRITE(IMR, dev_priv->irq_mask_reg); I915_WRITE(IER, enable_mask); - (void) I915_READ(IER); + POSTING_READ(IER); if (I915_HAS_HOTPLUG(dev)) { u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); -- cgit v1.2.3 From e72115bce326dc893bc1db96db72059a6a08148c Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Fri, 12 Nov 2010 10:27:44 +0100 Subject: staging: ft1000: Fix error goto statements. With commit 2dab1ac81b4767095f96503a9ac093a68c6e9c95 there was intruduced error which lead to stopping uninitialized kthread which leads to kernel panics. This patch fix problems with common entry point in correct way. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 99e333902376..6925622795a5 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -178,7 +178,7 @@ static int ft1000_probe(struct usb_interface *interface, if (IS_ERR(pft1000info->pPollThread)) { ret = PTR_ERR(pft1000info->pPollThread); - goto err_thread; + goto err_load; } msleep(500); @@ -186,7 +186,7 @@ static int ft1000_probe(struct usb_interface *interface, while (!pft1000info->CardReady) { if (gPollingfailed) { ret = -EIO; - goto err_load; + goto err_thread; } msleep(100); DEBUG("ft1000_probe::Waiting for Card Ready\n"); @@ -196,7 +196,7 @@ static int ft1000_probe(struct usb_interface *interface, ret = reg_ft1000_netdev(ft1000dev, interface); if (ret) - goto err_load; + goto err_thread; pft1000info->NetDevRegDone = 1; -- cgit v1.2.3 From 7f55f13c2ca82f6d998502df70f24deb550e5e0c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 11 Nov 2010 11:29:25 -0500 Subject: staging: ft1000: Copy from user into correct data While doing a ktest.pl I used a MIN_CONFIG that had STAGING enabled, and a randconfig with CONFIG_DEBUG_STRICT_USER_COPY_CHECKS enabled caught the following bug: In file included from /home/rostedt/work/autotest/nobackup/linux-test.git/arch/x86/include/asm/uaccess.h:571:0, from /home/rostedt/work/autotest/nobackup/linux-test.git/include/linux/poll.h:14, from /home/rostedt/work/autotest/nobackup/linux-test.git/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c:32: In function 'copy_from_user', inlined from 'ft1000_ChIoctl' at /home/rostedt/work/autotest/nobackup/linux-test.git/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c:702:36: /home/rostedt/work/autotest/nobackup/linux-test.git/arch/x86/include/asm/uaccess_32.h:212:26: error: call to 'copy_from_user_overflow' declared with attribute error: copy_from_user() buffer size is not provably correct Looking at the code it was obvious what the problem was. The pointer dpram_data was being allocated but the address was being written to. Looking at the comment above the code shows that it use to write into an element of that pointer where the '&' is appropriate. But now that it writes to the pointer itself, we need to remove the '&' otherwise we write over the pointer and not into the data it points to. Signed-off-by: Steven Rostedt Cc: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 197b3fb9462e..18c4c15c5aea 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -698,7 +698,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, break; //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) { - if ( copy_from_user(&dpram_data, argp, msgsz+2) ) { + if ( copy_from_user(dpram_data, argp, msgsz+2) ) { DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); result = -EFAULT; } -- cgit v1.2.3 From 886953e9b70bcb6913716b49bdf21b69450a7cd6 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:07 +0000 Subject: staging: vme: style: convert '&(foo)' to '&foo' done with find . -name '*.c' | xargs perl -p -i -e 's/&\(([^()]+)\)/&$1/g' Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_ca91cx42.c | 181 ++++++++++++------------- drivers/staging/vme/bridges/vme_tsi148.c | 204 ++++++++++++++--------------- drivers/staging/vme/devices/vme_user.c | 16 +-- drivers/staging/vme/vme.c | 114 ++++++++-------- 4 files changed, 258 insertions(+), 257 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index 4d745623211b..1f2089ff7f9f 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -58,7 +58,7 @@ static struct pci_driver ca91cx42_driver = { static u32 ca91cx42_DMA_irqhandler(struct ca91cx42_driver *bridge) { - wake_up(&(bridge->dma_queue)); + wake_up(&bridge->dma_queue); return CA91CX42_LINT_DMA; } @@ -82,14 +82,14 @@ static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat) /* XXX This needs to be split into 4 queues */ static u32 ca91cx42_MB_irqhandler(struct ca91cx42_driver *bridge, int mbox_mask) { - wake_up(&(bridge->mbox_queue)); + wake_up(&bridge->mbox_queue); return CA91CX42_LINT_MBOX; } static u32 ca91cx42_IACK_irqhandler(struct ca91cx42_driver *bridge) { - wake_up(&(bridge->iack_queue)); + wake_up(&bridge->iack_queue); return CA91CX42_LINT_SW_IACK; } @@ -207,9 +207,9 @@ static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge) pdev = container_of(ca91cx42_bridge->parent, struct pci_dev, dev); /* Initialise list for VME bus errors */ - INIT_LIST_HEAD(&(ca91cx42_bridge->vme_errors)); + INIT_LIST_HEAD(&ca91cx42_bridge->vme_errors); - mutex_init(&(ca91cx42_bridge->irq_mtx)); + mutex_init(&ca91cx42_bridge->irq_mtx); /* Disable interrupts from PCI to VME */ iowrite32(0, bridge->base + VINT_EN); @@ -299,7 +299,7 @@ int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, if (statid & 1) return -EINVAL; - mutex_lock(&(bridge->vme_int)); + mutex_lock(&bridge->vme_int); tmp = ioread32(bridge->base + VINT_EN); @@ -318,7 +318,7 @@ int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, tmp = tmp & ~(1 << (level + 24)); iowrite32(tmp, bridge->base + VINT_EN); - mutex_unlock(&(bridge->vme_int)); + mutex_unlock(&bridge->vme_int); return 0; } @@ -518,8 +518,8 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, image->kern_base = NULL; if (image->bus_resource.name != NULL) kfree(image->bus_resource.name); - release_resource(&(image->bus_resource)); - memset(&(image->bus_resource), 0, sizeof(struct resource)); + release_resource(&image->bus_resource); + memset(&image->bus_resource, 0, sizeof(struct resource)); } if (image->bus_resource.name == NULL) { @@ -540,7 +540,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, image->bus_resource.flags = IORESOURCE_MEM; retval = pci_bus_alloc_resource(pdev->bus, - &(image->bus_resource), size, size, PCIBIOS_MIN_MEM, + &image->bus_resource, size, size, PCIBIOS_MIN_MEM, 0, NULL, NULL); if (retval) { dev_err(ca91cx42_bridge->parent, "Failed to allocate mem " @@ -563,10 +563,10 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, iounmap(image->kern_base); image->kern_base = NULL; err_remap: - release_resource(&(image->bus_resource)); + release_resource(&image->bus_resource); err_resource: kfree(image->bus_resource.name); - memset(&(image->bus_resource), 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(struct resource)); err_name: return retval; } @@ -578,9 +578,9 @@ static void ca91cx42_free_resource(struct vme_master_resource *image) { iounmap(image->kern_base); image->kern_base = NULL; - release_resource(&(image->bus_resource)); + release_resource(&image->bus_resource); kfree(image->bus_resource.name); - memset(&(image->bus_resource), 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(struct resource)); } @@ -620,7 +620,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled, goto err_window; } - spin_lock(&(image->lock)); + spin_lock(&image->lock); /* * Let's allocate the resource here rather than further up the stack as @@ -628,7 +628,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled, */ retval = ca91cx42_alloc_resource(image, size); if (retval) { - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(ca91cx42_bridge->parent, "Unable to allocate memory " "for resource name\n"); retval = -ENOMEM; @@ -672,7 +672,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled, temp_ctl |= CA91CX42_LSI_CTL_VDW_D64; break; default: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(ca91cx42_bridge->parent, "Invalid data width\n"); retval = -EINVAL; goto err_dwidth; @@ -704,7 +704,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled, case VME_USER3: case VME_USER4: default: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(ca91cx42_bridge->parent, "Invalid address space\n"); retval = -EINVAL; goto err_aspace; @@ -730,7 +730,7 @@ int ca91cx42_master_set(struct vme_master_resource *image, int enabled, iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]); - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return 0; err_aspace: @@ -834,12 +834,12 @@ int ca91cx42_master_get(struct vme_master_resource *image, int *enabled, { int retval; - spin_lock(&(image->lock)); + spin_lock(&image->lock); retval = __ca91cx42_master_get(image, enabled, vme_base, size, aspace, cycle, dwidth); - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return retval; } @@ -855,7 +855,7 @@ ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf, if (count == 0) return 0; - spin_lock(&(image->lock)); + spin_lock(&image->lock); /* The following code handles VME address alignment problem * in order to assure the maximal data width cycle. @@ -899,7 +899,7 @@ ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf, } out: retval = count; - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return retval; } @@ -915,7 +915,7 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf, if (count == 0) return 0; - spin_lock(&(image->lock)); + spin_lock(&image->lock); /* Here we apply for the same strategy we do in master_read * function in order to assure D16 cycle when required. @@ -954,7 +954,8 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf, out: retval = count; - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); + return retval; } @@ -974,10 +975,10 @@ unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, i = image->number; /* Locking as we can only do one of these at a time */ - mutex_lock(&(bridge->vme_rmw)); + mutex_lock(&bridge->vme_rmw); /* Lock image */ - spin_lock(&(image->lock)); + spin_lock(&image->lock); pci_addr = (u32)image->kern_base + offset; @@ -1007,9 +1008,9 @@ unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, iowrite32(0, bridge->base + SCYC_CTL); out: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); - mutex_unlock(&(bridge->vme_rmw)); + mutex_unlock(&bridge->vme_rmw); return result; } @@ -1036,14 +1037,14 @@ int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, } /* Test descriptor alignment */ - if ((unsigned long)&(entry->descriptor) & CA91CX42_DCPP_M) { + if ((unsigned long)&entry->descriptor & CA91CX42_DCPP_M) { dev_err(dev, "Descriptor not aligned to 16 byte boundary as " - "required: %p\n", &(entry->descriptor)); + "required: %p\n", &entry->descriptor); retval = -EINVAL; goto err_align; } - memset(&(entry->descriptor), 0, sizeof(struct ca91cx42_dma_descriptor)); + memset(&entry->descriptor, 0, sizeof(struct ca91cx42_dma_descriptor)); if (dest->type == VME_DMA_VME) { entry->descriptor.dctl |= CA91CX42_DCTL_L2V; @@ -1138,14 +1139,14 @@ int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, entry->descriptor.dcpp = CA91CX42_DCPP_NULL; /* Add to list */ - list_add_tail(&(entry->list), &(list->entries)); + list_add_tail(&entry->list, &list->entries); /* Fill out previous descriptors "Next Address" */ - if (entry->list.prev != &(list->entries)) { + if (entry->list.prev != &list->entries) { prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry, list); /* We need the bus address for the pointer */ - desc_ptr = virt_to_bus(&(entry->descriptor)); + desc_ptr = virt_to_bus(&entry->descriptor); prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M; } @@ -1190,28 +1191,28 @@ int ca91cx42_dma_list_exec(struct vme_dma_list *list) bridge = ctrlr->parent->driver_priv; dev = ctrlr->parent->parent; - mutex_lock(&(ctrlr->mtx)); + mutex_lock(&ctrlr->mtx); - if (!(list_empty(&(ctrlr->running)))) { + if (!(list_empty(&ctrlr->running))) { /* * XXX We have an active DMA transfer and currently haven't * sorted out the mechanism for "pending" DMA transfers. * Return busy. */ /* Need to add to pending here */ - mutex_unlock(&(ctrlr->mtx)); + mutex_unlock(&ctrlr->mtx); return -EBUSY; } else { - list_add(&(list->list), &(ctrlr->running)); + list_add(&list->list, &ctrlr->running); } /* Get first bus address and write into registers */ - entry = list_first_entry(&(list->entries), struct ca91cx42_dma_entry, + entry = list_first_entry(&list->entries, struct ca91cx42_dma_entry, list); - bus_addr = virt_to_bus(&(entry->descriptor)); + bus_addr = virt_to_bus(&entry->descriptor); - mutex_unlock(&(ctrlr->mtx)); + mutex_unlock(&ctrlr->mtx); iowrite32(0, bridge->base + DTBC); iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP); @@ -1249,9 +1250,9 @@ int ca91cx42_dma_list_exec(struct vme_dma_list *list) } /* Remove list from running list */ - mutex_lock(&(ctrlr->mtx)); - list_del(&(list->list)); - mutex_unlock(&(ctrlr->mtx)); + mutex_lock(&ctrlr->mtx); + list_del(&list->list); + mutex_unlock(&ctrlr->mtx); return retval; @@ -1263,7 +1264,7 @@ int ca91cx42_dma_list_empty(struct vme_dma_list *list) struct ca91cx42_dma_entry *entry; /* detach and free each entry */ - list_for_each_safe(pos, temp, &(list->entries)) { + list_for_each_safe(pos, temp, &list->entries) { list_del(pos); entry = list_entry(pos, struct ca91cx42_dma_entry, list); kfree(entry); @@ -1298,12 +1299,12 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, return -EINVAL; } - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* If we already have a callback attached, we can't move it! */ for (i = 0; i < lm->monitors; i++) { if (bridge->lm_callback[i] != NULL) { - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(dev, "Location monitor callback attached, " "can't reset\n"); return -EBUSY; @@ -1321,7 +1322,7 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, lm_ctl |= CA91CX42_LM_CTL_AS_A32; break; default: - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(dev, "Invalid address space\n"); return -EINVAL; break; @@ -1339,7 +1340,7 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, iowrite32(lm_base, bridge->base + LM_BS); iowrite32(lm_ctl, bridge->base + LM_CTL); - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return 0; } @@ -1355,7 +1356,7 @@ int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, bridge = lm->parent->driver_priv; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); *lm_base = (unsigned long long)ioread32(bridge->base + LM_BS); lm_ctl = ioread32(bridge->base + LM_CTL); @@ -1380,7 +1381,7 @@ int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, if (lm_ctl & CA91CX42_LM_CTL_DATA) *cycle |= VME_DATA; - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return enabled; } @@ -1400,19 +1401,19 @@ int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, bridge = lm->parent->driver_priv; dev = lm->parent->parent; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* Ensure that the location monitor is configured - need PGM or DATA */ lm_ctl = ioread32(bridge->base + LM_CTL); if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) { - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(dev, "Location monitor not properly configured\n"); return -EINVAL; } /* Check that a callback isn't already attached */ if (bridge->lm_callback[monitor] != NULL) { - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(dev, "Existing callback attached\n"); return -EBUSY; } @@ -1431,7 +1432,7 @@ int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, iowrite32(lm_ctl, bridge->base + LM_CTL); } - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return 0; } @@ -1446,7 +1447,7 @@ int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) bridge = lm->parent->driver_priv; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* Disable Location Monitor and ensure previous interrupts are clear */ tmp = ioread32(bridge->base + LINT_EN); @@ -1467,7 +1468,7 @@ int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) iowrite32(tmp, bridge->base + LM_CTL); } - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return 0; } @@ -1526,7 +1527,7 @@ static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge, /* Allocate mem for CR/CSR image */ bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE, - &(bridge->crcsr_bus)); + &bridge->crcsr_bus); if (bridge->crcsr_kernel == NULL) { dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR " "image\n"); @@ -1632,12 +1633,12 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* Initialize wait queues & mutual exclusion flags */ - init_waitqueue_head(&(ca91cx42_device->dma_queue)); - init_waitqueue_head(&(ca91cx42_device->iack_queue)); - mutex_init(&(ca91cx42_device->vme_int)); - mutex_init(&(ca91cx42_device->vme_rmw)); + init_waitqueue_head(&ca91cx42_device->dma_queue); + init_waitqueue_head(&ca91cx42_device->iack_queue); + mutex_init(&ca91cx42_device->vme_int); + mutex_init(&ca91cx42_device->vme_rmw); - ca91cx42_bridge->parent = &(pdev->dev); + ca91cx42_bridge->parent = &pdev->dev; strcpy(ca91cx42_bridge->name, driver_name); /* Setup IRQ */ @@ -1648,7 +1649,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* Add master windows to list */ - INIT_LIST_HEAD(&(ca91cx42_bridge->master_resources)); + INIT_LIST_HEAD(&ca91cx42_bridge->master_resources); for (i = 0; i < CA91C142_MAX_MASTER; i++) { master_image = kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL); @@ -1659,7 +1660,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_master; } master_image->parent = ca91cx42_bridge; - spin_lock_init(&(master_image->lock)); + spin_lock_init(&master_image->lock); master_image->locked = 0; master_image->number = i; master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | @@ -1667,15 +1668,15 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | VME_SUPER | VME_USER | VME_PROG | VME_DATA; master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64; - memset(&(master_image->bus_resource), 0, + memset(&master_image->bus_resource, 0, sizeof(struct resource)); master_image->kern_base = NULL; - list_add_tail(&(master_image->list), - &(ca91cx42_bridge->master_resources)); + list_add_tail(&master_image->list, + &ca91cx42_bridge->master_resources); } /* Add slave windows to list */ - INIT_LIST_HEAD(&(ca91cx42_bridge->slave_resources)); + INIT_LIST_HEAD(&ca91cx42_bridge->slave_resources); for (i = 0; i < CA91C142_MAX_SLAVE; i++) { slave_image = kmalloc(sizeof(struct vme_slave_resource), GFP_KERNEL); @@ -1686,7 +1687,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_slave; } slave_image->parent = ca91cx42_bridge; - mutex_init(&(slave_image->mtx)); + mutex_init(&slave_image->mtx); slave_image->locked = 0; slave_image->number = i; slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 | @@ -1698,12 +1699,12 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | VME_SUPER | VME_USER | VME_PROG | VME_DATA; - list_add_tail(&(slave_image->list), - &(ca91cx42_bridge->slave_resources)); + list_add_tail(&slave_image->list, + &ca91cx42_bridge->slave_resources); } /* Add dma engines to list */ - INIT_LIST_HEAD(&(ca91cx42_bridge->dma_resources)); + INIT_LIST_HEAD(&ca91cx42_bridge->dma_resources); for (i = 0; i < CA91C142_MAX_DMA; i++) { dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource), GFP_KERNEL); @@ -1714,19 +1715,19 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_dma; } dma_ctrlr->parent = ca91cx42_bridge; - mutex_init(&(dma_ctrlr->mtx)); + mutex_init(&dma_ctrlr->mtx); dma_ctrlr->locked = 0; dma_ctrlr->number = i; dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM | VME_DMA_MEM_TO_VME; - INIT_LIST_HEAD(&(dma_ctrlr->pending)); - INIT_LIST_HEAD(&(dma_ctrlr->running)); - list_add_tail(&(dma_ctrlr->list), - &(ca91cx42_bridge->dma_resources)); + INIT_LIST_HEAD(&dma_ctrlr->pending); + INIT_LIST_HEAD(&dma_ctrlr->running); + list_add_tail(&dma_ctrlr->list, + &ca91cx42_bridge->dma_resources); } /* Add location monitor to list */ - INIT_LIST_HEAD(&(ca91cx42_bridge->lm_resources)); + INIT_LIST_HEAD(&ca91cx42_bridge->lm_resources); lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL); if (lm == NULL) { dev_err(&pdev->dev, "Failed to allocate memory for " @@ -1735,11 +1736,11 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_lm; } lm->parent = ca91cx42_bridge; - mutex_init(&(lm->mtx)); + mutex_init(&lm->mtx); lm->locked = 0; lm->number = 1; lm->monitors = 4; - list_add_tail(&(lm->list), &(ca91cx42_bridge->lm_resources)); + list_add_tail(&lm->list, &ca91cx42_bridge->lm_resources); ca91cx42_bridge->slave_get = ca91cx42_slave_get; ca91cx42_bridge->slave_set = ca91cx42_slave_set; @@ -1786,28 +1787,28 @@ err_reg: ca91cx42_crcsr_exit(ca91cx42_bridge, pdev); err_lm: /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->lm_resources)) { + list_for_each(pos, &ca91cx42_bridge->lm_resources) { lm = list_entry(pos, struct vme_lm_resource, list); list_del(pos); kfree(lm); } err_dma: /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->dma_resources)) { + list_for_each(pos, &ca91cx42_bridge->dma_resources) { dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); list_del(pos); kfree(dma_ctrlr); } err_slave: /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->slave_resources)) { + list_for_each(pos, &ca91cx42_bridge->slave_resources) { slave_image = list_entry(pos, struct vme_slave_resource, list); list_del(pos); kfree(slave_image); } err_master: /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->master_resources)) { + list_for_each(pos, &ca91cx42_bridge->master_resources) { master_image = list_entry(pos, struct vme_master_resource, list); list_del(pos); @@ -1870,28 +1871,28 @@ void ca91cx42_remove(struct pci_dev *pdev) ca91cx42_crcsr_exit(ca91cx42_bridge, pdev); /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->lm_resources)) { + list_for_each(pos, &ca91cx42_bridge->lm_resources) { lm = list_entry(pos, struct vme_lm_resource, list); list_del(pos); kfree(lm); } /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->dma_resources)) { + list_for_each(pos, &ca91cx42_bridge->dma_resources) { dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); list_del(pos); kfree(dma_ctrlr); } /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->slave_resources)) { + list_for_each(pos, &ca91cx42_bridge->slave_resources) { slave_image = list_entry(pos, struct vme_slave_resource, list); list_del(pos); kfree(slave_image); } /* resources are stored in link list */ - list_for_each(pos, &(ca91cx42_bridge->master_resources)) { + list_for_each(pos, &ca91cx42_bridge->master_resources) { master_image = list_entry(pos, struct vme_master_resource, list); list_del(pos); diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 492ddb2d5108..1cba1fa16079 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -81,11 +81,11 @@ static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge, u32 serviced = 0; if (channel_mask & TSI148_LCSR_INTS_DMA0S) { - wake_up(&(bridge->dma_queue[0])); + wake_up(&bridge->dma_queue[0]); serviced |= TSI148_LCSR_INTC_DMA0C; } if (channel_mask & TSI148_LCSR_INTS_DMA1S) { - wake_up(&(bridge->dma_queue[1])); + wake_up(&bridge->dma_queue[1]); serviced |= TSI148_LCSR_INTC_DMA1C; } @@ -191,7 +191,7 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) if (error) { error->address = error_addr; error->attributes = error_attrib; - list_add_tail(&(error->list), &(tsi148_bridge->vme_errors)); + list_add_tail(&error->list, &tsi148_bridge->vme_errors); } else { dev_err(tsi148_bridge->parent, "Unable to alloc memory for " "VMEbus Error reporting\n"); @@ -210,7 +210,7 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) */ static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge) { - wake_up(&(bridge->iack_queue)); + wake_up(&bridge->iack_queue); return TSI148_LCSR_INTC_IACKC; } @@ -320,9 +320,9 @@ static int tsi148_irq_init(struct vme_bridge *tsi148_bridge) bridge = tsi148_bridge->driver_priv; /* Initialise list for VME bus errors */ - INIT_LIST_HEAD(&(tsi148_bridge->vme_errors)); + INIT_LIST_HEAD(&tsi148_bridge->vme_errors); - mutex_init(&(tsi148_bridge->irq_mtx)); + mutex_init(&tsi148_bridge->irq_mtx); result = request_irq(pdev->irq, tsi148_irqhandler, @@ -452,7 +452,7 @@ int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, int statid) bridge = tsi148_bridge->driver_priv; - mutex_lock(&(bridge->vme_int)); + mutex_lock(&bridge->vme_int); /* Read VICR register */ tmp = ioread32be(bridge->base + TSI148_LCSR_VICR); @@ -470,7 +470,7 @@ int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, int statid) wait_event_interruptible(bridge->iack_queue, tsi148_iack_received(bridge)); - mutex_unlock(&(bridge->vme_int)); + mutex_unlock(&bridge->vme_int); return 0; } @@ -496,7 +496,7 @@ static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge, */ err_pos = NULL; /* Iterate through errors */ - list_for_each(err_pos, &(tsi148_bridge->vme_errors)) { + list_for_each(err_pos, &tsi148_bridge->vme_errors) { vme_err = list_entry(err_pos, struct vme_bus_error, list); if ((vme_err->address >= address) && (vme_err->address < bound)) { @@ -530,7 +530,7 @@ static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, */ err_pos = NULL; /* Iterate through errors */ - list_for_each_safe(err_pos, temp, &(tsi148_bridge->vme_errors)) { + list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) { vme_err = list_entry(err_pos, struct vme_bus_error, list); if ((vme_err->address >= address) && @@ -819,8 +819,8 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, image->kern_base = NULL; if (image->bus_resource.name != NULL) kfree(image->bus_resource.name); - release_resource(&(image->bus_resource)); - memset(&(image->bus_resource), 0, sizeof(struct resource)); + release_resource(&image->bus_resource); + memset(&image->bus_resource, 0, sizeof(struct resource)); } /* Exit here if size is zero */ @@ -845,7 +845,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, image->bus_resource.flags = IORESOURCE_MEM; retval = pci_bus_alloc_resource(pdev->bus, - &(image->bus_resource), size, size, PCIBIOS_MIN_MEM, + &image->bus_resource, size, size, PCIBIOS_MIN_MEM, 0, NULL, NULL); if (retval) { dev_err(tsi148_bridge->parent, "Failed to allocate mem " @@ -868,10 +868,10 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, iounmap(image->kern_base); image->kern_base = NULL; err_remap: - release_resource(&(image->bus_resource)); + release_resource(&image->bus_resource); err_resource: kfree(image->bus_resource.name); - memset(&(image->bus_resource), 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(struct resource)); err_name: return retval; } @@ -883,9 +883,9 @@ static void tsi148_free_resource(struct vme_master_resource *image) { iounmap(image->kern_base); image->kern_base = NULL; - release_resource(&(image->bus_resource)); + release_resource(&image->bus_resource); kfree(image->bus_resource.name); - memset(&(image->bus_resource), 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(struct resource)); } /* @@ -924,7 +924,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled, goto err_window; } - spin_lock(&(image->lock)); + spin_lock(&image->lock); /* Let's allocate the resource here rather than further up the stack as * it avoids pushing loads of bus dependant stuff up the stack. If size @@ -932,7 +932,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled, */ retval = tsi148_alloc_resource(image, size); if (retval) { - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(tsi148_bridge->parent, "Unable to allocate memory for " "resource\n"); goto err_res; @@ -959,19 +959,19 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled, reg_split(vme_offset, &vme_offset_high, &vme_offset_low); if (pci_base_low & 0xFFFF) { - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n"); retval = -EINVAL; goto err_gran; } if (pci_bound_low & 0xFFFF) { - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n"); retval = -EINVAL; goto err_gran; } if (vme_offset_low & 0xFFFF) { - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(tsi148_bridge->parent, "Invalid VME Offset " "alignment\n"); retval = -EINVAL; @@ -1035,7 +1035,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled, temp_ctl |= TSI148_LCSR_OTAT_DBW_32; break; default: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(tsi148_bridge->parent, "Invalid data width\n"); retval = -EINVAL; goto err_dwidth; @@ -1072,7 +1072,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled, temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4; break; default: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); dev_err(tsi148_bridge->parent, "Invalid address space\n"); retval = -EINVAL; goto err_aspace; @@ -1109,7 +1109,7 @@ int tsi148_master_set(struct vme_master_resource *image, int enabled, iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + TSI148_LCSR_OFFSET_OTAT); - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return 0; err_aspace: @@ -1243,12 +1243,12 @@ int tsi148_master_get(struct vme_master_resource *image, int *enabled, { int retval; - spin_lock(&(image->lock)); + spin_lock(&image->lock); retval = __tsi148_master_get(image, enabled, vme_base, size, aspace, cycle, dwidth); - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return retval; } @@ -1266,7 +1266,7 @@ ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, tsi148_bridge = image->parent; - spin_lock(&(image->lock)); + spin_lock(&image->lock); memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count); retval = count; @@ -1289,7 +1289,7 @@ ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, } skip_chk: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return retval; } @@ -1312,7 +1312,7 @@ ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, bridge = tsi148_bridge->driver_priv; - spin_lock(&(image->lock)); + spin_lock(&image->lock); memcpy_toio(image->kern_base + offset, buf, (unsigned int)count); retval = count; @@ -1352,7 +1352,7 @@ ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, } skip_chk: - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); return retval; } @@ -1378,10 +1378,10 @@ unsigned int tsi148_master_rmw(struct vme_master_resource *image, i = image->number; /* Locking as we can only do one of these at a time */ - mutex_lock(&(bridge->vme_rmw)); + mutex_lock(&bridge->vme_rmw); /* Lock image */ - spin_lock(&(image->lock)); + spin_lock(&image->lock); pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + TSI148_LCSR_OFFSET_OTSAU); @@ -1411,9 +1411,9 @@ unsigned int tsi148_master_rmw(struct vme_master_resource *image, tmp &= ~TSI148_LCSR_VMCTRL_RMWEN; iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL); - spin_unlock(&(image->lock)); + spin_unlock(&image->lock); - mutex_unlock(&(bridge->vme_rmw)); + mutex_unlock(&bridge->vme_rmw); return result; } @@ -1633,10 +1633,10 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, } /* Test descriptor alignment */ - if ((unsigned long)&(entry->descriptor) & 0x7) { + if ((unsigned long)&entry->descriptor & 0x7) { dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 " "byte boundary as required: %p\n", - &(entry->descriptor)); + &entry->descriptor); retval = -EINVAL; goto err_align; } @@ -1644,7 +1644,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, /* Given we are going to fill out the structure, we probably don't * need to zero it, but better safe than sorry for now. */ - memset(&(entry->descriptor), 0, sizeof(struct tsi148_dma_descriptor)); + memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor)); /* Fill out source part */ switch (src->type) { @@ -1681,7 +1681,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME; retval = tsi148_dma_set_vme_src_attributes( - tsi148_bridge->parent, &(entry->descriptor.dsat), + tsi148_bridge->parent, &entry->descriptor.dsat, vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth); if (retval < 0) goto err_source; @@ -1719,7 +1719,7 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME; retval = tsi148_dma_set_vme_dest_attributes( - tsi148_bridge->parent, &(entry->descriptor.ddat), + tsi148_bridge->parent, &entry->descriptor.ddat, vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth); if (retval < 0) goto err_dest; @@ -1735,16 +1735,16 @@ int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, entry->descriptor.dcnt = (u32)count; /* Add to list */ - list_add_tail(&(entry->list), &(list->entries)); + list_add_tail(&entry->list, &list->entries); /* Fill out previous descriptors "Next Address" */ - if (entry->list.prev != &(list->entries)) { + if (entry->list.prev != &list->entries) { prev = list_entry(entry->list.prev, struct tsi148_dma_entry, list); /* We need the bus address for the pointer */ - desc_ptr = virt_to_bus(&(entry->descriptor)); - reg_split(desc_ptr, &(prev->descriptor.dnlau), - &(prev->descriptor.dnlal)); + desc_ptr = virt_to_bus(&entry->descriptor); + reg_split(desc_ptr, &prev->descriptor.dnlau, + &prev->descriptor.dnlal); } return 0; @@ -1799,30 +1799,30 @@ int tsi148_dma_list_exec(struct vme_dma_list *list) bridge = tsi148_bridge->driver_priv; - mutex_lock(&(ctrlr->mtx)); + mutex_lock(&ctrlr->mtx); channel = ctrlr->number; - if (!list_empty(&(ctrlr->running))) { + if (!list_empty(&ctrlr->running)) { /* * XXX We have an active DMA transfer and currently haven't * sorted out the mechanism for "pending" DMA transfers. * Return busy. */ /* Need to add to pending here */ - mutex_unlock(&(ctrlr->mtx)); + mutex_unlock(&ctrlr->mtx); return -EBUSY; } else { - list_add(&(list->list), &(ctrlr->running)); + list_add(&list->list, &ctrlr->running); } /* Get first bus address and write into registers */ - entry = list_first_entry(&(list->entries), struct tsi148_dma_entry, + entry = list_first_entry(&list->entries, struct tsi148_dma_entry, list); - bus_addr = virt_to_bus(&(entry->descriptor)); + bus_addr = virt_to_bus(&entry->descriptor); - mutex_unlock(&(ctrlr->mtx)); + mutex_unlock(&ctrlr->mtx); reg_split(bus_addr, &bus_addr_high, &bus_addr_low); @@ -1850,9 +1850,9 @@ int tsi148_dma_list_exec(struct vme_dma_list *list) } /* Remove list from running list */ - mutex_lock(&(ctrlr->mtx)); - list_del(&(list->list)); - mutex_unlock(&(ctrlr->mtx)); + mutex_lock(&ctrlr->mtx); + list_del(&list->list); + mutex_unlock(&ctrlr->mtx); return retval; } @@ -1868,7 +1868,7 @@ int tsi148_dma_list_empty(struct vme_dma_list *list) struct tsi148_dma_entry *entry; /* detach and free each entry */ - list_for_each_safe(pos, temp, &(list->entries)) { + list_for_each_safe(pos, temp, &list->entries) { list_del(pos); entry = list_entry(pos, struct tsi148_dma_entry, list); kfree(entry); @@ -1896,12 +1896,12 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, bridge = tsi148_bridge->driver_priv; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* If we already have a callback attached, we can't move it! */ for (i = 0; i < lm->monitors; i++) { if (bridge->lm_callback[i] != NULL) { - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(tsi148_bridge->parent, "Location monitor " "callback attached, can't reset\n"); return -EBUSY; @@ -1922,7 +1922,7 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, lm_ctl |= TSI148_LCSR_LMAT_AS_A64; break; default: - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(tsi148_bridge->parent, "Invalid address space\n"); return -EINVAL; break; @@ -1943,7 +1943,7 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL); iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT); - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return 0; } @@ -1959,7 +1959,7 @@ int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, bridge = lm->parent->driver_priv; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU); lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL); @@ -1992,7 +1992,7 @@ int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, if (lm_ctl & TSI148_LCSR_LMAT_DATA) *cycle |= VME_DATA; - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return enabled; } @@ -2013,12 +2013,12 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, bridge = tsi148_bridge->driver_priv; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* Ensure that the location monitor is configured - need PGM or DATA */ lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT); if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) { - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(tsi148_bridge->parent, "Location monitor not properly " "configured\n"); return -EINVAL; @@ -2026,7 +2026,7 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, /* Check that a callback isn't already attached */ if (bridge->lm_callback[monitor] != NULL) { - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); dev_err(tsi148_bridge->parent, "Existing callback attached\n"); return -EBUSY; } @@ -2049,7 +2049,7 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT); } - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return 0; } @@ -2064,7 +2064,7 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) bridge = lm->parent->driver_priv; - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* Disable Location Monitor and ensure previous interrupts are clear */ lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN); @@ -2089,7 +2089,7 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT); } - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); return 0; } @@ -2142,7 +2142,7 @@ static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge, /* Allocate mem for CR/CSR image */ bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE, - &(bridge->crcsr_bus)); + &bridge->crcsr_bus); if (bridge->crcsr_kernel == NULL) { dev_err(tsi148_bridge->parent, "Failed to allocate memory for " "CR/CSR image\n"); @@ -2280,13 +2280,13 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* Initialize wait queues & mutual exclusion flags */ - init_waitqueue_head(&(tsi148_device->dma_queue[0])); - init_waitqueue_head(&(tsi148_device->dma_queue[1])); - init_waitqueue_head(&(tsi148_device->iack_queue)); - mutex_init(&(tsi148_device->vme_int)); - mutex_init(&(tsi148_device->vme_rmw)); + init_waitqueue_head(&tsi148_device->dma_queue[0]); + init_waitqueue_head(&tsi148_device->dma_queue[1]); + init_waitqueue_head(&tsi148_device->iack_queue); + mutex_init(&tsi148_device->vme_int); + mutex_init(&tsi148_device->vme_rmw); - tsi148_bridge->parent = &(pdev->dev); + tsi148_bridge->parent = &pdev->dev; strcpy(tsi148_bridge->name, driver_name); /* Setup IRQ */ @@ -2314,7 +2314,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_master; } tsi148_device->flush_image->parent = tsi148_bridge; - spin_lock_init(&(tsi148_device->flush_image->lock)); + spin_lock_init(&tsi148_device->flush_image->lock); tsi148_device->flush_image->locked = 1; tsi148_device->flush_image->number = master_num; tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 | @@ -2324,13 +2324,13 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | VME_PROG | VME_DATA; tsi148_device->flush_image->width_attr = VME_D16 | VME_D32; - memset(&(tsi148_device->flush_image->bus_resource), 0, + memset(&tsi148_device->flush_image->bus_resource, 0, sizeof(struct resource)); tsi148_device->flush_image->kern_base = NULL; } /* Add master windows to list */ - INIT_LIST_HEAD(&(tsi148_bridge->master_resources)); + INIT_LIST_HEAD(&tsi148_bridge->master_resources); for (i = 0; i < master_num; i++) { master_image = kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL); @@ -2341,7 +2341,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_master; } master_image->parent = tsi148_bridge; - spin_lock_init(&(master_image->lock)); + spin_lock_init(&master_image->lock); master_image->locked = 0; master_image->number = i; master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | @@ -2351,15 +2351,15 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | VME_PROG | VME_DATA; master_image->width_attr = VME_D16 | VME_D32; - memset(&(master_image->bus_resource), 0, + memset(&master_image->bus_resource, 0, sizeof(struct resource)); master_image->kern_base = NULL; - list_add_tail(&(master_image->list), - &(tsi148_bridge->master_resources)); + list_add_tail(&master_image->list, + &tsi148_bridge->master_resources); } /* Add slave windows to list */ - INIT_LIST_HEAD(&(tsi148_bridge->slave_resources)); + INIT_LIST_HEAD(&tsi148_bridge->slave_resources); for (i = 0; i < TSI148_MAX_SLAVE; i++) { slave_image = kmalloc(sizeof(struct vme_slave_resource), GFP_KERNEL); @@ -2370,7 +2370,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_slave; } slave_image->parent = tsi148_bridge; - mutex_init(&(slave_image->mtx)); + mutex_init(&slave_image->mtx); slave_image->locked = 0; slave_image->number = i; slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | @@ -2380,12 +2380,12 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | VME_PROG | VME_DATA; - list_add_tail(&(slave_image->list), - &(tsi148_bridge->slave_resources)); + list_add_tail(&slave_image->list, + &tsi148_bridge->slave_resources); } /* Add dma engines to list */ - INIT_LIST_HEAD(&(tsi148_bridge->dma_resources)); + INIT_LIST_HEAD(&tsi148_bridge->dma_resources); for (i = 0; i < TSI148_MAX_DMA; i++) { dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource), GFP_KERNEL); @@ -2396,21 +2396,21 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_dma; } dma_ctrlr->parent = tsi148_bridge; - mutex_init(&(dma_ctrlr->mtx)); + mutex_init(&dma_ctrlr->mtx); dma_ctrlr->locked = 0; dma_ctrlr->number = i; dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM | VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME | VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME | VME_DMA_PATTERN_TO_MEM; - INIT_LIST_HEAD(&(dma_ctrlr->pending)); - INIT_LIST_HEAD(&(dma_ctrlr->running)); - list_add_tail(&(dma_ctrlr->list), - &(tsi148_bridge->dma_resources)); + INIT_LIST_HEAD(&dma_ctrlr->pending); + INIT_LIST_HEAD(&dma_ctrlr->running); + list_add_tail(&dma_ctrlr->list, + &tsi148_bridge->dma_resources); } /* Add location monitor to list */ - INIT_LIST_HEAD(&(tsi148_bridge->lm_resources)); + INIT_LIST_HEAD(&tsi148_bridge->lm_resources); lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL); if (lm == NULL) { dev_err(&pdev->dev, "Failed to allocate memory for " @@ -2419,11 +2419,11 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_lm; } lm->parent = tsi148_bridge; - mutex_init(&(lm->mtx)); + mutex_init(&lm->mtx); lm->locked = 0; lm->number = 1; lm->monitors = 4; - list_add_tail(&(lm->list), &(tsi148_bridge->lm_resources)); + list_add_tail(&lm->list, &tsi148_bridge->lm_resources); tsi148_bridge->slave_get = tsi148_slave_get; tsi148_bridge->slave_set = tsi148_slave_set; @@ -2483,28 +2483,28 @@ err_reg: err_crcsr: err_lm: /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->lm_resources)) { + list_for_each(pos, &tsi148_bridge->lm_resources) { lm = list_entry(pos, struct vme_lm_resource, list); list_del(pos); kfree(lm); } err_dma: /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->dma_resources)) { + list_for_each(pos, &tsi148_bridge->dma_resources) { dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); list_del(pos); kfree(dma_ctrlr); } err_slave: /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->slave_resources)) { + list_for_each(pos, &tsi148_bridge->slave_resources) { slave_image = list_entry(pos, struct vme_slave_resource, list); list_del(pos); kfree(slave_image); } err_master: /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->master_resources)) { + list_for_each(pos, &tsi148_bridge->master_resources) { master_image = list_entry(pos, struct vme_master_resource, list); list_del(pos); @@ -2589,21 +2589,21 @@ static void tsi148_remove(struct pci_dev *pdev) tsi148_crcsr_exit(tsi148_bridge, pdev); /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->dma_resources)) { + list_for_each(pos, &tsi148_bridge->dma_resources) { dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); list_del(pos); kfree(dma_ctrlr); } /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->slave_resources)) { + list_for_each(pos, &tsi148_bridge->slave_resources) { slave_image = list_entry(pos, struct vme_slave_resource, list); list_del(pos); kfree(slave_image); } /* resources are stored in link list */ - list_for_each(pos, &(tsi148_bridge->master_resources)) { + list_for_each(pos, &tsi148_bridge->master_resources) { master_image = list_entry(pos, struct vme_master_resource, list); list_del(pos); diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 71bbc526626c..cbe2e11d9af7 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -470,9 +470,9 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, * to userspace as they are */ retval = vme_master_get(image[minor].resource, - &(master.enable), &(master.vme_addr), - &(master.size), &(master.aspace), - &(master.cycle), &(master.dwidth)); + &master.enable, &master.vme_addr, + &master.size, &master.aspace, + &master.cycle, &master.dwidth); copied = copy_to_user((char *)arg, &master, sizeof(struct vme_master)); @@ -514,9 +514,9 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, * to userspace as they are */ retval = vme_slave_get(image[minor].resource, - &(slave.enable), &(slave.vme_addr), - &(slave.size), &pci_addr, &(slave.aspace), - &(slave.cycle)); + &slave.enable, &slave.vme_addr, + &slave.size, &pci_addr, &slave.aspace, + &slave.cycle); copied = copy_to_user((char *)arg, &slave, sizeof(struct vme_slave)); @@ -683,7 +683,7 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot) for (i = 0; i < VME_DEVS; i++) { image[i].kern_buf = NULL; image[i].pci_buf = 0; - sema_init(&(image[i].sem), 1); + sema_init(&image[i].sem, 1); image[i].device = NULL; image[i].resource = NULL; image[i].users = 0; @@ -727,7 +727,7 @@ static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot) } image[i].size_buf = PCI_BUF_SIZE; image[i].kern_buf = vme_alloc_consistent(image[i].resource, - image[i].size_buf, &(image[i].pci_buf)); + image[i].size_buf, &image[i].pci_buf); if (image[i].kern_buf == NULL) { printk(KERN_WARNING "Unable to allocate memory for " "buffer\n"); diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c index 093fbffbf557..47e9d5ccf784 100644 --- a/drivers/staging/vme/vme.c +++ b/drivers/staging/vme/vme.c @@ -245,7 +245,7 @@ struct vme_resource *vme_slave_request(struct device *dev, } /* Loop through slave resources */ - list_for_each(slave_pos, &(bridge->slave_resources)) { + list_for_each(slave_pos, &bridge->slave_resources) { slave_image = list_entry(slave_pos, struct vme_slave_resource, list); @@ -255,17 +255,17 @@ struct vme_resource *vme_slave_request(struct device *dev, } /* Find an unlocked and compatible image */ - mutex_lock(&(slave_image->mtx)); + mutex_lock(&slave_image->mtx); if (((slave_image->address_attr & address) == address) && ((slave_image->cycle_attr & cycle) == cycle) && (slave_image->locked == 0)) { slave_image->locked = 1; - mutex_unlock(&(slave_image->mtx)); + mutex_unlock(&slave_image->mtx); allocated_image = slave_image; break; } - mutex_unlock(&(slave_image->mtx)); + mutex_unlock(&slave_image->mtx); } /* No free image */ @@ -278,15 +278,15 @@ struct vme_resource *vme_slave_request(struct device *dev, goto err_alloc; } resource->type = VME_SLAVE; - resource->entry = &(allocated_image->list); + resource->entry = &allocated_image->list; return resource; err_alloc: /* Unlock image */ - mutex_lock(&(slave_image->mtx)); + mutex_lock(&slave_image->mtx); slave_image->locked = 0; - mutex_unlock(&(slave_image->mtx)); + mutex_unlock(&slave_image->mtx); err_image: err_bus: return NULL; @@ -369,12 +369,12 @@ void vme_slave_free(struct vme_resource *resource) } /* Unlock image */ - mutex_lock(&(slave_image->mtx)); + mutex_lock(&slave_image->mtx); if (slave_image->locked == 0) printk(KERN_ERR "Image is already free\n"); slave_image->locked = 0; - mutex_unlock(&(slave_image->mtx)); + mutex_unlock(&slave_image->mtx); /* Free up resource memory */ kfree(resource); @@ -401,7 +401,7 @@ struct vme_resource *vme_master_request(struct device *dev, } /* Loop through master resources */ - list_for_each(master_pos, &(bridge->master_resources)) { + list_for_each(master_pos, &bridge->master_resources) { master_image = list_entry(master_pos, struct vme_master_resource, list); @@ -411,18 +411,18 @@ struct vme_resource *vme_master_request(struct device *dev, } /* Find an unlocked and compatible image */ - spin_lock(&(master_image->lock)); + spin_lock(&master_image->lock); if (((master_image->address_attr & address) == address) && ((master_image->cycle_attr & cycle) == cycle) && ((master_image->width_attr & dwidth) == dwidth) && (master_image->locked == 0)) { master_image->locked = 1; - spin_unlock(&(master_image->lock)); + spin_unlock(&master_image->lock); allocated_image = master_image; break; } - spin_unlock(&(master_image->lock)); + spin_unlock(&master_image->lock); } /* Check to see if we found a resource */ @@ -437,16 +437,16 @@ struct vme_resource *vme_master_request(struct device *dev, goto err_alloc; } resource->type = VME_MASTER; - resource->entry = &(allocated_image->list); + resource->entry = &allocated_image->list; return resource; kfree(resource); err_alloc: /* Unlock image */ - spin_lock(&(master_image->lock)); + spin_lock(&master_image->lock); master_image->locked = 0; - spin_unlock(&(master_image->lock)); + spin_unlock(&master_image->lock); err_image: err_bus: return NULL; @@ -628,12 +628,12 @@ void vme_master_free(struct vme_resource *resource) } /* Unlock image */ - spin_lock(&(master_image->lock)); + spin_lock(&master_image->lock); if (master_image->locked == 0) printk(KERN_ERR "Image is already free\n"); master_image->locked = 0; - spin_unlock(&(master_image->lock)); + spin_unlock(&master_image->lock); /* Free up resource memory */ kfree(resource); @@ -662,7 +662,7 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route) } /* Loop through DMA resources */ - list_for_each(dma_pos, &(bridge->dma_resources)) { + list_for_each(dma_pos, &bridge->dma_resources) { dma_ctrlr = list_entry(dma_pos, struct vme_dma_resource, list); @@ -672,16 +672,16 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route) } /* Find an unlocked and compatible controller */ - mutex_lock(&(dma_ctrlr->mtx)); + mutex_lock(&dma_ctrlr->mtx); if (((dma_ctrlr->route_attr & route) == route) && (dma_ctrlr->locked == 0)) { dma_ctrlr->locked = 1; - mutex_unlock(&(dma_ctrlr->mtx)); + mutex_unlock(&dma_ctrlr->mtx); allocated_ctrlr = dma_ctrlr; break; } - mutex_unlock(&(dma_ctrlr->mtx)); + mutex_unlock(&dma_ctrlr->mtx); } /* Check to see if we found a resource */ @@ -694,15 +694,15 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route) goto err_alloc; } resource->type = VME_DMA; - resource->entry = &(allocated_ctrlr->list); + resource->entry = &allocated_ctrlr->list; return resource; err_alloc: /* Unlock image */ - mutex_lock(&(dma_ctrlr->mtx)); + mutex_lock(&dma_ctrlr->mtx); dma_ctrlr->locked = 0; - mutex_unlock(&(dma_ctrlr->mtx)); + mutex_unlock(&dma_ctrlr->mtx); err_ctrlr: err_bus: return NULL; @@ -729,9 +729,9 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) printk(KERN_ERR "Unable to allocate memory for new dma list\n"); return NULL; } - INIT_LIST_HEAD(&(dma_list->entries)); + INIT_LIST_HEAD(&dma_list->entries); dma_list->parent = ctrlr; - mutex_init(&(dma_list->mtx)); + mutex_init(&dma_list->mtx); return dma_list; } @@ -880,14 +880,14 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, return -EINVAL; } - if (!mutex_trylock(&(list->mtx))) { + if (!mutex_trylock(&list->mtx)) { printk(KERN_ERR "Link List already submitted\n"); return -EINVAL; } retval = bridge->dma_list_add(list, src, dest, count); - mutex_unlock(&(list->mtx)); + mutex_unlock(&list->mtx); return retval; } @@ -903,11 +903,11 @@ int vme_dma_list_exec(struct vme_dma_list *list) return -EINVAL; } - mutex_lock(&(list->mtx)); + mutex_lock(&list->mtx); retval = bridge->dma_list_exec(list); - mutex_unlock(&(list->mtx)); + mutex_unlock(&list->mtx); return retval; } @@ -923,7 +923,7 @@ int vme_dma_list_free(struct vme_dma_list *list) return -EINVAL; } - if (!mutex_trylock(&(list->mtx))) { + if (!mutex_trylock(&list->mtx)) { printk(KERN_ERR "Link List in use\n"); return -EINVAL; } @@ -935,10 +935,10 @@ int vme_dma_list_free(struct vme_dma_list *list) retval = bridge->dma_list_empty(list); if (retval) { printk(KERN_ERR "Unable to empty link-list entries\n"); - mutex_unlock(&(list->mtx)); + mutex_unlock(&list->mtx); return retval; } - mutex_unlock(&(list->mtx)); + mutex_unlock(&list->mtx); kfree(list); return retval; @@ -956,20 +956,20 @@ int vme_dma_free(struct vme_resource *resource) ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); - if (!mutex_trylock(&(ctrlr->mtx))) { + if (!mutex_trylock(&ctrlr->mtx)) { printk(KERN_ERR "Resource busy, can't free\n"); return -EBUSY; } - if (!(list_empty(&(ctrlr->pending)) && list_empty(&(ctrlr->running)))) { + if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) { printk(KERN_WARNING "Resource still processing transfers\n"); - mutex_unlock(&(ctrlr->mtx)); + mutex_unlock(&ctrlr->mtx); return -EBUSY; } ctrlr->locked = 0; - mutex_unlock(&(ctrlr->mtx)); + mutex_unlock(&ctrlr->mtx); return 0; } @@ -1013,10 +1013,10 @@ int vme_irq_request(struct device *dev, int level, int statid, return -EINVAL; } - mutex_lock(&(bridge->irq_mtx)); + mutex_lock(&bridge->irq_mtx); if (bridge->irq[level - 1].callback[statid].func) { - mutex_unlock(&(bridge->irq_mtx)); + mutex_unlock(&bridge->irq_mtx); printk(KERN_WARNING "VME Interrupt already taken\n"); return -EBUSY; } @@ -1028,7 +1028,7 @@ int vme_irq_request(struct device *dev, int level, int statid, /* Enable IRQ level */ bridge->irq_set(bridge, level, 1, 1); - mutex_unlock(&(bridge->irq_mtx)); + mutex_unlock(&bridge->irq_mtx); return 0; } @@ -1054,7 +1054,7 @@ void vme_irq_free(struct device *dev, int level, int statid) return; } - mutex_lock(&(bridge->irq_mtx)); + mutex_lock(&bridge->irq_mtx); bridge->irq[level - 1].count--; @@ -1065,7 +1065,7 @@ void vme_irq_free(struct device *dev, int level, int statid) bridge->irq[level - 1].callback[statid].func = NULL; bridge->irq[level - 1].callback[statid].priv_data = NULL; - mutex_unlock(&(bridge->irq_mtx)); + mutex_unlock(&bridge->irq_mtx); } EXPORT_SYMBOL(vme_irq_free); @@ -1111,7 +1111,7 @@ struct vme_resource *vme_lm_request(struct device *dev) } /* Loop through DMA resources */ - list_for_each(lm_pos, &(bridge->lm_resources)) { + list_for_each(lm_pos, &bridge->lm_resources) { lm = list_entry(lm_pos, struct vme_lm_resource, list); @@ -1122,14 +1122,14 @@ struct vme_resource *vme_lm_request(struct device *dev) } /* Find an unlocked controller */ - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); if (lm->locked == 0) { lm->locked = 1; - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); allocated_lm = lm; break; } - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); } /* Check to see if we found a resource */ @@ -1142,15 +1142,15 @@ struct vme_resource *vme_lm_request(struct device *dev) goto err_alloc; } resource->type = VME_LM; - resource->entry = &(allocated_lm->list); + resource->entry = &allocated_lm->list; return resource; err_alloc: /* Unlock image */ - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); lm->locked = 0; - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); err_lm: err_bus: return NULL; @@ -1270,7 +1270,7 @@ void vme_lm_free(struct vme_resource *resource) lm = list_entry(resource->entry, struct vme_lm_resource, list); - mutex_lock(&(lm->mtx)); + mutex_lock(&lm->mtx); /* XXX * Check to see that there aren't any callbacks still attached, if @@ -1279,7 +1279,7 @@ void vme_lm_free(struct vme_resource *resource) lm->locked = 0; - mutex_unlock(&(lm->mtx)); + mutex_unlock(&lm->mtx); kfree(resource); } @@ -1343,11 +1343,11 @@ int vme_register_bridge(struct vme_bridge *bridge) * specification. */ for (i = 0; i < VME_SLOTS_MAX; i++) { - dev = &(bridge->dev[i]); + dev = &bridge->dev[i]; memset(dev, 0, sizeof(struct device)); dev->parent = bridge->parent; - dev->bus = &(vme_bus_type); + dev->bus = &vme_bus_type; /* * We save a pointer to the bridge in platform_data so that we * can get to it later. We keep driver_data for use by the @@ -1366,7 +1366,7 @@ int vme_register_bridge(struct vme_bridge *bridge) i = VME_SLOTS_MAX; err_reg: while (i > -1) { - dev = &(bridge->dev[i]); + dev = &bridge->dev[i]; device_unregister(dev); } vme_free_bus_num(bridge->num); @@ -1381,7 +1381,7 @@ void vme_unregister_bridge(struct vme_bridge *bridge) for (i = 0; i < VME_SLOTS_MAX; i++) { - dev = &(bridge->dev[i]); + dev = &bridge->dev[i]; device_unregister(dev); } vme_free_bus_num(bridge->num); @@ -1418,7 +1418,7 @@ static int vme_calc_slot(struct device *dev) /* Determine slot number */ num = 0; while (num < VME_SLOTS_MAX) { - if (&(bridge->dev[num]) == dev) + if (&bridge->dev[num] == dev) break; num++; -- cgit v1.2.3 From 55db50205adaf14db1bda07d0931b647b794de2f Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:14 +0000 Subject: staging: vme_user: return the appropriate error code when module_init fails When init_module fails, 0 is returned anyway; the module is then installed and oopses when we try to remove it: [ 3236.368009] WARNING: at drivers/base/driver.c:262 driver_unregister+0x36/0x6f() [ 3236.368012] Hardware name: [ 3236.368014] Unexpected driver unregister! [ 3236.368016] Modules linked in: vme_user(-) vme_tsi148 vme e1000e iTCO_wdt iTCO_vendor_support [last unloaded: vme] [ 3236.368027] Pid: 16162, comm: rmmod Not tainted 2.6.35 #2 [ 3236.368029] Call Trace: [ 3236.368037] [] warn_slowpath_common+0x80/0x98 [ 3236.368044] [] ? __try_stop_module+0x0/0x58 [ 3236.368049] [] warn_slowpath_fmt+0x41/0x43 [ 3236.368054] [] ? __try_stop_module+0x0/0x58 [ 3236.368059] [] driver_unregister+0x36/0x6f [ 3236.368066] [] vme_unregister_driver+0xd/0xf [vme] [ 3236.368072] [] vme_user_exit+0x10/0x1e [vme_user] [ 3236.368076] [] sys_delete_module+0x1ba/0x226 [ 3236.368082] [] ? do_page_fault+0x25d/0x28a [ 3236.368088] [] system_call_fastpath+0x16/0x1b [ 3236.368092] ---[ end trace cab6d88ebc44c1de ]--- The appended fixes it by returning the appropriate error code in module_init whenever something goes wrong, thus cancelling the insertion of the module. Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index cbe2e11d9af7..a6f61162af3f 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -611,6 +611,7 @@ static int __init vme_user_init(void) if (bus_num == 0) { printk(KERN_ERR "%s: No cards, skipping registration\n", driver_name); + retval = -ENODEV; goto err_nocard; } @@ -629,6 +630,7 @@ static int __init vme_user_init(void) if (ids == NULL) { printk(KERN_ERR "%s: Unable to allocate ID table\n", driver_name); + retval = -ENOMEM; goto err_id; } -- cgit v1.2.3 From c0779fd01df76b3097cc77e3a404e8bb067e5628 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:20 +0000 Subject: staging: vme_user: remove unreachable line Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index a6f61162af3f..bdc4e1ecfaf3 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -654,7 +654,6 @@ static int __init vme_user_init(void) return retval; - vme_unregister_driver(&vme_user_driver); err_reg: kfree(ids); err_id: -- cgit v1.2.3 From db6d8fc5596ef866e64e9a7eef96bacdc6e51e11 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:27 +0000 Subject: staging: vme: fix bogus clearing of the bus number in vme_free_bus_num Signed-off-by: Emilio G. Cota Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/vme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c index 47e9d5ccf784..d9fc8644376e 100644 --- a/drivers/staging/vme/vme.c +++ b/drivers/staging/vme/vme.c @@ -1326,7 +1326,7 @@ static int vme_alloc_bus_num(void) static void vme_free_bus_num(int bus) { mutex_lock(&vme_bus_num_mtx); - vme_bus_numbers |= ~(0x1 << bus); + vme_bus_numbers &= ~(0x1 << bus); mutex_unlock(&vme_bus_num_mtx); } -- cgit v1.2.3 From b558ba2f356c28269de179c4f7f6f179a4fa6a1d Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:34 +0000 Subject: staging: vme: tsi148: use list_for_each_safe when deleting resources in .remove This fixes an oops when removing the module. Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_tsi148.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 1cba1fa16079..5c25cd8c9209 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -2531,6 +2531,7 @@ err_struct: static void tsi148_remove(struct pci_dev *pdev) { struct list_head *pos = NULL; + struct list_head *tmplist; struct vme_master_resource *master_image; struct vme_slave_resource *slave_image; struct vme_dma_resource *dma_ctrlr; @@ -2589,21 +2590,21 @@ static void tsi148_remove(struct pci_dev *pdev) tsi148_crcsr_exit(tsi148_bridge, pdev); /* resources are stored in link list */ - list_for_each(pos, &tsi148_bridge->dma_resources) { + list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) { dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); list_del(pos); kfree(dma_ctrlr); } /* resources are stored in link list */ - list_for_each(pos, &tsi148_bridge->slave_resources) { + list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) { slave_image = list_entry(pos, struct vme_slave_resource, list); list_del(pos); kfree(slave_image); } /* resources are stored in link list */ - list_for_each(pos, &tsi148_bridge->master_resources) { + list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) { master_image = list_entry(pos, struct vme_master_resource, list); list_del(pos); -- cgit v1.2.3 From b12ef0b1f5d0358bc13cc716155d6e9b5584af48 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:40 +0000 Subject: staging: vme: tsi148: remove double freeing of the IRQ in .remove tsi148_irq_exit is called twice in .remove, which causes an oops. Remove the second call, which apart from being redundant cannot possibly work; the CR/CSR space has been already unmapped. Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_tsi148.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 5c25cd8c9209..2f8f399df85b 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -2611,8 +2611,6 @@ static void tsi148_remove(struct pci_dev *pdev) kfree(master_image); } - tsi148_irq_exit(bridge, pdev); - iounmap(bridge->base); pci_release_regions(pdev); -- cgit v1.2.3 From a82ad05ecd9dbd909509a332d3aa5f4ac439a054 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:47 +0000 Subject: staging: vme: tsi148: fix warning in free_irq The cookie passed to request_irq isn't the same as the one passed to free_irq, which results in the following warning: [ 63.243533] WARNING: at kernel/irq/manage.c:899 __free_irq+0x9b/0x17d() [ 63.243533] Hardware name: [ 63.243533] Trying to free already-free IRQ 17 [ 63.243533] Modules linked in: vme_tsi148(-) vme e1000e iTCO_wdt iTCO_vendor_support [last unloaded: scsi_wait_scan] [ 63.243533] Pid: 2013, comm: rmmod Not tainted 2.6.35 #2 [ 63.243533] Call Trace: [ 63.243533] [] warn_slowpath_common+0x80/0x98 [ 63.243533] [] warn_slowpath_fmt+0x41/0x43 [ 63.243533] [] __free_irq+0x9b/0x17d [ 63.243533] [] free_irq+0x33/0x4e [ 63.243533] [] tsi148_irq_exit+0x6b/0x70 [vme_tsi148] [...] [ 63.243533] ---[ end trace bbf92311d969efb4 ]--- Fix it by passing the same cookie to both functions. Signed-off-by: Emilio G. Cota [martyn.welch@ge.com: modified to remove checkpatch warnings] Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/Module.symvers | 0 drivers/staging/vme/bridges/vme_tsi148.c | 11 +++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 drivers/staging/vme/bridges/Module.symvers (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 2f8f399df85b..70c9e41154e7 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -374,8 +374,11 @@ static int tsi148_irq_init(struct vme_bridge *tsi148_bridge) return 0; } -static void tsi148_irq_exit(struct tsi148_driver *bridge, struct pci_dev *pdev) +static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge, + struct pci_dev *pdev) { + struct tsi148_driver *bridge = tsi148_bridge->driver_priv; + /* Turn off interrupts */ iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO); iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN); @@ -384,7 +387,7 @@ static void tsi148_irq_exit(struct tsi148_driver *bridge, struct pci_dev *pdev) iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC); /* Detach interrupt handler */ - free_irq(pdev->irq, pdev); + free_irq(pdev->irq, tsi148_bridge); } /* @@ -2511,7 +2514,7 @@ err_master: kfree(master_image); } - tsi148_irq_exit(tsi148_device, pdev); + tsi148_irq_exit(tsi148_bridge, pdev); err_irq: err_test: iounmap(tsi148_device->base); @@ -2583,7 +2586,7 @@ static void tsi148_remove(struct pci_dev *pdev) iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1); iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2); - tsi148_irq_exit(bridge, pdev); + tsi148_irq_exit(tsi148_bridge, pdev); vme_unregister_bridge(tsi148_bridge); -- cgit v1.2.3 From 84295e0b243cba070fcfe8be825c39827ea022e6 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:14:54 +0000 Subject: staging: vme: tsi148: remove unreachable line Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_tsi148.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 70c9e41154e7..e79a5fad458c 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -2480,7 +2480,6 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; - vme_unregister_bridge(tsi148_bridge); err_reg: tsi148_crcsr_exit(tsi148_bridge, pdev); err_crcsr: -- cgit v1.2.3 From 5ade6c4d79377efc371ac89db07e4f6594d1286a Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:00 +0000 Subject: staging: vme: tsi148: declare static functions as such Signed-off-by: Emilio G. Cota [martyn.welch@ge.com: modified to remove checkpatch warnings] Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_tsi148.c | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index e79a5fad458c..9550b4a8f93a 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -393,7 +393,7 @@ static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge, /* * Check to see if an IACk has been received, return true (1) or false (0). */ -int tsi148_iack_received(struct tsi148_driver *bridge) +static int tsi148_iack_received(struct tsi148_driver *bridge) { u32 tmp; @@ -408,7 +408,7 @@ int tsi148_iack_received(struct tsi148_driver *bridge) /* * Configure VME interrupt */ -void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level, +static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level, int state, int sync) { struct pci_dev *pdev; @@ -448,7 +448,8 @@ void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level, * Generate a VME bus interrupt at the requested level & vector. Wait for * interrupt to be acked. */ -int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, int statid) +static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, + int statid) { u32 tmp; struct tsi148_driver *bridge; @@ -548,7 +549,7 @@ static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, /* * Initialize a slave window with the requested attributes. */ -int tsi148_slave_set(struct vme_slave_resource *image, int enabled, +static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, unsigned long long vme_base, unsigned long long size, dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle) { @@ -698,7 +699,7 @@ int tsi148_slave_set(struct vme_slave_resource *image, int enabled, /* * Get slave window configuration. */ -int tsi148_slave_get(struct vme_slave_resource *image, int *enabled, +static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle) { @@ -894,7 +895,7 @@ static void tsi148_free_resource(struct vme_master_resource *image) /* * Set the attributes of an outbound window. */ -int tsi148_master_set(struct vme_master_resource *image, int enabled, +static int tsi148_master_set(struct vme_master_resource *image, int enabled, unsigned long long vme_base, unsigned long long size, vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) { @@ -1130,7 +1131,7 @@ err_window: * * XXX Not parsing prefetch information. */ -int __tsi148_master_get(struct vme_master_resource *image, int *enabled, +static int __tsi148_master_get(struct vme_master_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) { @@ -1240,7 +1241,7 @@ int __tsi148_master_get(struct vme_master_resource *image, int *enabled, } -int tsi148_master_get(struct vme_master_resource *image, int *enabled, +static int tsi148_master_get(struct vme_master_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) { @@ -1256,7 +1257,7 @@ int tsi148_master_get(struct vme_master_resource *image, int *enabled, return retval; } -ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, +static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, size_t count, loff_t offset) { int retval, enabled; @@ -1298,7 +1299,7 @@ skip_chk: } -ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, +static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, size_t count, loff_t offset) { int retval = 0, enabled; @@ -1365,7 +1366,7 @@ skip_chk: * * Requires a previously configured master window, returns final value. */ -unsigned int tsi148_master_rmw(struct vme_master_resource *image, +static unsigned int tsi148_master_rmw(struct vme_master_resource *image, unsigned int mask, unsigned int compare, unsigned int swap, loff_t offset) { @@ -1612,8 +1613,8 @@ static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr, /* * Add a link list descriptor to the list */ -int tsi148_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, - struct vme_dma_attr *dest, size_t count) +static int tsi148_dma_list_add(struct vme_dma_list *list, + struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count) { struct tsi148_dma_entry *entry, *prev; u32 address_high, address_low; @@ -1785,7 +1786,7 @@ static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel) * * XXX Need to provide control register configuration. */ -int tsi148_dma_list_exec(struct vme_dma_list *list) +static int tsi148_dma_list_exec(struct vme_dma_list *list) { struct vme_dma_resource *ctrlr; int channel, retval = 0; @@ -1865,7 +1866,7 @@ int tsi148_dma_list_exec(struct vme_dma_list *list) * * We have a separate function, don't assume that the chain can't be reused. */ -int tsi148_dma_list_empty(struct vme_dma_list *list) +static int tsi148_dma_list_empty(struct vme_dma_list *list) { struct list_head *pos, *temp; struct tsi148_dma_entry *entry; @@ -1887,7 +1888,7 @@ int tsi148_dma_list_empty(struct vme_dma_list *list) * This does not enable the LM monitor - that should be done when the first * callback is attached and disabled when the last callback is removed. */ -int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, +static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, vme_address_t aspace, vme_cycle_t cycle) { u32 lm_base_high, lm_base_low, lm_ctl = 0; @@ -1954,8 +1955,8 @@ int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, /* Get configuration of the callback monitor and return whether it is enabled * or disabled. */ -int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, - vme_address_t *aspace, vme_cycle_t *cycle) +static int tsi148_lm_get(struct vme_lm_resource *lm, + unsigned long long *lm_base, vme_address_t *aspace, vme_cycle_t *cycle) { u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0; struct tsi148_driver *bridge; @@ -2005,7 +2006,7 @@ int tsi148_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, * * Callback will be passed the monitor triggered. */ -int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, +static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, void (*callback)(int)) { u32 lm_ctl, tmp; @@ -2060,7 +2061,7 @@ int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, /* * Detach a callback function forn a specific location monitor. */ -int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) +static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) { u32 lm_en, tmp; struct tsi148_driver *bridge; @@ -2100,7 +2101,7 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) /* * Determine Geographical Addressing */ -int tsi148_slot_get(struct vme_bridge *tsi148_bridge) +static int tsi148_slot_get(struct vme_bridge *tsi148_bridge) { u32 slot = 0; struct tsi148_driver *bridge; -- cgit v1.2.3 From efbb979d1b31638a95d76b5acf65cf00a3213fe4 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:07 +0000 Subject: staging: vme: ca91cx42: declare static functions as such Signed-off-by: Emilio G. Cota [martyn.welch@ge.com: modified to remove checkpatch warnings] Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_ca91cx42.c | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index 1f2089ff7f9f..3ddc93ba7049 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -259,8 +259,8 @@ static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge, /* * Set up an VME interrupt */ -void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, int state, - int sync) +static void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, + int state, int sync) { struct pci_dev *pdev; @@ -287,7 +287,7 @@ void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, int state, } } -int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, +static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, int statid) { u32 tmp; @@ -323,7 +323,7 @@ int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, return 0; } -int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled, +static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled, unsigned long long vme_base, unsigned long long size, dma_addr_t pci_base, vme_address_t aspace, vme_cycle_t cycle) { @@ -429,7 +429,7 @@ int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled, return 0; } -int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled, +static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, dma_addr_t *pci_base, vme_address_t *aspace, vme_cycle_t *cycle) { @@ -584,7 +584,7 @@ static void ca91cx42_free_resource(struct vme_master_resource *image) } -int ca91cx42_master_set(struct vme_master_resource *image, int enabled, +static int ca91cx42_master_set(struct vme_master_resource *image, int enabled, unsigned long long vme_base, unsigned long long size, vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth) { @@ -741,8 +741,8 @@ err_window: return retval; } -int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, +static int __ca91cx42_master_get(struct vme_master_resource *image, + int *enabled, unsigned long long *vme_base, unsigned long long *size, vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) { unsigned int i, ctl; @@ -828,7 +828,7 @@ int __ca91cx42_master_get(struct vme_master_resource *image, int *enabled, return 0; } -int ca91cx42_master_get(struct vme_master_resource *image, int *enabled, +static int ca91cx42_master_get(struct vme_master_resource *image, int *enabled, unsigned long long *vme_base, unsigned long long *size, vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth) { @@ -844,8 +844,8 @@ int ca91cx42_master_get(struct vme_master_resource *image, int *enabled, return retval; } -ssize_t ca91cx42_master_read(struct vme_master_resource *image, void *buf, - size_t count, loff_t offset) +static ssize_t ca91cx42_master_read(struct vme_master_resource *image, + void *buf, size_t count, loff_t offset) { ssize_t retval; void *addr = image->kern_base + offset; @@ -904,8 +904,8 @@ out: return retval; } -ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf, - size_t count, loff_t offset) +static ssize_t ca91cx42_master_write(struct vme_master_resource *image, + void *buf, size_t count, loff_t offset) { ssize_t retval; void *addr = image->kern_base + offset; @@ -959,7 +959,7 @@ out: return retval; } -unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, +static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, unsigned int mask, unsigned int compare, unsigned int swap, loff_t offset) { @@ -1015,8 +1015,8 @@ out: return result; } -int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, - struct vme_dma_attr *dest, size_t count) +static int ca91cx42_dma_list_add(struct vme_dma_list *list, + struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count) { struct ca91cx42_dma_entry *entry, *prev; struct vme_dma_pci *pci_attr; @@ -1176,7 +1176,7 @@ static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge) return 1; } -int ca91cx42_dma_list_exec(struct vme_dma_list *list) +static int ca91cx42_dma_list_exec(struct vme_dma_list *list) { struct vme_dma_resource *ctrlr; struct ca91cx42_dma_entry *entry; @@ -1258,7 +1258,7 @@ int ca91cx42_dma_list_exec(struct vme_dma_list *list) } -int ca91cx42_dma_list_empty(struct vme_dma_list *list) +static int ca91cx42_dma_list_empty(struct vme_dma_list *list) { struct list_head *pos, *temp; struct ca91cx42_dma_entry *entry; @@ -1280,8 +1280,8 @@ int ca91cx42_dma_list_empty(struct vme_dma_list *list) * This does not enable the LM monitor - that should be done when the first * callback is attached and disabled when the last callback is removed. */ -int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, - vme_address_t aspace, vme_cycle_t cycle) +static int ca91cx42_lm_set(struct vme_lm_resource *lm, + unsigned long long lm_base, vme_address_t aspace, vme_cycle_t cycle) { u32 temp_base, lm_ctl = 0; int i; @@ -1348,8 +1348,8 @@ int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, /* Get configuration of the callback monitor and return whether it is enabled * or disabled. */ -int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, - vme_address_t *aspace, vme_cycle_t *cycle) +static int ca91cx42_lm_get(struct vme_lm_resource *lm, + unsigned long long *lm_base, vme_address_t *aspace, vme_cycle_t *cycle) { u32 lm_ctl, enabled = 0; struct ca91cx42_driver *bridge; @@ -1391,7 +1391,7 @@ int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, * * Callback will be passed the monitor triggered. */ -int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, +static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, void (*callback)(int)) { u32 lm_ctl, tmp; @@ -1440,7 +1440,7 @@ int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, /* * Detach a callback function forn a specific location monitor. */ -int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) +static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) { u32 tmp; struct ca91cx42_driver *bridge; @@ -1473,7 +1473,7 @@ int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) return 0; } -int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge) +static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge) { u32 slot = 0; struct ca91cx42_driver *bridge; @@ -1832,7 +1832,7 @@ err_struct: } -void ca91cx42_remove(struct pci_dev *pdev) +static void ca91cx42_remove(struct pci_dev *pdev) { struct list_head *pos = NULL; struct vme_master_resource *master_image; -- cgit v1.2.3 From b9cc293486e27f4d29a9813da6ebcb8574071dfa Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:14 +0000 Subject: staging: vme_user: declare private variables as static Signed-off-by: Emilio G. Cota [martyn.welch@ge.com: modified to remove checkpatch warnings] Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index bdc4e1ecfaf3..f7fa02d0d87b 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -114,9 +114,9 @@ typedef struct { } driver_stats_t; static driver_stats_t statistics; -struct cdev *vme_user_cdev; /* Character device */ -struct class *vme_user_sysfs_class; /* Sysfs class */ -struct device *vme_user_bridge; /* Pointer to the bridge device */ +static struct cdev *vme_user_cdev; /* Character device */ +static struct class *vme_user_sysfs_class; /* Sysfs class */ +static struct device *vme_user_bridge; /* Pointer to bridge device */ static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR, -- cgit v1.2.3 From c949231838006d7de4ad38be38d9e112826862da Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:21 +0000 Subject: staging: vme_user: use an unsigned int for counting the number of kparams unsigned int is what struct kparam_array internally uses. Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index f7fa02d0d87b..7c61adc8eb79 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -44,7 +44,7 @@ static DEFINE_MUTEX(vme_user_mutex); static char driver_name[] = "vme_user"; static int bus[USER_BUS_MAX]; -static int bus_num; +static unsigned int bus_num; /* Currently Documentation/devices.txt defines the following for VME: * -- cgit v1.2.3 From 0a81a0f768e5bb0c32db6e44440c5b7c1b4658e7 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:27 +0000 Subject: staging: vme_user: remove __iomem marking from kern_buf and derivates kern_buf is not iomem; it comes from kmalloc and is directly dereferenced. Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 7c61adc8eb79..5d3a39bcd2a8 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -92,7 +92,7 @@ static unsigned int bus_num; * Structure to handle image related parameters. */ typedef struct { - void __iomem *kern_buf; /* Buffer address in kernel space */ + void *kern_buf; /* Buffer address in kernel space */ dma_addr_t pci_buf; /* Buffer address in PCI address space */ unsigned long long size_buf; /* Buffer size */ struct semaphore sem; /* Semaphore for locking image */ @@ -277,7 +277,7 @@ static ssize_t resource_from_user(unsigned int minor, const char *buf, static ssize_t buffer_to_user(unsigned int minor, char __user *buf, size_t count, loff_t *ppos) { - void __iomem *image_ptr; + void *image_ptr; ssize_t retval; image_ptr = image[minor].kern_buf + *ppos; @@ -296,7 +296,7 @@ static ssize_t buffer_to_user(unsigned int minor, char __user *buf, static ssize_t buffer_from_user(unsigned int minor, const char *buf, size_t count, loff_t *ppos) { - void __iomem *image_ptr; + void *image_ptr; size_t retval; image_ptr = image[minor].kern_buf + *ppos; -- cgit v1.2.3 From 1a85f2073d99080ea70962f767edca479c768b6e Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:34 +0000 Subject: staging: vme_user: mark user-space buffers with __user Signed-off-by: Emilio G. Cota [martyn.welch@ge.com: modified to remove checkpatch warnings] Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 5d3a39bcd2a8..36381489b797 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -129,8 +129,9 @@ static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR, static int vme_user_open(struct inode *, struct file *); static int vme_user_release(struct inode *, struct file *); -static ssize_t vme_user_read(struct file *, char *, size_t, loff_t *); -static ssize_t vme_user_write(struct file *, const char *, size_t, loff_t *); +static ssize_t vme_user_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t vme_user_write(struct file *, const char __user *, size_t, + loff_t *); static loff_t vme_user_llseek(struct file *, loff_t, int); static long vme_user_unlocked_ioctl(struct file *, unsigned int, unsigned long); @@ -246,7 +247,7 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, * page) transfers will lock the user space buffer into memory and then * transfer the data directly from the user space buffers out to VME. */ -static ssize_t resource_from_user(unsigned int minor, const char *buf, +static ssize_t resource_from_user(unsigned int minor, const char __user *buf, size_t count, loff_t *ppos) { ssize_t retval; @@ -293,7 +294,7 @@ static ssize_t buffer_to_user(unsigned int minor, char __user *buf, return retval; } -static ssize_t buffer_from_user(unsigned int minor, const char *buf, +static ssize_t buffer_from_user(unsigned int minor, const char __user *buf, size_t count, loff_t *ppos) { void *image_ptr; @@ -312,7 +313,7 @@ static ssize_t buffer_from_user(unsigned int minor, const char *buf, return retval; } -static ssize_t vme_user_read(struct file *file, char *buf, size_t count, +static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); @@ -356,8 +357,8 @@ static ssize_t vme_user_read(struct file *file, char *buf, size_t count, return retval; } -static ssize_t vme_user_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) +static ssize_t vme_user_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); ssize_t retval; @@ -455,6 +456,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, unsigned int minor = MINOR(inode->i_rdev); int retval; dma_addr_t pci_addr; + void __user *argp = (void __user *)arg; statistics.ioctls++; @@ -474,7 +476,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, &master.size, &master.aspace, &master.cycle, &master.dwidth); - copied = copy_to_user((char *)arg, &master, + copied = copy_to_user(argp, &master, sizeof(struct vme_master)); if (copied != 0) { printk(KERN_WARNING "Partial copy to " @@ -487,8 +489,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, case VME_SET_MASTER: - copied = copy_from_user(&master, (char *)arg, - sizeof(master)); + copied = copy_from_user(&master, argp, sizeof(master)); if (copied != 0) { printk(KERN_WARNING "Partial copy from " "userspace\n"); @@ -518,7 +519,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, &slave.size, &pci_addr, &slave.aspace, &slave.cycle); - copied = copy_to_user((char *)arg, &slave, + copied = copy_to_user(argp, &slave, sizeof(struct vme_slave)); if (copied != 0) { printk(KERN_WARNING "Partial copy to " @@ -531,8 +532,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, case VME_SET_SLAVE: - copied = copy_from_user(&slave, (char *)arg, - sizeof(slave)); + copied = copy_from_user(&slave, argp, sizeof(slave)); if (copied != 0) { printk(KERN_WARNING "Partial copy from " "userspace\n"); -- cgit v1.2.3 From 0599726793d6dca6bd171cd4e497f9aac21e8f0c Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:40 +0000 Subject: staging: vme: mark struct vme_master_resource's base address pointer as __iomem Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/vme_bridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h index b653ec02e1fc..4c6ec31b01db 100644 --- a/drivers/staging/vme/vme_bridge.h +++ b/drivers/staging/vme/vme_bridge.h @@ -20,7 +20,7 @@ struct vme_master_resource { vme_cycle_t cycle_attr; vme_width_t width_attr; struct resource bus_resource; - void *kern_base; + void __iomem *kern_base; }; struct vme_slave_resource { -- cgit v1.2.3 From e20cbcf199e2c3e4a4822e890726c49b70a4d280 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:47 +0000 Subject: staging: vme: tsi148: mark the registers' base address pointer as __iomem Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_tsi148.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/staging/vme/bridges/vme_tsi148.h index bda64ef85754..9f97fa8084e8 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.h +++ b/drivers/staging/vme/bridges/vme_tsi148.h @@ -35,7 +35,7 @@ /* Structure used to hold driver specific information */ struct tsi148_driver { - void *base; /* Base Address of device registers */ + void __iomem *base; /* Base Address of device registers */ wait_queue_head_t dma_queue[2]; wait_queue_head_t iack_queue; void (*lm_callback[4])(int); /* Called in interrupt handler */ -- cgit v1.2.3 From e08e02faff68d33c938fd0322c0f8318a25ddb39 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 12 Nov 2010 11:15:54 +0000 Subject: staging: vme: ca91cx42: mark the registers' base address pointer as __iomem Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_ca91cx42.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/staging/vme/bridges/vme_ca91cx42.h index e72c65b193ec..02a7c794db05 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.h +++ b/drivers/staging/vme/bridges/vme_ca91cx42.h @@ -39,7 +39,7 @@ /* Structure used to hold driver specific information */ struct ca91cx42_driver { - void *base; /* Base Address of device registers */ + void __iomem *base; /* Base Address of device registers */ wait_queue_head_t dma_queue; wait_queue_head_t iack_queue; wait_queue_head_t mbox_queue; -- cgit v1.2.3 From f96c377ead5ed308f0cf18b9156f86fdf207a288 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Sat, 13 Nov 2010 19:43:27 +0100 Subject: staging: comedi: fix typo in error message Fix typo in error message of dux commands allocation. Signed-off-by: Nicolas Kaiser Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbdux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 1f177a67ff11..aca4d140193b 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -2398,7 +2398,7 @@ static int usbduxsub_probe(struct usb_interface *uinterf, usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); if (!usbduxsub[index].dux_commands) { dev_err(dev, "comedi_: usbdux: " - "error alloc space for dac commands\n"); + "error alloc space for dux commands\n"); tidy_up(&(usbduxsub[index])); up(&start_stop_sem); return -ENOMEM; -- cgit v1.2.3 From baebc160c12ba88baf201d35ecc22f1e250aad3f Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 12 Nov 2010 15:28:30 -0800 Subject: staging: brcm80211: simplify pci_config_read/write osl routines. Start simplifying osl with goal of purging it entirely. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/util/linux_osl.c | 47 ++++-------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 7211f8a383ff..461ecbaf8214 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -30,8 +30,6 @@ #include -#define PCI_CFG_RETRY 10 - #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */ #define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ @@ -139,51 +137,16 @@ void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send) u32 osl_pci_read_config(osl_t *osh, uint offset, uint size) { - uint val = 0; - uint retry = PCI_CFG_RETRY; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - /* only 4byte access supported */ - ASSERT(size == 4); - - do { - pci_read_config_dword(osh->pdev, offset, &val); - if (val != 0xffffffff) - break; - } while (retry--); - -#ifdef BCMDBG - if (retry < PCI_CFG_RETRY) - printk("PCI CONFIG READ access to %d required %d retries\n", - offset, (PCI_CFG_RETRY - retry)); -#endif /* BCMDBG */ - + uint val; + pci_read_config_dword(osh->pdev, offset, &val); return val; } void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) { - uint retry = PCI_CFG_RETRY; - - ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); - - /* only 4byte access supported */ - ASSERT(size == 4); - - do { - pci_write_config_dword(osh->pdev, offset, val); - if (offset != PCI_BAR0_WIN) - break; - if (osl_pci_read_config(osh, offset, size) == val) - break; - } while (retry--); - -#if defined(BCMDBG) && !defined(BRCM_FULLMAC) - if (retry < PCI_CFG_RETRY) - printk("PCI CONFIG WRITE access to %d required %d retries\n", - offset, (PCI_CFG_RETRY - retry)); -#endif /* BCMDBG */ + pci_write_config_dword(osh->pdev, offset, val); + if (offset == PCI_BAR0_WIN) + ASSERT(osl_pci_read_config(osh, offset, size) == val); } /* return bus # for the pci device pointed by osh->pdev */ -- cgit v1.2.3 From a1dc08b7d95817faea5e6a358e22c6185b84163a Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 12 Nov 2010 18:10:17 -0800 Subject: staging: brcm80211: get rid of last bit of pci configspace workaround. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/util/linux_osl.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 461ecbaf8214..625cbacc8665 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -145,8 +145,6 @@ u32 osl_pci_read_config(osl_t *osh, uint offset, uint size) void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) { pci_write_config_dword(osh->pdev, offset, val); - if (offset == PCI_BAR0_WIN) - ASSERT(osl_pci_read_config(osh, offset, size) == val); } /* return bus # for the pci device pointed by osh->pdev */ -- cgit v1.2.3 From 5b93a8b8e0514ebacb49a50c67a8846139bcd1bd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 14 Nov 2010 13:36:21 +0200 Subject: staging: brcm80211: remove unused osl_pkt{get,free}_static Signed-off-by: Mike Rapoport Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 586e652e75c7..0fb6e1c86793 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -291,9 +291,6 @@ extern void *osl_pktget(osl_t *osh, uint len); extern void osl_pktfree(osl_t *osh, void *skb, bool send); #ifdef BRCM_FULLMAC -extern void *osl_pktget_static(osl_t *osh, uint len); -extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); - static inline void * osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb) { -- cgit v1.2.3 From ae0d9ebaffe47ed553e715ab5243660c33b6338c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 14 Nov 2010 13:36:23 +0200 Subject: staging: brcm80211: brcmfmac: remove PXA SDIO controller binding Signed-off-by: Mike Rapoport Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index be33696b8f74..b021d97e59fa 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -137,17 +137,6 @@ static int __devinit bcmsdh_probe(struct device *dev); static int __devexit bcmsdh_remove(struct device *dev); #endif /* BCMLXSDMMC */ -#ifndef BCMLXSDMMC -static struct device_driver bcmsdh_driver = { - .name = "pxa2xx-mci", - .bus = &platform_bus_type, - .probe = bcmsdh_probe, - .remove = bcmsdh_remove, - .suspend = NULL, - .resume = NULL, -}; -#endif /* BCMLXSDMMC */ - #ifndef BCMLXSDMMC static #endif /* BCMLXSDMMC */ @@ -522,9 +511,6 @@ int bcmsdh_register(bcmsdh_driver_t *driver) #if defined(BCMLXSDMMC) SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n")); error = sdio_function_init(); -#else - SDLX_MSG(("Intel PXA270 SDIO Driver\n")); - error = driver_register(&bcmsdh_driver); #endif /* defined(BCMLXSDMMC) */ return error; #endif /* defined(BCMPLATFORM_BUS) */ @@ -544,9 +530,6 @@ extern void sdio_function_cleanup(void); void bcmsdh_unregister(void) { -#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) - driver_unregister(&bcmsdh_driver); -#endif #if defined(BCMLXSDMMC) sdio_function_cleanup(); #endif /* BCMLXSDMMC */ -- cgit v1.2.3 From 859171ca92f2865453b4b2e17bf679c67044a833 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 19:04:48 -0800 Subject: drivers/staging: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c | 2 +- drivers/staging/ath6kl/os/linux/ar6000_drv.c | 2 +- drivers/staging/bcm/InterfaceInit.c | 2 +- drivers/staging/bcm/InterfaceIsr.c | 2 +- drivers/staging/bcm/Misc.c | 4 ++-- drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c | 2 +- drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c | 2 +- drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c | 2 +- drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c | 2 +- drivers/staging/comedi/drivers/amplc_pci230.c | 2 +- drivers/staging/comedi/drivers/cb_das16_cs.c | 2 +- drivers/staging/comedi/drivers/comedi_bond.c | 2 +- drivers/staging/crystalhd/crystalhd_hw.c | 2 +- drivers/staging/go7007/go7007-driver.c | 2 +- drivers/staging/iio/accel/lis3l02dq_ring.c | 2 +- drivers/staging/intel_sst/intel_sst_drv_interface.c | 4 ++-- drivers/staging/keucr/smilmain.c | 4 ++-- drivers/staging/keucr/smilsub.c | 4 ++-- drivers/staging/msm/lcdc_toshiba_wvga_pt.c | 2 +- drivers/staging/rt2860/common/cmm_data_pci.c | 4 ++-- drivers/staging/rt2860/rt_linux.c | 2 +- drivers/staging/rt2860/rtmp.h | 2 +- drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8192e/r819xE_phy.c | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8192u/r8192U_core.c | 2 +- drivers/staging/rtl8192u/r819xU_phy.c | 2 +- drivers/staging/rtl8712/rtl8712_efuse.c | 2 +- drivers/staging/rtl8712/rtl8712_xmit.c | 2 +- drivers/staging/rtl8712/rtl871x_xmit.c | 2 +- drivers/staging/tidspbridge/core/tiomap3430.c | 4 ++-- drivers/staging/tidspbridge/rmgr/nldr.c | 2 +- drivers/staging/vt6655/card.c | 2 +- drivers/staging/vt6655/iwctl.c | 2 +- drivers/staging/vt6655/wpa2.c | 4 ++-- drivers/staging/vt6656/baseband.c | 2 +- drivers/staging/vt6656/iwctl.c | 2 +- drivers/staging/vt6656/power.c | 2 +- drivers/staging/vt6656/wpa2.c | 4 ++-- 39 files changed, 47 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c index 6454a86c174c..e96662b84ed9 100644 --- a/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c +++ b/drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c @@ -876,7 +876,7 @@ HIFAckInterrupt(HIF_DEVICE *device) void HIFUnMaskInterrupt(HIF_DEVICE *device) { - int ret;; + int ret; AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->func != NULL); diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c index a659f7047373..126a36a2daa6 100644 --- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c +++ b/drivers/staging/ath6kl/os/linux/ar6000_drv.c @@ -4439,7 +4439,7 @@ skip_key: for (i = assoc_req_ie_pos; i < assoc_req_ie_pos + assocReqLen - 4; i++) { AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("%2.2x ", assocInfo[i])); sprintf(pos, "%2.2x", assocInfo[i]); - pos += 2;; + pos += 2; } AR_DEBUG_PRINTF(ATH_DEBUG_WLAN_CONNECT,("\n")); diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 869ebabfba77..7ffbfecaa117 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -236,7 +236,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) uint32_t uiNackZeroLengthInt=4; if(wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt))) { - return -EIO;; + return -EIO; } } diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c index 423464765e59..220ff922bdcf 100644 --- a/drivers/staging/bcm/InterfaceIsr.c +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -90,7 +90,7 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt IN endPoint has got halted/stalled...need to clear this"); Adapter->bEndPointHalted = TRUE ; wake_up(&Adapter->tx_packet_wait_queue); - urb->status = STATUS_SUCCESS ;; + urb->status = STATUS_SUCCESS ; return; } /* software-driven interface shutdown */ diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 1bb6a1d97ce0..023c511c0001 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -706,7 +706,7 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter) /* Wake the LED Thread with IDLEMODE_ENTER State */ Adapter->DriverState = LOWPOWER_MODE_ENTER; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"LED Thread is Running..Hence Setting LED Event as IDLEMODE_ENTER jiffies:%ld",jiffies);; + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,"LED Thread is Running..Hence Setting LED Event as IDLEMODE_ENTER jiffies:%ld",jiffies); wake_up(&Adapter->LEDInfo.notify_led_event); /* Wait for 1 SEC for LED to OFF */ @@ -1277,7 +1277,7 @@ static int bcm_parse_target_params(PMINI_ADAPTER Adapter) void beceem_parse_target_struct(PMINI_ADAPTER Adapter) { - UINT uiHostDrvrCfg6 =0, uiEEPROMFlag = 0;; + UINT uiHostDrvrCfg6 =0, uiEEPROMFlag = 0; if(ntohl(Adapter->pstargetparams->m_u32PhyParameter2) & AUTO_SYNC_DISABLE) { diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c index 7361d508bf37..0e6affd95962 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c @@ -1008,7 +1008,7 @@ int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, b_ExternGate = (unsigned char) data[3]; b_CycleMode = (unsigned char) data[4]; b_InterruptEnable = (unsigned char) data[5]; - i_ReturnValue = insn->n;; + i_ReturnValue = insn->n; devpriv->tsk_Current = current; /* Save the current process task structure */ /**************************/ /* Test the module number */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 2a8a6c730920..62f421a06f05 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -2850,7 +2850,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) i_Logic = 0; i_CounterLogic = 0; i_InterruptMask = 0; - i_InputChannel = 0;; + i_InputChannel = 0; i_TimerCounter1Enabled = 0; i_TimerCounter2Enabled = 0; i_WatchdogCounter3Enabled = 0; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c index 12fcc35ecc52..8a584a014b0b 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c @@ -335,7 +335,7 @@ int i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subde return -EINVAL; } /* if else data[3]==1) */ } /* if else data[3]==0) */ - return (insn->n);; + return (insn->n); } /* diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index 356a1891e2e7..acaceb01629a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -339,7 +339,7 @@ int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subde int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0;; + unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0; ul_Channel_no = CR_CHAN(insn->chanspec); diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 5d064577b2f1..7edeb1103dc8 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -971,7 +971,7 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (thisboard->ao_chans > 0) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = thisboard->ao_chans;; + s->n_chan = thisboard->ao_chans; s->maxdata = (1 << thisboard->ao_bits) - 1; s->range_table = &pci230_ao_range; s->insn_write = &pci230_ao_winsn; diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 0345b4caba73..bb93685d8b93 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -169,7 +169,7 @@ static int das16cs_attach(struct comedi_device *dev, if (!link) return -EIO; - dev->iobase = link->resource[0]->start;; + dev->iobase = link->resource[0]->start; printk("I/O base=0x%04lx ", dev->iobase); printk("fingerprint:\n"); diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index cfcbd9b8f393..d8aefb23d6b9 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -370,7 +370,7 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS]; memset(devs_opened, 0, sizeof(devs_opened)); - devpriv->name[0] = 0;; + devpriv->name[0] = 0; /* Loop through all comedi devices specified on the command-line, building our device list */ for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) { diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c index f63185790c48..153ddbf4247d 100644 --- a/drivers/staging/crystalhd/crystalhd_hw.c +++ b/drivers/staging/crystalhd/crystalhd_hw.c @@ -1711,7 +1711,7 @@ enum BC_STATUS crystalhd_download_fw(struct crystalhd_adp *adp, void *buffer, ui } BCMLOG(BCMLOG_INFO, "Firmware Downloaded Successfully\n"); - return BC_STS_SUCCESS;; + return BC_STS_SUCCESS; } enum BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw, diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c index b3f42f37a313..8426a02b4bb2 100644 --- a/drivers/staging/go7007/go7007-driver.c +++ b/drivers/staging/go7007/go7007-driver.c @@ -624,7 +624,7 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) go->dvd_mode = 0; go->interlace_coding = 0; for (i = 0; i < 4; ++i) - go->modet[i].enable = 0;; + go->modet[i].enable = 0; for (i = 0; i < 1624; ++i) go->modet_map[i] = 0; go->audio_deliver = NULL; diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 330d5d6dbba4..1fd088a11076 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -517,7 +517,7 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev) ret = iio_alloc_pollfunc(indio_dev, NULL, &lis3l02dq_poll_func_th); if (ret) - goto error_iio_sw_rb_free;; + goto error_iio_sw_rb_free; indio_dev->modes |= INDIO_RING_TRIGGERED; return 0; diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index 5b10ddf60092..1165303eeeb4 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -173,9 +173,9 @@ static int sst_get_sfreq(struct snd_sst_params *str_param) case SST_CODEC_TYPE_MP3: return str_param->sparams.uc.mp3_params.sfreq; case SST_CODEC_TYPE_AAC: - return str_param->sparams.uc.aac_params.sfreq;; + return str_param->sparams.uc.aac_params.sfreq; case SST_CODEC_TYPE_WMA9: - return str_param->sparams.uc.wma_params.sfreq;; + return str_param->sparams.uc.wma_params.sfreq; default: return 0; } diff --git a/drivers/staging/keucr/smilmain.c b/drivers/staging/keucr/smilmain.c index bdfbf76f8df9..2cbe9f897eef 100644 --- a/drivers/staging/keucr/smilmain.c +++ b/drivers/staging/keucr/smilmain.c @@ -153,9 +153,9 @@ int Media_D_ReadSector(struct us_data *us, DWORD start,WORD count,BYTE *buf) WORD len, bn; //if (Check_D_MediaPower()) ; b 6250 don't care - // return(ErrCode); ; + // return(ErrCode); //if (Check_D_MediaFmt(fdoExt)) ; - // return(ErrCode); ; + // return(ErrCode); if (Conv_D_MediaAddr(us, start)) return(ErrCode); diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c index 1b52535a388f..ce10cf215f51 100644 --- a/drivers/staging/keucr/smilsub.c +++ b/drivers/staging/keucr/smilsub.c @@ -763,8 +763,8 @@ int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant) bcb->CDB[7] = (BYTE)addr; bcb->CDB[6] = (BYTE)(addr/0x0100); bcb->CDB[5] = Media.Zone/2; - bcb->CDB[8] = *(redundant+REDT_ADDR1H);; - bcb->CDB[9] = *(redundant+REDT_ADDR1L);; + bcb->CDB[8] = *(redundant+REDT_ADDR1H); + bcb->CDB[9] = *(redundant+REDT_ADDR1L); result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0); if (result != USB_STOR_XFER_GOOD) diff --git a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c index 864d7c18913d..edba78a3afcf 100644 --- a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c +++ b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c @@ -77,7 +77,7 @@ static void toshiba_spi_write(char cmd, uint32 data, int num) /* followed by parameter bytes */ if (num) { - bp = (char *)&data;; + bp = (char *)&data; bp += (num - 1); while (num) { toshiba_spi_write_byte(1, *bp); diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c index 43d73a05c8eb..7af59ff9e220 100644 --- a/drivers/staging/rt2860/common/cmm_data_pci.c +++ b/drivers/staging/rt2860/common/cmm_data_pci.c @@ -137,7 +137,7 @@ u16 RtmpPCI_WriteSingleTxResource(struct rt_rtmp_adapter *pAd, pTxD->SDPtr0 = BufBasePaLow; pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; /* include padding */ - pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; + pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); pTxD->SDLen1 = pTxBlk->SrcBufLen; pTxD->LastSec0 = 0; pTxD->LastSec1 = (bIsLast) ? 1 : 0; @@ -215,7 +215,7 @@ u16 RtmpPCI_WriteMultiTxResource(struct rt_rtmp_adapter *pAd, pTxD->SDPtr0 = BufBasePaLow; pTxD->SDLen0 = firstDMALen; /* include padding */ - pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; + pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); pTxD->SDLen1 = pTxBlk->SrcBufLen; pTxD->LastSec0 = 0; pTxD->LastSec1 = (bIsLast) ? 1 : 0; diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c index e680b0d97f74..0bbd04a71a6a 100644 --- a/drivers/staging/rt2860/rt_linux.c +++ b/drivers/staging/rt2860/rt_linux.c @@ -854,7 +854,7 @@ void send_monitor_packets(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) RSSI1, RSSI_1), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2, - RSSI_2));; + RSSI_2)); ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; ph->signal.status = 0; diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h index caf466242a13..70daaa4f9ac2 100644 --- a/drivers/staging/rt2860/rtmp.h +++ b/drivers/staging/rt2860/rtmp.h @@ -2979,7 +2979,7 @@ void LinkDown(struct rt_rtmp_adapter *pAd, IN BOOLEAN IsReqFromAP); void IterateOnBssTab(struct rt_rtmp_adapter *pAd); -void IterateOnBssTab2(struct rt_rtmp_adapter *pAd);; +void IterateOnBssTab2(struct rt_rtmp_adapter *pAd); void JoinParmFill(struct rt_rtmp_adapter *pAd, struct rt_mlme_join_req *JoinReq, unsigned long BssIdx); diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c index dd8a221e21ae..b26b5a8b5f6b 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c @@ -822,7 +822,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev) { txb->queue_index = UP2AC(skb->priority); } else { - txb->queue_index = WME_AC_BK;; + txb->queue_index = WME_AC_BK; } diff --git a/drivers/staging/rtl8192e/r819xE_phy.c b/drivers/staging/rtl8192e/r819xE_phy.c index d83bcbcb20bd..50cd0e52b921 100644 --- a/drivers/staging/rtl8192e/r819xE_phy.c +++ b/drivers/staging/rtl8192e/r819xE_phy.c @@ -2596,7 +2596,7 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E break; } - return ret;; + return ret; } /****************************************************************************** diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index 81aa2ed226ac..ec7845ecdb7e 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -754,7 +754,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { txb->queue_index = UP2AC(skb->priority); } else { - txb->queue_index = WME_AC_BK;; + txb->queue_index = WME_AC_BK; } diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 4cc7b418c91e..cbfe1341d856 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -5085,7 +5085,7 @@ static void rtl8192_query_rxphystatus( //Get Rx snr value in DB tmp_rxsnr = pofdm_buf->rxsnr_X[i]; rx_snrX = (char)(tmp_rxsnr); - //rx_snrX >>= 1;; + //rx_snrX >>= 1; rx_snrX /= 2; priv->stats.rxSNRdB[i] = (long)rx_snrX; diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c index a3adaedece9a..8e10992366fe 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.c +++ b/drivers/staging/rtl8192u/r819xU_phy.c @@ -1011,7 +1011,7 @@ u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E break; } - return ret;; + return ret; } /****************************************************************************** diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c index 9730ae1c58d5..1dc12b7a2f52 100644 --- a/drivers/staging/rtl8712/rtl8712_efuse.c +++ b/drivers/staging/rtl8712/rtl8712_efuse.c @@ -428,7 +428,7 @@ u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, u16 start_addr, u16 cnts, u8 *data) { int i; - u8 res = true;; + u8 res = true; if (start_addr > EFUSE_MAX_SIZE) return false; diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c index 8edc518536f9..88a15049bc2a 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/drivers/staging/rtl8712/rtl8712_xmit.c @@ -148,7 +148,7 @@ static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe) case 0x11: case 0x12: case 0x13: - addr = RTL8712_DMA_H2CCMD;; + addr = RTL8712_DMA_H2CCMD; break; default: addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c index b8195e3a72d4..75f1a6bba2f6 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.c +++ b/drivers/staging/rtl8712/rtl871x_xmit.c @@ -372,7 +372,7 @@ static sint xmitframe_addmic(struct _adapter *padapter, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; datalen = pattrib->pktlen - pattrib->hdrlen; - pframe = pxmitframe->buf_addr + TXDESC_OFFSET;; + pframe = pxmitframe->buf_addr + TXDESC_OFFSET; if (bmcst) { if (!memcmp(psecuritypriv->XGrptxmickey [psecuritypriv->XGrpKeyid].skey, diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c index 1be081f917a7..a3b0a183d570 100644 --- a/drivers/staging/tidspbridge/core/tiomap3430.c +++ b/drivers/staging/tidspbridge/core/tiomap3430.c @@ -596,7 +596,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, dev_dbg(bridge, "DSP c_int00 Address = 0x%x\n", dsp_addr); if (dsp_debug) while (__raw_readw(dw_sync_addr)) - ;; + ; /* Wait for DSP to clear word in shared memory */ /* Read the Location */ @@ -1671,7 +1671,7 @@ static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va, /* Find a free L2 PT. */ for (i = 0; (i < pt->l2_num_pages) && (pt->pg_info[i].num_entries != 0); i++) - ;; + ; if (i < pt->l2_num_pages) { l2_page_num = i; l2_base_pa = pt->l2_base_pa + (l2_page_num * diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c index a6ae007015d0..28354bbf1aeb 100644 --- a/drivers/staging/tidspbridge/rmgr/nldr.c +++ b/drivers/staging/tidspbridge/rmgr/nldr.c @@ -943,7 +943,7 @@ static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info, /* Determine which phase this section belongs to */ for (pch = sect_name + 1; *pch && *pch != seps; pch++) - ;; + ; if (*pch) { pch++; /* Skip over the ':' */ diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 32d095c4d51c..951a3a8ddcb2 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -2058,7 +2058,7 @@ bool CARDbSoftwareReset (void *pDeviceHandler) QWORD CARDqGetTSFOffset (unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2) { QWORD qwTSFOffset; - unsigned short wRxBcnTSFOffst= 0;; + unsigned short wRxBcnTSFOffst= 0; HIDWORD(qwTSFOffset) = 0; LODWORD(qwTSFOffset) = 0; diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c index 92e33999054b..5e425d1476b8 100644 --- a/drivers/staging/vt6655/iwctl.c +++ b/drivers/staging/vt6655/iwctl.c @@ -2073,7 +2073,7 @@ int iwctl_giwencodeext(struct net_device *dev, struct iw_point *wrq, char *extra) { - return -EOPNOTSUPP;; + return -EOPNOTSUPP; } int iwctl_siwmlme(struct net_device *dev, diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c index 805164bed7e4..744799cfe832 100644 --- a/drivers/staging/vt6655/wpa2.c +++ b/drivers/staging/vt6655/wpa2.c @@ -216,7 +216,7 @@ WPA2vParseRSN ( m = *((unsigned short *) &(pRSN->abyRSN[4])); if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2) - pBSSNode->wAKMSSAuthCount = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));; + pBSSNode->wAKMSSAuthCount = *((unsigned short *) &(pRSN->abyRSN[6+4*m])); j = 0; pbyOUI = &(pRSN->abyRSN[8+4*m]); for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) { @@ -235,7 +235,7 @@ WPA2vParseRSN ( pBSSNode->wAKMSSAuthCount = (unsigned short)j; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount); - n = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));; + n = *((unsigned short *) &(pRSN->abyRSN[6+4*m])); if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2) pBSSNode->sRSNCapObj.bRSNCapExist = true; pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *) &(pRSN->abyRSN[8+4*m+4*n])); diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c index e5add2046375..0d11147f91c1 100644 --- a/drivers/staging/vt6656/baseband.c +++ b/drivers/staging/vt6656/baseband.c @@ -963,7 +963,7 @@ BBvSetAntennaMode (PSDevice pDevice, BYTE byAntennaMode) break; case ANT_RXB: pDevice->byBBRxConf &= 0xFE; - pDevice->byBBRxConf |= 0x02;; + pDevice->byBBRxConf |= 0x02; break; } diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c index 0004be8e3957..2121205a912b 100644 --- a/drivers/staging/vt6656/iwctl.c +++ b/drivers/staging/vt6656/iwctl.c @@ -1883,7 +1883,7 @@ int iwctl_giwencodeext(struct net_device *dev, struct iw_point *wrq, char *extra) { - return -EOPNOTSUPP;; + return -EOPNOTSUPP; } int iwctl_siwmlme(struct net_device *dev, diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c index 0c12fd36d0f9..e8c1b35e8128 100644 --- a/drivers/staging/vt6656/power.c +++ b/drivers/staging/vt6656/power.c @@ -192,7 +192,7 @@ BOOL PSbConsiderPowerDown(void *hDeviceContext, // check if already in Doze mode ControlvReadByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PSCTL, &byData); if ( (byData & PSCTL_PS) != 0 ) - return TRUE;; + return TRUE; if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) { // check if in TIM wake period diff --git a/drivers/staging/vt6656/wpa2.c b/drivers/staging/vt6656/wpa2.c index 6d13190885d1..d4f3f7530ee4 100644 --- a/drivers/staging/vt6656/wpa2.c +++ b/drivers/staging/vt6656/wpa2.c @@ -215,7 +215,7 @@ WPA2vParseRSN ( m = *((PWORD) &(pRSN->abyRSN[4])); if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2) - pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m]));; + pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m])); j = 0; pbyOUI = &(pRSN->abyRSN[8+4*m]); for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(BYTE)); i++) { @@ -234,7 +234,7 @@ WPA2vParseRSN ( pBSSNode->wAKMSSAuthCount = (WORD)j; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount); - n = *((PWORD) &(pRSN->abyRSN[6+4*m]));; + n = *((PWORD) &(pRSN->abyRSN[6+4*m])); if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2) pBSSNode->sRSNCapObj.bRSNCapExist = TRUE; pBSSNode->sRSNCapObj.wRSNCap = *((PWORD) &(pRSN->abyRSN[8+4*m+4*n])); -- cgit v1.2.3 From 345594d6ef696b8ad4b96cffe462c6cde2f27292 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 15 Nov 2010 12:14:00 -0800 Subject: drivers/staging: Remove unnecessary casts of pci_get_drvdata Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/staging/crystalhd/crystalhd_lnx.c | 6 +++--- drivers/staging/et131x/et131x_initpci.c | 2 +- drivers/staging/wlags49_h2/wl_pci.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c index 28c6b8ced424..719e70bc871e 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.c +++ b/drivers/staging/crystalhd/crystalhd_lnx.c @@ -516,7 +516,7 @@ static void __devexit chd_dec_pci_remove(struct pci_dev *pdev) BCMLOG_ENTER; - pinfo = (struct crystalhd_adp *) pci_get_drvdata(pdev); + pinfo = pci_get_drvdata(pdev); if (!pinfo) { BCMLOG_ERR("could not get adp\n"); return; @@ -626,7 +626,7 @@ int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state) struct crystalhd_ioctl_data *temp; enum BC_STATUS sts = BC_STS_SUCCESS; - adp = (struct crystalhd_adp *)pci_get_drvdata(pdev); + adp = pci_get_drvdata(pdev); if (!adp) { BCMLOG_ERR("could not get adp\n"); return -ENODEV; @@ -660,7 +660,7 @@ int chd_dec_pci_resume(struct pci_dev *pdev) enum BC_STATUS sts = BC_STS_SUCCESS; int rc; - adp = (struct crystalhd_adp *)pci_get_drvdata(pdev); + adp = pci_get_drvdata(pdev); if (!adp) { BCMLOG_ERR("could not get adp\n"); return -ENODEV; diff --git a/drivers/staging/et131x/et131x_initpci.c b/drivers/staging/et131x/et131x_initpci.c index 10bcb45d73a3..f62ba7a68f34 100644 --- a/drivers/staging/et131x/et131x_initpci.c +++ b/drivers/staging/et131x/et131x_initpci.c @@ -783,7 +783,7 @@ static void __devexit et131x_pci_remove(struct pci_dev *pdev) /* Retrieve the net_device pointer from the pci_dev struct, as well * as the private adapter struct */ - netdev = (struct net_device *) pci_get_drvdata(pdev); + netdev = pci_get_drvdata(pdev); adapter = netdev_priv(netdev); /* Perform device cleanup */ diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c index 020b17adee2d..28ae9dd1b44e 100644 --- a/drivers/staging/wlags49_h2/wl_pci.c +++ b/drivers/staging/wlags49_h2/wl_pci.c @@ -458,7 +458,7 @@ void __devexit wl_pci_remove(struct pci_dev *pdev) return; } - dev = (struct net_device *)pci_get_drvdata( pdev ); + dev = pci_get_drvdata( pdev ); if( dev == NULL ) { DBG_ERROR( DbgInfo, "Could not retrieve net_device structure\n" ); return; -- cgit v1.2.3 From e33196e108197e4a1f1a5331dc7740ad9263f4f5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 15 Nov 2010 13:12:32 -0800 Subject: drivers/staging: Remove unnecessary casts of netdev_priv Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c | 54 +++++++++++----------- drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c | 8 ++-- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 8 ++-- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 16 +++---- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 6 +-- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 2 +- drivers/staging/rtl8712/usb_intf.c | 2 +- 7 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c index eed7e94308db..588afd5a5ddb 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c @@ -132,7 +132,7 @@ inline void ft1000_asic_write(struct net_device *dev, u16 offset, u16 value) //--------------------------------------------------------------------------- static inline u16 ft1000_read_fifo_len(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); if (info->AsicID == ELECTRABUZZ_ID) { return (ft1000_read_reg(dev, FT1000_REG_UFIFO_STAT) - 16); @@ -155,7 +155,7 @@ static inline u16 ft1000_read_fifo_len(struct net_device *dev) //--------------------------------------------------------------------------- u16 ft1000_read_dpram(struct net_device * dev, int offset) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); unsigned long flags; u16 data; @@ -184,7 +184,7 @@ u16 ft1000_read_dpram(struct net_device * dev, int offset) static inline void ft1000_write_dpram(struct net_device *dev, int offset, u16 value) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); unsigned long flags; // Provide mutual exclusive access while reading ASIC registers. @@ -208,7 +208,7 @@ static inline void ft1000_write_dpram(struct net_device *dev, //--------------------------------------------------------------------------- u16 ft1000_read_dpram_mag_16(struct net_device *dev, int offset, int Index) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); unsigned long flags; u16 data; @@ -242,7 +242,7 @@ u16 ft1000_read_dpram_mag_16(struct net_device *dev, int offset, int Index) static inline void ft1000_write_dpram_mag_16(struct net_device *dev, int offset, u16 value, int Index) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); unsigned long flags; // Provide mutual exclusive access while reading ASIC registers. @@ -270,7 +270,7 @@ static inline void ft1000_write_dpram_mag_16(struct net_device *dev, //--------------------------------------------------------------------------- u32 ft1000_read_dpram_mag_32(struct net_device *dev, int offset) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); unsigned long flags; u32 data; @@ -298,7 +298,7 @@ u32 ft1000_read_dpram_mag_32(struct net_device *dev, int offset) //--------------------------------------------------------------------------- void ft1000_write_dpram_mag_32(struct net_device *dev, int offset, u32 value) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); unsigned long flags; // Provide mutual exclusive access while reading ASIC registers. @@ -320,7 +320,7 @@ void ft1000_write_dpram_mag_32(struct net_device *dev, int offset, u32 value) //--------------------------------------------------------------------------- static void ft1000_enable_interrupts(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 tempword; DEBUG(1, "ft1000_hw:ft1000_enable_interrupts()\n"); @@ -345,7 +345,7 @@ static void ft1000_enable_interrupts(struct net_device *dev) //--------------------------------------------------------------------------- static void ft1000_disable_interrupts(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 tempword; DEBUG(1, "ft1000_hw: ft1000_disable_interrupts()\n"); @@ -370,7 +370,7 @@ static void ft1000_disable_interrupts(struct net_device *dev) //--------------------------------------------------------------------------- static void ft1000_reset_asic(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 tempword; DEBUG(1, "ft1000_hw:ft1000_reset_asic called\n"); @@ -414,7 +414,7 @@ static void ft1000_reset_asic(struct net_device *dev) //--------------------------------------------------------------------------- static int ft1000_reset_card(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 tempword; int i; unsigned long flags; @@ -618,7 +618,7 @@ static void ft1000_hbchk(u_long data) FT1000_INFO *info; USHORT tempword; - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); if (info->CardReady == 1) { // Perform dsp heartbeat check @@ -831,7 +831,7 @@ static void ft1000_hbchk(u_long data) //--------------------------------------------------------------------------- void ft1000_send_cmd (struct net_device *dev, u16 *ptempbuffer, int size, u16 qtype) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); int i; u16 tempword; unsigned long flags; @@ -916,7 +916,7 @@ void ft1000_send_cmd (struct net_device *dev, u16 *ptempbuffer, int size, u16 qt //--------------------------------------------------------------------------- BOOLEAN ft1000_receive_cmd(struct net_device *dev, u16 * pbuffer, int maxsz, u16 *pnxtph) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 size; u16 *ppseudohdr; int i; @@ -1009,7 +1009,7 @@ BOOLEAN ft1000_receive_cmd(struct net_device *dev, u16 * pbuffer, int maxsz, u16 //--------------------------------------------------------------------------- void ft1000_proc_drvmsg(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 msgtype; u16 tempword; PMEDIAMSG pmediamsg; @@ -1292,7 +1292,7 @@ void ft1000_proc_drvmsg(struct net_device *dev) //--------------------------------------------------------------------------- int ft1000_parse_dpram_msg(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 doorbell; u16 portid; u16 nxtph; @@ -1449,7 +1449,7 @@ int ft1000_parse_dpram_msg(struct net_device *dev) //--------------------------------------------------------------------------- static void ft1000_flush_fifo(struct net_device *dev, u16 DrvErrNum) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 i; u32 templong; u16 tempword; @@ -1596,7 +1596,7 @@ static void ft1000_flush_fifo(struct net_device *dev, u16 DrvErrNum) int ft1000_copy_up_pkt(struct net_device *dev) { u16 tempword; - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 len; struct sk_buff *skb; u16 i; @@ -1783,7 +1783,7 @@ int ft1000_copy_up_pkt(struct net_device *dev) //--------------------------------------------------------------------------- int ft1000_copy_down_pkt(struct net_device *dev, u16 * packet, u16 len) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); union { PSEUDO_HDR blk; u16 buff[sizeof(PSEUDO_HDR) >> 1]; @@ -1943,7 +1943,7 @@ int ft1000_copy_down_pkt(struct net_device *dev, u16 * packet, u16 len) static struct net_device_stats *ft1000_stats(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); return (&info->stats); } @@ -1967,7 +1967,7 @@ static int ft1000_open(struct net_device *dev) static int ft1000_close(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); DEBUG(0, "ft1000_hw: ft1000_close()\n"); @@ -1989,7 +1989,7 @@ static int ft1000_close(struct net_device *dev) static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u8 *pdata; DEBUG(1, "ft1000_hw: ft1000_start_xmit()\n"); @@ -2026,7 +2026,7 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev) static irqreturn_t ft1000_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); u16 tempword; u16 inttype; int cnt; @@ -2091,7 +2091,7 @@ static irqreturn_t ft1000_interrupt(int irq, void *dev_id) void stop_ft1000_card(struct net_device *dev) { - FT1000_INFO *info = (FT1000_INFO *) netdev_priv(dev); + FT1000_INFO *info = netdev_priv(dev); PPROV_RECORD ptr; // int cnt; @@ -2127,7 +2127,7 @@ static void ft1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { FT1000_INFO *ft_info; - ft_info = (FT1000_INFO *) netdev_priv(dev); + ft_info = netdev_priv(dev); snprintf(info->driver, 32, "ft1000"); snprintf(info->bus_info, ETHTOOL_BUSINFO_LEN, "PCMCIA 0x%lx", @@ -2139,7 +2139,7 @@ static void ft1000_get_drvinfo(struct net_device *dev, static u32 ft1000_get_link(struct net_device *dev) { FT1000_INFO *info; - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); return info->mediastate; } @@ -2185,7 +2185,7 @@ struct net_device *init_ft1000_card(unsigned short irq, int port, } SET_NETDEV_DEV(dev, fdev); - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); memset(info, 0, sizeof(FT1000_INFO)); diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c index b45de9bc1b20..935608e72007 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c @@ -65,7 +65,7 @@ int ft1000ReadProc(char *page, char **start, off_t off, time_t delta; dev = (struct net_device *)data; - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); if (off > 0) { *eof = 1; @@ -174,7 +174,7 @@ static int ft1000NotifyProc(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; FT1000_INFO *info; - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); switch (event) { case NETDEV_CHANGENAME: @@ -195,7 +195,7 @@ void ft1000InitProc(struct net_device *dev) { FT1000_INFO *info; - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); info->proc_ft1000 = proc_mkdir(FT1000_PROC, init_net.proc_net); create_proc_read_entry(dev->name, 0644, info->proc_ft1000, @@ -208,7 +208,7 @@ void ft1000CleanupProc(struct net_device *dev) { FT1000_INFO *info; - info = (FT1000_INFO *) netdev_priv(dev); + info = netdev_priv(dev); remove_proc_entry(dev->name, info->proc_ft1000); remove_proc_entry(FT1000_PROC, init_net.proc_net); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 18c4c15c5aea..7b4963326e8c 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -423,7 +423,7 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File) if ( pdevobj[num] != NULL ) //info = (struct ft1000_info *)(pdevobj[num]->net->priv); - info = (struct ft1000_info *)netdev_priv(pdevobj[num]->net); + info = netdev_priv(pdevobj[num]->net); else { DEBUG("ft1000_ChOpen: can not find device object %d\n", num); @@ -488,7 +488,7 @@ static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait) return (-EBADF); } - info = (struct ft1000_info *) netdev_priv(dev); + info = netdev_priv(dev); // Search for matching file object for (i=0; iprivate_data; - info = (struct ft1000_info *) netdev_priv(dev); + info = netdev_priv(dev); ft1000dev = info->pFt1000Dev; cmd = _IOC_NR(Command); //DEBUG("FT1000:ft1000_ChIoctl:cmd = 0x%x\n", cmd); @@ -900,7 +900,7 @@ static int ft1000_ChRelease (struct inode *Inode, struct file *File) DEBUG("ft1000_ChRelease called\n"); dev = File->private_data; - info = (struct ft1000_info *) netdev_priv(dev); + info = netdev_priv(dev); if (ft1000_flarion_cnt == 0) { info->appcnt--; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index b41884e60d07..1ca01e2ea361 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -786,7 +786,7 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev) return -ENOMEM; } - pInfo = (struct ft1000_info *) netdev_priv(netdev); + pInfo = netdev_priv(netdev); //DEBUG("init_ft1000_netdev: gFt1000Info=%x, netdev=%x, ft1000dev=%x\n", gFt1000Info, netdev, ft1000dev); @@ -1345,7 +1345,7 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info) //--------------------------------------------------------------------------- static int ft1000_open (struct net_device *dev) { - struct ft1000_info *pInfo = (struct ft1000_info *)netdev_priv(dev); + struct ft1000_info *pInfo = netdev_priv(dev); struct timeval tv; //mbelian int ret; @@ -1386,7 +1386,7 @@ static int ft1000_open (struct net_device *dev) //--------------------------------------------------------------------------- int ft1000_close(struct net_device *net) { - struct ft1000_info *pInfo = (struct ft1000_info *) netdev_priv(net); + struct ft1000_info *pInfo = netdev_priv(net); struct ft1000_device *ft1000dev = pInfo->pFt1000Dev; //DEBUG ("ft1000_close: netdev->refcnt=%d\n", net->refcnt); @@ -1409,7 +1409,7 @@ int ft1000_close(struct net_device *net) static struct net_device_stats *ft1000_netdev_stats(struct net_device *dev) { - struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev); + struct ft1000_info *info = netdev_priv(dev); return &(info->stats); //mbelian } @@ -1435,7 +1435,7 @@ Jim static int ft1000_chkcard (struct ft1000_device *dev) { u16 tempword; u16 status; - struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net); + struct ft1000_info *info = netdev_priv(dev->net); if (info->fCondResetPend) { @@ -1535,7 +1535,7 @@ static bool ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int max static int ft1000_dsp_prov(void *arg) { struct ft1000_device *dev = (struct ft1000_device *)arg; - struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net); + struct ft1000_info *info = netdev_priv(dev->net); u16 tempword; u16 len; u16 i=0; @@ -1618,7 +1618,7 @@ static int ft1000_dsp_prov(void *arg) static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) { - struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net); + struct ft1000_info *info = netdev_priv(dev->net); u16 msgtype; u16 tempword; struct media_msg *pmediamsg; @@ -1901,7 +1901,7 @@ out: int ft1000_poll(void* dev_id) { struct ft1000_device *dev = (struct ft1000_device *)dev_id; - struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev->net); + struct ft1000_info *info = netdev_priv(dev->net); u16 tempword; u16 status; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index f665640058ae..105846d104ff 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -65,7 +65,7 @@ ft1000ReadProc (char *page, char **start, off_t off, int count, int *eof, time_t delta; dev = (struct net_device *) data; - info = (struct ft1000_info *) netdev_priv(dev); + info = netdev_priv(dev); if (off > 0) { @@ -172,7 +172,7 @@ ft1000NotifyProc (struct notifier_block *this, unsigned long event, void *ptr) struct ft1000_info *info; struct proc_dir_entry *ft1000_proc_file; -info = (struct ft1000_info *) netdev_priv(dev); +info = netdev_priv(dev); switch (event) @@ -198,7 +198,7 @@ ft1000InitProc (struct net_device *dev) { struct ft1000_info *info; struct proc_dir_entry *ft1000_proc_file; - info = (struct ft1000_info *) netdev_priv(dev); + info = netdev_priv(dev); info->ft1000_proc_dir = proc_mkdir (FT1000_PROC_DIR, FTNET_PROC); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 6925622795a5..1369f06cb0df 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -163,7 +163,7 @@ static int ft1000_probe(struct usb_interface *interface, if (ret) goto err_load; - pft1000info = (struct ft1000_info *) netdev_priv(ft1000dev->net); + pft1000info = netdev_priv(ft1000dev->net); DEBUG("In probe: pft1000info=%p\n", pft1000info); ret = dsp_reload(ft1000dev); diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index f1f0c63e5bbc..a692ee88b9e9 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -527,7 +527,7 @@ error: static void r871xu_dev_remove(struct usb_interface *pusb_intf) { struct net_device *pnetdev = usb_get_intfdata(pusb_intf); - struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev); + struct _adapter *padapter = netdev_priv(pnetdev); struct usb_device *udev = interface_to_usbdev(pusb_intf); if (padapter) { -- cgit v1.2.3 From 0ff36f69bd3e7846557880fe934dd0cdeee6a29e Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Mon, 15 Nov 2010 11:55:33 -0800 Subject: staging: hv: add explanation of no-op set_multicast_list I was going to remove netvsc_set_multicast_list() so I think it is worth adding a comment since it isn't immediately clear why you would want this. Signed-off-by: Brandon Philips Acked-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 141535295a41..f527e5f24f56 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -66,6 +66,9 @@ MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); /* The one and only one */ static struct netvsc_driver_context g_netvsc_drv; +/* no-op so the netdev core doesn't return -EINVAL when modifying the the + * multicast address list in SIOCADDMULTI. hv is setup to get all multicast + * when it calls RndisFilterOnOpen() */ static void netvsc_set_multicast_list(struct net_device *net) { } -- cgit v1.2.3 From defc19cebc7f700cb05226f0c4496b9d50c84643 Mon Sep 17 00:00:00 2001 From: Tushar Mehta Date: Tue, 16 Nov 2010 12:13:50 +0530 Subject: Staging: autofs: fix coding style issue in dirhash.c This is a patch to the dirhash.c file that fixes up a number of issues found by the checkpatch.pl tool Signed-off-by: Tushar Mehta Signed-off-by: Greg Kroah-Hartman --- drivers/staging/autofs/dirhash.c | 87 ++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/autofs/dirhash.c b/drivers/staging/autofs/dirhash.c index 8f3e2b816129..d3f42c8325f7 100644 --- a/drivers/staging/autofs/dirhash.c +++ b/drivers/staging/autofs/dirhash.c @@ -30,7 +30,7 @@ void autofs_update_usage(struct autofs_dirhash *dh, struct autofs_dir_ent *ent) { autofs_delete_usage(ent); /* Unlink from current position */ - autofs_init_usage(dh,ent); /* Relink at queue tail */ + autofs_init_usage(dh, ent); /* Relink at queue tail */ } struct autofs_dir_ent *autofs_expire(struct super_block *sb, @@ -45,17 +45,18 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, struct path path; int umount_ok; - if ( list_empty(&dh->expiry_head) || sbi->catatonic ) + if (list_empty(&dh->expiry_head) || sbi->catatonic) return NULL; /* No entries */ /* We keep the list sorted by last_usage and want old stuff */ - ent = list_entry(dh->expiry_head.next, struct autofs_dir_ent, exp); + ent = list_entry(dh->expiry_head.next, + struct autofs_dir_ent, exp); if (jiffies - ent->last_usage < timeout) break; /* Move to end of list in case expiry isn't desirable */ autofs_update_usage(dh, ent); /* Check to see that entry is expirable */ - if ( ent->ino < AUTOFS_FIRST_DIR_INO ) + if (ent->ino < AUTOFS_FIRST_DIR_INO) return ent; /* Symlinks are always expirable */ /* Get the dentry for the autofs subdirectory */ @@ -63,14 +64,15 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, if (!path.dentry) { /* Should only happen in catatonic mode */ - printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name); + printk(KERN_DEBUG "autofs: dentry == NULL but inode \ + range is directory, entry %s\n", ent->name); autofs_delete_usage(ent); continue; } if (!path.dentry->d_inode) { dput(path.dentry); - printk("autofs: negative dentry on expiry queue: %s\n", + printk(KERN_DEBUG "autofs: negative dentry on expiry queue: %s\n", ent->name); autofs_delete_usage(ent); continue; @@ -80,14 +82,16 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, point to the mounted-on-top root. */ if (!S_ISDIR(path.dentry->d_inode->i_mode) || !d_mountpoint(path.dentry)) { - DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); + DPRINTK(("autofs: not expirable \ + (not a mounted directory): %s\n", ent->name)); continue; } path.mnt = mnt; path_get(&path); if (!follow_down(&path)) { path_put(&path); - DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); + DPRINTK(("autofs: not expirable\ + (not a mounted directory): %s\n", ent->name)); continue; } while (d_mountpoint(path.dentry) && follow_down(&path)) @@ -96,30 +100,37 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, path_put(&path); if (umount_ok) { - DPRINTK(("autofs: signaling expire on %s\n", ent->name)); + DPRINTK(("autofs: signaling expire on %s\n", + ent->name)); return ent; /* Expirable! */ } - DPRINTK(("autofs: didn't expire due to may_umount: %s\n", ent->name)); + + DPRINTK(("autofs: didn't expire due to may_umount: %s\n", + ent->name)); } return NULL; /* No expirable entries */ } -void autofs_initialize_hash(struct autofs_dirhash *dh) { +void autofs_initialize_hash(struct autofs_dirhash *dh) +{ memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *)); INIT_LIST_HEAD(&dh->expiry_head); } -struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name) +struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, + struct qstr *name) { struct autofs_dir_ent *dhn; DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", name->hash)); - autofs_say(name->name,name->len); + autofs_say(name->name, name->len); - for ( dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) { - if ( name->hash == dhn->hash && + for (dhn = dh->h[(unsigned) name->hash % AUTOFS_HASH_SIZE]; + dhn; + dhn = dhn->next) { + if (name->hash == dhn->hash && name->len == dhn->len && - !memcmp(name->name, dhn->name, name->len) ) + !memcmp(name->name, dhn->name, name->len)) break; } @@ -131,9 +142,9 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent) struct autofs_dir_ent **dhnp; DPRINTK(("autofs_hash_insert: hash = 0x%08x, name = ", ent->hash)); - autofs_say(ent->name,ent->len); + autofs_say(ent->name, ent->len); - autofs_init_usage(dh,ent); + autofs_init_usage(dh, ent); if (ent->dentry) dget(ent->dentry); @@ -141,19 +152,19 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent) ent->next = *dhnp; ent->back = dhnp; *dhnp = ent; - if ( ent->next ) + if (ent->next) ent->next->back = &(ent->next); } void autofs_hash_delete(struct autofs_dir_ent *ent) { *(ent->back) = ent->next; - if ( ent->next ) + if (ent->next) ent->next->back = ent->back; autofs_delete_usage(ent); - if ( ent->dentry ) + if (ent->dentry) dput(ent->dentry); kfree(ent->name); kfree(ent); @@ -176,37 +187,37 @@ struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, bucket = (*ptr >> 16) - 1; ecount = *ptr & 0xffff; - if ( bucket < 0 ) { + if (bucket < 0) bucket = ecount = 0; - } DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount)); ent = last ? last->next : NULL; - if ( ent ) { + if (ent) { ecount++; } else { - while ( bucket < AUTOFS_HASH_SIZE ) { + while (bucket < AUTOFS_HASH_SIZE) { ent = dh->h[bucket]; - for ( i = ecount ; ent && i ; i-- ) + for (i = ecount ; ent && i ; i--) ent = ent->next; - + if (ent) { ecount++; /* Point to *next* entry */ break; } - + bucket++; ecount = 0; } } #ifdef DEBUG - if ( !ent ) - printk("autofs_hash_enum: nothing found\n"); + if (!ent) + printk(KERN_DEBUG "autofs_hash_enum: nothing found\n"); else { - printk("autofs_hash_enum: found hash %08x, name", ent->hash); - autofs_say(ent->name,ent->len); + printk(KERN_DEBUG "autofs_hash_enum: found hash %08x, name", + ent->hash); + autofs_say(ent->name, ent->len); } #endif @@ -221,9 +232,9 @@ void autofs_hash_dputall(struct autofs_dirhash *dh) int i; struct autofs_dir_ent *ent; - for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) { - for ( ent = dh->h[i] ; ent ; ent = ent->next ) { - if ( ent->dentry ) { + for (i = 0 ; i < AUTOFS_HASH_SIZE ; i++) { + for (ent = dh->h[i] ; ent ; ent = ent->next) { + if (ent->dentry) { dput(ent->dentry); ent->dentry = NULL; } @@ -238,10 +249,10 @@ void autofs_hash_nuke(struct autofs_sb_info *sbi) int i; struct autofs_dir_ent *ent, *nent; - for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) { - for ( ent = sbi->dirhash.h[i] ; ent ; ent = nent ) { + for (i = 0 ; i < AUTOFS_HASH_SIZE ; i++) { + for (ent = sbi->dirhash.h[i] ; ent ; ent = nent) { nent = ent->next; - if ( ent->dentry ) + if (ent->dentry) dput(ent->dentry); kfree(ent->name); kfree(ent); -- cgit v1.2.3 From a65e659d97bc652b2e14a63beaf9efbf5d4e18b2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 12 Nov 2010 14:47:02 -0800 Subject: staging: fix ste_rmi4 build, depends on INPUT The synaptics_i2c_rmi4 driver uses input_*() interfaces, so it should depend on INPUT to fix its build errors: ERROR: "input_event" [drivers/staging/ste_rmi4/synaptics_i2c_rmi4.ko] undefined! ERROR: "input_free_device" [drivers/staging/ste_rmi4/synaptics_i2c_rmi4.ko] undefined! ERROR: "input_register_device" [drivers/staging/ste_rmi4/synaptics_i2c_rmi4.ko] undefined! ERROR: "input_set_abs_params" [drivers/staging/ste_rmi4/synaptics_i2c_rmi4.ko] undefined! ERROR: "input_allocate_device" [drivers/staging/ste_rmi4/synaptics_i2c_rmi4.ko] undefined! ERROR: "input_unregister_device" [drivers/staging/ste_rmi4/synaptics_i2c_rmi4.ko] undefined! Signed-off-by: Randy Dunlap Cc: naveen.gaddipati@stericsson.com, js.ha@stericsson.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ste_rmi4/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ste_rmi4/Kconfig b/drivers/staging/ste_rmi4/Kconfig index 95fd5a915f0a..e8679509e525 100644 --- a/drivers/staging/ste_rmi4/Kconfig +++ b/drivers/staging/ste_rmi4/Kconfig @@ -1,6 +1,6 @@ config TOUCHSCREEN_SYNAPTICS_I2C_RMI4 tristate "Synaptics i2c rmi4 touchscreen" - depends on I2C + depends on I2C && INPUT help Say Y here if you have a Synaptics RMI4 and want to enable support for the built-in touchscreen. -- cgit v1.2.3 From 62af33ec6e73d658720ea1190861c8c0609a94b3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 11 Nov 2010 10:44:22 -0800 Subject: staging/easycap: make module params private/static, fix build The easycap driver has module parameters (bars, gain, & debug) with global scope that intrude on the kernel namespace and cause build problems. Change the names of them to be driver-specific and make 2 of them static. drivers/built-in.o:(.bss+0x97c00): multiple definition of `debug' ld: Warning: size of symbol `debug' changed from 58 in arch/x86/built-in.o to 4 in drivers/built-in.o Signed-off-by: Randy Dunlap Cc: Mike Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/easycap/easycap.h | 4 ++-- drivers/staging/easycap/easycap_debug.h | 4 ++-- drivers/staging/easycap/easycap_low.c | 10 +++++----- drivers/staging/easycap/easycap_main.c | 18 +++++++++--------- 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h index cc8e8c581ae8..ea4259179325 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/easycap/easycap.h @@ -630,13 +630,13 @@ unsigned long long int remainder; #if defined(EASYCAP_DEBUG) #define JOT(n, format, args...) do { \ - if (n <= debug) { \ + if (n <= easycap_debug) { \ printk(KERN_DEBUG "easycap:: %s: " \ format, __func__, ##args);\ } \ } while (0) #define JOM(n, format, args...) do { \ - if (n <= debug) { \ + if (n <= easycap_debug) { \ printk(KERN_DEBUG "easycap::%i%s: " \ format, peasycap->isdongle, __func__, ##args);\ } \ diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h index 518392e0d72d..b6b571843125 100644 --- a/drivers/staging/easycap/easycap_debug.h +++ b/drivers/staging/easycap/easycap_debug.h @@ -24,6 +24,6 @@ * */ /*****************************************************************************/ -extern int debug; -extern int gain; +extern int easycap_debug; +extern int easycap_gain; extern struct easycap_dongle easycap_dongle[]; diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c index b75db82bba73..28c4d1e3c02f 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/easycap/easycap_low.c @@ -1082,11 +1082,11 @@ SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2); * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN. */ /*---------------------------------------------------------------------------*/ -if (31 < gain) - gain = 31; -if (0 > gain) - gain = 0; -if (0 != audio_gainset(pusb_device, (__s8)gain)) +if (31 < easycap_gain) + easycap_gain = 31; +if (0 > easycap_gain) + easycap_gain = 0; +if (0 != audio_gainset(pusb_device, (__s8)easycap_gain)) SAY("ERROR: audio_gainset() failed\n"); check_vt(pusb_device); return 0; diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c index 25e41784f4e5..acc1f56e6f29 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/easycap/easycap_main.c @@ -32,12 +32,12 @@ #include "easycap_standard.h" #include "easycap_ioctl.h" -int debug; -int bars; -int gain = 16; -module_param(debug, int, S_IRUGO | S_IWUSR); -module_param(bars, int, S_IRUGO | S_IWUSR); -module_param(gain, int, S_IRUGO | S_IWUSR); +static int easycap_debug; +static int easycap_bars; +int easycap_gain = 16; +module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR); +module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR); +module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR); /*---------------------------------------------------------------------------*/ /* @@ -1464,7 +1464,7 @@ if (peasycap->field_read == peasycap->field_fill) { easycap_testcard(peasycap, peasycap->field_read); #else if (0 <= input && INPUT_MANY > input) { - if (bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input]) + if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input]) easycap_testcard(peasycap, peasycap->field_read); } #endif /*EASYCAP_TESTCARD*/ @@ -5008,8 +5008,8 @@ easycap_module_init(void) int result; SAY("========easycap=======\n"); -JOT(4, "begins. %i=debug %i=bars %i=gain\n", debug, bars, \ - gain); +JOT(4, "begins. %i=debug %i=bars %i=gain\n", easycap_debug, easycap_bars, \ + easycap_gain); SAY("version: " EASYCAP_DRIVER_VERSION "\n"); /*---------------------------------------------------------------------------*/ /* -- cgit v1.2.3 From a1a26e492c4a90466cb3e064ccf69db4dd66d63a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 13 Nov 2010 11:34:16 +0300 Subject: Staging: cptm1217: move free under dereference We dereference "ts" in the printk so move the kfree() down a line. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/cptm1217/clearpad_tm1217.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c index 269503f9516f..76e4b782d2fb 100644 --- a/drivers/staging/cptm1217/clearpad_tm1217.c +++ b/drivers/staging/cptm1217/clearpad_tm1217.c @@ -460,9 +460,9 @@ static int cp_tm1217_probe(struct i2c_client *client, for (i = 0; i < TOUCH_SUPPORTED; i++) { input_dev = input_allocate_device(); if (input_dev == NULL) { - kfree(ts); dev_err(ts->dev, "cp_tm1217:Input Device Struct alloc failed\n"); + kfree(ts); return -ENOMEM; } input_info = &ts->cp_input_info[i]; -- cgit v1.2.3 From 59a126418b96e9f5337d431e6024a8d50bbd6e4e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 13 Nov 2010 12:05:32 +0300 Subject: Staging: iio/dds: double locking bugs This is a static checker patch and I don't have this hardware. This code is unusual because while I've often seen a double lock, this is the first time I've seen code that takes a lock 11 times in a row. I feel like I must have missed something. But I've looked very carefully I don't see any way the original code is correct. Does spi_sync() somehow release the lock in a way that I can't see? Even if it does, the locking would still be wrong. Signed-off-by: Dan Carpenter Acked-by: Michael Hennerich Acked-by: Cliff Cai Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/ad9832.c | 2 -- drivers/staging/iio/dds/ad9852.c | 11 +---------- drivers/staging/iio/dds/ad9910.c | 26 ++++++-------------------- drivers/staging/iio/dds/ad9951.c | 5 ----- 4 files changed, 7 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c index a4bb0482ed5b..e911893b3db0 100644 --- a/drivers/staging/iio/dds/ad9832.c +++ b/drivers/staging/iio/dds/ad9832.c @@ -166,8 +166,6 @@ static void ad9832_init(struct ad9832_state *st) config = 0x3 << 14; - mutex_lock(&st->lock); - xfer.len = 2; xfer.tx_buf = &config; diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c index 0a41d25583af..594fb6a94331 100644 --- a/drivers/staging/iio/dds/ad9852.c +++ b/drivers/staging/iio/dds/ad9852.c @@ -86,7 +86,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 3; xfer.tx_buf = &config->phajst1[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -96,7 +95,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 6; xfer.tx_buf = &config->fretun1[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -106,7 +104,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 6; xfer.tx_buf = &config->fretun2[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -116,7 +113,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 6; xfer.tx_buf = &config->dltafre[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -126,7 +122,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->updtclk[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -136,7 +131,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 4; xfer.tx_buf = &config->ramprat[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -146,7 +140,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->control[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -156,7 +149,6 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 3; xfer.tx_buf = &config->outpskm[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -166,16 +158,15 @@ static ssize_t ad9852_set_parameter(struct device *dev, xfer.len = 2; xfer.tx_buf = &config->outpskr[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 3; xfer.tx_buf = &config->daccntl[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c index c59b40794768..e8fb75cb66ec 100644 --- a/drivers/staging/iio/dds/ad9910.c +++ b/drivers/staging/iio/dds/ad9910.c @@ -138,7 +138,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->ioupd[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -148,7 +147,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->ftw[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -158,7 +156,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 3; xfer.tx_buf = &config->pow[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -168,7 +165,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->asf[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -178,7 +174,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->multc[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -188,7 +183,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 9; xfer.tx_buf = &config->dig_rampl[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -198,7 +192,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 9; xfer.tx_buf = &config->dig_ramps[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -208,7 +201,6 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->dig_rampr[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -218,25 +210,24 @@ static ssize_t ad9910_set_parameter(struct device *dev, xfer.len = 9; xfer.tx_buf = &config->sin_tonep0[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 9; xfer.tx_buf = &config->sin_tonep1[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 9; xfer.tx_buf = &config->sin_tonep2[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -245,43 +236,42 @@ static ssize_t ad9910_set_parameter(struct device *dev, goto error_ret; xfer.len = 9; xfer.tx_buf = &config->sin_tonep3[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 9; xfer.tx_buf = &config->sin_tonep4[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 9; xfer.tx_buf = &config->sin_tonep5[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 9; xfer.tx_buf = &config->sin_tonep6[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); ret = spi_sync(st->sdev, &msg); if (ret) goto error_ret; + xfer.len = 9; xfer.tx_buf = &config->sin_tonep7[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -326,8 +316,6 @@ static void ad9910_init(struct ad9910_state *st) cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB; cfr[4] = PARA_ENA; - mutex_lock(&st->lock); - xfer.len = 5; xfer.tx_buf = 𝔠 @@ -343,8 +331,6 @@ static void ad9910_init(struct ad9910_state *st) cfr[3] = REFCLK_RST | REFCLK_BYP; cfr[4] = 0; - mutex_lock(&st->lock); - xfer.len = 5; xfer.tx_buf = 𝔠 diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c index bc3befff167a..57eddf6d4713 100644 --- a/drivers/staging/iio/dds/ad9951.c +++ b/drivers/staging/iio/dds/ad9951.c @@ -79,7 +79,6 @@ static ssize_t ad9951_set_parameter(struct device *dev, xfer.len = 2; xfer.tx_buf = &config->arr[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -89,7 +88,6 @@ static ssize_t ad9951_set_parameter(struct device *dev, xfer.len = 5; xfer.tx_buf = &config->ftw0[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -99,7 +97,6 @@ static ssize_t ad9951_set_parameter(struct device *dev, xfer.len = 3; xfer.tx_buf = &config->ftw1[0]; - mutex_lock(&st->lock); spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -143,8 +140,6 @@ static void ad9951_init(struct ad9951_state *st) cfr[2] = HSPD_SYNC; cfr[3] = 0; - mutex_lock(&st->lock); - xfer.len = 4; xfer.tx_buf = 𝔠 -- cgit v1.2.3 From 0ebce2696305c3f49f54f3af25cb966ef1b24f71 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 13 Nov 2010 08:44:35 -0800 Subject: staging: fix iio/gyro typos, build errors Typo causes build errors. Did anyone even build this driver? Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/adis16251.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/adis16251.h b/drivers/staging/iio/gyro/adis16251.h index 999db4981413..d23852cf78e8 100644 --- a/drivers/staging/iio/gyro/adis16251.h +++ b/drivers/staging/iio/gyro/adis16251.h @@ -56,14 +56,14 @@ #define ADIS16251_DIAG_STAT_POWER_HIGH (1<<1) #define ADIS16251_DIAG_STAT_POWER_LOW (1<<0) -#define ADIS16251_DIAG_STAT_ERR_MASK (ADIS16261_DIAG_STAT_ALARM2 | \ - ADIS16261_DIAG_STAT_ALARM1 | \ - ADIS16261_DIAG_STAT_SELF_TEST | \ - ADIS16261_DIAG_STAT_OVERFLOW | \ - ADIS16261_DIAG_STAT_SPI_FAIL | \ - ADIS16261_DIAG_STAT_FLASH_UPT | \ - ADIS16261_DIAG_STAT_POWER_HIGH | \ - ADIS16261_DIAG_STAT_POWER_LOW) +#define ADIS16251_DIAG_STAT_ERR_MASK (ADIS16251_DIAG_STAT_ALARM2 | \ + ADIS16251_DIAG_STAT_ALARM1 | \ + ADIS16251_DIAG_STAT_SELF_TEST | \ + ADIS16251_DIAG_STAT_OVERFLOW | \ + ADIS16251_DIAG_STAT_SPI_FAIL | \ + ADIS16251_DIAG_STAT_FLASH_UPT | \ + ADIS16251_DIAG_STAT_POWER_HIGH | \ + ADIS16251_DIAG_STAT_POWER_LOW) /* GLOB_CMD */ #define ADIS16251_GLOB_CMD_SW_RESET (1<<7) -- cgit v1.2.3 From f05321cca53da7c7abad4bc726699e9f27bf4922 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 13 Nov 2010 07:37:49 +0300 Subject: Staging: bcm: signedness bug in StoreSFParam() wrm() returns negative error codes so "ret" needs to be signed here. There was place where wrm() returned positive EACCES instead of negative -EACCES so I fixed that as well. Also a few checkpatch.pl issues. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/CmHost.c | 8 ++++---- drivers/staging/bcm/InterfaceMisc.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index a685cadb778d..5ac45820d564 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -1649,17 +1649,17 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet static ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG ulAddrSFParamSet) { UINT nBytesToWrite = sizeof(stServiceFlowParamSI); - UINT uiRetVal =0; + int ret = 0; if(ulAddrSFParamSet == 0 || NULL == pucSrcBuffer) { return 0; } - uiRetVal = wrm(Adapter,ulAddrSFParamSet,(PUCHAR)pucSrcBuffer, nBytesToWrite); - if(uiRetVal < 0) { + ret = wrm(Adapter, ulAddrSFParamSet, (u8 *)pucSrcBuffer, nBytesToWrite); + if (ret < 0) { BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "%s:%d WRM failed",__FUNCTION__, __LINE__); - return uiRetVal; + return ret; } return 1; } diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c index b7d6e7a414a9..a51185b522cf 100644 --- a/drivers/staging/bcm/InterfaceMisc.c +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -90,7 +90,7 @@ InterfaceWRM(PS_INTERFACE_ADAPTER psIntfAdapter, if((psIntfAdapter->psAdapter->StopAllXaction == TRUE) && (psIntfAdapter->psAdapter->chip_id >= T3LPB)) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL,"Currently Xaction is not allowed on the bus..."); - return EACCES; + return -EACCES; } if(psIntfAdapter->bSuspended ==TRUE || psIntfAdapter->bPreparingForBusSuspend == TRUE) -- cgit v1.2.3 From 2e3161390130f50fdbb4b989c667f42e5008107f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 13 Nov 2010 11:24:22 +0300 Subject: Staging: bcm: signedness bug in InitCardAndDownloadFirmware() status is used to store negative error codes throughout. The only place where this is a runtime bug is if create_worker_threads() fails. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/Misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 023c511c0001..9588fbe101d9 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -1079,7 +1079,7 @@ int run_card_proc(PMINI_ADAPTER ps_adapter ) int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) { - UINT status = STATUS_SUCCESS; + int status; UINT value = 0; /* * Create the threads first and then download the -- cgit v1.2.3 From 1070137de3e3b0f3fdfedc420a06a43d05a6e705 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 16 Nov 2010 13:16:58 -0800 Subject: staging: brcm80211: expose osl contents and start combining osl and pub_osl. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 13 ------------- drivers/staging/brcm80211/include/osl.h | 26 ++++++++++++++++++++++++-- drivers/staging/brcm80211/util/linux_osl.c | 7 ------- 3 files changed, 24 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 0fb6e1c86793..1181f014a114 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -54,19 +54,6 @@ extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); extern uint osl_pci_bus(osl_t *osh); extern uint osl_pci_slot(osl_t *osh); -/* Pkttag flag should be part of public information */ -typedef struct { - uint pktalloced; /* Number of allocated packet buffers */ - bool mmbus; /* Bus supports memory-mapped register accesses */ - pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ - void *tx_ctx; /* Context to the callback function */ -#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) - osl_rreg_fn_t rreg_fn; /* Read Register function */ - osl_wreg_fn_t wreg_fn; /* Write Register function */ - void *reg_ctx; /* Context to the reg callback functions */ -#endif -} osl_pubinfo_t; - #define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ do { \ ((osl_pubinfo_t *)osh)->tx_fn = _tx_fn; \ diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index bcb56aa5dc96..0cdd15d992fa 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -17,12 +17,34 @@ #ifndef _osl_h_ #define _osl_h_ +/* Drivers use PKTFREESETCB to register a callback function + when a packet is freed by OSL */ +typedef void (*pktfree_cb_fn_t) (void *ctx, void *pkt, unsigned int status); + +struct osl_pubinfo { + uint pktalloced; /* Number of allocated packet buffers */ + bool mmbus; /* Bus supports memory-mapped registers */ + pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ + void *tx_ctx; /* Context to the callback function */ +#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) + osl_rreg_fn_t rreg_fn; /* Read Register function */ + osl_wreg_fn_t wreg_fn; /* Write Register function */ + void *reg_ctx; /* Context to the reg callback functions */ +#endif +}; + /* osl handle type forward declaration */ +struct osl_info { + struct osl_pubinfo pub; + uint magic; + void *pdev; + uint bustype; +}; + typedef struct osl_info osl_t; +typedef struct osl_pubinfo osl_pubinfo_t; typedef struct osl_dmainfo osldma_t; -/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ -typedef void (*pktfree_cb_fn_t) (void *ctx, void *pkt, unsigned int status); #ifdef BCMSDIO /* Drivers use REGOPSSET() to register register read/write funcitons */ diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 625cbacc8665..3869de75d8c8 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -33,13 +33,6 @@ #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognise osh */ #define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ -struct osl_info { - osl_pubinfo_t pub; - uint magic; - void *pdev; - uint bustype; -}; - /* Global ASSERT type flag */ u32 g_assert_type; -- cgit v1.2.3 From e6a12a07d0b06f8e614a212e26002e62071242e8 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 16 Nov 2010 13:16:59 -0800 Subject: staging: brcm80211: completely remove osl_pubinfo_t typedef Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 29 ++++++++++++++------------- drivers/staging/brcm80211/include/osl.h | 1 - drivers/staging/brcm80211/util/linux_osl.c | 24 +++++++++++----------- 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 1181f014a114..124b579f87c5 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -56,16 +56,16 @@ extern uint osl_pci_slot(osl_t *osh); #define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ do { \ - ((osl_pubinfo_t *)osh)->tx_fn = _tx_fn; \ - ((osl_pubinfo_t *)osh)->tx_ctx = _tx_ctx; \ + ((struct osl_pubinfo *)osh)->tx_fn = _tx_fn; \ + ((struct osl_pubinfo *)osh)->tx_ctx = _tx_ctx; \ } while (0) #if defined(BCMSDIO) && !defined(BRCM_FULLMAC) #define REGOPSSET(osh, rreg, wreg, ctx) \ do { \ - ((osl_pubinfo_t *)osh)->rreg_fn = rreg; \ - ((osl_pubinfo_t *)osh)->wreg_fn = wreg; \ - ((osl_pubinfo_t *)osh)->reg_ctx = ctx; \ + ((struct osl_pubinfo *)osh)->rreg_fn = rreg; \ + ((struct osl_pubinfo *)osh)->wreg_fn = wreg; \ + ((struct osl_pubinfo *)osh)->reg_ctx = ctx; \ } while (0) #endif @@ -111,10 +111,11 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #endif #if defined(BCMSDIO) -#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t *)(osh))->mmbus) \ +#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) \ + if (((struct osl_pubinfo *)(osh))->mmbus) \ mmap_op else bus_op -#define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t *)(osh))->mmbus) ? \ - mmap_op : bus_op +#define SELECT_BUS_READ(osh, mmap_op, bus_op) \ + (((struct osl_pubinfo *)(osh))->mmbus) ? mmap_op : bus_op #else #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op #define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op @@ -271,7 +272,7 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len)) #define PKTPUSH(skb, bytes) skb_push((struct sk_buff *)(skb), (bytes)) #define PKTPULL(skb, bytes) skb_pull((struct sk_buff *)(skb), (bytes)) -#define PKTALLOCED(osh) (((osl_pubinfo_t *)(osh))->pktalloced) +#define PKTALLOCED(osh) (((struct osl_pubinfo *)(osh))->pktalloced) #define PKTSETPOOL(osh, skb, x, y) do {} while (0) #define PKTPOOL(osh, skb) false extern void *osl_pktget(osl_t *osh, uint len); @@ -279,7 +280,7 @@ extern void osl_pktfree(osl_t *osh, void *skb, bool send); #ifdef BRCM_FULLMAC static inline void * -osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb) +osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) { struct sk_buff *nskb; @@ -289,10 +290,10 @@ osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb) return (void *)skb; } #define PKTFRMNATIVE(osh, skb) \ - osl_pkt_frmnative(((osl_pubinfo_t *)osh), (struct sk_buff*)(skb)) + osl_pkt_frmnative(((struct osl_pubinfo *)osh), (struct sk_buff*)(skb)) static inline struct sk_buff * -osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt) +osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) { struct sk_buff *nskb; @@ -302,9 +303,9 @@ osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt) return (struct sk_buff *)pkt; } #define PKTTONATIVE(osh, pkt) \ - osl_pkt_tonative((osl_pubinfo_t *)(osh), (pkt)) + osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) #else /* !BRCM_FULLMAC */ -#define PKTUNALLOC(osh) (((osl_pubinfo_t *)(osh))->pktalloced--) +#define PKTUNALLOC(osh) (((struct osl_pubinfo *)(osh))->pktalloced--) #define PKTSETSKIPCT(osh, skb) #define PKTCLRSKIPCT(osh, skb) diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 0cdd15d992fa..5a9bc59e9217 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -42,7 +42,6 @@ struct osl_info { }; typedef struct osl_info osl_t; -typedef struct osl_pubinfo osl_pubinfo_t; typedef struct osl_dmainfo osldma_t; diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 3869de75d8c8..eb5d285efc04 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -245,48 +245,48 @@ void osl_assert(char *exp, char *file, int line) #if defined(BCMSDIO) && !defined(BRCM_FULLMAC) u8 osl_readb(osl_t *osh, volatile u8 *r) { - osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn; - void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; + void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; return (u8) ((rreg) (ctx, (void *)r, sizeof(u8))); } u16 osl_readw(osl_t *osh, volatile u16 *r) { - osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn; - void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; + void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; return (u16) ((rreg) (ctx, (void *)r, sizeof(u16))); } u32 osl_readl(osl_t *osh, volatile u32 *r) { - osl_rreg_fn_t rreg = ((osl_pubinfo_t *) osh)->rreg_fn; - void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; + void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; return (u32) ((rreg) (ctx, (void *)r, sizeof(u32))); } void osl_writeb(osl_t *osh, volatile u8 *r, u8 v) { - osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn; - void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; + void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; ((wreg) (ctx, (void *)r, v, sizeof(u8))); } void osl_writew(osl_t *osh, volatile u16 *r, u16 v) { - osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn; - void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; + void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; ((wreg) (ctx, (void *)r, v, sizeof(u16))); } void osl_writel(osl_t *osh, volatile u32 *r, u32 v) { - osl_wreg_fn_t wreg = ((osl_pubinfo_t *) osh)->wreg_fn; - void *ctx = ((osl_pubinfo_t *) osh)->reg_ctx; + osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; + void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; ((wreg) (ctx, (void *)r, v, sizeof(u32))); } -- cgit v1.2.3 From e69284f24320e2589dbd78bf531ffa18d097ae4c Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 16 Nov 2010 15:45:48 -0800 Subject: staging: brcm80211: s/osl_t/struct osl_info/g Do the substitution (and then fix all the dang lines that were pushed past 80 columns.) Some of the touched lines triggered checkpatch warnings for completely unrelated reasons that were already there. Those will have to be addressed later. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh.c | 7 ++- drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 10 ++-- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 4 +- drivers/staging/brcm80211/brcmfmac/dhd.h | 9 +-- drivers/staging/brcm80211/brcmfmac/dhd_bus.h | 4 +- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 7 ++- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 54 +++++++++-------- drivers/staging/brcm80211/include/bcm_rpc.h | 2 +- drivers/staging/brcm80211/include/bcm_rpc_tp.h | 2 +- drivers/staging/brcm80211/include/bcmsdbus.h | 4 +- drivers/staging/brcm80211/include/bcmsdh.h | 10 ++-- drivers/staging/brcm80211/include/bcmsdh_sdmmc.h | 6 +- drivers/staging/brcm80211/include/bcmsrom.h | 8 +-- drivers/staging/brcm80211/include/bcmutils.h | 18 +++--- drivers/staging/brcm80211/include/hnddma.h | 4 +- drivers/staging/brcm80211/include/hndpmu.h | 44 +++++++------- drivers/staging/brcm80211/include/linux_osl.h | 42 +++++++------ drivers/staging/brcm80211/include/nicpci.h | 10 ++-- drivers/staging/brcm80211/include/osl.h | 1 - drivers/staging/brcm80211/include/rpc_osl.h | 2 +- drivers/staging/brcm80211/include/siutils.h | 10 ++-- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 16 ++--- drivers/staging/brcm80211/phy/wlc_phy_int.h | 2 +- drivers/staging/brcm80211/sys/wl_export.h | 8 +-- drivers/staging/brcm80211/sys/wl_mac80211.c | 4 +- drivers/staging/brcm80211/sys/wl_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_alloc.c | 20 ++++--- drivers/staging/brcm80211/sys/wlc_alloc.h | 10 ++-- drivers/staging/brcm80211/sys/wlc_ampdu.c | 2 +- drivers/staging/brcm80211/sys/wlc_antsel.c | 2 +- drivers/staging/brcm80211/sys/wlc_antsel.h | 2 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 46 +++++++------- drivers/staging/brcm80211/sys/wlc_bmac.h | 4 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 36 +++++------ drivers/staging/brcm80211/sys/wlc_mac80211.h | 4 +- drivers/staging/brcm80211/sys/wlc_pub.h | 6 +- drivers/staging/brcm80211/util/bcmotp.c | 10 ++-- drivers/staging/brcm80211/util/bcmsrom.c | 61 ++++++++++--------- drivers/staging/brcm80211/util/bcmutils.c | 18 +++--- drivers/staging/brcm80211/util/hnddma.c | 24 ++++---- drivers/staging/brcm80211/util/hndpmu.c | 73 ++++++++++++----------- drivers/staging/brcm80211/util/linux_osl.c | 46 +++++++------- drivers/staging/brcm80211/util/nicpci.c | 23 +++---- drivers/staging/brcm80211/util/nvram/nvram_ro.c | 2 +- drivers/staging/brcm80211/util/siutils.c | 10 ++-- 45 files changed, 356 insertions(+), 333 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c index 6738983e2d5c..6171ebf56ff1 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c @@ -39,7 +39,7 @@ struct bcmsdh_info { bool init_success; /* underlying driver successfully attached */ void *sdioh; /* handler for sdioh */ u32 vendevid; /* Target Vendor and Device ID on SD bus */ - osl_t *osh; + struct osl_info *osh; bool regfail; /* Save status of last reg_read/reg_write call */ u32 sbwad; /* Save backplane window address */ @@ -56,7 +56,8 @@ void bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) } #endif -bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq) +bcmsdh_info_t *bcmsdh_attach(struct osl_info *osh, void *cfghdl, + void **regsva, uint irq) { bcmsdh_info_t *bcmsdh; @@ -85,7 +86,7 @@ bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq) return bcmsdh; } -int bcmsdh_detach(osl_t *osh, void *sdh) +int bcmsdh_detach(struct osl_info *osh, void *sdh) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh; diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index b021d97e59fa..6e32056451f1 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -56,7 +56,7 @@ struct bcmsdh_hc { #else struct pci_dev *dev; /* pci device handle */ #endif /* BCMPLATFORM_BUS */ - osl_t *osh; + struct osl_info *osh; void *regs; /* SDIO Host Controller address */ bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ void *ch; @@ -142,7 +142,7 @@ static #endif /* BCMLXSDMMC */ int bcmsdh_probe(struct device *dev) { - osl_t *osh = NULL; + struct osl_info *osh = NULL; bcmsdh_hc_t *sdhc = NULL; unsigned long regs = 0; bcmsdh_info_t *sdh = NULL; @@ -246,7 +246,7 @@ static int bcmsdh_remove(struct device *dev) { bcmsdh_hc_t *sdhc, *prev; - osl_t *osh; + struct osl_info *osh; sdhc = sdhcinfo; drvinfo.detach(sdhc->ch); @@ -339,7 +339,7 @@ module_param(sd_pci_slot, uint, 0); static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - osl_t *osh = NULL; + struct osl_info *osh = NULL; bcmsdh_hc_t *sdhc = NULL; unsigned long regs; bcmsdh_info_t *sdh = NULL; @@ -470,7 +470,7 @@ err: static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev) { bcmsdh_hc_t *sdhc, *prev; - osl_t *osh; + struct osl_info *osh; /* find the SDIO Host Controller state for this pdev and take it out from the list */ diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 039f114130d2..babda77d9326 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -112,7 +112,7 @@ static int sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) /* * Public entry points & extern's */ -extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq) +extern sdioh_info_t *sdioh_attach(struct osl_info *osh, void *bar0, uint irq) { sdioh_info_t *sd; int err_ret; @@ -175,7 +175,7 @@ extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq) return sd; } -extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd) +extern SDIOH_API_RC sdioh_detach(struct osl_info *osh, sdioh_info_t *sd) { sd_trace(("%s\n", __func__)); diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h index 57d06b2da46f..7785772ed917 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd.h +++ b/drivers/staging/brcm80211/brcmfmac/dhd.h @@ -77,7 +77,7 @@ enum dhd_prealloc_index { /* Common structure for module and instance linkage */ typedef struct dhd_pub { /* Linkage ponters */ - osl_t *osh; /* OSL handle */ + struct osl_info *osh; /* OSL handle */ struct dhd_bus *bus; /* Bus module handle */ struct dhd_prot *prot; /* Protocol module handle */ struct dhd_info *info; /* Info module handle */ @@ -277,15 +277,16 @@ typedef struct dhd_if_event { */ /* To allow osl_attach/detach calls from os-independent modules */ -osl_t *dhd_osl_attach(void *pdev, uint bustype); -void dhd_osl_detach(osl_t *osh); +struct osl_info *dhd_osl_attach(void *pdev, uint bustype); +void dhd_osl_detach(struct osl_info *osh); /* Indication from bus module regarding presence/insertion of dongle. * Return dhd_pub_t pointer, used as handle to OS module in later calls. * Returned structure should have bus and prot pointers filled in. * bus_hdrlen specifies required headroom for bus module header. */ -extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); +extern dhd_pub_t *dhd_attach(struct osl_info *osh, struct dhd_bus *bus, + uint bus_hdrlen); extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); /* Indication from bus module regarding removal/absence of dongle */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h index 3b39c9966f81..6629a229b4a1 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h @@ -26,8 +26,8 @@ extern int dhd_bus_register(void); extern void dhd_bus_unregister(void); /* Download firmware image and nvram image */ -extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t * osh, - char *fw_path, char *nv_path); +extern bool dhd_bus_download_firmware(struct dhd_bus *bus, + struct osl_info *osh, char *fw_path, char *nv_path); /* Stop bus module: clear pending frames, disable data flow */ extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 48f0e6c518b6..27d4e02d3aab 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1863,12 +1863,12 @@ static int dhd_open(struct net_device *net) return ret; } -osl_t *dhd_osl_attach(void *pdev, uint bustype) +struct osl_info *dhd_osl_attach(void *pdev, uint bustype) { return osl_attach(pdev, bustype); } -void dhd_osl_detach(osl_t *osh) +void dhd_osl_detach(struct osl_info *osh) { osl_detach(osh); } @@ -1926,7 +1926,8 @@ void dhd_del_if(dhd_info_t *dhd, int ifidx) up(&dhd->sysioc_sem); } -dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) +dhd_pub_t *dhd_attach(struct osl_info *osh, struct dhd_bus *bus, + uint bus_hdrlen) { dhd_info_t *dhd = NULL; struct net_device *net; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 66884d47e834..bc8739665d66 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -431,15 +431,16 @@ static int dhdsdio_mem_dump(dhd_bus_t *bus); #endif /* DHD_DEBUG */ static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); -static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); +static void dhdsdio_release(dhd_bus_t *bus, struct osl_info *osh); +static void dhdsdio_release_malloc(dhd_bus_t *bus, struct osl_info *osh); static void dhdsdio_disconnect(void *ptr); static bool dhdsdio_chipmatch(u16 chipid); -static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, - void *regsva, u16 devid); -static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); -static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t * osh); +static bool dhdsdio_probe_attach(dhd_bus_t *bus, struct osl_info *osh, + void *sdh, void *regsva, u16 devid); +static bool dhdsdio_probe_malloc(dhd_bus_t *bus, struct osl_info *osh, + void *sdh); +static bool dhdsdio_probe_init(dhd_bus_t *bus, struct osl_info *osh, void *sdh); +static void dhdsdio_release_dongle(dhd_bus_t *bus, struct osl_info * osh); static uint process_nvram_vars(char *varbuf, uint len); @@ -451,7 +452,7 @@ static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags, u8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, +static bool dhdsdio_download_firmware(struct dhd_bus *bus, struct osl_info *osh, void *sdh); static int _dhdsdio_download_firmware(struct dhd_bus *bus); @@ -904,7 +905,7 @@ void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) { int ret; - osl_t *osh; + struct osl_info *osh; u8 *frame; u16 len, pad = 0; u32 swheader; @@ -1065,7 +1066,7 @@ done: int dhd_bus_txdata(struct dhd_bus *bus, void *pkt) { int ret = BCME_ERROR; - osl_t *osh; + struct osl_info *osh; uint datalen, prec; DHD_TRACE(("%s: Enter\n", __func__)); @@ -2824,7 +2825,7 @@ exit: void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) { - osl_t *osh = bus->dhd->osh; + struct osl_info *osh = bus->dhd->osh; u32 local_hostintmask; u8 saveclk; uint retries; @@ -3180,7 +3181,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) u16 sublen, check; void *pfirst, *plast, *pnext, *save_pfirst; - osl_t *osh = bus->dhd->osh; + struct osl_info *osh = bus->dhd->osh; int errcode; u8 chan, seq, doff, sfdoff; @@ -3581,7 +3582,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) /* Return true if there may be more frames to read */ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) { - osl_t *osh = bus->dhd->osh; + struct osl_info *osh = bus->dhd->osh; bcmsdh_info_t *sdh = bus->sdh; u16 len, check; /* Extracted hardware header fields */ @@ -4631,7 +4632,7 @@ static void dhdsdio_pktgen(dhd_bus_t *bus) u8 *data; uint pktcount; uint fillbyte; - osl_t *osh = bus->dhd->osh; + struct osl_info *osh = bus->dhd->osh; u16 len; /* Display current count if appropriate */ @@ -4736,7 +4737,7 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) { void *pkt; u8 *data; - osl_t *osh = bus->dhd->osh; + struct osl_info *osh = bus->dhd->osh; /* Allocate the packet */ pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, @@ -4761,7 +4762,7 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) { - osl_t *osh = bus->dhd->osh; + struct osl_info *osh = bus->dhd->osh; u8 *data; uint pktlen; @@ -5062,7 +5063,7 @@ static bool dhdsdio_chipmatch(u16 chipid) static void *dhdsdio_probe(u16 venid, u16 devid, u16 bus_no, u16 slot, u16 func, uint bustype, void *regsva, - osl_t *osh, void *sdh) + struct osl_info *osh, void *sdh) { int ret; dhd_bus_t *bus; @@ -5221,8 +5222,8 @@ fail: } static bool -dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, - u16 devid) +dhdsdio_probe_attach(struct dhd_bus *bus, struct osl_info *osh, void *sdh, + void *regsva, u16 devid) { u8 clkctl = 0; int err = 0; @@ -5379,7 +5380,8 @@ fail: return false; } -static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) +static bool dhdsdio_probe_malloc(dhd_bus_t *bus, struct osl_info *osh, + void *sdh) { DHD_TRACE(("%s: Enter\n", __func__)); @@ -5420,7 +5422,7 @@ fail: return false; } -static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) +static bool dhdsdio_probe_init(dhd_bus_t *bus, struct osl_info *osh, void *sdh) { s32 fnum; @@ -5497,7 +5499,7 @@ static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) } bool -dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, +dhd_bus_download_firmware(struct dhd_bus *bus, struct osl_info *osh, char *fw_path, char *nv_path) { bool ret; @@ -5510,7 +5512,7 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, } static bool -dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) +dhdsdio_download_firmware(struct dhd_bus *bus, struct osl_info *osh, void *sdh) { bool ret; @@ -5525,7 +5527,7 @@ dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) } /* Detach and free everything */ -static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh) +static void dhdsdio_release(dhd_bus_t *bus, struct osl_info *osh) { DHD_TRACE(("%s: Enter\n", __func__)); @@ -5555,7 +5557,7 @@ static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh) DHD_TRACE(("%s: Disconnected\n", __func__)); } -static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) +static void dhdsdio_release_malloc(dhd_bus_t *bus, struct osl_info *osh) { DHD_TRACE(("%s: Enter\n", __func__)); @@ -5574,7 +5576,7 @@ static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) } } -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh) +static void dhdsdio_release_dongle(dhd_bus_t *bus, struct osl_info *osh) { DHD_TRACE(("%s: Enter\n", __func__)); diff --git a/drivers/staging/brcm80211/include/bcm_rpc.h b/drivers/staging/brcm80211/include/bcm_rpc.h index 77e5d8f71966..7a379ba15ce1 100644 --- a/drivers/staging/brcm80211/include/bcm_rpc.h +++ b/drivers/staging/brcm80211/include/bcm_rpc.h @@ -26,7 +26,7 @@ typedef void (*rpc_dispatch_cb_t) (void *ctx, struct rpc_buf *buf); typedef void (*rpc_resync_cb_t) (void *ctx); typedef void (*rpc_down_cb_t) (void *ctx); typedef void (*rpc_txdone_cb_t) (void *ctx, struct rpc_buf *buf); -extern struct rpc_info *bcm_rpc_attach(void *pdev, osl_t *osh, +extern struct rpc_info *bcm_rpc_attach(void *pdev, struct osl_info *osh, struct rpc_transport_info *rpc_th); extern void bcm_rpc_detach(struct rpc_info *rpc); diff --git a/drivers/staging/brcm80211/include/bcm_rpc_tp.h b/drivers/staging/brcm80211/include/bcm_rpc_tp.h index bb8dc6dd6f44..0136118284f9 100644 --- a/drivers/staging/brcm80211/include/bcm_rpc_tp.h +++ b/drivers/staging/brcm80211/include/bcm_rpc_tp.h @@ -57,7 +57,7 @@ typedef void (*rpc_rx_fn_t) (void *, rpc_buf_t *); typedef void (*rpc_txflowctl_cb_t) (void *ctx, bool on); #endif -extern rpc_tp_info_t *bcm_rpc_tp_attach(osl_t *osh, void *bus); +extern rpc_tp_info_t *bcm_rpc_tp_attach(struct osl_info *osh, void *bus); extern void bcm_rpc_tp_detach(rpc_tp_info_t *rpcb); extern void bcm_rpc_tp_down(rpc_tp_info_t *rpcb); extern void bcm_rpc_tp_watchdog(rpc_tp_info_t *rpcb); diff --git a/drivers/staging/brcm80211/include/bcmsdbus.h b/drivers/staging/brcm80211/include/bcmsdbus.h index ca99495eaa89..4f040e41ae50 100644 --- a/drivers/staging/brcm80211/include/bcmsdbus.h +++ b/drivers/staging/brcm80211/include/bcmsdbus.h @@ -46,8 +46,8 @@ typedef void (*sdioh_cb_fn_t) (void *); * The handler shall be provided by all subsequent calls. No local cache * cfghdl points to the starting address of pci device mapped memory */ -extern sdioh_info_t *sdioh_attach(osl_t *osh, void *cfghdl, uint irq); -extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si); +extern sdioh_info_t *sdioh_attach(struct osl_info *osh, void *cfghdl, uint irq); +extern SDIOH_API_RC sdioh_detach(struct osl_info *osh, sdioh_info_t *si); extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); diff --git a/drivers/staging/brcm80211/include/bcmsdh.h b/drivers/staging/brcm80211/include/bcmsdh.h index 6b80983d43c9..69aa061bb524 100644 --- a/drivers/staging/brcm80211/include/bcmsdh.h +++ b/drivers/staging/brcm80211/include/bcmsdh.h @@ -40,11 +40,11 @@ typedef void (*bcmsdh_cb_fn_t) (void *); * implementation may maintain a single "default" handle (e.g. the first or * most recent one) to enable single-instance implementations to pass NULL. */ -extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, - uint irq); +extern bcmsdh_info_t *bcmsdh_attach(struct osl_info *osh, void *cfghdl, + void **regsva, uint irq); /* Detach - freeup resources allocated in attach */ -extern int bcmsdh_detach(osl_t *osh, void *sdh); +extern int bcmsdh_detach(struct osl_info *osh, void *sdh); /* Query if SD device interrupts are enabled */ extern bool bcmsdh_intr_query(void *sdh); @@ -174,8 +174,8 @@ extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); typedef struct { /* attach to device */ void *(*attach) (u16 vend_id, u16 dev_id, u16 bus, u16 slot, - u16 func, uint bustype, void *regsva, osl_t *osh, - void *param); + u16 func, uint bustype, void *regsva, + struct osl_info *osh, void *param); /* detach from device */ void (*detach) (void *ch); } bcmsdh_driver_t; diff --git a/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h b/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h index 7d5aa71a7dc7..4d671ddb3af1 100644 --- a/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h +++ b/drivers/staging/brcm80211/include/bcmsdh_sdmmc.h @@ -51,7 +51,7 @@ extern void sdioh_sdmmc_osfree(sdioh_info_t *sd); #define CLIENT_INTR 0x100 /* Get rid of this! */ struct sdioh_info { - osl_t *osh; /* osh handler */ + struct osl_info *osh; /* osh handler */ bool client_intr_enabled; /* interrupt connnected flag */ bool intr_handler_valid; /* client driver interrupt handler valid */ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ @@ -94,8 +94,8 @@ extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); */ /* Register mapping routines */ -extern u32 *sdioh_sdmmc_reg_map(osl_t *osh, s32 addr, int size); -extern void sdioh_sdmmc_reg_unmap(osl_t *osh, s32 addr, int size); +extern u32 *sdioh_sdmmc_reg_map(struct osl_info *osh, s32 addr, int size); +extern void sdioh_sdmmc_reg_unmap(struct osl_info *osh, s32 addr, int size); /* Interrupt (de)registration routines */ extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); diff --git a/drivers/staging/brcm80211/include/bcmsrom.h b/drivers/staging/brcm80211/include/bcmsrom.h index 9d53657fdaa1..cdcef746284f 100644 --- a/drivers/staging/brcm80211/include/bcmsrom.h +++ b/drivers/staging/brcm80211/include/bcmsrom.h @@ -20,15 +20,15 @@ #include /* Prototypes */ -extern int srom_var_init(si_t *sih, uint bus, void *curmap, osl_t *osh, - char **vars, uint *count); +extern int srom_var_init(si_t *sih, uint bus, void *curmap, + struct osl_info *osh, char **vars, uint *count); -extern int srom_read(si_t *sih, uint bus, void *curmap, osl_t *osh, +extern int srom_read(si_t *sih, uint bus, void *curmap, struct osl_info *osh, uint byteoff, uint nbytes, u16 *buf, bool check_crc); /* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP * and extract from it into name=value pairs */ -extern int srom_parsecis(osl_t *osh, u8 **pcis, uint ciscnt, +extern int srom_parsecis(struct osl_info *osh, u8 **pcis, uint ciscnt, char **vars, uint *count); #endif /* _bcmsrom_h_ */ diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h index 7f1d33481ee8..4c1c111bac9b 100644 --- a/drivers/staging/brcm80211/include/bcmutils.h +++ b/drivers/staging/brcm80211/include/bcmutils.h @@ -110,10 +110,10 @@ extern void *pktq_pdeq_tail(struct pktq *pq, int prec); /* Empty the queue at particular precedence level */ #ifdef BRCM_FULLMAC - extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, + extern void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir); #else - extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, + extern void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg); #endif /* BRCM_FULLMAC */ @@ -141,18 +141,18 @@ /* prec_out may be NULL if caller is not interested in return value */ extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); #ifdef BRCM_FULLMAC - extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); + extern void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir); #else - extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, + extern void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); #endif /* externs */ /* packet */ - extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, - unsigned char *buf); - extern uint pktsegcnt(osl_t *osh, void *p); - extern uint pkttotlen(osl_t *osh, void *p); + extern uint pktfrombuf(struct osl_info *osh, void *p, uint offset, + int len, unsigned char *buf); + extern uint pktsegcnt(struct osl_info *osh, void *p); + extern uint pkttotlen(struct osl_info *osh, void *p); /* ethernet address */ extern int bcm_ether_atoe(char *p, struct ether_addr *ea); @@ -165,7 +165,7 @@ extern char *getvar(char *vars, const char *name); extern int getintvar(char *vars, const char *name); #ifdef BCMDBG - extern void prpkt(const char *msg, osl_t *osh, void *p0); + extern void prpkt(const char *msg, struct osl_info *osh, void *p0); #endif /* BCMDBG */ #define bcm_perf_enable() #define bcmstats(fmt) diff --git a/drivers/staging/brcm80211/include/hnddma.h b/drivers/staging/brcm80211/include/hnddma.h index bee4c89be23d..854a3996baa8 100644 --- a/drivers/staging/brcm80211/include/hnddma.h +++ b/drivers/staging/brcm80211/include/hnddma.h @@ -141,7 +141,7 @@ struct hnddma_pub { uint txnobuf; /* tx out of dma descriptors */ }; -extern hnddma_t *dma_attach(osl_t *osh, char *name, si_t *sih, +extern hnddma_t *dma_attach(struct osl_info *osh, char *name, si_t *sih, void *dmaregstx, void *dmaregsrx, uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, uint nrxpost, uint rxoffset, uint *msg_level); @@ -238,6 +238,6 @@ extern const di_fcn_t dma64proc; extern uint dma_addrwidth(si_t *sih, void *dmaregs); /* pio helpers */ -extern void dma_txpioloopback(osl_t *osh, dma32regs_t *); +extern void dma_txpioloopback(struct osl_info *osh, dma32regs_t *); #endif /* _hnddma_h_ */ diff --git a/drivers/staging/brcm80211/include/hndpmu.h b/drivers/staging/brcm80211/include/hndpmu.h index bbcf0eecd212..a0110e4c9ac4 100644 --- a/drivers/staging/brcm80211/include/hndpmu.h +++ b/drivers/staging/brcm80211/include/hndpmu.h @@ -28,44 +28,44 @@ #define SET_LDO_VOLTAGE_LNLDO1 9 #define SET_LDO_VOLTAGE_LNLDO2_SEL 10 -extern void si_pmu_init(si_t *sih, osl_t *osh); -extern void si_pmu_chip_init(si_t *sih, osl_t *osh); -extern void si_pmu_pll_init(si_t *sih, osl_t *osh, u32 xtalfreq); -extern void si_pmu_res_init(si_t *sih, osl_t *osh); -extern void si_pmu_swreg_init(si_t *sih, osl_t *osh); +extern void si_pmu_init(si_t *sih, struct osl_info *osh); +extern void si_pmu_chip_init(si_t *sih, struct osl_info *osh); +extern void si_pmu_pll_init(si_t *sih, struct osl_info *osh, u32 xtalfreq); +extern void si_pmu_res_init(si_t *sih, struct osl_info *osh); +extern void si_pmu_swreg_init(si_t *sih, struct osl_info *osh); -extern u32 si_pmu_force_ilp(si_t *sih, osl_t *osh, bool force); +extern u32 si_pmu_force_ilp(si_t *sih, struct osl_info *osh, bool force); -extern u32 si_pmu_si_clock(si_t *sih, osl_t *osh); -extern u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh); -extern u32 si_pmu_mem_clock(si_t *sih, osl_t *osh); -extern u32 si_pmu_alp_clock(si_t *sih, osl_t *osh); -extern u32 si_pmu_ilp_clock(si_t *sih, osl_t *osh); +extern u32 si_pmu_si_clock(si_t *sih, struct osl_info *osh); +extern u32 si_pmu_cpu_clock(si_t *sih, struct osl_info *osh); +extern u32 si_pmu_mem_clock(si_t *sih, struct osl_info *osh); +extern u32 si_pmu_alp_clock(si_t *sih, struct osl_info *osh); +extern u32 si_pmu_ilp_clock(si_t *sih, struct osl_info *osh); -extern void si_pmu_set_switcher_voltage(si_t *sih, osl_t *osh, +extern void si_pmu_set_switcher_voltage(si_t *sih, struct osl_info *osh, u8 bb_voltage, u8 rf_voltage); -extern void si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, u8 ldo, +extern void si_pmu_set_ldo_voltage(si_t *sih, struct osl_info *osh, u8 ldo, u8 voltage); -extern u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh); -extern void si_pmu_rcal(si_t *sih, osl_t *osh); +extern u16 si_pmu_fast_pwrup_delay(si_t *sih, struct osl_info *osh); +extern void si_pmu_rcal(si_t *sih, struct osl_info *osh); extern void si_pmu_pllupd(si_t *sih); -extern void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid); +extern void si_pmu_spuravoid(si_t *sih, struct osl_info *osh, u8 spuravoid); -extern bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh); -extern u32 si_pmu_measure_alpclk(si_t *sih, osl_t *osh); +extern bool si_pmu_is_otp_powered(si_t *sih, struct osl_info *osh); +extern u32 si_pmu_measure_alpclk(si_t *sih, struct osl_info *osh); extern u32 si_pmu_chipcontrol(si_t *sih, uint reg, u32 mask, u32 val); extern u32 si_pmu_regcontrol(si_t *sih, uint reg, u32 mask, u32 val); extern u32 si_pmu_pllcontrol(si_t *sih, uint reg, u32 mask, u32 val); extern void si_pmu_pllupd(si_t *sih); -extern void si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable); +extern void si_pmu_sprom_enable(si_t *sih, struct osl_info *osh, bool enable); extern void si_pmu_radio_enable(si_t *sih, bool enable); -extern u32 si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, +extern u32 si_pmu_waitforclk_on_backplane(si_t *sih, struct osl_info *osh, u32 clk, u32 delay); -extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on); -extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, +extern void si_pmu_otp_power(si_t *sih, struct osl_info *osh, bool on); +extern void si_sdiod_drive_strength_init(si_t *sih, struct osl_info *osh, u32 drivestrength); #endif /* _hndpmu_h_ */ diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 124b579f87c5..70621692150a 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -18,8 +18,8 @@ #define _linux_osl_h_ -extern osl_t *osl_attach(void *pdev, uint bustype); -extern void osl_detach(osl_t *osh); +extern struct osl_info *osl_attach(void *pdev, uint bustype); +extern void osl_detach(struct osl_info *osh); extern u32 g_assert_type; @@ -45,14 +45,15 @@ extern void osl_assert(char *exp, char *file, int line); osl_pci_read_config((osh), (offset), (size)) #define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ osl_pci_write_config((osh), (offset), (size), (val)) -extern u32 osl_pci_read_config(osl_t *osh, uint offset, uint size); -extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); +extern u32 osl_pci_read_config(struct osl_info *osh, uint offset, uint size); +extern void osl_pci_write_config(struct osl_info *osh, uint offset, uint size, + uint val); /* PCI device bus # and slot # */ #define OSL_PCI_BUS(osh) osl_pci_bus(osh) #define OSL_PCI_SLOT(osh) osl_pci_slot(osh) -extern uint osl_pci_bus(osl_t *osh); -extern uint osl_pci_slot(osl_t *osh); +extern uint osl_pci_bus(struct osl_info *osh); +extern uint osl_pci_slot(struct osl_info *osh); #define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ do { \ @@ -71,8 +72,8 @@ extern uint osl_pci_slot(osl_t *osh); #define BUS_SWAP32(v) (v) -extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align, - uint *tot, unsigned long *pap); +extern void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, + u16 align, uint *tot, unsigned long *pap); #ifdef BRCM_FULLMAC #define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \ @@ -84,7 +85,8 @@ extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align, #define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ osl_dma_free_consistent((osh), (void *)(va), (size), (pa)) -extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa); +extern void osl_dma_free_consistent(struct osl_info *osh, void *va, + uint size, unsigned long pa); /* map/unmap direction */ #define DMA_TX 1 /* TX direction for DMA */ @@ -95,8 +97,10 @@ extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned lo osl_dma_map((osh), (va), (size), (direction)) #define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ osl_dma_unmap((osh), (pa), (size), (direction)) -extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction); -extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); +extern uint osl_dma_map(struct osl_info *osh, void *va, uint size, + int direction); +extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, + int direction); /* API for DMA addressing capability */ #define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) @@ -275,8 +279,8 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); #define PKTALLOCED(osh) (((struct osl_pubinfo *)(osh))->pktalloced) #define PKTSETPOOL(osh, skb, x, y) do {} while (0) #define PKTPOOL(osh, skb) false -extern void *osl_pktget(osl_t *osh, uint len); -extern void osl_pktfree(osl_t *osh, void *skb, bool send); +extern void *osl_pktget(struct osl_info *osh, uint len); +extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); #ifdef BRCM_FULLMAC static inline void * @@ -342,12 +346,12 @@ osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) } \ } while (0) -extern u8 osl_readb(osl_t *osh, volatile u8 *r); -extern u16 osl_readw(osl_t *osh, volatile u16 *r); -extern u32 osl_readl(osl_t *osh, volatile u32 *r); -extern void osl_writeb(osl_t *osh, volatile u8 *r, u8 v); -extern void osl_writew(osl_t *osh, volatile u16 *r, u16 v); -extern void osl_writel(osl_t *osh, volatile u32 *r, u32 v); +extern u8 osl_readb(struct osl_info *osh, volatile u8 *r); +extern u16 osl_readw(struct osl_info *osh, volatile u16 *r); +extern u32 osl_readl(struct osl_info *osh, volatile u32 *r); +extern void osl_writeb(struct osl_info *osh, volatile u8 *r, u8 v); +extern void osl_writew(struct osl_info *osh, volatile u16 *r, u16 v); +extern void osl_writel(struct osl_info *osh, volatile u32 *r, u32 v); #endif /* BCMSDIO */ #endif /* _linux_osl_h_ */ diff --git a/drivers/staging/brcm80211/include/nicpci.h b/drivers/staging/brcm80211/include/nicpci.h index ce146e88ffdf..7ea7daf7c2b6 100644 --- a/drivers/staging/brcm80211/include/nicpci.h +++ b/drivers/staging/brcm80211/include/nicpci.h @@ -45,17 +45,17 @@ #else struct sbpcieregs; -extern u8 pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, +extern u8 pcicore_find_pci_capability(struct osl_info *osh, u8 req_cap_id, unsigned char *buf, u32 *buflen); -extern uint pcie_readreg(osl_t *osh, struct sbpcieregs *pcieregs, +extern uint pcie_readreg(struct osl_info *osh, struct sbpcieregs *pcieregs, uint addrtype, uint offset); -extern uint pcie_writereg(osl_t *osh, struct sbpcieregs *pcieregs, +extern uint pcie_writereg(struct osl_info *osh, struct sbpcieregs *pcieregs, uint addrtype, uint offset, uint val); extern u8 pcie_clkreq(void *pch, u32 mask, u32 val); extern u32 pcie_lcreg(void *pch, u32 mask, u32 val); -extern void *pcicore_init(si_t *sih, osl_t *osh, void *regs); +extern void *pcicore_init(si_t *sih, struct osl_info *osh, void *regs); extern void pcicore_deinit(void *pch); extern void pcicore_attach(void *pch, char *pvars, int state); extern void pcicore_hwup(void *pch); @@ -70,7 +70,7 @@ extern u32 pcicore_pcieserdesreg(void *pch, u32 mdioslave, u32 offset, extern u32 pcicore_pciereg(void *pch, u32 offset, u32 mask, u32 val, uint type); -extern bool pcicore_pmecap_fast(osl_t *osh); +extern bool pcicore_pmecap_fast(struct osl_info *osh); extern void pcicore_pmeen(void *pch); extern void pcicore_pmeclr(void *pch); extern bool pcicore_pmestat(void *pch); diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 5a9bc59e9217..e2205c481a3f 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -41,7 +41,6 @@ struct osl_info { uint bustype; }; -typedef struct osl_info osl_t; typedef struct osl_dmainfo osldma_t; diff --git a/drivers/staging/brcm80211/include/rpc_osl.h b/drivers/staging/brcm80211/include/rpc_osl.h index 4a2648001bf0..c59d9ed1397a 100644 --- a/drivers/staging/brcm80211/include/rpc_osl.h +++ b/drivers/staging/brcm80211/include/rpc_osl.h @@ -18,7 +18,7 @@ #define _rpcosl_h_ typedef struct rpc_osl rpc_osl_t; -extern rpc_osl_t *rpc_osl_attach(osl_t *osh); +extern rpc_osl_t *rpc_osl_attach(struct osl_info *osh); extern void rpc_osl_detach(rpc_osl_t *rpc_osh); #define RPC_OSL_LOCK(rpc_osh) rpc_osl_lock((rpc_osh)) diff --git a/drivers/staging/brcm80211/include/siutils.h b/drivers/staging/brcm80211/include/siutils.h index 57c36507a040..6f83e7e5b313 100644 --- a/drivers/staging/brcm80211/include/siutils.h +++ b/drivers/staging/brcm80211/include/siutils.h @@ -128,8 +128,8 @@ typedef void (*gpio_handler_t) (u32 stat, void *arg); #define GPIO_CTRL_EPA_EN_MASK 0x40 /* === exported functions === */ -extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, - void *sdh, char **vars, uint *varsz); +extern si_t *si_attach(uint pcidev, struct osl_info *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz); extern void si_detach(si_t *sih); extern bool si_pci_war16165(si_t *sih); @@ -344,9 +344,9 @@ extern void si_epa_4313war(si_t *sih); char *si_getnvramflvar(si_t *sih, const char *name); /* AMBA Interconnect exported externs */ -extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, - void *sdh, char **vars, uint *varsz); -extern si_t *ai_kattach(osl_t *osh); +extern si_t *ai_attach(uint pcidev, struct osl_info *osh, void *regs, + uint bustype, void *sdh, char **vars, uint *varsz); +extern si_t *ai_kattach(struct osl_info *osh); extern void ai_scan(si_t *sih, void *regs, uint devid); extern uint ai_flag(si_t *sih); diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index 9e6bbcdf8b6f..e20c1f09f8bb 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -276,7 +276,7 @@ u16 read_radio_reg(phy_info_t *pi, u16 addr) void write_radio_reg(phy_info_t *pi, u16 addr, u16 val) { - osl_t *osh; + struct osl_info *osh; if (NORADIO_ENAB(pi->pubpi)) return; @@ -409,7 +409,7 @@ static bool wlc_phy_war41476(phy_info_t *pi) u16 read_phy_reg(phy_info_t *pi, u16 addr) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs; osh = pi->sh->osh; @@ -430,7 +430,7 @@ u16 read_phy_reg(phy_info_t *pi, u16 addr) void write_phy_reg(phy_info_t *pi, u16 addr, u16 val) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs; osh = pi->sh->osh; @@ -456,7 +456,7 @@ void write_phy_reg(phy_info_t *pi, u16 addr, u16 val) void and_phy_reg(phy_info_t *pi, u16 addr, u16 val) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs; osh = pi->sh->osh; @@ -477,7 +477,7 @@ void and_phy_reg(phy_info_t *pi, u16 addr, u16 val) void or_phy_reg(phy_info_t *pi, u16 addr, u16 val) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs; osh = pi->sh->osh; @@ -498,7 +498,7 @@ void or_phy_reg(phy_info_t *pi, u16 addr, u16 val) void mod_phy_reg(phy_info_t *pi, u16 addr, u16 mask, u16 val) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs; osh = pi->sh->osh; @@ -595,7 +595,7 @@ shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp) void wlc_phy_shared_detach(shared_phy_t *phy_sh) { - osl_t *osh; + struct osl_info *osh; if (phy_sh) { osh = phy_sh->osh; @@ -613,7 +613,7 @@ wlc_phy_t *wlc_phy_attach(shared_phy_t *sh, void *regs, int bandtype, char *vars u32 sflags = 0; uint phyversion; int i; - osl_t *osh; + struct osl_info *osh; osh = sh->osh; diff --git a/drivers/staging/brcm80211/phy/wlc_phy_int.h b/drivers/staging/brcm80211/phy/wlc_phy_int.h index 9513b87fa163..fb92c3bccb16 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_int.h +++ b/drivers/staging/brcm80211/phy/wlc_phy_int.h @@ -527,7 +527,7 @@ typedef struct { struct shared_phy { struct phy_info *phy_head; uint unit; - osl_t *osh; + struct osl_info *osh; si_t *sih; void *physhim; uint corerev; diff --git a/drivers/staging/brcm80211/sys/wl_export.h b/drivers/staging/brcm80211/sys/wl_export.h index 08442f8e84e0..aa8b5a3ed633 100644 --- a/drivers/staging/brcm80211/sys/wl_export.h +++ b/drivers/staging/brcm80211/sys/wl_export.h @@ -45,10 +45,10 @@ extern void wl_add_timer(struct wl_info *wl, struct wl_timer *timer, uint ms, int periodic); extern bool wl_del_timer(struct wl_info *wl, struct wl_timer *timer); -extern uint wl_buf_to_pktcopy(osl_t *osh, void *p, unsigned char *buf, int len, - uint offset); -extern void *wl_get_pktbuffer(osl_t *osh, int len); -extern int wl_set_pktlen(osl_t *osh, void *p, int len); +extern uint wl_buf_to_pktcopy(struct osl_info *osh, void *p, unsigned char *buf, + int len, uint offset); +extern void *wl_get_pktbuffer(struct osl_info *osh, int len); +extern int wl_set_pktlen(struct osl_info *osh, void *p, int len); #define wl_sort_bsslist(a, b) false diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 4b59e073aa15..af6d7dea4697 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -743,7 +743,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, uint bustype, void *btparam, uint irq) { wl_info_t *wl; - osl_t *osh; + struct osl_info *osh; int unit, err; unsigned long base_addr; @@ -1512,7 +1512,7 @@ module_exit(wl_module_exit); void wl_free(wl_info_t *wl) { wl_timer_t *t, *next; - osl_t *osh; + struct osl_info *osh; ASSERT(wl); #ifndef WLC_HIGH_ONLY diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h index 78cee4454b0b..54bbb15d9585 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.h +++ b/drivers/staging/brcm80211/sys/wl_mac80211.h @@ -62,7 +62,7 @@ struct wl_firmware { struct wl_info { wlc_pub_t *pub; /* pointer to public wlc state */ void *wlc; /* pointer to private common os-independent data */ - osl_t *osh; /* pointer to os handler */ + struct osl_info *osh; /* pointer to os handler */ u32 magic; int irq; diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 8001dca44918..1fb9976ef8b4 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -32,12 +32,12 @@ #include #include -static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, +static wlc_pub_t *wlc_pub_malloc(struct osl_info *osh, uint unit, uint *err, uint devid); -static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub); +static void wlc_pub_mfree(struct osl_info *osh, wlc_pub_t *pub); static void wlc_tunables_init(wlc_tunables_t *tunables, uint devid); -void *wlc_calloc(osl_t *osh, uint unit, uint size) +void *wlc_calloc(struct osl_info *osh, uint unit, uint size) { void *item; @@ -70,7 +70,8 @@ void wlc_tunables_init(wlc_tunables_t *tunables, uint devid) #endif /* WLC_HIGH_ONLY */ } -static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid) +static wlc_pub_t *wlc_pub_malloc(struct osl_info *osh, uint unit, uint *err, + uint devid) { wlc_pub_t *pub; @@ -104,7 +105,7 @@ static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err, uint devid) return NULL; } -static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub) +static void wlc_pub_mfree(struct osl_info *osh, wlc_pub_t *pub) { if (pub == NULL) return; @@ -119,7 +120,7 @@ static void wlc_pub_mfree(osl_t *osh, wlc_pub_t *pub) kfree(pub); } -wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t *osh, uint unit) +wlc_bsscfg_t *wlc_bsscfg_malloc(struct osl_info *osh, uint unit) { wlc_bsscfg_t *cfg; @@ -139,7 +140,7 @@ wlc_bsscfg_t *wlc_bsscfg_malloc(osl_t *osh, uint unit) return NULL; } -void wlc_bsscfg_mfree(osl_t *osh, wlc_bsscfg_t *cfg) +void wlc_bsscfg_mfree(struct osl_info *osh, wlc_bsscfg_t *cfg) { if (cfg == NULL) return; @@ -169,7 +170,8 @@ void wlc_bsscfg_ID_assign(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg) /* * The common driver entry routine. Error codes should be unique */ -wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid) +wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, + uint devid) { wlc_info_t *wlc; @@ -306,7 +308,7 @@ wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, uint devid) return NULL; } -void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh) +void wlc_detach_mfree(wlc_info_t *wlc, struct osl_info *osh) { if (wlc == NULL) return; diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.h b/drivers/staging/brcm80211/sys/wlc_alloc.h index 678a2b9784f8..eedf62912698 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.h +++ b/drivers/staging/brcm80211/sys/wlc_alloc.h @@ -14,12 +14,12 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -extern void *wlc_calloc(osl_t *osh, uint unit, uint size); +extern void *wlc_calloc(struct osl_info *osh, uint unit, uint size); -extern wlc_info_t *wlc_attach_malloc(osl_t *osh, uint unit, uint *err, +extern wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, uint devid); -extern void wlc_detach_mfree(wlc_info_t *wlc, osl_t *osh); +extern void wlc_detach_mfree(wlc_info_t *wlc, struct osl_info *osh); struct wlc_bsscfg; -extern struct wlc_bsscfg *wlc_bsscfg_malloc(osl_t *osh, uint unit); -extern void wlc_bsscfg_mfree(osl_t *osh, struct wlc_bsscfg *cfg); +extern struct wlc_bsscfg *wlc_bsscfg_malloc(struct osl_info *osh, uint unit); +extern void wlc_bsscfg_mfree(struct osl_info *osh, struct wlc_bsscfg *cfg); diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 0bd7069dc331..5d06105ba1f6 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -504,7 +504,7 @@ int BCMFASTPATH wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec) { wlc_info_t *wlc; - osl_t *osh; + struct osl_info *osh; void *p, *pkt[AMPDU_MAX_MPDU]; u8 tid, ndelim; int err = 0; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index ecc35de77004..4e4571a098f7 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -93,7 +93,7 @@ const u8 mimo_2x3_div_antselid_tbl[16] = { 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */ }; -antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, osl_t *osh, +antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, struct osl_info *osh, wlc_pub_t *pub, wlc_hw_info_t *wlc_hw) { antsel_info_t *asi; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.h b/drivers/staging/brcm80211/sys/wlc_antsel.h index 1d048bbea946..f3361f8106e8 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.h +++ b/drivers/staging/brcm80211/sys/wlc_antsel.h @@ -16,7 +16,7 @@ #ifndef _wlc_antsel_h_ #define _wlc_antsel_h_ -extern antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, osl_t *osh, +extern antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, struct osl_info *osh, wlc_pub_t *pub, wlc_hw_info_t *wlc_hw); extern void wlc_antsel_detach(antsel_info_t *asi); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index fc5201d5171a..214b5d82ab23 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -193,7 +193,7 @@ void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot) */ static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs; osh = wlc_hw->osh; @@ -586,7 +586,7 @@ static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme) if (wlc_hw->di[0] == 0) { /* Init FIFOs */ uint addrwidth; int dma_attach_err = 0; - osl_t *osh = wlc_hw->osh; + struct osl_info *osh = wlc_hw->osh; /* Find out the DMA addressing capability and let OS know * All the channels within one DMA core have 'common-minimum' same @@ -708,8 +708,8 @@ static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw) * put the whole chip in reset(driver down state), no clock */ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, - bool piomode, osl_t *osh, void *regsva, uint bustype, - void *btparam) + bool piomode, struct osl_info *osh, void *regsva, + uint bustype, void *btparam) { wlc_hw_info_t *wlc_hw; d11regs_t *regs; @@ -1719,7 +1719,7 @@ wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx, volatile u16 *objdata16 = (volatile u16 *)®s->objdata; u32 mac_hm; u16 mac_l; - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__)); @@ -1752,7 +1752,7 @@ wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset, u16 mac_l; u16 mac_m; u16 mac_h; - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw->unit)); @@ -1783,7 +1783,7 @@ wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len, #ifdef IL_BIGENDIAN volatile u16 *dptr = NULL; #endif /* IL_BIGENDIAN */ - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: wlc_bmac_write_template_ram\n", wlc_hw->unit)); @@ -1819,7 +1819,7 @@ wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len, void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin) { - osl_t *osh; + struct osl_info *osh; osh = wlc_hw->osh; wlc_hw->band->CWmin = newmin; @@ -1831,7 +1831,7 @@ void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin) void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax) { - osl_t *osh; + struct osl_info *osh; osh = wlc_hw->osh; wlc_hw->band->CWmax = newmax; @@ -2299,7 +2299,7 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw) static bool wlc_dma_rxreset(wlc_hw_info_t *wlc_hw, uint fifo) { hnddma_t *di = wlc_hw->di[fifo]; - osl_t *osh; + struct osl_info *osh; if (D11REV_LT(wlc_hw->corerev, 12)) { bool rxidle = true; @@ -2425,7 +2425,7 @@ static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw) u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk; u16 txfifo_def, txfifo_def1; u16 txfifo_cmd; - osl_t *osh; + struct osl_info *osh; if (D11REV_LT(wlc_hw->corerev, 9)) goto exit; @@ -2486,7 +2486,7 @@ static void wlc_coreinit(wlc_info_t *wlc) uint bcnint_us; uint i = 0; bool fifosz_fixup = false; - osl_t *osh; + struct osl_info *osh; int err = 0; u16 buf[NFIFO]; @@ -2692,7 +2692,7 @@ static void wlc_coreinit(wlc_info_t *wlc) void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode) { d11regs_t *regs; - osl_t *osh; + struct osl_info *osh; regs = wlc_hw->regs; osh = wlc_hw->osh; @@ -2725,7 +2725,7 @@ static void wlc_gpio_init(wlc_info_t *wlc) wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs; u32 gc, gm; - osl_t *osh; + struct osl_info *osh; regs = wlc_hw->regs; osh = wlc_hw->osh; @@ -2815,7 +2815,7 @@ static void wlc_ucode_download(wlc_hw_info_t *wlc_hw) static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[], const uint nbytes) { - osl_t *osh; + struct osl_info *osh; d11regs_t *regs = wlc_hw->regs; uint i; uint count; @@ -2837,7 +2837,7 @@ static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[], static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits) { int i; - osl_t *osh; + struct osl_info *osh; volatile u8 *base; WL_TRACE(("wl%d: wlc_write_inits\n", wlc_hw->unit)); @@ -3180,7 +3180,7 @@ static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr) d11regs_t *regs = wlc_hw->regs; u32 macintstatus; u32 intstatus_rxfifo, intstatus_txsfifo; - osl_t *osh; + struct osl_info *osh; osh = wlc_hw->osh; @@ -3326,7 +3326,7 @@ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw) { void *status_p; tx_status_t *txs; - osl_t *osh; + struct osl_info *osh; bool fatal = false; WL_TRACE(("wl%d: wlc_txstatusrecv\n", wlc_hw->unit)); @@ -3393,7 +3393,7 @@ wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal) } else { /* corerev >= 5 */ d11regs_t *regs; - osl_t *osh; + struct osl_info *osh; tx_status_t txstatus, *txs; u32 s1, s2; uint n = 0; @@ -3446,7 +3446,7 @@ void wlc_suspend_mac_and_wait(wlc_info_t *wlc) wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; u32 mc, mi; - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n", wlc_hw->unit, wlc_hw->band->bandunit)); @@ -3510,7 +3510,7 @@ void wlc_enable_mac(wlc_info_t *wlc) wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; u32 mc, mi; - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: wlc_enable_mac: bandunit %d\n", wlc_hw->unit, wlc->band->bandunit)); @@ -3673,7 +3673,7 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw) d11regs_t *regs; u32 w, val; volatile u16 *reg16; - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: validate_chip_access\n", wlc_hw->unit)); @@ -3766,7 +3766,7 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw) void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on) { d11regs_t *regs; - osl_t *osh; + struct osl_info *osh; u32 tmp; WL_TRACE(("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw->unit)); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.h b/drivers/staging/brcm80211/sys/wlc_bmac.h index 872bc8d866d2..4cc41f9f4619 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.h +++ b/drivers/staging/brcm80211/sys/wlc_bmac.h @@ -131,8 +131,8 @@ typedef enum { } wlc_bmac_state_id_t; extern int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, - uint unit, bool piomode, osl_t *osh, void *regsva, - uint bustype, void *btparam); + uint unit, bool piomode, struct osl_info *osh, + void *regsva, uint bustype, void *btparam); extern int wlc_bmac_detach(wlc_info_t *wlc); extern void wlc_bmac_watchdog(void *arg); extern void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index a9fa48a14c5d..9e57dc3cde21 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -265,8 +265,9 @@ static int wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val, static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc); /* send and receive */ -static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh); -static void wlc_txq_free(wlc_info_t *wlc, osl_t *osh, wlc_txq_info_t *qi); +static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, struct osl_info *osh); +static void wlc_txq_free(wlc_info_t *wlc, struct osl_info *osh, + wlc_txq_info_t *qi); static void wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, int prio); static void wlc_txflowcontrol_reset(wlc_info_t *wlc); @@ -277,7 +278,7 @@ static void wlc_compute_ofdm_plcp(ratespec_t rate, uint length, u8 *plcp); static void wlc_compute_mimo_plcp(ratespec_t rate, uint length, u8 *plcp); static u16 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type, uint next_frag_len); -static void wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, +static void wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, void *p); static uint wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type, uint dur); @@ -324,7 +325,7 @@ void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr) { d11regs_t *regs = wlc->regs; u32 v32; - osl_t *osh; + struct osl_info *osh; WL_TRACE(("wl%d: %s\n", WLCWLUNIT(wlc), __func__)); @@ -1754,8 +1755,8 @@ wlc_pub_t *wlc_pub(void *wlc) * The common driver entry routine. Error codes should be unique */ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, - osl_t *osh, void *regsva, uint bustype, void *btparam, - uint *perr) + struct osl_info *osh, void *regsva, uint bustype, + void *btparam, uint *perr) { wlc_info_t *wlc; uint err = 0; @@ -2141,8 +2142,8 @@ static bool wlc_attach_stf_ant_init(wlc_info_t *wlc) #ifdef WLC_HIGH_ONLY /* HIGH_ONLY bmac_attach, which sync over LOW_ONLY bmac_attach states */ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, - bool piomode, osl_t *osh, void *regsva, uint bustype, - void *btparam) + bool piomode, struct osl_info *osh, void *regsva, + uint bustype, void *btparam) { wlc_bmac_revinfo_t revinfo; uint idx = 0; @@ -3271,7 +3272,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) uint band; rw_reg_t *r; wlc_bsscfg_t *bsscfg; - osl_t *osh; + struct osl_info *osh; wlc_bss_info_t *current_bss; /* update bsscfg pointer */ @@ -5877,7 +5878,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, struct dot11_header *h; d11txh_t *txh; u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN]; - osl_t *osh; + struct osl_info *osh; int len, phylen, rts_phylen; u16 fc, type, frameid, mch, phyctl, xfts, mainrates; u16 seq = 0, mcl = 0, status = 0; @@ -6750,7 +6751,7 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) d11txh_t *txh; struct scb *scb = NULL; bool free_pdu; - osl_t *osh; + struct osl_info *osh; int tx_rts, tx_frame_count, tx_rts_count; uint totlen, supr_status; bool lastframe; @@ -7144,7 +7145,7 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p, } static void -wlc_recvctl(wlc_info_t *wlc, osl_t *osh, d11rxhdr_t *rxh, void *p) +wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, void *p) { int len_mpdu; struct ieee80211_rx_status rx_status; @@ -7211,7 +7212,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p) { d11rxhdr_t *rxh; struct dot11_header *h; - osl_t *osh; + struct osl_info *osh; u16 fc; uint len; bool is_amsdu; @@ -7913,7 +7914,7 @@ void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg) u16 bcn[BCN_TMPL_LEN / 2]; u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD; d11regs_t *regs = wlc->regs; - osl_t *osh = NULL; + struct osl_info *osh = NULL; osh = wlc->osh; @@ -8035,7 +8036,7 @@ wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend) /* prepares pdu for transmission. returns BCM error codes */ int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifop) { - osl_t *osh; + struct osl_info *osh; uint fifo; d11txh_t *txh; struct dot11_header *h; @@ -8628,7 +8629,7 @@ wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, } } -static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh) +static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, struct osl_info *osh) { wlc_txq_info_t *qi, *p; @@ -8658,7 +8659,8 @@ static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, osl_t *osh) return qi; } -static void wlc_txq_free(wlc_info_t *wlc, osl_t *osh, wlc_txq_info_t *qi) +static void wlc_txq_free(wlc_info_t *wlc, struct osl_info *osh, + wlc_txq_info_t *qi) { wlc_txq_info_t *p; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index a3c6fb884990..ee0081b307f1 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -433,7 +433,7 @@ struct wlc_hw_info { #ifdef WLC_SPLIT rpc_info_t *rpc; /* Handle to RPC module */ #endif - osl_t *osh; /* pointer to os handle */ + struct osl_info *osh; /* pointer to os handle */ bool _piomode; /* true if pio mode */ wlc_info_t *wlc; @@ -536,7 +536,7 @@ typedef struct wlc_txq_info { */ struct wlc_info { wlc_pub_t *pub; /* pointer to wlc public state */ - osl_t *osh; /* pointer to os handle */ + struct osl_info *osh; /* pointer to os handle */ struct wl_info *wl; /* pointer to os-specific private state */ d11regs_t *regs; /* pointer to device registers */ diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index f6ac5e99cf31..09be41d921c5 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -260,7 +260,7 @@ typedef struct wlc_pub { uint mac80211_state; uint unit; /* device instance number */ uint corerev; /* core revision */ - osl_t *osh; /* pointer to os handle */ + struct osl_info *osh; /* pointer to os handle */ si_t *sih; /* SB handle (cookie for siutils calls) */ char *vars; /* "environment" name=value */ bool up; /* interface up and running */ @@ -493,8 +493,8 @@ extern const u8 wme_fifo2ac[]; /* common functions for every port */ extern void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, - bool piomode, osl_t *osh, void *regsva, uint bustype, - void *btparam, uint *perr); + bool piomode, struct osl_info *osh, void *regsva, + uint bustype, void *btparam, uint *perr); extern uint wlc_detach(struct wlc_info *wlc); extern int wlc_up(struct wlc_info *wlc); extern uint wlc_down(struct wlc_info *wlc); diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c index 9b1e6d961a72..499cf0366200 100644 --- a/drivers/staging/brcm80211/util/bcmotp.c +++ b/drivers/staging/brcm80211/util/bcmotp.c @@ -78,7 +78,7 @@ typedef struct { uint ccrev; /* chipc revision */ otp_fn_t *fn; /* OTP functions */ si_t *sih; /* Saved sb handle */ - osl_t *osh; + struct osl_info *osh; #ifdef BCMIPXOTP /* IPX OTP section */ @@ -570,7 +570,7 @@ static int hndotp_size(void *oh) static u16 hndotp_otpr(void *oh, chipcregs_t *cc, uint wn) { otpinfo_t *oi = (otpinfo_t *) oh; - osl_t *osh; + struct osl_info *osh; volatile u16 *ptr; ASSERT(wn < ((oi->size / 2) + OTP_RC_LIM_OFF)); @@ -585,7 +585,7 @@ static u16 hndotp_otpr(void *oh, chipcregs_t *cc, uint wn) static u16 hndotp_otproff(void *oh, chipcregs_t *cc, int woff) { otpinfo_t *oi = (otpinfo_t *) oh; - osl_t *osh; + struct osl_info *osh; volatile u16 *ptr; ASSERT(woff >= (-((int)oi->size / 2))); @@ -604,7 +604,7 @@ static u16 hndotp_read_bit(void *oh, chipcregs_t *cc, uint idx) otpinfo_t *oi = (otpinfo_t *) oh; uint k, row, col; u32 otpp, st; - osl_t *osh; + struct osl_info *osh; osh = si_osh(oi->sih); row = idx / 65; @@ -637,7 +637,7 @@ static void *hndotp_init(si_t *sih) otpinfo_t *oi; u32 cap = 0, clkdiv, otpdiv = 0; void *ret = NULL; - osl_t *osh; + struct osl_info *osh; oi = &otpinfo; diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 4f3d3ca1af79..7240e3c11c5c 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -67,29 +67,30 @@ extern uint _varsz; #define SROM_CIS_SINGLE 1 -static int initvars_srom_si(si_t *sih, osl_t *osh, void *curmap, char **vars, - uint *count); +static int initvars_srom_si(si_t *sih, struct osl_info *osh, void *curmap, + char **vars, uint *count); static void _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, varbuf_t *b); static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count); static int initvars_flash_si(si_t *sih, char **vars, uint *count); #ifdef BCMSDIO -static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count); -static int sprom_cmd_sdio(osl_t *osh, u8 cmd); -static int sprom_read_sdio(osl_t *osh, u16 addr, u16 *data); +static int initvars_cis_sdio(struct osl_info *osh, char **vars, uint *count); +static int sprom_cmd_sdio(struct osl_info *osh, u8 cmd); +static int sprom_read_sdio(struct osl_info *osh, u16 addr, u16 *data); #endif /* BCMSDIO */ -static int sprom_read_pci(osl_t *osh, si_t *sih, u16 *sprom, uint wordoff, - u16 *buf, uint nwords, bool check_crc); +static int sprom_read_pci(struct osl_info *osh, si_t *sih, u16 *sprom, + uint wordoff, u16 *buf, uint nwords, bool check_crc); #if defined(BCMNVRAMR) -static int otp_read_pci(osl_t *osh, si_t *sih, u16 *buf, uint bufsz); +static int otp_read_pci(struct osl_info *osh, si_t *sih, u16 *buf, uint bufsz); #endif -static u16 srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, u32 cmd, +static u16 srom_cc_cmd(si_t *sih, struct osl_info *osh, void *ccregs, u32 cmd, uint wordoff, u16 data); -static int initvars_table(osl_t *osh, char *start, char *end, char **vars, - uint *count); -static int initvars_flash(si_t *sih, osl_t *osh, char **vp, uint len); +static int initvars_table(struct osl_info *osh, char *start, char *end, + char **vars, uint *count); +static int initvars_flash(si_t *sih, struct osl_info *osh, char **vp, + uint len); /* Initialization of varbuf structure */ static void varbuf_init(varbuf_t *b, char *buf, uint size) @@ -156,7 +157,7 @@ static int varbuf_append(varbuf_t *b, const char *fmt, ...) * Initialize local vars from the right source for this platform. * Return 0 on success, nonzero on error. */ -int srom_var_init(si_t *sih, uint bustype, void *curmap, osl_t *osh, +int srom_var_init(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, char **vars, uint *count) { uint len; @@ -195,7 +196,7 @@ int srom_var_init(si_t *sih, uint bustype, void *curmap, osl_t *osh, /* support only 16-bit word read from srom */ int -srom_read(si_t *sih, uint bustype, void *curmap, osl_t *osh, +srom_read(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, uint byteoff, uint nbytes, u16 *buf, bool check_crc) { uint off, nw; @@ -377,7 +378,8 @@ u8 patch_pair; /* For dongle HW, accept partial calibration parameters */ #define BCMDONGLECASE(n) -int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count) +int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, + uint *count) { char eabuf[32]; char *base; @@ -1406,8 +1408,8 @@ int srom_parsecis(osl_t *osh, u8 *pcis[], uint ciscnt, char **vars, uint *count) * not in the bus cores. */ static u16 -srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, u32 cmd, uint wordoff, - u16 data) +srom_cc_cmd(si_t *sih, struct osl_info *osh, void *ccregs, u32 cmd, + uint wordoff, u16 data) { chipcregs_t *cc = (chipcregs_t *) ccregs; uint wait_cnt = 1000; @@ -1440,7 +1442,7 @@ srom_cc_cmd(si_t *sih, osl_t *osh, void *ccregs, u32 cmd, uint wordoff, * Return 0 on success, nonzero on error. */ static int -sprom_read_pci(osl_t *osh, si_t *sih, u16 *sprom, uint wordoff, +sprom_read_pci(struct osl_info *osh, si_t *sih, u16 *sprom, uint wordoff, u16 *buf, uint nwords, bool check_crc) { int err = 0; @@ -1500,7 +1502,7 @@ sprom_read_pci(osl_t *osh, si_t *sih, u16 *sprom, uint wordoff, } #if defined(BCMNVRAMR) -static int otp_read_pci(osl_t *osh, si_t *sih, u16 *buf, uint bufsz) +static int otp_read_pci(struct osl_info *osh, si_t *sih, u16 *buf, uint bufsz) { u8 *otp; uint sz = OTP_SZ_MAX / 2; /* size in words */ @@ -1548,8 +1550,8 @@ static int otp_read_pci(osl_t *osh, si_t *sih, u16 *buf, uint bufsz) * Create variable table from memory. * Return 0 on success, nonzero on error. */ -static int initvars_table(osl_t *osh, char *start, char *end, char **vars, - uint *count) +static int initvars_table(struct osl_info *osh, char *start, char *end, + char **vars, uint *count) { int c = (int)(end - start); @@ -1575,7 +1577,8 @@ static int initvars_table(osl_t *osh, char *start, char *end, char **vars, * of the table upon enter and to the end of the table upon exit when success. * Return 0 on success, nonzero on error. */ -static int initvars_flash(si_t *sih, osl_t *osh, char **base, uint len) +static int initvars_flash(si_t *sih, struct osl_info *osh, char **base, + uint len) { char *vp = *base; char *flash; @@ -1635,7 +1638,7 @@ static int initvars_flash(si_t *sih, osl_t *osh, char **base, uint len) */ static int initvars_flash_si(si_t *sih, char **vars, uint *count) { - osl_t *osh = si_osh(sih); + struct osl_info *osh = si_osh(sih); char *vp, *base; int err; @@ -1846,7 +1849,7 @@ static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count) u32 sr; varbuf_t b; char *vp, *base = NULL; - osl_t *osh = si_osh(sih); + struct osl_info *osh = si_osh(sih); bool flash = false; int err = 0; @@ -1987,7 +1990,7 @@ static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count) * Read the SDIO cis and call parsecis to initialize the vars. * Return 0 on success, nonzero on error. */ -static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count) +static int initvars_cis_sdio(struct osl_info *osh, char **vars, uint *count) { u8 *cis[SBSDIO_NUM_FUNCTION + 1]; uint fn, numfn; @@ -2021,7 +2024,7 @@ static int initvars_cis_sdio(osl_t *osh, char **vars, uint *count) } /* set SDIO sprom command register */ -static int sprom_cmd_sdio(osl_t *osh, u8 cmd) +static int sprom_cmd_sdio(struct osl_info *osh, u8 cmd) { u8 status = 0; uint wait_cnt = 1000; @@ -2041,7 +2044,7 @@ static int sprom_cmd_sdio(osl_t *osh, u8 cmd) } /* read a word from the SDIO srom */ -static int sprom_read_sdio(osl_t *osh, u16 addr, u16 *data) +static int sprom_read_sdio(struct osl_info *osh, u16 addr, u16 *data) { u8 addr_l, addr_h, data_l, data_h; @@ -2069,8 +2072,8 @@ static int sprom_read_sdio(osl_t *osh, u16 addr, u16 *data) } #endif /* BCMSDIO */ -static int initvars_srom_si(si_t *sih, osl_t *osh, void *curmap, char **vars, - uint *varsz) +static int initvars_srom_si(si_t *sih, struct osl_info *osh, void *curmap, + char **vars, uint *varsz) { /* Search flash nvram section for srom variables */ return initvars_flash_si(sih, vars, varsz); diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 869d34c420d2..83f96cdfe771 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -33,7 +33,8 @@ #include /* copy a buffer into a pkt buffer chain */ -uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf) +uint pktfrombuf(struct osl_info *osh, void *p, uint offset, int len, + unsigned char *buf) { uint n, ret = 0; @@ -60,7 +61,7 @@ uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf) return ret; } /* return total length of buffer chain */ -uint BCMFASTPATH pkttotlen(osl_t *osh, void *p) +uint BCMFASTPATH pkttotlen(struct osl_info *osh, void *p) { uint total; @@ -185,7 +186,7 @@ void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) } #ifdef BRCM_FULLMAC -void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir) +void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir) { struct pktq_prec *q; void *p; @@ -204,7 +205,7 @@ void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir) q->tail = NULL; } -void pktq_flush(osl_t *osh, struct pktq *pq, bool dir) +void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir) { int prec; for (prec = 0; prec < pq->num_prec; prec++) @@ -213,8 +214,8 @@ void pktq_flush(osl_t *osh, struct pktq *pq, bool dir) } #else /* !BRCM_FULLMAC */ void -pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, - int arg) +pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir, + ifpkt_cb_t fn, int arg) { struct pktq_prec *q; void *p, *prev = NULL; @@ -245,7 +246,8 @@ pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, } } -void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) +void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir, + ifpkt_cb_t fn, int arg) { int prec; for (prec = 0; prec < pq->num_prec; prec++) @@ -405,7 +407,7 @@ int getintvar(char *vars, const char *name) #if defined(BCMDBG) /* pretty hex print a pkt buffer chain */ -void prpkt(const char *msg, osl_t *osh, void *p0) +void prpkt(const char *msg, struct osl_info *osh, void *p0) { void *p; diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index b4dcb05705b3..a945156eb31f 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -223,7 +223,7 @@ static void _dma_counterreset(dma_info_t *di); static void _dma_fifoloopbackenable(dma_info_t *di); static uint _dma_ctrlflags(dma_info_t *di, uint mask, uint flags); static u8 dma_align_sizetobits(uint size); -static void *dma_ringalloc(osl_t *osh, u32 boundary, uint size, +static void *dma_ringalloc(struct osl_info *osh, u32 boundary, uint size, u16 *alignbits, uint *alloced, dmaaddr_t *descpa, osldma_t **dmah); @@ -247,7 +247,7 @@ static bool dma32_txstopped(dma_info_t *di); static bool dma32_rxstopped(dma_info_t *di); static bool dma32_rxenabled(dma_info_t *di); -static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs); +static bool _dma32_addrext(struct osl_info *osh, dma32regs_t *dma32regs); /* Prototypes for 64-bit routines */ static bool dma64_alloc(dma_info_t *di, uint direction); @@ -271,7 +271,7 @@ static void dma64_txreclaim(dma_info_t *di, txd_range_t range); static bool dma64_txstopped(dma_info_t *di); static bool dma64_rxstopped(dma_info_t *di); static bool dma64_rxenabled(dma_info_t *di); -static bool _dma64_addrext(osl_t *osh, dma64regs_t *dma64regs); +static bool _dma64_addrext(struct osl_info *osh, dma64regs_t *dma64regs); static inline u32 parity32(u32 data); @@ -369,10 +369,10 @@ static const di_fcn_t dma32proc = { 39 }; -hnddma_t *dma_attach(osl_t *osh, char *name, si_t *sih, void *dmaregstx, - void *dmaregsrx, uint ntxd, uint nrxd, uint rxbufsize, - int rxextheadroom, uint nrxpost, uint rxoffset, - uint *msg_level) +hnddma_t *dma_attach(struct osl_info *osh, char *name, si_t *sih, + void *dmaregstx, void *dmaregsrx, uint ntxd, + uint nrxd, uint rxbufsize, int rxextheadroom, + uint nrxpost, uint rxoffset, uint *msg_level) { dma_info_t *di; uint size; @@ -664,7 +664,7 @@ dma64_dd_upd(dma_info_t *di, dma64dd_t *ddring, dmaaddr_t pa, uint outidx, } } -static bool _dma32_addrext(osl_t *osh, dma32regs_t *dma32regs) +static bool _dma32_addrext(struct osl_info *osh, dma32regs_t *dma32regs) { u32 w; @@ -1373,7 +1373,7 @@ static unsigned long _dma_getvar(dma_info_t *di, const char *name) return 0; } -void dma_txpioloopback(osl_t *osh, dma32regs_t *regs) +void dma_txpioloopback(struct osl_info *osh, dma32regs_t *regs) { OR_REG(osh, ®s->control, XC_LE); } @@ -1396,7 +1396,7 @@ u8 dma_align_sizetobits(uint size) * descriptor ring size aligned location. This will ensure that the ring will * not cross page boundary */ -static void *dma_ringalloc(osl_t *osh, u32 boundary, uint size, +static void *dma_ringalloc(struct osl_info *osh, u32 boundary, uint size, u16 *alignbits, uint *alloced, dmaaddr_t *descpa, osldma_t **dmah) { @@ -2564,7 +2564,7 @@ static void *BCMFASTPATH dma64_getnextrxp(dma_info_t *di, bool forceall) return rxp; } -static bool _dma64_addrext(osl_t *osh, dma64regs_t * dma64regs) +static bool _dma64_addrext(struct osl_info *osh, dma64regs_t * dma64regs) { u32 w; OR_REG(osh, &dma64regs->control, D64_XC_AE); @@ -2655,7 +2655,7 @@ static void dma64_txrotate(dma_info_t *di) uint dma_addrwidth(si_t *sih, void *dmaregs) { dma32regs_t *dma32regs; - osl_t *osh; + struct osl_info *osh; osh = si_osh(sih); diff --git a/drivers/staging/brcm80211/util/hndpmu.c b/drivers/staging/brcm80211/util/hndpmu.c index 6fb256bc5549..5b6fa72b99e8 100644 --- a/drivers/staging/brcm80211/util/hndpmu.c +++ b/drivers/staging/brcm80211/util/hndpmu.c @@ -44,23 +44,23 @@ #define PMU_NONE(args) /* PLL controls/clocks */ -static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, +static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, u32 xtal); -static u32 si_pmu1_cpuclk0(si_t *sih, osl_t *osh, chipcregs_t *cc); -static u32 si_pmu1_alpclk0(si_t *sih, osl_t *osh, chipcregs_t *cc); +static u32 si_pmu1_cpuclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc); +static u32 si_pmu1_alpclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc); /* PMU resources */ static bool si_pmu_res_depfltr_bb(si_t *sih); static bool si_pmu_res_depfltr_ncb(si_t *sih); static bool si_pmu_res_depfltr_paldo(si_t *sih); static bool si_pmu_res_depfltr_npaldo(si_t *sih); -static u32 si_pmu_res_deps(si_t *sih, osl_t *osh, chipcregs_t *cc, +static u32 si_pmu_res_deps(si_t *sih, struct osl_info *osh, chipcregs_t *cc, u32 rsrcs, bool all); -static uint si_pmu_res_uptime(si_t *sih, osl_t *osh, chipcregs_t *cc, +static uint si_pmu_res_uptime(si_t *sih, struct osl_info *osh, chipcregs_t *cc, u8 rsrc); static void si_pmu_res_masks(si_t *sih, u32 * pmin, u32 * pmax); static void si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, - osl_t *osh, u8 spuravoid); + struct osl_info *osh, u8 spuravoid); static void si_pmu_set_4330_plldivs(si_t *sih); @@ -105,7 +105,7 @@ void si_pmu_pllupd(si_t *sih) } /* Setup switcher voltage */ -void si_pmu_set_switcher_voltage(si_t *sih, osl_t *osh, u8 bb_voltage, +void si_pmu_set_switcher_voltage(si_t *sih, struct osl_info *osh, u8 bb_voltage, u8 rf_voltage) { chipcregs_t *cc; @@ -128,7 +128,7 @@ void si_pmu_set_switcher_voltage(si_t *sih, osl_t *osh, u8 bb_voltage, si_setcoreidx(sih, origidx); } -void si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, u8 ldo, u8 voltage) +void si_pmu_set_ldo_voltage(si_t *sih, struct osl_info *osh, u8 ldo, u8 voltage) { u8 sr_cntl_shift = 0, rc_shift = 0, shift = 0, mask = 0; u8 addr = 0; @@ -186,7 +186,7 @@ void si_pmu_set_ldo_voltage(si_t *sih, osl_t *osh, u8 ldo, u8 voltage) /* d11 slow to fast clock transition time in slow clock cycles */ #define D11SCC_SLOW2FAST_TRANSITION 2 -u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh) +u16 si_pmu_fast_pwrup_delay(si_t *sih, struct osl_info *osh) { uint delay = PMU_MAX_TRANSITION_DLY; chipcregs_t *cc; @@ -263,7 +263,7 @@ u16 si_pmu_fast_pwrup_delay(si_t *sih, osl_t *osh) return (u16) delay; } -u32 si_pmu_force_ilp(si_t *sih, osl_t *osh, bool force) +u32 si_pmu_force_ilp(si_t *sih, struct osl_info *osh, bool force) { chipcregs_t *cc; uint origidx; @@ -681,7 +681,7 @@ static void si_pmu_res_masks(si_t *sih, u32 * pmin, u32 * pmax) } /* initialize PMU resources */ -void si_pmu_res_init(si_t *sih, osl_t *osh) +void si_pmu_res_init(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -1182,7 +1182,7 @@ static u32 si_pmu1_pllfvco0(si_t *sih) /* query alp/xtal clock frequency */ static u32 -si_pmu1_alpclk0(si_t *sih, osl_t *osh, chipcregs_t *cc) +si_pmu1_alpclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc) { const pmu1_xtaltab0_t *xt; u32 xf; @@ -1207,7 +1207,8 @@ si_pmu1_alpclk0(si_t *sih, osl_t *osh, chipcregs_t *cc) * case the xtal frequency is unknown to the s/w so we need to call * si_pmu1_xtaldef0() wherever it is needed to return a default value. */ -static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal) +static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, + u32 xtal) { const pmu1_xtaltab0_t *xt; u32 tmp; @@ -1452,7 +1453,7 @@ static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 xtal) /* query the CPU clock frequency */ static u32 -si_pmu1_cpuclk0(si_t *sih, osl_t *osh, chipcregs_t *cc) +si_pmu1_cpuclk0(si_t *sih, struct osl_info *osh, chipcregs_t *cc) { u32 tmp, m1div; #ifdef BCMDBG @@ -1506,7 +1507,7 @@ si_pmu1_cpuclk0(si_t *sih, osl_t *osh, chipcregs_t *cc) } /* initialize PLL */ -void si_pmu_pll_init(si_t *sih, osl_t *osh, uint xtalfreq) +void si_pmu_pll_init(si_t *sih, struct osl_info *osh, uint xtalfreq) { chipcregs_t *cc; uint origidx; @@ -1559,7 +1560,7 @@ void si_pmu_pll_init(si_t *sih, osl_t *osh, uint xtalfreq) } /* query alp/xtal clock frequency */ -u32 si_pmu_alp_clock(si_t *sih, osl_t *osh) +u32 si_pmu_alp_clock(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -1620,7 +1621,7 @@ u32 si_pmu_alp_clock(si_t *sih, osl_t *osh) * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. */ static u32 -si_pmu5_clock(si_t *sih, osl_t *osh, chipcregs_t *cc, uint pll0, +si_pmu5_clock(si_t *sih, struct osl_info *osh, chipcregs_t *cc, uint pll0, uint m) { u32 tmp, div, ndiv, p1, p2, fc; @@ -1673,7 +1674,7 @@ si_pmu5_clock(si_t *sih, osl_t *osh, chipcregs_t *cc, uint pll0, /* For designs that feed the same clock to both backplane * and CPU just return the CPU clock speed. */ -u32 si_pmu_si_clock(si_t *sih, osl_t *osh) +u32 si_pmu_si_clock(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -1752,7 +1753,7 @@ u32 si_pmu_si_clock(si_t *sih, osl_t *osh) } /* query CPU clock frequency */ -u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh) +u32 si_pmu_cpu_clock(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -1796,7 +1797,7 @@ u32 si_pmu_cpu_clock(si_t *sih, osl_t *osh) } /* query memory clock frequency */ -u32 si_pmu_mem_clock(si_t *sih, osl_t *osh) +u32 si_pmu_mem_clock(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -1845,7 +1846,7 @@ u32 si_pmu_mem_clock(si_t *sih, osl_t *osh) static u32 ilpcycles_per_sec; -u32 si_pmu_ilp_clock(si_t *sih, osl_t *osh) +u32 si_pmu_ilp_clock(si_t *sih, struct osl_info *osh) { if (ISSIM_ENAB(sih)) return ILP_CLOCK; @@ -1909,7 +1910,7 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) void -si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, +si_sdiod_drive_strength_init(si_t *sih, struct osl_info *osh, u32 drivestrength) { chipcregs_t *cc; uint origidx, intr_val = 0; @@ -1980,7 +1981,7 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, } /* initialize PMU */ -void si_pmu_init(si_t *sih, osl_t *osh) +void si_pmu_init(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -2012,7 +2013,7 @@ void si_pmu_init(si_t *sih, osl_t *osh) /* Return up time in ILP cycles for the given resource. */ static uint -si_pmu_res_uptime(si_t *sih, osl_t *osh, chipcregs_t *cc, +si_pmu_res_uptime(si_t *sih, struct osl_info *osh, chipcregs_t *cc, u8 rsrc) { u32 deps; uint up, i, dup, dmax; @@ -2049,7 +2050,7 @@ si_pmu_res_uptime(si_t *sih, osl_t *osh, chipcregs_t *cc, /* Return dependancies (direct or all/indirect) for the given resources */ static u32 -si_pmu_res_deps(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 rsrcs, +si_pmu_res_deps(si_t *sih, struct osl_info *osh, chipcregs_t *cc, u32 rsrcs, bool all) { u32 deps = 0; @@ -2069,7 +2070,7 @@ si_pmu_res_deps(si_t *sih, osl_t *osh, chipcregs_t *cc, u32 rsrcs, } /* power up/down OTP through PMU resources */ -void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on) +void si_pmu_otp_power(si_t *sih, struct osl_info *osh, bool on) { chipcregs_t *cc; uint origidx; @@ -2139,7 +2140,7 @@ void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on) si_setcoreidx(sih, origidx); } -void si_pmu_rcal(si_t *sih, osl_t *osh) +void si_pmu_rcal(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; @@ -2222,7 +2223,7 @@ void si_pmu_rcal(si_t *sih, osl_t *osh) si_setcoreidx(sih, origidx); } -void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid) +void si_pmu_spuravoid(si_t *sih, struct osl_info *osh, u8 spuravoid) { chipcregs_t *cc; uint origidx, intr_val; @@ -2259,7 +2260,7 @@ void si_pmu_spuravoid(si_t *sih, osl_t *osh, u8 spuravoid) } static void -si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, osl_t *osh, +si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, struct osl_info *osh, u8 spuravoid) { u32 tmp = 0; @@ -2455,7 +2456,7 @@ si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, osl_t *osh, W_REG(osh, &cc->pmucontrol, tmp); } -bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh) +bool si_pmu_is_otp_powered(si_t *sih, struct osl_info *osh) { uint idx; chipcregs_t *cc; @@ -2507,9 +2508,9 @@ bool si_pmu_is_otp_powered(si_t *sih, osl_t *osh) void #if defined(BCMDBG) -si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable) +si_pmu_sprom_enable(si_t *sih, struct osl_info *osh, bool enable) #else -si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable) +si_pmu_sprom_enable(si_t *sih, struct osl_info *osh, bool enable) #endif { chipcregs_t *cc; @@ -2525,7 +2526,7 @@ si_pmu_sprom_enable(si_t *sih, osl_t *osh, bool enable) } /* initialize PMU chip controls and other chip level stuff */ -void si_pmu_chip_init(si_t *sih, osl_t *osh) +void si_pmu_chip_init(si_t *sih, struct osl_info *osh) { uint origidx; @@ -2547,7 +2548,7 @@ void si_pmu_chip_init(si_t *sih, osl_t *osh) } /* initialize PMU switch/regulators */ -void si_pmu_swreg_init(si_t *sih, osl_t *osh) +void si_pmu_swreg_init(si_t *sih, struct osl_info *osh) { ASSERT(sih->cccaps & CC_CAP_PMU); @@ -2591,7 +2592,7 @@ void si_pmu_radio_enable(si_t *sih, bool enable) /* Wait for a particular clock level to be on the backplane */ u32 -si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, u32 clk, +si_pmu_waitforclk_on_backplane(si_t *sih, struct osl_info *osh, u32 clk, u32 delay) { chipcregs_t *cc; @@ -2620,7 +2621,7 @@ si_pmu_waitforclk_on_backplane(si_t *sih, osl_t *osh, u32 clk, #define EXT_ILP_HZ 32768 -u32 si_pmu_measure_alpclk(si_t *sih, osl_t *osh) +u32 si_pmu_measure_alpclk(si_t *sih, struct osl_info *osh) { chipcregs_t *cc; uint origidx; diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index eb5d285efc04..e6e52f660780 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -36,14 +36,14 @@ /* Global ASSERT type flag */ u32 g_assert_type; -osl_t *osl_attach(void *pdev, uint bustype) +struct osl_info *osl_attach(void *pdev, uint bustype) { - osl_t *osh; + struct osl_info *osh; - osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); + osh = kmalloc(sizeof(struct osl_info), GFP_ATOMIC); ASSERT(osh); - bzero(osh, sizeof(osl_t)); + bzero(osh, sizeof(struct osl_info)); osh->magic = OS_HANDLE_MAGIC; osh->pdev = pdev; @@ -70,7 +70,7 @@ osl_t *osl_attach(void *pdev, uint bustype) return osh; } -void osl_detach(osl_t *osh) +void osl_detach(struct osl_info *osh) { if (osh == NULL) return; @@ -79,7 +79,7 @@ void osl_detach(osl_t *osh) kfree(osh); } -void *BCMFASTPATH osl_pktget(osl_t *osh, uint len) +void *BCMFASTPATH osl_pktget(struct osl_info *osh, uint len) { struct sk_buff *skb; @@ -95,7 +95,7 @@ void *BCMFASTPATH osl_pktget(osl_t *osh, uint len) } /* Free the driver packet. Free the tag if present */ -void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send) +void BCMFASTPATH osl_pktfree(struct osl_info *osh, void *p, bool send) { struct sk_buff *skb, *nskb; int nest = 0; @@ -128,20 +128,21 @@ void BCMFASTPATH osl_pktfree(osl_t *osh, void *p, bool send) } } -u32 osl_pci_read_config(osl_t *osh, uint offset, uint size) +u32 osl_pci_read_config(struct osl_info *osh, uint offset, uint size) { uint val; pci_read_config_dword(osh->pdev, offset, &val); return val; } -void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) +void osl_pci_write_config(struct osl_info *osh, uint offset, uint size, + uint val) { pci_write_config_dword(osh->pdev, offset, val); } /* return bus # for the pci device pointed by osh->pdev */ -uint osl_pci_bus(osl_t *osh) +uint osl_pci_bus(struct osl_info *osh) { ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); @@ -149,14 +150,14 @@ uint osl_pci_bus(osl_t *osh) } /* return slot # for the pci device pointed by osh->pdev */ -uint osl_pci_slot(osl_t *osh) +uint osl_pci_slot(struct osl_info *osh) { ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); } -void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits, +void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, u16 align_bits, uint *alloced, unsigned long *pap) { ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); @@ -170,14 +171,16 @@ void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits, return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap); } -void osl_dma_free_consistent(osl_t *osh, void *va, uint size, unsigned long pa) +void osl_dma_free_consistent(struct osl_info *osh, void *va, uint size, + unsigned long pa) { ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa); } -uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction) +uint BCMFASTPATH osl_dma_map(struct osl_info *osh, void *va, uint size, + int direction) { int dir; @@ -186,7 +189,8 @@ uint BCMFASTPATH osl_dma_map(osl_t *osh, void *va, uint size, int direction) return pci_map_single(osh->pdev, va, size, dir); } -void BCMFASTPATH osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) +void BCMFASTPATH osl_dma_unmap(struct osl_info *osh, uint pa, uint size, + int direction) { int dir; @@ -243,7 +247,7 @@ void osl_assert(char *exp, char *file, int line) #endif /* defined(BCMDBG_ASSERT) */ #if defined(BCMSDIO) && !defined(BRCM_FULLMAC) -u8 osl_readb(osl_t *osh, volatile u8 *r) +u8 osl_readb(struct osl_info *osh, volatile u8 *r) { osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; @@ -251,7 +255,7 @@ u8 osl_readb(osl_t *osh, volatile u8 *r) return (u8) ((rreg) (ctx, (void *)r, sizeof(u8))); } -u16 osl_readw(osl_t *osh, volatile u16 *r) +u16 osl_readw(struct osl_info *osh, volatile u16 *r) { osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; @@ -259,7 +263,7 @@ u16 osl_readw(osl_t *osh, volatile u16 *r) return (u16) ((rreg) (ctx, (void *)r, sizeof(u16))); } -u32 osl_readl(osl_t *osh, volatile u32 *r) +u32 osl_readl(struct osl_info *osh, volatile u32 *r) { osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; @@ -267,7 +271,7 @@ u32 osl_readl(osl_t *osh, volatile u32 *r) return (u32) ((rreg) (ctx, (void *)r, sizeof(u32))); } -void osl_writeb(osl_t *osh, volatile u8 *r, u8 v) +void osl_writeb(struct osl_info *osh, volatile u8 *r, u8 v) { osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; @@ -275,7 +279,7 @@ void osl_writeb(osl_t *osh, volatile u8 *r, u8 v) ((wreg) (ctx, (void *)r, v, sizeof(u8))); } -void osl_writew(osl_t *osh, volatile u16 *r, u16 v) +void osl_writew(struct osl_info *osh, volatile u16 *r, u16 v) { osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; @@ -283,7 +287,7 @@ void osl_writew(osl_t *osh, volatile u16 *r, u16 v) ((wreg) (ctx, (void *)r, v, sizeof(u16))); } -void osl_writel(osl_t *osh, volatile u32 *r, u32 v) +void osl_writel(struct osl_info *osh, volatile u32 *r, u32 v) { osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; diff --git a/drivers/staging/brcm80211/util/nicpci.c b/drivers/staging/brcm80211/util/nicpci.c index 169a4287ee63..8a7b71ee93d3 100644 --- a/drivers/staging/brcm80211/util/nicpci.c +++ b/drivers/staging/brcm80211/util/nicpci.c @@ -35,7 +35,7 @@ typedef struct { } regs; /* Memory mapped register to the core */ si_t *sih; /* System interconnect handle */ - osl_t *osh; /* OSL handle */ + struct osl_info *osh; /* OSL handle */ u8 pciecap_lcreg_offset; /* PCIE capability LCreg offset in the config space */ bool pcie_pr42767; u8 pcie_polarity; @@ -107,7 +107,7 @@ static bool pcicore_pmecap(pcicore_info_t *pi); /* Initialize the PCI core. It's caller's responsibility to make sure that this is done * only once */ -void *pcicore_init(si_t *sih, osl_t *osh, void *regs) +void *pcicore_init(si_t *sih, struct osl_info *osh, void *regs) { pcicore_info_t *pi; @@ -149,8 +149,8 @@ void pcicore_deinit(void *pch) /* return cap_offset if requested capability exists in the PCI config space */ /* Note that it's caller's responsibility to make sure it's a pci bus */ u8 -pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, unsigned char *buf, - u32 *buflen) +pcicore_find_pci_capability(struct osl_info *osh, u8 req_cap_id, + unsigned char *buf, u32 *buflen) { u8 cap_id; u8 cap_ptr = 0; @@ -210,7 +210,8 @@ pcicore_find_pci_capability(osl_t *osh, u8 req_cap_id, unsigned char *buf, /* ***** Register Access API */ uint -pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset) +pcie_readreg(struct osl_info *osh, sbpcieregs_t *pcieregs, uint addrtype, + uint offset) { uint retval = 0xFFFFFFFF; @@ -236,8 +237,8 @@ pcie_readreg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset) } uint -pcie_writereg(osl_t *osh, sbpcieregs_t *pcieregs, uint addrtype, uint offset, - uint val) +pcie_writereg(struct osl_info *osh, sbpcieregs_t *pcieregs, uint addrtype, + uint offset, uint val) { ASSERT(pcieregs != NULL); @@ -393,7 +394,7 @@ static void pcie_extendL1timer(pcicore_info_t *pi, bool extend) { u32 w; si_t *sih = pi->sih; - osl_t *osh = pi->osh; + struct osl_info *osh = pi->osh; sbpcieregs_t *pcieregs = pi->regs.pcieregs; if (!PCIE_PUB(sih) || sih->buscorerev < 7) @@ -577,7 +578,7 @@ static void pcie_war_noplldown(pcicore_info_t *pi) static void pcie_war_pci_setup(pcicore_info_t *pi) { si_t *sih = pi->sih; - osl_t *osh = pi->osh; + struct osl_info *osh = pi->osh; sbpcieregs_t *pcieregs = pi->regs.pcieregs; u32 w; @@ -718,7 +719,7 @@ void pcicore_down(void *pch, int state) /* ***** Wake-on-wireless-LAN (WOWL) support functions ***** */ /* Just uses PCI config accesses to find out, when needed before sb_attach is done */ -bool pcicore_pmecap_fast(osl_t *osh) +bool pcicore_pmecap_fast(struct osl_info *osh) { u8 cap_ptr; u32 pmecap; @@ -842,7 +843,7 @@ pcicore_pciereg(void *pch, u32 offset, u32 mask, u32 val, uint type) u32 reg_val = 0; pcicore_info_t *pi = (pcicore_info_t *) pch; sbpcieregs_t *pcieregs = pi->regs.pcieregs; - osl_t *osh = pi->osh; + struct osl_info *osh = pi->osh; if (mask) { PCI_ERROR(("PCIEREG: 0x%x writeval 0x%x\n", offset, val)); diff --git a/drivers/staging/brcm80211/util/nvram/nvram_ro.c b/drivers/staging/brcm80211/util/nvram/nvram_ro.c index f80375cd6801..2521c5b19192 100644 --- a/drivers/staging/brcm80211/util/nvram/nvram_ro.c +++ b/drivers/staging/brcm80211/util/nvram/nvram_ro.c @@ -49,7 +49,7 @@ static char *findvar(char *vars, char *lim, const char *name); /* copy flash to ram */ static void get_flash_nvram(si_t *sih, struct nvram_header *nvh) { - osl_t *osh; + struct osl_info *osh; uint nvs, bufsz; vars_t *new; diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 3b99293307ea..4d2df4977727 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -57,7 +57,7 @@ #endif /* local prototypes */ -static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, +static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz); static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, @@ -85,8 +85,8 @@ static u32 si_gpioreservation; * vars - pointer to a pointer area for "environment" variables * varsz - pointer to int to return the size of the vars */ -si_t *si_attach(uint devid, osl_t *osh, void *regs, uint bustype, void *sdh, - char **vars, uint *varsz) +si_t *si_attach(uint devid, struct osl_info *osh, void *regs, uint bustype, + void *sdh, char **vars, uint *varsz) { si_info_t *sii; @@ -368,7 +368,7 @@ static __used void si_nvram_process(si_info_t *sii, char *pvars) /* this is will make Sonics calls directly, since Sonics is no longer supported in the Si abstraction */ /* this has been customized for the bcm 4329 ONLY */ #ifdef BCMSDIO -static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, +static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz) { @@ -503,7 +503,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, } #else /* BCMSDIO */ -static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, +static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, void *regs, uint bustype, void *sdh, char **vars, uint *varsz) { -- cgit v1.2.3 From 93760716840a3feada381786f2defbd47a8099de Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 16 Nov 2010 17:41:15 -0800 Subject: staging: brcm80211: nicpci.c: replace osl based PCI calls with native linux pci calls Get rid of the private PCI access routines and replace with standard calls from linux/pci.h in nicpci.c (The private versions are still used in siutils.c... for now) Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/util/nicpci.c | 96 ++++++++++++--------------------- 1 file changed, 33 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/util/nicpci.c b/drivers/staging/brcm80211/util/nicpci.c index 8a7b71ee93d3..2127cc903223 100644 --- a/drivers/staging/brcm80211/util/nicpci.c +++ b/drivers/staging/brcm80211/util/nicpci.c @@ -71,35 +71,6 @@ static bool pcicore_pmecap(pcicore_info_t *pi); #define PCIE_ASPM(sih) ((PCIE_PUB(sih)) && (((sih)->buscorerev >= 3) && ((sih)->buscorerev <= 5))) -#define DWORD_ALIGN(x) (x & ~(0x03)) -#define BYTE_POS(x) (x & 0x3) -#define WORD_POS(x) (x & 0x1) - -#define BYTE_SHIFT(x) (8 * BYTE_POS(x)) -#define WORD_SHIFT(x) (16 * WORD_POS(x)) - -#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF) -#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF) - -#define read_pci_cfg_byte(a) \ - (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff) - -#define read_pci_cfg_word(a) \ - (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff) - -#define write_pci_cfg_byte(a, val) do { \ - u32 tmpval; \ - tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \ - val << BYTE_POS(a); \ - OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ - } while (0) - -#define write_pci_cfg_word(a, val) do { \ - u32 tmpval; \ - tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \ - val << WORD_POS(a); \ - OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ - } while (0) /* delay needed between the mdio control/ mdiodata register data access */ #define PR28829_DELAY() udelay(10) @@ -158,29 +129,29 @@ pcicore_find_pci_capability(struct osl_info *osh, u8 req_cap_id, u8 byte_val; /* check for Header type 0 */ - byte_val = read_pci_cfg_byte(PCI_CFG_HDR); + pci_read_config_byte(osh->pdev, PCI_CFG_HDR, &byte_val); if ((byte_val & 0x7f) != PCI_HEADER_NORMAL) goto end; /* check if the capability pointer field exists */ - byte_val = read_pci_cfg_byte(PCI_CFG_STAT); + pci_read_config_byte(osh->pdev, PCI_CFG_STAT, &byte_val); if (!(byte_val & PCI_CAPPTR_PRESENT)) goto end; - cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR); + pci_read_config_byte(osh->pdev, PCI_CFG_CAPPTR, &cap_ptr); /* check if the capability pointer is 0x00 */ if (cap_ptr == 0x00) goto end; /* loop thr'u the capability list and see if the pcie capabilty exists */ - cap_id = read_pci_cfg_byte(cap_ptr); + pci_read_config_byte(osh->pdev, cap_ptr, &cap_id); while (cap_id != req_cap_id) { - cap_ptr = read_pci_cfg_byte((cap_ptr + 1)); + pci_read_config_byte(osh->pdev, cap_ptr + 1, &cap_ptr); if (cap_ptr == 0x00) break; - cap_id = read_pci_cfg_byte(cap_ptr); + pci_read_config_byte(osh->pdev, cap_ptr, &cap_id); } if (cap_id != req_cap_id) { goto end; @@ -199,7 +170,7 @@ pcicore_find_pci_capability(struct osl_info *osh, u8 req_cap_id, bufsize = SZPCR - cap_data; *buflen = bufsize; while (bufsize--) { - *buf = read_pci_cfg_byte(cap_data); + pci_read_config_byte(osh->pdev, cap_data, buf); cap_data++; buf++; } @@ -374,15 +345,15 @@ u8 pcie_clkreq(void *pch, u32 mask, u32 val) if (!offset) return 0; - reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, offset, ®_val); /* set operation */ if (mask) { if (val) reg_val |= PCIE_CLKREQ_ENAB; else reg_val &= ~PCIE_CLKREQ_ENAB; - OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(u32), reg_val); - reg_val = OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(u32)); + pci_write_config_dword(pi->osh->pdev, offset, reg_val); + pci_read_config_dword(pi->osh->pdev, offset, ®_val); } if (reg_val & PCIE_CLKREQ_ENAB) return 1; @@ -503,12 +474,12 @@ static void pcie_war_aspm_clkreq(pcicore_info_t *pi) W_REG(pi->osh, reg16, val16); - w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, - sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, pi->pciecap_lcreg_offset, + &w); w &= ~PCIE_ASPM_ENAB; w |= pi->pcie_war_aspm_ovr; - OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, - sizeof(u32), w); + pci_write_config_dword(pi->osh->pdev, + pi->pciecap_lcreg_offset, w); } reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5]; @@ -695,11 +666,9 @@ void pcicore_sleep(void *pch) if (!pi || !PCIE_ASPM(pi->sih)) return; - w = OSL_PCI_READ_CONFIG(pi->osh, pi->pciecap_lcreg_offset, - sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, pi->pciecap_lcreg_offset, &w); w &= ~PCIE_CAP_LCREG_ASPML1; - OSL_PCI_WRITE_CONFIG(pi->osh, pi->pciecap_lcreg_offset, sizeof(u32), - w); + pci_write_config_dword(pi->osh->pdev, pi->pciecap_lcreg_offset, w); pi->pcie_pr42767 = false; } @@ -731,7 +700,7 @@ bool pcicore_pmecap_fast(struct osl_info *osh) if (!cap_ptr) return false; - pmecap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(u32)); + pci_read_config_dword(osh->pdev, cap_ptr, &pmecap); return (pmecap & PME_CAP_PM_STATES) != 0; } @@ -754,9 +723,8 @@ static bool pcicore_pmecap(pcicore_info_t *pi) pi->pmecap_offset = cap_ptr; - pmecap = - OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset, - sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset, + &pmecap); /* At least one state can generate PME */ pi->pmecap = (pmecap & PME_CAP_PM_STATES) != 0; @@ -775,11 +743,11 @@ void pcicore_pmeen(void *pch) if (!pcicore_pmecap(pi)) return; - w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, - sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset + PME_CSR_OFFSET, + &w); w |= (PME_CSR_PME_EN); - OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, - sizeof(u32), w); + pci_write_config_dword(pi->osh->pdev, + pi->pmecap_offset + PME_CSR_OFFSET, w); } /* @@ -793,8 +761,8 @@ bool pcicore_pmestat(void *pch) if (!pcicore_pmecap(pi)) return false; - w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, - sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset + PME_CSR_OFFSET, + &w); return (w & PME_CSR_PME_STAT) == PME_CSR_PME_STAT; } @@ -809,22 +777,23 @@ void pcicore_pmeclr(void *pch) if (!pcicore_pmecap(pi)) return; - w = OSL_PCI_READ_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, - sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, pi->pmecap_offset + PME_CSR_OFFSET, + &w); PCI_ERROR(("pcicore_pci_pmeclr PMECSR : 0x%x\n", w)); /* PMESTAT is cleared by writing 1 to it */ w &= ~(PME_CSR_PME_EN); - OSL_PCI_WRITE_CONFIG(pi->osh, pi->pmecap_offset + PME_CSR_OFFSET, - sizeof(u32), w); + pci_write_config_dword(pi->osh->pdev, + pi->pmecap_offset + PME_CSR_OFFSET, w); } u32 pcie_lcreg(void *pch, u32 mask, u32 val) { pcicore_info_t *pi = (pcicore_info_t *) pch; u8 offset; + u32 tmpval; offset = pi->pciecap_lcreg_offset; if (!offset) @@ -832,9 +801,10 @@ u32 pcie_lcreg(void *pch, u32 mask, u32 val) /* set operation */ if (mask) - OSL_PCI_WRITE_CONFIG(pi->osh, offset, sizeof(u32), val); + pci_write_config_dword(pi->osh->pdev, offset, val); - return OSL_PCI_READ_CONFIG(pi->osh, offset, sizeof(u32)); + pci_read_config_dword(pi->osh->pdev, offset, &tmpval); + return tmpval; } u32 -- cgit v1.2.3 From 237a1a1aef91ab654988cb459d783ac0ee09d2ea Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 17 Nov 2010 11:54:35 +0300 Subject: Staging: ft1000-usb: freeing uninitialized pointer GCC complains that if (info->CardReady) is false we kfree() an uninitialized pointer. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 7b4963326e8c..76cee9e30624 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -650,7 +650,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, break; case IOCTL_SET_DPRAM_CMD: { - IOCTL_DPRAM_BLK *dpram_data; + IOCTL_DPRAM_BLK *dpram_data = NULL; //IOCTL_DPRAM_COMMAND dpram_command; u16 qtype; u16 msgsz; -- cgit v1.2.3 From 6f5a416216fe2c39171326897e074d417df1082b Mon Sep 17 00:00:00 2001 From: Yong Wang Date: Wed, 17 Nov 2010 22:08:28 +0800 Subject: staging: spectra: move all init logic into nand_pci_probe Currently there are some driver initialization logic that is not part of nand_pci_probe function. This will result in that part of driver initialization code executing even on platforms without the corresponding hardware which is always dangerous. Signed-off-by: Chuanxiao Dong Signed-off-by: Yong Wang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 56 ++++++------ drivers/staging/spectra/ffsport.h | 1 + drivers/staging/spectra/flash.c | 4 +- drivers/staging/spectra/lld_nand.c | 177 ++++++++++++++++++++----------------- 4 files changed, 127 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index c7932da03c56..c6b4a2d16850 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -729,34 +729,16 @@ static void create_sysfs_entry(struct device *dev) } */ -static int GLOB_SBD_init(void) +int register_spectra_ftl() { int i; - /* Set debug output level (0~3) here. 3 is most verbose */ - printk(KERN_ALERT "Spectra: %s\n", GLOB_version); - - mutex_init(&spectra_lock); - - GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME); - if (GLOB_SBD_majornum <= 0) { - printk(KERN_ERR "Unable to get the major %d for Spectra", - GLOB_SBD_majornum); - return -EBUSY; - } - - if (PASS != GLOB_FTL_Flash_Init()) { - printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. " - "Aborting\n"); - goto out_flash_register; - } - /* create_sysfs_entry(&dev->dev); */ if (PASS != GLOB_FTL_IdentifyDevice(&IdentifyDeviceData)) { printk(KERN_ERR "Spectra: Unable to Read Flash Device. " "Aborting\n"); - goto out_flash_register; + return -ENOMEM; } else { nand_dbg_print(NAND_DBG_WARN, "In GLOB_SBD_init: " "Num blocks=%d, pagesperblock=%d, " @@ -775,24 +757,46 @@ static int GLOB_SBD_init(void) } printk(KERN_ALERT "Spectra: block table has been found.\n"); + GLOB_SBD_majornum = register_blkdev(0, GLOB_SBD_NAME); + if (GLOB_SBD_majornum <= 0) { + printk(KERN_ERR "Unable to get the major %d for Spectra", + GLOB_SBD_majornum); + goto out_ftl_flash_register; + } + for (i = 0; i < NUM_DEVICES; i++) if (SBD_setup_device(&nand_device[i], i) == -ENOMEM) - goto out_ftl_flash_register; + goto out_blk_register; nand_dbg_print(NAND_DBG_DEBUG, "Spectra: module loaded with major number %d\n", GLOB_SBD_majornum); - return 0; + return PASS; +out_blk_register: + unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME); out_ftl_flash_register: GLOB_FTL_Cache_Release(); -out_flash_register: - GLOB_FTL_Flash_Release(); - unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME); printk(KERN_ERR "Spectra: Module load failed.\n"); - return -ENOMEM; + return FAIL; +} +EXPORT_SYMBOL_GPL(register_spectra_ftl); + +static int GLOB_SBD_init(void) +{ + /* Set debug output level (0~3) here. 3 is most verbose */ + printk(KERN_ALERT "Spectra: %s\n", GLOB_version); + + mutex_init(&spectra_lock); + + if (PASS != GLOB_FTL_Flash_Init()) { + printk(KERN_ERR "Spectra: Unable to Initialize Flash Device. " + "Aborting\n"); + return -ENODEV; + } + return 0; } static void __exit GLOB_SBD_exit(void) diff --git a/drivers/staging/spectra/ffsport.h b/drivers/staging/spectra/ffsport.h index 6c5d90c53430..85c0750612f6 100644 --- a/drivers/staging/spectra/ffsport.h +++ b/drivers/staging/spectra/ffsport.h @@ -80,5 +80,6 @@ extern int nand_debug_level; extern int GLOB_Calc_Used_Bits(u32 n); extern u64 GLOB_u64_Div(u64 addr, u32 divisor); extern u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type); +extern int register_spectra_ftl(void); #endif /* _FFSPORT_ */ diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index 4e6e451cd5c8..fb39c8ecf596 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -1258,9 +1258,7 @@ int GLOB_FTL_Flash_Init(void) g_SBDCmdIndex = 0; - GLOB_LLD_Flash_Init(); - - status = GLOB_LLD_Read_Device_ID(); + status = GLOB_LLD_Flash_Init(); return status; } diff --git a/drivers/staging/spectra/lld_nand.c b/drivers/staging/spectra/lld_nand.c index 0d647a8fd2b6..2263d3ea5456 100644 --- a/drivers/staging/spectra/lld_nand.c +++ b/drivers/staging/spectra/lld_nand.c @@ -2395,14 +2395,94 @@ static int nand_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) unsigned long csr_base; unsigned long csr_len; struct mrst_nand_info *pndev = &info; + u32 int_mask; nand_dbg_print(NAND_DBG_WARN, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); + FlashReg = ioremap_nocache(GLOB_HWCTL_REG_BASE, + GLOB_HWCTL_REG_SIZE); + if (!FlashReg) { + printk(KERN_ERR "Spectra: ioremap_nocache failed!"); + return -ENOMEM; + } + nand_dbg_print(NAND_DBG_WARN, + "Spectra: Remapped reg base address: " + "0x%p, len: %d\n", + FlashReg, GLOB_HWCTL_REG_SIZE); + + FlashMem = ioremap_nocache(GLOB_HWCTL_MEM_BASE, + GLOB_HWCTL_MEM_SIZE); + if (!FlashMem) { + printk(KERN_ERR "Spectra: ioremap_nocache failed!"); + iounmap(FlashReg); + return -ENOMEM; + } + nand_dbg_print(NAND_DBG_WARN, + "Spectra: Remapped flash base address: " + "0x%p, len: %d\n", + (void *)FlashMem, GLOB_HWCTL_MEM_SIZE); + + nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:" + "acc_clks: %d, re_2_we: %d, we_2_re: %d," + "addr_2_data: %d, rdwr_en_lo_cnt: %d, " + "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", + ioread32(FlashReg + ACC_CLKS), + ioread32(FlashReg + RE_2_WE), + ioread32(FlashReg + WE_2_RE), + ioread32(FlashReg + ADDR_2_DATA), + ioread32(FlashReg + RDWR_EN_LO_CNT), + ioread32(FlashReg + RDWR_EN_HI_CNT), + ioread32(FlashReg + CS_SETUP_CNT)); + + NAND_Flash_Reset(); + + iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); + +#if CMD_DMA + info.pcmds_num = 0; + info.flash_bank = 0; + info.cdma_num = 0; + int_mask = (DMA_INTR__DESC_COMP_CHANNEL0 | + DMA_INTR__DESC_COMP_CHANNEL1 | + DMA_INTR__DESC_COMP_CHANNEL2 | + DMA_INTR__DESC_COMP_CHANNEL3 | + DMA_INTR__MEMCOPY_DESC_COMP); + iowrite32(int_mask, FlashReg + DMA_INTR_EN); + iowrite32(0xFFFF, FlashReg + DMA_INTR); + + int_mask = (INTR_STATUS0__ECC_ERR | + INTR_STATUS0__PROGRAM_FAIL | + INTR_STATUS0__ERASE_FAIL); +#else + int_mask = INTR_STATUS0__DMA_CMD_COMP | + INTR_STATUS0__ECC_TRANSACTION_DONE | + INTR_STATUS0__ECC_ERR | + INTR_STATUS0__PROGRAM_FAIL | + INTR_STATUS0__ERASE_FAIL; +#endif + iowrite32(int_mask, FlashReg + INTR_EN0); + iowrite32(int_mask, FlashReg + INTR_EN1); + iowrite32(int_mask, FlashReg + INTR_EN2); + iowrite32(int_mask, FlashReg + INTR_EN3); + + /* Clear all status bits */ + iowrite32(0xFFFF, FlashReg + INTR_STATUS0); + iowrite32(0xFFFF, FlashReg + INTR_STATUS1); + iowrite32(0xFFFF, FlashReg + INTR_STATUS2); + iowrite32(0xFFFF, FlashReg + INTR_STATUS3); + + iowrite32(0x0F, FlashReg + RB_PIN_ENABLED); + iowrite32(CHIP_EN_DONT_CARE__FLAG, FlashReg + CHIP_ENABLE_DONT_CARE); + + /* Should set value for these registers when init */ + iowrite32(0, FlashReg + TWO_ROW_ADDR_CYCLES); + iowrite32(1, FlashReg + ECC_ENABLE); + enable_ecc = 1; ret = pci_enable_device(dev); if (ret) { printk(KERN_ERR "Spectra: pci_enable_device failed.\n"); - return ret; + goto failed_req_csr; } pci_set_master(dev); @@ -2461,12 +2541,26 @@ static int nand_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_set_drvdata(dev, pndev); + ret = GLOB_LLD_Read_Device_ID(); + if (ret) { + iounmap(pndev->ioaddr); + goto failed_remap_csr; + } + + ret = register_spectra_ftl(); + if (ret) { + iounmap(pndev->ioaddr); + goto failed_remap_csr; + } + return 0; failed_remap_csr: pci_release_regions(dev); failed_req_csr: pci_disable_device(dev); + iounmap(FlashMem); + iounmap(FlashReg); return ret; } @@ -2498,91 +2592,10 @@ static struct pci_driver nand_pci_driver = { int NAND_Flash_Init(void) { int retval; - u32 int_mask; nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); - FlashReg = ioremap_nocache(GLOB_HWCTL_REG_BASE, - GLOB_HWCTL_REG_SIZE); - if (!FlashReg) { - printk(KERN_ERR "Spectra: ioremap_nocache failed!"); - return -ENOMEM; - } - nand_dbg_print(NAND_DBG_WARN, - "Spectra: Remapped reg base address: " - "0x%p, len: %d\n", - FlashReg, GLOB_HWCTL_REG_SIZE); - - FlashMem = ioremap_nocache(GLOB_HWCTL_MEM_BASE, - GLOB_HWCTL_MEM_SIZE); - if (!FlashMem) { - printk(KERN_ERR "Spectra: ioremap_nocache failed!"); - iounmap(FlashReg); - return -ENOMEM; - } - nand_dbg_print(NAND_DBG_WARN, - "Spectra: Remapped flash base address: " - "0x%p, len: %d\n", - (void *)FlashMem, GLOB_HWCTL_MEM_SIZE); - - nand_dbg_print(NAND_DBG_DEBUG, "Dump timing register values:" - "acc_clks: %d, re_2_we: %d, we_2_re: %d," - "addr_2_data: %d, rdwr_en_lo_cnt: %d, " - "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", - ioread32(FlashReg + ACC_CLKS), - ioread32(FlashReg + RE_2_WE), - ioread32(FlashReg + WE_2_RE), - ioread32(FlashReg + ADDR_2_DATA), - ioread32(FlashReg + RDWR_EN_LO_CNT), - ioread32(FlashReg + RDWR_EN_HI_CNT), - ioread32(FlashReg + CS_SETUP_CNT)); - - NAND_Flash_Reset(); - - iowrite32(0, FlashReg + GLOBAL_INT_ENABLE); - -#if CMD_DMA - info.pcmds_num = 0; - info.flash_bank = 0; - info.cdma_num = 0; - int_mask = (DMA_INTR__DESC_COMP_CHANNEL0 | - DMA_INTR__DESC_COMP_CHANNEL1 | - DMA_INTR__DESC_COMP_CHANNEL2 | - DMA_INTR__DESC_COMP_CHANNEL3 | - DMA_INTR__MEMCOPY_DESC_COMP); - iowrite32(int_mask, FlashReg + DMA_INTR_EN); - iowrite32(0xFFFF, FlashReg + DMA_INTR); - - int_mask = (INTR_STATUS0__ECC_ERR | - INTR_STATUS0__PROGRAM_FAIL | - INTR_STATUS0__ERASE_FAIL); -#else - int_mask = INTR_STATUS0__DMA_CMD_COMP | - INTR_STATUS0__ECC_TRANSACTION_DONE | - INTR_STATUS0__ECC_ERR | - INTR_STATUS0__PROGRAM_FAIL | - INTR_STATUS0__ERASE_FAIL; -#endif - iowrite32(int_mask, FlashReg + INTR_EN0); - iowrite32(int_mask, FlashReg + INTR_EN1); - iowrite32(int_mask, FlashReg + INTR_EN2); - iowrite32(int_mask, FlashReg + INTR_EN3); - - /* Clear all status bits */ - iowrite32(0xFFFF, FlashReg + INTR_STATUS0); - iowrite32(0xFFFF, FlashReg + INTR_STATUS1); - iowrite32(0xFFFF, FlashReg + INTR_STATUS2); - iowrite32(0xFFFF, FlashReg + INTR_STATUS3); - - iowrite32(0x0F, FlashReg + RB_PIN_ENABLED); - iowrite32(CHIP_EN_DONT_CARE__FLAG, FlashReg + CHIP_ENABLE_DONT_CARE); - - /* Should set value for these registers when init */ - iowrite32(0, FlashReg + TWO_ROW_ADDR_CYCLES); - iowrite32(1, FlashReg + ECC_ENABLE); - enable_ecc = 1; - retval = pci_register_driver(&nand_pci_driver); if (retval) return -ENOMEM; -- cgit v1.2.3 From 63fcf10db218a89cbd1e34c47540c3e28706cff1 Mon Sep 17 00:00:00 2001 From: Yong Wang Date: Wed, 17 Nov 2010 22:09:54 +0800 Subject: staging: spectra: asynchronous init The spectra nand driver takes quite some time to initialize because it needs to scan the whole nand disk to find the latest block table. This patch initializes the spectra nand driver asynchronously so that other things in the kernel can initialize in parallel to the scanning operation. Signed-off-by: Yong Wang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index c6b4a2d16850..c3849e9b66d3 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -28,6 +28,7 @@ #include #include #include +#include /**** Helper functions used for Div, Remainder operation on u64 ****/ @@ -729,7 +730,7 @@ static void create_sysfs_entry(struct device *dev) } */ -int register_spectra_ftl() +static void register_spectra_ftl_async(void *unused, async_cookie_t cookie) { int i; @@ -738,7 +739,7 @@ int register_spectra_ftl() if (PASS != GLOB_FTL_IdentifyDevice(&IdentifyDeviceData)) { printk(KERN_ERR "Spectra: Unable to Read Flash Device. " "Aborting\n"); - return -ENOMEM; + return; } else { nand_dbg_print(NAND_DBG_WARN, "In GLOB_SBD_init: " "Num blocks=%d, pagesperblock=%d, " @@ -772,15 +773,19 @@ int register_spectra_ftl() "Spectra: module loaded with major number %d\n", GLOB_SBD_majornum); - return PASS; + return; out_blk_register: unregister_blkdev(GLOB_SBD_majornum, GLOB_SBD_NAME); out_ftl_flash_register: GLOB_FTL_Cache_Release(); printk(KERN_ERR "Spectra: Module load failed.\n"); +} - return FAIL; +int register_spectra_ftl() +{ + async_schedule(register_spectra_ftl_async, NULL); + return 0; } EXPORT_SYMBOL_GPL(register_spectra_ftl); -- cgit v1.2.3 From 24aee93c37fe7fa2aa2381d3017be478e9c55c47 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 17 Nov 2010 15:57:57 +0000 Subject: sst: remove rest of aava bits and aava related code This removes the remaining bit of aava dependent and related bits from driver Signed-off-by: Vinod Koul Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intelmid.h | 5 --- drivers/staging/intel_sst/intelmid_v1_control.c | 50 ------------------------- drivers/staging/intel_sst/intelmid_v2_control.c | 2 +- 3 files changed, 1 insertion(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intelmid.h b/drivers/staging/intel_sst/intelmid.h index 81e744816765..0ce103185848 100644 --- a/drivers/staging/intel_sst/intelmid.h +++ b/drivers/staging/intel_sst/intelmid.h @@ -178,9 +178,4 @@ extern struct snd_kcontrol_new snd_intelmad_controls_mrst[]; extern struct snd_kcontrol_new snd_intelmad_controls_mfld[]; extern struct snd_pmic_ops *intelmad_vendor_ops[]; -/* This is an enabler hook as the platform detection logic isn't yet - present and depends on some firmware and DMI support to detect AAVA - devices. It will vanish once the AAVA platform support is merged */ -#define is_aava() 0 - #endif /* __INTELMID_H */ diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c index 62a932bf809a..478cfecdefd7 100644 --- a/drivers/staging/intel_sst/intelmid_v1_control.c +++ b/drivers/staging/intel_sst/intelmid_v1_control.c @@ -134,56 +134,6 @@ static int mx_init_card(void) return sst_sc_reg_access(sc_access, PMIC_WRITE, 47); } -static int mx_init_capture_card(void) -{ - struct sc_reg_access sc_access[] = { - {0x206, 0x5a, 0x0}, - {0x207, 0xbe, 0x0}, - {0x208, 0x90, 0x0}, - {0x209, 0x32, 0x0}, - {0x20e, 0x22, 0x0}, - {0x210, 0x84, 0x0}, - {0x223, 0x20, 0x0}, - {0x226, 0xC0, 0x0}, - }; - - int retval = 0; - - retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 8); - if (0 != retval) { - /* pmic communication fails */ - pr_debug("pmic commn failed\n"); - return retval; - } - - pr_debug("Capture configuration complete!!\n"); - return 0; -} - -static int mx_init_playback_card(void) -{ - struct sc_reg_access sc_access[] = { - {0x206, 0x00, 0x0}, - {0x207, 0x00, 0x0}, - {0x208, 0x00, 0x0}, - {0x209, 0x51, 0x0}, - {0x20e, 0x51, 0x0}, - {0x210, 0x21, 0x0}, - {0x223, 0x01, 0x0}, - }; - int retval = 0; - - retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 9); - if (0 != retval) { - /* pmic communication fails */ - pr_debug("pmic commn failed\n"); - return retval; - } - - pr_debug("Playback configuration complete!!\n"); - return 0; -} - static int mx_enable_audiodac(int value) { struct sc_reg_access sc_access[3]; diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c index 81cb9d70870b..e38e89df6e84 100644 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ b/drivers/staging/intel_sst/intelmid_v2_control.c @@ -873,7 +873,7 @@ static int nc_set_selected_input_dev(u8 value) sc_access[2].mask = MASK6; sc_access[3].reg_addr = 0x109; sc_access[3].mask = MASK6; - sc_access[3].value = 0x40; + sc_access[3].value = 0x00; num_val = 4; break; default: -- cgit v1.2.3 From 6b6e39a6a8da7234c538d14c43d3583da8875f9c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 15 Nov 2010 23:13:18 +0100 Subject: driver-core: merge private parts of class and bus As classes and busses are pretty much the same thing, and we want to merge them together into a 'subsystem' in the future, let us share the same private data parts to make that merge easier. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 62 ++++++++++++++++++++------------------------------ drivers/base/bus.c | 13 +++++------ drivers/base/class.c | 38 +++++++++++++++---------------- drivers/base/core.c | 22 +++++++++--------- include/linux/device.h | 7 +++--- 5 files changed, 64 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/base/base.h b/drivers/base/base.h index 2ca7f5b7b824..19f49e41ce5d 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,31 +1,46 @@ /** - * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure. + * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. * - * @subsys - the struct kset that defines this bus. This is the main kobject - * @drivers_kset - the list of drivers associated with this bus - * @devices_kset - the list of devices associated with this bus + * @subsys - the struct kset that defines this subsystem + * @devices_kset - the list of devices associated + * + * @drivers_kset - the list of drivers associated * @klist_devices - the klist to iterate over the @devices_kset * @klist_drivers - the klist to iterate over the @drivers_kset * @bus_notifier - the bus notifier list for anything that cares about things - * on this bus. + * on this bus. * @bus - pointer back to the struct bus_type that this structure is associated - * with. + * with. + * + * @class_interfaces - list of class_interfaces associated + * @glue_dirs - "glue" directory to put in-between the parent device to + * avoid namespace conflicts + * @class_mutex - mutex to protect the children, devices, and interfaces lists. + * @class - pointer back to the struct class that this structure is associated + * with. * * This structure is the one that is the actual kobject allowing struct - * bus_type to be statically allocated safely. Nothing outside of the driver - * core should ever touch these fields. + * bus_type/class to be statically allocated safely. Nothing outside of the + * driver core should ever touch these fields. */ -struct bus_type_private { +struct subsys_private { struct kset subsys; - struct kset *drivers_kset; struct kset *devices_kset; + + struct kset *drivers_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus; + + struct list_head class_interfaces; + struct kset glue_dirs; + struct mutex class_mutex; + struct class *class; }; +#define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj) struct driver_private { struct kobject kobj; @@ -36,33 +51,6 @@ struct driver_private { }; #define to_driver(obj) container_of(obj, struct driver_private, kobj) - -/** - * struct class_private - structure to hold the private to the driver core portions of the class structure. - * - * @class_subsys - the struct kset that defines this class. This is the main kobject - * @class_devices - list of devices associated with this class - * @class_interfaces - list of class_interfaces associated with this class - * @class_dirs - "glue" directory for virtual devices associated with this class - * @class_mutex - mutex to protect the children, devices, and interfaces lists. - * @class - pointer back to the struct class that this structure is associated - * with. - * - * This structure is the one that is the actual kobject allowing struct - * class to be statically allocated safely. Nothing outside of the driver - * core should ever touch these fields. - */ -struct class_private { - struct kset class_subsys; - struct klist class_devices; - struct list_head class_interfaces; - struct kset class_dirs; - struct mutex class_mutex; - struct class *class; -}; -#define to_class(obj) \ - container_of(obj, struct class_private, class_subsys.kobj) - /** * struct device_private - structure to hold the private to the driver core portions of the device structure. * diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 33c270a64db7..e243bd49764b 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -20,7 +20,6 @@ #include "power/power.h" #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) -#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj) /* * sysfs bindings for drivers @@ -96,11 +95,11 @@ static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct bus_attribute *bus_attr = to_bus_attr(attr); - struct bus_type_private *bus_priv = to_bus(kobj); + struct subsys_private *subsys_priv = to_subsys_private(kobj); ssize_t ret = 0; if (bus_attr->show) - ret = bus_attr->show(bus_priv->bus, buf); + ret = bus_attr->show(subsys_priv->bus, buf); return ret; } @@ -108,11 +107,11 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct bus_attribute *bus_attr = to_bus_attr(attr); - struct bus_type_private *bus_priv = to_bus(kobj); + struct subsys_private *subsys_priv = to_subsys_private(kobj); ssize_t ret = 0; if (bus_attr->store) - ret = bus_attr->store(bus_priv->bus, buf, count); + ret = bus_attr->store(subsys_priv->bus, buf, count); return ret; } @@ -858,9 +857,9 @@ static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); int bus_register(struct bus_type *bus) { int retval; - struct bus_type_private *priv; + struct subsys_private *priv; - priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/base/class.c b/drivers/base/class.c index 7975a52bdf5b..4f1df2e8fd74 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -27,7 +27,7 @@ static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct class_attribute *class_attr = to_class_attr(attr); - struct class_private *cp = to_class(kobj); + struct subsys_private *cp = to_subsys_private(kobj); ssize_t ret = -EIO; if (class_attr->show) @@ -39,7 +39,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct class_attribute *class_attr = to_class_attr(attr); - struct class_private *cp = to_class(kobj); + struct subsys_private *cp = to_subsys_private(kobj); ssize_t ret = -EIO; if (class_attr->store) @@ -49,7 +49,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, static void class_release(struct kobject *kobj) { - struct class_private *cp = to_class(kobj); + struct subsys_private *cp = to_subsys_private(kobj); struct class *class = cp->class; pr_debug("class '%s': release.\n", class->name); @@ -65,7 +65,7 @@ static void class_release(struct kobject *kobj) static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj) { - struct class_private *cp = to_class(kobj); + struct subsys_private *cp = to_subsys_private(kobj); struct class *class = cp->class; return class->ns_type; @@ -82,7 +82,7 @@ static struct kobj_type class_ktype = { .child_ns_type = class_child_ns_type, }; -/* Hotplug events for classes go to the class class_subsys */ +/* Hotplug events for classes go to the class subsys */ static struct kset *class_kset; @@ -90,7 +90,7 @@ int class_create_file(struct class *cls, const struct class_attribute *attr) { int error; if (cls) - error = sysfs_create_file(&cls->p->class_subsys.kobj, + error = sysfs_create_file(&cls->p->subsys.kobj, &attr->attr); else error = -EINVAL; @@ -100,20 +100,20 @@ int class_create_file(struct class *cls, const struct class_attribute *attr) void class_remove_file(struct class *cls, const struct class_attribute *attr) { if (cls) - sysfs_remove_file(&cls->p->class_subsys.kobj, &attr->attr); + sysfs_remove_file(&cls->p->subsys.kobj, &attr->attr); } static struct class *class_get(struct class *cls) { if (cls) - kset_get(&cls->p->class_subsys); + kset_get(&cls->p->subsys); return cls; } static void class_put(struct class *cls) { if (cls) - kset_put(&cls->p->class_subsys); + kset_put(&cls->p->subsys); } static int add_class_attrs(struct class *cls) @@ -162,7 +162,7 @@ static void klist_class_dev_put(struct klist_node *n) int __class_register(struct class *cls, struct lock_class_key *key) { - struct class_private *cp; + struct subsys_private *cp; int error; pr_debug("device class '%s': registering\n", cls->name); @@ -170,11 +170,11 @@ int __class_register(struct class *cls, struct lock_class_key *key) cp = kzalloc(sizeof(*cp), GFP_KERNEL); if (!cp) return -ENOMEM; - klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put); + klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); INIT_LIST_HEAD(&cp->class_interfaces); - kset_init(&cp->class_dirs); + kset_init(&cp->glue_dirs); __mutex_init(&cp->class_mutex, "struct class mutex", key); - error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name); + error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); if (error) { kfree(cp); return error; @@ -187,15 +187,15 @@ int __class_register(struct class *cls, struct lock_class_key *key) #if defined(CONFIG_BLOCK) /* let the block class directory show up in the root of sysfs */ if (!sysfs_deprecated || cls != &block_class) - cp->class_subsys.kobj.kset = class_kset; + cp->subsys.kobj.kset = class_kset; #else - cp->class_subsys.kobj.kset = class_kset; + cp->subsys.kobj.kset = class_kset; #endif - cp->class_subsys.kobj.ktype = &class_ktype; + cp->subsys.kobj.ktype = &class_ktype; cp->class = cls; cls->p = cp; - error = kset_register(&cp->class_subsys); + error = kset_register(&cp->subsys); if (error) { kfree(cp); return error; @@ -210,7 +210,7 @@ void class_unregister(struct class *cls) { pr_debug("device class '%s': unregistering\n", cls->name); remove_class_attrs(cls); - kset_unregister(&cls->p->class_subsys); + kset_unregister(&cls->p->subsys); } static void class_create_release(struct class *cls) @@ -295,7 +295,7 @@ void class_dev_iter_init(struct class_dev_iter *iter, struct class *class, if (start) start_knode = &start->knode_class; - klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode); + klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode); iter->type = type; } EXPORT_SYMBOL_GPL(class_dev_iter_init); diff --git a/drivers/base/core.c b/drivers/base/core.c index 6ed645411c40..46ff6c251932 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -610,7 +610,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) dir->class = class; kobject_init(&dir->kobj, &class_dir_ktype); - dir->kobj.kset = &class->p->class_dirs; + dir->kobj.kset = &class->p->glue_dirs; retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); if (retval < 0) { @@ -635,7 +635,7 @@ static struct kobject *get_device_parent(struct device *dev, if (sysfs_deprecated && dev->class == &block_class) { if (parent && parent->class == &block_class) return &parent->kobj; - return &block_class.p->class_subsys.kobj; + return &block_class.p->subsys.kobj; } #endif @@ -654,13 +654,13 @@ static struct kobject *get_device_parent(struct device *dev, mutex_lock(&gdp_mutex); /* find our class-directory at the parent and reference it */ - spin_lock(&dev->class->p->class_dirs.list_lock); - list_for_each_entry(k, &dev->class->p->class_dirs.list, entry) + spin_lock(&dev->class->p->glue_dirs.list_lock); + list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } - spin_unlock(&dev->class->p->class_dirs.list_lock); + spin_unlock(&dev->class->p->glue_dirs.list_lock); if (kobj) { mutex_unlock(&gdp_mutex); return kobj; @@ -682,7 +682,7 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) { /* see if we live in a "glue" directory */ if (!glue_dir || !dev->class || - glue_dir->kset != &dev->class->p->class_dirs) + glue_dir->kset != &dev->class->p->glue_dirs) return; kobject_put(glue_dir); @@ -709,7 +709,7 @@ static int device_add_class_symlinks(struct device *dev) return 0; error = sysfs_create_link(&dev->kobj, - &dev->class->p->class_subsys.kobj, + &dev->class->p->subsys.kobj, "subsystem"); if (error) goto out; @@ -728,7 +728,7 @@ static int device_add_class_symlinks(struct device *dev) #endif /* link in the class directory pointing to the device */ - error = sysfs_create_link(&dev->class->p->class_subsys.kobj, + error = sysfs_create_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); if (error) goto out_device; @@ -756,7 +756,7 @@ static void device_remove_class_symlinks(struct device *dev) if (sysfs_deprecated && dev->class == &block_class) return; #endif - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); + sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); } /** @@ -947,7 +947,7 @@ int device_add(struct device *dev) mutex_lock(&dev->class->p->class_mutex); /* tie the class to the device */ klist_add_tail(&dev->knode_class, - &dev->class->p->class_devices); + &dev->class->p->klist_devices); /* notify any interfaces that the device is here */ list_for_each_entry(class_intf, @@ -1535,7 +1535,7 @@ int device_rename(struct device *dev, const char *new_name) } if (dev->class) { - error = sysfs_rename_link(&dev->class->p->class_subsys.kobj, + error = sysfs_rename_link(&dev->class->p->subsys.kobj, &dev->kobj, old_device_name, new_name); if (error) goto out; diff --git a/include/linux/device.h b/include/linux/device.h index dd4895313468..1e2d335ab683 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -30,9 +30,8 @@ struct device_private; struct device_driver; struct driver_private; struct class; -struct class_private; +struct subsys_private; struct bus_type; -struct bus_type_private; struct device_node; struct bus_attribute { @@ -65,7 +64,7 @@ struct bus_type { const struct dev_pm_ops *pm; - struct bus_type_private *p; + struct subsys_private *p; }; extern int __must_check bus_register(struct bus_type *bus); @@ -213,7 +212,7 @@ struct class { const struct dev_pm_ops *pm; - struct class_private *p; + struct subsys_private *p; }; struct class_dev_iter { -- cgit v1.2.3 From d47d612459300510215fc54bf1283f81710745df Mon Sep 17 00:00:00 2001 From: Tracey Dent Date: Thu, 18 Nov 2010 10:42:30 +0100 Subject: HID: Clean up makefile (-y instead of -objs) Changed Makefile to use -y instead of -objs because -objs is deprecated and should now be switched. According to (documentation/kbuild/makefiles.txt). Signed-off-by: Tracey Dent Signed-off-by: Jiri Kosina --- drivers/hid/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 86192f67d7c2..b406269d1bcb 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -1,7 +1,7 @@ # # Makefile for the HID driver # -hid-objs := hid-core.o hid-input.o +hid-y := hid-core.o hid-input.o ifdef CONFIG_DEBUG_FS hid-objs += hid-debug.o @@ -11,18 +11,18 @@ obj-$(CONFIG_HID) += hid.o hid-$(CONFIG_HIDRAW) += hidraw.o -hid-logitech-objs := hid-lg.o +hid-logitech-y := hid-lg.o ifdef CONFIG_LOGITECH_FF - hid-logitech-objs += hid-lgff.o + hid-logitech-y += hid-lgff.o endif ifdef CONFIG_LOGIRUMBLEPAD2_FF - hid-logitech-objs += hid-lg2ff.o + hid-logitech-y += hid-lg2ff.o endif ifdef CONFIG_LOGIG940_FF - hid-logitech-objs += hid-lg3ff.o + hid-logitech-y += hid-lg3ff.o endif ifdef CONFIG_LOGIWII_FF - hid-logitech-objs += hid-lg4ff.o + hid-logitech-y += hid-lg4ff.o endif obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o -- cgit v1.2.3 From e9229faf920aba47dd1ba6940b3ca138024543d3 Mon Sep 17 00:00:00 2001 From: Tracey Dent Date: Sun, 7 Nov 2010 09:46:28 -0500 Subject: HID: usbhid: Clean up makefile (-y instead of -objs) Changed Makefile to use -y instead of -objs because -objs is deprecated and should now be switched. According to (documentation/kbuild/makefiles.txt). Signed-off-by: Tracey Dent Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index 1329ecb37a1c..db3cf31c6fa1 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -3,15 +3,15 @@ # # Multipart objects. -usbhid-objs := hid-core.o hid-quirks.o +usbhid-y := hid-core.o hid-quirks.o # Optional parts of multipart objects. ifeq ($(CONFIG_USB_HIDDEV),y) - usbhid-objs += hiddev.o + usbhid-y += hiddev.o endif ifeq ($(CONFIG_HID_PID),y) - usbhid-objs += hid-pidff.o + usbhid-y += hid-pidff.o endif obj-$(CONFIG_USB_HID) += usbhid.o -- cgit v1.2.3 From 86af95039b69a90db15294eb1f9c147f1df0a8ea Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Fri, 12 Nov 2010 11:36:22 +0100 Subject: ds2760_battery: Fix calculation of time_to_empty_now A check against division by zero was modified in commit b0525b48. Since this change time_to_empty_now is always reported as zero while the battery is discharging and as a negative value while the battery is charging. This is because current is negative while the battery is discharging. Fix the check introduced by commit b0525b48 so that time_to_empty_now is reported correctly during discharge and as zero while charging. Signed-off-by: Sven Neumann Acked-by: Daniel Mack Cc: stable@kernel.org [2.6.32..2.6.36] Signed-off-by: Anton Vorontsov --- drivers/power/ds2760_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index b3c01c16a164..11e1ac508e57 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di) if (di->rem_capacity > 100) di->rem_capacity = 100; - if (di->current_uA >= 100L) + if (di->current_uA < -100L) di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L) / (di->current_uA / 100L); else -- cgit v1.2.3 From 8ec98fe0b4ffdedce4c1caa9fb3d550f52ad1c6b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 11 Nov 2010 19:00:52 +0100 Subject: jz4740-battery: Protect against concurrent battery readings We can not handle more then one ADC request at a time to the battery. The patch adds a mutex around the ADC read code to ensure this. Signed-off-by: Lars-Peter Clausen Cc: stable@kernel.org Signed-off-by: Anton Vorontsov --- drivers/power/jz4740-battery.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index a8108a73593e..2bbe04ae13a7 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -47,6 +47,8 @@ struct jz_battery { struct power_supply battery; struct delayed_work work; + + struct mutex lock; }; static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy) @@ -68,6 +70,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery) unsigned long val; long voltage; + mutex_lock(&battery->lock); + INIT_COMPLETION(battery->read_completion); enable_irq(battery->irq); @@ -91,6 +95,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery) battery->cell->disable(battery->pdev); disable_irq(battery->irq); + mutex_unlock(&battery->lock); + return voltage; } @@ -291,6 +297,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev) jz_battery->pdev = pdev; init_completion(&jz_battery->read_completion); + mutex_init(&jz_battery->lock); INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work); -- cgit v1.2.3 From 5070437cd99511f69ae561f2ab417142a47a85ec Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 21 Oct 2010 17:55:01 +0200 Subject: power_supply: Add gpio charger driver This patch adds a simple driver for chargers indicating their online status through a GPIO pin. Signed-off-by: Lars-Peter Clausen Signed-off-by: Anton Vorontsov --- drivers/power/Kconfig | 10 ++ drivers/power/Makefile | 1 + drivers/power/gpio-charger.c | 185 +++++++++++++++++++++++++++++++++++++ include/linux/power/gpio-charger.h | 41 ++++++++ 4 files changed, 237 insertions(+) create mode 100644 drivers/power/gpio-charger.c create mode 100644 include/linux/power/gpio-charger.h (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 60d83d983a36..32165295cb1b 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -185,4 +185,14 @@ config CHARGER_TWL4030 help Say Y here to enable support for TWL4030 Battery Charge Interface. +config CHARGER_GPIO + tristate "GPIO charger" + depends on GPIOLIB + help + Say Y to include support for chargers which report their online status + through a GPIO pin. + + This driver can be build as a module. If so, the module will be + called gpio-charger. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index c75772eb157c..545459f9f356 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o +obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c new file mode 100644 index 000000000000..fccbe99b619c --- /dev/null +++ b/drivers/power/gpio-charger.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * Driver for chargers which report their online status through a GPIO pin + * + * 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. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct gpio_charger { + const struct gpio_charger_platform_data *pdata; + unsigned int irq; + + struct power_supply charger; +}; + +static irqreturn_t gpio_charger_irq(int irq, void *devid) +{ + struct power_supply *charger = devid; + + power_supply_changed(charger); + + return IRQ_HANDLED; +} + +static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy) +{ + return container_of(psy, struct gpio_charger, charger); +} + +static int gpio_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val) +{ + struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); + const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = gpio_get_value(pdata->gpio); + val->intval ^= pdata->gpio_active_low; + break; + default: + return -EINVAL; + } + + return 0; +} + +static enum power_supply_property gpio_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int __devinit gpio_charger_probe(struct platform_device *pdev) +{ + const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; + struct gpio_charger *gpio_charger; + struct power_supply *charger; + int ret; + int irq; + + if (!pdata) { + dev_err(&pdev->dev, "No platform data\n"); + return -EINVAL; + } + + if (!gpio_is_valid(pdata->gpio)) { + dev_err(&pdev->dev, "Invalid gpio pin\n"); + return -EINVAL; + } + + gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); + + charger = &gpio_charger->charger; + + charger->name = pdata->name; + charger->type = pdata->type; + charger->properties = gpio_charger_properties; + charger->num_properties = ARRAY_SIZE(gpio_charger_properties); + charger->get_property = gpio_charger_get_property; + charger->supplied_to = pdata->supplied_to; + charger->num_supplicants = pdata->num_supplicants; + + ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); + if (ret) { + dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); + goto err_free; + } + ret = gpio_direction_input(pdata->gpio); + if (ret) { + dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); + goto err_gpio_free; + } + + irq = gpio_to_irq(pdata->gpio); + if (irq > 0) { + ret = request_irq(irq, gpio_charger_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + dev_name(&pdev->dev), charger); + if (ret) + dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret); + else + gpio_charger->irq = irq; + } + + gpio_charger->pdata = pdata; + + ret = power_supply_register(&pdev->dev, charger); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register power supply: %d\n", ret); + goto err_irq_free; + } + + platform_set_drvdata(pdev, gpio_charger); + + return 0; + +err_irq_free: + if (gpio_charger->irq) + free_irq(gpio_charger->irq, charger); +err_gpio_free: + gpio_free(pdata->gpio); +err_free: + kfree(gpio_charger); + return ret; +} + +static int __devexit gpio_charger_remove(struct platform_device *pdev) +{ + struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); + + power_supply_unregister(&gpio_charger->charger); + + if (gpio_charger->irq) + free_irq(gpio_charger->irq, &gpio_charger->charger); + gpio_free(gpio_charger->pdata->gpio); + + platform_set_drvdata(pdev, NULL); + kfree(gpio_charger); + + return 0; +} + +static struct platform_driver gpio_charger_driver = { + .probe = gpio_charger_probe, + .remove = __devexit_p(gpio_charger_remove), + .driver = { + .name = "gpio-charger", + .owner = THIS_MODULE, + }, +}; + +static int __init gpio_charger_init(void) +{ + return platform_driver_register(&gpio_charger_driver); +} +module_init(gpio_charger_init); + +static void __exit gpio_charger_exit(void) +{ + platform_driver_unregister(&gpio_charger_driver); +} +module_exit(gpio_charger_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-charger"); diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h new file mode 100644 index 000000000000..de1dfe09a03d --- /dev/null +++ b/include/linux/power/gpio-charger.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010, Lars-Peter Clausen + * + * 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. + * + * 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 __LINUX_POWER_GPIO_CHARGER_H__ +#define __LINUX_POWER_GPIO_CHARGER_H__ + +#include +#include + +/** + * struct gpio_charger_platform_data - platform_data for gpio_charger devices + * @name: Name for the chargers power_supply device + * @type: Type of the charger + * @gpio: GPIO which is used to indicate the chargers status + * @gpio_active_low: Should be set to 1 if the GPIO is active low otherwise 0 + * @supplied_to: Array of battery names to which this chargers supplies power + * @num_supplicants: Number of entries in the supplied_to array + */ +struct gpio_charger_platform_data { + const char *name; + enum power_supply_type type; + + int gpio; + int gpio_active_low; + + char **supplied_to; + size_t num_supplicants; +}; + +#endif -- cgit v1.2.3 From 746d8fb8c6933337c927f40c9ef90dcbddcfd39e Mon Sep 17 00:00:00 2001 From: Ameya Palande Date: Thu, 4 Nov 2010 16:31:46 +0200 Subject: isp1704_charger: Correct length for storing model Model should have room to accommodate the trailing null byte, "isp170[4|7]\0". Signed-off-by: Ameya Palande Acked-by: Heikki Krogerus Signed-off-by: Anton Vorontsov --- drivers/power/isp1704_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 72512185f3e2..87252e13e29c 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -59,7 +59,7 @@ struct isp1704_charger { struct notifier_block nb; struct work_struct work; - char model[7]; + char model[8]; unsigned present:1; }; -- cgit v1.2.3 From bac43b20501058ab0728246acce3bb85f2e72648 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 4 Nov 2010 16:31:47 +0200 Subject: isp1704_charger: Detect HUB/Host chargers To avoid breaking high speed chirp handshaking with CDP chargers, no more then 500mA should be drawn. To make sure of this, utilizing current_max property. After the device has enumerated, it's safe to draw the maximum 1800mA as defined in the Battery Charging Specification. This can be also used with normal USB connection if the controller sends ENUMERATED notification with the milliamps as data. From now on the online property indicates VBUS, present property if there is a charger and current_max the milliamps possible to draw from VBUS. Signed-off-by: Heikki Krogerus Signed-off-by: Anton Vorontsov --- drivers/power/isp1704_charger.c | 180 +++++++++++++++++++++++++++++++--------- 1 file changed, 142 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 87252e13e29c..10c7cc5fb5f9 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -59,10 +59,60 @@ struct isp1704_charger { struct notifier_block nb; struct work_struct work; + /* properties */ char model[8]; unsigned present:1; + unsigned online:1; + unsigned current_max; + + /* temp storage variables */ + unsigned long event; + unsigned max_power; }; +/* + * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB + * chargers). + * + * REVISIT: The method is defined in Battery Charging Specification and is + * applicable to any ULPI transceiver. Nothing isp170x specific here. + */ +static inline int isp1704_charger_type(struct isp1704_charger *isp) +{ + u8 reg; + u8 func_ctrl; + u8 otg_ctrl; + int type = POWER_SUPPLY_TYPE_USB_DCP; + + func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL); + otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL); + + /* disable pulldowns */ + reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN; + otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg); + + /* full speed */ + otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL), + ULPI_FUNC_CTRL_XCVRSEL_MASK); + otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), + ULPI_FUNC_CTRL_FULL_SPEED); + + /* Enable strong pull-up on DP (1.5K) and reset */ + reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET; + otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg); + usleep_range(1000, 2000); + + reg = otg_io_read(isp->otg, ULPI_DEBUG); + if ((reg & 3) != 3) + type = POWER_SUPPLY_TYPE_USB_CDP; + + /* recover original state */ + otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl); + otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl); + + return type; +} + /* * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger * is actually a dedicated charger, the following steps need to be taken. @@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp) static inline int isp1704_charger_detect(struct isp1704_charger *isp) { unsigned long timeout; - u8 r; + u8 pwr_ctrl; int ret = 0; + pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL); + /* set SW control bit in PWR_CTRL register */ otg_io_write(isp->otg, ISP1704_PWR_CTRL, ISP1704_PWR_CTRL_SWCTRL); /* enable manual charger detection */ - r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN); - otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r); + otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), + ISP1704_PWR_CTRL_SWCTRL + | ISP1704_PWR_CTRL_DPVSRC_EN); usleep_range(1000, 2000); timeout = jiffies + msecs_to_jiffies(300); @@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp) ret = isp1704_charger_verify(isp); break; } - } while (!time_after(jiffies, timeout)); + } while (!time_after(jiffies, timeout) && isp->online); + + /* recover original state */ + otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl); return ret; } @@ -155,53 +211,93 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp) static void isp1704_charger_work(struct work_struct *data) { int detect; + unsigned long event; + unsigned power; struct isp1704_charger *isp = container_of(data, struct isp1704_charger, work); + static DEFINE_MUTEX(lock); - /* - * FIXME Only supporting dedicated chargers even though isp1704 can - * detect HUB and HOST chargers. If the device has already been - * enumerated, the detection will break the connection. - */ - if (isp->otg->state != OTG_STATE_B_IDLE) - return; - - /* disable data pullups */ - if (isp->otg->gadget) - usb_gadget_disconnect(isp->otg->gadget); - - /* detect charger */ - detect = isp1704_charger_detect(isp); - if (detect) { - isp->present = detect; - power_supply_changed(&isp->psy); - } + event = isp->event; + power = isp->max_power; - /* enable data pullups */ - if (isp->otg->gadget) - usb_gadget_connect(isp->otg->gadget); -} - -static int isp1704_notifier_call(struct notifier_block *nb, - unsigned long event, void *unused) -{ - struct isp1704_charger *isp = - container_of(nb, struct isp1704_charger, nb); + mutex_lock(&lock); switch (event) { case USB_EVENT_VBUS: - schedule_work(&isp->work); + isp->online = true; + + /* detect charger */ + detect = isp1704_charger_detect(isp); + + if (detect) { + isp->present = detect; + isp->psy.type = isp1704_charger_type(isp); + } + + switch (isp->psy.type) { + case POWER_SUPPLY_TYPE_USB_DCP: + isp->current_max = 1800; + break; + case POWER_SUPPLY_TYPE_USB_CDP: + /* + * Only 500mA here or high speed chirp + * handshaking may break + */ + isp->current_max = 500; + /* FALLTHROUGH */ + case POWER_SUPPLY_TYPE_USB: + default: + /* enable data pullups */ + if (isp->otg->gadget) + usb_gadget_connect(isp->otg->gadget); + } break; case USB_EVENT_NONE: - if (isp->present) { - isp->present = 0; - power_supply_changed(&isp->psy); - } + isp->online = false; + isp->current_max = 0; + isp->present = 0; + isp->current_max = 0; + isp->psy.type = POWER_SUPPLY_TYPE_USB; + + /* + * Disable data pullups. We need to prevent the controller from + * enumerating. + * + * FIXME: This is here to allow charger detection with Host/HUB + * chargers. The pullups may be enabled elsewhere, so this can + * not be the final solution. + */ + if (isp->otg->gadget) + usb_gadget_disconnect(isp->otg->gadget); + break; + case USB_EVENT_ENUMERATED: + if (isp->present) + isp->current_max = 1800; + else + isp->current_max = power; break; default: - return NOTIFY_DONE; + goto out; } + power_supply_changed(&isp->psy); +out: + mutex_unlock(&lock); +} + +static int isp1704_notifier_call(struct notifier_block *nb, + unsigned long event, void *power) +{ + struct isp1704_charger *isp = + container_of(nb, struct isp1704_charger, nb); + + isp->event = event; + + if (power) + isp->max_power = *((unsigned *)power); + + schedule_work(&isp->work); + return NOTIFY_OK; } @@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_PRESENT: val->intval = isp->present; break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = isp->online; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = isp->current_max; + break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = isp->model; break; @@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy, static enum power_supply_property power_props[] = { POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, }; -- cgit v1.2.3 From a4607d9f5cbae1aad7f86e8204b57d66c0e14e36 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 4 Nov 2010 16:31:48 +0200 Subject: isp1704_charger: Set isp->dev before anything needs it isp1704_test_ulpi() is the first place that needs isp->dev member, so it must be set before calling the function. Signed-off-by: Heikki Krogerus Signed-off-by: Anton Vorontsov --- drivers/power/isp1704_charger.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 10c7cc5fb5f9..77c11f1d72e2 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -391,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) if (!isp->otg) goto fail0; + isp->dev = &pdev->dev; + platform_set_drvdata(pdev, isp); + ret = isp1704_test_ulpi(isp); if (ret < 0) goto fail1; - isp->dev = &pdev->dev; - platform_set_drvdata(pdev, isp); - isp->psy.name = "isp1704"; isp->psy.type = POWER_SUPPLY_TYPE_USB; isp->psy.properties = power_props; -- cgit v1.2.3 From e1a85694e08d03efae9e08fdb292dfd4870837bc Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 8 Nov 2010 12:22:40 +0200 Subject: isp1704_charger: Detect charger after probe If the device is booted up with cable connected, or the module is loaded after plugging in the cable, the notification has come and gone, so not relying on it at probe time. Instead this checks the VBUS level manually after probe. Signed-off-by: Heikki Krogerus Signed-off-by: Anton Vorontsov --- drivers/power/isp1704_charger.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 77c11f1d72e2..2ad9b14a5ce3 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -422,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) dev_info(isp->dev, "registered with product id %s\n", isp->model); + /* + * Taking over the D+ pullup. + * + * FIXME: The device will be disconnected if it was already + * enumerated. The charger driver should be always loaded before any + * gadget is loaded. + */ + if (isp->otg->gadget) + usb_gadget_disconnect(isp->otg->gadget); + + /* Detect charger if VBUS is valid (the cable was already plugged). */ + ret = otg_io_read(isp->otg, ULPI_USB_INT_STS); + if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) { + isp->event = USB_EVENT_VBUS; + schedule_work(&isp->work); + } + return 0; fail2: power_supply_unregister(&isp->psy); -- cgit v1.2.3 From 8477cedb49c69ce64b603d76c7776811eec0f9d7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 11 Nov 2010 19:00:53 +0100 Subject: jz4740-battery: Check if platform_data is supplied Currently platform_data is dereferenced without checking whether it is actually set, which can lead to kernel crashes. This patch adds a check which will abort the drivers probe function gracefully if no platform_data is supplied. Signed-off-by: Lars-Peter Clausen Signed-off-by: Anton Vorontsov --- drivers/power/jz4740-battery.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index 2bbe04ae13a7..5b4821593201 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -246,6 +246,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev) struct jz_battery *jz_battery; struct power_supply *battery; + if (!pdata) { + dev_err(&pdev->dev, "No platform_data supplied\n"); + return -ENXIO; + } + jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL); if (!jz_battery) { dev_err(&pdev->dev, "Failed to allocate driver structure\n"); -- cgit v1.2.3 From c311598b29f09c5092747a2603700f96a7daec2a Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 18 Nov 2010 16:27:07 +0100 Subject: HID: prodikeys: make sysfs permissions more strict It's not really dangerous in this driver, but it's against general practice and worth fixing. Proper place for handling this correctly is udev. Reported-by: Linus Torvalds Signed-off-by: Jiri Kosina --- drivers/hid/hid-prodikeys.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index 48eab84f53b5..5f0fa6c1bf87 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -130,7 +130,7 @@ static ssize_t store_channel(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(channel, S_IRUGO | S_IWUGO, show_channel, +static DEVICE_ATTR(channel, S_IRUGO | S_IWUSR | S_IWGRP , show_channel, store_channel); static struct device_attribute *sysfs_device_attr_channel = { @@ -169,7 +169,7 @@ static ssize_t store_sustain(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(sustain, S_IRUGO | S_IWUGO, show_sustain, +static DEVICE_ATTR(sustain, S_IRUGO | S_IWUSR | S_IWGRP, show_sustain, store_sustain); static struct device_attribute *sysfs_device_attr_sustain = { @@ -207,7 +207,7 @@ static ssize_t store_octave(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(octave, S_IRUGO | S_IWUGO, show_octave, +static DEVICE_ATTR(octave, S_IRUGO | S_IWUSR | S_IWGRP, show_octave, store_octave); static struct device_attribute *sysfs_device_attr_octave = { -- cgit v1.2.3 From edd2126aa8aab8a87db7cc480d5047e9280d7acf Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 18 Nov 2010 16:28:43 +0100 Subject: HID: wacom: make sysfs permissions more strict It's not really dangerous in this driver, but it's against general practice and worth fixing. Wacom uses the attribute for changing the reporting speed of the tablet (and this actually requires poking the device in the background) (still I wouldn't consider it a security issue though). udev is a proper place to handle this. Reported-by: Linus Torvalds Signed-off-by: Jiri Kosina --- drivers/hid/hid-wacom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 724f46ed612f..94caae731381 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -172,7 +172,7 @@ static ssize_t wacom_store_speed(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, wacom_show_speed, wacom_store_speed); static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, -- cgit v1.2.3 From 5dc177da85a813ff73c35f2d9edfb0bc2fe8271c Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 17 Nov 2010 09:58:46 +0200 Subject: staging: brcm80211: brcmfmac: remove PCI SDIO controller binding Signed-off-by: Mike Rapoport Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 229 ---------------------- 1 file changed, 229 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index 6e32056451f1..9527e2959608 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -279,224 +279,6 @@ int bcmsdh_remove(struct device *dev) return 0; } - -#else /* BCMPLATFORM_BUS */ - -#if !defined(BCMLXSDMMC) -/* forward declarations for PCI probe and remove functions. */ -static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent); -static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev); - -/** - * pci id table - */ -static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = { -{ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = 0, - .class_mask = 0, - .driver_data = 0, -}, -{0,} -}; - -MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid); - -/** - * SDIO Host Controller pci driver info - */ -static struct pci_driver bcmsdh_pci_driver = { - .node = {}, - .name = "bcmsdh", - .id_table = bcmsdh_pci_devid, - .probe = bcmsdh_pci_probe, - .remove = bcmsdh_pci_remove, - .suspend = NULL, - .resume = NULL, -}; - -extern uint sd_pci_slot; /* Force detection to a particular PCI */ - /* slot only . Allows for having multiple */ - /* WL devices at once in a PC */ - /* Only one instance of dhd will be */ - /* usable at a time */ - /* Upper word is bus number, */ - /* lower word is slot number */ - /* Default value of 0xFFFFffff turns this */ - /* off */ -module_param(sd_pci_slot, uint, 0); - -/** - * Detect supported SDIO Host Controller and attach if found. - * - * Determine if the device described by pdev is a supported SDIO Host - * Controller. If so, attach to it and attach to the target device. - */ -static int __devinit -bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct osl_info *osh = NULL; - bcmsdh_hc_t *sdhc = NULL; - unsigned long regs; - bcmsdh_info_t *sdh = NULL; - int rc; - - if (sd_pci_slot != 0xFFFFffff) { - if (pdev->bus->number != (sd_pci_slot >> 16) || - PCI_SLOT(pdev->devfn) != (sd_pci_slot & 0xffff)) { - SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n", - __func__, - bcmsdh_chipmatch(pdev->vendor, pdev->device) ? - "Found compatible SDIOHC" : - "Probing unknown device", - pdev->bus->number, PCI_SLOT(pdev->devfn), - pdev->vendor, pdev->device)); - return -ENODEV; - } - SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X " - "(good PCI location)\n", __func__, - bcmsdh_chipmatch(pdev->vendor, pdev->device) ? - "Using compatible SDIOHC" : "WARNING, forced use " - "of unkown device", - pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, - pdev->device)); - } - - if ((pdev->vendor == VENDOR_TI) - && ((pdev->device == PCIXX21_FLASHMEDIA_ID) - || (pdev->device == PCIXX21_FLASHMEDIA0_ID))) { - u32 config_reg; - - SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", - __func__)); - osh = osl_attach(pdev, PCI_BUS); - if (!osh) { - SDLX_MSG(("%s: osl_attach failed\n", __func__)); - goto err; - } - - config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4); - - /* - * Set MMC_SD_DIS bit in FlashMedia Controller. - * Disbling the SD/MMC Controller in the FlashMedia Controller - * allows the Standard SD Host Controller to take over control - * of the SD Slot. - */ - config_reg |= 0x02; - OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg); - osl_detach(osh); - } - /* match this pci device with what we support */ - /* we can't solely rely on this to believe it is - our SDIO Host Controller! */ - if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) - return -ENODEV; - - /* this is a pci device we might support */ - SDLX_MSG(("%s: Found possible SDIO Host Controller: " - "bus %d slot %d func %d irq %d\n", __func__, - pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq)); - - /* use bcmsdh_query_device() to get the vendor ID of the target device - * so it will eventually appear in the Broadcom string on the console - */ - - /* allocate SDIO Host Controller state info */ - osh = osl_attach(pdev, PCI_BUS); - if (!osh) { - SDLX_MSG(("%s: osl_attach failed\n", __func__)); - goto err; - } - sdhc = kzalloc(sizeof(bcmsdh_hc_t), GFP_ATOMIC); - if (!sdhc) { - SDLX_MSG(("%s: out of memory\n", __func__)); - goto err; - } - sdhc->osh = osh; - - sdhc->dev = pdev; - - /* map to address where host can access */ - pci_set_master(pdev); - rc = pci_enable_device(pdev); - if (rc) { - SDLX_MSG(("%s: Cannot enable PCI device\n", __func__)); - goto err; - } - sdh = bcmsdh_attach(osh, (void *)(unsigned long)pci_resource_start(pdev, 0), - (void **)®s, pdev->irq); - if (!sdh) { - SDLX_MSG(("%s: bcmsdh_attach failed\n", __func__)); - goto err; - } - - sdhc->sdh = sdh; - - /* try to attach to the target device */ - sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */ - bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0, - (void *)regs, NULL, sdh); - if (!sdhc->ch) { - SDLX_MSG(("%s: device attach failed\n", __func__)); - goto err; - } - - /* chain SDIO Host Controller info together */ - sdhc->next = sdhcinfo; - sdhcinfo = sdhc; - - return 0; - - /* error handling */ -err: - if (sdhc->sdh) - bcmsdh_detach(sdhc->osh, sdhc->sdh); - if (sdhc) - kfree(sdhc); - if (osh) - osl_detach(osh); - return -ENODEV; -} - -/** - * Detach from target devices and SDIO Host Controller - */ -static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev) -{ - bcmsdh_hc_t *sdhc, *prev; - struct osl_info *osh; - - /* find the SDIO Host Controller state for this - pdev and take it out from the list */ - for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { - if (sdhc->dev == pdev) { - if (prev) - prev->next = sdhc->next; - else - sdhcinfo = NULL; - break; - } - prev = sdhc; - } - if (!sdhc) - return; - - drvinfo.detach(sdhc->ch); - - bcmsdh_detach(sdhc->osh, sdhc->sdh); - - /* release SDIO Host Controller info */ - osh = sdhc->osh; - kfree(sdhc); - osl_detach(osh); -} -#endif /* BCMLXSDMMC */ #endif /* BCMPLATFORM_BUS */ extern int sdio_function_init(void); @@ -515,14 +297,6 @@ int bcmsdh_register(bcmsdh_driver_t *driver) return error; #endif /* defined(BCMPLATFORM_BUS) */ -#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) - error = pci_register_driver(&bcmsdh_pci_driver); - if (!error) - return 0; - - SDLX_MSG(("%s: pci_register_driver failed 0x%x\n", __func__, error)); -#endif /* BCMPLATFORM_BUS */ - return error; } @@ -533,9 +307,6 @@ void bcmsdh_unregister(void) #if defined(BCMLXSDMMC) sdio_function_cleanup(); #endif /* BCMLXSDMMC */ -#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) - pci_unregister_driver(&bcmsdh_pci_driver); -#endif /* BCMPLATFORM_BUS */ } #if defined(OOB_INTR_ONLY) -- cgit v1.2.3 From 26361116d7c94984a5fbdc1b6a11555a9dc33cf0 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 17 Nov 2010 10:00:00 +0200 Subject: staging: brcm80211: brcmfmac: cleanup bcmsdh_(un)register Signed-off-by: Mike Rapoport Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index 9527e2959608..d24b5e7d753c 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -285,28 +285,17 @@ extern int sdio_function_init(void); int bcmsdh_register(bcmsdh_driver_t *driver) { - int error = 0; - drvinfo = *driver; -#if defined(BCMPLATFORM_BUS) -#if defined(BCMLXSDMMC) SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n")); - error = sdio_function_init(); -#endif /* defined(BCMLXSDMMC) */ - return error; -#endif /* defined(BCMPLATFORM_BUS) */ - - return error; + return sdio_function_init(); } extern void sdio_function_cleanup(void); void bcmsdh_unregister(void) { -#if defined(BCMLXSDMMC) sdio_function_cleanup(); -#endif /* BCMLXSDMMC */ } #if defined(OOB_INTR_ONLY) -- cgit v1.2.3 From c303ecbda8b7c86975c4ba23f56b8cbe297cd060 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 18 Nov 2010 20:46:43 +0100 Subject: staging: brcm80211: replace PKTPUSH and PKTPULL macros with native skbuff calls Replacing PKTPUSH by skb_push() call and PKTPULL by skb_pull() call to make it obvious what the operation is doing with the packet. Reviewed-by: Henry Ptasinski Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 4 ++-- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 26 +++++++++++++------------- drivers/staging/brcm80211/include/linux_osl.h | 2 -- drivers/staging/brcm80211/sys/wlc_ampdu.c | 8 ++++---- drivers/staging/brcm80211/sys/wlc_mac80211.c | 14 +++++++------- drivers/staging/brcm80211/util/hnddma.c | 2 +- 6 files changed, 27 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c index 0d14f6c1fcfa..8e4e10794dce 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c @@ -321,7 +321,7 @@ void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) #ifdef BDC /* Push BDC header used to convey priority for buses that don't */ - PKTPUSH(pktbuf, BDC_HEADER_LEN); + skb_push(pktbuf, BDC_HEADER_LEN); h = (struct bdc_header *)PKTDATA(pktbuf); @@ -398,7 +398,7 @@ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf) PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); - PKTPULL(pktbuf, BDC_HEADER_LEN); + skb_pull(pktbuf, BDC_HEADER_LEN); #endif /* BDC */ return 0; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index bc8739665d66..db649a038938 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -365,7 +365,7 @@ extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); ASSERT(datalign < (align)); \ ASSERT(PKTLEN((p)) >= ((len) + datalign)); \ if (datalign) \ - PKTPULL((p), datalign); \ + skb_pull((p), datalign); \ PKTSETLEN((p), (len)); \ } while (0) @@ -953,7 +953,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) ASSERT(((unsigned long)frame % DHD_SDALIGN) == 0); pad = 0; } else { - PKTPUSH(pkt, pad); + skb_push(pkt, pad); frame = (u8 *) PKTDATA(pkt); ASSERT((pad + SDPCM_HDRLEN) <= (int)PKTLEN(pkt)); @@ -1052,7 +1052,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) done: /* restore pkt buffer pointer before calling tx complete routine */ - PKTPULL(pkt, SDPCM_HDRLEN + pad); + skb_pull(pkt, SDPCM_HDRLEN + pad); dhd_os_sdunlock(bus->dhd); dhd_txcomplete(bus->dhd, pkt, ret != 0); dhd_os_sdlock(bus->dhd); @@ -1078,7 +1078,7 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt) /* Push the test header if doing loopback */ if (bus->ext_loop) { u8 *data; - PKTPUSH(pkt, SDPCM_TEST_HDRLEN); + skb_push(pkt, SDPCM_TEST_HDRLEN); data = PKTDATA(pkt); *data++ = SDPCM_TEST_ECHOREQ; *data++ = (u8) bus->loopid++; @@ -1089,7 +1089,7 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt) #endif /* SDTEST */ /* Add space for the header */ - PKTPUSH(pkt, SDPCM_HDRLEN); + skb_push(pkt, SDPCM_HDRLEN); ASSERT(IS_ALIGNED((unsigned long)PKTDATA(pkt), 2)); prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); @@ -1107,7 +1107,7 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt) /* Priority based enq */ dhd_os_sdlock_txq(bus->dhd); if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == false) { - PKTPULL(pkt, SDPCM_HDRLEN); + skb_pull(pkt, SDPCM_HDRLEN); dhd_txcomplete(bus->dhd, pkt, false); PKTFREE(osh, pkt, true); DHD_ERROR(("%s: out of bus->txq !!!\n", __func__)); @@ -3426,7 +3426,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) bus->tx_max = txmax; /* Remove superframe header, remember offset */ - PKTPULL(pfirst, doff); + skb_pull(pfirst, doff); sfdoff = doff; /* Validate all the subframe headers */ @@ -3471,7 +3471,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) a couple retries */ if (bus->glomerr++ < 3) { /* Restore superframe header space */ - PKTPUSH(pfirst, sfdoff); + skb_push(pfirst, sfdoff); dhdsdio_rxfail(bus, true, true); } else { bus->glomerr = 0; @@ -3522,7 +3522,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) #endif PKTSETLEN(pfirst, sublen); - PKTPULL(pfirst, doff); + skb_pull(pfirst, doff); if (PKTLEN(pfirst) == 0) { PKTFREE(bus->dhd->osh, pfirst, false); @@ -4104,7 +4104,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Leave room for what we already read, and align remainder */ ASSERT(firstread < (PKTLEN(pkt))); - PKTPULL(pkt, firstread); + skb_pull(pkt, firstread); PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); /* Read the remaining frame data */ @@ -4132,7 +4132,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } /* Copy the already-read portion */ - PKTPUSH(pkt, firstread); + skb_push(pkt, firstread); bcopy(bus->rxhdr, PKTDATA(pkt), firstread); #ifdef DHD_DEBUG @@ -4153,7 +4153,7 @@ deliver: #endif PKTSETLEN(pkt, len); ASSERT(doff == SDPCM_HDRLEN); - PKTPULL(pkt, SDPCM_HDRLEN); + skb_pull(pkt, SDPCM_HDRLEN); bus->glomd = pkt; } else { DHD_ERROR(("%s: glom superframe w/o " @@ -4165,7 +4165,7 @@ deliver: /* Fill in packet len and prio, deliver upward */ PKTSETLEN(pkt, len); - PKTPULL(pkt, doff); + skb_pull(pkt, doff); #ifdef SDTEST /* Test channel packets are processed separately */ diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 70621692150a..a7f0da271001 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -274,8 +274,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define PKTSETNEXT(skb, x) \ (((struct sk_buff *)(skb))->next = (struct sk_buff *)(x)) #define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len)) -#define PKTPUSH(skb, bytes) skb_push((struct sk_buff *)(skb), (bytes)) -#define PKTPULL(skb, bytes) skb_pull((struct sk_buff *)(skb), (bytes)) #define PKTALLOCED(osh) (((struct osl_pubinfo *)(osh))->pktalloced) #define PKTSETPOOL(osh, skb, x, y) do {} while (0) #define PKTPOOL(osh, skb) false diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 5d06105ba1f6..dc327026a0f0 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -1187,8 +1187,8 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p, status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT; - PKTPULL(p, D11_PHY_HDR_LEN); - PKTPULL(p, D11_TXH_LEN); + skb_pull(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_TXH_LEN); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); @@ -1213,8 +1213,8 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p, ieee80211_tx_info_clear_status(tx_info); tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - PKTPULL(p, D11_PHY_HDR_LEN); - PKTPULL(p, D11_TXH_LEN); + skb_pull(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_TXH_LEN); WL_ERROR(("%s: BA Timeout, seq %d, in_transit %d\n", SHORTNAME, seq, ini->tx_in_transit)); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 9e57dc3cde21..94b809c24783 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -5942,10 +5942,10 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, ASSERT(tx_info); /* add PLCP */ - plcp = PKTPUSH(p, D11_PHY_HDR_LEN); + plcp = skb_push(p, D11_PHY_HDR_LEN); /* add Broadcom tx descriptor header */ - txh = (d11txh_t *) PKTPUSH(p, D11_TXH_LEN); + txh = (d11txh_t *) skb_push(p, D11_TXH_LEN); bzero((char *)txh, D11_TXH_LEN); /* setup frameid */ @@ -6890,8 +6890,8 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) PKTSETLINK(p, NULL); wlc->txretried = 0; /* remove PLCP & Broadcom tx descriptor header */ - PKTPULL(p, D11_PHY_HDR_LEN); - PKTPULL(p, D11_TXH_LEN); + skb_pull(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_TXH_LEN); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); WLCNTINCR(wlc->pub->_cnt->ieee_tx_status); } else { @@ -7163,7 +7163,7 @@ wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, void *p) /* mac header+body length, exclude CRC and plcp header */ len_mpdu = PKTLEN(p) - D11_PHY_HDR_LEN - DOT11_FCS_LEN; - PKTPULL(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_PHY_HDR_LEN); PKTSETLEN(p, len_mpdu); ASSERT(!PKTNEXT(p)); @@ -7225,7 +7225,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p) rxh = (d11rxhdr_t *) PKTDATA(p); /* strip off rxhdr */ - PKTPULL(p, wlc->hwrxoff); + skb_pull(p, wlc->hwrxoff); /* fixup rx header endianness */ ltoh16_buf((void *)rxh, sizeof(d11rxhdr_t)); @@ -7238,7 +7238,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p) wlc->pub->unit, PKTLEN(p))); goto toss; } - PKTPULL(p, 2); + skb_pull(p, 2); } h = (struct dot11_header *)(PKTDATA(p) + D11_PHY_HDR_LEN); diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index a945156eb31f..7fdcdcacab0f 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -1110,7 +1110,7 @@ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di) } /* reserve an extra headroom, if applicable */ if (extra_offset) - PKTPULL(p, extra_offset); + skb_pull(p, extra_offset); /* Do a cached write instead of uncached write since DMA_MAP * will flush the cache. -- cgit v1.2.3 From 2cb8ada64f209c5c033f1821bbbc0e8d388cbf7f Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 18 Nov 2010 20:46:44 +0100 Subject: staging: brcm80211: replaced PKTSETLEN macro by native __skb_trim call - removed PKTSETLEN macro and used __skb_trim call instead. - removed unused macros PKTSETPOOL and PKTPOOL Reviewed-by: Henry Ptasinski Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 8 ++++---- drivers/staging/brcm80211/include/linux_osl.h | 3 --- drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- drivers/staging/brcm80211/util/hnddma.c | 4 ++-- 4 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index db649a038938..d94b11a3271b 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -366,7 +366,7 @@ extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); ASSERT(PKTLEN((p)) >= ((len) + datalign)); \ if (datalign) \ skb_pull((p), datalign); \ - PKTSETLEN((p), (len)); \ + __skb_trim((p), (len)); \ } while (0) /* Limit on rounding up frames */ @@ -3521,7 +3521,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) prhex("Rx Subframe Data", dptr, dlen); #endif - PKTSETLEN(pfirst, sublen); + __skb_trim(pfirst, sublen); skb_pull(pfirst, doff); if (PKTLEN(pfirst) == 0) { @@ -4151,7 +4151,7 @@ deliver: prhex("Glom Data", PKTDATA(pkt), len); } #endif - PKTSETLEN(pkt, len); + __skb_trim(pkt, len); ASSERT(doff == SDPCM_HDRLEN); skb_pull(pkt, SDPCM_HDRLEN); bus->glomd = pkt; @@ -4164,7 +4164,7 @@ deliver: } /* Fill in packet len and prio, deliver upward */ - PKTSETLEN(pkt, len); + __skb_trim(pkt, len); skb_pull(pkt, doff); #ifdef SDTEST diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index a7f0da271001..11239fbba766 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -273,10 +273,7 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define PKTNEXT(skb) (((struct sk_buff *)(skb))->next) #define PKTSETNEXT(skb, x) \ (((struct sk_buff *)(skb))->next = (struct sk_buff *)(x)) -#define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len)) #define PKTALLOCED(osh) (((struct osl_pubinfo *)(osh))->pktalloced) -#define PKTSETPOOL(osh, skb, x, y) do {} while (0) -#define PKTPOOL(osh, skb) false extern void *osl_pktget(struct osl_info *osh, uint len); extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 94b809c24783..513e4d9a1ad2 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -7164,7 +7164,7 @@ wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, void *p) /* mac header+body length, exclude CRC and plcp header */ len_mpdu = PKTLEN(p) - D11_PHY_HDR_LEN - DOT11_FCS_LEN; skb_pull(p, D11_PHY_HDR_LEN); - PKTSETLEN(p, len_mpdu); + __skb_trim(p, len_mpdu); ASSERT(!PKTNEXT(p)); ASSERT(!PKTLINK(p)); diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index 7fdcdcacab0f..f1e9cfcca991 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -1003,7 +1003,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) /* set actual length */ pkt_len = min((di->rxoffset + len), di->rxbufsize); - PKTSETLEN(head, pkt_len); + __skb_trim(head, pkt_len); resid = len - (di->rxbufsize - di->rxoffset); /* check for single or multi-buffer rx */ @@ -1012,7 +1012,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) while ((resid > 0) && (p = _dma_getnextrxp(di, false))) { PKTSETNEXT(tail, p); pkt_len = min(resid, (int)di->rxbufsize); - PKTSETLEN(p, pkt_len); + __skb_trim(p, pkt_len); tail = p; resid -= di->rxbufsize; -- cgit v1.2.3 From 29efb1a9f450450e764d9901b434557349c3af53 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:52 -0800 Subject: staging: brcm80211: unifdef -UWLC_HIGH_ONLY Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/phy/wlc_phy_hal.h | 4 - drivers/staging/brcm80211/sys/wl_mac80211.c | 498 --------------------------- drivers/staging/brcm80211/sys/wl_mac80211.h | 30 -- drivers/staging/brcm80211/sys/wlc_alloc.c | 5 - drivers/staging/brcm80211/sys/wlc_ampdu.c | 53 --- drivers/staging/brcm80211/sys/wlc_ampdu.h | 4 - drivers/staging/brcm80211/sys/wlc_bmac.h | 10 - drivers/staging/brcm80211/sys/wlc_mac80211.c | 226 ------------ drivers/staging/brcm80211/sys/wlc_mac80211.h | 21 -- drivers/staging/brcm80211/sys/wlc_rpctx.h | 24 -- 10 files changed, 875 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/phy/wlc_phy_hal.h b/drivers/staging/brcm80211/phy/wlc_phy_hal.h index 52260b2d0eba..c462387d20b9 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_hal.h +++ b/drivers/staging/brcm80211/phy/wlc_phy_hal.h @@ -122,11 +122,7 @@ typedef struct shared_phy shared_phy_t; struct phy_pub; -#ifdef WLC_HIGH_ONLY -typedef struct wlc_rpc_phy wlc_phy_t; -#else typedef struct phy_pub wlc_phy_t; -#endif typedef struct shared_phy_params { void *osh; diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index af6d7dea4697..e336fef111e5 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -29,9 +29,7 @@ #include #include -#ifndef WLC_HIGH_ONLY #include -#endif #include #include #include @@ -46,20 +44,11 @@ #include #endif #include -#ifdef WLC_HIGH_ONLY -#include "dbus.h" -#include "bcm_rpc_tp.h" -#include "bcm_rpc.h" -#include "bcm_xdr.h" -#include "wlc_rpc.h" -#endif #include #include -#ifndef WLC_HIGH_ONLY #include #include -#endif #ifdef BCMSDIO extern struct device *sdiommc_dev; @@ -75,21 +64,6 @@ void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, static void wl_timer(unsigned long data); static void _wl_timer(wl_timer_t *t); -#ifdef WLC_HIGH_ONLY -#define RPCQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->rpcq_lock, (_flags)) -#define RPCQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->rpcq_lock, (_flags)) -#define TXQ_LOCK(_wl, _flags) spin_lock_irqsave(&(_wl)->txq_lock, (_flags)) -#define TXQ_UNLOCK(_wl, _flags) spin_unlock_irqrestore(&(_wl)->txq_lock, (_flags)) -static void wl_rpc_down(void *wlh); -static void wl_rpcq_free(wl_info_t *wl); -static void wl_rpcq_dispatch(struct wl_task *task); -static void wl_rpc_dispatch_schedule(void *ctx, struct rpc_buf *buf); -static void wl_start_txqwork(struct wl_task *task); -static void wl_txq_free(wl_info_t *wl); -static void wl_timer_task(wl_task_t *task); -static int wl_schedule_task(wl_info_t *wl, void (*fn) (struct wl_task *), - void *context); -#endif /* WLC_HIGH_ONLY */ static int ieee_hw_init(struct ieee80211_hw *hw); static int ieee_hw_rate_init(struct ieee80211_hw *hw); @@ -137,12 +111,10 @@ struct ieee80211_tkip_data { u8 rx_hdr[16], tx_hdr[16]; }; -#ifndef WLC_HIGH_ONLY #define WL_DEV_IF(dev) ((wl_if_t *)netdev_priv(dev)) #define WL_INFO(dev) ((wl_info_t *)(WL_DEV_IF(dev)->wl)) /* points to wl */ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev); static void wl_release_fw(wl_info_t *wl); -#endif /* local prototypes */ static int wl_start(struct sk_buff *skb, wl_info_t *wl); @@ -176,19 +148,13 @@ module_param(sd_drivestrength, uint, 0); #ifdef BCMDBG static int msglevel = 0xdeadbeef; module_param(msglevel, int, 0); -#ifndef WLC_HIGH_ONLY static int phymsglevel = 0xdeadbeef; module_param(phymsglevel, int, 0); -#endif /* WLC_HIGH_ONLY */ #endif /* BCMDBG */ #define HW_TO_WL(hw) (hw->priv) #define WL_TO_HW(wl) (wl->pub->ieee_hw) -#ifdef WLC_HIGH_ONLY -static int wl_ops_tx_nl(struct ieee80211_hw *hw, struct sk_buff *skb); -#else static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -#endif static int wl_ops_start(struct ieee80211_hw *hw); static void wl_ops_stop(struct ieee80211_hw *hw); static int wl_ops_add_interface(struct ieee80211_hw *hw, @@ -226,21 +192,6 @@ static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn); -#ifdef WLC_HIGH_ONLY -static int wl_ops_tx_nl(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - int status; - wl_info_t *wl = hw->priv; - if (!wl->pub->up) { - WL_ERROR(("ops->tx called while down\n")); - status = -ENETDOWN; - goto done; - } - status = wl_start(skb, wl); - done: - return status; -} -#else static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { int status; @@ -256,7 +207,6 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) WL_UNLOCK(wl); return status; } -#endif /* WLC_HIGH_ONLY */ static int wl_ops_start(struct ieee80211_hw *hw) { @@ -415,9 +365,6 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, wl_info_t *wl = HW_TO_WL(hw); int val; -#ifdef WLC_HIGH_ONLY - WL_LOCK(wl); -#endif if (changed & BSS_CHANGED_ASSOC) { WL_ERROR(("Associated:\t%s\n", info->assoc ? "True" : "False")); @@ -477,9 +424,6 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, info->enable_beacon ? "True" : "False")); /* Beaconing should be enabled/disabled (beaconing modes) */ } -#ifdef WLC_HIGH_ONLY - WL_UNLOCK(wl); -#endif return; } @@ -488,9 +432,7 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { -#ifndef WLC_HIGH_ONLY wl_info_t *wl = hw->priv; -#endif changed_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS; @@ -508,7 +450,6 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, WL_ERROR(("FIF_OTHER_BSS\n")); if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n")); -#ifndef WLC_HIGH_ONLY WL_LOCK(wl); if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; @@ -518,7 +459,6 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; } WL_UNLOCK(wl); -#endif } return; } @@ -618,20 +558,12 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wl->pub->global_scb = scb; wl->pub->global_ampdu = &(scb->scb_ampdu); wl->pub->global_ampdu->scb = scb; -#ifdef WLC_HIGH_ONLY - wl->pub->global_ampdu->max_pdu = AMPDU_NUM_MPDU; -#else wl->pub->global_ampdu->max_pdu = 16; -#endif pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID, AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT); sta->ht_cap.ht_supported = true; -#ifdef WLC_HIGH_ONLY - sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_16K; -#else sta->ht_cap.ampdu_factor = AMPDU_RX_FACTOR_64K; -#endif sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY; sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | @@ -695,11 +627,7 @@ wl_ampdu_action(struct ieee80211_hw *hw, } static const struct ieee80211_ops wl_ops = { -#ifdef WLC_HIGH_ONLY - .tx = wl_ops_tx_nl, -#else .tx = wl_ops_tx, -#endif .start = wl_ops_start, .stop = wl_ops_stop, .add_interface = wl_ops_add_interface, @@ -761,20 +689,9 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, osh = osl_attach(btparam, bustype); ASSERT(osh); -#ifdef WLC_HIGH_ONLY - hw = ieee80211_alloc_hw(sizeof(wl_info_t), &wl_ops); - if (!hw) { - WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__)); - ASSERT(0); - } - - bzero(hw->priv, sizeof(*wl)); - wl = hw->priv; -#else /* allocate private info */ hw = pci_get_drvdata(btparam); /* btparam == pdev */ wl = hw->priv; -#endif ASSERT(wl); wl->osh = osh; @@ -783,25 +700,6 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, /* setup the bottom half handler */ tasklet_init(&wl->tasklet, wl_dpc, (unsigned long) wl); -#ifdef WLC_HIGH_ONLY - wl->rpc_th = bcm_rpc_tp_attach(osh, NULL); - if (wl->rpc_th == NULL) { - WL_ERROR(("wl%d: %s: bcm_rpc_tp_attach failed!\n", unit, - __func__)); - goto fail; - } - - wl->rpc = bcm_rpc_attach(NULL, osh, wl->rpc_th); - if (wl->rpc == NULL) { - WL_ERROR(("wl%d: %s: bcm_rpc_attach failed!\n", unit, - __func__)); - goto fail; - } - - /* init tx work queue for wl_start/send pkt; no need to destroy workitem */ - INIT_WORK(&wl->txq_task.work, (work_func_t) wl_start_txqwork); - wl->txq_task.context = wl; -#endif /* WLC_HIGH_ONLY */ #ifdef BCMSDIO SET_IEEE80211_DEV(hw, sdiommc_dev); @@ -819,28 +717,14 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, } wl->bcm_bustype = bustype; -#ifdef WLC_HIGH_ONLY - if (wl->bcm_bustype == RPC_BUS) { - wl->regsva = (void *)0; - btparam = wl->rpc; - } else -#endif wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ); if (wl->regsva == NULL) { WL_ERROR(("wl%d: ioremap() failed\n", unit)); goto fail; } -#ifdef WLC_HIGH_ONLY - spin_lock_init(&wl->rpcq_lock); - spin_lock_init(&wl->txq_lock); - - sema_init(&wl->sem, 1); -#else spin_lock_init(&wl->lock); spin_lock_init(&wl->isr_lock); -#endif -#ifndef WLC_HIGH_ONLY /* prepare ucode */ if (wl_request_fw(wl, (struct pci_dev *)btparam)) { printf("%s: Failed to find firmware usually in %s\n", @@ -849,14 +733,11 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, wl_remove((struct pci_dev *)btparam); goto fail1; } -#endif /* common load-time initialization */ wl->wlc = wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh, wl->regsva, wl->bcm_bustype, btparam, &err); -#ifndef WLC_HIGH_ONLY wl_release_fw(wl); -#endif if (!wl->wlc) { printf("%s: wlc_attach() failed with code %d\n", KBUILD_MODNAME, err); @@ -868,14 +749,6 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, ASSERT(wl->pub->ieee_hw); ASSERT(wl->pub->ieee_hw->priv == wl); -#ifdef WLC_HIGH_ONLY - REGOPSSET(osh, (osl_rreg_fn_t) wlc_reg_read, - (osl_wreg_fn_t) wlc_reg_write, wl->wlc); - wl->rpc_dispatch_ctx.rpc = wl->rpc; - wl->rpc_dispatch_ctx.wlc = wl->wlc; - bcm_rpc_rxcb_init(wl->rpc, wl, wl_rpc_dispatch_schedule, wl, - wl_rpc_down, NULL, NULL); -#endif /* WLC_HIGH_ONLY */ if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { WL_ERROR(("wl%d: Error setting MPC variable to 0\n", @@ -922,13 +795,8 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__, err)); } -#ifndef WLC_HIGH_ONLY WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver " " (" PHY_VERSION_STR ")", unit)); -#else - WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 Splitmac MAC80211 Driver " - , unit)); -#endif #ifdef BCMDBG printf(" (Compiled at " __TIME__ " on " __DATE__ ")"); @@ -944,54 +812,6 @@ fail1: return NULL; } -#ifdef WLC_HIGH_ONLY -static void *wl_dbus_probe_cb(void *arg, const char *desc, u32 bustype, - u32 hdrlen) -{ - wl_info_t *wl; - WL_ERROR(("%s:\n", __func__)); - - wl = wl_attach(BCM_DNGL_VID, BCM_DNGL_BDC_PID, (unsigned long) NULL, RPC_BUS, - NULL, 0); - if (!wl) { - WL_ERROR(("%s: wl_attach failed\n", __func__)); - } - - /* This is later passed to wl_dbus_disconnect_cb */ - return wl; -} - -static void wl_dbus_disconnect_cb(void *arg) -{ - wl_info_t *wl = arg; - - WL_ERROR(("%s:\n", __func__)); - - if (wl) { -#ifdef WLC_HIGH_ONLY - if (wl->pub->ieee_hw) { - ieee80211_unregister_hw(wl->pub->ieee_hw); - WL_ERROR(("%s: Back from down\n", __func__)); - } - wlc_device_removed(wl->wlc); - wlc_bmac_dngl_reboot(wl->rpc); - bcm_rpc_down(wl->rpc); -#endif - WL_LOCK(wl); - wl_down(wl); - WL_UNLOCK(wl); -#ifdef WLC_HIGH_ONLY - if (wl->pub->ieee_hw) { - ieee80211_free_hw(wl->pub->ieee_hw); - WL_ERROR(("%s: Back from ieee80211_free_hw\n", - __func__)); - wl->pub->ieee_hw = NULL; - } -#endif - wl_free(wl); - } -} -#endif /* WLC_HIGH_ONLY */ #define CHAN2GHZ(channel, freqency, chflags) { \ @@ -1129,29 +949,13 @@ static struct ieee80211_supported_band wl_band_2GHz_nphy = { .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, -#ifdef WLC_HIGH_ONLY - .ht_supported = true, - .ampdu_factor = AMPDU_RX_FACTOR_16K, -#else .ht_supported = true, .ampdu_factor = AMPDU_RX_FACTOR_64K, -#endif .ampdu_density = AMPDU_DEF_MPDU_DENSITY, .mcs = { /* placeholders for now */ -#ifdef WLC_HIGH_ONLY - /* - * rx_mask[0] = 0xff by default - * rx_mask[1] = 0xff if number of rx chain >=2 - * rx_mask[2] = 0xff if number of rx chain >=3 - * rx_mask[4] = 1 if 40Mhz is supported - */ - .rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - .rx_highest = 72, /* max rate of single stream */ -#else .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, .rx_highest = 500, -#endif .tx_params = IEEE80211_HT_MCS_TX_DEFINED} } }; @@ -1192,16 +996,12 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) } WL_NONE(("%s: phylist = %c\n", __func__, phy_list[0])); -#ifndef WLC_HIGH_ONLY if (phy_list[0] == 'n' || phy_list[0] == 'c') { if (phy_list[0] == 'c') { /* Single stream */ wl_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0; wl_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72; } -#else - if (phy_list[0] == 's') { -#endif hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl_band_2GHz_nphy; } else { BUG(); @@ -1211,11 +1011,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) /* Assume all bands use the same phy. True for 11n devices. */ if (NBANDS_PUB(wl->pub) > 1) { has_5g++; -#ifndef WLC_HIGH_ONLY if (phy_list[0] == 'n' || phy_list[0] == 'c') { -#else - if (phy_list[0] == 's') { -#endif hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl_band_5GHz_nphy; } else { @@ -1446,7 +1242,6 @@ static int __init wl_module_init(void) if (var) wl_msg_level = simple_strtoul(var, NULL, 0); } -#ifndef WLC_HIGH_ONLY { extern u32 phyhal_msg_level; @@ -1458,7 +1253,6 @@ static int __init wl_module_init(void) phyhal_msg_level = simple_strtoul(var, NULL, 0); } } -#endif /* WLC_HIGH_ONLY */ #endif /* BCMDBG */ #ifndef BCMSDIO @@ -1468,15 +1262,6 @@ static int __init wl_module_init(void) #endif /* !BCMSDIO */ -#ifdef WLC_HIGH_ONLY - /* BMAC_NOTE: define hardcode number, why NODEVICE is ok ? */ - error = - dbus_register(BCM_DNGL_VID, 0, wl_dbus_probe_cb, - wl_dbus_disconnect_cb, NULL, NULL, NULL); - if (error == DBUS_ERR_NODEVICE) { - error = DBUS_OK; - } -#endif /* WLC_HIGH_ONLY */ return error; } @@ -1494,9 +1279,6 @@ static void __exit wl_module_exit(void) pci_unregister_driver(&wl_pci_driver); #endif /* !BCMSDIO */ -#ifdef WLC_HIGH_ONLY - dbus_deregister(); -#endif /* WLC_HIGH_ONLY */ } module_init(wl_module_init); @@ -1515,13 +1297,11 @@ void wl_free(wl_info_t *wl) struct osl_info *osh; ASSERT(wl); -#ifndef WLC_HIGH_ONLY /* free ucode data */ if (wl->fw.fw_cnt) wl_ucode_data_free(); if (wl->irq) free_irq(wl->irq, wl); -#endif /* kill dpc */ tasklet_kill(&wl->tasklet); @@ -1565,21 +1345,6 @@ void wl_free(wl_info_t *wl) } wl->regsva = NULL; -#ifdef WLC_HIGH_ONLY - wl_rpcq_free(wl); - - wl_txq_free(wl); - - if (wl->rpc) { - bcm_rpc_detach(wl->rpc); - wl->rpc = NULL; - } - - if (wl->rpc_th) { - bcm_rpc_tp_detach(wl->rpc_th); - wl->rpc_th = NULL; - } -#endif /* WLC_HIGH_ONLY */ osl_detach(osh); } @@ -1598,13 +1363,7 @@ static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) static int BCMFASTPATH wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, struct sk_buff *skb) { -#ifdef WLC_HIGH_ONLY - WL_LOCK(wl); -#endif wlc_sendpkt_mac80211(wl->wlc, skb, hw); -#ifdef WLC_HIGH_ONLY - WL_UNLOCK(wl); -#endif return NETDEV_TX_OK; } @@ -1613,36 +1372,6 @@ void wl_txflowcontrol(wl_info_t *wl, struct wl_if *wlif, bool state, int prio) WL_ERROR(("Shouldn't be here %s\n", __func__)); } -#if defined(WLC_HIGH_ONLY) -/* Schedule a completion handler to run at safe time */ -static int -wl_schedule_task(wl_info_t *wl, void (*fn) (struct wl_task *task), - void *context) -{ - wl_task_t *task; - - WL_TRACE(("wl%d: wl_schedule_task\n", wl->pub->unit)); - - task = kmalloc(sizeof(wl_task_t), GFP_ATOMIC); - if (!task) { - WL_ERROR(("wl%d: wl_schedule_task: out of memory\n", wl->pub->unit)); - return -ENOMEM; - } - - INIT_WORK(&task->work, (work_func_t) fn); - task->context = context; - - if (!schedule_work(&task->work)) { - WL_ERROR(("wl%d: schedule_work() failed\n", wl->pub->unit)); - kfree(task); - return -ENOMEM; - } - - atomic_inc(&wl->callbacks); - - return 0; -} -#endif /* defined(WLC_HIGH_ONLY) */ void wl_init(wl_info_t *wl) { @@ -1734,12 +1463,10 @@ void wl_down(wl_info_t *wl) /* wait for down callbacks to complete */ WL_UNLOCK(wl); -#ifndef WLC_HIGH_ONLY /* For HIGH_only driver, it's important to actually schedule other work, * not just spin wait since everything runs at schedule level */ SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); -#endif /* WLC_HIGH_ONLY */ WL_LOCK(wl); } @@ -1843,12 +1570,7 @@ void wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e) static void wl_timer(unsigned long data) { -#ifndef WLC_HIGH_ONLY _wl_timer((wl_timer_t *) data); -#else - wl_timer_t *t = (wl_timer_t *) data; - wl_schedule_task(t->wl, wl_timer_task, t); -#endif /* WLC_HIGH_ONLY */ } static void _wl_timer(wl_timer_t *t) @@ -2015,226 +1737,7 @@ struct wl_fw_hdr { u32 idx; }; -#ifdef WLC_HIGH_ONLY -static void wl_rpc_down(void *wlh) -{ - wl_info_t *wl = (wl_info_t *) (wlh); - - wlc_device_removed(wl->wlc); - - wl_rpcq_free(wl); -} - -static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) -{ - - unsigned long flags; - - skb->prev = NULL; - - /* Lock the queue as tasklet could be running at this time */ - TXQ_LOCK(wl, flags); - if (wl->txq_head == NULL) - wl->txq_head = skb; - else { - wl->txq_tail->prev = skb; - } - wl->txq_tail = skb; - - if (wl->txq_dispatched == false) { - wl->txq_dispatched = true; - - if (schedule_work(&wl->txq_task.work)) { - atomic_inc(&wl->callbacks); - } else { - WL_ERROR(("wl%d: wl_start/schedule_work failed\n", - wl->pub->unit)); - } - } - - TXQ_UNLOCK(wl, flags); - - return 0; - -} - -static void wl_start_txqwork(struct wl_task *task) -{ - wl_info_t *wl = (wl_info_t *) task->context; - struct sk_buff *skb; - unsigned long flags; - uint count = 0; - - WL_TRACE(("wl%d: wl_start_txqwork\n", wl->pub->unit)); - - /* First remove an entry then go for execution */ - TXQ_LOCK(wl, flags); - while (wl->txq_head) { - skb = wl->txq_head; - wl->txq_head = skb->prev; - skb->prev = NULL; - if (wl->txq_head == NULL) - wl->txq_tail = NULL; - TXQ_UNLOCK(wl, flags); - - /* it has WL_LOCK/WL_UNLOCK inside */ - wl_start_int(wl, WL_TO_HW(wl), skb); - - /* bounded our execution, reshedule ourself next */ - if (++count >= 10) - break; - - TXQ_LOCK(wl, flags); - } - - if (count >= 10) { - if (!schedule_work(&wl->txq_task.work)) { - WL_ERROR(("wl%d: wl_start/schedule_work failed\n", - wl->pub->unit)); - atomic_dec(&wl->callbacks); - } - } else { - wl->txq_dispatched = false; - TXQ_UNLOCK(wl, flags); - atomic_dec(&wl->callbacks); - } - - return; -} - -static void wl_txq_free(wl_info_t *wl) -{ - struct sk_buff *skb; - - if (wl->txq_head == NULL) { - ASSERT(wl->txq_tail == NULL); - return; - } - - while (wl->txq_head) { - skb = wl->txq_head; - wl->txq_head = skb->prev; - PKTFREE(wl->osh, skb, true); - } - - wl->txq_tail = NULL; -} - -static void wl_rpcq_free(wl_info_t *wl) -{ - rpc_buf_t *buf; - - if (wl->rpcq_head == NULL) { - ASSERT(wl->rpcq_tail == NULL); - return; - } - - while (wl->rpcq_head) { - buf = wl->rpcq_head; - wl->rpcq_head = bcm_rpc_buf_next_get(wl->rpc_th, buf); - bcm_rpc_buf_free(wl->rpc_dispatch_ctx.rpc, buf); - } - - wl->rpcq_tail = NULL; -} - -static void wl_rpcq_dispatch(struct wl_task *task) -{ - wl_info_t *wl = (wl_info_t *) task->context; - rpc_buf_t *buf; - unsigned long flags; - - /* First remove an entry then go for execution */ - RPCQ_LOCK(wl, flags); - while (wl->rpcq_head) { - buf = wl->rpcq_head; - wl->rpcq_head = bcm_rpc_buf_next_get(wl->rpc_th, buf); - - if (wl->rpcq_head == NULL) - wl->rpcq_tail = NULL; - RPCQ_UNLOCK(wl, flags); - - WL_LOCK(wl); - wlc_rpc_high_dispatch(&wl->rpc_dispatch_ctx, buf); - WL_UNLOCK(wl); - - RPCQ_LOCK(wl, flags); - } - - wl->rpcq_dispatched = false; - - RPCQ_UNLOCK(wl, flags); - - kfree(task); - atomic_dec(&wl->callbacks); -} - -static void wl_rpcq_add(wl_info_t *wl, rpc_buf_t *buf) -{ - unsigned long flags; - - bcm_rpc_buf_next_set(wl->rpc_th, buf, NULL); - - /* Lock the queue as tasklet could be running at this time */ - RPCQ_LOCK(wl, flags); - if (wl->rpcq_head == NULL) - wl->rpcq_head = buf; - else - bcm_rpc_buf_next_set(wl->rpc_th, wl->rpcq_tail, buf); - - wl->rpcq_tail = buf; - - if (wl->rpcq_dispatched == false) { - wl->rpcq_dispatched = true; - wl_schedule_task(wl, wl_rpcq_dispatch, wl); - } - - RPCQ_UNLOCK(wl, flags); -} - -#if defined(BCMDBG) -static const struct name_entry rpc_name_tbl[] = RPC_ID_TABLE; -#endif /* BCMDBG */ - -/* dongle-side rpc dispatch routine */ -static void wl_rpc_dispatch_schedule(void *ctx, struct rpc_buf *buf) -{ - bcm_xdr_buf_t b; - wl_info_t *wl = (wl_info_t *) ctx; - wlc_rpc_id_t rpc_id; - int err; - - bcm_xdr_buf_init(&b, bcm_rpc_buf_data(wl->rpc_th, buf), - bcm_rpc_buf_len_get(wl->rpc_th, buf)); - - err = bcm_xdr_unpack_u32(&b, &rpc_id); - ASSERT(!err); - WL_TRACE(("%s: Dispatch id %s\n", __func__, - WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id))); - - /* Handle few emergency ones */ - switch (rpc_id) { - default: - wl_rpcq_add(wl, buf); - break; - } -} - -static void wl_timer_task(wl_task_t *task) -{ - wl_timer_t *t = (wl_timer_t *) task->context; - - _wl_timer(t); - kfree(task); - - /* This dec is for the task_schedule. The timer related - * callback is decremented in _wl_timer - */ - atomic_dec(&t->wl->callbacks); -} -#endif /* WLC_HIGH_ONLY */ -#ifndef WLC_HIGH_ONLY char *wl_firmwares[WL_MAX_FW] = { "brcm/bcm43xx", NULL @@ -2345,4 +1848,3 @@ static void wl_release_fw(wl_info_t *wl) release_firmware(wl->fw.fw_hdr[i]); } } -#endif /* WLC_HIGH_ONLY */ diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h index 54bbb15d9585..ba9d48cd0193 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.h +++ b/drivers/staging/brcm80211/sys/wl_mac80211.h @@ -67,12 +67,8 @@ struct wl_info { int irq; -#ifdef WLC_HIGH_ONLY - struct semaphore sem; /* use semaphore to allow sleep */ -#else spinlock_t lock; /* per-device perimeter lock */ spinlock_t isr_lock; /* per-device ISR synchronization lock */ -#endif uint bcm_bustype; /* bus type */ bool piomode; /* set from insmod argument */ void *regsva; /* opaque chip registers virtual address */ @@ -88,30 +84,12 @@ struct wl_info { u32 pci_psstate[16]; /* pci ps-state save/restore */ #endif /* RPC, handle, lock, txq, workitem */ -#ifdef WLC_HIGH_ONLY - rpc_info_t *rpc; /* RPC handle */ - rpc_tp_info_t *rpc_th; /* RPC transport handle */ - wlc_rpc_ctx_t rpc_dispatch_ctx; - - bool rpcq_dispatched; /* Avoid scheduling multiple tasks */ - spinlock_t rpcq_lock; /* Lock for the queue */ - rpc_buf_t *rpcq_head; /* RPC Q */ - rpc_buf_t *rpcq_tail; /* Points to the last buf */ - - bool txq_dispatched; /* Avoid scheduling multiple tasks */ - spinlock_t txq_lock; /* Lock for the queue */ - struct sk_buff *txq_head; /* TX Q */ - struct sk_buff *txq_tail; /* Points to the last buf */ - - wl_task_t txq_task; /* work queue for wl_start() */ -#endif /* WLC_HIGH_ONLY */ uint stats_id; /* the current set of stats */ /* ping-pong stats counters updated by Linux watchdog */ struct net_device_stats stats_watchdog[2]; struct wl_firmware fw; }; -#ifndef WLC_HIGH_ONLY #define WL_LOCK(wl) spin_lock_bh(&(wl)->lock) #define WL_UNLOCK(wl) spin_unlock_bh(&(wl)->lock) @@ -122,14 +100,6 @@ struct wl_info { /* locking under WL_LOCK() to synchronize with wl_isr */ #define INT_LOCK(wl, flags) spin_lock_irqsave(&(wl)->isr_lock, flags) #define INT_UNLOCK(wl, flags) spin_unlock_irqrestore(&(wl)->isr_lock, flags) -#else /* BCMSDIO */ - -#define WL_LOCK(wl) down(&(wl)->sem) -#define WL_UNLOCK(wl) up(&(wl)->sem) - -#define WL_ISRLOCK(wl) -#define WL_ISRUNLOCK(wl) -#endif /* WLC_HIGH_ONLY */ /* handle forward declaration */ typedef struct wl_info wl_info_t; diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 1fb9976ef8b4..e863a81e045c 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -63,11 +63,6 @@ void wlc_tunables_init(wlc_tunables_t *tunables, uint devid) tunables->ampdudatahiwat = WLC_AMPDUDATAHIWAT; tunables->rxbnd = RXBND; tunables->txsbnd = TXSBND; -#if defined(WLC_HIGH_ONLY) && defined(NTXD_USB_4319) - if (devid == BCM4319_CHIP_ID) { - tunables->ntxd = NTXD_USB_4319; - } -#endif /* WLC_HIGH_ONLY */ } static wlc_pub_t *wlc_pub_malloc(struct osl_info *osh, uint unit, uint *err, diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index dc327026a0f0..ab883ba76def 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -38,10 +38,6 @@ #include #include -#ifdef WLC_HIGH_ONLY -#include -#include -#endif #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */ #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */ @@ -126,11 +122,6 @@ struct ampdu_info { */ wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */ -#ifdef WLC_HIGH_ONLY - void *p; - tx_status_t txs; - bool waiting_status; /* To help sanity checks */ -#endif }; #define AMPDU_CLEANUPFLAG_RX (0x1) @@ -210,10 +201,6 @@ ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc) ampdu->rx_factor = AMPDU_RX_FACTOR_32K; else ampdu->rx_factor = AMPDU_RX_FACTOR_64K; -#ifdef WLC_HIGH_ONLY - /* Restrict to smaller rcv size for BMAC dongle */ - ampdu->rx_factor = AMPDU_RX_FACTOR_32K; -#endif ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT; ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT; @@ -887,19 +874,9 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec) if (frameid & TXFID_RATE_PROBE_MASK) { WL_ERROR(("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n", __func__)); } -#ifdef WLC_HIGH_ONLY - if (wlc->rpc_agg & BCM_RPC_TP_HOST_AGG_AMPDU) - bcm_rpc_tp_agg_set(bcm_rpc_tp_get(wlc->rpc), - BCM_RPC_TP_HOST_AGG_AMPDU, true); -#endif for (i = 0; i < count; i++) wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1), ampdu->txpkt_weight); -#ifdef WLC_HIGH_ONLY - if (wlc->rpc_agg & BCM_RPC_TP_HOST_AGG_AMPDU) - bcm_rpc_tp_agg_set(bcm_rpc_tp_get(wlc->rpc), - BCM_RPC_TP_HOST_AGG_AMPDU, false); -#endif } /* endif (count) */ @@ -967,31 +944,6 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p, wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini); } -#ifdef WLC_HIGH_ONLY -void wlc_ampdu_txstatus_complete(ampdu_info_t *ampdu, u32 s1, u32 s2) -{ - WL_AMPDU_TX(("wl%d: wlc_ampdu_txstatus_complete: High Recvd 0x%x 0x%x p:%p\n", ampdu->wlc->pub->unit, s1, s2, ampdu->p)); - - ASSERT(ampdu->waiting_status); - - /* The packet may have been freed if the SCB went away, if so, then still free the - * DMA chain - */ - if (ampdu->p) { - struct ieee80211_tx_info *tx_info; - struct scb *scb; - - tx_info = IEEE80211_SKB_CB(ampdu->p); - scb = (struct scb *)tx_info->control.sta->drv_priv; - - wlc_ampdu_dotxstatus_complete(ampdu, scb, ampdu->p, &du->txs, - s1, s2); - ampdu->p = NULL; - } - - ampdu->waiting_status = false; -} -#endif /* WLC_HIGH_ONLY */ void rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info, tx_status_t *txs, u8 mcs); @@ -1117,11 +1069,6 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p, if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid]) > 0) { tx_error = true; -#ifdef WLC_HIGH_ONLY - /* With BMAC, TX Underflows should not happen */ - WL_ERROR(("wl%d: BMAC TX Underflow?", - wlc->pub->unit)); -#endif } } } else if (txs->phyerr) { diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.h b/drivers/staging/brcm80211/sys/wlc_ampdu.h index c721b16cc706..939cae0d7b4f 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.h +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.h @@ -32,9 +32,5 @@ extern void wlc_ampdu_shm_upd(ampdu_info_t *ampdu); extern u8 wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb, ratespec_t rspec, int phylen); extern void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb); -#ifdef WLC_HIGH_ONLY -extern void wlc_ampdu_txstatus_complete(ampdu_info_t *ampdu, u32 s1, - u32 s2); -#endif #endif /* _wlc_ampdu_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.h b/drivers/staging/brcm80211/sys/wlc_bmac.h index 4cc41f9f4619..c3d251a6417a 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.h +++ b/drivers/staging/brcm80211/sys/wlc_bmac.h @@ -242,16 +242,6 @@ extern void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL, extern void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw); -#ifdef WLC_HIGH_ONLY -extern void wlc_bmac_dngl_reboot(rpc_info_t *); -extern void wlc_bmac_dngl_rpc_agg(rpc_info_t *, u16 agg); -extern void wlc_bmac_dngl_rpc_msglevel(rpc_info_t *, u16 level); -extern void wlc_bmac_dngl_rpc_txq_wm_set(rpc_info_t *rpc, u32 wm); -extern void wlc_bmac_dngl_rpc_txq_wm_get(rpc_info_t *rpc, u32 *wm); -extern void wlc_bmac_dngl_rpc_agg_limit_set(rpc_info_t *rpc, u32 val); -extern void wlc_bmac_dngl_rpc_agg_limit_get(rpc_info_t *rpc, u32 *pval); -extern int wlc_bmac_debug_template(wlc_hw_info_t *wlc_hw); -#endif /* API for BMAC driver (e.g. wlc_phy.c etc) */ diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 513e4d9a1ad2..c270d3f4072f 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -53,23 +53,10 @@ #else #include "d11ucode_ext.h" #endif -#ifdef WLC_HIGH_ONLY -#include -#include -#include -#include -#include -#endif /* WLC_HIGH_ONLY */ #include #include #include -#ifdef WLC_HIGH_ONLY -#undef R_REG -#undef W_REG -#define R_REG(osh, r) RPC_READ_REG(osh, r) -#define W_REG(osh, r, v) RPC_WRITE_REG(osh, r, v) -#endif /* * buffer length needed for wlc_format_ssid @@ -109,12 +96,8 @@ /* To inform the ucode of the last mcast frame posted so that it can clear moredata bit */ #define BCMCFID(wlc, fid) wlc_bmac_write_shm((wlc)->hw, M_BCMC_FID, (fid)) -#ifndef WLC_HIGH_ONLY #define WLC_WAR16165(wlc) (BUSTYPE(wlc->pub->sih->bustype) == PCI_BUS && \ (!AP_ENAB(wlc->pub)) && (wlc->war16165)) -#else -#define WLC_WAR16165(wlc) (false) -#endif /* WLC_HIGH_ONLY */ /* debug/trace */ uint wl_msg_level = @@ -401,22 +384,6 @@ void wlc_reset(wlc_info_t *wlc) wlc_ampdu_reset(wlc->ampdu); wlc->txretried = 0; -#ifdef WLC_HIGH_ONLY - /* Need to set a flag(to be cleared asynchronously by BMAC driver with high call) - * in order to prevent wlc_rpctx_txreclaim() from screwing wlc_rpctx_getnexttxp(), - * which could be invoked by already QUEUED high call(s) from BMAC driver before - * wlc_bmac_reset() finishes. - * It's not needed before in monolithic driver model because d11core interrupts would - * have been cleared instantly in wlc_bmac_reset() and no txstatus interrupt - * will come to driver to fetch those flushed dma pkt pointers. - */ - wlc->reset_bmac_pending = true; - - wlc_rpctx_txreclaim(wlc->rpctx); - - wlc_stf_phy_txant_upd(wlc); - wlc_phy_ant_rxdiv_set(wlc->band->pi, wlc->stf->ant_rx_ovr); -#endif } void wlc_fatal_error(wlc_info_t *wlc) @@ -1858,10 +1825,6 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, /* propagate *vars* from BMAC driver to high driver */ wlc_bmac_copyfrom_vars(wlc->hw, &pub->vars, &wlc->vars_size); -#ifdef WLC_HIGH_ONLY - WL_TRACE(("nvram : vars %p , vars_size %d\n", pub->vars, - wlc->vars_size)); -#endif /* set maximum allowed duty cycle */ wlc->tx_duty_cycle_ofdm = @@ -2139,134 +2102,6 @@ static bool wlc_attach_stf_ant_init(wlc_info_t *wlc) return true; } -#ifdef WLC_HIGH_ONLY -/* HIGH_ONLY bmac_attach, which sync over LOW_ONLY bmac_attach states */ -int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, - bool piomode, struct osl_info *osh, void *regsva, - uint bustype, void *btparam) -{ - wlc_bmac_revinfo_t revinfo; - uint idx = 0; - rpc_info_t *rpc = (rpc_info_t *) btparam; - - ASSERT(bustype == RPC_BUS); - - /* install the rpc handle in the various state structures used by stub RPC functions */ - wlc->rpc = rpc; - wlc->hw->rpc = rpc; - wlc->hw->osh = osh; - - wlc->regs = 0; - - wlc->rpctx = wlc_rpctx_attach(wlc->pub, wlc); - if (wlc->rpctx == NULL) - return -1; - - /* - * FIFO 0 - * TX: TX_AC_BK_FIFO (TX AC Background data packets) - */ - /* Always initialized */ - ASSERT(NRPCTXBUFPOST <= NTXD); - wlc_rpctx_fifoinit(wlc->rpctx, TX_DATA_FIFO, NRPCTXBUFPOST); - wlc_rpctx_fifoinit(wlc->rpctx, TX_CTL_FIFO, NRPCTXBUFPOST); - wlc_rpctx_fifoinit(wlc->rpctx, TX_BCMC_FIFO, NRPCTXBUFPOST); - - /* VI and BK inited only if WME */ - if (WME_ENAB(wlc->pub)) { - wlc_rpctx_fifoinit(wlc->rpctx, TX_AC_BK_FIFO, NRPCTXBUFPOST); - wlc_rpctx_fifoinit(wlc->rpctx, TX_AC_VI_FIFO, NRPCTXBUFPOST); - } - - /* Allocate SB handle */ - wlc->pub->sih = osl_malloc(wlc->osh, sizeof(si_t)); - if (!wlc->pub->sih) - return -1; - bzero(wlc->pub->sih, sizeof(si_t)); - - /* sync up revinfo with BMAC */ - bzero(&revinfo, sizeof(wlc_bmac_revinfo_t)); - if (wlc_bmac_revinfo_get(wlc->hw, &revinfo) != 0) - return -1; - wlc->vendorid = (u16) revinfo.vendorid; - wlc->deviceid = (u16) revinfo.deviceid; - - wlc->pub->boardrev = (u16) revinfo.boardrev; - wlc->pub->corerev = revinfo.corerev; - wlc->pub->sromrev = (u8) revinfo.sromrev; - wlc->pub->sih->chiprev = revinfo.chiprev; - wlc->pub->sih->chip = revinfo.chip; - wlc->pub->sih->chippkg = revinfo.chippkg; - wlc->pub->sih->boardtype = revinfo.boardtype; - wlc->pub->sih->boardvendor = revinfo.boardvendor; - wlc->pub->sih->bustype = revinfo.bustype; - wlc->pub->sih->buscoretype = revinfo.buscoretype; - wlc->pub->sih->buscorerev = revinfo.buscorerev; - wlc->pub->sih->issim = (bool) revinfo.issim; - wlc->pub->sih->rpc = rpc; - - if (revinfo.nbands == 0 || revinfo.nbands > 2) - return -1; - wlc->pub->_nbands = revinfo.nbands; - - for (idx = 0; idx < wlc->pub->_nbands; idx++) { - uint bandunit, bandtype; /* To access bandstate */ - wlc_phy_t *pi = osl_malloc(wlc->osh, sizeof(wlc_phy_t)); - - if (!pi) - return -1; - bzero(pi, sizeof(wlc_phy_t)); - pi->rpc = rpc; - - bandunit = revinfo.band[idx].bandunit; - bandtype = revinfo.band[idx].bandtype; - wlc->bandstate[bandunit]->radiorev = - (u8) revinfo.band[idx].radiorev; - wlc->bandstate[bandunit]->phytype = - (u16) revinfo.band[idx].phytype; - wlc->bandstate[bandunit]->phyrev = - (u16) revinfo.band[idx].phyrev; - wlc->bandstate[bandunit]->radioid = - (u16) revinfo.band[idx].radioid; - wlc->bandstate[bandunit]->abgphy_encore = - revinfo.band[idx].abgphy_encore; - - wlc->bandstate[bandunit]->pi = pi; - wlc->bandstate[bandunit]->bandunit = bandunit; - wlc->bandstate[bandunit]->bandtype = bandtype; - } - - /* misc stuff */ - - return 0; -} - -/* Free the convenience handles */ -int wlc_bmac_detach(wlc_info_t *wlc) -{ - uint idx; - - if (wlc->pub->sih) { - osl_mfree(wlc->osh, (void *)wlc->pub->sih, sizeof(si_t)); - wlc->pub->sih = NULL; - } - - for (idx = 0; idx < MAXBANDS; idx++) - if (wlc->bandstate[idx]->pi) { - kfree(wlc->bandstate[idx]->pi); - wlc->bandstate[idx]->pi = NULL; - } - - if (wlc->rpctx) { - wlc_rpctx_detach(wlc->rpctx); - wlc->rpctx = NULL; - } - - return 0; - -} - -#endif /* WLC_HIGH_ONLY */ static void wlc_timers_deinit(wlc_info_t *wlc) { @@ -2335,15 +2170,6 @@ uint wlc_detach(wlc_info_t *wlc) /* free other state */ -#ifdef WLC_HIGH_ONLY - /* High-Only driver has an allocated copy of vars, monolithic just - * references the wlc->hw->vars which is freed in wlc_bmac_detach() - */ - if (wlc->pub->vars) { - kfree(wlc->pub->vars); - wlc->pub->vars = NULL; - } -#endif #ifdef BCMDBG if (wlc->country_ie_override) { @@ -2677,10 +2503,6 @@ static void wlc_watchdog(void *arg) #ifdef WLC_LOW wlc_bmac_watchdog(wlc); #endif -#ifdef WLC_HIGH_ONLY - /* maintenance */ - wlc_bmac_rpc_watchdog(wlc); -#endif /* occasionally sample mac stat counters to detect 16-bit counter wrap */ if ((WLC_UPDATE_STATS(wlc)) @@ -2929,9 +2751,6 @@ uint wlc_down(wlc_info_t *wlc) /* wlc_bmac_down_finish has done wlc_coredisable(). so clk is off */ wlc->clk = false; -#ifdef WLC_HIGH_ONLY - wlc_rpctx_txreclaim(wlc->rpctx); -#endif /* Verify all packets are flushed from the driver */ if (PKTALLOCED(wlc->osh) != 0) { @@ -3395,10 +3214,6 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) wlc_set_chanspec(wlc, chspec); wlc_enable_mac(wlc); } -#ifdef WLC_HIGH_ONLY - /* delay for channel change */ - msleep(50); -#endif break; } @@ -4629,11 +4444,6 @@ wlc_iovar_op(wlc_info_t *wlc, const char *name, /* iovar name not found */ if (i >= WLC_MAXMODULES) { err = BCME_UNSUPPORTED; -#ifdef WLC_HIGH_ONLY - err = - bcmsdh_iovar_op(wlc->btparam, name, params, p_len, arg, len, - set); -#endif goto exit; } @@ -5195,14 +5005,6 @@ u16 wlc_rate_shm_offset(wlc_info_t *wlc, u8 rate) } /* Callback for device removed */ -#if defined(WLC_HIGH_ONLY) -void wlc_device_removed(void *arg) -{ - wlc_info_t *wlc = (wlc_info_t *) arg; - - wlc->device_present = false; -} -#endif /* WLC_HIGH_ONLY */ /* * Attempts to queue a packet onto a multiple-precedence queue, @@ -5467,13 +5269,6 @@ wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend) if (WLC_WAR16165(wlc)) wlc_war16165(wlc, true); -#ifdef WLC_HIGH_ONLY - if (RPCTX_ENAB(wlc->pub)) { - (void)wlc_rpctx_tx(wlc->rpctx, fifo, p, commit, frameid, - txpktpend); - return; - } -#else /* Bump up pending count for if not using rpc. If rpc is used, this will be handled * in wlc_bmac_txfifo() @@ -5491,7 +5286,6 @@ wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend) if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) { WL_ERROR(("wlc_txfifo: fatal, toss frames !!!\n")); } -#endif /* WLC_HIGH_ONLY */ } static u16 @@ -5805,9 +5599,7 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec) /* phy clock must support 40Mhz if tx descriptor uses it */ if ((phyctl1 & PHY_TXC1_BW_MASK) >= PHY_TXC1_BW_40MHZ) { ASSERT(CHSPEC_WLC_BW(wlc->chanspec) == WLC_40_MHZ); -#ifndef WLC_HIGH_ONLY ASSERT(wlc->chanspec == wlc_phy_chanspec_get(wlc->band->pi)); -#endif } #endif /* BCMDBG */ return phyctl1; @@ -5988,13 +5780,6 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, if (txrate[1]->idx < 0) { txrate[1] = txrate[0]; } -#ifdef WLC_HIGH_ONLY - /* Double protection , just in case */ - if (txrate[0]->idx > HIGHEST_SINGLE_STREAM_MCS) - txrate[0]->idx = HIGHEST_SINGLE_STREAM_MCS; - if (txrate[1]->idx > HIGHEST_SINGLE_STREAM_MCS) - txrate[1]->idx = HIGHEST_SINGLE_STREAM_MCS; -#endif for (k = 0; k < hw->max_rates; k++) { is_mcs[k] = @@ -6693,9 +6478,7 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus) if (!pktq_empty(&wlc->active_queue->q)) wlc_send_q(wlc, wlc->active_queue); -#ifndef WLC_HIGH_ONLY ASSERT(wlc_ps_check(wlc)); -#endif } static void *wlc_15420war(wlc_info_t *wlc, uint queue) @@ -6906,12 +6689,6 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) if (p) PKTFREE(osh, p, true); -#ifdef WLC_HIGH_ONLY - /* If this is a split driver, do the big-hammer here. - * If this is a monolithic driver, wlc_bmac.c:wlc_dpc() will do the big-hammer. - */ - wl_init(wlc->wl); -#endif return true; } @@ -8483,9 +8260,6 @@ void wlc_pllreq(wlc_info_t *wlc, bool set, mbool req_bit) void wlc_reset_bmac_done(wlc_info_t *wlc) { -#ifdef WLC_HIGH_ONLY - wlc->reset_bmac_pending = false; -#endif } void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index ee0081b307f1..cb142101c0c2 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -214,15 +214,11 @@ extern const u8 prio2fifo[]; * (some platforms return all 0). * If clocks are present, call the sb routine which will figure out if the device is removed. */ -#ifdef WLC_HIGH_ONLY -#define DEVICEREMOVED(wlc) (!wlc->device_present) -#else #define DEVICEREMOVED(wlc) \ ((wlc->hw->clk) ? \ ((R_REG(wlc->hw->osh, &wlc->hw->regs->maccontrol) & \ (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN) : \ (si_deviceremoved(wlc->hw->sih))) -#endif /* WLC_HIGH_ONLY */ #define WLCWLUNIT(wlc) ((wlc)->pub->unit) @@ -578,12 +574,6 @@ struct wlc_info { s8 txpwr_local_max; /* regulatory local txpwr max */ u8 txpwr_local_constraint; /* local power contraint in dB */ -#ifdef WLC_HIGH_ONLY - rpctx_info_t *rpctx; /* RPC TX module */ - bool reset_bmac_pending; /* bmac reset is in progressing */ - u32 rpc_agg; /* host agg: bit 16-31, bmac agg: bit 0-15 */ - u32 rpc_msglevel; /* host rpc: bit 16-31, bmac rpc: bit 0-15 */ -#endif ampdu_info_t *ampdu; /* ampdu module handler */ antsel_info_t *asi; /* antsel module handler */ @@ -843,16 +833,6 @@ struct antsel_info { #endif /* sum the individual fifo tx pending packet counts */ -#if defined(WLC_HIGH_ONLY) -#define TXPKTPENDTOT(wlc) (wlc_rpctx_txpktpend((wlc)->rpctx, 0, true)) -#define TXPKTPENDGET(wlc, fifo) (wlc_rpctx_txpktpend((wlc)->rpctx, (fifo), false)) -#define TXPKTPENDINC(wlc, fifo, val) (wlc_rpctx_txpktpendinc((wlc)->rpctx, (fifo), (val))) -#define TXPKTPENDDEC(wlc, fifo, val) (wlc_rpctx_txpktpenddec((wlc)->rpctx, (fifo), (val))) -#define TXPKTPENDCLR(wlc, fifo) (wlc_rpctx_txpktpendclr((wlc)->rpctx, (fifo))) -#define TXAVAIL(wlc, fifo) (wlc_rpctx_txavail((wlc)->rpctx, (fifo))) -#define GETNEXTTXP(wlc, _queue) (wlc_rpctx_getnexttxp((wlc)->rpctx, (_queue))) - -#else #define TXPKTPENDTOT(wlc) ((wlc)->core->txpktpend[0] + (wlc)->core->txpktpend[1] + \ (wlc)->core->txpktpend[2] + (wlc)->core->txpktpend[3]) #define TXPKTPENDGET(wlc, fifo) ((wlc)->core->txpktpend[(fifo)]) @@ -862,7 +842,6 @@ struct antsel_info { #define TXAVAIL(wlc, fifo) (*(wlc)->core->txavail[(fifo)]) #define GETNEXTTXP(wlc, _queue) \ dma_getnexttxp((wlc)->hw->di[(_queue)], HNDDMA_RANGE_TRANSMITTED) -#endif /* WLC_HIGH_ONLY */ #define WLC_IS_MATCH_SSID(wlc, ssid1, ssid2, len1, len2) \ ((len1 == len2) && !bcmp(ssid1, ssid2, len1)) diff --git a/drivers/staging/brcm80211/sys/wlc_rpctx.h b/drivers/staging/brcm80211/sys/wlc_rpctx.h index 7427154a4bd4..58ce5438632f 100644 --- a/drivers/staging/brcm80211/sys/wlc_rpctx.h +++ b/drivers/staging/brcm80211/sys/wlc_rpctx.h @@ -28,29 +28,6 @@ struct wlc_info; #define NRPCTXBUFPOST NTXD #endif -#if defined(WLC_HIGH_ONLY) - -struct wlc_rpc_phy { - struct rpc_info *rpc; -}; - -#define RPCTX_ENAB(pub) (true) -extern rpctx_info_t *wlc_rpctx_attach(wlc_pub_t *pub, struct wlc_info *wlc); -extern int wlc_rpctx_fifoinit(rpctx_info_t *rpctx, uint fifo, uint ntxd); -extern void wlc_rpctx_detach(rpctx_info_t *rpctx); -extern int wlc_rpctx_dump(rpctx_info_t *rpctx, struct bcmstrbuf *b); -extern void *wlc_rpctx_getnexttxp(rpctx_info_t *rpctx, uint fifo); -extern void wlc_rpctx_txreclaim(rpctx_info_t *rpctx); -extern uint wlc_rpctx_txavail(rpctx_info_t *rpctx, uint fifo); -extern int wlc_rpctx_pkteng(rpctx_info_t *rpctx, uint fifo, void *p); -extern int wlc_rpctx_tx(rpctx_info_t *rpctx, uint fifo, void *p, bool commit, - u16 frameid, u8 txpktpend); -extern void wlc_rpctx_txpktpendinc(rpctx_info_t *rpctx, uint fifo, u8 val); -extern void wlc_rpctx_txpktpenddec(rpctx_info_t *rpctx, uint fifo, u8 val); -extern void wlc_rpctx_txpktpendclr(rpctx_info_t *rpctx, uint fifo); -extern int wlc_rpctx_txpktpend(rpctx_info_t *rpctx, uint fifo, bool all); - -#else #define RPCTX_ENAB(pub) (false) #define wlc_rpctx_attach(pub, wlc) (NULL) #define wlc_rpctx_fifoinit(rpctx, fifo, ntxd) (0) @@ -66,6 +43,5 @@ extern int wlc_rpctx_txpktpend(rpctx_info_t *rpctx, uint fifo, bool all); #define wlc_rpctx_txpktpendclr(rpctx, f) do { } while (0) #define wlc_rpctx_txpktpend(rpctx, f, all) (0) -#endif /* WLC_HIGH */ #endif /* _wlc_rpctx_h_ */ -- cgit v1.2.3 From 02db6b4769e2465b872a6cd87465a3e20d4573ce Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:53 -0800 Subject: staging: brcm80211: unifdef -UWLC_LOW_ONLY Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index cb142101c0c2..9d0d8f336dde 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -496,15 +496,6 @@ struct wlc_hw_info { #endif bool ucode_loaded; /* true after ucode downloaded */ -#ifdef WLC_LOW_ONLY - struct wl_timer *wdtimer; /* timer for watchdog routine */ - struct ether_addr orig_etheraddr; /* original hw ethernet address */ - u16 rpc_dngl_agg; /* rpc agg control for dongle */ - u32 mem_required_def; /* memory required to replenish RX DMA ring */ - u32 mem_required_lower; /* memory required with lower RX bound */ - u32 mem_required_least; /* minimum memory requirement to handle RX */ - -#endif /* WLC_LOW_ONLY */ u8 hw_stf_ss_opmode; /* STF single stream operation mode */ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic -- cgit v1.2.3 From 501c09346ce74ec688113d5c6b8a321514935228 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:54 -0800 Subject: staging: brcm80211: unifdef -DWLC_LOW Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcm_rpc_tp.h | 4 ---- drivers/staging/brcm80211/include/siutils.h | 10 ---------- drivers/staging/brcm80211/phy/wlc_phy_hal.h | 2 -- drivers/staging/brcm80211/sys/wl_mac80211.c | 22 ---------------------- drivers/staging/brcm80211/sys/wl_mac80211.h | 2 -- drivers/staging/brcm80211/sys/wlc_alloc.c | 4 ---- drivers/staging/brcm80211/sys/wlc_ampdu.c | 13 ------------- drivers/staging/brcm80211/sys/wlc_bmac.c | 3 --- drivers/staging/brcm80211/sys/wlc_bmac.h | 2 -- drivers/staging/brcm80211/sys/wlc_cfg.h | 6 ------ drivers/staging/brcm80211/sys/wlc_mac80211.c | 18 ------------------ drivers/staging/brcm80211/sys/wlc_mac80211.h | 12 ------------ drivers/staging/brcm80211/sys/wlc_rpc.h | 4 ---- drivers/staging/brcm80211/sys/wlc_types.h | 5 ----- 14 files changed, 107 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcm_rpc_tp.h b/drivers/staging/brcm80211/include/bcm_rpc_tp.h index 0136118284f9..6102a495f3bd 100644 --- a/drivers/staging/brcm80211/include/bcm_rpc_tp.h +++ b/drivers/staging/brcm80211/include/bcm_rpc_tp.h @@ -53,9 +53,7 @@ typedef struct rpc_transport_info rpc_tp_info_t; typedef void (*rpc_tx_complete_fn_t) (void *, rpc_buf_t *, int status); typedef void (*rpc_rx_fn_t) (void *, rpc_buf_t *); -#ifdef WLC_LOW typedef void (*rpc_txflowctl_cb_t) (void *ctx, bool on); -#endif extern rpc_tp_info_t *bcm_rpc_tp_attach(struct osl_info *osh, void *bus); extern void bcm_rpc_tp_detach(rpc_tp_info_t *rpcb); @@ -94,7 +92,6 @@ extern int bcm_rpc_tp_get_device_speed(rpc_tp_info_t *rpc_th); extern int bcm_rpc_tp_dump(rpc_tp_info_t *rpcb, struct bcmstrbuf *b); #endif -#ifdef WLC_LOW /* intercept USB pkt to parse RPC header: USB driver rx-> wl_send -> this -> wl driver */ extern void bcm_rpc_tp_rx_from_dnglbus(rpc_tp_info_t *rpc_th, struct lbuf *lb); @@ -110,7 +107,6 @@ extern void bcm_rpc_tp_txq_wm_set(rpc_tp_info_t *rpc_th, u8 hiwm, u8 lowm); extern void bcm_rpc_tp_txq_wm_get(rpc_tp_info_t *rpc_th, u8 *hiwm, u8 *lowm); -#endif /* WLC_LOW */ extern void bcm_rpc_tp_agg_set(rpc_tp_info_t *rpcb, u32 reason, bool set); extern void bcm_rpc_tp_agg_limit_set(rpc_tp_info_t *rpc_th, u8 sf, diff --git a/drivers/staging/brcm80211/include/siutils.h b/drivers/staging/brcm80211/include/siutils.h index 6f83e7e5b313..6a074ab9f34b 100644 --- a/drivers/staging/brcm80211/include/siutils.h +++ b/drivers/staging/brcm80211/include/siutils.h @@ -19,9 +19,6 @@ #include -#if !defined(WLC_LOW) -#include "bcm_rpc.h" -#endif /* * Data structure to export all chip specific common variables * public (read-only) portion of siutils handle returned by si_attach() @@ -50,19 +47,12 @@ struct si_pub { uint socirev; /* SOC interconnect rev */ bool pci_pr32414; -#if !defined(WLC_LOW) - rpc_info_t *rpc; -#endif }; /* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver * for monolithic driver, it is readonly to prevent accident change */ -#if !defined(WLC_LOW) -typedef struct si_pub si_t; -#else typedef const struct si_pub si_t; -#endif /* * Many of the routines below take an 'sih' handle as their first arg. diff --git a/drivers/staging/brcm80211/phy/wlc_phy_hal.h b/drivers/staging/brcm80211/phy/wlc_phy_hal.h index c462387d20b9..514e15e00283 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_hal.h +++ b/drivers/staging/brcm80211/phy/wlc_phy_hal.h @@ -146,7 +146,6 @@ typedef struct shared_phy_params { u32 boardflags2; } shared_phy_params_t; -#ifdef WLC_LOW extern shared_phy_t *wlc_phy_shared_attach(shared_phy_params_t *shp); extern void wlc_phy_shared_detach(shared_phy_t *phy_sh); @@ -185,7 +184,6 @@ extern void wlc_phy_set_deaf(wlc_phy_t *ppi, bool user_flag); extern void wlc_phy_switch_radio(wlc_phy_t *ppi, bool on); extern void wlc_phy_anacore(wlc_phy_t *ppi, bool on); -#endif /* WLC_LOW */ extern void wlc_phy_BSSinit(wlc_phy_t *ppi, bool bonlyap, int rssi); diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index e336fef111e5..37e6ced84db5 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -759,14 +759,12 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, wlc_iovar_setint(wl->wlc, "sd_drivestrength", sd_drivestrength); #endif -#ifdef WLC_LOW /* register our interrupt handler */ if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { WL_ERROR(("wl%d: request_irq() failed\n", unit)); goto fail; } wl->irq = irq; -#endif /* WLC_LOW */ /* register module */ wlc_module_register(wl->pub, NULL, "linux", wl, NULL, wl_linux_watchdog, @@ -1349,7 +1347,6 @@ void wl_free(wl_info_t *wl) osl_detach(osh); } -#ifdef WLC_LOW /* transmit a packet */ static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) { @@ -1358,7 +1355,6 @@ static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) return wl_start_int(wl, WL_TO_HW(wl), skb); } -#endif /* WLC_LOW */ static int BCMFASTPATH wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, struct sk_buff *skb) @@ -1400,13 +1396,11 @@ uint wl_reset(wl_info_t *wl) */ void BCMFASTPATH wl_intrson(wl_info_t *wl) { -#if defined(WLC_LOW) unsigned long flags; INT_LOCK(wl, flags); wlc_intrson(wl->wlc); INT_UNLOCK(wl, flags); -#endif /* WLC_LOW */ } bool wl_alloc_dma_resources(wl_info_t *wl, uint addrwidth) @@ -1416,7 +1410,6 @@ bool wl_alloc_dma_resources(wl_info_t *wl, uint addrwidth) u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl) { -#if defined(WLC_LOW) unsigned long flags; u32 status; @@ -1424,20 +1417,15 @@ u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl) status = wlc_intrsoff(wl->wlc); INT_UNLOCK(wl, flags); return status; -#else - return 0; -#endif /* WLC_LOW */ } void wl_intrsrestore(wl_info_t *wl, u32 macintmask) { -#if defined(WLC_LOW) unsigned long flags; INT_LOCK(wl, flags); wlc_intrsrestore(wl->wlc, macintmask); INT_UNLOCK(wl, flags); -#endif /* WLC_LOW */ } int wl_up(wl_info_t *wl) @@ -1473,7 +1461,6 @@ void wl_down(wl_info_t *wl) irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) { -#if defined(WLC_LOW) wl_info_t *wl; bool ours, wantdpc; unsigned long flags; @@ -1498,14 +1485,10 @@ irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) WL_ISRUNLOCK(wl, flags); return IRQ_RETVAL(ours); -#else - return IRQ_RETVAL(0); -#endif /* WLC_LOW */ } static void BCMFASTPATH wl_dpc(unsigned long data) { -#ifdef WLC_LOW wl_info_t *wl; wl = (wl_info_t *) data; @@ -1539,7 +1522,6 @@ static void BCMFASTPATH wl_dpc(unsigned long data) done: WL_UNLOCK(wl); -#endif /* WLC_LOW */ } static void wl_link_up(wl_info_t *wl, char *ifname) @@ -1743,7 +1725,6 @@ char *wl_firmwares[WL_MAX_FW] = { NULL }; -#ifdef WLC_LOW int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx) { int i, entry; @@ -1790,7 +1771,6 @@ int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx) printf("ERROR: ucode tag:%d can not be found!\n", idx); return -1; } -#endif /* WLC_LOW */ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) { @@ -1833,12 +1813,10 @@ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) return 0; } -#ifdef WLC_LOW void wl_ucode_free_buf(void *p) { kfree(p); } -#endif /* WLC_LOW */ static void wl_release_fw(wl_info_t *wl) { diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h index ba9d48cd0193..220d570710cb 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.h +++ b/drivers/staging/brcm80211/sys/wl_mac80211.h @@ -122,10 +122,8 @@ extern void wl_free(wl_info_t *wl); extern int wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); extern int wl_ucode_data_init(wl_info_t *wl); extern void wl_ucode_data_free(void); -#ifdef WLC_LOW extern void wl_ucode_free_buf(void *); extern int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx); extern int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx); -#endif /* WLC_LOW */ #endif /* _wl_mac80211_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index e863a81e045c..659ebd0ee2de 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -196,7 +196,6 @@ wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, } wlc->hw->wlc = wlc; -#ifdef WLC_LOW wlc->hw->bandstate[0] = (wlc_hwband_t *)wlc_calloc(osh, unit, (sizeof(wlc_hwband_t) * MAXBANDS)); if (wlc->hw->bandstate[0] == NULL) { @@ -211,7 +210,6 @@ wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, (sizeof(wlc_hwband_t) * i)); } } -#endif /* WLC_LOW */ wlc->modulecb = (modulecb_t *)wlc_calloc(osh, unit, sizeof(modulecb_t) * WLC_MAXMODULES); @@ -357,12 +355,10 @@ void wlc_detach_mfree(wlc_info_t *wlc, struct osl_info *osh) } if (wlc->hw) { -#ifdef WLC_LOW if (wlc->hw->bandstate[0]) { kfree(wlc->hw->bandstate[0]); wlc->hw->bandstate[0] = NULL; } -#endif /* free hw struct */ kfree(wlc->hw); diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index ab883ba76def..1fa56cefeed9 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -908,7 +908,6 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p, * call the first one */ if (txs->status & TX_STATUS_ACK_RCV) { -#ifdef WLC_LOW u8 status_delay = 0; /* wait till the next 8 bytes of txstatus is available */ @@ -926,18 +925,6 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p, ASSERT(!(s1 & TX_STATUS_INTERMEDIATE)); ASSERT(s1 & TX_STATUS_AMPDU); s2 = R_REG(wlc->osh, &wlc->regs->frmtxstatus2); -#else /* WLC_LOW */ - - /* Store the relevant information in ampdu structure */ - WL_AMPDU_TX(("wl%d: wlc_ampdu_dotxstatus: High Recvd\n", - wlc->pub->unit)); - - ASSERT(!ampdu->p); - ampdu->p = p; - bcopy(txs, &du->txs, sizeof(tx_status_t)); - ampdu->waiting_status = true; - return; -#endif /* WLC_LOW */ } wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 214b5d82ab23..110710ad6e78 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -14,9 +14,6 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef WLC_LOW -#error "This file needs WLC_LOW" -#endif #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.h b/drivers/staging/brcm80211/sys/wlc_bmac.h index c3d251a6417a..c705f667469c 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.h +++ b/drivers/staging/brcm80211/sys/wlc_bmac.h @@ -138,9 +138,7 @@ extern void wlc_bmac_watchdog(void *arg); extern void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw); /* up/down, reset, clk */ -#ifdef WLC_LOW extern void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want); -#endif extern void wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw, uint offset, const void *buf, int len, diff --git a/drivers/staging/brcm80211/sys/wlc_cfg.h b/drivers/staging/brcm80211/sys/wlc_cfg.h index a415e1fd2c05..e36d209c72fd 100644 --- a/drivers/staging/brcm80211/sys/wlc_cfg.h +++ b/drivers/staging/brcm80211/sys/wlc_cfg.h @@ -24,12 +24,6 @@ #define IS_SINGLEBAND_5G(device) 0 /* Keep WLC_HIGH_ONLY, WLC_SPLIT for USB extension later on */ -#if !defined(WLC_LOW) -#define WLC_HIGH_ONLY -#endif -#if !defined(WLC_LOW) -#define WLC_SPLIT -#endif /* **** Core type/rev defaults **** */ #define D11_DEFAULT 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27 diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index c270d3f4072f..c6f64c2e461a 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -626,21 +626,11 @@ bool wlc_ps_check(wlc_info_t *wlc) res = false; } -#ifdef WLC_LOW /* For a monolithic build the wake check can be exact since it looks at wake * override bits. The MCTL_WAKE bit should match the 'wake' value. */ wake = STAY_AWAKE(wlc) || wlc->hw->wake_override; wake_ok = (wake == ((tmp & MCTL_WAKE) != 0)); -#else - /* For a split build we will not have access to any wake overrides from the low - * level. The check can only make sure the MCTL_WAKE bit is on if the high - * level 'wake' value is true. If the high level 'wake' is false, the MCTL_WAKE - * may be either true or false due to the low level override. - */ - wake = STAY_AWAKE(wlc); - wake_ok = ((tmp & MCTL_WAKE) != 0) || !wake; -#endif if (hps && !wake_ok) { WL_ERROR(("wl%d: wake not sync, sw %d maccontrol 0x%x\n", wlc->pub->unit, wake, tmp)); res = false; @@ -1842,14 +1832,12 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain, wlc->stf->hw_rxchain); -#ifdef WLC_LOW /* pull up some info resulting from the low attach */ { int i; for (i = 0; i < NFIFO; i++) wlc->core->txavail[i] = wlc->hw->txavail[i]; } -#endif /* WLC_LOW */ wlc_bmac_hw_etheraddr(wlc->hw, &wlc->perm_etheraddr); @@ -2500,9 +2488,7 @@ static void wlc_watchdog(void *arg) if (wlc->pub->radio_disabled) return; -#ifdef WLC_LOW wlc_bmac_watchdog(wlc); -#endif /* occasionally sample mac stat counters to detect 16-bit counter wrap */ if ((WLC_UPDATE_STATS(wlc)) @@ -2531,10 +2517,8 @@ static void wlc_watchdog(void *arg) wlc->tempsense_lasttime = wlc->pub->now; wlc_tempsense_upd(wlc); } -#ifdef WLC_LOW /* BMAC_NOTE: for HIGH_ONLY driver, this seems being called after RPC bus failed */ ASSERT(wlc_bmac_taclear(wlc->hw, true)); -#endif /* Verify that tx_prec_map and fifos are in sync to avoid lock ups */ ASSERT(wlc_tx_prec_map_verify(wlc)); @@ -4228,14 +4212,12 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) } } -#ifdef WLC_LOW /* BMAC_NOTE: for HIGH_ONLY driver, this seems being called after RPC bus failed */ /* In hw_off condition, IOCTLs that reach here are deemed safe but taclear would * certainly result in getting -1 for register reads. So skip ta_clear altogether */ if (!(wlc->pub->hw_off)) ASSERT(wlc_bmac_taclear(wlc->hw, ta_ok) || !ta_ok); -#endif return bcmerror; } diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 9d0d8f336dde..046158813115 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -306,13 +306,11 @@ typedef struct wlc_stf { * core state (mac) */ typedef struct wlccore { -#ifdef WLC_LOW uint coreidx; /* # sb enumerated core */ /* fifo */ uint *txavail[NFIFO]; /* # tx descriptors available */ s16 txpktpend[NFIFO]; /* tx admission control */ -#endif /* WLC_LOW */ macstat_t *macstat_snapshot; /* mac hw prev read values */ } wlccore_t; @@ -406,7 +404,6 @@ struct wlc_if { /* flags for the interface */ #define WLC_IF_LINKED 0x02 /* this interface is linked to a wl_if */ -#ifdef WLC_LOW typedef struct wlc_hwband { int bandtype; /* WLC_BAND_2G, WLC_BAND_5G */ uint bandunit; /* bandstate[] index */ @@ -423,7 +420,6 @@ typedef struct wlc_hwband { wlc_phy_t *pi; /* pointer to phy specific information */ bool abgphy_encore; } wlc_hwband_t; -#endif /* WLC_LOW */ struct wlc_hw_info { #ifdef WLC_SPLIT @@ -436,7 +432,6 @@ struct wlc_hw_info { /* fifo */ hnddma_t *di[NFIFO]; /* hnddma handles, per fifo */ -#ifdef WLC_LOW uint unit; /* device instance number */ /* version info */ @@ -502,7 +497,6 @@ struct wlc_hw_info { * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board */ u32 antsel_avail; /* put antsel_info_t here if more info is needed */ -#endif /* WLC_LOW */ }; /* TX Queue information @@ -817,11 +811,7 @@ struct antsel_info { #define IS_MBAND_UNLOCKED(wlc) \ ((NBANDS(wlc) > 1) && !(wlc)->bandlocked) -#ifdef WLC_LOW #define WLC_BAND_PI_RADIO_CHANSPEC wlc_phy_chanspec_get(wlc->band->pi) -#else -#define WLC_BAND_PI_RADIO_CHANSPEC (wlc->chanspec) -#endif /* sum the individual fifo tx pending packet counts */ #define TXPKTPENDTOT(wlc) ((wlc)->core->txpktpend[0] + (wlc)->core->txpktpend[1] + \ @@ -881,10 +871,8 @@ extern void wlc_print_txdesc(d11txh_t *txh); extern void wlc_print_dot11_mac_hdr(u8 *buf, int len); #endif -#ifdef WLC_LOW extern void wlc_setxband(wlc_hw_info_t *wlc_hw, uint bandunit); extern void wlc_coredisable(wlc_hw_info_t *wlc_hw); -#endif extern bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rate, int band, bool verbose); diff --git a/drivers/staging/brcm80211/sys/wlc_rpc.h b/drivers/staging/brcm80211/sys/wlc_rpc.h index db39645ccbdc..e3f31d42dd80 100644 --- a/drivers/staging/brcm80211/sys/wlc_rpc.h +++ b/drivers/staging/brcm80211/sys/wlc_rpc.h @@ -480,13 +480,9 @@ static __inline int _wlc_rpc_call(struct rpc_info *rpc, rpc_buf_t *send) #include #include -#ifdef WLC_LOW extern void wlc_rpc_bmac_dispatch(wlc_rpc_ctx_t *rpc_ctx, struct rpc_buf *buf); extern void wlc_rpc_bmac_dump_txfifohist(wlc_hw_info_t *wlc_hw, bool dump_clear); -#else -extern void wlc_rpc_high_dispatch(wlc_rpc_ctx_t *ctx, struct rpc_buf *buf); -#endif /* Packed structure for ease of transport across RPC bus along u32 boundary */ typedef struct wlc_rpc_txstatus { diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 33047ebab979..dffba3e8b62f 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -35,12 +35,7 @@ typedef struct wlc_auth_info wlc_auth_info_t; typedef struct supplicant supplicant_t; typedef struct authenticator authenticator_t; typedef struct antsel_info antsel_info_t; -#if !defined(WLC_LOW) -typedef struct rpctx_info rpctx_info_t; -#endif -#ifdef WLC_LOW typedef struct bmac_pmq bmac_pmq_t; -#endif struct d11init; -- cgit v1.2.3 From f3ce1ef2f80627c2b6339bfc96ee5c1b189cac06 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:55 -0800 Subject: staging: brcm80211: unifdef -UWLC_SPLIT Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 046158813115..459e3cfc84aa 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -20,9 +20,6 @@ #include #include #include -#ifdef WLC_SPLIT -#include -#endif #include #include @@ -422,9 +419,6 @@ typedef struct wlc_hwband { } wlc_hwband_t; struct wlc_hw_info { -#ifdef WLC_SPLIT - rpc_info_t *rpc; /* Handle to RPC module */ -#endif struct osl_info *osh; /* pointer to os handle */ bool _piomode; /* true if pio mode */ wlc_info_t *wlc; @@ -522,9 +516,6 @@ struct wlc_info { d11regs_t *regs; /* pointer to device registers */ wlc_hw_info_t *hw; /* HW related state used primarily by BMAC */ -#ifdef WLC_SPLIT - rpc_info_t *rpc; /* Handle to RPC module */ -#endif /* clock */ int clkreq_override; /* setting for clkreq for PCIE : Auto, 0, 1 */ -- cgit v1.2.3 From c73b9d6759993f521e3b0cb24abf74c4527469e3 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:56 -0800 Subject: staging: brcm80211: remove bmac-only header files Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcm_rpc.h | 79 ---- drivers/staging/brcm80211/include/bcm_rpc_tp.h | 133 ------- drivers/staging/brcm80211/include/bcm_xdr.h | 60 --- drivers/staging/brcm80211/include/dbus.h | 353 ----------------- drivers/staging/brcm80211/sys/wlc_rpc.h | 523 ------------------------- drivers/staging/brcm80211/sys/wlc_rpctx.h | 47 --- 6 files changed, 1195 deletions(-) delete mode 100644 drivers/staging/brcm80211/include/bcm_rpc.h delete mode 100644 drivers/staging/brcm80211/include/bcm_rpc_tp.h delete mode 100644 drivers/staging/brcm80211/include/bcm_xdr.h delete mode 100644 drivers/staging/brcm80211/include/dbus.h delete mode 100644 drivers/staging/brcm80211/sys/wlc_rpc.h delete mode 100644 drivers/staging/brcm80211/sys/wlc_rpctx.h (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcm_rpc.h b/drivers/staging/brcm80211/include/bcm_rpc.h deleted file mode 100644 index 7a379ba15ce1..000000000000 --- a/drivers/staging/brcm80211/include/bcm_rpc.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BCM_RPC_H_ -#define _BCM_RPC_H_ - -#include - -typedef struct rpc_info rpc_info_t; -typedef struct rpc_buf rpc_buf_t; -struct rpc_transport_info; -typedef void (*rpc_dispatch_cb_t) (void *ctx, struct rpc_buf *buf); -typedef void (*rpc_resync_cb_t) (void *ctx); -typedef void (*rpc_down_cb_t) (void *ctx); -typedef void (*rpc_txdone_cb_t) (void *ctx, struct rpc_buf *buf); -extern struct rpc_info *bcm_rpc_attach(void *pdev, struct osl_info *osh, - struct rpc_transport_info *rpc_th); - -extern void bcm_rpc_detach(struct rpc_info *rpc); -extern void bcm_rpc_down(struct rpc_info *rpc); -extern void bcm_rpc_watchdog(struct rpc_info *rpc); - -extern struct rpc_buf *bcm_rpc_buf_alloc(struct rpc_info *rpc, int len); -extern void bcm_rpc_buf_free(struct rpc_info *rpc, struct rpc_buf *b); -/* get rpc transport handle */ -extern struct rpc_transport_info *bcm_rpc_tp_get(struct rpc_info *rpc); - -/* callback for: data_rx, down, resync */ -extern void bcm_rpc_rxcb_init(struct rpc_info *rpc, void *ctx, - rpc_dispatch_cb_t cb, void *dnctx, - rpc_down_cb_t dncb, rpc_resync_cb_t resync_cb, - rpc_txdone_cb_t); -extern void bcm_rpc_rxcb_deinit(struct rpc_info *rpci); - -/* HOST or CLIENT rpc call, requiring no return value */ -extern int bcm_rpc_call(struct rpc_info *rpc, struct rpc_buf *b); - -/* HOST rpc call, demanding return. - * The thread may be suspended and control returns back to OS - * The thread will resume(waked up) on either the return signal received or timeout - * The implementation details depend on OS - */ -extern struct rpc_buf *bcm_rpc_call_with_return(struct rpc_info *rpc, - struct rpc_buf *b); - -/* CLIENT rpc call to respond to bcm_rpc_call_with_return, requiring no return value */ -extern int bcm_rpc_call_return(struct rpc_info *rpc, struct rpc_buf *retb); - -extern uint bcm_rpc_buf_header_len(struct rpc_info *rpci); - -#define RPC_PKTLOG_SIZE 50 /* Depth of the history */ -#define RPC_PKTLOG_RD_LEN 3 -#define RPC_PKTLOG_DUMP_SIZE 150 /* dump size should be more than the product of above two */ -extern int bcm_rpc_pktlog_get(struct rpc_info *rpci, u32 *buf, - uint buf_size, bool send); -extern int bcm_rpc_dump(rpc_info_t *rpci, struct bcmstrbuf *b); - -/* HIGH/BMAC: bit 15-8: RPC module, bit 7-0: TP module */ -#define RPC_ERROR_VAL 0x0001 -#define RPC_TRACE_VAL 0x0002 -#define RPC_PKTTRACE_VAL 0x0004 -#define RPC_PKTLOG_VAL 0x0008 -extern void bcm_rpc_msglevel_set(struct rpc_info *rpci, u16 msglevel, - bool high_low); - -#endif /* _BCM_RPC_H_ */ diff --git a/drivers/staging/brcm80211/include/bcm_rpc_tp.h b/drivers/staging/brcm80211/include/bcm_rpc_tp.h deleted file mode 100644 index 6102a495f3bd..000000000000 --- a/drivers/staging/brcm80211/include/bcm_rpc_tp.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _bcm_rpc_tp_h_ -#define _bcm_rpc_tp_h_ -#include - -#define DBUS_RX_BUFFER_SIZE_RPC (2100) /* rxbufsize for dbus_attach, linux only for now */ - -#define BCM_RPC_TP_ENCAP_LEN 4 /* TP header is 4 bytes */ - -#define BCM_RPC_TP_HOST_AGG_MASK 0xffff0000 -#define BCM_RPC_TP_HOST_AGG_SHIFT 16 -#define BCM_RPC_TP_HOST_AGG_AMPDU 0x00010000 /* HOST->DNGL ampdu aggregation */ -#define BCM_RPC_TP_HOST_AGG_TEST 0x00100000 /* HOST->DNGL test aggregation */ -#define BCM_RPC_TP_DNGL_AGG_MASK 0x0000ffff -#define BCM_RPC_TP_DNGL_AGG_DPC 0x00000001 /* DNGL->HOST data aggregation */ -#define BCM_RPC_TP_DNGL_AGG_FLOWCTL 0x00000002 /* DNGL->HOST tx flowcontrol agg */ -#define BCM_RPC_TP_DNGL_AGG_TEST 0x00000010 /* DNGL->HOST test agg */ - -#define BCM_RPC_TP_DNGL_AGG_MAX_SFRAME 3 /* max agg subframes, must be <= USB_NTXD */ -#define BCM_RPC_TP_DNGL_AGG_MAX_BYTE 4000 /* max agg bytes */ - -#define BCM_RPC_TP_HOST_AGG_MAX_SFRAME 3 /* max agg subframes, AMPDU only, 3 is enough */ -#define BCM_RPC_TP_HOST_AGG_MAX_BYTE 3400 /* max agg bytes; to fit 2+ tcp/udp pkts. Each one: - * 802.3pkt + 802.11 hdr + rpc hdr + tp hdr < 1700B - * Need to be in sync with dongle usb rx dma - * rxbufsize(USBBULK_RXBUF_GIANT in usbdev_sb.c) - */ -/* TP-DBUS pkts flowcontrol */ -#define BCM_RPC_TP_DBUS_NTXQ 50 /* queue size for TX on bulk OUT, aggregation possible */ -#define BCM_RPC_TP_DBUS_NRXQ 50 /* queue size for RX on bulk IN, aggregation possible */ -#define BCM_RPC_TP_DBUS_NRXQ_CTRL 1 /* queue size for RX on ctl EP0 */ - -#define BCM_RPC_TP_DBUS_NRXQ_PKT (BCM_RPC_TP_DBUS_NRXQ * BCM_RPC_TP_DNGL_AGG_MAX_SFRAME) -#define BCM_RPC_TP_DBUS_NTXQ_PKT (BCM_RPC_TP_DBUS_NTXQ * BCM_RPC_TP_HOST_AGG_MAX_SFRAME) - -typedef struct rpc_transport_info rpc_tp_info_t; - -typedef void (*rpc_tx_complete_fn_t) (void *, rpc_buf_t *, int status); -typedef void (*rpc_rx_fn_t) (void *, rpc_buf_t *); - -typedef void (*rpc_txflowctl_cb_t) (void *ctx, bool on); - -extern rpc_tp_info_t *bcm_rpc_tp_attach(struct osl_info *osh, void *bus); -extern void bcm_rpc_tp_detach(rpc_tp_info_t *rpcb); -extern void bcm_rpc_tp_down(rpc_tp_info_t *rpcb); -extern void bcm_rpc_tp_watchdog(rpc_tp_info_t *rpcb); - -extern int bcm_rpc_tp_buf_send(rpc_tp_info_t *rpcb, rpc_buf_t *buf); - -/* callback for tx_complete, rx_pkt */ -extern void bcm_rpc_tp_register_cb(rpc_tp_info_t *rpcb, - rpc_tx_complete_fn_t txcmplt, - void *tx_context, rpc_rx_fn_t rxpkt, - void *rx_context, rpc_osl_t *rpc_osh); -extern void bcm_rpc_tp_deregister_cb(rpc_tp_info_t *rpcb); - -/* Buffer manipulation */ -extern uint bcm_rpc_buf_tp_header_len(rpc_tp_info_t *rpcb); -extern rpc_buf_t *bcm_rpc_tp_buf_alloc(rpc_tp_info_t *rpcb, int len); -extern void bcm_rpc_tp_buf_free(rpc_tp_info_t *rpcb, rpc_buf_t *buf); -extern int bcm_rpc_buf_len_get(rpc_tp_info_t *rpcb, rpc_buf_t *b); -extern int bcm_rpc_buf_len_set(rpc_tp_info_t *rpcb, rpc_buf_t *b, uint len); -extern rpc_buf_t *bcm_rpc_buf_next_get(rpc_tp_info_t *rpcb, rpc_buf_t *b); -extern void bcm_rpc_buf_next_set(rpc_tp_info_t *rpcb, rpc_buf_t *b, - rpc_buf_t *nextb); -extern unsigned char *bcm_rpc_buf_data(rpc_tp_info_t *rpcb, rpc_buf_t *b); -extern unsigned char *bcm_rpc_buf_push(rpc_tp_info_t *rpcb, rpc_buf_t *b, - uint delta); -extern unsigned char *bcm_rpc_buf_pull(rpc_tp_info_t *rpcb, rpc_buf_t *b, - uint delta); -extern void bcm_rpc_tp_buf_release(rpc_tp_info_t *rpcb, rpc_buf_t *buf); -extern void bcm_rpc_tp_buf_cnt_adjust(rpc_tp_info_t *rpcb, int adjust); -/* RPC call_with_return */ -extern int bcm_rpc_tp_recv_rtn(rpc_tp_info_t *rpcb); -extern int bcm_rpc_tp_get_device_speed(rpc_tp_info_t *rpc_th); -#ifdef BCMDBG -extern int bcm_rpc_tp_dump(rpc_tp_info_t *rpcb, struct bcmstrbuf *b); -#endif - -/* intercept USB pkt to parse RPC header: USB driver rx-> wl_send -> this -> wl driver */ -extern void bcm_rpc_tp_rx_from_dnglbus(rpc_tp_info_t *rpc_th, struct lbuf *lb); - -/* RPC callreturn pkt, go to USB driver tx */ -extern int bcm_rpc_tp_send_callreturn(rpc_tp_info_t *rpc_th, rpc_buf_t *b); - -extern void bcm_rpc_tp_dump(rpc_tp_info_t *rpcb); -extern void bcm_rpc_tp_txflowctl(rpc_tp_info_t *rpcb, bool state, int prio); -extern void bcm_rpc_tp_txflowctlcb_init(rpc_tp_info_t *rpc_th, void *ctx, - rpc_txflowctl_cb_t cb); -extern void bcm_rpc_tp_txflowctlcb_deinit(rpc_tp_info_t *rpc_th); -extern void bcm_rpc_tp_txq_wm_set(rpc_tp_info_t *rpc_th, u8 hiwm, - u8 lowm); -extern void bcm_rpc_tp_txq_wm_get(rpc_tp_info_t *rpc_th, u8 *hiwm, - u8 *lowm); - -extern void bcm_rpc_tp_agg_set(rpc_tp_info_t *rpcb, u32 reason, bool set); -extern void bcm_rpc_tp_agg_limit_set(rpc_tp_info_t *rpc_th, u8 sf, - u16 bytes); -extern void bcm_rpc_tp_agg_limit_get(rpc_tp_info_t *rpc_th, u8 *sf, - u16 *bytes); - -#define BCM_RPC_TP_MSG_LEVEL_MASK 0x00ff -/* dongle msg level */ -#define RPC_TP_MSG_DNGL_ERR_VAL 0x0001 /* DNGL TP error msg */ -#define RPC_TP_MSG_DNGL_DBG_VAL 0x0002 /* DNGL TP dbg msg */ -#define RPC_TP_MSG_DNGL_AGG_VAL 0x0004 /* DNGL TP agg msg */ -#define RPC_TP_MSG_DNGL_DEA_VAL 0x0008 /* DNGL TP deag msg */ - -/* host msg level */ -#define RPC_TP_MSG_HOST_ERR_VAL 0x0001 /* DNGL TP error msg */ -#define RPC_TP_MSG_HOST_DBG_VAL 0x0002 /* DNGL TP dbg msg */ -#define RPC_TP_MSG_HOST_AGG_VAL 0x0004 /* DNGL TP agg msg */ -#define RPC_TP_MSG_HOST_DEA_VAL 0x0008 /* DNGL TP deag msg */ - -extern void bcm_rpc_tp_msglevel_set(rpc_tp_info_t *rpc_th, u8 msglevel, - bool high_low); - -#endif /* _bcm_rpc_tp_h_ */ diff --git a/drivers/staging/brcm80211/include/bcm_xdr.h b/drivers/staging/brcm80211/include/bcm_xdr.h deleted file mode 100644 index 50fbd78a8804..000000000000 --- a/drivers/staging/brcm80211/include/bcm_xdr.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BCM_XDR_H -#define _BCM_XDR_H - -/* - * bcm_xdr_buf_t - * Structure used for bookkeeping of a buffer being packed or unpacked. - * Keeps a current read/write pointer and size as well as - * the original buffer pointer and size. - * - */ -typedef struct { - u8 *buf; /* pointer to current position in origbuf */ - uint size; /* current (residual) size in bytes */ - u8 *origbuf; /* unmodified pointer to orignal buffer */ - uint origsize; /* unmodified orignal buffer size in bytes */ -} bcm_xdr_buf_t; - -void bcm_xdr_buf_init(bcm_xdr_buf_t *b, void *buf, size_t len); - -int bcm_xdr_pack_u32(bcm_xdr_buf_t *b, u32 val); -int bcm_xdr_unpack_u32(bcm_xdr_buf_t *b, u32 *pval); -int bcm_xdr_pack_s32(bcm_xdr_buf_t *b, s32 val); -int bcm_xdr_unpack_s32(bcm_xdr_buf_t *b, s32 *pval); -int bcm_xdr_pack_s8(bcm_xdr_buf_t *b, s8 val); -int bcm_xdr_unpack_s8(bcm_xdr_buf_t *b, s8 *pval); -int bcm_xdr_pack_opaque(bcm_xdr_buf_t *b, uint len, void *data); -int bcm_xdr_unpack_opaque(bcm_xdr_buf_t *b, uint len, void **pdata); -int bcm_xdr_unpack_opaque_cpy(bcm_xdr_buf_t *b, uint len, void *data); -int bcm_xdr_pack_opaque_varlen(bcm_xdr_buf_t *b, uint len, void *data); -int bcm_xdr_unpack_opaque_varlen(bcm_xdr_buf_t *b, uint *plen, void **pdata); -int bcm_xdr_pack_string(bcm_xdr_buf_t *b, char *str); -int bcm_xdr_unpack_string(bcm_xdr_buf_t *b, uint *plen, char **pstr); - -int bcm_xdr_pack_u8_vec(bcm_xdr_buf_t *, u8 *vec, u32 elems); -int bcm_xdr_unpack_u8_vec(bcm_xdr_buf_t *, u8 *vec, u32 elems); -int bcm_xdr_pack_u16_vec(bcm_xdr_buf_t *b, uint len, void *vec); -int bcm_xdr_unpack_u16_vec(bcm_xdr_buf_t *b, uint len, void *vec); -int bcm_xdr_pack_u32_vec(bcm_xdr_buf_t *b, uint len, void *vec); -int bcm_xdr_unpack_u32_vec(bcm_xdr_buf_t *b, uint len, void *vec); - -int bcm_xdr_pack_opaque_raw(bcm_xdr_buf_t *b, uint len, void *data); -int bcm_xdr_pack_opaque_pad(bcm_xdr_buf_t *b); - -#endif /* _BCM_XDR_H */ diff --git a/drivers/staging/brcm80211/include/dbus.h b/drivers/staging/brcm80211/include/dbus.h deleted file mode 100644 index 81ffea79d008..000000000000 --- a/drivers/staging/brcm80211/include/dbus.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __DBUS_H__ -#define __DBUS_H__ - -#ifdef BCMDBG -#define DBUSERR(args) do { if (net_ratelimit()) printf args; } while (0) -#define DBUSTRACE(args) -#define DBUSDBGLOCK(args) - -#else -#define DBUSTRACE(args) -#define DBUSERR(args) -#define DBUSDBGLOCK(args) -#endif - -enum { - DBUS_OK = 0, - DBUS_ERR = -200, - DBUS_ERR_TIMEOUT, - DBUS_ERR_DISCONNECT, - DBUS_ERR_NODEVICE, - DBUS_ERR_UNSUPPORTED, - DBUS_ERR_PENDING, - DBUS_ERR_NOMEM, - DBUS_ERR_TXFAIL, - DBUS_ERR_TXTIMEOUT, - DBUS_ERR_TXDROP, - DBUS_ERR_RXFAIL, - DBUS_ERR_RXDROP, - DBUS_ERR_TXCTLFAIL, - DBUS_ERR_RXCTLFAIL, - DBUS_ERR_REG_PARAM, - DBUS_STATUS_CANCELLED -}; - -#define ERR_CBMASK_TXFAIL 0x00000001 -#define ERR_CBMASK_RXFAIL 0x00000002 -#define ERR_CBMASK_ALL 0xFFFFFFFF - -#define DBUS_CBCTL_WRITE 0 -#define DBUS_CBCTL_READ 1 - -#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */ -#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */ - -#define DBUS_BUFFER_SIZE_TX 5000 -#define DBUS_BUFFER_SIZE_RX 5000 - -#define DBUS_BUFFER_SIZE_TX_NOAGG 2048 -#define DBUS_BUFFER_SIZE_RX_NOAGG 2048 - -/* DBUS types */ -enum { - DBUS_USB, - DBUS_SDIO, - DBUS_SPI, - DBUS_UNKNOWN -}; - -enum dbus_state { - DBUS_STATE_DL_PENDING, - DBUS_STATE_DL_DONE, - DBUS_STATE_UP, - DBUS_STATE_DOWN, - DBUS_STATE_PNP_FWDL, - DBUS_STATE_DISCONNECT -}; - -enum dbus_pnp_state { - DBUS_PNP_DISCONNECT, - DBUS_PNP_SLEEP, - DBUS_PNP_RESUME -}; - -typedef enum _DEVICE_SPEED { - INVALID_SPEED = -1, - LOW_SPEED = 1, /* USB 1.1: 1.5 Mbps */ - FULL_SPEED, /* USB 1.1: 12 Mbps */ - HIGH_SPEED, /* USB 2.0: 480 Mbps */ - SUPER_SPEED, /* USB 3.0: 4.8 Gbps */ -} DEVICE_SPEED; - -typedef struct { - int bustype; - int vid; - int pid; - int devid; - int chiprev; /* chip revsion number */ - int mtu; - int nchan; /* Data Channels */ -} dbus_attrib_t; - -/* FIX: Account for errors related to DBUS; - * Let upper layer account for packets/bytes - */ -typedef struct { - u32 rx_errors; - u32 tx_errors; - u32 rx_dropped; - u32 tx_dropped; -} dbus_stats_t; - -/* - * Configurable BUS parameters - */ -typedef struct { - bool rxctl_deferrespok; -} dbus_config_t; - -struct dbus_callbacks; -struct exec_parms; - -typedef void *(*probe_cb_t) (void *arg, const char *desc, u32 bustype, - u32 hdrlen); -typedef void (*disconnect_cb_t) (void *arg); -typedef void *(*exec_cb_t) (struct exec_parms *args); - -/* Client callbacks registered during dbus_attach() */ -typedef struct dbus_callbacks { - void (*send_complete) (void *cbarg, void *info, int status); - void (*recv_buf) (void *cbarg, u8 *buf, int len); - void (*recv_pkt) (void *cbarg, void *pkt); - void (*txflowcontrol) (void *cbarg, bool onoff); - void (*errhandler) (void *cbarg, int err); - void (*ctl_complete) (void *cbarg, int type, int status); - void (*state_change) (void *cbarg, int state); - void *(*pktget) (void *cbarg, uint len, bool send); - void (*pktfree) (void *cbarg, void *p, bool send); -} dbus_callbacks_t; - -struct dbus_pub; -struct bcmstrbuf; -struct dbus_irb; -struct dbus_irb_rx; -struct dbus_irb_tx; -struct dbus_intf_callbacks; - -typedef struct { - void *(*attach) (struct dbus_pub *pub, void *cbarg, - struct dbus_intf_callbacks *cbs); - void (*detach) (struct dbus_pub *pub, void *bus); - - int (*up) (void *bus); - int (*down) (void *bus); - int (*send_irb) (void *bus, struct dbus_irb_tx *txirb); - int (*recv_irb) (void *bus, struct dbus_irb_rx *rxirb); - int (*cancel_irb) (void *bus, struct dbus_irb_tx *txirb); - int (*send_ctl) (void *bus, u8 *buf, int len); - int (*recv_ctl) (void *bus, u8 *buf, int len); - int (*get_stats) (void *bus, dbus_stats_t *stats); - int (*get_attrib) (void *bus, dbus_attrib_t *attrib); - - int (*pnp) (void *bus, int event); - int (*remove) (void *bus); - int (*resume) (void *bus); - int (*suspend) (void *bus); - int (*stop) (void *bus); - int (*reset) (void *bus); - - /* Access to bus buffers directly */ - void *(*pktget) (void *bus, int len); - void (*pktfree) (void *bus, void *pkt); - - int (*iovar_op) (void *bus, const char *name, void *params, int plen, - void *arg, int len, bool set); - void (*dump) (void *bus, struct bcmstrbuf *strbuf); - int (*set_config) (void *bus, dbus_config_t *config); - int (*get_config) (void *bus, dbus_config_t *config); - - bool(*device_exists) (void *bus); - bool(*dlneeded) (void *bus); - int (*dlstart) (void *bus, u8 *fw, int len); - int (*dlrun) (void *bus); - bool(*recv_needed) (void *bus); - - void *(*exec_rxlock) (void *bus, exec_cb_t func, - struct exec_parms *args); - void *(*exec_txlock) (void *bus, exec_cb_t func, - struct exec_parms *args); - - int (*tx_timer_init) (void *bus); - int (*tx_timer_start) (void *bus, uint timeout); - int (*tx_timer_stop) (void *bus); - - int (*sched_dpc) (void *bus); - int (*lock) (void *bus); - int (*unlock) (void *bus); - int (*sched_probe_cb) (void *bus); - - int (*shutdown) (void *bus); - - int (*recv_stop) (void *bus); - int (*recv_resume) (void *bus); - - /* Add from the bottom */ -} dbus_intf_t; - -typedef struct dbus_pub { - struct osl_info *osh; - dbus_stats_t stats; - dbus_attrib_t attrib; - enum dbus_state busstate; - DEVICE_SPEED device_speed; - int ntxq, nrxq, rxsize; - void *bus; - struct shared_info *sh; -} dbus_pub_t; - -#define BUS_INFO(bus, type) (((type *) bus)->pub->bus) - -/* - * Public Bus Function Interface - */ -extern int dbus_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, void *param1, - void *param2); -extern int dbus_deregister(void); - -extern const dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, - int ntxq, void *cbarg, - dbus_callbacks_t *cbs, - struct shared_info *sh); -extern void dbus_detach(const dbus_pub_t *pub); - -extern int dbus_up(const dbus_pub_t *pub); -extern int dbus_down(const dbus_pub_t *pub); -extern int dbus_stop(const dbus_pub_t *pub); -extern int dbus_shutdown(const dbus_pub_t *pub); -extern void dbus_flowctrl_rx(const dbus_pub_t *pub, bool on); - -extern int dbus_send_buf(const dbus_pub_t *pub, u8 *buf, int len, - void *info); -extern int dbus_send_pkt(const dbus_pub_t *pub, void *pkt, void *info); -extern int dbus_send_ctl(const dbus_pub_t *pub, u8 *buf, int len); -extern int dbus_recv_ctl(const dbus_pub_t *pub, u8 *buf, int len); - -extern int dbus_get_stats(const dbus_pub_t *pub, dbus_stats_t *stats); -extern int dbus_get_attrib(const dbus_pub_t *pub, dbus_attrib_t *attrib); -extern int dbus_get_device_speed(const dbus_pub_t *pub); -extern int dbus_set_config(const dbus_pub_t *pub, dbus_config_t *config); -extern int dbus_get_config(const dbus_pub_t *pub, dbus_config_t *config); - -extern void *dbus_pktget(const dbus_pub_t *pub, int len); -extern void dbus_pktfree(const dbus_pub_t *pub, void *pkt); - -extern int dbus_set_errmask(const dbus_pub_t *pub, u32 mask); -extern int dbus_pnp_sleep(const dbus_pub_t *pub); -extern int dbus_pnp_resume(const dbus_pub_t *pub, int *fw_reload); -extern int dbus_pnp_disconnect(const dbus_pub_t *pub); - -extern int dbus_iovar_op(const dbus_pub_t *pub, const char *name, - void *params, int plen, void *arg, int len, bool set); -#ifdef BCMDBG -extern void dbus_hist_dump(const dbus_pub_t *pub, struct bcmstrbuf *b); -#endif /* BCMDBG */ -/* - * Private Common Bus Interface - */ - -/* IO Request Block (IRB) */ -typedef struct dbus_irb { - struct dbus_irb *next; /* it's casted from dbus_irb_tx or dbus_irb_rx struct */ -} dbus_irb_t; - -typedef struct dbus_irb_rx { - struct dbus_irb irb; /* Must be first */ - u8 *buf; - int buf_len; - int actual_len; - void *pkt; - void *info; - void *arg; -} dbus_irb_rx_t; - -typedef struct dbus_irb_tx { - struct dbus_irb irb; /* Must be first */ - u8 *buf; - int len; - void *pkt; - int retry_count; - void *info; - void *arg; -} dbus_irb_tx_t; - -/* DBUS interface callbacks are different from user callbacks - * so, internally, different info can be passed to upper layer - */ -typedef struct dbus_intf_callbacks { - void (*send_irb_timeout) (void *cbarg, dbus_irb_tx_t *txirb); - void (*send_irb_complete) (void *cbarg, dbus_irb_tx_t *txirb, - int status); - void (*recv_irb_complete) (void *cbarg, dbus_irb_rx_t *rxirb, - int status); - void (*errhandler) (void *cbarg, int err); - void (*ctl_complete) (void *cbarg, int type, int status); - void (*state_change) (void *cbarg, int state); - bool(*isr) (void *cbarg, bool *wantdpc); - bool(*dpc) (void *cbarg, bool bounded); - void (*watchdog) (void *cbarg); - void *(*pktget) (void *cbarg, uint len, bool send); - void (*pktfree) (void *cbarg, void *p, bool send); - struct dbus_irb *(*getirb) (void *cbarg, bool send); - void (*rxerr_indicate) (void *cbarg, bool on); -} dbus_intf_callbacks_t; - -/* - * Porting: To support new bus, port these functions below - */ - -/* - * Bus specific Interface - * Implemented by dbus_usb.c/dbus_sdio.c - */ -extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf, void *param1, void *param2); -extern int dbus_bus_deregister(void); - -/* - * Bus-specific and OS-specific Interface - * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c - */ -extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf, void *param1, - void *param2); -extern int dbus_bus_osl_deregister(void); - -/* - * Bus-specific, OS-specific, HW-specific Interface - * Mainly for SDIO Host HW controller - */ -extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, - dbus_intf_t **intf); -extern int dbus_bus_osl_hw_deregister(void); - -#endif /* __DBUS_H__ */ diff --git a/drivers/staging/brcm80211/sys/wlc_rpc.h b/drivers/staging/brcm80211/sys/wlc_rpc.h deleted file mode 100644 index e3f31d42dd80..000000000000 --- a/drivers/staging/brcm80211/sys/wlc_rpc.h +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _WLC_RPC_H_ -#define _WLC_RPC_H_ - -#include - -/* RPC IDs, reordering is OK. This needs to be in sync with RPC_ID_TABLE below */ -typedef enum { - WLRPC_NULL_ID = 0, - WLRPC_WLC_REG_READ_ID, - WLRPC_WLC_REG_WRITE_ID, - WLRPC_WLC_MHF_SET_ID, - WLRPC_WLC_MHF_GET_ID, - WLRPC_WLC_BMAC_UP_PREP_ID, - WLRPC_WLC_BMAC_UP_FINISH_ID, - WLRPC_WLC_BMAC_DOWN_PREP_ID, - WLRPC_WLC_BMAC_DOWN_FINISH_ID, - WLRPC_WLC_BMAC_WRITE_HW_BCNTEMPLATES_ID, - WLRPC_WLC_BMAC_RESET_ID, - WLRPC_WLC_DNGL_REBOOT_ID, - WLRPC_WLC_BMAC_RPC_TXQ_WM_SET_ID, - WLRPC_WLC_BMAC_RPC_TXQ_WM_GET_ID, - WLRPC_WLC_BMAC_RPC_AGG_SET_ID, - WLRPC_WLC_BMAC_RPC_MSGLEVEL_SET_ID, - WLRPC_WLC_BMAC_RPC_AGG_LIMIT_SET_ID, - WLRPC_WLC_BMAC_RPC_AGG_LIMIT_GET_ID, - WLRPC_WLC_BMAC_INIT_ID, - WLRPC_WLC_BMAC_SET_CWMIN_ID, - WLRPC_WLC_BMAC_MUTE_ID, - WLRPC_WLC_PHY_DOIOVAR_ID, - WLRPC_WLC_PHY_HOLD_UPD_ID, - WLRPC_WLC_PHY_MUTE_UPD_ID, - WLRPC_WLC_PHY_CLEAR_TSSI_ID, - WLRPC_WLC_PHY_ANT_RXDIV_GET_ID, - WLRPC_WLC_PHY_ANT_RXDIV_SET_ID, - WLRPC_WLC_PHY_PREAMBLE_SET_ID, - WLRPC_WLC_PHY_FREQTRACK_END_ID, - WLRPC_WLC_PHY_FREQTRACK_START_ID, - WLRPC_WLC_PHY_IOCTL_ID, - WLRPC_WLC_PHY_NOISE_SAMPLE_REQUEST_ID, - WLRPC_WLC_PHY_CAL_PERICAL_ID, - WLRPC_WLC_PHY_TXPOWER_GET_ID, - WLRPC_WLC_PHY_TXPOWER_SET_ID, - WLRPC_WLC_PHY_TXPOWER_SROMLIMIT_ID, - WLRPC_WLC_PHY_RADAR_DETECT_ENABLE_ID, - WLRPC_WLC_PHY_RADAR_DETECT_RUN_ID, - WLRPC_WLC_PHY_TEST_ISON_ID, - WLRPC_WLC_BMAC_COPYFROM_OBJMEM_ID, - WLRPC_WLC_BMAC_COPYTO_OBJMEM_ID, - WLRPC_WLC_ENABLE_MAC_ID, - WLRPC_WLC_MCTRL_ID, - WLRPC_WLC_CORERESET_ID, - WLRPC_WLC_BMAC_READ_SHM_ID, - WLRPC_WLC_BMAC_READ_TSF_ID, - WLRPC_WLC_BMAC_SET_ADDRMATCH_ID, - WLRPC_WLC_BMAC_SET_CWMAX_ID, - WLRPC_WLC_BMAC_SET_RCMTA_ID, - WLRPC_WLC_BMAC_SET_SHM_ID, - WLRPC_WLC_SUSPEND_MAC_AND_WAIT_ID, - WLRPC_WLC_BMAC_WRITE_SHM_ID, - WLRPC_WLC_BMAC_WRITE_TEMPLATE_RAM_ID, - WLRPC_WLC_TX_FIFO_SUSPEND_ID, - WLRPC_WLC_TX_FIFO_RESUME_ID, - WLRPC_WLC_TX_FIFO_SUSPENDED_ID, - WLRPC_WLC_HW_ETHERADDR_ID, - WLRPC_WLC_SET_HW_ETHERADDR_ID, - WLRPC_WLC_BMAC_CHANSPEC_SET_ID, - WLRPC_WLC_BMAC_TXANT_SET_ID, - WLRPC_WLC_BMAC_ANTSEL_TYPE_SET_ID, - WLRPC_WLC_BMAC_TXFIFO_ID, - WLRPC_WLC_RADIO_READ_HWDISABLED_ID, - WLRPC_WLC_RM_CCA_MEASURE_ID, - WLRPC_WLC_SET_SHORTSLOT_ID, - WLRPC_WLC_WAIT_FOR_WAKE_ID, - WLRPC_WLC_PHY_TXPOWER_GET_CURRENT_ID, - WLRPC_WLC_PHY_TXPOWER_HW_CTRL_GET_ID, - WLRPC_WLC_PHY_TXPOWER_HW_CTRL_SET_ID, - WLRPC_WLC_PHY_BSSINIT_ID, - WLRPC_WLC_BAND_STF_SS_SET_ID, - WLRPC_WLC_PHY_BAND_FIRST_CHANSPEC_ID, - WLRPC_WLC_PHY_TXPOWER_LIMIT_SET_ID, - WLRPC_WLC_PHY_BAND_CHANNELS_ID, - WLRPC_WLC_BMAC_REVINFO_GET_ID, - WLRPC_WLC_BMAC_STATE_GET_ID, - WLRPC_WLC_BMAC_XMTFIFO_SZ_GET_ID, - WLRPC_WLC_BMAC_XMTFIFO_SZ_SET_ID, - WLRPC_WLC_BMAC_VALIDATE_CHIP_ACCESS_ID, - WLRPC_WLC_RM_CCA_COMPLETE_ID, - WLRPC_WLC_RECV_ID, - WLRPC_WLC_DOTXSTATUS_ID, - WLRPC_WLC_HIGH_DPC_ID, - WLRPC_WLC_FATAL_ERROR_ID, - WLRPC_WLC_PHY_SET_CHANNEL_14_WIDE_FILTER_ID, - WLRPC_WLC_PHY_NOISE_AVG_ID, - WLRPC_WLC_PHYCHAIN_INIT_ID, - WLRPC_WLC_PHYCHAIN_SET_ID, - WLRPC_WLC_PHYCHAIN_GET_ID, - WLRPC_WLC_PHY_TKIP_RIFS_WAR_ID, - WLRPC_WLC_BMAC_COPYFROM_VARS_ID, - WLRPC_WLC_BMAC_RETRYLIMIT_UPD_ID, - WLRPC_WLC_BMAC_BTC_MODE_SET_ID, - WLRPC_WLC_BMAC_BTC_MODE_GET_ID, - WLRPC_WLC_BMAC_BTC_WIRE_SET_ID, - WLRPC_WLC_BMAC_BTC_WIRE_GET_ID, - WLRPC_WLC_BMAC_SET_NORESET_ID, - WLRPC_WLC_AMPDU_TXSTATUS_COMPLETE_ID, - WLRPC_WLC_BMAC_FIFOERRORS_ID, - WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MIN_ID, - WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MAX_ID, - WLRPC_WLC_NOISE_CB_ID, - WLRPC_WLC_BMAC_LED_HW_DEINIT_ID, - WLRPC_WLC_BMAC_LED_HW_MASK_INIT_ID, - WLRPC_WLC_PLLREQ_ID, - WLRPC_WLC_BMAC_TACLEAR_ID, - WLRPC_WLC_BMAC_SET_CLK_ID, - WLRPC_WLC_PHY_OFDM_RATESET_WAR_ID, - WLRPC_WLC_PHY_BF_PREEMPT_ENABLE_ID, - WLRPC_WLC_BMAC_DOIOVARS_ID, - WLRPC_WLC_BMAC_DUMP_ID, - WLRPC_WLC_CISWRITE_ID, - WLRPC_WLC_CISDUMP_ID, - WLRPC_WLC_UPDATE_PHY_MODE_ID, - WLRPC_WLC_RESET_BMAC_DONE_ID, - WLRPC_WLC_BMAC_LED_BLINK_EVENT_ID, - WLRPC_WLC_BMAC_LED_SET_ID, - WLRPC_WLC_BMAC_LED_BLINK_ID, - WLRPC_WLC_BMAC_LED_ID, - WLRPC_WLC_BMAC_RATE_SHM_OFFSET_ID, - WLRPC_SI_ISCORE_UP_ID, - WLRPC_WLC_BMAC_PS_SWITCH_ID, - WLRPC_WLC_PHY_STF_SSMODE_GET_ID, - WLRPC_WLC_BMAC_DEBUG_ID, - WLRPC_WLC_EXTLOG_MSG_ID, - WLRPC_WLC_EXTLOG_CFG_ID, - WLRPC_BCM_ASSERT_LOG_ID, - WLRPC_BCM_ASSERT_TYPE_ID, - WLRPC_WLC_BMAC_SET_PHYCAL_CACHE_FLAG_ID, - WLRPC_WLC_BMAC_GET_PHYCAL_CACHE_FLAG_ID, - WLRPC_WLC_PHY_CAL_CACHE_INIT_ID, - WLRPC_WLC_PHY_CAL_CACHE_DEINIT_ID, - WLRPC_WLC_BMAC_HW_UP_ID, - WLRPC_WLC_BMAC_SET_TXPWR_PERCENT_ID, - WLRPC_WLC_PHYCHAIN_ACTIVE_GET_ID, - WLRPC_WLC_BMAC_BLINK_SYNC_ID, - WLRPC_WLC_BMAC_UCODE_DBGSEL_SET_ID, - WLRPC_WLC_BMAC_UCODE_DBGSEL_GET_ID, - WLRPC_WLC_PHY_RADAR_DETECT_MODE_SET_ID, - WLRPC_WLC_PHY_ACIM_NOISEM_RESET_NPHY_ID, - WLRPC_WLC_PHY_INTERFER_SET_NPHY_ID, - WLRPC_WLC_BMAC_IFSCTL_EDCRS_SET_ID, - WLRPC_WLC_PKTENGTX, - WLRPC_WLC_BMAC_SET_DEAF, - WLRPC_WLC_BMAC_CLEAR_DEAF, - WLRPC_WLC_BMAC_BTC_FLAGS_SET_ID, - WLRPC_WLC_BMAC_BTC_FLAGS_GET_ID, - WLRPC_WLC_BMAC_SET_RCMTA_TYPE_ID, - WLRPC_WLC_BMAC_BTC_FLAGS_UPD_ID, - WLRPC_WLC_BMAC_BTC_STUCKWAR_ID, - WLRPC_WLC_BMAC_CCA_STATS_READ_ID, - WLRPC_WLC_BMAC_ANTSEL_SET_ID, - WLRPC_WLC_BMAC_SET_UCODE_LOADED, - WLRPC_WLC_PHY_LDPC_SET_ID, - - WLRPC_LAST -} wlc_rpc_id_t; - -#if defined(BCMDBG) | 0 -struct name_entry { - int id; - char *name; -}; - -#define NAME_ENTRY(x) {x, #x} - -#define RPC_ID_TABLE { \ - NAME_ENTRY(WLRPC_WLC_REG_READ_ID), \ - NAME_ENTRY(WLRPC_WLC_REG_WRITE_ID), \ - NAME_ENTRY(WLRPC_WLC_MHF_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_MHF_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_UP_PREP_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_UP_FINISH_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_DOWN_PREP_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_DOWN_FINISH_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_WRITE_HW_BCNTEMPLATES_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RESET_ID), \ - NAME_ENTRY(WLRPC_WLC_DNGL_REBOOT_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RPC_TXQ_WM_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RPC_TXQ_WM_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RPC_AGG_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RPC_MSGLEVEL_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RPC_AGG_LIMIT_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RPC_AGG_LIMIT_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_INIT_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_CWMIN_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_MUTE_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_DOIOVAR_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_HOLD_UPD_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_MUTE_UPD_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_CLEAR_TSSI_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_ANT_RXDIV_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_ANT_RXDIV_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_PREAMBLE_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_FREQTRACK_END_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_FREQTRACK_START_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_IOCTL_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_NOISE_SAMPLE_REQUEST_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_CAL_PERICAL_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_SROMLIMIT_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_RADAR_DETECT_ENABLE_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_RADAR_DETECT_RUN_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TEST_ISON_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_COPYFROM_OBJMEM_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_COPYTO_OBJMEM_ID), \ - NAME_ENTRY(WLRPC_WLC_ENABLE_MAC_ID), \ - NAME_ENTRY(WLRPC_WLC_MCTRL_ID), \ - NAME_ENTRY(WLRPC_WLC_CORERESET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_READ_SHM_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_READ_TSF_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_ADDRMATCH_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_CWMAX_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_RCMTA_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_SHM_ID), \ - NAME_ENTRY(WLRPC_WLC_SUSPEND_MAC_AND_WAIT_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_WRITE_SHM_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_WRITE_TEMPLATE_RAM_ID), \ - NAME_ENTRY(WLRPC_WLC_TX_FIFO_SUSPEND_ID), \ - NAME_ENTRY(WLRPC_WLC_TX_FIFO_RESUME_ID), \ - NAME_ENTRY(WLRPC_WLC_TX_FIFO_SUSPENDED_ID), \ - NAME_ENTRY(WLRPC_WLC_HW_ETHERADDR_ID), \ - NAME_ENTRY(WLRPC_WLC_SET_HW_ETHERADDR_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_CHANSPEC_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_TXANT_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_ANTSEL_TYPE_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_TXFIFO_ID), \ - NAME_ENTRY(WLRPC_WLC_RADIO_READ_HWDISABLED_ID), \ - NAME_ENTRY(WLRPC_WLC_RM_CCA_MEASURE_ID), \ - NAME_ENTRY(WLRPC_WLC_SET_SHORTSLOT_ID), \ - NAME_ENTRY(WLRPC_WLC_WAIT_FOR_WAKE_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_CURRENT_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_HW_CTRL_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_HW_CTRL_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_BSSINIT_ID), \ - NAME_ENTRY(WLRPC_WLC_BAND_STF_SS_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_BAND_FIRST_CHANSPEC_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_LIMIT_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_BAND_CHANNELS_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_REVINFO_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_STATE_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_XMTFIFO_SZ_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_XMTFIFO_SZ_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_VALIDATE_CHIP_ACCESS_ID), \ - NAME_ENTRY(WLRPC_WLC_RM_CCA_COMPLETE_ID), \ - NAME_ENTRY(WLRPC_WLC_RECV_ID), \ - NAME_ENTRY(WLRPC_WLC_DOTXSTATUS_ID), \ - NAME_ENTRY(WLRPC_WLC_HIGH_DPC_ID), \ - NAME_ENTRY(WLRPC_WLC_FATAL_ERROR_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_SET_CHANNEL_14_WIDE_FILTER_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_NOISE_AVG_ID), \ - NAME_ENTRY(WLRPC_WLC_PHYCHAIN_INIT_ID), \ - NAME_ENTRY(WLRPC_WLC_PHYCHAIN_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHYCHAIN_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TKIP_RIFS_WAR_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_COPYFROM_VARS_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RETRYLIMIT_UPD_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BTC_MODE_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BTC_MODE_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BTC_WIRE_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BTC_WIRE_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_NORESET_ID), \ - NAME_ENTRY(WLRPC_WLC_AMPDU_TXSTATUS_COMPLETE_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_FIFOERRORS_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MIN_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_TXPOWER_GET_TARGET_MAX_ID), \ - NAME_ENTRY(WLRPC_WLC_NOISE_CB_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_LED_HW_DEINIT_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_LED_HW_MASK_INIT_ID), \ - NAME_ENTRY(WLRPC_WLC_PLLREQ_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_TACLEAR_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_CLK_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_OFDM_RATESET_WAR_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_BF_PREEMPT_ENABLE_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_DOIOVARS_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_DUMP_ID), \ - NAME_ENTRY(WLRPC_WLC_CISWRITE_ID), \ - NAME_ENTRY(WLRPC_WLC_CISDUMP_ID), \ - NAME_ENTRY(WLRPC_WLC_UPDATE_PHY_MODE_ID), \ - NAME_ENTRY(WLRPC_WLC_RESET_BMAC_DONE_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_LED_BLINK_EVENT_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_LED_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_LED_BLINK_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_LED_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_RATE_SHM_OFFSET_ID), \ - NAME_ENTRY(WLRPC_SI_ISCORE_UP_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_PS_SWITCH_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_STF_SSMODE_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_DEBUG_ID), \ - NAME_ENTRY(WLRPC_WLC_EXTLOG_MSG_ID), \ - NAME_ENTRY(WLRPC_WLC_EXTLOG_CFG_ID), \ - NAME_ENTRY(WLRPC_BCM_ASSERT_LOG_ID), \ - NAME_ENTRY(WLRPC_BCM_ASSERT_TYPE_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_PHYCAL_CACHE_FLAG_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_GET_PHYCAL_CACHE_FLAG_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_CAL_CACHE_INIT_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_CAL_CACHE_DEINIT_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_HW_UP_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_TXPWR_PERCENT_ID), \ - NAME_ENTRY(WLRPC_WLC_PHYCHAIN_ACTIVE_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BLINK_SYNC_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_UCODE_DBGSEL_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_UCODE_DBGSEL_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_RADAR_DETECT_MODE_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_ACIM_NOISEM_RESET_NPHY_ID), \ - NAME_ENTRY(WLRPC_WLC_PHY_INTERFER_SET_NPHY_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_IFSCTL_EDCRS_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_PKTENGTX), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_DEAF), \ - NAME_ENTRY(WLRPC_WLC_BMAC_CLEAR_DEAF), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BTC_FLAGS_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_BTC_FLAGS_GET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_RCMTA_TYPE_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_CCA_STATS_READ_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_ANTSEL_SET_ID), \ - NAME_ENTRY(WLRPC_WLC_BMAC_SET_UCODE_LOADED), \ - NAME_ENTRY(WLRPC_WLC_PHY_LDPC_SET_ID), \ - {0, NULL} \ - } - -static __inline char *_wlc_rpc_id_lookup(const struct name_entry *tbl, int _id) -{ - const struct name_entry *elt = tbl; - static char __unknown[64]; - for (; elt->name != NULL; elt++) { - if (_id == elt->id) - break; - } - if (_id == elt->id) - strncpy(__unknown, elt->name, sizeof(__unknown)); - else - snprintf(__unknown, sizeof(__unknown), "ID:%d", _id); - return __unknown; -} - -#define WLC_RPC_ID_LOOKUP(tbl, _id) (_wlc_rpc_id_lookup(tbl, _id)) - -#endif /* BCMDBG */ - -/* refer to txpwr_limits_t for each elements, mcs32 is the at the end for 1 byte */ -#define TXPOWER_XDR_SZ (roundup(WLC_NUM_RATES_CCK, 4) + roundup(WLC_NUM_RATES_OFDM, 4) * 4 + \ - roundup(WLC_NUM_RATES_MCS_1_STREAM, 4) * 6 + roundup(WLC_NUM_RATES_MCS_2_STREAM, 4) * 2 + \ - roundup(1, 4)) - -#define wlc_rpc_txpwr_limits(b, txpwr, op, err) \ - do { \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->cck, WLC_NUM_RATES_CCK); \ - ASSERT(!(err)); \ - \ - /* 20 MHz Legacy OFDM rates with SISO transmission */ \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm, WLC_NUM_RATES_OFDM); \ - ASSERT(!(err)); \ - \ - /* 20 MHz Legacy OFDM rates with CDD transmission */ \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm_cdd, WLC_NUM_RATES_OFDM); \ - ASSERT(!(err)); \ - \ - /* 40 MHz Legacy OFDM rates with SISO transmission */ \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm_40_siso, WLC_NUM_RATES_OFDM); \ - ASSERT(!(err)); \ - \ - /* 40 MHz Legacy OFDM rates with CDD transmission */ \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->ofdm_40_cdd, WLC_NUM_RATES_OFDM); \ - ASSERT(!(err)); \ - \ - /* 20MHz MCS rates SISO/CDD/STBC/SDM */ \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_siso, WLC_NUM_RATES_MCS_1_STREAM); \ - ASSERT(!(err)); \ - \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_cdd, WLC_NUM_RATES_MCS_1_STREAM); \ - ASSERT(!(err)); \ - \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_stbc, WLC_NUM_RATES_MCS_1_STREAM); \ - ASSERT(!(err)); \ - \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_20_mimo, WLC_NUM_RATES_MCS_2_STREAM); \ - ASSERT(!(err)); \ - \ - /* 40MHz MCS rates SISO/CDD/STBC/SDM */ \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_siso, WLC_NUM_RATES_MCS_1_STREAM); \ - ASSERT(!(err)); \ - \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_cdd, WLC_NUM_RATES_MCS_1_STREAM); \ - ASSERT(!(err)); \ - \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_stbc, WLC_NUM_RATES_MCS_1_STREAM); \ - ASSERT(!(err)); \ - \ - (err) = bcm_xdr_##op##_u8_vec((b), (txpwr)->mcs_40_mimo, WLC_NUM_RATES_MCS_2_STREAM); \ - ASSERT(!(err)); \ - } while (0) - -typedef struct wlc_rpc_ctx { - rpc_info_t *rpc; - wlc_info_t *wlc; - wlc_hw_info_t *wlc_hw; -} wlc_rpc_ctx_t; - -static inline rpc_buf_t *wlc_rpc_buf_alloc(rpc_info_t *rpc, bcm_xdr_buf_t *b, - uint len, wlc_rpc_id_t rpc_id) -{ - rpc_buf_t *rpc_buf; - - rpc_buf = bcm_rpc_buf_alloc(rpc, len + sizeof(u32)); - - if (!rpc_buf) - return NULL; - - bcm_xdr_buf_init(b, bcm_rpc_buf_data(bcm_rpc_tp_get(rpc), rpc_buf), - len + sizeof(u32)); - - bcm_xdr_pack_u32(b, rpc_id); - - return rpc_buf; -} - -#if defined(BCMDBG) -static __inline wlc_rpc_id_t -wlc_rpc_id_get(struct rpc_info *rpc, rpc_buf_t *buf) -{ - wlc_rpc_id_t rpc_id; - bcm_xdr_buf_t b; - - bcm_xdr_buf_init(&b, bcm_rpc_buf_data(bcm_rpc_tp_get(rpc), buf), - sizeof(u32)); - - bcm_xdr_unpack_u32(&b, (u32 *)((unsigned long) & rpc_id)); - return rpc_id; -} -#endif - -static __inline int _wlc_rpc_call(struct rpc_info *rpc, rpc_buf_t *send) -{ - int _err = 0; -#if defined(BCMDBG) - wlc_rpc_id_t rpc_id = wlc_rpc_id_get(rpc, send); - /* const struct name_entry rpc_name_tbl[] = RPC_ID_TABLE; */ - static struct name_entry rpc_name_tbl[] = RPC_ID_TABLE; - WL_TRACE(("%s: Called id %s\n", __func__, - WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id))); -#endif - _err = bcm_rpc_call(rpc, send); - if (_err) { -#if defined(BCMDBG) - WL_ERROR(("%s: Call id %s FAILED\n", __func__, - WLC_RPC_ID_LOOKUP(rpc_name_tbl, rpc_id))); -#endif - _err = 0; - } - return _err; -} - -#define wlc_rpc_call(rpc, send) (_wlc_rpc_call(rpc, send)) - -#include -#include -#include - -extern void wlc_rpc_bmac_dispatch(wlc_rpc_ctx_t *rpc_ctx, struct rpc_buf *buf); -extern void wlc_rpc_bmac_dump_txfifohist(wlc_hw_info_t *wlc_hw, - bool dump_clear); - -/* Packed structure for ease of transport across RPC bus along u32 boundary */ -typedef struct wlc_rpc_txstatus { - u32 PAD_framelen; - u32 status_frameid; - u32 sequence_lasttxtime; - u32 ackphyrxsh_phyerr; -} wlc_rpc_txstatus_t; - -static inline - void txstatus2rpc_txstatus(tx_status_t *txstatus, - wlc_rpc_txstatus_t *rpc_txstatus) -{ - rpc_txstatus->PAD_framelen = txstatus->framelen; - rpc_txstatus->status_frameid = - (txstatus->status << 16) | txstatus->frameid; - rpc_txstatus->sequence_lasttxtime = - (txstatus->sequence << 16) | txstatus->lasttxtime; - rpc_txstatus->ackphyrxsh_phyerr = - (txstatus->ackphyrxsh << 16) | txstatus->phyerr; -} - -static inline - void rpc_txstatus2txstatus(wlc_rpc_txstatus_t *rpc_txstatus, - tx_status_t *txstatus) -{ - txstatus->framelen = rpc_txstatus->PAD_framelen & 0xffff; - txstatus->status = (rpc_txstatus->status_frameid >> 16) & 0xffff; - txstatus->frameid = rpc_txstatus->status_frameid & 0xffff; - txstatus->sequence = (rpc_txstatus->sequence_lasttxtime >> 16) & 0xffff; - txstatus->lasttxtime = rpc_txstatus->sequence_lasttxtime & 0xffff; - txstatus->ackphyrxsh = (rpc_txstatus->ackphyrxsh_phyerr >> 16) & 0xffff; - txstatus->phyerr = rpc_txstatus->ackphyrxsh_phyerr & 0xffff; -} - -extern void wlc_bmac_dngl_reboot(rpc_info_t *rpc); - -#endif /* WLC_RPC_H */ diff --git a/drivers/staging/brcm80211/sys/wlc_rpctx.h b/drivers/staging/brcm80211/sys/wlc_rpctx.h deleted file mode 100644 index 58ce5438632f..000000000000 --- a/drivers/staging/brcm80211/sys/wlc_rpctx.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _wlc_rpctx_h_ -#define _wlc_rpctx_h_ - -/* forward declaration */ -struct wlc_info; - -/* This controls how many packets are given to the dongle. This is required as - * NTXD needs to be power of 2 but we may not have enough memory to absorb that - * large number of frames - */ -#ifndef NRPCTXBUFPOST -#define NRPCTXBUFPOST NTXD -#endif - -#define RPCTX_ENAB(pub) (false) -#define wlc_rpctx_attach(pub, wlc) (NULL) -#define wlc_rpctx_fifoinit(rpctx, fifo, ntxd) (0) -#define wlc_rpctx_detach(rpctx) ASSERT(0) -#define wlc_rpctx_txavail(rpctx, f) (false) -#define wlc_rpctx_dump(rpctx, b) (0) -#define wlc_rpctx_getnexttxp(rpctx, f) (NULL) -#define wlc_rpctx_txreclaim(rpctx) ASSERT(0) -#define wlc_rpctx_pkteng(rpctx, fifo, p) do { } while (0) -#define wlc_rpctx_tx(rpctx, f, p, c, fid, t) (0) -#define wlc_rpctx_txpktpendinc(rpctx, f, val) do { } while (0) -#define wlc_rpctx_txpktpenddec(rpctx, f, val) do { } while (0) -#define wlc_rpctx_txpktpendclr(rpctx, f) do { } while (0) -#define wlc_rpctx_txpktpend(rpctx, f, all) (0) - - -#endif /* _wlc_rpctx_h_ */ -- cgit v1.2.3 From f9ec972793fb61f6ec612ecee5b1cc6efeacfbd6 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:57 -0800 Subject: staging: brcm80211: unifdef -UBCMSDIO Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wl_mac80211.c | 25 ------------------------- drivers/staging/brcm80211/sys/wl_mac80211.h | 4 ---- drivers/staging/brcm80211/sys/wlc_bmac.c | 5 ----- drivers/staging/brcm80211/sys/wlc_cfg.h | 16 ---------------- drivers/staging/brcm80211/sys/wlc_mac80211.c | 4 ---- drivers/staging/brcm80211/sys/wlc_mac80211.h | 3 --- drivers/staging/brcm80211/sys/wlc_pub.h | 3 --- 7 files changed, 60 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 37e6ced84db5..6c162b9f864a 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -40,9 +40,6 @@ #include #include #include -#ifdef BCMSDIO -#include -#endif #include #include @@ -50,9 +47,6 @@ #include #include -#ifdef BCMSDIO -extern struct device *sdiommc_dev; -#endif extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend); @@ -127,7 +121,6 @@ MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -#ifndef BCMSDIO /* recognized PCI IDs */ static struct pci_device_id wl_id_table[] = { {PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43225 2G */ @@ -138,12 +131,7 @@ static struct pci_device_id wl_id_table[] = { MODULE_DEVICE_TABLE(pci, wl_id_table); static void wl_remove(struct pci_dev *pdev); -#endif /* !BCMSDIO */ -#ifdef BCMSDIO -static uint sd_drivestrength = 6; -module_param(sd_drivestrength, uint, 0); -#endif #ifdef BCMDBG static int msglevel = 0xdeadbeef; @@ -701,9 +689,6 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, tasklet_init(&wl->tasklet, wl_dpc, (unsigned long) wl); -#ifdef BCMSDIO - SET_IEEE80211_DEV(hw, sdiommc_dev); -#endif base_addr = regs; @@ -754,10 +739,6 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, WL_ERROR(("wl%d: Error setting MPC variable to 0\n", unit)); } -#ifdef BCMSDIO - /* Set SDIO drive strength */ - wlc_iovar_setint(wl->wlc, "sd_drivestrength", sd_drivestrength); -#endif /* register our interrupt handler */ if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { @@ -1048,7 +1029,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw) return ieee_hw_rate_init(hw); } -#ifndef BCMSDIO /** * determines if a device is a WL device, and if so, attaches it. * @@ -1219,7 +1199,6 @@ static struct pci_driver wl_pci_driver = { .remove = __devexit_p(wl_remove), .id_table = wl_id_table, }; -#endif /* !BCMSDIO */ /** * This is the main entry point for the WL driver. @@ -1253,12 +1232,10 @@ static int __init wl_module_init(void) } #endif /* BCMDBG */ -#ifndef BCMSDIO error = pci_register_driver(&wl_pci_driver); if (!error) return 0; -#endif /* !BCMSDIO */ return error; @@ -1273,9 +1250,7 @@ static int __init wl_module_init(void) */ static void __exit wl_module_exit(void) { -#ifndef BCMSDIO pci_unregister_driver(&wl_pci_driver); -#endif /* !BCMSDIO */ } diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h index 220d570710cb..239ef3a0ed9b 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.h +++ b/drivers/staging/brcm80211/sys/wl_mac80211.h @@ -75,10 +75,6 @@ struct wl_info { atomic_t callbacks; /* # outstanding callback functions */ struct wl_timer *timers; /* timer cleanup queue */ struct tasklet_struct tasklet; /* dpc tasklet */ -#ifdef BCMSDIO - bcmsdh_info_t *sdh; /* pointer to sdio bus handler */ - unsigned long flags; /* current irq flags */ -#endif /* BCMSDIO */ bool resched; /* dpc needs to be and is rescheduled */ #ifdef LINUXSTA_PS u32 pci_psstate[16]; /* pci ps-state save/restore */ diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 110710ad6e78..4b2708620049 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -56,9 +56,6 @@ #include #include "wl_ucode.h" #include "d11ucode_ext.h" -#ifdef BCMSDIO -#include -#endif #include /* BMAC_NOTE: With WLC_HIGH defined, some fns in this file make calls to high level @@ -3209,9 +3206,7 @@ static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr) */ /* turn off the interrupts */ W_REG(osh, ®s->macintmask, 0); -#ifndef BCMSDIO (void)R_REG(osh, ®s->macintmask); /* sync readback */ -#endif wlc->macintmask = 0; /* clear device interrupts */ diff --git a/drivers/staging/brcm80211/sys/wlc_cfg.h b/drivers/staging/brcm80211/sys/wlc_cfg.h index e36d209c72fd..e56adb78f4fa 100644 --- a/drivers/staging/brcm80211/sys/wlc_cfg.h +++ b/drivers/staging/brcm80211/sys/wlc_cfg.h @@ -55,22 +55,6 @@ * 3 5356a0 */ -#ifdef BCMSDIO -#define D11CONF 0x100000 -#define SSLPNCONF 2 -#define GCCONF 0 -#define ACCONF 0 -#define NCONF 0 -#define LPCONF 0 -#define LCNCONF 0 -#define NTXD 32 -#define NRXD 16 -#define NRXBUFPOST 8 -#define WLC_DATAHIWAT 32 -#define RXBND 8 -#define MAXPKTCB 64 -#define AMPDU_NUM_MPDU 8 -#endif /* For undefined values, use defaults */ #ifndef D11CONF diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index c6f64c2e461a..37a87d8f23c8 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -48,11 +48,7 @@ #include #include #include -#ifdef BCMSDIO -#include -#else #include "d11ucode_ext.h" -#endif #include #include #include diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 459e3cfc84aa..8c961e21002f 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -480,9 +480,6 @@ struct wlc_hw_info { bool phyclk; /* phy is out of reset and has clock */ bool dma_lpbk; /* core is in DMA loopback */ -#ifdef BCMSDIO - void *sdh; -#endif bool ucode_loaded; /* true after ucode downloaded */ diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index 09be41d921c5..2f4b899f0fe1 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -318,9 +318,6 @@ typedef struct wlc_pub { * is implemented properly in osl of that port * when it enables this Power Save feature. */ -#ifdef BCMSDIO - uint sdiod_drive_strength; /* SDIO drive strength */ -#endif /* BCMSDIO */ u16 boardrev; /* version # of particular board */ u8 sromrev; /* version # of the srom */ -- cgit v1.2.3 From 861f67031899b8ab909d672eaea85070317855c9 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 19 Nov 2010 14:30:58 -0800 Subject: staging: brcm80211: stragglers not handled by unifdef Part of BMAC removal. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 37 -------------------- drivers/staging/brcm80211/include/osl.h | 5 --- drivers/staging/brcm80211/sys/wlc_cfg.h | 2 -- drivers/staging/brcm80211/sys/wlc_mac80211.h | 1 - drivers/staging/brcm80211/sys/wlc_pub.h | 4 --- drivers/staging/brcm80211/util/linux_osl.c | 49 --------------------------- 6 files changed, 98 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 11239fbba766..d314dfb2b62f 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -61,15 +61,6 @@ extern uint osl_pci_slot(struct osl_info *osh); ((struct osl_pubinfo *)osh)->tx_ctx = _tx_ctx; \ } while (0) -#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) -#define REGOPSSET(osh, rreg, wreg, ctx) \ - do { \ - ((struct osl_pubinfo *)osh)->rreg_fn = rreg; \ - ((struct osl_pubinfo *)osh)->wreg_fn = wreg; \ - ((struct osl_pubinfo *)osh)->reg_ctx = ctx; \ - } while (0) -#endif - #define BUS_SWAP32(v) (v) extern void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, @@ -321,32 +312,4 @@ osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) /* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ #define PKTSHARED(skb) (((struct sk_buff *)(skb))->cloned) -#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) -#define RPC_READ_REG(osh, r) (\ - sizeof(*(r)) == sizeof(u8) ? osl_readb((osh), (volatile u8*)(r)) : \ - sizeof(*(r)) == sizeof(u16) ? osl_readw((osh), (volatile u16*)(r)) : \ - osl_readl((osh), (volatile u32*)(r)) \ -) -#define RPC_WRITE_REG(osh, r, v) do { \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - osl_writeb((osh), (volatile u8*)(r), (u8)(v)); \ - break; \ - case sizeof(u16): \ - osl_writew((osh), (volatile u16*)(r), (u16)(v)); \ - break; \ - case sizeof(u32): \ - osl_writel((osh), (volatile u32*)(r), (u32)(v)); \ - break; \ - } \ -} while (0) - -extern u8 osl_readb(struct osl_info *osh, volatile u8 *r); -extern u16 osl_readw(struct osl_info *osh, volatile u16 *r); -extern u32 osl_readl(struct osl_info *osh, volatile u32 *r); -extern void osl_writeb(struct osl_info *osh, volatile u8 *r, u8 v); -extern void osl_writew(struct osl_info *osh, volatile u16 *r, u16 v); -extern void osl_writel(struct osl_info *osh, volatile u32 *r, u32 v); -#endif /* BCMSDIO */ - #endif /* _linux_osl_h_ */ diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index e2205c481a3f..4d0ce9705500 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -26,11 +26,6 @@ struct osl_pubinfo { bool mmbus; /* Bus supports memory-mapped registers */ pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ void *tx_ctx; /* Context to the callback function */ -#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) - osl_rreg_fn_t rreg_fn; /* Read Register function */ - osl_wreg_fn_t wreg_fn; /* Write Register function */ - void *reg_ctx; /* Context to the reg callback functions */ -#endif }; /* osl handle type forward declaration */ diff --git a/drivers/staging/brcm80211/sys/wlc_cfg.h b/drivers/staging/brcm80211/sys/wlc_cfg.h index e56adb78f4fa..3decb7d1a5e5 100644 --- a/drivers/staging/brcm80211/sys/wlc_cfg.h +++ b/drivers/staging/brcm80211/sys/wlc_cfg.h @@ -23,8 +23,6 @@ #define IS_SINGLEBAND_5G(device) 0 -/* Keep WLC_HIGH_ONLY, WLC_SPLIT for USB extension later on */ - /* **** Core type/rev defaults **** */ #define D11_DEFAULT 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27 * also need to update wlc.h MAXCOREREV diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 8c961e21002f..006880049f37 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -815,7 +815,6 @@ struct antsel_info { #define WLC_IS_MATCH_SSID(wlc, ssid1, ssid2, len1, len2) \ ((len1 == len2) && !bcmp(ssid1, ssid2, len1)) -/* API shared by both WLC_HIGH and WLC_LOW driver */ extern void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus); extern void wlc_fatal_error(wlc_info_t *wlc); extern void wlc_bmac_rpc_watchdog(wlc_info_t *wlc); diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index 2f4b899f0fe1..4b1ab1d1c2ce 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -610,10 +610,6 @@ extern void wlc_pmkid_event(struct wlc_bsscfg *cfg); #define BAND_2G_NAME "2.4G" #define BAND_5G_NAME "5G" -#if defined(BCMSDIO) || defined(WLC_HIGH_ONLY) -void wlc_device_removed(void *arg); -#endif - /* BMAC RPC: 7 u32 params: pkttotlen, fifo, commit, fid, txpktpend, pktflag, rpc_id */ #define WLC_RPCTX_PARAMS 32 diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index e6e52f660780..a07eada14d08 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -246,52 +246,3 @@ void osl_assert(char *exp, char *file, int line) } #endif /* defined(BCMDBG_ASSERT) */ -#if defined(BCMSDIO) && !defined(BRCM_FULLMAC) -u8 osl_readb(struct osl_info *osh, volatile u8 *r) -{ - osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; - void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; - - return (u8) ((rreg) (ctx, (void *)r, sizeof(u8))); -} - -u16 osl_readw(struct osl_info *osh, volatile u16 *r) -{ - osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; - void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; - - return (u16) ((rreg) (ctx, (void *)r, sizeof(u16))); -} - -u32 osl_readl(struct osl_info *osh, volatile u32 *r) -{ - osl_rreg_fn_t rreg = ((struct osl_pubinfo *) osh)->rreg_fn; - void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; - - return (u32) ((rreg) (ctx, (void *)r, sizeof(u32))); -} - -void osl_writeb(struct osl_info *osh, volatile u8 *r, u8 v) -{ - osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; - void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; - - ((wreg) (ctx, (void *)r, v, sizeof(u8))); -} - -void osl_writew(struct osl_info *osh, volatile u16 *r, u16 v) -{ - osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; - void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; - - ((wreg) (ctx, (void *)r, v, sizeof(u16))); -} - -void osl_writel(struct osl_info *osh, volatile u32 *r, u32 v) -{ - osl_wreg_fn_t wreg = ((struct osl_pubinfo *) osh)->wreg_fn; - void *ctx = ((struct osl_pubinfo *) osh)->reg_ctx; - - ((wreg) (ctx, (void *)r, v, sizeof(u32))); -} -#endif /* BCMSDIO */ -- cgit v1.2.3 From 5a7f4fddae8a50d076b5714f47936ea78e0c0858 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 19 Nov 2010 13:32:38 +0100 Subject: staging: iio: dac: more consistent DAC sysfs attributes naming Align DAC sysfs attributes naming with the convention used by ADC Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/dac.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h index 55005eec1214..d9384c9a3e85 100644 --- a/drivers/staging/iio/dac/dac.h +++ b/drivers/staging/iio/dac/dac.h @@ -2,5 +2,9 @@ * dac.h - sysfs attributes associated with DACs */ +/* Deprecated */ #define IIO_DEV_ATTR_DAC(_num, _store, _addr) \ IIO_DEVICE_ATTR(dac_##_num, S_IWUSR, NULL, _store, _addr) + +#define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr) \ + IIO_DEVICE_ATTR(out##_num##_raw, S_IWUSR, NULL, _store, _addr) -- cgit v1.2.3 From 51f8ad36022e880019e79a9dea2351cc47c739d7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 19 Nov 2010 15:16:43 +0100 Subject: staging: iio: dac: Update drivers to use new attribute naming Remove depreciated macro from header Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/ad5624r_spi.c | 16 ++++++++-------- drivers/staging/iio/dac/dac.h | 4 ---- 2 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c index 705ff505bf25..c0d7de90b784 100644 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -180,10 +180,10 @@ static ssize_t ad5624r_write_internal_ref_mode(struct device *dev, return ret ? ret : len; } -static IIO_DEV_ATTR_DAC(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); -static IIO_DEV_ATTR_DAC(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); -static IIO_DEV_ATTR_DAC(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); -static IIO_DEV_ATTR_DAC(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); +static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); +static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); +static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); +static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode, ad5624r_write_ldac_mode, 0); @@ -199,10 +199,10 @@ static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode, ad5624r_write static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 3); static struct attribute *ad5624r_attributes[] = { - &iio_dev_attr_dac_0.dev_attr.attr, - &iio_dev_attr_dac_1.dev_attr.attr, - &iio_dev_attr_dac_2.dev_attr.attr, - &iio_dev_attr_dac_3.dev_attr.attr, + &iio_dev_attr_out0_raw.dev_attr.attr, + &iio_dev_attr_out1_raw.dev_attr.attr, + &iio_dev_attr_out2_raw.dev_attr.attr, + &iio_dev_attr_out3_raw.dev_attr.attr, &iio_dev_attr_dac_power_mode_0.dev_attr.attr, &iio_dev_attr_dac_power_mode_1.dev_attr.attr, &iio_dev_attr_dac_power_mode_2.dev_attr.attr, diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h index d9384c9a3e85..1d82f353241c 100644 --- a/drivers/staging/iio/dac/dac.h +++ b/drivers/staging/iio/dac/dac.h @@ -2,9 +2,5 @@ * dac.h - sysfs attributes associated with DACs */ -/* Deprecated */ -#define IIO_DEV_ATTR_DAC(_num, _store, _addr) \ - IIO_DEVICE_ATTR(dac_##_num, S_IWUSR, NULL, _store, _addr) - #define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr) \ IIO_DEVICE_ATTR(out##_num##_raw, S_IWUSR, NULL, _store, _addr) -- cgit v1.2.3 From df9cd1052079e5d0f88ed230276a17a49cc41045 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 19 Nov 2010 15:16:44 +0100 Subject: staging: iio: dac: Use spi_write() and handle return value Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/ad5624r_spi.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c index c0d7de90b784..17588b4b055d 100644 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -35,10 +35,9 @@ struct ad5624r_state { int internal_ref; }; -static int ad5624r_spi_write(struct spi_device *spi, u8 cmd, u8 addr, u16 val, u8 len) +static int ad5624r_spi_write(struct spi_device *spi, + u8 cmd, u8 addr, u16 val, u8 len) { - struct spi_transfer t; - struct spi_message m; u32 data; u8 msg[3]; @@ -54,15 +53,7 @@ static int ad5624r_spi_write(struct spi_device *spi, u8 cmd, u8 addr, u16 val, u msg[1] = data >> 8; msg[2] = data; - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - t.tx_buf = &msg[0]; - t.len = 3; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; + return spi_write(spi, msg, 3); } static ssize_t ad5624r_write_dac(struct device *dev, @@ -80,7 +71,7 @@ static ssize_t ad5624r_write_dac(struct device *dev, if (ret) return ret; - ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, + ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, this_attr->address, readin, st->data_len); return ret ? ret : len; } @@ -109,7 +100,7 @@ static ssize_t ad5624r_write_ldac_mode(struct device *dev, if (ret) return ret; - ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0, readin & 0xF, 16); + ret = ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0, readin & 0xF, 16); st->ldac_mode = readin & 0xF; return ret ? ret : len; @@ -141,7 +132,7 @@ static ssize_t ad5624r_write_dac_power_mode(struct device *dev, if (ret) return ret; - ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0, + ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0, ((readin & 0x3) << 4) | (1 << this_attr->address), 16); st->dac_power_mode[this_attr->address] = readin & 0x3; @@ -173,7 +164,7 @@ static ssize_t ad5624r_write_internal_ref_mode(struct device *dev, if (ret) return ret; - ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!readin, 16); + ret = ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!readin, 16); st->internal_ref = !!readin; -- cgit v1.2.3 From ece30c15921f94c1d58c494507f528c9482db409 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 19 Nov 2010 15:16:45 +0100 Subject: staging: iio: dac: Use spi_device_id Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/ad5624r_spi.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c index 17588b4b055d..b7c1661f6872 100644 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -209,13 +209,8 @@ static const struct attribute_group ad5624r_attribute_group = { static int __devinit ad5624r_probe(struct spi_device *spi) { - struct ad5624r_state *st; int ret = 0; - char *chip_name = spi->dev.platform_data; - - if (!chip_name) - return -ENODEV; st = kzalloc(sizeof(*st), GFP_KERNEL); if (st == NULL) { @@ -224,17 +219,7 @@ static int __devinit ad5624r_probe(struct spi_device *spi) } spi_set_drvdata(spi, st); - if (strcmp(chip_name, "ad5624r") == 0) - st->data_len = 12; - else if (strcmp(chip_name, "ad5644r") == 0) - st->data_len = 14; - else if (strcmp(chip_name, "ad5664r") == 0) - st->data_len = 16; - else { - dev_err(&spi->dev, "not supported chip type\n"); - ret = -EINVAL; - goto error_ret; - } + st->data_len = spi_get_device_id(spi)->driver_data; st->us = spi; st->indio_dev = iio_allocate_device(); @@ -278,6 +263,13 @@ static int __devexit ad5624r_remove(struct spi_device *spi) return 0; } +static const struct spi_device_id ad5624r_id[] = { + {"ad5624r", 12}, + {"ad5644r", 14}, + {"ad5664r", 16}, + {} +}; + static struct spi_driver ad5624r_driver = { .driver = { .name = "ad5624r", @@ -285,6 +277,7 @@ static struct spi_driver ad5624r_driver = { }, .probe = ad5624r_probe, .remove = __devexit_p(ad5624r_remove), + .id_table = ad5624r_id, }; static __init int ad5624r_spi_init(void) -- cgit v1.2.3 From 24d6050b352aa76364bd344c41b3e3e0f51466cc Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Fri, 19 Nov 2010 15:16:46 +0100 Subject: staging: iio: dac: Cleanup style - no functional changes Stick to the 80 character line limit at least for code Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/ad5624r_spi.c | 67 ++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c index b7c1661f6872..2b1c6dde4fdd 100644 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -57,9 +57,8 @@ static int ad5624r_spi_write(struct spi_device *spi, } static ssize_t ad5624r_write_dac(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { long readin; int ret; @@ -72,13 +71,12 @@ static ssize_t ad5624r_write_dac(struct device *dev, return ret; ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, - this_attr->address, readin, st->data_len); + this_attr->address, readin, st->data_len); return ret ? ret : len; } static ssize_t ad5624r_read_ldac_mode(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5624r_state *st = indio_dev->dev_data; @@ -87,9 +85,8 @@ static ssize_t ad5624r_read_ldac_mode(struct device *dev, } static ssize_t ad5624r_write_ldac_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { long readin; int ret; @@ -100,15 +97,16 @@ static ssize_t ad5624r_write_ldac_mode(struct device *dev, if (ret) return ret; - ret = ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0, readin & 0xF, 16); + ret = ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0, + readin & 0xF, 16); st->ldac_mode = readin & 0xF; return ret ? ret : len; } static ssize_t ad5624r_read_dac_power_mode(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5624r_state *st = indio_dev->dev_data; @@ -118,9 +116,8 @@ static ssize_t ad5624r_read_dac_power_mode(struct device *dev, } static ssize_t ad5624r_write_dac_power_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { long readin; int ret; @@ -133,7 +130,8 @@ static ssize_t ad5624r_write_dac_power_mode(struct device *dev, return ret; ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0, - ((readin & 0x3) << 4) | (1 << this_attr->address), 16); + ((readin & 0x3) << 4) | + (1 << this_attr->address), 16); st->dac_power_mode[this_attr->address] = readin & 0x3; @@ -141,8 +139,8 @@ static ssize_t ad5624r_write_dac_power_mode(struct device *dev, } static ssize_t ad5624r_read_internal_ref_mode(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5624r_state *st = indio_dev->dev_data; @@ -151,9 +149,8 @@ static ssize_t ad5624r_read_internal_ref_mode(struct device *dev, } static ssize_t ad5624r_write_internal_ref_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { long readin; int ret; @@ -164,7 +161,8 @@ static ssize_t ad5624r_write_internal_ref_mode(struct device *dev, if (ret) return ret; - ret = ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!readin, 16); + ret = ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, + !!readin, 16); st->internal_ref = !!readin; @@ -177,17 +175,22 @@ static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode, - ad5624r_write_ldac_mode, 0); -static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR, ad5624r_read_internal_ref_mode, - ad5624r_write_internal_ref_mode, 0); + ad5624r_write_ldac_mode, 0); +static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR, + ad5624r_read_internal_ref_mode, + ad5624r_write_internal_ref_mode, 0); #define IIO_DEV_ATTR_DAC_POWER_MODE(_num, _show, _store, _addr) \ IIO_DEVICE_ATTR(dac_power_mode_##_num, S_IRUGO | S_IWUSR, _show, _store, _addr) -static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 0); -static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 1); -static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 2); -static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 3); +static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode, + ad5624r_write_dac_power_mode, 0); +static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode, + ad5624r_write_dac_power_mode, 1); +static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode, + ad5624r_write_dac_power_mode, 2); +static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode, + ad5624r_write_dac_power_mode, 3); static struct attribute *ad5624r_attributes[] = { &iio_dev_attr_out0_raw.dev_attr.attr, @@ -272,9 +275,9 @@ static const struct spi_device_id ad5624r_id[] = { static struct spi_driver ad5624r_driver = { .driver = { - .name = "ad5624r", - .owner = THIS_MODULE, - }, + .name = "ad5624r", + .owner = THIS_MODULE, + }, .probe = ad5624r_probe, .remove = __devexit_p(ad5624r_remove), .id_table = ad5624r_id, -- cgit v1.2.3 From 7716090be5603f1ad4df1379652b8d107c207f5c Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 18 Nov 2010 09:49:09 +0100 Subject: staging: ft1000: Fix compilation warning. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fix following warning: drivers/staging/ft1000/ft1000-usb/ft1000_usb.c:67:22: warning: ‘pft1000info’ may be used uninitialized in this function Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 1369f06cb0df..f88ff86df177 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -64,7 +64,7 @@ static int ft1000_probe(struct usb_interface *interface, int i, ret = 0, size; struct ft1000_device *ft1000dev; - struct ft1000_info *pft1000info; + struct ft1000_info *pft1000info = NULL; const struct firmware *dsp_fw; ft1000dev = kmalloc(sizeof(struct ft1000_device), GFP_KERNEL); -- cgit v1.2.3 From d948d5f96a4b5923599a7a657dbbd8660b0f9fa5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 17 Nov 2010 15:38:46 -0800 Subject: staging: clearpad_tm1217 depends on INPUT clearpad_tm1217 driver uses many input_() interfaces, so it should depend on INPUT. clearpad_tm1217.c:(.text+0xf19ac): undefined reference to `input_unregister_device' clearpad_tm1217.c:(.text+0xf1b19): undefined reference to `input_event' clearpad_tm1217.c:(.text+0xf1b31): undefined reference to `input_event' clearpad_tm1217.c:(.text+0xf1bb4): undefined reference to `input_event' clearpad_tm1217.c:(.text+0xf1bf2): undefined reference to `input_event' drivers/built-in.o:clearpad_tm1217.c:(.text+0xf1c08): more undefined references to `input_event' follow clearpad_tm1217.c:(.text+0xf1df3): undefined reference to `input_allocate_device' clearpad_tm1217.c:(.text+0xf1eac): undefined reference to `input_set_abs_params' clearpad_tm1217.c:(.text+0xf1ed1): undefined reference to `input_set_abs_params' clearpad_tm1217.c:(.text+0xf1ed8): undefined reference to `input_register_device' clearpad_tm1217.c:(.text+0xf2040): undefined reference to `input_unregister_device' clearpad_tm1217.c:(.text+0xf204b): undefined reference to `input_free_device' Signed-off-by: Randy Dunlap Cc: Ramesh Agarwal Signed-off-by: Greg Kroah-Hartman --- drivers/staging/cptm1217/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/cptm1217/Kconfig b/drivers/staging/cptm1217/Kconfig index f90545d78f93..43b1cc0a50a5 100644 --- a/drivers/staging/cptm1217/Kconfig +++ b/drivers/staging/cptm1217/Kconfig @@ -2,6 +2,7 @@ config TOUCHSCREEN_CLEARPAD_TM1217 tristate "Synaptics Clearpad TM1217" depends on I2C depends on GPIOLIB + depends on INPUT help Say Y here if you have a Synaptics Clearpad TM1217 Controller -- cgit v1.2.3 From 4856ab33eb5c33bdf17a5a1bd8d720bffe5f6110 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Wed, 17 Nov 2010 15:45:36 -0800 Subject: Staging: sep: Introduce sep driver This driver is for the Security Processor, a dedicated encryption and decryption driver that is used on the Intel mobile platform. This has been checked with checkpatch and there are four warnings for lines over 80 charactors. There is one compile warning. This is for a function that is only used if the rar register driver is needed. There is an ifdef in a header file that stubs out the rar register driver if the rar register is not configured. This driver does add a configuration, which is CONFIG_DX_SEP. Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/sep/Kconfig | 11 + drivers/staging/sep/Makefile | 2 + drivers/staging/sep/TODO | 12 + drivers/staging/sep/sep_dev.h | 156 ++ drivers/staging/sep/sep_driver.c | 4152 ++++++++++++++++++++++++++++++ drivers/staging/sep/sep_driver_api.h | 309 +++ drivers/staging/sep/sep_driver_config.h | 428 +++ drivers/staging/sep/sep_driver_hw_defs.h | 234 ++ 10 files changed, 5307 insertions(+) create mode 100644 drivers/staging/sep/Kconfig create mode 100644 drivers/staging/sep/Makefile create mode 100644 drivers/staging/sep/TODO create mode 100644 drivers/staging/sep/sep_dev.h create mode 100644 drivers/staging/sep/sep_driver.c create mode 100644 drivers/staging/sep/sep_driver_api.h create mode 100644 drivers/staging/sep/sep_driver_config.h create mode 100644 drivers/staging/sep/sep_driver_hw_defs.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 49aee27b296d..1f61914a3ab8 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -119,6 +119,8 @@ source "drivers/staging/vme/Kconfig" source "drivers/staging/memrar/Kconfig" +source "drivers/staging/sep/Kconfig" + source "drivers/staging/iio/Kconfig" source "drivers/staging/zram/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 20c5641b6cd7..75c0c1ff1cf5 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_FB_UDL) += udlfb/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ +obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig new file mode 100644 index 000000000000..34f3ef5f9df8 --- /dev/null +++ b/drivers/staging/sep/Kconfig @@ -0,0 +1,11 @@ +config DX_SEP + tristate "Discretix SEP driver" + depends on PCI + default y + help + Discretix SEP driver; used for the security processor subsystem + on bard the Intel Mobile Internet Device. + + The driver's name is sep_driver. + + If unsure, select N. diff --git a/drivers/staging/sep/Makefile b/drivers/staging/sep/Makefile new file mode 100644 index 000000000000..628d5f919414 --- /dev/null +++ b/drivers/staging/sep/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_DX_SEP) := sep_driver.o + diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO new file mode 100644 index 000000000000..371ee279f327 --- /dev/null +++ b/drivers/staging/sep/TODO @@ -0,0 +1,12 @@ +Todo's so far (from Alan Cox) +- Fix firmware loading - Done 09/10 M. Allyn +- Get firmware into firmware git tree - Firmware is non open source +- Review and tidy each algorithm function - Done 09/10 M. Allyn +- Check whether it can be plugged into any of the kernel crypto API + interfaces - Crypto API 'glue' is still not ready to submit +- Do something about the magic shared memory interface and replace it + with something saner (in Linux terms) - Done 09/10 M. Allyn +- Clean up unused ioctls - Needs vendor help +- Clean up unused fields in ioctl structures - Needs vendor help +- 64 bit size to be used for all user space addresses passed + to ioctl - Done 10/10 M. Allyn diff --git a/drivers/staging/sep/sep_dev.h b/drivers/staging/sep/sep_dev.h new file mode 100644 index 000000000000..7b4993b3650d --- /dev/null +++ b/drivers/staging/sep/sep_dev.h @@ -0,0 +1,156 @@ +#ifndef __SEP_DEV_H__ +#define __SEP_DEV_H__ + +/* + * + * sep_dev.h - Security Processor Device Structures + * + * Copyright(c) 2009,2010 Intel Corporation. All rights reserved. + * Contributions(c) 2009,2010 Discretix. All rights reserved. + * + * 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; version 2 of the License. + * + * 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. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * Jayant Mangalampalli jayant.mangalampalli@intel.com + * + * CHANGES + * 2010.09.14 upgrade to Medfield + */ + +struct sep_device { + /* pointer to pci dev */ + struct pci_dev *pdev; + + /* character device file */ + struct cdev sep_cdev; + struct cdev sep_daemon_cdev; + struct cdev sep_singleton_cdev; + + /* devices (using misc dev) */ + struct miscdevice miscdev_sep; + struct miscdevice miscdev_singleton; + struct miscdevice miscdev_daemon; + + /* major / minor numbers of device */ + dev_t sep_devno; + dev_t sep_daemon_devno; + dev_t sep_singleton_devno; + + struct mutex sep_mutex; + struct mutex ioctl_mutex; + spinlock_t snd_rply_lck; + + /* flags to indicate use and lock status of sep */ + u32 pid_doing_transaction; + unsigned long in_use_flags; + + /* request daemon alread open */ + unsigned long request_daemon_open; + + /* 1 = Moorestown; 0 = Medfield */ + int mrst; + + /* address of the shared memory allocated during init for SEP driver + (coherent alloc) */ + dma_addr_t shared_bus; + size_t shared_size; + void *shared_addr; + + /* restricted access region (coherent alloc) */ + dma_addr_t rar_bus; + size_t rar_size; + void *rar_addr; + + /* Firmware regions; cache is at rar for Moorestown and + resident is at rar for Medfield */ + dma_addr_t cache_bus; + size_t cache_size; + void *cache_addr; + + dma_addr_t resident_bus; + size_t resident_size; + void *resident_addr; + + /* sep's scratchpad */ + dma_addr_t dcache_bus; + size_t dcache_size; + void *dcache_addr; + + /* Only used on Medfield */ + dma_addr_t extapp_bus; + size_t extapp_size; + void *extapp_addr; + + /* start address of the access to the SEP registers from driver */ + dma_addr_t reg_physical_addr; + dma_addr_t reg_physical_end; + void __iomem *reg_addr; + + /* wait queue head (event) of the driver */ + wait_queue_head_t event; + wait_queue_head_t event_request_daemon; + wait_queue_head_t event_mmap; + + struct sep_caller_id_entry + caller_id_table[SEP_CALLER_ID_TABLE_NUM_ENTRIES]; + + /* access flag for singleton device */ + unsigned long singleton_access_flag; + + /* transaction counter that coordinates the + transactions between SEP and HOST */ + unsigned long send_ct; + /* counter for the messages from sep */ + unsigned long reply_ct; + /* counter for the number of bytes allocated in the pool for the + current transaction */ + long data_pool_bytes_allocated; + + u32 num_of_data_allocations; + + /* number of the lli tables created in the current transaction */ + u32 num_lli_tables_created; + + /* number of data control blocks */ + u32 nr_dcb_creat; + + struct sep_dma_resource dma_res_arr[SEP_MAX_NUM_SYNC_DMA_OPS]; + +}; + +static inline void sep_write_reg(struct sep_device *dev, int reg, u32 value) +{ + void __iomem *addr = dev->reg_addr + reg; + writel(value, addr); +} + +static inline u32 sep_read_reg(struct sep_device *dev, int reg) +{ + void __iomem *addr = dev->reg_addr + reg; + return readl(addr); +} + +/* wait for SRAM write complete(indirect write */ +static inline void sep_wait_sram_write(struct sep_device *dev) +{ + u32 reg_val; + do + reg_val = sep_read_reg(dev, HW_SRAM_DATA_READY_REG_ADDR); + while (!(reg_val & 1)); +} + + +#endif diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c new file mode 100644 index 000000000000..ef36239c7b24 --- /dev/null +++ b/drivers/staging/sep/sep_driver.c @@ -0,0 +1,4152 @@ +/* + * + * sep_driver.c - Security Processor Driver main group of functions + * + * Copyright(c) 2009,2010 Intel Corporation. All rights reserved. + * Contributions(c) 2009,2010 Discretix. All rights reserved. + * + * 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; version 2 of the License. + * + * 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. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * Jayant Mangalampalli jayant.mangalampalli@intel.com + * + * CHANGES: + * + * 2009.06.26 Initial publish + * 2010.09.14 Upgrade to Medfield + * + */ +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sep_driver_hw_defs.h" +#include "sep_driver_config.h" +#include "sep_driver_api.h" +#include "sep_dev.h" + +/*---------------------------------------- + DEFINES +-----------------------------------------*/ + +#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000 + +/*-------------------------------------------- + GLOBAL variables +--------------------------------------------*/ + +/* Keep this a single static object for now to keep the conversion easy */ + +static struct sep_device *sep_dev; + +/** + * sep_load_firmware - copy firmware cache/resident + * This functions copies the cache and resident from their source + * location into destination shared memory. + * @sep: pointer to struct sep_device + */ + +static int sep_load_firmware(struct sep_device *sep) +{ + const struct firmware *fw; + char *cache_name = "cache.image.bin"; + char *res_name = "resident.image.bin"; + char *extapp_name = "extapp.image.bin"; + + int error = 0; + unsigned int work1, work2, work3; + + /* set addresses and load resident */ + sep->resident_bus = sep->rar_bus; + sep->resident_addr = sep->rar_addr; + + error = request_firmware(&fw, res_name, &sep->pdev->dev); + if (error) { + dev_warn(&sep->pdev->dev, "cant request resident fw\n"); + return error; + } + + memcpy(sep->resident_addr, (void *)fw->data, fw->size); + sep->resident_size = fw->size; + release_firmware(fw); + + dev_dbg(&sep->pdev->dev, "resident virtual is %p\n", + sep->resident_addr); + dev_dbg(&sep->pdev->dev, "residnet bus is %lx\n", + (unsigned long)sep->resident_bus); + dev_dbg(&sep->pdev->dev, "resident size is %08x\n", + sep->resident_size); + + /* set addresses for dcache (no loading needed) */ + work1 = (unsigned int)sep->resident_bus; + work2 = (unsigned int)sep->resident_size; + work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000; + sep->dcache_bus = (dma_addr_t)work3; + + work1 = (unsigned int)sep->resident_addr; + work2 = (unsigned int)sep->resident_size; + work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000; + sep->dcache_addr = (void *)work3; + + sep->dcache_size = 1024 * 128; + + /* set addresses and load cache */ + sep->cache_bus = sep->dcache_bus + sep->dcache_size; + sep->cache_addr = sep->dcache_addr + sep->dcache_size; + + error = request_firmware(&fw, cache_name, &sep->pdev->dev); + if (error) { + dev_warn(&sep->pdev->dev, "cant request cache fw\n"); + return error; + } + + memcpy(sep->cache_addr, (void *)fw->data, fw->size); + sep->cache_size = fw->size; + release_firmware(fw); + + dev_dbg(&sep->pdev->dev, "cache virtual is %p\n", + sep->cache_addr); + dev_dbg(&sep->pdev->dev, "cache bus is %08lx\n", + (unsigned long)sep->cache_bus); + dev_dbg(&sep->pdev->dev, "cache size is %08x\n", + sep->cache_size); + + /* set addresses and load extapp */ + sep->extapp_bus = sep->cache_bus + (1024 * 370); + sep->extapp_addr = sep->cache_addr + (1024 * 370); + + error = request_firmware(&fw, extapp_name, &sep->pdev->dev); + if (error) { + dev_warn(&sep->pdev->dev, "cant request extapp fw\n"); + return error; + } + + memcpy(sep->extapp_addr, (void *)fw->data, fw->size); + sep->extapp_size = fw->size; + release_firmware(fw); + + dev_dbg(&sep->pdev->dev, "extapp virtual is %p\n", + sep->extapp_addr); + dev_dbg(&sep->pdev->dev, "extapp bus is %08llx\n", + (unsigned long long)sep->extapp_bus); + dev_dbg(&sep->pdev->dev, "extapp size is %08x\n", + sep->extapp_size); + + return error; +} + +MODULE_FIRMWARE("sep/cache.image.bin"); +MODULE_FIRMWARE("sep/resident.image.bin"); +MODULE_FIRMWARE("sep/extapp.image.bin"); + +/** + * sep_dump_message - dump the message that is pending + * @sep: sep device + */ + +static void sep_dump_message(struct sep_device *sep) +{ + int count; + u32 *p = sep->shared_addr; + for (count = 0; count < 12 * 4; count += 4) + dev_dbg(&sep->pdev->dev, + "Word %d of the message is %x\n", + count, *p++); +} + +/** + * sep_map_and_alloc_shared_area - allocate shared block + * @sep: security processor + * @size: size of shared area + */ + +static int sep_map_and_alloc_shared_area(struct sep_device *sep) +{ + sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev, + sep->shared_size, + &sep->shared_bus, GFP_KERNEL); + + if (!sep->shared_addr) { + dev_warn(&sep->pdev->dev, + "shared memory dma_alloc_coherent failed\n"); + return -ENOMEM; + } + dev_dbg(&sep->pdev->dev, + "sep: shared_addr %x bytes @%p (bus %llx)\n", + sep->shared_size, sep->shared_addr, + (unsigned long long)sep->shared_bus); + return 0; +} + +/** + * sep_unmap_and_free_shared_area - free shared block + * @sep: security processor + */ +static void sep_unmap_and_free_shared_area(struct sep_device *sep) +{ + dev_dbg(&sep->pdev->dev, "shared area unmap and free\n"); + dma_free_coherent(&sep->pdev->dev, sep->shared_size, + sep->shared_addr, sep->shared_bus); +} + +/** + * sep_shared_bus_to_virt - convert bus/virt addresses + * Returns virtual address inside the shared area according + * to the bus address. + * @sep: pointer to struct sep_device + * @bus_address: address to convert + */ + +static void *sep_shared_bus_to_virt(struct sep_device *sep, + dma_addr_t bus_address) +{ + return sep->shared_addr + (bus_address - sep->shared_bus); +} + +/** + * open function for the singleton driver + * @inode_ptr struct inode * + * @file_ptr struct file * + */ + +static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) +{ + int error = 0; + + struct sep_device *sep; + + /** + * get the sep device structure and use it for the + * private_data field in filp for other methods + */ + sep = sep_dev; + + file_ptr->private_data = sep; + + dev_dbg(&sep->pdev->dev, "Singleton open for pid %d\n", + current->pid); + + dev_dbg(&sep->pdev->dev, "calling test and set for singleton 0\n"); + if (test_and_set_bit(0, &sep->singleton_access_flag)) { + error = -EBUSY; + goto end_function; + } + + dev_dbg(&sep->pdev->dev, + "sep_singleton_open end\n"); +end_function: + + return error; +} + +/** + * sep_open - device open method + * @inode: inode of sep device + * @filp: file handle to sep device + * + * Open method for the SEP device. Called when userspace opens + * the SEP device node. Must also release the memory data pool + * allocations. + * + * Returns zero on success otherwise an error code. + */ + +static int sep_open(struct inode *inode, struct file *filp) +{ + struct sep_device *sep; + + /** + * get the sep device structure and use it for the + * private_data field in filp for other methods + */ + sep = sep_dev; + filp->private_data = sep; + + dev_dbg(&sep->pdev->dev, "Open for pid %d\n", current->pid); + + /* anyone can open; locking takes place at transaction level */ + return 0; +} + +/** + * sep_singleton_release - close a SEP singleton device + * @inode: inode of SEP device + * @filp: file handle being closed + * + * Called on the final close of a SEP device. As the open protects against + * multiple simultaenous opens that means this method is called when the + * final reference to the open handle is dropped. + */ + +static int sep_singleton_release(struct inode *inode, struct file *filp) +{ + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, "Singleton release for pid %d\n", + current->pid); + + clear_bit(0, &sep->singleton_access_flag); + + return 0; +} + +/** + * sep_request_daemonopen - request daemon open method + * @inode: inode of sep device + * @filp: file handle to sep device + * + * Open method for the SEP request daemon. Called when + * request daemon in userspace opens + * the SEP device node. + * + * Returns zero on success otherwise an error code. + */ + +static int sep_request_daemon_open(struct inode *inode, struct file *filp) +{ + struct sep_device *sep; + + int error = 0; + + sep = sep_dev; + filp->private_data = sep; + + dev_dbg(&sep->pdev->dev, "Request daemon open for pid %d\n", + current->pid); + + /* There is supposed to be only one request daemon */ + dev_dbg(&sep->pdev->dev, "calling test and set for req_dmon open 0\n"); + if (test_and_set_bit(0, &sep->request_daemon_open)) { + error = -EBUSY; + goto end_function; + } + +end_function: + + return error; +} + +/** + * sep_request_daemon_release - close a SEP daemon + * @inode: inode of SEP device + * @filp: file handle being closed + * + * Called on the final close of a SEP daemon. + */ + +static int sep_request_daemon_release(struct inode *inode, struct file *filp) +{ + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, "Reques daemon release for pid %d\n", + current->pid); + + /* clear the request_daemon_open flag */ + clear_bit(0, &sep->request_daemon_open); + + return 0; +} + +/** + * This function raises interrupt to SEPm that signals that is has a + * new command from HOST + * @sep: struct sep_device * + */ +static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) +{ + int error = 0; + + unsigned long lck_flags; + + dev_dbg(&sep->pdev->dev, + "sep_req_daemon_send_reply_command_handler start\n"); + + error = 0; + + sep_dump_message(sep); + + /* counters are lockable region */ + spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); + sep->send_ct++; + sep->reply_ct++; + + /* send the interrupt to SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, + sep->send_ct); + + sep->send_ct++; + + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + + dev_dbg(&sep->pdev->dev, + "sep_req_daemon_send_reply send_ct %lx reply_ct %lx\n", + sep->send_ct, sep->reply_ct); + + dev_dbg(&sep->pdev->dev, + "sep_req_daemon_send_reply_command_handler end\n"); + + return error; +} + + +/** + * sep_free_dma_table_data_handler - handles the request + * for freeing dma table for synhronic actions + * @sep: pointere to struct sep_device + */ + +static int sep_free_dma_table_data_handler(struct sep_device *sep) +{ + /* counter */ + int count = 0; + + /* dcb counter */ + int dcb_counter = 0; + + /* pointer to the current dma_resource struct */ + struct sep_dma_resource *dma; + + dev_dbg(&sep->pdev->dev, + "sep_free_dma_table_data_handler start\n"); + + + for (dcb_counter = 0; dcb_counter < sep->nr_dcb_creat; + dcb_counter++) { + + dma = &sep->dma_res_arr[dcb_counter]; + + /* unmap and free input map array */ + if (dma->in_map_array) { + + for (count = 0; count < dma->in_num_pages; + count++) { + + dma_unmap_page(&sep->pdev->dev, + dma->in_map_array[count].dma_addr, + dma->in_map_array[count].size, + DMA_TO_DEVICE); + } + + kfree(dma->in_map_array); + } + + /* unmap output map array, DON'T free it yet */ + if (dma->out_map_array) { + for (count = 0; count < dma->out_num_pages; + count++) { + + dma_unmap_page(&sep->pdev->dev, + dma->out_map_array[count].dma_addr, + dma->out_map_array[count].size, + DMA_FROM_DEVICE); + } + + kfree(dma->out_map_array); + } + + /* free page cache for output */ + if (dma->in_page_array) { + for (count = 0; count < dma->in_num_pages; + count++) { + + flush_dcache_page(dma->in_page_array[count]); + page_cache_release(dma->in_page_array[count]); + } + + kfree(dma->in_page_array); + + } + + if (dma->out_page_array) { + for (count = 0; count < dma->out_num_pages; + count++) { + + if (!PageReserved(dma->out_page_array[count])) + SetPageDirty(dma->out_page_array[count]); + + flush_dcache_page(dma->out_page_array[count]); + page_cache_release(dma->out_page_array[count]); + } + + kfree(dma->out_page_array); + } + + /* reset all the values */ + dma->in_page_array = 0; + dma->out_page_array = 0; + dma->in_num_pages = 0; + dma->out_num_pages = 0; + dma->in_map_array = 0; + dma->out_map_array = 0; + dma->in_map_num_entries = 0; + dma->out_map_num_entries = 0; + + } + + sep->nr_dcb_creat = 0; + sep->num_lli_tables_created = 0; + + dev_dbg(&sep->pdev->dev, + "sep_free_dma_table_data_handler end\n"); + + return 0; +} + + +/** + * sep_request_daemon_mmap - maps the + * shared area to user space + * @filp: pointer to struct file + * @vma: pointer to vm_area_struct + */ +static int sep_request_daemon_mmap(struct file *filp, + struct vm_area_struct *vma) +{ + /* device */ + struct sep_device *sep = filp->private_data; + + dma_addr_t bus_address; + + int error = 0; + + dev_dbg(&sep->pdev->dev, "daemon mmap start\n"); + + if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) { + error = -EINVAL; + goto end_function; + } + + /* get physical address */ + bus_address = sep->shared_bus; + + dev_dbg(&sep->pdev->dev, + "bus_address is %08lx\n", + (unsigned long)bus_address); + + if (remap_pfn_range(vma, vma->vm_start, bus_address >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) { + + dev_warn(&sep->pdev->dev, + "remap_page_range failed\n"); + error = -EAGAIN; + goto end_function; + } + +end_function: + + dev_dbg(&sep->pdev->dev, "daemon mmap end\n"); + + return error; +} + +/** + * sep_request_daemon_poll - + * @sep: struct sep_device * for current sep device + * @filp: struct file * for open file + * @wait: poll_table * for poll + */ +static unsigned int sep_request_daemon_poll(struct file *filp, + poll_table *wait) +{ + u32 mask = 0; + + /* GPR2 register */ + u32 retval2; + + unsigned long lck_flags; + + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, + "daemon poll: start\n"); + + dev_dbg(&sep->pdev->dev, "daemon poll: calling poll wait sep_event\n"); + + poll_wait(filp, &sep->event_request_daemon, wait); + + dev_dbg(&sep->pdev->dev, "daemon poll: exit poll wait sep_event\n"); + + dev_dbg(&sep->pdev->dev, + "daemon poll: send_ct is %lx reply ct is %lx\n", + sep->send_ct, sep->reply_ct); + + spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); + /* check if the data is ready */ + if (sep->send_ct == sep->reply_ct) { + + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + + retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); + + dev_dbg(&sep->pdev->dev, + "daemon poll: data check (GPR2) is %x\n", retval2); + + /* check if PRINT request */ + if ((retval2 >> 30) & 0x1) { + + dev_dbg(&sep->pdev->dev, + "daemon poll: PRINTF request in\n"); + mask |= POLLIN; + goto end_function; + } + + /* check if NVS request */ + if (retval2 >> 31) { + + dev_dbg(&sep->pdev->dev, + "daemon poll: NVS request in\n"); + mask |= POLLPRI | POLLWRNORM; + } + } + + else { + + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + + dev_dbg(&sep->pdev->dev, + "daemon poll: no reply received; returning 0\n"); + mask = 0; + } + +end_function: + + dev_dbg(&sep->pdev->dev, + "daemon poll: exit\n"); + return mask; +} + +/** + * sep_release - close a SEP device + * @inode: inode of SEP device + * @filp: file handle being closed + * + * Called on the final close of a SEP device. + */ + +static int sep_release(struct inode *inode, struct file *filp) +{ + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, "Release for pid %d\n", current->pid); + + mutex_lock(&sep->sep_mutex); + /* is this the process that has a transaction open? + * If so, lets reset pid_doing_transaction to 0 and + * clear the in use flags, and then wake up sep_event + * so that other processes can do transactions + */ + dev_dbg(&sep->pdev->dev, "waking up event and mmap_event\n"); + if (sep->pid_doing_transaction == current->pid) { + clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags); + clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags); + sep_free_dma_table_data_handler(sep); + wake_up(&sep->event); + sep->pid_doing_transaction = 0; + } + + mutex_unlock(&sep->sep_mutex); + return 0; +} + +/** + * sep_mmap - maps the shared area to user space + * @filp: pointer to struct file + * @vma: pointer to vm_area_struct + */ +static int sep_mmap(struct file *filp, struct vm_area_struct *vma) +{ + dma_addr_t bus_addr; + struct sep_device *sep = filp->private_data; + unsigned long error = 0; + + dev_dbg(&sep->pdev->dev, "mmap start\n"); + + + dev_dbg(&sep->pdev->dev, "calling wait on event_mmap, tsetbit" + " SEP_MMAP_LOCK_BIT in_use_flags 0\n"); + /* Set the transaction busy (own the device) */ + wait_event_interruptible(sep->event, + test_and_set_bit(SEP_MMAP_LOCK_BIT, + &sep->in_use_flags) == 0); + + if (signal_pending(current)) { + error = -EINTR; + goto end_function_with_error; + } + /* + * The pid_doing_transaction indicates that this process + * now owns the facilities to performa a transaction with + * the sep. While this process is performing a transaction, + * no other process who has the sep device open can perform + * any transactions. This method allows more than one process + * to have the device open at any given time, which provides + * finer granularity for device utilization by multiple + * processes. + */ + mutex_lock(&sep->sep_mutex); + sep->pid_doing_transaction = current->pid; + mutex_unlock(&sep->sep_mutex); + + /* zero the pools and the number of data pool alocation pointers */ + sep->data_pool_bytes_allocated = 0; + sep->num_of_data_allocations = 0; + + /* + * check that the size of the mapped range is as the size of the message + * shared area + */ + if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) { + error = -EINVAL; + goto end_function_with_error; + } + + dev_dbg(&sep->pdev->dev, + "shared_addr is %p\n", sep->shared_addr); + + /* get bus address */ + bus_addr = sep->shared_bus; + + dev_dbg(&sep->pdev->dev, + "bus_address is %lx\n", (unsigned long)bus_addr); + + if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) { + dev_warn(&sep->pdev->dev, + "remap_page_range failed\n"); + error = -EAGAIN; + goto end_function_with_error; + } + + dev_dbg(&sep->pdev->dev, "mmap end\n"); + goto end_function; + +end_function_with_error: + + /* clear the bit */ + clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags); + mutex_lock(&sep->sep_mutex); + sep->pid_doing_transaction = 0; + mutex_unlock(&sep->sep_mutex); + + /* raise event for stuck contextes */ + + dev_warn(&sep->pdev->dev, "mmap error - waking up event\n"); + wake_up(&sep->event); + +end_function: + + return error; +} + +/** + * sep_poll - + * @filp: pointer to struct file + * @wait: pointer to poll_table + */ +static unsigned int sep_poll(struct file *filp, poll_table *wait) +{ + u32 mask = 0; + u32 retval = 0; + u32 retval2 = 0; + + unsigned long lck_flags; + + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, "poll: start\n"); + + /* am I the process that own the transaction? */ + mutex_lock(&sep->sep_mutex); + if (current->pid != sep->pid_doing_transaction) { + dev_warn(&sep->pdev->dev, "poll; wrong pid\n"); + mask = POLLERR; + mutex_unlock(&sep->sep_mutex); + goto end_function; + } + + mutex_unlock(&sep->sep_mutex); + + /* check if send command or send_reply were activated previously */ + if (!test_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) { + dev_warn(&sep->pdev->dev, "poll; lock bit set\n"); + mask = POLLERR; + goto end_function; + } + + /* add the event to the polling wait table */ + dev_dbg(&sep->pdev->dev, "poll: calling wait sep_event\n"); + + poll_wait(filp, &sep->event, wait); + + dev_dbg(&sep->pdev->dev, "poll: exit wait sep_event\n"); + + dev_dbg(&sep->pdev->dev, "poll: send_ct is %lx reply ct is %lx\n", + sep->send_ct, sep->reply_ct); + + /* check if error occured during poll */ + retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + + if (retval2 != 0x0) { + + dev_warn(&sep->pdev->dev, "poll; poll error %x\n", + retval2); + mask |= POLLERR; + goto end_function; + } + + spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); + + if (sep->send_ct == sep->reply_ct) { + + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); + dev_dbg(&sep->pdev->dev, "poll: data ready check (GPR2) %x\n", + retval); + + /* check if printf request */ + if ((retval >> 30) & 0x1) { + + dev_dbg(&sep->pdev->dev, "poll: sep printf request\n"); + wake_up(&sep->event_request_daemon); + goto end_function; + + } + + /* check if the this is sep reply or request */ + if (retval >> 31) { + + dev_dbg(&sep->pdev->dev, "poll: sep request\n"); + wake_up(&sep->event_request_daemon); + + } else { + + dev_dbg(&sep->pdev->dev, "poll: normal return\n"); + + /* in case it is again by send_reply_comand */ + + clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags); + + sep_dump_message(sep); + + dev_dbg(&sep->pdev->dev, + "poll; sep reply POLLIN | POLLRDNORM\n"); + + mask |= POLLIN | POLLRDNORM; + } + + } else { + + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + + dev_dbg(&sep->pdev->dev, + "poll; no reply received; returning mask of 0\n"); + mask = 0; + } + +end_function: + + dev_dbg(&sep->pdev->dev, "poll: end\n"); + return mask; +} + +/** + * sep_time_address - address in SEP memory of time + * @sep: SEP device we want the address from + * + * Return the address of the two dwords in memory used for time + * setting. + */ + +static u32 *sep_time_address(struct sep_device *sep) +{ + return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; +} + +/** + * sep_set_time - set the SEP time + * @sep: the SEP we are setting the time for + * + * Calculates time and sets it at the predefined address. + * Called with the sep mutex held. + */ +static unsigned long sep_set_time(struct sep_device *sep) +{ + struct timeval time; + u32 *time_addr; /* address of time as seen by the kernel */ + + + dev_dbg(&sep->pdev->dev, + "sep:sep_set_time start\n"); + + do_gettimeofday(&time); + + /* set value in the SYSTEM MEMORY offset */ + time_addr = sep_time_address(sep); + + time_addr[0] = SEP_TIME_VAL_TOKEN; + time_addr[1] = time.tv_sec; + + dev_dbg(&sep->pdev->dev, + "time.tv_sec is %lu\n", time.tv_sec); + dev_dbg(&sep->pdev->dev, + "time_addr is %p\n", time_addr); + dev_dbg(&sep->pdev->dev, + "sep->shared_addr is %p\n", sep->shared_addr); + + return time.tv_sec; +} + +/** + * sep_init_caller_id - initializes the caller id functionality + * @sep: pointer to struct sep_device + */ +static int sep_init_caller_id(struct sep_device *sep) +{ + /* return value */ + int ret_val; + + /* counter */ + int counter; + + struct cb_id caller_id; + + dev_dbg(&sep->pdev->dev, + "sep_init_caller_id start\n"); + + ret_val = 0; + + /* init cb_id struct */ + caller_id.idx = CN_IDX_PROC; + caller_id.val = CN_VAL_PROC; + + /** + * init caller id table + * note that locking is not needed here as this function is + * called prior to registering the device file + */ + for (counter = 0; counter < SEP_CALLER_ID_TABLE_NUM_ENTRIES; counter++) + sep->caller_id_table[counter].pid = 0; + + + /* init access flag */ + sep->singleton_access_flag = 0; + + dev_dbg(&sep->pdev->dev, + "caller id table init finished\n"); + + /* register to netlink connector */ + + if (ret_val) + dev_warn(&sep->pdev->dev, + "cn_add_callback failed %x\n", ret_val); + + dev_dbg(&sep->pdev->dev, + "sep_init_caller_id end\n"); + + return ret_val; +} + +/** + * sep_set_caller_id_handler - inserts the data into the caller id table + * note that this function does fall under the ioctl lock + * @sep: sep device + * @arg: pointer to struct caller_id_struct + */ +static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) +{ + void __user *hash; + int error; + int i; + struct caller_id_struct command_args; + + dev_dbg(&sep->pdev->dev, + "sep_set_caller_id_handler start\n"); + + error = 0; + + for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) { + if (sep->caller_id_table[i].pid == 0) + break; + } + + if (i == SEP_CALLER_ID_TABLE_NUM_ENTRIES) { + dev_warn(&sep->pdev->dev, + "no more caller id entries left\n"); + dev_warn(&sep->pdev->dev, + "maximum number is %d\n", + SEP_CALLER_ID_TABLE_NUM_ENTRIES); + + error = -EUSERS; + goto end_function; + } + + /* copy the data */ + if (copy_from_user(&command_args, (void __user *)arg, + sizeof(command_args))) { + error = -EFAULT; + goto end_function; + } + + hash = (void __user *)(unsigned long)command_args.callerIdAddress; + + if (!command_args.pid || !command_args.callerIdSizeInBytes) { + error = -EINVAL; + goto end_function; + } + + dev_dbg(&sep->pdev->dev, "pid is %x\n", command_args.pid); + dev_dbg(&sep->pdev->dev, "callerIdSizeInBytes is %x\n", + command_args.callerIdSizeInBytes); + + if (command_args.callerIdSizeInBytes > + SEP_CALLER_ID_HASH_SIZE_IN_BYTES) { + error = -EMSGSIZE; + goto end_function; + } + + sep->caller_id_table[i].pid = command_args.pid; + + if (copy_from_user(sep->caller_id_table[i].callerIdHash, + hash, command_args.callerIdSizeInBytes)) + error = -EFAULT; +end_function: + dev_dbg(&sep->pdev->dev, + "sep_set_caller_id_handler end\n"); + return error; +} + +/** + * sep_set_current_caller_id - set the caller id (if exists) to the sep + * note that this function does fall under the ioctl lock + * @sep: pointer to struct_sep + */ +static int sep_set_current_caller_id(struct sep_device *sep) +{ + int i; + + dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id start\n"); + + dev_dbg(&sep->pdev->dev, "current process is %d\n", current->pid); + + /* zero the previous value */ + memset((void *)(sep->shared_addr + + (SEP_CALLER_ID_OFFSET_BYTES)), + 0, + SEP_CALLER_ID_HASH_SIZE_IN_BYTES); + + for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) { + if (sep->caller_id_table[i].pid == current->pid) { + dev_dbg(&sep->pdev->dev, "Caller Id found\n"); + + memcpy((void *)(sep->shared_addr + + (SEP_CALLER_ID_OFFSET_BYTES)), + (void *)(sep->caller_id_table[i].callerIdHash), + SEP_CALLER_ID_HASH_SIZE_IN_BYTES); + break; + } + } + + dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id end\n"); + + return 0; +} + +/** + * sep_send_command_handler - kick off a command + * note that this function does fall under the ioctl lock + * This function raises interrupt to SEP that signals that is has a new + * command from the host + * @sep: sep being signalled + */ + +static int sep_send_command_handler(struct sep_device *sep) +{ + unsigned long lck_flags; + int error = 0; + + dev_dbg(&sep->pdev->dev, "sep_send_command_handler start\n"); + + dev_dbg(&sep->pdev->dev, "calling test and set for " + " in_use_flags SEP_SEND_MSG_LOCK_BIT 0\n"); + if (test_and_set_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) { + error = -EPROTO; + goto end_function; + } + + sep_set_time(sep); + + /* only Medfield has caller id */ + if (sep->mrst == 0) + sep_set_current_caller_id(sep); + + sep_dump_message(sep); + + /* update counter */ + spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); + sep->send_ct++; + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + + dev_dbg(&sep->pdev->dev, "sep_send_command_handler" + "send_ct %lx reply_ct %lx\n", sep->send_ct, sep->reply_ct); + + /* send interrupt to SEP */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); + +end_function: + dev_dbg(&sep->pdev->dev, "sep_send_command_handler end\n"); + return error; +} + +/** + * sep_allocate_data_pool_memory_handler - + * This function handles the allocate data pool memory request + * This function returns calculates the bus address of the + * allocated memory, and the offset of this area from the mapped address. + * Therefore, the FVOs in user space can calculate the exact virtual + * address of this allocated memory + * @sep: pointer to struct_sep + * @arg: pointer to struct alloc_struct + */ +static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, + unsigned long arg) +{ + int error = 0; + struct alloc_struct command_args; + + /* holds the allocated buffer address in the system memory pool */ + u32 *token_addr; + + dev_dbg(&sep->pdev->dev, + "sep_allocate_data_pool_memory_handler start\n"); + + if (copy_from_user(&command_args, (void __user *)arg, + sizeof(struct alloc_struct))) { + error = -EFAULT; + goto end_function; + } + + /* allocate memory */ + if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { + error = -ENOMEM; + goto end_function; + } + + dev_dbg(&sep->pdev->dev, + "bytes_allocated: %x\n", (int)sep->data_pool_bytes_allocated); + dev_dbg(&sep->pdev->dev, + "offset: %x\n", SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES); + /* set the virtual and bus address */ + command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + + sep->data_pool_bytes_allocated; + + dev_dbg(&sep->pdev->dev, + "command_args.offset: %x\n", command_args.offset); + + /* place in the shared area that is known by the sep */ + token_addr = (u32 *)(sep->shared_addr + + SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES + + (sep->num_of_data_allocations)*2*sizeof(u32)); + + dev_dbg(&sep->pdev->dev, + "allocation offset: %x\n", + SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES); + dev_dbg(&sep->pdev->dev, "data pool token addr is %p\n", token_addr); + + token_addr[0] = SEP_DATA_POOL_POINTERS_VAL_TOKEN; + token_addr[1] = (u32)sep->shared_bus + + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + + sep->data_pool_bytes_allocated; + + dev_dbg(&sep->pdev->dev, "data pool token [0] %x\n", token_addr[0]); + dev_dbg(&sep->pdev->dev, "data pool token [1] %x\n", token_addr[1]); + + /* write the memory back to the user space */ + error = copy_to_user((void *)arg, (void *)&command_args, + sizeof(struct alloc_struct)); + if (error) { + + dev_warn(&sep->pdev->dev, + "allocate data pool copy to user error\n"); + goto end_function; + } + + /* update the allocation */ + sep->data_pool_bytes_allocated += command_args.num_bytes; + sep->num_of_data_allocations += 1; + + dev_dbg(&sep->pdev->dev, "data_allocations %d\n", + sep->num_of_data_allocations); + dev_dbg(&sep->pdev->dev, "bytes allocated %d\n", + (int)sep->data_pool_bytes_allocated); + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_allocate_data_pool_memory_handler end\n"); + return error; +} + +/** + * sep_lock_kernel_pages - + * This function locks all the physical pages of the kernel virtual buffer + * and construct a basic lli array, where each entry holds the physical + * page address and the size that application data holds in this page + * This function is used only during kernel crypto mod calls from within + * the kernel (when ioctl is not used) + * @sep: pointer to struct sep_device + * @kernel_virt_addr: address of data buffer in kernel + * @data_size: size of data + * @lli_array_ptr: lli array + * @in_out_flag: input into device or output from device + */ +static int sep_lock_kernel_pages(struct sep_device *sep, + u32 kernel_virt_addr, + u32 data_size, + struct sep_lli_entry **lli_array_ptr, + int in_out_flag) + +{ + /* error */ + int error = 0; + + /* array of lli */ + struct sep_lli_entry *lli_array; + + /* map array */ + struct sep_dma_map *map_array; + + dev_dbg(&sep->pdev->dev, + "sep_lock_kernel_pages start\n"); + + dev_dbg(&sep->pdev->dev, + "kernel_virt_addr is %08x\n", kernel_virt_addr); + dev_dbg(&sep->pdev->dev, + "data_size is %x\n", data_size); + + lli_array = kmalloc(sizeof(struct sep_lli_entry), GFP_ATOMIC); + if (!lli_array) { + + error = -ENOMEM; + goto end_function; + } + + map_array = kmalloc(sizeof(struct sep_dma_map), GFP_ATOMIC); + if (!map_array) { + error = -ENOMEM; + goto end_function_with_error; + } + + map_array[0].dma_addr = + dma_map_single(&sep->pdev->dev, (void *)kernel_virt_addr, + data_size, DMA_BIDIRECTIONAL); + map_array[0].size = data_size; + + + /* + * set the start address of the first page - app data may start not at + * the beginning of the page + */ + lli_array[0].bus_address = (u32)map_array[0].dma_addr; + lli_array[0].block_size = map_array[0].size; + + dev_dbg(&sep->pdev->dev, + "lli_array[0].bus_address is %08lx," + " lli_array[0].block_size is %x\n", + (unsigned long)lli_array[0].bus_address, + lli_array[0].block_size); + + /* set the output parameters */ + if (in_out_flag == SEP_DRIVER_IN_FLAG) { + *lli_array_ptr = lli_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 1; + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = 1; + } else { + *lli_array_ptr = lli_array; + sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = 1; + sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array; + sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = 1; + } + + goto end_function; + +end_function_with_error: + + kfree(lli_array); + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_lock_kernel_pages end\n"); + + return error; +} + +/** + * sep_lock_user_pages - + * This function locks all the physical pages of the application + * virtual buffer and construct a basic lli array, where each entry + * holds the physical page address and the size that application + * data holds in this physical pages + * @sep: pointer to struct sep_device + * @app_virt_addr: user memory data buffer + * @data_size: size of data buffer + * @lli_array_ptr: lli array + * @in_out_flag: input or output to device + */ +static int sep_lock_user_pages(struct sep_device *sep, + u32 app_virt_addr, + u32 data_size, + struct sep_lli_entry **lli_array_ptr, + int in_out_flag) + +{ + /* error */ + int error; + + /* the the page of the end address of the user space buffer */ + u32 end_page; + + /* the page of the start address of the user space buffer */ + u32 start_page; + + /* the range in pages */ + u32 num_pages; + + /* array of pointers ot page */ + struct page **page_array; + + /* array of lli */ + struct sep_lli_entry *lli_array; + + /* map array */ + struct sep_dma_map *map_array; + + /* direction of the DMA mapping for locked pages */ + enum dma_data_direction dir; + + /* count */ + u32 count; + + /* result */ + int result; + + dev_dbg(&sep->pdev->dev, + "sep_lock_user_pages start\n"); + + error = 0; + + /* set start and end pages and num pages */ + end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; + start_page = app_virt_addr >> PAGE_SHIFT; + num_pages = end_page - start_page + 1; + + dev_dbg(&sep->pdev->dev, + "app_virt_addr is %x\n", app_virt_addr); + dev_dbg(&sep->pdev->dev, + "data_size is %x\n", data_size); + dev_dbg(&sep->pdev->dev, + "start_page is %x\n", start_page); + dev_dbg(&sep->pdev->dev, + "end_page is %x\n", end_page); + dev_dbg(&sep->pdev->dev, + "num_pages is %x\n", num_pages); + + dev_dbg(&sep->pdev->dev, + "starting page_array malloc\n"); + + /* allocate array of pages structure pointers */ + page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); + if (!page_array) { + error = -ENOMEM; + goto end_function; + } + + map_array = kmalloc(sizeof(struct sep_dma_map) * num_pages, GFP_ATOMIC); + if (!map_array) { + dev_warn(&sep->pdev->dev, + "kmalloc for map_array failed\n"); + error = -ENOMEM; + goto end_function_with_error1; + } + + lli_array = kmalloc(sizeof(struct sep_lli_entry) * num_pages, + GFP_ATOMIC); + + if (!lli_array) { + + dev_warn(&sep->pdev->dev, + "kmalloc for lli_array failed\n"); + error = -ENOMEM; + goto end_function_with_error2; + } + + dev_dbg(&sep->pdev->dev, + "starting get_user_pages\n"); + + /* convert the application virtual address into a set of physical */ + down_read(¤t->mm->mmap_sem); + result = get_user_pages(current, current->mm, app_virt_addr, + num_pages, + ((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1), + 0, page_array, 0); + + up_read(¤t->mm->mmap_sem); + + /* check the number of pages locked - if not all then exit with error */ + if (result != num_pages) { + + dev_warn(&sep->pdev->dev, + "not all pages locked by get_user_pages\n"); + error = -ENOMEM; + goto end_function_with_error3; + } + + dev_dbg(&sep->pdev->dev, + "get_user_pages succeeded\n"); + + /* set direction */ + if (in_out_flag == SEP_DRIVER_IN_FLAG) + dir = DMA_TO_DEVICE; + else + dir = DMA_FROM_DEVICE; + + /* + * fill the array using page array data and + * map the pages - this action + * will also flush the cache as needed + */ + for (count = 0; count < num_pages; count++) { + /* fill the map array */ + map_array[count].dma_addr = + dma_map_page(&sep->pdev->dev, page_array[count], + 0, PAGE_SIZE, /*dir*/DMA_BIDIRECTIONAL); + + map_array[count].size = PAGE_SIZE; + + /* fill the lli array entry */ + lli_array[count].bus_address = (u32)map_array[count].dma_addr; + lli_array[count].block_size = PAGE_SIZE; + + dev_warn(&sep->pdev->dev, + "lli_array[%x].bus_address is %08lx, \ + lli_array[%x].block_size is %x\n", + count, (unsigned long)lli_array[count].bus_address, + count, lli_array[count].block_size); + } + + /* check the offset for the first page */ + lli_array[0].bus_address = + lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK)); + + /* check that not all the data is in the first page only */ + if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) + lli_array[0].block_size = data_size; + else + lli_array[0].block_size = + PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); + + dev_dbg(&sep->pdev->dev, + "lli_array[0].bus_address is %08lx, \ + lli_array[0].block_size is %x\n", + (unsigned long)lli_array[count].bus_address, + lli_array[count].block_size); + + /* check the size of the last page */ + if (num_pages > 1) { + + lli_array[num_pages - 1].block_size = + (app_virt_addr + data_size) & (~PAGE_MASK); + + dev_warn(&sep->pdev->dev, + "lli_array[%x].bus_address is %08lx, \ + lli_array[%x].block_size is %x\n", + num_pages - 1, + (unsigned long)lli_array[count].bus_address, + num_pages - 1, + lli_array[count].block_size); + } + + /* set output params acording to the in_out flag */ + if (in_out_flag == SEP_DRIVER_IN_FLAG) { + *lli_array_ptr = lli_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = + num_pages; + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = + page_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = + map_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = + num_pages; + } else { + *lli_array_ptr = lli_array; + sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = + num_pages; + sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = + page_array; + sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = + map_array; + sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = + num_pages; + } + + goto end_function; + +end_function_with_error3: + + /* free lli array */ + kfree(lli_array); + +end_function_with_error2: + + kfree(map_array); + +end_function_with_error1: + + /* free page array */ + kfree(page_array); + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_lock_user_pages end\n"); + + return error; +} + +/** + * u32 sep_calculate_lli_table_max_size - + * this function calculates the size of data + * that can be inserted into the lli + * table from this array the condition is that + * either the table is full + * (all etnries are entered), or there are no more + * entries in the lli array + * @sep: pointer to struct sep_device + * @lli_in_array_ptr + * @num_array_entries + * @last_table_flag + */ +static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, + struct sep_lli_entry *lli_in_array_ptr, + u32 num_array_entries, + u32 *last_table_flag) +{ + /* table data size */ + u32 table_data_size; + + /* data size for the next table */ + u32 next_table_data_size; + + /* counter */ + u32 counter; + + table_data_size = 0; + *last_table_flag = 0; + + /* + * calculate the data in the out lli table till we fill the whole + * table or till the data has ended + */ + for (counter = 0; + (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && + (counter < num_array_entries); counter++) + table_data_size += lli_in_array_ptr[counter].block_size; + + /* + * check if we reached the last entry, + * meaning this ia the last table to build, + * and no need to check the block alignment + */ + if (counter == num_array_entries) { + + /* set the last table flag */ + *last_table_flag = 1; + goto end_function; + } + + /* + * calculate the data size of the next table. + * Stop if no entries left or + * if data size is more the DMA restriction + */ + next_table_data_size = 0; + for (; counter < num_array_entries; counter++) { + + next_table_data_size += lli_in_array_ptr[counter].block_size; + + if (next_table_data_size >= SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) + + break; + } + + /* + * check if the next table data size is less then DMA rstriction. + * if it is - recalculate the current table size, so that the next + * table data size will be adaquete for DMA + */ + if (next_table_data_size && + next_table_data_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) + + table_data_size -= (SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE - + next_table_data_size); + + dev_dbg(&sep->pdev->dev, + "table data size is %x\n", table_data_size); + +end_function: + + return table_data_size; +} + +/** + * sep_build_lli_table - + * this functions builds ont lli table from the lli_array according to + * the given size of data + * @sep: pointer to struct sep_device + * @lli_array_ptr: pointer to lli array + * @lli_table_ptr: pointer to lli table + * @num_processed_entries_ptr: pointer to number of entries + * @num_table_entries_ptr: pointer to number of tables + * @table_data_size: total data size + */ +static void sep_build_lli_table(struct sep_device *sep, + struct sep_lli_entry *lli_array_ptr, + struct sep_lli_entry *lli_table_ptr, + u32 *num_processed_entries_ptr, + u32 *num_table_entries_ptr, + u32 table_data_size) +{ + /* current table data size */ + u32 curr_table_data_size; + + /* counter of lli array entry */ + u32 array_counter; + + dev_dbg(&sep->pdev->dev, + "sep_build_lli_table start\n"); + + /* init currrent table data size and lli array entry counter */ + curr_table_data_size = 0; + array_counter = 0; + *num_table_entries_ptr = 1; + + dev_dbg(&sep->pdev->dev, + "table_data_size is %x\n", table_data_size); + + /* fill the table till table size reaches the needed amount */ + while (curr_table_data_size < table_data_size) { + /* update the number of entries in table */ + (*num_table_entries_ptr)++; + + lli_table_ptr->bus_address = + cpu_to_le32(lli_array_ptr[array_counter].bus_address); + + lli_table_ptr->block_size = + cpu_to_le32(lli_array_ptr[array_counter].block_size); + + curr_table_data_size += lli_array_ptr[array_counter].block_size; + + dev_dbg(&sep->pdev->dev, + "lli_table_ptr is %p\n", lli_table_ptr); + dev_dbg(&sep->pdev->dev, + "lli_table_ptr->bus_address is %08lx\n", + (unsigned long)lli_table_ptr->bus_address); + dev_dbg(&sep->pdev->dev, + "lli_table_ptr->block_size is %x\n", + lli_table_ptr->block_size); + + /* check for overflow of the table data */ + if (curr_table_data_size > table_data_size) { + + dev_dbg(&sep->pdev->dev, + "curr_table_data_size too large\n"); + + /* update the size of block in the table */ + lli_table_ptr->block_size -= + cpu_to_le32((curr_table_data_size - table_data_size)); + + /* update the physical address in the lli array */ + lli_array_ptr[array_counter].bus_address += + cpu_to_le32(lli_table_ptr->block_size); + + /* update the block size left in the lli array */ + lli_array_ptr[array_counter].block_size = + (curr_table_data_size - table_data_size); + + } else + + /* advance to the next entry in the lli_array */ + array_counter++; + + dev_dbg(&sep->pdev->dev, + "lli_table_ptr->bus_address is %08lx\n", + (unsigned long)lli_table_ptr->bus_address); + dev_dbg(&sep->pdev->dev, + "lli_table_ptr->block_size is %x\n", + lli_table_ptr->block_size); + + /* move to the next entry in table */ + lli_table_ptr++; + } + + /* set the info entry to default */ + lli_table_ptr->bus_address = 0xffffffff; + lli_table_ptr->block_size = 0; + + dev_dbg(&sep->pdev->dev, + "lli_table_ptr is %p\n", lli_table_ptr); + dev_dbg(&sep->pdev->dev, + "lli_table_ptr->bus_address is %08lx\n", + (unsigned long)lli_table_ptr->bus_address); + dev_dbg(&sep->pdev->dev, + "lli_table_ptr->block_size is %x\n", + lli_table_ptr->block_size); + + /* set the output parameter */ + *num_processed_entries_ptr += array_counter; + + dev_dbg(&sep->pdev->dev, + "num_processed_entries_ptr is %x\n", + *num_processed_entries_ptr); + + dev_dbg(&sep->pdev->dev, + "sep_build_lli_table end\n"); + + return; +} + +/** + * sep_shared_area_virt_to_bus - + * This functions returns the physical address inside shared area according + * to the virtual address. It can be either on the externa RAM device + * (ioremapped), or on the system RAM + * This implementation is for the external RAM + * @sep: pointer to struct sep_device + * @virt_address: virtual address to convert + */ +static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep, + void *virt_address) +{ + dev_dbg(&sep->pdev->dev, + "sh virt to phys v %08lx\n", + (unsigned long)virt_address); + dev_dbg(&sep->pdev->dev, + "sh virt to phys p %08lx\n", + (unsigned long)(sep->shared_bus + + (virt_address - sep->shared_addr))); + + return sep->shared_bus + + (size_t)(virt_address - sep->shared_addr); +} + +/** + * sep_shared_area_bus_to_virt - + * This functions returns the virtual address inside shared area + * according to the physical address. It can be either on the + * externa RAM device (ioremapped), or on the system RAM + * This implementation is for the external RAM + * @sep: pointer to struct sep_device + * @bus_address: bus address to convert + */ + +static void *sep_shared_area_bus_to_virt(struct sep_device *sep, + dma_addr_t bus_address) +{ + dev_dbg(&sep->pdev->dev, + "shared bus to virt b=%x v=%x\n", + (u32)bus_address, + (u32)(sep->shared_addr + + (size_t)(bus_address - sep->shared_bus))); + + return sep->shared_addr + + (size_t)(bus_address - sep->shared_bus); +} + +/** + * sep_debug_print_lli_tables - + * this function goes over the list of the print created tables and + * prints all the data + * @sep: pointer to struct sep_device + * @lli_table_ptr: pointer to sep_lli_entry + * @num_table_entries: number of entries + * @table_data_size: total data size + */ +static void sep_debug_print_lli_tables(struct sep_device *sep, + struct sep_lli_entry *lli_table_ptr, + unsigned long num_table_entries, + unsigned long table_data_size) +{ + unsigned long table_count = 0; + unsigned long entries_count = 0; + + dev_dbg(&sep->pdev->dev, + "sep_debug_print_lli_tables start\n"); + + table_count = 1; + while ((unsigned long) lli_table_ptr != 0xffffffff) { + dev_dbg(&sep->pdev->dev, + "lli table %08lx, table_data_size is %lu\n", + table_count, table_data_size); + dev_dbg(&sep->pdev->dev, + "num_table_entries is %lu\n", + num_table_entries); + + /* print entries of the table (without info entry) */ + for (entries_count = 0; entries_count < num_table_entries; + entries_count++, lli_table_ptr++) { + + dev_dbg(&sep->pdev->dev, + "lli_table_ptr address is %08lx\n", + (unsigned long) lli_table_ptr); + + dev_dbg(&sep->pdev->dev, + "phys address is %08lx block size is %x\n", + (unsigned long)lli_table_ptr->bus_address, + lli_table_ptr->block_size); + } + + /* point to the info entry */ + lli_table_ptr--; + + dev_dbg(&sep->pdev->dev, + "phys lli_table_ptr->block_size is %x\n", + lli_table_ptr->block_size); + + dev_dbg(&sep->pdev->dev, + "phys lli_table_ptr->physical_address is %08lu\n", + (unsigned long)lli_table_ptr->bus_address); + + + table_data_size = lli_table_ptr->block_size & 0xffffff; + num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff; + lli_table_ptr = (struct sep_lli_entry *) + (lli_table_ptr->bus_address); + + dev_dbg(&sep->pdev->dev, + "phys table_data_size is %lu num_table_entries is" + " %lu lli_table_ptr is%lu\n", table_data_size, + num_table_entries, (unsigned long)lli_table_ptr); + + if ((unsigned long)lli_table_ptr != 0xffffffff) + lli_table_ptr = (struct sep_lli_entry *) + sep_shared_bus_to_virt(sep, + (unsigned long)lli_table_ptr); + + table_count++; + } + dev_dbg(&sep->pdev->dev, + "sep_debug_print_lli_tables end\n"); +} + + +/** + * sep_prepare_empty_lli_table - + * This function creates empty lli tables when there is no data + * @sep: pointer to struct sep_device + * @lli_table_addr_ptr: pointer to lli table + * @num_entries_ptr: pointer to number of entries + * @table_data_size_ptr: point to table data size + */ +static void sep_prepare_empty_lli_table(struct sep_device *sep, + dma_addr_t *lli_table_addr_ptr, + u32 *num_entries_ptr, + u32 *table_data_size_ptr) +{ + struct sep_lli_entry *lli_table_ptr; + + dev_dbg(&sep->pdev->dev, "sep_prepare_empty_lli_table start\n"); + + /* find the area for new table */ + lli_table_ptr = + (struct sep_lli_entry *)(sep->shared_addr + + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + + sep->num_lli_tables_created * + sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + + lli_table_ptr->bus_address = 0; + lli_table_ptr->block_size = 0; + + lli_table_ptr++; + lli_table_ptr->bus_address = 0xFFFFFFFF; + lli_table_ptr->block_size = 0; + + /* set the output parameter value */ + *lli_table_addr_ptr = sep->shared_bus + + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + + sep->num_lli_tables_created * + sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + /* set the num of entries and table data size for empty table */ + *num_entries_ptr = 2; + *table_data_size_ptr = 0; + + /* update the number of created tables */ + sep->num_lli_tables_created++; + + dev_dbg(&sep->pdev->dev, "sep_prepare_empty_lli_table start\n"); + +} + +/** + * sep_prepare_input_dma_table - + * This function prepares only input DMA table for synhronic symmetric + * operations (HASH) + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device + * @sep: pointer to struct sep_device + * @data_size: + * @block_size: + * @lli_table_ptr: + * @num_entries_ptr: + * @table_data_size_ptr: + * @is_kva: set for kernel data (kernel cryptio call) + */ +static int sep_prepare_input_dma_table(struct sep_device *sep, + unsigned long app_virt_addr, + u32 data_size, + u32 block_size, + dma_addr_t *lli_table_ptr, + u32 *num_entries_ptr, + u32 *table_data_size_ptr, + bool is_kva) +{ + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry *info_entry_ptr; + + /* array of pointers ot page */ + struct sep_lli_entry *lli_array_ptr; + + /* points to the first entry to be processed in the lli_in_array */ + u32 current_entry = 0; + + /* num entries in the virtual buffer */ + u32 sep_lli_entries = 0; + + /* lli table pointer */ + struct sep_lli_entry *in_lli_table_ptr; + + /* the total data in one table */ + u32 table_data_size = 0; + + /* flag for last table */ + u32 last_table_flag = 0; + + /* number of entries in lli table */ + u32 num_entries_in_table = 0; + + /* next table address */ + u32 lli_table_alloc_addr = 0; + + /* error */ + int error = 0; + + dev_dbg(&sep->pdev->dev, + "sep_prepare_input_dma_table start\n"); + + dev_dbg(&sep->pdev->dev, + "data_size is %x\n", data_size); + dev_dbg(&sep->pdev->dev, + "block_size is %x\n", block_size); + + /* initialize the pages pointers */ + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 0; + + /* set the kernel address for first table to be allocated */ + lli_table_alloc_addr = (u32)(sep->shared_addr + + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + + sep->num_lli_tables_created * + sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + + if (data_size == 0) { + + /* special case - create meptu table - 2 entries, zero data */ + sep_prepare_empty_lli_table(sep, lli_table_ptr, + num_entries_ptr, + table_data_size_ptr); + + goto update_dcb_counter; + } + + /* check if the pages are in Kernel Virtual Address layout */ + if (is_kva == true) + + /* lock the pages in the kernel */ + error = sep_lock_kernel_pages(sep, app_virt_addr, + data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG); + + else + + /* + * lock the pages of the user buffer + * and translate them to pages + */ + error = sep_lock_user_pages(sep, app_virt_addr, + data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG); + + if (error) + goto end_function; + + dev_dbg(&sep->pdev->dev, + "output sep_in_num_pages is %x\n", + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages); + + current_entry = 0; + info_entry_ptr = 0; + + sep_lli_entries = + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages; + + /* loop till all the entries in in array are not processed */ + while (current_entry < sep_lli_entries) { + + /* set the new input and output tables */ + in_lli_table_ptr = + (struct sep_lli_entry *)lli_table_alloc_addr; + + lli_table_alloc_addr += sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + if (lli_table_alloc_addr > + ((u32)sep->shared_addr + + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) { + + error = -ENOMEM; + goto end_function_error; + + } + + /* update the number of created tables */ + sep->num_lli_tables_created++; + + /* calculate the maximum size of data for input table */ + table_data_size = sep_calculate_lli_table_max_size(sep, + &lli_array_ptr[current_entry], + (sep_lli_entries - current_entry), + &last_table_flag); + + /** + * if this is not the last table - + * then allign it to the block size + */ + if (!last_table_flag) + table_data_size = + (table_data_size / block_size) * block_size; + + dev_dbg(&sep->pdev->dev, + "output table_data_size is %x\n", + table_data_size); + + /* construct input lli table */ + sep_build_lli_table(sep, &lli_array_ptr[current_entry], + in_lli_table_ptr, + ¤t_entry, &num_entries_in_table, table_data_size); + + if (info_entry_ptr == 0) { + + /* set the output parameters to physical addresses */ + *lli_table_ptr = sep_shared_area_virt_to_bus(sep, + in_lli_table_ptr); + *num_entries_ptr = num_entries_in_table; + *table_data_size_ptr = table_data_size; + + dev_dbg(&sep->pdev->dev, + "output lli_table_in_ptr is %08lx\n", + (unsigned long)*lli_table_ptr); + + } + + else { + + /* update the info entry of the previous in table */ + info_entry_ptr->bus_address = + sep_shared_area_virt_to_bus(sep, + in_lli_table_ptr); + info_entry_ptr->block_size = + ((num_entries_in_table) << 24) | + (table_data_size); + } + + /* save the pointer to the info entry of the current tables */ + info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; + + } + + /* print input tables */ + sep_debug_print_lli_tables(sep, (struct sep_lli_entry *) + sep_shared_area_bus_to_virt(sep, *lli_table_ptr), + *num_entries_ptr, + *table_data_size_ptr); + + /* the array of the pages */ + kfree(lli_array_ptr); + +update_dcb_counter: + + /* update dcb counter */ + sep->nr_dcb_creat++; + + goto end_function; + +end_function_error: + + /* free all the allocated resources */ + kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array); + kfree(lli_array_ptr); + kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array); + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_prepare_input_dma_table end\n"); + + return error; + +} +/** + * sep_construct_dma_tables_from_lli - + * This function creates the input and output dma tables for + * symmetric operations (AES/DES) according to the block + * size from LLI arays + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device + * @sep: pointer to struct_sep + * @lli_in_array: + * @sep_in_lli_entries: + * @lli_out_array: + * @sep_out_lli_entries + * @block_size + * @lli_table_in_ptr + * @lli_table_out_ptr + * @in_num_entries_ptr + * @out_num_entries_ptr + * @table_data_size_ptr + */ +static int sep_construct_dma_tables_from_lli( + struct sep_device *sep, + struct sep_lli_entry *lli_in_array, + u32 sep_in_lli_entries, + struct sep_lli_entry *lli_out_array, + u32 sep_out_lli_entries, + u32 block_size, + dma_addr_t *lli_table_in_ptr, + dma_addr_t *lli_table_out_ptr, + u32 *in_num_entries_ptr, + u32 *out_num_entries_ptr, + u32 *table_data_size_ptr) +{ + /* points to the area where next lli table can be allocated */ + u32 lli_table_alloc_addr = 0; + + /* input lli table */ + struct sep_lli_entry *in_lli_table_ptr = 0; + + /* output lli table */ + struct sep_lli_entry *out_lli_table_ptr = 0; + + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry *info_in_entry_ptr = 0; + + /* pointer to the info entry of the table - the last entry */ + struct sep_lli_entry *info_out_entry_ptr = 0; + + /* points to the first entry to be processed in the lli_in_array */ + u32 current_in_entry = 0; + + /* points to the first entry to be processed in the lli_out_array */ + u32 current_out_entry = 0; + + /* max size of the input table */ + u32 in_table_data_size = 0; + + /* max size of the output table */ + u32 out_table_data_size = 0; + + /* flag te signifies if this is the last tables build */ + u32 last_table_flag = 0; + + /* the data size that should be in table */ + u32 table_data_size = 0; + + /* number of etnries in the input table */ + u32 num_entries_in_table = 0; + + /* number of etnries in the output table */ + u32 num_entries_out_table = 0; + + dev_dbg(&sep->pdev->dev, + "sep_construct_dma_tables_from_lli start\n"); + + /* initiate to point after the message area */ + lli_table_alloc_addr = (u32)(sep->shared_addr + + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + + (sep->num_lli_tables_created * + (sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP))); + + /* loop till all the entries in in array are not processed */ + while (current_in_entry < sep_in_lli_entries) { + + /* set the new input and output tables */ + in_lli_table_ptr = + (struct sep_lli_entry *)lli_table_alloc_addr; + + lli_table_alloc_addr += sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + /* set the first output tables */ + out_lli_table_ptr = + (struct sep_lli_entry *)lli_table_alloc_addr; + + /* check if the DMA table area limit was overrun */ + if ((lli_table_alloc_addr + sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP) > + ((u32)sep->shared_addr + + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) { + + dev_warn(&sep->pdev->dev, + "dma table limit overrun\n"); + return -ENOMEM; + } + + /* update the number of the lli tables created */ + sep->num_lli_tables_created += 2; + + lli_table_alloc_addr += sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; + + /* calculate the maximum size of data for input table */ + in_table_data_size = + sep_calculate_lli_table_max_size(sep, + &lli_in_array[current_in_entry], + (sep_in_lli_entries - current_in_entry), + &last_table_flag); + + /* calculate the maximum size of data for output table */ + out_table_data_size = + sep_calculate_lli_table_max_size(sep, + &lli_out_array[current_out_entry], + (sep_out_lli_entries - current_out_entry), + &last_table_flag); + + dev_dbg(&sep->pdev->dev, + "in_table_data_size is %x\n", + in_table_data_size); + + dev_dbg(&sep->pdev->dev, + "out_table_data_size is %x\n", + out_table_data_size); + + table_data_size = in_table_data_size; + + if (!last_table_flag) { + /* + * if this is not the last table, + * then must check where the data is smallest + * and then align it to the block size + */ + if (table_data_size > out_table_data_size) + table_data_size = out_table_data_size; + + /* + * now calculate the table size so that + * it will be module block size + */ + table_data_size = (table_data_size / block_size) * + block_size; + } + + dev_dbg(&sep->pdev->dev, + "table_data_size is %x\n", table_data_size); + + /* construct input lli table */ + sep_build_lli_table(sep, &lli_in_array[current_in_entry], + in_lli_table_ptr, + ¤t_in_entry, + &num_entries_in_table, + table_data_size); + + /* construct output lli table */ + sep_build_lli_table(sep, &lli_out_array[current_out_entry], + out_lli_table_ptr, + ¤t_out_entry, + &num_entries_out_table, + table_data_size); + + /* if info entry is null - this is the first table built */ + if (info_in_entry_ptr == 0) { + /* set the output parameters to physical addresses */ + *lli_table_in_ptr = + sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); + + *in_num_entries_ptr = num_entries_in_table; + + *lli_table_out_ptr = + sep_shared_area_virt_to_bus(sep, + out_lli_table_ptr); + + *out_num_entries_ptr = num_entries_out_table; + *table_data_size_ptr = table_data_size; + + dev_dbg(&sep->pdev->dev, + "output lli_table_in_ptr is %08lx\n", + (unsigned long)*lli_table_in_ptr); + dev_dbg(&sep->pdev->dev, + "output lli_table_out_ptr is %08lx\n", + (unsigned long)*lli_table_out_ptr); + } else { + /* update the info entry of the previous in table */ + info_in_entry_ptr->bus_address = + sep_shared_area_virt_to_bus(sep, + in_lli_table_ptr); + + info_in_entry_ptr->block_size = + ((num_entries_in_table) << 24) | + (table_data_size); + + /* update the info entry of the previous in table */ + info_out_entry_ptr->bus_address = + sep_shared_area_virt_to_bus(sep, + out_lli_table_ptr); + + info_out_entry_ptr->block_size = + ((num_entries_out_table) << 24) | + (table_data_size); + + dev_dbg(&sep->pdev->dev, + "output lli_table_in_ptr:%08lx %08x\n", + (unsigned long)info_in_entry_ptr->bus_address, + info_in_entry_ptr->block_size); + + dev_dbg(&sep->pdev->dev, + "output lli_table_out_ptr:%08lx %08x\n", + (unsigned long)info_out_entry_ptr->bus_address, + info_out_entry_ptr->block_size); + } + + /* save the pointer to the info entry of the current tables */ + info_in_entry_ptr = in_lli_table_ptr + + num_entries_in_table - 1; + info_out_entry_ptr = out_lli_table_ptr + + num_entries_out_table - 1; + + dev_dbg(&sep->pdev->dev, + "output num_entries_out_table is %x\n", + (u32)num_entries_out_table); + dev_dbg(&sep->pdev->dev, + "output info_in_entry_ptr is %lx\n", + (unsigned long)info_in_entry_ptr); + dev_dbg(&sep->pdev->dev, + "output info_out_entry_ptr is %lx\n", + (unsigned long)info_out_entry_ptr); + } + + /* print input tables */ + sep_debug_print_lli_tables(sep, + (struct sep_lli_entry *) + sep_shared_area_bus_to_virt(sep, *lli_table_in_ptr), + *in_num_entries_ptr, + *table_data_size_ptr); + + /* print output tables */ + sep_debug_print_lli_tables(sep, + (struct sep_lli_entry *) + sep_shared_area_bus_to_virt(sep, *lli_table_out_ptr), + *out_num_entries_ptr, + *table_data_size_ptr); + + dev_dbg(&sep->pdev->dev, + "sep_construct_dma_tables_from_lli end\n"); + + return 0; +} + +/** + * sep_prepare_input_output_dma_table - + * This function builds input and output DMA tables for synhronic + * symmetric operations (AES, DES, HASH). It also checks that each table + * is of the modular block size + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device + * @app_virt_in_addr: + * @app_virt_out_addr: + * @data_size: + * @block_size: + * @lli_table_in_ptr: + * @lli_table_out_ptr: + * @in_num_entries_ptr: + * @out_num_entries_ptr: + * @table_data_size_ptr: + * @is_kva: set for kernel data; used only for kernel crypto module + */ +static int sep_prepare_input_output_dma_table(struct sep_device *sep, + unsigned long app_virt_in_addr, + unsigned long app_virt_out_addr, + u32 data_size, + u32 block_size, + dma_addr_t *lli_table_in_ptr, + dma_addr_t *lli_table_out_ptr, + u32 *in_num_entries_ptr, + u32 *out_num_entries_ptr, + u32 *table_data_size_ptr, + bool is_kva) + +{ + /* array of pointers of page */ + struct sep_lli_entry *lli_in_array; + + /* array of pointers of page */ + struct sep_lli_entry *lli_out_array; + + /* error */ + int error = 0; + + dev_dbg(&sep->pdev->dev, + "sep_prepare_input_output_dma_table start\n"); + + if (data_size == 0) { + + /* prepare empty table for input and output */ + sep_prepare_empty_lli_table(sep, lli_table_in_ptr, + in_num_entries_ptr, table_data_size_ptr); + + sep_prepare_empty_lli_table(sep, lli_table_out_ptr, + out_num_entries_ptr, table_data_size_ptr); + + goto update_dcb_counter; + } + + /* initialize the pages pointers */ + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = 0; + + /* lock the pages of the buffer and translate them to pages */ + if (is_kva == true) { + error = sep_lock_kernel_pages(sep, app_virt_in_addr, + data_size, &lli_in_array, SEP_DRIVER_IN_FLAG); + + if (error) { + dev_warn(&sep->pdev->dev, + "lock kernel for in failed\n"); + goto end_function; + } + + error = sep_lock_kernel_pages(sep, app_virt_out_addr, + data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG); + + if (error) { + dev_warn(&sep->pdev->dev, + "lock kernel for out failed\n"); + goto end_function; + } + } + + else { + error = sep_lock_user_pages(sep, app_virt_in_addr, + data_size, &lli_in_array, SEP_DRIVER_IN_FLAG); + if (error) { + dev_warn(&sep->pdev->dev, "sep_lock_user_pages for " + "input virtual buffer failed\n"); + goto end_function; + } + + error = sep_lock_user_pages(sep, app_virt_out_addr, + data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG); + + if (error) { + dev_warn(&sep->pdev->dev, "sep_lock_user_pages for " + "output virtual buffer failed\n"); + goto end_function_free_lli_in; + } + } + + dev_dbg(&sep->pdev->dev, + "sep_in_num_pages is %x\n", + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages); + dev_dbg(&sep->pdev->dev, + "sep_out_num_pages is %x\n", + sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages); + dev_dbg(&sep->pdev->dev, + "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + + /* call the fucntion that creates table from the lli arrays */ + error = sep_construct_dma_tables_from_lli(sep, lli_in_array, + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages, + lli_out_array, + sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages, + block_size, lli_table_in_ptr, lli_table_out_ptr, + in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr); + + if (error) { + dev_warn(&sep->pdev->dev, + "sep_construct_dma_tables_from_lli failed\n"); + goto end_function_with_error; + } + + kfree(lli_out_array); + kfree(lli_in_array); + +update_dcb_counter: + + /* update dcb counter */ + sep->nr_dcb_creat++; + + /* fall through - free the lli entry arrays */ + dev_dbg(&sep->pdev->dev, + "in_num_entries_ptr is %08x\n", *in_num_entries_ptr); + dev_dbg(&sep->pdev->dev, + "out_num_entries_ptr is %08x\n", *out_num_entries_ptr); + dev_dbg(&sep->pdev->dev, + "table_data_size_ptr is %08x\n", *table_data_size_ptr); + + goto end_function; + +end_function_with_error: + + kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_map_array); + kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_page_array); + kfree(lli_out_array); + + +end_function_free_lli_in: + + kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array); + kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array); + kfree(lli_in_array); + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_prepare_input_output_dma_table" + " end result = %d\n", error); + + return error; + +} + +/** + * sep_prepare_input_output_dma_table_in_dcb - + * This function prepares the linked dma tables and puts the + * address for the linked list of tables inta a dcb (data control + * block) the address of which is known by the sep hardware + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device + * @app_in_address: unsigned long; for data buffer in (user space) + * @app_out_address: unsigned long; for data buffer out (user space) + * @data_in_size: u32; for size of data + * @block_size: u32; for block size + * @tail_block_size: u32; for size of tail block + * @isapplet: bool; to indicate external app + * @is_kva: bool; kernel buffer; only used for kernel crypto module + */ +static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, + u32 app_in_address, + u32 app_out_address, + u32 data_in_size, + u32 block_size, + u32 tail_block_size, + bool isapplet, + bool is_kva) +{ + /* error */ + int error = 0; + + /* size of tail */ + u32 tail_size = 0; + + /* address of the created dcb table */ + struct sep_dcblock *dcb_table_ptr = 0; + + /* the physical address of the first input DMA table */ + dma_addr_t in_first_mlli_address = 0; + + /* number of entries in the first input DMA table */ + u32 in_first_num_entries = 0; + + /* the physical address of the first output DMA table */ + dma_addr_t out_first_mlli_address = 0; + + /* number of entries in the first output DMA table */ + u32 out_first_num_entries = 0; + + /* data in the first input/output table */ + u32 first_data_size = 0; + + dev_dbg(&sep->pdev->dev, + "prepare_input_output_dma_table_in_dcb start\n"); + + if (sep->nr_dcb_creat == SEP_MAX_NUM_SYNC_DMA_OPS) { + /*No more DCBS to allocate*/ + dev_warn(&sep->pdev->dev, "no more dcb's available\n"); + error = -ENOSPC; + goto end_function; + } + + /* allocate new DCB */ + dcb_table_ptr = (struct sep_dcblock *)(sep->shared_addr + + SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES + + (sep->nr_dcb_creat * sizeof(struct sep_dcblock))); + + /* set the default values in the dcb */ + dcb_table_ptr->input_mlli_address = 0; + dcb_table_ptr->input_mlli_num_entries = 0; + dcb_table_ptr->input_mlli_data_size = 0; + dcb_table_ptr->output_mlli_address = 0; + dcb_table_ptr->output_mlli_num_entries = 0; + dcb_table_ptr->output_mlli_data_size = 0; + dcb_table_ptr->tail_data_size = 0; + dcb_table_ptr->out_vr_tail_pt = 0; + + if (isapplet == true) { + tail_size = data_in_size % block_size; + + if (tail_size) { + + if (data_in_size < tail_block_size) { + dev_warn(&sep->pdev->dev, + "data in size smaller than tail" + " block size\n"); + error = -ENOSPC; + goto end_function; + } + + if (tail_block_size) + /* + * case the tail size should be + * bigger than the real block size + */ + tail_size = tail_block_size + + ((data_in_size - + tail_block_size) % block_size); + } + + /* check if there is enough data for dma operation */ + if (data_in_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) { + if (is_kva == true) { + memcpy(dcb_table_ptr->tail_data, + (void *)app_in_address, data_in_size); + } + + else { + if (copy_from_user(dcb_table_ptr->tail_data, + (void __user *)app_in_address, + data_in_size)) { + error = -EFAULT; + goto end_function; + } + } + + dcb_table_ptr->tail_data_size = data_in_size; + + /* set the output user-space address for mem2mem op */ + if (app_out_address) + dcb_table_ptr->out_vr_tail_pt = + (u32)app_out_address; + + /* + * Update both data length parameters in order to avoid + * second data copy and allow building of empty mlli + * tables + */ + tail_size = 0x0; + data_in_size = 0x0; + } + + if (tail_size) { + if (is_kva == true) { + memcpy(dcb_table_ptr->tail_data, + (void *)(app_in_address + data_in_size - + tail_size), tail_size); + } + + else { + /* we have tail data - copy it to dcb */ + if (copy_from_user(dcb_table_ptr->tail_data, + (void *)(app_in_address + + data_in_size - tail_size), tail_size)) { + error = -EFAULT; + goto end_function; + } + } + + if (app_out_address) + /* + * Caclulate the output address + * according to tail data size + */ + dcb_table_ptr->out_vr_tail_pt = + app_out_address + data_in_size + - tail_size; + + /*save the real tail data size*/ + dcb_table_ptr->tail_data_size = tail_size; + /* + * Update the data size without the tail + * data size AKA data for the dma + */ + data_in_size = (data_in_size - tail_size); + } + } + + /* check if we need to build only input table or input/output */ + if (app_out_address) { + /* prepare input/output tables */ + error = sep_prepare_input_output_dma_table(sep, + app_in_address, + app_out_address, + data_in_size, + block_size, + &in_first_mlli_address, + &out_first_mlli_address, + &in_first_num_entries, + &out_first_num_entries, + &first_data_size, + is_kva); + } + + else { + /* prepare input tables */ + error = sep_prepare_input_dma_table(sep, + app_in_address, + data_in_size, + block_size, + &in_first_mlli_address, + &in_first_num_entries, + &first_data_size, + is_kva); + } + + if (error) { + dev_warn(&sep->pdev->dev, "prepare dma table call failed" + " from prepare dcb call\n"); + goto end_function; + } + + /* set the dcb values */ + dcb_table_ptr->input_mlli_address = in_first_mlli_address; + dcb_table_ptr->input_mlli_num_entries = in_first_num_entries; + dcb_table_ptr->input_mlli_data_size = first_data_size; + dcb_table_ptr->output_mlli_address = out_first_mlli_address; + dcb_table_ptr->output_mlli_num_entries = out_first_num_entries; + dcb_table_ptr->output_mlli_data_size = first_data_size; + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_prepare_input_output_dma_table_in_dcb end\n"); + return error; + +} + + +/** + * sep_create_sync_dma_tables_handler - + * this function handles tha request for creation of the DMA table + * for the synchronic symmetric operations (AES,DES) + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device + * @sep: pointer to struct sep_device + * @arg: pointer to struct bld_syn_tab_struct +*/ +static int sep_create_sync_dma_tables_handler(struct sep_device *sep, + unsigned long arg) +{ + int error = 0; + + /* command arguments */ + struct bld_syn_tab_struct command_args; + + dev_dbg(&sep->pdev->dev, + "sep_create_sync_dma_tables_handler start\n"); + + if (copy_from_user(&command_args, (void __user *)arg, + sizeof(struct bld_syn_tab_struct))) { + error = -EFAULT; + dev_warn(&sep->pdev->dev, "create dma tables;" + " copy_from_user fails\n"); + goto end_function; + } + + dev_dbg(&sep->pdev->dev, + "app_in_address is %08llx\n", command_args.app_in_address); + dev_dbg(&sep->pdev->dev, + "app_out_address is %08llx\n", command_args.app_out_address); + dev_dbg(&sep->pdev->dev, + "data_size is %u\n", command_args.data_in_size); + dev_dbg(&sep->pdev->dev, + "block_size is %u\n", command_args.block_size); + + /* validate user parameters */ + if (!command_args.app_in_address) { + + dev_warn(&sep->pdev->dev, + "params validation error\n"); + + error = -EINVAL; + goto end_function; + } + + error = sep_prepare_input_output_dma_table_in_dcb(sep, + command_args.app_in_address, + command_args.app_out_address, + command_args.data_in_size, + command_args.block_size, + 0x0, + false, + false); + +end_function: + + dev_dbg(&sep->pdev->dev, "sep_create_sync_dma_tables_handler end\n"); + return error; +} + +/** + * sep_free_dma_tables_and_dcb - + * This function frees the dma tables and dcb block + * @sep: pointer to struct sep_device + * @isapplet: indicates external application (used for kernel access) + * @is_kva: indicates kernel addresses (only used for kernel crypto) + */ +static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, + bool is_kva) +{ + + int i = 0; + int error = 0; + int error_temp = 0; + + struct sep_dcblock *dcb_table_ptr; + + dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb start\n"); + + if (isapplet == true) { + + /* set pointer to first dcb table */ + dcb_table_ptr = (struct sep_dcblock *) + (sep->shared_addr + + SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES); + + /* go over each dcb and see if tail pointer must be updated */ + for (i = 0; i < sep->nr_dcb_creat; i++, dcb_table_ptr++) { + + if (dcb_table_ptr->out_vr_tail_pt) { + + if (is_kva == true) { + memcpy((void *)dcb_table_ptr->out_vr_tail_pt, + dcb_table_ptr->tail_data, + dcb_table_ptr->tail_data_size); + } + + else { + error_temp = copy_to_user( + (void *)dcb_table_ptr->out_vr_tail_pt, + dcb_table_ptr->tail_data, + dcb_table_ptr->tail_data_size); + } + + if (error_temp) { + /* release the dma resource */ + error = error_temp; + } + } + } + } + + /* free the output pages, if any */ + sep_free_dma_table_data_handler(sep); + + dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb end\n"); + return error; +} + +/** + * sep_get_static_pool_addr_handler - + * this function sets the bus and virtual addresses of the static pool + * and returns the virtual address + * @sep: pointer to struct sep_device + * @arg: parameters from user space application + */ +static int sep_get_static_pool_addr_handler(struct sep_device *sep, + unsigned long arg) +{ + struct stat_pool_addr_struct command_args; + + u32 *static_pool_addr = 0; + + unsigned long addr_hold; + + dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler start\n"); + + static_pool_addr = (u32 *)(sep->shared_addr + + SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES); + + static_pool_addr[0] = SEP_STATIC_POOL_VAL_TOKEN; + static_pool_addr[1] = sep->shared_bus + + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; + + addr_hold = (unsigned long) + (sep->shared_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES); + command_args.static_virt_address = (aligned_u64)addr_hold; + + dev_dbg(&sep->pdev->dev, "static pool: physical %x virtual %x\n", + (u32)static_pool_addr[1], + (u32)command_args.static_virt_address); + + /* send the parameters to user application */ + if (copy_to_user((void __user *) arg, &command_args, + sizeof(struct stat_pool_addr_struct))) + return -EFAULT; + + dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler end\n"); + + return 0; +} + +/** + * sep_start_handler - + * This function starts the sep device + * @sep: pointer to struct sep_device + */ +static int sep_start_handler(struct sep_device *sep) +{ + unsigned long reg_val; + unsigned long error = 0; + + dev_dbg(&sep->pdev->dev, "sep_start_handler start\n"); + + /* wait in polling for message from SEP */ + do + reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + while (!reg_val); + + /* check the value */ + if (reg_val == 0x1) + /* fatal error - read error status from GPRO */ + error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); + dev_dbg(&sep->pdev->dev, "sep_start_handler end\n"); + return error; +} + +/** + * ep_check_sum_calc - + * This function performs a checsum for messages that are sent + * to the sep + * @data: + * @length: + */ +static u32 sep_check_sum_calc(u8 *data, u32 length) +{ + u32 sum = 0; + u16 *Tdata = (u16 *)data; + + while (length > 1) { + /* This is the inner loop */ + sum += *Tdata++; + length -= 2; + } + + /* Add left-over byte, if any */ + if (length > 0) + sum += *(u8 *)Tdata; + + /* Fold 32-bit sum to 16 bits */ + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum & 0xFFFF; +} + +/** + * sep_init_handler - + * this function handles the request for SEP initialization + * Note that this will go away for Medfield once the SCU + * SEP initialization is complete + * Also note that the message to the sep has components + * from user space as well as components written by the driver + * This is becuase the portions of the message that partain to + * physical addresses must be set by the driver after the message + * leaves custody of the user space application for security + * reasons. + * @sep: pointer to struct sep_device + * @arg: parameters from user space application + */ +static int sep_init_handler(struct sep_device *sep, unsigned long arg) +{ + u32 message_buff[14]; + u32 counter; + int error = 0; + u32 reg_val; + dma_addr_t new_base_addr; + unsigned long addr_hold; + struct init_struct command_args; + + dev_dbg(&sep->pdev->dev, "sep_init_handler start\n"); + error = 0; + + /* make sure that we have not initialized already */ + reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + + if (reg_val != 0x2) { + error = SEP_ALREADY_INITIALIZED_ERR; + dev_warn(&sep->pdev->dev, + "init; device already initialized\n"); + goto end_function; + } + + /* only root can initialize */ + if (!capable(CAP_SYS_ADMIN)) { + dev_warn(&sep->pdev->dev, + "init; only root can init\n"); + error = -EACCES; + goto end_function; + } + + /* copy in the parameters */ + error = copy_from_user(&command_args, (void __user *)arg, + sizeof(struct init_struct)); + + if (error) { + dev_warn(&sep->pdev->dev, + "init; copy_from_user failed %x\n", error); + goto end_function; + } + + /* validate parameters */ + if (!command_args.message_addr || !command_args.sep_sram_addr || + command_args.message_size_in_words > 14) { + + dev_warn(&sep->pdev->dev, + "init; parameter error\n"); + error = -EINVAL; + goto end_function; + } + + /* copy in the sep init message */ + addr_hold = (unsigned long)command_args.message_addr; + error = copy_from_user(message_buff, + (void __user *)addr_hold, + command_args.message_size_in_words*sizeof(u32)); + + if (error) { + + dev_warn(&sep->pdev->dev, + "init; copy sep init message failed %x\n", error); + goto end_function; + } + + /* load resident, cache, and extapp firmware */ + error = sep_load_firmware(sep); + + if (error) { + + dev_warn(&sep->pdev->dev, + "init; copy sep init message failed %x\n", error); + goto end_function; + } + + /* compute the base address */ + new_base_addr = sep->shared_bus; + + if (sep->resident_bus < new_base_addr) + new_base_addr = sep->resident_bus; + + if (sep->cache_bus < new_base_addr) + new_base_addr = sep->cache_bus; + + if (sep->dcache_bus < new_base_addr) + new_base_addr = sep->dcache_bus; + + /* put physical addresses in sep message */ + message_buff[3] = (u32)new_base_addr; + message_buff[4] = (u32)sep->shared_bus; + message_buff[6] = (u32)sep->resident_bus; + message_buff[7] = (u32)sep->cache_bus; + message_buff[8] = (u32)sep->dcache_bus; + + message_buff[command_args.message_size_in_words - 1] = 0x0; + message_buff[command_args.message_size_in_words - 1] = + sep_check_sum_calc((u8 *)message_buff, + command_args.message_size_in_words*sizeof(u32)); + + /* debug print of message */ + for (counter = 0; counter < command_args.message_size_in_words; + counter++) + + dev_dbg(&sep->pdev->dev, + "init; sep message word %d is %x\n", + counter, message_buff[counter]); + + /* tell the sep the sram address */ + sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, command_args.sep_sram_addr); + + /* push the message to the sep */ + for (counter = 0; counter < command_args.message_size_in_words; + counter++) { + + sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, + message_buff[counter]); + + sep_wait_sram_write(sep); + } + + /* signal sep that message is ready and to init */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1); + + /* wait for acknowledge */ + dev_dbg(&sep->pdev->dev, "init; waiting for msg response\n"); + + do + reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + while (!(reg_val & 0xFFFFFFFD)); + + if (reg_val == 0x1) { + + dev_warn(&sep->pdev->dev, "init; device int failed\n"); + error = sep_read_reg(sep, 0x8060); + dev_warn(&sep->pdev->dev, "init; sw monitor is %x\n", error); + error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); + dev_warn(&sep->pdev->dev, "init; error is %x\n", error); + goto end_function; + } + + dev_dbg(&sep->pdev->dev, "init; end CC INIT, reg_val is %x\n", + reg_val); + + /* signal sep to zero the GPR3 */ + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x10); + + /* wait for response */ + dev_dbg(&sep->pdev->dev, "init; waiting for zero set response\n"); + + do + reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); + while (reg_val != 0); + + +end_function: + dev_dbg(&sep->pdev->dev, "init is done\n"); + return error; +} + +/** + * sep_end_transaction_handler - + * This API handles the end transaction request + * @sep: pointer to struct sep_device + */ +static int sep_end_transaction_handler(struct sep_device *sep) +{ + dev_dbg(&sep->pdev->dev, "sep_end_transaction_handler start\n"); + + /* clear the data pool pointers Token */ + memset((void *)(sep->shared_addr + + SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES), + 0, sep->num_of_data_allocations*2*sizeof(u32)); + + /* check that all the dma resources were freed */ + sep_free_dma_table_data_handler(sep); + + clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags); + + /* + * we are now through with the transaction. Let's + * allow other processes who have the device open + * to perform transactions + */ + mutex_lock(&sep->sep_mutex); + sep->pid_doing_transaction = 0; + mutex_unlock(&sep->sep_mutex); + /* raise event for stuck contextes */ + wake_up(&sep->event); + + dev_dbg(&sep->pdev->dev, "waking up event\n"); + dev_dbg(&sep->pdev->dev, "sep_end_transaction_handler end\n"); + + return 0; +} + +/** + * sep_prepare_dcb_handler - + * This function will retrieve the RAR buffer physical addresses, type + * & size corresponding to the RAR handles provided in the buffers vector. + * @sep: pointer to struct sep_device + * @arg: pointer to user parameters + */ + +static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg) +{ + /* error */ + int error = 0; + + /* command arguments */ + struct build_dcb_struct command_args; + + dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler start\n"); + + /* get the command arguments */ + if (copy_from_user(&command_args, (void __user *)arg, + sizeof(struct build_dcb_struct))) { + error = -EFAULT; + goto end_function; + } + + dev_dbg(&sep->pdev->dev, + "app_in_address is %08llx\n", command_args.app_in_address); + dev_dbg(&sep->pdev->dev, + "app_out_address is %08llx\n", command_args.app_out_address); + dev_dbg(&sep->pdev->dev, + "data_size is %x\n", command_args.data_in_size); + dev_dbg(&sep->pdev->dev, + "block_size is %x\n", command_args.block_size); + dev_dbg(&sep->pdev->dev, + "tail block_size is %x\n", command_args.tail_block_size); + + error = sep_prepare_input_output_dma_table_in_dcb(sep, + command_args.app_in_address, command_args.app_out_address, + command_args.data_in_size, command_args.block_size, + command_args.tail_block_size, true, false); + +end_function: + + dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler end\n"); + return error; + +} + +/** + * sep_free_dcb_handler - + * this function frees the DCB resources + * and updates the needed user-space buffers + * @sep: pointer to struct sep_device + */ +static int sep_free_dcb_handler(struct sep_device *sep) +{ + int error ; + + dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler start\n"); + dev_dbg(&sep->pdev->dev, "num of DCBs %x\n", sep->nr_dcb_creat); + + error = sep_free_dma_tables_and_dcb(sep, false, false); + + dev_dbg(&sep->pdev->dev, "sep_free_dcb_handler end\n"); + return error; +} + +/** + * sep_rar_prepare_output_msg_handler - + * This function will retrieve the RAR buffer physical addresses, type + * & size corresponding to the RAR handles provided in the buffers vector. + * @sep: pointer to struct sep_device + * @arg: pointer to user parameters + */ + +static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, + unsigned long arg) +{ + /* error return code */ + int error = 0; + + /* command args */ + struct rar_hndl_to_bus_struct command_args; + struct RAR_buffer rar_buf; + + /* bus address */ + dma_addr_t rar_bus = 0; + + /* holds the RAR address in the system memory offset */ + u32 *rar_addr; + + dev_dbg(&sep->pdev->dev, + "sep_rar_prepare_output_msg_handler start\n"); + + /* copy the data */ + if (copy_from_user(&command_args, + (void __user *)arg, + sizeof(command_args))) { + error = -EFAULT; + goto end_function; + } + + /* call to translation function only if user handle is not NULL */ + if (command_args.rar_handle) { + + memset(&rar_buf, 0, sizeof(rar_buf)); + rar_buf.info.handle = (u32)command_args.rar_handle; + + if (rar_handle_to_bus(&rar_buf, 1) != 1) { + dev_dbg(&sep->pdev->dev, + "rar_handle_to_bus failure\n"); + error = -EFAULT; + goto end_function; + } + + rar_bus = rar_buf.bus_address; + } + + dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", + (u32)rar_bus); + + /* set value in the SYSTEM MEMORY offset */ + rar_addr = (u32 *)(sep->shared_addr + + SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES); + + /* copy the physical address to the System Area for the sep */ + rar_addr[0] = SEP_RAR_VAL_TOKEN; + rar_addr[1] = rar_bus; + +end_function: + + dev_dbg(&sep->pdev->dev, + "sep_rar_prepare_output_msg_handler start\n"); + + return error; +} + +/** + * sep_realloc_ext_cache_handler - + * This function tells the sep where the extapp is located + * @sep: pointer to struct sep_device + * @arg: pointer to user parameters + */ +static int sep_realloc_ext_cache_handler(struct sep_device *sep, + unsigned long arg) +{ + /* holds the new ext cache address in the system memory offset */ + u32 *system_addr; + + /* set value in the SYSTEM MEMORY offset */ + system_addr = (u32 *)(sep->shared_addr + + SEP_DRIVER_SYSTEM_EXT_CACHE_ADDR_OFFSET_IN_BYTES); + + /* copy the physical address to the System Area for the sep */ + + system_addr[0] = SEP_EXT_CACHE_ADDR_VAL_TOKEN; + dev_dbg(&sep->pdev->dev, + "ext cache init; system addr 0 is %x\n", system_addr[0]); + system_addr[1] = sep->extapp_bus; + dev_dbg(&sep->pdev->dev, + "ext cache init; system addr 1 is %x\n", system_addr[1]); + + return 0; +} + +/** + * sep_ioctl - ioctl api + * @filp: pointer to struct file + * @cmd: command + * @arg: pointer to argument structure + */ +static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int error = 0; + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, "ioctl start\n"); + + dev_dbg(&sep->pdev->dev, "cmd is %x\n", cmd); + dev_dbg(&sep->pdev->dev, + "SEP_IOCSENDSEPCOMMAND is %x\n", SEP_IOCSENDSEPCOMMAND); + dev_dbg(&sep->pdev->dev, + "SEP_IOCALLOCDATAPOLL is %x\n", SEP_IOCALLOCDATAPOLL); + dev_dbg(&sep->pdev->dev, + "SEP_IOCCREATESYMDMATABLE is %x\n", SEP_IOCCREATESYMDMATABLE); + dev_dbg(&sep->pdev->dev, + "SEP_IOCFREEDMATABLEDATA is %x\n", SEP_IOCFREEDMATABLEDATA); + dev_dbg(&sep->pdev->dev, + "SEP_IOCSEPSTART is %x\n", SEP_IOCSEPSTART); + dev_dbg(&sep->pdev->dev, + "SEP_IOCSEPINIT is %x\n", SEP_IOCSEPINIT); + dev_dbg(&sep->pdev->dev, + "SEP_IOCGETSTATICPOOLADDR is %x\n", SEP_IOCGETSTATICPOOLADDR); + dev_dbg(&sep->pdev->dev, + "SEP_IOCENDTRANSACTION is %x\n", SEP_IOCENDTRANSACTION); + dev_dbg(&sep->pdev->dev, + "SEP_IOCREALLOCEXTCACHE is %x\n", SEP_IOCREALLOCEXTCACHE); + dev_dbg(&sep->pdev->dev, + "SEP_IOCRARPREPAREMESSAGE is %x\n", SEP_IOCRARPREPAREMESSAGE); + dev_dbg(&sep->pdev->dev, + "SEP_IOCPREPAREDCB is %x\n", SEP_IOCPREPAREDCB); + dev_dbg(&sep->pdev->dev, + "SEP_IOCFREEDCB is %x\n", SEP_IOCFREEDCB); + + /* make sure we own this device */ + mutex_lock(&sep->sep_mutex); + if ((current->pid != sep->pid_doing_transaction) && + (sep->pid_doing_transaction != 0)) { + + dev_dbg(&sep->pdev->dev, "ioctl pid is not owner\n"); + mutex_unlock(&sep->sep_mutex); + error = -EACCES; + goto end_function; + } + + mutex_unlock(&sep->sep_mutex); + + /* check that the command is for sep device */ + if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { + error = -ENOTTY; + goto end_function; + } + + /* lock to prevent the daemon to interfere with operation */ + mutex_lock(&sep->ioctl_mutex); + + switch (cmd) { + case SEP_IOCSENDSEPCOMMAND: + /* send command to SEP */ + error = sep_send_command_handler(sep); + break; + case SEP_IOCALLOCDATAPOLL: + /* allocate data pool */ + error = sep_allocate_data_pool_memory_handler(sep, arg); + break; + case SEP_IOCCREATESYMDMATABLE: + /* create dma table for synhronic operation */ + error = sep_create_sync_dma_tables_handler(sep, arg); + break; + case SEP_IOCFREEDMATABLEDATA: + /* free the pages */ + error = sep_free_dma_table_data_handler(sep); + break; + case SEP_IOCSEPSTART: + /* start command to sep */ + if (sep->pdev->revision == 0) /* only for old chip */ + error = sep_start_handler(sep); + else + error = -EPERM; /* not permitted on new chip */ + break; + case SEP_IOCSEPINIT: + /* init command to sep */ + if (sep->pdev->revision == 0) /* only for old chip */ + error = sep_init_handler(sep, arg); + else + error = -EPERM; /* not permitted on new chip */ + break; + case SEP_IOCGETSTATICPOOLADDR: + /* get the physical and virtual addresses of the static pool */ + error = sep_get_static_pool_addr_handler(sep, arg); + break; + case SEP_IOCENDTRANSACTION: + error = sep_end_transaction_handler(sep); + break; + case SEP_IOCREALLOCEXTCACHE: + if (sep->mrst) + error = -ENODEV; + if (sep->pdev->revision == 0) /* only for old chip */ + error = sep_realloc_ext_cache_handler(sep, arg); + else + error = -EPERM; /* not permitted on new chip */ + break; + case SEP_IOCRARPREPAREMESSAGE: + error = sep_rar_prepare_output_msg_handler(sep, arg); + break; + case SEP_IOCPREPAREDCB: + error = sep_prepare_dcb_handler(sep, arg); + break; + case SEP_IOCFREEDCB: + error = sep_free_dcb_handler(sep); + break; + default: + dev_warn(&sep->pdev->dev, "invalid ioctl %x\n", cmd); + error = -ENOTTY; + break; + } + + mutex_unlock(&sep->ioctl_mutex); + +end_function: + + dev_dbg(&sep->pdev->dev, "ioctl end\n"); + return error; +} + +/** + * sep_singleton_ioctl - ioctl api for singleton interface + * @filp: pointer to struct file + * @cmd: command + * @arg: pointer to argument structure + */ +static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg) +{ + + /* error */ + long error; + struct sep_device *sep = filp->private_data; + + error = 0; + + dev_dbg(&sep->pdev->dev, + "singleton_ioctl start\n"); + + dev_dbg(&sep->pdev->dev, + "cmd is %x\n", cmd); + + /* check that the command is for sep device */ + if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { + error = -ENOTTY; + goto end_function; + } + + /* make sure we own this device */ + mutex_lock(&sep->sep_mutex); + if ((current->pid != sep->pid_doing_transaction) && + (sep->pid_doing_transaction != 0)) { + + dev_dbg(&sep->pdev->dev, "singleton ioctl pid is not owner\n"); + mutex_unlock(&sep->sep_mutex); + error = -EACCES; + goto end_function; + } + + mutex_unlock(&sep->sep_mutex); + + switch (cmd) { + + case SEP_IOCTLSETCALLERID: + mutex_lock(&sep->ioctl_mutex); + error = sep_set_caller_id_handler(sep, arg); + mutex_unlock(&sep->ioctl_mutex); + break; + + default: + error = sep_ioctl(filp, cmd, arg); + break; + + } + +end_function: + + dev_dbg(&sep->pdev->dev, "singleton ioctl end\n"); + return error; +} + +/** + * sep_request_daemon_ioctl - ioctl for daemon + * @filp: pointer to struct file + * @cmd: command + * @arg: pointer to argument structure + * Called by the request daemon to perform ioctls on the daemon device + */ + +static long sep_request_daemon_ioctl(struct file *filp, u32 cmd, + unsigned long arg) +{ + + long error; + + struct sep_device *sep = filp->private_data; + + dev_dbg(&sep->pdev->dev, + "daemon ioctl: start\n"); + + dev_dbg(&sep->pdev->dev, + "daemon ioctl: cmd is %x\n", cmd); + + /* check that the command is for sep device */ + if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { + error = -ENOTTY; + goto end_function; + } + + /* only one process can access ioctl at any given time */ + mutex_lock(&sep->ioctl_mutex); + + switch (cmd) { + case SEP_IOCSENDSEPRPLYCOMMAND: + + /* send reply command to SEP */ + error = sep_req_daemon_send_reply_command_handler(sep); + break; + + case SEP_IOCENDTRANSACTION: + + /* + * end req daemon transaction, do nothing + * will be removed upon update in middleware + * API library + */ + error = 0; + break; + + default: + dev_dbg(&sep->pdev->dev, + "daemon ioctl: no such IOCTL\n"); + error = -ENOTTY; + } + + mutex_unlock(&sep->ioctl_mutex); + +end_function: + + dev_dbg(&sep->pdev->dev, + "daemon ioctl: end\n"); + return error; + +} + +/** + * sep_inthandler - Interrupt Handler + * @irq: interrupt + * @dev_id: device id + */ + +static irqreturn_t sep_inthandler(int irq, void *dev_id) +{ + irqreturn_t int_error = IRQ_HANDLED; + unsigned long lck_flags; + u32 reg_val, reg_val2 = 0; + struct sep_device *sep = dev_id; + + /* read the IRR register to check if this is SEP interrupt */ + reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); + dev_dbg(&sep->pdev->dev, + "SEP Interrupt - reg is %08x\n", reg_val); + + if (reg_val & (0x1 << 13)) { + + /* lock and update the counter of reply messages */ + spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); + sep->reply_ct++; + spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); + + dev_dbg(&sep->pdev->dev, "sep int: send_ct %lx reply_ct %lx\n", + sep->send_ct, sep->reply_ct); + + /* is this printf or daemon request? */ + reg_val2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); + dev_dbg(&sep->pdev->dev, + "SEP Interrupt - reg2 is %08x\n", reg_val2); + + if ((reg_val2 >> 30) & 0x1) { + + dev_dbg(&sep->pdev->dev, "int: printf request\n"); + wake_up(&sep->event_request_daemon); + } + + else if (reg_val2 >> 31) { + + dev_dbg(&sep->pdev->dev, "int: daemon request\n"); + wake_up(&sep->event_request_daemon); + } else { + + dev_dbg(&sep->pdev->dev, "int: sep reply\n"); + wake_up(&sep->event); + } + + } else { + + dev_dbg(&sep->pdev->dev, "int: not sep interrupt\n"); + int_error = IRQ_NONE; + } + + if (int_error == IRQ_HANDLED) + sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val); + + return int_error; +} + +/** + * sep_callback - + * Function that is called by rar_register when it is ready with + * a region (only for Moorestown) + * @sep_context_pointer: pointer to struct sep_device + */ +static int sep_callback(unsigned long sep_context_pointer) +{ + int error = 0; + struct sep_device *sep = + (struct sep_device *)sep_context_pointer; + + dma_addr_t rar_end_address = 0; + + dev_dbg(&sep->pdev->dev, "callback start\n"); + + error = rar_get_address(RAR_TYPE_IMAGE, &sep->rar_bus, + &rar_end_address); + + if (error) { + dev_warn(&sep->pdev->dev, "mrst cant get rar region\n"); + goto end_function; + } + + sep->rar_size = (size_t)(rar_end_address - sep->rar_bus + 1); + + if (!request_mem_region(sep->rar_bus, sep->rar_size, + "sep_sec_driver")) { + dev_warn(&sep->pdev->dev, + "request mem region for mrst failed\n"); + error = -1; + goto end_function; + } + + sep->rar_addr = ioremap_nocache(sep->rar_bus, sep->rar_size); + if (!sep->rar_addr) { + dev_warn(&sep->pdev->dev, + "ioremap nocache for mrst rar failed\n"); + error = -1; + goto end_function; + } + + dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx," + " size is %x\n", + sep->rar_addr, (unsigned long long)sep->rar_bus, + sep->rar_size); + +end_function: + + dev_dbg(&sep->pdev->dev, "callback end\n"); + return error; +} + +/** + * sep_probe - + * Function that is activated on the successful probe of the SEP device + * @pdev: pci_device + * @end: pci_device_id + */ +static int __devinit sep_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int error = 0; + struct sep_device *sep; + + pr_debug("Sep pci probe starting\n"); + if (sep_dev != NULL) { + dev_warn(&pdev->dev, "only one SEP supported.\n"); + return -EBUSY; + } + + /* enable the device */ + error = pci_enable_device(pdev); + if (error) { + dev_warn(&pdev->dev, "error enabling pci device\n"); + goto end_function; + } + + /* allocate the sep_device structure for this device */ + sep_dev = kmalloc(sizeof(struct sep_device), GFP_ATOMIC); + + if (sep_dev == NULL) { + dev_warn(&pdev->dev, + "can't kmalloc the sep_device structure\n"); + return -ENOMEM; + } + + /* zero out sep structure */ + memset((void *)sep_dev, 0, sizeof(struct sep_device)); + + /* + * we're going to use another variable for actually + * working with the device; this way, if we have + * multiple devices in the future, it would be easier + * to make appropriate changes + */ + sep = sep_dev; + + sep->pdev = pdev; + + if (pdev->device == MRST_PCI_DEVICE_ID) + sep->mrst = 1; + else + sep->mrst = 0; + + dev_dbg(&sep->pdev->dev, "PCI obtained, device being prepared\n"); + dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision); + + /* set up our register area */ + sep->reg_physical_addr = pci_resource_start(sep->pdev, 0); + if (!sep->reg_physical_addr) { + dev_warn(&sep->pdev->dev, "Error getting register start\n"); + pci_dev_put(sep->pdev); + return -ENODEV; + } + + sep->reg_physical_end = pci_resource_end(sep->pdev, 0); + if (!sep->reg_physical_end) { + dev_warn(&sep->pdev->dev, "Error getting register end\n"); + pci_dev_put(sep->pdev); + return -ENODEV; + } + + sep->reg_addr = ioremap_nocache(sep->reg_physical_addr, + (size_t)(sep->reg_physical_end - sep->reg_physical_addr + 1)); + if (!sep->reg_addr) { + dev_warn(&sep->pdev->dev, "Error getting register virtual\n"); + pci_dev_put(sep->pdev); + return -ENODEV; + } + + dev_dbg(&sep->pdev->dev, + "Register area start %llx end %llx virtual %p\n", + (unsigned long long)sep->reg_physical_addr, + (unsigned long long)sep->reg_physical_end, + sep->reg_addr); + + /* allocate the shared area */ + sep->shared_size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES + + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; + + if (sep_map_and_alloc_shared_area(sep)) { + error = -ENOMEM; + /* allocation failed */ + goto end_function_error; + } + + /* the next section depends on type of unit */ + if (sep->mrst) { + error = register_rar(RAR_TYPE_IMAGE, &sep_callback, + (unsigned long)sep); + if (error) { + dev_dbg(&sep->pdev->dev, + "error register_rar\n"); + goto end_function_deallocate_sep_shared_area; + } + } else { + + sep->rar_size = FAKE_RAR_SIZE; + sep->rar_addr = dma_alloc_coherent(NULL, + sep->rar_size, &sep->rar_bus, GFP_KERNEL); + if (sep->rar_addr == NULL) { + dev_warn(&sep->pdev->dev, "cant allocate mfld rar\n"); + error = -ENOMEM; + goto end_function_deallocate_sep_shared_area; + } + + dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx," + " size is %x\n", sep->rar_addr, + (unsigned long long)sep->rar_bus, + sep->rar_size); + } + + dev_dbg(&sep->pdev->dev, + "about to write IMR and ICR REG_ADDR\n"); + + /* clear ICR register */ + sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF); + + /* set the IMR register - open only GPR 2 */ + sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); + + dev_dbg(&sep->pdev->dev, + "about to call request_irq\n"); + /* get the interrupt line */ + error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, + "sep_driver", sep); + + if (error) + goto end_function_free_res; + + goto end_function; + +end_function_free_res: + if (sep->rar_addr) + dma_free_coherent(&sep->pdev->dev, sep->rar_size, + sep->rar_addr, sep->rar_bus); + goto end_function; + +end_function_deallocate_sep_shared_area: + /* de-allocate shared area */ + sep_unmap_and_free_shared_area(sep); + +end_function_error: + iounmap(sep->reg_addr); + kfree(sep_dev); + sep_dev = NULL; + +end_function: + return error; +} + +static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MRST_PCI_DEVICE_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_PCI_DEVICE_ID)}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl); + +/* field for registering driver to PCI device */ +static struct pci_driver sep_pci_driver = { + .name = "sep_sec_driver", + .id_table = sep_pci_id_tbl, + .probe = sep_probe + /* FIXME: remove handler */ +}; + +/* file operation for singleton sep operations */ +static const struct file_operations singleton_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_singleton_ioctl, + .poll = sep_poll, + .open = sep_singleton_open, + .release = sep_singleton_release, + .mmap = sep_mmap, +}; + +/* file operation for daemon operations */ +static const struct file_operations daemon_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_request_daemon_ioctl, + .poll = sep_request_daemon_poll, + .open = sep_request_daemon_open, + .release = sep_request_daemon_release, + .mmap = sep_request_daemon_mmap, +}; + +/* the files operations structure of the driver */ +static const struct file_operations sep_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_ioctl, + .poll = sep_poll, + .open = sep_open, + .release = sep_release, + .mmap = sep_mmap, +}; + +/** + * sep_reconfig_shared_area - + * reconfig the shared area between HOST and SEP - needed in case + * the DX_CC_Init function was called before OS loading + * @sep: pointer to struct sep_device + */ +static int sep_reconfig_shared_area(struct sep_device *sep) +{ + int ret_val = 0; + + dev_dbg(&sep->pdev->dev, "reconfig shared area start\n"); + + /* send the new SHARED MESSAGE AREA to the SEP */ + dev_dbg(&sep->pdev->dev, "sending %08llx to sep\n", + (unsigned long long)sep->shared_bus); + + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, + sep->shared_bus); + + /* poll for SEP response */ + ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); + + while (ret_val != 0xffffffff && + ret_val != sep->shared_bus) { + + ret_val = sep_read_reg(sep, + HW_HOST_SEP_HOST_GPR1_REG_ADDR); + } + + /* check the return value (register) */ + if (ret_val != sep->shared_bus) { + dev_warn(&sep->pdev->dev, "could not reconfig shared area\n"); + dev_warn(&sep->pdev->dev, "result was %x\n", ret_val); + ret_val = -ENOMEM; + } + + else { + ret_val = 0; + } + + dev_dbg(&sep->pdev->dev, "reconfig shared area end\n"); + return ret_val; +} + +/** + * sep_register_driver_to_fs - + * This function registers the driver to the file system + * @sep: pointer to struct sep_device + */ +static int sep_register_driver_to_fs(struct sep_device *sep) +{ + int ret_val = 0; + + sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR; + sep->miscdev_sep.name = SEP_DEV_NAME; + sep->miscdev_sep.fops = &sep_file_operations; + + sep->miscdev_singleton.minor = MISC_DYNAMIC_MINOR; + sep->miscdev_singleton.name = SEP_DEV_SINGLETON; + sep->miscdev_singleton.fops = &singleton_file_operations; + + sep->miscdev_daemon.minor = MISC_DYNAMIC_MINOR; + sep->miscdev_daemon.name = SEP_DEV_DAEMON; + sep->miscdev_daemon.fops = &daemon_file_operations; + + ret_val = misc_register(&sep->miscdev_sep); + if (ret_val) { + dev_warn(&sep->pdev->dev, "misc reg fails for sep %x\n", + ret_val); + return ret_val; + } + + ret_val = misc_register(&sep->miscdev_singleton); + if (ret_val) { + dev_warn(&sep->pdev->dev, "misc reg fails for sing %x\n", + ret_val); + misc_deregister(&sep->miscdev_sep); + return ret_val; + } + + if (!sep->mrst) { + ret_val = misc_register(&sep->miscdev_daemon); + if (ret_val) { + dev_warn(&sep->pdev->dev, + "misc reg fails for dmn %x\n", + ret_val); + misc_deregister(&sep->miscdev_sep); + misc_deregister(&sep->miscdev_singleton); + + return ret_val; + } + } + + return ret_val; +} + +/** + * sep_init - init function; this is the first thing called on boot + */ +static int __init sep_init(void) +{ + int ret_val = 0; + struct sep_device *sep = NULL; + + pr_debug("Sep driver: Init start\n"); + + ret_val = pci_register_driver(&sep_pci_driver); + if (ret_val) { + pr_debug("sep_driver:sep_driver_to_device failed," + " ret_val is %d\n", ret_val); + goto end_function; + } + + sep = sep_dev; + + init_waitqueue_head(&sep->event); + init_waitqueue_head(&sep->event_request_daemon); + spin_lock_init(&sep->snd_rply_lck); + mutex_init(&sep->sep_mutex); + mutex_init(&sep->ioctl_mutex); + + if (sep->mrst == 0) { + ret_val = sep_init_caller_id(sep); + if (ret_val) { + dev_warn(&sep->pdev->dev, + "cant init caller id\n"); + goto end_function_unregister_pci; + } + + } + + /* new chip requires share area reconfigure */ + if (sep->pdev->revision == 4) { /* only for new chip */ + ret_val = sep_reconfig_shared_area(sep); + if (ret_val) + goto end_function_unregister_pci; + } + + /* register driver to fs */ + ret_val = sep_register_driver_to_fs(sep); + if (ret_val) { + dev_warn(&sep->pdev->dev, + "error registering device to file\n"); + goto end_function_unregister_pci; + } + + goto end_function; + +end_function_unregister_pci: + pci_unregister_driver(&sep_pci_driver); + +end_function: + dev_dbg(&sep->pdev->dev, "Init end\n"); + return ret_val; +} + + +/** + * sep_exit - called to unload driver (never called on static compile) + */ +static void __exit sep_exit(void) +{ + struct sep_device *sep; + + sep = sep_dev; + pr_debug("Exit start\n"); + + /* unregister from fs */ + misc_deregister(&sep->miscdev_sep); + misc_deregister(&sep->miscdev_singleton); + misc_deregister(&sep->miscdev_daemon); + + /* free the irq */ + free_irq(sep->pdev->irq, sep); + + /* unregister the driver */ + pci_unregister_driver(&sep_pci_driver); + + /* free shared area */ + if (sep_dev) { + sep_unmap_and_free_shared_area(sep_dev); + dev_dbg(&sep->pdev->dev, + "free pages SEP SHARED AREA\n"); + iounmap((void *) sep_dev->reg_addr); + dev_dbg(&sep->pdev->dev, + "iounmap\n"); + } + pr_debug("release_mem_region\n"); + pr_debug("Exit end\n"); +} + + +module_init(sep_init); +module_exit(sep_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h new file mode 100644 index 000000000000..1207722d8b6a --- /dev/null +++ b/drivers/staging/sep/sep_driver_api.h @@ -0,0 +1,309 @@ +/* + * + * sep_driver_api.h - Security Processor Driver api definitions + * + * Copyright(c) 2009,2010 Intel Corporation. All rights reserved. + * Contributions(c) 2009,2010 Discretix. All rights reserved. + * + * 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; version 2 of the License. + * + * 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. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * Jayant Mangalampalli jayant.mangalampalli@intel.com + * + * CHANGES: + * + * 2010.09.14 Upgrade to Medfield + * + */ + +#ifndef __SEP_DRIVER_API_H__ +#define __SEP_DRIVER_API_H__ + +/* Type of request from device */ +#define SEP_DRIVER_SRC_REPLY 1 +#define SEP_DRIVER_SRC_REQ 2 +#define SEP_DRIVER_SRC_PRINTF 3 + + +/*------------------------------------------- + TYPEDEFS +----------------------------------------------*/ + +/* + * Note that several members of these structres are only here + * for campatability with the middleware; they are not used + * by this driver. + * All user space buffer addresses are set to aligned u64 + * in order to ensure compatibility with 64 bit systems + */ + +/* + init command struct; this will go away when SCU does init +*/ +struct init_struct { + /* address that SEP can access for message */ + aligned_u64 message_addr; + + /* message size */ + u32 message_size_in_words; + + /* offset of the init message in the sep sram */ + aligned_u64 sep_sram_addr; + + /* -not used- resident size in bytes*/ + u32 unused_resident_size_in_bytes; + + /* -not used- cache size in bytes*/ + u32 unused_cache_size_in_bytes; + + /* -not used- ext cache current address */ + aligned_u64 unused_extcache_addr; + + /* -not used- ext cache size in bytes*/ + u32 unused_extcache_size_in_bytes; +}; + +struct realloc_ext_struct { + /* -not used- current external cache address */ + aligned_u64 unused_ext_cache_addr; + + /* -not used- external cache size in bytes*/ + u32 unused_ext_cache_size_in_bytes; +}; + +struct alloc_struct { + /* offset from start of shared pool area */ + u32 offset; + /* number of bytes to allocate */ + u32 num_bytes; +}; + +/* + Note that all app addresses are cast as u32; the sep + middleware sends them as fixed 32 bit words +*/ +struct bld_syn_tab_struct { + /* address value of the data in (user space addr) */ + aligned_u64 app_in_address; + + /* size of data in */ + u32 data_in_size; + + /* address of the data out (user space addr) */ + aligned_u64 app_out_address; + + /* the size of the block of the operation - if needed, + every table will be modulo this parameter */ + u32 block_size; + + /* -not used- distinct user/kernel layout */ + bool isKernelVirtualAddress; + +}; + +/* + * command struct for static pool addresses + * Please note that this is a kernel virtual + * address; this will be removed at the next + * release of the Discretix middleware + */ +struct stat_pool_addr_struct { + /* virtual address of the static pool */ + aligned_u64 static_virt_address; +}; + + +/* command struct for getting caller id value and address */ +struct caller_id_struct { + /* pid of the process */ + u32 pid; + /* virtual address of the caller id hash */ + aligned_u64 callerIdAddress; + /* caller id hash size in bytes */ + u32 callerIdSizeInBytes; +}; + +/* + structure that represents DCB +*/ +struct sep_dcblock { + /* physical address of the first input mlli */ + u32 input_mlli_address; + /* num of entries in the first input mlli */ + u32 input_mlli_num_entries; + /* size of data in the first input mlli */ + u32 input_mlli_data_size; + /* physical address of the first output mlli */ + u32 output_mlli_address; + /* num of entries in the first output mlli */ + u32 output_mlli_num_entries; + /* size of data in the first output mlli */ + u32 output_mlli_data_size; + /* pointer to the output virtual tail */ + u32 out_vr_tail_pt; + /* size of tail data */ + u32 tail_data_size; + /* input tail data array */ + u8 tail_data[64]; +}; + +struct sep_caller_id_entry { + int pid; + unsigned char callerIdHash[SEP_CALLER_ID_HASH_SIZE_IN_BYTES]; +}; + +/* + command structure for building dcb block (currently for ext app only +*/ +struct build_dcb_struct { + /* address value of the data in */ + aligned_u64 app_in_address; + /* size of data in */ + u32 data_in_size; + /* address of the data out */ + aligned_u64 app_out_address; + /* the size of the block of the operation - if needed, + every table will be modulo this parameter */ + u32 block_size; + /* the size of the block of the operation - if needed, + every table will be modulo this parameter */ + u32 tail_block_size; +}; + +/** + * @struct sep_dma_map + * + * Structure that contains all information needed for mapping the user pages + * or kernel buffers for dma operations + * + * + */ +struct sep_dma_map { + /* mapped dma address */ + dma_addr_t dma_addr; + /* size of the mapped data */ + size_t size; +}; + +struct sep_dma_resource { + /* array of pointers to the pages that represent + input data for the synchronic DMA action */ + struct page **in_page_array; + + /* array of pointers to the pages that represent out + data for the synchronic DMA action */ + struct page **out_page_array; + + /* number of pages in the sep_in_page_array */ + u32 in_num_pages; + + /* number of pages in the sep_out_page_array */ + u32 out_num_pages; + + /* map array of the input data */ + struct sep_dma_map *in_map_array; + + /* map array of the output data */ + struct sep_dma_map *out_map_array; + + /* number of entries of the input mapp array */ + u32 in_map_num_entries; + + /* number of entries of the output mapp array */ + u32 out_map_num_entries; +}; + + +/* command struct for translating rar handle to bus address + and setting it at predefined location */ +struct rar_hndl_to_bus_struct { + + /* rar handle */ + aligned_u64 rar_handle; +}; + +/* + structure that represent one entry in the DMA LLI table +*/ +struct sep_lli_entry { + /* physical address */ + u32 bus_address; + + /* block size */ + u32 block_size; +}; + +/*---------------------------------------------------------------- + IOCTL command defines + -----------------------------------------------------------------*/ + +/* magic number 1 of the sep IOCTL command */ +#define SEP_IOC_MAGIC_NUMBER 's' + +/* sends interrupt to sep that message is ready */ +#define SEP_IOCSENDSEPCOMMAND \ + _IO(SEP_IOC_MAGIC_NUMBER, 0) + +/* sends interrupt to sep that message is ready */ +#define SEP_IOCSENDSEPRPLYCOMMAND \ + _IO(SEP_IOC_MAGIC_NUMBER, 1) + +/* allocate memory in data pool */ +#define SEP_IOCALLOCDATAPOLL \ + _IOW(SEP_IOC_MAGIC_NUMBER, 2, struct alloc_struct) + +/* create sym dma lli tables */ +#define SEP_IOCCREATESYMDMATABLE \ + _IOW(SEP_IOC_MAGIC_NUMBER, 5, struct bld_syn_tab_struct) + +/* free dynamic data aalocated during table creation */ +#define SEP_IOCFREEDMATABLEDATA \ + _IO(SEP_IOC_MAGIC_NUMBER, 7) + +/* get the static pool area addersses (physical and virtual) */ +#define SEP_IOCGETSTATICPOOLADDR \ + _IOR(SEP_IOC_MAGIC_NUMBER, 8, struct stat_pool_addr_struct) + +/* start sep command */ +#define SEP_IOCSEPSTART \ + _IO(SEP_IOC_MAGIC_NUMBER, 12) + +/* init sep command */ +#define SEP_IOCSEPINIT \ + _IOW(SEP_IOC_MAGIC_NUMBER, 13, struct init_struct) + +/* end transaction command */ +#define SEP_IOCENDTRANSACTION \ + _IO(SEP_IOC_MAGIC_NUMBER, 15) + +/* reallocate external app; unused structure still needed for + * compatability with middleware */ +#define SEP_IOCREALLOCEXTCACHE \ + _IOW(SEP_IOC_MAGIC_NUMBER, 18, struct realloc_ext_struct) + +#define SEP_IOCRARPREPAREMESSAGE \ + _IOW(SEP_IOC_MAGIC_NUMBER, 20, struct rar_hndl_to_bus_struct) + +#define SEP_IOCTLSETCALLERID \ + _IOW(SEP_IOC_MAGIC_NUMBER, 34, struct caller_id_struct) + +#define SEP_IOCPREPAREDCB \ + _IOW(SEP_IOC_MAGIC_NUMBER, 35, struct build_dcb_struct) + +#define SEP_IOCFREEDCB \ + _IO(SEP_IOC_MAGIC_NUMBER, 36) + +#endif diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h new file mode 100644 index 000000000000..686a353c8c98 --- /dev/null +++ b/drivers/staging/sep/sep_driver_config.h @@ -0,0 +1,428 @@ +/* + * + * sep_driver_config.h - Security Processor Driver configuration + * + * Copyright(c) 2009,2010 Intel Corporation. All rights reserved. + * Contributions(c) 2009,2010 Discretix. All rights reserved. + * + * 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; version 2 of the License. + * + * 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. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * Jayant Mangalampalli jayant.mangalampalli@intel.com + * + * CHANGES: + * + * 2010.06.26 Upgrade to Medfield + * + */ + +#ifndef __SEP_DRIVER_CONFIG_H__ +#define __SEP_DRIVER_CONFIG_H__ + + +/*-------------------------------------- + DRIVER CONFIGURATION FLAGS + -------------------------------------*/ + +/* if flag is on , then the driver is running in polling and + not interrupt mode */ +#define SEP_DRIVER_POLLING_MODE 0 + +/* flag which defines if the shared area address should be + reconfiged (send to SEP anew) during init of the driver */ +#define SEP_DRIVER_RECONFIG_MESSAGE_AREA 0 + +/* the mode for running on the ARM1172 Evaluation platform (flag is 1) */ +#define SEP_DRIVER_ARM_DEBUG_MODE 0 + +/*------------------------------------------- + INTERNAL DATA CONFIGURATION + -------------------------------------------*/ + +/* flag for the input array */ +#define SEP_DRIVER_IN_FLAG 0 + +/* flag for output array */ +#define SEP_DRIVER_OUT_FLAG 1 + +/* maximum number of entries in one LLI tables */ +#define SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP 31 + +/* minimum data size of the MLLI table */ +#define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE 16 + +/* flag that signifies tah the lock is +currently held by the proccess (struct file) */ +#define SEP_DRIVER_OWN_LOCK_FLAG 1 + +/* flag that signifies tah the lock is currently NOT +held by the proccess (struct file) */ +#define SEP_DRIVER_DISOWN_LOCK_FLAG 0 + +/* indicates whether driver has mapped/unmapped shared area */ +#define SEP_REQUEST_DAEMON_MAPPED 1 +#define SEP_REQUEST_DAEMON_UNMAPPED 0 + +/*-------------------------------------------------------- + SHARED AREA memory total size is 36K + it is divided is following: + + SHARED_MESSAGE_AREA 8K } + } + STATIC_POOL_AREA 4K } MAPPED AREA ( 24 K) + } + DATA_POOL_AREA 12K } + + SYNCHRONIC_DMA_TABLES_AREA 5K + + placeholder until drver changes + FLOW_DMA_TABLES_AREA 4K + + SYSTEM_MEMORY_AREA 3k + + SYSTEM_MEMORY total size is 3k + it is divided as following: + + TIME_MEMORY_AREA 8B +-----------------------------------------------------------*/ + +#define SEP_DEV_NAME "sep_sec_driver" +#define SEP_DEV_SINGLETON "sep_sec_singleton_driver" +#define SEP_DEV_DAEMON "sep_req_daemon_driver" + + +/* + the maximum length of the message - the rest of the message shared + area will be dedicated to the dma lli tables +*/ +#define SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES (8 * 1024) + +/* the size of the message shared area in pages */ +#define SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES (8 * 1024) + +/* the size of the data pool static area in pages */ +#define SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES (4 * 1024) + +/* the size of the data pool shared area size in pages */ +#define SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES (16 * 1024) + +/* the size of the message shared area in pages */ +#define SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES (1024 * 5) + +/* Placeholder until driver changes */ +#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 4) + +/* system data (time, caller id etc') pool */ +#define SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES (1024 * 3) + +/* the size in bytes of the time memory */ +#define SEP_DRIVER_TIME_MEMORY_SIZE_IN_BYTES 8 + +/* the size in bytes of the RAR parameters memory */ +#define SEP_DRIVER_SYSTEM_RAR_MEMORY_SIZE_IN_BYTES 8 + +/* area size that is mapped - we map the MESSAGE AREA, STATIC POOL and + DATA POOL areas. area must be module 4k */ +#define SEP_DRIVER_MMMAP_AREA_SIZE (1024 * 28) + +/*----------------------------------------------- + offsets of the areas starting from the shared area start address +*/ + +/* message area offset */ +#define SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES 0 + +/* static pool area offset */ +#define SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES \ + (SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES) + +/* data pool area offset */ +#define SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES \ + (SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES + \ + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES) + +/* synhronic dma tables area offset */ +#define SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES \ + (SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + \ + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) + +/* system memory offset in bytes */ +#define SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES \ + (SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + \ + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES) + +/* offset of the time area */ +#define SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES \ + (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES) + +/* offset of the RAR area */ +#define SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES \ + (SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES + \ + SEP_DRIVER_TIME_MEMORY_SIZE_IN_BYTES) + +/* offset of the caller id area */ +#define SEP_CALLER_ID_OFFSET_BYTES \ + (SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES + \ + SEP_DRIVER_SYSTEM_RAR_MEMORY_SIZE_IN_BYTES) + +/* offset of the DCB area */ +#define SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES \ + (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES + \ + 0x400) + +/* offset of the ext cache area */ +#define SEP_DRIVER_SYSTEM_EXT_CACHE_ADDR_OFFSET_IN_BYTES \ + SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES + +/* offset of the allocation data pointer area */ +#define SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES \ + (SEP_CALLER_ID_OFFSET_BYTES + \ + SEP_CALLER_ID_HASH_SIZE_IN_BYTES) + +/* the token that defines the start of time address */ +#define SEP_TIME_VAL_TOKEN 0x12345678 + +#define FAKE_RAR_SIZE (1024*1024) /* used only for mfld */ +/* DEBUG LEVEL MASKS */ + +/* size of the caller id hash (sha2) */ +#define SEP_CALLER_ID_HASH_SIZE_IN_BYTES 32 + +/* maximum number of entries in the caller id table */ +#define SEP_CALLER_ID_TABLE_NUM_ENTRIES 20 + +/* maximum number of symetric operation (that require DMA resource) + per one message */ +#define SEP_MAX_NUM_SYNC_DMA_OPS 16 + +/* the token that defines the start of time address */ +#define SEP_RAR_VAL_TOKEN 0xABABABAB + +/* ioctl error that should be returned when trying + to realloc the cache/resident second time */ +#define SEP_ALREADY_INITIALIZED_ERR 12 + +/* bit that locks access to the shared area */ +#define SEP_MMAP_LOCK_BIT 0 + +/* bit that lock access to the poll - after send_command */ +#define SEP_SEND_MSG_LOCK_BIT 1 + +/* the token that defines the static pool address address */ +#define SEP_STATIC_POOL_VAL_TOKEN 0xABBAABBA + +/* the token that defines the data pool pointers address */ +#define SEP_DATA_POOL_POINTERS_VAL_TOKEN 0xEDDEEDDE + +/* the token that defines the data pool pointers address */ +#define SEP_EXT_CACHE_ADDR_VAL_TOKEN 0xBABABABA + +/* rar handler */ +#ifndef CONFIG_MRST_RAR_HANDLER + +/* This stub header is for non Moorestown driver only */ + +/* + * Constants that specify different kinds of RAR regions that could be + * set up. + */ +static __u32 const RAR_TYPE_VIDEO; /* 0 */ +static __u32 const RAR_TYPE_AUDIO = 1; +static __u32 const RAR_TYPE_IMAGE = 2; +static __u32 const RAR_TYPE_DATA = 3; + +/* + * @struct RAR_stat + * + * @brief This structure is used for @c RAR_HANDLER_STAT ioctl and for + * @c RAR_get_stat() user space wrapper function. + */ +struct RAR_stat { + /* Type of RAR memory (e.g., audio vs. video) */ + __u32 type; + + /* + * Total size of RAR memory region. + */ + __u32 capacity; + + /* Size of the largest reservable block. */ + __u32 largest_block_size; +}; + + +/* + * @struct RAR_block_info + * + * @brief The argument for the @c RAR_HANDLER_RESERVE @c ioctl. + * + */ +struct RAR_block_info { + /* Type of RAR memory (e.g., audio vs. video) */ + __u32 type; + + /* Requested size of a block to be reserved in RAR. */ + __u32 size; + + /* Handle that can be used to refer to reserved block. */ + __u32 handle; +}; + +/* + * @struct RAR_buffer + * + * Structure that contains all information related to a given block of + * memory in RAR. It is generally only used when retrieving bus + * addresses. + * + * @note This structure is used only by RAR-enabled drivers, and is + * not intended to be exposed to the user space. + */ +struct RAR_buffer { + /* Structure containing base RAR buffer information */ + struct RAR_block_info info; + + /* Buffer bus address */ + __u32 bus_address; +}; + + +#define RAR_IOCTL_BASE 0xE0 + +/* Reserve RAR block. */ +#define RAR_HANDLER_RESERVE _IOWR(RAR_IOCTL_BASE, 0x00, struct RAR_block_info) + +/* Release previously reserved RAR block. */ +#define RAR_HANDLER_RELEASE _IOW(RAR_IOCTL_BASE, 0x01, __u32) + +/* Get RAR stats. */ +#define RAR_HANDLER_STAT _IOWR(RAR_IOCTL_BASE, 0x02, struct RAR_stat) + + +/* -------------------------------------------------------------- */ +/* Kernel Side RAR Handler Interface */ +/* -------------------------------------------------------------- */ + +/* + * @function rar_reserve + * + * @brief Reserve RAR buffers. + * + * This function will reserve buffers in the restricted access regions + * of given types. + * + * @return Number of successfully reserved buffers. + * Successful buffer reservations will have the corresponding + * @c bus_address field set to a non-zero value in the + * given @a buffers vector. + */ +#define rar_reserve(a, b) ((size_t)NULL) + +/* + * @function rar_release + * + * @brief Release RAR buffers retrieved through call to + * @c rar_reserve() or @c rar_handle_to_bus(). + * + * This function will release RAR buffers that were retrieved through + * a call to @c rar_reserve() or @c rar_handle_to_bus() by + * decrementing the reference count. The RAR buffer will be reclaimed + * when the reference count drops to zero. + * + * @return Number of successfully released buffers. + * Successful releases will have their handle field set to + * zero in the given @a buffers vector. + */ +#define rar_release(a, b) ((size_t)NULL) + +/* + * @function rar_handle_to_bus + * + * @brief Convert a vector of RAR handles to bus addresses. + * + * This function will retrieve the RAR buffer bus addresses, type and + * size corresponding to the RAR handles provided in the @a buffers + * vector. + * + * @return Number of successfully converted buffers. + * The bus address will be set to @c 0 for unrecognized + * handles. + * + * @note The reference count for each corresponding buffer in RAR will + * be incremented. Call @c rar_release() when done with the + * buffers. + */ +#define rar_handle_to_bus(a, b) ((size_t)NULL) + +#else /* using rear memrar */ + +#include "../memrar/memrar.h" + +#endif /* MEMRAR */ + +/* rar_register */ +#ifndef CONFIG_RAR_REGISTER +/* This stub header is for non Moorestown driver only */ + +/* The register_rar function is to used by other device drivers + * to ensure that this driver is ready. As we cannot be sure of + * the compile/execute order of dirvers in ther kernel, it is + * best to give this driver a callback function to call when + * it is ready to give out addresses. The callback function + * would have those steps that continue the initialization of + * a driver that do require a valid RAR address. One of those + * steps would be to call get_rar_address() + * This function return 0 on success an -1 on failure. + */ +#define register_rar(a, b, c) (-ENODEV) + +/* The get_rar_address function is used by other device drivers + * to obtain RAR address information on a RAR. It takes two + * parameter: + * + * int rar_index + * The rar_index is an index to the rar for which you wish to retrieve + * the address information. + * Values can be 0,1, or 2. + * + * struct RAR_address_struct is a pointer to a place to which the function + * can return the address structure for the RAR. + * + * The function returns a 0 upon success or a -1 if there is no RAR + * facility on this system. + */ +#define rar_get_address(a, b, c) (-ENODEV) + +/* The lock_rar function is ued by other device drivers to lock an RAR. + * once an RAR is locked, it stays locked until the next system reboot. + * The function takes one parameter: + * + * int rar_index + * The rar_index is an index to the rar that you want to lock. + * Values can be 0,1, or 2. + * + * The function returns a 0 upon success or a -1 if there is no RAR + * facility on this system. + */ +#define rar_lock(a) (-1) + +#else /* using real RAR_REGISTER */ + +#include "../rar_register/rar_register.h" + +#endif /* CONFIG_RAR_REGISTER */ + +#endif /* SEP DRIVER CONFIG */ diff --git a/drivers/staging/sep/sep_driver_hw_defs.h b/drivers/staging/sep/sep_driver_hw_defs.h new file mode 100644 index 000000000000..29addd7b5dd3 --- /dev/null +++ b/drivers/staging/sep/sep_driver_hw_defs.h @@ -0,0 +1,234 @@ +/* + * + * sep_driver_hw_defs.h - Security Processor Driver hardware definitions + * + * Copyright(c) 2009,2010 Intel Corporation. All rights reserved. + * Contributions(c) 2009,2010 Discretix. All rights reserved. + * + * 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; version 2 of the License. + * + * 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. + * + * CONTACTS: + * + * Mark Allyn mark.a.allyn@intel.com + * Jayant Mangalampalli jayant.mangalampalli@intel.com + * + * CHANGES: + * + * 2010.09.20 Upgrade to Medfield + * + */ + +#ifndef SEP_DRIVER_HW_DEFS__H +#define SEP_DRIVER_HW_DEFS__H + +/* PCI ID's */ +#define MRST_PCI_DEVICE_ID 0x080c +#define MFLD_PCI_DEVICE_ID 0x0826 + +/*----------------------- */ +/* HW Registers Defines. */ +/* */ +/*---------------------- -*/ + + +/* cf registers */ +#define HW_R0B_ADDR_0_REG_ADDR 0x0000UL +#define HW_R0B_ADDR_1_REG_ADDR 0x0004UL +#define HW_R0B_ADDR_2_REG_ADDR 0x0008UL +#define HW_R0B_ADDR_3_REG_ADDR 0x000cUL +#define HW_R0B_ADDR_4_REG_ADDR 0x0010UL +#define HW_R0B_ADDR_5_REG_ADDR 0x0014UL +#define HW_R0B_ADDR_6_REG_ADDR 0x0018UL +#define HW_R0B_ADDR_7_REG_ADDR 0x001cUL +#define HW_R0B_ADDR_8_REG_ADDR 0x0020UL +#define HW_R2B_ADDR_0_REG_ADDR 0x0080UL +#define HW_R2B_ADDR_1_REG_ADDR 0x0084UL +#define HW_R2B_ADDR_2_REG_ADDR 0x0088UL +#define HW_R2B_ADDR_3_REG_ADDR 0x008cUL +#define HW_R2B_ADDR_4_REG_ADDR 0x0090UL +#define HW_R2B_ADDR_5_REG_ADDR 0x0094UL +#define HW_R2B_ADDR_6_REG_ADDR 0x0098UL +#define HW_R2B_ADDR_7_REG_ADDR 0x009cUL +#define HW_R2B_ADDR_8_REG_ADDR 0x00a0UL +#define HW_R3B_REG_ADDR 0x00C0UL +#define HW_R4B_REG_ADDR 0x0100UL +#define HW_CSA_ADDR_0_REG_ADDR 0x0140UL +#define HW_CSA_ADDR_1_REG_ADDR 0x0144UL +#define HW_CSA_ADDR_2_REG_ADDR 0x0148UL +#define HW_CSA_ADDR_3_REG_ADDR 0x014cUL +#define HW_CSA_ADDR_4_REG_ADDR 0x0150UL +#define HW_CSA_ADDR_5_REG_ADDR 0x0154UL +#define HW_CSA_ADDR_6_REG_ADDR 0x0158UL +#define HW_CSA_ADDR_7_REG_ADDR 0x015cUL +#define HW_CSA_ADDR_8_REG_ADDR 0x0160UL +#define HW_CSA_REG_ADDR 0x0140UL +#define HW_SINB_REG_ADDR 0x0180UL +#define HW_SOUTB_REG_ADDR 0x0184UL +#define HW_PKI_CONTROL_REG_ADDR 0x01C0UL +#define HW_PKI_STATUS_REG_ADDR 0x01C4UL +#define HW_PKI_BUSY_REG_ADDR 0x01C8UL +#define HW_PKI_A_1025_REG_ADDR 0x01CCUL +#define HW_PKI_SDMA_CTL_REG_ADDR 0x01D0UL +#define HW_PKI_SDMA_OFFSET_REG_ADDR 0x01D4UL +#define HW_PKI_SDMA_POINTERS_REG_ADDR 0x01D8UL +#define HW_PKI_SDMA_DLENG_REG_ADDR 0x01DCUL +#define HW_PKI_SDMA_EXP_POINTERS_REG_ADDR 0x01E0UL +#define HW_PKI_SDMA_RES_POINTERS_REG_ADDR 0x01E4UL +#define HW_PKI_CLR_REG_ADDR 0x01E8UL +#define HW_PKI_SDMA_BUSY_REG_ADDR 0x01E8UL +#define HW_PKI_SDMA_FIRST_EXP_N_REG_ADDR 0x01ECUL +#define HW_PKI_SDMA_MUL_BY1_REG_ADDR 0x01F0UL +#define HW_PKI_SDMA_RMUL_SEL_REG_ADDR 0x01F4UL +#define HW_DES_KEY_0_REG_ADDR 0x0208UL +#define HW_DES_KEY_1_REG_ADDR 0x020CUL +#define HW_DES_KEY_2_REG_ADDR 0x0210UL +#define HW_DES_KEY_3_REG_ADDR 0x0214UL +#define HW_DES_KEY_4_REG_ADDR 0x0218UL +#define HW_DES_KEY_5_REG_ADDR 0x021CUL +#define HW_DES_CONTROL_0_REG_ADDR 0x0220UL +#define HW_DES_CONTROL_1_REG_ADDR 0x0224UL +#define HW_DES_IV_0_REG_ADDR 0x0228UL +#define HW_DES_IV_1_REG_ADDR 0x022CUL +#define HW_AES_KEY_0_ADDR_0_REG_ADDR 0x0400UL +#define HW_AES_KEY_0_ADDR_1_REG_ADDR 0x0404UL +#define HW_AES_KEY_0_ADDR_2_REG_ADDR 0x0408UL +#define HW_AES_KEY_0_ADDR_3_REG_ADDR 0x040cUL +#define HW_AES_KEY_0_ADDR_4_REG_ADDR 0x0410UL +#define HW_AES_KEY_0_ADDR_5_REG_ADDR 0x0414UL +#define HW_AES_KEY_0_ADDR_6_REG_ADDR 0x0418UL +#define HW_AES_KEY_0_ADDR_7_REG_ADDR 0x041cUL +#define HW_AES_KEY_0_REG_ADDR 0x0400UL +#define HW_AES_IV_0_ADDR_0_REG_ADDR 0x0440UL +#define HW_AES_IV_0_ADDR_1_REG_ADDR 0x0444UL +#define HW_AES_IV_0_ADDR_2_REG_ADDR 0x0448UL +#define HW_AES_IV_0_ADDR_3_REG_ADDR 0x044cUL +#define HW_AES_IV_0_REG_ADDR 0x0440UL +#define HW_AES_CTR1_ADDR_0_REG_ADDR 0x0460UL +#define HW_AES_CTR1_ADDR_1_REG_ADDR 0x0464UL +#define HW_AES_CTR1_ADDR_2_REG_ADDR 0x0468UL +#define HW_AES_CTR1_ADDR_3_REG_ADDR 0x046cUL +#define HW_AES_CTR1_REG_ADDR 0x0460UL +#define HW_AES_SK_REG_ADDR 0x0478UL +#define HW_AES_MAC_OK_REG_ADDR 0x0480UL +#define HW_AES_PREV_IV_0_ADDR_0_REG_ADDR 0x0490UL +#define HW_AES_PREV_IV_0_ADDR_1_REG_ADDR 0x0494UL +#define HW_AES_PREV_IV_0_ADDR_2_REG_ADDR 0x0498UL +#define HW_AES_PREV_IV_0_ADDR_3_REG_ADDR 0x049cUL +#define HW_AES_PREV_IV_0_REG_ADDR 0x0490UL +#define HW_AES_CONTROL_REG_ADDR 0x04C0UL +#define HW_HASH_H0_REG_ADDR 0x0640UL +#define HW_HASH_H1_REG_ADDR 0x0644UL +#define HW_HASH_H2_REG_ADDR 0x0648UL +#define HW_HASH_H3_REG_ADDR 0x064CUL +#define HW_HASH_H4_REG_ADDR 0x0650UL +#define HW_HASH_H5_REG_ADDR 0x0654UL +#define HW_HASH_H6_REG_ADDR 0x0658UL +#define HW_HASH_H7_REG_ADDR 0x065CUL +#define HW_HASH_H8_REG_ADDR 0x0660UL +#define HW_HASH_H9_REG_ADDR 0x0664UL +#define HW_HASH_H10_REG_ADDR 0x0668UL +#define HW_HASH_H11_REG_ADDR 0x066CUL +#define HW_HASH_H12_REG_ADDR 0x0670UL +#define HW_HASH_H13_REG_ADDR 0x0674UL +#define HW_HASH_H14_REG_ADDR 0x0678UL +#define HW_HASH_H15_REG_ADDR 0x067CUL +#define HW_HASH_CONTROL_REG_ADDR 0x07C0UL +#define HW_HASH_PAD_EN_REG_ADDR 0x07C4UL +#define HW_HASH_PAD_CFG_REG_ADDR 0x07C8UL +#define HW_HASH_CUR_LEN_0_REG_ADDR 0x07CCUL +#define HW_HASH_CUR_LEN_1_REG_ADDR 0x07D0UL +#define HW_HASH_CUR_LEN_2_REG_ADDR 0x07D4UL +#define HW_HASH_CUR_LEN_3_REG_ADDR 0x07D8UL +#define HW_HASH_PARAM_REG_ADDR 0x07DCUL +#define HW_HASH_INT_BUSY_REG_ADDR 0x07E0UL +#define HW_HASH_SW_RESET_REG_ADDR 0x07E4UL +#define HW_HASH_ENDIANESS_REG_ADDR 0x07E8UL +#define HW_HASH_DATA_REG_ADDR 0x07ECUL +#define HW_DRNG_CONTROL_REG_ADDR 0x0800UL +#define HW_DRNG_VALID_REG_ADDR 0x0804UL +#define HW_DRNG_DATA_REG_ADDR 0x0808UL +#define HW_RND_SRC_EN_REG_ADDR 0x080CUL +#define HW_AES_CLK_ENABLE_REG_ADDR 0x0810UL +#define HW_DES_CLK_ENABLE_REG_ADDR 0x0814UL +#define HW_HASH_CLK_ENABLE_REG_ADDR 0x0818UL +#define HW_PKI_CLK_ENABLE_REG_ADDR 0x081CUL +#define HW_CLK_STATUS_REG_ADDR 0x0824UL +#define HW_CLK_ENABLE_REG_ADDR 0x0828UL +#define HW_DRNG_SAMPLE_REG_ADDR 0x0850UL +#define HW_RND_SRC_CTL_REG_ADDR 0x0858UL +#define HW_CRYPTO_CTL_REG_ADDR 0x0900UL +#define HW_CRYPTO_STATUS_REG_ADDR 0x090CUL +#define HW_CRYPTO_BUSY_REG_ADDR 0x0910UL +#define HW_AES_BUSY_REG_ADDR 0x0914UL +#define HW_DES_BUSY_REG_ADDR 0x0918UL +#define HW_HASH_BUSY_REG_ADDR 0x091CUL +#define HW_CONTENT_REG_ADDR 0x0924UL +#define HW_VERSION_REG_ADDR 0x0928UL +#define HW_CONTEXT_ID_REG_ADDR 0x0930UL +#define HW_DIN_BUFFER_REG_ADDR 0x0C00UL +#define HW_DIN_MEM_DMA_BUSY_REG_ADDR 0x0c20UL +#define HW_SRC_LLI_MEM_ADDR_REG_ADDR 0x0c24UL +#define HW_SRC_LLI_WORD0_REG_ADDR 0x0C28UL +#define HW_SRC_LLI_WORD1_REG_ADDR 0x0C2CUL +#define HW_SRAM_SRC_ADDR_REG_ADDR 0x0c30UL +#define HW_DIN_SRAM_BYTES_LEN_REG_ADDR 0x0c34UL +#define HW_DIN_SRAM_DMA_BUSY_REG_ADDR 0x0C38UL +#define HW_WRITE_ALIGN_REG_ADDR 0x0C3CUL +#define HW_OLD_DATA_REG_ADDR 0x0C48UL +#define HW_WRITE_ALIGN_LAST_REG_ADDR 0x0C4CUL +#define HW_DOUT_BUFFER_REG_ADDR 0x0C00UL +#define HW_DST_LLI_WORD0_REG_ADDR 0x0D28UL +#define HW_DST_LLI_WORD1_REG_ADDR 0x0D2CUL +#define HW_DST_LLI_MEM_ADDR_REG_ADDR 0x0D24UL +#define HW_DOUT_MEM_DMA_BUSY_REG_ADDR 0x0D20UL +#define HW_SRAM_DEST_ADDR_REG_ADDR 0x0D30UL +#define HW_DOUT_SRAM_BYTES_LEN_REG_ADDR 0x0D34UL +#define HW_DOUT_SRAM_DMA_BUSY_REG_ADDR 0x0D38UL +#define HW_READ_ALIGN_REG_ADDR 0x0D3CUL +#define HW_READ_LAST_DATA_REG_ADDR 0x0D44UL +#define HW_RC4_THRU_CPU_REG_ADDR 0x0D4CUL +#define HW_AHB_SINGLE_REG_ADDR 0x0E00UL +#define HW_SRAM_DATA_REG_ADDR 0x0F00UL +#define HW_SRAM_ADDR_REG_ADDR 0x0F04UL +#define HW_SRAM_DATA_READY_REG_ADDR 0x0F08UL +#define HW_HOST_IRR_REG_ADDR 0x0A00UL +#define HW_HOST_IMR_REG_ADDR 0x0A04UL +#define HW_HOST_ICR_REG_ADDR 0x0A08UL +#define HW_HOST_SEP_SRAM_THRESHOLD_REG_ADDR 0x0A10UL +#define HW_HOST_SEP_BUSY_REG_ADDR 0x0A14UL +#define HW_HOST_SEP_LCS_REG_ADDR 0x0A18UL +#define HW_HOST_CC_SW_RST_REG_ADDR 0x0A40UL +#define HW_HOST_SEP_SW_RST_REG_ADDR 0x0A44UL +#define HW_HOST_FLOW_DMA_SW_INT0_REG_ADDR 0x0A80UL +#define HW_HOST_FLOW_DMA_SW_INT1_REG_ADDR 0x0A84UL +#define HW_HOST_FLOW_DMA_SW_INT2_REG_ADDR 0x0A88UL +#define HW_HOST_FLOW_DMA_SW_INT3_REG_ADDR 0x0A8cUL +#define HW_HOST_FLOW_DMA_SW_INT4_REG_ADDR 0x0A90UL +#define HW_HOST_FLOW_DMA_SW_INT5_REG_ADDR 0x0A94UL +#define HW_HOST_FLOW_DMA_SW_INT6_REG_ADDR 0x0A98UL +#define HW_HOST_FLOW_DMA_SW_INT7_REG_ADDR 0x0A9cUL +#define HW_HOST_SEP_HOST_GPR0_REG_ADDR 0x0B00UL +#define HW_HOST_SEP_HOST_GPR1_REG_ADDR 0x0B04UL +#define HW_HOST_SEP_HOST_GPR2_REG_ADDR 0x0B08UL +#define HW_HOST_SEP_HOST_GPR3_REG_ADDR 0x0B0CUL +#define HW_HOST_HOST_SEP_GPR0_REG_ADDR 0x0B80UL +#define HW_HOST_HOST_SEP_GPR1_REG_ADDR 0x0B84UL +#define HW_HOST_HOST_SEP_GPR2_REG_ADDR 0x0B88UL +#define HW_HOST_HOST_SEP_GPR3_REG_ADDR 0x0B8CUL +#define HW_HOST_HOST_ENDIAN_REG_ADDR 0x0B90UL +#define HW_HOST_HOST_COMM_CLK_EN_REG_ADDR 0x0B94UL +#define HW_CLR_SRAM_BUSY_REG_REG_ADDR 0x0F0CUL +#define HW_CC_SRAM_BASE_ADDRESS 0x5800UL + +#endif /* ifndef HW_DEFS */ -- cgit v1.2.3 From 6f6ffec188b5416642b20ef14034d40cfeb3256e Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Nov 2010 15:06:31 +0000 Subject: sst: Change the SST driver PCM interface The PCM interface in SST driver is cmds only, this patch changes the interface to open, close and cmd interface. This allows SST driver to keep easy track of handles open Signed-off-by: Vinod Koul Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst.h | 8 +- .../staging/intel_sst/intel_sst_app_interface.c | 20 ++-- drivers/staging/intel_sst/intel_sst_common.h | 4 +- .../staging/intel_sst/intel_sst_drv_interface.c | 118 ++++++++++++++------- drivers/staging/intel_sst/intel_sst_fw_ipc.h | 1 + drivers/staging/intel_sst/intel_sst_stream.c | 2 +- .../staging/intel_sst/intel_sst_stream_encoded.c | 9 +- drivers/staging/intel_sst/intelmid.c | 37 +++---- drivers/staging/intel_sst/intelmid_ctrl.c | 13 ++- drivers/staging/intel_sst/intelmid_pvt.c | 10 +- 10 files changed, 134 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intel_sst.h b/drivers/staging/intel_sst/intel_sst.h index 1f19f0d1d316..cb03ff7d1a21 100644 --- a/drivers/staging/intel_sst/intel_sst.h +++ b/drivers/staging/intel_sst/intel_sst.h @@ -29,6 +29,7 @@ * and middleware. * This file is shared between the SST and MAD drivers */ +#include "intel_sst_ioctl.h" #define SST_CARD_NAMES "intel_mid_card" @@ -107,10 +108,15 @@ struct snd_pmic_ops { int (*power_down_pmic) (void); }; +struct intel_sst_pcm_control { + int (*open) (struct snd_sst_params *str_param); + int (*device_control) (int cmd, void *arg); + int (*close) (unsigned int str_id); +}; struct intel_sst_card_ops { char *module_name; unsigned int vendor_id; - int (*control_set) (int control_element, void *value); + struct intel_sst_pcm_control *pcm_control; struct snd_pmic_ops *scard_ops; }; diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index 09909559a922..c1ca39ef3646 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c @@ -100,11 +100,15 @@ static int intel_sst_check_device(void) */ int intel_sst_open(struct inode *i_node, struct file *file_ptr) { - int retval = intel_sst_check_device(); - if (retval) - return retval; + unsigned int retval; mutex_lock(&sst_drv_ctx->stream_lock); + retval = intel_sst_check_device(); + if (retval) { + mutex_unlock(&sst_drv_ctx->stream_lock); + return retval; + } + if (sst_drv_ctx->encoded_cnt < MAX_ENC_STREAM) { struct ioctl_pvt_data *data = kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL); @@ -139,12 +143,16 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr) */ int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr) { - int retval = intel_sst_check_device(); - if (retval) - return retval; + unsigned int retval; /* audio manager open */ mutex_lock(&sst_drv_ctx->stream_lock); + retval = intel_sst_check_device(); + if (retval) { + mutex_unlock(&sst_drv_ctx->stream_lock); + return retval; + } + if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) { sst_drv_ctx->am_cnt++; pr_debug("AM handle opened...\n"); diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h index bf0ead78bfae..dcc1ebbe1ac6 100644 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ b/drivers/staging/intel_sst/intel_sst_common.h @@ -28,8 +28,8 @@ * Common private declarations for SST */ -#define SST_DRIVER_VERSION "1.2.05" -#define SST_VERSION_NUM 0x1205 +#define SST_DRIVER_VERSION "1.2.09" +#define SST_VERSION_NUM 0x1209 /* driver names */ #define SST_DRV_NAME "intel_sst_driver" diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index 1165303eeeb4..9ecbff60cacf 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -288,18 +288,27 @@ void sst_process_mad_ops(struct work_struct *work) } return; } + +void send_intial_rx_timeslot(void) +{ + if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID && + sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT + && sst_drv_ctx->pmic_vendor != SND_NC) + sst_enable_rx_timeslot(sst_drv_ctx->rx_time_slot_status); +} + /* - * sst_control_set - Set Control params + * sst_open_pcm_stream - Open PCM interface * - * @control_list: list of controls to be set + * @str_param: parameters of pcm stream * - * This function is called by MID sound card driver to set - * SST/Sound card controls. This is registered with MID driver + * This function is called by MID sound card driver to open + * a new pcm interface */ -int sst_control_set(int control_element, void *value) +int sst_open_pcm_stream(struct snd_sst_params *str_param) { - int retval = 0, str_id = 0; - struct stream_info *stream; + struct stream_info *str_info; + int retval; if (sst_drv_ctx->sst_state == SST_SUSPENDED) { /*LPE is suspended, resume it before proceding*/ @@ -318,53 +327,76 @@ int sst_control_set(int control_element, void *value) pr_err("FW download fail %x, abort\n", retval); return retval; } - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID && - sst_drv_ctx->rx_time_slot_status != RX_TIMESLOT_UNINIT - && sst_drv_ctx->pmic_vendor != SND_NC) - sst_enable_rx_timeslot( - sst_drv_ctx->rx_time_slot_status); + send_intial_rx_timeslot(); } - switch (control_element) { - case SST_SND_ALLOC: { - struct snd_sst_params *str_param; - struct stream_info *str_info; + if (!str_param) + return -EINVAL; - str_param = (struct snd_sst_params *)value; - BUG_ON(!str_param); - retval = sst_get_stream(str_param); - if (retval >= 0) - sst_drv_ctx->stream_cnt++; + retval = sst_get_stream(str_param); + if (retval > 0) { + sst_drv_ctx->stream_cnt++; str_info = &sst_drv_ctx->streams[retval]; str_info->src = MAD_DRV; - break; } + return retval; +} +/* + * sst_close_pcm_stream - Close PCM interface + * + * @str_id: stream id to be closed + * + * This function is called by MID sound card driver to close + * an existing pcm interface + */ +int sst_close_pcm_stream(unsigned int str_id) +{ + struct stream_info *stream; + + pr_debug("sst: stream free called\n"); + if (sst_validate_strid(str_id)) + return -EINVAL; + stream = &sst_drv_ctx->streams[str_id]; + free_stream_context(str_id); + stream->pcm_substream = NULL; + stream->status = STREAM_UN_INIT; + stream->period_elapsed = NULL; + sst_drv_ctx->stream_cnt--; + pr_debug("sst: will call runtime put now\n"); + return 0; +} + +/* + * sst_device_control - Set Control params + * + * @cmd: control cmd to be set + * @arg: command argument + * + * This function is called by MID sound card driver to set + * SST/Sound card controls for an opened stream. + * This is registered with MID driver + */ +int sst_device_control(int cmd, void *arg) +{ + int retval = 0, str_id = 0; + + switch (cmd) { case SST_SND_PAUSE: case SST_SND_RESUME: case SST_SND_DROP: case SST_SND_START: - sst_drv_ctx->mad_ops.control_op = control_element; - sst_drv_ctx->mad_ops.stream_id = *(int *)value; + sst_drv_ctx->mad_ops.control_op = cmd; + sst_drv_ctx->mad_ops.stream_id = *(int *)arg; queue_work(sst_drv_ctx->mad_wq, &sst_drv_ctx->mad_ops.wq); break; - case SST_SND_FREE: - str_id = *(int *)value; - stream = &sst_drv_ctx->streams[str_id]; - free_stream_context(str_id); - stream->pcm_substream = NULL; - stream->status = STREAM_UN_INIT; - stream->period_elapsed = NULL; - sst_drv_ctx->stream_cnt--; - break; - case SST_SND_STREAM_INIT: { struct pcm_stream_info *str_info; struct stream_info *stream; pr_debug("stream init called\n"); - str_info = (struct pcm_stream_info *)value; + str_info = (struct pcm_stream_info *)arg; str_id = str_info->str_id; retval = sst_validate_strid(str_id); if (retval) @@ -386,7 +418,7 @@ int sst_control_set(int control_element, void *value) struct stream_info *stream; - stream_info = (struct pcm_stream_info *)value; + stream_info = (struct pcm_stream_info *)arg; str_id = stream_info->str_id; retval = sst_validate_strid(str_id); if (retval) @@ -412,7 +444,7 @@ int sst_control_set(int control_element, void *value) break; } case SST_ENABLE_RX_TIME_SLOT: { - int status = *(int *)value; + int status = *(int *)arg; sst_drv_ctx->rx_time_slot_status = status ; sst_enable_rx_timeslot(status); break; @@ -427,8 +459,14 @@ int sst_control_set(int control_element, void *value) } +struct intel_sst_pcm_control pcm_ops = { + .open = sst_open_pcm_stream, + .device_control = sst_device_control, + .close = sst_close_pcm_stream, +}; + struct intel_sst_card_ops sst_pmic_ops = { - .control_set = sst_control_set, + .pcm_control = &pcm_ops, }; /* @@ -458,7 +496,7 @@ int register_sst_card(struct intel_sst_card_ops *card) sst_pmic_ops.module_name = card->module_name; sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE; sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/ - card->control_set = sst_pmic_ops.control_set; + card->pcm_control = sst_pmic_ops.pcm_control; sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT; return 0; } else { @@ -484,7 +522,7 @@ EXPORT_SYMBOL_GPL(register_sst_card); */ void unregister_sst_card(struct intel_sst_card_ops *card) { - if (sst_pmic_ops.control_set == card->control_set) { + if (sst_pmic_ops.pcm_control == card->pcm_control) { /* unreg */ sst_pmic_ops.module_name = ""; sst_drv_ctx->pmic_state = SND_MAD_UN_INIT; diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h index 9d3c36807e07..1a2f67f0aedc 100644 --- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h +++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h @@ -31,6 +31,7 @@ */ #define MAX_NUM_STREAMS_MRST 3 +#define MAX_NUM_STREAMS_MFLD 6 #define MAX_NUM_STREAMS 6 #define MAX_DBG_RW_BYTES 80 #define MAX_NUM_SCATTER_BUFFERS 8 diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c index 8f6e1005371d..795e42ab7360 100644 --- a/drivers/staging/intel_sst/intel_sst_stream.c +++ b/drivers/staging/intel_sst/intel_sst_stream.c @@ -47,7 +47,7 @@ */ int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot) { - if (device >= MAX_NUM_STREAMS) { + if (device > MAX_NUM_STREAMS_MFLD) { pr_debug("device type invalid %d\n", device); return -EINVAL; } diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c index d4e94f1ec830..028ef8ea9bef 100644 --- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c +++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c @@ -32,9 +32,9 @@ #include #include #include -#include #ifdef CONFIG_MRST_RAR_HANDLER -#include "../../../drivers/staging/memrar/memrar.h" +#include +#include "../memrar/memrar.h" #endif #include "intel_sst_ioctl.h" #include "intel_sst.h" @@ -880,13 +880,13 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info, return retval; } +#ifdef CONFIG_MRST_RAR_HANDLER static int sst_prepare_input_buffers_rar(struct stream_info *str_info, struct snd_sst_dbufs *dbufs, int *input_index, int *in_copied, int *input_index_valid_size, int *new_entry_flag) { int retval = 0; -#ifdef CONFIG_MRST_RAR_HANDLER int i; if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) { @@ -921,9 +921,10 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info, str_info->decode_ibuf_type = dbufs->ibufs->type; *in_copied = str_info->decode_isize; } -#endif return retval; } +#endif + /*This function is used to prepare the kernel input buffers with contents before sending for decode*/ static int sst_prepare_input_buffers(struct stream_info *str_info, diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c index 47b91e500c3c..fb2292186703 100644 --- a/drivers/staging/intel_sst/intelmid.c +++ b/drivers/staging/intel_sst/intelmid.c @@ -104,12 +104,10 @@ static struct snd_pcm_hardware snd_intelmad_stream = { static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - int ret_val = 0; + int ret_val = 0, str_id; struct snd_intelmad *intelmaddata; struct mad_stream_pvt *stream; - /*struct stream_buffer buffer_to_sst;*/ - - + struct intel_sst_pcm_control *sst_ops; WARN_ON(!substream); @@ -118,38 +116,35 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream, WARN_ON(!intelmaddata->sstdrv_ops); WARN_ON(!intelmaddata->sstdrv_ops->scard_ops); + sst_ops = intelmaddata->sstdrv_ops->pcm_control; + str_id = stream->stream_info.str_id; switch (cmd) { case SNDRV_PCM_TRIGGER_START: pr_debug("Trigger Start\n"); - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_START, - &stream->stream_info.str_id); + ret_val = sst_ops->device_control(SST_SND_START, &str_id); if (ret_val) return ret_val; stream->stream_status = RUNNING; stream->substream = substream; - stream->stream_status = RUNNING; break; case SNDRV_PCM_TRIGGER_STOP: pr_debug("in stop\n"); - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP, - &stream->stream_info.str_id); + ret_val = sst_ops->device_control(SST_SND_DROP, &str_id); if (ret_val) return ret_val; stream->stream_status = DROPPED; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: pr_debug("in pause\n"); - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_PAUSE, - &stream->stream_info.str_id); + ret_val = sst_ops->device_control(SST_SND_PAUSE, &str_id); if (ret_val) return ret_val; stream->stream_status = PAUSED; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("in pause release\n"); - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_RESUME, - &stream->stream_info.str_id); + ret_val = sst_ops->device_control(SST_SND_RESUME, &str_id); if (ret_val) return ret_val; stream->stream_status = RUNNING; @@ -184,8 +179,8 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream) if (stream->stream_info.str_id) { pr_debug("Prepare called for already set stream\n"); - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP, - &stream->stream_info.str_id); + ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control( + SST_SND_DROP, &stream->stream_info.str_id); return ret_val; } @@ -253,8 +248,8 @@ static snd_pcm_uframes_t snd_intelmad_pcm_pointer if (stream->stream_status == INIT) return 0; - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_BUFFER_POINTER, - &stream->stream_info); + ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control( + SST_SND_BUFFER_POINTER, &stream->stream_info); if (ret_val) { pr_err("error code = 0x%x\n", ret_val); return ret_val; @@ -280,20 +275,20 @@ static int snd_intelmad_close(struct snd_pcm_substream *substream) { struct snd_intelmad *intelmaddata; struct mad_stream_pvt *stream; - int ret_val = 0; + int ret_val = 0, str_id; WARN_ON(!substream); stream = substream->runtime->private_data; + str_id = stream->stream_info.str_id; - pr_debug("snd_intelmad_close called\n"); + pr_debug("sst: snd_intelmad_close called for %d\n", str_id); intelmaddata = snd_pcm_substream_chip(substream); pr_debug("str id = %d\n", stream->stream_info.str_id); if (stream->stream_info.str_id) { /* SST API to actually stop/free the stream */ - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_FREE, - &stream->stream_info.str_id); + ret_val = intelmaddata->sstdrv_ops->pcm_control->close(str_id); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) intelmaddata->playback_cnt--; else diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c index 0d9135715c74..69af0704ce94 100644 --- a/drivers/staging/intel_sst/intelmid_ctrl.c +++ b/drivers/staging/intel_sst/intelmid_ctrl.c @@ -494,6 +494,7 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, struct snd_intelmad *intelmaddata; struct snd_pmic_ops *scard_ops; int ret_val = 0, vendor, status; + struct intel_sst_pcm_control *pcm_control; pr_debug("snd_intelmad_device_set called\n"); @@ -521,15 +522,13 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol, case INPUT_SEL: vendor = intelmaddata->sstdrv_ops->vendor_id; if ((vendor == SND_MX) || (vendor == SND_FS)) { - if (uval->value.enumerated.item[0] == HS_MIC) { + pcm_control = intelmaddata->sstdrv_ops->pcm_control; + if (uval->value.enumerated.item[0] == HS_MIC) status = 1; - intelmaddata->sstdrv_ops-> - control_set(SST_ENABLE_RX_TIME_SLOT, &status); - } else { + else status = 0; - intelmaddata->sstdrv_ops-> - control_set(SST_ENABLE_RX_TIME_SLOT, &status); - } + pcm_control->device_control( + SST_ENABLE_RX_TIME_SLOT, &status); } ret_val = scard_ops->set_input_dev( uval->value.enumerated.item[0]); diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c index 4f9bdf364dca..cb71fe028333 100644 --- a/drivers/staging/intel_sst/intelmid_pvt.c +++ b/drivers/staging/intel_sst/intelmid_pvt.c @@ -95,10 +95,8 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream) pr_debug("Capture stream,Device %d\n", stream->device); } str_params.device_type = stream->device; - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC, - &str_params); - pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", - ret_val); + ret_val = intelmaddata->sstdrv_ops->pcm_control->open(&str_params); + pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); if (ret_val < 0) return ret_val; @@ -121,8 +119,8 @@ int snd_intelmad_init_stream(struct snd_pcm_substream *substream) stream->stream_info.mad_substream = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT, - &stream->stream_info); + ret_val = intelmaddata->sstdrv_ops->pcm_control->device_control( + SST_SND_STREAM_INIT, &stream->stream_info); if (ret_val) pr_err("control_set ret error %d\n", ret_val); return ret_val; -- cgit v1.2.3 From 90abe60b32a4762fff9bef33295e08bc9bb355af Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Nov 2010 15:09:50 +0000 Subject: sst: Firmware error codes force number values To avoid mismatch in driver and firmware error codes assign specfic values to each enum. Signed-off-by: Vinod Koul Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst_fw_ipc.h | 110 +++++++++++++++------------ 1 file changed, 62 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h index 1a2f67f0aedc..75c187672450 100644 --- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h +++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h @@ -142,73 +142,87 @@ enum sst_error_codes { /* Error code,response to msgId: Description */ /* Common error codes */ SST_SUCCESS = 0, /* Success */ - SST_ERR_INVALID_STREAM_ID, /* Invalid stream ID */ - SST_ERR_INVALID_MSG_ID, /* Invalid message ID */ - SST_ERR_INVALID_STREAM_OP, /* Invalid stream operation request */ - SST_ERR_INVALID_PARAMS, /* Invalid params */ - SST_ERR_INVALID_CODEC, /* Invalid codec type */ - SST_ERR_INVALID_MEDIA_TYPE, /* Invalid media type */ - SST_ERR_STREAM_ERR, /* ANY: Stream control or config or - processing error */ + SST_ERR_INVALID_STREAM_ID = 1, + SST_ERR_INVALID_MSG_ID = 2, + SST_ERR_INVALID_STREAM_OP = 3, + SST_ERR_INVALID_PARAMS = 4, + SST_ERR_INVALID_CODEC = 5, + SST_ERR_INVALID_MEDIA_TYPE = 6, + SST_ERR_STREAM_ERR = 7, /* IPC specific error codes */ - SST_IPC_ERR_CALL_BACK_NOT_REGD, /* Call back for msg not regd */ - SST_IPC_ERR_STREAM_NOT_ALLOCATED, /* Stream is not allocated */ - SST_IPC_ERR_STREAM_ALLOC_FAILED, /* ALLOC:Stream alloc failed */ - SST_IPC_ERR_GET_STREAM_FAILED, /* ALLOC:Get stream id failed*/ - SST_ERR_MOD_NOT_AVAIL, /* SET/GET: Mod(AEC/AGC/ALC) not available */ - SST_ERR_MOD_DNLD_RQD, /* SET/GET: Mod(AEC/AGC/ALC) download required */ - SST_ERR_STREAM_STOPPED, /* ANY: Stream is in stopped state */ - SST_ERR_STREAM_IN_USE, /* ANY: Stream is already in use */ + SST_IPC_ERR_CALL_BACK_NOT_REGD = 8, + SST_IPC_ERR_STREAM_NOT_ALLOCATED = 9, + SST_IPC_ERR_STREAM_ALLOC_FAILED = 10, + SST_IPC_ERR_GET_STREAM_FAILED = 11, + SST_ERR_MOD_NOT_AVAIL = 12, + SST_ERR_MOD_DNLD_RQD = 13, + SST_ERR_STREAM_STOPPED = 14, + SST_ERR_STREAM_IN_USE = 15, /* Capture specific error codes */ - SST_CAP_ERR_INCMPLTE_CAPTURE_MSG,/* ANY:Incomplete message */ - SST_CAP_ERR_CAPTURE_FAIL, /* ANY:Capture op failed */ - SST_CAP_ERR_GET_DDR_NEW_SGLIST, - SST_CAP_ERR_UNDER_RUN, /* lack of input data */ - SST_CAP_ERR_OVERFLOW, /* lack of output space */ + SST_CAP_ERR_INCMPLTE_CAPTURE_MSG = 16, + SST_CAP_ERR_CAPTURE_FAIL = 17, + SST_CAP_ERR_GET_DDR_NEW_SGLIST = 18, + SST_CAP_ERR_UNDER_RUN = 19, + SST_CAP_ERR_OVERFLOW = 20, /* Playback specific error codes*/ - SST_PB_ERR_INCMPLTE_PLAY_MSG, /* ANY: Incomplete message */ - SST_PB_ERR_PLAY_FAIL, /* ANY: Playback operation failed */ - SST_PB_ERR_GET_DDR_NEW_SGLIST, + SST_PB_ERR_INCMPLTE_PLAY_MSG = 21, + SST_PB_ERR_PLAY_FAIL = 22, + SST_PB_ERR_GET_DDR_NEW_SGLIST = 23, /* Codec manager specific error codes */ - SST_LIB_ERR_LIB_DNLD_REQUIRED, /* ALLOC: Codec download required */ - SST_LIB_ERR_LIB_NOT_SUPPORTED, /* Library is not supported */ + SST_LIB_ERR_LIB_DNLD_REQUIRED = 24, + SST_LIB_ERR_LIB_NOT_SUPPORTED = 25, /* Library manager specific error codes */ - SST_SCC_ERR_PREP_DNLD_FAILED, /* Failed to prepare for codec download */ - SST_SCC_ERR_LIB_DNLD_RES_FAILED, /* Lib download resume failed */ + SST_SCC_ERR_PREP_DNLD_FAILED = 26, + SST_SCC_ERR_LIB_DNLD_RES_FAILED = 27, /* Scheduler specific error codes */ - SST_SCH_ERR_FAIL, /* REPORT: */ + SST_SCH_ERR_FAIL = 28, /* DMA specific error codes */ - SST_DMA_ERR_NO_CHNL_AVAILABLE, /* DMA Ch not available */ - SST_DMA_ERR_INVALID_INPUT_PARAMS, /* Invalid input params */ - SST_DMA_ERR_CHNL_ALREADY_SUSPENDED, /* Ch is suspended */ - SST_DMA_ERR_CHNL_ALREADY_STARTED, /* Ch already started */ - SST_DMA_ERR_CHNL_NOT_ENABLED, /* Ch not enabled */ - SST_DMA_ERR_TRANSFER_FAILED, /* Transfer failed */ - SST_SSP_ERR_ALREADY_ENABLED, /* REPORT: SSP already enabled */ - SST_SSP_ERR_ALREADY_DISABLED, /* REPORT: SSP already disabled */ - SST_SSP_ERR_NOT_INITIALIZED, + SST_DMA_ERR_NO_CHNL_AVAILABLE = 29, + SST_DMA_ERR_INVALID_INPUT_PARAMS = 30, + SST_DMA_ERR_CHNL_ALREADY_SUSPENDED = 31, + SST_DMA_ERR_CHNL_ALREADY_STARTED = 32, + SST_DMA_ERR_CHNL_NOT_ENABLED = 33, + SST_DMA_ERR_TRANSFER_FAILED = 34, + + SST_SSP_ERR_ALREADY_ENABLED = 35, + SST_SSP_ERR_ALREADY_DISABLED = 36, + SST_SSP_ERR_NOT_INITIALIZED = 37, + SST_SSP_ERR_SRAM_NO_DMA_DATA = 38, /* Other error codes */ - SST_ERR_MOD_INIT_FAIL, /* Firmware Module init failed */ + SST_ERR_MOD_INIT_FAIL = 39, /* FW init error codes */ - SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED, - SST_RDR_ERR_ROUTE_ALREADY_STARTED, - SST_RDR_PREP_CODEC_DNLD_FAILED, + SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED = 40, + SST_RDR_ERR_ROUTE_ALREADY_STARTED = 41, + SST_RDR_ERR_IO_DEV_SEL_FAILED = 42, + SST_RDR_PREP_CODEC_DNLD_FAILED = 43, /* Memory debug error codes */ - SST_ERR_DBG_MEM_READ_FAIL, - SST_ERR_DBG_MEM_WRITE_FAIL, - - /* Decode error codes */ - SST_ERR_DEC_NEED_INPUT_BUF, - + SST_ERR_DBG_MEM_READ_FAIL = 44, + SST_ERR_DBG_MEM_WRITE_FAIL = 45, + SST_ERR_INSUFFICIENT_INPUT_SG_LIST = 46, + SST_ERR_INSUFFICIENT_OUTPUT_SG_LIST = 47, + + SST_ERR_BUFFER_NOT_AVAILABLE = 48, + SST_ERR_BUFFER_NOT_ALLOCATED = 49, + SST_ERR_INVALID_REGION_TYPE = 50, + SST_ERR_NULL_PTR = 51, + SST_ERR_INVALID_BUFFER_SIZE = 52, + SST_ERR_INVALID_BUFFER_INDEX = 53, + + /*IIPC specific error codes */ + SST_IIPC_QUEUE_FULL = 54, + SST_IIPC_ERR_MSG_SND_FAILED = 55, + SST_PB_ERR_UNDERRUN_OCCURED = 56, + SST_RDR_INSUFFICIENT_MIXER_BUFFER = 57, + SST_INVALID_TIME_SLOTS = 58, }; enum dbg_mem_data_type { -- cgit v1.2.3 From b21bded7c006a29ccda0b8515c4ae3b49e3b599b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Nov 2010 15:10:39 +0000 Subject: sst: log error returned by scu ipc read/write scu ipc driver fails sometimes to read/write. This add logs with register addr and ret code when these errors occur. Signed-off-by: Vinod Koul Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intelmid_pvt.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c index cb71fe028333..3ba9daf67526 100644 --- a/drivers/staging/intel_sst/intelmid_pvt.c +++ b/drivers/staging/intel_sst/intelmid_pvt.c @@ -146,30 +146,29 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access, for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, sc_access[i].value); - if (retval) { - pr_err("IPC write failed!!! %d\n", retval); - return retval; - } + if (retval) + goto err; } } else if (type == PMIC_READ) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, &(sc_access[i].value)); - if (retval) { - pr_err("IPC read failed!!!!!%d\n", retval); - return retval; - } + if (retval) + goto err; } } else { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_update_register( sc_access[i].reg_addr, sc_access[i].value, sc_access[i].mask); - if (retval) { - pr_err("IPC Modify failed!!!%d\n", retval); - return retval; - } + if (retval) + goto err; } } - return retval; + return 0; +err: + pr_err("IPC failed for cmd %d, %d\n", retval, type); + pr_err("reg:0x%2x addr:0x%2x\n", + sc_access[i].reg_addr, sc_access[i].value); + return retval; } -- cgit v1.2.3 From dca25ebdd09c7aa877f00c2bdbd58c74a909c6f8 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sun, 21 Nov 2010 08:15:01 -0500 Subject: Fix "forcably" comment typo Signed-off-by: Robert P. J. Day Signed-off-by: Jiri Kosina --- drivers/base/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 33c270a64db7..8f0b1ba522f0 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -976,7 +976,7 @@ struct klist *bus_get_device_klist(struct bus_type *bus) EXPORT_SYMBOL_GPL(bus_get_device_klist); /* - * Yes, this forcably breaks the klist abstraction temporarily. It + * Yes, this forcibly breaks the klist abstraction temporarily. It * just wants to sort the klist, not change reference counts and * take/drop locks rapidly in the process. It does all this while * holding the lock for the list, so objects can't otherwise be -- cgit v1.2.3 From 27641c3f003e7f3b6585c01d8a788883603eb262 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Sat, 23 Oct 2010 04:20:23 +0200 Subject: drm/vblank: Add support for precise vblank timestamping. The DRI2 swap & sync implementation needs precise vblank counts and precise timestamps corresponding to those vblank counts. For conformance to the OpenML OML_sync_control extension specification the DRM timestamp associated with a vblank count should correspond to the start of video scanout of the first scanline of the video frame following the vblank interval for that vblank count. Therefore we need to carry around precise timestamps for vblanks. Currently the DRM and KMS drivers generate timestamps ad-hoc via do_gettimeofday() in some places. The resulting timestamps are sometimes not very precise due to interrupt handling delays, they don't conform to OML_sync_control and some are wrong, as they aren't taken synchronized to the vblank. This patch implements support inside the drm core for precise and robust timestamping. It consists of the following interrelated pieces. 1. Vblank timestamp caching: A per-crtc ringbuffer stores the most recent vblank timestamps corresponding to vblank counts. The ringbuffer can be read out lock-free via the accessor function: struct timeval timestamp; vblankcount = drm_vblank_count_and_time(dev, crtcid, ×tamp). The function returns the current vblank count and the corresponding timestamp for start of video scanout following the vblank interval. It can be used anywhere between enclosing drm_vblank_get(dev, crtcid) and drm_vblank_put(dev,crtcid) statements. It is used inside the drmWaitVblank ioctl and in the vblank event queueing and handling. It should be used by kms drivers for timestamping of bufferswap completion. The timestamp ringbuffer is reinitialized each time vblank irq's get reenabled in drm_vblank_get()/ drm_update_vblank_count(). It is invalidated when vblank irq's get disabled. The ringbuffer is updated inside drm_handle_vblank() at each vblank irq. 2. Calculation of precise vblank timestamps: drm_get_last_vbltimestamp() is used to compute the timestamp for the end of the most recent vblank (if inside active scanout), or the expected end of the current vblank interval (if called inside a vblank interval). The function calls into a new optional kms driver entry point dev->driver->get_vblank_timestamp() which is supposed to provide the precise timestamp. If a kms driver doesn't implement the entry point or if the call fails, a simple do_gettimeofday() timestamp is returned as crude approximation of the true vblank time. A new drm module parameter drm.timestamp_precision_usec allows to disable high precision timestamps (if set to zero) or to specify the maximum acceptable error in the timestamps in microseconds. Kms drivers could implement their get_vblank_timestamp() function in a gpu specific way, as long as returned timestamps conform to OML_sync_control, e.g., by use of gpu specific hardware timestamps. Optionally, kms drivers can simply wrap and use the new utility function drm_calc_vbltimestamp_from_scanoutpos(). This function calls a new optional kms driver function dev->driver->get_scanout_position() which returns the current horizontal and vertical video scanout position of the crtc. The scanout position together with the drm_display_timing of the current video mode is used to calculate elapsed time relative to start of active scanout for the current video frame. This elapsed time is subtracted from the current do_gettimeofday() time to get the timestamp corresponding to start of video scanout. Currently non-interlaced, non-doublescan video modes, with or without panel scaling are handled correctly. Interlaced/ doublescan modes are tbd in a future patch. 3. Filtering of redundant vblank irq's and removal of some race-conditions in the vblank irq enable/disable path: Some gpu's (e.g., Radeon R500/R600) send spurious vblank irq's outside the vblank if vblank irq's get reenabled. These get detected by use of the vblank timestamps and filtered out to avoid miscounting of vblanks. Some race-conditions between the vblank irq enable/disable functions, the vblank irq handler and the gpu itself (updating its hardware vblank counter in the "wrong" moment) are fixed inside vblank_disable_and_save() and drm_update_vblank_count() by use of the vblank timestamps and a new spinlock dev->vblank_time_lock. The time until vblank irq disable is now configurable via a new drm module parameter drm.vblankoffdelay to allow experimentation with timeouts that are much shorter than the current 5 seconds and should allow longer vblank off periods for better power savings. Followup patches will use these new functions to implement precise timestamping for the intel and radeon kms drivers. Signed-off-by: Mario Kleiner Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 13 +- drivers/gpu/drm/drm_irq.c | 563 ++++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/drm_stub.c | 10 + include/drm/drmP.h | 93 +++++++ include/drm/drm_crtc.h | 9 + 5 files changed, 662 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index f7af91cb273d..4c200931a6bc 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -336,7 +336,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; - struct drm_display_mode *adjusted_mode, saved_mode; + struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_encoder_helper_funcs *encoder_funcs; int saved_x, saved_y; @@ -350,6 +350,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (!crtc->enabled) return true; + saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; saved_x = crtc->x; saved_y = crtc->y; @@ -427,11 +428,21 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, } + /* Store real post-adjustment hardware mode. */ + crtc->hwmode = *adjusted_mode; + + /* Calculate and store various constants which + * are later needed by vblank and swap-completion + * timestamping. They are derived from true hwmode. + */ + drm_calc_timestamping_constants(crtc); + /* XXX free adjustedmode */ drm_mode_destroy(dev, adjusted_mode); /* FIXME: add subpixel order */ done: if (!ret) { + crtc->hwmode = saved_hwmode; crtc->mode = saved_mode; crtc->x = saved_x; crtc->y = saved_y; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 9d3a5030b6e1..4e82d0d3c378 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -40,6 +40,22 @@ #include #include + +/* Access macro for slots in vblank timestamp ringbuffer. */ +#define vblanktimestamp(dev, crtc, count) ( \ + (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \ + ((count) % DRM_VBLANKTIME_RBSIZE)]) + +/* Retry timestamp calculation up to 3 times to satisfy + * drm_timestamp_precision before giving up. + */ +#define DRM_TIMESTAMP_MAXRETRIES 3 + +/* Threshold in nanoseconds for detection of redundant + * vblank irq in drm_handle_vblank(). 1 msec should be ok. + */ +#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 + /** * Get interrupt from bus id. * @@ -77,6 +93,87 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, return 0; } +/* + * Clear vblank timestamp buffer for a crtc. + */ +static void clear_vblank_timestamps(struct drm_device *dev, int crtc) +{ + memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0, + DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval)); +} + +/* + * Disable vblank irq's on crtc, make sure that last vblank count + * of hardware and corresponding consistent software vblank counter + * are preserved, even if there are any spurious vblank irq's after + * disable. + */ +static void vblank_disable_and_save(struct drm_device *dev, int crtc) +{ + unsigned long irqflags; + u32 vblcount; + s64 diff_ns; + int vblrc; + struct timeval tvblank; + + /* Prevent vblank irq processing while disabling vblank irqs, + * so no updates of timestamps or count can happen after we've + * disabled. Needed to prevent races in case of delayed irq's. + * Disable preemption, so vblank_time_lock is held as short as + * possible, even under a kernel with PREEMPT_RT patches. + */ + preempt_disable(); + spin_lock_irqsave(&dev->vblank_time_lock, irqflags); + + dev->driver->disable_vblank(dev, crtc); + dev->vblank_enabled[crtc] = 0; + + /* No further vblank irq's will be processed after + * this point. Get current hardware vblank count and + * vblank timestamp, repeat until they are consistent. + * + * FIXME: There is still a race condition here and in + * drm_update_vblank_count() which can cause off-by-one + * reinitialization of software vblank counter. If gpu + * vblank counter doesn't increment exactly at the leading + * edge of a vblank interval, then we can lose 1 count if + * we happen to execute between start of vblank and the + * delayed gpu counter increment. + */ + do { + dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); + vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); + } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc)); + + /* Compute time difference to stored timestamp of last vblank + * as updated by last invocation of drm_handle_vblank() in vblank irq. + */ + vblcount = atomic_read(&dev->_vblank_count[crtc]); + diff_ns = timeval_to_ns(&tvblank) - + timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); + + /* If there is at least 1 msec difference between the last stored + * timestamp and tvblank, then we are currently executing our + * disable inside a new vblank interval, the tvblank timestamp + * corresponds to this new vblank interval and the irq handler + * for this vblank didn't run yet and won't run due to our disable. + * Therefore we need to do the job of drm_handle_vblank() and + * increment the vblank counter by one to account for this vblank. + * + * Skip this step if there isn't any high precision timestamp + * available. In that case we can't account for this and just + * hope for the best. + */ + if ((vblrc > 0) && (abs(diff_ns) > 1000000)) + atomic_inc(&dev->_vblank_count[crtc]); + + /* Invalidate all timestamps while vblank irq's are off. */ + clear_vblank_timestamps(dev, crtc); + + spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); + preempt_enable(); +} + static void vblank_disable_fn(unsigned long arg) { struct drm_device *dev = (struct drm_device *)arg; @@ -91,10 +188,7 @@ static void vblank_disable_fn(unsigned long arg) if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { DRM_DEBUG("disabling vblank on crtc %d\n", i); - dev->last_vblank[i] = - dev->driver->get_vblank_counter(dev, i); - dev->driver->disable_vblank(dev, i); - dev->vblank_enabled[i] = 0; + vblank_disable_and_save(dev, i); } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } @@ -117,6 +211,7 @@ void drm_vblank_cleanup(struct drm_device *dev) kfree(dev->last_vblank); kfree(dev->last_vblank_wait); kfree(dev->vblank_inmodeset); + kfree(dev->_vblank_time); dev->num_crtcs = 0; } @@ -129,6 +224,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, (unsigned long)dev); spin_lock_init(&dev->vbl_lock); + spin_lock_init(&dev->vblank_time_lock); + dev->num_crtcs = num_crtcs; dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs, @@ -161,6 +258,19 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_inmodeset) goto err; + dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE, + sizeof(struct timeval), GFP_KERNEL); + if (!dev->_vblank_time) + goto err; + + DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n"); + + /* Driver specific high-precision vblank timestamping supported? */ + if (dev->driver->get_vblank_timestamp) + DRM_INFO("Driver supports precise vblank timestamp query.\n"); + else + DRM_INFO("No driver support for vblank timestamp query.\n"); + /* Zero per-crtc vblank stuff */ for (i = 0; i < num_crtcs; i++) { init_waitqueue_head(&dev->vbl_queue[i]); @@ -279,7 +389,7 @@ EXPORT_SYMBOL(drm_irq_install); * * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq. */ -int drm_irq_uninstall(struct drm_device * dev) +int drm_irq_uninstall(struct drm_device *dev) { unsigned long irqflags; int irq_enabled, i; @@ -335,7 +445,9 @@ int drm_control(struct drm_device *dev, void *data, { struct drm_control *ctl = data; - /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */ + /* if we haven't irq we fallback for compatibility reasons - + * this used to be a separate function in drm_dma.h + */ switch (ctl->func) { @@ -359,6 +471,287 @@ int drm_control(struct drm_device *dev, void *data, } } +/** + * drm_calc_timestamping_constants - Calculate and + * store various constants which are later needed by + * vblank and swap-completion timestamping, e.g, by + * drm_calc_vbltimestamp_from_scanoutpos(). + * They are derived from crtc's true scanout timing, + * so they take things like panel scaling or other + * adjustments into account. + * + * @crtc drm_crtc whose timestamp constants should be updated. + * + */ +void drm_calc_timestamping_constants(struct drm_crtc *crtc) +{ + s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; + u64 dotclock; + + /* Dot clock in Hz: */ + dotclock = (u64) crtc->hwmode.clock * 1000; + + /* Valid dotclock? */ + if (dotclock > 0) { + /* Convert scanline length in pixels and video dot clock to + * line duration, frame duration and pixel duration in + * nanoseconds: + */ + pixeldur_ns = (s64) div64_u64(1000000000, dotclock); + linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * + 1000000000), dotclock); + framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns; + } else + DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", + crtc->base.id); + + crtc->pixeldur_ns = pixeldur_ns; + crtc->linedur_ns = linedur_ns; + crtc->framedur_ns = framedur_ns; + + DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", + crtc->base.id, crtc->hwmode.crtc_htotal, + crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); + DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", + crtc->base.id, (int) dotclock/1000, (int) framedur_ns, + (int) linedur_ns, (int) pixeldur_ns); +} +EXPORT_SYMBOL(drm_calc_timestamping_constants); + +/** + * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms + * drivers. Implements calculation of exact vblank timestamps from + * given drm_display_mode timings and current video scanout position + * of a crtc. This can be called from within get_vblank_timestamp() + * implementation of a kms driver to implement the actual timestamping. + * + * Should return timestamps conforming to the OML_sync_control OpenML + * extension specification. The timestamp corresponds to the end of + * the vblank interval, aka start of scanout of topmost-leftmost display + * pixel in the following video frame. + * + * Requires support for optional dev->driver->get_scanout_position() + * in kms driver, plus a bit of setup code to provide a drm_display_mode + * that corresponds to the true scanout timing. + * + * The current implementation only handles standard video modes. It + * returns as no operation if a doublescan or interlaced video mode is + * active. Higher level code is expected to handle this. + * + * @dev: DRM device. + * @crtc: Which crtc's vblank timestamp to retrieve. + * @max_error: Desired maximum allowable error in timestamps (nanosecs). + * On return contains true maximum error of timestamp. + * @vblank_time: Pointer to struct timeval which should receive the timestamp. + * @flags: Flags to pass to driver: + * 0 = Default. + * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. + * @refcrtc: drm_crtc* of crtc which defines scanout timing. + * + * Returns negative value on error, failure or if not supported in current + * video mode: + * + * -EINVAL - Invalid crtc. + * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. + * -ENOTSUPP - Function not supported in current display mode. + * -EIO - Failed, e.g., due to failed scanout position query. + * + * Returns or'ed positive status flags on success: + * + * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. + * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. + * + */ +int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags, + struct drm_crtc *refcrtc) +{ + struct timeval stime, raw_time; + struct drm_display_mode *mode; + int vbl_status, vtotal, vdisplay; + int vpos, hpos, i; + s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; + bool invbl; + + if (crtc < 0 || crtc >= dev->num_crtcs) { + DRM_ERROR("Invalid crtc %d\n", crtc); + return -EINVAL; + } + + /* Scanout position query not supported? Should not happen. */ + if (!dev->driver->get_scanout_position) { + DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); + return -EIO; + } + + mode = &refcrtc->hwmode; + vtotal = mode->crtc_vtotal; + vdisplay = mode->crtc_vdisplay; + + /* Durations of frames, lines, pixels in nanoseconds. */ + framedur_ns = refcrtc->framedur_ns; + linedur_ns = refcrtc->linedur_ns; + pixeldur_ns = refcrtc->pixeldur_ns; + + /* If mode timing undefined, just return as no-op: + * Happens during initial modesetting of a crtc. + */ + if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { + DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); + return -EAGAIN; + } + + /* Don't know yet how to handle interlaced or + * double scan modes. Just no-op for now. + */ + if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) { + DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc); + return -ENOTSUPP; + } + + /* Get current scanout position with system timestamp. + * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times + * if single query takes longer than max_error nanoseconds. + * + * This guarantees a tight bound on maximum error if + * code gets preempted or delayed for some reason. + */ + for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { + /* Disable preemption to make it very likely to + * succeed in the first iteration even on PREEMPT_RT kernel. + */ + preempt_disable(); + + /* Get system timestamp before query. */ + do_gettimeofday(&stime); + + /* Get vertical and horizontal scanout pos. vpos, hpos. */ + vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos); + + /* Get system timestamp after query. */ + do_gettimeofday(&raw_time); + + preempt_enable(); + + /* Return as no-op if scanout query unsupported or failed. */ + if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { + DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", + crtc, vbl_status); + return -EIO; + } + + duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime); + + /* Accept result with < max_error nsecs timing uncertainty. */ + if (duration_ns <= (s64) *max_error) + break; + } + + /* Noisy system timing? */ + if (i == DRM_TIMESTAMP_MAXRETRIES) { + DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", + crtc, (int) duration_ns/1000, *max_error/1000, i); + } + + /* Return upper bound of timestamp precision error. */ + *max_error = (int) duration_ns; + + /* Check if in vblank area: + * vpos is >=0 in video scanout area, but negative + * within vblank area, counting down the number of lines until + * start of scanout. + */ + invbl = vbl_status & DRM_SCANOUTPOS_INVBL; + + /* Convert scanout position into elapsed time at raw_time query + * since start of scanout at first display scanline. delta_ns + * can be negative if start of scanout hasn't happened yet. + */ + delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; + + /* Is vpos outside nominal vblank area, but less than + * 1/100 of a frame height away from start of vblank? + * If so, assume this isn't a massively delayed vblank + * interrupt, but a vblank interrupt that fired a few + * microseconds before true start of vblank. Compensate + * by adding a full frame duration to the final timestamp. + * Happens, e.g., on ATI R500, R600. + * + * We only do this if DRM_CALLED_FROM_VBLIRQ. + */ + if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && + ((vdisplay - vpos) < vtotal / 100)) { + delta_ns = delta_ns - framedur_ns; + + /* Signal this correction as "applied". */ + vbl_status |= 0x8; + } + + /* Subtract time delta from raw timestamp to get final + * vblank_time timestamp for end of vblank. + */ + *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns); + + DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n", + crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec, + raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec, + (int) duration_ns/1000, i); + + vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; + if (invbl) + vbl_status |= DRM_VBLANKTIME_INVBL; + + return vbl_status; +} +EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); + +/** + * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent + * vblank interval. + * + * @dev: DRM device + * @crtc: which crtc's vblank timestamp to retrieve + * @tvblank: Pointer to target struct timeval which should receive the timestamp + * @flags: Flags to pass to driver: + * 0 = Default. + * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. + * + * Fetches the system timestamp corresponding to the time of the most recent + * vblank interval on specified crtc. May call into kms-driver to + * compute the timestamp with a high-precision GPU specific method. + * + * Returns zero if timestamp originates from uncorrected do_gettimeofday() + * call, i.e., it isn't very precisely locked to the true vblank. + * + * Returns non-zero if timestamp is considered to be very precise. + */ +u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, + struct timeval *tvblank, unsigned flags) +{ + int ret = 0; + + /* Define requested maximum error on timestamps (nanoseconds). */ + int max_error = (int) drm_timestamp_precision * 1000; + + /* Query driver if possible and precision timestamping enabled. */ + if (dev->driver->get_vblank_timestamp && (max_error > 0)) { + ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, + tvblank, flags); + if (ret > 0) + return (u32) ret; + } + + /* GPU high precision timestamp query unsupported or failed. + * Return gettimeofday timestamp as best estimate. + */ + do_gettimeofday(tvblank); + + return 0; +} +EXPORT_SYMBOL(drm_get_last_vbltimestamp); + /** * drm_vblank_count - retrieve "cooked" vblank counter value * @dev: DRM device @@ -374,6 +767,40 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_count); +/** + * drm_vblank_count_and_time - retrieve "cooked" vblank counter value + * and the system timestamp corresponding to that vblank counter value. + * + * @dev: DRM device + * @crtc: which counter to retrieve + * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. + * + * Fetches the "cooked" vblank count value that represents the number of + * vblank events since the system was booted, including lost events due to + * modesetting activity. Returns corresponding system timestamp of the time + * of the vblank interval that corresponds to the current value vblank counter + * value. + */ +u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, + struct timeval *vblanktime) +{ + u32 cur_vblank; + + /* Read timestamp from slot of _vblank_time ringbuffer + * that corresponds to current vblank count. Retry if + * count has incremented during readout. This works like + * a seqlock. + */ + do { + cur_vblank = atomic_read(&dev->_vblank_count[crtc]); + *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); + smp_rmb(); + } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); + + return cur_vblank; +} +EXPORT_SYMBOL(drm_vblank_count_and_time); + /** * drm_update_vblank_count - update the master vblank counter * @dev: DRM device @@ -392,7 +819,8 @@ EXPORT_SYMBOL(drm_vblank_count); */ static void drm_update_vblank_count(struct drm_device *dev, int crtc) { - u32 cur_vblank, diff; + u32 cur_vblank, diff, tslot, rc; + struct timeval t_vblank; /* * Interrupts were disabled prior to this call, so deal with counter @@ -400,8 +828,18 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) * NOTE! It's possible we lost a full dev->max_vblank_count events * here if the register is small or we had vblank interrupts off for * a long time. + * + * We repeat the hardware vblank counter & timestamp query until + * we get consistent results. This to prevent races between gpu + * updating its hardware counter while we are retrieving the + * corresponding vblank timestamp. */ - cur_vblank = dev->driver->get_vblank_counter(dev, crtc); + do { + cur_vblank = dev->driver->get_vblank_counter(dev, crtc); + rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); + } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); + + /* Deal with counter wrap */ diff = cur_vblank - dev->last_vblank[crtc]; if (cur_vblank < dev->last_vblank[crtc]) { diff += dev->max_vblank_count; @@ -413,6 +851,16 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); + /* Reinitialize corresponding vblank timestamp if high-precision query + * available. Skip this step if query unsupported or failed. Will + * reinitialize delayed at next vblank interrupt in that case. + */ + if (rc) { + tslot = atomic_read(&dev->_vblank_count[crtc]) + diff; + vblanktimestamp(dev, crtc, tslot) = t_vblank; + smp_wmb(); + } + atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -429,15 +877,27 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) */ int drm_vblank_get(struct drm_device *dev, int crtc) { - unsigned long irqflags; + unsigned long irqflags, irqflags2; int ret = 0; spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { + /* Disable preemption while holding vblank_time_lock. Do + * it explicitely to guard against PREEMPT_RT kernel. + */ + preempt_disable(); + spin_lock_irqsave(&dev->vblank_time_lock, irqflags2); if (!dev->vblank_enabled[crtc]) { + /* Enable vblank irqs under vblank_time_lock protection. + * All vblank count & timestamp updates are held off + * until we are done reinitializing master counter and + * timestamps. Filtercode in drm_handle_vblank() will + * prevent double-accounting of same vblank interval. + */ ret = dev->driver->enable_vblank(dev, crtc); - DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); + DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", + crtc, ret); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); else { @@ -445,6 +905,8 @@ int drm_vblank_get(struct drm_device *dev, int crtc) drm_update_vblank_count(dev, crtc); } } + spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2); + preempt_enable(); } else { if (!dev->vblank_enabled[crtc]) { atomic_dec(&dev->vblank_refcount[crtc]); @@ -463,15 +925,17 @@ EXPORT_SYMBOL(drm_vblank_get); * @crtc: which counter to give up * * Release ownership of a given vblank counter, turning off interrupts - * if possible. + * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. */ void drm_vblank_put(struct drm_device *dev, int crtc) { - BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0); + BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0); /* Last user schedules interrupt disable */ - if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) - mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); + if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) && + (drm_vblank_offdelay > 0)) + mod_timer(&dev->vblank_disable_timer, + jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000)); } EXPORT_SYMBOL(drm_vblank_put); @@ -480,10 +944,8 @@ void drm_vblank_off(struct drm_device *dev, int crtc) unsigned long irqflags; spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->driver->disable_vblank(dev, crtc); + vblank_disable_and_save(dev, crtc); DRM_WAKEUP(&dev->vbl_queue[crtc]); - dev->vblank_enabled[crtc] = 0; - dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); @@ -599,7 +1061,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->base.file_priv = file_priv; e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; - do_gettimeofday(&now); spin_lock_irqsave(&dev->event_lock, flags); if (file_priv->event_space < sizeof e->event) { @@ -609,7 +1070,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, } file_priv->event_space -= sizeof e->event; - seq = drm_vblank_count(dev, pipe); + seq = drm_vblank_count_and_time(dev, pipe, &now); + if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && (seq - vblwait->request.sequence) <= (1 << 23)) { vblwait->request.sequence = seq + 1; @@ -718,11 +1180,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (ret != -EINTR) { struct timeval now; - do_gettimeofday(&now); - + vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now); vblwait->reply.tval_sec = now.tv_sec; vblwait->reply.tval_usec = now.tv_usec; - vblwait->reply.sequence = drm_vblank_count(dev, crtc); + DRM_DEBUG("returning %d to client\n", vblwait->reply.sequence); } else { @@ -741,8 +1202,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) unsigned long flags; unsigned int seq; - do_gettimeofday(&now); - seq = drm_vblank_count(dev, crtc); + seq = drm_vblank_count_and_time(dev, crtc, &now); spin_lock_irqsave(&dev->event_lock, flags); @@ -780,11 +1240,64 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) */ void drm_handle_vblank(struct drm_device *dev, int crtc) { + u32 vblcount; + s64 diff_ns; + struct timeval tvblank; + unsigned long irqflags; + if (!dev->num_crtcs) return; - atomic_inc(&dev->_vblank_count[crtc]); + /* Need timestamp lock to prevent concurrent execution with + * vblank enable/disable, as this would cause inconsistent + * or corrupted timestamps and vblank counts. + */ + spin_lock_irqsave(&dev->vblank_time_lock, irqflags); + + /* Vblank irq handling disabled. Nothing to do. */ + if (!dev->vblank_enabled[crtc]) { + spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); + return; + } + + /* Fetch corresponding timestamp for this vblank interval from + * driver and store it in proper slot of timestamp ringbuffer. + */ + + /* Get current timestamp and count. */ + vblcount = atomic_read(&dev->_vblank_count[crtc]); + drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); + + /* Compute time difference to timestamp of last vblank */ + diff_ns = timeval_to_ns(&tvblank) - + timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); + + /* Update vblank timestamp and count if at least + * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds + * difference between last stored timestamp and current + * timestamp. A smaller difference means basically + * identical timestamps. Happens if this vblank has + * been already processed and this is a redundant call, + * e.g., due to spurious vblank interrupts. We need to + * ignore those for accounting. + */ + if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { + /* Store new timestamp in ringbuffer. */ + vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; + smp_wmb(); + + /* Increment cooked vblank count. This also atomically commits + * the timestamp computed above. + */ + atomic_inc(&dev->_vblank_count[crtc]); + } else { + DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", + crtc, (int) diff_ns); + } + DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_handle_vblank_events(dev, crtc); + + spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); } EXPORT_SYMBOL(drm_handle_vblank); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index cdc89ee042cc..d59edc18301f 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -40,12 +40,22 @@ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); +unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ +EXPORT_SYMBOL(drm_vblank_offdelay); + +unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ +EXPORT_SYMBOL(drm_timestamp_precision); + MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output"); +MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); +MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); module_param_named(debug, drm_debug, int, 0600); +module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); +module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); struct idr drm_minors_idr; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 274eaaa15c36..2b3398004aa5 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -683,6 +683,21 @@ struct drm_master { void *driver_priv; /**< Private structure for driver to use */ }; +/* Size of ringbuffer for vblank timestamps. Just double-buffer + * in initial implementation. + */ +#define DRM_VBLANKTIME_RBSIZE 2 + +/* Flags and return codes for get_vblank_timestamp() driver function. */ +#define DRM_CALLED_FROM_VBLIRQ 1 +#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) +#define DRM_VBLANKTIME_INVBL (1 << 1) + +/* get_scanout_position() return flags */ +#define DRM_SCANOUTPOS_VALID (1 << 0) +#define DRM_SCANOUTPOS_INVBL (1 << 1) +#define DRM_SCANOUTPOS_ACCURATE (1 << 2) + /** * DRM driver structure. This structure represent the common code for * a family of cards. There will one drm_device for each card present @@ -760,6 +775,68 @@ struct drm_driver { */ int (*device_is_agp) (struct drm_device *dev); + /** + * Called by vblank timestamping code. + * + * Return the current display scanout position from a crtc. + * + * \param dev DRM device. + * \param crtc Id of the crtc to query. + * \param *vpos Target location for current vertical scanout position. + * \param *hpos Target location for current horizontal scanout position. + * + * Returns vpos as a positive number while in active scanout area. + * Returns vpos as a negative number inside vblank, counting the number + * of scanlines to go until end of vblank, e.g., -1 means "one scanline + * until start of active scanout / end of vblank." + * + * \return Flags, or'ed together as follows: + * + * DRM_SCANOUTPOS_VALID = Query successfull. + * DRM_SCANOUTPOS_INVBL = Inside vblank. + * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of + * this flag means that returned position may be offset by a constant + * but unknown small number of scanlines wrt. real scanout position. + * + */ + int (*get_scanout_position) (struct drm_device *dev, int crtc, + int *vpos, int *hpos); + + /** + * Called by \c drm_get_last_vbltimestamp. Should return a precise + * timestamp when the most recent VBLANK interval ended or will end. + * + * Specifically, the timestamp in @vblank_time should correspond as + * closely as possible to the time when the first video scanline of + * the video frame after the end of VBLANK will start scanning out, + * the time immmediately after end of the VBLANK interval. If the + * @crtc is currently inside VBLANK, this will be a time in the future. + * If the @crtc is currently scanning out a frame, this will be the + * past start time of the current scanout. This is meant to adhere + * to the OpenML OML_sync_control extension specification. + * + * \param dev dev DRM device handle. + * \param crtc crtc for which timestamp should be returned. + * \param *max_error Maximum allowable timestamp error in nanoseconds. + * Implementation should strive to provide timestamp + * with an error of at most *max_error nanoseconds. + * Returns true upper bound on error for timestamp. + * \param *vblank_time Target location for returned vblank timestamp. + * \param flags 0 = Defaults, no special treatment needed. + * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank + * irq handler. Some drivers need to apply some workarounds + * for gpu-specific vblank irq quirks if flag is set. + * + * \returns + * Zero if timestamping isn't supported in current display mode or a + * negative number on failure. A positive status code on success, + * which describes how the vblank_time timestamp was computed. + */ + int (*get_vblank_timestamp) (struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags); + /* these have to be filled in */ irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); @@ -983,6 +1060,8 @@ struct drm_device { wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ + struct timeval *_vblank_time; /**< timestamp of current vblank_count (drivers must alloc right number of fields) */ + spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ spinlock_t vbl_lock; atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ @@ -1284,11 +1363,22 @@ extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); +extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, + struct timeval *vblanktime); extern void drm_handle_vblank(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); extern void drm_vblank_cleanup(struct drm_device *dev); +extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, + struct timeval *tvblank, unsigned flags); +extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, + int crtc, int *max_error, + struct timeval *vblank_time, + unsigned flags, + struct drm_crtc *refcrtc); +extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); + /* Modesetting support */ extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc); @@ -1340,6 +1430,9 @@ extern void drm_put_dev(struct drm_device *dev); extern int drm_put_minor(struct drm_minor **minor); extern unsigned int drm_debug; +extern unsigned int drm_vblank_offdelay; +extern unsigned int drm_timestamp_precision; + extern struct class *drm_class; extern struct proc_dir_entry *drm_proc_root; extern struct dentry *drm_debugfs_root; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 029aa688e787..acd7fade160d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -351,8 +351,14 @@ struct drm_crtc { bool enabled; + /* Requested mode from modesetting. */ struct drm_display_mode mode; + /* Programmed mode in hw, after adjustments for encoders, + * crtc, panel scaling etc. Needed for timestamping etc. + */ + struct drm_display_mode hwmode; + int x, y; const struct drm_crtc_funcs *funcs; @@ -360,6 +366,9 @@ struct drm_crtc { uint32_t gamma_size; uint16_t *gamma_store; + /* Constants needed for precise vblank and swap timestamping. */ + s64 framedur_ns, linedur_ns, pixeldur_ns; + /* if you are using the helper */ void *helper_private; }; -- cgit v1.2.3 From f5a8020903932624cf020dc72455a10a3e005087 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Sat, 23 Oct 2010 04:42:17 +0200 Subject: drm/kms/radeon: Add support for precise vblank timestamping. This patch adds new functions for use by the drm core: .get_vblank_timestamp() provides a precise timestamp for the end of the most recent (or current) vblank interval of a given crtc, as needed for the DRI2 implementation of the OML_sync_control extension. It is a thin wrapper around the drm function drm_calc_vbltimestamp_from_scanoutpos() which does almost all the work and is shared across drivers. .get_scanout_position() provides the current horizontal and vertical video scanout position and "in vblank" status of a given crtc, as needed by the drm for use by drm_calc_vbltimestamp_from_scanoutpos(). The function is also used by the dynamic gpu reclocking code to determine when it is safe to reclock inside vblank. For that purpose radeon_pm_in_vbl() is modified to accomodate a small change in the function prototype of the radeon_get_crtc_scanoutpos() which is hooked up to .get_scanout_position(). This code has been tested on AVIVO hardware, a RV530 (ATI Mobility Radeon X1600) in a Intel Core-2 Duo MacBookPro and some R600 variant (FireGL V7600) in a single cpu AMD Athlon 64 PC. Signed-off-by: Mario Kleiner Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 40 +++++++++++++++++---------------- drivers/gpu/drm/radeon/radeon_drv.c | 8 +++++++ drivers/gpu/drm/radeon/radeon_kms.c | 21 +++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 7 ++---- drivers/gpu/drm/radeon/radeon_pm.c | 6 ++--- 5 files changed, 55 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1df4dc6c063c..eeea7cbb9517 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1019,7 +1019,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, /* * Retrieve current video scanout position of crtc on a given gpu. * - * \param rdev Device to query. + * \param dev Device to query. * \param crtc Crtc to query. * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. @@ -1031,72 +1031,74 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * * \return Flags, or'ed together as follows: * - * RADEON_SCANOUTPOS_VALID = Query successfull. - * RADEON_SCANOUTPOS_INVBL = Inside vblank. - * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of + * DRM_SCANOUTPOS_VALID = Query successfull. + * DRM_SCANOUTPOS_INVBL = Inside vblank. + * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of * this flag means that returned position may be offset by a constant but * unknown small number of scanlines wrt. real scanout position. * */ -int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos) +int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos) { u32 stat_crtc = 0, vbl = 0, position = 0; int vbl_start, vbl_end, vtotal, ret = 0; bool in_vbl = true; + struct radeon_device *rdev = dev->dev_private; + if (ASIC_IS_DCE4(rdev)) { if (crtc == 0) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC0_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC0_REGISTER_OFFSET); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 1) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC1_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC1_REGISTER_OFFSET); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 2) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC2_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC2_REGISTER_OFFSET); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 3) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC3_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC3_REGISTER_OFFSET); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 4) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC4_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC4_REGISTER_OFFSET); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 5) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC5_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC5_REGISTER_OFFSET); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } } else if (ASIC_IS_AVIVO(rdev)) { if (crtc == 0) { vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 1) { vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } } else { /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */ @@ -1112,7 +1114,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, if (!(stat_crtc & 1)) in_vbl = false; - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } if (crtc == 1) { vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) & @@ -1122,7 +1124,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, if (!(stat_crtc & 1)) in_vbl = false; - ret |= RADEON_SCANOUTPOS_VALID; + ret |= DRM_SCANOUTPOS_VALID; } } @@ -1133,13 +1135,13 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, /* Valid vblank area boundaries from gpu retrieved? */ if (vbl > 0) { /* Yes: Decode. */ - ret |= RADEON_SCANOUTPOS_ACCURATE; + ret |= DRM_SCANOUTPOS_ACCURATE; vbl_start = vbl & 0x1fff; vbl_end = (vbl >> 16) & 0x1fff; } else { /* No: Fake something reasonable which gives at least ok results. */ - vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay; + vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; vbl_end = 0; } @@ -1155,7 +1157,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, /* Inside "upper part" of vblank area? Apply corrective offset if so: */ if (in_vbl && (*vpos >= vbl_start)) { - vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal; + vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; *vpos = *vpos - vtotal; } @@ -1164,7 +1166,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, /* In vblank? */ if (in_vbl) - ret |= RADEON_SCANOUTPOS_INVBL; + ret |= DRM_SCANOUTPOS_INVBL; return ret; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 88e4ea925900..32ec0cc6be92 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -66,6 +66,10 @@ int radeon_resume_kms(struct drm_device *dev); u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc); int radeon_enable_vblank_kms(struct drm_device *dev, int crtc); void radeon_disable_vblank_kms(struct drm_device *dev, int crtc); +int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags); void radeon_driver_irq_preinstall_kms(struct drm_device *dev); int radeon_driver_irq_postinstall_kms(struct drm_device *dev); void radeon_driver_irq_uninstall_kms(struct drm_device *dev); @@ -74,6 +78,8 @@ int radeon_dma_ioctl_kms(struct drm_device *dev, void *data, struct drm_file *file_priv); int radeon_gem_object_init(struct drm_gem_object *obj); void radeon_gem_object_free(struct drm_gem_object *obj); +extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, + int *vpos, int *hpos); extern struct drm_ioctl_desc radeon_ioctls_kms[]; extern int radeon_max_kms_ioctl; int radeon_mmap(struct file *filp, struct vm_area_struct *vma); @@ -277,6 +283,8 @@ static struct drm_driver kms_driver = { .get_vblank_counter = radeon_get_vblank_counter_kms, .enable_vblank = radeon_enable_vblank_kms, .disable_vblank = radeon_disable_vblank_kms, + .get_vblank_timestamp = radeon_get_vblank_timestamp_kms, + .get_scanout_position = radeon_get_crtc_scanoutpos, #if defined(CONFIG_DEBUG_FS) .debugfs_init = radeon_debugfs_init, .debugfs_cleanup = radeon_debugfs_cleanup, diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 8fbbe1c6ebbd..4bf423ca4c12 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -277,6 +277,27 @@ void radeon_disable_vblank_kms(struct drm_device *dev, int crtc) radeon_irq_set(rdev); } +int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags) +{ + struct drm_crtc *drmcrtc; + struct radeon_device *rdev = dev->dev_private; + + if (crtc < 0 || crtc >= dev->num_crtcs) { + DRM_ERROR("Invalid crtc %d\n", crtc); + return -EINVAL; + } + + /* Get associated drm_crtc: */ + drmcrtc = &rdev->mode_info.crtcs[crtc]->base; + + /* Helper routine in DRM core does all the work: */ + return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, + vblank_time, flags, + drmcrtc); +} /* * IOCTL. diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index e301c6f9e059..55856ad0ac41 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -442,10 +442,6 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; -/* radeon_get_crtc_scanoutpos() return flags */ -#define RADEON_SCANOUTPOS_VALID (1 << 0) -#define RADEON_SCANOUTPOS_INVBL (1 << 1) -#define RADEON_SCANOUTPOS_ACCURATE (1 << 2) extern enum radeon_tv_std radeon_combios_get_tv_info(struct radeon_device *rdev); @@ -562,7 +558,8 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); -extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos); +extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, + int *vpos, int *hpos); extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); extern struct edid * diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 8c9b2ef32c68..5eda5e471980 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -720,9 +720,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) */ for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { if (rdev->pm.active_crtcs & (1 << crtc)) { - vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos); - if ((vbl_status & RADEON_SCANOUTPOS_VALID) && - !(vbl_status & RADEON_SCANOUTPOS_INVBL)) + vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos); + if ((vbl_status & DRM_SCANOUTPOS_VALID) && + !(vbl_status & DRM_SCANOUTPOS_INVBL)) in_vbl = false; } } -- cgit v1.2.3 From 6f34be50bd1bdd2ff3c955940e033a80d05f248a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 21 Nov 2010 10:59:01 -0500 Subject: drm/radeon/kms: add pageflip ioctl support (v3) This adds support for dri2 pageflipping. v2: precision updates from Mario Kleiner. v3: Multihead fixes from Mario Kleiner; missing crtc offset add note about update pending bit on pre-avivo chips Signed-off-by: Alex Deucher Signed-off-by: Mario Kleiner Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 301 +++++++++++++++++++++----------- drivers/gpu/drm/radeon/evergreen_reg.h | 6 + drivers/gpu/drm/radeon/r100.c | 74 +++++++- drivers/gpu/drm/radeon/r500_reg.h | 4 + drivers/gpu/drm/radeon/r600.c | 126 +++++++------ drivers/gpu/drm/radeon/r600d.h | 9 + drivers/gpu/drm/radeon/radeon.h | 57 ++++++ drivers/gpu/drm/radeon/radeon_asic.c | 42 +++++ drivers/gpu/drm/radeon/radeon_asic.h | 10 ++ drivers/gpu/drm/radeon/radeon_display.c | 261 +++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_drv.c | 3 +- drivers/gpu/drm/radeon/radeon_irq_kms.c | 39 ++++- drivers/gpu/drm/radeon/radeon_mode.h | 6 + drivers/gpu/drm/radeon/radeon_reg.h | 1 + drivers/gpu/drm/radeon/rs600.c | 116 +++++++++--- drivers/gpu/drm/radeon/rv770.c | 34 ++++ drivers/gpu/drm/radeon/rv770d.h | 7 + 17 files changed, 900 insertions(+), 196 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4dc5b4714c5a..df3f37243222 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -40,6 +40,61 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; + u32 tmp; + + /* make sure flip is at vb rather than hb */ + tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; + WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); + + /* set pageflip to happen anywhere in vblank interval */ + WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); + + /* enable the pflip int */ + radeon_irq_kms_pflip_irq_get(rdev, crtc); +} + +void evergreen_post_page_flip(struct radeon_device *rdev, int crtc) +{ + /* disable the pflip int */ + radeon_irq_kms_pflip_irq_put(rdev, crtc); +} + +u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); + + /* Lock the graphics update lock */ + tmp |= EVERGREEN_GRPH_UPDATE_LOCK; + WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + + /* update the scanout addresses */ + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, + upper_32_bits(crtc_base)); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32)crtc_base); + + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, + upper_32_bits(crtc_base)); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32)crtc_base); + + /* Wait for update_pending to go high. */ + while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING)); + DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); + + /* Unlock the lock, so double-buffering can take place inside vblank */ + tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK; + WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + + /* Return current update_pending status: */ + return RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING; +} + /* get temperature in millidegrees */ u32 evergreen_get_temp(struct radeon_device *rdev) { @@ -2060,6 +2115,7 @@ int evergreen_irq_set(struct radeon_device *rdev) u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; u32 grbm_int_cntl = 0; + u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); @@ -2085,27 +2141,33 @@ int evergreen_irq_set(struct radeon_device *rdev) cp_int_cntl |= RB_INT_ENABLE; cp_int_cntl |= TIME_STAMP_INT_ENABLE; } - if (rdev->irq.crtc_vblank_int[0]) { + if (rdev->irq.crtc_vblank_int[0] || + rdev->irq.pflip[0]) { DRM_DEBUG("evergreen_irq_set: vblank 0\n"); crtc1 |= VBLANK_INT_MASK; } - if (rdev->irq.crtc_vblank_int[1]) { + if (rdev->irq.crtc_vblank_int[1] || + rdev->irq.pflip[1]) { DRM_DEBUG("evergreen_irq_set: vblank 1\n"); crtc2 |= VBLANK_INT_MASK; } - if (rdev->irq.crtc_vblank_int[2]) { + if (rdev->irq.crtc_vblank_int[2] || + rdev->irq.pflip[2]) { DRM_DEBUG("evergreen_irq_set: vblank 2\n"); crtc3 |= VBLANK_INT_MASK; } - if (rdev->irq.crtc_vblank_int[3]) { + if (rdev->irq.crtc_vblank_int[3] || + rdev->irq.pflip[3]) { DRM_DEBUG("evergreen_irq_set: vblank 3\n"); crtc4 |= VBLANK_INT_MASK; } - if (rdev->irq.crtc_vblank_int[4]) { + if (rdev->irq.crtc_vblank_int[4] || + rdev->irq.pflip[4]) { DRM_DEBUG("evergreen_irq_set: vblank 4\n"); crtc5 |= VBLANK_INT_MASK; } - if (rdev->irq.crtc_vblank_int[5]) { + if (rdev->irq.crtc_vblank_int[5] || + rdev->irq.pflip[5]) { DRM_DEBUG("evergreen_irq_set: vblank 5\n"); crtc6 |= VBLANK_INT_MASK; } @@ -2148,6 +2210,13 @@ int evergreen_irq_set(struct radeon_device *rdev) WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); + WREG32(DC_HPD1_INT_CONTROL, hpd1); WREG32(DC_HPD2_INT_CONTROL, hpd2); WREG32(DC_HPD3_INT_CONTROL, hpd3); @@ -2158,79 +2227,92 @@ int evergreen_irq_set(struct radeon_device *rdev) return 0; } -static inline void evergreen_irq_ack(struct radeon_device *rdev, - u32 *disp_int, - u32 *disp_int_cont, - u32 *disp_int_cont2, - u32 *disp_int_cont3, - u32 *disp_int_cont4, - u32 *disp_int_cont5) +static inline void evergreen_irq_ack(struct radeon_device *rdev) { u32 tmp; - *disp_int = RREG32(DISP_INTERRUPT_STATUS); - *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); - *disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); - *disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); - *disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); - *disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); - - if (*disp_int & LB_D1_VBLANK_INTERRUPT) + rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS); + rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); + rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); + rdev->irq.stat_regs.evergreen.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); + rdev->irq.stat_regs.evergreen.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); + rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); + rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); + rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); + + if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED) + WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); + + if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK); - if (*disp_int & LB_D1_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK); - if (*disp_int_cont & LB_D2_VBLANK_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK); - if (*disp_int_cont & LB_D2_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK); - if (*disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK); - if (*disp_int_cont2 & LB_D3_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); - if (*disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); - if (*disp_int_cont3 & LB_D4_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); - if (*disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK); - if (*disp_int_cont4 & LB_D5_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); - if (*disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); - if (*disp_int_cont5 & LB_D6_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); - if (*disp_int & DC_HPD1_INTERRUPT) { + if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { tmp = RREG32(DC_HPD1_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD1_INT_CONTROL, tmp); } - if (*disp_int_cont & DC_HPD2_INTERRUPT) { + if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { tmp = RREG32(DC_HPD2_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD2_INT_CONTROL, tmp); } - if (*disp_int_cont2 & DC_HPD3_INTERRUPT) { + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { tmp = RREG32(DC_HPD3_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD3_INT_CONTROL, tmp); } - if (*disp_int_cont3 & DC_HPD4_INTERRUPT) { + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { tmp = RREG32(DC_HPD4_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD4_INT_CONTROL, tmp); } - if (*disp_int_cont4 & DC_HPD5_INTERRUPT) { + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { tmp = RREG32(DC_HPD5_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD5_INT_CONTROL, tmp); } - if (*disp_int_cont5 & DC_HPD6_INTERRUPT) { + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { tmp = RREG32(DC_HPD5_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD6_INT_CONTROL, tmp); @@ -2239,14 +2321,10 @@ static inline void evergreen_irq_ack(struct radeon_device *rdev, void evergreen_irq_disable(struct radeon_device *rdev) { - u32 disp_int, disp_int_cont, disp_int_cont2; - u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; - r600_disable_interrupts(rdev); /* Wait and acknowledge irq */ mdelay(1); - evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, - &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); + evergreen_irq_ack(rdev); evergreen_disable_interrupt_state(rdev); } @@ -2286,8 +2364,6 @@ int evergreen_irq_process(struct radeon_device *rdev) u32 rptr = rdev->ih.rptr; u32 src_id, src_data; u32 ring_index; - u32 disp_int, disp_int_cont, disp_int_cont2; - u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; unsigned long flags; bool queue_hotplug = false; @@ -2308,8 +2384,7 @@ int evergreen_irq_process(struct radeon_device *rdev) restart_ih: /* display interrupts */ - evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, - &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); + evergreen_irq_ack(rdev); rdev->ih.wptr = wptr; while (rptr != wptr) { @@ -2322,17 +2397,21 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (disp_int & LB_D1_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int &= ~LB_D1_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; DRM_DEBUG("IH: D1 vblank\n"); } break; case 1: /* D1 vline */ - if (disp_int & LB_D1_VLINE_INTERRUPT) { - disp_int &= ~LB_D1_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; DRM_DEBUG("IH: D1 vline\n"); } break; @@ -2344,17 +2423,21 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; DRM_DEBUG("IH: D2 vblank\n"); } break; case 1: /* D2 vline */ - if (disp_int_cont & LB_D2_VLINE_INTERRUPT) { - disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; DRM_DEBUG("IH: D2 vline\n"); } break; @@ -2366,17 +2449,21 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (rdev->irq.pflip[2]) + radeon_crtc_handle_flip(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; DRM_DEBUG("IH: D3 vblank\n"); } break; case 1: /* D3 vline */ - if (disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; DRM_DEBUG("IH: D3 vline\n"); } break; @@ -2388,17 +2475,21 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (rdev->irq.pflip[3]) + radeon_crtc_handle_flip(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; DRM_DEBUG("IH: D4 vblank\n"); } break; case 1: /* D4 vline */ - if (disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; DRM_DEBUG("IH: D4 vline\n"); } break; @@ -2410,17 +2501,21 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (rdev->irq.pflip[4]) + radeon_crtc_handle_flip(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; DRM_DEBUG("IH: D5 vblank\n"); } break; case 1: /* D5 vline */ - if (disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; DRM_DEBUG("IH: D5 vline\n"); } break; @@ -2432,17 +2527,21 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (rdev->irq.pflip[5]) + radeon_crtc_handle_flip(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; DRM_DEBUG("IH: D6 vblank\n"); } break; case 1: /* D6 vline */ - if (disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; DRM_DEBUG("IH: D6 vline\n"); } break; @@ -2454,43 +2553,43 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (disp_int & DC_HPD1_INTERRUPT) { - disp_int &= ~DC_HPD1_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD1\n"); } break; case 1: - if (disp_int_cont & DC_HPD2_INTERRUPT) { - disp_int_cont &= ~DC_HPD2_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD2\n"); } break; case 2: - if (disp_int_cont2 & DC_HPD3_INTERRUPT) { - disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD3\n"); } break; case 3: - if (disp_int_cont3 & DC_HPD4_INTERRUPT) { - disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD4\n"); } break; case 4: - if (disp_int_cont4 & DC_HPD5_INTERRUPT) { - disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD5\n"); } break; case 5: - if (disp_int_cont5 & DC_HPD6_INTERRUPT) { - disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD6\n"); } diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 2330f3a36fd5..c781c92c3451 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -105,6 +105,11 @@ #define EVERGREEN_GRPH_Y_START 0x6830 #define EVERGREEN_GRPH_X_END 0x6834 #define EVERGREEN_GRPH_Y_END 0x6838 +#define EVERGREEN_GRPH_UPDATE 0x6844 +# define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING (1 << 2) +# define EVERGREEN_GRPH_UPDATE_LOCK (1 << 16) +#define EVERGREEN_GRPH_FLIP_CONTROL 0x6848 +# define EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0) /* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */ #define EVERGREEN_CUR_CONTROL 0x6998 @@ -178,6 +183,7 @@ # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) #define EVERGREEN_CRTC_STATUS 0x6e8c #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 +#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 8e10aa9f74b0..b2e29798a99d 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -68,6 +68,54 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +void r100_pre_page_flip(struct radeon_device *rdev, int crtc) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; + u32 tmp; + + /* make sure flip is at vb rather than hb */ + tmp = RREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset); + tmp &= ~RADEON_CRTC_OFFSET_FLIP_CNTL; + WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, tmp); + + /* set pageflip to happen as late as possible in the vblank interval. + * same field for crtc1/2 + */ + tmp = RREG32(RADEON_CRTC_GEN_CNTL); + tmp &= ~RADEON_CRTC_VSTAT_MODE_MASK; + WREG32(RADEON_CRTC_GEN_CNTL, tmp); + + /* enable the pflip int */ + radeon_irq_kms_pflip_irq_get(rdev, crtc); +} + +void r100_post_page_flip(struct radeon_device *rdev, int crtc) +{ + /* disable the pflip int */ + radeon_irq_kms_pflip_irq_put(rdev, crtc); +} + +u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; + + /* Lock the graphics update lock */ + /* update the scanout addresses */ + WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); + + /* Note: We don't wait for update_pending to assert, as this never + * happens for some reason on R1xx - R4xx. Adds a bit of imprecision. + */ + + /* Unlock the lock, so double-buffering can take place inside vblank */ + tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK; + WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); + + /* Return current update_pending status: */ + return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET; +} + void r100_pm_get_dynpm_state(struct radeon_device *rdev) { int i; @@ -526,10 +574,12 @@ int r100_irq_set(struct radeon_device *rdev) if (rdev->irq.gui_idle) { tmp |= RADEON_GUI_IDLE_MASK; } - if (rdev->irq.crtc_vblank_int[0]) { + if (rdev->irq.crtc_vblank_int[0] || + rdev->irq.pflip[0]) { tmp |= RADEON_CRTC_VBLANK_MASK; } - if (rdev->irq.crtc_vblank_int[1]) { + if (rdev->irq.crtc_vblank_int[1] || + rdev->irq.pflip[1]) { tmp |= RADEON_CRTC2_VBLANK_MASK; } if (rdev->irq.hpd[0]) { @@ -600,14 +650,22 @@ int r100_irq_process(struct radeon_device *rdev) } /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } } if (status & RADEON_CRTC2_VBLANK_STAT) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } } if (status & RADEON_FP_DETECT_STAT) { queue_hotplug = true; diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 6ac1f604e29b..fc437059918f 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -355,6 +355,8 @@ #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 +#define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4 + /* master controls */ #define AVIVO_DC_CRTC_MASTER_EN 0x60f8 #define AVIVO_DC_CRTC_TV_CONTROL 0x60fc @@ -409,8 +411,10 @@ #define AVIVO_D1GRPH_X_END 0x6134 #define AVIVO_D1GRPH_Y_END 0x6138 #define AVIVO_D1GRPH_UPDATE 0x6144 +# define AVIVO_D1GRPH_SURFACE_UPDATE_PENDING (1 << 2) # define AVIVO_D1GRPH_UPDATE_LOCK (1 << 16) #define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 +# define AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0) #define AVIVO_D1CUR_CONTROL 0x6400 # define AVIVO_D1CURSOR_EN (1 << 0) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a3552594ccc4..15b95724c408 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2863,6 +2863,8 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev) WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); WREG32(GRBM_INT_CNTL, 0); WREG32(DxMODE_INT_MASK, 0); + WREG32(D1GRPH_INTERRUPT_CONTROL, 0); + WREG32(D2GRPH_INTERRUPT_CONTROL, 0); if (ASIC_IS_DCE3(rdev)) { WREG32(DCE3_DACA_AUTODETECT_INT_CONTROL, 0); WREG32(DCE3_DACB_AUTODETECT_INT_CONTROL, 0); @@ -2987,6 +2989,7 @@ int r600_irq_set(struct radeon_device *rdev) u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; u32 grbm_int_cntl = 0; u32 hdmi1, hdmi2; + u32 d1grph = 0, d2grph = 0; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); @@ -3023,11 +3026,13 @@ int r600_irq_set(struct radeon_device *rdev) cp_int_cntl |= RB_INT_ENABLE; cp_int_cntl |= TIME_STAMP_INT_ENABLE; } - if (rdev->irq.crtc_vblank_int[0]) { + if (rdev->irq.crtc_vblank_int[0] || + rdev->irq.pflip[0]) { DRM_DEBUG("r600_irq_set: vblank 0\n"); mode_int |= D1MODE_VBLANK_INT_MASK; } - if (rdev->irq.crtc_vblank_int[1]) { + if (rdev->irq.crtc_vblank_int[1] || + rdev->irq.pflip[1]) { DRM_DEBUG("r600_irq_set: vblank 1\n"); mode_int |= D2MODE_VBLANK_INT_MASK; } @@ -3070,6 +3075,8 @@ int r600_irq_set(struct radeon_device *rdev) WREG32(CP_INT_CNTL, cp_int_cntl); WREG32(DxMODE_INT_MASK, mode_int); + WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph); + WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph); WREG32(GRBM_INT_CNTL, grbm_int_cntl); WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); if (ASIC_IS_DCE3(rdev)) { @@ -3092,32 +3099,35 @@ int r600_irq_set(struct radeon_device *rdev) return 0; } -static inline void r600_irq_ack(struct radeon_device *rdev, - u32 *disp_int, - u32 *disp_int_cont, - u32 *disp_int_cont2) +static inline void r600_irq_ack(struct radeon_device *rdev) { u32 tmp; if (ASIC_IS_DCE3(rdev)) { - *disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS); - *disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE); - *disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2); + rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS); + rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE); + rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2); } else { - *disp_int = RREG32(DISP_INTERRUPT_STATUS); - *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); - *disp_int_cont2 = 0; - } - - if (*disp_int & LB_D1_VBLANK_INTERRUPT) + rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS); + rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); + rdev->irq.stat_regs.r600.disp_int_cont2 = 0; + } + rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS); + rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS); + + if (rdev->irq.stat_regs.r600.d1grph_int & DxGRPH_PFLIP_INT_OCCURRED) + WREG32(D1GRPH_INTERRUPT_STATUS, DxGRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.r600.d2grph_int & DxGRPH_PFLIP_INT_OCCURRED) + WREG32(D2GRPH_INTERRUPT_STATUS, DxGRPH_PFLIP_INT_CLEAR); + if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) WREG32(D1MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK); - if (*disp_int & LB_D1_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) WREG32(D1MODE_VLINE_STATUS, DxMODE_VLINE_ACK); - if (*disp_int & LB_D2_VBLANK_INTERRUPT) + if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) WREG32(D2MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK); - if (*disp_int & LB_D2_VLINE_INTERRUPT) + if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) WREG32(D2MODE_VLINE_STATUS, DxMODE_VLINE_ACK); - if (*disp_int & DC_HPD1_INTERRUPT) { + if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { if (ASIC_IS_DCE3(rdev)) { tmp = RREG32(DC_HPD1_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; @@ -3128,7 +3138,7 @@ static inline void r600_irq_ack(struct radeon_device *rdev, WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp); } } - if (*disp_int & DC_HPD2_INTERRUPT) { + if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { if (ASIC_IS_DCE3(rdev)) { tmp = RREG32(DC_HPD2_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; @@ -3139,7 +3149,7 @@ static inline void r600_irq_ack(struct radeon_device *rdev, WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp); } } - if (*disp_int_cont & DC_HPD3_INTERRUPT) { + if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { if (ASIC_IS_DCE3(rdev)) { tmp = RREG32(DC_HPD3_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; @@ -3150,18 +3160,18 @@ static inline void r600_irq_ack(struct radeon_device *rdev, WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp); } } - if (*disp_int_cont & DC_HPD4_INTERRUPT) { + if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { tmp = RREG32(DC_HPD4_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD4_INT_CONTROL, tmp); } if (ASIC_IS_DCE32(rdev)) { - if (*disp_int_cont2 & DC_HPD5_INTERRUPT) { + if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { tmp = RREG32(DC_HPD5_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD5_INT_CONTROL, tmp); } - if (*disp_int_cont2 & DC_HPD6_INTERRUPT) { + if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { tmp = RREG32(DC_HPD5_INT_CONTROL); tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD6_INT_CONTROL, tmp); @@ -3183,12 +3193,10 @@ static inline void r600_irq_ack(struct radeon_device *rdev, void r600_irq_disable(struct radeon_device *rdev) { - u32 disp_int, disp_int_cont, disp_int_cont2; - r600_disable_interrupts(rdev); /* Wait and acknowledge irq */ mdelay(1); - r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2); + r600_irq_ack(rdev); r600_disable_interrupt_state(rdev); } @@ -3251,7 +3259,7 @@ int r600_irq_process(struct radeon_device *rdev) u32 wptr = r600_get_ih_wptr(rdev); u32 rptr = rdev->ih.rptr; u32 src_id, src_data; - u32 ring_index, disp_int, disp_int_cont, disp_int_cont2; + u32 ring_index; unsigned long flags; bool queue_hotplug = false; @@ -3272,7 +3280,7 @@ int r600_irq_process(struct radeon_device *rdev) restart_ih: /* display interrupts */ - r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2); + r600_irq_ack(rdev); rdev->ih.wptr = wptr; while (rptr != wptr) { @@ -3285,17 +3293,21 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (disp_int & LB_D1_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int &= ~LB_D1_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) { + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; DRM_DEBUG("IH: D1 vblank\n"); } break; case 1: /* D1 vline */ - if (disp_int & LB_D1_VLINE_INTERRUPT) { - disp_int &= ~LB_D1_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; DRM_DEBUG("IH: D1 vline\n"); } break; @@ -3307,17 +3319,21 @@ restart_ih: case 5: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (disp_int & LB_D2_VBLANK_INTERRUPT) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - disp_int &= ~LB_D2_VBLANK_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) { + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; DRM_DEBUG("IH: D2 vblank\n"); } break; case 1: /* D1 vline */ - if (disp_int & LB_D2_VLINE_INTERRUPT) { - disp_int &= ~LB_D2_VLINE_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; DRM_DEBUG("IH: D2 vline\n"); } break; @@ -3329,43 +3345,43 @@ restart_ih: case 19: /* HPD/DAC hotplug */ switch (src_data) { case 0: - if (disp_int & DC_HPD1_INTERRUPT) { - disp_int &= ~DC_HPD1_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD1\n"); } break; case 1: - if (disp_int & DC_HPD2_INTERRUPT) { - disp_int &= ~DC_HPD2_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD2\n"); } break; case 4: - if (disp_int_cont & DC_HPD3_INTERRUPT) { - disp_int_cont &= ~DC_HPD3_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD3\n"); } break; case 5: - if (disp_int_cont & DC_HPD4_INTERRUPT) { - disp_int_cont &= ~DC_HPD4_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD4\n"); } break; case 10: - if (disp_int_cont2 & DC_HPD5_INTERRUPT) { - disp_int_cont2 &= ~DC_HPD5_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD5\n"); } break; case 12: - if (disp_int_cont2 & DC_HPD6_INTERRUPT) { - disp_int_cont2 &= ~DC_HPD6_INTERRUPT; + if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; queue_hotplug = true; DRM_DEBUG("IH: HPD6\n"); } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index bff4dc4f410f..c89cfa8e0c05 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -728,6 +728,15 @@ /* DCE 3.2 */ # define DC_HPDx_EN (1 << 28) +#define D1GRPH_INTERRUPT_STATUS 0x6158 +#define D2GRPH_INTERRUPT_STATUS 0x6958 +# define DxGRPH_PFLIP_INT_OCCURRED (1 << 0) +# define DxGRPH_PFLIP_INT_CLEAR (1 << 8) +#define D1GRPH_INTERRUPT_CONTROL 0x615c +#define D2GRPH_INTERRUPT_CONTROL 0x695c +# define DxGRPH_PFLIP_INT_MASK (1 << 0) +# define DxGRPH_PFLIP_INT_TYPE (1 << 8) + /* * PM4 */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3a7095743d44..ddf1eca13401 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -377,11 +377,56 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg); /* * IRQS. */ + +struct radeon_unpin_work { + struct work_struct work; + struct radeon_device *rdev; + int crtc_id; + struct radeon_fence *fence; + struct drm_pending_vblank_event *event; + struct radeon_bo *old_rbo; + u64 new_crtc_base; +}; + +struct r500_irq_stat_regs { + u32 disp_int; +}; + +struct r600_irq_stat_regs { + u32 disp_int; + u32 disp_int_cont; + u32 disp_int_cont2; + u32 d1grph_int; + u32 d2grph_int; +}; + +struct evergreen_irq_stat_regs { + u32 disp_int; + u32 disp_int_cont; + u32 disp_int_cont2; + u32 disp_int_cont3; + u32 disp_int_cont4; + u32 disp_int_cont5; + u32 d1grph_int; + u32 d2grph_int; + u32 d3grph_int; + u32 d4grph_int; + u32 d5grph_int; + u32 d6grph_int; +}; + +union radeon_irq_stat_regs { + struct r500_irq_stat_regs r500; + struct r600_irq_stat_regs r600; + struct evergreen_irq_stat_regs evergreen; +}; + struct radeon_irq { bool installed; bool sw_int; /* FIXME: use a define max crtc rather than hardcode it */ bool crtc_vblank_int[6]; + bool pflip[6]; wait_queue_head_t vblank_queue; /* FIXME: use defines for max hpd/dacs */ bool hpd[6]; @@ -392,12 +437,17 @@ struct radeon_irq { bool hdmi[2]; spinlock_t sw_lock; int sw_refcount; + union radeon_irq_stat_regs stat_regs; + spinlock_t pflip_lock[6]; + int pflip_refcount[6]; }; int radeon_irq_kms_init(struct radeon_device *rdev); void radeon_irq_kms_fini(struct radeon_device *rdev); void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev); void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev); +void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc); +void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc); /* * CP & ring. @@ -881,6 +931,10 @@ struct radeon_asic { void (*pm_finish)(struct radeon_device *rdev); void (*pm_init_profile)(struct radeon_device *rdev); void (*pm_get_dynpm_state)(struct radeon_device *rdev); + /* pageflipping */ + void (*pre_page_flip)(struct radeon_device *rdev, int crtc); + u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base); + void (*post_page_flip)(struct radeon_device *rdev, int crtc); }; /* @@ -1344,6 +1398,9 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) #define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev)) #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev)) +#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pre_page_flip((rdev), (crtc)) +#define radeon_page_flip(rdev, crtc, base) rdev->asic->page_flip((rdev), (crtc), (base)) +#define radeon_post_page_flip(rdev, crtc) rdev->asic->post_page_flip((rdev), (crtc)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 64fb89ecbf74..6b126b3f5fa9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -171,6 +171,9 @@ static struct radeon_asic r100_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &r100_pre_page_flip, + .page_flip = &r100_page_flip, + .post_page_flip = &r100_post_page_flip, }; static struct radeon_asic r200_asic = { @@ -215,6 +218,9 @@ static struct radeon_asic r200_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &r100_pre_page_flip, + .page_flip = &r100_page_flip, + .post_page_flip = &r100_post_page_flip, }; static struct radeon_asic r300_asic = { @@ -260,6 +266,9 @@ static struct radeon_asic r300_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &r100_pre_page_flip, + .page_flip = &r100_page_flip, + .post_page_flip = &r100_post_page_flip, }; static struct radeon_asic r300_asic_pcie = { @@ -304,6 +313,9 @@ static struct radeon_asic r300_asic_pcie = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &r100_pre_page_flip, + .page_flip = &r100_page_flip, + .post_page_flip = &r100_post_page_flip, }; static struct radeon_asic r420_asic = { @@ -349,6 +361,9 @@ static struct radeon_asic r420_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &r100_pre_page_flip, + .page_flip = &r100_page_flip, + .post_page_flip = &r100_post_page_flip, }; static struct radeon_asic rs400_asic = { @@ -394,6 +409,9 @@ static struct radeon_asic rs400_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &r100_pre_page_flip, + .page_flip = &r100_page_flip, + .post_page_flip = &r100_post_page_flip, }; static struct radeon_asic rs600_asic = { @@ -439,6 +457,9 @@ static struct radeon_asic rs600_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rs600_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic rs690_asic = { @@ -484,6 +505,9 @@ static struct radeon_asic rs690_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rs600_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic rv515_asic = { @@ -529,6 +553,9 @@ static struct radeon_asic rv515_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rs600_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic r520_asic = { @@ -574,6 +601,9 @@ static struct radeon_asic r520_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rs600_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic r600_asic = { @@ -618,6 +648,9 @@ static struct radeon_asic r600_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r600_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rs600_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic rs780_asic = { @@ -662,6 +695,9 @@ static struct radeon_asic rs780_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &rs780_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rs600_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic rv770_asic = { @@ -706,6 +742,9 @@ static struct radeon_asic rv770_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r600_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .pre_page_flip = &rs600_pre_page_flip, + .page_flip = &rv770_page_flip, + .post_page_flip = &rs600_post_page_flip, }; static struct radeon_asic evergreen_asic = { @@ -749,6 +788,9 @@ static struct radeon_asic evergreen_asic = { .pm_finish = &evergreen_pm_finish, .pm_init_profile = &r600_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .pre_page_flip = &evergreen_pre_page_flip, + .page_flip = &evergreen_page_flip, + .post_page_flip = &evergreen_post_page_flip, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 740988244143..4970eda1bd41 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -130,6 +130,9 @@ extern void r100_pm_prepare(struct radeon_device *rdev); extern void r100_pm_finish(struct radeon_device *rdev); extern void r100_pm_init_profile(struct radeon_device *rdev); extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); +extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc); +extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); +extern void r100_post_page_flip(struct radeon_device *rdev, int crtc); /* * r200,rv250,rs300,rv280 @@ -205,6 +208,9 @@ void rs600_hpd_set_polarity(struct radeon_device *rdev, extern void rs600_pm_misc(struct radeon_device *rdev); extern void rs600_pm_prepare(struct radeon_device *rdev); extern void rs600_pm_finish(struct radeon_device *rdev); +extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc); +extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); +extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc); /* * rs690,rs740 @@ -287,6 +293,7 @@ void rv770_fini(struct radeon_device *rdev); int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); extern void rv770_pm_misc(struct radeon_device *rdev); +extern u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); /* * evergreen @@ -314,5 +321,8 @@ extern int evergreen_cs_parse(struct radeon_cs_parser *p); extern void evergreen_pm_misc(struct radeon_device *rdev); extern void evergreen_pm_prepare(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev); +extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc); +extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); +extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc); #endif diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index eeea7cbb9517..f6493f444faa 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -183,12 +183,273 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc) kfree(radeon_crtc); } +/* + * Handle unpin events outside the interrupt handler proper. + */ +static void radeon_unpin_work_func(struct work_struct *__work) +{ + struct radeon_unpin_work *work = + container_of(__work, struct radeon_unpin_work, work); + int r; + + /* unpin of the old buffer */ + r = radeon_bo_reserve(work->old_rbo, false); + if (likely(r == 0)) { + r = radeon_bo_unpin(work->old_rbo); + if (unlikely(r != 0)) { + DRM_ERROR("failed to unpin buffer after flip\n"); + } + radeon_bo_unreserve(work->old_rbo); + } else + DRM_ERROR("failed to reserve buffer after flip\n"); + kfree(work); +} + +void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + struct radeon_unpin_work *work; + struct drm_pending_vblank_event *e; + struct timeval now; + unsigned long flags; + u32 update_pending; + int vpos, hpos; + + spin_lock_irqsave(&rdev->ddev->event_lock, flags); + work = radeon_crtc->unpin_work; + if (work == NULL || + !radeon_fence_signaled(work->fence)) { + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); + return; + } + /* New pageflip, or just completion of a previous one? */ + if (!radeon_crtc->deferred_flip_completion) { + /* do the flip (mmio) */ + update_pending = radeon_page_flip(rdev, crtc_id, work->new_crtc_base); + } else { + /* This is just a completion of a flip queued in crtc + * at last invocation. Make sure we go directly to + * completion routine. + */ + update_pending = 0; + radeon_crtc->deferred_flip_completion = 0; + } + + /* Has the pageflip already completed in crtc, or is it certain + * to complete in this vblank? + */ + if (update_pending && + (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, + &vpos, &hpos)) && + (vpos >=0) && + (vpos < (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100)) { + /* crtc didn't flip in this target vblank interval, + * but flip is pending in crtc. It will complete it + * in next vblank interval, so complete the flip at + * next vblank irq. + */ + radeon_crtc->deferred_flip_completion = 1; + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); + return; + } + + /* Pageflip (will be) certainly completed in this vblank. Clean up. */ + radeon_crtc->unpin_work = NULL; + + /* wakeup userspace */ + if (work->event) { + e = work->event; + do_gettimeofday(&now); + e->event.sequence = drm_vblank_count(rdev->ddev, radeon_crtc->crtc_id); + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + list_add_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + } + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); + + drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); + radeon_fence_unref(&work->fence); + radeon_post_page_flip(work->rdev, work->crtc_id); + schedule_work(&work->work); +} + +static int radeon_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_framebuffer *old_radeon_fb; + struct radeon_framebuffer *new_radeon_fb; + struct drm_gem_object *obj; + struct radeon_bo *rbo; + struct radeon_fence *fence; + struct radeon_unpin_work *work; + unsigned long flags; + u32 tiling_flags, pitch_pixels; + u64 base; + int r; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (work == NULL) + return -ENOMEM; + + r = radeon_fence_create(rdev, &fence); + if (unlikely(r != 0)) { + kfree(work); + DRM_ERROR("flip queue: failed to create fence.\n"); + return -ENOMEM; + } + work->event = event; + work->rdev = rdev; + work->crtc_id = radeon_crtc->crtc_id; + work->fence = radeon_fence_ref(fence); + old_radeon_fb = to_radeon_framebuffer(crtc->fb); + new_radeon_fb = to_radeon_framebuffer(fb); + /* schedule unpin of the old buffer */ + obj = old_radeon_fb->obj; + rbo = obj->driver_private; + work->old_rbo = rbo; + INIT_WORK(&work->work, radeon_unpin_work_func); + + /* We borrow the event spin lock for protecting unpin_work */ + spin_lock_irqsave(&dev->event_lock, flags); + if (radeon_crtc->unpin_work) { + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(work); + radeon_fence_unref(&fence); + + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); + return -EBUSY; + } + radeon_crtc->unpin_work = work; + radeon_crtc->deferred_flip_completion = 0; + spin_unlock_irqrestore(&dev->event_lock, flags); + + /* pin the new buffer */ + obj = new_radeon_fb->obj; + rbo = obj->driver_private; + + DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n", + work->old_rbo, rbo); + + r = radeon_bo_reserve(rbo, false); + if (unlikely(r != 0)) { + DRM_ERROR("failed to reserve new rbo buffer before flip\n"); + goto pflip_cleanup; + } + r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base); + if (unlikely(r != 0)) { + radeon_bo_unreserve(rbo); + r = -EINVAL; + DRM_ERROR("failed to pin new rbo buffer before flip\n"); + goto pflip_cleanup; + } + radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); + radeon_bo_unreserve(rbo); + + if (!ASIC_IS_AVIVO(rdev)) { + /* crtc offset is from display base addr not FB location */ + base -= radeon_crtc->legacy_display_base_addr; + pitch_pixels = fb->pitch / (fb->bits_per_pixel / 8); + + if (tiling_flags & RADEON_TILING_MACRO) { + if (ASIC_IS_R300(rdev)) { + base &= ~0x7ff; + } else { + int byteshift = fb->bits_per_pixel >> 4; + int tile_addr = (((crtc->y >> 3) * pitch_pixels + crtc->x) >> (8 - byteshift)) << 11; + base += tile_addr + ((crtc->x << byteshift) % 256) + ((crtc->y % 8) << 8); + } + } else { + int offset = crtc->y * pitch_pixels + crtc->x; + switch (fb->bits_per_pixel) { + case 8: + default: + offset *= 1; + break; + case 15: + case 16: + offset *= 2; + break; + case 24: + offset *= 3; + break; + case 32: + offset *= 4; + break; + } + base += offset; + } + base &= ~7; + } + + spin_lock_irqsave(&dev->event_lock, flags); + work->new_crtc_base = base; + spin_unlock_irqrestore(&dev->event_lock, flags); + + /* update crtc fb */ + crtc->fb = fb; + + r = drm_vblank_get(dev, radeon_crtc->crtc_id); + if (r) { + DRM_ERROR("failed to get vblank before flip\n"); + goto pflip_cleanup1; + } + + /* 32 ought to cover us */ + r = radeon_ring_lock(rdev, 32); + if (r) { + DRM_ERROR("failed to lock the ring before flip\n"); + goto pflip_cleanup2; + } + + /* emit the fence */ + radeon_fence_emit(rdev, fence); + /* set the proper interrupt */ + radeon_pre_page_flip(rdev, radeon_crtc->crtc_id); + /* fire the ring */ + radeon_ring_unlock_commit(rdev); + + return 0; + +pflip_cleanup2: + drm_vblank_put(dev, radeon_crtc->crtc_id); + +pflip_cleanup1: + r = radeon_bo_reserve(rbo, false); + if (unlikely(r != 0)) { + DRM_ERROR("failed to reserve new rbo in error path\n"); + goto pflip_cleanup; + } + r = radeon_bo_unpin(rbo); + if (unlikely(r != 0)) { + radeon_bo_unreserve(rbo); + r = -EINVAL; + DRM_ERROR("failed to unpin new rbo in error path\n"); + goto pflip_cleanup; + } + radeon_bo_unreserve(rbo); + +pflip_cleanup: + spin_lock_irqsave(&dev->event_lock, flags); + radeon_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + radeon_fence_unref(&fence); + kfree(work); + + return r; +} + static const struct drm_crtc_funcs radeon_crtc_funcs = { .cursor_set = radeon_crtc_cursor_set, .cursor_move = radeon_crtc_cursor_move, .gamma_set = radeon_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = radeon_crtc_destroy, + .page_flip = radeon_crtc_page_flip, }; static void radeon_crtc_init(struct drm_device *dev, int index) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 32ec0cc6be92..a92d2a5cea90 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -48,9 +48,10 @@ * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs + * 2.8.0 - pageflip support */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 7 +#define KMS_DRIVER_MINOR 8 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a108c7ed14f5..e0d1c6d1b9c7 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -71,8 +71,10 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) { rdev->irq.hpd[i] = false; + rdev->irq.pflip[i] = false; + } radeon_irq_set(rdev); /* Clear bits */ radeon_irq_process(rdev); @@ -101,8 +103,10 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) rdev->irq.gui_idle = false; for (i = 0; i < rdev->num_crtc; i++) rdev->irq.crtc_vblank_int[i] = false; - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) { rdev->irq.hpd[i] = false; + rdev->irq.pflip[i] = false; + } radeon_irq_set(rdev); } @@ -175,3 +179,34 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev) spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags); } +void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc) +{ + unsigned long irqflags; + + if (crtc < 0 || crtc >= rdev->num_crtc) + return; + + spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags); + if (rdev->ddev->irq_enabled && (++rdev->irq.pflip_refcount[crtc] == 1)) { + rdev->irq.pflip[crtc] = true; + radeon_irq_set(rdev); + } + spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags); +} + +void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc) +{ + unsigned long irqflags; + + if (crtc < 0 || crtc >= rdev->num_crtc) + return; + + spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags); + BUG_ON(rdev->ddev->irq_enabled && rdev->irq.pflip_refcount[crtc] <= 0); + if (rdev->ddev->irq_enabled && (--rdev->irq.pflip_refcount[crtc] == 0)) { + rdev->irq.pflip[crtc] = false; + radeon_irq_set(rdev); + } + spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags); +} + diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 55856ad0ac41..f406f02bf14e 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -277,6 +277,9 @@ struct radeon_crtc { fixed20_12 hsc; struct drm_display_mode native_mode; int pll_id; + /* page flipping */ + struct radeon_unpin_work *unpin_work; + int deferred_flip_completion; }; struct radeon_encoder_primary_dac { @@ -659,4 +662,7 @@ int radeon_fbdev_total_size(struct radeon_device *rdev); bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); void radeon_fb_output_poll_changed(struct radeon_device *rdev); + +void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id); + #endif diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 64928814de53..26c43e234350 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -422,6 +422,7 @@ # define RADEON_CRTC_CSYNC_EN (1 << 4) # define RADEON_CRTC_ICON_EN (1 << 15) # define RADEON_CRTC_CUR_EN (1 << 16) +# define RADEON_CRTC_VSTAT_MODE_MASK (3 << 17) # define RADEON_CRTC_CUR_MODE_MASK (7 << 20) # define RADEON_CRTC_CUR_MODE_SHIFT 20 # define RADEON_CRTC_CUR_MODE_MONO 0 diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index f1c6e02c2e6b..683652bea17c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -46,6 +46,56 @@ void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); +void rs600_pre_page_flip(struct radeon_device *rdev, int crtc) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; + u32 tmp; + + /* make sure flip is at vb rather than hb */ + tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); + + /* set pageflip to happen anywhere in vblank interval */ + WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); + + /* enable the pflip int */ + radeon_irq_kms_pflip_irq_get(rdev, crtc); +} + +void rs600_post_page_flip(struct radeon_device *rdev, int crtc) +{ + /* disable the pflip int */ + radeon_irq_kms_pflip_irq_put(rdev, crtc); +} + +u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + + /* Lock the graphics update lock */ + tmp |= AVIVO_D1GRPH_UPDATE_LOCK; + WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + + /* update the scanout addresses */ + WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32)crtc_base); + WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32)crtc_base); + + /* Wait for update_pending to go high. */ + while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); + + /* Unlock the lock, so double-buffering can take place inside vblank */ + tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; + WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + + /* Return current update_pending status: */ + return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; +} + void rs600_pm_misc(struct radeon_device *rdev) { int requested_index = rdev->pm.requested_power_state_index; @@ -515,10 +565,12 @@ int rs600_irq_set(struct radeon_device *rdev) if (rdev->irq.gui_idle) { tmp |= S_000040_GUI_IDLE(1); } - if (rdev->irq.crtc_vblank_int[0]) { + if (rdev->irq.crtc_vblank_int[0] || + rdev->irq.pflip[0]) { mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1); } - if (rdev->irq.crtc_vblank_int[1]) { + if (rdev->irq.crtc_vblank_int[1] || + rdev->irq.pflip[1]) { mode_int |= S_006540_D2MODE_VBLANK_INT_MASK(1); } if (rdev->irq.hpd[0]) { @@ -534,7 +586,7 @@ int rs600_irq_set(struct radeon_device *rdev) return 0; } -static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int) +static inline u32 rs600_irq_ack(struct radeon_device *rdev) { uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS); uint32_t irq_mask = S_000044_SW_INT(1); @@ -547,27 +599,27 @@ static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_ } if (G_000044_DISPLAY_INT_STAT(irqs)) { - *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); - if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) { + rdev->irq.stat_regs.r500.disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); + if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { WREG32(R_006534_D1MODE_VBLANK_STATUS, S_006534_D1MODE_VBLANK_ACK(1)); } - if (G_007EDC_LB_D2_VBLANK_INTERRUPT(*r500_disp_int)) { + if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { WREG32(R_006D34_D2MODE_VBLANK_STATUS, S_006D34_D2MODE_VBLANK_ACK(1)); } - if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(*r500_disp_int)) { + if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL); tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_ACK(1); WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp); } - if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(*r500_disp_int)) { + if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL); tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_ACK(1); WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp); } } else { - *r500_disp_int = 0; + rdev->irq.stat_regs.r500.disp_int = 0; } if (irqs) { @@ -578,32 +630,30 @@ static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_ void rs600_irq_disable(struct radeon_device *rdev) { - u32 tmp; - WREG32(R_000040_GEN_INT_CNTL, 0); WREG32(R_006540_DxMODE_INT_MASK, 0); /* Wait and acknowledge irq */ mdelay(1); - rs600_irq_ack(rdev, &tmp); + rs600_irq_ack(rdev); } int rs600_irq_process(struct radeon_device *rdev) { - uint32_t status, msi_rearm; - uint32_t r500_disp_int; + u32 status, msi_rearm; bool queue_hotplug = false; /* reset gui idle ack. the status bit is broken */ rdev->irq.gui_idle_acked = false; - status = rs600_irq_ack(rdev, &r500_disp_int); - if (!status && !r500_disp_int) { + status = rs600_irq_ack(rdev); + if (!status && !rdev->irq.stat_regs.r500.disp_int) { return IRQ_NONE; } - while (status || r500_disp_int) { + while (status || rdev->irq.stat_regs.r500.disp_int) { /* SW interrupt */ - if (G_000044_SW_INT(status)) + if (G_000044_SW_INT(status)) { radeon_fence_process(rdev); + } /* GUI idle */ if (G_000040_GUI_IDLE(status)) { rdev->irq.gui_idle_acked = true; @@ -611,25 +661,33 @@ int rs600_irq_process(struct radeon_device *rdev) wake_up(&rdev->irq.idle_queue); } /* Vertical blank interrupts */ - if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); + if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } } - if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); + if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } } - if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) { + if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { queue_hotplug = true; DRM_DEBUG("HPD1\n"); } - if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) { + if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { queue_hotplug = true; DRM_DEBUG("HPD2\n"); } - status = rs600_irq_ack(rdev, &r500_disp_int); + status = rs600_irq_ack(rdev); } /* reset gui idle ack. the status bit is broken */ rdev->irq.gui_idle_acked = false; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4dfead8cee33..42ff07893f3a 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -42,6 +42,40 @@ static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + + /* Lock the graphics update lock */ + tmp |= AVIVO_D1GRPH_UPDATE_LOCK; + WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + + /* update the scanout addresses */ + if (radeon_crtc->crtc_id) { + WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); + WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); + } else { + WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); + WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); + } + WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32)crtc_base); + WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + (u32)crtc_base); + + /* Wait for update_pending to go high. */ + while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); + + /* Unlock the lock, so double-buffering can take place inside vblank */ + tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; + WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + + /* Return current update_pending status: */ + return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; +} + /* get temperature in millidegrees */ u32 rv770_get_temp(struct radeon_device *rdev) { diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index b7a5a20e81dc..11955c685ad1 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -351,4 +351,11 @@ #define SRBM_STATUS 0x0E50 +#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 +#define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114 +#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c +#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c + #endif -- cgit v1.2.3 From 3e4ea7421f45966c93c8cbe81569e8dc93a58b87 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Sun, 21 Nov 2010 10:59:02 -0500 Subject: drm/kms/radeon: Reorder vblank and pageflip interrupt handling. In the vblank irq handler, calls to actual vblank handling, or at least drm_handle_vblank(), need to happen before calls to radeon_crtc_handle_flip(). Reason: The high precision pageflip timestamping and some other pageflip optimizations will need the updated vblank count and timestamps for the current vblank interval. These are calculated in drm_handle_vblank(), therefore it must go first. Signed-off-by: Mario Kleiner Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 8 ++++---- drivers/gpu/drm/radeon/r100.c | 8 ++++---- drivers/gpu/drm/radeon/r600.c | 8 ++++---- drivers/gpu/drm/radeon/rs600.c | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index df3f37243222..25e84379e7c6 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2398,13 +2398,13 @@ restart_ih: switch (src_data) { case 0: /* D1 vblank */ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.pflip[0]) - radeon_crtc_handle_flip(rdev, 0); if (rdev->irq.crtc_vblank_int[0]) { drm_handle_vblank(rdev->ddev, 0); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; DRM_DEBUG("IH: D1 vblank\n"); } @@ -2424,13 +2424,13 @@ restart_ih: switch (src_data) { case 0: /* D2 vblank */ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.pflip[1]) - radeon_crtc_handle_flip(rdev, 1); if (rdev->irq.crtc_vblank_int[1]) { drm_handle_vblank(rdev->ddev, 1); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; DRM_DEBUG("IH: D2 vblank\n"); } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index b2e29798a99d..2316f73db6c0 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -650,22 +650,22 @@ int r100_irq_process(struct radeon_device *rdev) } /* Vertical blank interrupts */ if (status & RADEON_CRTC_VBLANK_STAT) { - if (rdev->irq.pflip[0]) - radeon_crtc_handle_flip(rdev, 0); if (rdev->irq.crtc_vblank_int[0]) { drm_handle_vblank(rdev->ddev, 0); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); } if (status & RADEON_CRTC2_VBLANK_STAT) { - if (rdev->irq.pflip[1]) - radeon_crtc_handle_flip(rdev, 1); if (rdev->irq.crtc_vblank_int[1]) { drm_handle_vblank(rdev->ddev, 1); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); } if (status & RADEON_FP_DETECT_STAT) { queue_hotplug = true; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 15b95724c408..7057b392e005 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3294,13 +3294,13 @@ restart_ih: switch (src_data) { case 0: /* D1 vblank */ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.pflip[0]) - radeon_crtc_handle_flip(rdev, 0); if (rdev->irq.crtc_vblank_int[0]) { drm_handle_vblank(rdev->ddev, 0); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; DRM_DEBUG("IH: D1 vblank\n"); } @@ -3320,13 +3320,13 @@ restart_ih: switch (src_data) { case 0: /* D2 vblank */ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.pflip[1]) - radeon_crtc_handle_flip(rdev, 1); if (rdev->irq.crtc_vblank_int[1]) { drm_handle_vblank(rdev->ddev, 1); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; DRM_DEBUG("IH: D2 vblank\n"); } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 683652bea17c..9a85b1614c86 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -662,22 +662,22 @@ int rs600_irq_process(struct radeon_device *rdev) } /* Vertical blank interrupts */ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - if (rdev->irq.pflip[0]) - radeon_crtc_handle_flip(rdev, 0); if (rdev->irq.crtc_vblank_int[0]) { drm_handle_vblank(rdev->ddev, 0); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[0]) + radeon_crtc_handle_flip(rdev, 0); } if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - if (rdev->irq.pflip[1]) - radeon_crtc_handle_flip(rdev, 1); if (rdev->irq.crtc_vblank_int[1]) { drm_handle_vblank(rdev->ddev, 1); rdev->pm.vblank_sync = true; wake_up(&rdev->irq.vblank_queue); } + if (rdev->irq.pflip[1]) + radeon_crtc_handle_flip(rdev, 1); } if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { queue_hotplug = true; -- cgit v1.2.3 From b6724405bc67ef3ae1318002085cde382b12345f Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Sun, 21 Nov 2010 10:59:03 -0500 Subject: drm/kms/radeon: Use high precision timestamps for pageflip completion events. Signed-off-by: Mario Kleiner Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index f6493f444faa..15f24f2ee04d 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -259,8 +259,7 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) /* wakeup userspace */ if (work->event) { e = work->event; - do_gettimeofday(&now); - e->event.sequence = drm_vblank_count(rdev->ddev, radeon_crtc->crtc_id); + e->event.sequence = drm_vblank_count_and_time(rdev->ddev, crtc_id, &now); e->event.tv_sec = now.tv_sec; e->event.tv_usec = now.tv_usec; list_add_tail(&e->base.link, &e->base.file_priv->event_list); -- cgit v1.2.3 From d6ea88865d3e5b0c62040531310c1f2c6a994f46 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 22 Nov 2010 13:24:40 +1000 Subject: drm/ttm: Add a bo list reserve fastpath (v2) Makes it possible to reserve a list of buffer objects with a single spin lock / unlock if there is no contention. Should improve cpu usage on SMP kernels. v2: Initialize private list members on reserve and don't call ttm_bo_list_ref_sub() with zero put_count. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 32 ++++----- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 124 ++++++++++++++++++++++++++++++--- include/drm/ttm/ttm_bo_api.h | 38 ++++++++++ include/drm/ttm/ttm_bo_driver.h | 14 ++++ include/drm/ttm/ttm_execbuf_util.h | 6 +- 5 files changed, 186 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 148a322d8f5d..a586378b1b2b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -169,7 +169,7 @@ int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible) } EXPORT_SYMBOL(ttm_bo_wait_unreserved); -static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) +void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; struct ttm_mem_type_manager *man; @@ -191,11 +191,7 @@ static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) } } -/** - * Call with the lru_lock held. - */ - -static int ttm_bo_del_from_lru(struct ttm_buffer_object *bo) +int ttm_bo_del_from_lru(struct ttm_buffer_object *bo) { int put_count = 0; @@ -267,6 +263,15 @@ static void ttm_bo_ref_bug(struct kref *list_kref) BUG(); } +void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, + bool never_free) +{ + while (count--) + kref_put(&bo->list_kref, + (never_free || (count >= 0)) ? ttm_bo_ref_bug : + ttm_bo_release_list); +} + int ttm_bo_reserve(struct ttm_buffer_object *bo, bool interruptible, bool no_wait, bool use_sequence, uint32_t sequence) @@ -282,8 +287,7 @@ int ttm_bo_reserve(struct ttm_buffer_object *bo, put_count = ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); - while (put_count--) - kref_put(&bo->list_kref, ttm_bo_ref_bug); + ttm_bo_list_ref_sub(bo, put_count, true); return ret; } @@ -496,8 +500,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) spin_unlock(&glob->lru_lock); ttm_bo_cleanup_memtype_use(bo); - while (put_count--) - kref_put(&bo->list_kref, ttm_bo_ref_bug); + ttm_bo_list_ref_sub(bo, put_count, true); return; } else { @@ -580,8 +583,7 @@ retry: spin_unlock(&glob->lru_lock); ttm_bo_cleanup_memtype_use(bo); - while (put_count--) - kref_put(&bo->list_kref, ttm_bo_ref_bug); + ttm_bo_list_ref_sub(bo, put_count, true); return 0; } @@ -802,8 +804,7 @@ retry: BUG_ON(ret != 0); - while (put_count--) - kref_put(&bo->list_kref, ttm_bo_ref_bug); + ttm_bo_list_ref_sub(bo, put_count, true); ret = ttm_bo_evict(bo, interruptible, no_wait_reserve, no_wait_gpu); ttm_bo_unreserve(bo); @@ -1783,8 +1784,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) put_count = ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); - while (put_count--) - kref_put(&bo->list_kref, ttm_bo_ref_bug); + ttm_bo_list_ref_sub(bo, put_count, true); /** * Wait for GPU, then move to system cached. diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index c285c2902d15..201a71d111ec 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -32,6 +32,72 @@ #include #include +static void ttm_eu_backoff_reservation_locked(struct list_head *list) +{ + struct ttm_validate_buffer *entry; + + list_for_each_entry(entry, list, head) { + struct ttm_buffer_object *bo = entry->bo; + if (!entry->reserved) + continue; + + if (entry->removed) { + ttm_bo_add_to_lru(bo); + entry->removed = false; + + } + entry->reserved = false; + atomic_set(&bo->reserved, 0); + wake_up_all(&bo->event_queue); + } +} + +static void ttm_eu_del_from_lru_locked(struct list_head *list) +{ + struct ttm_validate_buffer *entry; + + list_for_each_entry(entry, list, head) { + struct ttm_buffer_object *bo = entry->bo; + if (!entry->reserved) + continue; + + if (!entry->removed) { + entry->put_count = ttm_bo_del_from_lru(bo); + entry->removed = true; + } + } +} + +static void ttm_eu_list_ref_sub(struct list_head *list) +{ + struct ttm_validate_buffer *entry; + + list_for_each_entry(entry, list, head) { + struct ttm_buffer_object *bo = entry->bo; + + if (entry->put_count) { + ttm_bo_list_ref_sub(bo, entry->put_count, true); + entry->put_count = 0; + } + } +} + +static int ttm_eu_wait_unreserved_locked(struct list_head *list, + struct ttm_buffer_object *bo) +{ + struct ttm_bo_global *glob = bo->glob; + int ret; + + ttm_eu_del_from_lru_locked(list); + spin_unlock(&glob->lru_lock); + ret = ttm_bo_wait_unreserved(bo, true); + spin_lock(&glob->lru_lock); + if (unlikely(ret != 0)) + ttm_eu_backoff_reservation_locked(list); + return ret; +} + + void ttm_eu_backoff_reservation(struct list_head *list) { struct ttm_validate_buffer *entry; @@ -61,35 +127,71 @@ EXPORT_SYMBOL(ttm_eu_backoff_reservation); int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq) { + struct ttm_bo_global *glob; struct ttm_validate_buffer *entry; int ret; + if (list_empty(list)) + return 0; + + list_for_each_entry(entry, list, head) { + entry->reserved = false; + entry->put_count = 0; + entry->removed = false; + } + + entry = list_first_entry(list, struct ttm_validate_buffer, head); + glob = entry->bo->glob; + retry: + spin_lock(&glob->lru_lock); list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - entry->reserved = false; - ret = ttm_bo_reserve(bo, true, false, true, val_seq); - if (ret != 0) { - ttm_eu_backoff_reservation(list); - if (ret == -EAGAIN) { - ret = ttm_bo_wait_unreserved(bo, true); - if (unlikely(ret != 0)) - return ret; - goto retry; - } else +retry_this_bo: + ret = ttm_bo_reserve_locked(bo, true, true, true, val_seq); + switch (ret) { + case 0: + break; + case -EBUSY: + ret = ttm_eu_wait_unreserved_locked(list, bo); + if (unlikely(ret != 0)) { + spin_unlock(&glob->lru_lock); + ttm_eu_list_ref_sub(list); + return ret; + } + goto retry_this_bo; + case -EAGAIN: + ttm_eu_backoff_reservation_locked(list); + spin_unlock(&glob->lru_lock); + ttm_eu_list_ref_sub(list); + ret = ttm_bo_wait_unreserved(bo, true); + if (unlikely(ret != 0)) return ret; + goto retry; + default: + ttm_eu_backoff_reservation_locked(list); + spin_unlock(&glob->lru_lock); + ttm_eu_list_ref_sub(list); + return ret; } entry->reserved = true; if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { - ttm_eu_backoff_reservation(list); + ttm_eu_backoff_reservation_locked(list); + spin_unlock(&glob->lru_lock); + ttm_eu_list_ref_sub(list); ret = ttm_bo_wait_cpu(bo, false); if (ret) return ret; goto retry; } } + + ttm_eu_del_from_lru_locked(list); + spin_unlock(&glob->lru_lock); + ttm_eu_list_ref_sub(list); + return 0; } EXPORT_SYMBOL(ttm_eu_reserve_buffers); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index beafc156a535..b0fc9c12554b 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -364,6 +364,44 @@ extern int ttm_bo_validate(struct ttm_buffer_object *bo, */ extern void ttm_bo_unref(struct ttm_buffer_object **bo); + +/** + * ttm_bo_list_ref_sub + * + * @bo: The buffer object. + * @count: The number of references with which to decrease @bo::list_kref; + * @never_free: The refcount should not reach zero with this operation. + * + * Release @count lru list references to this buffer object. + */ +extern void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, + bool never_free); + +/** + * ttm_bo_add_to_lru + * + * @bo: The buffer object. + * + * Add this bo to the relevant mem type lru and, if it's backed by + * system pages (ttms) to the swap list. + * This function must be called with struct ttm_bo_global::lru_lock held, and + * is typically called immediately prior to unreserving a bo. + */ +extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); + +/** + * ttm_bo_del_from_lru + * + * @bo: The buffer object. + * + * Remove this bo from all lru lists used to lookup and reserve an object. + * This function must be called with struct ttm_bo_global::lru_lock held, + * and is usually called just immediately after the bo has been reserved to + * avoid recursive reservation from lru lists. + */ +extern int ttm_bo_del_from_lru(struct ttm_buffer_object *bo); + + /** * ttm_bo_lock_delayed_workqueue * diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 8e0c848326b6..95068e6024db 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -864,6 +864,20 @@ extern int ttm_bo_reserve(struct ttm_buffer_object *bo, bool interruptible, bool no_wait, bool use_sequence, uint32_t sequence); + +/** + * ttm_bo_reserve_locked: + * + * Similar to ttm_bo_reserve, but must be called with the glob::lru_lock + * spinlock held, and will not remove reserved buffers from the lru lists. + * The function may release the LRU spinlock if it needs to sleep. + */ + +extern int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, + bool interruptible, + bool no_wait, bool use_sequence, + uint32_t sequence); + /** * ttm_bo_unreserve * diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index cd2c475da9ea..fd09b8438977 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -41,7 +41,9 @@ * @bo: refcounted buffer object pointer. * @new_sync_obj_arg: New sync_obj_arg for @bo, to be used once * adding a new sync object. - * @reservied: Indicates whether @bo has been reserved for validation. + * @reserved: Indicates whether @bo has been reserved for validation. + * @removed: Indicates whether @bo has been removed from lru lists. + * @put_count: Number of outstanding references on bo::list_kref. */ struct ttm_validate_buffer { @@ -49,6 +51,8 @@ struct ttm_validate_buffer { struct ttm_buffer_object *bo; void *new_sync_obj_arg; bool reserved; + bool removed; + int put_count; }; /** -- cgit v1.2.3 From 2357cbe5f4ca8a52329c2c2a26b68839870d5d43 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 16 Nov 2010 15:21:08 +0100 Subject: drm/ttm: Use kref_sub instead of repeatedly calling kref_put Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index a586378b1b2b..9ef893d5da88 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -266,10 +266,8 @@ static void ttm_bo_ref_bug(struct kref *list_kref) void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, bool never_free) { - while (count--) - kref_put(&bo->list_kref, - (never_free || (count >= 0)) ? ttm_bo_ref_bug : - ttm_bo_release_list); + kref_sub(&bo->list_kref, count, + (never_free) ? ttm_bo_ref_bug : ttm_bo_release_list); } int ttm_bo_reserve(struct ttm_buffer_object *bo, -- cgit v1.2.3 From 68c4fa31aa52765314b4285a7835368ea35b509c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 12:28:27 +0000 Subject: drm/ttm: Optimize ttm_eu_backoff_reservation Avoid the ttm_bo_unreserve() spinlocks by calling ttm_eu_backoff_reservation_locked under the lru spinlock. Signed-off-by: Thomas Hellstrom Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 201a71d111ec..7dcc6470e2f5 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -101,15 +101,16 @@ static int ttm_eu_wait_unreserved_locked(struct list_head *list, void ttm_eu_backoff_reservation(struct list_head *list) { struct ttm_validate_buffer *entry; + struct ttm_bo_global *glob; - list_for_each_entry(entry, list, head) { - struct ttm_buffer_object *bo = entry->bo; - if (!entry->reserved) - continue; + if (list_empty(list)) + return; - entry->reserved = false; - ttm_bo_unreserve(bo); - } + entry = list_first_entry(list, struct ttm_validate_buffer, head); + glob = entry->bo->glob; + spin_lock(&glob->lru_lock); + ttm_eu_backoff_reservation_locked(list); + spin_unlock(&glob->lru_lock); } EXPORT_SYMBOL(ttm_eu_backoff_reservation); -- cgit v1.2.3 From 96726fe50feae74812a2ccf5d5da23cb01c0a413 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 12:28:28 +0000 Subject: drm/ttm: Don't deadlock on recursive multi-bo reservations Add an aid for the driver to detect deadlocks on multi-bo reservations Update documentation. Signed-off-by: Thomas Hellstrom Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 15 ++++++++++++--- include/drm/ttm/ttm_bo_driver.h | 25 ++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 9ef893d5da88..5d8750830dc3 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -223,9 +223,18 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, /** * Deadlock avoidance for multi-bo reserving. */ - if (use_sequence && bo->seq_valid && - (sequence - bo->val_seq < (1 << 31))) { - return -EAGAIN; + if (use_sequence && bo->seq_valid) { + /** + * We've already reserved this one. + */ + if (unlikely(sequence == bo->val_seq)) + return -EDEADLK; + /** + * Already reserved by a thread that will not back + * off for us. We need to back off. + */ + if (unlikely(sequence - bo->val_seq < (1 << 31))) + return -EAGAIN; } if (no_wait) diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 95068e6024db..1e25a40c688e 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -859,6 +859,9 @@ extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo); * try again. (only if use_sequence == 1). * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by * a signal. Release all buffer reservations and return to user-space. + * -EBUSY: The function needed to sleep, but @no_wait was true + * -EDEADLK: Bo already reserved using @sequence. This error code will only + * be returned if @use_sequence is set to true. */ extern int ttm_bo_reserve(struct ttm_buffer_object *bo, bool interruptible, @@ -868,11 +871,27 @@ extern int ttm_bo_reserve(struct ttm_buffer_object *bo, /** * ttm_bo_reserve_locked: * - * Similar to ttm_bo_reserve, but must be called with the glob::lru_lock - * spinlock held, and will not remove reserved buffers from the lru lists. + * @bo: A pointer to a struct ttm_buffer_object. + * @interruptible: Sleep interruptible if waiting. + * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. + * @use_sequence: If @bo is already reserved, Only sleep waiting for + * it to become unreserved if @sequence < (@bo)->sequence. + * + * Must be called with struct ttm_bo_global::lru_lock held, + * and will not remove reserved buffers from the lru lists. * The function may release the LRU spinlock if it needs to sleep. + * Otherwise identical to ttm_bo_reserve. + * + * Returns: + * -EAGAIN: The reservation may cause a deadlock. + * Release all buffer reservations, wait for @bo to become unreserved and + * try again. (only if use_sequence == 1). + * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by + * a signal. Release all buffer reservations and return to user-space. + * -EBUSY: The function needed to sleep, but @no_wait was true + * -EDEADLK: Bo already reserved using @sequence. This error code will only + * be returned if @use_sequence is set to true. */ - extern int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, bool interruptible, bool no_wait, bool use_sequence, -- cgit v1.2.3 From 702adba22433c175e8429a47760f35ca16caf1cd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 12:28:29 +0000 Subject: drm/ttm/radeon/nouveau: Kill the bo lock in favour of a bo device fence_lock The bo lock used only to protect the bo sync object members, and since it is a per bo lock, fencing a buffer list will see a lot of locks and unlocks. Replace it with a per-device lock that protects the sync object members on *all* bos. Reading and setting these members will always be very quick, so the risc of heavy lock contention is microscopic. Note that waiting for sync objects will always take place outside of this lock. The bo device fence lock will eventually be replaced with a seqlock / rcu mechanism so we can determine that a bo is idle under a rcu / read seqlock. However this change will allow us to batch fencing and unreserving of buffers with a minimal amount of locking. Signed-off-by: Thomas Hellstrom Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_gem.c | 12 ++++---- drivers/gpu/drm/radeon/radeon_object.c | 4 +-- drivers/gpu/drm/radeon/radeon_object.h | 4 +-- drivers/gpu/drm/ttm/ttm_bo.c | 55 +++++++++++++++++----------------- drivers/gpu/drm/ttm/ttm_bo_util.c | 7 ++--- drivers/gpu/drm/ttm/ttm_bo_vm.c | 6 ++-- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 7 +++-- include/drm/ttm/ttm_bo_api.h | 6 ++-- include/drm/ttm/ttm_bo_driver.h | 3 ++ 9 files changed, 53 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 9a1fdcf400c2..1f2301d26c0a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -234,10 +234,10 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) if (likely(fence)) { struct nouveau_fence *prev_fence; - spin_lock(&nvbo->bo.lock); + spin_lock(&nvbo->bo.bdev->fence_lock); prev_fence = nvbo->bo.sync_obj; nvbo->bo.sync_obj = nouveau_fence_ref(fence); - spin_unlock(&nvbo->bo.lock); + spin_unlock(&nvbo->bo.bdev->fence_lock); nouveau_fence_unref((void *)&prev_fence); } @@ -557,9 +557,9 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, data |= r->vor; } - spin_lock(&nvbo->bo.lock); + spin_lock(&nvbo->bo.bdev->fence_lock); ret = ttm_bo_wait(&nvbo->bo, false, false, false); - spin_unlock(&nvbo->bo.lock); + spin_unlock(&nvbo->bo.bdev->fence_lock); if (ret) { NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret); break; @@ -791,9 +791,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, } if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) { - spin_lock(&nvbo->bo.lock); + spin_lock(&nvbo->bo.bdev->fence_lock); ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait); - spin_unlock(&nvbo->bo.lock); + spin_unlock(&nvbo->bo.bdev->fence_lock); } else { ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait); if (ret == 0) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 1d067743fee0..e939cb6a91cc 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -369,11 +369,11 @@ void radeon_bo_list_fence(struct list_head *head, void *fence) list_for_each_entry(lobj, head, list) { bo = lobj->bo; - spin_lock(&bo->tbo.lock); + spin_lock(&bo->tbo.bdev->fence_lock); old_fence = (struct radeon_fence *)bo->tbo.sync_obj; bo->tbo.sync_obj = radeon_fence_ref(fence); bo->tbo.sync_obj_arg = NULL; - spin_unlock(&bo->tbo.lock); + spin_unlock(&bo->tbo.bdev->fence_lock); if (old_fence) { radeon_fence_unref(&old_fence); } diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index d143702b244a..fd536751f865 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -126,12 +126,12 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); if (unlikely(r != 0)) return r; - spin_lock(&bo->tbo.lock); + spin_lock(&bo->tbo.bdev->fence_lock); if (mem_type) *mem_type = bo->tbo.mem.mem_type; if (bo->tbo.sync_obj) r = ttm_bo_wait(&bo->tbo, true, true, no_wait); - spin_unlock(&bo->tbo.lock); + spin_unlock(&bo->tbo.bdev->fence_lock); ttm_bo_unreserve(&bo->tbo); return r; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 5d8750830dc3..d93c73b1c471 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -427,11 +427,9 @@ moved: } if (bo->mem.mm_node) { - spin_lock(&bo->lock); bo->offset = (bo->mem.start << PAGE_SHIFT) + bdev->man[bo->mem.mem_type].gpu_offset; bo->cur_placement = bo->mem.placement; - spin_unlock(&bo->lock); } else bo->offset = 0; @@ -485,14 +483,14 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) int put_count; int ret; - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); (void) ttm_bo_wait(bo, false, false, true); if (!bo->sync_obj) { spin_lock(&glob->lru_lock); /** - * Lock inversion between bo::reserve and bo::lock here, + * Lock inversion between bo:reserve and bdev::fence_lock here, * but that's OK, since we're only trylocking. */ @@ -501,7 +499,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) if (unlikely(ret == -EBUSY)) goto queue; - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); put_count = ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); @@ -522,7 +520,7 @@ queue: kref_get(&bo->list_kref); list_add_tail(&bo->ddestroy, &bdev->ddestroy); spin_unlock(&glob->lru_lock); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (sync_obj) { driver->sync_obj_flush(sync_obj, sync_obj_arg); @@ -547,14 +545,15 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool no_wait_reserve, bool no_wait_gpu) { + struct ttm_bo_device *bdev = bo->bdev; struct ttm_bo_global *glob = bo->glob; int put_count; int ret = 0; retry: - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (unlikely(ret != 0)) return ret; @@ -707,9 +706,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, struct ttm_placement placement; int ret = 0; - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (unlikely(ret != 0)) { if (ret != -ERESTARTSYS) { @@ -1044,6 +1043,7 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, { int ret = 0; struct ttm_mem_reg mem; + struct ttm_bo_device *bdev = bo->bdev; BUG_ON(!atomic_read(&bo->reserved)); @@ -1052,9 +1052,9 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, * Have the driver move function wait for idle when necessary, * instead of doing it here. */ - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (ret) return ret; mem.num_pages = bo->num_pages; @@ -1171,7 +1171,6 @@ int ttm_bo_init(struct ttm_bo_device *bdev, } bo->destroy = destroy; - spin_lock_init(&bo->lock); kref_init(&bo->kref); kref_init(&bo->list_kref); atomic_set(&bo->cpu_writers, 0); @@ -1535,7 +1534,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, bdev->dev_mapping = NULL; bdev->glob = glob; bdev->need_dma32 = need_dma32; - + spin_lock_init(&bdev->fence_lock); mutex_lock(&glob->device_list_mutex); list_add_tail(&bdev->device_list, &glob->device_list); mutex_unlock(&glob->device_list_mutex); @@ -1659,6 +1658,7 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy, bool interruptible, bool no_wait) { struct ttm_bo_driver *driver = bo->bdev->driver; + struct ttm_bo_device *bdev = bo->bdev; void *sync_obj; void *sync_obj_arg; int ret = 0; @@ -1672,9 +1672,9 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, void *tmp_obj = bo->sync_obj; bo->sync_obj = NULL; clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); driver->sync_obj_unref(&tmp_obj); - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); continue; } @@ -1683,29 +1683,29 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, sync_obj = driver->sync_obj_ref(bo->sync_obj); sync_obj_arg = bo->sync_obj_arg; - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); ret = driver->sync_obj_wait(sync_obj, sync_obj_arg, lazy, interruptible); if (unlikely(ret != 0)) { driver->sync_obj_unref(&sync_obj); - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); return ret; } - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); if (likely(bo->sync_obj == sync_obj && bo->sync_obj_arg == sync_obj_arg)) { void *tmp_obj = bo->sync_obj; bo->sync_obj = NULL; clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); driver->sync_obj_unref(&sync_obj); driver->sync_obj_unref(&tmp_obj); - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); } else { - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); driver->sync_obj_unref(&sync_obj); - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); } } return 0; @@ -1714,6 +1714,7 @@ EXPORT_SYMBOL(ttm_bo_wait); int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) { + struct ttm_bo_device *bdev = bo->bdev; int ret = 0; /* @@ -1723,9 +1724,9 @@ int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) ret = ttm_bo_reserve(bo, true, no_wait, false, 0); if (unlikely(ret != 0)) return ret; - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, true, no_wait); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (likely(ret == 0)) atomic_inc(&bo->cpu_writers); ttm_bo_unreserve(bo); @@ -1797,9 +1798,9 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) * Wait for GPU, then move to system cached. */ - spin_lock(&bo->lock); + spin_lock(&bo->bdev->fence_lock); ret = ttm_bo_wait(bo, false, false, false); - spin_unlock(&bo->lock); + spin_unlock(&bo->bdev->fence_lock); if (unlikely(ret != 0)) goto out; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 3106d5bcce32..4b75133d6606 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -337,7 +337,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, * TODO: Explicit member copy would probably be better here. */ - spin_lock_init(&fbo->lock); init_waitqueue_head(&fbo->event_queue); INIT_LIST_HEAD(&fbo->ddestroy); INIT_LIST_HEAD(&fbo->lru); @@ -520,7 +519,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, struct ttm_buffer_object *ghost_obj; void *tmp_obj = NULL; - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); if (bo->sync_obj) { tmp_obj = bo->sync_obj; bo->sync_obj = NULL; @@ -529,7 +528,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, bo->sync_obj_arg = sync_obj_arg; if (evict) { ret = ttm_bo_wait(bo, false, false, false); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (tmp_obj) driver->sync_obj_unref(&tmp_obj); if (ret) @@ -552,7 +551,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, */ set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (tmp_obj) driver->sync_obj_unref(&tmp_obj); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index fe6cb77899f4..8dd446cb778e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -118,17 +118,17 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * move. */ - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) { ret = ttm_bo_wait(bo, false, true, false); - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); if (unlikely(ret != 0)) { retval = (ret != -ERESTARTSYS) ? VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; goto out_unlock; } } else - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); ret = ttm_mem_io_reserve(bdev, &bo->mem); diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 7dcc6470e2f5..c3a2100bace6 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -203,14 +203,15 @@ void ttm_eu_fence_buffer_objects(struct list_head *list, void *sync_obj) list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - struct ttm_bo_driver *driver = bo->bdev->driver; + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_bo_driver *driver = bdev->driver; void *old_sync_obj; - spin_lock(&bo->lock); + spin_lock(&bdev->fence_lock); old_sync_obj = bo->sync_obj; bo->sync_obj = driver->sync_obj_ref(sync_obj); bo->sync_obj_arg = entry->new_sync_obj_arg; - spin_unlock(&bo->lock); + spin_unlock(&bdev->fence_lock); ttm_bo_unreserve(bo); entry->reserved = false; if (old_sync_obj) diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index b0fc9c12554b..edacd483c59c 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -154,7 +154,6 @@ struct ttm_tt; * keeps one refcount. When this refcount reaches zero, * the object is destroyed. * @event_queue: Queue for processes waiting on buffer object status change. - * @lock: spinlock protecting mostly synchronization members. * @mem: structure describing current placement. * @persistant_swap_storage: Usually the swap storage is deleted for buffers * pinned in physical memory. If this behaviour is not desired, this member @@ -213,7 +212,6 @@ struct ttm_buffer_object { struct kref kref; struct kref list_kref; wait_queue_head_t event_queue; - spinlock_t lock; /** * Members protected by the bo::reserved lock. @@ -248,10 +246,10 @@ struct ttm_buffer_object { atomic_t reserved; /** - * Members protected by the bo::lock + * Members protected by struct buffer_object_device::fence_lock * In addition, setting sync_obj to anything else * than NULL requires bo::reserved to be held. This allows for - * checking NULL while reserved but not holding bo::lock. + * checking NULL while reserved but not holding the mentioned lock. */ void *sync_obj_arg; diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 1e25a40c688e..ca8131e98300 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -510,6 +510,8 @@ struct ttm_bo_global { * * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. * @man: An array of mem_type_managers. + * @fence_lock: Protects the synchronizing members on *all* bos belonging + * to this device. * @addr_space_mm: Range manager for the device address space. * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. @@ -531,6 +533,7 @@ struct ttm_bo_device { struct ttm_bo_driver *driver; rwlock_t vm_lock; struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; + spinlock_t fence_lock; /* * Protected by the vm lock. */ -- cgit v1.2.3 From 95762c2b34069bf4adb7929969f1f5f5fc8a38df Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 12:28:30 +0000 Subject: drm/ttm: Improved fencing of buffer object lists Drastically reduce the number of spin lock / unlock operations by performing unreserving and fencing under global locks. Signed-off-by: Thomas Hellstrom Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 11 ++++++++--- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 36 +++++++++++++++++++++++----------- include/drm/ttm/ttm_bo_driver.h | 10 ++++++++++ include/drm/ttm/ttm_execbuf_util.h | 2 ++ 4 files changed, 45 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index d93c73b1c471..551a5d31cadf 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -299,14 +299,19 @@ int ttm_bo_reserve(struct ttm_buffer_object *bo, return ret; } +void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo) +{ + ttm_bo_add_to_lru(bo); + atomic_set(&bo->reserved, 0); + wake_up_all(&bo->event_queue); +} + void ttm_bo_unreserve(struct ttm_buffer_object *bo) { struct ttm_bo_global *glob = bo->glob; spin_lock(&glob->lru_lock); - ttm_bo_add_to_lru(bo); - atomic_set(&bo->reserved, 0); - wake_up_all(&bo->event_queue); + ttm_bo_unreserve_locked(bo); spin_unlock(&glob->lru_lock); } EXPORT_SYMBOL(ttm_bo_unreserve); diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index c3a2100bace6..b6da65cc502a 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -200,22 +200,36 @@ EXPORT_SYMBOL(ttm_eu_reserve_buffers); void ttm_eu_fence_buffer_objects(struct list_head *list, void *sync_obj) { struct ttm_validate_buffer *entry; + struct ttm_buffer_object *bo; + struct ttm_bo_global *glob; + struct ttm_bo_device *bdev; + struct ttm_bo_driver *driver; - list_for_each_entry(entry, list, head) { - struct ttm_buffer_object *bo = entry->bo; - struct ttm_bo_device *bdev = bo->bdev; - struct ttm_bo_driver *driver = bdev->driver; - void *old_sync_obj; + if (list_empty(list)) + return; + + bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo; + bdev = bo->bdev; + driver = bdev->driver; + glob = bo->glob; - spin_lock(&bdev->fence_lock); - old_sync_obj = bo->sync_obj; + spin_lock(&bdev->fence_lock); + spin_lock(&glob->lru_lock); + + list_for_each_entry(entry, list, head) { + bo = entry->bo; + entry->old_sync_obj = bo->sync_obj; bo->sync_obj = driver->sync_obj_ref(sync_obj); bo->sync_obj_arg = entry->new_sync_obj_arg; - spin_unlock(&bdev->fence_lock); - ttm_bo_unreserve(bo); + ttm_bo_unreserve_locked(bo); entry->reserved = false; - if (old_sync_obj) - driver->sync_obj_unref(&old_sync_obj); + } + spin_unlock(&glob->lru_lock); + spin_unlock(&bdev->fence_lock); + + list_for_each_entry(entry, list, head) { + if (entry->old_sync_obj) + driver->sync_obj_unref(&entry->old_sync_obj); } } EXPORT_SYMBOL(ttm_eu_fence_buffer_objects); diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index ca8131e98300..cfb9ca4ec1c4 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -909,6 +909,16 @@ extern int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, */ extern void ttm_bo_unreserve(struct ttm_buffer_object *bo); +/** + * ttm_bo_unreserve_locked + * + * @bo: A pointer to a struct ttm_buffer_object. + * + * Unreserve a previous reservation of @bo. + * Needs to be called with struct ttm_bo_global::lru_lock held. + */ +extern void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo); + /** * ttm_bo_wait_unreserved * diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index fd09b8438977..535ab00407e0 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -44,6 +44,7 @@ * @reserved: Indicates whether @bo has been reserved for validation. * @removed: Indicates whether @bo has been removed from lru lists. * @put_count: Number of outstanding references on bo::list_kref. + * @old_sync_obj: Pointer to a sync object about to be unreferenced */ struct ttm_validate_buffer { @@ -53,6 +54,7 @@ struct ttm_validate_buffer { bool reserved; bool removed; int put_count; + void *old_sync_obj; }; /** -- cgit v1.2.3 From 65705962025df490d13df59ec57c5329d1bd0a16 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 12:28:31 +0000 Subject: drm/ttm/vmwgfx: Have TTM manage the validation sequence. Rather than having the driver supply the validation sequence, leave that responsibility to TTM. This saves some confusion and a function argument. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 1 + drivers/gpu/drm/ttm/ttm_execbuf_util.c | 5 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 3 +-- include/drm/ttm/ttm_bo_driver.h | 2 ++ include/drm/ttm/ttm_execbuf_util.h | 3 +-- 6 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 551a5d31cadf..25e4c2a1d1d8 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1539,6 +1539,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, bdev->dev_mapping = NULL; bdev->glob = glob; bdev->need_dma32 = need_dma32; + bdev->val_seq = 0; spin_lock_init(&bdev->fence_lock); mutex_lock(&glob->device_list_mutex); list_add_tail(&bdev->device_list, &glob->device_list); diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index b6da65cc502a..3832fe10b4df 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -126,11 +126,12 @@ EXPORT_SYMBOL(ttm_eu_backoff_reservation); * buffers in different orders. */ -int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq) +int ttm_eu_reserve_buffers(struct list_head *list) { struct ttm_bo_global *glob; struct ttm_validate_buffer *entry; int ret; + uint32_t val_seq; if (list_empty(list)) return 0; @@ -146,6 +147,8 @@ int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq) retry: spin_lock(&glob->lru_lock); + val_seq = entry->bo->bdev->val_seq++; + list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e7a58d055041..10fc01f69c40 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -264,7 +264,6 @@ struct vmw_private { */ struct vmw_sw_context ctx; - uint32_t val_seq; struct mutex cmdbuf_mutex; /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 76954e3528c1..41b95ed6dbcd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -653,8 +653,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ret = vmw_cmd_check_all(dev_priv, sw_context, cmd, arg->command_size); if (unlikely(ret != 0)) goto out_err; - ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes, - dev_priv->val_seq++); + ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes); if (unlikely(ret != 0)) goto out_err; diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index cfb9ca4ec1c4..e3b2e245db1b 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -515,6 +515,7 @@ struct ttm_bo_global { * @addr_space_mm: Range manager for the device address space. * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. + * @val_seq: Current validation sequence. * @nice_mode: Try nicely to wait for buffer idle when cleaning a manager. * If a GPU lockup has been detected, this is forced to 0. * @dev_mapping: A pointer to the struct address_space representing the @@ -544,6 +545,7 @@ struct ttm_bo_device { * Protected by the global:lru lock. */ struct list_head ddestroy; + uint32_t val_seq; /* * Protected by load / firstopen / lastclose /unload sync. diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index 535ab00407e0..26cc7f9ffa41 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -72,7 +72,6 @@ extern void ttm_eu_backoff_reservation(struct list_head *list); * function ttm_eu_reserve_buffers * * @list: thread private list of ttm_validate_buffer structs. - * @val_seq: A unique sequence number. * * Tries to reserve bos pointed to by the list entries for validation. * If the function returns 0, all buffers are marked as "unfenced", @@ -94,7 +93,7 @@ extern void ttm_eu_backoff_reservation(struct list_head *list); * has failed. */ -extern int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq); +extern int ttm_eu_reserve_buffers(struct list_head *list); /** * function ttm_eu_fence_buffer_objects. -- cgit v1.2.3 From eba67093f535322cb4f1c4b737319c0907a0c81d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 11 Nov 2010 09:41:57 +0100 Subject: drm/ttm: Fix up io_mem_reserve / io_mem_free calling This patch attempts to fix up shortcomings with the current calling sequences. 1) There's a fastpath where no locking occurs and only io_mem_reserved is called to obtain needed info for mapping. The fastpath is set per memory type manager. 2) If the fastpath is disabled, io_mem_reserve and io_mem_free will be exactly balanced and not called recursively for the same struct ttm_mem_reg. 3) Optionally the driver can choose to enable a per memory type manager LRU eviction mechanism that, when io_mem_reserve returns -EAGAIN will attempt to kill user-space mappings of memory in that manager to free up needed resources Signed-off-by: Thomas Hellstrom Reviewed-by: Ben Skeggs Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 44 ++++++++++--- drivers/gpu/drm/ttm/ttm_bo_util.c | 129 +++++++++++++++++++++++++++++++++----- drivers/gpu/drm/ttm/ttm_bo_vm.c | 23 ++++--- include/drm/ttm/ttm_bo_api.h | 6 +- include/drm/ttm/ttm_bo_driver.h | 104 +++++++++++++++--------------- 5 files changed, 226 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 25e4c2a1d1d8..cf2ec562550e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -378,8 +378,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, int ret = 0; if (old_is_pci || new_is_pci || - ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) - ttm_bo_unmap_virtual(bo); + ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) { + ret = ttm_mem_io_lock(old_man, true); + if (unlikely(ret != 0)) + goto out_err; + ttm_bo_unmap_virtual_locked(bo); + ttm_mem_io_unlock(old_man); + } /* * Create and bind a ttm if required. @@ -466,7 +471,6 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) ttm_tt_destroy(bo->ttm); bo->ttm = NULL; } - ttm_bo_mem_put(bo, &bo->mem); atomic_set(&bo->reserved, 0); @@ -665,6 +669,7 @@ static void ttm_bo_release(struct kref *kref) struct ttm_buffer_object *bo = container_of(kref, struct ttm_buffer_object, kref); struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; if (likely(bo->vm_node != NULL)) { rb_erase(&bo->vm_rb, &bdev->addr_space_rb); @@ -672,6 +677,9 @@ static void ttm_bo_release(struct kref *kref) bo->vm_node = NULL; } write_unlock(&bdev->vm_lock); + ttm_mem_io_lock(man, false); + ttm_mem_io_free_vm(bo); + ttm_mem_io_unlock(man); ttm_bo_cleanup_refs_or_queue(bo); kref_put(&bo->list_kref, ttm_bo_release_list); write_lock(&bdev->vm_lock); @@ -728,7 +736,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, evict_mem = bo->mem; evict_mem.mm_node = NULL; - evict_mem.bus.io_reserved = false; + evict_mem.bus.io_reserved_vm = false; + evict_mem.bus.io_reserved_count = 0; placement.fpfn = 0; placement.lpfn = 0; @@ -1065,7 +1074,8 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, mem.num_pages = bo->num_pages; mem.size = mem.num_pages << PAGE_SHIFT; mem.page_alignment = bo->mem.page_alignment; - mem.bus.io_reserved = false; + mem.bus.io_reserved_vm = false; + mem.bus.io_reserved_count = 0; /* * Determine where to move the buffer. */ @@ -1184,6 +1194,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, INIT_LIST_HEAD(&bo->lru); INIT_LIST_HEAD(&bo->ddestroy); INIT_LIST_HEAD(&bo->swap); + INIT_LIST_HEAD(&bo->io_reserve_lru); bo->bdev = bdev; bo->glob = bdev->glob; bo->type = type; @@ -1193,7 +1204,8 @@ int ttm_bo_init(struct ttm_bo_device *bdev, bo->mem.num_pages = bo->num_pages; bo->mem.mm_node = NULL; bo->mem.page_alignment = page_alignment; - bo->mem.bus.io_reserved = false; + bo->mem.bus.io_reserved_vm = false; + bo->mem.bus.io_reserved_count = 0; bo->buffer_start = buffer_start & PAGE_MASK; bo->priv_flags = 0; bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED); @@ -1367,6 +1379,10 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, BUG_ON(type >= TTM_NUM_MEM_TYPES); man = &bdev->man[type]; BUG_ON(man->has_type); + man->io_reserve_fastpath = true; + man->use_io_reserve_lru = false; + mutex_init(&man->io_reserve_mutex); + INIT_LIST_HEAD(&man->io_reserve_lru); ret = bdev->driver->init_mem_type(bdev, type, man); if (ret) @@ -1574,7 +1590,7 @@ bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) return true; } -void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) +void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; loff_t offset = (loff_t) bo->addr_space_offset; @@ -1583,8 +1599,20 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) if (!bdev->dev_mapping) return; unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1); - ttm_mem_io_free(bdev, &bo->mem); + ttm_mem_io_free_vm(bo); } + +void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) +{ + struct ttm_bo_device *bdev = bo->bdev; + struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; + + ttm_mem_io_lock(man, false); + ttm_bo_unmap_virtual_locked(bo); + ttm_mem_io_unlock(man); +} + + EXPORT_SYMBOL(ttm_bo_unmap_virtual); static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo) diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 4b75133d6606..a89839f83f6c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -75,37 +75,123 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, } EXPORT_SYMBOL(ttm_bo_move_ttm); -int ttm_mem_io_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) { - int ret; + if (likely(man->io_reserve_fastpath)) + return 0; + + if (interruptible) + return mutex_lock_interruptible(&man->io_reserve_mutex); + + mutex_lock(&man->io_reserve_mutex); + return 0; +} - if (!mem->bus.io_reserved) { - mem->bus.io_reserved = true; +void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) +{ + if (likely(man->io_reserve_fastpath)) + return; + + mutex_unlock(&man->io_reserve_mutex); +} + +static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) +{ + struct ttm_buffer_object *bo; + + if (!man->use_io_reserve_lru || list_empty(&man->io_reserve_lru)) + return -EAGAIN; + + bo = list_first_entry(&man->io_reserve_lru, + struct ttm_buffer_object, + io_reserve_lru); + list_del_init(&bo->io_reserve_lru); + ttm_bo_unmap_virtual_locked(bo); + + return 0; +} + +static int ttm_mem_io_reserve(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + int ret = 0; + + if (!bdev->driver->io_mem_reserve) + return 0; + if (likely(man->io_reserve_fastpath)) + return bdev->driver->io_mem_reserve(bdev, mem); + + if (bdev->driver->io_mem_reserve && + mem->bus.io_reserved_count++ == 0) { +retry: ret = bdev->driver->io_mem_reserve(bdev, mem); + if (ret == -EAGAIN) { + ret = ttm_mem_io_evict(man); + if (ret == 0) + goto retry; + } + } + return ret; +} + +static void ttm_mem_io_free(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + + if (likely(man->io_reserve_fastpath)) + return; + + if (bdev->driver->io_mem_reserve && + --mem->bus.io_reserved_count == 0 && + bdev->driver->io_mem_free) + bdev->driver->io_mem_free(bdev, mem); + +} + +int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) +{ + struct ttm_mem_reg *mem = &bo->mem; + int ret; + + if (!mem->bus.io_reserved_vm) { + struct ttm_mem_type_manager *man = + &bo->bdev->man[mem->mem_type]; + + ret = ttm_mem_io_reserve(bo->bdev, mem); if (unlikely(ret != 0)) return ret; + mem->bus.io_reserved_vm = true; + if (man->use_io_reserve_lru) + list_add_tail(&bo->io_reserve_lru, + &man->io_reserve_lru); } return 0; } -void ttm_mem_io_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) +void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) { - if (bdev->driver->io_mem_reserve) { - if (mem->bus.io_reserved) { - mem->bus.io_reserved = false; - bdev->driver->io_mem_free(bdev, mem); - } + struct ttm_mem_reg *mem = &bo->mem; + + if (mem->bus.io_reserved_vm) { + mem->bus.io_reserved_vm = false; + list_del_init(&bo->io_reserve_lru); + ttm_mem_io_free(bo->bdev, mem); } } int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, void **virtual) { + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; int ret; void *addr; *virtual = NULL; + (void) ttm_mem_io_lock(man, false); ret = ttm_mem_io_reserve(bdev, mem); + ttm_mem_io_unlock(man); if (ret || !mem->bus.is_iomem) return ret; @@ -117,7 +203,9 @@ int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, else addr = ioremap_nocache(mem->bus.base + mem->bus.offset, mem->bus.size); if (!addr) { + (void) ttm_mem_io_lock(man, false); ttm_mem_io_free(bdev, mem); + ttm_mem_io_unlock(man); return -ENOMEM; } } @@ -134,7 +222,9 @@ void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, if (virtual && mem->bus.addr == NULL) iounmap(virtual); + (void) ttm_mem_io_lock(man, false); ttm_mem_io_free(bdev, mem); + ttm_mem_io_unlock(man); } static int ttm_copy_io_page(void *dst, void *src, unsigned long page) @@ -231,7 +321,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; struct ttm_tt *ttm = bo->ttm; struct ttm_mem_reg *old_mem = &bo->mem; - struct ttm_mem_reg old_copy = *old_mem; + struct ttm_mem_reg old_copy; void *old_iomap; void *new_iomap; int ret; @@ -281,7 +371,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, mb(); out2: ttm_bo_free_old_node(bo); - + old_copy = *old_mem; *old_mem = *new_mem; new_mem->mm_node = NULL; @@ -292,7 +382,7 @@ out2: } out1: - ttm_mem_reg_iounmap(bdev, new_mem, new_iomap); + ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); out: ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); return ret; @@ -341,6 +431,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, INIT_LIST_HEAD(&fbo->ddestroy); INIT_LIST_HEAD(&fbo->lru); INIT_LIST_HEAD(&fbo->swap); + INIT_LIST_HEAD(&fbo->io_reserve_lru); fbo->vm_node = NULL; atomic_set(&fbo->cpu_writers, 0); @@ -452,6 +543,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page, unsigned long num_pages, struct ttm_bo_kmap_obj *map) { + struct ttm_mem_type_manager *man = + &bo->bdev->man[bo->mem.mem_type]; unsigned long offset, size; int ret; @@ -466,7 +559,9 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC)) return -EPERM; #endif + (void) ttm_mem_io_lock(man, false); ret = ttm_mem_io_reserve(bo->bdev, &bo->mem); + ttm_mem_io_unlock(man); if (ret) return ret; if (!bo->mem.bus.is_iomem) { @@ -481,12 +576,15 @@ EXPORT_SYMBOL(ttm_bo_kmap); void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) { + struct ttm_buffer_object *bo = map->bo; + struct ttm_mem_type_manager *man = + &bo->bdev->man[bo->mem.mem_type]; + if (!map->virtual) return; switch (map->bo_kmap_type) { case ttm_bo_map_iomap: iounmap(map->virtual); - ttm_mem_io_free(map->bo->bdev, &map->bo->mem); break; case ttm_bo_map_vmap: vunmap(map->virtual); @@ -499,6 +597,9 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) default: BUG(); } + (void) ttm_mem_io_lock(man, false); + ttm_mem_io_free(map->bo->bdev, &map->bo->mem); + ttm_mem_io_unlock(man); map->virtual = NULL; map->page = NULL; } diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 8dd446cb778e..221b924acebe 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -83,6 +83,8 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int i; unsigned long address = (unsigned long)vmf->virtual_address; int retval = VM_FAULT_NOPAGE; + struct ttm_mem_type_manager *man = + &bdev->man[bo->mem.mem_type]; /* * Work around locking order reversal in fault / nopfn @@ -130,12 +132,16 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } else spin_unlock(&bdev->fence_lock); - - ret = ttm_mem_io_reserve(bdev, &bo->mem); - if (ret) { - retval = VM_FAULT_SIGBUS; + ret = ttm_mem_io_lock(man, true); + if (unlikely(ret != 0)) { + retval = VM_FAULT_NOPAGE; goto out_unlock; } + ret = ttm_mem_io_reserve_vm(bo); + if (unlikely(ret != 0)) { + retval = VM_FAULT_SIGBUS; + goto out_io_unlock; + } page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) + bo->vm_node->start - vma->vm_pgoff; @@ -144,7 +150,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (unlikely(page_offset >= bo->num_pages)) { retval = VM_FAULT_SIGBUS; - goto out_unlock; + goto out_io_unlock; } /* @@ -182,7 +188,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) page = ttm_tt_get_page(ttm, page_offset); if (unlikely(!page && i == 0)) { retval = VM_FAULT_OOM; - goto out_unlock; + goto out_io_unlock; } else if (unlikely(!page)) { break; } @@ -200,14 +206,15 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) else if (unlikely(ret != 0)) { retval = (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; - goto out_unlock; + goto out_io_unlock; } address += PAGE_SIZE; if (unlikely(++page_offset >= page_last)) break; } - +out_io_unlock: + ttm_mem_io_unlock(man); out_unlock: ttm_bo_unreserve(bo); return retval; diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index edacd483c59c..50852aad260a 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -74,6 +74,8 @@ struct ttm_placement { * @is_iomem: is this io memory ? * @size: size in byte * @offset: offset from the base address + * @io_reserved_vm: The VM system has a refcount in @io_reserved_count + * @io_reserved_count: Refcounting the numbers of callers to ttm_mem_io_reserve * * Structure indicating the bus placement of an object. */ @@ -83,7 +85,8 @@ struct ttm_bus_placement { unsigned long size; unsigned long offset; bool is_iomem; - bool io_reserved; + bool io_reserved_vm; + uint64_t io_reserved_count; }; @@ -235,6 +238,7 @@ struct ttm_buffer_object { struct list_head lru; struct list_head ddestroy; struct list_head swap; + struct list_head io_reserve_lru; uint32_t val_seq; bool seq_valid; diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index e3b2e245db1b..1da8af6ac884 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -179,30 +179,6 @@ struct ttm_tt { #define TTM_MEMTYPE_FLAG_MAPPABLE (1 << 1) /* Memory mappable */ #define TTM_MEMTYPE_FLAG_CMA (1 << 3) /* Can't map aperture */ -/** - * struct ttm_mem_type_manager - * - * @has_type: The memory type has been initialized. - * @use_type: The memory type is enabled. - * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory - * managed by this memory type. - * @gpu_offset: If used, the GPU offset of the first managed page of - * fixed memory or the first managed location in an aperture. - * @size: Size of the managed region. - * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, - * as defined in ttm_placement_common.h - * @default_caching: The default caching policy used for a buffer object - * placed in this memory type if the user doesn't provide one. - * @manager: The range manager used for this memory type. FIXME: If the aperture - * has a page size different from the underlying system, the granularity - * of this manager should take care of this. But the range allocating code - * in ttm_bo.c needs to be modified for this. - * @lru: The lru list for this memory type. - * - * This structure is used to identify and manage memory types for a device. - * It's set up by the ttm_bo_driver::init_mem_type method. - */ - struct ttm_mem_type_manager; struct ttm_mem_type_manager_func { @@ -287,6 +263,36 @@ struct ttm_mem_type_manager_func { void (*debug)(struct ttm_mem_type_manager *man, const char *prefix); }; +/** + * struct ttm_mem_type_manager + * + * @has_type: The memory type has been initialized. + * @use_type: The memory type is enabled. + * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory + * managed by this memory type. + * @gpu_offset: If used, the GPU offset of the first managed page of + * fixed memory or the first managed location in an aperture. + * @size: Size of the managed region. + * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, + * as defined in ttm_placement_common.h + * @default_caching: The default caching policy used for a buffer object + * placed in this memory type if the user doesn't provide one. + * @func: structure pointer implementing the range manager. See above + * @priv: Driver private closure for @func. + * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures + * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions + * reserved by the TTM vm system. + * @io_reserve_lru: Optional lru list for unreserving io mem regions. + * @io_reserve_fastpath: Only use bdev::driver::io_mem_reserve to obtain + * static information. bdev::driver::io_mem_free is never used. + * @lru: The lru list for this memory type. + * + * This structure is used to identify and manage memory types for a device. + * It's set up by the ttm_bo_driver::init_mem_type method. + */ + + + struct ttm_mem_type_manager { struct ttm_bo_device *bdev; @@ -303,6 +309,15 @@ struct ttm_mem_type_manager { uint32_t default_caching; const struct ttm_mem_type_manager_func *func; void *priv; + struct mutex io_reserve_mutex; + bool use_io_reserve_lru; + bool io_reserve_fastpath; + + /* + * Protected by @io_reserve_mutex: + */ + + struct list_head io_reserve_lru; /* * Protected by the global->lru_lock. @@ -758,31 +773,6 @@ extern void ttm_bo_mem_put_locked(struct ttm_buffer_object *bo, extern int ttm_bo_wait_cpu(struct ttm_buffer_object *bo, bool no_wait); -/** - * ttm_bo_pci_offset - Get the PCI offset for the buffer object memory. - * - * @bo Pointer to a struct ttm_buffer_object. - * @bus_base On return the base of the PCI region - * @bus_offset On return the byte offset into the PCI region - * @bus_size On return the byte size of the buffer object or zero if - * the buffer object memory is not accessible through a PCI region. - * - * Returns: - * -EINVAL if the buffer object is currently not mappable. - * 0 otherwise. - */ - -extern int ttm_bo_pci_offset(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem, - unsigned long *bus_base, - unsigned long *bus_offset, - unsigned long *bus_size); - -extern int ttm_mem_io_reserve(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); -extern void ttm_mem_io_free(struct ttm_bo_device *bdev, - struct ttm_mem_reg *mem); - extern void ttm_bo_global_release(struct drm_global_reference *ref); extern int ttm_bo_global_init(struct drm_global_reference *ref); @@ -814,6 +804,22 @@ extern int ttm_bo_device_init(struct ttm_bo_device *bdev, */ extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo); +/** + * ttm_bo_unmap_virtual + * + * @bo: tear down the virtual mappings for this BO + * + * The caller must take ttm_mem_io_lock before calling this function. + */ +extern void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo); + +extern int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo); +extern void ttm_mem_io_free_vm(struct ttm_buffer_object *bo); +extern int ttm_mem_io_lock(struct ttm_mem_type_manager *man, + bool interruptible); +extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); + + /** * ttm_bo_reserve: * -- cgit v1.2.3 From 147666fb3b93b8c484f562da33a37f886ddff768 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 17 Nov 2010 12:38:32 +0000 Subject: drm/radeon: Use the ttm execbuf utilities Rather than re-implementing in the Radeon driver, Use the execbuf / cs / pushbuf utilities that comes with TTM. This comes with an even greater benefit now that many spinlocks have been optimized away... Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 4 +-- drivers/gpu/drm/radeon/radeon_cs.c | 17 ++++++----- drivers/gpu/drm/radeon/radeon_object.c | 55 +++------------------------------- drivers/gpu/drm/radeon/radeon_object.h | 3 -- 4 files changed, 16 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3a7095743d44..b1e073b7381f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -69,6 +69,7 @@ #include #include #include +#include #include "radeon_family.h" #include "radeon_mode.h" @@ -259,13 +260,12 @@ struct radeon_bo { }; struct radeon_bo_list { - struct list_head list; + struct ttm_validate_buffer tv; struct radeon_bo *bo; uint64_t gpu_offset; unsigned rdomain; unsigned wdomain; u32 tiling_flags; - bool reserved; }; /* diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 6d64a2705f12..35b5eb8fbe2a 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -77,13 +77,13 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p) p->relocs_ptr[i] = &p->relocs[i]; p->relocs[i].robj = p->relocs[i].gobj->driver_private; p->relocs[i].lobj.bo = p->relocs[i].robj; - p->relocs[i].lobj.rdomain = r->read_domains; p->relocs[i].lobj.wdomain = r->write_domain; + p->relocs[i].lobj.rdomain = r->read_domains; + p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo; p->relocs[i].handle = r->handle; p->relocs[i].flags = r->flags; - INIT_LIST_HEAD(&p->relocs[i].lobj.list); radeon_bo_list_add_object(&p->relocs[i].lobj, - &p->validated); + &p->validated); } } return radeon_bo_list_validate(&p->validated); @@ -189,10 +189,13 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) { unsigned i; - if (!error && parser->ib) { - radeon_bo_list_fence(&parser->validated, parser->ib->fence); - } - radeon_bo_list_unreserve(&parser->validated); + + if (!error && parser->ib) + ttm_eu_fence_buffer_objects(&parser->validated, + parser->ib->fence); + else + ttm_eu_backoff_reservation(&parser->validated); + if (parser->relocs != NULL) { for (i = 0; i < parser->nrelocs; i++) { if (parser->relocs[i].gobj) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index e939cb6a91cc..a8594d289bcf 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -293,34 +293,9 @@ void radeon_bo_list_add_object(struct radeon_bo_list *lobj, struct list_head *head) { if (lobj->wdomain) { - list_add(&lobj->list, head); + list_add(&lobj->tv.head, head); } else { - list_add_tail(&lobj->list, head); - } -} - -int radeon_bo_list_reserve(struct list_head *head) -{ - struct radeon_bo_list *lobj; - int r; - - list_for_each_entry(lobj, head, list){ - r = radeon_bo_reserve(lobj->bo, false); - if (unlikely(r != 0)) - return r; - lobj->reserved = true; - } - return 0; -} - -void radeon_bo_list_unreserve(struct list_head *head) -{ - struct radeon_bo_list *lobj; - - list_for_each_entry(lobj, head, list) { - /* only unreserve object we successfully reserved */ - if (lobj->reserved && radeon_bo_is_reserved(lobj->bo)) - radeon_bo_unreserve(lobj->bo); + list_add_tail(&lobj->tv.head, head); } } @@ -331,14 +306,11 @@ int radeon_bo_list_validate(struct list_head *head) u32 domain; int r; - list_for_each_entry(lobj, head, list) { - lobj->reserved = false; - } - r = radeon_bo_list_reserve(head); + r = ttm_eu_reserve_buffers(head); if (unlikely(r != 0)) { return r; } - list_for_each_entry(lobj, head, list) { + list_for_each_entry(lobj, head, tv.head) { bo = lobj->bo; if (!bo->pin_count) { domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain; @@ -361,25 +333,6 @@ int radeon_bo_list_validate(struct list_head *head) return 0; } -void radeon_bo_list_fence(struct list_head *head, void *fence) -{ - struct radeon_bo_list *lobj; - struct radeon_bo *bo; - struct radeon_fence *old_fence = NULL; - - list_for_each_entry(lobj, head, list) { - bo = lobj->bo; - spin_lock(&bo->tbo.bdev->fence_lock); - old_fence = (struct radeon_fence *)bo->tbo.sync_obj; - bo->tbo.sync_obj = radeon_fence_ref(fence); - bo->tbo.sync_obj_arg = NULL; - spin_unlock(&bo->tbo.bdev->fence_lock); - if (old_fence) { - radeon_fence_unref(&old_fence); - } - } -} - int radeon_bo_fbdev_mmap(struct radeon_bo *bo, struct vm_area_struct *vma) { diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index fd536751f865..22d4c237dea5 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -152,10 +152,7 @@ extern int radeon_bo_init(struct radeon_device *rdev); extern void radeon_bo_fini(struct radeon_device *rdev); extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, struct list_head *head); -extern int radeon_bo_list_reserve(struct list_head *head); -extern void radeon_bo_list_unreserve(struct list_head *head); extern int radeon_bo_list_validate(struct list_head *head); -extern void radeon_bo_list_fence(struct list_head *head, void *fence); extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, struct vm_area_struct *vma); extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, -- cgit v1.2.3 From c724e8a9407683a8a2ee8eb00b972badf237bbe1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Nov 2010 08:07:02 +0000 Subject: drm/i915: Capture pinned buffers on error The pinned buffers are useful for diagnosing errors in setting up state for the chipset, which may not necessarily be 'active' at the time of the error, e.g. the cursor buffer object. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 63 +++++++++++++++++---------- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/i915_irq.c | 87 ++++++++++++++++++++++++------------- 3 files changed, 98 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4c8fae9baaad..24a88ac63212 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -609,6 +609,36 @@ static const char *purgeable_flag(int purgeable) return purgeable ? " purgeable" : ""; } +static void print_error_buffers(struct seq_file *m, + const char *name, + struct drm_i915_error_buffer *err, + int count) +{ + seq_printf(m, "%s [%d]:\n", name, count); + + while (count--) { + seq_printf(m, " %08x %8zd %04x %04x %08x%s%s%s%s%s", + err->gtt_offset, + err->size, + err->read_domains, + err->write_domain, + err->seqno, + pin_flag(err->pinned), + tiling_flag(err->tiling), + dirty_flag(err->dirty), + purgeable_flag(err->purgeable), + ring_str(err->ring)); + + if (err->name) + seq_printf(m, " (name: %d)", err->name); + if (err->fence_reg != I915_FENCE_REG_NONE) + seq_printf(m, " (fence: %d)", err->fence_reg); + + seq_printf(m, "\n"); + err++; + } +} + static int i915_error_state(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -658,30 +688,15 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); seq_printf(m, " seqno: 0x%08x\n", error->seqno); - if (error->active_bo_count) { - seq_printf(m, "Buffers [%d]:\n", error->active_bo_count); - - for (i = 0; i < error->active_bo_count; i++) { - seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s %s", - error->active_bo[i].gtt_offset, - error->active_bo[i].size, - error->active_bo[i].read_domains, - error->active_bo[i].write_domain, - error->active_bo[i].seqno, - pin_flag(error->active_bo[i].pinned), - tiling_flag(error->active_bo[i].tiling), - dirty_flag(error->active_bo[i].dirty), - purgeable_flag(error->active_bo[i].purgeable), - ring_str(error->active_bo[i].ring)); - - if (error->active_bo[i].name) - seq_printf(m, " (name: %d)", error->active_bo[i].name); - if (error->active_bo[i].fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d)", error->active_bo[i].fence_reg); - - seq_printf(m, "\n"); - } - } + if (error->active_bo) + print_error_buffers(m, "Active", + error->active_bo, + error->active_bo_count); + + if (error->pinned_bo) + print_error_buffers(m, "Pinned", + error->pinned_bo, + error->pinned_bo_count); for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) { if (error->batchbuffer[i]) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 73a41f7ab8c6..826c7237409b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -184,8 +184,8 @@ struct drm_i915_error_state { u32 dirty:1; u32 purgeable:1; u32 ring:4; - } *active_bo; - u32 active_bo_count; + } *active_bo, *pinned_bo; + u32 active_bo_count, pinned_bo_count; struct intel_overlay_error_state *overlay; }; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ef3503733ebb..bbcd5da89ba5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -552,6 +552,40 @@ i915_ringbuffer_last_batch(struct drm_device *dev, return bbaddr; } +static u32 capture_bo_list(struct drm_i915_error_buffer *err, + int count, + struct list_head *head) +{ + struct drm_i915_gem_object *obj; + int i = 0; + + list_for_each_entry(obj, head, mm_list) { + err->size = obj->base.size; + err->name = obj->base.name; + err->seqno = obj->last_rendering_seqno; + err->gtt_offset = obj->gtt_offset; + err->read_domains = obj->base.read_domains; + err->write_domain = obj->base.write_domain; + err->fence_reg = obj->fence_reg; + err->pinned = 0; + if (obj->pin_count > 0) + err->pinned = 1; + if (obj->user_pin_count > 0) + err->pinned = -1; + err->tiling = obj->tiling_mode; + err->dirty = obj->dirty; + err->purgeable = obj->madv != I915_MADV_WILLNEED; + err->ring = obj->ring->id; + + if (++i == count) + break; + + err++; + } + + return i; +} + /** * i915_capture_error_state - capture an error record for later analysis * @dev: drm device @@ -700,42 +734,35 @@ static void i915_capture_error_state(struct drm_device *dev) error->ringbuffer = i915_error_object_create(dev, dev_priv->render_ring.gem_object); - /* Record buffers on the active list. */ + /* Record buffers on the active and pinned lists. */ error->active_bo = NULL; - error->active_bo_count = 0; + error->pinned_bo = NULL; - if (count) + error->active_bo_count = count; + list_for_each_entry(obj_priv, &dev_priv->mm.pinned_list, mm_list) + count++; + error->pinned_bo_count = count - error->active_bo_count; + + if (count) { error->active_bo = kmalloc(sizeof(*error->active_bo)*count, GFP_ATOMIC); - - if (error->active_bo) { - int i = 0; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { - struct drm_gem_object *obj = &obj_priv->base; - - error->active_bo[i].size = obj->size; - error->active_bo[i].name = obj->name; - error->active_bo[i].seqno = obj_priv->last_rendering_seqno; - error->active_bo[i].gtt_offset = obj_priv->gtt_offset; - error->active_bo[i].read_domains = obj->read_domains; - error->active_bo[i].write_domain = obj->write_domain; - error->active_bo[i].fence_reg = obj_priv->fence_reg; - error->active_bo[i].pinned = 0; - if (obj_priv->pin_count > 0) - error->active_bo[i].pinned = 1; - if (obj_priv->user_pin_count > 0) - error->active_bo[i].pinned = -1; - error->active_bo[i].tiling = obj_priv->tiling_mode; - error->active_bo[i].dirty = obj_priv->dirty; - error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED; - error->active_bo[i].ring = obj_priv->ring->id; - - if (++i == count) - break; - } - error->active_bo_count = i; + if (error->active_bo) + error->pinned_bo = + error->active_bo + error->active_bo_count; } + if (error->active_bo) + error->active_bo_count = + capture_bo_list(error->active_bo, + error->active_bo_count, + &dev_priv->mm.active_list); + + if (error->pinned_bo) + error->pinned_bo_count = + capture_bo_list(error->pinned_bo, + error->pinned_bo_count, + &dev_priv->mm.pinned_list); + do_gettimeofday(&error->time); error->overlay = intel_overlay_capture_error_state(dev); -- cgit v1.2.3 From c4a1d9e4dc5d5313cfec2cc0c9d630efe8a6f287 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 21 Nov 2010 13:12:35 +0000 Subject: drm/i915: Capture interesting display registers on error When trying to diagnose mysterious errors on resume, capture the display register contents as well. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 + drivers/gpu/drm/i915/i915_drv.h | 8 +++ drivers/gpu/drm/i915/i915_irq.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 6 +- drivers/gpu/drm/i915/intel_display.c | 110 +++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 24a88ac63212..421b8414b577 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -729,6 +729,9 @@ static int i915_error_state(struct seq_file *m, void *unused) if (error->overlay) intel_overlay_print_error_state(m, error->overlay); + if (error->display) + intel_display_print_error_state(m, dev, error->display); + out: spin_unlock_irqrestore(&dev_priv->error_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 826c7237409b..4c20ad92c0f3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -140,6 +140,8 @@ struct sdvo_device_mapping { u8 ddc_pin; }; +struct intel_display_error_state; + struct drm_i915_error_state { u32 eir; u32 pgtbl_er; @@ -187,6 +189,7 @@ struct drm_i915_error_state { } *active_bo, *pinned_bo; u32 active_bo_count, pinned_bo_count; struct intel_overlay_error_state *overlay; + struct intel_display_error_state *display; }; struct drm_i915_display_funcs { @@ -1223,6 +1226,11 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #ifdef CONFIG_DEBUG_FS extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error); + +extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev); +extern void intel_display_print_error_state(struct seq_file *m, + struct drm_device *dev, + struct intel_display_error_state *error); #endif /** diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bbcd5da89ba5..0b6052abedd1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -766,6 +766,7 @@ static void i915_capture_error_state(struct drm_device *dev) do_gettimeofday(&error->time); error->overlay = intel_overlay_capture_error_state(dev); + error->display = intel_display_capture_error_state(dev); spin_lock_irqsave(&dev_priv->error_lock, flags); if (dev_priv->first_error == NULL) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 886c0e072490..ec2a8b07ba5b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1193,7 +1193,6 @@ #define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B) #define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B) #define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B) -#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC) #define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B) /* VGA port control */ @@ -2207,6 +2206,7 @@ #define PIPE_6BPC (2 << 5) #define PIPE_12BPC (3 << 5) +#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC) #define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF) #define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL) @@ -2376,6 +2376,10 @@ #define CURBBASE 0x700c4 #define CURBPOS 0x700c8 +#define CURCNTR(pipe) _PIPE(pipe, CURACNTR, CURBCNTR) +#define CURBASE(pipe) _PIPE(pipe, CURABASE, CURBBASE) +#define CURPOS(pipe) _PIPE(pipe, CURAPOS, CURBPOS) + /* Display A control */ #define DSPACNTR 0x70180 #define DISPLAY_PLANE_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3fa5aaa941d2..d4bc443f43fc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6269,3 +6269,113 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state) pci_write_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, gmch_ctrl); return 0; } + +#ifdef CONFIG_DEBUG_FS +#include + +struct intel_display_error_state { + struct intel_cursor_error_state { + u32 control; + u32 position; + u32 base; + u32 size; + } cursor[2]; + + struct intel_pipe_error_state { + u32 conf; + u32 source; + + u32 htotal; + u32 hblank; + u32 hsync; + u32 vtotal; + u32 vblank; + u32 vsync; + } pipe[2]; + + struct intel_plane_error_state { + u32 control; + u32 stride; + u32 size; + u32 pos; + u32 addr; + u32 surface; + u32 tile_offset; + } plane[2]; +}; + +struct intel_display_error_state * +intel_display_capture_error_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_display_error_state *error; + int i; + + error = kmalloc(sizeof(*error), GFP_ATOMIC); + if (error == NULL) + return NULL; + + for (i = 0; i < 2; i++) { + error->cursor[i].control = I915_READ(CURCNTR(i)); + error->cursor[i].position = I915_READ(CURPOS(i)); + error->cursor[i].base = I915_READ(CURBASE(i)); + + error->plane[i].control = I915_READ(DSPCNTR(i)); + error->plane[i].stride = I915_READ(DSPSTRIDE(i)); + error->plane[i].size = I915_READ(DSPSIZE(i)); + error->plane[i].pos= I915_READ(DSPPOS(i)); + error->plane[i].addr = I915_READ(DSPADDR(i)); + if (INTEL_INFO(dev)->gen >= 4) { + error->plane[i].surface = I915_READ(DSPSURF(i)); + error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i)); + } + + error->pipe[i].conf = I915_READ(PIPECONF(i)); + error->pipe[i].source = I915_READ(PIPESRC(i)); + error->pipe[i].htotal = I915_READ(HTOTAL(i)); + error->pipe[i].hblank = I915_READ(HBLANK(i)); + error->pipe[i].hsync = I915_READ(HSYNC(i)); + error->pipe[i].vtotal = I915_READ(VTOTAL(i)); + error->pipe[i].vblank = I915_READ(VBLANK(i)); + error->pipe[i].vsync = I915_READ(VSYNC(i)); + } + + return error; +} + +void +intel_display_print_error_state(struct seq_file *m, + struct drm_device *dev, + struct intel_display_error_state *error) +{ + int i; + + for (i = 0; i < 2; i++) { + seq_printf(m, "Pipe [%d]:\n", i); + seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); + seq_printf(m, " SRC: %08x\n", error->pipe[i].source); + seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); + seq_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); + seq_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); + seq_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); + seq_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); + seq_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); + + seq_printf(m, "Plane [%d]:\n", i); + seq_printf(m, " CNTR: %08x\n", error->plane[i].control); + seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); + seq_printf(m, " SIZE: %08x\n", error->plane[i].size); + seq_printf(m, " POS: %08x\n", error->plane[i].pos); + seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); + if (INTEL_INFO(dev)->gen >= 4) { + seq_printf(m, " SURF: %08x\n", error->plane[i].surface); + seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); + } + + seq_printf(m, "Cursor [%d]:\n", i); + seq_printf(m, " CNTR: %08x\n", error->cursor[i].control); + seq_printf(m, " POS: %08x\n", error->cursor[i].position); + seq_printf(m, " BASE: %08x\n", error->cursor[i].base); + } +} +#endif -- cgit v1.2.3 From df9c2042858e85ab46731c13e708a5b0799db848 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Nov 2010 09:31:12 +0800 Subject: drm/i915: Correct a comment about the use of the workqueue. It isn't used for the hangcheck, which does its work right from the timer trigger, but hangcheck can lead to error state recording, which is run off of the workqueue. Signed-off-by: Eric Anholt Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4cd04917868d..cf4e06a9417a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1962,7 +1962,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) * bo. * * It is also used for periodic low-priority events, such as - * idle-timers and hangcheck. + * idle-timers and recording error state. * * All tasks on the workqueue are expected to acquire the dev mutex * so there is no point in running more than one instance of the -- cgit v1.2.3 From 75a6898ffd20a13aba8d03f005eb4ab940134fcb Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Nov 2010 09:31:13 +0800 Subject: drm/i915: Also reinit the BSD and BLT rings after a GPU reset. Signed-off-by: Eric Anholt Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f0e6bd06fc0e..99b574050fde 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -472,9 +472,14 @@ int i915_reset(struct drm_device *dev, u8 flags) */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->mm.suspended) { - struct intel_ring_buffer *ring = &dev_priv->render_ring; dev_priv->mm.suspended = 0; - ring->init(ring); + + dev_priv->render_ring.init(&dev_priv->render_ring); + if (HAS_BSD(dev)) + dev_priv->bsd_ring.init(&dev_priv->bsd_ring); + if (HAS_BLT(dev)) + dev_priv->blt_ring.init(&dev_priv->blt_ring); + mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); drm_irq_install(dev); -- cgit v1.2.3 From cff458c21063de960bde0e39770a0f4cd0477d95 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Nov 2010 09:31:14 +0800 Subject: drm/i915: Add support for GPU reset on gen6. This has proven sufficient to recover from a hang of the GPU using the gem_bad_blit test while at the KMS console then starting X. When attempting the same during an X session, the timer doesn't appear to trigger. Signed-off-by: Eric Anholt Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 11 +++++++++++ drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 99b574050fde..8c5541950b8d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -405,6 +405,14 @@ static int ironlake_do_reset(struct drm_device *dev, u8 flags) return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); } +static int gen6_do_reset(struct drm_device *dev, u8 flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_GDRST, GEN6_GRDOM_FULL); + return wait_for((I915_READ(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); +} + /** * i965_reset - reset chip after a hang * @dev: drm device to reset @@ -439,6 +447,9 @@ int i915_reset(struct drm_device *dev, u8 flags) if (get_seconds() - dev_priv->last_gpu_reset < 5) { DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); } else switch (INTEL_INFO(dev)->gen) { + case 6: + ret = gen6_do_reset(dev, flags); + break; case 5: ret = ironlake_do_reset(dev, flags); break; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ec2a8b07ba5b..c668b2fb7e3d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -78,6 +78,12 @@ #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) +#define GEN6_GDRST 0x941c +#define GEN6_GRDOM_FULL (1 << 0) +#define GEN6_GRDOM_RENDER (1 << 1) +#define GEN6_GRDOM_MEDIA (1 << 2) +#define GEN6_GRDOM_BLT (1 << 3) + /* VGA stuff */ #define VGA_ST01_MDA 0x3ba -- cgit v1.2.3 From 5f75377db4d8d81ca4465b54d3c339c70c6a0fa2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Nov 2010 09:24:22 +0000 Subject: drm/i915: Fix restore of 965 fence regs since the register tracing change. We were reading our 64-bit value in I915_READ64 and returning 32 bits of it. The restoration of fence regs at resume then had a zero end value, and the fence had no effect. Version 2: Split register access functions into per-size versions Sharing code between different sizes seemed reasonable when we only needed a single copy, but as 64-bit access requires its own version, it makes sense to just split them out for each size. Reported-by: Peter Clifton Signed-off-by: Eric Anholt Signed-off-by: Keith Packard [ickle: use a macro to create the various read/write routines] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 68 ++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4c20ad92c0f3..db79df376b86 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1245,45 +1245,49 @@ extern void intel_display_print_error_state(struct seq_file *m, LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) -#define I915_READ(reg) i915_read(dev_priv, (reg), 4) -#define I915_WRITE(reg, val) i915_write(dev_priv, (reg), (val), 4) -#define I915_READ16(reg) i915_read(dev_priv, (reg), 2) -#define I915_WRITE16(reg, val) i915_write(dev_priv, (reg), (val), 2) -#define I915_READ8(reg) i915_read(dev_priv, (reg), 1) -#define I915_WRITE8(reg, val) i915_write(dev_priv, (reg), (val), 1) -#define I915_WRITE64(reg, val) i915_write(dev_priv, (reg), (val), 8) -#define I915_READ64(reg) i915_read(dev_priv, (reg), 8) +#define __i915_read(x, y) \ +static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ + u##x val = read##y(dev_priv->regs + reg); \ + trace_i915_reg_rw('R', reg, val, sizeof(val)); \ + return val; \ +} +__i915_read(8, b) +__i915_read(16, w) +__i915_read(32, l) +__i915_read(64, q) +#undef __i915_read + +#define __i915_write(x, y) \ +static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ + trace_i915_reg_rw('W', reg, val, sizeof(val)); \ + write##y(val, dev_priv->regs + reg); \ +} +__i915_write(8, b) +__i915_write(16, w) +__i915_write(32, l) +__i915_write(64, q) +#undef __i915_write + +#define I915_READ8(reg) i915_read8(dev_priv, (reg)) +#define I915_WRITE8(reg, val) i915_write8(dev_priv, (reg), (val)) + +#define I915_READ16(reg) i915_read16(dev_priv, (reg)) +#define I915_WRITE16(reg, val) i915_write16(dev_priv, (reg), (val)) +#define I915_READ16_NOTRACE(reg) readw(dev_priv->regs + (reg)) +#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg)) + +#define I915_READ(reg) i915_read32(dev_priv, (reg)) +#define I915_WRITE(reg, val) i915_write32(dev_priv, (reg), (val)) #define I915_READ_NOTRACE(reg) readl(dev_priv->regs + (reg)) #define I915_WRITE_NOTRACE(reg, val) writel(val, dev_priv->regs + (reg)) -#define I915_READ16_NOTRACE(reg) readw(dev_priv->regs + (reg)) -#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg)) + +#define I915_WRITE64(reg, val) i915_write64(dev_priv, (reg), (val)) +#define I915_READ64(reg) i915_read64(dev_priv, (reg)) #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) -static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg, int len) -{ - u64 val = 0; - - switch (len) { - case 8: - val = readq(dev_priv->regs + reg); - break; - case 4: - val = readl(dev_priv->regs + reg); - break; - case 2: - val = readw(dev_priv->regs + reg); - break; - case 1: - val = readb(dev_priv->regs + reg); - break; - } - trace_i915_reg_rw('R', reg, val, len); - - return val; -} /* On SNB platform, before reading ring registers forcewake bit * must be set to prevent GT core from power down and stale values being -- cgit v1.2.3 From 9535ab7323351bacf02d82af79921df1d6594969 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:18 -0500 Subject: drm/radeon/kms: setup mc chremap properly on r7xx/evergreen Should improve performance slightly and possibly fix some issues. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 38 +++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/evergreend.h | 4 ++++ drivers/gpu/drm/radeon/rv770.c | 45 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rv770d.h | 2 ++ 4 files changed, 89 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4dc5b4714c5a..728358e6b798 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1382,6 +1382,42 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, return backend_map; } +static void evergreen_program_channel_remap(struct radeon_device *rdev) +{ + u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp; + + tmp = RREG32(MC_SHARED_CHMAP); + switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { + case 0: + case 1: + case 2: + case 3: + default: + /* default mapping */ + mc_shared_chremap = 0x00fac688; + break; + } + + switch (rdev->family) { + case CHIP_HEMLOCK: + case CHIP_CYPRESS: + tcp_chan_steer_lo = 0x54763210; + tcp_chan_steer_hi = 0x0000ba98; + break; + case CHIP_JUNIPER: + case CHIP_REDWOOD: + case CHIP_CEDAR: + default: + tcp_chan_steer_lo = 0x76543210; + tcp_chan_steer_hi = 0x0000ba98; + break; + } + + WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo); + WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi); + WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); +} + static void evergreen_gpu_init(struct radeon_device *rdev) { u32 cc_rb_backend_disable = 0; @@ -1685,6 +1721,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); + evergreen_program_channel_remap(rdev); + num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1; grbm_gfx_index = INSTANCE_BROADCAST_WRITES; diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 113c70cc8b39..9644b1cbfb09 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -180,6 +180,7 @@ #define MC_SHARED_CHMAP 0x2004 #define NOOFCHAN_SHIFT 12 #define NOOFCHAN_MASK 0x00003000 +#define MC_SHARED_CHREMAP 0x2008 #define MC_ARB_RAMCFG 0x2760 #define NOOFBANK_SHIFT 0 @@ -348,6 +349,9 @@ #define SYNC_WALKER (1 << 25) #define SYNC_ALIGNER (1 << 26) +#define TCP_CHAN_STEER_LO 0x960c +#define TCP_CHAN_STEER_HI 0x9610 + #define VGT_CACHE_INVALIDATION 0x88C4 #define CACHE_INVALIDATION(x) ((x) << 0) #define VC_ONLY 0 diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4dfead8cee33..24ebd0879c4b 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -489,6 +489,49 @@ static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev, return backend_map; } +static void rv770_program_channel_remap(struct radeon_device *rdev) +{ + u32 tcp_chan_steer, mc_shared_chremap, tmp; + bool force_no_swizzle; + + switch (rdev->family) { + case CHIP_RV770: + case CHIP_RV730: + force_no_swizzle = false; + break; + case CHIP_RV710: + case CHIP_RV740: + default: + force_no_swizzle = true; + break; + } + + tmp = RREG32(MC_SHARED_CHMAP); + switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { + case 0: + case 1: + default: + /* default mapping */ + mc_shared_chremap = 0x00fac688; + break; + case 2: + case 3: + if (force_no_swizzle) + mc_shared_chremap = 0x00fac688; + else + mc_shared_chremap = 0x00bbc298; + break; + } + + if (rdev->family == CHIP_RV740) + tcp_chan_steer = 0x00ef2a60; + else + tcp_chan_steer = 0x00fac688; + + WREG32(TCP_CHAN_STEER, tcp_chan_steer); + WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); +} + static void rv770_gpu_init(struct radeon_device *rdev) { int i, j, num_qd_pipes; @@ -688,6 +731,8 @@ static void rv770_gpu_init(struct radeon_device *rdev) WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); + rv770_program_channel_remap(rdev); + WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index b7a5a20e81dc..7b1c8f8f4074 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -138,6 +138,7 @@ #define MC_SHARED_CHMAP 0x2004 #define NOOFCHAN_SHIFT 12 #define NOOFCHAN_MASK 0x00003000 +#define MC_SHARED_CHREMAP 0x2008 #define MC_ARB_RAMCFG 0x2760 #define NOOFBANK_SHIFT 0 @@ -303,6 +304,7 @@ #define BILINEAR_PRECISION_8_BIT (1 << 31) #define TCP_CNTL 0x9610 +#define TCP_CHAN_STEER 0x9614 #define VGT_CACHE_INVALIDATION 0x88C4 #define CACHE_INVALIDATION(x) ((x)<<0) -- cgit v1.2.3 From 5d68e501bf000b8b1696875455c7a556ce2e9c43 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:19 -0500 Subject: drm/radeon/kms: upstream ObjectID.h updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/ObjectID.h | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h index c714179d1bfa..c61c3fe9fb98 100644 --- a/drivers/gpu/drm/radeon/ObjectID.h +++ b/drivers/gpu/drm/radeon/ObjectID.h @@ -37,6 +37,8 @@ #define GRAPH_OBJECT_TYPE_CONNECTOR 0x3 #define GRAPH_OBJECT_TYPE_ROUTER 0x4 /* deleted */ +#define GRAPH_OBJECT_TYPE_DISPLAY_PATH 0x6 +#define GRAPH_OBJECT_TYPE_GENERIC 0x7 /****************************************************/ /* Encoder Object ID Definition */ @@ -64,6 +66,9 @@ #define ENCODER_OBJECT_ID_VT1623 0x10 #define ENCODER_OBJECT_ID_HDMI_SI1930 0x11 #define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12 +#define ENCODER_OBJECT_ID_ALMOND 0x22 +#define ENCODER_OBJECT_ID_TRAVIS 0x23 +#define ENCODER_OBJECT_ID_NUTMEG 0x22 /* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */ #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13 #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14 @@ -108,6 +113,7 @@ #define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13 #define CONNECTOR_OBJECT_ID_eDP 0x14 #define CONNECTOR_OBJECT_ID_MXM 0x15 +#define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16 /* deleted */ @@ -124,6 +130,7 @@ #define GENERIC_OBJECT_ID_GLSYNC 0x01 #define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02 #define GENERIC_OBJECT_ID_MXM_OPM 0x03 +#define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin /****************************************************/ /* Graphics Object ENUM ID Definition */ @@ -360,6 +367,26 @@ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT) +#define ENCODER_ALMOND_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT) + +#define ENCODER_ALMOND_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT) + +#define ENCODER_TRAVIS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT) + +#define ENCODER_TRAVIS_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT) + +#define ENCODER_NUTMEG_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_NUTMEG << OBJECT_ID_SHIFT) + /****************************************************/ /* Connector Object ID definition - Shared with BIOS */ /****************************************************/ @@ -421,6 +448,14 @@ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + #define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) @@ -512,6 +547,7 @@ #define CONNECTOR_7PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) + #define CONNECTOR_7PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) @@ -593,6 +629,14 @@ GRAPH_OBJECT_ENUM_ID7 << ENUM_ID_SHIFT |\ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DAC +#define CONNECTOR_LVDS_eDP_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT) + +#define CONNECTOR_LVDS_eDP_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT) + /****************************************************/ /* Router Object ID definition - Shared with BIOS */ /****************************************************/ @@ -621,6 +665,10 @@ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ GENERIC_OBJECT_ID_MXM_OPM << OBJECT_ID_SHIFT) +#define GENERICOBJECT_STEREO_PIN_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT) + /****************************************************/ /* Object Cap definition - Shared with BIOS */ /****************************************************/ -- cgit v1.2.3 From 1422ef52efa2b9abcf8e9d4d641f3a12579f1027 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:20 -0500 Subject: drm/radeon/kms: upstream atombios.h updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios.h | 853 +++++++++++++++++++++++++++++++++++--- 1 file changed, 792 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index fe359a239df3..6a9baa2443f8 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -73,8 +73,18 @@ #define ATOM_PPLL1 0 #define ATOM_PPLL2 1 #define ATOM_DCPLL 2 +#define ATOM_PPLL0 2 +#define ATOM_EXT_PLL1 8 +#define ATOM_EXT_PLL2 9 +#define ATOM_EXT_CLOCK 10 #define ATOM_PPLL_INVALID 0xFF +#define ENCODER_REFCLK_SRC_P1PLL 0 +#define ENCODER_REFCLK_SRC_P2PLL 1 +#define ENCODER_REFCLK_SRC_DCPLL 2 +#define ENCODER_REFCLK_SRC_EXTCLK 3 +#define ENCODER_REFCLK_SRC_INVALID 0xFF + #define ATOM_SCALER1 0 #define ATOM_SCALER2 1 @@ -192,6 +202,9 @@ typedef struct _ATOM_COMMON_TABLE_HEADER /*Image can't be updated, while Driver needs to carry the new table! */ }ATOM_COMMON_TABLE_HEADER; +/****************************************************************************/ +// Structure stores the ROM header. +/****************************************************************************/ typedef struct _ATOM_ROM_HEADER { ATOM_COMMON_TABLE_HEADER sHeader; @@ -221,6 +234,9 @@ typedef struct _ATOM_ROM_HEADER #define USHORT void* #endif +/****************************************************************************/ +// Structures used in Command.mtb +/****************************************************************************/ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1 USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON @@ -312,6 +328,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ #define SetUniphyInstance ASIC_StaticPwrMgtStatusChange #define HPDInterruptService ReadHWAssistedI2CStatus #define EnableVGA_Access GetSCLKOverMCLKRatio +#define GetDispObjectInfo EnableYUV typedef struct _ATOM_MASTER_COMMAND_TABLE { @@ -357,6 +374,24 @@ typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER /****************************************************************************/ #define COMPUTE_MEMORY_PLL_PARAM 1 #define COMPUTE_ENGINE_PLL_PARAM 2 +#define ADJUST_MC_SETTING_PARAM 3 + +/****************************************************************************/ +// Structures used by AdjustMemoryControllerTable +/****************************************************************************/ +typedef struct _ATOM_ADJUST_MEMORY_CLOCK_FREQ +{ +#if ATOM_BIG_ENDIAN + ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block + ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0] + ULONG ulClockFreq:24; +#else + ULONG ulClockFreq:24; + ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0] + ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block +#endif +}ATOM_ADJUST_MEMORY_CLOCK_FREQ; +#define POINTER_RETURN_FLAG 0x80 typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS { @@ -440,6 +475,26 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 #endif }COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4; +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 +{ + union + { + ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter + ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter + }; + UCHAR ucRefDiv; //Output Parameter + UCHAR ucPostDiv; //Output Parameter + union + { + UCHAR ucCntlFlag; //Output Flags + UCHAR ucInputFlag; //Input Flags. ucInputFlag[0] - Strobe(1)/Performance(0) mode + }; + UCHAR ucReserved; +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5; + +// ucInputFlag +#define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN 1 // 1-StrobeMode, 0-PerformanceMode + typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER { ATOM_COMPUTE_CLOCK_FREQ ulClock; @@ -583,6 +638,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS #define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 #define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00 #define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_5_40GHZ 0x02 #define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04 #define ATOM_ENCODER_CONFIG_LINKA 0x00 #define ATOM_ENCODER_CONFIG_LINKB 0x04 @@ -608,6 +664,9 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS #define ATOM_ENCODER_MODE_TV 13 #define ATOM_ENCODER_MODE_CV 14 #define ATOM_ENCODER_MODE_CRT 15 +#define ATOM_ENCODER_MODE_DVO 16 +#define ATOM_ENCODER_MODE_DP_SST ATOM_ENCODER_MODE_DP // For DP1.2 +#define ATOM_ENCODER_MODE_DP_MST 5 // For DP1.2 typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 { @@ -661,6 +720,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_START 0x08 #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1 0x09 #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2 0x0a +#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3 0x13 #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE 0x0b #define ATOM_ENCODER_CMD_DP_VIDEO_OFF 0x0c #define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d @@ -671,24 +731,34 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 #define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10 #define ATOM_ENCODER_STATUS_LINK_TRAINING_INCOMPLETE 0x00 +//ucTableFormatRevision=1 +//ucTableContentRevision=3 // Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver typedef struct _ATOM_DIG_ENCODER_CONFIG_V3 { #if ATOM_BIG_ENDIAN UCHAR ucReserved1:1; - UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) UCHAR ucReserved:3; UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz #else UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz UCHAR ucReserved:3; - UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) UCHAR ucReserved1:1; #endif }ATOM_DIG_ENCODER_CONFIG_V3; +#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03 +#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01 #define ATOM_ENCODER_CONFIG_V3_ENCODER_SEL 0x70 - +#define ATOM_ENCODER_CONFIG_V3_DIG0_ENCODER 0x00 +#define ATOM_ENCODER_CONFIG_V3_DIG1_ENCODER 0x10 +#define ATOM_ENCODER_CONFIG_V3_DIG2_ENCODER 0x20 +#define ATOM_ENCODER_CONFIG_V3_DIG3_ENCODER 0x30 +#define ATOM_ENCODER_CONFIG_V3_DIG4_ENCODER 0x40 +#define ATOM_ENCODER_CONFIG_V3_DIG5_ENCODER 0x50 typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3 { @@ -707,6 +777,56 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3 UCHAR ucReserved; }DIG_ENCODER_CONTROL_PARAMETERS_V3; +//ucTableFormatRevision=1 +//ucTableContentRevision=4 +// start from NI +// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver +typedef struct _ATOM_DIG_ENCODER_CONFIG_V4 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucReserved1:1; + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) + UCHAR ucReserved:2; + UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version +#else + UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version + UCHAR ucReserved:2; + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) + UCHAR ucReserved1:1; +#endif +}ATOM_DIG_ENCODER_CONFIG_V4; + +#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_MASK 0x03 +#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ 0x02 +#define ATOM_ENCODER_CONFIG_V4_ENCODER_SEL 0x70 +#define ATOM_ENCODER_CONFIG_V4_DIG0_ENCODER 0x00 +#define ATOM_ENCODER_CONFIG_V4_DIG1_ENCODER 0x10 +#define ATOM_ENCODER_CONFIG_V4_DIG2_ENCODER 0x20 +#define ATOM_ENCODER_CONFIG_V4_DIG3_ENCODER 0x30 +#define ATOM_ENCODER_CONFIG_V4_DIG4_ENCODER 0x40 +#define ATOM_ENCODER_CONFIG_V4_DIG5_ENCODER 0x50 + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + union{ + ATOM_DIG_ENCODER_CONFIG_V4 acConfig; + UCHAR ucConfig; + }; + UCHAR ucAction; + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + // =5: DP audio + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP + UCHAR ucHPD_ID; // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version +}DIG_ENCODER_CONTROL_PARAMETERS_V4; // define ucBitPerColor: #define PANEL_BPC_UNDEFINE 0x00 @@ -893,6 +1013,7 @@ typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V3 #endif }ATOM_DIG_TRANSMITTER_CONFIG_V3; + typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 { union @@ -936,6 +1057,149 @@ typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 #define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER2 0x40 //CD #define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER3 0x80 //EF + +/****************************************************************************/ +// Structures used by UNIPHYTransmitterControlTable V1.4 +// ASIC Families: NI +// ucTableFormatRevision=1 +// ucTableContentRevision=4 +/****************************************************************************/ +typedef struct _ATOM_DP_VS_MODE_V4 +{ + UCHAR ucLaneSel; + union + { + UCHAR ucLaneSet; + struct { +#if ATOM_BIG_ENDIAN + UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4 + UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level + UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level +#else + UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level + UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level + UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4 +#endif + }; + }; +}ATOM_DP_VS_MODE_V4; + +typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V4 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) + UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector +#else + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F + UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) +#endif +}ATOM_DIG_TRANSMITTER_CONFIG_V4; + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE_V4 asMode; // DP Voltage swing mode Redefined comparing to previous version + }; + union + { + ATOM_DIG_TRANSMITTER_CONFIG_V4 acConfig; + UCHAR ucConfig; + }; + UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX + UCHAR ucLaneNum; + UCHAR ucReserved[3]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS_V4; + +//ucConfig +//Bit0 +#define ATOM_TRANSMITTER_CONFIG_V4_DUAL_LINK_CONNECTOR 0x01 +//Bit1 +#define ATOM_TRANSMITTER_CONFIG_V4_COHERENT 0x02 +//Bit2 +#define ATOM_TRANSMITTER_CONFIG_V4_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_V4_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_V4_LINKB 0x04 +// Bit3 +#define ATOM_TRANSMITTER_CONFIG_V4_ENCODER_SEL_MASK 0x08 +#define ATOM_TRANSMITTER_CONFIG_V4_DIG1_ENCODER 0x00 +#define ATOM_TRANSMITTER_CONFIG_V4_DIG2_ENCODER 0x08 +// Bit5:4 +#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SEL_MASK 0x30 +#define ATOM_TRANSMITTER_CONFIG_V4_P1PLL 0x00 +#define ATOM_TRANSMITTER_CONFIG_V4_P2PLL 0x10 +#define ATOM_TRANSMITTER_CONFIG_V4_DCPLL 0x20 // New in _V4 +#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SRC_EXT 0x30 // Changed comparing to V3 +// Bit7:6 +#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER_SEL_MASK 0xC0 +#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER1 0x00 //AB +#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER2 0x40 //CD +#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER3 0x80 //EF + + +/****************************************************************************/ +// Structures used by ExternalEncoderControlTable V1.3 +// ASIC Families: Evergreen, Llano, NI +// ucTableFormatRevision=1 +// ucTableContentRevision=3 +/****************************************************************************/ + +typedef struct _EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 +{ + union{ + USHORT usPixelClock; // pixel clock in 10Khz, valid when ucAction=SETUP/ENABLE_OUTPUT + USHORT usConnectorId; // connector id, valid when ucAction = INIT + }; + UCHAR ucConfig; // indicate which encoder, and DP link rate when ucAction = SETUP/ENABLE_OUTPUT + UCHAR ucAction; // + UCHAR ucEncoderMode; // encoder mode, only used when ucAction = SETUP/ENABLE_OUTPUT + UCHAR ucLaneNum; // lane number, only used when ucAction = SETUP/ENABLE_OUTPUT + UCHAR ucBitPerColor; // output bit per color, only valid when ucAction = SETUP/ENABLE_OUTPUT and ucEncodeMode= DP + UCHAR ucReserved; +}EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3; + +// ucAction +#define EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT 0x00 +#define EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT 0x01 +#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT 0x07 +#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP 0x0f +#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF 0x10 +#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING 0x11 +#define EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION 0x12 + +// ucConfig +#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03 +#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00 +#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01 +#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ 0x02 +#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER_SEL_MASK 0x70 +#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER1 0x00 +#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER2 0x10 +#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER3 0x20 + +typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 +{ + EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 sExtEncoder; + ULONG ulReserved[2]; +}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3; + + /****************************************************************************/ // Structures used by DAC1OuputControlTable // DAC2OuputControlTable @@ -1142,6 +1406,7 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V2 #define PIXEL_CLOCK_V4_MISC_SS_ENABLE 0x10 #define PIXEL_CLOCK_V4_MISC_COHERENT_MODE 0x20 + typedef struct _PIXEL_CLOCK_PARAMETERS_V3 { USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) @@ -1202,6 +1467,55 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V5 #define PIXEL_CLOCK_V5_MISC_HDMI_32BPP 0x08 #define PIXEL_CLOCK_V5_MISC_REF_DIV_SRC 0x10 +typedef struct _CRTC_PIXEL_CLOCK_FREQ +{ +#if ATOM_BIG_ENDIAN + ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to + // drive the pixel clock. not used for DCPLL case. + ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing. + // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version. +#else + ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing. + // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version. + ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to + // drive the pixel clock. not used for DCPLL case. +#endif +}CRTC_PIXEL_CLOCK_FREQ; + +typedef struct _PIXEL_CLOCK_PARAMETERS_V6 +{ + union{ + CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; // pixel clock and CRTC id frequency + ULONG ulDispEngClkFreq; // dispclk frequency + }; + USHORT usFbDiv; // feedback divider integer part. + UCHAR ucPostDiv; // post divider. + UCHAR ucRefDiv; // Reference divider + UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL + UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h, + // indicate which graphic encoder will be used. + UCHAR ucEncoderMode; // Encoder mode: + UCHAR ucMiscInfo; // bit[0]= Force program PPLL + // bit[1]= when VGA timing is used. + // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp + // bit[4]= RefClock source for PPLL. + // =0: XTLAIN( default mode ) + // =1: other external clock source, which is pre-defined + // by VBIOS depend on the feature required. + // bit[7:5]: reserved. + ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 ) + +}PIXEL_CLOCK_PARAMETERS_V6; + +#define PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL 0x01 +#define PIXEL_CLOCK_V6_MISC_VGA_MODE 0x02 +#define PIXEL_CLOCK_V6_MISC_HDMI_BPP_MASK 0x0c +#define PIXEL_CLOCK_V6_MISC_HDMI_24BPP 0x00 +#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP 0x04 +#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP 0x08 +#define PIXEL_CLOCK_V6_MISC_HDMI_48BPP 0x0c +#define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC 0x10 + typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2 { PIXEL_CLOCK_PARAMETERS_V3 sDispClkInput; @@ -1241,10 +1555,11 @@ typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS typedef struct _ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3 { USHORT usPixelClock; // target pixel clock - UCHAR ucTransmitterID; // transmitter id defined in objectid.h + UCHAR ucTransmitterID; // GPU transmitter id defined in objectid.h UCHAR ucEncodeMode; // encoder mode: CRT, LVDS, DP, TMDS or HDMI UCHAR ucDispPllConfig; // display pll configure parameter defined as following DISPPLL_CONFIG_XXXX - UCHAR ucReserved[3]; + UCHAR ucExtTransmitterID; // external encoder id. + UCHAR ucReserved[2]; }ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3; // usDispPllConfig v1.2 for RoadRunner @@ -1358,6 +1673,7 @@ typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS /**************************************************************************/ #define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + /****************************************************************************/ // Structures used by PowerConnectorDetectionTable /****************************************************************************/ @@ -1438,6 +1754,31 @@ typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 #define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK 0x0F00 #define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT 8 +// Used by DCE5.0 + typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 +{ + USHORT usSpreadSpectrumAmountFrac; // SS_AMOUNT_DSFRAC New in DCE5.0 + UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread. + // Bit[1]: 1-Ext. 0-Int. + // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL + // Bits[7:4] reserved + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8] + USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC +}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3; + +#define ATOM_PPLL_SS_TYPE_V3_DOWN_SPREAD 0x00 +#define ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD 0x01 +#define ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD 0x02 +#define ATOM_PPLL_SS_TYPE_V3_PPLL_SEL_MASK 0x0c +#define ATOM_PPLL_SS_TYPE_V3_P1PLL 0x00 +#define ATOM_PPLL_SS_TYPE_V3_P2PLL 0x04 +#define ATOM_PPLL_SS_TYPE_V3_DCPLL 0x08 +#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK 0x00FF +#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT 0 +#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK 0x0F00 +#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT 8 + #define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL /**************************************************************************/ @@ -1706,7 +2047,7 @@ typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES USHORT StandardVESA_Timing; // Only used by Bios USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4 USHORT DAC_Info; // Will be obsolete from R600 - USHORT LVDS_Info; // Shared by various SW components,latest version 1.1 + USHORT LCD_Info; // Shared by various SW components,latest version 1.3, was called LVDS_Info USHORT TMDS_Info; // Will be obsolete from R600 USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1 USHORT SupportedDevicesInfo; // Will be obsolete from R600 @@ -1736,12 +2077,16 @@ typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1 }ATOM_MASTER_LIST_OF_DATA_TABLES; +// For backward compatible +#define LVDS_Info LCD_Info + typedef struct _ATOM_MASTER_DATA_TABLE { ATOM_COMMON_TABLE_HEADER sHeader; ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; }ATOM_MASTER_DATA_TABLE; + /****************************************************************************/ // Structure used in MultimediaCapabilityInfoTable /****************************************************************************/ @@ -1776,6 +2121,7 @@ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) }ATOM_MULTIMEDIA_CONFIG_INFO; + /****************************************************************************/ // Structures used in FirmwareInfoTable /****************************************************************************/ @@ -2031,8 +2377,47 @@ typedef struct _ATOM_FIRMWARE_INFO_V2_1 UCHAR ucReserved4[3]; }ATOM_FIRMWARE_INFO_V2_1; +//the structure below to be used from NI +//ucTableFormatRevision=2 +//ucTableContentRevision=2 +typedef struct _ATOM_FIRMWARE_INFO_V2_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulReserved[2]; + ULONG ulReserved1; //Was ulMaxEngineClockPLL_Output; //In 10Khz unit* + ULONG ulReserved2; //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit* + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock ? + ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit. This is the frequency before DCDTO, corresponding to usBootUpVDDCVoltage. + UCHAR ucReserved3; //Was ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + USHORT usBootUpVDDCVoltage; //In MV unit + USHORT usLcdMinPixelClockPLL_Output; // In MHz unit + USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit + ULONG ulReserved4; //Was ulAsicMaximumVoltage + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + ULONG ulReserved5; //Was usMinEngineClockPLL_Input and usMaxEngineClockPLL_Input + ULONG ulReserved6; //Was usMinEngineClockPLL_Output and usMinMemoryClockPLL_Input + ULONG ulReserved7; //Was usMaxMemoryClockPLL_Input and usMinMemoryClockPLL_Output + USHORT usReserved11; //Was usMaxPixelClock; //In 10Khz unit, Max. Pclk used only for DAC + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usBootUpVDDCIVoltage; //In unit of mv; Was usMinPixelClockPLL_Output; + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usCoreReferenceClock; //In 10Khz unit + USHORT usMemoryReferenceClock; //In 10Khz unit + USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock + UCHAR ucMemoryModule_ID; //Indicate what is the board design + UCHAR ucReserved9[3]; + USHORT usBootUpMVDDCVoltage; //In unit of mv; Was usMinPixelClockPLL_Output; + USHORT usReserved12; + ULONG ulReserved10[3]; // New added comparing to previous version +}ATOM_FIRMWARE_INFO_V2_2; -#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_1 +#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_2 /****************************************************************************/ // Structures used in IntegratedSystemInfoTable @@ -2212,7 +2597,7 @@ ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pi ucDockingPinBit: which bit in this register to read the pin status; ucDockingPinPolarity:Polarity of the pin when docked; -ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 +ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, [7:0]=4:Pharaoh, other bits reserved for now and must be 0x0 usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. @@ -2250,6 +2635,14 @@ usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to rep usMinDownStreamHTLinkWidth: same as above. */ +// ATOM_INTEGRATED_SYSTEM_INFO::ulCPUCapInfo - CPU type definition +#define INTEGRATED_SYSTEM_INFO__UNKNOWN_CPU 0 +#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GRIFFIN 1 +#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GREYHOUND 2 +#define INTEGRATED_SYSTEM_INFO__AMD_CPU__K8 3 +#define INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH 4 + +#define INTEGRATED_SYSTEM_INFO__AMD_CPU__MAX_CODE INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH // this deff reflects max defined CPU code #define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 #define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 @@ -2778,8 +3171,88 @@ typedef struct _ATOM_LVDS_INFO_V12 #define PANEL_RANDOM_DITHER 0x80 #define PANEL_RANDOM_DITHER_MASK 0x80 +#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 // no need to change this + +/****************************************************************************/ +// Structures used by LCD_InfoTable V1.3 Note: previous version was called ATOM_LVDS_INFO_V12 +// ASIC Families: NI +// ucTableFormatRevision=1 +// ucTableContentRevision=3 +/****************************************************************************/ +typedef struct _ATOM_LCD_INFO_V13 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usExtInfoTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + ULONG ulReserved0; + UCHAR ucLCD_Misc; // Reorganized in V13 + // Bit0: {=0:single, =1:dual}, + // Bit1: {=0:LDI format for RGB888, =1 FPDI format for RGB888} // was {=0:666RGB, =1:888RGB}, + // Bit3:2: {Grey level} + // Bit6:4 Color Bit Depth definition (see below definition in EDID V1.4 @BYTE 14h) + // Bit7 Reserved. was for ATOM_PANEL_MISC_API_ENABLED, still need it? + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; + USHORT usLCDVenderID; + USHORT usLCDProductID; + UCHAR ucLCDPanel_SpecialHandlingCap; // Reorganized in V13 + // Bit0: Once DAL sees this CAP is set, it will read EDID from LCD on its own + // Bit1: See LCDPANEL_CAP_DRR_SUPPORTED + // Bit2: a quick reference whether an embadded panel (LCD1 ) is LVDS (0) or eDP (1) + // Bit7-3: Reserved + UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable + USHORT usBacklightPWM; // Backlight PWM in Hz. New in _V13 + + UCHAR ucPowerSequenceDIGONtoDE_in4Ms; + UCHAR ucPowerSequenceDEtoVARY_BL_in4Ms; + UCHAR ucPowerSequenceDEtoDIGON_in4Ms; + UCHAR ucPowerSequenceVARY_BLtoDE_in4Ms; + + UCHAR ucOffDelay_in4Ms; + UCHAR ucPowerSequenceVARY_BLtoBLON_in4Ms; + UCHAR ucPowerSequenceBLONtoVARY_BL_in4Ms; + UCHAR ucReserved1; + + ULONG ulReserved[4]; +}ATOM_LCD_INFO_V13; + +#define ATOM_LCD_INFO_LAST ATOM_LCD_INFO_V13 + +//Definitions for ucLCD_Misc +#define ATOM_PANEL_MISC_V13_DUAL 0x00000001 +#define ATOM_PANEL_MISC_V13_FPDI 0x00000002 +#define ATOM_PANEL_MISC_V13_GREY_LEVEL 0x0000000C +#define ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT 2 +#define ATOM_PANEL_MISC_V13_COLOR_BIT_DEPTH_MASK 0x70 +#define ATOM_PANEL_MISC_V13_6BIT_PER_COLOR 0x10 +#define ATOM_PANEL_MISC_V13_8BIT_PER_COLOR 0x20 + +//Color Bit Depth definition in EDID V1.4 @BYTE 14h +//Bit 6 5 4 + // 0 0 0 - Color bit depth is undefined + // 0 0 1 - 6 Bits per Primary Color + // 0 1 0 - 8 Bits per Primary Color + // 0 1 1 - 10 Bits per Primary Color + // 1 0 0 - 12 Bits per Primary Color + // 1 0 1 - 14 Bits per Primary Color + // 1 1 0 - 16 Bits per Primary Color + // 1 1 1 - Reserved + +//Definitions for ucLCDPanel_SpecialHandlingCap: + +//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. +//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL +#define LCDPANEL_CAP_V13_READ_EDID 0x1 // = LCDPANEL_CAP_READ_EDID no change comparing to previous version -#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 +//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together +//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static +//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12 +#define LCDPANEL_CAP_V13_DRR_SUPPORTED 0x2 // = LCDPANEL_CAP_DRR_SUPPORTED no change comparing to previous version + +//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP. +#define LCDPANEL_CAP_V13_eDP 0x4 // = LCDPANEL_CAP_eDP no change comparing to previous version typedef struct _ATOM_PATCH_RECORD_MODE { @@ -2944,9 +3417,9 @@ typedef struct _ATOM_DPCD_INFO #define MAX_DTD_MODE_IN_VRAM 6 #define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT) #define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) -#define DFP_ENCODER_TYPE_OFFSET 0x80 -#define DP_ENCODER_LANE_NUM_OFFSET 0x84 -#define DP_ENCODER_LINK_RATE_OFFSET 0x88 +//20 bytes for Encoder Type and DPCD in STD EDID area +#define DFP_ENCODER_TYPE_OFFSET (ATOM_EDID_RAW_DATASIZE + ATOM_DTD_MODE_SUPPORT_TBL_SIZE + ATOM_STD_MODE_SUPPORT_TBL_SIZE - 20) +#define ATOM_DP_DPCD_OFFSET (DFP_ENCODER_TYPE_OFFSET + 4 ) #define ATOM_HWICON1_SURFACE_ADDR 0 #define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) @@ -2997,14 +3470,16 @@ typedef struct _ATOM_DPCD_INFO #define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) #define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) -#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) -#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256) -#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512 +#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR + 1024) +#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START + 512 //The size below is in Kb! #define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC) +#define ATOM_VRAM_RESERVE_V2_SIZE 32 + #define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L #define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 #define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 @@ -3206,6 +3681,15 @@ typedef struct _ATOM_DISPLAY_OBJECT_PATH USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. }ATOM_DISPLAY_OBJECT_PATH; +typedef struct _ATOM_DISPLAY_EXTERNAL_OBJECT_PATH +{ + USHORT usDeviceTag; //supported device + USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH + USHORT usConnObjectId; //Connector Object ID + USHORT usGPUObjectId; //GPU ID + USHORT usGraphicObjIds[2]; //usGraphicObjIds[0]= GPU internal encoder, usGraphicObjIds[1]= external encoder +}ATOM_DISPLAY_EXTERNAL_OBJECT_PATH; + typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE { UCHAR ucNumOfDispPath; @@ -3261,6 +3745,47 @@ typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset #define EXT_AUXDDC_LUTINDEX_7 7 #define MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES (EXT_AUXDDC_LUTINDEX_7+1) +//ucChannelMapping are defined as following +//for DP connector, eDP, DP to VGA/LVDS +//Bit[1:0]: Define which pin connect to DP connector DP_Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +//Bit[3:2]: Define which pin connect to DP connector DP_Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +//Bit[5:4]: Define which pin connect to DP connector DP_Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +//Bit[7:6]: Define which pin connect to DP connector DP_Lane3, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +typedef struct _ATOM_DP_CONN_CHANNEL_MAPPING +{ +#if ATOM_BIG_ENDIAN + UCHAR ucDP_Lane3_Source:2; + UCHAR ucDP_Lane2_Source:2; + UCHAR ucDP_Lane1_Source:2; + UCHAR ucDP_Lane0_Source:2; +#else + UCHAR ucDP_Lane0_Source:2; + UCHAR ucDP_Lane1_Source:2; + UCHAR ucDP_Lane2_Source:2; + UCHAR ucDP_Lane3_Source:2; +#endif +}ATOM_DP_CONN_CHANNEL_MAPPING; + +//for DVI/HDMI, in dual link case, both links have to have same mapping. +//Bit[1:0]: Define which pin connect to DVI connector data Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +//Bit[3:2]: Define which pin connect to DVI connector data Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +//Bit[5:4]: Define which pin connect to DVI connector data Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +//Bit[7:6]: Define which pin connect to DVI connector clock lane, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 +typedef struct _ATOM_DVI_CONN_CHANNEL_MAPPING +{ +#if ATOM_BIG_ENDIAN + UCHAR ucDVI_CLK_Source:2; + UCHAR ucDVI_DATA0_Source:2; + UCHAR ucDVI_DATA1_Source:2; + UCHAR ucDVI_DATA2_Source:2; +#else + UCHAR ucDVI_DATA2_Source:2; + UCHAR ucDVI_DATA1_Source:2; + UCHAR ucDVI_DATA0_Source:2; + UCHAR ucDVI_CLK_Source:2; +#endif +}ATOM_DVI_CONN_CHANNEL_MAPPING; + typedef struct _EXT_DISPLAY_PATH { USHORT usDeviceTag; //A bit vector to show what devices are supported @@ -3269,7 +3794,13 @@ typedef struct _EXT_DISPLAY_PATH UCHAR ucExtAUXDDCLutIndex; //An index into external AUX/DDC channel LUT UCHAR ucExtHPDPINLutIndex; //An index into external HPD pin LUT USHORT usExtEncoderObjId; //external encoder object id - USHORT usReserved[3]; + union{ + UCHAR ucChannelMapping; // if ucChannelMapping=0, using default one to one mapping + ATOM_DP_CONN_CHANNEL_MAPPING asDPMapping; + ATOM_DVI_CONN_CHANNEL_MAPPING asDVIMapping; + }; + UCHAR ucReserved; + USHORT usReserved[2]; }EXT_DISPLAY_PATH; #define NUMBER_OF_UCHAR_FOR_GUID 16 @@ -3281,7 +3812,8 @@ typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO UCHAR ucGuid [NUMBER_OF_UCHAR_FOR_GUID]; // a GUID is a 16 byte long string EXT_DISPLAY_PATH sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries. UCHAR ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0. - UCHAR Reserved [7]; // for potential expansion + UCHAR uc3DStereoPinId; // use for eDP panel + UCHAR Reserved [6]; // for potential expansion }ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO; //Related definitions, all records are differnt but they have a commond header @@ -3311,10 +3843,11 @@ typedef struct _ATOM_COMMON_RECORD_HEADER #define ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE 17 //This is for the case when connectors are not known to object table #define ATOM_OBJECT_LINK_RECORD_TYPE 18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record #define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE 19 +#define ATOM_ENCODER_CAP_RECORD_TYPE 20 //Must be updated when new record type is added,equal to that record definition! -#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE +#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_ENCODER_CAP_RECORD_TYPE typedef struct _ATOM_I2C_RECORD { @@ -3441,6 +3974,26 @@ typedef struct _ATOM_ENCODER_DVO_CF_RECORD UCHAR ucPadding[2]; }ATOM_ENCODER_DVO_CF_RECORD; +// Bit maps for ATOM_ENCODER_CAP_RECORD.ucEncoderCap +#define ATOM_ENCODER_CAP_RECORD_HBR2 0x01 // DP1.2 HBR2 is supported by this path + +typedef struct _ATOM_ENCODER_CAP_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + union { + USHORT usEncoderCap; + struct { +#if ATOM_BIG_ENDIAN + USHORT usReserved:15; // Bit1-15 may be defined for other capability in future + USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability. +#else + USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability. + USHORT usReserved:15; // Bit1-15 may be defined for other capability in future +#endif + }; + }; +}ATOM_ENCODER_CAP_RECORD; + // value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle #define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1 #define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2 @@ -3580,6 +4133,11 @@ typedef struct _ATOM_VOLTAGE_CONTROL #define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI #define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage #define VOLTAGE_CONTROL_ID_DS4402 0x04 +#define VOLTAGE_CONTROL_ID_UP6266 0x05 +#define VOLTAGE_CONTROL_ID_SCORPIO 0x06 +#define VOLTAGE_CONTROL_ID_VT1556M 0x07 +#define VOLTAGE_CONTROL_ID_CHL822x 0x08 +#define VOLTAGE_CONTROL_ID_VT1586M 0x09 typedef struct _ATOM_VOLTAGE_OBJECT { @@ -3670,66 +4228,157 @@ typedef struct _ATOM_POWER_SOURCE_INFO #define POWER_SENSOR_GPIO 0x01 #define POWER_SENSOR_I2C 0x02 +typedef struct _ATOM_CLK_VOLT_CAPABILITY +{ + ULONG ulVoltageIndex; // The Voltage Index indicated by FUSE, same voltage index shared with SCLK DPM fuse table + ULONG ulMaximumSupportedCLK; // Maximum clock supported with specified voltage index, unit in 10kHz +}ATOM_CLK_VOLT_CAPABILITY; + +typedef struct _ATOM_AVAILABLE_SCLK_LIST +{ + ULONG ulSupportedSCLK; // Maximum clock supported with specified voltage index, unit in 10kHz + USHORT usVoltageIndex; // The Voltage Index indicated by FUSE for specified SCLK + USHORT usVoltageID; // The Voltage ID indicated by FUSE for specified SCLK +}ATOM_AVAILABLE_SCLK_LIST; + +// ATOM_INTEGRATED_SYSTEM_INFO_V6 ulSystemConfig cap definition +#define ATOM_IGP_INFO_V6_SYSTEM_CONFIG__PCIE_POWER_GATING_ENABLE 1 // refer to ulSystemConfig bit[0] + +// this IntegrateSystemInfoTable is used for Liano/Ontario APU typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 { ATOM_COMMON_TABLE_HEADER sHeader; ULONG ulBootUpEngineClock; ULONG ulDentistVCOFreq; ULONG ulBootUpUMAClock; - ULONG ulReserved1[8]; + ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4]; ULONG ulBootUpReqDisplayVector; ULONG ulOtherDisplayMisc; ULONG ulGPUCapInfo; - ULONG ulReserved2[3]; + ULONG ulSB_MMIO_Base_Addr; + USHORT usRequestedPWMFreqInHz; + UCHAR ucHtcTmpLmt; + UCHAR ucHtcHystLmt; + ULONG ulMinEngineClock; ULONG ulSystemConfig; ULONG ulCPUCapInfo; - USHORT usMaxNBVoltage; - USHORT usMinNBVoltage; - USHORT usBootUpNBVoltage; - USHORT usExtDispConnInfoOffset; - UCHAR ucHtcTmpLmt; - UCHAR ucTjOffset; + USHORT usNBP0Voltage; + USHORT usNBP1Voltage; + USHORT usBootUpNBVoltage; + USHORT usExtDispConnInfoOffset; + USHORT usPanelRefreshRateRange; UCHAR ucMemoryType; UCHAR ucUMAChannelNumber; ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10]; ULONG ulCSR_M3_ARB_CNTL_UVD[10]; ULONG ulCSR_M3_ARB_CNTL_FS3D[10]; - ULONG ulReserved3[42]; + ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5]; + ULONG ulGMCRestoreResetTime; + ULONG ulMinimumNClk; + ULONG ulIdleNClk; + ULONG ulDDR_DLL_PowerUpTime; + ULONG ulDDR_PLL_PowerUpTime; + USHORT usPCIEClkSSPercentage; + USHORT usPCIEClkSSType; + USHORT usLvdsSSPercentage; + USHORT usLvdsSSpreadRateIn10Hz; + USHORT usHDMISSPercentage; + USHORT usHDMISSpreadRateIn10Hz; + USHORT usDVISSPercentage; + USHORT usDVISSpreadRateIn10Hz; + ULONG ulReserved3[21]; ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo; }ATOM_INTEGRATED_SYSTEM_INFO_V6; +// ulGPUCapInfo +#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01 +#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__DISABLE_AUX_HW_MODE_DETECTION 0x08 + +// ulOtherDisplayMisc +#define INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT 0x01 + + /********************************************************************************************************************** -// ATOM_INTEGRATED_SYSTEM_INFO_V6 Description -//ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. -//ulDentistVCOFreq: Dentist VCO clock in 10kHz unit. -//ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit. -//ulReserved1[8] Reserved by now, must be 0x0. -//ulBootUpReqDisplayVector VBIOS boot up display IDs -// ATOM_DEVICE_CRT1_SUPPORT 0x0001 -// ATOM_DEVICE_CRT2_SUPPORT 0x0010 -// ATOM_DEVICE_DFP1_SUPPORT 0x0008 -// ATOM_DEVICE_DFP6_SUPPORT 0x0040 -// ATOM_DEVICE_DFP2_SUPPORT 0x0080 -// ATOM_DEVICE_DFP3_SUPPORT 0x0200 -// ATOM_DEVICE_DFP4_SUPPORT 0x0400 -// ATOM_DEVICE_DFP5_SUPPORT 0x0800 -// ATOM_DEVICE_LCD1_SUPPORT 0x0002 -//ulOtherDisplayMisc Other display related flags, not defined yet. -//ulGPUCapInfo TBD -//ulReserved2[3] must be 0x0 for the reserved. -//ulSystemConfig TBD -//ulCPUCapInfo TBD -//usMaxNBVoltage High NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse. -//usMinNBVoltage Low NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse. -//usBootUpNBVoltage Boot up NB voltage in unit of mv. -//ucHtcTmpLmt Bit [22:16] of D24F3x64 Thermal Control (HTC) Register. -//ucTjOffset Bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed. -//ucMemoryType [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved. -//ucUMAChannelNumber System memory channel numbers. -//usExtDispConnectionInfoOffset ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO offset relative to beginning of this table. -//ulCSR_M3_ARB_CNTL_DEFAULT[10] Arrays with values for CSR M3 arbiter for default -//ulCSR_M3_ARB_CNTL_UVD[10] Arrays with values for CSR M3 arbiter for UVD playback. -//ulCSR_M3_ARB_CNTL_FS3D[10] Arrays with values for CSR M3 arbiter for Full Screen 3D applications. + ATOM_INTEGRATED_SYSTEM_INFO_V6 Description +ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock +ulDentistVCOFreq: Dentist VCO clock in 10kHz unit. +ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit. +sDISPCLK_Voltage: Report Display clock voltage requirement. + +ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Liano/Ontaio projects: + ATOM_DEVICE_CRT1_SUPPORT 0x0001 + ATOM_DEVICE_CRT2_SUPPORT 0x0010 + ATOM_DEVICE_DFP1_SUPPORT 0x0008 + ATOM_DEVICE_DFP6_SUPPORT 0x0040 + ATOM_DEVICE_DFP2_SUPPORT 0x0080 + ATOM_DEVICE_DFP3_SUPPORT 0x0200 + ATOM_DEVICE_DFP4_SUPPORT 0x0400 + ATOM_DEVICE_DFP5_SUPPORT 0x0800 + ATOM_DEVICE_LCD1_SUPPORT 0x0002 +ulOtherDisplayMisc: Other display related flags, not defined yet. +ulGPUCapInfo: bit[0]=0: TMDS/HDMI Coherent Mode use cascade PLL mode. + =1: TMDS/HDMI Coherent Mode use signel PLL mode. + bit[3]=0: Enable HW AUX mode detection logic + =1: Disable HW AUX mode dettion logic +ulSB_MMIO_Base_Addr: Physical Base address to SB MMIO space. Driver needs to initialize it for SMU usage. + +usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW). + Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0; + + When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below: + 1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use; + VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result, + Changing BL using VBIOS function is functional in both driver and non-driver present environment; + and enabling VariBri under the driver environment from PP table is optional. + + 2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating + that BL control from GPU is expected. + VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1 + Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but + it's per platform + and enabling VariBri under the driver environment from PP table is optional. + +ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt. + Threshold on value to enter HTC_active state. +ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt. + To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt. +ulMinEngineClock: Minimum SCLK allowed in 10kHz unit. This is calculated based on WRCK Fuse settings. +ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled + =1: PCIE Power Gating Enabled + Bit[1]=0: DDR-DLL shut-down feature disabled. + 1: DDR-DLL shut-down feature enabled. + Bit[2]=0: DDR-PLL Power down feature disabled. + 1: DDR-PLL Power down feature enabled. +ulCPUCapInfo: TBD +usNBP0Voltage: VID for voltage on NB P0 State +usNBP1Voltage: VID for voltage on NB P1 State +usBootUpNBVoltage: Voltage Index of GNB voltage configured by SBIOS, which is suffcient to support VBIOS DISPCLK requirement. +usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure +usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set + to indicate a range. + SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 + SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 + SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 + SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 +ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved. +ucUMAChannelNumber: System memory channel numbers. +ulCSR_M3_ARB_CNTL_DEFAULT[10]: Arrays with values for CSR M3 arbiter for default +ulCSR_M3_ARB_CNTL_UVD[10]: Arrays with values for CSR M3 arbiter for UVD playback. +ulCSR_M3_ARB_CNTL_FS3D[10]: Arrays with values for CSR M3 arbiter for Full Screen 3D applications. +sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high +ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. +ulMinimumNClk: Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz. +ulIdleNClk: NCLK speed while memory runs in self-refresh state. Unit in 10kHz. +ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns. +ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns. +usPCIEClkSSPercentage: PCIE Clock Spred Spectrum Percentage in unit 0.01%; 100 mean 1%. +usPCIEClkSSType: PCIE Clock Spred Spectrum Type. 0 for Down spread(default); 1 for Center spread. +usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. +usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. +usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. +usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. +usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. +usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. **********************************************************************************************************************/ /**************************************************************************/ @@ -3790,6 +4439,7 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT #define ASIC_INTERNAL_SS_ON_LVDS 6 #define ASIC_INTERNAL_SS_ON_DP 7 #define ASIC_INTERNAL_SS_ON_DCPLL 8 +#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9 typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2 { @@ -3903,6 +4553,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1 #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2 #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LIT2AC 4 //Byte aligned defintion for BIOS usage #define ATOM_S0_CRT1_MONOb0 0x01 @@ -4529,7 +5180,8 @@ typedef struct _ATOM_INIT_REG_BLOCK{ #define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1) #define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1) #define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1) - +//#define ACCESS_MCIODEBUGIND 0x40 //defined in BIOS code +#define ACCESS_PLACEHOLDER 0x80 typedef struct _ATOM_MC_INIT_PARAM_TABLE { @@ -4554,6 +5206,10 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE #define _32Mx32 0x33 #define _64Mx8 0x41 #define _64Mx16 0x42 +#define _64Mx32 0x43 +#define _128Mx8 0x51 +#define _128Mx16 0x52 +#define _256Mx8 0x61 #define SAMSUNG 0x1 #define INFINEON 0x2 @@ -4569,10 +5225,11 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE #define QIMONDA INFINEON #define PROMOS MOSEL #define KRETON INFINEON +#define ELIXIR NANYA /////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// -#define UCODE_ROM_START_ADDRESS 0x1c000 +#define UCODE_ROM_START_ADDRESS 0x1b800 #define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode //uCode block header for reference @@ -4903,7 +5560,34 @@ typedef struct _ATOM_VRAM_MODULE_V6 ATOM_MEMORY_TIMING_FORMAT_V2 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock }ATOM_VRAM_MODULE_V6; - +typedef struct _ATOM_VRAM_MODULE_V7 +{ +// Design Specific Values + ULONG ulChannelMapCfg; // mmMC_SHARED_CHREMAP + USHORT usModuleSize; // Size of ATOM_VRAM_MODULE_V7 + USHORT usPrivateReserved; // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // Current memory module ID + UCHAR ucMemoryType; // MEM_TYPE_DDR2/DDR3/GDDR3/GDDR5 + UCHAR ucChannelNum; // Number of mem. channels supported in this module + UCHAR ucChannelWidth; // CHANNEL_16BIT/CHANNEL_32BIT/CHANNEL_64BIT + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucReserve; // Former container for Mx_FLAGS like DBI_AC_MODE_ENABLE_ASIC for GDDR4. Not used now. + UCHAR ucMisc; // RANK_OF_THISMEMORY etc. + UCHAR ucVREFI; // Not used. + UCHAR ucNPL_RT; // Round trip delay (MC_SEQ_CAS_TIMING [28:24]:TCL=CL+NPL_RT-2). Always 2. + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; +// Memory Module specific values + USHORT usEMRS2Value; // EMRS2/MR2 Value. + USHORT usEMRS3Value; // EMRS3/MR3 Value. + UCHAR ucMemoryVenderID; // [7:4] Revision, [3:0] Vendor code + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucFIFODepth; // FIFO depth can be detected during vendor detection, here is hardcoded per memory + UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth + char strMemPNString[20]; // part number end with '0'. +}ATOM_VRAM_MODULE_V7; typedef struct _ATOM_VRAM_INFO_V2 { @@ -4942,6 +5626,20 @@ typedef struct _ATOM_VRAM_INFO_V4 // ATOM_INIT_REG_BLOCK aMemAdjust; }ATOM_VRAM_INFO_V4; +typedef struct _ATOM_VRAM_INFO_HEADER_V2_1 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usReserved[4]; + UCHAR ucNumOfVRAMModule; // indicate number of VRAM module + UCHAR ucMemoryClkPatchTblVer; // version of memory AC timing register list + UCHAR ucVramModuleVer; // indicate ATOM_VRAM_MODUE version + UCHAR ucReserved; + ATOM_VRAM_MODULE_V7 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; +}ATOM_VRAM_INFO_HEADER_V2_1; + + typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO { ATOM_COMMON_TABLE_HEADER sHeader; @@ -5182,6 +5880,16 @@ typedef struct _ASIC_TRANSMITTER_INFO UCHAR ucReserved; }ASIC_TRANSMITTER_INFO; +#define ASIC_TRANSMITTER_INFO_CONFIG__DVO_SDR_MODE 0x01 +#define ASIC_TRANSMITTER_INFO_CONFIG__COHERENT_MODE 0x02 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODEROBJ_ID_MASK 0xc4 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_A 0x00 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_B 0x04 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_C 0x40 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_D 0x44 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_E 0x80 +#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_F 0x84 + typedef struct _ASIC_ENCODER_INFO { UCHAR ucEncoderID; @@ -5284,6 +5992,28 @@ typedef struct _DP_ENCODER_SERVICE_PARAMETERS /* /obselete */ #define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +typedef struct _DP_ENCODER_SERVICE_PARAMETERS_V2 +{ + USHORT usExtEncoderObjId; // External Encoder Object Id, output parameter only, use when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION + UCHAR ucAuxId; + UCHAR ucAction; + UCHAR ucSinkType; // Iput and Output parameters. + UCHAR ucHPDId; // Input parameter, used when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION + UCHAR ucReserved[2]; +}DP_ENCODER_SERVICE_PARAMETERS_V2; + +typedef struct _DP_ENCODER_SERVICE_PS_ALLOCATION_V2 +{ + DP_ENCODER_SERVICE_PARAMETERS_V2 asDPServiceParam; + PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 asAuxParam; +}DP_ENCODER_SERVICE_PS_ALLOCATION_V2; + +// ucAction +#define DP_SERVICE_V2_ACTION_GET_SINK_TYPE 0x01 +#define DP_SERVICE_V2_ACTION_DET_LCD_CONNECTION 0x02 + + // DP_TRAINING_TABLE #define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR #define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 ) @@ -5339,6 +6069,7 @@ typedef struct _SET_HWBLOCK_INSTANCE_PARAMETER_V2 #define SELECT_DCIO_IMPCAL 4 #define SELECT_DCIO_DIG 6 #define SELECT_CRTC_PIXEL_RATE 7 +#define SELECT_VGA_BLK 8 /****************************************************************************/ //Portion VI: Definitinos for vbios MC scratch registers that driver used -- cgit v1.2.3 From 603a9da37b83c2b4cc4495ecab7916f45cf5837e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:21 -0500 Subject: drm/radeon/kms: upstream power table updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios.h | 144 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 6a9baa2443f8..58a0cd02c0a2 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -6475,7 +6475,17 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER #define ATOM_PP_THERMALCONTROLLER_ADT7473 9 #define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11 #define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12 +#define ATOM_PP_THERMALCONTROLLER_EMC2103 13 /* 0x0D */ // Only fan control will be implemented, do NOT show this in PPGen. +#define ATOM_PP_THERMALCONTROLLER_SUMO 14 /* 0x0E */ // Sumo type, used internally +#define ATOM_PP_THERMALCONTROLLER_NISLANDS 15 + +// Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal. +// We probably should reserve the bit 0x80 for this use. +// To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here). +// The driver can pick the correct internal controller based on the ASIC. + #define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller +#define ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D // EMC2103 Fan Control + Internal Thermal Controller typedef struct _ATOM_PPLIB_STATE { @@ -6572,6 +6582,29 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 USHORT usExtendendedHeaderOffset; } ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3; +typedef struct _ATOM_PPLIB_POWERPLAYTABLE4 +{ + ATOM_PPLIB_POWERPLAYTABLE3 basicTable3; + ULONG ulGoldenPPID; // PPGen use only + ULONG ulGoldenRevision; // PPGen use only + USHORT usVddcDependencyOnSCLKOffset; + USHORT usVddciDependencyOnMCLKOffset; + USHORT usVddcDependencyOnMCLKOffset; + USHORT usMaxClockVoltageOnDCOffset; + USHORT usReserved[2]; +} ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4; + +typedef struct _ATOM_PPLIB_POWERPLAYTABLE5 +{ + ATOM_PPLIB_POWERPLAYTABLE4 basicTable4; + ULONG ulTDPLimit; + ULONG ulNearTDPLimit; + ULONG ulSQRampingThreshold; + USHORT usCACLeakageTableOffset; // Points to ATOM_PPLIB_CAC_Leakage_Table + ULONG ulCACLeakage; // TBD, this parameter is still under discussion. Change to ulReserved if not needed. + ULONG ulReserved; +} ATOM_PPLIB_POWERPLAYTABLE5, *LPATOM_PPLIB_POWERPLAYTABLE5; + //// ATOM_PPLIB_NONCLOCK_INFO::usClassification #define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 #define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 @@ -6595,6 +6628,10 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 #define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000 #define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000 +//// ATOM_PPLIB_NONCLOCK_INFO::usClassification2 +#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001 +#define ATOM_PPLIB_CLASSIFICATION2_ULV 0x0002 + //// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings #define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001 #define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002 @@ -6627,9 +6664,21 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 #define ATOM_PPLIB_M3ARB_MASK 0x00060000 #define ATOM_PPLIB_M3ARB_SHIFT 17 +#define ATOM_PPLIB_ENABLE_DRR 0x00080000 + +// remaining 16 bits are reserved +typedef struct _ATOM_PPLIB_THERMAL_STATE +{ + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucThermalAction; +}ATOM_PPLIB_THERMAL_STATE, *LPATOM_PPLIB_THERMAL_STATE; + // Contained in an array starting at the offset // in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset. // referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex +#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 +#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 typedef struct _ATOM_PPLIB_NONCLOCK_INFO { USHORT usClassification; @@ -6637,15 +6686,15 @@ typedef struct _ATOM_PPLIB_NONCLOCK_INFO UCHAR ucMaxTemperature; ULONG ulCapsAndSettings; UCHAR ucRequiredPower; - UCHAR ucUnused1[3]; + USHORT usClassification2; + ULONG ulVCLK; + ULONG ulDCLK; + UCHAR ucUnused[5]; } ATOM_PPLIB_NONCLOCK_INFO; // Contained in an array starting at the offset // in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset. // referenced from ATOM_PPLIB_STATE::ucClockStateIndices -#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 -#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 - typedef struct _ATOM_PPLIB_R600_CLOCK_INFO { USHORT usEngineClockLow; @@ -6716,6 +6765,93 @@ typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO #define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1 #define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2 +typedef struct _ATOM_PPLIB_SUMO_CLOCK_INFO{ + USHORT usEngineClockLow; //clockfrequency & 0xFFFF. The unit is in 10khz + UCHAR ucEngineClockHigh; //clockfrequency >> 16. + UCHAR vddcIndex; //2-bit vddc index; + UCHAR leakage; //please use 8-bit absolute value, not the 6-bit % value + //please initalize to 0 + UCHAR rsv; + //please initalize to 0 + USHORT rsv1; + //please initialize to 0s + ULONG rsv2[2]; +}ATOM_PPLIB_SUMO_CLOCK_INFO; + + + +typedef struct _ATOM_PPLIB_STATE_V2 +{ + //number of valid dpm levels in this state; Driver uses it to calculate the whole + //size of the state: sizeof(ATOM_PPLIB_STATE_V2) + (ucNumDPMLevels - 1) * sizeof(UCHAR) + UCHAR ucNumDPMLevels; + + //a index to the array of nonClockInfos + UCHAR nonClockInfoIndex; + /** + * Driver will read the first ucNumDPMLevels in this array + */ + UCHAR clockInfoIndex[1]; +} ATOM_PPLIB_STATE_V2; + +typedef struct StateArray{ + //how many states we have + UCHAR ucNumEntries; + + ATOM_PPLIB_STATE_V2 states[1]; +}StateArray; + + +typedef struct ClockInfoArray{ + //how many clock levels we have + UCHAR ucNumEntries; + + //sizeof(ATOM_PPLIB_SUMO_CLOCK_INFO) + UCHAR ucEntrySize; + + //this is for Sumo + ATOM_PPLIB_SUMO_CLOCK_INFO clockInfo[1]; +}ClockInfoArray; + +typedef struct NonClockInfoArray{ + + //how many non-clock levels we have. normally should be same as number of states + UCHAR ucNumEntries; + //sizeof(ATOM_PPLIB_NONCLOCK_INFO) + UCHAR ucEntrySize; + + ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1]; +}NonClockInfoArray; + +typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record +{ + USHORT usClockLow; + UCHAR ucClockHigh; + USHORT usVoltage; +}ATOM_PPLIB_Clock_Voltage_Dependency_Record; + +typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Table +{ + UCHAR ucNumEntries; // Number of entries. + ATOM_PPLIB_Clock_Voltage_Dependency_Record entries[1]; // Dynamically allocate entries. +}ATOM_PPLIB_Clock_Voltage_Dependency_Table; + +typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Record +{ + USHORT usSclkLow; + UCHAR ucSclkHigh; + USHORT usMclkLow; + UCHAR ucMclkHigh; + USHORT usVddc; + USHORT usVddci; +}ATOM_PPLIB_Clock_Voltage_Limit_Record; + +typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table +{ + UCHAR ucNumEntries; // Number of entries. + ATOM_PPLIB_Clock_Voltage_Limit_Record entries[1]; // Dynamically allocate entries. +}ATOM_PPLIB_Clock_Voltage_Limit_Table; + /**************************************************************************/ -- cgit v1.2.3 From 2f062fda4f83932b87b3b6c903eeade43422245a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:22 -0500 Subject: drm/radeon/kms: add new family id for AMD Ontario APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_family.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3a7095743d44..cfaf71323491 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1269,6 +1269,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) +#define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM)) /* * BIOS helpers. diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h index e329066dcabd..4c222d5437d1 100644 --- a/drivers/gpu/drm/radeon/radeon_family.h +++ b/drivers/gpu/drm/radeon/radeon_family.h @@ -80,6 +80,7 @@ enum radeon_family { CHIP_JUNIPER, CHIP_CYPRESS, CHIP_HEMLOCK, + CHIP_PALM, CHIP_LAST, }; -- cgit v1.2.3 From 4e8c65a1f9ee1a976d95c1d5d2027761aba2f1c3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:23 -0500 Subject: drm/radeon/kms: atom changes for DCE4.1 devices Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 4 +++- drivers/gpu/drm/radeon/radeon_encoders.c | 25 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 64fb89ecbf74..bf7ec0441e63 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -849,7 +849,9 @@ int radeon_asic_init(struct radeon_device *rdev) if (rdev->flags & RADEON_SINGLE_CRTC) rdev->num_crtc = 1; else { - if (ASIC_IS_DCE4(rdev)) + if (ASIC_IS_DCE41(rdev)) + rdev->num_crtc = 2; + else if (ASIC_IS_DCE4(rdev)) rdev->num_crtc = 6; else rdev->num_crtc = 2; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 041943df966b..806d552299bf 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -713,7 +713,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) * DIG1/2 can drive UNIPHY0/1/2 link A or link B * * DCE 4.0 - * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B). + * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). * Supports up to 6 digital outputs * - 6 DIG encoder blocks. * - DIG to PHY mapping is hardcoded @@ -724,6 +724,12 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) * DIG5 drives UNIPHY2 link A, A+B * DIG6 drives UNIPHY2 link B * + * DCE 4.1 + * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). + * Supports up to 6 digital outputs + * - 2 DIG encoder blocks. + * DIG1/2 can drive UNIPHY0/1/2 link A or link B + * * Routing * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) * Examples: @@ -904,9 +910,15 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else args.v3.ucLaneNum = 4; - if (dig->linkb) { - args.v3.acConfig.ucLinkSel = 1; - args.v3.acConfig.ucEncoderSel = 1; + if (ASIC_IS_DCE41(rdev)) { + args.v3.acConfig.ucEncoderSel = dig->dig_encoder; + if (dig->linkb) + args.v3.acConfig.ucLinkSel = 1; + } else { + if (dig->linkb) { + args.v3.acConfig.ucLinkSel = 1; + args.v3.acConfig.ucEncoderSel = 1; + } } /* Select the PLL for the PHY @@ -1483,6 +1495,11 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) struct radeon_encoder_atom_dig *dig; uint32_t dig_enc_in_use = 0; + /* on DCE41 and encoder can driver any phy so just crtc id */ + if (ASIC_IS_DCE41(rdev)) { + return radeon_crtc->crtc_id; + } + if (ASIC_IS_DCE4(rdev)) { dig = radeon_encoder->enc_priv; switch (radeon_encoder->encoder_id) { -- cgit v1.2.3 From bf982ebf22d5d84dd4a2a8d8f1a11f75920020a7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:24 -0500 Subject: drm/radeon/kms: Add support for external encoders on fusion APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 4 ++- drivers/gpu/drm/radeon/radeon_encoders.c | 54 ++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1df4dc6c063c..2697801e36e7 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -225,7 +225,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index) radeon_legacy_init_crtc(dev, radeon_crtc); } -static const char *encoder_names[34] = { +static const char *encoder_names[36] = { "NONE", "INTERNAL_LVDS", "INTERNAL_TMDS1", @@ -260,6 +260,8 @@ static const char *encoder_names[34] = { "INTERNAL_KLDSCP_LVTMA", "INTERNAL_UNIPHY1", "INTERNAL_UNIPHY2", + "NUTMEG", + "TRAVIS", }; static const char *connector_names[15] = { diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 806d552299bf..e4e64a80b58d 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1056,6 +1056,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action) union external_encoder_control { EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; }; static void @@ -1066,6 +1067,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); union external_encoder_control args; struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); @@ -1073,6 +1075,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, int dp_clock = 0; int dp_lane_count = 0; int connector_object_id = 0; + u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -1111,6 +1114,37 @@ atombios_external_encoder_setup(struct drm_encoder *encoder, else args.v1.sDigEncoder.ucLaneNum = 4; break; + case 3: + args.v3.sExtEncoder.ucAction = action; + if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) + args.v3.sExtEncoder.usConnectorId = connector_object_id; + else + args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (args.v3.sExtEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { + if (dp_clock == 270000) + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; + else if (dp_clock == 540000) + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; + args.v3.sExtEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v3.sExtEncoder.ucLaneNum = 8; + else + args.v3.sExtEncoder.ucLaneNum = 4; + switch (ext_enum) { + case GRAPH_OBJECT_ENUM_ID1: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; + break; + case GRAPH_OBJECT_ENUM_ID2: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; + break; + case GRAPH_OBJECT_ENUM_ID3: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; + break; + } + args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; default: DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); return; @@ -1301,12 +1335,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) switch (mode) { case DRM_MODE_DPMS_ON: default: - action = ATOM_ENABLE; + if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) + action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT; + else + action = ATOM_ENABLE; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - action = ATOM_DISABLE; + if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) + action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT; + else + action = ATOM_DISABLE; break; } atombios_external_encoder_setup(encoder, ext_encoder, action); @@ -1627,7 +1667,13 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } if (ext_encoder) { - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); } atombios_apply_encoder_quirks(encoder, adjusted_mode); @@ -2046,6 +2092,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t case ENCODER_OBJECT_ID_TITFP513: case ENCODER_OBJECT_ID_VT1623: case ENCODER_OBJECT_ID_HDMI_SI1930: + case ENCODER_OBJECT_ID_TRAVIS: + case ENCODER_OBJECT_ID_NUTMEG: /* these are handled by the primary encoders */ radeon_encoder->is_ext_encoder = true; if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) -- cgit v1.2.3 From 4339c442c0736db42329b68602308e95bcc75a30 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:25 -0500 Subject: drm/radeon/kms: add support for ss overrides on Fusion APUs System specific spread spectrum overrides can be specified in the integrated system info table for Fusion APUs. This adds support for using those overrides. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 87ead090c7d5..4d37b2d1ba74 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1321,6 +1321,43 @@ bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, return false; } +static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev, + struct radeon_atom_ss *ss, + int id) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); + u16 data_offset, size; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *igp_info; + u8 frev, crev; + u16 percentage = 0, rate = 0; + + /* get any igp specific overrides */ + if (atom_parse_data_header(mode_info->atom_context, index, &size, + &frev, &crev, &data_offset)) { + igp_info = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *) + (mode_info->atom_context->bios + data_offset); + switch (id) { + case ASIC_INTERNAL_SS_ON_TMDS: + percentage = le16_to_cpu(igp_info->usDVISSPercentage); + rate = le16_to_cpu(igp_info->usDVISSpreadRateIn10Hz); + break; + case ASIC_INTERNAL_SS_ON_HDMI: + percentage = le16_to_cpu(igp_info->usHDMISSPercentage); + rate = le16_to_cpu(igp_info->usHDMISSpreadRateIn10Hz); + break; + case ASIC_INTERNAL_SS_ON_LVDS: + percentage = le16_to_cpu(igp_info->usLvdsSSPercentage); + rate = le16_to_cpu(igp_info->usLvdsSSpreadRateIn10Hz); + break; + } + if (percentage) + ss->percentage = percentage; + if (rate) + ss->rate = rate; + } +} + union asic_ss_info { struct _ATOM_ASIC_INTERNAL_SS_INFO info; struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2; @@ -1385,6 +1422,8 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage); ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz); + if (rdev->flags & RADEON_IS_IGP) + radeon_atombios_get_igp_ss_overrides(rdev, ss, id); return true; } } -- cgit v1.2.3 From 0ef0c1f7349e782f6c79cb7e4bf8a4c3ce3371c6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:26 -0500 Subject: drm/radeon/kms: move r7xx/evergreen to its own vram_gtt setup function MC_VM_FB_LOCATION is at a different offset between r6xx and r7xx/evergreen. The location is needed for vram setup on fusion chips. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/rv770.c | 44 +++++++++++++++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 728358e6b798..e9b262fdaa2c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1945,7 +1945,7 @@ int evergreen_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; rdev->mc.visible_vram_size = rdev->mc.aper_size; rdev->mc.active_vram_size = rdev->mc.visible_vram_size; - r600_vram_gtt_location(rdev, &rdev->mc); + r700_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); return 0; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index a3552594ccc4..93b1c687328b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1161,7 +1161,7 @@ static void r600_mc_program(struct radeon_device *rdev) * Note: GTT start, end, size should be initialized before calling this * function on AGP platform. */ -void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) +static void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) { u64 size_bf, size_af; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index cfaf71323491..bf3a4fc82964 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1433,7 +1433,6 @@ extern void rs690_line_buffer_adjust(struct radeon_device *rdev, struct drm_display_mode *mode2); /* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */ -extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); extern int r600_cp_start(struct radeon_device *rdev); @@ -1479,6 +1478,7 @@ extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mo extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder); +extern void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern void r700_cp_stop(struct radeon_device *rdev); extern void r700_cp_fini(struct radeon_device *rdev); extern void evergreen_disable_interrupt_state(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 24ebd0879c4b..c23349a46fd2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1001,6 +1001,48 @@ static void rv770_vram_scratch_fini(struct radeon_device *rdev) radeon_bo_unref(&rdev->vram_scratch.robj); } +void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) +{ + u64 size_bf, size_af; + + if (mc->mc_vram_size > 0xE0000000) { + /* leave room for at least 512M GTT */ + dev_warn(rdev->dev, "limiting VRAM\n"); + mc->real_vram_size = 0xE0000000; + mc->mc_vram_size = 0xE0000000; + } + if (rdev->flags & RADEON_IS_AGP) { + size_bf = mc->gtt_start; + size_af = 0xFFFFFFFF - mc->gtt_end + 1; + if (size_bf > size_af) { + if (mc->mc_vram_size > size_bf) { + dev_warn(rdev->dev, "limiting VRAM\n"); + mc->real_vram_size = size_bf; + mc->mc_vram_size = size_bf; + } + mc->vram_start = mc->gtt_start - mc->mc_vram_size; + } else { + if (mc->mc_vram_size > size_af) { + dev_warn(rdev->dev, "limiting VRAM\n"); + mc->real_vram_size = size_af; + mc->mc_vram_size = size_af; + } + mc->vram_start = mc->gtt_end; + } + mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; + dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n", + mc->mc_vram_size >> 20, mc->vram_start, + mc->vram_end, mc->real_vram_size >> 20); + } else { + u64 base = 0; + if (rdev->flags & RADEON_IS_IGP) + base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; + radeon_vram_location(rdev, &rdev->mc, base); + rdev->mc.gtt_base_align = 0; + radeon_gtt_location(rdev, mc); + } +} + int rv770_mc_init(struct radeon_device *rdev) { u32 tmp; @@ -1041,7 +1083,7 @@ int rv770_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.visible_vram_size = rdev->mc.aper_size; rdev->mc.active_vram_size = rdev->mc.visible_vram_size; - r600_vram_gtt_location(rdev, &rdev->mc); + r700_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); return 0; -- cgit v1.2.3 From 6eb18f8b6006b0e869a8484b1daaa63adce1b73e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:27 -0500 Subject: drm/radeon/kms: MC setup changes for fusion APUs - CONFIG_MEMSIZE is in bytes on fusion. - FB_BASE and FB_TOP are finer grained. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 12 +++++++++--- drivers/gpu/drm/radeon/rv770.c | 10 +++++++++- drivers/gpu/drm/radeon/rv770d.h | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e9b262fdaa2c..090f74700081 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1940,9 +1940,15 @@ int evergreen_mc_init(struct radeon_device *rdev) rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); /* Setup GPU memory space */ - /* size in MB on evergreen */ - rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; - rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; + if (rdev->flags & RADEON_IS_IGP) { + /* size in bytes on fusion */ + rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); + rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); + } else { + /* size in MB on evergreen */ + rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; + rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; + } rdev->mc.visible_vram_size = rdev->mc.aper_size; rdev->mc.active_vram_size = rdev->mc.visible_vram_size; r700_vram_gtt_location(rdev, &rdev->mc); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index c23349a46fd2..2b66af9066b2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -237,6 +237,12 @@ static void rv770_mc_program(struct radeon_device *rdev) rdev->mc.vram_end >> 12); } WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + if (rdev->flags & RADEON_IS_IGP) { + tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF; + tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24; + tmp |= ((rdev->mc.vram_start >> 20) & 0xF) << 20; + WREG32(MC_FUS_VM_FB_OFFSET, tmp); + } tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); @@ -1035,8 +1041,10 @@ void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->vram_end, mc->real_vram_size >> 20); } else { u64 base = 0; - if (rdev->flags & RADEON_IS_IGP) + if (rdev->flags & RADEON_IS_IGP) { base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; + base |= RREG32(MC_FUS_VM_FB_OFFSET) & 0x00F00000; + } radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 7b1c8f8f4074..e09a403f1c64 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -158,6 +158,7 @@ #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 #define MC_VM_FB_LOCATION 0x2024 +#define MC_FUS_VM_FB_OFFSET 0x2898 #define MC_VM_MB_L1_TLB0_CNTL 0x2234 #define MC_VM_MB_L1_TLB1_CNTL 0x2238 #define MC_VM_MB_L1_TLB2_CNTL 0x223C -- cgit v1.2.3 From 180074010c6a8d1948638b4a136d2bd8111f4459 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:28 -0500 Subject: drm/radeon/kms: evergreen.c updates for fusion fusion chips only have 2 crtcs. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 188 +++++++++++++++++++-------------- drivers/gpu/drm/radeon/radeon_device.c | 7 +- 2 files changed, 113 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 090f74700081..07c4c6f216f0 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -888,31 +888,39 @@ static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_sa save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); - save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); - save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); - save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); - save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (!(rdev->flags & RADEON_IS_IGP)) { + save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); + save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); + save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); + save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); + } /* Stop all video */ WREG32(VGA_RENDER_CONTROL, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); + } WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + } WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + } WREG32(D1VGA_CONTROL, 0); WREG32(D2VGA_CONTROL, 0); @@ -942,41 +950,43 @@ static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, - upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, + upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, + (u32)rdev->mc.vram_start); + } WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); @@ -992,22 +1002,28 @@ static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_ WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); + } WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]); WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); + WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); + } WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + } WREG32(VGA_RENDER_CONTROL, save->vga_render_control); } @@ -2068,17 +2084,21 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev) WREG32(GRBM_INT_CNTL, 0); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + } WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); + } WREG32(DACA_AUTODETECT_INT_CONTROL, 0); WREG32(DACB_AUTODETECT_INT_CONTROL, 0); @@ -2187,10 +2207,12 @@ int evergreen_irq_set(struct radeon_device *rdev) WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); - WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); - WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); - WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); - WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); + if (!(rdev->flags & RADEON_IS_IGP)) { + WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); + WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); + WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); + WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); + } WREG32(DC_HPD1_INT_CONTROL, hpd1); WREG32(DC_HPD2_INT_CONTROL, hpd2); @@ -2710,12 +2732,16 @@ static bool evergreen_card_posted(struct radeon_device *rdev) u32 reg; /* first check CRTCs */ - reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (rdev->flags & RADEON_IS_IGP) + reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); + else + reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); if (reg & EVERGREEN_CRTC_MASTER_EN) return true; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index d8ac1849180d..dd93c9c94144 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -335,7 +335,12 @@ bool radeon_card_posted(struct radeon_device *rdev) uint32_t reg; /* first check CRTCs */ - if (ASIC_IS_DCE4(rdev)) { + if (ASIC_IS_DCE41(rdev)) { + reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); + if (reg & EVERGREEN_CRTC_MASTER_EN) + return true; + } else if (ASIC_IS_DCE4(rdev)) { reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | -- cgit v1.2.3 From 958261d1e8755d1423beb0951ed0b9552c96f638 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:30 -0500 Subject: drm/radeon/kms: add radeon_asic struct for AMD Ontario fusion APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index bf7ec0441e63..4e487cc16e7f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -751,6 +751,49 @@ static struct radeon_asic evergreen_asic = { .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; +static struct radeon_asic sumo_asic = { + .init = &evergreen_init, + .fini = &evergreen_fini, + .suspend = &evergreen_suspend, + .resume = &evergreen_resume, + .cp_commit = &r600_cp_commit, + .gpu_is_lockup = &evergreen_gpu_is_lockup, + .asic_reset = &evergreen_asic_reset, + .vga_set_state = &r600_vga_set_state, + .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .irq_set = &evergreen_irq_set, + .irq_process = &evergreen_irq_process, + .get_vblank_counter = &evergreen_get_vblank_counter, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &evergreen_cs_parse, + .copy_blit = NULL, + .copy_dma = NULL, + .copy = NULL, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = NULL, + .set_memory_clock = NULL, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = NULL, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &evergreen_bandwidth_update, + .hpd_init = &evergreen_hpd_init, + .hpd_fini = &evergreen_hpd_fini, + .hpd_sense = &evergreen_hpd_sense, + .hpd_set_polarity = &evergreen_hpd_set_polarity, + .gui_idle = &r600_gui_idle, + .pm_misc = &evergreen_pm_misc, + .pm_prepare = &evergreen_pm_prepare, + .pm_finish = &evergreen_pm_finish, + .pm_init_profile = &rs780_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, +}; + int radeon_asic_init(struct radeon_device *rdev) { radeon_register_accessor_init(rdev); @@ -835,6 +878,9 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_HEMLOCK: rdev->asic = &evergreen_asic; break; + case CHIP_PALM: + rdev->asic = &sumo_asic; + break; default: /* FIXME: not supported yet */ return -EINVAL; -- cgit v1.2.3 From d5e455e48b095df7f5381dff028f8523aaf565a9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:29 -0500 Subject: drm/radeon/kms: fill in GPU init for AMD Ontario Fusion APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 07c4c6f216f0..7f859ffe99ce 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1299,6 +1299,7 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, switch (rdev->family) { case CHIP_CEDAR: case CHIP_REDWOOD: + case CHIP_PALM: force_no_swizzle = false; break; case CHIP_CYPRESS: @@ -1423,6 +1424,7 @@ static void evergreen_program_channel_remap(struct radeon_device *rdev) case CHIP_JUNIPER: case CHIP_REDWOOD: case CHIP_CEDAR: + case CHIP_PALM: default: tcp_chan_steer_lo = 0x76543210; tcp_chan_steer_hi = 0x0000ba98; @@ -1541,6 +1543,27 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.max_hw_contexts = 4; rdev->config.evergreen.sq_num_cf_insts = 1; + rdev->config.evergreen.sc_prim_fifo_size = 0x40; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_PALM: + rdev->config.evergreen.num_ses = 1; + rdev->config.evergreen.max_pipes = 2; + rdev->config.evergreen.max_tile_pipes = 2; + rdev->config.evergreen.max_simds = 2; + rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 192; + rdev->config.evergreen.max_gs_threads = 16; + rdev->config.evergreen.max_stack_entries = 256; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 128; + rdev->config.evergreen.sx_max_export_pos_size = 32; + rdev->config.evergreen.sx_max_export_smx_size = 96; + rdev->config.evergreen.max_hw_contexts = 4; + rdev->config.evergreen.sq_num_cf_insts = 1; + rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; @@ -1821,9 +1844,15 @@ static void evergreen_gpu_init(struct radeon_device *rdev) GS_PRIO(2) | ES_PRIO(3)); - if (rdev->family == CHIP_CEDAR) + switch (rdev->family) { + case CHIP_CEDAR: + case CHIP_PALM: /* no vertex cache */ sq_config &= ~VC_ENABLE; + break; + default: + break; + } sq_lds_resource_mgmt = RREG32(SQ_LDS_RESOURCE_MGMT); @@ -1835,10 +1864,15 @@ static void evergreen_gpu_init(struct radeon_device *rdev) sq_gpr_resource_mgmt_3 = NUM_HS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32); sq_gpr_resource_mgmt_3 |= NUM_LS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32); - if (rdev->family == CHIP_CEDAR) + switch (rdev->family) { + case CHIP_CEDAR: + case CHIP_PALM: ps_thread_count = 96; - else + break; + default: ps_thread_count = 128; + break; + } sq_thread_resource_mgmt = NUM_PS_THREADS(ps_thread_count); sq_thread_resource_mgmt |= NUM_VS_THREADS((((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8); @@ -1869,10 +1903,15 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) | FORCE_EOV_MAX_REZ_CNT(255))); - if (rdev->family == CHIP_CEDAR) + switch (rdev->family) { + case CHIP_CEDAR: + case CHIP_PALM: vgt_cache_invalidation = CACHE_INVALIDATION(TC_ONLY); - else + break; + default: vgt_cache_invalidation = CACHE_INVALIDATION(VC_AND_TC); + break; + } vgt_cache_invalidation |= AUTO_INVLD_EN(ES_AND_GS_AUTO); WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation); -- cgit v1.2.3 From e33df25fecd31be889a878bc75313817bc292bac Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:32 -0500 Subject: drm/radeon/kms: add thermal sensor support for fusion APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 8 ++++++++ drivers/gpu/drm/radeon/evergreend.h | 4 +++- drivers/gpu/drm/radeon/radeon.h | 2 ++ drivers/gpu/drm/radeon/radeon_pm.c | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 7f859ffe99ce..075d6c172595 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -57,6 +57,14 @@ u32 evergreen_get_temp(struct radeon_device *rdev) return actual_temp * 1000; } +u32 sumo_get_temp(struct radeon_device *rdev) +{ + u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff; + u32 actual_temp = (temp >> 1) & 0xff; + + return actual_temp * 1000; +} + void evergreen_pm_misc(struct radeon_device *rdev) { int req_ps_idx = rdev->pm.requested_power_state_index; diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 9644b1cbfb09..87fcaba76695 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -164,11 +164,13 @@ #define SE_SC_BUSY (1 << 29) #define SE_DB_BUSY (1 << 30) #define SE_CB_BUSY (1 << 31) - +/* evergreen */ #define CG_MULT_THERMAL_STATUS 0x740 #define ASIC_T(x) ((x) << 16) #define ASIC_T_MASK 0x7FF0000 #define ASIC_T_SHIFT 16 +/* APU */ +#define CG_THERMAL_STATUS 0x678 #define HDP_HOST_PATH_CNTL 0x2C00 #define HDP_NONSURFACE_BASE 0x2C04 diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index bf3a4fc82964..0507ee7e16eb 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -180,6 +180,7 @@ void rs690_pm_info(struct radeon_device *rdev); extern u32 rv6xx_get_temp(struct radeon_device *rdev); extern u32 rv770_get_temp(struct radeon_device *rdev); extern u32 evergreen_get_temp(struct radeon_device *rdev); +extern u32 sumo_get_temp(struct radeon_device *rdev); /* * Fences. @@ -687,6 +688,7 @@ enum radeon_int_thermal_type { THERMAL_TYPE_RV6XX, THERMAL_TYPE_RV770, THERMAL_TYPE_EVERGREEN, + THERMAL_TYPE_SUMO, }; struct radeon_voltage { diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 8c9b2ef32c68..ac4efb0f1cb4 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -449,6 +449,9 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev, case THERMAL_TYPE_EVERGREEN: temp = evergreen_get_temp(rdev); break; + case THERMAL_TYPE_SUMO: + temp = sumo_get_temp(rdev); + break; default: temp = 0; break; @@ -487,6 +490,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev) case THERMAL_TYPE_RV6XX: case THERMAL_TYPE_RV770: case THERMAL_TYPE_EVERGREEN: + case THERMAL_TYPE_SUMO: rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev); if (IS_ERR(rdev->pm.int_hwmon_dev)) { err = PTR_ERR(rdev->pm.int_hwmon_dev); -- cgit v1.2.3 From e719ebd916c2ecee072affc9e7f0b92aa33c2f94 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:33 -0500 Subject: drm/radeon/kms: add bo blit support for Ontario fusion APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_blit_kms.c | 27 +++++++++++++++++++++++++-- drivers/gpu/drm/radeon/radeon_asic.c | 6 +++--- 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index e0e590110dd4..2ccd1f0545fe 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -147,7 +147,8 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) radeon_ring_write(rdev, 0); radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30); - if (rdev->family == CHIP_CEDAR) + if ((rdev->family == CHIP_CEDAR) || + (rdev->family == CHIP_PALM)) cp_set_surface_sync(rdev, PACKET3_TC_ACTION_ENA, 48, gpu_addr); else @@ -331,9 +332,31 @@ set_default_state(struct radeon_device *rdev) num_hs_stack_entries = 85; num_ls_stack_entries = 85; break; + case CHIP_PALM: + num_ps_gprs = 93; + num_vs_gprs = 46; + num_temp_gprs = 4; + num_gs_gprs = 31; + num_es_gprs = 31; + num_hs_gprs = 23; + num_ls_gprs = 23; + num_ps_threads = 96; + num_vs_threads = 16; + num_gs_threads = 16; + num_es_threads = 16; + num_hs_threads = 16; + num_ls_threads = 16; + num_ps_stack_entries = 42; + num_vs_stack_entries = 42; + num_gs_stack_entries = 42; + num_es_stack_entries = 42; + num_hs_stack_entries = 42; + num_ls_stack_entries = 42; + break; } - if (rdev->family == CHIP_CEDAR) + if ((rdev->family == CHIP_CEDAR) || + (rdev->family == CHIP_PALM)) sq_config = 0; else sq_config = VC_ENABLE; diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 4e487cc16e7f..de7bfbcd09c9 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -769,9 +769,9 @@ static struct radeon_asic sumo_asic = { .get_vblank_counter = &evergreen_get_vblank_counter, .fence_ring_emit = &r600_fence_ring_emit, .cs_parse = &evergreen_cs_parse, - .copy_blit = NULL, - .copy_dma = NULL, - .copy = NULL, + .copy_blit = &evergreen_copy_blit, + .copy_dma = &evergreen_copy_blit, + .copy = &evergreen_copy_blit, .get_engine_clock = &radeon_atom_get_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = NULL, -- cgit v1.2.3 From 560154e9a27f2f260fcb2dd18c488203246f257e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:34 -0500 Subject: drm/radeon/kms: refactor atombios power state fetching The function was getting too large. Rework it to share more state better handle new power table formats. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 941 ++++++++++++++++--------------- 1 file changed, 475 insertions(+), 466 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 4d37b2d1ba74..7056e20d329d 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1763,495 +1763,504 @@ static const char *pp_lib_thermal_controller_names[] = { "RV6xx", "RV770", "adt7473", + "NONE", "External GPIO", "Evergreen", "adt7473 with internal", - }; union power_info { struct _ATOM_POWERPLAY_INFO info; struct _ATOM_POWERPLAY_INFO_V2 info_2; struct _ATOM_POWERPLAY_INFO_V3 info_3; - struct _ATOM_PPLIB_POWERPLAYTABLE info_4; + struct _ATOM_PPLIB_POWERPLAYTABLE pplib; }; -void radeon_atombios_get_power_modes(struct radeon_device *rdev) +union pplib_clock_info { + struct _ATOM_PPLIB_R600_CLOCK_INFO r600; + struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; + struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; +}; + +union pplib_power_state { + struct _ATOM_PPLIB_STATE v1; + struct _ATOM_PPLIB_STATE_V2 v2; +}; + +static void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev, + int state_index, + u32 misc, u32 misc2) +{ + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; + /* order matters! */ + if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_POWERSAVE; + if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_BATTERY; + if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_BATTERY; + if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_BALANCED; + if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_PERFORMANCE; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + } + if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_BALANCED; + if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state_index = state_index; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + } else if (state_index == 0) { + rdev->pm.power_state[state_index].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; + } +} + +static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; + u32 misc, misc2 = 0; + int num_modes = 0, i; + int state_index = 0; + struct radeon_i2c_bus_rec i2c_bus; + union power_info *power_info; int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); - u16 data_offset; + u16 data_offset; u8 frev, crev; - u32 misc, misc2 = 0, sclk, mclk; - union power_info *power_info; - struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; - struct _ATOM_PPLIB_STATE *power_state; - int num_modes = 0, i, j; - int state_index = 0, mode_index = 0; - struct radeon_i2c_bus_rec i2c_bus; - - rdev->pm.default_power_state_index = -1; - if (atom_parse_data_header(mode_info->atom_context, index, NULL, - &frev, &crev, &data_offset)) { - power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); - if (frev < 4) { - /* add the i2c bus for thermal/fan chip */ - if (power_info->info.ucOverdriveThermalController > 0) { - DRM_INFO("Possible %s thermal controller at 0x%02x\n", - thermal_controller_names[power_info->info.ucOverdriveThermalController], - power_info->info.ucOverdriveControllerAddress >> 1); - i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); - rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); - if (rdev->pm.i2c_bus) { - struct i2c_board_info info = { }; - const char *name = thermal_controller_names[power_info->info. - ucOverdriveThermalController]; - info.addr = power_info->info.ucOverdriveControllerAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); - i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); - } + if (!atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) + return state_index; + power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); + + /* add the i2c bus for thermal/fan chip */ + if (power_info->info.ucOverdriveThermalController > 0) { + DRM_INFO("Possible %s thermal controller at 0x%02x\n", + thermal_controller_names[power_info->info.ucOverdriveThermalController], + power_info->info.ucOverdriveControllerAddress >> 1); + i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); + rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); + if (rdev->pm.i2c_bus) { + struct i2c_board_info info = { }; + const char *name = thermal_controller_names[power_info->info. + ucOverdriveThermalController]; + info.addr = power_info->info.ucOverdriveControllerAddress >> 1; + strlcpy(info.type, name, sizeof(info.type)); + i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); + } + } + num_modes = power_info->info.ucNumOfPowerModeEntries; + if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) + num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; + /* last mode is usually default, array is low to high */ + for (i = 0; i < num_modes; i++) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + switch (frev) { + case 1: + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = + le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); + rdev->pm.power_state[state_index].clock_info[0].sclk = + le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + continue; + rdev->pm.power_state[state_index].pcie_lanes = + power_info->info.asPowerPlayInfo[i].ucNumPciELanes; + misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_GPIO; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = + radeon_lookup_gpio(rdev, + power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_VDDC; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = + power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; } - num_modes = power_info->info.ucNumOfPowerModeEntries; - if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) - num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; - /* last mode is usually default, array is low to high */ - for (i = 0; i < num_modes; i++) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - switch (frev) { - case 1: - rdev->pm.power_state[state_index].num_clock_modes = 1; - rdev->pm.power_state[state_index].clock_info[0].mclk = - le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); - rdev->pm.power_state[state_index].clock_info[0].sclk = - le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); - /* skip invalid modes */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || - (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) - continue; - rdev->pm.power_state[state_index].pcie_lanes = - power_info->info.asPowerPlayInfo[i].ucNumPciELanes; - misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); - if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || - (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = - VOLTAGE_GPIO; - rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, - power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) - rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = - true; - else - rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = - false; - } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = - VOLTAGE_VDDC; - rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = - power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; - } - rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - rdev->pm.power_state[state_index].misc = misc; - /* order matters! */ - if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_POWERSAVE; - if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_PERFORMANCE; - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - } - if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state_index = state_index; - rdev->pm.power_state[state_index].default_clock_mode = - &rdev->pm.power_state[state_index].clock_info[0]; - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - } else if (state_index == 0) { - rdev->pm.power_state[state_index].clock_info[0].flags |= - RADEON_PM_MODE_NO_DISPLAY; - } - state_index++; - break; - case 2: - rdev->pm.power_state[state_index].num_clock_modes = 1; - rdev->pm.power_state[state_index].clock_info[0].mclk = - le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); - rdev->pm.power_state[state_index].clock_info[0].sclk = - le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); - /* skip invalid modes */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || - (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) - continue; - rdev->pm.power_state[state_index].pcie_lanes = - power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; - misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); - misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); - if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || - (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = - VOLTAGE_GPIO; - rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, - power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) - rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = - true; - else - rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = - false; - } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = - VOLTAGE_VDDC; - rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = - power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; - } - rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - rdev->pm.power_state[state_index].misc = misc; - rdev->pm.power_state[state_index].misc2 = misc2; - /* order matters! */ - if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_POWERSAVE; - if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_PERFORMANCE; - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - } - if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BALANCED; - if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT) - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state_index = state_index; - rdev->pm.power_state[state_index].default_clock_mode = - &rdev->pm.power_state[state_index].clock_info[0]; - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - } else if (state_index == 0) { - rdev->pm.power_state[state_index].clock_info[0].flags |= - RADEON_PM_MODE_NO_DISPLAY; - } - state_index++; - break; - case 3: - rdev->pm.power_state[state_index].num_clock_modes = 1; - rdev->pm.power_state[state_index].clock_info[0].mclk = - le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); - rdev->pm.power_state[state_index].clock_info[0].sclk = - le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); - /* skip invalid modes */ - if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || - (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) - continue; - rdev->pm.power_state[state_index].pcie_lanes = - power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; - misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); - misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); - if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || - (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = - VOLTAGE_GPIO; - rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, - power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) - rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = - true; - else - rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = - false; - } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { - rdev->pm.power_state[state_index].clock_info[0].voltage.type = - VOLTAGE_VDDC; - rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = - power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; - if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { - rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = - true; - rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = - power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; - } - } - rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - rdev->pm.power_state[state_index].misc = misc; - rdev->pm.power_state[state_index].misc2 = misc2; - /* order matters! */ - if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_POWERSAVE; - if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_PERFORMANCE; - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - } - if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BALANCED; - if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state_index = state_index; - rdev->pm.power_state[state_index].default_clock_mode = - &rdev->pm.power_state[state_index].clock_info[0]; - } else if (state_index == 0) { - rdev->pm.power_state[state_index].clock_info[0].flags |= - RADEON_PM_MODE_NO_DISPLAY; - } - state_index++; - break; - } + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0); + state_index++; + break; + case 2: + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = + le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); + rdev->pm.power_state[state_index].clock_info[0].sclk = + le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + continue; + rdev->pm.power_state[state_index].pcie_lanes = + power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; + misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); + misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_GPIO; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = + radeon_lookup_gpio(rdev, + power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_VDDC; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = + power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; } - /* last mode is usually default */ - if (rdev->pm.default_power_state_index == -1) { - rdev->pm.power_state[state_index - 1].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state_index = state_index - 1; - rdev->pm.power_state[state_index - 1].default_clock_mode = - &rdev->pm.power_state[state_index - 1].clock_info[0]; - rdev->pm.power_state[state_index].flags &= - ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - rdev->pm.power_state[state_index].misc = 0; - rdev->pm.power_state[state_index].misc2 = 0; + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); + state_index++; + break; + case 3: + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = + le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); + rdev->pm.power_state[state_index].clock_info[0].sclk = + le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) + continue; + rdev->pm.power_state[state_index].pcie_lanes = + power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; + misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); + misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_GPIO; + rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = + radeon_lookup_gpio(rdev, + power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); + if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + true; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = + false; + } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { + rdev->pm.power_state[state_index].clock_info[0].voltage.type = + VOLTAGE_VDDC; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = + power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; + if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { + rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = + true; + rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = + power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; + } } + rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); + state_index++; + break; + } + } + /* last mode is usually default */ + if (rdev->pm.default_power_state_index == -1) { + rdev->pm.power_state[state_index - 1].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state_index = state_index - 1; + rdev->pm.power_state[state_index - 1].default_clock_mode = + &rdev->pm.power_state[state_index - 1].clock_info[0]; + rdev->pm.power_state[state_index].flags &= + ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + rdev->pm.power_state[state_index].misc = 0; + rdev->pm.power_state[state_index].misc2 = 0; + } + return state_index; +} + +static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev, + ATOM_PPLIB_THERMALCONTROLLER *controller) +{ + struct radeon_i2c_bus_rec i2c_bus; + + /* add the i2c bus for thermal/fan chip */ + if (controller->ucType > 0) { + if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; + } else if ((controller->ucType == + ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || + (controller->ucType == + ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { + DRM_INFO("Special thermal controller config\n"); } else { - int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); - uint8_t fw_frev, fw_crev; - uint16_t fw_data_offset, vddc = 0; - union firmware_info *firmware_info; - ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; - - if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, - &fw_frev, &fw_crev, &fw_data_offset)) { - firmware_info = - (union firmware_info *)(mode_info->atom_context->bios + - fw_data_offset); - vddc = firmware_info->info_14.usBootUpVDDCVoltage; + DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", + pp_lib_thermal_controller_names[controller->ucType], + controller->ucI2cAddress >> 1, + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); + rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); + if (rdev->pm.i2c_bus) { + struct i2c_board_info info = { }; + const char *name = pp_lib_thermal_controller_names[controller->ucType]; + info.addr = controller->ucI2cAddress >> 1; + strlcpy(info.type, name, sizeof(info.type)); + i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } + } + } +} - /* add the i2c bus for thermal/fan chip */ - if (controller->ucType > 0) { - if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { - DRM_INFO("Internal thermal controller %s fan control\n", - (controller->ucFanParameters & - ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); - rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; - } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { - DRM_INFO("Internal thermal controller %s fan control\n", - (controller->ucFanParameters & - ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); - rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; - } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { - DRM_INFO("Internal thermal controller %s fan control\n", - (controller->ucFanParameters & - ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); - rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; - } else if ((controller->ucType == - ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || - (controller->ucType == - ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { - DRM_INFO("Special thermal controller config\n"); - } else { - DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", - pp_lib_thermal_controller_names[controller->ucType], - controller->ucI2cAddress >> 1, - (controller->ucFanParameters & - ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); - i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); - rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); - if (rdev->pm.i2c_bus) { - struct i2c_board_info info = { }; - const char *name = pp_lib_thermal_controller_names[controller->ucType]; - info.addr = controller->ucI2cAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); - i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); - } +static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); + u8 frev, crev; + u16 data_offset; + union firmware_info *firmware_info; + u16 vddc = 0; - } - } - /* first mode is usually default, followed by low to high */ - for (i = 0; i < power_info->info_4.ucNumStates; i++) { - mode_index = 0; - power_state = (struct _ATOM_PPLIB_STATE *) - (mode_info->atom_context->bios + - data_offset + - le16_to_cpu(power_info->info_4.usStateArrayOffset) + - i * power_info->info_4.ucStateEntrySize); - non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) - (mode_info->atom_context->bios + - data_offset + - le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) + - (power_state->ucNonClockStateIndex * - power_info->info_4.ucNonClockSize)); - for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) { - if (rdev->flags & RADEON_IS_IGP) { - struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info = - (struct _ATOM_PPLIB_RS780_CLOCK_INFO *) - (mode_info->atom_context->bios + - data_offset + - le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + - (power_state->ucClockStateIndices[j] * - power_info->info_4.ucClockInfoSize)); - sclk = le16_to_cpu(clock_info->usLowEngineClockLow); - sclk |= clock_info->ucLowEngineClockHigh << 16; - rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; - /* skip invalid modes */ - if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) - continue; - /* voltage works differently on IGPs */ - mode_index++; - } else if (ASIC_IS_DCE4(rdev)) { - struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = - (struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *) - (mode_info->atom_context->bios + - data_offset + - le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + - (power_state->ucClockStateIndices[j] * - power_info->info_4.ucClockInfoSize)); - sclk = le16_to_cpu(clock_info->usEngineClockLow); - sclk |= clock_info->ucEngineClockHigh << 16; - mclk = le16_to_cpu(clock_info->usMemoryClockLow); - mclk |= clock_info->ucMemoryClockHigh << 16; - rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; - rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; - /* skip invalid modes */ - if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || - (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) - continue; - rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = - VOLTAGE_SW; - rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = - clock_info->usVDDC; - /* XXX usVDDCI */ - mode_index++; - } else { - struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info = - (struct _ATOM_PPLIB_R600_CLOCK_INFO *) - (mode_info->atom_context->bios + - data_offset + - le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + - (power_state->ucClockStateIndices[j] * - power_info->info_4.ucClockInfoSize)); - sclk = le16_to_cpu(clock_info->usEngineClockLow); - sclk |= clock_info->ucEngineClockHigh << 16; - mclk = le16_to_cpu(clock_info->usMemoryClockLow); - mclk |= clock_info->ucMemoryClockHigh << 16; - rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; - rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; - /* skip invalid modes */ - if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || - (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) - continue; - rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = - VOLTAGE_SW; - rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = - clock_info->usVDDC; - mode_index++; - } - } - rdev->pm.power_state[state_index].num_clock_modes = mode_index; - if (mode_index) { - misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); - misc2 = le16_to_cpu(non_clock_info->usClassification); - rdev->pm.power_state[state_index].misc = misc; - rdev->pm.power_state[state_index].misc2 = misc2; - rdev->pm.power_state[state_index].pcie_lanes = - ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> - ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; - switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { - case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BATTERY; - break; - case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_BALANCED; - break; - case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_PERFORMANCE; - break; - case ATOM_PPLIB_CLASSIFICATION_UI_NONE: - if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_PERFORMANCE; - break; - } - rdev->pm.power_state[state_index].flags = 0; - if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) - rdev->pm.power_state[state_index].flags |= - RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state_index = state_index; - rdev->pm.power_state[state_index].default_clock_mode = - &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; - /* patch the table values with the default slck/mclk from firmware info */ - for (j = 0; j < mode_index; j++) { - rdev->pm.power_state[state_index].clock_info[j].mclk = - rdev->clock.default_mclk; - rdev->pm.power_state[state_index].clock_info[j].sclk = - rdev->clock.default_sclk; - if (vddc) - rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = - vddc; - } - } - state_index++; - } - } - /* if multiple clock modes, mark the lowest as no display */ - for (i = 0; i < state_index; i++) { - if (rdev->pm.power_state[i].num_clock_modes > 1) - rdev->pm.power_state[i].clock_info[0].flags |= - RADEON_PM_MODE_NO_DISPLAY; - } - /* first mode is usually default */ - if (rdev->pm.default_power_state_index == -1) { - rdev->pm.power_state[0].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.default_power_state_index = 0; - rdev->pm.power_state[0].default_clock_mode = - &rdev->pm.power_state[0].clock_info[0]; - } + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + firmware_info = + (union firmware_info *)(mode_info->atom_context->bios + + data_offset); + vddc = firmware_info->info_14.usBootUpVDDCVoltage; + } + + return vddc; +} + +static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, + int state_index, int mode_index, + struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) +{ + int j; + u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); + u32 misc2 = le16_to_cpu(non_clock_info->usClassification); + u16 vddc = radeon_atombios_get_default_vddc(rdev); + + rdev->pm.power_state[state_index].misc = misc; + rdev->pm.power_state[state_index].misc2 = misc2; + rdev->pm.power_state[state_index].pcie_lanes = + ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> + ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; + switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { + case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_BATTERY; + break; + case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_BALANCED; + break; + case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_PERFORMANCE; + break; + case ATOM_PPLIB_CLASSIFICATION_UI_NONE: + if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_PERFORMANCE; + break; + } + rdev->pm.power_state[state_index].flags = 0; + if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) + rdev->pm.power_state[state_index].flags |= + RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; + if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state_index = state_index; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; + /* patch the table values with the default slck/mclk from firmware info */ + for (j = 0; j < mode_index; j++) { + rdev->pm.power_state[state_index].clock_info[j].mclk = + rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[j].sclk = + rdev->clock.default_sclk; + if (vddc) + rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = + vddc; + } + } +} + +static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, + int state_index, int mode_index, + union pplib_clock_info *clock_info) +{ + u32 sclk, mclk; + + if (rdev->flags & RADEON_IS_IGP) { + sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); + sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + } else if (ASIC_IS_DCE4(rdev)) { + sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); + sclk |= clock_info->evergreen.ucEngineClockHigh << 16; + mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); + mclk |= clock_info->evergreen.ucMemoryClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = + VOLTAGE_SW; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = + clock_info->evergreen.usVDDC; + } else { + sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); + sclk |= clock_info->r600.ucEngineClockHigh << 16; + mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); + mclk |= clock_info->r600.ucMemoryClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = + VOLTAGE_SW; + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = + clock_info->r600.usVDDC; + } + + if (rdev->flags & RADEON_IS_IGP) { + /* skip invalid modes */ + if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) + return false; + } else { + /* skip invalid modes */ + if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || + (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) + return false; + } + return true; +} + +static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; + union pplib_power_state *power_state; + int i, j; + int state_index = 0, mode_index = 0; + union pplib_clock_info *clock_info; + bool valid; + union power_info *power_info; + int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); + u16 data_offset; + u8 frev, crev; + + if (!atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) + return state_index; + power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); + + radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); + /* first mode is usually default, followed by low to high */ + for (i = 0; i < power_info->pplib.ucNumStates; i++) { + mode_index = 0; + power_state = (union pplib_power_state *) + (mode_info->atom_context->bios + data_offset + + le16_to_cpu(power_info->pplib.usStateArrayOffset) + + i * power_info->pplib.ucStateEntrySize); + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + (mode_info->atom_context->bios + data_offset + + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + + (power_state->v1.ucNonClockStateIndex * + power_info->pplib.ucNonClockSize)); + for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { + clock_info = (union pplib_clock_info *) + (mode_info->atom_context->bios + data_offset + + le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + + (power_state->v1.ucClockStateIndices[j] * + power_info->pplib.ucClockInfoSize)); + valid = radeon_atombios_parse_pplib_clock_info(rdev, + state_index, mode_index, + clock_info); + if (valid) + mode_index++; + } + rdev->pm.power_state[state_index].num_clock_modes = mode_index; + if (mode_index) { + radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, + non_clock_info); + state_index++; + } + } + /* if multiple clock modes, mark the lowest as no display */ + for (i = 0; i < state_index; i++) { + if (rdev->pm.power_state[i].num_clock_modes > 1) + rdev->pm.power_state[i].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; + } + /* first mode is usually default */ + if (rdev->pm.default_power_state_index == -1) { + rdev->pm.power_state[0].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state_index = 0; + rdev->pm.power_state[0].default_clock_mode = + &rdev->pm.power_state[0].clock_info[0]; + } + return state_index; +} + +void radeon_atombios_get_power_modes(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); + u16 data_offset; + u8 frev, crev; + int state_index = 0; + + rdev->pm.default_power_state_index = -1; + + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + switch (frev) { + case 1: + case 2: + case 3: + state_index = radeon_atombios_parse_power_table_1_3(rdev); + break; + case 4: + case 5: + state_index = radeon_atombios_parse_power_table_4_5(rdev); + break; + default: + break; } } else { /* add the default mode */ -- cgit v1.2.3 From b0e664140a170382531a8c8b5396bf7e6903d5e3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:35 -0500 Subject: drm/radeon/kms: add power table parsing support for Ontario fusion APUs The vbios power tables on my inagua board seem a bit funky... Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 106 +++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 7056e20d329d..ac882639b3ed 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1766,7 +1766,8 @@ static const char *pp_lib_thermal_controller_names[] = { "NONE", "External GPIO", "Evergreen", - "adt7473 with internal", + "emc2103", + "Sumo", }; union power_info { @@ -1774,12 +1775,15 @@ union power_info { struct _ATOM_POWERPLAY_INFO_V2 info_2; struct _ATOM_POWERPLAY_INFO_V3 info_3; struct _ATOM_PPLIB_POWERPLAYTABLE pplib; + struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; + struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; }; union pplib_clock_info { struct _ATOM_PPLIB_R600_CLOCK_INFO r600; struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; + struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; }; union pplib_power_state { @@ -2022,10 +2026,17 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO; } else if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || (controller->ucType == - ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { + ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) || + (controller->ucType == + ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { DRM_INFO("Special thermal controller config\n"); } else { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", @@ -2129,9 +2140,15 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, u32 sclk, mclk; if (rdev->flags & RADEON_IS_IGP) { - sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); - sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; - rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + if (rdev->family >= CHIP_PALM) { + sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); + sclk |= clock_info->sumo.ucEngineClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + } else { + sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); + sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; + rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; + } } else if (ASIC_IS_DCE4(rdev)) { sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); sclk |= clock_info->evergreen.ucEngineClockHigh << 16; @@ -2237,6 +2254,82 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) return state_index; } +static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; + union pplib_power_state *power_state; + int i, j, non_clock_array_index, clock_array_index; + int state_index = 0, mode_index = 0; + union pplib_clock_info *clock_info; + struct StateArray *state_array; + struct ClockInfoArray *clock_info_array; + struct NonClockInfoArray *non_clock_info_array; + bool valid; + union power_info *power_info; + int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); + u16 data_offset; + u8 frev, crev; + + if (!atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) + return state_index; + power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); + + radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); + state_array = (struct StateArray *) + (mode_info->atom_context->bios + data_offset + + power_info->pplib.usStateArrayOffset); + clock_info_array = (struct ClockInfoArray *) + (mode_info->atom_context->bios + data_offset + + power_info->pplib.usClockInfoArrayOffset); + non_clock_info_array = (struct NonClockInfoArray *) + (mode_info->atom_context->bios + data_offset + + power_info->pplib.usNonClockInfoArrayOffset); + for (i = 0; i < state_array->ucNumEntries; i++) { + mode_index = 0; + power_state = (union pplib_power_state *)&state_array->states[i]; + /* XXX this might be an inagua bug... */ + non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + &non_clock_info_array->nonClockInfo[non_clock_array_index]; + for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { + clock_array_index = power_state->v2.clockInfoIndex[j]; + /* XXX this might be an inagua bug... */ + if (clock_array_index >= clock_info_array->ucNumEntries) + continue; + clock_info = (union pplib_clock_info *) + &clock_info_array->clockInfo[clock_array_index]; + valid = radeon_atombios_parse_pplib_clock_info(rdev, + state_index, mode_index, + clock_info); + if (valid) + mode_index++; + } + rdev->pm.power_state[state_index].num_clock_modes = mode_index; + if (mode_index) { + radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, + non_clock_info); + state_index++; + } + } + /* if multiple clock modes, mark the lowest as no display */ + for (i = 0; i < state_index; i++) { + if (rdev->pm.power_state[i].num_clock_modes > 1) + rdev->pm.power_state[i].clock_info[0].flags |= + RADEON_PM_MODE_NO_DISPLAY; + } + /* first mode is usually default */ + if (rdev->pm.default_power_state_index == -1) { + rdev->pm.power_state[0].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.default_power_state_index = 0; + rdev->pm.power_state[0].default_clock_mode = + &rdev->pm.power_state[0].clock_info[0]; + } + return state_index; +} + void radeon_atombios_get_power_modes(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; @@ -2259,6 +2352,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) case 5: state_index = radeon_atombios_parse_power_table_4_5(rdev); break; + case 6: + state_index = radeon_atombios_parse_power_table_6(rdev); + break; default: break; } -- cgit v1.2.3 From bbbf9b7b02e0090d91c422398089c9f22361dc94 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:36 -0500 Subject: drm/radeon/kms: enable MSIs on fusion APUs Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a108c7ed14f5..b492b7dc63ac 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -121,7 +121,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev) * chips. Disable MSI on them for now. */ if ((rdev->family >= CHIP_RV380) && - (!(rdev->flags & RADEON_IS_IGP)) && + ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) && (!(rdev->flags & RADEON_IS_AGP))) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { -- cgit v1.2.3 From 439bd6cde45d0bff4f97513b01b976b9f72ae1f0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Nov 2010 17:56:31 -0500 Subject: drm/radeon/kms: add Ontario APU ucode loading support Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 93b1c687328b..b37361b69ad5 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -83,6 +83,9 @@ MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin"); MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin"); MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); +MODULE_FIRMWARE("radeon/PALM_pfp.bin"); +MODULE_FIRMWARE("radeon/PALM_me.bin"); +MODULE_FIRMWARE("radeon/SUMO_rlc.bin"); int r600_debugfs_mc_info_init(struct radeon_device *rdev); @@ -1998,6 +2001,10 @@ int r600_init_microcode(struct radeon_device *rdev) chip_name = "CYPRESS"; rlc_chip_name = "CYPRESS"; break; + case CHIP_PALM: + chip_name = "PALM"; + rlc_chip_name = "SUMO"; + break; default: BUG(); } -- cgit v1.2.3 From 3685092b717882bb9b6801bf3e4b02a106e3b129 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 08:49:38 +0000 Subject: drm/i915: Avoid oops when capturing NULL ring for inactive pinned buffers Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++--- drivers/gpu/drm/i915/i915_irq.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 421b8414b577..4fe49e0228ef 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -572,9 +572,9 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) static const char *ring_str(int ring) { switch (ring) { - case RING_RENDER: return "render"; - case RING_BSD: return "bsd"; - case RING_BLT: return "blt"; + case RING_RENDER: return " render"; + case RING_BSD: return " bsd"; + case RING_BLT: return " blt"; default: return ""; } } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0b6052abedd1..a8f55f061f6d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -575,7 +575,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err, err->tiling = obj->tiling_mode; err->dirty = obj->dirty; err->purgeable = obj->madv != I915_MADV_WILLNEED; - err->ring = obj->ring->id; + err->ring = obj->ring ? obj->ring->id : 0; if (++i == count) break; -- cgit v1.2.3 From 0b0b053a3949f5c467c3b3ba135d4c161f9fbd00 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 09:45:50 +0000 Subject: drm/i915/panel: Restore saved value of BLC_PWM_CTL After a GPU reset, the backlight controller registers may be also reset to 0. In that case we should restore those to the original values programmed by the BIOS. Note that we still lack the code to handle the case where the BIOS failed to program those registers at all... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_panel.c | 52 ++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 92ff8f385278..7350ec2515c6 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -125,15 +125,55 @@ static int is_backlight_combination_mode(struct drm_device *dev) return 0; } +static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) +{ + u32 val; + + /* Restore the CTL value if it lost, e.g. GPU reset */ + + if (HAS_PCH_SPLIT(dev_priv->dev)) { + val = I915_READ(BLC_PWM_PCH_CTL2); + if (dev_priv->saveBLC_PWM_CTL2 == 0) { + dev_priv->saveBLC_PWM_CTL2 = val; + } else if (val == 0) { + I915_WRITE(BLC_PWM_PCH_CTL2, + dev_priv->saveBLC_PWM_CTL); + val = dev_priv->saveBLC_PWM_CTL; + } + } else { + val = I915_READ(BLC_PWM_CTL); + if (dev_priv->saveBLC_PWM_CTL == 0) { + dev_priv->saveBLC_PWM_CTL = val; + dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + } else if (val == 0) { + I915_WRITE(BLC_PWM_CTL, + dev_priv->saveBLC_PWM_CTL); + I915_WRITE(BLC_PWM_CTL2, + dev_priv->saveBLC_PWM_CTL2); + val = dev_priv->saveBLC_PWM_CTL; + } + } + + return val; +} + u32 intel_panel_get_max_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 max; + max = i915_read_blc_pwm_ctl(dev_priv); + if (max == 0) { + /* XXX add code here to query mode clock or hardware clock + * and program max PWM appropriately. + */ + printk_once(KERN_WARNING "fixme: max PWM is zero.\n"); + return 1; + } + if (HAS_PCH_SPLIT(dev)) { - max = I915_READ(BLC_PWM_PCH_CTL2) >> 16; + max >>= 16; } else { - max = I915_READ(BLC_PWM_CTL); if (IS_PINEVIEW(dev)) { max >>= 17; } else { @@ -146,14 +186,6 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) max *= 0xff; } - if (max == 0) { - /* XXX add code here to query mode clock or hardware clock - * and program max PWM appropriately. - */ - DRM_ERROR("fixme: max PWM is zero.\n"); - max = 1; - } - DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); return max; } -- cgit v1.2.3 From fe669bf88e9108b96a847385df08c9b1e98c1420 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 12:09:30 +0000 Subject: drm/i915: Compute physical addresses from base of stolen memory The GATT is a write-only set of registers, reading from them in the manner of i915_gtt_to_phys() is supposed to be undefined. However a simple solution exists as we allocate linear memory from the stolen area, we can simply add the block offset to the base register. As a side-effect we recover all the unused stolen GTT entries and so enlarge our aperture. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 197 ++++++++++++++++------------------------ drivers/gpu/drm/i915/i915_drv.h | 2 +- 2 files changed, 77 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index cf4e06a9417a..3df271215ab9 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1007,73 +1007,47 @@ intel_teardown_mchbar(struct drm_device *dev) #define PTE_VALID (1 << 0) /** - * i915_gtt_to_phys - take a GTT address and turn it into a physical one + * i915_stolen_to_phys - take an offset into stolen memory and turn it into + * a physical one * @dev: drm device - * @gtt_addr: address to translate + * @offset: address to translate * - * Some chip functions require allocations from stolen space but need the - * physical address of the memory in question. We use this routine - * to get a physical address suitable for register programming from a given - * GTT address. + * Some chip functions require allocations from stolen space and need the + * physical address of the memory in question. */ -static unsigned long i915_gtt_to_phys(struct drm_device *dev, - unsigned long gtt_addr) +static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset) { - unsigned long *gtt; - unsigned long entry, phys; - int gtt_bar = IS_GEN2(dev) ? 1 : 0; - int gtt_offset, gtt_size; - - if (INTEL_INFO(dev)->gen >= 4) { - if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) { - gtt_offset = 2*1024*1024; - gtt_size = 2*1024*1024; - } else { - gtt_offset = 512*1024; - gtt_size = 512*1024; - } + struct drm_i915_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev_priv->bridge_dev; + u32 base; + +#if 0 + /* On the machines I have tested the Graphics Base of Stolen Memory + * is unreliable, so compute the base by subtracting the stolen memory + * from the Top of Low Usable DRAM which is where the BIOS places + * the graphics stolen memory. + */ + if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { + /* top 32bits are reserved = 0 */ + pci_read_config_dword(pdev, 0xA4, &base); } else { - gtt_bar = 3; - gtt_offset = 0; - gtt_size = pci_resource_len(dev->pdev, gtt_bar); - } - - gtt = ioremap_wc(pci_resource_start(dev->pdev, gtt_bar) + gtt_offset, - gtt_size); - if (!gtt) { - DRM_ERROR("ioremap of GTT failed\n"); - return 0; - } - - entry = *(volatile u32 *)(gtt + (gtt_addr / 1024)); - - DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry); - - /* Mask out these reserved bits on this hardware. */ - if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev)) - entry &= ~PTE_ADDRESS_MASK_HIGH; - - /* If it's not a mapping type we know, then bail. */ - if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED && - (entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_CACHED) { - iounmap(gtt); - return 0; - } - - if (!(entry & PTE_VALID)) { - DRM_ERROR("bad GTT entry in stolen space\n"); - iounmap(gtt); - return 0; + /* XXX presume 8xx is the same as i915 */ + pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base); + } +#else + if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { + u16 val; + pci_read_config_word(pdev, 0xb0, &val); + base = val >> 4 << 20; + } else { + u8 val; + pci_read_config_byte(pdev, 0x9c, &val); + base = val >> 3 << 27; } + base -= dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; +#endif - iounmap(gtt); - - phys =(entry & PTE_ADDRESS_MASK) | - ((uint64_t)(entry & PTE_ADDRESS_MASK_HIGH) << (32 - 4)); - - DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, phys addr: 0x%08lx\n", gtt_addr, phys); - - return phys; + return base + offset; } static void i915_warn_stolen(struct drm_device *dev) @@ -1089,47 +1063,28 @@ static void i915_setup_compression(struct drm_device *dev, int size) unsigned long cfb_base; unsigned long ll_base = 0; - /* Leave 1M for line length buffer & misc. */ - compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0); - if (!compressed_fb) { - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - i915_warn_stolen(dev); - return; - } - - compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); - if (!compressed_fb) { - i915_warn_stolen(dev); - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - return; - } + compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0); + if (compressed_fb) + compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); + if (!compressed_fb) + goto err; - cfb_base = i915_gtt_to_phys(dev, compressed_fb->start); - if (!cfb_base) { - DRM_ERROR("failed to get stolen phys addr, disabling FBC\n"); - drm_mm_put_block(compressed_fb); - } + cfb_base = i915_stolen_to_phys(dev, compressed_fb->start); + if (!cfb_base) + goto err_fb; if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) { - compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096, - 4096, 0); - if (!compressed_llb) { - i915_warn_stolen(dev); - return; - } - - compressed_llb = drm_mm_get_block(compressed_llb, 4096, 4096); - if (!compressed_llb) { - i915_warn_stolen(dev); - return; - } + compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen, + 4096, 4096, 0); + if (compressed_llb) + compressed_llb = drm_mm_get_block(compressed_llb, + 4096, 4096); + if (!compressed_llb) + goto err_fb; - ll_base = i915_gtt_to_phys(dev, compressed_llb->start); - if (!ll_base) { - DRM_ERROR("failed to get stolen phys addr, disabling FBC\n"); - drm_mm_put_block(compressed_fb); - drm_mm_put_block(compressed_llb); - } + ll_base = i915_stolen_to_phys(dev, compressed_llb->start); + if (!ll_base) + goto err_llb; } dev_priv->cfb_size = size; @@ -1146,8 +1101,17 @@ static void i915_setup_compression(struct drm_device *dev, int size) dev_priv->compressed_llb = compressed_llb; } - DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base, - ll_base, size >> 20); + DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", + cfb_base, ll_base, size >> 20); + return; + +err_llb: + drm_mm_put_block(compressed_llb); +err_fb: + drm_mm_put_block(compressed_fb); +err: + dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + i915_warn_stolen(dev); } static void i915_cleanup_compression(struct drm_device *dev) @@ -1207,12 +1171,11 @@ static int i915_load_modeset_init(struct drm_device *dev) prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - gtt_size -= PAGE_SIZE; - /* Basic memrange allocator for stolen space (aka mm.vram) */ - drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size); + /* Basic memrange allocator for stolen space */ + drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); - /* Let GEM Manage from end of prealloc space to end of aperture. + /* Let GEM Manage all of the aperture. * * However, leave one page at the end still bound to the scratch page. * There are a number of places where the hardware apparently @@ -1221,7 +1184,7 @@ static int i915_load_modeset_init(struct drm_device *dev) * at the last page of the aperture. One page should be enough to * keep any prefetching inside of the aperture. */ - i915_gem_do_init(dev, prealloc_size, mappable_size, gtt_size); + i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE); mutex_lock(&dev->struct_mutex); ret = i915_gem_init_ringbuffer(dev); @@ -1233,16 +1196,17 @@ static int i915_load_modeset_init(struct drm_device *dev) if (I915_HAS_FBC(dev) && i915_powersave) { int cfb_size; - /* Try to get an 8M buffer... */ - if (prealloc_size > (9*1024*1024)) - cfb_size = 8*1024*1024; + /* Leave 1M for line length buffer & misc. */ + + /* Try to get a 32M buffer... */ + if (prealloc_size > (36*1024*1024)) + cfb_size = 32*1024*1024; else /* fall back to 7/8 of the stolen space */ cfb_size = prealloc_size * 7 / 8; i915_setup_compression(dev, cfb_size); } - /* Allow hardware batchbuffers unless told otherwise. - */ + /* Allow hardware batchbuffers unless told otherwise. */ dev_priv->allow_batchbuffer = 1; ret = intel_parse_bios(dev); @@ -1892,7 +1856,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv; int ret = 0, mmio_bar; - uint32_t agp_size, prealloc_size; + uint32_t agp_size; + /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; @@ -1932,7 +1897,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_iomapfree; } - prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; dev_priv->mm.gtt_mapping = @@ -1980,15 +1944,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* enable GEM by default */ dev_priv->has_gem = 1; - if (prealloc_size > agp_size * 3 / 4) { - DRM_ERROR("Detected broken video BIOS with %d/%dkB of video " - "memory stolen.\n", - prealloc_size / 1024, agp_size / 1024); - DRM_ERROR("Disabling GEM. (try reducing stolen memory or " - "updating the BIOS to fix).\n"); - dev_priv->has_gem = 0; - } - if (dev_priv->has_gem == 0 && drm_core_check_feature(dev, DRIVER_MODESET)) { DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n"); @@ -2162,7 +2117,7 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); if (I915_HAS_FBC(dev) && i915_powersave) i915_cleanup_compression(dev); - drm_mm_takedown(&dev_priv->mm.vram); + drm_mm_takedown(&dev_priv->mm.stolen); intel_cleanup_overlay(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index db79df376b86..745e46b0673f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -544,7 +544,7 @@ typedef struct drm_i915_private { /** Bridge to intel-gtt-ko */ struct intel_gtt *gtt; /** Memory allocator for GTT stolen memory */ - struct drm_mm vram; + struct drm_mm stolen; /** Memory allocator for GTT */ struct drm_mm gtt_space; /** End of mappable part of GTT */ -- cgit v1.2.3 From 1b6064d79b9a1c5e5aa6fcc6855f3da5e639ff73 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 12:33:54 +0000 Subject: agp/intel: Remove the artificial cap on stolen size Now that the stolen memory does not also steal entries from the GTT, we can use all the memory the BIOS set aside for the GPU. Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index fc1637c32cb1..19919ef9d661 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -39,9 +39,6 @@ #define USE_PCI_DMA_API 0 #endif -/* Max amount of stolen space, anything above will be returned to Linux */ -int intel_max_stolen = 32 * 1024 * 1024; - static const struct aper_size_info_fixed intel_i810_sizes[] = { {64, 16384, 4}, @@ -486,7 +483,7 @@ static unsigned int intel_gtt_stolen_entries(void) u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; - unsigned int overhead_entries, stolen_entries; + unsigned int overhead_entries; unsigned int stolen_size = 0; pci_read_config_word(intel_private.bridge_dev, @@ -625,12 +622,7 @@ static unsigned int intel_gtt_stolen_entries(void) } } - if (!local && stolen_size > intel_max_stolen) { - dev_info(&intel_private.bridge_dev->dev, - "detected %dK stolen memory, trimming to %dK\n", - stolen_size / KB(1), intel_max_stolen / KB(1)); - stolen_size = intel_max_stolen; - } else if (stolen_size > 0) { + if (stolen_size > 0) { dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", stolen_size / KB(1), local ? "local" : "stolen"); } else { @@ -639,9 +631,7 @@ static unsigned int intel_gtt_stolen_entries(void) stolen_size = 0; } - stolen_entries = stolen_size/KB(4) - overhead_entries; - - return stolen_entries; + return stolen_size/KB(4) - overhead_entries; } static void i965_adjust_pgetbl_size(unsigned int size_flag) -- cgit v1.2.3 From c64f7ba5f1006d8c20eacafecf98d4d00a6902a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 14:24:24 +0000 Subject: agp/intel: Remove confusion of stolen entries not stolen memory Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 40 +++++++--------------------------------- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 2 +- include/drm/intel-gtt.h | 11 +++++------ 4 files changed, 15 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 19919ef9d661..d2733e526a68 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -477,26 +477,17 @@ static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { {512, 131072, 7}, }; -static unsigned int intel_gtt_stolen_entries(void) +static unsigned int intel_gtt_stolen_size(void) { u16 gmch_ctrl; u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; - unsigned int overhead_entries; unsigned int stolen_size = 0; pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); - if (INTEL_GTT_GEN > 4 || IS_PINEVIEW) - overhead_entries = 0; - else - overhead_entries = intel_private.base.gtt_mappable_entries - / 1024; - - overhead_entries += 1; /* BIOS popup */ - if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { @@ -631,7 +622,7 @@ static unsigned int intel_gtt_stolen_entries(void) stolen_size = 0; } - return stolen_size/KB(4) - overhead_entries; + return stolen_size; } static void i965_adjust_pgetbl_size(unsigned int size_flag) @@ -817,8 +808,8 @@ static int intel_gtt_init(void) global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ - intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); - if (intel_private.base.gtt_stolen_entries == 0) { + intel_private.base.stolen_size = intel_gtt_stolen_size(); + if (intel_private.base.stolen_size == 0) { intel_private.driver->cleanup(); iounmap(intel_private.registers); iounmap(intel_private.gtt); @@ -1006,8 +997,7 @@ static int intel_fake_agp_configure(void) agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; - for (i = intel_private.base.gtt_stolen_entries; - i < intel_private.base.gtt_total_entries; i++) { + for (i = 0; i < intel_private.base.gtt_total_entries; i++) { intel_private.driver->write_entry(intel_private.scratch_page_dma, i, 0); } @@ -1065,17 +1055,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (mem->page_count == 0) goto out; - if (pg_start < intel_private.base.gtt_stolen_entries) { - dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, - "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", - pg_start, intel_private.base.gtt_stolen_entries); - - dev_info(&intel_private.pcidev->dev, - "trying to insert into local/stolen memory\n"); - goto out_err; - } - - if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries) + if (pg_start + mem->page_count > intel_private.base.gtt_total_entries) goto out_err; if (type != mem->type) @@ -1118,12 +1098,6 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, if (mem->page_count == 0) return 0; - if (pg_start < intel_private.base.gtt_stolen_entries) { - dev_info(&intel_private.pcidev->dev, - "trying to disable local/stolen memory\n"); - return -EINVAL; - } - if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) intel_agp_unmap_memory(mem); @@ -1629,7 +1603,7 @@ int intel_gmch_probe(struct pci_dev *pdev, } EXPORT_SYMBOL(intel_gmch_probe); -struct intel_gtt *intel_gtt_get(void) +const struct intel_gtt *intel_gtt_get(void) { return &intel_private.base; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3df271215ab9..86b0e8052ec9 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1044,7 +1044,7 @@ static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset) pci_read_config_byte(pdev, 0x9c, &val); base = val >> 3 << 27; } - base -= dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; + base -= dev_priv->mm.gtt->stolen_size; #endif return base + offset; @@ -1168,7 +1168,7 @@ static int i915_load_modeset_init(struct drm_device *dev) unsigned long prealloc_size, gtt_size, mappable_size; int ret = 0; - prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT; + prealloc_size = dev_priv->mm.gtt->stolen_size; gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 745e46b0673f..b62ff5d6fa7e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -542,7 +542,7 @@ typedef struct drm_i915_private { struct { /** Bridge to intel-gtt-ko */ - struct intel_gtt *gtt; + const struct intel_gtt *gtt; /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; /** Memory allocator for GTT */ diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index d3c81946f613..020f8aab7e5b 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -2,17 +2,16 @@ #ifndef _DRM_INTEL_GTT_H #define _DRM_INTEL_GTT_H -struct intel_gtt { - /* Number of stolen gtt entries at the beginning. */ - unsigned int gtt_stolen_entries; + +const struct intel_gtt { + /* Size of memory reserved for graphics by the BIOS */ + unsigned int stolen_size; /* Total number of gtt entries. */ unsigned int gtt_total_entries; /* Part of the gtt that is mappable by the cpu, for those chips where * this is not the full gtt. */ unsigned int gtt_mappable_entries; -}; - -struct intel_gtt *intel_gtt_get(void); +} *intel_gtt_get(void); #endif -- cgit v1.2.3 From faa60c4174d943696b9478c5de6438c4f0fecba6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 13:50:14 +0000 Subject: drm/i915: Contract the magic IPS constants into a direct LUT ... and no need to perform a linear search for the index. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 304 +++++++++++++++++++--------------------- 1 file changed, 144 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 86b0e8052ec9..7084de7c4c55 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1396,152 +1396,12 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev) } } -struct v_table { - u8 vid; - unsigned long vd; /* in .1 mil */ - unsigned long vm; /* in .1 mil */ - u8 pvid; -}; - -static struct v_table v_table[] = { - { 0, 16125, 15000, 0x7f, }, - { 1, 16000, 14875, 0x7e, }, - { 2, 15875, 14750, 0x7d, }, - { 3, 15750, 14625, 0x7c, }, - { 4, 15625, 14500, 0x7b, }, - { 5, 15500, 14375, 0x7a, }, - { 6, 15375, 14250, 0x79, }, - { 7, 15250, 14125, 0x78, }, - { 8, 15125, 14000, 0x77, }, - { 9, 15000, 13875, 0x76, }, - { 10, 14875, 13750, 0x75, }, - { 11, 14750, 13625, 0x74, }, - { 12, 14625, 13500, 0x73, }, - { 13, 14500, 13375, 0x72, }, - { 14, 14375, 13250, 0x71, }, - { 15, 14250, 13125, 0x70, }, - { 16, 14125, 13000, 0x6f, }, - { 17, 14000, 12875, 0x6e, }, - { 18, 13875, 12750, 0x6d, }, - { 19, 13750, 12625, 0x6c, }, - { 20, 13625, 12500, 0x6b, }, - { 21, 13500, 12375, 0x6a, }, - { 22, 13375, 12250, 0x69, }, - { 23, 13250, 12125, 0x68, }, - { 24, 13125, 12000, 0x67, }, - { 25, 13000, 11875, 0x66, }, - { 26, 12875, 11750, 0x65, }, - { 27, 12750, 11625, 0x64, }, - { 28, 12625, 11500, 0x63, }, - { 29, 12500, 11375, 0x62, }, - { 30, 12375, 11250, 0x61, }, - { 31, 12250, 11125, 0x60, }, - { 32, 12125, 11000, 0x5f, }, - { 33, 12000, 10875, 0x5e, }, - { 34, 11875, 10750, 0x5d, }, - { 35, 11750, 10625, 0x5c, }, - { 36, 11625, 10500, 0x5b, }, - { 37, 11500, 10375, 0x5a, }, - { 38, 11375, 10250, 0x59, }, - { 39, 11250, 10125, 0x58, }, - { 40, 11125, 10000, 0x57, }, - { 41, 11000, 9875, 0x56, }, - { 42, 10875, 9750, 0x55, }, - { 43, 10750, 9625, 0x54, }, - { 44, 10625, 9500, 0x53, }, - { 45, 10500, 9375, 0x52, }, - { 46, 10375, 9250, 0x51, }, - { 47, 10250, 9125, 0x50, }, - { 48, 10125, 9000, 0x4f, }, - { 49, 10000, 8875, 0x4e, }, - { 50, 9875, 8750, 0x4d, }, - { 51, 9750, 8625, 0x4c, }, - { 52, 9625, 8500, 0x4b, }, - { 53, 9500, 8375, 0x4a, }, - { 54, 9375, 8250, 0x49, }, - { 55, 9250, 8125, 0x48, }, - { 56, 9125, 8000, 0x47, }, - { 57, 9000, 7875, 0x46, }, - { 58, 8875, 7750, 0x45, }, - { 59, 8750, 7625, 0x44, }, - { 60, 8625, 7500, 0x43, }, - { 61, 8500, 7375, 0x42, }, - { 62, 8375, 7250, 0x41, }, - { 63, 8250, 7125, 0x40, }, - { 64, 8125, 7000, 0x3f, }, - { 65, 8000, 6875, 0x3e, }, - { 66, 7875, 6750, 0x3d, }, - { 67, 7750, 6625, 0x3c, }, - { 68, 7625, 6500, 0x3b, }, - { 69, 7500, 6375, 0x3a, }, - { 70, 7375, 6250, 0x39, }, - { 71, 7250, 6125, 0x38, }, - { 72, 7125, 6000, 0x37, }, - { 73, 7000, 5875, 0x36, }, - { 74, 6875, 5750, 0x35, }, - { 75, 6750, 5625, 0x34, }, - { 76, 6625, 5500, 0x33, }, - { 77, 6500, 5375, 0x32, }, - { 78, 6375, 5250, 0x31, }, - { 79, 6250, 5125, 0x30, }, - { 80, 6125, 5000, 0x2f, }, - { 81, 6000, 4875, 0x2e, }, - { 82, 5875, 4750, 0x2d, }, - { 83, 5750, 4625, 0x2c, }, - { 84, 5625, 4500, 0x2b, }, - { 85, 5500, 4375, 0x2a, }, - { 86, 5375, 4250, 0x29, }, - { 87, 5250, 4125, 0x28, }, - { 88, 5125, 4000, 0x27, }, - { 89, 5000, 3875, 0x26, }, - { 90, 4875, 3750, 0x25, }, - { 91, 4750, 3625, 0x24, }, - { 92, 4625, 3500, 0x23, }, - { 93, 4500, 3375, 0x22, }, - { 94, 4375, 3250, 0x21, }, - { 95, 4250, 3125, 0x20, }, - { 96, 4125, 3000, 0x1f, }, - { 97, 4125, 3000, 0x1e, }, - { 98, 4125, 3000, 0x1d, }, - { 99, 4125, 3000, 0x1c, }, - { 100, 4125, 3000, 0x1b, }, - { 101, 4125, 3000, 0x1a, }, - { 102, 4125, 3000, 0x19, }, - { 103, 4125, 3000, 0x18, }, - { 104, 4125, 3000, 0x17, }, - { 105, 4125, 3000, 0x16, }, - { 106, 4125, 3000, 0x15, }, - { 107, 4125, 3000, 0x14, }, - { 108, 4125, 3000, 0x13, }, - { 109, 4125, 3000, 0x12, }, - { 110, 4125, 3000, 0x11, }, - { 111, 4125, 3000, 0x10, }, - { 112, 4125, 3000, 0x0f, }, - { 113, 4125, 3000, 0x0e, }, - { 114, 4125, 3000, 0x0d, }, - { 115, 4125, 3000, 0x0c, }, - { 116, 4125, 3000, 0x0b, }, - { 117, 4125, 3000, 0x0a, }, - { 118, 4125, 3000, 0x09, }, - { 119, 4125, 3000, 0x08, }, - { 120, 1125, 0, 0x07, }, - { 121, 1000, 0, 0x06, }, - { 122, 875, 0, 0x05, }, - { 123, 750, 0, 0x04, }, - { 124, 625, 0, 0x03, }, - { 125, 500, 0, 0x02, }, - { 126, 375, 0, 0x01, }, - { 127, 0, 0, 0x00, }, -}; - -struct cparams { - int i; - int t; - int m; - int c; -}; - -static struct cparams cparams[] = { +static const struct cparams { + u16 i; + u16 t; + u16 m; + u16 c; +} cparams[] = { { 1, 1333, 301, 28664 }, { 1, 1066, 294, 24460 }, { 1, 800, 294, 25192 }, @@ -1607,21 +1467,145 @@ unsigned long i915_mch_val(struct drm_i915_private *dev_priv) return ((m * x) / 127) - b; } -static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) +static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) { - unsigned long val = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(v_table); i++) { - if (v_table[i].pvid == pxvid) { - if (IS_MOBILE(dev_priv->dev)) - val = v_table[i].vm; - else - val = v_table[i].vd; - } - } - - return val; + static const struct v_table { + u16 vd; /* in .1 mil */ + u16 vm; /* in .1 mil */ + } v_table[] = { + { 0, 0, }, + { 375, 0, }, + { 500, 0, }, + { 625, 0, }, + { 750, 0, }, + { 875, 0, }, + { 1000, 0, }, + { 1125, 0, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4125, 3000, }, + { 4250, 3125, }, + { 4375, 3250, }, + { 4500, 3375, }, + { 4625, 3500, }, + { 4750, 3625, }, + { 4875, 3750, }, + { 5000, 3875, }, + { 5125, 4000, }, + { 5250, 4125, }, + { 5375, 4250, }, + { 5500, 4375, }, + { 5625, 4500, }, + { 5750, 4625, }, + { 5875, 4750, }, + { 6000, 4875, }, + { 6125, 5000, }, + { 6250, 5125, }, + { 6375, 5250, }, + { 6500, 5375, }, + { 6625, 5500, }, + { 6750, 5625, }, + { 6875, 5750, }, + { 7000, 5875, }, + { 7125, 6000, }, + { 7250, 6125, }, + { 7375, 6250, }, + { 7500, 6375, }, + { 7625, 6500, }, + { 7750, 6625, }, + { 7875, 6750, }, + { 8000, 6875, }, + { 8125, 7000, }, + { 8250, 7125, }, + { 8375, 7250, }, + { 8500, 7375, }, + { 8625, 7500, }, + { 8750, 7625, }, + { 8875, 7750, }, + { 9000, 7875, }, + { 9125, 8000, }, + { 9250, 8125, }, + { 9375, 8250, }, + { 9500, 8375, }, + { 9625, 8500, }, + { 9750, 8625, }, + { 9875, 8750, }, + { 10000, 8875, }, + { 10125, 9000, }, + { 10250, 9125, }, + { 10375, 9250, }, + { 10500, 9375, }, + { 10625, 9500, }, + { 10750, 9625, }, + { 10875, 9750, }, + { 11000, 9875, }, + { 11125, 10000, }, + { 11250, 10125, }, + { 11375, 10250, }, + { 11500, 10375, }, + { 11625, 10500, }, + { 11750, 10625, }, + { 11875, 10750, }, + { 12000, 10875, }, + { 12125, 11000, }, + { 12250, 11125, }, + { 12375, 11250, }, + { 12500, 11375, }, + { 12625, 11500, }, + { 12750, 11625, }, + { 12875, 11750, }, + { 13000, 11875, }, + { 13125, 12000, }, + { 13250, 12125, }, + { 13375, 12250, }, + { 13500, 12375, }, + { 13625, 12500, }, + { 13750, 12625, }, + { 13875, 12750, }, + { 14000, 12875, }, + { 14125, 13000, }, + { 14250, 13125, }, + { 14375, 13250, }, + { 14500, 13375, }, + { 14625, 13500, }, + { 14750, 13625, }, + { 14875, 13750, }, + { 15000, 13875, }, + { 15125, 14000, }, + { 15250, 14125, }, + { 15375, 14250, }, + { 15500, 14375, }, + { 15625, 14500, }, + { 15750, 14625, }, + { 15875, 14750, }, + { 16000, 14875, }, + { 16125, 15000, }, + }; + if (dev_priv->info->is_mobile) + return v_table[pxvid].vm; + else + return v_table[pxvid].vd; } void i915_update_gfx_val(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From b47cf66f315a258c458ed4345c443dba396fb787 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Nov 2010 18:41:50 +0100 Subject: intel-gtt: drop dcache support for i830 and later i830_check_flags already disallows it, so no need to implement it in the write_entry function. Seems to be a remnant from i810 support. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index d2733e526a68..8a30a16c5706 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -896,14 +896,8 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, { u32 pte_flags = I810_PTE_VALID; - switch (flags) { - case AGP_DCACHE_MEMORY: - pte_flags |= I810_PTE_LOCAL; - break; - case AGP_USER_CACHED_MEMORY: + if (flags == AGP_USER_CACHED_MEMORY) pte_flags |= I830_PTE_SYSTEM_CACHED; - break; - } writel(addr | pte_flags, intel_private.gtt + entry); } -- cgit v1.2.3 From 24a6b387af7cd5d1e0e5d15b15104644a5105de7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Nov 2010 20:14:15 +0100 Subject: intel-gtt: kill unneeded sandybridge memory types Used for the now dead agp type_to_mask stuff. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 8a30a16c5706..2470040023d3 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -59,12 +59,6 @@ static struct gatt_mask intel_i810_masks[] = .type = INTEL_AGP_CACHED_MEMORY} }; -#define INTEL_AGP_UNCACHED_MEMORY 0 -#define INTEL_AGP_CACHED_MEMORY_LLC 1 -#define INTEL_AGP_CACHED_MEMORY_LLC_GFDT 2 -#define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 -#define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 - struct intel_gtt_driver { unsigned int gen : 8; unsigned int is_g33 : 1; -- cgit v1.2.3 From 625dd9d331d8a1ce5ee4e9924a22f3e55b7ac615 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Nov 2010 20:07:57 +0100 Subject: intel-gtt: switch i81x to the write_entry helpers Initialization is still done with the old code with a few added things sprinkled in to make the intel_fake_agp helper functions work. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 152 +++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 2470040023d3..9d17a6d51640 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -101,6 +101,9 @@ static struct _intel_private { dma_addr_t scratch_page_dma; } intel_private; +static int intel_fake_agp_insert_entries(struct agp_memory *mem, + off_t pg_start, int type); + #define INTEL_GTT_GEN intel_private.driver->gen #define IS_G33 intel_private.driver->is_g33 #define IS_PINEVIEW intel_private.driver->is_pineview @@ -176,10 +179,12 @@ static int intel_i810_fetch_size(void) if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { agp_bridge->current_size = (void *) (values + 1); agp_bridge->aperture_size_idx = 1; + intel_private.base.gtt_total_entries = KB(32) / 4; return values[1].size; } else { agp_bridge->current_size = (void *) (values); agp_bridge->aperture_size_idx = 0; + intel_private.base.gtt_total_entries = KB(64) / 4; return values[0].size; } @@ -206,6 +211,9 @@ static int intel_i810_configure(void) } } + intel_private.gtt = intel_private.registers + I810_PTE_BASE; + intel_private.scratch_page_dma = agp_bridge->scratch_page & PAGE_MASK; + if ((readl(intel_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ @@ -273,79 +281,27 @@ static void i8xx_destroy_pages(struct page *page) static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { - int i, j, num_entries; - void *temp; - int ret = -EINVAL; - int mask_type; - - if (mem->page_count == 0) - goto out; - - temp = agp_bridge->current_size; - num_entries = A_SIZE_FIX(temp)->num_entries; - - if ((pg_start + mem->page_count) > num_entries) - goto out_err; - - - for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) { - ret = -EBUSY; - goto out_err; - } - } - - if (type != mem->type) - goto out_err; + int i; - mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + if (type == AGP_DCACHE_MEMORY) { + if ((pg_start + mem->page_count) + > intel_private.num_dcache_entries) + return -EINVAL; - switch (mask_type) { - case AGP_DCACHE_MEMORY: if (!mem->is_flushed) global_cache_flush(); + for (i = pg_start; i < (pg_start + mem->page_count); i++) { - writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, - intel_private.registers+I810_PTE_BASE+(i*4)); - } - readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); - break; - case AGP_PHYS_MEMORY: - case AGP_NORMAL_MEMORY: - if (!mem->is_flushed) - global_cache_flush(); - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - page_to_phys(mem->pages[i]), mask_type), - intel_private.registers+I810_PTE_BASE+(j*4)); + dma_addr_t addr = i << PAGE_SHIFT; + intel_private.driver->write_entry(addr, + i, type); } - readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); - break; - default: - goto out_err; - } - -out: - ret = 0; -out_err: - mem->is_flushed = true; - return ret; -} + readl(intel_private.gtt+i-1); -static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, - int type) -{ - int i; - - if (mem->page_count == 0) return 0; - - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); - return 0; + return intel_fake_agp_insert_entries(mem, pg_start, type); } /* @@ -390,29 +346,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) return new; } -static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) -{ - struct agp_memory *new; - - if (type == AGP_DCACHE_MEMORY) { - if (pg_count != intel_private.num_dcache_entries) - return NULL; - - new = agp_create_memory(1); - if (new == NULL) - return NULL; - - new->type = AGP_DCACHE_MEMORY; - new->page_count = pg_count; - new->num_scratch_pages = 0; - agp_free_page_array(new); - return new; - } - if (type == AGP_PHYS_MEMORY) - return alloc_agpphysmem_i8xx(pg_count, type); - return NULL; -} - static void intel_i810_free_by_type(struct agp_memory *curr) { agp_free_key(curr->key); @@ -463,6 +396,23 @@ static int intel_gtt_setup_scratch_page(void) return 0; } +static void i810_write_entry(dma_addr_t addr, unsigned int entry, + unsigned int flags) +{ + u32 pte_flags = I810_PTE_VALID; + + switch (flags) { + case AGP_DCACHE_MEMORY: + pte_flags |= I810_PTE_LOCAL; + break; + case AGP_USER_CACHED_MEMORY: + pte_flags |= I830_PTE_SYSTEM_CACHED; + break; + } + + writel(addr | pte_flags, intel_private.gtt + entry); +} + static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ @@ -760,7 +710,7 @@ static void intel_gtt_cleanup(void) iounmap(intel_private.gtt); iounmap(intel_private.registers); - + intel_gtt_teardown_scratch_page(); } @@ -889,7 +839,7 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, unsigned int flags) { u32 pte_flags = I810_PTE_VALID; - + if (flags == AGP_USER_CACHED_MEMORY) pte_flags |= I830_PTE_SYSTEM_CACHED; @@ -1106,6 +1056,22 @@ static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, int type) { + struct agp_memory *new; + + if (type == AGP_DCACHE_MEMORY && INTEL_GTT_GEN == 1) { + if (pg_count != intel_private.num_dcache_entries) + return NULL; + + new = agp_create_memory(1); + if (new == NULL) + return NULL; + + new->type = AGP_DCACHE_MEMORY; + new->page_count = pg_count; + new->num_scratch_pages = 0; + agp_free_page_array(new); + return new; + } if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); /* always return NULL for other allocation types for now */ @@ -1316,8 +1282,8 @@ static const struct agp_bridge_driver intel_810_driver = { .create_gatt_table = agp_generic_create_gatt_table, .free_gatt_table = agp_generic_free_gatt_table, .insert_memory = intel_i810_insert_entries, - .remove_memory = intel_i810_remove_entries, - .alloc_by_type = intel_i810_alloc_by_type, + .remove_memory = intel_fake_agp_remove_entries, + .alloc_by_type = intel_fake_agp_alloc_by_type, .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, @@ -1352,6 +1318,8 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { static const struct intel_gtt_driver i81x_gtt_driver = { .gen = 1, .dma_mask_size = 32, + .check_flags = i830_check_flags, + .write_entry = i810_write_entry, }; static const struct intel_gtt_driver i8xx_gtt_driver = { .gen = 2, @@ -1369,7 +1337,7 @@ static const struct intel_gtt_driver i915_gtt_driver = { .setup = i9xx_setup, .cleanup = i9xx_cleanup, /* i945 is the last gpu to need phys mem (for overlay and cursors). */ - .write_entry = i830_write_entry, + .write_entry = i830_write_entry, .dma_mask_size = 32, .check_flags = i830_check_flags, .chipset_flush = i9xx_chipset_flush, @@ -1557,7 +1525,7 @@ int intel_gmch_probe(struct pci_dev *pdev, if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { bridge->driver = intel_gtt_chipsets[i].gmch_driver; - intel_private.driver = + intel_private.driver = intel_gtt_chipsets[i].gtt_driver; break; } -- cgit v1.2.3 From 820647b97a9cbdd976c7177f1b6047fc1f6dd5c0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 13:30:14 +0100 Subject: intel-gtt: switch i81x to the common initialization helpers Still a separate agp_bridge_driver because of the i81x-only dedicated vram support. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 198 ++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 9d17a6d51640..4b79a7b47522 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -39,26 +39,10 @@ #define USE_PCI_DMA_API 0 #endif -static const struct aper_size_info_fixed intel_i810_sizes[] = -{ - {64, 16384, 4}, - /* The 32M mode still requires a 64k gatt */ - {32, 8192, 4} -}; - #define AGP_DCACHE_MEMORY 1 #define AGP_PHYS_MEMORY 2 #define INTEL_AGP_CACHED_MEMORY 3 -static struct gatt_mask intel_i810_masks[] = -{ - {.mask = I810_PTE_VALID, .type = 0}, - {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY}, - {.mask = I810_PTE_VALID, .type = 0}, - {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED, - .type = INTEL_AGP_CACHED_MEMORY} -}; - struct intel_gtt_driver { unsigned int gen : 8; unsigned int is_g33 : 1; @@ -94,6 +78,7 @@ static struct _intel_private { void __iomem *i9xx_flush_page; void *i8xx_flush_page; }; + char *i81x_gtt_table; struct page *i8xx_page; struct resource ifp_resource; int resource_valid; @@ -163,86 +148,6 @@ static void intel_agp_unmap_memory(struct agp_memory *mem) intel_agp_free_sglist(mem); } -static int intel_i810_fetch_size(void) -{ - u32 smram_miscc; - struct aper_size_info_fixed *values; - - pci_read_config_dword(intel_private.bridge_dev, - I810_SMRAM_MISCC, &smram_miscc); - values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); - - if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n"); - return 0; - } - if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { - agp_bridge->current_size = (void *) (values + 1); - agp_bridge->aperture_size_idx = 1; - intel_private.base.gtt_total_entries = KB(32) / 4; - return values[1].size; - } else { - agp_bridge->current_size = (void *) (values); - agp_bridge->aperture_size_idx = 0; - intel_private.base.gtt_total_entries = KB(64) / 4; - return values[0].size; - } - - return 0; -} - -static int intel_i810_configure(void) -{ - struct aper_size_info_fixed *current_size; - u32 temp; - int i; - - current_size = A_SIZE_FIX(agp_bridge->current_size); - - if (!intel_private.registers) { - pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); - temp &= 0xfff80000; - - intel_private.registers = ioremap(temp, 128 * 4096); - if (!intel_private.registers) { - dev_err(&intel_private.pcidev->dev, - "can't remap memory\n"); - return -ENOMEM; - } - } - - intel_private.gtt = intel_private.registers + I810_PTE_BASE; - intel_private.scratch_page_dma = agp_bridge->scratch_page & PAGE_MASK; - - if ((readl(intel_private.registers+I810_DRAM_CTL) - & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { - /* This will need to be dynamically assigned */ - dev_info(&intel_private.pcidev->dev, - "detected 4MB dedicated video ram\n"); - intel_private.num_dcache_entries = 1024; - } - pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); - agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); - readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ - - if (agp_bridge->driver->needs_scratch_page) { - for (i = 0; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); - } - readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */ - } - global_cache_flush(); - return 0; -} - -static void intel_i810_cleanup(void) -{ - writel(0, intel_private.registers+I810_PGETBL_CTL); - readl(intel_private.registers); /* PCI Posting. */ - iounmap(intel_private.registers); -} - static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) { return; @@ -278,6 +183,46 @@ static void i8xx_destroy_pages(struct page *page) atomic_dec(&agp_bridge->current_memory_agp); } +#define I810_GTT_ORDER 4 +static int i810_setup(void) +{ + u32 reg_addr; + char *gtt_table; + + /* i81x does not preallocate the gtt. It's always 64kb in size. */ + gtt_table = alloc_gatt_pages(I810_GTT_ORDER); + if (gtt_table == NULL) + return -ENOMEM; + intel_private.i81x_gtt_table = gtt_table; + + pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); + reg_addr &= 0xfff80000; + + intel_private.registers = ioremap(reg_addr, KB(64)); + if (!intel_private.registers) + return -ENOMEM; + + writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED, + intel_private.registers+I810_PGETBL_CTL); + + intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; + + if ((readl(intel_private.registers+I810_DRAM_CTL) + & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { + dev_info(&intel_private.pcidev->dev, + "detected 4MB dedicated video ram\n"); + intel_private.num_dcache_entries = 1024; + } + + return 0; +} + +static void i810_cleanup(void) +{ + writel(0, intel_private.registers+I810_PGETBL_CTL); + free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); +} + static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -363,13 +308,6 @@ static void intel_i810_free_by_type(struct agp_memory *curr) kfree(curr); } -static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, - dma_addr_t addr, int type) -{ - /* Type checking must be done elsewhere */ - return addr | bridge->driver->masks[type].mask; -} - static int intel_gtt_setup_scratch_page(void) { struct page *page; @@ -414,9 +352,9 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry, } static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { + {32, 8192, 3}, + {64, 16384, 4}, {128, 32768, 5}, - /* The 64M mode still requires a 128k gatt */ - {64, 16384, 5}, {256, 65536, 6}, {512, 131072, 7}, }; @@ -429,6 +367,9 @@ static unsigned int intel_gtt_stolen_size(void) static const int ddt[4] = { 0, 16, 32, 64 }; unsigned int stolen_size = 0; + if (INTEL_GTT_GEN == 1) + return 0; /* no stolen mem on i81x */ + pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); @@ -677,7 +618,18 @@ static unsigned int intel_gtt_mappable_entries(void) { unsigned int aperture_size; - if (INTEL_GTT_GEN == 2) { + if (INTEL_GTT_GEN == 1) { + u32 smram_miscc; + + pci_read_config_dword(intel_private.bridge_dev, + I810_SMRAM_MISCC, &smram_miscc); + + if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) + == I810_GFX_MEM_WIN_32M) + aperture_size = MB(32); + else + aperture_size = MB(64); + } else if (INTEL_GTT_GEN == 2) { u16 gmch_ctrl; pci_read_config_word(intel_private.bridge_dev, @@ -751,14 +703,7 @@ static int intel_gtt_init(void) global_cache_flush(); /* FIXME: ? */ - /* we have to call this as early as possible after the MMIO base address is known */ intel_private.base.stolen_size = intel_gtt_stolen_size(); - if (intel_private.base.stolen_size == 0) { - intel_private.driver->cleanup(); - iounmap(intel_private.registers); - iounmap(intel_private.gtt); - return -ENOMEM; - } ret = intel_gtt_setup_scratch_page(); if (ret != 0) { @@ -851,7 +796,7 @@ static bool intel_enable_gtt(void) u32 gma_addr; u8 __iomem *reg; - if (INTEL_GTT_GEN == 2) + if (INTEL_GTT_GEN <= 2) pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &gma_addr); else @@ -1268,19 +1213,16 @@ static int i9xx_setup(void) static const struct agp_bridge_driver intel_810_driver = { .owner = THIS_MODULE, - .aperture_sizes = intel_i810_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 2, - .needs_scratch_page = true, - .configure = intel_i810_configure, - .fetch_size = intel_i810_fetch_size, - .cleanup = intel_i810_cleanup, - .mask_memory = intel_i810_mask_memory, - .masks = intel_i810_masks, + .aperture_sizes = intel_fake_agp_sizes, + .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), + .configure = intel_fake_agp_configure, + .fetch_size = intel_fake_agp_fetch_size, + .cleanup = intel_gtt_cleanup, .agp_enable = intel_fake_agp_enable, .cache_flush = global_cache_flush, - .create_gatt_table = agp_generic_create_gatt_table, - .free_gatt_table = agp_generic_free_gatt_table, + .create_gatt_table = intel_fake_agp_create_gatt_table, + .free_gatt_table = intel_fake_agp_free_gatt_table, .insert_memory = intel_i810_insert_entries, .remove_memory = intel_fake_agp_remove_entries, .alloc_by_type = intel_fake_agp_alloc_by_type, @@ -1289,7 +1231,6 @@ static const struct agp_bridge_driver intel_810_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static const struct agp_bridge_driver intel_fake_agp_driver = { @@ -1317,7 +1258,10 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { static const struct intel_gtt_driver i81x_gtt_driver = { .gen = 1, + .has_pgtbl_enable = 1, .dma_mask_size = 32, + .setup = i810_setup, + .cleanup = i810_cleanup, .check_flags = i830_check_flags, .write_entry = i810_write_entry, }; @@ -1549,8 +1493,8 @@ int intel_gmch_probe(struct pci_dev *pdev, pci_set_consistent_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)); - if (bridge->driver == &intel_810_driver) - return 1; + /*if (bridge->driver == &intel_810_driver) + return 1;*/ if (intel_gtt_init() != 0) return 0; -- cgit v1.2.3 From ff26860fb53f2dcfaaaf1bf017b09dbdfddff5ee Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 15:43:35 +0100 Subject: intel-gtt: fold i81x-only dcache support into the generic driver Now the intel-gtt.c rewrite is complete! Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 150 ++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 4b79a7b47522..72267c801637 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -86,9 +86,6 @@ static struct _intel_private { dma_addr_t scratch_page_dma; } intel_private; -static int intel_fake_agp_insert_entries(struct agp_memory *mem, - off_t pg_start, int type); - #define INTEL_GTT_GEN intel_private.driver->gen #define IS_G33 intel_private.driver->is_g33 #define IS_PINEVIEW intel_private.driver->is_pineview @@ -223,30 +220,26 @@ static void i810_cleanup(void) free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); } -static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, - int type) +static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, + int type) { int i; - if (type == AGP_DCACHE_MEMORY) { - if ((pg_start + mem->page_count) - > intel_private.num_dcache_entries) - return -EINVAL; - - if (!mem->is_flushed) - global_cache_flush(); + if ((pg_start + mem->page_count) + > intel_private.num_dcache_entries) + return -EINVAL; - for (i = pg_start; i < (pg_start + mem->page_count); i++) { - dma_addr_t addr = i << PAGE_SHIFT; - intel_private.driver->write_entry(addr, - i, type); - } - readl(intel_private.gtt+i-1); + if (!mem->is_flushed) + global_cache_flush(); - return 0; + for (i = pg_start; i < (pg_start + mem->page_count); i++) { + dma_addr_t addr = i << PAGE_SHIFT; + intel_private.driver->write_entry(addr, + i, type); } + readl(intel_private.gtt+i-1); - return intel_fake_agp_insert_entries(mem, pg_start, type); + return 0; } /* @@ -935,6 +928,9 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, int i, j; int ret = -EINVAL; + if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) + return i810_insert_dcache_entries(mem, pg_start, type); + if (mem->page_count == 0) goto out; @@ -1211,28 +1207,6 @@ static int i9xx_setup(void) return 0; } -static const struct agp_bridge_driver intel_810_driver = { - .owner = THIS_MODULE, - .size_type = FIXED_APER_SIZE, - .aperture_sizes = intel_fake_agp_sizes, - .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), - .configure = intel_fake_agp_configure, - .fetch_size = intel_fake_agp_fetch_size, - .cleanup = intel_gtt_cleanup, - .agp_enable = intel_fake_agp_enable, - .cache_flush = global_cache_flush, - .create_gatt_table = intel_fake_agp_create_gatt_table, - .free_gatt_table = intel_fake_agp_free_gatt_table, - .insert_memory = intel_i810_insert_entries, - .remove_memory = intel_fake_agp_remove_entries, - .alloc_by_type = intel_fake_agp_alloc_by_type, - .free_by_type = intel_i810_free_by_type, - .agp_alloc_page = agp_generic_alloc_page, - .agp_alloc_pages = agp_generic_alloc_pages, - .agp_destroy_page = agp_generic_destroy_page, - .agp_destroy_pages = agp_generic_destroy_pages, -}; - static const struct agp_bridge_driver intel_fake_agp_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, @@ -1352,93 +1326,92 @@ static const struct intel_gtt_driver sandybridge_gtt_driver = { static const struct intel_gtt_driver_description { unsigned int gmch_chip_id; char *name; - const struct agp_bridge_driver *gmch_driver; const struct intel_gtt_driver *gtt_driver; } intel_gtt_chipsets[] = { - { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver, + { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &i81x_gtt_driver}, - { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver, + { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &i81x_gtt_driver}, - { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver, + { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &i81x_gtt_driver}, - { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, + { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &i81x_gtt_driver}, { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", - &intel_fake_agp_driver, &i8xx_gtt_driver}, + &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", - &intel_fake_agp_driver, &i8xx_gtt_driver}, + &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82854_IG, "854", - &intel_fake_agp_driver, &i8xx_gtt_driver}, + &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", - &intel_fake_agp_driver, &i8xx_gtt_driver}, + &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82865_IG, "865", - &intel_fake_agp_driver, &i8xx_gtt_driver}, + &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", - &intel_fake_agp_driver, &i915_gtt_driver }, + &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", - &intel_fake_agp_driver, &i915_gtt_driver }, + &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", - &intel_fake_agp_driver, &i915_gtt_driver }, + &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", - &intel_fake_agp_driver, &i915_gtt_driver }, + &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", - &intel_fake_agp_driver, &i915_gtt_driver }, + &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", - &intel_fake_agp_driver, &i915_gtt_driver }, + &i915_gtt_driver }, { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", - &intel_fake_agp_driver, &i965_gtt_driver }, + &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", - &intel_fake_agp_driver, &i965_gtt_driver }, + &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", - &intel_fake_agp_driver, &i965_gtt_driver }, + &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", - &intel_fake_agp_driver, &i965_gtt_driver }, + &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", - &intel_fake_agp_driver, &i965_gtt_driver }, + &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", - &intel_fake_agp_driver, &i965_gtt_driver }, + &i965_gtt_driver }, { PCI_DEVICE_ID_INTEL_G33_IG, "G33", - &intel_fake_agp_driver, &g33_gtt_driver }, + &g33_gtt_driver }, { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", - &intel_fake_agp_driver, &g33_gtt_driver }, + &g33_gtt_driver }, { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", - &intel_fake_agp_driver, &g33_gtt_driver }, + &g33_gtt_driver }, { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", - &intel_fake_agp_driver, &pineview_gtt_driver }, + &pineview_gtt_driver }, { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", - &intel_fake_agp_driver, &pineview_gtt_driver }, + &pineview_gtt_driver }, { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_B43_IG, "B43", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_G41_IG, "G41", - &intel_fake_agp_driver, &g4x_gtt_driver }, + &g4x_gtt_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, - "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, + "HD Graphics", &ironlake_gtt_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, - "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, + "HD Graphics", &ironlake_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, - "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, + "Sandybridge", &sandybridge_gtt_driver }, { 0, NULL, NULL } }; @@ -1463,21 +1436,20 @@ int intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge) { int i, mask; - bridge->driver = NULL; + intel_private.driver = NULL; for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { - bridge->driver = - intel_gtt_chipsets[i].gmch_driver; intel_private.driver = intel_gtt_chipsets[i].gtt_driver; break; } } - if (!bridge->driver) + if (!intel_private.driver) return 0; + bridge->driver = &intel_fake_agp_driver; bridge->dev_private_data = &intel_private; bridge->dev = pdev; -- cgit v1.2.3 From 23ed992a5ebe6964ebe312b54142fbc5e8185cdc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 18:04:52 +0100 Subject: drm/i915|intel-gtt: consolidate intel-gtt.h headers ... and a few other defines. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 5 ----- drivers/gpu/drm/i915/i915_gem.c | 1 - include/drm/intel-gtt.h | 12 ++++++++++++ include/linux/intel-gtt.h | 20 -------------------- 4 files changed, 12 insertions(+), 26 deletions(-) delete mode 100644 include/linux/intel-gtt.h (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 72267c801637..291ac5113576 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -24,7 +24,6 @@ #include #include "agp.h" #include "intel-agp.h" -#include #include /* @@ -39,10 +38,6 @@ #define USE_PCI_DMA_API 0 #endif -#define AGP_DCACHE_MEMORY 1 -#define AGP_PHYS_MEMORY 2 -#define INTEL_AGP_CACHED_MEMORY 3 - struct intel_gtt_driver { unsigned int gen : 8; unsigned int is_g33 : 1; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bf05ac414b1f..68492357658c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -34,7 +34,6 @@ #include #include #include -#include struct change_domains { uint32_t invalidate_domains; diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 020f8aab7e5b..9f91cbe35157 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -13,5 +13,17 @@ const struct intel_gtt { unsigned int gtt_mappable_entries; } *intel_gtt_get(void); + +/* Special gtt memory types */ +#define AGP_DCACHE_MEMORY 1 +#define AGP_PHYS_MEMORY 2 + +/* New caching attributes for gen6/sandybridge */ +#define AGP_USER_CACHED_MEMORY_LLC_MLC (AGP_USER_TYPES + 2) +#define AGP_USER_UNCACHED_MEMORY (AGP_USER_TYPES + 4) + +/* flag for GFDT type */ +#define AGP_USER_CACHED_MEMORY_GFDT (1 << 3) + #endif diff --git a/include/linux/intel-gtt.h b/include/linux/intel-gtt.h deleted file mode 100644 index 1d19ab2afa39..000000000000 --- a/include/linux/intel-gtt.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Common Intel AGPGART and GTT definitions. - */ -#ifndef _INTEL_GTT_H -#define _INTEL_GTT_H - -#include - -/* This is for Intel only GTT controls. - * - * Sandybridge: AGP_USER_CACHED_MEMORY default to LLC only - */ - -#define AGP_USER_CACHED_MEMORY_LLC_MLC (AGP_USER_TYPES + 2) -#define AGP_USER_UNCACHED_MEMORY (AGP_USER_TYPES + 4) - -/* flag for GFDT type */ -#define AGP_USER_CACHED_MEMORY_GFDT (1 << 3) - -#endif -- cgit v1.2.3 From 40ce6575102b23e432932b5ce41c44bf7cc5023b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 18:12:18 +0100 Subject: drm/i915/gtt: call chipset flush directly Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 7 +++++++ drivers/gpu/drm/i915/i915_gem.c | 9 ++++----- include/drm/intel-gtt.h | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 291ac5113576..8e2e208c925b 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1476,6 +1476,13 @@ const struct intel_gtt *intel_gtt_get(void) } EXPORT_SYMBOL(intel_gtt_get); +void intel_gtt_chipset_flush(void) +{ + if (intel_private.driver->chipset_flush) + intel_private.driver->chipset_flush(); +} +EXPORT_SYMBOL(intel_gtt_chipset_flush); + void intel_gmch_remove(struct pci_dev *pdev) { if (intel_private.pcidev) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 68492357658c..b663d2da1db3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2192,7 +2192,7 @@ i915_gem_flush(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); + intel_gtt_chipset_flush(); if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { if (flush_rings & RING_RENDER) @@ -2920,14 +2920,13 @@ i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj) static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) { - struct drm_device *dev = obj->dev; uint32_t old_write_domain; if (obj->write_domain != I915_GEM_DOMAIN_CPU) return; i915_gem_clflush_object(obj); - drm_agp_chipset_flush(dev); + intel_gtt_chipset_flush(); old_write_domain = obj->write_domain; obj->write_domain = 0; @@ -5069,7 +5068,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, page_cache_release(page); } } - drm_agp_chipset_flush(dev); + intel_gtt_chipset_flush(); obj_priv->phys_obj->cur_obj = NULL; obj_priv->phys_obj = NULL; @@ -5161,7 +5160,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, return -EFAULT; } - drm_agp_chipset_flush(dev); + intel_gtt_chipset_flush(); return 0; } diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 9f91cbe35157..c35817a11690 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -13,6 +13,7 @@ const struct intel_gtt { unsigned int gtt_mappable_entries; } *intel_gtt_get(void); +void intel_gtt_chipset_flush(void); /* Special gtt memory types */ #define AGP_DCACHE_MEMORY 1 @@ -26,4 +27,3 @@ const struct intel_gtt { #define AGP_USER_CACHED_MEMORY_GFDT (1 << 3) #endif - -- cgit v1.2.3 From 4af72e2865a23ac090884a421bd1a8b19e247a22 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 18:13:43 +0100 Subject: drm: kill drm_agp_chipset_flush No longer used. Cc: Dave Airlie Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/drm_agpsupport.c | 6 ------ include/drm/drmP.h | 1 - 2 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 252fdb98b73a..0cb2ba50af53 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -466,10 +466,4 @@ drm_agp_bind_pages(struct drm_device *dev, } EXPORT_SYMBOL(drm_agp_bind_pages); -void drm_agp_chipset_flush(struct drm_device *dev) -{ - agp_flush_chipset(dev->agp->bridge); -} -EXPORT_SYMBOL(drm_agp_chipset_flush); - #endif /* __OS_HAS_AGP */ diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d4bc0f5cab8f..628f76772d22 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1319,7 +1319,6 @@ extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void drm_agp_chipset_flush(struct drm_device *dev); /* Stub support (drm_stub.h) */ extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From f050a8abbda0efcd597c6b1825e3b9ce4d613383 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 18:40:56 +0100 Subject: agp: kill agp_flush_chipset and corresponding ioctl The intel drm calls the chipset functions now directly. Userspace never called the corresponding ioctl, hence it can be killed, too. Cc: Dave Airlie Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/agp.h | 1 - drivers/char/agp/compat_ioctl.c | 1 - drivers/char/agp/compat_ioctl.h | 1 - drivers/char/agp/frontend.c | 8 -------- drivers/char/agp/generic.c | 7 ------- drivers/char/agp/intel-gtt.c | 6 ------ include/linux/agp_backend.h | 1 - 7 files changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 5259065f3c79..3e67ddde9e16 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -120,7 +120,6 @@ struct agp_bridge_driver { void (*agp_destroy_page)(struct page *, int flags); void (*agp_destroy_pages)(struct agp_memory *); int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); - void (*chipset_flush)(struct agp_bridge_data *); }; struct agp_bridge_data { diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c index 9d2c97a69cdd..a48e05b31593 100644 --- a/drivers/char/agp/compat_ioctl.c +++ b/drivers/char/agp/compat_ioctl.c @@ -276,7 +276,6 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case AGPIOC_CHIPSET_FLUSH32: - ret_val = agpioc_chipset_flush_wrap(curr_priv); break; } diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h index 0c9678ac0371..f30e0fd97963 100644 --- a/drivers/char/agp/compat_ioctl.h +++ b/drivers/char/agp/compat_ioctl.h @@ -102,6 +102,5 @@ void agp_free_memory_wrap(struct agp_memory *memory); struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type); struct agp_memory *agp_find_mem_by_key(int key); struct agp_client *agp_find_client_by_pid(pid_t id); -int agpioc_chipset_flush_wrap(struct agp_file_private *priv); #endif /* _AGP_COMPAT_H */ diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 3cb4539a98b2..2e044338753c 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -957,13 +957,6 @@ static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) return agp_unbind_memory(memory); } -int agpioc_chipset_flush_wrap(struct agp_file_private *priv) -{ - DBG(""); - agp_flush_chipset(agp_bridge); - return 0; -} - static long agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1039,7 +1032,6 @@ static long agp_ioctl(struct file *file, break; case AGPIOC_CHIPSET_FLUSH: - ret_val = agpioc_chipset_flush_wrap(curr_priv); break; } diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 4956f1c8f9d5..78bc8de0f234 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -81,13 +81,6 @@ static int agp_get_key(void) return -1; } -void agp_flush_chipset(struct agp_bridge_data *bridge) -{ - if (bridge->driver->chipset_flush) - bridge->driver->chipset_flush(bridge); -} -EXPORT_SYMBOL(agp_flush_chipset); - /* * Use kmalloc if possible for the page list. Otherwise fall back to * vmalloc. This speeds things up and also saves memory for small AGP diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 8e2e208c925b..1603e4f8ae73 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -984,11 +984,6 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, return 0; } -static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) -{ - intel_private.driver->chipset_flush(); -} - static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, int type) { @@ -1222,7 +1217,6 @@ static const struct agp_bridge_driver intel_fake_agp_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .chipset_flush = intel_fake_agp_chipset_flush, }; static const struct intel_gtt_driver i81x_gtt_driver = { diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index 09ea4a1e9505..a479b4885d25 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -106,6 +106,5 @@ extern int agp_rebind_memory(void); extern void agp_enable(struct agp_bridge_data *, u32); extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *); extern void agp_backend_release(struct agp_bridge_data *); -extern void agp_flush_chipset(struct agp_bridge_data *); #endif /* _AGP_BACKEND_H */ -- cgit v1.2.3 From 93a37f20eabeea4039130527b07453038c07f471 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 20:24:53 +0100 Subject: drm/i915: track objects in the gtt This is required to restore gtt mappings on resume when agp is gone. The right way to do this would be to make sturct drm_mm_node embeddable and use the allocation list maintained by the drm memory manager. But that's a bigger project. Getting rid of the per bo agp_mem will save more memory than this wastes, anyway. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_gem.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b62ff5d6fa7e..67ec046aeb90 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -547,6 +547,9 @@ typedef struct drm_i915_private { struct drm_mm stolen; /** Memory allocator for GTT */ struct drm_mm gtt_space; + /** List of all objects in gtt_space. Used to restore gtt + * mappings on resume */ + struct list_head gtt_list; /** End of mappable part of GTT */ unsigned long gtt_mappable_end; @@ -714,6 +717,7 @@ struct drm_i915_gem_object { /** Current space allocated to this object in the GTT, if any. */ struct drm_mm_node *gtt_space; + struct list_head gtt_list; /** This object's place on the active/flushing/inactive lists */ struct list_head ring_list; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b663d2da1db3..07e1b25f4a8a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -95,6 +95,7 @@ static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv, min_t(size_t, obj->gtt_space->size, dev_priv->mm.gtt_mappable_end - obj->gtt_offset); } + list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list); } static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, @@ -107,6 +108,7 @@ static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, min_t(size_t, obj->gtt_space->size, dev_priv->mm.gtt_mappable_end - obj->gtt_offset); } + list_del_init(&obj->gtt_list); } /** @@ -4604,6 +4606,7 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, obj->base.driver_private = NULL; obj->fence_reg = I915_FENCE_REG_NONE; INIT_LIST_HEAD(&obj->mm_list); + INIT_LIST_HEAD(&obj->gtt_list); INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->gpu_write_list); obj->madv = I915_MADV_WILLNEED; @@ -4916,6 +4919,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.pinned_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list); + INIT_LIST_HEAD(&dev_priv->mm.gtt_list); init_ring_lists(&dev_priv->render_ring); init_ring_lists(&dev_priv->bsd_ring); init_ring_lists(&dev_priv->blt_ring); -- cgit v1.2.3 From 76aaf22016caa7764f40e792aaca7b4918312b22 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 22:23:30 +0100 Subject: drm/i915: restore gtt on resume in the drm instead of in intel-gtt.ko This still uses the agp functions to actually reinstate the mappings (with a gross hack to make agp cooperate), but it wires everything up correctly for the switchover. The call to agp_rebind_memory can be dropped because all non-kms drivers do all their rebinding on EnterVT. v2: Be more paranoid and flush the chipset cache after restoring gtt mappings. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.c | 5 ---- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem_gtt.c | 49 +++++++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_gtt.c (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index e72f49d52202..07e9796fead7 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -828,14 +828,9 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - int ret_val; bridge->driver->configure(); - ret_val = agp_rebind_memory(); - if (ret_val != 0) - return ret_val; - return 0; } #endif diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index fdc833d5cc7b..b3cdb4fe46e0 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -8,6 +8,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ i915_suspend.o \ i915_gem.o \ i915_gem_debug.o \ + i915_gem_gtt.o \ i915_gem_evict.o \ i915_gem_tiling.o \ i915_trace_points.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 8c5541950b8d..1a15b7886b8c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -310,6 +310,7 @@ static int i915_drm_thaw(struct drm_device *dev) /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { mutex_lock(&dev->struct_mutex); + i915_gem_restore_gtt_mappings(dev); dev_priv->mm.suspended = 0; error = i915_gem_init_ringbuffer(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 67ec046aeb90..b6b5d08c9956 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1141,6 +1141,9 @@ void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); +/* i915_gem_gtt.c */ +void i915_gem_restore_gtt_mappings(struct drm_device *dev); + /* i915_gem_evict.c */ int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment, bool mappable); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c new file mode 100644 index 000000000000..5f21d0a962c4 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -0,0 +1,49 @@ +/* + * Copyright © 2010 Daniel Vetter + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" + +void i915_gem_restore_gtt_mappings(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj_priv; + int ret; + + list_for_each_entry(obj_priv, + &dev_priv->mm.gtt_list, + gtt_list) { + /* Hack to force agp to reinsert buffer object. */ + obj_priv->agp_mem->is_bound = false; + ret = agp_bind_memory(obj_priv->agp_mem, obj_priv->gtt_space->start / PAGE_SIZE); + BUG_ON(ret != 0); + } + + /* Be paranoid and flush the chipset cache. */ + intel_gtt_chipset_flush(); +} -- cgit v1.2.3 From cb16b67b5cb33b7d6732e0c416d29d933eea13ce Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 5 Nov 2010 22:27:10 +0100 Subject: agp: kill agp_rebind_memory Its only user, intel-gtt.c is now gone. Cc: Dave Airlie Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/generic.c | 20 -------------------- include/linux/agp_backend.h | 1 - 2 files changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 78bc8de0f234..012cba0d6d96 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -480,26 +480,6 @@ int agp_unbind_memory(struct agp_memory *curr) } EXPORT_SYMBOL(agp_unbind_memory); -/** - * agp_rebind_emmory - Rewrite the entire GATT, useful on resume - */ -int agp_rebind_memory(void) -{ - struct agp_memory *curr; - int ret_val = 0; - - spin_lock(&agp_bridge->mapped_lock); - list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) { - ret_val = curr->bridge->driver->insert_memory(curr, - curr->pg_start, - curr->type); - if (ret_val != 0) - break; - } - spin_unlock(&agp_bridge->mapped_lock); - return ret_val; -} -EXPORT_SYMBOL(agp_rebind_memory); /* End - Routines for handling swapping of agp_memory into the GATT */ diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index a479b4885d25..eaf6cd75a1b1 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -102,7 +102,6 @@ extern struct agp_memory *agp_allocate_memory(struct agp_bridge_data *, size_t, extern int agp_copy_info(struct agp_bridge_data *, struct agp_kern_info *); extern int agp_bind_memory(struct agp_memory *, off_t); extern int agp_unbind_memory(struct agp_memory *); -extern int agp_rebind_memory(void); extern void agp_enable(struct agp_bridge_data *, u32); extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *); extern void agp_backend_release(struct agp_bridge_data *); -- cgit v1.2.3 From 7c2e6fdf452cddeff6a8ee5156edba39e53246fc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 6 Nov 2010 10:10:47 +0100 Subject: drm/i915: move gtt handling to i915_gem_gtt.c No more drm_*_agp in i915_gem.c! Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 14 +++----------- drivers/gpu/drm/i915/i915_gem_gtt.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b6b5d08c9956..b3bfab93e14c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1143,6 +1143,8 @@ void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); /* i915_gem_gtt.c */ void i915_gem_restore_gtt_mappings(struct drm_device *dev); +int i915_gem_gtt_bind_object(struct drm_gem_object *obj); +void i915_gem_gtt_unbind_object(struct drm_gem_object *obj); /* i915_gem_evict.c */ int i915_gem_evict_something(struct drm_device *dev, int min_size, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 07e1b25f4a8a..3cac366b3053 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2288,8 +2288,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) if (obj_priv->fence_reg != I915_FENCE_REG_NONE) i915_gem_clear_fence_reg(obj); - drm_unbind_agp(obj_priv->agp_mem); - drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); + i915_gem_gtt_unbind_object(obj); i915_gem_object_put_pages_gtt(obj); @@ -2808,15 +2807,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, return ret; } - /* Create an AGP memory structure pointing at our pages, and bind it - * into the GTT. - */ - obj_priv->agp_mem = drm_agp_bind_pages(dev, - obj_priv->pages, - obj->size >> PAGE_SHIFT, - obj_priv->gtt_space->start, - obj_priv->agp_type); - if (obj_priv->agp_mem == NULL) { + ret = i915_gem_gtt_bind_object(obj); + if (ret) { i915_gem_object_put_pages_gtt(obj); drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5f21d0a962c4..f78c15f9e7f2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -47,3 +47,31 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) /* Be paranoid and flush the chipset cache. */ intel_gtt_chipset_flush(); } + +int i915_gem_gtt_bind_object(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + + /* Create an AGP memory structure pointing at our pages, and bind it + * into the GTT. + */ + obj_priv->agp_mem = drm_agp_bind_pages(dev, + obj_priv->pages, + obj->size >> PAGE_SHIFT, + obj_priv->gtt_space->start, + obj_priv->agp_type); + + if (obj_priv->agp_mem) + return 0; + else + return -ENOMEM; +} + +void i915_gem_gtt_unbind_object(struct drm_gem_object *obj) +{ + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + + drm_unbind_agp(obj_priv->agp_mem); + drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); +} -- cgit v1.2.3 From 4080775b60cc26044e7c4aba5e76e5041b0d7004 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 6 Nov 2010 11:18:58 +0100 Subject: intel-gtt: export api for drm/i915 Just some minor shuffling to get rid of any agp traces in the exported functions. Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 120 ++++++++++++++++++++++++------------------- include/drm/intel-gtt.h | 12 +++++ 2 files changed, 80 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 1603e4f8ae73..5a2b7360f5be 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -87,41 +87,29 @@ static struct _intel_private { #define IS_IRONLAKE intel_private.driver->is_ironlake #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable -static void intel_agp_free_sglist(struct agp_memory *mem) -{ - struct sg_table st; - - st.sgl = mem->sg_list; - st.orig_nents = st.nents = mem->page_count; - - sg_free_table(&st); - - mem->sg_list = NULL; - mem->num_sg = 0; -} - -static int intel_agp_map_memory(struct agp_memory *mem) +int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, + struct scatterlist **sg_list, int *num_sg) { struct sg_table st; struct scatterlist *sg; int i; - if (mem->sg_list) + if (*sg_list) return 0; /* already mapped (for e.g. resume */ - DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); + DBG("try mapping %lu pages\n", (unsigned long)num_entries); - if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) + if (sg_alloc_table(&st, num_entries, GFP_KERNEL)) goto err; - mem->sg_list = sg = st.sgl; + *sg_list = sg = st.sgl; - for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg)) - sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0); + for (i = 0 ; i < num_entries; i++, sg = sg_next(sg)) + sg_set_page(sg, pages[i], PAGE_SIZE, 0); - mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, - mem->page_count, PCI_DMA_BIDIRECTIONAL); - if (unlikely(!mem->num_sg)) + *num_sg = pci_map_sg(intel_private.pcidev, *sg_list, + num_entries, PCI_DMA_BIDIRECTIONAL); + if (unlikely(!*num_sg)) goto err; return 0; @@ -130,15 +118,22 @@ err: sg_free_table(&st); return -ENOMEM; } +EXPORT_SYMBOL(intel_gtt_map_memory); -static void intel_agp_unmap_memory(struct agp_memory *mem) +void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) { + struct sg_table st; DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); - pci_unmap_sg(intel_private.pcidev, mem->sg_list, - mem->page_count, PCI_DMA_BIDIRECTIONAL); - intel_agp_free_sglist(mem); + pci_unmap_sg(intel_private.pcidev, sg_list, + num_sg, PCI_DMA_BIDIRECTIONAL); + + st.sgl = sg_list; + st.orig_nents = st.nents = num_sg; + + sg_free_table(&st); } +EXPORT_SYMBOL(intel_gtt_unmap_memory); static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) { @@ -307,7 +302,7 @@ static int intel_gtt_setup_scratch_page(void) get_page(page); set_pages_uc(page, 1); - if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { + if (intel_private.base.needs_dmar) { dma_addr = pci_map_page(intel_private.pcidev, page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) @@ -699,6 +694,8 @@ static int intel_gtt_init(void) return ret; } + intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; + return 0; } @@ -892,10 +889,10 @@ static bool i830_check_flags(unsigned int flags) return false; } -static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, - unsigned int sg_len, - unsigned int pg_start, - unsigned int flags) +void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, + unsigned int sg_len, + unsigned int pg_start, + unsigned int flags) { struct scatterlist *sg; unsigned int len, m; @@ -916,11 +913,25 @@ static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, } readl(intel_private.gtt+j-1); } +EXPORT_SYMBOL(intel_gtt_insert_sg_entries); + +void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, + struct page **pages, unsigned int flags) +{ + int i, j; + + for (i = 0, j = first_entry; i < num_entries; i++, j++) { + dma_addr_t addr = page_to_phys(pages[i]); + intel_private.driver->write_entry(addr, + j, flags); + } + readl(intel_private.gtt+j-1); +} +EXPORT_SYMBOL(intel_gtt_insert_pages); static int intel_fake_agp_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { - int i, j; int ret = -EINVAL; if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) @@ -941,21 +952,17 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (!mem->is_flushed) global_cache_flush(); - if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { - ret = intel_agp_map_memory(mem); + if (intel_private.base.needs_dmar) { + ret = intel_gtt_map_memory(mem->pages, mem->page_count, + &mem->sg_list, &mem->num_sg); if (ret != 0) return ret; intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, pg_start, type); - } else { - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - dma_addr_t addr = page_to_phys(mem->pages[i]); - intel_private.driver->write_entry(addr, - j, type); - } - readl(intel_private.gtt+j-1); - } + } else + intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, + type); out: ret = 0; @@ -964,22 +971,31 @@ out_err: return ret; } +void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) +{ + unsigned int i; + + for (i = first_entry; i < (first_entry + num_entries); i++) { + intel_private.driver->write_entry(intel_private.scratch_page_dma, + i, 0); + } + readl(intel_private.gtt+i-1); +} +EXPORT_SYMBOL(intel_gtt_clear_range); + static int intel_fake_agp_remove_entries(struct agp_memory *mem, off_t pg_start, int type) { - int i; - if (mem->page_count == 0) return 0; - if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) - intel_agp_unmap_memory(mem); - - for (i = pg_start; i < (mem->page_count + pg_start); i++) { - intel_private.driver->write_entry(intel_private.scratch_page_dma, - i, 0); + if (intel_private.base.needs_dmar) { + intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); + mem->sg_list = NULL; + mem->num_sg = 0; } - readl(intel_private.gtt+i-1); + + intel_gtt_clear_range(pg_start, mem->page_count); return 0; } diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index c35817a11690..9e343c0998b4 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -11,9 +11,21 @@ const struct intel_gtt { /* Part of the gtt that is mappable by the cpu, for those chips where * this is not the full gtt. */ unsigned int gtt_mappable_entries; + /* Whether i915 needs to use the dmar apis or not. */ + unsigned int needs_dmar : 1; } *intel_gtt_get(void); void intel_gtt_chipset_flush(void); +void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg); +void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries); +int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, + struct scatterlist **sg_list, int *num_sg); +void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, + unsigned int sg_len, + unsigned int pg_start, + unsigned int flags); +void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, + struct page **pages, unsigned int flags); /* Special gtt memory types */ #define AGP_DCACHE_MEMORY 1 -- cgit v1.2.3 From 185cbcb304ba4dee55e39593fd86dcd7813f62ec Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 6 Nov 2010 12:12:35 +0100 Subject: drm/i915: no more agp for gem Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 9 ++++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 63 ++++++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b3bfab93e14c..dc371d987aa7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -791,11 +791,14 @@ struct drm_i915_gem_object { unsigned int fault_mappable : 1; unsigned int pin_mappable : 1; - /** AGP memory structure for our GTT binding. */ - DRM_AGP_MEM *agp_mem; - struct page **pages; + /** + * DMAR support + */ + struct scatterlist *sg_list; + int num_sg; + /** * Current offset of the object in GTT space. * diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f78c15f9e7f2..0b34a1aee9b6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -33,15 +33,24 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; - int ret; list_for_each_entry(obj_priv, &dev_priv->mm.gtt_list, gtt_list) { - /* Hack to force agp to reinsert buffer object. */ - obj_priv->agp_mem->is_bound = false; - ret = agp_bind_memory(obj_priv->agp_mem, obj_priv->gtt_space->start / PAGE_SIZE); - BUG_ON(ret != 0); + if (dev_priv->mm.gtt->needs_dmar) { + BUG_ON(!obj_priv->sg_list); + + intel_gtt_insert_sg_entries(obj_priv->sg_list, + obj_priv->num_sg, + obj_priv->gtt_space->start + >> PAGE_SHIFT, + obj_priv->agp_type); + } else + intel_gtt_insert_pages(obj_priv->gtt_space->start + >> PAGE_SHIFT, + obj_priv->base.size >> PAGE_SHIFT, + obj_priv->pages, + obj_priv->agp_type); } /* Be paranoid and flush the chipset cache. */ @@ -51,27 +60,43 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) int i915_gem_gtt_bind_object(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + int ret; - /* Create an AGP memory structure pointing at our pages, and bind it - * into the GTT. - */ - obj_priv->agp_mem = drm_agp_bind_pages(dev, - obj_priv->pages, - obj->size >> PAGE_SHIFT, - obj_priv->gtt_space->start, - obj_priv->agp_type); + if (dev_priv->mm.gtt->needs_dmar) { + ret = intel_gtt_map_memory(obj_priv->pages, + obj->size >> PAGE_SHIFT, + &obj_priv->sg_list, + &obj_priv->num_sg); + if (ret != 0) + return ret; + + intel_gtt_insert_sg_entries(obj_priv->sg_list, obj_priv->num_sg, + obj_priv->gtt_space->start + >> PAGE_SHIFT, + obj_priv->agp_type); + } else + intel_gtt_insert_pages(obj_priv->gtt_space->start >> PAGE_SHIFT, + obj->size >> PAGE_SHIFT, + obj_priv->pages, + obj_priv->agp_type); - if (obj_priv->agp_mem) - return 0; - else - return -ENOMEM; + return 0; } void i915_gem_gtt_unbind_object(struct drm_gem_object *obj) { + struct drm_device *dev = obj->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - drm_unbind_agp(obj_priv->agp_mem); - drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); + if (dev_priv->mm.gtt->needs_dmar) { + intel_gtt_unmap_memory(obj_priv->sg_list, obj_priv->num_sg); + obj_priv->sg_list = NULL; + obj_priv->num_sg = 0; + } + + intel_gtt_clear_range(obj_priv->gtt_space->start >> PAGE_SHIFT, + obj->size >> PAGE_SHIFT); } -- cgit v1.2.3 From 05394f3975dceb107a5e1393e2244946e5b43660 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 8 Nov 2010 19:18:58 +0000 Subject: drm/i915: Use drm_i915_gem_object as the preferred type A glorified s/obj_priv/obj/ with a net reduction of over a 100 lines and many characters! Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 64 +- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 84 +- drivers/gpu/drm/i915/i915_gem.c | 1268 +++++++++++++++---------------- drivers/gpu/drm/i915/i915_gem_debug.c | 23 +- drivers/gpu/drm/i915/i915_gem_evict.c | 67 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 68 +- drivers/gpu/drm/i915/i915_gem_tiling.c | 104 ++- drivers/gpu/drm/i915/i915_irq.c | 67 +- drivers/gpu/drm/i915/i915_trace.h | 41 +- drivers/gpu/drm/i915/intel_display.c | 242 +++--- drivers/gpu/drm/i915/intel_drv.h | 15 +- drivers/gpu/drm/i915/intel_fb.c | 25 +- drivers/gpu/drm/i915/intel_overlay.c | 48 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 54 +- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +- 16 files changed, 1019 insertions(+), 1157 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4fe49e0228ef..1e8cd74d18d5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -87,19 +87,19 @@ static int i915_capabilities(struct seq_file *m, void *data) return 0; } -static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv) +static const char *get_pin_flag(struct drm_i915_gem_object *obj) { - if (obj_priv->user_pin_count > 0) + if (obj->user_pin_count > 0) return "P"; - else if (obj_priv->pin_count > 0) + else if (obj->pin_count > 0) return "p"; else return " "; } -static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv) +static const char *get_tiling_flag(struct drm_i915_gem_object *obj) { - switch (obj_priv->tiling_mode) { + switch (obj->tiling_mode) { default: case I915_TILING_NONE: return " "; case I915_TILING_X: return "X"; @@ -140,7 +140,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) struct list_head *head; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; size_t total_obj_size, total_gtt_size; int count, ret; @@ -175,12 +175,12 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) } total_obj_size = total_gtt_size = count = 0; - list_for_each_entry(obj_priv, head, mm_list) { + list_for_each_entry(obj, head, mm_list) { seq_printf(m, " "); - describe_obj(m, obj_priv); + describe_obj(m, obj); seq_printf(m, "\n"); - total_obj_size += obj_priv->base.size; - total_gtt_size += obj_priv->gtt_space->size; + total_obj_size += obj->base.size; + total_gtt_size += obj->gtt_space->size; count++; } mutex_unlock(&dev->struct_mutex); @@ -251,14 +251,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) seq_printf(m, "%d prepares\n", work->pending); if (work->old_fb_obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(work->old_fb_obj); - if(obj_priv) - seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj_priv->gtt_offset ); + struct drm_i915_gem_object *obj = work->old_fb_obj; + if (obj) + seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj->gtt_offset); } if (work->pending_flip_obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(work->pending_flip_obj); - if(obj_priv) - seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj_priv->gtt_offset ); + struct drm_i915_gem_object *obj = work->pending_flip_obj; + if (obj) + seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj->gtt_offset); } } spin_unlock_irqrestore(&dev->event_lock, flags); @@ -421,17 +421,17 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start); seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs); for (i = 0; i < dev_priv->num_fence_regs; i++) { - struct drm_gem_object *obj = dev_priv->fence_regs[i].obj; + struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj; seq_printf(m, "Fenced object[%2d] = ", i); if (obj == NULL) seq_printf(m, "unused"); else - describe_obj(m, to_intel_bo(obj)); + describe_obj(m, obj); seq_printf(m, "\n"); } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -465,14 +465,14 @@ static int i915_hws_info(struct seq_file *m, void *data) static void i915_dump_object(struct seq_file *m, struct io_mapping *mapping, - struct drm_i915_gem_object *obj_priv) + struct drm_i915_gem_object *obj) { int page, page_count, i; - page_count = obj_priv->base.size / PAGE_SIZE; + page_count = obj->base.size / PAGE_SIZE; for (page = 0; page < page_count; page++) { u32 *mem = io_mapping_map_wc(mapping, - obj_priv->gtt_offset + page * PAGE_SIZE); + obj->gtt_offset + page * PAGE_SIZE); for (i = 0; i < PAGE_SIZE; i += 4) seq_printf(m, "%08x : %08x\n", i, mem[i / 4]); io_mapping_unmap(mem); @@ -484,25 +484,21 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { - obj = &obj_priv->base; - if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { - seq_printf(m, "--- gtt_offset = 0x%08x\n", - obj_priv->gtt_offset); - i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv); + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { + if (obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) { + seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset); + i915_dump_object(m, dev_priv->mm.gtt_mapping, obj); } } mutex_unlock(&dev->struct_mutex); - return 0; } @@ -525,7 +521,7 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) if (ret) return ret; - if (!ring->gem_object) { + if (!ring->obj) { seq_printf(m, "No ringbuffer setup\n"); } else { u8 *virt = ring->virtual_start; @@ -983,7 +979,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fb->base.height, fb->base.depth, fb->base.bits_per_pixel); - describe_obj(m, to_intel_bo(fb->obj)); + describe_obj(m, fb->obj); seq_printf(m, "\n"); list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { @@ -995,7 +991,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fb->base.height, fb->base.depth, fb->base.bits_per_pixel); - describe_obj(m, to_intel_bo(fb->obj)); + describe_obj(m, fb->obj); seq_printf(m, "\n"); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7084de7c4c55..7960fd63ecb1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -157,7 +157,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (dev_priv->render_ring.gem_object != NULL) { + if (dev_priv->render_ring.obj != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dc371d987aa7..22d6388b331f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -32,7 +32,6 @@ #include "i915_reg.h" #include "intel_bios.h" -#include "i915_trace.h" #include "intel_ringbuffer.h" #include #include @@ -90,7 +89,7 @@ struct drm_i915_gem_phys_object { int id; struct page **page_list; drm_dma_handle_t *handle; - struct drm_gem_object *cur_obj; + struct drm_i915_gem_object *cur_obj; }; struct mem_block { @@ -125,7 +124,7 @@ struct drm_i915_master_private { #define I915_FENCE_REG_NONE -1 struct drm_i915_fence_reg { - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; struct list_head lru_list; bool gpu; }; @@ -280,9 +279,9 @@ typedef struct drm_i915_private { uint32_t counter; unsigned int seqno_gfx_addr; drm_local_map_t hws_map; - struct drm_gem_object *seqno_obj; - struct drm_gem_object *pwrctx; - struct drm_gem_object *renderctx; + struct drm_i915_gem_object *seqno_obj; + struct drm_i915_gem_object *pwrctx; + struct drm_i915_gem_object *renderctx; struct resource mch_res; @@ -690,14 +689,14 @@ typedef struct drm_i915_private { u8 fmax; u8 fstart; - u64 last_count1; - unsigned long last_time1; - u64 last_count2; - struct timespec last_time2; - unsigned long gfx_power; - int c_m; - int r_t; - u8 corr; + u64 last_count1; + unsigned long last_time1; + u64 last_count2; + struct timespec last_time2; + unsigned long gfx_power; + int c_m; + int r_t; + u8 corr; spinlock_t *mchdev_lock; enum no_fbc_reason no_fbc_reason; @@ -711,7 +710,6 @@ typedef struct drm_i915_private { struct intel_fbdev *fbdev; } drm_i915_private_t; -/** driver private structure attached to each drm_gem_object */ struct drm_i915_gem_object { struct drm_gem_object base; @@ -918,7 +916,7 @@ enum intel_chip_family { #define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) -#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) +#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte @@ -947,6 +945,8 @@ enum intel_chip_family { #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) +#include "i915_trace.h" + extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; @@ -1085,14 +1085,15 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); int i915_gem_init_object(struct drm_gem_object *obj); -struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, - size_t size); +struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, + size_t size); void i915_gem_free_object(struct drm_gem_object *obj); -int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, +int i915_gem_object_pin(struct drm_i915_gem_object *obj, + uint32_t alignment, bool map_and_fenceable); -void i915_gem_object_unpin(struct drm_gem_object *obj); -int i915_gem_object_unbind(struct drm_gem_object *obj); -void i915_gem_release_mmap(struct drm_gem_object *obj); +void i915_gem_object_unpin(struct drm_i915_gem_object *obj); +int i915_gem_object_unbind(struct drm_i915_gem_object *obj); +void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); /** @@ -1104,14 +1105,14 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } -int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, +int i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, bool interruptible); -int i915_gem_object_put_fence_reg(struct drm_gem_object *obj, +int i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, bool interruptible); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset(struct drm_device *dev); -void i915_gem_clflush_object(struct drm_gem_object *obj); -int i915_gem_object_set_domain(struct drm_gem_object *obj, +void i915_gem_clflush_object(struct drm_i915_gem_object *obj); +int i915_gem_object_set_domain(struct drm_i915_gem_object *obj, uint32_t read_domains, uint32_t write_domain); int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, @@ -1131,23 +1132,23 @@ int i915_do_wait_request(struct drm_device *dev, bool interruptible, struct intel_ring_buffer *ring); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); -int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, +int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, int write); -int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, +int i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, bool pipelined); int i915_gem_attach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj, + struct drm_i915_gem_object *obj, int id, int align); void i915_gem_detach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj); + struct drm_i915_gem_object *obj); void i915_gem_free_all_phys_object(struct drm_device *dev); -void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); +void i915_gem_release(struct drm_device *dev, struct drm_file *file); /* i915_gem_gtt.c */ void i915_gem_restore_gtt_mappings(struct drm_device *dev); -int i915_gem_gtt_bind_object(struct drm_gem_object *obj); -void i915_gem_gtt_unbind_object(struct drm_gem_object *obj); +int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); +void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); /* i915_gem_evict.c */ int i915_gem_evict_something(struct drm_device *dev, int min_size, @@ -1157,19 +1158,20 @@ int i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); -void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj); -void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj); +void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); +void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); /* i915_gem_debug.c */ -void i915_gem_dump_object(struct drm_gem_object *obj, int len, +void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, const char *where, uint32_t mark); #if WATCH_LISTS int i915_verify_lists(struct drm_device *dev); #else #define i915_verify_lists(dev) 0 #endif -void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle); -void i915_gem_dump_object(struct drm_gem_object *obj, int len, +void i915_gem_object_check_coherency(struct drm_i915_gem_object *obj, + int handle); +void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, const char *where, uint32_t mark); /* i915_debugfs.c */ @@ -1251,10 +1253,10 @@ extern void intel_display_print_error_state(struct seq_file *m, * In that case, we don't need to do it when GEM is initialized as nobody else * has access to the ring. */ -#define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \ - if (((drm_i915_private_t *)dev->dev_private)->render_ring.gem_object \ +#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \ + if (((drm_i915_private_t *)dev->dev_private)->render_ring.obj \ == NULL) \ - LOCK_TEST_WITH_RETURN(dev, file_priv); \ + LOCK_TEST_WITH_RETURN(dev, file); \ } while (0) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3cac366b3053..d196895527a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -41,29 +41,30 @@ struct change_domains { uint32_t flush_rings; }; -static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv); -static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv); +static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj); +static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj); -static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, +static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, bool pipelined); -static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); -static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); -static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, +static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); +static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj); +static int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, int write); -static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, +static int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, uint64_t offset, uint64_t size); -static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj); -static int i915_gem_object_wait_rendering(struct drm_gem_object *obj, +static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj); +static int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool interruptible); -static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, +static int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable); -static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); -static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, +static void i915_gem_clear_fence_reg(struct drm_i915_gem_object *obj); +static int i915_gem_phys_pwrite(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, - struct drm_file *file_priv); -static void i915_gem_free_object_tail(struct drm_gem_object *obj); + struct drm_file *file); +static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj); static int i915_gem_inactive_shrink(struct shrinker *shrinker, int nr_to_scan, @@ -212,11 +213,9 @@ static int i915_mutex_lock_interruptible(struct drm_device *dev) } static inline bool -i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) +i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) { - return obj_priv->gtt_space && - !obj_priv->active && - obj_priv->pin_count == 0; + return obj->gtt_space && !obj->active && obj->pin_count == 0; } int i915_gem_do_init(struct drm_device *dev, @@ -244,7 +243,7 @@ int i915_gem_do_init(struct drm_device *dev, int i915_gem_init_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_init *args = data; int ret; @@ -258,7 +257,7 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_get_aperture *args = data; @@ -280,10 +279,10 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, */ int i915_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_create *args = data; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; int ret; u32 handle; @@ -294,29 +293,28 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOMEM; - ret = drm_gem_handle_create(file_priv, obj, &handle); + ret = drm_gem_handle_create(file, &obj->base, &handle); if (ret) { - drm_gem_object_release(obj); - i915_gem_info_remove_obj(dev->dev_private, obj->size); + drm_gem_object_release(&obj->base); + i915_gem_info_remove_obj(dev->dev_private, obj->base.size); kfree(obj); return ret; } /* drop reference from allocate - handle holds it now */ - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); trace_i915_gem_object_create(obj); args->handle = handle; return 0; } -static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj) +static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) { - drm_i915_private_t *dev_priv = obj->dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + drm_i915_private_t *dev_priv = obj->base.dev->dev_private; return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && - obj_priv->tiling_mode != I915_TILING_NONE; + obj->tiling_mode != I915_TILING_NONE; } static inline void @@ -392,12 +390,12 @@ slow_shmem_bit17_copy(struct page *gpu_page, * fault, it fails so we can fall back to i915_gem_shmem_pwrite_slow(). */ static int -i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_shmem_pread_fast(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pread *args, - struct drm_file *file_priv) + struct drm_file *file) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; + struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; ssize_t remain; loff_t offset; char __user *user_data; @@ -406,7 +404,6 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - obj_priv = to_intel_bo(obj); offset = args->offset; while (remain > 0) { @@ -455,12 +452,12 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, * and not take page faults. */ static int -i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_shmem_pread_slow(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pread *args, - struct drm_file *file_priv) + struct drm_file *file) { - struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; struct mm_struct *mm = current->mm; struct page **user_pages; ssize_t remain; @@ -506,7 +503,6 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - obj_priv = to_intel_bo(obj); offset = args->offset; while (remain > 0) { @@ -575,11 +571,10 @@ out: */ int i915_gem_pread_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_pread *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret = 0; if (args->size == 0) @@ -599,15 +594,15 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); /* Bounds check source. */ - if (args->offset > obj->size || args->size > obj->size - args->offset) { + if (args->offset > obj->base.size || + args->size > obj->base.size - args->offset) { ret = -EINVAL; goto out; } @@ -620,12 +615,12 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, ret = -EFAULT; if (!i915_gem_object_needs_bit17_swizzle(obj)) - ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv); + ret = i915_gem_shmem_pread_fast(dev, obj, args, file); if (ret == -EFAULT) - ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv); + ret = i915_gem_shmem_pread_slow(dev, obj, args, file); out: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -680,11 +675,11 @@ slow_kernel_write(struct io_mapping *mapping, * user into the GTT, uncached. */ static int -i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_gtt_pwrite_fast(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, - struct drm_file *file_priv) + struct drm_file *file) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); drm_i915_private_t *dev_priv = dev->dev_private; ssize_t remain; loff_t offset, page_base; @@ -694,8 +689,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - obj_priv = to_intel_bo(obj); - offset = obj_priv->gtt_offset + args->offset; + offset = obj->gtt_offset + args->offset; while (remain > 0) { /* Operation in this page @@ -735,11 +729,11 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, * than using i915_gem_gtt_pwrite_fast on a G45 (32-bit). */ static int -i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_gtt_pwrite_slow(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, - struct drm_file *file_priv) + struct drm_file *file) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); drm_i915_private_t *dev_priv = dev->dev_private; ssize_t remain; loff_t gtt_page_base, offset; @@ -780,8 +774,7 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, if (ret) goto out_unpin_pages; - obj_priv = to_intel_bo(obj); - offset = obj_priv->gtt_offset + args->offset; + offset = obj->gtt_offset + args->offset; while (remain > 0) { /* Operation in this page @@ -827,12 +820,12 @@ out_unpin_pages: * copy_from_user into the kmapped pages backing the object. */ static int -i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_shmem_pwrite_fast(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, - struct drm_file *file_priv) + struct drm_file *file) { - struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; ssize_t remain; loff_t offset; char __user *user_data; @@ -841,9 +834,8 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, user_data = (char __user *) (uintptr_t) args->data_ptr; remain = args->size; - obj_priv = to_intel_bo(obj); offset = args->offset; - obj_priv->dirty = 1; + obj->dirty = 1; while (remain > 0) { struct page *page; @@ -898,12 +890,12 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, * struct_mutex is held. */ static int -i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_shmem_pwrite_slow(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, - struct drm_file *file_priv) + struct drm_file *file) { - struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; struct mm_struct *mm = current->mm; struct page **user_pages; ssize_t remain; @@ -947,9 +939,8 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); - obj_priv = to_intel_bo(obj); offset = args->offset; - obj_priv->dirty = 1; + obj->dirty = 1; while (remain > 0) { struct page *page; @@ -1020,8 +1011,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_pwrite *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; if (args->size == 0) @@ -1041,15 +1031,15 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - obj = drm_gem_object_lookup(dev, file, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); /* Bounds check destination. */ - if (args->offset > obj->size || args->size > obj->size - args->offset) { + if (args->offset > obj->base.size || + args->size > obj->base.size - args->offset) { ret = -EINVAL; goto out; } @@ -1060,11 +1050,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, * pread/pwrite currently are reading and writing from the CPU * perspective, requiring manual detiling by the client. */ - if (obj_priv->phys_obj) + if (obj->phys_obj) ret = i915_gem_phys_pwrite(dev, obj, args, file); - else if (obj_priv->tiling_mode == I915_TILING_NONE && - obj_priv->gtt_space && - obj->write_domain != I915_GEM_DOMAIN_CPU) { + else if (obj->tiling_mode == I915_TILING_NONE && + obj->gtt_space && + obj->base.write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_object_pin(obj, 0, true); if (ret) goto out; @@ -1092,7 +1082,7 @@ out_unpin: } out: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -1104,12 +1094,11 @@ unlock: */ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_set_domain *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; uint32_t read_domains = args->read_domains; uint32_t write_domain = args->write_domain; int ret; @@ -1134,12 +1123,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); intel_mark_busy(dev, obj); @@ -1149,9 +1137,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, /* Update the LRU on the fence for the CPU access that's * about to occur. */ - if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { + if (obj->fence_reg != I915_FENCE_REG_NONE) { struct drm_i915_fence_reg *reg = - &dev_priv->fence_regs[obj_priv->fence_reg]; + &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); } @@ -1167,10 +1155,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, } /* Maintain LRU order of "inactive" objects */ - if (ret == 0 && i915_gem_object_is_inactive(obj_priv)) - list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); + if (ret == 0 && i915_gem_object_is_inactive(obj)) + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -1181,10 +1169,10 @@ unlock: */ int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_sw_finish *args = data; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; int ret = 0; if (!(dev->driver->driver_features & DRIVER_GEM)) @@ -1194,17 +1182,17 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } /* Pinned buffers may be scanout, so flush the cache */ - if (to_intel_bo(obj)->pin_count) + if (obj->pin_count) i915_gem_object_flush_cpu_write_domain(obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -1219,7 +1207,7 @@ unlock: */ int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_mmap *args = data; @@ -1230,7 +1218,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = drm_gem_object_lookup(dev, file, args->handle); if (obj == NULL) return -ENOENT; @@ -1273,10 +1261,9 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, */ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - struct drm_gem_object *obj = vma->vm_private_data; - struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data); + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); pgoff_t page_offset; unsigned long pfn; int ret = 0; @@ -1288,17 +1275,17 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Now bind it into the GTT if needed */ mutex_lock(&dev->struct_mutex); - BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable); + BUG_ON(obj->pin_count && !obj->pin_mappable); - if (obj_priv->gtt_space) { - if (!obj_priv->map_and_fenceable) { + if (obj->gtt_space) { + if (!obj->map_and_fenceable) { ret = i915_gem_object_unbind(obj); if (ret) goto unlock; } } - if (!obj_priv->gtt_space) { + if (!obj->gtt_space) { ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) goto unlock; @@ -1308,22 +1295,22 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (ret) goto unlock; - if (!obj_priv->fault_mappable) { - obj_priv->fault_mappable = true; - i915_gem_info_update_mappable(dev_priv, obj_priv, true); + if (!obj->fault_mappable) { + obj->fault_mappable = true; + i915_gem_info_update_mappable(dev_priv, obj, true); } /* Need a new fence register? */ - if (obj_priv->tiling_mode != I915_TILING_NONE) { + if (obj->tiling_mode != I915_TILING_NONE) { ret = i915_gem_object_get_fence_reg(obj, true); if (ret) goto unlock; } - if (i915_gem_object_is_inactive(obj_priv)) - list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); + if (i915_gem_object_is_inactive(obj)) + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + + pfn = ((dev->agp->base + obj->gtt_offset) >> PAGE_SHIFT) + page_offset; /* Finally, remap it using the new GTT offset */ @@ -1356,36 +1343,39 @@ unlock: * This routine allocates and attaches a fake offset for @obj. */ static int -i915_gem_create_mmap_offset(struct drm_gem_object *obj) +i915_gem_create_mmap_offset(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_gem_mm *mm = dev->mm_private; struct drm_map_list *list; struct drm_local_map *map; int ret = 0; /* Set the object up for mmap'ing */ - list = &obj->map_list; + list = &obj->base.map_list; list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); if (!list->map) return -ENOMEM; map = list->map; map->type = _DRM_GEM; - map->size = obj->size; + map->size = obj->base.size; map->handle = obj; /* Get a DRM GEM mmap offset allocated... */ list->file_offset_node = drm_mm_search_free(&mm->offset_manager, - obj->size / PAGE_SIZE, 0, 0); + obj->base.size / PAGE_SIZE, + 0, 0); if (!list->file_offset_node) { - DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); + DRM_ERROR("failed to allocate offset for bo %d\n", + obj->base.name); ret = -ENOSPC; goto out_free_list; } list->file_offset_node = drm_mm_get_block(list->file_offset_node, - obj->size / PAGE_SIZE, 0); + obj->base.size / PAGE_SIZE, + 0); if (!list->file_offset_node) { ret = -ENOMEM; goto out_free_list; @@ -1424,29 +1414,28 @@ out_free_list: * fixup by i915_gem_fault(). */ void -i915_gem_release_mmap(struct drm_gem_object *obj) +i915_gem_release_mmap(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - if (unlikely(obj->map_list.map && dev->dev_mapping)) + if (unlikely(obj->base.map_list.map && dev->dev_mapping)) unmap_mapping_range(dev->dev_mapping, - (loff_t)obj->map_list.hash.key<size, 1); + (loff_t)obj->base.map_list.hash.key<base.size, 1); - if (obj_priv->fault_mappable) { - obj_priv->fault_mappable = false; - i915_gem_info_update_mappable(dev_priv, obj_priv, false); + if (obj->fault_mappable) { + obj->fault_mappable = false; + i915_gem_info_update_mappable(dev_priv, obj, false); } } static void -i915_gem_free_mmap_offset(struct drm_gem_object *obj) +i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_gem_mm *mm = dev->mm_private; - struct drm_map_list *list = &obj->map_list; + struct drm_map_list *list = &obj->base.map_list; drm_ht_remove_item(&mm->offset_hash, &list->hash); drm_mm_put_block(list->file_offset_node); @@ -1462,23 +1451,23 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj) * potential fence register mapping. */ static uint32_t -i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv) +i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj_priv->base.dev; + struct drm_device *dev = obj->base.dev; /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ if (INTEL_INFO(dev)->gen >= 4 || - obj_priv->tiling_mode == I915_TILING_NONE) + obj->tiling_mode == I915_TILING_NONE) return 4096; /* * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. */ - return i915_gem_get_gtt_size(obj_priv); + return i915_gem_get_gtt_size(obj); } /** @@ -1490,16 +1479,16 @@ i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv) * unfenced tiled surface requirements. */ static uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj_priv) +i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj_priv->base.dev; + struct drm_device *dev = obj->base.dev; int tile_height; /* * Minimum alignment is 4k (GTT page size) for sane hw. */ if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || - obj_priv->tiling_mode == I915_TILING_NONE) + obj->tiling_mode == I915_TILING_NONE) return 4096; /* @@ -1508,18 +1497,18 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj_priv) * placed in a fenced gtt region). */ if (IS_GEN2(dev) || - (obj_priv->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))) + (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))) tile_height = 32; else tile_height = 8; - return tile_height * obj_priv->stride * 2; + return tile_height * obj->stride * 2; } static uint32_t -i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) +i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj_priv->base.dev; + struct drm_device *dev = obj->base.dev; uint32_t size; /* @@ -1527,7 +1516,7 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) * if a fence register is needed for the object. */ if (INTEL_INFO(dev)->gen >= 4) - return obj_priv->base.size; + return obj->base.size; /* * Previous chips need to be aligned to the size of the smallest @@ -1538,7 +1527,7 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) else size = 512*1024; - while (size < obj_priv->base.size) + while (size < obj->base.size) size <<= 1; return size; @@ -1548,7 +1537,7 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing * @dev: DRM device * @data: GTT mapping ioctl data - * @file_priv: GEM object info + * @file: GEM object info * * Simply returns the fake offset to userspace so it can mmap it. * The mmap call will end up in drm_gem_mmap(), which will set things @@ -1561,12 +1550,11 @@ i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv) */ int i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_mmap_gtt *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; if (!(dev->driver->driver_features & DRIVER_GEM)) @@ -1576,44 +1564,42 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); - if (obj->size > dev_priv->mm.gtt_mappable_end) { + if (obj->base.size > dev_priv->mm.gtt_mappable_end) { ret = -E2BIG; goto unlock; } - if (obj_priv->madv != I915_MADV_WILLNEED) { + if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to mmap a purgeable buffer\n"); ret = -EINVAL; goto out; } - if (!obj->map_list.map) { + if (!obj->base.map_list.map) { ret = i915_gem_create_mmap_offset(obj); if (ret) goto out; } - args->offset = (u64)obj->map_list.hash.key << PAGE_SHIFT; + args->offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT; out: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; } static int -i915_gem_object_get_pages_gtt(struct drm_gem_object *obj, +i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, gfp_t gfpmask) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int page_count, i; struct address_space *mapping; struct inode *inode; @@ -1622,13 +1608,13 @@ i915_gem_object_get_pages_gtt(struct drm_gem_object *obj, /* Get the list of pages out of our struct file. They'll be pinned * at this point until we release them. */ - page_count = obj->size / PAGE_SIZE; - BUG_ON(obj_priv->pages != NULL); - obj_priv->pages = drm_malloc_ab(page_count, sizeof(struct page *)); - if (obj_priv->pages == NULL) + page_count = obj->base.size / PAGE_SIZE; + BUG_ON(obj->pages != NULL); + obj->pages = drm_malloc_ab(page_count, sizeof(struct page *)); + if (obj->pages == NULL) return -ENOMEM; - inode = obj->filp->f_path.dentry->d_inode; + inode = obj->base.filp->f_path.dentry->d_inode; mapping = inode->i_mapping; for (i = 0; i < page_count; i++) { page = read_cache_page_gfp(mapping, i, @@ -1639,51 +1625,50 @@ i915_gem_object_get_pages_gtt(struct drm_gem_object *obj, if (IS_ERR(page)) goto err_pages; - obj_priv->pages[i] = page; + obj->pages[i] = page; } - if (obj_priv->tiling_mode != I915_TILING_NONE) + if (obj->tiling_mode != I915_TILING_NONE) i915_gem_object_do_bit_17_swizzle(obj); return 0; err_pages: while (i--) - page_cache_release(obj_priv->pages[i]); + page_cache_release(obj->pages[i]); - drm_free_large(obj_priv->pages); - obj_priv->pages = NULL; + drm_free_large(obj->pages); + obj->pages = NULL; return PTR_ERR(page); } static void -i915_gem_object_put_pages_gtt(struct drm_gem_object *obj) +i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - int page_count = obj->size / PAGE_SIZE; + int page_count = obj->base.size / PAGE_SIZE; int i; - BUG_ON(obj_priv->madv == __I915_MADV_PURGED); + BUG_ON(obj->madv == __I915_MADV_PURGED); - if (obj_priv->tiling_mode != I915_TILING_NONE) + if (obj->tiling_mode != I915_TILING_NONE) i915_gem_object_save_bit_17_swizzle(obj); - if (obj_priv->madv == I915_MADV_DONTNEED) - obj_priv->dirty = 0; + if (obj->madv == I915_MADV_DONTNEED) + obj->dirty = 0; for (i = 0; i < page_count; i++) { - if (obj_priv->dirty) - set_page_dirty(obj_priv->pages[i]); + if (obj->dirty) + set_page_dirty(obj->pages[i]); - if (obj_priv->madv == I915_MADV_WILLNEED) - mark_page_accessed(obj_priv->pages[i]); + if (obj->madv == I915_MADV_WILLNEED) + mark_page_accessed(obj->pages[i]); - page_cache_release(obj_priv->pages[i]); + page_cache_release(obj->pages[i]); } - obj_priv->dirty = 0; + obj->dirty = 0; - drm_free_large(obj_priv->pages); - obj_priv->pages = NULL; + drm_free_large(obj->pages); + obj->pages = NULL; } static uint32_t @@ -1695,47 +1680,44 @@ i915_gem_next_request_seqno(struct drm_device *dev, } static void -i915_gem_object_move_to_active(struct drm_gem_object *obj, +i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t seqno = i915_gem_next_request_seqno(dev, ring); BUG_ON(ring == NULL); - obj_priv->ring = ring; + obj->ring = ring; /* Add a reference if we're newly entering the active list. */ - if (!obj_priv->active) { - drm_gem_object_reference(obj); - obj_priv->active = 1; + if (!obj->active) { + drm_gem_object_reference(&obj->base); + obj->active = 1; } /* Move from whatever list we were on to the tail of execution. */ - list_move_tail(&obj_priv->mm_list, &dev_priv->mm.active_list); - list_move_tail(&obj_priv->ring_list, &ring->active_list); - obj_priv->last_rendering_seqno = seqno; + list_move_tail(&obj->mm_list, &dev_priv->mm.active_list); + list_move_tail(&obj->ring_list, &ring->active_list); + obj->last_rendering_seqno = seqno; } static void -i915_gem_object_move_to_flushing(struct drm_gem_object *obj) +i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - BUG_ON(!obj_priv->active); - list_move_tail(&obj_priv->mm_list, &dev_priv->mm.flushing_list); - list_del_init(&obj_priv->ring_list); - obj_priv->last_rendering_seqno = 0; + BUG_ON(!obj->active); + list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list); + list_del_init(&obj->ring_list); + obj->last_rendering_seqno = 0; } /* Immediately discard the backing storage */ static void -i915_gem_object_truncate(struct drm_gem_object *obj) +i915_gem_object_truncate(struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct inode *inode; /* Our goal here is to return as much of the memory as @@ -1744,40 +1726,39 @@ i915_gem_object_truncate(struct drm_gem_object *obj) * backing pages, *now*. Here we mirror the actions taken * when by shmem_delete_inode() to release the backing store. */ - inode = obj->filp->f_path.dentry->d_inode; + inode = obj->base.filp->f_path.dentry->d_inode; truncate_inode_pages(inode->i_mapping, 0); if (inode->i_op->truncate_range) inode->i_op->truncate_range(inode, 0, (loff_t)-1); - obj_priv->madv = __I915_MADV_PURGED; + obj->madv = __I915_MADV_PURGED; } static inline int -i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv) +i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) { - return obj_priv->madv == I915_MADV_DONTNEED; + return obj->madv == I915_MADV_DONTNEED; } static void -i915_gem_object_move_to_inactive(struct drm_gem_object *obj) +i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - if (obj_priv->pin_count != 0) - list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list); + if (obj->pin_count != 0) + list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); else - list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); - list_del_init(&obj_priv->ring_list); + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + list_del_init(&obj->ring_list); - BUG_ON(!list_empty(&obj_priv->gpu_write_list)); + BUG_ON(!list_empty(&obj->gpu_write_list)); - obj_priv->last_rendering_seqno = 0; - obj_priv->ring = NULL; - if (obj_priv->active) { - obj_priv->active = 0; - drm_gem_object_unreference(obj); + obj->last_rendering_seqno = 0; + obj->ring = NULL; + if (obj->active) { + obj->active = 0; + drm_gem_object_unreference(&obj->base); } WARN_ON(i915_verify_lists(dev)); } @@ -1788,30 +1769,28 @@ i915_gem_process_flushing_list(struct drm_device *dev, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv, *next; + struct drm_i915_gem_object *obj, *next; - list_for_each_entry_safe(obj_priv, next, + list_for_each_entry_safe(obj, next, &ring->gpu_write_list, gpu_write_list) { - struct drm_gem_object *obj = &obj_priv->base; + if (obj->base.write_domain & flush_domains) { + uint32_t old_write_domain = obj->base.write_domain; - if (obj->write_domain & flush_domains) { - uint32_t old_write_domain = obj->write_domain; - - obj->write_domain = 0; - list_del_init(&obj_priv->gpu_write_list); + obj->base.write_domain = 0; + list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_active(obj, ring); /* update the fence lru list */ - if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { + if (obj->fence_reg != I915_FENCE_REG_NONE) { struct drm_i915_fence_reg *reg = - &dev_priv->fence_regs[obj_priv->fence_reg]; + &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); } trace_i915_gem_object_change_domain(obj, - obj->read_domains, + obj->base.read_domains, old_write_domain); } } @@ -1912,22 +1891,22 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, } while (!list_empty(&ring->active_list)) { - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; - obj_priv = list_first_entry(&ring->active_list, - struct drm_i915_gem_object, - ring_list); + obj = list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + ring_list); - obj_priv->base.write_domain = 0; - list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_inactive(&obj_priv->base); + obj->base.write_domain = 0; + list_del_init(&obj->gpu_write_list); + i915_gem_object_move_to_inactive(obj); } } void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int i; i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring); @@ -1939,23 +1918,23 @@ void i915_gem_reset(struct drm_device *dev) * lost bo to the inactive list. */ while (!list_empty(&dev_priv->mm.flushing_list)) { - obj_priv = list_first_entry(&dev_priv->mm.flushing_list, - struct drm_i915_gem_object, - mm_list); + obj= list_first_entry(&dev_priv->mm.flushing_list, + struct drm_i915_gem_object, + mm_list); - obj_priv->base.write_domain = 0; - list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_inactive(&obj_priv->base); + obj->base.write_domain = 0; + list_del_init(&obj->gpu_write_list); + i915_gem_object_move_to_inactive(obj); } /* Move everything out of the GPU domains to ensure we do any * necessary invalidation upon reuse. */ - list_for_each_entry(obj_priv, + list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { - obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS; + obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; } /* The fence registers are invalidated so clear them out */ @@ -2008,18 +1987,16 @@ i915_gem_retire_requests_ring(struct drm_device *dev, * by the ringbuffer to the flushing/inactive lists as appropriate. */ while (!list_empty(&ring->active_list)) { - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; - obj_priv = list_first_entry(&ring->active_list, - struct drm_i915_gem_object, - ring_list); + obj= list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + ring_list); - if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno)) + if (!i915_seqno_passed(seqno, obj->last_rendering_seqno)) break; - obj = &obj_priv->base; - if (obj->write_domain != 0) + if (obj->base.write_domain != 0) i915_gem_object_move_to_flushing(obj); else i915_gem_object_move_to_inactive(obj); @@ -2040,17 +2017,17 @@ i915_gem_retire_requests(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!list_empty(&dev_priv->mm.deferred_free_list)) { - struct drm_i915_gem_object *obj_priv, *tmp; + struct drm_i915_gem_object *obj, *next; /* We must be careful that during unbind() we do not * accidentally infinitely recurse into retire requests. * Currently: * retire -> free -> unbind -> wait -> retire_ring */ - list_for_each_entry_safe(obj_priv, tmp, + list_for_each_entry_safe(obj, next, &dev_priv->mm.deferred_free_list, mm_list) - i915_gem_free_object_tail(&obj_priv->base); + i915_gem_free_object_tail(obj); } i915_gem_retire_requests_ring(dev, &dev_priv->render_ring); @@ -2175,7 +2152,6 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno, static void i915_gem_flush_ring(struct drm_device *dev, - struct drm_file *file_priv, struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains) @@ -2186,7 +2162,6 @@ i915_gem_flush_ring(struct drm_device *dev, static void i915_gem_flush(struct drm_device *dev, - struct drm_file *file_priv, uint32_t invalidate_domains, uint32_t flush_domains, uint32_t flush_rings) @@ -2198,16 +2173,13 @@ i915_gem_flush(struct drm_device *dev, if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { if (flush_rings & RING_RENDER) - i915_gem_flush_ring(dev, file_priv, - &dev_priv->render_ring, + i915_gem_flush_ring(dev, &dev_priv->render_ring, invalidate_domains, flush_domains); if (flush_rings & RING_BSD) - i915_gem_flush_ring(dev, file_priv, - &dev_priv->bsd_ring, + i915_gem_flush_ring(dev, &dev_priv->bsd_ring, invalidate_domains, flush_domains); if (flush_rings & RING_BLT) - i915_gem_flush_ring(dev, file_priv, - &dev_priv->blt_ring, + i915_gem_flush_ring(dev, &dev_priv->blt_ring, invalidate_domains, flush_domains); } } @@ -2217,26 +2189,25 @@ i915_gem_flush(struct drm_device *dev, * safe to unbind from the GTT or access from the CPU. */ static int -i915_gem_object_wait_rendering(struct drm_gem_object *obj, +i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool interruptible) { - struct drm_device *dev = obj->dev; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct drm_device *dev = obj->base.dev; int ret; /* This function only exists to support waiting for existing rendering, * not for emitting required flushes. */ - BUG_ON((obj->write_domain & I915_GEM_GPU_DOMAINS) != 0); + BUG_ON((obj->base.write_domain & I915_GEM_GPU_DOMAINS) != 0); /* If there is rendering queued on the buffer being evicted, wait for * it. */ - if (obj_priv->active) { + if (obj->active) { ret = i915_do_wait_request(dev, - obj_priv->last_rendering_seqno, + obj->last_rendering_seqno, interruptible, - obj_priv->ring); + obj->ring); if (ret) return ret; } @@ -2248,17 +2219,16 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj, * Unbinds an object from the GTT aperture. */ int -i915_gem_object_unbind(struct drm_gem_object *obj) +i915_gem_object_unbind(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret = 0; - if (obj_priv->gtt_space == NULL) + if (obj->gtt_space == NULL) return 0; - if (obj_priv->pin_count != 0) { + if (obj->pin_count != 0) { DRM_ERROR("Attempting to unbind pinned buffer\n"); return -EINVAL; } @@ -2281,27 +2251,27 @@ i915_gem_object_unbind(struct drm_gem_object *obj) */ if (ret) { i915_gem_clflush_object(obj); - obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU; + obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU; } /* release the fence reg _after_ flushing */ - if (obj_priv->fence_reg != I915_FENCE_REG_NONE) + if (obj->fence_reg != I915_FENCE_REG_NONE) i915_gem_clear_fence_reg(obj); i915_gem_gtt_unbind_object(obj); i915_gem_object_put_pages_gtt(obj); - i915_gem_info_remove_gtt(dev_priv, obj_priv); - list_del_init(&obj_priv->mm_list); + i915_gem_info_remove_gtt(dev_priv, obj); + list_del_init(&obj->mm_list); /* Avoid an unnecessary call to unbind on rebind. */ - obj_priv->map_and_fenceable = true; + obj->map_and_fenceable = true; - drm_mm_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; - obj_priv->gtt_offset = 0; + drm_mm_put_block(obj->gtt_space); + obj->gtt_space = NULL; + obj->gtt_offset = 0; - if (i915_gem_object_is_purgeable(obj_priv)) + if (i915_gem_object_is_purgeable(obj)) i915_gem_object_truncate(obj); trace_i915_gem_object_unbind(obj); @@ -2315,7 +2285,7 @@ static int i915_ring_idle(struct drm_device *dev, if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list)) return 0; - i915_gem_flush_ring(dev, NULL, ring, + i915_gem_flush_ring(dev, ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); return i915_wait_request(dev, i915_gem_next_request_seqno(dev, ring), @@ -2350,89 +2320,86 @@ i915_gpu_idle(struct drm_device *dev) return 0; } -static void sandybridge_write_fence_reg(struct drm_gem_object *obj) +static void sandybridge_write_fence_reg(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - u32 size = i915_gem_get_gtt_size(obj_priv); - int regnum = obj_priv->fence_reg; + u32 size = obj->gtt_space->size; + int regnum = obj->fence_reg; uint64_t val; - val = (uint64_t)((obj_priv->gtt_offset + size - 4096) & + val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; - val |= obj_priv->gtt_offset & 0xfffff000; - val |= (uint64_t)((obj_priv->stride / 128) - 1) << + val |= obj->gtt_offset & 0xfffff000; + val |= (uint64_t)((obj->stride / 128) - 1) << SANDYBRIDGE_FENCE_PITCH_SHIFT; - if (obj_priv->tiling_mode == I915_TILING_Y) + if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val); } -static void i965_write_fence_reg(struct drm_gem_object *obj) +static void i965_write_fence_reg(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - u32 size = i915_gem_get_gtt_size(obj_priv); - int regnum = obj_priv->fence_reg; + u32 size = obj->gtt_space->size; + int regnum = obj->fence_reg; uint64_t val; - val = (uint64_t)((obj_priv->gtt_offset + size - 4096) & + val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; - val |= obj_priv->gtt_offset & 0xfffff000; - val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; - if (obj_priv->tiling_mode == I915_TILING_Y) + val |= obj->gtt_offset & 0xfffff000; + val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; + if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val); } -static void i915_write_fence_reg(struct drm_gem_object *obj) +static void i915_write_fence_reg(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - u32 size = i915_gem_get_gtt_size(obj_priv); + u32 size = obj->gtt_space->size; uint32_t fence_reg, val, pitch_val; int tile_width; - if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || - (obj_priv->gtt_offset & (size - 1))) { + if ((obj->gtt_offset & ~I915_FENCE_START_MASK) || + (obj->gtt_offset & (size - 1))) { WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n", - __func__, obj_priv->gtt_offset, obj_priv->map_and_fenceable, size, - obj_priv->gtt_space->start, obj_priv->gtt_space->size); + __func__, obj->gtt_offset, obj->map_and_fenceable, size, + obj->gtt_space->start, obj->gtt_space->size); return; } - if (obj_priv->tiling_mode == I915_TILING_Y && + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) tile_width = 128; else tile_width = 512; /* Note: pitch better be a power of two tile widths */ - pitch_val = obj_priv->stride / tile_width; + pitch_val = obj->stride / tile_width; pitch_val = ffs(pitch_val) - 1; - if (obj_priv->tiling_mode == I915_TILING_Y && + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL); else WARN_ON(pitch_val > I915_FENCE_MAX_PITCH_VAL); - val = obj_priv->gtt_offset; - if (obj_priv->tiling_mode == I915_TILING_Y) + val = obj->gtt_offset; + if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; val |= I915_FENCE_SIZE_BITS(size); val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; - fence_reg = obj_priv->fence_reg; + fence_reg = obj->fence_reg; if (fence_reg < 8) fence_reg = FENCE_REG_830_0 + fence_reg * 4; else @@ -2440,30 +2407,29 @@ static void i915_write_fence_reg(struct drm_gem_object *obj) I915_WRITE(fence_reg, val); } -static void i830_write_fence_reg(struct drm_gem_object *obj) +static void i830_write_fence_reg(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - u32 size = i915_gem_get_gtt_size(obj_priv); - int regnum = obj_priv->fence_reg; + u32 size = obj->gtt_space->size; + int regnum = obj->fence_reg; uint32_t val; uint32_t pitch_val; uint32_t fence_size_bits; - if ((obj_priv->gtt_offset & ~I830_FENCE_START_MASK) || - (obj_priv->gtt_offset & (obj->size - 1))) { + if ((obj->gtt_offset & ~I830_FENCE_START_MASK) || + (obj->gtt_offset & (obj->base.size - 1))) { WARN(1, "%s: object 0x%08x not 512K or size aligned\n", - __func__, obj_priv->gtt_offset); + __func__, obj->gtt_offset); return; } - pitch_val = obj_priv->stride / 128; + pitch_val = obj->stride / 128; pitch_val = ffs(pitch_val) - 1; WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL); - val = obj_priv->gtt_offset; - if (obj_priv->tiling_mode == I915_TILING_Y) + val = obj->gtt_offset; + if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; fence_size_bits = I830_FENCE_SIZE_BITS(size); WARN_ON(fence_size_bits & ~0x00000f00); @@ -2479,7 +2445,7 @@ static int i915_find_fence_reg(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_fence_reg *reg; - struct drm_i915_gem_object *obj_priv = NULL; + struct drm_i915_gem_object *obj = NULL; int i, avail, ret; /* First try to find a free reg */ @@ -2489,9 +2455,8 @@ static int i915_find_fence_reg(struct drm_device *dev, if (!reg->obj) return i; - obj_priv = to_intel_bo(reg->obj); - if (!obj_priv->pin_count) - avail++; + if (!reg->obj->pin_count) + avail++; } if (avail == 0) @@ -2501,12 +2466,12 @@ static int i915_find_fence_reg(struct drm_device *dev, avail = I915_FENCE_REG_NONE; list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { - obj_priv = to_intel_bo(reg->obj); - if (obj_priv->pin_count) + obj = reg->obj; + if (obj->pin_count) continue; /* found one! */ - avail = obj_priv->fence_reg; + avail = obj->fence_reg; break; } @@ -2516,9 +2481,9 @@ static int i915_find_fence_reg(struct drm_device *dev, * might drop that one, causing a use-after-free in it. So hold a * private reference to obj like the other callers of put_fence_reg * (set_tiling ioctl) do. */ - drm_gem_object_reference(&obj_priv->base); - ret = i915_gem_object_put_fence_reg(&obj_priv->base, interruptible); - drm_gem_object_unreference(&obj_priv->base); + drm_gem_object_reference(&obj->base); + ret = i915_gem_object_put_fence_reg(obj, interruptible); + drm_gem_object_unreference(&obj->base); if (ret != 0) return ret; @@ -2539,39 +2504,38 @@ static int i915_find_fence_reg(struct drm_device *dev, * and tiling format. */ int -i915_gem_object_get_fence_reg(struct drm_gem_object *obj, +i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, bool interruptible) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_fence_reg *reg = NULL; int ret; /* Just update our place in the LRU if our fence is getting used. */ - if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { - reg = &dev_priv->fence_regs[obj_priv->fence_reg]; + if (obj->fence_reg != I915_FENCE_REG_NONE) { + reg = &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); return 0; } - switch (obj_priv->tiling_mode) { + switch (obj->tiling_mode) { case I915_TILING_NONE: WARN(1, "allocating a fence for non-tiled object?\n"); break; case I915_TILING_X: - if (!obj_priv->stride) + if (!obj->stride) return -EINVAL; - WARN((obj_priv->stride & (512 - 1)), + WARN((obj->stride & (512 - 1)), "object 0x%08x is X tiled but has non-512B pitch\n", - obj_priv->gtt_offset); + obj->gtt_offset); break; case I915_TILING_Y: - if (!obj_priv->stride) + if (!obj->stride) return -EINVAL; - WARN((obj_priv->stride & (128 - 1)), + WARN((obj->stride & (128 - 1)), "object 0x%08x is Y tiled but has non-128B pitch\n", - obj_priv->gtt_offset); + obj->gtt_offset); break; } @@ -2579,8 +2543,8 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, if (ret < 0) return ret; - obj_priv->fence_reg = ret; - reg = &dev_priv->fence_regs[obj_priv->fence_reg]; + obj->fence_reg = ret; + reg = &dev_priv->fence_regs[obj->fence_reg]; list_add_tail(®->lru_list, &dev_priv->mm.fence_list); reg->obj = obj; @@ -2602,8 +2566,8 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, } trace_i915_gem_object_get_fence(obj, - obj_priv->fence_reg, - obj_priv->tiling_mode); + obj->fence_reg, + obj->tiling_mode); return 0; } @@ -2613,40 +2577,38 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, * @obj: object to clear * * Zeroes out the fence register itself and clears out the associated - * data structures in dev_priv and obj_priv. + * data structures in dev_priv and obj. */ static void -i915_gem_clear_fence_reg(struct drm_gem_object *obj) +i915_gem_clear_fence_reg(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - struct drm_i915_fence_reg *reg = - &dev_priv->fence_regs[obj_priv->fence_reg]; + struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[obj->fence_reg]; uint32_t fence_reg; switch (INTEL_INFO(dev)->gen) { case 6: I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + - (obj_priv->fence_reg * 8), 0); + (obj->fence_reg * 8), 0); break; case 5: case 4: - I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); + I915_WRITE64(FENCE_REG_965_0 + (obj->fence_reg * 8), 0); break; case 3: - if (obj_priv->fence_reg >= 8) - fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4; + if (obj->fence_reg >= 8) + fence_reg = FENCE_REG_945_8 + (obj->fence_reg - 8) * 4; else case 2: - fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4; + fence_reg = FENCE_REG_830_0 + obj->fence_reg * 4; I915_WRITE(fence_reg, 0); break; } reg->obj = NULL; - obj_priv->fence_reg = I915_FENCE_REG_NONE; + obj->fence_reg = I915_FENCE_REG_NONE; list_del_init(®->lru_list); } @@ -2657,18 +2619,17 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) * @bool: whether the wait upon the fence is interruptible * * Zeroes out the fence register itself and clears out the associated - * data structures in dev_priv and obj_priv. + * data structures in dev_priv and obj. */ int -i915_gem_object_put_fence_reg(struct drm_gem_object *obj, +i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, bool interruptible) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_fence_reg *reg; - if (obj_priv->fence_reg == I915_FENCE_REG_NONE) + if (obj->fence_reg == I915_FENCE_REG_NONE) return 0; /* If we've changed tiling, GTT-mappings of the object @@ -2681,7 +2642,7 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, * therefore we must wait for any outstanding access to complete * before clearing the fence. */ - reg = &dev_priv->fence_regs[obj_priv->fence_reg]; + reg = &dev_priv->fence_regs[obj->fence_reg]; if (reg->gpu) { int ret; @@ -2706,27 +2667,26 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj, * Finds free space in the GTT aperture and binds the object there. */ static int -i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, +i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_mm_node *free_space; gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; u32 size, fence_size, fence_alignment, unfenced_alignment; bool mappable, fenceable; int ret; - if (obj_priv->madv != I915_MADV_WILLNEED) { + if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to bind a purgeable object\n"); return -EINVAL; } - fence_size = i915_gem_get_gtt_size(obj_priv); - fence_alignment = i915_gem_get_gtt_alignment(obj_priv); - unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj_priv); + fence_size = i915_gem_get_gtt_size(obj); + fence_alignment = i915_gem_get_gtt_alignment(obj); + unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj); if (alignment == 0) alignment = map_and_fenceable ? fence_alignment : @@ -2736,12 +2696,12 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, return -EINVAL; } - size = map_and_fenceable ? fence_size : obj->size; + size = map_and_fenceable ? fence_size : obj->base.size; /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ - if (obj->size > + if (obj->base.size > (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; @@ -2760,16 +2720,16 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, if (free_space != NULL) { if (map_and_fenceable) - obj_priv->gtt_space = + obj->gtt_space = drm_mm_get_block_range_generic(free_space, size, alignment, 0, dev_priv->mm.gtt_mappable_end, 0); else - obj_priv->gtt_space = + obj->gtt_space = drm_mm_get_block(free_space, size, alignment); } - if (obj_priv->gtt_space == NULL) { + if (obj->gtt_space == NULL) { /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ @@ -2783,8 +2743,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, ret = i915_gem_object_get_pages_gtt(obj, gfpmask); if (ret) { - drm_mm_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; + drm_mm_put_block(obj->gtt_space); + obj->gtt_space = NULL; if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ @@ -2810,8 +2770,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, ret = i915_gem_gtt_bind_object(obj); if (ret) { i915_gem_object_put_pages_gtt(obj); - drm_mm_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; + drm_mm_put_block(obj->gtt_space); + obj->gtt_space = NULL; ret = i915_gem_evict_something(dev, size, alignment, map_and_fenceable); @@ -2821,65 +2781,61 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, goto search_free; } - obj_priv->gtt_offset = obj_priv->gtt_space->start; + obj->gtt_offset = obj->gtt_space->start; /* keep track of bounds object by adding it to the inactive list */ - list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_add_gtt(dev_priv, obj_priv); + list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + i915_gem_info_add_gtt(dev_priv, obj); /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache */ - BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS); - BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); + BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); + BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); - trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, map_and_fenceable); + trace_i915_gem_object_bind(obj, obj->gtt_offset, map_and_fenceable); fenceable = - obj_priv->gtt_space->size == fence_size && - (obj_priv->gtt_space->start & (fence_alignment -1)) == 0; + obj->gtt_space->size == fence_size && + (obj->gtt_space->start & (fence_alignment -1)) == 0; mappable = - obj_priv->gtt_offset + obj->size <= dev_priv->mm.gtt_mappable_end; + obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; - obj_priv->map_and_fenceable = mappable && fenceable; + obj->map_and_fenceable = mappable && fenceable; return 0; } void -i915_gem_clflush_object(struct drm_gem_object *obj) +i915_gem_clflush_object(struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - /* If we don't have a page list set up, then we're not pinned * to GPU, and we can ignore the cache flush because it'll happen * again at bind time. */ - if (obj_priv->pages == NULL) + if (obj->pages == NULL) return; trace_i915_gem_object_clflush(obj); - drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE); + drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE); } /** Flushes any GPU write domain for the object if it's dirty. */ static int -i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, +i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, bool pipelined) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; - if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) + if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) return 0; /* Queue the GPU write cache flushing we need. */ - i915_gem_flush_ring(dev, NULL, - to_intel_bo(obj)->ring, - 0, obj->write_domain); - BUG_ON(obj->write_domain); + i915_gem_flush_ring(dev, obj->ring, 0, obj->base.write_domain); + BUG_ON(obj->base.write_domain); if (pipelined) return 0; @@ -2889,11 +2845,11 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj, /** Flushes the GTT write domain for the object if it's dirty. */ static void -i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj) +i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) { uint32_t old_write_domain; - if (obj->write_domain != I915_GEM_DOMAIN_GTT) + if (obj->base.write_domain != I915_GEM_DOMAIN_GTT) return; /* No actual flushing is required for the GTT write domain. Writes @@ -2902,30 +2858,30 @@ i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj) */ i915_gem_release_mmap(obj); - old_write_domain = obj->write_domain; - obj->write_domain = 0; + old_write_domain = obj->base.write_domain; + obj->base.write_domain = 0; trace_i915_gem_object_change_domain(obj, - obj->read_domains, + obj->base.read_domains, old_write_domain); } /** Flushes the CPU write domain for the object if it's dirty. */ static void -i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) +i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) { uint32_t old_write_domain; - if (obj->write_domain != I915_GEM_DOMAIN_CPU) + if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) return; i915_gem_clflush_object(obj); intel_gtt_chipset_flush(); - old_write_domain = obj->write_domain; - obj->write_domain = 0; + old_write_domain = obj->base.write_domain; + obj->base.write_domain = 0; trace_i915_gem_object_change_domain(obj, - obj->read_domains, + obj->base.read_domains, old_write_domain); } @@ -2936,14 +2892,13 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) * flushes to occur. */ int -i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) +i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, int write) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t old_write_domain, old_read_domains; int ret; /* Not valid to be called on unbound objects. */ - if (obj_priv->gtt_space == NULL) + if (obj->gtt_space == NULL) return -EINVAL; ret = i915_gem_object_flush_gpu_write_domain(obj, false); @@ -2958,18 +2913,18 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) return ret; } - old_write_domain = obj->write_domain; - old_read_domains = obj->read_domains; + old_write_domain = obj->base.write_domain; + old_read_domains = obj->base.read_domains; /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ - BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); - obj->read_domains |= I915_GEM_DOMAIN_GTT; + BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0); + obj->base.read_domains |= I915_GEM_DOMAIN_GTT; if (write) { - obj->read_domains = I915_GEM_DOMAIN_GTT; - obj->write_domain = I915_GEM_DOMAIN_GTT; - obj_priv->dirty = 1; + obj->base.read_domains = I915_GEM_DOMAIN_GTT; + obj->base.write_domain = I915_GEM_DOMAIN_GTT; + obj->dirty = 1; } trace_i915_gem_object_change_domain(obj, @@ -2984,15 +2939,14 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) * wait, as in modesetting process we're not supposed to be interrupted. */ int -i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, +i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, bool pipelined) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t old_read_domains; int ret; /* Not valid to be called on unbound objects. */ - if (obj_priv->gtt_space == NULL) + if (obj->gtt_space == NULL) return -EINVAL; ret = i915_gem_object_flush_gpu_write_domain(obj, true); @@ -3008,12 +2962,12 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj, i915_gem_object_flush_cpu_write_domain(obj); - old_read_domains = obj->read_domains; - obj->read_domains |= I915_GEM_DOMAIN_GTT; + old_read_domains = obj->base.read_domains; + obj->base.read_domains |= I915_GEM_DOMAIN_GTT; trace_i915_gem_object_change_domain(obj, old_read_domains, - obj->write_domain); + obj->base.write_domain); return 0; } @@ -3026,10 +2980,10 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, return 0; if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) - i915_gem_flush_ring(obj->base.dev, NULL, obj->ring, + i915_gem_flush_ring(obj->base.dev, obj->ring, 0, obj->base.write_domain); - return i915_gem_object_wait_rendering(&obj->base, interruptible); + return i915_gem_object_wait_rendering(obj, interruptible); } /** @@ -3039,7 +2993,7 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, * flushes to occur. */ static int -i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) +i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, int write) { uint32_t old_write_domain, old_read_domains; int ret; @@ -3061,27 +3015,27 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) return ret; } - old_write_domain = obj->write_domain; - old_read_domains = obj->read_domains; + old_write_domain = obj->base.write_domain; + old_read_domains = obj->base.read_domains; /* Flush the CPU cache if it's still invalid. */ - if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) { + if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) { i915_gem_clflush_object(obj); - obj->read_domains |= I915_GEM_DOMAIN_CPU; + obj->base.read_domains |= I915_GEM_DOMAIN_CPU; } /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ - BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_CPU) != 0); + BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) != 0); /* If we're writing through the CPU, then the GPU read domains will * need to be invalidated at next use. */ if (write) { - obj->read_domains = I915_GEM_DOMAIN_CPU; - obj->write_domain = I915_GEM_DOMAIN_CPU; + obj->base.read_domains = I915_GEM_DOMAIN_CPU; + obj->base.write_domain = I915_GEM_DOMAIN_CPU; } trace_i915_gem_object_change_domain(obj, @@ -3203,20 +3157,18 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) * drm_agp_chipset_flush */ static void -i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, +i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring, struct change_domains *cd) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - uint32_t invalidate_domains = 0; - uint32_t flush_domains = 0; + uint32_t invalidate_domains = 0, flush_domains = 0; /* * If the object isn't moving to a new write domain, * let the object stay in multiple read domains */ - if (obj->pending_write_domain == 0) - obj->pending_read_domains |= obj->read_domains; + if (obj->base.pending_write_domain == 0) + obj->base.pending_read_domains |= obj->base.read_domains; /* * Flush the current write domain if @@ -3224,18 +3176,18 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, * any read domains which differ from the old * write domain */ - if (obj->write_domain && - (obj->write_domain != obj->pending_read_domains || - obj_priv->ring != ring)) { - flush_domains |= obj->write_domain; + if (obj->base.write_domain && + (obj->base.write_domain != obj->base.pending_read_domains || + obj->ring != ring)) { + flush_domains |= obj->base.write_domain; invalidate_domains |= - obj->pending_read_domains & ~obj->write_domain; + obj->base.pending_read_domains & ~obj->base.write_domain; } /* * Invalidate any read caches which may have * stale data. That is, any new read domains. */ - invalidate_domains |= obj->pending_read_domains & ~obj->read_domains; + invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains; if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); @@ -3249,13 +3201,13 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, * write_domains). So if we have a current write domain that we * aren't changing, set pending_write_domain to that. */ - if (flush_domains == 0 && obj->pending_write_domain == 0) - obj->pending_write_domain = obj->write_domain; + if (flush_domains == 0 && obj->base.pending_write_domain == 0) + obj->base.pending_write_domain = obj->base.write_domain; cd->invalidate_domains |= invalidate_domains; cd->flush_domains |= flush_domains; if (flush_domains & I915_GEM_GPU_DOMAINS) - cd->flush_rings |= obj_priv->ring->id; + cd->flush_rings |= obj->ring->id; if (invalidate_domains & I915_GEM_GPU_DOMAINS) cd->flush_rings |= ring->id; } @@ -3267,30 +3219,28 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, * and doesn't handle transitioning from !(read_domains & I915_GEM_DOMAIN_CPU). */ static void -i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) +i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - - if (!obj_priv->page_cpu_valid) + if (!obj->page_cpu_valid) return; /* If we're partially in the CPU read domain, finish moving it in. */ - if (obj->read_domains & I915_GEM_DOMAIN_CPU) { + if (obj->base.read_domains & I915_GEM_DOMAIN_CPU) { int i; - for (i = 0; i <= (obj->size - 1) / PAGE_SIZE; i++) { - if (obj_priv->page_cpu_valid[i]) + for (i = 0; i <= (obj->base.size - 1) / PAGE_SIZE; i++) { + if (obj->page_cpu_valid[i]) continue; - drm_clflush_pages(obj_priv->pages + i, 1); + drm_clflush_pages(obj->pages + i, 1); } } /* Free the page_cpu_valid mappings which are now stale, whether * or not we've got I915_GEM_DOMAIN_CPU. */ - kfree(obj_priv->page_cpu_valid); - obj_priv->page_cpu_valid = NULL; + kfree(obj->page_cpu_valid); + obj->page_cpu_valid = NULL; } /** @@ -3306,14 +3256,13 @@ i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) * flushes to occur. */ static int -i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, +i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, uint64_t offset, uint64_t size) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t old_read_domains; int i, ret; - if (offset == 0 && size == obj->size) + if (offset == 0 && size == obj->base.size) return i915_gem_object_set_to_cpu_domain(obj, 0); ret = i915_gem_object_flush_gpu_write_domain(obj, false); @@ -3322,45 +3271,45 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, i915_gem_object_flush_gtt_write_domain(obj); /* If we're already fully in the CPU read domain, we're done. */ - if (obj_priv->page_cpu_valid == NULL && - (obj->read_domains & I915_GEM_DOMAIN_CPU) != 0) + if (obj->page_cpu_valid == NULL && + (obj->base.read_domains & I915_GEM_DOMAIN_CPU) != 0) return 0; /* Otherwise, create/clear the per-page CPU read domain flag if we're * newly adding I915_GEM_DOMAIN_CPU */ - if (obj_priv->page_cpu_valid == NULL) { - obj_priv->page_cpu_valid = kzalloc(obj->size / PAGE_SIZE, - GFP_KERNEL); - if (obj_priv->page_cpu_valid == NULL) + if (obj->page_cpu_valid == NULL) { + obj->page_cpu_valid = kzalloc(obj->base.size / PAGE_SIZE, + GFP_KERNEL); + if (obj->page_cpu_valid == NULL) return -ENOMEM; - } else if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) - memset(obj_priv->page_cpu_valid, 0, obj->size / PAGE_SIZE); + } else if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0) + memset(obj->page_cpu_valid, 0, obj->base.size / PAGE_SIZE); /* Flush the cache on any pages that are still invalid from the CPU's * perspective. */ for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE; i++) { - if (obj_priv->page_cpu_valid[i]) + if (obj->page_cpu_valid[i]) continue; - drm_clflush_pages(obj_priv->pages + i, 1); + drm_clflush_pages(obj->pages + i, 1); - obj_priv->page_cpu_valid[i] = 1; + obj->page_cpu_valid[i] = 1; } /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ - BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_CPU) != 0); + BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) != 0); - old_read_domains = obj->read_domains; - obj->read_domains |= I915_GEM_DOMAIN_CPU; + old_read_domains = obj->base.read_domains; + obj->base.read_domains |= I915_GEM_DOMAIN_CPU; trace_i915_gem_object_change_domain(obj, old_read_domains, - obj->write_domain); + obj->base.write_domain); return 0; } @@ -3490,7 +3439,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, uint32_t __iomem *reloc_entry; void __iomem *reloc_page; - ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret) goto err; @@ -3564,14 +3513,14 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, struct drm_file *file, - struct drm_gem_object **object_list, + struct drm_i915_gem_object **object_list, struct drm_i915_gem_exec_object2 *exec_list, int count) { int i, ret; for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); + struct drm_i915_gem_object *obj = object_list[i]; obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object(obj, file, @@ -3586,7 +3535,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, static int i915_gem_execbuffer_reserve(struct drm_device *dev, struct drm_file *file, - struct drm_gem_object **object_list, + struct drm_i915_gem_object **object_list, struct drm_i915_gem_exec_object2 *exec_list, int count) { @@ -3599,7 +3548,7 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, ret = 0; for (i = 0; i < count; i++) { struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; - struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); + struct drm_i915_gem_object *obj = object_list[i]; bool need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; @@ -3610,12 +3559,12 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, /* Check fence reg constraints and rebind if necessary */ if (need_mappable && !obj->map_and_fenceable) { - ret = i915_gem_object_unbind(&obj->base); + ret = i915_gem_object_unbind(obj); if (ret) break; } - ret = i915_gem_object_pin(&obj->base, + ret = i915_gem_object_pin(obj, entry->alignment, need_mappable); if (ret) @@ -3626,9 +3575,9 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, * to properly handle blits to/from tiled surfaces. */ if (need_fence) { - ret = i915_gem_object_get_fence_reg(&obj->base, true); + ret = i915_gem_object_get_fence_reg(obj, true); if (ret) { - i915_gem_object_unpin(&obj->base); + i915_gem_object_unpin(obj); break; } @@ -3658,17 +3607,15 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, - struct drm_gem_object **object_list, + struct drm_i915_gem_object **object_list, struct drm_i915_gem_exec_object2 *exec_list, int count) { struct drm_i915_gem_relocation_entry *reloc; int i, total, ret; - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); - obj->in_execbuffer = false; - } + for (i = 0; i < count; i++) + object_list[i]->in_execbuffer = false; mutex_unlock(&dev->struct_mutex); @@ -3713,7 +3660,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, total = 0; for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]); + struct drm_i915_gem_object *obj = object_list[i]; obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object_slow(obj, file, @@ -3740,7 +3687,7 @@ static int i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, struct drm_file *file, struct intel_ring_buffer *ring, - struct drm_gem_object **objects, + struct drm_i915_gem_object **objects, int count) { struct change_domains cd; @@ -3759,17 +3706,17 @@ i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, cd.invalidate_domains, cd.flush_domains); #endif - i915_gem_flush(dev, file, + i915_gem_flush(dev, cd.invalidate_domains, cd.flush_domains, cd.flush_rings); } for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = to_intel_bo(objects[i]); + struct drm_i915_gem_object *obj = objects[i]; /* XXX replace with semaphores */ if (obj->ring && ring != obj->ring) { - ret = i915_gem_object_wait_rendering(&obj->base, true); + ret = i915_gem_object_wait_rendering(obj, true); if (ret) return ret; } @@ -3891,8 +3838,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_exec_object2 *exec_list) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object **object_list = NULL; - struct drm_gem_object *batch_obj; + struct drm_i915_gem_object **object_list = NULL; + struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct drm_i915_gem_request *request = NULL; int ret, i, flips; @@ -3987,29 +3934,29 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Look up object handles */ for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; - object_list[i] = drm_gem_object_lookup(dev, file, - exec_list[i].handle); - if (object_list[i] == NULL) { + obj = to_intel_bo (drm_gem_object_lookup(dev, file, + exec_list[i].handle)); + if (obj == NULL) { DRM_ERROR("Invalid object handle %d at index %d\n", exec_list[i].handle, i); /* prevent error path from reading uninitialized data */ - args->buffer_count = i + 1; + args->buffer_count = i; ret = -ENOENT; goto err; } + object_list[i] = obj; - obj_priv = to_intel_bo(object_list[i]); - if (obj_priv->in_execbuffer) { + if (obj->in_execbuffer) { DRM_ERROR("Object %p appears more than once in object list\n", - object_list[i]); + obj); /* prevent error path from reading uninitialized data */ args->buffer_count = i + 1; ret = -EINVAL; goto err; } - obj_priv->in_execbuffer = true; + obj->in_execbuffer = true; } /* Move the objects en-masse into the GTT, evicting if necessary. */ @@ -4037,15 +3984,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Set the pending read domains for the batch buffer to COMMAND */ batch_obj = object_list[args->buffer_count-1]; - if (batch_obj->pending_write_domain) { + if (batch_obj->base.pending_write_domain) { DRM_ERROR("Attempting to use self-modifying batch buffer\n"); ret = -EINVAL; goto err; } - batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; /* Sanity check the batch buffer */ - exec_offset = to_intel_bo(batch_obj)->gtt_offset; + exec_offset = batch_obj->gtt_offset; ret = i915_gem_check_execbuffer(args, exec_offset); if (ret != 0) { DRM_ERROR("execbuf with invalid offset/length\n"); @@ -4077,8 +4024,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ flips = 0; for (i = 0; i < args->buffer_count; i++) { - if (object_list[i]->write_domain) - flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip); + if (object_list[i]->base.write_domain) + flips |= atomic_read(&object_list[i]->pending_flip); } if (flips) { int plane, flip_mask; @@ -4110,23 +4057,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } for (i = 0; i < args->buffer_count; i++) { - struct drm_gem_object *obj = object_list[i]; + struct drm_i915_gem_object *obj = object_list[i]; - obj->read_domains = obj->pending_read_domains; - obj->write_domain = obj->pending_write_domain; + obj->base.read_domains = obj->base.pending_read_domains; + obj->base.write_domain = obj->base.pending_write_domain; i915_gem_object_move_to_active(obj, ring); - if (obj->write_domain) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - obj_priv->dirty = 1; - list_move_tail(&obj_priv->gpu_write_list, + if (obj->base.write_domain) { + obj->dirty = 1; + list_move_tail(&obj->gpu_write_list, &ring->gpu_write_list); intel_mark_busy(dev, obj); } trace_i915_gem_object_change_domain(obj, - obj->read_domains, - obj->write_domain); + obj->base.read_domains, + obj->base.write_domain); } /* @@ -4142,11 +4088,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, err: for (i = 0; i < args->buffer_count; i++) { - if (object_list[i] == NULL) - break; - - to_intel_bo(object_list[i])->in_execbuffer = false; - drm_gem_object_unreference(object_list[i]); + object_list[i]->in_execbuffer = false; + drm_gem_object_unreference(&object_list[i]->base); } mutex_unlock(&dev->struct_mutex); @@ -4165,7 +4108,7 @@ pre_mutex_err: */ int i915_gem_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_execbuffer *args = data; struct drm_i915_gem_execbuffer2 exec2; @@ -4227,7 +4170,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, exec2.cliprects_ptr = args->cliprects_ptr; exec2.flags = I915_EXEC_RENDER; - ret = i915_gem_do_execbuffer(dev, data, file_priv, &exec2, exec2_list); + ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ for (i = 0; i < args->buffer_count; i++) @@ -4252,7 +4195,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, int i915_gem_execbuffer2(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_execbuffer2 *args = data; struct drm_i915_gem_exec_object2 *exec2_list = NULL; @@ -4285,7 +4228,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, return -EFAULT; } - ret = i915_gem_do_execbuffer(dev, data, file_priv, args, exec2_list); + ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); if (!ret) { /* Copy the new buffer offsets back to the user's exec list. */ ret = copy_to_user((struct drm_i915_relocation_entry __user *) @@ -4305,109 +4248,106 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, } int -i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, +i915_gem_object_pin(struct drm_i915_gem_object *obj, + uint32_t alignment, bool map_and_fenceable) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; - BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); + BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); BUG_ON(map_and_fenceable && !map_and_fenceable); WARN_ON(i915_verify_lists(dev)); - if (obj_priv->gtt_space != NULL) { - if ((alignment && obj_priv->gtt_offset & (alignment - 1)) || - (map_and_fenceable && !obj_priv->map_and_fenceable)) { - WARN(obj_priv->pin_count, + if (obj->gtt_space != NULL) { + if ((alignment && obj->gtt_offset & (alignment - 1)) || + (map_and_fenceable && !obj->map_and_fenceable)) { + WARN(obj->pin_count, "bo is already pinned with incorrect alignment:" " offset=%x, req.alignment=%x, req.map_and_fenceable=%d," " obj->map_and_fenceable=%d\n", - obj_priv->gtt_offset, alignment, + obj->gtt_offset, alignment, map_and_fenceable, - obj_priv->map_and_fenceable); + obj->map_and_fenceable); ret = i915_gem_object_unbind(obj); if (ret) return ret; } } - if (obj_priv->gtt_space == NULL) { + if (obj->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment, map_and_fenceable); if (ret) return ret; } - if (obj_priv->pin_count++ == 0) { - i915_gem_info_add_pin(dev_priv, obj_priv, map_and_fenceable); - if (!obj_priv->active) - list_move_tail(&obj_priv->mm_list, + if (obj->pin_count++ == 0) { + i915_gem_info_add_pin(dev_priv, obj, map_and_fenceable); + if (!obj->active) + list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); } - BUG_ON(!obj_priv->pin_mappable && map_and_fenceable); + BUG_ON(!obj->pin_mappable && map_and_fenceable); WARN_ON(i915_verify_lists(dev)); return 0; } void -i915_gem_object_unpin(struct drm_gem_object *obj) +i915_gem_object_unpin(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); WARN_ON(i915_verify_lists(dev)); - BUG_ON(obj_priv->pin_count == 0); - BUG_ON(obj_priv->gtt_space == NULL); + BUG_ON(obj->pin_count == 0); + BUG_ON(obj->gtt_space == NULL); - if (--obj_priv->pin_count == 0) { - if (!obj_priv->active) - list_move_tail(&obj_priv->mm_list, + if (--obj->pin_count == 0) { + if (!obj->active) + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_remove_pin(dev_priv, obj_priv); + i915_gem_info_remove_pin(dev_priv, obj); } WARN_ON(i915_verify_lists(dev)); } int i915_gem_pin_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_pin *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); - if (obj_priv->madv != I915_MADV_WILLNEED) { + if (obj->madv != I915_MADV_WILLNEED) { DRM_ERROR("Attempting to pin a purgeable buffer\n"); ret = -EINVAL; goto out; } - if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) { + if (obj->pin_filp != NULL && obj->pin_filp != file) { DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n", args->handle); ret = -EINVAL; goto out; } - obj_priv->user_pin_count++; - obj_priv->pin_filp = file_priv; - if (obj_priv->user_pin_count == 1) { + obj->user_pin_count++; + obj->pin_filp = file; + if (obj->user_pin_count == 1) { ret = i915_gem_object_pin(obj, args->alignment, true); if (ret) goto out; @@ -4417,9 +4357,9 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, * as the X server doesn't manage domains yet */ i915_gem_object_flush_cpu_write_domain(obj); - args->offset = obj_priv->gtt_offset; + args->offset = obj->gtt_offset; out: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -4427,38 +4367,36 @@ unlock: int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_pin *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); - if (obj_priv->pin_filp != file_priv) { + if (obj->pin_filp != file) { DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", args->handle); ret = -EINVAL; goto out; } - obj_priv->user_pin_count--; - if (obj_priv->user_pin_count == 0) { - obj_priv->pin_filp = NULL; + obj->user_pin_count--; + if (obj->user_pin_count == 0) { + obj->pin_filp = NULL; i915_gem_object_unpin(obj); } out: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -4466,52 +4404,49 @@ unlock: int i915_gem_busy_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_busy *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); /* Count all active objects as busy, even if they are currently not used * by the gpu. Users of this interface expect objects to eventually * become non-busy without any further actions, therefore emit any * necessary flushes here. */ - args->busy = obj_priv->active; + args->busy = obj->active; if (args->busy) { /* Unconditionally flush objects, even when the gpu still uses this * object. Userspace calling this function indicates that it wants to * use this buffer rather sooner than later, so issuing the required * flush earlier is beneficial. */ - if (obj->write_domain & I915_GEM_GPU_DOMAINS) - i915_gem_flush_ring(dev, file_priv, - obj_priv->ring, - 0, obj->write_domain); + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) + i915_gem_flush_ring(dev, obj->ring, + 0, obj->base.write_domain); /* Update the active list for the hardware's current position. * Otherwise this only updates on a delayed timer or when irqs * are actually unmasked, and our working set ends up being * larger than required. */ - i915_gem_retire_requests_ring(dev, obj_priv->ring); + i915_gem_retire_requests_ring(dev, obj->ring); - args->busy = obj_priv->active; + args->busy = obj->active; } - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -4529,8 +4464,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_gem_madvise *args = data; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; switch (args->madv) { @@ -4545,37 +4479,36 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file_priv, args->handle)); if (obj == NULL) { ret = -ENOENT; goto unlock; } - obj_priv = to_intel_bo(obj); - if (obj_priv->pin_count) { + if (obj->pin_count) { ret = -EINVAL; goto out; } - if (obj_priv->madv != __I915_MADV_PURGED) - obj_priv->madv = args->madv; + if (obj->madv != __I915_MADV_PURGED) + obj->madv = args->madv; /* if the object is no longer bound, discard its backing storage */ - if (i915_gem_object_is_purgeable(obj_priv) && - obj_priv->gtt_space == NULL) + if (i915_gem_object_is_purgeable(obj) && + obj->gtt_space == NULL) i915_gem_object_truncate(obj); - args->retained = obj_priv->madv != __I915_MADV_PURGED; + args->retained = obj->madv != __I915_MADV_PURGED; out: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); return ret; } -struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, - size_t size) +struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, + size_t size) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; @@ -4605,7 +4538,7 @@ struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev, /* Avoid an unnecessary call to unbind on the first bind. */ obj->map_and_fenceable = true; - return &obj->base; + return obj; } int i915_gem_init_object(struct drm_gem_object *obj) @@ -4615,42 +4548,41 @@ int i915_gem_init_object(struct drm_gem_object *obj) return 0; } -static void i915_gem_free_object_tail(struct drm_gem_object *obj) +static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; ret = i915_gem_object_unbind(obj); if (ret == -ERESTARTSYS) { - list_move(&obj_priv->mm_list, + list_move(&obj->mm_list, &dev_priv->mm.deferred_free_list); return; } - if (obj->map_list.map) + if (obj->base.map_list.map) i915_gem_free_mmap_offset(obj); - drm_gem_object_release(obj); - i915_gem_info_remove_obj(dev_priv, obj->size); + drm_gem_object_release(&obj->base); + i915_gem_info_remove_obj(dev_priv, obj->base.size); - kfree(obj_priv->page_cpu_valid); - kfree(obj_priv->bit_17); - kfree(obj_priv); + kfree(obj->page_cpu_valid); + kfree(obj->bit_17); + kfree(obj); } -void i915_gem_free_object(struct drm_gem_object *obj) +void i915_gem_free_object(struct drm_gem_object *gem_obj) { - struct drm_device *dev = obj->dev; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); + struct drm_device *dev = obj->base.dev; trace_i915_gem_object_destroy(obj); - while (obj_priv->pin_count > 0) + while (obj->pin_count > 0) i915_gem_object_unpin(obj); - if (obj_priv->phys_obj) + if (obj->phys_obj) i915_gem_detach_phys_object(dev, obj); i915_gem_free_object_tail(obj); @@ -4710,8 +4642,7 @@ static int i915_gem_init_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; obj = i915_gem_alloc_object(dev, 4096); @@ -4720,15 +4651,14 @@ i915_gem_init_pipe_control(struct drm_device *dev) ret = -ENOMEM; goto err; } - obj_priv = to_intel_bo(obj); - obj_priv->agp_type = AGP_USER_CACHED_MEMORY; + obj->agp_type = AGP_USER_CACHED_MEMORY; ret = i915_gem_object_pin(obj, 4096, true); if (ret) goto err_unref; - dev_priv->seqno_gfx_addr = obj_priv->gtt_offset; - dev_priv->seqno_page = kmap(obj_priv->pages[0]); + dev_priv->seqno_gfx_addr = obj->gtt_offset; + dev_priv->seqno_page = kmap(obj->pages[0]); if (dev_priv->seqno_page == NULL) goto err_unpin; @@ -4740,7 +4670,7 @@ i915_gem_init_pipe_control(struct drm_device *dev) err_unpin: i915_gem_object_unpin(obj); err_unref: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); err: return ret; } @@ -4750,14 +4680,12 @@ static void i915_gem_cleanup_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; obj = dev_priv->seqno_obj; - obj_priv = to_intel_bo(obj); - kunmap(obj_priv->pages[0]); + kunmap(obj->pages[0]); i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); dev_priv->seqno_obj = NULL; dev_priv->seqno_page = NULL; @@ -5035,20 +4963,18 @@ void i915_gem_free_all_phys_object(struct drm_device *dev) } void i915_gem_detach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj) + struct drm_i915_gem_object *obj) { - struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; char *vaddr; int i; int page_count; - if (!obj_priv->phys_obj) + if (!obj->phys_obj) return; - vaddr = obj_priv->phys_obj->handle->vaddr; - - page_count = obj->size / PAGE_SIZE; + vaddr = obj->phys_obj->handle->vaddr; + page_count = obj->base.size / PAGE_SIZE; for (i = 0; i < page_count; i++) { struct page *page = read_cache_page_gfp(mapping, i, GFP_HIGHUSER | __GFP_RECLAIMABLE); @@ -5066,19 +4992,18 @@ void i915_gem_detach_phys_object(struct drm_device *dev, } intel_gtt_chipset_flush(); - obj_priv->phys_obj->cur_obj = NULL; - obj_priv->phys_obj = NULL; + obj->phys_obj->cur_obj = NULL; + obj->phys_obj = NULL; } int i915_gem_attach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj, + struct drm_i915_gem_object *obj, int id, int align) { - struct address_space *mapping = obj->filp->f_path.dentry->d_inode->i_mapping; + struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; int ret = 0; int page_count; int i; @@ -5086,10 +5011,8 @@ i915_gem_attach_phys_object(struct drm_device *dev, if (id > I915_MAX_PHYS_OBJECT) return -EINVAL; - obj_priv = to_intel_bo(obj); - - if (obj_priv->phys_obj) { - if (obj_priv->phys_obj->id == id) + if (obj->phys_obj) { + if (obj->phys_obj->id == id) return 0; i915_gem_detach_phys_object(dev, obj); } @@ -5097,18 +5020,19 @@ i915_gem_attach_phys_object(struct drm_device *dev, /* create a new object */ if (!dev_priv->mm.phys_objs[id - 1]) { ret = i915_gem_init_phys_object(dev, id, - obj->size, align); + obj->base.size, align); if (ret) { - DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size); + DRM_ERROR("failed to init phys object %d size: %zu\n", + id, obj->base.size); return ret; } } /* bind to the object */ - obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; - obj_priv->phys_obj->cur_obj = obj; + obj->phys_obj = dev_priv->mm.phys_objs[id - 1]; + obj->phys_obj->cur_obj = obj; - page_count = obj->size / PAGE_SIZE; + page_count = obj->base.size / PAGE_SIZE; for (i = 0; i < page_count; i++) { struct page *page; @@ -5120,7 +5044,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, return PTR_ERR(page); src = kmap_atomic(page); - dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE); + dst = obj->phys_obj->handle->vaddr + (i * PAGE_SIZE); memcpy(dst, src, PAGE_SIZE); kunmap_atomic(src); @@ -5132,16 +5056,14 @@ i915_gem_attach_phys_object(struct drm_device *dev, } static int -i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, +i915_gem_phys_pwrite(struct drm_device *dev, + struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset; + void *vaddr = obj->phys_obj->handle->vaddr + args->offset; char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; - DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size); - if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { unsigned long unwritten; @@ -5228,7 +5150,7 @@ rescan: &dev_priv->mm.inactive_list, mm_list) { if (i915_gem_object_is_purgeable(obj)) { - i915_gem_object_unbind(&obj->base); + i915_gem_object_unbind(obj); if (--nr_to_scan == 0) break; } @@ -5240,7 +5162,7 @@ rescan: &dev_priv->mm.inactive_list, mm_list) { if (nr_to_scan) { - i915_gem_object_unbind(&obj->base); + i915_gem_object_unbind(obj); nr_to_scan--; } else cnt++; diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c index 48644b840a8d..29d014c48ca2 100644 --- a/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/drivers/gpu/drm/i915/i915_gem_debug.c @@ -152,13 +152,12 @@ i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end, } void -i915_gem_dump_object(struct drm_gem_object *obj, int len, +i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, const char *where, uint32_t mark) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int page; - DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset); + DRM_INFO("%s: object at offset %08x\n", where, obj->gtt_offset); for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) { int page_len, chunk, chunk_len; @@ -170,9 +169,9 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len, chunk_len = page_len - chunk; if (chunk_len > 128) chunk_len = 128; - i915_gem_dump_page(obj_priv->pages[page], + i915_gem_dump_page(obj->pages[page], chunk, chunk + chunk_len, - obj_priv->gtt_offset + + obj->gtt_offset + page * PAGE_SIZE, mark); } @@ -182,21 +181,19 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len, #if WATCH_COHERENCY void -i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) +i915_gem_object_check_coherency(struct drm_i915_gem_object *obj, int handle) { - struct drm_device *dev = obj->dev; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct drm_device *dev = obj->base.dev; int page; uint32_t *gtt_mapping; uint32_t *backing_map = NULL; int bad_count = 0; DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %zdkb):\n", - __func__, obj, obj_priv->gtt_offset, handle, + __func__, obj, obj->gtt_offset, handle, obj->size / 1024); - gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset, - obj->size); + gtt_mapping = ioremap(dev->agp->base + obj->gtt_offset, obj->base.size); if (gtt_mapping == NULL) { DRM_ERROR("failed to map GTT space\n"); return; @@ -205,7 +202,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) for (page = 0; page < obj->size / PAGE_SIZE; page++) { int i; - backing_map = kmap_atomic(obj_priv->pages[page], KM_USER0); + backing_map = kmap_atomic(obj->pages[page], KM_USER0); if (backing_map == NULL) { DRM_ERROR("failed to map backing page\n"); @@ -220,7 +217,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle) if (cpuval != gttval) { DRM_INFO("incoherent CPU vs GPU at 0x%08x: " "0x%08x vs 0x%08x\n", - (int)(obj_priv->gtt_offset + + (int)(obj->gtt_offset + page * PAGE_SIZE + i * 4), cpuval, gttval); if (bad_count++ >= 8) { diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 3f6f336bbb4d..03e15d37b550 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -32,12 +32,11 @@ #include "i915_drm.h" static bool -mark_free(struct drm_i915_gem_object *obj_priv, - struct list_head *unwind) +mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) { - list_add(&obj_priv->evict_list, unwind); - drm_gem_object_reference(&obj_priv->base); - return drm_mm_scan_add_block(obj_priv->gtt_space); + list_add(&obj->evict_list, unwind); + drm_gem_object_reference(&obj->base); + return drm_mm_scan_add_block(obj->gtt_space); } int @@ -46,7 +45,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, { drm_i915_private_t *dev_priv = dev->dev_private; struct list_head eviction_list, unwind_list; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret = 0; i915_gem_retire_requests(dev); @@ -96,42 +95,42 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); /* First see if there is a large enough contiguous idle region... */ - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) { - if (mark_free(obj_priv, &unwind_list)) + list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { + if (mark_free(obj, &unwind_list)) goto found; } /* Now merge in the soon-to-be-expired objects... */ - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { /* Does the object require an outstanding flush? */ - if (obj_priv->base.write_domain || obj_priv->pin_count) + if (obj->base.write_domain || obj->pin_count) continue; - if (mark_free(obj_priv, &unwind_list)) + if (mark_free(obj, &unwind_list)) goto found; } /* Finally add anything with a pending flush (in order of retirement) */ - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) { - if (obj_priv->pin_count) + list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) { + if (obj->pin_count) continue; - if (mark_free(obj_priv, &unwind_list)) + if (mark_free(obj, &unwind_list)) goto found; } - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { - if (! obj_priv->base.write_domain || obj_priv->pin_count) + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { + if (! obj->base.write_domain || obj->pin_count) continue; - if (mark_free(obj_priv, &unwind_list)) + if (mark_free(obj, &unwind_list)) goto found; } /* Nothing found, clean up and bail out! */ - list_for_each_entry(obj_priv, &unwind_list, evict_list) { - ret = drm_mm_scan_remove_block(obj_priv->gtt_space); + list_for_each_entry(obj, &unwind_list, evict_list) { + ret = drm_mm_scan_remove_block(obj->gtt_space); BUG_ON(ret); - drm_gem_object_unreference(&obj_priv->base); + drm_gem_object_unreference(&obj->base); } /* We expect the caller to unpin, evict all and try again, or give up. @@ -145,26 +144,26 @@ found: * temporary list. */ INIT_LIST_HEAD(&eviction_list); while (!list_empty(&unwind_list)) { - obj_priv = list_first_entry(&unwind_list, - struct drm_i915_gem_object, - evict_list); - if (drm_mm_scan_remove_block(obj_priv->gtt_space)) { - list_move(&obj_priv->evict_list, &eviction_list); + obj = list_first_entry(&unwind_list, + struct drm_i915_gem_object, + evict_list); + if (drm_mm_scan_remove_block(obj->gtt_space)) { + list_move(&obj->evict_list, &eviction_list); continue; } - list_del(&obj_priv->evict_list); - drm_gem_object_unreference(&obj_priv->base); + list_del(&obj->evict_list); + drm_gem_object_unreference(&obj->base); } /* Unbinding will emit any required flushes */ while (!list_empty(&eviction_list)) { - obj_priv = list_first_entry(&eviction_list, - struct drm_i915_gem_object, - evict_list); + obj = list_first_entry(&eviction_list, + struct drm_i915_gem_object, + evict_list); if (ret == 0) - ret = i915_gem_object_unbind(&obj_priv->base); - list_del(&obj_priv->evict_list); - drm_gem_object_unreference(&obj_priv->base); + ret = i915_gem_object_unbind(obj); + list_del(&obj->evict_list); + drm_gem_object_unreference(&obj->base); } return ret; @@ -203,7 +202,7 @@ i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only) list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) { if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) { - int ret = i915_gem_object_unbind(&obj->base); + int ret = i915_gem_object_unbind(obj); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0b34a1aee9b6..71c2b0f3747b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -32,71 +32,67 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; - list_for_each_entry(obj_priv, - &dev_priv->mm.gtt_list, - gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { if (dev_priv->mm.gtt->needs_dmar) { - BUG_ON(!obj_priv->sg_list); + BUG_ON(!obj->sg_list); - intel_gtt_insert_sg_entries(obj_priv->sg_list, - obj_priv->num_sg, - obj_priv->gtt_space->start + intel_gtt_insert_sg_entries(obj->sg_list, + obj->num_sg, + obj->gtt_space->start >> PAGE_SHIFT, - obj_priv->agp_type); + obj->agp_type); } else - intel_gtt_insert_pages(obj_priv->gtt_space->start + intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, - obj_priv->base.size >> PAGE_SHIFT, - obj_priv->pages, - obj_priv->agp_type); + obj->base.size >> PAGE_SHIFT, + obj->pages, + obj->agp_type); } /* Be paranoid and flush the chipset cache. */ intel_gtt_chipset_flush(); } -int i915_gem_gtt_bind_object(struct drm_gem_object *obj) +int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; if (dev_priv->mm.gtt->needs_dmar) { - ret = intel_gtt_map_memory(obj_priv->pages, - obj->size >> PAGE_SHIFT, - &obj_priv->sg_list, - &obj_priv->num_sg); + ret = intel_gtt_map_memory(obj->pages, + obj->base.size >> PAGE_SHIFT, + &obj->sg_list, + &obj->num_sg); if (ret != 0) return ret; - intel_gtt_insert_sg_entries(obj_priv->sg_list, obj_priv->num_sg, - obj_priv->gtt_space->start - >> PAGE_SHIFT, - obj_priv->agp_type); + intel_gtt_insert_sg_entries(obj->sg_list, + obj->num_sg, + obj->gtt_space->start >> PAGE_SHIFT, + obj->agp_type); } else - intel_gtt_insert_pages(obj_priv->gtt_space->start >> PAGE_SHIFT, - obj->size >> PAGE_SHIFT, - obj_priv->pages, - obj_priv->agp_type); + intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT, + obj->pages, + obj->agp_type); return 0; } -void i915_gem_gtt_unbind_object(struct drm_gem_object *obj) +void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); if (dev_priv->mm.gtt->needs_dmar) { - intel_gtt_unmap_memory(obj_priv->sg_list, obj_priv->num_sg); - obj_priv->sg_list = NULL; - obj_priv->num_sg = 0; + intel_gtt_unmap_memory(obj->sg_list, obj->num_sg); + obj->sg_list = NULL; + obj->num_sg = 0; } - intel_gtt_clear_range(obj_priv->gtt_space->start >> PAGE_SHIFT, - obj->size >> PAGE_SHIFT); + intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index a517b48d441d..1c5fdb30f272 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -234,25 +234,24 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) /* Is the current GTT allocation valid for the change in tiling? */ static bool -i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode) +i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); u32 size; if (tiling_mode == I915_TILING_NONE) return true; - if (INTEL_INFO(obj->dev)->gen >= 4) + if (INTEL_INFO(obj->base.dev)->gen >= 4) return true; - if (!obj_priv->gtt_space) + if (!obj->gtt_space) return true; - if (INTEL_INFO(obj->dev)->gen == 3) { - if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + if (INTEL_INFO(obj->base.dev)->gen == 3) { + if (obj->gtt_offset & ~I915_FENCE_START_MASK) return false; } else { - if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) + if (obj->gtt_offset & ~I830_FENCE_START_MASK) return false; } @@ -260,18 +259,18 @@ i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode) * Previous chips need to be aligned to the size of the smallest * fence register that can contain the object. */ - if (INTEL_INFO(obj->dev)->gen == 3) + if (INTEL_INFO(obj->base.dev)->gen == 3) size = 1024*1024; else size = 512*1024; - while (size < obj_priv->base.size) + while (size < obj->base.size) size <<= 1; - if (obj_priv->gtt_space->size != size) + if (obj->gtt_space->size != size) return false; - if (obj_priv->gtt_offset & (size - 1)) + if (obj->gtt_offset & (size - 1)) return false; return true; @@ -283,30 +282,29 @@ i915_gem_object_fence_ok(struct drm_gem_object *obj, int tiling_mode) */ int i915_gem_set_tiling(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_set_tiling *args = data; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; ret = i915_gem_check_is_wedged(dev); if (ret) return ret; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) return -ENOENT; - obj_priv = to_intel_bo(obj); - if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { - drm_gem_object_unreference_unlocked(obj); + if (!i915_tiling_ok(dev, + args->stride, obj->base.size, args->tiling_mode)) { + drm_gem_object_unreference_unlocked(&obj->base); return -EINVAL; } - if (obj_priv->pin_count) { - drm_gem_object_unreference_unlocked(obj); + if (obj->pin_count) { + drm_gem_object_unreference_unlocked(&obj->base); return -EBUSY; } @@ -340,8 +338,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, } mutex_lock(&dev->struct_mutex); - if (args->tiling_mode != obj_priv->tiling_mode || - args->stride != obj_priv->stride) { + if (args->tiling_mode != obj->tiling_mode || + args->stride != obj->stride) { /* We need to rebind the object if its current allocation * no longer meets the alignment restrictions for its new * tiling mode. Otherwise we can just leave it alone, but @@ -349,22 +347,22 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, */ if (!i915_gem_object_fence_ok(obj, args->tiling_mode)) ret = i915_gem_object_unbind(obj); - else if (obj_priv->fence_reg != I915_FENCE_REG_NONE) + else if (obj->fence_reg != I915_FENCE_REG_NONE) ret = i915_gem_object_put_fence_reg(obj, true); else i915_gem_release_mmap(obj); if (ret != 0) { - args->tiling_mode = obj_priv->tiling_mode; - args->stride = obj_priv->stride; + args->tiling_mode = obj->tiling_mode; + args->stride = obj->stride; goto err; } - obj_priv->tiling_mode = args->tiling_mode; - obj_priv->stride = args->stride; + obj->tiling_mode = args->tiling_mode; + obj->stride = args->stride; } err: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); return ret; @@ -375,22 +373,20 @@ err: */ int i915_gem_get_tiling(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { struct drm_i915_gem_get_tiling *args = data; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); if (obj == NULL) return -ENOENT; - obj_priv = to_intel_bo(obj); mutex_lock(&dev->struct_mutex); - args->tiling_mode = obj_priv->tiling_mode; - switch (obj_priv->tiling_mode) { + args->tiling_mode = obj->tiling_mode; + switch (obj->tiling_mode) { case I915_TILING_X: args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; break; @@ -410,7 +406,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17) args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10; - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); return 0; @@ -440,46 +436,44 @@ i915_gem_swizzle_page(struct page *page) } void -i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj) +i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - int page_count = obj->size >> PAGE_SHIFT; + int page_count = obj->base.size >> PAGE_SHIFT; int i; if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17) return; - if (obj_priv->bit_17 == NULL) + if (obj->bit_17 == NULL) return; for (i = 0; i < page_count; i++) { - char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17; + char new_bit_17 = page_to_phys(obj->pages[i]) >> 17; if ((new_bit_17 & 0x1) != - (test_bit(i, obj_priv->bit_17) != 0)) { - i915_gem_swizzle_page(obj_priv->pages[i]); - set_page_dirty(obj_priv->pages[i]); + (test_bit(i, obj->bit_17) != 0)) { + i915_gem_swizzle_page(obj->pages[i]); + set_page_dirty(obj->pages[i]); } } } void -i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj) +i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->dev; + struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - int page_count = obj->size >> PAGE_SHIFT; + int page_count = obj->base.size >> PAGE_SHIFT; int i; if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17) return; - if (obj_priv->bit_17 == NULL) { - obj_priv->bit_17 = kmalloc(BITS_TO_LONGS(page_count) * + if (obj->bit_17 == NULL) { + obj->bit_17 = kmalloc(BITS_TO_LONGS(page_count) * sizeof(long), GFP_KERNEL); - if (obj_priv->bit_17 == NULL) { + if (obj->bit_17 == NULL) { DRM_ERROR("Failed to allocate memory for bit 17 " "record\n"); return; @@ -487,9 +481,9 @@ i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj) } for (i = 0; i < page_count; i++) { - if (page_to_phys(obj_priv->pages[i]) & (1 << 17)) - __set_bit(i, obj_priv->bit_17); + if (page_to_phys(obj->pages[i]) & (1 << 17)) + __set_bit(i, obj->bit_17); else - __clear_bit(i, obj_priv->bit_17); + __clear_bit(i, obj->bit_17); } } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a8f55f061f6d..09ac3bbd8165 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -423,28 +423,23 @@ static void i915_error_work_func(struct work_struct *work) #ifdef CONFIG_DEBUG_FS static struct drm_i915_error_object * i915_error_object_create(struct drm_device *dev, - struct drm_gem_object *src) + struct drm_i915_gem_object *src) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_object *dst; - struct drm_i915_gem_object *src_priv; int page, page_count; u32 reloc_offset; - if (src == NULL) + if (src == NULL || src->pages == NULL) return NULL; - src_priv = to_intel_bo(src); - if (src_priv->pages == NULL) - return NULL; - - page_count = src->size / PAGE_SIZE; + page_count = src->base.size / PAGE_SIZE; dst = kmalloc(sizeof(*dst) + page_count * sizeof (u32 *), GFP_ATOMIC); if (dst == NULL) return NULL; - reloc_offset = src_priv->gtt_offset; + reloc_offset = src->gtt_offset; for (page = 0; page < page_count; page++) { unsigned long flags; void __iomem *s; @@ -466,7 +461,7 @@ i915_error_object_create(struct drm_device *dev, reloc_offset += PAGE_SIZE; } dst->page_count = page_count; - dst->gtt_offset = src_priv->gtt_offset; + dst->gtt_offset = src->gtt_offset; return dst; @@ -598,9 +593,9 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err, static void i915_capture_error_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; struct drm_i915_error_state *error; - struct drm_gem_object *batchbuffer[2]; + struct drm_i915_gem_object *batchbuffer[2]; unsigned long flags; u32 bbaddr; int count; @@ -668,34 +663,30 @@ static void i915_capture_error_state(struct drm_device *dev) batchbuffer[0] = NULL; batchbuffer[1] = NULL; count = 0; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) { - struct drm_gem_object *obj = &obj_priv->base; - + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { if (batchbuffer[0] == NULL && - bbaddr >= obj_priv->gtt_offset && - bbaddr < obj_priv->gtt_offset + obj->size) + bbaddr >= obj->gtt_offset && + bbaddr < obj->gtt_offset + obj->base.size) batchbuffer[0] = obj; if (batchbuffer[1] == NULL && - error->acthd >= obj_priv->gtt_offset && - error->acthd < obj_priv->gtt_offset + obj->size) + error->acthd >= obj->gtt_offset && + error->acthd < obj->gtt_offset + obj->base.size) batchbuffer[1] = obj; count++; } /* Scan the other lists for completeness for those bizarre errors. */ if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) { - struct drm_gem_object *obj = &obj_priv->base; - + list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) { if (batchbuffer[0] == NULL && - bbaddr >= obj_priv->gtt_offset && - bbaddr < obj_priv->gtt_offset + obj->size) + bbaddr >= obj->gtt_offset && + bbaddr < obj->gtt_offset + obj->base.size) batchbuffer[0] = obj; if (batchbuffer[1] == NULL && - error->acthd >= obj_priv->gtt_offset && - error->acthd < obj_priv->gtt_offset + obj->size) + error->acthd >= obj->gtt_offset && + error->acthd < obj->gtt_offset + obj->base.size) batchbuffer[1] = obj; if (batchbuffer[0] && batchbuffer[1]) @@ -703,17 +694,15 @@ static void i915_capture_error_state(struct drm_device *dev) } } if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) { - struct drm_gem_object *obj = &obj_priv->base; - + list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { if (batchbuffer[0] == NULL && - bbaddr >= obj_priv->gtt_offset && - bbaddr < obj_priv->gtt_offset + obj->size) + bbaddr >= obj->gtt_offset && + bbaddr < obj->gtt_offset + obj->base.size) batchbuffer[0] = obj; if (batchbuffer[1] == NULL && - error->acthd >= obj_priv->gtt_offset && - error->acthd < obj_priv->gtt_offset + obj->size) + error->acthd >= obj->gtt_offset && + error->acthd < obj->gtt_offset + obj->base.size) batchbuffer[1] = obj; if (batchbuffer[0] && batchbuffer[1]) @@ -732,14 +721,14 @@ static void i915_capture_error_state(struct drm_device *dev) /* Record the ringbuffer */ error->ringbuffer = i915_error_object_create(dev, - dev_priv->render_ring.gem_object); + dev_priv->render_ring.obj); /* Record buffers on the active and pinned lists. */ error->active_bo = NULL; error->pinned_bo = NULL; error->active_bo_count = count; - list_for_each_entry(obj_priv, &dev_priv->mm.pinned_list, mm_list) + list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list) count++; error->pinned_bo_count = count - error->active_bo_count; @@ -948,7 +937,7 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; struct intel_unpin_work *work; unsigned long flags; bool stall_detected; @@ -967,13 +956,13 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) } /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ - obj_priv = to_intel_bo(work->pending_flip_obj); + obj = work->pending_flip_obj; if (INTEL_INFO(dev)->gen >= 4) { int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF; - stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset; + stall_detected = I915_READ(dspsurf) == obj->gtt_offset; } else { int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR; - stall_detected = I915_READ(dspaddr) == (obj_priv->gtt_offset + + stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + crtc->y * crtc->fb->pitch + crtc->x * crtc->fb->bits_per_pixel/8); } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 34ef49fd0377..1df7262ae077 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -6,6 +6,7 @@ #include #include +#include "i915_drv.h" #undef TRACE_SYSTEM #define TRACE_SYSTEM i915 @@ -16,18 +17,18 @@ TRACE_EVENT(i915_gem_object_create, - TP_PROTO(struct drm_gem_object *obj), + TP_PROTO(struct drm_i915_gem_object *obj), TP_ARGS(obj), TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) __field(u32, size) ), TP_fast_assign( __entry->obj = obj; - __entry->size = obj->size; + __entry->size = obj->base.size; ), TP_printk("obj=%p, size=%u", __entry->obj, __entry->size) @@ -35,12 +36,12 @@ TRACE_EVENT(i915_gem_object_create, TRACE_EVENT(i915_gem_object_bind, - TP_PROTO(struct drm_gem_object *obj, u32 gtt_offset, bool mappable), + TP_PROTO(struct drm_i915_gem_object *obj, u32 gtt_offset, bool mappable), TP_ARGS(obj, gtt_offset, mappable), TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) __field(u32, gtt_offset) __field(bool, mappable) ), @@ -58,20 +59,20 @@ TRACE_EVENT(i915_gem_object_bind, TRACE_EVENT(i915_gem_object_change_domain, - TP_PROTO(struct drm_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain), + TP_PROTO(struct drm_i915_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain), TP_ARGS(obj, old_read_domains, old_write_domain), TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) __field(u32, read_domains) __field(u32, write_domain) ), TP_fast_assign( __entry->obj = obj; - __entry->read_domains = obj->read_domains | (old_read_domains << 16); - __entry->write_domain = obj->write_domain | (old_write_domain << 16); + __entry->read_domains = obj->base.read_domains | (old_read_domains << 16); + __entry->write_domain = obj->base.write_domain | (old_write_domain << 16); ), TP_printk("obj=%p, read=%04x, write=%04x", @@ -81,12 +82,12 @@ TRACE_EVENT(i915_gem_object_change_domain, TRACE_EVENT(i915_gem_object_get_fence, - TP_PROTO(struct drm_gem_object *obj, int fence, int tiling_mode), + TP_PROTO(struct drm_i915_gem_object *obj, int fence, int tiling_mode), TP_ARGS(obj, fence, tiling_mode), TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) __field(int, fence) __field(int, tiling_mode) ), @@ -103,12 +104,12 @@ TRACE_EVENT(i915_gem_object_get_fence, DECLARE_EVENT_CLASS(i915_gem_object, - TP_PROTO(struct drm_gem_object *obj), + TP_PROTO(struct drm_i915_gem_object *obj), TP_ARGS(obj), TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) ), TP_fast_assign( @@ -120,21 +121,21 @@ DECLARE_EVENT_CLASS(i915_gem_object, DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush, - TP_PROTO(struct drm_gem_object *obj), + TP_PROTO(struct drm_i915_gem_object *obj), TP_ARGS(obj) ); DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind, - TP_PROTO(struct drm_gem_object *obj), + TP_PROTO(struct drm_i915_gem_object *obj), TP_ARGS(obj) ); DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy, - TP_PROTO(struct drm_gem_object *obj), + TP_PROTO(struct drm_i915_gem_object *obj), TP_ARGS(obj) ); @@ -266,13 +267,13 @@ DEFINE_EVENT(i915_ring, i915_ring_wait_end, ); TRACE_EVENT(i915_flip_request, - TP_PROTO(int plane, struct drm_gem_object *obj), + TP_PROTO(int plane, struct drm_i915_gem_object *obj), TP_ARGS(plane, obj), TP_STRUCT__entry( __field(int, plane) - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) ), TP_fast_assign( @@ -284,13 +285,13 @@ TRACE_EVENT(i915_flip_request, ); TRACE_EVENT(i915_flip_complete, - TP_PROTO(int plane, struct drm_gem_object *obj), + TP_PROTO(int plane, struct drm_i915_gem_object *obj), TP_ARGS(plane, obj), TP_STRUCT__entry( __field(int, plane) - __field(struct drm_gem_object *, obj) + __field(struct drm_i915_gem_object *, obj) ), TP_fast_assign( diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d4bc443f43fc..ae7d4f55ce07 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1066,13 +1066,13 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb = crtc->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj); + struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane, i; u32 fbc_ctl, fbc_ctl2; if (fb->pitch == dev_priv->cfb_pitch && - obj_priv->fence_reg == dev_priv->cfb_fence && + obj->fence_reg == dev_priv->cfb_fence && intel_crtc->plane == dev_priv->cfb_plane && I915_READ(FBC_CONTROL) & FBC_CTL_EN) return; @@ -1086,7 +1086,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* FBC_CTL wants 64B units */ dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1; - dev_priv->cfb_fence = obj_priv->fence_reg; + dev_priv->cfb_fence = obj->fence_reg; dev_priv->cfb_plane = intel_crtc->plane; plane = dev_priv->cfb_plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; @@ -1096,7 +1096,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* Set it up... */ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | plane; - if (obj_priv->tiling_mode != I915_TILING_NONE) + if (obj->tiling_mode != I915_TILING_NONE) fbc_ctl2 |= FBC_CTL_CPU_FENCE; I915_WRITE(FBC_CONTROL2, fbc_ctl2); I915_WRITE(FBC_FENCE_OFF, crtc->y); @@ -1107,7 +1107,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; - if (obj_priv->tiling_mode != I915_TILING_NONE) + if (obj->tiling_mode != I915_TILING_NONE) fbc_ctl |= dev_priv->cfb_fence; I915_WRITE(FBC_CONTROL, fbc_ctl); @@ -1150,7 +1150,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb = crtc->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj); + struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; unsigned long stall_watermark = 200; @@ -1159,7 +1159,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl = I915_READ(DPFC_CONTROL); if (dpfc_ctl & DPFC_CTL_EN) { if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 && - dev_priv->cfb_fence == obj_priv->fence_reg && + dev_priv->cfb_fence == obj->fence_reg && dev_priv->cfb_plane == intel_crtc->plane && dev_priv->cfb_y == crtc->y) return; @@ -1170,12 +1170,12 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) } dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1; - dev_priv->cfb_fence = obj_priv->fence_reg; + dev_priv->cfb_fence = obj->fence_reg; dev_priv->cfb_plane = intel_crtc->plane; dev_priv->cfb_y = crtc->y; dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; - if (obj_priv->tiling_mode != I915_TILING_NONE) { + if (obj->tiling_mode != I915_TILING_NONE) { dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence; I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); } else { @@ -1221,7 +1221,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb = crtc->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj); + struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; unsigned long stall_watermark = 200; @@ -1230,9 +1230,9 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); if (dpfc_ctl & DPFC_CTL_EN) { if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 && - dev_priv->cfb_fence == obj_priv->fence_reg && + dev_priv->cfb_fence == obj->fence_reg && dev_priv->cfb_plane == intel_crtc->plane && - dev_priv->cfb_offset == obj_priv->gtt_offset && + dev_priv->cfb_offset == obj->gtt_offset && dev_priv->cfb_y == crtc->y) return; @@ -1242,14 +1242,14 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) } dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1; - dev_priv->cfb_fence = obj_priv->fence_reg; + dev_priv->cfb_fence = obj->fence_reg; dev_priv->cfb_plane = intel_crtc->plane; - dev_priv->cfb_offset = obj_priv->gtt_offset; + dev_priv->cfb_offset = obj->gtt_offset; dev_priv->cfb_y = crtc->y; dpfc_ctl &= DPFC_RESERVED; dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); - if (obj_priv->tiling_mode != I915_TILING_NONE) { + if (obj->tiling_mode != I915_TILING_NONE) { dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence); I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); } else { @@ -1260,7 +1260,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); - I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID); + I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); @@ -1345,7 +1345,7 @@ static void intel_update_fbc(struct drm_device *dev) struct intel_crtc *intel_crtc; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; DRM_DEBUG_KMS("\n"); @@ -1384,9 +1384,9 @@ static void intel_update_fbc(struct drm_device *dev) intel_crtc = to_intel_crtc(crtc); fb = crtc->fb; intel_fb = to_intel_framebuffer(fb); - obj_priv = to_intel_bo(intel_fb->obj); + obj = intel_fb->obj; - if (intel_fb->obj->size > dev_priv->cfb_size) { + if (intel_fb->obj->base.size > dev_priv->cfb_size) { DRM_DEBUG_KMS("framebuffer too large, disabling " "compression\n"); dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; @@ -1410,7 +1410,7 @@ static void intel_update_fbc(struct drm_device *dev) dev_priv->no_fbc_reason = FBC_BAD_PLANE; goto out_disable; } - if (obj_priv->tiling_mode != I915_TILING_X) { + if (obj->tiling_mode != I915_TILING_X) { DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n"); dev_priv->no_fbc_reason = FBC_NOT_TILED; goto out_disable; @@ -1433,14 +1433,13 @@ out_disable: int intel_pin_and_fence_fb_obj(struct drm_device *dev, - struct drm_gem_object *obj, + struct drm_i915_gem_object *obj, bool pipelined) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); u32 alignment; int ret; - switch (obj_priv->tiling_mode) { + switch (obj->tiling_mode) { case I915_TILING_NONE: if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) alignment = 128 * 1024; @@ -1474,7 +1473,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * framebuffer compression. For simplicity, we always install * a fence as the cost is not that onerous. */ - if (obj_priv->tiling_mode != I915_TILING_NONE) { + if (obj->tiling_mode != I915_TILING_NONE) { ret = i915_gem_object_get_fence_reg(obj, false); if (ret) goto err_unpin; @@ -1496,8 +1495,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned long Start, Offset; u32 dspcntr; @@ -1514,7 +1512,6 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; - obj_priv = to_intel_bo(obj); reg = DSPCNTR(plane); dspcntr = I915_READ(reg); @@ -1539,7 +1536,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, return -EINVAL; } if (INTEL_INFO(dev)->gen >= 4) { - if (obj_priv->tiling_mode != I915_TILING_NONE) + if (obj->tiling_mode != I915_TILING_NONE) dspcntr |= DISPPLANE_TILED; else dspcntr &= ~DISPPLANE_TILED; @@ -1551,7 +1548,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, I915_WRITE(reg, dspcntr); - Start = obj_priv->gtt_offset; + Start = obj->gtt_offset; Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", @@ -1605,18 +1602,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (old_fb) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; wait_event(dev_priv->pending_flip_queue, - atomic_read(&obj_priv->pending_flip) == 0); + atomic_read(&obj->pending_flip) == 0); /* Big Hammer, we also need to ensure that any pending * MI_WAIT_FOR_EVENT inside a user batch buffer on the * current scanout is retired before unpinning the old * framebuffer. */ - ret = i915_gem_object_flush_gpu(obj_priv, false); + ret = i915_gem_object_flush_gpu(obj, false); if (ret) { i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); @@ -2010,16 +2006,16 @@ static void intel_clear_scanline_wait(struct drm_device *dev) static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; struct drm_i915_private *dev_priv; if (crtc->fb == NULL) return; - obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj); + obj = to_intel_framebuffer(crtc->fb)->obj; dev_priv = crtc->dev->dev_private; wait_event(dev_priv->pending_flip_queue, - atomic_read(&obj_priv->pending_flip) == 0); + atomic_read(&obj->pending_flip) == 0); } static void ironlake_crtc_enable(struct drm_crtc *crtc) @@ -4333,15 +4329,14 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, } static int intel_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, + struct drm_file *file, uint32_t handle, uint32_t width, uint32_t height) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_gem_object *bo; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; uint32_t addr; int ret; @@ -4351,7 +4346,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, if (!handle) { DRM_DEBUG_KMS("cursor off\n"); addr = 0; - bo = NULL; + obj = NULL; mutex_lock(&dev->struct_mutex); goto finish; } @@ -4362,13 +4357,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } - bo = drm_gem_object_lookup(dev, file_priv, handle); - if (!bo) + obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); + if (!obj) return -ENOENT; - obj_priv = to_intel_bo(bo); - - if (bo->size < width * height * 4) { + if (obj->base.size < width * height * 4) { DRM_ERROR("buffer is to small\n"); ret = -ENOMEM; goto fail; @@ -4377,29 +4370,29 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { - ret = i915_gem_object_pin(bo, PAGE_SIZE, true); + ret = i915_gem_object_pin(obj, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin cursor bo\n"); goto fail_locked; } - ret = i915_gem_object_set_to_gtt_domain(bo, 0); + ret = i915_gem_object_set_to_gtt_domain(obj, 0); if (ret) { DRM_ERROR("failed to move cursor bo into the GTT\n"); goto fail_unpin; } - addr = obj_priv->gtt_offset; + addr = obj->gtt_offset; } else { int align = IS_I830(dev) ? 16 * 1024 : 256; - ret = i915_gem_attach_phys_object(dev, bo, + ret = i915_gem_attach_phys_object(dev, obj, (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1, align); if (ret) { DRM_ERROR("failed to attach phys object\n"); goto fail_locked; } - addr = obj_priv->phys_obj->handle->busaddr; + addr = obj->phys_obj->handle->busaddr; } if (IS_GEN2(dev)) @@ -4408,17 +4401,17 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, finish: if (intel_crtc->cursor_bo) { if (dev_priv->info->cursor_needs_physical) { - if (intel_crtc->cursor_bo != bo) + if (intel_crtc->cursor_bo != obj) i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo); } else i915_gem_object_unpin(intel_crtc->cursor_bo); - drm_gem_object_unreference(intel_crtc->cursor_bo); + drm_gem_object_unreference(&intel_crtc->cursor_bo->base); } mutex_unlock(&dev->struct_mutex); intel_crtc->cursor_addr = addr; - intel_crtc->cursor_bo = bo; + intel_crtc->cursor_bo = obj; intel_crtc->cursor_width = width; intel_crtc->cursor_height = height; @@ -4426,11 +4419,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, return 0; fail_unpin: - i915_gem_object_unpin(bo); + i915_gem_object_unpin(obj); fail_locked: mutex_unlock(&dev->struct_mutex); fail: - drm_gem_object_unreference_unlocked(bo); + drm_gem_object_unreference_unlocked(&obj->base); return ret; } @@ -4890,7 +4883,7 @@ static void intel_idle_update(struct work_struct *work) * buffer), we'll also mark the display as busy, so we know to increase its * clock frequency. */ -void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj) +void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = NULL; @@ -4971,8 +4964,8 @@ static void intel_unpin_work_fn(struct work_struct *__work) mutex_lock(&work->dev->struct_mutex); i915_gem_object_unpin(work->old_fb_obj); - drm_gem_object_unreference(work->pending_flip_obj); - drm_gem_object_unreference(work->old_fb_obj); + drm_gem_object_unreference(&work->pending_flip_obj->base); + drm_gem_object_unreference(&work->old_fb_obj->base); mutex_unlock(&work->dev->struct_mutex); kfree(work); } @@ -4983,7 +4976,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; struct drm_pending_vblank_event *e; struct timeval now; unsigned long flags; @@ -5015,10 +5008,10 @@ static void do_intel_finish_page_flip(struct drm_device *dev, spin_unlock_irqrestore(&dev->event_lock, flags); - obj_priv = to_intel_bo(work->old_fb_obj); + obj = work->old_fb_obj; atomic_clear_mask(1 << intel_crtc->plane, - &obj_priv->pending_flip.counter); - if (atomic_read(&obj_priv->pending_flip) == 0) + &obj->pending_flip.counter); + if (atomic_read(&obj->pending_flip) == 0) wake_up(&dev_priv->pending_flip_queue); schedule_work(&work->work); @@ -5065,8 +5058,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; unsigned long flags, offset; @@ -5105,8 +5097,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_work; /* Reference the objects for the scheduled work. */ - drm_gem_object_reference(work->old_fb_obj); - drm_gem_object_reference(obj); + drm_gem_object_reference(&work->old_fb_obj->base); + drm_gem_object_reference(&obj->base); crtc->fb = fb; @@ -5134,7 +5126,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, } work->pending_flip_obj = obj; - obj_priv = to_intel_bo(obj); work->enable_stall_check = true; @@ -5148,15 +5139,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, /* Block clients from rendering to the new back buffer until * the flip occurs and the object is no longer visible. */ - atomic_add(1 << intel_crtc->plane, - &to_intel_bo(work->old_fb_obj)->pending_flip); + atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); switch (INTEL_INFO(dev)->gen) { case 2: OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(obj_priv->gtt_offset + offset); + OUT_RING(obj->gtt_offset + offset); OUT_RING(MI_NOOP); break; @@ -5164,7 +5154,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(obj_priv->gtt_offset + offset); + OUT_RING(obj->gtt_offset + offset); OUT_RING(MI_NOOP); break; @@ -5177,7 +5167,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); + OUT_RING(obj->gtt_offset | obj->tiling_mode); /* XXX Enabling the panel-fitter across page-flip is so far * untested on non-native modes, so ignore it for now. @@ -5191,8 +5181,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, case 6: OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); - OUT_RING(fb->pitch | obj_priv->tiling_mode); - OUT_RING(obj_priv->gtt_offset); + OUT_RING(fb->pitch | obj->tiling_mode); + OUT_RING(obj->gtt_offset); pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff; @@ -5208,8 +5198,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, return 0; cleanup_objs: - drm_gem_object_unreference(work->old_fb_obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&work->old_fb_obj->base); + drm_gem_object_unreference(&obj->base); cleanup_work: mutex_unlock(&dev->struct_mutex); @@ -5295,7 +5285,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data; @@ -5440,19 +5430,19 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); drm_framebuffer_cleanup(fb); - drm_gem_object_unreference_unlocked(intel_fb->obj); + drm_gem_object_unreference_unlocked(&intel_fb->obj->base); kfree(intel_fb); } static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, + struct drm_file *file, unsigned int *handle) { struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_gem_object *object = intel_fb->obj; + struct drm_i915_gem_object *obj = intel_fb->obj; - return drm_gem_handle_create(file_priv, object, handle); + return drm_gem_handle_create(file, &obj->base, handle); } static const struct drm_framebuffer_funcs intel_fb_funcs = { @@ -5463,12 +5453,11 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *intel_fb, struct drm_mode_fb_cmd *mode_cmd, - struct drm_gem_object *obj) + struct drm_i915_gem_object *obj) { - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; - if (obj_priv->tiling_mode == I915_TILING_Y) + if (obj->tiling_mode == I915_TILING_Y) return -EINVAL; if (mode_cmd->pitch & 63) @@ -5500,11 +5489,11 @@ intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, struct drm_mode_fb_cmd *mode_cmd) { - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; struct intel_framebuffer *intel_fb; int ret; - obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); + obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); if (!obj) return ERR_PTR(-ENOENT); @@ -5512,10 +5501,9 @@ intel_user_framebuffer_create(struct drm_device *dev, if (!intel_fb) return ERR_PTR(-ENOMEM); - ret = intel_framebuffer_init(dev, intel_fb, - mode_cmd, obj); + ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); if (ret) { - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_unreference_unlocked(&obj->base); kfree(intel_fb); return ERR_PTR(ret); } @@ -5528,10 +5516,10 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fb_output_poll_changed, }; -static struct drm_gem_object * +static struct drm_i915_gem_object * intel_alloc_context_page(struct drm_device *dev) { - struct drm_gem_object *ctx; + struct drm_i915_gem_object *ctx; int ret; ctx = i915_gem_alloc_object(dev, 4096); @@ -5559,7 +5547,7 @@ intel_alloc_context_page(struct drm_device *dev) err_unpin: i915_gem_object_unpin(ctx); err_unref: - drm_gem_object_unreference(ctx); + drm_gem_object_unreference(&ctx->base); mutex_unlock(&dev->struct_mutex); return NULL; } @@ -5886,20 +5874,17 @@ void intel_init_clock_gating(struct drm_device *dev) if (dev_priv->renderctx == NULL) dev_priv->renderctx = intel_alloc_context_page(dev); if (dev_priv->renderctx) { - struct drm_i915_gem_object *obj_priv; - obj_priv = to_intel_bo(dev_priv->renderctx); - if (obj_priv) { - if (BEGIN_LP_RING(4) == 0) { - OUT_RING(MI_SET_CONTEXT); - OUT_RING(obj_priv->gtt_offset | - MI_MM_SPACE_GTT | - MI_SAVE_EXT_STATE_EN | - MI_RESTORE_EXT_STATE_EN | - MI_RESTORE_INHIBIT); - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); - ADVANCE_LP_RING(); - } + struct drm_i915_gem_object *obj = dev_priv->renderctx; + if (BEGIN_LP_RING(4) == 0) { + OUT_RING(MI_SET_CONTEXT); + OUT_RING(obj->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); } } else DRM_DEBUG_KMS("Failed to allocate render context." @@ -5907,22 +5892,11 @@ void intel_init_clock_gating(struct drm_device *dev) } if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { - struct drm_i915_gem_object *obj_priv = NULL; - + if (dev_priv->pwrctx == NULL) + dev_priv->pwrctx = intel_alloc_context_page(dev); if (dev_priv->pwrctx) { - obj_priv = to_intel_bo(dev_priv->pwrctx); - } else { - struct drm_gem_object *pwrctx; - - pwrctx = intel_alloc_context_page(dev); - if (pwrctx) { - dev_priv->pwrctx = pwrctx; - obj_priv = to_intel_bo(pwrctx); - } - } - - if (obj_priv) { - I915_WRITE(PWRCTXA, obj_priv->gtt_offset | PWRCTX_EN); + struct drm_i915_gem_object *obj = dev_priv->pwrctx; + I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN); I915_WRITE(MCHBAR_RENDER_STANDBY, I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); } @@ -6197,23 +6171,25 @@ void intel_modeset_cleanup(struct drm_device *dev) dev_priv->display.disable_fbc(dev); if (dev_priv->renderctx) { - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj = dev_priv->renderctx; + + I915_WRITE(CCID, obj->gtt_offset &~ CCID_EN); + POSTING_READ(CCID); - obj_priv = to_intel_bo(dev_priv->renderctx); - I915_WRITE(CCID, obj_priv->gtt_offset &~ CCID_EN); - I915_READ(CCID); - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(dev_priv->renderctx); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + dev_priv->renderctx = NULL; } if (dev_priv->pwrctx) { - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj = dev_priv->pwrctx; + + I915_WRITE(PWRCTXA, obj->gtt_offset &~ PWRCTX_EN); + POSTING_READ(PWRCTXA); - obj_priv = to_intel_bo(dev_priv->pwrctx); - I915_WRITE(PWRCTXA, obj_priv->gtt_offset &~ PWRCTX_EN); - I915_READ(PWRCTXA); - i915_gem_object_unpin(dev_priv->pwrctx); - drm_gem_object_unreference(dev_priv->pwrctx); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + dev_priv->pwrctx = NULL; } if (IS_IRONLAKE_M(dev)) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 21551fe74541..5a4f14e36d6c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -127,7 +127,7 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) struct intel_framebuffer { struct drm_framebuffer base; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; }; struct intel_fbdev { @@ -166,7 +166,7 @@ struct intel_crtc { struct intel_unpin_work *unpin_work; int fdi_lanes; - struct drm_gem_object *cursor_bo; + struct drm_i915_gem_object *cursor_bo; uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; @@ -220,8 +220,8 @@ intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) struct intel_unpin_work { struct work_struct work; struct drm_device *dev; - struct drm_gem_object *old_fb_obj; - struct drm_gem_object *pending_flip_obj; + struct drm_i915_gem_object *old_fb_obj; + struct drm_i915_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; int pending; bool enable_stall_check; @@ -236,7 +236,8 @@ void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); extern bool intel_sdvo_init(struct drm_device *dev, int output_device); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); -extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj); +extern void intel_mark_busy(struct drm_device *dev, + struct drm_i915_gem_object *obj); extern void intel_lvds_init(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int dp_reg); void @@ -299,13 +300,13 @@ extern void ironlake_disable_drps(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev); extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, - struct drm_gem_object *obj, + struct drm_i915_gem_object *obj, bool pipelined); extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd *mode_cmd, - struct drm_gem_object *obj); + struct drm_i915_gem_object *obj); extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index af2a1dddc28e..c2cffeb4fe89 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -65,8 +65,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, struct fb_info *info; struct drm_framebuffer *fb; struct drm_mode_fb_cmd mode_cmd; - struct drm_gem_object *fbo = NULL; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; struct device *device = &dev->pdev->dev; int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0; @@ -83,18 +82,17 @@ static int intelfb_create(struct intel_fbdev *ifbdev, size = mode_cmd.pitch * mode_cmd.height; size = ALIGN(size, PAGE_SIZE); - fbo = i915_gem_alloc_object(dev, size); - if (!fbo) { + obj = i915_gem_alloc_object(dev, size); + if (!obj) { DRM_ERROR("failed to allocate framebuffer\n"); ret = -ENOMEM; goto out; } - obj_priv = to_intel_bo(fbo); mutex_lock(&dev->struct_mutex); /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, fbo, false); + ret = intel_pin_and_fence_fb_obj(dev, obj, false); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; @@ -108,7 +106,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, info->par = ifbdev; - ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); + ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); if (ret) goto out_unpin; @@ -134,11 +132,10 @@ static int intelfb_create(struct intel_fbdev *ifbdev, else info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); - info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; + info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; info->fix.smem_len = size; - info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, - size); + info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size); if (!info->screen_base) { ret = -ENOSPC; goto out_unpin; @@ -168,7 +165,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", fb->width, fb->height, - obj_priv->gtt_offset, fbo); + obj->gtt_offset, obj); mutex_unlock(&dev->struct_mutex); @@ -176,9 +173,9 @@ static int intelfb_create(struct intel_fbdev *ifbdev, return 0; out_unpin: - i915_gem_object_unpin(fbo); + i915_gem_object_unpin(obj); out_unref: - drm_gem_object_unreference(fbo); + drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); out: return ret; @@ -225,7 +222,7 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_framebuffer_cleanup(&ifb->base); if (ifb->obj) { - drm_gem_object_unreference_unlocked(ifb->obj); + drm_gem_object_unreference_unlocked(&ifb->obj->base); ifb->obj = NULL; } } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index ec8ffaccbbdb..af715cc03ee0 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -376,24 +376,23 @@ static int intel_overlay_continue(struct intel_overlay *overlay, static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) { - struct drm_gem_object *obj = &overlay->old_vid_bo->base; + struct drm_i915_gem_object *obj = overlay->old_vid_bo; i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); overlay->old_vid_bo = NULL; } static void intel_overlay_off_tail(struct intel_overlay *overlay) { - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj = overlay->vid_bo; /* never have the overlay hw on without showing a frame */ BUG_ON(!overlay->vid_bo); - obj = &overlay->vid_bo->base; i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); overlay->vid_bo = NULL; overlay->crtc->overlay = NULL; @@ -764,13 +763,12 @@ static u32 overlay_cmd_reg(struct put_image_params *params) } static int intel_overlay_do_put_image(struct intel_overlay *overlay, - struct drm_gem_object *new_bo, + struct drm_i915_gem_object *new_bo, struct put_image_params *params) { int ret, tmp_width; struct overlay_registers *regs; bool scale_changed = false; - struct drm_i915_gem_object *bo_priv = to_intel_bo(new_bo); struct drm_device *dev = overlay->dev; BUG_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -825,7 +823,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, regs->SWIDTHSW = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width); regs->SHEIGHT = params->src_h; - regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y; + regs->OBUF_0Y = new_bo->gtt_offset + params-> offset_Y; regs->OSTRIDE = params->stride_Y; if (params->format & I915_OVERLAY_YUV_PLANAR) { @@ -839,8 +837,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, params->src_w/uv_hscale); regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16; regs->SHEIGHT |= (params->src_h/uv_vscale) << 16; - regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U; - regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V; + regs->OBUF_0U = new_bo->gtt_offset + params->offset_U; + regs->OBUF_0V = new_bo->gtt_offset + params->offset_V; regs->OSTRIDE |= params->stride_UV << 16; } @@ -857,7 +855,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_unpin; overlay->old_vid_bo = overlay->vid_bo; - overlay->vid_bo = to_intel_bo(new_bo); + overlay->vid_bo = new_bo; return 0; @@ -970,7 +968,7 @@ static int check_overlay_scaling(struct put_image_params *rec) static int check_overlay_src(struct drm_device *dev, struct drm_intel_overlay_put_image *rec, - struct drm_gem_object *new_bo) + struct drm_i915_gem_object *new_bo) { int uv_hscale = uv_hsubsampling(rec->flags); int uv_vscale = uv_vsubsampling(rec->flags); @@ -1055,7 +1053,7 @@ static int check_overlay_src(struct drm_device *dev, return -EINVAL; tmp = rec->stride_Y*rec->src_height; - if (rec->offset_Y + tmp > new_bo->size) + if (rec->offset_Y + tmp > new_bo->base.size) return -EINVAL; break; @@ -1066,12 +1064,12 @@ static int check_overlay_src(struct drm_device *dev, return -EINVAL; tmp = rec->stride_Y * rec->src_height; - if (rec->offset_Y + tmp > new_bo->size) + if (rec->offset_Y + tmp > new_bo->base.size) return -EINVAL; tmp = rec->stride_UV * (rec->src_height / uv_vscale); - if (rec->offset_U + tmp > new_bo->size || - rec->offset_V + tmp > new_bo->size) + if (rec->offset_U + tmp > new_bo->base.size || + rec->offset_V + tmp > new_bo->base.size) return -EINVAL; break; } @@ -1114,7 +1112,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, struct intel_overlay *overlay; struct drm_mode_object *drmmode_obj; struct intel_crtc *crtc; - struct drm_gem_object *new_bo; + struct drm_i915_gem_object *new_bo; struct put_image_params *params; int ret; @@ -1153,8 +1151,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, } crtc = to_intel_crtc(obj_to_crtc(drmmode_obj)); - new_bo = drm_gem_object_lookup(dev, file_priv, - put_image_rec->bo_handle); + new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv, + put_image_rec->bo_handle)); if (!new_bo) { ret = -ENOENT; goto out_free; @@ -1245,7 +1243,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, out_unlock: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->mode_config.mutex); - drm_gem_object_unreference_unlocked(new_bo); + drm_gem_object_unreference_unlocked(&new_bo->base); out_free: kfree(params); @@ -1398,7 +1396,7 @@ void intel_setup_overlay(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_overlay *overlay; - struct drm_gem_object *reg_bo; + struct drm_i915_gem_object *reg_bo; struct overlay_registers *regs; int ret; @@ -1413,7 +1411,7 @@ void intel_setup_overlay(struct drm_device *dev) reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE); if (!reg_bo) goto out_free; - overlay->reg_bo = to_intel_bo(reg_bo); + overlay->reg_bo = reg_bo; if (OVERLAY_NEEDS_PHYSICAL(dev)) { ret = i915_gem_attach_phys_object(dev, reg_bo, @@ -1423,14 +1421,14 @@ void intel_setup_overlay(struct drm_device *dev) DRM_ERROR("failed to attach phys overlay regs\n"); goto out_free_bo; } - overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr; + overlay->flip_addr = reg_bo->phys_obj->handle->busaddr; } else { ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin overlay register bo\n"); goto out_free_bo; } - overlay->flip_addr = overlay->reg_bo->gtt_offset; + overlay->flip_addr = reg_bo->gtt_offset; ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); if (ret) { @@ -1462,7 +1460,7 @@ void intel_setup_overlay(struct drm_device *dev) out_unpin_bo: i915_gem_object_unpin(reg_bo); out_free_bo: - drm_gem_object_unreference(reg_bo); + drm_gem_object_unreference(®_bo->base); out_free: kfree(overlay); return; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1db860d7989a..181aad31125d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -139,7 +139,7 @@ u32 intel_ring_get_active_head(struct intel_ring_buffer *ring) static int init_ring_common(struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = ring->dev->dev_private; - struct drm_i915_gem_object *obj_priv = to_intel_bo(ring->gem_object); + struct drm_i915_gem_object *obj = ring->obj; u32 head; /* Stop the ring if it's running. */ @@ -148,7 +148,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) ring->write_tail(ring, 0); /* Initialize the ring. */ - I915_WRITE_START(ring, obj_priv->gtt_offset); + I915_WRITE_START(ring, obj->gtt_offset); head = I915_READ_HEAD(ring) & HEAD_ADDR; /* G45 ring initialization fails to reset head to zero */ @@ -178,7 +178,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) /* If the head is still not zero, the ring is dead */ if ((I915_READ_CTL(ring) & RING_VALID) == 0 || - I915_READ_START(ring) != obj_priv->gtt_offset || + I915_READ_START(ring) != obj->gtt_offset || (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) { DRM_ERROR("%s initialization failed " "ctl %08x head %08x tail %08x start %08x\n", @@ -514,17 +514,15 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, static void cleanup_status_page(struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = ring->dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; obj = ring->status_page.obj; if (obj == NULL) return; - obj_priv = to_intel_bo(obj); - kunmap(obj_priv->pages[0]); + kunmap(obj->pages[0]); i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); ring->status_page.obj = NULL; memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); @@ -534,8 +532,7 @@ static int init_status_page(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; + struct drm_i915_gem_object *obj; int ret; obj = i915_gem_alloc_object(dev, 4096); @@ -544,16 +541,15 @@ static int init_status_page(struct intel_ring_buffer *ring) ret = -ENOMEM; goto err; } - obj_priv = to_intel_bo(obj); - obj_priv->agp_type = AGP_USER_CACHED_MEMORY; + obj->agp_type = AGP_USER_CACHED_MEMORY; ret = i915_gem_object_pin(obj, 4096, true); if (ret != 0) { goto err_unref; } - ring->status_page.gfx_addr = obj_priv->gtt_offset; - ring->status_page.page_addr = kmap(obj_priv->pages[0]); + ring->status_page.gfx_addr = obj->gtt_offset; + ring->status_page.page_addr = kmap(obj->pages[0]); if (ring->status_page.page_addr == NULL) { memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); goto err_unpin; @@ -570,7 +566,7 @@ static int init_status_page(struct intel_ring_buffer *ring) err_unpin: i915_gem_object_unpin(obj); err_unref: - drm_gem_object_unreference(obj); + drm_gem_object_unreference(&obj->base); err: return ret; } @@ -578,8 +574,7 @@ err: int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; int ret; ring->dev = dev; @@ -600,15 +595,14 @@ int intel_init_ring_buffer(struct drm_device *dev, goto err_hws; } - ring->gem_object = obj; + ring->obj = obj; ret = i915_gem_object_pin(obj, PAGE_SIZE, true); if (ret) goto err_unref; - obj_priv = to_intel_bo(obj); ring->map.size = ring->size; - ring->map.offset = dev->agp->base + obj_priv->gtt_offset; + ring->map.offset = dev->agp->base + obj->gtt_offset; ring->map.type = 0; ring->map.flags = 0; ring->map.mtrr = 0; @@ -632,8 +626,8 @@ err_unmap: err_unpin: i915_gem_object_unpin(obj); err_unref: - drm_gem_object_unreference(obj); - ring->gem_object = NULL; + drm_gem_object_unreference(&obj->base); + ring->obj = NULL; err_hws: cleanup_status_page(ring); return ret; @@ -644,7 +638,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) struct drm_i915_private *dev_priv; int ret; - if (ring->gem_object == NULL) + if (ring->obj == NULL) return; /* Disable the ring buffer. The ring must be idle at this point */ @@ -654,9 +648,9 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) drm_core_ioremapfree(&ring->map, ring->dev); - i915_gem_object_unpin(ring->gem_object); - drm_gem_object_unreference(ring->gem_object); - ring->gem_object = NULL; + i915_gem_object_unpin(ring->obj); + drm_gem_object_unreference(&ring->obj->base); + ring->obj = NULL; if (ring->cleanup) ring->cleanup(ring); @@ -902,11 +896,11 @@ static int blt_ring_init(struct intel_ring_buffer *ring) u32 *ptr; int ret; - obj = to_intel_bo(i915_gem_alloc_object(ring->dev, 4096)); + obj = i915_gem_alloc_object(ring->dev, 4096); if (obj == NULL) return -ENOMEM; - ret = i915_gem_object_pin(&obj->base, 4096, true); + ret = i915_gem_object_pin(obj, 4096, true); if (ret) { drm_gem_object_unreference(&obj->base); return ret; @@ -917,9 +911,9 @@ static int blt_ring_init(struct intel_ring_buffer *ring) *ptr++ = MI_NOOP; kunmap(obj->pages[0]); - ret = i915_gem_object_set_to_gtt_domain(&obj->base, false); + ret = i915_gem_object_set_to_gtt_domain(obj, false); if (ret) { - i915_gem_object_unpin(&obj->base); + i915_gem_object_unpin(obj); drm_gem_object_unreference(&obj->base); return ret; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2565d65a625b..1747e329ee94 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -4,7 +4,7 @@ struct intel_hw_status_page { u32 __iomem *page_addr; unsigned int gfx_addr; - struct drm_gem_object *obj; + struct drm_i915_gem_object *obj; }; #define I915_RING_READ(reg) i915_safe_read(dev_priv, reg) @@ -32,7 +32,7 @@ struct intel_ring_buffer { u32 mmio_base; void *virtual_start; struct drm_device *dev; - struct drm_gem_object *gem_object; + struct drm_i915_gem_object *obj; unsigned int head; unsigned int tail; -- cgit v1.2.3 From 92b88aeb1ad67417c002fdd77409771ca7e5433a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 9 Nov 2010 11:47:32 +0000 Subject: drm/i915: Not all mappable regions require GTT fence regions Combining map_and_fenceable revealed a bug in i915_gem_object_gtt_size() in that it always computed the appropriate fence size for the object regardless of tiling state which caused us to over-allocate linear buffers when binding to the GTT. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 53 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d196895527a6..8e3f1de681ed 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -41,9 +41,6 @@ struct change_domains { uint32_t flush_rings; }; -static uint32_t i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj); -static uint32_t i915_gem_get_gtt_size(struct drm_i915_gem_object *obj); - static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, bool pipelined); static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); @@ -1443,6 +1440,28 @@ i915_gem_free_mmap_offset(struct drm_i915_gem_object *obj) list->map = NULL; } +static uint32_t +i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + uint32_t size; + + if (INTEL_INFO(dev)->gen >= 4 || + obj->tiling_mode == I915_TILING_NONE) + return obj->base.size; + + /* Previous chips need a power-of-two fence region when tiling */ + if (INTEL_INFO(dev)->gen == 3) + size = 1024*1024; + else + size = 512*1024; + + while (size < obj->base.size) + size <<= 1; + + return size; +} + /** * i915_gem_get_gtt_alignment - return required GTT alignment for an object * @obj: object to check @@ -1505,34 +1524,6 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj) return tile_height * obj->stride * 2; } -static uint32_t -i915_gem_get_gtt_size(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - uint32_t size; - - /* - * Minimum alignment is 4k (GTT page size), but might be greater - * if a fence register is needed for the object. - */ - if (INTEL_INFO(dev)->gen >= 4) - return obj->base.size; - - /* - * Previous chips need to be aligned to the size of the smallest - * fence register that can contain the object. - */ - if (INTEL_INFO(dev)->gen == 3) - size = 1024*1024; - else - size = 512*1024; - - while (size < obj->base.size) - size <<= 1; - - return size; -} - /** * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing * @dev: DRM device -- cgit v1.2.3 From 7bdc9ab00b1b0fdbb490f41c5c7c2fbc66fed9ee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 9 Nov 2010 17:53:20 +0000 Subject: agp/intel: Remove duplicate const drivers/char/agp/intel-gtt.c:340:48: warning: duplicate const Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 5a2b7360f5be..8cf600cdac06 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -334,7 +334,7 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry, writel(addr | pte_flags, intel_private.gtt + entry); } -static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { +static const struct aper_size_info_fixed intel_fake_agp_sizes[] = { {32, 8192, 3}, {64, 16384, 4}, {128, 32768, 5}, -- cgit v1.2.3 From 748ebc6017a943ec065e653e975a5e8dace77ac6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 24 Oct 2010 10:28:47 +0100 Subject: drm/i915: Record fence registers on error. Having seen the effects of erroneous fencing on the batchbuffer, a useful sanity check is to record the fence registers at the time of an error. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1e8cd74d18d5..addb9392e1c4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -684,6 +684,9 @@ static int i915_error_state(struct seq_file *m, void *unused) seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); seq_printf(m, " seqno: 0x%08x\n", error->seqno); + for (i = 0; i < 16; i++) + seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); + if (error->active_bo) print_error_buffers(m, "Active", error->active_bo, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 22d6388b331f..699e71a0dab7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -166,6 +166,7 @@ struct drm_i915_error_state { u32 instdone1; u32 seqno; u64 bbaddr; + u64 fence[16]; struct timeval time; struct drm_i915_error_object { int page_count; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 09ac3bbd8165..de95c7bb6dba 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -581,6 +581,35 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err, return i; } +static void i915_gem_record_fences(struct drm_device *dev, + struct drm_i915_error_state *error) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + /* Fences */ + switch (INTEL_INFO(dev)->gen) { + case 6: + for (i = 0; i < 16; i++) + error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); + break; + case 5: + case 4: + for (i = 0; i < 16; i++) + error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); + break; + case 3: + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); + case 2: + for (i = 0; i < 8; i++) + error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); + break; + + } +} + /** * i915_capture_error_state - capture an error record for later analysis * @dev: drm device @@ -656,6 +685,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->acthd = I915_READ(ACTHD); error->bbaddr = 0; } + i915_gem_record_fences(dev, error); bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->render_ring); -- cgit v1.2.3 From b6913e4bdb09134dbdccd613e880d413b5911591 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 10:46:37 +0000 Subject: drm/i915: Move the implementation details of PIPE_CONTROL to the ringbuffer The pipe control object is allocated by the device for the sole use of the render ringbuffer. Move this detail from the general code to the render ring buffer initialisation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 3 - drivers/gpu/drm/i915/i915_gem.c | 70 +-------------------- drivers/gpu/drm/i915/intel_ringbuffer.c | 105 +++++++++++++++++++++++++++++--- 3 files changed, 97 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 699e71a0dab7..5afcf2a07cfc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -275,12 +275,9 @@ typedef struct drm_i915_private { uint32_t next_seqno; drm_dma_handle_t *status_page_dmah; - void *seqno_page; dma_addr_t dma_status_page; uint32_t counter; - unsigned int seqno_gfx_addr; drm_local_map_t hws_map; - struct drm_i915_gem_object *seqno_obj; struct drm_i915_gem_object *pwrctx; struct drm_i915_gem_object *renderctx; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8e3f1de681ed..027212e5c34a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4625,78 +4625,15 @@ i915_gem_idle(struct drm_device *dev) return 0; } -/* - * 965+ support PIPE_CONTROL commands, which provide finer grained control - * over cache flushing. - */ -static int -i915_gem_init_pipe_control(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj; - int ret; - - obj = i915_gem_alloc_object(dev, 4096); - if (obj == NULL) { - DRM_ERROR("Failed to allocate seqno page\n"); - ret = -ENOMEM; - goto err; - } - obj->agp_type = AGP_USER_CACHED_MEMORY; - - ret = i915_gem_object_pin(obj, 4096, true); - if (ret) - goto err_unref; - - dev_priv->seqno_gfx_addr = obj->gtt_offset; - dev_priv->seqno_page = kmap(obj->pages[0]); - if (dev_priv->seqno_page == NULL) - goto err_unpin; - - dev_priv->seqno_obj = obj; - memset(dev_priv->seqno_page, 0, PAGE_SIZE); - - return 0; - -err_unpin: - i915_gem_object_unpin(obj); -err_unref: - drm_gem_object_unreference(&obj->base); -err: - return ret; -} - - -static void -i915_gem_cleanup_pipe_control(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj; - - obj = dev_priv->seqno_obj; - kunmap(obj->pages[0]); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - dev_priv->seqno_obj = NULL; - - dev_priv->seqno_page = NULL; -} - int i915_gem_init_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; - if (HAS_PIPE_CONTROL(dev)) { - ret = i915_gem_init_pipe_control(dev); - if (ret) - return ret; - } - ret = intel_init_render_ring_buffer(dev); if (ret) - goto cleanup_pipe_control; + return ret; if (HAS_BSD(dev)) { ret = intel_init_bsd_ring_buffer(dev); @@ -4718,9 +4655,6 @@ cleanup_bsd_ring: intel_cleanup_ring_buffer(&dev_priv->bsd_ring); cleanup_render_ring: intel_cleanup_ring_buffer(&dev_priv->render_ring); -cleanup_pipe_control: - if (HAS_PIPE_CONTROL(dev)) - i915_gem_cleanup_pipe_control(dev); return ret; } @@ -4732,8 +4666,6 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) intel_cleanup_ring_buffer(&dev_priv->render_ring); intel_cleanup_ring_buffer(&dev_priv->bsd_ring); intel_cleanup_ring_buffer(&dev_priv->blt_ring); - if (HAS_PIPE_CONTROL(dev)) - i915_gem_cleanup_pipe_control(dev); } int diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 181aad31125d..b12578558268 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -202,6 +202,78 @@ static int init_ring_common(struct intel_ring_buffer *ring) return 0; } +/* + * 965+ support PIPE_CONTROL commands, which provide finer grained control + * over cache flushing. + */ +struct pipe_control { + struct drm_i915_gem_object *obj; + volatile u32 *cpu_page; + u32 gtt_offset; +}; + +static int +init_pipe_control(struct intel_ring_buffer *ring) +{ + struct pipe_control *pc; + struct drm_i915_gem_object *obj; + int ret; + + if (ring->private) + return 0; + + pc = kmalloc(sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + obj = i915_gem_alloc_object(ring->dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate seqno page\n"); + ret = -ENOMEM; + goto err; + } + obj->agp_type = AGP_USER_CACHED_MEMORY; + + ret = i915_gem_object_pin(obj, 4096, true); + if (ret) + goto err_unref; + + pc->gtt_offset = obj->gtt_offset; + pc->cpu_page = kmap(obj->pages[0]); + if (pc->cpu_page == NULL) + goto err_unpin; + + pc->obj = obj; + ring->private = pc; + return 0; + +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(&obj->base); +err: + kfree(pc); + return ret; +} + +static void +cleanup_pipe_control(struct intel_ring_buffer *ring) +{ + struct pipe_control *pc = ring->private; + struct drm_i915_gem_object *obj; + + if (!ring->private) + return; + + obj = pc->obj; + kunmap(obj->pages[0]); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + + kfree(pc); + ring->private = NULL; +} + static int init_render_ring(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -215,9 +287,23 @@ static int init_render_ring(struct intel_ring_buffer *ring) I915_WRITE(MI_MODE, mode); } + if (HAS_PIPE_CONTROL(dev)) { + ret = init_pipe_control(ring); + if (ret) + return ret; + } + return ret; } +static void render_ring_cleanup(struct intel_ring_buffer *ring) +{ + if (!ring->private) + return; + + cleanup_pipe_control(ring); +} + #define PIPE_CONTROL_FLUSH(ring__, addr__) \ do { \ intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ @@ -240,8 +326,8 @@ render_ring_add_request(struct intel_ring_buffer *ring, u32 *result) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; u32 seqno = i915_gem_get_seqno(dev); + struct pipe_control *pc = ring->private; int ret; if (IS_GEN6(dev)) { @@ -253,12 +339,12 @@ render_ring_add_request(struct intel_ring_buffer *ring, intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); intel_ring_emit(ring, seqno); intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); } else if (HAS_PIPE_CONTROL(dev)) { - u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; + u32 scratch_addr = pc->gtt_offset + 128; /* * Workaround qword write incoherence by flushing the @@ -271,7 +357,7 @@ render_ring_add_request(struct intel_ring_buffer *ring, intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); intel_ring_emit(ring, seqno); intel_ring_emit(ring, 0); PIPE_CONTROL_FLUSH(ring, scratch_addr); @@ -288,7 +374,7 @@ render_ring_add_request(struct intel_ring_buffer *ring, intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); intel_ring_emit(ring, seqno); intel_ring_emit(ring, 0); } else { @@ -312,10 +398,10 @@ static u32 render_ring_get_seqno(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - if (HAS_PIPE_CONTROL(dev)) - return ((volatile u32 *)(dev_priv->seqno_page))[0]; - else + if (HAS_PIPE_CONTROL(dev)) { + struct pipe_control *pc = ring->private; + return pc->cpu_page[0]; + } else return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } @@ -767,6 +853,7 @@ static const struct intel_ring_buffer render_ring = { .user_irq_get = render_ring_get_user_irq, .user_irq_put = render_ring_put_user_irq, .dispatch_execbuffer = render_ring_dispatch_execbuffer, + .cleanup = render_ring_cleanup, }; /* ring buffer for bit-stream decoder */ -- cgit v1.2.3 From dddbc0e5257572079602654258adc8d117e168ad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 13:56:11 +0000 Subject: drm/i915: Remove a defunct BUG_ON This used to check the precondition that all fences were to be located in a mappable area, redundant now as those two parameters are combined into one. After pinning, we assert that the buffer is bound into the desired region. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 027212e5c34a..7d6ce34789ca 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4248,7 +4248,6 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, int ret; BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); - BUG_ON(map_and_fenceable && !map_and_fenceable); WARN_ON(i915_verify_lists(dev)); if (obj->gtt_space != NULL) { -- cgit v1.2.3 From 576ae4b8e46b4cb9d5390f4348c265329793d9bf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 13:36:26 +0000 Subject: drm/i915: Extend hangcheck timeout ... reduce the frequency of checking to further reduce the wakeups and CPU overhead. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5afcf2a07cfc..eb3f1f756e81 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -315,7 +315,7 @@ typedef struct drm_i915_private { int num_pipe; /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */ +#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ struct timer_list hangcheck_timer; int hangcheck_count; uint32_t last_acthd; -- cgit v1.2.3 From 919926aeb3e89825093c743dd54f04e42e7d9150 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 13:42:53 +0000 Subject: drm/i915: Thread the pipelining ring through the callers. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 28 +++++++++++++--------------- drivers/gpu/drm/i915/intel_display.c | 6 +++--- drivers/gpu/drm/i915/intel_drv.h | 2 +- 4 files changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eb3f1f756e81..42d3e901619d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1133,7 +1133,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, int write); int i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, - bool pipelined); + struct intel_ring_buffer *pipelined); int i915_gem_attach_phys_object(struct drm_device *dev, struct drm_i915_gem_object *obj, int id, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7d6ce34789ca..465e07abf5d0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -42,11 +42,11 @@ struct change_domains { }; static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, - bool pipelined); + struct intel_ring_buffer *pipelined); static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj); static int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, - int write); + bool write); static int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, uint64_t offset, uint64_t size); @@ -1274,12 +1274,10 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) mutex_lock(&dev->struct_mutex); BUG_ON(obj->pin_count && !obj->pin_mappable); - if (obj->gtt_space) { - if (!obj->map_and_fenceable) { - ret = i915_gem_object_unbind(obj); - if (ret) - goto unlock; - } + if (!obj->map_and_fenceable) { + ret = i915_gem_object_unbind(obj); + if (ret) + goto unlock; } if (!obj->gtt_space) { @@ -2637,7 +2635,7 @@ i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, if (reg->gpu) { int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj, NULL); if (ret) return ret; @@ -2817,7 +2815,7 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) /** Flushes any GPU write domain for the object if it's dirty. */ static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, - bool pipelined) + struct intel_ring_buffer *pipelined) { struct drm_device *dev = obj->base.dev; @@ -2828,7 +2826,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, i915_gem_flush_ring(dev, obj->ring, 0, obj->base.write_domain); BUG_ON(obj->base.write_domain); - if (pipelined) + if (pipelined && pipelined == obj->ring) return 0; return i915_gem_object_wait_rendering(obj, true); @@ -2892,7 +2890,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, int write) if (obj->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj, false); + ret = i915_gem_object_flush_gpu_write_domain(obj, NULL); if (ret != 0) return ret; @@ -2931,7 +2929,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, int write) */ int i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, - bool pipelined) + struct intel_ring_buffer *pipelined) { uint32_t old_read_domains; int ret; @@ -2940,7 +2938,7 @@ i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, if (obj->gtt_space == NULL) return -EINVAL; - ret = i915_gem_object_flush_gpu_write_domain(obj, true); + ret = i915_gem_object_flush_gpu_write_domain(obj, pipelined); if (ret) return ret; @@ -2984,7 +2982,7 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, * flushes to occur. */ static int -i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, int write) +i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) { uint32_t old_write_domain, old_read_domains; int ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ae7d4f55ce07..c2c94a26f92e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1434,7 +1434,7 @@ out_disable: int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, - bool pipelined) + struct intel_ring_buffer *pipelined) { u32 alignment; int ret; @@ -1594,7 +1594,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, to_intel_framebuffer(crtc->fb)->obj, - false); + NULL); if (ret != 0) { mutex_unlock(&dev->struct_mutex); return ret; @@ -5092,7 +5092,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, obj = intel_fb->obj; mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj, true); + ret = intel_pin_and_fence_fb_obj(dev, obj, &dev_priv->render_ring); if (ret) goto cleanup_work; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5a4f14e36d6c..5154e315300d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -301,7 +301,7 @@ extern void intel_init_emon(struct drm_device *dev); extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, - bool pipelined); + struct intel_ring_buffer *pipelined); extern int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, -- cgit v1.2.3 From a7a09aebe8c0dd2b76c7b97018a9c614ddb483a5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 13:49:09 +0000 Subject: drm/i915: Rework execbuffer pinning Avoid evicting buffers that will be used later in the batch in order to make room for the initial buffers by pinning all bound buffers in a single pass before binding (and evicting for) fresh buffer. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 81 +++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 465e07abf5d0..061426e1bbf4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3531,44 +3531,75 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int ret, i, retry; - /* attempt to pin all of the buffers into the GTT */ + /* Attempt to pin all of the buffers into the GTT. + * This is done in 3 phases: + * + * 1a. Unbind all objects that do not match the GTT constraints for + * the execbuffer (fenceable, mappable, alignment etc). + * 1b. Increment pin count for already bound objects. + * 2. Bind new objects. + * 3. Decrement pin count. + * + * This avoid unnecessary unbinding of later objects in order to makr + * room for the earlier objects *unless* we need to defragment. + */ retry = 0; do { ret = 0; + + /* Unbind any ill-fitting objects or pin. */ for (i = 0; i < count; i++) { - struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; struct drm_i915_gem_object *obj = object_list[i]; - bool need_fence = + struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; + bool need_fence, need_mappable; + + if (!obj->gtt_space) + continue; + + need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; - - /* g33/pnv can't fence buffers in the unmappable part */ - bool need_mappable = + need_mappable = entry->relocation_count ? true : need_fence; - /* Check fence reg constraints and rebind if necessary */ - if (need_mappable && !obj->map_and_fenceable) { + if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) || + (need_mappable && !obj->map_and_fenceable)) ret = i915_gem_object_unbind(obj); + else + ret = i915_gem_object_pin(obj, + entry->alignment, + need_mappable); + if (ret) { + count = i; + goto err; + } + } + + /* Bind fresh objects */ + for (i = 0; i < count; i++) { + struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; + struct drm_i915_gem_object *obj = object_list[i]; + bool need_fence; + + need_fence = + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + + if (!obj->gtt_space) { + bool need_mappable = + entry->relocation_count ? true : need_fence; + + ret = i915_gem_object_pin(obj, + entry->alignment, + need_mappable); if (ret) break; } - ret = i915_gem_object_pin(obj, - entry->alignment, - need_mappable); - if (ret) - break; - - /* - * Pre-965 chips need a fence register set up in order - * to properly handle blits to/from tiled surfaces. - */ if (need_fence) { ret = i915_gem_object_get_fence_reg(obj, true); - if (ret) { - i915_gem_object_unpin(obj); + if (ret) break; - } dev_priv->fence_regs[obj->fence_reg].gpu = true; } @@ -3576,8 +3607,12 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, entry->offset = obj->gtt_offset; } - while (i--) - i915_gem_object_unpin(object_list[i]); +err: /* Decrement pin count for bound objects */ + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = object_list[i]; + if (obj->gtt_space) + i915_gem_object_unpin(obj); + } if (ret != -ENOSPC || retry > 1) return ret; -- cgit v1.2.3 From caea7476d48e5f401f2d18b1738827748fb56c12 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 13:53:37 +0000 Subject: drm/i915: More accurately track last fence usage by the GPU Based on a patch by Daniel Vetter. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +- drivers/gpu/drm/i915/i915_drv.h | 17 ++++-- drivers/gpu/drm/i915/i915_gem.c | 110 +++++++++++++++++++++--------------- 3 files changed, 78 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index addb9392e1c4..5faae476954c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -110,7 +110,7 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj) static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { - seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s", + seq_printf(m, "%p: %s%s %8zd %04x %04x %d %d%s%s", &obj->base, get_pin_flag(obj), get_tiling_flag(obj), @@ -118,6 +118,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) obj->base.read_domains, obj->base.write_domain, obj->last_rendering_seqno, + obj->last_fenced_seqno, obj->dirty ? " dirty" : "", obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); if (obj->base.name) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 42d3e901619d..ee7df1d2b8c8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -124,9 +124,8 @@ struct drm_i915_master_private { #define I915_FENCE_REG_NONE -1 struct drm_i915_fence_reg { - struct drm_i915_gem_object *obj; struct list_head lru_list; - bool gpu; + struct drm_i915_gem_object *obj; }; struct sdvo_device_mapping { @@ -787,6 +786,12 @@ struct drm_i915_gem_object { unsigned int fault_mappable : 1; unsigned int pin_mappable : 1; + /* + * Is the GPU currently using a fence to access this buffer, + */ + unsigned int pending_fenced_gpu_access:1; + unsigned int fenced_gpu_access:1; + struct page **pages; /** @@ -802,11 +807,13 @@ struct drm_i915_gem_object { */ uint32_t gtt_offset; - /* Which ring is refering to is this object */ - struct intel_ring_buffer *ring; - /** Breadcrumb of last rendering to the buffer. */ uint32_t last_rendering_seqno; + struct intel_ring_buffer *ring; + + /** Breadcrumb of last fenced GPU access to the buffer. */ + uint32_t last_fenced_seqno; + struct intel_ring_buffer *last_fenced_ring; /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 061426e1bbf4..2cfdee8811c4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1688,7 +1688,27 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, /* Move from whatever list we were on to the tail of execution. */ list_move_tail(&obj->mm_list, &dev_priv->mm.active_list); list_move_tail(&obj->ring_list, &ring->active_list); + obj->last_rendering_seqno = seqno; + if (obj->fenced_gpu_access) { + struct drm_i915_fence_reg *reg; + + BUG_ON(obj->fence_reg == I915_FENCE_REG_NONE); + + obj->last_fenced_seqno = seqno; + obj->last_fenced_ring = ring; + + reg = &dev_priv->fence_regs[obj->fence_reg]; + list_move_tail(®->lru_list, &dev_priv->mm.fence_list); + } +} + +static void +i915_gem_object_move_off_active(struct drm_i915_gem_object *obj) +{ + list_del_init(&obj->ring_list); + obj->last_rendering_seqno = 0; + obj->last_fenced_seqno = 0; } static void @@ -1699,8 +1719,33 @@ i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj) BUG_ON(!obj->active); list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list); - list_del_init(&obj->ring_list); - obj->last_rendering_seqno = 0; + + i915_gem_object_move_off_active(obj); +} + +static void +i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (obj->pin_count != 0) + list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); + else + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + + BUG_ON(!list_empty(&obj->gpu_write_list)); + BUG_ON(!obj->active); + obj->ring = NULL; + + i915_gem_object_move_off_active(obj); + obj->fenced_gpu_access = false; + obj->last_fenced_ring = NULL; + + obj->active = 0; + drm_gem_object_unreference(&obj->base); + + WARN_ON(i915_verify_lists(dev)); } /* Immediately discard the backing storage */ @@ -1729,35 +1774,11 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) return obj->madv == I915_MADV_DONTNEED; } -static void -i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - if (obj->pin_count != 0) - list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); - else - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - list_del_init(&obj->ring_list); - - BUG_ON(!list_empty(&obj->gpu_write_list)); - - obj->last_rendering_seqno = 0; - obj->ring = NULL; - if (obj->active) { - obj->active = 0; - drm_gem_object_unreference(&obj->base); - } - WARN_ON(i915_verify_lists(dev)); -} - static void i915_gem_process_flushing_list(struct drm_device *dev, uint32_t flush_domains, struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj, *next; list_for_each_entry_safe(obj, next, @@ -1770,14 +1791,6 @@ i915_gem_process_flushing_list(struct drm_device *dev, list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_active(obj, ring); - /* update the fence lru list */ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_fence_reg *reg = - &dev_priv->fence_regs[obj->fence_reg]; - list_move_tail(®->lru_list, - &dev_priv->mm.fence_list); - } - trace_i915_gem_object_change_domain(obj, obj->base.read_domains, old_write_domain); @@ -2615,8 +2628,7 @@ i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, bool interruptible) { struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg; + int ret; if (obj->fence_reg == I915_FENCE_REG_NONE) return 0; @@ -2631,19 +2643,23 @@ i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, * therefore we must wait for any outstanding access to complete * before clearing the fence. */ - reg = &dev_priv->fence_regs[obj->fence_reg]; - if (reg->gpu) { - int ret; - + if (obj->fenced_gpu_access) { ret = i915_gem_object_flush_gpu_write_domain(obj, NULL); if (ret) return ret; - ret = i915_gem_object_wait_rendering(obj, interruptible); + obj->fenced_gpu_access = false; + } + + if (obj->last_fenced_seqno) { + ret = i915_do_wait_request(dev, + obj->last_fenced_seqno, + interruptible, + obj->last_fenced_ring); if (ret) return ret; - reg->gpu = false; + obj->last_fenced_seqno = false; } i915_gem_object_flush_gtt_write_domain(obj); @@ -3166,8 +3182,9 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, * write domain */ if (obj->base.write_domain && - (obj->base.write_domain != obj->base.pending_read_domains || - obj->ring != ring)) { + (((obj->base.write_domain != obj->base.pending_read_domains || + obj->ring != ring)) || + (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) { flush_domains |= obj->base.write_domain; invalidate_domains |= obj->base.pending_read_domains & ~obj->base.write_domain; @@ -3528,7 +3545,6 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, struct drm_i915_gem_exec_object2 *exec_list, int count) { - struct drm_i915_private *dev_priv = dev->dev_private; int ret, i, retry; /* Attempt to pin all of the buffers into the GTT. @@ -3601,7 +3617,7 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, if (ret) break; - dev_priv->fence_regs[obj->fence_reg].gpu = true; + obj->pending_fenced_gpu_access = true; } entry->offset = obj->gtt_offset; @@ -3981,6 +3997,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } obj->in_execbuffer = true; + obj->pending_fenced_gpu_access = false; } /* Move the objects en-masse into the GTT, evicting if necessary. */ @@ -4085,6 +4102,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, obj->base.read_domains = obj->base.pending_read_domains; obj->base.write_domain = obj->base.pending_write_domain; + obj->fenced_gpu_access = obj->pending_fenced_gpu_access; i915_gem_object_move_to_active(obj, ring); if (obj->base.write_domain) { -- cgit v1.2.3 From b9e4b1e0cd401e915e3ba97afc152946f78f9f0b Mon Sep 17 00:00:00 2001 From: Dennis Kügler Date: Tue, 23 Nov 2010 21:40:09 +0100 Subject: HID: Add support for Perixx PERIBOARD-707 (Plus) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the media keys of the Perixx PERIBOARD-707 (Plus) keyboard / remote control. Signed-off-by: Dennis Kügler Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-topseed.c | 1 + drivers/hid/usbhid/hid-quirks.c | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 53ac909e2fff..dc56bd61edb7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1298,6 +1298,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 104b9f9a4c0b..d91bb12f9c54 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -162,6 +162,7 @@ #define USB_VENDOR_ID_CHICONY 0x04f2 #define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d +#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 #define USB_VENDOR_ID_CIDC 0x1677 diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 956ed9ac19d4..613ff7b1d746 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c @@ -66,6 +66,7 @@ static const struct hid_device_id ts_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { } }; MODULE_DEVICE_TABLE(hid, ts_devices); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 2c185477eeb3..76b9a149c7df 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -85,7 +85,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE }, { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT }, - + { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT }, { 0, 0 } }; -- cgit v1.2.3 From c6642782b988e907bb50767eab50042f4947e163 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Nov 2010 13:46:18 +0000 Subject: drm/i915: Add a mechanism for pipelining fence register updates Not employed just yet... Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 133 +++++++++++++++++++++++++++------------- drivers/gpu/drm/i915/i915_reg.h | 8 ++- 2 files changed, 98 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2cfdee8811c4..1e9cf2bf9ba4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2322,7 +2322,8 @@ i915_gpu_idle(struct drm_device *dev) return 0; } -static void sandybridge_write_fence_reg(struct drm_i915_gem_object *obj) +static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2331,7 +2332,7 @@ static void sandybridge_write_fence_reg(struct drm_i915_gem_object *obj) uint64_t val; val = (uint64_t)((obj->gtt_offset + size - 4096) & - 0xfffff000) << 32; + 0xfffff000) << 32; val |= obj->gtt_offset & 0xfffff000; val |= (uint64_t)((obj->stride / 128) - 1) << SANDYBRIDGE_FENCE_PITCH_SHIFT; @@ -2340,10 +2341,26 @@ static void sandybridge_write_fence_reg(struct drm_i915_gem_object *obj) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val); + if (pipelined) { + int ret = intel_ring_begin(pipelined, 6); + if (ret) + return ret; + + intel_ring_emit(pipelined, MI_NOOP); + intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2)); + intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8); + intel_ring_emit(pipelined, (u32)val); + intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8 + 4); + intel_ring_emit(pipelined, (u32)(val >> 32)); + intel_ring_advance(pipelined); + } else + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val); + + return 0; } -static void i965_write_fence_reg(struct drm_i915_gem_object *obj) +static int i965_write_fence_reg(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2359,27 +2376,41 @@ static void i965_write_fence_reg(struct drm_i915_gem_object *obj) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; - I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val); + if (pipelined) { + int ret = intel_ring_begin(pipelined, 6); + if (ret) + return ret; + + intel_ring_emit(pipelined, MI_NOOP); + intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2)); + intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8); + intel_ring_emit(pipelined, (u32)val); + intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8 + 4); + intel_ring_emit(pipelined, (u32)(val >> 32)); + intel_ring_advance(pipelined); + } else + I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val); + + return 0; } -static void i915_write_fence_reg(struct drm_i915_gem_object *obj) +static int i915_write_fence_reg(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 size = obj->gtt_space->size; - uint32_t fence_reg, val, pitch_val; + u32 fence_reg, val, pitch_val; int tile_width; - if ((obj->gtt_offset & ~I915_FENCE_START_MASK) || - (obj->gtt_offset & (size - 1))) { - WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n", - __func__, obj->gtt_offset, obj->map_and_fenceable, size, - obj->gtt_space->start, obj->gtt_space->size); - return; - } + if (WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) || + (size & -size) != size || + (obj->gtt_offset & (size - 1)), + "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", + obj->gtt_offset, obj->map_and_fenceable, size)) + return -EINVAL; - if (obj->tiling_mode == I915_TILING_Y && - HAS_128_BYTE_Y_TILING(dev)) + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) tile_width = 128; else tile_width = 512; @@ -2388,12 +2419,6 @@ static void i915_write_fence_reg(struct drm_i915_gem_object *obj) pitch_val = obj->stride / tile_width; pitch_val = ffs(pitch_val) - 1; - if (obj->tiling_mode == I915_TILING_Y && - HAS_128_BYTE_Y_TILING(dev)) - WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL); - else - WARN_ON(pitch_val > I915_FENCE_MAX_PITCH_VAL); - val = obj->gtt_offset; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; @@ -2406,10 +2431,25 @@ static void i915_write_fence_reg(struct drm_i915_gem_object *obj) fence_reg = FENCE_REG_830_0 + fence_reg * 4; else fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; - I915_WRITE(fence_reg, val); + + if (pipelined) { + int ret = intel_ring_begin(pipelined, 4); + if (ret) + return ret; + + intel_ring_emit(pipelined, MI_NOOP); + intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(pipelined, fence_reg); + intel_ring_emit(pipelined, val); + intel_ring_advance(pipelined); + } else + I915_WRITE(fence_reg, val); + + return 0; } -static void i830_write_fence_reg(struct drm_i915_gem_object *obj) +static int i830_write_fence_reg(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2417,29 +2457,38 @@ static void i830_write_fence_reg(struct drm_i915_gem_object *obj) int regnum = obj->fence_reg; uint32_t val; uint32_t pitch_val; - uint32_t fence_size_bits; - if ((obj->gtt_offset & ~I830_FENCE_START_MASK) || - (obj->gtt_offset & (obj->base.size - 1))) { - WARN(1, "%s: object 0x%08x not 512K or size aligned\n", - __func__, obj->gtt_offset); - return; - } + if (WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) || + (size & -size) != size || + (obj->gtt_offset & (size - 1)), + "object 0x%08x not 512K or pot-size 0x%08x aligned\n", + obj->gtt_offset, size)) + return -EINVAL; pitch_val = obj->stride / 128; pitch_val = ffs(pitch_val) - 1; - WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL); val = obj->gtt_offset; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; - fence_size_bits = I830_FENCE_SIZE_BITS(size); - WARN_ON(fence_size_bits & ~0x00000f00); - val |= fence_size_bits; + val |= I830_FENCE_SIZE_BITS(size); val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; - I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); + if (pipelined) { + int ret = intel_ring_begin(pipelined, 4); + if (ret) + return ret; + + intel_ring_emit(pipelined, MI_NOOP); + intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(pipelined, FENCE_REG_830_0 + regnum*4); + intel_ring_emit(pipelined, val); + intel_ring_advance(pipelined); + } else + I915_WRITE(FENCE_REG_830_0 + regnum * 4, val); + + return 0; } static int i915_find_fence_reg(struct drm_device *dev, @@ -2512,6 +2561,7 @@ i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_fence_reg *reg = NULL; + struct intel_ring_buffer *pipelined = NULL; int ret; /* Just update our place in the LRU if our fence is getting used. */ @@ -2553,25 +2603,24 @@ i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, switch (INTEL_INFO(dev)->gen) { case 6: - sandybridge_write_fence_reg(obj); + ret = sandybridge_write_fence_reg(obj, pipelined); break; case 5: case 4: - i965_write_fence_reg(obj); + ret = i965_write_fence_reg(obj, pipelined); break; case 3: - i915_write_fence_reg(obj); + ret = i915_write_fence_reg(obj, pipelined); break; case 2: - i830_write_fence_reg(obj); + ret = i830_write_fence_reg(obj, pipelined); break; } trace_i915_gem_object_get_fence(obj, obj->fence_reg, obj->tiling_mode); - - return 0; + return ret; } /** diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c668b2fb7e3d..ce97471d9c40 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -164,7 +164,13 @@ #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) #define MI_STORE_DWORD_INDEX_SHIFT 2 -#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1) +/* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM: + * - Always issue a MI_NOOP _before_ the MI_LOAD_REGISTER_IMM - otherwise hw + * simply ignores the register load under certain conditions. + * - One can actually load arbitrary many arbitrary registers: Simply issue x + * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! + */ +#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) #define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */ #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) -- cgit v1.2.3 From 312817a39f17dbb4de000165b5b724e3728cd91c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Nov 2010 11:50:11 +0000 Subject: drm/i915: Only save and restore fences for UMS With KMS, we can simply relinquish the fence when we idle the GPU and reassign it upon first use. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 25 ++++++----- drivers/gpu/drm/i915/i915_suspend.c | 89 +++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1e9cf2bf9ba4..939c9e34ce96 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1905,11 +1905,22 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, } } +static void i915_gem_reset_fences(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < 16; i++) { + struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; + if (reg->obj) + i915_gem_clear_fence_reg(reg->obj); + } +} + void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; - int i; i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring); i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring); @@ -1940,15 +1951,7 @@ void i915_gem_reset(struct drm_device *dev) } /* The fence registers are invalidated so clear them out */ - for (i = 0; i < 16; i++) { - struct drm_i915_fence_reg *reg; - - reg = &dev_priv->fence_regs[i]; - if (!reg->obj) - continue; - - i915_gem_clear_fence_reg(reg->obj); - } + i915_gem_reset_fences(dev); } /** @@ -4706,6 +4709,8 @@ i915_gem_idle(struct drm_device *dev) } } + i915_gem_reset_fences(dev); + /* Hack! Don't let anybody do execbuf while we don't control the chip. * We need to replace this with a semaphore, or something. * And not confound mm.suspended! diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 42729d25da58..011325e51e3a 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -235,6 +235,7 @@ static void i915_restore_vga(struct drm_device *dev) static void i915_save_modeset_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int i; if (drm_core_check_feature(dev, DRIVER_MODESET)) return; @@ -367,6 +368,28 @@ static void i915_save_modeset_reg(struct drm_device *dev) } i915_save_palette(dev, PIPE_B); dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); + + /* Fences */ + switch (INTEL_INFO(dev)->gen) { + case 6: + for (i = 0; i < 16; i++) + dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); + break; + case 5: + case 4: + for (i = 0; i < 16; i++) + dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); + break; + case 3: + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); + case 2: + for (i = 0; i < 8; i++) + dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); + break; + } + return; } @@ -375,10 +398,33 @@ static void i915_restore_modeset_reg(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int dpll_a_reg, fpa0_reg, fpa1_reg; int dpll_b_reg, fpb0_reg, fpb1_reg; + int i; if (drm_core_check_feature(dev, DRIVER_MODESET)) return; + /* Fences */ + switch (INTEL_INFO(dev)->gen) { + case 6: + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]); + break; + case 5: + case 4: + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]); + break; + case 3: + case 2: + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]); + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]); + break; + } + + if (HAS_PCH_SPLIT(dev)) { dpll_a_reg = PCH_DPLL_A; dpll_b_reg = PCH_DPLL_B; @@ -788,28 +834,6 @@ int i915_save_state(struct drm_device *dev) for (i = 0; i < 3; i++) dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 6: - for (i = 0; i < 16; i++) - dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); - break; - case 3: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); - case 2: - for (i = 0; i < 8; i++) - dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - break; - - } - return 0; } @@ -823,27 +847,6 @@ int i915_restore_state(struct drm_device *dev) /* Hardware status page */ I915_WRITE(HWS_PGA, dev_priv->saveHWS); - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 6: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]); - break; - case 3: - case 2: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]); - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]); - break; - } - i915_restore_display(dev); /* Interrupt state */ -- cgit v1.2.3 From ab5793ad3ae11a5cbe2194b449e5fdd80b19f14f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Nov 2010 13:24:13 +0000 Subject: drm/i915: Tweak on-error bbaddr parsing for clarity Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index de95c7bb6dba..9aa1e1dc5fd5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -525,26 +525,23 @@ i915_ringbuffer_last_batch(struct drm_device *dev, /* Locate the current position in the ringbuffer and walk back * to find the most recently dispatched batch buffer. */ - bbaddr = 0; head = I915_READ_HEAD(ring) & HEAD_ADDR; - val = (u32 *)(ring->virtual_start + head); + val = (u32 *)(ring->virtual_start + head); while (--val >= (u32 *)ring->virtual_start) { bbaddr = i915_get_bbaddr(dev, val); if (bbaddr) - break; + return bbaddr; } - if (bbaddr == 0) { - val = (u32 *)(ring->virtual_start + ring->size); - while (--val >= (u32 *)ring->virtual_start) { - bbaddr = i915_get_bbaddr(dev, val); - if (bbaddr) - break; - } + val = (u32 *)(ring->virtual_start + ring->size); + while (--val >= (u32 *)ring->virtual_start) { + bbaddr = i915_get_bbaddr(dev, val); + if (bbaddr) + return bbaddr; } - return bbaddr; + return 0; } static u32 capture_bo_list(struct drm_i915_error_buffer *err, -- cgit v1.2.3 From 2021746e1d5ad1e3b51e24480c566acbb833c7c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 23 Nov 2010 15:26:33 +0000 Subject: drm/i915: Mark a few functions as __must_check ... to benefit from the compiler checking that we remember to handle and propagate errors. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 77 ++++++++++++++++++++++------------------- drivers/gpu/drm/i915/i915_gem.c | 37 +++++++++----------- 2 files changed, 58 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ee7df1d2b8c8..b6ca10ade426 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1093,11 +1093,11 @@ int i915_gem_init_object(struct drm_gem_object *obj); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); -int i915_gem_object_pin(struct drm_i915_gem_object *obj, - uint32_t alignment, - bool map_and_fenceable); +int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, + uint32_t alignment, + bool map_and_fenceable); void i915_gem_object_unpin(struct drm_i915_gem_object *obj); -int i915_gem_object_unbind(struct drm_i915_gem_object *obj); +int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); @@ -1110,37 +1110,42 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } -int i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, - bool interruptible); -int i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, - bool interruptible); +int __must_check i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, + bool interruptible); +int __must_check i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, + bool interruptible); + void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset(struct drm_device *dev); void i915_gem_clflush_object(struct drm_i915_gem_object *obj); -int i915_gem_object_set_domain(struct drm_i915_gem_object *obj, - uint32_t read_domains, - uint32_t write_domain); -int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, - bool interruptible); -int i915_gem_init_ringbuffer(struct drm_device *dev); +int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj, + uint32_t read_domains, + uint32_t write_domain); +int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, + bool interruptible); +int __must_check i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); -int i915_gem_do_init(struct drm_device *dev, unsigned long start, - unsigned long mappable_end, unsigned long end); -int i915_gpu_idle(struct drm_device *dev); -int i915_gem_idle(struct drm_device *dev); -int i915_add_request(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring); -int i915_do_wait_request(struct drm_device *dev, - uint32_t seqno, - bool interruptible, - struct intel_ring_buffer *ring); +void i915_gem_do_init(struct drm_device *dev, + unsigned long start, + unsigned long mappable_end, + unsigned long end); +int __must_check i915_gpu_idle(struct drm_device *dev); +int __must_check i915_gem_idle(struct drm_device *dev); +int __must_check i915_add_request(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_i915_gem_request *request, + struct intel_ring_buffer *ring); +int __must_check i915_do_wait_request(struct drm_device *dev, + uint32_t seqno, + bool interruptible, + struct intel_ring_buffer *ring); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); -int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, - int write); -int i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined); +int __must_check +i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, + bool write); +int __must_check +i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined); int i915_gem_attach_phys_object(struct drm_device *dev, struct drm_i915_gem_object *obj, int id, @@ -1152,14 +1157,16 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file); /* i915_gem_gtt.c */ void i915_gem_restore_gtt_mappings(struct drm_device *dev); -int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); +int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); /* i915_gem_evict.c */ -int i915_gem_evict_something(struct drm_device *dev, int min_size, - unsigned alignment, bool mappable); -int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only); -int i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only); +int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size, + unsigned alignment, bool mappable); +int __must_check i915_gem_evict_everything(struct drm_device *dev, + bool purgeable_only); +int __must_check i915_gem_evict_inactive(struct drm_device *dev, + bool purgeable_only); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 939c9e34ce96..f6167c55a649 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -215,27 +215,19 @@ i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) return obj->gtt_space && !obj->active && obj->pin_count == 0; } -int i915_gem_do_init(struct drm_device *dev, - unsigned long start, - unsigned long mappable_end, - unsigned long end) +void i915_gem_do_init(struct drm_device *dev, + unsigned long start, + unsigned long mappable_end, + unsigned long end) { drm_i915_private_t *dev_priv = dev->dev_private; - if (start >= end || - (start & (PAGE_SIZE - 1)) != 0 || - (end & (PAGE_SIZE - 1)) != 0) { - return -EINVAL; - } - drm_mm_init(&dev_priv->mm.gtt_space, start, end - start); dev_priv->mm.gtt_total = end - start; dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; dev_priv->mm.gtt_mappable_end = mappable_end; - - return 0; } int @@ -243,13 +235,16 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_init *args = data; - int ret; + + if (args->gtt_start >= args->gtt_end || + (args->gtt_end | args->gtt_start) & (PAGE_SIZE - 1)) + return -EINVAL; mutex_lock(&dev->struct_mutex); - ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end, args->gtt_end); + i915_gem_do_init(dev, args->gtt_start, args->gtt_end, args->gtt_end); mutex_unlock(&dev->struct_mutex); - return ret; + return 0; } int @@ -2949,7 +2944,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) * flushes to occur. */ int -i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, int write) +i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) { uint32_t old_write_domain, old_read_domains; int ret; @@ -5177,8 +5172,8 @@ rescan: &dev_priv->mm.inactive_list, mm_list) { if (i915_gem_object_is_purgeable(obj)) { - i915_gem_object_unbind(obj); - if (--nr_to_scan == 0) + if (i915_gem_object_unbind(obj) == 0 && + --nr_to_scan == 0) break; } } @@ -5188,10 +5183,10 @@ rescan: list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) { - if (nr_to_scan) { - i915_gem_object_unbind(obj); + if (nr_to_scan && + i915_gem_object_unbind(obj) == 0) nr_to_scan--; - } else + else cnt++; } -- cgit v1.2.3 From 6299f992c0491232f008028a1f40bc9d86c4c76c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 24 Nov 2010 12:23:44 +0000 Subject: drm/i915: Defer accounting until read from debugfs Simply remove our accounting of objects inside the aperture, keeping only track of what is in the aperture and its current usage. This removes the over-complication of BUGs that were attempting to keep the accounting correct and also removes the overhead of the accounting on the hot-paths. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 84 +++++++++++++++++++---- drivers/gpu/drm/i915/i915_drv.h | 11 +--- drivers/gpu/drm/i915/i915_gem.c | 128 +++++++----------------------------- 3 files changed, 95 insertions(+), 128 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5faae476954c..3c9d4b876865 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -128,8 +128,15 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) if (obj->gtt_space != NULL) seq_printf(m, " (gtt offset: %08x, size: %08x)", obj->gtt_offset, (unsigned int)obj->gtt_space->size); - if (obj->pin_mappable || obj->fault_mappable) - seq_printf(m, " (mappable)"); + if (obj->pin_mappable || obj->fault_mappable) { + char s[3], *t = s; + if (obj->pin_mappable) + *t++ = 'p'; + if (obj->fault_mappable) + *t++ = 'f'; + *t = '\0'; + seq_printf(m, " (%s mappable)", s); + } if (obj->ring != NULL) seq_printf(m, " (%s)", obj->ring->name); } @@ -191,28 +198,79 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) return 0; } +#define count_objects(list, member) do { \ + list_for_each_entry(obj, list, member) { \ + size += obj->gtt_space->size; \ + ++count; \ + if (obj->map_and_fenceable) { \ + mappable_size += obj->gtt_space->size; \ + ++mappable_count; \ + } \ + } \ +} while(0) + static int i915_gem_object_info(struct seq_file *m, void* data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 count, mappable_count; + size_t size, mappable_size; + struct drm_i915_gem_object *obj; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - seq_printf(m, "%u objects\n", dev_priv->mm.object_count); - seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory); - seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count); - seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory); - seq_printf(m, "%u mappable objects in gtt\n", dev_priv->mm.gtt_mappable_count); - seq_printf(m, "%zu mappable gtt bytes\n", dev_priv->mm.gtt_mappable_memory); - seq_printf(m, "%zu mappable gtt used bytes\n", dev_priv->mm.mappable_gtt_used); - seq_printf(m, "%zu mappable gtt total\n", dev_priv->mm.mappable_gtt_total); - seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count); - seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory); - seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total); + seq_printf(m, "%u objects, %zu bytes\n", + dev_priv->mm.object_count, + dev_priv->mm.object_memory); + + size = count = mappable_size = mappable_count = 0; + count_objects(&dev_priv->mm.gtt_list, gtt_list); + seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n", + count, mappable_count, size, mappable_size); + + size = count = mappable_size = mappable_count = 0; + count_objects(&dev_priv->mm.active_list, mm_list); + count_objects(&dev_priv->mm.flushing_list, mm_list); + seq_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n", + count, mappable_count, size, mappable_size); + + size = count = mappable_size = mappable_count = 0; + count_objects(&dev_priv->mm.pinned_list, mm_list); + seq_printf(m, " %u [%u] pinned objects, %zu [%zu] bytes\n", + count, mappable_count, size, mappable_size); + + size = count = mappable_size = mappable_count = 0; + count_objects(&dev_priv->mm.inactive_list, mm_list); + seq_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n", + count, mappable_count, size, mappable_size); + + size = count = mappable_size = mappable_count = 0; + count_objects(&dev_priv->mm.deferred_free_list, mm_list); + seq_printf(m, " %u [%u] freed objects, %zu [%zu] bytes\n", + count, mappable_count, size, mappable_size); + + size = count = mappable_size = mappable_count = 0; + list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + if (obj->fault_mappable) { + size += obj->gtt_space->size; + ++count; + } + if (obj->pin_mappable) { + mappable_size += obj->gtt_space->size; + ++mappable_count; + } + } + seq_printf(m, "%u pinned mappable objects, %zu bytes\n", + mappable_count, mappable_size); + seq_printf(m, "%u fault mappable objects, %zu bytes\n", + count, size); + + seq_printf(m, "%zu [%zu] gtt total\n", + dev_priv->mm.gtt_total, dev_priv->mm.mappable_gtt_total); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b6ca10ade426..4ad34f9c55a2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -642,17 +642,10 @@ typedef struct drm_i915_private { struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; /* accounting, useful for userland debugging */ - size_t object_memory; - size_t pin_memory; - size_t gtt_memory; - size_t gtt_mappable_memory; - size_t mappable_gtt_used; - size_t mappable_gtt_total; size_t gtt_total; + size_t mappable_gtt_total; + size_t object_memory; u32 object_count; - u32 pin_count; - u32 gtt_mappable_count; - u32 gtt_count; } mm; struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f6167c55a649..7507a86c3feb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -83,80 +83,6 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, dev_priv->mm.object_memory -= size; } -static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *obj) -{ - dev_priv->mm.gtt_count++; - dev_priv->mm.gtt_memory += obj->gtt_space->size; - if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) { - dev_priv->mm.mappable_gtt_used += - min_t(size_t, obj->gtt_space->size, - dev_priv->mm.gtt_mappable_end - obj->gtt_offset); - } - list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list); -} - -static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *obj) -{ - dev_priv->mm.gtt_count--; - dev_priv->mm.gtt_memory -= obj->gtt_space->size; - if (obj->gtt_offset < dev_priv->mm.gtt_mappable_end) { - dev_priv->mm.mappable_gtt_used -= - min_t(size_t, obj->gtt_space->size, - dev_priv->mm.gtt_mappable_end - obj->gtt_offset); - } - list_del_init(&obj->gtt_list); -} - -/** - * Update the mappable working set counters. Call _only_ when there is a change - * in one of (pin|fault)_mappable and update *_mappable _before_ calling. - * @mappable: new state the changed mappable flag (either pin_ or fault_). - */ -static void -i915_gem_info_update_mappable(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *obj, - bool mappable) -{ - if (mappable) { - if (obj->pin_mappable && obj->fault_mappable) - /* Combined state was already mappable. */ - return; - dev_priv->mm.gtt_mappable_count++; - dev_priv->mm.gtt_mappable_memory += obj->gtt_space->size; - } else { - if (obj->pin_mappable || obj->fault_mappable) - /* Combined state still mappable. */ - return; - dev_priv->mm.gtt_mappable_count--; - dev_priv->mm.gtt_mappable_memory -= obj->gtt_space->size; - } -} - -static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *obj, - bool mappable) -{ - dev_priv->mm.pin_count++; - dev_priv->mm.pin_memory += obj->gtt_space->size; - if (mappable) { - obj->pin_mappable = true; - i915_gem_info_update_mappable(dev_priv, obj, true); - } -} - -static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *obj) -{ - dev_priv->mm.pin_count--; - dev_priv->mm.pin_memory -= obj->gtt_space->size; - if (obj->pin_mappable) { - obj->pin_mappable = false; - i915_gem_info_update_mappable(dev_priv, obj, false); - } -} - int i915_gem_check_is_wedged(struct drm_device *dev) { @@ -253,19 +179,24 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_get_aperture *args = data; + struct drm_i915_gem_object *obj; + size_t pinned; if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; + pinned = 0; mutex_lock(&dev->struct_mutex); - args->aper_size = dev_priv->mm.gtt_total; - args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory; + list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list) + pinned += obj->gtt_space->size; mutex_unlock(&dev->struct_mutex); + args->aper_size = dev_priv->mm.gtt_total; + args->aper_available_size = args->aper_size -pinned; + return 0; } - /** * Creates a new mm object and returns a handle to it. */ @@ -1267,14 +1198,12 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Now bind it into the GTT if needed */ mutex_lock(&dev->struct_mutex); - BUG_ON(obj->pin_count && !obj->pin_mappable); if (!obj->map_and_fenceable) { ret = i915_gem_object_unbind(obj); if (ret) goto unlock; } - if (!obj->gtt_space) { ret = i915_gem_object_bind_to_gtt(obj, 0, true); if (ret) @@ -1285,11 +1214,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (ret) goto unlock; - if (!obj->fault_mappable) { - obj->fault_mappable = true; - i915_gem_info_update_mappable(dev_priv, obj, true); - } - /* Need a new fence register? */ if (obj->tiling_mode != I915_TILING_NONE) { ret = i915_gem_object_get_fence_reg(obj, true); @@ -1300,6 +1224,8 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (i915_gem_object_is_inactive(obj)) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + obj->fault_mappable = true; + pfn = ((dev->agp->base + obj->gtt_offset) >> PAGE_SHIFT) + page_offset; @@ -1406,18 +1332,14 @@ out_free_list: void i915_gem_release_mmap(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + if (!obj->fault_mappable) + return; - if (unlikely(obj->base.map_list.map && dev->dev_mapping)) - unmap_mapping_range(dev->dev_mapping, - (loff_t)obj->base.map_list.hash.key<base.size, 1); + unmap_mapping_range(obj->base.dev->dev_mapping, + (loff_t)obj->base.map_list.hash.key<base.size, 1); - if (obj->fault_mappable) { - obj->fault_mappable = false; - i915_gem_info_update_mappable(dev_priv, obj, false); - } + obj->fault_mappable = false; } static void @@ -2221,8 +2143,6 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, int i915_gem_object_unbind(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; if (obj->gtt_space == NULL) @@ -2259,10 +2179,9 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) i915_gem_clear_fence_reg(obj); i915_gem_gtt_unbind_object(obj); - i915_gem_object_put_pages_gtt(obj); - i915_gem_info_remove_gtt(dev_priv, obj); + list_del_init(&obj->gtt_list); list_del_init(&obj->mm_list); /* Avoid an unnecessary call to unbind on rebind. */ obj->map_and_fenceable = true; @@ -2833,11 +2752,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, goto search_free; } - obj->gtt_offset = obj->gtt_space->start; - - /* keep track of bounds object by adding it to the inactive list */ + list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_add_gtt(dev_priv, obj); /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in @@ -2846,7 +2762,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); - trace_i915_gem_object_bind(obj, obj->gtt_offset, map_and_fenceable); + obj->gtt_offset = obj->gtt_space->start; fenceable = obj->gtt_space->size == fence_size && @@ -2857,6 +2773,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, obj->map_and_fenceable = mappable && fenceable; + trace_i915_gem_object_bind(obj, obj->gtt_offset, map_and_fenceable); return 0; } @@ -4372,12 +4289,11 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, } if (obj->pin_count++ == 0) { - i915_gem_info_add_pin(dev_priv, obj, map_and_fenceable); if (!obj->active) list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list); } - BUG_ON(!obj->pin_mappable && map_and_fenceable); + obj->pin_mappable |= map_and_fenceable; WARN_ON(i915_verify_lists(dev)); return 0; @@ -4397,7 +4313,7 @@ i915_gem_object_unpin(struct drm_i915_gem_object *obj) if (!obj->active) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - i915_gem_info_remove_pin(dev_priv, obj); + obj->pin_mappable = false; } WARN_ON(i915_verify_lists(dev)); } -- cgit v1.2.3 From 54cf91dc4e51fd5070a9a2346377493cc38a1ca9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 25 Nov 2010 18:00:26 +0000 Subject: drm/i915: Split i915_gem_execbuffer into its own file. A number of dragons have been seen lurking within the execbuffer code. The first step is then to isolate them from the rest and begin to scrutinise them in depth. Suggested by Daniel Vetter. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_drv.h | 18 + drivers/gpu/drm/i915/i915_gem.c | 1164 +--------------------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 1155 +++++++++++++++++++++++++++ 4 files changed, 1188 insertions(+), 1152 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_execbuffer.c (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b3cdb4fe46e0..0ae6a7c5020f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -8,8 +8,9 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ i915_suspend.o \ i915_gem.o \ i915_gem_debug.o \ - i915_gem_gtt.o \ i915_gem_evict.o \ + i915_gem_execbuffer.o \ + i915_gem_gtt.o \ i915_gem_tiling.o \ i915_trace_points.o \ intel_display.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4ad34f9c55a2..6c10b645dde9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1083,6 +1083,10 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); int i915_gem_init_object(struct drm_gem_object *obj); +void i915_gem_flush_ring(struct drm_device *dev, + struct intel_ring_buffer *ring, + uint32_t invalidate_domains, + uint32_t flush_domains); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); @@ -1094,6 +1098,12 @@ int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); +int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); +int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, + bool interruptible); +void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring); + /** * Returns true if seq1 is later than seq2. */ @@ -1103,6 +1113,14 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } +static inline u32 +i915_gem_next_request_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return ring->outstanding_lazy_request = dev_priv->next_seqno; +} + int __must_check i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, bool interruptible); int __must_check i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 7507a86c3feb..b30c6c167048 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,12 +35,6 @@ #include #include -struct change_domains { - uint32_t invalidate_domains; - uint32_t flush_domains; - uint32_t flush_rings; -}; - static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined); static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); @@ -51,8 +45,6 @@ static int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object uint64_t offset, uint64_t size); static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj); -static int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, - bool interruptible); static int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable); @@ -113,7 +105,7 @@ i915_gem_check_is_wedged(struct drm_device *dev) return -EIO; } -static int i915_mutex_lock_interruptible(struct drm_device *dev) +int i915_mutex_lock_interruptible(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -1577,15 +1569,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) obj->pages = NULL; } -static uint32_t -i915_gem_next_request_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - return ring->outstanding_lazy_request = dev_priv->next_seqno; -} - -static void +void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring) { @@ -1762,24 +1746,6 @@ i915_add_request(struct drm_device *dev, return 0; } -/** - * Command execution barrier - * - * Ensures that all commands in the ring are finished - * before signalling the CPU - */ -static void -i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) -{ - uint32_t flush_domains = 0; - - /* The sampler always gets flushed on i965 (sigh) */ - if (INTEL_INFO(dev)->gen >= 4) - flush_domains |= I915_GEM_DOMAIN_SAMPLER; - - ring->flush(ring, I915_GEM_DOMAIN_COMMAND, flush_domains); -} - static inline void i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) { @@ -2072,45 +2038,11 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno, return i915_do_wait_request(dev, seqno, 1, ring); } -static void -i915_gem_flush_ring(struct drm_device *dev, - struct intel_ring_buffer *ring, - uint32_t invalidate_domains, - uint32_t flush_domains) -{ - ring->flush(ring, invalidate_domains, flush_domains); - i915_gem_process_flushing_list(dev, flush_domains, ring); -} - -static void -i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains, - uint32_t flush_rings) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (flush_domains & I915_GEM_DOMAIN_CPU) - intel_gtt_chipset_flush(); - - if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { - if (flush_rings & RING_RENDER) - i915_gem_flush_ring(dev, &dev_priv->render_ring, - invalidate_domains, flush_domains); - if (flush_rings & RING_BSD) - i915_gem_flush_ring(dev, &dev_priv->bsd_ring, - invalidate_domains, flush_domains); - if (flush_rings & RING_BLT) - i915_gem_flush_ring(dev, &dev_priv->blt_ring, - invalidate_domains, flush_domains); - } -} - /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. */ -static int +int i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool interruptible) { @@ -2198,6 +2130,16 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) return ret; } +void +i915_gem_flush_ring(struct drm_device *dev, + struct intel_ring_buffer *ring, + uint32_t invalidate_domains, + uint32_t flush_domains) +{ + ring->flush(ring, invalidate_domains, flush_domains); + i915_gem_process_flushing_list(dev, flush_domains, ring); +} + static int i915_ring_idle(struct drm_device *dev, struct intel_ring_buffer *ring) { @@ -3014,174 +2956,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) return 0; } -/* - * Set the next domain for the specified object. This - * may not actually perform the necessary flushing/invaliding though, - * as that may want to be batched with other set_domain operations - * - * This is (we hope) the only really tricky part of gem. The goal - * is fairly simple -- track which caches hold bits of the object - * and make sure they remain coherent. A few concrete examples may - * help to explain how it works. For shorthand, we use the notation - * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the - * a pair of read and write domain masks. - * - * Case 1: the batch buffer - * - * 1. Allocated - * 2. Written by CPU - * 3. Mapped to GTT - * 4. Read by GPU - * 5. Unmapped from GTT - * 6. Freed - * - * Let's take these a step at a time - * - * 1. Allocated - * Pages allocated from the kernel may still have - * cache contents, so we set them to (CPU, CPU) always. - * 2. Written by CPU (using pwrite) - * The pwrite function calls set_domain (CPU, CPU) and - * this function does nothing (as nothing changes) - * 3. Mapped by GTT - * This function asserts that the object is not - * currently in any GPU-based read or write domains - * 4. Read by GPU - * i915_gem_execbuffer calls set_domain (COMMAND, 0). - * As write_domain is zero, this function adds in the - * current read domains (CPU+COMMAND, 0). - * flush_domains is set to CPU. - * invalidate_domains is set to COMMAND - * clflush is run to get data out of the CPU caches - * then i915_dev_set_domain calls i915_gem_flush to - * emit an MI_FLUSH and drm_agp_chipset_flush - * 5. Unmapped from GTT - * i915_gem_object_unbind calls set_domain (CPU, CPU) - * flush_domains and invalidate_domains end up both zero - * so no flushing/invalidating happens - * 6. Freed - * yay, done - * - * Case 2: The shared render buffer - * - * 1. Allocated - * 2. Mapped to GTT - * 3. Read/written by GPU - * 4. set_domain to (CPU,CPU) - * 5. Read/written by CPU - * 6. Read/written by GPU - * - * 1. Allocated - * Same as last example, (CPU, CPU) - * 2. Mapped to GTT - * Nothing changes (assertions find that it is not in the GPU) - * 3. Read/written by GPU - * execbuffer calls set_domain (RENDER, RENDER) - * flush_domains gets CPU - * invalidate_domains gets GPU - * clflush (obj) - * MI_FLUSH and drm_agp_chipset_flush - * 4. set_domain (CPU, CPU) - * flush_domains gets GPU - * invalidate_domains gets CPU - * wait_rendering (obj) to make sure all drawing is complete. - * This will include an MI_FLUSH to get the data from GPU - * to memory - * clflush (obj) to invalidate the CPU cache - * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?) - * 5. Read/written by CPU - * cache lines are loaded and dirtied - * 6. Read written by GPU - * Same as last GPU access - * - * Case 3: The constant buffer - * - * 1. Allocated - * 2. Written by CPU - * 3. Read by GPU - * 4. Updated (written) by CPU again - * 5. Read by GPU - * - * 1. Allocated - * (CPU, CPU) - * 2. Written by CPU - * (CPU, CPU) - * 3. Read by GPU - * (CPU+RENDER, 0) - * flush_domains = CPU - * invalidate_domains = RENDER - * clflush (obj) - * MI_FLUSH - * drm_agp_chipset_flush - * 4. Updated (written) by CPU again - * (CPU, CPU) - * flush_domains = 0 (no previous write domain) - * invalidate_domains = 0 (no new read domains) - * 5. Read by GPU - * (CPU+RENDER, 0) - * flush_domains = CPU - * invalidate_domains = RENDER - * clflush (obj) - * MI_FLUSH - * drm_agp_chipset_flush - */ -static void -i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring, - struct change_domains *cd) -{ - uint32_t invalidate_domains = 0, flush_domains = 0; - - /* - * If the object isn't moving to a new write domain, - * let the object stay in multiple read domains - */ - if (obj->base.pending_write_domain == 0) - obj->base.pending_read_domains |= obj->base.read_domains; - - /* - * Flush the current write domain if - * the new read domains don't match. Invalidate - * any read domains which differ from the old - * write domain - */ - if (obj->base.write_domain && - (((obj->base.write_domain != obj->base.pending_read_domains || - obj->ring != ring)) || - (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) { - flush_domains |= obj->base.write_domain; - invalidate_domains |= - obj->base.pending_read_domains & ~obj->base.write_domain; - } - /* - * Invalidate any read caches which may have - * stale data. That is, any new read domains. - */ - invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains; - if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) - i915_gem_clflush_object(obj); - - /* blow away mappings if mapped through GTT */ - if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT) - i915_gem_release_mmap(obj); - - /* The actual obj->write_domain will be updated with - * pending_write_domain after we emit the accumulated flush for all - * of our domain changes in execbuffers (which clears objects' - * write_domains). So if we have a current write domain that we - * aren't changing, set pending_write_domain to that. - */ - if (flush_domains == 0 && obj->base.pending_write_domain == 0) - obj->base.pending_write_domain = obj->base.write_domain; - - cd->invalidate_domains |= invalidate_domains; - cd->flush_domains |= flush_domains; - if (flush_domains & I915_GEM_GPU_DOMAINS) - cd->flush_rings |= obj->ring->id; - if (invalidate_domains & I915_GEM_GPU_DOMAINS) - cd->flush_rings |= ring->id; -} - /** * Moves the object from a partially CPU read to a full one. * @@ -3284,451 +3058,6 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, return 0; } -static int -i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, - struct drm_i915_gem_exec_object2 *entry, - struct drm_i915_gem_relocation_entry *reloc) -{ - struct drm_device *dev = obj->base.dev; - struct drm_gem_object *target_obj; - uint32_t target_offset; - int ret = -EINVAL; - - target_obj = drm_gem_object_lookup(dev, file_priv, - reloc->target_handle); - if (target_obj == NULL) - return -ENOENT; - - target_offset = to_intel_bo(target_obj)->gtt_offset; - -#if WATCH_RELOC - DRM_INFO("%s: obj %p offset %08x target %d " - "read %08x write %08x gtt %08x " - "presumed %08x delta %08x\n", - __func__, - obj, - (int) reloc->offset, - (int) reloc->target_handle, - (int) reloc->read_domains, - (int) reloc->write_domain, - (int) target_offset, - (int) reloc->presumed_offset, - reloc->delta); -#endif - - /* The target buffer should have appeared before us in the - * exec_object list, so it should have a GTT space bound by now. - */ - if (target_offset == 0) { - DRM_ERROR("No GTT space found for object %d\n", - reloc->target_handle); - goto err; - } - - /* Validate that the target is in a valid r/w GPU domain */ - if (reloc->write_domain & (reloc->write_domain - 1)) { - DRM_ERROR("reloc with multiple write domains: " - "obj %p target %d offset %d " - "read %08x write %08x", - obj, reloc->target_handle, - (int) reloc->offset, - reloc->read_domains, - reloc->write_domain); - goto err; - } - if (reloc->write_domain & I915_GEM_DOMAIN_CPU || - reloc->read_domains & I915_GEM_DOMAIN_CPU) { - DRM_ERROR("reloc with read/write CPU domains: " - "obj %p target %d offset %d " - "read %08x write %08x", - obj, reloc->target_handle, - (int) reloc->offset, - reloc->read_domains, - reloc->write_domain); - goto err; - } - if (reloc->write_domain && target_obj->pending_write_domain && - reloc->write_domain != target_obj->pending_write_domain) { - DRM_ERROR("Write domain conflict: " - "obj %p target %d offset %d " - "new %08x old %08x\n", - obj, reloc->target_handle, - (int) reloc->offset, - reloc->write_domain, - target_obj->pending_write_domain); - goto err; - } - - target_obj->pending_read_domains |= reloc->read_domains; - target_obj->pending_write_domain |= reloc->write_domain; - - /* If the relocation already has the right value in it, no - * more work needs to be done. - */ - if (target_offset == reloc->presumed_offset) - goto out; - - /* Check that the relocation address is valid... */ - if (reloc->offset > obj->base.size - 4) { - DRM_ERROR("Relocation beyond object bounds: " - "obj %p target %d offset %d size %d.\n", - obj, reloc->target_handle, - (int) reloc->offset, - (int) obj->base.size); - goto err; - } - if (reloc->offset & 3) { - DRM_ERROR("Relocation not 4-byte aligned: " - "obj %p target %d offset %d.\n", - obj, reloc->target_handle, - (int) reloc->offset); - goto err; - } - - /* and points to somewhere within the target object. */ - if (reloc->delta >= target_obj->size) { - DRM_ERROR("Relocation beyond target object bounds: " - "obj %p target %d delta %d size %d.\n", - obj, reloc->target_handle, - (int) reloc->delta, - (int) target_obj->size); - goto err; - } - - reloc->delta += target_offset; - if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) { - uint32_t page_offset = reloc->offset & ~PAGE_MASK; - char *vaddr; - - vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]); - *(uint32_t *)(vaddr + page_offset) = reloc->delta; - kunmap_atomic(vaddr); - } else { - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t __iomem *reloc_entry; - void __iomem *reloc_page; - - ret = i915_gem_object_set_to_gtt_domain(obj, 1); - if (ret) - goto err; - - /* Map the page containing the relocation we're going to perform. */ - reloc->offset += obj->gtt_offset; - reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, - reloc->offset & PAGE_MASK); - reloc_entry = (uint32_t __iomem *) - (reloc_page + (reloc->offset & ~PAGE_MASK)); - iowrite32(reloc->delta, reloc_entry); - io_mapping_unmap_atomic(reloc_page); - } - - /* and update the user's relocation entry */ - reloc->presumed_offset = target_offset; - -out: - ret = 0; -err: - drm_gem_object_unreference(target_obj); - return ret; -} - -static int -i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, - struct drm_i915_gem_exec_object2 *entry) -{ - struct drm_i915_gem_relocation_entry __user *user_relocs; - int i, ret; - - user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; - for (i = 0; i < entry->relocation_count; i++) { - struct drm_i915_gem_relocation_entry reloc; - - if (__copy_from_user_inatomic(&reloc, - user_relocs+i, - sizeof(reloc))) - return -EFAULT; - - ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &reloc); - if (ret) - return ret; - - if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset, - &reloc.presumed_offset, - sizeof(reloc.presumed_offset))) - return -EFAULT; - } - - return 0; -} - -static int -i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, - struct drm_i915_gem_exec_object2 *entry, - struct drm_i915_gem_relocation_entry *relocs) -{ - int i, ret; - - for (i = 0; i < entry->relocation_count; i++) { - ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &relocs[i]); - if (ret) - return ret; - } - - return 0; -} - -static int -i915_gem_execbuffer_relocate(struct drm_device *dev, - struct drm_file *file, - struct drm_i915_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, - int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - obj->base.pending_read_domains = 0; - obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate_object(obj, file, - &exec_list[i]); - if (ret) - return ret; - } - - return 0; -} - -static int -i915_gem_execbuffer_reserve(struct drm_device *dev, - struct drm_file *file, - struct drm_i915_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, - int count) -{ - int ret, i, retry; - - /* Attempt to pin all of the buffers into the GTT. - * This is done in 3 phases: - * - * 1a. Unbind all objects that do not match the GTT constraints for - * the execbuffer (fenceable, mappable, alignment etc). - * 1b. Increment pin count for already bound objects. - * 2. Bind new objects. - * 3. Decrement pin count. - * - * This avoid unnecessary unbinding of later objects in order to makr - * room for the earlier objects *unless* we need to defragment. - */ - retry = 0; - do { - ret = 0; - - /* Unbind any ill-fitting objects or pin. */ - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; - bool need_fence, need_mappable; - - if (!obj->gtt_space) - continue; - - need_fence = - entry->flags & EXEC_OBJECT_NEEDS_FENCE && - obj->tiling_mode != I915_TILING_NONE; - need_mappable = - entry->relocation_count ? true : need_fence; - - if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) || - (need_mappable && !obj->map_and_fenceable)) - ret = i915_gem_object_unbind(obj); - else - ret = i915_gem_object_pin(obj, - entry->alignment, - need_mappable); - if (ret) { - count = i; - goto err; - } - } - - /* Bind fresh objects */ - for (i = 0; i < count; i++) { - struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; - struct drm_i915_gem_object *obj = object_list[i]; - bool need_fence; - - need_fence = - entry->flags & EXEC_OBJECT_NEEDS_FENCE && - obj->tiling_mode != I915_TILING_NONE; - - if (!obj->gtt_space) { - bool need_mappable = - entry->relocation_count ? true : need_fence; - - ret = i915_gem_object_pin(obj, - entry->alignment, - need_mappable); - if (ret) - break; - } - - if (need_fence) { - ret = i915_gem_object_get_fence_reg(obj, true); - if (ret) - break; - - obj->pending_fenced_gpu_access = true; - } - - entry->offset = obj->gtt_offset; - } - -err: /* Decrement pin count for bound objects */ - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - if (obj->gtt_space) - i915_gem_object_unpin(obj); - } - - if (ret != -ENOSPC || retry > 1) - return ret; - - /* First attempt, just clear anything that is purgeable. - * Second attempt, clear the entire GTT. - */ - ret = i915_gem_evict_everything(dev, retry == 0); - if (ret) - return ret; - - retry++; - } while (1); -} - -static int -i915_gem_execbuffer_relocate_slow(struct drm_device *dev, - struct drm_file *file, - struct drm_i915_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, - int count) -{ - struct drm_i915_gem_relocation_entry *reloc; - int i, total, ret; - - for (i = 0; i < count; i++) - object_list[i]->in_execbuffer = false; - - mutex_unlock(&dev->struct_mutex); - - total = 0; - for (i = 0; i < count; i++) - total += exec_list[i].relocation_count; - - reloc = drm_malloc_ab(total, sizeof(*reloc)); - if (reloc == NULL) { - mutex_lock(&dev->struct_mutex); - return -ENOMEM; - } - - total = 0; - for (i = 0; i < count; i++) { - struct drm_i915_gem_relocation_entry __user *user_relocs; - - user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; - - if (copy_from_user(reloc+total, user_relocs, - exec_list[i].relocation_count * - sizeof(*reloc))) { - ret = -EFAULT; - mutex_lock(&dev->struct_mutex); - goto err; - } - - total += exec_list[i].relocation_count; - } - - ret = i915_mutex_lock_interruptible(dev); - if (ret) { - mutex_lock(&dev->struct_mutex); - goto err; - } - - ret = i915_gem_execbuffer_reserve(dev, file, - object_list, exec_list, - count); - if (ret) - goto err; - - total = 0; - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - obj->base.pending_read_domains = 0; - obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate_object_slow(obj, file, - &exec_list[i], - reloc + total); - if (ret) - goto err; - - total += exec_list[i].relocation_count; - } - - /* Leave the user relocations as are, this is the painfully slow path, - * and we want to avoid the complication of dropping the lock whilst - * having buffers reserved in the aperture and so causing spurious - * ENOSPC for random operations. - */ - -err: - drm_free_large(reloc); - return ret; -} - -static int -i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, - struct drm_file *file, - struct intel_ring_buffer *ring, - struct drm_i915_gem_object **objects, - int count) -{ - struct change_domains cd; - int ret, i; - - cd.invalidate_domains = 0; - cd.flush_domains = 0; - cd.flush_rings = 0; - for (i = 0; i < count; i++) - i915_gem_object_set_to_gpu_domain(objects[i], ring, &cd); - - if (cd.invalidate_domains | cd.flush_domains) { -#if WATCH_EXEC - DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", - __func__, - cd.invalidate_domains, - cd.flush_domains); -#endif - i915_gem_flush(dev, - cd.invalidate_domains, - cd.flush_domains, - cd.flush_rings); - } - - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = objects[i]; - /* XXX replace with semaphores */ - if (obj->ring && ring != obj->ring) { - ret = i915_gem_object_wait_rendering(obj, true); - if (ret) - return ret; - } - } - - return 0; -} - /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * @@ -3786,473 +3115,6 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) return ret; } -static int -i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec, - uint64_t exec_offset) -{ - uint32_t exec_start, exec_len; - - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - exec_len = (uint32_t) exec->batch_len; - - if ((exec_start | exec_len) & 0x7) - return -EINVAL; - - if (!exec_start) - return -EINVAL; - - return 0; -} - -static int -validate_exec_list(struct drm_i915_gem_exec_object2 *exec, - int count) -{ - int i; - - for (i = 0; i < count; i++) { - char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; - int length; /* limited by fault_in_pages_readable() */ - - /* First check for malicious input causing overflow */ - if (exec[i].relocation_count > - INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) - return -EINVAL; - - length = exec[i].relocation_count * - sizeof(struct drm_i915_gem_relocation_entry); - if (!access_ok(VERIFY_READ, ptr, length)) - return -EFAULT; - - /* we may also need to update the presumed offsets */ - if (!access_ok(VERIFY_WRITE, ptr, length)) - return -EFAULT; - - if (fault_in_pages_readable(ptr, length)) - return -EFAULT; - } - - return 0; -} - -static int -i915_gem_do_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file, - struct drm_i915_gem_execbuffer2 *args, - struct drm_i915_gem_exec_object2 *exec_list) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object **object_list = NULL; - struct drm_i915_gem_object *batch_obj; - struct drm_clip_rect *cliprects = NULL; - struct drm_i915_gem_request *request = NULL; - int ret, i, flips; - uint64_t exec_offset; - - struct intel_ring_buffer *ring = NULL; - - ret = i915_gem_check_is_wedged(dev); - if (ret) - return ret; - - ret = validate_exec_list(exec_list, args->buffer_count); - if (ret) - return ret; - -#if WATCH_EXEC - DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", - (int) args->buffers_ptr, args->buffer_count, args->batch_len); -#endif - switch (args->flags & I915_EXEC_RING_MASK) { - case I915_EXEC_DEFAULT: - case I915_EXEC_RENDER: - ring = &dev_priv->render_ring; - break; - case I915_EXEC_BSD: - if (!HAS_BSD(dev)) { - DRM_ERROR("execbuf with invalid ring (BSD)\n"); - return -EINVAL; - } - ring = &dev_priv->bsd_ring; - break; - case I915_EXEC_BLT: - if (!HAS_BLT(dev)) { - DRM_ERROR("execbuf with invalid ring (BLT)\n"); - return -EINVAL; - } - ring = &dev_priv->blt_ring; - break; - default: - DRM_ERROR("execbuf with unknown ring: %d\n", - (int)(args->flags & I915_EXEC_RING_MASK)); - return -EINVAL; - } - - if (args->buffer_count < 1) { - DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); - return -EINVAL; - } - object_list = drm_malloc_ab(sizeof(*object_list), args->buffer_count); - if (object_list == NULL) { - DRM_ERROR("Failed to allocate object list for %d buffers\n", - args->buffer_count); - ret = -ENOMEM; - goto pre_mutex_err; - } - - if (args->num_cliprects != 0) { - cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), - GFP_KERNEL); - if (cliprects == NULL) { - ret = -ENOMEM; - goto pre_mutex_err; - } - - ret = copy_from_user(cliprects, - (struct drm_clip_rect __user *) - (uintptr_t) args->cliprects_ptr, - sizeof(*cliprects) * args->num_cliprects); - if (ret != 0) { - DRM_ERROR("copy %d cliprects failed: %d\n", - args->num_cliprects, ret); - ret = -EFAULT; - goto pre_mutex_err; - } - } - - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) { - ret = -ENOMEM; - goto pre_mutex_err; - } - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto pre_mutex_err; - - if (dev_priv->mm.suspended) { - mutex_unlock(&dev->struct_mutex); - ret = -EBUSY; - goto pre_mutex_err; - } - - /* Look up object handles */ - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj; - - obj = to_intel_bo (drm_gem_object_lookup(dev, file, - exec_list[i].handle)); - if (obj == NULL) { - DRM_ERROR("Invalid object handle %d at index %d\n", - exec_list[i].handle, i); - /* prevent error path from reading uninitialized data */ - args->buffer_count = i; - ret = -ENOENT; - goto err; - } - object_list[i] = obj; - - if (obj->in_execbuffer) { - DRM_ERROR("Object %p appears more than once in object list\n", - obj); - /* prevent error path from reading uninitialized data */ - args->buffer_count = i + 1; - ret = -EINVAL; - goto err; - } - obj->in_execbuffer = true; - obj->pending_fenced_gpu_access = false; - } - - /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(dev, file, - object_list, exec_list, - args->buffer_count); - if (ret) - goto err; - - /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, file, - object_list, exec_list, - args->buffer_count); - if (ret) { - if (ret == -EFAULT) { - ret = i915_gem_execbuffer_relocate_slow(dev, file, - object_list, - exec_list, - args->buffer_count); - BUG_ON(!mutex_is_locked(&dev->struct_mutex)); - } - if (ret) - goto err; - } - - /* Set the pending read domains for the batch buffer to COMMAND */ - batch_obj = object_list[args->buffer_count-1]; - if (batch_obj->base.pending_write_domain) { - DRM_ERROR("Attempting to use self-modifying batch buffer\n"); - ret = -EINVAL; - goto err; - } - batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; - - /* Sanity check the batch buffer */ - exec_offset = batch_obj->gtt_offset; - ret = i915_gem_check_execbuffer(args, exec_offset); - if (ret != 0) { - DRM_ERROR("execbuf with invalid offset/length\n"); - goto err; - } - - ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring, - object_list, args->buffer_count); - if (ret) - goto err; - -#if WATCH_COHERENCY - for (i = 0; i < args->buffer_count; i++) { - i915_gem_object_check_coherency(object_list[i], - exec_list[i].handle); - } -#endif - -#if WATCH_EXEC - i915_gem_dump_object(batch_obj, - args->batch_len, - __func__, - ~0); -#endif - - /* Check for any pending flips. As we only maintain a flip queue depth - * of 1, we can simply insert a WAIT for the next display flip prior - * to executing the batch and avoid stalling the CPU. - */ - flips = 0; - for (i = 0; i < args->buffer_count; i++) { - if (object_list[i]->base.write_domain) - flips |= atomic_read(&object_list[i]->pending_flip); - } - if (flips) { - int plane, flip_mask; - - for (plane = 0; flips >> plane; plane++) { - if (((flips >> plane) & 1) == 0) - continue; - - if (plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - - ret = intel_ring_begin(ring, 2); - if (ret) - goto err; - - intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } - } - - /* Exec the batchbuffer */ - ret = ring->dispatch_execbuffer(ring, args, cliprects, exec_offset); - if (ret) { - DRM_ERROR("dispatch failed %d\n", ret); - goto err; - } - - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - - obj->base.read_domains = obj->base.pending_read_domains; - obj->base.write_domain = obj->base.pending_write_domain; - obj->fenced_gpu_access = obj->pending_fenced_gpu_access; - - i915_gem_object_move_to_active(obj, ring); - if (obj->base.write_domain) { - obj->dirty = 1; - list_move_tail(&obj->gpu_write_list, - &ring->gpu_write_list); - intel_mark_busy(dev, obj); - } - - trace_i915_gem_object_change_domain(obj, - obj->base.read_domains, - obj->base.write_domain); - } - - /* - * Ensure that the commands in the batch buffer are - * finished before the interrupt fires - */ - i915_retire_commands(dev, ring); - - if (i915_add_request(dev, file, request, ring)) - i915_gem_next_request_seqno(dev, ring); - else - request = NULL; - -err: - for (i = 0; i < args->buffer_count; i++) { - object_list[i]->in_execbuffer = false; - drm_gem_object_unreference(&object_list[i]->base); - } - - mutex_unlock(&dev->struct_mutex); - -pre_mutex_err: - drm_free_large(object_list); - kfree(cliprects); - kfree(request); - - return ret; -} - -/* - * Legacy execbuffer just creates an exec2 list from the original exec object - * list array and passes it to the real function. - */ -int -i915_gem_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_i915_gem_execbuffer *args = data; - struct drm_i915_gem_execbuffer2 exec2; - struct drm_i915_gem_exec_object *exec_list = NULL; - struct drm_i915_gem_exec_object2 *exec2_list = NULL; - int ret, i; - -#if WATCH_EXEC - DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", - (int) args->buffers_ptr, args->buffer_count, args->batch_len); -#endif - - if (args->buffer_count < 1) { - DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); - return -EINVAL; - } - - /* Copy in the exec list from userland */ - exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count); - exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); - if (exec_list == NULL || exec2_list == NULL) { - DRM_ERROR("Failed to allocate exec list for %d buffers\n", - args->buffer_count); - drm_free_large(exec_list); - drm_free_large(exec2_list); - return -ENOMEM; - } - ret = copy_from_user(exec_list, - (struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, - sizeof(*exec_list) * args->buffer_count); - if (ret != 0) { - DRM_ERROR("copy %d exec entries failed %d\n", - args->buffer_count, ret); - drm_free_large(exec_list); - drm_free_large(exec2_list); - return -EFAULT; - } - - for (i = 0; i < args->buffer_count; i++) { - exec2_list[i].handle = exec_list[i].handle; - exec2_list[i].relocation_count = exec_list[i].relocation_count; - exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr; - exec2_list[i].alignment = exec_list[i].alignment; - exec2_list[i].offset = exec_list[i].offset; - if (INTEL_INFO(dev)->gen < 4) - exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; - else - exec2_list[i].flags = 0; - } - - exec2.buffers_ptr = args->buffers_ptr; - exec2.buffer_count = args->buffer_count; - exec2.batch_start_offset = args->batch_start_offset; - exec2.batch_len = args->batch_len; - exec2.DR1 = args->DR1; - exec2.DR4 = args->DR4; - exec2.num_cliprects = args->num_cliprects; - exec2.cliprects_ptr = args->cliprects_ptr; - exec2.flags = I915_EXEC_RENDER; - - ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list); - if (!ret) { - /* Copy the new buffer offsets back to the user's exec list. */ - for (i = 0; i < args->buffer_count; i++) - exec_list[i].offset = exec2_list[i].offset; - /* ... and back out to userspace */ - ret = copy_to_user((struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, - exec_list, - sizeof(*exec_list) * args->buffer_count); - if (ret) { - ret = -EFAULT; - DRM_ERROR("failed to copy %d exec entries " - "back to user (%d)\n", - args->buffer_count, ret); - } - } - - drm_free_large(exec_list); - drm_free_large(exec2_list); - return ret; -} - -int -i915_gem_execbuffer2(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_i915_gem_execbuffer2 *args = data; - struct drm_i915_gem_exec_object2 *exec2_list = NULL; - int ret; - -#if WATCH_EXEC - DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", - (int) args->buffers_ptr, args->buffer_count, args->batch_len); -#endif - - if (args->buffer_count < 1) { - DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count); - return -EINVAL; - } - - exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); - if (exec2_list == NULL) { - DRM_ERROR("Failed to allocate exec list for %d buffers\n", - args->buffer_count); - return -ENOMEM; - } - ret = copy_from_user(exec2_list, - (struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, - sizeof(*exec2_list) * args->buffer_count); - if (ret != 0) { - DRM_ERROR("copy %d exec entries failed %d\n", - args->buffer_count, ret); - drm_free_large(exec2_list); - return -EFAULT; - } - - ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); - if (!ret) { - /* Copy the new buffer offsets back to the user's exec list. */ - ret = copy_to_user((struct drm_i915_relocation_entry __user *) - (uintptr_t) args->buffers_ptr, - exec2_list, - sizeof(*exec2_list) * args->buffer_count); - if (ret) { - ret = -EFAULT; - DRM_ERROR("failed to copy %d exec entries " - "back to user (%d)\n", - args->buffer_count, ret); - } - } - - drm_free_large(exec2_list); - return ret; -} - int i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c new file mode 100644 index 000000000000..bdc613b91af8 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -0,0 +1,1155 @@ +/* + * Copyright © 2008,2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" + +struct change_domains { + uint32_t invalidate_domains; + uint32_t flush_domains; + uint32_t flush_rings; +}; + +/* + * Set the next domain for the specified object. This + * may not actually perform the necessary flushing/invaliding though, + * as that may want to be batched with other set_domain operations + * + * This is (we hope) the only really tricky part of gem. The goal + * is fairly simple -- track which caches hold bits of the object + * and make sure they remain coherent. A few concrete examples may + * help to explain how it works. For shorthand, we use the notation + * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the + * a pair of read and write domain masks. + * + * Case 1: the batch buffer + * + * 1. Allocated + * 2. Written by CPU + * 3. Mapped to GTT + * 4. Read by GPU + * 5. Unmapped from GTT + * 6. Freed + * + * Let's take these a step at a time + * + * 1. Allocated + * Pages allocated from the kernel may still have + * cache contents, so we set them to (CPU, CPU) always. + * 2. Written by CPU (using pwrite) + * The pwrite function calls set_domain (CPU, CPU) and + * this function does nothing (as nothing changes) + * 3. Mapped by GTT + * This function asserts that the object is not + * currently in any GPU-based read or write domains + * 4. Read by GPU + * i915_gem_execbuffer calls set_domain (COMMAND, 0). + * As write_domain is zero, this function adds in the + * current read domains (CPU+COMMAND, 0). + * flush_domains is set to CPU. + * invalidate_domains is set to COMMAND + * clflush is run to get data out of the CPU caches + * then i915_dev_set_domain calls i915_gem_flush to + * emit an MI_FLUSH and drm_agp_chipset_flush + * 5. Unmapped from GTT + * i915_gem_object_unbind calls set_domain (CPU, CPU) + * flush_domains and invalidate_domains end up both zero + * so no flushing/invalidating happens + * 6. Freed + * yay, done + * + * Case 2: The shared render buffer + * + * 1. Allocated + * 2. Mapped to GTT + * 3. Read/written by GPU + * 4. set_domain to (CPU,CPU) + * 5. Read/written by CPU + * 6. Read/written by GPU + * + * 1. Allocated + * Same as last example, (CPU, CPU) + * 2. Mapped to GTT + * Nothing changes (assertions find that it is not in the GPU) + * 3. Read/written by GPU + * execbuffer calls set_domain (RENDER, RENDER) + * flush_domains gets CPU + * invalidate_domains gets GPU + * clflush (obj) + * MI_FLUSH and drm_agp_chipset_flush + * 4. set_domain (CPU, CPU) + * flush_domains gets GPU + * invalidate_domains gets CPU + * wait_rendering (obj) to make sure all drawing is complete. + * This will include an MI_FLUSH to get the data from GPU + * to memory + * clflush (obj) to invalidate the CPU cache + * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?) + * 5. Read/written by CPU + * cache lines are loaded and dirtied + * 6. Read written by GPU + * Same as last GPU access + * + * Case 3: The constant buffer + * + * 1. Allocated + * 2. Written by CPU + * 3. Read by GPU + * 4. Updated (written) by CPU again + * 5. Read by GPU + * + * 1. Allocated + * (CPU, CPU) + * 2. Written by CPU + * (CPU, CPU) + * 3. Read by GPU + * (CPU+RENDER, 0) + * flush_domains = CPU + * invalidate_domains = RENDER + * clflush (obj) + * MI_FLUSH + * drm_agp_chipset_flush + * 4. Updated (written) by CPU again + * (CPU, CPU) + * flush_domains = 0 (no previous write domain) + * invalidate_domains = 0 (no new read domains) + * 5. Read by GPU + * (CPU+RENDER, 0) + * flush_domains = CPU + * invalidate_domains = RENDER + * clflush (obj) + * MI_FLUSH + * drm_agp_chipset_flush + */ +static void +i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring, + struct change_domains *cd) +{ + uint32_t invalidate_domains = 0, flush_domains = 0; + + /* + * If the object isn't moving to a new write domain, + * let the object stay in multiple read domains + */ + if (obj->base.pending_write_domain == 0) + obj->base.pending_read_domains |= obj->base.read_domains; + + /* + * Flush the current write domain if + * the new read domains don't match. Invalidate + * any read domains which differ from the old + * write domain + */ + if (obj->base.write_domain && + (((obj->base.write_domain != obj->base.pending_read_domains || + obj->ring != ring)) || + (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) { + flush_domains |= obj->base.write_domain; + invalidate_domains |= + obj->base.pending_read_domains & ~obj->base.write_domain; + } + /* + * Invalidate any read caches which may have + * stale data. That is, any new read domains. + */ + invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains; + if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) + i915_gem_clflush_object(obj); + + /* blow away mappings if mapped through GTT */ + if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT) + i915_gem_release_mmap(obj); + + /* The actual obj->write_domain will be updated with + * pending_write_domain after we emit the accumulated flush for all + * of our domain changes in execbuffers (which clears objects' + * write_domains). So if we have a current write domain that we + * aren't changing, set pending_write_domain to that. + */ + if (flush_domains == 0 && obj->base.pending_write_domain == 0) + obj->base.pending_write_domain = obj->base.write_domain; + + cd->invalidate_domains |= invalidate_domains; + cd->flush_domains |= flush_domains; + if (flush_domains & I915_GEM_GPU_DOMAINS) + cd->flush_rings |= obj->ring->id; + if (invalidate_domains & I915_GEM_GPU_DOMAINS) + cd->flush_rings |= ring->id; +} + +static int +i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, + struct drm_file *file_priv, + struct drm_i915_gem_exec_object2 *entry, + struct drm_i915_gem_relocation_entry *reloc) +{ + struct drm_device *dev = obj->base.dev; + struct drm_gem_object *target_obj; + uint32_t target_offset; + int ret = -EINVAL; + + target_obj = drm_gem_object_lookup(dev, file_priv, + reloc->target_handle); + if (target_obj == NULL) + return -ENOENT; + + target_offset = to_intel_bo(target_obj)->gtt_offset; + +#if WATCH_RELOC + DRM_INFO("%s: obj %p offset %08x target %d " + "read %08x write %08x gtt %08x " + "presumed %08x delta %08x\n", + __func__, + obj, + (int) reloc->offset, + (int) reloc->target_handle, + (int) reloc->read_domains, + (int) reloc->write_domain, + (int) target_offset, + (int) reloc->presumed_offset, + reloc->delta); +#endif + + /* The target buffer should have appeared before us in the + * exec_object list, so it should have a GTT space bound by now. + */ + if (target_offset == 0) { + DRM_ERROR("No GTT space found for object %d\n", + reloc->target_handle); + goto err; + } + + /* Validate that the target is in a valid r/w GPU domain */ + if (reloc->write_domain & (reloc->write_domain - 1)) { + DRM_ERROR("reloc with multiple write domains: " + "obj %p target %d offset %d " + "read %08x write %08x", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->read_domains, + reloc->write_domain); + goto err; + } + if (reloc->write_domain & I915_GEM_DOMAIN_CPU || + reloc->read_domains & I915_GEM_DOMAIN_CPU) { + DRM_ERROR("reloc with read/write CPU domains: " + "obj %p target %d offset %d " + "read %08x write %08x", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->read_domains, + reloc->write_domain); + goto err; + } + if (reloc->write_domain && target_obj->pending_write_domain && + reloc->write_domain != target_obj->pending_write_domain) { + DRM_ERROR("Write domain conflict: " + "obj %p target %d offset %d " + "new %08x old %08x\n", + obj, reloc->target_handle, + (int) reloc->offset, + reloc->write_domain, + target_obj->pending_write_domain); + goto err; + } + + target_obj->pending_read_domains |= reloc->read_domains; + target_obj->pending_write_domain |= reloc->write_domain; + + /* If the relocation already has the right value in it, no + * more work needs to be done. + */ + if (target_offset == reloc->presumed_offset) + goto out; + + /* Check that the relocation address is valid... */ + if (reloc->offset > obj->base.size - 4) { + DRM_ERROR("Relocation beyond object bounds: " + "obj %p target %d offset %d size %d.\n", + obj, reloc->target_handle, + (int) reloc->offset, + (int) obj->base.size); + goto err; + } + if (reloc->offset & 3) { + DRM_ERROR("Relocation not 4-byte aligned: " + "obj %p target %d offset %d.\n", + obj, reloc->target_handle, + (int) reloc->offset); + goto err; + } + + /* and points to somewhere within the target object. */ + if (reloc->delta >= target_obj->size) { + DRM_ERROR("Relocation beyond target object bounds: " + "obj %p target %d delta %d size %d.\n", + obj, reloc->target_handle, + (int) reloc->delta, + (int) target_obj->size); + goto err; + } + + reloc->delta += target_offset; + if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) { + uint32_t page_offset = reloc->offset & ~PAGE_MASK; + char *vaddr; + + vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]); + *(uint32_t *)(vaddr + page_offset) = reloc->delta; + kunmap_atomic(vaddr); + } else { + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t __iomem *reloc_entry; + void __iomem *reloc_page; + + ret = i915_gem_object_set_to_gtt_domain(obj, 1); + if (ret) + goto err; + + /* Map the page containing the relocation we're going to perform. */ + reloc->offset += obj->gtt_offset; + reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + reloc->offset & PAGE_MASK); + reloc_entry = (uint32_t __iomem *) + (reloc_page + (reloc->offset & ~PAGE_MASK)); + iowrite32(reloc->delta, reloc_entry); + io_mapping_unmap_atomic(reloc_page); + } + + /* and update the user's relocation entry */ + reloc->presumed_offset = target_offset; + +out: + ret = 0; +err: + drm_gem_object_unreference(target_obj); + return ret; +} + +static int +i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, + struct drm_file *file_priv, + struct drm_i915_gem_exec_object2 *entry) +{ + struct drm_i915_gem_relocation_entry __user *user_relocs; + int i, ret; + + user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; + for (i = 0; i < entry->relocation_count; i++) { + struct drm_i915_gem_relocation_entry reloc; + + if (__copy_from_user_inatomic(&reloc, + user_relocs+i, + sizeof(reloc))) + return -EFAULT; + + ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &reloc); + if (ret) + return ret; + + if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset, + &reloc.presumed_offset, + sizeof(reloc.presumed_offset))) + return -EFAULT; + } + + return 0; +} + +static int +i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, + struct drm_file *file_priv, + struct drm_i915_gem_exec_object2 *entry, + struct drm_i915_gem_relocation_entry *relocs) +{ + int i, ret; + + for (i = 0; i < entry->relocation_count; i++) { + ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &relocs[i]); + if (ret) + return ret; + } + + return 0; +} + +static int +i915_gem_execbuffer_relocate(struct drm_device *dev, + struct drm_file *file, + struct drm_i915_gem_object **object_list, + struct drm_i915_gem_exec_object2 *exec_list, + int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = object_list[i]; + obj->base.pending_read_domains = 0; + obj->base.pending_write_domain = 0; + ret = i915_gem_execbuffer_relocate_object(obj, file, + &exec_list[i]); + if (ret) + return ret; + } + + return 0; +} + +static int +i915_gem_execbuffer_reserve(struct drm_device *dev, + struct drm_file *file, + struct drm_i915_gem_object **object_list, + struct drm_i915_gem_exec_object2 *exec_list, + int count) +{ + int ret, i, retry; + + /* Attempt to pin all of the buffers into the GTT. + * This is done in 3 phases: + * + * 1a. Unbind all objects that do not match the GTT constraints for + * the execbuffer (fenceable, mappable, alignment etc). + * 1b. Increment pin count for already bound objects. + * 2. Bind new objects. + * 3. Decrement pin count. + * + * This avoid unnecessary unbinding of later objects in order to makr + * room for the earlier objects *unless* we need to defragment. + */ + retry = 0; + do { + ret = 0; + + /* Unbind any ill-fitting objects or pin. */ + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = object_list[i]; + struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; + bool need_fence, need_mappable; + + if (!obj->gtt_space) + continue; + + need_fence = + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + need_mappable = + entry->relocation_count ? true : need_fence; + + if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) || + (need_mappable && !obj->map_and_fenceable)) + ret = i915_gem_object_unbind(obj); + else + ret = i915_gem_object_pin(obj, + entry->alignment, + need_mappable); + if (ret) { + count = i; + goto err; + } + } + + /* Bind fresh objects */ + for (i = 0; i < count; i++) { + struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; + struct drm_i915_gem_object *obj = object_list[i]; + bool need_fence; + + need_fence = + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + + if (!obj->gtt_space) { + bool need_mappable = + entry->relocation_count ? true : need_fence; + + ret = i915_gem_object_pin(obj, + entry->alignment, + need_mappable); + if (ret) + break; + } + + if (need_fence) { + ret = i915_gem_object_get_fence_reg(obj, true); + if (ret) + break; + + obj->pending_fenced_gpu_access = true; + } + + entry->offset = obj->gtt_offset; + } + +err: /* Decrement pin count for bound objects */ + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = object_list[i]; + if (obj->gtt_space) + i915_gem_object_unpin(obj); + } + + if (ret != -ENOSPC || retry > 1) + return ret; + + /* First attempt, just clear anything that is purgeable. + * Second attempt, clear the entire GTT. + */ + ret = i915_gem_evict_everything(dev, retry == 0); + if (ret) + return ret; + + retry++; + } while (1); +} + +static int +i915_gem_execbuffer_relocate_slow(struct drm_device *dev, + struct drm_file *file, + struct drm_i915_gem_object **object_list, + struct drm_i915_gem_exec_object2 *exec_list, + int count) +{ + struct drm_i915_gem_relocation_entry *reloc; + int i, total, ret; + + for (i = 0; i < count; i++) + object_list[i]->in_execbuffer = false; + + mutex_unlock(&dev->struct_mutex); + + total = 0; + for (i = 0; i < count; i++) + total += exec_list[i].relocation_count; + + reloc = drm_malloc_ab(total, sizeof(*reloc)); + if (reloc == NULL) { + mutex_lock(&dev->struct_mutex); + return -ENOMEM; + } + + total = 0; + for (i = 0; i < count; i++) { + struct drm_i915_gem_relocation_entry __user *user_relocs; + + user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; + + if (copy_from_user(reloc+total, user_relocs, + exec_list[i].relocation_count * + sizeof(*reloc))) { + ret = -EFAULT; + mutex_lock(&dev->struct_mutex); + goto err; + } + + total += exec_list[i].relocation_count; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) { + mutex_lock(&dev->struct_mutex); + goto err; + } + + ret = i915_gem_execbuffer_reserve(dev, file, + object_list, exec_list, + count); + if (ret) + goto err; + + total = 0; + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = object_list[i]; + obj->base.pending_read_domains = 0; + obj->base.pending_write_domain = 0; + ret = i915_gem_execbuffer_relocate_object_slow(obj, file, + &exec_list[i], + reloc + total); + if (ret) + goto err; + + total += exec_list[i].relocation_count; + } + + /* Leave the user relocations as are, this is the painfully slow path, + * and we want to avoid the complication of dropping the lock whilst + * having buffers reserved in the aperture and so causing spurious + * ENOSPC for random operations. + */ + +err: + drm_free_large(reloc); + return ret; +} + +static void +i915_gem_execbuffer_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains, + uint32_t flush_rings) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (flush_domains & I915_GEM_DOMAIN_CPU) + intel_gtt_chipset_flush(); + + if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { + if (flush_rings & RING_RENDER) + i915_gem_flush_ring(dev, &dev_priv->render_ring, + invalidate_domains, flush_domains); + if (flush_rings & RING_BSD) + i915_gem_flush_ring(dev, &dev_priv->bsd_ring, + invalidate_domains, flush_domains); + if (flush_rings & RING_BLT) + i915_gem_flush_ring(dev, &dev_priv->blt_ring, + invalidate_domains, flush_domains); + } +} + + +static int +i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, + struct drm_file *file, + struct intel_ring_buffer *ring, + struct drm_i915_gem_object **objects, + int count) +{ + struct change_domains cd; + int ret, i; + + cd.invalidate_domains = 0; + cd.flush_domains = 0; + cd.flush_rings = 0; + for (i = 0; i < count; i++) + i915_gem_object_set_to_gpu_domain(objects[i], ring, &cd); + + if (cd.invalidate_domains | cd.flush_domains) { +#if WATCH_EXEC + DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", + __func__, + cd.invalidate_domains, + cd.flush_domains); +#endif + i915_gem_execbuffer_flush(dev, + cd.invalidate_domains, + cd.flush_domains, + cd.flush_rings); + } + + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj = objects[i]; + /* XXX replace with semaphores */ + if (obj->ring && ring != obj->ring) { + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; + } + } + + return 0; +} + +static int +i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec, + uint64_t exec_offset) +{ + uint32_t exec_start, exec_len; + + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + exec_len = (uint32_t) exec->batch_len; + + if ((exec_start | exec_len) & 0x7) + return -EINVAL; + + if (!exec_start) + return -EINVAL; + + return 0; +} + +static int +validate_exec_list(struct drm_i915_gem_exec_object2 *exec, + int count) +{ + int i; + + for (i = 0; i < count; i++) { + char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; + int length; /* limited by fault_in_pages_readable() */ + + /* First check for malicious input causing overflow */ + if (exec[i].relocation_count > + INT_MAX / sizeof(struct drm_i915_gem_relocation_entry)) + return -EINVAL; + + length = exec[i].relocation_count * + sizeof(struct drm_i915_gem_relocation_entry); + if (!access_ok(VERIFY_READ, ptr, length)) + return -EFAULT; + + /* we may also need to update the presumed offsets */ + if (!access_ok(VERIFY_WRITE, ptr, length)) + return -EFAULT; + + if (fault_in_pages_readable(ptr, length)) + return -EFAULT; + } + + return 0; +} + +static void +i915_gem_execbuffer_retire_commands(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + uint32_t flush_domains = 0; + + /* The sampler always gets flushed on i965 (sigh) */ + if (INTEL_INFO(dev)->gen >= 4) + flush_domains |= I915_GEM_DOMAIN_SAMPLER; + + ring->flush(ring, I915_GEM_DOMAIN_COMMAND, flush_domains); +} + + +static int +i915_gem_do_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file, + struct drm_i915_gem_execbuffer2 *args, + struct drm_i915_gem_exec_object2 *exec_list) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_object **object_list = NULL; + struct drm_i915_gem_object *batch_obj; + struct drm_clip_rect *cliprects = NULL; + struct drm_i915_gem_request *request = NULL; + struct intel_ring_buffer *ring; + int ret, i, flips; + uint64_t exec_offset; + + ret = validate_exec_list(exec_list, args->buffer_count); + if (ret) + return ret; + +#if WATCH_EXEC + DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", + (int) args->buffers_ptr, args->buffer_count, args->batch_len); +#endif + switch (args->flags & I915_EXEC_RING_MASK) { + case I915_EXEC_DEFAULT: + case I915_EXEC_RENDER: + ring = &dev_priv->render_ring; + break; + case I915_EXEC_BSD: + if (!HAS_BSD(dev)) { + DRM_ERROR("execbuf with invalid ring (BSD)\n"); + return -EINVAL; + } + ring = &dev_priv->bsd_ring; + break; + case I915_EXEC_BLT: + if (!HAS_BLT(dev)) { + DRM_ERROR("execbuf with invalid ring (BLT)\n"); + return -EINVAL; + } + ring = &dev_priv->blt_ring; + break; + default: + DRM_ERROR("execbuf with unknown ring: %d\n", + (int)(args->flags & I915_EXEC_RING_MASK)); + return -EINVAL; + } + + if (args->buffer_count < 1) { + DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); + return -EINVAL; + } + object_list = drm_malloc_ab(sizeof(*object_list), args->buffer_count); + if (object_list == NULL) { + DRM_ERROR("Failed to allocate object list for %d buffers\n", + args->buffer_count); + ret = -ENOMEM; + goto pre_mutex_err; + } + + if (args->num_cliprects != 0) { + cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), + GFP_KERNEL); + if (cliprects == NULL) { + ret = -ENOMEM; + goto pre_mutex_err; + } + + ret = copy_from_user(cliprects, + (struct drm_clip_rect __user *) + (uintptr_t) args->cliprects_ptr, + sizeof(*cliprects) * args->num_cliprects); + if (ret != 0) { + DRM_ERROR("copy %d cliprects failed: %d\n", + args->num_cliprects, ret); + ret = -EFAULT; + goto pre_mutex_err; + } + } + + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) { + ret = -ENOMEM; + goto pre_mutex_err; + } + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto pre_mutex_err; + + if (dev_priv->mm.suspended) { + mutex_unlock(&dev->struct_mutex); + ret = -EBUSY; + goto pre_mutex_err; + } + + /* Look up object handles */ + for (i = 0; i < args->buffer_count; i++) { + struct drm_i915_gem_object *obj; + + obj = to_intel_bo (drm_gem_object_lookup(dev, file, + exec_list[i].handle)); + if (obj == NULL) { + DRM_ERROR("Invalid object handle %d at index %d\n", + exec_list[i].handle, i); + /* prevent error path from reading uninitialized data */ + args->buffer_count = i; + ret = -ENOENT; + goto err; + } + object_list[i] = obj; + + if (obj->in_execbuffer) { + DRM_ERROR("Object %p appears more than once in object list\n", + obj); + /* prevent error path from reading uninitialized data */ + args->buffer_count = i + 1; + ret = -EINVAL; + goto err; + } + obj->in_execbuffer = true; + obj->pending_fenced_gpu_access = false; + } + + /* Move the objects en-masse into the GTT, evicting if necessary. */ + ret = i915_gem_execbuffer_reserve(dev, file, + object_list, exec_list, + args->buffer_count); + if (ret) + goto err; + + /* The objects are in their final locations, apply the relocations. */ + ret = i915_gem_execbuffer_relocate(dev, file, + object_list, exec_list, + args->buffer_count); + if (ret) { + if (ret == -EFAULT) { + ret = i915_gem_execbuffer_relocate_slow(dev, file, + object_list, + exec_list, + args->buffer_count); + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + } + if (ret) + goto err; + } + + /* Set the pending read domains for the batch buffer to COMMAND */ + batch_obj = object_list[args->buffer_count-1]; + if (batch_obj->base.pending_write_domain) { + DRM_ERROR("Attempting to use self-modifying batch buffer\n"); + ret = -EINVAL; + goto err; + } + batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + + /* Sanity check the batch buffer */ + exec_offset = batch_obj->gtt_offset; + ret = i915_gem_check_execbuffer(args, exec_offset); + if (ret != 0) { + DRM_ERROR("execbuf with invalid offset/length\n"); + goto err; + } + + ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring, + object_list, args->buffer_count); + if (ret) + goto err; + +#if WATCH_COHERENCY + for (i = 0; i < args->buffer_count; i++) { + i915_gem_object_check_coherency(object_list[i], + exec_list[i].handle); + } +#endif + +#if WATCH_EXEC + i915_gem_dump_object(batch_obj, + args->batch_len, + __func__, + ~0); +#endif + + /* Check for any pending flips. As we only maintain a flip queue depth + * of 1, we can simply insert a WAIT for the next display flip prior + * to executing the batch and avoid stalling the CPU. + */ + flips = 0; + for (i = 0; i < args->buffer_count; i++) { + if (object_list[i]->base.write_domain) + flips |= atomic_read(&object_list[i]->pending_flip); + } + if (flips) { + int plane, flip_mask; + + for (plane = 0; flips >> plane; plane++) { + if (((flips >> plane) & 1) == 0) + continue; + + if (plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + + ret = intel_ring_begin(ring, 2); + if (ret) + goto err; + + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } + } + + /* Exec the batchbuffer */ + ret = ring->dispatch_execbuffer(ring, args, cliprects, exec_offset); + if (ret) { + DRM_ERROR("dispatch failed %d\n", ret); + goto err; + } + + for (i = 0; i < args->buffer_count; i++) { + struct drm_i915_gem_object *obj = object_list[i]; + + obj->base.read_domains = obj->base.pending_read_domains; + obj->base.write_domain = obj->base.pending_write_domain; + obj->fenced_gpu_access = obj->pending_fenced_gpu_access; + + i915_gem_object_move_to_active(obj, ring); + if (obj->base.write_domain) { + obj->dirty = 1; + list_move_tail(&obj->gpu_write_list, + &ring->gpu_write_list); + intel_mark_busy(dev, obj); + } + + trace_i915_gem_object_change_domain(obj, + obj->base.read_domains, + obj->base.write_domain); + } + + /* + * Ensure that the commands in the batch buffer are + * finished before the interrupt fires + */ + i915_gem_execbuffer_retire_commands(dev, ring); + + if (i915_add_request(dev, file, request, ring)) + i915_gem_next_request_seqno(dev, ring); + else + request = NULL; + +err: + for (i = 0; i < args->buffer_count; i++) { + object_list[i]->in_execbuffer = false; + drm_gem_object_unreference(&object_list[i]->base); + } + + mutex_unlock(&dev->struct_mutex); + +pre_mutex_err: + drm_free_large(object_list); + kfree(cliprects); + kfree(request); + + return ret; +} + +/* + * Legacy execbuffer just creates an exec2 list from the original exec object + * list array and passes it to the real function. + */ +int +i915_gem_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_execbuffer *args = data; + struct drm_i915_gem_execbuffer2 exec2; + struct drm_i915_gem_exec_object *exec_list = NULL; + struct drm_i915_gem_exec_object2 *exec2_list = NULL; + int ret, i; + +#if WATCH_EXEC + DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", + (int) args->buffers_ptr, args->buffer_count, args->batch_len); +#endif + + if (args->buffer_count < 1) { + DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); + return -EINVAL; + } + + /* Copy in the exec list from userland */ + exec_list = drm_malloc_ab(sizeof(*exec_list), args->buffer_count); + exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); + if (exec_list == NULL || exec2_list == NULL) { + DRM_ERROR("Failed to allocate exec list for %d buffers\n", + args->buffer_count); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return -ENOMEM; + } + ret = copy_from_user(exec_list, + (struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + sizeof(*exec_list) * args->buffer_count); + if (ret != 0) { + DRM_ERROR("copy %d exec entries failed %d\n", + args->buffer_count, ret); + drm_free_large(exec_list); + drm_free_large(exec2_list); + return -EFAULT; + } + + for (i = 0; i < args->buffer_count; i++) { + exec2_list[i].handle = exec_list[i].handle; + exec2_list[i].relocation_count = exec_list[i].relocation_count; + exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr; + exec2_list[i].alignment = exec_list[i].alignment; + exec2_list[i].offset = exec_list[i].offset; + if (INTEL_INFO(dev)->gen < 4) + exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; + else + exec2_list[i].flags = 0; + } + + exec2.buffers_ptr = args->buffers_ptr; + exec2.buffer_count = args->buffer_count; + exec2.batch_start_offset = args->batch_start_offset; + exec2.batch_len = args->batch_len; + exec2.DR1 = args->DR1; + exec2.DR4 = args->DR4; + exec2.num_cliprects = args->num_cliprects; + exec2.cliprects_ptr = args->cliprects_ptr; + exec2.flags = I915_EXEC_RENDER; + + ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list); + if (!ret) { + /* Copy the new buffer offsets back to the user's exec list. */ + for (i = 0; i < args->buffer_count; i++) + exec_list[i].offset = exec2_list[i].offset; + /* ... and back out to userspace */ + ret = copy_to_user((struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + exec_list, + sizeof(*exec_list) * args->buffer_count); + if (ret) { + ret = -EFAULT; + DRM_ERROR("failed to copy %d exec entries " + "back to user (%d)\n", + args->buffer_count, ret); + } + } + + drm_free_large(exec_list); + drm_free_large(exec2_list); + return ret; +} + +int +i915_gem_execbuffer2(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_execbuffer2 *args = data; + struct drm_i915_gem_exec_object2 *exec2_list = NULL; + int ret; + +#if WATCH_EXEC + DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", + (int) args->buffers_ptr, args->buffer_count, args->batch_len); +#endif + + if (args->buffer_count < 1) { + DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count); + return -EINVAL; + } + + exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); + if (exec2_list == NULL) { + DRM_ERROR("Failed to allocate exec list for %d buffers\n", + args->buffer_count); + return -ENOMEM; + } + ret = copy_from_user(exec2_list, + (struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + sizeof(*exec2_list) * args->buffer_count); + if (ret != 0) { + DRM_ERROR("copy %d exec entries failed %d\n", + args->buffer_count, ret); + drm_free_large(exec2_list); + return -EFAULT; + } + + ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); + if (!ret) { + /* Copy the new buffer offsets back to the user's exec list. */ + ret = copy_to_user((struct drm_i915_relocation_entry __user *) + (uintptr_t) args->buffers_ptr, + exec2_list, + sizeof(*exec2_list) * args->buffer_count); + if (ret) { + ret = -EFAULT; + DRM_ERROR("failed to copy %d exec entries " + "back to user (%d)\n", + args->buffer_count, ret); + } + } + + drm_free_large(exec2_list); + return ret; +} + -- cgit v1.2.3 From 432e58edc9de1d9c3d6a7b444b3c455b8f209a7d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 25 Nov 2010 19:32:06 +0000 Subject: drm/i915: Avoid allocation for execbuffer object list Besides the minimal improvement in reducing the execbuffer overhead, the real benefit is clarifying a few routines. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 10 +- drivers/gpu/drm/i915/i915_gem.c | 1 + drivers/gpu/drm/i915/i915_gem_evict.c | 14 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 403 ++++++++++++++--------------- 4 files changed, 199 insertions(+), 229 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6c10b645dde9..e7c4108c94cd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -712,8 +712,8 @@ struct drm_i915_gem_object { struct list_head mm_list; /** This object's place on GPU write list */ struct list_head gpu_write_list; - /** This object's place on eviction list */ - struct list_head evict_list; + /** This object's place in the batchbuffer or on the eviction list */ + struct list_head exec_list; /** * This is set if the object is on the active or flushing lists @@ -737,12 +737,6 @@ struct drm_i915_gem_object { */ signed int fence_reg : 5; - /** - * Used for checking the object doesn't appear more than once - * in an execbuffer object list. - */ - unsigned int in_execbuffer : 1; - /** * Advice: are the backing pages purgeable? */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b30c6c167048..d9d81f94a4b8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3399,6 +3399,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, INIT_LIST_HEAD(&obj->mm_list); INIT_LIST_HEAD(&obj->gtt_list); INIT_LIST_HEAD(&obj->ring_list); + INIT_LIST_HEAD(&obj->exec_list); INIT_LIST_HEAD(&obj->gpu_write_list); obj->madv = I915_MADV_WILLNEED; /* Avoid an unnecessary call to unbind on the first bind. */ diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 03e15d37b550..78b8cf90c922 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -34,7 +34,7 @@ static bool mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) { - list_add(&obj->evict_list, unwind); + list_add(&obj->exec_list, unwind); drm_gem_object_reference(&obj->base); return drm_mm_scan_add_block(obj->gtt_space); } @@ -127,7 +127,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, } /* Nothing found, clean up and bail out! */ - list_for_each_entry(obj, &unwind_list, evict_list) { + list_for_each_entry(obj, &unwind_list, exec_list) { ret = drm_mm_scan_remove_block(obj->gtt_space); BUG_ON(ret); drm_gem_object_unreference(&obj->base); @@ -146,12 +146,12 @@ found: while (!list_empty(&unwind_list)) { obj = list_first_entry(&unwind_list, struct drm_i915_gem_object, - evict_list); + exec_list); if (drm_mm_scan_remove_block(obj->gtt_space)) { - list_move(&obj->evict_list, &eviction_list); + list_move(&obj->exec_list, &eviction_list); continue; } - list_del(&obj->evict_list); + list_del_init(&obj->exec_list); drm_gem_object_unreference(&obj->base); } @@ -159,10 +159,10 @@ found: while (!list_empty(&eviction_list)) { obj = list_first_entry(&eviction_list, struct drm_i915_gem_object, - evict_list); + exec_list); if (ret == 0) ret = i915_gem_object_unbind(obj); - list_del(&obj->evict_list); + list_del_init(&obj->exec_list); drm_gem_object_unreference(&obj->base); } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index bdc613b91af8..d54070111f9d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -406,18 +406,16 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, struct drm_file *file, - struct drm_i915_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, - int count) + struct list_head *objects, + struct drm_i915_gem_exec_object2 *exec) { - int i, ret; + struct drm_i915_gem_object *obj; + int ret; - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; + list_for_each_entry(obj, objects, exec_list) { obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate_object(obj, file, - &exec_list[i]); + ret = i915_gem_execbuffer_relocate_object(obj, file, exec++); if (ret) return ret; } @@ -428,11 +426,12 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, static int i915_gem_execbuffer_reserve(struct drm_device *dev, struct drm_file *file, - struct drm_i915_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, - int count) + struct list_head *objects, + struct drm_i915_gem_exec_object2 *exec) { - int ret, i, retry; + struct drm_i915_gem_object *obj; + struct drm_i915_gem_exec_object2 *entry; + int ret, retry; /* Attempt to pin all of the buffers into the GTT. * This is done in 3 phases: @@ -451,13 +450,14 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, ret = 0; /* Unbind any ill-fitting objects or pin. */ - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; + entry = exec; + list_for_each_entry(obj, objects, exec_list) { bool need_fence, need_mappable; - if (!obj->gtt_space) + if (!obj->gtt_space) { + entry++; continue; + } need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE && @@ -472,16 +472,15 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, ret = i915_gem_object_pin(obj, entry->alignment, need_mappable); - if (ret) { - count = i; + if (ret) goto err; - } + + entry++; } /* Bind fresh objects */ - for (i = 0; i < count; i++) { - struct drm_i915_gem_exec_object2 *entry = &exec_list[i]; - struct drm_i915_gem_object *obj = object_list[i]; + entry = exec; + list_for_each_entry(obj, objects, exec_list) { bool need_fence; need_fence = @@ -504,15 +503,15 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, if (ret) break; - obj->pending_fenced_gpu_access = true; } + obj->pending_fenced_gpu_access = need_fence; entry->offset = obj->gtt_offset; + entry++; } -err: /* Decrement pin count for bound objects */ - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; + /* Decrement pin count for bound objects */ + list_for_each_entry(obj, objects, exec_list) { if (obj->gtt_space) i915_gem_object_unpin(obj); } @@ -529,26 +528,36 @@ err: /* Decrement pin count for bound objects */ retry++; } while (1); + +err: + while (objects != &obj->exec_list) { + if (obj->gtt_space) + i915_gem_object_unpin(obj); + + obj = list_entry(obj->exec_list.prev, + struct drm_i915_gem_object, + exec_list); + } + + return ret; } static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, - struct drm_i915_gem_object **object_list, - struct drm_i915_gem_exec_object2 *exec_list, + struct list_head *objects, + struct drm_i915_gem_exec_object2 *exec, int count) { struct drm_i915_gem_relocation_entry *reloc; + struct drm_i915_gem_object *obj; int i, total, ret; - for (i = 0; i < count; i++) - object_list[i]->in_execbuffer = false; - mutex_unlock(&dev->struct_mutex); total = 0; for (i = 0; i < count; i++) - total += exec_list[i].relocation_count; + total += exec[i].relocation_count; reloc = drm_malloc_ab(total, sizeof(*reloc)); if (reloc == NULL) { @@ -560,17 +569,16 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, for (i = 0; i < count; i++) { struct drm_i915_gem_relocation_entry __user *user_relocs; - user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr; + user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; if (copy_from_user(reloc+total, user_relocs, - exec_list[i].relocation_count * - sizeof(*reloc))) { + exec[i].relocation_count * sizeof(*reloc))) { ret = -EFAULT; mutex_lock(&dev->struct_mutex); goto err; } - total += exec_list[i].relocation_count; + total += exec[i].relocation_count; } ret = i915_mutex_lock_interruptible(dev); @@ -579,24 +587,22 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; } - ret = i915_gem_execbuffer_reserve(dev, file, - object_list, exec_list, - count); + ret = i915_gem_execbuffer_reserve(dev, file, objects, exec); if (ret) goto err; total = 0; - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; + list_for_each_entry(obj, objects, exec_list) { obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object_slow(obj, file, - &exec_list[i], + exec, reloc + total); if (ret) goto err; - total += exec_list[i].relocation_count; + total += exec->relocation_count; + exec++; } /* Leave the user relocations as are, this is the painfully slow path, @@ -636,20 +642,18 @@ i915_gem_execbuffer_flush(struct drm_device *dev, static int -i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, - struct drm_file *file, - struct intel_ring_buffer *ring, - struct drm_i915_gem_object **objects, - int count) +i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, + struct list_head *objects) { + struct drm_i915_gem_object *obj; struct change_domains cd; - int ret, i; + int ret; cd.invalidate_domains = 0; cd.flush_domains = 0; cd.flush_rings = 0; - for (i = 0; i < count; i++) - i915_gem_object_set_to_gpu_domain(objects[i], ring, &cd); + list_for_each_entry(obj, objects, exec_list) + i915_gem_object_set_to_gpu_domain(obj, ring, &cd); if (cd.invalidate_domains | cd.flush_domains) { #if WATCH_EXEC @@ -658,14 +662,13 @@ i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, cd.invalidate_domains, cd.flush_domains); #endif - i915_gem_execbuffer_flush(dev, + i915_gem_execbuffer_flush(ring->dev, cd.invalidate_domains, cd.flush_domains, cd.flush_rings); } - for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj = objects[i]; + list_for_each_entry(obj, objects, exec_list) { /* XXX replace with semaphores */ if (obj->ring && ring != obj->ring) { ret = i915_gem_object_wait_rendering(obj, true); @@ -677,22 +680,10 @@ i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, return 0; } -static int -i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec, - uint64_t exec_offset) +static bool +i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) { - uint32_t exec_start, exec_len; - - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - exec_len = (uint32_t) exec->batch_len; - - if ((exec_start | exec_len) & 0x7) - return -EINVAL; - - if (!exec_start) - return -EINVAL; - - return 0; + return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0; } static int @@ -726,36 +717,119 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, return 0; } +static int +i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, + struct list_head *objects) +{ + struct drm_i915_gem_object *obj; + int flips; + + /* Check for any pending flips. As we only maintain a flip queue depth + * of 1, we can simply insert a WAIT for the next display flip prior + * to executing the batch and avoid stalling the CPU. + */ + flips = 0; + list_for_each_entry(obj, objects, exec_list) { + if (obj->base.write_domain) + flips |= atomic_read(&obj->pending_flip); + } + if (flips) { + int plane, flip_mask, ret; + + for (plane = 0; flips >> plane; plane++) { + if (((flips >> plane) & 1) == 0) + continue; + + if (plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } + } + + return 0; +} + +static void +i915_gem_execbuffer_move_to_active(struct list_head *objects, + struct intel_ring_buffer *ring) +{ + struct drm_i915_gem_object *obj; + + list_for_each_entry(obj, objects, exec_list) { + obj->base.read_domains = obj->base.pending_read_domains; + obj->base.write_domain = obj->base.pending_write_domain; + obj->fenced_gpu_access = obj->pending_fenced_gpu_access; + + i915_gem_object_move_to_active(obj, ring); + if (obj->base.write_domain) { + obj->dirty = 1; + list_move_tail(&obj->gpu_write_list, + &ring->gpu_write_list); + intel_mark_busy(ring->dev, obj); + } + + trace_i915_gem_object_change_domain(obj, + obj->base.read_domains, + obj->base.write_domain); + } +} + static void i915_gem_execbuffer_retire_commands(struct drm_device *dev, + struct drm_file *file, struct intel_ring_buffer *ring) { - uint32_t flush_domains = 0; + struct drm_i915_gem_request *request; + u32 flush_domains; - /* The sampler always gets flushed on i965 (sigh) */ + /* + * Ensure that the commands in the batch buffer are + * finished before the interrupt fires. + * + * The sampler always gets flushed on i965 (sigh). + */ + flush_domains = 0; if (INTEL_INFO(dev)->gen >= 4) flush_domains |= I915_GEM_DOMAIN_SAMPLER; ring->flush(ring, I915_GEM_DOMAIN_COMMAND, flush_domains); -} + /* Add a breadcrumb for the completion of the batch buffer */ + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL || i915_add_request(dev, file, request, ring)) { + i915_gem_next_request_seqno(dev, ring); + kfree(request); + } +} static int i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_file *file, struct drm_i915_gem_execbuffer2 *args, - struct drm_i915_gem_exec_object2 *exec_list) + struct drm_i915_gem_exec_object2 *exec) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object **object_list = NULL; + struct list_head objects; struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; - struct drm_i915_gem_request *request = NULL; struct intel_ring_buffer *ring; - int ret, i, flips; - uint64_t exec_offset; + int ret, i; - ret = validate_exec_list(exec_list, args->buffer_count); + if (!i915_gem_check_execbuffer(args)) { + DRM_ERROR("execbuf with invalid offset/length\n"); + return -EINVAL; + } + + ret = validate_exec_list(exec, args->buffer_count); if (ret) return ret; @@ -792,40 +866,24 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); return -EINVAL; } - object_list = drm_malloc_ab(sizeof(*object_list), args->buffer_count); - if (object_list == NULL) { - DRM_ERROR("Failed to allocate object list for %d buffers\n", - args->buffer_count); - ret = -ENOMEM; - goto pre_mutex_err; - } if (args->num_cliprects != 0) { - cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), + cliprects = kmalloc(args->num_cliprects * sizeof(*cliprects), GFP_KERNEL); if (cliprects == NULL) { ret = -ENOMEM; goto pre_mutex_err; } - ret = copy_from_user(cliprects, - (struct drm_clip_rect __user *) - (uintptr_t) args->cliprects_ptr, - sizeof(*cliprects) * args->num_cliprects); - if (ret != 0) { - DRM_ERROR("copy %d cliprects failed: %d\n", - args->num_cliprects, ret); + if (copy_from_user(cliprects, + (struct drm_clip_rect __user *)(uintptr_t) + args->cliprects_ptr, + sizeof(*cliprects)*args->num_cliprects)) { ret = -EFAULT; goto pre_mutex_err; } } - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) { - ret = -ENOMEM; - goto pre_mutex_err; - } - ret = i915_mutex_lock_interruptible(dev); if (ret) goto pre_mutex_err; @@ -837,49 +895,41 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Look up object handles */ + INIT_LIST_HEAD(&objects); for (i = 0; i < args->buffer_count; i++) { struct drm_i915_gem_object *obj; - obj = to_intel_bo (drm_gem_object_lookup(dev, file, - exec_list[i].handle)); + obj = to_intel_bo(drm_gem_object_lookup(dev, file, + exec[i].handle)); if (obj == NULL) { DRM_ERROR("Invalid object handle %d at index %d\n", - exec_list[i].handle, i); + exec[i].handle, i); /* prevent error path from reading uninitialized data */ - args->buffer_count = i; ret = -ENOENT; goto err; } - object_list[i] = obj; - if (obj->in_execbuffer) { - DRM_ERROR("Object %p appears more than once in object list\n", - obj); - /* prevent error path from reading uninitialized data */ - args->buffer_count = i + 1; + if (!list_empty(&obj->exec_list)) { + DRM_ERROR("Object %p [handle %d, index %d] appears more than once in object list\n", + obj, exec[i].handle, i); ret = -EINVAL; goto err; } - obj->in_execbuffer = true; - obj->pending_fenced_gpu_access = false; + + list_add_tail(&obj->exec_list, &objects); } /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(dev, file, - object_list, exec_list, - args->buffer_count); + ret = i915_gem_execbuffer_reserve(dev, file, &objects, exec); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, file, - object_list, exec_list, - args->buffer_count); + ret = i915_gem_execbuffer_relocate(dev, file, &objects, exec); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, file, - object_list, - exec_list, + &objects, exec, args->buffer_count); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } @@ -888,7 +938,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Set the pending read domains for the batch buffer to COMMAND */ - batch_obj = object_list[args->buffer_count-1]; + batch_obj = list_entry(objects.prev, + struct drm_i915_gem_object, + exec_list); if (batch_obj->base.pending_write_domain) { DRM_ERROR("Attempting to use self-modifying batch buffer\n"); ret = -EINVAL; @@ -896,115 +948,38 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; - /* Sanity check the batch buffer */ - exec_offset = batch_obj->gtt_offset; - ret = i915_gem_check_execbuffer(args, exec_offset); - if (ret != 0) { - DRM_ERROR("execbuf with invalid offset/length\n"); + ret = i915_gem_execbuffer_move_to_gpu(ring, &objects); + if (ret) goto err; - } - ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring, - object_list, args->buffer_count); + ret = i915_gem_execbuffer_wait_for_flips(ring, &objects); if (ret) goto err; -#if WATCH_COHERENCY - for (i = 0; i < args->buffer_count; i++) { - i915_gem_object_check_coherency(object_list[i], - exec_list[i].handle); - } -#endif - -#if WATCH_EXEC - i915_gem_dump_object(batch_obj, - args->batch_len, - __func__, - ~0); -#endif - - /* Check for any pending flips. As we only maintain a flip queue depth - * of 1, we can simply insert a WAIT for the next display flip prior - * to executing the batch and avoid stalling the CPU. - */ - flips = 0; - for (i = 0; i < args->buffer_count; i++) { - if (object_list[i]->base.write_domain) - flips |= atomic_read(&object_list[i]->pending_flip); - } - if (flips) { - int plane, flip_mask; - - for (plane = 0; flips >> plane; plane++) { - if (((flips >> plane) & 1) == 0) - continue; - - if (plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - - ret = intel_ring_begin(ring, 2); - if (ret) - goto err; - - intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } - } - - /* Exec the batchbuffer */ - ret = ring->dispatch_execbuffer(ring, args, cliprects, exec_offset); - if (ret) { - DRM_ERROR("dispatch failed %d\n", ret); + ret = ring->dispatch_execbuffer(ring, + args, cliprects, + batch_obj->gtt_offset); + if (ret) goto err; - } - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj = object_list[i]; - - obj->base.read_domains = obj->base.pending_read_domains; - obj->base.write_domain = obj->base.pending_write_domain; - obj->fenced_gpu_access = obj->pending_fenced_gpu_access; - - i915_gem_object_move_to_active(obj, ring); - if (obj->base.write_domain) { - obj->dirty = 1; - list_move_tail(&obj->gpu_write_list, - &ring->gpu_write_list); - intel_mark_busy(dev, obj); - } - - trace_i915_gem_object_change_domain(obj, - obj->base.read_domains, - obj->base.write_domain); - } - - /* - * Ensure that the commands in the batch buffer are - * finished before the interrupt fires - */ - i915_gem_execbuffer_retire_commands(dev, ring); - - if (i915_add_request(dev, file, request, ring)) - i915_gem_next_request_seqno(dev, ring); - else - request = NULL; + i915_gem_execbuffer_move_to_active(&objects, ring); + i915_gem_execbuffer_retire_commands(dev, file, ring); err: - for (i = 0; i < args->buffer_count; i++) { - object_list[i]->in_execbuffer = false; - drm_gem_object_unreference(&object_list[i]->base); + while (!list_empty(&objects)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&objects, + struct drm_i915_gem_object, + exec_list); + list_del_init(&obj->exec_list); + drm_gem_object_unreference(&obj->base); } mutex_unlock(&dev->struct_mutex); pre_mutex_err: - drm_free_large(object_list); kfree(cliprects); - kfree(request); - return ret; } -- cgit v1.2.3 From acb325062afc09c196f7d3888b81312e6ebcdc35 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 23 Nov 2010 00:41:00 -0500 Subject: drm/radeon/kms: improve pflip precision on r1xx-r4xx The update pending bit has a separate enable bit. Cc: Mario Kleiner Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 8 +++++--- drivers/gpu/drm/radeon/radeon_reg.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 2316f73db6c0..300b4a64d8fe 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -76,6 +76,8 @@ void r100_pre_page_flip(struct radeon_device *rdev, int crtc) /* make sure flip is at vb rather than hb */ tmp = RREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset); tmp &= ~RADEON_CRTC_OFFSET_FLIP_CNTL; + /* make sure pending bit is asserted */ + tmp |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN; WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, tmp); /* set pageflip to happen as late as possible in the vblank interval. @@ -104,9 +106,9 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) /* update the scanout addresses */ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); - /* Note: We don't wait for update_pending to assert, as this never - * happens for some reason on R1xx - R4xx. Adds a bit of imprecision. - */ + /* Wait for update_pending to go high. */ + while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)); + DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK; diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 26c43e234350..0a310b7f71c3 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -510,6 +510,8 @@ # define RADEON_CRTC_TILE_EN (1 << 15) # define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16) # define RADEON_CRTC_STEREO_OFFSET_EN (1 << 17) +# define RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN (1 << 28) +# define RADEON_CRTC_GUI_TRIG_OFFSET_RIGHT_EN (1 << 29) #define R300_CRTC_TILE_X0_Y0 0x0350 #define R300_CRTC2_TILE_X0_Y0 0x0358 -- cgit v1.2.3 From 73d8c34f3d78ccf90a431c221df10377affce650 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 15 Nov 2010 16:03:04 -0500 Subject: SCSI: improve two error messages This trivial patch (as1338) makes two uninformative error messages in scsi_sysfs_add_sdev() more explicit. Signed-off-by: Alan Stern Signed-off-by: Jiri Kosina --- drivers/scsi/scsi_sysfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 20ad59dff730..9c52ce4f7129 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -864,13 +864,15 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) error = device_add(&sdev->sdev_gendev); if (error) { - printk(KERN_INFO "error 1\n"); + sdev_printk(KERN_INFO, sdev, + "failed to add device: %d\n", error); return error; } device_enable_async_suspend(&sdev->sdev_dev); error = device_add(&sdev->sdev_dev); if (error) { - printk(KERN_INFO "error 2\n"); + sdev_printk(KERN_INFO, sdev, + "failed to add class device: %d\n", error); device_del(&sdev->sdev_gendev); return error; } -- cgit v1.2.3 From 559e0df6b3ffbc218a11bb9dada5320a217cb7a6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Aug 2010 19:25:12 +0100 Subject: mfd: Add initial WM8958 support The WM8958 is a derivative of the WM8994 which is register compatible with the addition of some extra features, mostly in the CODEC side. The major change visible at the MFD level is that rather than a single DBVDD supply we now have three separate DBVDDs so we must request and enable a different set of supplies. Signed-off-by: Mark Brown Acked-by: Samuel Ortiz Acked-by: Liam Girdwood --- drivers/mfd/wm8994-core.c | 93 ++++++++++++++++++++++++++++++++--------- include/linux/mfd/wm8994/core.h | 8 ++++ 2 files changed, 82 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index b3b2aaf89dbe..8d221ba5e38d 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -218,6 +218,18 @@ static const char *wm8994_main_supplies[] = { "SPKVDD2", }; +static const char *wm8958_main_supplies[] = { + "DBVDD1", + "DBVDD2", + "DBVDD3", + "DCVDD", + "AVDD1", + "AVDD2", + "CPVDD", + "SPKVDD1", + "SPKVDD2", +}; + #ifdef CONFIG_PM static int wm8994_device_suspend(struct device *dev) { @@ -239,7 +251,7 @@ static int wm8994_device_suspend(struct device *dev) if (ret < 0) dev_err(dev, "Failed to save LDO registers: %d\n", ret); - ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + ret = regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to disable supplies: %d\n", ret); @@ -254,7 +266,7 @@ static int wm8994_device_resume(struct device *dev) struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; - ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), + ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to enable supplies: %d\n", ret); @@ -305,9 +317,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) /* * Instantiate the generic non-control parts of the device. */ -static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) +static int wm8994_device_init(struct wm8994 *wm8994, int irq) { struct wm8994_pdata *pdata = wm8994->dev->platform_data; + const char *devname; int ret, i; mutex_init(&wm8994->io_lock); @@ -323,25 +336,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) goto err; } + switch (wm8994->type) { + case WM8994: + wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); + break; + case WM8958: + wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies); + break; + default: + BUG(); + return -EINVAL; + } + wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * - ARRAY_SIZE(wm8994_main_supplies), + wm8994->num_supplies, GFP_KERNEL); if (!wm8994->supplies) { ret = -ENOMEM; goto err; } - for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) - wm8994->supplies[i].supply = wm8994_main_supplies[i]; - - ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies), + switch (wm8994->type) { + case WM8994: + for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) + wm8994->supplies[i].supply = wm8994_main_supplies[i]; + break; + case WM8958: + for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++) + wm8994->supplies[i].supply = wm8958_main_supplies[i]; + break; + default: + BUG(); + return -EINVAL; + } + + ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); goto err_supplies; } - ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), + ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); @@ -353,7 +389,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) dev_err(wm8994->dev, "Failed to read ID register\n"); goto err_enable; } - if (ret != 0x8994) { + switch (ret) { + case 0x8994: + devname = "WM8994"; + if (wm8994->type != WM8994) + dev_warn(wm8994->dev, "Device registered as type %d\n", + wm8994->type); + wm8994->type = WM8994; + break; + case 0x8958: + devname = "WM8958"; + if (wm8994->type != WM8958) + dev_warn(wm8994->dev, "Device registered as type %d\n", + wm8994->type); + wm8994->type = WM8958; + break; + default: dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n", ret); ret = -EINVAL; @@ -370,14 +421,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) switch (ret) { case 0: case 1: - dev_warn(wm8994->dev, "revision %c not fully supported\n", - 'A' + ret); + if (wm8994->type == WM8994) + dev_warn(wm8994->dev, + "revision %c not fully supported\n", + 'A' + ret); break; default: - dev_info(wm8994->dev, "revision %c\n", 'A' + ret); break; } + dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret); if (pdata) { wm8994->irq_base = pdata->irq_base; @@ -423,10 +476,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) err_irq: wm8994_irq_exit(wm8994); err_enable: - regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); err_get: - regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); + regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); err_supplies: kfree(wm8994->supplies); err: @@ -439,9 +492,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994) { mfd_remove_devices(wm8994->dev); wm8994_irq_exit(wm8994); - regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); - regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); + regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); kfree(wm8994->supplies); kfree(wm8994); } @@ -506,8 +559,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, wm8994->read_dev = wm8994_i2c_read_device; wm8994->write_dev = wm8994_i2c_write_device; wm8994->irq = i2c->irq; + wm8994->type = id->driver_data; - return wm8994_device_init(wm8994, id->driver_data, i2c->irq); + return wm8994_device_init(wm8994, i2c->irq); } static int wm8994_i2c_remove(struct i2c_client *i2c) @@ -535,7 +589,8 @@ static int wm8994_i2c_resume(struct i2c_client *i2c) #endif static const struct i2c_device_id wm8994_i2c_id[] = { - { "wm8994", 0 }, + { "wm8994", WM8994 }, + { "wm8958", WM8958 }, { } }; MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h index de79baee4925..3fd36845ca45 100644 --- a/include/linux/mfd/wm8994/core.h +++ b/include/linux/mfd/wm8994/core.h @@ -17,6 +17,11 @@ #include +enum wm8994_type { + WM8994 = 0, + WM8958 = 1, +}; + struct regulator_dev; struct regulator_bulk_data; @@ -48,6 +53,8 @@ struct wm8994 { struct mutex io_lock; struct mutex irq_lock; + enum wm8994_type type; + struct device *dev; int (*read_dev)(struct wm8994 *wm8994, unsigned short reg, int bytes, void *dest); @@ -68,6 +75,7 @@ struct wm8994 { u16 gpio_regs[WM8994_NUM_GPIO_REGS]; struct regulator_dev *dbvdd; + int num_supplies; struct regulator_bulk_data *supplies; }; -- cgit v1.2.3 From 4b666729010cbf315c9099b956b193df8edc6753 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Sep 2010 10:47:16 +0100 Subject: gpiolib: Add WM8958 support to the WM8994 driver Several of the GPIOs on the WM8994 are fixed function on the WM8958 so error out if the user tries to request them with gpiolib. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- drivers/gpio/wm8994-gpio.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c index 618398e4ed8e..c822baacd8fc 100644 --- a/drivers/gpio/wm8994-gpio.c +++ b/drivers/gpio/wm8994-gpio.c @@ -35,6 +35,29 @@ static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip) return container_of(chip, struct wm8994_gpio, gpio_chip); } +static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + + switch (wm8994->type) { + case WM8958: + switch (offset) { + case 1: + case 2: + case 3: + case 4: + case 6: + return -EINVAL; + } + break; + default: + break; + } + + return 0; +} + static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); @@ -136,6 +159,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static struct gpio_chip template_chip = { .label = "wm8994", .owner = THIS_MODULE, + .request = wm8994_gpio_request, .direction_input = wm8994_gpio_direction_in, .get = wm8994_gpio_get, .direction_output = wm8994_gpio_direction_out, -- cgit v1.2.3 From 0c3cf4cc9abd854dcc6488719348a75b8f328c54 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:22 +0200 Subject: crypto: omap-sham - uses digest buffer in request context Currently driver storred digest results in req->results provided by the client. But some clients do not set it until final() call. It leads to crash. Changed to use internal buffer to store temporary digest results. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index a081c7c7d03f..222237014007 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -97,6 +97,7 @@ struct omap_sham_reqctx { unsigned long flags; unsigned long op; + u8 digest[SHA1_DIGEST_SIZE]; size_t digcnt; u8 *buffer; size_t bufcnt; @@ -194,7 +195,7 @@ static inline int omap_sham_wait(struct omap_sham_dev *dd, u32 offset, u32 bit) static void omap_sham_copy_hash(struct ahash_request *req, int out) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - u32 *hash = (u32 *)req->result; + u32 *hash = (u32 *)ctx->digest; int i; if (likely(ctx->flags & FLAGS_SHA1)) { @@ -453,8 +454,11 @@ static void omap_sham_cleanup(struct ahash_request *req) ctx->flags |= FLAGS_CLEAN; spin_unlock_irqrestore(&dd->lock, flags); - if (ctx->digcnt) + if (ctx->digcnt) { clk_disable(dd->iclk); + memcpy(req->result, ctx->digest, (ctx->flags & FLAGS_SHA1) ? + SHA1_DIGEST_SIZE : MD5_DIGEST_SIZE); + } if (ctx->dma_addr) dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, @@ -576,6 +580,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) static int omap_sham_finish_req_hmac(struct ahash_request *req) { + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct omap_sham_hmac_ctx *bctx = tctx->base; int bs = crypto_shash_blocksize(bctx->shash); @@ -590,7 +595,7 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req) return crypto_shash_init(&desc.shash) ?: crypto_shash_update(&desc.shash, bctx->opad, bs) ?: - crypto_shash_finup(&desc.shash, req->result, ds, req->result); + crypto_shash_finup(&desc.shash, ctx->digest, ds, ctx->digest); } static void omap_sham_finish_req(struct ahash_request *req, int err) -- cgit v1.2.3 From c8eb54041acc4dedeaf0d9da34b91b8658386751 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:23 +0200 Subject: crypto: omap-sham - DMA initialization fixes for off mode DMA parameters for constant data were initialized during driver probe(). It seems that those settings sometimes are lost when devices goes to off mode. This patch makes DMA initialization just before use. It solves off mode problems. Fixes: NB#202786 - Aegis & SHA1 block off mode changes Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 222237014007..9dfbc4ab7711 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -318,6 +318,16 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); + omap_set_dma_dest_params(dd->dma_lch, 0, + OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + SHA_REG_DIN(0), 0, 16); + + omap_set_dma_dest_burst_mode(dd->dma_lch, + OMAP_DMA_DATA_BURST_16); + + omap_set_dma_src_burst_mode(dd->dma_lch, + OMAP_DMA_DATA_BURST_4); + err = omap_sham_write_ctrl(dd, length, final, 1); if (err) return err; @@ -1071,15 +1081,6 @@ static int omap_sham_dma_init(struct omap_sham_dev *dd) dev_err(dd->dev, "Unable to request DMA channel\n"); return err; } - omap_set_dma_dest_params(dd->dma_lch, 0, - OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + SHA_REG_DIN(0), 0, 16); - - omap_set_dma_dest_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_16); - - omap_set_dma_src_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_4); return 0; } -- cgit v1.2.3 From 3e133c8bf6a6723377d94bc97aa52596e49a4090 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:24 +0200 Subject: crypto: omap-sham - error handling improved Introduces DMA error handling. DMA error is returned as a result code of the hash request. Clients needs to handle error codes and may repeat hash calculation attempt. Also in the case of DMA error, SHAM module is set to be re-initialized again. It significantly improves stability against possible HW failures. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 67 ++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 9dfbc4ab7711..db206284835a 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -83,6 +83,7 @@ #define FLAGS_INIT 0x0100 #define FLAGS_CPU 0x0200 #define FLAGS_HMAC 0x0400 +#define FLAGS_ERROR 0x0800 /* 3rd byte */ #define FLAGS_BUSY 16 @@ -137,6 +138,7 @@ struct omap_sham_dev { int irq; struct clk *iclk; spinlock_t lock; + int err; int dma; int dma_lch; struct tasklet_struct done_task; @@ -234,10 +236,12 @@ static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); if (omap_sham_wait(dd, SHA_REG_SYSSTATUS, - SHA_REG_SYSSTATUS_RESETDONE)) + SHA_REG_SYSSTATUS_RESETDONE)) { + clk_disable(dd->iclk); return -ETIMEDOUT; - + } dd->flags |= FLAGS_INIT; + dd->err = 0; } } else { omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt); @@ -279,11 +283,12 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf, if (err) return err; + /* should be non-zero before next lines to disable clocks later */ + ctx->digcnt += length; + if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY)) return -ETIMEDOUT; - ctx->digcnt += length; - if (final) ctx->flags |= FLAGS_FINAL; /* catch last interrupt */ @@ -303,7 +308,6 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n", ctx->digcnt, length, final); - /* flush cache entries related to our page */ if (dma_addr == ctx->dma_addr) dma_sync_single_for_device(dd->dev, dma_addr, length, @@ -411,6 +415,7 @@ static int omap_sham_update_dma_fast(struct omap_sham_dev *dd) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); unsigned int length; + int err; ctx->flags |= FLAGS_FAST; @@ -424,7 +429,11 @@ static int omap_sham_update_dma_fast(struct omap_sham_dev *dd) ctx->total -= length; - return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); + err = omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); + if (err != -EINPROGRESS) + dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); + + return err; } static int omap_sham_update_cpu(struct omap_sham_dev *dd) @@ -580,9 +589,6 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) ctx->bufcnt = 0; - if (err != -EINPROGRESS) - omap_sham_cleanup(req); - dev_dbg(dd->dev, "final_req: err: %d\n", err); return err; @@ -616,9 +622,11 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) omap_sham_copy_hash(ctx->dd->req, 1); if (ctx->flags & FLAGS_HMAC) err = omap_sham_finish_req_hmac(req); + } else { + ctx->flags |= FLAGS_ERROR; } - if (ctx->flags & FLAGS_FINAL) + if ((ctx->flags & FLAGS_FINAL) || err) omap_sham_cleanup(req); clear_bit(FLAGS_BUSY, &ctx->dd->flags); @@ -776,12 +784,14 @@ static int omap_sham_final(struct ahash_request *req) ctx->flags |= FLAGS_FINUP; - /* OMAP HW accel works only with buffers >= 9 */ - /* HMAC is always >= 9 because of ipad */ - if ((ctx->digcnt + ctx->bufcnt) < 9) - err = omap_sham_final_shash(req); - else if (ctx->bufcnt) - return omap_sham_enqueue(req, OP_FINAL); + if (!(ctx->flags & FLAGS_ERROR)) { + /* OMAP HW accel works only with buffers >= 9 */ + /* HMAC is always >= 9 because of ipad */ + if ((ctx->digcnt + ctx->bufcnt) < 9) + err = omap_sham_final_shash(req); + else if (ctx->bufcnt) + return omap_sham_enqueue(req, OP_FINAL); + } omap_sham_cleanup(req); @@ -851,6 +861,8 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm); const char *alg_name = crypto_tfm_alg_name(tfm); + pr_info("enter\n"); + /* Allocate a fallback and abort if it failed. */ tctx->fallback = crypto_alloc_shash(alg_name, 0, CRYPTO_ALG_NEED_FALLBACK); @@ -1008,7 +1020,7 @@ static void omap_sham_done_task(unsigned long data) struct omap_sham_dev *dd = (struct omap_sham_dev *)data; struct ahash_request *req = dd->req; struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - int ready = 1; + int ready = 0, err = 0; if (ctx->flags & FLAGS_OUTPUT_READY) { ctx->flags &= ~FLAGS_OUTPUT_READY; @@ -1018,13 +1030,16 @@ static void omap_sham_done_task(unsigned long data) if (dd->flags & FLAGS_DMA_ACTIVE) { dd->flags &= ~FLAGS_DMA_ACTIVE; omap_sham_update_dma_stop(dd); - omap_sham_update_dma_slow(dd); + if (!dd->err) + err = omap_sham_update_dma_slow(dd); } - if (ready && !(dd->flags & FLAGS_DMA_ACTIVE)) { - dev_dbg(dd->dev, "update done\n"); + err = dd->err ? : err; + + if (err != -EINPROGRESS && (ready || err)) { + dev_dbg(dd->dev, "update done: err: %d\n", err); /* finish curent request */ - omap_sham_finish_req(req, 0); + omap_sham_finish_req(req, err); /* start new request */ omap_sham_handle_queue(dd); } @@ -1056,6 +1071,7 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id) omap_sham_read(dd, SHA_REG_CTRL); ctx->flags |= FLAGS_OUTPUT_READY; + dd->err = 0; tasklet_schedule(&dd->done_task); return IRQ_HANDLED; @@ -1065,8 +1081,13 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data) { struct omap_sham_dev *dd = data; - if (likely(lch == dd->dma_lch)) - tasklet_schedule(&dd->done_task); + if (ch_status != OMAP_DMA_BLOCK_IRQ) { + pr_err("omap-sham DMA error status: 0x%hx\n", ch_status); + dd->err = -EIO; + dd->flags &= ~FLAGS_INIT; /* request to re-initialize */ + } + + tasklet_schedule(&dd->done_task); } static int omap_sham_dma_init(struct omap_sham_dev *dd) -- cgit v1.2.3 From a5d87237bb15eed8449e5a30c0bbe626e0e7f43d Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:25 +0200 Subject: crypto: omap-sham - removed redundunt locking Locking for queuing and dequeuing is combined. test_and_set_bit() is also replaced with checking under dd->lock. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 47 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index db206284835a..6340c5ef4712 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -84,9 +84,7 @@ #define FLAGS_CPU 0x0200 #define FLAGS_HMAC 0x0400 #define FLAGS_ERROR 0x0800 - -/* 3rd byte */ -#define FLAGS_BUSY 16 +#define FLAGS_BUSY 0x1000 #define OP_UPDATE 1 #define OP_FINAL 2 @@ -629,32 +627,37 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if ((ctx->flags & FLAGS_FINAL) || err) omap_sham_cleanup(req); - clear_bit(FLAGS_BUSY, &ctx->dd->flags); + ctx->dd->flags &= ~FLAGS_BUSY; if (req->base.complete) req->base.complete(&req->base, err); } -static int omap_sham_handle_queue(struct omap_sham_dev *dd) +static int omap_sham_handle_queue(struct omap_sham_dev *dd, + struct ahash_request *req) { struct crypto_async_request *async_req, *backlog; struct omap_sham_reqctx *ctx; - struct ahash_request *req, *prev_req; + struct ahash_request *prev_req; unsigned long flags; - int err = 0; - - if (test_and_set_bit(FLAGS_BUSY, &dd->flags)) - return 0; + int err = 0, ret = 0; spin_lock_irqsave(&dd->lock, flags); - backlog = crypto_get_backlog(&dd->queue); + if (req) + ret = ahash_enqueue_request(&dd->queue, req); + if (dd->flags & FLAGS_BUSY) { + spin_unlock_irqrestore(&dd->lock, flags); + return ret; + } async_req = crypto_dequeue_request(&dd->queue); - if (!async_req) - clear_bit(FLAGS_BUSY, &dd->flags); + if (async_req) { + dd->flags |= FLAGS_BUSY; + backlog = crypto_get_backlog(&dd->queue); + } spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) - return 0; + return ret; if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -690,7 +693,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd) dev_dbg(dd->dev, "exit, err: %d\n", err); - return err; + return ret; } static int omap_sham_enqueue(struct ahash_request *req, unsigned int op) @@ -698,18 +701,10 @@ static int omap_sham_enqueue(struct ahash_request *req, unsigned int op) struct omap_sham_reqctx *ctx = ahash_request_ctx(req); struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct omap_sham_dev *dd = tctx->dd; - unsigned long flags; - int err; ctx->op = op; - spin_lock_irqsave(&dd->lock, flags); - err = ahash_enqueue_request(&dd->queue, req); - spin_unlock_irqrestore(&dd->lock, flags); - - omap_sham_handle_queue(dd); - - return err; + return omap_sham_handle_queue(dd, req); } static int omap_sham_update(struct ahash_request *req) @@ -1041,7 +1036,7 @@ static void omap_sham_done_task(unsigned long data) /* finish curent request */ omap_sham_finish_req(req, err); /* start new request */ - omap_sham_handle_queue(dd); + omap_sham_handle_queue(dd, NULL); } } @@ -1049,7 +1044,7 @@ static void omap_sham_queue_task(unsigned long data) { struct omap_sham_dev *dd = (struct omap_sham_dev *)data; - omap_sham_handle_queue(dd); + omap_sham_handle_queue(dd, NULL); } static irqreturn_t omap_sham_irq(int irq, void *dev_id) -- cgit v1.2.3 From 798eed5d9204b01862985ba0643ce5cf84114072 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:26 +0200 Subject: crypto: omap-sham - crypto_ahash_final() now not need to be called. According to the Herbert Xu, client may not always call crypto_ahash_final(). In the case of error in hash calculation resources will be automatically cleaned up. But if no hash calculation error happens and client will not call crypto_ahash_final() at all, then internal buffer will not be freed, and clocks will not be disabled. This patch provides support for atomic crypto_ahash_update() call. Clocks are now enabled and disabled per update request. Data buffer is now allocated as a part of request context. Client is obligated to free it with crypto_free_ahash(). Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 168 ++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 6340c5ef4712..85d627774538 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -89,6 +89,11 @@ #define OP_UPDATE 1 #define OP_FINAL 2 +#define OMAP_ALIGN_MASK (sizeof(u32)-1) +#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32)))) + +#define BUFLEN PAGE_SIZE + struct omap_sham_dev; struct omap_sham_reqctx { @@ -96,9 +101,8 @@ struct omap_sham_reqctx { unsigned long flags; unsigned long op; - u8 digest[SHA1_DIGEST_SIZE]; + u8 digest[SHA1_DIGEST_SIZE] OMAP_ALIGNED; size_t digcnt; - u8 *buffer; size_t bufcnt; size_t buflen; dma_addr_t dma_addr; @@ -107,6 +111,8 @@ struct omap_sham_reqctx { struct scatterlist *sg; unsigned int offset; /* offset in current sg */ unsigned int total; /* total request */ + + u8 buffer[0] OMAP_ALIGNED; }; struct omap_sham_hmac_ctx { @@ -219,31 +225,33 @@ static void omap_sham_copy_hash(struct ahash_request *req, int out) } } -static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, - int final, int dma) +static int omap_sham_hw_init(struct omap_sham_dev *dd) { - struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - u32 val = length << 5, mask; + clk_enable(dd->iclk); - if (unlikely(!ctx->digcnt)) { + if (!(dd->flags & FLAGS_INIT)) { + omap_sham_write_mask(dd, SHA_REG_MASK, + SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); - clk_enable(dd->iclk); + if (omap_sham_wait(dd, SHA_REG_SYSSTATUS, + SHA_REG_SYSSTATUS_RESETDONE)) + return -ETIMEDOUT; - if (!(dd->flags & FLAGS_INIT)) { - omap_sham_write_mask(dd, SHA_REG_MASK, - SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); + dd->flags |= FLAGS_INIT; + dd->err = 0; + } - if (omap_sham_wait(dd, SHA_REG_SYSSTATUS, - SHA_REG_SYSSTATUS_RESETDONE)) { - clk_disable(dd->iclk); - return -ETIMEDOUT; - } - dd->flags |= FLAGS_INIT; - dd->err = 0; - } - } else { + return 0; +} + +static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, + int final, int dma) +{ + struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); + u32 val = length << 5, mask; + + if (likely(ctx->digcnt)) omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt); - } omap_sham_write_mask(dd, SHA_REG_MASK, SHA_REG_MASK_IT_EN | (dma ? SHA_REG_MASK_DMA_EN : 0), @@ -263,23 +271,19 @@ static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH; omap_sham_write_mask(dd, SHA_REG_CTRL, val, mask); - - return 0; } static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf, size_t length, int final) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - int err, count, len32; + int count, len32; const u32 *buffer = (const u32 *)buf; dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n", ctx->digcnt, length, final); - err = omap_sham_write_ctrl(dd, length, final, 0); - if (err) - return err; + omap_sham_write_ctrl(dd, length, final, 0); /* should be non-zero before next lines to disable clocks later */ ctx->digcnt += length; @@ -302,14 +306,10 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, size_t length, int final) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - int err, len32; + int len32; dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n", ctx->digcnt, length, final); - /* flush cache entries related to our page */ - if (dma_addr == ctx->dma_addr) - dma_sync_single_for_device(dd->dev, dma_addr, length, - DMA_TO_DEVICE); len32 = DIV_ROUND_UP(length, sizeof(u32)); @@ -320,19 +320,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); - omap_set_dma_dest_params(dd->dma_lch, 0, - OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + SHA_REG_DIN(0), 0, 16); - - omap_set_dma_dest_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_16); - - omap_set_dma_src_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_4); - - err = omap_sham_write_ctrl(dd, length, final, 1); - if (err) - return err; + omap_sham_write_ctrl(dd, length, final, 1); ctx->digcnt += length; @@ -384,6 +372,21 @@ static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx) return 0; } +static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd, + struct omap_sham_reqctx *ctx, + size_t length, int final) +{ + ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen, + DMA_TO_DEVICE); + if (dma_mapping_error(dd->dev, ctx->dma_addr)) { + dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen); + return -EINVAL; + } + + /* next call does not fail... so no unmap in the case of error */ + return omap_sham_xmit_dma(dd, ctx->dma_addr, length, final); +} + static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); @@ -403,7 +406,7 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) { count = ctx->bufcnt; ctx->bufcnt = 0; - return omap_sham_xmit_dma(dd, ctx->dma_addr, count, final); + return omap_sham_xmit_dma_map(dd, ctx, count, final); } return 0; @@ -413,7 +416,6 @@ static int omap_sham_update_dma_fast(struct omap_sham_dev *dd) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); unsigned int length; - int err; ctx->flags |= FLAGS_FAST; @@ -427,11 +429,8 @@ static int omap_sham_update_dma_fast(struct omap_sham_dev *dd) ctx->total -= length; - err = omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); - if (err != -EINPROGRESS) - dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); - - return err; + /* next call does not fail... so no unmap in the case of error */ + return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); } static int omap_sham_update_cpu(struct omap_sham_dev *dd) @@ -453,6 +452,9 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd) omap_stop_dma(dd->dma_lch); if (ctx->flags & FLAGS_FAST) dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); + else + dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, + DMA_TO_DEVICE); return 0; } @@ -471,18 +473,9 @@ static void omap_sham_cleanup(struct ahash_request *req) ctx->flags |= FLAGS_CLEAN; spin_unlock_irqrestore(&dd->lock, flags); - if (ctx->digcnt) { - clk_disable(dd->iclk); + if (ctx->digcnt) memcpy(req->result, ctx->digest, (ctx->flags & FLAGS_SHA1) ? SHA1_DIGEST_SIZE : MD5_DIGEST_SIZE); - } - - if (ctx->dma_addr) - dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, - DMA_TO_DEVICE); - - if (ctx->buffer) - free_page((unsigned long)ctx->buffer); dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); } @@ -520,21 +513,7 @@ static int omap_sham_init(struct ahash_request *req) ctx->bufcnt = 0; ctx->digcnt = 0; - - ctx->buflen = PAGE_SIZE; - ctx->buffer = (void *)__get_free_page( - (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC); - if (!ctx->buffer) - return -ENOMEM; - - ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen, - DMA_TO_DEVICE); - if (dma_mapping_error(dd->dev, ctx->dma_addr)) { - dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen); - free_page((unsigned long)ctx->buffer); - return -EINVAL; - } + ctx->buflen = BUFLEN; if (tctx->flags & FLAGS_HMAC) { struct omap_sham_hmac_ctx *bctx = tctx->base; @@ -581,7 +560,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) use_dma = 0; if (use_dma) - err = omap_sham_xmit_dma(dd, ctx->dma_addr, ctx->bufcnt, 1); + err = omap_sham_xmit_dma_map(dd, ctx, ctx->bufcnt, 1); else err = omap_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1); @@ -615,6 +594,7 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req) static void omap_sham_finish_req(struct ahash_request *req, int err) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + struct omap_sham_dev *dd = ctx->dd; if (!err) { omap_sham_copy_hash(ctx->dd->req, 1); @@ -627,7 +607,8 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if ((ctx->flags & FLAGS_FINAL) || err) omap_sham_cleanup(req); - ctx->dd->flags &= ~FLAGS_BUSY; + clk_disable(dd->iclk); + dd->flags &= ~FLAGS_BUSY; if (req->base.complete) req->base.complete(&req->base, err); @@ -636,7 +617,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) static int omap_sham_handle_queue(struct omap_sham_dev *dd, struct ahash_request *req) { - struct crypto_async_request *async_req, *backlog; + struct crypto_async_request *async_req, *backlog = 0; struct omap_sham_reqctx *ctx; struct ahash_request *prev_req; unsigned long flags; @@ -672,7 +653,22 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", ctx->op, req->nbytes); - if (req != prev_req && ctx->digcnt) + + err = omap_sham_hw_init(dd); + if (err) + goto err1; + + omap_set_dma_dest_params(dd->dma_lch, 0, + OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + SHA_REG_DIN(0), 0, 16); + + omap_set_dma_dest_burst_mode(dd->dma_lch, + OMAP_DMA_DATA_BURST_16); + + omap_set_dma_src_burst_mode(dd->dma_lch, + OMAP_DMA_DATA_BURST_4); + + if (ctx->digcnt) /* request has changed - restore hash */ omap_sham_copy_hash(req, 0); @@ -684,7 +680,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, } else if (ctx->op == OP_FINAL) { err = omap_sham_final_req(dd); } - +err1: if (err != -EINPROGRESS) { /* done_task will not finish it, so do it here */ omap_sham_finish_req(req, err); @@ -868,7 +864,7 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) } crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct omap_sham_reqctx)); + sizeof(struct omap_sham_reqctx) + BUFLEN); if (alg_base) { struct omap_sham_hmac_ctx *bctx = tctx->base; @@ -954,7 +950,7 @@ static struct ahash_alg algs[] = { CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_sham_ctx), - .cra_alignmask = 0, + .cra_alignmask = OMAP_ALIGN_MASK, .cra_module = THIS_MODULE, .cra_init = omap_sham_cra_init, .cra_exit = omap_sham_cra_exit, @@ -978,7 +974,7 @@ static struct ahash_alg algs[] = { .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_sham_ctx) + sizeof(struct omap_sham_hmac_ctx), - .cra_alignmask = 0, + .cra_alignmask = OMAP_ALIGN_MASK, .cra_module = THIS_MODULE, .cra_init = omap_sham_cra_sha1_init, .cra_exit = omap_sham_cra_exit, @@ -1002,7 +998,7 @@ static struct ahash_alg algs[] = { .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_sham_ctx) + sizeof(struct omap_sham_hmac_ctx), - .cra_alignmask = 0, + .cra_alignmask = OMAP_ALIGN_MASK, .cra_module = THIS_MODULE, .cra_init = omap_sham_cra_md5_init, .cra_exit = omap_sham_cra_exit, -- cgit v1.2.3 From 3c8d758ab528317ecd6d91f8651170ffd2331899 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:27 +0200 Subject: crypto: omap-sham - hash-in-progress is stored in hw format Hash-in-progress is now stored in hw format. Only on final call, hash is converted to correct format. Speedup copy procedure and will allow to use OMAP burst mode. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 85d627774538..c8d30eb4794a 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -204,24 +204,35 @@ static void omap_sham_copy_hash(struct ahash_request *req, int out) u32 *hash = (u32 *)ctx->digest; int i; + /* MD5 is almost unused. So copy sha1 size to reduce code */ + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) { + if (out) + hash[i] = omap_sham_read(ctx->dd, + SHA_REG_DIGEST(i)); + else + omap_sham_write(ctx->dd, + SHA_REG_DIGEST(i), hash[i]); + } +} + +static void omap_sham_copy_ready_hash(struct ahash_request *req) +{ + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + u32 *in = (u32 *)ctx->digest; + u32 *hash = (u32 *)req->result; + int i; + + if (!hash) + return; + if (likely(ctx->flags & FLAGS_SHA1)) { /* SHA1 results are in big endian */ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) - if (out) - hash[i] = be32_to_cpu(omap_sham_read(ctx->dd, - SHA_REG_DIGEST(i))); - else - omap_sham_write(ctx->dd, SHA_REG_DIGEST(i), - cpu_to_be32(hash[i])); + hash[i] = be32_to_cpu(in[i]); } else { /* MD5 results are in little endian */ for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++) - if (out) - hash[i] = le32_to_cpu(omap_sham_read(ctx->dd, - SHA_REG_DIGEST(i))); - else - omap_sham_write(ctx->dd, SHA_REG_DIGEST(i), - cpu_to_le32(hash[i])); + hash[i] = le32_to_cpu(in[i]); } } @@ -474,8 +485,7 @@ static void omap_sham_cleanup(struct ahash_request *req) spin_unlock_irqrestore(&dd->lock, flags); if (ctx->digcnt) - memcpy(req->result, ctx->digest, (ctx->flags & FLAGS_SHA1) ? - SHA1_DIGEST_SIZE : MD5_DIGEST_SIZE); + omap_sham_copy_ready_hash(req); dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); } -- cgit v1.2.3 From a55b290b0e41e02d1969589c5d77d966ac2b7ec8 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:28 +0200 Subject: crypto: omap-sham - FLAGS_FIRST is redundant and removed bufcnt is 0 if it was no update requests before, which is exact meaning of FLAGS_FIRST. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index c8d30eb4794a..d88d7ebfffa7 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -72,7 +72,6 @@ #define DEFAULT_TIMEOUT_INTERVAL HZ -#define FLAGS_FIRST 0x0001 #define FLAGS_FINUP 0x0002 #define FLAGS_FINAL 0x0004 #define FLAGS_FAST 0x0008 @@ -513,8 +512,6 @@ static int omap_sham_init(struct ahash_request *req) ctx->flags = 0; - ctx->flags |= FLAGS_FIRST; - dev_dbg(dd->dev, "init: digest size: %d\n", crypto_ahash_digestsize(tfm)); @@ -739,12 +736,9 @@ static int omap_sham_update(struct ahash_request *req) /* may be can use faster functions */ int aligned = IS_ALIGNED((u32)ctx->sg->offset, sizeof(u32)); - - if (aligned && (ctx->flags & FLAGS_FIRST)) + if (aligned) /* digest: first and final */ ctx->flags |= FLAGS_FAST; - - ctx->flags &= ~FLAGS_FIRST; } } else if (ctx->bufcnt + ctx->total <= ctx->buflen) { /* if not finaup -> not fast */ -- cgit v1.2.3 From 887c883eea9867535059f3c8414c8cfc952ccff1 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Fri, 19 Nov 2010 16:04:29 +0200 Subject: crypto: omap-sham - zero-copy scatterlist handling If scatterlist have more than one entry, current driver uses aligned buffer to copy data to to accelerator to tackle possible issues with DMA and SHA buffer alignment. This commit adds more intelligence to verify SG alignment and possibility to use DMA directly on the data without using copy buffer. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 87 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index d88d7ebfffa7..eb988e7a2fd9 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -74,7 +74,7 @@ #define FLAGS_FINUP 0x0002 #define FLAGS_FINAL 0x0004 -#define FLAGS_FAST 0x0008 +#define FLAGS_SG 0x0008 #define FLAGS_SHA1 0x0010 #define FLAGS_DMA_ACTIVE 0x0020 #define FLAGS_OUTPUT_READY 0x0040 @@ -393,6 +393,8 @@ static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd, return -EINVAL; } + ctx->flags &= ~FLAGS_SG; + /* next call does not fail... so no unmap in the case of error */ return omap_sham_xmit_dma(dd, ctx->dma_addr, length, final); } @@ -403,9 +405,6 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) unsigned int final; size_t count; - if (!ctx->total) - return 0; - omap_sham_append_sg(ctx); final = (ctx->flags & FLAGS_FINUP) && !ctx->total; @@ -422,25 +421,62 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) return 0; } -static int omap_sham_update_dma_fast(struct omap_sham_dev *dd) +/* Start address alignment */ +#define SG_AA(sg) (IS_ALIGNED(sg->offset, sizeof(u32))) +/* SHA1 block size alignment */ +#define SG_SA(sg) (IS_ALIGNED(sg->length, SHA1_MD5_BLOCK_SIZE)) + +static int omap_sham_update_dma_start(struct omap_sham_dev *dd) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - unsigned int length; + unsigned int length, final, tail; + struct scatterlist *sg; + + if (!ctx->total) + return 0; + + if (ctx->bufcnt || ctx->offset) + return omap_sham_update_dma_slow(dd); + + dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n", + ctx->digcnt, ctx->bufcnt, ctx->total); + + sg = ctx->sg; - ctx->flags |= FLAGS_FAST; + if (!SG_AA(sg)) + return omap_sham_update_dma_slow(dd); - length = min(ctx->total, sg_dma_len(ctx->sg)); - ctx->total = length; + if (!sg_is_last(sg) && !SG_SA(sg)) + /* size is not SHA1_BLOCK_SIZE aligned */ + return omap_sham_update_dma_slow(dd); + + length = min(ctx->total, sg->length); + + if (sg_is_last(sg)) { + if (!(ctx->flags & FLAGS_FINUP)) { + /* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */ + tail = length & (SHA1_MD5_BLOCK_SIZE - 1); + /* without finup() we need one block to close hash */ + if (!tail) + tail = SHA1_MD5_BLOCK_SIZE; + length -= tail; + } + } if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) { dev_err(dd->dev, "dma_map_sg error\n"); return -EINVAL; } + ctx->flags |= FLAGS_SG; + ctx->total -= length; + ctx->offset = length; /* offset where to start slow */ + + final = (ctx->flags & FLAGS_FINUP) && !ctx->total; /* next call does not fail... so no unmap in the case of error */ - return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); + return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final); } static int omap_sham_update_cpu(struct omap_sham_dev *dd) @@ -460,11 +496,17 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd) struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); omap_stop_dma(dd->dma_lch); - if (ctx->flags & FLAGS_FAST) + if (ctx->flags & FLAGS_SG) { dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); - else + if (ctx->sg->length == ctx->offset) { + ctx->sg = sg_next(ctx->sg); + if (ctx->sg) + ctx->offset = 0; + } + } else { dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, DMA_TO_DEVICE); + } return 0; } @@ -545,10 +587,8 @@ static int omap_sham_update_req(struct omap_sham_dev *dd) if (ctx->flags & FLAGS_CPU) err = omap_sham_update_cpu(dd); - else if (ctx->flags & FLAGS_FAST) - err = omap_sham_update_dma_fast(dd); else - err = omap_sham_update_dma_slow(dd); + err = omap_sham_update_dma_start(dd); /* wait for dma completion before can take more data */ dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt); @@ -730,18 +770,13 @@ static int omap_sham_update(struct ahash_request *req) */ omap_sham_append_sg(ctx); return 0; - } else if (ctx->bufcnt + ctx->total <= 64) { + } else if (ctx->bufcnt + ctx->total <= SHA1_MD5_BLOCK_SIZE) { + /* + * faster to use CPU for short transfers + */ ctx->flags |= FLAGS_CPU; - } else if (!ctx->bufcnt && sg_is_last(ctx->sg)) { - /* may be can use faster functions */ - int aligned = IS_ALIGNED((u32)ctx->sg->offset, - sizeof(u32)); - if (aligned) - /* digest: first and final */ - ctx->flags |= FLAGS_FAST; } - } else if (ctx->bufcnt + ctx->total <= ctx->buflen) { - /* if not finaup -> not fast */ + } else if (ctx->bufcnt + ctx->total < ctx->buflen) { omap_sham_append_sg(ctx); return 0; } @@ -1026,7 +1061,7 @@ static void omap_sham_done_task(unsigned long data) dd->flags &= ~FLAGS_DMA_ACTIVE; omap_sham_update_dma_stop(dd); if (!dd->err) - err = omap_sham_update_dma_slow(dd); + err = omap_sham_update_dma_start(dd); } err = dd->err ? : err; -- cgit v1.2.3 From 602606a472963a67b234e6b5c99293de4aa9d06b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 28 Nov 2010 15:31:02 +0000 Subject: drm/i915/execbuffer: On error, starting unwinding from the previous object As the error occurred on the current object, it means that its state was not changed and so it should be excluded from the unwind. Reported-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d54070111f9d..66c898c8716d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -530,6 +530,9 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, } while (1); err: + obj = list_entry(obj->exec_list.prev, + struct drm_i915_gem_object, + exec_list); while (objects != &obj->exec_list) { if (obj->gtt_space) i915_gem_object_unpin(obj); -- cgit v1.2.3 From ce06b9d6d33fd2ed799b6e825d68fe95077da354 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 28 Nov 2010 16:37:14 +0100 Subject: HID: hid-core - rename hid_blacklist to hid_have_special_driver To avoid confusion with hid_blacklist describing various quirks in usbhid code, let's rename this one. Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index dc56bd61edb7..396f8c7e0076 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1230,7 +1230,7 @@ void hid_disconnect(struct hid_device *hdev) EXPORT_SYMBOL_GPL(hid_disconnect); /* a list of devices for which there is a specialized driver on HID bus */ -static const struct hid_device_id hid_blacklist[] = { +static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, @@ -1503,9 +1503,9 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv) if (!hid_match_device(hdev, hdrv)) return 0; - /* generic wants all non-blacklisted */ + /* generic wants all that don't have specialized driver */ if (!strncmp(hdrv->name, "generic-", 8)) - return !hid_match_id(hdev, hid_blacklist); + return !hid_match_id(hdev, hid_have_special_driver); return 1; } -- cgit v1.2.3 From 7d2cb39c332146b0906651a8567f8b81af4b1584 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 27 Nov 2010 17:38:29 +0000 Subject: drm/i915: Release fenced GTT mapping on suspend ... so that upon first use after resume we will reacquire the fence reg. Reported-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a090acdf3bd5..eae52de75a4c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1794,8 +1794,15 @@ static void i915_gem_reset_fences(struct drm_device *dev) for (i = 0; i < 16; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - if (reg->obj) - i915_gem_clear_fence_reg(reg->obj); + struct drm_i915_gem_object *obj = reg->obj; + + if (!obj) + continue; + + if (obj->tiling_mode) + i915_gem_release_mmap(obj); + + i915_gem_clear_fence_reg(obj); } } -- cgit v1.2.3 From a0e39349d80d8b5deeb264fb190bd064f7063252 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 23 Nov 2010 17:50:32 -0500 Subject: tpm: add module_put wrapper For readability, define a tpm_chip_put() wrapper to call module_put(). Replace existing module_put() calls with the wrapper. (Change based on trusted/encrypted patchset review by David Howells.) Signed-off-by: Mimi Zohar Signed-off-by: David Safford Acked-by: David Howells Acked-by: Serge E. Hallyn Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 4 ++-- drivers/char/tpm/tpm.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 7c4133582dba..26c09f3b4a74 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -736,7 +736,7 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) if (chip == NULL) return -ENODEV; rc = __tpm_pcr_read(chip, pcr_idx, res_buf); - module_put(chip->dev->driver->owner); + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_read); @@ -775,7 +775,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, "attempting extend a PCR value"); - module_put(chip->dev->driver->owner); + tpm_chip_put(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_extend); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 792868d24f2a..72ddb031b69a 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -113,6 +113,11 @@ struct tpm_chip { #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) +static inline void tpm_chip_put(struct tpm_chip *chip) +{ + module_put(chip->dev->driver->owner); +} + static inline int tpm_read_index(int base, int index) { outb(index, base); -- cgit v1.2.3 From c749ba912e87ccebd674ae24b97462176c63732e Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 23 Nov 2010 18:54:16 -0500 Subject: key: add tpm_send command Add internal kernel tpm_send() command used to seal/unseal keys. Changelog: - replaced module_put in tpm_send() with new tpm_chip_put() wrapper (suggested by David Howells) - Make tpm_send() cmd argument a 'void *' (suggested by David Howells) Signed-off-by: David Safford Signed-off-by: Mimi Zohar Acked-by: David Howells Acked-by: Serge E. Hallyn Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 16 ++++++++++++++++ include/linux/tpm.h | 4 ++++ 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 26c09f3b4a74..068bac858b4a 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -780,6 +780,22 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) } EXPORT_SYMBOL_GPL(tpm_pcr_extend); +int tpm_send(u32 chip_num, void *cmd, size_t buflen) +{ + struct tpm_chip *chip; + int rc; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL) + return -ENODEV; + + rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); + + tpm_chip_put(chip); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_send); + ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/include/linux/tpm.h b/include/linux/tpm.h index ac5d1c1285d9..fdc718abf83b 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -31,6 +31,7 @@ extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); +extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); #else static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { return -ENODEV; @@ -38,5 +39,8 @@ static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { return -ENODEV; } +static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { + return -ENODEV; +} #endif #endif -- cgit v1.2.3 From 5a71c61b7724ad0acedff254e07dc1a7dd05ee76 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Sep 2010 09:47:42 +0000 Subject: drivers/char/hvc_vio: Use static const char arrays Signed-off-by: Joe Perches Reviewed-by: Stephen Rothwell Signed-off-by: Benjamin Herrenschmidt --- drivers/char/hvc_vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 27370e99c66f..5e2f52b33327 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -39,7 +39,7 @@ #include "hvc_console.h" -char hvc_driver_name[] = "hvc_console"; +static const char hvc_driver_name[] = "hvc_console"; static struct vio_device_id hvc_driver_table[] __devinitdata = { {"serial", "hvterm1"}, -- cgit v1.2.3 From 8cb7c71bda16e2d67a332642661e0b4219641a23 Mon Sep 17 00:00:00 2001 From: Srikanth Krishnakar Date: Thu, 14 Oct 2010 04:03:35 +0000 Subject: rtc-cmos.c : Fix warning on PowerPC The following warning is seen while compilation of PowerPC kernel: CC drivers/rtc/rtc-cmos.o drivers/rtc/rtc-cmos.c:697:2: warning: #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. Fix it by adding defined(__powerpc__). Signed-off-by: Srikanth Krishnakar Signed-off-by: Benjamin Herrenschmidt --- drivers/rtc/rtc-cmos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 5856167a0c90..7e6ce626b7f1 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -687,7 +687,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) #if defined(CONFIG_ATARI) address_space = 64; #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \ - || defined(__sparc__) || defined(__mips__) + || defined(__sparc__) || defined(__mips__) \ + || defined(__powerpc__) address_space = 128; #else #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. -- cgit v1.2.3 From 72b962d3bba19657abaa6cc8806661ecbde5ee92 Mon Sep 17 00:00:00 2001 From: Tracey Dent Date: Fri, 15 Oct 2010 17:30:48 +0000 Subject: powerpc/ps3: Replace the use of -objs with -y Changed -objs to -y in Makefile. Signed-off-by: Tracey Dent Signed-off-by: Benjamin Herrenschmidt --- drivers/ps3/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index ccea15c11c19..50cb1e1b4a12 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_PS3_VUART) += ps3-vuart.o obj-$(CONFIG_PS3_PS3AV) += ps3av_mod.o -ps3av_mod-objs += ps3av.o ps3av_cmd.o +ps3av_mod-y := ps3av.o ps3av_cmd.o obj-$(CONFIG_PPC_PS3) += sys-manager-core.o obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o -- cgit v1.2.3 From f6aedd8606ae673f8e1f4d972fc86c451fbc8ba7 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Tue, 26 Oct 2010 17:35:11 +0000 Subject: powerpc/macio: Ensure all dma routines get copied over Also add a comment to dev_archdata, indicating that changes there need to be verified against the driver code. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/device.h | 6 ++++++ drivers/macintosh/macio_asic.c | 7 +++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index a3954e4fcbe2..16d25c0974be 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h @@ -9,6 +9,12 @@ struct dma_map_ops; struct device_node; +/* + * Arch extensions to struct device. + * + * When adding fields, consider macio_add_one_device in + * drivers/macintosh/macio_asic.c + */ struct dev_archdata { /* DMA operations on that device */ struct dma_map_ops *dma_ops; diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index b6e7ddc09d76..4daf9e5a7736 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -387,11 +387,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, /* Set the DMA ops to the ones from the PCI device, this could be * fishy if we didn't know that on PowerMac it's always direct ops * or iommu ops that will work fine + * + * To get all the fields, copy all archdata */ - dev->ofdev.dev.archdata.dma_ops = - chip->lbus.pdev->dev.archdata.dma_ops; - dev->ofdev.dev.archdata.dma_data = - chip->lbus.pdev->dev.archdata.dma_data; + dev->ofdev.dev.archdata = chip->lbus.pdev->dev.archdata; #endif /* CONFIG_PCI */ #ifdef DEBUG -- cgit v1.2.3 From 95bd48578bbe66fa5d16029c59dfbe95749a5f0b Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 20 Nov 2010 20:06:18 +0800 Subject: staging: brcm80211: remove duplicated #include Remove duplicated #include('s) in drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c Signed-off-by: Huang Weiyi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index b907376d054d..0d7aa4adbb77 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -29,10 +29,6 @@ #include #include -#include -#include -#include - #include #include #include -- cgit v1.2.3 From b5a49481754a5cbfdc47bd701208f77c5c9010c6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 22 Nov 2010 11:15:23 +0100 Subject: staging: iio: dac: Enable driver support for AD5444 and AD5446 DA converters Enable support for AD5444 and AD5446: 12-/14-Bit High Bandwidth Multiplying DACs with Serial Interface. staging: iio: dac: Add support for AD5541A, AD5512A digital to analog convertors staging: iio: dac: Fix according to review feedback Review feedback by Jonathan Cameron: Remove spurious new line. Document struct members. Remove redundant variable initialization. Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/Kconfig | 10 ++ drivers/staging/iio/dac/Makefile | 1 + drivers/staging/iio/dac/ad5446.c | 249 +++++++++++++++++++++++++++++++++++++++ drivers/staging/iio/dac/ad5446.h | 46 ++++++++ 4 files changed, 306 insertions(+) create mode 100644 drivers/staging/iio/dac/ad5446.c create mode 100644 drivers/staging/iio/dac/ad5446.h (limited to 'drivers') diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig index 583df785fd25..9c497ccd3dce 100644 --- a/drivers/staging/iio/dac/Kconfig +++ b/drivers/staging/iio/dac/Kconfig @@ -9,3 +9,13 @@ config AD5624R_SPI help Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R convertors (DAC). This driver uses the common SPI interface. + +config AD5446 + tristate "Analog Devices AD5444, AD5446 and AD5541A, AD5512A DAC SPI driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD5444, AD5446 + and AD5541A, AD5512A DACs. + + To compile this driver as a module, choose M here: the + module will be called ad5446. diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile index 7ddf05d5f1b4..7cf331b4e001 100644 --- a/drivers/staging/iio/dac/Makefile +++ b/drivers/staging/iio/dac/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o +obj-$(CONFIG_AD5446) += ad5446.o diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c new file mode 100644 index 000000000000..ac3165b0aeff --- /dev/null +++ b/drivers/staging/iio/dac/ad5446.c @@ -0,0 +1,249 @@ +/* + * AD5446 SPI DAC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "dac.h" + +#include "ad5446.h" + +static ssize_t ad5446_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad5446_state *st = dev_info->dev_data; + int ret; + long val; + + ret = strict_strtol(buf, 10, &val); + if (ret) + goto error_ret; + + if (val > RES_MASK(st->chip_info->bits)) { + ret = -EINVAL; + goto error_ret; + } + + mutex_lock(&dev_info->mlock); + switch (spi_get_device_id(st->spi)->driver_data) { + case ID_AD5444: + case ID_AD5446: + st->data = cpu_to_be16(AD5446_LOAD | + (val << st->chip_info->left_shift)); + break; + case ID_AD5542A: + case ID_AD5512A: + st->data = cpu_to_be16(val << st->chip_info->left_shift); + break; + } + + ret = spi_sync(st->spi, &st->msg); + mutex_unlock(&dev_info->mlock); + +error_ret: + return ret ? ret : len; +} + +static IIO_DEV_ATTR_OUT_RAW(0, ad5446_write, 0); + +static ssize_t ad5446_show_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad5446_state *st = iio_dev_get_devdata(dev_info); + /* Corresponds to Vref / 2^(bits) */ + unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; + + return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); +} +static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0); + +static ssize_t ad5446_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad5446_state *st = iio_dev_get_devdata(dev_info); + + return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); +} +static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0); + +static struct attribute *ad5446_attributes[] = { + &iio_dev_attr_out0_raw.dev_attr.attr, + &iio_dev_attr_out_scale.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad5446_attribute_group = { + .attrs = ad5446_attributes, +}; + +static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { + [ID_AD5444] = { + .bits = 12, + .storagebits = 16, + .left_shift = 2, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + }, + [ID_AD5446] = { + .bits = 14, + .storagebits = 16, + .left_shift = 0, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + }, + [ID_AD5542A] = { + .bits = 16, + .storagebits = 16, + .left_shift = 0, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + }, + [ID_AD5512A] = { + .bits = 12, + .storagebits = 16, + .left_shift = 4, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + }, +}; + +static int __devinit ad5446_probe(struct spi_device *spi) +{ + struct ad5446_state *st; + int ret, voltage_uv = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + st->reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + voltage_uv = regulator_get_voltage(st->reg); + } + + st->chip_info = + &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + spi_set_drvdata(spi, st); + + st->spi = spi; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + /* Estabilish that the iio_dev is a child of the spi device */ + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->attrs = &ad5446_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + /* Setup default message */ + + st->xfer.tx_buf = &st->data, + st->xfer.len = 2, + + spi_message_init(&st->msg); + spi_message_add_tail(&st->xfer, &st->msg); + + if (voltage_uv) + st->vref_mv = voltage_uv / 1000; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_free_device; + + return 0; + +error_free_device: + iio_free_device(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static int ad5446_remove(struct spi_device *spi) +{ + struct ad5446_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + return 0; +} + +static const struct spi_device_id ad5446_id[] = { + {"ad5444", ID_AD5444}, + {"ad5446", ID_AD5446}, + {"ad5542a", ID_AD5542A}, + {"ad5512a", ID_AD5512A}, + {} +}; + +static struct spi_driver ad5446_driver = { + .driver = { + .name = "ad5446", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad5446_probe, + .remove = __devexit_p(ad5446_remove), + .id_table = ad5446_id, +}; + +static int __init ad5446_init(void) +{ + return spi_register_driver(&ad5446_driver); +} +module_init(ad5446_init); + +static void __exit ad5446_exit(void) +{ + spi_unregister_driver(&ad5446_driver); +} +module_exit(ad5446_exit); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad5446"); diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h new file mode 100644 index 000000000000..24a9cda6b997 --- /dev/null +++ b/drivers/staging/iio/dac/ad5446.h @@ -0,0 +1,46 @@ +/* + * AD5446 SPI DAC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_ADC_AD5446_H_ +#define IIO_ADC_AD5446_H_ + +/* DAC Control Bits */ + +#define AD5446_LOAD (0x0 << 14) /* Load and update */ +#define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */ +#define AD5446_NOP (0x2 << 14) /* No operation */ +#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */ + +#define RES_MASK(bits) ((1 << (bits)) - 1) + +struct ad5446_chip_info { + u8 bits; /* number of DAC bits */ + u8 storagebits; /* number of bits written to the DAC */ + u8 left_shift; /* number of bits the datum must be shifted */ + char sign; /* [s]igned or [u]nsigned */ +}; + +struct ad5446_state { + struct iio_dev *indio_dev; + struct spi_device *spi; + const struct ad5446_chip_info *chip_info; + struct regulator *reg; + struct work_struct poll_work; + unsigned short vref_mv; + struct spi_transfer xfer; + struct spi_message msg; + unsigned short data; +}; + +enum ad5446_supported_device_ids { + ID_AD5444, + ID_AD5446, + ID_AD5542A, + ID_AD5512A, +}; + +#endif /* IIO_ADC_AD5446_H_ */ -- cgit v1.2.3 From 2b4756aa36909a94596752db341a0a2c8bb8c6ea Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 22 Nov 2010 14:35:32 +0100 Subject: staging: iio: adc: Enable driver support for ad7887 AD converter Enable support for AD7887: SPI Micropower, 2-Channel, 125 kSPS, 12-Bit ADC staging: iio: adc: Fix according to review feedback Review feedback by Jonathan Cameron: Combine statements. Document struct members. Remove redundant variable initialization. Simplify multichannel scan from ring logic. Fix coding style. [v2] staging: iio: adc: ad7887: Fix typos Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/adc/Kconfig | 14 ++ drivers/staging/iio/adc/Makefile | 4 + drivers/staging/iio/adc/ad7887.h | 105 ++++++++++++ drivers/staging/iio/adc/ad7887_core.c | 305 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/ad7887_ring.c | 266 +++++++++++++++++++++++++++++ 5 files changed, 694 insertions(+) create mode 100644 drivers/staging/iio/adc/ad7887.h create mode 100644 drivers/staging/iio/adc/ad7887_core.c create mode 100644 drivers/staging/iio/adc/ad7887_ring.c (limited to 'drivers') diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 9ca6565d2bae..86869cd233ae 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -97,6 +97,20 @@ config AD7476 To compile this driver as a module, choose M here: the module will be called ad7476. +config AD7887 + tristate "Analog Devices AD7887 ADC driver" + depends on SPI + select IIO_RING_BUFFER + select IIO_SW_RING + select IIO_TRIGGER + help + Say yes here to build support for Analog Devices + AD7887 SPI analog to digital convertor (ADC). + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called ad7887. + config AD7745 tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver" depends on I2C diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index a7dce6bd5f3a..6f231a2cb777 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -15,6 +15,10 @@ ad7476-y := ad7476_core.o ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o obj-$(CONFIG_AD7476) += ad7476.o +ad7887-y := ad7887_core.o +ad7887-$(CONFIG_IIO_RING_BUFFER) += ad7887_ring.o +obj-$(CONFIG_AD7887) += ad7887.o + obj-$(CONFIG_AD7150) += ad7150.o obj-$(CONFIG_AD7152) += ad7152.o obj-$(CONFIG_AD7291) += ad7291.o diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h new file mode 100644 index 000000000000..8c2a218c9496 --- /dev/null +++ b/drivers/staging/iio/adc/ad7887.h @@ -0,0 +1,105 @@ +/* + * AD7887 SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_ADC_AD7887_H_ +#define IIO_ADC_AD7887_H_ + +#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */ +#define AD7887_DUAL (1 << 4) /* dual-channel mode */ +#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */ +#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */ +#define AD7887_PM_MODE1 (0) /* CS based shutdown */ +#define AD7887_PM_MODE2 (1) /* full on */ +#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */ +#define AD7887_PM_MODE4 (3) /* standby mode */ + +enum ad7887_channels { + AD7887_CH0, + AD7887_CH0_CH1, + AD7887_CH1, +}; + +#define RES_MASK(bits) ((1 << (bits)) - 1) /* TODO: move this into a common header */ + +/* + * TODO: struct ad7887_platform_data needs to go into include/linux/iio + */ + +struct ad7887_platform_data { + /* External Vref voltage applied */ + u16 vref_mv; + /* + * AD7887: + * In single channel mode en_dual = flase, AIN1/Vref pins assumes its + * Vref function. In dual channel mode en_dual = true, AIN1 becomes the + * second input channel, and Vref is internally connected to Vdd. + */ + bool en_dual; + /* + * AD7887: + * use_onchip_ref = true, the Vref is internally connected to the 2.500V + * Voltage reference. If use_onchip_ref = false, the reference voltage + * is supplied by AIN1/Vref + */ + bool use_onchip_ref; +}; + +struct ad7887_chip_info { + u8 bits; /* number of ADC bits */ + u8 storagebits; /* number of bits read from the ADC */ + u8 left_shift; /* number of bits the sample must be shifted */ + char sign; /* [s]igned or [u]nsigned */ + u16 int_vref_mv; /* internal reference voltage */ +}; + +struct ad7887_state { + struct iio_dev *indio_dev; + struct spi_device *spi; + const struct ad7887_chip_info *chip_info; + struct regulator *reg; + struct work_struct poll_work; + atomic_t protect_ring; + u16 int_vref_mv; + bool en_dual; + struct spi_transfer xfer[4]; + struct spi_message msg[3]; + struct spi_message *ring_msg; + unsigned char tx_cmd_buf[8]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + + unsigned char data[4] ____cacheline_aligned; +}; + +enum ad7887_supported_device_ids { + ID_AD7887 +}; + +#ifdef CONFIG_IIO_RING_BUFFER +int ad7887_scan_from_ring(struct ad7887_state *st, long mask); +int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev); +void ad7887_ring_cleanup(struct iio_dev *indio_dev); +#else /* CONFIG_IIO_RING_BUFFER */ +static inline int ad7887_scan_from_ring(struct ad7887_state *st, long mask) +{ + return 0; +} + +static inline int +ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void ad7887_ring_cleanup(struct iio_dev *indio_dev) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* IIO_ADC_AD7887_H_ */ diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c new file mode 100644 index 000000000000..685908995d49 --- /dev/null +++ b/drivers/staging/iio/adc/ad7887_core.c @@ -0,0 +1,305 @@ +/* + * AD7887 SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_generic.h" +#include "adc.h" + +#include "ad7887.h" + +static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch) +{ + int ret = spi_sync(st->spi, &st->msg[ch]); + if (ret) + return ret; + + return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1]; +} + +static ssize_t ad7887_scan(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7887_state *st = dev_info->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + + mutex_lock(&dev_info->mlock); + if (iio_ring_enabled(dev_info)) + ret = ad7887_scan_from_ring(st, 1 << this_attr->address); + else + ret = ad7887_scan_direct(st, this_attr->address); + mutex_unlock(&dev_info->mlock); + + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", (ret >> st->chip_info->left_shift) & + RES_MASK(st->chip_info->bits)); +} +static IIO_DEV_ATTR_IN_RAW(0, ad7887_scan, 0); +static IIO_DEV_ATTR_IN_RAW(1, ad7887_scan, 1); + +static ssize_t ad7887_show_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* Driver currently only support internal vref */ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7887_state *st = iio_dev_get_devdata(dev_info); + /* Corresponds to Vref / 2^(bits) */ + unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; + + return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); +} +static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7887_show_scale, NULL, 0); + +static ssize_t ad7887_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7887_state *st = iio_dev_get_devdata(dev_info); + + return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); +} +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7887_show_name, NULL, 0); + +static struct attribute *ad7887_attributes[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static mode_t ad7887_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7887_state *st = iio_dev_get_devdata(dev_info); + + mode_t mode = attr->mode; + + if ((attr == &iio_dev_attr_in1_raw.dev_attr.attr) && !st->en_dual) + mode = 0; + + return mode; +} + +static const struct attribute_group ad7887_attribute_group = { + .attrs = ad7887_attributes, + .is_visible = ad7887_attr_is_visible, +}; + +static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { + /* + * More devices added in future + */ + [ID_AD7887] = { + .bits = 12, + .storagebits = 16, + .left_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 2500, + }, +}; + +static int __devinit ad7887_probe(struct spi_device *spi) +{ + struct ad7887_platform_data *pdata = spi->dev.platform_data; + struct ad7887_state *st; + int ret, voltage_uv = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + st->reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + voltage_uv = regulator_get_voltage(st->reg); + } + + st->chip_info = + &ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + spi_set_drvdata(spi, st); + + atomic_set(&st->protect_ring, 0); + st->spi = spi; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + /* Estabilish that the iio_dev is a child of the spi device */ + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->attrs = &ad7887_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + /* Setup default message */ + + st->tx_cmd_buf[0] = AD7887_CH_AIN0 | AD7887_PM_MODE4 | + ((pdata && pdata->use_onchip_ref) ? + 0 : AD7887_REF_DIS); + + st->xfer[0].rx_buf = &st->data[0]; + st->xfer[0].tx_buf = &st->tx_cmd_buf[0]; + st->xfer[0].len = 2; + + spi_message_init(&st->msg[AD7887_CH0]); + spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]); + + if (pdata && pdata->en_dual) { + st->tx_cmd_buf[0] |= AD7887_DUAL | AD7887_REF_DIS; + + st->tx_cmd_buf[2] = AD7887_CH_AIN1 | AD7887_DUAL | + AD7887_REF_DIS | AD7887_PM_MODE4; + st->tx_cmd_buf[4] = AD7887_CH_AIN0 | AD7887_DUAL | + AD7887_REF_DIS | AD7887_PM_MODE4; + st->tx_cmd_buf[6] = AD7887_CH_AIN1 | AD7887_DUAL | + AD7887_REF_DIS | AD7887_PM_MODE4; + + st->xfer[1].rx_buf = &st->data[0]; + st->xfer[1].tx_buf = &st->tx_cmd_buf[2]; + st->xfer[1].len = 2; + + st->xfer[2].rx_buf = &st->data[2]; + st->xfer[2].tx_buf = &st->tx_cmd_buf[4]; + st->xfer[2].len = 2; + + spi_message_init(&st->msg[AD7887_CH0_CH1]); + spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]); + spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]); + + st->xfer[3].rx_buf = &st->data[0]; + st->xfer[3].tx_buf = &st->tx_cmd_buf[6]; + st->xfer[3].len = 2; + + spi_message_init(&st->msg[AD7887_CH1]); + spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]); + + st->en_dual = true; + + if (pdata && pdata->vref_mv) + st->int_vref_mv = pdata->vref_mv; + else if (voltage_uv) + st->int_vref_mv = voltage_uv / 1000; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + + } else { + if (pdata && pdata->vref_mv) + st->int_vref_mv = pdata->vref_mv; + else if (pdata && pdata->use_onchip_ref) + st->int_vref_mv = st->chip_info->int_vref_mv; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + } + + + ret = ad7887_register_ring_funcs_and_init(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); + if (ret) + goto error_cleanup_ring; + return 0; + +error_cleanup_ring: + ad7887_ring_cleanup(st->indio_dev); + iio_device_unregister(st->indio_dev); +error_free_device: + iio_free_device(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static int ad7887_remove(struct spi_device *spi) +{ + struct ad7887_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + iio_ring_buffer_unregister(indio_dev->ring); + ad7887_ring_cleanup(indio_dev); + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + return 0; +} + +static const struct spi_device_id ad7887_id[] = { + {"ad7887", ID_AD7887}, + {} +}; + +static struct spi_driver ad7887_driver = { + .driver = { + .name = "ad7887", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad7887_probe, + .remove = __devexit_p(ad7887_remove), + .id_table = ad7887_id, +}; + +static int __init ad7887_init(void) +{ + return spi_register_driver(&ad7887_driver); +} +module_init(ad7887_init); + +static void __exit ad7887_exit(void) +{ + spi_unregister_driver(&ad7887_driver); +} +module_exit(ad7887_exit); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7887 ADC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad7887"); diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c new file mode 100644 index 000000000000..6b9cb1f95a1e --- /dev/null +++ b/drivers/staging/iio/adc/ad7887_ring.c @@ -0,0 +1,266 @@ +/* + * Copyright 2010 Analog Devices Inc. + * Copyright (C) 2008 Jonathan Cameron + * + * Licensed under the GPL-2 or later. + * + * ad7887_ring.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../ring_generic.h" +#include "../ring_sw.h" +#include "../trigger.h" +#include "../sysfs.h" + +#include "ad7887.h" + +static IIO_SCAN_EL_C(in0, 0, 0, NULL); +static IIO_SCAN_EL_C(in1, 1, 0, NULL); + +static ssize_t ad7887_show_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct ad7887_state *st = indio_dev->dev_data; + + return sprintf(buf, "%c%d/%d>>%d\n", st->chip_info->sign, + st->chip_info->bits, st->chip_info->storagebits, + st->chip_info->left_shift); +} +static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7887_show_type, NULL, 0); + +static struct attribute *ad7887_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static mode_t ad7887_scan_el_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct ad7887_state *st = indio_dev->dev_data; + + mode_t mode = attr->mode; + + if ((attr == &iio_scan_el_in1.dev_attr.attr) || + (attr == &iio_const_attr_in1_index.dev_attr.attr)) + if (!st->en_dual) + mode = 0; + + return mode; +} + +static struct attribute_group ad7887_scan_el_group = { + .name = "scan_elements", + .attrs = ad7887_scan_el_attrs, + .is_visible = ad7887_scan_el_attr_is_visible, +}; + +int ad7887_scan_from_ring(struct ad7887_state *st, long mask) +{ + struct iio_ring_buffer *ring = st->indio_dev->ring; + int count = 0, ret; + u16 *ring_data; + + if (!(ring->scan_mask & mask)) { + ret = -EBUSY; + goto error_ret; + } + + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); + if (ring_data == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = ring->access.read_last(ring, (u8 *) ring_data); + if (ret) + goto error_free_ring_data; + + /* for single channel scan the result is stored with zero offset */ + if ((ring->scan_mask == ((1 << 1) | (1 << 0))) && (mask == (1 << 1))) + count = 1; + + ret = be16_to_cpu(ring_data[count]); + +error_free_ring_data: + kfree(ring_data); +error_ret: + return ret; +} + +/** + * ad7887_ring_preenable() setup the parameters of the ring before enabling + * + * The complex nature of the setting of the nuber of bytes per datum is due + * to this driver currently ensuring that the timestamp is stored at an 8 + * byte boundary. + **/ +static int ad7887_ring_preenable(struct iio_dev *indio_dev) +{ + struct ad7887_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring = indio_dev->ring; + size_t d_size; + + if (indio_dev->ring->access.set_bytes_per_datum) { + d_size = st->chip_info->storagebits / 8 + sizeof(s64); + if (d_size % 8) + d_size += 8 - (d_size % 8); + indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring, + d_size); + } + + switch (ring->scan_mask) { + case (1 << 0): + st->ring_msg = &st->msg[AD7887_CH0]; + break; + case (1 << 1): + st->ring_msg = &st->msg[AD7887_CH1]; + /* Dummy read: push CH1 setting down to hardware */ + spi_sync(st->spi, st->ring_msg); + break; + case ((1 << 1) | (1 << 0)): + st->ring_msg = &st->msg[AD7887_CH0_CH1]; + break; + } + + return 0; +} + +static int ad7887_ring_postdisable(struct iio_dev *indio_dev) +{ + struct ad7887_state *st = indio_dev->dev_data; + + /* dummy read: restore default CH0 settin */ + return spi_sync(st->spi, &st->msg[AD7887_CH0]); +} + +/** + * ad7887_poll_func_th() th of trigger launched polling to ring buffer + * + * As sampling only occurs on spi comms occuring, leave timestamping until + * then. Some triggers will generate their own time stamp. Currently + * there is no way of notifying them when no one cares. + **/ +static void ad7887_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct ad7887_state *st = indio_dev->dev_data; + + schedule_work(&st->poll_work); + return; +} +/** + * ad7887_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * @work_s: the work struct through which this was scheduled + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad7887_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad7887_state *st = container_of(work_s, struct ad7887_state, + poll_work); + struct iio_dev *indio_dev = st->indio_dev; + struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring); + struct iio_ring_buffer *ring = indio_dev->ring; + s64 time_ns; + __u8 *buf; + int b_sent; + size_t d_size; + + unsigned int bytes = ring->scan_count * st->chip_info->storagebits / 8; + + /* Ensure the timestamp is 8 byte aligned */ + d_size = bytes + sizeof(s64); + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - (d_size % sizeof(s64)); + + /* Ensure only one copy of this function running at a time */ + if (atomic_inc_return(&st->protect_ring) > 1) + return; + + buf = kzalloc(d_size, GFP_KERNEL); + if (buf == NULL) + return; + + b_sent = spi_sync(st->spi, st->ring_msg); + if (b_sent) + goto done; + + time_ns = iio_get_time_ns(); + + memcpy(buf, st->data, bytes); + memcpy(buf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + + indio_dev->ring->access.store_to(&sw_ring->buf, buf, time_ns); +done: + kfree(buf); + atomic_dec(&st->protect_ring); +} + +int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + struct ad7887_state *st = indio_dev->dev_data; + int ret; + + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + if (!indio_dev->ring) { + ret = -ENOMEM; + goto error_ret; + } + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&indio_dev->ring->access); + ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7887_poll_func_th); + if (ret) + goto error_deallocate_sw_rb; + + /* Ring buffer functions - here trigger setup related */ + + indio_dev->ring->preenable = &ad7887_ring_preenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; + indio_dev->ring->postdisable = &ad7887_ring_postdisable; + indio_dev->ring->scan_el_attrs = &ad7887_scan_el_group; + + INIT_WORK(&st->poll_work, &ad7887_poll_bh_to_ring); + + /* Flag that polled ring buffering is possible */ + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb: + iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + +void ad7887_ring_cleanup(struct iio_dev *indio_dev) +{ + /* ensure that the trigger has been detached */ + if (indio_dev->trig) { + iio_put_trigger(indio_dev->trig); + iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc); + } + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} -- cgit v1.2.3 From a9672951a5c4e57e048895d868a2172962ef7ffd Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 22 Nov 2010 23:09:47 +0000 Subject: staging: iio: adis16260 add id table support Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/adis16260_core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 8190c0fe0bea..6f549030e3bb 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -635,6 +635,12 @@ err_ret: return ret; } +static const struct spi_device_id adis16260_id[] = { + {"adis16260", 0}, + {"adis16265", 0}, + {} +}; + static struct spi_driver adis16260_driver = { .driver = { .name = "adis16260", @@ -642,6 +648,7 @@ static struct spi_driver adis16260_driver = { }, .probe = adis16260_probe, .remove = __devexit_p(adis16260_remove), + .id_table = adis16260_id, }; static __init int adis16260_init(void) -- cgit v1.2.3 From fe34604844c151668579cb6ad52f75a5c651bed9 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 22 Nov 2010 23:09:48 +0000 Subject: staging: iio: adis16260 add suppport for adis16255 and adis16250. Unusual element is addition of 'negate' and 'axis' platform data to ensure we support all the functionality of the adis16255 driver currently in staging. Signed-off-by: Jonathan Cameron Acked-by: Matthias Brugger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/gyro/adis16260.h | 3 + drivers/staging/iio/gyro/adis16260_core.c | 133 +++++++++++++++------ drivers/staging/iio/gyro/adis16260_platform_data.h | 19 +++ drivers/staging/iio/gyro/gyro.h | 9 ++ 4 files changed, 125 insertions(+), 39 deletions(-) create mode 100644 drivers/staging/iio/gyro/adis16260_platform_data.h (limited to 'drivers') diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h index 812440af57d6..c1fd4364287f 100644 --- a/drivers/staging/iio/gyro/adis16260.h +++ b/drivers/staging/iio/gyro/adis16260.h @@ -1,5 +1,6 @@ #ifndef SPI_ADIS16260_H_ #define SPI_ADIS16260_H_ +#include "adis16260_platform_data.h" #define ADIS16260_STARTUP_DELAY 220 /* ms */ @@ -92,6 +93,7 @@ * @tx: transmit buffer * @rx: recieve buffer * @buf_lock: mutex to protect tx and rx + * @negate: negate the scale parameter **/ struct adis16260_state { struct spi_device *us; @@ -102,6 +104,7 @@ struct adis16260_state { u8 *tx; u8 *rx; struct mutex buf_lock; + unsigned negate:1; }; int adis16260_set_irq(struct device *dev, bool enable); diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index 6f549030e3bb..045e27da980a 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -134,8 +134,6 @@ static int adis16260_spi_read_reg_16(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = ADIS16260_READ_REG(lower_reg_address); st->tx[1] = 0; - st->tx[2] = 0; - st->tx[3] = 0; spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); @@ -293,6 +291,22 @@ static ssize_t adis16260_write_frequency(struct device *dev, return ret ? ret : len; } +static ssize_t adis16260_read_gyro_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adis16260_state *st = iio_dev_get_devdata(indio_dev); + ssize_t ret = 0; + + if (st->negate) + ret = sprintf(buf, "-"); + /* Take the iio_dev status lock */ + ret += sprintf(buf + ret, "%s\n", "0.00127862821"); + + return ret; +} + static int adis16260_reset(struct device *dev) { int ret; @@ -447,18 +461,6 @@ static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, ADIS16260_SUPPLY_OUT); static IIO_CONST_ATTR_IN_NAMED_SCALE(0, supply, "0.0018315"); -static IIO_DEV_ATTR_GYRO(adis16260_read_14bit_signed, - ADIS16260_GYRO_OUT); -static IIO_CONST_ATTR_GYRO_SCALE("0.00127862821"); -static IIO_DEV_ATTR_GYRO_CALIBSCALE(S_IWUSR | S_IRUGO, - adis16260_read_14bit_signed, - adis16260_write_16bit, - ADIS16260_GYRO_SCALE); -static IIO_DEV_ATTR_GYRO_CALIBBIAS(S_IWUSR | S_IRUGO, - adis16260_read_12bit_signed, - adis16260_write_16bit, - ADIS16260_GYRO_OFF); - static IIO_DEV_ATTR_TEMP_RAW(adis16260_read_12bit_unsigned); static IIO_CONST_ATTR_TEMP_OFFSET("25"); static IIO_CONST_ATTR_TEMP_SCALE("0.1453"); @@ -470,8 +472,6 @@ static IIO_CONST_ATTR(in1_scale, "0.0006105"); static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16260_read_frequency, adis16260_write_frequency); -static IIO_DEV_ATTR_ANGL(adis16260_read_14bit_signed, - ADIS16260_ANGL_OUT); static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16260_write_reset, 0); @@ -487,38 +487,70 @@ static struct attribute_group adis16260_event_attribute_group = { .attrs = adis16260_event_attributes, }; -static struct attribute *adis16260_attributes[] = { - &iio_dev_attr_in0_supply_raw.dev_attr.attr, - &iio_const_attr_in0_supply_scale.dev_attr.attr, - &iio_dev_attr_gyro_raw.dev_attr.attr, - &iio_const_attr_gyro_scale.dev_attr.attr, - &iio_dev_attr_gyro_calibscale.dev_attr.attr, - &iio_dev_attr_gyro_calibbias.dev_attr.attr, - &iio_dev_attr_angl_raw.dev_attr.attr, - &iio_dev_attr_temp_raw.dev_attr.attr, - &iio_const_attr_temp_offset.dev_attr.attr, - &iio_const_attr_temp_scale.dev_attr.attr, - &iio_dev_attr_in1_raw.dev_attr.attr, - &iio_const_attr_in1_scale.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_reset.dev_attr.attr, - &iio_const_attr_name.dev_attr.attr, - NULL -}; +#define ADIS16260_GYRO_ATTR_SET(axis) \ + IIO_DEV_ATTR_GYRO##axis(adis16260_read_14bit_signed, \ + ADIS16260_GYRO_OUT); \ + static IIO_DEV_ATTR_GYRO##axis##_SCALE(S_IRUGO, \ + adis16260_read_gyro_scale, \ + NULL, \ + 0); \ + static IIO_DEV_ATTR_GYRO##axis##_CALIBSCALE(S_IRUGO | S_IWUSR, \ + adis16260_read_12bit_unsigned, \ + adis16260_write_16bit, \ + ADIS16260_GYRO_SCALE); \ + static IIO_DEV_ATTR_GYRO##axis##_CALIBBIAS(S_IWUSR | S_IRUGO, \ + adis16260_read_12bit_signed, \ + adis16260_write_16bit, \ + ADIS16260_GYRO_OFF); \ + static IIO_DEV_ATTR_ANGL##axis(adis16260_read_14bit_signed, \ + ADIS16260_ANGL_OUT); + +static ADIS16260_GYRO_ATTR_SET(); +static ADIS16260_GYRO_ATTR_SET(_X); +static ADIS16260_GYRO_ATTR_SET(_Y); +static ADIS16260_GYRO_ATTR_SET(_Z); + +#define ADIS16260_ATTR_GROUP(axis) \ + struct attribute *adis16260_attributes##axis[] = { \ + &iio_dev_attr_in0_supply_raw.dev_attr.attr, \ + &iio_const_attr_in0_supply_scale.dev_attr.attr, \ + &iio_dev_attr_gyro##axis##_raw.dev_attr.attr, \ + &iio_dev_attr_gyro##axis##_scale.dev_attr.attr, \ + &iio_dev_attr_gyro##axis##_calibscale.dev_attr.attr, \ + &iio_dev_attr_gyro##axis##_calibbias.dev_attr.attr, \ + &iio_dev_attr_angl##axis##_raw.dev_attr.attr, \ + &iio_dev_attr_temp_raw.dev_attr.attr, \ + &iio_const_attr_temp_offset.dev_attr.attr, \ + &iio_const_attr_temp_scale.dev_attr.attr, \ + &iio_dev_attr_in1_raw.dev_attr.attr, \ + &iio_const_attr_in1_scale.dev_attr.attr, \ + &iio_dev_attr_sampling_frequency.dev_attr.attr, \ + &iio_const_attr_sampling_frequency_available.dev_attr.attr, \ + &iio_dev_attr_reset.dev_attr.attr, \ + &iio_const_attr_name.dev_attr.attr, \ + NULL \ + }; \ + static const struct attribute_group adis16260_attribute_group##axis \ + = { \ + .attrs = adis16260_attributes##axis, \ + }; -static const struct attribute_group adis16260_attribute_group = { - .attrs = adis16260_attributes, -}; +static ADIS16260_ATTR_GROUP(); +static ADIS16260_ATTR_GROUP(_x); +static ADIS16260_ATTR_GROUP(_y); +static ADIS16260_ATTR_GROUP(_z); static int __devinit adis16260_probe(struct spi_device *spi) { int ret, regdone = 0; + struct adis16260_platform_data *pd = spi->dev.platform_data; struct adis16260_state *st = kzalloc(sizeof *st, GFP_KERNEL); if (!st) { ret = -ENOMEM; goto error_ret; } + if (pd) + st->negate = pd->negate; /* this is only used for removal purposes */ spi_set_drvdata(spi, st); @@ -545,7 +577,24 @@ static int __devinit adis16260_probe(struct spi_device *spi) st->indio_dev->dev.parent = &spi->dev; st->indio_dev->num_interrupt_lines = 1; st->indio_dev->event_attrs = &adis16260_event_attribute_group; - st->indio_dev->attrs = &adis16260_attribute_group; + if (pd && pd->direction) + switch (pd->direction) { + case 'x': + st->indio_dev->attrs = &adis16260_attribute_group_x; + break; + case 'y': + st->indio_dev->attrs = &adis16260_attribute_group_y; + break; + case 'z': + st->indio_dev->attrs = &adis16260_attribute_group_z; + break; + default: + st->indio_dev->attrs = &adis16260_attribute_group; + break; + } + else + st->indio_dev->attrs = &adis16260_attribute_group; + st->indio_dev->dev_data = (void *)(st); st->indio_dev->driver_module = THIS_MODULE; st->indio_dev->modes = INDIO_DIRECT_MODE; @@ -635,9 +684,15 @@ err_ret: return ret; } +/* + * These parts do not need to be differentiated until someone adds + * support for the on chip filtering. + */ static const struct spi_device_id adis16260_id[] = { {"adis16260", 0}, {"adis16265", 0}, + {"adis16250", 0}, + {"adis16255", 0}, {} }; diff --git a/drivers/staging/iio/gyro/adis16260_platform_data.h b/drivers/staging/iio/gyro/adis16260_platform_data.h new file mode 100644 index 000000000000..12802e97be92 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16260_platform_data.h @@ -0,0 +1,19 @@ +/* + * ADIS16260 Programmable Digital Gyroscope Sensor Driver Platform Data + * + * Based on adis16255.h Matthia Brugger + * + * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits + * + * Licensed under the GPL-2 or later. + */ + +/** + * struct adis16260_platform_data - instance specific data + * @direction: x y or z + * @negate: flag to indicate value should be inverted. + **/ +struct adis16260_platform_data { + char direction; + unsigned negate:1; +}; diff --git a/drivers/staging/iio/gyro/gyro.h b/drivers/staging/iio/gyro/gyro.h index 98b837b775a2..b4ea5bf161ff 100644 --- a/drivers/staging/iio/gyro/gyro.h +++ b/drivers/staging/iio/gyro/gyro.h @@ -71,3 +71,12 @@ #define IIO_DEV_ATTR_ANGL(_show, _addr) \ IIO_DEVICE_ATTR(angl_raw, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ANGL_X(_show, _addr) \ + IIO_DEVICE_ATTR(angl_x_raw, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ANGL_Y(_show, _addr) \ + IIO_DEVICE_ATTR(angl_y_raw, S_IRUGO, _show, NULL, _addr) + +#define IIO_DEV_ATTR_ANGL_Z(_show, _addr) \ + IIO_DEVICE_ATTR(angl_z_raw, S_IRUGO, _show, NULL, _addr) -- cgit v1.2.3 From f386caa3cd74231cd86c813fe4453e3d6e39876c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 22 Nov 2010 23:31:16 +0000 Subject: staging: iio: documentation rewrite and cleanup of sysfs documetation Change to capital syntax for documetation e.g. 'inX-inY_raw' Use multiple 'What:' entries rather than wild cards or options so as to make the documentation clearer and easier to search. Some trivial spelling fixes. Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/Documentation/sysfs-bus-iio | 627 ++++++++++++++++-------- 1 file changed, 428 insertions(+), 199 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio index fdb017a1c1a2..2dde97de75f8 100644 --- a/drivers/staging/iio/Documentation/sysfs-bus-iio +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio @@ -1,11 +1,12 @@ -What: /sys/bus/iio/devices/device[n] +What: /sys/bus/iio/devices/deviceX KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: Hardware chip or device accessed by on communication port. - Corresponds to a grouping of sensor channels. + Corresponds to a grouping of sensor channels. X is the IIO + index of the device. -What: /sys/bus/iio/devices/trigger[n] +What: /sys/bus/iio/devices/triggerX KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -13,25 +14,26 @@ Description: May be provided by a device driver that also has an IIO device based on hardware generated events (e.g. data ready) or provided by a separate driver for other hardware (e.g. - periodic timer, gpio or high resolution timer). + periodic timer, GPIO or high resolution timer). Contains trigger type specific elements. These do not generalize well and hence are not documented in this file. + X is the IIO index of the trigger. -What: /sys/bus/iio/devices/device[n]:buffer +What: /sys/bus/iio/devices/deviceX:buffer KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Link to /sys/class/iio/device[n]/device[n]:buffer. n indicates + Link to /sys/class/iio/deviceX/deviceX:buffer. X indicates the device with which this buffer buffer is associated. -What: /sys/.../device[n]/name +What: /sys/bus/iio/devices/deviceX/name KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Description of the physical chip / device. Typically a part - number. + Description of the physical chip / device for device X. + Typically a part number. -What: /sys/.../device[n]/sampling_frequency +What: /sys/bus/iio/devices/deviceX/sampling_frequency KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -44,158 +46,233 @@ Description: relevant directories. If it effects all of the above then it is to be found in the base device directory as here. -What: /sys/.../device[n]/sampling_frequency_available +What: /sys/bus/iio/devices/deviceX/sampling_frequency_available KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: When the internal sampling clock can only take a small - discrete set of values, this file lists those availale. + discrete set of values, this file lists those available. -What: /sys/.../device[n]/in[m][_name]_raw +What: /sys/bus/iio/devices/deviceX/inY_raw +What: /sys/bus/iio/devices/deviceX/inY_supply_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: Raw (unscaled no bias removal etc) voltage measurement from - channel m. name is used in special cases where this does - not correspond to externally available input (e.g. supply - voltage monitoring in which case the file is in_supply_raw). - If the device supports events on this channel then m must be - specified (even on named channels) so as to allow the source - of event codes to be identified. - -What: /sys/.../device[n]/in[m][_name]_offset + channel Y. In special cases where the channel does not + correspond to externally available input one of the named + versions may be used. The number must always be specified and + unique to allow association with event codes. + +What: /sys/bus/iio/devices/deviceX/inY-inZ_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - If known for a device, offset to be added to in[m]_raw prior - to scaling by in[_name][m]_scale in order to obtain voltage in - millivolts. Not present if the offset is always 0 or unknown. - If m is not present, then voltage offset applies to all in - channels. May be writable if a variable offset is controlled - by the device. Note that this is different to calibbias which - is for devices that apply offsets to compensate for variation - between different instances of the part, typically adjusted by - using some hardware supported calibration procedure. + Raw (unscaled) differential voltage measurement equivalent to + channel Y - channel Z where these channel numbers apply to the + physically equivalent inputs when non differential readings are + separately available. In differential only parts, then all that + is required is a consistent labeling. -What: /sys/.../device[n]/in[m][_name]_offset_available +What: /sys/bus/iio/devices/deviceX/temp_raw +What: /sys/bus/iio/devices/deviceX/temp_x_raw +What: /sys/bus/iio/devices/deviceX/temp_y_raw +What: /sys/bus/iio/devices/deviceX/temp_z_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - If a small number of discrete offset values are available, this - will be a space separated list. If these are independant (but - options the same) for individual offsets then m should not be - present. + Raw (unscaled no bias removal etc) temperature measurement. + It an axis is specified it generally means that the temperature + sensor is associated with one part of a compound device (e.g. + a gyroscope axis). -What: /sys/.../device[n]/in[m][_name]_offset_[min|max] +What: /sys/bus/iio/devices/deviceX/accel_x_raw +What: /sys/bus/iio/devices/deviceX/accel_y_raw +What: /sys/bus/iio/devices/deviceX/accel_z_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - If a more or less continuous range of voltage offsets are - supported then these specify the minimum and maximum. If shared - by all in channels then m is not present. + Acceleration in direction x, y or z (may be arbitrarily assigned + but should match other such assignments on device) + channel m (not present if only one accelerometer channel at + this orientation). Has all of the equivalent parameters as per + inY. Units after application of scale and offset are m/s^2. -What: /sys/.../device[n]/in[m][_name]_calibbias +What: /sys/bus/iio/devices/deviceX/gyro_x_raw +What: /sys/bus/iio/devices/deviceX/gyro_y_raw +What: /sys/bus/iio/devices/deviceX/gyro_z_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Hardware applied calibration offset. (assumed to fix production - inaccuracies) + Angular velocity about axis x, y or z (may be arbitrarily + assigned) Data converted by application of offset then scale to + radians per second. Has all the equivalent parameters as + per inY. -What /sys/.../device[n]/in[m][_name]_calibscale +What: /sys/bus/iio/devices/deviceX/incli_x_raw +What: /sys/bus/iio/devices/deviceX/incli_y_raw +What: /sys/bus/iio/devices/deviceX/incli_z_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Hardware applied calibration scale factor. (assumed to fix - production inaccuracies) + Inclination raw reading about axis x, y or z (may be + arbitrarily assigned). Data converted by application of offset + and scale to Degrees. -What: /sys/.../device[n]/in[m][_name]_scale +What: /sys/bus/iio/devices/deviceX/magn_x_raw +What: /sys/bus/iio/devices/deviceX/magn_y_raw +What: /sys/bus/iio/devices/deviceX/magn_z_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - If known for a device, scale to be applied to volt[m]_raw post - addition of in[_name][m]_offset in order to obtain the measured - voltage in millivolts. If shared across all in channels then - m is not present. + Magnetic field along axis x, y or z (may be arbitrarily + assigned) channel m (not present if only one magnetometer + at this orientation). Data converted by application of + offset then scale to Gauss. Has all the equivalent modifiers + as per inY. -What: /sys/.../device[n]/in[m]-in[o]_raw -KernelVersion: 2.6.35 +What: /sys/bus/iio/devices/deviceX/accel_x_peak_raw +What: /sys/bus/iio/devices/deviceX/accel_y_peak_raw +What: /sys/bus/iio/devices/deviceX/accel_z_peak_raw +KernelVersion: 2.6.36 Contact: linux-iio@vger.kernel.org Description: - Raw (unscaled) differential voltage measurement equivalent to - channel m - channel o where these channel numbers apply to the - physically equivalent inputs when non differential readings are - separately available. In differential only parts, then all that - is required is a consistent labelling. + Some devices provide a store of the highest value seen since + some reset condition. These attributes allow access to this + and are otherwise the direct equivalent of the + Y[_name]_raw attributes. -What: /sys/.../device[n]/accel[_x|_y|_z][m]_raw -KernelVersion: 2.6.35 +What: /sys/bus/iio/devices/deviceX/accel_xyz_squared_peak_raw +KernelVersion: 2.6.36 Contact: linux-iio@vger.kernel.org Description: - Acceleration in direction x, y or z (may be arbitrarily assigned - but should match other such assignments on device) - channel m (not present if only one accelerometer channel at - this orientation). Has all of the equivalent parameters as per - in[m]. Units after application of scale and offset are m/s^2. + A computed peak value based on the sum squared magnitude of + the underlying value in the specified directions. -What: /sys/.../device[n]/gyro[_x|_y|_z][m]_raw +What: /sys/bus/iio/devices/deviceX/accel_offset +What: /sys/bus/iio/devices/deviceX/temp_offset KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Angular velocity about axis x, y or z (may be arbitrarily - assigned) channel m (not present if only one gyroscope at - this orientation). - Data converted by application of offset then scale to - radians per second. Has all the equivalent parameters as - per in[m]. - -What: /sys/.../device[n]/incli[_x|_y|_z][m]_raw + If known for a device, offset to be added to [Y]_raw prior + to scaling by [Y]_scale in order to obtain value in the + units as specified in [y]_raw documentation. + Not present if the offset is always 0 or unknown. If Y is not + present, then the offset applies to all in channels of . + May be writable if a variable offset can be applied on the + device. Note that this is different to calibbias which + is for devices (or drivers) that apply offsets to compensate + for variation between different instances of the part, typically + adjusted by using some hardware supported calibration procedure. + +What: /sys/bus/iio/devices/deviceX/inY_scale +What: /sys/bus/iio/devices/deviceX/inY_supply_scale +What: /sys/bus/iio/devices/deviceX/in_scale +What: /sys/bus/iio/devices/deviceX/accel_scale +What: /sys/bus/iio/devices/deviceX/accel_peak_scale +What: /sys/bus/iio/devices/deviceX/gyro_scale +What: /sys/bus/iio/devices/deviceX/magn_scale +What: /sys/bus/iio/devices/deviceX/magn_x_scale +What: /sys/bus/iio/devices/deviceX/magn_y_scale +What: /sys/bus/iio/devices/deviceX/magn_z_scale KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Inclination raw reading about axis x, y or z (may be arbitarily - assigned) channel m (not present if only one inclinometer at - this orientation). Data converted by application of offset - and scale to Degrees. - -What: /sys/.../device[n]/magn[_x|_y|_z][m]_raw + If known for a device, scale to be applied to Y[_name]_raw + post addition of [Y][_name]_offset in order to obtain the + measured value in units as specified in + [Y][_name]_raw documentation.. If shared across all in + channels then Y is not present and the value is called + [Y][_name]_scale. The peak modifier means this value + is applied to Y[_name]_peak_raw values. + +What: /sys/bus/iio/devices/deviceX/accel_x_calibbias +What: /sys/bus/iio/devices/deviceX/accel_y_calibbias +What: /sys/bus/iio/devices/deviceX/accel_z_calibbias +What: /sys/bus/iio/devices/deviceX/gyro_x_calibbias +What: /sys/bus/iio/devices/deviceX/gyro_y_calibbias +What: /sys/bus/iio/devices/deviceX/gyro_z_calibbias KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Magnetic field along axis x, y or z (may be arbitrarily - assigned) channel m (not present if only one magnetometer - at this orientation). Data converted by application of - offset then scale to Gauss. Has all the equivalent modifiers - as per in[m]. - -What: /sys/.../device[n]/device[n]:event[m] + Hardware applied calibration offset. (assumed to fix production + inaccuracies). If shared across all channels, _calibbias + is used. + +What /sys/bus/iio/devices/deviceX/inY_calibscale +What /sys/bus/iio/devices/deviceX/inY_supply_calibscale +What /sys/bus/iio/devices/deviceX/in_calibscale +What /sys/bus/iio/devices/deviceX/accel_x_calibscale +What /sys/bus/iio/devices/deviceX/accel_y_calibscale +What /sys/bus/iio/devices/deviceX/accel_z_calibscale +What /sys/bus/iio/devices/deviceX/gyro_x_calibscale +What /sys/bus/iio/devices/deviceX/gyro_y_calibscale +What /sys/bus/iio/devices/deviceX/gyro_z_calibscale KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Configuration of which hardware generated events are passed up to - userspace. Some of these are a bit complex to generalize so this - section is a work in progress. + Hardware applied calibration scale factor. (assumed to fix + production inaccuracies). If shared across all channels, + _calibscale is used. -What: /sys/.../device[n]:event[m]/dev -KernelVersion: 2.6.35 +What: /sys/bus/iio/devices/deviceX/accel_scale_available +KernelVersion: 2.635 Contact: linux-iio@vger.kernel.org Description: - major:minor character device numbers for the event line. + If a discrete set of scale values are available, they + are listed in this attribute. -Taking accel_x0 as an example +What: /sys/bus/iio/devices/deviceX/deviceX:eventY +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Configuration of which hardware generated events are passed up + to user-space. -What: /sys/.../device[n]:event[m]/accel_x0_thresh[_rising|_falling]_en +What: /sys/bus/iio/devices/deviceX:event/dev +What: /sys/bus/iio/devices/deviceX:eventY/dev +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + major:minor character device numbers for the event line Y of + device X. + +What: /sys/.../deviceX:eventY/accel_x_thresh_rising_en +What: /sys/.../deviceX:eventY/accel_x_thresh_falling_en +What: /sys/.../deviceX:eventY/accel_y_thresh_rising_en +What: /sys/.../deviceX:eventY/accel_y_thresh_falling_en +What: /sys/.../deviceX:eventY/accel_z_thresh_rising_en +What: /sys/.../deviceX:eventY/accel_z_thresh_falling_en +What: /sys/.../deviceX:eventY/gyro_x_thresh_rising_en +What: /sys/.../deviceX:eventY/gyro_x_thresh_falling_en +What: /sys/.../deviceX:eventY/gyro_y_thresh_rising_en +What: /sys/.../deviceX:eventY/gyro_y_thresh_falling_en +What: /sys/.../deviceX:eventY/gyro_z_thresh_rising_en +What: /sys/.../deviceX:eventY/gyro_z_thresh_falling_en +What: /sys/.../deviceX:eventY/magn_x_thresh_rising_en +What: /sys/.../deviceX:eventY/magn_x_thresh_falling_en +What: /sys/.../deviceX:eventY/magn_y_thresh_rising_en +What: /sys/.../deviceX:eventY/magn_y_thresh_falling_en +What: /sys/.../deviceX:eventY/magn_z_thresh_rising_en +What: /sys/.../deviceX:eventY/magn_z_thresh_falling_en +What: /sys/.../deviceX:eventY/inZ_supply_thresh_rising_en +What: /sys/.../deviceX:eventY/inZ_supply_thresh_falling_en +What: /sys/.../deviceX:eventY/inZ_thresh_rising_en +What: /sys/.../deviceX:eventY/inZ_thresh_falling_en +What: /sys/.../deviceX:eventY/temp_thresh_rising_en +What: /sys/.../deviceX:eventY/temp_thresh_falling_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Event generated when accel_x0 passes a threshold in the specfied + Event generated when channel passes a threshold in the specified (_rising|_falling) direction. If the direction is not specified, then either the device will report an event which ever direction a single threshold value is called in (e.g. - accel_x0__thresh_value) or - accel_x0__thresh_rising_value and - accel_x0__thresh_falling_value may take different - values, but the device can only enable both thresholds or - neither. + [Z][_name]__thresh_value) or + [Z][_name]__thresh_rising_value and + [Z][_name]__thresh_falling_value may take + different values, but the device can only enable both thresholds + or neither. Note the driver will assume the last p events requested are to be enabled where p is however many it supports (which may vary depending on the exact set requested. So if you want to be @@ -205,186 +282,338 @@ Description: a given event type is enabled a future point (and not those for whatever event was previously enabled). -What: /sys/.../accel_x0__thresh[_rising|_falling]_value +What: /sys/.../deviceX:eventY/accel_x_roc_rising_en +What: /sys/.../deviceX:eventY/accel_x_roc_falling_en +What: /sys/.../deviceX:eventY/accel_y_roc_rising_en +What: /sys/.../deviceX:eventY/accel_y_roc_falling_en +What: /sys/.../deviceX:eventY/accel_z_roc_rising_en +What: /sys/.../deviceX:eventY/accel_z_roc_falling_en +What: /sys/.../deviceX:eventY/gyro_x_roc_rising_en +What: /sys/.../deviceX:eventY/gyro_x_roc_falling_en +What: /sys/.../deviceX:eventY/gyro_y_roc_rising_en +What: /sys/.../deviceX:eventY/gyro_y_roc_falling_en +What: /sys/.../deviceX:eventY/gyro_z_roc_rising_en +What: /sys/.../deviceX:eventY/gyro_z_roc_falling_en +What: /sys/.../deviceX:eventY/magn_x_roc_rising_en +What: /sys/.../deviceX:eventY/magn_x_roc_falling_en +What: /sys/.../deviceX:eventY/magn_y_roc_rising_en +What: /sys/.../deviceX:eventY/magn_y_roc_falling_en +What: /sys/.../deviceX:eventY/magn_z_roc_rising_en +What: /sys/.../deviceX:eventY/magn_z_roc_falling_en +What: /sys/.../deviceX:eventY/inZ_supply_roc_rising_en +What: /sys/.../deviceX:eventY/inZ_supply_roc_falling_en +What: /sys/.../deviceX:eventY/inZ_roc_rising_en +What: /sys/.../deviceX:eventY/inZ_roc_falling_en +What: /sys/.../deviceX:eventY/temp_roc_rising_en +What: /sys/.../deviceX:eventY/temp_roc_falling_en +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Event generated when channel passes a threshold on the rate of + change (1st differential) in the specified (_rising|_falling) + direction. If the direction is not specified, then either the + device will report an event which ever direction a single + threshold value is called in (e.g. + [Z][_name]__roc_value) or + [Z][_name]__roc_rising_value and + [Z][_name]__roc_falling_value may take + different values, but the device can only enable both rate of + change thresholds or neither. + Note the driver will assume the last p events requested are + to be enabled where p is however many it supports (which may + vary depending on the exact set requested. So if you want to be + sure you have set what you think you have, check the contents of + these attributes after everything is configured. Drivers may + have to buffer any parameters so that they are consistent when + a given event type is enabled a future point (and not those for + whatever event was previously enabled). + +What: /sys/.../deviceX:eventY/accel_x_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/accel_x_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/accel_y_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/accel_y_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/accel_z_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/accel_z_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/gyro_x_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/gyro_x_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/gyro_y_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/gyro_y_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/gyro_z_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/gyro_z_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/magn_x_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/magn_x_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/magn_y_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/magn_y_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/magn_z_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/magn_z_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/inZ_supply_raw_thresh_rising_value +What: /sys/.../deviceX:eventY/inZ_supply_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/inZ_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/inZ_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/temp_raw_thresh_falling_value +What: /sys/.../deviceX:eventY/temp_raw_thresh_falling_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Specifies the value of threshold that the device is comparing against for the events enabled by - accel_x0__thresh[_rising|falling]_en. - If seperate exist for the two directions, but direction is - not specified for this attribute, then a single threshold value - applies to both directions. + Z[_name]_thresh[_rising|falling]_en. + If separate attributes exist for the two directions, but + direction is not specified for this attribute, then a single + threshold value applies to both directions. The raw or input element of the name indicates whether the value is in raw device units or in processed units (as _raw and _input do on sysfs direct channel read attributes). -What: /sys/.../accel_x0_thresh[_rising|_falling]_meanperiod +What: /sys/.../deviceX:eventY/accel_x_raw_roc_rising_value +What: /sys/.../deviceX:eventY/accel_x_raw_roc_falling_value +What: /sys/.../deviceX:eventY/accel_y_raw_roc_rising_value +What: /sys/.../deviceX:eventY/accel_y_raw_roc_falling_value +What: /sys/.../deviceX:eventY/accel_z_raw_roc_rising_value +What: /sys/.../deviceX:eventY/accel_z_raw_roc_falling_value +What: /sys/.../deviceX:eventY/gyro_x_raw_roc_rising_value +What: /sys/.../deviceX:eventY/gyro_x_raw_roc_falling_value +What: /sys/.../deviceX:eventY/gyro_y_raw_roc_rising_value +What: /sys/.../deviceX:eventY/gyro_y_raw_roc_falling_value +What: /sys/.../deviceX:eventY/gyro_z_raw_roc_rising_value +What: /sys/.../deviceX:eventY/gyro_z_raw_roc_falling_value +What: /sys/.../deviceX:eventY/magn_x_raw_roc_rising_value +What: /sys/.../deviceX:eventY/magn_x_raw_roc_falling_value +What: /sys/.../deviceX:eventY/magn_y_raw_roc_rising_value +What: /sys/.../deviceX:eventY/magn_y_raw_roc_falling_value +What: /sys/.../deviceX:eventY/magn_z_raw_roc_rising_value +What: /sys/.../deviceX:eventY/magn_z_raw_roc_falling_value +What: /sys/.../deviceX:eventY/inZ_supply_raw_roc_rising_value +What: /sys/.../deviceX:eventY/inZ_supply_raw_roc_falling_value +What: /sys/.../deviceX:eventY/inZ_raw_roc_falling_value +What: /sys/.../deviceX:eventY/inZ_raw_roc_falling_value +What: /sys/.../deviceX:eventY/temp_raw_roc_falling_value +What: /sys/.../deviceX:eventY/temp_raw_roc_falling_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Period of time (in seconds) over which the raw channel value - is averaged before being compared with the threshold set in - accel_x0_thresh[_rising|_falling]_meanperiod. If direction is - not specified then this mean period applies to both directions. + Specifies the value of rate of change threshold that the + device is comparing against for the events enabled by + [Z][_name]_roc[_rising|falling]_en. + If separate attributes exist for the two directions, + but direction is not specified for this attribute, + then a single threshold value applies to both directions. + The raw or input element of the name indicates whether the + value is in raw device units or in processed units (as _raw + and _input do on sysfs direct channel read attributes). -What: /sys/.../accel_x0_thresh[_rising|_falling]_period +What: /sys/.../deviceX:eventY/accel_x_thresh_rising_period +What: /sys/.../deviceX:eventY/accel_x_thresh_falling_period +hat: /sys/.../deviceX:eventY/accel_x_roc_rising_period +What: /sys/.../deviceX:eventY/accel_x_roc_falling_period +What: /sys/.../deviceX:eventY/accel_y_thresh_rising_period +What: /sys/.../deviceX:eventY/accel_y_thresh_falling_period +What: /sys/.../deviceX:eventY/accel_y_roc_rising_period +What: /sys/.../deviceX:eventY/accel_y_roc_falling_period +What: /sys/.../deviceX:eventY/accel_z_thresh_rising_period +What: /sys/.../deviceX:eventY/accel_z_thresh_falling_period +What: /sys/.../deviceX:eventY/accel_z_roc_rising_period +What: /sys/.../deviceX:eventY/accel_z_roc_falling_period +What: /sys/.../deviceX:eventY/gyro_x_thresh_rising_period +What: /sys/.../deviceX:eventY/gyro_x_thresh_falling_period +What: /sys/.../deviceX:eventY/gyro_x_roc_rising_period +What: /sys/.../deviceX:eventY/gyro_x_roc_falling_period +What: /sys/.../deviceX:eventY/gyro_y_thresh_rising_period +What: /sys/.../deviceX:eventY/gyro_y_thresh_falling_period +What: /sys/.../deviceX:eventY/gyro_y_roc_rising_period +What: /sys/.../deviceX:eventY/gyro_y_roc_falling_period +What: /sys/.../deviceX:eventY/gyro_z_thresh_rising_period +What: /sys/.../deviceX:eventY/gyro_z_thresh_falling_period +What: /sys/.../deviceX:eventY/gyro_z_roc_rising_period +What: /sys/.../deviceX:eventY/gyro_z_roc_falling_period +What: /sys/.../deviceX:eventY/magn_x_thresh_rising_period +What: /sys/.../deviceX:eventY/magn_x_thresh_falling_period +What: /sys/.../deviceX:eventY/magn_x_roc_rising_period +What: /sys/.../deviceX:eventY/magn_x_roc_falling_period +What: /sys/.../deviceX:eventY/magn_y_thresh_rising_period +What: /sys/.../deviceX:eventY/magn_y_thresh_falling_period +What: /sys/.../deviceX:eventY/magn_y_roc_rising_period +What: /sys/.../deviceX:eventY/magn_y_roc_falling_period +What: /sys/.../deviceX:eventY/magn_z_thresh_rising_period +What: /sys/.../deviceX:eventY/magn_z_thresh_falling_period +What: /sys/.../deviceX:eventY/magn_z_roc_rising_period +What: /sys/.../deviceX:eventY/magn_z_roc_falling_period +What: /sys/.../deviceX:eventY/inZ_supply_thresh_rising_period +What: /sys/.../deviceX:eventY/inZ_supply_thresh_falling_period +What: /sys/.../deviceX:eventY/inz_supply_roc_rising_period +What: /sys/.../deviceX:eventY/inZ_supply_roc_falling_period +What: /sys/.../deviceX:eventY/inZ_thresh_rising_period +What: /sys/.../deviceX:eventY/inZ_thresh_falling_period +What: /sys/.../deviceX:eventY/inZ_roc_rising_period +What: /sys/.../deviceX:eventY/inZ_roc_falling_period +What: /sys/.../deviceX:eventY/temp_thresh_rising_period +What: /sys/.../deviceX:eventY/temp_thresh_falling_period +What: /sys/.../deviceX:eventY/temp_roc_rising_period +What: /sys/.../deviceX:eventY/temp_roc_falling_period +What: /sys/.../deviceX:eventY/accel_x&y&z_mag_falling_period KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Period of time (in seconds) for which the threshold must be - passed before an event is generated. If direction is not + Period of time (in seconds) for which the condition must be + met before an event is generated. If direction is not specified then this period applies to both directions. -What: /sys/.../device[n]:event[m]/accel_x0_mag[_rising|_falling]_en +What: /sys/.../deviceX:eventY/accel_mag_en +What: /sys/.../deviceX:eventY/accel_mag_rising_en +What: /sys/.../deviceX:eventY/accel_mag_falling_en +What: /sys/.../deviceX:eventY/accel_x_mag_en +What: /sys/.../deviceX:eventY/accel_x_mag_rising_en +What: /sys/.../deviceX:eventY/accel_x_mag_falling_en +What: /sys/.../deviceX:eventY/accel_y_mag_en +What: /sys/.../deviceX:eventY/accel_y_mag_rising_en +What: /sys/.../deviceX:eventY/accel_y_mag_falling_en +What: /sys/.../deviceX:eventY/accel_z_mag_en +What: /sys/.../deviceX:eventY/accel_z_mag_rising_en +What: /sys/.../deviceX:eventY/accel_z_mag_falling_en +What: /sys/.../deviceX:eventY/accel_x&y&z_mag_rising_en +What: /sys/.../deviceX:eventY/accel_x&y&z_mag_falling_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Similar to accel_x0_thresh[_rising|_falling]_en, but here the + Similar to accel_x_thresh[_rising|_falling]_en, but here the magnitude of the channel is compared to the threshold, not its signed value. -What: /sys/.../accel_x0__mag[_rising|_falling]_value -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - The value to which the magnitude of the channel is compared. - -What: /sys/.../accel_x0_mag[_rising|_falling]_meanperiod -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - Period of time (in seconds) over which the value of the channel - is averaged before being compared to the threshold - -What: /sys/.../accel_x0_mag[_rising|_falling]_period -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - Period of time (in seconds) for which the condition must be true - before an event occurs. - -What: /sys/.../device[n]:event[m]/accel_x0_roc[_rising|_falling]_en +What: /sys/.../accel_raw_mag_value +What: /sys/.../accel_x_raw_mag_rising_value +What: /sys/.../accel_y_raw_mag_rising_value +What: /sys/.../accel_z_raw_mag_rising_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Similar to accel_x0_thresh[_rising|_falling]_en, but here the - first differential is compared with the threshold. + The value to which the magnitude of the channel is compared. If + number or direction is not specified, applies to all channels of + this type. -What: /sys/.../accel_x0__roc[_rising|_falling]_value -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - The value to which the first differential of the channel is - compared. - -What: /sys/.../accel_x0_roc[_rising|_falling]_meanperiod -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - Period of time (in seconds) over which the value of the channel - is averaged before being compared to the threshold - -What: /sys/.../accel_x0_roc[_rising|_falling]_period -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - Period of time (in seconds) for which the condition must be true - before an event occurs. - -What: /sys/.../device[n]/device[n]:buffer:event/dev +What: /sys/bus/iio/devices/deviceX:buffer:event/dev KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Buffer for device n event character device major:minor numbers. + Buffer for device X event character device major:minor numbers. -What: /sys/.../device[n]/device[n]:buffer:access/dev +What: /sys/bus/iio/devices/deviceX:buffer:access/dev KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: - Buffer for device n access character device o major:minor numbers. + Buffer for device X access character device major:minor numbers. -What: /sys/.../device[n]:buffer/trigger +What: /sys/bus/iio/devices/deviceX:buffer/trigger KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: The name of the trigger source being used, as per string given - in /sys/class/iio/trigger[n]/name. + in /sys/class/iio/triggerY/name. -What: /sys/.../device[n]:buffer/length +What: /sys/bus/iio/devices/deviceX:buffer/length KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: Number of scans contained by the buffer. -What: /sys/.../device[n]:buffer/bytes_per_datum +What: /sys/bus/iio/devices/deviceX:buffer/bytes_per_datum KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Bytes per scan. Due to alignment fun, the scan may be larger than implied directly by the scan_element parameters. -What: /sys/.../device[n]:buffer/enable +What: /sys/bus/iio/devices/deviceX:buffer/enable KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: Actually start the buffer capture up. Will start trigger if first device and appropriate. -What: /sys/.../device[n]:buffer/alignment -KernelVersion: 2.6.35 -Contact: linux-iio@vger.kernel.org -Description: - Minimum data alignment. Scan elements larger than this are - aligned to the nearest power of 2 times this. (may not be - true in weird hardware buffers that pack data well) - -What: /sys/.../device[n]/buffer/scan_elements +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Directory containing interfaces for elements that will be captured for a single triggered sample set in the buffer. -What: /sys/.../device[n]/buffer/scan_elements/accel_x0_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_x_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_y_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_z_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_x_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_y_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_z_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_x_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_y_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_z_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/timestamp_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_supply_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY-inZ_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_x_en +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_y_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Scan element control for triggered data capture. -What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_type +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_type +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_type +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_type +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_type +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_type +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/in-in_type +What: /sys/.../deviceX:buffer/scan_elements/inY_supply_type +What: /sys/.../deviceX:buffer/scan_elements/timestamp_type KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Description of the scan element data storage within the buffer - and hence the form in which it is read from userspace. - Form is [s|u]bits/storagebits. s or u specifies if signed - (2's complement) or unsigned. bits is the number of bits of - data and storagebits is the space (after padding) that it - occupies in the buffer. Note that some devices will have - additional information in the unused bits so to get a clean - value, the bits value must be used to mask the buffer output - value appropriately. The storagebits value also specifies the - data alignment. So s48/64 will be a signed 48 bit integer - stored in a 64 bit location aligned to a a64 bit boundary. + and hence the form in which it is read from user-space. + Form is [s|u]bits/storagebits[>>shift]. s or u specifies if + signed (2's complement) or unsigned. bits is the number of bits + of data and storagebits is the space (after padding) that it + occupies in the buffer. shift if specified, is the shift that + needs to be applied prior to masking out unused bits. Some + devices put their data in the middle of the transferred elements + with additional information on both sides. Note that some + devices will have additional information in the unused bits + so to get a clean value, the bits value must be used to mask + the buffer output value appropriately. The storagebits value + also specifies the data alignment. So s48/64>>2 will be a + signed 48 bit integer stored in a 64 bit location aligned to + a a64 bit boundary. To obtain the clean value, shift right 2 + and apply a mask to zero the top 16 bits of the result. For other storage combinations this attribute will be extended appropriately. -What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_index +What: /sys/.../deviceX:buffer/scan_elements/accel_type_available +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + If the type parameter can take one of a small set of values, + this attribute lists them. + +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_index +What: /sys/.../deviceX:buffer/scan_elements/inY_supply_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_x_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_y_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_z_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_x_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_y_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_z_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_x_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_y_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_z_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_x_index +What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_y_index +What: /sys/.../deviceX:buffer/scan_elements/timestamp_index KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: A single positive integer specifying the position of this - scan element in the buffer. Note these are not dependant on - what is enabled and may not be contiguous. Thus for userspace + scan element in the buffer. Note these are not dependent on + what is enabled and may not be contiguous. Thus for user-space to establish the full layout these must be used in conjunction with all _en attributes to establish which channels are present, and the relevant _type attributes to establish the data storage format. - -What: /sys/.../device[n]/buffer/scan_elements/accel[_x0]_shift -KernelVersion: 2.6.37 -Contact: linux-iio@vger.kernel.org -Description: - A bit shift (to right) that must be applied prior to - extracting the bits specified by accel[_x0]_precision. -- cgit v1.2.3 From d846263da4c6032b7a9440d335794ef8d3e76dfb Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 23 Nov 2010 11:14:16 +0100 Subject: staging: iio: dac: ad5446: Enable driver support for AD5620/AD5640/AD5660 DA converters Initial support for single channel, 12-/14-/16-Bit nanoDAC with On-Chip Reference staging: iio: dac: ad5446: Fix according to review feedback Review feedback by Jonathan Cameron: Use kernel doc style to document headers. Turn data into a union Add some comments for clarity Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/Kconfig | 6 +- drivers/staging/iio/dac/ad5446.c | 120 +++++++++++++++++++++++++++++++++------ drivers/staging/iio/dac/ad5446.h | 72 +++++++++++++++++++---- 3 files changed, 167 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig index 9c497ccd3dce..9191bd23cc08 100644 --- a/drivers/staging/iio/dac/Kconfig +++ b/drivers/staging/iio/dac/Kconfig @@ -11,11 +11,11 @@ config AD5624R_SPI AD5664R convertors (DAC). This driver uses the common SPI interface. config AD5446 - tristate "Analog Devices AD5444, AD5446 and AD5541A, AD5512A DAC SPI driver" + tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5541A/12A DAC SPI driver" depends on SPI help - Say yes here to build support for Analog Devices AD5444, AD5446 - and AD5541A, AD5512A DACs. + Say yes here to build support for Analog Devices AD5444, AD5446, + AD5620, AD5640, AD5660 and AD5541A, AD5512A DACs. To compile this driver as a module, choose M here: the module will be called ad5446. diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index ac3165b0aeff..4d65d274b1ee 100644 --- a/drivers/staging/iio/dac/ad5446.c +++ b/drivers/staging/iio/dac/ad5446.c @@ -23,6 +23,31 @@ #include "ad5446.h" +static void ad5446_store_sample(struct ad5446_state *st, unsigned val) +{ + st->data.d16 = cpu_to_be16(AD5446_LOAD | + (val << st->chip_info->left_shift)); +} + +static void ad5542_store_sample(struct ad5446_state *st, unsigned val) +{ + st->data.d16 = cpu_to_be16(val << st->chip_info->left_shift); +} + +static void ad5620_store_sample(struct ad5446_state *st, unsigned val) +{ + st->data.d16 = cpu_to_be16(AD5620_LOAD | + (val << st->chip_info->left_shift)); +} + +static void ad5660_store_sample(struct ad5446_state *st, unsigned val) +{ + val |= AD5660_LOAD; + st->data.d24[0] = (val >> 16) & 0xFF; + st->data.d24[1] = (val >> 8) & 0xFF; + st->data.d24[2] = val & 0xFF; +} + static ssize_t ad5446_write(struct device *dev, struct device_attribute *attr, const char *buf, @@ -43,18 +68,7 @@ static ssize_t ad5446_write(struct device *dev, } mutex_lock(&dev_info->mlock); - switch (spi_get_device_id(st->spi)->driver_data) { - case ID_AD5444: - case ID_AD5446: - st->data = cpu_to_be16(AD5446_LOAD | - (val << st->chip_info->left_shift)); - break; - case ID_AD5542A: - case ID_AD5512A: - st->data = cpu_to_be16(val << st->chip_info->left_shift); - break; - } - + st->chip_info->store_sample(st, val); ret = spi_sync(st->spi, &st->msg); mutex_unlock(&dev_info->mlock); @@ -105,24 +119,76 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .storagebits = 16, .left_shift = 2, .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .store_sample = ad5446_store_sample, }, [ID_AD5446] = { .bits = 14, .storagebits = 16, .left_shift = 0, .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .store_sample = ad5446_store_sample, }, [ID_AD5542A] = { .bits = 16, .storagebits = 16, .left_shift = 0, .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .store_sample = ad5542_store_sample, }, [ID_AD5512A] = { .bits = 12, .storagebits = 16, .left_shift = 4, .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .store_sample = ad5542_store_sample, + }, + [ID_AD5620_2500] = { + .bits = 12, + .storagebits = 16, + .left_shift = 2, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .int_vref_mv = 2500, + .store_sample = ad5620_store_sample, + }, + [ID_AD5620_1250] = { + .bits = 12, + .storagebits = 16, + .left_shift = 2, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .int_vref_mv = 1250, + .store_sample = ad5620_store_sample, + }, + [ID_AD5640_2500] = { + .bits = 14, + .storagebits = 16, + .left_shift = 0, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .int_vref_mv = 2500, + .store_sample = ad5620_store_sample, + }, + [ID_AD5640_1250] = { + .bits = 14, + .storagebits = 16, + .left_shift = 0, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .int_vref_mv = 1250, + .store_sample = ad5620_store_sample, + }, + [ID_AD5660_2500] = { + .bits = 16, + .storagebits = 24, + .left_shift = 0, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .int_vref_mv = 2500, + .store_sample = ad5660_store_sample, + }, + [ID_AD5660_1250] = { + .bits = 16, + .storagebits = 24, + .left_shift = 0, + .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ + .int_vref_mv = 1250, + .store_sample = ad5660_store_sample, }, }; @@ -168,16 +234,28 @@ static int __devinit ad5446_probe(struct spi_device *spi) /* Setup default message */ - st->xfer.tx_buf = &st->data, - st->xfer.len = 2, + st->xfer.tx_buf = &st->data; + st->xfer.len = st->chip_info->storagebits / 8; spi_message_init(&st->msg); spi_message_add_tail(&st->xfer, &st->msg); - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - dev_warn(&spi->dev, "reference voltage unspecified\n"); + switch (spi_get_device_id(spi)->driver_data) { + case ID_AD5620_2500: + case ID_AD5620_1250: + case ID_AD5640_2500: + case ID_AD5640_1250: + case ID_AD5660_2500: + case ID_AD5660_1250: + st->vref_mv = st->chip_info->int_vref_mv; + break; + default: + if (voltage_uv) + st->vref_mv = voltage_uv / 1000; + else + dev_warn(&spi->dev, + "reference voltage unspecified\n"); + } ret = iio_device_register(st->indio_dev); if (ret) @@ -217,6 +295,12 @@ static const struct spi_device_id ad5446_id[] = { {"ad5446", ID_AD5446}, {"ad5542a", ID_AD5542A}, {"ad5512a", ID_AD5512A}, + {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ + {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ + {"ad5640-2500", ID_AD5640_2500}, + {"ad5640-1250", ID_AD5640_1250}, + {"ad5660-2500", ID_AD5660_2500}, + {"ad5660-1250", ID_AD5660_1250}, {} }; diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h index 24a9cda6b997..ca795a9d1866 100644 --- a/drivers/staging/iio/dac/ad5446.h +++ b/drivers/staging/iio/dac/ad5446.h @@ -5,8 +5,8 @@ * * Licensed under the GPL-2 or later. */ -#ifndef IIO_ADC_AD5446_H_ -#define IIO_ADC_AD5446_H_ +#ifndef IIO_DAC_AD5446_H_ +#define IIO_DAC_AD5446_H_ /* DAC Control Bits */ @@ -15,14 +15,30 @@ #define AD5446_NOP (0x2 << 14) /* No operation */ #define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */ +#define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/ +#define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */ +#define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */ +#define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */ + +#define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/ +#define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */ +#define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */ +#define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */ + #define RES_MASK(bits) ((1 << (bits)) - 1) -struct ad5446_chip_info { - u8 bits; /* number of DAC bits */ - u8 storagebits; /* number of bits written to the DAC */ - u8 left_shift; /* number of bits the datum must be shifted */ - char sign; /* [s]igned or [u]nsigned */ -}; +/** + * struct ad5446_state - driver instance specific data + * @indio_dev: the industrial I/O device + * @spi: spi_device + * @chip_info: chip model specific constants, available modes etc + * @reg: supply regulator + * @poll_work: bottom half of polling interrupt handler + * @vref_mv: actual reference voltage used + * @xfer: default spi transfer + * @msg: default spi message + * @data: spi transmit buffer + */ struct ad5446_state { struct iio_dev *indio_dev; @@ -33,14 +49,50 @@ struct ad5446_state { unsigned short vref_mv; struct spi_transfer xfer; struct spi_message msg; - unsigned short data; + union { + unsigned short d16; + unsigned char d24[3]; + } data; +}; + +/** + * struct ad5446_chip_info - chip specifc information + * @bits: accuracy of the DAC in bits + * @storagebits: number of bits written to the DAC + * @left_shift: number of bits the datum must be shifted + * @sign: data representation [s]igned or [u]nsigned + * @int_vref_mv: AD5620/40/60: the internal reference voltage + * @store_sample: chip specifc helper function to store the datum + */ + +struct ad5446_chip_info { + u8 bits; + u8 storagebits; + u8 left_shift; + char sign; + u16 int_vref_mv; + void (*store_sample) (struct ad5446_state *st, unsigned val); }; +/** + * ad5446_supported_device_ids: + * The AD5620/40/60 parts are available in different fixed internal reference + * voltage options. The actual part numbers may look differently + * (and a bit cryptic), however this style is used to make clear which + * parts are supported here. + */ + enum ad5446_supported_device_ids { ID_AD5444, ID_AD5446, ID_AD5542A, ID_AD5512A, + ID_AD5620_2500, + ID_AD5620_1250, + ID_AD5640_2500, + ID_AD5640_1250, + ID_AD5660_2500, + ID_AD5660_1250, }; -#endif /* IIO_ADC_AD5446_H_ */ +#endif /* IIO_DAC_AD5446_H_ */ -- cgit v1.2.3 From 4f76548299196e0fd880469a39552ccde797474b Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 23 Nov 2010 11:40:13 +0100 Subject: staging: iio: dac: ad5446: Remove unused sign member from chip specific information structure Remove unused sign member from chip specific information structure Fix typos Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dac/ad5446.c | 10 ---------- drivers/staging/iio/dac/ad5446.h | 6 ++---- 2 files changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index 4d65d274b1ee..e3387cd31145 100644 --- a/drivers/staging/iio/dac/ad5446.c +++ b/drivers/staging/iio/dac/ad5446.c @@ -118,35 +118,30 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .bits = 12, .storagebits = 16, .left_shift = 2, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .store_sample = ad5446_store_sample, }, [ID_AD5446] = { .bits = 14, .storagebits = 16, .left_shift = 0, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .store_sample = ad5446_store_sample, }, [ID_AD5542A] = { .bits = 16, .storagebits = 16, .left_shift = 0, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .store_sample = ad5542_store_sample, }, [ID_AD5512A] = { .bits = 12, .storagebits = 16, .left_shift = 4, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .store_sample = ad5542_store_sample, }, [ID_AD5620_2500] = { .bits = 12, .storagebits = 16, .left_shift = 2, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .int_vref_mv = 2500, .store_sample = ad5620_store_sample, }, @@ -154,7 +149,6 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .bits = 12, .storagebits = 16, .left_shift = 2, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .int_vref_mv = 1250, .store_sample = ad5620_store_sample, }, @@ -162,7 +156,6 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .bits = 14, .storagebits = 16, .left_shift = 0, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .int_vref_mv = 2500, .store_sample = ad5620_store_sample, }, @@ -170,7 +163,6 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .bits = 14, .storagebits = 16, .left_shift = 0, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .int_vref_mv = 1250, .store_sample = ad5620_store_sample, }, @@ -178,7 +170,6 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .bits = 16, .storagebits = 24, .left_shift = 0, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .int_vref_mv = 2500, .store_sample = ad5660_store_sample, }, @@ -186,7 +177,6 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { .bits = 16, .storagebits = 24, .left_shift = 0, - .sign = 'u', /* IIO_SCAN_EL_TYPE_UNSIGNED */ .int_vref_mv = 1250, .store_sample = ad5660_store_sample, }, diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h index ca795a9d1866..902542e22c4a 100644 --- a/drivers/staging/iio/dac/ad5446.h +++ b/drivers/staging/iio/dac/ad5446.h @@ -56,20 +56,18 @@ struct ad5446_state { }; /** - * struct ad5446_chip_info - chip specifc information + * struct ad5446_chip_info - chip specific information * @bits: accuracy of the DAC in bits * @storagebits: number of bits written to the DAC * @left_shift: number of bits the datum must be shifted - * @sign: data representation [s]igned or [u]nsigned * @int_vref_mv: AD5620/40/60: the internal reference voltage - * @store_sample: chip specifc helper function to store the datum + * @store_sample: chip specific helper function to store the datum */ struct ad5446_chip_info { u8 bits; u8 storagebits; u8 left_shift; - char sign; u16 int_vref_mv; void (*store_sample) (struct ad5446_state *st, unsigned val); }; -- cgit v1.2.3 From 4f26559156eae1b616ef2d0d168bd25f493e02f4 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:39 +0100 Subject: Staging: batman-adv: Replace Andrew Lunn as Staging maintainer Andrew Lunn didn't submit patches to staging since a while and may not be the right person for new patches. Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO index 11c384f8b063..7967ffaa833e 100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@ -9,6 +9,6 @@ Please send all patches to: Marek Lindner Simon Wunderlich - Andrew Lunn + Sven Eckelmann b.a.t.m.a.n@lists.open-mesh.org Greg Kroah-Hartman -- cgit v1.2.3 From 2f1646788f4d3cd2ce5cb24d13096afbd8782665 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:55:40 +0100 Subject: Staging: batman-adv: ensure that eth_type_trans gets linear memory eth_type_trans tries to pull data with the length of the ethernet header from the skb. We only ensured that enough data for the first ethernet header and the batman header is available in non-paged memory of the skb and not for the ethernet after the batman header. eth_type_trans would fail sometimes with drivers which don't ensure that all there data is perfectly linearised. Reported-by: Rafal Lesniak Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/soft-interface.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 3904db9ce7b1..0e996181daf7 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -194,14 +194,15 @@ void interface_rx(struct net_device *soft_iface, struct bat_priv *priv = netdev_priv(soft_iface); /* check if enough space is available for pulling, and pull */ - if (!pskb_may_pull(skb, hdr_size)) { - kfree_skb(skb); - return; - } + if (!pskb_may_pull(skb, hdr_size)) + goto dropped; + skb_pull_rcsum(skb, hdr_size); /* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/ /* skb->dev & skb->pkt_type are set here */ + if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) + goto dropped; skb->protocol = eth_type_trans(skb, soft_iface); /* should not be neccesary anymore as we use skb_pull_rcsum() @@ -216,6 +217,11 @@ void interface_rx(struct net_device *soft_iface, soft_iface->last_rx = jiffies; netif_rx(skb); + return; + +dropped: + kfree_skb(skb); + return; } #ifdef HAVE_NET_DEVICE_OPS -- cgit v1.2.3 From 43fc987224a45dc53ccc302df5889230d9587921 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:41 +0100 Subject: Staging: batman-adv: Add new sysfs files to README Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README index 7c878bb07f3a..77f0cdd5b0dd 100644 --- a/drivers/staging/batman-adv/README +++ b/drivers/staging/batman-adv/README @@ -1,4 +1,4 @@ -[state: 04-09-2010] +[state: 21-11-2010] BATMAN-ADV ---------- @@ -67,7 +67,8 @@ All mesh wide settings can be found in batman's own interface folder: # ls /sys/class/net/bat0/mesh/ -# aggregated_ogms bonding orig_interval vis_mode +# aggregated_ogms bonding fragmentation orig_interval +# vis_mode There is a special folder for debugging informations: @@ -237,4 +238,3 @@ You can also contact the Authors: Marek Lindner Simon Wunderlich - -- cgit v1.2.3 From bd27509f49ab841bc10fd604ccd9e7f9914b7120 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:42 +0100 Subject: Staging: batman-adv: Don't remove interface with spinlock held We call a lot of the netdevice code when holding if_list_lock which will spin the whole time. This is not necessary because we only want to protect the access to the list to be serialized. An extra queue can be used which hold all interfaces which should be removed and then use that queue without any locks for netdevice cleanup. Reported-by: Rafal Lesniak Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index b68a7e5173be..d85de82f941a 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -463,9 +463,6 @@ static void hardif_remove_interface(struct batman_if *batman_if) return; batman_if->if_status = IF_TO_BE_REMOVED; - - /* caller must take if_list_lock */ - list_del_rcu(&batman_if->list); synchronize_rcu(); sysfs_del_hardif(&batman_if->hardif_obj); hardif_put(batman_if); @@ -474,13 +471,21 @@ static void hardif_remove_interface(struct batman_if *batman_if) void hardif_remove_interfaces(void) { struct batman_if *batman_if, *batman_if_tmp; + struct list_head if_queue; + + INIT_LIST_HEAD(&if_queue); - rtnl_lock(); spin_lock(&if_list_lock); list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { - hardif_remove_interface(batman_if); + list_del_rcu(&batman_if->list); + list_add_tail(&batman_if->list, &if_queue); } spin_unlock(&if_list_lock); + + rtnl_lock(); + list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) { + hardif_remove_interface(batman_if); + } rtnl_unlock(); } @@ -507,8 +512,10 @@ static int hard_if_event(struct notifier_block *this, break; case NETDEV_UNREGISTER: spin_lock(&if_list_lock); - hardif_remove_interface(batman_if); + list_del_rcu(&batman_if->list); spin_unlock(&if_list_lock); + + hardif_remove_interface(batman_if); break; case NETDEV_CHANGEMTU: if (batman_if->soft_iface) -- cgit v1.2.3 From b4abfcd4c79ec12340b4c68e3a211badd3c90e20 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:55:43 +0100 Subject: Staging: batman-adv: convert batman_if custom refcounting to kref functions Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/bat_sysfs.c | 12 ++++++------ drivers/staging/batman-adv/hard-interface.c | 30 ++++++++++++++--------------- drivers/staging/batman-adv/hard-interface.h | 14 +++++--------- drivers/staging/batman-adv/types.h | 2 +- 4 files changed, 26 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index bc17fb816300..536f65120edd 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -413,7 +413,7 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? "none" : batman_if->soft_iface->name); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return length; } @@ -436,7 +436,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, if (strlen(buff) >= IFNAMSIZ) { pr_err("Invalid parameter for 'mesh_iface' setting received: " "interface name too long '%s'\n", buff); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return -EINVAL; } @@ -447,7 +447,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return count; } @@ -455,7 +455,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, rtnl_lock(); hardif_disable_interface(batman_if); rtnl_unlock(); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return count; } @@ -467,7 +467,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, } ret = hardif_enable_interface(batman_if, buff); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return ret; } @@ -502,7 +502,7 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, break; } - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); return length; } diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index d85de82f941a..6d5b74862f23 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -50,7 +50,7 @@ struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev) out: if (batman_if) - hardif_hold(batman_if); + kref_get(&batman_if->refcount); rcu_read_unlock(); return batman_if; @@ -100,7 +100,7 @@ static struct batman_if *get_active_batman_if(struct net_device *soft_iface) out: if (batman_if) - hardif_hold(batman_if); + kref_get(&batman_if->refcount); rcu_read_unlock(); return batman_if; @@ -125,13 +125,13 @@ static void set_primary_if(struct bat_priv *bat_priv, struct batman_if *old_if; if (batman_if) - hardif_hold(batman_if); + kref_get(&batman_if->refcount); old_if = bat_priv->primary_if; bat_priv->primary_if = batman_if; if (old_if) - hardif_put(old_if); + kref_put(&old_if->refcount, hardif_free_ref); if (!bat_priv->primary_if) return; @@ -315,7 +315,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN); batman_if->batman_adv_ptype.func = batman_skb_recv; batman_if->batman_adv_ptype.dev = batman_if->net_dev; - hardif_hold(batman_if); + kref_get(&batman_if->refcount); dev_add_pack(&batman_if->batman_adv_ptype); atomic_set(&batman_if->seqno, 1); @@ -374,7 +374,7 @@ void hardif_disable_interface(struct batman_if *batman_if) bat_info(batman_if->soft_iface, "Removing interface: %s\n", batman_if->net_dev->name); dev_remove_pack(&batman_if->batman_adv_ptype); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); bat_priv->num_ifaces--; orig_hash_del_if(batman_if, bat_priv->num_ifaces); @@ -386,7 +386,7 @@ void hardif_disable_interface(struct batman_if *batman_if) set_primary_if(bat_priv, new_if); if (new_if) - hardif_put(new_if); + kref_put(&new_if->refcount, hardif_free_ref); } kfree(batman_if->packet_buff); @@ -432,8 +432,7 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) batman_if->soft_iface = NULL; batman_if->if_status = IF_NOT_IN_USE; INIT_LIST_HEAD(&batman_if->list); - atomic_set(&batman_if->refcnt, 0); - hardif_hold(batman_if); + kref_init(&batman_if->refcount); check_known_mac_addr(batman_if->net_dev); @@ -442,7 +441,7 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) spin_unlock(&if_list_lock); /* extra reference for return */ - hardif_hold(batman_if); + kref_get(&batman_if->refcount); return batman_if; free_if: @@ -465,7 +464,7 @@ static void hardif_remove_interface(struct batman_if *batman_if) batman_if->if_status = IF_TO_BE_REMOVED; synchronize_rcu(); sysfs_del_hardif(&batman_if->hardif_obj); - hardif_put(batman_if); + kref_put(&batman_if->refcount, hardif_free_ref); } void hardif_remove_interfaces(void) @@ -522,10 +521,8 @@ static int hard_if_event(struct notifier_block *this, update_min_mtu(batman_if->soft_iface); break; case NETDEV_CHANGEADDR: - if (batman_if->if_status == IF_NOT_IN_USE) { - hardif_put(batman_if); - goto out; - } + if (batman_if->if_status == IF_NOT_IN_USE) + goto hardif_put; check_known_mac_addr(batman_if->net_dev); update_mac_addresses(batman_if); @@ -537,8 +534,9 @@ static int hard_if_event(struct notifier_block *this, default: break; }; - hardif_put(batman_if); +hardif_put: + kref_put(&batman_if->refcount, hardif_free_ref); out: return NOTIFY_DONE; } diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h index d5508899065b..1d1cd9ff7126 100644 --- a/drivers/staging/batman-adv/hard-interface.h +++ b/drivers/staging/batman-adv/hard-interface.h @@ -42,17 +42,13 @@ int batman_skb_recv(struct sk_buff *skb, int hardif_min_mtu(struct net_device *soft_iface); void update_min_mtu(struct net_device *soft_iface); -static inline void hardif_hold(struct batman_if *batman_if) +static inline void hardif_free_ref(struct kref *refcount) { - atomic_inc(&batman_if->refcnt); -} + struct batman_if *batman_if; -static inline void hardif_put(struct batman_if *batman_if) -{ - if (atomic_dec_and_test(&batman_if->refcnt)) { - dev_put(batman_if->net_dev); - kfree(batman_if); - } + batman_if = container_of(refcount, struct batman_if, refcount); + dev_put(batman_if->net_dev); + kfree(batman_if); } #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index f3f7366231e7..d89ec70a67a8 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -43,7 +43,7 @@ struct batman_if { unsigned char *packet_buff; int packet_len; struct kobject *hardif_obj; - atomic_t refcnt; + struct kref refcount; struct packet_type batman_adv_ptype; struct net_device *soft_iface; }; -- cgit v1.2.3 From 3f427604d669031343af8e6ecd8d1cc7a6408ab2 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:55:44 +0100 Subject: Staging: batman-adv: use rcu callbacks when freeing batman_if Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 12 ++++++++++-- drivers/staging/batman-adv/hard-interface.h | 1 - drivers/staging/batman-adv/types.h | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 6d5b74862f23..c2ff29432a5e 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -36,6 +36,15 @@ /* protect update critical side of if_list - but not the content */ static DEFINE_SPINLOCK(if_list_lock); +static void hardif_free_rcu(struct rcu_head *rcu) +{ + struct batman_if *batman_if; + + batman_if = container_of(rcu, struct batman_if, rcu); + dev_put(batman_if->net_dev); + kref_put(&batman_if->refcount, hardif_free_ref); +} + struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev) { struct batman_if *batman_if; @@ -462,9 +471,8 @@ static void hardif_remove_interface(struct batman_if *batman_if) return; batman_if->if_status = IF_TO_BE_REMOVED; - synchronize_rcu(); sysfs_del_hardif(&batman_if->hardif_obj); - kref_put(&batman_if->refcount, hardif_free_ref); + call_rcu(&batman_if->rcu, hardif_free_rcu); } void hardif_remove_interfaces(void) diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h index 1d1cd9ff7126..30ec3b8db459 100644 --- a/drivers/staging/batman-adv/hard-interface.h +++ b/drivers/staging/batman-adv/hard-interface.h @@ -47,7 +47,6 @@ static inline void hardif_free_ref(struct kref *refcount) struct batman_if *batman_if; batman_if = container_of(refcount, struct batman_if, refcount); - dev_put(batman_if->net_dev); kfree(batman_if); } diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index d89ec70a67a8..8f6ba1c56927 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -46,6 +46,7 @@ struct batman_if { struct kref refcount; struct packet_type batman_adv_ptype; struct net_device *soft_iface; + struct rcu_head rcu; }; /** -- cgit v1.2.3 From 49b588e79f7c85aec05008a945fdf17d281e83f9 Mon Sep 17 00:00:00 2001 From: Andreas Langer Date: Mon, 22 Nov 2010 00:55:45 +0100 Subject: Staging: batman-adv: restructure fragmentation to handle batman unicast packets The unicast_frag_send_skb() function expected 'raw' packets (without any batman-adv header) to fragment them. This needs to be changed, so that this function is able to fragment packets that already traveled inside the mesh but need to be fragmented now. Signed-off-by: Andreas Langer Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/unicast.c | 66 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 0459413ff67f..58bf2b6201bf 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -152,55 +152,58 @@ void frag_list_free(struct list_head *head) return; } -static int unicast_send_frag_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[], - struct orig_node *orig_node) +static int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct batman_if *batman_if, uint8_t dstaddr[]) { - struct unicast_frag_packet *ucast_frag1, *ucast_frag2; - int hdr_len = sizeof(struct unicast_frag_packet); + struct unicast_packet tmp_uc, *unicast_packet; struct sk_buff *frag_skb; + struct unicast_frag_packet *frag1, *frag2; + int uc_hdr_len = sizeof(struct unicast_packet); + int ucf_hdr_len = sizeof(struct unicast_frag_packet); int data_len = skb->len; if (!bat_priv->primary_if) goto dropped; - frag_skb = dev_alloc_skb(data_len - (data_len / 2) + hdr_len); + unicast_packet = (struct unicast_packet *) skb->data; + + memcpy(&tmp_uc, unicast_packet, uc_hdr_len); + frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); skb_split(skb, frag_skb, data_len / 2); - if (my_skb_head_push(frag_skb, hdr_len) < 0 || - my_skb_head_push(skb, hdr_len) < 0) + if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || + my_skb_head_push(frag_skb, ucf_hdr_len) < 0) goto drop_frag; - ucast_frag1 = (struct unicast_frag_packet *)skb->data; - ucast_frag2 = (struct unicast_frag_packet *)frag_skb->data; + frag1 = (struct unicast_frag_packet *)skb->data; + frag2 = (struct unicast_frag_packet *)frag_skb->data; - ucast_frag1->version = COMPAT_VERSION; - ucast_frag1->packet_type = BAT_UNICAST_FRAG; - ucast_frag1->ttl = TTL; - memcpy(ucast_frag1->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - memcpy(ucast_frag1->dest, orig_node->orig, ETH_ALEN); + memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet)); - memcpy(ucast_frag2, ucast_frag1, sizeof(struct unicast_frag_packet)); + frag1->ttl--; + frag1->version = COMPAT_VERSION; + frag1->packet_type = BAT_UNICAST_FRAG; - ucast_frag1->flags |= UNI_FRAG_HEAD; - ucast_frag2->flags &= ~UNI_FRAG_HEAD; + memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); - ucast_frag1->seqno = htons((uint16_t)atomic_inc_return( - &batman_if->frag_seqno)); + frag1->flags |= UNI_FRAG_HEAD; + frag2->flags &= ~UNI_FRAG_HEAD; - ucast_frag2->seqno = htons((uint16_t)atomic_inc_return( - &batman_if->frag_seqno)); + frag1->seqno = htons((uint16_t)atomic_inc_return( + &batman_if->frag_seqno)); + frag2->seqno = htons((uint16_t)atomic_inc_return( + &batman_if->frag_seqno)); send_skb_packet(skb, batman_if, dstaddr); send_skb_packet(frag_skb, batman_if, dstaddr); - return 0; + return NET_RX_SUCCESS; drop_frag: kfree_skb(frag_skb); dropped: kfree_skb(skb); - return 1; + return NET_RX_DROP; } int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) @@ -240,11 +243,6 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) if (batman_if->if_status != IF_ACTIVE) goto dropped; - if (atomic_read(&bat_priv->frag_enabled) && - data_len + sizeof(struct unicast_packet) > batman_if->net_dev->mtu) - return unicast_send_frag_skb(skb, bat_priv, batman_if, - dstaddr, orig_node); - if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) goto dropped; @@ -258,6 +256,14 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); + if (atomic_read(&bat_priv->frag_enabled) && + data_len + sizeof(struct unicast_packet) > + batman_if->net_dev->mtu) { + /* send frag skb decreases ttl */ + unicast_packet->ttl++; + return frag_send_skb(skb, bat_priv, batman_if, + dstaddr); + } send_skb_packet(skb, batman_if, dstaddr); return 0; -- cgit v1.2.3 From 8bbde32cf5bd9dbe2f53d562f563b465c0829b23 Mon Sep 17 00:00:00 2001 From: Andreas Langer Date: Mon, 22 Nov 2010 00:55:46 +0100 Subject: Staging: batman-adv: add frag_ prefix to all fragmentation related functions Signed-off-by: Andreas Langer Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/routing.c | 8 ++++---- drivers/staging/batman-adv/unicast.c | 8 ++++---- drivers/staging/batman-adv/unicast.h | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 657b69e6b957..295e92e49429 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1231,24 +1231,24 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) orig_node->last_frag_packet = jiffies; if (list_empty(&orig_node->frag_list) && - create_frag_buffer(&orig_node->frag_list)) { + frag_create_buffer(&orig_node->frag_list)) { spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); return NET_RX_DROP; } tmp_frag_entry = - search_frag_packet(&orig_node->frag_list, + frag_search_packet(&orig_node->frag_list, unicast_packet); if (!tmp_frag_entry) { - create_frag_entry(&orig_node->frag_list, skb); + frag_create_entry(&orig_node->frag_list, skb); spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); return NET_RX_SUCCESS; } - skb = merge_frag_packet(&orig_node->frag_list, + skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry, skb); spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); if (!skb) diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 58bf2b6201bf..fef8521235f1 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -29,7 +29,7 @@ #include "hard-interface.h" -struct sk_buff *merge_frag_packet(struct list_head *head, +struct sk_buff *frag_merge_packet(struct list_head *head, struct frag_packet_list_entry *tfp, struct sk_buff *skb) { @@ -62,7 +62,7 @@ struct sk_buff *merge_frag_packet(struct list_head *head, return skb; } -void create_frag_entry(struct list_head *head, struct sk_buff *skb) +void frag_create_entry(struct list_head *head, struct sk_buff *skb) { struct frag_packet_list_entry *tfp; struct unicast_frag_packet *up = @@ -78,7 +78,7 @@ void create_frag_entry(struct list_head *head, struct sk_buff *skb) return; } -int create_frag_buffer(struct list_head *head) +int frag_create_buffer(struct list_head *head) { int i; struct frag_packet_list_entry *tfp; @@ -99,7 +99,7 @@ int create_frag_buffer(struct list_head *head) return 0; } -struct frag_packet_list_entry *search_frag_packet(struct list_head *head, +struct frag_packet_list_entry *frag_search_packet(struct list_head *head, struct unicast_frag_packet *up) { struct frag_packet_list_entry *tfp; diff --git a/drivers/staging/batman-adv/unicast.h b/drivers/staging/batman-adv/unicast.h index 797369771900..b50d61b83600 100644 --- a/drivers/staging/batman-adv/unicast.h +++ b/drivers/staging/batman-adv/unicast.h @@ -25,13 +25,13 @@ #define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */ #define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */ -struct sk_buff *merge_frag_packet(struct list_head *head, +struct sk_buff *frag_merge_packet(struct list_head *head, struct frag_packet_list_entry *tfp, struct sk_buff *skb); -void create_frag_entry(struct list_head *head, struct sk_buff *skb); -int create_frag_buffer(struct list_head *head); -struct frag_packet_list_entry *search_frag_packet(struct list_head *head, +void frag_create_entry(struct list_head *head, struct sk_buff *skb); +int frag_create_buffer(struct list_head *head); +struct frag_packet_list_entry *frag_search_packet(struct list_head *head, struct unicast_frag_packet *up); void frag_list_free(struct list_head *head); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); -- cgit v1.2.3 From f3cc7595d242a22a9ffba91979d2cd4e4e815424 Mon Sep 17 00:00:00 2001 From: Andreas Langer Date: Mon, 22 Nov 2010 00:55:47 +0100 Subject: Staging: batman-adv: move skb reassembly of fragmented packets into dedicated function Signed-off-by: Andreas Langer Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/routing.c | 43 ++++------------------- drivers/staging/batman-adv/unicast.c | 66 ++++++++++++++++++++++++++++++++---- drivers/staging/batman-adv/unicast.h | 10 ++---- 3 files changed, 69 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 295e92e49429..d36c3f932d8c 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1204,10 +1204,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct unicast_frag_packet *unicast_packet; - struct orig_node *orig_node; - struct frag_packet_list_entry *tmp_frag_entry; int hdr_size = sizeof(struct unicast_frag_packet); - unsigned long flags; + struct sk_buff *new_skb = NULL; + int ret; if (check_unicast_packet(skb, hdr_size) < 0) return NET_RX_DROP; @@ -1217,44 +1216,16 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) /* packet for me */ if (is_my_mac(unicast_packet->dest)) { - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, unicast_packet->orig)); - - if (!orig_node) { - pr_debug("couldn't find orig node for fragmentation\n"); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); - return NET_RX_DROP; - } - - orig_node->last_frag_packet = jiffies; + ret = frag_reassemble_skb(skb, bat_priv, &new_skb); - if (list_empty(&orig_node->frag_list) && - frag_create_buffer(&orig_node->frag_list)) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); + if (ret == NET_RX_DROP) return NET_RX_DROP; - } - - tmp_frag_entry = - frag_search_packet(&orig_node->frag_list, - unicast_packet); - if (!tmp_frag_entry) { - frag_create_entry(&orig_node->frag_list, skb); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); + /* packet was buffered for late merge */ + if (!new_skb) return NET_RX_SUCCESS; - } - skb = frag_merge_packet(&orig_node->frag_list, - tmp_frag_entry, skb); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); - if (!skb) - return NET_RX_DROP; - - interface_rx(recv_if->soft_iface, skb, hdr_size); + interface_rx(recv_if->soft_iface, new_skb, hdr_size); return NET_RX_SUCCESS; } diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index fef8521235f1..57fe2de627a1 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -29,9 +29,9 @@ #include "hard-interface.h" -struct sk_buff *frag_merge_packet(struct list_head *head, - struct frag_packet_list_entry *tfp, - struct sk_buff *skb) +static struct sk_buff *frag_merge_packet(struct list_head *head, + struct frag_packet_list_entry *tfp, + struct sk_buff *skb) { struct unicast_frag_packet *up = (struct unicast_frag_packet *)skb->data; @@ -62,7 +62,7 @@ struct sk_buff *frag_merge_packet(struct list_head *head, return skb; } -void frag_create_entry(struct list_head *head, struct sk_buff *skb) +static void frag_create_entry(struct list_head *head, struct sk_buff *skb) { struct frag_packet_list_entry *tfp; struct unicast_frag_packet *up = @@ -78,7 +78,7 @@ void frag_create_entry(struct list_head *head, struct sk_buff *skb) return; } -int frag_create_buffer(struct list_head *head) +static int frag_create_buffer(struct list_head *head) { int i; struct frag_packet_list_entry *tfp; @@ -99,7 +99,7 @@ int frag_create_buffer(struct list_head *head) return 0; } -struct frag_packet_list_entry *frag_search_packet(struct list_head *head, +static struct frag_packet_list_entry *frag_search_packet(struct list_head *head, struct unicast_frag_packet *up) { struct frag_packet_list_entry *tfp; @@ -152,6 +152,60 @@ void frag_list_free(struct list_head *head) return; } +/* frag_reassemble_skb(): + * returns NET_RX_DROP if the operation failed - skb is left intact + * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL) + * or the skb could be reassembled (skb_new will point to the new packet and + * skb was freed) + */ +int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct sk_buff **new_skb) +{ + unsigned long flags; + struct orig_node *orig_node; + struct frag_packet_list_entry *tmp_frag_entry; + int ret = NET_RX_DROP; + struct unicast_frag_packet *unicast_packet = + (struct unicast_frag_packet *)skb->data; + + *new_skb = NULL; + spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + orig_node = ((struct orig_node *) + hash_find(bat_priv->orig_hash, unicast_packet->orig)); + + if (!orig_node) { + pr_debug("couldn't find originator in orig_hash\n"); + goto out; + } + + orig_node->last_frag_packet = jiffies; + + if (list_empty(&orig_node->frag_list) && + frag_create_buffer(&orig_node->frag_list)) { + pr_debug("couldn't create frag buffer\n"); + goto out; + } + + tmp_frag_entry = frag_search_packet(&orig_node->frag_list, + unicast_packet); + + if (!tmp_frag_entry) { + frag_create_entry(&orig_node->frag_list, skb); + ret = NET_RX_SUCCESS; + goto out; + } + + *new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry, + skb); + /* if not, merge failed */ + if (*new_skb) + ret = NET_RX_SUCCESS; +out: + spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + + return ret; +} + static int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, struct batman_if *batman_if, uint8_t dstaddr[]) { diff --git a/drivers/staging/batman-adv/unicast.h b/drivers/staging/batman-adv/unicast.h index b50d61b83600..5908b01fb1c5 100644 --- a/drivers/staging/batman-adv/unicast.h +++ b/drivers/staging/batman-adv/unicast.h @@ -25,14 +25,8 @@ #define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */ #define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */ -struct sk_buff *frag_merge_packet(struct list_head *head, - struct frag_packet_list_entry *tfp, - struct sk_buff *skb); - -void frag_create_entry(struct list_head *head, struct sk_buff *skb); -int frag_create_buffer(struct list_head *head); -struct frag_packet_list_entry *frag_search_packet(struct list_head *head, - struct unicast_frag_packet *up); +int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct sk_buff **new_skb); void frag_list_free(struct list_head *head); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); -- cgit v1.2.3 From b8cd75445e842b11a0a8ff1e763303a575c21c77 Mon Sep 17 00:00:00 2001 From: Andreas Langer Date: Mon, 22 Nov 2010 00:55:48 +0100 Subject: Staging: batman-adv: remove redundant is_my_mac() check in route_unicast_packet Callers should check the if the received packet is for us before it calls route_unicast_packet. Signed-off-by: Andreas Langer Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/routing.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index d36c3f932d8c..9b61d6bc37d6 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1131,12 +1131,6 @@ static int route_unicast_packet(struct sk_buff *skb, unicast_packet = (struct unicast_packet *)skb->data; - /* packet for me */ - if (is_my_mac(unicast_packet->dest)) { - interface_rx(recv_if->soft_iface, skb, hdr_size); - return NET_RX_SUCCESS; - } - /* TTL exceeded */ if (unicast_packet->ttl < 2) { pr_debug("Warning - can't forward unicast packet from %pM to " @@ -1170,7 +1164,6 @@ static int route_unicast_packet(struct sk_buff *skb, return NET_RX_DROP; unicast_packet = (struct unicast_packet *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); /* decrement ttl */ unicast_packet->ttl--; -- cgit v1.2.3 From 9061109ab18352c73b5dda426043dbb6d5e2dae7 Mon Sep 17 00:00:00 2001 From: Andreas Langer Date: Mon, 22 Nov 2010 00:55:49 +0100 Subject: Staging: batman-adv: fragment forwarded packets If a packet is too big to be forwarded over an interface it will be fragmented on-the-fly (if fragmentation is enabled). Signed-off-by: Andreas Langer Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/routing.c | 6 ++++++ drivers/staging/batman-adv/unicast.c | 4 ++-- drivers/staging/batman-adv/unicast.h | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 9b61d6bc37d6..1e101113b6ff 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1165,6 +1165,12 @@ static int route_unicast_packet(struct sk_buff *skb, unicast_packet = (struct unicast_packet *)skb->data; + if (unicast_packet->packet_type == BAT_UNICAST && + atomic_read(&bat_priv->frag_enabled) && + skb->len > batman_if->net_dev->mtu) + return frag_send_skb(skb, bat_priv, batman_if, + dstaddr); + /* decrement ttl */ unicast_packet->ttl--; diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 57fe2de627a1..12afae618ce2 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -206,8 +206,8 @@ out: return ret; } -static int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[]) +int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct batman_if *batman_if, uint8_t dstaddr[]) { struct unicast_packet tmp_uc, *unicast_packet; struct sk_buff *frag_skb; diff --git a/drivers/staging/batman-adv/unicast.h b/drivers/staging/batman-adv/unicast.h index 5908b01fb1c5..e32b7867a9a4 100644 --- a/drivers/staging/batman-adv/unicast.h +++ b/drivers/staging/batman-adv/unicast.h @@ -29,5 +29,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, struct sk_buff **new_skb); void frag_list_free(struct list_head *head); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); +int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, + struct batman_if *batman_if, uint8_t dstaddr[]); #endif /* _NET_BATMAN_ADV_UNICAST_H_ */ -- cgit v1.2.3 From 225f7b0b950d141819a8d9694141571b349e563d Mon Sep 17 00:00:00 2001 From: Andreas Langer Date: Mon, 22 Nov 2010 00:55:50 +0100 Subject: Staging: batman-adv: reassemble fragmented skb if mtu allows it Signed-off-by: Andreas Langer Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/routing.c | 21 ++++++++++++++++++++- drivers/staging/batman-adv/unicast.c | 8 ++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 1e101113b6ff..750cec708244 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1128,6 +1128,8 @@ static int route_unicast_packet(struct sk_buff *skb, unsigned long flags; struct unicast_packet *unicast_packet; struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); + int ret; + struct sk_buff *new_skb; unicast_packet = (struct unicast_packet *)skb->data; @@ -1171,6 +1173,22 @@ static int route_unicast_packet(struct sk_buff *skb, return frag_send_skb(skb, bat_priv, batman_if, dstaddr); + if (unicast_packet->packet_type == BAT_UNICAST_FRAG && + 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) { + + ret = frag_reassemble_skb(skb, bat_priv, &new_skb); + + if (ret == NET_RX_DROP) + return NET_RX_DROP; + + /* packet was buffered for late merge */ + if (!new_skb) + return NET_RX_SUCCESS; + + skb = new_skb; + unicast_packet = (struct unicast_packet *) skb->data; + } + /* decrement ttl */ unicast_packet->ttl--; @@ -1224,7 +1242,8 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) if (!new_skb) return NET_RX_SUCCESS; - interface_rx(recv_if->soft_iface, new_skb, hdr_size); + interface_rx(recv_if->soft_iface, new_skb, + sizeof(struct unicast_packet)); return NET_RX_SUCCESS; } diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 12afae618ce2..e58e634c2806 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -36,6 +36,9 @@ static struct sk_buff *frag_merge_packet(struct list_head *head, struct unicast_frag_packet *up = (struct unicast_frag_packet *)skb->data; struct sk_buff *tmp_skb; + struct unicast_packet *unicast_packet; + int hdr_len = sizeof(struct unicast_packet), + uni_diff = sizeof(struct unicast_frag_packet) - hdr_len; /* set skb to the first part and tmp_skb to the second part */ if (up->flags & UNI_FRAG_HEAD) { @@ -59,6 +62,11 @@ static struct sk_buff *frag_merge_packet(struct list_head *head, memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len); kfree_skb(tmp_skb); + + memmove(skb->data + uni_diff, skb->data, hdr_len); + unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); + unicast_packet->packet_type = BAT_UNICAST; + return skb; } -- cgit v1.2.3 From 420193573f1191b22e08f85ead41c090d283dd05 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:55:51 +0100 Subject: Staging: batman-adv: softif bridge loop avoidance By connecting multiple batman-adv mesh nodes to the same ethernet segment a loop can be created when the soft-interface is bridged into that ethernet segment. A simple visualization of the loop involving the most common case - a LAN as ethernet segment: node1 <-- LAN --> node2 | | wifi <-- mesh --> wifi Packets from the LAN (e.g. ARP broadcasts) will circle forever from node1 or node2 over the mesh back into the LAN. This patch adds the functionality to detect other batman-adv nodes connected to the LAN and select a 'gateway' to talk to the non-batman-adv devices on this LAN. All traffic from and to the mesh will be handled by this gateway to avoid the loop. OGMs received via the soft-interface are interpreted as 'port announcements' to locate potential batman-adv nodes. The patch can also deal with vlans on top of batX and offers a list of LAN neighbors via debugfs. Signed-off-by: Marek Lindner [sven.eckelmann@gmx.de: Rework on top of current version] Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/bat_debugfs.c | 9 + drivers/staging/batman-adv/main.c | 4 + drivers/staging/batman-adv/main.h | 2 + drivers/staging/batman-adv/originator.c | 2 + drivers/staging/batman-adv/routing.c | 12 +- drivers/staging/batman-adv/routing.h | 2 + drivers/staging/batman-adv/soft-interface.c | 296 +++++++++++++++++++++++++++- drivers/staging/batman-adv/soft-interface.h | 5 +- drivers/staging/batman-adv/types.h | 12 ++ 9 files changed, 331 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c index 57f84a9f8234..22f3eb98470f 100644 --- a/drivers/staging/batman-adv/bat_debugfs.c +++ b/drivers/staging/batman-adv/bat_debugfs.c @@ -27,6 +27,7 @@ #include "translation-table.h" #include "originator.h" #include "hard-interface.h" +#include "soft-interface.h" #include "vis.h" #include "icmp_socket.h" @@ -227,6 +228,12 @@ static int originators_open(struct inode *inode, struct file *file) return single_open(file, orig_seq_print_text, net_dev); } +static int softif_neigh_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, softif_neigh_seq_print_text, net_dev); +} + static int transtable_global_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@ -263,12 +270,14 @@ struct bat_debuginfo bat_debuginfo_##_name = { \ }; static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); +static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); static struct bat_debuginfo *mesh_debuginfos[] = { &bat_debuginfo_originators, + &bat_debuginfo_softif_neigh, &bat_debuginfo_transtable_global, &bat_debuginfo_transtable_local, &bat_debuginfo_vis_data, diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 0587940d2723..f7d6733e3d9a 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -86,9 +86,11 @@ int mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->hna_ghash_lock); spin_lock_init(&bat_priv->vis_hash_lock); spin_lock_init(&bat_priv->vis_list_lock); + spin_lock_init(&bat_priv->softif_neigh_lock); INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); + INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); if (originator_init(bat_priv) < 1) goto err; @@ -132,6 +134,8 @@ void mesh_free(struct net_device *soft_iface) hna_local_free(bat_priv); hna_global_free(bat_priv); + softif_neigh_purge(bat_priv); + atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); } diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index 5e3f51681f5e..ec35ef8920bd 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -71,6 +71,8 @@ * forw_packet->direct_link_flags */ #define MAX_AGGREGATION_MS 100 +#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ + #define RESET_PROTECTION_MS 30000 #define EXPECTED_SEQNO_RANGE 65536 /* don't reset again within 30 seconds */ diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index 55270080a44b..fc7fb31b5eda 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -28,6 +28,7 @@ #include "routing.h" #include "hard-interface.h" #include "unicast.h" +#include "soft-interface.h" static void purge_orig(struct work_struct *work); @@ -286,6 +287,7 @@ static void _purge_orig(struct bat_priv *bat_priv) spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + softif_neigh_purge(bat_priv); } static void purge_orig(struct work_struct *work) diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 750cec708244..3946c7c1b8e7 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1117,8 +1117,8 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) return 0; } -static int route_unicast_packet(struct sk_buff *skb, - struct batman_if *recv_if, int hdr_size) +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct orig_node *orig_node; @@ -1186,7 +1186,7 @@ static int route_unicast_packet(struct sk_buff *skb, return NET_RX_SUCCESS; skb = new_skb; - unicast_packet = (struct unicast_packet *) skb->data; + unicast_packet = (struct unicast_packet *)skb->data; } /* decrement ttl */ @@ -1210,7 +1210,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) /* packet for me */ if (is_my_mac(unicast_packet->dest)) { - interface_rx(recv_if->soft_iface, skb, hdr_size); + interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); return NET_RX_SUCCESS; } @@ -1242,7 +1242,7 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) if (!new_skb) return NET_RX_SUCCESS; - interface_rx(recv_if->soft_iface, new_skb, + interface_rx(recv_if->soft_iface, new_skb, recv_if, sizeof(struct unicast_packet)); return NET_RX_SUCCESS; } @@ -1324,7 +1324,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) add_bcast_packet_to_list(bat_priv, skb); /* broadcast for me */ - interface_rx(recv_if->soft_iface, skb, hdr_size); + interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); return NET_RX_SUCCESS; } diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h index 92674c8d9c03..f108f230bfdb 100644 --- a/drivers/staging/batman-adv/routing.h +++ b/drivers/staging/batman-adv/routing.h @@ -32,6 +32,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); +int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size); int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 0e996181daf7..c3313d0616cc 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -33,7 +33,9 @@ #include #include #include +#include #include "unicast.h" +#include "routing.h" static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); @@ -75,6 +77,220 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) return 0; } +static void softif_neigh_free_ref(struct kref *refcount) +{ + struct softif_neigh *softif_neigh; + + softif_neigh = container_of(refcount, struct softif_neigh, refcount); + kfree(softif_neigh); +} + +static void softif_neigh_free_rcu(struct rcu_head *rcu) +{ + struct softif_neigh *softif_neigh; + + softif_neigh = container_of(rcu, struct softif_neigh, rcu); + kref_put(&softif_neigh->refcount, softif_neigh_free_ref); +} + +void softif_neigh_purge(struct bat_priv *bat_priv) +{ + struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct hlist_node *node, *node_tmp; + unsigned long flags; + + spin_lock_irqsave(&bat_priv->softif_neigh_lock, flags); + + hlist_for_each_entry_safe(softif_neigh, node, node_tmp, + &bat_priv->softif_neigh_list, list) { + + if ((!time_after(jiffies, softif_neigh->last_seen + + msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && + (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) + continue; + + hlist_del_rcu(&softif_neigh->list); + + if (bat_priv->softif_neigh == softif_neigh) { + bat_dbg(DBG_ROUTES, bat_priv, + "Current mesh exit point '%pM' vanished " + "(vid: %d).\n", + softif_neigh->addr, softif_neigh->vid); + softif_neigh_tmp = bat_priv->softif_neigh; + bat_priv->softif_neigh = NULL; + kref_put(&softif_neigh_tmp->refcount, + softif_neigh_free_ref); + } + + call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + } + + spin_unlock_irqrestore(&bat_priv->softif_neigh_lock, flags); +} + +static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, + uint8_t *addr, short vid) +{ + struct softif_neigh *softif_neigh; + struct hlist_node *node; + unsigned long flags; + + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh, node, + &bat_priv->softif_neigh_list, list) { + if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) + continue; + + if (softif_neigh->vid != vid) + continue; + + softif_neigh->last_seen = jiffies; + goto found; + } + + softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); + if (!softif_neigh) + goto out; + + memcpy(softif_neigh->addr, addr, ETH_ALEN); + softif_neigh->vid = vid; + softif_neigh->last_seen = jiffies; + kref_init(&softif_neigh->refcount); + + INIT_HLIST_NODE(&softif_neigh->list); + spin_lock_irqsave(&bat_priv->softif_neigh_lock, flags); + hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); + spin_unlock_irqrestore(&bat_priv->softif_neigh_lock, flags); + +found: + kref_get(&softif_neigh->refcount); +out: + rcu_read_unlock(); + return softif_neigh; +} + +int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) +{ + struct net_device *net_dev = (struct net_device *)seq->private; + struct bat_priv *bat_priv = netdev_priv(net_dev); + struct softif_neigh *softif_neigh; + struct hlist_node *node; + size_t buf_size, pos; + char *buff; + + if (!bat_priv->primary_if) { + return seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + } + + seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); + + buf_size = 1; + /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh, node, + &bat_priv->softif_neigh_list, list) + buf_size += 30; + rcu_read_unlock(); + + buff = kmalloc(buf_size, GFP_ATOMIC); + if (!buff) + return -ENOMEM; + + buff[0] = '\0'; + pos = 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh, node, + &bat_priv->softif_neigh_list, list) { + pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", + bat_priv->softif_neigh == softif_neigh + ? "=>" : " ", softif_neigh->addr, + softif_neigh->vid); + } + rcu_read_unlock(); + + seq_printf(seq, "%s", buff); + kfree(buff); + return 0; +} + +static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, + short vid) +{ + struct bat_priv *bat_priv = netdev_priv(dev); + struct ethhdr *ethhdr = (struct ethhdr *)skb->data; + struct batman_packet *batman_packet; + struct softif_neigh *softif_neigh, *softif_neigh_tmp; + + if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) + batman_packet = (struct batman_packet *) + (skb->data + ETH_HLEN + VLAN_HLEN); + else + batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); + + if (batman_packet->version != COMPAT_VERSION) + goto err; + + if (batman_packet->packet_type != BAT_PACKET) + goto err; + + if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) + goto err; + + if (is_my_mac(batman_packet->orig)) + goto err; + + softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); + + if (!softif_neigh) + goto err; + + if (bat_priv->softif_neigh == softif_neigh) + goto out; + + /* we got a neighbor but its mac is 'bigger' than ours */ + if (memcmp(bat_priv->primary_if->net_dev->dev_addr, + softif_neigh->addr, ETH_ALEN) < 0) + goto out; + + /* switch to new 'smallest neighbor' */ + if ((bat_priv->softif_neigh) && + (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, + ETH_ALEN) < 0)) { + bat_dbg(DBG_ROUTES, bat_priv, + "Changing mesh exit point from %pM (vid: %d) " + "to %pM (vid: %d).\n", + bat_priv->softif_neigh->addr, + bat_priv->softif_neigh->vid, + softif_neigh->addr, softif_neigh->vid); + softif_neigh_tmp = bat_priv->softif_neigh; + bat_priv->softif_neigh = softif_neigh; + kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); + /* we need to hold the additional reference */ + goto err; + } + + /* close own batX device and use softif_neigh as exit node */ + if ((!bat_priv->softif_neigh) && + (memcmp(softif_neigh->addr, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { + bat_dbg(DBG_ROUTES, bat_priv, + "Setting mesh exit point to %pM (vid: %d).\n", + softif_neigh->addr, softif_neigh->vid); + bat_priv->softif_neigh = softif_neigh; + /* we need to hold the additional reference */ + goto err; + } + +out: + kref_put(&softif_neigh->refcount, softif_neigh_free_ref); +err: + kfree_skb(skb); + return; +} + static int interface_open(struct net_device *dev) { netif_start_queue(dev); @@ -109,7 +325,6 @@ static int interface_set_mac_addr(struct net_device *dev, void *p) } memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); - return 0; } @@ -129,13 +344,36 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bcast_packet *bcast_packet; + struct vlan_ethhdr *vhdr; int data_len = skb->len, ret; + short vid = -1; if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dropped; soft_iface->trans_start = jiffies; + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_8021Q: + vhdr = (struct vlan_ethhdr *)skb->data; + vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + + if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) + break; + + /* fall through */ + case ETH_P_BATMAN: + softif_batman_recv(skb, soft_iface, vid); + goto end; + } + + /** + * if we have a another chosen mesh exit node in range + * it will transport the packets to the mesh + */ + if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) + goto dropped; + /* TODO: check this for locks */ hna_local_add(soft_iface, ethhdr->h_source); @@ -189,16 +427,60 @@ end: } void interface_rx(struct net_device *soft_iface, - struct sk_buff *skb, int hdr_size) + struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size) { - struct bat_priv *priv = netdev_priv(soft_iface); + struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct unicast_packet *unicast_packet; + struct ethhdr *ethhdr; + struct vlan_ethhdr *vhdr; + short vid = -1; + int ret; /* check if enough space is available for pulling, and pull */ if (!pskb_may_pull(skb, hdr_size)) goto dropped; skb_pull_rcsum(skb, hdr_size); -/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/ + skb_reset_mac_header(skb); + + ethhdr = (struct ethhdr *)skb_mac_header(skb); + + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_8021Q: + vhdr = (struct vlan_ethhdr *)skb->data; + vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; + + if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) + break; + + /* fall through */ + case ETH_P_BATMAN: + goto dropped; + } + + /** + * if we have a another chosen mesh exit node in range + * it will transport the packets to the non-mesh network + */ + if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { + skb_push(skb, hdr_size); + unicast_packet = (struct unicast_packet *)skb->data; + + if ((unicast_packet->packet_type != BAT_UNICAST) && + (unicast_packet->packet_type != BAT_UNICAST_FRAG)) + goto dropped; + + skb_reset_mac_header(skb); + + memcpy(unicast_packet->dest, + bat_priv->softif_neigh->addr, ETH_ALEN); + ret = route_unicast_packet(skb, recv_if, hdr_size); + if (ret == NET_RX_DROP) + goto dropped; + + goto out; + } /* skb->dev & skb->pkt_type are set here */ if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) @@ -211,8 +493,8 @@ void interface_rx(struct net_device *soft_iface, /* skb->ip_summed = CHECKSUM_UNNECESSARY;*/ - priv->stats.rx_packets++; - priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); + bat_priv->stats.rx_packets++; + bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); soft_iface->last_rx = jiffies; @@ -221,6 +503,7 @@ void interface_rx(struct net_device *soft_iface, dropped: kfree_skb(skb); +out: return; } @@ -310,6 +593,7 @@ struct net_device *softif_create(char *name) bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0; + bat_priv->softif_neigh = NULL; ret = sysfs_add_meshif(soft_iface); if (ret < 0) diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h index 843a7ec082fe..02b77334d10d 100644 --- a/drivers/staging/batman-adv/soft-interface.h +++ b/drivers/staging/batman-adv/soft-interface.h @@ -23,9 +23,12 @@ #define _NET_BATMAN_ADV_SOFT_INTERFACE_H_ int my_skb_head_push(struct sk_buff *skb, unsigned int len); +int softif_neigh_seq_print_text(struct seq_file *seq, void *offset); +void softif_neigh_purge(struct bat_priv *bat_priv); int interface_tx(struct sk_buff *skb, struct net_device *soft_iface); void interface_rx(struct net_device *soft_iface, - struct sk_buff *skb, int hdr_size); + struct sk_buff *skb, struct batman_if *recv_if, + int hdr_size); struct net_device *softif_create(char *name); void softif_destroy(struct net_device *soft_iface); diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index 8f6ba1c56927..835d51f9a95d 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -123,6 +123,8 @@ struct bat_priv { atomic_t bcast_queue_left; atomic_t batman_queue_left; char num_ifaces; + struct hlist_head softif_neigh_list; + struct softif_neigh *softif_neigh; struct debug_log *debug_log; struct batman_if *primary_if; struct kobject *mesh_obj; @@ -141,6 +143,7 @@ struct bat_priv { spinlock_t hna_ghash_lock; /* protects hna_global_hash */ spinlock_t vis_hash_lock; /* protects vis_hash */ spinlock_t vis_list_lock; /* protects vis_info::recv_list */ + spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ int16_t num_local_hna; atomic_t hna_local_changed; struct delayed_work hna_work; @@ -239,4 +242,13 @@ struct recvlist_node { uint8_t mac[ETH_ALEN]; }; +struct softif_neigh { + struct hlist_node list; + uint8_t addr[ETH_ALEN]; + unsigned long last_seen; + short vid; + struct kref refcount; + struct rcu_head rcu; +}; + #endif /* _NET_BATMAN_ADV_TYPES_H_ */ -- cgit v1.2.3 From 641ee3f8f4375bde4e216aacd26d286a34efed61 Mon Sep 17 00:00:00 2001 From: Linus Lüssing Date: Mon, 22 Nov 2010 00:55:52 +0100 Subject: Staging: batman-adv: Unify sysfs file names with their bat_priv atomics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both sysfs entries and variable names shall be as descriptive as possible while not exceeding a certain length. This patch renames bat_priv atomics to be equally descriptive with their according sysfs entries. Unifying sysfs and bat_priv atomic names also makes it easier to find each others pendant. The reduced ("type"-)information which was previously indicated with a _enabled for booleans got substituted by a comment in bat_priv. This patch has also been done in regards for the future BAT_ATTR_* macros (they only need one name argument instead of a file and variable name). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/aggregation.c | 6 +++--- drivers/staging/batman-adv/bat_sysfs.c | 24 ++++++++++++------------ drivers/staging/batman-adv/hard-interface.c | 6 +++--- drivers/staging/batman-adv/routing.c | 4 ++-- drivers/staging/batman-adv/soft-interface.c | 6 +++--- drivers/staging/batman-adv/translation-table.c | 2 +- drivers/staging/batman-adv/types.h | 12 ++++++------ drivers/staging/batman-adv/unicast.c | 2 +- 8 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c index 08624d44e231..3dfed2f4bb5d 100644 --- a/drivers/staging/batman-adv/aggregation.c +++ b/drivers/staging/batman-adv/aggregation.c @@ -123,7 +123,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, return; } - if ((atomic_read(&bat_priv->aggregation_enabled)) && + if ((atomic_read(&bat_priv->aggregated_ogms)) && (packet_len < MAX_AGGREGATION_BYTES)) forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + sizeof(struct ethhdr)); @@ -206,7 +206,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, /* find position for the packet in the forward queue */ spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); /* own packets are not to be aggregated */ - if ((atomic_read(&bat_priv->aggregation_enabled)) && (!own_packet)) { + if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { hlist_for_each_entry(forw_packet_pos, tmp_node, &bat_priv->forw_bat_list, list) { if (can_aggregate_with(batman_packet, @@ -233,7 +233,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, * later on */ if ((!own_packet) && - (atomic_read(&bat_priv->aggregation_enabled))) + (atomic_read(&bat_priv->aggregated_ogms))) send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); new_aggregated_packet(packet_buff, packet_len, diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index 536f65120edd..a67c54c48ff4 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -41,7 +41,7 @@ static ssize_t show_aggr_ogms(struct kobject *kobj, struct attribute *attr, { struct device *dev = to_dev(kobj->parent); struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int aggr_status = atomic_read(&bat_priv->aggregation_enabled); + int aggr_status = atomic_read(&bat_priv->aggregated_ogms); return sprintf(buff, "%s\n", aggr_status == 0 ? "disabled" : "enabled"); @@ -73,15 +73,15 @@ static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr, return -EINVAL; } - if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp) + if (atomic_read(&bat_priv->aggregated_ogms) == aggr_tmp) return count; bat_info(net_dev, "Changing aggregation from: %s to: %s\n", - atomic_read(&bat_priv->aggregation_enabled) == 1 ? + atomic_read(&bat_priv->aggregated_ogms) == 1 ? "enabled" : "disabled", aggr_tmp == 1 ? "enabled" : "disabled"); - atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp); + atomic_set(&bat_priv->aggregated_ogms, (unsigned)aggr_tmp); return count; } @@ -90,7 +90,7 @@ static ssize_t show_bond(struct kobject *kobj, struct attribute *attr, { struct device *dev = to_dev(kobj->parent); struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int bond_status = atomic_read(&bat_priv->bonding_enabled); + int bond_status = atomic_read(&bat_priv->bonding); return sprintf(buff, "%s\n", bond_status == 0 ? "disabled" : "enabled"); @@ -122,15 +122,15 @@ static ssize_t store_bond(struct kobject *kobj, struct attribute *attr, return -EINVAL; } - if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp) + if (atomic_read(&bat_priv->bonding) == bonding_enabled_tmp) return count; bat_info(net_dev, "Changing bonding from: %s to: %s\n", - atomic_read(&bat_priv->bonding_enabled) == 1 ? + atomic_read(&bat_priv->bonding) == 1 ? "enabled" : "disabled", bonding_enabled_tmp == 1 ? "enabled" : "disabled"); - atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp); + atomic_set(&bat_priv->bonding, (unsigned)bonding_enabled_tmp); return count; } @@ -139,7 +139,7 @@ static ssize_t show_frag(struct kobject *kobj, struct attribute *attr, { struct device *dev = to_dev(kobj->parent); struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int frag_status = atomic_read(&bat_priv->frag_enabled); + int frag_status = atomic_read(&bat_priv->fragmentation); return sprintf(buff, "%s\n", frag_status == 0 ? "disabled" : "enabled"); @@ -171,15 +171,15 @@ static ssize_t store_frag(struct kobject *kobj, struct attribute *attr, return -EINVAL; } - if (atomic_read(&bat_priv->frag_enabled) == frag_enabled_tmp) + if (atomic_read(&bat_priv->fragmentation) == frag_enabled_tmp) return count; bat_info(net_dev, "Changing fragmentation from: %s to: %s\n", - atomic_read(&bat_priv->frag_enabled) == 1 ? + atomic_read(&bat_priv->fragmentation) == 1 ? "enabled" : "disabled", frag_enabled_tmp == 1 ? "enabled" : "disabled"); - atomic_set(&bat_priv->frag_enabled, (unsigned)frag_enabled_tmp); + atomic_set(&bat_priv->fragmentation, (unsigned)frag_enabled_tmp); update_min_mtu(net_dev); return count; } diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index c2ff29432a5e..ff0ac9825001 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -208,7 +208,7 @@ int hardif_min_mtu(struct net_device *soft_iface) * (have MTU > 1500 + BAT_HEADER_LEN) */ int min_mtu = ETH_DATA_LEN; - if (atomic_read(&bat_priv->frag_enabled)) + if (atomic_read(&bat_priv->fragmentation)) goto out; rcu_read_lock(); @@ -332,7 +332,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) bat_info(batman_if->soft_iface, "Adding interface: %s\n", batman_if->net_dev->name); - if (atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu < + if (atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(batman_if->soft_iface, "The MTU of interface %s is too small (%i) to handle " @@ -343,7 +343,7 @@ int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) batman_if->net_dev->name, batman_if->net_dev->mtu, ETH_DATA_LEN + BAT_HEADER_LEN); - if (!atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu < + if (!atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < ETH_DATA_LEN + BAT_HEADER_LEN) bat_info(batman_if->soft_iface, "The MTU of interface %s is too small (%i) to handle " diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 3946c7c1b8e7..1b3548634904 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -1019,7 +1019,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, /* without bonding, the first node should * always choose the default router. */ - bonding_enabled = atomic_read(&bat_priv->bonding_enabled); + bonding_enabled = atomic_read(&bat_priv->bonding); if ((!recv_if) && (!bonding_enabled)) return orig_node->router; @@ -1168,7 +1168,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, unicast_packet = (struct unicast_packet *)skb->data; if (unicast_packet->packet_type == BAT_UNICAST && - atomic_read(&bat_priv->frag_enabled) && + atomic_read(&bat_priv->fragmentation) && skb->len > batman_if->net_dev->mtu) return frag_send_skb(skb, bat_priv, batman_if, dstaddr); diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index c3313d0616cc..c903a76ad0e2 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -578,12 +578,12 @@ struct net_device *softif_create(char *name) bat_priv = netdev_priv(soft_iface); - atomic_set(&bat_priv->aggregation_enabled, 1); - atomic_set(&bat_priv->bonding_enabled, 0); + atomic_set(&bat_priv->aggregated_ogms, 1); + atomic_set(&bat_priv->bonding, 0); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); atomic_set(&bat_priv->orig_interval, 1000); atomic_set(&bat_priv->log_level, 0); - atomic_set(&bat_priv->frag_enabled, 1); + atomic_set(&bat_priv->fragmentation, 1); atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN); diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c index 681ccbda3eac..3bc752111638 100644 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@ -79,7 +79,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) required_bytes += BAT_PACKET_LEN; if ((required_bytes > ETH_DATA_LEN) || - (atomic_read(&bat_priv->aggregation_enabled) && + (atomic_read(&bat_priv->aggregated_ogms) && required_bytes > MAX_AGGREGATION_BYTES) || (bat_priv->num_local_hna + 1 > 255)) { bat_dbg(DBG_ROUTES, bat_priv, diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index 835d51f9a95d..4463da391498 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -113,12 +113,12 @@ struct neigh_node { struct bat_priv { atomic_t mesh_state; struct net_device_stats stats; - atomic_t aggregation_enabled; - atomic_t bonding_enabled; - atomic_t frag_enabled; - atomic_t vis_mode; - atomic_t orig_interval; - atomic_t log_level; + atomic_t aggregated_ogms; /* boolean */ + atomic_t bonding; /* boolean */ + atomic_t fragmentation; /* boolean */ + atomic_t vis_mode; /* VIS_TYPE_* */ + atomic_t orig_interval; /* uint */ + atomic_t log_level; /* uint */ atomic_t bcast_seqno; atomic_t bcast_queue_left; atomic_t batman_queue_left; diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index e58e634c2806..5ae959327b48 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -318,7 +318,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* copy the destination for faster routing */ memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); - if (atomic_read(&bat_priv->frag_enabled) && + if (atomic_read(&bat_priv->fragmentation) && data_len + sizeof(struct unicast_packet) > batman_if->net_dev->mtu) { /* send frag skb decreases ttl */ -- cgit v1.2.3 From add9e1722755072f40d79104db04e350b25624d9 Mon Sep 17 00:00:00 2001 From: Linus Lüssing Date: Mon, 22 Nov 2010 00:55:53 +0100 Subject: Staging: batman-adv: Wrapper functions for sysfs storing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sysfs configuration options that just took a boolean value (enable(d)/disable(d)/0/1) and integer setting basically all had the same structure. To avoid even more copy and pasting in the future and to make introducing new configuration parameters for batman-adv simpler, more generic wrapper functions are being introduced with this commit. They can deal with boolean and unsigned integer parameters, storing them in the specified atomic_t variables. Signed-off-by: Linus Lüssing Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/bat_sysfs.c | 333 +++++++++++++-------------------- 1 file changed, 130 insertions(+), 203 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index a67c54c48ff4..19be53174bc6 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -28,6 +28,7 @@ #define to_dev(obj) container_of(obj, struct device, kobj) +/* Use this, if you have customized show and store functions */ #define BAT_ATTR(_name, _mode, _show, _store) \ struct bat_attribute bat_attr_##_name = { \ .attr = {.name = __stringify(_name), \ @@ -36,152 +37,168 @@ struct bat_attribute bat_attr_##_name = { \ .store = _store, \ }; -static ssize_t show_aggr_ogms(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int aggr_status = atomic_read(&bat_priv->aggregated_ogms); +#define BAT_ATTR_STORE_BOOL(_name, _post_func) \ +ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff, size_t count) \ +{ \ + struct device *dev = to_dev(kobj->parent); \ + struct net_device *net_dev = to_net_dev(dev); \ + struct bat_priv *bat_priv = netdev_priv(net_dev); \ + return __store_bool_attr(buff, count, _post_func, attr, \ + &bat_priv->_name, net_dev); \ +} - return sprintf(buff, "%s\n", - aggr_status == 0 ? "disabled" : "enabled"); +#define BAT_ATTR_SHOW_BOOL(_name) \ +ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff) \ +{ \ + struct device *dev = to_dev(kobj->parent); \ + struct net_device *net_dev = to_net_dev(dev); \ + struct bat_priv *bat_priv = netdev_priv(net_dev); \ + return sprintf(buff, "%s\n", \ + atomic_read(&bat_priv->_name) == 0 ? \ + "disabled" : "enabled"); \ +} \ + +/* Use this, if you are going to turn a [name] in bat_priv on or off */ +#define BAT_ATTR_BOOL(_name, _mode, _post_func) \ + static BAT_ATTR_STORE_BOOL(_name, _post_func) \ + static BAT_ATTR_SHOW_BOOL(_name) \ + static BAT_ATTR(_name, _mode, show_##_name, store_##_name) + + +#define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ +ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff, size_t count) \ +{ \ + struct device *dev = to_dev(kobj->parent); \ + struct net_device *net_dev = to_net_dev(dev); \ + struct bat_priv *bat_priv = netdev_priv(net_dev); \ + return __store_uint_attr(buff, count, _min, _max, _post_func, \ + attr, &bat_priv->_name, net_dev); \ } -static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) +#define BAT_ATTR_SHOW_UINT(_name) \ +ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ + char *buff) \ +{ \ + struct device *dev = to_dev(kobj->parent); \ + struct net_device *net_dev = to_net_dev(dev); \ + struct bat_priv *bat_priv = netdev_priv(net_dev); \ + return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ +} \ + +/* Use this, if you are going to set [name] in bat_priv to unsigned integer + * values only */ +#define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ + static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ + static BAT_ATTR_SHOW_UINT(_name) \ + static BAT_ATTR(_name, _mode, show_##_name, store_##_name) + + +static int store_bool_attr(char *buff, size_t count, + struct net_device *net_dev, + char *attr_name, atomic_t *attr) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - int aggr_tmp = -1; + int enabled = -1; - if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - aggr_tmp = 1; + if (buff[count - 1] == '\n') + buff[count - 1] = '\0'; - if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - aggr_tmp = 0; + if ((strncmp(buff, "1", 2) == 0) || + (strncmp(buff, "enable", 7) == 0) || + (strncmp(buff, "enabled", 8) == 0)) + enabled = 1; - if (aggr_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; + if ((strncmp(buff, "0", 2) == 0) || + (strncmp(buff, "disable", 8) == 0) || + (strncmp(buff, "disabled", 9) == 0)) + enabled = 0; + if (enabled < 0) { bat_info(net_dev, - "Invalid parameter for 'aggregate OGM' setting" - "received: %s\n", buff); + "%s: Invalid parameter received: %s\n", + attr_name, buff); return -EINVAL; } - if (atomic_read(&bat_priv->aggregated_ogms) == aggr_tmp) + if (atomic_read(attr) == enabled) return count; - bat_info(net_dev, "Changing aggregation from: %s to: %s\n", - atomic_read(&bat_priv->aggregated_ogms) == 1 ? - "enabled" : "disabled", aggr_tmp == 1 ? "enabled" : - "disabled"); + bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, + atomic_read(attr) == 1 ? "enabled" : "disabled", + enabled == 1 ? "enabled" : "disabled"); - atomic_set(&bat_priv->aggregated_ogms, (unsigned)aggr_tmp); + atomic_set(attr, (unsigned)enabled); return count; } -static ssize_t show_bond(struct kobject *kobj, struct attribute *attr, - char *buff) +static inline ssize_t __store_bool_attr(char *buff, size_t count, + void (*post_func)(struct net_device *), + struct attribute *attr, + atomic_t *attr_store, struct net_device *net_dev) { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int bond_status = atomic_read(&bat_priv->bonding); + int ret; - return sprintf(buff, "%s\n", - bond_status == 0 ? "disabled" : "enabled"); + ret = store_bool_attr(buff, count, net_dev, (char *)attr->name, + attr_store); + if (post_func && ret) + post_func(net_dev); + + return ret; } -static ssize_t store_bond(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) +static int store_uint_attr(char *buff, size_t count, + struct net_device *net_dev, char *attr_name, + unsigned int min, unsigned int max, atomic_t *attr) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - int bonding_enabled_tmp = -1; - - if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - bonding_enabled_tmp = 1; + unsigned long uint_val; + int ret; - if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - bonding_enabled_tmp = 0; + ret = strict_strtoul(buff, 10, &uint_val); + if (ret) { + bat_info(net_dev, + "%s: Invalid parameter received: %s\n", + attr_name, buff); + return -EINVAL; + } - if (bonding_enabled_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; + if (uint_val < min) { + bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", + attr_name, uint_val, min); + return -EINVAL; + } - bat_err(net_dev, - "Invalid parameter for 'bonding' setting received: " - "%s\n", buff); + if (uint_val > max) { + bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", + attr_name, uint_val, max); return -EINVAL; } - if (atomic_read(&bat_priv->bonding) == bonding_enabled_tmp) + if (atomic_read(attr) == uint_val) return count; - bat_info(net_dev, "Changing bonding from: %s to: %s\n", - atomic_read(&bat_priv->bonding) == 1 ? - "enabled" : "disabled", - bonding_enabled_tmp == 1 ? "enabled" : "disabled"); + bat_info(net_dev, "%s: Changing from: %i to: %lu\n", + attr_name, atomic_read(attr), uint_val); - atomic_set(&bat_priv->bonding, (unsigned)bonding_enabled_tmp); + atomic_set(attr, uint_val); return count; } -static ssize_t show_frag(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int frag_status = atomic_read(&bat_priv->fragmentation); - - return sprintf(buff, "%s\n", - frag_status == 0 ? "disabled" : "enabled"); -} - -static ssize_t store_frag(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) +static inline ssize_t __store_uint_attr(char *buff, size_t count, + int min, int max, + void (*post_func)(struct net_device *), + struct attribute *attr, + atomic_t *attr_store, struct net_device *net_dev) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - int frag_enabled_tmp = -1; - - if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - frag_enabled_tmp = 1; - - if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - frag_enabled_tmp = 0; - - if (frag_enabled_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - bat_err(net_dev, - "Invalid parameter for 'fragmentation' setting on mesh" - "received: %s\n", buff); - return -EINVAL; - } - - if (atomic_read(&bat_priv->fragmentation) == frag_enabled_tmp) - return count; + int ret; - bat_info(net_dev, "Changing fragmentation from: %s to: %s\n", - atomic_read(&bat_priv->fragmentation) == 1 ? - "enabled" : "disabled", - frag_enabled_tmp == 1 ? "enabled" : "disabled"); + ret = store_uint_attr(buff, count, net_dev, (char *)attr->name, + min, max, attr_store); + if (post_func && ret) + post_func(net_dev); - atomic_set(&bat_priv->fragmentation, (unsigned)frag_enabled_tmp); - update_min_mtu(net_dev); - return count; + return ret; } static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, @@ -238,103 +255,13 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, return count; } -static ssize_t show_orig_interval(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buff, "%i\n", - atomic_read(&bat_priv->orig_interval)); -} - -static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - unsigned long orig_interval_tmp; - int ret; - - ret = strict_strtoul(buff, 10, &orig_interval_tmp); - if (ret) { - bat_info(net_dev, "Invalid parameter for 'orig_interval' " - "setting received: %s\n", buff); - return -EINVAL; - } - - if (orig_interval_tmp < JITTER * 2) { - bat_info(net_dev, "New originator interval too small: %li " - "(min: %i)\n", orig_interval_tmp, JITTER * 2); - return -EINVAL; - } - - if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp) - return count; - - bat_info(net_dev, "Changing originator interval from: %i to: %li\n", - atomic_read(&bat_priv->orig_interval), - orig_interval_tmp); - - atomic_set(&bat_priv->orig_interval, orig_interval_tmp); - return count; -} - -#ifdef CONFIG_BATMAN_ADV_DEBUG -static ssize_t show_log_level(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int log_level = atomic_read(&bat_priv->log_level); - - return sprintf(buff, "%d\n", log_level); -} - -static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - struct bat_priv *bat_priv = netdev_priv(net_dev); - unsigned long log_level_tmp; - int ret; - - ret = strict_strtoul(buff, 10, &log_level_tmp); - if (ret) { - bat_info(net_dev, "Invalid parameter for 'log_level' " - "setting received: %s\n", buff); - return -EINVAL; - } - - if (log_level_tmp > 3) { - bat_info(net_dev, "New log level too big: %li " - "(max: %i)\n", log_level_tmp, 3); - return -EINVAL; - } - - if (atomic_read(&bat_priv->log_level) == log_level_tmp) - return count; - - bat_info(net_dev, "Changing log level from: %i to: %li\n", - atomic_read(&bat_priv->log_level), - log_level_tmp); - - atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp); - return count; -} -#endif - -static BAT_ATTR(aggregated_ogms, S_IRUGO | S_IWUSR, - show_aggr_ogms, store_aggr_ogms); -static BAT_ATTR(bonding, S_IRUGO | S_IWUSR, show_bond, store_bond); -static BAT_ATTR(fragmentation, S_IRUGO | S_IWUSR, show_frag, store_frag); +BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); +BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); +BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); -static BAT_ATTR(orig_interval, S_IRUGO | S_IWUSR, - show_orig_interval, store_orig_interval); +BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); #ifdef CONFIG_BATMAN_ADV_DEBUG -static BAT_ATTR(log_level, S_IRUGO | S_IWUSR, show_log_level, store_log_level); +BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); #endif static struct bat_attribute *mesh_attrs[] = { -- cgit v1.2.3 From 1623948f879069b33d07986aa95e3b9969322ff4 Mon Sep 17 00:00:00 2001 From: Linus Lüssing Date: Mon, 22 Nov 2010 00:55:54 +0100 Subject: Staging: batman-adv: Ommit storing struct device in sysfs functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We actually do not need an extra struct device variable, therefore replacing them with defines that directly get the bat_priv or net_device. This further reduces the code size in bat_sysfs.c and especially shortens some macros. Signed-off-by: Linus Lüssing Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/bat_sysfs.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index 19be53174bc6..9bec60de42ba 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -26,7 +26,9 @@ #include "hard-interface.h" #include "vis.h" -#define to_dev(obj) container_of(obj, struct device, kobj) +#define to_dev(obj) container_of(obj, struct device, kobj) +#define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent)) +#define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj)) /* Use this, if you have customized show and store functions */ #define BAT_ATTR(_name, _mode, _show, _store) \ @@ -41,8 +43,7 @@ struct bat_attribute bat_attr_##_name = { \ ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ char *buff, size_t count) \ { \ - struct device *dev = to_dev(kobj->parent); \ - struct net_device *net_dev = to_net_dev(dev); \ + struct net_device *net_dev = kobj_to_netdev(kobj); \ struct bat_priv *bat_priv = netdev_priv(net_dev); \ return __store_bool_attr(buff, count, _post_func, attr, \ &bat_priv->_name, net_dev); \ @@ -52,9 +53,7 @@ ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ char *buff) \ { \ - struct device *dev = to_dev(kobj->parent); \ - struct net_device *net_dev = to_net_dev(dev); \ - struct bat_priv *bat_priv = netdev_priv(net_dev); \ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ return sprintf(buff, "%s\n", \ atomic_read(&bat_priv->_name) == 0 ? \ "disabled" : "enabled"); \ @@ -71,8 +70,7 @@ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ char *buff, size_t count) \ { \ - struct device *dev = to_dev(kobj->parent); \ - struct net_device *net_dev = to_net_dev(dev); \ + struct net_device *net_dev = kobj_to_netdev(kobj); \ struct bat_priv *bat_priv = netdev_priv(net_dev); \ return __store_uint_attr(buff, count, _min, _max, _post_func, \ attr, &bat_priv->_name, net_dev); \ @@ -82,9 +80,7 @@ ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ char *buff) \ { \ - struct device *dev = to_dev(kobj->parent); \ - struct net_device *net_dev = to_net_dev(dev); \ - struct bat_priv *bat_priv = netdev_priv(net_dev); \ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ } \ @@ -204,8 +200,7 @@ static inline ssize_t __store_uint_attr(char *buff, size_t count, static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, char *buff) { - struct device *dev = to_dev(kobj->parent); - struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); int vis_mode = atomic_read(&bat_priv->vis_mode); return sprintf(buff, "%s\n", @@ -216,8 +211,7 @@ static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); + struct net_device *net_dev = kobj_to_netdev(kobj); struct bat_priv *bat_priv = netdev_priv(net_dev); unsigned long val; int ret, vis_mode_tmp = -1; @@ -329,8 +323,7 @@ void sysfs_del_meshif(struct net_device *dev) static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, char *buff) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); + struct net_device *net_dev = kobj_to_netdev(kobj); struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); ssize_t length; @@ -348,8 +341,7 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); + struct net_device *net_dev = kobj_to_netdev(kobj); struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); int status_tmp = -1; int ret; @@ -402,8 +394,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, char *buff) { - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); + struct net_device *net_dev = kobj_to_netdev(kobj); struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); ssize_t length; -- cgit v1.2.3 From 1341a00ad356dfb21978ce4e5e979024558042d2 Mon Sep 17 00:00:00 2001 From: Linus Lüssing Date: Mon, 22 Nov 2010 00:55:55 +0100 Subject: Staging: batman-adv: Make hop_penalty configurable via sysfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When having a mixed topology of both very mobile and rather static nodes, you are usually best advised to set the originator interval on all nodes to a level best suited for the most mobile node. However, if most of the nodes are rather static, this can create a lot of undesired overhead as a trade-off then. If setting the interval too low on the static nodes, a mobile node might be chosen as a router for too long, not switching away from it fast enough because of its mobility and the low frequency of ogms of static nodes. Exposing the hop_penalty is especially useful for the stated scenario: A static node can keep the default originator interval, a mobile node can select a quicker one resulting in faster route updates towards this mobile node. Additionally, such a mobile node could select a higher hop penalty (or even set it to 255 to disable acting as a router for other nodes) to make it less desirable, letting other nodes avoid selecting this mobile node as a router. Signed-off-by: Linus Lüssing Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/bat_sysfs.c | 2 ++ drivers/staging/batman-adv/main.h | 2 -- drivers/staging/batman-adv/send.c | 7 ++++--- drivers/staging/batman-adv/soft-interface.c | 1 + drivers/staging/batman-adv/sysfs-class-net-mesh | 7 +++++++ drivers/staging/batman-adv/types.h | 1 + 6 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index 9bec60de42ba..5ff6e5e6a1e2 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -254,6 +254,7 @@ BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); +BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); #ifdef CONFIG_BATMAN_ADV_DEBUG BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); #endif @@ -264,6 +265,7 @@ static struct bat_attribute *mesh_attrs[] = { &bat_attr_fragmentation, &bat_attr_vis_mode, &bat_attr_orig_interval, + &bat_attr_hop_penalty, #ifdef CONFIG_BATMAN_ADV_DEBUG &bat_attr_log_level, #endif diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index ec35ef8920bd..d8d50f35610a 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -52,8 +52,6 @@ #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 #define TQ_TOTAL_BIDRECT_LIMIT 1 -#define TQ_HOP_PENALTY 10 - #define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) #define PACKBUFF_SIZE 2000 diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index 7adf76ddd0ba..1489b6c760f6 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -33,9 +33,10 @@ static void send_outstanding_bcast_packet(struct work_struct *work); /* apply hop penalty for a normal link */ -static uint8_t hop_penalty(const uint8_t tq) +static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) { - return (tq * (TQ_MAX_VALUE - TQ_HOP_PENALTY)) / (TQ_MAX_VALUE); + int hop_penalty = atomic_read(&bat_priv->hop_penalty); + return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); } /* when do we schedule our own packet to be sent */ @@ -330,7 +331,7 @@ void schedule_forward_packet(struct orig_node *orig_node, } /* apply hop penalty */ - batman_packet->tq = hop_penalty(batman_packet->tq); + batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: tq_orig: %i, tq_avg: %i, " diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index c903a76ad0e2..1cf9aa21a408 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -582,6 +582,7 @@ struct net_device *softif_create(char *name) atomic_set(&bat_priv->bonding, 0); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); atomic_set(&bat_priv->orig_interval, 1000); + atomic_set(&bat_priv->hop_penalty, 10); atomic_set(&bat_priv->log_level, 0); atomic_set(&bat_priv->fragmentation, 1); atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); diff --git a/drivers/staging/batman-adv/sysfs-class-net-mesh b/drivers/staging/batman-adv/sysfs-class-net-mesh index b4cdb6038bf1..bd20e14261c0 100644 --- a/drivers/staging/batman-adv/sysfs-class-net-mesh +++ b/drivers/staging/batman-adv/sysfs-class-net-mesh @@ -29,6 +29,13 @@ Description: Defines the interval in milliseconds in which batman sends its protocol messages. +What: /sys/class/net//mesh/hop_penalty +Date: Oct 2010 +Contact: Linus Lüssing +Description: + Defines the penalty which will be applied to an + originator message's tq-field on every hop. + What: /sys/class/net//mesh/vis_mode Date: May 2010 Contact: Marek Lindner diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index 4463da391498..e41f95fbf61f 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -118,6 +118,7 @@ struct bat_priv { atomic_t fragmentation; /* boolean */ atomic_t vis_mode; /* VIS_TYPE_* */ atomic_t orig_interval; /* uint */ + atomic_t hop_penalty; /* uint */ atomic_t log_level; /* uint */ atomic_t bcast_seqno; atomic_t bcast_queue_left; -- cgit v1.2.3 From 51f3d8a27c1a1ac6aced25ea93fc5c0520e9256c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:56 +0100 Subject: Staging: batman-adv: Remove hashdata_compare_cb from hash Function pointers cannot be inlined by a compiler and thus always has the overhead of an call. hashdata_compare_cb's are one of the most often called function pointers and its overhead must kept relative low. As first step, every function which uses this function pointer takes it as parameter instead of storing it inside the hash abstraction structure. This not generate any performance gain right now. The called functions must also be able to be inlined by the calling functions to enable inlining of the function pointer. Reported-by: David S. Miller Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/TODO | 2 +- drivers/staging/batman-adv/hash.c | 25 +++++++++-------- drivers/staging/batman-adv/hash.h | 23 +++++++-------- drivers/staging/batman-adv/icmp_socket.c | 2 ++ drivers/staging/batman-adv/main.c | 7 ----- drivers/staging/batman-adv/main.h | 1 - drivers/staging/batman-adv/originator.c | 9 +++--- drivers/staging/batman-adv/originator.h | 7 +++++ drivers/staging/batman-adv/routing.c | 15 ++++++---- drivers/staging/batman-adv/send.c | 1 + drivers/staging/batman-adv/translation-table.c | 39 ++++++++++++++++---------- drivers/staging/batman-adv/unicast.c | 5 +++- drivers/staging/batman-adv/vis.c | 15 ++++++---- 13 files changed, 89 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO index 7967ffaa833e..a9c77d671a5a 100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@ -1,6 +1,6 @@ * remove own list functionality from hash * use hlist_head, hlist_node in hash - * don't use callbacks for compare+choose in hash + * don't use callbacks for choose in hash * think about more efficient ways instead of abstraction of hash * Request a new review * Process the comments from the review diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c index 8ef26eb4949d..a4abe140a953 100644 --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@ -137,8 +137,7 @@ struct hash_it_t *hash_iterate(struct hashtable_t *hash, } /* allocates and clears the hash */ -struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, - hashdata_choose_cb choose) +struct hashtable_t *hash_new(int size, hashdata_choose_cb choose) { struct hashtable_t *hash; @@ -157,14 +156,13 @@ struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, hash_init(hash); - hash->compare = compare; hash->choose = choose; return hash; } /* adds data to the hashtable. returns 0 on success, -1 on error */ -int hash_add(struct hashtable_t *hash, void *data) +int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, void *data) { int index; struct element_t *bucket, *prev_bucket = NULL; @@ -176,7 +174,7 @@ int hash_add(struct hashtable_t *hash, void *data) bucket = hash->table[index]; while (bucket != NULL) { - if (hash->compare(bucket->data, data)) + if (compare(bucket->data, data)) return -1; prev_bucket = bucket; @@ -204,7 +202,8 @@ int hash_add(struct hashtable_t *hash, void *data) /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ -void *hash_find(struct hashtable_t *hash, void *keydata) +void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, + void *keydata) { int index; struct element_t *bucket; @@ -216,7 +215,7 @@ void *hash_find(struct hashtable_t *hash, void *keydata) bucket = hash->table[index]; while (bucket != NULL) { - if (hash->compare(bucket->data, keydata)) + if (compare(bucket->data, keydata)) return bucket->data; bucket = bucket->next; @@ -250,7 +249,8 @@ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) * can remove the used structure yourself, or NULL on error . data could be the * structure you use with just the key filled, we just need the key for * comparing. */ -void *hash_remove(struct hashtable_t *hash, void *data) +void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, + void *data) { struct hash_it_t hash_it_t; @@ -259,7 +259,7 @@ void *hash_remove(struct hashtable_t *hash, void *data) hash_it_t.prev_bucket = NULL; while (hash_it_t.bucket != NULL) { - if (hash->compare(hash_it_t.bucket->data, data)) { + if (compare(hash_it_t.bucket->data, data)) { hash_it_t.first_bucket = (hash_it_t.bucket == hash->table[hash_it_t.index] ? @@ -276,14 +276,15 @@ void *hash_remove(struct hashtable_t *hash, void *data) /* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success. */ -struct hashtable_t *hash_resize(struct hashtable_t *hash, int size) +struct hashtable_t *hash_resize(struct hashtable_t *hash, + hashdata_compare_cb compare, int size) { struct hashtable_t *new_hash; struct element_t *bucket; int i; /* initialize a new hash with the new size */ - new_hash = hash_new(size, hash->compare, hash->choose); + new_hash = hash_new(size, hash->choose); if (new_hash == NULL) return NULL; @@ -293,7 +294,7 @@ struct hashtable_t *hash_resize(struct hashtable_t *hash, int size) bucket = hash->table[i]; while (bucket != NULL) { - hash_add(new_hash, bucket->data); + hash_add(new_hash, compare, bucket->data); bucket = bucket->next; } } diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h index 2c8e1762389f..742277ea980b 100644 --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@ -27,7 +27,10 @@ .prev_bucket = NULL, \ .first_bucket = NULL } - +/* callback to a compare function. should + * compare 2 element datas for their keys, + * return 0 if same and not 0 if not + * same */ typedef int (*hashdata_compare_cb)(void *, void *); typedef int (*hashdata_choose_cb)(void *, int); typedef void (*hashdata_free_cb)(void *, void *); @@ -48,18 +51,13 @@ struct hashtable_t { struct element_t **table; /* the hashtable itself, with the buckets */ int elements; /* number of elements registered */ int size; /* size of hashtable */ - hashdata_compare_cb compare;/* callback to a compare function. should - * compare 2 element datas for their keys, - * return 0 if same and not 0 if not - * same */ hashdata_choose_cb choose; /* the hashfunction, should return an index * based on the key in the data of the first * argument and the size the second */ }; /* allocates and clears the hash */ -struct hashtable_t *hash_new(int size, hashdata_compare_cb compare, - hashdata_choose_cb choose); +struct hashtable_t *hash_new(int size, hashdata_choose_cb choose); /* remove bucket (this might be used in hash_iterate() if you already found the * bucket you want to delete and don't need the overhead to find it again with @@ -76,21 +74,24 @@ void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg); void hash_destroy(struct hashtable_t *hash); /* adds data to the hashtable. returns 0 on success, -1 on error */ -int hash_add(struct hashtable_t *hash, void *data); +int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, void *data); /* removes data from hash, if found. returns pointer do data on success, so you * can remove the used structure yourself, or NULL on error . data could be the * structure you use with just the key filled, we just need the key for * comparing. */ -void *hash_remove(struct hashtable_t *hash, void *data); +void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, + void *data); /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ -void *hash_find(struct hashtable_t *hash, void *keydata); +void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, + void *keydata); /* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success */ -struct hashtable_t *hash_resize(struct hashtable_t *hash, int size); +struct hashtable_t *hash_resize(struct hashtable_t *hash, + hashdata_compare_cb compare, int size); /* iterate though the hash. first element is selected with iter_in NULL. use * the returned iterator to access the elements until hash_it_t returns NULL. */ diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c index 48856ca73b6a..a7b98ce295f9 100644 --- a/drivers/staging/batman-adv/icmp_socket.c +++ b/drivers/staging/batman-adv/icmp_socket.c @@ -26,6 +26,7 @@ #include "send.h" #include "types.h" #include "hash.h" +#include "originator.h" #include "hard-interface.h" @@ -225,6 +226,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, icmp_packet->dst)); if (!orig_node) diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index f7d6733e3d9a..2ed77dd88509 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -149,13 +149,6 @@ void dec_module_count(void) module_put(THIS_MODULE); } -/* returns 1 if they are the same originator */ - -int compare_orig(void *data1, void *data2) -{ - return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); -} - /* hashfunction to choose an entry in a hash table of given size */ /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ int choose_orig(void *data, int32_t size) diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index d8d50f35610a..97a74b047c57 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -135,7 +135,6 @@ int mesh_init(struct net_device *soft_iface); void mesh_free(struct net_device *soft_iface); void inc_module_count(void); void dec_module_count(void); -int compare_orig(void *data1, void *data2); int choose_orig(void *data, int32_t size); int is_my_mac(uint8_t *addr); int is_bcast(uint8_t *addr); diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index fc7fb31b5eda..7735b7fcf157 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -45,7 +45,7 @@ int originator_init(struct bat_priv *bat_priv) return 1; spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); - bat_priv->orig_hash = hash_new(128, compare_orig, choose_orig); + bat_priv->orig_hash = hash_new(128, choose_orig); if (!bat_priv->orig_hash) goto err; @@ -129,7 +129,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) struct hashtable_t *swaphash; int size; - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, addr)); + orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, addr)); if (orig_node) return orig_node; @@ -166,11 +167,11 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) if (!orig_node->bcast_own_sum) goto free_bcast_own; - if (hash_add(bat_priv->orig_hash, orig_node) < 0) + if (hash_add(bat_priv->orig_hash, compare_orig, orig_node) < 0) goto free_bcast_own_sum; if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) { - swaphash = hash_resize(bat_priv->orig_hash, + swaphash = hash_resize(bat_priv->orig_hash, compare_orig, bat_priv->orig_hash->size * 2); if (!swaphash) diff --git a/drivers/staging/batman-adv/originator.h b/drivers/staging/batman-adv/originator.h index a97c4004776a..ed903dcaa35c 100644 --- a/drivers/staging/batman-adv/originator.h +++ b/drivers/staging/batman-adv/originator.h @@ -33,4 +33,11 @@ int orig_seq_print_text(struct seq_file *seq, void *offset); int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); + +/* returns 1 if they are the same originator */ +static inline int compare_orig(void *data1, void *data2) +{ + return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); +} + #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 1b3548634904..bb0bd7871959 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -811,6 +811,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, icmp_packet->orig)); ret = NET_RX_DROP; @@ -873,7 +874,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, icmp_packet->orig)); + hash_find(bat_priv->orig_hash, compare_orig, + icmp_packet->orig)); ret = NET_RX_DROP; if ((orig_node != NULL) && @@ -967,7 +969,8 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, icmp_packet->dst)); + hash_find(bat_priv->orig_hash, compare_orig, + icmp_packet->dst)); if ((orig_node != NULL) && (orig_node->router != NULL)) { @@ -1038,7 +1041,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, router_orig->orig, ETH_ALEN) == 0) { primary_orig_node = router_orig; } else { - primary_orig_node = hash_find(bat_priv->orig_hash, + primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, router_orig->primary_addr); if (!primary_orig_node) @@ -1144,7 +1147,8 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, unicast_packet->dest)); + hash_find(bat_priv->orig_hash, compare_orig, + unicast_packet->dest)); router = find_router(bat_priv, orig_node, recv_if); @@ -1290,7 +1294,8 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, bcast_packet->orig)); + hash_find(bat_priv->orig_hash, compare_orig, + bcast_packet->orig)); if (orig_node == NULL) { spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index 1489b6c760f6..1840ef0e3755 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -28,6 +28,7 @@ #include "types.h" #include "vis.h" #include "aggregation.h" +#include "originator.h" static void send_outstanding_bcast_packet(struct work_struct *work); diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c index 3bc752111638..33cd5daa414c 100644 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@ -24,6 +24,7 @@ #include "soft-interface.h" #include "types.h" #include "hash.h" +#include "originator.h" static void hna_local_purge(struct work_struct *work); static void _hna_global_del_orig(struct bat_priv *bat_priv, @@ -41,7 +42,7 @@ int hna_local_init(struct bat_priv *bat_priv) if (bat_priv->hna_local_hash) return 1; - bat_priv->hna_local_hash = hash_new(128, compare_orig, choose_orig); + bat_priv->hna_local_hash = hash_new(128, choose_orig); if (!bat_priv->hna_local_hash) return 0; @@ -64,7 +65,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hna_local_entry = ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, - addr)); + compare_orig, addr)); spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); if (hna_local_entry) { @@ -107,13 +108,13 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); - hash_add(bat_priv->hna_local_hash, hna_local_entry); + hash_add(bat_priv->hna_local_hash, compare_orig, hna_local_entry); bat_priv->num_local_hna++; atomic_set(&bat_priv->hna_local_changed, 1); if (bat_priv->hna_local_hash->elements * 4 > bat_priv->hna_local_hash->size) { - swaphash = hash_resize(bat_priv->hna_local_hash, + swaphash = hash_resize(bat_priv->hna_local_hash, compare_orig, bat_priv->hna_local_hash->size * 2); if (!swaphash) @@ -128,7 +129,8 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hna_global_entry = ((struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, addr)); + hash_find(bat_priv->hna_global_hash, + compare_orig, addr)); if (hna_global_entry) _hna_global_del_orig(bat_priv, hna_global_entry, @@ -232,7 +234,8 @@ static void hna_local_del(struct bat_priv *bat_priv, bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", hna_local_entry->addr, message); - hash_remove(bat_priv->hna_local_hash, hna_local_entry->addr); + hash_remove(bat_priv->hna_local_hash, compare_orig, + hna_local_entry->addr); _hna_local_del(hna_local_entry, bat_priv); } @@ -245,7 +248,7 @@ void hna_local_remove(struct bat_priv *bat_priv, spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, addr); + hash_find(bat_priv->hna_local_hash, compare_orig, addr); if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, message); @@ -295,7 +298,7 @@ int hna_global_init(struct bat_priv *bat_priv) if (bat_priv->hna_global_hash) return 1; - bat_priv->hna_global_hash = hash_new(128, compare_orig, choose_orig); + bat_priv->hna_global_hash = hash_new(128, choose_orig); if (!bat_priv->hna_global_hash) return 0; @@ -319,7 +322,8 @@ void hna_global_add_orig(struct bat_priv *bat_priv, hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, hna_ptr); + hash_find(bat_priv->hna_global_hash, compare_orig, + hna_ptr); if (!hna_global_entry) { spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, @@ -340,7 +344,8 @@ void hna_global_add_orig(struct bat_priv *bat_priv, hna_global_entry->addr, orig_node->orig); spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); - hash_add(bat_priv->hna_global_hash, hna_global_entry); + hash_add(bat_priv->hna_global_hash, compare_orig, + hna_global_entry); } @@ -352,7 +357,8 @@ void hna_global_add_orig(struct bat_priv *bat_priv, hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, hna_ptr); + hash_find(bat_priv->hna_local_hash, compare_orig, + hna_ptr); if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, @@ -379,7 +385,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, if (bat_priv->hna_global_hash->elements * 4 > bat_priv->hna_global_hash->size) { - swaphash = hash_resize(bat_priv->hna_global_hash, + swaphash = hash_resize(bat_priv->hna_global_hash, compare_orig, bat_priv->hna_global_hash->size * 2); if (!swaphash) @@ -450,7 +456,8 @@ static void _hna_global_del_orig(struct bat_priv *bat_priv, hna_global_entry->addr, hna_global_entry->orig_node->orig, message); - hash_remove(bat_priv->hna_global_hash, hna_global_entry->addr); + hash_remove(bat_priv->hna_global_hash, compare_orig, + hna_global_entry->addr); kfree(hna_global_entry); } @@ -470,7 +477,8 @@ void hna_global_del_orig(struct bat_priv *bat_priv, while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, hna_ptr); + hash_find(bat_priv->hna_global_hash, compare_orig, + hna_ptr); if ((hna_global_entry) && (hna_global_entry->orig_node == orig_node)) @@ -508,7 +516,8 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, addr); + hash_find(bat_priv->hna_global_hash, + compare_orig, addr); spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); if (!hna_global_entry) diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 5ae959327b48..1f4d911d9e5a 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -23,6 +23,7 @@ #include "unicast.h" #include "send.h" #include "soft-interface.h" +#include "originator.h" #include "hash.h" #include "translation-table.h" #include "routing.h" @@ -179,7 +180,8 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, *new_skb = NULL; spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, unicast_packet->orig)); + hash_find(bat_priv->orig_hash, compare_orig, + unicast_packet->orig)); if (!orig_node) { pr_debug("couldn't find originator in orig_hash\n"); @@ -283,6 +285,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* get routing information */ orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, ethhdr->h_dest)); /* check for hna host */ diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index 4473cc8ed6b0..ff0abe9f5607 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -26,6 +26,7 @@ #include "soft-interface.h" #include "hard-interface.h" #include "hash.h" +#include "originator.h" #define MAX_VIS_PACKET_SIZE 1000 @@ -363,7 +364,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, sizeof(struct vis_packet)); memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); - old_info = hash_find(bat_priv->vis_hash, &search_elem); + old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, &search_elem); kfree_skb(search_elem.skb_packet); if (old_info != NULL) { @@ -380,7 +381,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, } } /* remove old entry */ - hash_remove(bat_priv->vis_hash, old_info); + hash_remove(bat_priv->vis_hash, vis_info_cmp, old_info); send_list_del(old_info); kref_put(&old_info->refcount, free_info); } @@ -421,7 +422,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); /* try to add it */ - if (hash_add(bat_priv->vis_hash, info) < 0) { + if (hash_add(bat_priv->vis_hash, vis_info_cmp, info) < 0) { /* did not work (for some reason) */ kref_put(&old_info->refcount, free_info); info = NULL; @@ -710,6 +711,7 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); packet = (struct vis_packet *)info->skb_packet->data; orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, packet->target_orig)); if ((!orig_node) || (!orig_node->router)) @@ -794,13 +796,14 @@ int vis_init(struct bat_priv *bat_priv) { struct vis_packet *packet; unsigned long flags; + int hash_added; if (bat_priv->vis_hash) return 1; spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); - bat_priv->vis_hash = hash_new(256, vis_info_cmp, vis_info_choose); + bat_priv->vis_hash = hash_new(256, vis_info_choose); if (!bat_priv->vis_hash) { pr_err("Can't initialize vis_hash\n"); goto err; @@ -839,7 +842,9 @@ int vis_init(struct bat_priv *bat_priv) INIT_LIST_HEAD(&bat_priv->vis_send_list); - if (hash_add(bat_priv->vis_hash, bat_priv->my_vis_info) < 0) { + hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, + bat_priv->my_vis_info); + if (hash_added < 0) { pr_err("Can't add own vis packet into hash\n"); /* not in hash, need to remove it manually. */ kref_put(&bat_priv->my_vis_info->refcount, free_info); -- cgit v1.2.3 From 6d5e654240dc14ded3d74aa5df6857572ba9f5e3 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:57 +0100 Subject: Staging: batman-adv: Remove hashdata_choose_cb from hash Function pointers cannot be inlined by a compiler and thus always has the overhead of an call. hashdata_choose_cb's are one of the most often called function pointers and its overhead must kept relative low. As first step, every function which uses this function pointer takes it as parameter instead of storing it inside the hash abstraction structure. This not generate any performance gain right now. The called functions must also be able to be inlined by the calling functions to enable inlining of the function pointer. Reported-by: David S. Miller Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/TODO | 1 - drivers/staging/batman-adv/hash.c | 24 ++++++++++---------- drivers/staging/batman-adv/hash.h | 19 +++++++++------- drivers/staging/batman-adv/icmp_socket.c | 2 +- drivers/staging/batman-adv/main.c | 21 ----------------- drivers/staging/batman-adv/main.h | 1 - drivers/staging/batman-adv/originator.c | 11 ++++++--- drivers/staging/batman-adv/originator.h | 21 +++++++++++++++++ drivers/staging/batman-adv/routing.c | 13 ++++++----- drivers/staging/batman-adv/translation-table.c | 31 +++++++++++++++----------- drivers/staging/batman-adv/unicast.c | 3 ++- drivers/staging/batman-adv/vis.c | 17 +++++++++----- 12 files changed, 91 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO index a9c77d671a5a..2c02aa107de8 100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@ -1,6 +1,5 @@ * remove own list functionality from hash * use hlist_head, hlist_node in hash - * don't use callbacks for choose in hash * think about more efficient ways instead of abstraction of hash * Request a new review * Process the comments from the review diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c index a4abe140a953..6361a3175520 100644 --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@ -137,7 +137,7 @@ struct hash_it_t *hash_iterate(struct hashtable_t *hash, } /* allocates and clears the hash */ -struct hashtable_t *hash_new(int size, hashdata_choose_cb choose) +struct hashtable_t *hash_new(int size) { struct hashtable_t *hash; @@ -156,13 +156,12 @@ struct hashtable_t *hash_new(int size, hashdata_choose_cb choose) hash_init(hash); - hash->choose = choose; - return hash; } /* adds data to the hashtable. returns 0 on success, -1 on error */ -int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, void *data) +int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, + hashdata_choose_cb choose, void *data) { int index; struct element_t *bucket, *prev_bucket = NULL; @@ -170,7 +169,7 @@ int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, void *data) if (!hash) return -1; - index = hash->choose(data, hash->size); + index = choose(data, hash->size); bucket = hash->table[index]; while (bucket != NULL) { @@ -203,7 +202,7 @@ int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, void *data) /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, - void *keydata) + hashdata_choose_cb choose, void *keydata) { int index; struct element_t *bucket; @@ -211,7 +210,7 @@ void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, if (!hash) return NULL; - index = hash->choose(keydata , hash->size); + index = choose(keydata , hash->size); bucket = hash->table[index]; while (bucket != NULL) { @@ -250,11 +249,11 @@ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) * structure you use with just the key filled, we just need the key for * comparing. */ void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, - void *data) + hashdata_choose_cb choose, void *data) { struct hash_it_t hash_it_t; - hash_it_t.index = hash->choose(data, hash->size); + hash_it_t.index = choose(data, hash->size); hash_it_t.bucket = hash->table[hash_it_t.index]; hash_it_t.prev_bucket = NULL; @@ -277,14 +276,15 @@ void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, /* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success. */ struct hashtable_t *hash_resize(struct hashtable_t *hash, - hashdata_compare_cb compare, int size) + hashdata_compare_cb compare, + hashdata_choose_cb choose, int size) { struct hashtable_t *new_hash; struct element_t *bucket; int i; /* initialize a new hash with the new size */ - new_hash = hash_new(size, hash->choose); + new_hash = hash_new(size); if (new_hash == NULL) return NULL; @@ -294,7 +294,7 @@ struct hashtable_t *hash_resize(struct hashtable_t *hash, bucket = hash->table[i]; while (bucket != NULL) { - hash_add(new_hash, compare, bucket->data); + hash_add(new_hash, compare, choose, bucket->data); bucket = bucket->next; } } diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h index 742277ea980b..85ee12b0779a 100644 --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@ -32,6 +32,10 @@ * return 0 if same and not 0 if not * same */ typedef int (*hashdata_compare_cb)(void *, void *); + +/* the hashfunction, should return an index + * based on the key in the data of the first + * argument and the size the second */ typedef int (*hashdata_choose_cb)(void *, int); typedef void (*hashdata_free_cb)(void *, void *); @@ -51,13 +55,10 @@ struct hashtable_t { struct element_t **table; /* the hashtable itself, with the buckets */ int elements; /* number of elements registered */ int size; /* size of hashtable */ - hashdata_choose_cb choose; /* the hashfunction, should return an index - * based on the key in the data of the first - * argument and the size the second */ }; /* allocates and clears the hash */ -struct hashtable_t *hash_new(int size, hashdata_choose_cb choose); +struct hashtable_t *hash_new(int size); /* remove bucket (this might be used in hash_iterate() if you already found the * bucket you want to delete and don't need the overhead to find it again with @@ -74,24 +75,26 @@ void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg); void hash_destroy(struct hashtable_t *hash); /* adds data to the hashtable. returns 0 on success, -1 on error */ -int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, void *data); +int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, + hashdata_choose_cb choose, void *data); /* removes data from hash, if found. returns pointer do data on success, so you * can remove the used structure yourself, or NULL on error . data could be the * structure you use with just the key filled, we just need the key for * comparing. */ void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, - void *data); + hashdata_choose_cb choose, void *data); /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, - void *keydata); + hashdata_choose_cb choose, void *keydata); /* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success */ struct hashtable_t *hash_resize(struct hashtable_t *hash, - hashdata_compare_cb compare, int size); + hashdata_compare_cb compare, + hashdata_choose_cb choose, int size); /* iterate though the hash. first element is selected with iter_in NULL. use * the returned iterator to access the elements until hash_it_t returns NULL. */ diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c index a7b98ce295f9..a8c98aa9630c 100644 --- a/drivers/staging/batman-adv/icmp_socket.c +++ b/drivers/staging/batman-adv/icmp_socket.c @@ -226,7 +226,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, + compare_orig, choose_orig, icmp_packet->dst)); if (!orig_node) diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 2ed77dd88509..61d1aa66e956 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -149,27 +149,6 @@ void dec_module_count(void) module_put(THIS_MODULE); } -/* hashfunction to choose an entry in a hash table of given size */ -/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ -int choose_orig(void *data, int32_t size) -{ - unsigned char *key = data; - uint32_t hash = 0; - size_t i; - - for (i = 0; i < 6; i++) { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - - return hash % size; -} - int is_my_mac(uint8_t *addr) { struct batman_if *batman_if; diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index 97a74b047c57..3ee1eb0a7253 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -135,7 +135,6 @@ int mesh_init(struct net_device *soft_iface); void mesh_free(struct net_device *soft_iface); void inc_module_count(void); void dec_module_count(void); -int choose_orig(void *data, int32_t size); int is_my_mac(uint8_t *addr); int is_bcast(uint8_t *addr); int is_mcast(uint8_t *addr); diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index 7735b7fcf157..7c1fae7a2fac 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -45,7 +45,7 @@ int originator_init(struct bat_priv *bat_priv) return 1; spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); - bat_priv->orig_hash = hash_new(128, choose_orig); + bat_priv->orig_hash = hash_new(128); if (!bat_priv->orig_hash) goto err; @@ -128,9 +128,11 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) struct orig_node *orig_node; struct hashtable_t *swaphash; int size; + int hash_added; orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, addr)); + compare_orig, choose_orig, + addr)); if (orig_node) return orig_node; @@ -167,11 +169,14 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) if (!orig_node->bcast_own_sum) goto free_bcast_own; - if (hash_add(bat_priv->orig_hash, compare_orig, orig_node) < 0) + hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig, + orig_node); + if (hash_added < 0) goto free_bcast_own_sum; if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) { swaphash = hash_resize(bat_priv->orig_hash, compare_orig, + choose_orig, bat_priv->orig_hash->size * 2); if (!swaphash) diff --git a/drivers/staging/batman-adv/originator.h b/drivers/staging/batman-adv/originator.h index ed903dcaa35c..d474ceb2a4eb 100644 --- a/drivers/staging/batman-adv/originator.h +++ b/drivers/staging/batman-adv/originator.h @@ -40,4 +40,25 @@ static inline int compare_orig(void *data1, void *data2) return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); } +/* hashfunction to choose an entry in a hash table of given size */ +/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ +static inline int choose_orig(void *data, int32_t size) +{ + unsigned char *key = data; + uint32_t hash = 0; + size_t i; + + for (i = 0; i < 6; i++) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash % size; +} + #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index bb0bd7871959..9cbb19594e34 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -811,7 +811,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, + compare_orig, choose_orig, icmp_packet->orig)); ret = NET_RX_DROP; @@ -874,7 +874,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->orig)); ret = NET_RX_DROP; @@ -969,7 +969,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->dst)); if ((orig_node != NULL) && @@ -1042,7 +1042,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, primary_orig_node = router_orig; } else { primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, - router_orig->primary_addr); + choose_orig, + router_orig->primary_addr); if (!primary_orig_node) return orig_node->router; @@ -1147,7 +1148,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, /* get routing information */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, unicast_packet->dest)); router = find_router(bat_priv, orig_node, recv_if); @@ -1294,7 +1295,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, bcast_packet->orig)); if (orig_node == NULL) { diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c index 33cd5daa414c..96d59b100df8 100644 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@ -42,7 +42,7 @@ int hna_local_init(struct bat_priv *bat_priv) if (bat_priv->hna_local_hash) return 1; - bat_priv->hna_local_hash = hash_new(128, choose_orig); + bat_priv->hna_local_hash = hash_new(128); if (!bat_priv->hna_local_hash) return 0; @@ -65,7 +65,8 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hna_local_entry = ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, - compare_orig, addr)); + compare_orig, choose_orig, + addr)); spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); if (hna_local_entry) { @@ -108,13 +109,15 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); - hash_add(bat_priv->hna_local_hash, compare_orig, hna_local_entry); + hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig, + hna_local_entry); bat_priv->num_local_hna++; atomic_set(&bat_priv->hna_local_changed, 1); if (bat_priv->hna_local_hash->elements * 4 > bat_priv->hna_local_hash->size) { swaphash = hash_resize(bat_priv->hna_local_hash, compare_orig, + choose_orig, bat_priv->hna_local_hash->size * 2); if (!swaphash) @@ -130,7 +133,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) hna_global_entry = ((struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, - compare_orig, addr)); + compare_orig, choose_orig, addr)); if (hna_global_entry) _hna_global_del_orig(bat_priv, hna_global_entry, @@ -234,7 +237,7 @@ static void hna_local_del(struct bat_priv *bat_priv, bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", hna_local_entry->addr, message); - hash_remove(bat_priv->hna_local_hash, compare_orig, + hash_remove(bat_priv->hna_local_hash, compare_orig, choose_orig, hna_local_entry->addr); _hna_local_del(hna_local_entry, bat_priv); } @@ -248,7 +251,8 @@ void hna_local_remove(struct bat_priv *bat_priv, spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, compare_orig, addr); + hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, + addr); if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, message); @@ -298,7 +302,7 @@ int hna_global_init(struct bat_priv *bat_priv) if (bat_priv->hna_global_hash) return 1; - bat_priv->hna_global_hash = hash_new(128, choose_orig); + bat_priv->hna_global_hash = hash_new(128); if (!bat_priv->hna_global_hash) return 0; @@ -323,7 +327,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, compare_orig, - hna_ptr); + choose_orig, hna_ptr); if (!hna_global_entry) { spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, @@ -345,7 +349,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hash_add(bat_priv->hna_global_hash, compare_orig, - hna_global_entry); + choose_orig, hna_global_entry); } @@ -358,7 +362,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_local_entry = (struct hna_local_entry *) hash_find(bat_priv->hna_local_hash, compare_orig, - hna_ptr); + choose_orig, hna_ptr); if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, @@ -386,6 +390,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, if (bat_priv->hna_global_hash->elements * 4 > bat_priv->hna_global_hash->size) { swaphash = hash_resize(bat_priv->hna_global_hash, compare_orig, + choose_orig, bat_priv->hna_global_hash->size * 2); if (!swaphash) @@ -456,7 +461,7 @@ static void _hna_global_del_orig(struct bat_priv *bat_priv, hna_global_entry->addr, hna_global_entry->orig_node->orig, message); - hash_remove(bat_priv->hna_global_hash, compare_orig, + hash_remove(bat_priv->hna_global_hash, compare_orig, choose_orig, hna_global_entry->addr); kfree(hna_global_entry); } @@ -478,7 +483,7 @@ void hna_global_del_orig(struct bat_priv *bat_priv, hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, compare_orig, - hna_ptr); + choose_orig, hna_ptr); if ((hna_global_entry) && (hna_global_entry->orig_node == orig_node)) @@ -517,7 +522,7 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hna_global_entry = (struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, - compare_orig, addr); + compare_orig, choose_orig, addr); spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); if (!hna_global_entry) diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 1f4d911d9e5a..132875047835 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -180,7 +180,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, *new_skb = NULL; spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, + hash_find(bat_priv->orig_hash, compare_orig, choose_orig, unicast_packet->orig)); if (!orig_node) { @@ -286,6 +286,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* get routing information */ orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, + choose_orig, ethhdr->h_dest)); /* check for hna host */ diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index ff0abe9f5607..dccd296c6ff3 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -350,6 +350,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, struct vis_packet *search_packet, *old_packet; struct vis_info search_elem; struct vis_packet *packet; + int hash_added; *is_new = 0; /* sanity check */ @@ -364,7 +365,8 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, sizeof(struct vis_packet)); memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); - old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, &search_elem); + old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + &search_elem); kfree_skb(search_elem.skb_packet); if (old_info != NULL) { @@ -381,7 +383,8 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, } } /* remove old entry */ - hash_remove(bat_priv->vis_hash, vis_info_cmp, old_info); + hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + old_info); send_list_del(old_info); kref_put(&old_info->refcount, free_info); } @@ -422,7 +425,9 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv, recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); /* try to add it */ - if (hash_add(bat_priv->vis_hash, vis_info_cmp, info) < 0) { + hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, + info); + if (hash_added < 0) { /* did not work (for some reason) */ kref_put(&old_info->refcount, free_info); info = NULL; @@ -711,7 +716,7 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); packet = (struct vis_packet *)info->skb_packet->data; orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, + compare_orig, choose_orig, packet->target_orig)); if ((!orig_node) || (!orig_node->router)) @@ -803,7 +808,7 @@ int vis_init(struct bat_priv *bat_priv) spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); - bat_priv->vis_hash = hash_new(256, vis_info_choose); + bat_priv->vis_hash = hash_new(256); if (!bat_priv->vis_hash) { pr_err("Can't initialize vis_hash\n"); goto err; @@ -842,7 +847,7 @@ int vis_init(struct bat_priv *bat_priv) INIT_LIST_HEAD(&bat_priv->vis_send_list); - hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, + hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, bat_priv->my_vis_info); if (hash_added < 0) { pr_err("Can't add own vis packet into hash\n"); -- cgit v1.2.3 From 60eb502436910fb8118639e2ce4d7a4f732b6754 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:58 +0100 Subject: Staging: batman-adv: Move hash callback related function to header To enable inlining of the function pointers hashdata_choose_cb, hashdata_choose_cb and hashdata_free_cb, also the hash functions which uses them must be inlined by the called function. This should increase the performance, but also increases the size of the generated machine code slightly. Reported-by: David S. Miller Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hash.c | 150 ------------------------------------- drivers/staging/batman-adv/hash.h | 152 +++++++++++++++++++++++++++++++++++--- 2 files changed, 140 insertions(+), 162 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c index 6361a3175520..7d0498754afd 100644 --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@ -33,30 +33,6 @@ static void hash_init(struct hashtable_t *hash) hash->table[i] = NULL; } -/* remove the hash structure. if hashdata_free_cb != NULL, this function will be - * called to remove the elements inside of the hash. if you don't remove the - * elements, memory might be leaked. */ -void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg) -{ - struct element_t *bucket, *last_bucket; - int i; - - for (i = 0; i < hash->size; i++) { - bucket = hash->table[i]; - - while (bucket != NULL) { - if (free_cb != NULL) - free_cb(bucket->data, arg); - - last_bucket = bucket; - bucket = bucket->next; - kfree(last_bucket); - } - } - - hash_destroy(hash); -} - /* free only the hashtable and the hash itself. */ void hash_destroy(struct hashtable_t *hash) { @@ -159,70 +135,6 @@ struct hashtable_t *hash_new(int size) return hash; } -/* adds data to the hashtable. returns 0 on success, -1 on error */ -int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, - hashdata_choose_cb choose, void *data) -{ - int index; - struct element_t *bucket, *prev_bucket = NULL; - - if (!hash) - return -1; - - index = choose(data, hash->size); - bucket = hash->table[index]; - - while (bucket != NULL) { - if (compare(bucket->data, data)) - return -1; - - prev_bucket = bucket; - bucket = bucket->next; - } - - /* found the tail of the list, add new element */ - bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); - - if (bucket == NULL) - return -1; - - bucket->data = data; - bucket->next = NULL; - - /* and link it */ - if (prev_bucket == NULL) - hash->table[index] = bucket; - else - prev_bucket->next = bucket; - - hash->elements++; - return 0; -} - -/* finds data, based on the key in keydata. returns the found data on success, - * or NULL on error */ -void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, - hashdata_choose_cb choose, void *keydata) -{ - int index; - struct element_t *bucket; - - if (!hash) - return NULL; - - index = choose(keydata , hash->size); - bucket = hash->table[index]; - - while (bucket != NULL) { - if (compare(bucket->data, keydata)) - return bucket->data; - - bucket = bucket->next; - } - - return NULL; -} - /* remove bucket (this might be used in hash_iterate() if you already found the * bucket you want to delete and don't need the overhead to find it again with * hash_remove(). But usually, you don't want to use this function, as it @@ -243,65 +155,3 @@ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) return data_save; } - -/* removes data from hash, if found. returns pointer do data on success, so you - * can remove the used structure yourself, or NULL on error . data could be the - * structure you use with just the key filled, we just need the key for - * comparing. */ -void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, - hashdata_choose_cb choose, void *data) -{ - struct hash_it_t hash_it_t; - - hash_it_t.index = choose(data, hash->size); - hash_it_t.bucket = hash->table[hash_it_t.index]; - hash_it_t.prev_bucket = NULL; - - while (hash_it_t.bucket != NULL) { - if (compare(hash_it_t.bucket->data, data)) { - hash_it_t.first_bucket = - (hash_it_t.bucket == - hash->table[hash_it_t.index] ? - &hash->table[hash_it_t.index] : NULL); - return hash_remove_bucket(hash, &hash_it_t); - } - - hash_it_t.prev_bucket = hash_it_t.bucket; - hash_it_t.bucket = hash_it_t.bucket->next; - } - - return NULL; -} - -/* resize the hash, returns the pointer to the new hash or NULL on - * error. removes the old hash on success. */ -struct hashtable_t *hash_resize(struct hashtable_t *hash, - hashdata_compare_cb compare, - hashdata_choose_cb choose, int size) -{ - struct hashtable_t *new_hash; - struct element_t *bucket; - int i; - - /* initialize a new hash with the new size */ - new_hash = hash_new(size); - - if (new_hash == NULL) - return NULL; - - /* copy the elements */ - for (i = 0; i < hash->size; i++) { - bucket = hash->table[i]; - - while (bucket != NULL) { - hash_add(new_hash, compare, choose, bucket->data); - bucket = bucket->next; - } - } - - /* remove hash and eventual overflow buckets but not the content - * itself. */ - hash_delete(hash, NULL, NULL); - - return new_hash; -} diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h index 85ee12b0779a..efc4c28f7c15 100644 --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@ -66,35 +66,163 @@ struct hashtable_t *hash_new(int size); * fiddles with hash-internals. */ void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t); +/* free only the hashtable and the hash itself. */ +void hash_destroy(struct hashtable_t *hash); + /* remove the hash structure. if hashdata_free_cb != NULL, this function will be * called to remove the elements inside of the hash. if you don't remove the * elements, memory might be leaked. */ -void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg); +static inline void hash_delete(struct hashtable_t *hash, + hashdata_free_cb free_cb, void *arg) +{ + struct element_t *bucket, *last_bucket; + int i; -/* free only the hashtable and the hash itself. */ -void hash_destroy(struct hashtable_t *hash); + for (i = 0; i < hash->size; i++) { + bucket = hash->table[i]; + + while (bucket != NULL) { + if (free_cb != NULL) + free_cb(bucket->data, arg); + + last_bucket = bucket; + bucket = bucket->next; + kfree(last_bucket); + } + } + + hash_destroy(hash); +} /* adds data to the hashtable. returns 0 on success, -1 on error */ -int hash_add(struct hashtable_t *hash, hashdata_compare_cb compare, - hashdata_choose_cb choose, void *data); +static inline int hash_add(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, void *data) +{ + int index; + struct element_t *bucket, *prev_bucket = NULL; + + if (!hash) + return -1; + + index = choose(data, hash->size); + bucket = hash->table[index]; + + while (bucket != NULL) { + if (compare(bucket->data, data)) + return -1; + + prev_bucket = bucket; + bucket = bucket->next; + } + + /* found the tail of the list, add new element */ + bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); + + if (bucket == NULL) + return -1; + + bucket->data = data; + bucket->next = NULL; + + /* and link it */ + if (prev_bucket == NULL) + hash->table[index] = bucket; + else + prev_bucket->next = bucket; + + hash->elements++; + return 0; +} /* removes data from hash, if found. returns pointer do data on success, so you * can remove the used structure yourself, or NULL on error . data could be the * structure you use with just the key filled, we just need the key for * comparing. */ -void *hash_remove(struct hashtable_t *hash, hashdata_compare_cb compare, - hashdata_choose_cb choose, void *data); +static inline void *hash_remove(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, void *data) +{ + struct hash_it_t hash_it_t; + + hash_it_t.index = choose(data, hash->size); + hash_it_t.bucket = hash->table[hash_it_t.index]; + hash_it_t.prev_bucket = NULL; + + while (hash_it_t.bucket != NULL) { + if (compare(hash_it_t.bucket->data, data)) { + hash_it_t.first_bucket = + (hash_it_t.bucket == + hash->table[hash_it_t.index] ? + &hash->table[hash_it_t.index] : NULL); + return hash_remove_bucket(hash, &hash_it_t); + } + + hash_it_t.prev_bucket = hash_it_t.bucket; + hash_it_t.bucket = hash_it_t.bucket->next; + } + + return NULL; +} /* finds data, based on the key in keydata. returns the found data on success, * or NULL on error */ -void *hash_find(struct hashtable_t *hash, hashdata_compare_cb compare, - hashdata_choose_cb choose, void *keydata); +static inline void *hash_find(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, void *keydata) +{ + int index; + struct element_t *bucket; + + if (!hash) + return NULL; + + index = choose(keydata , hash->size); + bucket = hash->table[index]; + + while (bucket != NULL) { + if (compare(bucket->data, keydata)) + return bucket->data; + + bucket = bucket->next; + } + + return NULL; +} /* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success */ -struct hashtable_t *hash_resize(struct hashtable_t *hash, - hashdata_compare_cb compare, - hashdata_choose_cb choose, int size); +static inline struct hashtable_t *hash_resize(struct hashtable_t *hash, + hashdata_compare_cb compare, + hashdata_choose_cb choose, + int size) +{ + struct hashtable_t *new_hash; + struct element_t *bucket; + int i; + + /* initialize a new hash with the new size */ + new_hash = hash_new(size); + + if (new_hash == NULL) + return NULL; + + /* copy the elements */ + for (i = 0; i < hash->size; i++) { + bucket = hash->table[i]; + + while (bucket != NULL) { + hash_add(new_hash, compare, choose, bucket->data); + bucket = bucket->next; + } + } + + /* remove hash and eventual overflow buckets but not the content + * itself. */ + hash_delete(hash, NULL, NULL); + + return new_hash; +} /* iterate though the hash. first element is selected with iter_in NULL. use * the returned iterator to access the elements until hash_it_t returns NULL. */ -- cgit v1.2.3 From a3238c3b379146a2d480dfee4c7f76c4692d7466 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:55:59 +0100 Subject: Staging: batman-adv: Make hash_iterate inlineable hash_iterate is next to the function pointers the most called function related to hashes which benefits from inlining as it is uses in loops. Reported-by: David S. Miller Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/TODO | 1 - drivers/staging/batman-adv/hash.c | 72 ------------------------------------- drivers/staging/batman-adv/hash.h | 74 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO index 2c02aa107de8..91b5e9cd48d5 100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@ -1,6 +1,5 @@ * remove own list functionality from hash * use hlist_head, hlist_node in hash - * think about more efficient ways instead of abstraction of hash * Request a new review * Process the comments from the review * Move into mainline proper diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c index 7d0498754afd..bfe943cac1ab 100644 --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@ -40,78 +40,6 @@ void hash_destroy(struct hashtable_t *hash) kfree(hash); } -/* iterate though the hash. First element is selected if an iterator - * initialized with HASHIT() is supplied as iter. Use the returned - * (or supplied) iterator to access the elements until hash_iterate returns - * NULL. */ - -struct hash_it_t *hash_iterate(struct hashtable_t *hash, - struct hash_it_t *iter) -{ - if (!hash) - return NULL; - if (!iter) - return NULL; - - /* sanity checks first (if our bucket got deleted in the last - * iteration): */ - if (iter->bucket != NULL) { - if (iter->first_bucket != NULL) { - /* we're on the first element and it got removed after - * the last iteration. */ - if ((*iter->first_bucket) != iter->bucket) { - /* there are still other elements in the list */ - if ((*iter->first_bucket) != NULL) { - iter->prev_bucket = NULL; - iter->bucket = (*iter->first_bucket); - iter->first_bucket = - &hash->table[iter->index]; - return iter; - } else { - iter->bucket = NULL; - } - } - } else if (iter->prev_bucket != NULL) { - /* - * we're not on the first element, and the bucket got - * removed after the last iteration. the last bucket's - * next pointer is not pointing to our actual bucket - * anymore. select the next. - */ - if (iter->prev_bucket->next != iter->bucket) - iter->bucket = iter->prev_bucket; - } - } - - /* now as we are sane, select the next one if there is some */ - if (iter->bucket != NULL) { - if (iter->bucket->next != NULL) { - iter->prev_bucket = iter->bucket; - iter->bucket = iter->bucket->next; - iter->first_bucket = NULL; - return iter; - } - } - - /* if not returned yet, we've reached the last one on the index and have - * to search forward */ - iter->index++; - /* go through the entries of the hash table */ - while (iter->index < hash->size) { - if ((hash->table[iter->index]) != NULL) { - iter->prev_bucket = NULL; - iter->bucket = hash->table[iter->index]; - iter->first_bucket = &hash->table[iter->index]; - return iter; - } else { - iter->index++; - } - } - - /* nothing to iterate over anymore */ - return NULL; -} - /* allocates and clears the hash */ struct hashtable_t *hash_new(int size) { diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h index efc4c28f7c15..a8e4dd1ec6a0 100644 --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@ -224,9 +224,75 @@ static inline struct hashtable_t *hash_resize(struct hashtable_t *hash, return new_hash; } -/* iterate though the hash. first element is selected with iter_in NULL. use - * the returned iterator to access the elements until hash_it_t returns NULL. */ -struct hash_it_t *hash_iterate(struct hashtable_t *hash, - struct hash_it_t *iter_in); +/* iterate though the hash. First element is selected if an iterator + * initialized with HASHIT() is supplied as iter. Use the returned + * (or supplied) iterator to access the elements until hash_iterate returns + * NULL. */ +static inline struct hash_it_t *hash_iterate(struct hashtable_t *hash, + struct hash_it_t *iter) +{ + if (!hash) + return NULL; + if (!iter) + return NULL; + + /* sanity checks first (if our bucket got deleted in the last + * iteration): */ + if (iter->bucket != NULL) { + if (iter->first_bucket != NULL) { + /* we're on the first element and it got removed after + * the last iteration. */ + if ((*iter->first_bucket) != iter->bucket) { + /* there are still other elements in the list */ + if ((*iter->first_bucket) != NULL) { + iter->prev_bucket = NULL; + iter->bucket = (*iter->first_bucket); + iter->first_bucket = + &hash->table[iter->index]; + return iter; + } else { + iter->bucket = NULL; + } + } + } else if (iter->prev_bucket != NULL) { + /* + * we're not on the first element, and the bucket got + * removed after the last iteration. the last bucket's + * next pointer is not pointing to our actual bucket + * anymore. select the next. + */ + if (iter->prev_bucket->next != iter->bucket) + iter->bucket = iter->prev_bucket; + } + } + + /* now as we are sane, select the next one if there is some */ + if (iter->bucket != NULL) { + if (iter->bucket->next != NULL) { + iter->prev_bucket = iter->bucket; + iter->bucket = iter->bucket->next; + iter->first_bucket = NULL; + return iter; + } + } + + /* if not returned yet, we've reached the last one on the index and have + * to search forward */ + iter->index++; + /* go through the entries of the hash table */ + while (iter->index < hash->size) { + if ((hash->table[iter->index]) != NULL) { + iter->prev_bucket = NULL; + iter->bucket = hash->table[iter->index]; + iter->first_bucket = &hash->table[iter->index]; + return iter; + } else { + iter->index++; + } + } + + /* nothing to iterate over anymore */ + return NULL; +} #endif /* _NET_BATMAN_ADV_HASH_H_ */ -- cgit v1.2.3 From bd204952cf161404eae0aa6478fb1b4c586ac678 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:56:00 +0100 Subject: Staging: batman-adv: Rewrite hash using hlist_* The hash implementation is a complete implementation of a hash using buckets as hash entries and overflow buckets attached to them. The kernel already provides datastructures hlist_head and hlist_node which can be used to implement an hash using lists as hash buckets. So it is better to implement heavily used functionality on top of those instead of providing a full hash implementation. The rewrite changes the behavior of some functions slightly: * hash_add add elements to the front instead of the tail * hash_iterate doesn't provide pointer to access bucket->data directly, but it can be accessed using hlist_entry Reported-by: David S. Miller Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/TODO | 2 - drivers/staging/batman-adv/hash.c | 14 +- drivers/staging/batman-adv/hash.h | 175 ++++++++++--------------- drivers/staging/batman-adv/originator.c | 20 ++- drivers/staging/batman-adv/routing.c | 4 +- drivers/staging/batman-adv/translation-table.c | 22 ++-- drivers/staging/batman-adv/vis.c | 29 +++- 7 files changed, 126 insertions(+), 140 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO index 91b5e9cd48d5..ba69ba3ab62d 100644 --- a/drivers/staging/batman-adv/TODO +++ b/drivers/staging/batman-adv/TODO @@ -1,5 +1,3 @@ - * remove own list functionality from hash - * use hlist_head, hlist_node in hash * Request a new review * Process the comments from the review * Move into mainline proper diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c index bfe943cac1ab..8605e2fd0427 100644 --- a/drivers/staging/batman-adv/hash.c +++ b/drivers/staging/batman-adv/hash.c @@ -30,7 +30,7 @@ static void hash_init(struct hashtable_t *hash) hash->elements = 0; for (i = 0 ; i < hash->size; i++) - hash->table[i] = NULL; + INIT_HLIST_HEAD(&hash->table[i]); } /* free only the hashtable and the hash itself. */ @@ -70,15 +70,13 @@ struct hashtable_t *hash_new(int size) void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) { void *data_save; + struct element_t *bucket; - data_save = hash_it_t->bucket->data; + bucket = hlist_entry(hash_it_t->walk, struct element_t, hlist); + data_save = bucket->data; - if (hash_it_t->prev_bucket != NULL) - hash_it_t->prev_bucket->next = hash_it_t->bucket->next; - else if (hash_it_t->first_bucket != NULL) - (*hash_it_t->first_bucket) = hash_it_t->bucket->next; - - kfree(hash_it_t->bucket); + hlist_del(hash_it_t->walk); + kfree(bucket); hash->elements--; return data_save; diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h index a8e4dd1ec6a0..0b61c6e3e7cf 100644 --- a/drivers/staging/batman-adv/hash.h +++ b/drivers/staging/batman-adv/hash.h @@ -22,10 +22,11 @@ #ifndef _NET_BATMAN_ADV_HASH_H_ #define _NET_BATMAN_ADV_HASH_H_ +#include + #define HASHIT(name) struct hash_it_t name = { \ - .index = -1, .bucket = NULL, \ - .prev_bucket = NULL, \ - .first_bucket = NULL } + .index = 0, .walk = NULL, \ + .safe = NULL} /* callback to a compare function. should * compare 2 element datas for their keys, @@ -41,18 +42,17 @@ typedef void (*hashdata_free_cb)(void *, void *); struct element_t { void *data; /* pointer to the data */ - struct element_t *next; /* overflow bucket pointer */ + struct hlist_node hlist; /* bucket list pointer */ }; struct hash_it_t { - int index; - struct element_t *bucket; - struct element_t *prev_bucket; - struct element_t **first_bucket; + size_t index; + struct hlist_node *walk; + struct hlist_node *safe; }; struct hashtable_t { - struct element_t **table; /* the hashtable itself, with the buckets */ + struct hlist_head *table; /* the hashtable itself, with the buckets */ int elements; /* number of elements registered */ int size; /* size of hashtable */ }; @@ -75,19 +75,21 @@ void hash_destroy(struct hashtable_t *hash); static inline void hash_delete(struct hashtable_t *hash, hashdata_free_cb free_cb, void *arg) { - struct element_t *bucket, *last_bucket; + struct hlist_head *head; + struct hlist_node *walk, *safe; + struct element_t *bucket; int i; for (i = 0; i < hash->size; i++) { - bucket = hash->table[i]; + head = &hash->table[i]; - while (bucket != NULL) { + hlist_for_each_safe(walk, safe, head) { + bucket = hlist_entry(walk, struct element_t, hlist); if (free_cb != NULL) free_cb(bucket->data, arg); - last_bucket = bucket; - bucket = bucket->next; - kfree(last_bucket); + hlist_del(walk); + kfree(bucket); } } @@ -100,36 +102,30 @@ static inline int hash_add(struct hashtable_t *hash, hashdata_choose_cb choose, void *data) { int index; - struct element_t *bucket, *prev_bucket = NULL; + struct hlist_head *head; + struct hlist_node *walk, *safe; + struct element_t *bucket; if (!hash) return -1; index = choose(data, hash->size); - bucket = hash->table[index]; + head = &hash->table[index]; - while (bucket != NULL) { + hlist_for_each_safe(walk, safe, head) { + bucket = hlist_entry(walk, struct element_t, hlist); if (compare(bucket->data, data)) return -1; - - prev_bucket = bucket; - bucket = bucket->next; } - /* found the tail of the list, add new element */ + /* no duplicate found in list, add new element */ bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); if (bucket == NULL) return -1; bucket->data = data; - bucket->next = NULL; - - /* and link it */ - if (prev_bucket == NULL) - hash->table[index] = bucket; - else - prev_bucket->next = bucket; + hlist_add_head(&bucket->hlist, head); hash->elements++; return 0; @@ -144,22 +140,16 @@ static inline void *hash_remove(struct hashtable_t *hash, hashdata_choose_cb choose, void *data) { struct hash_it_t hash_it_t; + struct element_t *bucket; + struct hlist_head *head; hash_it_t.index = choose(data, hash->size); - hash_it_t.bucket = hash->table[hash_it_t.index]; - hash_it_t.prev_bucket = NULL; - - while (hash_it_t.bucket != NULL) { - if (compare(hash_it_t.bucket->data, data)) { - hash_it_t.first_bucket = - (hash_it_t.bucket == - hash->table[hash_it_t.index] ? - &hash->table[hash_it_t.index] : NULL); - return hash_remove_bucket(hash, &hash_it_t); - } + head = &hash->table[hash_it_t.index]; - hash_it_t.prev_bucket = hash_it_t.bucket; - hash_it_t.bucket = hash_it_t.bucket->next; + hlist_for_each(hash_it_t.walk, head) { + bucket = hlist_entry(hash_it_t.walk, struct element_t, hlist); + if (compare(bucket->data, data)) + return hash_remove_bucket(hash, &hash_it_t); } return NULL; @@ -172,19 +162,20 @@ static inline void *hash_find(struct hashtable_t *hash, hashdata_choose_cb choose, void *keydata) { int index; + struct hlist_head *head; + struct hlist_node *walk; struct element_t *bucket; if (!hash) return NULL; index = choose(keydata , hash->size); - bucket = hash->table[index]; + head = &hash->table[index]; - while (bucket != NULL) { + hlist_for_each(walk, head) { + bucket = hlist_entry(walk, struct element_t, hlist); if (compare(bucket->data, keydata)) return bucket->data; - - bucket = bucket->next; } return NULL; @@ -193,13 +184,14 @@ static inline void *hash_find(struct hashtable_t *hash, /* resize the hash, returns the pointer to the new hash or NULL on * error. removes the old hash on success */ static inline struct hashtable_t *hash_resize(struct hashtable_t *hash, - hashdata_compare_cb compare, hashdata_choose_cb choose, int size) { struct hashtable_t *new_hash; + struct hlist_head *head, *new_head; + struct hlist_node *walk, *safe; struct element_t *bucket; - int i; + int i, new_index; /* initialize a new hash with the new size */ new_hash = hash_new(size); @@ -209,17 +201,20 @@ static inline struct hashtable_t *hash_resize(struct hashtable_t *hash, /* copy the elements */ for (i = 0; i < hash->size; i++) { - bucket = hash->table[i]; + head = &hash->table[i]; + + hlist_for_each_safe(walk, safe, head) { + bucket = hlist_entry(walk, struct element_t, hlist); - while (bucket != NULL) { - hash_add(new_hash, compare, choose, bucket->data); - bucket = bucket->next; + new_index = choose(bucket->data, size); + new_head = &new_hash->table[new_index]; + + hlist_del(walk); + hlist_add_head(walk, new_head); } } - /* remove hash and eventual overflow buckets but not the content - * itself. */ - hash_delete(hash, NULL, NULL); + hash_destroy(hash); return new_hash; } @@ -236,63 +231,29 @@ static inline struct hash_it_t *hash_iterate(struct hashtable_t *hash, if (!iter) return NULL; - /* sanity checks first (if our bucket got deleted in the last - * iteration): */ - if (iter->bucket != NULL) { - if (iter->first_bucket != NULL) { - /* we're on the first element and it got removed after - * the last iteration. */ - if ((*iter->first_bucket) != iter->bucket) { - /* there are still other elements in the list */ - if ((*iter->first_bucket) != NULL) { - iter->prev_bucket = NULL; - iter->bucket = (*iter->first_bucket); - iter->first_bucket = - &hash->table[iter->index]; - return iter; - } else { - iter->bucket = NULL; - } - } - } else if (iter->prev_bucket != NULL) { - /* - * we're not on the first element, and the bucket got - * removed after the last iteration. the last bucket's - * next pointer is not pointing to our actual bucket - * anymore. select the next. - */ - if (iter->prev_bucket->next != iter->bucket) - iter->bucket = iter->prev_bucket; - } - } + iter->walk = iter->safe; - /* now as we are sane, select the next one if there is some */ - if (iter->bucket != NULL) { - if (iter->bucket->next != NULL) { - iter->prev_bucket = iter->bucket; - iter->bucket = iter->bucket->next; - iter->first_bucket = NULL; - return iter; - } - } + /* we search for the next head with list entries */ + if (!iter->walk) { + while (iter->index < hash->size) { + if (hlist_empty(&hash->table[iter->index])) + iter->index++; + else { + iter->walk = hash->table[iter->index].first; - /* if not returned yet, we've reached the last one on the index and have - * to search forward */ - iter->index++; - /* go through the entries of the hash table */ - while (iter->index < hash->size) { - if ((hash->table[iter->index]) != NULL) { - iter->prev_bucket = NULL; - iter->bucket = hash->table[iter->index]; - iter->first_bucket = &hash->table[iter->index]; - return iter; - } else { - iter->index++; + /* search next time */ + ++iter->index; + break; + } } } - /* nothing to iterate over anymore */ - return NULL; + /* return iter when we found bucket otherwise null */ + if (!iter->walk) + return NULL; + + iter->safe = iter->walk->next; + return iter; } #endif /* _NET_BATMAN_ADV_HASH_H_ */ diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index 7c1fae7a2fac..a4b7d377d941 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -175,8 +175,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) goto free_bcast_own_sum; if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) { - swaphash = hash_resize(bat_priv->orig_hash, compare_orig, - choose_orig, + swaphash = hash_resize(bat_priv->orig_hash, choose_orig, bat_priv->orig_hash->size * 2); if (!swaphash) @@ -272,6 +271,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv, static void _purge_orig(struct bat_priv *bat_priv) { HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; unsigned long flags; @@ -279,7 +279,8 @@ static void _purge_orig(struct bat_priv *bat_priv) /* for all origins... */ while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; if (purge_orig_node(bat_priv, orig_node)) { hash_remove_bucket(bat_priv->orig_hash, &hashit); @@ -315,6 +316,7 @@ void purge_orig_ref(struct bat_priv *bat_priv) int orig_seq_print_text(struct seq_file *seq, void *offset) { HASHIT(hashit); + struct element_t *bucket; struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct orig_node *orig_node; @@ -347,8 +349,8 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); while (hash_iterate(bat_priv->orig_hash, &hashit)) { - - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; if (!orig_node->router) continue; @@ -419,13 +421,15 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) struct orig_node *orig_node; unsigned long flags; HASHIT(hashit); + struct element_t *bucket; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; if (orig_node_add_if(orig_node, max_if_num) == -1) goto err; @@ -498,6 +502,7 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) struct orig_node *orig_node; unsigned long flags; HASHIT(hashit); + struct element_t *bucket; int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on @@ -505,7 +510,8 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; ret = orig_node_del_if(orig_node, max_if_num, batman_if->if_num); diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 9cbb19594e34..77e5d1411c99 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -38,6 +38,7 @@ void slide_own_bcast_window(struct batman_if *batman_if) { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; TYPE_OF_WORD *word; unsigned long flags; @@ -45,7 +46,8 @@ void slide_own_bcast_window(struct batman_if *batman_if) spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]); bit_get_packet(bat_priv, word, 1, 0); diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c index 96d59b100df8..6639bfb66ab8 100644 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@ -116,8 +116,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) if (bat_priv->hna_local_hash->elements * 4 > bat_priv->hna_local_hash->size) { - swaphash = hash_resize(bat_priv->hna_local_hash, compare_orig, - choose_orig, + swaphash = hash_resize(bat_priv->hna_local_hash, choose_orig, bat_priv->hna_local_hash->size * 2); if (!swaphash) @@ -146,6 +145,7 @@ int hna_local_fill_buffer(struct bat_priv *bat_priv, unsigned char *buff, int buff_len) { struct hna_local_entry *hna_local_entry; + struct element_t *bucket; HASHIT(hashit); int i = 0; unsigned long flags; @@ -157,7 +157,8 @@ int hna_local_fill_buffer(struct bat_priv *bat_priv, if (buff_len < (i + 1) * ETH_ALEN) break; - hna_local_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_local_entry = bucket->data; memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN); i++; @@ -178,6 +179,7 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) struct hna_local_entry *hna_local_entry; HASHIT(hashit); HASHIT(hashit_count); + struct element_t *bucket; unsigned long flags; size_t buf_size, pos; char *buff; @@ -208,7 +210,8 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) pos = 0; while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - hna_local_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_local_entry = bucket->data; pos += snprintf(buff + pos, 22, " * %pM\n", hna_local_entry->addr); @@ -267,13 +270,15 @@ static void hna_local_purge(struct work_struct *work) container_of(delayed_work, struct bat_priv, hna_work); struct hna_local_entry *hna_local_entry; HASHIT(hashit); + struct element_t *bucket; unsigned long flags; unsigned long timeout; spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - hna_local_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_local_entry = bucket->data; timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ; @@ -389,8 +394,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, if (bat_priv->hna_global_hash->elements * 4 > bat_priv->hna_global_hash->size) { - swaphash = hash_resize(bat_priv->hna_global_hash, compare_orig, - choose_orig, + swaphash = hash_resize(bat_priv->hna_global_hash, choose_orig, bat_priv->hna_global_hash->size * 2); if (!swaphash) @@ -409,6 +413,7 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) struct hna_global_entry *hna_global_entry; HASHIT(hashit); HASHIT(hashit_count); + struct element_t *bucket; unsigned long flags; size_t buf_size, pos; char *buff; @@ -438,7 +443,8 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) pos = 0; while (hash_iterate(bat_priv->hna_global_hash, &hashit)) { - hna_global_entry = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + hna_global_entry = bucket->data; pos += snprintf(buff + pos, 44, " * %pM via %pM\n", hna_global_entry->addr, diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index dccd296c6ff3..e2031c9aab9d 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -177,6 +177,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) { HASHIT(hashit); HASHIT(hashit_count); + struct element_t *bucket; struct vis_info *info; struct vis_packet *packet; struct vis_info_entry *entries; @@ -199,7 +200,9 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) /* Estimate length */ spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); while (hash_iterate(bat_priv->vis_hash, &hashit_count)) { - info = hashit_count.bucket->data; + bucket = hlist_entry(hashit_count.walk, struct element_t, + hlist); + info = bucket->data; packet = (struct vis_packet *)info->skb_packet->data; entries = (struct vis_info_entry *) ((char *)packet + sizeof(struct vis_packet)); @@ -237,7 +240,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) buff_pos = 0; while (hash_iterate(bat_priv->vis_hash, &hashit)) { - info = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + info = bucket->data; packet = (struct vis_packet *)info->skb_packet->data; entries = (struct vis_info_entry *) ((char *)packet + sizeof(struct vis_packet)); @@ -515,6 +519,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv, struct vis_info *info) { HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; struct vis_packet *packet; int best_tq = -1; @@ -522,7 +527,8 @@ static int find_best_vis_server(struct bat_priv *bat_priv, packet = (struct vis_packet *)info->skb_packet->data; while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; if ((orig_node) && (orig_node->router) && (orig_node->flags & VIS_SERVER) && (orig_node->router->tq_avg > best_tq)) { @@ -551,6 +557,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) { HASHIT(hashit_local); HASHIT(hashit_global); + struct element_t *bucket; struct orig_node *orig_node; struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; @@ -580,7 +587,9 @@ static int generate_vis_packet(struct bat_priv *bat_priv) } while (hash_iterate(bat_priv->orig_hash, &hashit_global)) { - orig_node = hashit_global.bucket->data; + bucket = hlist_entry(hashit_global.walk, struct element_t, + hlist); + orig_node = bucket->data; if (!orig_node->router) continue; @@ -615,7 +624,9 @@ static int generate_vis_packet(struct bat_priv *bat_priv) spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) { - hna_local_entry = hashit_local.bucket->data; + bucket = hlist_entry(hashit_local.walk, struct element_t, + hlist); + hna_local_entry = bucket->data; entry = (struct vis_info_entry *)skb_put(info->skb_packet, sizeof(*entry)); memset(entry->src, 0, ETH_ALEN); @@ -639,10 +650,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv) static void purge_vis_packets(struct bat_priv *bat_priv) { HASHIT(hashit); + struct element_t *bucket; struct vis_info *info; while (hash_iterate(bat_priv->vis_hash, &hashit)) { - info = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + info = bucket->data; /* never purge own data. */ if (info == bat_priv->my_vis_info) @@ -661,6 +674,7 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { HASHIT(hashit); + struct element_t *bucket; struct orig_node *orig_node; struct vis_packet *packet; struct sk_buff *skb; @@ -674,7 +688,8 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, /* send to all routers in range. */ while (hash_iterate(bat_priv->orig_hash, &hashit)) { - orig_node = hashit.bucket->data; + bucket = hlist_entry(hashit.walk, struct element_t, hlist); + orig_node = bucket->data; /* if it's a vis server and reachable, send it. */ if ((!orig_node) || (!orig_node->router)) -- cgit v1.2.3 From 7a18deb7b03e4112af5add8498889f9b2b36d59f Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:56:01 +0100 Subject: Staging: batman-adv: Limit spin_locks to spin_lock_bh spin_lock_irqsave disables the IRQs and stores them inside the flags provided by the caller. This is needed to protect a bottom half handler or a user context critical section from being interrupted by an interrupt handler which also tries to acquire the spinlock and locks forever. The linux device drivers will receive the packets inside an interrupt handler and the network infrastructure will process them inside bottom half. Thus batman-adv will only run in user context and bottom half handlers. We can conclude that batman-adv doesn't share its own spinlocks with real interrupt handlers. This makes it possible to exchange the quite complex spin_lock_irqsave with spin_lock_bh which only stops bottom halves from running on the current cpu, but allows interrupt handlers to take over to keep the interrupt latency low. Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/aggregation.c | 12 ++-- drivers/staging/batman-adv/bat_debugfs.c | 14 ++-- drivers/staging/batman-adv/icmp_socket.c | 24 +++---- drivers/staging/batman-adv/originator.c | 37 +++++------ drivers/staging/batman-adv/routing.c | 49 ++++++-------- drivers/staging/batman-adv/send.c | 32 ++++----- drivers/staging/batman-adv/soft-interface.c | 10 ++- drivers/staging/batman-adv/translation-table.c | 70 +++++++++----------- drivers/staging/batman-adv/unicast.c | 12 ++-- drivers/staging/batman-adv/vis.c | 90 +++++++++++--------------- 10 files changed, 147 insertions(+), 203 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c index 3dfed2f4bb5d..0c92e3b35abf 100644 --- a/drivers/staging/batman-adv/aggregation.c +++ b/drivers/staging/batman-adv/aggregation.c @@ -104,7 +104,6 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct forw_packet *forw_packet_aggr; - unsigned long flags; unsigned char *skb_buff; /* own packet should always be scheduled */ @@ -156,9 +155,9 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, forw_packet_aggr->direct_link_flags |= 1; /* add new packet to packet list */ - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); /* start timer for this packet */ INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, @@ -201,10 +200,9 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, struct batman_packet *batman_packet = (struct batman_packet *)packet_buff; bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; - unsigned long flags; /* find position for the packet in the forward queue */ - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); /* own packets are not to be aggregated */ if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { hlist_for_each_entry(forw_packet_pos, tmp_node, @@ -225,7 +223,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, * suitable aggregation packet found */ if (forw_packet_aggr == NULL) { /* the following section can run without the lock */ - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); /** * if we could not aggregate this packet with one of the others @@ -243,7 +241,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, aggregate(forw_packet_aggr, packet_buff, packet_len, direct_link); - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); } } diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c index 22f3eb98470f..cbac1a53ad74 100644 --- a/drivers/staging/batman-adv/bat_debugfs.c +++ b/drivers/staging/batman-adv/bat_debugfs.c @@ -54,12 +54,11 @@ static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) va_list args; static char debug_log_buf[256]; char *p; - unsigned long flags; if (!debug_log) return 0; - spin_lock_irqsave(&debug_log->lock, flags); + spin_lock_bh(&debug_log->lock); va_start(args, fmt); printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); @@ -68,7 +67,7 @@ static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) for (p = debug_log_buf; *p != 0; p++) emit_log_char(debug_log, *p); - spin_unlock_irqrestore(&debug_log->lock, flags); + spin_unlock_bh(&debug_log->lock); wake_up(&debug_log->queue_wait); @@ -110,7 +109,6 @@ static ssize_t log_read(struct file *file, char __user *buf, struct debug_log *debug_log = bat_priv->debug_log; int error, i = 0; char c; - unsigned long flags; if ((file->f_flags & O_NONBLOCK) && !(debug_log->log_end - debug_log->log_start)) @@ -131,7 +129,7 @@ static ssize_t log_read(struct file *file, char __user *buf, if (error) return error; - spin_lock_irqsave(&debug_log->lock, flags); + spin_lock_bh(&debug_log->lock); while ((!error) && (i < count) && (debug_log->log_start != debug_log->log_end)) { @@ -139,18 +137,18 @@ static ssize_t log_read(struct file *file, char __user *buf, debug_log->log_start++; - spin_unlock_irqrestore(&debug_log->lock, flags); + spin_unlock_bh(&debug_log->lock); error = __put_user(c, buf); - spin_lock_irqsave(&debug_log->lock, flags); + spin_lock_bh(&debug_log->lock); buf++; i++; } - spin_unlock_irqrestore(&debug_log->lock, flags); + spin_unlock_bh(&debug_log->lock); if (!error) return i; diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c index a8c98aa9630c..a933ca609b74 100644 --- a/drivers/staging/batman-adv/icmp_socket.c +++ b/drivers/staging/batman-adv/icmp_socket.c @@ -85,9 +85,8 @@ static int bat_socket_release(struct inode *inode, struct file *file) struct socket_client *socket_client = file->private_data; struct socket_packet *socket_packet; struct list_head *list_pos, *list_pos_tmp; - unsigned long flags; - spin_lock_irqsave(&socket_client->lock, flags); + spin_lock_bh(&socket_client->lock); /* for all packets in the queue ... */ list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) { @@ -99,7 +98,7 @@ static int bat_socket_release(struct inode *inode, struct file *file) } socket_client_hash[socket_client->index] = NULL; - spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock); kfree(socket_client); dec_module_count(); @@ -114,7 +113,6 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, struct socket_packet *socket_packet; size_t packet_len; int error; - unsigned long flags; if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0)) return -EAGAIN; @@ -131,14 +129,14 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, if (error) return error; - spin_lock_irqsave(&socket_client->lock, flags); + spin_lock_bh(&socket_client->lock); socket_packet = list_first_entry(&socket_client->queue_list, struct socket_packet, list); list_del(&socket_packet->list); socket_client->queue_len--; - spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock); error = __copy_to_user(buf, &socket_packet->icmp_packet, socket_packet->icmp_len); @@ -164,7 +162,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, struct batman_if *batman_if; size_t packet_len = sizeof(struct icmp_packet); uint8_t dstaddr[ETH_ALEN]; - unsigned long flags; if (len < sizeof(struct icmp_packet)) { bat_dbg(DBG_BATMAN, bat_priv, @@ -224,7 +221,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dst_unreach; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->dst)); @@ -238,7 +235,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); if (!batman_if) goto dst_unreach; @@ -258,7 +255,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, goto out; unlock: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); dst_unreach: icmp_packet->msg_type = DESTINATION_UNREACHABLE; bat_socket_add_packet(socket_client, icmp_packet, packet_len); @@ -313,7 +310,6 @@ static void bat_socket_add_packet(struct socket_client *socket_client, size_t icmp_len) { struct socket_packet *socket_packet; - unsigned long flags; socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC); @@ -324,12 +320,12 @@ static void bat_socket_add_packet(struct socket_client *socket_client, memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len); socket_packet->icmp_len = icmp_len; - spin_lock_irqsave(&socket_client->lock, flags); + spin_lock_bh(&socket_client->lock); /* while waiting for the lock the socket_client could have been * deleted */ if (!socket_client_hash[icmp_packet->uid]) { - spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock); kfree(socket_packet); return; } @@ -346,7 +342,7 @@ static void bat_socket_add_packet(struct socket_client *socket_client, socket_client->queue_len--; } - spin_unlock_irqrestore(&socket_client->lock, flags); + spin_unlock_bh(&socket_client->lock); wake_up(&socket_client->queue_wait); } diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index a4b7d377d941..8bef4681bf82 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -40,22 +40,21 @@ static void start_purge_timer(struct bat_priv *bat_priv) int originator_init(struct bat_priv *bat_priv) { - unsigned long flags; if (bat_priv->orig_hash) return 1; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); bat_priv->orig_hash = hash_new(128); if (!bat_priv->orig_hash) goto err; - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); start_purge_timer(bat_priv); return 1; err: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; } @@ -108,17 +107,15 @@ static void free_orig_node(void *data, void *arg) void originator_free(struct bat_priv *bat_priv) { - unsigned long flags; - if (!bat_priv->orig_hash) return; cancel_delayed_work_sync(&bat_priv->orig_work); - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv); bat_priv->orig_hash = NULL; - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); } /* this function finds or creates an originator entry for the given @@ -273,9 +270,8 @@ static void _purge_orig(struct bat_priv *bat_priv) HASHIT(hashit); struct element_t *bucket; struct orig_node *orig_node; - unsigned long flags; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); /* for all origins... */ while (hash_iterate(bat_priv->orig_hash, &hashit)) { @@ -292,7 +288,7 @@ static void _purge_orig(struct bat_priv *bat_priv) frag_list_free(&orig_node->frag_list); } - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); softif_neigh_purge(bat_priv); } @@ -324,7 +320,6 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) int batman_count = 0; int last_seen_secs; int last_seen_msecs; - unsigned long flags; if ((!bat_priv->primary_if) || (bat_priv->primary_if->if_status != IF_ACTIVE)) { @@ -346,7 +341,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops"); - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); while (hash_iterate(bat_priv->orig_hash, &hashit)) { bucket = hlist_entry(hashit.walk, struct element_t, hlist); @@ -377,7 +372,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) batman_count++; } - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); if ((batman_count == 0)) seq_printf(seq, "No batman nodes in range ...\n"); @@ -419,13 +414,12 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct orig_node *orig_node; - unsigned long flags; HASHIT(hashit); struct element_t *bucket; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); while (hash_iterate(bat_priv->orig_hash, &hashit)) { bucket = hlist_entry(hashit.walk, struct element_t, hlist); @@ -435,11 +429,11 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) goto err; } - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; err: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return -ENOMEM; } @@ -500,14 +494,13 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct batman_if *batman_if_tmp; struct orig_node *orig_node; - unsigned long flags; HASHIT(hashit); struct element_t *bucket; int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); while (hash_iterate(bat_priv->orig_hash, &hashit)) { bucket = hlist_entry(hashit.walk, struct element_t, hlist); @@ -538,10 +531,10 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) rcu_read_unlock(); batman_if->if_num = -1; - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; err: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return -ENOMEM; } diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 77e5d1411c99..1536963dd69f 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -41,9 +41,8 @@ void slide_own_bcast_window(struct batman_if *batman_if) struct element_t *bucket; struct orig_node *orig_node; TYPE_OF_WORD *word; - unsigned long flags; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); while (hash_iterate(bat_priv->orig_hash, &hashit)) { bucket = hlist_entry(hashit.walk, struct element_t, hlist); @@ -55,7 +54,7 @@ void slide_own_bcast_window(struct batman_if *batman_if) bit_packet_count(word); } - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); } static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, @@ -749,7 +748,6 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) { struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct ethhdr *ethhdr; - unsigned long flags; /* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) @@ -775,12 +773,12 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); receive_aggr_bat_packet(ethhdr, skb->data, skb_headlen(skb), batman_if); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); kfree_skb(skb); return NET_RX_SUCCESS; @@ -794,7 +792,6 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct ethhdr *ethhdr; struct batman_if *batman_if; int ret; - unsigned long flags; uint8_t dstaddr[ETH_ALEN]; icmp_packet = (struct icmp_packet_rr *)skb->data; @@ -811,7 +808,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* answer echo request (ping) */ /* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->orig)); @@ -824,7 +821,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -843,7 +840,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ret = NET_RX_SUCCESS; } else - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return ret; } @@ -856,7 +853,6 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct ethhdr *ethhdr; struct batman_if *batman_if; int ret; - unsigned long flags; uint8_t dstaddr[ETH_ALEN]; icmp_packet = (struct icmp_packet *)skb->data; @@ -874,7 +870,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, return NET_RX_DROP; /* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->orig)); @@ -887,7 +883,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -906,7 +902,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, ret = NET_RX_SUCCESS; } else - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return ret; } @@ -921,7 +917,6 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) struct batman_if *batman_if; int hdr_size = sizeof(struct icmp_packet); int ret; - unsigned long flags; uint8_t dstaddr[ETH_ALEN]; /** @@ -969,7 +964,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) ret = NET_RX_DROP; /* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->dst)); @@ -981,7 +976,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -998,7 +993,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) ret = NET_RX_SUCCESS; } else - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return ret; } @@ -1131,7 +1126,6 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, struct neigh_node *router; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN]; - unsigned long flags; struct unicast_packet *unicast_packet; struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); int ret; @@ -1148,7 +1142,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, } /* get routing information */ - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, unicast_packet->dest)); @@ -1156,7 +1150,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, router = find_router(bat_priv, orig_node, recv_if); if (!router) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; } @@ -1166,7 +1160,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, batman_if = router->if_incoming; memcpy(dstaddr, router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -1266,7 +1260,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) struct ethhdr *ethhdr; int hdr_size = sizeof(struct bcast_packet); int32_t seq_diff; - unsigned long flags; /* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) @@ -1295,13 +1288,13 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (bcast_packet->ttl < 2) return NET_RX_DROP; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, bcast_packet->orig)); if (orig_node == NULL) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; } @@ -1309,7 +1302,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, ntohl(bcast_packet->seqno))) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; } @@ -1318,7 +1311,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) /* check whether the packet is old and the host just restarted. */ if (window_protected(bat_priv, seq_diff, &orig_node->bcast_seqno_reset)) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return NET_RX_DROP; } @@ -1327,7 +1320,7 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); /* rebroadcast packet */ add_bcast_packet_to_list(bat_priv, skb); diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index 1840ef0e3755..9ed77d7bbca0 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -367,13 +367,12 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, struct forw_packet *forw_packet, unsigned long send_time) { - unsigned long flags; INIT_HLIST_NODE(&forw_packet->list); /* add new packet to packet list */ - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list); - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock); /* start timer for this packet */ INIT_DELAYED_WORK(&forw_packet->delayed_work, @@ -443,14 +442,13 @@ static void send_outstanding_bcast_packet(struct work_struct *work) container_of(work, struct delayed_work, work); struct forw_packet *forw_packet = container_of(delayed_work, struct forw_packet, delayed_work); - unsigned long flags; struct sk_buff *skb1; struct net_device *soft_iface = forw_packet->if_incoming->soft_iface; struct bat_priv *bat_priv = netdev_priv(soft_iface); - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); hlist_del(&forw_packet->list); - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock); if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; @@ -488,13 +486,12 @@ void send_outstanding_bat_packet(struct work_struct *work) container_of(work, struct delayed_work, work); struct forw_packet *forw_packet = container_of(delayed_work, struct forw_packet, delayed_work); - unsigned long flags; struct bat_priv *bat_priv; bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface); - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); hlist_del(&forw_packet->list); - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) goto out; @@ -522,7 +519,6 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, { struct forw_packet *forw_packet; struct hlist_node *tmp_node, *safe_tmp_node; - unsigned long flags; if (batman_if) bat_dbg(DBG_BATMAN, bat_priv, @@ -533,7 +529,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, "purge_outstanding_packets()\n"); /* free bcast list */ - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, &bat_priv->forw_bcast_list, list) { @@ -545,19 +541,19 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, (forw_packet->if_incoming != batman_if)) continue; - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock); /** * send_outstanding_bcast_packet() will lock the list to * delete the item from the list */ cancel_delayed_work_sync(&forw_packet->delayed_work); - spin_lock_irqsave(&bat_priv->forw_bcast_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bcast_list_lock); } - spin_unlock_irqrestore(&bat_priv->forw_bcast_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bcast_list_lock); /* free batman packet list */ - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, &bat_priv->forw_bat_list, list) { @@ -569,14 +565,14 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, (forw_packet->if_incoming != batman_if)) continue; - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); /** * send_outstanding_bat_packet() will lock the list to * delete the item from the list */ cancel_delayed_work_sync(&forw_packet->delayed_work); - spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags); + spin_lock_bh(&bat_priv->forw_bat_list_lock); } - spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags); + spin_unlock_bh(&bat_priv->forw_bat_list_lock); } diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 1cf9aa21a408..28ffe34919d3 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -97,9 +97,8 @@ void softif_neigh_purge(struct bat_priv *bat_priv) { struct softif_neigh *softif_neigh, *softif_neigh_tmp; struct hlist_node *node, *node_tmp; - unsigned long flags; - spin_lock_irqsave(&bat_priv->softif_neigh_lock, flags); + spin_lock_bh(&bat_priv->softif_neigh_lock); hlist_for_each_entry_safe(softif_neigh, node, node_tmp, &bat_priv->softif_neigh_list, list) { @@ -125,7 +124,7 @@ void softif_neigh_purge(struct bat_priv *bat_priv) call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); } - spin_unlock_irqrestore(&bat_priv->softif_neigh_lock, flags); + spin_unlock_bh(&bat_priv->softif_neigh_lock); } static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, @@ -133,7 +132,6 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, { struct softif_neigh *softif_neigh; struct hlist_node *node; - unsigned long flags; rcu_read_lock(); hlist_for_each_entry_rcu(softif_neigh, node, @@ -158,9 +156,9 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, kref_init(&softif_neigh->refcount); INIT_HLIST_NODE(&softif_neigh->list); - spin_lock_irqsave(&bat_priv->softif_neigh_lock, flags); + spin_lock_bh(&bat_priv->softif_neigh_lock); hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); - spin_unlock_irqrestore(&bat_priv->softif_neigh_lock, flags); + spin_unlock_bh(&bat_priv->softif_neigh_lock); found: kref_get(&softif_neigh->refcount); diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c index 6639bfb66ab8..4b0a1079347b 100644 --- a/drivers/staging/batman-adv/translation-table.c +++ b/drivers/staging/batman-adv/translation-table.c @@ -59,15 +59,14 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) struct hna_local_entry *hna_local_entry; struct hna_global_entry *hna_global_entry; struct hashtable_t *swaphash; - unsigned long flags; int required_bytes; - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); hna_local_entry = ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, addr)); - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); if (hna_local_entry) { hna_local_entry->last_seen = jiffies; @@ -107,7 +106,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) else hna_local_entry->never_purge = 0; - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig, hna_local_entry); @@ -125,10 +124,10 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) bat_priv->hna_local_hash = swaphash; } - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); /* remove address from global hash if present */ - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); hna_global_entry = ((struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, @@ -138,7 +137,7 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr) _hna_global_del_orig(bat_priv, hna_global_entry, "local hna received"); - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); } int hna_local_fill_buffer(struct bat_priv *bat_priv, @@ -148,9 +147,8 @@ int hna_local_fill_buffer(struct bat_priv *bat_priv, struct element_t *bucket; HASHIT(hashit); int i = 0; - unsigned long flags; - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { @@ -168,7 +166,7 @@ int hna_local_fill_buffer(struct bat_priv *bat_priv, if (i == bat_priv->num_local_hna) atomic_set(&bat_priv->hna_local_changed, 0); - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return i; } @@ -180,7 +178,6 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) HASHIT(hashit); HASHIT(hashit_count); struct element_t *bucket; - unsigned long flags; size_t buf_size, pos; char *buff; @@ -194,7 +191,7 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) "announced via HNA:\n", net_dev->name); - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ @@ -203,7 +200,7 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return -ENOMEM; } buff[0] = '\0'; @@ -217,7 +214,7 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) hna_local_entry->addr); } - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); seq_printf(seq, "%s", buff); kfree(buff); @@ -249,9 +246,8 @@ void hna_local_remove(struct bat_priv *bat_priv, uint8_t *addr, char *message) { struct hna_local_entry *hna_local_entry; - unsigned long flags; - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); hna_local_entry = (struct hna_local_entry *) hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, @@ -259,7 +255,7 @@ void hna_local_remove(struct bat_priv *bat_priv, if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, message); - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); } static void hna_local_purge(struct work_struct *work) @@ -271,10 +267,9 @@ static void hna_local_purge(struct work_struct *work) struct hna_local_entry *hna_local_entry; HASHIT(hashit); struct element_t *bucket; - unsigned long flags; unsigned long timeout; - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { bucket = hlist_entry(hashit.walk, struct element_t, hlist); @@ -288,7 +283,7 @@ static void hna_local_purge(struct work_struct *work) "address timed out"); } - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); hna_local_start_timer(bat_priv); } @@ -323,11 +318,10 @@ void hna_global_add_orig(struct bat_priv *bat_priv, struct hna_local_entry *hna_local_entry; struct hashtable_t *swaphash; int hna_buff_count = 0; - unsigned long flags; unsigned char *hna_ptr; while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) @@ -335,8 +329,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, choose_orig, hna_ptr); if (!hna_global_entry) { - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, - flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); hna_global_entry = kmalloc(sizeof(struct hna_global_entry), @@ -352,17 +345,17 @@ void hna_global_add_orig(struct bat_priv *bat_priv, "%pM (via %pM)\n", hna_global_entry->addr, orig_node->orig); - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); hash_add(bat_priv->hna_global_hash, compare_orig, choose_orig, hna_global_entry); } hna_global_entry->orig_node = orig_node; - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); /* remove address from local hash if present */ - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_local_entry = (struct hna_local_entry *) @@ -373,7 +366,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, hna_local_del(bat_priv, hna_local_entry, "global hna received"); - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); hna_buff_count++; } @@ -390,7 +383,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, } } - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); if (bat_priv->hna_global_hash->elements * 4 > bat_priv->hna_global_hash->size) { @@ -403,7 +396,7 @@ void hna_global_add_orig(struct bat_priv *bat_priv, bat_priv->hna_global_hash = swaphash; } - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); } int hna_global_seq_print_text(struct seq_file *seq, void *offset) @@ -414,7 +407,6 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) HASHIT(hashit); HASHIT(hashit_count); struct element_t *bucket; - unsigned long flags; size_t buf_size, pos; char *buff; @@ -427,7 +419,7 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", net_dev->name); - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ @@ -436,7 +428,7 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); return -ENOMEM; } buff[0] = '\0'; @@ -451,7 +443,7 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) hna_global_entry->orig_node->orig); } - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); seq_printf(seq, "%s", buff); kfree(buff); @@ -477,13 +469,12 @@ void hna_global_del_orig(struct bat_priv *bat_priv, { struct hna_global_entry *hna_global_entry; int hna_buff_count = 0; - unsigned long flags; unsigned char *hna_ptr; if (orig_node->hna_buff_len == 0) return; - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); @@ -499,7 +490,7 @@ void hna_global_del_orig(struct bat_priv *bat_priv, hna_buff_count++; } - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); orig_node->hna_buff_len = 0; kfree(orig_node->hna_buff); @@ -523,13 +514,12 @@ void hna_global_free(struct bat_priv *bat_priv) struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) { struct hna_global_entry *hna_global_entry; - unsigned long flags; - spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); + spin_lock_bh(&bat_priv->hna_ghash_lock); hna_global_entry = (struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, compare_orig, choose_orig, addr); - spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); + spin_unlock_bh(&bat_priv->hna_ghash_lock); if (!hna_global_entry) return NULL; diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 132875047835..3b62d998a2f1 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -170,7 +170,6 @@ void frag_list_free(struct list_head *head) int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, struct sk_buff **new_skb) { - unsigned long flags; struct orig_node *orig_node; struct frag_packet_list_entry *tmp_frag_entry; int ret = NET_RX_DROP; @@ -178,7 +177,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, (struct unicast_frag_packet *)skb->data; *new_skb = NULL; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, unicast_packet->orig)); @@ -211,7 +210,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, if (*new_skb) ret = NET_RX_SUCCESS; out: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return ret; } @@ -279,9 +278,8 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) struct neigh_node *router; int data_len = skb->len; uint8_t dstaddr[6]; - unsigned long flags; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); /* get routing information */ orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, @@ -304,7 +302,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) batman_if = router->if_incoming; memcpy(dstaddr, router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); if (batman_if->if_status != IF_ACTIVE) goto dropped; @@ -334,7 +332,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) return 0; unlock: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); dropped: kfree_skb(skb); return 1; diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index e2031c9aab9d..65676dcd40ed 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -54,16 +54,15 @@ static void free_info(struct kref *ref) struct vis_info *info = container_of(ref, struct vis_info, refcount); struct bat_priv *bat_priv = info->bat_priv; struct recvlist_node *entry, *tmp; - unsigned long flags; list_del_init(&info->send_list); - spin_lock_irqsave(&bat_priv->vis_list_lock, flags); + spin_lock_bh(&bat_priv->vis_list_lock); list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { list_del(&entry->list); kfree(entry); } - spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags); + spin_unlock_bh(&bat_priv->vis_list_lock); kfree_skb(info->skb_packet); } @@ -187,7 +186,6 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) struct if_list_entry *entry; struct hlist_node *pos, *n; int i; - unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode); size_t buff_pos, buf_size; char *buff; @@ -198,7 +196,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) buf_size = 1; /* Estimate length */ - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); while (hash_iterate(bat_priv->vis_hash, &hashit_count)) { bucket = hlist_entry(hashit_count.walk, struct element_t, hlist); @@ -233,7 +231,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); return -ENOMEM; } buff[0] = '\0'; @@ -278,7 +276,7 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) } } - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); seq_printf(seq, "%s", buff); kfree(buff); @@ -311,16 +309,15 @@ static void recv_list_add(struct bat_priv *bat_priv, struct list_head *recv_list, char *mac) { struct recvlist_node *entry; - unsigned long flags; entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); if (!entry) return; memcpy(entry->mac, mac, ETH_ALEN); - spin_lock_irqsave(&bat_priv->vis_list_lock, flags); + spin_lock_bh(&bat_priv->vis_list_lock); list_add_tail(&entry->list, recv_list); - spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags); + spin_unlock_bh(&bat_priv->vis_list_lock); } /* returns 1 if this mac is in the recv_list */ @@ -328,17 +325,15 @@ static int recv_list_is_in(struct bat_priv *bat_priv, struct list_head *recv_list, char *mac) { struct recvlist_node *entry; - unsigned long flags; - spin_lock_irqsave(&bat_priv->vis_list_lock, flags); + spin_lock_bh(&bat_priv->vis_list_lock); list_for_each_entry(entry, recv_list, list) { if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { - spin_unlock_irqrestore(&bat_priv->vis_list_lock, - flags); + spin_unlock_bh(&bat_priv->vis_list_lock); return 1; } } - spin_unlock_irqrestore(&bat_priv->vis_list_lock, flags); + spin_unlock_bh(&bat_priv->vis_list_lock); return 0; } @@ -447,12 +442,11 @@ void receive_server_sync_packet(struct bat_priv *bat_priv, { struct vis_info *info; int is_new, make_broadcast; - unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode); make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC); - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); info = add_packet(bat_priv, vis_packet, vis_info_len, &is_new, make_broadcast); if (!info) @@ -463,7 +457,7 @@ void receive_server_sync_packet(struct bat_priv *bat_priv, if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) send_list_add(bat_priv, info); end: - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); } /* handle an incoming client update packet and schedule forward if needed. */ @@ -474,7 +468,6 @@ void receive_client_update_packet(struct bat_priv *bat_priv, struct vis_info *info; struct vis_packet *packet; int is_new; - unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode); int are_target = 0; @@ -487,7 +480,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv, is_my_mac(vis_packet->target_orig)) are_target = 1; - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); info = add_packet(bat_priv, vis_packet, vis_info_len, &is_new, are_target); @@ -508,7 +501,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv, } end: - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); } /* Walk the originators and find the VIS server with the best tq. Set the packet @@ -564,12 +557,11 @@ static int generate_vis_packet(struct bat_priv *bat_priv) struct vis_info_entry *entry; struct hna_local_entry *hna_local_entry; int best_tq = -1; - unsigned long flags; info->first_seen = jiffies; packet->vis_type = atomic_read(&bat_priv->vis_mode); - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); packet->ttl = TTL; packet->seqno = htonl(ntohl(packet->seqno) + 1); @@ -580,8 +572,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) best_tq = find_best_vis_server(bat_priv, info); if (best_tq < 0) { - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, - flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return -1; } } @@ -614,15 +605,14 @@ static int generate_vis_packet(struct bat_priv *bat_priv) packet->entries++; if (vis_packet_full(info)) { - spin_unlock_irqrestore( - &bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; } } - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); - spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); + spin_lock_bh(&bat_priv->hna_lhash_lock); while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) { bucket = hlist_entry(hashit_local.walk, struct element_t, hlist); @@ -635,13 +625,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv) packet->entries++; if (vis_packet_full(info)) { - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, - flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return 0; } } - spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); + spin_unlock_bh(&bat_priv->hna_lhash_lock); return 0; } @@ -678,12 +667,11 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, struct orig_node *orig_node; struct vis_packet *packet; struct sk_buff *skb; - unsigned long flags; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN]; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data; /* send to all routers in range. */ @@ -705,17 +693,17 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) send_skb_packet(skb, batman_if, dstaddr); - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); } - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); } static void unicast_vis_packet(struct bat_priv *bat_priv, @@ -724,11 +712,10 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, struct orig_node *orig_node; struct sk_buff *skb; struct vis_packet *packet; - unsigned long flags; struct batman_if *batman_if; uint8_t dstaddr[ETH_ALEN]; - spin_lock_irqsave(&bat_priv->orig_hash_lock, flags); + spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data; orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, @@ -741,7 +728,7 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, * copy the required data before sending */ batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) @@ -750,7 +737,7 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, return; out: - spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags); + spin_unlock_bh(&bat_priv->orig_hash_lock); } /* only send one vis packet. called from send_vis_packets() */ @@ -783,9 +770,8 @@ static void send_vis_packets(struct work_struct *work) struct bat_priv *bat_priv = container_of(delayed_work, struct bat_priv, vis_work); struct vis_info *info, *temp; - unsigned long flags; - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); purge_vis_packets(bat_priv); if (generate_vis_packet(bat_priv) == 0) { @@ -797,16 +783,16 @@ static void send_vis_packets(struct work_struct *work) send_list) { kref_get(&info->refcount); - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); if (bat_priv->primary_if) send_vis_packet(bat_priv, info); - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); send_list_del(info); kref_put(&info->refcount, free_info); } - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); start_vis_timer(bat_priv); } @@ -815,13 +801,12 @@ static void send_vis_packets(struct work_struct *work) int vis_init(struct bat_priv *bat_priv) { struct vis_packet *packet; - unsigned long flags; int hash_added; if (bat_priv->vis_hash) return 1; - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); bat_priv->vis_hash = hash_new(256); if (!bat_priv->vis_hash) { @@ -871,7 +856,7 @@ int vis_init(struct bat_priv *bat_priv) goto err; } - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); start_vis_timer(bat_priv); return 1; @@ -879,7 +864,7 @@ free_info: kfree(bat_priv->my_vis_info); bat_priv->my_vis_info = NULL; err: - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); vis_quit(bat_priv); return 0; } @@ -896,18 +881,17 @@ static void free_info_ref(void *data, void *arg) /* shutdown vis-server */ void vis_quit(struct bat_priv *bat_priv) { - unsigned long flags; if (!bat_priv->vis_hash) return; cancel_delayed_work_sync(&bat_priv->vis_work); - spin_lock_irqsave(&bat_priv->vis_hash_lock, flags); + spin_lock_bh(&bat_priv->vis_hash_lock); /* properly remove, kill timers ... */ hash_delete(bat_priv->vis_hash, free_info_ref, NULL); bat_priv->vis_hash = NULL; bat_priv->my_vis_info = NULL; - spin_unlock_irqrestore(&bat_priv->vis_hash_lock, flags); + spin_unlock_bh(&bat_priv->vis_hash_lock); } /* schedule packets for (re)transmission */ -- cgit v1.2.3 From dfaf9dd3459cac02411cebf418e8469aa0d8ca5d Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:56:02 +0100 Subject: Staging: batman-adv: adding gateway functionality Via the /sys filesystem you can change the gateway mode of a node using gw_mode. Adjustments to it can be done using gw_bandwidth for server mode and gw_sel_class for client mode. Signed-off-by: Marek Lindner [sven.eckelmann@gmx.de: Rework on top of current version] Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/Makefile | 19 +- drivers/staging/batman-adv/bat_debugfs.c | 10 + drivers/staging/batman-adv/bat_sysfs.c | 115 +++++++ drivers/staging/batman-adv/gateway_client.c | 387 ++++++++++++++++++++++++ drivers/staging/batman-adv/gateway_client.h | 35 +++ drivers/staging/batman-adv/gateway_common.c | 177 +++++++++++ drivers/staging/batman-adv/gateway_common.h | 38 +++ drivers/staging/batman-adv/main.c | 4 + drivers/staging/batman-adv/originator.c | 6 + drivers/staging/batman-adv/packet.h | 4 +- drivers/staging/batman-adv/routing.c | 16 +- drivers/staging/batman-adv/send.c | 8 + drivers/staging/batman-adv/soft-interface.c | 4 + drivers/staging/batman-adv/sysfs-class-net-mesh | 21 ++ drivers/staging/batman-adv/types.h | 18 +- 15 files changed, 858 insertions(+), 4 deletions(-) create mode 100644 drivers/staging/batman-adv/gateway_client.c create mode 100644 drivers/staging/batman-adv/gateway_client.h create mode 100644 drivers/staging/batman-adv/gateway_common.c create mode 100644 drivers/staging/batman-adv/gateway_common.h (limited to 'drivers') diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile index 78924283ea74..d936aeccd194 100644 --- a/drivers/staging/batman-adv/Makefile +++ b/drivers/staging/batman-adv/Makefile @@ -19,4 +19,21 @@ # obj-$(CONFIG_BATMAN_ADV) += batman-adv.o -batman-adv-y := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o unicast.o +batman-adv-y += aggregation.o +batman-adv-y += bat_debugfs.o +batman-adv-y += bat_sysfs.o +batman-adv-y += bitarray.o +batman-adv-y += gateway_client.o +batman-adv-y += gateway_common.o +batman-adv-y += hard-interface.o +batman-adv-y += hash.o +batman-adv-y += icmp_socket.o +batman-adv-y += main.o +batman-adv-y += originator.o +batman-adv-y += ring_buffer.o +batman-adv-y += routing.o +batman-adv-y += send.o +batman-adv-y += soft-interface.o +batman-adv-y += translation-table.o +batman-adv-y += unicast.o +batman-adv-y += vis.o diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c index cbac1a53ad74..0ae81d07f102 100644 --- a/drivers/staging/batman-adv/bat_debugfs.c +++ b/drivers/staging/batman-adv/bat_debugfs.c @@ -27,6 +27,8 @@ #include "translation-table.h" #include "originator.h" #include "hard-interface.h" +#include "gateway_common.h" +#include "gateway_client.h" #include "soft-interface.h" #include "vis.h" #include "icmp_socket.h" @@ -226,6 +228,12 @@ static int originators_open(struct inode *inode, struct file *file) return single_open(file, orig_seq_print_text, net_dev); } +static int gateways_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, gw_client_seq_print_text, net_dev); +} + static int softif_neigh_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@ -268,6 +276,7 @@ struct bat_debuginfo bat_debuginfo_##_name = { \ }; static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); +static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); @@ -275,6 +284,7 @@ static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); static struct bat_debuginfo *mesh_debuginfos[] = { &bat_debuginfo_originators, + &bat_debuginfo_gateways, &bat_debuginfo_softif_neigh, &bat_debuginfo_transtable_global, &bat_debuginfo_transtable_local, diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index 5ff6e5e6a1e2..cd7bb51825f1 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -24,6 +24,8 @@ #include "translation-table.h" #include "originator.h" #include "hard-interface.h" +#include "gateway_common.h" +#include "gateway_client.h" #include "vis.h" #define to_dev(obj) container_of(obj, struct device, kobj) @@ -249,12 +251,122 @@ static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, return count; } +static void post_gw_deselect(struct net_device *net_dev) +{ + struct bat_priv *bat_priv = netdev_priv(net_dev); + gw_deselect(bat_priv); +} + +static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, + char *buff) +{ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); + int bytes_written; + + switch (atomic_read(&bat_priv->gw_mode)) { + case GW_MODE_CLIENT: + bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); + break; + case GW_MODE_SERVER: + bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); + break; + default: + bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); + break; + } + + return bytes_written; +} + +static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, + char *buff, size_t count) +{ + struct net_device *net_dev = kobj_to_netdev(kobj); + struct bat_priv *bat_priv = netdev_priv(net_dev); + char *curr_gw_mode_str; + int gw_mode_tmp = -1; + + if (buff[count - 1] == '\n') + buff[count - 1] = '\0'; + + if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) + gw_mode_tmp = GW_MODE_OFF; + + if (strncmp(buff, GW_MODE_CLIENT_NAME, + strlen(GW_MODE_CLIENT_NAME)) == 0) + gw_mode_tmp = GW_MODE_CLIENT; + + if (strncmp(buff, GW_MODE_SERVER_NAME, + strlen(GW_MODE_SERVER_NAME)) == 0) + gw_mode_tmp = GW_MODE_SERVER; + + if (gw_mode_tmp < 0) { + bat_info(net_dev, + "Invalid parameter for 'gw mode' setting received: " + "%s\n", buff); + return -EINVAL; + } + + if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) + return count; + + switch (atomic_read(&bat_priv->gw_mode)) { + case GW_MODE_CLIENT: + curr_gw_mode_str = GW_MODE_CLIENT_NAME; + break; + case GW_MODE_SERVER: + curr_gw_mode_str = GW_MODE_SERVER_NAME; + break; + default: + curr_gw_mode_str = GW_MODE_OFF_NAME; + break; + } + + bat_info(net_dev, "Changing gw mode from: %s to: %s\n", + curr_gw_mode_str, buff); + + gw_deselect(bat_priv); + atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); + return count; +} + +static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, + char *buff) +{ + struct bat_priv *bat_priv = kobj_to_batpriv(kobj); + int down, up; + int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); + + gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); + return sprintf(buff, "%i%s/%i%s\n", + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); +} + +static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, + char *buff, size_t count) +{ + struct net_device *net_dev = kobj_to_netdev(kobj); + + if (buff[count - 1] == '\n') + buff[count - 1] = '\0'; + + return gw_bandwidth_set(net_dev, buff, count); +} + BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); +static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); +BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, + post_gw_deselect); +static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, + store_gw_bwidth); #ifdef CONFIG_BATMAN_ADV_DEBUG BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); #endif @@ -264,8 +376,11 @@ static struct bat_attribute *mesh_attrs[] = { &bat_attr_bonding, &bat_attr_fragmentation, &bat_attr_vis_mode, + &bat_attr_gw_mode, &bat_attr_orig_interval, &bat_attr_hop_penalty, + &bat_attr_gw_sel_class, + &bat_attr_gw_bandwidth, #ifdef CONFIG_BATMAN_ADV_DEBUG &bat_attr_log_level, #endif diff --git a/drivers/staging/batman-adv/gateway_client.c b/drivers/staging/batman-adv/gateway_client.c new file mode 100644 index 000000000000..1846a6219631 --- /dev/null +++ b/drivers/staging/batman-adv/gateway_client.c @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: + * + * Marek Lindner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "main.h" +#include "gateway_client.h" +#include "gateway_common.h" +#include "hard-interface.h" + +static void gw_node_free_ref(struct kref *refcount) +{ + struct gw_node *gw_node; + + gw_node = container_of(refcount, struct gw_node, refcount); + kfree(gw_node); +} + +static void gw_node_free_rcu(struct rcu_head *rcu) +{ + struct gw_node *gw_node; + + gw_node = container_of(rcu, struct gw_node, rcu); + kref_put(&gw_node->refcount, gw_node_free_ref); +} + +void gw_deselect(struct bat_priv *bat_priv) +{ + struct gw_node *gw_node = bat_priv->curr_gw; + + bat_priv->curr_gw = NULL; + + if (gw_node) + kref_put(&gw_node->refcount, gw_node_free_ref); +} + +static struct gw_node *gw_select(struct bat_priv *bat_priv, + struct gw_node *new_gw_node) +{ + struct gw_node *curr_gw_node = bat_priv->curr_gw; + + if (new_gw_node) + kref_get(&new_gw_node->refcount); + + bat_priv->curr_gw = new_gw_node; + return curr_gw_node; +} + +void gw_election(struct bat_priv *bat_priv) +{ + struct hlist_node *node; + struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL; + uint8_t max_tq = 0; + uint32_t max_gw_factor = 0, tmp_gw_factor = 0; + int down, up; + + /** + * The batman daemon checks here if we already passed a full originator + * cycle in order to make sure we don't choose the first gateway we + * hear about. This check is based on the daemon's uptime which we + * don't have. + **/ + if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) + return; + + if (bat_priv->curr_gw) + return; + + rcu_read_lock(); + if (hlist_empty(&bat_priv->gw_list)) { + rcu_read_unlock(); + + if (bat_priv->curr_gw) { + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + gw_deselect(bat_priv); + } + + return; + } + + hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { + if (!gw_node->orig_node->router) + continue; + + if (gw_node->deleted) + continue; + + switch (atomic_read(&bat_priv->gw_sel_class)) { + case 1: /* fast connection */ + gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, + &down, &up); + + tmp_gw_factor = (gw_node->orig_node->router->tq_avg * + gw_node->orig_node->router->tq_avg * + down * 100 * 100) / + (TQ_LOCAL_WINDOW_SIZE * + TQ_LOCAL_WINDOW_SIZE * 64); + + if ((tmp_gw_factor > max_gw_factor) || + ((tmp_gw_factor == max_gw_factor) && + (gw_node->orig_node->router->tq_avg > max_tq))) + curr_gw_tmp = gw_node; + break; + + default: /** + * 2: stable connection (use best statistic) + * 3: fast-switch (use best statistic but change as + * soon as a better gateway appears) + * XX: late-switch (use best statistic but change as + * soon as a better gateway appears which has + * $routing_class more tq points) + **/ + if (gw_node->orig_node->router->tq_avg > max_tq) + curr_gw_tmp = gw_node; + break; + } + + if (gw_node->orig_node->router->tq_avg > max_tq) + max_tq = gw_node->orig_node->router->tq_avg; + + if (tmp_gw_factor > max_gw_factor) + max_gw_factor = tmp_gw_factor; + } + + if (bat_priv->curr_gw != curr_gw_tmp) { + if ((bat_priv->curr_gw) && (!curr_gw_tmp)) + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + else if ((!bat_priv->curr_gw) && (curr_gw_tmp)) + bat_dbg(DBG_BATMAN, bat_priv, + "Adding route to gateway %pM " + "(gw_flags: %i, tq: %i)\n", + curr_gw_tmp->orig_node->orig, + curr_gw_tmp->orig_node->gw_flags, + curr_gw_tmp->orig_node->router->tq_avg); + else + bat_dbg(DBG_BATMAN, bat_priv, + "Changing route to gateway %pM " + "(gw_flags: %i, tq: %i)\n", + curr_gw_tmp->orig_node->orig, + curr_gw_tmp->orig_node->gw_flags, + curr_gw_tmp->orig_node->router->tq_avg); + + old_gw_node = gw_select(bat_priv, curr_gw_tmp); + } + + rcu_read_unlock(); + + /* the kfree() has to be outside of the rcu lock */ + if (old_gw_node) + kref_put(&old_gw_node->refcount, gw_node_free_ref); +} + +void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) +{ + struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; + uint8_t gw_tq_avg, orig_tq_avg; + + if (!curr_gateway_tmp) + return; + + if (!curr_gateway_tmp->orig_node) + goto deselect; + + if (!curr_gateway_tmp->orig_node->router) + goto deselect; + + /* this node already is the gateway */ + if (curr_gateway_tmp->orig_node == orig_node) + return; + + if (!orig_node->router) + return; + + gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; + orig_tq_avg = orig_node->router->tq_avg; + + /* the TQ value has to be better */ + if (orig_tq_avg < gw_tq_avg) + return; + + /** + * if the routing class is greater than 3 the value tells us how much + * greater the TQ value of the new gateway must be + **/ + if ((atomic_read(&bat_priv->gw_sel_class) > 3) && + (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class))) + return; + + bat_dbg(DBG_BATMAN, bat_priv, + "Restarting gateway selection: better gateway found (tq curr: " + "%i, tq new: %i)\n", + gw_tq_avg, orig_tq_avg); + +deselect: + gw_deselect(bat_priv); +} + +static void gw_node_add(struct bat_priv *bat_priv, + struct orig_node *orig_node, uint8_t new_gwflags) +{ + struct gw_node *gw_node; + int down, up; + + gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); + if (!gw_node) + return; + + memset(gw_node, 0, sizeof(struct gw_node)); + INIT_HLIST_NODE(&gw_node->list); + gw_node->orig_node = orig_node; + kref_init(&gw_node->refcount); + + spin_lock_bh(&bat_priv->gw_list_lock); + hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list); + spin_unlock_bh(&bat_priv->gw_list_lock); + + gw_bandwidth_to_kbit(new_gwflags, &down, &up); + bat_dbg(DBG_BATMAN, bat_priv, + "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", + orig_node->orig, new_gwflags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); +} + +void gw_node_update(struct bat_priv *bat_priv, + struct orig_node *orig_node, uint8_t new_gwflags) +{ + struct hlist_node *node; + struct gw_node *gw_node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { + if (gw_node->orig_node != orig_node) + continue; + + bat_dbg(DBG_BATMAN, bat_priv, + "Gateway class of originator %pM changed from " + "%i to %i\n", + orig_node->orig, gw_node->orig_node->gw_flags, + new_gwflags); + + gw_node->deleted = 0; + + if (new_gwflags == 0) { + gw_node->deleted = jiffies; + bat_dbg(DBG_BATMAN, bat_priv, + "Gateway %pM removed from gateway list\n", + orig_node->orig); + + if (gw_node == bat_priv->curr_gw) { + rcu_read_unlock(); + gw_deselect(bat_priv); + return; + } + } + + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + + if (new_gwflags == 0) + return; + + gw_node_add(bat_priv, orig_node, new_gwflags); +} + +void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) +{ + return gw_node_update(bat_priv, orig_node, 0); +} + +void gw_node_purge(struct bat_priv *bat_priv) +{ + struct gw_node *gw_node; + struct hlist_node *node, *node_tmp; + unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + + spin_lock_bh(&bat_priv->gw_list_lock); + + hlist_for_each_entry_safe(gw_node, node, node_tmp, + &bat_priv->gw_list, list) { + if (((!gw_node->deleted) || + (time_before(jiffies, gw_node->deleted + timeout))) && + atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) + continue; + + if (bat_priv->curr_gw == gw_node) + gw_deselect(bat_priv); + + hlist_del_rcu(&gw_node->list); + call_rcu(&gw_node->rcu, gw_node_free_rcu); + } + + + spin_unlock_bh(&bat_priv->gw_list_lock); +} + +static int _write_buffer_text(struct bat_priv *bat_priv, + struct seq_file *seq, struct gw_node *gw_node) +{ + int down, up; + + gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); + + return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", + (bat_priv->curr_gw == gw_node ? "=>" : " "), + gw_node->orig_node->orig, + gw_node->orig_node->router->tq_avg, + gw_node->orig_node->router->addr, + gw_node->orig_node->router->if_incoming->net_dev->name, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); +} + +int gw_client_seq_print_text(struct seq_file *seq, void *offset) +{ + struct net_device *net_dev = (struct net_device *)seq->private; + struct bat_priv *bat_priv = netdev_priv(net_dev); + struct gw_node *gw_node; + struct hlist_node *node; + int gw_count = 0; + + if (!bat_priv->primary_if) { + + return seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + } + + if (bat_priv->primary_if->if_status != IF_ACTIVE) { + + return seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + } + + seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " + "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", + "Gateway", "#", TQ_MAX_VALUE, "Nexthop", + "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, + bat_priv->primary_if->net_dev->name, + bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + + rcu_read_lock(); + hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { + if (gw_node->deleted) + continue; + + if (!gw_node->orig_node->router) + continue; + + _write_buffer_text(bat_priv, seq, gw_node); + gw_count++; + } + rcu_read_unlock(); + + if (gw_count == 0) + seq_printf(seq, "No gateways in range ...\n"); + + return 0; +} diff --git a/drivers/staging/batman-adv/gateway_client.h b/drivers/staging/batman-adv/gateway_client.h new file mode 100644 index 000000000000..7383b903faea --- /dev/null +++ b/drivers/staging/batman-adv/gateway_client.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: + * + * Marek Lindner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ +#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ + +void gw_deselect(struct bat_priv *bat_priv); +void gw_election(struct bat_priv *bat_priv); +void *gw_get_selected(struct bat_priv *bat_priv); +void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); +void gw_node_update(struct bat_priv *bat_priv, + struct orig_node *orig_node, uint8_t new_gwflags); +void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); +void gw_node_purge(struct bat_priv *bat_priv); +int gw_client_seq_print_text(struct seq_file *seq, void *offset); + +#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/drivers/staging/batman-adv/gateway_common.c b/drivers/staging/batman-adv/gateway_common.c new file mode 100644 index 000000000000..b962982f017e --- /dev/null +++ b/drivers/staging/batman-adv/gateway_common.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: + * + * Marek Lindner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "main.h" +#include "gateway_common.h" +#include "gateway_client.h" + +/* calculates the gateway class from kbit */ +static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) +{ + int mdown = 0, tdown, tup, difference; + uint8_t sbit, part; + + *gw_srv_class = 0; + difference = 0x0FFFFFFF; + + /* test all downspeeds */ + for (sbit = 0; sbit < 2; sbit++) { + for (part = 0; part < 16; part++) { + tdown = 32 * (sbit + 2) * (1 << part); + + if (abs(tdown - down) < difference) { + *gw_srv_class = (sbit << 7) + (part << 3); + difference = abs(tdown - down); + mdown = tdown; + } + } + } + + /* test all upspeeds */ + difference = 0x0FFFFFFF; + + for (part = 0; part < 8; part++) { + tup = ((part + 1) * (mdown)) / 8; + + if (abs(tup - up) < difference) { + *gw_srv_class = (*gw_srv_class & 0xF8) | part; + difference = abs(tup - up); + } + } +} + +/* returns the up and downspeeds in kbit, calculated from the class */ +void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) +{ + char sbit = (gw_srv_class & 0x80) >> 7; + char dpart = (gw_srv_class & 0x78) >> 3; + char upart = (gw_srv_class & 0x07); + + if (!gw_srv_class) { + *down = 0; + *up = 0; + return; + } + + *down = 32 * (sbit + 2) * (1 << dpart); + *up = ((upart + 1) * (*down)) / 8; +} + +static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, + long *up, long *down) +{ + int ret, multi = 1; + char *slash_ptr, *tmp_ptr; + + slash_ptr = strchr(buff, '/'); + if (slash_ptr) + *slash_ptr = 0; + + if (strlen(buff) > 4) { + tmp_ptr = buff + strlen(buff) - 4; + + if (strnicmp(tmp_ptr, "mbit", 4) == 0) + multi = 1024; + + if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || + (multi > 1)) + *tmp_ptr = '\0'; + } + + ret = strict_strtoul(buff, 10, down); + if (ret) { + bat_err(net_dev, + "Download speed of gateway mode invalid: %s\n", + buff); + return false; + } + + *down *= multi; + + /* we also got some upload info */ + if (slash_ptr) { + multi = 1; + + if (strlen(slash_ptr + 1) > 4) { + tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); + + if (strnicmp(tmp_ptr, "mbit", 4) == 0) + multi = 1024; + + if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || + (multi > 1)) + *tmp_ptr = '\0'; + } + + ret = strict_strtoul(slash_ptr + 1, 10, up); + if (ret) { + bat_err(net_dev, + "Upload speed of gateway mode invalid: " + "%s\n", slash_ptr + 1); + return false; + } + + *up *= multi; + } + + return true; +} + +ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) +{ + struct bat_priv *bat_priv = netdev_priv(net_dev); + long gw_bandwidth_tmp = 0, up = 0, down = 0; + bool ret; + + ret = parse_gw_bandwidth(net_dev, buff, &up, &down); + if (!ret) + goto end; + + if ((!down) || (down < 256)) + down = 2000; + + if (!up) + up = down / 5; + + kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); + + /** + * the gw bandwidth we guessed above might not match the given + * speeds, hence we need to calculate it back to show the number + * that is going to be propagated + **/ + gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, + (int *)&down, (int *)&up); + + gw_deselect(bat_priv); + bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " + "(propagating: %ld%s/%ld%s)\n", + atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + + atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); + +end: + return count; +} diff --git a/drivers/staging/batman-adv/gateway_common.h b/drivers/staging/batman-adv/gateway_common.h new file mode 100644 index 000000000000..5e728d0b7959 --- /dev/null +++ b/drivers/staging/batman-adv/gateway_common.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: + * + * Marek Lindner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_ +#define _NET_BATMAN_ADV_GATEWAY_COMMON_H_ + +enum gw_modes { + GW_MODE_OFF, + GW_MODE_CLIENT, + GW_MODE_SERVER, +}; + +#define GW_MODE_OFF_NAME "off" +#define GW_MODE_CLIENT_NAME "client" +#define GW_MODE_SERVER_NAME "server" + +void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); +ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count); + +#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 61d1aa66e956..c91e635d3d96 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -29,6 +29,7 @@ #include "icmp_socket.h" #include "translation-table.h" #include "hard-interface.h" +#include "gateway_client.h" #include "types.h" #include "vis.h" #include "hash.h" @@ -84,12 +85,14 @@ int mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->forw_bcast_list_lock); spin_lock_init(&bat_priv->hna_lhash_lock); spin_lock_init(&bat_priv->hna_ghash_lock); + spin_lock_init(&bat_priv->gw_list_lock); spin_lock_init(&bat_priv->vis_hash_lock); spin_lock_init(&bat_priv->vis_list_lock); spin_lock_init(&bat_priv->softif_neigh_lock); INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); + INIT_HLIST_HEAD(&bat_priv->gw_list); INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); if (originator_init(bat_priv) < 1) @@ -129,6 +132,7 @@ void mesh_free(struct net_device *soft_iface) vis_quit(bat_priv); + gw_node_purge(bat_priv); originator_free(bat_priv); hna_local_free(bat_priv); diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index 8bef4681bf82..89ec02100a3b 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -26,6 +26,7 @@ #include "hash.h" #include "translation-table.h" #include "routing.h" +#include "gateway_client.h" #include "hard-interface.h" #include "unicast.h" #include "soft-interface.h" @@ -279,6 +280,8 @@ static void _purge_orig(struct bat_priv *bat_priv) orig_node = bucket->data; if (purge_orig_node(bat_priv, orig_node)) { + if (orig_node->gw_flags) + gw_node_delete(bat_priv, orig_node); hash_remove_bucket(bat_priv->orig_hash, &hashit); free_orig_node(orig_node, bat_priv); } @@ -290,6 +293,9 @@ static void _purge_orig(struct bat_priv *bat_priv) spin_unlock_bh(&bat_priv->orig_hash_lock); + gw_node_purge(bat_priv); + gw_election(bat_priv); + softif_neigh_purge(bat_priv); } diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h index 2693383889a4..b49fdf70a6d5 100644 --- a/drivers/staging/batman-adv/packet.h +++ b/drivers/staging/batman-adv/packet.h @@ -32,7 +32,7 @@ #define BAT_UNICAST_FRAG 0x06 /* this file is included by batctl which needs these defines */ -#define COMPAT_VERSION 13 +#define COMPAT_VERSION 12 #define DIRECTLINK 0x40 #define VIS_SERVER 0x20 #define PRIMARIES_FIRST_HOP 0x10 @@ -61,6 +61,8 @@ struct batman_packet { uint8_t prev_sender[6]; uint8_t ttl; uint8_t num_hna; + uint8_t gw_flags; /* flags related to gateway class */ + uint8_t align; } __attribute__((packed)); #define BAT_PACKET_LEN sizeof(struct batman_packet) diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 1536963dd69f..9f31167a9058 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -32,6 +32,8 @@ #include "ring_buffer.h" #include "vis.h" #include "aggregation.h" +#include "gateway_common.h" +#include "gateway_client.h" #include "unicast.h" void slide_own_bcast_window(struct batman_if *batman_if) @@ -316,11 +318,23 @@ static void update_orig(struct bat_priv *bat_priv, update_routes(bat_priv, orig_node, neigh_node, hna_buff, tmp_hna_buff_len); - return; + goto update_gw; update_hna: update_routes(bat_priv, orig_node, orig_node->router, hna_buff, tmp_hna_buff_len); + +update_gw: + if (orig_node->gw_flags != batman_packet->gw_flags) + gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); + + orig_node->gw_flags = batman_packet->gw_flags; + + /* restart gateway selection if fast or late switching was enabled */ + if ((orig_node->gw_flags) && + (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && + (atomic_read(&bat_priv->gw_sel_class) > 2)) + gw_check_election(bat_priv, orig_node); } /* checks whether the host restarted and is in the protection time. diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index 9ed77d7bbca0..36945dc5a44b 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -28,6 +28,7 @@ #include "types.h" #include "vis.h" #include "aggregation.h" +#include "gateway_common.h" #include "originator.h" @@ -284,6 +285,13 @@ void schedule_own_packet(struct batman_if *batman_if) else batman_packet->flags &= ~VIS_SERVER; + if ((batman_if == bat_priv->primary_if) && + (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) + batman_packet->gw_flags = + (uint8_t)atomic_read(&bat_priv->gw_bandwidth); + else + batman_packet->gw_flags = 0; + atomic_inc(&batman_if->seqno); slide_own_bcast_window(batman_if); diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 28ffe34919d3..64eaf2a56fb0 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -28,6 +28,7 @@ #include "translation-table.h" #include "types.h" #include "hash.h" +#include "gateway_common.h" #include "send.h" #include "bat_sysfs.h" #include @@ -579,6 +580,9 @@ struct net_device *softif_create(char *name) atomic_set(&bat_priv->aggregated_ogms, 1); atomic_set(&bat_priv->bonding, 0); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); + atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); + atomic_set(&bat_priv->gw_sel_class, 20); + atomic_set(&bat_priv->gw_bandwidth, 41); atomic_set(&bat_priv->orig_interval, 1000); atomic_set(&bat_priv->hop_penalty, 10); atomic_set(&bat_priv->log_level, 0); diff --git a/drivers/staging/batman-adv/sysfs-class-net-mesh b/drivers/staging/batman-adv/sysfs-class-net-mesh index bd20e14261c0..748fe1701d25 100644 --- a/drivers/staging/batman-adv/sysfs-class-net-mesh +++ b/drivers/staging/batman-adv/sysfs-class-net-mesh @@ -22,6 +22,27 @@ Description: mesh will be fragmented or silently discarded if the packet size exceeds the outgoing interface MTU. +What: /sys/class/net//mesh/gw_bandwidth +Date: October 2010 +Contact: Marek Lindner +Description: + Defines the bandwidth which is propagated by this + node if gw_mode was set to 'server'. + +What: /sys/class/net//mesh/gw_mode +Date: October 2010 +Contact: Marek Lindner +Description: + Defines the state of the gateway features. Can be + either 'off', 'client' or 'server'. + +What: /sys/class/net//mesh/gw_sel_class +Date: October 2010 +Contact: Marek Lindner +Description: + Defines the selection criteria this node will use + to choose a gateway if gw_mode was set to 'client'. + What: /sys/class/net//mesh/orig_interval Date: May 2010 Contact: Marek Lindner diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index e41f95fbf61f..1d0084995c7c 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -55,6 +55,7 @@ struct batman_if { * @last_valid: when last packet from this node was received * @bcast_seqno_reset: time when the broadcast seqno window was reset * @batman_seqno_reset: time when the batman seqno window was reset + * @gw_flags: flags related to gateway class * @flags: for now only VIS_SERVER flag * @last_real_seqno: last and best known squence number * @last_ttl: ttl of last received packet @@ -74,7 +75,8 @@ struct orig_node { unsigned long last_valid; unsigned long bcast_seqno_reset; unsigned long batman_seqno_reset; - uint8_t flags; + uint8_t gw_flags; + uint8_t flags; unsigned char *hna_buff; int16_t hna_buff_len; uint32_t last_real_seqno; @@ -90,6 +92,14 @@ struct orig_node { } bond; }; +struct gw_node { + struct hlist_node list; + struct orig_node *orig_node; + unsigned long deleted; + struct kref refcount; + struct rcu_head rcu; +}; + /** * neigh_node * @last_valid: when last packet via this neighbor was received @@ -117,6 +127,9 @@ struct bat_priv { atomic_t bonding; /* boolean */ atomic_t fragmentation; /* boolean */ atomic_t vis_mode; /* VIS_TYPE_* */ + atomic_t gw_mode; /* GW_MODE_* */ + atomic_t gw_sel_class; /* uint */ + atomic_t gw_bandwidth; /* gw bandwidth */ atomic_t orig_interval; /* uint */ atomic_t hop_penalty; /* uint */ atomic_t log_level; /* uint */ @@ -132,6 +145,7 @@ struct bat_priv { struct dentry *debug_dir; struct hlist_head forw_bat_list; struct hlist_head forw_bcast_list; + struct hlist_head gw_list; struct list_head vis_send_list; struct hashtable_t *orig_hash; struct hashtable_t *hna_local_hash; @@ -142,6 +156,7 @@ struct bat_priv { spinlock_t forw_bcast_list_lock; /* protects */ spinlock_t hna_lhash_lock; /* protects hna_local_hash */ spinlock_t hna_ghash_lock; /* protects hna_global_hash */ + spinlock_t gw_list_lock; /* protects gw_list */ spinlock_t vis_hash_lock; /* protects vis_hash */ spinlock_t vis_list_lock; /* protects vis_info::recv_list */ spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ @@ -150,6 +165,7 @@ struct bat_priv { struct delayed_work hna_work; struct delayed_work orig_work; struct delayed_work vis_work; + struct gw_node *curr_gw; struct vis_info *my_vis_info; }; -- cgit v1.2.3 From 6c3a42db6ca46204b35f0cdb8abfa9e4771641ef Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:56:03 +0100 Subject: Staging: batman-adv: send DHCP requests directly to the chosen gw If the gateway client mode is active batman-adv will send the broadcasted DHCP requests via unicast to the currently selected best gateway. Therefore attached clients can profit from batman's knowledge about the network topology. Signed-off-by: Marek Lindner [sven.eckelmann@gmx.de: Rework on top of current version] Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/gateway_client.c | 60 +++++++++++++++++++++++++++++ drivers/staging/batman-adv/gateway_client.h | 1 + drivers/staging/batman-adv/soft-interface.c | 14 ++++++- drivers/staging/batman-adv/unicast.c | 12 ++++-- 4 files changed, 82 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/gateway_client.c b/drivers/staging/batman-adv/gateway_client.c index 1846a6219631..3d4e1096a9dc 100644 --- a/drivers/staging/batman-adv/gateway_client.c +++ b/drivers/staging/batman-adv/gateway_client.c @@ -23,6 +23,9 @@ #include "gateway_client.h" #include "gateway_common.h" #include "hard-interface.h" +#include +#include +#include static void gw_node_free_ref(struct kref *refcount) { @@ -40,6 +43,16 @@ static void gw_node_free_rcu(struct rcu_head *rcu) kref_put(&gw_node->refcount, gw_node_free_ref); } +void *gw_get_selected(struct bat_priv *bat_priv) +{ + struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; + + if (!curr_gateway_tmp) + return NULL; + + return curr_gateway_tmp->orig_node; +} + void gw_deselect(struct bat_priv *bat_priv) { struct gw_node *gw_node = bat_priv->curr_gw; @@ -385,3 +398,50 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) return 0; } + +int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) +{ + struct ethhdr *ethhdr; + struct iphdr *iphdr; + struct udphdr *udphdr; + unsigned int header_len = 0; + + if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) + return 0; + + /* check for ethernet header */ + if (!pskb_may_pull(skb, header_len + ETH_HLEN)) + return 0; + ethhdr = (struct ethhdr *)skb->data; + header_len += ETH_HLEN; + + /* check for ip header */ + if (ntohs(ethhdr->h_proto) != ETH_P_IP) + return 0; + + if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) + return 0; + iphdr = (struct iphdr *)(skb->data + header_len); + header_len += iphdr->ihl * 4; + + /* check for udp header */ + if (iphdr->protocol != IPPROTO_UDP) + return 0; + + if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) + return 0; + udphdr = (struct udphdr *)(skb->data + header_len); + header_len += sizeof(struct udphdr); + + /* check for bootp port */ + if (ntohs(udphdr->dest) != 67) + return 0; + + if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) + return -1; + + if (!bat_priv->curr_gw) + return 0; + + return 1; +} diff --git a/drivers/staging/batman-adv/gateway_client.h b/drivers/staging/batman-adv/gateway_client.h index 7383b903faea..4585e6549844 100644 --- a/drivers/staging/batman-adv/gateway_client.h +++ b/drivers/staging/batman-adv/gateway_client.h @@ -31,5 +31,6 @@ void gw_node_update(struct bat_priv *bat_priv, void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); void gw_node_purge(struct bat_priv *bat_priv); int gw_client_seq_print_text(struct seq_file *seq, void *offset); +int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 64eaf2a56fb0..9b968df185d1 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -29,6 +29,7 @@ #include "types.h" #include "hash.h" #include "gateway_common.h" +#include "gateway_client.h" #include "send.h" #include "bat_sysfs.h" #include @@ -346,6 +347,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) struct vlan_ethhdr *vhdr; int data_len = skb->len, ret; short vid = -1; + bool do_bcast = false; if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dropped; @@ -376,8 +378,18 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) /* TODO: check this for locks */ hna_local_add(soft_iface, ethhdr->h_source); - /* ethernet packet should be broadcasted */ if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { + ret = gw_is_target(bat_priv, skb); + + if (ret < 0) + goto dropped; + + if (ret == 0) + do_bcast = true; + } + + /* ethernet packet should be broadcasted */ + if (do_bcast) { if (!bat_priv->primary_if) goto dropped; diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 3b62d998a2f1..7b9385b658c8 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -23,6 +23,7 @@ #include "unicast.h" #include "send.h" #include "soft-interface.h" +#include "gateway_client.h" #include "originator.h" #include "hash.h" #include "translation-table.h" @@ -282,10 +283,13 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) spin_lock_bh(&bat_priv->orig_hash_lock); /* get routing information */ - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, - choose_orig, - ethhdr->h_dest)); + if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) + orig_node = (struct orig_node *)gw_get_selected(bat_priv); + else + orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, + compare_orig, + choose_orig, + ethhdr->h_dest)); /* check for hna host */ if (!orig_node) -- cgit v1.2.3 From c9c556b63b19c8b52de5c5ea6f47ab16fc540e47 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:56:04 +0100 Subject: Staging: batman-adv: best gw DHCP filter 802.1Q support The DHCP filter inspects packets to determine whether or not to send them via ethernet unicast. This patch adds 802.1Q (vlan) support for this check. Signed-off-by: Marek Lindner [sven.eckelmann@gmx.de: Rework on top of current version] Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/gateway_client.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/gateway_client.c b/drivers/staging/batman-adv/gateway_client.c index 3d4e1096a9dc..fde1d8a952fd 100644 --- a/drivers/staging/batman-adv/gateway_client.c +++ b/drivers/staging/batman-adv/gateway_client.c @@ -415,6 +415,14 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) ethhdr = (struct ethhdr *)skb->data; header_len += ETH_HLEN; + /* check for initial vlan header */ + if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { + if (!pskb_may_pull(skb, header_len + VLAN_HLEN)) + return 0; + ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); + header_len += VLAN_HLEN; + } + /* check for ip header */ if (ntohs(ethhdr->h_proto) != ETH_P_IP) return 0; -- cgit v1.2.3 From 003db3b2ad61c2964d624b0786cf8202e9a92c8e Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Nov 2010 00:56:05 +0100 Subject: Staging: batman-adv: add gateway IPv6 support by filtering DHCPv6 messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some additional checks will be needed in case of extension headers like the fragmentation or hop-by-hop (for jumbo frames for example) headers or ipsec stuff. But this patch should do for most people for now, the rest can be added with a later one. Signed-off-by: Marek Lindner Acked-by: Linus Lüssing Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/gateway_client.c | 40 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/gateway_client.c b/drivers/staging/batman-adv/gateway_client.c index fde1d8a952fd..0065ffb8d96d 100644 --- a/drivers/staging/batman-adv/gateway_client.c +++ b/drivers/staging/batman-adv/gateway_client.c @@ -24,6 +24,7 @@ #include "gateway_common.h" #include "hard-interface.h" #include +#include #include #include @@ -403,6 +404,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) { struct ethhdr *ethhdr; struct iphdr *iphdr; + struct ipv6hdr *ipv6hdr; struct udphdr *udphdr; unsigned int header_len = 0; @@ -424,17 +426,32 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) } /* check for ip header */ - if (ntohs(ethhdr->h_proto) != ETH_P_IP) - return 0; + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_IP: + if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) + return 0; + iphdr = (struct iphdr *)(skb->data + header_len); + header_len += iphdr->ihl * 4; - if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) - return 0; - iphdr = (struct iphdr *)(skb->data + header_len); - header_len += iphdr->ihl * 4; + /* check for udp header */ + if (iphdr->protocol != IPPROTO_UDP) + return 0; + + break; + case ETH_P_IPV6: + if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr))) + return 0; + ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); + header_len += sizeof(struct ipv6hdr); - /* check for udp header */ - if (iphdr->protocol != IPPROTO_UDP) + /* check for udp header */ + if (ipv6hdr->nexthdr != IPPROTO_UDP) + return 0; + + break; + default: return 0; + } if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) return 0; @@ -442,7 +459,12 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) header_len += sizeof(struct udphdr); /* check for bootp port */ - if (ntohs(udphdr->dest) != 67) + if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && + (ntohs(udphdr->dest) != 67)) + return 0; + + if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && + (ntohs(udphdr->dest) != 547)) return 0; if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) -- cgit v1.2.3 From 8cab2fbe6dacfdd3b122c450d2fffde6ac06a8b6 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:56:06 +0100 Subject: Staging: batman-adv: Use kernel version min macro The kernel headers already provide different versions of a min/max macro which should be used by all modules according to Documentation/CodingStyle. Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index ff0ac9825001..4f95777ce080 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -31,8 +31,6 @@ #include -#define MIN(x, y) ((x) < (y) ? (x) : (y)) - /* protect update critical side of if_list - but not the content */ static DEFINE_SPINLOCK(if_list_lock); @@ -220,8 +218,8 @@ int hardif_min_mtu(struct net_device *soft_iface) if (batman_if->soft_iface != soft_iface) continue; - min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN, - min_mtu); + min_mtu = min_t(int, batman_if->net_dev->mtu - BAT_HEADER_LEN, + min_mtu); } rcu_read_unlock(); out: -- cgit v1.2.3 From 951c44e0dbfaa580d5b4fb13427ab93ee252636a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 22 Nov 2010 00:56:07 +0100 Subject: Staging: batman-adv: Use kernel functions to identify broadcasts linux/etherdevice.h already provides functions to classify different ethernet addresses. These inlineable functions should be used instead of custom functions. The check for multicast together with multicast can also be replaced with a single test for multicast because for every ethernet address x following is always true: is_broadcast_ether_addr(x) => is_multicast_ether_addr(x) or when looking more at the implementation: (FF:FF:FF:FF:FF:FF == x) => [(01:00:00:00:00:00 & x) != 00:00:00:00:00:00] Reported-by: Tobias Klauser Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/main.c | 10 ---------- drivers/staging/batman-adv/main.h | 3 +-- drivers/staging/batman-adv/routing.c | 16 ++++++++-------- drivers/staging/batman-adv/soft-interface.c | 2 +- drivers/staging/batman-adv/unicast.c | 2 +- drivers/staging/batman-adv/vis.c | 4 ++-- 6 files changed, 13 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index c91e635d3d96..b827f6a158cb 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -172,16 +172,6 @@ int is_my_mac(uint8_t *addr) } -int is_bcast(uint8_t *addr) -{ - return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff); -} - -int is_mcast(uint8_t *addr) -{ - return *addr & 0x01; -} - module_init(batman_init); module_exit(batman_exit); diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h index 3ee1eb0a7253..6b60c33a8b77 100644 --- a/drivers/staging/batman-adv/main.h +++ b/drivers/staging/batman-adv/main.h @@ -109,6 +109,7 @@ #include /* mutex */ #include /* needed by all modules */ #include /* netdevice */ +#include /* ethernet address classifaction */ #include /* ethernet header */ #include /* poll_table */ #include /* kernel threads */ @@ -136,8 +137,6 @@ void mesh_free(struct net_device *soft_iface); void inc_module_count(void); void dec_module_count(void); int is_my_mac(uint8_t *addr); -int is_bcast(uint8_t *addr); -int is_mcast(uint8_t *addr); #ifdef CONFIG_BATMAN_ADV_DEBUG int debug_log(struct bat_priv *bat_priv, char *fmt, ...); diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 9f31167a9058..d8b0c5a6d5df 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -770,11 +770,11 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) + if (!is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP; /* create a copy of the skb, if needed, to modify it. */ @@ -946,11 +946,11 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) + if (is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP; /* not for me */ @@ -1118,11 +1118,11 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ - if (is_bcast(ethhdr->h_dest)) + if (is_broadcast_ether_addr(ethhdr->h_dest)) return -1; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return -1; /* not for me */ @@ -1282,11 +1282,11 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ - if (!is_bcast(ethhdr->h_dest)) + if (!is_broadcast_ether_addr(ethhdr->h_dest)) return NET_RX_DROP; /* packet with broadcast sender address */ - if (is_bcast(ethhdr->h_source)) + if (is_broadcast_ether_addr(ethhdr->h_source)) return NET_RX_DROP; /* ignore broadcasts sent by myself */ diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 9b968df185d1..e89ede192ed0 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -378,7 +378,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) /* TODO: check this for locks */ hna_local_add(soft_iface, ethhdr->h_source); - if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { + if (is_multicast_ether_addr(ethhdr->h_dest)) { ret = gw_is_target(bat_priv, skb); if (ret < 0) diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c index 7b9385b658c8..dc2e28bed844 100644 --- a/drivers/staging/batman-adv/unicast.c +++ b/drivers/staging/batman-adv/unicast.c @@ -283,7 +283,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) spin_lock_bh(&bat_priv->orig_hash_lock); /* get routing information */ - if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) + if (is_multicast_ether_addr(ethhdr->h_dest)) orig_node = (struct orig_node *)gw_get_selected(bat_priv); else orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c index 65676dcd40ed..957a08624ff8 100644 --- a/drivers/staging/batman-adv/vis.c +++ b/drivers/staging/batman-adv/vis.c @@ -472,7 +472,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv, int are_target = 0; /* clients shall not broadcast. */ - if (is_bcast(vis_packet->target_orig)) + if (is_broadcast_ether_addr(vis_packet->target_orig)) return; /* Are we the target for this VIS packet? */ @@ -755,7 +755,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) ETH_ALEN); packet->ttl--; - if (is_bcast(packet->target_orig)) + if (is_broadcast_ether_addr(packet->target_orig)) broadcast_vis_packet(bat_priv, info); else unicast_vis_packet(bat_priv, info); -- cgit v1.2.3 From 964c6975e8a4314c451d420f1cb54880ab535433 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 22 Nov 2010 10:33:28 +0000 Subject: Staging: sst: Add runtime PM support This adds runtime PM support for audio driver. This also fixes LPA audio mode for moorestown platform Signed-off-by: Vinod Koul Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst.c | 43 ++++++++++++++++++++-- .../staging/intel_sst/intel_sst_app_interface.c | 13 ++++++- drivers/staging/intel_sst/intel_sst_common.h | 1 + .../staging/intel_sst/intel_sst_drv_interface.c | 16 ++++++-- drivers/staging/intel_sst/intel_sst_dsp.c | 3 +- drivers/staging/intel_sst/intel_sst_ipc.c | 1 + 6 files changed, 69 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c index 0ba6742d9236..bd92549893a6 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/drivers/staging/intel_sst/intel_sst.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "intel_sst.h" #include "intel_sst_ioctl.h" @@ -320,6 +321,9 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, } } sst_drv_ctx->lpe_stalled = 0; + pm_runtime_set_active(&pci->dev); + pm_runtime_enable(&pci->dev); + pm_runtime_allow(&pci->dev); pr_debug("...successfully done!!!\n"); return ret; @@ -408,8 +412,10 @@ int intel_sst_suspend(struct pci_dev *pci, pm_message_t state) pr_debug("intel_sst_suspend called\n"); - if (sst_drv_ctx->pb_streams != 0 || sst_drv_ctx->cp_streams != 0) - return -EPERM; + if (sst_drv_ctx->stream_cnt) { + pr_err("active streams,not able to suspend\n"); + return -EBUSY; + } /*Assert RESET on LPE Processor*/ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); csr.full = csr.full | 0x2; @@ -439,7 +445,7 @@ int intel_sst_resume(struct pci_dev *pci) pr_debug("intel_sst_resume called\n"); if (sst_drv_ctx->sst_state != SST_SUSPENDED) { pr_err("SST is not in suspended state\n"); - return -EPERM; + return 0; } sst_drv_ctx = pci_get_drvdata(pci); pci_set_power_state(pci, PCI_D0); @@ -454,6 +460,34 @@ int intel_sst_resume(struct pci_dev *pci) return 0; } +static int intel_sst_runtime_suspend(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + pr_debug("runtime_suspend called\n"); + return intel_sst_suspend(pci_dev, PMSG_SUSPEND); +} + +static int intel_sst_runtime_resume(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + pr_debug("runtime_resume called\n"); + return intel_sst_resume(pci_dev); +} + +static int intel_sst_runtime_idle(struct device *dev) +{ + pr_debug("runtime_idle called\n"); + if (sst_drv_ctx->stream_cnt == 0 && sst_drv_ctx->am_cnt == 0) + pm_schedule_suspend(dev, SST_SUSPEND_DELAY); + return -EBUSY; +} + +static const struct dev_pm_ops intel_sst_pm = { + .runtime_suspend = intel_sst_runtime_suspend, + .runtime_resume = intel_sst_runtime_resume, + .runtime_idle = intel_sst_runtime_idle, +}; + /* PCI Routines */ static struct pci_device_id intel_sst_ids[] = { { PCI_VDEVICE(INTEL, SST_MRST_PCI_ID), 3}, @@ -470,6 +504,9 @@ static struct pci_driver driver = { #ifdef CONFIG_PM .suspend = intel_sst_suspend, .resume = intel_sst_resume, + .driver = { + .pm = &intel_sst_pm, + }, #endif }; diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index c1ca39ef3646..4b316ccab411 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_MRST_RAR_HANDLER @@ -103,8 +104,10 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr) unsigned int retval; mutex_lock(&sst_drv_ctx->stream_lock); + pm_runtime_get_sync(&sst_drv_ctx->pci->dev); retval = intel_sst_check_device(); if (retval) { + pm_runtime_put(&sst_drv_ctx->pci->dev); mutex_unlock(&sst_drv_ctx->stream_lock); return retval; } @@ -113,6 +116,7 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr) struct ioctl_pvt_data *data = kzalloc(sizeof(struct ioctl_pvt_data), GFP_KERNEL); if (!data) { + pm_runtime_put(&sst_drv_ctx->pci->dev); mutex_unlock(&sst_drv_ctx->stream_lock); return -ENOMEM; } @@ -125,6 +129,7 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr) pr_debug("pvt_id handle = %d!\n", data->pvt_id); } else { retval = -EUSERS; + pm_runtime_put(&sst_drv_ctx->pci->dev); mutex_unlock(&sst_drv_ctx->stream_lock); } return retval; @@ -147,8 +152,10 @@ int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr) /* audio manager open */ mutex_lock(&sst_drv_ctx->stream_lock); + pm_runtime_get_sync(&sst_drv_ctx->pci->dev); retval = intel_sst_check_device(); if (retval) { + pm_runtime_put(&sst_drv_ctx->pci->dev); mutex_unlock(&sst_drv_ctx->stream_lock); return retval; } @@ -157,8 +164,10 @@ int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr) sst_drv_ctx->am_cnt++; pr_debug("AM handle opened...\n"); file_ptr->private_data = NULL; - } else + } else { retval = -EACCES; + pm_runtime_put(&sst_drv_ctx->pci->dev); + } mutex_unlock(&sst_drv_ctx->stream_lock); return retval; @@ -181,6 +190,7 @@ int intel_sst_release(struct inode *i_node, struct file *file_ptr) mutex_lock(&sst_drv_ctx->stream_lock); sst_drv_ctx->encoded_cnt--; sst_drv_ctx->stream_cnt--; + pm_runtime_put(&sst_drv_ctx->pci->dev); mutex_unlock(&sst_drv_ctx->stream_lock); free_stream_context(data->str_id); kfree(data); @@ -192,6 +202,7 @@ int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr) /* audio manager close */ mutex_lock(&sst_drv_ctx->stream_lock); sst_drv_ctx->am_cnt--; + pm_runtime_put(&sst_drv_ctx->pci->dev); mutex_unlock(&sst_drv_ctx->stream_lock); pr_debug("AM handle closed\n"); return 0; diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h index dcc1ebbe1ac6..a82882423d2d 100644 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ b/drivers/staging/intel_sst/intel_sst_common.h @@ -37,6 +37,7 @@ #define SST_FW_FILENAME_MFLD "fw_sst_082f.bin" #define SST_MRST_PCI_ID 0x080A #define SST_MFLD_PCI_ID 0x082F +#define SST_SUSPEND_DELAY 2000 enum sst_states { SST_FW_LOADED = 1, diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index 9ecbff60cacf..f91c914ba209 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "intel_sst.h" #include "intel_sst_ioctl.h" #include "intel_sst_fw_ipc.h" @@ -310,12 +311,15 @@ int sst_open_pcm_stream(struct snd_sst_params *str_param) struct stream_info *str_info; int retval; + pm_runtime_get_sync(&sst_drv_ctx->pci->dev); + if (sst_drv_ctx->sst_state == SST_SUSPENDED) { - /*LPE is suspended, resume it before proceding*/ + /* LPE is suspended, resume it before proceding*/ pr_debug("Resuming from Suspended state\n"); retval = intel_sst_resume(sst_drv_ctx->pci); if (retval) { pr_err("Resume Failed = %#x, abort\n", retval); + pm_runtime_put(&sst_drv_ctx->pci->dev); return retval; } } @@ -325,20 +329,25 @@ int sst_open_pcm_stream(struct snd_sst_params *str_param) retval = sst_download_fw(); if (retval) { pr_err("FW download fail %x, abort\n", retval); + pm_runtime_put(&sst_drv_ctx->pci->dev); return retval; } send_intial_rx_timeslot(); } - if (!str_param) + if (!str_param) { + pm_runtime_put(&sst_drv_ctx->pci->dev); return -EINVAL; + } retval = sst_get_stream(str_param); if (retval > 0) { sst_drv_ctx->stream_cnt++; str_info = &sst_drv_ctx->streams[retval]; str_info->src = MAD_DRV; - } + } else + pm_runtime_put(&sst_drv_ctx->pci->dev); + return retval; } @@ -364,6 +373,7 @@ int sst_close_pcm_stream(unsigned int str_id) stream->period_elapsed = NULL; sst_drv_ctx->stream_cnt--; pr_debug("sst: will call runtime put now\n"); + pm_runtime_put(&sst_drv_ctx->pci->dev); return 0; } diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c index d1b0537cf4b8..6e5c9152da9f 100644 --- a/drivers/staging/intel_sst/intel_sst_dsp.c +++ b/drivers/staging/intel_sst/intel_sst_dsp.c @@ -51,7 +51,8 @@ static int intel_sst_reset_dsp_mrst(void) union config_status_reg csr; pr_debug("Resetting the DSP in mrst\n"); - csr.full = 0x3a2; + csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); + csr.full |= 0x382; sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR); csr.part.strb_cntr_rst = 0; diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c index 993c5333e906..5aa92ba9018c 100644 --- a/drivers/staging/intel_sst/intel_sst_ipc.c +++ b/drivers/staging/intel_sst/intel_sst_ipc.c @@ -182,6 +182,7 @@ int process_fw_init(struct sst_ipc_msg_wq *msg) sst_send_sound_card_type(); mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_FW_RUNNING; + sst_drv_ctx->lpe_stalled = 0; mutex_unlock(&sst_drv_ctx->sst_lock); pr_debug("FW Version %x.%x\n", init->fw_version.major, init->fw_version.minor); -- cgit v1.2.3 From 79a35ad57300f78c7250eeeca57b602e06ff402a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 22 Nov 2010 10:33:40 +0000 Subject: Staging: sst: Construct fw string name runtime The firmware name for each platform is appended by PCI id of device. This patch makes use of pci id to construct the string rather than hardcode the string. Signed-off-by: Vinod Koul Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst_common.h | 3 +-- drivers/staging/intel_sst/intel_sst_drv_interface.c | 11 ++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h index a82882423d2d..e0c6339ca0ae 100644 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ b/drivers/staging/intel_sst/intel_sst_common.h @@ -33,10 +33,9 @@ /* driver names */ #define SST_DRV_NAME "intel_sst_driver" -#define SST_FW_FILENAME_MRST "fw_sst_080a.bin" -#define SST_FW_FILENAME_MFLD "fw_sst_082f.bin" #define SST_MRST_PCI_ID 0x080A #define SST_MFLD_PCI_ID 0x082F +#define PCI_ID_LENGTH 4 #define SST_SUSPEND_DELAY 2000 enum sst_states { diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index f91c914ba209..ea8e251b5099 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -48,13 +48,14 @@ int sst_download_fw(void) { int retval; const struct firmware *fw_sst; - const char *name; + char name[20]; + if (sst_drv_ctx->sst_state != SST_UN_INIT) return -EPERM; - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) - name = SST_FW_FILENAME_MRST; - else - name = SST_FW_FILENAME_MFLD; + + snprintf(name, sizeof(name), "%s%04x%s", "fw_sst_", + sst_drv_ctx->pci_id, ".bin"); + pr_debug("Downloading %s FW now...\n", name); retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev); if (retval) { -- cgit v1.2.3 From 62877913ba55b3f2e5ac34dbc1a2975868ea8d25 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 22 Nov 2010 10:33:51 +0000 Subject: Staging: sst: add ioctls for post processing algorithm interface This patch adds two new ioctls to intel_sst_ctrl device. This i/f can be used by application to send algorithm parameters Signed-off-by: Vinod Koul [This will need further discussion in the context of the final ALSA interface but is fine for staging, ie anyone who relies on it should expect changes Also fixed a missing kmalloc fail check] Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst.c | 27 ++-- .../staging/intel_sst/intel_sst_app_interface.c | 143 +++++++++++++++++++++ drivers/staging/intel_sst/intel_sst_common.h | 2 +- drivers/staging/intel_sst/intel_sst_fw_ipc.h | 2 + drivers/staging/intel_sst/intel_sst_ioctl.h | 15 +-- drivers/staging/intel_sst/intel_sst_ipc.c | 49 +++++++ 6 files changed, 215 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c index bd92549893a6..ce4a9f79ccd2 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/drivers/staging/intel_sst/intel_sst.c @@ -306,19 +306,19 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, goto do_unmap_dram; pr_debug("Registered IRQ 0x%x\n", pci->irq); + /*Register LPE Control as misc driver*/ + ret = misc_register(&lpe_ctrl); + if (ret) { + pr_err("couldn't register control device\n"); + goto do_free_irq; + } + if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { ret = misc_register(&lpe_dev); if (ret) { - pr_err("couldn't register LPE device\n"); - goto do_free_irq; - } - - /*Register LPE Control as misc driver*/ - ret = misc_register(&lpe_ctrl); - if (ret) { - pr_err("couldn't register misc driver\n"); - goto do_free_irq; - } + pr_err("couldn't register misc driver\n"); + goto do_free_misc; + } } sst_drv_ctx->lpe_stalled = 0; pm_runtime_set_active(&pci->dev); @@ -327,6 +327,8 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, pr_debug("...successfully done!!!\n"); return ret; +do_free_misc: + misc_deregister(&lpe_ctrl); do_free_irq: free_irq(pci->irq, sst_drv_ctx); do_unmap_dram: @@ -371,10 +373,9 @@ static void __devexit intel_sst_remove(struct pci_dev *pci) mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_UN_INIT; mutex_unlock(&sst_drv_ctx->sst_lock); - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { + misc_deregister(&lpe_ctrl); + if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) misc_deregister(&lpe_dev); - misc_deregister(&lpe_ctrl); - } free_irq(pci->irq, sst_drv_ctx); iounmap(sst_drv_ctx->dram); iounmap(sst_drv_ctx->iram); diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index 4b316ccab411..ce2c755a1766 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c @@ -827,6 +827,141 @@ static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm) return; } +/** + * sst_create_algo_ipc - create ipc msg for algorithm parameters + * + * @algo_params: Algorithm parameters + * @msg: post msg pointer + * + * This function is called to create ipc msg + */ +int sst_create_algo_ipc(struct snd_ppp_params *algo_params, + struct ipc_post **msg) +{ + if (sst_create_large_msg(msg)) + return -ENOMEM; + sst_fill_header(&(*msg)->header, + IPC_IA_ALG_PARAMS, 1, algo_params->str_id); + (*msg)->header.part.data = sizeof(u32) + + sizeof(*algo_params) + algo_params->size; + memcpy((*msg)->mailbox_data, &(*msg)->header, sizeof(u32)); + memcpy((*msg)->mailbox_data + sizeof(u32), + algo_params, sizeof(*algo_params)); + return 0; +} + +/** + * sst_send_algo_ipc - send ipc msg for algorithm parameters + * + * @msg: post msg pointer + * + * This function is called to send ipc msg + */ +int sst_send_algo_ipc(struct ipc_post **msg) +{ + sst_drv_ctx->ppp_params_blk.condition = false; + sst_drv_ctx->ppp_params_blk.ret_code = 0; + sst_drv_ctx->ppp_params_blk.on = true; + sst_drv_ctx->ppp_params_blk.data = NULL; + spin_lock(&sst_drv_ctx->list_spin_lock); + list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list); + spin_unlock(&sst_drv_ctx->list_spin_lock); + sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); + return sst_wait_interruptible_timeout(sst_drv_ctx, + &sst_drv_ctx->ppp_params_blk, SST_BLOCK_TIMEOUT); +} + +/** + * intel_sst_ioctl_dsp - recieves the device ioctl's + * + * @cmd:Ioctl cmd + * @arg:data + * + * This function is called when a user space component + * sends a DSP Ioctl to SST driver + */ +long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg) +{ + int retval = 0; + struct snd_ppp_params algo_params; + struct snd_ppp_params *algo_params_copied; + struct ipc_post *msg; + + switch (_IOC_NR(cmd)) { + case _IOC_NR(SNDRV_SST_SET_ALGO): + if (copy_from_user(&algo_params, (void __user *)arg, + sizeof(algo_params))) + return -EFAULT; + if (algo_params.size > SST_MAILBOX_SIZE) + return -EMSGSIZE; + + pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", + algo_params.algo_id, algo_params.str_id, + algo_params.enable, algo_params.size); + retval = sst_create_algo_ipc(&algo_params, &msg); + if (retval) + break; + algo_params.reserved = 0; + if (copy_from_user(msg->mailbox_data + sizeof(algo_params), + algo_params.params, algo_params.size)) + return -EFAULT; + + retval = sst_send_algo_ipc(&msg); + if (retval) { + pr_debug("Error in sst_set_algo = %d\n", retval); + retval = -EIO; + } + break; + + case _IOC_NR(SNDRV_SST_GET_ALGO): + if (copy_from_user(&algo_params, (void __user *)arg, + sizeof(algo_params))) + return -EFAULT; + pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", + algo_params.algo_id, algo_params.str_id, + algo_params.enable, algo_params.size); + retval = sst_create_algo_ipc(&algo_params, &msg); + if (retval) + break; + algo_params.reserved = 1; + retval = sst_send_algo_ipc(&msg); + if (retval) { + pr_debug("Error in sst_get_algo = %d\n", retval); + retval = -EIO; + break; + } + algo_params_copied = (struct snd_ppp_params *) + sst_drv_ctx->ppp_params_blk.data; + if (algo_params_copied->size > algo_params.size) { + pr_debug("mem insufficient to copy\n"); + retval = -EMSGSIZE; + goto free_mem; + } else { + char __user *tmp; + + if (copy_to_user(algo_params.params, + algo_params_copied->params, + algo_params_copied->size)) { + retval = -EFAULT; + goto free_mem; + } + tmp = (char __user *)arg + offsetof( + struct snd_ppp_params, size); + if (copy_to_user(tmp, &algo_params_copied->size, + sizeof(__u32))) { + retval = -EFAULT; + goto free_mem; + } + + } +free_mem: + kfree(algo_params_copied->params); + kfree(algo_params_copied); + break; + } + return retval; +} + /** * intel_sst_ioctl - receives the device ioctl's * @file_ptr:pointer to file @@ -1270,6 +1405,14 @@ free_iobufs: kfree(fw_info); break; } + case _IOC_NR(SNDRV_SST_GET_ALGO): + case _IOC_NR(SNDRV_SST_SET_ALGO): + if (minor != AM_MODULE) { + retval = -EBADRQC; + break; + } + retval = intel_sst_ioctl_dsp(cmd, arg); + break; default: retval = -EINVAL; } diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h index e0c6339ca0ae..0a60e865b696 100644 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ b/drivers/staging/intel_sst/intel_sst_common.h @@ -392,7 +392,7 @@ struct intel_sst_drv { struct stream_info streams[MAX_NUM_STREAMS]; struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM]; - struct sst_block tgt_dev_blk, fw_info_blk, + struct sst_block tgt_dev_blk, fw_info_blk, ppp_params_blk, vol_info_blk, mute_info_blk, hs_info_blk; struct mutex list_lock;/* mutex for IPC list locking */ spinlock_t list_spin_lock; /* mutex for IPC list locking */ diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h index 75c187672450..8df313d10d2a 100644 --- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h +++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h @@ -68,6 +68,8 @@ #define IPC_IA_CAPT_VOICE 0x17 #define IPC_IA_DECODE_FRAMES 0x18 +#define IPC_IA_ALG_PARAMS 0x1A + /* I2L Stream config/control msgs */ #define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */ #define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */ diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/drivers/staging/intel_sst/intel_sst_ioctl.h index 03b931619a3e..bebc395a3c1f 100644 --- a/drivers/staging/intel_sst/intel_sst_ioctl.h +++ b/drivers/staging/intel_sst/intel_sst_ioctl.h @@ -190,21 +190,15 @@ struct snd_prp_params { __u32 reserved; /* No pre-processing defined yet */ }; -struct snd_params_block { - __u32 type; /*Type of the parameter*/ - __u32 size; /*size of the parameters in the block*/ - __u8 params[0]; /*Parameters of the algorithm*/ -}; - /* Pre and post processing params structure */ struct snd_ppp_params { - enum sst_algo_types algo_id;/* Post/Pre processing algorithm ID */ + __u8 algo_id;/* Post/Pre processing algorithm ID */ __u8 str_id; /*Only 5 bits used 0 - 31 are valid*/ __u8 enable; /* 0= disable, 1= enable*/ __u8 reserved; __u32 size; /*Size of parameters for all blocks*/ - struct snd_params_block params[0]; -}; + void *params; +} __attribute__ ((packed)); struct snd_sst_postproc_info { __u32 src_min; /* Supported SRC Min sampling freq */ @@ -431,5 +425,8 @@ struct snd_sst_dbufs { #define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *) #define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \ struct snd_sst_target_device *) +/*DSP Ioctls on /dev/intel_sst_ctrl only*/ +#define SNDRV_SST_SET_ALGO _IOW('L', 0x30, struct snd_ppp_params *) +#define SNDRV_SST_GET_ALGO _IOWR('L', 0x31, struct snd_ppp_params *) #endif /* __INTEL_SST_IOCTL_H__ */ diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c index 5aa92ba9018c..0742dde2685d 100644 --- a/drivers/staging/intel_sst/intel_sst_ipc.c +++ b/drivers/staging/intel_sst/intel_sst_ipc.c @@ -336,6 +336,55 @@ void sst_process_reply(struct work_struct *work) wake_up(&sst_drv_ctx->wait_queue); } break; + case IPC_IA_ALG_PARAMS: { + pr_debug("sst:IPC_ALG_PARAMS response %x\n", msg->header.full); + pr_debug("sst: data value %x\n", msg->header.part.data); + pr_debug("sst: large value %x\n", msg->header.part.large); + + if (!msg->header.part.large) { + if (!msg->header.part.data) { + pr_debug("sst: alg set success\n"); + sst_drv_ctx->ppp_params_blk.ret_code = 0; + } else { + pr_debug("sst: alg set failed\n"); + sst_drv_ctx->ppp_params_blk.ret_code = + -msg->header.part.data; + } + + } else if (msg->header.part.data) { + struct snd_ppp_params *mailbox_params, *get_params; + char *params; + + pr_debug("sst: alg get success\n"); + mailbox_params = (struct snd_ppp_params *)msg->mailbox; + get_params = kzalloc(sizeof(*get_params), GFP_KERNEL); + if (get_params == NULL) { + pr_err("sst: out of memory for ALG PARAMS"); + break; + } + memcpy_fromio(get_params, mailbox_params, + sizeof(*get_params)); + get_params->params = kzalloc(mailbox_params->size, + GFP_KERNEL); + if (get_params->params == NULL) { + kfree(get_params); + pr_err("sst: out of memory for ALG PARAMS block"); + break; + } + params = msg->mailbox; + params = params + sizeof(*mailbox_params) - sizeof(u32); + memcpy_fromio(get_params->params, params, + get_params->size); + sst_drv_ctx->ppp_params_blk.ret_code = 0; + sst_drv_ctx->ppp_params_blk.data = get_params; + } + + if (sst_drv_ctx->ppp_params_blk.on == true) { + sst_drv_ctx->ppp_params_blk.condition = true; + wake_up(&sst_drv_ctx->wait_queue); + } + break; + } case IPC_IA_GET_FW_INFO: { struct snd_sst_fw_info *fw_info = (struct snd_sst_fw_info *)msg->mailbox; -- cgit v1.2.3 From de92e3a3b25dd0cda00a07b30c325785b5c2d939 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:33:26 +0000 Subject: Staging: sep: minimal fix for wrong include Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h index 686a353c8c98..68688cbc2a92 100644 --- a/drivers/staging/sep/sep_driver_config.h +++ b/drivers/staging/sep/sep_driver_config.h @@ -421,7 +421,7 @@ struct RAR_buffer { #else /* using real RAR_REGISTER */ -#include "../rar_register/rar_register.h" +#include #endif /* CONFIG_RAR_REGISTER */ -- cgit v1.2.3 From 62a8c3a32e4143812ed8e0f3783ef1ea40dc87e4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:33:43 +0000 Subject: Staging: sep: handle the rar definition stuff in the header SEP isn't the only driver that may need to handle both cases easily Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 1 + drivers/staging/sep/sep_driver_config.h | 61 --------------------------------- include/linux/rar_register.h | 16 +++++++++ 3 files changed, 17 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index ef36239c7b24..8a1ff861b135 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h index 68688cbc2a92..cfda86f2aaff 100644 --- a/drivers/staging/sep/sep_driver_config.h +++ b/drivers/staging/sep/sep_driver_config.h @@ -235,15 +235,6 @@ held by the proccess (struct file) */ /* This stub header is for non Moorestown driver only */ -/* - * Constants that specify different kinds of RAR regions that could be - * set up. - */ -static __u32 const RAR_TYPE_VIDEO; /* 0 */ -static __u32 const RAR_TYPE_AUDIO = 1; -static __u32 const RAR_TYPE_IMAGE = 2; -static __u32 const RAR_TYPE_DATA = 3; - /* * @struct RAR_stat * @@ -373,56 +364,4 @@ struct RAR_buffer { #endif /* MEMRAR */ -/* rar_register */ -#ifndef CONFIG_RAR_REGISTER -/* This stub header is for non Moorestown driver only */ - -/* The register_rar function is to used by other device drivers - * to ensure that this driver is ready. As we cannot be sure of - * the compile/execute order of dirvers in ther kernel, it is - * best to give this driver a callback function to call when - * it is ready to give out addresses. The callback function - * would have those steps that continue the initialization of - * a driver that do require a valid RAR address. One of those - * steps would be to call get_rar_address() - * This function return 0 on success an -1 on failure. - */ -#define register_rar(a, b, c) (-ENODEV) - -/* The get_rar_address function is used by other device drivers - * to obtain RAR address information on a RAR. It takes two - * parameter: - * - * int rar_index - * The rar_index is an index to the rar for which you wish to retrieve - * the address information. - * Values can be 0,1, or 2. - * - * struct RAR_address_struct is a pointer to a place to which the function - * can return the address structure for the RAR. - * - * The function returns a 0 upon success or a -1 if there is no RAR - * facility on this system. - */ -#define rar_get_address(a, b, c) (-ENODEV) - -/* The lock_rar function is ued by other device drivers to lock an RAR. - * once an RAR is locked, it stays locked until the next system reboot. - * The function takes one parameter: - * - * int rar_index - * The rar_index is an index to the rar that you want to lock. - * Values can be 0,1, or 2. - * - * The function returns a 0 upon success or a -1 if there is no RAR - * facility on this system. - */ -#define rar_lock(a) (-1) - -#else /* using real RAR_REGISTER */ - -#include - -#endif /* CONFIG_RAR_REGISTER */ - #endif /* SEP DRIVER CONFIG */ diff --git a/include/linux/rar_register.h b/include/linux/rar_register.h index ffa805780f85..5c6118189363 100644 --- a/include/linux/rar_register.h +++ b/include/linux/rar_register.h @@ -34,11 +34,27 @@ struct rar_device; +#if defined(CONFIG_RAR_REGISTER) int register_rar(int num, int (*callback)(unsigned long data), unsigned long data); void unregister_rar(int num); int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end); int rar_lock(int rar_index); +#else +extern void unregister_rar(int num) { } +extern int rar_lock(int rar_index) { return -EIO; } + +extern inline int register_rar(int num, + int (*callback)(unsigned long data), unsigned long data) +{ + return -ENODEV; +} + +extern int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end) +{ + return -ENODEV; +} +#endif /* RAR_REGISTER */ #endif /* __KERNEL__ */ #endif /* _RAR_REGISTER_H */ -- cgit v1.2.3 From 266aa856f2c3aeddadd2fcf186d119af10539c3e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:33:55 +0000 Subject: Staging: sep: handle the memrar stuff in the headers Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/memrar/memrar.h | 19 +++++ drivers/staging/sep/sep_driver.c | 2 + drivers/staging/sep/sep_driver_config.h | 133 -------------------------------- 3 files changed, 21 insertions(+), 133 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/memrar/memrar.h b/drivers/staging/memrar/memrar.h index 0b735b827c09..0feb73b94c91 100644 --- a/drivers/staging/memrar/memrar.h +++ b/drivers/staging/memrar/memrar.h @@ -95,6 +95,7 @@ struct RAR_buffer { dma_addr_t bus_address; }; +#if defined(CONFIG_MRST_RAR_HANDLER) /** * rar_reserve() - reserve RAR buffers * @buffers: array of RAR_buffers where type and size of buffers to @@ -149,7 +150,25 @@ extern size_t rar_release(struct RAR_buffer *buffers, extern size_t rar_handle_to_bus(struct RAR_buffer *buffers, size_t count); +#else +extern inline size_t rar_reserve(struct RAR_buffer *buffers, size_t count) +{ + return 0; +} + +extern inline size_t rar_release(struct RAR_buffer *buffers, size_t count) +{ + return 0; +} + +extern inline size_t rar_handle_to_bus(struct RAR_buffer *buffers, + size_t count) +{ + return 0; +} + +#endif /* MRST_RAR_HANDLER */ #endif /* __KERNEL__ */ #endif /* _MEMRAR_H */ diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 8a1ff861b135..b2cf553da341 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -59,6 +59,8 @@ #include #include +#include "../memrar/memrar.h" + #include "sep_driver_hw_defs.h" #include "sep_driver_config.h" #include "sep_driver_api.h" diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h index cfda86f2aaff..b96045f178cd 100644 --- a/drivers/staging/sep/sep_driver_config.h +++ b/drivers/staging/sep/sep_driver_config.h @@ -230,138 +230,5 @@ held by the proccess (struct file) */ /* the token that defines the data pool pointers address */ #define SEP_EXT_CACHE_ADDR_VAL_TOKEN 0xBABABABA -/* rar handler */ -#ifndef CONFIG_MRST_RAR_HANDLER - -/* This stub header is for non Moorestown driver only */ - -/* - * @struct RAR_stat - * - * @brief This structure is used for @c RAR_HANDLER_STAT ioctl and for - * @c RAR_get_stat() user space wrapper function. - */ -struct RAR_stat { - /* Type of RAR memory (e.g., audio vs. video) */ - __u32 type; - - /* - * Total size of RAR memory region. - */ - __u32 capacity; - - /* Size of the largest reservable block. */ - __u32 largest_block_size; -}; - - -/* - * @struct RAR_block_info - * - * @brief The argument for the @c RAR_HANDLER_RESERVE @c ioctl. - * - */ -struct RAR_block_info { - /* Type of RAR memory (e.g., audio vs. video) */ - __u32 type; - - /* Requested size of a block to be reserved in RAR. */ - __u32 size; - - /* Handle that can be used to refer to reserved block. */ - __u32 handle; -}; - -/* - * @struct RAR_buffer - * - * Structure that contains all information related to a given block of - * memory in RAR. It is generally only used when retrieving bus - * addresses. - * - * @note This structure is used only by RAR-enabled drivers, and is - * not intended to be exposed to the user space. - */ -struct RAR_buffer { - /* Structure containing base RAR buffer information */ - struct RAR_block_info info; - - /* Buffer bus address */ - __u32 bus_address; -}; - - -#define RAR_IOCTL_BASE 0xE0 - -/* Reserve RAR block. */ -#define RAR_HANDLER_RESERVE _IOWR(RAR_IOCTL_BASE, 0x00, struct RAR_block_info) - -/* Release previously reserved RAR block. */ -#define RAR_HANDLER_RELEASE _IOW(RAR_IOCTL_BASE, 0x01, __u32) - -/* Get RAR stats. */ -#define RAR_HANDLER_STAT _IOWR(RAR_IOCTL_BASE, 0x02, struct RAR_stat) - - -/* -------------------------------------------------------------- */ -/* Kernel Side RAR Handler Interface */ -/* -------------------------------------------------------------- */ - -/* - * @function rar_reserve - * - * @brief Reserve RAR buffers. - * - * This function will reserve buffers in the restricted access regions - * of given types. - * - * @return Number of successfully reserved buffers. - * Successful buffer reservations will have the corresponding - * @c bus_address field set to a non-zero value in the - * given @a buffers vector. - */ -#define rar_reserve(a, b) ((size_t)NULL) - -/* - * @function rar_release - * - * @brief Release RAR buffers retrieved through call to - * @c rar_reserve() or @c rar_handle_to_bus(). - * - * This function will release RAR buffers that were retrieved through - * a call to @c rar_reserve() or @c rar_handle_to_bus() by - * decrementing the reference count. The RAR buffer will be reclaimed - * when the reference count drops to zero. - * - * @return Number of successfully released buffers. - * Successful releases will have their handle field set to - * zero in the given @a buffers vector. - */ -#define rar_release(a, b) ((size_t)NULL) - -/* - * @function rar_handle_to_bus - * - * @brief Convert a vector of RAR handles to bus addresses. - * - * This function will retrieve the RAR buffer bus addresses, type and - * size corresponding to the RAR handles provided in the @a buffers - * vector. - * - * @return Number of successfully converted buffers. - * The bus address will be set to @c 0 for unrecognized - * handles. - * - * @note The reference count for each corresponding buffer in RAR will - * be incremented. Call @c rar_release() when done with the - * buffers. - */ -#define rar_handle_to_bus(a, b) ((size_t)NULL) - -#else /* using rear memrar */ - -#include "../memrar/memrar.h" - -#endif /* MEMRAR */ #endif /* SEP DRIVER CONFIG */ -- cgit v1.2.3 From 8d80e4e2da31be71b8c1a5def986e10831d2aada Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:34:08 +0000 Subject: Staging: sep: netlink - what netlink Kill unused stuff Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index b2cf553da341..38b2db49c403 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -55,10 +55,6 @@ #include #include -#include -#include -#include - #include "../memrar/memrar.h" #include "sep_driver_hw_defs.h" @@ -943,23 +939,11 @@ static unsigned long sep_set_time(struct sep_device *sep) */ static int sep_init_caller_id(struct sep_device *sep) { - /* return value */ - int ret_val; - - /* counter */ int counter; - struct cb_id caller_id; - dev_dbg(&sep->pdev->dev, "sep_init_caller_id start\n"); - ret_val = 0; - - /* init cb_id struct */ - caller_id.idx = CN_IDX_PROC; - caller_id.val = CN_VAL_PROC; - /** * init caller id table * note that locking is not needed here as this function is @@ -975,16 +959,10 @@ static int sep_init_caller_id(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "caller id table init finished\n"); - /* register to netlink connector */ - - if (ret_val) - dev_warn(&sep->pdev->dev, - "cn_add_callback failed %x\n", ret_val); - dev_dbg(&sep->pdev->dev, "sep_init_caller_id end\n"); - return ret_val; + return 0; } /** -- cgit v1.2.3 From 4c8e2a1f3d5e6b63ebfd26f324a2b24194af37fa Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:34:25 +0000 Subject: Staging: sep: clean up caller_id function This is called on a kmalloc/memset object. Remove everything that isn't a set to zero Oh look 8) Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 42 ---------------------------------------- 1 file changed, 42 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 38b2db49c403..c98cb9b481bd 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -933,38 +933,6 @@ static unsigned long sep_set_time(struct sep_device *sep) return time.tv_sec; } -/** - * sep_init_caller_id - initializes the caller id functionality - * @sep: pointer to struct sep_device - */ -static int sep_init_caller_id(struct sep_device *sep) -{ - int counter; - - dev_dbg(&sep->pdev->dev, - "sep_init_caller_id start\n"); - - /** - * init caller id table - * note that locking is not needed here as this function is - * called prior to registering the device file - */ - for (counter = 0; counter < SEP_CALLER_ID_TABLE_NUM_ENTRIES; counter++) - sep->caller_id_table[counter].pid = 0; - - - /* init access flag */ - sep->singleton_access_flag = 0; - - dev_dbg(&sep->pdev->dev, - "caller id table init finished\n"); - - dev_dbg(&sep->pdev->dev, - "sep_init_caller_id end\n"); - - return 0; -} - /** * sep_set_caller_id_handler - inserts the data into the caller id table * note that this function does fall under the ioctl lock @@ -4056,16 +4024,6 @@ static int __init sep_init(void) mutex_init(&sep->sep_mutex); mutex_init(&sep->ioctl_mutex); - if (sep->mrst == 0) { - ret_val = sep_init_caller_id(sep); - if (ret_val) { - dev_warn(&sep->pdev->dev, - "cant init caller id\n"); - goto end_function_unregister_pci; - } - - } - /* new chip requires share area reconfigure */ if (sep->pdev->revision == 4) { /* only for new chip */ ret_val = sep_reconfig_shared_area(sep); -- cgit v1.2.3 From d1bb83213d5b7b3a4e3db59179917a433f82762c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:34:52 +0000 Subject: Staging: sep: Fix the kernel-doc in SEP The long blurb goes at the end Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 322 +++++++++++++++++++++++---------------- 1 file changed, 188 insertions(+), 134 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index c98cb9b481bd..4a0bb4350424 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -78,9 +78,10 @@ static struct sep_device *sep_dev; /** * sep_load_firmware - copy firmware cache/resident + * @sep: pointer to struct sep_device we are loading + * * This functions copies the cache and resident from their source * location into destination shared memory. - * @sep: pointer to struct sep_device */ static int sep_load_firmware(struct sep_device *sep) @@ -228,10 +229,11 @@ static void sep_unmap_and_free_shared_area(struct sep_device *sep) /** * sep_shared_bus_to_virt - convert bus/virt addresses - * Returns virtual address inside the shared area according - * to the bus address. * @sep: pointer to struct sep_device * @bus_address: address to convert + * + * Returns virtual address inside the shared area according + * to the bus address. */ static void *sep_shared_bus_to_virt(struct sep_device *sep, @@ -244,6 +246,8 @@ static void *sep_shared_bus_to_virt(struct sep_device *sep, * open function for the singleton driver * @inode_ptr struct inode * * @file_ptr struct file * + * + * Called when the user opens the singleton device interface */ static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) @@ -252,8 +256,8 @@ static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) struct sep_device *sep; - /** - * get the sep device structure and use it for the + /* + * Get the sep device structure and use it for the * private_data field in filp for other methods */ sep = sep_dev; @@ -282,8 +286,7 @@ end_function: * @filp: file handle to sep device * * Open method for the SEP device. Called when userspace opens - * the SEP device node. Must also release the memory data pool - * allocations. + * the SEP device node. * * Returns zero on success otherwise an error code. */ @@ -292,8 +295,8 @@ static int sep_open(struct inode *inode, struct file *filp) { struct sep_device *sep; - /** - * get the sep device structure and use it for the + /* + * Get the sep device structure and use it for the * private_data field in filp for other methods */ sep = sep_dev; @@ -301,7 +304,7 @@ static int sep_open(struct inode *inode, struct file *filp) dev_dbg(&sep->pdev->dev, "Open for pid %d\n", current->pid); - /* anyone can open; locking takes place at transaction level */ + /* Anyone can open; locking takes place at transaction level */ return 0; } @@ -333,8 +336,7 @@ static int sep_singleton_release(struct inode *inode, struct file *filp) * @filp: file handle to sep device * * Open method for the SEP request daemon. Called when - * request daemon in userspace opens - * the SEP device node. + * request daemon in userspace opens the SEP device node. * * Returns zero on success otherwise an error code. */ @@ -385,9 +387,11 @@ static int sep_request_daemon_release(struct inode *inode, struct file *filp) } /** + * sep_req_daemon_send_reply_command_handler - poke the SEP + * @sep: struct sep_device * + * * This function raises interrupt to SEPm that signals that is has a * new command from HOST - * @sep: struct sep_device * */ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) { @@ -427,9 +431,10 @@ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) /** - * sep_free_dma_table_data_handler - handles the request - * for freeing dma table for synhronic actions + * sep_free_dma_table_data_handler - free DMA table * @sep: pointere to struct sep_device + * + * Handles the request to free dma table for synchronic actions */ static int sep_free_dma_table_data_handler(struct sep_device *sep) @@ -531,10 +536,12 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) /** - * sep_request_daemon_mmap - maps the - * shared area to user space + * sep_request_daemon_mmap - maps the shared area to user space * @filp: pointer to struct file * @vma: pointer to vm_area_struct + * + * Called by the kernel when the daemon attempts an mmap() syscall + * using our handle. */ static int sep_request_daemon_mmap(struct file *filp, struct vm_area_struct *vma) @@ -577,10 +584,12 @@ end_function: } /** - * sep_request_daemon_poll - + * sep_request_daemon_poll - poll implementation * @sep: struct sep_device * for current sep device * @filp: struct file * for open file * @wait: poll_table * for poll + * + * Called when our device is part of a poll() or select() syscall */ static unsigned int sep_request_daemon_poll(struct file *filp, poll_table *wait) @@ -689,6 +698,8 @@ static int sep_release(struct inode *inode, struct file *filp) * sep_mmap - maps the shared area to user space * @filp: pointer to struct file * @vma: pointer to vm_area_struct + * + * Called on an mmap of our space via the normal sep device */ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) { @@ -776,9 +787,12 @@ end_function: } /** - * sep_poll - + * sep_poll - poll handler * @filp: pointer to struct file * @wait: pointer to poll_table + * + * Called by the OS when the kernel is asked to do a poll on + * a SEP file handle. */ static unsigned int sep_poll(struct file *filp, poll_table *wait) { @@ -792,7 +806,7 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) dev_dbg(&sep->pdev->dev, "poll: start\n"); - /* am I the process that own the transaction? */ + /* Am I the process that owns the transaction? */ mutex_lock(&sep->sep_mutex); if (current->pid != sep->pid_doing_transaction) { dev_warn(&sep->pdev->dev, "poll; wrong pid\n"); @@ -934,10 +948,12 @@ static unsigned long sep_set_time(struct sep_device *sep) } /** - * sep_set_caller_id_handler - inserts the data into the caller id table - * note that this function does fall under the ioctl lock + * sep_set_caller_id_handler - insert caller id entry * @sep: sep device * @arg: pointer to struct caller_id_struct + * + * Inserts the data into the caller id table. Note that this function + * falls under the ioctl lock */ static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) { @@ -1003,9 +1019,11 @@ end_function: } /** - * sep_set_current_caller_id - set the caller id (if exists) to the sep - * note that this function does fall under the ioctl lock + * sep_set_current_caller_id - set the caller id * @sep: pointer to struct_sep + * + * Set the caller ID (if it exists) to the sep. Note that this + * function falls under the ioctl lock */ static int sep_set_current_caller_id(struct sep_device *sep) { @@ -1040,10 +1058,12 @@ static int sep_set_current_caller_id(struct sep_device *sep) /** * sep_send_command_handler - kick off a command - * note that this function does fall under the ioctl lock + * @sep: sep being signalled + * * This function raises interrupt to SEP that signals that is has a new * command from the host - * @sep: sep being signalled + * + * Note that this function does fall under the ioctl lock */ static int sep_send_command_handler(struct sep_device *sep) @@ -1085,14 +1105,15 @@ end_function: } /** - * sep_allocate_data_pool_memory_handler - + * sep_allocate_data_pool_memory_handler -allocate pool memory + * @sep: pointer to struct_sep + * @arg: pointer to struct alloc_struct + * * This function handles the allocate data pool memory request * This function returns calculates the bus address of the * allocated memory, and the offset of this area from the mapped address. * Therefore, the FVOs in user space can calculate the exact virtual * address of this allocated memory - * @sep: pointer to struct_sep - * @arg: pointer to struct alloc_struct */ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, unsigned long arg) @@ -1100,7 +1121,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, int error = 0; struct alloc_struct command_args; - /* holds the allocated buffer address in the system memory pool */ + /* Holds the allocated buffer address in the system memory pool */ u32 *token_addr; dev_dbg(&sep->pdev->dev, @@ -1112,7 +1133,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, goto end_function; } - /* allocate memory */ + /* Allocate memory */ if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { error = -ENOMEM; @@ -1123,14 +1144,14 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, "bytes_allocated: %x\n", (int)sep->data_pool_bytes_allocated); dev_dbg(&sep->pdev->dev, "offset: %x\n", SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES); - /* set the virtual and bus address */ + /* Set the virtual and bus address */ command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; dev_dbg(&sep->pdev->dev, "command_args.offset: %x\n", command_args.offset); - /* place in the shared area that is known by the sep */ + /* Place in the shared area that is known by the sep */ token_addr = (u32 *)(sep->shared_addr + SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES + (sep->num_of_data_allocations)*2*sizeof(u32)); @@ -1148,7 +1169,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "data pool token [0] %x\n", token_addr[0]); dev_dbg(&sep->pdev->dev, "data pool token [1] %x\n", token_addr[1]); - /* write the memory back to the user space */ + /* Write the memory back to the user space */ error = copy_to_user((void *)arg, (void *)&command_args, sizeof(struct alloc_struct)); if (error) { @@ -1175,17 +1196,18 @@ end_function: } /** - * sep_lock_kernel_pages - - * This function locks all the physical pages of the kernel virtual buffer - * and construct a basic lli array, where each entry holds the physical - * page address and the size that application data holds in this page - * This function is used only during kernel crypto mod calls from within - * the kernel (when ioctl is not used) + * sep_lock_kernel_pages - map kernel pages for DMA * @sep: pointer to struct sep_device * @kernel_virt_addr: address of data buffer in kernel * @data_size: size of data * @lli_array_ptr: lli array * @in_out_flag: input into device or output from device + * + * This function locks all the physical pages of the kernel virtual buffer + * and construct a basic lli array, where each entry holds the physical + * page address and the size that application data holds in this page + * This function is used only during kernel crypto mod calls from within + * the kernel (when ioctl is not used) */ static int sep_lock_kernel_pages(struct sep_device *sep, u32 kernel_virt_addr, @@ -1273,16 +1295,17 @@ end_function: } /** - * sep_lock_user_pages - - * This function locks all the physical pages of the application - * virtual buffer and construct a basic lli array, where each entry - * holds the physical page address and the size that application - * data holds in this physical pages + * sep_lock_user_pages - lock and map user pages for DMA * @sep: pointer to struct sep_device * @app_virt_addr: user memory data buffer * @data_size: size of data buffer * @lli_array_ptr: lli array * @in_out_flag: input or output to device + * + * This function locks all the physical pages of the application + * virtual buffer and construct a basic lli array, where each entry + * holds the physical page address and the size that application + * data holds in this physical pages */ static int sep_lock_user_pages(struct sep_device *sep, u32 app_virt_addr, @@ -1505,17 +1528,16 @@ end_function: } /** - * u32 sep_calculate_lli_table_max_size - - * this function calculates the size of data - * that can be inserted into the lli - * table from this array the condition is that - * either the table is full - * (all etnries are entered), or there are no more - * entries in the lli array + * u32 sep_calculate_lli_table_max_size - size the LLI table * @sep: pointer to struct sep_device * @lli_in_array_ptr * @num_array_entries * @last_table_flag + * + * This function calculates the size of data that can be inserted into + * the lli table from this array, such that either the table is full + * (all entries are entered), or there are no more entries in the + * lli array */ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, struct sep_lli_entry *lli_in_array_ptr, @@ -1590,15 +1612,16 @@ end_function: } /** - * sep_build_lli_table - - * this functions builds ont lli table from the lli_array according to - * the given size of data + * sep_build_lli_table - build an lli array for the given table * @sep: pointer to struct sep_device * @lli_array_ptr: pointer to lli array * @lli_table_ptr: pointer to lli table * @num_processed_entries_ptr: pointer to number of entries * @num_table_entries_ptr: pointer to number of tables * @table_data_size: total data size + * + * Builds ant lli table from the lli_array according to + * the given size of data */ static void sep_build_lli_table(struct sep_device *sep, struct sep_lli_entry *lli_array_ptr, @@ -1707,13 +1730,14 @@ static void sep_build_lli_table(struct sep_device *sep, } /** - * sep_shared_area_virt_to_bus - + * sep_shared_area_virt_to_bus - map shared area to bus address + * @sep: pointer to struct sep_device + * @virt_address: virtual address to convert + * * This functions returns the physical address inside shared area according * to the virtual address. It can be either on the externa RAM device * (ioremapped), or on the system RAM * This implementation is for the external RAM - * @sep: pointer to struct sep_device - * @virt_address: virtual address to convert */ static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep, void *virt_address) @@ -1731,13 +1755,14 @@ static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep, } /** - * sep_shared_area_bus_to_virt - + * sep_shared_area_bus_to_virt - map shared area bus address to kernel + * @sep: pointer to struct sep_device + * @bus_address: bus address to convert + * * This functions returns the virtual address inside shared area * according to the physical address. It can be either on the * externa RAM device (ioremapped), or on the system RAM * This implementation is for the external RAM - * @sep: pointer to struct sep_device - * @bus_address: bus address to convert */ static void *sep_shared_area_bus_to_virt(struct sep_device *sep, @@ -1754,13 +1779,13 @@ static void *sep_shared_area_bus_to_virt(struct sep_device *sep, } /** - * sep_debug_print_lli_tables - - * this function goes over the list of the print created tables and - * prints all the data + * sep_debug_print_lli_tables - dump LLI table * @sep: pointer to struct sep_device * @lli_table_ptr: pointer to sep_lli_entry * @num_table_entries: number of entries * @table_data_size: total data size + * + * Walk the the list of the print created tables and print all the data */ static void sep_debug_print_lli_tables(struct sep_device *sep, struct sep_lli_entry *lli_table_ptr, @@ -1831,12 +1856,14 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, /** - * sep_prepare_empty_lli_table - - * This function creates empty lli tables when there is no data + * sep_prepare_empty_lli_table - create a blank LLI table * @sep: pointer to struct sep_device * @lli_table_addr_ptr: pointer to lli table * @num_entries_ptr: pointer to number of entries * @table_data_size_ptr: point to table data size + * + * This function creates empty lli tables when there is no data + */ static void sep_prepare_empty_lli_table(struct sep_device *sep, dma_addr_t *lli_table_addr_ptr, @@ -1881,11 +1908,7 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep, } /** - * sep_prepare_input_dma_table - - * This function prepares only input DMA table for synhronic symmetric - * operations (HASH) - * Note that all bus addresses that are passed to the sep - * are in 32 bit format; the SEP is a 32 bit device + * sep_prepare_input_dma_table - prepare input DMA mappings * @sep: pointer to struct sep_device * @data_size: * @block_size: @@ -1893,6 +1916,11 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep, * @num_entries_ptr: * @table_data_size_ptr: * @is_kva: set for kernel data (kernel cryptio call) + * + * This function prepares only input DMA table for synhronic symmetric + * operations (HASH) + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_dma_table(struct sep_device *sep, unsigned long app_virt_addr, @@ -2099,12 +2127,7 @@ end_function: } /** - * sep_construct_dma_tables_from_lli - - * This function creates the input and output dma tables for - * symmetric operations (AES/DES) according to the block - * size from LLI arays - * Note that all bus addresses that are passed to the sep - * are in 32 bit format; the SEP is a 32 bit device + * sep_construct_dma_tables_from_lli - prepare AES/DES mappings * @sep: pointer to struct_sep * @lli_in_array: * @sep_in_lli_entries: @@ -2116,6 +2139,12 @@ end_function: * @in_num_entries_ptr * @out_num_entries_ptr * @table_data_size_ptr + * + * This function creates the input and output dma tables for + * symmetric operations (AES/DES) according to the block + * size from LLI arays + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device */ static int sep_construct_dma_tables_from_lli( struct sep_device *sep, @@ -2358,12 +2387,7 @@ static int sep_construct_dma_tables_from_lli( } /** - * sep_prepare_input_output_dma_table - - * This function builds input and output DMA tables for synhronic - * symmetric operations (AES, DES, HASH). It also checks that each table - * is of the modular block size - * Note that all bus addresses that are passed to the sep - * are in 32 bit format; the SEP is a 32 bit device + * sep_prepare_input_output_dma_table - prepare DMA I/O table * @app_virt_in_addr: * @app_virt_out_addr: * @data_size: @@ -2374,6 +2398,12 @@ static int sep_construct_dma_tables_from_lli( * @out_num_entries_ptr: * @table_data_size_ptr: * @is_kva: set for kernel data; used only for kernel crypto module + * + * This function builds input and output DMA tables for synhronic + * symmetric operations (AES, DES, HASH). It also checks that each table + * is of the modular block size + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_output_dma_table(struct sep_device *sep, unsigned long app_virt_in_addr, @@ -2522,12 +2552,7 @@ end_function: } /** - * sep_prepare_input_output_dma_table_in_dcb - - * This function prepares the linked dma tables and puts the - * address for the linked list of tables inta a dcb (data control - * block) the address of which is known by the sep hardware - * Note that all bus addresses that are passed to the sep - * are in 32 bit format; the SEP is a 32 bit device + * sep_prepare_input_output_dma_table_in_dcb - prepare control blocks * @app_in_address: unsigned long; for data buffer in (user space) * @app_out_address: unsigned long; for data buffer out (user space) * @data_in_size: u32; for size of data @@ -2535,6 +2560,12 @@ end_function: * @tail_block_size: u32; for size of tail block * @isapplet: bool; to indicate external app * @is_kva: bool; kernel buffer; only used for kernel crypto module + * + * This function prepares the linked dma tables and puts the + * address for the linked list of tables inta a dcb (data control + * block) the address of which is known by the sep hardware + * Note that all bus addresses that are passed to the sep + * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, u32 app_in_address, @@ -2737,14 +2768,14 @@ end_function: /** - * sep_create_sync_dma_tables_handler - - * this function handles tha request for creation of the DMA table - * for the synchronic symmetric operations (AES,DES) - * Note that all bus addresses that are passed to the sep - * are in 32 bit format; the SEP is a 32 bit device + * sep_create_sync_dma_tables_handler - create sync dma tables * @sep: pointer to struct sep_device * @arg: pointer to struct bld_syn_tab_struct -*/ + * + * Handle the request for creation of the DMA tables for the synchronic + * symmetric operations (AES,DES). Note that all bus addresses that are + * passed to the SEP are in 32 bit format; the SEP is a 32 bit device + */ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, unsigned long arg) { @@ -2799,11 +2830,12 @@ end_function: } /** - * sep_free_dma_tables_and_dcb - - * This function frees the dma tables and dcb block + * sep_free_dma_tables_and_dcb - free DMA tables and DCBs * @sep: pointer to struct sep_device * @isapplet: indicates external application (used for kernel access) * @is_kva: indicates kernel addresses (only used for kernel crypto) + * + * This function frees the dma tables and dcb block */ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, bool is_kva) @@ -2858,11 +2890,12 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, } /** - * sep_get_static_pool_addr_handler - - * this function sets the bus and virtual addresses of the static pool - * and returns the virtual address + * sep_get_static_pool_addr_handler - get static pool address * @sep: pointer to struct sep_device * @arg: parameters from user space application + * + * This function sets the bus and virtual addresses of the static pool + * and returns the virtual address */ static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg) @@ -2901,8 +2934,7 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, } /** - * sep_start_handler - - * This function starts the sep device + * sep_start_handler - start device * @sep: pointer to struct sep_device */ static int sep_start_handler(struct sep_device *sep) @@ -2926,11 +2958,12 @@ static int sep_start_handler(struct sep_device *sep) } /** - * ep_check_sum_calc - - * This function performs a checsum for messages that are sent + * ep_check_sum_calc - checksum messages + * @data: buffer to checksum + * @length: buffer size + * + * This function performs a checksum for messages that are sent * to the sep - * @data: - * @length: */ static u32 sep_check_sum_calc(u8 *data, u32 length) { @@ -2956,17 +2989,18 @@ static u32 sep_check_sum_calc(u8 *data, u32 length) /** * sep_init_handler - - * this function handles the request for SEP initialization + * @sep: pointer to struct sep_device + * @arg: parameters from user space application + * + * Handles the request for SEP initialization * Note that this will go away for Medfield once the SCU * SEP initialization is complete * Also note that the message to the sep has components * from user space as well as components written by the driver - * This is becuase the portions of the message that partain to + * This is becuase the portions of the message that pertain to * physical addresses must be set by the driver after the message * leaves custody of the user space application for security * reasons. - * @sep: pointer to struct sep_device - * @arg: parameters from user space application */ static int sep_init_handler(struct sep_device *sep, unsigned long arg) { @@ -3127,9 +3161,10 @@ end_function: } /** - * sep_end_transaction_handler - - * This API handles the end transaction request + * sep_end_transaction_handler - end transaction * @sep: pointer to struct sep_device + * + * This API handles the end transaction request */ static int sep_end_transaction_handler(struct sep_device *sep) { @@ -3163,11 +3198,12 @@ static int sep_end_transaction_handler(struct sep_device *sep) } /** - * sep_prepare_dcb_handler - - * This function will retrieve the RAR buffer physical addresses, type - * & size corresponding to the RAR handles provided in the buffers vector. + * sep_prepare_dcb_handler - prepare a control block * @sep: pointer to struct sep_device * @arg: pointer to user parameters + * + * This function will retrieve the RAR buffer physical addresses, type + * & size corresponding to the RAR handles provided in the buffers vector. */ static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg) @@ -3211,10 +3247,11 @@ end_function: } /** - * sep_free_dcb_handler - - * this function frees the DCB resources - * and updates the needed user-space buffers + * sep_free_dcb_handler - free control block resources * @sep: pointer to struct sep_device + * + * This function frees the DCB resources and updates the needed + * user-space buffers. */ static int sep_free_dcb_handler(struct sep_device *sep) { @@ -3230,11 +3267,12 @@ static int sep_free_dcb_handler(struct sep_device *sep) } /** - * sep_rar_prepare_output_msg_handler - - * This function will retrieve the RAR buffer physical addresses, type - * & size corresponding to the RAR handles provided in the buffers vector. + * sep_rar_prepare_output_msg_handler - prepare an output message * @sep: pointer to struct sep_device * @arg: pointer to user parameters + * + * This function will retrieve the RAR buffer physical addresses, type + * & size corresponding to the RAR handles provided in the buffers vector. */ static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, @@ -3300,10 +3338,11 @@ end_function: } /** - * sep_realloc_ext_cache_handler - - * This function tells the sep where the extapp is located + * sep_realloc_ext_cache_handler - report location of extcache * @sep: pointer to struct sep_device * @arg: pointer to user parameters + * + * This function tells the sep where the extapp is located */ static int sep_realloc_ext_cache_handler(struct sep_device *sep, unsigned long arg) @@ -3332,6 +3371,8 @@ static int sep_realloc_ext_cache_handler(struct sep_device *sep, * @filp: pointer to struct file * @cmd: command * @arg: pointer to argument structure + * + * Implement the ioctl methods availble on the SEP device. */ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -3462,6 +3503,8 @@ end_function: * @filp: pointer to struct file * @cmd: command * @arg: pointer to argument structure + * + * Implement the additional ioctls for the singleton device */ static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg) { @@ -3522,6 +3565,7 @@ end_function: * @filp: pointer to struct file * @cmd: command * @arg: pointer to argument structure + * * Called by the request daemon to perform ioctls on the daemon device */ @@ -3643,10 +3687,11 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) } /** - * sep_callback - + * sep_callback - RAR callback + * @sep_context_pointer: pointer to struct sep_device + * * Function that is called by rar_register when it is ready with * a region (only for Moorestown) - * @sep_context_pointer: pointer to struct sep_device */ static int sep_callback(unsigned long sep_context_pointer) { @@ -3696,10 +3741,12 @@ end_function: } /** - * sep_probe - - * Function that is activated on the successful probe of the SEP device + * sep_probe - probe a matching PCI device * @pdev: pci_device * @end: pci_device_id + * + * Attempt to set up and configure a SEP device that has been + * discovered by the PCI layer. */ static int __devinit sep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -3904,10 +3951,11 @@ static const struct file_operations sep_file_operations = { }; /** - * sep_reconfig_shared_area - - * reconfig the shared area between HOST and SEP - needed in case - * the DX_CC_Init function was called before OS loading + * sep_reconfig_shared_area - reconfigure shared area * @sep: pointer to struct sep_device + * + * Reconfig the shared area between HOST and SEP - needed in case + * the DX_CC_Init function was called before OS loading. */ static int sep_reconfig_shared_area(struct sep_device *sep) { @@ -3948,9 +3996,10 @@ static int sep_reconfig_shared_area(struct sep_device *sep) } /** - * sep_register_driver_to_fs - - * This function registers the driver to the file system + * sep_register_driver_to_fs - register misc devices * @sep: pointer to struct sep_device + * + * This function registers the driver to the file system */ static int sep_register_driver_to_fs(struct sep_device *sep) { @@ -4000,7 +4049,9 @@ static int sep_register_driver_to_fs(struct sep_device *sep) } /** - * sep_init - init function; this is the first thing called on boot + * sep_init - init function + * + * Module load time. Register the PCI device driver. */ static int __init sep_init(void) { @@ -4051,7 +4102,10 @@ end_function: /** - * sep_exit - called to unload driver (never called on static compile) + * sep_exit - called to unload driver + * + * Drop the misc devices then remove and unmap the various resources + * that are not released by the driver remove method. */ static void __exit sep_exit(void) { -- cgit v1.2.3 From da14e55130785db243a98523b57ddf56d6c6320a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:38:02 +0000 Subject: Staging: sep: clean up some of the obvious sillies Various assignments are done but not used dev_dbg formatting is a bit weird and wraps when not needed Take out some of the blank lines and reformat a bit to reduce view size Remove some comments that are obvious Fix else formatting Remove some user triggerable dev_warns Fix copy_from_user error return cases (-EFAULT not bytes copied) Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 941 +++++++++++---------------------------- 1 file changed, 249 insertions(+), 692 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 4a0bb4350424..f576285fbb8f 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -83,15 +83,13 @@ static struct sep_device *sep_dev; * This functions copies the cache and resident from their source * location into destination shared memory. */ - static int sep_load_firmware(struct sep_device *sep) { const struct firmware *fw; char *cache_name = "cache.image.bin"; char *res_name = "resident.image.bin"; char *extapp_name = "extapp.image.bin"; - - int error = 0; + int error ; unsigned int work1, work2, work3; /* set addresses and load resident */ @@ -110,7 +108,7 @@ static int sep_load_firmware(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "resident virtual is %p\n", sep->resident_addr); - dev_dbg(&sep->pdev->dev, "residnet bus is %lx\n", + dev_dbg(&sep->pdev->dev, "resident bus is %lx\n", (unsigned long)sep->resident_bus); dev_dbg(&sep->pdev->dev, "resident size is %08x\n", sep->resident_size); @@ -134,7 +132,7 @@ static int sep_load_firmware(struct sep_device *sep) error = request_firmware(&fw, cache_name, &sep->pdev->dev); if (error) { - dev_warn(&sep->pdev->dev, "cant request cache fw\n"); + dev_warn(&sep->pdev->dev, "Unable to request cache firmware\n"); return error; } @@ -155,7 +153,7 @@ static int sep_load_firmware(struct sep_device *sep) error = request_firmware(&fw, extapp_name, &sep->pdev->dev); if (error) { - dev_warn(&sep->pdev->dev, "cant request extapp fw\n"); + dev_warn(&sep->pdev->dev, "Unable to request extapp firmware\n"); return error; } @@ -181,15 +179,13 @@ MODULE_FIRMWARE("sep/extapp.image.bin"); * sep_dump_message - dump the message that is pending * @sep: sep device */ - static void sep_dump_message(struct sep_device *sep) { int count; u32 *p = sep->shared_addr; for (count = 0; count < 12 * 4; count += 4) - dev_dbg(&sep->pdev->dev, - "Word %d of the message is %x\n", - count, *p++); + dev_dbg(&sep->pdev->dev, "Word %d of the message is %x\n", + count, *p++); } /** @@ -197,7 +193,6 @@ static void sep_dump_message(struct sep_device *sep) * @sep: security processor * @size: size of shared area */ - static int sep_map_and_alloc_shared_area(struct sep_device *sep) { sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev, @@ -211,8 +206,8 @@ static int sep_map_and_alloc_shared_area(struct sep_device *sep) } dev_dbg(&sep->pdev->dev, "sep: shared_addr %x bytes @%p (bus %llx)\n", - sep->shared_size, sep->shared_addr, - (unsigned long long)sep->shared_bus); + sep->shared_size, sep->shared_addr, + (unsigned long long)sep->shared_bus); return 0; } @@ -235,7 +230,6 @@ static void sep_unmap_and_free_shared_area(struct sep_device *sep) * Returns virtual address inside the shared area according * to the bus address. */ - static void *sep_shared_bus_to_virt(struct sep_device *sep, dma_addr_t bus_address) { @@ -249,11 +243,9 @@ static void *sep_shared_bus_to_virt(struct sep_device *sep, * * Called when the user opens the singleton device interface */ - static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) { int error = 0; - struct sep_device *sep; /* @@ -290,7 +282,6 @@ end_function: * * Returns zero on success otherwise an error code. */ - static int sep_open(struct inode *inode, struct file *filp) { struct sep_device *sep; @@ -317,16 +308,13 @@ static int sep_open(struct inode *inode, struct file *filp) * multiple simultaenous opens that means this method is called when the * final reference to the open handle is dropped. */ - static int sep_singleton_release(struct inode *inode, struct file *filp) { struct sep_device *sep = filp->private_data; dev_dbg(&sep->pdev->dev, "Singleton release for pid %d\n", - current->pid); - + current->pid); clear_bit(0, &sep->singleton_access_flag); - return 0; } @@ -340,14 +328,11 @@ static int sep_singleton_release(struct inode *inode, struct file *filp) * * Returns zero on success otherwise an error code. */ - static int sep_request_daemon_open(struct inode *inode, struct file *filp) { - struct sep_device *sep; - + struct sep_device *sep = sep_dev; int error = 0; - sep = sep_dev; filp->private_data = sep; dev_dbg(&sep->pdev->dev, "Request daemon open for pid %d\n", @@ -355,13 +340,8 @@ static int sep_request_daemon_open(struct inode *inode, struct file *filp) /* There is supposed to be only one request daemon */ dev_dbg(&sep->pdev->dev, "calling test and set for req_dmon open 0\n"); - if (test_and_set_bit(0, &sep->request_daemon_open)) { + if (test_and_set_bit(0, &sep->request_daemon_open)) error = -EBUSY; - goto end_function; - } - -end_function: - return error; } @@ -372,7 +352,6 @@ end_function: * * Called on the final close of a SEP daemon. */ - static int sep_request_daemon_release(struct inode *inode, struct file *filp) { struct sep_device *sep = filp->private_data; @@ -382,7 +361,6 @@ static int sep_request_daemon_release(struct inode *inode, struct file *filp) /* clear the request_daemon_open flag */ clear_bit(0, &sep->request_daemon_open); - return 0; } @@ -395,15 +373,11 @@ static int sep_request_daemon_release(struct inode *inode, struct file *filp) */ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) { - int error = 0; - unsigned long lck_flags; dev_dbg(&sep->pdev->dev, "sep_req_daemon_send_reply_command_handler start\n"); - error = 0; - sep_dump_message(sep); /* counters are lockable region */ @@ -426,7 +400,7 @@ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "sep_req_daemon_send_reply_command_handler end\n"); - return error; + return 0; } @@ -436,80 +410,56 @@ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) * * Handles the request to free dma table for synchronic actions */ - static int sep_free_dma_table_data_handler(struct sep_device *sep) { - /* counter */ - int count = 0; - - /* dcb counter */ - int dcb_counter = 0; - + int count; + int dcb_counter; /* pointer to the current dma_resource struct */ struct sep_dma_resource *dma; - dev_dbg(&sep->pdev->dev, - "sep_free_dma_table_data_handler start\n"); - - - for (dcb_counter = 0; dcb_counter < sep->nr_dcb_creat; - dcb_counter++) { + dev_dbg(&sep->pdev->dev, "sep_free_dma_table_data_handler start\n"); + for (dcb_counter = 0; dcb_counter < sep->nr_dcb_creat; dcb_counter++) { dma = &sep->dma_res_arr[dcb_counter]; /* unmap and free input map array */ if (dma->in_map_array) { - - for (count = 0; count < dma->in_num_pages; - count++) { - + for (count = 0; count < dma->in_num_pages; count++) { dma_unmap_page(&sep->pdev->dev, dma->in_map_array[count].dma_addr, dma->in_map_array[count].size, DMA_TO_DEVICE); } - kfree(dma->in_map_array); } /* unmap output map array, DON'T free it yet */ if (dma->out_map_array) { - for (count = 0; count < dma->out_num_pages; - count++) { - + for (count = 0; count < dma->out_num_pages; count++) { dma_unmap_page(&sep->pdev->dev, dma->out_map_array[count].dma_addr, dma->out_map_array[count].size, DMA_FROM_DEVICE); } - kfree(dma->out_map_array); } /* free page cache for output */ if (dma->in_page_array) { - for (count = 0; count < dma->in_num_pages; - count++) { - + for (count = 0; count < dma->in_num_pages; count++) { flush_dcache_page(dma->in_page_array[count]); page_cache_release(dma->in_page_array[count]); } - kfree(dma->in_page_array); - } if (dma->out_page_array) { - for (count = 0; count < dma->out_num_pages; - count++) { - + for (count = 0; count < dma->out_num_pages; count++) { if (!PageReserved(dma->out_page_array[count])) SetPageDirty(dma->out_page_array[count]); - flush_dcache_page(dma->out_page_array[count]); page_cache_release(dma->out_page_array[count]); } - kfree(dma->out_page_array); } @@ -522,19 +472,15 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) dma->out_map_array = 0; dma->in_map_num_entries = 0; dma->out_map_num_entries = 0; - } sep->nr_dcb_creat = 0; sep->num_lli_tables_created = 0; - dev_dbg(&sep->pdev->dev, - "sep_free_dma_table_data_handler end\n"); - + dev_dbg(&sep->pdev->dev, "sep_free_dma_table_data_handler end\n"); return 0; } - /** * sep_request_daemon_mmap - maps the shared area to user space * @filp: pointer to struct file @@ -546,11 +492,8 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) static int sep_request_daemon_mmap(struct file *filp, struct vm_area_struct *vma) { - /* device */ struct sep_device *sep = filp->private_data; - dma_addr_t bus_address; - int error = 0; dev_dbg(&sep->pdev->dev, "daemon mmap start\n"); @@ -563,23 +506,19 @@ static int sep_request_daemon_mmap(struct file *filp, /* get physical address */ bus_address = sep->shared_bus; - dev_dbg(&sep->pdev->dev, - "bus_address is %08lx\n", - (unsigned long)bus_address); + dev_dbg(&sep->pdev->dev, "bus_address is %08lx\n", + (unsigned long)bus_address); if (remap_pfn_range(vma, vma->vm_start, bus_address >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - dev_warn(&sep->pdev->dev, - "remap_page_range failed\n"); + dev_warn(&sep->pdev->dev, "remap_page_range failed\n"); error = -EAGAIN; goto end_function; } end_function: - dev_dbg(&sep->pdev->dev, "daemon mmap end\n"); - return error; } @@ -595,69 +534,46 @@ static unsigned int sep_request_daemon_poll(struct file *filp, poll_table *wait) { u32 mask = 0; - /* GPR2 register */ u32 retval2; - unsigned long lck_flags; - struct sep_device *sep = filp->private_data; - dev_dbg(&sep->pdev->dev, - "daemon poll: start\n"); - - dev_dbg(&sep->pdev->dev, "daemon poll: calling poll wait sep_event\n"); + dev_dbg(&sep->pdev->dev, "daemon poll: start\n"); poll_wait(filp, &sep->event_request_daemon, wait); - dev_dbg(&sep->pdev->dev, "daemon poll: exit poll wait sep_event\n"); - - dev_dbg(&sep->pdev->dev, - "daemon poll: send_ct is %lx reply ct is %lx\n", - sep->send_ct, sep->reply_ct); + dev_dbg(&sep->pdev->dev, "daemon poll: send_ct is %lx reply ct is %lx\n", + sep->send_ct, sep->reply_ct); spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); /* check if the data is ready */ if (sep->send_ct == sep->reply_ct) { - spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); - dev_dbg(&sep->pdev->dev, "daemon poll: data check (GPR2) is %x\n", retval2); /* check if PRINT request */ if ((retval2 >> 30) & 0x1) { - - dev_dbg(&sep->pdev->dev, - "daemon poll: PRINTF request in\n"); + dev_dbg(&sep->pdev->dev, "daemon poll: PRINTF request in\n"); mask |= POLLIN; goto end_function; } - /* check if NVS request */ if (retval2 >> 31) { - - dev_dbg(&sep->pdev->dev, - "daemon poll: NVS request in\n"); + dev_dbg(&sep->pdev->dev, "daemon poll: NVS request in\n"); mask |= POLLPRI | POLLWRNORM; } - } - - else { - + } else { spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); - dev_dbg(&sep->pdev->dev, "daemon poll: no reply received; returning 0\n"); mask = 0; } - end_function: - - dev_dbg(&sep->pdev->dev, - "daemon poll: exit\n"); + dev_dbg(&sep->pdev->dev, "daemon poll: exit\n"); return mask; } @@ -668,7 +584,6 @@ end_function: * * Called on the final close of a SEP device. */ - static int sep_release(struct inode *inode, struct file *filp) { struct sep_device *sep = filp->private_data; @@ -709,9 +624,6 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) dev_dbg(&sep->pdev->dev, "mmap start\n"); - - dev_dbg(&sep->pdev->dev, "calling wait on event_mmap, tsetbit" - " SEP_MMAP_LOCK_BIT in_use_flags 0\n"); /* Set the transaction busy (own the device) */ wait_event_interruptible(sep->event, test_and_set_bit(SEP_MMAP_LOCK_BIT, @@ -748,8 +660,7 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) goto end_function_with_error; } - dev_dbg(&sep->pdev->dev, - "shared_addr is %p\n", sep->shared_addr); + dev_dbg(&sep->pdev->dev, "shared_addr is %p\n", sep->shared_addr); /* get bus address */ bus_addr = sep->shared_bus; @@ -759,17 +670,14 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - dev_warn(&sep->pdev->dev, - "remap_page_range failed\n"); + dev_warn(&sep->pdev->dev, "remap_page_range failed\n"); error = -EAGAIN; goto end_function_with_error; } - dev_dbg(&sep->pdev->dev, "mmap end\n"); goto end_function; end_function_with_error: - /* clear the bit */ clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags); mutex_lock(&sep->sep_mutex); @@ -782,7 +690,6 @@ end_function_with_error: wake_up(&sep->event); end_function: - return error; } @@ -799,7 +706,6 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) u32 mask = 0; u32 retval = 0; u32 retval2 = 0; - unsigned long lck_flags; struct sep_device *sep = filp->private_data; @@ -814,7 +720,6 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) mutex_unlock(&sep->sep_mutex); goto end_function; } - mutex_unlock(&sep->sep_mutex); /* check if send command or send_reply were activated previously */ @@ -829,18 +734,13 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) poll_wait(filp, &sep->event, wait); - dev_dbg(&sep->pdev->dev, "poll: exit wait sep_event\n"); - dev_dbg(&sep->pdev->dev, "poll: send_ct is %lx reply ct is %lx\n", sep->send_ct, sep->reply_ct); /* check if error occured during poll */ retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - if (retval2 != 0x0) { - - dev_warn(&sep->pdev->dev, "poll; poll error %x\n", - retval2); + dev_warn(&sep->pdev->dev, "poll; poll error %x\n", retval2); mask |= POLLERR; goto end_function; } @@ -848,7 +748,6 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); if (sep->send_ct == sep->reply_ct) { - spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); dev_dbg(&sep->pdev->dev, "poll: data ready check (GPR2) %x\n", @@ -856,46 +755,33 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) /* check if printf request */ if ((retval >> 30) & 0x1) { - dev_dbg(&sep->pdev->dev, "poll: sep printf request\n"); wake_up(&sep->event_request_daemon); goto end_function; - } /* check if the this is sep reply or request */ if (retval >> 31) { - dev_dbg(&sep->pdev->dev, "poll: sep request\n"); wake_up(&sep->event_request_daemon); - } else { - dev_dbg(&sep->pdev->dev, "poll: normal return\n"); - /* in case it is again by send_reply_comand */ - clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags); - sep_dump_message(sep); - dev_dbg(&sep->pdev->dev, "poll; sep reply POLLIN | POLLRDNORM\n"); mask |= POLLIN | POLLRDNORM; } - } else { - spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); - dev_dbg(&sep->pdev->dev, "poll; no reply received; returning mask of 0\n"); mask = 0; } end_function: - dev_dbg(&sep->pdev->dev, "poll: end\n"); return mask; } @@ -907,7 +793,6 @@ end_function: * Return the address of the two dwords in memory used for time * setting. */ - static u32 *sep_time_address(struct sep_device *sep) { return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; @@ -926,8 +811,7 @@ static unsigned long sep_set_time(struct sep_device *sep) u32 *time_addr; /* address of time as seen by the kernel */ - dev_dbg(&sep->pdev->dev, - "sep:sep_set_time start\n"); + dev_dbg(&sep->pdev->dev, "sep:sep_set_time start\n"); do_gettimeofday(&time); @@ -937,12 +821,9 @@ static unsigned long sep_set_time(struct sep_device *sep) time_addr[0] = SEP_TIME_VAL_TOKEN; time_addr[1] = time.tv_sec; - dev_dbg(&sep->pdev->dev, - "time.tv_sec is %lu\n", time.tv_sec); - dev_dbg(&sep->pdev->dev, - "time_addr is %p\n", time_addr); - dev_dbg(&sep->pdev->dev, - "sep->shared_addr is %p\n", sep->shared_addr); + dev_dbg(&sep->pdev->dev, "time.tv_sec is %lu\n", time.tv_sec); + dev_dbg(&sep->pdev->dev, "time_addr is %p\n", time_addr); + dev_dbg(&sep->pdev->dev, "sep->shared_addr is %p\n", sep->shared_addr); return time.tv_sec; } @@ -958,14 +839,11 @@ static unsigned long sep_set_time(struct sep_device *sep) static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) { void __user *hash; - int error; + int error = 0; int i; struct caller_id_struct command_args; - dev_dbg(&sep->pdev->dev, - "sep_set_caller_id_handler start\n"); - - error = 0; + dev_dbg(&sep->pdev->dev, "sep_set_caller_id_handler start\n"); for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) { if (sep->caller_id_table[i].pid == 0) @@ -973,12 +851,9 @@ static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) } if (i == SEP_CALLER_ID_TABLE_NUM_ENTRIES) { - dev_warn(&sep->pdev->dev, - "no more caller id entries left\n"); - dev_warn(&sep->pdev->dev, - "maximum number is %d\n", - SEP_CALLER_ID_TABLE_NUM_ENTRIES); - + dev_warn(&sep->pdev->dev, "no more caller id entries left\n"); + dev_warn(&sep->pdev->dev, "maximum number is %d\n", + SEP_CALLER_ID_TABLE_NUM_ENTRIES); error = -EUSERS; goto end_function; } @@ -1002,7 +877,7 @@ static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) command_args.callerIdSizeInBytes); if (command_args.callerIdSizeInBytes > - SEP_CALLER_ID_HASH_SIZE_IN_BYTES) { + SEP_CALLER_ID_HASH_SIZE_IN_BYTES) { error = -EMSGSIZE; goto end_function; } @@ -1013,8 +888,7 @@ static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) hash, command_args.callerIdSizeInBytes)) error = -EFAULT; end_function: - dev_dbg(&sep->pdev->dev, - "sep_set_caller_id_handler end\n"); + dev_dbg(&sep->pdev->dev, "sep_set_caller_id_handler end\n"); return error; } @@ -1030,29 +904,23 @@ static int sep_set_current_caller_id(struct sep_device *sep) int i; dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id start\n"); - dev_dbg(&sep->pdev->dev, "current process is %d\n", current->pid); /* zero the previous value */ - memset((void *)(sep->shared_addr + - (SEP_CALLER_ID_OFFSET_BYTES)), - 0, - SEP_CALLER_ID_HASH_SIZE_IN_BYTES); + memset(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES, + 0, SEP_CALLER_ID_HASH_SIZE_IN_BYTES); for (i = 0; i < SEP_CALLER_ID_TABLE_NUM_ENTRIES; i++) { if (sep->caller_id_table[i].pid == current->pid) { dev_dbg(&sep->pdev->dev, "Caller Id found\n"); - memcpy((void *)(sep->shared_addr + - (SEP_CALLER_ID_OFFSET_BYTES)), + memcpy(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES, (void *)(sep->caller_id_table[i].callerIdHash), SEP_CALLER_ID_HASH_SIZE_IN_BYTES); break; } } - dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id end\n"); - return 0; } @@ -1065,7 +933,6 @@ static int sep_set_current_caller_id(struct sep_device *sep) * * Note that this function does fall under the ioctl lock */ - static int sep_send_command_handler(struct sep_device *sep) { unsigned long lck_flags; @@ -1073,13 +940,10 @@ static int sep_send_command_handler(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "sep_send_command_handler start\n"); - dev_dbg(&sep->pdev->dev, "calling test and set for " - " in_use_flags SEP_SEND_MSG_LOCK_BIT 0\n"); if (test_and_set_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) { error = -EPROTO; goto end_function; } - sep_set_time(sep); /* only Medfield has caller id */ @@ -1093,8 +957,9 @@ static int sep_send_command_handler(struct sep_device *sep) sep->send_ct++; spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); - dev_dbg(&sep->pdev->dev, "sep_send_command_handler" - "send_ct %lx reply_ct %lx\n", sep->send_ct, sep->reply_ct); + dev_dbg(&sep->pdev->dev, + "sep_send_command_handler send_ct %lx reply_ct %lx\n", + sep->send_ct, sep->reply_ct); /* send interrupt to SEP */ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); @@ -1156,8 +1021,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES + (sep->num_of_data_allocations)*2*sizeof(u32)); - dev_dbg(&sep->pdev->dev, - "allocation offset: %x\n", + dev_dbg(&sep->pdev->dev, "allocation offset: %x\n", SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES); dev_dbg(&sep->pdev->dev, "data pool token addr is %p\n", token_addr); @@ -1173,7 +1037,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, error = copy_to_user((void *)arg, (void *)&command_args, sizeof(struct alloc_struct)); if (error) { - + error = -EFAULT; dev_warn(&sep->pdev->dev, "allocate data pool copy to user error\n"); goto end_function; @@ -1189,9 +1053,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, (int)sep->data_pool_bytes_allocated); end_function: - - dev_dbg(&sep->pdev->dev, - "sep_allocate_data_pool_memory_handler end\n"); + dev_dbg(&sep->pdev->dev, "sep_allocate_data_pool_memory_handler end\n"); return error; } @@ -1216,12 +1078,9 @@ static int sep_lock_kernel_pages(struct sep_device *sep, int in_out_flag) { - /* error */ int error = 0; - /* array of lli */ struct sep_lli_entry *lli_array; - /* map array */ struct sep_dma_map *map_array; @@ -1235,11 +1094,9 @@ static int sep_lock_kernel_pages(struct sep_device *sep, lli_array = kmalloc(sizeof(struct sep_lli_entry), GFP_ATOMIC); if (!lli_array) { - error = -ENOMEM; goto end_function; } - map_array = kmalloc(sizeof(struct sep_dma_map), GFP_ATOMIC); if (!map_array) { error = -ENOMEM; @@ -1260,8 +1117,7 @@ static int sep_lock_kernel_pages(struct sep_device *sep, lli_array[0].block_size = map_array[0].size; dev_dbg(&sep->pdev->dev, - "lli_array[0].bus_address is %08lx," - " lli_array[0].block_size is %x\n", + "lli_array[0].bus_address is %08lx, lli_array[0].block_size is %x\n", (unsigned long)lli_array[0].bus_address, lli_array[0].block_size); @@ -1279,18 +1135,13 @@ static int sep_lock_kernel_pages(struct sep_device *sep, sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array; sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = 1; } - goto end_function; end_function_with_error: - kfree(lli_array); end_function: - - dev_dbg(&sep->pdev->dev, - "sep_lock_kernel_pages end\n"); - + dev_dbg(&sep->pdev->dev, "sep_lock_kernel_pages end\n"); return error; } @@ -1314,59 +1165,39 @@ static int sep_lock_user_pages(struct sep_device *sep, int in_out_flag) { - /* error */ - int error; - + int error = 0; + u32 count; + int result; /* the the page of the end address of the user space buffer */ u32 end_page; - /* the page of the start address of the user space buffer */ u32 start_page; - /* the range in pages */ u32 num_pages; - - /* array of pointers ot page */ + /* array of pointers to page */ struct page **page_array; - /* array of lli */ struct sep_lli_entry *lli_array; - /* map array */ struct sep_dma_map *map_array; - /* direction of the DMA mapping for locked pages */ enum dma_data_direction dir; - /* count */ - u32 count; - - /* result */ - int result; - dev_dbg(&sep->pdev->dev, "sep_lock_user_pages start\n"); - error = 0; - /* set start and end pages and num pages */ end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; start_page = app_virt_addr >> PAGE_SHIFT; num_pages = end_page - start_page + 1; - dev_dbg(&sep->pdev->dev, - "app_virt_addr is %x\n", app_virt_addr); - dev_dbg(&sep->pdev->dev, - "data_size is %x\n", data_size); - dev_dbg(&sep->pdev->dev, - "start_page is %x\n", start_page); - dev_dbg(&sep->pdev->dev, - "end_page is %x\n", end_page); - dev_dbg(&sep->pdev->dev, - "num_pages is %x\n", num_pages); + dev_dbg(&sep->pdev->dev, "app_virt_addr is %x\n", app_virt_addr); + dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size); + dev_dbg(&sep->pdev->dev, "start_page is %x\n", start_page); + dev_dbg(&sep->pdev->dev, "end_page is %x\n", end_page); + dev_dbg(&sep->pdev->dev, "num_pages is %x\n", num_pages); - dev_dbg(&sep->pdev->dev, - "starting page_array malloc\n"); + dev_dbg(&sep->pdev->dev, "starting page_array malloc\n"); /* allocate array of pages structure pointers */ page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); @@ -1374,11 +1205,9 @@ static int sep_lock_user_pages(struct sep_device *sep, error = -ENOMEM; goto end_function; } - map_array = kmalloc(sizeof(struct sep_dma_map) * num_pages, GFP_ATOMIC); if (!map_array) { - dev_warn(&sep->pdev->dev, - "kmalloc for map_array failed\n"); + dev_warn(&sep->pdev->dev, "kmalloc for map_array failed\n"); error = -ENOMEM; goto end_function_with_error1; } @@ -1387,15 +1216,12 @@ static int sep_lock_user_pages(struct sep_device *sep, GFP_ATOMIC); if (!lli_array) { - - dev_warn(&sep->pdev->dev, - "kmalloc for lli_array failed\n"); + dev_warn(&sep->pdev->dev, "kmalloc for lli_array failed\n"); error = -ENOMEM; goto end_function_with_error2; } - dev_dbg(&sep->pdev->dev, - "starting get_user_pages\n"); + dev_dbg(&sep->pdev->dev, "starting get_user_pages\n"); /* convert the application virtual address into a set of physical */ down_read(¤t->mm->mmap_sem); @@ -1408,15 +1234,13 @@ static int sep_lock_user_pages(struct sep_device *sep, /* check the number of pages locked - if not all then exit with error */ if (result != num_pages) { - dev_warn(&sep->pdev->dev, "not all pages locked by get_user_pages\n"); error = -ENOMEM; goto end_function_with_error3; } - dev_dbg(&sep->pdev->dev, - "get_user_pages succeeded\n"); + dev_dbg(&sep->pdev->dev, "get_user_pages succeeded\n"); /* set direction */ if (in_out_flag == SEP_DRIVER_IN_FLAG) @@ -1441,9 +1265,7 @@ static int sep_lock_user_pages(struct sep_device *sep, lli_array[count].bus_address = (u32)map_array[count].dma_addr; lli_array[count].block_size = PAGE_SIZE; - dev_warn(&sep->pdev->dev, - "lli_array[%x].bus_address is %08lx, \ - lli_array[%x].block_size is %x\n", + dev_warn(&sep->pdev->dev, "lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is %x\n", count, (unsigned long)lli_array[count].bus_address, count, lli_array[count].block_size); } @@ -1460,20 +1282,17 @@ static int sep_lock_user_pages(struct sep_device *sep, PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); dev_dbg(&sep->pdev->dev, - "lli_array[0].bus_address is %08lx, \ - lli_array[0].block_size is %x\n", + "lli_array[0].bus_address is %08lx, lli_array[0].block_size is %x\n", (unsigned long)lli_array[count].bus_address, lli_array[count].block_size); /* check the size of the last page */ if (num_pages > 1) { - lli_array[num_pages - 1].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); dev_warn(&sep->pdev->dev, - "lli_array[%x].bus_address is %08lx, \ - lli_array[%x].block_size is %x\n", + "lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is %x\n", num_pages - 1, (unsigned long)lli_array[count].bus_address, num_pages - 1, @@ -1483,47 +1302,35 @@ static int sep_lock_user_pages(struct sep_device *sep, /* set output params acording to the in_out flag */ if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; - sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = - num_pages; - sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = - page_array; - sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = - map_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = num_pages; + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = page_array; + sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array; sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = - num_pages; + num_pages; } else { *lli_array_ptr = lli_array; - sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = - num_pages; + sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = num_pages; sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = - page_array; - sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = - map_array; + page_array; + sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array; sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = - num_pages; + num_pages; } - goto end_function; end_function_with_error3: - /* free lli array */ kfree(lli_array); end_function_with_error2: - kfree(map_array); end_function_with_error1: - /* free page array */ kfree(page_array); end_function: - - dev_dbg(&sep->pdev->dev, - "sep_lock_user_pages end\n"); - + dev_dbg(&sep->pdev->dev, "sep_lock_user_pages end\n"); return error; } @@ -1544,16 +1351,12 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, u32 num_array_entries, u32 *last_table_flag) { + u32 counter; /* table data size */ - u32 table_data_size; - + u32 table_data_size = 0; /* data size for the next table */ u32 next_table_data_size; - /* counter */ - u32 counter; - - table_data_size = 0; *last_table_flag = 0; /* @@ -1562,7 +1365,7 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, */ for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && - (counter < num_array_entries); counter++) + (counter < num_array_entries); counter++) table_data_size += lli_in_array_ptr[counter].block_size; /* @@ -1571,7 +1374,6 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, * and no need to check the block alignment */ if (counter == num_array_entries) { - /* set the last table flag */ *last_table_flag = 1; goto end_function; @@ -1584,11 +1386,8 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, */ next_table_data_size = 0; for (; counter < num_array_entries; counter++) { - next_table_data_size += lli_in_array_ptr[counter].block_size; - if (next_table_data_size >= SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) - break; } @@ -1603,11 +1402,9 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, table_data_size -= (SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE - next_table_data_size); - dev_dbg(&sep->pdev->dev, - "table data size is %x\n", table_data_size); - + dev_dbg(&sep->pdev->dev, "table data size is %x\n", + table_data_size); end_function: - return table_data_size; } @@ -1632,20 +1429,17 @@ static void sep_build_lli_table(struct sep_device *sep, { /* current table data size */ u32 curr_table_data_size; - /* counter of lli array entry */ u32 array_counter; - dev_dbg(&sep->pdev->dev, - "sep_build_lli_table start\n"); + dev_dbg(&sep->pdev->dev, "sep_build_lli_table start\n"); /* init currrent table data size and lli array entry counter */ curr_table_data_size = 0; array_counter = 0; *num_table_entries_ptr = 1; - dev_dbg(&sep->pdev->dev, - "table_data_size is %x\n", table_data_size); + dev_dbg(&sep->pdev->dev, "table_data_size is %x\n", table_data_size); /* fill the table till table size reaches the needed amount */ while (curr_table_data_size < table_data_size) { @@ -1660,18 +1454,15 @@ static void sep_build_lli_table(struct sep_device *sep, curr_table_data_size += lli_array_ptr[array_counter].block_size; - dev_dbg(&sep->pdev->dev, - "lli_table_ptr is %p\n", lli_table_ptr); - dev_dbg(&sep->pdev->dev, - "lli_table_ptr->bus_address is %08lx\n", - (unsigned long)lli_table_ptr->bus_address); - dev_dbg(&sep->pdev->dev, - "lli_table_ptr->block_size is %x\n", + dev_dbg(&sep->pdev->dev, "lli_table_ptr is %p\n", + lli_table_ptr); + dev_dbg(&sep->pdev->dev, "lli_table_ptr->bus_address is %08lx\n", + (unsigned long)lli_table_ptr->bus_address); + dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n", lli_table_ptr->block_size); /* check for overflow of the table data */ if (curr_table_data_size > table_data_size) { - dev_dbg(&sep->pdev->dev, "curr_table_data_size too large\n"); @@ -1686,15 +1477,13 @@ static void sep_build_lli_table(struct sep_device *sep, /* update the block size left in the lli array */ lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size); - } else - /* advance to the next entry in the lli_array */ array_counter++; dev_dbg(&sep->pdev->dev, "lli_table_ptr->bus_address is %08lx\n", - (unsigned long)lli_table_ptr->bus_address); + (unsigned long)lli_table_ptr->bus_address); dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n", lli_table_ptr->block_size); @@ -1707,26 +1496,19 @@ static void sep_build_lli_table(struct sep_device *sep, lli_table_ptr->bus_address = 0xffffffff; lli_table_ptr->block_size = 0; - dev_dbg(&sep->pdev->dev, - "lli_table_ptr is %p\n", lli_table_ptr); - dev_dbg(&sep->pdev->dev, - "lli_table_ptr->bus_address is %08lx\n", - (unsigned long)lli_table_ptr->bus_address); - dev_dbg(&sep->pdev->dev, - "lli_table_ptr->block_size is %x\n", - lli_table_ptr->block_size); + dev_dbg(&sep->pdev->dev, "lli_table_ptr is %p\n", lli_table_ptr); + dev_dbg(&sep->pdev->dev, "lli_table_ptr->bus_address is %08lx\n", + (unsigned long)lli_table_ptr->bus_address); + dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n", + lli_table_ptr->block_size); /* set the output parameter */ *num_processed_entries_ptr += array_counter; - dev_dbg(&sep->pdev->dev, - "num_processed_entries_ptr is %x\n", + dev_dbg(&sep->pdev->dev, "num_processed_entries_ptr is %x\n", *num_processed_entries_ptr); - dev_dbg(&sep->pdev->dev, - "sep_build_lli_table end\n"); - - return; + dev_dbg(&sep->pdev->dev, "sep_build_lli_table end\n"); } /** @@ -1742,16 +1524,12 @@ static void sep_build_lli_table(struct sep_device *sep, static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep, void *virt_address) { - dev_dbg(&sep->pdev->dev, - "sh virt to phys v %08lx\n", - (unsigned long)virt_address); - dev_dbg(&sep->pdev->dev, - "sh virt to phys p %08lx\n", - (unsigned long)(sep->shared_bus - + (virt_address - sep->shared_addr))); + dev_dbg(&sep->pdev->dev, "sh virt to phys v %p\n", virt_address); + dev_dbg(&sep->pdev->dev, "sh virt to phys p %08lx\n", + (unsigned long) + sep->shared_bus + (virt_address - sep->shared_addr)); - return sep->shared_bus - + (size_t)(virt_address - sep->shared_addr); + return sep->shared_bus + (size_t)(virt_address - sep->shared_addr); } /** @@ -1764,18 +1542,14 @@ static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep, * externa RAM device (ioremapped), or on the system RAM * This implementation is for the external RAM */ - static void *sep_shared_area_bus_to_virt(struct sep_device *sep, dma_addr_t bus_address) { - dev_dbg(&sep->pdev->dev, - "shared bus to virt b=%x v=%x\n", - (u32)bus_address, - (u32)(sep->shared_addr + + dev_dbg(&sep->pdev->dev, "shared bus to virt b=%x v=%x\n", + (u32)bus_address, (u32)(sep->shared_addr + (size_t)(bus_address - sep->shared_bus))); - return sep->shared_addr - + (size_t)(bus_address - sep->shared_bus); + return sep->shared_addr + (size_t)(bus_address - sep->shared_bus); } /** @@ -1792,20 +1566,17 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, unsigned long num_table_entries, unsigned long table_data_size) { - unsigned long table_count = 0; + unsigned long table_count = 1; unsigned long entries_count = 0; - dev_dbg(&sep->pdev->dev, - "sep_debug_print_lli_tables start\n"); + dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables start\n"); - table_count = 1; while ((unsigned long) lli_table_ptr != 0xffffffff) { dev_dbg(&sep->pdev->dev, "lli table %08lx, table_data_size is %lu\n", table_count, table_data_size); - dev_dbg(&sep->pdev->dev, - "num_table_entries is %lu\n", - num_table_entries); + dev_dbg(&sep->pdev->dev, "num_table_entries is %lu\n", + num_table_entries); /* print entries of the table (without info entry) */ for (entries_count = 0; entries_count < num_table_entries; @@ -1820,7 +1591,6 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, (unsigned long)lli_table_ptr->bus_address, lli_table_ptr->block_size); } - /* point to the info entry */ lli_table_ptr--; @@ -1850,8 +1620,7 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, table_count++; } - dev_dbg(&sep->pdev->dev, - "sep_debug_print_lli_tables end\n"); + dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables end\n"); } @@ -1863,7 +1632,6 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, * @table_data_size_ptr: point to table data size * * This function creates empty lli tables when there is no data - */ static void sep_prepare_empty_lli_table(struct sep_device *sep, dma_addr_t *lli_table_addr_ptr, @@ -1878,9 +1646,8 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep, lli_table_ptr = (struct sep_lli_entry *)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + - sep->num_lli_tables_created * - sizeof(struct sep_lli_entry) * - SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); + sep->num_lli_tables_created * sizeof(struct sep_lli_entry) * + SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); lli_table_ptr->bus_address = 0; lli_table_ptr->block_size = 0; @@ -1931,43 +1698,29 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, u32 *table_data_size_ptr, bool is_kva) { + int error = 0; /* pointer to the info entry of the table - the last entry */ struct sep_lli_entry *info_entry_ptr; - - /* array of pointers ot page */ + /* array of pointers to page */ struct sep_lli_entry *lli_array_ptr; - /* points to the first entry to be processed in the lli_in_array */ u32 current_entry = 0; - /* num entries in the virtual buffer */ u32 sep_lli_entries = 0; - /* lli table pointer */ struct sep_lli_entry *in_lli_table_ptr; - /* the total data in one table */ u32 table_data_size = 0; - /* flag for last table */ u32 last_table_flag = 0; - /* number of entries in lli table */ u32 num_entries_in_table = 0; - /* next table address */ u32 lli_table_alloc_addr = 0; - /* error */ - int error = 0; - - dev_dbg(&sep->pdev->dev, - "sep_prepare_input_dma_table start\n"); - - dev_dbg(&sep->pdev->dev, - "data_size is %x\n", data_size); - dev_dbg(&sep->pdev->dev, - "block_size is %x\n", block_size); + dev_dbg(&sep->pdev->dev, "sep_prepare_input_dma_table start\n"); + dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size); + dev_dbg(&sep->pdev->dev, "block_size is %x\n", block_size); /* initialize the pages pointers */ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; @@ -1976,29 +1729,22 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, /* set the kernel address for first table to be allocated */ lli_table_alloc_addr = (u32)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + - sep->num_lli_tables_created * - sizeof(struct sep_lli_entry) * + sep->num_lli_tables_created * sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); if (data_size == 0) { - /* special case - create meptu table - 2 entries, zero data */ sep_prepare_empty_lli_table(sep, lli_table_ptr, - num_entries_ptr, - table_data_size_ptr); - + num_entries_ptr, table_data_size_ptr); goto update_dcb_counter; } /* check if the pages are in Kernel Virtual Address layout */ if (is_kva == true) - /* lock the pages in the kernel */ error = sep_lock_kernel_pages(sep, app_virt_addr, data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG); - else - /* * lock the pages of the user buffer * and translate them to pages @@ -2009,15 +1755,13 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, if (error) goto end_function; - dev_dbg(&sep->pdev->dev, - "output sep_in_num_pages is %x\n", + dev_dbg(&sep->pdev->dev, "output sep_in_num_pages is %x\n", sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages); current_entry = 0; info_entry_ptr = 0; - sep_lli_entries = - sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages; + sep_lli_entries = sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages; /* loop till all the entries in in array are not processed */ while (current_entry < sep_lli_entries) { @@ -2048,17 +1792,16 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, (sep_lli_entries - current_entry), &last_table_flag); - /** + /* * if this is not the last table - * then allign it to the block size */ if (!last_table_flag) table_data_size = - (table_data_size / block_size) * block_size; + (table_data_size / block_size) * block_size; - dev_dbg(&sep->pdev->dev, - "output table_data_size is %x\n", - table_data_size); + dev_dbg(&sep->pdev->dev, "output table_data_size is %x\n", + table_data_size); /* construct input lli table */ sep_build_lli_table(sep, &lli_array_ptr[current_entry], @@ -2077,52 +1820,38 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, "output lli_table_in_ptr is %08lx\n", (unsigned long)*lli_table_ptr); - } - - else { - + } else { /* update the info entry of the previous in table */ info_entry_ptr->bus_address = sep_shared_area_virt_to_bus(sep, - in_lli_table_ptr); - info_entry_ptr->block_size = + in_lli_table_ptr); + info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); } - /* save the pointer to the info entry of the current tables */ info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; - } - /* print input tables */ sep_debug_print_lli_tables(sep, (struct sep_lli_entry *) sep_shared_area_bus_to_virt(sep, *lli_table_ptr), - *num_entries_ptr, - *table_data_size_ptr); - + *num_entries_ptr, *table_data_size_ptr); /* the array of the pages */ kfree(lli_array_ptr); update_dcb_counter: - /* update dcb counter */ sep->nr_dcb_creat++; - goto end_function; end_function_error: - /* free all the allocated resources */ kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array); kfree(lli_array_ptr); kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array); end_function: - - dev_dbg(&sep->pdev->dev, - "sep_prepare_input_dma_table end\n"); - + dev_dbg(&sep->pdev->dev, "sep_prepare_input_dma_table end\n"); return error; } @@ -2161,45 +1890,32 @@ static int sep_construct_dma_tables_from_lli( { /* points to the area where next lli table can be allocated */ u32 lli_table_alloc_addr = 0; - /* input lli table */ struct sep_lli_entry *in_lli_table_ptr = 0; - /* output lli table */ struct sep_lli_entry *out_lli_table_ptr = 0; - /* pointer to the info entry of the table - the last entry */ struct sep_lli_entry *info_in_entry_ptr = 0; - /* pointer to the info entry of the table - the last entry */ struct sep_lli_entry *info_out_entry_ptr = 0; - /* points to the first entry to be processed in the lli_in_array */ u32 current_in_entry = 0; - /* points to the first entry to be processed in the lli_out_array */ u32 current_out_entry = 0; - /* max size of the input table */ u32 in_table_data_size = 0; - /* max size of the output table */ u32 out_table_data_size = 0; - /* flag te signifies if this is the last tables build */ u32 last_table_flag = 0; - /* the data size that should be in table */ u32 table_data_size = 0; - /* number of etnries in the input table */ u32 num_entries_in_table = 0; - /* number of etnries in the output table */ u32 num_entries_out_table = 0; - dev_dbg(&sep->pdev->dev, - "sep_construct_dma_tables_from_lli start\n"); + dev_dbg(&sep->pdev->dev, "sep_construct_dma_tables_from_lli start\n"); /* initiate to point after the message area */ lli_table_alloc_addr = (u32)(sep->shared_addr + @@ -2210,7 +1926,6 @@ static int sep_construct_dma_tables_from_lli( /* loop till all the entries in in array are not processed */ while (current_in_entry < sep_in_lli_entries) { - /* set the new input and output tables */ in_lli_table_ptr = (struct sep_lli_entry *)lli_table_alloc_addr; @@ -2229,8 +1944,7 @@ static int sep_construct_dma_tables_from_lli( SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) { - dev_warn(&sep->pdev->dev, - "dma table limit overrun\n"); + dev_warn(&sep->pdev->dev, "dma table limit overrun\n"); return -ENOMEM; } @@ -2281,8 +1995,8 @@ static int sep_construct_dma_tables_from_lli( block_size; } - dev_dbg(&sep->pdev->dev, - "table_data_size is %x\n", table_data_size); + dev_dbg(&sep->pdev->dev, "table_data_size is %x\n", + table_data_size); /* construct input lli table */ sep_build_lli_table(sep, &lli_in_array[current_in_entry], @@ -2380,9 +2094,7 @@ static int sep_construct_dma_tables_from_lli( *out_num_entries_ptr, *table_data_size_ptr); - dev_dbg(&sep->pdev->dev, - "sep_construct_dma_tables_from_lli end\n"); - + dev_dbg(&sep->pdev->dev, "sep_construct_dma_tables_from_lli end\n"); return 0; } @@ -2418,20 +2130,15 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, bool is_kva) { + int error = 0; /* array of pointers of page */ struct sep_lli_entry *lli_in_array; - /* array of pointers of page */ struct sep_lli_entry *lli_out_array; - /* error */ - int error = 0; - - dev_dbg(&sep->pdev->dev, - "sep_prepare_input_output_dma_table start\n"); + dev_dbg(&sep->pdev->dev, "sep_prepare_input_output_dma_table start\n"); if (data_size == 0) { - /* prepare empty table for input and output */ sep_prepare_empty_lli_table(sep, lli_table_in_ptr, in_num_entries_ptr, table_data_size_ptr); @@ -2471,8 +2178,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, error = sep_lock_user_pages(sep, app_virt_in_addr, data_size, &lli_in_array, SEP_DRIVER_IN_FLAG); if (error) { - dev_warn(&sep->pdev->dev, "sep_lock_user_pages for " - "input virtual buffer failed\n"); + dev_warn(&sep->pdev->dev, + "sep_lock_user_pages for input virtual buffer failed\n"); goto end_function; } @@ -2480,20 +2187,17 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, data_size, &lli_out_array, SEP_DRIVER_OUT_FLAG); if (error) { - dev_warn(&sep->pdev->dev, "sep_lock_user_pages for " - "output virtual buffer failed\n"); + dev_warn(&sep->pdev->dev, + "sep_lock_user_pages for output virtual buffer failed\n"); goto end_function_free_lli_in; } } - dev_dbg(&sep->pdev->dev, - "sep_in_num_pages is %x\n", + dev_dbg(&sep->pdev->dev, "sep_in_num_pages is %x\n", sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages); - dev_dbg(&sep->pdev->dev, - "sep_out_num_pages is %x\n", + dev_dbg(&sep->pdev->dev, "sep_out_num_pages is %x\n", sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages); - dev_dbg(&sep->pdev->dev, - "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", + dev_dbg(&sep->pdev->dev, "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); /* call the fucntion that creates table from the lli arrays */ @@ -2514,38 +2218,32 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, kfree(lli_in_array); update_dcb_counter: - /* update dcb counter */ sep->nr_dcb_creat++; - /* fall through - free the lli entry arrays */ - dev_dbg(&sep->pdev->dev, - "in_num_entries_ptr is %08x\n", *in_num_entries_ptr); - dev_dbg(&sep->pdev->dev, - "out_num_entries_ptr is %08x\n", *out_num_entries_ptr); - dev_dbg(&sep->pdev->dev, - "table_data_size_ptr is %08x\n", *table_data_size_ptr); + dev_dbg(&sep->pdev->dev, "in_num_entries_ptr is %08x\n", + *in_num_entries_ptr); + dev_dbg(&sep->pdev->dev, "out_num_entries_ptr is %08x\n", + *out_num_entries_ptr); + dev_dbg(&sep->pdev->dev, "table_data_size_ptr is %08x\n", + *table_data_size_ptr); goto end_function; end_function_with_error: - kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_map_array); kfree(sep->dma_res_arr[sep->nr_dcb_creat].out_page_array); kfree(lli_out_array); end_function_free_lli_in: - kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array); kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array); kfree(lli_in_array); end_function: - dev_dbg(&sep->pdev->dev, - "sep_prepare_input_output_dma_table" - " end result = %d\n", error); + "sep_prepare_input_output_dma_table end result = %d\n", error); return error; @@ -2576,35 +2274,26 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, bool isapplet, bool is_kva) { - /* error */ int error = 0; - /* size of tail */ u32 tail_size = 0; - /* address of the created dcb table */ struct sep_dcblock *dcb_table_ptr = 0; - /* the physical address of the first input DMA table */ dma_addr_t in_first_mlli_address = 0; - /* number of entries in the first input DMA table */ u32 in_first_num_entries = 0; - /* the physical address of the first output DMA table */ dma_addr_t out_first_mlli_address = 0; - /* number of entries in the first output DMA table */ u32 out_first_num_entries = 0; - /* data in the first input/output table */ u32 first_data_size = 0; - dev_dbg(&sep->pdev->dev, - "prepare_input_output_dma_table_in_dcb start\n"); + dev_dbg(&sep->pdev->dev, "prepare_input_output_dma_table_in_dcb start\n"); if (sep->nr_dcb_creat == SEP_MAX_NUM_SYNC_DMA_OPS) { - /*No more DCBS to allocate*/ + /* No more DCBS to allocate */ dev_warn(&sep->pdev->dev, "no more dcb's available\n"); error = -ENOSPC; goto end_function; @@ -2627,17 +2316,12 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, if (isapplet == true) { tail_size = data_in_size % block_size; - if (tail_size) { - if (data_in_size < tail_block_size) { - dev_warn(&sep->pdev->dev, - "data in size smaller than tail" - " block size\n"); + dev_warn(&sep->pdev->dev, "data in size smaller than tail block size\n"); error = -ENOSPC; goto end_function; } - if (tail_block_size) /* * case the tail size should be @@ -2645,7 +2329,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, */ tail_size = tail_block_size + ((data_in_size - - tail_block_size) % block_size); + tail_block_size) % block_size); } /* check if there is enough data for dma operation */ @@ -2653,9 +2337,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, if (is_kva == true) { memcpy(dcb_table_ptr->tail_data, (void *)app_in_address, data_in_size); - } - - else { + } else { if (copy_from_user(dcb_table_ptr->tail_data, (void __user *)app_in_address, data_in_size)) { @@ -2669,7 +2351,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, /* set the output user-space address for mem2mem op */ if (app_out_address) dcb_table_ptr->out_vr_tail_pt = - (u32)app_out_address; + (u32)app_out_address; /* * Update both data length parameters in order to avoid @@ -2679,15 +2361,12 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, tail_size = 0x0; data_in_size = 0x0; } - if (tail_size) { if (is_kva == true) { memcpy(dcb_table_ptr->tail_data, (void *)(app_in_address + data_in_size - tail_size), tail_size); - } - - else { + } else { /* we have tail data - copy it to dcb */ if (copy_from_user(dcb_table_ptr->tail_data, (void *)(app_in_address + @@ -2696,17 +2375,16 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, goto end_function; } } - if (app_out_address) /* - * Caclulate the output address + * Calculate the output address * according to tail data size */ dcb_table_ptr->out_vr_tail_pt = app_out_address + data_in_size - tail_size; - /*save the real tail data size*/ + /* Save the real tail data size */ dcb_table_ptr->tail_data_size = tail_size; /* * Update the data size without the tail @@ -2715,7 +2393,6 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, data_in_size = (data_in_size - tail_size); } } - /* check if we need to build only input table or input/output */ if (app_out_address) { /* prepare input/output tables */ @@ -2730,9 +2407,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, &out_first_num_entries, &first_data_size, is_kva); - } - - else { + } else { /* prepare input tables */ error = sep_prepare_input_dma_table(sep, app_in_address, @@ -2745,8 +2420,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, } if (error) { - dev_warn(&sep->pdev->dev, "prepare dma table call failed" - " from prepare dcb call\n"); + dev_warn(&sep->pdev->dev, "prepare dma table call failed from prepare dcb call\n"); goto end_function; } @@ -2759,7 +2433,6 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, dcb_table_ptr->output_mlli_data_size = first_data_size; end_function: - dev_dbg(&sep->pdev->dev, "sep_prepare_input_output_dma_table_in_dcb end\n"); return error; @@ -2788,28 +2461,22 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, "sep_create_sync_dma_tables_handler start\n"); if (copy_from_user(&command_args, (void __user *)arg, - sizeof(struct bld_syn_tab_struct))) { + sizeof(struct bld_syn_tab_struct))) { error = -EFAULT; - dev_warn(&sep->pdev->dev, "create dma tables;" - " copy_from_user fails\n"); goto end_function; } - dev_dbg(&sep->pdev->dev, - "app_in_address is %08llx\n", command_args.app_in_address); - dev_dbg(&sep->pdev->dev, - "app_out_address is %08llx\n", command_args.app_out_address); - dev_dbg(&sep->pdev->dev, - "data_size is %u\n", command_args.data_in_size); - dev_dbg(&sep->pdev->dev, - "block_size is %u\n", command_args.block_size); + dev_dbg(&sep->pdev->dev, "app_in_address is %08llx\n", + command_args.app_in_address); + dev_dbg(&sep->pdev->dev, "app_out_address is %08llx\n", + command_args.app_out_address); + dev_dbg(&sep->pdev->dev, "data_size is %u\n", + command_args.data_in_size); + dev_dbg(&sep->pdev->dev, "block_size is %u\n", + command_args.block_size); /* validate user parameters */ if (!command_args.app_in_address) { - - dev_warn(&sep->pdev->dev, - "params validation error\n"); - error = -EINVAL; goto end_function; } @@ -2824,7 +2491,6 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, false); end_function: - dev_dbg(&sep->pdev->dev, "sep_create_sync_dma_tables_handler end\n"); return error; } @@ -2840,17 +2506,14 @@ end_function: static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, bool is_kva) { - int i = 0; int error = 0; int error_temp = 0; - struct sep_dcblock *dcb_table_ptr; dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb start\n"); if (isapplet == true) { - /* set pointer to first dcb table */ dcb_table_ptr = (struct sep_dcblock *) (sep->shared_addr + @@ -2858,30 +2521,25 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, /* go over each dcb and see if tail pointer must be updated */ for (i = 0; i < sep->nr_dcb_creat; i++, dcb_table_ptr++) { - if (dcb_table_ptr->out_vr_tail_pt) { - if (is_kva == true) { memcpy((void *)dcb_table_ptr->out_vr_tail_pt, dcb_table_ptr->tail_data, dcb_table_ptr->tail_data_size); - } - - else { + } else { error_temp = copy_to_user( (void *)dcb_table_ptr->out_vr_tail_pt, dcb_table_ptr->tail_data, dcb_table_ptr->tail_data_size); } - if (error_temp) { /* release the dma resource */ - error = error_temp; + error = -EFAULT; + break; } } } } - /* free the output pages, if any */ sep_free_dma_table_data_handler(sep); @@ -2901,9 +2559,7 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg) { struct stat_pool_addr_struct command_args; - u32 *static_pool_addr = 0; - unsigned long addr_hold; dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler start\n"); @@ -3013,22 +2669,18 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) struct init_struct command_args; dev_dbg(&sep->pdev->dev, "sep_init_handler start\n"); - error = 0; /* make sure that we have not initialized already */ reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); if (reg_val != 0x2) { error = SEP_ALREADY_INITIALIZED_ERR; - dev_warn(&sep->pdev->dev, - "init; device already initialized\n"); + dev_warn(&sep->pdev->dev, "init; device already initialized\n"); goto end_function; } /* only root can initialize */ if (!capable(CAP_SYS_ADMIN)) { - dev_warn(&sep->pdev->dev, - "init; only root can init\n"); error = -EACCES; goto end_function; } @@ -3038,17 +2690,13 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) sizeof(struct init_struct)); if (error) { - dev_warn(&sep->pdev->dev, - "init; copy_from_user failed %x\n", error); + error = -EFAULT; goto end_function; } /* validate parameters */ if (!command_args.message_addr || !command_args.sep_sram_addr || command_args.message_size_in_words > 14) { - - dev_warn(&sep->pdev->dev, - "init; parameter error\n"); error = -EINVAL; goto end_function; } @@ -3060,9 +2708,7 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) command_args.message_size_in_words*sizeof(u32)); if (error) { - - dev_warn(&sep->pdev->dev, - "init; copy sep init message failed %x\n", error); + error = -EFAULT; goto end_function; } @@ -3070,7 +2716,6 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) error = sep_load_firmware(sep); if (error) { - dev_warn(&sep->pdev->dev, "init; copy sep init message failed %x\n", error); goto end_function; @@ -3102,10 +2747,8 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) /* debug print of message */ for (counter = 0; counter < command_args.message_size_in_words; - counter++) - - dev_dbg(&sep->pdev->dev, - "init; sep message word %d is %x\n", + counter++) + dev_dbg(&sep->pdev->dev, "init; sep message word %d is %x\n", counter, message_buff[counter]); /* tell the sep the sram address */ @@ -3113,11 +2756,9 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) /* push the message to the sep */ for (counter = 0; counter < command_args.message_size_in_words; - counter++) { - + counter++) { sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, - message_buff[counter]); - + message_buff[counter]); sep_wait_sram_write(sep); } @@ -3132,7 +2773,6 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) while (!(reg_val & 0xFFFFFFFD)); if (reg_val == 0x1) { - dev_warn(&sep->pdev->dev, "init; device int failed\n"); error = sep_read_reg(sep, 0x8060); dev_warn(&sep->pdev->dev, "init; sw monitor is %x\n", error); @@ -3140,9 +2780,7 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) dev_warn(&sep->pdev->dev, "init; error is %x\n", error); goto end_function; } - - dev_dbg(&sep->pdev->dev, "init; end CC INIT, reg_val is %x\n", - reg_val); + dev_dbg(&sep->pdev->dev, "init; end CC INIT, reg_val is %x\n", reg_val); /* signal sep to zero the GPR3 */ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x10); @@ -3154,7 +2792,6 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); while (reg_val != 0); - end_function: dev_dbg(&sep->pdev->dev, "init is done\n"); return error; @@ -3205,34 +2842,32 @@ static int sep_end_transaction_handler(struct sep_device *sep) * This function will retrieve the RAR buffer physical addresses, type * & size corresponding to the RAR handles provided in the buffers vector. */ - static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg) { /* error */ - int error = 0; - + int error; /* command arguments */ struct build_dcb_struct command_args; dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler start\n"); - /* get the command arguments */ + /* Get the command arguments */ if (copy_from_user(&command_args, (void __user *)arg, - sizeof(struct build_dcb_struct))) { + sizeof(struct build_dcb_struct))) { error = -EFAULT; goto end_function; } - dev_dbg(&sep->pdev->dev, - "app_in_address is %08llx\n", command_args.app_in_address); - dev_dbg(&sep->pdev->dev, - "app_out_address is %08llx\n", command_args.app_out_address); - dev_dbg(&sep->pdev->dev, - "data_size is %x\n", command_args.data_in_size); - dev_dbg(&sep->pdev->dev, - "block_size is %x\n", command_args.block_size); - dev_dbg(&sep->pdev->dev, - "tail block_size is %x\n", command_args.tail_block_size); + dev_dbg(&sep->pdev->dev, "app_in_address is %08llx\n", + command_args.app_in_address); + dev_dbg(&sep->pdev->dev, "app_out_address is %08llx\n", + command_args.app_out_address); + dev_dbg(&sep->pdev->dev, "data_size is %x\n", + command_args.data_in_size); + dev_dbg(&sep->pdev->dev, "block_size is %x\n", + command_args.block_size); + dev_dbg(&sep->pdev->dev, "tail block_size is %x\n", + command_args.tail_block_size); error = sep_prepare_input_output_dma_table_in_dcb(sep, command_args.app_in_address, command_args.app_out_address, @@ -3240,7 +2875,6 @@ static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg) command_args.tail_block_size, true, false); end_function: - dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler end\n"); return error; @@ -3274,52 +2908,40 @@ static int sep_free_dcb_handler(struct sep_device *sep) * This function will retrieve the RAR buffer physical addresses, type * & size corresponding to the RAR handles provided in the buffers vector. */ - static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, unsigned long arg) { - /* error return code */ int error = 0; - /* command args */ struct rar_hndl_to_bus_struct command_args; struct RAR_buffer rar_buf; - /* bus address */ dma_addr_t rar_bus = 0; - /* holds the RAR address in the system memory offset */ u32 *rar_addr; - dev_dbg(&sep->pdev->dev, - "sep_rar_prepare_output_msg_handler start\n"); + dev_dbg(&sep->pdev->dev, "sep_rar_prepare_output_msg_handler start\n"); /* copy the data */ - if (copy_from_user(&command_args, - (void __user *)arg, - sizeof(command_args))) { + if (copy_from_user(&command_args, (void __user *)arg, + sizeof(command_args))) { error = -EFAULT; goto end_function; } /* call to translation function only if user handle is not NULL */ if (command_args.rar_handle) { - memset(&rar_buf, 0, sizeof(rar_buf)); rar_buf.info.handle = (u32)command_args.rar_handle; if (rar_handle_to_bus(&rar_buf, 1) != 1) { - dev_dbg(&sep->pdev->dev, - "rar_handle_to_bus failure\n"); + dev_dbg(&sep->pdev->dev, "rar_handle_to_bus failure\n"); error = -EFAULT; goto end_function; } - rar_bus = rar_buf.bus_address; } - - dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", - (u32)rar_bus); + dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", (u32)rar_bus); /* set value in the SYSTEM MEMORY offset */ rar_addr = (u32 *)(sep->shared_addr + @@ -3330,10 +2952,7 @@ static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, rar_addr[1] = rar_bus; end_function: - - dev_dbg(&sep->pdev->dev, - "sep_rar_prepare_output_msg_handler start\n"); - + dev_dbg(&sep->pdev->dev, "sep_rar_prepare_output_msg_handler start\n"); return error; } @@ -3355,13 +2974,12 @@ static int sep_realloc_ext_cache_handler(struct sep_device *sep, SEP_DRIVER_SYSTEM_EXT_CACHE_ADDR_OFFSET_IN_BYTES); /* copy the physical address to the System Area for the sep */ - system_addr[0] = SEP_EXT_CACHE_ADDR_VAL_TOKEN; - dev_dbg(&sep->pdev->dev, - "ext cache init; system addr 0 is %x\n", system_addr[0]); + dev_dbg(&sep->pdev->dev, "ext cache init; system addr 0 is %x\n", + system_addr[0]); system_addr[1] = sep->extapp_bus; - dev_dbg(&sep->pdev->dev, - "ext cache init; system addr 1 is %x\n", system_addr[1]); + dev_dbg(&sep->pdev->dev, "ext cache init; system addr 1 is %x\n", + system_addr[1]); return 0; } @@ -3410,8 +3028,7 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* make sure we own this device */ mutex_lock(&sep->sep_mutex); if ((current->pid != sep->pid_doing_transaction) && - (sep->pid_doing_transaction != 0)) { - + (sep->pid_doing_transaction != 0)) { dev_dbg(&sep->pdev->dev, "ioctl pid is not owner\n"); mutex_unlock(&sep->sep_mutex); error = -EACCES; @@ -3485,15 +3102,13 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) error = sep_free_dcb_handler(sep); break; default: - dev_warn(&sep->pdev->dev, "invalid ioctl %x\n", cmd); + dev_dbg(&sep->pdev->dev, "invalid ioctl %x\n", cmd); error = -ENOTTY; break; } - mutex_unlock(&sep->ioctl_mutex); end_function: - dev_dbg(&sep->pdev->dev, "ioctl end\n"); return error; } @@ -3508,18 +3123,12 @@ end_function: */ static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg) { - /* error */ - long error; + long error = 0; struct sep_device *sep = filp->private_data; - error = 0; - - dev_dbg(&sep->pdev->dev, - "singleton_ioctl start\n"); - - dev_dbg(&sep->pdev->dev, - "cmd is %x\n", cmd); + dev_dbg(&sep->pdev->dev, "singleton_ioctl start\n"); + dev_dbg(&sep->pdev->dev, "cmd is %x\n", cmd); /* check that the command is for sep device */ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { @@ -3530,8 +3139,7 @@ static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg) /* make sure we own this device */ mutex_lock(&sep->sep_mutex); if ((current->pid != sep->pid_doing_transaction) && - (sep->pid_doing_transaction != 0)) { - + (sep->pid_doing_transaction != 0)) { dev_dbg(&sep->pdev->dev, "singleton ioctl pid is not owner\n"); mutex_unlock(&sep->sep_mutex); error = -EACCES; @@ -3541,21 +3149,17 @@ static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg) mutex_unlock(&sep->sep_mutex); switch (cmd) { - case SEP_IOCTLSETCALLERID: mutex_lock(&sep->ioctl_mutex); error = sep_set_caller_id_handler(sep, arg); mutex_unlock(&sep->ioctl_mutex); break; - default: error = sep_ioctl(filp, cmd, arg); break; - } end_function: - dev_dbg(&sep->pdev->dev, "singleton ioctl end\n"); return error; } @@ -3568,20 +3172,15 @@ end_function: * * Called by the request daemon to perform ioctls on the daemon device */ - static long sep_request_daemon_ioctl(struct file *filp, u32 cmd, unsigned long arg) { long error; - struct sep_device *sep = filp->private_data; - dev_dbg(&sep->pdev->dev, - "daemon ioctl: start\n"); - - dev_dbg(&sep->pdev->dev, - "daemon ioctl: cmd is %x\n", cmd); + dev_dbg(&sep->pdev->dev, "daemon ioctl: start\n"); + dev_dbg(&sep->pdev->dev, "daemon ioctl: cmd is %x\n", cmd); /* check that the command is for sep device */ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { @@ -3594,13 +3193,10 @@ static long sep_request_daemon_ioctl(struct file *filp, u32 cmd, switch (cmd) { case SEP_IOCSENDSEPRPLYCOMMAND: - /* send reply command to SEP */ error = sep_req_daemon_send_reply_command_handler(sep); break; - case SEP_IOCENDTRANSACTION: - /* * end req daemon transaction, do nothing * will be removed upon update in middleware @@ -3608,19 +3204,14 @@ static long sep_request_daemon_ioctl(struct file *filp, u32 cmd, */ error = 0; break; - default: - dev_dbg(&sep->pdev->dev, - "daemon ioctl: no such IOCTL\n"); + dev_dbg(&sep->pdev->dev, "daemon ioctl: no such IOCTL\n"); error = -ENOTTY; } - mutex_unlock(&sep->ioctl_mutex); end_function: - - dev_dbg(&sep->pdev->dev, - "daemon ioctl: end\n"); + dev_dbg(&sep->pdev->dev, "daemon ioctl: end\n"); return error; } @@ -3630,7 +3221,6 @@ end_function: * @irq: interrupt * @dev_id: device id */ - static irqreturn_t sep_inthandler(int irq, void *dev_id) { irqreturn_t int_error = IRQ_HANDLED; @@ -3640,18 +3230,16 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) /* read the IRR register to check if this is SEP interrupt */ reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); - dev_dbg(&sep->pdev->dev, - "SEP Interrupt - reg is %08x\n", reg_val); + dev_dbg(&sep->pdev->dev, "SEP Interrupt - reg is %08x\n", reg_val); if (reg_val & (0x1 << 13)) { - /* lock and update the counter of reply messages */ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); sep->reply_ct++; spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); dev_dbg(&sep->pdev->dev, "sep int: send_ct %lx reply_ct %lx\n", - sep->send_ct, sep->reply_ct); + sep->send_ct, sep->reply_ct); /* is this printf or daemon request? */ reg_val2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); @@ -3659,27 +3247,19 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) "SEP Interrupt - reg2 is %08x\n", reg_val2); if ((reg_val2 >> 30) & 0x1) { - dev_dbg(&sep->pdev->dev, "int: printf request\n"); wake_up(&sep->event_request_daemon); - } - - else if (reg_val2 >> 31) { - + } else if (reg_val2 >> 31) { dev_dbg(&sep->pdev->dev, "int: daemon request\n"); wake_up(&sep->event_request_daemon); } else { - dev_dbg(&sep->pdev->dev, "int: sep reply\n"); wake_up(&sep->event); } - } else { - dev_dbg(&sep->pdev->dev, "int: not sep interrupt\n"); int_error = IRQ_NONE; } - if (int_error == IRQ_HANDLED) sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val); @@ -3695,16 +3275,14 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) */ static int sep_callback(unsigned long sep_context_pointer) { - int error = 0; - struct sep_device *sep = - (struct sep_device *)sep_context_pointer; - - dma_addr_t rar_end_address = 0; + int error; + struct sep_device *sep = (struct sep_device *)sep_context_pointer; + dma_addr_t rar_end_address; dev_dbg(&sep->pdev->dev, "callback start\n"); error = rar_get_address(RAR_TYPE_IMAGE, &sep->rar_bus, - &rar_end_address); + &rar_end_address); if (error) { dev_warn(&sep->pdev->dev, "mrst cant get rar region\n"); @@ -3714,9 +3292,9 @@ static int sep_callback(unsigned long sep_context_pointer) sep->rar_size = (size_t)(rar_end_address - sep->rar_bus + 1); if (!request_mem_region(sep->rar_bus, sep->rar_size, - "sep_sec_driver")) { + "sep_sec_driver")) { dev_warn(&sep->pdev->dev, - "request mem region for mrst failed\n"); + "request mem region for mrst failed\n"); error = -1; goto end_function; } @@ -3724,18 +3302,15 @@ static int sep_callback(unsigned long sep_context_pointer) sep->rar_addr = ioremap_nocache(sep->rar_bus, sep->rar_size); if (!sep->rar_addr) { dev_warn(&sep->pdev->dev, - "ioremap nocache for mrst rar failed\n"); - error = -1; + "ioremap nocache for mrst rar failed\n"); + error = -ENOMEM; goto end_function; } - - dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx," - " size is %x\n", - sep->rar_addr, (unsigned long long)sep->rar_bus, - sep->rar_size); + dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx, size is %x\n", + sep->rar_addr, (unsigned long long)sep->rar_bus, + sep->rar_size); end_function: - dev_dbg(&sep->pdev->dev, "callback end\n"); return error; } @@ -3769,7 +3344,6 @@ static int __devinit sep_probe(struct pci_dev *pdev, /* allocate the sep_device structure for this device */ sep_dev = kmalloc(sizeof(struct sep_device), GFP_ATOMIC); - if (sep_dev == NULL) { dev_warn(&pdev->dev, "can't kmalloc the sep_device structure\n"); @@ -3865,8 +3439,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, sep->rar_size); } - dev_dbg(&sep->pdev->dev, - "about to write IMR and ICR REG_ADDR\n"); + dev_dbg(&sep->pdev->dev, "about to write IMR and ICR REG_ADDR\n"); /* clear ICR register */ sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF); @@ -3874,18 +3447,14 @@ static int __devinit sep_probe(struct pci_dev *pdev, /* set the IMR register - open only GPR 2 */ sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); - dev_dbg(&sep->pdev->dev, - "about to call request_irq\n"); + dev_dbg(&sep->pdev->dev, "about to call request_irq\n"); /* get the interrupt line */ error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep); - if (error) - goto end_function_free_res; - - goto end_function; + if (!error) + goto end_function; -end_function_free_res: if (sep->rar_addr) dma_free_coherent(&sep->pdev->dev, sep->rar_size, sep->rar_addr, sep->rar_bus); @@ -3959,37 +3528,29 @@ static const struct file_operations sep_file_operations = { */ static int sep_reconfig_shared_area(struct sep_device *sep) { - int ret_val = 0; + int ret_val; dev_dbg(&sep->pdev->dev, "reconfig shared area start\n"); /* send the new SHARED MESSAGE AREA to the SEP */ dev_dbg(&sep->pdev->dev, "sending %08llx to sep\n", - (unsigned long long)sep->shared_bus); + (unsigned long long)sep->shared_bus); - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, - sep->shared_bus); + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); /* poll for SEP response */ ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - while (ret_val != 0xffffffff && - ret_val != sep->shared_bus) { - - ret_val = sep_read_reg(sep, - HW_HOST_SEP_HOST_GPR1_REG_ADDR); - } + while (ret_val != 0xffffffff && ret_val != sep->shared_bus) + ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); /* check the return value (register) */ if (ret_val != sep->shared_bus) { dev_warn(&sep->pdev->dev, "could not reconfig shared area\n"); dev_warn(&sep->pdev->dev, "result was %x\n", ret_val); ret_val = -ENOMEM; - } - - else { + } else ret_val = 0; - } dev_dbg(&sep->pdev->dev, "reconfig shared area end\n"); return ret_val; @@ -4003,7 +3564,7 @@ static int sep_reconfig_shared_area(struct sep_device *sep) */ static int sep_register_driver_to_fs(struct sep_device *sep) { - int ret_val = 0; + int ret_val; sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR; sep->miscdev_sep.name = SEP_DEV_NAME; @@ -4035,8 +3596,7 @@ static int sep_register_driver_to_fs(struct sep_device *sep) if (!sep->mrst) { ret_val = misc_register(&sep->miscdev_daemon); if (ret_val) { - dev_warn(&sep->pdev->dev, - "misc reg fails for dmn %x\n", + dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n", ret_val); misc_deregister(&sep->miscdev_sep); misc_deregister(&sep->miscdev_singleton); @@ -4044,7 +3604,6 @@ static int sep_register_driver_to_fs(struct sep_device *sep) return ret_val; } } - return ret_val; } @@ -4062,8 +3621,8 @@ static int __init sep_init(void) ret_val = pci_register_driver(&sep_pci_driver); if (ret_val) { - pr_debug("sep_driver:sep_driver_to_device failed," - " ret_val is %d\n", ret_val); + pr_debug("sep_driver:sep_driver_to_device failed, ret_val is %d\n", + ret_val); goto end_function; } @@ -4085,11 +3644,9 @@ static int __init sep_init(void) /* register driver to fs */ ret_val = sep_register_driver_to_fs(sep); if (ret_val) { - dev_warn(&sep->pdev->dev, - "error registering device to file\n"); + dev_warn(&sep->pdev->dev, "error registering device to file\n"); goto end_function_unregister_pci; } - goto end_function; end_function_unregister_pci: -- cgit v1.2.3 From 7c9eb69123a634c8551e8887bda03c2e549da233 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:38:21 +0000 Subject: Staging: sep: Use kzalloc when needed Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index f576285fbb8f..ff9df36d5461 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -3343,16 +3343,13 @@ static int __devinit sep_probe(struct pci_dev *pdev, } /* allocate the sep_device structure for this device */ - sep_dev = kmalloc(sizeof(struct sep_device), GFP_ATOMIC); + sep_dev = kzalloc(sizeof(struct sep_device), GFP_ATOMIC); if (sep_dev == NULL) { dev_warn(&pdev->dev, "can't kmalloc the sep_device structure\n"); return -ENOMEM; } - /* zero out sep structure */ - memset((void *)sep_dev, 0, sizeof(struct sep_device)); - /* * we're going to use another variable for actually * working with the device; this way, if we have @@ -3365,8 +3362,6 @@ static int __devinit sep_probe(struct pci_dev *pdev, if (pdev->device == MRST_PCI_DEVICE_ID) sep->mrst = 1; - else - sep->mrst = 0; dev_dbg(&sep->pdev->dev, "PCI obtained, device being prepared\n"); dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision); @@ -3423,7 +3418,6 @@ static int __devinit sep_probe(struct pci_dev *pdev, goto end_function_deallocate_sep_shared_area; } } else { - sep->rar_size = FAKE_RAR_SIZE; sep->rar_addr = dma_alloc_coherent(NULL, sep->rar_size, &sep->rar_bus, GFP_KERNEL); -- cgit v1.2.3 From 6eb44c531763ff50325822bac749e92938782795 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:38:39 +0000 Subject: Staging: sep: Make SEP consistent SEP is initials so make it consistent in the driver, ditto DMA and DCB Consistent capitalisation of comment leads Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 631 +++++++++++++++++++-------------------- 1 file changed, 313 insertions(+), 318 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index ff9df36d5461..9c165587a247 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -92,7 +92,7 @@ static int sep_load_firmware(struct sep_device *sep) int error ; unsigned int work1, work2, work3; - /* set addresses and load resident */ + /* Set addresses and load resident */ sep->resident_bus = sep->rar_bus; sep->resident_addr = sep->rar_addr; @@ -113,7 +113,7 @@ static int sep_load_firmware(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "resident size is %08x\n", sep->resident_size); - /* set addresses for dcache (no loading needed) */ + /* Set addresses for dcache (no loading needed) */ work1 = (unsigned int)sep->resident_bus; work2 = (unsigned int)sep->resident_size; work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000; @@ -126,7 +126,7 @@ static int sep_load_firmware(struct sep_device *sep) sep->dcache_size = 1024 * 128; - /* set addresses and load cache */ + /* Set addresses and load cache */ sep->cache_bus = sep->dcache_bus + sep->dcache_size; sep->cache_addr = sep->dcache_addr + sep->dcache_size; @@ -147,7 +147,7 @@ static int sep_load_firmware(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "cache size is %08x\n", sep->cache_size); - /* set addresses and load extapp */ + /* Set addresses and load extapp */ sep->extapp_bus = sep->cache_bus + (1024 * 370); sep->extapp_addr = sep->cache_addr + (1024 * 370); @@ -177,7 +177,7 @@ MODULE_FIRMWARE("sep/extapp.image.bin"); /** * sep_dump_message - dump the message that is pending - * @sep: sep device + * @sep: SEP device */ static void sep_dump_message(struct sep_device *sep) { @@ -205,7 +205,7 @@ static int sep_map_and_alloc_shared_area(struct sep_device *sep) return -ENOMEM; } dev_dbg(&sep->pdev->dev, - "sep: shared_addr %x bytes @%p (bus %llx)\n", + "shared_addr %x bytes @%p (bus %llx)\n", sep->shared_size, sep->shared_addr, (unsigned long long)sep->shared_bus); return 0; @@ -249,7 +249,7 @@ static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) struct sep_device *sep; /* - * Get the sep device structure and use it for the + * Get the SEP device structure and use it for the * private_data field in filp for other methods */ sep = sep_dev; @@ -274,8 +274,8 @@ end_function: /** * sep_open - device open method - * @inode: inode of sep device - * @filp: file handle to sep device + * @inode: inode of SEP device + * @filp: file handle to SEP device * * Open method for the SEP device. Called when userspace opens * the SEP device node. @@ -287,7 +287,7 @@ static int sep_open(struct inode *inode, struct file *filp) struct sep_device *sep; /* - * Get the sep device structure and use it for the + * Get the SEP device structure and use it for the * private_data field in filp for other methods */ sep = sep_dev; @@ -320,8 +320,8 @@ static int sep_singleton_release(struct inode *inode, struct file *filp) /** * sep_request_daemonopen - request daemon open method - * @inode: inode of sep device - * @filp: file handle to sep device + * @inode: inode of SEP device + * @filp: file handle to SEP device * * Open method for the SEP request daemon. Called when * request daemon in userspace opens the SEP device node. @@ -359,7 +359,7 @@ static int sep_request_daemon_release(struct inode *inode, struct file *filp) dev_dbg(&sep->pdev->dev, "Reques daemon release for pid %d\n", current->pid); - /* clear the request_daemon_open flag */ + /* Clear the request_daemon_open flag */ clear_bit(0, &sep->request_daemon_open); return 0; } @@ -380,12 +380,12 @@ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) sep_dump_message(sep); - /* counters are lockable region */ + /* Counters are lockable region */ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); sep->send_ct++; sep->reply_ct++; - /* send the interrupt to SEP */ + /* Send the interrupt to SEP */ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct); @@ -408,13 +408,13 @@ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) * sep_free_dma_table_data_handler - free DMA table * @sep: pointere to struct sep_device * - * Handles the request to free dma table for synchronic actions + * Handles the request to free DMA table for synchronic actions */ static int sep_free_dma_table_data_handler(struct sep_device *sep) { int count; int dcb_counter; - /* pointer to the current dma_resource struct */ + /* Pointer to the current dma_resource struct */ struct sep_dma_resource *dma; dev_dbg(&sep->pdev->dev, "sep_free_dma_table_data_handler start\n"); @@ -422,7 +422,7 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) for (dcb_counter = 0; dcb_counter < sep->nr_dcb_creat; dcb_counter++) { dma = &sep->dma_res_arr[dcb_counter]; - /* unmap and free input map array */ + /* Unmap and free input map array */ if (dma->in_map_array) { for (count = 0; count < dma->in_num_pages; count++) { dma_unmap_page(&sep->pdev->dev, @@ -433,7 +433,7 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) kfree(dma->in_map_array); } - /* unmap output map array, DON'T free it yet */ + /* Unmap output map array, DON'T free it yet */ if (dma->out_map_array) { for (count = 0; count < dma->out_num_pages; count++) { dma_unmap_page(&sep->pdev->dev, @@ -444,7 +444,7 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) kfree(dma->out_map_array); } - /* free page cache for output */ + /* Free page cache for output */ if (dma->in_page_array) { for (count = 0; count < dma->in_num_pages; count++) { flush_dcache_page(dma->in_page_array[count]); @@ -463,7 +463,7 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) kfree(dma->out_page_array); } - /* reset all the values */ + /* Reset all the values */ dma->in_page_array = 0; dma->out_page_array = 0; dma->in_num_pages = 0; @@ -503,7 +503,7 @@ static int sep_request_daemon_mmap(struct file *filp, goto end_function; } - /* get physical address */ + /* Get physical address */ bus_address = sep->shared_bus; dev_dbg(&sep->pdev->dev, "bus_address is %08lx\n", @@ -524,7 +524,7 @@ end_function: /** * sep_request_daemon_poll - poll implementation - * @sep: struct sep_device * for current sep device + * @sep: struct sep_device * for current SEP device * @filp: struct file * for open file * @wait: poll_table * for poll * @@ -547,7 +547,7 @@ static unsigned int sep_request_daemon_poll(struct file *filp, sep->send_ct, sep->reply_ct); spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); - /* check if the data is ready */ + /* Check if the data is ready */ if (sep->send_ct == sep->reply_ct) { spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); @@ -555,13 +555,13 @@ static unsigned int sep_request_daemon_poll(struct file *filp, dev_dbg(&sep->pdev->dev, "daemon poll: data check (GPR2) is %x\n", retval2); - /* check if PRINT request */ + /* Check if PRINT request */ if ((retval2 >> 30) & 0x1) { dev_dbg(&sep->pdev->dev, "daemon poll: PRINTF request in\n"); mask |= POLLIN; goto end_function; } - /* check if NVS request */ + /* Check if NVS request */ if (retval2 >> 31) { dev_dbg(&sep->pdev->dev, "daemon poll: NVS request in\n"); mask |= POLLPRI | POLLWRNORM; @@ -591,7 +591,7 @@ static int sep_release(struct inode *inode, struct file *filp) dev_dbg(&sep->pdev->dev, "Release for pid %d\n", current->pid); mutex_lock(&sep->sep_mutex); - /* is this the process that has a transaction open? + /* Is this the process that has a transaction open? * If so, lets reset pid_doing_transaction to 0 and * clear the in use flags, and then wake up sep_event * so that other processes can do transactions @@ -614,7 +614,7 @@ static int sep_release(struct inode *inode, struct file *filp) * @filp: pointer to struct file * @vma: pointer to vm_area_struct * - * Called on an mmap of our space via the normal sep device + * Called on an mmap of our space via the normal SEP device */ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) { @@ -636,8 +636,8 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) /* * The pid_doing_transaction indicates that this process * now owns the facilities to performa a transaction with - * the sep. While this process is performing a transaction, - * no other process who has the sep device open can perform + * the SEP. While this process is performing a transaction, + * no other process who has the SEP device open can perform * any transactions. This method allows more than one process * to have the device open at any given time, which provides * finer granularity for device utilization by multiple @@ -647,12 +647,12 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) sep->pid_doing_transaction = current->pid; mutex_unlock(&sep->sep_mutex); - /* zero the pools and the number of data pool alocation pointers */ + /* Zero the pools and the number of data pool alocation pointers */ sep->data_pool_bytes_allocated = 0; sep->num_of_data_allocations = 0; /* - * check that the size of the mapped range is as the size of the message + * Check that the size of the mapped range is as the size of the message * shared area */ if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) { @@ -662,7 +662,7 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) dev_dbg(&sep->pdev->dev, "shared_addr is %p\n", sep->shared_addr); - /* get bus address */ + /* Get bus address */ bus_addr = sep->shared_bus; dev_dbg(&sep->pdev->dev, @@ -678,13 +678,13 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) goto end_function; end_function_with_error: - /* clear the bit */ + /* Clear the bit */ clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags); mutex_lock(&sep->sep_mutex); sep->pid_doing_transaction = 0; mutex_unlock(&sep->sep_mutex); - /* raise event for stuck contextes */ + /* Raise event for stuck contextes */ dev_warn(&sep->pdev->dev, "mmap error - waking up event\n"); wake_up(&sep->event); @@ -722,14 +722,14 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) } mutex_unlock(&sep->sep_mutex); - /* check if send command or send_reply were activated previously */ + /* Check if send command or send_reply were activated previously */ if (!test_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags)) { dev_warn(&sep->pdev->dev, "poll; lock bit set\n"); mask = POLLERR; goto end_function; } - /* add the event to the polling wait table */ + /* Add the event to the polling wait table */ dev_dbg(&sep->pdev->dev, "poll: calling wait sep_event\n"); poll_wait(filp, &sep->event, wait); @@ -737,7 +737,7 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) dev_dbg(&sep->pdev->dev, "poll: send_ct is %lx reply ct is %lx\n", sep->send_ct, sep->reply_ct); - /* check if error occured during poll */ + /* Check if error occured during poll */ retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); if (retval2 != 0x0) { dev_warn(&sep->pdev->dev, "poll; poll error %x\n", retval2); @@ -753,25 +753,24 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) dev_dbg(&sep->pdev->dev, "poll: data ready check (GPR2) %x\n", retval); - /* check if printf request */ + /* Check if printf request */ if ((retval >> 30) & 0x1) { - dev_dbg(&sep->pdev->dev, "poll: sep printf request\n"); + dev_dbg(&sep->pdev->dev, "poll: SEP printf request\n"); wake_up(&sep->event_request_daemon); goto end_function; } - /* check if the this is sep reply or request */ + /* Check if the this is SEP reply or request */ if (retval >> 31) { - dev_dbg(&sep->pdev->dev, "poll: sep request\n"); + dev_dbg(&sep->pdev->dev, "poll: SEP request\n"); wake_up(&sep->event_request_daemon); } else { dev_dbg(&sep->pdev->dev, "poll: normal return\n"); - /* in case it is again by send_reply_comand */ + /* In case it is again by send_reply_comand */ clear_bit(SEP_SEND_MSG_LOCK_BIT, &sep->in_use_flags); sep_dump_message(sep); dev_dbg(&sep->pdev->dev, - "poll; sep reply POLLIN | POLLRDNORM\n"); - + "poll; SEP reply POLLIN | POLLRDNORM\n"); mask |= POLLIN | POLLRDNORM; } } else { @@ -803,19 +802,19 @@ static u32 *sep_time_address(struct sep_device *sep) * @sep: the SEP we are setting the time for * * Calculates time and sets it at the predefined address. - * Called with the sep mutex held. + * Called with the SEP mutex held. */ static unsigned long sep_set_time(struct sep_device *sep) { struct timeval time; - u32 *time_addr; /* address of time as seen by the kernel */ + u32 *time_addr; /* Address of time as seen by the kernel */ - dev_dbg(&sep->pdev->dev, "sep:sep_set_time start\n"); + dev_dbg(&sep->pdev->dev, "sep_set_time start\n"); do_gettimeofday(&time); - /* set value in the SYSTEM MEMORY offset */ + /* Set value in the SYSTEM MEMORY offset */ time_addr = sep_time_address(sep); time_addr[0] = SEP_TIME_VAL_TOKEN; @@ -830,7 +829,7 @@ static unsigned long sep_set_time(struct sep_device *sep) /** * sep_set_caller_id_handler - insert caller id entry - * @sep: sep device + * @sep: SEP device * @arg: pointer to struct caller_id_struct * * Inserts the data into the caller id table. Note that this function @@ -858,7 +857,7 @@ static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) goto end_function; } - /* copy the data */ + /* Copy the data */ if (copy_from_user(&command_args, (void __user *)arg, sizeof(command_args))) { error = -EFAULT; @@ -894,9 +893,9 @@ end_function: /** * sep_set_current_caller_id - set the caller id - * @sep: pointer to struct_sep + * @sep: pointer to struct_sep_device * - * Set the caller ID (if it exists) to the sep. Note that this + * Set the caller ID (if it exists) to the SEP. Note that this * function falls under the ioctl lock */ static int sep_set_current_caller_id(struct sep_device *sep) @@ -906,7 +905,7 @@ static int sep_set_current_caller_id(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id start\n"); dev_dbg(&sep->pdev->dev, "current process is %d\n", current->pid); - /* zero the previous value */ + /* Zero the previous value */ memset(sep->shared_addr + SEP_CALLER_ID_OFFSET_BYTES, 0, SEP_CALLER_ID_HASH_SIZE_IN_BYTES); @@ -926,7 +925,7 @@ static int sep_set_current_caller_id(struct sep_device *sep) /** * sep_send_command_handler - kick off a command - * @sep: sep being signalled + * @sep: SEP being signalled * * This function raises interrupt to SEP that signals that is has a new * command from the host @@ -946,13 +945,13 @@ static int sep_send_command_handler(struct sep_device *sep) } sep_set_time(sep); - /* only Medfield has caller id */ + /* Only Medfield has caller id */ if (sep->mrst == 0) sep_set_current_caller_id(sep); sep_dump_message(sep); - /* update counter */ + /* Update counter */ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); sep->send_ct++; spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); @@ -961,7 +960,7 @@ static int sep_send_command_handler(struct sep_device *sep) "sep_send_command_handler send_ct %lx reply_ct %lx\n", sep->send_ct, sep->reply_ct); - /* send interrupt to SEP */ + /* Send interrupt to SEP */ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); end_function: @@ -971,7 +970,7 @@ end_function: /** * sep_allocate_data_pool_memory_handler -allocate pool memory - * @sep: pointer to struct_sep + * @sep: pointer to struct sep_device * @arg: pointer to struct alloc_struct * * This function handles the allocate data pool memory request @@ -1016,7 +1015,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "command_args.offset: %x\n", command_args.offset); - /* Place in the shared area that is known by the sep */ + /* Place in the shared area that is known by the SEP */ token_addr = (u32 *)(sep->shared_addr + SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES + (sep->num_of_data_allocations)*2*sizeof(u32)); @@ -1043,7 +1042,7 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, goto end_function; } - /* update the allocation */ + /* Update the allocation */ sep->data_pool_bytes_allocated += command_args.num_bytes; sep->num_of_data_allocations += 1; @@ -1079,9 +1078,9 @@ static int sep_lock_kernel_pages(struct sep_device *sep, { int error = 0; - /* array of lli */ + /* Array of lli */ struct sep_lli_entry *lli_array; - /* map array */ + /* Map array */ struct sep_dma_map *map_array; dev_dbg(&sep->pdev->dev, @@ -1110,7 +1109,7 @@ static int sep_lock_kernel_pages(struct sep_device *sep, /* - * set the start address of the first page - app data may start not at + * Set the start address of the first page - app data may start not at * the beginning of the page */ lli_array[0].bus_address = (u32)map_array[0].dma_addr; @@ -1121,7 +1120,7 @@ static int sep_lock_kernel_pages(struct sep_device *sep, (unsigned long)lli_array[0].bus_address, lli_array[0].block_size); - /* set the output parameters */ + /* Set the output parameters */ if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 1; @@ -1168,25 +1167,25 @@ static int sep_lock_user_pages(struct sep_device *sep, int error = 0; u32 count; int result; - /* the the page of the end address of the user space buffer */ + /* The the page of the end address of the user space buffer */ u32 end_page; - /* the page of the start address of the user space buffer */ + /* The page of the start address of the user space buffer */ u32 start_page; - /* the range in pages */ + /* The range in pages */ u32 num_pages; - /* array of pointers to page */ + /* Array of pointers to page */ struct page **page_array; - /* array of lli */ + /* Array of lli */ struct sep_lli_entry *lli_array; - /* map array */ + /* Map array */ struct sep_dma_map *map_array; - /* direction of the DMA mapping for locked pages */ + /* Direction of the DMA mapping for locked pages */ enum dma_data_direction dir; dev_dbg(&sep->pdev->dev, "sep_lock_user_pages start\n"); - /* set start and end pages and num pages */ + /* Set start and end pages and num pages */ end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; start_page = app_virt_addr >> PAGE_SHIFT; num_pages = end_page - start_page + 1; @@ -1199,7 +1198,7 @@ static int sep_lock_user_pages(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "starting page_array malloc\n"); - /* allocate array of pages structure pointers */ + /* Allocate array of pages structure pointers */ page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); if (!page_array) { error = -ENOMEM; @@ -1223,7 +1222,7 @@ static int sep_lock_user_pages(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "starting get_user_pages\n"); - /* convert the application virtual address into a set of physical */ + /* Convert the application virtual address into a set of physical */ down_read(¤t->mm->mmap_sem); result = get_user_pages(current, current->mm, app_virt_addr, num_pages, @@ -1232,7 +1231,7 @@ static int sep_lock_user_pages(struct sep_device *sep, up_read(¤t->mm->mmap_sem); - /* check the number of pages locked - if not all then exit with error */ + /* Check the number of pages locked - if not all then exit with error */ if (result != num_pages) { dev_warn(&sep->pdev->dev, "not all pages locked by get_user_pages\n"); @@ -1242,26 +1241,25 @@ static int sep_lock_user_pages(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "get_user_pages succeeded\n"); - /* set direction */ + /* Set direction */ if (in_out_flag == SEP_DRIVER_IN_FLAG) dir = DMA_TO_DEVICE; else dir = DMA_FROM_DEVICE; /* - * fill the array using page array data and - * map the pages - this action - * will also flush the cache as needed + * Fill the array using page array data and + * map the pages - this action will also flush the cache as needed */ for (count = 0; count < num_pages; count++) { - /* fill the map array */ + /* Fill the map array */ map_array[count].dma_addr = dma_map_page(&sep->pdev->dev, page_array[count], 0, PAGE_SIZE, /*dir*/DMA_BIDIRECTIONAL); map_array[count].size = PAGE_SIZE; - /* fill the lli array entry */ + /* Fill the lli array entry */ lli_array[count].bus_address = (u32)map_array[count].dma_addr; lli_array[count].block_size = PAGE_SIZE; @@ -1270,11 +1268,11 @@ static int sep_lock_user_pages(struct sep_device *sep, count, lli_array[count].block_size); } - /* check the offset for the first page */ + /* Check the offset for the first page */ lli_array[0].bus_address = lli_array[0].bus_address + (app_virt_addr & (~PAGE_MASK)); - /* check that not all the data is in the first page only */ + /* Check that not all the data is in the first page only */ if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) lli_array[0].block_size = data_size; else @@ -1286,7 +1284,7 @@ static int sep_lock_user_pages(struct sep_device *sep, (unsigned long)lli_array[count].bus_address, lli_array[count].block_size); - /* check the size of the last page */ + /* Check the size of the last page */ if (num_pages > 1) { lli_array[num_pages - 1].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); @@ -1299,7 +1297,7 @@ static int sep_lock_user_pages(struct sep_device *sep, lli_array[count].block_size); } - /* set output params acording to the in_out flag */ + /* Set output params acording to the in_out flag */ if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = num_pages; @@ -1319,14 +1317,14 @@ static int sep_lock_user_pages(struct sep_device *sep, goto end_function; end_function_with_error3: - /* free lli array */ + /* Free lli array */ kfree(lli_array); end_function_with_error2: kfree(map_array); end_function_with_error1: - /* free page array */ + /* Free page array */ kfree(page_array); end_function: @@ -1352,15 +1350,15 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, u32 *last_table_flag) { u32 counter; - /* table data size */ + /* Table data size */ u32 table_data_size = 0; - /* data size for the next table */ + /* Data size for the next table */ u32 next_table_data_size; *last_table_flag = 0; /* - * calculate the data in the out lli table till we fill the whole + * Calculate the data in the out lli table till we fill the whole * table or till the data has ended */ for (counter = 0; @@ -1369,20 +1367,19 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, table_data_size += lli_in_array_ptr[counter].block_size; /* - * check if we reached the last entry, + * Check if we reached the last entry, * meaning this ia the last table to build, * and no need to check the block alignment */ if (counter == num_array_entries) { - /* set the last table flag */ + /* Set the last table flag */ *last_table_flag = 1; goto end_function; } /* - * calculate the data size of the next table. - * Stop if no entries left or - * if data size is more the DMA restriction + * Calculate the data size of the next table. + * Stop if no entries left or if data size is more the DMA restriction */ next_table_data_size = 0; for (; counter < num_array_entries; counter++) { @@ -1392,7 +1389,7 @@ static u32 sep_calculate_lli_table_max_size(struct sep_device *sep, } /* - * check if the next table data size is less then DMA rstriction. + * Check if the next table data size is less then DMA rstriction. * if it is - recalculate the current table size, so that the next * table data size will be adaquete for DMA */ @@ -1427,23 +1424,23 @@ static void sep_build_lli_table(struct sep_device *sep, u32 *num_table_entries_ptr, u32 table_data_size) { - /* current table data size */ + /* Current table data size */ u32 curr_table_data_size; - /* counter of lli array entry */ + /* Counter of lli array entry */ u32 array_counter; dev_dbg(&sep->pdev->dev, "sep_build_lli_table start\n"); - /* init currrent table data size and lli array entry counter */ + /* Init currrent table data size and lli array entry counter */ curr_table_data_size = 0; array_counter = 0; *num_table_entries_ptr = 1; dev_dbg(&sep->pdev->dev, "table_data_size is %x\n", table_data_size); - /* fill the table till table size reaches the needed amount */ + /* Fill the table till table size reaches the needed amount */ while (curr_table_data_size < table_data_size) { - /* update the number of entries in table */ + /* Update the number of entries in table */ (*num_table_entries_ptr)++; lli_table_ptr->bus_address = @@ -1461,24 +1458,24 @@ static void sep_build_lli_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n", lli_table_ptr->block_size); - /* check for overflow of the table data */ + /* Check for overflow of the table data */ if (curr_table_data_size > table_data_size) { dev_dbg(&sep->pdev->dev, "curr_table_data_size too large\n"); - /* update the size of block in the table */ + /* Update the size of block in the table */ lli_table_ptr->block_size -= cpu_to_le32((curr_table_data_size - table_data_size)); - /* update the physical address in the lli array */ + /* Update the physical address in the lli array */ lli_array_ptr[array_counter].bus_address += cpu_to_le32(lli_table_ptr->block_size); - /* update the block size left in the lli array */ + /* Update the block size left in the lli array */ lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size); } else - /* advance to the next entry in the lli_array */ + /* Advance to the next entry in the lli_array */ array_counter++; dev_dbg(&sep->pdev->dev, @@ -1488,11 +1485,11 @@ static void sep_build_lli_table(struct sep_device *sep, "lli_table_ptr->block_size is %x\n", lli_table_ptr->block_size); - /* move to the next entry in table */ + /* Move to the next entry in table */ lli_table_ptr++; } - /* set the info entry to default */ + /* Set the info entry to default */ lli_table_ptr->bus_address = 0xffffffff; lli_table_ptr->block_size = 0; @@ -1502,7 +1499,7 @@ static void sep_build_lli_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "lli_table_ptr->block_size is %x\n", lli_table_ptr->block_size); - /* set the output parameter */ + /* Set the output parameter */ *num_processed_entries_ptr += array_counter; dev_dbg(&sep->pdev->dev, "num_processed_entries_ptr is %x\n", @@ -1578,7 +1575,7 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "num_table_entries is %lu\n", num_table_entries); - /* print entries of the table (without info entry) */ + /* Print entries of the table (without info entry) */ for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) { @@ -1591,7 +1588,7 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, (unsigned long)lli_table_ptr->bus_address, lli_table_ptr->block_size); } - /* point to the info entry */ + /* Point to the info entry */ lli_table_ptr--; dev_dbg(&sep->pdev->dev, @@ -1642,7 +1639,7 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "sep_prepare_empty_lli_table start\n"); - /* find the area for new table */ + /* Find the area for new table */ lli_table_ptr = (struct sep_lli_entry *)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + @@ -1656,18 +1653,18 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep, lli_table_ptr->bus_address = 0xFFFFFFFF; lli_table_ptr->block_size = 0; - /* set the output parameter value */ + /* Set the output parameter value */ *lli_table_addr_ptr = sep->shared_bus + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + sep->num_lli_tables_created * sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - /* set the num of entries and table data size for empty table */ + /* Set the num of entries and table data size for empty table */ *num_entries_ptr = 2; *table_data_size_ptr = 0; - /* update the number of created tables */ + /* Update the number of created tables */ sep->num_lli_tables_created++; dev_dbg(&sep->pdev->dev, "sep_prepare_empty_lli_table start\n"); @@ -1686,7 +1683,7 @@ static void sep_prepare_empty_lli_table(struct sep_device *sep, * * This function prepares only input DMA table for synhronic symmetric * operations (HASH) - * Note that all bus addresses that are passed to the sep + * Note that all bus addresses that are passed to the SEP * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_dma_table(struct sep_device *sep, @@ -1699,54 +1696,54 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, bool is_kva) { int error = 0; - /* pointer to the info entry of the table - the last entry */ + /* Pointer to the info entry of the table - the last entry */ struct sep_lli_entry *info_entry_ptr; - /* array of pointers to page */ + /* Array of pointers to page */ struct sep_lli_entry *lli_array_ptr; - /* points to the first entry to be processed in the lli_in_array */ + /* Points to the first entry to be processed in the lli_in_array */ u32 current_entry = 0; - /* num entries in the virtual buffer */ + /* Num entries in the virtual buffer */ u32 sep_lli_entries = 0; - /* lli table pointer */ + /* Lli table pointer */ struct sep_lli_entry *in_lli_table_ptr; - /* the total data in one table */ + /* The total data in one table */ u32 table_data_size = 0; - /* flag for last table */ + /* Flag for last table */ u32 last_table_flag = 0; - /* number of entries in lli table */ + /* Number of entries in lli table */ u32 num_entries_in_table = 0; - /* next table address */ + /* Next table address */ u32 lli_table_alloc_addr = 0; dev_dbg(&sep->pdev->dev, "sep_prepare_input_dma_table start\n"); dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size); dev_dbg(&sep->pdev->dev, "block_size is %x\n", block_size); - /* initialize the pages pointers */ + /* Initialize the pages pointers */ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 0; - /* set the kernel address for first table to be allocated */ + /* Set the kernel address for first table to be allocated */ lli_table_alloc_addr = (u32)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + sep->num_lli_tables_created * sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); if (data_size == 0) { - /* special case - create meptu table - 2 entries, zero data */ + /* Special case - create meptu table - 2 entries, zero data */ sep_prepare_empty_lli_table(sep, lli_table_ptr, num_entries_ptr, table_data_size_ptr); goto update_dcb_counter; } - /* check if the pages are in Kernel Virtual Address layout */ + /* Check if the pages are in Kernel Virtual Address layout */ if (is_kva == true) - /* lock the pages in the kernel */ + /* Lock the pages in the kernel */ error = sep_lock_kernel_pages(sep, app_virt_addr, data_size, &lli_array_ptr, SEP_DRIVER_IN_FLAG); else /* - * lock the pages of the user buffer + * Lock the pages of the user buffer * and translate them to pages */ error = sep_lock_user_pages(sep, app_virt_addr, @@ -1763,10 +1760,10 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, sep_lli_entries = sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages; - /* loop till all the entries in in array are not processed */ + /* Loop till all the entries in in array are not processed */ while (current_entry < sep_lli_entries) { - /* set the new input and output tables */ + /* Set the new input and output tables */ in_lli_table_ptr = (struct sep_lli_entry *)lli_table_alloc_addr; @@ -1783,17 +1780,17 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, } - /* update the number of created tables */ + /* Update the number of created tables */ sep->num_lli_tables_created++; - /* calculate the maximum size of data for input table */ + /* Calculate the maximum size of data for input table */ table_data_size = sep_calculate_lli_table_max_size(sep, &lli_array_ptr[current_entry], (sep_lli_entries - current_entry), &last_table_flag); /* - * if this is not the last table - + * If this is not the last table - * then allign it to the block size */ if (!last_table_flag) @@ -1803,14 +1800,14 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "output table_data_size is %x\n", table_data_size); - /* construct input lli table */ + /* Construct input lli table */ sep_build_lli_table(sep, &lli_array_ptr[current_entry], in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); if (info_entry_ptr == 0) { - /* set the output parameters to physical addresses */ + /* Set the output parameters to physical addresses */ *lli_table_ptr = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); *num_entries_ptr = num_entries_in_table; @@ -1821,7 +1818,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, (unsigned long)*lli_table_ptr); } else { - /* update the info entry of the previous in table */ + /* Update the info entry of the previous in table */ info_entry_ptr->bus_address = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); @@ -1829,23 +1826,23 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, ((num_entries_in_table) << 24) | (table_data_size); } - /* save the pointer to the info entry of the current tables */ + /* Save the pointer to the info entry of the current tables */ info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; } - /* print input tables */ + /* Print input tables */ sep_debug_print_lli_tables(sep, (struct sep_lli_entry *) sep_shared_area_bus_to_virt(sep, *lli_table_ptr), *num_entries_ptr, *table_data_size_ptr); - /* the array of the pages */ + /* The array of the pages */ kfree(lli_array_ptr); update_dcb_counter: - /* update dcb counter */ + /* Update DCB counter */ sep->nr_dcb_creat++; goto end_function; end_function_error: - /* free all the allocated resources */ + /* Free all the allocated resources */ kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_map_array); kfree(lli_array_ptr); kfree(sep->dma_res_arr[sep->nr_dcb_creat].in_page_array); @@ -1857,7 +1854,7 @@ end_function: } /** * sep_construct_dma_tables_from_lli - prepare AES/DES mappings - * @sep: pointer to struct_sep + * @sep: pointer to struct sep_device * @lli_in_array: * @sep_in_lli_entries: * @lli_out_array: @@ -1869,10 +1866,10 @@ end_function: * @out_num_entries_ptr * @table_data_size_ptr * - * This function creates the input and output dma tables for + * This function creates the input and output DMA tables for * symmetric operations (AES/DES) according to the block * size from LLI arays - * Note that all bus addresses that are passed to the sep + * Note that all bus addresses that are passed to the SEP * are in 32 bit format; the SEP is a 32 bit device */ static int sep_construct_dma_tables_from_lli( @@ -1888,56 +1885,56 @@ static int sep_construct_dma_tables_from_lli( u32 *out_num_entries_ptr, u32 *table_data_size_ptr) { - /* points to the area where next lli table can be allocated */ + /* Points to the area where next lli table can be allocated */ u32 lli_table_alloc_addr = 0; - /* input lli table */ + /* Input lli table */ struct sep_lli_entry *in_lli_table_ptr = 0; - /* output lli table */ + /* Output lli table */ struct sep_lli_entry *out_lli_table_ptr = 0; - /* pointer to the info entry of the table - the last entry */ + /* Pointer to the info entry of the table - the last entry */ struct sep_lli_entry *info_in_entry_ptr = 0; - /* pointer to the info entry of the table - the last entry */ + /* Pointer to the info entry of the table - the last entry */ struct sep_lli_entry *info_out_entry_ptr = 0; - /* points to the first entry to be processed in the lli_in_array */ + /* Points to the first entry to be processed in the lli_in_array */ u32 current_in_entry = 0; - /* points to the first entry to be processed in the lli_out_array */ + /* Points to the first entry to be processed in the lli_out_array */ u32 current_out_entry = 0; - /* max size of the input table */ + /* Max size of the input table */ u32 in_table_data_size = 0; - /* max size of the output table */ + /* Max size of the output table */ u32 out_table_data_size = 0; - /* flag te signifies if this is the last tables build */ + /* Flag te signifies if this is the last tables build */ u32 last_table_flag = 0; - /* the data size that should be in table */ + /* The data size that should be in table */ u32 table_data_size = 0; - /* number of etnries in the input table */ + /* Number of etnries in the input table */ u32 num_entries_in_table = 0; - /* number of etnries in the output table */ + /* Number of etnries in the output table */ u32 num_entries_out_table = 0; dev_dbg(&sep->pdev->dev, "sep_construct_dma_tables_from_lli start\n"); - /* initiate to point after the message area */ + /* Initiate to point after the message area */ lli_table_alloc_addr = (u32)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + (sep->num_lli_tables_created * (sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP))); - /* loop till all the entries in in array are not processed */ + /* Loop till all the entries in in array are not processed */ while (current_in_entry < sep_in_lli_entries) { - /* set the new input and output tables */ + /* Set the new input and output tables */ in_lli_table_ptr = (struct sep_lli_entry *)lli_table_alloc_addr; lli_table_alloc_addr += sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - /* set the first output tables */ + /* Set the first output tables */ out_lli_table_ptr = (struct sep_lli_entry *)lli_table_alloc_addr; - /* check if the DMA table area limit was overrun */ + /* Check if the DMA table area limit was overrun */ if ((lli_table_alloc_addr + sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP) > ((u32)sep->shared_addr + @@ -1948,20 +1945,20 @@ static int sep_construct_dma_tables_from_lli( return -ENOMEM; } - /* update the number of the lli tables created */ + /* Update the number of the lli tables created */ sep->num_lli_tables_created += 2; lli_table_alloc_addr += sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - /* calculate the maximum size of data for input table */ + /* Calculate the maximum size of data for input table */ in_table_data_size = sep_calculate_lli_table_max_size(sep, &lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry), &last_table_flag); - /* calculate the maximum size of data for output table */ + /* Calculate the maximum size of data for output table */ out_table_data_size = sep_calculate_lli_table_max_size(sep, &lli_out_array[current_out_entry], @@ -1980,7 +1977,7 @@ static int sep_construct_dma_tables_from_lli( if (!last_table_flag) { /* - * if this is not the last table, + * If this is not the last table, * then must check where the data is smallest * and then align it to the block size */ @@ -1988,7 +1985,7 @@ static int sep_construct_dma_tables_from_lli( table_data_size = out_table_data_size; /* - * now calculate the table size so that + * Now calculate the table size so that * it will be module block size */ table_data_size = (table_data_size / block_size) * @@ -1998,23 +1995,23 @@ static int sep_construct_dma_tables_from_lli( dev_dbg(&sep->pdev->dev, "table_data_size is %x\n", table_data_size); - /* construct input lli table */ + /* Construct input lli table */ sep_build_lli_table(sep, &lli_in_array[current_in_entry], in_lli_table_ptr, ¤t_in_entry, &num_entries_in_table, table_data_size); - /* construct output lli table */ + /* Construct output lli table */ sep_build_lli_table(sep, &lli_out_array[current_out_entry], out_lli_table_ptr, ¤t_out_entry, &num_entries_out_table, table_data_size); - /* if info entry is null - this is the first table built */ + /* If info entry is null - this is the first table built */ if (info_in_entry_ptr == 0) { - /* set the output parameters to physical addresses */ + /* Set the output parameters to physical addresses */ *lli_table_in_ptr = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); @@ -2034,7 +2031,7 @@ static int sep_construct_dma_tables_from_lli( "output lli_table_out_ptr is %08lx\n", (unsigned long)*lli_table_out_ptr); } else { - /* update the info entry of the previous in table */ + /* Update the info entry of the previous in table */ info_in_entry_ptr->bus_address = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); @@ -2043,7 +2040,7 @@ static int sep_construct_dma_tables_from_lli( ((num_entries_in_table) << 24) | (table_data_size); - /* update the info entry of the previous in table */ + /* Update the info entry of the previous in table */ info_out_entry_ptr->bus_address = sep_shared_area_virt_to_bus(sep, out_lli_table_ptr); @@ -2063,7 +2060,7 @@ static int sep_construct_dma_tables_from_lli( info_out_entry_ptr->block_size); } - /* save the pointer to the info entry of the current tables */ + /* Save the pointer to the info entry of the current tables */ info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; info_out_entry_ptr = out_lli_table_ptr + @@ -2080,14 +2077,14 @@ static int sep_construct_dma_tables_from_lli( (unsigned long)info_out_entry_ptr); } - /* print input tables */ + /* Print input tables */ sep_debug_print_lli_tables(sep, (struct sep_lli_entry *) sep_shared_area_bus_to_virt(sep, *lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr); - /* print output tables */ + /* Print output tables */ sep_debug_print_lli_tables(sep, (struct sep_lli_entry *) sep_shared_area_bus_to_virt(sep, *lli_table_out_ptr), @@ -2114,7 +2111,7 @@ static int sep_construct_dma_tables_from_lli( * This function builds input and output DMA tables for synhronic * symmetric operations (AES, DES, HASH). It also checks that each table * is of the modular block size - * Note that all bus addresses that are passed to the sep + * Note that all bus addresses that are passed to the SEP * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_output_dma_table(struct sep_device *sep, @@ -2131,15 +2128,15 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, { int error = 0; - /* array of pointers of page */ + /* Array of pointers of page */ struct sep_lli_entry *lli_in_array; - /* array of pointers of page */ + /* Array of pointers of page */ struct sep_lli_entry *lli_out_array; dev_dbg(&sep->pdev->dev, "sep_prepare_input_output_dma_table start\n"); if (data_size == 0) { - /* prepare empty table for input and output */ + /* Prepare empty table for input and output */ sep_prepare_empty_lli_table(sep, lli_table_in_ptr, in_num_entries_ptr, table_data_size_ptr); @@ -2149,11 +2146,11 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, goto update_dcb_counter; } - /* initialize the pages pointers */ + /* Initialize the pages pointers */ sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = 0; - /* lock the pages of the buffer and translate them to pages */ + /* Lock the pages of the buffer and translate them to pages */ if (is_kva == true) { error = sep_lock_kernel_pages(sep, app_virt_in_addr, data_size, &lli_in_array, SEP_DRIVER_IN_FLAG); @@ -2200,7 +2197,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); - /* call the fucntion that creates table from the lli arrays */ + /* Call the fucntion that creates table from the lli arrays */ error = sep_construct_dma_tables_from_lli(sep, lli_in_array, sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages, lli_out_array, @@ -2218,9 +2215,9 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, kfree(lli_in_array); update_dcb_counter: - /* update dcb counter */ + /* Update DCB counter */ sep->nr_dcb_creat++; - /* fall through - free the lli entry arrays */ + /* Fall through - free the lli entry arrays */ dev_dbg(&sep->pdev->dev, "in_num_entries_ptr is %08x\n", *in_num_entries_ptr); dev_dbg(&sep->pdev->dev, "out_num_entries_ptr is %08x\n", @@ -2259,10 +2256,10 @@ end_function: * @isapplet: bool; to indicate external app * @is_kva: bool; kernel buffer; only used for kernel crypto module * - * This function prepares the linked dma tables and puts the - * address for the linked list of tables inta a dcb (data control - * block) the address of which is known by the sep hardware - * Note that all bus addresses that are passed to the sep + * This function prepares the linked DMA tables and puts the + * address for the linked list of tables inta a DCB (data control + * block) the address of which is known by the SEP hardware + * Note that all bus addresses that are passed to the SEP * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, @@ -2275,36 +2272,36 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, bool is_kva) { int error = 0; - /* size of tail */ + /* Size of tail */ u32 tail_size = 0; - /* address of the created dcb table */ + /* Address of the created DCB table */ struct sep_dcblock *dcb_table_ptr = 0; - /* the physical address of the first input DMA table */ + /* The physical address of the first input DMA table */ dma_addr_t in_first_mlli_address = 0; - /* number of entries in the first input DMA table */ + /* Number of entries in the first input DMA table */ u32 in_first_num_entries = 0; - /* the physical address of the first output DMA table */ + /* The physical address of the first output DMA table */ dma_addr_t out_first_mlli_address = 0; - /* number of entries in the first output DMA table */ + /* Number of entries in the first output DMA table */ u32 out_first_num_entries = 0; - /* data in the first input/output table */ + /* Data in the first input/output table */ u32 first_data_size = 0; dev_dbg(&sep->pdev->dev, "prepare_input_output_dma_table_in_dcb start\n"); if (sep->nr_dcb_creat == SEP_MAX_NUM_SYNC_DMA_OPS) { - /* No more DCBS to allocate */ - dev_warn(&sep->pdev->dev, "no more dcb's available\n"); + /* No more DCBs to allocate */ + dev_warn(&sep->pdev->dev, "no more DCBs available\n"); error = -ENOSPC; goto end_function; } - /* allocate new DCB */ + /* Allocate new DCB */ dcb_table_ptr = (struct sep_dcblock *)(sep->shared_addr + SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES + (sep->nr_dcb_creat * sizeof(struct sep_dcblock))); - /* set the default values in the dcb */ + /* Set the default values in the DCB */ dcb_table_ptr->input_mlli_address = 0; dcb_table_ptr->input_mlli_num_entries = 0; dcb_table_ptr->input_mlli_data_size = 0; @@ -2324,7 +2321,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, } if (tail_block_size) /* - * case the tail size should be + * Case the tail size should be * bigger than the real block size */ tail_size = tail_block_size + @@ -2332,7 +2329,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, tail_block_size) % block_size); } - /* check if there is enough data for dma operation */ + /* Check if there is enough data for DMA operation */ if (data_in_size < SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE) { if (is_kva == true) { memcpy(dcb_table_ptr->tail_data, @@ -2348,7 +2345,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, dcb_table_ptr->tail_data_size = data_in_size; - /* set the output user-space address for mem2mem op */ + /* Set the output user-space address for mem2mem op */ if (app_out_address) dcb_table_ptr->out_vr_tail_pt = (u32)app_out_address; @@ -2367,7 +2364,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, (void *)(app_in_address + data_in_size - tail_size), tail_size); } else { - /* we have tail data - copy it to dcb */ + /* We have tail data - copy it to DCB */ if (copy_from_user(dcb_table_ptr->tail_data, (void *)(app_in_address + data_in_size - tail_size), tail_size)) { @@ -2393,9 +2390,9 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, data_in_size = (data_in_size - tail_size); } } - /* check if we need to build only input table or input/output */ + /* Check if we need to build only input table or input/output */ if (app_out_address) { - /* prepare input/output tables */ + /* Prepare input/output tables */ error = sep_prepare_input_output_dma_table(sep, app_in_address, app_out_address, @@ -2408,7 +2405,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, &first_data_size, is_kva); } else { - /* prepare input tables */ + /* Prepare input tables */ error = sep_prepare_input_dma_table(sep, app_in_address, data_in_size, @@ -2420,11 +2417,11 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, } if (error) { - dev_warn(&sep->pdev->dev, "prepare dma table call failed from prepare dcb call\n"); + dev_warn(&sep->pdev->dev, "prepare DMA table call failed from prepare DCB call\n"); goto end_function; } - /* set the dcb values */ + /* Set the DCB values */ dcb_table_ptr->input_mlli_address = in_first_mlli_address; dcb_table_ptr->input_mlli_num_entries = in_first_num_entries; dcb_table_ptr->input_mlli_data_size = first_data_size; @@ -2441,7 +2438,7 @@ end_function: /** - * sep_create_sync_dma_tables_handler - create sync dma tables + * sep_create_sync_dma_tables_handler - create sync DMA tables * @sep: pointer to struct sep_device * @arg: pointer to struct bld_syn_tab_struct * @@ -2454,7 +2451,7 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, { int error = 0; - /* command arguments */ + /* Command arguments */ struct bld_syn_tab_struct command_args; dev_dbg(&sep->pdev->dev, @@ -2475,7 +2472,7 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "block_size is %u\n", command_args.block_size); - /* validate user parameters */ + /* Validate user parameters */ if (!command_args.app_in_address) { error = -EINVAL; goto end_function; @@ -2501,7 +2498,7 @@ end_function: * @isapplet: indicates external application (used for kernel access) * @is_kva: indicates kernel addresses (only used for kernel crypto) * - * This function frees the dma tables and dcb block + * This function frees the DMA tables and DCB */ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, bool is_kva) @@ -2514,12 +2511,12 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb start\n"); if (isapplet == true) { - /* set pointer to first dcb table */ + /* Set pointer to first DCB table */ dcb_table_ptr = (struct sep_dcblock *) (sep->shared_addr + SEP_DRIVER_SYSTEM_DCB_MEMORY_OFFSET_IN_BYTES); - /* go over each dcb and see if tail pointer must be updated */ + /* Go over each DCB and see if tail pointer must be updated */ for (i = 0; i < sep->nr_dcb_creat; i++, dcb_table_ptr++) { if (dcb_table_ptr->out_vr_tail_pt) { if (is_kva == true) { @@ -2533,14 +2530,14 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, dcb_table_ptr->tail_data_size); } if (error_temp) { - /* release the dma resource */ + /* Release the DMA resource */ error = -EFAULT; break; } } } } - /* free the output pages, if any */ + /* Free the output pages, if any */ sep_free_dma_table_data_handler(sep); dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb end\n"); @@ -2579,7 +2576,7 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, (u32)static_pool_addr[1], (u32)command_args.static_virt_address); - /* send the parameters to user application */ + /* Send the parameters to user application */ if (copy_to_user((void __user *) arg, &command_args, sizeof(struct stat_pool_addr_struct))) return -EFAULT; @@ -2600,14 +2597,14 @@ static int sep_start_handler(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "sep_start_handler start\n"); - /* wait in polling for message from SEP */ + /* Wait in polling for message from SEP */ do reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); while (!reg_val); - /* check the value */ + /* Check the value */ if (reg_val == 0x1) - /* fatal error - read error status from GPRO */ + /* Fatal error - read error status from GPRO */ error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); dev_dbg(&sep->pdev->dev, "sep_start_handler end\n"); return error; @@ -2619,7 +2616,7 @@ static int sep_start_handler(struct sep_device *sep) * @length: buffer size * * This function performs a checksum for messages that are sent - * to the sep + * to the SEP. */ static u32 sep_check_sum_calc(u8 *data, u32 length) { @@ -2651,7 +2648,7 @@ static u32 sep_check_sum_calc(u8 *data, u32 length) * Handles the request for SEP initialization * Note that this will go away for Medfield once the SCU * SEP initialization is complete - * Also note that the message to the sep has components + * Also note that the message to the SEP has components * from user space as well as components written by the driver * This is becuase the portions of the message that pertain to * physical addresses must be set by the driver after the message @@ -2670,7 +2667,7 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) dev_dbg(&sep->pdev->dev, "sep_init_handler start\n"); - /* make sure that we have not initialized already */ + /* Make sure that we have not initialized already */ reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); if (reg_val != 0x2) { @@ -2679,13 +2676,13 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) goto end_function; } - /* only root can initialize */ + /* Only root can initialize */ if (!capable(CAP_SYS_ADMIN)) { error = -EACCES; goto end_function; } - /* copy in the parameters */ + /* Copy in the parameters */ error = copy_from_user(&command_args, (void __user *)arg, sizeof(struct init_struct)); @@ -2694,14 +2691,14 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) goto end_function; } - /* validate parameters */ + /* Validate parameters */ if (!command_args.message_addr || !command_args.sep_sram_addr || command_args.message_size_in_words > 14) { error = -EINVAL; goto end_function; } - /* copy in the sep init message */ + /* Copy in the SEP init message */ addr_hold = (unsigned long)command_args.message_addr; error = copy_from_user(message_buff, (void __user *)addr_hold, @@ -2712,16 +2709,16 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) goto end_function; } - /* load resident, cache, and extapp firmware */ + /* Load resident, cache, and extapp firmware */ error = sep_load_firmware(sep); if (error) { dev_warn(&sep->pdev->dev, - "init; copy sep init message failed %x\n", error); + "init; copy SEP init message failed %x\n", error); goto end_function; } - /* compute the base address */ + /* Compute the base address */ new_base_addr = sep->shared_bus; if (sep->resident_bus < new_base_addr) @@ -2733,7 +2730,7 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) if (sep->dcache_bus < new_base_addr) new_base_addr = sep->dcache_bus; - /* put physical addresses in sep message */ + /* Put physical addresses in SEP message */ message_buff[3] = (u32)new_base_addr; message_buff[4] = (u32)sep->shared_bus; message_buff[6] = (u32)sep->resident_bus; @@ -2745,16 +2742,16 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) sep_check_sum_calc((u8 *)message_buff, command_args.message_size_in_words*sizeof(u32)); - /* debug print of message */ + /* Debug print of message */ for (counter = 0; counter < command_args.message_size_in_words; counter++) - dev_dbg(&sep->pdev->dev, "init; sep message word %d is %x\n", + dev_dbg(&sep->pdev->dev, "init; SEP message word %d is %x\n", counter, message_buff[counter]); - /* tell the sep the sram address */ + /* Tell the SEP the sram address */ sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, command_args.sep_sram_addr); - /* push the message to the sep */ + /* Push the message to the SEP */ for (counter = 0; counter < command_args.message_size_in_words; counter++) { sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, @@ -2762,10 +2759,10 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) sep_wait_sram_write(sep); } - /* signal sep that message is ready and to init */ + /* Signal SEP that message is ready and to init */ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1); - /* wait for acknowledge */ + /* Wait for acknowledge */ dev_dbg(&sep->pdev->dev, "init; waiting for msg response\n"); do @@ -2782,10 +2779,10 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) } dev_dbg(&sep->pdev->dev, "init; end CC INIT, reg_val is %x\n", reg_val); - /* signal sep to zero the GPR3 */ + /* Signal SEP to zero the GPR3 */ sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x10); - /* wait for response */ + /* Wait for response */ dev_dbg(&sep->pdev->dev, "init; waiting for zero set response\n"); do @@ -2807,25 +2804,25 @@ static int sep_end_transaction_handler(struct sep_device *sep) { dev_dbg(&sep->pdev->dev, "sep_end_transaction_handler start\n"); - /* clear the data pool pointers Token */ + /* Clear the data pool pointers Token */ memset((void *)(sep->shared_addr + SEP_DRIVER_DATA_POOL_ALLOCATION_OFFSET_IN_BYTES), 0, sep->num_of_data_allocations*2*sizeof(u32)); - /* check that all the dma resources were freed */ + /* Check that all the DMA resources were freed */ sep_free_dma_table_data_handler(sep); clear_bit(SEP_MMAP_LOCK_BIT, &sep->in_use_flags); /* - * we are now through with the transaction. Let's + * We are now through with the transaction. Let's * allow other processes who have the device open * to perform transactions */ mutex_lock(&sep->sep_mutex); sep->pid_doing_transaction = 0; mutex_unlock(&sep->sep_mutex); - /* raise event for stuck contextes */ + /* Raise event for stuck contextes */ wake_up(&sep->event); dev_dbg(&sep->pdev->dev, "waking up event\n"); @@ -2844,9 +2841,8 @@ static int sep_end_transaction_handler(struct sep_device *sep) */ static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg) { - /* error */ int error; - /* command arguments */ + /* Command arguments */ struct build_dcb_struct command_args; dev_dbg(&sep->pdev->dev, "sep_prepare_dcb_handler start\n"); @@ -2912,24 +2908,24 @@ static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, unsigned long arg) { int error = 0; - /* command args */ + /* Command args */ struct rar_hndl_to_bus_struct command_args; struct RAR_buffer rar_buf; - /* bus address */ + /* Bus address */ dma_addr_t rar_bus = 0; - /* holds the RAR address in the system memory offset */ + /* Holds the RAR address in the system memory offset */ u32 *rar_addr; dev_dbg(&sep->pdev->dev, "sep_rar_prepare_output_msg_handler start\n"); - /* copy the data */ + /* Copy the data */ if (copy_from_user(&command_args, (void __user *)arg, sizeof(command_args))) { error = -EFAULT; goto end_function; } - /* call to translation function only if user handle is not NULL */ + /* Call to translation function only if user handle is not NULL */ if (command_args.rar_handle) { memset(&rar_buf, 0, sizeof(rar_buf)); rar_buf.info.handle = (u32)command_args.rar_handle; @@ -2943,11 +2939,11 @@ static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, } dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", (u32)rar_bus); - /* set value in the SYSTEM MEMORY offset */ + /* Set value in the SYSTEM MEMORY offset */ rar_addr = (u32 *)(sep->shared_addr + SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES); - /* copy the physical address to the System Area for the sep */ + /* Copy the physical address to the System Area for the SEP */ rar_addr[0] = SEP_RAR_VAL_TOKEN; rar_addr[1] = rar_bus; @@ -2961,19 +2957,19 @@ end_function: * @sep: pointer to struct sep_device * @arg: pointer to user parameters * - * This function tells the sep where the extapp is located + * This function tells the SEP where the extapp is located */ static int sep_realloc_ext_cache_handler(struct sep_device *sep, unsigned long arg) { - /* holds the new ext cache address in the system memory offset */ + /* Holds the new ext cache address in the system memory offset */ u32 *system_addr; - /* set value in the SYSTEM MEMORY offset */ + /* Set value in the SYSTEM MEMORY offset */ system_addr = (u32 *)(sep->shared_addr + SEP_DRIVER_SYSTEM_EXT_CACHE_ADDR_OFFSET_IN_BYTES); - /* copy the physical address to the System Area for the sep */ + /* Copy the physical address to the System Area for the SEP */ system_addr[0] = SEP_EXT_CACHE_ADDR_VAL_TOKEN; dev_dbg(&sep->pdev->dev, "ext cache init; system addr 0 is %x\n", system_addr[0]); @@ -3025,7 +3021,7 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) dev_dbg(&sep->pdev->dev, "SEP_IOCFREEDCB is %x\n", SEP_IOCFREEDCB); - /* make sure we own this device */ + /* Make sure we own this device */ mutex_lock(&sep->sep_mutex); if ((current->pid != sep->pid_doing_transaction) && (sep->pid_doing_transaction != 0)) { @@ -3037,48 +3033,48 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mutex_unlock(&sep->sep_mutex); - /* check that the command is for sep device */ + /* Check that the command is for SEP device */ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { error = -ENOTTY; goto end_function; } - /* lock to prevent the daemon to interfere with operation */ + /* Lock to prevent the daemon to interfere with operation */ mutex_lock(&sep->ioctl_mutex); switch (cmd) { case SEP_IOCSENDSEPCOMMAND: - /* send command to SEP */ + /* Send command to SEP */ error = sep_send_command_handler(sep); break; case SEP_IOCALLOCDATAPOLL: - /* allocate data pool */ + /* Allocate data pool */ error = sep_allocate_data_pool_memory_handler(sep, arg); break; case SEP_IOCCREATESYMDMATABLE: - /* create dma table for synhronic operation */ + /* Create DMA table for synhronic operation */ error = sep_create_sync_dma_tables_handler(sep, arg); break; case SEP_IOCFREEDMATABLEDATA: - /* free the pages */ + /* Free the pages */ error = sep_free_dma_table_data_handler(sep); break; case SEP_IOCSEPSTART: - /* start command to sep */ - if (sep->pdev->revision == 0) /* only for old chip */ + /* Start command to SEP */ + if (sep->pdev->revision == 0) /* Only for old chip */ error = sep_start_handler(sep); else - error = -EPERM; /* not permitted on new chip */ + error = -EPERM; /* Not permitted on new chip */ break; case SEP_IOCSEPINIT: - /* init command to sep */ - if (sep->pdev->revision == 0) /* only for old chip */ + /* Init command to SEP */ + if (sep->pdev->revision == 0) /* Only for old chip */ error = sep_init_handler(sep, arg); else - error = -EPERM; /* not permitted on new chip */ + error = -EPERM; /* Not permitted on new chip */ break; case SEP_IOCGETSTATICPOOLADDR: - /* get the physical and virtual addresses of the static pool */ + /* Get the physical and virtual addresses of the static pool */ error = sep_get_static_pool_addr_handler(sep, arg); break; case SEP_IOCENDTRANSACTION: @@ -3087,10 +3083,10 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case SEP_IOCREALLOCEXTCACHE: if (sep->mrst) error = -ENODEV; - if (sep->pdev->revision == 0) /* only for old chip */ + if (sep->pdev->revision == 0) /* Only for old chip */ error = sep_realloc_ext_cache_handler(sep, arg); else - error = -EPERM; /* not permitted on new chip */ + error = -EPERM; /* Not permitted on new chip */ break; case SEP_IOCRARPREPAREMESSAGE: error = sep_rar_prepare_output_msg_handler(sep, arg); @@ -3123,20 +3119,19 @@ end_function: */ static long sep_singleton_ioctl(struct file *filp, u32 cmd, unsigned long arg) { - /* error */ long error = 0; struct sep_device *sep = filp->private_data; dev_dbg(&sep->pdev->dev, "singleton_ioctl start\n"); dev_dbg(&sep->pdev->dev, "cmd is %x\n", cmd); - /* check that the command is for sep device */ + /* Check that the command is for the SEP device */ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { error = -ENOTTY; goto end_function; } - /* make sure we own this device */ + /* Make sure we own this device */ mutex_lock(&sep->sep_mutex); if ((current->pid != sep->pid_doing_transaction) && (sep->pid_doing_transaction != 0)) { @@ -3182,23 +3177,23 @@ static long sep_request_daemon_ioctl(struct file *filp, u32 cmd, dev_dbg(&sep->pdev->dev, "daemon ioctl: start\n"); dev_dbg(&sep->pdev->dev, "daemon ioctl: cmd is %x\n", cmd); - /* check that the command is for sep device */ + /* Check that the command is for SEP device */ if (_IOC_TYPE(cmd) != SEP_IOC_MAGIC_NUMBER) { error = -ENOTTY; goto end_function; } - /* only one process can access ioctl at any given time */ + /* Only one process can access ioctl at any given time */ mutex_lock(&sep->ioctl_mutex); switch (cmd) { case SEP_IOCSENDSEPRPLYCOMMAND: - /* send reply command to SEP */ + /* Send reply command to SEP */ error = sep_req_daemon_send_reply_command_handler(sep); break; case SEP_IOCENDTRANSACTION: /* - * end req daemon transaction, do nothing + * End req daemon transaction, do nothing * will be removed upon update in middleware * API library */ @@ -3217,7 +3212,7 @@ end_function: } /** - * sep_inthandler - Interrupt Handler + * sep_inthandler - interrupt handler * @irq: interrupt * @dev_id: device id */ @@ -3228,12 +3223,12 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) u32 reg_val, reg_val2 = 0; struct sep_device *sep = dev_id; - /* read the IRR register to check if this is SEP interrupt */ + /* Read the IRR register to check if this is SEP interrupt */ reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); dev_dbg(&sep->pdev->dev, "SEP Interrupt - reg is %08x\n", reg_val); if (reg_val & (0x1 << 13)) { - /* lock and update the counter of reply messages */ + /* Lock and update the counter of reply messages */ spin_lock_irqsave(&sep->snd_rply_lck, lck_flags); sep->reply_ct++; spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); @@ -3241,7 +3236,7 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) dev_dbg(&sep->pdev->dev, "sep int: send_ct %lx reply_ct %lx\n", sep->send_ct, sep->reply_ct); - /* is this printf or daemon request? */ + /* Is this printf or daemon request? */ reg_val2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); dev_dbg(&sep->pdev->dev, "SEP Interrupt - reg2 is %08x\n", reg_val2); @@ -3253,11 +3248,11 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) dev_dbg(&sep->pdev->dev, "int: daemon request\n"); wake_up(&sep->event_request_daemon); } else { - dev_dbg(&sep->pdev->dev, "int: sep reply\n"); + dev_dbg(&sep->pdev->dev, "int: SEP reply\n"); wake_up(&sep->event); } } else { - dev_dbg(&sep->pdev->dev, "int: not sep interrupt\n"); + dev_dbg(&sep->pdev->dev, "int: not SEP interrupt\n"); int_error = IRQ_NONE; } if (int_error == IRQ_HANDLED) @@ -3329,20 +3324,20 @@ static int __devinit sep_probe(struct pci_dev *pdev, int error = 0; struct sep_device *sep; - pr_debug("Sep pci probe starting\n"); + pr_debug("SEP pci probe starting\n"); if (sep_dev != NULL) { dev_warn(&pdev->dev, "only one SEP supported.\n"); return -EBUSY; } - /* enable the device */ + /* Enable the device */ error = pci_enable_device(pdev); if (error) { dev_warn(&pdev->dev, "error enabling pci device\n"); goto end_function; } - /* allocate the sep_device structure for this device */ + /* Allocate the sep_device structure for this device */ sep_dev = kzalloc(sizeof(struct sep_device), GFP_ATOMIC); if (sep_dev == NULL) { dev_warn(&pdev->dev, @@ -3351,7 +3346,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, } /* - * we're going to use another variable for actually + * We're going to use another variable for actually * working with the device; this way, if we have * multiple devices in the future, it would be easier * to make appropriate changes @@ -3366,7 +3361,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, dev_dbg(&sep->pdev->dev, "PCI obtained, device being prepared\n"); dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision); - /* set up our register area */ + /* Set up our register area */ sep->reg_physical_addr = pci_resource_start(sep->pdev, 0); if (!sep->reg_physical_addr) { dev_warn(&sep->pdev->dev, "Error getting register start\n"); @@ -3395,7 +3390,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, (unsigned long long)sep->reg_physical_end, sep->reg_addr); - /* allocate the shared area */ + /* Allocate the shared area */ sep->shared_size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + @@ -3404,11 +3399,11 @@ static int __devinit sep_probe(struct pci_dev *pdev, if (sep_map_and_alloc_shared_area(sep)) { error = -ENOMEM; - /* allocation failed */ + /* Allocation failed */ goto end_function_error; } - /* the next section depends on type of unit */ + /* The next section depends on type of unit */ if (sep->mrst) { error = register_rar(RAR_TYPE_IMAGE, &sep_callback, (unsigned long)sep); @@ -3435,14 +3430,14 @@ static int __devinit sep_probe(struct pci_dev *pdev, dev_dbg(&sep->pdev->dev, "about to write IMR and ICR REG_ADDR\n"); - /* clear ICR register */ + /* Clear ICR register */ sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF); - /* set the IMR register - open only GPR 2 */ + /* Set the IMR register - open only GPR 2 */ sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); dev_dbg(&sep->pdev->dev, "about to call request_irq\n"); - /* get the interrupt line */ + /* Get the interrupt line */ error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep); @@ -3455,7 +3450,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, goto end_function; end_function_deallocate_sep_shared_area: - /* de-allocate shared area */ + /* De-allocate shared area */ sep_unmap_and_free_shared_area(sep); end_function_error: @@ -3475,7 +3470,7 @@ static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = { MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl); -/* field for registering driver to PCI device */ +/* Field for registering driver to PCI device */ static struct pci_driver sep_pci_driver = { .name = "sep_sec_driver", .id_table = sep_pci_id_tbl, @@ -3483,7 +3478,7 @@ static struct pci_driver sep_pci_driver = { /* FIXME: remove handler */ }; -/* file operation for singleton sep operations */ +/* File operation for singleton SEP operations */ static const struct file_operations singleton_file_operations = { .owner = THIS_MODULE, .unlocked_ioctl = sep_singleton_ioctl, @@ -3493,7 +3488,7 @@ static const struct file_operations singleton_file_operations = { .mmap = sep_mmap, }; -/* file operation for daemon operations */ +/* File operation for daemon operations */ static const struct file_operations daemon_file_operations = { .owner = THIS_MODULE, .unlocked_ioctl = sep_request_daemon_ioctl, @@ -3503,7 +3498,7 @@ static const struct file_operations daemon_file_operations = { .mmap = sep_request_daemon_mmap, }; -/* the files operations structure of the driver */ +/* The files operations structure of the driver */ static const struct file_operations sep_file_operations = { .owner = THIS_MODULE, .unlocked_ioctl = sep_ioctl, @@ -3526,19 +3521,19 @@ static int sep_reconfig_shared_area(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "reconfig shared area start\n"); - /* send the new SHARED MESSAGE AREA to the SEP */ + /* Send the new SHARED MESSAGE AREA to the SEP */ dev_dbg(&sep->pdev->dev, "sending %08llx to sep\n", (unsigned long long)sep->shared_bus); sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); - /* poll for SEP response */ + /* Poll for SEP response */ ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); while (ret_val != 0xffffffff && ret_val != sep->shared_bus) ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - /* check the return value (register) */ + /* Check the return value (register) */ if (ret_val != sep->shared_bus) { dev_warn(&sep->pdev->dev, "could not reconfig shared area\n"); dev_warn(&sep->pdev->dev, "result was %x\n", ret_val); @@ -3574,7 +3569,7 @@ static int sep_register_driver_to_fs(struct sep_device *sep) ret_val = misc_register(&sep->miscdev_sep); if (ret_val) { - dev_warn(&sep->pdev->dev, "misc reg fails for sep %x\n", + dev_warn(&sep->pdev->dev, "misc reg fails for SEP %x\n", ret_val); return ret_val; } @@ -3611,7 +3606,7 @@ static int __init sep_init(void) int ret_val = 0; struct sep_device *sep = NULL; - pr_debug("Sep driver: Init start\n"); + pr_debug("SEP driver: Init start\n"); ret_val = pci_register_driver(&sep_pci_driver); if (ret_val) { @@ -3628,14 +3623,14 @@ static int __init sep_init(void) mutex_init(&sep->sep_mutex); mutex_init(&sep->ioctl_mutex); - /* new chip requires share area reconfigure */ - if (sep->pdev->revision == 4) { /* only for new chip */ + /* The new chip requires ashared area reconfigure */ + if (sep->pdev->revision == 4) { /* Only for new chip */ ret_val = sep_reconfig_shared_area(sep); if (ret_val) goto end_function_unregister_pci; } - /* register driver to fs */ + /* Register driver to fs */ ret_val = sep_register_driver_to_fs(sep); if (ret_val) { dev_warn(&sep->pdev->dev, "error registering device to file\n"); @@ -3665,18 +3660,18 @@ static void __exit sep_exit(void) sep = sep_dev; pr_debug("Exit start\n"); - /* unregister from fs */ + /* Unregister from fs */ misc_deregister(&sep->miscdev_sep); misc_deregister(&sep->miscdev_singleton); misc_deregister(&sep->miscdev_daemon); - /* free the irq */ + /* Free the irq */ free_irq(sep->pdev->irq, sep); - /* unregister the driver */ + /* Unregister the driver */ pci_unregister_driver(&sep_pci_driver); - /* free shared area */ + /* Free the shared area */ if (sep_dev) { sep_unmap_and_free_shared_area(sep_dev); dev_dbg(&sep->pdev->dev, -- cgit v1.2.3 From 2bb3af58d0f712c728cf1230539044d94c9a3be0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:38:54 +0000 Subject: Staging: sep: cant is an angular inclination So use can't instead. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 9c165587a247..ebe7a90aec0e 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -98,7 +98,7 @@ static int sep_load_firmware(struct sep_device *sep) error = request_firmware(&fw, res_name, &sep->pdev->dev); if (error) { - dev_warn(&sep->pdev->dev, "cant request resident fw\n"); + dev_warn(&sep->pdev->dev, "can't request resident fw\n"); return error; } @@ -3280,7 +3280,7 @@ static int sep_callback(unsigned long sep_context_pointer) &rar_end_address); if (error) { - dev_warn(&sep->pdev->dev, "mrst cant get rar region\n"); + dev_warn(&sep->pdev->dev, "mrst can't get rar region\n"); goto end_function; } @@ -3417,7 +3417,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, sep->rar_addr = dma_alloc_coherent(NULL, sep->rar_size, &sep->rar_bus, GFP_KERNEL); if (sep->rar_addr == NULL) { - dev_warn(&sep->pdev->dev, "cant allocate mfld rar\n"); + dev_warn(&sep->pdev->dev, "can't allocate mfld rar\n"); error = -ENOMEM; goto end_function_deallocate_sep_shared_area; } -- cgit v1.2.3 From 6f89be93ce6e718a51215336845c70ada06627ba Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:39:07 +0000 Subject: Staging: sep: clean up a couple of spots missed in pass one Another copy_user case and some formatting of dbg Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index ebe7a90aec0e..5e27b5a4d043 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -1037,8 +1037,6 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, sizeof(struct alloc_struct)); if (error) { error = -EFAULT; - dev_warn(&sep->pdev->dev, - "allocate data pool copy to user error\n"); goto end_function; } @@ -1083,13 +1081,10 @@ static int sep_lock_kernel_pages(struct sep_device *sep, /* Map array */ struct sep_dma_map *map_array; - dev_dbg(&sep->pdev->dev, - "sep_lock_kernel_pages start\n"); - - dev_dbg(&sep->pdev->dev, - "kernel_virt_addr is %08x\n", kernel_virt_addr); - dev_dbg(&sep->pdev->dev, - "data_size is %x\n", data_size); + dev_dbg(&sep->pdev->dev, "sep_lock_kernel_pages start\n"); + dev_dbg(&sep->pdev->dev, "kernel_virt_addr is %08x\n", + kernel_virt_addr); + dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size); lli_array = kmalloc(sizeof(struct sep_lli_entry), GFP_ATOMIC); if (!lli_array) { @@ -1182,8 +1177,7 @@ static int sep_lock_user_pages(struct sep_device *sep, /* Direction of the DMA mapping for locked pages */ enum dma_data_direction dir; - dev_dbg(&sep->pdev->dev, - "sep_lock_user_pages start\n"); + dev_dbg(&sep->pdev->dev, "sep_lock_user_pages start\n"); /* Set start and end pages and num pages */ end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; -- cgit v1.2.3 From da3f825bc71b420e129b6344be0e3e863ebf8a42 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 Nov 2010 19:39:20 +0000 Subject: Staging: sep: Fix crash if a device is not found The existing code works mostly by luck. The PCI probe is done by the register and completes before the register returns thus allowing the other init code to run in time. Without a SEP or if unlucky this doesn't occur and you get an OOPS which for some reason causes grumpiness. As the season of good b^Hcheer is supposed to be approaching we should probably fix it. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 363 ++++++++++++++++++--------------------- 1 file changed, 167 insertions(+), 196 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 5e27b5a4d043..76331112a264 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -256,8 +256,7 @@ static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) file_ptr->private_data = sep; - dev_dbg(&sep->pdev->dev, "Singleton open for pid %d\n", - current->pid); + dev_dbg(&sep->pdev->dev, "Singleton open for pid %d\n", current->pid); dev_dbg(&sep->pdev->dev, "calling test and set for singleton 0\n"); if (test_and_set_bit(0, &sep->singleton_access_flag)) { @@ -265,10 +264,8 @@ static int sep_singleton_open(struct inode *inode_ptr, struct file *file_ptr) goto end_function; } - dev_dbg(&sep->pdev->dev, - "sep_singleton_open end\n"); + dev_dbg(&sep->pdev->dev, "sep_singleton_open end\n"); end_function: - return error; } @@ -386,9 +383,7 @@ static int sep_req_daemon_send_reply_command_handler(struct sep_device *sep) sep->reply_ct++; /* Send the interrupt to SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, - sep->send_ct); - + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct); sep->send_ct++; spin_unlock_irqrestore(&sep->snd_rply_lck, lck_flags); @@ -3304,6 +3299,125 @@ end_function: return error; } +/** + * sep_reconfig_shared_area - reconfigure shared area + * @sep: pointer to struct sep_device + * + * Reconfig the shared area between HOST and SEP - needed in case + * the DX_CC_Init function was called before OS loading. + */ +static int sep_reconfig_shared_area(struct sep_device *sep) +{ + int ret_val; + + dev_dbg(&sep->pdev->dev, "reconfig shared area start\n"); + + /* Send the new SHARED MESSAGE AREA to the SEP */ + dev_dbg(&sep->pdev->dev, "sending %08llx to sep\n", + (unsigned long long)sep->shared_bus); + + sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); + + /* Poll for SEP response */ + ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); + + while (ret_val != 0xffffffff && ret_val != sep->shared_bus) + ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); + + /* Check the return value (register) */ + if (ret_val != sep->shared_bus) { + dev_warn(&sep->pdev->dev, "could not reconfig shared area\n"); + dev_warn(&sep->pdev->dev, "result was %x\n", ret_val); + ret_val = -ENOMEM; + } else + ret_val = 0; + + dev_dbg(&sep->pdev->dev, "reconfig shared area end\n"); + return ret_val; +} + +/* File operation for singleton SEP operations */ +static const struct file_operations singleton_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_singleton_ioctl, + .poll = sep_poll, + .open = sep_singleton_open, + .release = sep_singleton_release, + .mmap = sep_mmap, +}; + +/* File operation for daemon operations */ +static const struct file_operations daemon_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_request_daemon_ioctl, + .poll = sep_request_daemon_poll, + .open = sep_request_daemon_open, + .release = sep_request_daemon_release, + .mmap = sep_request_daemon_mmap, +}; + +/* The files operations structure of the driver */ +static const struct file_operations sep_file_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = sep_ioctl, + .poll = sep_poll, + .open = sep_open, + .release = sep_release, + .mmap = sep_mmap, +}; + +/** + * sep_register_driver_with_fs - register misc devices + * @sep: pointer to struct sep_device + * + * This function registers the driver with the file system + */ +static int sep_register_driver_with_fs(struct sep_device *sep) +{ + int ret_val; + + sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR; + sep->miscdev_sep.name = SEP_DEV_NAME; + sep->miscdev_sep.fops = &sep_file_operations; + + sep->miscdev_singleton.minor = MISC_DYNAMIC_MINOR; + sep->miscdev_singleton.name = SEP_DEV_SINGLETON; + sep->miscdev_singleton.fops = &singleton_file_operations; + + sep->miscdev_daemon.minor = MISC_DYNAMIC_MINOR; + sep->miscdev_daemon.name = SEP_DEV_DAEMON; + sep->miscdev_daemon.fops = &daemon_file_operations; + + ret_val = misc_register(&sep->miscdev_sep); + if (ret_val) { + dev_warn(&sep->pdev->dev, "misc reg fails for SEP %x\n", + ret_val); + return ret_val; + } + + ret_val = misc_register(&sep->miscdev_singleton); + if (ret_val) { + dev_warn(&sep->pdev->dev, "misc reg fails for sing %x\n", + ret_val); + misc_deregister(&sep->miscdev_sep); + return ret_val; + } + + if (!sep->mrst) { + ret_val = misc_register(&sep->miscdev_daemon); + if (ret_val) { + dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n", + ret_val); + misc_deregister(&sep->miscdev_sep); + misc_deregister(&sep->miscdev_singleton); + + return ret_val; + } + } + return ret_val; +} + + /** * sep_probe - probe a matching PCI device * @pdev: pci_device @@ -3349,6 +3463,12 @@ static int __devinit sep_probe(struct pci_dev *pdev, sep->pdev = pdev; + init_waitqueue_head(&sep->event); + init_waitqueue_head(&sep->event_request_daemon); + spin_lock_init(&sep->snd_rply_lck); + mutex_init(&sep->sep_mutex); + mutex_init(&sep->ioctl_mutex); + if (pdev->device == MRST_PCI_DEVICE_ID) sep->mrst = 1; @@ -3435,9 +3555,26 @@ static int __devinit sep_probe(struct pci_dev *pdev, error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep); - if (!error) - goto end_function; + if (error) + goto end_function_dealloc_rar; + /* The new chip requires ashared area reconfigure */ + if (sep->pdev->revision == 4) { /* Only for new chip */ + error = sep_reconfig_shared_area(sep); + if (error) + goto end_function_free_irq; + } + /* Finally magic up the device nodes */ + /* Register driver with the fs */ + error = sep_register_driver_with_fs(sep); + if (error == 0) + /* Success */ + return 0; + +end_function_free_irq: + free_irq(pdev->irq, sep); + +end_function_dealloc_rar: if (sep->rar_addr) dma_free_coherent(&sep->pdev->dev, sep->rar_size, sep->rar_addr, sep->rar_bus); @@ -3456,6 +3593,23 @@ end_function: return error; } +static void sep_remove(struct pci_dev *pdev) +{ + struct sep_device *sep = sep_dev; + + /* Unregister from fs */ + misc_deregister(&sep->miscdev_sep); + misc_deregister(&sep->miscdev_singleton); + misc_deregister(&sep->miscdev_daemon); + + /* Free the irq */ + free_irq(sep->pdev->irq, sep); + + /* Free the shared area */ + sep_unmap_and_free_shared_area(sep_dev); + iounmap((void *) sep_dev->reg_addr); +} + static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MRST_PCI_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_PCI_DEVICE_ID)}, @@ -3468,127 +3622,10 @@ MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl); static struct pci_driver sep_pci_driver = { .name = "sep_sec_driver", .id_table = sep_pci_id_tbl, - .probe = sep_probe - /* FIXME: remove handler */ + .probe = sep_probe, + .remove = sep_remove }; -/* File operation for singleton SEP operations */ -static const struct file_operations singleton_file_operations = { - .owner = THIS_MODULE, - .unlocked_ioctl = sep_singleton_ioctl, - .poll = sep_poll, - .open = sep_singleton_open, - .release = sep_singleton_release, - .mmap = sep_mmap, -}; - -/* File operation for daemon operations */ -static const struct file_operations daemon_file_operations = { - .owner = THIS_MODULE, - .unlocked_ioctl = sep_request_daemon_ioctl, - .poll = sep_request_daemon_poll, - .open = sep_request_daemon_open, - .release = sep_request_daemon_release, - .mmap = sep_request_daemon_mmap, -}; - -/* The files operations structure of the driver */ -static const struct file_operations sep_file_operations = { - .owner = THIS_MODULE, - .unlocked_ioctl = sep_ioctl, - .poll = sep_poll, - .open = sep_open, - .release = sep_release, - .mmap = sep_mmap, -}; - -/** - * sep_reconfig_shared_area - reconfigure shared area - * @sep: pointer to struct sep_device - * - * Reconfig the shared area between HOST and SEP - needed in case - * the DX_CC_Init function was called before OS loading. - */ -static int sep_reconfig_shared_area(struct sep_device *sep) -{ - int ret_val; - - dev_dbg(&sep->pdev->dev, "reconfig shared area start\n"); - - /* Send the new SHARED MESSAGE AREA to the SEP */ - dev_dbg(&sep->pdev->dev, "sending %08llx to sep\n", - (unsigned long long)sep->shared_bus); - - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); - - /* Poll for SEP response */ - ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - - while (ret_val != 0xffffffff && ret_val != sep->shared_bus) - ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - - /* Check the return value (register) */ - if (ret_val != sep->shared_bus) { - dev_warn(&sep->pdev->dev, "could not reconfig shared area\n"); - dev_warn(&sep->pdev->dev, "result was %x\n", ret_val); - ret_val = -ENOMEM; - } else - ret_val = 0; - - dev_dbg(&sep->pdev->dev, "reconfig shared area end\n"); - return ret_val; -} - -/** - * sep_register_driver_to_fs - register misc devices - * @sep: pointer to struct sep_device - * - * This function registers the driver to the file system - */ -static int sep_register_driver_to_fs(struct sep_device *sep) -{ - int ret_val; - - sep->miscdev_sep.minor = MISC_DYNAMIC_MINOR; - sep->miscdev_sep.name = SEP_DEV_NAME; - sep->miscdev_sep.fops = &sep_file_operations; - - sep->miscdev_singleton.minor = MISC_DYNAMIC_MINOR; - sep->miscdev_singleton.name = SEP_DEV_SINGLETON; - sep->miscdev_singleton.fops = &singleton_file_operations; - - sep->miscdev_daemon.minor = MISC_DYNAMIC_MINOR; - sep->miscdev_daemon.name = SEP_DEV_DAEMON; - sep->miscdev_daemon.fops = &daemon_file_operations; - - ret_val = misc_register(&sep->miscdev_sep); - if (ret_val) { - dev_warn(&sep->pdev->dev, "misc reg fails for SEP %x\n", - ret_val); - return ret_val; - } - - ret_val = misc_register(&sep->miscdev_singleton); - if (ret_val) { - dev_warn(&sep->pdev->dev, "misc reg fails for sing %x\n", - ret_val); - misc_deregister(&sep->miscdev_sep); - return ret_val; - } - - if (!sep->mrst) { - ret_val = misc_register(&sep->miscdev_daemon); - if (ret_val) { - dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n", - ret_val); - misc_deregister(&sep->miscdev_sep); - misc_deregister(&sep->miscdev_singleton); - - return ret_val; - } - } - return ret_val; -} /** * sep_init - init function @@ -3597,47 +3634,7 @@ static int sep_register_driver_to_fs(struct sep_device *sep) */ static int __init sep_init(void) { - int ret_val = 0; - struct sep_device *sep = NULL; - - pr_debug("SEP driver: Init start\n"); - - ret_val = pci_register_driver(&sep_pci_driver); - if (ret_val) { - pr_debug("sep_driver:sep_driver_to_device failed, ret_val is %d\n", - ret_val); - goto end_function; - } - - sep = sep_dev; - - init_waitqueue_head(&sep->event); - init_waitqueue_head(&sep->event_request_daemon); - spin_lock_init(&sep->snd_rply_lck); - mutex_init(&sep->sep_mutex); - mutex_init(&sep->ioctl_mutex); - - /* The new chip requires ashared area reconfigure */ - if (sep->pdev->revision == 4) { /* Only for new chip */ - ret_val = sep_reconfig_shared_area(sep); - if (ret_val) - goto end_function_unregister_pci; - } - - /* Register driver to fs */ - ret_val = sep_register_driver_to_fs(sep); - if (ret_val) { - dev_warn(&sep->pdev->dev, "error registering device to file\n"); - goto end_function_unregister_pci; - } - goto end_function; - -end_function_unregister_pci: - pci_unregister_driver(&sep_pci_driver); - -end_function: - dev_dbg(&sep->pdev->dev, "Init end\n"); - return ret_val; + return pci_register_driver(&sep_pci_driver); } @@ -3649,33 +3646,7 @@ end_function: */ static void __exit sep_exit(void) { - struct sep_device *sep; - - sep = sep_dev; - pr_debug("Exit start\n"); - - /* Unregister from fs */ - misc_deregister(&sep->miscdev_sep); - misc_deregister(&sep->miscdev_singleton); - misc_deregister(&sep->miscdev_daemon); - - /* Free the irq */ - free_irq(sep->pdev->irq, sep); - - /* Unregister the driver */ pci_unregister_driver(&sep_pci_driver); - - /* Free the shared area */ - if (sep_dev) { - sep_unmap_and_free_shared_area(sep_dev); - dev_dbg(&sep->pdev->dev, - "free pages SEP SHARED AREA\n"); - iounmap((void *) sep_dev->reg_addr); - dev_dbg(&sep->pdev->dev, - "iounmap\n"); - } - pr_debug("release_mem_region\n"); - pr_debug("Exit end\n"); } -- cgit v1.2.3 From 3b93ff030204ca36fb1e9917743bbf22a423e527 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 29 Nov 2010 11:18:08 -0800 Subject: Staging: sep: do not select the driver by default The Kconfig file should not have 'y' as the default, especially as the driver will crash a machine if it is loaded and the hardware is not present. Cc: Mark Allyn Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig index 34f3ef5f9df8..92bf16667d04 100644 --- a/drivers/staging/sep/Kconfig +++ b/drivers/staging/sep/Kconfig @@ -1,7 +1,6 @@ config DX_SEP tristate "Discretix SEP driver" depends on PCI - default y help Discretix SEP driver; used for the security processor subsystem on bard the Intel Mobile Internet Device. -- cgit v1.2.3 From 57d8cd23c2a0d261bdc959201dd4a33a2080bdfb Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Mon, 22 Nov 2010 16:58:52 -0800 Subject: staging: brcm80211: OSL shrink: Remove OSL_PCI_READ/WRITE_CONFIG Replace OSL layer PCI READ/WRITE macros with native calls. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 9 ---- drivers/staging/brcm80211/include/siutils.h | 2 +- drivers/staging/brcm80211/util/aiutils.c | 6 +-- drivers/staging/brcm80211/util/linux_osl.c | 13 ----- drivers/staging/brcm80211/util/siutils.c | 70 ++++++++++++++------------- 5 files changed, 40 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index d314dfb2b62f..010182fa1a92 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -40,15 +40,6 @@ extern void osl_assert(char *exp, char *file, int line); #endif /* __GNUC__ */ #endif /* defined(BCMDBG_ASSERT) */ -/* PCI configuration space access macros */ -#define OSL_PCI_READ_CONFIG(osh, offset, size) \ - osl_pci_read_config((osh), (offset), (size)) -#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ - osl_pci_write_config((osh), (offset), (size), (val)) -extern u32 osl_pci_read_config(struct osl_info *osh, uint offset, uint size); -extern void osl_pci_write_config(struct osl_info *osh, uint offset, uint size, - uint val); - /* PCI device bus # and slot # */ #define OSL_PCI_BUS(osh) osl_pci_bus(osh) #define OSL_PCI_SLOT(osh) osl_pci_slot(osh) diff --git a/drivers/staging/brcm80211/include/siutils.h b/drivers/staging/brcm80211/include/siutils.h index 6a074ab9f34b..0f042799c376 100644 --- a/drivers/staging/brcm80211/include/siutils.h +++ b/drivers/staging/brcm80211/include/siutils.h @@ -217,7 +217,7 @@ typedef struct gpioh_item { /* misc si info needed by some of the routines */ typedef struct si_info { struct si_pub pub; /* back plane public state (must be first field) */ - void *osh; /* osl os handle */ + struct osl_info *osh; /* osl os handle */ void *sdh; /* bcmsdh handle */ uint dev_coreid; /* the core provides driver functions */ void *intr_arg; /* interrupt callback function arg */ diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c index 1d4e3729ad61..dbb3e369b740 100644 --- a/drivers/staging/brcm80211/util/aiutils.c +++ b/drivers/staging/brcm80211/util/aiutils.c @@ -129,7 +129,7 @@ void ai_scan(si_t *sih, void *regs, uint devid) sii->curwrap = (void *)((unsigned long)regs + SI_CORE_SIZE); /* Now point the window at the erom */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); + pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN, erombase); eromptr = regs; break; @@ -351,10 +351,10 @@ void *ai_setcoreidx(si_t *sih, uint coreidx) case PCI_BUS: /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); + pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN, addr); regs = sii->curmap; /* point bar0 2nd 4KB window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); + pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN2, wrap); break; #ifdef BCMSDIO diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index a07eada14d08..a0f9dcb0b786 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -128,19 +128,6 @@ void BCMFASTPATH osl_pktfree(struct osl_info *osh, void *p, bool send) } } -u32 osl_pci_read_config(struct osl_info *osh, uint offset, uint size) -{ - uint val; - pci_read_config_dword(osh->pdev, offset, &val); - return val; -} - -void osl_pci_write_config(struct osl_info *osh, uint offset, uint size, - uint val) -{ - pci_write_config_dword(osh->pdev, offset, val); -} - /* return bus # for the pci device pointed by osh->pdev */ uint osl_pci_bus(struct osl_info *osh) { diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 4d2df4977727..e13053626d29 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -315,7 +315,7 @@ static __used void si_nvram_process(si_info_t *sii, char *pvars) switch (BUSTYPE(sii->pub.bustype)) { case PCI_BUS: /* do a pci config read to get subsystem id and subvendor id */ - w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(u32)); + pci_read_config_dword(sii->osh->pdev, PCI_CFG_SVID, &w); /* Let nvram variables override subsystem Vend/ID */ sii->pub.boardvendor = (u16)si_getdevpathintvar(&sii->pub, "boardvendor"); @@ -526,20 +526,23 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, sii->osh = osh; /* check to see if we are a si core mimic'ing a pci core */ - if ((bustype == PCI_BUS) && - (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(u32)) == - 0xffffffff)) { - SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " "devid:0x%x\n", __func__, devid)); - bustype = SI_BUS; + if (bustype == PCI_BUS) { + pci_read_config_dword(sii->osh->pdev, PCI_SPROM_CONTROL, &w); + if (w == 0xffffffff) { + SI_ERROR(("%s: incoming bus is PCI but it's a lie, " + " switching to SI devid:0x%x\n", + __func__, devid)); + bustype = SI_BUS; + } } /* find Chipcommon address */ if (bustype == PCI_BUS) { - savewin = - OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(u32)); + pci_read_config_dword(sii->osh->pdev, PCI_BAR0_WIN, &savewin); if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) savewin = SI_ENUM_BASE; - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); + pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN, + SI_ENUM_BASE); cc = (chipcregs_t *) regs; } else { cc = (chipcregs_t *) REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); @@ -1089,16 +1092,18 @@ void si_watchdog(si_t *sih, uint ticks) static uint si_slowclk_src(si_info_t *sii) { chipcregs_t *cc; + u32 val; ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); if (sii->pub.ccrev < 6) { - if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && - (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(u32)) - & PCI_CFG_GPIO_SCS)) - return SCC_SS_PCI; - else - return SCC_SS_XTAL; + if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, + &val); + if (val & PCI_CFG_GPIO_SCS) + return SCC_SS_PCI; + } + return SCC_SS_XTAL; } else if (sii->pub.ccrev < 10) { cc = (chipcregs_t *) si_setcoreidx(&sii->pub, sii->curidx); return R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK; @@ -1280,12 +1285,9 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on) if (PCIE(sii)) return -1; - in = OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_IN, sizeof(u32)); - out = - OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(u32)); - outen = - OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUTEN, - sizeof(u32)); + pci_read_config_dword(sii->osh->pdev, PCI_GPIO_IN, &in); + pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, &out); + pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUTEN, &outen); /* * Avoid glitching the clock if GPRS is already using it. @@ -1306,18 +1308,18 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on) out |= PCI_CFG_GPIO_XTAL; if (what & PLL) out |= PCI_CFG_GPIO_PLL; - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT, - sizeof(u32), out); - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN, - sizeof(u32), outen); + pci_write_config_dword(sii->osh->pdev, + PCI_GPIO_OUT, out); + pci_write_config_dword(sii->osh->pdev, + PCI_GPIO_OUTEN, outen); udelay(XTAL_ON_DELAY); } /* turn pll on */ if (what & PLL) { out &= ~PCI_CFG_GPIO_PLL; - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT, - sizeof(u32), out); + pci_write_config_dword(sii->osh->pdev, + PCI_GPIO_OUT, out); mdelay(2); } } else { @@ -1325,10 +1327,10 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on) out &= ~PCI_CFG_GPIO_XTAL; if (what & PLL) out |= PCI_CFG_GPIO_PLL; - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT, - sizeof(u32), out); - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN, - sizeof(u32), outen); + pci_write_config_dword(sii->osh->pdev, + PCI_GPIO_OUT, out); + pci_write_config_dword(sii->osh->pdev, + PCI_GPIO_OUTEN, outen); } default: @@ -1696,9 +1698,9 @@ void si_pci_setup(si_t *sih, uint coremask) */ if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) { /* pci config write to set this core bit in PCIIntMask */ - w = OSL_PCI_READ_CONFIG(sii->osh, PCI_INT_MASK, sizeof(u32)); + pci_read_config_dword(sii->osh->pdev, PCI_INT_MASK, &w); w |= (coremask << PCI_SBIM_SHIFT); - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_INT_MASK, sizeof(u32), w); + pci_write_config_dword(sii->osh->pdev, PCI_INT_MASK, w); } else { /* set sbintvec bit for our flag number */ si_setint(sih, siflag); @@ -1936,7 +1938,7 @@ bool si_deviceremoved(si_t *sih) switch (BUSTYPE(sih->bustype)) { case PCI_BUS: ASSERT(sii->osh != NULL); - w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(u32)); + pci_read_config_dword(sii->osh->pdev, PCI_CFG_VID, &w); if ((w & 0xFFFF) != VENDOR_BROADCOM) return true; break; -- cgit v1.2.3 From 7c8bc0147f54ecb43f48d9e898ad7f85cb934db7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Nov 2010 08:04:29 +0100 Subject: staging: brcm80211: add include file for using semaphore related definitions Source wl_iw.c uses semaphore definitions and as such should include . Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index d583b9d65d35..e714d6a9452b 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include -- cgit v1.2.3 From b6eb5c0f71af22f7b44353a01241fff9a02997af Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Nov 2010 14:06:22 +0100 Subject: staging: brcm80211: remove unneccessary packets funtion prototype The prototype for function pktsegcnt in bmcutils.h is not defined nor used anywhere in the driver so it can be removed. Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmutils.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h index 4c1c111bac9b..632bceb480cb 100644 --- a/drivers/staging/brcm80211/include/bcmutils.h +++ b/drivers/staging/brcm80211/include/bcmutils.h @@ -149,10 +149,9 @@ /* externs */ /* packet */ - extern uint pktfrombuf(struct osl_info *osh, void *p, uint offset, - int len, unsigned char *buf); - extern uint pktsegcnt(struct osl_info *osh, void *p); - extern uint pkttotlen(struct osl_info *osh, void *p); + extern uint pktfrombuf(struct osl_info *osh, struct sk_buff *p, + uint offset, int len, unsigned char *buf); + extern uint pkttotlen(struct osl_info *osh, struct sk_buff *p); /* ethernet address */ extern int bcm_ether_atoe(char *p, struct ether_addr *ea); -- cgit v1.2.3 From c26b1378a71de617fb5ba7da8b6fdc882caed0e8 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Nov 2010 14:06:23 +0100 Subject: staging: brcm80211: change packet buffer type to native struct sk_buff The packet queues now store struct sk_buff pointer and subsequently all driver code handling packets now use struct sk_buff as package storage type. Next step will be getting rid of packet macros. Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh.c | 2 +- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 8 ++--- drivers/staging/brcm80211/brcmfmac/dhd.h | 10 +++--- drivers/staging/brcm80211/brcmfmac/dhd_bus.h | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 6 ++-- drivers/staging/brcm80211/brcmfmac/dhd_common.c | 5 +-- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 10 +++--- drivers/staging/brcm80211/brcmfmac/dhd_proto.h | 7 ++-- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 39 ++++++++++++----------- drivers/staging/brcm80211/include/bcmsdbus.h | 2 +- drivers/staging/brcm80211/include/bcmsdh.h | 2 +- drivers/staging/brcm80211/include/bcmutils.h | 28 +++++++++------- drivers/staging/brcm80211/include/hnddma.h | 2 +- drivers/staging/brcm80211/sys/wl_mac80211.c | 7 ---- drivers/staging/brcm80211/sys/wlc_ampdu.c | 25 +++++++-------- drivers/staging/brcm80211/sys/wlc_ampdu.h | 8 ++--- drivers/staging/brcm80211/sys/wlc_bmac.c | 8 ++--- drivers/staging/brcm80211/sys/wlc_mac80211.c | 39 ++++++++++++----------- drivers/staging/brcm80211/sys/wlc_mac80211.h | 16 +++++----- drivers/staging/brcm80211/sys/wlc_pub.h | 7 ++++ drivers/staging/brcm80211/util/bcmutils.c | 33 ++++++++++--------- drivers/staging/brcm80211/util/hnddma.c | 17 +++++----- 22 files changed, 151 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c index 6171ebf56ff1..acf43a365081 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c @@ -453,7 +453,7 @@ bool bcmsdh_regfail(void *sdh) int bcmsdh_recv_buf(void *sdh, u32 addr, uint fn, uint flags, - u8 *buf, uint nbytes, void *pkt, + u8 *buf, uint nbytes, struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete, void *handle) { bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh; diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index babda77d9326..3d3a428fa279 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -928,13 +928,13 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, static SDIOH_API_RC sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, void *pkt) + uint addr, struct sk_buff *pkt) { bool fifo = (fix_inc == SDIOH_DATA_FIX); u32 SGCount = 0; int err_ret = 0; - void *pnext; + struct sk_buff *pnext; sd_trace(("%s: Enter\n", __func__)); @@ -1026,10 +1026,10 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, uint addr, uint reg_width, uint buflen_u, - u8 *buffer, void *pkt) + u8 *buffer, struct sk_buff *pkt) { SDIOH_API_RC Status; - void *mypkt = NULL; + struct sk_buff *mypkt = NULL; sd_trace(("%s: Enter\n", __func__)); diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h index 7785772ed917..69c6a0272812 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd.h +++ b/drivers/staging/brcm80211/brcmfmac/dhd.h @@ -295,10 +295,12 @@ extern void dhd_detach(dhd_pub_t *dhdp); /* Indication from bus module to change flow-control state */ extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); -extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); +extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, + struct sk_buff *pkt, int prec); /* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt); +extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, + struct sk_buff *rxp, int numpkt); /* Return pointer to interface name */ extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); @@ -307,7 +309,7 @@ extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); extern void dhd_sched_dpc(dhd_pub_t *dhdp); /* Notify tx completion */ -extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); +extern void dhd_txcomplete(dhd_pub_t *dhdp, struct sk_buff *txp, bool success); /* Query ioctl */ extern int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, @@ -378,7 +380,7 @@ extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, unsigned char * cp, int len); /* Send packet to dongle via data channel */ -extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); +extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pkt); /* Send event to host */ extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h index 6629a229b4a1..cd0d5400bf07 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h @@ -36,7 +36,7 @@ extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); /* Send a data frame to the dongle. Callee disposes of txp. */ -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); +extern int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *txp); /* Send/receive a control message to/from the dongle. * Expects caller to enforce a single outstanding transaction. diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c index 8e4e10794dce..c23d30b13147 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c @@ -310,7 +310,7 @@ void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); } -void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) +void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, struct sk_buff *pktbuf) { #ifdef BDC struct bdc_header *h; @@ -336,7 +336,7 @@ void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) BDC_SET_IF_IDX(h, ifidx); } -bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, u8 * fcbits) +bool dhd_proto_fcinfo(dhd_pub_t *dhd, struct sk_buff *pktbuf, u8 * fcbits) { #ifdef BDC struct bdc_header *h; @@ -356,7 +356,7 @@ bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, u8 * fcbits) return false; } -int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf) +int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, struct sk_buff *pktbuf) { #ifdef BDC struct bdc_header *h; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c index f7ffea69233c..e212abb8a357 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c @@ -327,9 +327,10 @@ void dhd_store_conn_status(u32 event, u32 status, u32 reason) } } -bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) +bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, struct sk_buff *pkt, + int prec) { - void *p; + struct sk_buff *p; int eprec = -1; /* precedence to evict from */ bool discard_oldest; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 27d4e02d3aab..ec887fb32faa 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1018,7 +1018,7 @@ static void dhd_set_multicast_list(struct net_device *dev) up(&dhd->sysioc_sem); } -int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) +int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf) { int ret; dhd_info_t *dhd = (dhd_info_t *) (dhdp->info); @@ -1132,13 +1132,15 @@ void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) netif_wake_queue(net); } -void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) +void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf, + int numpkt) { dhd_info_t *dhd = (dhd_info_t *) dhdp->info; struct sk_buff *skb; unsigned char *eth; uint len; - void *data, *pnext, *save_pktbuf; + void *data; + struct sk_buff *pnext, *save_pktbuf; int i; dhd_if_t *ifp; wl_event_msg_t event; @@ -1222,7 +1224,7 @@ void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) return; } -void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) +void dhd_txcomplete(dhd_pub_t *dhdp, struct sk_buff *txp, bool success) { uint ifidx; dhd_info_t *dhd = (dhd_info_t *) (dhdp->info); diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h index cc42fa4a9140..a5309e27b65b 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h +++ b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h @@ -46,15 +46,16 @@ extern int dhd_prot_init(dhd_pub_t *dhdp); /* Stop protocol: sync w/dongle state. */ extern void dhd_prot_stop(dhd_pub_t *dhdp); -extern bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, u8 *fcbits); +extern bool dhd_proto_fcinfo(dhd_pub_t *dhd, struct sk_buff *pktbuf, + u8 *fcbits); /* Add any protocol-specific data header. * Caller must reserve prot_hdrlen prepend space. */ -extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); +extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, struct sk_buff *txp); /* Remove any protocol-specific data header. */ -extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp); +extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, struct sk_buff *rxp); /* Use protocol to issue ioctl to dongle */ extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t *ioc, diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index d94b11a3271b..12bb7c602f1f 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -203,8 +203,8 @@ typedef struct dhd_bus { u8 rx_seq; /* Receive sequence number (expected) */ bool rxskip; /* Skip receive (awaiting NAK ACK) */ - void *glomd; /* Packet containing glomming descriptor */ - void *glom; /* Packet chain for glommed superframe */ + struct sk_buff *glomd; /* Packet containing glomming descriptor */ + struct sk_buff *glom; /* Packet chain for glommed superframe */ uint glomerr; /* Glom packet read errors */ u8 *rxbuf; /* Buffer for receiving control packets */ @@ -446,11 +446,13 @@ static uint process_nvram_vars(char *varbuf, uint len); static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete, void *handle); + uint flags, u8 *buf, uint nbytes, + struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete, + void *handle); static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, u32 addr, uint fn, - uint flags, u8 *buf, uint nbytes, void *pkt, - bcmsdh_cmplt_fn_t complete, void *handle); + uint flags, u8 *buf, uint nbytes, + struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete, + void *handle); static bool dhdsdio_download_firmware(struct dhd_bus *bus, struct osl_info *osh, void *sdh); @@ -902,7 +904,8 @@ void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ -static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) +static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, + bool free_pkt) { int ret; struct osl_info *osh; @@ -911,7 +914,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) u32 swheader; uint retries = 0; bcmsdh_info_t *sdh; - void *new; + struct sk_buff *new; int i; DHD_TRACE(("%s: Enter\n", __func__)); @@ -1063,7 +1066,7 @@ done: return ret; } -int dhd_bus_txdata(struct dhd_bus *bus, void *pkt) +int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *pkt) { int ret = BCME_ERROR; struct osl_info *osh; @@ -1164,7 +1167,7 @@ int dhd_bus_txdata(struct dhd_bus *bus, void *pkt) static uint dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) { - void *pkt; + struct sk_buff *pkt; u32 intstatus = 0; uint retries = 0; int ret = 0, prec_out; @@ -3180,7 +3183,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) u8 *dptr, num = 0; u16 sublen, check; - void *pfirst, *plast, *pnext, *save_pfirst; + struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; struct osl_info *osh = bus->dhd->osh; int errcode; @@ -3590,7 +3593,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) u8 fcbits; /* Extracted fcbits from software header */ u8 delta; - void *pkt; /* Packet for event or data frames */ + struct sk_buff *pkt; /* Packet for event or data frames */ u16 pad; /* Number of pad bytes to read */ u16 rdlen; /* Total number of bytes to read */ u8 rxseq; /* Next sequence number to expect */ @@ -4628,7 +4631,7 @@ static void dhdsdio_pktgen_init(dhd_bus_t *bus) static void dhdsdio_pktgen(dhd_bus_t *bus) { - void *pkt; + struct sk_buff *pkt; u8 *data; uint pktcount; uint fillbyte; @@ -4735,7 +4738,7 @@ static void dhdsdio_pktgen(dhd_bus_t *bus) static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) { - void *pkt; + struct sk_buff *pkt; u8 *data; struct osl_info *osh = bus->dhd->osh; @@ -4760,7 +4763,7 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) bus->pktgen_fail++; } -static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) +static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) { struct osl_info *osh = bus->dhd->osh; u8 *data; @@ -4962,7 +4965,7 @@ extern int dhd_bus_console_in(dhd_pub_t *dhdp, unsigned char *msg, uint msglen) dhd_bus_t *bus = dhdp->bus; u32 addr, val; int rv; - void *pkt; + struct sk_buff *pkt; /* Address could be zero if CONSOLE := 0 in dongle Makefile */ if (bus->console_addr == 0) @@ -5989,7 +5992,7 @@ err: static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags, - u8 *buf, uint nbytes, void *pkt, + u8 *buf, uint nbytes, struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete, void *handle) { int status; @@ -6003,7 +6006,7 @@ dhd_bcmsdh_recv_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags, static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, u32 addr, uint fn, uint flags, - u8 *buf, uint nbytes, void *pkt, + u8 *buf, uint nbytes, struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete, void *handle) { return bcmsdh_send_buf diff --git a/drivers/staging/brcm80211/include/bcmsdbus.h b/drivers/staging/brcm80211/include/bcmsdbus.h index 4f040e41ae50..89059dd8088b 100644 --- a/drivers/staging/brcm80211/include/bcmsdbus.h +++ b/drivers/staging/brcm80211/include/bcmsdbus.h @@ -79,7 +79,7 @@ extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, uint rw, uint fnc_num, u32 addr, uint regwidth, u32 buflen, u8 *buffer, - void *pkt); + struct sk_buff *pkt); /* get cis data */ extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, u8 *cis, diff --git a/drivers/staging/brcm80211/include/bcmsdh.h b/drivers/staging/brcm80211/include/bcmsdh.h index 69aa061bb524..0e1f79919c9c 100644 --- a/drivers/staging/brcm80211/include/bcmsdh.h +++ b/drivers/staging/brcm80211/include/bcmsdh.h @@ -122,7 +122,7 @@ extern int bcmsdh_send_buf(void *sdh, u32 addr, uint fn, uint flags, u8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); extern int bcmsdh_recv_buf(void *sdh, u32 addr, uint fn, uint flags, - u8 *buf, uint nbytes, void *pkt, + u8 *buf, uint nbytes, struct sk_buff *pkt, bcmsdh_cmplt_fn_t complete, void *handle); /* Flags bits */ diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h index 632bceb480cb..e673dfd21622 100644 --- a/drivers/staging/brcm80211/include/bcmutils.h +++ b/drivers/staging/brcm80211/include/bcmutils.h @@ -55,10 +55,10 @@ #endif typedef struct pktq_prec { - void *head; /* first packet to dequeue */ - void *tail; /* last packet to dequeue */ - u16 len; /* number of queued packets */ - u16 max; /* maximum number of queued packets */ + struct sk_buff *head; /* first packet to dequeue */ + struct sk_buff *tail; /* last packet to dequeue */ + u16 len; /* number of queued packets */ + u16 max; /* maximum number of queued packets */ } pktq_prec_t; /* multi-priority pkt queue */ @@ -104,10 +104,13 @@ #define pktq_ppeek(pq, prec) ((pq)->q[prec].head) #define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) - extern void *pktq_penq(struct pktq *pq, int prec, void *p); - extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); - extern void *pktq_pdeq(struct pktq *pq, int prec); - extern void *pktq_pdeq_tail(struct pktq *pq, int prec); +extern struct sk_buff *pktq_penq(struct pktq *pq, int prec, + struct sk_buff *p); +extern struct sk_buff *pktq_penq_head(struct pktq *pq, int prec, + struct sk_buff *p); +extern struct sk_buff *pktq_pdeq(struct pktq *pq, int prec); +extern struct sk_buff *pktq_pdeq_tail(struct pktq *pq, int prec); + /* Empty the queue at particular precedence level */ #ifdef BRCM_FULLMAC extern void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, @@ -119,8 +122,8 @@ /* operations on a set of precedences in packet queue */ - extern int pktq_mlen(struct pktq *pq, uint prec_bmp); - extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); +extern int pktq_mlen(struct pktq *pq, uint prec_bmp); +extern struct sk_buff *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); /* operations on packet queue as a whole */ @@ -139,7 +142,7 @@ extern void pktq_init(struct pktq *pq, int num_prec, int max_len); /* prec_out may be NULL if caller is not interested in return value */ - extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); + extern struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out); #ifdef BRCM_FULLMAC extern void pktq_flush(struct osl_info *osh, struct pktq *pq, bool dir); #else @@ -164,7 +167,8 @@ extern char *getvar(char *vars, const char *name); extern int getintvar(char *vars, const char *name); #ifdef BCMDBG - extern void prpkt(const char *msg, struct osl_info *osh, void *p0); + extern void prpkt(const char *msg, struct osl_info *osh, + struct sk_buff *p0); #endif /* BCMDBG */ #define bcm_perf_enable() #define bcmstats(fmt) diff --git a/drivers/staging/brcm80211/include/hnddma.h b/drivers/staging/brcm80211/include/hnddma.h index 854a3996baa8..05dd9ba19858 100644 --- a/drivers/staging/brcm80211/include/hnddma.h +++ b/drivers/staging/brcm80211/include/hnddma.h @@ -41,7 +41,7 @@ typedef void (*di_txsuspend_t) (hnddma_t *dmah); typedef void (*di_txresume_t) (hnddma_t *dmah); typedef bool(*di_txsuspended_t) (hnddma_t *dmah); typedef bool(*di_txsuspendedidle_t) (hnddma_t *dmah); -typedef int (*di_txfast_t) (hnddma_t *dmah, void *p, bool commit); +typedef int (*di_txfast_t) (hnddma_t *dmah, struct sk_buff *p, bool commit); typedef int (*di_txunframed_t) (hnddma_t *dmah, void *p, uint len, bool commit); typedef void *(*di_getpos_t) (hnddma_t *di, bool direction); diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 6c162b9f864a..76f611d3c3ad 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -48,13 +48,6 @@ #include -extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, - bool suspend); -bool wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw); -void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc); -void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, - const struct ether_addr *addr); - static void wl_timer(unsigned long data); static void _wl_timer(wl_timer_t *t); diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 1fa56cefeed9..f2acda77d47b 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -146,11 +146,10 @@ static void scb_ampdu_update_config_all(ampdu_info_t *ampdu); #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0) static void wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, - void *p, tx_status_t *txs, - u32 frmtxstatus, - u32 frmtxstatus2); + struct sk_buff *p, tx_status_t *txs, + u32 frmtxstatus, u32 frmtxstatus2); -static inline u16 pkt_txh_seqnum(wlc_info_t *wlc, void *p) +static inline u16 pkt_txh_seqnum(wlc_info_t *wlc, struct sk_buff *p) { d11txh_t *txh; struct dot11_header *h; @@ -471,7 +470,8 @@ static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f) } static void BCMFASTPATH -wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, void *p, uint prec) +wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, + uint prec) { scb_ampdu_t *scb_ampdu; scb_ampdu_tid_ini_t *ini; @@ -488,11 +488,12 @@ wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, void *p, uint prec) } int BCMFASTPATH -wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec) +wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, + int prec) { wlc_info_t *wlc; struct osl_info *osh; - void *p, *pkt[AMPDU_MAX_MPDU]; + struct sk_buff *p, *pkt[AMPDU_MAX_MPDU]; u8 tid, ndelim; int err = 0; u8 preamble_type = WLC_GF_PREAMBLE; @@ -884,7 +885,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec) } void BCMFASTPATH -wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p, +wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, tx_status_t *txs) { scb_ampdu_t *scb_ampdu; @@ -948,14 +949,12 @@ rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info, } } -extern void wlc_txq_enq(wlc_info_t *wlc, struct scb *scb, void *sdu, - uint prec); - #define SHORTNAME "AMPDU status" static void BCMFASTPATH -wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p, - tx_status_t *txs, u32 s1, u32 s2) +wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, + struct sk_buff *p, tx_status_t *txs, + u32 s1, u32 s2) { scb_ampdu_t *scb_ampdu; wlc_info_t *wlc = ampdu->wlc; diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.h b/drivers/staging/brcm80211/sys/wlc_ampdu.h index 939cae0d7b4f..c86411beac11 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.h +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.h @@ -21,10 +21,10 @@ extern ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc); extern void wlc_ampdu_detach(ampdu_info_t *ampdu); extern bool wlc_ampdu_cap(ampdu_info_t *ampdu); extern int wlc_ampdu_set(ampdu_info_t *ampdu, bool on); -extern int wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **aggp, - int prec); -extern void wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p, - tx_status_t *txs); +extern int wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, + struct sk_buff **aggp, int prec); +extern void wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, + struct sk_buff *p, tx_status_t *txs); extern void wlc_ampdu_reset(ampdu_info_t *ampdu); extern void wlc_ampdu_macaddr_upd(wlc_info_t *wlc); extern void wlc_ampdu_shm_upd(ampdu_info_t *ampdu); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 4b2708620049..2a2ad494746d 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -270,9 +270,9 @@ static u32 WLBANDINITFN(wlc_setband_inact) (wlc_info_t *wlc, uint bandunit) static bool BCMFASTPATH wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound) { - void *p; - void *head = NULL; - void *tail = NULL; + struct sk_buff *p; + struct sk_buff *head = NULL; + struct sk_buff *tail = NULL; uint n = 0; uint bound_limit = bound ? wlc_hw->wlc->pub->tunables->rxbnd : -1; u32 tsf_h, tsf_l; @@ -3316,7 +3316,7 @@ bool BCMFASTPATH wlc_isr(wlc_info_t *wlc, bool *wantdpc) /* process tx completion events for corerev < 5 */ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw) { - void *status_p; + struct sk_buff *status_p; tx_status_t *txs; struct osl_info *osh; bool fatal = false; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 37a87d8f23c8..d99fcb524d54 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -221,16 +221,15 @@ static const u8 acbitmap2maxprio[] = { #define WLC_REPLAY_CNTRS_VALUE WPA_CAP_16_REPLAY_CNTRS /* local prototypes */ -extern void wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec); static u16 BCMFASTPATH wlc_d11hdrs_mac80211(wlc_info_t *wlc, - struct ieee80211_hw *hw, void *p, + struct ieee80211_hw *hw, + struct sk_buff *p, struct scb *scb, uint frag, uint nfrags, uint queue, uint next_frag_len, wsec_key_t *key, ratespec_t rspec_override); -bool wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw); -void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend); + static void wlc_bss_default_init(wlc_info_t *wlc); static void wlc_ucode_mac_upd(wlc_info_t *wlc); static ratespec_t mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, @@ -258,7 +257,7 @@ static void wlc_compute_mimo_plcp(ratespec_t rate, uint length, u8 *plcp); static u16 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type, uint next_frag_len); static void wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, - void *p); + struct sk_buff *p); static uint wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type, uint dur); static uint wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rate, @@ -5000,10 +4999,10 @@ wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec) } bool BCMFASTPATH -wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec, - bool head) +wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, struct sk_buff *pkt, + int prec, bool head) { - void *p; + struct sk_buff *p; int eprec = -1; /* precedence to evict from */ /* Determine precedence from which to evict packet, if any */ @@ -5064,7 +5063,8 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec, return true; } -void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec) +void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, + uint prec) { wlc_info_t *wlc = (wlc_info_t *) ctx; wlc_txq_info_t *qi = wlc->active_queue; /* Check me */ @@ -5104,7 +5104,8 @@ void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, void *sdu, uint prec) } bool BCMFASTPATH -wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw) +wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, + struct ieee80211_hw *hw) { u8 prio; uint fifo; @@ -5141,7 +5142,7 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, void *sdu, struct ieee80211_hw *hw) void BCMFASTPATH wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi) { - void *pkt[DOT11_MAXNUMFRAGS]; + struct sk_buff *pkt[DOT11_MAXNUMFRAGS]; int prec; u16 prec_map; int err = 0, i, count; @@ -5228,7 +5229,8 @@ bcmc_fid_generate(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh) } void BCMFASTPATH -wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, s8 txpktpend) +wlc_txfifo(wlc_info_t *wlc, uint fifo, struct sk_buff *p, bool commit, + s8 txpktpend) { u16 frameid = INVALIDFID; d11txh_t *txh; @@ -5641,7 +5643,7 @@ wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, bool use_rspec, */ static u16 BCMFASTPATH wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, - void *p, struct scb *scb, uint frag, + struct sk_buff *p, struct scb *scb, uint frag, uint nfrags, uint queue, uint next_frag_len, wsec_key_t *key, ratespec_t rspec_override) { @@ -6507,7 +6509,7 @@ static void wlc_war16165(wlc_info_t *wlc, bool tx) bool BCMFASTPATH wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) { - void *p; + struct sk_buff *p; uint queue; d11txh_t *txh; struct scb *scb = NULL; @@ -6790,7 +6792,7 @@ void wlc_bcn_li_upd(wlc_info_t *wlc) } static void -prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p, +prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, struct sk_buff *p, struct ieee80211_rx_status *rx_status) { u32 tsf_l, tsf_h; @@ -6900,7 +6902,8 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, void *p, } static void -wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, void *p) +wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, + struct sk_buff *p) { int len_mpdu; struct ieee80211_rx_status rx_status; @@ -6963,7 +6966,7 @@ void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list) * Param 'bound' indicates max. # frames to process before break out. */ /* WLC_HIGH_API */ -void BCMFASTPATH wlc_recv(wlc_info_t *wlc, void *p) +void BCMFASTPATH wlc_recv(wlc_info_t *wlc, struct sk_buff *p) { d11rxhdr_t *rxh; struct dot11_header *h; @@ -7789,7 +7792,7 @@ wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend) } /* prepares pdu for transmission. returns BCM error codes */ -int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifop) +int wlc_prep_pdu(wlc_info_t *wlc, struct sk_buff *pdu, uint *fifop) { struct osl_info *osh; uint fifo; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 006880049f37..72a9236d8d86 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -818,11 +818,13 @@ struct antsel_info { extern void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus); extern void wlc_fatal_error(wlc_info_t *wlc); extern void wlc_bmac_rpc_watchdog(wlc_info_t *wlc); -extern void wlc_recv(wlc_info_t *wlc, void *p); +extern void wlc_recv(wlc_info_t *wlc, struct sk_buff *p); extern bool wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2); -extern void wlc_txfifo(wlc_info_t *wlc, uint fifo, void *p, bool commit, - s8 txpktpend); +extern void wlc_txfifo(wlc_info_t *wlc, uint fifo, struct sk_buff *p, + bool commit, s8 txpktpend); extern void wlc_txfifo_complete(wlc_info_t *wlc, uint fifo, s8 txpktpend); +extern void wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, + uint prec); extern void wlc_info_init(wlc_info_t *wlc, int unit); extern void wlc_print_txstatus(tx_status_t *txs); extern int wlc_xmtfifo_sz_get(wlc_info_t *wlc, uint fifo, uint *blocks); @@ -879,7 +881,7 @@ extern void wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, extern bool wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *qi, int prio); extern void wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi); -extern int wlc_prep_pdu(wlc_info_t *wlc, void *pdu, uint *fifo); +extern int wlc_prep_pdu(wlc_info_t *wlc, struct sk_buff *pdu, uint *fifo); extern u16 wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, uint mac_len); @@ -923,8 +925,8 @@ extern bool wlc_ismpc(wlc_info_t *wlc); extern bool wlc_is_non_delay_mpc(wlc_info_t *wlc); extern void wlc_radio_mpc_upd(wlc_info_t *wlc); extern bool wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec); -extern bool wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, void *pkt, - int prec, bool head); +extern bool wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, + struct sk_buff *pkt, int prec, bool head); extern u16 wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec); extern void wlc_compute_plcp(wlc_info_t *wlc, ratespec_t rate, uint length, u8 *plcp); @@ -953,8 +955,6 @@ extern void wlc_mimops_action_ht_send(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, extern void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot); extern void wlc_set_bssid(wlc_bsscfg_t *cfg); extern void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend); -extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, - bool suspend); extern void wlc_set_ratetable(wlc_info_t *wlc); extern int wlc_set_mac(wlc_bsscfg_t *cfg); diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index 4b1ab1d1c2ce..b3ad4c0233ab 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -512,6 +512,8 @@ extern bool wlc_isr(struct wlc_info *wlc, bool *wantdpc); extern bool wlc_dpc(struct wlc_info *wlc, bool bounded); extern bool wlc_send80211_raw(struct wlc_info *wlc, wlc_if_t *wlcif, void *p, uint ac); +extern bool wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, + struct ieee80211_hw *hw); extern int wlc_iovar_op(struct wlc_info *wlc, const char *name, void *params, int p_len, void *arg, int len, bool set, struct wlc_if *wlcif); @@ -520,6 +522,11 @@ extern int wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, /* helper functions */ extern void wlc_statsupd(struct wlc_info *wlc); extern int wlc_get_header_len(void); +extern void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc); +extern void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, + const struct ether_addr *addr); +extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, + bool suspend); extern wlc_pub_t *wlc_pub(void *wlc); diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 83f96cdfe771..701ea0170933 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -33,7 +33,7 @@ #include /* copy a buffer into a pkt buffer chain */ -uint pktfrombuf(struct osl_info *osh, void *p, uint offset, int len, +uint pktfrombuf(struct osl_info *osh, struct sk_buff *p, uint offset, int len, unsigned char *buf) { uint n, ret = 0; @@ -61,7 +61,7 @@ uint pktfrombuf(struct osl_info *osh, void *p, uint offset, int len, return ret; } /* return total length of buffer chain */ -uint BCMFASTPATH pkttotlen(struct osl_info *osh, void *p) +uint BCMFASTPATH pkttotlen(struct osl_info *osh, struct sk_buff *p) { uint total; @@ -75,7 +75,8 @@ uint BCMFASTPATH pkttotlen(struct osl_info *osh, void *p) * osl multiple-precedence packet queue * hi_prec is always >= the number of the highest non-empty precedence */ -void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p) +struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, + struct sk_buff *p) { struct pktq_prec *q; @@ -103,7 +104,8 @@ void *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, void *p) return p; } -void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p) +struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, + struct sk_buff *p) { struct pktq_prec *q; @@ -130,10 +132,10 @@ void *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, void *p) return p; } -void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec) +struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec) { struct pktq_prec *q; - void *p; + struct sk_buff *p; ASSERT(prec >= 0 && prec < pq->num_prec); @@ -156,10 +158,10 @@ void *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec) return p; } -void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) +struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) { struct pktq_prec *q; - void *p, *prev; + struct sk_buff *p, *prev; ASSERT(prec >= 0 && prec < pq->num_prec); @@ -189,7 +191,7 @@ void *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir) { struct pktq_prec *q; - void *p; + struct sk_buff *p; q = &pq->q[prec]; p = q->head; @@ -218,7 +220,7 @@ pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) { struct pktq_prec *q; - void *p, *prev = NULL; + struct sk_buff *p, *prev = NULL; q = &pq->q[prec]; p = q->head; @@ -275,7 +277,7 @@ void pktq_init(struct pktq *pq, int num_prec, int max_len) pq->q[prec].max = pq->max; } -void *pktq_peek_tail(struct pktq *pq, int *prec_out) +struct sk_buff *pktq_peek_tail(struct pktq *pq, int *prec_out) { int prec; @@ -306,10 +308,11 @@ int pktq_mlen(struct pktq *pq, uint prec_bmp) return len; } /* Priority dequeue from a specific set of precedences */ -void *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) +struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, + int *prec_out) { struct pktq_prec *q; - void *p; + struct sk_buff *p; int prec; if (pq->len == 0) @@ -407,9 +410,9 @@ int getintvar(char *vars, const char *name) #if defined(BCMDBG) /* pretty hex print a pkt buffer chain */ -void prpkt(const char *msg, struct osl_info *osh, void *p0) +void prpkt(const char *msg, struct osl_info *osh, struct sk_buff *p0) { - void *p; + struct sk_buff *p; if (msg && (msg[0] != '\0')) printf("%s:\n", msg); diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index f1e9cfcca991..33d2c9a5a97c 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -232,7 +232,7 @@ static bool dma32_alloc(dma_info_t *di, uint direction); static bool dma32_txreset(dma_info_t *di); static bool dma32_rxreset(dma_info_t *di); static bool dma32_txsuspendedidle(dma_info_t *di); -static int dma32_txfast(dma_info_t *di, void *p0, bool commit); +static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit); static void *dma32_getnexttxp(dma_info_t *di, txd_range_t range); static void *dma32_getnextrxp(dma_info_t *di, bool forceall); static void dma32_txrotate(dma_info_t *di); @@ -254,7 +254,7 @@ static bool dma64_alloc(dma_info_t *di, uint direction); static bool dma64_txreset(dma_info_t *di); static bool dma64_rxreset(dma_info_t *di); static bool dma64_txsuspendedidle(dma_info_t *di); -static int dma64_txfast(dma_info_t *di, void *p0, bool commit); +static int dma64_txfast(dma_info_t *di, struct sk_buff *p0, bool commit); static int dma64_txunframed(dma_info_t *di, void *p0, uint len, bool commit); static void *dma64_getpos(dma_info_t *di, bool direction); static void *dma64_getnexttxp(dma_info_t *di, txd_range_t range); @@ -979,7 +979,7 @@ _dma_rx_param_get(dma_info_t *di, u16 *rxoffset, u16 *rxbufsize) */ static void *BCMFASTPATH _dma_rx(dma_info_t *di) { - void *p, *head, *tail; + struct sk_buff *p, *head, *tail; uint len; uint pkt_len; int resid = 0; @@ -1054,7 +1054,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) */ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di) { - void *p; + struct sk_buff *p; u16 rxin, rxout; u32 flags = 0; uint n; @@ -1652,9 +1652,9 @@ static bool dma32_txsuspendedidle(dma_info_t *di) * WARNING: call must check the return value for error. * the error(toss frames) could be fatal and cause many subsequent hard to debug problems */ -static int dma32_txfast(dma_info_t *di, void *p0, bool commit) +static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit) { - void *p, *next; + struct sk_buff *p, *next; unsigned char *data; uint len; u16 txout; @@ -2301,9 +2301,10 @@ static int dma64_txunframed(dma_info_t *di, void *buf, uint len, bool commit) * WARNING: call must check the return value for error. * the error(toss frames) could be fatal and cause many subsequent hard to debug problems */ -static int BCMFASTPATH dma64_txfast(dma_info_t *di, void *p0, bool commit) +static int BCMFASTPATH dma64_txfast(dma_info_t *di, struct sk_buff *p0, + bool commit) { - void *p, *next; + struct sk_buff *p, *next; unsigned char *data; uint len; u16 txout; -- cgit v1.2.3 From 54991ad6d05186bd0324dbdc9c64c5b7952e74c4 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Nov 2010 14:06:24 +0100 Subject: staging: brcm80211: removed packet macros for accessing sk_buff fields With the packet storage type changed from void pointer to struct sk_buff pointer there is no need for macros for accessing these fields through casting. These can now be accessed directly. Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 32 ++--- drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 18 +-- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 10 +- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 136 +++++++++++----------- drivers/staging/brcm80211/include/linux_osl.h | 18 +-- drivers/staging/brcm80211/sys/wlc_ampdu.c | 22 ++-- drivers/staging/brcm80211/sys/wlc_bmac.c | 10 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 50 ++++---- drivers/staging/brcm80211/sys/wlc_pub.h | 2 +- drivers/staging/brcm80211/util/bcmutils.c | 54 ++++----- drivers/staging/brcm80211/util/hnddma.c | 24 ++-- 11 files changed, 183 insertions(+), 193 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 3d3a428fa279..aadfe69a8a0c 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -944,8 +944,8 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, /* Claim host controller */ sdio_claim_host(gInstance->func[func]); - for (pnext = pkt; pnext; pnext = PKTNEXT(pnext)) { - uint pkt_len = PKTLEN(pnext); + for (pnext = pkt; pnext; pnext = pnext->next) { + uint pkt_len = pnext->len; pkt_len += 3; pkt_len &= 0xFFFFFFFC; @@ -962,23 +962,23 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, * is supposed to give * us something we can work with. */ - ASSERT(((u32) (PKTDATA(pkt)) & DMA_ALIGN_MASK) == 0); + ASSERT(((u32) (pkt->data) & DMA_ALIGN_MASK) == 0); if ((write) && (!fifo)) { err_ret = sdio_memcpy_toio(gInstance->func[func], addr, - ((u8 *) PKTDATA(pnext)), + ((u8 *) (pnext->data)), pkt_len); } else if (write) { err_ret = sdio_memcpy_toio(gInstance->func[func], addr, - ((u8 *) PKTDATA(pnext)), + ((u8 *) (pnext->data)), pkt_len); } else if (fifo) { err_ret = sdio_readsb(gInstance->func[func], - ((u8 *) PKTDATA(pnext)), + ((u8 *) (pnext->data)), addr, pkt_len); } else { err_ret = sdio_memcpy_fromio(gInstance->func[func], - ((u8 *) PKTDATA(pnext)), + ((u8 *) (pnext->data)), addr, pkt_len); } @@ -1048,41 +1048,41 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, /* For a write, copy the buffer data into the packet. */ if (write) - bcopy(buffer, PKTDATA(mypkt), buflen_u); + bcopy(buffer, mypkt->data, buflen_u); Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); /* For a read, copy the packet data back to the buffer. */ if (!write) - bcopy(PKTDATA(mypkt), buffer, buflen_u); + bcopy(mypkt->data, buffer, buflen_u); PKTFREE(sd->osh, mypkt, write ? true : false); - } else if (((u32) (PKTDATA(pkt)) & DMA_ALIGN_MASK) != 0) { + } else if (((u32) (pkt->data) & DMA_ALIGN_MASK) != 0) { /* Case 2: We have a packet, but it is unaligned. */ /* In this case, we cannot have a chain. */ - ASSERT(PKTNEXT(pkt) == NULL); + ASSERT(pkt->next == NULL); sd_data(("%s: Creating aligned %s Packet, len=%d\n", - __func__, write ? "TX" : "RX", PKTLEN(pkt))); - mypkt = PKTGET(sd->osh, PKTLEN(pkt), write ? true : false); + __func__, write ? "TX" : "RX", pkt->len)); + mypkt = PKTGET(sd->osh, pkt->len, write ? true : false); if (!mypkt) { sd_err(("%s: PKTGET failed: len %d\n", - __func__, PKTLEN(pkt))); + __func__, pkt->len)); return SDIOH_API_RC_FAIL; } /* For a write, copy the buffer data into the packet. */ if (write) - bcopy(PKTDATA(pkt), PKTDATA(mypkt), PKTLEN(pkt)); + bcopy(pkt->data, mypkt->data, pkt->len); Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); /* For a read, copy the packet data back to the buffer. */ if (!write) - bcopy(PKTDATA(mypkt), PKTDATA(pkt), PKTLEN(mypkt)); + bcopy(mypkt->data, pkt->data, mypkt->len); PKTFREE(sd->osh, mypkt, write ? true : false); } else { /* case 3: We have a packet and diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c index c23d30b13147..2fa77cb53040 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c @@ -323,13 +323,13 @@ void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, struct sk_buff *pktbuf) skb_push(pktbuf, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(pktbuf); + h = (struct bdc_header *)(pktbuf->data); h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); if (PKTSUMNEEDED(pktbuf)) h->flags |= BDC_FLAG_SUM_NEEDED; - h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); + h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); h->flags2 = 0; h->rssi = 0; #endif /* BDC */ @@ -341,13 +341,13 @@ bool dhd_proto_fcinfo(dhd_pub_t *dhd, struct sk_buff *pktbuf, u8 * fcbits) #ifdef BDC struct bdc_header *h; - if (PKTLEN(pktbuf) < BDC_HEADER_LEN) { + if (pktbuf->len < BDC_HEADER_LEN) { DHD_ERROR(("%s: rx data too short (%d < %d)\n", - __func__, PKTLEN(pktbuf), BDC_HEADER_LEN)); + __func__, pktbuf->len, BDC_HEADER_LEN)); return BCME_ERROR; } - h = (struct bdc_header *)PKTDATA(pktbuf); + h = (struct bdc_header *)(pktbuf->data); *fcbits = h->priority >> BDC_PRIORITY_FC_SHIFT; if ((h->flags2 & BDC_FLAG2_FC_FLAG) == BDC_FLAG2_FC_FLAG) @@ -367,13 +367,13 @@ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, struct sk_buff *pktbuf) #ifdef BDC /* Pop BDC header used to convey priority for buses that don't */ - if (PKTLEN(pktbuf) < BDC_HEADER_LEN) { + if (pktbuf->len < BDC_HEADER_LEN) { DHD_ERROR(("%s: rx data too short (%d < %d)\n", __func__, - PKTLEN(pktbuf), BDC_HEADER_LEN)); + pktbuf->len, BDC_HEADER_LEN)); return BCME_ERROR; } - h = (struct bdc_header *)PKTDATA(pktbuf); + h = (struct bdc_header *)(pktbuf->data); *ifidx = BDC_GET_IF_IDX(h); if (*ifidx >= DHD_MAX_IFS) { @@ -396,7 +396,7 @@ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, struct sk_buff *pktbuf) PKTSETSUMGOOD(pktbuf, true); } - PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); + pktbuf->priority = h->priority & BDC_PRIORITY_MASK; skb_pull(pktbuf, BDC_HEADER_LEN); #endif /* BDC */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index ec887fb32faa..2a502f9ab66d 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1028,8 +1028,8 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf) return -ENODEV; /* Update multicast statistic */ - if (PKTLEN(pktbuf) >= ETHER_ADDR_LEN) { - u8 *pktdata = (u8 *) PKTDATA(pktbuf); + if (pktbuf->len >= ETHER_ADDR_LEN) { + u8 *pktdata = (u8 *) (pktbuf->data); struct ether_header *eh = (struct ether_header *)pktdata; if (ETHER_ISMULTI(eh->ether_dhost)) @@ -1151,8 +1151,8 @@ void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf, for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { - pnext = PKTNEXT(pktbuf); - PKTSETNEXT(pktbuf, NULL); + pnext = pktbuf->next; + pktbuf->next = NULL; skb = PKTTONATIVE(dhdp->osh, pktbuf); @@ -1233,7 +1233,7 @@ void dhd_txcomplete(dhd_pub_t *dhdp, struct sk_buff *txp, bool success) dhd_prot_hdrpull(dhdp, &ifidx, txp); - eh = (struct ether_header *)PKTDATA(txp); + eh = (struct ether_header *)(txp->data); type = ntoh16(eh->ether_type); if (type == ETHER_TYPE_802_1X) diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 12bb7c602f1f..1d06fb299801 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -357,16 +357,16 @@ extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ -#define PKTALIGN(osh, p, len, align) \ +#define PKTALIGN(_osh, _p, _len, _align) \ do { \ uint datalign; \ - datalign = (unsigned long)PKTDATA((p)); \ - datalign = roundup(datalign, (align)) - datalign; \ - ASSERT(datalign < (align)); \ - ASSERT(PKTLEN((p)) >= ((len) + datalign)); \ + datalign = (unsigned long)((_p)->data); \ + datalign = roundup(datalign, (_align)) - datalign; \ + ASSERT(datalign < (_align)); \ + ASSERT((_p)->len >= ((_len) + datalign)); \ if (datalign) \ - skb_pull((p), datalign); \ - __skb_trim((p), (len)); \ + skb_pull((_p), datalign); \ + __skb_trim((_p), (_len)); \ } while (0) /* Limit on rounding up frames */ @@ -927,7 +927,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, goto done; } - frame = (u8 *) PKTDATA(pkt); + frame = (u8 *) (pkt->data); /* Add alignment padding, allocate new packet if needed */ pad = ((unsigned long)frame % DHD_SDALIGN); @@ -936,37 +936,37 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, DHD_INFO(("%s: insufficient headroom %d for %d pad\n", __func__, (int)PKTHEADROOM(pkt), pad)); bus->dhd->tx_realloc++; - new = PKTGET(osh, (PKTLEN(pkt) + DHD_SDALIGN), true); + new = PKTGET(osh, (pkt->len + DHD_SDALIGN), true); if (!new) { DHD_ERROR(("%s: couldn't allocate new %d-byte " "packet\n", - __func__, PKTLEN(pkt) + DHD_SDALIGN)); + __func__, pkt->len + DHD_SDALIGN)); ret = BCME_NOMEM; goto done; } - PKTALIGN(osh, new, PKTLEN(pkt), DHD_SDALIGN); - bcopy(PKTDATA(pkt), PKTDATA(new), PKTLEN(pkt)); + PKTALIGN(osh, new, pkt->len, DHD_SDALIGN); + bcopy(pkt->data, new->data, pkt->len); if (free_pkt) PKTFREE(osh, pkt, true); /* free the pkt if canned one is not used */ free_pkt = true; pkt = new; - frame = (u8 *) PKTDATA(pkt); + frame = (u8 *) (pkt->data); ASSERT(((unsigned long)frame % DHD_SDALIGN) == 0); pad = 0; } else { skb_push(pkt, pad); - frame = (u8 *) PKTDATA(pkt); + frame = (u8 *) (pkt->data); - ASSERT((pad + SDPCM_HDRLEN) <= (int)PKTLEN(pkt)); + ASSERT((pad + SDPCM_HDRLEN) <= (int)(pkt->len)); bzero(frame, pad + SDPCM_HDRLEN); } } ASSERT(pad < DHD_SDALIGN); /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - len = (u16) PKTLEN(pkt); + len = (u16) (pkt->len); *(u16 *) frame = htol16(len); *(((u16 *) frame) + 1) = htol16(~len); @@ -979,7 +979,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); #ifdef DHD_DEBUG - tx_packets[PKTPRIO(pkt)]++; + tx_packets[pkt->priority]++; if (DHD_BYTES_ON() && (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { @@ -1075,14 +1075,14 @@ int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *pkt) DHD_TRACE(("%s: Enter\n", __func__)); osh = bus->dhd->osh; - datalen = PKTLEN(pkt); + datalen = pkt->len; #ifdef SDTEST /* Push the test header if doing loopback */ if (bus->ext_loop) { u8 *data; skb_push(pkt, SDPCM_TEST_HDRLEN); - data = PKTDATA(pkt); + data = pkt->data; *data++ = SDPCM_TEST_ECHOREQ; *data++ = (u8) bus->loopid++; *data++ = (datalen >> 0); @@ -1093,9 +1093,9 @@ int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *pkt) /* Add space for the header */ skb_push(pkt, SDPCM_HDRLEN); - ASSERT(IS_ALIGNED((unsigned long)PKTDATA(pkt), 2)); + ASSERT(IS_ALIGNED((unsigned long)(pkt->data), 2)); - prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); + prec = PRIO2PREC((pkt->priority & PRIOMASK)); /* Check for existing queue, current flow-control, pending event, or pending clock */ @@ -1191,7 +1191,7 @@ static uint dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) break; } dhd_os_sdunlock_txq(bus->dhd); - datalen = PKTLEN(pkt) - SDPCM_HDRLEN; + datalen = pkt->len - SDPCM_HDRLEN; #ifndef SDTEST ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); @@ -3204,8 +3204,8 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) dhd_os_sdlock_rxq(bus->dhd); pfirst = plast = pnext = NULL; - dlen = (u16) PKTLEN(bus->glomd); - dptr = PKTDATA(bus->glomd); + dlen = (u16) (bus->glomd->len); + dptr = bus->glomd->data; if (!dlen || (dlen & 1)) { DHD_ERROR(("%s: bad glomd len(%d), ignore descriptor\n", __func__, dlen)); @@ -3246,13 +3246,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) __func__, num, sublen)); break; } - ASSERT(!PKTLINK(pnext)); + ASSERT(!(pnext->prev)); if (!pfirst) { ASSERT(!plast); pfirst = plast = pnext; } else { ASSERT(plast); - PKTSETNEXT(plast, pnext); + plast->next = pnext; plast = pnext; } @@ -3295,10 +3295,10 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) if (DHD_GLOM_ON()) { DHD_GLOM(("%s: try superframe read, packet chain:\n", __func__)); - for (pnext = bus->glom; pnext; pnext = PKTNEXT(pnext)) { + for (pnext = bus->glom; pnext; pnext = pnext->next) { DHD_GLOM((" %p: %p len 0x%04x (%d)\n", - pnext, (u8 *) PKTDATA(pnext), - PKTLEN(pnext), PKTLEN(pnext))); + pnext, (u8 *) (pnext->data), + pnext->len, pnext->len)); } } @@ -3314,7 +3314,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) bcmsdh_cur_sbwad (bus->sdh), SDIO_FUNC_2, F2SYNC, - (u8 *) PKTDATA(pfirst), + (u8 *) pfirst->data, dlen, pfirst, NULL, NULL); } else if (bus->dataptr) { errcode = dhd_bcmsdh_recv_buf(bus, @@ -3360,13 +3360,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) } #ifdef DHD_DEBUG if (DHD_GLOM_ON()) { - prhex("SUPERFRAME", PKTDATA(pfirst), - min_t(int, PKTLEN(pfirst), 48)); + prhex("SUPERFRAME", pfirst->data, + min_t(int, pfirst->len, 48)); } #endif /* Validate the superframe header */ - dptr = (u8 *) PKTDATA(pfirst); + dptr = (u8 *) (pfirst->data); sublen = ltoh16_ua(dptr); check = ltoh16_ua(dptr + sizeof(u16)); @@ -3404,11 +3404,11 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) __func__)); errcode = -1; } else if ((doff < SDPCM_HDRLEN) || - (doff > (PKTLEN(pfirst) - SDPCM_HDRLEN))) { + (doff > (pfirst->len - SDPCM_HDRLEN))) { DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d " "pkt %d min %d\n", __func__, doff, sublen, - PKTLEN(pfirst), SDPCM_HDRLEN)); + pfirst->len, SDPCM_HDRLEN)); errcode = -1; } @@ -3434,9 +3434,9 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) /* Validate all the subframe headers */ for (num = 0, pnext = pfirst; pnext && !errcode; - num++, pnext = PKTNEXT(pnext)) { - dptr = (u8 *) PKTDATA(pnext); - dlen = (u16) PKTLEN(pnext); + num++, pnext = pnext->next) { + dptr = (u8 *) (pnext->data); + dlen = (u16) (pnext->len); sublen = ltoh16_ua(dptr); check = ltoh16_ua(dptr + sizeof(u16)); chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); @@ -3496,10 +3496,10 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) dhd_os_sdlock_rxq(bus->dhd); for (num = 0; pfirst; rxseq++, pfirst = pnext) { - pnext = PKTNEXT(pfirst); - PKTSETNEXT(pfirst, NULL); + pnext = pfirst->next; + pfirst->next = NULL; - dptr = (u8 *) PKTDATA(pfirst); + dptr = (u8 *) (pfirst->data); sublen = ltoh16_ua(dptr); chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); @@ -3507,8 +3507,8 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d " "chan %d seq %d\n", - __func__, num, pfirst, PKTDATA(pfirst), - PKTLEN(pfirst), sublen, chan, seq)); + __func__, num, pfirst, pfirst->data, + pfirst->len, sublen, chan, seq)); ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); @@ -3527,10 +3527,10 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) __skb_trim(pfirst, sublen); skb_pull(pfirst, doff); - if (PKTLEN(pfirst) == 0) { + if (pfirst->len == 0) { PKTFREE(bus->dhd->osh, pfirst, false); if (plast) { - PKTSETNEXT(plast, pnext); + plast->next = pnext; } else { ASSERT(save_pfirst == pfirst); save_pfirst = pnext; @@ -3543,7 +3543,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) bus->dhd->rx_errors++; PKTFREE(osh, pfirst, false); if (plast) { - PKTSETNEXT(plast, pnext); + plast->next = pnext; } else { ASSERT(save_pfirst == pfirst); save_pfirst = pnext; @@ -3553,7 +3553,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) /* this packet will go up, link back into chain and count it */ - PKTSETNEXT(pfirst, pnext); + pfirst->next = pnext; plast = pfirst; num++; @@ -3561,11 +3561,11 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) if (DHD_GLOM_ON()) { DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) " "nxt/lnk %p/%p\n", - __func__, num, pfirst, PKTDATA(pfirst), - PKTLEN(pfirst), PKTNEXT(pfirst), - PKTLINK(pfirst))); - prhex("", (u8 *) PKTDATA(pfirst), - min_t(int, PKTLEN(pfirst), 32)); + __func__, num, pfirst, pfirst->data, + pfirst->len, pfirst->next, + pfirst->prev)); + prhex("", (u8 *) pfirst->data, + min_t(int, pfirst->len, 32)); } #endif /* DHD_DEBUG */ } @@ -3737,9 +3737,9 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if (bus->bus == SPI_BUS) bus->usebufpool = true; - ASSERT(!PKTLINK(pkt)); + ASSERT(!(pkt->prev)); PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - rxbuf = (u8 *) PKTDATA(pkt); + rxbuf = (u8 *) (pkt->data); /* Read the entire frame */ sdret = dhd_bcmsdh_recv_buf(bus, @@ -4103,17 +4103,17 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } dhd_os_sdunlock_rxq(bus->dhd); - ASSERT(!PKTLINK(pkt)); + ASSERT(!(pkt->prev)); /* Leave room for what we already read, and align remainder */ - ASSERT(firstread < (PKTLEN(pkt))); + ASSERT(firstread < pkt->len); skb_pull(pkt, firstread); PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); /* Read the remaining frame data */ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, - F2SYNC, ((u8 *) PKTDATA(pkt)), rdlen, + F2SYNC, ((u8 *) (pkt->data)), rdlen, pkt, NULL, NULL); bus->f2rxdata++; ASSERT(sdret != BCME_PENDING); @@ -4136,11 +4136,11 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Copy the already-read portion */ skb_push(pkt, firstread); - bcopy(bus->rxhdr, PKTDATA(pkt), firstread); + bcopy(bus->rxhdr, pkt->data, firstread); #ifdef DHD_DEBUG if (DHD_BYTES_ON() && DHD_DATA_ON()) - prhex("Rx Data", PKTDATA(pkt), len); + prhex("Rx Data", pkt->data, len); #endif deliver: @@ -4151,7 +4151,7 @@ deliver: __func__, len)); #ifdef DHD_DEBUG if (DHD_GLOM_ON()) { - prhex("Glom Data", PKTDATA(pkt), len); + prhex("Glom Data", pkt->data, len); } #endif __skb_trim(pkt, len); @@ -4178,7 +4178,7 @@ deliver: } #endif /* SDTEST */ - if (PKTLEN(pkt) == 0) { + if (pkt->len == 0) { dhd_os_sdlock_rxq(bus->dhd); PKTFREE(bus->dhd->osh, pkt, false); dhd_os_sdunlock_rxq(bus->dhd); @@ -4672,7 +4672,7 @@ static void dhdsdio_pktgen(dhd_bus_t *bus) } PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); - data = (u8 *) PKTDATA(pkt) + SDPCM_HDRLEN; + data = (u8 *) (pkt->data) + SDPCM_HDRLEN; /* Write test header cmd and extra based on mode */ switch (bus->pktgen_mode) { @@ -4711,9 +4711,9 @@ static void dhdsdio_pktgen(dhd_bus_t *bus) #ifdef DHD_DEBUG if (DHD_BYTES_ON() && DHD_DATA_ON()) { - data = (u8 *) PKTDATA(pkt) + SDPCM_HDRLEN; + data = (u8 *) (pkt->data) + SDPCM_HDRLEN; prhex("dhdsdio_pktgen: Tx Data", data, - PKTLEN(pkt) - SDPCM_HDRLEN); + pkt->len - SDPCM_HDRLEN); } #endif @@ -4750,7 +4750,7 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) return; } PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); - data = (u8 *) PKTDATA(pkt) + SDPCM_HDRLEN; + data = (u8 *) (pkt->data) + SDPCM_HDRLEN; /* Fill in the test header */ *data++ = SDPCM_TEST_SEND; @@ -4775,7 +4775,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) u16 offset; /* Check for min length */ - pktlen = PKTLEN(pkt); + pktlen = pkt->len; if (pktlen < SDPCM_TEST_HDRLEN) { DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); @@ -4784,7 +4784,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) } /* Extract header fields */ - data = PKTDATA(pkt); + data = pkt->data; cmd = *data++; extra = *data++; len = *data++; @@ -4807,7 +4807,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) case SDPCM_TEST_ECHOREQ: /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ - *(u8 *) (PKTDATA(pkt)) = SDPCM_TEST_ECHORSP; + *(u8 *) (pkt->data) = SDPCM_TEST_ECHORSP; if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true) == 0) { bus->pktgen_sent++; } else { diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 010182fa1a92..4e446606b5c1 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -246,15 +246,10 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define BZERO_SM(r, len) memset((r), '\0', (len)) /* packet primitives */ -#define PKTGET(osh, len, send) osl_pktget((osh), (len)) -#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -#define PKTDATA(skb) (((struct sk_buff *)(skb))->data) -#define PKTLEN(skb) (((struct sk_buff *)(skb))->len) -#define PKTHEADROOM(skb) (PKTDATA(skb)-(((struct sk_buff *)(skb))->head)) -#define PKTTAILROOM(skb) ((((struct sk_buff *)(skb))->end)-(((struct sk_buff *)(skb))->tail)) -#define PKTNEXT(skb) (((struct sk_buff *)(skb))->next) -#define PKTSETNEXT(skb, x) \ - (((struct sk_buff *)(skb))->next = (struct sk_buff *)(x)) +#define PKTGET(osh, len, send) osl_pktget((osh), (len)) +#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) +#define PKTHEADROOM(skb) ((skb)->data - (skb)->head) +#define PKTTAILROOM(skb) ((skb)->end - (skb)->tail) #define PKTALLOCED(osh) (((struct osl_pubinfo *)(osh))->pktalloced) extern void *osl_pktget(struct osl_info *osh, uint len); extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); @@ -293,14 +288,9 @@ osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) #define PKTSKIPCT(osh, skb) #endif /* BRCM_FULLMAC */ -#define PKTLINK(skb) (((struct sk_buff *)(skb))->prev) -#define PKTSETLINK(skb, x) (((struct sk_buff *)(skb))->prev = (struct sk_buff*)(x)) -#define PKTPRIO(skb) (((struct sk_buff *)(skb))->priority) -#define PKTSETPRIO(skb, x) (((struct sk_buff *)(skb))->priority = (x)) #define PKTSUMNEEDED(skb) (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL) #define PKTSETSUMGOOD(skb, x) (((struct sk_buff *)(skb))->ip_summed = \ ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) /* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ -#define PKTSHARED(skb) (((struct sk_buff *)(skb))->cloned) #endif /* _linux_osl_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index f2acda77d47b..c5ab4a459471 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -153,7 +153,7 @@ static inline u16 pkt_txh_seqnum(wlc_info_t *wlc, struct sk_buff *p) { d11txh_t *txh; struct dot11_header *h; - txh = (d11txh_t *) PKTDATA(p); + txh = (d11txh_t *) p->data; h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); return ltoh16(h->seq) >> SEQNUM_SHIFT; } @@ -475,7 +475,7 @@ wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, { scb_ampdu_t *scb_ampdu; scb_ampdu_tid_ini_t *ini; - u8 tid = (u8) PKTPRIO(p); + u8 tid = (u8) (p->priority); scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb); @@ -529,7 +529,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, ASSERT(p); - tid = (u8) PKTPRIO(p); + tid = (u8) (p->priority); ASSERT(tid < AMPDU_MAX_SCB_TID); f = ampdu->fifo_tb + prio2fifo[tid]; @@ -589,7 +589,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, /* pkt is good to be aggregated */ ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU); - txh = (d11txh_t *) PKTDATA(p); + txh = (d11txh_t *) p->data; plcp = (u8 *) (txh + 1); h = (struct dot11_header *)(plcp + D11_PHY_HDR_LEN); seq = ltoh16(h->seq) >> SEQNUM_SHIFT; @@ -744,7 +744,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, if (p) { if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && - ((u8) PKTPRIO(p) == tid)) { + ((u8) (p->priority) == tid)) { plen = pkttotlen(osh, p) + AMPDU_MAX_MPDU_OVERHEAD; @@ -778,7 +778,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, WLCNTADD(ampdu->cnt->txmpdu, count); /* patch up the last txh */ - txh = (d11txh_t *) PKTDATA(pkt[count - 1]); + txh = (d11txh_t *) pkt[count - 1]->data; mcl = ltoh16(txh->MacTxControlLow); mcl &= ~TXC_AMPDU_MASK; mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT); @@ -796,7 +796,7 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, ampdu_len -= roundup(len, 4) - len; /* patch up the first txh & plcp */ - txh = (d11txh_t *) PKTDATA(pkt[0]); + txh = (d11txh_t *) pkt[0]->data; plcp = (u8 *) (txh + 1); WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len); @@ -901,7 +901,7 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, ASSERT(txs->status & TX_STATUS_AMPDU); scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb); ASSERT(scb_ampdu); - ini = SCB_AMPDU_INI(scb_ampdu, PKTPRIO(p)); + ini = SCB_AMPDU_INI(scb_ampdu, p->priority); ASSERT(ini->scb == scb); /* BMAC_NOTE: For the split driver, second level txstatus comes later @@ -985,7 +985,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb); ASSERT(scb_ampdu); - tid = (u8) PKTPRIO(p); + tid = (u8) (p->priority); ini = SCB_AMPDU_INI(scb_ampdu, tid); retry_limit = ampdu->retry_limit_tid[tid]; @@ -1065,7 +1065,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, #ifdef BCMDBG if (WL_ERROR_ON()) { prpkt("txpkt (AMPDU)", wlc->osh, p); - wlc_print_txdesc((d11txh_t *) PKTDATA(p)); + wlc_print_txdesc((d11txh_t *) p->data); wlc_print_txstatus(txs); } #endif /* BCMDBG */ @@ -1076,7 +1076,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, while (p) { tx_info = IEEE80211_SKB_CB(p); ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU); - txh = (d11txh_t *) PKTDATA(p); + txh = (d11txh_t *) p->data; mcl = ltoh16(txh->MacTxControlLow); plcp = (u8 *) (txh + 1); h = (struct dot11_header *)(plcp + D11_PHY_HDR_LEN); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 2a2ad494746d..264389f788f1 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -285,7 +285,7 @@ wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound) if (!tail) head = tail = p; else { - PKTSETLINK(tail, p); + tail->prev = p; tail = p; } @@ -302,11 +302,11 @@ wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound) /* process each frame */ while ((p = head) != NULL) { - head = PKTLINK(head); - PKTSETLINK(p, NULL); + head = head->prev; + p->prev = NULL; /* record the tsf_l in wlc_rxd11hdr */ - wlc_rxhdr = (wlc_d11rxhdr_t *) PKTDATA(p); + wlc_rxhdr = (wlc_d11rxhdr_t *) p->data; wlc_rxhdr->tsf_l = htol32(tsf_l); /* compute the RSSI from d11rxhdr and record it in wlc_rxd11hr */ @@ -3327,7 +3327,7 @@ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw) while (!fatal && (status_p = dma_rx(wlc_hw->di[RX_TXSTATUS_FIFO]))) { - txs = (tx_status_t *) PKTDATA(status_p); + txs = (tx_status_t *) status_p->data; /* MAC uses little endian only */ ltoh16_buf((void *)txs, sizeof(tx_status_t)); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index d99fcb524d54..52e4d95a5cb1 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -5042,9 +5042,9 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, struct sk_buff *pkt, /* Increment wme stats */ if (WME_ENAB(wlc->pub)) { WLCNTINCR(wlc->pub->_wme_cnt-> - tx_failed[WME_PRIO2AC(PKTPRIO(p))].packets); + tx_failed[WME_PRIO2AC(p->priority)].packets); WLCNTADD(wlc->pub->_wme_cnt-> - tx_failed[WME_PRIO2AC(PKTPRIO(p))].bytes, + tx_failed[WME_PRIO2AC(p->priority)].bytes, pkttotlen(wlc->osh, p)); } @@ -5071,7 +5071,7 @@ void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, struct pktq *q = &qi->q; int prio; - prio = PKTPRIO(sdu); + prio = sdu->priority; ASSERT(pktq_max(q) >= wlc->pub->tunables->datahiwat); @@ -5111,7 +5111,7 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, uint fifo; void *pkt; struct scb *scb = &global_scb; - struct dot11_header *d11_header = (struct dot11_header *)PKTDATA(sdu); + struct dot11_header *d11_header = (struct dot11_header *)(sdu->data); u16 type, fc; ASSERT(sdu); @@ -5120,13 +5120,13 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, type = FC_TYPE(fc); /* 802.11 standard requires management traffic to go at highest priority */ - prio = (type == FC_TYPE_DATA ? PKTPRIO(sdu) : MAXPRIO); + prio = (type == FC_TYPE_DATA ? sdu->priority : MAXPRIO); fifo = prio2fifo[prio]; ASSERT((uint) PKTHEADROOM(sdu) >= TXOFF); - ASSERT(!PKTSHARED(sdu)); - ASSERT(!PKTNEXT(sdu)); - ASSERT(!PKTLINK(sdu)); + ASSERT(!(sdu->cloned)); + ASSERT(!(sdu->next)); + ASSERT(!(sdu->prev)); ASSERT(fifo < NFIFO); pkt = sdu; @@ -5236,7 +5236,7 @@ wlc_txfifo(wlc_info_t *wlc, uint fifo, struct sk_buff *p, bool commit, d11txh_t *txh; ASSERT(fifo < NFIFO); - txh = (d11txh_t *) PKTDATA(p); + txh = (d11txh_t *) (p->data); /* When a BC/MC frame is being committed to the BCMC fifo via DMA (NOT PIO), update * ucode or BSS info as appropriate. @@ -5690,7 +5690,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, osh = wlc->osh; /* locate 802.11 MAC header */ - h = (struct dot11_header *)PKTDATA(p); + h = (struct dot11_header *)(p->data); fc = ltoh16(h->fc); type = FC_TYPE(fc); @@ -5731,12 +5731,12 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, } else { /* Increment the counter for first fragment */ if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) { - SCB_SEQNUM(scb, PKTPRIO(p))++; + SCB_SEQNUM(scb, p->priority)++; } /* extract fragment number from frame first */ seq = ltoh16(seq) & FRAGNUM_MASK; - seq |= (SCB_SEQNUM(scb, PKTPRIO(p)) << SEQNUM_SHIFT); + seq |= (SCB_SEQNUM(scb, p->priority) << SEQNUM_SHIFT); h->seq = htol16(seq); frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | @@ -6559,7 +6559,7 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) if (p == NULL) goto fatal; - txh = (d11txh_t *) PKTDATA(p); + txh = (d11txh_t *) (p->data); mcl = ltoh16(txh->MacTxControlLow); if (txs->phyerr) { @@ -6649,8 +6649,8 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) wlc_txfifo_complete(wlc, queue, 1); if (lastframe) { - PKTSETNEXT(p, NULL); - PKTSETLINK(p, NULL); + p->next = NULL; + p->prev = NULL; wlc->txretried = 0; /* remove PLCP & Broadcom tx descriptor header */ skb_pull(p, D11_PHY_HDR_LEN); @@ -6825,7 +6825,7 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, struct sk_buff *p, /* qual */ rx_status->antenna = (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0; /* ant */ - plcp = PKTDATA(p); + plcp = p->data; rspec = wlc_compute_rspec(rxh, plcp); if (IS_MCS(rspec)) { @@ -6920,12 +6920,12 @@ wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, prep_mac80211_status(wlc, rxh, p, &rx_status); /* mac header+body length, exclude CRC and plcp header */ - len_mpdu = PKTLEN(p) - D11_PHY_HDR_LEN - DOT11_FCS_LEN; + len_mpdu = p->len - D11_PHY_HDR_LEN - DOT11_FCS_LEN; skb_pull(p, D11_PHY_HDR_LEN); __skb_trim(p, len_mpdu); - ASSERT(!PKTNEXT(p)); - ASSERT(!PKTLINK(p)); + ASSERT(!(p->next)); + ASSERT(!(p->prev)); ASSERT(IS_ALIGNED((unsigned long)skb->data, 2)); @@ -6980,7 +6980,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, struct sk_buff *p) osh = wlc->osh; /* frame starts with rxhdr */ - rxh = (d11rxhdr_t *) PKTDATA(p); + rxh = (d11rxhdr_t *) (p->data); /* strip off rxhdr */ skb_pull(p, wlc->hwrxoff); @@ -6990,17 +6990,17 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, struct sk_buff *p) /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */ if (rxh->RxStatus1 & RXS_PBPRES) { - if (PKTLEN(p) < 2) { + if (p->len < 2) { WLCNTINCR(wlc->pub->_cnt->rxrunt); WL_ERROR(("wl%d: wlc_recv: rcvd runt of len %d\n", - wlc->pub->unit, PKTLEN(p))); + wlc->pub->unit, p->len)); goto toss; } skb_pull(p, 2); } - h = (struct dot11_header *)(PKTDATA(p) + D11_PHY_HDR_LEN); - len = PKTLEN(p); + h = (struct dot11_header *)(p->data + D11_PHY_HDR_LEN); + len = p->len; if (rxh->RxStatus1 & RXS_FCSERR) { if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { @@ -7804,7 +7804,7 @@ int wlc_prep_pdu(wlc_info_t *wlc, struct sk_buff *pdu, uint *fifop) osh = wlc->osh; ASSERT(pdu); - txh = (d11txh_t *) PKTDATA(pdu); + txh = (d11txh_t *) (pdu->data); ASSERT(txh); h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); ASSERT(h); diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index b3ad4c0233ab..ea796cb40b7a 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -440,7 +440,7 @@ struct wlc_if; #define WLC_PREC_COUNT 16 /* Max precedence level implemented */ -/* pri is PKTPRIO encoded in the packet. This maps the Packet priority to +/* pri is priority encoded in the packet. This maps the Packet priority to * enqueue precedence as defined in wlc_prec_map */ extern const u8 wlc_prio2prec_map[]; diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 701ea0170933..49c1f74dda83 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -39,19 +39,19 @@ uint pktfrombuf(struct osl_info *osh, struct sk_buff *p, uint offset, int len, uint n, ret = 0; /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(p)) { - if (offset < (uint) PKTLEN(p)) + for (; p && offset; p = p->next) { + if (offset < (uint) (p->len)) break; - offset -= PKTLEN(p); + offset -= p->len; } if (!p) return 0; /* copy the data */ - for (; p && len; p = PKTNEXT(p)) { - n = min((uint) PKTLEN(p) - offset, (uint) len); - bcopy(buf, PKTDATA(p) + offset, n); + for (; p && len; p = p->next) { + n = min((uint) (p->len) - offset, (uint) len); + bcopy(buf, p->data + offset, n); buf += n; len -= n; ret += n; @@ -66,8 +66,8 @@ uint BCMFASTPATH pkttotlen(struct osl_info *osh, struct sk_buff *p) uint total; total = 0; - for (; p; p = PKTNEXT(p)) - total += PKTLEN(p); + for (; p; p = p->next) + total += p->len; return total; } @@ -81,7 +81,7 @@ struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, struct pktq_prec *q; ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + ASSERT(p->prev == NULL); /* queueing chains not allowed */ ASSERT(!pktq_full(pq)); ASSERT(!pktq_pfull(pq, prec)); @@ -89,7 +89,7 @@ struct sk_buff *BCMFASTPATH pktq_penq(struct pktq *pq, int prec, q = &pq->q[prec]; if (q->head) - PKTSETLINK(q->tail, p); + q->tail->prev = p; else q->head = p; @@ -110,7 +110,7 @@ struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, struct pktq_prec *q; ASSERT(prec >= 0 && prec < pq->num_prec); - ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ + ASSERT(p->prev == NULL); /* queueing chains not allowed */ ASSERT(!pktq_full(pq)); ASSERT(!pktq_pfull(pq, prec)); @@ -120,7 +120,7 @@ struct sk_buff *BCMFASTPATH pktq_penq_head(struct pktq *pq, int prec, if (q->head == NULL) q->tail = p; - PKTSETLINK(p, q->head); + p->prev = q->head; q->head = p; q->len++; @@ -145,7 +145,7 @@ struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec) if (p == NULL) return NULL; - q->head = PKTLINK(p); + q->head = p->prev; if (q->head == NULL) q->tail = NULL; @@ -153,7 +153,7 @@ struct sk_buff *BCMFASTPATH pktq_pdeq(struct pktq *pq, int prec) pq->len--; - PKTSETLINK(p, NULL); + p->prev = NULL; return p; } @@ -171,11 +171,11 @@ struct sk_buff *BCMFASTPATH pktq_pdeq_tail(struct pktq *pq, int prec) if (p == NULL) return NULL; - for (prev = NULL; p != q->tail; p = PKTLINK(p)) + for (prev = NULL; p != q->tail; p = p->prev) prev = p; if (prev) - PKTSETLINK(prev, NULL); + prev->prev = NULL; else q->head = NULL; @@ -196,8 +196,8 @@ void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir) q = &pq->q[prec]; p = q->head; while (p) { - q->head = PKTLINK(p); - PKTSETLINK(p, NULL); + q->head = p->prev; + p->prev = NULL; PKTFREE(osh, p, dir); q->len--; pq->len--; @@ -228,17 +228,17 @@ pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir, if (fn == NULL || (*fn) (p, arg)) { bool head = (p == q->head); if (head) - q->head = PKTLINK(p); + q->head = p->prev; else - PKTSETLINK(prev, PKTLINK(p)); - PKTSETLINK(p, NULL); + prev->prev = p->prev; + p->prev = NULL; PKTFREE(osh, p, dir); q->len--; pq->len--; - p = (head ? q->head : PKTLINK(prev)); + p = (head ? q->head : prev->prev); } else { prev = p; - p = PKTLINK(p); + p = p->prev; } } @@ -331,7 +331,7 @@ struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, if (p == NULL) return NULL; - q->head = PKTLINK(p); + q->head = p->prev; if (q->head == NULL) q->tail = NULL; @@ -342,7 +342,7 @@ struct sk_buff *BCMFASTPATH pktq_mdeq(struct pktq *pq, uint prec_bmp, pq->len--; - PKTSETLINK(p, NULL); + p->prev = NULL; return p; } @@ -417,8 +417,8 @@ void prpkt(const char *msg, struct osl_info *osh, struct sk_buff *p0) if (msg && (msg[0] != '\0')) printf("%s:\n", msg); - for (p = p0; p; p = PKTNEXT(p)) - prhex(NULL, PKTDATA(p), PKTLEN(p)); + for (p = p0; p; p = p->next) + prhex(NULL, p->data, p->len); } #endif /* defined(BCMDBG) */ diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index 33d2c9a5a97c..c9dddcdb1099 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -989,15 +989,15 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) if (head == NULL) return NULL; - len = ltoh16(*(u16 *) (PKTDATA(head))); + len = ltoh16(*(u16 *) (head->data)); DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); #if defined(__mips__) if (!len) { - while (!(len = *(u16 *) OSL_UNCACHED(PKTDATA(head)))) + while (!(len = *(u16 *) OSL_UNCACHED(head->data))) udelay(1); - *(u16 *) PKTDATA(head) = htol16((u16) len); + *(u16 *) (head->data) = htol16((u16) len); } #endif /* defined(__mips__) */ @@ -1010,7 +1010,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) if (resid > 0) { tail = head; while ((resid > 0) && (p = _dma_getnextrxp(di, false))) { - PKTSETNEXT(tail, p); + tail->next = p; pkt_len = min(resid, (int)di->rxbufsize); __skb_trim(p, pkt_len); @@ -1115,12 +1115,12 @@ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di) /* Do a cached write instead of uncached write since DMA_MAP * will flush the cache. */ - *(u32 *) (PKTDATA(p)) = 0; + *(u32 *) (p->data) = 0; if (DMASGLIST_ENAB) bzero(&di->rxp_dmah[rxout], sizeof(hnddma_seg_map_t)); - pa = DMA_MAP(di->osh, PKTDATA(p), + pa = DMA_MAP(di->osh, p->data, di->rxbufsize, DMA_RX, p, &di->rxp_dmah[rxout]); ASSERT(IS_ALIGNED(PHYSADDRLO(pa), 4)); @@ -1673,12 +1673,12 @@ static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit) uint nsegs, j; hnddma_seg_map_t *map; - data = PKTDATA(p); - len = PKTLEN(p); + data = p->data; + len = p->len; #ifdef BCM_DMAPAD len += PKTDMAPAD(di->osh, p); #endif - next = PKTNEXT(p); + next = p->next; /* return nonzero if out of tx descriptors */ if (NEXTTXD(txout) == di->txin) @@ -2323,12 +2323,12 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, struct sk_buff *p0, uint nsegs, j; hnddma_seg_map_t *map; - data = PKTDATA(p); - len = PKTLEN(p); + data = p->data; + len = p->len; #ifdef BCM_DMAPAD len += PKTDMAPAD(di->osh, p); #endif /* BCM_DMAPAD */ - next = PKTNEXT(p); + next = p->next; /* return nonzero if out of tx descriptors */ if (NEXTTXD(txout) == di->txin) -- cgit v1.2.3 From 3be727c8f076cafaf26a1ceda4cad85f5166c8a3 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Nov 2010 22:20:30 +0100 Subject: staging: brcm80211: remove some more packet related macros macros PKTHEADROOM and PKTTAILROOM have been replaced by native skbuff functions and macros PKTALLOCED and PKTUNALLOC have been removed. Reviewed-by: Roland Vossen Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 8 ++++---- drivers/staging/brcm80211/include/linux_osl.h | 7 ++----- drivers/staging/brcm80211/sys/wlc_mac80211.c | 8 ++++---- 3 files changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 1d06fb299801..9e96c7e6e3c5 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -932,9 +932,9 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, /* Add alignment padding, allocate new packet if needed */ pad = ((unsigned long)frame % DHD_SDALIGN); if (pad) { - if (PKTHEADROOM(pkt) < pad) { + if (skb_headroom(pkt) < pad) { DHD_INFO(("%s: insufficient headroom %d for %d pad\n", - __func__, (int)PKTHEADROOM(pkt), pad)); + __func__, skb_headroom(pkt), pad)); bus->dhd->tx_realloc++; new = PKTGET(osh, (pkt->len + DHD_SDALIGN), true); if (!new) { @@ -994,7 +994,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, u16 pad = bus->blocksize - (len % bus->blocksize); if ((pad <= bus->roundup) && (pad < bus->blocksize)) #ifdef NOTUSED - if (pad <= PKTTAILROOM(pkt)) + if (pad <= skb_tailroom(pkt)) #endif /* NOTUSED */ len += pad; } else if (len % DHD_SDALIGN) { @@ -1004,7 +1004,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, /* Some controllers have trouble with odd bytes -- round to even */ if (forcealign && (len & (ALIGNMENT - 1))) { #ifdef NOTUSED - if (PKTTAILROOM(pkt)) + if (skb_tailroom(pkt)) #endif len = roundup(len, ALIGNMENT); #ifdef NOTUSED diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 4e446606b5c1..b973f3fea7e2 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -17,6 +17,7 @@ #ifndef _linux_osl_h_ #define _linux_osl_h_ +#include extern struct osl_info *osl_attach(void *pdev, uint bustype); extern void osl_detach(struct osl_info *osh); @@ -248,9 +249,7 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, /* packet primitives */ #define PKTGET(osh, len, send) osl_pktget((osh), (len)) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -#define PKTHEADROOM(skb) ((skb)->data - (skb)->head) -#define PKTTAILROOM(skb) ((skb)->end - (skb)->tail) -#define PKTALLOCED(osh) (((struct osl_pubinfo *)(osh))->pktalloced) + extern void *osl_pktget(struct osl_info *osh, uint len); extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); @@ -281,8 +280,6 @@ osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) #define PKTTONATIVE(osh, pkt) \ osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) #else /* !BRCM_FULLMAC */ -#define PKTUNALLOC(osh) (((struct osl_pubinfo *)(osh))->pktalloced--) - #define PKTSETSKIPCT(osh, skb) #define PKTCLRSKIPCT(osh, skb) #define PKTSKIPCT(osh, skb) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 52e4d95a5cb1..e61aa5a62c45 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -2732,9 +2732,9 @@ uint wlc_down(wlc_info_t *wlc) /* Verify all packets are flushed from the driver */ - if (PKTALLOCED(wlc->osh) != 0) { + if (wlc->osh->pub.pktalloced != 0) { WL_ERROR(("%d packets not freed at wlc_down!!!!!!\n", - PKTALLOCED(wlc->osh))); + wlc->osh->pub.pktalloced)); } #ifdef BCMDBG /* Since all the packets should have been freed, @@ -5123,7 +5123,7 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, prio = (type == FC_TYPE_DATA ? sdu->priority : MAXPRIO); fifo = prio2fifo[prio]; - ASSERT((uint) PKTHEADROOM(sdu) >= TXOFF); + ASSERT((uint) skb_headroom(sdu) >= TXOFF); ASSERT(!(sdu->cloned)); ASSERT(!(sdu->next)); ASSERT(!(sdu->prev)); @@ -6933,7 +6933,7 @@ wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p); WLCNTINCR(wlc->pub->_cnt->ieee_rx); - PKTUNALLOC(osh); + osh->pub.pktalloced--; return; } -- cgit v1.2.3 From c95e66e1fae810110410b59f411110ca671ffb28 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 23 Nov 2010 22:20:31 +0100 Subject: staging: brcm80211: remove unused dhd_ops_virt variable definition The variable dhd_ops_virt was used before although its use was rather limited as can be found in previous commit: | commit 4fd68ae1a558043a2cc4ea2faf7235e71c3241aa | Author: Julia Lawall | Date: Tue Oct 26 12:25:33 2010 +0200 | | drivers/staging/brcm80211/brcmfmac/dhd_linux.c: delete double assignment | Reviewed-by: Roland Vossen Reviewed-by: Brett Rudley Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 2a502f9ab66d..7f66d7a84b6e 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -2251,14 +2251,6 @@ static struct net_device_ops dhd_ops_pri = { .ndo_set_multicast_list = dhd_set_multicast_list }; -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list -}; - int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { dhd_info_t *dhd = (dhd_info_t *) dhdp->info; -- cgit v1.2.3 From fa7a1db200ecb7a5912722a563646935700765a8 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 23 Nov 2010 15:30:02 -0800 Subject: staging: brcm80211: Remove BUSTYPE macro BUSTYPE isn't used in this configuration. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmdefs.h | 1 - drivers/staging/brcm80211/include/nicpci.h | 2 +- drivers/staging/brcm80211/include/siutils.h | 4 +- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 4 +- drivers/staging/brcm80211/phy/wlc_phy_int.h | 2 +- drivers/staging/brcm80211/sys/wl_mac80211.c | 4 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 20 +++++----- drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- drivers/staging/brcm80211/util/aiutils.c | 8 ++-- drivers/staging/brcm80211/util/bcmsrom.c | 12 +++--- drivers/staging/brcm80211/util/hnddma.c | 8 ++-- drivers/staging/brcm80211/util/nicpci.c | 3 +- drivers/staging/brcm80211/util/sbutils.c | 8 ++-- drivers/staging/brcm80211/util/siutils.c | 57 ++++++++++++---------------- 14 files changed, 63 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h index ae6a65a64714..ba1f5e93179b 100644 --- a/drivers/staging/brcm80211/include/bcmdefs.h +++ b/drivers/staging/brcm80211/include/bcmdefs.h @@ -51,7 +51,6 @@ #define SPI_BUS 6 /* gSPI target */ #define RPC_BUS 7 /* RPC target */ -#define BUSTYPE(bus) (bus) #define CHIPTYPE(bus) (bus) #define CHIPID(chip) (chip) #define CHIPREV(rev) (rev) diff --git a/drivers/staging/brcm80211/include/nicpci.h b/drivers/staging/brcm80211/include/nicpci.h index 7ea7daf7c2b6..928818daedd7 100644 --- a/drivers/staging/brcm80211/include/nicpci.h +++ b/drivers/staging/brcm80211/include/nicpci.h @@ -74,6 +74,6 @@ extern bool pcicore_pmecap_fast(struct osl_info *osh); extern void pcicore_pmeen(void *pch); extern void pcicore_pmeclr(void *pch); extern bool pcicore_pmestat(void *pch); -#endif /* defined(BCMSDIO) || (defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS)) */ +#endif /* defined(BCMSDIO)||(defined(BCMBUSTYPE) && (BCMBUSTYPE==SI_BUS)) */ #endif /* _NICPCI_H */ diff --git a/drivers/staging/brcm80211/include/siutils.h b/drivers/staging/brcm80211/include/siutils.h index 0f042799c376..d6115cdd94f6 100644 --- a/drivers/staging/brcm80211/include/siutils.h +++ b/drivers/staging/brcm80211/include/siutils.h @@ -295,9 +295,9 @@ typedef struct si_info { #define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ #define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ -#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ +#define PCI(si) (((si)->pub.bustype == PCI_BUS) && \ ((si)->pub.buscoretype == PCI_CORE_ID)) -#define PCIE(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ +#define PCIE(si) (((si)->pub.bustype == PCI_BUS) && \ ((si)->pub.buscoretype == PCIE_CORE_ID)) #define PCI_FORCEHT(si) \ (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID)) diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index e20c1f09f8bb..87d33dd8e01b 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -300,7 +300,7 @@ void write_radio_reg(phy_info_t *pi, u16 addr, u16 val) W_REG(osh, &pi->regs->phy4wdatalo, val); } - if (BUSTYPE(pi->sh->bustype) == PCI_BUS) { + if (pi->sh->bustype == PCI_BUS) { if (++pi->phy_wreg >= pi->phy_wreg_limit) { (void)R_REG(osh, &pi->regs->maccontrol); pi->phy_wreg = 0; @@ -445,7 +445,7 @@ void write_phy_reg(phy_info_t *pi, u16 addr, u16 val) #else W_REG(osh, (volatile u32 *)(®s->phyregaddr), addr | (val << 16)); - if (BUSTYPE(pi->sh->bustype) == PCI_BUS) { + if (pi->sh->bustype == PCI_BUS) { if (++pi->phy_wreg >= pi->phy_wreg_limit) { pi->phy_wreg = 0; (void)R_REG(osh, ®s->phyversion); diff --git a/drivers/staging/brcm80211/phy/wlc_phy_int.h b/drivers/staging/brcm80211/phy/wlc_phy_int.h index fb92c3bccb16..72eee9120c2f 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_int.h +++ b/drivers/staging/brcm80211/phy/wlc_phy_int.h @@ -1158,7 +1158,7 @@ extern void wlc_phy_table_write_nphy(phy_info_t *pi, u32, u32, u32, (pi->ipa5g_on && CHSPEC_IS5G(pi->radio_chanspec))) #define WLC_PHY_WAR_PR51571(pi) \ - if ((BUSTYPE((pi)->sh->bustype) == PCI_BUS) && NREV_LT((pi)->pubpi.phy_rev, 3)) \ + if (((pi)->sh->bustype == PCI_BUS) && NREV_LT((pi)->pubpi.phy_rev, 3)) \ (void)R_REG((pi)->sh->osh, &(pi)->regs->maccontrol) extern void wlc_phy_cal_perical_nphy_run(phy_info_t *pi, u8 caltype); diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 76f611d3c3ad..7d18d4f269e9 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -1305,8 +1305,8 @@ void wl_free(wl_info_t *wl) * unregister_netdev() calls get_stats() which may read chip registers * so we cannot unmap the chip registers until after calling unregister_netdev() . */ - if (wl->regsva && BUSTYPE(wl->bcm_bustype) != SDIO_BUS && - BUSTYPE(wl->bcm_bustype) != JTAG_BUS) { + if (wl->regsva && wl->bcm_bustype != SDIO_BUS && + wl->bcm_bustype != JTAG_BUS) { iounmap((void *)wl->regsva); } wl->regsva = NULL; diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 264389f788f1..d427980aebed 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -832,7 +832,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, || (wlc_hw->boardflags & BFL_NOPLLDOWN)) wlc_bmac_pllreq(wlc_hw, true, WLC_PLLREQ_SHARED); - if ((BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if ((wlc_hw->sih->bustype == PCI_BUS) && (si_pci_war16165(wlc_hw->sih))) wlc->war16165 = true; @@ -992,7 +992,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, wlc_coredisable(wlc_hw); /* Match driver "down" state */ - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if (wlc_hw->sih->bustype == PCI_BUS) si_pci_down(wlc_hw->sih); /* register sb interrupt callback functions */ @@ -1081,7 +1081,7 @@ int wlc_bmac_detach(wlc_info_t *wlc) */ si_deregister_intr_callback(wlc_hw->sih); - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if (wlc_hw->sih->bustype == PCI_BUS) si_pci_sleep(wlc_hw->sih); } @@ -1207,7 +1207,7 @@ int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw) */ coremask = (1 << wlc_hw->wlc->core->coreidx); - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if (wlc_hw->sih->bustype == PCI_BUS) si_pci_setup(wlc_hw->sih, coremask); ASSERT(si_coreid(wlc_hw->sih) == D11_CORE_ID); @@ -1218,13 +1218,13 @@ int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw) */ if (wlc_bmac_radio_read_hwdisabled(wlc_hw)) { /* put SB PCI in down state again */ - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if (wlc_hw->sih->bustype == PCI_BUS) si_pci_down(wlc_hw->sih); wlc_bmac_xtal(wlc_hw, OFF); return BCME_RADIOOFF; } - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if (wlc_hw->sih->bustype == PCI_BUS) si_pci_up(wlc_hw->sih); /* reset the d11 core */ @@ -1310,7 +1310,7 @@ int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw) /* turn off primary xtal and pll */ if (!wlc_hw->noreset) { - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) + if (wlc_hw->sih->bustype == PCI_BUS) si_pci_down(wlc_hw->sih); wlc_bmac_xtal(wlc_hw, OFF); } @@ -2263,7 +2263,7 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw) si_clkctl_init(wlc_hw->sih); wlc_clkctl_clk(wlc_hw, CLK_FAST); - if (BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) { + if (wlc_hw->sih->bustype == PCI_BUS) { si_pci_fixcfg(wlc_hw->sih); /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */ @@ -4123,8 +4123,8 @@ void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw) /* Only chips with internal bus or PCIE cores or certain PCI cores * are able to switch cores w/o disabling interrupts */ - if (!((BUSTYPE(wlc_hw->sih->bustype) == SI_BUS) || - ((BUSTYPE(wlc_hw->sih->bustype) == PCI_BUS) && + if (!((wlc_hw->sih->bustype == SI_BUS) || + ((wlc_hw->sih->bustype == PCI_BUS) && ((wlc_hw->sih->buscoretype == PCIE_CORE_ID) || (wlc_hw->sih->buscorerev >= 13))))) return; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index e61aa5a62c45..29b6139ae4f0 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -92,7 +92,7 @@ /* To inform the ucode of the last mcast frame posted so that it can clear moredata bit */ #define BCMCFID(wlc, fid) wlc_bmac_write_shm((wlc)->hw, M_BCMC_FID, (fid)) -#define WLC_WAR16165(wlc) (BUSTYPE(wlc->pub->sih->bustype) == PCI_BUS && \ +#define WLC_WAR16165(wlc) (wlc->pub->sih->bustype == PCI_BUS && \ (!AP_ENAB(wlc->pub)) && (wlc->war16165)) /* debug/trace */ diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c index dbb3e369b740..cf900773fa7d 100644 --- a/drivers/staging/brcm80211/util/aiutils.c +++ b/drivers/staging/brcm80211/util/aiutils.c @@ -119,7 +119,7 @@ void ai_scan(si_t *sih, void *regs, uint devid) erombase = R_REG(sii->osh, &cc->eromptr); - switch (BUSTYPE(sih->bustype)) { + switch (sih->bustype) { case SI_BUS: eromptr = (u32 *) REG_MAP(erombase, SI_CORE_SIZE); break; @@ -334,7 +334,7 @@ void *ai_setcoreidx(si_t *sih, uint coreidx) ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn) ((sii)->intr_arg)); - switch (BUSTYPE(sih->bustype)) { + switch (sih->bustype) { case SI_BUS: /* map new one */ if (!sii->regs[coreidx]) { @@ -508,7 +508,7 @@ uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) if (coreidx >= SI_MAXCORES) return 0; - if (BUSTYPE(sih->bustype) == SI_BUS) { + if (sih->bustype == SI_BUS) { /* If internal bus, we can always get at everything */ fast = true; /* map if does not exist */ @@ -518,7 +518,7 @@ uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ASSERT(GOODREGS(sii->regs[coreidx])); } r = (u32 *) ((unsigned char *) sii->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { + } else if (sih->bustype == PCI_BUS) { /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 7240e3c11c5c..af4658e4d67e 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -164,14 +164,14 @@ int srom_var_init(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, len = 0; - ASSERT(bustype == BUSTYPE(bustype)); + ASSERT(bustype == bustype); if (vars == NULL || count == NULL) return 0; *vars = NULL; *count = 0; - switch (BUSTYPE(bustype)) { + switch (bustype) { case SI_BUS: case JTAG_BUS: return initvars_srom_si(sih, osh, curmap, vars, count); @@ -204,7 +204,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, uint i; #endif /* BCMSDIO */ - ASSERT(bustype == BUSTYPE(bustype)); + ASSERT(bustype == bustype); /* check input - 16-bit access only */ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > SROM_MAX) @@ -213,7 +213,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, off = byteoff / 2; nw = nbytes / 2; - if (BUSTYPE(bustype) == PCI_BUS) { + if (bustype == PCI_BUS) { if (!curmap) return 1; @@ -235,7 +235,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, } #endif #ifdef BCMSDIO - } else if (BUSTYPE(bustype) == SDIO_BUS) { + } else if (bustype == SDIO_BUS) { off = byteoff / 2; nw = nbytes / 2; for (i = 0; i < nw; i++) { @@ -244,7 +244,7 @@ srom_read(si_t *sih, uint bustype, void *curmap, struct osl_info *osh, return 1; } #endif /* BCMSDIO */ - } else if (BUSTYPE(bustype) == SI_BUS) { + } else if (bustype == SI_BUS) { return 1; } else { return 1; diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index c9dddcdb1099..3c85aa584d8f 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -2666,8 +2666,8 @@ uint dma_addrwidth(si_t *sih, void *dmaregs) /* backplane are 64-bit capable */ if (si_backplane64(sih)) /* If bus is System Backplane or PCIE then we can access 64-bits */ - if ((BUSTYPE(sih->bustype) == SI_BUS) || - ((BUSTYPE(sih->bustype) == PCI_BUS) && + if ((sih->bustype == SI_BUS) || + ((sih->bustype == PCI_BUS) && (sih->buscoretype == PCIE_CORE_ID))) return DMADDRWIDTH_64; @@ -2681,8 +2681,8 @@ uint dma_addrwidth(si_t *sih, void *dmaregs) dma32regs = (dma32regs_t *) dmaregs; /* For System Backplane, PCIE bus or addrext feature, 32-bits ok */ - if ((BUSTYPE(sih->bustype) == SI_BUS) || - ((BUSTYPE(sih->bustype) == PCI_BUS) + if ((sih->bustype == SI_BUS) || + ((sih->bustype == PCI_BUS) && sih->buscoretype == PCIE_CORE_ID) || (_dma32_addrext(osh, dma32regs))) return DMADDRWIDTH_32; diff --git a/drivers/staging/brcm80211/util/nicpci.c b/drivers/staging/brcm80211/util/nicpci.c index 2127cc903223..1adac0783369 100644 --- a/drivers/staging/brcm80211/util/nicpci.c +++ b/drivers/staging/brcm80211/util/nicpci.c @@ -47,7 +47,8 @@ typedef struct { /* debug/trace */ #define PCI_ERROR(args) -#define PCIE_PUB(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID)) +#define PCIE_PUB(sih) \ + (((sih)->bustype == PCI_BUS) && ((sih)->buscoretype == PCIE_CORE_ID)) /* routines to access mdio slave device registers */ static bool pcie_mdiosetblock(pcicore_info_t *pi, uint blk); diff --git a/drivers/staging/brcm80211/util/sbutils.c b/drivers/staging/brcm80211/util/sbutils.c index 82767e266e97..7b93ac22d4fc 100644 --- a/drivers/staging/brcm80211/util/sbutils.c +++ b/drivers/staging/brcm80211/util/sbutils.c @@ -90,7 +90,7 @@ static u32 _sb_coresba(si_info_t *sii) { u32 sbaddr = 0; - switch (BUSTYPE(sii->pub.bustype)) { + switch (sii->pub.bustype) { case SPI_BUS: case SDIO_BUS: sbaddr = (u32)(unsigned long)sii->curmap; @@ -347,7 +347,7 @@ static void *_sb_setcoreidx(si_info_t *sii, uint coreidx) u32 sbaddr = sii->coresba[coreidx]; void *regs; - switch (BUSTYPE(sii->pub.bustype)) { + switch (sii->pub.bustype) { #ifdef BCMSDIO case SPI_BUS: case SDIO_BUS: @@ -412,8 +412,8 @@ bool sb_taclear(si_t *sih, bool details) sii = SI_INFO(sih); - if ((BUSTYPE(sii->pub.bustype) == SDIO_BUS) || - (BUSTYPE(sii->pub.bustype) == SPI_BUS)) { + if ((sii->pub.bustype == SDIO_BUS) || + (sii->pub.bustype == SPI_BUS)) { INTR_OFF(sii, intr_val); origidx = si_coreidx(sih); diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index e13053626d29..050c2d248978 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -117,12 +117,12 @@ static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, #ifndef BRCM_FULLMAC /* kludge to enable the clock on the 4306 which lacks a slowclock */ - if (BUSTYPE(bustype) == PCI_BUS && !si_ispcie(sii)) + if (bustype == PCI_BUS && !si_ispcie(sii)) si_clkctl_xtal(&sii->pub, XTAL | PLL, ON); #endif #if defined(BCMSDIO) - if (BUSTYPE(bustype) == SDIO_BUS) { + if (bustype == SDIO_BUS) { int err; u8 clkset; @@ -224,7 +224,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", i, cid, crev, sii->coresba[i], sii->regs[i])); - if (BUSTYPE(bustype) == PCI_BUS) { + if (bustype == PCI_BUS) { if (cid == PCI_CORE_ID) { pciidx = i; pcirev = crev; @@ -236,8 +236,8 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, } } #ifdef BCMSDIO - else if (((BUSTYPE(bustype) == SDIO_BUS) || - (BUSTYPE(bustype) == SPI_BUS)) && + else if (((bustype == SDIO_BUS) || + (bustype == SPI_BUS)) && ((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) { sii->pub.buscorerev = crev; sii->pub.buscoretype = cid; @@ -259,7 +259,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, * or downloaded code was * already running. */ - if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { + if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) si_core_disable(&sii->pub, 0); @@ -285,7 +285,7 @@ static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, sii->pub.buscoretype, sii->pub.buscorerev)); /* fixup necessary chip/core configurations */ - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (sii->pub.bustype == PCI_BUS) { if (SI_FAST(sii)) { if (!sii->pch) { sii->pch = (void *)pcicore_init( @@ -312,7 +312,7 @@ static __used void si_nvram_process(si_info_t *sii, char *pvars) uint w = 0; /* get boardtype and boardrev */ - switch (BUSTYPE(sii->pub.bustype)) { + switch (sii->pub.bustype) { case PCI_BUS: /* do a pci config read to get subsystem id and subvendor id */ pci_read_config_dword(sii->osh->pdev, PCI_CFG_SVID, &w); @@ -394,11 +394,6 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, cc = (chipcregs_t *) sii->curmap; sih->bustype = bustype; - if (bustype != BUSTYPE(bustype)) { - SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); - return NULL; - } - /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", @@ -448,7 +443,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, /* Init nvram from sprom/otp if they exist */ if (srom_var_init - (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) { + (&sii->pub, bustype, regs, sii->osh, vars, varsz)) { SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n")); goto exit; } @@ -549,10 +544,6 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, } sih->bustype = bustype; - if (bustype != BUSTYPE(bustype)) { - SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); - return NULL; - } /* bus/core/clk setup for register access */ if (!si_buscore_prep(sii, bustype, devid, sdh)) { @@ -620,7 +611,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, /* Init nvram from sprom/otp if they exist */ if (srom_var_init - (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) { + (&sii->pub, bustype, regs, sii->osh, vars, varsz)) { SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n")); goto exit; } @@ -691,7 +682,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, return sii; exit: - if (BUSTYPE(sih->bustype) == PCI_BUS) { + if (sih->bustype == PCI_BUS) { if (sii->pch) pcicore_deinit(sii->pch); sii->pch = NULL; @@ -715,7 +706,7 @@ void si_detach(si_t *sih) if (sii == NULL) return; - if (BUSTYPE(sih->bustype) == SI_BUS) + if (sih->bustype == SI_BUS) for (idx = 0; idx < SI_MAXCORES; idx++) if (sii->regs[idx]) { REG_UNMAP(sii->regs[idx]); @@ -725,7 +716,7 @@ void si_detach(si_t *sih) #ifndef BRCM_FULLMAC nvram_exit((void *)si_local); /* free up nvram buffers */ - if (BUSTYPE(sih->bustype) == PCI_BUS) { + if (sih->bustype == PCI_BUS) { if (sii->pch) pcicore_deinit(sii->pch); sii->pch = NULL; @@ -1097,7 +1088,7 @@ static uint si_slowclk_src(si_info_t *sii) ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); if (sii->pub.ccrev < 6) { - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { + if (sii->pub.bustype == PCI_BUS) { pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, &val); if (val & PCI_CFG_GPIO_SCS) @@ -1273,7 +1264,7 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on) sii = SI_INFO(sih); - switch (BUSTYPE(sih->bustype)) { + switch (sih->bustype) { #ifdef BCMSDIO case SDIO_BUS: @@ -1384,7 +1375,7 @@ static bool _si_clkctl_cc(si_info_t *sii, uint mode) INTR_OFF(sii, intr_val); origidx = sii->curidx; - if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && + if ((sii->pub.bustype == SI_BUS) && si_setcore(&sii->pub, MIPS33_CORE_ID, 0) && (si_corerev(&sii->pub) <= 7) && (sii->pub.ccrev >= 10)) goto done; @@ -1466,7 +1457,7 @@ int si_devpath(si_t *sih, char *path, int size) if (!path || size <= 0) return -1; - switch (BUSTYPE(sih->bustype)) { + switch (sih->bustype) { case SI_BUS: case JTAG_BUS: slen = snprintf(path, (size_t) size, "sb/%u/", si_coreidx(sih)); @@ -1556,7 +1547,7 @@ static __used bool si_ispcie(si_info_t *sii) { u8 cap_ptr; - if (BUSTYPE(sii->pub.bustype) != PCI_BUS) + if (sii->pub.bustype != PCI_BUS) return false; cap_ptr = @@ -1623,7 +1614,7 @@ void si_pci_up(si_t *sih) sii = SI_INFO(sih); /* if not pci bus, we're done */ - if (BUSTYPE(sih->bustype) != PCI_BUS) + if (sih->bustype != PCI_BUS) return; if (PCI_FORCEHT(sii)) @@ -1652,7 +1643,7 @@ void si_pci_down(si_t *sih) sii = SI_INFO(sih); /* if not pci bus, we're done */ - if (BUSTYPE(sih->bustype) != PCI_BUS) + if (sih->bustype != PCI_BUS) return; /* release FORCEHT since chip is going to "down" state */ @@ -1675,7 +1666,7 @@ void si_pci_setup(si_t *sih, uint coremask) sii = SI_INFO(sih); - if (BUSTYPE(sii->pub.bustype) != PCI_BUS) + if (sii->pub.bustype != PCI_BUS) return; ASSERT(PCI(sii) || PCIE(sii)); @@ -1737,7 +1728,7 @@ int si_pci_fixcfg(si_t *sih) si_info_t *sii = SI_INFO(sih); - ASSERT(BUSTYPE(sii->pub.bustype) == PCI_BUS); + ASSERT(sii->pub.bustype == PCI_BUS); /* Fixup PI in SROM shadow area to enable the correct PCI core access */ /* save the current index */ @@ -1783,7 +1774,7 @@ u32 si_gpiocontrol(si_t *sih, u32 mask, u32 val, u8 priority) * ignore reservation if it's high priority (e.g., test apps) */ if ((priority != GPIO_HI_PRIORITY) && - (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { + (sih->bustype == SI_BUS) && (val || mask)) { mask = priority ? (si_gpioreservation & mask) : ((si_gpioreservation | mask) & ~(si_gpioreservation)); val &= mask; @@ -1935,7 +1926,7 @@ bool si_deviceremoved(si_t *sih) sii = SI_INFO(sih); - switch (BUSTYPE(sih->bustype)) { + switch (sih->bustype) { case PCI_BUS: ASSERT(sii->osh != NULL); pci_read_config_dword(sii->osh->pdev, PCI_CFG_VID, &w); -- cgit v1.2.3 From 8956110dbbb75773d851854e6e11cd8428fce71a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 24 Nov 2010 11:46:09 -0800 Subject: staging: fix intel_sst/intelmid sound build SND_INTELMID selects 3 SND_* kconfig symbols, but that is useless if the SOUND & SND symbols in their hierarchy are not enabled, so make this symbol depend on SOUND & SND. ERROR: "snd_pcm_period_elapsed" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_card_create" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_hw_constraint_integer" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_device_new" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_set_ops" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_jack_new" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_lib_free_pages" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_lib_ioctl" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_lib_malloc_pages" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_ctl_new1" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_lib_preallocate_pages_for_all" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_card_free" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_card_register" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_jack_report" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_pcm_new" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! ERROR: "snd_ctl_add" [drivers/staging/intel_sst/snd-intelmid.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/Kconfig b/drivers/staging/intel_sst/Kconfig index b46bd9d1b324..82391077b384 100644 --- a/drivers/staging/intel_sst/Kconfig +++ b/drivers/staging/intel_sst/Kconfig @@ -8,6 +8,7 @@ config SND_INTEL_SST config SND_INTELMID tristate "Intel MID sound card driver" + depends on SOUND && SND select SND_PCM select SND_SEQUENCER select SND_JACK -- cgit v1.2.3 From 280740a9016db986758db811bbc998acc79e5551 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 26 Nov 2010 20:06:53 +0300 Subject: staging: msm: tvenc: fix error handling Driver init() function should return error code. Also fix tvenc_clk leak. Signed-off-by: Vasiliy Kulikov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/msm/tvenc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c index f41c5ac22f25..4fbb77b253d3 100644 --- a/drivers/staging/msm/tvenc.c +++ b/drivers/staging/msm/tvenc.c @@ -279,12 +279,13 @@ static int __init tvenc_driver_init(void) if (IS_ERR(tvenc_clk)) { printk(KERN_ERR "error: can't get tvenc_clk!\n"); - return IS_ERR(tvenc_clk); + return PTR_ERR(tvenc_clk); } if (IS_ERR(tvdac_clk)) { printk(KERN_ERR "error: can't get tvdac_clk!\n"); - return IS_ERR(tvdac_clk); + clk_put(tvenc_clk); + return PTR_ERR(tvdac_clk); } // pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", -- cgit v1.2.3 From e93192acff4eaf7024c2450d91f3de69258f1f12 Mon Sep 17 00:00:00 2001 From: Al Cho Date: Fri, 26 Nov 2010 19:06:39 +0800 Subject: staging: keucr: fix keucr init coding style fix keucr init.c init.h coding style. only fix coding style check by checkpatch.pl. Signed-off-by: Al Cho Signed-off-by: Greg Kroah-Hartman --- drivers/staging/keucr/init.c | 415 ++++++++++++++++++++++--------------------- drivers/staging/keucr/init.h | 3 + 2 files changed, 217 insertions(+), 201 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c index 978bf87ff13d..e6c56deec94c 100644 --- a/drivers/staging/keucr/init.c +++ b/drivers/staging/keucr/init.c @@ -11,43 +11,37 @@ #include "transport.h" #include "init.h" -BYTE IsSSFDCCompliance; -BYTE IsXDCompliance; -extern DWORD MediaChange; -extern int Check_D_MediaFmt(struct us_data *); +BYTE IsSSFDCCompliance; +BYTE IsXDCompliance; -//----- ENE_InitMedia() ---------------------------------------- +/* + * ENE_InitMedia(): + */ int ENE_InitMedia(struct us_data *us) { int result; BYTE MiscReg03 = 0; - printk("--- Init Media ---\n"); + printk(KERN_INFO "--- Init Media ---\n"); result = ENE_Read_BYTE(us, REG_CARD_STATUS, &MiscReg03); - if (result != USB_STOR_XFER_GOOD) - { - printk("Read register fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Read register fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } - printk("MiscReg03 = %x\n", MiscReg03); + printk(KERN_INFO "MiscReg03 = %x\n", MiscReg03); - if (MiscReg03 & 0x01) - { - if (!us->SD_Status.Ready) - { + if (MiscReg03 & 0x01) { + if (!us->SD_Status.Ready) { result = ENE_SDInit(us); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } } - if (MiscReg03 & 0x02) - { - if (!us->SM_Status.Ready && !us->MS_Status.Ready) - { + if (MiscReg03 & 0x02) { + if (!us->SM_Status.Ready && !us->MS_Status.Ready) { result = ENE_SMInit(us); - if (result != USB_STOR_XFER_GOOD) - { + if (result != USB_STOR_XFER_GOOD) { result = ENE_MSInit(us); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -58,7 +52,9 @@ int ENE_InitMedia(struct us_data *us) return result; } -//----- ENE_Read_BYTE() ---------------------------------------- +/* + * ENE_Read_BYTE() : + */ int ENE_Read_BYTE(struct us_data *us, WORD index, void *buf) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; @@ -76,19 +72,20 @@ int ENE_Read_BYTE(struct us_data *us, WORD index, void *buf) return result; } -//----- ENE_SDInit() --------------------- +/* + * ENE_SDInit(): + */ int ENE_SDInit(struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; BYTE buf[0x200]; - printk("transport --- ENE_SDInit\n"); - // SD Init Part-1 + printk(KERN_INFO "transport --- ENE_SDInit\n"); + /* SD Init Part-1 */ result = ENE_LoadBinCode(us, SD_INIT1_PATTERN); - if (result != USB_STOR_XFER_GOOD) - { - printk("Load SD Init Code Part-1 Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Load SD Init Code Part-1 Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -98,17 +95,15 @@ int ENE_SDInit(struct us_data *us) bcb->CDB[0] = 0xF2; result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0); - if (result != USB_STOR_XFER_GOOD) - { - printk("Exection SD Init Code Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Exection SD Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } - // SD Init Part-2 + /* SD Init Part-2 */ result = ENE_LoadBinCode(us, SD_INIT2_PATTERN); - if (result != USB_STOR_XFER_GOOD) - { - printk("Load SD Init Code Part-2 Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Load SD Init Code Part-2 Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -119,45 +114,41 @@ int ENE_SDInit(struct us_data *us) bcb->CDB[0] = 0xF1; result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0); - if (result != USB_STOR_XFER_GOOD) - { - printk("Exection SD Init Code Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Exection SD Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } us->SD_Status = *(PSD_STATUS)&buf[0]; - if (us->SD_Status.Insert && us->SD_Status.Ready) - { + if (us->SD_Status.Insert && us->SD_Status.Ready) { ENE_ReadSDReg(us, (PBYTE)&buf); - printk("Insert = %x\n", us->SD_Status.Insert); - printk("Ready = %x\n", us->SD_Status.Ready); - printk("IsMMC = %x\n", us->SD_Status.IsMMC); - printk("HiCapacity = %x\n", us->SD_Status.HiCapacity); - printk("HiSpeed = %x\n", us->SD_Status.HiSpeed); - printk("WtP = %x\n", us->SD_Status.WtP); - } - else - { - printk("SD Card Not Ready --- %x\n", buf[0]); + printk(KERN_INFO "Insert = %x\n", us->SD_Status.Insert); + printk(KERN_INFO "Ready = %x\n", us->SD_Status.Ready); + printk(KERN_INFO "IsMMC = %x\n", us->SD_Status.IsMMC); + printk(KERN_INFO "HiCapacity = %x\n", us->SD_Status.HiCapacity); + printk(KERN_INFO "HiSpeed = %x\n", us->SD_Status.HiSpeed); + printk(KERN_INFO "WtP = %x\n", us->SD_Status.WtP); + } else { + printk(KERN_ERR "SD Card Not Ready --- %x\n", buf[0]); return USB_STOR_TRANSPORT_ERROR; } return USB_STOR_TRANSPORT_GOOD; } -//----- ENE_MSInit() ---------------------------------------- +/* + * ENE_MSInit(): + */ int ENE_MSInit(struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; BYTE buf[0x200]; WORD MSP_BlockSize, MSP_UserAreaBlocks; - - printk("transport --- ENE_MSInit\n"); + printk(KERN_INFO "transport --- ENE_MSInit\n"); result = ENE_LoadBinCode(us, MS_INIT_PATTERN); - if (result != USB_STOR_XFER_GOOD) - { - printk("Load MS Init Code Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Load MS Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -169,53 +160,49 @@ int ENE_MSInit(struct us_data *us) bcb->CDB[1] = 0x01; result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0); - if (result != USB_STOR_XFER_GOOD) - { - printk("Exection MS Init Code Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Exection MS Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } us->MS_Status = *(PMS_STATUS)&buf[0]; - if (us->MS_Status.Insert && us->MS_Status.Ready) - { - printk("Insert = %x\n", us->MS_Status.Insert); - printk("Ready = %x\n", us->MS_Status.Ready); - printk("IsMSPro = %x\n", us->MS_Status.IsMSPro); - printk("IsMSPHG = %x\n", us->MS_Status.IsMSPHG); - printk("WtP = %x\n", us->MS_Status.WtP); - if (us->MS_Status.IsMSPro) - { - MSP_BlockSize = (buf[6] <<8) | buf[7]; - MSP_UserAreaBlocks = (buf[10]<<8) | buf[11]; + if (us->MS_Status.Insert && us->MS_Status.Ready) { + printk(KERN_INFO "Insert = %x\n", us->MS_Status.Insert); + printk(KERN_INFO "Ready = %x\n", us->MS_Status.Ready); + printk(KERN_INFO "IsMSPro = %x\n", us->MS_Status.IsMSPro); + printk(KERN_INFO "IsMSPHG = %x\n", us->MS_Status.IsMSPHG); + printk(KERN_INFO "WtP = %x\n", us->MS_Status.WtP); + if (us->MS_Status.IsMSPro) { + MSP_BlockSize = (buf[6] << 8) | buf[7]; + MSP_UserAreaBlocks = (buf[10] << 8) | buf[11]; us->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; - } - else + } else { MS_CardInit(us); - printk("MS Init Code OK !!\n"); - } - else - { - printk("MS Card Not Ready --- %x\n", buf[0]); + } + printk(KERN_INFO "MS Init Code OK !!\n"); + } else { + printk(KERN_INFO "MS Card Not Ready --- %x\n", buf[0]); return USB_STOR_TRANSPORT_ERROR; } return USB_STOR_TRANSPORT_GOOD; } -//----- ENE_SMInit() ---------------------------------------- +/* + *ENE_SMInit() + */ int ENE_SMInit(struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; BYTE buf[0x200]; - printk("transport --- ENE_SMInit\n"); + printk(KERN_INFO "transport --- ENE_SMInit\n"); result = ENE_LoadBinCode(us, SM_INIT_PATTERN); - if (result != USB_STOR_XFER_GOOD) - { - printk("Load SM Init Code Fail !!\n"); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_INFO "Load SM Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -227,9 +214,9 @@ int ENE_SMInit(struct us_data *us) bcb->CDB[1] = 0x01; result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0); - if (result != USB_STOR_XFER_GOOD) - { - printk("Exection SM Init Code Fail !! result = %x\n", result); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR + "Exection SM Init Code Fail !! result = %x\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -238,32 +225,31 @@ int ENE_SMInit(struct us_data *us) us->SM_DeviceID = buf[1]; us->SM_CardID = buf[2]; - if (us->SM_Status.Insert && us->SM_Status.Ready) - { - printk("Insert = %x\n", us->SM_Status.Insert); - printk("Ready = %x\n", us->SM_Status.Ready); - printk("WtP = %x\n", us->SM_Status.WtP); - printk("DeviceID = %x\n", us->SM_DeviceID); - printk("CardID = %x\n", us->SM_CardID); + if (us->SM_Status.Insert && us->SM_Status.Ready) { + printk(KERN_INFO "Insert = %x\n", us->SM_Status.Insert); + printk(KERN_INFO "Ready = %x\n", us->SM_Status.Ready); + printk(KERN_INFO "WtP = %x\n", us->SM_Status.WtP); + printk(KERN_INFO "DeviceID = %x\n", us->SM_DeviceID); + printk(KERN_INFO "CardID = %x\n", us->SM_CardID); MediaChange = 1; Check_D_MediaFmt(us); - } - else - { - printk("SM Card Not Ready --- %x\n", buf[0]); + } else { + printk(KERN_ERR "SM Card Not Ready --- %x\n", buf[0]); return USB_STOR_TRANSPORT_ERROR; } return USB_STOR_TRANSPORT_GOOD; } -//----- ENE_ReadSDReg() ---------------------------------------------- +/* + * ENE_ReadSDReg() + */ int ENE_ReadSDReg(struct us_data *us, u8 *RdBuf) { WORD tmpreg; DWORD reg4b; - - //printk("transport --- ENE_ReadSDReg\n"); + + /* printk(KERN_INFO "transport --- ENE_ReadSDReg\n"); */ reg4b = *(PDWORD)&RdBuf[0x18]; us->SD_READ_BL_LEN = (BYTE)((reg4b >> 8) & 0x0f); @@ -277,74 +263,75 @@ int ENE_ReadSDReg(struct us_data *us, u8 *RdBuf) if (us->SD_Status.HiCapacity && us->SD_Status.IsMMC) us->HC_C_SIZE = *(PDWORD)(&RdBuf[0x100]); - if (us->SD_READ_BL_LEN > SD_BLOCK_LEN) - { - us->SD_Block_Mult = 1 << (us->SD_READ_BL_LEN - SD_BLOCK_LEN); us->SD_READ_BL_LEN = SD_BLOCK_LEN; - } - else - { us->SD_Block_Mult = 1; + if (us->SD_READ_BL_LEN > SD_BLOCK_LEN) { + us->SD_Block_Mult = + 1 << (us->SD_READ_BL_LEN - SD_BLOCK_LEN); + us->SD_READ_BL_LEN = SD_BLOCK_LEN; + } else { + us->SD_Block_Mult = 1; } return USB_STOR_TRANSPORT_GOOD; } -//----- ENE_LoadBinCode() --------------------- +/* + * ENE_LoadBinCode() + */ int ENE_LoadBinCode(struct us_data *us, BYTE flag) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; - //void *buf; + /* void *buf; */ PBYTE buf; - //printk("transport --- ENE_LoadBinCode\n"); + /* printk(KERN_INFO "transport --- ENE_LoadBinCode\n"); */ if (us->BIN_FLAG == flag) return USB_STOR_TRANSPORT_GOOD; buf = kmalloc(0x800, GFP_KERNEL); if (buf == NULL) return USB_STOR_TRANSPORT_ERROR; - switch ( flag ) - { - // For SD - case SD_INIT1_PATTERN: - printk("SD_INIT1_PATTERN\n"); - memcpy(buf, SD_Init1, 0x800); + switch (flag) { + /* For SD */ + case SD_INIT1_PATTERN: + printk(KERN_INFO "SD_INIT1_PATTERN\n"); + memcpy(buf, SD_Init1, 0x800); break; - case SD_INIT2_PATTERN: - printk("SD_INIT2_PATTERN\n"); - memcpy(buf, SD_Init2, 0x800); + case SD_INIT2_PATTERN: + printk(KERN_INFO "SD_INIT2_PATTERN\n"); + memcpy(buf, SD_Init2, 0x800); break; - case SD_RW_PATTERN: - printk("SD_RW_PATTERN\n"); - memcpy(buf, SD_Rdwr, 0x800); + case SD_RW_PATTERN: + printk(KERN_INFO "SD_RW_PATTERN\n"); + memcpy(buf, SD_Rdwr, 0x800); break; - // For MS - case MS_INIT_PATTERN: - printk("MS_INIT_PATTERN\n"); - memcpy(buf, MS_Init, 0x800); + /* For MS */ + case MS_INIT_PATTERN: + printk(KERN_INFO "MS_INIT_PATTERN\n"); + memcpy(buf, MS_Init, 0x800); break; - case MSP_RW_PATTERN: - printk("MSP_RW_PATTERN\n"); - memcpy(buf, MSP_Rdwr, 0x800); + case MSP_RW_PATTERN: + printk(KERN_INFO "MSP_RW_PATTERN\n"); + memcpy(buf, MSP_Rdwr, 0x800); break; - case MS_RW_PATTERN: - printk("MS_RW_PATTERN\n"); - memcpy(buf, MS_Rdwr, 0x800); + case MS_RW_PATTERN: + printk(KERN_INFO "MS_RW_PATTERN\n"); + memcpy(buf, MS_Rdwr, 0x800); break; - // For SS - case SM_INIT_PATTERN: - printk("SM_INIT_PATTERN\n"); - memcpy(buf, SM_Init, 0x800); + /* For SS */ + case SM_INIT_PATTERN: + printk(KERN_INFO "SM_INIT_PATTERN\n"); + memcpy(buf, SM_Init, 0x800); break; - case SM_RW_PATTERN: - printk("SM_RW_PATTERN\n"); - memcpy(buf, SM_Rdwr, 0x800); + case SM_RW_PATTERN: + printk(KERN_INFO "SM_RW_PATTERN\n"); + memcpy(buf, SM_Rdwr, 0x800); break; } memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = 0x800; - bcb->Flags =0x00; + bcb->Flags = 0x00; bcb->CDB[0] = 0xEF; result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0); @@ -354,54 +341,58 @@ int ENE_LoadBinCode(struct us_data *us, BYTE flag) return result; } -//----- ENE_SendScsiCmd() --------------------- +/* + * ENE_SendScsiCmd(): + */ int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; int result; - unsigned int transfer_length=bcb->DataTransferLength, cswlen=0, partial=0; + unsigned int transfer_length = bcb->DataTransferLength, + cswlen = 0, partial = 0; unsigned int residue; - //printk("transport --- ENE_SendScsiCmd\n"); - // send cmd to out endpoint - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL); - if (result != USB_STOR_XFER_GOOD) - { - printk("send cmd to out endpoint fail ---\n"); + /* printk(KERN_INFO "transport --- ENE_SendScsiCmd\n"); */ + /* send cmd to out endpoint */ + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + bcb, US_BULK_CB_WRAP_LEN, NULL); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "send cmd to out endpoint fail ---\n"); return USB_STOR_TRANSPORT_ERROR; } - if (buf) - { - unsigned int pipe = fDir == FDIR_READ ? us->recv_bulk_pipe : us->send_bulk_pipe; - // Bulk + if (buf) { + unsigned int pipe = fDir == + FDIR_READ ? us->recv_bulk_pipe : us->send_bulk_pipe; + /* Bulk */ if (use_sg) result = usb_stor_bulk_srb(us, pipe, us->srb); else - result = usb_stor_bulk_transfer_sg(us, pipe, buf, transfer_length, 0, &partial); - if (result != USB_STOR_XFER_GOOD) - { - printk("data transfer fail ---\n"); + result = usb_stor_bulk_transfer_sg(us, pipe, buf, + transfer_length, 0, &partial); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "data transfer fail ---\n"); return USB_STOR_TRANSPORT_ERROR; } } - // Get CSW for device status - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); + /* Get CSW for device status */ + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, + US_BULK_CS_WRAP_LEN, &cswlen); - if (result == USB_STOR_XFER_SHORT && cswlen == 0) - { - printk("Received 0-length CSW; retrying...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); + if (result == USB_STOR_XFER_SHORT && cswlen == 0) { + printk(KERN_WARNING "Received 0-length CSW; retrying...\n"); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + bcs, US_BULK_CS_WRAP_LEN, &cswlen); } - if (result == USB_STOR_XFER_STALLED) - { + if (result == USB_STOR_XFER_STALLED) { /* get the status again */ - printk("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); + printk(KERN_WARNING "Attempting to get CSW (2nd try)...\n"); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + bcs, US_BULK_CS_WRAP_LEN, NULL); } if (result != USB_STOR_XFER_GOOD) @@ -410,12 +401,14 @@ int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg) /* check bulk status */ residue = le32_to_cpu(bcs->Residue); - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ - if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) - { + /* + * try to compute the actual residue, based on how much data + * was really transferred and what the device tells us + */ + if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { residue = min(residue, transfer_length); - scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), (int) residue)); + scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), + (int) residue)); } if (bcs->Status != US_BULK_STAT_OK) @@ -424,35 +417,40 @@ int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg) return USB_STOR_TRANSPORT_GOOD; } -//----- ENE_Read_Data() --------------------- +/* + * ENE_Read_Data() + */ int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; int result; - //printk("transport --- ENE_Read_Data\n"); - // set up the command wrapper + /* printk(KERN_INFO "transport --- ENE_Read_Data\n"); */ + /* set up the command wrapper */ memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = length; - bcb->Flags =0x80; + bcb->Flags = 0x80; bcb->CDB[0] = 0xED; bcb->CDB[2] = 0xFF; bcb->CDB[3] = 0x81; - // send cmd to out endpoint - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL); + /* send cmd to out endpoint */ + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, + US_BULK_CB_WRAP_LEN, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // R/W data - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, buf, length, NULL); + /* R/W data */ + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + buf, length, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Get CSW for device status - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); + /* Get CSW for device status */ + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, + US_BULK_CS_WRAP_LEN, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (bcs->Status != US_BULK_STAT_OK) @@ -461,35 +459,40 @@ int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length) return USB_STOR_TRANSPORT_GOOD; } -//----- ENE_Write_Data() --------------------- +/* + * ENE_Write_Data(): + */ int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; int result; - //printk("transport --- ENE_Write_Data\n"); - // set up the command wrapper + /* printk("transport --- ENE_Write_Data\n"); */ + /* set up the command wrapper */ memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = length; - bcb->Flags =0x00; + bcb->Flags = 0x00; bcb->CDB[0] = 0xEE; bcb->CDB[2] = 0xFF; bcb->CDB[3] = 0x81; - // send cmd to out endpoint - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL); + /* send cmd to out endpoint */ + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, + US_BULK_CB_WRAP_LEN, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // R/W data - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, buf, length, NULL); + /* R/W data */ + result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + buf, length, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - // Get CSW for device status - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); + /* Get CSW for device status */ + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, + US_BULK_CS_WRAP_LEN, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (bcs->Status != US_BULK_STAT_OK) @@ -498,42 +501,52 @@ int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length) return USB_STOR_TRANSPORT_GOOD; } -//----- usb_stor_print_cmd() --------------------- +/* + * usb_stor_print_cmd(): + */ void usb_stor_print_cmd(struct scsi_cmnd *srb) { PBYTE Cdb = srb->cmnd; DWORD cmd = Cdb[0]; - DWORD bn = ((Cdb[2]<<24) & 0xff000000) | ((Cdb[3]<<16) & 0x00ff0000) | - ((Cdb[4]<< 8) & 0x0000ff00) | ((Cdb[5]<< 0) & 0x000000ff); - WORD blen = ((Cdb[7]<< 8) & 0xff00) | ((Cdb[8]<< 0) & 0x00ff); + DWORD bn = ((Cdb[2] << 24) & 0xff000000) | + ((Cdb[3] << 16) & 0x00ff0000) | + ((Cdb[4] << 8) & 0x0000ff00) | + ((Cdb[5] << 0) & 0x000000ff); + WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff); switch (cmd) { case TEST_UNIT_READY: - //printk("scsi cmd %X --- SCSIOP_TEST_UNIT_READY\n", cmd); + /* printk(KERN_INFO + "scsi cmd %X --- SCSIOP_TEST_UNIT_READY\n", cmd); */ break; case INQUIRY: - printk("scsi cmd %X --- SCSIOP_INQUIRY\n", cmd); + printk(KERN_INFO "scsi cmd %X --- SCSIOP_INQUIRY\n", cmd); break; case MODE_SENSE: - printk("scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd); + printk(KERN_INFO "scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd); break; case START_STOP: - printk("scsi cmd %X --- SCSIOP_START_STOP\n", cmd); + printk(KERN_INFO "scsi cmd %X --- SCSIOP_START_STOP\n", cmd); break; case READ_CAPACITY: - printk("scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd); + printk(KERN_INFO "scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd); break; case READ_10: - //printk("scsi cmd %X --- SCSIOP_READ, bn = %X, blen = %X\n", cmd, bn, blen); + /* printk(KERN_INFO + "scsi cmd %X --- SCSIOP_READ,bn = %X, blen = %X\n" + ,cmd, bn, blen); */ break; case WRITE_10: - //printk("scsi cmd %X --- SCSIOP_WRITE, bn = %X, blen = %X\n", cmd, bn, blen); + /* printk(KERN_INFO + "scsi cmd %X --- SCSIOP_WRITE, + bn = %X, blen = %X\n" , cmd, bn, blen); */ break; case ALLOW_MEDIUM_REMOVAL: - printk("scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd); + printk(KERN_INFO + "scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd); break; default: - printk("scsi cmd %X --- Other cmd\n", cmd); + printk(KERN_INFO "scsi cmd %X --- Other cmd\n", cmd); break; } bn = 0; diff --git a/drivers/staging/keucr/init.h b/drivers/staging/keucr/init.h index cd199fc1e6d5..5223132a6c24 100644 --- a/drivers/staging/keucr/init.h +++ b/drivers/staging/keucr/init.h @@ -1,5 +1,8 @@ #include "common.h" +extern DWORD MediaChange; +extern int Check_D_MediaFmt(struct us_data *); + BYTE SD_Init1[] = { 0x90, 0xFF, 0x09, 0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74, 0x80, 0xF0, 0x90, 0xFF, 0x09, -- cgit v1.2.3 From 6efe04ee4109a9d3fc0d419667f54861628b0d45 Mon Sep 17 00:00:00 2001 From: Al Cho Date: Fri, 26 Nov 2010 19:07:27 +0800 Subject: staging: keucr: fix keucr init other coding style fix keucr init.c other coding style but not from checkpatch.pl. replace ternary conditional "?:" with if/else. Signed-off-by: Al Cho Signed-off-by: Greg Kroah-Hartman --- drivers/staging/keucr/init.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c index e6c56deec94c..515e448852a0 100644 --- a/drivers/staging/keucr/init.c +++ b/drivers/staging/keucr/init.c @@ -364,8 +364,13 @@ int ENE_SendScsiCmd(struct us_data *us, BYTE fDir, void *buf, int use_sg) } if (buf) { - unsigned int pipe = fDir == - FDIR_READ ? us->recv_bulk_pipe : us->send_bulk_pipe; + unsigned int pipe = fDir; + + if (fDir == FDIR_READ) + pipe = us->recv_bulk_pipe; + else + pipe = us->send_bulk_pipe; + /* Bulk */ if (use_sg) result = usb_stor_bulk_srb(us, pipe, us->srb); -- cgit v1.2.3 From e999fb057436c2167d5ee3f5c82753e953981525 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 23 Nov 2010 13:29:28 +0100 Subject: staging: ft1000: Remove functions which create devices in kernel space. Remove exec_mknod() and rm_mknod() helpers which was used for device nodes creating/removing in kernel space. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 93 ------------------------ 1 file changed, 93 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 76cee9e30624..1aec926c993c 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -78,88 +78,6 @@ static struct file_operations ft1000fops = .llseek = no_llseek, }; - - - -//--------------------------------------------------------------------------- -// Function: exec_mknod -// -// Parameters: -// -// Returns: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- -static int exec_mknod (void *pdata) -{ - struct ft1000_info *info; - char mjnum[4]; - char minornum[4]; - char temp[32]; - int retcode; -// int i; //aelias [-] reason : unused variable - char *envp[] = { "HOME=/", "PATH=/usr/bin:/bin", NULL }; - char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL}; - - info = pdata; - DEBUG("ft1000_chdev:exec_mknod is called with major number = %d\n", info->DeviceMajor); - sprintf(temp, "%s%s", "/dev/", info->DeviceName) ; - sprintf(mjnum, "%d", info->DeviceMajor); - sprintf(minornum, "%d", info->CardNumber); - - //char *argv[]={"mknod","-m 666",temp,"c",mjnum,minornum,NULL}; -// char *argv[]={"-m 666",temp,"c",mjnum,minornum,NULL}; - - //for (i=0; i<7;i++) - // DEBUG("argv[%d]=%s\n", i, argv[i]); - - - retcode = call_usermodehelper ("/bin/mknod", argv, envp, 1); - if (retcode) { - DEBUG("ft1000_chdev:exec_mknod failed to make the node: retcode = %d\n", retcode); - } - - - - return retcode; - -} - -//--------------------------------------------------------------------------- -// Function: rm_mknod -// -// Description: This module removes the FT1000 device file -// -//--------------------------------------------------------------------------- -static int rm_mknod (void *pdata) -{ - - struct ft1000_info *info; - //char *argv[4]={"rm", "-f", "/dev/FT1000", NULL}; - int retcode; - char temp[32]; - char *argv[]={"rm", "-f", temp, NULL}; - - info = (struct ft1000_info *)pdata; - DEBUG("ft1000_chdev:rm_mknod is called for device %s\n", info->DeviceName); - sprintf(temp, "%s%s", "/dev/", info->DeviceName) ; - -// char *argv[]={"rm", "-f", temp, NULL}; - - retcode = call_usermodehelper ("/bin/rm", argv, NULL, 1); - if (retcode) { - DEBUG("ft1000_chdev:rm_mknod failed to remove the node: retcode = %d\n", retcode); - } - else - DEBUG("ft1000_chdev:rm_mknod done!\n"); - - - return retcode; - -} //--------------------------------------------------------------------------- // Function: ft1000_get_buffer // @@ -238,15 +156,10 @@ int ft1000_CreateDevice(struct ft1000_device *dev) struct ft1000_info *info = netdev_priv(dev->net); int result; int i; - pid_t pid; // make a new device name sprintf(info->DeviceName, "%s%d", "FT100", info->CardNumber); - // Delete any existing FT1000 node - pid = kernel_thread (rm_mknod,(void *)info, 0); - msleep(1000); - DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt); DEBUG("DeviceCreated = %x\n", info->DeviceCreated); @@ -282,9 +195,6 @@ int ft1000_CreateDevice(struct ft1000_device *dev) DEBUG("ft1000_PcdCreateDevice: device major = %d\n", info->DeviceMajor); } - // Create a thread to call user mode app to mknod - pid = kernel_thread (exec_mknod, (void *)info, 0); - // initialize application information // if (ft1000_flarion_cnt == 0) { @@ -350,7 +260,6 @@ void ft1000_DestroyDevice(struct net_device *dev) { struct ft1000_info *info = netdev_priv(dev); int result = 0; - pid_t pid; int i; struct dpram_blk *pdpram_blk; struct dpram_blk *ptr; @@ -366,8 +275,6 @@ void ft1000_DestroyDevice(struct net_device *dev) DEBUG("ft1000_DestroyDevice: unregistered device \"%s\", result = %d\n", info->DeviceName, result); - pid = kernel_thread (rm_mknod, (void *)info, 0); - // Make sure we free any memory reserve for slow Queue for (i=0; iapp_info[i].app_sqlist) == 0) { -- cgit v1.2.3 From 4960b8fe1b0602195e2170bb94d50edc47d36d73 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 24 Nov 2010 10:42:39 +0100 Subject: staging: ft1000: Fix goto error logic. Fix goto error logic which could lead to kernel panics because kthread_stop() is called in not correct error conditions. Seen it sometimes when dsp_reload() fails then I got kernel panic. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index f88ff86df177..d71ac30629f5 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -204,9 +204,9 @@ static int ft1000_probe(struct usb_interface *interface, return 0; -err_load: - kthread_stop(pft1000info->pPollThread); err_thread: + kthread_stop(pft1000info->pPollThread); +err_load: kfree(pFileStart); err_fw: kfree(ft1000dev); -- cgit v1.2.3 From c6c0ac664c86ff6408fadbed4913938c8a732e26 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 25 Nov 2010 09:44:07 +1100 Subject: driver core: Document that device_rename() is only for networking Document that device_rename() is not to be used by anything other than the network core. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index 46ff6c251932..610d967632cd 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1513,6 +1513,8 @@ EXPORT_SYMBOL_GPL(device_destroy); * exclusion between two different calls of device_rename * on the same device to ensure that new_name is valid and * won't conflict with other devices. + * + * "Never use this function, bad things will happen" - gregkh */ int device_rename(struct device *dev, const char *new_name) { -- cgit v1.2.3 From 70eac33e7ac370dc137cabff7a4ba3094ca25a8c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 30 Nov 2010 14:07:47 +0000 Subject: drm/i915: Move instruction state invalidation from execbuffer to flush Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b12578558268..7fc55a80be20 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -109,6 +109,10 @@ render_ring_flush(struct intel_ring_buffer *ring, if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) cmd |= MI_EXE_FLUSH; + if (invalidate_domains & I915_GEM_DOMAIN_COMMAND && + (IS_G4X(dev) || IS_GEN5(dev))) + cmd |= MI_INVALIDATE_ISP; + #if WATCH_EXEC DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); #endif @@ -583,17 +587,6 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, intel_ring_advance(ring); } - if (IS_G4X(dev) || IS_GEN5(dev)) { - if (intel_ring_begin(ring, 2) == 0) { - intel_ring_emit(ring, MI_FLUSH | - MI_NO_WRITE_FLUSH | - MI_INVALIDATE_ISP ); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } - } - /* XXX breadcrumb */ - return 0; } -- cgit v1.2.3 From c4e7a4146798ce22c229dd21ed31f59f07c4119e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 30 Nov 2010 14:10:25 +0000 Subject: drm/i915/ringbuffer: Handle cliprects in the caller This makes the various rings more consistent by removing the anomalous handing of the rendering ring execbuffer dispatch. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 22 ++++---- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 30 +++++++++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 86 ++++++++++-------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +- 5 files changed, 67 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7960fd63ecb1..9a22da9b2083 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -352,16 +352,16 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) int i915_emit_box(struct drm_device *dev, - struct drm_clip_rect *boxes, - int i, int DR1, int DR4) + struct drm_clip_rect *box, + int DR1, int DR4) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_clip_rect box = boxes[i]; int ret; - if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { + if (box->y2 <= box->y1 || box->x2 <= box->x1 || + box->y2 <= 0 || box->x2 <= 0) { DRM_ERROR("Bad box %d,%d..%d,%d\n", - box.x1, box.y1, box.x2, box.y2); + box->x1, box->y1, box->x2, box->y2); return -EINVAL; } @@ -371,8 +371,8 @@ i915_emit_box(struct drm_device *dev, return ret; OUT_RING(GFX_OP_DRAWRECT_INFO_I965); - OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); - OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); + OUT_RING((box->x1 & 0xffff) | (box->y1 << 16)); + OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16)); OUT_RING(DR4); } else { ret = BEGIN_LP_RING(6); @@ -381,8 +381,8 @@ i915_emit_box(struct drm_device *dev, OUT_RING(GFX_OP_DRAWRECT_INFO); OUT_RING(DR1); - OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); - OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); + OUT_RING((box->x1 & 0xffff) | (box->y1 << 16)); + OUT_RING(((box->x2 - 1) & 0xffff) | ((box->y2 - 1) << 16)); OUT_RING(DR4); OUT_RING(0); } @@ -434,7 +434,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, for (i = 0; i < count; i++) { if (i < nbox) { - ret = i915_emit_box(dev, cliprects, i, + ret = i915_emit_box(dev, &cliprects[i], cmd->DR1, cmd->DR4); if (ret) return ret; @@ -467,7 +467,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, count = nbox ? nbox : 1; for (i = 0; i < count; i++) { if (i < nbox) { - ret = i915_emit_box(dev, cliprects, i, + ret = i915_emit_box(dev, &cliprects[i], batch->DR1, batch->DR4); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e7c4108c94cd..590d8f2d0958 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -966,8 +966,8 @@ extern int i915_driver_device_is_agp(struct drm_device * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); extern int i915_emit_box(struct drm_device *dev, - struct drm_clip_rect *boxes, - int i, int DR1, int DR4); + struct drm_clip_rect *box, + int DR1, int DR4); extern int i915_reset(struct drm_device *dev, u8 flags); extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 66c898c8716d..f57536a70a3a 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -825,6 +825,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; + u32 exec_start, exec_len; int ret, i; if (!i915_gem_check_execbuffer(args)) { @@ -871,6 +872,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (args->num_cliprects != 0) { + if (ring != &dev_priv->render_ring) { + DRM_ERROR("clip rectangles are only valid with the render ring\n"); + return -EINVAL; + } + cliprects = kmalloc(args->num_cliprects * sizeof(*cliprects), GFP_KERNEL); if (cliprects == NULL) { @@ -959,11 +965,25 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - ret = ring->dispatch_execbuffer(ring, - args, cliprects, - batch_obj->gtt_offset); - if (ret) - goto err; + exec_start = batch_obj->gtt_offset + args->batch_start_offset; + exec_len = args->batch_len; + if (cliprects) { + for (i = 0; i < args->num_cliprects; i++) { + ret = i915_emit_box(dev, &cliprects[i], + args->DR1, args->DR4); + if (ret) + goto err; + + ret = ring->dispatch_execbuffer(ring, + exec_start, exec_len); + if (ret) + goto err; + } + } else { + ret = ring->dispatch_execbuffer(ring, exec_start, exec_len); + if (ret) + goto err; + } i915_gem_execbuffer_move_to_active(&objects, ring); i915_gem_execbuffer_retire_commands(dev, file, ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7fc55a80be20..21871b0766e2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -508,25 +508,18 @@ ring_status_page_get_seqno(struct intel_ring_buffer *ring) } static int -ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) +ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) { - uint32_t exec_start; int ret; - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - ret = intel_ring_begin(ring, 2); if (ret) return ret; intel_ring_emit(ring, - MI_BATCH_BUFFER_START | - (2 << 6) | + MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); - intel_ring_emit(ring, exec_start); + intel_ring_emit(ring, offset); intel_ring_advance(ring); return 0; @@ -534,58 +527,40 @@ ring_dispatch_execbuffer(struct intel_ring_buffer *ring, static int render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) + u32 offset, u32 len) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int nbox = exec->num_cliprects; - uint32_t exec_start, exec_len; - int i, count, ret; - - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - exec_len = (uint32_t) exec->batch_len; + int ret; trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1); - count = nbox ? nbox : 1; - for (i = 0; i < count; i++) { - if (i < nbox) { - ret = i915_emit_box(dev, cliprects, i, - exec->DR1, exec->DR4); - if (ret) - return ret; - } + if (IS_I830(dev) || IS_845G(dev)) { + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; - if (IS_I830(dev) || IS_845G(dev)) { - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; + intel_ring_emit(ring, MI_BATCH_BUFFER); + intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); + intel_ring_emit(ring, offset + len - 8); + intel_ring_emit(ring, 0); + } else { + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; - intel_ring_emit(ring, MI_BATCH_BUFFER); - intel_ring_emit(ring, exec_start | MI_BATCH_NON_SECURE); - intel_ring_emit(ring, exec_start + exec_len - 4); - intel_ring_emit(ring, 0); + if (INTEL_INFO(dev)->gen >= 4) { + intel_ring_emit(ring, + MI_BATCH_BUFFER_START | (2 << 6) | + MI_BATCH_NON_SECURE_I965); + intel_ring_emit(ring, offset); } else { - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; - - if (INTEL_INFO(dev)->gen >= 4) { - intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6) - | MI_BATCH_NON_SECURE_I965); - intel_ring_emit(ring, exec_start); - } else { - intel_ring_emit(ring, MI_BATCH_BUFFER_START - | (2 << 6)); - intel_ring_emit(ring, exec_start | - MI_BATCH_NON_SECURE); - } + intel_ring_emit(ring, + MI_BATCH_BUFFER_START | (2 << 6)); + intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); } - intel_ring_advance(ring); } + intel_ring_advance(ring); return 0; } @@ -904,22 +879,17 @@ static void gen6_ring_flush(struct intel_ring_buffer *ring, static int gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) + u32 offset, u32 len) { - uint32_t exec_start; int ret; - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - ret = intel_ring_begin(ring, 2); if (ret) return ret; intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965); /* bit0-7 is the length on GEN6+ */ - intel_ring_emit(ring, exec_start); + intel_ring_emit(ring, offset); intel_ring_advance(ring); return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1747e329ee94..8e3526777926 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -57,9 +57,7 @@ struct intel_ring_buffer { u32 *seqno); u32 (*get_seqno)(struct intel_ring_buffer *ring); int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset); + u32 offset, u32 length); void (*cleanup)(struct intel_ring_buffer *ring); /** -- cgit v1.2.3 From 5b275ce27077d6463ca28c9671dce7c2c1f622e2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 11 Nov 2010 15:27:29 +0000 Subject: thermal: make ops constant And while touching that function definition do something about the disaster of formatting there. Signed-off-by: Alan Cox Acked-by: Zhang Rui Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 17 +++++------------ include/linux/thermal.h | 15 +++++---------- 2 files changed, 10 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 13c72c629329..bde3477c1c6b 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -823,11 +823,8 @@ static struct class thermal_class = { * @devdata: device private data. * @ops: standard thermal cooling devices callbacks. */ -struct thermal_cooling_device *thermal_cooling_device_register(char *type, - void *devdata, - struct - thermal_cooling_device_ops - *ops) +struct thermal_cooling_device *thermal_cooling_device_register( + char *type, void *devdata, const struct thermal_cooling_device_ops *ops) { struct thermal_cooling_device *cdev; struct thermal_zone_device *pos; @@ -1048,13 +1045,9 @@ EXPORT_SYMBOL(thermal_zone_device_update); * section 11.1.5.1 of the ACPI specification 3.0. */ struct thermal_zone_device *thermal_zone_device_register(char *type, - int trips, - void *devdata, struct - thermal_zone_device_ops - *ops, int tc1, int - tc2, - int passive_delay, - int polling_delay) + int trips, void *devdata, + const struct thermal_zone_device_ops *ops, + int tc1, int tc2, int passive_delay, int polling_delay) { struct thermal_zone_device *tz; struct thermal_cooling_device *pos; diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 1de8b9eb841b..06626904daa0 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -77,7 +77,7 @@ struct thermal_cooling_device { char type[THERMAL_NAME_LENGTH]; struct device device; void *devdata; - struct thermal_cooling_device_ops *ops; + const struct thermal_cooling_device_ops *ops; struct list_head node; }; @@ -114,7 +114,7 @@ struct thermal_zone_device { int last_temperature; bool passive; unsigned int forced_passive; - struct thermal_zone_device_ops *ops; + const struct thermal_zone_device_ops *ops; struct list_head cooling_devices; struct idr idr; struct mutex lock; /* protect cooling devices list */ @@ -129,11 +129,8 @@ struct thermal_zone_device { }; struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, - struct - thermal_zone_device_ops - *, int tc1, int tc2, - int passive_freq, - int polling_freq); + const struct thermal_zone_device_ops *, int tc1, int tc2, + int passive_freq, int polling_freq); void thermal_zone_device_unregister(struct thermal_zone_device *); int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, @@ -142,9 +139,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, struct thermal_cooling_device *); void thermal_zone_device_update(struct thermal_zone_device *); struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, - struct - thermal_cooling_device_ops - *); + const struct thermal_cooling_device_ops *); void thermal_cooling_device_unregister(struct thermal_cooling_device *); #endif /* __THERMAL_H__ */ -- cgit v1.2.3 From 257e48f1474a1f5bfa6fcafb12f77a8479063293 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Nov 2010 16:19:24 +0000 Subject: drm/i915/lvds: Disable panel-fitter on gen4 for 1:1 scale factors Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4324a326f98e..5b88e145ee79 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -269,14 +269,13 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; - pfit_control |= PFIT_ENABLE; /* 965+ is easy, it does everything in hw */ if (scaled_width > scaled_height) - pfit_control |= PFIT_SCALING_PILLAR; + pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR; else if (scaled_width < scaled_height) - pfit_control |= PFIT_SCALING_LETTER; - else - pfit_control |= PFIT_SCALING_AUTO; + pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER; + else if (adjusted_mode->hdisplay != mode->hdisplay) + pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; } else { u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; @@ -323,13 +322,17 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * Full scaling, even if it changes the aspect ratio. * Fortunately this is all done for us in hw. */ - pfit_control |= PFIT_ENABLE; - if (INTEL_INFO(dev)->gen >= 4) - pfit_control |= PFIT_SCALING_AUTO; - else - pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); + if (mode->vdisplay != adjusted_mode->vdisplay || + mode->hdisplay != adjusted_mode->hdisplay) { + pfit_control |= PFIT_ENABLE; + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= PFIT_SCALING_AUTO; + else + pfit_control |= (VERT_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_AUTO_SCALE | + HORIZ_INTERP_BILINEAR); + } break; default: -- cgit v1.2.3 From ac5435b9800f313bdcd6a43444ceb1d89f241a5e Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 22:59:56 +0200 Subject: Staging: w35und: Remove unused defines from sysdef.h This patch removes all the defines in sysdef.h that are not used at all. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/sysdef.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h index 9195adf98e14..7198708108bb 100644 --- a/drivers/staging/winbond/sysdef.h +++ b/drivers/staging/winbond/sysdef.h @@ -2,17 +2,11 @@ #ifndef SYS_DEF_H #define SYS_DEF_H -#define WB_LINUX -#define WB_LINUX_WPA_PSK #define _USE_FALLBACK_RATE_ #define _WPA2_ -#ifndef _WPA_PSK_DEBUG -#undef _WPA_PSK_DEBUG -#endif - /* debug print options, mark what debug you don't need */ #ifdef FULL_DEBUG -- cgit v1.2.3 From 1140bd9f30f4d6dac6b53365a70819ecd4cc8c54 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 22:59:57 +0200 Subject: Staging: w35und: Kill _USE_FALLBACK_RATE_ macro The _USE_FALLBACK_RATE_ macro parametrizes DEFAULT_RATE_RETRY_LIMIT. It's only used in Mxx_initial() in reg.c where _USE_FALLBACK_RATE_ is always defined because the reg.c file includes sysdef.h at the top. It's therefore safe to remove the _USE_FALLBACK_RATE_ macro. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/sysdef.h | 2 -- drivers/staging/winbond/wb35reg_s.h | 4 ---- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h index 7198708108bb..f8d8606a4efa 100644 --- a/drivers/staging/winbond/sysdef.h +++ b/drivers/staging/winbond/sysdef.h @@ -3,8 +3,6 @@ #ifndef SYS_DEF_H #define SYS_DEF_H -#define _USE_FALLBACK_RATE_ - #define _WPA2_ /* debug print options, mark what debug you don't need */ diff --git a/drivers/staging/winbond/wb35reg_s.h b/drivers/staging/winbond/wb35reg_s.h index 9d5993bfc1f4..9b782ededf43 100644 --- a/drivers/staging/winbond/wb35reg_s.h +++ b/drivers/staging/winbond/wb35reg_s.h @@ -51,11 +51,7 @@ struct hw_data; #define DEFAULT_CWMAX 1023 /* (M2C) CWmax. Its value is in the range 0-1023. */ #define DEFAULT_AID 1 /* (M34) AID. Its value is in the range 1-2007. */ -#ifdef _USE_FALLBACK_RATE_ #define DEFAULT_RATE_RETRY_LIMIT 2 /* (M38) as named */ -#else -#define DEFAULT_RATE_RETRY_LIMIT 7 /* (M38) as named */ -#endif #define DEFAULT_LONG_RETRY_LIMIT 7 /* (M38) LongRetryLimit. Its value is in the range 0-15. */ #define DEFAULT_SHORT_RETRY_LIMIT 7 /* (M38) ShortRetryLimit. Its value is in the range 0-15. */ -- cgit v1.2.3 From c84fa49f61798b6248cef56876f1643db3b7b2f3 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 22:59:58 +0200 Subject: Staging: w35und: Kill WPA2 definitions The _WPA2_ macro is always defined but the data structures that are wrapped by it are never used. Kill them. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mac_structures.h | 46 -------------------------------- drivers/staging/winbond/sysdef.h | 2 -- 2 files changed, 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/mac_structures.h b/drivers/staging/winbond/mac_structures.h index ed3df2964065..91c550e94d87 100644 --- a/drivers/staging/winbond/mac_structures.h +++ b/drivers/staging/winbond/mac_structures.h @@ -111,9 +111,6 @@ /* -- WPA -- */ #define ELEMENT_ID_RSN_WPA 221 -#ifdef _WPA2_ -#define ELEMENT_ID_RSN_WPA2 48 -#endif /* endif WPA2 */ #define WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT ((u16) 6) #define WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT ((u16) 2) @@ -367,21 +364,11 @@ struct Extended_Supported_Rates_Element { /* WPA(802.11i draft 3.0) */ #define VERSION_WPA 1 -#ifdef _WPA2_ -#define VERSION_WPA2 1 -#endif /* end def _WPA2_ */ /* WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type */ #define OUI_WPA 0x00F25000 -#ifdef _WPA2_ -/* for wpa2 change to 0x00ACOF04 by Ws 26/04/04 */ -#define OUI_WPA2 0x00AC0F00 -#endif /* end def _WPA2_ */ #define OUI_WPA_ADDITIONAL 0x01 #define WLAN_MIN_RSN_WPA_LENGTH 6 /* added by ws 09/10/04 */ -#ifdef _WPA2_ -#define WLAN_MIN_RSN_WPA2_LENGTH 2 /* Fix to 2 09/14/05 */ -#endif /* end def _WPA2_ */ #define oui_wpa (u32)(OUI_WPA|OUI_WPA_ADDITIONAL) @@ -390,12 +377,6 @@ struct Extended_Supported_Rates_Element { /* 20061108 For WPS. It's little endian. Big endian is 0x0050F204 */ #define WPA_WPS_OUI cpu_to_le32(0x04F25000) -/* -----WPA2----- */ -#ifdef _WPA2_ -#define WPA2_OUI_BIG ((u32)0x01AC0F00) -#define WPA2_OUI_LITTLE ((u32)0x01AC0F01) -#endif /* end def _WPA2_ */ - /* Authentication suite */ #define OUI_AUTH_WPA_NONE 0x00 /* for WPA_NONE */ #define OUI_AUTH_8021X 0x01 @@ -460,33 +441,6 @@ struct RSN_Capability_Element { } __attribute__ ((packed)) ; } __attribute__ ((packed)) ; -#ifdef _WPA2_ -struct pmkid { - u8 pValue[16]; -}; - -struct WPA2_RSN_Information_Element { - u8 Element_ID; - u8 Length; - u16 Version; - struct suite_selector GroupKeySuite; - u16 PairwiseKeySuiteCount; - struct suite_selector PairwiseKeySuite[1]; - -} __attribute__ ((packed)); - -struct WPA2_RSN_Auth_Sub_Information_Element { - u16 AuthKeyMngtSuiteCount; - struct suite_selector AuthKeyMngtSuite[1]; -} __attribute__ ((packed)); - - -struct PMKID_Information_Element { - u16 PMKID_Count; - struct pmkid pmkid[16]; -} __attribute__ ((packed)); - -#endif /* enddef _WPA2_ */ /*============================================================ // MAC Frame structure (different type) and subfield structure //============================================================*/ diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h index f8d8606a4efa..8d4ebe15d930 100644 --- a/drivers/staging/winbond/sysdef.h +++ b/drivers/staging/winbond/sysdef.h @@ -3,8 +3,6 @@ #ifndef SYS_DEF_H #define SYS_DEF_H -#define _WPA2_ - /* debug print options, mark what debug you don't need */ #ifdef FULL_DEBUG -- cgit v1.2.3 From a4170e3dddc5eb88d23dd5f6e7c9cdefc244001e Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 22:59:59 +0200 Subject: Staging: w35und: Kill unused code in mac_structures.h This patch kills tons of unused macros and struct definitions from mac_structures.h. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mac_structures.h | 499 ------------------------------- 1 file changed, 499 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/mac_structures.h b/drivers/staging/winbond/mac_structures.h index 91c550e94d87..76c63c74d50c 100644 --- a/drivers/staging/winbond/mac_structures.h +++ b/drivers/staging/winbond/mac_structures.h @@ -21,23 +21,11 @@ #ifndef _MAC_Structures_H_ #define _MAC_Structures_H_ -#include - -/*========================================================= -// Some miscellaneous definitions -//-----*/ -#define MAX_CHANNELS 30 #define MAC_ADDR_LENGTH 6 -#define MAX_WEP_KEY_SIZE 16 /* 128 bits */ -#define MAX_802_11_FRAGMENT_NUMBER 10 /* By spec */ /* ======================================================== // 802.11 Frame define //----- */ -#define MASK_PROTOCOL_VERSION_TYPE 0x0F -#define MASK_FRAGMENT_NUMBER 0x000F -#define SEQUENCE_NUMBER_SHIFT 4 -#define DIFFER_11_TO_3 18 #define DOT_11_MAC_HEADER_SIZE 24 #define DOT_11_SNAP_SIZE 6 #define DOT_11_DURATION_OFFSET 2 @@ -47,15 +35,9 @@ #define DOT_11_TYPE_OFFSET 30 #define DOT_11_DATA_OFFSET 24 #define DOT_11_DA_OFFSET 4 -#define DOT_3_TYPE_ARP 0x80F3 -#define DOT_3_TYPE_IPX 0x8137 -#define DOT_3_TYPE_OFFSET 12 - -#define ETHERNET_HEADER_SIZE 14 #define MAX_ETHERNET_PACKET_SIZE 1514 - /* ----- management : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) */ #define MAC_SUBTYPE_MNGMNT_ASSOC_REQUEST 0x00 #define MAC_SUBTYPE_MNGMNT_ASSOC_RESPONSE 0x10 @@ -69,126 +51,6 @@ #define MAC_SUBTYPE_MNGMNT_AUTHENTICATION 0xB0 #define MAC_SUBTYPE_MNGMNT_DEAUTHENTICATION 0xC0 -/* ----- control : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) */ -#define MAC_SUBTYPE_CONTROL_PSPOLL 0xA4 -#define MAC_SUBTYPE_CONTROL_RTS 0xB4 -#define MAC_SUBTYPE_CONTROL_CTS 0xC4 -#define MAC_SUBTYPE_CONTROL_ACK 0xD4 -#define MAC_SUBTYPE_CONTROL_CFEND 0xE4 -#define MAC_SUBTYPE_CONTROL_CFEND_CFACK 0xF4 - -/* ----- data : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) */ -#define MAC_SUBTYPE_DATA 0x08 -#define MAC_SUBTYPE_DATA_CFACK 0x18 -#define MAC_SUBTYPE_DATA_CFPOLL 0x28 -#define MAC_SUBTYPE_DATA_CFACK_CFPOLL 0x38 -#define MAC_SUBTYPE_DATA_NULL 0x48 -#define MAC_SUBTYPE_DATA_CFACK_NULL 0x58 -#define MAC_SUBTYPE_DATA_CFPOLL_NULL 0x68 -#define MAC_SUBTYPE_DATA_CFACK_CFPOLL_NULL 0x78 - -/* ----- Frame Type of Bits (2, 3) */ -#define MAC_TYPE_MANAGEMENT 0x00 -#define MAC_TYPE_CONTROL 0x04 -#define MAC_TYPE_DATA 0x08 - -/* ----- definitions for Management Frame Element ID (1 BYTE) */ -#define ELEMENT_ID_SSID 0 -#define ELEMENT_ID_SUPPORTED_RATES 1 -#define ELEMENT_ID_FH_PARAMETER_SET 2 -#define ELEMENT_ID_DS_PARAMETER_SET 3 -#define ELEMENT_ID_CF_PARAMETER_SET 4 -#define ELEMENT_ID_TIM 5 -#define ELEMENT_ID_IBSS_PARAMETER_SET 6 -/* 7~15 reserverd */ -#define ELEMENT_ID_CHALLENGE_TEXT 16 -/* 17~31 reserved for challenge text extension */ -/* 32~255 reserved */ -/*-- 11G -- */ -#define ELEMENT_ID_ERP_INFORMATION 42 -#define ELEMENT_ID_EXTENDED_SUPPORTED_RATES 50 - -/* -- WPA -- */ - -#define ELEMENT_ID_RSN_WPA 221 - -#define WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT ((u16) 6) -#define WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT ((u16) 2) - -/* =================================================================== -* Reason Code (Table 18): indicate the reason of DisAssoc, DeAuthen -* length of ReasonCode is 2 Octs. -* =================================================================== */ -#define REASON_REASERED 0 -#define REASON_UNSPECIDIED 1 -#define REASON_PREAUTH_INVALID 2 -#define DEAUTH_REASON_LEFT_BSS 3 -#define DISASS_REASON_AP_INACTIVE 4 -#define DISASS_REASON_AP_BUSY 5 -#define REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 -#define REASON_CLASS3_FRAME_FROM_NONASSO_STA 7 -#define DISASS_REASON_LEFT_BSS 8 -#define REASON_NOT_AUTH_YET 9 -/* 802.11i define */ -#define REASON_INVALID_IE 13 -#define REASON_MIC_ERROR 14 -#define REASON_4WAY_HANDSHAKE_TIMEOUT 15 -#define REASON_GROUPKEY_UPDATE_TIMEOUT 16 -#define REASON_IE_DIFF_4WAY_ASSOC 17 -#define REASON_INVALID_MULTICAST_CIPHER 18 -#define REASON_INVALID_UNICAST_CIPHER 19 -#define REASON_INVALID_AKMP 20 -#define REASON_UNSUPPORTED_RSNIE_VERSION 21 -#define REASON_INVALID_RSNIE_CAPABILITY 22 -#define REASON_802_1X_AUTH_FAIL 23 -#define REASON_CIPHER_REJECT_PER_SEC_POLICY 14 - -/* -//=========================================================== -// enum_MMPDUResultCode -- -// Status code (2 Octs) in the MMPDU's frame body. Table.19 -// -//=========================================================== -enum enum_MMPDUResultCode -{ -// SUCCESS = 0, // Redefined - UNSPECIFIED_FAILURE = 1, - - // 2 - 9 Reserved - - NOT_SUPPROT_CAPABILITIES = 10, - - //REASSOCIATION_DENIED - // - REASSOC_DENIED_UNABLE_CFM_ASSOC_EXIST = 11, - - //ASSOCIATION_DENIED_NOT_IN_STANDARD - // - ASSOC_DENIED_REASON_NOT_IN_STANDARD = 12, - PEER_NOT_SUPPORT_AUTH_ALGORITHM = 13, - AUTH_SEQNUM_OUT_OF_EXPECT = 14, - AUTH_REJECT_REASON_CHALLENGE_FAIL = 15, - AUTH_REJECT_REASON_WAIT_TIMEOUT = 16, - ASSOC_DENIED_REASON_AP_BUSY = 17, - ASSOC_DENIED_REASON_NOT_SUPPORT_BASIC_RATE = 18 -} WB_MMPDURESULTCODE, *PWB_MMPDURESULTCODE; -*/ - -#define RATE_BITMAP_1M 1 -#define RATE_BITMAP_2M 2 -#define RATE_BITMAP_5dot5M 5 -#define RATE_BITMAP_6M 6 -#define RATE_BITMAP_9M 9 -#define RATE_BITMAP_11M 11 -#define RATE_BITMAP_12M 12 -#define RATE_BITMAP_18M 18 -#define RATE_BITMAP_22M 22 -#define RATE_BITMAP_24M 24 -#define RATE_BITMAP_33M 17 -#define RATE_BITMAP_36M 19 -#define RATE_BITMAP_48M 25 -#define RATE_BITMAP_54M 28 - #define RATE_AUTO 0 #define RATE_1M 2 #define RATE_2M 4 @@ -206,365 +68,4 @@ enum enum_MMPDUResultCode #define RATE_54M 108 #define RATE_MAX 255 -/* CAPABILITY */ -#define CAPABILITY_ESS_BIT 0x0001 -#define CAPABILITY_IBSS_BIT 0x0002 -#define CAPABILITY_CF_POLL_BIT 0x0004 -#define CAPABILITY_CF_POLL_REQ_BIT 0x0008 -#define CAPABILITY_PRIVACY_BIT 0x0010 -#define CAPABILITY_SHORT_PREAMBLE_BIT 0x0020 -#define CAPABILITY_PBCC_BIT 0x0040 -#define CAPABILITY_CHAN_AGILITY_BIT 0x0080 -#define CAPABILITY_SHORT_SLOT_TIME_BIT 0x0400 -#define CAPABILITY_DSSS_OFDM_BIT 0x2000 - - -struct Capability_Information_Element { - union { - u16 __attribute__ ((packed)) wValue; - #ifdef _BIG_ENDIAN_ /* 20060926 add by anson's endian */ - struct _Capability { - /* -- 11G -- */ - u8 Reserved3:2; - u8 DSSS_OFDM:1; - u8 Reserved2:2; - u8 Short_Slot_Time:1; - u8 Reserved1:2; - u8 Channel_Agility:1; - u8 PBCC:1; - u8 ShortPreamble:1; - u8 CF_Privacy:1; - u8 CF_Poll_Request:1; - u8 CF_Pollable:1; - u8 IBSS:1; - u8 ESS:1; - } __attribute__ ((packed)) Capability; - #else - struct _Capability { - u8 ESS:1; - u8 IBSS:1; - u8 CF_Pollable:1; - u8 CF_Poll_Request:1; - u8 CF_Privacy:1; - u8 ShortPreamble:1; - u8 PBCC:1; - u8 Channel_Agility:1; - u8 Reserved1:2; - /* -- 11G -- */ - u8 Short_Slot_Time:1; - u8 Reserved2:2; - u8 DSSS_OFDM:1; - u8 Reserved3:2; - } __attribute__ ((packed)) Capability; - #endif - } __attribute__ ((packed)) ; -} __attribute__ ((packed)); - -struct FH_Parameter_Set_Element { - u8 Element_ID; - u8 Length; - u8 Dwell_Time[2]; - u8 Hop_Set; - u8 Hop_Pattern; - u8 Hop_Index; -}; - -struct DS_Parameter_Set_Element { - u8 Element_ID; - u8 Length; - u8 Current_Channel; -}; - -struct Supported_Rates_Element { - u8 Element_ID; - u8 Length; - u8 SupportedRates[8]; -} __attribute__ ((packed)); - -struct SSID_Element { - u8 Element_ID; - u8 Length; - u8 SSID[32]; -} __attribute__ ((packed)) ; - -struct CF_Parameter_Set_Element { - u8 Element_ID; - u8 Length; - u8 CFP_Count; - u8 CFP_Period; - u8 CFP_MaxDuration[2]; /* in Time Units */ - u8 CFP_DurRemaining[2]; /* in time units */ -}; - -struct TIM_Element { - u8 Element_ID; - u8 Length; - u8 DTIM_Count; - u8 DTIM_Period; - u8 Bitmap_Control; - u8 Partial_Virtual_Bitmap[251]; -}; - -struct IBSS_Parameter_Set_Element { - u8 Element_ID; - u8 Length; - u8 ATIM_Window[2]; -}; - -struct Challenge_Text_Element { - u8 Element_ID; - u8 Length; - u8 Challenge_Text[253]; -}; - -struct PHY_Parameter_Set_Element { -/* int aSlotTime; */ -/* int aSifsTime; */ - s32 aCCATime; - s32 aRxTxTurnaroundTime; - s32 aTxPLCPDelay; - s32 RxPLCPDelay; - s32 aRxTxSwitchTime; - s32 aTxRampOntime; - s32 aTxRampOffTime; - s32 aTxRFDelay; - s32 aRxRFDelay; - s32 aAirPropagationTime; - s32 aMACProcessingDelay; - s32 aPreambleLength; - s32 aPLCPHeaderLength; - s32 aMPDUDurationFactor; - s32 aMPDUMaxLength; -/* int aCWmin; */ -/* int aCWmax; */ -}; - -/* -- 11G -- */ -struct ERP_Information_Element { - u8 Element_ID; - u8 Length; - #ifdef _BIG_ENDIAN_ /* 20060926 add by anson's endian */ - u8 Reserved:5; /* 20060926 add by anson */ - u8 Barker_Preamble_Mode:1; - u8 Use_Protection:1; - u8 NonERP_Present:1; - #else - u8 NonERP_Present:1; - u8 Use_Protection:1; - u8 Barker_Preamble_Mode:1; - u8 Reserved:5; - #endif -}; - -struct Extended_Supported_Rates_Element { - u8 Element_ID; - u8 Length; - u8 ExtendedSupportedRates[255]; -} __attribute__ ((packed)); - -/* WPA(802.11i draft 3.0) */ -#define VERSION_WPA 1 -/* WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type */ -#define OUI_WPA 0x00F25000 - -#define OUI_WPA_ADDITIONAL 0x01 -#define WLAN_MIN_RSN_WPA_LENGTH 6 /* added by ws 09/10/04 */ - -#define oui_wpa (u32)(OUI_WPA|OUI_WPA_ADDITIONAL) - -#define WPA_OUI_BIG ((u32) 0x01F25000)/* added by ws 09/23/04 */ -#define WPA_OUI_LITTLE ((u32) 0x01F25001)/* added by ws 09/23/04 */ -/* 20061108 For WPS. It's little endian. Big endian is 0x0050F204 */ -#define WPA_WPS_OUI cpu_to_le32(0x04F25000) - -/* Authentication suite */ -#define OUI_AUTH_WPA_NONE 0x00 /* for WPA_NONE */ -#define OUI_AUTH_8021X 0x01 -#define OUI_AUTH_PSK 0x02 -/* Cipher suite */ -#define OUI_CIPHER_GROUP_KEY 0x00 /* added by ws 05/21/04 */ -#define OUI_CIPHER_WEP_40 0x01 -#define OUI_CIPHER_TKIP 0x02 -#define OUI_CIPHER_CCMP 0x04 -#define OUI_CIPHER_WEP_104 0x05 - -struct suite_selector{ - union{ - u8 Value[4]; - struct _SUIT_ { - u8 OUI[3]; - u8 Type; - } SuitSelector; - }; -}; - -/* -- WPA -- */ -struct RSN_Information_Element{ - u8 Element_ID; - u8 Length; - /* WPA version 2.0 additional field, and should be 00:50:F2:01 */ - struct suite_selector OuiWPAAdditional; - u16 Version; - struct suite_selector GroupKeySuite; - u16 PairwiseKeySuiteCount; - struct suite_selector PairwiseKeySuite[1]; -} __attribute__ ((packed)); -struct RSN_Auth_Sub_Information_Element { - u16 AuthKeyMngtSuiteCount; - struct suite_selector AuthKeyMngtSuite[1]; -} __attribute__ ((packed)); - -/* -- WPA2 -- */ -struct RSN_Capability_Element { - union { - u16 __attribute__ ((packed)) wValue; - #ifdef _BIG_ENDIAN_ /* 20060927 add by anson's endian */ - struct _RSN_Capability { - u16 __attribute__ ((packed)) Reserved2:8; /* 20051201 */ - u16 __attribute__ ((packed)) Reserved1:2; - u16 __attribute__ ((packed)) GTK_Replay_Counter:2; - u16 __attribute__ ((packed)) PTK_Replay_Counter:2; - u16 __attribute__ ((packed)) No_Pairwise:1; - u16 __attribute__ ((packed)) Pre_Auth:1; - } __attribute__ ((packed)) RSN_Capability; - #else - struct _RSN_Capability { - u16 __attribute__ ((packed)) Pre_Auth:1; - u16 __attribute__ ((packed)) No_Pairwise:1; - u16 __attribute__ ((packed)) PTK_Replay_Counter:2; - u16 __attribute__ ((packed)) GTK_Replay_Counter:2; - u16 __attribute__ ((packed)) Reserved1:2; - u16 __attribute__ ((packed)) Reserved2:8; /* 20051201 */ - } __attribute__ ((packed)) RSN_Capability; - #endif - - } __attribute__ ((packed)) ; -} __attribute__ ((packed)) ; - -/*============================================================ -// MAC Frame structure (different type) and subfield structure -//============================================================*/ -struct MAC_frame_control { -/* a combination of the [Protocol Version, Control Type, Control Subtype]*/ - u8 mac_frame_info; -/* 20060927 add by anson's endian */ - #ifdef _BIG_ENDIAN_ - u8 order:1; - u8 WEP:1; - u8 more_data:1; - u8 pwr_mgt:1; - u8 retry:1; - u8 more_frag:1; - u8 from_ds:1; - u8 to_ds:1; - #else - u8 to_ds:1; - u8 from_ds:1; - u8 more_frag:1; - u8 retry:1; - u8 pwr_mgt:1; - u8 more_data:1; - u8 WEP:1; - u8 order:1; - #endif -} __attribute__ ((packed)); - -struct Management_Frame { -/* 2B, ToDS,FromDS,MoreFrag,MoreData,Order=0 */ - struct MAC_frame_control frame_control; - u16 duration; - u8 DA[MAC_ADDR_LENGTH]; /* Addr1 */ - u8 SA[MAC_ADDR_LENGTH]; /* Addr2 */ - u8 BSSID[MAC_ADDR_LENGTH]; /* Addr3 */ - u16 Sequence_Control; - /* Management Frame Body <= 325 bytes */ - /* FCS 4 bytes */ -} __attribute__ ((packed)); - -/* SW-MAC don't Tx/Rx Control-Frame, HW-MAC do it. */ -struct Control_Frame { -/* ToDS,FromDS,MoreFrag,Retry,MoreData,WEP,Order=0 */ - struct MAC_frame_control frame_control; - u16 duration; - u8 RA[MAC_ADDR_LENGTH]; - u8 TA[MAC_ADDR_LENGTH]; - u16 FCS; -} __attribute__ ((packed)); - -struct Data_Frame { - struct MAC_frame_control frame_control; - u16 duration; - u8 Addr1[MAC_ADDR_LENGTH]; - u8 Addr2[MAC_ADDR_LENGTH]; - u8 Addr3[MAC_ADDR_LENGTH]; - u16 Sequence_Control; - u8 Addr4[MAC_ADDR_LENGTH]; /* only exist when ToDS=FromDS=1 */ - /* Data Frame Body <= 2312 */ - /* FCS */ -} __attribute__ ((packed)); - -struct Disassociation_Frame_Body { - u16 reasonCode; -} __attribute__ ((packed)); - -struct Association_Request_Frame_Body { - u16 capability_information; - u16 listenInterval; - u8 Current_AP_Address[MAC_ADDR_LENGTH];/* for reassociation only */ - /* SSID (2+32 bytes) */ - /* Supported_Rates (2+8 bytes) */ -} __attribute__ ((packed)); - -struct Association_Response_Frame_Body { - u16 capability_information; - u16 statusCode; - u16 Association_ID; - struct Supported_Rates_Element supportedRates; -} __attribute__ ((packed)); - -/*struct Reassociation_Request_Frame_Body -{ - u16 capability_information; - u16 listenInterval; - u8 Current_AP_Address[MAC_ADDR_LENGTH]; - // SSID (2+32 bytes) - // Supported_Rates (2+8 bytes) -};*/ -/* eliminated by WS 07/22/04 comboined with associateion request frame. */ - -struct Reassociation_Response_Frame_Body { - u16 capability_information; - u16 statusCode; - u16 Association_ID; - struct Supported_Rates_Element supportedRates; -} __attribute__ ((packed)); - -struct Deauthentication_Frame_Body { - u16 reasonCode; -} __attribute__ ((packed)); - - -struct Probe_Response_Frame_Body { - u16 Timestamp; - u16 Beacon_Interval; - u16 Capability_Information; - /* SSID - // Supported_Rates - // PHY parameter Set (DS Parameters) - // CF parameter Set - // IBSS parameter Set */ -} __attribute__ ((packed)); - -struct Authentication_Frame_Body { - u16 algorithmNumber; - u16 sequenceNumber; - u16 statusCode; - /* NB: don't include ChallengeText in this structure - // struct Challenge_Text_Element sChallengeTextElement; - // wkchen added */ -} __attribute__ ((packed)); - - #endif /* _MAC_Structure_H_ */ - - -- cgit v1.2.3 From 2855bb79d75ad1419b1f54008f861a39517acfd5 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:00 +0200 Subject: Staging: w35und: Use pr_debug() for debugging Use pr_debug() for debugging printk's and kill the FULL_DEBUG macro. It would be even better to use dev_dbg() but unfortunately looking up struct device in the current code structure makes things very ugly. Please note that I dropped the DataDmp() calls from RFSynthesizer_SwitchingChannel() because that function doesn't exist. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mds.c | 16 ++++------------ drivers/staging/winbond/reg.c | 27 +++++---------------------- drivers/staging/winbond/sysdef.h | 12 ------------ drivers/staging/winbond/wb35reg.c | 20 +++++--------------- drivers/staging/winbond/wb35rx.c | 21 +++++---------------- drivers/staging/winbond/wb35tx.c | 16 ++++------------ drivers/staging/winbond/wbusb.c | 13 +++---------- 7 files changed, 26 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 90f2cc019d3b..8ae3d84e34bb 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -346,9 +346,7 @@ static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor * ctmp1 = ctmpf = CURRENT_TX_RATE_FOR_MNG; pDes->TxRate = ctmp1; - #ifdef _PE_TX_DUMP_ - printk("Tx rate =%x\n", ctmp1); - #endif + pr_debug("Tx rate =%x\n", ctmp1); pT01->T01_modulation_type = (ctmp1%3) ? 0 : 1; @@ -426,9 +424,7 @@ Mds_Tx(struct wbsoft_priv *adapter) do { FillIndex = pMds->TxFillIndex; if (pMds->TxOwner[FillIndex]) { /* Is owned by software 0:Yes 1:No */ -#ifdef _PE_TX_DUMP_ - printk("[Mds_Tx] Tx Owner is H/W.\n"); -#endif + pr_debug("[Mds_Tx] Tx Owner is H/W.\n"); break; } @@ -472,9 +468,7 @@ Mds_Tx(struct wbsoft_priv *adapter) /* For speed up Key setting */ if (pTxDes->EapFix) { -#ifdef _PE_TX_DUMP_ - printk("35: EPA 4th frame detected. Size = %d\n", PacketSize); -#endif + pr_debug("35: EPA 4th frame detected. Size = %d\n", PacketSize); pHwData->IsKeyPreSet = 1; } @@ -563,9 +557,7 @@ Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pT02) pHwData->tx_retry_count[RetryCount] += RetryCount; else pHwData->tx_retry_count[7] += RetryCount; - #ifdef _PE_STATE_DUMP_ - printk("dto_tx_retry_count =%d\n", pHwData->dto_tx_retry_count); - #endif + pr_debug("dto_tx_retry_count =%d\n", pHwData->dto_tx_retry_count); MTO_SetTxCount(adapter, TxRate, RetryCount); } pHwData->dto_tx_frag_count += (RetryCount+1); diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index 439d213fe951..dcd7560ce2cc 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -1012,9 +1012,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData) case RF_AIROHA_7230: /* Start to fill RF parameters, PLL_ON should be pulled low. */ Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000000); - #ifdef _PE_STATE_DUMP_ - printk("* PLL_ON low\n"); - #endif + pr_debug("* PLL_ON low\n"); number = ARRAY_SIZE(al7230_rf_data_24); Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number); break; @@ -1100,9 +1098,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData) case RF_AIROHA_7230: /* RF parameters have filled completely, PLL_ON should be pulled high */ Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000080); - #ifdef _PE_STATE_DUMP_ - printk("* PLL_ON high\n"); - #endif + pr_debug("* PLL_ON high\n"); /* 2.4GHz */ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F; @@ -1117,9 +1113,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData) /* 5GHz */ Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000000); - #ifdef _PE_STATE_DUMP_ - printk("* PLL_ON low\n"); - #endif + pr_debug("* PLL_ON low\n"); number = ARRAY_SIZE(al7230_rf_data_50); Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number); @@ -1129,9 +1123,7 @@ void RFSynthesizer_initial(struct hw_data *pHwData) msleep(5); Wb35Reg_WriteSync(pHwData, 0x03dc, 0x00000080); - #ifdef _PE_STATE_DUMP_ - printk("* PLL_ON high\n"); - #endif + pr_debug("* PLL_ON high\n"); ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F; Wb35Reg_WriteSync(pHwData, 0x0864, ltmp); @@ -1797,9 +1789,7 @@ void RFSynthesizer_SwitchingChannel(struct hw_data *pHwData, struct chan_info C /* Write to register. number must less and equal than 16 */ Wb35Reg_BurstWrite(pHwData, 0x0864, pltmp, number, NO_INCREMENT); - #ifdef _PE_STATE_DUMP_ - printk("Band changed\n"); - #endif + pr_debug("Band changed\n"); } if (Channel.band <= BAND_TYPE_OFDM_24) { /* channel 1 ~ 14 */ @@ -2338,13 +2328,6 @@ void EEPROMTxVgaAdjust(struct hw_data *pHwData) pHwData->TxVgaFor50[32].TxVgaValue = pTxVga[17] - stmp * 2 / 4; pHwData->TxVgaFor50[31].TxVgaValue = pTxVga[17] - stmp * 3 / 4; } - - #ifdef _PE_STATE_DUMP_ - printk(" TxVgaFor24 :\n"); - DataDmp((u8 *)pHwData->TxVgaFor24, 14 , 0); - printk(" TxVgaFor50 :\n"); - DataDmp((u8 *)pHwData->TxVgaFor50, 70 , 0); - #endif } void BBProcessor_RateChanging(struct hw_data *pHwData, u8 rate) diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h index 8d4ebe15d930..04e6e8ff7349 100644 --- a/drivers/staging/winbond/sysdef.h +++ b/drivers/staging/winbond/sysdef.h @@ -3,16 +3,4 @@ #ifndef SYS_DEF_H #define SYS_DEF_H -/* debug print options, mark what debug you don't need */ - -#ifdef FULL_DEBUG -#define _PE_STATE_DUMP_ -#define _PE_TX_DUMP_ -#define _PE_RX_DUMP_ -#define _PE_OID_DUMP_ -#define _PE_DTO_DUMP_ -#define _PE_REG_DUMP_ -#define _PE_USB_INI_DUMP_ -#endif - #endif diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c index 770722385eeb..f33f4f80b462 100644 --- a/drivers/staging/winbond/wb35reg.c +++ b/drivers/staging/winbond/wb35reg.c @@ -150,9 +150,7 @@ unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 Reg Wb35Reg_EP0VM_start(pHwData); if (ret < 0) { -#ifdef _PE_REG_DUMP_ - printk("EP0 Write register usb message sending error\n"); -#endif + pr_debug("EP0 Write register usb message sending error\n"); pHwData->SurpriseRemove = 1; return false; } @@ -320,9 +318,7 @@ unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRe Wb35Reg_EP0VM_start(pHwData); if (ret < 0) { -#ifdef _PE_REG_DUMP_ - printk("EP0 Read register usb message sending error\n"); -#endif + pr_debug("EP0 Read register usb message sending error\n"); pHwData->SurpriseRemove = 1; return false; } @@ -442,9 +438,7 @@ void Wb35Reg_EP0VM(struct hw_data *pHwData) ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { -#ifdef _PE_REG_DUMP_ - printk("EP0 Irp sending error\n"); -#endif + pr_debug("EP0 Irp sending error\n"); goto cleanup; } return; @@ -479,9 +473,7 @@ void Wb35Reg_EP0VM_complete(struct urb *urb) spin_unlock_irq(®->EP0VM_spin_lock); if (reg->EP0VM_status) { -#ifdef _PE_REG_DUMP_ - printk("EP0 IoCompleteRoutine return error\n"); -#endif + pr_debug("EP0 IoCompleteRoutine return error\n"); reg->EP0vm_state = VM_STOP; pHwData->SurpriseRemove = 1; } else { @@ -526,9 +518,7 @@ void Wb35Reg_destroy(struct hw_data *pHwData) usb_free_urb(urb); kfree(reg_queue); } else { -#ifdef _PE_REG_DUMP_ - printk("EP0 queue release error\n"); -#endif + pr_debug("EP0 queue release error\n"); } spin_lock_irq(®->EP0VM_spin_lock); diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c index 5af271f2de9c..02557289ffb6 100644 --- a/drivers/staging/winbond/wb35rx.c +++ b/drivers/staging/winbond/wb35rx.c @@ -109,10 +109,7 @@ static u16 Wb35Rx_indicate(struct ieee80211_hw *hw) /* Basic check for Rx length. Is length valid? */ if (PacketSize > MAX_PACKET_SIZE) { -#ifdef _PE_RX_DUMP_ - printk("Serious ERROR : Rx data size too long, size =%d\n", PacketSize); -#endif - + pr_debug("Serious ERROR : Rx data size too long, size =%d\n", PacketSize); pWb35Rx->EP3vm_state = VM_STOP; pWb35Rx->Ep3ErrorCount2++; break; @@ -186,9 +183,7 @@ static void Wb35Rx_Complete(struct urb *urb) /* The URB is completed, check the result */ if (pWb35Rx->EP3VM_status != 0) { -#ifdef _PE_USB_STATE_DUMP_ - printk("EP3 IoCompleteRoutine return error\n"); -#endif + pr_debug("EP3 IoCompleteRoutine return error\n"); pWb35Rx->EP3vm_state = VM_STOP; goto error; } @@ -249,9 +244,7 @@ static void Wb35Rx(struct ieee80211_hw *hw) RxBufferId = pWb35Rx->RxBufferId; if (!pWb35Rx->RxOwner[RxBufferId]) { /* It's impossible to run here. */ -#ifdef _PE_RX_DUMP_ - printk("Rx driver fifo unavailable\n"); -#endif + pr_debug("Rx driver fifo unavailable\n"); goto error; } @@ -337,9 +330,7 @@ void Wb35Rx_stop(struct hw_data *pHwData) /* Canceling the Irp if already sends it out. */ if (pWb35Rx->EP3vm_state == VM_RUNNING) { usb_unlink_urb(pWb35Rx->RxUrb); /* Only use unlink, let Wb35Rx_destroy to free them */ -#ifdef _PE_RX_DUMP_ - printk("EP3 Rx stop\n"); -#endif + pr_debug("EP3 Rx stop\n"); } } @@ -355,8 +346,6 @@ void Wb35Rx_destroy(struct hw_data *pHwData) if (pWb35Rx->RxUrb) usb_free_urb(pWb35Rx->RxUrb); -#ifdef _PE_RX_DUMP_ - printk("Wb35Rx_destroy OK\n"); -#endif + pr_debug("Wb35Rx_destroy OK\n"); } diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c index fd52554e46f8..8f0d5273d907 100644 --- a/drivers/staging/winbond/wb35tx.c +++ b/drivers/staging/winbond/wb35tx.c @@ -153,16 +153,12 @@ void Wb35Tx_stop(struct hw_data * pHwData) // Trying to canceling the Trp of EP2 if (pWb35Tx->EP2vm_state == VM_RUNNING) usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them - #ifdef _PE_TX_DUMP_ - printk("EP2 Tx stop\n"); - #endif + pr_debug("EP2 Tx stop\n"); // Trying to canceling the Irp of EP4 if (pWb35Tx->EP4vm_state == VM_RUNNING) usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them - #ifdef _PE_TX_DUMP_ - printk("EP4 Tx stop\n"); - #endif + pr_debug("EP4 Tx stop\n"); } //====================================================== @@ -182,9 +178,7 @@ void Wb35Tx_destroy(struct hw_data * pHwData) if (pWb35Tx->Tx2Urb) usb_free_urb( pWb35Tx->Tx2Urb ); - #ifdef _PE_TX_DUMP_ - printk("Wb35Tx_destroy OK\n"); - #endif + pr_debug("Wb35Tx_destroy OK\n"); } void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) @@ -279,9 +273,7 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) retv = usb_submit_urb(pUrb, GFP_ATOMIC); if (retv < 0) { - #ifdef _PE_TX_DUMP_ - printk("EP2 Tx Irp sending error\n"); - #endif + pr_debug("EP2 Tx Irp sending error\n"); goto error; } diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index dcb6d5b63d76..5f54b0fd706a 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -184,10 +184,7 @@ static void hal_set_current_channel_ex(struct hw_data *pHwData, struct chan_info RFSynthesizer_SwitchingChannel(pHwData, channel); /* Switch channel */ pHwData->Channel = channel.ChanNo; pHwData->band = channel.band; -#ifdef _PE_STATE_DUMP_ - printk("Set channel is %d, band =%d\n", pHwData->Channel, - pHwData->band); -#endif + pr_debug("Set channel is %d, band =%d\n", pHwData->Channel, pHwData->band); reg->M28_MacControl &= ~0xff; /* Clean channel information field */ reg->M28_MacControl |= channel.ChanNo; Wb35Reg_WriteWithCallbackValue(pHwData, 0x0828, reg->M28_MacControl, @@ -728,9 +725,7 @@ static int wb35_hw_init(struct ieee80211_hw *hw) } priv->sLocalPara.bAntennaNo = hal_get_antenna_number(pHwData); -#ifdef _PE_STATE_DUMP_ - printk("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo); -#endif + pr_debug("Driver init, antenna no = %d\n", priv->sLocalPara.bAntennaNo); hal_get_hw_radio_off(pHwData); /* Waiting for HAL setting OK */ @@ -856,9 +851,7 @@ static void wb35_hw_halt(struct wbsoft_priv *adapter) { /* Turn off Rx and Tx hardware ability */ hal_stop(&adapter->sHwData); -#ifdef _PE_USB_INI_DUMP_ - printk("[w35und] Hal_stop O.K.\n"); -#endif + pr_debug("[w35und] Hal_stop O.K.\n"); /* Waiting Irp completed */ msleep(100); -- cgit v1.2.3 From ddee7e28e7d5e4ba2b8537c6a59b035745c250bb Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:01 +0200 Subject: Staging: w35und: Remove empty sysdef.h header The sysdef.h header is empty now so kill it. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mds.c | 1 - drivers/staging/winbond/mlmetxrx.c | 2 -- drivers/staging/winbond/mto.c | 1 - drivers/staging/winbond/phy_calibration.c | 1 - drivers/staging/winbond/reg.c | 1 - drivers/staging/winbond/sysdef.h | 6 ------ drivers/staging/winbond/wb35reg.c | 1 - drivers/staging/winbond/wb35rx.c | 1 - drivers/staging/winbond/wb35tx.c | 1 - 9 files changed, 15 deletions(-) delete mode 100644 drivers/staging/winbond/sysdef.h (limited to 'drivers') diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 8ae3d84e34bb..b4e0514b7f34 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -1,7 +1,6 @@ #include "mds_f.h" #include "mlmetxrx_f.h" #include "mto.h" -#include "sysdef.h" #include "wbhal.h" #include "wblinux_f.h" #include "wb35tx_f.h" diff --git a/drivers/staging/winbond/mlmetxrx.c b/drivers/staging/winbond/mlmetxrx.c index 7425a23f12e8..87f339f1af43 100644 --- a/drivers/staging/winbond/mlmetxrx.c +++ b/drivers/staging/winbond/mlmetxrx.c @@ -15,8 +15,6 @@ Copyright (c) 1996-2002 Winbond Electronics Corp. All Rights Reserved. ============================================================================ */ -#include "sysdef.h" - #include "mds_f.h" void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc) diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c index 1faebceceff7..c03e5010ca34 100644 --- a/drivers/staging/winbond/mto.c +++ b/drivers/staging/winbond/mto.c @@ -17,7 +17,6 @@ * ============================================================================ */ -#include "sysdef.h" #include "sme_api.h" #include "wbhal.h" #include "wb35reg_f.h" diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c index 0658b09c7853..09844db64fe9 100644 --- a/drivers/staging/winbond/phy_calibration.c +++ b/drivers/staging/winbond/phy_calibration.c @@ -10,7 +10,6 @@ */ /****************** INCLUDE FILES SECTION ***********************************/ -#include "sysdef.h" #include "phy_calibration.h" #include "wbhal.h" #include "wb35reg_f.h" diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index dcd7560ce2cc..4d2c6a12a951 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -1,4 +1,3 @@ -#include "sysdef.h" #include "wbhal.h" #include "wb35reg_f.h" #include "core.h" diff --git a/drivers/staging/winbond/sysdef.h b/drivers/staging/winbond/sysdef.h deleted file mode 100644 index 04e6e8ff7349..000000000000 --- a/drivers/staging/winbond/sysdef.h +++ /dev/null @@ -1,6 +0,0 @@ -/* Winbond WLAN System Configuration defines */ - -#ifndef SYS_DEF_H -#define SYS_DEF_H - -#endif diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c index f33f4f80b462..a15de1eab796 100644 --- a/drivers/staging/winbond/wb35reg.c +++ b/drivers/staging/winbond/wb35reg.c @@ -1,4 +1,3 @@ -#include "sysdef.h" #include "wb35reg_f.h" #include diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c index 02557289ffb6..190758ebad5c 100644 --- a/drivers/staging/winbond/wb35rx.c +++ b/drivers/staging/winbond/wb35rx.c @@ -14,7 +14,6 @@ #include #include "core.h" -#include "sysdef.h" #include "wb35rx_f.h" static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int PacketSize) diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c index 8f0d5273d907..5e9e21a6dbff 100644 --- a/drivers/staging/winbond/wb35tx.c +++ b/drivers/staging/winbond/wb35tx.c @@ -13,7 +13,6 @@ #include "wb35tx_f.h" #include "mds_f.h" -#include "sysdef.h" unsigned char Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer) -- cgit v1.2.3 From 9255650cbf997762bd667896b0b86661cd81c9b4 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:02 +0200 Subject: Staging: w35und: Kill Vendor2 ifdef from hal_init_hardware The Vendor2 macro is never defined so remove the ifdef'd block from hal_init_hardware(). Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wbusb.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 5f54b0fd706a..9fc078f8c77a 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -642,13 +642,6 @@ static int hal_init_hardware(struct ieee80211_hw *hw) SoftwareSet = hal_software_set(pHwData); -#ifdef Vendor2 - /* Try to make sure the EEPROM contain */ - SoftwareSet >>= 8; - if (SoftwareSet != 0x82) - return false; -#endif - Wb35Rx_start(hw); Wb35Tx_EP2VM_start(priv); -- cgit v1.2.3 From 9618386a4e58e0459932846d9b07fa81225840d3 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:03 +0200 Subject: Staging: w35und: Kill write-only ->TxToggle This patch removes ->TxToggle from struct wb35_mds because it's a write only struct member. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mds.c | 5 ----- drivers/staging/winbond/mds_s.h | 4 ---- 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index b4e0514b7f34..0daabdc8d91c 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -481,11 +481,6 @@ Mds_Tx(struct wbsoft_priv *adapter) XmitBufSize += CurrentSize; XmitBufAddress += CurrentSize; -#ifdef _IBSS_BEACON_SEQ_STICK_ - if ((XmitBufAddress[DOT_11_DA_OFFSET+8] & 0xfc) != MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) /* +8 for USB hdr */ -#endif - pMds->TxToggle = true; - /* Get packet to transmit completed, 1:TESTSTA 2:MLME 3: Ndis data */ MLME_SendComplete(adapter, 0, true); diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h index e2de4bd23b4d..eeedf0186365 100644 --- a/drivers/staging/winbond/mds_s.h +++ b/drivers/staging/winbond/mds_s.h @@ -107,10 +107,6 @@ struct wb35_mds { u8 TxRate[((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01)][2]; /* [0] current tx rate, [1] fall back rate */ u8 TxInfo[((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01)]; /*Store information for callback function */ - /* for scanning mechanism */ - u8 TxToggle; /* It is TRUE if there are tx activities in some time interval */ - u8 Reserved_[3]; - /* ---- for Tx Parameter */ u16 TxFragmentThreshold; /* For frame body only */ u16 TxRTSThreshold; -- cgit v1.2.3 From 37b0544a4a455609cbf25fa56441a6f1221dec85 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:04 +0200 Subject: Staging: w35und: Kill _IBSS_BEACON_SEQ_STICK_ This patch kills the _IBSS_BEACON_SEQ_STICK_ ifdefs because the macro is never defined. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mlmetxrx_f.h | 4 ---- drivers/staging/winbond/reg.c | 4 ---- 2 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/mlmetxrx_f.h b/drivers/staging/winbond/mlmetxrx_f.h index 012507fc49e3..6db423bc6677 100644 --- a/drivers/staging/winbond/mlmetxrx_f.h +++ b/drivers/staging/winbond/mlmetxrx_f.h @@ -16,8 +16,4 @@ void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK); -#ifdef _IBSS_BEACON_SEQ_STICK_ -s8 SendBCNullData(struct wbsoft_priv *adapter, u16 wIdx); -#endif - #endif diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index 4d2c6a12a951..1b38d6d225c9 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -2064,11 +2064,7 @@ void Mxx_initial(struct hw_data *pHwData) */ /* M00 bit set */ - #ifdef _IBSS_BEACON_SEQ_STICK_ - reg->M00_MacControl = 0; /* Solve beacon sequence number stop by software */ - #else reg->M00_MacControl = 0x80000000; /* Solve beacon sequence number stop by hardware */ - #endif /* M24 disable enter power save, BB RxOn and enable NAV attack */ reg->M24_MacControl = 0x08040042; -- cgit v1.2.3 From 01b5ceeca5aa45735a987420c83228a9778a791f Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:05 +0200 Subject: Staging: w35und: Merge mlmetxrx.c to mds.c This patch merges mlmetxrx.c to mds.c because it's small and the functions are only used in mto.c. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/Makefile | 1 - drivers/staging/winbond/mds.c | 39 ++++++++++++++++++++++- drivers/staging/winbond/mlmetxrx.c | 60 ------------------------------------ drivers/staging/winbond/mlmetxrx_f.h | 19 ------------ drivers/staging/winbond/wbusb.c | 1 - 5 files changed, 38 insertions(+), 82 deletions(-) delete mode 100644 drivers/staging/winbond/mlmetxrx.c delete mode 100644 drivers/staging/winbond/mlmetxrx_f.h (limited to 'drivers') diff --git a/drivers/staging/winbond/Makefile b/drivers/staging/winbond/Makefile index 79fa2271a0c1..081d48db04cb 100644 --- a/drivers/staging/winbond/Makefile +++ b/drivers/staging/winbond/Makefile @@ -1,6 +1,5 @@ w35und-y := \ mds.o \ - mlmetxrx.o \ mto.o \ phy_calibration.o \ reg.o \ diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 0daabdc8d91c..00e9756da9c1 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -1,5 +1,4 @@ #include "mds_f.h" -#include "mlmetxrx_f.h" #include "mto.h" #include "wbhal.h" #include "wblinux_f.h" @@ -397,6 +396,44 @@ static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor * } +static void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc) +{ + desc->InternalUsed = desc->buffer_start_index + desc->buffer_number; + desc->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX; + desc->buffer_address[desc->InternalUsed] = adapter->sMlmeFrame.pMMPDU; + desc->buffer_size[desc->InternalUsed] = adapter->sMlmeFrame.len; + desc->buffer_total_size += adapter->sMlmeFrame.len; + desc->buffer_number++; + desc->Type = adapter->sMlmeFrame.DataType; +} + +static void MLMEfreeMMPDUBuffer(struct wbsoft_priv *adapter, s8 *pData) +{ + int i; + + /* Reclaim the data buffer */ + for (i = 0; i < MAX_NUM_TX_MMPDU; i++) { + if (pData == (s8 *)&(adapter->sMlmeFrame.TxMMPDU[i])) + break; + } + if (adapter->sMlmeFrame.TxMMPDUInUse[i]) + adapter->sMlmeFrame.TxMMPDUInUse[i] = false; + else { + /* Something wrong + PD43 Add debug code here??? */ + } +} + +static void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK) +{ + /* Reclaim the data buffer */ + adapter->sMlmeFrame.len = 0; + MLMEfreeMMPDUBuffer(adapter, adapter->sMlmeFrame.pMMPDU); + + /* Return resource */ + adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE; +} + void Mds_Tx(struct wbsoft_priv *adapter) { diff --git a/drivers/staging/winbond/mlmetxrx.c b/drivers/staging/winbond/mlmetxrx.c deleted file mode 100644 index 87f339f1af43..000000000000 --- a/drivers/staging/winbond/mlmetxrx.c +++ /dev/null @@ -1,60 +0,0 @@ -/* ============================================================================ - Module Name: - MLMETxRx.C - - Description: - The interface between MDS (MAC Data Service) and MLME. - - Revision History: - -------------------------------------------------------------------------- - 200209 UN20 Jennifer Xu - Initial Release - 20021108 PD43 Austin Liu - 20030117 PD43 Austin Liu - Deleted MLMEReturnPacket and MLMEProcThread() - - Copyright (c) 1996-2002 Winbond Electronics Corp. All Rights Reserved. -============================================================================ */ -#include "mds_f.h" - -void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc) -{ - desc->InternalUsed = desc->buffer_start_index + desc->buffer_number; - desc->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX; - desc->buffer_address[desc->InternalUsed] = adapter->sMlmeFrame.pMMPDU; - desc->buffer_size[desc->InternalUsed] = adapter->sMlmeFrame.len; - desc->buffer_total_size += adapter->sMlmeFrame.len; - desc->buffer_number++; - desc->Type = adapter->sMlmeFrame.DataType; -} - -static void MLMEfreeMMPDUBuffer(struct wbsoft_priv *adapter, s8 *pData) -{ - int i; - - /* Reclaim the data buffer */ - for (i = 0; i < MAX_NUM_TX_MMPDU; i++) { - if (pData == (s8 *)&(adapter->sMlmeFrame.TxMMPDU[i])) - break; - } - if (adapter->sMlmeFrame.TxMMPDUInUse[i]) - adapter->sMlmeFrame.TxMMPDUInUse[i] = false; - else { - /* Something wrong - PD43 Add debug code here??? */ - } -} - -void -MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK) -{ - /* Reclaim the data buffer */ - adapter->sMlmeFrame.len = 0; - MLMEfreeMMPDUBuffer(adapter, adapter->sMlmeFrame.pMMPDU); - - /* Return resource */ - adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE; -} - - - diff --git a/drivers/staging/winbond/mlmetxrx_f.h b/drivers/staging/winbond/mlmetxrx_f.h deleted file mode 100644 index 6db423bc6677..000000000000 --- a/drivers/staging/winbond/mlmetxrx_f.h +++ /dev/null @@ -1,19 +0,0 @@ -/* ================================================================ -// MLMETxRx.H -- -// -// Functions defined in MLMETxRx.c. -// -// Copyright (c) 2002 Winbond Electrics Corp. All Rights Reserved. -//================================================================ */ -#ifndef _MLMETXRX_H -#define _MLMETXRX_H - -#include "core.h" - -void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes); - -void -MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, - unsigned char SendOK); - -#endif diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 9fc078f8c77a..c5a3107bd4a7 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -14,7 +14,6 @@ #include "core.h" #include "mds_f.h" -#include "mlmetxrx_f.h" #include "mto.h" #include "wbhal.h" #include "wb35reg_f.h" -- cgit v1.2.3 From 4398954e5f91e340f5a2db53d219b6562e3e1bf0 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:06 +0200 Subject: Staging: w35und: Kill wblinux_f.h header The wblinux_f.h header file doesn't contain anything that's actually used. Kill it. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/mds.c | 1 - drivers/staging/winbond/wblinux_f.h | 17 ----------------- drivers/staging/winbond/wbusb.c | 1 - 3 files changed, 19 deletions(-) delete mode 100644 drivers/staging/winbond/wblinux_f.h (limited to 'drivers') diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 00e9756da9c1..9cfea94bcea5 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -1,7 +1,6 @@ #include "mds_f.h" #include "mto.h" #include "wbhal.h" -#include "wblinux_f.h" #include "wb35tx_f.h" unsigned char diff --git a/drivers/staging/winbond/wblinux_f.h b/drivers/staging/winbond/wblinux_f.h deleted file mode 100644 index 0a9d214f7187..000000000000 --- a/drivers/staging/winbond/wblinux_f.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __WBLINUX_F_H -#define __WBLINUX_F_H - -#include "core.h" -#include "mds_s.h" - -/* - * ==================================================================== - * Copyright (c) 1996-2004 Winbond Electronic Corporation - * - * wblinux_f.h - * ==================================================================== - */ -int wb35_start_xmit(struct sk_buff *skb, struct net_device *netdev); -void wb35_set_multicast(struct net_device *netdev); -struct net_device_stats *wb35_netdev_stats(struct net_device *netdev); -#endif diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index c5a3107bd4a7..4f959c203857 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -19,7 +19,6 @@ #include "wb35reg_f.h" #include "wb35tx_f.h" #include "wb35rx_f.h" -#include "wblinux_f.h" MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 9be98819d31c4e105ad028ee092d27a46a9e298a Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:07 +0200 Subject: Staging: w35und: Remove unused fields from struct wb_usb This patch removes two unused fields from struct wb_usb: - DetectCount which is always zero - IsUsb20 which is a write-only struct member Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wb35reg_s.h | 1 - drivers/staging/winbond/wbusb.c | 8 ++------ drivers/staging/winbond/wbusb_s.h | 2 -- 3 files changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/winbond/wb35reg_s.h b/drivers/staging/winbond/wb35reg_s.h index 9b782ededf43..eb274ffdd1ba 100644 --- a/drivers/staging/winbond/wb35reg_s.h +++ b/drivers/staging/winbond/wb35reg_s.h @@ -234,7 +234,6 @@ u32 hal_get_bss_pk_cnt(struct hw_data *hw_data); /* return 100ms count */ #define hal_get_time_count(_P) (_P->time_count / 10) -#define hal_detect_error(_P) (_P->WbUsb.DetectCount) #define hal_ibss_disconnect(_A) (hal_stop_sync_bss(_A)) diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 4f959c203857..3f5baa7eac26 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -337,10 +337,8 @@ static void hal_stop(struct hw_data *pHwData) static unsigned char hal_idle(struct hw_data *pHwData) { struct wb35_reg *reg = &pHwData->reg; - struct wb_usb *pWbUsb = &pHwData->WbUsb; - if (!pHwData->SurpriseRemove - && (pWbUsb->DetectCount || reg->EP0vm_state != VM_STOP)) + if (!pHwData->SurpriseRemove && reg->EP0vm_state != VM_STOP) return false; return true; @@ -786,10 +784,8 @@ static int wb35_probe(struct usb_interface *intf, interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - if (endpoint[2].wMaxPacketSize == 512) { + if (endpoint[2].wMaxPacketSize == 512) printk("[w35und] Working on USB 2.0\n"); - pWbUsb->IsUsb20 = 1; - } err = wb35_hw_init(dev); if (err) diff --git a/drivers/staging/winbond/wbusb_s.h b/drivers/staging/winbond/wbusb_s.h index 8961ae594c4e..f62639176a4f 100644 --- a/drivers/staging/winbond/wbusb_s.h +++ b/drivers/staging/winbond/wbusb_s.h @@ -11,8 +11,6 @@ #include struct wb_usb { - u32 IsUsb20; struct usb_device *udev; - u32 DetectCount; }; #endif -- cgit v1.2.3 From 2894c6cd0ea84c30fc028ba92f8e61fbe7971e65 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 28 Nov 2010 23:00:08 +0200 Subject: Staging: w35und: Kill struct wb_usb This patch kills struct wb_usb which now only contains a pointer to struct usb_device. Cc: Pavel Machek Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/winbond/wb35reg.c | 12 ++++++------ drivers/staging/winbond/wb35rx.c | 4 ++-- drivers/staging/winbond/wb35tx.c | 6 +++--- drivers/staging/winbond/wbhal.h | 3 +-- drivers/staging/winbond/wbusb.c | 4 +--- drivers/staging/winbond/wbusb_s.h | 16 ---------------- 6 files changed, 13 insertions(+), 32 deletions(-) delete mode 100644 drivers/staging/winbond/wbusb_s.h (limited to 'drivers') diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c index a15de1eab796..42ae61014522 100644 --- a/drivers/staging/winbond/wb35reg.c +++ b/drivers/staging/winbond/wb35reg.c @@ -139,8 +139,8 @@ unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 Reg /* Sync IoCallDriver */ reg->EP0vm_state = VM_RUNNING; - ret = usb_control_msg(pHwData->WbUsb.udev, - usb_sndctrlpipe(pHwData->WbUsb.udev, 0), + ret = usb_control_msg(pHwData->udev, + usb_sndctrlpipe(pHwData->udev, 0), 0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x0, RegisterNo, &RegisterValue, 4, HZ * 100); reg->EP0vm_state = VM_STOP; @@ -302,8 +302,8 @@ unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRe msleep(10); reg->EP0vm_state = VM_RUNNING; - ret = usb_control_msg(pHwData->WbUsb.udev, - usb_rcvctrlpipe(pHwData->WbUsb.udev, 0), + ret = usb_control_msg(pHwData->udev, + usb_rcvctrlpipe(pHwData->udev, 0), 0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x0, RegisterNo, pltmp, 4, HZ * 100); @@ -427,8 +427,8 @@ void Wb35Reg_EP0VM(struct hw_data *pHwData) if (reg_queue->DIRECT == 1) /* output */ pBuffer = ®_queue->VALUE; - usb_fill_control_urb(urb, pHwData->WbUsb.udev, - REG_DIRECTION(pHwData->WbUsb.udev, reg_queue), + usb_fill_control_urb(urb, pHwData->udev, + REG_DIRECTION(pHwData->udev, reg_queue), (u8 *)dr, pBuffer, cpu_to_le16(dr->wLength), Wb35Reg_EP0VM_complete, (void *)pHwData); diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c index 190758ebad5c..f118eeba396a 100644 --- a/drivers/staging/winbond/wb35rx.c +++ b/drivers/staging/winbond/wb35rx.c @@ -260,8 +260,8 @@ static void Wb35Rx(struct ieee80211_hw *hw) } pRxBufferAddress = pWb35Rx->pDRx; - usb_fill_bulk_urb(urb, pHwData->WbUsb.udev, - usb_rcvbulkpipe(pHwData->WbUsb.udev, 3), + usb_fill_bulk_urb(urb, pHwData->udev, + usb_rcvbulkpipe(pHwData->udev, 3), pRxBufferAddress, MAX_USB_RX_BUFFER, Wb35Rx_Complete, hw); diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c index 5e9e21a6dbff..44fc3fe79b79 100644 --- a/drivers/staging/winbond/wb35tx.c +++ b/drivers/staging/winbond/wb35tx.c @@ -88,8 +88,8 @@ static void Wb35Tx(struct wbsoft_priv *adapter) // // Issuing URB // - usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev, - usb_sndbulkpipe(pHwData->WbUsb.udev, 4), + usb_fill_bulk_urb(pUrb, pHwData->udev, + usb_sndbulkpipe(pHwData->udev, 4), pTxBufferAddress, pMds->TxBufferSize[ SendIndex ], Wb35Tx_complete, adapter); @@ -265,7 +265,7 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) // // Issuing URB // - usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2), + usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2), pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32); pWb35Tx->EP2vm_state = VM_RUNNING; diff --git a/drivers/staging/winbond/wbhal.h b/drivers/staging/winbond/wbhal.h index dcf3b213b4f1..39e84a0d9729 100644 --- a/drivers/staging/winbond/wbhal.h +++ b/drivers/staging/winbond/wbhal.h @@ -356,7 +356,6 @@ struct txvga_for_50 { * ============================================== */ -#include "wbusb_s.h" #include "wb35reg_s.h" #include "wb35tx_s.h" #include "wb35rx_s.h" @@ -437,7 +436,7 @@ struct hw_data { * Variable for each module * ================================================== */ - struct wb_usb WbUsb; /* Need WbUsb.h */ + struct usb_device *udev; struct wb35_reg reg; /* Need Wb35Reg.h */ struct wb35_tx Wb35Tx; /* Need Wb35Tx.h */ struct wb35_rx Wb35Rx; /* Need Wb35Rx.h */ diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 3f5baa7eac26..2163d60c2eaf 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -747,7 +747,6 @@ static int wb35_probe(struct usb_interface *intf, struct usb_host_interface *interface; struct ieee80211_hw *dev; struct wbsoft_priv *priv; - struct wb_usb *pWbUsb; int nr, err; u32 ltmp; @@ -778,8 +777,7 @@ static int wb35_probe(struct usb_interface *intf, priv = dev->priv; - pWbUsb = &priv->sHwData.WbUsb; - pWbUsb->udev = udev; + priv->sHwData.udev = udev; interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; diff --git a/drivers/staging/winbond/wbusb_s.h b/drivers/staging/winbond/wbusb_s.h deleted file mode 100644 index f62639176a4f..000000000000 --- a/drivers/staging/winbond/wbusb_s.h +++ /dev/null @@ -1,16 +0,0 @@ -/* ========================================================= - * Copyright (c) 1996-2004 Winbond Electronic Corporation - * - * Module Name: - * wbusb_s.h - * ========================================================= - */ -#ifndef __WINBOND_WBUSB_S_H -#define __WINBOND_WBUSB_S_H - -#include - -struct wb_usb { - struct usb_device *udev; -}; -#endif -- cgit v1.2.3 From 0e7a3e7a746b5dc6ccf9896e882441c4fdbfd09a Mon Sep 17 00:00:00 2001 From: David Chosrova Date: Mon, 29 Nov 2010 21:50:48 +0100 Subject: Staging: rtl8192u: remove dead code to disable dot11d This patch removes all the ENABLE_DOT11D ifdefs. It is always defined for driver. DOT11D has to do with regulatory domains. What prompted this patch was a warning message in Sparse. drivers/staging/rtl8192u/r8192U_core.c:247:1: warning: "eqMacAddr" redefined in file included from drivers/staging/rtl8192u/:81:81: drivers/staging/rtl8192u/dot11d.h:35:1: warning: this is the location of the previous definition Now there are no ifdefs around dot11d.h it made no sense to have this second definition, so I removed that macro as well. ( Thanks Dan ;-) ). Acked-by. Dan Carpenter Signed-off-by: David Chosrova Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/Makefile | 1 - drivers/staging/rtl8192u/dot11d.h | 2 - drivers/staging/rtl8192u/ieee80211/Makefile | 2 - drivers/staging/rtl8192u/ieee80211/dot11d.c | 2 - drivers/staging/rtl8192u/ieee80211/dot11d.h | 3 -- drivers/staging/rtl8192u/ieee80211/ieee80211.h | 8 ---- drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c | 12 ------ .../staging/rtl8192u/ieee80211/ieee80211_softmac.c | 44 ---------------------- .../rtl8192u/ieee80211/ieee80211_softmac_wx.c | 4 -- drivers/staging/rtl8192u/r8192U_core.c | 21 ----------- drivers/staging/rtl8192u/r8192U_wx.c | 6 --- drivers/staging/rtl8192u/r819xU_phy.c | 4 -- 12 files changed, 109 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/Makefile b/drivers/staging/rtl8192u/Makefile index 206d924a707c..eefc657ce99e 100644 --- a/drivers/staging/rtl8192u/Makefile +++ b/drivers/staging/rtl8192u/Makefile @@ -9,7 +9,6 @@ ccflags-y += -DTHOMAS_BEACON -DTHOMAS_TASKLET -DTHOMAS_SKB -DTHOMAS_TURBO #ccflags-y += -DUSB_TX_DRIVER_AGGREGATION_ENABLE #ccflags-y += -DUSB_RX_AGGREGATION_SUPPORT ccflags-y += -DUSE_ONE_PIPE -ccflags-y += -DENABLE_DOT11D ccflags-y += -Idrivers/staging/rtl8192u/ieee80211 r8192u_usb-y := r8192U_core.o r8180_93cx6.o r8192U_wx.o \ diff --git a/drivers/staging/rtl8192u/dot11d.h b/drivers/staging/rtl8192u/dot11d.h index d99cc030ec7a..92e7a00f3ee1 100644 --- a/drivers/staging/rtl8192u/dot11d.h +++ b/drivers/staging/rtl8192u/dot11d.h @@ -1,7 +1,6 @@ #ifndef __INC_DOT11D_H #define __INC_DOT11D_H -#ifdef ENABLE_DOT11D #include "ieee80211/ieee80211.h" @@ -98,5 +97,4 @@ int ToLegalChannel( struct ieee80211_device *dev, u8 channel ); -#endif /* ENABLE_DOT11D */ #endif /* #ifndef __INC_DOT11D_H */ diff --git a/drivers/staging/rtl8192u/ieee80211/Makefile b/drivers/staging/rtl8192u/ieee80211/Makefile index 45704f85ef0b..0775c5599d69 100644 --- a/drivers/staging/rtl8192u/ieee80211/Makefile +++ b/drivers/staging/rtl8192u/ieee80211/Makefile @@ -20,7 +20,6 @@ ifeq ($(NIC_SELECT),RTL8192U) endif #ccflags-y := -DJOHN_NOCPY #flags to enable or disble 80211D feature -ccflags-y += -DENABLE_DOT11D ieee80211-rsl-objs := ieee80211_rx.o \ ieee80211_softmac.o \ ieee80211_tx.o \ @@ -75,7 +74,6 @@ CFLAGS += -I$(KSRC)/include -I. CFLAGS += -DMODVERSIONS -DEXPORT_SYMTAB -include $(KSRC)/include/linux/modversions.h #Kernel 2.4.20 #CFLAGS += -D__NO_VERSION__ -DEXPORT_SYMTAB -#CFLAGS += -DENABLE_DOT11D SMP := $(shell $(CC) $(MODCFLAGS) -E -dM $(CONFIG_FILE) | \ grep CONFIG_SMP | awk '{print $$3}') ifneq ($(SMP),1) diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.c b/drivers/staging/rtl8192u/ieee80211/dot11d.c index b91cbfcfa71f..ce63fc341c6e 100644 --- a/drivers/staging/rtl8192u/ieee80211/dot11d.c +++ b/drivers/staging/rtl8192u/ieee80211/dot11d.c @@ -1,4 +1,3 @@ -#ifdef ENABLE_DOT11D //----------------------------------------------------------------------------- // File: // Dot11d.c @@ -220,4 +219,3 @@ EXPORT_SYMBOL(DOT11D_ScanComplete); EXPORT_SYMBOL(IsLegalChannel); EXPORT_SYMBOL(ToLegalChannel); -#endif diff --git a/drivers/staging/rtl8192u/ieee80211/dot11d.h b/drivers/staging/rtl8192u/ieee80211/dot11d.h index 15b7a4ba37b6..54f2b4c434ff 100644 --- a/drivers/staging/rtl8192u/ieee80211/dot11d.h +++ b/drivers/staging/rtl8192u/ieee80211/dot11d.h @@ -1,10 +1,8 @@ #ifndef __INC_DOT11D_H #define __INC_DOT11D_H -#ifdef ENABLE_DOT11D #include "ieee80211.h" -//#define ENABLE_DOT11D //#define DOT11D_MAX_CHNL_NUM 83 @@ -98,5 +96,4 @@ int ToLegalChannel( struct ieee80211_device * dev, u8 channel ); -#endif //ENABLE_DOT11D #endif // #ifndef __INC_DOT11D_H diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index e1216b704959..c0b844d75c0d 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -1572,10 +1572,8 @@ struct ieee80211_network { #ifdef THOMAS_TURBO u8 Turbo_Enable;//enable turbo mode, added by thomas #endif -#ifdef ENABLE_DOT11D u16 CountryIeLen; u8 CountryIeBuf[MAX_IE_LEN]; -#endif // HT Related, by amy, 2008.04.29 BSS_HT bssht; // Add to handle broadcom AP management frame CCK rate. @@ -1769,7 +1767,6 @@ typedef u32 RT_RF_CHANGE_SOURCE; #define RF_CHANGE_BY_IPS BIT28 #define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17. -#ifdef ENABLE_DOT11D typedef enum { COUNTRY_CODE_FCC = 0, @@ -1784,7 +1781,6 @@ typedef enum COUNTRY_CODE_MIC, COUNTRY_CODE_GLOBAL_DOMAIN }country_code_type_t; -#endif #define RT_MAX_LD_SLOT_NUM 10 typedef struct _RT_LINK_DETECT_T{ @@ -1970,12 +1966,8 @@ struct ieee80211_device { /* map of allowed channels. 0 is dummy */ // FIXME: remeber to default to a basic channel plan depending of the PHY type -#ifdef ENABLE_DOT11D void* pDot11dInfo; bool bGlobalDomain; -#else - int channel_map[MAX_CHANNEL_NUMBER+1]; -#endif int rate; /* current rate */ int basic_rate; //FIXME: pleace callback, see if redundant with softmac_features diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index c8ca9d8ed5d2..1ea8da3655ec 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -44,9 +44,7 @@ #include #include "ieee80211.h" -#ifdef ENABLE_DOT11D #include "dot11d.h" -#endif static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats) @@ -1599,7 +1597,6 @@ static const char *get_info_element_string(u16 id) } #endif -#ifdef ENABLE_DOT11D static inline void ieee80211_extract_country_ie( struct ieee80211_device *ieee, struct ieee80211_info_element *info_element, @@ -1632,7 +1629,6 @@ static inline void ieee80211_extract_country_ie( } } -#endif int ieee80211_parse_info_param(struct ieee80211_device *ieee, struct ieee80211_info_element *info_element, @@ -2086,14 +2082,12 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee, "QoS Error need to parse QOS_PARAMETER IE\n"); break; -#ifdef ENABLE_DOT11D case MFIE_TYPE_COUNTRY: IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", info_element->len); //printk("=====>Receive <%s> Country IE\n",network->ssid); ieee80211_extract_country_ie(ieee, info_element, network, network->bssid);//addr2 is same as addr3 when from an AP break; -#endif /* TODO */ default: IEEE80211_DEBUG_MGMT @@ -2229,10 +2223,8 @@ static inline int ieee80211_network_init( #ifdef THOMAS_TURBO network->Turbo_Enable = 0; #endif -#ifdef ENABLE_DOT11D network->CountryIeLen = 0; memset(network->CountryIeBuf, 0, MAX_IE_LEN); -#endif //Initialize HT parameters //ieee80211_ht_initialize(&network->bssht); HTInitializeBssDesc(&network->bssht); @@ -2399,10 +2391,8 @@ static inline void update_network(struct ieee80211_network *dst, dst->Turbo_Enable = src->Turbo_Enable; #endif -#ifdef ENABLE_DOT11D dst->CountryIeLen = src->CountryIeLen; memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); -#endif //added by amy for LEAP dst->bWithAironetIE = src->bWithAironetIE; @@ -2470,7 +2460,6 @@ static inline void ieee80211_process_probe_response( return; } -#ifdef ENABLE_DOT11D // For Asus EeePc request, // (1) if wireless adapter receive get any 802.11d country code in AP beacon, // wireless adapter should follow the country code. @@ -2527,7 +2516,6 @@ static inline void ieee80211_process_probe_response( } } } -#endif /* The network parsed correctly -- so now we scan our known networks * to see if we can find it in our list. diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index bc8c42533693..12858880f95f 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -21,9 +21,7 @@ #include #include #include -#ifdef ENABLE_DOT11D #include "dot11d.h" -#endif u8 rsn_authen_cipher_suite[16][4] = { {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved @@ -430,10 +428,8 @@ void ieee80211_send_probe_requests(struct ieee80211_device *ieee) void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) { short ch = 0; -#ifdef ENABLE_DOT11D u8 channel_map[MAX_CHANNEL_NUMBER+1]; memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); -#endif down(&ieee->scan_sem); while(1) @@ -443,11 +439,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) ch++; if (ch > MAX_CHANNEL_NUMBER) goto out; /* scan completed */ -#ifdef ENABLE_DOT11D }while(!channel_map[ch]); -#else - }while(!ieee->channel_map[ch]); -#endif /* this function can be called in two situations * 1- We have switched to ad-hoc mode and we are @@ -471,9 +463,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) if (ieee->state == IEEE80211_LINKED) goto out; ieee->set_chan(ieee->dev, ch); -#ifdef ENABLE_DOT11D if(channel_map[ch] == 1) -#endif ieee80211_send_probe_requests(ieee); /* this prevent excessive time wait when we @@ -496,10 +486,8 @@ out: } else{ ieee->sync_scan_hurryup = 0; -#ifdef ENABLE_DOT11D if(IS_DOT11D_ENABLE(ieee)) DOT11D_ScanComplete(ieee); -#endif up(&ieee->scan_sem); } } @@ -510,10 +498,8 @@ void ieee80211_softmac_scan_wq(struct work_struct *work) struct delayed_work *dwork = container_of(work, struct delayed_work, work); struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); static short watchdog = 0; -#ifdef ENABLE_DOT11D u8 channel_map[MAX_CHANNEL_NUMBER+1]; memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); -#endif if(!ieee->ieee_up) return; down(&ieee->scan_sem); @@ -523,25 +509,15 @@ void ieee80211_softmac_scan_wq(struct work_struct *work) if (watchdog++ > MAX_CHANNEL_NUMBER) { //if current channel is not in channel map, set to default channel. - #ifdef ENABLE_DOT11D if (!channel_map[ieee->current_network.channel]); - #else - if (!ieee->channel_map[ieee->current_network.channel]); - #endif ieee->current_network.channel = 6; goto out; /* no good chans */ } -#ifdef ENABLE_DOT11D }while(!channel_map[ieee->current_network.channel]); -#else - }while(!ieee->channel_map[ieee->current_network.channel]); -#endif if (ieee->scanning == 0 ) goto out; ieee->set_chan(ieee->dev, ieee->current_network.channel); -#ifdef ENABLE_DOT11D if(channel_map[ieee->current_network.channel] == 1) -#endif ieee80211_send_probe_requests(ieee); @@ -550,10 +526,8 @@ void ieee80211_softmac_scan_wq(struct work_struct *work) up(&ieee->scan_sem); return; out: -#ifdef ENABLE_DOT11D if(IS_DOT11D_ENABLE(ieee)) DOT11D_ScanComplete(ieee); -#endif ieee->actscanning = false; watchdog = 0; ieee->scanning = 0; @@ -635,7 +609,6 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee) /* called with ieee->lock held */ void ieee80211_start_scan(struct ieee80211_device *ieee) { -#ifdef ENABLE_DOT11D if(IS_DOT11D_ENABLE(ieee) ) { if(IS_COUNTRY_IE_VALID(ieee)) @@ -643,7 +616,6 @@ void ieee80211_start_scan(struct ieee80211_device *ieee) RESET_CIE_WATCHDOG(ieee); } } -#endif if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ if (ieee->scanning == 0){ ieee->scanning = 1; @@ -657,7 +629,6 @@ void ieee80211_start_scan(struct ieee80211_device *ieee) /* called with wx_sem held */ void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) { -#ifdef ENABLE_DOT11D if(IS_DOT11D_ENABLE(ieee) ) { if(IS_COUNTRY_IE_VALID(ieee)) @@ -665,7 +636,6 @@ void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) RESET_CIE_WATCHDOG(ieee); } } -#endif ieee->sync_scan_hurryup = 0; if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ieee80211_softmac_scan_syncro(ieee); @@ -2390,11 +2360,9 @@ void ieee80211_start_ibss_wq(struct work_struct *work) ieee80211_softmac_check_all_nets(ieee); -#ifdef ENABLE_DOT11D //if creating an ad-hoc, set its channel to 10 temporarily--this is the requirement for ASUS, not 11D, so disable 11d. // if((IS_DOT11D_ENABLE(ieee)) && (ieee->state == IEEE80211_NOLINK)) if (ieee->state == IEEE80211_NOLINK) ieee->current_network.channel = 6; -#endif /* if not then the state is not linked. Maybe the user swithced to * ad-hoc mode just after being in monitor mode, or just after * being very few time in managed mode (so the card have had no @@ -2483,7 +2451,6 @@ inline void ieee80211_start_ibss(struct ieee80211_device *ieee) void ieee80211_start_bss(struct ieee80211_device *ieee) { unsigned long flags; -#ifdef ENABLE_DOT11D // // Ref: 802.11d 11.1.3.3 // STA shall not start a BSS unless properly formed Beacon frame including a Country IE. @@ -2495,7 +2462,6 @@ void ieee80211_start_bss(struct ieee80211_device *ieee) return; } } -#endif /* check if we have already found the net we * are interested in (if any). * if not (we are disassociated and we are not @@ -2530,10 +2496,8 @@ void ieee80211_disassociate(struct ieee80211_device *ieee) if (ieee->data_hard_stop) ieee->data_hard_stop(ieee->dev); -#ifdef ENABLE_DOT11D if(IS_DOT11D_ENABLE(ieee)) Dot11d_Reset(ieee); -#endif ieee->state = IEEE80211_NOLINK; ieee->is_set_key = false; ieee->link_change(ieee->dev); @@ -2669,11 +2633,7 @@ void ieee80211_start_protocol(struct ieee80211_device *ieee) ch++; if (ch > MAX_CHANNEL_NUMBER) return; /* no channel found */ -#ifdef ENABLE_DOT11D }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]); -#else - }while(!ieee->channel_map[ch]); -#endif ieee->current_network.channel = ch; } @@ -2721,11 +2681,9 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee) for(i = 0; i < 5; i++) { ieee->seq_ctrl[i] = 0; } -#ifdef ENABLE_DOT11D ieee->pDot11dInfo = kzalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); if (!ieee->pDot11dInfo) IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for DOT11D\n"); -#endif //added for AP roaming ieee->LinkDetectInfo.SlotNum = 2; ieee->LinkDetectInfo.NumRecvBcnInPeriod=0; @@ -2796,13 +2754,11 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee) void ieee80211_softmac_free(struct ieee80211_device *ieee) { down(&ieee->wx_sem); -#ifdef ENABLE_DOT11D if(NULL != ieee->pDot11dInfo) { kfree(ieee->pDot11dInfo); ieee->pDot11dInfo = NULL; } -#endif del_timer_sync(&ieee->associate_timer); cancel_delayed_work(&ieee->associate_retry_wq); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c index f335c258ba84..cb5a3c32974e 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c @@ -15,9 +15,7 @@ #include "ieee80211.h" -#ifdef ENABLE_DOT11D #include "dot11d.h" -#endif /* FIXME: add A freqs */ const long ieee80211_wlan_frequencies[] = { @@ -63,12 +61,10 @@ int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info }else { /* Set the channel */ -#ifdef ENABLE_DOT11D if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) { ret = -EINVAL; goto out; } -#endif ieee->current_network.channel = fwrq->m; ieee->set_chan(ieee->dev, ieee->current_network.channel); diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index cbfe1341d856..9cd41b698161 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -77,9 +77,7 @@ double __extendsfdf2(float a) {return a;} #include "r8192_pm.h" #endif -#ifdef ENABLE_DOT11D #include "dot11d.h" -#endif //set here to open your trace code. //WB u32 rt_global_debug_component = \ // COMP_INIT | @@ -166,7 +164,6 @@ static struct usb_driver rtl8192_usb_driver = { #endif }; -#ifdef ENABLE_DOT11D typedef struct _CHANNEL_LIST { @@ -242,9 +239,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv) } return; } -#endif -#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) #define rx_hal_is_cck_rate(_pdrvinfo)\ (_pdrvinfo->RxRate == DESC90_RATE1M ||\ @@ -3155,7 +3150,6 @@ static void rtl8192_read_eeprom_info(struct net_device* dev) short rtl8192_get_channel_map(struct net_device * dev) { struct r8192_priv *priv = ieee80211_priv(dev); -#ifdef ENABLE_DOT11D if(priv->ChannelPlan > COUNTRY_CODE_GLOBAL_DOMAIN){ printk("rtl8180_init:Error channel plan! Set to default.\n"); priv->ChannelPlan= 0; @@ -3163,21 +3157,6 @@ short rtl8192_get_channel_map(struct net_device * dev) RT_TRACE(COMP_INIT, "Channel plan is %d\n",priv->ChannelPlan); rtl819x_set_channel_map(priv->ChannelPlan, priv); -#else - int ch,i; - //Set Default Channel Plan - if(!channels){ - DMESG("No channels, aborting"); - return -1; - } - ch=channels; - priv->ChannelPlan= 0;//hikaru - // set channels 1..14 allowed in given locale - for (i=1; i<=14; i++) { - (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); - ch >>= 1; - } -#endif return 0; } diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c index 25d5c870b0fb..f6408f98ede6 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.c +++ b/drivers/staging/rtl8192u/r8192U_wx.c @@ -21,9 +21,7 @@ #include "r8192U.h" #include "r8192U_hw.h" -#ifdef ENABLE_DOT11D #include "dot11d.h" -#endif #define RATE_COUNT 12 u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000, @@ -458,11 +456,7 @@ static int rtl8180_wx_get_range(struct net_device *dev, for (i = 0, val = 0; i < 14; i++) { // Include only legal frequencies for some countries -#ifdef ENABLE_DOT11D if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { -#else - if ((priv->ieee80211->channel_map)[i+1]) { -#endif range->freq[val].i = i + 1; range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; range->freq[val].e = 1; diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c index 8e10992366fe..41684e8fcf4c 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.c +++ b/drivers/staging/rtl8192u/r819xU_phy.c @@ -6,9 +6,7 @@ #include "r8192U_dm.h" #include "r819xU_firmware_img.h" -#ifdef ENABLE_DOT11D #include "dot11d.h" -#endif static u32 RF_CHANNEL_TABLE_ZEBRA[] = { 0, 0x085c, //2412 1 @@ -1257,13 +1255,11 @@ u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u RT_TRACE(COMP_CH, "====>%s()====stage:%d, step:%d, channel:%d\n", __FUNCTION__, *stage, *step, channel); // RT_ASSERT(IsLegalChannel(Adapter, channel), ("illegal channel: %d\n", channel)); -#ifdef ENABLE_DOT11D if (!IsLegalChannel(priv->ieee80211, channel)) { RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel); return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop. } -#endif //FIXME:need to check whether channel is legal or not here.WB -- cgit v1.2.3 From 8c66be9203d891ea37346a78925f0e6534b98bd3 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 1 Dec 2010 17:34:39 +0100 Subject: staging: iio: dds: ad9832: Fix kconfig description The AD9832 driver doesn't support the AD9833 and AD9834 Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index d045ed69ad38..7969be29b0eb 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -11,11 +11,11 @@ config AD5930 ad5930/ad5932, provides direct access via sysfs. config AD9832 - tristate "Analog Devices ad9832/3/4/5 driver" + tristate "Analog Devices ad9832/5 driver" depends on SPI help Say yes here to build support for Analog Devices DDS chip - ad9832/3/4/5, provides direct access via sysfs. + ad9832 and ad9835, provides direct access via sysfs. config AD9850 tristate "Analog Devices ad9850/1 driver" -- cgit v1.2.3 From b834517572d19d34c9cd9adb878aec3138db9224 Mon Sep 17 00:00:00 2001 From: David Chosrova Date: Wed, 1 Dec 2010 13:42:16 +0100 Subject: Staging: rtl8192u: check return code kmalloc. This patch checks the return code of kmalloc when trying to allocate memory for priv->rx_urb in rtl8192_usb_initendpoints(), return -ENOMEM when failed. Signed-off-by: David Chosrova Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r8192U_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 9cd41b698161..ae4f2b9d9e8f 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2198,6 +2198,8 @@ short rtl8192_usb_initendpoints(struct net_device *dev) priv->rx_urb = kmalloc(sizeof(struct urb *) * (MAX_RX_URB+1), GFP_KERNEL); + if (priv->rx_urb == NULL) + return -ENOMEM; #ifndef JACKSON_NEW_RX for(i=0;i<(MAX_RX_URB+1);i++){ -- cgit v1.2.3 From 954c7a6c960bcedf28e8b5dcdcd6fe68d8c6c110 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 30 Nov 2010 15:22:13 -0800 Subject: staging: brcm80211: Remove OSL_DMADDRWIDTH Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 3 --- drivers/staging/brcm80211/sys/wlc_bmac.c | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index b973f3fea7e2..18bc1f0d2d84 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -85,9 +85,6 @@ extern uint osl_dma_map(struct osl_info *osh, void *va, uint size, extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, int direction); -/* API for DMA addressing capability */ -#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) - /* register access macros */ #if defined(BCMSDIO) #ifdef BRCM_FULLMAC diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index d427980aebed..2245a8b25a24 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -588,7 +588,6 @@ static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme) */ addrwidth = dma_addrwidth(wlc_hw->sih, DMAREG(wlc_hw, DMA_TX, 0)); - OSL_DMADDRWIDTH(osh, addrwidth); if (!wl_alloc_dma_resources(wlc_hw->wlc->wl, addrwidth)) { WL_ERROR(("wl%d: wlc_attach: alloc_dma_resources failed\n", unit)); -- cgit v1.2.3 From f5343314f62ba392ec069210ae342bc32c4ce367 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 30 Nov 2010 15:22:14 -0800 Subject: staging: brcm80211: Remove unused PKTFREESETCB Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 6 ------ drivers/staging/brcm80211/include/osl.h | 6 ------ drivers/staging/brcm80211/util/linux_osl.c | 3 --- 3 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 18bc1f0d2d84..0e2e53e623cf 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -47,12 +47,6 @@ extern void osl_assert(char *exp, char *file, int line); extern uint osl_pci_bus(struct osl_info *osh); extern uint osl_pci_slot(struct osl_info *osh); -#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ - do { \ - ((struct osl_pubinfo *)osh)->tx_fn = _tx_fn; \ - ((struct osl_pubinfo *)osh)->tx_ctx = _tx_ctx; \ - } while (0) - #define BUS_SWAP32(v) (v) extern void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 4d0ce9705500..186bb77b7623 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -17,15 +17,9 @@ #ifndef _osl_h_ #define _osl_h_ -/* Drivers use PKTFREESETCB to register a callback function - when a packet is freed by OSL */ -typedef void (*pktfree_cb_fn_t) (void *ctx, void *pkt, unsigned int status); - struct osl_pubinfo { uint pktalloced; /* Number of allocated packet buffers */ bool mmbus; /* Bus supports memory-mapped registers */ - pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */ - void *tx_ctx; /* Context to the callback function */ }; /* osl handle type forward declaration */ diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index a0f9dcb0b786..260995e0e90e 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -103,9 +103,6 @@ void BCMFASTPATH osl_pktfree(struct osl_info *osh, void *p, bool send) skb = (struct sk_buff *)p; ASSERT(skb); - if (send && osh->pub.tx_fn) - osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); - /* perversion: we use skb->next to chain multi-skb packets */ while (skb) { nskb = skb->next; -- cgit v1.2.3 From c53d201371bf45cdb5b843ade52edd8903bb72f6 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 30 Nov 2010 15:22:15 -0800 Subject: staging: brcm80211: Remove bogus gcc version checking Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 0e2e53e623cf..94f5d12d53d9 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -29,17 +29,8 @@ extern u32 g_assert_type; do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) extern void osl_assert(char *exp, char *file, int line); #else -#ifdef __GNUC__ -#define GCC_VERSION \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#if GCC_VERSION > 30100 #define ASSERT(exp) do {} while (0) -#else - /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ -#define ASSERT(exp) -#endif /* GCC_VERSION > 30100 */ -#endif /* __GNUC__ */ -#endif /* defined(BCMDBG_ASSERT) */ +#endif /* defined(BCMDBG_ASSERT) */ /* PCI device bus # and slot # */ #define OSL_PCI_BUS(osh) osl_pci_bus(osh) -- cgit v1.2.3 From c10407ac459577f6b58f3db0777b6d0d53a3be9f Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 30 Nov 2010 17:35:09 -0800 Subject: staging: brcm80211: remove OSL_SYSUPTIME_SUPPORT Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/osl.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 186bb77b7623..662b5197b374 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -56,11 +56,4 @@ typedef void (*osl_wreg_fn_t) (void *ctx, void *reg, unsigned int val, #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) #endif /* !OR_REG */ -#if !defined(OSL_SYSUPTIME) -#define OSL_SYSUPTIME() (0) -#define OSL_SYSUPTIME_SUPPORT false -#else -#define OSL_SYSUPTIME_SUPPORT true -#endif /* OSL_SYSUPTIME */ - #endif /* _osl_h_ */ -- cgit v1.2.3 From 9249ede9d4d9dbf41ab6545a7a43fd5f6e5aa620 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 30 Nov 2010 20:09:49 -0800 Subject: staging: brcm80211: bzero => memset s/bzero/memset/g Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 2 +- .../brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 8 ++-- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 24 +++++------ drivers/staging/brcm80211/include/linux_osl.h | 3 -- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 16 ++++---- drivers/staging/brcm80211/phy/wlc_phy_lcn.c | 6 +-- drivers/staging/brcm80211/sys/wl_mac80211.c | 8 ++-- drivers/staging/brcm80211/sys/wlc_ampdu.c | 6 +-- drivers/staging/brcm80211/sys/wlc_bmac.c | 2 +- drivers/staging/brcm80211/sys/wlc_channel.c | 10 ++--- drivers/staging/brcm80211/sys/wlc_mac80211.c | 48 +++++++++++----------- drivers/staging/brcm80211/sys/wlc_rate.c | 2 +- drivers/staging/brcm80211/util/bcmotp.c | 2 +- drivers/staging/brcm80211/util/bcmsrom.c | 2 +- drivers/staging/brcm80211/util/bcmutils.c | 2 +- drivers/staging/brcm80211/util/hnddma.c | 13 +++--- drivers/staging/brcm80211/util/linux_osl.c | 2 +- drivers/staging/brcm80211/util/siutils.c | 4 +- 19 files changed, 82 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index aadfe69a8a0c..2e02d5e58415 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -751,7 +751,7 @@ sdioh_cis_read(sdioh_info_t *sd, uint func, u8 *cisd, u32 length) sd_trace(("%s: Func = %d\n", __func__, func)); if (!sd->func_cis_ptr[func]) { - bzero(cis, length); + memset(cis, 0, length); sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func)); return SDIOH_API_RC_FAIL; } diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c index 14f73fd28760..ceaa47490680 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c @@ -213,7 +213,7 @@ int sdio_function_init(void) if (!gInstance) return -ENOMEM; - bzero(&sdmmc_dev, sizeof(sdmmc_dev)); + memset(&sdmmc_dev, 0, sizeof(sdmmc_dev)); error = sdio_register_driver(&bcmsdh_sdmmc_driver); return error; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 9e96c7e6e3c5..6b41d1f1b764 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -960,7 +960,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, frame = (u8 *) (pkt->data); ASSERT((pad + SDPCM_HDRLEN) <= (int)(pkt->len)); - bzero(frame, pad + SDPCM_HDRLEN); + memset(frame, 0, pad + SDPCM_HDRLEN); } } ASSERT(pad < DHD_SDALIGN); @@ -1252,7 +1252,7 @@ int dhd_bus_txctl(struct dhd_bus *bus, unsigned char *msg, uint msglen) frame -= doff; len += doff; msglen += doff; - bzero(frame, doff + SDPCM_HDRLEN); + memset(frame, 0, doff + SDPCM_HDRLEN); } ASSERT(doff < DHD_SDALIGN); } @@ -2536,7 +2536,7 @@ static int dhdsdio_write_vars(dhd_bus_t *bus) if (!vbuffer) return BCME_NOMEM; - bzero(vbuffer, varsize); + memset(vbuffer, 0, varsize); bcopy(bus->vars, vbuffer, bus->varsz); /* Write the vars list */ @@ -5285,7 +5285,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, struct osl_info *osh, void *sdh, "failed\n", fn)); break; } - bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); + memset(cis[fn], 0, SBSDIO_CIS_SIZE_LIMIT); err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT); diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index e714d6a9452b..8bf24c7ce684 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -347,10 +347,10 @@ wl_iw_config_commit(struct net_device *dev, if (!ssid.SSID_len) return 0; - bzero(&bssid, sizeof(struct sockaddr)); + memset(&bssid, 0, sizeof(struct sockaddr)); error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN); if (error) { - WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __func__, + WL_ERROR(("%s: WLC_REASSOC to %s failed\n", __func__, ssid.SSID)); return error; } @@ -775,7 +775,7 @@ wl_iw_set_wap(struct net_device *dev, if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { scb_val_t scbval; - bzero(&scbval, sizeof(scb_val_t)); + memset(&scbval, 0, sizeof(scb_val_t)); (void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); return 0; @@ -2412,7 +2412,7 @@ wl_iw_get_encode(struct net_device *dev, WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name)); - bzero(&key, sizeof(wl_wsec_key_t)); + memset(&key, 0, sizeof(wl_wsec_key_t)); if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; @@ -2647,7 +2647,7 @@ wl_iw_set_pmksa(struct net_device *dev, if (iwpmksa->cmd == IW_PMKSA_FLUSH) { WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); - bzero((char *)&pmkid_list, sizeof(pmkid_list)); + memset((char *)&pmkid_list, 0, sizeof(pmkid_list)); } else if (iwpmksa->cmd == IW_PMKSA_REMOVE) { @@ -2676,7 +2676,7 @@ wl_iw_set_pmksa(struct net_device *dev, if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) { - bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t)); + memset(&pmkid_list.pmkids.pmkid[i], 0, sizeof(pmkid_t)); for (; i < (pmkid_list.pmkids.npmkid - 1); i++) { bcopy(&pmkid_list.pmkids.pmkid[i + 1].BSSID, &pmkid_list.pmkids.pmkid[i].BSSID, @@ -3409,16 +3409,16 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: cmd = SIOCGIWAP; - bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); + memset(wrqu.addr.sa_data, 0, ETHER_ADDR_LEN); wrqu.addr.sa_family = ARPHRD_ETHER; - bzero(&extra, ETHER_ADDR_LEN); + memset(&extra, 0, ETHER_ADDR_LEN); break; case WLC_E_LINK: case WLC_E_NDIS_LINK: cmd = SIOCGIWAP; if (!(flags & WLC_EVENT_MSG_LINK)) { - bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); - bzero(&extra, ETHER_ADDR_LEN); + memset(wrqu.addr.sa_data, 0, ETHER_ADDR_LEN); + memset(&extra, 0, ETHER_ADDR_LEN); WAKE_LOCK_TIMEOUT(iw->pub, WAKE_LOCK_LINK_DOWN_TMOUT, 20 * HZ); } else { @@ -3488,7 +3488,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) wrqu.data.length = sizeof(struct iw_pmkid_cand); pmkidcand = pmkcandlist->pmkid_cand; while (count) { - bzero(iwpmkidcand, + memset(iwpmkidcand, 0, sizeof(struct iw_pmkid_cand)); if (pmkidcand->preauth) iwpmkidcand->flags |= @@ -3586,7 +3586,7 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) phy_noise = dtoh32(phy_noise); WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise)); - bzero(&scb_val, sizeof(scb_val_t)); + memset(&scb_val, 0, sizeof(scb_val_t)); res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); if (res) goto done; diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index 94f5d12d53d9..ec1c51119637 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -102,7 +102,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, /* bcopy's: Linux kernel doesn't provide these (anymore) */ #define bcopy(src, dst, len) memcpy((dst), (src), (len)) #define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -#define bzero(b, len) memset((b), '\0', (len)) /* register access macros */ #if defined(OSLREGOPS) @@ -201,10 +200,8 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -/* bcopy, bcmp, and bzero functions */ #define bcopy(src, dst, len) memcpy((dst), (src), (len)) #define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -#define bzero(b, len) memset((b), '\0', (len)) /* uncached/cached virtual address */ #ifdef __mips__ diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index 87d33dd8e01b..6ea4df64d18e 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -1538,7 +1538,7 @@ wlc_phy_chanspec_band_validch(wlc_phy_t *ppi, uint band, chanvec_t *channels) ASSERT((band == WLC_BAND_2G) || (band == WLC_BAND_5G)); - bzero(channels, sizeof(chanvec_t)); + memset(channels, 0, sizeof(chanvec_t)); for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { channel = chan_info_all[i].chan; @@ -1900,7 +1900,7 @@ void wlc_phy_txpower_recalc_target(phy_info_t *pi) tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]); } - bzero(pi->tx_power_offset, sizeof(pi->tx_power_offset)); + memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset)); pi->tx_power_max = tx_pwr_max; pi->tx_power_min = tx_pwr_min; pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind; @@ -2511,7 +2511,7 @@ wlc_phy_noise_calc_phy(phy_info_t *pi, u32 *cmplx_pwr, s8 *pwr_ant) s8 cmplx_pwr_dbm[PHY_CORE_MAX]; u8 i; - bzero((u8 *) cmplx_pwr_dbm, sizeof(cmplx_pwr_dbm)); + memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm)); ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX); wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum); @@ -2625,9 +2625,9 @@ wlc_phy_noise_sample_request(wlc_phy_t *pih, u8 reason, u8 ch) u8 wait_crs = 0; u8 i; - bzero((u8 *) est, sizeof(est)); - bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr)); - bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant)); + memset((u8 *) est, 0, sizeof(est)); + memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); + memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; num_samps = 1 << log_num_samps; @@ -2708,8 +2708,8 @@ static s8 wlc_phy_noise_read_shmem(phy_info_t *pi) u8 idx, core; ASSERT(pi->pubpi.phy_corenum <= PHY_CORE_MAX); - bzero((u8 *) cmplx_pwr, sizeof(cmplx_pwr)); - bzero((u8 *) noise_dbm_ant, sizeof(noise_dbm_ant)); + memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); + memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) { lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx)); diff --git a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c index 1fde9d5701b0..9492ca5421f8 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c @@ -1331,7 +1331,7 @@ static void wlc_lcnphy_clear_tx_power_offsets(phy_info_t *pi) u32 data_buf[64]; phytbl_info_t tab; - bzero(data_buf, sizeof(data_buf)); + memset(data_buf, 0, sizeof(data_buf)); tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; tab.tbl_width = 32; @@ -1955,7 +1955,7 @@ wlc_lcnphy_tx_iqlo_cal(phy_info_t *pi, band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0); cal_gains = *target_gains; - bzero(ncorr_override, sizeof(ncorr_override)); + memset(ncorr_override, 0, sizeof(ncorr_override)); for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) { if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) { cal_gains.gm_gain = @@ -2533,7 +2533,7 @@ static void wlc_lcnphy_clear_papd_comptable(phy_info_t *pi) tab.tbl_width = 32; tab.tbl_offset = 0; - bzero(temp_offset, sizeof(temp_offset)); + memset(temp_offset, 0, sizeof(temp_offset)); for (j = 1; j < 128; j += 2) temp_offset[j] = 0x80000; diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 7d18d4f269e9..959ea528245a 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -530,7 +530,7 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* Init the scb */ scb = (struct scb *)sta->drv_priv; - bzero(scb, sizeof(struct scb)); + memset(scb, 0, sizeof(struct scb)); for (i = 0; i < NUMPRIO; i++) scb->seqctl[i] = 0xFFFF; scb->seqctl_nonqos = 0xFFFF; @@ -1073,7 +1073,7 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, hw); - bzero(hw->priv, sizeof(*wl)); + memset(hw->priv, 0, sizeof(*wl)); wl = wl_attach(pdev->vendor, pdev->device, pci_resource_start(pdev, 0), PCI_BUS, pdev, pdev->irq); @@ -1555,7 +1555,7 @@ wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg, return 0; } - bzero(t, sizeof(wl_timer_t)); + memset(t, 0, sizeof(wl_timer_t)); init_timer(&t->timer); t->timer.data = (unsigned long) t; @@ -1747,7 +1747,7 @@ static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) char fw_name[100]; int i; - bzero((void *)&wl->fw, sizeof(struct wl_firmware)); + memset((void *)&wl->fw, 0, sizeof(struct wl_firmware)); for (i = 0; i < WL_MAX_FW; i++) { if (wl_firmwares[i] == NULL) break; diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index c5ab4a459471..86563b5860a2 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -976,7 +976,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, #ifdef BCMDBG u8 hole[AMPDU_MAX_MPDU]; - bzero(hole, sizeof(hole)); + memset(hole, 0, sizeof(hole)); #endif ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU); @@ -993,7 +993,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, ASSERT(ini->scb == scb); - bzero(bitmap, sizeof(bitmap)); + memset(bitmap, 0, sizeof(bitmap)); queue = txs->frameid & TXFID_QUEUE_MASK; ASSERT(queue < AC_COUNT); @@ -1318,7 +1318,7 @@ void wlc_ampdu_macaddr_upd(wlc_info_t *wlc) char template[T_RAM_ACCESS_SZ * 2]; /* driver needs to write the ta in the template; ta is at offset 16 */ - bzero(template, sizeof(template)); + memset(template, 0, sizeof(template)); bcopy((char *)wlc->pub->cur_etheraddr.octet, template, ETHER_ADDR_LEN); wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2), template); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 2245a8b25a24..6711c69edf38 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -1457,7 +1457,7 @@ wlc_mhfdef(wlc_info_t *wlc, u16 *mhfs, u16 mhf2_init) { wlc_hw_info_t *wlc_hw = wlc->hw; - bzero(mhfs, sizeof(u16) * MHFMAX); + memset(mhfs, 0, MHFMAX * sizeof(u16)); mhfs[MHF2] |= mhf2_init; diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index 2fcdbc72c837..bb82a8c008a4 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -382,7 +382,7 @@ void wlc_locale_get_channels(const locale_info_t *locale, chanvec_t *channels) { u8 i; - bzero(channels, sizeof(chanvec_t)); + memset(channels, 0, sizeof(chanvec_t)); for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) { if (locale->valid_channels & (1 << i)) { @@ -634,7 +634,7 @@ wlc_cm_info_t *wlc_channel_mgr_attach(wlc_info_t *wlc) } /* internal country information which must match regulatory constraints in firmware */ - bzero(country_abbrev, WLC_CNTRY_BUF_SZ); + memset(country_abbrev, 0, WLC_CNTRY_BUF_SZ); strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1); country = wlc_country_lookup(wlc, country_abbrev); @@ -763,7 +763,7 @@ wlc_set_country_common(wlc_cm_info_t *wlc_cm, /* save current country state */ wlc_cm->country = country; - bzero(&prev_country_abbrev, WLC_CNTRY_BUF_SZ); + memset(&prev_country_abbrev, 0, WLC_CNTRY_BUF_SZ); strncpy(prev_country_abbrev, wlc_cm->country_abbrev, WLC_CNTRY_BUF_SZ - 1); @@ -1008,7 +1008,7 @@ void wlc_quiet_channels_reset(wlc_cm_info_t *wlc_cm) wlcband_t *band; const chanvec_t *chanvec; - bzero(&wlc_cm->quiet_channels, sizeof(chanvec_t)); + memset(&wlc_cm->quiet_channels, 0, sizeof(chanvec_t)); band = wlc->band; for (i = 0; i < NBANDS(wlc); @@ -1319,7 +1319,7 @@ wlc_channel_reg_limits(wlc_cm_info_t *wlc_cm, chanspec_t chanspec, int maxpwr_idx; uint j; - bzero(txpwr, sizeof(txpwr_limits_t)); + memset(txpwr, 0, sizeof(txpwr_limits_t)); if (!wlc_valid_chanspec_db(wlc_cm, chanspec)) { country = wlc_country_lookup(wlc, wlc->autocountry_default); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 29b6139ae4f0..7017db68c983 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -372,7 +372,8 @@ void wlc_reset(wlc_info_t *wlc) wlc_statsupd(wlc); /* reset our snapshot of macstat counters */ - bzero((char *)wlc->core->macstat_snapshot, sizeof(macstat_t)); + memset((char *)wlc->core->macstat_snapshot, 0, + sizeof(macstat_t)); } wlc_bmac_reset(wlc->hw); @@ -866,7 +867,7 @@ static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len) else if (len < sizeof(tx_power_t)) return BCME_BUFTOOSHORT; - bzero(&power, sizeof(tx_power_t)); + memset(&power, 0, sizeof(tx_power_t)); power.chanspec = WLC_BAND_PI_RADIO_CHANSPEC; if (wlc->pub->associated) @@ -988,7 +989,7 @@ static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len) } else { int band_idx = CHSPEC_IS2G(power.chanspec) ? 0 : 1; - bzero(old_power, sizeof(tx_power_legacy_t)); + memset(old_power, 0, sizeof(tx_power_legacy_t)); old_power->txpwr_local_max = power.local_max; old_power->txpwr_local_constraint = power.local_constraint; @@ -1359,7 +1360,7 @@ void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend) wlc->wme_admctl = 0; do { - bzero((char *)&acp_shm, sizeof(shm_acparams_t)); + memset((char *)&acp_shm, 0, sizeof(shm_acparams_t)); /* find out which ac this set of params applies to */ ASSERT(aci < AC_COUNT); /* set the admission control policy for this AC */ @@ -1440,7 +1441,7 @@ void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend) wlc->wme_admctl = 0; for (i = 0; i < AC_COUNT; i++, edcf_acp++) { - bzero((char *)&acp_shm, sizeof(shm_acparams_t)); + memset((char *)&acp_shm, 0, sizeof(shm_acparams_t)); /* find out which ac this set of params applies to */ aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT; ASSERT(aci < AC_COUNT); @@ -2633,7 +2634,7 @@ int wlc_up(wlc_info_t *wlc) static void wlc_tx_prec_map_init(wlc_info_t *wlc) { wlc->tx_prec_map = WLC_PREC_BMP_ALL; - bzero(wlc->fifo2prec_map, sizeof(u16) * NFIFO); + memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16)); /* For non-WME, both fifos have overlapping MAXPRIO. So just disable all precedences * if either is full. @@ -2790,10 +2791,10 @@ int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config) wlc_protection_upd(wlc, WLC_PROT_G_USER, gmode); /* Clear supported rates filter */ - bzero(&wlc->sup_rates_override, sizeof(wlc_rateset_t)); + memset(&wlc->sup_rates_override, 0, sizeof(wlc_rateset_t)); /* Clear rateset override */ - bzero(&rs, sizeof(wlc_rateset_t)); + memset(&rs, 0, sizeof(wlc_rateset_t)); switch (gmode) { case GMODE_LEGACY_B: @@ -3589,7 +3590,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) break; } - bzero((char *)&key, sizeof(key)); + memset((char *)&key, 0, sizeof(key)); if (src_key) { key.index = src_key->id; key.len = src_key->len; @@ -3686,7 +3687,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) wlc_rateset_t rs; wl_rateset_t *ret_rs = (wl_rateset_t *) arg; - bzero(&rs, sizeof(wlc_rateset_t)); + memset(&rs, 0, sizeof(wlc_rateset_t)); wlc_default_rateset(wlc, (wlc_rateset_t *) &rs); if (len < (int)(rs.count + sizeof(rs.count))) { @@ -3714,7 +3715,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) break; } - bzero(&rs, sizeof(wlc_rateset_t)); + memset(&rs, 0, sizeof(wlc_rateset_t)); /* Copy only legacy rateset section */ rs.count = in_rs->count; @@ -4048,7 +4049,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) /* check for an empty rateset to clear the override */ if (rs.count == 0) { - bzero(&wlc->sup_rates_override, + memset(&wlc->sup_rates_override, 0, sizeof(wlc_rateset_t)); break; } @@ -4349,7 +4350,7 @@ int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl) for (i = 0; i < WLC_MAXMODULES; i++) { if (!strcmp(wlc->modulecb[i].name, name) && (wlc->modulecb[i].hdl == hdl)) { - bzero(&wlc->modulecb[i], sizeof(modulecb_t)); + memset(&wlc->modulecb[i], 0, sizeof(modulecb_t)); return 0; } } @@ -5355,7 +5356,7 @@ wlc_compute_ofdm_plcp(ratespec_t rspec, u32 length, u8 *plcp) rate_signal = rate_info[rate] & RATE_MASK; ASSERT(rate_signal != 0); - bzero(plcp, D11_PHY_HDR_LEN); + memset(plcp, 0, D11_PHY_HDR_LEN); D11A_PHY_HDR_SRATE((ofdm_phy_hdr_t *) plcp, rate_signal); tmp = (length & 0xfff) << 5; @@ -5718,7 +5719,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, /* add Broadcom tx descriptor header */ txh = (d11txh_t *) skb_push(p, D11_TXH_LEN); - bzero((char *)txh, D11_TXH_LEN); + memset((char *)txh, 0, D11_TXH_LEN); /* setup frameid */ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -6134,9 +6135,10 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, D11A_PHY_HDR_GRATE((ofdm_phy_hdr_t *) rts_plcp) : rts_plcp[0]) << 8; } else { - bzero((char *)txh->RTSPhyHeader, D11_PHY_HDR_LEN); - bzero((char *)&txh->rts_frame, sizeof(struct dot11_rts_frame)); - bzero((char *)txh->RTSPLCPFallback, + memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); + memset((char *)&txh->rts_frame, 0, + sizeof(struct dot11_rts_frame)); + memset((char *)txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback)); txh->RTSDurFallback = 0; } @@ -7274,7 +7276,7 @@ void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset) uint i; /* incoming rates are in 500kbps units as in 802.11 Supported Rates */ - bzero(br, WLC_MAXRATE + 1); + memset(br, 0, WLC_MAXRATE + 1); /* For each basic rate in the rates list, make an entry in the * best basic lookup. @@ -7608,7 +7610,7 @@ wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rspec, *len = hdr_len + body_len; /* return actual size */ /* format PHY and MAC headers */ - bzero((char *)buf, hdr_len); + memset((char *)buf, 0, hdr_len); plcp = (cck_phy_hdr_t *) buf; @@ -7729,7 +7731,7 @@ void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg) u8 ssidbuf[DOT11_MAX_SSID_LEN]; /* padding the ssid with zero and copy it into shm */ - bzero(ssidbuf, DOT11_MAX_SSID_LEN); + memset(ssidbuf, 0, DOT11_MAX_SSID_LEN); bcopy(ssidptr, ssidbuf, cfg->SSID_len); wlc_copyto_shm(wlc, base, ssidbuf, DOT11_MAX_SSID_LEN); @@ -7845,7 +7847,7 @@ void wlc_reprate_init(wlc_info_t *wlc) void wlc_bsscfg_reprate_init(wlc_bsscfg_t *bsscfg) { bsscfg->txrspecidx = 0; - bzero((char *)bsscfg->txrspec, sizeof(bsscfg->txrspec)); + memset((char *)bsscfg->txrspec, 0, sizeof(bsscfg->txrspec)); } /* Retrieve a consolidated set of revision information, @@ -7900,7 +7902,7 @@ static void wlc_bss_default_init(wlc_info_t *wlc) wlc_bss_info_t *bi = wlc->default_bss; /* init default and target BSS with some sane initial values */ - bzero((char *)(bi), sizeof(wlc_bss_info_t)); + memset((char *)(bi), 0, sizeof(wlc_bss_info_t)); bi->beacon_period = ISSIM_ENAB(wlc->pub->sih) ? BEACON_INTERVAL_DEF_QT : BEACON_INTERVAL_DEFAULT; bi->dtim_period = ISSIM_ENAB(wlc->pub->sih) ? DTIM_INTERVAL_DEF_QT : diff --git a/drivers/staging/brcm80211/sys/wlc_rate.c b/drivers/staging/brcm80211/sys/wlc_rate.c index e1199b236f5f..ab7d0bed3c0a 100644 --- a/drivers/staging/brcm80211/sys/wlc_rate.c +++ b/drivers/staging/brcm80211/sys/wlc_rate.c @@ -299,7 +299,7 @@ wlc_rate_hwrs_filter_sort_validate(wlc_rateset_t *rs, uint count; uint i; - bzero(rateset, sizeof(rateset)); + memset(rateset, 0, sizeof(rateset)); count = rs->count; for (i = 0; i < count; i++) { diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c index 499cf0366200..ac25989c8dab 100644 --- a/drivers/staging/brcm80211/util/bcmotp.c +++ b/drivers/staging/brcm80211/util/bcmotp.c @@ -901,7 +901,7 @@ void *otp_init(si_t *sih) void *ret = NULL; oi = &otpinfo; - bzero(oi, sizeof(otpinfo_t)); + memset(oi, 0, sizeof(otpinfo_t)); oi->ccrev = sih->ccrev; diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index af4658e4d67e..77098465d541 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -405,7 +405,7 @@ int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, return -2; varbuf_init(&b, base, MAXSZ_NVRAM_VARS); - bzero(base, MAXSZ_NVRAM_VARS); + memset(base, 0, MAXSZ_NVRAM_VARS); eabuf[0] = '\0'; for (cisnum = 0; cisnum < ciscnt; cisnum++) { cis = *pcis++; diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 49c1f74dda83..64d1440a5041 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -266,7 +266,7 @@ void pktq_init(struct pktq *pq, int num_prec, int max_len) ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); /* pq is variable size; only zero out what's requested */ - bzero(pq, + memset(pq, 0, offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); pq->num_prec = (u16) num_prec; diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index 3c85aa584d8f..996998d805e0 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -1118,7 +1118,8 @@ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di) *(u32 *) (p->data) = 0; if (DMASGLIST_ENAB) - bzero(&di->rxp_dmah[rxout], sizeof(hnddma_seg_map_t)); + memset(&di->rxp_dmah[rxout], 0, + sizeof(hnddma_seg_map_t)); pa = DMA_MAP(di->osh, p->data, di->rxbufsize, DMA_RX, p, &di->rxp_dmah[rxout]); @@ -1688,7 +1689,8 @@ static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit) continue; if (DMASGLIST_ENAB) - bzero(&di->txp_dmah[txout], sizeof(hnddma_seg_map_t)); + memset(&di->txp_dmah[txout], 0, + sizeof(hnddma_seg_map_t)); /* get physical address of buffer start */ pa = DMA_MAP(di->osh, data, len, DMA_TX, p, @@ -1960,7 +1962,7 @@ static void dma32_txrotate(dma_info_t *di) if (DMASGLIST_ENAB) { bcopy(&di->txp_dmah[old], &di->txp_dmah[new], sizeof(hnddma_seg_map_t)); - bzero(&di->txp_dmah[old], sizeof(hnddma_seg_map_t)); + memset(&di->txp_dmah[old], 0, sizeof(hnddma_seg_map_t)); } di->txp[old] = NULL; @@ -2339,7 +2341,8 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, struct sk_buff *p0, /* get physical address of buffer start */ if (DMASGLIST_ENAB) - bzero(&di->txp_dmah[txout], sizeof(hnddma_seg_map_t)); + memset(&di->txp_dmah[txout], 0, + sizeof(hnddma_seg_map_t)); pa = DMA_MAP(di->osh, data, len, DMA_TX, p, &di->txp_dmah[txout]); @@ -2637,7 +2640,7 @@ static void dma64_txrotate(dma_info_t *di) if (DMASGLIST_ENAB) { bcopy(&di->txp_dmah[old], &di->txp_dmah[new], sizeof(hnddma_seg_map_t)); - bzero(&di->txp_dmah[old], sizeof(hnddma_seg_map_t)); + memset(&di->txp_dmah[old], 0, sizeof(hnddma_seg_map_t)); } di->txp[old] = NULL; diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 260995e0e90e..6a06d61568b9 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -43,7 +43,7 @@ struct osl_info *osl_attach(void *pdev, uint bustype) osh = kmalloc(sizeof(struct osl_info), GFP_ATOMIC); ASSERT(osh); - bzero(osh, sizeof(struct osl_info)); + memset(osh, 0, sizeof(struct osl_info)); osh->magic = OS_HANDLE_MAGIC; osh->pdev = pdev; diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 050c2d248978..1a9ff1a895c2 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -380,7 +380,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, ASSERT(GOODREGS(regs)); - bzero((unsigned char *) sii, sizeof(si_info_t)); + memset((unsigned char *) sii, 0, sizeof(si_info_t)); savewin = 0; @@ -510,7 +510,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, ASSERT(GOODREGS(regs)); - bzero((unsigned char *) sii, sizeof(si_info_t)); + memset((unsigned char *) sii, 0, sizeof(si_info_t)); savewin = 0; -- cgit v1.2.3 From a043b26646444eba28e5010965dbf61bc3ba5277 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Tue, 30 Nov 2010 20:32:51 -0800 Subject: staging: brcm80211: bcmp => memcmp s/bcmp/memcmp/ Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_common.c | 2 +- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 8 ++++---- drivers/staging/brcm80211/include/linux_osl.h | 2 -- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 +- drivers/staging/brcm80211/util/bcmsrom.c | 2 +- drivers/staging/brcm80211/util/bcmutils.c | 2 +- drivers/staging/brcm80211/util/nvram/nvram_ro.c | 2 +- 8 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c index e212abb8a357..ce5f9134055c 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c @@ -834,7 +834,7 @@ wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, u16 flags; int evlen; - if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { + if (memcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { DHD_ERROR(("%s: mismatched OUI, bailing\n", __func__)); return BCME_ERROR; } diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index 8bf24c7ce684..e524cd102c41 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -1407,7 +1407,7 @@ static bool ie_is_wpa_ie(u8 **wpaie, u8 **tlvs, int *tlvs_len) u8 *ie = *wpaie; if ((ie[1] >= 6) && - !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { + !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { return true; } @@ -1423,7 +1423,7 @@ static bool ie_is_wps_ie(u8 **wpsie, u8 **tlvs, int *tlvs_len) u8 *ie = *wpsie; if ((ie[1] >= 4) && - !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { + !memcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { return true; } @@ -2669,7 +2669,7 @@ wl_iw_set_pmksa(struct net_device *dev, } for (i = 0; i < pmkid_list.pmkids.npmkid; i++) - if (!bcmp + if (!memcmp (&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) break; @@ -2692,7 +2692,7 @@ wl_iw_set_pmksa(struct net_device *dev, else if (iwpmksa->cmd == IW_PMKSA_ADD) { for (i = 0; i < pmkid_list.pmkids.npmkid; i++) - if (!bcmp + if (!memcmp (&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) break; diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h index ec1c51119637..c2edea4649cb 100644 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ b/drivers/staging/brcm80211/include/linux_osl.h @@ -101,7 +101,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #endif /* bcopy's: Linux kernel doesn't provide these (anymore) */ #define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) /* register access macros */ #if defined(OSLREGOPS) @@ -201,7 +200,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) #define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) /* uncached/cached virtual address */ #ifdef __mips__ diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index 6ea4df64d18e..574d4f3a2084 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -167,7 +167,7 @@ char *phy_getvar(phy_info_t *pi, const char *name) return NULL; for (s = vars; s && *s;) { - if ((bcmp(s, name, len) == 0) && (s[len] == '=')) + if ((memcmp(s, name, len) == 0) && (s[len] == '=')) return &s[len + 1]; while (*s++) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 72a9236d8d86..2a6cf2ab19dd 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -813,7 +813,7 @@ struct antsel_info { dma_getnexttxp((wlc)->hw->di[(_queue)], HNDDMA_RANGE_TRANSMITTED) #define WLC_IS_MATCH_SSID(wlc, ssid1, ssid2, len1, len2) \ - ((len1 == len2) && !bcmp(ssid1, ssid2, len1)) + ((len1 == len2) && !memcmp(ssid1, ssid2, len1)) extern void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus); extern void wlc_fatal_error(wlc_info_t *wlc); diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 77098465d541..3a0beb93c0b6 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -131,7 +131,7 @@ static int varbuf_append(varbuf_t *b, const char *fmt, ...) if (s != NULL) { len = (size_t) (s - b->buf); for (s = b->base; s < b->buf;) { - if ((bcmp(s, b->buf, len) == 0) && s[len] == '=') { + if ((memcmp(s, b->buf, len) == 0) && s[len] == '=') { len = strlen(s) + 1; memmove(s, (s + len), ((b->buf + r + 1) - (s + len))); diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 64d1440a5041..9c4d46764aca 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -379,7 +379,7 @@ char *getvar(char *vars, const char *name) /* first look in vars[] */ for (s = vars; s && *s;) { - if ((bcmp(s, name, len) == 0) && (s[len] == '=')) + if ((memcmp(s, name, len) == 0) && (s[len] == '=')) return &s[len + 1]; while (*s++) diff --git a/drivers/staging/brcm80211/util/nvram/nvram_ro.c b/drivers/staging/brcm80211/util/nvram/nvram_ro.c index 2521c5b19192..e4d41ee78e2a 100644 --- a/drivers/staging/brcm80211/util/nvram/nvram_ro.c +++ b/drivers/staging/brcm80211/util/nvram/nvram_ro.c @@ -133,7 +133,7 @@ static char *findvar(char *vars, char *lim, const char *name) len = strlen(name); for (s = vars; (s < lim) && *s;) { - if ((bcmp(s, name, len) == 0) && (s[len] == '=')) + if ((memcmp(s, name, len) == 0) && (s[len] == '=')) return &s[len + 1]; while (*s++) -- cgit v1.2.3 From 01d11441fd7ede922e10008986ecdb0a84256bc5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 1 Dec 2010 11:16:35 -0800 Subject: staging: brcm80211 needs lots of delay.h Fix lots of errors like: drivers/staging/brcm80211/phy/wlc_phy_n.c:17613: error: implicit declaration of function 'mdelay' drivers/staging/brcm80211/util/nicpci.c:246: error: implicit declaration of function 'udelay' Signed-off-by: Randy Dunlap Cc: Brett Rudley Cc: Henry Ptasinski Cc: Dowan Kim Cc: Roland Vossen Cc: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 1 + drivers/staging/brcm80211/phy/wlc_phy_lcn.c | 1 + drivers/staging/brcm80211/phy/wlc_phy_n.c | 1 + drivers/staging/brcm80211/util/aiutils.c | 1 + drivers/staging/brcm80211/util/bcmotp.c | 1 + drivers/staging/brcm80211/util/hndpmu.c | 1 + drivers/staging/brcm80211/util/nicpci.c | 1 + drivers/staging/brcm80211/util/siutils.c | 1 + 8 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index 574d4f3a2084..b223433482f1 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c index 9492ca5421f8..3ac2b49d9a9d 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_lcn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_lcn.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/phy/wlc_phy_n.c b/drivers/staging/brcm80211/phy/wlc_phy_n.c index 3e1ab579c086..c328de56e59a 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_n.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_n.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c index cf900773fa7d..09e09c9770a9 100644 --- a/drivers/staging/brcm80211/util/aiutils.c +++ b/drivers/staging/brcm80211/util/aiutils.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c index ac25989c8dab..3c625c84619e 100644 --- a/drivers/staging/brcm80211/util/bcmotp.c +++ b/drivers/staging/brcm80211/util/bcmotp.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/hndpmu.c b/drivers/staging/brcm80211/util/hndpmu.c index 5b6fa72b99e8..45f4fdaed0ac 100644 --- a/drivers/staging/brcm80211/util/hndpmu.c +++ b/drivers/staging/brcm80211/util/hndpmu.c @@ -13,6 +13,7 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/nicpci.c b/drivers/staging/brcm80211/util/nicpci.c index 1adac0783369..56e658c429a8 100644 --- a/drivers/staging/brcm80211/util/nicpci.c +++ b/drivers/staging/brcm80211/util/nicpci.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 1a9ff1a895c2..33a42f672af8 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include -- cgit v1.2.3 From 2cb22a7a5624603b9db3571fc65489f5389b512c Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Wed, 1 Dec 2010 21:37:34 +0100 Subject: staging: brcm80211: replaced typedef struct wl_info_t by struct wl_info. Part of the code cleanup effort. CodingStyle doc advises to restrict the usage of typedefs. Also moved several function declarations from .c to .h file because this typedef replace operation induced checkpatch.pl warnings. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 3 +- drivers/staging/brcm80211/include/bcmdefs.h | 3 + drivers/staging/brcm80211/sys/wl_mac80211.c | 109 ++++++++++++------------ drivers/staging/brcm80211/sys/wl_mac80211.h | 10 +-- drivers/staging/brcm80211/sys/wl_ucode.h | 8 ++ drivers/staging/brcm80211/sys/wl_ucode_loader.c | 9 +- 6 files changed, 69 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index e524cd102c41..d8600bfc304e 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -32,14 +32,13 @@ #include #include -typedef void wlc_info_t; -typedef void wl_info_t; typedef const struct si_pub si_t; #include #include #include #include + #define WL_ERROR(x) printf x #define WL_TRACE(x) #define WL_ASSOC(x) diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h index ba1f5e93179b..4ce4486a19a1 100644 --- a/drivers/staging/brcm80211/include/bcmdefs.h +++ b/drivers/staging/brcm80211/include/bcmdefs.h @@ -144,4 +144,7 @@ typedef struct { /* Max. nvram variable table size */ #define MAXSZ_NVRAM_VARS 4096 +/* handle forward declaration */ +struct wl_info; + #endif /* _bcmdefs_h_ */ diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 959ea528245a..364b34986621 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -99,13 +99,13 @@ struct ieee80211_tkip_data { }; #define WL_DEV_IF(dev) ((wl_if_t *)netdev_priv(dev)) -#define WL_INFO(dev) ((wl_info_t *)(WL_DEV_IF(dev)->wl)) /* points to wl */ -static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev); -static void wl_release_fw(wl_info_t *wl); +#define WL_INFO(dev) ((struct wl_info *)(WL_DEV_IF(dev)->wl)) +static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev); +static void wl_release_fw(struct wl_info *wl); /* local prototypes */ -static int wl_start(struct sk_buff *skb, wl_info_t *wl); -static int wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, +static int wl_start(struct sk_buff *skb, struct wl_info *wl); +static int wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, struct sk_buff *skb); static void wl_dpc(unsigned long data); @@ -176,7 +176,7 @@ static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { int status; - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; WL_LOCK(wl); if (!wl->pub->up) { WL_ERROR(("ops->tx called while down\n")); @@ -191,7 +191,7 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl_ops_start(struct ieee80211_hw *hw) { - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; /* struct ieee80211_channel *curchan = hw->conf.channel; */ WL_NONE(("%s : Initial channel: %d\n", __func__, curchan->hw_value)); @@ -204,7 +204,7 @@ static int wl_ops_start(struct ieee80211_hw *hw) static void wl_ops_stop(struct ieee80211_hw *hw) { - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; ASSERT(wl); WL_LOCK(wl); wl_down(wl); @@ -217,7 +217,7 @@ static void wl_ops_stop(struct ieee80211_hw *hw) static int wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - wl_info_t *wl; + struct wl_info *wl; int err; /* Just STA for now */ @@ -251,7 +251,7 @@ static int ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, enum nl80211_channel_type type) { - wl_info_t *wl = HW_TO_WL(hw); + struct wl_info *wl = HW_TO_WL(hw); int err = 0; switch (type) { @@ -276,7 +276,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) { struct ieee80211_conf *conf = &hw->conf; - wl_info_t *wl = HW_TO_WL(hw); + struct wl_info *wl = HW_TO_WL(hw); int err = 0; int new_int; @@ -343,7 +343,7 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { - wl_info_t *wl = HW_TO_WL(hw); + struct wl_info *wl = HW_TO_WL(hw); int val; @@ -413,7 +413,7 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; changed_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS; @@ -500,7 +500,7 @@ static int wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; WL_NONE(("%s: Enter (WME config)\n", __func__)); WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue, @@ -526,7 +526,7 @@ wl_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct scb *scb; int i; - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; /* Init the scb */ scb = (struct scb *)sta->drv_priv; @@ -571,7 +571,7 @@ wl_ampdu_action(struct ieee80211_hw *hw, #if defined(BCMDBG) struct scb *scb = (struct scb *)sta->drv_priv; #endif - wl_info_t *wl = hw->priv; + struct wl_info *wl = hw->priv; ASSERT(scb->magic == SCB_MAGIC); switch (action) { @@ -630,7 +630,7 @@ static const struct ieee80211_ops wl_ops = { .ampdu_action = wl_ampdu_action, }; -static int wl_set_hint(wl_info_t *wl, char *abbrev) +static int wl_set_hint(struct wl_info *wl, char *abbrev) { WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__, abbrev[0], abbrev[1])); @@ -648,10 +648,10 @@ static int wl_set_hint(wl_info_t *wl, char *abbrev) * a warning that this function is defined but not used if we declare * it as static. */ -static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs, +static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, uint bustype, void *btparam, uint irq) { - wl_info_t *wl; + struct wl_info *wl; struct osl_info *osh; int unit, err; @@ -954,7 +954,7 @@ static struct ieee80211_supported_band wl_band_5GHz_nphy = { static int ieee_hw_rate_init(struct ieee80211_hw *hw) { - wl_info_t *wl = HW_TO_WL(hw); + struct wl_info *wl = HW_TO_WL(hw); int has_5g; char phy_list[4]; @@ -1033,7 +1033,7 @@ int __devinit wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc; - wl_info_t *wl; + struct wl_info *wl; struct ieee80211_hw *hw; u32 val; @@ -1062,7 +1062,7 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - hw = ieee80211_alloc_hw(sizeof(wl_info_t), &wl_ops); + hw = ieee80211_alloc_hw(sizeof(struct wl_info), &wl_ops); if (!hw) { WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__)); rc = -ENOMEM; @@ -1092,7 +1092,7 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef LINUXSTA_PS static int wl_suspend(struct pci_dev *pdev, pm_message_t state) { - wl_info_t *wl; + struct wl_info *wl; struct ieee80211_hw *hw; WL_TRACE(("wl: wl_suspend\n")); @@ -1115,7 +1115,7 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state) static int wl_resume(struct pci_dev *pdev) { - wl_info_t *wl; + struct wl_info *wl; struct ieee80211_hw *hw; int err = 0; u32 val; @@ -1154,7 +1154,7 @@ static int wl_resume(struct pci_dev *pdev) static void wl_remove(struct pci_dev *pdev) { - wl_info_t *wl; + struct wl_info *wl; struct ieee80211_hw *hw; hw = pci_get_drvdata(pdev); @@ -1257,7 +1257,7 @@ module_exit(wl_module_exit); * by the wl parameter. * */ -void wl_free(wl_info_t *wl) +void wl_free(struct wl_info *wl) { wl_timer_t *t, *next; struct osl_info *osh; @@ -1316,7 +1316,7 @@ void wl_free(wl_info_t *wl) } /* transmit a packet */ -static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) +static int BCMFASTPATH wl_start(struct sk_buff *skb, struct wl_info *wl) { if (!wl) return -ENETDOWN; @@ -1325,19 +1325,19 @@ static int BCMFASTPATH wl_start(struct sk_buff *skb, wl_info_t *wl) } static int BCMFASTPATH -wl_start_int(wl_info_t *wl, struct ieee80211_hw *hw, struct sk_buff *skb) +wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, struct sk_buff *skb) { wlc_sendpkt_mac80211(wl->wlc, skb, hw); return NETDEV_TX_OK; } -void wl_txflowcontrol(wl_info_t *wl, struct wl_if *wlif, bool state, int prio) +void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, + int prio) { WL_ERROR(("Shouldn't be here %s\n", __func__)); } - -void wl_init(wl_info_t *wl) +void wl_init(struct wl_info *wl) { WL_TRACE(("wl%d: wl_init\n", wl->pub->unit)); @@ -1346,7 +1346,7 @@ void wl_init(wl_info_t *wl) wlc_init(wl->wlc); } -uint wl_reset(wl_info_t *wl) +uint wl_reset(struct wl_info *wl) { WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit)); @@ -1362,7 +1362,7 @@ uint wl_reset(wl_info_t *wl) * These are interrupt on/off entry points. Disable interrupts * during interrupt state transition. */ -void BCMFASTPATH wl_intrson(wl_info_t *wl) +void BCMFASTPATH wl_intrson(struct wl_info *wl) { unsigned long flags; @@ -1371,12 +1371,12 @@ void BCMFASTPATH wl_intrson(wl_info_t *wl) INT_UNLOCK(wl, flags); } -bool wl_alloc_dma_resources(wl_info_t *wl, uint addrwidth) +bool wl_alloc_dma_resources(struct wl_info *wl, uint addrwidth) { return true; } -u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl) +u32 BCMFASTPATH wl_intrsoff(struct wl_info *wl) { unsigned long flags; u32 status; @@ -1387,7 +1387,7 @@ u32 BCMFASTPATH wl_intrsoff(wl_info_t *wl) return status; } -void wl_intrsrestore(wl_info_t *wl, u32 macintmask) +void wl_intrsrestore(struct wl_info *wl, u32 macintmask) { unsigned long flags; @@ -1396,7 +1396,7 @@ void wl_intrsrestore(wl_info_t *wl, u32 macintmask) INT_UNLOCK(wl, flags); } -int wl_up(wl_info_t *wl) +int wl_up(struct wl_info *wl) { int error = 0; @@ -1408,7 +1408,7 @@ int wl_up(wl_info_t *wl) return error; } -void wl_down(wl_info_t *wl) +void wl_down(struct wl_info *wl) { uint callbacks, ret_val = 0; @@ -1429,11 +1429,11 @@ void wl_down(wl_info_t *wl) irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) { - wl_info_t *wl; + struct wl_info *wl; bool ours, wantdpc; unsigned long flags; - wl = (wl_info_t *) dev_id; + wl = (struct wl_info *) dev_id; WL_ISRLOCK(wl, flags); @@ -1457,9 +1457,9 @@ irqreturn_t BCMFASTPATH wl_isr(int irq, void *dev_id) static void BCMFASTPATH wl_dpc(unsigned long data) { - wl_info_t *wl; + struct wl_info *wl; - wl = (wl_info_t *) data; + wl = (struct wl_info *) data; WL_LOCK(wl); @@ -1492,17 +1492,17 @@ static void BCMFASTPATH wl_dpc(unsigned long data) WL_UNLOCK(wl); } -static void wl_link_up(wl_info_t *wl, char *ifname) +static void wl_link_up(struct wl_info *wl, char *ifname) { WL_ERROR(("wl%d: link up (%s)\n", wl->pub->unit, ifname)); } -static void wl_link_down(wl_info_t *wl, char *ifname) +static void wl_link_down(struct wl_info *wl, char *ifname) { WL_ERROR(("wl%d: link down (%s)\n", wl->pub->unit, ifname)); } -void wl_event(wl_info_t *wl, char *ifname, wlc_event_t *e) +void wl_event(struct wl_info *wl, char *ifname, wlc_event_t *e) { switch (e->event.event_type) { @@ -1544,7 +1544,7 @@ static void _wl_timer(wl_timer_t *t) WL_UNLOCK(t->wl); } -wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg, +wl_timer_t *wl_init_timer(struct wl_info *wl, void (*fn) (void *arg), void *arg, const char *name) { wl_timer_t *t; @@ -1578,7 +1578,7 @@ wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn) (void *arg), void *arg, /* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate * as well as it's easier to make it periodic */ -void wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic) +void wl_add_timer(struct wl_info *wl, wl_timer_t *t, uint ms, int periodic) { #ifdef BCMDBG if (t->set) { @@ -1598,7 +1598,7 @@ void wl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic) } /* return true if timer successfully deleted, false if still pending */ -bool wl_del_timer(wl_info_t *wl, wl_timer_t *t) +bool wl_del_timer(struct wl_info *wl, wl_timer_t *t) { if (t->set) { t->set = false; @@ -1611,7 +1611,7 @@ bool wl_del_timer(wl_info_t *wl, wl_timer_t *t) return true; } -void wl_free_timer(wl_info_t *wl, wl_timer_t *t) +void wl_free_timer(struct wl_info *wl, wl_timer_t *t) { wl_timer_t *tmp; @@ -1647,7 +1647,7 @@ void wl_free_timer(wl_info_t *wl, wl_timer_t *t) static int wl_linux_watchdog(void *ctx) { - wl_info_t *wl = (wl_info_t *) ctx; + struct wl_info *wl = (struct wl_info *) ctx; struct net_device_stats *stats = NULL; uint id; /* refresh stats */ @@ -1687,13 +1687,12 @@ struct wl_fw_hdr { u32 idx; }; - char *wl_firmwares[WL_MAX_FW] = { "brcm/bcm43xx", NULL }; -int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx) +int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, u32 idx) { int i, entry; const u8 *pdata; @@ -1719,7 +1718,7 @@ int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx) return -1; } -int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx) +int wl_ucode_init_uint(struct wl_info *wl, u32 *data, u32 idx) { int i, entry; const u8 *pdata; @@ -1740,7 +1739,7 @@ int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx) return -1; } -static int wl_request_fw(wl_info_t *wl, struct pci_dev *pdev) +static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) { int status; struct device *device = &pdev->dev; @@ -1786,7 +1785,7 @@ void wl_ucode_free_buf(void *p) kfree(p); } -static void wl_release_fw(wl_info_t *wl) +static void wl_release_fw(struct wl_info *wl) { int i; for (i = 0; i < WL_MAX_FW; i++) { diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h index 239ef3a0ed9b..87a8128d1b3c 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.h +++ b/drivers/staging/brcm80211/sys/wl_mac80211.h @@ -97,9 +97,6 @@ struct wl_info { #define INT_LOCK(wl, flags) spin_lock_irqsave(&(wl)->isr_lock, flags) #define INT_UNLOCK(wl, flags) spin_unlock_irqrestore(&(wl)->isr_lock, flags) -/* handle forward declaration */ -typedef struct wl_info wl_info_t; - #ifndef PCI_D0 #define PCI_D0 0 #endif @@ -114,12 +111,7 @@ extern irqreturn_t wl_isr(int irq, void *dev_id); extern int __devinit wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -extern void wl_free(wl_info_t *wl); +extern void wl_free(struct wl_info *wl); extern int wl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -extern int wl_ucode_data_init(wl_info_t *wl); -extern void wl_ucode_data_free(void); -extern void wl_ucode_free_buf(void *); -extern int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, u32 idx); -extern int wl_ucode_init_uint(wl_info_t *wl, u32 *data, u32 idx); #endif /* _wl_mac80211_h_ */ diff --git a/drivers/staging/brcm80211/sys/wl_ucode.h b/drivers/staging/brcm80211/sys/wl_ucode.h index a1ba37209f96..b797ab661195 100644 --- a/drivers/staging/brcm80211/sys/wl_ucode.h +++ b/drivers/staging/brcm80211/sys/wl_ucode.h @@ -35,3 +35,11 @@ extern u32 *bcm43xx_24_lcn; extern u32 bcm43xx_24_lcnsz; extern u32 *bcm43xx_bommajor; extern u32 *bcm43xx_bomminor; + +extern int wl_ucode_data_init(struct wl_info *wl); +extern void wl_ucode_data_free(void); + +extern int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, unsigned int idx); +extern int wl_ucode_init_uint(struct wl_info *wl, unsigned *data, + unsigned int idx); +extern void wl_ucode_free_buf(void *); diff --git a/drivers/staging/brcm80211/sys/wl_ucode_loader.c b/drivers/staging/brcm80211/sys/wl_ucode_loader.c index 0b41a9cb1ec9..acd24726b0f0 100644 --- a/drivers/staging/brcm80211/sys/wl_ucode_loader.c +++ b/drivers/staging/brcm80211/sys/wl_ucode_loader.c @@ -14,17 +14,12 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -typedef struct wl_info wl_info_t; #include #include #include #include -extern int wl_ucode_init_buf(wl_info_t *wl, void **pbuf, unsigned int idx); -extern int wl_ucode_init_uint(wl_info_t *wl, unsigned *data, unsigned int idx); -extern int wl_ucode_data_init(wl_info_t *wl); -extern void wl_ucode_data_free(void); -extern void wl_ucode_free_buf(void *); + d11init_t *d11lcn0bsinitvals24; d11init_t *d11lcn0initvals24; @@ -42,7 +37,7 @@ u32 bcm43xx_24_lcnsz; u32 *bcm43xx_bommajor; u32 *bcm43xx_bomminor; -int wl_ucode_data_init(wl_info_t *wl) +int wl_ucode_data_init(struct wl_info *wl) { wl_ucode_init_buf(wl, (void **)&d11lcn0bsinitvals24, D11LCN0BSINITVALS24); -- cgit v1.2.3 From 3bd2e2216bc82a83fc5048f8e61d2d22dd5d9cda Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 30 Nov 2010 10:13:27 +0200 Subject: crypto: omap-aes - DMA initialization fixes for OMAP off mode DMA parameters for constant data were initialized during driver probe(). It seems that those settings sometimes are lost when devices goes to off mode. This patch makes DMA initialization just before use. It solves off mode problems. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 799ca517c121..41c91f3c7f14 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -339,18 +339,6 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd) goto err_dma_out; } - omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - - omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - return 0; err_dma_out: @@ -443,6 +431,12 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, len32 = DIV_ROUND_UP(length, sizeof(u32)); /* IN */ + omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + AES_REG_DATA, 0, 4); + + omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); + omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); + omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32, len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in, OMAP_DMA_DST_SYNC); @@ -451,6 +445,12 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, dma_addr_in, 0, 0); /* OUT */ + omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + AES_REG_DATA, 0, 4); + + omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); + omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32, len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_out, OMAP_DMA_SRC_SYNC); -- cgit v1.2.3 From eeb2b202c5b886b76c3bfa76f47e450fa69389fb Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 30 Nov 2010 10:13:28 +0200 Subject: crypto: omap-aes - redundant locking is removed Submitting request involved double locking for enqueuing and dequeuing. Now it is done under the same lock. FLAGS_BUSY is now handled under the same lock. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 70 ++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 41c91f3c7f14..2d8f72eaf896 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -78,7 +78,7 @@ #define FLAGS_NEW_IV BIT(5) #define FLAGS_INIT BIT(6) #define FLAGS_FAST BIT(7) -#define FLAGS_BUSY 8 +#define FLAGS_BUSY BIT(8) struct omap_aes_ctx { struct omap_aes_dev *dd; @@ -179,9 +179,8 @@ static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit) static int omap_aes_hw_init(struct omap_aes_dev *dd) { - int err = 0; - clk_enable(dd->iclk); + if (!(dd->flags & FLAGS_INIT)) { /* is it necessary to reset before every operation? */ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET, @@ -193,18 +192,15 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd) __asm__ __volatile__("nop"); __asm__ __volatile__("nop"); - err = omap_aes_wait(dd, AES_REG_SYSSTATUS, - AES_REG_SYSSTATUS_RESETDONE); - if (!err) - dd->flags |= FLAGS_INIT; + if (omap_aes_wait(dd, AES_REG_SYSSTATUS, + AES_REG_SYSSTATUS_RESETDONE)) { + clk_disable(dd->iclk); + return -ETIMEDOUT; + } + dd->flags |= FLAGS_INIT; } - return err; -} - -static void omap_aes_hw_cleanup(struct omap_aes_dev *dd) -{ - clk_disable(dd->iclk); + return 0; } static void omap_aes_write_ctrl(struct omap_aes_dev *dd) @@ -538,6 +534,8 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) pr_debug("err: %d\n", err); + dd->flags &= ~FLAGS_BUSY; + ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req)); if (!dd->total) @@ -553,7 +551,7 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START); - omap_aes_hw_cleanup(dd); + clk_disable(dd->iclk); omap_stop_dma(dd->dma_lch_in); omap_stop_dma(dd->dma_lch_out); @@ -580,22 +578,26 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) return err; } -static int omap_aes_handle_req(struct omap_aes_dev *dd) +static int omap_aes_handle_req(struct omap_aes_dev *dd, + struct ablkcipher_request *req) { struct crypto_async_request *async_req, *backlog; struct omap_aes_ctx *ctx; struct omap_aes_reqctx *rctx; - struct ablkcipher_request *req; unsigned long flags; - - if (dd->total) - goto start; + int err = 0; spin_lock_irqsave(&dd->lock, flags); + if (req) + err = ablkcipher_enqueue_request(&dd->queue, req); + if (dd->flags & FLAGS_BUSY) { + spin_unlock_irqrestore(&dd->lock, flags); + return err; + } backlog = crypto_get_backlog(&dd->queue); async_req = crypto_dequeue_request(&dd->queue); - if (!async_req) - clear_bit(FLAGS_BUSY, &dd->flags); + if (async_req) + dd->flags |= FLAGS_BUSY; spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) @@ -637,20 +639,23 @@ static int omap_aes_handle_req(struct omap_aes_dev *dd) if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) pr_err("request size is not exact amount of AES blocks\n"); -start: - return omap_aes_crypt_dma_start(dd); + omap_aes_crypt_dma_start(dd); + + return err; } static void omap_aes_task(unsigned long data) { struct omap_aes_dev *dd = (struct omap_aes_dev *)data; - int err; pr_debug("enter\n"); - err = omap_aes_crypt_dma_stop(dd); + omap_aes_crypt_dma_stop(dd); - err = omap_aes_handle_req(dd); + if (dd->total) + omap_aes_crypt_dma_start(dd); + else + omap_aes_handle_req(dd, NULL); pr_debug("exit\n"); } @@ -661,8 +666,6 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) crypto_ablkcipher_reqtfm(req)); struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req); struct omap_aes_dev *dd; - unsigned long flags; - int err; pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes, !!(mode & FLAGS_ENCRYPT), @@ -674,16 +677,7 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) rctx->mode = mode; - spin_lock_irqsave(&dd->lock, flags); - err = ablkcipher_enqueue_request(&dd->queue, req); - spin_unlock_irqrestore(&dd->lock, flags); - - if (!test_and_set_bit(FLAGS_BUSY, &dd->flags)) - omap_aes_handle_req(dd); - - pr_debug("exit\n"); - - return err; + return omap_aes_handle_req(dd, req); } /* ********************** ALG API ************************************ */ -- cgit v1.2.3 From 21fe9767f3bd56fd9a271dc43b93cd4608d47f4a Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 30 Nov 2010 10:13:29 +0200 Subject: crypto: omap-aes - error handling implementation improved Previous version had not error handling. Request could remain uncompleted. Also in the case of DMA error, FLAGS_INIT is unset and accelerator will be initialized again. Buffer size allignment is checked. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 134 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 2d8f72eaf896..704cc701ab42 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -103,14 +103,16 @@ struct omap_aes_dev { struct omap_aes_ctx *ctx; struct device *dev; unsigned long flags; + int err; u32 *iv; u32 ctrl; - spinlock_t lock; - struct crypto_queue queue; + spinlock_t lock; + struct crypto_queue queue; - struct tasklet_struct task; + struct tasklet_struct done_task; + struct tasklet_struct queue_task; struct ablkcipher_request *req; size_t total; @@ -198,24 +200,30 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd) return -ETIMEDOUT; } dd->flags |= FLAGS_INIT; + dd->err = 0; } return 0; } -static void omap_aes_write_ctrl(struct omap_aes_dev *dd) +static int omap_aes_write_ctrl(struct omap_aes_dev *dd) { unsigned int key32; - int i; + int i, err, init = dd->flags & FLAGS_INIT; u32 val, mask; + err = omap_aes_hw_init(dd); + if (err) + return err; + val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); if (dd->flags & FLAGS_CBC) val |= AES_REG_CTRL_CBC; if (dd->flags & FLAGS_ENCRYPT) val |= AES_REG_CTRL_DIRECTION; - if (dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) && + /* check if hw state & mode have not changed */ + if (init && dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) && !(dd->ctx->flags & FLAGS_NEW_KEY)) goto out; @@ -257,6 +265,8 @@ out: /* start DMA or disable idle mode */ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, AES_REG_MASK_START); + + return 0; } static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx) @@ -284,8 +294,16 @@ static void omap_aes_dma_callback(int lch, u16 ch_status, void *data) { struct omap_aes_dev *dd = data; - if (lch == dd->dma_lch_out) - tasklet_schedule(&dd->task); + if (ch_status != OMAP_DMA_BLOCK_IRQ) { + pr_err("omap-aes DMA error status: 0x%hx\n", ch_status); + dd->err = -EIO; + dd->flags &= ~FLAGS_INIT; /* request to re-initialize */ + } else if (lch == dd->dma_lch_in) { + return; + } + + /* dma_lch_out - completed */ + tasklet_schedule(&dd->done_task); } static int omap_aes_dma_init(struct omap_aes_dev *dd) @@ -390,6 +408,11 @@ static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf, if (!count) return off; + /* + * buflen and total are AES_BLOCK_SIZE size aligned, + * so count should be also aligned + */ + sg_copy_buf(buf + off, *sg, *offset, count, out); off += count; @@ -415,6 +438,7 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); struct omap_aes_dev *dd = ctx->dd; int len32; + int err; pr_debug("len: %d\n", length); @@ -454,11 +478,13 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC, dma_addr_out, 0, 0); + err = omap_aes_write_ctrl(dd); + if (err) + return err; + omap_start_dma(dd->dma_lch_in); omap_start_dma(dd->dma_lch_out); - omap_aes_write_ctrl(dd); - return 0; } @@ -484,8 +510,10 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) count = min(dd->total, sg_dma_len(dd->in_sg)); count = min(count, sg_dma_len(dd->out_sg)); - if (count != dd->total) + if (count != dd->total) { + pr_err("request length != buffer length\n"); return -EINVAL; + } pr_debug("fast\n"); @@ -521,25 +549,28 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) dd->total -= count; - err = omap_aes_hw_init(dd); - err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count); + if (err) { + dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); + dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE); + } return err; } static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) { + struct ablkcipher_request *req = dd->req; struct omap_aes_ctx *ctx; pr_debug("err: %d\n", err); dd->flags &= ~FLAGS_BUSY; - ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req)); + ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); - if (!dd->total) - dd->req->base.complete(&dd->req->base, err); + if (req->base.complete) + req->base.complete(&req->base, err); } static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) @@ -551,11 +582,11 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START); - clk_disable(dd->iclk); - omap_stop_dma(dd->dma_lch_in); omap_stop_dma(dd->dma_lch_out); + clk_disable(dd->iclk); + if (dd->flags & FLAGS_FAST) { dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); @@ -572,27 +603,24 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) } } - if (err || !dd->total) - omap_aes_finish_req(dd, err); - return err; } -static int omap_aes_handle_req(struct omap_aes_dev *dd, +static int omap_aes_handle_queue(struct omap_aes_dev *dd, struct ablkcipher_request *req) { struct crypto_async_request *async_req, *backlog; struct omap_aes_ctx *ctx; struct omap_aes_reqctx *rctx; unsigned long flags; - int err = 0; + int err, ret = 0; spin_lock_irqsave(&dd->lock, flags); if (req) - err = ablkcipher_enqueue_request(&dd->queue, req); + ret = ablkcipher_enqueue_request(&dd->queue, req); if (dd->flags & FLAGS_BUSY) { spin_unlock_irqrestore(&dd->lock, flags); - return err; + return ret; } backlog = crypto_get_backlog(&dd->queue); async_req = crypto_dequeue_request(&dd->queue); @@ -601,7 +629,7 @@ static int omap_aes_handle_req(struct omap_aes_dev *dd, spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) - return 0; + return ret; if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -636,30 +664,46 @@ static int omap_aes_handle_req(struct omap_aes_dev *dd, ctx->flags |= FLAGS_NEW_KEY; } - if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) - pr_err("request size is not exact amount of AES blocks\n"); - - omap_aes_crypt_dma_start(dd); + err = omap_aes_crypt_dma_start(dd); + if (err) { + /* aes_task will not finish it, so do it here */ + omap_aes_finish_req(dd, err); + tasklet_schedule(&dd->queue_task); + } - return err; + return ret; /* return ret, which is enqueue return value */ } -static void omap_aes_task(unsigned long data) +static void omap_aes_done_task(unsigned long data) { struct omap_aes_dev *dd = (struct omap_aes_dev *)data; + int err; pr_debug("enter\n"); - omap_aes_crypt_dma_stop(dd); + err = omap_aes_crypt_dma_stop(dd); - if (dd->total) - omap_aes_crypt_dma_start(dd); - else - omap_aes_handle_req(dd, NULL); + err = dd->err ? : err; + + if (dd->total && !err) { + err = omap_aes_crypt_dma_start(dd); + if (!err) + return; /* DMA started. Not fininishing. */ + } + + omap_aes_finish_req(dd, err); + omap_aes_handle_queue(dd, NULL); pr_debug("exit\n"); } +static void omap_aes_queue_task(unsigned long data) +{ + struct omap_aes_dev *dd = (struct omap_aes_dev *)data; + + omap_aes_handle_queue(dd, NULL); +} + static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) { struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx( @@ -671,13 +715,18 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); + if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { + pr_err("request size is not exact amount of AES blocks\n"); + return -EINVAL; + } + dd = omap_aes_find_dev(ctx); if (!dd) return -ENODEV; rctx->mode = mode; - return omap_aes_handle_req(dd, req); + return omap_aes_handle_queue(dd, req); } /* ********************** ALG API ************************************ */ @@ -843,7 +892,8 @@ static int omap_aes_probe(struct platform_device *pdev) (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR); clk_disable(dd->iclk); - tasklet_init(&dd->task, omap_aes_task, (unsigned long)dd); + tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd); + tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd); err = omap_aes_dma_init(dd); if (err) @@ -870,7 +920,8 @@ err_algs: crypto_unregister_alg(&algs[j]); omap_aes_dma_cleanup(dd); err_dma: - tasklet_kill(&dd->task); + tasklet_kill(&dd->done_task); + tasklet_kill(&dd->queue_task); iounmap(dd->io_base); err_io: clk_put(dd->iclk); @@ -897,7 +948,8 @@ static int omap_aes_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(algs); i++) crypto_unregister_alg(&algs[i]); - tasklet_kill(&dd->task); + tasklet_kill(&dd->done_task); + tasklet_kill(&dd->queue_task); omap_aes_dma_cleanup(dd); iounmap(dd->io_base); clk_put(dd->iclk); -- cgit v1.2.3 From 67a730ce449561f6df838f0b38a2b72cbf4e3c4c Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 30 Nov 2010 10:13:30 +0200 Subject: crypto: omap-aes - unnecessary code removed Key and IV should always be set before AES operation. So no need to check if it has changed or not. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 70 ++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 704cc701ab42..0b21dcef0289 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -74,11 +74,9 @@ #define FLAGS_CBC BIT(1) #define FLAGS_GIV BIT(2) -#define FLAGS_NEW_KEY BIT(4) -#define FLAGS_NEW_IV BIT(5) -#define FLAGS_INIT BIT(6) -#define FLAGS_FAST BIT(7) -#define FLAGS_BUSY BIT(8) +#define FLAGS_INIT BIT(4) +#define FLAGS_FAST BIT(5) +#define FLAGS_BUSY BIT(6) struct omap_aes_ctx { struct omap_aes_dev *dd; @@ -105,9 +103,6 @@ struct omap_aes_dev { unsigned long flags; int err; - u32 *iv; - u32 ctrl; - spinlock_t lock; struct crypto_queue queue; @@ -209,28 +204,13 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd) static int omap_aes_write_ctrl(struct omap_aes_dev *dd) { unsigned int key32; - int i, err, init = dd->flags & FLAGS_INIT; + int i, err; u32 val, mask; err = omap_aes_hw_init(dd); if (err) return err; - val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); - if (dd->flags & FLAGS_CBC) - val |= AES_REG_CTRL_CBC; - if (dd->flags & FLAGS_ENCRYPT) - val |= AES_REG_CTRL_DIRECTION; - - /* check if hw state & mode have not changed */ - if (init && dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) && - !(dd->ctx->flags & FLAGS_NEW_KEY)) - goto out; - - /* only need to write control registers for new settings */ - - dd->ctrl = val; - val = 0; if (dd->dma_lch_out >= 0) val |= AES_REG_MASK_DMA_OUT_EN; @@ -241,27 +221,28 @@ static int omap_aes_write_ctrl(struct omap_aes_dev *dd) omap_aes_write_mask(dd, AES_REG_MASK, val, mask); - pr_debug("Set key\n"); key32 = dd->ctx->keylen / sizeof(u32); - /* set a key */ + + /* it seems a key should always be set even if it has not changed */ for (i = 0; i < key32; i++) { omap_aes_write(dd, AES_REG_KEY(i), __le32_to_cpu(dd->ctx->key[i])); } - dd->ctx->flags &= ~FLAGS_NEW_KEY; - if (dd->flags & FLAGS_NEW_IV) { - pr_debug("Set IV\n"); - omap_aes_write_n(dd, AES_REG_IV(0), dd->iv, 4); - dd->flags &= ~FLAGS_NEW_IV; - } + if ((dd->flags & FLAGS_CBC) && dd->req->info) + omap_aes_write_n(dd, AES_REG_IV(0), dd->req->info, 4); + + val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); + if (dd->flags & FLAGS_CBC) + val |= AES_REG_CTRL_CBC; + if (dd->flags & FLAGS_ENCRYPT) + val |= AES_REG_CTRL_DIRECTION; mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION | AES_REG_CTRL_KEY_SIZE; - omap_aes_write_mask(dd, AES_REG_CTRL, dd->ctrl, mask); + omap_aes_write_mask(dd, AES_REG_CTRL, val, mask); -out: /* start DMA or disable idle mode */ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, AES_REG_MASK_START); @@ -561,16 +542,12 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) { struct ablkcipher_request *req = dd->req; - struct omap_aes_ctx *ctx; pr_debug("err: %d\n", err); dd->flags &= ~FLAGS_BUSY; - ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); - - if (req->base.complete) - req->base.complete(&req->base, err); + req->base.complete(&req->base, err); } static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) @@ -636,8 +613,6 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd, req = ablkcipher_request_cast(async_req); - pr_debug("get new req\n"); - /* assign new request to device */ dd->req = req; dd->total = req->nbytes; @@ -651,18 +626,8 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd, rctx->mode &= FLAGS_MODE_MASK; dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; - dd->iv = req->info; - if ((dd->flags & FLAGS_CBC) && dd->iv) - dd->flags |= FLAGS_NEW_IV; - else - dd->flags &= ~FLAGS_NEW_IV; - + dd->ctx = ctx; ctx->dd = dd; - if (dd->ctx != ctx) { - /* assign new context to device */ - dd->ctx = ctx; - ctx->flags |= FLAGS_NEW_KEY; - } err = omap_aes_crypt_dma_start(dd); if (err) { @@ -744,7 +709,6 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, memcpy(ctx->key, key, keylen); ctx->keylen = keylen; - ctx->flags |= FLAGS_NEW_KEY; return 0; } -- cgit v1.2.3 From 83ea7e0fe1471508ab8e8d7b317e743fe7a05a5f Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 30 Nov 2010 10:13:31 +0200 Subject: crypto: omap-aes - initialize aes module once per request AES module was initialized for every DMA transaction. That is redundant. Now it is initialized once per request. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 54 ++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 0b21dcef0289..b69da4f07c89 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -176,6 +176,11 @@ static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit) static int omap_aes_hw_init(struct omap_aes_dev *dd) { + /* + * clocks are enabled when request starts and disabled when finished. + * It may be long delays between requests. + * Device might go to off mode to save power. + */ clk_enable(dd->iclk); if (!(dd->flags & FLAGS_INIT)) { @@ -190,10 +195,9 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd) __asm__ __volatile__("nop"); if (omap_aes_wait(dd, AES_REG_SYSSTATUS, - AES_REG_SYSSTATUS_RESETDONE)) { - clk_disable(dd->iclk); + AES_REG_SYSSTATUS_RESETDONE)) return -ETIMEDOUT; - } + dd->flags |= FLAGS_INIT; dd->err = 0; } @@ -243,9 +247,19 @@ static int omap_aes_write_ctrl(struct omap_aes_dev *dd) omap_aes_write_mask(dd, AES_REG_CTRL, val, mask); - /* start DMA or disable idle mode */ - omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, - AES_REG_MASK_START); + /* IN */ + omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + AES_REG_DATA, 0, 4); + + omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); + omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); + + /* OUT */ + omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + AES_REG_DATA, 0, 4); + + omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); return 0; } @@ -419,7 +433,6 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm); struct omap_aes_dev *dd = ctx->dd; int len32; - int err; pr_debug("len: %d\n", length); @@ -432,12 +445,6 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, len32 = DIV_ROUND_UP(length, sizeof(u32)); /* IN */ - omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32, len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in, OMAP_DMA_DST_SYNC); @@ -446,12 +453,6 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, dma_addr_in, 0, 0); /* OUT */ - omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32, len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_out, OMAP_DMA_SRC_SYNC); @@ -459,13 +460,13 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC, dma_addr_out, 0, 0); - err = omap_aes_write_ctrl(dd); - if (err) - return err; - omap_start_dma(dd->dma_lch_in); omap_start_dma(dd->dma_lch_out); + /* start DMA or disable idle mode */ + omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, + AES_REG_MASK_START); + return 0; } @@ -545,6 +546,7 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) pr_debug("err: %d\n", err); + clk_disable(dd->iclk); dd->flags &= ~FLAGS_BUSY; req->base.complete(&req->base, err); @@ -562,8 +564,6 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) omap_stop_dma(dd->dma_lch_in); omap_stop_dma(dd->dma_lch_out); - clk_disable(dd->iclk); - if (dd->flags & FLAGS_FAST) { dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); @@ -629,7 +629,9 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd, dd->ctx = ctx; ctx->dd = dd; - err = omap_aes_crypt_dma_start(dd); + err = omap_aes_write_ctrl(dd); + if (!err) + err = omap_aes_crypt_dma_start(dd); if (err) { /* aes_task will not finish it, so do it here */ omap_aes_finish_req(dd, err); -- cgit v1.2.3 From efce41b65f66251d60484781df305e8a85c9507b Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 30 Nov 2010 10:13:32 +0200 Subject: crypto: omap-aes - checkpatch --file warning fixes Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index b69da4f07c89..add2a1a72ba4 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -96,7 +96,7 @@ struct omap_aes_reqctx { struct omap_aes_dev { struct list_head list; unsigned long phys_base; - void __iomem *io_base; + void __iomem *io_base; struct clk *iclk; struct omap_aes_ctx *ctx; struct device *dev; @@ -759,7 +759,7 @@ static struct crypto_alg algs[] = { .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), - .cra_alignmask = 0, + .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, .cra_init = omap_aes_cra_init, @@ -779,7 +779,7 @@ static struct crypto_alg algs[] = { .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), - .cra_alignmask = 0, + .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, .cra_init = omap_aes_cra_init, -- cgit v1.2.3 From 87ca9c8a7ea9c8c7ce1561edaad1aa8570f1a01e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 2 Dec 2010 09:42:56 +0000 Subject: drm/i915: Prevent stalling for a GTT read back from a read-only GPU target Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++++ drivers/gpu/drm/i915/i915_gem.c | 9 ++++++--- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 590d8f2d0958..7b37c198cb19 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -728,6 +728,12 @@ struct drm_i915_gem_object { */ unsigned int dirty : 1; + /** + * This is set if the object has been written to since the last + * GPU flush. + */ + unsigned int pending_gpu_write : 1; + /** * Fence register bits (if any) for this object. Will be set * as needed when mapped into the GTT. diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index eae52de75a4c..c3e6d7bda6e1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1643,6 +1643,7 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) obj->last_fenced_ring = NULL; obj->active = 0; + obj->pending_gpu_write = false; drm_gem_object_unreference(&obj->base); WARN_ON(i915_verify_lists(dev)); @@ -2810,9 +2811,11 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) return -EINVAL; i915_gem_object_flush_gpu_write_domain(obj); - ret = i915_gem_object_wait_rendering(obj, true); - if (ret) - return ret; + if (obj->pending_gpu_write || write) { + ret = i915_gem_object_wait_rendering(obj, true); + if (ret) + return ret; + } i915_gem_object_flush_cpu_write_domain(obj); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f57536a70a3a..af01a58a643b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -775,6 +775,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, i915_gem_object_move_to_active(obj, ring); if (obj->base.write_domain) { obj->dirty = 1; + obj->pending_gpu_write = true; list_move_tail(&obj->gpu_write_list, &ring->gpu_write_list); intel_mark_busy(ring->dev, obj); -- cgit v1.2.3 From d9e86c0ee60f323e890484628f351bf50fa9a15d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 10 Nov 2010 16:40:20 +0000 Subject: drm/i915: Pipelined fencing [infrastructure] With this change, every batchbuffer can use all available fences (save pinned and scanout, of course) without ever stalling the gpu! In theory. Currently the actual pipelined update of the register is disabled due to some stability issues. However, just the deferred update is a significant win. Based on a series of patches by Daniel Vetter. The premise is that before every access to a buffer through the GTT we have to declare whether we need a register or not. If the access is by the GPU, a pipelined update to the register is made via the ringbuffer, and we track the last seqno of the batches that access it. If by the CPU we wait for the last GPU access and update the register (either to clear or to set it for the current buffer). One advantage of being able to pipeline changes is that we can defer the actual updating of the fence register until we first need to access the object through the GTT, i.e. we can eliminate the stall on set_tiling. This is important as the userspace bo cache does not track the tiling status of active buffers which generate frequent stalls on gen3 when enabling tiling for an already bound buffer. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 +- drivers/gpu/drm/i915/i915_gem.c | 360 ++++++++++++++++++----------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 20 +- drivers/gpu/drm/i915/i915_gem_tiling.c | 23 +- drivers/gpu/drm/i915/intel_display.c | 17 +- drivers/gpu/drm/i915/intel_overlay.c | 10 + 6 files changed, 274 insertions(+), 166 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7b37c198cb19..af9ff40b135b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -126,6 +126,7 @@ struct drm_i915_master_private { struct drm_i915_fence_reg { struct list_head lru_list; struct drm_i915_gem_object *obj; + uint32_t setup_seqno; }; struct sdvo_device_mapping { @@ -752,6 +753,7 @@ struct drm_i915_gem_object { * Current tiling mode for the object. */ unsigned int tiling_mode : 2; + unsigned int tiling_changed : 1; /** How many users have pinned this object in GTT space. The following * users can each hold at most one reference: pwrite/pread, pin_ioctl @@ -1121,10 +1123,10 @@ i915_gem_next_request_seqno(struct drm_device *dev, return ring->outstanding_lazy_request = dev_priv->next_seqno; } -int __must_check i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, - bool interruptible); -int __must_check i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, - bool interruptible); +int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined, + bool interruptible); +int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_reset(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c3e6d7bda6e1..23d2417a3585 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -47,7 +47,8 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_obje static int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable); -static void i915_gem_clear_fence_reg(struct drm_i915_gem_object *obj); +static void i915_gem_clear_fence_reg(struct drm_device *dev, + struct drm_i915_fence_reg *reg); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -684,7 +685,11 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, goto out_unpin_pages; } - ret = i915_gem_object_set_to_gtt_domain(obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + goto out_unpin_pages; + + ret = i915_gem_object_put_fence(obj); if (ret) goto out_unpin_pages; @@ -966,14 +971,17 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, */ if (obj->phys_obj) ret = i915_gem_phys_pwrite(dev, obj, args, file); - else if (obj->tiling_mode == I915_TILING_NONE && - obj->gtt_space && + else if (obj->gtt_space && obj->base.write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_object_pin(obj, 0, true); if (ret) goto out; - ret = i915_gem_object_set_to_gtt_domain(obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + goto out_unpin; + + ret = i915_gem_object_put_fence(obj); if (ret) goto out_unpin; @@ -1205,12 +1213,12 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (ret) goto unlock; - /* Need a new fence register? */ - if (obj->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, true); - if (ret) - goto unlock; - } + if (obj->tiling_mode == I915_TILING_NONE) + ret = i915_gem_object_put_fence(obj); + else + ret = i915_gem_object_get_fence(obj, NULL, true); + if (ret) + goto unlock; if (i915_gem_object_is_inactive(obj)) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); @@ -1608,7 +1616,6 @@ i915_gem_object_move_off_active(struct drm_i915_gem_object *obj) { list_del_init(&obj->ring_list); obj->last_rendering_seqno = 0; - obj->last_fenced_seqno = 0; } static void @@ -1640,7 +1647,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) i915_gem_object_move_off_active(obj); obj->fenced_gpu_access = false; - obj->last_fenced_ring = NULL; obj->active = 0; obj->pending_gpu_write = false; @@ -1803,7 +1809,11 @@ static void i915_gem_reset_fences(struct drm_device *dev) if (obj->tiling_mode) i915_gem_release_mmap(obj); - i915_gem_clear_fence_reg(obj); + reg->obj->fence_reg = I915_FENCE_REG_NONE; + reg->obj->fenced_gpu_access = false; + reg->obj->last_fenced_seqno = 0; + reg->obj->last_fenced_ring = NULL; + i915_gem_clear_fence_reg(dev, reg); } } @@ -2114,8 +2124,9 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) } /* release the fence reg _after_ flushing */ - if (obj->fence_reg != I915_FENCE_REG_NONE) - i915_gem_clear_fence_reg(obj); + ret = i915_gem_object_put_fence(obj); + if (ret == -ERESTARTSYS) + return ret; i915_gem_gtt_unbind_object(obj); i915_gem_object_put_pages_gtt(obj); @@ -2357,59 +2368,118 @@ static int i830_write_fence_reg(struct drm_i915_gem_object *obj, return 0; } -static int i915_find_fence_reg(struct drm_device *dev, - bool interruptible) +static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + return i915_seqno_passed(ring->get_seqno(ring), seqno); +} + +static int +i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined, + bool interruptible) +{ + int ret; + + if (obj->fenced_gpu_access) { + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) + i915_gem_flush_ring(obj->base.dev, + obj->last_fenced_ring, + 0, obj->base.write_domain); + + obj->fenced_gpu_access = false; + } + + if (obj->last_fenced_seqno && pipelined != obj->last_fenced_ring) { + if (!ring_passed_seqno(obj->last_fenced_ring, + obj->last_fenced_seqno)) { + ret = i915_do_wait_request(obj->base.dev, + obj->last_fenced_seqno, + interruptible, + obj->last_fenced_ring); + if (ret) + return ret; + } + + obj->last_fenced_seqno = 0; + obj->last_fenced_ring = NULL; + } + + return 0; +} + +int +i915_gem_object_put_fence(struct drm_i915_gem_object *obj) +{ + int ret; + + if (obj->tiling_mode) + i915_gem_release_mmap(obj); + + ret = i915_gem_object_flush_fence(obj, NULL, true); + if (ret) + return ret; + + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + i915_gem_clear_fence_reg(obj->base.dev, + &dev_priv->fence_regs[obj->fence_reg]); + + obj->fence_reg = I915_FENCE_REG_NONE; + } + + return 0; +} + +static struct drm_i915_fence_reg * +i915_find_fence_reg(struct drm_device *dev, + struct intel_ring_buffer *pipelined) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg; - struct drm_i915_gem_object *obj = NULL; - int i, avail, ret; + struct drm_i915_fence_reg *reg, *first, *avail; + int i; /* First try to find a free reg */ - avail = 0; + avail = NULL; for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { reg = &dev_priv->fence_regs[i]; if (!reg->obj) - return i; + return reg; if (!reg->obj->pin_count) - avail++; + avail = reg; } - if (avail == 0) - return -ENOSPC; + if (avail == NULL) + return NULL; /* None available, try to steal one or wait for a user to finish */ - avail = I915_FENCE_REG_NONE; - list_for_each_entry(reg, &dev_priv->mm.fence_list, - lru_list) { - obj = reg->obj; - if (obj->pin_count) + avail = first = NULL; + list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { + if (reg->obj->pin_count) continue; - /* found one! */ - avail = obj->fence_reg; - break; - } + if (first == NULL) + first = reg; - BUG_ON(avail == I915_FENCE_REG_NONE); + if (!pipelined || + !reg->obj->last_fenced_ring || + reg->obj->last_fenced_ring == pipelined) { + avail = reg; + break; + } + } - /* We only have a reference on obj from the active list. put_fence_reg - * might drop that one, causing a use-after-free in it. So hold a - * private reference to obj like the other callers of put_fence_reg - * (set_tiling ioctl) do. */ - drm_gem_object_reference(&obj->base); - ret = i915_gem_object_put_fence_reg(obj, interruptible); - drm_gem_object_unreference(&obj->base); - if (ret != 0) - return ret; + if (avail == NULL) + avail = first; return avail; } /** - * i915_gem_object_get_fence_reg - set up a fence reg for an object + * i915_gem_object_get_fence - set up a fence reg for an object * @obj: object to map through a fence reg + * @pipelined: ring on which to queue the change, or NULL for CPU access + * @interruptible: must we wait uninterruptibly for the register to retire? * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. @@ -2421,52 +2491,119 @@ static int i915_find_fence_reg(struct drm_device *dev, * and tiling format. */ int -i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, - bool interruptible) +i915_gem_object_get_fence(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *pipelined, + bool interruptible) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg = NULL; - struct intel_ring_buffer *pipelined = NULL; + struct drm_i915_fence_reg *reg; int ret; - /* Just update our place in the LRU if our fence is getting used. */ + /* Just update our place in the LRU if our fence is getting reused. */ if (obj->fence_reg != I915_FENCE_REG_NONE) { reg = &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); + + if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) + pipelined = NULL; + + if (!pipelined) { + if (reg->setup_seqno) { + if (!ring_passed_seqno(obj->last_fenced_ring, + reg->setup_seqno)) { + ret = i915_do_wait_request(obj->base.dev, + reg->setup_seqno, + interruptible, + obj->last_fenced_ring); + if (ret) + return ret; + } + + reg->setup_seqno = 0; + } + } else if (obj->last_fenced_ring && + obj->last_fenced_ring != pipelined) { + ret = i915_gem_object_flush_fence(obj, + pipelined, + interruptible); + if (ret) + return ret; + } else if (obj->tiling_changed) { + if (obj->fenced_gpu_access) { + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) + i915_gem_flush_ring(obj->base.dev, obj->ring, + 0, obj->base.write_domain); + + obj->fenced_gpu_access = false; + } + } + + if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) + pipelined = NULL; + BUG_ON(!pipelined && reg->setup_seqno); + + if (obj->tiling_changed) { + if (pipelined) { + reg->setup_seqno = + i915_gem_next_request_seqno(dev, pipelined); + obj->last_fenced_seqno = reg->setup_seqno; + obj->last_fenced_ring = pipelined; + } + goto update; + } + return 0; } - switch (obj->tiling_mode) { - case I915_TILING_NONE: - WARN(1, "allocating a fence for non-tiled object?\n"); - break; - case I915_TILING_X: - if (!obj->stride) - return -EINVAL; - WARN((obj->stride & (512 - 1)), - "object 0x%08x is X tiled but has non-512B pitch\n", - obj->gtt_offset); - break; - case I915_TILING_Y: - if (!obj->stride) - return -EINVAL; - WARN((obj->stride & (128 - 1)), - "object 0x%08x is Y tiled but has non-128B pitch\n", - obj->gtt_offset); - break; - } + reg = i915_find_fence_reg(dev, pipelined); + if (reg == NULL) + return -ENOSPC; - ret = i915_find_fence_reg(dev, interruptible); - if (ret < 0) + ret = i915_gem_object_flush_fence(obj, pipelined, interruptible); + if (ret) return ret; - obj->fence_reg = ret; - reg = &dev_priv->fence_regs[obj->fence_reg]; - list_add_tail(®->lru_list, &dev_priv->mm.fence_list); + if (reg->obj) { + struct drm_i915_gem_object *old = reg->obj; + + drm_gem_object_reference(&old->base); + + if (old->tiling_mode) + i915_gem_release_mmap(old); + + /* XXX The pipelined change over appears to be incoherent. */ + ret = i915_gem_object_flush_fence(old, + NULL, //pipelined, + interruptible); + if (ret) { + drm_gem_object_unreference(&old->base); + return ret; + } + + if (old->last_fenced_seqno == 0 && obj->last_fenced_seqno == 0) + pipelined = NULL; + + old->fence_reg = I915_FENCE_REG_NONE; + old->last_fenced_ring = pipelined; + old->last_fenced_seqno = + pipelined ? i915_gem_next_request_seqno(dev, pipelined) : 0; + + drm_gem_object_unreference(&old->base); + } else if (obj->last_fenced_seqno == 0) + pipelined = NULL; reg->obj = obj; + list_move_tail(®->lru_list, &dev_priv->mm.fence_list); + obj->fence_reg = reg - dev_priv->fence_regs; + obj->last_fenced_ring = pipelined; + reg->setup_seqno = + pipelined ? i915_gem_next_request_seqno(dev, pipelined) : 0; + obj->last_fenced_seqno = reg->setup_seqno; + +update: + obj->tiling_changed = false; switch (INTEL_INFO(dev)->gen) { case 6: ret = sandybridge_write_fence_reg(obj, pipelined); @@ -2497,87 +2634,34 @@ i915_gem_object_get_fence_reg(struct drm_i915_gem_object *obj, * data structures in dev_priv and obj. */ static void -i915_gem_clear_fence_reg(struct drm_i915_gem_object *obj) +i915_gem_clear_fence_reg(struct drm_device *dev, + struct drm_i915_fence_reg *reg) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[obj->fence_reg]; - uint32_t fence_reg; + uint32_t fence_reg = reg - dev_priv->fence_regs; switch (INTEL_INFO(dev)->gen) { case 6: - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + - (obj->fence_reg * 8), 0); + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0); break; case 5: case 4: - I915_WRITE64(FENCE_REG_965_0 + (obj->fence_reg * 8), 0); + I915_WRITE64(FENCE_REG_965_0 + fence_reg*8, 0); break; case 3: - if (obj->fence_reg >= 8) - fence_reg = FENCE_REG_945_8 + (obj->fence_reg - 8) * 4; + if (fence_reg >= 8) + fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; else case 2: - fence_reg = FENCE_REG_830_0 + obj->fence_reg * 4; + fence_reg = FENCE_REG_830_0 + fence_reg * 4; I915_WRITE(fence_reg, 0); break; } - reg->obj = NULL; - obj->fence_reg = I915_FENCE_REG_NONE; list_del_init(®->lru_list); -} - -/** - * i915_gem_object_put_fence_reg - waits on outstanding fenced access - * to the buffer to finish, and then resets the fence register. - * @obj: tiled object holding a fence register. - * @bool: whether the wait upon the fence is interruptible - * - * Zeroes out the fence register itself and clears out the associated - * data structures in dev_priv and obj. - */ -int -i915_gem_object_put_fence_reg(struct drm_i915_gem_object *obj, - bool interruptible) -{ - struct drm_device *dev = obj->base.dev; - int ret; - - if (obj->fence_reg == I915_FENCE_REG_NONE) - return 0; - - /* If we've changed tiling, GTT-mappings of the object - * need to re-fault to ensure that the correct fence register - * setup is in place. - */ - i915_gem_release_mmap(obj); - - /* On the i915, GPU access to tiled buffers is via a fence, - * therefore we must wait for any outstanding access to complete - * before clearing the fence. - */ - if (obj->fenced_gpu_access) { - i915_gem_object_flush_gpu_write_domain(obj); - obj->fenced_gpu_access = false; - } - - if (obj->last_fenced_seqno) { - ret = i915_do_wait_request(dev, - obj->last_fenced_seqno, - interruptible, - obj->last_fenced_ring); - if (ret) - return ret; - - obj->last_fenced_seqno = false; - } - - i915_gem_object_flush_gtt_write_domain(obj); - i915_gem_clear_fence_reg(obj); - - return 0; + reg->obj = NULL; + reg->setup_seqno = 0; } /** diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index af01a58a643b..9bdc495e17bb 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -424,7 +424,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, } static int -i915_gem_execbuffer_reserve(struct drm_device *dev, +i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_file *file, struct list_head *objects, struct drm_i915_gem_exec_object2 *exec) @@ -499,10 +499,15 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, } if (need_fence) { - ret = i915_gem_object_get_fence_reg(obj, true); + ret = i915_gem_object_get_fence(obj, ring, 1); + if (ret) + break; + } else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode == I915_TILING_NONE) { + /* XXX pipelined! */ + ret = i915_gem_object_put_fence(obj); if (ret) break; - } obj->pending_fenced_gpu_access = need_fence; @@ -522,7 +527,7 @@ i915_gem_execbuffer_reserve(struct drm_device *dev, /* First attempt, just clear anything that is purgeable. * Second attempt, clear the entire GTT. */ - ret = i915_gem_evict_everything(dev, retry == 0); + ret = i915_gem_evict_everything(ring->dev, retry == 0); if (ret) return ret; @@ -548,6 +553,7 @@ err: static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, + struct intel_ring_buffer *ring, struct list_head *objects, struct drm_i915_gem_exec_object2 *exec, int count) @@ -590,7 +596,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; } - ret = i915_gem_execbuffer_reserve(dev, file, objects, exec); + ret = i915_gem_execbuffer_reserve(ring, file, objects, exec); if (ret) goto err; @@ -930,7 +936,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(dev, file, &objects, exec); + ret = i915_gem_execbuffer_reserve(ring, file, &objects, exec); if (ret) goto err; @@ -938,7 +944,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ret = i915_gem_execbuffer_relocate(dev, file, &objects, exec); if (ret) { if (ret == -EFAULT) { - ret = i915_gem_execbuffer_relocate_slow(dev, file, + ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, &objects, exec, args->buffer_count); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 1c5fdb30f272..22a32b9932c5 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -244,9 +244,6 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) if (INTEL_INFO(obj->base.dev)->gen >= 4) return true; - if (!obj->gtt_space) - return true; - if (INTEL_INFO(obj->base.dev)->gen == 3) { if (obj->gtt_offset & ~I915_FENCE_START_MASK) return false; @@ -345,27 +342,21 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, * tiling mode. Otherwise we can just leave it alone, but * need to ensure that any fence register is cleared. */ - if (!i915_gem_object_fence_ok(obj, args->tiling_mode)) - ret = i915_gem_object_unbind(obj); - else if (obj->fence_reg != I915_FENCE_REG_NONE) - ret = i915_gem_object_put_fence_reg(obj, true); - else - i915_gem_release_mmap(obj); + i915_gem_release_mmap(obj); - if (ret != 0) { - args->tiling_mode = obj->tiling_mode; - args->stride = obj->stride; - goto err; - } + obj->map_and_fenceable = + obj->gtt_space == NULL || + (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end && + i915_gem_object_fence_ok(obj, args->tiling_mode)); + obj->tiling_changed = true; obj->tiling_mode = args->tiling_mode; obj->stride = args->stride; } -err: drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); - return ret; + return 0; } /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c2c94a26f92e..e141dd2e46e5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1474,7 +1474,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * a fence as the cost is not that onerous. */ if (obj->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, false); + ret = i915_gem_object_get_fence(obj, pipelined, false); if (ret) goto err_unpin; } @@ -4370,6 +4370,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { + if (obj->tiling_mode) { + DRM_ERROR("cursor cannot be tiled\n"); + ret = -EINVAL; + goto fail_locked; + } + ret = i915_gem_object_pin(obj, PAGE_SIZE, true); if (ret) { DRM_ERROR("failed to pin cursor bo\n"); @@ -4382,6 +4388,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, goto fail_unpin; } + ret = i915_gem_object_put_fence(obj); + if (ret) { + DRM_ERROR("failed to move cursor bo into the GTT\n"); + goto fail_unpin; + } + addr = obj->gtt_offset; } else { int align = IS_I830(dev) ? 16 * 1024 : 256; @@ -4966,6 +4978,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) i915_gem_object_unpin(work->old_fb_obj); drm_gem_object_unreference(&work->pending_flip_obj->base); drm_gem_object_unreference(&work->old_fb_obj->base); + mutex_unlock(&work->dev->struct_mutex); kfree(work); } @@ -5009,10 +5022,12 @@ static void do_intel_finish_page_flip(struct drm_device *dev, spin_unlock_irqrestore(&dev->event_lock, flags); obj = work->old_fb_obj; + atomic_clear_mask(1 << intel_crtc->plane, &obj->pending_flip.counter); if (atomic_read(&obj->pending_flip) == 0) wake_up(&dev_priv->pending_flip_queue); + schedule_work(&work->work); trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index af715cc03ee0..d0c1add393a3 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -787,6 +787,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) goto out_unpin; + ret = i915_gem_object_put_fence(new_bo); + if (ret) + goto out_unpin; + if (!overlay->active) { regs = intel_overlay_map_regs(overlay); if (!regs) { @@ -1161,6 +1165,12 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->struct_mutex); + if (new_bo->tiling_mode) { + DRM_ERROR("buffer used for overlay image can not be tiled\n"); + ret = -EINVAL; + goto out_unlock; + } + ret = intel_overlay_recover_from_interrupt(overlay, true); if (ret != 0) goto out_unlock; -- cgit v1.2.3 From c6748e09eed072be077fe583976516b76daf42ec Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 16:02:21 +0000 Subject: drm/i915: Remove inactive LRU tracking from set_domain_ioctl As the userspace mappings are torn down on every GPU write, we prefer to track when the buffer is activated (via a fresh i915_gem_fault). This makes the LRU conceptually simpler. With coherent mappings, the remaining use-case for set_domain_ioctl is GPU synchronisation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 23d2417a3585..9e036010e3fc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1018,7 +1018,6 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_set_domain *args = data; struct drm_i915_gem_object *obj; uint32_t read_domains = args->read_domains; @@ -1051,21 +1050,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, goto unlock; } - intel_mark_busy(dev, obj); - if (read_domains & I915_GEM_DOMAIN_GTT) { ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0); - /* Update the LRU on the fence for the CPU access that's - * about to occur. - */ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_fence_reg *reg = - &dev_priv->fence_regs[obj->fence_reg]; - list_move_tail(®->lru_list, - &dev_priv->mm.fence_list); - } - /* Silently promote "you're not bound, there was nothing to do" * to success, since the client was just asking us to * make sure everything was done. @@ -1076,10 +1063,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); } - /* Maintain LRU order of "inactive" objects */ - if (ret == 0 && i915_gem_object_is_inactive(obj)) - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - drm_gem_object_unreference(&obj->base); unlock: mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 60de2ba51eaba9eefcc355cb20c8582b1481e755 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Nov 2010 15:53:11 +0000 Subject: drm/i915: Kill the get_fence tracepoint As the tracepoint is now decoupled from when the actual register is assigned and was never complemented by detailing when the object lost its fence, it has outlived its limited usefulness. Profiling the actual stalls is a far more profitable venture anyway. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 3 --- drivers/gpu/drm/i915/i915_trace.h | 22 ---------------------- 2 files changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9e036010e3fc..d99212fe54ed 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2603,9 +2603,6 @@ update: break; } - trace_i915_gem_object_get_fence(obj, - obj->fence_reg, - obj->tiling_mode); return ret; } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 1df7262ae077..7f0fc3ed61aa 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -80,28 +80,6 @@ TRACE_EVENT(i915_gem_object_change_domain, __entry->read_domains, __entry->write_domain) ); -TRACE_EVENT(i915_gem_object_get_fence, - - TP_PROTO(struct drm_i915_gem_object *obj, int fence, int tiling_mode), - - TP_ARGS(obj, fence, tiling_mode), - - TP_STRUCT__entry( - __field(struct drm_i915_gem_object *, obj) - __field(int, fence) - __field(int, tiling_mode) - ), - - TP_fast_assign( - __entry->obj = obj; - __entry->fence = fence; - __entry->tiling_mode = tiling_mode; - ), - - TP_printk("obj=%p, fence=%d, tiling=%d", - __entry->obj, __entry->fence, __entry->tiling_mode) -); - DECLARE_EVENT_CLASS(i915_gem_object, TP_PROTO(struct drm_i915_gem_object *obj), -- cgit v1.2.3 From 89733aa9cca016a542dc621d147a32d6b0fcdad5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:22:41 -0800 Subject: Staging: hv: remove OnChildDeviceCreate vmbus_driver callback It's only ever set to one function, so just call that function instead. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel_mgmt.c | 2 +- drivers/staging/hv/vmbus.c | 13 ------------- drivers/staging/hv/vmbus_api.h | 3 --- drivers/staging/hv/vmbus_drv.c | 10 +++------- drivers/staging/hv/vmbus_private.h | 2 +- 5 files changed, 5 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index ae830f2e4e3a..3105fd1afe7d 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -355,7 +355,7 @@ static void vmbus_process_offer(void *context) * We need to set the DeviceObject field before calling * VmbusChildDeviceAdd() */ - newchannel->device_obj = VmbusChildDeviceCreate( + newchannel->device_obj = vmbus_child_device_create( &newchannel->offermsg.offer.InterfaceType, &newchannel->offermsg.offer.InterfaceInstance, newchannel); diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index e6462c6774d1..163c743ea476 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -60,19 +60,6 @@ static void VmbusGetChannelOffers(void) vmbus_request_offers(); } -/* - * VmbusCreateChildDevice - Creates the child device on the bus that represents the channel offer - */ -struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType, - struct hv_guid *DeviceInstance, - struct vmbus_channel *channel) -{ - struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver; - - return vmbusDriver->OnChildDeviceCreate(DeviceType, DeviceInstance, - channel); -} - /* * VmbusChildDeviceAdd - Registers the child device with the vmbus */ diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 2af42e550076..e26365c0e798 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -122,9 +122,6 @@ struct vmbus_driver { struct hv_driver Base; /* Set by the caller */ - struct hv_device * (*OnChildDeviceCreate)(struct hv_guid *DeviceType, - struct hv_guid *DeviceInstance, - struct vmbus_channel *channel); void (*OnChildDeviceDestroy)(struct hv_device *device); int (*OnChildDeviceAdd)(struct hv_device *RootDevice, struct hv_device *ChildDevice); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 096587592e23..224e8440b818 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -69,9 +69,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id); static void vmbus_device_release(struct device *device); static void vmbus_bus_release(struct device *device); -static struct hv_device *vmbus_child_device_create(struct hv_guid *type, - struct hv_guid *instance, - struct vmbus_channel *channel); static void vmbus_child_device_destroy(struct hv_device *device_obj); static int vmbus_child_device_register(struct hv_device *root_device_obj, struct hv_device *child_device_obj); @@ -301,7 +298,6 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) * Set this up to allow lower layer to callback to add/remove child * devices on the bus */ - vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create; vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy; vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister; @@ -492,9 +488,9 @@ EXPORT_SYMBOL(vmbus_child_driver_unregister); * vmbus_child_device_create - Creates and registers a new child device * on the vmbus. */ -static struct hv_device *vmbus_child_device_create(struct hv_guid *type, - struct hv_guid *instance, - struct vmbus_channel *channel) +struct hv_device *vmbus_child_device_create(struct hv_guid *type, + struct hv_guid *instance, + struct vmbus_channel *channel) { struct vm_device *child_device_ctx; struct hv_device *child_device_obj; diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h index 09eaec964b30..d07d832edc01 100644 --- a/drivers/staging/hv/vmbus_private.h +++ b/drivers/staging/hv/vmbus_private.h @@ -102,7 +102,7 @@ extern struct VMBUS_CONNECTION gVmbusConnection; /* General vmbus interface */ -struct hv_device *VmbusChildDeviceCreate(struct hv_guid *deviceType, +struct hv_device *vmbus_child_device_create(struct hv_guid *deviceType, struct hv_guid *deviceInstance, struct vmbus_channel *channel); -- cgit v1.2.3 From 9205307cd88f09e51f2c4aeba79266317a299853 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:25:17 -0800 Subject: Staging: hv: remove OnChildDeviceDestroy vmbus_driver callback No one ever calls it so get rid of it, it's pointless. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus_api.h | 1 - drivers/staging/hv/vmbus_drv.c | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index e26365c0e798..189b672a21ee 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -122,7 +122,6 @@ struct vmbus_driver { struct hv_driver Base; /* Set by the caller */ - void (*OnChildDeviceDestroy)(struct hv_device *device); int (*OnChildDeviceAdd)(struct hv_device *RootDevice, struct hv_device *ChildDevice); void (*OnChildDeviceRemove)(struct hv_device *device); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 224e8440b818..656e9541e5ec 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -69,7 +69,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id); static void vmbus_device_release(struct device *device); static void vmbus_bus_release(struct device *device); -static void vmbus_child_device_destroy(struct hv_device *device_obj); static int vmbus_child_device_register(struct hv_device *root_device_obj, struct hv_device *child_device_obj); static void vmbus_child_device_unregister(struct hv_device *child_device_obj); @@ -298,7 +297,6 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) * Set this up to allow lower layer to callback to add/remove child * devices on the bus */ - vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy; vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister; @@ -599,13 +597,6 @@ static void vmbus_child_device_unregister(struct hv_device *device_obj) &device_ctx->device); } -/* - * vmbus_child_device_destroy - Destroy the specified child device on the vmbus. - */ -static void vmbus_child_device_destroy(struct hv_device *device_obj) -{ -} - /* * vmbus_uevent - add uevent for our device * @@ -848,7 +839,6 @@ static void vmbus_device_release(struct device *device) { struct vm_device *device_ctx = device_to_vm_device(device); - /* vmbus_child_device_destroy(&device_ctx->device_obj); */ kfree(device_ctx); /* !!DO NOT REFERENCE device_ctx anymore at this point!! */ -- cgit v1.2.3 From 9d8bd71ad4f295f80450b5089d239c3135802699 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:34:45 -0800 Subject: Staging: hv: remove OnChildDeviceRemove vmbus_driver callback It's only ever set to one function, so just call that function instead. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel_mgmt.c | 4 ++-- drivers/staging/hv/vmbus.c | 10 ---------- drivers/staging/hv/vmbus_api.h | 1 - drivers/staging/hv/vmbus_drv.c | 4 +--- drivers/staging/hv/vmbus_private.h | 2 +- 5 files changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index 3105fd1afe7d..0f4d6093f674 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -413,7 +413,7 @@ static void vmbus_process_rescind_offer(void *context) { struct vmbus_channel *channel = context; - VmbusChildDeviceRemove(channel->device_obj); + vmbus_child_device_unregister(channel->device_obj); } /* @@ -847,7 +847,7 @@ void vmbus_release_unattached_channels(void) "Releasing unattached device object %p", channel->device_obj); - VmbusChildDeviceRemove(channel->device_obj); + vmbus_child_device_unregister(channel->device_obj); free_channel(channel); } else { if (!start) diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index 163c743ea476..d7db7d0f5ee6 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -70,16 +70,6 @@ int VmbusChildDeviceAdd(struct hv_device *ChildDevice) return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice); } -/* - * VmbusChildDeviceRemove Unregisters the child device from the vmbus - */ -void VmbusChildDeviceRemove(struct hv_device *ChildDevice) -{ - struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver; - - vmbusDriver->OnChildDeviceRemove(ChildDevice); -} - /* * VmbusOnDeviceAdd - Callback when the root bus device is added */ diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 189b672a21ee..59742800b06e 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -124,7 +124,6 @@ struct vmbus_driver { /* Set by the caller */ int (*OnChildDeviceAdd)(struct hv_device *RootDevice, struct hv_device *ChildDevice); - void (*OnChildDeviceRemove)(struct hv_device *device); /* Set by the callee */ int (*OnIsr)(struct hv_driver *driver); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 656e9541e5ec..7323f334f83e 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -71,7 +71,6 @@ static void vmbus_bus_release(struct device *device); static int vmbus_child_device_register(struct hv_device *root_device_obj, struct hv_device *child_device_obj); -static void vmbus_child_device_unregister(struct hv_device *child_device_obj); static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf); @@ -298,7 +297,6 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) * devices on the bus */ vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; - vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister; /* Call to bus driver to initialize */ ret = drv_init(&vmbus_drv_obj->Base); @@ -580,7 +578,7 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj, * vmbus_child_device_unregister - Remove the specified child device * from the vmbus. */ -static void vmbus_child_device_unregister(struct hv_device *device_obj) +void vmbus_child_device_unregister(struct hv_device *device_obj) { struct vm_device *device_ctx = to_vm_device(device_obj); diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h index d07d832edc01..a5965f8ca107 100644 --- a/drivers/staging/hv/vmbus_private.h +++ b/drivers/staging/hv/vmbus_private.h @@ -108,7 +108,7 @@ struct hv_device *vmbus_child_device_create(struct hv_guid *deviceType, int VmbusChildDeviceAdd(struct hv_device *Device); -void VmbusChildDeviceRemove(struct hv_device *Device); +void vmbus_child_device_unregister(struct hv_device *device_obj); /* static void */ /* VmbusChildDeviceDestroy( */ -- cgit v1.2.3 From 097e310329fb69c928aa44b517a547e4a17658fd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:41:05 -0800 Subject: Staging: hv: remove OnIsr vmbus_driver callback It's only ever set to one function, so just call that function instead. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 5 ++--- drivers/staging/hv/vmbus_api.h | 2 +- drivers/staging/hv/vmbus_drv.c | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index d7db7d0f5ee6..09b04517ee09 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -175,9 +175,9 @@ static void VmbusOnEventDPC(struct hv_driver *drv) } /* - * VmbusOnISR - ISR routine + * vmbus_on_isr - ISR routine */ -static int VmbusOnISR(struct hv_driver *drv) +int vmbus_on_isr(struct hv_driver *drv) { int ret = 0; int cpu = smp_processor_id(); @@ -235,7 +235,6 @@ int VmbusInitialize(struct hv_driver *drv) driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; driver->Base.OnCleanup = VmbusOnCleanup; - driver->OnIsr = VmbusOnISR; driver->OnMsgDpc = VmbusOnMsgDPC; driver->OnEventDpc = VmbusOnEventDPC; driver->GetChannelOffers = VmbusGetChannelOffers; diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 59742800b06e..d0c30a725c7a 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -126,12 +126,12 @@ struct vmbus_driver { struct hv_device *ChildDevice); /* Set by the callee */ - int (*OnIsr)(struct hv_driver *driver); void (*OnMsgDpc)(struct hv_driver *driver); void (*OnEventDpc)(struct hv_driver *driver); void (*GetChannelOffers)(void); }; int VmbusInitialize(struct hv_driver *drv); +int vmbus_on_isr(struct hv_driver *drv); #endif /* _VMBUS_API_H_ */ diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 7323f334f83e..4551a469832d 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -873,10 +873,8 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id) struct vmbus_driver *vmbus_driver_obj = &g_vmbus_drv.drv_obj; int ret; - /* ASSERT(vmbus_driver_obj->OnIsr != NULL); */ - /* Call to bus driver to handle interrupt */ - ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base); + ret = vmbus_on_isr(&vmbus_driver_obj->Base); /* Schedules a dpc if necessary */ if (ret > 0) { -- cgit v1.2.3 From 4a1494fc101b05f895ef52b9d01769d382c5a6e2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:44:48 -0800 Subject: Staging: hv: remove OnMsgDpc vmbus_driver callback It's only ever set to one function, so just call that function instead. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 5 ++--- drivers/staging/hv/vmbus_api.h | 2 +- drivers/staging/hv/vmbus_drv.c | 6 ++---- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index 09b04517ee09..df986be8bb84 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -119,9 +119,9 @@ static void VmbusOnCleanup(struct hv_driver *drv) } /* - * VmbusOnMsgDPC - DPC routine to handle messages from the hypervisior + * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior */ -static void VmbusOnMsgDPC(struct hv_driver *drv) +void vmbus_on_msg_dpc(struct hv_driver *drv) { int cpu = smp_processor_id(); void *page_addr = hv_context.synic_message_page[cpu]; @@ -235,7 +235,6 @@ int VmbusInitialize(struct hv_driver *drv) driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; driver->Base.OnCleanup = VmbusOnCleanup; - driver->OnMsgDpc = VmbusOnMsgDPC; driver->OnEventDpc = VmbusOnEventDPC; driver->GetChannelOffers = VmbusGetChannelOffers; diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index d0c30a725c7a..332a92d2cfd3 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -126,12 +126,12 @@ struct vmbus_driver { struct hv_device *ChildDevice); /* Set by the callee */ - void (*OnMsgDpc)(struct hv_driver *driver); void (*OnEventDpc)(struct hv_driver *driver); void (*GetChannelOffers)(void); }; int VmbusInitialize(struct hv_driver *drv); int vmbus_on_isr(struct hv_driver *drv); +void vmbus_on_msg_dpc(struct hv_driver *drv); #endif /* _VMBUS_API_H_ */ diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 4551a469832d..d57f54db2a5a 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -849,14 +849,12 @@ static void vmbus_msg_dpc(unsigned long data) { struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data; - /* ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); */ - /* Call to bus driver to handle interrupt */ - vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base); + vmbus_on_msg_dpc(&vmbus_drv_obj->Base); } /* - * vmbus_msg_dpc - Tasklet routine to handle hypervisor events + * vmbus_event_dpc - Tasklet routine to handle hypervisor events */ static void vmbus_event_dpc(unsigned long data) { -- cgit v1.2.3 From c722bd3e2cb92be7afec346894faa29605436c1a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:47:11 -0800 Subject: Staging: hv: remove OnEventDpc vmbus_driver callback It's only ever set to one function, so just call that function instead. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 5 ++--- drivers/staging/hv/vmbus_api.h | 2 +- drivers/staging/hv/vmbus_drv.c | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index df986be8bb84..3aeedf6026e3 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -166,9 +166,9 @@ void vmbus_on_msg_dpc(struct hv_driver *drv) } /* - * VmbusOnEventDPC - DPC routine to handle events from the hypervisior + * vmbus_on_event_dpc - DPC routine to handle events from the hypervisior */ -static void VmbusOnEventDPC(struct hv_driver *drv) +void vmbus_on_event_dpc(struct hv_driver *drv) { /* TODO: Process any events */ VmbusOnEvents(); @@ -235,7 +235,6 @@ int VmbusInitialize(struct hv_driver *drv) driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; driver->Base.OnCleanup = VmbusOnCleanup; - driver->OnEventDpc = VmbusOnEventDPC; driver->GetChannelOffers = VmbusGetChannelOffers; /* Hypervisor initialization...setup hypercall page..etc */ diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 332a92d2cfd3..31549c9579ba 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -126,12 +126,12 @@ struct vmbus_driver { struct hv_device *ChildDevice); /* Set by the callee */ - void (*OnEventDpc)(struct hv_driver *driver); void (*GetChannelOffers)(void); }; int VmbusInitialize(struct hv_driver *drv); int vmbus_on_isr(struct hv_driver *drv); void vmbus_on_msg_dpc(struct hv_driver *drv); +void vmbus_on_event_dpc(struct hv_driver *drv); #endif /* _VMBUS_API_H_ */ diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index d57f54db2a5a..d075d9624279 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -860,10 +860,8 @@ static void vmbus_event_dpc(unsigned long data) { struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data; - /* ASSERT(vmbus_drv_obj->OnEventDpc != NULL); */ - /* Call to bus driver to handle interrupt */ - vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base); + vmbus_on_event_dpc(&vmbus_drv_obj->Base); } static irqreturn_t vmbus_isr(int irq, void *dev_id) -- cgit v1.2.3 From 2d6e882bada0ca7828347647c5b1091bf5f18fee Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 08:50:58 -0800 Subject: Staging: hv: remove GetChannelOffers vmbus_driver callback It's only ever set to one function, so just call that function instead. Actually, that wrapper function only ever called vmbus_request_offers() so just call that function instead, no need for a do-nothing intermediate step here. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 9 --------- drivers/staging/hv/vmbus_api.h | 3 --- drivers/staging/hv/vmbus_drv.c | 7 ++----- 3 files changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index 3aeedf6026e3..ae9e298f5c85 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -52,14 +52,6 @@ static const struct hv_guid gVmbusDeviceId = { static struct hv_driver *gDriver; /* vmbus driver object */ static struct hv_device *gDevice; /* vmbus root device */ -/* - * VmbusGetChannelOffers - Retrieve the channel offers from the parent partition - */ -static void VmbusGetChannelOffers(void) -{ - vmbus_request_offers(); -} - /* * VmbusChildDeviceAdd - Registers the child device with the vmbus */ @@ -235,7 +227,6 @@ int VmbusInitialize(struct hv_driver *drv) driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; driver->Base.OnCleanup = VmbusOnCleanup; - driver->GetChannelOffers = VmbusGetChannelOffers; /* Hypervisor initialization...setup hypercall page..etc */ ret = hv_init(); diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 31549c9579ba..c85d7d43146e 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -124,9 +124,6 @@ struct vmbus_driver { /* Set by the caller */ int (*OnChildDeviceAdd)(struct hv_device *RootDevice, struct hv_device *ChildDevice); - - /* Set by the callee */ - void (*GetChannelOffers)(void); }; int VmbusInitialize(struct hv_driver *drv); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index d075d9624279..6de53c40e023 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -387,9 +387,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) goto cleanup; } - - vmbus_drv_obj->GetChannelOffers(); - + vmbus_request_offers(); wait_for_completion(&hv_channel_ready); cleanup: @@ -441,7 +439,6 @@ static void vmbus_bus_exit(void) */ int vmbus_child_driver_register(struct driver_context *driver_ctx) { - struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj; int ret; DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", @@ -452,7 +449,7 @@ int vmbus_child_driver_register(struct driver_context *driver_ctx) ret = driver_register(&driver_ctx->driver); - vmbus_drv_obj->GetChannelOffers(); + vmbus_request_offers(); return ret; } -- cgit v1.2.3 From 98293a279cc0ff085ead7c032c6b8cb7b6ad7e88 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 09:16:04 -0800 Subject: Staging: hv: remove OnChildDeviceAdd vmbus_driver callback It's only ever set to one function, so just call that function instead. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 4 +--- drivers/staging/hv/vmbus_api.h | 4 ---- drivers/staging/hv/vmbus_drv.c | 12 ++---------- drivers/staging/hv/vmbus_private.h | 3 ++- 4 files changed, 5 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index ae9e298f5c85..7a7454ce8cad 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -57,9 +57,7 @@ static struct hv_device *gDevice; /* vmbus root device */ */ int VmbusChildDeviceAdd(struct hv_device *ChildDevice) { - struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver; - - return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice); + return vmbus_child_device_register(gDevice, ChildDevice); } /* diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index c85d7d43146e..6f3d59c7589d 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -120,10 +120,6 @@ struct vmbus_driver { /* !! Must be the 1st field !! */ /* FIXME if ^, then someone is doing somthing stupid */ struct hv_driver Base; - - /* Set by the caller */ - int (*OnChildDeviceAdd)(struct hv_device *RootDevice, - struct hv_device *ChildDevice); }; int VmbusInitialize(struct hv_driver *drv); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 6de53c40e023..4fa23c92128b 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -69,8 +69,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id); static void vmbus_device_release(struct device *device); static void vmbus_bus_release(struct device *device); -static int vmbus_child_device_register(struct hv_device *root_device_obj, - struct hv_device *child_device_obj); static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf); @@ -292,12 +290,6 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) int ret; unsigned int vector; - /* - * Set this up to allow lower layer to callback to add/remove child - * devices on the bus - */ - vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; - /* Call to bus driver to initialize */ ret = drv_init(&vmbus_drv_obj->Base); if (ret != 0) { @@ -530,8 +522,8 @@ struct hv_device *vmbus_child_device_create(struct hv_guid *type, /* * vmbus_child_device_register - Register the child device on the specified bus */ -static int vmbus_child_device_register(struct hv_device *root_device_obj, - struct hv_device *child_device_obj) +int vmbus_child_device_register(struct hv_device *root_device_obj, + struct hv_device *child_device_obj) { int ret = 0; struct vm_device *root_device_ctx = diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h index a5965f8ca107..07f6d22eeabb 100644 --- a/drivers/staging/hv/vmbus_private.h +++ b/drivers/staging/hv/vmbus_private.h @@ -107,7 +107,8 @@ struct hv_device *vmbus_child_device_create(struct hv_guid *deviceType, struct vmbus_channel *channel); int VmbusChildDeviceAdd(struct hv_device *Device); - +int vmbus_child_device_register(struct hv_device *root_device_obj, + struct hv_device *child_device_obj); void vmbus_child_device_unregister(struct hv_device *device_obj); /* static void */ -- cgit v1.2.3 From a69a6691d71cc24979ce29394478218307a77a84 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 09:42:18 -0800 Subject: Staging: hv: remove struct vmbus_driver It's only a wrapper for the struct hv_driver structure, so just use that instead, as there are no other fields left in it at the moment. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 15 +++++++-------- drivers/staging/hv/vmbus_api.h | 7 ------- drivers/staging/hv/vmbus_drv.c | 42 +++++++++++++++++++++--------------------- 3 files changed, 28 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index 7a7454ce8cad..650a97598f17 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -202,9 +202,8 @@ int vmbus_on_isr(struct hv_driver *drv) /* * VmbusInitialize - Main entry point */ -int VmbusInitialize(struct hv_driver *drv) +int VmbusInitialize(struct hv_driver *driver) { - struct vmbus_driver *driver = (struct vmbus_driver *)drv; int ret; DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++", @@ -218,20 +217,20 @@ int VmbusInitialize(struct hv_driver *drv) sizeof(struct vmbus_channel_packet_page_buffer), sizeof(struct vmbus_channel_packet_multipage_buffer)); - drv->name = gDriverName; - memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); + driver->name = gDriverName; + memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); /* Setup dispatch table */ - driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; - driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; - driver->Base.OnCleanup = VmbusOnCleanup; + driver->OnDeviceAdd = VmbusOnDeviceAdd; + driver->OnDeviceRemove = VmbusOnDeviceRemove; + driver->OnCleanup = VmbusOnCleanup; /* Hypervisor initialization...setup hypercall page..etc */ ret = hv_init(); if (ret != 0) DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); - gDriver = drv; + gDriver = driver; return ret; } diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 6f3d59c7589d..45c9b9a55528 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -115,13 +115,6 @@ struct hv_device { void *Extension; }; -/* Vmbus driver object */ -struct vmbus_driver { - /* !! Must be the 1st field !! */ - /* FIXME if ^, then someone is doing somthing stupid */ - struct hv_driver Base; -}; - int VmbusInitialize(struct hv_driver *drv); int vmbus_on_isr(struct hv_driver *drv); void vmbus_on_msg_dpc(struct hv_driver *drv); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 4fa23c92128b..2d3cf0f35328 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -46,7 +46,7 @@ struct vmbus_driver_context { /* The driver field is not used in here. Instead, the bus field is */ /* used to represent the driver */ struct driver_context drv_ctx; - struct vmbus_driver drv_obj; + struct hv_driver drv_obj; struct bus_type bus; struct tasklet_struct msg_dpc; @@ -285,32 +285,32 @@ static ssize_t vmbus_show_device_attr(struct device *dev, static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) { struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv; - struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj; + struct hv_driver *driver = &g_vmbus_drv.drv_obj; struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx; int ret; unsigned int vector; /* Call to bus driver to initialize */ - ret = drv_init(&vmbus_drv_obj->Base); + ret = drv_init(driver); if (ret != 0) { DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret); goto cleanup; } /* Sanity checks */ - if (!vmbus_drv_obj->Base.OnDeviceAdd) { + if (!driver->OnDeviceAdd) { DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set"); ret = -1; goto cleanup; } - vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name; + vmbus_drv_ctx->bus.name = driver->name; /* Initialize the bus context */ tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, - (unsigned long)vmbus_drv_obj); + (unsigned long)driver); tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, - (unsigned long)vmbus_drv_obj); + (unsigned long)driver); /* Now, register the bus driver with LDM */ ret = bus_register(&vmbus_drv_ctx->bus); @@ -321,7 +321,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) /* Get the interrupt resource */ ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM, - vmbus_drv_obj->Base.name, NULL); + driver->name, NULL); if (ret != 0) { DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", @@ -339,7 +339,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) /* Call to bus driver to add the root device */ memset(dev_ctx, 0, sizeof(struct vm_device)); - ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector); + ret = driver->OnDeviceAdd(&dev_ctx->device_obj, &vector); if (ret != 0) { DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device"); @@ -393,17 +393,17 @@ cleanup: */ static void vmbus_bus_exit(void) { - struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj; + struct hv_driver *driver = &g_vmbus_drv.drv_obj; struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv; struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx; /* Remove the root device */ - if (vmbus_drv_obj->Base.OnDeviceRemove) - vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj); + if (driver->OnDeviceRemove) + driver->OnDeviceRemove(&dev_ctx->device_obj); - if (vmbus_drv_obj->Base.OnCleanup) - vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base); + if (driver->OnCleanup) + driver->OnCleanup(driver); /* Unregister the root bus device */ device_unregister(&dev_ctx->device); @@ -678,7 +678,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver) struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context *)driver_ctx; - device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base; + device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj; DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, @@ -836,10 +836,10 @@ static void vmbus_device_release(struct device *device) */ static void vmbus_msg_dpc(unsigned long data) { - struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data; + struct hv_driver *driver = (struct hv_driver *)data; /* Call to bus driver to handle interrupt */ - vmbus_on_msg_dpc(&vmbus_drv_obj->Base); + vmbus_on_msg_dpc(driver); } /* @@ -847,19 +847,19 @@ static void vmbus_msg_dpc(unsigned long data) */ static void vmbus_event_dpc(unsigned long data) { - struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data; + struct hv_driver *driver = (struct hv_driver *)data; /* Call to bus driver to handle interrupt */ - vmbus_on_event_dpc(&vmbus_drv_obj->Base); + vmbus_on_event_dpc(driver); } static irqreturn_t vmbus_isr(int irq, void *dev_id) { - struct vmbus_driver *vmbus_driver_obj = &g_vmbus_drv.drv_obj; + struct hv_driver *driver = &g_vmbus_drv.drv_obj; int ret; /* Call to bus driver to handle interrupt */ - ret = vmbus_on_isr(&vmbus_driver_obj->Base); + ret = vmbus_on_isr(driver); /* Schedules a dpc if necessary */ if (ret > 0) { -- cgit v1.2.3 From 1953ecfc293911311f04d8c19f04d2249a30707b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 11:28:28 -0800 Subject: Staging: hv: rename the vmbus to "hyperv" This changes the name of the bus in sysfs from "vmbus" to "hyperv" which is the name it should show (vmbus is way to generic). Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c index 650a97598f17..df342f285c04 100644 --- a/drivers/staging/hv/vmbus.c +++ b/drivers/staging/hv/vmbus.c @@ -27,7 +27,7 @@ #include "version_info.h" #include "vmbus_private.h" -static const char *gDriverName = "vmbus"; +static const char *gDriverName = "hyperv"; /* * Windows vmbus does not defined this. -- cgit v1.2.3 From 36199a992aba4f3ea1bc0430f04655e99010a65d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 11:59:22 -0800 Subject: Staging: hv: remove vmbus.c Merge the functions into vmbus_drv.c as there's no need to have them separate anymore. It will also make unwinding some of the function and pointer mess easier, as well as making functions static in the future. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/Makefile | 2 +- drivers/staging/hv/vmbus.c | 236 ----------------------------------------- drivers/staging/hv/vmbus_drv.c | 209 ++++++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 237 deletions(-) delete mode 100644 drivers/staging/hv/vmbus.c (limited to 'drivers') diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile index b46349bb43bf..acd39bd75b1c 100644 --- a/drivers/staging/hv/Makefile +++ b/drivers/staging/hv/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o hv_vmbus-y := vmbus_drv.o osd.o \ - vmbus.o hv.o connection.o channel.o \ + hv.o connection.o channel.o \ channel_mgmt.o ring_buffer.o hv_storvsc-y := storvsc_drv.o storvsc.o hv_blkvsc-y := blkvsc_drv.o blkvsc.o diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c deleted file mode 100644 index df342f285c04..000000000000 --- a/drivers/staging/hv/vmbus.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2009, Microsoft Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * Authors: - * Haiyang Zhang - * Hank Janssen - * - */ -#include -#include -#include -#include "osd.h" -#include "logging.h" -#include "version_info.h" -#include "vmbus_private.h" - -static const char *gDriverName = "hyperv"; - -/* - * Windows vmbus does not defined this. - * We defined this to be consistent with other devices - */ -/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */ -static const struct hv_guid gVmbusDeviceType = { - .data = { - 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, - 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85 - } -}; - -/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */ -static const struct hv_guid gVmbusDeviceId = { - .data = { - 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, - 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5 - } -}; - -static struct hv_driver *gDriver; /* vmbus driver object */ -static struct hv_device *gDevice; /* vmbus root device */ - -/* - * VmbusChildDeviceAdd - Registers the child device with the vmbus - */ -int VmbusChildDeviceAdd(struct hv_device *ChildDevice) -{ - return vmbus_child_device_register(gDevice, ChildDevice); -} - -/* - * VmbusOnDeviceAdd - Callback when the root bus device is added - */ -static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) -{ - u32 *irqvector = AdditionalInfo; - int ret; - - gDevice = dev; - - memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); - memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, - sizeof(struct hv_guid)); - - /* strcpy(dev->name, "vmbus"); */ - /* SynIC setup... */ - on_each_cpu(hv_synic_init, (void *)irqvector, 1); - - /* Connect to VMBus in the root partition */ - ret = VmbusConnect(); - - /* VmbusSendEvent(device->localPortId+1); */ - return ret; -} - -/* - * VmbusOnDeviceRemove - Callback when the root bus device is removed - */ -static int VmbusOnDeviceRemove(struct hv_device *dev) -{ - int ret = 0; - - vmbus_release_unattached_channels(); - VmbusDisconnect(); - on_each_cpu(hv_synic_cleanup, NULL, 1); - return ret; -} - -/* - * VmbusOnCleanup - Perform any cleanup when the driver is removed - */ -static void VmbusOnCleanup(struct hv_driver *drv) -{ - /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */ - - hv_cleanup(); -} - -/* - * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior - */ -void vmbus_on_msg_dpc(struct hv_driver *drv) -{ - int cpu = smp_processor_id(); - void *page_addr = hv_context.synic_message_page[cpu]; - struct hv_message *msg = (struct hv_message *)page_addr + - VMBUS_MESSAGE_SINT; - struct hv_message *copied; - - while (1) { - if (msg->header.message_type == HVMSG_NONE) { - /* no msg */ - break; - } else { - copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC); - if (copied == NULL) - continue; - - osd_schedule_callback(gVmbusConnection.WorkQueue, - vmbus_onmessage, - (void *)copied); - } - - msg->header.message_type = HVMSG_NONE; - - /* - * Make sure the write to MessageType (ie set to - * HVMSG_NONE) happens before we read the - * MessagePending and EOMing. Otherwise, the EOMing - * will not deliver any more messages since there is - * no empty slot - */ - mb(); - - if (msg->header.message_flags.msg_pending) { - /* - * This will cause message queue rescan to - * possibly deliver another msg from the - * hypervisor - */ - wrmsrl(HV_X64_MSR_EOM, 0); - } - } -} - -/* - * vmbus_on_event_dpc - DPC routine to handle events from the hypervisior - */ -void vmbus_on_event_dpc(struct hv_driver *drv) -{ - /* TODO: Process any events */ - VmbusOnEvents(); -} - -/* - * vmbus_on_isr - ISR routine - */ -int vmbus_on_isr(struct hv_driver *drv) -{ - int ret = 0; - int cpu = smp_processor_id(); - void *page_addr; - struct hv_message *msg; - union hv_synic_event_flags *event; - - page_addr = hv_context.synic_message_page[cpu]; - msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; - - /* Check if there are actual msgs to be process */ - if (msg->header.message_type != HVMSG_NONE) { - DPRINT_DBG(VMBUS, "received msg type %d size %d", - msg->header.message_type, - msg->header.payload_size); - ret |= 0x1; - } - - /* TODO: Check if there are events to be process */ - page_addr = hv_context.synic_event_page[cpu]; - event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; - - /* Since we are a child, we only need to check bit 0 */ - if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { - DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]); - ret |= 0x2; - } - - return ret; -} - -/* - * VmbusInitialize - Main entry point - */ -int VmbusInitialize(struct hv_driver *driver) -{ - int ret; - - DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++", - HV_DRV_VERSION); - DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", - VMBUS_REVISION_NUMBER); - DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", - VMBUS_MESSAGE_SINT); - DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, " - "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd", - sizeof(struct vmbus_channel_packet_page_buffer), - sizeof(struct vmbus_channel_packet_multipage_buffer)); - - driver->name = gDriverName; - memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); - - /* Setup dispatch table */ - driver->OnDeviceAdd = VmbusOnDeviceAdd; - driver->OnDeviceRemove = VmbusOnDeviceRemove; - driver->OnCleanup = VmbusOnCleanup; - - /* Hypervisor initialization...setup hypercall page..etc */ - ret = hv_init(); - if (ret != 0) - DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", - ret); - gDriver = driver; - - return ret; -} diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 2d3cf0f35328..9c2325dff1c0 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -33,6 +33,7 @@ #include "logging.h" #include "vmbus.h" #include "channel.h" +#include "vmbus_private.h" /* FIXME! We need to do this dynamically for PIC and APIC system */ @@ -122,6 +123,214 @@ static struct vmbus_driver_context g_vmbus_drv = { .bus.dev_attrs = vmbus_device_attrs, }; +static const char *gDriverName = "hyperv"; + +/* + * Windows vmbus does not defined this. + * We defined this to be consistent with other devices + */ +/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */ +static const struct hv_guid gVmbusDeviceType = { + .data = { + 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, + 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85 + } +}; + +/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */ +static const struct hv_guid gVmbusDeviceId = { + .data = { + 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, + 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5 + } +}; + +static struct hv_driver *gDriver; /* vmbus driver object */ +static struct hv_device *gDevice; /* vmbus root device */ + +/* + * VmbusChildDeviceAdd - Registers the child device with the vmbus + */ +int VmbusChildDeviceAdd(struct hv_device *ChildDevice) +{ + return vmbus_child_device_register(gDevice, ChildDevice); +} + +/* + * VmbusOnDeviceAdd - Callback when the root bus device is added + */ +static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) +{ + u32 *irqvector = AdditionalInfo; + int ret; + + gDevice = dev; + + memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); + memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, + sizeof(struct hv_guid)); + + /* strcpy(dev->name, "vmbus"); */ + /* SynIC setup... */ + on_each_cpu(hv_synic_init, (void *)irqvector, 1); + + /* Connect to VMBus in the root partition */ + ret = VmbusConnect(); + + /* VmbusSendEvent(device->localPortId+1); */ + return ret; +} + +/* + * VmbusOnDeviceRemove - Callback when the root bus device is removed + */ +static int VmbusOnDeviceRemove(struct hv_device *dev) +{ + int ret = 0; + + vmbus_release_unattached_channels(); + VmbusDisconnect(); + on_each_cpu(hv_synic_cleanup, NULL, 1); + return ret; +} + +/* + * VmbusOnCleanup - Perform any cleanup when the driver is removed + */ +static void VmbusOnCleanup(struct hv_driver *drv) +{ + /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */ + + hv_cleanup(); +} + +/* + * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior + */ +void vmbus_on_msg_dpc(struct hv_driver *drv) +{ + int cpu = smp_processor_id(); + void *page_addr = hv_context.synic_message_page[cpu]; + struct hv_message *msg = (struct hv_message *)page_addr + + VMBUS_MESSAGE_SINT; + struct hv_message *copied; + + while (1) { + if (msg->header.message_type == HVMSG_NONE) { + /* no msg */ + break; + } else { + copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC); + if (copied == NULL) + continue; + + osd_schedule_callback(gVmbusConnection.WorkQueue, + vmbus_onmessage, + (void *)copied); + } + + msg->header.message_type = HVMSG_NONE; + + /* + * Make sure the write to MessageType (ie set to + * HVMSG_NONE) happens before we read the + * MessagePending and EOMing. Otherwise, the EOMing + * will not deliver any more messages since there is + * no empty slot + */ + mb(); + + if (msg->header.message_flags.msg_pending) { + /* + * This will cause message queue rescan to + * possibly deliver another msg from the + * hypervisor + */ + wrmsrl(HV_X64_MSR_EOM, 0); + } + } +} + +/* + * vmbus_on_event_dpc - DPC routine to handle events from the hypervisior + */ +void vmbus_on_event_dpc(struct hv_driver *drv) +{ + /* TODO: Process any events */ + VmbusOnEvents(); +} + +/* + * vmbus_on_isr - ISR routine + */ +int vmbus_on_isr(struct hv_driver *drv) +{ + int ret = 0; + int cpu = smp_processor_id(); + void *page_addr; + struct hv_message *msg; + union hv_synic_event_flags *event; + + page_addr = hv_context.synic_message_page[cpu]; + msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; + + /* Check if there are actual msgs to be process */ + if (msg->header.message_type != HVMSG_NONE) { + DPRINT_DBG(VMBUS, "received msg type %d size %d", + msg->header.message_type, + msg->header.payload_size); + ret |= 0x1; + } + + /* TODO: Check if there are events to be process */ + page_addr = hv_context.synic_event_page[cpu]; + event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; + + /* Since we are a child, we only need to check bit 0 */ + if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { + DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]); + ret |= 0x2; + } + + return ret; +} + +/* + * VmbusInitialize - Main entry point + */ +int VmbusInitialize(struct hv_driver *driver) +{ + int ret; + + DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++", + HV_DRV_VERSION); + DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", + VMBUS_REVISION_NUMBER); + DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", + VMBUS_MESSAGE_SINT); + DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, " + "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd", + sizeof(struct vmbus_channel_packet_page_buffer), + sizeof(struct vmbus_channel_packet_multipage_buffer)); + + driver->name = gDriverName; + memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); + + /* Setup dispatch table */ + driver->OnDeviceAdd = VmbusOnDeviceAdd; + driver->OnDeviceRemove = VmbusOnDeviceRemove; + driver->OnCleanup = VmbusOnCleanup; + + /* Hypervisor initialization...setup hypercall page..etc */ + ret = hv_init(); + if (ret != 0) + DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", + ret); + gDriver = driver; + + return ret; +} + static void get_channel_info(struct hv_device *device, struct hv_device_info *info) { -- cgit v1.2.3 From 6c884555f23d0c73f7e71ce977ee4dd882532c0f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 12:04:00 -0800 Subject: Staging: hv: call VmbusInitialize directly from vmbus_bus_init() No need to pass a function pointer to a function in the same file. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus_api.h | 1 - drivers/staging/hv/vmbus_drv.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index 45c9b9a55528..bb71cd22bce9 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -115,7 +115,6 @@ struct hv_device { void *Extension; }; -int VmbusInitialize(struct hv_driver *drv); int vmbus_on_isr(struct hv_driver *drv); void vmbus_on_msg_dpc(struct hv_driver *drv); void vmbus_on_event_dpc(struct hv_driver *drv); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 9c2325dff1c0..01b9a3dc00d6 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -298,7 +298,7 @@ int vmbus_on_isr(struct hv_driver *drv) /* * VmbusInitialize - Main entry point */ -int VmbusInitialize(struct hv_driver *driver) +static int VmbusInitialize(struct hv_driver *driver) { int ret; @@ -491,7 +491,7 @@ static ssize_t vmbus_show_device_attr(struct device *dev, * - setup the vmbus root device * - retrieve the channel offers */ -static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) +static int vmbus_bus_init(void) { struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv; struct hv_driver *driver = &g_vmbus_drv.drv_obj; @@ -500,7 +500,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv)) unsigned int vector; /* Call to bus driver to initialize */ - ret = drv_init(driver); + ret = VmbusInitialize(driver); if (ret != 0) { DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret); goto cleanup; @@ -1107,7 +1107,7 @@ static int __init vmbus_init(void) if (!dmi_check_system(microsoft_hv_dmi_table)) return -ENODEV; - return vmbus_bus_init(VmbusInitialize); + return vmbus_bus_init(); } static void __exit vmbus_exit(void) -- cgit v1.2.3 From 0bdb250c69251499f53a4ac6f9dae117da490696 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 12:04:59 -0800 Subject: Staging: hv: remove gDriver variable It's only set and never used anymore, so remove it. Gotta love static variables with a "global" hungarian notatation on the name... Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus_drv.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 01b9a3dc00d6..b18fa53f3a24 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -145,7 +145,6 @@ static const struct hv_guid gVmbusDeviceId = { } }; -static struct hv_driver *gDriver; /* vmbus driver object */ static struct hv_device *gDevice; /* vmbus root device */ /* @@ -326,8 +325,6 @@ static int VmbusInitialize(struct hv_driver *driver) if (ret != 0) DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); - gDriver = driver; - return ret; } -- cgit v1.2.3 From 6d26e38fa2085ab3ba37a52e34caf46f8e049544 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 12:08:08 -0800 Subject: Staging: hv: merge VmbusInitialize into vmbus_bus_init No need to have two functions for this. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus_drv.c | 60 ++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index b18fa53f3a24..3f5810a7a699 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -294,40 +294,6 @@ int vmbus_on_isr(struct hv_driver *drv) return ret; } -/* - * VmbusInitialize - Main entry point - */ -static int VmbusInitialize(struct hv_driver *driver) -{ - int ret; - - DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++", - HV_DRV_VERSION); - DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", - VMBUS_REVISION_NUMBER); - DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", - VMBUS_MESSAGE_SINT); - DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, " - "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd", - sizeof(struct vmbus_channel_packet_page_buffer), - sizeof(struct vmbus_channel_packet_multipage_buffer)); - - driver->name = gDriverName; - memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); - - /* Setup dispatch table */ - driver->OnDeviceAdd = VmbusOnDeviceAdd; - driver->OnDeviceRemove = VmbusOnDeviceRemove; - driver->OnCleanup = VmbusOnCleanup; - - /* Hypervisor initialization...setup hypercall page..etc */ - ret = hv_init(); - if (ret != 0) - DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", - ret); - return ret; -} - static void get_channel_info(struct hv_device *device, struct hv_device_info *info) { @@ -496,10 +462,30 @@ static int vmbus_bus_init(void) int ret; unsigned int vector; - /* Call to bus driver to initialize */ - ret = VmbusInitialize(driver); + DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++", + HV_DRV_VERSION); + DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", + VMBUS_REVISION_NUMBER); + DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", + VMBUS_MESSAGE_SINT); + DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, " + "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd", + sizeof(struct vmbus_channel_packet_page_buffer), + sizeof(struct vmbus_channel_packet_multipage_buffer)); + + driver->name = gDriverName; + memcpy(&driver->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); + + /* Setup dispatch table */ + driver->OnDeviceAdd = VmbusOnDeviceAdd; + driver->OnDeviceRemove = VmbusOnDeviceRemove; + driver->OnCleanup = VmbusOnCleanup; + + /* Hypervisor initialization...setup hypercall page..etc */ + ret = hv_init(); if (ret != 0) { - DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret); + DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", + ret); goto cleanup; } -- cgit v1.2.3 From cef6dbfa8ef6b8c474e020a24758aa848a2632fa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 12:11:25 -0800 Subject: Staging: hv: make some vmbus_drv functions static Now that vmbus_drv.c is merged with vmbus.c, some of the newly global functions can now be marked static. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus_api.h | 4 ---- drivers/staging/hv/vmbus_drv.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus_api.h b/drivers/staging/hv/vmbus_api.h index bb71cd22bce9..2da3f52610b3 100644 --- a/drivers/staging/hv/vmbus_api.h +++ b/drivers/staging/hv/vmbus_api.h @@ -115,8 +115,4 @@ struct hv_device { void *Extension; }; -int vmbus_on_isr(struct hv_driver *drv); -void vmbus_on_msg_dpc(struct hv_driver *drv); -void vmbus_on_event_dpc(struct hv_driver *drv); - #endif /* _VMBUS_API_H_ */ diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index 3f5810a7a699..f623b57c59d0 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -206,7 +206,7 @@ static void VmbusOnCleanup(struct hv_driver *drv) /* * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior */ -void vmbus_on_msg_dpc(struct hv_driver *drv) +static void vmbus_on_msg_dpc(struct hv_driver *drv) { int cpu = smp_processor_id(); void *page_addr = hv_context.synic_message_page[cpu]; @@ -253,7 +253,7 @@ void vmbus_on_msg_dpc(struct hv_driver *drv) /* * vmbus_on_event_dpc - DPC routine to handle events from the hypervisior */ -void vmbus_on_event_dpc(struct hv_driver *drv) +static void vmbus_on_event_dpc(struct hv_driver *drv) { /* TODO: Process any events */ VmbusOnEvents(); @@ -262,7 +262,7 @@ void vmbus_on_event_dpc(struct hv_driver *drv) /* * vmbus_on_isr - ISR routine */ -int vmbus_on_isr(struct hv_driver *drv) +static int vmbus_on_isr(struct hv_driver *drv) { int ret = 0; int cpu = smp_processor_id(); -- cgit v1.2.3 From bafbb8df076de1e3b63914473a403fba96b88f3c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Dec 2010 12:12:46 -0800 Subject: Staging: hv: remove vmbus_on_event_dpc() Just call VmbusOnEvents() as that's all the function did, so we can remove it. Cc: Haiyang Zhang Cc: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/vmbus_drv.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index f623b57c59d0..d794b603bf17 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -250,15 +250,6 @@ static void vmbus_on_msg_dpc(struct hv_driver *drv) } } -/* - * vmbus_on_event_dpc - DPC routine to handle events from the hypervisior - */ -static void vmbus_on_event_dpc(struct hv_driver *drv) -{ - /* TODO: Process any events */ - VmbusOnEvents(); -} - /* * vmbus_on_isr - ISR routine */ @@ -1039,10 +1030,8 @@ static void vmbus_msg_dpc(unsigned long data) */ static void vmbus_event_dpc(unsigned long data) { - struct hv_driver *driver = (struct hv_driver *)data; - /* Call to bus driver to handle interrupt */ - vmbus_on_event_dpc(driver); + VmbusOnEvents(); } static irqreturn_t vmbus_isr(int irq, void *dev_id) -- cgit v1.2.3 From df880a42dc4086ba7ff16f6ccb255e78fc0dc374 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Wed, 1 Dec 2010 15:36:38 -0800 Subject: staging: brcm80211: Remove unused code from osl.h Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/osl.h | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 662b5197b374..c2fa2975c955 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -38,22 +38,10 @@ typedef struct osl_dmainfo osldma_t; typedef unsigned int (*osl_rreg_fn_t) (void *ctx, void *reg, unsigned int size); typedef void (*osl_wreg_fn_t) (void *ctx, void *reg, unsigned int val, unsigned int size); -#endif +#endif /* BCMSDIO */ #include -/* -------------------------------------------------------------------------- -** Register manipulation macros. -*/ - #define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) -#ifndef AND_REG -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#endif /* !AND_REG */ - -#ifndef OR_REG -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -#endif /* !OR_REG */ - -#endif /* _osl_h_ */ +#endif /* _osl_h_ */ -- cgit v1.2.3 From c523ea78ec9a33586fa7a73859de7c462097cdfc Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Wed, 1 Dec 2010 15:36:39 -0800 Subject: staging: brcm80211: absorb linux_osl.h into osl.h Move code from linux_osl.h into osl.h and delete linux_osl.h, which created a bunch of checkpatch errors... I fixed most but volatile warnings will have to be dealt with later. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/linux_osl.h | 270 -------------------------- drivers/staging/brcm80211/include/osl.h | 261 ++++++++++++++++++++++++- 2 files changed, 259 insertions(+), 272 deletions(-) delete mode 100644 drivers/staging/brcm80211/include/linux_osl.h (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/linux_osl.h b/drivers/staging/brcm80211/include/linux_osl.h deleted file mode 100644 index c2edea4649cb..000000000000 --- a/drivers/staging/brcm80211/include/linux_osl.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _linux_osl_h_ -#define _linux_osl_h_ - -#include - -extern struct osl_info *osl_attach(void *pdev, uint bustype); -extern void osl_detach(struct osl_info *osh); - -extern u32 g_assert_type; - -#if defined(BCMDBG_ASSERT) -#define ASSERT(exp) \ - do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) -extern void osl_assert(char *exp, char *file, int line); -#else -#define ASSERT(exp) do {} while (0) -#endif /* defined(BCMDBG_ASSERT) */ - -/* PCI device bus # and slot # */ -#define OSL_PCI_BUS(osh) osl_pci_bus(osh) -#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) -extern uint osl_pci_bus(struct osl_info *osh); -extern uint osl_pci_slot(struct osl_info *osh); - -#define BUS_SWAP32(v) (v) - -extern void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, - u16 align, uint *tot, unsigned long *pap); - -#ifdef BRCM_FULLMAC -#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \ - osl_dma_alloc_consistent((osh), (size), (0), (tot), (pap)) -#else -#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ - osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) -#endif /* BRCM_FULLMAC */ - -#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ - osl_dma_free_consistent((osh), (void *)(va), (size), (pa)) -extern void osl_dma_free_consistent(struct osl_info *osh, void *va, - uint size, unsigned long pa); - -/* map/unmap direction */ -#define DMA_TX 1 /* TX direction for DMA */ -#define DMA_RX 2 /* RX direction for DMA */ - -/* map/unmap shared (dma-able) memory */ -#define DMA_MAP(osh, va, size, direction, p, dmah) \ - osl_dma_map((osh), (va), (size), (direction)) -#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ - osl_dma_unmap((osh), (pa), (size), (direction)) -extern uint osl_dma_map(struct osl_info *osh, void *va, uint size, - int direction); -extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, - int direction); - -/* register access macros */ -#if defined(BCMSDIO) -#ifdef BRCM_FULLMAC -#include -#endif -#define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (unsigned long)(r), sizeof(*(r)), (v))) -#define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (unsigned long)(r), sizeof(*(r)))) -#endif - -#if defined(BCMSDIO) -#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) \ - if (((struct osl_pubinfo *)(osh))->mmbus) \ - mmap_op else bus_op -#define SELECT_BUS_READ(osh, mmap_op, bus_op) \ - (((struct osl_pubinfo *)(osh))->mmbus) ? mmap_op : bus_op -#else -#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op -#define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op -#endif - -/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ -#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ - -#define OSL_SYSUPTIME() ((u32)jiffies * (1000 / HZ)) -#define printf(fmt, args...) printk(fmt , ## args) -#ifdef BRCM_FULLMAC -#include /* for vsn/printf's */ -#include /* for mem*, str* */ -#endif -/* bcopy's: Linux kernel doesn't provide these (anymore) */ -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) - -/* register access macros */ -#if defined(OSLREGOPS) -#else -#ifndef IL_BIGENDIAN -#ifndef __mips__ -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(u8) ? readb((volatile u8*)(r)) : \ - sizeof(*(r)) == sizeof(u16) ? readw((volatile u16*)(r)) : \ - readl((volatile u32*)(r)), OSL_READ_REG(osh, r)) \ -) -#else /* __mips__ */ -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, \ - ({ \ - __typeof(*(r)) __osl_v; \ - __asm__ __volatile__("sync"); \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - __osl_v = readb((volatile u8*)(r)); \ - break; \ - case sizeof(u16): \ - __osl_v = readw((volatile u16*)(r)); \ - break; \ - case sizeof(u32): \ - __osl_v = \ - readl((volatile u32*)(r)); \ - break; \ - } \ - __asm__ __volatile__("sync"); \ - __osl_v; \ - }), \ - ({ \ - __typeof(*(r)) __osl_v; \ - __asm__ __volatile__("sync"); \ - __osl_v = OSL_READ_REG(osh, r); \ - __asm__ __volatile__("sync"); \ - __osl_v; \ - })) \ -) -#endif /* __mips__ */ - -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - writeb((u8)(v), (volatile u8*)(r)); break; \ - case sizeof(u16): \ - writew((u16)(v), (volatile u16*)(r)); break; \ - case sizeof(u32): \ - writel((u32)(v), (volatile u32*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) -#else /* IL_BIGENDIAN */ -#define R_REG(osh, r) (\ - SELECT_BUS_READ(osh, \ - ({ \ - __typeof(*(r)) __osl_v; \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - __osl_v = \ - readb((volatile u8*)((r)^3)); \ - break; \ - case sizeof(u16): \ - __osl_v = \ - readw((volatile u16*)((r)^2)); \ - break; \ - case sizeof(u32): \ - __osl_v = readl((volatile u32*)(r)); \ - break; \ - } \ - __osl_v; \ - }), \ - OSL_READ_REG(osh, r)) \ -) -#define W_REG(osh, r, v) do { \ - SELECT_BUS_WRITE(osh, \ - switch (sizeof(*(r))) { \ - case sizeof(u8): \ - writeb((u8)(v), \ - (volatile u8*)((r)^3)); break; \ - case sizeof(u16): \ - writew((u16)(v), \ - (volatile u16*)((r)^2)); break; \ - case sizeof(u32): \ - writel((u32)(v), \ - (volatile u32*)(r)); break; \ - }, \ - (OSL_WRITE_REG(osh, r, v))); \ - } while (0) -#endif /* IL_BIGENDIAN */ - -#endif /* OSLREGOPS */ - -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) - -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) - -/* uncached/cached virtual address */ -#ifdef __mips__ -#include -#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va))) -#define OSL_CACHED(va) ((void *)KSEG0ADDR((va))) -#else -#define OSL_UNCACHED(va) ((void *)va) -#define OSL_CACHED(va) ((void *)va) -#endif /* mips */ - -/* map/unmap physical to virtual I/O */ -#if !defined(CONFIG_MMC_MSM7X00A) -#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) -#else -#define REG_MAP(pa, size) (void *)(0) -#endif /* !defined(CONFIG_MMC_MSM7X00A */ -#define REG_UNMAP(va) iounmap((va)) - -#define R_SM(r) (*(r)) -#define W_SM(r, v) (*(r) = (v)) -#define BZERO_SM(r, len) memset((r), '\0', (len)) - -/* packet primitives */ -#define PKTGET(osh, len, send) osl_pktget((osh), (len)) -#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) - -extern void *osl_pktget(struct osl_info *osh, uint len); -extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); - -#ifdef BRCM_FULLMAC -static inline void * -osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) -{ - struct sk_buff *nskb; - - for (nskb = skb; nskb; nskb = nskb->next) - osh->pktalloced++; - - return (void *)skb; -} -#define PKTFRMNATIVE(osh, skb) \ - osl_pkt_frmnative(((struct osl_pubinfo *)osh), (struct sk_buff*)(skb)) - -static inline struct sk_buff * -osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) -{ - struct sk_buff *nskb; - - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) - osh->pktalloced--; - - return (struct sk_buff *)pkt; -} -#define PKTTONATIVE(osh, pkt) \ - osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) -#else /* !BRCM_FULLMAC */ -#define PKTSETSKIPCT(osh, skb) -#define PKTCLRSKIPCT(osh, skb) -#define PKTSKIPCT(osh, skb) -#endif /* BRCM_FULLMAC */ - -#define PKTSUMNEEDED(skb) (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL) -#define PKTSETSUMGOOD(skb, x) (((struct sk_buff *)(skb))->ip_summed = \ - ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) -/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ - -#endif /* _linux_osl_h_ */ diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index c2fa2975c955..2368c80db60a 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -40,8 +40,265 @@ typedef void (*osl_wreg_fn_t) (void *ctx, void *reg, unsigned int val, unsigned int size); #endif /* BCMSDIO */ -#include +#include -#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) +extern struct osl_info *osl_attach(void *pdev, uint bustype); +extern void osl_detach(struct osl_info *osh); + +extern u32 g_assert_type; + +#if defined(BCMDBG_ASSERT) +#define ASSERT(exp) \ + do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) +extern void osl_assert(char *exp, char *file, int line); +#else +#define ASSERT(exp) do {} while (0) +#endif /* defined(BCMDBG_ASSERT) */ + +/* PCI device bus # and slot # */ +#define OSL_PCI_BUS(osh) osl_pci_bus(osh) +#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) +extern uint osl_pci_bus(struct osl_info *osh); +extern uint osl_pci_slot(struct osl_info *osh); + +#define BUS_SWAP32(v) (v) + +extern void *osl_dma_alloc_consistent(struct osl_info *osh, uint size, + u16 align, uint *tot, unsigned long *pap); + +#ifdef BRCM_FULLMAC +#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \ + osl_dma_alloc_consistent((osh), (size), (0), (tot), (pap)) +#else +#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ + osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) +#endif /* BRCM_FULLMAC */ + +#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ + osl_dma_free_consistent((osh), (void *)(va), (size), (pa)) +extern void osl_dma_free_consistent(struct osl_info *osh, void *va, + uint size, unsigned long pa); + +/* map/unmap direction */ +#define DMA_TX 1 /* TX direction for DMA */ +#define DMA_RX 2 /* RX direction for DMA */ + +/* map/unmap shared (dma-able) memory */ +#define DMA_MAP(osh, va, size, direction, p, dmah) \ + osl_dma_map((osh), (va), (size), (direction)) +#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ + osl_dma_unmap((osh), (pa), (size), (direction)) +extern uint osl_dma_map(struct osl_info *osh, void *va, uint size, + int direction); +extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, + int direction); + +/* register access macros */ +#if defined(BCMSDIO) +#ifdef BRCM_FULLMAC +#include +#endif +#define OSL_WRITE_REG(osh, r, v) \ + (bcmsdh_reg_write(NULL, (unsigned long)(r), sizeof(*(r)), (v))) +#define OSL_READ_REG(osh, r) \ + (bcmsdh_reg_read(NULL, (unsigned long)(r), sizeof(*(r)))) +#endif + +#if defined(BCMSDIO) +#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) \ + if (((struct osl_pubinfo *)(osh))->mmbus) \ + mmap_op else bus_op +#define SELECT_BUS_READ(osh, mmap_op, bus_op) \ + (((struct osl_pubinfo *)(osh))->mmbus) ? mmap_op : bus_op +#else +#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op +#define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op +#endif + +/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ +#define PKTBUFSZ 2048 + +#define OSL_SYSUPTIME() ((u32)jiffies * (1000 / HZ)) +#define printf(fmt, args...) printk(fmt , ## args) +#ifdef BRCM_FULLMAC +#include /* for vsn/printf's */ +#include /* for mem*, str* */ +#endif +/* bcopy's: Linux kernel doesn't provide these (anymore) */ +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) + +/* register access macros */ +#if defined(OSLREGOPS) +#else +#ifndef IL_BIGENDIAN +#ifndef __mips__ +#define R_REG(osh, r) (\ + SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(u8) ? \ + readb((volatile u8*)(r)) : \ + sizeof(*(r)) == sizeof(u16) ? readw((volatile u16*)(r)) : \ + readl((volatile u32*)(r)), OSL_READ_REG(osh, r)) \ +) +#else /* __mips__ */ +#define R_REG(osh, r) (\ + SELECT_BUS_READ(osh, \ + ({ \ + __typeof(*(r)) __osl_v; \ + __asm__ __volatile__("sync"); \ + switch (sizeof(*(r))) { \ + case sizeof(u8): \ + __osl_v = readb((volatile u8*)(r)); \ + break; \ + case sizeof(u16): \ + __osl_v = readw((volatile u16*)(r)); \ + break; \ + case sizeof(u32): \ + __osl_v = \ + readl((volatile u32*)(r)); \ + break; \ + } \ + __asm__ __volatile__("sync"); \ + __osl_v; \ + }), \ + ({ \ + __typeof(*(r)) __osl_v; \ + __asm__ __volatile__("sync"); \ + __osl_v = OSL_READ_REG(osh, r); \ + __asm__ __volatile__("sync"); \ + __osl_v; \ + })) \ +) +#endif /* __mips__ */ + +#define W_REG(osh, r, v) do { \ + SELECT_BUS_WRITE(osh, \ + switch (sizeof(*(r))) { \ + case sizeof(u8): \ + writeb((u8)(v), (volatile u8*)(r)); break; \ + case sizeof(u16): \ + writew((u16)(v), (volatile u16*)(r)); break; \ + case sizeof(u32): \ + writel((u32)(v), (volatile u32*)(r)); break; \ + }, \ + (OSL_WRITE_REG(osh, r, v))); \ + } while (0) +#else /* IL_BIGENDIAN */ +#define R_REG(osh, r) (\ + SELECT_BUS_READ(osh, \ + ({ \ + __typeof(*(r)) __osl_v; \ + switch (sizeof(*(r))) { \ + case sizeof(u8): \ + __osl_v = \ + readb((volatile u8*)((r)^3)); \ + break; \ + case sizeof(u16): \ + __osl_v = \ + readw((volatile u16*)((r)^2)); \ + break; \ + case sizeof(u32): \ + __osl_v = readl((volatile u32*)(r)); \ + break; \ + } \ + __osl_v; \ + }), \ + OSL_READ_REG(osh, r)) \ +) +#define W_REG(osh, r, v) do { \ + SELECT_BUS_WRITE(osh, \ + switch (sizeof(*(r))) { \ + case sizeof(u8): \ + writeb((u8)(v), \ + (volatile u8*)((r)^3)); break; \ + case sizeof(u16): \ + writew((u16)(v), \ + (volatile u16*)((r)^2)); break; \ + case sizeof(u32): \ + writel((u32)(v), \ + (volatile u32*)(r)); break; \ + }, \ + (OSL_WRITE_REG(osh, r, v))); \ + } while (0) +#endif /* IL_BIGENDIAN */ + +#endif /* OSLREGOPS */ + +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) + +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) + +/* uncached/cached virtual address */ +#ifdef __mips__ +#include +#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va))) +#define OSL_CACHED(va) ((void *)KSEG0ADDR((va))) +#else +#define OSL_UNCACHED(va) ((void *)va) +#define OSL_CACHED(va) ((void *)va) +#endif /* mips */ + +/* map/unmap physical to virtual I/O */ +#if !defined(CONFIG_MMC_MSM7X00A) +#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), \ + (unsigned long)(size)) +#else +#define REG_MAP(pa, size) (void *)(0) +#endif /* !defined(CONFIG_MMC_MSM7X00A */ +#define REG_UNMAP(va) iounmap((va)) + +#define R_SM(r) (*(r)) +#define W_SM(r, v) (*(r) = (v)) +#define BZERO_SM(r, len) memset((r), '\0', (len)) + +/* packet primitives */ +#define PKTGET(osh, len, send) osl_pktget((osh), (len)) +#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) + +extern void *osl_pktget(struct osl_info *osh, uint len); +extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); + +#ifdef BRCM_FULLMAC +static inline void * +osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) +{ + struct sk_buff *nskb; + + for (nskb = skb; nskb; nskb = nskb->next) + osh->pktalloced++; + + return (void *)skb; +} +#define PKTFRMNATIVE(osh, skb) \ + osl_pkt_frmnative(((struct osl_pubinfo *)osh), (struct sk_buff*)(skb)) + +static inline struct sk_buff * +osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) +{ + struct sk_buff *nskb; + + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) + osh->pktalloced--; + + return (struct sk_buff *)pkt; +} +#define PKTTONATIVE(osh, pkt) \ + osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) +#else /* !BRCM_FULLMAC */ +#define PKTSETSKIPCT(osh, skb) +#define PKTCLRSKIPCT(osh, skb) +#define PKTSKIPCT(osh, skb) +#endif /* BRCM_FULLMAC */ + +#define PKTSUMNEEDED(skb) \ + (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL) +#define PKTSETSUMGOOD(skb, x) \ + (((struct sk_buff *)(skb))->ip_summed = \ + ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) +/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because + skb->ip_summed is overloaded */ + + +#define SET_REG(osh, r, mask, val) \ + W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) #endif /* _osl_h_ */ -- cgit v1.2.3 From 92246bcbd7730eaaec0c29a2adc1cb4b4451ed9e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 2 Dec 2010 15:44:50 +0100 Subject: staging: brcm80211: remove redundant CHIPTYPE macro The CHIPTYPE macro simply expands to the macro argument so it is redundant and as such removed. Reviewed-by: Roland Vossen Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmdefs.h | 1 - drivers/staging/brcm80211/util/siutils.c | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h index 4ce4486a19a1..350bd6d526a4 100644 --- a/drivers/staging/brcm80211/include/bcmdefs.h +++ b/drivers/staging/brcm80211/include/bcmdefs.h @@ -51,7 +51,6 @@ #define SPI_BUS 6 /* gSPI target */ #define RPC_BUS 7 /* RPC target */ -#define CHIPTYPE(bus) (bus) #define CHIPID(chip) (chip) #define CHIPREV(rev) (rev) diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 33a42f672af8..da35edd2d7b5 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -568,7 +568,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, sih->issim = IS_SIM(sih->chippkg); /* scan for cores */ - if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { + if (sii->pub.socitype == SOCI_AI) { SI_MSG(("Found chip type AI (0x%08x)\n", w)); /* pass chipc address instead of original core base */ ai_scan(&sii->pub, (void *)cc, devid); @@ -765,7 +765,7 @@ void si_deregister_intr_callback(si_t *sih) uint si_flag(si_t *sih) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_flag(sih); else { ASSERT(0); @@ -775,7 +775,7 @@ uint si_flag(si_t *sih) void si_setint(si_t *sih, int siflag) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) ai_setint(sih, siflag); else ASSERT(0); @@ -807,7 +807,7 @@ bool si_backplane64(si_t *sih) #ifndef BCMSDIO uint si_corerev(si_t *sih) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_corerev(sih); else { ASSERT(0); @@ -850,7 +850,7 @@ void *si_setcore(si_t *sih, uint coreid, uint coreunit) if (!GOODIDX(idx)) return NULL; - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_setcoreidx(sih, idx); else { #ifdef BCMSDIO @@ -865,7 +865,7 @@ void *si_setcore(si_t *sih, uint coreid, uint coreunit) #ifndef BCMSDIO void *si_setcoreidx(si_t *sih, uint coreidx) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_setcoreidx(sih, coreidx); else { ASSERT(0); @@ -917,7 +917,7 @@ void si_restore_core(si_t *sih, uint coreid, uint intr_val) u32 si_core_cflags(si_t *sih, u32 mask, u32 val) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_core_cflags(sih, mask, val); else { ASSERT(0); @@ -927,7 +927,7 @@ u32 si_core_cflags(si_t *sih, u32 mask, u32 val) u32 si_core_sflags(si_t *sih, u32 mask, u32 val) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_core_sflags(sih, mask, val); else { ASSERT(0); @@ -937,7 +937,7 @@ u32 si_core_sflags(si_t *sih, u32 mask, u32 val) bool si_iscoreup(si_t *sih) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_iscoreup(sih); else { #ifdef BCMSDIO @@ -952,7 +952,7 @@ bool si_iscoreup(si_t *sih) void si_write_wrapperreg(si_t *sih, u32 offset, u32 val) { /* only for 4319, no requirement for SOCI_SB */ - if (CHIPTYPE(sih->socitype) == SOCI_AI) { + if (sih->socitype == SOCI_AI) { ai_write_wrap_reg(sih, offset, val); } } @@ -960,7 +960,7 @@ void si_write_wrapperreg(si_t *sih, u32 offset, u32 val) uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) return ai_corereg(sih, coreidx, regoff, mask, val); else { #ifdef BCMSDIO @@ -975,7 +975,7 @@ uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) void si_core_disable(si_t *sih, u32 bits) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) ai_core_disable(sih, bits); #ifdef BCMSDIO else @@ -985,7 +985,7 @@ void si_core_disable(si_t *sih, u32 bits) void si_core_reset(si_t *sih, u32 bits, u32 resetbits) { - if (CHIPTYPE(sih->socitype) == SOCI_AI) + if (sih->socitype == SOCI_AI) ai_core_reset(sih, bits, resetbits); #ifdef BCMSDIO else -- cgit v1.2.3 From dfa26436109d06f233a0ad735731cfb2d0c6ab5a Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 2 Dec 2010 15:44:51 +0100 Subject: staging: brcm80211: remove redundant CHIPID macro The CHIPID macro simply expands to the macro argument so it is redundant and as such removed. Reviewed-by: Roland Vossen Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmdefs.h | 1 - drivers/staging/brcm80211/phy/wlc_phy_cmn.c | 18 +++--- drivers/staging/brcm80211/phy/wlc_phy_n.c | 52 ++++++++--------- drivers/staging/brcm80211/sys/wlc_bmac.c | 24 ++++---- drivers/staging/brcm80211/sys/wlc_mac80211.c | 8 +-- drivers/staging/brcm80211/util/aiutils.c | 2 +- drivers/staging/brcm80211/util/bcmotp.c | 6 +- drivers/staging/brcm80211/util/hndpmu.c | 86 ++++++++++++++-------------- drivers/staging/brcm80211/util/sbutils.c | 2 +- drivers/staging/brcm80211/util/siutils.c | 22 +++---- 10 files changed, 110 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h index 350bd6d526a4..82356129caa5 100644 --- a/drivers/staging/brcm80211/include/bcmdefs.h +++ b/drivers/staging/brcm80211/include/bcmdefs.h @@ -51,7 +51,6 @@ #define SPI_BUS 6 /* gSPI target */ #define RPC_BUS 7 /* RPC target */ -#define CHIPID(chip) (chip) #define CHIPREV(rev) (rev) /* Defines for DMA Address Width - Shared between OSL and HNDDMA */ diff --git a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c index b223433482f1..3bed37cb59b8 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_cmn.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_cmn.c @@ -1085,8 +1085,8 @@ wlc_phy_table_addr(phy_info_t *pi, uint tbl_id, uint tbl_offset, pi->tbl_data_hi = tblDataHi; pi->tbl_data_lo = tblDataLo; - if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID || - CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) && + if ((pi->sh->chip == BCM43224_CHIP_ID || + pi->sh->chip == BCM43421_CHIP_ID) && (pi->sh->chiprev == 1)) { pi->tbl_addr = tblAddr; pi->tbl_save_id = tbl_id; @@ -1098,8 +1098,8 @@ void wlc_phy_table_data_write(phy_info_t *pi, uint width, u32 val) { ASSERT((width == 8) || (width == 16) || (width == 32)); - if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID || - CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) && + if ((pi->sh->chip == BCM43224_CHIP_ID || + pi->sh->chip == BCM43421_CHIP_ID) && (pi->sh->chiprev == 1) && (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { read_phy_reg(pi, pi->tbl_data_lo); @@ -1137,8 +1137,8 @@ wlc_phy_write_table(phy_info_t *pi, const phytbl_info_t *ptbl_info, for (idx = 0; idx < ptbl_info->tbl_len; idx++) { - if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID || - CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) && + if ((pi->sh->chip == BCM43224_CHIP_ID || + pi->sh->chip == BCM43421_CHIP_ID) && (pi->sh->chiprev == 1) && (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { read_phy_reg(pi, tblDataLo); @@ -1180,8 +1180,8 @@ wlc_phy_read_table(phy_info_t *pi, const phytbl_info_t *ptbl_info, for (idx = 0; idx < ptbl_info->tbl_len; idx++) { - if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID || - CHIPID(pi->sh->chip) == BCM43421_CHIP_ID) && + if ((pi->sh->chip == BCM43224_CHIP_ID || + pi->sh->chip == BCM43421_CHIP_ID) && (pi->sh->chiprev == 1)) { (void)read_phy_reg(pi, tblDataLo); @@ -3330,7 +3330,7 @@ const u8 *wlc_phy_get_ofdm_rate_lookup(void) void wlc_lcnphy_epa_switch(phy_info_t *pi, bool mode) { - if ((CHIPID(pi->sh->chip) == BCM4313_CHIP_ID) && + if ((pi->sh->chip == BCM4313_CHIP_ID) && (pi->sh->boardflags & BFL_FEM)) { if (mode) { u16 txant = 0; diff --git a/drivers/staging/brcm80211/phy/wlc_phy_n.c b/drivers/staging/brcm80211/phy/wlc_phy_n.c index c328de56e59a..c6cce8de1aee 100644 --- a/drivers/staging/brcm80211/phy/wlc_phy_n.c +++ b/drivers/staging/brcm80211/phy/wlc_phy_n.c @@ -14559,7 +14559,7 @@ void WLBANDINITFN(wlc_phy_init_nphy) (phy_info_t *pi) } } - if ((!PHY_IPA(pi)) && (CHIPID(pi->sh->chip) == BCM5357_CHIP_ID)) { + if ((!PHY_IPA(pi)) && (pi->sh->chip == BCM5357_CHIP_ID)) { si_pmu_chipcontrol(pi->sh->sih, 1, CCTRL5357_EXTPA, CCTRL5357_EXTPA); } @@ -17604,7 +17604,7 @@ static void wlc_phy_radio_postinit_2057(phy_info_t *pi) mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1); - if (CHIPID(pi->sh->chip) == !BCM6362_CHIP_ID) { + if (pi->sh->chip == !BCM6362_CHIP_ID) { mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x2, 0x2); } @@ -18012,8 +18012,8 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi, write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN, 0x1f); - if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID)) { + if ((pi->sh->chip == BCM4716_CHIP_ID) || + (pi->sh->chip == BCM47162_CHIP_ID)) { write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 | @@ -18075,8 +18075,8 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi, WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, PADG_IDAC, 0xcc); - if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) || - (CHIPID(pi->sh->chip) == + if ((pi->sh->chip == BCM4716_CHIP_ID) || + (pi->sh->chip == BCM47162_CHIP_ID)) { bias = 0x40; cascbias = 0x45; @@ -18088,11 +18088,11 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi, bias = 0x25; cascbias = 0x20; - if ((CHIPID(pi->sh->chip) == + if ((pi->sh->chip == BCM43224_CHIP_ID) - || (CHIPID(pi->sh->chip) == + || (pi->sh->chip == BCM43225_CHIP_ID) - || (CHIPID(pi->sh->chip) == + || (pi->sh->chip == BCM43421_CHIP_ID)) { if (pi->sh->chippkg == BCM43224_FAB_SMIC) { @@ -18203,9 +18203,9 @@ wlc_phy_chanspec_radio2056_setup(phy_info_t *pi, cascbias = 0x30; - if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM43225_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM43421_CHIP_ID)) { + if ((pi->sh->chip == BCM43224_CHIP_ID) || + (pi->sh->chip == BCM43225_CHIP_ID) || + (pi->sh->chip == BCM43421_CHIP_ID)) { if (pi->sh->chippkg == BCM43224_FAB_SMIC) { cascbias = 0x35; } @@ -18932,7 +18932,7 @@ static void wlc_phy_spurwar_nphy(phy_info_t *pi) case 38: case 102: case 118: - if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) && + if ((pi->sh->chip == BCM4716_CHIP_ID) && (pi->sh->chippkg == BCM4717_PKG_ID)) { nphy_adj_tone_id_buf[0] = 32; nphy_adj_noise_var_buf[0] = 0x21f; @@ -19067,7 +19067,7 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec, if (pi->nphy_aband_spurwar_en && ((val == 38) || (val == 102) || (val == 118))) { - if ((CHIPID(pi->sh->chip) == + if ((pi->sh->chip == BCM4716_CHIP_ID) && (pi->sh->chippkg == BCM4717_PKG_ID)) { @@ -19082,8 +19082,8 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec, if (pi->phy_spuravoid == SPURAVOID_FORCEON) spuravoid = 1; - if ((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID)) { + if ((pi->sh->chip == BCM4716_CHIP_ID) || + (pi->sh->chip == BCM47162_CHIP_ID)) { si_pmu_spuravoid(pi->sh->sih, pi->sh->osh, spuravoid); } else { wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); @@ -19091,9 +19091,9 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec, wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); } - if ((CHIPID(pi->sh->chip) == BCM43224_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM43225_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM43421_CHIP_ID)) { + if ((pi->sh->chip == BCM43224_CHIP_ID) || + (pi->sh->chip == BCM43225_CHIP_ID) || + (pi->sh->chip == BCM43421_CHIP_ID)) { if (spuravoid == 1) { @@ -19110,8 +19110,8 @@ wlc_phy_chanspec_nphy_setup(phy_info_t *pi, chanspec_t chanspec, } } - if (!((CHIPID(pi->sh->chip) == BCM4716_CHIP_ID) || - (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID))) { + if (!((pi->sh->chip == BCM4716_CHIP_ID) || + (pi->sh->chip == BCM47162_CHIP_ID))) { wlapi_bmac_core_phypll_reset(pi->sh->physhim); } @@ -21067,11 +21067,11 @@ s16 wlc_phy_tempsense_nphy(phy_info_t *pi) wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, &auxADC_rssi_ctrlH_save); - if (CHIPID(pi->sh->chip) == BCM5357_CHIP_ID) { + if (pi->sh->chip == BCM5357_CHIP_ID) { radio_temp[0] = (193 * (radio_temp[1] + radio_temp2[1]) + 88 * (auxADC_Vl) - 27111 + 128) / 256; - } else if (CHIPID(pi->sh->chip) == BCM43236_CHIP_ID) { + } else if (pi->sh->chip == BCM43236_CHIP_ID) { radio_temp[0] = (198 * (radio_temp[1] + radio_temp2[1]) + 91 * (auxADC_Vl) - 27243 + 128) / 256; @@ -26282,7 +26282,7 @@ static u32 *wlc_phy_get_ipa_gaintbl_nphy(phy_info_t *pi) } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6; - if (CHIPID(pi->sh->chip) == BCM47162_CHIP_ID) { + if (pi->sh->chip == BCM47162_CHIP_ID) { tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; } @@ -26838,7 +26838,7 @@ wlc_phy_a2_nphy(phy_info_t *pi, nphy_ipa_txcalgains_t *txgains, phy_a2 = 63; if (CHSPEC_IS2G(pi->radio_chanspec)) { - if (CHIPID(pi->sh->chip) == BCM6362_CHIP_ID) { + if (pi->sh->chip == BCM6362_CHIP_ID) { phy_a1 = 35; phy_a3 = 35; } else if ((pi->pubpi.radiorev == 4) @@ -26951,7 +26951,7 @@ wlc_phy_a2_nphy(phy_info_t *pi, nphy_ipa_txcalgains_t *txgains, if (NREV_GE(pi->pubpi.phy_rev, 6)) { phy_a5 = 0x00f7 | (phy_a4 << 8); - if (CHIPID(pi->sh->chip) == + if (pi->sh->chip == BCM47162_CHIP_ID) { phy_a5 = 0x10f7 | (phy_a4 << diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 6711c69edf38..b28dfb301ae4 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -407,8 +407,8 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded) WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now)); printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", - __func__, CHIPID(wlc_hw->sih->chip), - CHIPREV(wlc_hw->sih->chiprev)); + __func__, wlc_hw->sih->chip, + CHIPREV(wlc_hw->sih->chiprev)); WLCNTINCR(wlc->pub->_cnt->psmwds); @@ -842,7 +842,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, } else wlc_hw->_nbands = 1; - if ((CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID)) + if ((wlc_hw->sih->chip == BCM43225_CHIP_ID)) wlc_hw->_nbands = 1; /* BMAC_NOTE: remove init of pub values when wlc_attach() unconditionally does the @@ -2224,9 +2224,9 @@ bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw) flags |= SICF_PCLKE; /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */ - if ((CHIPID(wlc_hw->sih->chip) == BCM43224_CHIP_ID) || - (CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID) || - (CHIPID(wlc_hw->sih->chip) == BCM43421_CHIP_ID)) + if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || + (wlc_hw->sih->chip == BCM43225_CHIP_ID) || + (wlc_hw->sih->chip == BCM43421_CHIP_ID)) wlc_hw->regs = (d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID, 0); @@ -2266,9 +2266,9 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw) si_pci_fixcfg(wlc_hw->sih); /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */ - if ((CHIPID(wlc_hw->sih->chip) == BCM43224_CHIP_ID) || - (CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID) || - (CHIPID(wlc_hw->sih->chip) == BCM43421_CHIP_ID)) + if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || + (wlc_hw->sih->chip == BCM43225_CHIP_ID) || + (wlc_hw->sih->chip == BCM43421_CHIP_ID)) wlc_hw->regs = (d11regs_t *) si_setcore(wlc_hw->sih, D11_CORE_ID, 0); @@ -2281,7 +2281,7 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw) wlc_hw->wlc->pub->hw_up = true; if ((wlc_hw->boardflags & BFL_FEM) - && (CHIPID(wlc_hw->sih->chip) == BCM4313_CHIP_ID)) { + && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) { if (! (wlc_hw->boardrev >= 0x1250 && (wlc_hw->boardflags & BFL_FEM_BT))) @@ -2689,8 +2689,8 @@ void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode) regs = wlc_hw->regs; osh = wlc_hw->osh; - if ((CHIPID(wlc_hw->sih->chip) == BCM43224_CHIP_ID) || - (CHIPID(wlc_hw->sih->chip) == BCM43225_CHIP_ID)) { + if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || + (wlc_hw->sih->chip == BCM43225_CHIP_ID)) { if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ W_REG(osh, ®s->tsf_clk_frac_l, 0x2082); W_REG(osh, ®s->tsf_clk_frac_h, 0x8); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 7017db68c983..f64a9e8b8281 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -1991,7 +1991,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, wlc_radio_mpc_upd(wlc); if (WLANTSEL_ENAB(wlc)) { - if ((CHIPID(wlc->pub->sih->chip)) == BCM43235_CHIP_ID) { + if ((wlc->pub->sih->chip) == BCM43235_CHIP_ID) { if ((getintvar(wlc->pub->vars, "aa2g") == 7) || (getintvar(wlc->pub->vars, "aa5g") == 7)) { wlc_bmac_antsel_set(wlc->hw, 1); @@ -2537,7 +2537,7 @@ int wlc_up(wlc_info_t *wlc) } if ((wlc->pub->boardflags & BFL_FEM) - && (CHIPID(wlc->pub->sih->chip) == BCM4313_CHIP_ID)) { + && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) { if (wlc->pub->boardrev >= 0x1250 && (wlc->pub->boardflags & BFL_FEM_BT)) { wlc_mhf(wlc, MHF5, MHF5_4313_GPIOCTRL, @@ -6427,8 +6427,8 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus) WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc->pub->unit, wlc->pub->now)); printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", - __func__, CHIPID(wlc->pub->sih->chip), - CHIPREV(wlc->pub->sih->chiprev)); + __func__, wlc->pub->sih->chip, + CHIPREV(wlc->pub->sih->chiprev)); WLCNTINCR(wlc->pub->_cnt->psmwds); diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c index 09e09c9770a9..7e3cce24e174 100644 --- a/drivers/staging/brcm80211/util/aiutils.c +++ b/drivers/staging/brcm80211/util/aiutils.c @@ -31,7 +31,7 @@ #include #include -#define BCM47162_DMP() ((CHIPID(sih->chip) == BCM47162_CHIP_ID) && \ +#define BCM47162_DMP() ((sih->chip == BCM47162_CHIP_ID) && \ (CHIPREV(sih->chiprev) == 0) && \ (sii->coreid[sii->curidx] == MIPS74K_CORE_ID)) diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c index 3c625c84619e..d820e7b9e970 100644 --- a/drivers/staging/brcm80211/util/bcmotp.c +++ b/drivers/staging/brcm80211/util/bcmotp.c @@ -223,7 +223,7 @@ static int ipxotp_max_rgnsz(si_t *sih, int osizew) { int ret = 0; - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; @@ -273,8 +273,8 @@ static void _ipxotp_init(otpinfo_t *oi, chipcregs_t *cc) /* Read OTP lock bits and subregion programmed indication bits */ oi->status = R_REG(oi->osh, &cc->otpstatus); - if ((CHIPID(oi->sih->chip) == BCM43224_CHIP_ID) - || (CHIPID(oi->sih->chip) == BCM43225_CHIP_ID)) { + if ((oi->sih->chip == BCM43224_CHIP_ID) + || (oi->sih->chip == BCM43225_CHIP_ID)) { u32 p_bits; p_bits = (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) & diff --git a/drivers/staging/brcm80211/util/hndpmu.c b/drivers/staging/brcm80211/util/hndpmu.c index 45f4fdaed0ac..466c8a603022 100644 --- a/drivers/staging/brcm80211/util/hndpmu.c +++ b/drivers/staging/brcm80211/util/hndpmu.c @@ -136,7 +136,7 @@ void si_pmu_set_ldo_voltage(si_t *sih, struct osl_info *osh, u8 ldo, u8 voltage) ASSERT(sih->cccaps & CC_CAP_PMU); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4336_CHIP_ID: switch (ldo) { case SET_LDO_VOLTAGE_CLDO_PWM: @@ -204,7 +204,7 @@ u16 si_pmu_fast_pwrup_delay(si_t *sih, struct osl_info *osh) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM43421_CHIP_ID: @@ -604,7 +604,7 @@ static void si_pmu_res_masks(si_t *sih, u32 * pmin, u32 * pmax) rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT; /* determine min/max rsrc masks */ - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM43421_CHIP_ID: @@ -701,7 +701,7 @@ void si_pmu_res_init(si_t *sih, struct osl_info *osh) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: /* Optimize resources up/down timers */ if (ISSIM_ENAB(sih)) { @@ -1100,7 +1100,7 @@ static const pmu1_xtaltab0_t *si_pmu1_xtaltab0(si_t *sih) #ifdef BCMDBG char chn[8]; #endif - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: return pmu1_xtaltab0_880_4329; case BCM4319_CHIP_ID: @@ -1128,7 +1128,7 @@ static const pmu1_xtaltab0_t *si_pmu1_xtaldef0(si_t *sih) char chn[8]; #endif - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: /* Default to 38400Khz */ return &pmu1_xtaltab0_880_4329[PMU1_XTALTAB0_880_38400K]; @@ -1160,7 +1160,7 @@ static u32 si_pmu1_pllfvco0(si_t *sih) char chn[8]; #endif - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: return FVCO_880; case BCM4319_CHIP_ID: @@ -1239,8 +1239,8 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, */ if ((((R_REG(osh, &cc->pmucontrol) & PCTL_XTALFREQ_MASK) >> PCTL_XTALFREQ_SHIFT) == xt->xf) && - !((CHIPID(sih->chip) == BCM4319_CHIP_ID) - || (CHIPID(sih->chip) == BCM4330_CHIP_ID))) { + !((sih->chip == BCM4319_CHIP_ID) + || (sih->chip == BCM4330_CHIP_ID))) { PMU_MSG(("PLL already programmed for %d.%d MHz\n", xt->fref / 1000, xt->fref % 1000)); return; @@ -1250,7 +1250,7 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, PMU_MSG(("Programming PLL for %d.%d MHz\n", xt->fref / 1000, xt->fref % 1000)); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: /* Change the BBPLL drive strength to 8 for all channels */ buf_strength = 0x888888; @@ -1357,10 +1357,10 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, p2div << PMU1_PLL0_PC0_P2DIV_SHIFT) & PMU1_PLL0_PC0_P2DIV_MASK); W_REG(osh, &cc->pllcontrol_data, tmp); - if ((CHIPID(sih->chip) == BCM4330_CHIP_ID)) + if ((sih->chip == BCM4330_CHIP_ID)) si_pmu_set_4330_plldivs(sih); - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) + if ((sih->chip == BCM4329_CHIP_ID) && (CHIPREV(sih->chiprev) == 0)) { W_REG(osh, &cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); @@ -1369,9 +1369,9 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, tmp = tmp | DOT11MAC_880MHZ_CLK_DIVISOR_VAL; W_REG(osh, &cc->pllcontrol_data, tmp); } - if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) || - (CHIPID(sih->chip) == BCM4336_CHIP_ID) || - (CHIPID(sih->chip) == BCM4330_CHIP_ID)) + if ((sih->chip == BCM4319_CHIP_ID) || + (sih->chip == BCM4336_CHIP_ID) || + (sih->chip == BCM4330_CHIP_ID)) ndiv_mode = PMU1_PLL0_PC2_NDIV_MODE_MFB; else ndiv_mode = PMU1_PLL0_PC2_NDIV_MODE_MASH; @@ -1413,7 +1413,7 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, /* to operate the 4319 usb in 24MHz/48MHz; chipcontrol[2][84:83] needs * to be updated. */ - if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) + if ((sih->chip == BCM4319_CHIP_ID) && (xt->fref != XTAL_FREQ_30000MHZ)) { W_REG(osh, &cc->chipcontrol_addr, PMU1_PLL0_CHIPCTL2); tmp = @@ -1442,7 +1442,7 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, PCTL_ILP_DIV_MASK) | ((xt->xf << PCTL_XTALFREQ_SHIFT) & PCTL_XTALFREQ_MASK); - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) + if ((sih->chip == BCM4329_CHIP_ID) && CHIPREV(sih->chiprev) == 0) { /* clear the htstretch before clearing HTReqEn */ AND_REG(osh, &cc->clkstretch, ~CSTRETCH_HT); @@ -1523,7 +1523,7 @@ void si_pmu_pll_init(si_t *sih, struct osl_info *osh, uint xtalfreq) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: if (xtalfreq == 0) xtalfreq = 38400; @@ -1577,7 +1577,7 @@ u32 si_pmu_alp_clock(si_t *sih, struct osl_info *osh) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM43421_CHIP_ID: @@ -1637,7 +1637,7 @@ si_pmu5_clock(si_t *sih, struct osl_info *osh, chipcregs_t *cc, uint pll0, return 0; } - if (CHIPID(sih->chip) == BCM5357_CHIP_ID) { + if (sih->chip == BCM5357_CHIP_ID) { /* Detect failure in clock setting */ if ((R_REG(osh, &cc->chipstatus) & 0x40000) != 0) { return 133 * 1000000; @@ -1691,7 +1691,7 @@ u32 si_pmu_si_clock(si_t *sih, struct osl_info *osh) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM43224_CHIP_ID: case BCM43225_CHIP_ID: case BCM43421_CHIP_ID: @@ -1763,14 +1763,14 @@ u32 si_pmu_cpu_clock(si_t *sih, struct osl_info *osh) ASSERT(sih->cccaps & CC_CAP_PMU); if ((sih->pmurev >= 5) && - !((CHIPID(sih->chip) == BCM4329_CHIP_ID) || - (CHIPID(sih->chip) == BCM4319_CHIP_ID) || - (CHIPID(sih->chip) == BCM43236_CHIP_ID) || - (CHIPID(sih->chip) == BCM4336_CHIP_ID) || - (CHIPID(sih->chip) == BCM4330_CHIP_ID))) { + !((sih->chip == BCM4329_CHIP_ID) || + (sih->chip == BCM4319_CHIP_ID) || + (sih->chip == BCM43236_CHIP_ID) || + (sih->chip == BCM4336_CHIP_ID) || + (sih->chip == BCM4330_CHIP_ID))) { uint pll; - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM5356_CHIP_ID: pll = PMU5356_MAINPLL_PLL0; break; @@ -1807,14 +1807,14 @@ u32 si_pmu_mem_clock(si_t *sih, struct osl_info *osh) ASSERT(sih->cccaps & CC_CAP_PMU); if ((sih->pmurev >= 5) && - !((CHIPID(sih->chip) == BCM4329_CHIP_ID) || - (CHIPID(sih->chip) == BCM4319_CHIP_ID) || - (CHIPID(sih->chip) == BCM4330_CHIP_ID) || - (CHIPID(sih->chip) == BCM4336_CHIP_ID) || - (CHIPID(sih->chip) == BCM43236_CHIP_ID))) { + !((sih->chip == BCM4329_CHIP_ID) || + (sih->chip == BCM4319_CHIP_ID) || + (sih->chip == BCM4330_CHIP_ID) || + (sih->chip == BCM4336_CHIP_ID) || + (sih->chip == BCM43236_CHIP_ID))) { uint pll; - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM5356_CHIP_ID: pll = PMU5356_MAINPLL_PLL0; break; @@ -1999,7 +1999,7 @@ void si_pmu_init(si_t *sih, struct osl_info *osh) else if (sih->pmurev >= 2) OR_REG(osh, &cc->pmucontrol, PCTL_NOILP_ON_WAIT); - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 2)) { + if ((sih->chip == BCM4329_CHIP_ID) && (sih->chiprev == 2)) { /* Fix for 4329b0 bad LPOM state. */ W_REG(osh, &cc->regcontrol_addr, 2); OR_REG(osh, &cc->regcontrol_data, 0x100); @@ -2090,7 +2090,7 @@ void si_pmu_otp_power(si_t *sih, struct osl_info *osh, bool on) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: rsrcs = PMURES_BIT(RES4329_OTP_PU); break; @@ -2153,7 +2153,7 @@ void si_pmu_rcal(si_t *sih, struct osl_info *osh) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID:{ u8 rcal_code; u32 val; @@ -2236,7 +2236,7 @@ void si_pmu_spuravoid(si_t *sih, struct osl_info *osh, u8 spuravoid) ASSERT(cc != NULL); /* force the HT off */ - if (CHIPID(sih->chip) == BCM4336_CHIP_ID) { + if (sih->chip == BCM4336_CHIP_ID) { tmp = R_REG(osh, &cc->max_res_mask); tmp &= ~RES4336_HT_AVAIL; W_REG(osh, &cc->max_res_mask, tmp); @@ -2250,7 +2250,7 @@ void si_pmu_spuravoid(si_t *sih, struct osl_info *osh, u8 spuravoid) si_pmu_spuravoid_pllupdate(sih, cc, osh, spuravoid); /* enable HT back on */ - if (CHIPID(sih->chip) == BCM4336_CHIP_ID) { + if (sih->chip == BCM4336_CHIP_ID) { tmp = R_REG(osh, &cc->max_res_mask); tmp |= RES4336_HT_AVAIL; W_REG(osh, &cc->max_res_mask, tmp); @@ -2269,14 +2269,14 @@ si_pmu_spuravoid_pllupdate(si_t *sih, chipcregs_t *cc, struct osl_info *osh, u8 bcm5357_bcm43236_p1div[] = { 0x1, 0x5, 0x5 }; u8 bcm5357_bcm43236_ndiv[] = { 0x30, 0xf6, 0xfc }; - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM5357_CHIP_ID: case BCM43235_CHIP_ID: case BCM43236_CHIP_ID: case BCM43238_CHIP_ID: /* BCM5357 needs to touch PLL1_PLLCTL[02], so offset PLL0_PLLCTL[02] by 6 */ - phypll_offset = (CHIPID(sih->chip) == BCM5357_CHIP_ID) ? 6 : 0; + phypll_offset = (sih->chip == BCM5357_CHIP_ID) ? 6 : 0; /* RMW only the P1 divider */ W_REG(osh, &cc->pllcontrol_addr, @@ -2468,7 +2468,7 @@ bool si_pmu_is_otp_powered(si_t *sih, struct osl_info *osh) cc = si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc != NULL); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: st = (R_REG(osh, &cc->res_state) & PMURES_BIT(RES4329_OTP_PU)) != 0; @@ -2553,7 +2553,7 @@ void si_pmu_swreg_init(si_t *sih, struct osl_info *osh) { ASSERT(sih->cccaps & CC_CAP_PMU); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4336_CHIP_ID: /* Reduce CLDO PWM output voltage to 1.2V */ si_pmu_set_ldo_voltage(sih, osh, SET_LDO_VOLTAGE_CLDO_PWM, 0xe); @@ -2579,7 +2579,7 @@ void si_pmu_radio_enable(si_t *sih, bool enable) { ASSERT(sih->cccaps & CC_CAP_PMU); - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4319_CHIP_ID: if (enable) si_write_wrapperreg(sih, AI_OOBSELOUTB74, diff --git a/drivers/staging/brcm80211/util/sbutils.c b/drivers/staging/brcm80211/util/sbutils.c index 7b93ac22d4fc..63c3ab1866a4 100644 --- a/drivers/staging/brcm80211/util/sbutils.c +++ b/drivers/staging/brcm80211/util/sbutils.c @@ -251,7 +251,7 @@ static uint _sb_scan(si_info_t *sii, u32 sba, void *regs, uint bus, u32 sbba, else { /* Older chips */ SI_ERROR(("sb_chip2numcores: unsupported chip " - "0x%x\n", CHIPID(sii->pub.chip))); + "0x%x\n", sii->pub.chip)); ASSERT(0); numcores = 1; } diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index da35edd2d7b5..3d694b99f6c1 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -414,7 +414,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; - if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && + if ((sih->chip == BCM4329_CHIP_ID) && (sih->chippkg != BCM4329_289PIN_PKG_ID)) sih->chippkg = BCM4329_182PIN_PKG_ID; @@ -591,9 +591,9 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, /* assume current core is CC */ if ((sii->pub.ccrev == 0x25) && - ((CHIPID(sih->chip) == BCM43236_CHIP_ID - || CHIPID(sih->chip) == BCM43235_CHIP_ID - || CHIPID(sih->chip) == BCM43238_CHIP_ID) + ((sih->chip == BCM43236_CHIP_ID + || sih->chip == BCM43235_CHIP_ID + || sih->chip == BCM43238_CHIP_ID) && (CHIPREV(sii->pub.chiprev) <= 2))) { if ((cc->chipstatus & CST43236_BP_CLK) != 0) { @@ -650,8 +650,8 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, pcicore_attach(sii->pch, pvars, SI_DOATTACH); } - if ((CHIPID(sih->chip) == BCM43224_CHIP_ID) || - (CHIPID(sih->chip) == BCM43421_CHIP_ID)) { + if ((sih->chip == BCM43224_CHIP_ID) || + (sih->chip == BCM43421_CHIP_ID)) { /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */ if (CHIPREV(sih->chiprev) == 0) { SI_MSG(("Applying 43224A0 WARs\n")); @@ -669,14 +669,14 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, } } - if (CHIPID(sih->chip) == BCM4313_CHIP_ID) { + if (sih->chip == BCM4313_CHIP_ID) { /* enable 12 mA drive strenth for 4313 and set chipControl register bit 1 */ SI_MSG(("Applying 4313 WARs\n")); si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, CCTRL_4313_12MA_LED_DRIVE); } - if (CHIPID(sih->chip) == BCM4331_CHIP_ID) { + if (sih->chip == BCM4331_CHIP_ID) { /* Enable Ext PA lines depending on chip package option */ si_chipcontrl_epa4331(sih, true); } @@ -1042,7 +1042,7 @@ void si_watchdog(si_t *sih, uint ticks) if (PMUCTL_ENAB(sih)) { - if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && + if ((sih->chip == BCM4319_CHIP_ID) && (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, clk_ctl_st), ~0, 0x2); @@ -1957,7 +1957,7 @@ bool si_is_sprom_available(si_t *sih) return sromctrl & SRC_PRESENT; } - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: return (sih->chipst & CST4329_SPROM_SEL) != 0; case BCM4319_CHIP_ID: @@ -1977,7 +1977,7 @@ bool si_is_sprom_available(si_t *sih) bool si_is_otp_disabled(si_t *sih) { - switch (CHIPID(sih->chip)) { + switch (sih->chip) { case BCM4329_CHIP_ID: return (sih->chipst & CST4329_SPROM_OTP_SEL_MASK) == CST4329_OTP_PWRDN; -- cgit v1.2.3 From ff29ee8f9301c38f28d4d22fe49373d3b996956e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 2 Dec 2010 15:44:52 +0100 Subject: staging: brcm80211: remove redundant CHIPREV macro The CHIPREV macro simply expands to the macro argument so it is redundant and as such removed. Reviewed-by: Roland Vossen Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmdefs.h | 1 - drivers/staging/brcm80211/sys/wlc_bmac.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- drivers/staging/brcm80211/util/aiutils.c | 2 +- drivers/staging/brcm80211/util/hndpmu.c | 8 ++++---- drivers/staging/brcm80211/util/siutils.c | 8 ++++---- 6 files changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmdefs.h b/drivers/staging/brcm80211/include/bcmdefs.h index 82356129caa5..74601fc971c9 100644 --- a/drivers/staging/brcm80211/include/bcmdefs.h +++ b/drivers/staging/brcm80211/include/bcmdefs.h @@ -51,7 +51,6 @@ #define SPI_BUS 6 /* gSPI target */ #define RPC_BUS 7 /* RPC target */ -#define CHIPREV(rev) (rev) /* Defines for DMA Address Width - Shared between OSL and HNDDMA */ #define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index b28dfb301ae4..79ee24f3b07f 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -408,7 +408,7 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded) printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", __func__, wlc_hw->sih->chip, - CHIPREV(wlc_hw->sih->chiprev)); + wlc_hw->sih->chiprev); WLCNTINCR(wlc->pub->_cnt->psmwds); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index f64a9e8b8281..9aae3405aa11 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -6428,7 +6428,7 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus) printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", __func__, wlc->pub->sih->chip, - CHIPREV(wlc->pub->sih->chiprev)); + wlc->pub->sih->chiprev); WLCNTINCR(wlc->pub->_cnt->psmwds); diff --git a/drivers/staging/brcm80211/util/aiutils.c b/drivers/staging/brcm80211/util/aiutils.c index 7e3cce24e174..ddd2f9d64c20 100644 --- a/drivers/staging/brcm80211/util/aiutils.c +++ b/drivers/staging/brcm80211/util/aiutils.c @@ -32,7 +32,7 @@ #include #define BCM47162_DMP() ((sih->chip == BCM47162_CHIP_ID) && \ - (CHIPREV(sih->chiprev) == 0) && \ + (sih->chiprev == 0) && \ (sii->coreid[sii->curidx] == MIPS74K_CORE_ID)) /* EROM parsing */ diff --git a/drivers/staging/brcm80211/util/hndpmu.c b/drivers/staging/brcm80211/util/hndpmu.c index 466c8a603022..6cc59a895868 100644 --- a/drivers/staging/brcm80211/util/hndpmu.c +++ b/drivers/staging/brcm80211/util/hndpmu.c @@ -1361,7 +1361,7 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, si_pmu_set_4330_plldivs(sih); if ((sih->chip == BCM4329_CHIP_ID) - && (CHIPREV(sih->chiprev) == 0)) { + && (sih->chiprev == 0)) { W_REG(osh, &cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); tmp = R_REG(osh, &cc->pllcontrol_data); @@ -1443,7 +1443,7 @@ static void si_pmu1_pllinit0(si_t *sih, struct osl_info *osh, chipcregs_t *cc, ((xt->xf << PCTL_XTALFREQ_SHIFT) & PCTL_XTALFREQ_MASK); if ((sih->chip == BCM4329_CHIP_ID) - && CHIPREV(sih->chiprev) == 0) { + && sih->chiprev == 0) { /* clear the htstretch before clearing HTReqEn */ AND_REG(osh, &cc->clkstretch, ~CSTRETCH_HT); tmp &= ~PCTL_HT_REQ_EN; @@ -1708,7 +1708,7 @@ u32 si_pmu_si_clock(si_t *sih, struct osl_info *osh) PMU5_MAINPLL_SI); break; case BCM4329_CHIP_ID: - if (CHIPREV(sih->chiprev) == 0) + if (sih->chiprev == 0) clock = 38400 * 1000; else clock = si_pmu1_cpuclk0(sih, osh, cc); @@ -2562,7 +2562,7 @@ void si_pmu_swreg_init(si_t *sih, struct osl_info *osh) 0xe); /* Reduce LNLDO1 output voltage to 1.2V */ si_pmu_set_ldo_voltage(sih, osh, SET_LDO_VOLTAGE_LNLDO1, 0xe); - if (CHIPREV(sih->chiprev) == 0) + if (sih->chiprev == 0) si_pmu_regcontrol(sih, 2, 0x400000, 0x400000); break; diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 3d694b99f6c1..29d2d68354f6 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -594,7 +594,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, ((sih->chip == BCM43236_CHIP_ID || sih->chip == BCM43235_CHIP_ID || sih->chip == BCM43238_CHIP_ID) - && (CHIPREV(sii->pub.chiprev) <= 2))) { + && (sii->pub.chiprev <= 2))) { if ((cc->chipstatus & CST43236_BP_CLK) != 0) { uint clkdiv; @@ -653,7 +653,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, if ((sih->chip == BCM43224_CHIP_ID) || (sih->chip == BCM43421_CHIP_ID)) { /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */ - if (CHIPREV(sih->chiprev) == 0) { + if (sih->chiprev == 0) { SI_MSG(("Applying 43224A0 WARs\n")); si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, chipcontrol), @@ -662,7 +662,7 @@ static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, CCTRL_43224A0_12MA_LED_DRIVE); } - if (CHIPREV(sih->chiprev) >= 1) { + if (sih->chiprev >= 1) { SI_MSG(("Applying 43224B0+ WARs\n")); si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, CCTRL_43224B0_12MA_LED_DRIVE); @@ -1043,7 +1043,7 @@ void si_watchdog(si_t *sih, uint ticks) if (PMUCTL_ENAB(sih)) { if ((sih->chip == BCM4319_CHIP_ID) && - (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { + (sih->chiprev == 0) && (ticks != 0)) { si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, clk_ctl_st), ~0, 0x2); si_setcore(sih, USB20D_CORE_ID, 0); -- cgit v1.2.3 From eb6b420da13fee2edc30b7bde67c0c8993c4c30d Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 2 Dec 2010 00:43:32 +0100 Subject: staging/sep: Fix sparse warning 'do-while statement is not a compound statement' This patch fixes the warning generated by sparse: 'do-while statement is not a compound statement' by adding the necessary brackets around the do block Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_dev.h | 4 ++-- drivers/staging/sep/sep_driver.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_dev.h b/drivers/staging/sep/sep_dev.h index 7b4993b3650d..0ffe68cb7140 100644 --- a/drivers/staging/sep/sep_dev.h +++ b/drivers/staging/sep/sep_dev.h @@ -147,9 +147,9 @@ static inline u32 sep_read_reg(struct sep_device *dev, int reg) static inline void sep_wait_sram_write(struct sep_device *dev) { u32 reg_val; - do + do { reg_val = sep_read_reg(dev, HW_SRAM_DATA_READY_REG_ADDR); - while (!(reg_val & 1)); + } while (!(reg_val & 1)); } diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 76331112a264..d7348871b17b 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -2587,9 +2587,9 @@ static int sep_start_handler(struct sep_device *sep) dev_dbg(&sep->pdev->dev, "sep_start_handler start\n"); /* Wait in polling for message from SEP */ - do + do { reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!reg_val); + } while (!reg_val); /* Check the value */ if (reg_val == 0x1) @@ -2754,9 +2754,9 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) /* Wait for acknowledge */ dev_dbg(&sep->pdev->dev, "init; waiting for msg response\n"); - do + do { reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!(reg_val & 0xFFFFFFFD)); + } while (!(reg_val & 0xFFFFFFFD)); if (reg_val == 0x1) { dev_warn(&sep->pdev->dev, "init; device int failed\n"); @@ -2774,9 +2774,9 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) /* Wait for response */ dev_dbg(&sep->pdev->dev, "init; waiting for zero set response\n"); - do + do { reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (reg_val != 0); + } while (reg_val != 0); end_function: dev_dbg(&sep->pdev->dev, "init is done\n"); -- cgit v1.2.3 From dda16b23e32cf2351aa03590f43cc8a2873dc6a9 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 2 Dec 2010 00:43:33 +0100 Subject: staging/sep: Fix sparse warning 'Using plain integer as NULL pointer' This patch fixes the warning generated by sparse: "Using plain integer as NULL pointer" by replacing the offending 0s with NULL. Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index d7348871b17b..2216beddecee 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -459,12 +459,12 @@ static int sep_free_dma_table_data_handler(struct sep_device *sep) } /* Reset all the values */ - dma->in_page_array = 0; - dma->out_page_array = 0; + dma->in_page_array = NULL; + dma->out_page_array = NULL; dma->in_num_pages = 0; dma->out_num_pages = 0; - dma->in_map_array = 0; - dma->out_map_array = 0; + dma->in_map_array = NULL; + dma->out_map_array = NULL; dma->in_map_num_entries = 0; dma->out_map_num_entries = 0; } @@ -1114,13 +1114,13 @@ static int sep_lock_kernel_pages(struct sep_device *sep, if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 1; - sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL; sep->dma_res_arr[sep->nr_dcb_creat].in_map_array = map_array; sep->dma_res_arr[sep->nr_dcb_creat].in_map_num_entries = 1; } else { *lli_array_ptr = lli_array; sep->dma_res_arr[sep->nr_dcb_creat].out_num_pages = 1; - sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = NULL; sep->dma_res_arr[sep->nr_dcb_creat].out_map_array = map_array; sep->dma_res_arr[sep->nr_dcb_creat].out_map_num_entries = 1; } @@ -1216,7 +1216,7 @@ static int sep_lock_user_pages(struct sep_device *sep, result = get_user_pages(current, current->mm, app_virt_addr, num_pages, ((in_out_flag == SEP_DRIVER_IN_FLAG) ? 0 : 1), - 0, page_array, 0); + 0, page_array, NULL); up_read(¤t->mm->mmap_sem); @@ -1709,7 +1709,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "block_size is %x\n", block_size); /* Initialize the pages pointers */ - sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL; sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 0; /* Set the kernel address for first table to be allocated */ @@ -1745,7 +1745,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages); current_entry = 0; - info_entry_ptr = 0; + info_entry_ptr = NULL; sep_lli_entries = sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages; @@ -1794,7 +1794,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); - if (info_entry_ptr == 0) { + if (info_entry_ptr == NULL) { /* Set the output parameters to physical addresses */ *lli_table_ptr = sep_shared_area_virt_to_bus(sep, @@ -1877,13 +1877,13 @@ static int sep_construct_dma_tables_from_lli( /* Points to the area where next lli table can be allocated */ u32 lli_table_alloc_addr = 0; /* Input lli table */ - struct sep_lli_entry *in_lli_table_ptr = 0; + struct sep_lli_entry *in_lli_table_ptr = NULL; /* Output lli table */ - struct sep_lli_entry *out_lli_table_ptr = 0; + struct sep_lli_entry *out_lli_table_ptr = NULL; /* Pointer to the info entry of the table - the last entry */ - struct sep_lli_entry *info_in_entry_ptr = 0; + struct sep_lli_entry *info_in_entry_ptr = NULL; /* Pointer to the info entry of the table - the last entry */ - struct sep_lli_entry *info_out_entry_ptr = 0; + struct sep_lli_entry *info_out_entry_ptr = NULL; /* Points to the first entry to be processed in the lli_in_array */ u32 current_in_entry = 0; /* Points to the first entry to be processed in the lli_out_array */ @@ -1999,7 +1999,7 @@ static int sep_construct_dma_tables_from_lli( table_data_size); /* If info entry is null - this is the first table built */ - if (info_in_entry_ptr == 0) { + if (info_in_entry_ptr == NULL) { /* Set the output parameters to physical addresses */ *lli_table_in_ptr = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); @@ -2136,8 +2136,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, } /* Initialize the pages pointers */ - sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = 0; - sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = 0; + sep->dma_res_arr[sep->nr_dcb_creat].in_page_array = NULL; + sep->dma_res_arr[sep->nr_dcb_creat].out_page_array = NULL; /* Lock the pages of the buffer and translate them to pages */ if (is_kva == true) { @@ -2264,7 +2264,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, /* Size of tail */ u32 tail_size = 0; /* Address of the created DCB table */ - struct sep_dcblock *dcb_table_ptr = 0; + struct sep_dcblock *dcb_table_ptr = NULL; /* The physical address of the first input DMA table */ dma_addr_t in_first_mlli_address = 0; /* Number of entries in the first input DMA table */ @@ -2545,7 +2545,7 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg) { struct stat_pool_addr_struct command_args; - u32 *static_pool_addr = 0; + u32 *static_pool_addr = NULL; unsigned long addr_hold; dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler start\n"); -- cgit v1.2.3 From d1f521c16a4d7e46bbb9c6968076f80be995e0ed Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 2 Dec 2010 00:43:34 +0100 Subject: staging/sep: Fix printk format warning This patch fixes gcc's complaints about the wrong format string for size_t arguments: "format '%x' expects type 'unsigned int', but argument has type 'size_t'" Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 2216beddecee..f2c216df362e 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -110,7 +110,7 @@ static int sep_load_firmware(struct sep_device *sep) sep->resident_addr); dev_dbg(&sep->pdev->dev, "resident bus is %lx\n", (unsigned long)sep->resident_bus); - dev_dbg(&sep->pdev->dev, "resident size is %08x\n", + dev_dbg(&sep->pdev->dev, "resident size is %08zx\n", sep->resident_size); /* Set addresses for dcache (no loading needed) */ @@ -144,7 +144,7 @@ static int sep_load_firmware(struct sep_device *sep) sep->cache_addr); dev_dbg(&sep->pdev->dev, "cache bus is %08lx\n", (unsigned long)sep->cache_bus); - dev_dbg(&sep->pdev->dev, "cache size is %08x\n", + dev_dbg(&sep->pdev->dev, "cache size is %08zx\n", sep->cache_size); /* Set addresses and load extapp */ @@ -165,7 +165,7 @@ static int sep_load_firmware(struct sep_device *sep) sep->extapp_addr); dev_dbg(&sep->pdev->dev, "extapp bus is %08llx\n", (unsigned long long)sep->extapp_bus); - dev_dbg(&sep->pdev->dev, "extapp size is %08x\n", + dev_dbg(&sep->pdev->dev, "extapp size is %08zx\n", sep->extapp_size); return error; @@ -205,7 +205,7 @@ static int sep_map_and_alloc_shared_area(struct sep_device *sep) return -ENOMEM; } dev_dbg(&sep->pdev->dev, - "shared_addr %x bytes @%p (bus %llx)\n", + "shared_addr %zx bytes @%p (bus %llx)\n", sep->shared_size, sep->shared_addr, (unsigned long long)sep->shared_bus); return 0; @@ -3290,7 +3290,7 @@ static int sep_callback(unsigned long sep_context_pointer) error = -ENOMEM; goto end_function; } - dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx, size is %x\n", + dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx, size is %zx\n", sep->rar_addr, (unsigned long long)sep->rar_bus, sep->rar_size); @@ -3537,7 +3537,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, } dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx," - " size is %x\n", sep->rar_addr, + " size is %zx\n", sep->rar_addr, (unsigned long long)sep->rar_bus, sep->rar_size); } -- cgit v1.2.3 From d5c21fc6155549e7f92fdeb039227f2b8e597e98 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Thu, 2 Dec 2010 14:13:04 +0100 Subject: staging: adis16255 delete driver This patch deletes the adis16255 driver from staging as a similar implementation exists inside the iio subsystem. Signed-off-by: Matthias Brugger Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/adis16255/Kconfig | 11 - drivers/staging/adis16255/Makefile | 1 - drivers/staging/adis16255/adis16255.c | 468 ---------------------------------- drivers/staging/adis16255/adis16255.h | 12 - 6 files changed, 495 deletions(-) delete mode 100644 drivers/staging/adis16255/Kconfig delete mode 100644 drivers/staging/adis16255/Makefile delete mode 100644 drivers/staging/adis16255/adis16255.c delete mode 100644 drivers/staging/adis16255/adis16255.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 1f61914a3ab8..f2d9fe8cde5f 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -143,8 +143,6 @@ source "drivers/staging/cxt1e1/Kconfig" source "drivers/staging/ti-st/Kconfig" -source "drivers/staging/adis16255/Kconfig" - source "drivers/staging/xgifb/Kconfig" source "drivers/staging/msm/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 75c0c1ff1cf5..10c72bb1940d 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -54,7 +54,6 @@ obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_TI_ST) += ti-st/ -obj-$(CONFIG_ADIS16255) += adis16255/ obj-$(CONFIG_FB_XGI) += xgifb/ obj-$(CONFIG_MSM_STAGING) += msm/ obj-$(CONFIG_EASYCAP) += easycap/ diff --git a/drivers/staging/adis16255/Kconfig b/drivers/staging/adis16255/Kconfig deleted file mode 100644 index a883c1f4478b..000000000000 --- a/drivers/staging/adis16255/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config ADIS16255 - tristate "Analog Devices ADIS16250/16255" - depends on SPI && SYSFS - ---help--- - If you say yes here you get support for the Analog Devices - ADIS16250/16255 Low Power Gyroscope. The driver exposes - orientation and gyroscope value, as well as sample rate - to the sysfs. - - This driver can also be built as a module. If so, the module - will be called adis16255. diff --git a/drivers/staging/adis16255/Makefile b/drivers/staging/adis16255/Makefile deleted file mode 100644 index 8c3908106bfa..000000000000 --- a/drivers/staging/adis16255/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_ADIS16255) += adis16255.o diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c deleted file mode 100644 index 8d4d7cbab979..000000000000 --- a/drivers/staging/adis16255/adis16255.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Analog Devices ADIS16250/ADIS16255 Low Power Gyroscope - * - * Written by: Matthias Brugger - * - * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits - * - * 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. - */ - -/* - * The driver just has a bare interface to the sysfs (sample rate in Hz, - * orientation (x, y, z) and gyroscope data in °/sec. - * - * It should be added to iio subsystem when this has left staging. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include "adis16255.h" - -#define ADIS_STATUS 0x3d -#define ADIS_SMPL_PRD_MSB 0x37 -#define ADIS_SMPL_PRD_LSB 0x36 -#define ADIS_MSC_CTRL_MSB 0x35 -#define ADIS_MSC_CTRL_LSB 0x34 -#define ADIS_GPIO_CTRL 0x33 -#define ADIS_ALM_SMPL1 0x25 -#define ADIS_ALM_MAG1 0x21 -#define ADIS_GYRO_SCALE 0x17 -#define ADIS_GYRO_OUT 0x05 -#define ADIS_SUPPLY_OUT 0x03 -#define ADIS_ENDURANCE 0x01 - -/* - * data structure for every sensor - * - * @dev: Driver model representation of the device. - * @spi: Pointer to the spi device which will manage i/o to spi bus. - * @data: Last read data from device. - * @irq_adis: GPIO Number of IRQ signal - * @irq: irq line manage by kernel - * @negative: indicates if sensor is upside down (negative == 1) - * @direction: indicates axis (x, y, z) the sensor is meassuring - */ -struct spi_adis16255_data { - struct device dev; - struct spi_device *spi; - s16 data; - int irq; - u8 negative; - char direction; -}; - -/*-------------------------------------------------------------------------*/ - -static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis, - u8 adr, - u8 *rbuf) -{ - struct spi_device *spi = spiadis->spi; - struct spi_message msg; - struct spi_transfer xfer1, xfer2; - u8 *buf, *rx; - int ret; - - buf = kzalloc(4, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - rx = kzalloc(4, GFP_KERNEL); - if (rx == NULL) { - ret = -ENOMEM; - goto err_buf; - } - - buf[0] = adr; - - spi_message_init(&msg); - memset(&xfer1, 0, sizeof(xfer1)); - memset(&xfer2, 0, sizeof(xfer2)); - - xfer1.tx_buf = buf; - xfer1.rx_buf = buf + 2; - xfer1.len = 2; - xfer1.delay_usecs = 9; - - xfer2.tx_buf = rx + 2; - xfer2.rx_buf = rx; - xfer2.len = 2; - - spi_message_add_tail(&xfer1, &msg); - spi_message_add_tail(&xfer2, &msg); - - ret = spi_sync(spi, &msg); - if (ret == 0) { - rbuf[0] = rx[0]; - rbuf[1] = rx[1]; - } - - kfree(rx); -err_buf: - kfree(buf); - - return ret; -} - -static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis, - u8 adr1, - u8 adr2, - u8 *wbuf) -{ - struct spi_device *spi = spiadis->spi; - struct spi_message msg; - struct spi_transfer xfer1, xfer2; - u8 *buf, *rx; - int ret; - - buf = kmalloc(4, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - rx = kzalloc(4, GFP_KERNEL); - if (rx == NULL) { - ret = -ENOMEM; - goto err_buf; - } - - spi_message_init(&msg); - memset(&xfer1, 0, sizeof(xfer1)); - memset(&xfer2, 0, sizeof(xfer2)); - - buf[0] = adr1 | 0x80; - buf[1] = *wbuf; - - buf[2] = adr2 | 0x80; - buf[3] = *(wbuf + 1); - - xfer1.tx_buf = buf; - xfer1.rx_buf = rx; - xfer1.len = 2; - xfer1.delay_usecs = 9; - - xfer2.tx_buf = buf+2; - xfer2.rx_buf = rx+2; - xfer2.len = 2; - - spi_message_add_tail(&xfer1, &msg); - spi_message_add_tail(&xfer2, &msg); - - ret = spi_sync(spi, &msg); - if (ret != 0) - dev_warn(&spi->dev, "write data to %#x %#x failed\n", - buf[0], buf[2]); - - kfree(rx); -err_buf: - kfree(buf); - return ret; -} - -/*-------------------------------------------------------------------------*/ - -static irqreturn_t adis_irq_thread(int irq, void *dev_id) -{ - struct spi_adis16255_data *spiadis = dev_id; - int status; - u16 value = 0; - - status = spi_adis16255_read_data(spiadis, ADIS_GYRO_OUT, (u8 *)&value); - if (status != 0) { - dev_warn(&spiadis->spi->dev, "SPI FAILED\n"); - goto exit; - } - - /* perform on new data only... */ - if (value & 0x8000) { - /* delete error and new data bit */ - value = value & 0x3fff; - /* set negative value */ - if (value & 0x2000) - value = value | 0xe000; - - if (likely(spiadis->negative)) - value = -value; - - spiadis->data = (s16) value; - } - -exit: - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -ssize_t adis16255_show_data(struct device *device, - struct device_attribute *da, - char *buf) -{ - struct spi_adis16255_data *spiadis = dev_get_drvdata(device); - return snprintf(buf, PAGE_SIZE, "%d\n", spiadis->data); -} -DEVICE_ATTR(data, S_IRUGO , adis16255_show_data, NULL); - -ssize_t adis16255_show_direction(struct device *device, - struct device_attribute *da, - char *buf) -{ - struct spi_adis16255_data *spiadis = dev_get_drvdata(device); - return snprintf(buf, PAGE_SIZE, "%c\n", spiadis->direction); -} -DEVICE_ATTR(direction, S_IRUGO , adis16255_show_direction, NULL); - -ssize_t adis16255_show_sample_rate(struct device *device, - struct device_attribute *da, - char *buf) -{ - struct spi_adis16255_data *spiadis = dev_get_drvdata(device); - int status = 0; - u16 value = 0; - int ts = 0; - - status = spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB, - (u8 *)&value); - if (status != 0) - return -EINVAL; - - if (value & 0x80) { - /* timebase = 60.54 ms */ - ts = 60540 * ((0x7f & value) + 1); - } else { - /* timebase = 1.953 ms */ - ts = 1953 * ((0x7f & value) + 1); - } - - return snprintf(buf, PAGE_SIZE, "%d\n", (1000*1000)/ts); -} -DEVICE_ATTR(sample_rate, S_IRUGO , adis16255_show_sample_rate, NULL); - -static struct attribute *adis16255_attributes[] = { - &dev_attr_data.attr, - &dev_attr_direction.attr, - &dev_attr_sample_rate.attr, - NULL -}; - -static const struct attribute_group adis16255_attr_group = { - .attrs = adis16255_attributes, -}; - -/*-------------------------------------------------------------------------*/ - -static int spi_adis16255_shutdown(struct spi_adis16255_data *spiadis) -{ - u16 value = 0; - /* turn sensor off */ - spi_adis16255_write_data(spiadis, - ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, - (u8 *)&value); - spi_adis16255_write_data(spiadis, - ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, - (u8 *)&value); - return 0; -} - -static int spi_adis16255_bringup(struct spi_adis16255_data *spiadis) -{ - int status = 0; - u16 value = 0; - - status = spi_adis16255_read_data(spiadis, ADIS_GYRO_SCALE, - (u8 *)&value); - if (status != 0) - goto err; - if (value != 0x0800) { - dev_warn(&spiadis->spi->dev, "Scale factor is none default " - "value (%.4x)\n", value); - } - - /* timebase = 1.953 ms, Ns = 0 -> 512 Hz sample rate */ - value = 0x0001; - status = spi_adis16255_write_data(spiadis, - ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, - (u8 *)&value); - if (status != 0) - goto err; - - /* start internal self-test */ - value = 0x0400; - status = spi_adis16255_write_data(spiadis, - ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, - (u8 *)&value); - if (status != 0) - goto err; - - /* wait 35 ms to finish self-test */ - msleep(35); - - value = 0x0000; - status = spi_adis16255_read_data(spiadis, ADIS_STATUS, - (u8 *)&value); - if (status != 0) - goto err; - - if (value & 0x23) { - if (value & 0x20) { - dev_warn(&spiadis->spi->dev, "self-test error\n"); - status = -ENODEV; - goto err; - } else if (value & 0x3) { - dev_warn(&spiadis->spi->dev, "Sensor voltage " - "out of range.\n"); - status = -ENODEV; - goto err; - } - } - - /* set interrupt to active high on DIO0 when data ready */ - value = 0x0006; - status = spi_adis16255_write_data(spiadis, - ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, - (u8 *)&value); - if (status != 0) - goto err; - return status; - -err: - spi_adis16255_shutdown(spiadis); - return status; -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit spi_adis16255_probe(struct spi_device *spi) -{ - - struct adis16255_init_data *init_data = spi->dev.platform_data; - struct spi_adis16255_data *spiadis; - int status = 0; - - spiadis = kzalloc(sizeof(*spiadis), GFP_KERNEL); - if (!spiadis) - return -ENOMEM; - - spiadis->spi = spi; - spiadis->direction = init_data->direction; - - if (init_data->negative) - spiadis->negative = 1; - - status = gpio_request(init_data->irq, "adis16255"); - if (status != 0) - goto err; - - status = gpio_direction_input(init_data->irq); - if (status != 0) - goto gpio_err; - - spiadis->irq = gpio_to_irq(init_data->irq); - - status = request_threaded_irq(spiadis->irq, - NULL, adis_irq_thread, - IRQF_DISABLED, "adis-driver", spiadis); - - if (status != 0) { - dev_err(&spi->dev, "IRQ request failed\n"); - goto gpio_err; - } - - dev_dbg(&spi->dev, "GPIO %d IRQ %d\n", init_data->irq, spiadis->irq); - - dev_set_drvdata(&spi->dev, spiadis); - status = sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group); - if (status != 0) - goto irq_err; - - status = spi_adis16255_bringup(spiadis); - if (status != 0) - goto sysfs_err; - - dev_info(&spi->dev, "spi_adis16255 driver added!\n"); - - return status; - -sysfs_err: - sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group); -irq_err: - free_irq(spiadis->irq, spiadis); -gpio_err: - gpio_free(init_data->irq); -err: - kfree(spiadis); - return status; -} - -static int __devexit spi_adis16255_remove(struct spi_device *spi) -{ - struct spi_adis16255_data *spiadis = dev_get_drvdata(&spi->dev); - - spi_adis16255_shutdown(spiadis); - - free_irq(spiadis->irq, spiadis); - gpio_free(irq_to_gpio(spiadis->irq)); - - sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group); - - kfree(spiadis); - - dev_info(&spi->dev, "spi_adis16255 driver removed!\n"); - return 0; -} - -static struct spi_driver spi_adis16255_drv = { - .driver = { - .name = "spi_adis16255", - .owner = THIS_MODULE, - }, - .probe = spi_adis16255_probe, - .remove = __devexit_p(spi_adis16255_remove), -}; - -/*-------------------------------------------------------------------------*/ - -static int __init spi_adis16255_init(void) -{ - return spi_register_driver(&spi_adis16255_drv); -} -module_init(spi_adis16255_init); - -static void __exit spi_adis16255_exit(void) -{ - spi_unregister_driver(&spi_adis16255_drv); -} -module_exit(spi_adis16255_exit); - -MODULE_AUTHOR("Matthias Brugger"); -MODULE_DESCRIPTION("SPI device driver for ADIS16255 sensor"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/adis16255/adis16255.h b/drivers/staging/adis16255/adis16255.h deleted file mode 100644 index 03e07001bab2..000000000000 --- a/drivers/staging/adis16255/adis16255.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ADIS16255_H -#define ADIS16255_H - -#include - -struct adis16255_init_data { - char direction; - u8 negative; - int irq; -}; - -#endif -- cgit v1.2.3 From 7c74cbd01b2698583fb74ebdfcd7ef4c768e6346 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 23 Sep 2010 11:03:01 +1000 Subject: drm/nouveau: tidy fifo swmthd handler a little Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 56 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 7bfd9e6c9d67..a4fa9e14d66d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -108,36 +108,45 @@ nouveau_call_method(struct nouveau_channel *chan, int class, int mthd, int data) } static bool -nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data) +nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) { - struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = NULL; + struct nouveau_gpuobj *obj; const int subc = (addr >> 13) & 0x7; const int mthd = addr & 0x1ffc; + bool handled = false; + u32 engine; - if (mthd == 0x0000) { - struct nouveau_gpuobj *gpuobj; - - gpuobj = nouveau_ramht_find(chan, data); - if (!gpuobj) - return false; + if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) + chan = dev_priv->fifos[chid]; + if (unlikely(!chan)) + return false; - if (gpuobj->engine != NVOBJ_ENGINE_SW) - return false; + switch (mthd) { + case 0x0000: /* bind object to subchannel */ + obj = nouveau_ramht_find(chan, data); + if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) + break; - chan->sw_subchannel[subc] = gpuobj->class; - nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev, - NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4)); - return true; - } + chan->sw_subchannel[subc] = obj->class; + engine = 0x0000000f << (subc * 4); - /* hw object */ - if (nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE) & (1 << (subc*4))) - return false; + nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); + handled = true; + break; + default: + engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); + if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) + break; - if (nouveau_call_method(chan, chan->sw_subchannel[subc], mthd, data)) - return false; + if (!nouveau_call_method(chan, chan->sw_subchannel[subc], + mthd, data)) + handled = true; + break; + } - return true; + return handled; } static void @@ -150,14 +159,11 @@ nouveau_fifo_irq_handler(struct drm_device *dev) reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { - struct nouveau_channel *chan = NULL; uint32_t chid, get; nv_wr32(dev, NV03_PFIFO_CACHES, 0); chid = engine->fifo.channel_id(dev); - if (chid >= 0 && chid < engine->fifo.channels) - chan = dev_priv->fifos[chid]; get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); if (status & NV_PFIFO_INTR_CACHE_ERROR) { @@ -184,7 +190,7 @@ nouveau_fifo_irq_handler(struct drm_device *dev) NV40_PFIFO_CACHE1_DATA(ptr)); } - if (!chan || !nouveau_fifo_swmthd(chan, mthd, data)) { + if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " "Mthd 0x%04x Data 0x%08x\n", chid, (mthd >> 13) & 7, mthd & 0x1ffc, -- cgit v1.2.3 From ceed5f30bf0f515b52246230e5faacf89983fd8f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 5 Oct 2010 16:41:29 +1000 Subject: drm/nouveau: disallow fbcon accel if running in interrupt context A future commit will add locking to the DRM's channel, and there's numerous problems that come up if we allow printk from an interrupt context to be accelerated. It seems saner to just disallow it completely. As a nice side-effect, all the "to accel or not to accel" logic gets moved out of the chipset-specific code. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 137 +++++++++++++++++++++++--------- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 12 +-- drivers/gpu/drm/nouveau/nv04_fbcon.c | 68 ++++++---------- drivers/gpu/drm/nouveau/nv50_fbcon.c | 69 ++++++---------- 4 files changed, 153 insertions(+), 133 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 02a4d1fd4845..22e83adcc930 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -49,6 +49,90 @@ #include "nouveau_fbcon.h" #include "nouveau_dma.h" +static void +nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + ret = -ENODEV; + if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { + if (dev_priv->card_type < NV_50) + ret = nv04_fbcon_fillrect(info, rect); + else + if (dev_priv->card_type < NV_C0) + ret = nv50_fbcon_fillrect(info, rect); + } + + if (ret == 0) + return; + + if (ret != -ENODEV) + nouveau_fbcon_gpu_lockup(info); + cfb_fillrect(info, rect); +} + +static void +nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + ret = -ENODEV; + if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { + if (dev_priv->card_type < NV_50) + ret = nv04_fbcon_copyarea(info, image); + else + if (dev_priv->card_type < NV_C0) + ret = nv50_fbcon_copyarea(info, image); + } + + if (ret == 0) + return; + + if (ret != -ENODEV) + nouveau_fbcon_gpu_lockup(info); + cfb_copyarea(info, image); +} + +static void +nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + ret = -ENODEV; + if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { + if (dev_priv->card_type < NV_50) + ret = nv04_fbcon_imageblit(info, image); + else + if (dev_priv->card_type < NV_C0) + ret = nv50_fbcon_imageblit(info, image); + } + + if (ret == 0) + return; + + if (ret != -ENODEV) + nouveau_fbcon_gpu_lockup(info); + cfb_imageblit(info, image); +} + static int nouveau_fbcon_sync(struct fb_info *info) { @@ -97,24 +181,9 @@ static struct fb_ops nouveau_fbcon_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_sync = nouveau_fbcon_sync, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, -}; - -static struct fb_ops nv04_fbcon_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = nv04_fbcon_fillrect, - .fb_copyarea = nv04_fbcon_copyarea, - .fb_imageblit = nv04_fbcon_imageblit, + .fb_fillrect = nouveau_fbcon_fillrect, + .fb_copyarea = nouveau_fbcon_copyarea, + .fb_imageblit = nouveau_fbcon_imageblit, .fb_sync = nouveau_fbcon_sync, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, @@ -123,14 +192,13 @@ static struct fb_ops nv04_fbcon_ops = { .fb_debug_leave = drm_fb_helper_debug_leave, }; -static struct fb_ops nv50_fbcon_ops = { +static struct fb_ops nouveau_fbcon_sw_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = nv50_fbcon_fillrect, - .fb_copyarea = nv50_fbcon_copyarea, - .fb_imageblit = nv50_fbcon_imageblit, - .fb_sync = nouveau_fbcon_sync, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -257,7 +325,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; info->flags |= FBINFO_CAN_FORCE_OUTPUT; - info->fbops = &nouveau_fbcon_ops; + info->fbops = &nouveau_fbcon_sw_ops; info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - dev_priv->vm_vram_base; info->fix.smem_len = size; @@ -286,18 +354,15 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, info->pixmap.scan_align = 1; if (dev_priv->channel && !nouveau_nofbaccel) { - switch (dev_priv->card_type) { - case NV_C0: - break; - case NV_50: - nv50_fbcon_accel_init(info); - info->fbops = &nv50_fbcon_ops; - break; - default: - nv04_fbcon_accel_init(info); - info->fbops = &nv04_fbcon_ops; - break; - }; + ret = -ENODEV; + if (dev_priv->card_type < NV_50) + ret = nv04_fbcon_accel_init(info); + else + if (dev_priv->card_type < NV_C0) + ret = nv50_fbcon_accel_init(info); + + if (ret == 0) + info->fbops = &nouveau_fbcon_ops; } nouveau_fbcon_zfill(dev, nfbdev); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index e7e12684c37e..6b933f2c3a5b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -40,13 +40,13 @@ struct nouveau_fbdev { void nouveau_fbcon_restore(void); -void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); +int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv04_fbcon_accel_init(struct fb_info *info); -void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); +int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv50_fbcon_accel_init(struct fb_info *info); void nouveau_fbcon_gpu_lockup(struct fb_info *info); diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 33e4c9388bc1..a32804e7d202 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -28,52 +28,39 @@ #include "nouveau_ramht.h" #include "nouveau_fbcon.h" -void +int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbdev *nfbdev = info->par; struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + int ret; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 4)) { - nouveau_fbcon_gpu_lockup(info); - } - - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_copyarea(info, region); - return; - } + ret = RING_SPACE(chan, 4); + if (ret) + return ret; BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3); OUT_RING(chan, (region->sy << 16) | region->sx); OUT_RING(chan, (region->dy << 16) | region->dx); OUT_RING(chan, (region->height << 16) | region->width); FIRE_RING(chan); + return 0; } -void +int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbdev *nfbdev = info->par; struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + int ret; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) { - nouveau_fbcon_gpu_lockup(info); - } - - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_fillrect(info, rect); - return; - } + ret = RING_SPACE(chan, 7); + if (ret) + return ret; BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1); OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3); @@ -87,9 +74,10 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) OUT_RING(chan, (rect->dx << 16) | rect->dy); OUT_RING(chan, (rect->width << 16) | rect->height); FIRE_RING(chan); + return 0; } -void +int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbdev *nfbdev = info->par; @@ -101,23 +89,14 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) uint32_t dsize; uint32_t width; uint32_t *data = (uint32_t *)image->data; + int ret; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (image->depth != 1) { - cfb_imageblit(info, image); - return; - } - - if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) { - nouveau_fbcon_gpu_lockup(info); - } + if (image->depth != 1) + return -ENODEV; - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_imageblit(info, image); - return; - } + ret = RING_SPACE(chan, 8); + if (ret) + return ret; width = ALIGN(image->width, 8); dsize = ALIGN(width * image->height, 32) >> 5; @@ -144,11 +123,9 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) while (dsize) { int iter_len = dsize > 128 ? 128 : dsize; - if (RING_SPACE(chan, iter_len + 1)) { - nouveau_fbcon_gpu_lockup(info); - cfb_imageblit(info, image); - return; - } + ret = RING_SPACE(chan, iter_len + 1); + if (ret) + return ret; BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len); OUT_RINGp(chan, data, iter_len); @@ -157,6 +134,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) } FIRE_RING(chan); + return 0; } static int diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 6dcf048eddbc..6edf9dca35ca 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -4,26 +4,18 @@ #include "nouveau_ramht.h" #include "nouveau_fbcon.h" -void +int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbdev *nfbdev = info->par; struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + int ret; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (!(info->flags & FBINFO_HWACCEL_DISABLED) && - RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) { - nouveau_fbcon_gpu_lockup(info); - } - - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_fillrect(info, rect); - return; - } + ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11); + if (ret) + return ret; if (rect->rop != ROP_COPY) { BEGIN_RING(chan, NvSub2D, 0x02ac, 1); @@ -45,27 +37,21 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) OUT_RING(chan, 3); } FIRE_RING(chan); + return 0; } -void +int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbdev *nfbdev = info->par; struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + int ret; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) { - nouveau_fbcon_gpu_lockup(info); - } - - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_copyarea(info, region); - return; - } + ret = RING_SPACE(chan, 12); + if (ret) + return ret; BEGIN_RING(chan, NvSub2D, 0x0110, 1); OUT_RING(chan, 0); @@ -80,9 +66,10 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) OUT_RING(chan, 0); OUT_RING(chan, region->sy); FIRE_RING(chan); + return 0; } -void +int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbdev *nfbdev = info->par; @@ -92,23 +79,14 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) uint32_t width, dwords, *data = (uint32_t *)image->data; uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); uint32_t *palette = info->pseudo_palette; + int ret; - if (info->state != FBINFO_STATE_RUNNING) - return; - - if (image->depth != 1) { - cfb_imageblit(info, image); - return; - } - - if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) { - nouveau_fbcon_gpu_lockup(info); - } + if (image->depth != 1) + return -ENODEV; - if (info->flags & FBINFO_HWACCEL_DISABLED) { - cfb_imageblit(info, image); - return; - } + ret = RING_SPACE(chan, 11); + if (ret) + return ret; width = ALIGN(image->width, 32); dwords = (width * image->height) >> 5; @@ -134,11 +112,9 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) while (dwords) { int push = dwords > 2047 ? 2047 : dwords; - if (RING_SPACE(chan, push + 1)) { - nouveau_fbcon_gpu_lockup(info); - cfb_imageblit(info, image); - return; - } + ret = RING_SPACE(chan, push + 1); + if (ret) + return ret; dwords -= push; @@ -148,6 +124,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) } FIRE_RING(chan); + return 0; } int -- cgit v1.2.3 From 6a6b73f254123851f7f73ab5e57344a569d6a0ab Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 5 Oct 2010 16:53:48 +1000 Subject: drm/nouveau: add per-channel mutex, use to lock access to drm's channel This fixes a race condition between fbcon acceleration and TTM buffer moves. To reproduce: - start X - switch to vt and "while (true); do dmesg; done" - switch to another vt and "sleep 2 && cat /path/to/debugfs/dri/0/evict_vram" - switch back to vt running dmesg We don't make use of this on any other channel yet, they're currently protected by drm_global_mutex. This will change in the near future. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +++++++++++---- drivers/gpu/drm/nouveau/nouveau_channel.c | 1 + drivers/gpu/drm/nouveau/nouveau_drv.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_fbcon.c | 17 ++++++++++++++--- 4 files changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index c41e1c200ef5..d8817b4bb189 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -683,17 +683,24 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, int ret; chan = nvbo->channel; - if (!chan || nvbo->no_vm) + if (!chan || nvbo->no_vm) { chan = dev_priv->channel; + mutex_lock(&chan->mutex); + } if (dev_priv->card_type < NV_50) ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem); else ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem); - if (ret) - return ret; + if (ret == 0) { + ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict, + no_wait_reserve, + no_wait_gpu, new_mem); + } - return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); + if (chan == dev_priv->channel) + mutex_unlock(&chan->mutex); + return ret; } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 373950e34814..8636478c477a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -145,6 +145,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, chan->file_priv = file_priv; chan->vram_handle = vram_handle; chan->gart_handle = tt_handle; + mutex_init(&chan->mutex); NV_INFO(dev, "Allocating FIFO number %d\n", channel); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1c7db64c03bf..04bc56cf4f1a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -166,6 +166,8 @@ struct nouveau_channel { struct drm_device *dev; int id; + struct mutex mutex; + /* owner of this fifo */ struct drm_file *file_priv; /* mapping of the fifo itself */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 22e83adcc930..bc30dbe11d00 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -62,11 +62,13 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { + mutex_lock(&dev_priv->channel->mutex); if (dev_priv->card_type < NV_50) ret = nv04_fbcon_fillrect(info, rect); else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_fillrect(info, rect); + mutex_unlock(&dev_priv->channel->mutex); } if (ret == 0) @@ -90,11 +92,13 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { + mutex_lock(&dev_priv->channel->mutex); if (dev_priv->card_type < NV_50) ret = nv04_fbcon_copyarea(info, image); else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_copyarea(info, image); + mutex_unlock(&dev_priv->channel->mutex); } if (ret == 0) @@ -118,11 +122,13 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) ret = -ENODEV; if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { + mutex_lock(&dev_priv->channel->mutex); if (dev_priv->card_type < NV_50) ret = nv04_fbcon_imageblit(info, image); else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_imageblit(info, image); + mutex_unlock(&dev_priv->channel->mutex); } if (ret == 0) @@ -142,12 +148,15 @@ nouveau_fbcon_sync(struct fb_info *info) struct nouveau_channel *chan = dev_priv->channel; int ret, i; - if (!chan || !chan->accel_done || + if (!chan || !chan->accel_done || in_interrupt() || info->state != FBINFO_STATE_RUNNING || info->flags & FBINFO_HWACCEL_DISABLED) return 0; - if (RING_SPACE(chan, 4)) { + mutex_lock(&chan->mutex); + ret = RING_SPACE(chan, 4); + if (ret) { + mutex_unlock(&chan->mutex); nouveau_fbcon_gpu_lockup(info); return 0; } @@ -158,6 +167,7 @@ nouveau_fbcon_sync(struct fb_info *info) OUT_RING(chan, 0); nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); FIRE_RING(chan); + mutex_unlock(&chan->mutex); ret = -EBUSY; for (i = 0; i < 100000; i++) { @@ -353,6 +363,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; + mutex_unlock(&dev->struct_mutex); + if (dev_priv->channel && !nouveau_nofbaccel) { ret = -ENODEV; if (dev_priv->card_type < NV_50) @@ -373,7 +385,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, nouveau_fb->base.height, nvbo->bo.offset, nvbo); - mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; -- cgit v1.2.3 From cff5c1332486ced8ff4180e957e04983cb72a39e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 6 Oct 2010 16:16:59 +1000 Subject: drm/nouveau: add more fine-grained locking to channel list + structures Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 186 +++++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_drv.c | 7 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 23 ++-- drivers/gpu/drm/nouveau/nouveau_fence.c | 10 ++ drivers/gpu/drm/nouveau/nouveau_gem.c | 28 +++-- drivers/gpu/drm/nouveau/nouveau_irq.c | 42 ++++--- drivers/gpu/drm/nouveau/nouveau_notifier.c | 10 +- drivers/gpu/drm/nouveau/nouveau_object.c | 34 ++++-- drivers/gpu/drm/nouveau/nouveau_state.c | 8 +- drivers/gpu/drm/nouveau/nv04_fifo.c | 4 +- drivers/gpu/drm/nouveau/nv04_graph.c | 4 +- drivers/gpu/drm/nouveau/nv10_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv10_graph.c | 4 +- drivers/gpu/drm/nouveau/nv40_fifo.c | 2 +- drivers/gpu/drm/nouveau/nv40_graph.c | 2 +- drivers/gpu/drm/nouveau/nv50_fb.c | 6 +- drivers/gpu/drm/nouveau/nv50_fifo.c | 9 +- drivers/gpu/drm/nouveau/nv50_graph.c | 2 +- drivers/gpu/drm/nouveau/nv50_instmem.c | 14 +-- 19 files changed, 236 insertions(+), 161 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 8636478c477a..47bf2d3d658c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -107,54 +107,54 @@ nouveau_channel_user_pushbuf_alloc(struct drm_device *dev) int nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct drm_file *file_priv, - uint32_t vram_handle, uint32_t tt_handle) + uint32_t vram_handle, uint32_t gart_handle) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_channel *chan; - int channel, user; - int ret; - - /* - * Alright, here is the full story - * Nvidia cards have multiple hw fifo contexts (praise them for that, - * no complicated crash-prone context switches) - * We allocate a new context for each app and let it write to it - * directly (woo, full userspace command submission !) - * When there are no more contexts, you lost - */ - for (channel = 0; channel < pfifo->channels; channel++) { - if (dev_priv->fifos[channel] == NULL) - break; - } - - /* no more fifos. you lost. */ - if (channel == pfifo->channels) - return -EINVAL; + unsigned long flags; + int user, ret; - dev_priv->fifos[channel] = kzalloc(sizeof(struct nouveau_channel), - GFP_KERNEL); - if (!dev_priv->fifos[channel]) + /* allocate and lock channel structure */ + chan = kzalloc(sizeof(*chan), GFP_KERNEL); + if (!chan) return -ENOMEM; - chan = dev_priv->fifos[channel]; - INIT_LIST_HEAD(&chan->nvsw.vbl_wait); - INIT_LIST_HEAD(&chan->fence.pending); chan->dev = dev; - chan->id = channel; chan->file_priv = file_priv; chan->vram_handle = vram_handle; - chan->gart_handle = tt_handle; + chan->gart_handle = gart_handle; + + atomic_set(&chan->refcount, 1); mutex_init(&chan->mutex); + mutex_lock(&chan->mutex); - NV_INFO(dev, "Allocating FIFO number %d\n", channel); + /* allocate hw channel id */ + spin_lock_irqsave(&dev_priv->channels.lock, flags); + for (chan->id = 0; chan->id < pfifo->channels; chan->id++) { + if (!dev_priv->channels.ptr[chan->id]) { + dev_priv->channels.ptr[chan->id] = chan; + break; + } + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + + if (chan->id == pfifo->channels) { + mutex_unlock(&chan->mutex); + kfree(chan); + return -ENODEV; + } + + NV_DEBUG(dev, "initialising channel %d\n", chan->id); + INIT_LIST_HEAD(&chan->nvsw.vbl_wait); + INIT_LIST_HEAD(&chan->fence.pending); /* Allocate DMA push buffer */ chan->pushbuf_bo = nouveau_channel_user_pushbuf_alloc(dev); if (!chan->pushbuf_bo) { ret = -ENOMEM; NV_ERROR(dev, "pushbuf %d\n", ret); - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } @@ -162,18 +162,18 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, /* Locate channel's user control regs */ if (dev_priv->card_type < NV_40) - user = NV03_USER(channel); + user = NV03_USER(chan->id); else if (dev_priv->card_type < NV_50) - user = NV40_USER(channel); + user = NV40_USER(chan->id); else - user = NV50_USER(channel); + user = NV50_USER(chan->id); chan->user = ioremap(pci_resource_start(dev->pdev, 0) + user, PAGE_SIZE); if (!chan->user) { NV_ERROR(dev, "ioremap of regs failed.\n"); - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return -ENOMEM; } chan->user_put = 0x40; @@ -183,15 +183,15 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, ret = nouveau_notifier_init_channel(chan); if (ret) { NV_ERROR(dev, "ntfy %d\n", ret); - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } /* Setup channel's default objects */ - ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle); + ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); if (ret) { NV_ERROR(dev, "gpuobj %d\n", ret); - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } @@ -199,7 +199,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, ret = nouveau_channel_pushbuf_ctxdma_init(chan); if (ret) { NV_ERROR(dev, "pbctxdma %d\n", ret); - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } @@ -209,14 +209,14 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, /* Create a graphics context for new channel */ ret = pgraph->create_context(chan); if (ret) { - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } /* Construct inital RAMFC for new channel */ ret = pfifo->create_context(chan); if (ret) { - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } @@ -226,33 +226,70 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, if (!ret) ret = nouveau_fence_channel_init(chan); if (ret) { - nouveau_channel_free(chan); + nouveau_channel_put(&chan); return ret; } nouveau_debugfs_channel_init(chan); - NV_INFO(dev, "%s: initialised FIFO %d\n", __func__, channel); + NV_DEBUG(dev, "channel %d initialised\n", chan->id); *chan_ret = chan; return 0; } -/* stops a fifo */ +struct nouveau_channel * +nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = ERR_PTR(-ENODEV); + unsigned long flags; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + chan = dev_priv->channels.ptr[id]; + + if (unlikely(!chan || atomic_read(&chan->refcount) == 0)) { + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return ERR_PTR(-EINVAL); + } + + if (unlikely(file_priv && chan->file_priv != file_priv)) { + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return ERR_PTR(-EINVAL); + } + + atomic_inc(&chan->refcount); + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + + mutex_lock(&chan->mutex); + return chan; +} + void -nouveau_channel_free(struct nouveau_channel *chan) +nouveau_channel_put(struct nouveau_channel **pchan) { + struct nouveau_channel *chan = *pchan; struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; unsigned long flags; int ret; - NV_INFO(dev, "%s: freeing fifo %d\n", __func__, chan->id); + /* unlock the channel */ + mutex_unlock(&chan->mutex); + + /* decrement the refcount, and we're done if there's still refs */ + if (likely(!atomic_dec_and_test(&chan->refcount))) { + *pchan = NULL; + return; + } + /* noone wants the channel anymore */ + NV_DEBUG(dev, "freeing channel %d\n", chan->id); nouveau_debugfs_channel_fini(chan); + *pchan = NULL; - /* Give outstanding push buffers a chance to complete */ + /* give it chance to idle */ nouveau_fence_update(chan); if (chan->fence.sequence != chan->fence.sequence_ack) { struct nouveau_fence *fence = NULL; @@ -267,13 +304,13 @@ nouveau_channel_free(struct nouveau_channel *chan) NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); } - /* Ensure all outstanding fences are signaled. They should be if the + /* ensure all outstanding fences are signaled. they should be if the * above attempts at idling were OK, but if we failed this'll tell TTM * we're done with the buffers. */ nouveau_fence_channel_fini(chan); - /* This will prevent pfifo from switching channels. */ + /* boot it off the hardware */ pfifo->reassign(dev, false); /* We want to give pgraph a chance to idle and get rid of all potential @@ -302,7 +339,14 @@ nouveau_channel_free(struct nouveau_channel *chan) spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - /* Release the channel's resources */ + /* aside from its resources, the channel should now be dead, + * remove it from the channel list + */ + spin_lock_irqsave(&dev_priv->channels.lock, flags); + dev_priv->channels.ptr[chan->id] = NULL; + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + + /* destroy any resources the channel owned */ nouveau_gpuobj_ref(NULL, &chan->pushbuf); if (chan->pushbuf_bo) { nouveau_bo_unmap(chan->pushbuf_bo); @@ -314,7 +358,6 @@ nouveau_channel_free(struct nouveau_channel *chan) if (chan->user) iounmap(chan->user); - dev_priv->fifos[chan->id] = NULL; kfree(chan); } @@ -324,31 +367,20 @@ nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; + struct nouveau_channel *chan; int i; NV_DEBUG(dev, "clearing FIFO enables from file_priv\n"); for (i = 0; i < engine->fifo.channels; i++) { - struct nouveau_channel *chan = dev_priv->fifos[i]; + chan = nouveau_channel_get(dev, file_priv, i); + if (IS_ERR(chan)) + continue; - if (chan && chan->file_priv == file_priv) - nouveau_channel_free(chan); + atomic_dec(&chan->refcount); + nouveau_channel_put(&chan); } } -int -nouveau_channel_owner(struct drm_device *dev, struct drm_file *file_priv, - int channel) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; - - if (channel >= engine->fifo.channels) - return 0; - if (dev_priv->fifos[channel] == NULL) - return 0; - - return (dev_priv->fifos[channel]->file_priv == file_priv); -} /*********************************** * ioctls wrapping the functions @@ -396,24 +428,26 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, /* Named memory object area */ ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, &init->notifier_handle); - if (ret) { - nouveau_channel_free(chan); - return ret; - } - return 0; + if (ret == 0) + atomic_inc(&chan->refcount); /* userspace reference */ + nouveau_channel_put(&chan); + return ret; } static int nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_nouveau_channel_free *cfree = data; + struct drm_nouveau_channel_free *req = data; struct nouveau_channel *chan; - NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan); + chan = nouveau_channel_get(dev, file_priv, req->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); - nouveau_channel_free(chan); + atomic_dec(&chan->refcount); + nouveau_channel_put(&chan); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 90875494a65a..f139aa2cbe5c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -195,9 +195,8 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) for (i = 0; i < pfifo->channels; i++) { struct nouveau_fence *fence = NULL; - chan = dev_priv->fifos[i]; - if (!chan || (dev_priv->card_type >= NV_50 && - chan == dev_priv->fifos[0])) + chan = dev_priv->channels.ptr[i]; + if (!chan || !chan->pushbuf_bo) continue; ret = nouveau_fence_new(chan, &fence, true); @@ -313,7 +312,7 @@ nouveau_pci_resume(struct pci_dev *pdev) int j; for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - chan = dev_priv->fifos[i]; + chan = dev_priv->channels.ptr[i]; if (!chan || !chan->pushbuf_bo) continue; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 04bc56cf4f1a..c3f102125083 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -166,6 +166,7 @@ struct nouveau_channel { struct drm_device *dev; int id; + atomic_t refcount; struct mutex mutex; /* owner of this fifo */ @@ -607,8 +608,10 @@ struct drm_nouveau_private { struct nouveau_bo *bo; } fence; - int fifo_alloc_count; - struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; + struct { + spinlock_t lock; + struct nouveau_channel *ptr[NOUVEAU_MAX_CHANNEL_NR]; + } channels; struct nouveau_engine engine; struct nouveau_channel *channel; @@ -721,16 +724,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) return 0; } -#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ - struct drm_nouveau_private *nv = dev->dev_private; \ - if (!nouveau_channel_owner(dev, (cl), (id))) { \ - NV_ERROR(dev, "pid %d doesn't own channel %d\n", \ - DRM_CURRENTPID, (id)); \ - return -EPERM; \ - } \ - (ch) = nv->fifos[(id)]; \ -} while (0) - /* nouveau_drv.c */ extern int nouveau_agpmode; extern int nouveau_duallink; @@ -805,13 +798,13 @@ extern int nouveau_ioctl_notifier_free(struct drm_device *, void *data, extern struct drm_ioctl_desc nouveau_ioctls[]; extern int nouveau_max_ioctl; extern void nouveau_channel_cleanup(struct drm_device *, struct drm_file *); -extern int nouveau_channel_owner(struct drm_device *, struct drm_file *, - int channel); extern int nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan, struct drm_file *file_priv, uint32_t fb_ctxdma, uint32_t tt_ctxdma); -extern void nouveau_channel_free(struct nouveau_channel *); +extern struct nouveau_channel * +nouveau_channel_get(struct drm_device *, struct drm_file *, int id); +extern void nouveau_channel_put(struct nouveau_channel **); /* nouveau_object.c */ extern int nouveau_gpuobj_early_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index ab1bbfbf266e..42694b122eef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -393,8 +393,18 @@ nouveau_fence_sync(struct nouveau_fence *fence, return nouveau_fence_wait(fence, NULL, false, false); } + /* try to take wchan's mutex, if we can't take it right away + * we have to fallback to software sync to prevent locking + * order issues + */ + if (!mutex_trylock(&wchan->mutex)) { + free_semaphore(&sema->ref); + return nouveau_fence_wait(fence, NULL, false, false); + } + /* Make wchan wait until it gets signalled */ ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); + mutex_unlock(&wchan->mutex); if (ret) goto out; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 1f2301d26c0a..454d5ceb28f1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -146,11 +146,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; - if (req->channel_hint) { - NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel_hint, - file_priv, chan); - } - if (req->info.domain & NOUVEAU_GEM_DOMAIN_VRAM) flags |= TTM_PL_FLAG_VRAM; if (req->info.domain & NOUVEAU_GEM_DOMAIN_GART) @@ -161,10 +156,18 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, if (!nouveau_gem_tile_flags_valid(dev, req->info.tile_flags)) return -EINVAL; + if (req->channel_hint) { + chan = nouveau_channel_get(dev, file_priv, req->channel_hint); + if (IS_ERR(chan)) + return PTR_ERR(chan); + } + ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags, req->info.tile_mode, req->info.tile_flags, false, (req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE), &nvbo); + if (chan) + nouveau_channel_put(&chan); if (ret) return ret; @@ -341,9 +344,7 @@ retry: return -EINVAL; } - mutex_unlock(&drm_global_mutex); ret = ttm_bo_wait_cpu(&nvbo->bo, false); - mutex_lock(&drm_global_mutex); if (ret) { NV_ERROR(dev, "fail wait_cpu\n"); return ret; @@ -585,7 +586,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, struct nouveau_fence *fence = NULL; int i, j, ret = 0, do_reloc = 0; - NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); + chan = nouveau_channel_get(dev, file_priv, req->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); req->vram_available = dev_priv->fb_aper_free; req->gart_available = dev_priv->gart_info.aper_free; @@ -595,28 +598,34 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n", req->nr_push, NOUVEAU_GEM_MAX_PUSH); + nouveau_channel_put(&chan); return -EINVAL; } if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n", req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); + nouveau_channel_put(&chan); return -EINVAL; } if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n", req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); + nouveau_channel_put(&chan); return -EINVAL; } push = u_memcpya(req->push, req->nr_push, sizeof(*push)); - if (IS_ERR(push)) + if (IS_ERR(push)) { + nouveau_channel_put(&chan); return PTR_ERR(push); + } bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); if (IS_ERR(bo)) { kfree(push); + nouveau_channel_put(&chan); return PTR_ERR(bo); } @@ -750,6 +759,7 @@ out_next: req->suffix1 = 0x00000000; } + nouveau_channel_put(&chan); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index a4fa9e14d66d..c5e37bc17192 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -113,15 +113,17 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = NULL; struct nouveau_gpuobj *obj; + unsigned long flags; const int subc = (addr >> 13) & 0x7; const int mthd = addr & 0x1ffc; bool handled = false; u32 engine; + spin_lock_irqsave(&dev_priv->channels.lock, flags); if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) - chan = dev_priv->fifos[chid]; + chan = dev_priv->channels.ptr[chid]; if (unlikely(!chan)) - return false; + goto out; switch (mthd) { case 0x0000: /* bind object to subchannel */ @@ -146,6 +148,8 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) break; } +out: + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); return handled; } @@ -398,6 +402,8 @@ static int nouveau_graph_chid_from_grctx(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; + unsigned long flags; uint32_t inst; int i; @@ -407,27 +413,29 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev) if (dev_priv->card_type < NV_50) { inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4; + spin_lock_irqsave(&dev_priv->channels.lock, flags); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - struct nouveau_channel *chan = dev_priv->fifos[i]; - + chan = dev_priv->channels.ptr[i]; if (!chan || !chan->ramin_grctx) continue; if (inst == chan->ramin_grctx->pinst) break; } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); } else { inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12; + spin_lock_irqsave(&dev_priv->channels.lock, flags); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - struct nouveau_channel *chan = dev_priv->fifos[i]; - + chan = dev_priv->channels.ptr[i]; if (!chan || !chan->ramin) continue; if (inst == chan->ramin->vinst) break; } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); } @@ -449,7 +457,8 @@ nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) else channel = nouveau_graph_chid_from_grctx(dev); - if (channel >= engine->fifo.channels || !dev_priv->fifos[channel]) { + if (channel >= engine->fifo.channels || + !dev_priv->channels.ptr[channel]) { NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel); return -EINVAL; } @@ -532,14 +541,19 @@ nouveau_pgraph_intr_swmthd(struct drm_device *dev, struct nouveau_pgraph_trap *trap) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + if (trap->channel > 0 && + trap->channel < dev_priv->engine.fifo.channels && + dev_priv->channels.ptr[trap->channel]) { + ret = nouveau_call_method(dev_priv->channels.ptr[trap->channel], + trap->class, trap->mthd, trap->data); + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - if (trap->channel < 0 || - trap->channel >= dev_priv->engine.fifo.channels || - !dev_priv->fifos[trap->channel]) - return -ENODEV; - - return nouveau_call_method(dev_priv->fifos[trap->channel], - trap->class, trap->mthd, trap->data); + return ret; } static inline void diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 2cc59f8c658b..2c5a1f66f7f0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -185,11 +185,11 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; - NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan); + chan = nouveau_channel_get(dev, file_priv, na->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); - if (ret) - return ret; - - return 0; + nouveau_channel_put(&chan); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index dd572adca02a..068441c4b563 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -876,8 +876,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; - NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); - if (init->handle == ~0) return -EINVAL; @@ -893,8 +891,14 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, return -EPERM; } - if (nouveau_ramht_find(chan, init->handle)) - return -EEXIST; + chan = nouveau_channel_get(dev, file_priv, init->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); + + if (nouveau_ramht_find(chan, init->handle)) { + ret = -EEXIST; + goto out; + } if (!grc->software) ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr); @@ -903,7 +907,7 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, if (ret) { NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", ret, init->channel, init->handle); - return ret; + goto out; } ret = nouveau_ramht_insert(chan, init->handle, gr); @@ -911,10 +915,11 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, if (ret) { NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n", ret, init->channel, init->handle); - return ret; } - return 0; +out: + nouveau_channel_put(&chan); + return ret; } int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, @@ -923,15 +928,20 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, struct drm_nouveau_gpuobj_free *objfree = data; struct nouveau_gpuobj *gpuobj; struct nouveau_channel *chan; + int ret = -ENOENT; - NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); + chan = nouveau_channel_get(dev, file_priv, objfree->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); gpuobj = nouveau_ramht_find(chan, objfree->handle); - if (!gpuobj) - return -ENOENT; + if (gpuobj) { + nouveau_ramht_remove(chan, objfree->handle); + ret = 0; + } - nouveau_ramht_remove(chan, objfree->handle); - return 0; + nouveau_channel_put(&chan); + return ret; } u32 diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 049f755567e5..513c1063fb5e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -516,11 +516,11 @@ nouveau_card_init_channel(struct drm_device *dev) if (ret) goto out_err; + mutex_unlock(&dev_priv->channel->mutex); return 0; out_err: - nouveau_channel_free(dev_priv->channel); - dev_priv->channel = NULL; + nouveau_channel_put(&dev_priv->channel); return ret; } @@ -567,6 +567,7 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out; engine = &dev_priv->engine; + spin_lock_init(&dev_priv->channels.lock); spin_lock_init(&dev_priv->context_switch_lock); /* Make the CRTCs and I2C buses accessible */ @@ -713,8 +714,7 @@ static void nouveau_card_takedown(struct drm_device *dev) if (!engine->graph.accel_blocked) { nouveau_fence_fini(dev); - nouveau_channel_free(dev_priv->channel); - dev_priv->channel = NULL; + nouveau_channel_put(&dev_priv->channel); } if (!nouveau_noaccel) { diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 708293b7ddcd..25c439dcdfd9 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -208,7 +208,7 @@ nv04_fifo_unload_context(struct drm_device *dev) if (chid < 0 || chid >= dev_priv->engine.fifo.channels) return 0; - chan = dev_priv->fifos[chid]; + chan = dev_priv->channels.ptr[chid]; if (!chan) { NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid); return -EINVAL; @@ -289,7 +289,7 @@ nv04_fifo_init(struct drm_device *dev) pfifo->reassign(dev, true); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - if (dev_priv->fifos[i]) { + if (dev_priv->channels.ptr[i]) { uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE); nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i)); } diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index c8973421b635..98b9525c1ebd 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -357,7 +357,7 @@ nv04_graph_channel(struct drm_device *dev) if (chid >= dev_priv->engine.fifo.channels) return NULL; - return dev_priv->fifos[chid]; + return dev_priv->channels.ptr[chid]; } void @@ -376,7 +376,7 @@ nv04_graph_context_switch(struct drm_device *dev) /* Load context for next channel */ chid = dev_priv->engine.fifo.channel_id(dev); - chan = dev_priv->fifos[chid]; + chan = dev_priv->channels.ptr[chid]; if (chan) nv04_graph_load_context(chan); diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c index f1b03ad58fd5..39328fcce709 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c @@ -241,7 +241,7 @@ nv10_fifo_init(struct drm_device *dev) pfifo->reassign(dev, true); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - if (dev_priv->fifos[i]) { + if (dev_priv->channels.ptr[i]) { uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE); nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i)); } diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 8e68c9731159..cd931b57cf05 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -802,7 +802,7 @@ nv10_graph_context_switch(struct drm_device *dev) /* Load context for next channel */ chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; - chan = dev_priv->fifos[chid]; + chan = dev_priv->channels.ptr[chid]; if (chan && chan->pgraph_ctx) nv10_graph_load_context(chan); @@ -833,7 +833,7 @@ nv10_graph_channel(struct drm_device *dev) if (chid >= dev_priv->engine.fifo.channels) return NULL; - return dev_priv->fifos[chid]; + return dev_priv->channels.ptr[chid]; } int nv10_graph_create_context(struct nouveau_channel *chan) diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index d337b8b28cdd..3c7be3dc8b88 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -301,7 +301,7 @@ nv40_fifo_init(struct drm_device *dev) pfifo->reassign(dev, true); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - if (dev_priv->fifos[i]) { + if (dev_priv->channels.ptr[i]) { uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE); nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i)); } diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 7ee1b91569b8..e0b41a26447f 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -42,7 +42,7 @@ nv40_graph_channel(struct drm_device *dev) inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4; for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - struct nouveau_channel *chan = dev_priv->fifos[i]; + struct nouveau_channel *chan = dev_priv->channels.ptr[i]; if (chan && chan->ramin_grctx && chan->ramin_grctx->pinst == inst) diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index cd1988b15d2c..d745c952986a 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -42,6 +42,7 @@ void nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; u32 trap[6], idx, chinst; int i, ch; @@ -60,8 +61,10 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) return; chinst = (trap[2] << 16) | trap[1]; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { - struct nouveau_channel *chan = dev_priv->fifos[ch]; + struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; if (!chan || !chan->ramin) continue; @@ -69,6 +72,7 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) if (chinst == chan->ramin->vinst >> 12) break; } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " "channel %d (0x%08x)\n", diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index 1da65bd60c10..815960fe4f43 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -44,7 +44,8 @@ nv50_fifo_playlist_update(struct drm_device *dev) /* We never schedule channel 0 or 127 */ for (i = 1, nr = 0; i < 127; i++) { - if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) { + if (dev_priv->channels.ptr[i] && + dev_priv->channels.ptr[i]->ramfc) { nv_wo32(cur, (nr * 4), i); nr++; } @@ -60,7 +61,7 @@ static void nv50_fifo_channel_enable(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->fifos[channel]; + struct nouveau_channel *chan = dev_priv->channels.ptr[channel]; uint32_t inst; NV_DEBUG(dev, "ch%d\n", channel); @@ -118,7 +119,7 @@ nv50_fifo_init_context_table(struct drm_device *dev) NV_DEBUG(dev, "\n"); for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { - if (dev_priv->fifos[i]) + if (dev_priv->channels.ptr[i]) nv50_fifo_channel_enable(dev, i); else nv50_fifo_channel_disable(dev, i); @@ -392,7 +393,7 @@ nv50_fifo_unload_context(struct drm_device *dev) if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1) return 0; - chan = dev_priv->fifos[chid]; + chan = dev_priv->channels.ptr[chid]; if (!chan) { NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid); return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 8b669d0af610..24a3f8487579 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -190,7 +190,7 @@ nv50_graph_channel(struct drm_device *dev) inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12; for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - struct nouveau_channel *chan = dev_priv->fifos[i]; + struct nouveau_channel *chan = dev_priv->channels.ptr[i]; if (chan && chan->ramin && chan->ramin->vinst == inst) return chan; diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index b773229b7647..0651e7629235 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -131,10 +131,10 @@ nv50_instmem_init(struct drm_device *dev) } /* we need a channel to plug into the hw to control the BARs */ - ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]); + ret = nv50_channel_new(dev, 128*1024, &dev_priv->channels.ptr[0]); if (ret) return ret; - chan = dev_priv->fifos[127] = dev_priv->fifos[0]; + chan = dev_priv->channels.ptr[127] = dev_priv->channels.ptr[0]; /* allocate page table for PRAMIN BAR */ ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8, @@ -240,7 +240,7 @@ nv50_instmem_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; - struct nouveau_channel *chan = dev_priv->fifos[0]; + struct nouveau_channel *chan = dev_priv->channels.ptr[0]; int i; NV_DEBUG(dev, "\n"); @@ -264,8 +264,8 @@ nv50_instmem_takedown(struct drm_device *dev) nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); dev_priv->vm_vram_pt_nr = 0; - nv50_channel_del(&dev_priv->fifos[0]); - dev_priv->fifos[127] = NULL; + nv50_channel_del(&dev_priv->channels.ptr[0]); + dev_priv->channels.ptr[127] = NULL; } dev_priv->engine.instmem.priv = NULL; @@ -276,7 +276,7 @@ int nv50_instmem_suspend(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->fifos[0]; + struct nouveau_channel *chan = dev_priv->channels.ptr[0]; struct nouveau_gpuobj *ramin = chan->ramin; int i; @@ -294,7 +294,7 @@ nv50_instmem_resume(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; - struct nouveau_channel *chan = dev_priv->fifos[0]; + struct nouveau_channel *chan = dev_priv->channels.ptr[0]; struct nouveau_gpuobj *ramin = chan->ramin; int i; -- cgit v1.2.3 From b12120a58e06cc6b799494c80215e418c14f9f5f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 6 Oct 2010 16:20:17 +1000 Subject: drm/nouveau: switch to unlocked ioctls Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 47bf2d3d658c..0e2414b0ae50 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -456,18 +456,18 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, ***********************************/ struct drm_ioctl_desc nouveau_ioctls[] = { - DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), - DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH), }; int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); -- cgit v1.2.3 From 21e86c1c8a844bf978f8fc431a59c9f5a578812d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 11 Oct 2010 11:48:45 +1000 Subject: drm/nouveau: remove cpu_writers lock No other driver uses this, and userspace should be responsible for handling locking between them if they share BOs. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 - drivers/gpu/drm/nouveau/nouveau_gem.c | 64 +++-------------------------------- include/drm/nouveau_drm.h | 1 - 3 files changed, 4 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c3f102125083..b78663fc334c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -96,7 +96,6 @@ struct nouveau_bo { struct nouveau_tile_reg *tile; struct drm_gem_object *gem; - struct drm_file *cpu_filp; int pin_refcnt; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 454d5ceb28f1..e14d10e38870 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -48,9 +48,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem) return; nvbo->gem = NULL; - if (unlikely(nvbo->cpu_filp)) - ttm_bo_synccpu_write_release(bo); - if (unlikely(nvbo->pin_refcnt)) { nvbo->pin_refcnt = 1; nouveau_bo_unpin(nvbo); @@ -334,23 +331,6 @@ retry: validate_fini(op, NULL); return -EINVAL; } - - if (unlikely(atomic_read(&nvbo->bo.cpu_writers) > 0)) { - validate_fini(op, NULL); - - if (nvbo->cpu_filp == file_priv) { - NV_ERROR(dev, "bo %p mapped by process trying " - "to validate it!\n", nvbo); - return -EINVAL; - } - - ret = ttm_bo_wait_cpu(&nvbo->bo, false); - if (ret) { - NV_ERROR(dev, "fail wait_cpu\n"); - return ret; - } - goto retry; - } } return 0; @@ -791,26 +771,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, return -ENOENT; nvbo = nouveau_gem_object(gem); - if (nvbo->cpu_filp) { - if (nvbo->cpu_filp == file_priv) - goto out; - - ret = ttm_bo_wait_cpu(&nvbo->bo, no_wait); - if (ret) - goto out; - } - - if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) { - spin_lock(&nvbo->bo.bdev->fence_lock); - ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait); - spin_unlock(&nvbo->bo.bdev->fence_lock); - } else { - ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait); - if (ret == 0) - nvbo->cpu_filp = file_priv; - } - -out: + spin_lock(&nvbo->bo.bdev->fence_lock); + ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait); + spin_unlock(&nvbo->bo.bdev->fence_lock); drm_gem_object_unreference_unlocked(gem); return ret; } @@ -819,26 +782,7 @@ int nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_nouveau_gem_cpu_prep *req = data; - struct drm_gem_object *gem; - struct nouveau_bo *nvbo; - int ret = -EINVAL; - - gem = drm_gem_object_lookup(dev, file_priv, req->handle); - if (!gem) - return -ENOENT; - nvbo = nouveau_gem_object(gem); - - if (nvbo->cpu_filp != file_priv) - goto out; - nvbo->cpu_filp = NULL; - - ttm_bo_synccpu_write_release(&nvbo->bo); - ret = 0; - -out: - drm_gem_object_unreference_unlocked(gem); - return ret; + return 0; } int diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index bc5590b1a1ac..60a7b3e9c2e9 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -171,7 +171,6 @@ struct drm_nouveau_gem_pushbuf { }; #define NOUVEAU_GEM_CPU_PREP_NOWAIT 0x00000001 -#define NOUVEAU_GEM_CPU_PREP_NOBLOCK 0x00000002 #define NOUVEAU_GEM_CPU_PREP_WRITE 0x00000004 struct drm_nouveau_gem_cpu_prep { uint32_t handle; -- cgit v1.2.3 From 08cd3d4311fb9c5038bc6fb0c83c250cfb218da2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Oct 2010 08:01:59 +1000 Subject: drm/nouveau: fix thinko in channel locking in semaphore path Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 42694b122eef..5f9f66f35067 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -393,23 +393,23 @@ nouveau_fence_sync(struct nouveau_fence *fence, return nouveau_fence_wait(fence, NULL, false, false); } - /* try to take wchan's mutex, if we can't take it right away + /* try to take chan's mutex, if we can't take it right away * we have to fallback to software sync to prevent locking * order issues */ - if (!mutex_trylock(&wchan->mutex)) { + if (!mutex_trylock(&chan->mutex)) { free_semaphore(&sema->ref); return nouveau_fence_wait(fence, NULL, false, false); } /* Make wchan wait until it gets signalled */ ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); - mutex_unlock(&wchan->mutex); if (ret) goto out; /* Signal the semaphore from chan */ ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); + mutex_unlock(&chan->mutex); out: kref_put(&sema->ref, free_semaphore); return ret; -- cgit v1.2.3 From 938c40ed69b2c1eceb72247b5e8975b28afc195f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Oct 2010 09:54:54 +1000 Subject: drm/nouveau: use interruptible waits during pushbuf validation Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index e14d10e38870..23b521ea8e04 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -299,14 +299,15 @@ retry: return -EINVAL; } - ret = ttm_bo_reserve(&nvbo->bo, false, false, true, sequence); + ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence); if (ret) { validate_fini(op, NULL); - if (ret == -EAGAIN) - ret = ttm_bo_wait_unreserved(&nvbo->bo, false); + if (unlikely(ret == -EAGAIN)) + ret = ttm_bo_wait_unreserved(&nvbo->bo, true); drm_gem_object_unreference_unlocked(gem); - if (ret) { - NV_ERROR(dev, "fail reserve\n"); + if (unlikely(ret)) { + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "fail reserve\n"); return ret; } goto retry; @@ -365,10 +366,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, - false, false, false); + true, false, false); nvbo->channel = NULL; if (unlikely(ret)) { - NV_ERROR(dev, "fail ttm_validate\n"); + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "fail ttm_validate\n"); return ret; } @@ -420,13 +422,15 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); if (unlikely(ret)) { - NV_ERROR(dev, "validate_init\n"); + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "validate_init\n"); return ret; } ret = validate_list(chan, &op->vram_list, pbbo, user_buffers); if (unlikely(ret < 0)) { - NV_ERROR(dev, "validate vram_list\n"); + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "validate vram_list\n"); validate_fini(op, NULL); return ret; } @@ -434,7 +438,8 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ret = validate_list(chan, &op->gart_list, pbbo, user_buffers); if (unlikely(ret < 0)) { - NV_ERROR(dev, "validate gart_list\n"); + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "validate gart_list\n"); validate_fini(op, NULL); return ret; } @@ -442,7 +447,8 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ret = validate_list(chan, &op->both_list, pbbo, user_buffers); if (unlikely(ret < 0)) { - NV_ERROR(dev, "validate both_list\n"); + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "validate both_list\n"); validate_fini(op, NULL); return ret; } @@ -628,7 +634,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, req->nr_buffers, &op, &do_reloc); if (ret) { - NV_ERROR(dev, "validate: %d\n", ret); + if (ret != -ERESTARTSYS) + NV_ERROR(dev, "validate: %d\n", ret); goto out; } -- cgit v1.2.3 From 18a16a768c3d37f5bfdbb414217b530294d5d442 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Oct 2010 10:11:00 +1000 Subject: drm/nouveau: return error from nouveau_ramht_remove() if not found Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 10 ++-------- drivers/gpu/drm/nouveau/nouveau_ramht.c | 5 +++-- drivers/gpu/drm/nouveau/nouveau_ramht.h | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 068441c4b563..ce9958a30175 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -926,20 +926,14 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_nouveau_gpuobj_free *objfree = data; - struct nouveau_gpuobj *gpuobj; struct nouveau_channel *chan; - int ret = -ENOENT; + int ret; chan = nouveau_channel_get(dev, file_priv, objfree->channel); if (IS_ERR(chan)) return PTR_ERR(chan); - gpuobj = nouveau_ramht_find(chan, objfree->handle); - if (gpuobj) { - nouveau_ramht_remove(chan, objfree->handle); - ret = 0; - } - + ret = nouveau_ramht_remove(chan, objfree->handle); nouveau_channel_put(&chan); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c index 2d8580927ca4..b4c63c058888 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.c +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c @@ -214,18 +214,19 @@ out: spin_unlock_irqrestore(&chan->ramht->lock, flags); } -void +int nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) { struct nouveau_ramht_entry *entry; entry = nouveau_ramht_remove_entry(chan, handle); if (!entry) - return; + return -ENOENT; nouveau_ramht_remove_hash(chan, entry->handle); nouveau_gpuobj_ref(NULL, &entry->gpuobj); kfree(entry); + return 0; } struct nouveau_gpuobj * diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.h b/drivers/gpu/drm/nouveau/nouveau_ramht.h index b79cb5e1a8f1..c82de98fee0e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.h +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.h @@ -48,7 +48,7 @@ extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **, extern int nouveau_ramht_insert(struct nouveau_channel *, u32 handle, struct nouveau_gpuobj *); -extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle); +extern int nouveau_ramht_remove(struct nouveau_channel *, u32 handle); extern struct nouveau_gpuobj * nouveau_ramht_find(struct nouveau_channel *chan, u32 handle); -- cgit v1.2.3 From 6032649df9f456f379be8d51f64488cacbfa8317 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Oct 2010 12:31:32 +1000 Subject: drm/nouveau: hook up acpi power supply change tracking Not used at all yet, but lets hook it up now anyway. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_pm.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index b78663fc334c..699d546623bd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -439,6 +439,7 @@ struct nouveau_pm_engine { struct nouveau_pm_level *cur; struct device *hwmon; + struct notifier_block acpi_nb; int (*clock_get)(struct drm_device *, u32 id); void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *, diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 9f7b158f5825..d93814160bcf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -27,6 +27,10 @@ #include "nouveau_drv.h" #include "nouveau_pm.h" +#ifdef CONFIG_ACPI +#include +#endif +#include #include #include @@ -446,6 +450,25 @@ nouveau_hwmon_fini(struct drm_device *dev) #endif } +#ifdef CONFIG_ACPI +static int +nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) +{ + struct drm_nouveau_private *dev_priv = + container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb); + struct drm_device *dev = dev_priv->dev; + struct acpi_bus_event *entry = (struct acpi_bus_event *)data; + + if (strcmp(entry->device_class, "ac_adapter") == 0) { + bool ac = power_supply_is_system_supplied(); + + NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); + } + + return NOTIFY_OK; +} +#endif + int nouveau_pm_init(struct drm_device *dev) { @@ -485,6 +508,10 @@ nouveau_pm_init(struct drm_device *dev) nouveau_sysfs_init(dev); nouveau_hwmon_init(dev); +#ifdef CONFIG_ACPI + pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; + register_acpi_notifier(&pm->acpi_nb); +#endif return 0; } @@ -503,6 +530,9 @@ nouveau_pm_fini(struct drm_device *dev) nouveau_perf_fini(dev); nouveau_volt_fini(dev); +#ifdef CONFIG_ACPI + unregister_acpi_notifier(&pm->acpi_nb); +#endif nouveau_hwmon_fini(dev); nouveau_sysfs_fini(dev); } -- cgit v1.2.3 From 9acc8100cb14b91d446a482fdd0cf7e3ccbcf930 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 14 Oct 2010 14:55:23 +1000 Subject: drm/nouveau: fallback to sw fbcon if we can't get mutex immediately Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index bc30dbe11d00..0fce4eb914d5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -61,8 +61,8 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) return; ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { - mutex_lock(&dev_priv->channel->mutex); + if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && + mutex_trylock(&dev_priv->channel->mutex)) { if (dev_priv->card_type < NV_50) ret = nv04_fbcon_fillrect(info, rect); else @@ -91,8 +91,8 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) return; ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { - mutex_lock(&dev_priv->channel->mutex); + if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && + mutex_trylock(&dev_priv->channel->mutex)) { if (dev_priv->card_type < NV_50) ret = nv04_fbcon_copyarea(info, image); else @@ -121,8 +121,8 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) return; ret = -ENODEV; - if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED)) { - mutex_lock(&dev_priv->channel->mutex); + if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && + mutex_trylock(&dev_priv->channel->mutex)) { if (dev_priv->card_type < NV_50) ret = nv04_fbcon_imageblit(info, image); else @@ -153,7 +153,9 @@ nouveau_fbcon_sync(struct fb_info *info) info->flags & FBINFO_HWACCEL_DISABLED) return 0; - mutex_lock(&chan->mutex); + if (!mutex_trylock(&chan->mutex)) + return 0; + ret = RING_SPACE(chan, 4); if (ret) { mutex_unlock(&chan->mutex); -- cgit v1.2.3 From cbb4b608b603c7fba4c1cf5b298d1aa23d3fdd22 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 18 Oct 2010 12:34:04 +1000 Subject: drm/nv50: remove some unnecessary PDISPLAY init Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index f624c611ddea..7ac87efb791f 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -218,9 +218,9 @@ nv50_display_init(struct drm_device *dev) struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; struct nouveau_channel *evo = dev_priv->evo; struct drm_connector *connector; - uint32_t val, ram_amount; - uint64_t start; int ret, i; + u64 start; + u32 val; NV_DEBUG_KMS(dev, "\n"); @@ -262,17 +262,6 @@ nv50_display_init(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001); } - /* This used to be in crtc unblank, but seems out of place there. */ - nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0); - /* RAM is clamped to 256 MiB. */ - ram_amount = dev_priv->vram_size; - NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount); - if (ram_amount > 256*1024*1024) - ram_amount = 256*1024*1024; - nv_wr32(dev, NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); - nv_wr32(dev, NV50_PDISPLAY_UNK_388, 0x150000); - nv_wr32(dev, NV50_PDISPLAY_UNK_38C, 0); - /* The precise purpose is unknown, i suspect it has something to do * with text mode. */ -- cgit v1.2.3 From aa5ac7358c010dcb5916d1d0c2651ae65a4f7ab7 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 14 Oct 2010 20:37:56 +0200 Subject: drm/nouveau: Leave BO eviction synchronization for later. The pushbuf ioctl syncs after validation, no need for this anymore. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index d8817b4bb189..8442bfbf5d42 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -485,15 +485,8 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, if (ret) return ret; - if (nvbo->channel) { - ret = nouveau_fence_sync(fence, nvbo->channel); - if (ret) - goto out; - } - ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict, no_wait_reserve, no_wait_gpu, new_mem); -out: nouveau_fence_unref((void *)&fence); return ret; } -- cgit v1.2.3 From fcccab2e4eb8d579837481054cc2cb28eea0baef Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 14 Oct 2010 21:55:23 +0200 Subject: drm/nouveau: Use lazy fence waits when doing software interchannel sync. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 5f9f66f35067..0a22955998e8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -390,7 +390,7 @@ nouveau_fence_sync(struct nouveau_fence *fence, if (!sema) { /* Early card or broken userspace, fall back to * software sync. */ - return nouveau_fence_wait(fence, NULL, false, false); + return nouveau_fence_wait(fence, NULL, true, false); } /* try to take chan's mutex, if we can't take it right away @@ -399,7 +399,7 @@ nouveau_fence_sync(struct nouveau_fence *fence, */ if (!mutex_trylock(&chan->mutex)) { free_semaphore(&sema->ref); - return nouveau_fence_wait(fence, NULL, false, false); + return nouveau_fence_wait(fence, NULL, true, false); } /* Make wchan wait until it gets signalled */ -- cgit v1.2.3 From 3945e47543863385b54d94c94b023ee7ca9df972 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:53:39 +0200 Subject: drm/nouveau: Refactor context destruction to avoid a lock ordering issue. The destroy_context() engine hooks call gpuobj management functions to release the channel resources, these functions use HARDIRQ-unsafe locks whereas destroy_context() is called with the HARDIRQ-safe context_switch_lock held, that's a lock ordering violation. Push the engine-specific channel destruction logic into destroy_context() and let the hardware-specific code lock and unlock when it's actually needed. Change the engine destruction order to avoid a race in the small gap between pgraph and pfifo context uninitialization. Reported-by: Marcin Slusarz Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 24 ++++++------------------ drivers/gpu/drm/nouveau/nouveau_drv.h | 2 -- drivers/gpu/drm/nouveau/nouveau_state.c | 8 ++++---- drivers/gpu/drm/nouveau/nv04_fifo.c | 21 +++++++++++++++++++-- drivers/gpu/drm/nouveau/nv04_graph.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nv10_fifo.c | 11 ----------- drivers/gpu/drm/nouveau/nv10_graph.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nv20_graph.c | 14 +++++++++++++- drivers/gpu/drm/nouveau/nv40_fifo.c | 11 ----------- drivers/gpu/drm/nouveau/nv40_graph.c | 16 ++++++++++++++++ drivers/gpu/drm/nouveau/nv50_fifo.c | 17 +++++++++++++++++ drivers/gpu/drm/nouveau/nv50_graph.c | 11 +++++++++++ 12 files changed, 116 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 0e2414b0ae50..9a051fafa7c3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -313,32 +313,20 @@ nouveau_channel_put(struct nouveau_channel **pchan) /* boot it off the hardware */ pfifo->reassign(dev, false); - /* We want to give pgraph a chance to idle and get rid of all potential - * errors. We need to do this before the lock, otherwise the irq handler - * is unable to process them. + /* We want to give pgraph a chance to idle and get rid of all + * potential errors. We need to do this without the context + * switch lock held, otherwise the irq handler is unable to + * process them. */ if (pgraph->channel(dev) == chan) nouveau_wait_for_idle(dev); - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - - pgraph->fifo_access(dev, false); - if (pgraph->channel(dev) == chan) - pgraph->unload_context(dev); - pgraph->destroy_context(chan); - pgraph->fifo_access(dev, true); - - if (pfifo->channel_id(dev) == chan->id) { - pfifo->disable(dev); - pfifo->unload_context(dev); - pfifo->enable(dev); - } + /* destroy the engine specific contexts */ pfifo->destroy_context(chan); + pgraph->destroy_context(chan); pfifo->reassign(dev, true); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - /* aside from its resources, the channel should now be dead, * remove it from the channel list */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 699d546623bd..198dabebafb2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -998,14 +998,12 @@ extern int nv04_fifo_unload_context(struct drm_device *); extern int nv10_fifo_init(struct drm_device *); extern int nv10_fifo_channel_id(struct drm_device *); extern int nv10_fifo_create_context(struct nouveau_channel *); -extern void nv10_fifo_destroy_context(struct nouveau_channel *); extern int nv10_fifo_load_context(struct nouveau_channel *); extern int nv10_fifo_unload_context(struct drm_device *); /* nv40_fifo.c */ extern int nv40_fifo_init(struct drm_device *); extern int nv40_fifo_create_context(struct nouveau_channel *); -extern void nv40_fifo_destroy_context(struct nouveau_channel *); extern int nv40_fifo_load_context(struct nouveau_channel *); extern int nv40_fifo_unload_context(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 513c1063fb5e..1a4ba6ccafb1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -137,7 +137,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; - engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.destroy_context = nv04_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; engine->display.early_init = nv04_display_early_init; @@ -191,7 +191,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; - engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.destroy_context = nv04_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; engine->display.early_init = nv04_display_early_init; @@ -245,7 +245,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv10_fifo_create_context; - engine->fifo.destroy_context = nv10_fifo_destroy_context; + engine->fifo.destroy_context = nv04_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; engine->display.early_init = nv04_display_early_init; @@ -302,7 +302,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.cache_pull = nv04_fifo_cache_pull; engine->fifo.channel_id = nv10_fifo_channel_id; engine->fifo.create_context = nv40_fifo_create_context; - engine->fifo.destroy_context = nv40_fifo_destroy_context; + engine->fifo.destroy_context = nv04_fifo_destroy_context; engine->fifo.load_context = nv40_fifo_load_context; engine->fifo.unload_context = nv40_fifo_unload_context; engine->display.early_init = nv04_display_early_init; diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 25c439dcdfd9..4c0d3a8fca68 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -151,10 +151,27 @@ void nv04_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + unsigned long flags; - nv_wr32(dev, NV04_PFIFO_MODE, - nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pfifo->reassign(dev, false); + + /* Unload the context if it's the currently active one */ + if (pfifo->channel_id(dev) == chan->id) { + pfifo->disable(dev); + pfifo->unload_context(dev); + pfifo->enable(dev); + } + + /* Keep it from being rescheduled */ + nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0); + + pfifo->reassign(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + /* Free the channel resources */ nouveau_gpuobj_ref(NULL, &chan->ramfc); } diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 98b9525c1ebd..1e2ad3942330 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -412,10 +412,25 @@ int nv04_graph_create_context(struct nouveau_channel *chan) void nv04_graph_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct graph_state *pgraph_ctx = chan->pgraph_ctx; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pgraph->fifo_access(dev, false); + + /* Unload the context if it's the currently active one */ + if (pgraph->channel(dev) == chan) + pgraph->unload_context(dev); + /* Free the context resources */ kfree(pgraph_ctx); chan->pgraph_ctx = NULL; + + pgraph->fifo_access(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); } int nv04_graph_load_context(struct nouveau_channel *chan) diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c index 39328fcce709..912556f2e33c 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c @@ -73,17 +73,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) return 0; } -void -nv10_fifo_destroy_context(struct nouveau_channel *chan) -{ - struct drm_device *dev = chan->dev; - - nv_wr32(dev, NV04_PFIFO_MODE, - nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); - - nouveau_gpuobj_ref(NULL, &chan->ramfc); -} - static void nv10_fifo_do_load_context(struct drm_device *dev, int chid) { diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index cd931b57cf05..e3a87a64c164 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -875,10 +875,25 @@ int nv10_graph_create_context(struct nouveau_channel *chan) void nv10_graph_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct graph_state *pgraph_ctx = chan->pgraph_ctx; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pgraph->fifo_access(dev, false); + + /* Unload the context if it's the currently active one */ + if (pgraph->channel(dev) == chan) + pgraph->unload_context(dev); + /* Free the context resources */ kfree(pgraph_ctx); chan->pgraph_ctx = NULL; + + pgraph->fifo_access(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); } void diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 12ab9cd56eca..8a0402012557 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -425,9 +425,21 @@ nv20_graph_destroy_context(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + unsigned long flags; - nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pgraph->fifo_access(dev, false); + + /* Unload the context if it's the currently active one */ + if (pgraph->channel(dev) == chan) + pgraph->unload_context(dev); + + pgraph->fifo_access(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ nv_wo32(pgraph->ctx_table, chan->id * 4, 0); + nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); } int diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 3c7be3dc8b88..311ac9ea5d53 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -70,17 +70,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) return 0; } -void -nv40_fifo_destroy_context(struct nouveau_channel *chan) -{ - struct drm_device *dev = chan->dev; - - nv_wr32(dev, NV04_PFIFO_MODE, - nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); - - nouveau_gpuobj_ref(NULL, &chan->ramfc); -} - static void nv40_fifo_do_load_context(struct drm_device *dev, int chid) { diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index e0b41a26447f..70d97cde49d0 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -79,6 +79,22 @@ nv40_graph_create_context(struct nouveau_channel *chan) void nv40_graph_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pgraph->fifo_access(dev, false); + + /* Unload the context if it's the currently active one */ + if (pgraph->channel(dev) == chan) + pgraph->unload_context(dev); + + pgraph->fifo_access(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); } diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index 815960fe4f43..d3295aae0c4e 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -292,10 +292,23 @@ void nv50_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_gpuobj *ramfc = NULL; + unsigned long flags; NV_DEBUG(dev, "ch%d\n", chan->id); + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pfifo->reassign(dev, false); + + /* Unload the context if it's the currently active one */ + if (pfifo->channel_id(dev) == chan->id) { + pfifo->disable(dev); + pfifo->unload_context(dev); + pfifo->enable(dev); + } + /* This will ensure the channel is seen as disabled. */ nouveau_gpuobj_ref(chan->ramfc, &ramfc); nouveau_gpuobj_ref(NULL, &chan->ramfc); @@ -306,6 +319,10 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) nv50_fifo_channel_disable(dev, 127); nv50_fifo_playlist_update(dev); + pfifo->reassign(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the channel resources */ nouveau_gpuobj_ref(NULL, &ramfc); nouveau_gpuobj_ref(NULL, &chan->cache); } diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 24a3f8487579..dcc9175fb794 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -242,17 +242,28 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; + unsigned long flags; NV_DEBUG(dev, "ch%d\n", chan->id); if (!chan->ramin) return; + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + pgraph->fifo_access(dev, false); + + if (pgraph->channel(dev) == chan) + pgraph->unload_context(dev); + for (i = hdr; i < hdr + 24; i += 4) nv_wo32(chan->ramin, i, 0); dev_priv->engine.instmem.flush(dev); + pgraph->fifo_access(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); } -- cgit v1.2.3 From f175b745b50c5c5356e8b3b409b7f38aa44de6bb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:54:33 +0200 Subject: drm/nouveau: Fix race condition in channel refcount handling. nouveau_channel_put() can be executed after the 'refcount == 0' check in nouveau_channel_get() and before the channel reference count is incremented. In that case CPU0 will take the context down while CPU1 thinks it owns the channel and 'refcount == 1'. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 9a051fafa7c3..c46a6f641964 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -247,17 +247,16 @@ nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) spin_lock_irqsave(&dev_priv->channels.lock, flags); chan = dev_priv->channels.ptr[id]; - if (unlikely(!chan || atomic_read(&chan->refcount) == 0)) { + if (unlikely(!chan || (file_priv && chan->file_priv != file_priv))) { spin_unlock_irqrestore(&dev_priv->channels.lock, flags); return ERR_PTR(-EINVAL); } - if (unlikely(file_priv && chan->file_priv != file_priv)) { + if (unlikely(!atomic_inc_not_zero(&chan->refcount))) { spin_unlock_irqrestore(&dev_priv->channels.lock, flags); return ERR_PTR(-EINVAL); } - atomic_inc(&chan->refcount); spin_unlock_irqrestore(&dev_priv->channels.lock, flags); mutex_lock(&chan->mutex); -- cgit v1.2.3 From feeb0aecfb73b5b7699c0a85ba1650e6f9c50be2 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 02:58:04 +0200 Subject: drm/nouveau: Add unlocked variants of nouveau_channel_get/put. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 36 ++++++++++++++++++++----------- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +++ 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index c46a6f641964..38929fd3f4e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -237,34 +237,40 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return 0; } +struct nouveau_channel * +nouveau_channel_get_unlocked(struct nouveau_channel *ref) +{ + if (likely(ref && atomic_inc_not_zero(&ref->refcount))) + return ref; + + return NULL; +} + struct nouveau_channel * nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = ERR_PTR(-ENODEV); + struct nouveau_channel *chan; unsigned long flags; spin_lock_irqsave(&dev_priv->channels.lock, flags); - chan = dev_priv->channels.ptr[id]; + chan = nouveau_channel_get_unlocked(dev_priv->channels.ptr[id]); + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - if (unlikely(!chan || (file_priv && chan->file_priv != file_priv))) { - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + if (unlikely(!chan)) return ERR_PTR(-EINVAL); - } - if (unlikely(!atomic_inc_not_zero(&chan->refcount))) { - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + if (unlikely(file_priv && chan->file_priv != file_priv)) { + nouveau_channel_put_unlocked(&chan); return ERR_PTR(-EINVAL); } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - mutex_lock(&chan->mutex); return chan; } void -nouveau_channel_put(struct nouveau_channel **pchan) +nouveau_channel_put_unlocked(struct nouveau_channel **pchan) { struct nouveau_channel *chan = *pchan; struct drm_device *dev = chan->dev; @@ -274,9 +280,6 @@ nouveau_channel_put(struct nouveau_channel **pchan) unsigned long flags; int ret; - /* unlock the channel */ - mutex_unlock(&chan->mutex); - /* decrement the refcount, and we're done if there's still refs */ if (likely(!atomic_dec_and_test(&chan->refcount))) { *pchan = NULL; @@ -348,6 +351,13 @@ nouveau_channel_put(struct nouveau_channel **pchan) kfree(chan); } +void +nouveau_channel_put(struct nouveau_channel **pchan) +{ + mutex_unlock(&(*pchan)->mutex); + nouveau_channel_put_unlocked(pchan); +} + /* cleans up all the fifos from file_priv */ void nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 198dabebafb2..e6708be58bcf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -803,7 +803,10 @@ extern int nouveau_channel_alloc(struct drm_device *dev, struct drm_file *file_priv, uint32_t fb_ctxdma, uint32_t tt_ctxdma); extern struct nouveau_channel * +nouveau_channel_get_unlocked(struct nouveau_channel *); +extern struct nouveau_channel * nouveau_channel_get(struct drm_device *, struct drm_file *, int id); +extern void nouveau_channel_put_unlocked(struct nouveau_channel **); extern void nouveau_channel_put(struct nouveau_channel **); /* nouveau_object.c */ -- cgit v1.2.3 From 36c952e8b3bad911ef13111058f0a5c4b361027e Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:01:34 +0200 Subject: drm/nouveau: Fix lock unbalance on card take down. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 1a4ba6ccafb1..af203cc5d7ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -714,7 +714,7 @@ static void nouveau_card_takedown(struct drm_device *dev) if (!engine->graph.accel_blocked) { nouveau_fence_fini(dev); - nouveau_channel_put(&dev_priv->channel); + nouveau_channel_put_unlocked(&dev_priv->channel); } if (!nouveau_noaccel) { -- cgit v1.2.3 From f091a3d403065416b7d27221bbeb956481132ffd Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:55:48 +0200 Subject: drm/nouveau: Implement weak channel references. nouveau_channel_ref() takes a "weak" channel reference that doesn't prevent the hardware channel resources from being released, it just keeps the channel data structure alive. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 55 ++++++++++++++++++++++--------- drivers/gpu/drm/nouveau/nouveau_drv.h | 8 ++++- 2 files changed, 47 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 38929fd3f4e3..76033c509d35 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -125,7 +125,8 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, chan->vram_handle = vram_handle; chan->gart_handle = gart_handle; - atomic_set(&chan->refcount, 1); + kref_init(&chan->ref); + atomic_set(&chan->users, 1); mutex_init(&chan->mutex); mutex_lock(&chan->mutex); @@ -133,7 +134,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, spin_lock_irqsave(&dev_priv->channels.lock, flags); for (chan->id = 0; chan->id < pfifo->channels; chan->id++) { if (!dev_priv->channels.ptr[chan->id]) { - dev_priv->channels.ptr[chan->id] = chan; + nouveau_channel_ref(chan, &dev_priv->channels.ptr[chan->id]); break; } } @@ -240,10 +241,12 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct nouveau_channel * nouveau_channel_get_unlocked(struct nouveau_channel *ref) { - if (likely(ref && atomic_inc_not_zero(&ref->refcount))) - return ref; + struct nouveau_channel *chan = NULL; - return NULL; + if (likely(ref && atomic_inc_not_zero(&ref->users))) + nouveau_channel_ref(ref, &chan); + + return chan; } struct nouveau_channel * @@ -281,15 +284,14 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) int ret; /* decrement the refcount, and we're done if there's still refs */ - if (likely(!atomic_dec_and_test(&chan->refcount))) { - *pchan = NULL; + if (likely(!atomic_dec_and_test(&chan->users))) { + nouveau_channel_ref(NULL, pchan); return; } /* noone wants the channel anymore */ NV_DEBUG(dev, "freeing channel %d\n", chan->id); nouveau_debugfs_channel_fini(chan); - *pchan = NULL; /* give it chance to idle */ nouveau_fence_update(chan); @@ -333,7 +335,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) * remove it from the channel list */ spin_lock_irqsave(&dev_priv->channels.lock, flags); - dev_priv->channels.ptr[chan->id] = NULL; + nouveau_channel_ref(NULL, &dev_priv->channels.ptr[chan->id]); spin_unlock_irqrestore(&dev_priv->channels.lock, flags); /* destroy any resources the channel owned */ @@ -345,10 +347,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) } nouveau_gpuobj_channel_takedown(chan); nouveau_notifier_takedown_channel(chan); - if (chan->user) - iounmap(chan->user); - kfree(chan); + nouveau_channel_ref(NULL, pchan); } void @@ -358,6 +358,31 @@ nouveau_channel_put(struct nouveau_channel **pchan) nouveau_channel_put_unlocked(pchan); } +static void +nouveau_channel_del(struct kref *ref) +{ + struct nouveau_channel *chan = + container_of(ref, struct nouveau_channel, ref); + + if (chan->user) + iounmap(chan->user); + + kfree(chan); +} + +void +nouveau_channel_ref(struct nouveau_channel *chan, + struct nouveau_channel **pchan) +{ + if (chan) + kref_get(&chan->ref); + + if (*pchan) + kref_put(&(*pchan)->ref, nouveau_channel_del); + + *pchan = chan; +} + /* cleans up all the fifos from file_priv */ void nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) @@ -373,7 +398,7 @@ nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) if (IS_ERR(chan)) continue; - atomic_dec(&chan->refcount); + atomic_dec(&chan->users); nouveau_channel_put(&chan); } } @@ -427,7 +452,7 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, &init->notifier_handle); if (ret == 0) - atomic_inc(&chan->refcount); /* userspace reference */ + atomic_inc(&chan->users); /* userspace reference */ nouveau_channel_put(&chan); return ret; } @@ -443,7 +468,7 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, if (IS_ERR(chan)) return PTR_ERR(chan); - atomic_dec(&chan->refcount); + atomic_dec(&chan->users); nouveau_channel_put(&chan); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e6708be58bcf..d152bc334fd6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -165,7 +165,11 @@ struct nouveau_channel { struct drm_device *dev; int id; - atomic_t refcount; + /* references to the channel data structure */ + struct kref ref; + /* users of the hardware channel resources, the hardware + * context will be kicked off when it reaches zero. */ + atomic_t users; struct mutex mutex; /* owner of this fifo */ @@ -808,6 +812,8 @@ extern struct nouveau_channel * nouveau_channel_get(struct drm_device *, struct drm_file *, int id); extern void nouveau_channel_put_unlocked(struct nouveau_channel **); extern void nouveau_channel_put(struct nouveau_channel **); +extern void nouveau_channel_ref(struct nouveau_channel *chan, + struct nouveau_channel **pchan); /* nouveau_object.c */ extern int nouveau_gpuobj_early_init(struct drm_device *); -- cgit v1.2.3 From 2a6789ae5e8a6b25a0835834655205166a757a81 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:56:14 +0200 Subject: drm/nouveau: Make fences take a weak channel reference. Fences didn't increment the channel reference count, and the fenced channel could go away at any time. Fixes a potential race in nouveau_fence_update(). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 0a22955998e8..e1ae9bab6e41 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -64,6 +64,7 @@ nouveau_fence_del(struct kref *ref) struct nouveau_fence *fence = container_of(ref, struct nouveau_fence, refcount); + nouveau_channel_ref(NULL, &fence->channel); kfree(fence); } @@ -113,7 +114,7 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence, if (!fence) return -ENOMEM; kref_init(&fence->refcount); - fence->channel = chan; + nouveau_channel_ref(chan, &fence->channel); if (emit) ret = nouveau_fence_emit(fence); -- cgit v1.2.3 From 2b478addc0bfaaf5031e36ee166c9457ceae628c Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:56:40 +0200 Subject: drm/nouveau: Avoid race in the interchannel sync code. It needs a "strong" channel reference because it actually writes to the channel pushbuf, otherwise the corresponding FIFO context could get kicked off in the middle of nouveau_fence_sync(). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index e1ae9bab6e41..29fe03bc4870 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -128,7 +128,7 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence, struct nouveau_channel * nouveau_fence_channel(struct nouveau_fence *fence) { - return fence ? fence->channel : NULL; + return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL; } int @@ -381,17 +381,18 @@ nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan = nouveau_fence_channel(fence); struct drm_device *dev = wchan->dev; struct nouveau_semaphore *sema; - int ret; + int ret = 0; - if (likely(!fence || chan == wchan || + if (likely(!chan || chan == wchan || nouveau_fence_signalled(fence, NULL))) - return 0; + goto out; sema = alloc_semaphore(dev); if (!sema) { /* Early card or broken userspace, fall back to * software sync. */ - return nouveau_fence_wait(fence, NULL, true, false); + ret = nouveau_fence_wait(fence, NULL, true, false); + goto out; } /* try to take chan's mutex, if we can't take it right away @@ -399,20 +400,25 @@ nouveau_fence_sync(struct nouveau_fence *fence, * order issues */ if (!mutex_trylock(&chan->mutex)) { - free_semaphore(&sema->ref); - return nouveau_fence_wait(fence, NULL, true, false); + ret = nouveau_fence_wait(fence, NULL, true, false); + goto out_unref; } /* Make wchan wait until it gets signalled */ ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); if (ret) - goto out; + goto out_unlock; /* Signal the semaphore from chan */ ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); + +out_unlock: mutex_unlock(&chan->mutex); -out: +out_unref: kref_put(&sema->ref, free_semaphore); +out: + if (chan) + nouveau_channel_put_unlocked(&chan); return ret; } -- cgit v1.2.3 From 889fa93dc0ab94b9255e9dd8e2036facfee5485e Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 03:57:19 +0200 Subject: drm/nouveau: Take fence spinlock in nouveau_fence_channel_fini(). Without it there's a potential race with nouveau_fence_update(). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 29fe03bc4870..f70bec835f5f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -490,6 +490,8 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan) { struct nouveau_fence *tmp, *fence; + spin_lock(&chan->fence.lock); + list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { fence->signalled = true; list_del(&fence->entry); @@ -499,6 +501,8 @@ nouveau_fence_channel_fini(struct nouveau_channel *chan) kref_put(&fence->refcount, nouveau_fence_del); } + + spin_unlock(&chan->fence.lock); } int -- cgit v1.2.3 From 0541324abce0225a795222558fdfe35c8dbc5b4f Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 18 Oct 2010 16:15:15 +0200 Subject: drm/nv40: Ignore sync-to-vblank active when waiting for idle. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_reg.h | 1 + drivers/gpu/drm/nouveau/nouveau_state.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 1b42541ca9e5..1bbe7037cf99 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -332,6 +332,7 @@ #define NV04_PGRAPH_BSWIZZLE5 0x004006A0 #define NV03_PGRAPH_STATUS 0x004006B0 #define NV04_PGRAPH_STATUS 0x00400700 +# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000 #define NV04_PGRAPH_TRAPPED_ADDR 0x00400704 #define NV04_PGRAPH_TRAPPED_DATA 0x00400708 #define NV04_PGRAPH_SURFACE 0x0040070C diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index af203cc5d7ad..82b58188398b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1105,7 +1105,13 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout, /* Waits for PGRAPH to go completely idle */ bool nouveau_wait_for_idle(struct drm_device *dev) { - if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t mask = ~0; + + if (dev_priv->card_type == NV_40) + mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL; + + if (!nv_wait(dev, NV04_PGRAPH_STATUS, mask, 0)) { NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n", nv_rd32(dev, NV04_PGRAPH_STATUS)); return false; -- cgit v1.2.3 From 9100468d1be26063aa25ecd667ea922c101d203f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 15 Oct 2010 09:15:26 +1000 Subject: drm/nouveau: pass gpuobj alignment request down into backing allocator Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 8 ++++---- drivers/gpu/drm/nouveau/nouveau_object.c | 2 +- drivers/gpu/drm/nouveau/nv04_instmem.c | 2 +- drivers/gpu/drm/nouveau/nv50_instmem.c | 10 +++++----- drivers/gpu/drm/nouveau/nvc0_instmem.c | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d152bc334fd6..1d474f526986 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -265,7 +265,7 @@ struct nouveau_instmem_engine { void (*resume)(struct drm_device *dev); int (*populate)(struct drm_device *, struct nouveau_gpuobj *, - uint32_t *size); + u32 *size, u32 align); void (*clear)(struct drm_device *, struct nouveau_gpuobj *); int (*bind)(struct drm_device *, struct nouveau_gpuobj *); int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); @@ -1121,7 +1121,7 @@ extern void nv04_instmem_takedown(struct drm_device *); extern int nv04_instmem_suspend(struct drm_device *); extern void nv04_instmem_resume(struct drm_device *); extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, - uint32_t *size); + u32 *size, u32 align); extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -1133,7 +1133,7 @@ extern void nv50_instmem_takedown(struct drm_device *); extern int nv50_instmem_suspend(struct drm_device *); extern void nv50_instmem_resume(struct drm_device *); extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, - uint32_t *size); + u32 *size, u32 align); extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); @@ -1147,7 +1147,7 @@ extern void nvc0_instmem_takedown(struct drm_device *); extern int nvc0_instmem_suspend(struct drm_device *); extern void nvc0_instmem_resume(struct drm_device *); extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, - uint32_t *size); + u32 *size, u32 align); extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index ce9958a30175..0b8183edfcd7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -112,7 +112,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, NV_DEBUG(dev, "global heap\n"); /* allocate backing pages, sets vinst */ - ret = engine->instmem.populate(dev, gpuobj, &size); + ret = engine->instmem.populate(dev, gpuobj, &size, align); if (ret) { nouveau_gpuobj_ref(NULL, &gpuobj); return ret; diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c index 0b5ae297abde..554e55d0ec48 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c @@ -99,7 +99,7 @@ nv04_instmem_takedown(struct drm_device *dev) int nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, - uint32_t *sz) + u32 *size, u32 align) { return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 0651e7629235..2c98eb176d64 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -322,19 +322,19 @@ nv50_instmem_resume(struct drm_device *dev) int nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, - uint32_t *sz) + u32 *size, u32 align) { int ret; if (gpuobj->im_backing) return -EINVAL; - *sz = ALIGN(*sz, 4096); - if (*sz == 0) + *size = ALIGN(*size, 4096); + if (*size == 0) return -EINVAL; - ret = nouveau_bo_new(dev, NULL, *sz, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, - true, false, &gpuobj->im_backing); + ret = nouveau_bo_new(dev, NULL, *size, align, TTM_PL_FLAG_VRAM, + 0, 0x0000, true, false, &gpuobj->im_backing); if (ret) { NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 13a0f78a9088..7b4e71f5c274 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -28,7 +28,7 @@ int nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, - uint32_t *size) + u32 *size, u32 align) { int ret; @@ -36,8 +36,8 @@ nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, if (*size == 0) return -EINVAL; - ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, - true, false, &gpuobj->im_backing); + ret = nouveau_bo_new(dev, NULL, *size, align, TTM_PL_FLAG_VRAM, + 0, 0x0000, true, false, &gpuobj->im_backing); if (ret) { NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); return ret; -- cgit v1.2.3 From 50536946faaf3d9ac0245838eb09e5eb1065b06c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 19:47:06 +1000 Subject: drm/nouveau: store engine type in gpuobj class structs We will eventually want to address hw engines other than PGRAPH. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 +- drivers/gpu/drm/nouveau/nouveau_object.c | 2 +- drivers/gpu/drm/nouveau/nv04_graph.c | 84 ++++++++++++++++---------------- drivers/gpu/drm/nouveau/nv10_graph.c | 40 +++++++-------- drivers/gpu/drm/nouveau/nv20_graph.c | 70 +++++++++++++------------- drivers/gpu/drm/nouveau/nv40_graph.c | 34 ++++++------- drivers/gpu/drm/nouveau/nv50_graph.c | 20 ++++---- 7 files changed, 127 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1d474f526986..2fdc26655ca1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -132,7 +132,7 @@ enum nouveau_flags { #define NVOBJ_ENGINE_SW 0 #define NVOBJ_ENGINE_GR 1 -#define NVOBJ_ENGINE_DISPLAY 2 +#define NVOBJ_ENGINE_DISPLAY 0xcafe0001 #define NVOBJ_ENGINE_INT 0xdeadbeef #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) @@ -324,7 +324,7 @@ struct nouveau_pgraph_object_method { struct nouveau_pgraph_object_class { int id; - bool software; + u32 engine; struct nouveau_pgraph_object_method *methods; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 0b8183edfcd7..70ffd7530503 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -900,7 +900,7 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, goto out; } - if (!grc->software) + if (grc->engine != NVOBJ_ENGINE_SW) ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr); else ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr); diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 1e2ad3942330..5d8ab1b6b04a 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -1091,48 +1091,48 @@ static struct nouveau_pgraph_object_method nv04_graph_mthds_surf3d[] = { }; struct nouveau_pgraph_object_class nv04_graph_grclass[] = { - { 0x0038, false, NULL }, /* dvd subpicture */ - { 0x0039, false, NULL }, /* m2mf */ - { 0x004b, false, nv04_graph_mthds_nv03_gdirect }, /* nv03 gdirect */ - { 0x004a, false, nv04_graph_mthds_nv04_gdirect }, /* nv04 gdirect */ - { 0x001f, false, nv04_graph_mthds_nv01_imageblit }, /* nv01 imageblit */ - { 0x005f, false, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 imageblit */ - { 0x0060, false, nv04_graph_mthds_nv04_iifc }, /* nv04 iifc */ - { 0x0064, false, NULL }, /* nv05 iifc */ - { 0x0021, false, nv04_graph_mthds_nv01_ifc }, /* nv01 ifc */ - { 0x0061, false, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 ifc */ - { 0x0065, false, NULL }, /* nv05 ifc */ - { 0x0036, false, nv04_graph_mthds_nv03_sifc }, /* nv03 sifc */ - { 0x0076, false, nv04_graph_mthds_nv04_sifc }, /* nv04 sifc */ - { 0x0066, false, NULL }, /* nv05 sifc */ - { 0x0037, false, nv04_graph_mthds_nv03_sifm }, /* nv03 sifm */ - { 0x0077, false, nv04_graph_mthds_nv04_sifm }, /* nv04 sifm */ - { 0x0030, false, NULL }, /* null */ - { 0x0042, false, NULL }, /* surf2d */ - { 0x0043, false, NULL }, /* rop */ - { 0x0012, false, NULL }, /* beta1 */ - { 0x0072, false, NULL }, /* beta4 */ - { 0x0019, false, NULL }, /* cliprect */ - { 0x0018, false, NULL }, /* nv01 pattern */ - { 0x0044, false, NULL }, /* nv04 pattern */ - { 0x0052, false, NULL }, /* swzsurf */ - { 0x0053, false, nv04_graph_mthds_surf3d }, /* surf3d */ - { 0x0048, false, nv04_graph_mthds_nv03_tex_tri }, /* nv03 tex_tri */ - { 0x0054, false, NULL }, /* tex_tri */ - { 0x0055, false, NULL }, /* multitex_tri */ - { 0x0017, false, NULL }, /* nv01 chroma */ - { 0x0057, false, NULL }, /* nv04 chroma */ - { 0x0058, false, NULL }, /* surf_dst */ - { 0x0059, false, NULL }, /* surf_src */ - { 0x005a, false, NULL }, /* surf_color */ - { 0x005b, false, NULL }, /* surf_zeta */ - { 0x001c, false, nv04_graph_mthds_nv01_shape }, /* nv01 line */ - { 0x005c, false, nv04_graph_mthds_nv04_shape }, /* nv04 line */ - { 0x001d, false, nv04_graph_mthds_nv01_shape }, /* nv01 tri */ - { 0x005d, false, nv04_graph_mthds_nv04_shape }, /* nv04 tri */ - { 0x001e, false, nv04_graph_mthds_nv01_shape }, /* nv01 rect */ - { 0x005e, false, nv04_graph_mthds_nv04_shape }, /* nv04 rect */ - { 0x506e, true, nv04_graph_mthds_sw }, + { 0x0038, NVOBJ_ENGINE_GR, NULL }, /* dvd subpicture */ + { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ + { 0x004b, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_gdirect }, /* nv03 gdirect */ + { 0x004a, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_gdirect }, /* nv04 gdirect */ + { 0x001f, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_imageblit }, /* nv01 imageblit */ + { 0x005f, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 imageblit */ + { 0x0060, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_iifc }, /* nv04 iifc */ + { 0x0064, NVOBJ_ENGINE_GR, NULL }, /* nv05 iifc */ + { 0x0021, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_ifc }, /* nv01 ifc */ + { 0x0061, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 ifc */ + { 0x0065, NVOBJ_ENGINE_GR, NULL }, /* nv05 ifc */ + { 0x0036, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_sifc }, /* nv03 sifc */ + { 0x0076, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_sifc }, /* nv04 sifc */ + { 0x0066, NVOBJ_ENGINE_GR, NULL }, /* nv05 sifc */ + { 0x0037, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_sifm }, /* nv03 sifm */ + { 0x0077, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_sifm }, /* nv04 sifm */ + { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ + { 0x0042, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ + { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ + { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ + { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ + { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ + { 0x0018, NVOBJ_ENGINE_GR, NULL }, /* nv01 pattern */ + { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* nv04 pattern */ + { 0x0052, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ + { 0x0053, NVOBJ_ENGINE_GR, nv04_graph_mthds_surf3d }, /* surf3d */ + { 0x0048, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_tex_tri }, /* nv03 tex_tri */ + { 0x0054, NVOBJ_ENGINE_GR, NULL }, /* tex_tri */ + { 0x0055, NVOBJ_ENGINE_GR, NULL }, /* multitex_tri */ + { 0x0017, NVOBJ_ENGINE_GR, NULL }, /* nv01 chroma */ + { 0x0057, NVOBJ_ENGINE_GR, NULL }, /* nv04 chroma */ + { 0x0058, NVOBJ_ENGINE_GR, NULL }, /* surf_dst */ + { 0x0059, NVOBJ_ENGINE_GR, NULL }, /* surf_src */ + { 0x005a, NVOBJ_ENGINE_GR, NULL }, /* surf_color */ + { 0x005b, NVOBJ_ENGINE_GR, NULL }, /* surf_zeta */ + { 0x001c, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_shape }, /* nv01 line */ + { 0x005c, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_shape }, /* nv04 line */ + { 0x001d, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_shape }, /* nv01 tri */ + { 0x005d, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_shape }, /* nv04 tri */ + { 0x001e, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_shape }, /* nv01 rect */ + { 0x005e, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_shape }, /* nv04 rect */ + { 0x506e, NVOBJ_ENGINE_SW, nv04_graph_mthds_sw }, {} }; diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index e3a87a64c164..375d63161d12 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -1075,25 +1075,25 @@ static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = { }; struct nouveau_pgraph_object_class nv10_graph_grclass[] = { - { 0x0030, false, NULL }, /* null */ - { 0x0039, false, NULL }, /* m2mf */ - { 0x004a, false, NULL }, /* gdirect */ - { 0x005f, false, NULL }, /* imageblit */ - { 0x009f, false, NULL }, /* imageblit (nv12) */ - { 0x008a, false, NULL }, /* ifc */ - { 0x0089, false, NULL }, /* sifm */ - { 0x0062, false, NULL }, /* surf2d */ - { 0x0043, false, NULL }, /* rop */ - { 0x0012, false, NULL }, /* beta1 */ - { 0x0072, false, NULL }, /* beta4 */ - { 0x0019, false, NULL }, /* cliprect */ - { 0x0044, false, NULL }, /* pattern */ - { 0x0052, false, NULL }, /* swzsurf */ - { 0x0093, false, NULL }, /* surf3d */ - { 0x0094, false, NULL }, /* tex_tri */ - { 0x0095, false, NULL }, /* multitex_tri */ - { 0x0056, false, NULL }, /* celcius (nv10) */ - { 0x0096, false, NULL }, /* celcius (nv11) */ - { 0x0099, false, nv17_graph_celsius_mthds }, /* celcius (nv17) */ + { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ + { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ + { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ + { 0x005f, NVOBJ_ENGINE_GR, NULL }, /* imageblit */ + { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ + { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ + { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ + { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ + { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ + { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ + { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ + { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ + { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ + { 0x0052, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ + { 0x0093, NVOBJ_ENGINE_GR, NULL }, /* surf3d */ + { 0x0094, NVOBJ_ENGINE_GR, NULL }, /* tex_tri */ + { 0x0095, NVOBJ_ENGINE_GR, NULL }, /* multitex_tri */ + { 0x0056, NVOBJ_ENGINE_GR, NULL }, /* celcius (nv10) */ + { 0x0096, NVOBJ_ENGINE_GR, NULL }, /* celcius (nv11) */ + { 0x0099, NVOBJ_ENGINE_GR, nv17_graph_celsius_mthds }, /* celcius (nv17) */ {} }; diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 8a0402012557..109418d72f93 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -757,45 +757,45 @@ nv30_graph_init(struct drm_device *dev) } struct nouveau_pgraph_object_class nv20_graph_grclass[] = { - { 0x0030, false, NULL }, /* null */ - { 0x0039, false, NULL }, /* m2mf */ - { 0x004a, false, NULL }, /* gdirect */ - { 0x009f, false, NULL }, /* imageblit (nv12) */ - { 0x008a, false, NULL }, /* ifc */ - { 0x0089, false, NULL }, /* sifm */ - { 0x0062, false, NULL }, /* surf2d */ - { 0x0043, false, NULL }, /* rop */ - { 0x0012, false, NULL }, /* beta1 */ - { 0x0072, false, NULL }, /* beta4 */ - { 0x0019, false, NULL }, /* cliprect */ - { 0x0044, false, NULL }, /* pattern */ - { 0x009e, false, NULL }, /* swzsurf */ - { 0x0096, false, NULL }, /* celcius */ - { 0x0097, false, NULL }, /* kelvin (nv20) */ - { 0x0597, false, NULL }, /* kelvin (nv25) */ + { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ + { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ + { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ + { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ + { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ + { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ + { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ + { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ + { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ + { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ + { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ + { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ + { 0x009e, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ + { 0x0096, NVOBJ_ENGINE_GR, NULL }, /* celcius */ + { 0x0097, NVOBJ_ENGINE_GR, NULL }, /* kelvin (nv20) */ + { 0x0597, NVOBJ_ENGINE_GR, NULL }, /* kelvin (nv25) */ {} }; struct nouveau_pgraph_object_class nv30_graph_grclass[] = { - { 0x0030, false, NULL }, /* null */ - { 0x0039, false, NULL }, /* m2mf */ - { 0x004a, false, NULL }, /* gdirect */ - { 0x009f, false, NULL }, /* imageblit (nv12) */ - { 0x008a, false, NULL }, /* ifc */ - { 0x038a, false, NULL }, /* ifc (nv30) */ - { 0x0089, false, NULL }, /* sifm */ - { 0x0389, false, NULL }, /* sifm (nv30) */ - { 0x0062, false, NULL }, /* surf2d */ - { 0x0362, false, NULL }, /* surf2d (nv30) */ - { 0x0043, false, NULL }, /* rop */ - { 0x0012, false, NULL }, /* beta1 */ - { 0x0072, false, NULL }, /* beta4 */ - { 0x0019, false, NULL }, /* cliprect */ - { 0x0044, false, NULL }, /* pattern */ - { 0x039e, false, NULL }, /* swzsurf */ - { 0x0397, false, NULL }, /* rankine (nv30) */ - { 0x0497, false, NULL }, /* rankine (nv35) */ - { 0x0697, false, NULL }, /* rankine (nv34) */ + { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ + { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ + { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ + { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ + { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ + { 0x038a, NVOBJ_ENGINE_GR, NULL }, /* ifc (nv30) */ + { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ + { 0x0389, NVOBJ_ENGINE_GR, NULL }, /* sifm (nv30) */ + { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ + { 0x0362, NVOBJ_ENGINE_GR, NULL }, /* surf2d (nv30) */ + { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ + { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ + { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ + { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ + { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ + { 0x039e, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ + { 0x0397, NVOBJ_ENGINE_GR, NULL }, /* rankine (nv30) */ + { 0x0497, NVOBJ_ENGINE_GR, NULL }, /* rankine (nv35) */ + { 0x0697, NVOBJ_ENGINE_GR, NULL }, /* rankine (nv34) */ {} }; diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 70d97cde49d0..cd47760b2d0a 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -409,23 +409,23 @@ void nv40_graph_takedown(struct drm_device *dev) } struct nouveau_pgraph_object_class nv40_graph_grclass[] = { - { 0x0030, false, NULL }, /* null */ - { 0x0039, false, NULL }, /* m2mf */ - { 0x004a, false, NULL }, /* gdirect */ - { 0x009f, false, NULL }, /* imageblit (nv12) */ - { 0x008a, false, NULL }, /* ifc */ - { 0x0089, false, NULL }, /* sifm */ - { 0x3089, false, NULL }, /* sifm (nv40) */ - { 0x0062, false, NULL }, /* surf2d */ - { 0x3062, false, NULL }, /* surf2d (nv40) */ - { 0x0043, false, NULL }, /* rop */ - { 0x0012, false, NULL }, /* beta1 */ - { 0x0072, false, NULL }, /* beta4 */ - { 0x0019, false, NULL }, /* cliprect */ - { 0x0044, false, NULL }, /* pattern */ - { 0x309e, false, NULL }, /* swzsurf */ - { 0x4097, false, NULL }, /* curie (nv40) */ - { 0x4497, false, NULL }, /* curie (nv44) */ + { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ + { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ + { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ + { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ + { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ + { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ + { 0x3089, NVOBJ_ENGINE_GR, NULL }, /* sifm (nv40) */ + { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ + { 0x3062, NVOBJ_ENGINE_GR, NULL }, /* surf2d (nv40) */ + { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ + { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ + { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ + { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ + { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ + { 0x309e, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ + { 0x4097, NVOBJ_ENGINE_GR, NULL }, /* curie (nv40) */ + { 0x4497, NVOBJ_ENGINE_GR, NULL }, /* curie (nv44) */ {} }; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index dcc9175fb794..01a598917e3c 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -401,16 +401,16 @@ static struct nouveau_pgraph_object_method nv50_graph_nvsw_methods[] = { }; struct nouveau_pgraph_object_class nv50_graph_grclass[] = { - { 0x506e, true, nv50_graph_nvsw_methods }, /* nvsw */ - { 0x0030, false, NULL }, /* null */ - { 0x5039, false, NULL }, /* m2mf */ - { 0x502d, false, NULL }, /* 2d */ - { 0x50c0, false, NULL }, /* compute */ - { 0x85c0, false, NULL }, /* compute (nva3, nva5, nva8) */ - { 0x5097, false, NULL }, /* tesla (nv50) */ - { 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */ - { 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */ - { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ + { 0x506e, NVOBJ_ENGINE_SW, nv50_graph_nvsw_methods }, /* nvsw */ + { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ + { 0x5039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ + { 0x502d, NVOBJ_ENGINE_GR, NULL }, /* 2d */ + { 0x50c0, NVOBJ_ENGINE_GR, NULL }, /* compute */ + { 0x85c0, NVOBJ_ENGINE_GR, NULL }, /* compute (nva3, nva5, nva8) */ + { 0x5097, NVOBJ_ENGINE_GR, NULL }, /* tesla (nv50) */ + { 0x8297, NVOBJ_ENGINE_GR, NULL }, /* tesla (nv8x/nv9x) */ + { 0x8397, NVOBJ_ENGINE_GR, NULL }, /* tesla (nva0, nvaa, nvac) */ + { 0x8597, NVOBJ_ENGINE_GR, NULL }, /* tesla (nva3, nva5, nva8) */ {} }; -- cgit v1.2.3 From a6a1a38075661bec189f2bad7912f8861e6ce357 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 19:57:34 +1000 Subject: drm/nouveau: use object class structs more extensively The structs themselves, as well as the non-sw object creation function are probably very misnamed now. That's a problem for later :) Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 - drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- drivers/gpu/drm/nouveau/nouveau_object.c | 97 ++++++++++++++++---------------- drivers/gpu/drm/nouveau/nv10_graph.c | 1 + drivers/gpu/drm/nouveau/nv20_graph.c | 2 + drivers/gpu/drm/nouveau/nv40_graph.c | 1 + 6 files changed, 53 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 2fdc26655ca1..2099f04c0b0a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -842,8 +842,6 @@ extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, uint32_t *o_ret); extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, struct nouveau_gpuobj **); -extern int nouveau_gpuobj_sw_new(struct nouveau_channel *, int class, - struct nouveau_gpuobj **); extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index f70bec835f5f..75ce1b45d8a4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -437,7 +437,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) int ret; /* Create an NV_SW object for various sync purposes */ - ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj); + ret = nouveau_gpuobj_gr_new(chan, NV_SW, &obj); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 70ffd7530503..9c26da4cdc00 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -495,23 +495,67 @@ nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan, entry[5]: set to 0? */ +static int +nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, + struct nouveau_gpuobj **gpuobj_ret) +{ + struct drm_nouveau_private *dev_priv; + struct nouveau_gpuobj *gpuobj; + + if (!chan || !gpuobj_ret || *gpuobj_ret != NULL) + return -EINVAL; + dev_priv = chan->dev->dev_private; + + gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); + if (!gpuobj) + return -ENOMEM; + gpuobj->dev = chan->dev; + gpuobj->engine = NVOBJ_ENGINE_SW; + gpuobj->class = class; + kref_init(&gpuobj->refcount); + gpuobj->cinst = 0x40; + + spin_lock(&dev_priv->ramin_lock); + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + spin_unlock(&dev_priv->ramin_lock); + *gpuobj_ret = gpuobj; + return 0; +} + int nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj) { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_pgraph_object_class *grc; struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class); + grc = pgraph->grclass; + while (grc->id) { + if (grc->id == class) + break; + grc++; + } + + if (!grc->id) { + NV_ERROR(dev, "illegal object class: 0x%x\n", class); + return -EINVAL; + } + + if (grc->engine == NVOBJ_ENGINE_SW) + return nouveau_gpuobj_sw_new(chan, class, gpuobj); + ret = nouveau_gpuobj_new(dev, chan, nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, gpuobj); if (ret) { - NV_ERROR(dev, "Error creating gpuobj: %d\n", ret); + NV_ERROR(dev, "error creating gpuobj: %d\n", ret); return ret; } @@ -541,38 +585,11 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, } dev_priv->engine.instmem.flush(dev); - (*gpuobj)->engine = NVOBJ_ENGINE_GR; + (*gpuobj)->engine = grc->engine; (*gpuobj)->class = class; return 0; } -int -nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, - struct nouveau_gpuobj **gpuobj_ret) -{ - struct drm_nouveau_private *dev_priv; - struct nouveau_gpuobj *gpuobj; - - if (!chan || !gpuobj_ret || *gpuobj_ret != NULL) - return -EINVAL; - dev_priv = chan->dev->dev_private; - - gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); - if (!gpuobj) - return -ENOMEM; - gpuobj->dev = chan->dev; - gpuobj->engine = NVOBJ_ENGINE_SW; - gpuobj->class = class; - kref_init(&gpuobj->refcount); - gpuobj->cinst = 0x40; - - spin_lock(&dev_priv->ramin_lock); - list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); - spin_unlock(&dev_priv->ramin_lock); - *gpuobj_ret = gpuobj; - return 0; -} - static int nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) { @@ -868,10 +885,7 @@ nouveau_gpuobj_resume(struct drm_device *dev) int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_grobj_alloc *init = data; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - struct nouveau_pgraph_object_class *grc; struct nouveau_gpuobj *gr = NULL; struct nouveau_channel *chan; int ret; @@ -879,18 +893,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, if (init->handle == ~0) return -EINVAL; - grc = pgraph->grclass; - while (grc->id) { - if (grc->id == init->class) - break; - grc++; - } - - if (!grc->id) { - NV_ERROR(dev, "Illegal object class: 0x%x\n", init->class); - return -EPERM; - } - chan = nouveau_channel_get(dev, file_priv, init->channel); if (IS_ERR(chan)) return PTR_ERR(chan); @@ -900,10 +902,7 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, goto out; } - if (grc->engine != NVOBJ_ENGINE_SW) - ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr); - else - ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr); + ret = nouveau_gpuobj_gr_new(chan, init->class, &gr); if (ret) { NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", ret, init->channel, init->handle); diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 375d63161d12..ed31a622889e 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -1075,6 +1075,7 @@ static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = { }; struct nouveau_pgraph_object_class nv10_graph_grclass[] = { + { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 109418d72f93..872f8d059694 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -757,6 +757,7 @@ nv30_graph_init(struct drm_device *dev) } struct nouveau_pgraph_object_class nv20_graph_grclass[] = { + { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ @@ -777,6 +778,7 @@ struct nouveau_pgraph_object_class nv20_graph_grclass[] = { }; struct nouveau_pgraph_object_class nv30_graph_grclass[] = { + { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index cd47760b2d0a..70d957895cea 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -409,6 +409,7 @@ void nv40_graph_takedown(struct drm_device *dev) } struct nouveau_pgraph_object_class nv40_graph_grclass[] = { + { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ -- cgit v1.2.3 From b8c157d3a9a13871742c8a8d3d4598c3791ed5f5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 20 Oct 2010 10:39:35 +1000 Subject: drm/nouveau: only expose the object classes that are supported by the chipset We previously added all the available classes for the entire generation, even though the objects wouldn't work on the hardware. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 38 +-- drivers/gpu/drm/nouveau/nouveau_irq.c | 36 +-- drivers/gpu/drm/nouveau/nouveau_object.c | 112 ++++++- drivers/gpu/drm/nouveau/nouveau_state.c | 7 - drivers/gpu/drm/nouveau/nv04_graph.c | 530 ++++++++++++++++++------------- drivers/gpu/drm/nouveau/nv10_graph.c | 92 +++--- drivers/gpu/drm/nouveau/nv20_graph.c | 131 +++++--- drivers/gpu/drm/nouveau/nv40_graph.c | 63 ++-- drivers/gpu/drm/nouveau/nv50_graph.c | 91 ++++-- 9 files changed, 667 insertions(+), 433 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 2099f04c0b0a..3fb87995446b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -316,21 +316,9 @@ struct nouveau_fifo_engine { void (*tlb_flush)(struct drm_device *dev); }; -struct nouveau_pgraph_object_method { - int id; - int (*exec)(struct nouveau_channel *chan, int grclass, int mthd, - uint32_t data); -}; - -struct nouveau_pgraph_object_class { - int id; - u32 engine; - struct nouveau_pgraph_object_method *methods; -}; - struct nouveau_pgraph_engine { - struct nouveau_pgraph_object_class *grclass; bool accel_blocked; + bool registered; int grctx_size; /* NV2x/NV3x context table (0x400780) */ @@ -584,6 +572,7 @@ struct drm_nouveau_private { bool ramin_available; struct drm_mm ramin_heap; struct list_head gpuobj_list; + struct list_head classes; struct nouveau_bo *vga_ram; @@ -816,12 +805,29 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan, struct nouveau_channel **pchan); /* nouveau_object.c */ +#define NVOBJ_CLASS(d,c,e) do { \ + int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \ + if (ret) \ + return ret; \ +} while(0) + +#define NVOBJ_MTHD(d,c,m,e) do { \ + int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e)); \ + if (ret) \ + return ret; \ +} while(0) + extern int nouveau_gpuobj_early_init(struct drm_device *); extern int nouveau_gpuobj_init(struct drm_device *); extern void nouveau_gpuobj_takedown(struct drm_device *); extern int nouveau_gpuobj_suspend(struct drm_device *dev); extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev); extern void nouveau_gpuobj_resume(struct drm_device *dev); +extern int nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng); +extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd, + int (*exec)(struct nouveau_channel *, + u32 class, u32 mthd, u32 data)); +extern int nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32); extern int nouveau_gpuobj_channel_init(struct nouveau_channel *, uint32_t vram_h, uint32_t tt_h); extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); @@ -1038,7 +1044,6 @@ extern int nvc0_fifo_load_context(struct nouveau_channel *); extern int nvc0_fifo_unload_context(struct drm_device *); /* nv04_graph.c */ -extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; extern int nv04_graph_init(struct drm_device *); extern void nv04_graph_takedown(struct drm_device *); extern void nv04_graph_fifo_access(struct drm_device *, bool); @@ -1050,7 +1055,6 @@ extern int nv04_graph_unload_context(struct drm_device *); extern void nv04_graph_context_switch(struct drm_device *); /* nv10_graph.c */ -extern struct nouveau_pgraph_object_class nv10_graph_grclass[]; extern int nv10_graph_init(struct drm_device *); extern void nv10_graph_takedown(struct drm_device *); extern struct nouveau_channel *nv10_graph_channel(struct drm_device *); @@ -1063,8 +1067,6 @@ extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); /* nv20_graph.c */ -extern struct nouveau_pgraph_object_class nv20_graph_grclass[]; -extern struct nouveau_pgraph_object_class nv30_graph_grclass[]; extern int nv20_graph_create_context(struct nouveau_channel *); extern void nv20_graph_destroy_context(struct nouveau_channel *); extern int nv20_graph_load_context(struct nouveau_channel *); @@ -1076,7 +1078,6 @@ extern void nv20_graph_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); /* nv40_graph.c */ -extern struct nouveau_pgraph_object_class nv40_graph_grclass[]; extern int nv40_graph_init(struct drm_device *); extern void nv40_graph_takedown(struct drm_device *); extern struct nouveau_channel *nv40_graph_channel(struct drm_device *); @@ -1089,7 +1090,6 @@ extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); /* nv50_graph.c */ -extern struct nouveau_pgraph_object_class nv50_graph_grclass[]; extern int nv50_graph_init(struct drm_device *); extern void nv50_graph_takedown(struct drm_device *); extern void nv50_graph_fifo_access(struct drm_device *, bool); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index c5e37bc17192..f09151d17297 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -80,33 +80,6 @@ nouveau_irq_uninstall(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); } -static int -nouveau_call_method(struct nouveau_channel *chan, int class, int mthd, int data) -{ - struct drm_nouveau_private *dev_priv = chan->dev->dev_private; - struct nouveau_pgraph_object_method *grm; - struct nouveau_pgraph_object_class *grc; - - grc = dev_priv->engine.graph.grclass; - while (grc->id) { - if (grc->id == class) - break; - grc++; - } - - if (grc->id != class || !grc->methods) - return -ENOENT; - - grm = grc->methods; - while (grm->id) { - if (grm->id == mthd) - return grm->exec(chan, class, mthd, data); - grm++; - } - - return -ENOENT; -} - static bool nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) { @@ -142,8 +115,8 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) break; - if (!nouveau_call_method(chan, chan->sw_subchannel[subc], - mthd, data)) + if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc], + mthd, data)) handled = true; break; } @@ -541,6 +514,7 @@ nouveau_pgraph_intr_swmthd(struct drm_device *dev, struct nouveau_pgraph_trap *trap) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; unsigned long flags; int ret = -EINVAL; @@ -548,8 +522,8 @@ nouveau_pgraph_intr_swmthd(struct drm_device *dev, if (trap->channel > 0 && trap->channel < dev_priv->engine.fifo.channels && dev_priv->channels.ptr[trap->channel]) { - ret = nouveau_call_method(dev_priv->channels.ptr[trap->channel], - trap->class, trap->mthd, trap->data); + chan = dev_priv->channels.ptr[trap->channel]; + ret = nouveau_gpuobj_mthd_call(chan, trap->class, trap->mthd, trap->data); } spin_unlock_irqrestore(&dev_priv->channels.lock, flags); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 9c26da4cdc00..6226beb3613d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -36,6 +36,83 @@ #include "nouveau_drm.h" #include "nouveau_ramht.h" +struct nouveau_gpuobj_method { + struct list_head head; + u32 mthd; + int (*exec)(struct nouveau_channel *, u32 class, u32 mthd, u32 data); +}; + +struct nouveau_gpuobj_class { + struct list_head head; + struct list_head methods; + u32 id; + u32 engine; +}; + +int +nouveau_gpuobj_class_new(struct drm_device *dev, u32 class, u32 engine) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj_class *oc; + + oc = kzalloc(sizeof(*oc), GFP_KERNEL); + if (!oc) + return -ENOMEM; + + INIT_LIST_HEAD(&oc->methods); + oc->id = class; + oc->engine = engine; + list_add(&oc->head, &dev_priv->classes); + return 0; +} + +int +nouveau_gpuobj_mthd_new(struct drm_device *dev, u32 class, u32 mthd, + int (*exec)(struct nouveau_channel *, u32, u32, u32)) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj_method *om; + struct nouveau_gpuobj_class *oc; + + list_for_each_entry(oc, &dev_priv->classes, head) { + if (oc->id == class) + goto found; + } + + return -EINVAL; + +found: + om = kzalloc(sizeof(*om), GFP_KERNEL); + if (!om) + return -ENOMEM; + + om->mthd = mthd; + om->exec = exec; + list_add(&om->head, &oc->methods); + return 0; +} + +int +nouveau_gpuobj_mthd_call(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nouveau_gpuobj_method *om; + struct nouveau_gpuobj_class *oc; + + list_for_each_entry(oc, &dev_priv->classes, head) { + if (oc->id != class) + continue; + + list_for_each_entry(om, &oc->methods, head) { + if (om->mthd == mthd) + return om->exec(chan, class, mthd, data); + } + } + + return -ENOENT; +} + /* NVidia uses context objects to drive drawing operations. Context objects can be selected into 8 subchannels in the FIFO, @@ -205,9 +282,20 @@ void nouveau_gpuobj_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj_method *om, *tm; + struct nouveau_gpuobj_class *oc, *tc; NV_DEBUG(dev, "\n"); + list_for_each_entry_safe(oc, tc, &dev_priv->classes, head) { + list_for_each_entry_safe(om, tm, &oc->methods, head) { + list_del(&om->head); + kfree(om); + } + list_del(&oc->head); + kfree(oc); + } + BUG_ON(!list_empty(&dev_priv->gpuobj_list)); } @@ -527,26 +615,22 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - struct nouveau_pgraph_object_class *grc; struct drm_device *dev = chan->dev; + struct nouveau_gpuobj_class *oc; int ret; NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class); - grc = pgraph->grclass; - while (grc->id) { - if (grc->id == class) - break; - grc++; + list_for_each_entry(oc, &dev_priv->classes, head) { + if (oc->id == class) + goto found; } - if (!grc->id) { - NV_ERROR(dev, "illegal object class: 0x%x\n", class); - return -EINVAL; - } + NV_ERROR(dev, "illegal object class: 0x%x\n", class); + return -EINVAL; - if (grc->engine == NVOBJ_ENGINE_SW) +found: + if (oc->engine == NVOBJ_ENGINE_SW) return nouveau_gpuobj_sw_new(chan, class, gpuobj); ret = nouveau_gpuobj_new(dev, chan, @@ -585,8 +669,8 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, } dev_priv->engine.instmem.flush(dev); - (*gpuobj)->engine = grc->engine; - (*gpuobj)->class = class; + (*gpuobj)->engine = oc->engine; + (*gpuobj)->class = oc->id; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 82b58188398b..be28754ffd50 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -65,7 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv04_fb_init; engine->fb.takedown = nv04_fb_takedown; - engine->graph.grclass = nv04_graph_grclass; engine->graph.init = nv04_graph_init; engine->graph.takedown = nv04_graph_takedown; engine->graph.fifo_access = nv04_graph_fifo_access; @@ -118,7 +117,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; engine->fb.set_region_tiling = nv10_fb_set_region_tiling; - engine->graph.grclass = nv10_graph_grclass; engine->graph.init = nv10_graph_init; engine->graph.takedown = nv10_graph_takedown; engine->graph.channel = nv10_graph_channel; @@ -172,7 +170,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; engine->fb.set_region_tiling = nv10_fb_set_region_tiling; - engine->graph.grclass = nv20_graph_grclass; engine->graph.init = nv20_graph_init; engine->graph.takedown = nv20_graph_takedown; engine->graph.channel = nv10_graph_channel; @@ -226,7 +223,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fb.init = nv30_fb_init; engine->fb.takedown = nv30_fb_takedown; engine->fb.set_region_tiling = nv10_fb_set_region_tiling; - engine->graph.grclass = nv30_graph_grclass; engine->graph.init = nv30_graph_init; engine->graph.takedown = nv20_graph_takedown; engine->graph.fifo_access = nv04_graph_fifo_access; @@ -283,7 +279,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fb.init = nv40_fb_init; engine->fb.takedown = nv40_fb_takedown; engine->fb.set_region_tiling = nv40_fb_set_region_tiling; - engine->graph.grclass = nv40_graph_grclass; engine->graph.init = nv40_graph_init; engine->graph.takedown = nv40_graph_takedown; engine->graph.fifo_access = nv04_graph_fifo_access; @@ -345,7 +340,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv50_fb_init; engine->fb.takedown = nv50_fb_takedown; - engine->graph.grclass = nv50_graph_grclass; engine->graph.init = nv50_graph_init; engine->graph.takedown = nv50_graph_takedown; engine->graph.fifo_access = nv50_graph_fifo_access; @@ -424,7 +418,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nvc0_fb_init; engine->fb.takedown = nvc0_fb_takedown; - engine->graph.grclass = NULL; //nvc0_graph_grclass; engine->graph.init = nvc0_graph_init; engine->graph.takedown = nvc0_graph_takedown; engine->graph.fifo_access = nvc0_graph_fifo_access; diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 5d8ab1b6b04a..81aba097ef95 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -27,6 +27,8 @@ #include "nouveau_drm.h" #include "nouveau_drv.h" +static int nv04_graph_register(struct drm_device *dev); + static uint32_t nv04_graph_ctx_regs[] = { 0x0040053c, 0x00400544, @@ -483,12 +485,17 @@ int nv04_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t tmp; + int ret; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + ret = nv04_graph_register(dev); + if (ret) + return ret; + /* Enable PGRAPH interrupts */ nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -539,8 +546,8 @@ nv04_graph_fifo_access(struct drm_device *dev, bool enabled) } static int -nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_set_ref(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { atomic_set(&chan->fence.last_sequence_irq, data); return 0; @@ -621,12 +628,12 @@ nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass, */ static void -nv04_graph_set_ctx1(struct nouveau_channel *chan, uint32_t mask, uint32_t value) +nv04_graph_set_ctx1(struct nouveau_channel *chan, u32 mask, u32 value) { struct drm_device *dev = chan->dev; - uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; + u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; - uint32_t tmp; + u32 tmp; tmp = nv_ri32(dev, instance); tmp &= ~mask; @@ -638,11 +645,11 @@ nv04_graph_set_ctx1(struct nouveau_channel *chan, uint32_t mask, uint32_t value) } static void -nv04_graph_set_ctx_val(struct nouveau_channel *chan, uint32_t mask, uint32_t value) +nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value) { struct drm_device *dev = chan->dev; - uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; - uint32_t tmp, ctx1; + u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; + u32 tmp, ctx1; int class, op, valid = 1; ctx1 = nv_ri32(dev, instance); @@ -687,13 +694,13 @@ nv04_graph_set_ctx_val(struct nouveau_channel *chan, uint32_t mask, uint32_t val } static int -nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_set_operation(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { if (data > 5) return 1; /* Old versions of the objects only accept first three operations. */ - if (data > 2 && grclass < 0x40) + if (data > 2 && class < 0x40) return 1; nv04_graph_set_ctx1(chan, 0x00038000, data << 15); /* changing operation changes set of objects needed for validation */ @@ -702,8 +709,8 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { uint32_t min = data & 0xffff, max; uint32_t w = data >> 16; @@ -721,8 +728,8 @@ nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { uint32_t min = data & 0xffff, max; uint32_t w = data >> 16; @@ -740,8 +747,8 @@ nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -757,8 +764,8 @@ nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -778,8 +785,8 @@ nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -793,8 +800,8 @@ nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -808,8 +815,8 @@ nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -823,8 +830,8 @@ nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -838,8 +845,8 @@ nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -853,8 +860,8 @@ nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -868,8 +875,8 @@ nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -883,8 +890,8 @@ nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -898,8 +905,8 @@ nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -913,8 +920,8 @@ nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -928,8 +935,8 @@ nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, int grclass, } static int -nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { switch (nv_ri32(chan->dev, data << 4) & 0xff) { case 0x30: @@ -945,194 +952,259 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, int grclass, return 1; } -static struct nouveau_pgraph_object_method nv04_graph_mthds_sw[] = { - { 0x0150, nv04_graph_mthd_set_ref }, - {} -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_gdirect[] = { - { 0x0184, nv04_graph_mthd_bind_nv01_patt }, - { 0x0188, nv04_graph_mthd_bind_rop }, - { 0x018c, nv04_graph_mthd_bind_beta1 }, - { 0x0190, nv04_graph_mthd_bind_surf_dst }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_gdirect[] = { - { 0x0188, nv04_graph_mthd_bind_nv04_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_beta4 }, - { 0x0198, nv04_graph_mthd_bind_surf2d }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_imageblit[] = { - { 0x0184, nv04_graph_mthd_bind_chroma }, - { 0x0188, nv04_graph_mthd_bind_clip }, - { 0x018c, nv04_graph_mthd_bind_nv01_patt }, - { 0x0190, nv04_graph_mthd_bind_rop }, - { 0x0194, nv04_graph_mthd_bind_beta1 }, - { 0x0198, nv04_graph_mthd_bind_surf_dst }, - { 0x019c, nv04_graph_mthd_bind_surf_src }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_imageblit_ifc[] = { - { 0x0184, nv04_graph_mthd_bind_chroma }, - { 0x0188, nv04_graph_mthd_bind_clip }, - { 0x018c, nv04_graph_mthd_bind_nv04_patt }, - { 0x0190, nv04_graph_mthd_bind_rop }, - { 0x0194, nv04_graph_mthd_bind_beta1 }, - { 0x0198, nv04_graph_mthd_bind_beta4 }, - { 0x019c, nv04_graph_mthd_bind_surf2d }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_iifc[] = { - { 0x0188, nv04_graph_mthd_bind_chroma }, - { 0x018c, nv04_graph_mthd_bind_clip }, - { 0x0190, nv04_graph_mthd_bind_nv04_patt }, - { 0x0194, nv04_graph_mthd_bind_rop }, - { 0x0198, nv04_graph_mthd_bind_beta1 }, - { 0x019c, nv04_graph_mthd_bind_beta4 }, - { 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf }, - { 0x03e4, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_ifc[] = { - { 0x0184, nv04_graph_mthd_bind_chroma }, - { 0x0188, nv04_graph_mthd_bind_clip }, - { 0x018c, nv04_graph_mthd_bind_nv01_patt }, - { 0x0190, nv04_graph_mthd_bind_rop }, - { 0x0194, nv04_graph_mthd_bind_beta1 }, - { 0x0198, nv04_graph_mthd_bind_surf_dst }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_sifc[] = { - { 0x0184, nv04_graph_mthd_bind_chroma }, - { 0x0188, nv04_graph_mthd_bind_nv01_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_surf_dst }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_sifc[] = { - { 0x0184, nv04_graph_mthd_bind_chroma }, - { 0x0188, nv04_graph_mthd_bind_nv04_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_beta4 }, - { 0x0198, nv04_graph_mthd_bind_surf2d }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_sifm[] = { - { 0x0188, nv04_graph_mthd_bind_nv01_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_surf_dst }, - { 0x0304, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_sifm[] = { - { 0x0188, nv04_graph_mthd_bind_nv04_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_beta4 }, - { 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf }, - { 0x0304, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_shape[] = { - { 0x0184, nv04_graph_mthd_bind_clip }, - { 0x0188, nv04_graph_mthd_bind_nv01_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_surf_dst }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_shape[] = { - { 0x0184, nv04_graph_mthd_bind_clip }, - { 0x0188, nv04_graph_mthd_bind_nv04_patt }, - { 0x018c, nv04_graph_mthd_bind_rop }, - { 0x0190, nv04_graph_mthd_bind_beta1 }, - { 0x0194, nv04_graph_mthd_bind_beta4 }, - { 0x0198, nv04_graph_mthd_bind_surf2d }, - { 0x02fc, nv04_graph_mthd_set_operation }, - {}, -}; - -static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_tex_tri[] = { - { 0x0188, nv04_graph_mthd_bind_clip }, - { 0x018c, nv04_graph_mthd_bind_surf_color }, - { 0x0190, nv04_graph_mthd_bind_surf_zeta }, - {}, -}; +static int +nv04_graph_register(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; -static struct nouveau_pgraph_object_method nv04_graph_mthds_surf3d[] = { - { 0x02f8, nv04_graph_mthd_surf3d_clip_h }, - { 0x02fc, nv04_graph_mthd_surf3d_clip_v }, - {}, -}; + if (dev_priv->engine.graph.registered) + return 0; -struct nouveau_pgraph_object_class nv04_graph_grclass[] = { - { 0x0038, NVOBJ_ENGINE_GR, NULL }, /* dvd subpicture */ - { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ - { 0x004b, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_gdirect }, /* nv03 gdirect */ - { 0x004a, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_gdirect }, /* nv04 gdirect */ - { 0x001f, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_imageblit }, /* nv01 imageblit */ - { 0x005f, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 imageblit */ - { 0x0060, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_iifc }, /* nv04 iifc */ - { 0x0064, NVOBJ_ENGINE_GR, NULL }, /* nv05 iifc */ - { 0x0021, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_ifc }, /* nv01 ifc */ - { 0x0061, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 ifc */ - { 0x0065, NVOBJ_ENGINE_GR, NULL }, /* nv05 ifc */ - { 0x0036, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_sifc }, /* nv03 sifc */ - { 0x0076, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_sifc }, /* nv04 sifc */ - { 0x0066, NVOBJ_ENGINE_GR, NULL }, /* nv05 sifc */ - { 0x0037, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_sifm }, /* nv03 sifm */ - { 0x0077, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_sifm }, /* nv04 sifm */ - { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ - { 0x0042, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ - { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ - { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ - { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ - { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ - { 0x0018, NVOBJ_ENGINE_GR, NULL }, /* nv01 pattern */ - { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* nv04 pattern */ - { 0x0052, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ - { 0x0053, NVOBJ_ENGINE_GR, nv04_graph_mthds_surf3d }, /* surf3d */ - { 0x0048, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv03_tex_tri }, /* nv03 tex_tri */ - { 0x0054, NVOBJ_ENGINE_GR, NULL }, /* tex_tri */ - { 0x0055, NVOBJ_ENGINE_GR, NULL }, /* multitex_tri */ - { 0x0017, NVOBJ_ENGINE_GR, NULL }, /* nv01 chroma */ - { 0x0057, NVOBJ_ENGINE_GR, NULL }, /* nv04 chroma */ - { 0x0058, NVOBJ_ENGINE_GR, NULL }, /* surf_dst */ - { 0x0059, NVOBJ_ENGINE_GR, NULL }, /* surf_src */ - { 0x005a, NVOBJ_ENGINE_GR, NULL }, /* surf_color */ - { 0x005b, NVOBJ_ENGINE_GR, NULL }, /* surf_zeta */ - { 0x001c, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_shape }, /* nv01 line */ - { 0x005c, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_shape }, /* nv04 line */ - { 0x001d, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_shape }, /* nv01 tri */ - { 0x005d, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_shape }, /* nv04 tri */ - { 0x001e, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv01_shape }, /* nv01 rect */ - { 0x005e, NVOBJ_ENGINE_GR, nv04_graph_mthds_nv04_shape }, /* nv04 rect */ - { 0x506e, NVOBJ_ENGINE_SW, nv04_graph_mthds_sw }, - {} + /* dvd subpicture */ + NVOBJ_CLASS(dev, 0x0038, GR); + + /* m2mf */ + NVOBJ_CLASS(dev, 0x0039, GR); + + /* nv03 gdirect */ + NVOBJ_CLASS(dev, 0x004b, GR); + NVOBJ_MTHD (dev, 0x004b, 0x0184, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x004b, 0x0188, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x004b, 0x018c, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x004b, 0x0190, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x004b, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 gdirect */ + NVOBJ_CLASS(dev, 0x004a, GR); + NVOBJ_MTHD (dev, 0x004a, 0x0188, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x004a, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x004a, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x004a, 0x0194, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x004a, 0x0198, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x004a, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv01 imageblit */ + NVOBJ_CLASS(dev, 0x001f, GR); + NVOBJ_MTHD (dev, 0x001f, 0x0184, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x001f, 0x0188, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x001f, 0x018c, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x001f, 0x0190, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x001f, 0x0194, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x001f, 0x0198, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x001f, 0x019c, nv04_graph_mthd_bind_surf_src); + NVOBJ_MTHD (dev, 0x001f, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 imageblit */ + NVOBJ_CLASS(dev, 0x005f, GR); + NVOBJ_MTHD (dev, 0x005f, 0x0184, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x005f, 0x0188, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x005f, 0x018c, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x005f, 0x0190, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x005f, 0x0194, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x005f, 0x0198, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x005f, 0x019c, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x005f, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 iifc */ + NVOBJ_CLASS(dev, 0x0060, GR); + NVOBJ_MTHD (dev, 0x0060, 0x0188, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x0060, 0x018c, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x0060, 0x0190, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x0060, 0x0194, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0060, 0x0198, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0060, 0x019c, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x0060, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf); + NVOBJ_MTHD (dev, 0x0060, 0x03e4, nv04_graph_mthd_set_operation); + + /* nv05 iifc */ + NVOBJ_CLASS(dev, 0x0064, GR); + + /* nv01 ifc */ + NVOBJ_CLASS(dev, 0x0021, GR); + NVOBJ_MTHD (dev, 0x0021, 0x0184, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x0021, 0x0188, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x0021, 0x018c, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x0021, 0x0190, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0021, 0x0194, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0021, 0x0198, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x0021, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 ifc */ + NVOBJ_CLASS(dev, 0x0061, GR); + NVOBJ_MTHD (dev, 0x0061, 0x0184, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x0061, 0x0188, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x0061, 0x018c, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x0061, 0x0190, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0061, 0x0194, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0061, 0x0198, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x0061, 0x019c, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x0061, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv05 ifc */ + NVOBJ_CLASS(dev, 0x0065, GR); + + /* nv03 sifc */ + NVOBJ_CLASS(dev, 0x0036, GR); + NVOBJ_MTHD (dev, 0x0036, 0x0184, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x0036, 0x0188, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x0036, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0036, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0036, 0x0194, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x0036, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 sifc */ + NVOBJ_CLASS(dev, 0x0076, GR); + NVOBJ_MTHD (dev, 0x0076, 0x0184, nv04_graph_mthd_bind_chroma); + NVOBJ_MTHD (dev, 0x0076, 0x0188, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x0076, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0076, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0076, 0x0194, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x0076, 0x0198, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x0076, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv05 sifc */ + NVOBJ_CLASS(dev, 0x0066, GR); + + /* nv03 sifm */ + NVOBJ_CLASS(dev, 0x0037, GR); + NVOBJ_MTHD (dev, 0x0037, 0x0188, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x0037, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0037, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0037, 0x0194, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x0037, 0x0304, nv04_graph_mthd_set_operation); + + /* nv04 sifm */ + NVOBJ_CLASS(dev, 0x0077, GR); + NVOBJ_MTHD (dev, 0x0077, 0x0188, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x0077, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x0077, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x0077, 0x0194, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x0077, 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf); + NVOBJ_MTHD (dev, 0x0077, 0x0304, nv04_graph_mthd_set_operation); + + /* null */ + NVOBJ_CLASS(dev, 0x0030, GR); + + /* surf2d */ + NVOBJ_CLASS(dev, 0x0042, GR); + + /* rop */ + NVOBJ_CLASS(dev, 0x0043, GR); + + /* beta1 */ + NVOBJ_CLASS(dev, 0x0012, GR); + + /* beta4 */ + NVOBJ_CLASS(dev, 0x0072, GR); + + /* cliprect */ + NVOBJ_CLASS(dev, 0x0019, GR); + + /* nv01 pattern */ + NVOBJ_CLASS(dev, 0x0018, GR); + + /* nv04 pattern */ + NVOBJ_CLASS(dev, 0x0044, GR); + + /* swzsurf */ + NVOBJ_CLASS(dev, 0x0052, GR); + + /* surf3d */ + NVOBJ_CLASS(dev, 0x0053, GR); + NVOBJ_MTHD (dev, 0x0053, 0x02f8, nv04_graph_mthd_surf3d_clip_h); + NVOBJ_MTHD (dev, 0x0053, 0x02fc, nv04_graph_mthd_surf3d_clip_v); + + /* nv03 tex_tri */ + NVOBJ_CLASS(dev, 0x0048, GR); + NVOBJ_MTHD (dev, 0x0048, 0x0188, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x0048, 0x018c, nv04_graph_mthd_bind_surf_color); + NVOBJ_MTHD (dev, 0x0048, 0x0190, nv04_graph_mthd_bind_surf_zeta); + + /* tex_tri */ + NVOBJ_CLASS(dev, 0x0054, GR); + + /* multitex_tri */ + NVOBJ_CLASS(dev, 0x0055, GR); + + /* nv01 chroma */ + NVOBJ_CLASS(dev, 0x0017, GR); + + /* nv04 chroma */ + NVOBJ_CLASS(dev, 0x0057, GR); + + /* surf_dst */ + NVOBJ_CLASS(dev, 0x0058, GR); + + /* surf_src */ + NVOBJ_CLASS(dev, 0x0059, GR); + + /* surf_color */ + NVOBJ_CLASS(dev, 0x005a, GR); + + /* surf_zeta */ + NVOBJ_CLASS(dev, 0x005b, GR); + + /* nv01 line */ + NVOBJ_CLASS(dev, 0x001c, GR); + NVOBJ_MTHD (dev, 0x001c, 0x0184, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x001c, 0x0188, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x001c, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x001c, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x001c, 0x0194, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x001c, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 line */ + NVOBJ_CLASS(dev, 0x005c, GR); + NVOBJ_MTHD (dev, 0x005c, 0x0184, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x005c, 0x0188, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x005c, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x005c, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x005c, 0x0194, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x005c, 0x0198, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x005c, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv01 tri */ + NVOBJ_CLASS(dev, 0x001d, GR); + NVOBJ_MTHD (dev, 0x001d, 0x0184, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x001d, 0x0188, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x001d, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x001d, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x001d, 0x0194, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x001d, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 tri */ + NVOBJ_CLASS(dev, 0x005d, GR); + NVOBJ_MTHD (dev, 0x005d, 0x0184, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x005d, 0x0188, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x005d, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x005d, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x005d, 0x0194, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x005d, 0x0198, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x005d, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv01 rect */ + NVOBJ_CLASS(dev, 0x001e, GR); + NVOBJ_MTHD (dev, 0x001e, 0x0184, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x001e, 0x0188, nv04_graph_mthd_bind_nv01_patt); + NVOBJ_MTHD (dev, 0x001e, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x001e, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x001e, 0x0194, nv04_graph_mthd_bind_surf_dst); + NVOBJ_MTHD (dev, 0x001e, 0x02fc, nv04_graph_mthd_set_operation); + + /* nv04 rect */ + NVOBJ_CLASS(dev, 0x005e, GR); + NVOBJ_MTHD (dev, 0x005e, 0x0184, nv04_graph_mthd_bind_clip); + NVOBJ_MTHD (dev, 0x005e, 0x0188, nv04_graph_mthd_bind_nv04_patt); + NVOBJ_MTHD (dev, 0x005e, 0x018c, nv04_graph_mthd_bind_rop); + NVOBJ_MTHD (dev, 0x005e, 0x0190, nv04_graph_mthd_bind_beta1); + NVOBJ_MTHD (dev, 0x005e, 0x0194, nv04_graph_mthd_bind_beta4); + NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d); + NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation); + + /* nvsw */ + NVOBJ_CLASS(dev, 0x506e, SW); + NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref); + + dev_priv->engine.graph.registered = true; + return 0; }; - diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index ed31a622889e..17c20dbff232 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -27,6 +27,8 @@ #include "nouveau_drm.h" #include "nouveau_drv.h" +static int nv10_graph_register(struct drm_device *); + #define NV10_FIFO_NUMBER 32 struct pipe_state { @@ -914,13 +916,17 @@ int nv10_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t tmp; - int i; + int ret, i; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + ret = nv10_graph_register(dev); + if (ret) + return ret; + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -966,8 +972,8 @@ void nv10_graph_takedown(struct drm_device *dev) } static int -nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv17_graph_mthd_lma_window(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { struct drm_device *dev = chan->dev; struct graph_state *ctx = chan->pgraph_ctx; @@ -1046,8 +1052,8 @@ nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass, } static int -nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -1065,36 +1071,48 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass, return 0; } -static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = { - { 0x1638, nv17_graph_mthd_lma_window }, - { 0x163c, nv17_graph_mthd_lma_window }, - { 0x1640, nv17_graph_mthd_lma_window }, - { 0x1644, nv17_graph_mthd_lma_window }, - { 0x1658, nv17_graph_mthd_lma_enable }, - {} -}; +static int +nv10_graph_register(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; -struct nouveau_pgraph_object_class nv10_graph_grclass[] = { - { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ - { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ - { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ - { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ - { 0x005f, NVOBJ_ENGINE_GR, NULL }, /* imageblit */ - { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ - { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ - { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ - { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ - { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ - { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ - { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ - { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ - { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ - { 0x0052, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ - { 0x0093, NVOBJ_ENGINE_GR, NULL }, /* surf3d */ - { 0x0094, NVOBJ_ENGINE_GR, NULL }, /* tex_tri */ - { 0x0095, NVOBJ_ENGINE_GR, NULL }, /* multitex_tri */ - { 0x0056, NVOBJ_ENGINE_GR, NULL }, /* celcius (nv10) */ - { 0x0096, NVOBJ_ENGINE_GR, NULL }, /* celcius (nv11) */ - { 0x0099, NVOBJ_ENGINE_GR, nv17_graph_celsius_mthds }, /* celcius (nv17) */ - {} -}; + if (dev_priv->engine.graph.registered) + return 0; + + NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ + NVOBJ_CLASS(dev, 0x0030, GR); /* null */ + NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ + NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ + NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */ + NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ + NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ + NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ + NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ + NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ + NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ + NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ + NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ + NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ + NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */ + NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */ + NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */ + NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */ + + /* celcius */ + if (dev_priv->chipset <= 0x10) { + NVOBJ_CLASS(dev, 0x0056, GR); + } else + if (dev_priv->chipset <= 0x17 || dev_priv->chipset == 0x1a) { + NVOBJ_CLASS(dev, 0x0096, GR); + } else { + NVOBJ_CLASS(dev, 0x0099, GR); + NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window); + NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window); + NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window); + NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window); + NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable); + } + + dev_priv->engine.graph.registered = true; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 872f8d059694..7720bccb3c98 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -32,6 +32,9 @@ #define NV34_GRCTX_SIZE (18140) #define NV35_36_GRCTX_SIZE (22396) +static int nv20_graph_register(struct drm_device *); +static int nv30_graph_register(struct drm_device *); + static void nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) { @@ -572,6 +575,12 @@ nv20_graph_init(struct drm_device *dev) nv20_graph_rdi(dev); + ret = nv20_graph_register(dev); + if (ret) { + nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); + return ret; + } + nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -696,6 +705,12 @@ nv30_graph_init(struct drm_device *dev) return ret; } + ret = nv30_graph_register(dev); + if (ret) { + nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); + return ret; + } + nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctx_table->pinst >> 4); @@ -756,48 +771,76 @@ nv30_graph_init(struct drm_device *dev) return 0; } -struct nouveau_pgraph_object_class nv20_graph_grclass[] = { - { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ - { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ - { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ - { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ - { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ - { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ - { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ - { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ - { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ - { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ - { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ - { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ - { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ - { 0x009e, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ - { 0x0096, NVOBJ_ENGINE_GR, NULL }, /* celcius */ - { 0x0097, NVOBJ_ENGINE_GR, NULL }, /* kelvin (nv20) */ - { 0x0597, NVOBJ_ENGINE_GR, NULL }, /* kelvin (nv25) */ - {} -}; - -struct nouveau_pgraph_object_class nv30_graph_grclass[] = { - { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ - { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ - { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ - { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ - { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ - { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ - { 0x038a, NVOBJ_ENGINE_GR, NULL }, /* ifc (nv30) */ - { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ - { 0x0389, NVOBJ_ENGINE_GR, NULL }, /* sifm (nv30) */ - { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ - { 0x0362, NVOBJ_ENGINE_GR, NULL }, /* surf2d (nv30) */ - { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ - { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ - { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ - { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ - { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ - { 0x039e, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ - { 0x0397, NVOBJ_ENGINE_GR, NULL }, /* rankine (nv30) */ - { 0x0497, NVOBJ_ENGINE_GR, NULL }, /* rankine (nv35) */ - { 0x0697, NVOBJ_ENGINE_GR, NULL }, /* rankine (nv34) */ - {} -}; +static int +nv20_graph_register(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->engine.graph.registered) + return 0; + NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ + NVOBJ_CLASS(dev, 0x0030, GR); /* null */ + NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ + NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ + NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ + NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ + NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ + NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ + NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ + NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ + NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ + NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ + NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ + NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */ + NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */ + + /* kelvin */ + if (dev_priv->chipset < 0x25) + NVOBJ_CLASS(dev, 0x0097, GR); + else + NVOBJ_CLASS(dev, 0x0597, GR); + + dev_priv->engine.graph.registered = true; + return 0; +} + +static int +nv30_graph_register(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->engine.graph.registered) + return 0; + + NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ + NVOBJ_CLASS(dev, 0x0030, GR); /* null */ + NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ + NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ + NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ + NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ + NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */ + NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ + NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */ + NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ + NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */ + NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ + NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ + NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ + NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ + NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ + NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */ + + /* rankine */ + if (0x00000003 & (1 << (dev_priv->chipset & 0x0f))) + NVOBJ_CLASS(dev, 0x0397, GR); + else + if (0x00000010 & (1 << (dev_priv->chipset & 0x0f))) + NVOBJ_CLASS(dev, 0x0697, GR); + else + if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f))) + NVOBJ_CLASS(dev, 0x0497, GR); + + dev_priv->engine.graph.registered = true; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 70d957895cea..b9361e28687c 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -29,6 +29,8 @@ #include "nouveau_drv.h" #include "nouveau_grctx.h" +static int nv40_graph_register(struct drm_device *); + struct nouveau_channel * nv40_graph_channel(struct drm_device *dev) { @@ -248,7 +250,7 @@ nv40_graph_init(struct drm_device *dev) struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; struct nouveau_grctx ctx = {}; uint32_t vramsz, *cp; - int i, j; + int ret, i, j; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); @@ -272,6 +274,10 @@ nv40_graph_init(struct drm_device *dev) kfree(cp); + ret = nv40_graph_register(dev); + if (ret) + return ret; + /* No context present currently */ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); @@ -408,25 +414,38 @@ void nv40_graph_takedown(struct drm_device *dev) { } -struct nouveau_pgraph_object_class nv40_graph_grclass[] = { - { 0x506e, NVOBJ_ENGINE_SW, NULL }, /* nvsw */ - { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ - { 0x0039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ - { 0x004a, NVOBJ_ENGINE_GR, NULL }, /* gdirect */ - { 0x009f, NVOBJ_ENGINE_GR, NULL }, /* imageblit (nv12) */ - { 0x008a, NVOBJ_ENGINE_GR, NULL }, /* ifc */ - { 0x0089, NVOBJ_ENGINE_GR, NULL }, /* sifm */ - { 0x3089, NVOBJ_ENGINE_GR, NULL }, /* sifm (nv40) */ - { 0x0062, NVOBJ_ENGINE_GR, NULL }, /* surf2d */ - { 0x3062, NVOBJ_ENGINE_GR, NULL }, /* surf2d (nv40) */ - { 0x0043, NVOBJ_ENGINE_GR, NULL }, /* rop */ - { 0x0012, NVOBJ_ENGINE_GR, NULL }, /* beta1 */ - { 0x0072, NVOBJ_ENGINE_GR, NULL }, /* beta4 */ - { 0x0019, NVOBJ_ENGINE_GR, NULL }, /* cliprect */ - { 0x0044, NVOBJ_ENGINE_GR, NULL }, /* pattern */ - { 0x309e, NVOBJ_ENGINE_GR, NULL }, /* swzsurf */ - { 0x4097, NVOBJ_ENGINE_GR, NULL }, /* curie (nv40) */ - { 0x4497, NVOBJ_ENGINE_GR, NULL }, /* curie (nv44) */ - {} -}; +static int +nv40_graph_register(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->engine.graph.registered) + return 0; + NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ + NVOBJ_CLASS(dev, 0x0030, GR); /* null */ + NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ + NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ + NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */ + NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */ + NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */ + NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */ + NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */ + NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */ + NVOBJ_CLASS(dev, 0x0043, GR); /* rop */ + NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */ + NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */ + NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */ + NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */ + NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */ + + /* curie */ + if (dev_priv->chipset >= 0x60 || + 0x00005450 & (1 << (dev_priv->chipset & 0x0f))) + NVOBJ_CLASS(dev, 0x4497, GR); + else + NVOBJ_CLASS(dev, 0x4097, GR); + + dev_priv->engine.graph.registered = true; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 01a598917e3c..84ca90e91811 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -30,6 +30,8 @@ #include "nouveau_ramht.h" #include "nouveau_grctx.h" +static int nv50_graph_register(struct drm_device *); + static void nv50_graph_init_reset(struct drm_device *dev) { @@ -145,12 +147,15 @@ nv50_graph_init(struct drm_device *dev) nv50_graph_init_reset(dev); nv50_graph_init_regs__nv(dev); nv50_graph_init_regs(dev); - nv50_graph_init_intr(dev); ret = nv50_graph_init_ctxctl(dev); if (ret) return ret; + ret = nv50_graph_register(dev); + if (ret) + return ret; + nv50_graph_init_intr(dev); return 0; } @@ -333,8 +338,8 @@ nv50_graph_context_switch(struct drm_device *dev) } static int -nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { struct nouveau_gpuobj *gpuobj; @@ -351,8 +356,8 @@ nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass, } static int -nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { if (nouveau_notifier_offset(chan->nvsw.vblsem, &data)) return -ERANGE; @@ -362,16 +367,16 @@ nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass, } static int -nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { chan->nvsw.vblsem_rval = data; return 0; } static int -nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass, - int mthd, uint32_t data) +nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -392,27 +397,53 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass, return 0; } -static struct nouveau_pgraph_object_method nv50_graph_nvsw_methods[] = { - { 0x018c, nv50_graph_nvsw_dma_vblsem }, - { 0x0400, nv50_graph_nvsw_vblsem_offset }, - { 0x0404, nv50_graph_nvsw_vblsem_release_val }, - { 0x0408, nv50_graph_nvsw_vblsem_release }, - {} -}; - -struct nouveau_pgraph_object_class nv50_graph_grclass[] = { - { 0x506e, NVOBJ_ENGINE_SW, nv50_graph_nvsw_methods }, /* nvsw */ - { 0x0030, NVOBJ_ENGINE_GR, NULL }, /* null */ - { 0x5039, NVOBJ_ENGINE_GR, NULL }, /* m2mf */ - { 0x502d, NVOBJ_ENGINE_GR, NULL }, /* 2d */ - { 0x50c0, NVOBJ_ENGINE_GR, NULL }, /* compute */ - { 0x85c0, NVOBJ_ENGINE_GR, NULL }, /* compute (nva3, nva5, nva8) */ - { 0x5097, NVOBJ_ENGINE_GR, NULL }, /* tesla (nv50) */ - { 0x8297, NVOBJ_ENGINE_GR, NULL }, /* tesla (nv8x/nv9x) */ - { 0x8397, NVOBJ_ENGINE_GR, NULL }, /* tesla (nva0, nvaa, nvac) */ - { 0x8597, NVOBJ_ENGINE_GR, NULL }, /* tesla (nva3, nva5, nva8) */ - {} -}; +static int +nv50_graph_register(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->engine.graph.registered) + return 0; + + NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ + NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem); + NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset); + NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val); + NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release); + + NVOBJ_CLASS(dev, 0x0030, GR); /* null */ + NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ + NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */ + NVOBJ_CLASS(dev, 0x50c0, GR); /* compute */ + NVOBJ_CLASS(dev, 0x85c0, GR); /* compute (nva3, nva5, nva8) */ + + /* tesla */ + if (dev_priv->chipset == 0x50) + NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */ + else + if (dev_priv->chipset < 0xa0) + NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */ + else { + switch (dev_priv->chipset) { + case 0xa0: + case 0xaa: + case 0xac: + NVOBJ_CLASS(dev, 0x8397, GR); + break; + case 0xa3: + case 0xa5: + case 0xa8: + NVOBJ_CLASS(dev, 0x8597, GR); + break; + case 0xaf: + NVOBJ_CLASS(dev, 0x8697, GR); + break; + } + } + + dev_priv->engine.graph.registered = true; + return 0; +} void nv50_graph_tlb_flush(struct drm_device *dev) -- cgit v1.2.3 From bd2e597de8dbd000a3977871f15cb81e2925d63e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 20:06:01 +1000 Subject: drm/nv84: add support for the PCRYPT engine Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 1 + drivers/gpu/drm/nouveau/nouveau_channel.c | 12 ++++ drivers/gpu/drm/nouveau/nouveau_drv.c | 1 + drivers/gpu/drm/nouveau/nouveau_drv.h | 24 +++++++ drivers/gpu/drm/nouveau/nouveau_irq.c | 16 +++++ drivers/gpu/drm/nouveau/nouveau_object.c | 3 +- drivers/gpu/drm/nouveau/nouveau_state.c | 62 ++++++++++++++--- drivers/gpu/drm/nouveau/nv84_crypt.c | 110 ++++++++++++++++++++++++++++++ 8 files changed, 218 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nv84_crypt.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 23fa82d667d6..a541f5bff75d 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -18,6 +18,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o nvc0_graph.o \ nv40_grctx.o nv50_grctx.o \ + nv84_crypt.o \ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ nv50_crtc.o nv50_dac.o nv50_sor.o \ nv50_cursor.o nv50_display.o nv50_fbcon.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 76033c509d35..8f2df6beb893 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -112,6 +112,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; struct nouveau_channel *chan; unsigned long flags; int user, ret; @@ -214,6 +215,14 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, return ret; } + if (pcrypt->create_context) { + ret = pcrypt->create_context(chan); + if (ret) { + nouveau_channel_put(&chan); + return ret; + } + } + /* Construct inital RAMFC for new channel */ ret = pfifo->create_context(chan); if (ret) { @@ -280,6 +289,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; unsigned long flags; int ret; @@ -328,6 +338,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) /* destroy the engine specific contexts */ pfifo->destroy_context(chan); pgraph->destroy_context(chan); + if (pcrypt->destroy_context) + pcrypt->destroy_context(chan); pfifo->reassign(dev, true); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index f139aa2cbe5c..6dbb8818c530 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -299,6 +299,7 @@ nouveau_pci_resume(struct pci_dev *pdev) engine->timer.init(dev); engine->fb.init(dev); engine->graph.init(dev); + engine->crypt.init(dev); engine->fifo.init(dev); NV_INFO(dev, "Restoring GPU objects...\n"); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 3fb87995446b..d15bfd427267 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -132,6 +132,11 @@ enum nouveau_flags { #define NVOBJ_ENGINE_SW 0 #define NVOBJ_ENGINE_GR 1 +#define NVOBJ_ENGINE_PPP 2 +#define NVOBJ_ENGINE_COPY 3 +#define NVOBJ_ENGINE_VP 4 +#define NVOBJ_ENGINE_CRYPT 5 +#define NVOBJ_ENGINE_BSP 6 #define NVOBJ_ENGINE_DISPLAY 0xcafe0001 #define NVOBJ_ENGINE_INT 0xdeadbeef @@ -208,6 +213,7 @@ struct nouveau_channel { /* PGRAPH context */ /* XXX may be merge 2 pointers as private data ??? */ struct nouveau_gpuobj *ramin_grctx; + struct nouveau_gpuobj *crypt_ctx; void *pgraph_ctx; /* NV50 VM */ @@ -444,6 +450,16 @@ struct nouveau_pm_engine { int (*temp_get)(struct drm_device *); }; +struct nouveau_crypt_engine { + bool registered; + + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *); + int (*create_context)(struct nouveau_channel *); + void (*destroy_context)(struct nouveau_channel *); + void (*tlb_flush)(struct drm_device *dev); +}; + struct nouveau_engine { struct nouveau_instmem_engine instmem; struct nouveau_mc_engine mc; @@ -454,6 +470,7 @@ struct nouveau_engine { struct nouveau_display_engine display; struct nouveau_gpio_engine gpio; struct nouveau_pm_engine pm; + struct nouveau_crypt_engine crypt; }; struct nouveau_pll_vals { @@ -1113,6 +1130,13 @@ extern void nvc0_graph_destroy_context(struct nouveau_channel *); extern int nvc0_graph_load_context(struct nouveau_channel *); extern int nvc0_graph_unload_context(struct drm_device *); +/* nv84_crypt.c */ +extern int nv84_crypt_init(struct drm_device *dev); +extern void nv84_crypt_fini(struct drm_device *dev); +extern int nv84_crypt_create_context(struct nouveau_channel *); +extern void nv84_crypt_destroy_context(struct nouveau_channel *); +extern void nv84_crypt_tlb_flush(struct drm_device *dev); + /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); extern void nv04_instmem_takedown(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index f09151d17297..ca9b969f4f9c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -1230,6 +1230,22 @@ nouveau_irq_handler(DRM_IRQ_ARGS) status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; } + if (status & 0x00004000) { + u32 stat = nv_rd32(dev, 0x102130); + u32 mthd = nv_rd32(dev, 0x102190); + u32 data = nv_rd32(dev, 0x102194); + u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff; + + NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n", + stat, mthd, data, inst); + nv_wr32(dev, 0x102130, stat); + nv_wr32(dev, 0x10200c, 0x10); + + nv50_fb_vm_trap(dev, nouveau_ratelimit(), "PCRYPT"); + status &= ~0x00004000; + + } + if (status & NV_PMC_INTR_0_CRTCn_PENDING) { nouveau_crtc_irq_handler(dev, (status>>24)&3); status &= ~NV_PMC_INTR_0_CRTCn_PENDING; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 6226beb3613d..ee526534c6f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -272,6 +272,7 @@ nouveau_gpuobj_init(struct drm_device *dev) NV_DEBUG(dev, "\n"); INIT_LIST_HEAD(&dev_priv->gpuobj_list); + INIT_LIST_HEAD(&dev_priv->classes); spin_lock_init(&dev_priv->ramin_lock); dev_priv->ramin_base = ~0; @@ -686,7 +687,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); /* Base amount for object storage (4KiB enough?) */ - size = 0x1000; + size = 0x2000; base = 0; /* PGRAPH context */ diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index be28754ffd50..f13134aa8c4f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -98,6 +98,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_get = nv04_pm_clock_get; engine->pm.clock_pre = nv04_pm_clock_pre; engine->pm.clock_set = nv04_pm_clock_set; + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; break; case 0x10: engine->instmem.init = nv04_instmem_init; @@ -151,6 +153,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_get = nv04_pm_clock_get; engine->pm.clock_pre = nv04_pm_clock_pre; engine->pm.clock_set = nv04_pm_clock_set; + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; break; case 0x20: engine->instmem.init = nv04_instmem_init; @@ -204,6 +208,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_get = nv04_pm_clock_get; engine->pm.clock_pre = nv04_pm_clock_pre; engine->pm.clock_set = nv04_pm_clock_set; + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; break; case 0x30: engine->instmem.init = nv04_instmem_init; @@ -259,6 +265,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_set = nv04_pm_clock_set; engine->pm.voltage_get = nouveau_voltage_gpio_get; engine->pm.voltage_set = nouveau_voltage_gpio_set; + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; break; case 0x40: case 0x60: @@ -316,6 +324,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.voltage_get = nouveau_voltage_gpio_get; engine->pm.voltage_set = nouveau_voltage_gpio_set; engine->pm.temp_get = nv40_temp_get; + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; break; case 0x50: case 0x80: /* gotta love NVIDIA's consistency.. */ @@ -380,19 +390,23 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.set = nv50_gpio_set; engine->gpio.irq_enable = nv50_gpio_irq_enable; switch (dev_priv->chipset) { - case 0xa3: - case 0xa5: - case 0xa8: - case 0xaf: - engine->pm.clock_get = nva3_pm_clock_get; - engine->pm.clock_pre = nva3_pm_clock_pre; - engine->pm.clock_set = nva3_pm_clock_set; - break; - default: + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + case 0xa0: + case 0x50: engine->pm.clock_get = nv50_pm_clock_get; engine->pm.clock_pre = nv50_pm_clock_pre; engine->pm.clock_set = nv50_pm_clock_set; break; + default: + engine->pm.clock_get = nva3_pm_clock_get; + engine->pm.clock_pre = nva3_pm_clock_pre; + engine->pm.clock_set = nva3_pm_clock_set; + break; } engine->pm.voltage_get = nouveau_voltage_gpio_get; engine->pm.voltage_set = nouveau_voltage_gpio_set; @@ -400,6 +414,23 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.temp_get = nv84_temp_get; else engine->pm.temp_get = nv40_temp_get; + switch (dev_priv->chipset) { + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0xa0: + engine->crypt.init = nv84_crypt_init; + engine->crypt.takedown = nv84_crypt_fini; + engine->crypt.create_context = nv84_crypt_create_context; + engine->crypt.destroy_context = nv84_crypt_destroy_context; + break; + default: + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; + break; + } break; case 0xC0: engine->instmem.init = nvc0_instmem_init; @@ -447,6 +478,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.get = nv50_gpio_get; engine->gpio.set = nv50_gpio_set; engine->gpio.irq_enable = nv50_gpio_irq_enable; + engine->crypt.init = nouveau_stub_init; + engine->crypt.takedown = nouveau_stub_takedown; break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); @@ -619,10 +652,15 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_fb; + /* PCRYPT */ + ret = engine->crypt.init(dev); + if (ret) + goto out_graph; + /* PFIFO */ ret = engine->fifo.init(dev); if (ret) - goto out_graph; + goto out_crypt; } ret = engine->display.create(dev); @@ -669,6 +707,9 @@ out_display: out_fifo: if (!nouveau_noaccel) engine->fifo.takedown(dev); +out_crypt: + if (!nouveau_noaccel) + engine->crypt.takedown(dev); out_graph: if (!nouveau_noaccel) engine->graph.takedown(dev); @@ -712,6 +753,7 @@ static void nouveau_card_takedown(struct drm_device *dev) if (!nouveau_noaccel) { engine->fifo.takedown(dev); + engine->crypt.takedown(dev); engine->graph.takedown(dev); } engine->fb.takedown(dev); diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c new file mode 100644 index 000000000000..63bd6bb41e38 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -0,0 +1,110 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" + +int +nv84_crypt_create_context(struct nouveau_channel *chan) +{ + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *ramin = chan->ramin; + int ret; + + NV_DEBUG(dev, "ch%d\n", chan->id); + + ret = nouveau_gpuobj_new(dev, chan, 256, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, + &chan->crypt_ctx); + if (ret) + return ret; + + nv_wo32(ramin, 0xa0, 0x00190000); + nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff); + nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst); + nv_wo32(ramin, 0xac, 0); + nv_wo32(ramin, 0xb0, 0); + nv_wo32(ramin, 0xb4, 0); + + dev_priv->engine.instmem.flush(dev); + return 0; +} + +void +nv84_crypt_destroy_context(struct nouveau_channel *chan) +{ + struct drm_device *dev = chan->dev; + u32 inst; + + if (!chan->ramin) + return; + + inst = (chan->ramin->vinst >> 12); + inst |= 0x80000000; + + /* mark context as invalid if still on the hardware, not + * doing this causes issues the next time PCRYPT is used, + * unsurprisingly :) + */ + nv_wr32(dev, 0x10200c, 0x00000000); + if (nv_rd32(dev, 0x102188) == inst) + nv_mask(dev, 0x102188, 0x80000000, 0x00000000); + if (nv_rd32(dev, 0x10218c) == inst) + nv_mask(dev, 0x10218c, 0x80000000, 0x00000000); + nv_wr32(dev, 0x10200c, 0x00000010); + + nouveau_gpuobj_ref(NULL, &chan->crypt_ctx); +} + +void +nv84_crypt_tlb_flush(struct drm_device *dev) +{ + nv50_vm_flush(dev, 0x0a); +} + +int +nv84_crypt_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; + + if (!pcrypt->registered) { + NVOBJ_CLASS(dev, 0x74c1, CRYPT); + pcrypt->registered = true; + } + + nv_mask(dev, 0x000200, 0x00004000, 0x00000000); + nv_mask(dev, 0x000200, 0x00004000, 0x00004000); + nv_wr32(dev, 0x102130, 0xffffffff); + nv_wr32(dev, 0x102140, 0xffffffbf); + nv_wr32(dev, 0x10200c, 0x00000010); + return 0; +} + +void +nv84_crypt_fini(struct drm_device *dev) +{ + nv_wr32(dev, 0x102140, 0x00000000); +} -- cgit v1.2.3 From 3052be2cea64371300a0338d3ca5d3575fbd109c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 20 Oct 2010 11:46:38 +1000 Subject: drm/nv50: remove excessive alignment of graph/crypt contexts Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 2 +- drivers/gpu/drm/nouveau/nv84_crypt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 84ca90e91811..a764af52a3ba 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -216,7 +216,7 @@ nv50_graph_create_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000, + ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); if (ret) diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c index 63bd6bb41e38..f988b1a9d1d7 100644 --- a/drivers/gpu/drm/nouveau/nv84_crypt.c +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -35,7 +35,7 @@ nv84_crypt_create_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - ret = nouveau_gpuobj_new(dev, chan, 256, 0x1000, + ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, &chan->crypt_ctx); if (ret) -- cgit v1.2.3 From f4512e6579ddaa9b1f8ab1d5659131243ffc421f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 20 Oct 2010 11:47:09 +1000 Subject: drm/nv50: create graph and crypt contexts on demand This really needs cleaning up somehow, and probably investigate what's needed to do this on earlier generations. NVIDIA do something similar there too. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 11 ++--------- drivers/gpu/drm/nouveau/nouveau_object.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 8f2df6beb893..f2d674202369 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -112,7 +112,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; - struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; struct nouveau_channel *chan; unsigned long flags; int user, ret; @@ -209,14 +208,8 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, pfifo->reassign(dev, false); /* Create a graphics context for new channel */ - ret = pgraph->create_context(chan); - if (ret) { - nouveau_channel_put(&chan); - return ret; - } - - if (pcrypt->create_context) { - ret = pcrypt->create_context(chan); + if (dev_priv->card_type < NV_50) { + ret = pgraph->create_context(chan); if (ret) { nouveau_channel_put(&chan); return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index ee526534c6f4..54078186fe65 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -634,6 +634,29 @@ found: if (oc->engine == NVOBJ_ENGINE_SW) return nouveau_gpuobj_sw_new(chan, class, gpuobj); + switch (oc->engine) { + case NVOBJ_ENGINE_GR: + if (dev_priv->card_type >= NV_50 && !chan->ramin_grctx) { + struct nouveau_pgraph_engine *pgraph = + &dev_priv->engine.graph; + + ret = pgraph->create_context(chan); + if (ret) + return ret; + } + break; + case NVOBJ_ENGINE_CRYPT: + if (!chan->crypt_ctx) { + struct nouveau_crypt_engine *pcrypt = + &dev_priv->engine.crypt; + + ret = pcrypt->create_context(chan); + if (ret) + return ret; + } + break; + } + ret = nouveau_gpuobj_new(dev, chan, nouveau_gpuobj_class_instmem_size(dev, class), 16, -- cgit v1.2.3 From 106ddad5aa8e8e03503cea05f9a64611f849952f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 11:14:17 +1000 Subject: drm/nv50: clearer separation of the stages of evo init Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_reg.h | 14 ++--- drivers/gpu/drm/nouveau/nv50_display.c | 93 ++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 1bbe7037cf99..5e28bc63c41e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -747,15 +747,11 @@ #define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS 0x00030000 #define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE 0x00010000 -#define NV50_PDISPLAY_CTRL_STATE 0x00610300 -#define NV50_PDISPLAY_CTRL_STATE_PENDING 0x80000000 -#define NV50_PDISPLAY_CTRL_STATE_METHOD 0x00001ffc -#define NV50_PDISPLAY_CTRL_STATE_ENABLE 0x00000001 -#define NV50_PDISPLAY_CTRL_VAL 0x00610304 -#define NV50_PDISPLAY_UNK_380 0x00610380 -#define NV50_PDISPLAY_RAM_AMOUNT 0x00610384 -#define NV50_PDISPLAY_UNK_388 0x00610388 -#define NV50_PDISPLAY_UNK_38C 0x0061038c +#define NV50_PDISPLAY_PIO_CTRL 0x00610300 +#define NV50_PDISPLAY_PIO_CTRL_PENDING 0x80000000 +#define NV50_PDISPLAY_PIO_CTRL_MTHD 0x00001ffc +#define NV50_PDISPLAY_PIO_CTRL_ENABLED 0x00000001 +#define NV50_PDISPLAY_PIO_DATA 0x00610304 #define NV50_PDISPLAY_CRTC_P(i, r) ((i) * 0x540 + NV50_PDISPLAY_CRTC_##r) #define NV50_PDISPLAY_CRTC_C(i, r) (4 + (i) * 0x540 + NV50_PDISPLAY_CRTC_##r) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 7ac87efb791f..7c9c7c5bf22a 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -225,6 +225,7 @@ nv50_display_init(struct drm_device *dev) NV_DEBUG_KMS(dev, "\n"); nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004)); + /* * I think the 0x006101XX range is some kind of main control area * that enables things. @@ -240,16 +241,19 @@ nv50_display_init(struct drm_device *dev) val = nv_rd32(dev, 0x0061610c + (i * 0x800)); nv_wr32(dev, 0x0061019c + (i * 0x10), val); } + /* DAC */ for (i = 0; i < 3; i++) { val = nv_rd32(dev, 0x0061a000 + (i * 0x800)); nv_wr32(dev, 0x006101d0 + (i * 0x04), val); } + /* SOR */ for (i = 0; i < nv50_sor_nr(dev); i++) { val = nv_rd32(dev, 0x0061c000 + (i * 0x800)); nv_wr32(dev, 0x006101e0 + (i * 0x04), val); } + /* EXT */ for (i = 0; i < 3; i++) { val = nv_rd32(dev, 0x0061e000 + (i * 0x800)); @@ -276,6 +280,49 @@ nv50_display_init(struct drm_device *dev) } } + for (i = 0; i < 2; i++) { + nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); + if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { + NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); + NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); + return -EBUSY; + } + + nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); + if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, + NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) { + NV_ERROR(dev, "timeout: " + "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i); + NV_ERROR(dev, "CURSOR_CTRL2(%d) = 0x%08x\n", i, + nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); + return -EBUSY; + } + } + + nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); + nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000); + nv_wr32(dev, 0x610028, 0x00000000); + nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000); + nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000); + nv_wr32(dev, NV50_PDISPLAY_INTR_EN, + NV50_PDISPLAY_INTR_EN_CLK_UNK10 | + NV50_PDISPLAY_INTR_EN_CLK_UNK20 | + NV50_PDISPLAY_INTR_EN_CLK_UNK40); + + /* enable hotplug interrupts */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct nouveau_connector *conn = nouveau_connector(connector); + + if (conn->dcb->gpio_tag == 0xff) + continue; + + pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); + } + /* taken from nv bug #12637, attempts to un-wedge the hw if it's * stuck in some unspecified state */ @@ -297,7 +344,6 @@ nv50_display_init(struct drm_device *dev) } } - nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) { @@ -307,31 +353,6 @@ nv50_display_init(struct drm_device *dev) return -EBUSY; } - for (i = 0; i < 2; i++) { - nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); - if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), - NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { - NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); - NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); - return -EBUSY; - } - - nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), - NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); - if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), - NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, - NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) { - NV_ERROR(dev, "timeout: " - "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i); - NV_ERROR(dev, "CURSOR_CTRL2(%d) = 0x%08x\n", i, - nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); - return -EBUSY; - } - } - - nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); - /* initialise fifo */ nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | @@ -350,7 +371,9 @@ nv50_display_init(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0); nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x01000003 | NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); - nv_wr32(dev, 0x610300, nv_rd32(dev, 0x610300) & ~1); + + /* enable error reporting on the channel */ + nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << 0); evo->dma.max = (4096/4) - 2; evo->dma.put = 0; @@ -382,21 +405,6 @@ nv50_display_init(struct drm_device *dev) if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) NV_ERROR(dev, "evo pushbuf stalled\n"); - /* enable clock change interrupts. */ - nv_wr32(dev, 0x610028, 0x00010001); - nv_wr32(dev, NV50_PDISPLAY_INTR_EN, (NV50_PDISPLAY_INTR_EN_CLK_UNK10 | - NV50_PDISPLAY_INTR_EN_CLK_UNK20 | - NV50_PDISPLAY_INTR_EN_CLK_UNK40)); - - /* enable hotplug interrupts */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct nouveau_connector *conn = nouveau_connector(connector); - - if (conn->dcb->gpio_tag == 0xff) - continue; - - pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); - } return 0; } @@ -442,7 +450,6 @@ static int nv50_display_disable(struct drm_device *dev) } nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); - nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0); if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); NV_ERROR(dev, "0x610200 = 0x%08x\n", -- cgit v1.2.3 From b7bc613a4cc08d867b43189c2af0bb83b1fa1dc6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 13:05:51 +1000 Subject: drm/nv50: move evo handling to nv50_evo.c Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 2 +- drivers/gpu/drm/nouveau/nouveau_reg.h | 22 +-- drivers/gpu/drm/nouveau/nv50_display.c | 238 +------------------------- drivers/gpu/drm/nouveau/nv50_evo.c | 295 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv50_evo.h | 10 ++ 5 files changed, 322 insertions(+), 245 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nv50_evo.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index a541f5bff75d..c8c8de0bbc77 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -20,7 +20,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv40_grctx.o nv50_grctx.o \ nv84_crypt.o \ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ - nv50_crtc.o nv50_dac.o nv50_sor.o \ + nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ nv50_cursor.o nv50_display.o nv50_fbcon.o \ nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 5e28bc63c41e..d0ce86c24ebf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -729,17 +729,17 @@ #define NV50_PDISPLAY_UNK30_CTRL_PENDING 0x80000000 #define NV50_PDISPLAY_TRAPPED_ADDR 0x00610080 #define NV50_PDISPLAY_TRAPPED_DATA 0x00610084 -#define NV50_PDISPLAY_CHANNEL_STAT(i) ((i) * 0x10 + 0x00610200) -#define NV50_PDISPLAY_CHANNEL_STAT_DMA 0x00000010 -#define NV50_PDISPLAY_CHANNEL_STAT_DMA_DISABLED 0x00000000 -#define NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED 0x00000010 -#define NV50_PDISPLAY_CHANNEL_DMA_CB(i) ((i) * 0x10 + 0x00610204) -#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION 0x00000002 -#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM 0x00000000 -#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_SYSTEM 0x00000002 -#define NV50_PDISPLAY_CHANNEL_DMA_CB_VALID 0x00000001 -#define NV50_PDISPLAY_CHANNEL_UNK2(i) ((i) * 0x10 + 0x00610208) -#define NV50_PDISPLAY_CHANNEL_UNK3(i) ((i) * 0x10 + 0x0061020c) +#define NV50_PDISPLAY_EVO_CTRL(i) ((i) * 0x10 + 0x00610200) +#define NV50_PDISPLAY_EVO_CTRL_DMA 0x00000010 +#define NV50_PDISPLAY_EVO_CTRL_DMA_DISABLED 0x00000000 +#define NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED 0x00000010 +#define NV50_PDISPLAY_EVO_DMA_CB(i) ((i) * 0x10 + 0x00610204) +#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION 0x00000002 +#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM 0x00000000 +#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION_SYSTEM 0x00000002 +#define NV50_PDISPLAY_EVO_DMA_CB_VALID 0x00000001 +#define NV50_PDISPLAY_EVO_UNK2(i) ((i) * 0x10 + 0x00610208) +#define NV50_PDISPLAY_EVO_HASH_TAG(i) ((i) * 0x10 + 0x0061020c) #define NV50_PDISPLAY_CURSOR 0x00610270 #define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) ((i) * 0x10 + 0x00610270) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 7c9c7c5bf22a..db100a8f231e 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -46,159 +46,6 @@ nv50_sor_nr(struct drm_device *dev) return 4; } -static void -nv50_evo_channel_del(struct nouveau_channel **pchan) -{ - struct nouveau_channel *chan = *pchan; - - if (!chan) - return; - *pchan = NULL; - - nouveau_gpuobj_channel_takedown(chan); - nouveau_bo_unmap(chan->pushbuf_bo); - nouveau_bo_ref(NULL, &chan->pushbuf_bo); - - if (chan->user) - iounmap(chan->user); - - kfree(chan); -} - -static int -nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, - uint32_t tile_flags, uint32_t magic_flags, - uint32_t offset, uint32_t limit) -{ - struct drm_nouveau_private *dev_priv = evo->dev->dev_private; - struct drm_device *dev = evo->dev; - struct nouveau_gpuobj *obj = NULL; - int ret; - - ret = nouveau_gpuobj_new(dev, evo, 6*4, 32, 0, &obj); - if (ret) - return ret; - obj->engine = NVOBJ_ENGINE_DISPLAY; - - nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); - nv_wo32(obj, 4, limit); - nv_wo32(obj, 8, offset); - nv_wo32(obj, 12, 0x00000000); - nv_wo32(obj, 16, 0x00000000); - if (dev_priv->card_type < NV_C0) - nv_wo32(obj, 20, 0x00010000); - else - nv_wo32(obj, 20, 0x00020000); - dev_priv->engine.instmem.flush(dev); - - ret = nouveau_ramht_insert(evo, name, obj); - nouveau_gpuobj_ref(NULL, &obj); - if (ret) { - return ret; - } - - return 0; -} - -static int -nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *ramht = NULL; - struct nouveau_channel *chan; - int ret; - - chan = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); - if (!chan) - return -ENOMEM; - *pchan = chan; - - chan->id = -1; - chan->dev = dev; - chan->user_get = 4; - chan->user_put = 0; - - ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); - if (ret) { - NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } - - ret = drm_mm_init(&chan->ramin_heap, 0, 32768); - if (ret) { - NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } - - ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht); - if (ret) { - NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } - - ret = nouveau_ramht_new(dev, ramht, &chan->ramht); - nouveau_gpuobj_ref(NULL, &ramht); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } - - if (dev_priv->chipset != 0x50) { - ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, - 0, 0xffffffff); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } - - - ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB32, 0x7a, 0x19, - 0, 0xffffffff); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } - } - - ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19, - 0, dev_priv->vram_size); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } - - ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, - false, true, &chan->pushbuf_bo); - if (ret == 0) - ret = nouveau_bo_pin(chan->pushbuf_bo, TTM_PL_FLAG_VRAM); - if (ret) { - NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } - - ret = nouveau_bo_map(chan->pushbuf_bo); - if (ret) { - NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } - - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV50_PDISPLAY_USER(0), PAGE_SIZE); - if (!chan->user) { - NV_ERROR(dev, "Error mapping EVO control regs.\n"); - nv50_evo_channel_del(pchan); - return -ENOMEM; - } - - return 0; -} - int nv50_display_early_init(struct drm_device *dev) { @@ -214,12 +61,10 @@ int nv50_display_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; - struct nouveau_channel *evo = dev_priv->evo; struct drm_connector *connector; + struct nouveau_channel *evo; int ret, i; - u64 start; u32 val; NV_DEBUG_KMS(dev, "\n"); @@ -303,7 +148,6 @@ nv50_display_init(struct drm_device *dev) } } - nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000); nv_wr32(dev, 0x610028, 0x00000000); nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000); @@ -323,69 +167,12 @@ nv50_display_init(struct drm_device *dev) pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); } - /* taken from nv bug #12637, attempts to un-wedge the hw if it's - * stuck in some unspecified state - */ - start = ptimer->read(dev); - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x2b00); - while ((val = nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))) & 0x1e0000) { - if ((val & 0x9f0000) == 0x20000) - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), - val | 0x800000); - - if ((val & 0x3f0000) == 0x30000) - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), - val | 0x200000); - - if (ptimer->read(dev) - start > 1000000000ULL) { - NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", val); - return -EBUSY; - } - } - - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); - if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), - 0x40000000, 0x40000000)) { - NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); - return -EBUSY; - } - - /* initialise fifo */ - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), - ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | - NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM | - NV50_PDISPLAY_CHANNEL_DMA_CB_VALID); - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000); - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002); - if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); - return -EBUSY; - } - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), - (nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)) & ~0x00000003) | - NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); - nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0); - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x01000003 | - NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); - - /* enable error reporting on the channel */ - nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << 0); - - evo->dma.max = (4096/4) - 2; - evo->dma.put = 0; - evo->dma.cur = evo->dma.put; - evo->dma.free = evo->dma.max - evo->dma.cur; - - ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS); + ret = nv50_evo_init(dev); if (ret) return ret; + evo = dev_priv->evo; - for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) - OUT_RING(evo, 0); + nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); ret = RING_SPACE(evo, 11); if (ret) @@ -449,12 +236,7 @@ static int nv50_display_disable(struct drm_device *dev) } } - nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); - if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { - NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); - } + nv50_evo_fini(dev); for (i = 0; i < 3; i++) { if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i), @@ -504,13 +286,6 @@ int nv50_display_create(struct drm_device *dev) dev->mode_config.fb_base = dev_priv->fb_phys; - /* Create EVO channel */ - ret = nv50_evo_channel_new(dev, &dev_priv->evo); - if (ret) { - NV_ERROR(dev, "Error creating EVO channel: %d\n", ret); - return ret; - } - /* Create CRTC objects */ for (i = 0; i < 2; i++) nv50_crtc_create(dev, i); @@ -565,14 +340,11 @@ int nv50_display_create(struct drm_device *dev) void nv50_display_destroy(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - NV_DEBUG_KMS(dev, "\n"); drm_mode_config_cleanup(dev); nv50_display_disable(dev); - nv50_evo_channel_del(&dev_priv->evo); } static u16 diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c new file mode 100644 index 000000000000..211f5fb1dc73 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -0,0 +1,295 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" +#include "nouveau_dma.h" +#include "nouveau_ramht.h" + +static void +nv50_evo_channel_del(struct nouveau_channel **pchan) +{ + struct nouveau_channel *chan = *pchan; + + if (!chan) + return; + *pchan = NULL; + + nouveau_gpuobj_channel_takedown(chan); + nouveau_bo_unmap(chan->pushbuf_bo); + nouveau_bo_ref(NULL, &chan->pushbuf_bo); + + if (chan->user) + iounmap(chan->user); + + kfree(chan); +} + +int +nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, + u32 tile_flags, u32 magic_flags, u32 offset, u32 limit) +{ + struct drm_nouveau_private *dev_priv = evo->dev->dev_private; + struct drm_device *dev = evo->dev; + struct nouveau_gpuobj *obj = NULL; + int ret; + + ret = nouveau_gpuobj_new(dev, evo, 6*4, 32, 0, &obj); + if (ret) + return ret; + obj->engine = NVOBJ_ENGINE_DISPLAY; + + nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); + nv_wo32(obj, 4, limit); + nv_wo32(obj, 8, offset); + nv_wo32(obj, 12, 0x00000000); + nv_wo32(obj, 16, 0x00000000); + if (dev_priv->card_type < NV_C0) + nv_wo32(obj, 20, 0x00010000); + else + nv_wo32(obj, 20, 0x00020000); + dev_priv->engine.instmem.flush(dev); + + ret = nouveau_ramht_insert(evo, name, obj); + nouveau_gpuobj_ref(NULL, &obj); + if (ret) { + return ret; + } + + return 0; +} + +static int +nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *ramht = NULL; + struct nouveau_channel *chan; + int ret; + + chan = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); + if (!chan) + return -ENOMEM; + *pchan = chan; + + chan->id = -1; + chan->dev = dev; + chan->user_get = 4; + chan->user_put = 0; + + ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); + if (ret) { + NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); + nv50_evo_channel_del(pchan); + return ret; + } + + ret = drm_mm_init(&chan->ramin_heap, 0, 32768); + if (ret) { + NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); + nv50_evo_channel_del(pchan); + return ret; + } + + ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht); + if (ret) { + NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); + nv50_evo_channel_del(pchan); + return ret; + } + + ret = nouveau_ramht_new(dev, ramht, &chan->ramht); + nouveau_gpuobj_ref(NULL, &ramht); + if (ret) { + nv50_evo_channel_del(pchan); + return ret; + } + + if (dev_priv->chipset != 0x50) { + ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, + 0, 0xffffffff); + if (ret) { + nv50_evo_channel_del(pchan); + return ret; + } + + + ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB32, 0x7a, 0x19, + 0, 0xffffffff); + if (ret) { + nv50_evo_channel_del(pchan); + return ret; + } + } + + ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19, + 0, dev_priv->vram_size); + if (ret) { + nv50_evo_channel_del(pchan); + return ret; + } + + ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, + false, true, &chan->pushbuf_bo); + if (ret == 0) + ret = nouveau_bo_pin(chan->pushbuf_bo, TTM_PL_FLAG_VRAM); + if (ret) { + NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret); + nv50_evo_channel_del(pchan); + return ret; + } + + ret = nouveau_bo_map(chan->pushbuf_bo); + if (ret) { + NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret); + nv50_evo_channel_del(pchan); + return ret; + } + + chan->user = ioremap(pci_resource_start(dev->pdev, 0) + + NV50_PDISPLAY_USER(0), PAGE_SIZE); + if (!chan->user) { + NV_ERROR(dev, "Error mapping EVO control regs.\n"); + nv50_evo_channel_del(pchan); + return -ENOMEM; + } + + return 0; +} + +static int +nv50_evo_channel_init(struct nouveau_channel *evo) +{ + struct drm_nouveau_private *dev_priv = evo->dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + struct drm_device *dev = evo->dev; + int ret, i; + u64 start; + u32 tmp; + + /* taken from nv bug #12637, attempts to un-wedge the hw if it's + * stuck in some unspecified state + */ + start = ptimer->read(dev); + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x2b00); + while ((tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0))) & 0x1e0000) { + if ((tmp & 0x9f0000) == 0x20000) + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), tmp | 0x800000); + + if ((tmp & 0x3f0000) == 0x30000) + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), tmp | 0x200000); + + if (ptimer->read(dev) - start > 1000000000ULL) { + NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", tmp); + return -EBUSY; + } + } + + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x1000b03); + if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(0), + 0x40000000, 0x40000000)) { + NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0))); + return -EBUSY; + } + + /* initialise fifo */ + nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(0), + ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | + NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM | + NV50_PDISPLAY_EVO_DMA_CB_VALID); + nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(0), 0x00010000); + nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(0), 0x00000002); + if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) { + NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); + return -EBUSY; + } + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), + (nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0)) & ~0x00000003) | + NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); + nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0); + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x01000003 | + NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); + + /* enable error reporting on the channel */ + nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << 0); + + evo->dma.max = (4096/4) - 2; + evo->dma.put = 0; + evo->dma.cur = evo->dma.put; + evo->dma.free = evo->dma.max - evo->dma.cur; + + ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS); + if (ret) + return ret; + + for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) + OUT_RING(evo, 0); + + return 0; +} + +static void +nv50_evo_channel_fini(struct nouveau_channel *evo) +{ + struct drm_device *dev = evo->dev; + + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0); + if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x1e0000, 0)) { + NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); + NV_ERROR(dev, "0x610200 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0))); + } +} + +int +nv50_evo_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + if (!dev_priv->evo) { + ret = nv50_evo_channel_new(dev, &dev_priv->evo); + if (ret) + return ret; + } + + return nv50_evo_channel_init(dev_priv->evo); +} + +void +nv50_evo_fini(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->evo) { + nv50_evo_channel_fini(dev_priv->evo); + nv50_evo_channel_del(&dev_priv->evo); + } +} diff --git a/drivers/gpu/drm/nouveau/nv50_evo.h b/drivers/gpu/drm/nouveau/nv50_evo.h index aae13343bcec..aa4f0d3cea8e 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.h +++ b/drivers/gpu/drm/nouveau/nv50_evo.h @@ -24,6 +24,15 @@ * */ +#ifndef __NV50_EVO_H__ +#define __NV50_EVO_H__ + +int nv50_evo_init(struct drm_device *dev); +void nv50_evo_fini(struct drm_device *dev); +int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name, + u32 tile_flags, u32 magic_flags, + u32 offset, u32 limit); + #define NV50_EVO_UPDATE 0x00000080 #define NV50_EVO_UNK84 0x00000084 #define NV50_EVO_UNK84_NOTIFY 0x40000000 @@ -111,3 +120,4 @@ #define NV50_EVO_CRTC_SCALE_RES1 0x000008d8 #define NV50_EVO_CRTC_SCALE_RES2 0x000008dc +#endif -- cgit v1.2.3 From 1e96268aca1bb40f42bdbc9d2293b123b072f1de Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 14:18:06 +1000 Subject: drm/nv50: initial work to allow multiple evo channels This doesn't work yet for unknown reasons. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_ramht.c | 2 +- drivers/gpu/drm/nouveau/nv50_evo.c | 246 +++++++++++++++++++------------- 3 files changed, 147 insertions(+), 102 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d15bfd427267..bf34f25c7a54 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -689,6 +689,7 @@ struct drm_nouveau_private { struct backlight_device *backlight; struct nouveau_channel *evo; + u32 evo_alloc; struct { struct dcb_entry *dcb; u16 script; diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c index b4c63c058888..d4a2adc927d8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.c +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c @@ -114,7 +114,7 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } else { if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { - ctx = (gpuobj->cinst << 10) | 2; + ctx = (gpuobj->cinst << 10) | chan->id; } else { ctx = (gpuobj->cinst >> 4) | ((gpuobj->engine << diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index 211f5fb1dc73..dbad233e750f 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -29,22 +29,26 @@ #include "nouveau_ramht.h" static void -nv50_evo_channel_del(struct nouveau_channel **pchan) +nv50_evo_channel_del(struct nouveau_channel **pevo) { - struct nouveau_channel *chan = *pchan; + struct drm_nouveau_private *dev_priv; + struct nouveau_channel *evo = *pevo; - if (!chan) + if (!evo) return; - *pchan = NULL; + *pevo = NULL; - nouveau_gpuobj_channel_takedown(chan); - nouveau_bo_unmap(chan->pushbuf_bo); - nouveau_bo_ref(NULL, &chan->pushbuf_bo); + dev_priv = evo->dev->dev_private; + dev_priv->evo_alloc &= ~(1 << evo->id); - if (chan->user) - iounmap(chan->user); + nouveau_gpuobj_channel_takedown(evo); + nouveau_bo_unmap(evo->pushbuf_bo); + nouveau_bo_ref(NULL, &evo->pushbuf_bo); - kfree(chan); + if (evo->user) + iounmap(evo->user); + + kfree(evo); } int @@ -56,7 +60,7 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, struct nouveau_gpuobj *obj = NULL; int ret; - ret = nouveau_gpuobj_new(dev, evo, 6*4, 32, 0, &obj); + ret = nouveau_gpuobj_new(dev, dev_priv->evo, 6*4, 32, 0, &obj); if (ret) return ret; obj->engine = NVOBJ_ENGINE_DISPLAY; @@ -82,101 +86,63 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, } static int -nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) +nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pevo) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *ramht = NULL; - struct nouveau_channel *chan; + struct nouveau_channel *evo; int ret; - chan = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); - if (!chan) + evo = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); + if (!evo) return -ENOMEM; - *pchan = chan; - - chan->id = -1; - chan->dev = dev; - chan->user_get = 4; - chan->user_put = 0; - - ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); - if (ret) { - NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } - - ret = drm_mm_init(&chan->ramin_heap, 0, 32768); - if (ret) { - NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } + *pevo = evo; - ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht); - if (ret) { - NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); - nv50_evo_channel_del(pchan); - return ret; - } + for (evo->id = 0; evo->id < 5; evo->id++) { + if (dev_priv->evo_alloc & (1 << evo->id)) + continue; - ret = nouveau_ramht_new(dev, ramht, &chan->ramht); - nouveau_gpuobj_ref(NULL, &ramht); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; + dev_priv->evo_alloc |= (1 << evo->id); + break; } - if (dev_priv->chipset != 0x50) { - ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, - 0, 0xffffffff); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } - - - ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB32, 0x7a, 0x19, - 0, 0xffffffff); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } + if (evo->id == 5) { + kfree(evo); + return -ENODEV; } - ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19, - 0, dev_priv->vram_size); - if (ret) { - nv50_evo_channel_del(pchan); - return ret; - } + evo->dev = dev; + evo->user_get = 4; + evo->user_put = 0; ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, - false, true, &chan->pushbuf_bo); + false, true, &evo->pushbuf_bo); if (ret == 0) - ret = nouveau_bo_pin(chan->pushbuf_bo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM); if (ret) { NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret); - nv50_evo_channel_del(pchan); + nv50_evo_channel_del(pevo); return ret; } - ret = nouveau_bo_map(chan->pushbuf_bo); + ret = nouveau_bo_map(evo->pushbuf_bo); if (ret) { NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret); - nv50_evo_channel_del(pchan); + nv50_evo_channel_del(pevo); return ret; } - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + - NV50_PDISPLAY_USER(0), PAGE_SIZE); - if (!chan->user) { + evo->user = ioremap(pci_resource_start(dev->pdev, 0) + + NV50_PDISPLAY_USER(evo->id), PAGE_SIZE); + if (!evo->user) { NV_ERROR(dev, "Error mapping EVO control regs.\n"); - nv50_evo_channel_del(pchan); + nv50_evo_channel_del(pevo); return -ENOMEM; } + /* bind primary evo channel's ramht to the channel */ + if (dev_priv->evo && evo != dev_priv->evo) + nouveau_ramht_ref(dev_priv->evo->ramht, &evo->ramht, NULL); + return 0; } @@ -186,7 +152,7 @@ nv50_evo_channel_init(struct nouveau_channel *evo) struct drm_nouveau_private *dev_priv = evo->dev->dev_private; struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; struct drm_device *dev = evo->dev; - int ret, i; + int id = evo->id, ret, i; u64 start; u32 tmp; @@ -194,13 +160,13 @@ nv50_evo_channel_init(struct nouveau_channel *evo) * stuck in some unspecified state */ start = ptimer->read(dev); - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x2b00); - while ((tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0))) & 0x1e0000) { + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x2b00); + while ((tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))) & 0x1e0000) { if ((tmp & 0x9f0000) == 0x20000) - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), tmp | 0x800000); + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x800000); if ((tmp & 0x3f0000) == 0x30000) - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), tmp | 0x200000); + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x200000); if (ptimer->read(dev) - start > 1000000000ULL) { NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n"); @@ -209,36 +175,37 @@ nv50_evo_channel_init(struct nouveau_channel *evo) } } - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x1000b03); - if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(0), + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x1000b03); + if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x40000000, 0x40000000)) { NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); NV_ERROR(dev, "0x610200 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0))); + nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); return -EBUSY; } /* initialise fifo */ - nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(0), + nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(id), ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM | NV50_PDISPLAY_EVO_DMA_CB_VALID); - nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(0), 0x00010000); - nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(0), 0x00000002); - if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) { + nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000); + nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(id), id); + if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) { NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); + NV_ERROR(dev, "0x610200 = 0x%08x\n", + nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); return -EBUSY; } - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), - (nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0)) & ~0x00000003) | + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), + (nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)) & ~0x00000003) | NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); - nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0); - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x01000003 | - NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); + nv_wr32(dev, NV50_PDISPLAY_USER_PUT(id), 0); + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 | + NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); /* enable error reporting on the channel */ - nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << 0); + nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id); evo->dma.max = (4096/4) - 2; evo->dma.put = 0; @@ -260,12 +227,89 @@ nv50_evo_channel_fini(struct nouveau_channel *evo) { struct drm_device *dev = evo->dev; - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(0), 0); - if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(0), 0x1e0000, 0)) { + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(evo->id), 0); + if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(evo->id), 0x1e0000, 0)) { NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); NV_ERROR(dev, "0x610200 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(0))); + nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(evo->id))); + } +} + +static int +nv50_evo_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *ramht = NULL; + struct nouveau_channel *evo; + int ret; + + /* create primary evo channel, the one we use for modesetting + * purporses + */ + ret = nv50_evo_channel_new(dev, &dev_priv->evo); + if (ret) + return ret; + evo = dev_priv->evo; + + /* setup object management on it, any other evo channel will + * use this also as there's no per-channel support on the + * hardware + */ + ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin); + if (ret) { + NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + ret = drm_mm_init(&evo->ramin_heap, 0, 32768); + if (ret) { + NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + ret = nouveau_gpuobj_new(dev, evo, 4096, 16, 0, &ramht); + if (ret) { + NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + ret = nouveau_ramht_new(dev, ramht, &evo->ramht); + nouveau_gpuobj_ref(NULL, &ramht); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + /* create some default objects for the scanout memtypes we support */ + if (dev_priv->chipset != 0x50) { + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19, + 0, 0xffffffff); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0x7a, 0x19, + 0, 0xffffffff); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + } + + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, + 0, dev_priv->vram_size); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; } + + return 0; } int @@ -275,7 +319,7 @@ nv50_evo_init(struct drm_device *dev) int ret; if (!dev_priv->evo) { - ret = nv50_evo_channel_new(dev, &dev_priv->evo); + ret = nv50_evo_create(dev); if (ret) return ret; } -- cgit v1.2.3 From 43ce028ff2b1df68c690f0af14a109288d3e9e86 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 19 Oct 2010 18:01:41 +1000 Subject: drm/nv50: rework evo init to match nvidia more closely Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_evo.c | 73 ++++++++++++++------------------------ 1 file changed, 26 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index dbad233e750f..d270f17a5310 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -149,60 +149,36 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pevo) static int nv50_evo_channel_init(struct nouveau_channel *evo) { - struct drm_nouveau_private *dev_priv = evo->dev->dev_private; - struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; struct drm_device *dev = evo->dev; int id = evo->id, ret, i; - u64 start; + u64 pushbuf = evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT; u32 tmp; - /* taken from nv bug #12637, attempts to un-wedge the hw if it's - * stuck in some unspecified state - */ - start = ptimer->read(dev); - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x2b00); - while ((tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))) & 0x1e0000) { - if ((tmp & 0x9f0000) == 0x20000) - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x800000); - - if ((tmp & 0x3f0000) == 0x30000) - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x200000); - - if (ptimer->read(dev) - start > 1000000000ULL) { - NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", tmp); - return -EBUSY; - } - } + tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)); + if ((tmp & 0x009f0000) == 0x00020000) + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00800000); - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x1000b03); - if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), - 0x40000000, 0x40000000)) { - NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); - return -EBUSY; - } + tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)); + if ((tmp & 0x003f0000) == 0x00030000) + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00600000); /* initialise fifo */ - nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(id), - ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | - NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM | - NV50_PDISPLAY_EVO_DMA_CB_VALID); + nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(id), pushbuf >> 8 | + NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM | + NV50_PDISPLAY_EVO_DMA_CB_VALID); nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000); nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(id), id); + nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), NV50_PDISPLAY_EVO_CTRL_DMA, + NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); + + nv_wr32(dev, NV50_PDISPLAY_USER_PUT(id), 0x00000000); + nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 | + NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", + NV_ERROR(dev, "EvoCh %d init timeout: 0x%08x\n", id, nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); return -EBUSY; } - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), - (nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)) & ~0x00000003) | - NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); - nv_wr32(dev, NV50_PDISPLAY_USER_PUT(id), 0); - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 | - NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); /* enable error reporting on the channel */ nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id); @@ -226,12 +202,15 @@ static void nv50_evo_channel_fini(struct nouveau_channel *evo) { struct drm_device *dev = evo->dev; - - nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(evo->id), 0); - if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(evo->id), 0x1e0000, 0)) { - NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); - NV_ERROR(dev, "0x610200 = 0x%08x\n", - nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(evo->id))); + int id = evo->id; + + nv_mask(dev, 0x610028, 0x00010001 << id, 0x00000000); + nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000); + nv_wr32(dev, NV50_PDISPLAY_INTR_0, (1 << id)); + nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00000003, 0x00000000); + if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x001e0000, 0x00000000)) { + NV_ERROR(dev, "EvoCh %d takedown timeout: 0x%08x\n", id, + nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); } } -- cgit v1.2.3 From 97e2000f757c19bb53e032320669f9a0d0b2a989 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 20 Oct 2010 14:23:29 +1000 Subject: drm/nv50: improve evo error handler when more than just channel 0 active Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_reg.h | 21 +++++++++--------- drivers/gpu/drm/nouveau/nv50_display.c | 40 +++++++++++++++++++--------------- drivers/gpu/drm/nouveau/nv50_graph.c | 11 +++++----- 3 files changed, 39 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index d0ce86c24ebf..b6384d36d5d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -715,20 +715,21 @@ #define NV50_PDISPLAY_INTR_1_CLK_UNK10 0x00000010 #define NV50_PDISPLAY_INTR_1_CLK_UNK20 0x00000020 #define NV50_PDISPLAY_INTR_1_CLK_UNK40 0x00000040 -#define NV50_PDISPLAY_INTR_EN 0x0061002c -#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC 0x0000000c -#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(n) (1 << ((n) + 2)) -#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_0 0x00000004 -#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_1 0x00000008 -#define NV50_PDISPLAY_INTR_EN_CLK_UNK10 0x00000010 -#define NV50_PDISPLAY_INTR_EN_CLK_UNK20 0x00000020 -#define NV50_PDISPLAY_INTR_EN_CLK_UNK40 0x00000040 +#define NV50_PDISPLAY_INTR_EN_0 0x00610028 +#define NV50_PDISPLAY_INTR_EN_1 0x0061002c +#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC 0x0000000c +#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(n) (1 << ((n) + 2)) +#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_0 0x00000004 +#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_1 0x00000008 +#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 0x00000010 +#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 0x00000020 +#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK40 0x00000040 #define NV50_PDISPLAY_UNK30_CTRL 0x00610030 #define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 0x00000200 #define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 0x00000400 #define NV50_PDISPLAY_UNK30_CTRL_PENDING 0x80000000 -#define NV50_PDISPLAY_TRAPPED_ADDR 0x00610080 -#define NV50_PDISPLAY_TRAPPED_DATA 0x00610084 +#define NV50_PDISPLAY_TRAPPED_ADDR(i) ((i) * 0x08 + 0x00610080) +#define NV50_PDISPLAY_TRAPPED_DATA(i) ((i) * 0x08 + 0x00610084) #define NV50_PDISPLAY_EVO_CTRL(i) ((i) * 0x10 + 0x00610200) #define NV50_PDISPLAY_EVO_CTRL_DMA 0x00000010 #define NV50_PDISPLAY_EVO_CTRL_DMA_DISABLED 0x00000000 diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index db100a8f231e..99871e304d10 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -149,13 +149,13 @@ nv50_display_init(struct drm_device *dev) } nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000); - nv_wr32(dev, 0x610028, 0x00000000); nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000); + nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000); nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000); - nv_wr32(dev, NV50_PDISPLAY_INTR_EN, - NV50_PDISPLAY_INTR_EN_CLK_UNK10 | - NV50_PDISPLAY_INTR_EN_CLK_UNK20 | - NV50_PDISPLAY_INTR_EN_CLK_UNK40); + nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, + NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 | + NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 | + NV50_PDISPLAY_INTR_EN_1_CLK_UNK40); /* enable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -248,7 +248,7 @@ static int nv50_display_disable(struct drm_device *dev) } /* disable interrupts. */ - nv_wr32(dev, NV50_PDISPLAY_INTR_EN, 0x00000000); + nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000); /* disable hotplug interrupts */ nv_wr32(dev, 0xe054, 0xffffffff); @@ -451,8 +451,7 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1) nv50_display_vblank_crtc_handler(dev, 1); - nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev, - NV50_PDISPLAY_INTR_EN) & ~intr); + nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, intr, 0x00000000); nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr); } @@ -779,16 +778,23 @@ nv50_display_irq_handler_bh(struct work_struct *work) static void nv50_display_error_handler(struct drm_device *dev) { - uint32_t addr, data; + u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16; + u32 addr, data; + int chid; - nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000); - addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR); - data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA); + for (chid = 0; chid < 5; chid++) { + if (!(channels & (1 << chid))) + continue; - NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x (0x%04x 0x%02x)\n", - 0, addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf); + nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid); + addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid)); + data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid)); + NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x " + "(0x%04x 0x%02x)\n", chid, + addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf); - nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000); + nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000); + } } void @@ -891,9 +897,9 @@ nv50_display_irq_handler(struct drm_device *dev) if (!intr0 && !(intr1 & ~delayed)) break; - if (intr0 & 0x00010000) { + if (intr0 & 0x001f0000) { nv50_display_error_handler(dev); - intr0 &= ~0x00010000; + intr0 &= ~0x001f0000; } if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) { diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index a764af52a3ba..d441308a09cf 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -384,13 +384,12 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1) return -EINVAL; - if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN) & - NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data))) { + if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN_1) & + NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data))) { nv_wr32(dev, NV50_PDISPLAY_INTR_1, - NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data)); - nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev, - NV50_PDISPLAY_INTR_EN) | - NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data)); + NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data)); + nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0, + NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data)); } list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); -- cgit v1.2.3 From 8888cb18ffd1f32c51e61ca8d3d179c3c3946d1e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 20 Oct 2010 15:35:28 +1000 Subject: drm/nv50: fix evo instmem alignment Not an issue right now, we're forced to 64k size/alignment by the BO allocator anyway. This won't be the case soon. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_evo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index d270f17a5310..887b2a97e2a2 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -234,7 +234,7 @@ nv50_evo_create(struct drm_device *dev) * use this also as there's no per-channel support on the * hardware */ - ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, + ret = nouveau_gpuobj_new(dev, NULL, 32768, 65536, NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin); if (ret) { NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); -- cgit v1.2.3 From 01d63187d1aad6236dd229d5824c61a60f1ab42c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 21 Oct 2010 11:37:21 +1000 Subject: drm/nv10: fix thinko and let nv17 do 3d again :) Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv10_graph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 17c20dbff232..a571bfd4471b 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -1102,7 +1102,7 @@ nv10_graph_register(struct drm_device *dev) if (dev_priv->chipset <= 0x10) { NVOBJ_CLASS(dev, 0x0056, GR); } else - if (dev_priv->chipset <= 0x17 || dev_priv->chipset == 0x1a) { + if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) { NVOBJ_CLASS(dev, 0x0096, GR); } else { NVOBJ_CLASS(dev, 0x0099, GR); -- cgit v1.2.3 From 35fa2f2ad161024e735fb0cd571cb92e50171afd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 21 Oct 2010 14:07:03 +1000 Subject: drm/nouveau: add support for MSI Only supported on NV50+ so far, and disabled by default currently. The module parameter "msi=1" will enable it. There's a kernel bug which will cause this to fail if the module (or the NVIDIA binary driver) has ever been loaded before loading nouveau with MSI enabled. As such, this is only safe to enable if you have nouveau load on boot, and don't wish to ever reload it. The workaround is to "echo 0 > /sys/bus/pci/devices//enable" until the enable count reads 0. Then you should be able to load nouveau with MSI enabled. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.c | 4 ++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++++ drivers/gpu/drm/nouveau/nouveau_irq.c | 35 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_state.c | 9 +++------ 4 files changed, 47 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 6dbb8818c530..db926ecf5b6f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -115,6 +115,10 @@ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n"); int nouveau_perflvl_wr; module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); +MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n"); +int nouveau_msi; +module_param_named(msi, nouveau_msi, int, 0400); + int nouveau_fbpercrtc; #if 0 module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index bf34f25c7a54..9ab7dc8ede4e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -593,6 +593,8 @@ struct drm_nouveau_private { struct nouveau_bo *vga_ram; + /* interrupt handling */ + bool msi_enabled; struct workqueue_struct *wq; struct work_struct irq_work; struct work_struct hpd_work; @@ -754,6 +756,7 @@ extern int nouveau_force_post; extern int nouveau_override_conntype; extern char *nouveau_perflvl; extern int nouveau_perflvl_wr; +extern int nouveau_msi; extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); extern int nouveau_pci_resume(struct pci_dev *pdev); @@ -872,6 +875,8 @@ extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, struct drm_file *); /* nouveau_irq.c */ +extern int nouveau_irq_init(struct drm_device *); +extern void nouveau_irq_fini(struct drm_device *); extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); extern void nouveau_irq_preinstall(struct drm_device *); extern int nouveau_irq_postinstall(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index ca9b969f4f9c..17e2fa86cde7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -68,8 +68,13 @@ nouveau_irq_preinstall(struct drm_device *dev) int nouveau_irq_postinstall(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + /* Master enable */ nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE); + if (dev_priv->msi_enabled) + nv_wr08(dev, 0x00088068, 0xff); + return 0; } @@ -1263,5 +1268,35 @@ nouveau_irq_handler(DRM_IRQ_ARGS) spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + if (dev_priv->msi_enabled) + nv_wr08(dev, 0x00088068, 0xff); + return IRQ_HANDLED; } + +int +nouveau_irq_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) { + ret = pci_enable_msi(dev->pdev); + if (ret == 0) { + NV_INFO(dev, "enabled MSI\n"); + dev_priv->msi_enabled = true; + } + } + + return drm_irq_install(dev); +} + +void +nouveau_irq_fini(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + drm_irq_uninstall(dev); + if (dev_priv->msi_enabled) + pci_disable_msi(dev->pdev); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index f13134aa8c4f..410a79f5e0cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -667,10 +667,7 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_fifo; - /* this call irq_preinstall, register irq handler and - * call irq_postinstall - */ - ret = drm_irq_install(dev); + ret = nouveau_irq_init(dev); if (ret) goto out_display; @@ -701,7 +698,7 @@ nouveau_card_init(struct drm_device *dev) out_fence: nouveau_fence_fini(dev); out_irq: - drm_irq_uninstall(dev); + nouveau_irq_fini(dev); out_display: engine->display.destroy(dev); out_fifo: @@ -772,7 +769,7 @@ static void nouveau_card_takedown(struct drm_device *dev) nouveau_gpuobj_takedown(dev); nouveau_mem_vram_fini(dev); - drm_irq_uninstall(dev); + nouveau_irq_fini(dev); nouveau_pm_fini(dev); nouveau_bios_takedown(dev); -- cgit v1.2.3 From 5f80198e43cf96542923269ccb607052e5f144cc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 22 Oct 2010 08:44:09 +1000 Subject: drm/nv50: regression fix, point NVAA/NVAC at correct PM functions Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 410a79f5e0cd..c5f29f0d18da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -397,6 +397,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) case 0x96: case 0x98: case 0xa0: + case 0xaa: + case 0xac: case 0x50: engine->pm.clock_get = nv50_pm_clock_get; engine->pm.clock_pre = nv50_pm_clock_pre; -- cgit v1.2.3 From 382d62e524db528cdf53563ad9a018adc170dfde Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 20 Oct 2010 21:50:24 +0200 Subject: drm/nouveau: fix annoying nouveau_fence type issue nouveau_fence_* functions are not type safe, which could lead to bugs. Additionally every use of nouveau_fence_unref had to cast struct nouveau_fence to void **. Fix it by renaming old functions and creating static inline functions with new prototypes. We still need old functions, because we pass function pointers to ttm. As we are wrapping functions, drop unused "void *arg" parameter where possible. Signed-off-by: Marcin Slusarz Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 12 +++++------ drivers/gpu/drm/nouveau/nouveau_channel.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_drv.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_drv.h | 33 ++++++++++++++++++++++++++----- drivers/gpu/drm/nouveau/nouveau_fence.c | 22 ++++++++++----------- drivers/gpu/drm/nouveau/nouveau_gem.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_mem.c | 4 ++-- 7 files changed, 53 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 8442bfbf5d42..c09928322eb9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -487,7 +487,7 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict, no_wait_reserve, no_wait_gpu, new_mem); - nouveau_fence_unref((void *)&fence); + nouveau_fence_unref(&fence); return ret; } @@ -949,11 +949,11 @@ struct ttm_bo_driver nouveau_bo_driver = { .evict_flags = nouveau_bo_evict_flags, .move = nouveau_bo_move, .verify_access = nouveau_bo_verify_access, - .sync_obj_signaled = nouveau_fence_signalled, - .sync_obj_wait = nouveau_fence_wait, - .sync_obj_flush = nouveau_fence_flush, - .sync_obj_unref = nouveau_fence_unref, - .sync_obj_ref = nouveau_fence_ref, + .sync_obj_signaled = __nouveau_fence_signalled, + .sync_obj_wait = __nouveau_fence_wait, + .sync_obj_flush = __nouveau_fence_flush, + .sync_obj_unref = __nouveau_fence_unref, + .sync_obj_ref = __nouveau_fence_ref, .fault_reserve_notify = &nouveau_ttm_fault_reserve_notify, .io_mem_reserve = &nouveau_ttm_io_mem_reserve, .io_mem_free = &nouveau_ttm_io_mem_free, diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index f2d674202369..c9cdbd786dae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -303,8 +303,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) ret = nouveau_fence_new(chan, &fence, true); if (ret == 0) { - ret = nouveau_fence_wait(fence, NULL, false, false); - nouveau_fence_unref((void *)&fence); + ret = nouveau_fence_wait(fence, false, false); + nouveau_fence_unref(&fence); } if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index db926ecf5b6f..15f48493d0d8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -205,8 +205,8 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) ret = nouveau_fence_new(chan, &fence, true); if (ret == 0) { - ret = nouveau_fence_wait(fence, NULL, false, false); - nouveau_fence_unref((void *)&fence); + ret = nouveau_fence_wait(fence, false, false); + nouveau_fence_unref(&fence); } if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 9ab7dc8ede4e..a356d894a2ee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1264,12 +1264,35 @@ extern void nouveau_fence_work(struct nouveau_fence *fence, void (*work)(void *priv, bool signalled), void *priv); struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *); -extern bool nouveau_fence_signalled(void *obj, void *arg); -extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); + +extern bool __nouveau_fence_signalled(void *obj, void *arg); +extern int __nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); +extern int __nouveau_fence_flush(void *obj, void *arg); +extern void __nouveau_fence_unref(void **obj); +extern void *__nouveau_fence_ref(void *obj); + +static inline bool nouveau_fence_signalled(struct nouveau_fence *obj) +{ + return __nouveau_fence_signalled(obj, NULL); +} +static inline int +nouveau_fence_wait(struct nouveau_fence *obj, bool lazy, bool intr) +{ + return __nouveau_fence_wait(obj, NULL, lazy, intr); +} extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *); -extern int nouveau_fence_flush(void *obj, void *arg); -extern void nouveau_fence_unref(void **obj); -extern void *nouveau_fence_ref(void *obj); +static inline int nouveau_fence_flush(struct nouveau_fence *obj) +{ + return __nouveau_fence_flush(obj, NULL); +} +static inline void nouveau_fence_unref(struct nouveau_fence **obj) +{ + __nouveau_fence_unref((void **)obj); +} +static inline struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *obj) +{ + return __nouveau_fence_ref(obj); +} /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 75ce1b45d8a4..91aa6c54cc96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -120,7 +120,7 @@ nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence, ret = nouveau_fence_emit(fence); if (ret) - nouveau_fence_unref((void *)&fence); + nouveau_fence_unref(&fence); *pfence = fence; return ret; } @@ -183,7 +183,7 @@ nouveau_fence_work(struct nouveau_fence *fence, } void -nouveau_fence_unref(void **sync_obj) +__nouveau_fence_unref(void **sync_obj) { struct nouveau_fence *fence = nouveau_fence(*sync_obj); @@ -193,7 +193,7 @@ nouveau_fence_unref(void **sync_obj) } void * -nouveau_fence_ref(void *sync_obj) +__nouveau_fence_ref(void *sync_obj) { struct nouveau_fence *fence = nouveau_fence(sync_obj); @@ -202,7 +202,7 @@ nouveau_fence_ref(void *sync_obj) } bool -nouveau_fence_signalled(void *sync_obj, void *sync_arg) +__nouveau_fence_signalled(void *sync_obj, void *sync_arg) { struct nouveau_fence *fence = nouveau_fence(sync_obj); struct nouveau_channel *chan = fence->channel; @@ -215,13 +215,13 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg) } int -nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) +__nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) { unsigned long timeout = jiffies + (3 * DRM_HZ); int ret = 0; while (1) { - if (nouveau_fence_signalled(sync_obj, sync_arg)) + if (__nouveau_fence_signalled(sync_obj, sync_arg)) break; if (time_after_eq(jiffies, timeout)) { @@ -369,7 +369,7 @@ emit_semaphore(struct nouveau_channel *chan, int method, kref_get(&sema->ref); nouveau_fence_work(fence, semaphore_work, sema); - nouveau_fence_unref((void *)&fence); + nouveau_fence_unref(&fence); return 0; } @@ -384,14 +384,14 @@ nouveau_fence_sync(struct nouveau_fence *fence, int ret = 0; if (likely(!chan || chan == wchan || - nouveau_fence_signalled(fence, NULL))) + nouveau_fence_signalled(fence))) goto out; sema = alloc_semaphore(dev); if (!sema) { /* Early card or broken userspace, fall back to * software sync. */ - ret = nouveau_fence_wait(fence, NULL, true, false); + ret = nouveau_fence_wait(fence, true, false); goto out; } @@ -400,7 +400,7 @@ nouveau_fence_sync(struct nouveau_fence *fence, * order issues */ if (!mutex_trylock(&chan->mutex)) { - ret = nouveau_fence_wait(fence, NULL, true, false); + ret = nouveau_fence_wait(fence, true, false); goto out_unref; } @@ -423,7 +423,7 @@ out: } int -nouveau_fence_flush(void *sync_obj, void *sync_arg) +__nouveau_fence_flush(void *sync_obj, void *sync_arg) { return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 23b521ea8e04..de8535b58710 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -238,7 +238,7 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) prev_fence = nvbo->bo.sync_obj; nvbo->bo.sync_obj = nouveau_fence_ref(fence); spin_unlock(&nvbo->bo.bdev->fence_lock); - nouveau_fence_unref((void *)&prev_fence); + nouveau_fence_unref(&prev_fence); } if (unlikely(nvbo->validate_mapped)) { @@ -728,7 +728,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, out: validate_fini(&op, fence); - nouveau_fence_unref((void**)&fence); + nouveau_fence_unref(&fence); kfree(bo); kfree(push); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index fe4a30dc4b42..a7c3e08aa7b5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -54,7 +54,7 @@ nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, tile->addr = addr; tile->size = size; tile->used = !!pitch; - nouveau_fence_unref((void **)&tile->fence); + nouveau_fence_unref(&tile->fence); pfifo->reassign(dev, false); pfifo->cache_pull(dev, false); @@ -87,7 +87,7 @@ nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, continue; if (tile->fence && - !nouveau_fence_signalled(tile->fence, NULL)) + !nouveau_fence_signalled(tile->fence)) /* Pending tile region. */ continue; -- cgit v1.2.3 From 63f7fcfebd2ff1995b649101d6120b60fa0e5b06 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 22 Oct 2010 04:31:02 +0200 Subject: drm/nv04: Make CRTC base changes effective in the next hsync. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hw.c | 2 +- drivers/gpu/drm/nouveau/nv04_crtc.c | 5 ++++- drivers/gpu/drm/nouveau/nvreg.h | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index b9672a05c411..979275836985 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -953,7 +953,7 @@ nv_load_state_ext(struct drm_device *dev, int head, NVWriteCRTC(dev, head, NV_PCRTC_850, regp->crtc_850); reg900 = NVReadRAMDAC(dev, head, NV_PRAMDAC_900); - if (regp->crtc_cfg == NV_PCRTC_CONFIG_START_ADDRESS_HSYNC) + if (regp->crtc_cfg == NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC) NVWriteRAMDAC(dev, head, NV_PRAMDAC_900, reg900 | 0x10000); else NVWriteRAMDAC(dev, head, NV_PRAMDAC_900, reg900 & ~0x10000); diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 40e180741629..b61a7ff8b7b7 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -551,7 +551,10 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) if (dev_priv->card_type >= NV_30) regp->gpio_ext = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT); - regp->crtc_cfg = NV_PCRTC_CONFIG_START_ADDRESS_HSYNC; + if (dev_priv->card_type >= NV_10) + regp->crtc_cfg = NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC; + else + regp->crtc_cfg = NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC; /* Some misc regs */ if (dev_priv->card_type == NV_40) { diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h index 881f8a585613..fe0f253089ac 100644 --- a/drivers/gpu/drm/nouveau/nvreg.h +++ b/drivers/gpu/drm/nouveau/nvreg.h @@ -153,7 +153,8 @@ #define NV_PCRTC_START 0x00600800 #define NV_PCRTC_CONFIG 0x00600804 # define NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA (1 << 0) -# define NV_PCRTC_CONFIG_START_ADDRESS_HSYNC (2 << 0) +# define NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC (4 << 0) +# define NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC (2 << 0) #define NV_PCRTC_CURSOR_CONFIG 0x00600810 # define NV_PCRTC_CURSOR_CONFIG_ENABLE_ENABLE (1 << 0) # define NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE (1 << 4) -- cgit v1.2.3 From 042206c0cd4924879c4292c5ffa2bf1e8023ae5a Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 21 Oct 2010 18:19:29 +0200 Subject: drm/nouveau: Implement the vblank DRM hooks. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 27 +++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_drv.c | 4 ++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++++ drivers/gpu/drm/nouveau/nouveau_hw.c | 5 +++-- drivers/gpu/drm/nouveau/nouveau_irq.c | 8 ++++++-- drivers/gpu/drm/nouveau/nouveau_state.c | 12 +++++++----- drivers/gpu/drm/nouveau/nv50_display.c | 16 +++++++--------- drivers/gpu/drm/nouveau/nv50_graph.c | 9 +-------- 8 files changed, 59 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 2e11fd65b4dd..f8987bcb7f51 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -29,6 +29,7 @@ #include "nouveau_drv.h" #include "nouveau_fb.h" #include "nouveau_fbcon.h" +#include "nouveau_hw.h" static void nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) @@ -104,3 +105,29 @@ const struct drm_mode_config_funcs nouveau_mode_config_funcs = { .output_poll_changed = nouveau_fbcon_output_poll_changed, }; +int +nouveau_vblank_enable(struct drm_device *dev, int crtc) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->card_type >= NV_50) + nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0, + NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc)); + else + NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, + NV_PCRTC_INTR_0_VBLANK); + + return 0; +} + +void +nouveau_vblank_disable(struct drm_device *dev, int crtc) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (dev_priv->card_type >= NV_50) + nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, + NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0); + else + NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 15f48493d0d8..52f9307d7396 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -397,6 +397,9 @@ static struct drm_driver driver = { .irq_postinstall = nouveau_irq_postinstall, .irq_uninstall = nouveau_irq_uninstall, .irq_handler = nouveau_irq_handler, + .get_vblank_counter = drm_vblank_count, + .enable_vblank = nouveau_vblank_enable, + .disable_vblank = nouveau_vblank_disable, .reclaim_buffers = drm_core_reclaim_buffers, .ioctls = nouveau_ioctls, .fops = { @@ -407,6 +410,7 @@ static struct drm_driver driver = { .mmap = nouveau_ttm_mmap, .poll = drm_poll, .fasync = drm_fasync, + .read = drm_read, #if defined(CONFIG_COMPAT) .compat_ioctl = nouveau_compat_ioctl, #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a356d894a2ee..7cf034fd5cd0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1312,6 +1312,10 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); +/* nouveau_display.c */ +int nouveau_vblank_enable(struct drm_device *dev, int crtc); +void nouveau_vblank_disable(struct drm_device *dev, int crtc); + /* nv10_gpio.c */ int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index 979275836985..6ba640e7a7e9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -1017,8 +1017,9 @@ nv_load_state_ext(struct drm_device *dev, int head, NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start); - /* Setting 1 on this value gives you interrupts for every vblank period. */ - NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, 0); + /* Enable vblank interrupts. */ + NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, + (dev->vblank_enabled[head] ? 1 : 0)); NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK); } diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 17e2fa86cde7..f3ae74ef3318 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -1200,11 +1200,15 @@ nv50_pgraph_irq_handler(struct drm_device *dev) static void nouveau_crtc_irq_handler(struct drm_device *dev, int crtc) { - if (crtc & 1) + if (crtc & 1) { nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); + drm_handle_vblank(dev, 0); + } - if (crtc & 2) + if (crtc & 2) { nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); + drm_handle_vblank(dev, 1); + } } irqreturn_t diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index c5f29f0d18da..d72aa8d19a19 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -669,13 +669,13 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_fifo; - ret = nouveau_irq_init(dev); + ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1); if (ret) - goto out_display; + goto out_vblank; - ret = drm_vblank_init(dev, 0); + ret = nouveau_irq_init(dev); if (ret) - goto out_irq; + goto out_vblank; /* what about PVIDEO/PCRTC/PRAMDAC etc? */ @@ -701,7 +701,8 @@ out_fence: nouveau_fence_fini(dev); out_irq: nouveau_irq_fini(dev); -out_display: +out_vblank: + drm_vblank_cleanup(dev); engine->display.destroy(dev); out_fifo: if (!nouveau_noaccel) @@ -772,6 +773,7 @@ static void nouveau_card_takedown(struct drm_device *dev) nouveau_mem_vram_fini(dev); nouveau_irq_fini(dev); + drm_vblank_cleanup(dev); nouveau_pm_fini(dev); nouveau_bios_takedown(dev); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 99871e304d10..17b950abf200 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -428,31 +428,29 @@ static void nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - struct list_head *entry, *tmp; - - list_for_each_safe(entry, tmp, &dev_priv->vbl_waiting) { - chan = list_entry(entry, struct nouveau_channel, nvsw.vbl_wait); + struct nouveau_channel *chan, *tmp; + list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting, + nvsw.vbl_wait) { nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset, chan->nvsw.vblsem_rval); list_del(&chan->nvsw.vbl_wait); + drm_vblank_put(dev, crtc); } + + drm_handle_vblank(dev, crtc); } static void nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) { - intr &= NV50_PDISPLAY_INTR_1_VBLANK_CRTC; - if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0) nv50_display_vblank_crtc_handler(dev, 0); if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1) nv50_display_vblank_crtc_handler(dev, 1); - nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, intr, 0x00000000); - nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr); + nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC); } static void diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index d441308a09cf..ac7f62d524bb 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -384,14 +384,7 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1) return -EINVAL; - if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN_1) & - NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data))) { - nv_wr32(dev, NV50_PDISPLAY_INTR_1, - NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data)); - nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0, - NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data)); - } - + drm_vblank_get(dev, data); list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); return 0; } -- cgit v1.2.3 From 332b242f47786d1a43bd7a19a0513dd5d493db8e Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 20 Oct 2010 23:35:40 +0200 Subject: drm/nouveau: Implement the pageflip ioctl. nv0x-nv4x should be mostly fine, nv50 doesn't work yet. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 12 ++ drivers/gpu/drm/nouveau/nouveau_channel.c | 1 + drivers/gpu/drm/nouveau/nouveau_display.c | 180 ++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 16 +++ drivers/gpu/drm/nouveau/nouveau_gem.c | 11 +- drivers/gpu/drm/nouveau/nouveau_state.c | 3 + drivers/gpu/drm/nouveau/nv04_crtc.c | 1 + drivers/gpu/drm/nouveau/nv04_graph.c | 16 +++ drivers/gpu/drm/nouveau/nv10_graph.c | 4 + drivers/gpu/drm/nouveau/nv20_graph.c | 8 ++ drivers/gpu/drm/nouveau/nv40_graph.c | 4 + drivers/gpu/drm/nouveau/nv50_crtc.c | 1 + drivers/gpu/drm/nouveau/nv50_graph.c | 16 +++ include/drm/nouveau_drm.h | 1 + 14 files changed, 265 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index c09928322eb9..cdc8f544d47f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -942,6 +942,18 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) return ttm_bo_validate(bo, &nvbo->placement, false, true, false); } +void +nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) +{ + spin_lock(&nvbo->bo.bdev->fence_lock); + __nouveau_fence_unref(&nvbo->bo.sync_obj); + + if (likely(fence)) + nvbo->bo.sync_obj = nouveau_fence_ref(fence); + + spin_unlock(&nvbo->bo.bdev->fence_lock); +} + struct ttm_bo_driver nouveau_bo_driver = { .create_ttm_backend_entry = nouveau_bo_create_ttm_backend_entry, .invalidate_caches = nouveau_bo_invalidate_caches, diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index c9cdbd786dae..11b2370e16da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -148,6 +148,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, NV_DEBUG(dev, "initialising channel %d\n", chan->id); INIT_LIST_HEAD(&chan->nvsw.vbl_wait); + INIT_LIST_HEAD(&chan->nvsw.flip); INIT_LIST_HEAD(&chan->fence.pending); /* Allocate DMA push buffer */ diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index f8987bcb7f51..505c6bfb4d75 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -30,6 +30,8 @@ #include "nouveau_fb.h" #include "nouveau_fbcon.h" #include "nouveau_hw.h" +#include "nouveau_crtc.h" +#include "nouveau_dma.h" static void nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) @@ -131,3 +133,181 @@ nouveau_vblank_disable(struct drm_device *dev, int crtc) else NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0); } + +static int +nouveau_page_flip_reserve(struct nouveau_bo *old_bo, + struct nouveau_bo *new_bo) +{ + int ret; + + ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); + if (ret) + return ret; + + ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0); + if (ret) + goto fail; + + ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0); + if (ret) + goto fail_unreserve; + + return 0; + +fail_unreserve: + ttm_bo_unreserve(&new_bo->bo); +fail: + nouveau_bo_unpin(new_bo); + return ret; +} + +static void +nouveau_page_flip_unreserve(struct nouveau_bo *old_bo, + struct nouveau_bo *new_bo, + struct nouveau_fence *fence) +{ + nouveau_bo_fence(new_bo, fence); + ttm_bo_unreserve(&new_bo->bo); + + nouveau_bo_fence(old_bo, fence); + ttm_bo_unreserve(&old_bo->bo); + + nouveau_bo_unpin(old_bo); +} + +static int +nouveau_page_flip_emit(struct nouveau_channel *chan, + struct nouveau_bo *old_bo, + struct nouveau_bo *new_bo, + struct nouveau_page_flip_state *s, + struct nouveau_fence **pfence) +{ + struct drm_device *dev = chan->dev; + unsigned long flags; + int ret; + + /* Queue it to the pending list */ + spin_lock_irqsave(&dev->event_lock, flags); + list_add_tail(&s->head, &chan->nvsw.flip); + spin_unlock_irqrestore(&dev->event_lock, flags); + + /* Synchronize with the old framebuffer */ + ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan); + if (ret) + goto fail; + + /* Emit the pageflip */ + ret = RING_SPACE(chan, 2); + if (ret) + goto fail; + + BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); + OUT_RING(chan, 0); + FIRE_RING(chan); + + ret = nouveau_fence_new(chan, pfence, true); + if (ret) + goto fail; + + return 0; +fail: + spin_lock_irqsave(&dev->event_lock, flags); + list_del(&s->head); + spin_unlock_irqrestore(&dev->event_lock, flags); + return ret; +} + +int +nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct drm_device *dev = crtc->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; + struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; + struct nouveau_page_flip_state *s; + struct nouveau_channel *chan; + struct nouveau_fence *fence; + int ret; + + if (dev_priv->engine.graph.accel_blocked) + return -ENODEV; + + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + /* Don't let the buffers go away while we flip */ + ret = nouveau_page_flip_reserve(old_bo, new_bo); + if (ret) + goto fail_free; + + /* Initialize a page flip struct */ + *s = (struct nouveau_page_flip_state) + { { }, s->event, nouveau_crtc(crtc)->index, + fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y, + new_bo->bo.offset }; + + /* Choose the channel the flip will be handled in */ + chan = nouveau_fence_channel(new_bo->bo.sync_obj); + if (!chan) + chan = nouveau_channel_get_unlocked(dev_priv->channel); + mutex_lock(&chan->mutex); + + /* Emit a page flip */ + ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); + nouveau_channel_put(&chan); + if (ret) + goto fail_unreserve; + + /* Update the crtc struct and cleanup */ + crtc->fb = fb; + + nouveau_page_flip_unreserve(old_bo, new_bo, fence); + nouveau_fence_unref(&fence); + return 0; + +fail_unreserve: + nouveau_page_flip_unreserve(old_bo, new_bo, NULL); +fail_free: + kfree(s); + return ret; +} + +int +nouveau_finish_page_flip(struct nouveau_channel *chan, + struct nouveau_page_flip_state *ps) +{ + struct drm_device *dev = chan->dev; + struct nouveau_page_flip_state *s; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + if (list_empty(&chan->nvsw.flip)) { + NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id); + spin_unlock_irqrestore(&dev->event_lock, flags); + return -EINVAL; + } + + s = list_first_entry(&chan->nvsw.flip, + struct nouveau_page_flip_state, head); + if (s->event) { + struct drm_pending_vblank_event *e = s->event; + struct timeval now; + + do_gettimeofday(&now); + e->event.sequence = 0; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + list_add_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + } + + list_del(&s->head); + *ps = *s; + kfree(s); + + spin_unlock_irqrestore(&dev->event_lock, flags); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 7cf034fd5cd0..2bb1f1572a55 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -166,6 +166,13 @@ struct nouveau_gpuobj { void *priv; }; +struct nouveau_page_flip_state { + struct list_head head; + struct drm_pending_vblank_event *event; + int crtc, bpp, pitch, x, y; + uint64_t offset; +}; + struct nouveau_channel { struct drm_device *dev; int id; @@ -253,6 +260,7 @@ struct nouveau_channel { uint32_t vblsem_offset; uint32_t vblsem_rval; struct list_head vbl_wait; + struct list_head flip; } nvsw; struct { @@ -1076,6 +1084,8 @@ extern void nv04_graph_destroy_context(struct nouveau_channel *); extern int nv04_graph_load_context(struct nouveau_channel *); extern int nv04_graph_unload_context(struct drm_device *); extern void nv04_graph_context_switch(struct drm_device *); +extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data); /* nv10_graph.c */ extern int nv10_graph_init(struct drm_device *); @@ -1249,6 +1259,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); +extern void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *); /* nouveau_fence.c */ struct nouveau_fence; @@ -1315,6 +1326,10 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *, /* nouveau_display.c */ int nouveau_vblank_enable(struct drm_device *dev, int crtc); void nouveau_vblank_disable(struct drm_device *dev, int crtc); +int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event); +int nouveau_finish_page_flip(struct nouveau_channel *, + struct nouveau_page_flip_state *); /* nv10_gpio.c */ int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); @@ -1514,5 +1529,6 @@ nv_match_device(struct drm_device *dev, unsigned device, #define NV_SW_VBLSEM_OFFSET 0x00000400 #define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404 #define NV_SW_VBLSEM_RELEASE 0x00000408 +#define NV_SW_PAGE_FLIP 0x00000500 #endif /* __NOUVEAU_DRV_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index de8535b58710..9886b644f27d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -231,15 +231,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) list_for_each_safe(entry, tmp, list) { nvbo = list_entry(entry, struct nouveau_bo, entry); - if (likely(fence)) { - struct nouveau_fence *prev_fence; - - spin_lock(&nvbo->bo.bdev->fence_lock); - prev_fence = nvbo->bo.sync_obj; - nvbo->bo.sync_obj = nouveau_fence_ref(fence); - spin_unlock(&nvbo->bo.bdev->fence_lock); - nouveau_fence_unref(&prev_fence); - } + + nouveau_bo_fence(nvbo, fence); if (unlikely(nvbo->validate_mapped)) { ttm_bo_kunmap(&nvbo->kmap); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index d72aa8d19a19..ec9d193b6f61 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1090,6 +1090,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_HAS_BO_USAGE: getparam->value = 1; break; + case NOUVEAU_GETPARAM_HAS_PAGEFLIP: + getparam->value = (dev_priv->card_type < NV_50); + break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index b61a7ff8b7b7..e4aea721971f 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -989,6 +989,7 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = { .cursor_move = nv04_crtc_cursor_move, .gamma_set = nv_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, + .page_flip = nouveau_crtc_page_flip, .destroy = nv_crtc_destroy, }; diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 81aba097ef95..239519aefce6 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -26,6 +26,7 @@ #include "drm.h" #include "nouveau_drm.h" #include "nouveau_drv.h" +#include "nouveau_hw.h" static int nv04_graph_register(struct drm_device *dev); @@ -553,6 +554,20 @@ nv04_graph_mthd_set_ref(struct nouveau_channel *chan, return 0; } +int +nv04_graph_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) +{ + struct drm_device *dev = chan->dev; + struct nouveau_page_flip_state s; + + if (!nouveau_finish_page_flip(chan, &s)) + nv_set_crtc_base(dev, s.crtc, + s.offset + s.y * s.pitch + s.x * s.bpp / 8); + + return 0; +} + /* * Software methods, why they are needed, and how they all work: * @@ -1204,6 +1219,7 @@ nv04_graph_register(struct drm_device *dev) /* nvsw */ NVOBJ_CLASS(dev, 0x506e, SW); NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); dev_priv->engine.graph.registered = true; return 0; diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index a571bfd4471b..3fbb49dfc09c 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -1113,6 +1113,10 @@ nv10_graph_register(struct drm_device *dev) NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable); } + /* nvsw */ + NVOBJ_CLASS(dev, 0x506e, SW); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); + dev_priv->engine.graph.registered = true; return 0; } diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 7720bccb3c98..51b9dd12949d 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -801,6 +801,10 @@ nv20_graph_register(struct drm_device *dev) else NVOBJ_CLASS(dev, 0x0597, GR); + /* nvsw */ + NVOBJ_CLASS(dev, 0x506e, SW); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); + dev_priv->engine.graph.registered = true; return 0; } @@ -841,6 +845,10 @@ nv30_graph_register(struct drm_device *dev) if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f))) NVOBJ_CLASS(dev, 0x0497, GR); + /* nvsw */ + NVOBJ_CLASS(dev, 0x506e, SW); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); + dev_priv->engine.graph.registered = true; return 0; } diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index b9361e28687c..159bdcd757d4 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -446,6 +446,10 @@ nv40_graph_register(struct drm_device *dev) else NVOBJ_CLASS(dev, 0x4097, GR); + /* nvsw */ + NVOBJ_CLASS(dev, 0x506e, SW); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip); + dev_priv->engine.graph.registered = true; return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 56476d0c6de8..1225ea0a841b 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -437,6 +437,7 @@ static const struct drm_crtc_funcs nv50_crtc_funcs = { .cursor_move = nv50_crtc_cursor_move, .gamma_set = nv50_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, + .page_flip = nouveau_crtc_page_flip, .destroy = nv50_crtc_destroy, }; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index ac7f62d524bb..6d81f4dab37d 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -29,6 +29,8 @@ #include "nouveau_drv.h" #include "nouveau_ramht.h" #include "nouveau_grctx.h" +#include "nouveau_dma.h" +#include "nv50_evo.h" static int nv50_graph_register(struct drm_device *); @@ -389,6 +391,19 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, return 0; } +static int +nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) +{ + struct nouveau_page_flip_state s; + + if (!nouveau_finish_page_flip(chan, &s)) { + /* XXX - Do something here */ + } + + return 0; +} + static int nv50_graph_register(struct drm_device *dev) { @@ -402,6 +417,7 @@ nv50_graph_register(struct drm_device *dev) NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset); NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val); NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release); + NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip); NVOBJ_CLASS(dev, 0x0030, GR); /* null */ NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index 60a7b3e9c2e9..39aa0fd6a529 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -81,6 +81,7 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 #define NOUVEAU_GETPARAM_PTIMER_TIME 14 #define NOUVEAU_GETPARAM_HAS_BO_USAGE 15 +#define NOUVEAU_GETPARAM_HAS_PAGEFLIP 16 struct drm_nouveau_getparam { uint64_t param; uint64_t value; -- cgit v1.2.3 From 1c180fa5bd5f264e4863bb88861e8cd7d135b917 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 25 Oct 2010 03:30:34 +0200 Subject: drm/nouveau: Call drm_vblank_pre/post_modeset() around mode setting. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_crtc.c | 2 ++ drivers/gpu/drm/nouveau/nv50_crtc.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index e4aea721971f..297505eb98d5 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -672,6 +672,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc) if (nv_two_heads(dev)) NVSetOwner(dev, nv_crtc->index); + drm_vblank_pre_modeset(dev, nv_crtc->index); funcs->dpms(crtc, DRM_MODE_DPMS_OFF); NVBlankScreen(dev, nv_crtc->index, true); @@ -704,6 +705,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc) #endif funcs->dpms(crtc, DRM_MODE_DPMS_ON); + drm_vblank_post_modeset(dev, nv_crtc->index); } static void nv_crtc_destroy(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 1225ea0a841b..f3570cc45017 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -454,6 +454,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc) NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + drm_vblank_pre_modeset(dev, nv_crtc->index); nv50_crtc_blank(nv_crtc, true); } @@ -469,6 +470,7 @@ nv50_crtc_commit(struct drm_crtc *crtc) NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); nv50_crtc_blank(nv_crtc, false); + drm_vblank_post_modeset(dev, nv_crtc->index); ret = RING_SPACE(evo, 2); if (ret) { -- cgit v1.2.3 From 1f6d2de2c539df6fe52ad2187191a9dfe10c7233 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 24 Oct 2010 14:15:58 +0200 Subject: drm/nv50: Keep track of the head a channel is vsync'ing to. In a multihead setup vblank interrupts may end up enabled in both heads. In that case we want to ignore the vblank interrupts coming from the wrong CRTC to avoid tearing and unbalanced calls to drm_vblank_get/put (fdo bug 31074). Reported-by: Felix Leimbach Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 3 +++ drivers/gpu/drm/nouveau/nv50_graph.c | 3 +++ 3 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 2bb1f1572a55..5814db82f778 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -257,6 +257,7 @@ struct nouveau_channel { struct { struct nouveau_gpuobj *vblsem; + uint32_t vblsem_head; uint32_t vblsem_offset; uint32_t vblsem_rval; struct list_head vbl_wait; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 17b950abf200..41b212801870 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -432,6 +432,9 @@ nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting, nvsw.vbl_wait) { + if (chan->nvsw.vblsem_head != crtc) + continue; + nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset, chan->nvsw.vblsem_rval); list_del(&chan->nvsw.vbl_wait); diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 6d81f4dab37d..e0f52942b2eb 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -387,7 +387,10 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, return -EINVAL; drm_vblank_get(dev, data); + + chan->nvsw.vblsem_head = data; list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); + return 0; } -- cgit v1.2.3 From e419cf0954901bb3a987f8b76cbc9654ca06121c Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 25 Oct 2010 23:38:59 +0200 Subject: drm/nouveau: Add a separate class for the kernel channel mutex. nouveau_bo_move_m2mf() needs to lock the kernel channel, and it may be called from the pushbuf IOCTL with an user channel already locked. Use a separate subclass for the kernel channel mutex because this is legitimate mutex nesting. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index cdc8f544d47f..099f806f39ed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -678,7 +678,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, chan = nvbo->channel; if (!chan || nvbo->no_vm) { chan = dev_priv->channel; - mutex_lock(&chan->mutex); + mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX); } if (dev_priv->card_type < NV_50) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5814db82f778..ce0475ead381 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -173,6 +173,11 @@ struct nouveau_page_flip_state { uint64_t offset; }; +enum nouveau_channel_mutex_class { + NOUVEAU_UCHANNEL_MUTEX, + NOUVEAU_KCHANNEL_MUTEX +}; + struct nouveau_channel { struct drm_device *dev; int id; -- cgit v1.2.3 From a5cf68b04b2b8ea716cf6fd8499c1c54d05fdf5e Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 24 Oct 2010 16:14:41 +0200 Subject: drm/nouveau: Rework tile region handling. The point is to share more code between the PFB/PGRAPH tile region hooks, and give the hardware specific functions a chance to allocate per-region resources. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 11 ++-- drivers/gpu/drm/nouveau/nouveau_drv.h | 59 ++++++++++------- drivers/gpu/drm/nouveau/nouveau_mem.c | 111 +++++++++++++++++++------------- drivers/gpu/drm/nouveau/nouveau_state.c | 25 ++++--- drivers/gpu/drm/nouveau/nv10_fb.c | 48 +++++++++----- drivers/gpu/drm/nouveau/nv10_graph.c | 17 ++--- drivers/gpu/drm/nouveau/nv20_graph.c | 25 ++++--- drivers/gpu/drm/nouveau/nv30_fb.c | 23 ++++++- drivers/gpu/drm/nouveau/nv40_fb.c | 22 +++---- drivers/gpu/drm/nouveau/nv40_graph.c | 40 ++++++------ 10 files changed, 221 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 099f806f39ed..8d5dd980240d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -46,9 +46,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) if (unlikely(nvbo->gem)) DRM_ERROR("bo %p still attached to GEM object\n", bo); - if (nvbo->tile) - nv10_mem_expire_tiling(dev, nvbo->tile, NULL); - + nv10_mem_put_tile_region(dev, nvbo->tile, NULL); kfree(nvbo); } @@ -792,7 +790,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, } else if (dev_priv->card_type >= NV_10) { *new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size, - nvbo->tile_mode); + nvbo->tile_mode, + nvbo->tile_flags); } return 0; @@ -808,9 +807,7 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, if (dev_priv->card_type >= NV_10 && dev_priv->card_type < NV_50) { - if (*old_tile) - nv10_mem_expire_tiling(dev, *old_tile, bo->sync_obj); - + nv10_mem_put_tile_region(dev, *old_tile, bo->sync_obj); *old_tile = new_tile; } } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index ce0475ead381..8b524d894f18 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -66,10 +66,11 @@ struct nouveau_grctx; #define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK) struct nouveau_tile_reg { - struct nouveau_fence *fence; - uint32_t addr; - uint32_t size; bool used; + uint32_t addr; + uint32_t limit; + uint32_t pitch; + struct nouveau_fence *fence; }; struct nouveau_bo { @@ -309,8 +310,11 @@ struct nouveau_fb_engine { int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); - void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch); + void (*init_tile_region)(struct drm_device *dev, int i, + uint32_t addr, uint32_t size, + uint32_t pitch, uint32_t flags); + void (*set_tile_region)(struct drm_device *dev, int i); + void (*free_tile_region)(struct drm_device *dev, int i); }; struct nouveau_fifo_engine { @@ -356,8 +360,7 @@ struct nouveau_pgraph_engine { int (*unload_context)(struct drm_device *); void (*tlb_flush)(struct drm_device *dev); - void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch); + void (*set_tile_region)(struct drm_device *dev, int i); }; struct nouveau_display_engine { @@ -668,7 +671,10 @@ struct drm_nouveau_private { } gart_info; /* nv10-nv40 tiling regions */ - struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR]; + struct { + struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR]; + spinlock_t lock; + } tile; /* VRAM/fb configuration */ uint64_t vram_size; @@ -798,13 +804,12 @@ extern void nouveau_mem_gart_fini(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); extern int nouveau_mem_reset_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); -extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, - uint32_t addr, - uint32_t size, - uint32_t pitch); -extern void nv10_mem_expire_tiling(struct drm_device *dev, - struct nouveau_tile_reg *tile, - struct nouveau_fence *fence); +extern struct nouveau_tile_reg *nv10_mem_set_tiling( + struct drm_device *dev, uint32_t addr, uint32_t size, + uint32_t pitch, uint32_t flags); +extern void nv10_mem_put_tile_region(struct drm_device *dev, + struct nouveau_tile_reg *tile, + struct nouveau_fence *fence); extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt, uint32_t size, uint32_t flags, uint64_t phys); @@ -1011,18 +1016,25 @@ extern void nv04_fb_takedown(struct drm_device *); /* nv10_fb.c */ extern int nv10_fb_init(struct drm_device *); extern void nv10_fb_takedown(struct drm_device *); -extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, - uint32_t, uint32_t); +extern void nv10_fb_init_tile_region(struct drm_device *dev, int i, + uint32_t addr, uint32_t size, + uint32_t pitch, uint32_t flags); +extern void nv10_fb_set_tile_region(struct drm_device *dev, int i); +extern void nv10_fb_free_tile_region(struct drm_device *dev, int i); /* nv30_fb.c */ extern int nv30_fb_init(struct drm_device *); extern void nv30_fb_takedown(struct drm_device *); +extern void nv30_fb_init_tile_region(struct drm_device *dev, int i, + uint32_t addr, uint32_t size, + uint32_t pitch, uint32_t flags); +extern void nv30_fb_free_tile_region(struct drm_device *dev, int i); /* nv40_fb.c */ extern int nv40_fb_init(struct drm_device *); extern void nv40_fb_takedown(struct drm_device *); -extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, - uint32_t, uint32_t); +extern void nv40_fb_set_tile_region(struct drm_device *dev, int i); + /* nv50_fb.c */ extern int nv50_fb_init(struct drm_device *); extern void nv50_fb_takedown(struct drm_device *); @@ -1102,8 +1114,7 @@ extern void nv10_graph_destroy_context(struct nouveau_channel *); extern int nv10_graph_load_context(struct nouveau_channel *); extern int nv10_graph_unload_context(struct drm_device *); extern void nv10_graph_context_switch(struct drm_device *); -extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t, - uint32_t, uint32_t); +extern void nv10_graph_set_tile_region(struct drm_device *dev, int i); /* nv20_graph.c */ extern int nv20_graph_create_context(struct nouveau_channel *); @@ -1113,8 +1124,7 @@ extern int nv20_graph_unload_context(struct drm_device *); extern int nv20_graph_init(struct drm_device *); extern void nv20_graph_takedown(struct drm_device *); extern int nv30_graph_init(struct drm_device *); -extern void nv20_graph_set_region_tiling(struct drm_device *, int, uint32_t, - uint32_t, uint32_t); +extern void nv20_graph_set_tile_region(struct drm_device *dev, int i); /* nv40_graph.c */ extern int nv40_graph_init(struct drm_device *); @@ -1125,8 +1135,7 @@ extern void nv40_graph_destroy_context(struct nouveau_channel *); extern int nv40_graph_load_context(struct nouveau_channel *); extern int nv40_graph_unload_context(struct drm_device *); extern void nv40_grctx_init(struct nouveau_grctx *); -extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t, - uint32_t, uint32_t); +extern void nv40_graph_set_tile_region(struct drm_device *dev, int i); /* nv50_graph.c */ extern int nv50_graph_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index a7c3e08aa7b5..549f59052881 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -42,83 +42,104 @@ */ static void -nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch) +nv10_mem_update_tile_region(struct drm_device *dev, + struct nouveau_tile_reg *tile, uint32_t addr, + uint32_t size, uint32_t pitch, uint32_t flags) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - struct nouveau_tile_reg *tile = &dev_priv->tile[i]; + int i = tile - dev_priv->tile.reg; + unsigned long save; - tile->addr = addr; - tile->size = size; - tile->used = !!pitch; nouveau_fence_unref(&tile->fence); + if (tile->pitch) + pfb->free_tile_region(dev, i); + + if (pitch) + pfb->init_tile_region(dev, i, addr, size, pitch, flags); + + spin_lock_irqsave(&dev_priv->context_switch_lock, save); pfifo->reassign(dev, false); pfifo->cache_pull(dev, false); nouveau_wait_for_idle(dev); - pgraph->set_region_tiling(dev, i, addr, size, pitch); - pfb->set_region_tiling(dev, i, addr, size, pitch); + pfb->set_tile_region(dev, i); + pgraph->set_tile_region(dev, i); pfifo->cache_pull(dev, true); pfifo->reassign(dev, true); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, save); } -struct nouveau_tile_reg * -nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, - uint32_t pitch) +static struct nouveau_tile_reg * +nv10_mem_get_tile_region(struct drm_device *dev, int i) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nouveau_tile_reg *found = NULL; - unsigned long i, flags; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + spin_lock(&dev_priv->tile.lock); - for (i = 0; i < pfb->num_tiles; i++) { - struct nouveau_tile_reg *tile = &dev_priv->tile[i]; - - if (tile->used) - /* Tile region in use. */ - continue; + if (!tile->used && + (!tile->fence || nouveau_fence_signalled(tile->fence))) + tile->used = true; + else + tile = NULL; - if (tile->fence && - !nouveau_fence_signalled(tile->fence)) - /* Pending tile region. */ - continue; + spin_unlock(&dev_priv->tile.lock); + return tile; +} - if (max(tile->addr, addr) < - min(tile->addr + tile->size, addr + size)) - /* Kill an intersecting tile region. */ - nv10_mem_set_region_tiling(dev, i, 0, 0, 0); +void +nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile, + struct nouveau_fence *fence) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; - if (pitch && !found) { - /* Free tile region. */ - nv10_mem_set_region_tiling(dev, i, addr, size, pitch); - found = tile; + if (tile) { + spin_lock(&dev_priv->tile.lock); + if (fence) { + /* Mark it as pending. */ + tile->fence = fence; + nouveau_fence_ref(fence); } - } - - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - return found; + tile->used = false; + spin_unlock(&dev_priv->tile.lock); + } } -void -nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile, - struct nouveau_fence *fence) +struct nouveau_tile_reg * +nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, + uint32_t pitch, uint32_t flags) { - if (fence) { - /* Mark it as pending. */ - tile->fence = fence; - nouveau_fence_ref(fence); + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nouveau_tile_reg *tile, *found = NULL; + int i; + + for (i = 0; i < pfb->num_tiles; i++) { + tile = nv10_mem_get_tile_region(dev, i); + + if (pitch && !found) { + found = tile; + continue; + + } else if (tile && tile->pitch) { + /* Kill an unused tile region. */ + nv10_mem_update_tile_region(dev, tile, 0, 0, 0, 0); + } + + nv10_mem_put_tile_region(dev, tile, NULL); } - tile->used = false; + if (found) + nv10_mem_update_tile_region(dev, found, addr, size, + pitch, flags); + return found; } /* diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index ec9d193b6f61..1a7a50ccb7c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -118,7 +118,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; - engine->fb.set_region_tiling = nv10_fb_set_region_tiling; + engine->fb.init_tile_region = nv10_fb_init_tile_region; + engine->fb.set_tile_region = nv10_fb_set_tile_region; + engine->fb.free_tile_region = nv10_fb_free_tile_region; engine->graph.init = nv10_graph_init; engine->graph.takedown = nv10_graph_takedown; engine->graph.channel = nv10_graph_channel; @@ -127,7 +129,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.fifo_access = nv04_graph_fifo_access; engine->graph.load_context = nv10_graph_load_context; engine->graph.unload_context = nv10_graph_unload_context; - engine->graph.set_region_tiling = nv10_graph_set_region_tiling; + engine->graph.set_tile_region = nv10_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -173,7 +175,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv10_fb_init; engine->fb.takedown = nv10_fb_takedown; - engine->fb.set_region_tiling = nv10_fb_set_region_tiling; + engine->fb.init_tile_region = nv10_fb_init_tile_region; + engine->fb.set_tile_region = nv10_fb_set_tile_region; + engine->fb.free_tile_region = nv10_fb_free_tile_region; engine->graph.init = nv20_graph_init; engine->graph.takedown = nv20_graph_takedown; engine->graph.channel = nv10_graph_channel; @@ -182,7 +186,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.fifo_access = nv04_graph_fifo_access; engine->graph.load_context = nv20_graph_load_context; engine->graph.unload_context = nv20_graph_unload_context; - engine->graph.set_region_tiling = nv20_graph_set_region_tiling; + engine->graph.set_tile_region = nv20_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -228,7 +232,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv30_fb_init; engine->fb.takedown = nv30_fb_takedown; - engine->fb.set_region_tiling = nv10_fb_set_region_tiling; + engine->fb.init_tile_region = nv30_fb_init_tile_region; + engine->fb.set_tile_region = nv10_fb_set_tile_region; + engine->fb.free_tile_region = nv30_fb_free_tile_region; engine->graph.init = nv30_graph_init; engine->graph.takedown = nv20_graph_takedown; engine->graph.fifo_access = nv04_graph_fifo_access; @@ -237,7 +243,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv20_graph_destroy_context; engine->graph.load_context = nv20_graph_load_context; engine->graph.unload_context = nv20_graph_unload_context; - engine->graph.set_region_tiling = nv20_graph_set_region_tiling; + engine->graph.set_tile_region = nv20_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -286,7 +292,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->timer.takedown = nv04_timer_takedown; engine->fb.init = nv40_fb_init; engine->fb.takedown = nv40_fb_takedown; - engine->fb.set_region_tiling = nv40_fb_set_region_tiling; + engine->fb.init_tile_region = nv30_fb_init_tile_region; + engine->fb.set_tile_region = nv40_fb_set_tile_region; + engine->fb.free_tile_region = nv30_fb_free_tile_region; engine->graph.init = nv40_graph_init; engine->graph.takedown = nv40_graph_takedown; engine->graph.fifo_access = nv04_graph_fifo_access; @@ -295,7 +303,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv40_graph_destroy_context; engine->graph.load_context = nv40_graph_load_context; engine->graph.unload_context = nv40_graph_unload_context; - engine->graph.set_region_tiling = nv40_graph_set_region_tiling; + engine->graph.set_tile_region = nv40_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv40_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; @@ -596,6 +604,7 @@ nouveau_card_init(struct drm_device *dev) goto out; engine = &dev_priv->engine; spin_lock_init(&dev_priv->channels.lock); + spin_lock_init(&dev_priv->tile.lock); spin_lock_init(&dev_priv->context_switch_lock); /* Make the CRTCs and I2C buses accessible */ diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c index cc5cda44e501..d50acc6a90d1 100644 --- a/drivers/gpu/drm/nouveau/nv10_fb.c +++ b/drivers/gpu/drm/nouveau/nv10_fb.c @@ -4,22 +4,40 @@ #include "nouveau_drm.h" void -nv10_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch) +nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch, uint32_t flags) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t limit = max(1u, addr + size) - 1; - - if (pitch) { - if (dev_priv->card_type >= NV_20) - addr |= 1; - else - addr |= 1 << 31; - } - - nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); - nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); - nv_wr32(dev, NV10_PFB_TILE(i), addr); + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + tile->addr = addr; + tile->limit = max(1u, addr + size) - 1; + tile->pitch = pitch; + + if (dev_priv->card_type == NV_20) + tile->addr |= 1; + else + tile->addr |= 1 << 31; +} + +void +nv10_fb_free_tile_region(struct drm_device *dev, int i) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + tile->addr = tile->limit = tile->pitch = 0; +} + +void +nv10_fb_set_tile_region(struct drm_device *dev, int i) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); + nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); + nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); } int @@ -33,7 +51,7 @@ nv10_fb_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < pfb->num_tiles; i++) - pfb->set_region_tiling(dev, i, 0, 0, 0); + pfb->set_tile_region(dev, i); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 3fbb49dfc09c..1cd141edca04 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -899,17 +899,14 @@ void nv10_graph_destroy_context(struct nouveau_channel *chan) } void -nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch) +nv10_graph_set_tile_region(struct drm_device *dev, int i) { - uint32_t limit = max(1u, addr + size) - 1; - - if (pitch) - addr |= 1 << 31; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit); - nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch); - nv_wr32(dev, NV10_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr); } int nv10_graph_init(struct drm_device *dev) @@ -949,7 +946,7 @@ int nv10_graph_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < NV10_PFB_TILE__SIZE; i++) - nv10_graph_set_region_tiling(dev, i, 0, 0, 0); + nv10_graph_set_tile_region(dev, i); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index 51b9dd12949d..a71871b91c69 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -511,24 +511,21 @@ nv20_graph_rdi(struct drm_device *dev) } void -nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch) +nv20_graph_set_tile_region(struct drm_device *dev, int i) { - uint32_t limit = max(1u, addr + size) - 1; - - if (pitch) - addr |= 1; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); - nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, limit); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->limit); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, pitch); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, addr); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr); } int @@ -612,7 +609,7 @@ nv20_graph_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < NV10_PFB_TILE__SIZE; i++) - nv20_graph_set_region_tiling(dev, i, 0, 0, 0); + nv20_graph_set_tile_region(dev, i); for (i = 0; i < 8; i++) { nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4)); @@ -751,7 +748,7 @@ nv30_graph_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < NV10_PFB_TILE__SIZE; i++) - nv20_graph_set_region_tiling(dev, i, 0, 0, 0); + nv20_graph_set_tile_region(dev, i); nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c index 4a3f2f095128..e0135f0e2144 100644 --- a/drivers/gpu/drm/nouveau/nv30_fb.c +++ b/drivers/gpu/drm/nouveau/nv30_fb.c @@ -29,6 +29,27 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +void +nv30_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, + uint32_t size, uint32_t pitch, uint32_t flags) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + tile->addr = addr | 1; + tile->limit = max(1u, addr + size) - 1; + tile->pitch = pitch; +} + +void +nv30_fb_free_tile_region(struct drm_device *dev, int i) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + tile->addr = tile->limit = tile->pitch = 0; +} + static int calc_bias(struct drm_device *dev, int k, int i, int j) { @@ -65,7 +86,7 @@ nv30_fb_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < pfb->num_tiles; i++) - pfb->set_region_tiling(dev, i, 0, 0, 0); + pfb->set_tile_region(dev, i); /* Init the memory timing regs at 0x10037c/0x1003ac */ if (dev_priv->chipset == 0x30 || diff --git a/drivers/gpu/drm/nouveau/nv40_fb.c b/drivers/gpu/drm/nouveau/nv40_fb.c index 3cd07d8d5bd7..f3d9c0505f7b 100644 --- a/drivers/gpu/drm/nouveau/nv40_fb.c +++ b/drivers/gpu/drm/nouveau/nv40_fb.c @@ -4,26 +4,22 @@ #include "nouveau_drm.h" void -nv40_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch) +nv40_fb_set_tile_region(struct drm_device *dev, int i) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t limit = max(1u, addr + size) - 1; - - if (pitch) - addr |= 1; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; switch (dev_priv->chipset) { case 0x40: - nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); - nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); - nv_wr32(dev, NV10_PFB_TILE(i), addr); + nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); + nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); + nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); break; default: - nv_wr32(dev, NV40_PFB_TLIMIT(i), limit); - nv_wr32(dev, NV40_PFB_TSIZE(i), pitch); - nv_wr32(dev, NV40_PFB_TILE(i), addr); + nv_wr32(dev, NV40_PFB_TLIMIT(i), tile->limit); + nv_wr32(dev, NV40_PFB_TSIZE(i), tile->pitch); + nv_wr32(dev, NV40_PFB_TILE(i), tile->addr); break; } } @@ -64,7 +60,7 @@ nv40_fb_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < pfb->num_tiles; i++) - pfb->set_region_tiling(dev, i, 0, 0, 0); + pfb->set_tile_region(dev, i); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 159bdcd757d4..7a51608b55ba 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -192,43 +192,39 @@ nv40_graph_unload_context(struct drm_device *dev) } void -nv40_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, - uint32_t size, uint32_t pitch) +nv40_graph_set_tile_region(struct drm_device *dev, int i) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t limit = max(1u, addr + size) - 1; - - if (pitch) - addr |= 1; + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; switch (dev_priv->chipset) { case 0x44: case 0x4a: case 0x4e: - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); - nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); break; case 0x46: case 0x47: case 0x49: case 0x4b: - nv_wr32(dev, NV47_PGRAPH_TSIZE(i), pitch); - nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), limit); - nv_wr32(dev, NV47_PGRAPH_TILE(i), addr); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); + nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); break; default: - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); - nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); break; } } @@ -369,7 +365,7 @@ nv40_graph_init(struct drm_device *dev) /* Turn all the tiling regions off. */ for (i = 0; i < pfb->num_tiles; i++) - nv40_graph_set_region_tiling(dev, i, 0, 0, 0); + nv40_graph_set_tile_region(dev, i); /* begin RAM config */ vramsz = pci_resource_len(dev->pdev, 0) - 1; -- cgit v1.2.3 From 87a326a38589e1c919af5f86a59cd571ff0aa831 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 24 Oct 2010 16:36:12 +0200 Subject: drm/nv20: Add Z compression support. Signed-off-by: Francisco Jerez Tested-by: Xavier Chantry Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 ++ drivers/gpu/drm/nouveau/nouveau_reg.h | 6 +++ drivers/gpu/drm/nouveau/nv10_fb.c | 90 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/nouveau/nv20_graph.c | 21 ++++---- 4 files changed, 106 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 8b524d894f18..a94430b94a20 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -70,6 +70,8 @@ struct nouveau_tile_reg { uint32_t addr; uint32_t limit; uint32_t pitch; + uint32_t zcomp; + struct drm_mm_node *tag_mem; struct nouveau_fence *fence; }; @@ -306,6 +308,7 @@ struct nouveau_timer_engine { struct nouveau_fb_engine { int num_tiles; + struct drm_mm tag_heap; int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index b6384d36d5d0..df3a87e792f2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -45,6 +45,11 @@ # define NV04_PFB_REF_CMD_REFRESH (1 << 0) #define NV04_PFB_PRE 0x001002d4 # define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0) +#define NV20_PFB_ZCOMP(i) (0x00100300 + 4*(i)) +# define NV20_PFB_ZCOMP_MODE_32 (4 << 24) +# define NV20_PFB_ZCOMP_EN (1 << 31) +# define NV25_PFB_ZCOMP_MODE_16 (1 << 20) +# define NV25_PFB_ZCOMP_MODE_32 (2 << 20) #define NV10_PFB_CLOSE_PAGE2 0x0010033c #define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i)) #define NV40_PFB_TILE(i) (0x00100600 + (i*16)) @@ -379,6 +384,7 @@ #define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16)) #define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16)) #define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16)) +#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i)) #define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) #define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) #define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) diff --git a/drivers/gpu/drm/nouveau/nv10_fb.c b/drivers/gpu/drm/nouveau/nv10_fb.c index d50acc6a90d1..f78181a59b4a 100644 --- a/drivers/gpu/drm/nouveau/nv10_fb.c +++ b/drivers/gpu/drm/nouveau/nv10_fb.c @@ -3,21 +3,81 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +static struct drm_mm_node * +nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct drm_mm_node *mem; + int ret; + + ret = drm_mm_pre_get(&pfb->tag_heap); + if (ret) + return NULL; + + spin_lock(&dev_priv->tile.lock); + mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0); + if (mem) + mem = drm_mm_get_block_atomic(mem, size, 0); + spin_unlock(&dev_priv->tile.lock); + + return mem; +} + +static void +nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + spin_lock(&dev_priv->tile.lock); + drm_mm_put_block(mem); + spin_unlock(&dev_priv->tile.lock); +} + void nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, uint32_t size, uint32_t pitch, uint32_t flags) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16); tile->addr = addr; tile->limit = max(1u, addr + size) - 1; tile->pitch = pitch; - if (dev_priv->card_type == NV_20) - tile->addr |= 1; - else + if (dev_priv->card_type == NV_20) { + if (flags & NOUVEAU_GEM_TILE_ZETA) { + /* + * Allocate some of the on-die tag memory, + * used to store Z compression meta-data (most + * likely just a bitmap determining if a given + * tile is compressed or not). + */ + tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256); + + if (tile->tag_mem) { + /* Enable Z compression */ + if (dev_priv->chipset >= 0x25) + tile->zcomp = tile->tag_mem->start | + (bpp == 16 ? + NV25_PFB_ZCOMP_MODE_16 : + NV25_PFB_ZCOMP_MODE_32); + else + tile->zcomp = tile->tag_mem->start | + NV20_PFB_ZCOMP_EN | + (bpp == 16 ? 0 : + NV20_PFB_ZCOMP_MODE_32); + } + + tile->addr |= 3; + } else { + tile->addr |= 1; + } + + } else { tile->addr |= 1 << 31; + } } void @@ -26,7 +86,12 @@ nv10_fb_free_tile_region(struct drm_device *dev, int i) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - tile->addr = tile->limit = tile->pitch = 0; + if (tile->tag_mem) { + nv20_fb_free_tag(dev, tile->tag_mem); + tile->tag_mem = NULL; + } + + tile->addr = tile->limit = tile->pitch = tile->zcomp = 0; } void @@ -38,6 +103,9 @@ nv10_fb_set_tile_region(struct drm_device *dev, int i) nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); + + if (dev_priv->card_type == NV_20) + nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp); } int @@ -49,6 +117,11 @@ nv10_fb_init(struct drm_device *dev) pfb->num_tiles = NV10_PFB_TILE__SIZE; + if (dev_priv->card_type == NV_20) + drm_mm_init(&pfb->tag_heap, 0, + (dev_priv->chipset >= 0x25 ? + 64 * 1024 : 32 * 1024)); + /* Turn all the tiling regions off. */ for (i = 0; i < pfb->num_tiles; i++) pfb->set_tile_region(dev, i); @@ -59,4 +132,13 @@ nv10_fb_init(struct drm_device *dev) void nv10_fb_takedown(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + int i; + + for (i = 0; i < pfb->num_tiles; i++) + pfb->free_tile_region(dev, i); + + if (dev_priv->card_type == NV_20) + drm_mm_takedown(&pfb->tag_heap); } diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index a71871b91c69..bd065c2fcba4 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -526,6 +526,12 @@ nv20_graph_set_tile_region(struct drm_device *dev, int i) nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr); + + if (dev_priv->card_type == NV_20) { + nv_wr32(dev, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); + nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->zcomp); + } } int @@ -589,16 +595,17 @@ nv20_graph_init(struct drm_device *dev) nv_wr32(dev, 0x40009C , 0x00000040); if (dev_priv->chipset >= 0x25) { - nv_wr32(dev, 0x400890, 0x00080000); + nv_wr32(dev, 0x400890, 0x00a8cfff); nv_wr32(dev, 0x400610, 0x304B1FB6); - nv_wr32(dev, 0x400B80, 0x18B82880); + nv_wr32(dev, 0x400B80, 0x1cbd3883); nv_wr32(dev, 0x400B84, 0x44000000); nv_wr32(dev, 0x400098, 0x40000080); nv_wr32(dev, 0x400B88, 0x000000ff); + } else { - nv_wr32(dev, 0x400880, 0x00080000); /* 0x0008c7df */ + nv_wr32(dev, 0x400880, 0x0008c7df); nv_wr32(dev, 0x400094, 0x00000005); - nv_wr32(dev, 0x400B80, 0x45CAA208); /* 0x45eae20e */ + nv_wr32(dev, 0x400B80, 0x45eae20e); nv_wr32(dev, 0x400B84, 0x24000000); nv_wr32(dev, 0x400098, 0x00000040); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038); @@ -611,12 +618,6 @@ nv20_graph_init(struct drm_device *dev) for (i = 0; i < NV10_PFB_TILE__SIZE; i++) nv20_graph_set_tile_region(dev, i); - for (i = 0; i < 8; i++) { - nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4)); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, - nv_rd32(dev, 0x100300 + i * 4)); - } nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324)); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324)); -- cgit v1.2.3 From 23c45e8ed203f933753fb66a6290c4ff853eb7bb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 28 Oct 2010 23:10:29 +0200 Subject: drm/nouveau: Fix sleep while atomic in nouveau_bo_fence(). Reported-by: Pekka Paalanen Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 8d5dd980240d..f4ee43db00aa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -942,13 +942,17 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) void nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) { - spin_lock(&nvbo->bo.bdev->fence_lock); - __nouveau_fence_unref(&nvbo->bo.sync_obj); + struct nouveau_fence *old_fence; if (likely(fence)) - nvbo->bo.sync_obj = nouveau_fence_ref(fence); + nouveau_fence_ref(fence); + spin_lock(&nvbo->bo.bdev->fence_lock); + old_fence = nvbo->bo.sync_obj; + nvbo->bo.sync_obj = fence; spin_unlock(&nvbo->bo.bdev->fence_lock); + + nouveau_fence_unref(&old_fence); } struct ttm_bo_driver nouveau_bo_driver = { -- cgit v1.2.3 From aa2c2e8039e3692065022a7ff885009b2d88818a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 4 Nov 2010 13:40:15 +1000 Subject: drm/nv50: fix compute object class Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index e0f52942b2eb..7a98d41c68a6 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -425,8 +425,6 @@ nv50_graph_register(struct drm_device *dev) NVOBJ_CLASS(dev, 0x0030, GR); /* null */ NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */ - NVOBJ_CLASS(dev, 0x50c0, GR); /* compute */ - NVOBJ_CLASS(dev, 0x85c0, GR); /* compute (nva3, nva5, nva8) */ /* tesla */ if (dev_priv->chipset == 0x50) @@ -452,6 +450,14 @@ nv50_graph_register(struct drm_device *dev) } } + /* compute */ + if (dev_priv->chipset <= 0xa0 || + dev_priv->chipset == 0xaa || + dev_priv->chipset == 0xac) + NVOBJ_CLASS(dev, 0x50c0, GR); + else + NVOBJ_CLASS(dev, 0x85c0, GR); + dev_priv->engine.graph.registered = true; return 0; } -- cgit v1.2.3 From a169f09b96306cc353ffe0e1bc4bc0e1e9492281 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 5 Nov 2010 09:40:00 +1000 Subject: drm/nv50: 0x50c0 apparently works on NVA3+ too, so lets allow it Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_graph.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 7a98d41c68a6..6785269f778a 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -451,11 +451,10 @@ nv50_graph_register(struct drm_device *dev) } /* compute */ - if (dev_priv->chipset <= 0xa0 || - dev_priv->chipset == 0xaa || - dev_priv->chipset == 0xac) - NVOBJ_CLASS(dev, 0x50c0, GR); - else + NVOBJ_CLASS(dev, 0x50c0, GR); + if (dev_priv->chipset > 0xa0 && + dev_priv->chipset != 0xaa && + dev_priv->chipset != 0xac) NVOBJ_CLASS(dev, 0x85c0, GR); dev_priv->engine.graph.registered = true; -- cgit v1.2.3 From 8f8a54482b008714ccfad15f4592b3802b80d479 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 09:57:28 +1000 Subject: drm/nouveau: allow irq handlers to be installed by engine-specific code Lets start to clean up this mess! Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++++ drivers/gpu/drm/nouveau/nouveau_irq.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a94430b94a20..52dc97d87ebd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -614,6 +614,7 @@ struct drm_nouveau_private { struct nouveau_bo *vga_ram; /* interrupt handling */ + void (*irq_handler[32])(struct drm_device *); bool msi_enabled; struct workqueue_struct *wq; struct work_struct irq_work; @@ -900,6 +901,9 @@ extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, extern int nouveau_irq_init(struct drm_device *); extern void nouveau_irq_fini(struct drm_device *); extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); +extern void nouveau_irq_register(struct drm_device *, int status_bit, + void (*)(struct drm_device *)); +extern void nouveau_irq_unregister(struct drm_device *, int status_bit); extern void nouveau_irq_preinstall(struct drm_device *); extern int nouveau_irq_postinstall(struct drm_device *); extern void nouveau_irq_uninstall(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index f3ae74ef3318..819bc3dd89e0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -1216,8 +1216,9 @@ nouveau_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *)arg; struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t status; unsigned long flags; + u32 status; + int i; status = nv_rd32(dev, NV03_PMC_INTR_0); if (!status) @@ -1267,6 +1268,14 @@ nouveau_irq_handler(DRM_IRQ_ARGS) NV_PMC_INTR_0_NV50_I2C_PENDING); } + for (i = 0; i < 32 && status; i++) { + if (!(status & (1 << i)) || !dev_priv->irq_handler[i]) + continue; + + dev_priv->irq_handler[i](dev); + status &= ~(1 << i); + } + if (status) NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); @@ -1304,3 +1313,26 @@ nouveau_irq_fini(struct drm_device *dev) if (dev_priv->msi_enabled) pci_disable_msi(dev->pdev); } + +void +nouveau_irq_register(struct drm_device *dev, int status_bit, + void (*handler)(struct drm_device *)) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + dev_priv->irq_handler[status_bit] = handler; + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +} + +void +nouveau_irq_unregister(struct drm_device *dev, int status_bit) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + dev_priv->irq_handler[status_bit] = NULL; + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +} -- cgit v1.2.3 From d7facf9dc50acff69de9688088caa78b3cf69ebb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 10:06:43 +1000 Subject: drm/nv84: move PCRYPT ISR out of nouveau_irq.c Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 2 +- drivers/gpu/drm/nouveau/nouveau_irq.c | 25 +---------------------- drivers/gpu/drm/nouveau/nouveau_util.c | 36 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_util.h | 33 +++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv84_crypt.c | 27 +++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nouveau_util.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_util.h (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index c8c8de0bbc77..7ea9a1154ca8 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -5,7 +5,7 @@ ccflags-y := -Iinclude/drm nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o \ - nouveau_sgdma.o nouveau_dma.o \ + nouveau_sgdma.o nouveau_dma.o nouveau_util.o \ nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \ nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 819bc3dd89e0..bdaf8ae44476 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -36,19 +36,12 @@ #include "nouveau_drv.h" #include "nouveau_reg.h" #include "nouveau_ramht.h" -#include +#include "nouveau_util.h" /* needed for hotplug irq */ #include "nouveau_connector.h" #include "nv50_display.h" -static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); - -static int nouveau_ratelimit(void) -{ - return __ratelimit(&nouveau_ratelimit_state); -} - void nouveau_irq_preinstall(struct drm_device *dev) { @@ -1240,22 +1233,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; } - if (status & 0x00004000) { - u32 stat = nv_rd32(dev, 0x102130); - u32 mthd = nv_rd32(dev, 0x102190); - u32 data = nv_rd32(dev, 0x102194); - u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff; - - NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n", - stat, mthd, data, inst); - nv_wr32(dev, 0x102130, stat); - nv_wr32(dev, 0x10200c, 0x10); - - nv50_fb_vm_trap(dev, nouveau_ratelimit(), "PCRYPT"); - status &= ~0x00004000; - - } - if (status & NV_PMC_INTR_0_CRTCn_PENDING) { nouveau_crtc_irq_handler(dev, (status>>24)&3); status &= ~NV_PMC_INTR_0_CRTCn_PENDING; diff --git a/drivers/gpu/drm/nouveau/nouveau_util.c b/drivers/gpu/drm/nouveau/nouveau_util.c new file mode 100644 index 000000000000..e8b1eaaa212b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_util.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Nouveau Project + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include + +static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); + +int +nouveau_ratelimit(void) +{ + return __ratelimit(&nouveau_ratelimit_state); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_util.h b/drivers/gpu/drm/nouveau/nouveau_util.h new file mode 100644 index 000000000000..9a7a7c18c99a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_util.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 Nouveau Project + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __NOUVEAU_UTIL_H__ +#define __NOUVEAU_UTIL_H__ + +int nouveau_ratelimit(void); + +#endif diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c index f988b1a9d1d7..1cda0240f55d 100644 --- a/drivers/gpu/drm/nouveau/nv84_crypt.c +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -24,6 +24,9 @@ #include "drmP.h" #include "nouveau_drv.h" +#include "nouveau_util.h" + +static void nv84_crypt_isr(struct drm_device *); int nv84_crypt_create_context(struct nouveau_channel *chan) @@ -97,8 +100,11 @@ nv84_crypt_init(struct drm_device *dev) nv_mask(dev, 0x000200, 0x00004000, 0x00000000); nv_mask(dev, 0x000200, 0x00004000, 0x00004000); + + nouveau_irq_register(dev, 14, nv84_crypt_isr); nv_wr32(dev, 0x102130, 0xffffffff); nv_wr32(dev, 0x102140, 0xffffffbf); + nv_wr32(dev, 0x10200c, 0x00000010); return 0; } @@ -107,4 +113,25 @@ void nv84_crypt_fini(struct drm_device *dev) { nv_wr32(dev, 0x102140, 0x00000000); + nouveau_irq_unregister(dev, 14); +} + +static void +nv84_crypt_isr(struct drm_device *dev) +{ + u32 stat = nv_rd32(dev, 0x102130); + u32 mthd = nv_rd32(dev, 0x102190); + u32 data = nv_rd32(dev, 0x102194); + u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff; + int show = nouveau_ratelimit(); + + if (show) { + NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n", + stat, mthd, data, inst); + } + + nv_wr32(dev, 0x102130, stat); + nv_wr32(dev, 0x10200c, 0x10); + + nv50_fb_vm_trap(dev, show, "PCRYPT"); } -- cgit v1.2.3 From 2cbd4c818578ef8f2e486dc77267ead1e503c637 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 10:18:04 +1000 Subject: drm/nv50: move GPIO ISR to nv50_gpio.c Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_irq.c | 6 ++---- drivers/gpu/drm/nouveau/nouveau_state.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.c | 19 ----------------- drivers/gpu/drm/nouveau/nv50_gpio.c | 36 +++++++++++++++++++++++++++++++++ 5 files changed, 40 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 52dc97d87ebd..c0fad126eaa4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1359,6 +1359,7 @@ int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); /* nv50_gpio.c */ int nv50_gpio_init(struct drm_device *dev); +void nv50_gpio_fini(struct drm_device *dev); int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index bdaf8ae44476..061bae33b6e0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -1238,11 +1238,9 @@ nouveau_irq_handler(DRM_IRQ_ARGS) status &= ~NV_PMC_INTR_0_CRTCn_PENDING; } - if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING | - NV_PMC_INTR_0_NV50_I2C_PENDING)) { + if (status & NV_PMC_INTR_0_NV50_DISPLAY_PENDING) { nv50_display_irq_handler(dev); - status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING | - NV_PMC_INTR_0_NV50_I2C_PENDING); + status &= ~NV_PMC_INTR_0_NV50_DISPLAY_PENDING; } for (i = 0; i < 32 && status; i++) { diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 1a7a50ccb7c8..84bff459491e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -393,7 +393,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->display.init = nv50_display_init; engine->display.destroy = nv50_display_destroy; engine->gpio.init = nv50_gpio_init; - engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.takedown = nv50_gpio_fini; engine->gpio.get = nv50_gpio_get; engine->gpio.set = nv50_gpio_set; engine->gpio.irq_enable = nv50_gpio_irq_enable; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 41b212801870..42cb5b5c73c0 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -869,25 +869,6 @@ nv50_display_irq_handler(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t delayed = 0; - if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { - uint32_t hpd0_bits, hpd1_bits = 0; - - hpd0_bits = nv_rd32(dev, 0xe054); - nv_wr32(dev, 0xe054, hpd0_bits); - - if (dev_priv->chipset >= 0x90) { - hpd1_bits = nv_rd32(dev, 0xe074); - nv_wr32(dev, 0xe074, hpd1_bits); - } - - spin_lock(&dev_priv->hpd_state.lock); - dev_priv->hpd_state.hpd0_bits |= hpd0_bits; - dev_priv->hpd_state.hpd1_bits |= hpd1_bits; - spin_unlock(&dev_priv->hpd_state.lock); - - queue_work(dev_priv->wq, &dev_priv->hpd_work); - } - while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1); diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index b2fab2bf3d61..302f7ebe5b6f 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -26,6 +26,8 @@ #include "nouveau_drv.h" #include "nouveau_hw.h" +static void nv50_gpio_isr(struct drm_device *dev); + static int nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift) { @@ -107,5 +109,39 @@ nv50_gpio_init(struct drm_device *dev) nv_wr32(dev, 0xe074, 0xffffffff); } + nouveau_irq_register(dev, 21, nv50_gpio_isr); return 0; } + +void +nv50_gpio_fini(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + nv_wr32(dev, 0xe050, 0x00000000); + if (dev_priv->chipset >= 0x90) + nv_wr32(dev, 0xe070, 0x00000000); + nouveau_irq_unregister(dev, 21); +} + +static void +nv50_gpio_isr(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t hpd0_bits, hpd1_bits = 0; + + hpd0_bits = nv_rd32(dev, 0xe054); + nv_wr32(dev, 0xe054, hpd0_bits); + + if (dev_priv->chipset >= 0x90) { + hpd1_bits = nv_rd32(dev, 0xe074); + nv_wr32(dev, 0xe074, hpd1_bits); + } + + spin_lock(&dev_priv->hpd_state.lock); + dev_priv->hpd_state.hpd0_bits |= hpd0_bits; + dev_priv->hpd_state.hpd1_bits |= hpd1_bits; + spin_unlock(&dev_priv->hpd_state.lock); + + queue_work(dev_priv->wq, &dev_priv->hpd_work); +} -- cgit v1.2.3 From 19b7fc7bf59f4bf02ee738a79baaccae31220df3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 10:27:27 +1000 Subject: drm/nv50: use register/unregister functionality for PDISPLAY ISR Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 16 +--------------- drivers/gpu/drm/nouveau/nv50_display.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nv50_display.h | 1 - drivers/gpu/drm/nouveau/nv50_gpio.c | 4 ++++ 4 files changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 061bae33b6e0..2f546884f2ed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -38,10 +38,6 @@ #include "nouveau_ramht.h" #include "nouveau_util.h" -/* needed for hotplug irq */ -#include "nouveau_connector.h" -#include "nv50_display.h" - void nouveau_irq_preinstall(struct drm_device *dev) { @@ -50,12 +46,7 @@ nouveau_irq_preinstall(struct drm_device *dev) /* Master disable */ nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); - if (dev_priv->card_type >= NV_50) { - INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); - INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); - spin_lock_init(&dev_priv->hpd_state.lock); - INIT_LIST_HEAD(&dev_priv->vbl_waiting); - } + INIT_LIST_HEAD(&dev_priv->vbl_waiting); } int @@ -1238,11 +1229,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) status &= ~NV_PMC_INTR_0_CRTCn_PENDING; } - if (status & NV_PMC_INTR_0_NV50_DISPLAY_PENDING) { - nv50_display_irq_handler(dev); - status &= ~NV_PMC_INTR_0_NV50_DISPLAY_PENDING; - } - for (i = 0; i < 32 && status; i++) { if (!(status & (1 << i)) || !dev_priv->irq_handler[i]) continue; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 42cb5b5c73c0..e5dbd171672c 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -33,6 +33,8 @@ #include "nouveau_ramht.h" #include "drm_crtc_helper.h" +static void nv50_display_isr(struct drm_device *); + static inline int nv50_sor_nr(struct drm_device *dev) { @@ -328,6 +330,9 @@ int nv50_display_create(struct drm_device *dev) } } + INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); + nouveau_irq_register(dev, 26, nv50_display_isr); + ret = nv50_display_init(dev); if (ret) { nv50_display_destroy(dev); @@ -345,6 +350,7 @@ nv50_display_destroy(struct drm_device *dev) drm_mode_config_cleanup(dev); nv50_display_disable(dev); + nouveau_irq_unregister(dev, 26); } static u16 @@ -863,8 +869,8 @@ nv50_display_irq_hotplug_bh(struct work_struct *work) drm_helper_hpd_irq_event(dev); } -void -nv50_display_irq_handler(struct drm_device *dev) +static void +nv50_display_isr(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t delayed = 0; diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h index c551f0b85ee0..a269fccf3555 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.h +++ b/drivers/gpu/drm/nouveau/nv50_display.h @@ -35,7 +35,6 @@ #include "nouveau_crtc.h" #include "nv50_evo.h" -void nv50_display_irq_handler(struct drm_device *dev); void nv50_display_irq_handler_bh(struct work_struct *work); void nv50_display_irq_hotplug_bh(struct work_struct *work); int nv50_display_early_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index 302f7ebe5b6f..87266d1b5def 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -26,6 +26,8 @@ #include "nouveau_drv.h" #include "nouveau_hw.h" +#include "nv50_display.h" + static void nv50_gpio_isr(struct drm_device *dev); static int @@ -109,6 +111,8 @@ nv50_gpio_init(struct drm_device *dev) nv_wr32(dev, 0xe074, 0xffffffff); } + INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); + spin_lock_init(&dev_priv->hpd_state.lock); nouveau_irq_register(dev, 21, nv50_gpio_isr); return 0; } -- cgit v1.2.3 From 8cbe71a6e70b5439ae60bd542231c4b8878a8f1c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 10:45:48 +1000 Subject: drm/nouveau: move bitfield/enum helpers to nouveau_util.c Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 86 +++++++--------------------------- drivers/gpu/drm/nouveau/nouveau_util.c | 33 +++++++++++++ drivers/gpu/drm/nouveau/nouveau_util.h | 12 +++++ 3 files changed, 63 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 2f546884f2ed..e8a3c400f741 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -267,28 +267,25 @@ nouveau_fifo_irq_handler(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); } -struct nouveau_bitfield_names { - uint32_t mask; - const char *name; -}; - -static struct nouveau_bitfield_names nstatus_names[] = +static struct nouveau_bitfield nstatus_names[] = { { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, - { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" } + { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, + {} }; -static struct nouveau_bitfield_names nstatus_names_nv10[] = +static struct nouveau_bitfield nstatus_names_nv10[] = { { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, - { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" } + { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, + {} }; -static struct nouveau_bitfield_names nsource_names[] = +static struct nouveau_bitfield nsource_names[] = { { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" }, { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" }, @@ -309,57 +306,9 @@ static struct nouveau_bitfield_names nsource_names[] = { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" }, { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" }, { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" }, + {} }; -static void -nouveau_print_bitfield_names_(uint32_t value, - const struct nouveau_bitfield_names *namelist, - const int namelist_len) -{ - /* - * Caller must have already printed the KERN_* log level for us. - * Also the caller is responsible for adding the newline. - */ - int i; - for (i = 0; i < namelist_len; ++i) { - uint32_t mask = namelist[i].mask; - if (value & mask) { - printk(" %s", namelist[i].name); - value &= ~mask; - } - } - if (value) - printk(" (unknown bits 0x%08x)", value); -} -#define nouveau_print_bitfield_names(val, namelist) \ - nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist)) - -struct nouveau_enum_names { - uint32_t value; - const char *name; -}; - -static void -nouveau_print_enum_names_(uint32_t value, - const struct nouveau_enum_names *namelist, - const int namelist_len) -{ - /* - * Caller must have already printed the KERN_* log level for us. - * Also the caller is responsible for adding the newline. - */ - int i; - for (i = 0; i < namelist_len; ++i) { - if (value == namelist[i].value) { - printk("%s", namelist[i].name); - return; - } - } - printk("unknown value 0x%08x", value); -} -#define nouveau_print_enum_names(val, namelist) \ - nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist)) - static int nouveau_graph_chid_from_grctx(struct drm_device *dev) { @@ -482,12 +431,12 @@ nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id, if (dev_priv->card_type < NV_50) { NV_INFO(dev, "%s - nSource:", id); - nouveau_print_bitfield_names(nsource, nsource_names); + nouveau_bitfield_print(nsource_names, nsource); printk(", nStatus:"); if (dev_priv->card_type < NV_10) - nouveau_print_bitfield_names(nstatus, nstatus_names); + nouveau_bitfield_print(nstatus_names, nstatus); else - nouveau_print_bitfield_names(nstatus, nstatus_names_nv10); + nouveau_bitfield_print(nstatus_names_nv10, nstatus); printk("\n"); } @@ -631,13 +580,14 @@ nouveau_pgraph_irq_handler(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); } -static struct nouveau_enum_names nv50_mp_exec_error_names[] = +static struct nouveau_enum nv50_mp_exec_error_names[] = { { 3, "STACK_UNDERFLOW" }, { 4, "QUADON_ACTIVE" }, { 8, "TIMEOUT" }, { 0x10, "INVALID_OPCODE" }, { 0x40, "BREAKPOINT" }, + {} }; static void @@ -666,8 +616,7 @@ nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) ophigh= nv_rd32(dev, addr + 0x74); NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " "TP %d MP %d: ", tpid, i); - nouveau_print_enum_names(status, - nv50_mp_exec_error_names); + nouveau_enum_print(nv50_mp_exec_error_names, status); printk(" at %06x warp %d, opcode %08x %08x\n", pc&0xffffff, pc >> 24, oplow, ophigh); @@ -1020,7 +969,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev) } /* There must be a *lot* of these. Will take some time to gather them up. */ -static struct nouveau_enum_names nv50_data_error_names[] = +static struct nouveau_enum nv50_data_error_names[] = { { 4, "INVALID_VALUE" }, { 5, "INVALID_ENUM" }, @@ -1028,6 +977,7 @@ static struct nouveau_enum_names nv50_data_error_names[] = { 0xc, "INVALID_BITFIELD" }, { 0x28, "MP_NO_REG_SPACE" }, { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, + {} }; static void @@ -1126,8 +1076,8 @@ nv50_pgraph_irq_handler(struct drm_device *dev) nouveau_graph_dump_trap_info(dev, "PGRAPH_DATA_ERROR", &trap); NV_INFO (dev, "PGRAPH_DATA_ERROR - "); - nouveau_print_enum_names(nv_rd32(dev, 0x400110), - nv50_data_error_names); + nouveau_enum_print(nv50_data_error_names, + nv_rd32(dev, 0x400110)); printk("\n"); } status &= ~0x00100000; diff --git a/drivers/gpu/drm/nouveau/nouveau_util.c b/drivers/gpu/drm/nouveau/nouveau_util.c index e8b1eaaa212b..fbe0fb13bc1e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_util.c +++ b/drivers/gpu/drm/nouveau/nouveau_util.c @@ -27,8 +27,41 @@ #include +#include "nouveau_util.h" + static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); +void +nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) +{ + while (bf->name) { + if (value & bf->mask) { + printk(" %s", bf->name); + value &= ~bf->mask; + } + + bf++; + } + + if (value) + printk(" (unknown bits 0x%08x)", value); +} + +void +nouveau_enum_print(const struct nouveau_enum *en, u32 value) +{ + while (en->name) { + if (value == en->value) { + printk("%s", en->name); + return; + } + + en++; + } + + printk("(unknown enum 0x%08x)", value); +} + int nouveau_ratelimit(void) { diff --git a/drivers/gpu/drm/nouveau/nouveau_util.h b/drivers/gpu/drm/nouveau/nouveau_util.h index 9a7a7c18c99a..d9ceaea26f4b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_util.h +++ b/drivers/gpu/drm/nouveau/nouveau_util.h @@ -28,6 +28,18 @@ #ifndef __NOUVEAU_UTIL_H__ #define __NOUVEAU_UTIL_H__ +struct nouveau_bitfield { + u32 mask; + const char *name; +}; + +struct nouveau_enum { + u32 value; + const char *name; +}; + +void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value); +void nouveau_enum_print(const struct nouveau_enum *, u32 value); int nouveau_ratelimit(void); #endif -- cgit v1.2.3 From 25b85783da8c71e577c676173e9d60a1b7e6113a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 11:36:09 +1000 Subject: drm/nv04-nv40: register vblank isr Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_irq.c | 19 ------------------- drivers/gpu/drm/nouveau/nv04_display.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index e8a3c400f741..6c30669ac0b6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -1131,20 +1131,6 @@ nv50_pgraph_irq_handler(struct drm_device *dev) nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); } -static void -nouveau_crtc_irq_handler(struct drm_device *dev, int crtc) -{ - if (crtc & 1) { - nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); - drm_handle_vblank(dev, 0); - } - - if (crtc & 2) { - nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); - drm_handle_vblank(dev, 1); - } -} - irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS) { @@ -1174,11 +1160,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; } - if (status & NV_PMC_INTR_0_CRTCn_PENDING) { - nouveau_crtc_irq_handler(dev, (status>>24)&3); - status &= ~NV_PMC_INTR_0_CRTCn_PENDING; - } - for (i = 0; i < 32 && status; i++) { if (!(status & (1 << i)) || !dev_priv->irq_handler[i]) continue; diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 9e28cf772e3c..0978a5b326dc 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -32,6 +32,9 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" +static void nv04_vblank_crtc0_isr(struct drm_device *); +static void nv04_vblank_crtc1_isr(struct drm_device *); + static void nv04_display_store_initial_head_owner(struct drm_device *dev) { @@ -197,6 +200,8 @@ nv04_display_create(struct drm_device *dev) func->save(encoder); } + nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr); + nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr); return 0; } @@ -258,3 +263,16 @@ nv04_display_init(struct drm_device *dev) return 0; } +static void +nv04_vblank_crtc0_isr(struct drm_device *dev) +{ + nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); + drm_handle_vblank(dev, 0); +} + +static void +nv04_vblank_crtc1_isr(struct drm_device *dev) +{ + nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); + drm_handle_vblank(dev, 1); +} -- cgit v1.2.3 From 5178d40dff23b5eef7f0a3be2411fa6a347e750d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 10:56:05 +1000 Subject: drm/nouveau: move PFIFO ISR into nv04_fifo.c Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 + drivers/gpu/drm/nouveau/nouveau_irq.c | 203 ------------------------------- drivers/gpu/drm/nouveau/nouveau_state.c | 10 +- drivers/gpu/drm/nouveau/nv04_fifo.c | 206 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv10_fifo.c | 1 + drivers/gpu/drm/nouveau/nv40_fifo.c | 1 + drivers/gpu/drm/nouveau/nv50_fifo.c | 4 + 7 files changed, 219 insertions(+), 208 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c0fad126eaa4..e174479ab675 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1053,6 +1053,7 @@ extern void nvc0_fb_takedown(struct drm_device *); /* nv04_fifo.c */ extern int nv04_fifo_init(struct drm_device *); +extern void nv04_fifo_fini(struct drm_device *); extern void nv04_fifo_disable(struct drm_device *); extern void nv04_fifo_enable(struct drm_device *); extern bool nv04_fifo_reassign(struct drm_device *, bool); @@ -1062,6 +1063,7 @@ extern int nv04_fifo_create_context(struct nouveau_channel *); extern void nv04_fifo_destroy_context(struct nouveau_channel *); extern int nv04_fifo_load_context(struct nouveau_channel *); extern int nv04_fifo_unload_context(struct drm_device *); +extern void nv04_fifo_isr(struct drm_device *); /* nv10_fifo.c */ extern int nv10_fifo_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 6c30669ac0b6..16f42f774a9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -69,204 +69,6 @@ nouveau_irq_uninstall(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); } -static bool -nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; - struct nouveau_gpuobj *obj; - unsigned long flags; - const int subc = (addr >> 13) & 0x7; - const int mthd = addr & 0x1ffc; - bool handled = false; - u32 engine; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) - chan = dev_priv->channels.ptr[chid]; - if (unlikely(!chan)) - goto out; - - switch (mthd) { - case 0x0000: /* bind object to subchannel */ - obj = nouveau_ramht_find(chan, data); - if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) - break; - - chan->sw_subchannel[subc] = obj->class; - engine = 0x0000000f << (subc * 4); - - nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); - handled = true; - break; - default: - engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); - if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) - break; - - if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc], - mthd, data)) - handled = true; - break; - } - -out: - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - return handled; -} - -static void -nouveau_fifo_irq_handler(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; - uint32_t status, reassign; - int cnt = 0; - - reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; - while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { - uint32_t chid, get; - - nv_wr32(dev, NV03_PFIFO_CACHES, 0); - - chid = engine->fifo.channel_id(dev); - get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); - - if (status & NV_PFIFO_INTR_CACHE_ERROR) { - uint32_t mthd, data; - int ptr; - - /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before - * wrapping on my G80 chips, but CACHE1 isn't big - * enough for this much data.. Tests show that it - * wraps around to the start at GET=0x800.. No clue - * as to why.. - */ - ptr = (get & 0x7ff) >> 2; - - if (dev_priv->card_type < NV_40) { - mthd = nv_rd32(dev, - NV04_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(dev, - NV04_PFIFO_CACHE1_DATA(ptr)); - } else { - mthd = nv_rd32(dev, - NV40_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(dev, - NV40_PFIFO_CACHE1_DATA(ptr)); - } - - if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { - NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " - "Mthd 0x%04x Data 0x%08x\n", - chid, (mthd >> 13) & 7, mthd & 0x1ffc, - data); - } - - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); - nv_wr32(dev, NV03_PFIFO_INTR_0, - NV_PFIFO_INTR_CACHE_ERROR); - - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); - - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, - nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); - - status &= ~NV_PFIFO_INTR_CACHE_ERROR; - } - - if (status & NV_PFIFO_INTR_DMA_PUSHER) { - u32 dma_get = nv_rd32(dev, 0x003244); - u32 dma_put = nv_rd32(dev, 0x003240); - u32 push = nv_rd32(dev, 0x003220); - u32 state = nv_rd32(dev, 0x003228); - - if (dev_priv->card_type == NV_50) { - u32 ho_get = nv_rd32(dev, 0x003328); - u32 ho_put = nv_rd32(dev, 0x003320); - u32 ib_get = nv_rd32(dev, 0x003334); - u32 ib_put = nv_rd32(dev, 0x003330); - - if (nouveau_ratelimit()) - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " - "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " - "State 0x%08x Push 0x%08x\n", - chid, ho_get, dma_get, ho_put, - dma_put, ib_get, ib_put, state, - push); - - /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ - nv_wr32(dev, 0x003364, 0x00000000); - if (dma_get != dma_put || ho_get != ho_put) { - nv_wr32(dev, 0x003244, dma_put); - nv_wr32(dev, 0x003328, ho_put); - } else - if (ib_get != ib_put) { - nv_wr32(dev, 0x003334, ib_put); - } - } else { - NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " - "Put 0x%08x State 0x%08x Push 0x%08x\n", - chid, dma_get, dma_put, state, push); - - if (dma_get != dma_put) - nv_wr32(dev, 0x003244, dma_put); - } - - nv_wr32(dev, 0x003228, 0x00000000); - nv_wr32(dev, 0x003220, 0x00000001); - nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); - status &= ~NV_PFIFO_INTR_DMA_PUSHER; - } - - if (status & NV_PFIFO_INTR_SEMAPHORE) { - uint32_t sem; - - status &= ~NV_PFIFO_INTR_SEMAPHORE; - nv_wr32(dev, NV03_PFIFO_INTR_0, - NV_PFIFO_INTR_SEMAPHORE); - - sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); - nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); - - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); - } - - if (dev_priv->card_type == NV_50) { - if (status & 0x00000010) { - nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); - status &= ~0x00000010; - nv_wr32(dev, 0x002100, 0x00000010); - } - } - - if (status) { - if (nouveau_ratelimit()) - NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", - status, chid); - nv_wr32(dev, NV03_PFIFO_INTR_0, status); - status = 0; - } - - nv_wr32(dev, NV03_PFIFO_CACHES, reassign); - } - - if (status) { - NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); - nv_wr32(dev, 0x2140, 0); - nv_wr32(dev, 0x140, 0); - } - - nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); -} - static struct nouveau_bitfield nstatus_names[] = { { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, @@ -1146,11 +948,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - if (status & NV_PMC_INTR_0_PFIFO_PENDING) { - nouveau_fifo_irq_handler(dev); - status &= ~NV_PMC_INTR_0_PFIFO_PENDING; - } - if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { if (dev_priv->card_type >= NV_50) nv50_pgraph_irq_handler(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 84bff459491e..262545b58d96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -75,7 +75,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.unload_context = nv04_graph_unload_context; engine->fifo.channels = 16; engine->fifo.init = nv04_fifo_init; - engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.takedown = nv04_fifo_fini; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; @@ -132,7 +132,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.set_tile_region = nv10_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; - engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.takedown = nv04_fifo_fini; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; @@ -189,7 +189,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.set_tile_region = nv20_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; - engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.takedown = nv04_fifo_fini; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; @@ -246,7 +246,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.set_tile_region = nv20_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv10_fifo_init; - engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.takedown = nv04_fifo_fini; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; @@ -306,7 +306,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.set_tile_region = nv40_graph_set_tile_region; engine->fifo.channels = 32; engine->fifo.init = nv40_fifo_init; - engine->fifo.takedown = nouveau_stub_takedown; + engine->fifo.takedown = nv04_fifo_fini; engine->fifo.disable = nv04_fifo_disable; engine->fifo.enable = nv04_fifo_enable; engine->fifo.reassign = nv04_fifo_reassign; diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 4c0d3a8fca68..a32ba8ccaae6 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -28,6 +28,7 @@ #include "drm.h" #include "nouveau_drv.h" #include "nouveau_ramht.h" +#include "nouveau_util.h" #define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE)) #define NV04_RAMFC__SIZE 32 @@ -284,6 +285,7 @@ nv04_fifo_init_ramxx(struct drm_device *dev) static void nv04_fifo_init_intr(struct drm_device *dev) { + nouveau_irq_register(dev, 8, nv04_fifo_isr); nv_wr32(dev, 0x002100, 0xffffffff); nv_wr32(dev, 0x002140, 0xffffffff); } @@ -315,3 +317,207 @@ nv04_fifo_init(struct drm_device *dev) return 0; } +void +nv04_fifo_fini(struct drm_device *dev) +{ + nv_wr32(dev, 0x2140, 0x00000000); + nouveau_irq_unregister(dev, 8); +} + +static bool +nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = NULL; + struct nouveau_gpuobj *obj; + unsigned long flags; + const int subc = (addr >> 13) & 0x7; + const int mthd = addr & 0x1ffc; + bool handled = false; + u32 engine; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) + chan = dev_priv->channels.ptr[chid]; + if (unlikely(!chan)) + goto out; + + switch (mthd) { + case 0x0000: /* bind object to subchannel */ + obj = nouveau_ramht_find(chan, data); + if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) + break; + + chan->sw_subchannel[subc] = obj->class; + engine = 0x0000000f << (subc * 4); + + nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); + handled = true; + break; + default: + engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); + if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) + break; + + if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc], + mthd, data)) + handled = true; + break; + } + +out: + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return handled; +} + +void +nv04_fifo_isr(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; + uint32_t status, reassign; + int cnt = 0; + + reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; + while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { + uint32_t chid, get; + + nv_wr32(dev, NV03_PFIFO_CACHES, 0); + + chid = engine->fifo.channel_id(dev); + get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); + + if (status & NV_PFIFO_INTR_CACHE_ERROR) { + uint32_t mthd, data; + int ptr; + + /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before + * wrapping on my G80 chips, but CACHE1 isn't big + * enough for this much data.. Tests show that it + * wraps around to the start at GET=0x800.. No clue + * as to why.. + */ + ptr = (get & 0x7ff) >> 2; + + if (dev_priv->card_type < NV_40) { + mthd = nv_rd32(dev, + NV04_PFIFO_CACHE1_METHOD(ptr)); + data = nv_rd32(dev, + NV04_PFIFO_CACHE1_DATA(ptr)); + } else { + mthd = nv_rd32(dev, + NV40_PFIFO_CACHE1_METHOD(ptr)); + data = nv_rd32(dev, + NV40_PFIFO_CACHE1_DATA(ptr)); + } + + if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { + NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " + "Mthd 0x%04x Data 0x%08x\n", + chid, (mthd >> 13) & 7, mthd & 0x1ffc, + data); + } + + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); + nv_wr32(dev, NV03_PFIFO_INTR_0, + NV_PFIFO_INTR_CACHE_ERROR); + + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, + nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, + nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); + nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); + + nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, + nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + + status &= ~NV_PFIFO_INTR_CACHE_ERROR; + } + + if (status & NV_PFIFO_INTR_DMA_PUSHER) { + u32 dma_get = nv_rd32(dev, 0x003244); + u32 dma_put = nv_rd32(dev, 0x003240); + u32 push = nv_rd32(dev, 0x003220); + u32 state = nv_rd32(dev, 0x003228); + + if (dev_priv->card_type == NV_50) { + u32 ho_get = nv_rd32(dev, 0x003328); + u32 ho_put = nv_rd32(dev, 0x003320); + u32 ib_get = nv_rd32(dev, 0x003334); + u32 ib_put = nv_rd32(dev, 0x003330); + + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " + "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " + "State 0x%08x Push 0x%08x\n", + chid, ho_get, dma_get, ho_put, + dma_put, ib_get, ib_put, state, + push); + + /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ + nv_wr32(dev, 0x003364, 0x00000000); + if (dma_get != dma_put || ho_get != ho_put) { + nv_wr32(dev, 0x003244, dma_put); + nv_wr32(dev, 0x003328, ho_put); + } else + if (ib_get != ib_put) { + nv_wr32(dev, 0x003334, ib_put); + } + } else { + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " + "Put 0x%08x State 0x%08x Push 0x%08x\n", + chid, dma_get, dma_put, state, push); + + if (dma_get != dma_put) + nv_wr32(dev, 0x003244, dma_put); + } + + nv_wr32(dev, 0x003228, 0x00000000); + nv_wr32(dev, 0x003220, 0x00000001); + nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); + status &= ~NV_PFIFO_INTR_DMA_PUSHER; + } + + if (status & NV_PFIFO_INTR_SEMAPHORE) { + uint32_t sem; + + status &= ~NV_PFIFO_INTR_SEMAPHORE; + nv_wr32(dev, NV03_PFIFO_INTR_0, + NV_PFIFO_INTR_SEMAPHORE); + + sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); + nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + + nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); + } + + if (dev_priv->card_type == NV_50) { + if (status & 0x00000010) { + nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); + status &= ~0x00000010; + nv_wr32(dev, 0x002100, 0x00000010); + } + } + + if (status) { + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", + status, chid); + nv_wr32(dev, NV03_PFIFO_INTR_0, status); + status = 0; + } + + nv_wr32(dev, NV03_PFIFO_CACHES, reassign); + } + + if (status) { + NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); + nv_wr32(dev, 0x2140, 0); + nv_wr32(dev, 0x140, 0); + } + + nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); +} diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c index 912556f2e33c..acb9216e6d0a 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c @@ -208,6 +208,7 @@ nv10_fifo_init_ramxx(struct drm_device *dev) static void nv10_fifo_init_intr(struct drm_device *dev) { + nouveau_irq_register(dev, 8, nv04_fifo_isr); nv_wr32(dev, 0x002100, 0xffffffff); nv_wr32(dev, 0x002140, 0xffffffff); } diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 311ac9ea5d53..f6b3580c685a 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -268,6 +268,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev) static void nv40_fifo_init_intr(struct drm_device *dev) { + nouveau_irq_register(dev, 8, nv04_fifo_isr); nv_wr32(dev, 0x002100, 0xffffffff); nv_wr32(dev, 0x002140, 0xffffffff); } diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index d3295aae0c4e..ed18952ae7f4 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -106,6 +106,7 @@ nv50_fifo_init_intr(struct drm_device *dev) { NV_DEBUG(dev, "\n"); + nouveau_irq_register(dev, 8, nv04_fifo_isr); nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF); nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); } @@ -207,6 +208,9 @@ nv50_fifo_takedown(struct drm_device *dev) if (!pfifo->playlist[0]) return; + nv_wr32(dev, 0x2140, 0x00000000); + nouveau_irq_unregister(dev, 8); + nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); } -- cgit v1.2.3 From 274fec93cdd627408a799519fa602f2eecb14d2f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 3 Nov 2010 13:16:18 +1000 Subject: drm/nouveau: tidy+move PGRAPH ISRs to their respective *_graph.c files Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 8 +- drivers/gpu/drm/nouveau/nouveau_irq.c | 894 +------------------------------ drivers/gpu/drm/nouveau/nouveau_object.c | 18 + drivers/gpu/drm/nouveau/nv04_graph.c | 95 +++- drivers/gpu/drm/nouveau/nv10_graph.c | 72 ++- drivers/gpu/drm/nouveau/nv20_graph.c | 47 ++ drivers/gpu/drm/nouveau/nv40_graph.c | 69 +++ drivers/gpu/drm/nouveau/nv50_graph.c | 500 ++++++++++++++++- 8 files changed, 809 insertions(+), 894 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e174479ab675..b19ef7fbb9dd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -54,6 +54,7 @@ struct nouveau_fpriv { #include "nouveau_drm.h" #include "nouveau_reg.h" #include "nouveau_bios.h" +#include "nouveau_util.h" struct nouveau_grctx; #define MAX_NUM_DCB_ENTRIES 16 @@ -872,6 +873,7 @@ extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd, int (*exec)(struct nouveau_channel *, u32 class, u32 mthd, u32 data)); extern int nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32); +extern int nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32); extern int nouveau_gpuobj_channel_init(struct nouveau_channel *, uint32_t vram_h, uint32_t tt_h); extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); @@ -1110,9 +1112,9 @@ extern int nv04_graph_create_context(struct nouveau_channel *); extern void nv04_graph_destroy_context(struct nouveau_channel *); extern int nv04_graph_load_context(struct nouveau_channel *); extern int nv04_graph_unload_context(struct drm_device *); -extern void nv04_graph_context_switch(struct drm_device *); extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data); +extern struct nouveau_bitfield nv04_graph_nsource[]; /* nv10_graph.c */ extern int nv10_graph_init(struct drm_device *); @@ -1122,8 +1124,9 @@ extern int nv10_graph_create_context(struct nouveau_channel *); extern void nv10_graph_destroy_context(struct nouveau_channel *); extern int nv10_graph_load_context(struct nouveau_channel *); extern int nv10_graph_unload_context(struct drm_device *); -extern void nv10_graph_context_switch(struct drm_device *); extern void nv10_graph_set_tile_region(struct drm_device *dev, int i); +extern struct nouveau_bitfield nv10_graph_intr[]; +extern struct nouveau_bitfield nv10_graph_nstatus[]; /* nv20_graph.c */ extern int nv20_graph_create_context(struct nouveau_channel *); @@ -1155,7 +1158,6 @@ extern int nv50_graph_create_context(struct nouveau_channel *); extern void nv50_graph_destroy_context(struct nouveau_channel *); extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_unload_context(struct drm_device *); -extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); extern void nv50_graph_tlb_flush(struct drm_device *dev); extern void nv86_graph_tlb_flush(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 16f42f774a9e..2ba7265bc967 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -69,910 +69,34 @@ nouveau_irq_uninstall(struct drm_device *dev) nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); } -static struct nouveau_bitfield nstatus_names[] = -{ - { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, - { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, - { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, - { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, - {} -}; - -static struct nouveau_bitfield nstatus_names_nv10[] = -{ - { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, - { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, - { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, - { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, - {} -}; - -static struct nouveau_bitfield nsource_names[] = -{ - { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" }, - { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" }, - { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" }, - { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" }, - { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" }, - { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" }, - { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" }, - { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" }, - { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" }, - { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" }, - { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" }, - { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" }, - { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" }, - { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" }, - { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" }, - { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" }, - { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" }, - { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" }, - { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" }, - {} -}; - -static int -nouveau_graph_chid_from_grctx(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - unsigned long flags; - uint32_t inst; - int i; - - if (dev_priv->card_type < NV_40) - return dev_priv->engine.fifo.channels; - else - if (dev_priv->card_type < NV_50) { - inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->ramin_grctx) - continue; - - if (inst == chan->ramin_grctx->pinst) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - } else { - inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->ramin) - continue; - - if (inst == chan->ramin->vinst) - break; - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - } - - - return i; -} - -static int -nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; - int channel; - - if (dev_priv->card_type < NV_10) - channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf; - else - if (dev_priv->card_type < NV_40) - channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; - else - channel = nouveau_graph_chid_from_grctx(dev); - - if (channel >= engine->fifo.channels || - !dev_priv->channels.ptr[channel]) { - NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel); - return -EINVAL; - } - - *channel_ret = channel; - return 0; -} - -struct nouveau_pgraph_trap { - int channel; - int class; - int subc, mthd, size; - uint32_t data, data2; - uint32_t nsource, nstatus; -}; - -static void -nouveau_graph_trap_info(struct drm_device *dev, - struct nouveau_pgraph_trap *trap) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t address; - - trap->nsource = trap->nstatus = 0; - if (dev_priv->card_type < NV_50) { - trap->nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - trap->nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); - } - - if (nouveau_graph_trapped_channel(dev, &trap->channel)) - trap->channel = -1; - address = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); - - trap->mthd = address & 0x1FFC; - trap->data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); - if (dev_priv->card_type < NV_10) { - trap->subc = (address >> 13) & 0x7; - } else { - trap->subc = (address >> 16) & 0x7; - trap->data2 = nv_rd32(dev, NV10_PGRAPH_TRAPPED_DATA_HIGH); - } - - if (dev_priv->card_type < NV_10) - trap->class = nv_rd32(dev, 0x400180 + trap->subc*4) & 0xFF; - else if (dev_priv->card_type < NV_40) - trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFF; - else if (dev_priv->card_type < NV_50) - trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFFF; - else - trap->class = nv_rd32(dev, 0x400814); -} - -static void -nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id, - struct nouveau_pgraph_trap *trap) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t nsource = trap->nsource, nstatus = trap->nstatus; - - if (dev_priv->card_type < NV_50) { - NV_INFO(dev, "%s - nSource:", id); - nouveau_bitfield_print(nsource_names, nsource); - printk(", nStatus:"); - if (dev_priv->card_type < NV_10) - nouveau_bitfield_print(nstatus_names, nstatus); - else - nouveau_bitfield_print(nstatus_names_nv10, nstatus); - printk("\n"); - } - - NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x " - "Data 0x%08x:0x%08x\n", - id, trap->channel, trap->subc, - trap->class, trap->mthd, - trap->data2, trap->data); -} - -static int -nouveau_pgraph_intr_swmthd(struct drm_device *dev, - struct nouveau_pgraph_trap *trap) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&dev_priv->channels.lock, flags); - if (trap->channel > 0 && - trap->channel < dev_priv->engine.fifo.channels && - dev_priv->channels.ptr[trap->channel]) { - chan = dev_priv->channels.ptr[trap->channel]; - ret = nouveau_gpuobj_mthd_call(chan, trap->class, trap->mthd, trap->data); - } - spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - - return ret; -} - -static inline void -nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) -{ - struct nouveau_pgraph_trap trap; - int unhandled = 0; - - nouveau_graph_trap_info(dev, &trap); - - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - if (nouveau_pgraph_intr_swmthd(dev, &trap)) - unhandled = 1; - } else { - unhandled = 1; - } - - if (unhandled) - nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap); -} - - -static inline void -nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) -{ - struct nouveau_pgraph_trap trap; - int unhandled = 0; - - nouveau_graph_trap_info(dev, &trap); - trap.nsource = nsource; - - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - if (nouveau_pgraph_intr_swmthd(dev, &trap)) - unhandled = 1; - } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { - uint32_t v = nv_rd32(dev, 0x402000); - nv_wr32(dev, 0x402000, v); - - /* dump the error anyway for now: it's useful for - Gallium development */ - unhandled = 1; - } else { - unhandled = 1; - } - - if (unhandled && nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR", &trap); -} - -static inline void -nouveau_pgraph_intr_context_switch(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; - uint32_t chid; - - chid = engine->fifo.channel_id(dev); - NV_DEBUG(dev, "PGRAPH context switch interrupt channel %x\n", chid); - - switch (dev_priv->card_type) { - case NV_04: - nv04_graph_context_switch(dev); - break; - case NV_10: - nv10_graph_context_switch(dev); - break; - default: - NV_ERROR(dev, "Context switch not implemented\n"); - break; - } -} - -static void -nouveau_pgraph_irq_handler(struct drm_device *dev) -{ - uint32_t status; - - while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { - uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); - - if (status & NV_PGRAPH_INTR_NOTIFY) { - nouveau_pgraph_intr_notify(dev, nsource); - - status &= ~NV_PGRAPH_INTR_NOTIFY; - nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY); - } - - if (status & NV_PGRAPH_INTR_ERROR) { - nouveau_pgraph_intr_error(dev, nsource); - - status &= ~NV_PGRAPH_INTR_ERROR; - nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR); - } - - if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv_wr32(dev, NV03_PGRAPH_INTR, - NV_PGRAPH_INTR_CONTEXT_SWITCH); - - nouveau_pgraph_intr_context_switch(dev); - } - - if (status) { - NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status); - nv_wr32(dev, NV03_PGRAPH_INTR, status); - } - - if ((nv_rd32(dev, NV04_PGRAPH_FIFO) & (1 << 0)) == 0) - nv_wr32(dev, NV04_PGRAPH_FIFO, 1); - } - - nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); -} - -static struct nouveau_enum nv50_mp_exec_error_names[] = -{ - { 3, "STACK_UNDERFLOW" }, - { 4, "QUADON_ACTIVE" }, - { 8, "TIMEOUT" }, - { 0x10, "INVALID_OPCODE" }, - { 0x40, "BREAKPOINT" }, - {} -}; - -static void -nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t units = nv_rd32(dev, 0x1540); - uint32_t addr, mp10, status, pc, oplow, ophigh; - int i; - int mps = 0; - for (i = 0; i < 4; i++) { - if (!(units & 1 << (i+24))) - continue; - if (dev_priv->chipset < 0xa0) - addr = 0x408200 + (tpid << 12) + (i << 7); - else - addr = 0x408100 + (tpid << 11) + (i << 7); - mp10 = nv_rd32(dev, addr + 0x10); - status = nv_rd32(dev, addr + 0x14); - if (!status) - continue; - if (display) { - nv_rd32(dev, addr + 0x20); - pc = nv_rd32(dev, addr + 0x24); - oplow = nv_rd32(dev, addr + 0x70); - ophigh= nv_rd32(dev, addr + 0x74); - NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " - "TP %d MP %d: ", tpid, i); - nouveau_enum_print(nv50_mp_exec_error_names, status); - printk(" at %06x warp %d, opcode %08x %08x\n", - pc&0xffffff, pc >> 24, - oplow, ophigh); - } - nv_wr32(dev, addr + 0x10, mp10); - nv_wr32(dev, addr + 0x14, 0); - mps++; - } - if (!mps && display) - NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " - "No MPs claiming errors?\n", tpid); -} - -static void -nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, - uint32_t ustatus_new, int display, const char *name) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int tps = 0; - uint32_t units = nv_rd32(dev, 0x1540); - int i, r; - uint32_t ustatus_addr, ustatus; - for (i = 0; i < 16; i++) { - if (!(units & (1 << i))) - continue; - if (dev_priv->chipset < 0xa0) - ustatus_addr = ustatus_old + (i << 12); - else - ustatus_addr = ustatus_new + (i << 11); - ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; - if (!ustatus) - continue; - tps++; - switch (type) { - case 6: /* texture error... unknown for now */ - nv50_fb_vm_trap(dev, display, name); - if (display) { - NV_ERROR(dev, "magic set %d:\n", i); - for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) - NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, - nv_rd32(dev, r)); - } - break; - case 7: /* MP error */ - if (ustatus & 0x00010000) { - nv50_pgraph_mp_trap(dev, i, display); - ustatus &= ~0x00010000; - } - break; - case 8: /* TPDMA error */ - { - uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); - uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); - uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); - uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); - uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); - uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); - uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); - nv50_fb_vm_trap(dev, display, name); - /* 2d engine destination */ - if (ustatus & 0x00000010) { - if (display) { - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", - i, e14, e10); - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", - i, e0c, e18, e1c, e20, e24); - } - ustatus &= ~0x00000010; - } - /* Render target */ - if (ustatus & 0x00000040) { - if (display) { - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", - i, e14, e10); - NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", - i, e0c, e18, e1c, e20, e24); - } - ustatus &= ~0x00000040; - } - /* CUDA memory: l[], g[] or stack. */ - if (ustatus & 0x00000080) { - if (display) { - if (e18 & 0x80000000) { - /* g[] read fault? */ - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", - i, e14, e10 | ((e18 >> 24) & 0x1f)); - e18 &= ~0x1f000000; - } else if (e18 & 0xc) { - /* g[] write fault? */ - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", - i, e14, e10 | ((e18 >> 7) & 0x1f)); - e18 &= ~0x00000f80; - } else { - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", - i, e14, e10); - } - NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", - i, e0c, e18, e1c, e20, e24); - } - ustatus &= ~0x00000080; - } - } - break; - } - if (ustatus) { - if (display) - NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); - } - nv_wr32(dev, ustatus_addr, 0xc0000000); - } - - if (!tps && display) - NV_INFO(dev, "%s - No TPs claiming errors?\n", name); -} - -static void -nv50_pgraph_trap_handler(struct drm_device *dev) -{ - struct nouveau_pgraph_trap trap; - uint32_t status = nv_rd32(dev, 0x400108); - uint32_t ustatus; - int display = nouveau_ratelimit(); - - - if (!status && display) { - nouveau_graph_trap_info(dev, &trap); - nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap); - NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n"); - } - - /* DISPATCH: Relays commands to other units and handles NOTIFY, - * COND, QUERY. If you get a trap from it, the command is still stuck - * in DISPATCH and you need to do something about it. */ - if (status & 0x001) { - ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; - if (!ustatus && display) { - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); - } - - /* Known to be triggered by screwed up NOTIFY and COND... */ - if (ustatus & 0x00000001) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT"); - nv_wr32(dev, 0x400500, 0); - if (nv_rd32(dev, 0x400808) & 0x80000000) { - if (display) { - if (nouveau_graph_trapped_channel(dev, &trap.channel)) - trap.channel = -1; - trap.class = nv_rd32(dev, 0x400814); - trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc; - trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7; - trap.data = nv_rd32(dev, 0x40080c); - trap.data2 = nv_rd32(dev, 0x400810); - nouveau_graph_dump_trap_info(dev, - "PGRAPH_TRAP_DISPATCH_FAULT", &trap); - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808)); - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848)); - } - nv_wr32(dev, 0x400808, 0); - } else if (display) { - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n"); - } - nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); - nv_wr32(dev, 0x400848, 0); - ustatus &= ~0x00000001; - } - if (ustatus & 0x00000002) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY"); - nv_wr32(dev, 0x400500, 0); - if (nv_rd32(dev, 0x40084c) & 0x80000000) { - if (display) { - if (nouveau_graph_trapped_channel(dev, &trap.channel)) - trap.channel = -1; - trap.class = nv_rd32(dev, 0x400814); - trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc; - trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7; - trap.data = nv_rd32(dev, 0x40085c); - trap.data2 = 0; - nouveau_graph_dump_trap_info(dev, - "PGRAPH_TRAP_DISPATCH_QUERY", &trap); - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c)); - } - nv_wr32(dev, 0x40084c, 0); - } else if (display) { - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n"); - } - ustatus &= ~0x00000002; - } - if (ustatus && display) - NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus); - nv_wr32(dev, 0x400804, 0xc0000000); - nv_wr32(dev, 0x400108, 0x001); - status &= ~0x001; - } - - /* TRAPs other than dispatch use the "normal" trap regs. */ - if (status && display) { - nouveau_graph_trap_info(dev, &trap); - nouveau_graph_dump_trap_info(dev, - "PGRAPH_TRAP", &trap); - } - - /* M2MF: Memory to memory copy engine. */ - if (status & 0x002) { - ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; - if (!ustatus && display) { - NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n"); - } - if (ustatus & 0x00000001) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY"); - ustatus &= ~0x00000001; - } - if (ustatus & 0x00000002) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN"); - ustatus &= ~0x00000002; - } - if (ustatus & 0x00000004) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT"); - ustatus &= ~0x00000004; - } - NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n", - nv_rd32(dev, 0x406804), - nv_rd32(dev, 0x406808), - nv_rd32(dev, 0x40680c), - nv_rd32(dev, 0x406810)); - if (ustatus && display) - NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus); - /* No sane way found yet -- just reset the bugger. */ - nv_wr32(dev, 0x400040, 2); - nv_wr32(dev, 0x400040, 0); - nv_wr32(dev, 0x406800, 0xc0000000); - nv_wr32(dev, 0x400108, 0x002); - status &= ~0x002; - } - - /* VFETCH: Fetches data from vertex buffers. */ - if (status & 0x004) { - ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; - if (!ustatus && display) { - NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n"); - } - if (ustatus & 0x00000001) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT"); - NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n", - nv_rd32(dev, 0x400c00), - nv_rd32(dev, 0x400c08), - nv_rd32(dev, 0x400c0c), - nv_rd32(dev, 0x400c10)); - ustatus &= ~0x00000001; - } - if (ustatus && display) - NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus); - nv_wr32(dev, 0x400c04, 0xc0000000); - nv_wr32(dev, 0x400108, 0x004); - status &= ~0x004; - } - - /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ - if (status & 0x008) { - ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; - if (!ustatus && display) { - NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n"); - } - if (ustatus & 0x00000001) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT"); - NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n", - nv_rd32(dev, 0x401804), - nv_rd32(dev, 0x401808), - nv_rd32(dev, 0x40180c), - nv_rd32(dev, 0x401810)); - ustatus &= ~0x00000001; - } - if (ustatus && display) - NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus); - /* No sane way found yet -- just reset the bugger. */ - nv_wr32(dev, 0x400040, 0x80); - nv_wr32(dev, 0x400040, 0); - nv_wr32(dev, 0x401800, 0xc0000000); - nv_wr32(dev, 0x400108, 0x008); - status &= ~0x008; - } - - /* CCACHE: Handles code and c[] caches and fills them. */ - if (status & 0x010) { - ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; - if (!ustatus && display) { - NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n"); - } - if (ustatus & 0x00000001) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT"); - NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n", - nv_rd32(dev, 0x405800), - nv_rd32(dev, 0x405804), - nv_rd32(dev, 0x405808), - nv_rd32(dev, 0x40580c), - nv_rd32(dev, 0x405810), - nv_rd32(dev, 0x405814), - nv_rd32(dev, 0x40581c)); - ustatus &= ~0x00000001; - } - if (ustatus && display) - NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus); - nv_wr32(dev, 0x405018, 0xc0000000); - nv_wr32(dev, 0x400108, 0x010); - status &= ~0x010; - } - - /* Unknown, not seen yet... 0x402000 is the only trap status reg - * remaining, so try to handle it anyway. Perhaps related to that - * unknown DMA slot on tesla? */ - if (status & 0x20) { - nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04"); - ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; - if (display) - NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus); - nv_wr32(dev, 0x402000, 0xc0000000); - /* no status modifiction on purpose */ - } - - /* TEXTURE: CUDA texturing units */ - if (status & 0x040) { - nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display, - "PGRAPH_TRAP_TEXTURE"); - nv_wr32(dev, 0x400108, 0x040); - status &= ~0x040; - } - - /* MP: CUDA execution engines. */ - if (status & 0x080) { - nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display, - "PGRAPH_TRAP_MP"); - nv_wr32(dev, 0x400108, 0x080); - status &= ~0x080; - } - - /* TPDMA: Handles TP-initiated uncached memory accesses: - * l[], g[], stack, 2d surfaces, render targets. */ - if (status & 0x100) { - nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display, - "PGRAPH_TRAP_TPDMA"); - nv_wr32(dev, 0x400108, 0x100); - status &= ~0x100; - } - - if (status) { - if (display) - NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n", - status); - nv_wr32(dev, 0x400108, status); - } -} - -/* There must be a *lot* of these. Will take some time to gather them up. */ -static struct nouveau_enum nv50_data_error_names[] = -{ - { 4, "INVALID_VALUE" }, - { 5, "INVALID_ENUM" }, - { 8, "INVALID_OBJECT" }, - { 0xc, "INVALID_BITFIELD" }, - { 0x28, "MP_NO_REG_SPACE" }, - { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, - {} -}; - -static void -nv50_pgraph_irq_handler(struct drm_device *dev) -{ - struct nouveau_pgraph_trap trap; - int unhandled = 0; - uint32_t status; - - while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { - /* NOTIFY: You've set a NOTIFY an a command and it's done. */ - if (status & 0x00000001) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_NOTIFY", &trap); - status &= ~0x00000001; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); - } - - /* COMPUTE_QUERY: Purpose and exact cause unknown, happens - * when you write 0x200 to 0x50c0 method 0x31c. */ - if (status & 0x00000002) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_COMPUTE_QUERY", &trap); - status &= ~0x00000002; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002); - } - - /* Unknown, never seen: 0x4 */ - - /* ILLEGAL_MTHD: You used a wrong method for this class. */ - if (status & 0x00000010) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_pgraph_intr_swmthd(dev, &trap)) - unhandled = 1; - if (unhandled && nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_ILLEGAL_MTHD", &trap); - status &= ~0x00000010; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); - } - - /* ILLEGAL_CLASS: You used a wrong class. */ - if (status & 0x00000020) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_ILLEGAL_CLASS", &trap); - status &= ~0x00000020; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020); - } - - /* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */ - if (status & 0x00000040) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_DOUBLE_NOTIFY", &trap); - status &= ~0x00000040; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040); - } - - /* CONTEXT_SWITCH: PGRAPH needs us to load a new context */ - if (status & 0x00001000) { - nv_wr32(dev, 0x400500, 0x00000000); - nv_wr32(dev, NV03_PGRAPH_INTR, - NV_PGRAPH_INTR_CONTEXT_SWITCH); - nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev, - NV40_PGRAPH_INTR_EN) & - ~NV_PGRAPH_INTR_CONTEXT_SWITCH); - nv_wr32(dev, 0x400500, 0x00010001); - - nv50_graph_context_switch(dev); - - status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - } - - /* BUFFER_NOTIFY: Your m2mf transfer finished */ - if (status & 0x00010000) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_BUFFER_NOTIFY", &trap); - status &= ~0x00010000; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000); - } - - /* DATA_ERROR: Invalid value for this method, or invalid - * state in current PGRAPH context for this operation */ - if (status & 0x00100000) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) { - nouveau_graph_dump_trap_info(dev, - "PGRAPH_DATA_ERROR", &trap); - NV_INFO (dev, "PGRAPH_DATA_ERROR - "); - nouveau_enum_print(nv50_data_error_names, - nv_rd32(dev, 0x400110)); - printk("\n"); - } - status &= ~0x00100000; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); - } - - /* TRAP: Something bad happened in the middle of command - * execution. Has a billion types, subtypes, and even - * subsubtypes. */ - if (status & 0x00200000) { - nv50_pgraph_trap_handler(dev); - status &= ~0x00200000; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); - } - - /* Unknown, never seen: 0x00400000 */ - - /* SINGLE_STEP: Happens on every method if you turned on - * single stepping in 40008c */ - if (status & 0x01000000) { - nouveau_graph_trap_info(dev, &trap); - if (nouveau_ratelimit()) - nouveau_graph_dump_trap_info(dev, - "PGRAPH_SINGLE_STEP", &trap); - status &= ~0x01000000; - nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000); - } - - /* 0x02000000 happens when you pause a ctxprog... - * but the only way this can happen that I know is by - * poking the relevant MMIO register, and we don't - * do that. */ - - if (status) { - NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", - status); - nv_wr32(dev, NV03_PGRAPH_INTR, status); - } - - { - const int isb = (1 << 16) | (1 << 0); - - if ((nv_rd32(dev, 0x400500) & isb) != isb) - nv_wr32(dev, 0x400500, - nv_rd32(dev, 0x400500) | isb); - } - } - - nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); - if (nv_rd32(dev, 0x400824) & (1 << 31)) - nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); -} - irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *)arg; struct drm_nouveau_private *dev_priv = dev->dev_private; unsigned long flags; - u32 status; + u32 stat; int i; - status = nv_rd32(dev, NV03_PMC_INTR_0); - if (!status) + stat = nv_rd32(dev, NV03_PMC_INTR_0); + if (!stat) return IRQ_NONE; spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - - if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { - if (dev_priv->card_type >= NV_50) - nv50_pgraph_irq_handler(dev); - else - nouveau_pgraph_irq_handler(dev); - - status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; - } - - for (i = 0; i < 32 && status; i++) { - if (!(status & (1 << i)) || !dev_priv->irq_handler[i]) + for (i = 0; i < 32 && stat; i++) { + if (!(stat & (1 << i)) || !dev_priv->irq_handler[i]) continue; dev_priv->irq_handler[i](dev); - status &= ~(1 << i); + stat &= ~(1 << i); } - if (status) - NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); - - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - if (dev_priv->msi_enabled) nv_wr08(dev, 0x00088068, 0xff); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + if (stat && nouveau_ratelimit()) + NV_ERROR(dev, "PMC - unhandled INTR 0x%08x\n", stat); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 54078186fe65..94429553433c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -113,6 +113,24 @@ nouveau_gpuobj_mthd_call(struct nouveau_channel *chan, return -ENOENT; } +int +nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid, + u32 class, u32 mthd, u32 data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = NULL; + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + if (chid > 0 && chid < dev_priv->engine.fifo.channels) + chan = dev_priv->channels.ptr[chid]; + if (chan) + ret = nouveau_gpuobj_mthd_call(chan, class, mthd, data); + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return ret; +} + /* NVidia uses context objects to drive drawing operations. Context objects can be selected into 8 subchannels in the FIFO, diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 239519aefce6..0bc616d35eb6 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -27,8 +27,10 @@ #include "nouveau_drm.h" #include "nouveau_drv.h" #include "nouveau_hw.h" +#include "nouveau_util.h" -static int nv04_graph_register(struct drm_device *dev); +static int nv04_graph_register(struct drm_device *dev); +static void nv04_graph_isr(struct drm_device *dev); static uint32_t nv04_graph_ctx_regs[] = { 0x0040053c, @@ -363,7 +365,7 @@ nv04_graph_channel(struct drm_device *dev) return dev_priv->channels.ptr[chid]; } -void +static void nv04_graph_context_switch(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -498,6 +500,7 @@ int nv04_graph_init(struct drm_device *dev) return ret; /* Enable PGRAPH interrupts */ + nouveau_irq_register(dev, 12, nv04_graph_isr); nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -533,6 +536,8 @@ int nv04_graph_init(struct drm_device *dev) void nv04_graph_takedown(struct drm_device *dev) { + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + nouveau_irq_unregister(dev, 12); } void @@ -1224,3 +1229,89 @@ nv04_graph_register(struct drm_device *dev) dev_priv->engine.graph.registered = true; return 0; }; + +static struct nouveau_bitfield nv04_graph_intr[] = { + { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, + {} +}; + +static struct nouveau_bitfield nv04_graph_nstatus[] = +{ + { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, + { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, + { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, + { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, + {} +}; + +struct nouveau_bitfield nv04_graph_nsource[] = +{ + { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" }, + { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" }, + { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" }, + { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" }, + { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" }, + { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" }, + { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" }, + { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" }, + { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" }, + { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" }, + { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" }, + { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" }, + { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" }, + { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" }, + { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" }, + { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" }, + { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" }, + { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" }, + { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" }, + {} +}; + +static void +nv04_graph_isr(struct drm_device *dev) +{ + u32 stat; + + while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { + u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); + u32 chid = (addr & 0x0f000000) >> 24; + u32 subc = (addr & 0x0000e000) >> 13; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff; + u32 show = stat; + + if (stat & NV_PGRAPH_INTR_NOTIFY) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) + show &= ~NV_PGRAPH_INTR_NOTIFY; + } + } + + if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + nv04_graph_context_switch(dev); + } + + nv_wr32(dev, NV03_PGRAPH_INTR, stat); + nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); + + if (show && nouveau_ratelimit()) { + NV_INFO(dev, "PGRAPH -"); + nouveau_bitfield_print(nv04_graph_intr, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv04_graph_nstatus, nstatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, subc, class, mthd, data); + } + } +} diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 1cd141edca04..536b39e4a9e2 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -26,8 +26,10 @@ #include "drm.h" #include "nouveau_drm.h" #include "nouveau_drv.h" +#include "nouveau_util.h" -static int nv10_graph_register(struct drm_device *); +static int nv10_graph_register(struct drm_device *); +static void nv10_graph_isr(struct drm_device *); #define NV10_FIFO_NUMBER 32 @@ -788,7 +790,7 @@ nv10_graph_unload_context(struct drm_device *dev) return 0; } -void +static void nv10_graph_context_switch(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -924,6 +926,7 @@ int nv10_graph_init(struct drm_device *dev) if (ret) return ret; + nouveau_irq_register(dev, 12, nv10_graph_isr); nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -966,6 +969,8 @@ int nv10_graph_init(struct drm_device *dev) void nv10_graph_takedown(struct drm_device *dev) { + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + nouveau_irq_unregister(dev, 12); } static int @@ -1117,3 +1122,66 @@ nv10_graph_register(struct drm_device *dev) dev_priv->engine.graph.registered = true; return 0; } + +struct nouveau_bitfield nv10_graph_intr[] = { + { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, + { NV_PGRAPH_INTR_ERROR, "ERROR" }, + {} +}; + +struct nouveau_bitfield nv10_graph_nstatus[] = +{ + { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, + { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, + { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, + { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, + {} +}; + +static void +nv10_graph_isr(struct drm_device *dev) +{ + u32 stat; + + while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { + u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); + u32 chid = (addr & 0x01f00000) >> 20; + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff; + u32 show = stat; + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + } + } + + if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + nv10_graph_context_switch(dev); + } + + nv_wr32(dev, NV03_PGRAPH_INTR, stat); + nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); + + if (show && nouveau_ratelimit()) { + NV_INFO(dev, "PGRAPH -"); + nouveau_bitfield_print(nv10_graph_intr, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv10_graph_nstatus, nstatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, subc, class, mthd, data); + } + } +} diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index bd065c2fcba4..8464b76798d5 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -34,6 +34,7 @@ static int nv20_graph_register(struct drm_device *); static int nv30_graph_register(struct drm_device *); +static void nv20_graph_isr(struct drm_device *); static void nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) @@ -584,6 +585,7 @@ nv20_graph_init(struct drm_device *dev) return ret; } + nouveau_irq_register(dev, 12, nv20_graph_isr); nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -661,6 +663,9 @@ nv20_graph_takedown(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + nouveau_irq_unregister(dev, 12); + nouveau_gpuobj_ref(NULL, &pgraph->ctx_table); } @@ -712,6 +717,7 @@ nv30_graph_init(struct drm_device *dev) nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctx_table->pinst >> 4); + nouveau_irq_register(dev, 12, nv20_graph_isr); nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -850,3 +856,44 @@ nv30_graph_register(struct drm_device *dev) dev_priv->engine.graph.registered = true; return 0; } + +static void +nv20_graph_isr(struct drm_device *dev) +{ + u32 stat; + + while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { + u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); + u32 chid = (addr & 0x01f00000) >> 20; + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff; + u32 show = stat; + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + } + } + + nv_wr32(dev, NV03_PGRAPH_INTR, stat); + nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); + + if (show && nouveau_ratelimit()) { + NV_INFO(dev, "PGRAPH -"); + nouveau_bitfield_print(nv10_graph_intr, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv10_graph_nstatus, nstatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, subc, class, mthd, data); + } + } +} diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 7a51608b55ba..0618846a97ce 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -30,6 +30,7 @@ #include "nouveau_grctx.h" static int nv40_graph_register(struct drm_device *); +static void nv40_graph_isr(struct drm_device *); struct nouveau_channel * nv40_graph_channel(struct drm_device *dev) @@ -277,6 +278,7 @@ nv40_graph_init(struct drm_device *dev) /* No context present currently */ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + nouveau_irq_register(dev, 12, nv40_graph_isr); nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -408,6 +410,7 @@ nv40_graph_init(struct drm_device *dev) void nv40_graph_takedown(struct drm_device *dev) { + nouveau_irq_unregister(dev, 12); } static int @@ -449,3 +452,69 @@ nv40_graph_register(struct drm_device *dev) dev_priv->engine.graph.registered = true; return 0; } + +static int +nv40_graph_isr_chid(struct drm_device *dev, u32 inst) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; + unsigned long flags; + int i; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { + chan = dev_priv->channels.ptr[i]; + if (!chan || !chan->ramin_grctx) + continue; + + if (inst == chan->ramin_grctx->pinst) + break; + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return i; +} + +static void +nv40_graph_isr(struct drm_device *dev) +{ + u32 stat; + + while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) { + u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); + u32 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4; + u32 chid = nv40_graph_isr_chid(dev, inst); + u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff; + u32 show = stat; + + if (stat & NV_PGRAPH_INTR_ERROR) { + if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { + if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) + show &= ~NV_PGRAPH_INTR_ERROR; + } else + if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { + nv_mask(dev, 0x402000, 0, 0); + } + } + + nv_wr32(dev, NV03_PGRAPH_INTR, stat); + nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001); + + if (show && nouveau_ratelimit()) { + NV_INFO(dev, "PGRAPH -"); + nouveau_bitfield_print(nv10_graph_intr, show); + printk(" nsource:"); + nouveau_bitfield_print(nv04_graph_nsource, nsource); + printk(" nstatus:"); + nouveau_bitfield_print(nv10_graph_nstatus, nstatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + chid, inst, subc, class, mthd, data); + } + } +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 6785269f778a..b3900788c66d 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -32,7 +32,8 @@ #include "nouveau_dma.h" #include "nv50_evo.h" -static int nv50_graph_register(struct drm_device *); +static int nv50_graph_register(struct drm_device *); +static void nv50_graph_isr(struct drm_device *); static void nv50_graph_init_reset(struct drm_device *dev) @@ -50,6 +51,7 @@ nv50_graph_init_intr(struct drm_device *dev) { NV_DEBUG(dev, "\n"); + nouveau_irq_register(dev, 12, nv50_graph_isr); nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); nv_wr32(dev, 0x400138, 0xffffffff); nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); @@ -165,6 +167,8 @@ void nv50_graph_takedown(struct drm_device *dev) { NV_DEBUG(dev, "\n"); + nv_wr32(dev, 0x40013c, 0x00000000); + nouveau_irq_unregister(dev, 12); } void @@ -324,7 +328,7 @@ nv50_graph_unload_context(struct drm_device *dev) return 0; } -void +static void nv50_graph_context_switch(struct drm_device *dev) { uint32_t inst; @@ -512,3 +516,495 @@ nv86_graph_tlb_flush(struct drm_device *dev) nv_mask(dev, 0x400500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); } + +static struct nouveau_enum nv50_mp_exec_error_names[] = +{ + { 3, "STACK_UNDERFLOW" }, + { 4, "QUADON_ACTIVE" }, + { 8, "TIMEOUT" }, + { 0x10, "INVALID_OPCODE" }, + { 0x40, "BREAKPOINT" }, + {} +}; + +static struct nouveau_bitfield nv50_graph_trap_m2mf[] = { + { 0x00000001, "NOTIFY" }, + { 0x00000002, "IN" }, + { 0x00000004, "OUT" }, + {} +}; + +static struct nouveau_bitfield nv50_graph_trap_vfetch[] = { + { 0x00000001, "FAULT" }, + {} +}; + +static struct nouveau_bitfield nv50_graph_trap_strmout[] = { + { 0x00000001, "FAULT" }, + {} +}; + +static struct nouveau_bitfield nv50_graph_trap_ccache[] = { + { 0x00000001, "FAULT" }, + {} +}; + +/* There must be a *lot* of these. Will take some time to gather them up. */ +static struct nouveau_enum nv50_data_error_names[] = { + { 4, "INVALID_VALUE" }, + { 5, "INVALID_ENUM" }, + { 8, "INVALID_OBJECT" }, + { 0xc, "INVALID_BITFIELD" }, + { 0x28, "MP_NO_REG_SPACE" }, + { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, + {} +}; + +static struct nouveau_bitfield nv50_graph_intr[] = { + { 0x00000001, "NOTIFY" }, + { 0x00000002, "COMPUTE_QUERY" }, + { 0x00000010, "ILLEGAL_MTHD" }, + { 0x00000020, "ILLEGAL_CLASS" }, + { 0x00000040, "DOUBLE_NOTIFY" }, + { 0x00001000, "CONTEXT_SWITCH" }, + { 0x00010000, "BUFFER_NOTIFY" }, + { 0x00100000, "DATA_ERROR" }, + { 0x00200000, "TRAP" }, + { 0x01000000, "SINGLE_STEP" }, + {} +}; + +static void +nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t units = nv_rd32(dev, 0x1540); + uint32_t addr, mp10, status, pc, oplow, ophigh; + int i; + int mps = 0; + for (i = 0; i < 4; i++) { + if (!(units & 1 << (i+24))) + continue; + if (dev_priv->chipset < 0xa0) + addr = 0x408200 + (tpid << 12) + (i << 7); + else + addr = 0x408100 + (tpid << 11) + (i << 7); + mp10 = nv_rd32(dev, addr + 0x10); + status = nv_rd32(dev, addr + 0x14); + if (!status) + continue; + if (display) { + nv_rd32(dev, addr + 0x20); + pc = nv_rd32(dev, addr + 0x24); + oplow = nv_rd32(dev, addr + 0x70); + ophigh= nv_rd32(dev, addr + 0x74); + NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " + "TP %d MP %d: ", tpid, i); + nouveau_enum_print(nv50_mp_exec_error_names, status); + printk(" at %06x warp %d, opcode %08x %08x\n", + pc&0xffffff, pc >> 24, + oplow, ophigh); + } + nv_wr32(dev, addr + 0x10, mp10); + nv_wr32(dev, addr + 0x14, 0); + mps++; + } + if (!mps && display) + NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " + "No MPs claiming errors?\n", tpid); +} + +static void +nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, + uint32_t ustatus_new, int display, const char *name) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int tps = 0; + uint32_t units = nv_rd32(dev, 0x1540); + int i, r; + uint32_t ustatus_addr, ustatus; + for (i = 0; i < 16; i++) { + if (!(units & (1 << i))) + continue; + if (dev_priv->chipset < 0xa0) + ustatus_addr = ustatus_old + (i << 12); + else + ustatus_addr = ustatus_new + (i << 11); + ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; + if (!ustatus) + continue; + tps++; + switch (type) { + case 6: /* texture error... unknown for now */ + nv50_fb_vm_trap(dev, display, name); + if (display) { + NV_ERROR(dev, "magic set %d:\n", i); + for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) + NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, + nv_rd32(dev, r)); + } + break; + case 7: /* MP error */ + if (ustatus & 0x00010000) { + nv50_pgraph_mp_trap(dev, i, display); + ustatus &= ~0x00010000; + } + break; + case 8: /* TPDMA error */ + { + uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); + uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); + uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); + uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); + uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); + uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); + uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); + nv50_fb_vm_trap(dev, display, name); + /* 2d engine destination */ + if (ustatus & 0x00000010) { + if (display) { + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", + i, e14, e10); + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + i, e0c, e18, e1c, e20, e24); + } + ustatus &= ~0x00000010; + } + /* Render target */ + if (ustatus & 0x00000040) { + if (display) { + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", + i, e14, e10); + NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + i, e0c, e18, e1c, e20, e24); + } + ustatus &= ~0x00000040; + } + /* CUDA memory: l[], g[] or stack. */ + if (ustatus & 0x00000080) { + if (display) { + if (e18 & 0x80000000) { + /* g[] read fault? */ + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", + i, e14, e10 | ((e18 >> 24) & 0x1f)); + e18 &= ~0x1f000000; + } else if (e18 & 0xc) { + /* g[] write fault? */ + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", + i, e14, e10 | ((e18 >> 7) & 0x1f)); + e18 &= ~0x00000f80; + } else { + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", + i, e14, e10); + } + NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + i, e0c, e18, e1c, e20, e24); + } + ustatus &= ~0x00000080; + } + } + break; + } + if (ustatus) { + if (display) + NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + } + nv_wr32(dev, ustatus_addr, 0xc0000000); + } + + if (!tps && display) + NV_INFO(dev, "%s - No TPs claiming errors?\n", name); +} + +static int +nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid) +{ + u32 status = nv_rd32(dev, 0x400108); + u32 ustatus; + + if (!status && display) { + NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n"); + return 1; + } + + /* DISPATCH: Relays commands to other units and handles NOTIFY, + * COND, QUERY. If you get a trap from it, the command is still stuck + * in DISPATCH and you need to do something about it. */ + if (status & 0x001) { + ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; + if (!ustatus && display) { + NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); + } + + nv_wr32(dev, 0x400500, 0x00000000); + + /* Known to be triggered by screwed up NOTIFY and COND... */ + if (ustatus & 0x00000001) { + u32 addr = nv_rd32(dev, 0x400808); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 datal = nv_rd32(dev, 0x40080c); + u32 datah = nv_rd32(dev, 0x400810); + u32 class = nv_rd32(dev, 0x400814); + u32 r848 = nv_rd32(dev, 0x400848); + + NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n"); + if (display && (addr & 0x80000000)) { + NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x%08x " + "400808 0x%08x 400848 0x%08x\n", + chid, inst, subc, class, mthd, datah, + datal, addr, r848); + } else + if (display) { + NV_INFO(dev, "PGRAPH - no stuck command?\n"); + } + + nv_wr32(dev, 0x400808, 0); + nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); + nv_wr32(dev, 0x400848, 0); + ustatus &= ~0x00000001; + } + + if (ustatus & 0x00000002) { + u32 addr = nv_rd32(dev, 0x40084c); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(dev, 0x40085c); + u32 class = nv_rd32(dev, 0x400814); + + NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n"); + if (display && (addr & 0x80000000)) { + NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " + "subc %d class 0x%04x mthd 0x%04x " + "data 0x%08x 40084c 0x%08x\n", + chid, inst, subc, class, mthd, + data, addr); + } else + if (display) { + NV_INFO(dev, "PGRAPH - no stuck command?\n"); + } + + nv_wr32(dev, 0x40084c, 0); + ustatus &= ~0x00000002; + } + + if (ustatus && display) { + NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown " + "0x%08x)\n", ustatus); + } + + nv_wr32(dev, 0x400804, 0xc0000000); + nv_wr32(dev, 0x400108, 0x001); + status &= ~0x001; + if (!status) + return 0; + } + + /* M2MF: Memory to memory copy engine. */ + if (status & 0x002) { + u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; + if (display) { + NV_INFO(dev, "PGRAPH - TRAP_M2MF"); + nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n", + nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808), + nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810)); + + } + + /* No sane way found yet -- just reset the bugger. */ + nv_wr32(dev, 0x400040, 2); + nv_wr32(dev, 0x400040, 0); + nv_wr32(dev, 0x406800, 0xc0000000); + nv_wr32(dev, 0x400108, 0x002); + status &= ~0x002; + } + + /* VFETCH: Fetches data from vertex buffers. */ + if (status & 0x004) { + u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; + if (display) { + NV_INFO(dev, "PGRAPH - TRAP_VFETCH"); + nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n", + nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08), + nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10)); + } + + nv_wr32(dev, 0x400c04, 0xc0000000); + nv_wr32(dev, 0x400108, 0x004); + status &= ~0x004; + } + + /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ + if (status & 0x008) { + ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; + if (display) { + NV_INFO(dev, "PGRAPH - TRAP_STRMOUT"); + nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n", + nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808), + nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810)); + + } + + /* No sane way found yet -- just reset the bugger. */ + nv_wr32(dev, 0x400040, 0x80); + nv_wr32(dev, 0x400040, 0); + nv_wr32(dev, 0x401800, 0xc0000000); + nv_wr32(dev, 0x400108, 0x008); + status &= ~0x008; + } + + /* CCACHE: Handles code and c[] caches and fills them. */ + if (status & 0x010) { + ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; + if (display) { + NV_INFO(dev, "PGRAPH - TRAP_CCACHE"); + nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); + printk("\n"); + NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" + " %08x %08x %08x\n", + nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), + nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), + nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), + nv_rd32(dev, 0x40581c)); + + } + + nv_wr32(dev, 0x405018, 0xc0000000); + nv_wr32(dev, 0x400108, 0x010); + status &= ~0x010; + } + + /* Unknown, not seen yet... 0x402000 is the only trap status reg + * remaining, so try to handle it anyway. Perhaps related to that + * unknown DMA slot on tesla? */ + if (status & 0x20) { + ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; + if (display) + NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus); + nv_wr32(dev, 0x402000, 0xc0000000); + /* no status modifiction on purpose */ + } + + /* TEXTURE: CUDA texturing units */ + if (status & 0x040) { + nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display, + "PGRAPH - TRAP_TEXTURE"); + nv_wr32(dev, 0x400108, 0x040); + status &= ~0x040; + } + + /* MP: CUDA execution engines. */ + if (status & 0x080) { + nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display, + "PGRAPH - TRAP_MP"); + nv_wr32(dev, 0x400108, 0x080); + status &= ~0x080; + } + + /* TPDMA: Handles TP-initiated uncached memory accesses: + * l[], g[], stack, 2d surfaces, render targets. */ + if (status & 0x100) { + nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display, + "PGRAPH - TRAP_TPDMA"); + nv_wr32(dev, 0x400108, 0x100); + status &= ~0x100; + } + + if (status) { + if (display) + NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status); + nv_wr32(dev, 0x400108, status); + } + + return 1; +} + +static int +nv50_graph_isr_chid(struct drm_device *dev, u64 inst) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; + unsigned long flags; + int i; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { + chan = dev_priv->channels.ptr[i]; + if (!chan || !chan->ramin) + continue; + + if (inst == chan->ramin->vinst) + break; + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return i; +} + +static void +nv50_graph_isr(struct drm_device *dev) +{ + u32 stat; + + while ((stat = nv_rd32(dev, 0x400100))) { + u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12; + u32 chid = nv50_graph_isr_chid(dev, inst); + u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); + u32 subc = (addr & 0x00070000) >> 16; + u32 mthd = (addr & 0x00001ffc); + u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(dev, 0x400814); + u32 show = stat; + + if (stat & 0x00000010) { + if (!nouveau_gpuobj_mthd_call2(dev, chid, class, + mthd, data)) + show &= ~0x00000010; + } + + if (stat & 0x00001000) { + nv_wr32(dev, 0x400500, 0x00000000); + nv_wr32(dev, 0x400100, 0x00001000); + nv_mask(dev, 0x40013c, 0x00001000, 0x00000000); + nv50_graph_context_switch(dev); + stat &= ~0x00001000; + show &= ~0x00001000; + } + + show = (show && nouveau_ratelimit()) ? show : 0; + + if (show & 0x00100000) { + u32 ecode = nv_rd32(dev, 0x400110); + NV_INFO(dev, "PGRAPH - DATA_ERROR "); + nouveau_enum_print(nv50_data_error_names, ecode); + printk("\n"); + } + + if (stat & 0x00200000) { + if (!nv50_pgraph_trap_handler(dev, show, inst, chid)) + show &= ~0x00200000; + } + + nv_wr32(dev, 0x400100, stat); + nv_wr32(dev, 0x400500, 0x00010001); + + if (show) { + NV_INFO(dev, "PGRAPH -"); + nouveau_bitfield_print(nv50_graph_intr, show); + printk("\n"); + NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + chid, inst, subc, class, mthd, data); + } + } + + if (nv_rd32(dev, 0x400824) & (1 << 31)) + nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); +} -- cgit v1.2.3 From e4cbadcaaa4678020e37ca93502942ffdf9aef80 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 11 Nov 2010 13:59:05 +1000 Subject: drm/nv04-nv40: unregister irq handler on destroy Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_display.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 0978a5b326dc..1715e1464b7d 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -213,6 +213,9 @@ nv04_display_destroy(struct drm_device *dev) NV_DEBUG_KMS(dev, "\n"); + nouveau_irq_unregister(dev, 24); + nouveau_irq_unregister(dev, 25); + /* Turn every CRTC off. */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_mode_set modeset = { -- cgit v1.2.3 From fce2bad0ee2666d6a10bfeb634b1021469cc3d79 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 11 Nov 2010 16:14:56 +1000 Subject: drm/nv50: rework PGPIO IRQ handling and hotplug detection Allows callers to install their own handlers for when a GPIO line changes state (such as for hotplug detect). This also fixes a bug where we weren't acknowledging the GPIO IRQ until after the bottom half had run, causing a severe IRQ storm in some cases. Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 54 +++++++- drivers/gpu/drm/nouveau/nouveau_dp.c | 6 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 21 ++-- drivers/gpu/drm/nouveau/nouveau_state.c | 4 + drivers/gpu/drm/nouveau/nv50_display.c | 66 ---------- drivers/gpu/drm/nouveau/nv50_display.h | 1 - drivers/gpu/drm/nouveau/nv50_gpio.c | 186 +++++++++++++++++++++++++--- 7 files changed, 234 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 52c356e9a3d1..a21e00076839 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -37,6 +37,8 @@ #include "nouveau_connector.h" #include "nouveau_hw.h" +static void nouveau_connector_hotplug(void *, int); + static struct nouveau_encoder * find_encoder_by_type(struct drm_connector *connector, int type) { @@ -94,22 +96,30 @@ nouveau_connector_bpp(struct drm_connector *connector) } static void -nouveau_connector_destroy(struct drm_connector *drm_connector) +nouveau_connector_destroy(struct drm_connector *connector) { - struct nouveau_connector *nv_connector = - nouveau_connector(drm_connector); + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct drm_nouveau_private *dev_priv; + struct nouveau_gpio_engine *pgpio; struct drm_device *dev; if (!nv_connector) return; dev = nv_connector->base.dev; + dev_priv = dev->dev_private; NV_DEBUG_KMS(dev, "\n"); + pgpio = &dev_priv->engine.gpio; + if (pgpio->irq_unregister) { + pgpio->irq_unregister(dev, nv_connector->dcb->gpio_tag, + nouveau_connector_hotplug, connector); + } + kfree(nv_connector->edid); - drm_sysfs_connector_remove(drm_connector); - drm_connector_cleanup(drm_connector); - kfree(drm_connector); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(connector); } static struct nouveau_i2c_chan * @@ -760,6 +770,7 @@ nouveau_connector_create(struct drm_device *dev, int index) { const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; struct nouveau_connector *nv_connector = NULL; struct dcb_connector_table_entry *dcb = NULL; struct drm_connector *connector; @@ -876,6 +887,11 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } + if (pgpio->irq_register) { + pgpio->irq_register(dev, nv_connector->dcb->gpio_tag, + nouveau_connector_hotplug, connector); + } + drm_sysfs_connector_add(connector); dcb->drm = connector; return dcb->drm; @@ -886,3 +902,29 @@ fail: return ERR_PTR(ret); } + +static void +nouveau_connector_hotplug(void *data, int plugged) +{ + struct drm_connector *connector = data; + struct drm_device *dev = connector->dev; + + NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", + drm_get_connector_name(connector)); + + if (connector->encoder && connector->encoder->crtc && + connector->encoder->crtc->enabled) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder); + struct drm_encoder_helper_funcs *helper = + connector->encoder->helper_private; + + if (nv_encoder->dcb->type == OUTPUT_DP) { + if (plugged) + helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); + else + helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); + } + } + + drm_helper_hpd_irq_event(dev); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 4562f309ae3d..38d599554bce 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -279,7 +279,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder) struct bit_displayport_encoder_table *dpe; int dpe_headerlen; uint8_t config[4], status[3]; - bool cr_done, cr_max_vs, eq_done; + bool cr_done, cr_max_vs, eq_done, hpd_state; int ret = 0, i, tries, voltage; NV_DEBUG_KMS(dev, "link training!!\n"); @@ -297,7 +297,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder) /* disable hotplug detect, this flips around on some panels during * link training. */ - pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); + hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); if (dpe->script0) { NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); @@ -439,7 +439,7 @@ stop: } /* re-enable hotplug detect */ - pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); + pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state); return eq_done; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index b19ef7fbb9dd..912c9f785222 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -376,13 +376,19 @@ struct nouveau_display_engine { }; struct nouveau_gpio_engine { + void *priv; + int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); int (*get)(struct drm_device *, enum dcb_gpio_tag); int (*set)(struct drm_device *, enum dcb_gpio_tag, int state); - void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); + int (*irq_register)(struct drm_device *, enum dcb_gpio_tag, + void (*)(void *, int), void *); + void (*irq_unregister)(struct drm_device *, enum dcb_gpio_tag, + void (*)(void *, int), void *); + bool (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); }; struct nouveau_pm_voltage_level { @@ -619,13 +625,6 @@ struct drm_nouveau_private { bool msi_enabled; struct workqueue_struct *wq; struct work_struct irq_work; - struct work_struct hpd_work; - - struct { - spinlock_t lock; - uint32_t hpd0_bits; - uint32_t hpd1_bits; - } hpd_state; struct list_head vbl_waiting; @@ -1366,7 +1365,11 @@ int nv50_gpio_init(struct drm_device *dev); void nv50_gpio_fini(struct drm_device *dev); int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); -void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); +int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag, + void (*)(void *, int), void *); +void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag, + void (*)(void *, int), void *); +bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); /* nv50_calc. */ int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 262545b58d96..b26b34c419cb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -396,6 +396,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.takedown = nv50_gpio_fini; engine->gpio.get = nv50_gpio_get; engine->gpio.set = nv50_gpio_set; + engine->gpio.irq_register = nv50_gpio_irq_register; + engine->gpio.irq_unregister = nv50_gpio_irq_unregister; engine->gpio.irq_enable = nv50_gpio_irq_enable; switch (dev_priv->chipset) { case 0x84: @@ -487,6 +489,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.takedown = nouveau_stub_takedown; engine->gpio.get = nv50_gpio_get; engine->gpio.set = nv50_gpio_set; + engine->gpio.irq_register = nv50_gpio_irq_register; + engine->gpio.irq_unregister = nv50_gpio_irq_unregister; engine->gpio.irq_enable = nv50_gpio_irq_enable; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index e5dbd171672c..7cc94ed9ed95 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -804,71 +804,6 @@ nv50_display_error_handler(struct drm_device *dev) } } -void -nv50_display_irq_hotplug_bh(struct work_struct *work) -{ - struct drm_nouveau_private *dev_priv = - container_of(work, struct drm_nouveau_private, hpd_work); - struct drm_device *dev = dev_priv->dev; - struct drm_connector *connector; - const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; - uint32_t unplug_mask, plug_mask, change_mask; - uint32_t hpd0, hpd1; - - spin_lock_irq(&dev_priv->hpd_state.lock); - hpd0 = dev_priv->hpd_state.hpd0_bits; - dev_priv->hpd_state.hpd0_bits = 0; - hpd1 = dev_priv->hpd_state.hpd1_bits; - dev_priv->hpd_state.hpd1_bits = 0; - spin_unlock_irq(&dev_priv->hpd_state.lock); - - hpd0 &= nv_rd32(dev, 0xe050); - if (dev_priv->chipset >= 0x90) - hpd1 &= nv_rd32(dev, 0xe070); - - plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); - unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); - change_mask = plug_mask | unplug_mask; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_encoder_helper_funcs *helper; - struct nouveau_connector *nv_connector = - nouveau_connector(connector); - struct nouveau_encoder *nv_encoder; - struct dcb_gpio_entry *gpio; - uint32_t reg; - bool plugged; - - if (!nv_connector->dcb) - continue; - - gpio = nouveau_bios_gpio_entry(dev, nv_connector->dcb->gpio_tag); - if (!gpio || !(change_mask & (1 << gpio->line))) - continue; - - reg = nv_rd32(dev, gpio_reg[gpio->line >> 3]); - plugged = !!(reg & (4 << ((gpio->line & 7) << 2))); - NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", - drm_get_connector_name(connector)) ; - - if (!connector->encoder || !connector->encoder->crtc || - !connector->encoder->crtc->enabled) - continue; - nv_encoder = nouveau_encoder(connector->encoder); - helper = connector->encoder->helper_private; - - if (nv_encoder->dcb->type != OUTPUT_DP) - continue; - - if (plugged) - helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); - else - helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); - } - - drm_helper_hpd_irq_event(dev); -} - static void nv50_display_isr(struct drm_device *dev) { @@ -918,4 +853,3 @@ nv50_display_isr(struct drm_device *dev) } } } - diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h index a269fccf3555..f0e30b78ef6b 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.h +++ b/drivers/gpu/drm/nouveau/nv50_display.h @@ -36,7 +36,6 @@ #include "nv50_evo.h" void nv50_display_irq_handler_bh(struct work_struct *work); -void nv50_display_irq_hotplug_bh(struct work_struct *work); int nv50_display_early_init(struct drm_device *dev); void nv50_display_late_takedown(struct drm_device *dev); int nv50_display_create(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index 87266d1b5def..6b149c0cc06d 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -29,6 +29,24 @@ #include "nv50_display.h" static void nv50_gpio_isr(struct drm_device *dev); +static void nv50_gpio_isr_bh(struct work_struct *work); + +struct nv50_gpio_priv { + struct list_head handlers; + spinlock_t lock; +}; + +struct nv50_gpio_handler { + struct drm_device *dev; + struct list_head head; + struct work_struct work; + bool inhibit; + + struct dcb_gpio_entry *gpio; + + void (*handler)(void *data, int state); + void *data; +}; static int nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift) @@ -79,29 +97,123 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) return 0; } +int +nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, + void (*handler)(void *, int), void *data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nv50_gpio_priv *priv = pgpio->priv; + struct nv50_gpio_handler *gpioh; + struct dcb_gpio_entry *gpio; + unsigned long flags; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) + return -ENOENT; + + gpioh = kzalloc(sizeof(*gpioh), GFP_KERNEL); + if (!gpioh) + return -ENOMEM; + + INIT_WORK(&gpioh->work, nv50_gpio_isr_bh); + gpioh->dev = dev; + gpioh->gpio = gpio; + gpioh->handler = handler; + gpioh->data = data; + + spin_lock_irqsave(&priv->lock, flags); + list_add(&gpioh->head, &priv->handlers); + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + void -nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) +nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, + void (*handler)(void *, int), void *data) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nv50_gpio_priv *priv = pgpio->priv; + struct nv50_gpio_handler *gpioh, *tmp; struct dcb_gpio_entry *gpio; - u32 reg, mask; + unsigned long flags; gpio = nouveau_bios_gpio_entry(dev, tag); - if (!gpio) { - NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag); + if (!gpio) return; + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry_safe(gpioh, tmp, &priv->handlers, head) { + if (gpioh->gpio != gpio || + gpioh->handler != handler || + gpioh->data != data) + continue; + list_del(&gpioh->head); + kfree(gpioh); } + spin_unlock_irqrestore(&priv->lock, flags); +} + +bool +nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) +{ + struct dcb_gpio_entry *gpio; + u32 reg, mask; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) + return false; reg = gpio->line < 16 ? 0xe050 : 0xe070; mask = 0x00010001 << (gpio->line & 0xf); nv_wr32(dev, reg + 4, mask); - nv_mask(dev, reg + 0, mask, on ? mask : 0); + reg = nv_mask(dev, reg + 0, mask, on ? mask : 0); + return (reg & mask) == mask; +} + +static int +nv50_gpio_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nv50_gpio_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + INIT_LIST_HEAD(&priv->handlers); + spin_lock_init(&priv->lock); + pgpio->priv = priv; + return 0; +} + +static void +nv50_gpio_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + + kfree(pgpio->priv); + pgpio->priv = NULL; } int nv50_gpio_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nv50_gpio_priv *priv; + int ret; + + if (!pgpio->priv) { + ret = nv50_gpio_create(dev); + if (ret) + return ret; + } + priv = pgpio->priv; /* disable, and ack any pending gpio interrupts */ nv_wr32(dev, 0xe050, 0x00000000); @@ -111,8 +223,6 @@ nv50_gpio_init(struct drm_device *dev) nv_wr32(dev, 0xe074, 0xffffffff); } - INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); - spin_lock_init(&dev_priv->hpd_state.lock); nouveau_irq_register(dev, 21, nv50_gpio_isr); return 0; } @@ -126,26 +236,64 @@ nv50_gpio_fini(struct drm_device *dev) if (dev_priv->chipset >= 0x90) nv_wr32(dev, 0xe070, 0x00000000); nouveau_irq_unregister(dev, 21); + + nv50_gpio_destroy(dev); +} + +static void +nv50_gpio_isr_bh(struct work_struct *work) +{ + struct nv50_gpio_handler *gpioh = + container_of(work, struct nv50_gpio_handler, work); + struct drm_nouveau_private *dev_priv = gpioh->dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nv50_gpio_priv *priv = pgpio->priv; + unsigned long flags; + int state; + + state = pgpio->get(gpioh->dev, gpioh->gpio->tag); + if (state < 0) + return; + + gpioh->handler(gpioh->data, state); + + spin_lock_irqsave(&priv->lock, flags); + gpioh->inhibit = false; + spin_unlock_irqrestore(&priv->lock, flags); } static void nv50_gpio_isr(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t hpd0_bits, hpd1_bits = 0; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; + struct nv50_gpio_priv *priv = pgpio->priv; + struct nv50_gpio_handler *gpioh; + u32 intr0, intr1 = 0; + u32 hi, lo, ch; - hpd0_bits = nv_rd32(dev, 0xe054); - nv_wr32(dev, 0xe054, hpd0_bits); + intr0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); + if (dev_priv->chipset >= 0x90) + intr1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); - if (dev_priv->chipset >= 0x90) { - hpd1_bits = nv_rd32(dev, 0xe074); - nv_wr32(dev, 0xe074, hpd1_bits); - } + hi = (intr0 & 0x0000ffff) | (intr1 << 16); + lo = (intr0 >> 16) | (intr1 & 0xffff0000); + ch = hi | lo; - spin_lock(&dev_priv->hpd_state.lock); - dev_priv->hpd_state.hpd0_bits |= hpd0_bits; - dev_priv->hpd_state.hpd1_bits |= hpd1_bits; - spin_unlock(&dev_priv->hpd_state.lock); + nv_wr32(dev, 0xe054, intr0); + if (dev_priv->chipset >= 0x90) + nv_wr32(dev, 0xe074, intr1); + + spin_lock(&priv->lock); + list_for_each_entry(gpioh, &priv->handlers, head) { + if (!(ch & (1 << gpioh->gpio->line))) + continue; - queue_work(dev_priv->wq, &dev_priv->hpd_work); + if (gpioh->inhibit) + continue; + gpioh->inhibit = true; + + queue_work(dev_priv->wq, &gpioh->work); + } + spin_unlock(&priv->lock); } -- cgit v1.2.3 From dc1e5c0dbff27c2b5147eaea16c578d2337870c3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 25 Oct 2010 15:23:59 +1000 Subject: drm/nouveau: simplify gpuobj suspend/resume Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.c | 14 ++++---- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +- drivers/gpu/drm/nouveau/nouveau_object.c | 56 ++++++-------------------------- drivers/gpu/drm/nouveau/nv50_instmem.c | 21 ++---------- 4 files changed, 21 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 52f9307d7396..7ff5b4369f03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -222,17 +222,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) pfifo->unload_context(dev); pgraph->unload_context(dev); - NV_INFO(dev, "Suspending GPU objects...\n"); - ret = nouveau_gpuobj_suspend(dev); + ret = pinstmem->suspend(dev); if (ret) { NV_ERROR(dev, "... failed: %d\n", ret); goto out_abort; } - ret = pinstmem->suspend(dev); + NV_INFO(dev, "Suspending GPU objects...\n"); + ret = nouveau_gpuobj_suspend(dev); if (ret) { NV_ERROR(dev, "... failed: %d\n", ret); - nouveau_gpuobj_suspend_cleanup(dev); + pinstmem->resume(dev); goto out_abort; } @@ -297,6 +297,9 @@ nouveau_pci_resume(struct pci_dev *pdev) } } + NV_INFO(dev, "Restoring GPU objects...\n"); + nouveau_gpuobj_resume(dev); + NV_INFO(dev, "Reinitialising engines...\n"); engine->instmem.resume(dev); engine->mc.init(dev); @@ -306,9 +309,6 @@ nouveau_pci_resume(struct pci_dev *pdev) engine->crypt.init(dev); engine->fifo.init(dev); - NV_INFO(dev, "Restoring GPU objects...\n"); - nouveau_gpuobj_resume(dev); - nouveau_irq_postinstall(dev); /* Re-write SKIPS, they'll have been lost over the suspend */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 912c9f785222..18a611e1ab80 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -153,7 +153,7 @@ struct nouveau_gpuobj { struct drm_mm_node *im_pramin; struct nouveau_bo *im_backing; - uint32_t *im_backing_suspend; + u32 *suspend; int im_bound; uint32_t flags; @@ -865,7 +865,6 @@ extern int nouveau_gpuobj_early_init(struct drm_device *); extern int nouveau_gpuobj_init(struct drm_device *); extern void nouveau_gpuobj_takedown(struct drm_device *); extern int nouveau_gpuobj_suspend(struct drm_device *dev); -extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev); extern void nouveau_gpuobj_resume(struct drm_device *dev); extern int nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng); extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd, diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 94429553433c..8c5e35cc04df 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -934,54 +934,23 @@ nouveau_gpuobj_suspend(struct drm_device *dev) struct nouveau_gpuobj *gpuobj; int i; - if (dev_priv->card_type < NV_50) { - dev_priv->susres.ramin_copy = vmalloc(dev_priv->ramin_rsvd_vram); - if (!dev_priv->susres.ramin_copy) - return -ENOMEM; - - for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4) - dev_priv->susres.ramin_copy[i/4] = nv_ri32(dev, i); - return 0; - } - list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { - if (!gpuobj->im_backing) + if (gpuobj->cinst != 0xdeadbeef) continue; - gpuobj->im_backing_suspend = vmalloc(gpuobj->size); - if (!gpuobj->im_backing_suspend) { + gpuobj->suspend = vmalloc(gpuobj->size); + if (!gpuobj->suspend) { nouveau_gpuobj_resume(dev); return -ENOMEM; } for (i = 0; i < gpuobj->size; i += 4) - gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i); + gpuobj->suspend[i/4] = nv_ro32(gpuobj, i); } return 0; } -void -nouveau_gpuobj_suspend_cleanup(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *gpuobj; - - if (dev_priv->card_type < NV_50) { - vfree(dev_priv->susres.ramin_copy); - dev_priv->susres.ramin_copy = NULL; - return; - } - - list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { - if (!gpuobj->im_backing_suspend) - continue; - - vfree(gpuobj->im_backing_suspend); - gpuobj->im_backing_suspend = NULL; - } -} - void nouveau_gpuobj_resume(struct drm_device *dev) { @@ -989,23 +958,18 @@ nouveau_gpuobj_resume(struct drm_device *dev) struct nouveau_gpuobj *gpuobj; int i; - if (dev_priv->card_type < NV_50) { - for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4) - nv_wi32(dev, i, dev_priv->susres.ramin_copy[i/4]); - nouveau_gpuobj_suspend_cleanup(dev); - return; - } - list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { - if (!gpuobj->im_backing_suspend) + if (!gpuobj->suspend) continue; for (i = 0; i < gpuobj->size; i += 4) - nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]); - dev_priv->engine.instmem.flush(dev); + nv_wo32(gpuobj, i, gpuobj->suspend[i/4]); + + vfree(gpuobj->suspend); + gpuobj->suspend = NULL; } - nouveau_gpuobj_suspend_cleanup(dev); + dev_priv->engine.instmem.flush(dev); } int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 2c98eb176d64..1640c12d8b3a 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -276,16 +276,8 @@ int nv50_instmem_suspend(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->channels.ptr[0]; - struct nouveau_gpuobj *ramin = chan->ramin; - int i; - ramin->im_backing_suspend = vmalloc(ramin->size); - if (!ramin->im_backing_suspend) - return -ENOMEM; - - for (i = 0; i < ramin->size; i += 4) - ramin->im_backing_suspend[i/4] = nv_ri32(dev, i); + dev_priv->ramin_available = false; return 0; } @@ -295,17 +287,8 @@ nv50_instmem_resume(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; struct nouveau_channel *chan = dev_priv->channels.ptr[0]; - struct nouveau_gpuobj *ramin = chan->ramin; int i; - dev_priv->ramin_available = false; - dev_priv->ramin_base = ~0; - for (i = 0; i < ramin->size; i += 4) - nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]); - dev_priv->ramin_available = true; - vfree(ramin->im_backing_suspend); - ramin->im_backing_suspend = NULL; - /* Poke the relevant regs, and pray it works :) */ nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12)); nv_wr32(dev, NV50_PUNK_UNK1710, 0); @@ -318,6 +301,8 @@ nv50_instmem_resume(struct drm_device *dev) for (i = 0; i < 8; i++) nv_wr32(dev, 0x1900 + (i*4), 0); + + dev_priv->ramin_available = true; } int -- cgit v1.2.3 From e41115d0ad5c40a7ea4d85b1c77b4c02185a5581 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 1 Nov 2010 11:45:02 +1000 Subject: drm/nouveau: rework gpu-specific instmem interfaces Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 44 +++++------ drivers/gpu/drm/nouveau/nouveau_object.c | 112 +++++++++----------------- drivers/gpu/drm/nouveau/nouveau_state.c | 56 ++++++------- drivers/gpu/drm/nouveau/nv04_instmem.c | 50 ++++++++---- drivers/gpu/drm/nouveau/nv50_instmem.c | 130 +++++++++++++++++-------------- drivers/gpu/drm/nouveau/nvc0_instmem.c | 121 +++++++++++++++++----------- 6 files changed, 270 insertions(+), 243 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 18a611e1ab80..822cd40b3eb4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -146,15 +146,16 @@ enum nouveau_flags { #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) #define NVOBJ_FLAG_ZERO_FREE (1 << 2) + +#define NVOBJ_CINST_GLOBAL 0xdeadbeef + struct nouveau_gpuobj { struct drm_device *dev; struct kref refcount; struct list_head list; - struct drm_mm_node *im_pramin; - struct nouveau_bo *im_backing; + void *node; u32 *suspend; - int im_bound; uint32_t flags; @@ -288,11 +289,11 @@ struct nouveau_instmem_engine { int (*suspend)(struct drm_device *dev); void (*resume)(struct drm_device *dev); - int (*populate)(struct drm_device *, struct nouveau_gpuobj *, - u32 *size, u32 align); - void (*clear)(struct drm_device *, struct nouveau_gpuobj *); - int (*bind)(struct drm_device *, struct nouveau_gpuobj *); - int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); + int (*get)(struct nouveau_gpuobj *, u32 size, u32 align); + void (*put)(struct nouveau_gpuobj *); + int (*map)(struct nouveau_gpuobj *); + void (*unmap)(struct nouveau_gpuobj *); + void (*flush)(struct drm_device *); }; @@ -1182,11 +1183,10 @@ extern int nv04_instmem_init(struct drm_device *); extern void nv04_instmem_takedown(struct drm_device *); extern int nv04_instmem_suspend(struct drm_device *); extern void nv04_instmem_resume(struct drm_device *); -extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, - u32 *size, u32 align); -extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); -extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); -extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); +extern int nv04_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); +extern void nv04_instmem_put(struct nouveau_gpuobj *); +extern int nv04_instmem_map(struct nouveau_gpuobj *); +extern void nv04_instmem_unmap(struct nouveau_gpuobj *); extern void nv04_instmem_flush(struct drm_device *); /* nv50_instmem.c */ @@ -1194,11 +1194,10 @@ extern int nv50_instmem_init(struct drm_device *); extern void nv50_instmem_takedown(struct drm_device *); extern int nv50_instmem_suspend(struct drm_device *); extern void nv50_instmem_resume(struct drm_device *); -extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, - u32 *size, u32 align); -extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); -extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); -extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); +extern int nv50_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); +extern void nv50_instmem_put(struct nouveau_gpuobj *); +extern int nv50_instmem_map(struct nouveau_gpuobj *); +extern void nv50_instmem_unmap(struct nouveau_gpuobj *); extern void nv50_instmem_flush(struct drm_device *); extern void nv84_instmem_flush(struct drm_device *); extern void nv50_vm_flush(struct drm_device *, int engine); @@ -1208,11 +1207,10 @@ extern int nvc0_instmem_init(struct drm_device *); extern void nvc0_instmem_takedown(struct drm_device *); extern int nvc0_instmem_suspend(struct drm_device *); extern void nvc0_instmem_resume(struct drm_device *); -extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, - u32 *size, u32 align); -extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); -extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); -extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); +extern int nvc0_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); +extern void nvc0_instmem_put(struct nouveau_gpuobj *); +extern int nvc0_instmem_map(struct nouveau_gpuobj *); +extern void nvc0_instmem_unmap(struct nouveau_gpuobj *); extern void nvc0_instmem_flush(struct drm_device *); /* nv04_mc.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 8c5e35cc04df..e8c74de905ec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -168,17 +168,14 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, struct nouveau_gpuobj **gpuobj_ret) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; + struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; struct nouveau_gpuobj *gpuobj; struct drm_mm_node *ramin = NULL; - int ret; + int ret, i; NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", chan ? chan->id : -1, size, align, flags); - if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL) - return -EINVAL; - gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); if (!gpuobj) return -ENOMEM; @@ -193,88 +190,45 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, spin_unlock(&dev_priv->ramin_lock); if (chan) { - NV_DEBUG(dev, "channel heap\n"); - ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0); if (ramin) ramin = drm_mm_get_block(ramin, size, align); - if (!ramin) { nouveau_gpuobj_ref(NULL, &gpuobj); return -ENOMEM; } - } else { - NV_DEBUG(dev, "global heap\n"); - - /* allocate backing pages, sets vinst */ - ret = engine->instmem.populate(dev, gpuobj, &size, align); - if (ret) { - nouveau_gpuobj_ref(NULL, &gpuobj); - return ret; - } - /* try and get aperture space */ - do { - if (drm_mm_pre_get(&dev_priv->ramin_heap)) - return -ENOMEM; - - spin_lock(&dev_priv->ramin_lock); - ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, - align, 0); - if (ramin == NULL) { - spin_unlock(&dev_priv->ramin_lock); - nouveau_gpuobj_ref(NULL, &gpuobj); - return -ENOMEM; - } - - ramin = drm_mm_get_block_atomic(ramin, size, align); - spin_unlock(&dev_priv->ramin_lock); - } while (ramin == NULL); + gpuobj->pinst = chan->ramin->pinst; + if (gpuobj->pinst != ~0) + gpuobj->pinst += ramin->start; - /* on nv50 it's ok to fail, we have a fallback path */ - if (!ramin && dev_priv->card_type < NV_50) { - nouveau_gpuobj_ref(NULL, &gpuobj); - return -ENOMEM; - } - } + if (dev_priv->card_type < NV_50) + gpuobj->cinst = gpuobj->pinst; + else + gpuobj->cinst = ramin->start; - /* if we got a chunk of the aperture, map pages into it */ - gpuobj->im_pramin = ramin; - if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) { - ret = engine->instmem.bind(dev, gpuobj); + gpuobj->vinst = ramin->start + chan->ramin->vinst; + gpuobj->node = ramin; + } else { + ret = instmem->get(gpuobj, size, align); if (ret) { nouveau_gpuobj_ref(NULL, &gpuobj); return ret; } - } - - /* calculate the various different addresses for the object */ - if (chan) { - gpuobj->pinst = chan->ramin->pinst; - if (gpuobj->pinst != ~0) - gpuobj->pinst += gpuobj->im_pramin->start; - if (dev_priv->card_type < NV_50) { - gpuobj->cinst = gpuobj->pinst; - } else { - gpuobj->cinst = gpuobj->im_pramin->start; - gpuobj->vinst = gpuobj->im_pramin->start + - chan->ramin->vinst; - } - } else { - if (gpuobj->im_pramin) - gpuobj->pinst = gpuobj->im_pramin->start; - else + ret = -ENOSYS; + if (dev_priv->ramin_available) + ret = instmem->map(gpuobj); + if (ret) gpuobj->pinst = ~0; - gpuobj->cinst = 0xdeadbeef; + + gpuobj->cinst = NVOBJ_CINST_GLOBAL; } if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { - int i; - for (i = 0; i < gpuobj->size; i += 4) nv_wo32(gpuobj, i, 0); - engine->instmem.flush(dev); + instmem->flush(dev); } @@ -326,26 +280,34 @@ nouveau_gpuobj_del(struct kref *ref) container_of(ref, struct nouveau_gpuobj, refcount); struct drm_device *dev = gpuobj->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; + struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; int i; NV_DEBUG(dev, "gpuobj %p\n", gpuobj); - if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { + if (gpuobj->node && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { for (i = 0; i < gpuobj->size; i += 4) nv_wo32(gpuobj, i, 0); - engine->instmem.flush(dev); + instmem->flush(dev); } if (gpuobj->dtor) gpuobj->dtor(dev, gpuobj); - if (gpuobj->im_backing) - engine->instmem.clear(dev, gpuobj); + if (gpuobj->cinst == NVOBJ_CINST_GLOBAL) { + if (gpuobj->node) { + instmem->unmap(gpuobj); + instmem->put(gpuobj); + } + } else { + if (gpuobj->node) { + spin_lock(&dev_priv->ramin_lock); + drm_mm_put_block(gpuobj->node); + spin_unlock(&dev_priv->ramin_lock); + } + } spin_lock(&dev_priv->ramin_lock); - if (gpuobj->im_pramin) - drm_mm_put_block(gpuobj->im_pramin); list_del(&gpuobj->list); spin_unlock(&dev_priv->ramin_lock); @@ -385,7 +347,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst, kref_init(&gpuobj->refcount); gpuobj->size = size; gpuobj->pinst = pinst; - gpuobj->cinst = 0xdeadbeef; + gpuobj->cinst = NVOBJ_CINST_GLOBAL; gpuobj->vinst = vinst; if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { @@ -935,7 +897,7 @@ nouveau_gpuobj_suspend(struct drm_device *dev) int i; list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { - if (gpuobj->cinst != 0xdeadbeef) + if (gpuobj->cinst != NVOBJ_CINST_GLOBAL) continue; gpuobj->suspend = vmalloc(gpuobj->size); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index b26b34c419cb..b42e29d1935e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -53,10 +53,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nv04_instmem_takedown; engine->instmem.suspend = nv04_instmem_suspend; engine->instmem.resume = nv04_instmem_resume; - engine->instmem.populate = nv04_instmem_populate; - engine->instmem.clear = nv04_instmem_clear; - engine->instmem.bind = nv04_instmem_bind; - engine->instmem.unbind = nv04_instmem_unbind; + engine->instmem.get = nv04_instmem_get; + engine->instmem.put = nv04_instmem_put; + engine->instmem.map = nv04_instmem_map; + engine->instmem.unmap = nv04_instmem_unmap; engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; @@ -106,10 +106,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nv04_instmem_takedown; engine->instmem.suspend = nv04_instmem_suspend; engine->instmem.resume = nv04_instmem_resume; - engine->instmem.populate = nv04_instmem_populate; - engine->instmem.clear = nv04_instmem_clear; - engine->instmem.bind = nv04_instmem_bind; - engine->instmem.unbind = nv04_instmem_unbind; + engine->instmem.get = nv04_instmem_get; + engine->instmem.put = nv04_instmem_put; + engine->instmem.map = nv04_instmem_map; + engine->instmem.unmap = nv04_instmem_unmap; engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; @@ -163,10 +163,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nv04_instmem_takedown; engine->instmem.suspend = nv04_instmem_suspend; engine->instmem.resume = nv04_instmem_resume; - engine->instmem.populate = nv04_instmem_populate; - engine->instmem.clear = nv04_instmem_clear; - engine->instmem.bind = nv04_instmem_bind; - engine->instmem.unbind = nv04_instmem_unbind; + engine->instmem.get = nv04_instmem_get; + engine->instmem.put = nv04_instmem_put; + engine->instmem.map = nv04_instmem_map; + engine->instmem.unmap = nv04_instmem_unmap; engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; @@ -220,10 +220,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nv04_instmem_takedown; engine->instmem.suspend = nv04_instmem_suspend; engine->instmem.resume = nv04_instmem_resume; - engine->instmem.populate = nv04_instmem_populate; - engine->instmem.clear = nv04_instmem_clear; - engine->instmem.bind = nv04_instmem_bind; - engine->instmem.unbind = nv04_instmem_unbind; + engine->instmem.get = nv04_instmem_get; + engine->instmem.put = nv04_instmem_put; + engine->instmem.map = nv04_instmem_map; + engine->instmem.unmap = nv04_instmem_unmap; engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; @@ -280,10 +280,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nv04_instmem_takedown; engine->instmem.suspend = nv04_instmem_suspend; engine->instmem.resume = nv04_instmem_resume; - engine->instmem.populate = nv04_instmem_populate; - engine->instmem.clear = nv04_instmem_clear; - engine->instmem.bind = nv04_instmem_bind; - engine->instmem.unbind = nv04_instmem_unbind; + engine->instmem.get = nv04_instmem_get; + engine->instmem.put = nv04_instmem_put; + engine->instmem.map = nv04_instmem_map; + engine->instmem.unmap = nv04_instmem_unmap; engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv40_mc_init; engine->mc.takedown = nv40_mc_takedown; @@ -343,10 +343,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nv50_instmem_takedown; engine->instmem.suspend = nv50_instmem_suspend; engine->instmem.resume = nv50_instmem_resume; - engine->instmem.populate = nv50_instmem_populate; - engine->instmem.clear = nv50_instmem_clear; - engine->instmem.bind = nv50_instmem_bind; - engine->instmem.unbind = nv50_instmem_unbind; + engine->instmem.get = nv50_instmem_get; + engine->instmem.put = nv50_instmem_put; + engine->instmem.map = nv50_instmem_map; + engine->instmem.unmap = nv50_instmem_unmap; if (dev_priv->chipset == 0x50) engine->instmem.flush = nv50_instmem_flush; else @@ -449,10 +449,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nvc0_instmem_takedown; engine->instmem.suspend = nvc0_instmem_suspend; engine->instmem.resume = nvc0_instmem_resume; - engine->instmem.populate = nvc0_instmem_populate; - engine->instmem.clear = nvc0_instmem_clear; - engine->instmem.bind = nvc0_instmem_bind; - engine->instmem.unbind = nvc0_instmem_unbind; + engine->instmem.get = nvc0_instmem_get; + engine->instmem.put = nvc0_instmem_put; + engine->instmem.map = nvc0_instmem_map; + engine->instmem.unmap = nvc0_instmem_unmap; engine->instmem.flush = nvc0_instmem_flush; engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c index 554e55d0ec48..b8e3edb5c063 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c @@ -98,42 +98,66 @@ nv04_instmem_takedown(struct drm_device *dev) } int -nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, - u32 *size, u32 align) +nv04_instmem_suspend(struct drm_device *dev) { return 0; } void -nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -{ -} - -int -nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +nv04_instmem_resume(struct drm_device *dev) { - return 0; } int -nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +nv04_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) { + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + struct drm_mm_node *ramin = NULL; + + do { + if (drm_mm_pre_get(&dev_priv->ramin_heap)) + return -ENOMEM; + + spin_lock(&dev_priv->ramin_lock); + ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0); + if (ramin == NULL) { + spin_unlock(&dev_priv->ramin_lock); + return -ENOMEM; + } + + ramin = drm_mm_get_block_atomic(ramin, size, align); + spin_unlock(&dev_priv->ramin_lock); + } while (ramin == NULL); + + gpuobj->node = ramin; + gpuobj->vinst = ramin->start; return 0; } void -nv04_instmem_flush(struct drm_device *dev) +nv04_instmem_put(struct nouveau_gpuobj *gpuobj) { + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + + spin_lock(&dev_priv->ramin_lock); + drm_mm_put_block(gpuobj->node); + gpuobj->node = NULL; + spin_unlock(&dev_priv->ramin_lock); } int -nv04_instmem_suspend(struct drm_device *dev) +nv04_instmem_map(struct nouveau_gpuobj *gpuobj) { + gpuobj->pinst = gpuobj->vinst; return 0; } void -nv04_instmem_resume(struct drm_device *dev) +nv04_instmem_unmap(struct nouveau_gpuobj *gpuobj) { } +void +nv04_instmem_flush(struct drm_device *dev) +{ +} diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 1640c12d8b3a..87160952a30b 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -157,10 +157,7 @@ nv50_instmem_init(struct drm_device *dev) nv_wo32(priv->pramin_bar, 0x10, 0x00000000); nv_wo32(priv->pramin_bar, 0x14, 0x00000000); - /* map channel into PRAMIN, gpuobj didn't do it for us */ - ret = nv50_instmem_bind(dev, chan->ramin); - if (ret) - return ret; + nv50_instmem_map(chan->ramin); /* poke regs... */ nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); @@ -305,72 +302,91 @@ nv50_instmem_resume(struct drm_device *dev) dev_priv->ramin_available = true; } +struct nv50_gpuobj_node { + struct nouveau_bo *vram; + struct drm_mm_node *ramin; + u32 align; +}; + + int -nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, - u32 *size, u32 align) +nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) { + struct drm_device *dev = gpuobj->dev; + struct nv50_gpuobj_node *node = NULL; int ret; - if (gpuobj->im_backing) - return -EINVAL; - - *size = ALIGN(*size, 4096); - if (*size == 0) - return -EINVAL; + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + node->align = align; - ret = nouveau_bo_new(dev, NULL, *size, align, TTM_PL_FLAG_VRAM, - 0, 0x0000, true, false, &gpuobj->im_backing); + ret = nouveau_bo_new(dev, NULL, size, align, TTM_PL_FLAG_VRAM, + 0, 0x0000, true, false, &node->vram); if (ret) { NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); return ret; } - ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(node->vram, TTM_PL_FLAG_VRAM); if (ret) { NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); - nouveau_bo_ref(NULL, &gpuobj->im_backing); + nouveau_bo_ref(NULL, &node->vram); return ret; } - gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; + gpuobj->vinst = node->vram->bo.mem.start << PAGE_SHIFT; + gpuobj->size = node->vram->bo.mem.num_pages << PAGE_SHIFT; + gpuobj->node = node; return 0; } void -nv50_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +nv50_instmem_put(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_gpuobj_node *node; - if (gpuobj && gpuobj->im_backing) { - if (gpuobj->im_bound) - dev_priv->engine.instmem.unbind(dev, gpuobj); - nouveau_bo_unpin(gpuobj->im_backing); - nouveau_bo_ref(NULL, &gpuobj->im_backing); - gpuobj->im_backing = NULL; - } + node = gpuobj->node; + gpuobj->node = NULL; + + nouveau_bo_unpin(node->vram); + nouveau_bo_ref(NULL, &node->vram); + kfree(node); } int -nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +nv50_instmem_map(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; - struct nouveau_gpuobj *pramin_pt = priv->pramin_pt; - uint32_t pte, pte_end; - uint64_t vram; - - if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) - return -EINVAL; + struct nv50_gpuobj_node *node = gpuobj->node; + struct drm_device *dev = gpuobj->dev; + struct drm_mm_node *ramin = NULL; + u32 pte, pte_end; + u64 vram; + + do { + if (drm_mm_pre_get(&dev_priv->ramin_heap)) + return -ENOMEM; + + spin_lock(&dev_priv->ramin_lock); + ramin = drm_mm_search_free(&dev_priv->ramin_heap, gpuobj->size, + node->align, 0); + if (ramin == NULL) { + spin_unlock(&dev_priv->ramin_lock); + return -ENOMEM; + } - NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", - gpuobj->im_pramin->start, gpuobj->im_pramin->size); + ramin = drm_mm_get_block_atomic(ramin, gpuobj->size, node->align); + spin_unlock(&dev_priv->ramin_lock); + } while (ramin == NULL); - pte = (gpuobj->im_pramin->start >> 12) << 1; - pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; + pte = (ramin->start >> 12) << 1; + pte_end = ((ramin->size >> 12) << 1) + pte; vram = gpuobj->vinst; NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", - gpuobj->im_pramin->start, pte, pte_end); + ramin->start, pte, pte_end); NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); vram |= 1; @@ -380,8 +396,8 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) } while (pte < pte_end) { - nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); - nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); + nv_wo32(priv->pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); + nv_wo32(priv->pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); vram += 0x1000; pte += 2; } @@ -389,36 +405,36 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) nv50_vm_flush(dev, 6); - gpuobj->im_bound = 1; + node->ramin = ramin; + gpuobj->pinst = ramin->start; return 0; } -int -nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +void +nv50_instmem_unmap(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; - uint32_t pte, pte_end; - - if (gpuobj->im_bound == 0) - return -EINVAL; + struct nv50_gpuobj_node *node = gpuobj->node; + u32 pte, pte_end; - /* can happen during late takedown */ - if (unlikely(!dev_priv->ramin_available)) - return 0; + if (!node->ramin || !dev_priv->ramin_available) + return; - pte = (gpuobj->im_pramin->start >> 12) << 1; - pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; + pte = (node->ramin->start >> 12) << 1; + pte_end = ((node->ramin->size >> 12) << 1) + pte; while (pte < pte_end) { nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000); nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000); pte += 2; } - dev_priv->engine.instmem.flush(dev); + dev_priv->engine.instmem.flush(gpuobj->dev); - gpuobj->im_bound = 0; - return 0; + spin_lock(&dev_priv->ramin_lock); + drm_mm_put_block(node->ramin); + node->ramin = NULL; + spin_unlock(&dev_priv->ramin_lock); } void diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 7b4e71f5c274..39232085193d 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -26,67 +26,89 @@ #include "nouveau_drv.h" +struct nvc0_gpuobj_node { + struct nouveau_bo *vram; + struct drm_mm_node *ramin; + u32 align; +}; + int -nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, - u32 *size, u32 align) +nvc0_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) { + struct drm_device *dev = gpuobj->dev; + struct nvc0_gpuobj_node *node = NULL; int ret; - *size = ALIGN(*size, 4096); - if (*size == 0) - return -EINVAL; + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + node->align = align; - ret = nouveau_bo_new(dev, NULL, *size, align, TTM_PL_FLAG_VRAM, - 0, 0x0000, true, false, &gpuobj->im_backing); + ret = nouveau_bo_new(dev, NULL, size, align, TTM_PL_FLAG_VRAM, + 0, 0x0000, true, false, &node->vram); if (ret) { NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); return ret; } - ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(node->vram, TTM_PL_FLAG_VRAM); if (ret) { NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); - nouveau_bo_ref(NULL, &gpuobj->im_backing); + nouveau_bo_ref(NULL, &node->vram); return ret; } - gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; + gpuobj->vinst = node->vram->bo.mem.start << PAGE_SHIFT; + gpuobj->size = node->vram->bo.mem.num_pages << PAGE_SHIFT; + gpuobj->node = node; return 0; } void -nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +nvc0_instmem_put(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_gpuobj_node *node; - if (gpuobj && gpuobj->im_backing) { - if (gpuobj->im_bound) - dev_priv->engine.instmem.unbind(dev, gpuobj); - nouveau_bo_unpin(gpuobj->im_backing); - nouveau_bo_ref(NULL, &gpuobj->im_backing); - gpuobj->im_backing = NULL; - } + node = gpuobj->node; + gpuobj->node = NULL; + + nouveau_bo_unpin(node->vram); + nouveau_bo_ref(NULL, &node->vram); + kfree(node); } int -nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +nvc0_instmem_map(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t pte, pte_end; - uint64_t vram; - - if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) - return -EINVAL; - - NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", - gpuobj->im_pramin->start, gpuobj->im_pramin->size); - - pte = gpuobj->im_pramin->start >> 12; - pte_end = (gpuobj->im_pramin->size >> 12) + pte; + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + struct nvc0_gpuobj_node *node = gpuobj->node; + struct drm_device *dev = gpuobj->dev; + struct drm_mm_node *ramin = NULL; + u32 pte, pte_end; + u64 vram; + + do { + if (drm_mm_pre_get(&dev_priv->ramin_heap)) + return -ENOMEM; + + spin_lock(&dev_priv->ramin_lock); + ramin = drm_mm_search_free(&dev_priv->ramin_heap, gpuobj->size, + node->align, 0); + if (ramin == NULL) { + spin_unlock(&dev_priv->ramin_lock); + return -ENOMEM; + } + + ramin = drm_mm_get_block_atomic(ramin, gpuobj->size, node->align); + spin_unlock(&dev_priv->ramin_lock); + } while (ramin == NULL); + + pte = (ramin->start >> 12) << 1; + pte_end = ((ramin->size >> 12) << 1) + pte; vram = gpuobj->vinst; NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", - gpuobj->im_pramin->start, pte, pte_end); + ramin->start, pte, pte_end); NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); while (pte < pte_end) { @@ -103,30 +125,35 @@ nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) nv_wr32(dev, 0x100cbc, 0x80000005); } - gpuobj->im_bound = 1; + node->ramin = ramin; + gpuobj->pinst = ramin->start; return 0; } -int -nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) +void +nvc0_instmem_unmap(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t pte, pte_end; + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + struct nvc0_gpuobj_node *node = gpuobj->node; + u32 pte, pte_end; - if (gpuobj->im_bound == 0) - return -EINVAL; + if (!node->ramin || !dev_priv->ramin_available) + return; + + pte = (node->ramin->start >> 12) << 1; + pte_end = ((node->ramin->size >> 12) << 1) + pte; - pte = gpuobj->im_pramin->start >> 12; - pte_end = (gpuobj->im_pramin->size >> 12) + pte; while (pte < pte_end) { - nv_wr32(dev, 0x702000 + (pte * 8), 0); - nv_wr32(dev, 0x702004 + (pte * 8), 0); + nv_wr32(gpuobj->dev, 0x702000 + (pte * 8), 0); + nv_wr32(gpuobj->dev, 0x702004 + (pte * 8), 0); pte++; } - dev_priv->engine.instmem.flush(dev); + dev_priv->engine.instmem.flush(gpuobj->dev); - gpuobj->im_bound = 0; - return 0; + spin_lock(&dev_priv->ramin_lock); + drm_mm_put_block(node->ramin); + node->ramin = NULL; + spin_unlock(&dev_priv->ramin_lock); } void -- cgit v1.2.3 From 20f63afe988a25b0a4d991e87b41f76ee14e2a84 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 12:50:50 +1000 Subject: drm/nv50: allocate page for unknown PFB object in nv50_fb.c Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nv50_fb.c | 56 ++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 822cd40b3eb4..e1619c674380 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -311,6 +311,7 @@ struct nouveau_timer_engine { struct nouveau_fb_engine { int num_tiles; struct drm_mm tag_heap; + void *priv; int (*init)(struct drm_device *dev); void (*takedown)(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index d745c952986a..aa6d78366078 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -3,16 +3,58 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" +struct nv50_fb_priv { + struct page *r100c08_page; + dma_addr_t r100c08; +}; + +static int +nv50_fb_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_fb_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!priv->r100c08_page) { + kfree(priv); + return -ENOMEM; + } + + priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) { + __free_page(priv->r100c08_page); + kfree(priv); + return -EFAULT; + } + + dev_priv->engine.fb.priv = priv; + return 0; +} + int nv50_fb_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_fb_priv *priv; + int ret; + + if (!dev_priv->engine.fb.priv) { + ret = nv50_fb_create(dev); + if (ret) + return ret; + } + priv = dev_priv->engine.fb.priv; /* Not a clue what this is exactly. Without pointing it at a * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) * cause IOMMU "read from address 0" errors (rh#561267) */ - nv_wr32(dev, 0x100c08, dev_priv->gart_info.sg_dummy_bus >> 8); + nv_wr32(dev, 0x100c08, priv->r100c08 >> 8); /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ @@ -36,6 +78,18 @@ nv50_fb_init(struct drm_device *dev) void nv50_fb_takedown(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_fb_priv *priv; + + priv = dev_priv->engine.fb.priv; + if (!priv) + return; + dev_priv->engine.fb.priv = NULL; + + pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(priv->r100c08_page); + kfree(priv); } void -- cgit v1.2.3 From 9fea1bcbff037cb61f71e0d699180030b1f509a5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 12:52:23 +1000 Subject: drm/nv50: fix 0x100c90 init for NVAF Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index aa6d78366078..50290dea0ac4 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -60,15 +60,18 @@ nv50_fb_init(struct drm_device *dev) * on traps. No idea what these values mean exactly. */ switch (dev_priv->chipset) { case 0x50: - nv_wr32(dev, 0x100c90, 0x0707ff); + nv_wr32(dev, 0x100c90, 0x000707ff); break; case 0xa3: case 0xa5: case 0xa8: - nv_wr32(dev, 0x100c90, 0x0d0fff); + nv_wr32(dev, 0x100c90, 0x000d0fff); + break; + case 0xaf: + nv_wr32(dev, 0x100c90, 0x089d1fff); break; default: - nv_wr32(dev, 0x100c90, 0x1d07ff); + nv_wr32(dev, 0x100c90, 0x001d07ff); break; } -- cgit v1.2.3 From 7b4808bb6ee63c9cc9c9be5a52f0c7babfc50659 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 12:54:57 +1000 Subject: drm/nouveau: remove dummy page use from PCI(E)GART, use PTE present instead Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 -- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 38 +++------------------------------ 2 files changed, 3 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e1619c674380..d76d2c09049d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -672,8 +672,6 @@ struct drm_nouveau_private { uint64_t aper_free; struct nouveau_gpuobj *sg_ctxdma; - struct page *sg_dummy_page; - dma_addr_t sg_dummy_bus; } gart_info; /* nv10-nv40 tiling regions */ diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index d4ac97007038..54af7608d45c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -144,19 +144,15 @@ nouveau_sgdma_unbind(struct ttm_backend *be) pte = nvbe->pte_start; for (i = 0; i < nvbe->nr_pages; i++) { - dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus; - for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { if (dev_priv->card_type < NV_50) { - nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3); + nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); pte += 1; } else { nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000); pte += 2; } - - dma_offset += NV_CTXDMA_PAGE_SIZE; } } dev_priv->engine.instmem.flush(nvbe->dev); @@ -218,7 +214,6 @@ int nouveau_sgdma_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct pci_dev *pdev = dev->pdev; struct nouveau_gpuobj *gpuobj = NULL; uint32_t aper_size, obj_size; int i, ret; @@ -245,22 +240,6 @@ nouveau_sgdma_init(struct drm_device *dev) return ret; } - dev_priv->gart_info.sg_dummy_page = - alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO); - if (!dev_priv->gart_info.sg_dummy_page) { - nouveau_gpuobj_ref(NULL, &gpuobj); - return -ENOMEM; - } - - set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags); - dev_priv->gart_info.sg_dummy_bus = - pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) { - nouveau_gpuobj_ref(NULL, &gpuobj); - return -EFAULT; - } - if (dev_priv->card_type < NV_50) { /* special case, allocated from global instmem heap so * cinst is invalid, we use it on all channels though so @@ -277,10 +256,8 @@ nouveau_sgdma_init(struct drm_device *dev) (NV_DMA_ACCESS_RW << 14) | (NV_DMA_TARGET_PCI << 16)); nv_wo32(gpuobj, 4, aper_size - 1); - for (i = 2; i < 2 + (aper_size >> 12); i++) { - nv_wo32(gpuobj, i * 4, - dev_priv->gart_info.sg_dummy_bus | 3); - } + for (i = 2; i < 2 + (aper_size >> 12); i++) + nv_wo32(gpuobj, i * 4, 0x00000000); } else { for (i = 0; i < obj_size; i += 8) { nv_wo32(gpuobj, i + 0, 0x00000000); @@ -301,15 +278,6 @@ nouveau_sgdma_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - if (dev_priv->gart_info.sg_dummy_page) { - pci_unmap_page(dev->pdev, dev_priv->gart_info.sg_dummy_bus, - NV_CTXDMA_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - unlock_page(dev_priv->gart_info.sg_dummy_page); - __free_page(dev_priv->gart_info.sg_dummy_page); - dev_priv->gart_info.sg_dummy_page = NULL; - dev_priv->gart_info.sg_dummy_bus = 0; - } - nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma); } -- cgit v1.2.3 From 2cb3d3b6c64d37514fd8865748de66ff35a489af Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 16:28:19 +1000 Subject: drm/nv84: fix minor issues in PCRYPT implementation Fix running of destroy_context() when create_context() has never been called for the channel, and fill in engine's tlb_flush() function pointer. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 1 + drivers/gpu/drm/nouveau/nv84_crypt.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index b42e29d1935e..75e70022fbd3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -437,6 +437,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->crypt.takedown = nv84_crypt_fini; engine->crypt.create_context = nv84_crypt_create_context; engine->crypt.destroy_context = nv84_crypt_destroy_context; + engine->crypt.tlb_flush = nv84_crypt_tlb_flush; break; default: engine->crypt.init = nouveau_stub_init; diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c index 1cda0240f55d..780bb1d66f95 100644 --- a/drivers/gpu/drm/nouveau/nv84_crypt.c +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -61,7 +61,7 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; u32 inst; - if (!chan->ramin) + if (!chan->crypt_ctx) return; inst = (chan->ramin->vinst >> 12); -- cgit v1.2.3 From 6d6c5a157af45a5bd50ab913b07d826811a9ea0a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Nov 2010 10:17:53 +1000 Subject: drm/nouveau: remove some useless GETPARAMs These have been unused since UMS support was ripped out, so lets remove them completely. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 17 +---------------- include/drm/nouveau_drm.h | 3 --- 2 files changed, 1 insertion(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 75e70022fbd3..35b28406caf6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1074,21 +1074,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, else getparam->value = NV_PCI; break; - case NOUVEAU_GETPARAM_FB_PHYSICAL: - getparam->value = dev_priv->fb_phys; - break; - case NOUVEAU_GETPARAM_AGP_PHYSICAL: - getparam->value = dev_priv->gart_info.aper_base; - break; - case NOUVEAU_GETPARAM_PCI_PHYSICAL: - if (dev->sg) { - getparam->value = (unsigned long)dev->sg->virtual; - } else { - NV_ERROR(dev, "Requested PCIGART address, " - "while no PCIGART was created\n"); - return -EINVAL; - } - break; case NOUVEAU_GETPARAM_FB_SIZE: getparam->value = dev_priv->fb_available_size; break; @@ -1096,7 +1081,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, getparam->value = dev_priv->gart_info.aper_size; break; case NOUVEAU_GETPARAM_VM_VRAM_BASE: - getparam->value = dev_priv->vm_vram_base; + getparam->value = 0; /* deprecated */ break; case NOUVEAU_GETPARAM_PTIMER_TIME: getparam->value = dev_priv->engine.timer.read(dev); diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index 39aa0fd6a529..e2cfe80f6fca 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -71,11 +71,8 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_GETPARAM_PCI_VENDOR 3 #define NOUVEAU_GETPARAM_PCI_DEVICE 4 #define NOUVEAU_GETPARAM_BUS_TYPE 5 -#define NOUVEAU_GETPARAM_FB_PHYSICAL 6 -#define NOUVEAU_GETPARAM_AGP_PHYSICAL 7 #define NOUVEAU_GETPARAM_FB_SIZE 8 #define NOUVEAU_GETPARAM_AGP_SIZE 9 -#define NOUVEAU_GETPARAM_PCI_PHYSICAL 10 #define NOUVEAU_GETPARAM_CHIPSET_ID 11 #define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 -- cgit v1.2.3 From 7f4a195fcbd8b16f25f1de7f1419414d7505daa5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Nov 2010 11:50:09 +1000 Subject: drm/nouveau: tidy up and extend dma object creation interfaces Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 23 ++- drivers/gpu/drm/nouveau/nouveau_drv.h | 26 +++- drivers/gpu/drm/nouveau/nouveau_fence.c | 4 +- drivers/gpu/drm/nouveau/nouveau_notifier.c | 29 +--- drivers/gpu/drm/nouveau/nouveau_object.c | 235 +++++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_reg.h | 11 -- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 7 +- drivers/gpu/drm/nouveau/nouveau_state.c | 9 +- 8 files changed, 184 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 11b2370e16da..0f33132fba3b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -39,22 +39,22 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, - dev_priv->vm_end, NV_DMA_ACCESS_RO, - NV_DMA_TARGET_AGP, &pushbuf); + dev_priv->vm_end, NV_MEM_ACCESS_RO, + NV_MEM_TARGET_VM, &pushbuf); chan->pushbuf_base = pb->bo.offset; } else if (pb->bo.mem.mem_type == TTM_PL_TT) { - ret = nouveau_gpuobj_gart_dma_new(chan, 0, - dev_priv->gart_info.aper_size, - NV_DMA_ACCESS_RO, &pushbuf, - NULL); + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, + dev_priv->gart_info.aper_size, + NV_MEM_ACCESS_RO, + NV_MEM_TARGET_GART, &pushbuf); chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; } else if (dev_priv->card_type != NV_04) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->fb_available_size, - NV_DMA_ACCESS_RO, - NV_DMA_TARGET_VIDMEM, &pushbuf); + NV_MEM_ACCESS_RO, + NV_MEM_TARGET_VRAM, &pushbuf); chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; } else { /* NV04 cmdbuf hack, from original ddx.. not sure of it's @@ -62,11 +62,10 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) * VRAM. */ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - pci_resource_start(dev->pdev, - 1), + pci_resource_start(dev->pdev, 1), dev_priv->fb_available_size, - NV_DMA_ACCESS_RO, - NV_DMA_TARGET_PCI, &pushbuf); + NV_MEM_ACCESS_RO, + NV_MEM_TARGET_PCI, &pushbuf); chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d76d2c09049d..a52b1da32031 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -886,12 +886,14 @@ extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst, extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, uint64_t offset, uint64_t size, int access, int target, struct nouveau_gpuobj **); -extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, - uint64_t offset, uint64_t size, - int access, struct nouveau_gpuobj **, - uint32_t *o_ret); extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, struct nouveau_gpuobj **); +extern int nv50_gpuobj_dma_new(struct nouveau_channel *, int class, u64 base, + u64 size, int target, int access, u32 type, + u32 comp, struct nouveau_gpuobj **pobj); +extern void nv50_gpuobj_dma_init(struct nouveau_gpuobj *, u32 offset, + int class, u64 base, u64 size, int target, + int access, u32 type, u32 comp); extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, @@ -1545,6 +1547,22 @@ nv_match_device(struct drm_device *dev, unsigned device, dev->pdev->subsystem_device == sub_device; } +/* memory type/access flags, do not match hardware values */ +#define NV_MEM_ACCESS_RO 1 +#define NV_MEM_ACCESS_WO 2 +#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO) +#define NV_MEM_ACCESS_VM 4 + +#define NV_MEM_TARGET_VRAM 0 +#define NV_MEM_TARGET_PCI 1 +#define NV_MEM_TARGET_PCI_NOSNOOP 2 +#define NV_MEM_TARGET_VM 3 +#define NV_MEM_TARGET_GART 4 + +#define NV_MEM_TYPE_VM 0x7f +#define NV_MEM_COMP_VM 0x03 + +/* NV_SW object class */ #define NV_SW 0x0000506e #define NV_SW_DMA_SEMAPHORE 0x00000060 #define NV_SW_SEMAPHORE_OFFSET 0x00000064 diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 91aa6c54cc96..2579fc69d182 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -459,8 +459,8 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, mem->start << PAGE_SHIFT, mem->size << PAGE_SHIFT, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_VIDMEM, &obj); + NV_MEM_ACCESS_RW, + NV_MEM_TARGET_VRAM, &obj); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 2c5a1f66f7f0..a050b7b69782 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -99,7 +99,6 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, int size, uint32_t *b_offset) { struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *nobj = NULL; struct drm_mm_node *mem; uint32_t offset; @@ -113,31 +112,15 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, return -ENOMEM; } - offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; - if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) { - target = NV_DMA_TARGET_VIDMEM; - } else - if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_TT) { - if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA && - dev_priv->card_type < NV_50) { - ret = nouveau_sgdma_get_page(dev, offset, &offset); - if (ret) - return ret; - target = NV_DMA_TARGET_PCI; - } else { - target = NV_DMA_TARGET_AGP; - if (dev_priv->card_type >= NV_50) - offset += dev_priv->vm_gart_base; - } - } else { - NV_ERROR(dev, "Bad DMA target, mem_type %d!\n", - chan->notifier_bo->bo.mem.mem_type); - return -EINVAL; - } + if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) + target = NV_MEM_TARGET_VRAM; + else + target = NV_MEM_TARGET_GART; + offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; offset += mem->start; ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset, - mem->size, NV_DMA_ACCESS_RW, target, + mem->size, NV_MEM_ACCESS_RW, target, &nobj); if (ret) { drm_mm_put_block(mem); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index e8c74de905ec..924653c30783 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -404,113 +404,157 @@ nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class) The method below creates a DMA object in instance RAM and returns a handle to it that can be used to set up context objects. */ -int -nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, - uint64_t offset, uint64_t size, int access, - int target, struct nouveau_gpuobj **gpuobj) + +void +nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class, + u64 base, u64 size, int target, int access, + u32 type, u32 comp) { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; - int ret; + struct drm_nouveau_private *dev_priv = obj->dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + u32 flags0; - NV_DEBUG(dev, "ch%d class=0x%04x offset=0x%llx size=0x%llx\n", - chan->id, class, offset, size); - NV_DEBUG(dev, "access=%d target=%d\n", access, target); + flags0 = (comp << 29) | (type << 22) | class; + flags0 |= 0x00100000; + + switch (access) { + case NV_MEM_ACCESS_RO: flags0 |= 0x00040000; break; + case NV_MEM_ACCESS_RW: + case NV_MEM_ACCESS_WO: flags0 |= 0x00080000; break; + default: + break; + } switch (target) { - case NV_DMA_TARGET_AGP: - offset += dev_priv->gart_info.aper_base; + case NV_MEM_TARGET_VRAM: + flags0 |= 0x00010000; + break; + case NV_MEM_TARGET_PCI: + flags0 |= 0x00020000; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + flags0 |= 0x00030000; break; + case NV_MEM_TARGET_GART: + base += dev_priv->vm_gart_base; default: + flags0 &= ~0x00100000; break; } - ret = nouveau_gpuobj_new(dev, chan, - nouveau_gpuobj_class_instmem_size(dev, class), - 16, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, gpuobj); - if (ret) { - NV_ERROR(dev, "Error creating gpuobj: %d\n", ret); - return ret; - } + /* convert to base + limit */ + size = (base + size) - 1; - if (dev_priv->card_type < NV_50) { - uint32_t frame, adjust, pte_flags = 0; - - if (access != NV_DMA_ACCESS_RO) - pte_flags |= (1<<1); - adjust = offset & 0x00000fff; - frame = offset & ~0x00000fff; - - nv_wo32(*gpuobj, 0, ((1<<12) | (1<<13) | (adjust << 20) | - (access << 14) | (target << 16) | - class)); - nv_wo32(*gpuobj, 4, size - 1); - nv_wo32(*gpuobj, 8, frame | pte_flags); - nv_wo32(*gpuobj, 12, frame | pte_flags); - } else { - uint64_t limit = offset + size - 1; - uint32_t flags0, flags5; + nv_wo32(obj, offset + 0x00, flags0); + nv_wo32(obj, offset + 0x04, lower_32_bits(size)); + nv_wo32(obj, offset + 0x08, lower_32_bits(base)); + nv_wo32(obj, offset + 0x0c, upper_32_bits(size) << 24 | + upper_32_bits(base)); + nv_wo32(obj, offset + 0x10, 0x00000000); + nv_wo32(obj, offset + 0x14, 0x00000000); - if (target == NV_DMA_TARGET_VIDMEM) { - flags0 = 0x00190000; - flags5 = 0x00010000; - } else { - flags0 = 0x7fc00000; - flags5 = 0x00080000; - } + pinstmem->flush(obj->dev); +} - nv_wo32(*gpuobj, 0, flags0 | class); - nv_wo32(*gpuobj, 4, lower_32_bits(limit)); - nv_wo32(*gpuobj, 8, lower_32_bits(offset)); - nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) | - (upper_32_bits(offset) & 0xff)); - nv_wo32(*gpuobj, 20, flags5); - } +int +nv50_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, u64 size, + int target, int access, u32 type, u32 comp, + struct nouveau_gpuobj **pobj) +{ + struct drm_device *dev = chan->dev; + int ret; - instmem->flush(dev); + ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, pobj); + if (ret) + return ret; - (*gpuobj)->engine = NVOBJ_ENGINE_SW; - (*gpuobj)->class = class; + nv50_gpuobj_dma_init(*pobj, 0, class, base, size, target, + access, type, comp); return 0; } int -nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan, - uint64_t offset, uint64_t size, int access, - struct nouveau_gpuobj **gpuobj, - uint32_t *o_ret) +nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, + u64 size, int access, int target, + struct nouveau_gpuobj **pobj) { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *obj; + u32 page_addr, flags0, flags2; int ret; - if (dev_priv->gart_info.type == NOUVEAU_GART_AGP || - (dev_priv->card_type >= NV_50 && - dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) { - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - offset + dev_priv->vm_gart_base, - size, access, NV_DMA_TARGET_AGP, - gpuobj); - if (o_ret) - *o_ret = 0; - } else - if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) { - nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj); - if (offset & ~0xffffffffULL) { - NV_ERROR(dev, "obj offset exceeds 32-bits\n"); - return -EINVAL; + if (dev_priv->card_type >= NV_50) { + u32 comp = (target == NV_MEM_TARGET_VM) ? NV_MEM_COMP_VM : 0; + u32 type = (target == NV_MEM_TARGET_VM) ? NV_MEM_TYPE_VM : 0; + + return nv50_gpuobj_dma_new(chan, class, base, size, + target, access, type, comp, pobj); + } + + if (target == NV_MEM_TARGET_GART) { + if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) { + target = NV_MEM_TARGET_PCI_NOSNOOP; + base += dev_priv->gart_info.aper_base; + } else + if (base != 0) { + ret = nouveau_sgdma_get_page(dev, base, &page_addr); + if (ret) + return ret; + + target = NV_MEM_TARGET_PCI; + base = page_addr; + } else { + nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj); + return 0; } - if (o_ret) - *o_ret = (uint32_t)offset; - ret = (*gpuobj != NULL) ? 0 : -EINVAL; - } else { - NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type); - return -EINVAL; } - return ret; + flags0 = class; + flags0 |= 0x00003000; /* PT present, PT linear */ + flags2 = 0; + + switch (target) { + case NV_MEM_TARGET_PCI: + flags0 |= 0x00020000; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + flags0 |= 0x00030000; + break; + default: + break; + } + + switch (access) { + case NV_MEM_ACCESS_RO: + flags0 |= 0x00004000; + break; + case NV_MEM_ACCESS_WO: + flags0 |= 0x00008000; + default: + flags2 |= 0x00000002; + break; + } + + flags0 |= (base & 0x00000fff) << 20; + flags2 |= (base & 0xfffff000); + + ret = nouveau_gpuobj_new(dev, chan, (dev_priv->card_type >= NV_40) ? + 32 : 16, 16, NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, &obj); + if (ret) + return ret; + + nv_wo32(obj, 0x00, flags0); + nv_wo32(obj, 0x04, size - 1); + nv_wo32(obj, 0x08, flags2); + nv_wo32(obj, 0x0c, flags2); + + obj->engine = NVOBJ_ENGINE_SW; + obj->class = class; + *pobj = obj; + return 0; } /* Context objects in the instance RAM have the following structure. @@ -806,8 +850,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->vm_end, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_AGP, &vram); + NV_MEM_ACCESS_RW, + NV_MEM_TARGET_VM, &vram); if (ret) { NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); return ret; @@ -815,8 +859,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, } else { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->fb_available_size, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_VIDMEM, &vram); + NV_MEM_ACCESS_RW, + NV_MEM_TARGET_VRAM, &vram); if (ret) { NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); return ret; @@ -834,20 +878,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->vm_end, - NV_DMA_ACCESS_RW, - NV_DMA_TARGET_AGP, &tt); - if (ret) { - NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); - return ret; - } - } else - if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { - ret = nouveau_gpuobj_gart_dma_new(chan, 0, - dev_priv->gart_info.aper_size, - NV_DMA_ACCESS_RW, &tt, NULL); + NV_MEM_ACCESS_RW, + NV_MEM_TARGET_VM, &tt); } else { - NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type); - ret = -EINVAL; + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->gart_info.aper_size, + NV_MEM_ACCESS_RW, + NV_MEM_TARGET_GART, &tt); } if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index df3a87e792f2..04e8fb795269 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -79,17 +79,6 @@ # define NV40_RAMHT_CONTEXT_ENGINE_SHIFT 20 # define NV40_RAMHT_CONTEXT_INSTANCE_SHIFT 0 -/* DMA object defines */ -#define NV_DMA_ACCESS_RW 0 -#define NV_DMA_ACCESS_RO 1 -#define NV_DMA_ACCESS_WO 2 -#define NV_DMA_TARGET_VIDMEM 0 -#define NV_DMA_TARGET_PCI 2 -#define NV_DMA_TARGET_AGP 3 -/* The following is not a real value used by the card, it's changed by - * nouveau_object_dma_create */ -#define NV_DMA_TARGET_PCI_NONLINEAR 8 - /* Some object classes we care about in the drm */ #define NV_CLASS_DMA_FROM_MEMORY 0x00000002 #define NV_CLASS_DMA_TO_MEMORY 0x00000003 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 54af7608d45c..db32644f6114 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -247,14 +247,11 @@ nouveau_sgdma_init(struct drm_device *dev) */ gpuobj->cinst = gpuobj->pinst; - /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and - * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE - * on those cards? */ nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY | (1 << 12) /* PT present */ | (0 << 13) /* PT *not* linear */ | - (NV_DMA_ACCESS_RW << 14) | - (NV_DMA_TARGET_PCI << 16)); + (0 << 14) /* RW */ | + (2 << 16) /* PCI */); nv_wo32(gpuobj, 4, aper_size - 1); for (i = 2; i < 2 + (aper_size >> 12); i++) nv_wo32(gpuobj, i * 4, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 35b28406caf6..e779e9320453 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -536,7 +536,7 @@ nouveau_card_init_channel(struct drm_device *dev) ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->vram_size, - NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM, + NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM, &gpuobj); if (ret) goto out_err; @@ -546,9 +546,10 @@ nouveau_card_init_channel(struct drm_device *dev) if (ret) goto out_err; - ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0, - dev_priv->gart_info.aper_size, - NV_DMA_ACCESS_RW, &gpuobj, NULL); + ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, + 0, dev_priv->gart_info.aper_size, + NV_MEM_ACCESS_RW, NV_MEM_TARGET_GART, + &gpuobj); if (ret) goto out_err; -- cgit v1.2.3 From 2e5702aff39532662198459726c624d5eadbdd78 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 19 Nov 2010 18:08:47 +1000 Subject: drm/nouveau: fabricate DCB encoder table for iMac G4 In typical Apple fashion there's no standard information about what encoders are present on this machine, this patch adds a quirk to provide it. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 102 ++++++++++++--------------------- 1 file changed, 38 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b2293576f278..d3046559bf05 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6053,52 +6053,17 @@ static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb) return entry; } -static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads) +static void fabricate_dcb_output(struct dcb_table *dcb, int type, int i2c, + int heads, int or) { struct dcb_entry *entry = new_dcb_entry(dcb); - entry->type = 0; + entry->type = type; entry->i2c_index = i2c; entry->heads = heads; - entry->location = DCB_LOC_ON_CHIP; - entry->or = 1; -} - -static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads) -{ - struct dcb_entry *entry = new_dcb_entry(dcb); - - entry->type = 2; - entry->i2c_index = LEGACY_I2C_PANEL; - entry->heads = twoHeads ? 3 : 1; - entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */ - entry->or = 1; /* means |0x10 gets set on CRE_LCD__INDEX */ - entry->duallink_possible = false; /* SiI164 and co. are single link */ - -#if 0 - /* - * For dvi-a either crtc probably works, but my card appears to only - * support dvi-d. "nvidia" still attempts to program it for dvi-a, - * doing the full fp output setup (program 0x6808.. fp dimension regs, - * setting 0x680848 to 0x10000111 to enable, maybe setting 0x680880); - * the monitor picks up the mode res ok and lights up, but no pixel - * data appears, so the board manufacturer probably connected up the - * sync lines, but missed the video traces / components - * - * with this introduction, dvi-a left as an exercise for the reader. - */ - fabricate_vga_output(dcb, LEGACY_I2C_PANEL, entry->heads); -#endif -} - -static void fabricate_tv_output(struct dcb_table *dcb, bool twoHeads) -{ - struct dcb_entry *entry = new_dcb_entry(dcb); - - entry->type = 1; - entry->i2c_index = LEGACY_I2C_TV; - entry->heads = twoHeads ? 3 : 1; - entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */ + if (type != OUTPUT_ANALOG) + entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */ + entry->or = or; } static bool @@ -6365,8 +6330,36 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) return true; } +static void +fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios) +{ + struct dcb_table *dcb = &bios->dcb; + int all_heads = (nv_two_heads(dev) ? 3 : 1); + +#ifdef __powerpc__ + /* Apple iMac G4 NV17 */ + if (of_machine_is_compatible("PowerMac4,5")) { + fabricate_dcb_output(dcb, OUTPUT_TMDS, 0, all_heads, 1); + fabricate_dcb_output(dcb, OUTPUT_ANALOG, 1, all_heads, 2); + return; + } +#endif + + /* Make up some sane defaults */ + fabricate_dcb_output(dcb, OUTPUT_ANALOG, LEGACY_I2C_CRT, 1, 1); + + if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) + fabricate_dcb_output(dcb, OUTPUT_TV, LEGACY_I2C_TV, + all_heads, 0); + + else if (bios->tmds.output0_script_ptr || + bios->tmds.output1_script_ptr) + fabricate_dcb_output(dcb, OUTPUT_TMDS, LEGACY_I2C_PANEL, + all_heads, 1); +} + static int -parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) +parse_dcb_table(struct drm_device *dev, struct nvbios *bios) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &bios->dcb; @@ -6386,12 +6379,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) /* this situation likely means a really old card, pre DCB */ if (dcbptr == 0x0) { - NV_INFO(dev, "Assuming a CRT output exists\n"); - fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1); - - if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) - fabricate_tv_output(dcb, twoHeads); - + fabricate_dcb_encoder_table(dev, bios); return 0; } @@ -6451,21 +6439,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) */ NV_TRACEWARN(dev, "No useful information in BIOS output table; " "adding all possible outputs\n"); - fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1); - - /* - * Attempt to detect TV before DVI because the test - * for the former is more accurate and it rules the - * latter out. - */ - if (nv04_tv_identify(dev, - bios->legacy.i2c_indices.tv) >= 0) - fabricate_tv_output(dcb, twoHeads); - - else if (bios->tmds.output0_script_ptr || - bios->tmds.output1_script_ptr) - fabricate_dvi_i_output(dcb, twoHeads); - + fabricate_dcb_encoder_table(dev, bios); return 0; } @@ -6859,7 +6833,7 @@ nouveau_bios_init(struct drm_device *dev) if (ret) return ret; - ret = parse_dcb_table(dev, bios, nv_two_heads(dev)); + ret = parse_dcb_table(dev, bios); if (ret) return ret; -- cgit v1.2.3 From 66bde0b70aa2e348ac2c9b9626743c1402b9d466 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 28 Oct 2010 15:41:56 +0200 Subject: dma/intel_mid_dma: remove unneeded null check Smatch complains because we dereference "mid" before checking it. It turns out that "mid" is always a valid pointer here so we can just remove the check. Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/dma/intel_mid_dma.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 338bc4eed1f3..41941d05bfb9 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1021,11 +1021,6 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data) /*DMA Interrupt*/ pr_debug("MDMA:Got an interrupt on irq %d\n", irq); - if (!mid) { - pr_err("ERR_MDMA:null pointer mid\n"); - return -EINVAL; - } - pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask); tfr_status &= mid->intr_mask; if (tfr_status) { -- cgit v1.2.3 From 3345cc4f6d779753810c7f13aab6b29417869548 Mon Sep 17 00:00:00 2001 From: Guillaume LECERF Date: Fri, 29 Oct 2010 16:17:49 +0200 Subject: mtd: bcm963xx-flash: try JEDEC probe if CFI fails Signed-off-by: Guillaume LECERF Acked-by: Florian Fainelli Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/bcm963xx-flash.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c index d175c120ee84..1f3049590d9e 100644 --- a/drivers/mtd/maps/bcm963xx-flash.c +++ b/drivers/mtd/maps/bcm963xx-flash.c @@ -196,10 +196,15 @@ static int bcm963xx_probe(struct platform_device *pdev) bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); if (!bcm963xx_mtd_info) { dev_err(&pdev->dev, "failed to probe using CFI\n"); + bcm963xx_mtd_info = do_map_probe("jedec_probe", &bcm963xx_map); + if (bcm963xx_mtd_info) + goto probe_ok; + dev_err(&pdev->dev, "failed to probe using JEDEC\n"); err = -EIO; goto err_probe; } +probe_ok: bcm963xx_mtd_info->owner = THIS_MODULE; /* This is mutually exclusive */ -- cgit v1.2.3 From b7b6e08f9265db56129931983fc6c06d62c9f4f9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 30 Oct 2010 07:35:02 +0100 Subject: mtd: Fix MTD_OF_PARTS for all arch and minor tidy of MTD_PARTITIONS MTD_OF_PARTS should be possible on all architectures, not just powerpc and microblaze, and it probably should not be a user selectable option. Neither does it need to be in a separate module. Also, rework MTD Kconfig to group options dependant on MTD_PARTITIONS into a if/endif block. Do the same for MTD_REDBOOT_PARTS. Signed-off-by: Grant Likely Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/Kconfig | 19 +++++++++++-------- drivers/mtd/Makefile | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 1e2cbf5d9aa1..77414702cb00 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -53,9 +53,10 @@ config MTD_PARTITIONS devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. +if MTD_PARTITIONS + config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" - depends on MTD_PARTITIONS ---help--- RedBoot is a ROM monitor and bootloader which deals with multiple 'images' in flash devices by putting a table one of the erase @@ -72,9 +73,10 @@ config MTD_REDBOOT_PARTS SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. +if MTD_REDBOOT_PARTS + config MTD_REDBOOT_DIRECTORY_BLOCK int "Location of RedBoot partition table" - depends on MTD_REDBOOT_PARTS default "-1" ---help--- This option is the Linux counterpart to the @@ -91,18 +93,18 @@ config MTD_REDBOOT_DIRECTORY_BLOCK config MTD_REDBOOT_PARTS_UNALLOCATED bool "Include unallocated flash regions" - depends on MTD_REDBOOT_PARTS help If you need to register each unallocated flash region as a MTD 'partition', enable this option. config MTD_REDBOOT_PARTS_READONLY bool "Force read-only for RedBoot system images" - depends on MTD_REDBOOT_PARTS help If you need to force read-only for 'RedBoot', 'RedBoot Config' and 'FIS directory' images, enable this option. +endif # MTD_REDBOOT_PARTS + config MTD_CMDLINE_PARTS bool "Command line partition table parsing" depends on MTD_PARTITIONS = "y" && MTD = "y" @@ -142,7 +144,7 @@ config MTD_CMDLINE_PARTS config MTD_AFS_PARTS tristate "ARM Firmware Suite partition parsing" - depends on ARM && MTD_PARTITIONS + depends on ARM ---help--- The ARM Firmware Suite allows the user to divide flash devices into multiple 'images'. Each such image has a header containing its name @@ -158,8 +160,8 @@ config MTD_AFS_PARTS example. config MTD_OF_PARTS - tristate "Flash partition map based on OF description" - depends on (MICROBLAZE || PPC_OF) && MTD_PARTITIONS + def_bool y + depends on OF help This provides a partition parsing function which derives the partition map from the children of the flash node, @@ -167,10 +169,11 @@ config MTD_OF_PARTS config MTD_AR7_PARTS tristate "TI AR7 partitioning support" - depends on MTD_PARTITIONS ---help--- TI AR7 partitioning support +endif # MTD_PARTITIONS + comment "User Modules And Translation Layers" config MTD_CHAR diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 760abc533395..d4e7f25b1ebb 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -6,13 +6,13 @@ obj-$(CONFIG_MTD) += mtd.o mtd-y := mtdcore.o mtdsuper.o mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o +mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o -obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_CHAR) += mtdchar.o -- cgit v1.2.3 From f0dff9bd00d2cffea160fb3fa015b77607458634 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 30 Oct 2010 21:11:02 -0700 Subject: mtd: m25p80: Reinstate error print on unrecognized flash Commit b34bc037b26e621e5fc13466767e4da110a7b3d3 removed the "unrecognized JEDEC id" error message, causing the probe function to silently abort if the flash ID is unrecognized. It is desirable to produce diagnostic output in this situation so that the user has some idea what went wrong. Signed-off-by: Kevin Cernekee Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index bf5a002209bd..80404e1a4d5e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -764,6 +764,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) return &m25p_ids[tmp]; } } + dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); return ERR_PTR(-ENODEV); } -- cgit v1.2.3 From 4b7f7422b0331e802f8b7c593e058ccee981cff5 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 30 Oct 2010 21:11:03 -0700 Subject: mtd: m25p80: Add support for Macronix MX25L25635E This is a 256Mbit (32MiB) part so minor changes were made to support 4-byte addressing. Signed-off-by: Kevin Cernekee Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 80404e1a4d5e..96ae54e9650e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -51,6 +51,10 @@ #define OPCODE_WRDI 0x04 /* Write disable */ #define OPCODE_AAI_WP 0xad /* Auto address increment word program */ +/* Used for Macronix flashes only. */ +#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ +#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ + /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ @@ -62,7 +66,7 @@ /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ -#define MAX_CMD_SIZE 4 +#define MAX_CMD_SIZE 5 #ifdef CONFIG_M25PXX_USE_FAST_READ #define OPCODE_READ OPCODE_FAST_READ @@ -151,6 +155,16 @@ static inline int write_disable(struct m25p *flash) return spi_write_then_read(flash->spi, &code, 1, NULL, 0); } +/* + * Enable/disable 4-byte addressing mode. + */ +static inline int set_4byte(struct m25p *flash, int enable) +{ + u8 code = enable ? OPCODE_EN4B : OPCODE_EX4B; + + return spi_write_then_read(flash->spi, &code, 1, NULL, 0); +} + /* * Service routine to read status register until ready, or timeout occurs. * Returns non-zero if error. @@ -207,6 +221,7 @@ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) cmd[1] = addr >> (flash->addr_width * 8 - 8); cmd[2] = addr >> (flash->addr_width * 8 - 16); cmd[3] = addr >> (flash->addr_width * 8 - 24); + cmd[4] = addr >> (flash->addr_width * 8 - 32); } static int m25p_cmdsz(struct m25p *flash) @@ -607,7 +622,6 @@ struct flash_info { .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ - .addr_width = 3, \ .flags = (_flags), \ }) @@ -653,6 +667,7 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). @@ -884,7 +899,17 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->mtd.dev.parent = &spi->dev; flash->page_size = info->page_size; - flash->addr_width = info->addr_width; + + if (info->addr_width) + flash->addr_width = info->addr_width; + else { + /* enable 4-byte addressing if the device exceeds 16MiB */ + if (flash->mtd.size > 0x1000000) { + flash->addr_width = 4; + set_4byte(flash, 1); + } else + flash->addr_width = 3; + } dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->mtd.size >> 10); -- cgit v1.2.3 From ac622f583dccb025250becd2d4e60badaf571713 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 30 Oct 2010 21:11:04 -0700 Subject: mtd: m25p80: Add support for Macronix MX25L25655E Untested, but expected to be compatible with MX25L25635E which I did test. Signed-off-by: Kevin Cernekee Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 96ae54e9650e..eabe5fb071c6 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -668,6 +668,7 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, + { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). -- cgit v1.2.3 From daf05ec00c6e60a2c705820e7f93cbd31c804fe3 Mon Sep 17 00:00:00 2001 From: srimugunthan Date: Sat, 13 Nov 2010 12:46:05 +0200 Subject: mtd: nandsim: spell fixes in comments Signed-off-by: srimugunthan Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index a6a73aab1253..c45e06fba154 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -210,12 +210,12 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d #define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ #define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ #define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ -#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */ +#define STATE_CMD_PAGEPROG 0x00000004 /* start page program */ #define STATE_CMD_READOOB 0x00000005 /* read OOB area */ #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ #define STATE_CMD_STATUS 0x00000007 /* read status */ #define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ -#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */ +#define STATE_CMD_SEQIN 0x00000009 /* sequential data input */ #define STATE_CMD_READID 0x0000000A /* read ID */ #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ #define STATE_CMD_RESET 0x0000000C /* reset */ @@ -230,7 +230,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d #define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ #define STATE_ADDR_MASK 0x00000070 /* address states mask */ -/* Durind data input/output the simulator is in these states */ +/* During data input/output the simulator is in these states */ #define STATE_DATAIN 0x00000100 /* waiting for data input */ #define STATE_DATAIN_MASK 0x00000100 /* data input states mask */ @@ -248,7 +248,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d /* Simulator's actions bit masks */ #define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */ -#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */ +#define ACTION_PRGPAGE 0x00200000 /* program the internal buffer to flash */ #define ACTION_SECERASE 0x00300000 /* erase sector */ #define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */ #define ACTION_HALFOFF 0x00500000 /* add to address half of page */ @@ -263,18 +263,18 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ -#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */ +#define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */ #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ #define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ -/* Remove action bits ftom state */ +/* Remove action bits from state */ #define NS_STATE(x) ((x) & ~ACTION_MASK) /* * Maximum previous states which need to be saved. Currently saving is - * only needed for page programm operation with preceeded read command + * only needed for page program operation with preceded read command * (which is only valid for 512-byte pages). */ #define NS_MAX_PREVSTATES 1 @@ -380,16 +380,16 @@ static struct nandsim_operations { /* Read OOB */ {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, STATE_DATAOUT, STATE_READY}}, - /* Programm page starting from the beginning */ + /* Program page starting from the beginning */ {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, - /* Programm page starting from the beginning */ + /* Program page starting from the beginning */ {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, - /* Programm page starting from the second half */ + /* Program page starting from the second half */ {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, - /* Programm OOB */ + /* Program OOB */ {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, /* Erase sector */ @@ -1171,9 +1171,9 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) * of supported operations. * * Operation can be unknown because of the following. - * 1. New command was accepted and this is the firs call to find the + * 1. New command was accepted and this is the first call to find the * correspondent states chain. In this case ns->npstates = 0; - * 2. There is several operations which begin with the same command(s) + * 2. There are several operations which begin with the same command(s) * (for example program from the second half and read from the * second half operations both begin with the READ1 command). In this * case the ns->pstates[] array contains previous states. @@ -1186,7 +1186,7 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is * zeroed). * - * If there are several maches, the current state is pushed to the + * If there are several matches, the current state is pushed to the * ns->pstates. * * The operation can be unknown only while commands are input to the chip. @@ -1195,10 +1195,10 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) * operation is searched using the following pattern: * ns->pstates[0], ... ns->pstates[ns->npstates],
* - * It is supposed that this pattern must either match one operation on + * It is supposed that this pattern must either match one operation or * none. There can't be ambiguity in that case. * - * If no matches found, the functions does the following: + * If no matches found, the function does the following: * 1. if there are saved states present, try to ignore them and search * again only using the last command. If nothing was found, switch * to the STATE_READY state. @@ -1668,7 +1668,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) case ACTION_PRGPAGE: /* - * Programm page - move internal buffer data to the page. + * Program page - move internal buffer data to the page. */ if (ns->lines.wp) { @@ -1933,7 +1933,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) NS_DBG("read_byte: all bytes were read\n"); /* - * The OPT_AUTOINCR allows to read next conseqitive pages without + * The OPT_AUTOINCR allows to read next consecutive pages without * new read operation cycle. */ if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { -- cgit v1.2.3 From 08b3af3092bb2c284796e4e823c5309c2d0a9bca Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Tue, 2 Nov 2010 10:28:46 +0900 Subject: mtd: OneNAND: Fix page offset handling at 2KiB pagesize When use the 2KiB pagesize, it should be set the correct page offset. Signed-off-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/samsung.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 0de7a05e6de0..a4c74a9ba430 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, void __iomem *p; void *buf = (void *) buffer; dma_addr_t dma_src, dma_dst; - int err, page_dma = 0; + int err, ofs, page_dma = 0; struct device *dev = &onenand->pdev->dev; p = this->base + area; @@ -677,10 +677,13 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, if (!page) goto normal; + /* Page offset */ + ofs = ((size_t) buf & ~PAGE_MASK); page_dma = 1; + /* DMA routine */ dma_src = onenand->phys_base + (p - this->base); - dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); + dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE); } else { /* DMA routine */ dma_src = onenand->phys_base + (p - this->base); -- cgit v1.2.3 From 309b5e4e4154721f8079bc250d2233fd4b3aa039 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 4 Nov 2010 20:07:40 -0700 Subject: mtd: use vzalloc Signed-off-by: Joe Perches Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 3 +-- drivers/mtd/ubi/vtbl.c | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c45e06fba154..a5aa99f014ba 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -470,7 +470,7 @@ static int alloc_device(struct nandsim *ns) err = -EINVAL; goto err_close; } - ns->pages_written = vmalloc(ns->geom.pgnum); + ns->pages_written = vzalloc(ns->geom.pgnum); if (!ns->pages_written) { NS_ERR("alloc_device: unable to allocate pages written array\n"); err = -ENOMEM; @@ -483,7 +483,6 @@ static int alloc_device(struct nandsim *ns) goto err_free; } ns->cfile = cfile; - memset(ns->pages_written, 0, ns->geom.pgnum); return 0; } diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index fcdb7f65fe0b..0b8141fc5c26 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -425,12 +425,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, /* Read both LEB 0 and LEB 1 into memory */ ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { - leb[seb->lnum] = vmalloc(ubi->vtbl_size); + leb[seb->lnum] = vzalloc(ubi->vtbl_size); if (!leb[seb->lnum]) { err = -ENOMEM; goto out_free; } - memset(leb[seb->lnum], 0, ubi->vtbl_size); err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); @@ -516,10 +515,9 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, int i; struct ubi_vtbl_record *vtbl; - vtbl = vmalloc(ubi->vtbl_size); + vtbl = vzalloc(ubi->vtbl_size); if (!vtbl) return ERR_PTR(-ENOMEM); - memset(vtbl, 0, ubi->vtbl_size); for (i = 0; i < ubi->vtbl_slots; i++) memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); -- cgit v1.2.3 From d19d7b46d2b4936be14cfeef779ffeb76cf7b757 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Wed, 3 Nov 2010 12:55:20 +0200 Subject: mtd: onenand: fix omap2 code to handle cache program feature Some fixes are introduced into omap2 code to handle errors when cache program feature is used. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/omap2.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 9f322f1a7f22..da25a90af4a4 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -108,8 +108,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl, static int omap2_onenand_wait(struct mtd_info *mtd, int state) { struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); + struct onenand_chip *this = mtd->priv; unsigned int intr = 0; - unsigned int ctrl; + unsigned int ctrl, ctrl_mask; unsigned long timeout; u32 syscfg; @@ -180,7 +181,8 @@ retry: if (result == 0) { /* Timeout after 20ms */ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ONGO) { + if (ctrl & ONENAND_CTRL_ONGO && + !this->ongoing) { /* * The operation seems to be still going * so give it some more time. @@ -269,7 +271,11 @@ retry: return -EIO; } - if (ctrl & 0xFE9F) + ctrl_mask = 0xFE9F; + if (this->ongoing) + ctrl_mask &= ~0x8000; + + if (ctrl & ctrl_mask) wait_warn("unexpected controller status", state, ctrl, intr); return 0; -- cgit v1.2.3 From ac80dac00f8630803dc0c7f8fbe6983a8e2a8b5f Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Wed, 3 Nov 2010 12:55:21 +0200 Subject: mtd: onenand: implement cache program feature for 4KiB page onenand Implement cache program feature for 4KiB page onenand. This feature improves the write data performance. The observed 128KiB data program speed change is from 8827KiB/s to 14156 KiB/s when the feature is enabled. Signed-off-by: Roman Tereshonkov Acked-by: Mike Frysinger Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 6b3a875647c9..4d6e6c54cc2c 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1845,7 +1845,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, const u_char *buf = ops->datbuf; const u_char *oob = ops->oobbuf; u_char *oobbuf; - int ret = 0; + int ret = 0, cmd; DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", __func__, (unsigned int) to, (int) len); @@ -1954,7 +1954,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ONENAND_SET_NEXT_BUFFERRAM(this); } - this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); + this->ongoing = 0; + cmd = ONENAND_CMD_PROG; + + /* Exclude 1st OTP and OTP blocks for cache program feature */ + if (ONENAND_IS_CACHE_PROGRAM(this) && + likely(onenand_block(this, to) != 0) && + ONENAND_IS_4KB_PAGE(this) && + ((written + thislen) < len)) { + cmd = ONENAND_CMD_2X_CACHE_PROG; + this->ongoing = 1; + } + + this->command(mtd, cmd, to, mtd->writesize); /* * 2 PLANE, MLC, and Flex-OneNAND wait here @@ -3377,8 +3389,10 @@ static void onenand_check_features(struct mtd_info *mtd) case ONENAND_DEVICE_DENSITY_4Gb: if (ONENAND_IS_DDP(this)) this->options |= ONENAND_HAS_2PLANE; - else if (numbufs == 1) + else if (numbufs == 1) { this->options |= ONENAND_HAS_4KB_PAGE; + this->options |= ONENAND_HAS_CACHE_PROGRAM; + } case ONENAND_DEVICE_DENSITY_2Gb: /* 2Gb DDP does not have 2 plane */ @@ -3415,6 +3429,8 @@ static void onenand_check_features(struct mtd_info *mtd) printk(KERN_DEBUG "Chip has 2 plane\n"); if (this->options & ONENAND_HAS_4KB_PAGE) printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); + if (this->options & ONENAND_HAS_CACHE_PROGRAM) + printk(KERN_DEBUG "Chip has cache program feature\n"); } /** -- cgit v1.2.3 From a0c5a3944ce121bb2417c771f77b18485cd84e18 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sat, 6 Nov 2010 17:41:24 +0300 Subject: mtd: mtdchar: fix information leak to userland Structure mtd_info_user is copied to userland with padding byted between "type" and "flags" fields uninitialized. It leads to leaking of contents of kernel stack memory. Signed-off-by: Vasiliy Kulikov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdchar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 4759d827e8c7..cad8fcc7b239 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -601,6 +601,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } case MEMGETINFO: + memset(&info, 0, sizeof(info)); info.type = mtd->type; info.flags = mtd->flags; info.size = mtd->size; @@ -609,7 +610,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) info.oobsize = mtd->oobsize; /* The below fields are obsolete */ info.ecctype = -1; - info.eccsize = 0; if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) return -EFAULT; break; -- cgit v1.2.3 From ce4a37f7c93e9b12ac1452bedd823d73c43c0e63 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 Nov 2010 00:09:02 +0100 Subject: mtd: remove unnecessary casts of void ptr returning alloc function return values The [vk][cmz]alloc(_node) family of functions return void pointers which it's completely unnecessary/pointless to cast to other pointer types since that happens implicitly. This patch removes such casts from drivers/mtd/ Signed-off-by: Jesper Juhl Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/tqm8xxl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 60146984f4be..c08e140d40ed 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -139,7 +139,7 @@ static int __init init_tqm_mtd(void) goto error_mem; } - map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); + map_banks[idx]->name = kmalloc(16, GFP_KERNEL); if (!map_banks[idx]->name) { ret = -ENOMEM; -- cgit v1.2.3 From a338adafed0d09d823169161e938b1eab4dce901 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 11 Nov 2010 19:02:47 +0100 Subject: mtd: NAND: jz4740: Make 'struct platform_driver jz_nand_driver' static Signed-off-by: Lars-Peter Clausen Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/jz4740_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 67343fc31bd5..c9e2a59fd640 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -489,7 +489,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev) return 0; } -struct platform_driver jz_nand_driver = { +static struct platform_driver jz_nand_driver = { .probe = jz_nand_probe, .remove = __devexit_p(jz_nand_remove), .driver = { -- cgit v1.2.3 From 9118ea321ee320e3c670540122857ff0eba91e32 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 11 Nov 2010 19:02:48 +0100 Subject: mtd: NAND: jz4740: Remove custom {read,write}_page handlers Now that the mtd core supports more then 64 ecc bytes we can use it instead of some a custom hack in the jz4740 nand driver. This patch removes the custom {read,write}_page handlers from the jz4740 nand driver. Thus the driver will now fallback to the default handlers from the nand core. Signed-off-by: Lars-Peter Clausen Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/jz4740_nand.c | 55 ------------------------------------------ 1 file changed, 55 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index c9e2a59fd640..cea38a5d4ac5 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -251,58 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, return 0; } - -/* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos - * handling. The ecc area is for 4k chips 72 bytes long and thus does not fit - * into the eccpos array. */ -static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - unsigned int ecc_offset = chip->page_shift; - - /* Read the OOB area first */ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - - stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */ -static void jz_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - const uint8_t *p = buf; - unsigned int ecc_offset = chip->page_shift; - - for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &chip->oob_poi[i]); - } - - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); -} - #ifdef CONFIG_MTD_CMDLINE_PARTS static const char *part_probes[] = {"cmdline", NULL}; #endif @@ -393,9 +341,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->ecc.size = 512; chip->ecc.bytes = 9; - chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first; - chip->ecc.write_page = jz_nand_write_page_hwecc; - if (pdata) chip->ecc.layout = pdata->ecc_layout; -- cgit v1.2.3 From f9a5279c70af10e967872e922b91310a91f87b05 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 12 Nov 2010 13:37:57 -0800 Subject: mtd: maps: Use printf extension %pR for struct resource Using %pR standardizes the struct resource output. Signed-off-by: Joe Perches Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/amd76xrom.c | 7 ++----- drivers/mtd/maps/ck804xrom.c | 7 ++----- drivers/mtd/maps/esb2rom.c | 9 +++------ drivers/mtd/maps/ichxrom.c | 9 +++------ drivers/mtd/maps/physmap_of.c | 4 +--- drivers/mtd/maps/scx200_docflash.c | 5 ++--- 6 files changed, 13 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 19fe92db0c46..77d64ce19e9f 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -149,11 +149,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; printk(KERN_ERR MOD_NAME - " %s(): Unable to register resource" - " 0x%.16llx-0x%.16llx - kernel bug?\n", - __func__, - (unsigned long long)window->rsrc.start, - (unsigned long long)window->rsrc.end); + " %s(): Unable to register resource %pR - kernel bug?\n", + __func__, &window->rsrc); } diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index ddb462bea9b5..5fdb7b26cea3 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -178,11 +178,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; printk(KERN_ERR MOD_NAME - " %s(): Unable to register resource" - " 0x%.016llx-0x%.016llx - kernel bug?\n", - __func__, - (unsigned long long)window->rsrc.start, - (unsigned long long)window->rsrc.end); + " %s(): Unable to register resource %pR - kernel bug?\n", + __func__, &window->rsrc); } diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index d12c93dc1aad..4feb7507ab7c 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -242,12 +242,9 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; - printk(KERN_DEBUG MOD_NAME - ": %s(): Unable to register resource" - " 0x%.08llx-0x%.08llx - kernel bug?\n", - __func__, - (unsigned long long)window->rsrc.start, - (unsigned long long)window->rsrc.end); + printk(KERN_DEBUG MOD_NAME ": " + "%s(): Unable to register resource %pR - kernel bug?\n", + __func__, &window->rsrc); } /* Map the firmware hub into my address space. */ diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index f102bf243a74..1337a4191a0c 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -175,12 +175,9 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; - printk(KERN_DEBUG MOD_NAME - ": %s(): Unable to register resource" - " 0x%.16llx-0x%.16llx - kernel bug?\n", - __func__, - (unsigned long long)window->rsrc.start, - (unsigned long long)window->rsrc.end); + printk(KERN_DEBUG MOD_NAME ": " + "%s(): Unable to register resource %pR - kernel bug?\n", + __func__, &window->rsrc); } /* Map the firmware hub into my address space. */ diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 9861814aa027..8506578e6a35 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -274,9 +274,7 @@ static int __devinit of_flash_probe(struct platform_device *dev, continue; } - dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", - (unsigned long long)res.start, - (unsigned long long)res.end); + dev_dbg(&dev->dev, "of_flash device: %pR\n", &res); err = -EBUSY; res_size = resource_size(&res); diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index b5391ebb736e..027e628a4f1d 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c @@ -166,9 +166,8 @@ static int __init init_scx200_docflash(void) outl(pmr, scx200_cb_base + SCx200_PMR); } - printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n", - (unsigned long long)docmem.start, - (unsigned long long)docmem.end, width); + printk(KERN_INFO NAME ": DOCCS mapped at %pR, width %d\n", + &docmem, width); scx200_docflash_map.size = size; if (width == 8) -- cgit v1.2.3 From 23079f94daabc4e06436ab2b643fac31dec017d1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 12 Nov 2010 13:37:58 -0800 Subject: mtd: nand: Use printf extension %pR for struct resource Using %pR standardizes the struct resource output. Signed-off-by: Joe Perches Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/pasemi_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 6ddb2461d740..bb277a54986f 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -107,7 +107,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev, if (pasemi_nand_mtd) return -ENODEV; - pr_debug("pasemi_nand at %llx-%llx\n", res.start, res.end); + pr_debug("pasemi_nand at %pR\n", &res); /* Allocate memory for MTD device structure and private data */ pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + -- cgit v1.2.3 From cc31822250236ec173bb2aa149ebe2ba35405db2 Mon Sep 17 00:00:00 2001 From: Guillaume LECERF Date: Wed, 17 Nov 2010 12:35:50 +0100 Subject: mtd: cfi_fixup: remove unused 'param' parameter The 'param' parameter has never been used since its introduction, so simply remove it. Signed-off-by: Guillaume LECERF Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 54 ++++++++++----------- drivers/mtd/chips/cfi_cmdset_0002.c | 94 ++++++++++++++++++------------------- drivers/mtd/chips/cfi_util.c | 2 +- drivers/mtd/chips/fwh_lock.h | 2 +- include/linux/mtd/cfi.h | 3 +- 5 files changed, 77 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index ad9268b44416..44cbfc093ecc 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -162,7 +162,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) #endif /* Atmel chips don't use the same PRI format as Intel chips */ -static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) +static void fixup_convert_atmel_pri(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -202,7 +202,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) cfi->cfiq->BufWriteTimeoutMax = 0; } -static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) +static void fixup_at49bv640dx_lock(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -214,7 +214,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ -static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) +static void fixup_intel_strataflash(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -227,7 +227,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) #endif #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND -static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) +static void fixup_no_write_suspend(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -240,7 +240,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) } #endif -static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) +static void fixup_st_m28w320ct(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -249,7 +249,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ } -static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) +static void fixup_st_m28w320cb(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -259,7 +259,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; }; -static void fixup_use_point(struct mtd_info *mtd, void *param) +static void fixup_use_point(struct mtd_info *mtd) { struct map_info *map = mtd->priv; if (!mtd->point && map_is_linear(map)) { @@ -268,7 +268,7 @@ static void fixup_use_point(struct mtd_info *mtd, void *param) } } -static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) +static void fixup_use_write_buffers(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -282,7 +282,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) /* * Some chips power-up with all sectors locked by default. */ -static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) +static void fixup_unlock_powerup_lock(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -295,31 +295,31 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) } static struct cfi_fixup cfi_fixup_table[] = { - { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, - { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL }, - { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL }, + { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, + { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock }, + { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock }, #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash }, #endif #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND - { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend }, #endif #if !FORCE_WORD_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif - { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, - { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, - { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, }, - { 0, 0, NULL, NULL } + { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct }, + { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb }, + { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock }, + { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = { - { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, - { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, - { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, - { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock, NULL, }, - { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock, NULL, }, - { 0, 0, NULL, NULL } + { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock }, + { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock }, + { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock }, + { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock }, + { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock }, + { 0, 0, NULL } }; static struct cfi_fixup fixup_table[] = { /* The CFI vendor ids and the JEDEC vendor IDs appear @@ -327,8 +327,8 @@ static struct cfi_fixup fixup_table[] = { * well. This table is to pick all cases where * we know that is the case. */ - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL }, - { 0, 0, NULL, NULL } + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point }, + { 0, 0, NULL } }; static void cfi_fixup_major_minor(struct cfi_private *cfi, diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 3b8e32d87977..9d68ab919f31 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -134,7 +134,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) #ifdef AMD_BOOTLOC_BUG /* Wheee. Bring me the head of someone at AMD. */ -static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) +static void fixup_amd_bootblock(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -186,7 +186,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) } #endif -static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) +static void fixup_use_write_buffers(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -197,7 +197,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) } /* Atmel chips don't use the same PRI format as AMD chips */ -static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) +static void fixup_convert_atmel_pri(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -228,14 +228,14 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) cfi->cfiq->BufWriteTimeoutMax = 0; } -static void fixup_use_secsi(struct mtd_info *mtd, void *param) +static void fixup_use_secsi(struct mtd_info *mtd) { /* Setup for chips with a secsi area */ mtd->read_user_prot_reg = cfi_amdstd_secsi_read; mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; } -static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) +static void fixup_use_erase_chip(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -250,7 +250,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors * locked by default. */ -static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) +static void fixup_use_atmel_lock(struct mtd_info *mtd) { mtd->lock = cfi_atmel_lock; mtd->unlock = cfi_atmel_unlock; @@ -271,7 +271,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd) cfi->cfiq->NumEraseRegions = 1; } -static void fixup_sst39vf(struct mtd_info *mtd, void *param) +static void fixup_sst39vf(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -282,7 +282,7 @@ static void fixup_sst39vf(struct mtd_info *mtd, void *param) cfi->addr_unlock2 = 0x2AAA; } -static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) +static void fixup_sst39vf_rev_b(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -295,12 +295,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) cfi->sector_erase_cmd = CMD(0x50); } -static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) +static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - fixup_sst39vf_rev_b(mtd, param); + fixup_sst39vf_rev_b(mtd); /* * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where @@ -310,7 +310,7 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); } -static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) +static void fixup_s29gl064n_sectors(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -321,7 +321,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) } } -static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) +static void fixup_s29gl032n_sectors(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -334,47 +334,47 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) /* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { - { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ - { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ - { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ - { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ - { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ - { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ - { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ - { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ - { 0, 0, NULL, NULL } + { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ + { CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */ + { CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */ + { CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */ + { CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */ + { CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */ + { CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */ + { CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */ + { 0, 0, NULL } }; static struct cfi_fixup cfi_fixup_table[] = { - { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, + { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, #ifdef AMD_BOOTLOC_BUG - { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, - { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL }, + { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, + { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, #endif - { CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, }, - { CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, }, - { CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, }, - { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, - { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, - { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, - { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, }, - { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, - { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, - { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, - { CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ - { CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ - { CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ - { CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ + { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, + { CFI_MFR_AMD, 0x0053, fixup_use_secsi }, + { CFI_MFR_AMD, 0x0055, fixup_use_secsi }, + { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, + { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, + { CFI_MFR_AMD, 0x005F, fixup_use_secsi }, + { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors }, + { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, + { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, + { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, + { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ + { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ + { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ + { CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */ #if !FORCE_WORD_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif - { 0, 0, NULL, NULL } + { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = { - { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, - { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock, NULL, }, - { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, - { 0, 0, NULL, NULL } + { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock }, + { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock }, + { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock }, + { 0, 0, NULL } }; static struct cfi_fixup fixup_table[] = { @@ -383,9 +383,9 @@ static struct cfi_fixup fixup_table[] = { * well. This table is to pick all cases where * we know that is the case. */ - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, - { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, - { 0, 0, NULL, NULL } + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip }, + { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock }, + { 0, 0, NULL } }; diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 360525c637d2..6ae3d111e1e7 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -156,7 +156,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups) for (f=fixups; f->fixup; f++) { if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { - f->fixup(mtd, f->param); + f->fixup(mtd); } } } diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index d18064977192..5e3cc80128aa 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -98,7 +98,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) return ret; } -static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param) +static void fixup_use_fwh_lock(struct mtd_info *mtd) { printk(KERN_NOTICE "using fwh lock/unlock method\n"); /* Setup for the chips with the fwh lock method */ diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 4dd0c2cd7659..a9baee6864af 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -527,8 +527,7 @@ struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t s struct cfi_fixup { uint16_t mfr; uint16_t id; - void (*fixup)(struct mtd_info *mtd, void* param); - void* param; + void (*fixup)(struct mtd_info *mtd); }; #define CFI_MFR_ANY 0xFFFF -- cgit v1.2.3 From 1534b8b09757190ce6e97fa97f9ad77c49082cd8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 15:02:21 -0800 Subject: mtd: fix nand kernel-doc warnings Warning(include/linux/mtd/nand.h:543): No description found for parameter 'badblockbits' Warning(drivers/mtd/nand/nand_bbt.c:1101): No description found for parameter 'mtd' Signed-off-by: Randy Dunlap Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 3 ++- include/linux/mtd/nand.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 586b981f0e61..6ebd869993aa 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1092,7 +1092,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * verify_bbt_descr - verify the bad block description - * @bd: the table to verify + * @mtd: MTD device structure + * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 63e17d01fde9..1f489b247a29 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -448,6 +448,8 @@ struct nand_buffers { * See the defines for further explanation. * @badblockpos: [INTERN] position of the bad block marker in the oob * area. + * @badblockbits: [INTERN] number of bits to left-shift the bad block + * number * @cellinfo: [INTERN] MLC/multichip data from chip ident * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays -- cgit v1.2.3 From e14feafbe0d5c6d64bb6fe4eba928cb57ac9a4c8 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Fri, 19 Nov 2010 16:40:45 +0800 Subject: mtd: nand: add check for out of page read When run mtd_oobtest case, there will be one error for step(4), which turned out it need add one check for out of page read in nand_do_read_oob just like mtd_do_write_oob did it already. This commit also fix one typo error for comments in mtd_do_write_oob Signed-off-by: Jason Liu Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1f75a1b1f7c3..75d199e4f25b 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1782,6 +1782,13 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, else len = mtd->oobsize; + /* Do not allow read past end of page */ + if ((ops->ooboffs + readlen) > len) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to read " + "past end of page\n", __func__); + return -EINVAL; + } + if (unlikely(ops->ooboffs >= len)) { DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " "outside oob\n", __func__); @@ -2377,7 +2384,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; } - /* Do not allow reads past end of device */ + /* Do not allow write past end of device */ if (unlikely(to >= mtd->size || ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - -- cgit v1.2.3 From a7e93dcd9aacb3ef4acfcc4310577f3ae0741821 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Tue, 23 Nov 2010 14:17:17 +0200 Subject: mtd: fix master device identification for mtd repartition Function mtd_has_master renamed as mtd_is_partition to follow the function logic. The patch fixes the problem of checking the right mtd device for partition creation. To delete partition checking is not needed here so as it is done in mtd_del_partition. By master we consider the mtd device which does not belong to any partition. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdchar.c | 8 ++++---- drivers/mtd/mtdpart.c | 10 +++++----- include/linux/mtd/partitions.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index cad8fcc7b239..16de17b5b829 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -522,10 +522,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - /* Only master mtd device must be used to control partitions */ - if (!mtd_is_master(mtd)) - return -EINVAL; - if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) return -EFAULT; @@ -535,6 +531,10 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, switch (a.op) { case BLKPG_ADD_PARTITION: + /* Only master mtd device must be used to add partitions */ + if (mtd_is_partition(mtd)) + return -EINVAL; + return mtd_add_partition(mtd, p.devname, p.start, p.length); case BLKPG_DEL_PARTITION: diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 79e3689f1e16..1047ff0a4f55 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -720,19 +720,19 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } EXPORT_SYMBOL_GPL(parse_mtd_partitions); -int mtd_is_master(struct mtd_info *mtd) +int mtd_is_partition(struct mtd_info *mtd) { struct mtd_part *part; - int nopart = 0; + int ispart = 0; mutex_lock(&mtd_partitions_mutex); list_for_each_entry(part, &mtd_partitions, list) if (&part->mtd == mtd) { - nopart = 1; + ispart = 1; break; } mutex_unlock(&mtd_partitions_mutex); - return nopart; + return ispart; } -EXPORT_SYMBOL_GPL(mtd_is_master); +EXPORT_SYMBOL_GPL(mtd_is_partition); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 2b54316591d2..4a0a8ba90a72 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -89,7 +89,7 @@ static inline int mtd_has_cmdlinepart(void) { return 1; } static inline int mtd_has_cmdlinepart(void) { return 0; } #endif -int mtd_is_master(struct mtd_info *mtd); +int mtd_is_partition(struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, char *name, long long offset, long long length); int mtd_del_partition(struct mtd_info *master, int partno); -- cgit v1.2.3 From eeda667a29698b9a4d16dce8979afc6f512f3c42 Mon Sep 17 00:00:00 2001 From: "Sergej.Stepanov@ids.de" Date: Tue, 23 Nov 2010 18:38:36 +0100 Subject: mtd: fsl_elbc_nand: fix jffs2 problem after NAND-flash image record in u-boot This patch should fix the following problem: 1. the jffs2-image update in the u-boot was ok 2. first restart and first mount of the NAND-flash-partition was also ok 3. before the restart of controller there are no any activity on NAND-flash except of the jffs2_gcd_mtdX-process ... 4. BUT after the second restart the NAND-flash-partition could not be really used after the second mount, dmesg filled with messages: ... jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x03ce0000: 0xc0ff instead jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x03d00000: 0xc0ff instead .... Just for for info: the behaviour observed on mpc8313-based board with the large-page NAND. The only activity on NAND-flash was the garbage collector process, that looks for CLEANMARKER-nodes As Scott said it was broken by commit 3ab8f2a2e7011c5e83363b42950757e46ef06824 Signed-off-by: Sergej Stepanov -- Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index c141b07b25d1..7a13d42cbabd 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -388,6 +388,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, "page_addr: 0x%x, column: 0x%x.\n", page_addr, column); + elbc_fcm_ctrl->column = column; + elbc_fcm_ctrl->oob = 0; elbc_fcm_ctrl->use_mdr = 1; fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | -- cgit v1.2.3 From 2ebf0622cdc5d2b51f22b68a0983d90df8a976c8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 23 Nov 2010 17:02:13 -0200 Subject: mtd: mxc_nand: Fix warning on nr_parts unused variable If CONFIG_MTD_PARTITIONS is not selected, then the following warning is generated: CC drivers/mtd/nand/mxc_nand.o drivers/mtd/nand/mxc_nand.c: In function 'mxcnd_probe': drivers/mtd/nand/mxc_nand.c:1014: warning: unused variable 'nr_parts' Fix it by marking nr_parts as __maybe_unused. Signed-off-by: Fabio Estevam Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 214b03afdd48..ef932ba55a0b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1009,7 +1009,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; - int err = 0, nr_parts = 0; + int err = 0, __maybe_unused nr_parts = 0; struct nand_ecclayout *oob_smallpage, *oob_largepage; /* Allocate memory for MTD device structure and private data */ -- cgit v1.2.3 From 6b2995b62eba81df0f7d0b4be5b782be623c13eb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 26 Nov 2010 14:31:44 -0200 Subject: mtd: fix section mismatch on sst25l MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building the kernel with 'make CONFIG_DEBUG_SECTION_MISMATCH=y´ resulted in: WARNING: vmlinux.o(.data+0x15938): Section mismatch in reference from the variable sst25l_driver to the function .init.text:sst25l_probe() The variable sst25l_driver references the function __init sst25l_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console, Fix the section mismatch. Signed-off-by: Fabio Estevam Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/sst25l.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 684247a8a5ed..c163e619abc9 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -335,7 +335,7 @@ out: return ret; } -static struct flash_info *__init sst25l_match_device(struct spi_device *spi) +static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) { struct flash_info *flash_info = NULL; struct spi_message m; @@ -375,7 +375,7 @@ static struct flash_info *__init sst25l_match_device(struct spi_device *spi) return flash_info; } -static int __init sst25l_probe(struct spi_device *spi) +static int __devinit sst25l_probe(struct spi_device *spi) { struct flash_info *flash_info; struct sst25l_flash *flash; -- cgit v1.2.3 From 4ad916bca7c372110815e77c2db95fb2eb2f8ab3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 29 Nov 2010 13:52:06 +0100 Subject: mtd: FSMC NAND remove PARTITION macro and fix compile noise This removes the PARTITION macro that David didn't like and also removes a local variable that was dangling unused in some #ifdefs by being a bit more clever. Signed-off-by: Linus Walleij Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 66 ++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 02edfba25b0c..5af4b3c122f5 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -119,21 +119,36 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { } }; -/* - * Default partition tables to be used if the partition information not - * provided through platform data - */ -#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz} +#ifdef CONFIG_MTD_PARTITIONS /* + * Default partition tables to be used if the partition information not + * provided through platform data. + * * Default partition layout for small page(= 512 bytes) devices * Size for "Root file system" is updated in driver based on actual device size */ static struct mtd_partition partition_info_16KB_blk[] = { - PARTITION("X-loader", 0, 4 * 0x4000), - PARTITION("U-Boot", 0x10000, 20 * 0x4000), - PARTITION("Kernel", 0x60000, 256 * 0x4000), - PARTITION("Root File System", 0x460000, 0), + { + .name = "X-loader", + .offset = 0, + .size = 4*0x4000, + }, + { + .name = "U-Boot", + .offset = 0x10000, + .size = 20*0x4000, + }, + { + .name = "Kernel", + .offset = 0x60000, + .size = 256*0x4000, + }, + { + .name = "Root File System", + .offset = 0x460000, + .size = 0, + }, }; /* @@ -141,15 +156,32 @@ static struct mtd_partition partition_info_16KB_blk[] = { * Size for "Root file system" is updated in driver based on actual device size */ static struct mtd_partition partition_info_128KB_blk[] = { - PARTITION("X-loader", 0, 4 * 0x20000), - PARTITION("U-Boot", 0x80000, 12 * 0x20000), - PARTITION("Kernel", 0x200000, 48 * 0x20000), - PARTITION("Root File System", 0x800000, 0), + { + .name = "X-loader", + .offset = 0, + .size = 4*0x20000, + }, + { + .name = "U-Boot", + .offset = 0x80000, + .size = 12*0x20000, + }, + { + .name = "Kernel", + .offset = 0x200000, + .size = 48*0x20000, + }, + { + .name = "Root File System", + .offset = 0x800000, + .size = 0, + }, }; #ifdef CONFIG_MTD_CMDLINE_PARTS const char *part_probes[] = { "cmdlinepart", NULL }; #endif +#endif /** * struct fsmc_nand_data - atructure for FSMC NAND device state @@ -508,7 +540,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) struct nand_chip *nand; struct fsmc_regs *regs; struct resource *res; - int nr_parts, ret = 0; + int ret = 0; if (!pdata) { dev_err(&pdev->dev, "platform data is NULL\n"); @@ -676,11 +708,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * Check if partition info passed via command line */ host->mtd.name = "nand"; - nr_parts = parse_mtd_partitions(&host->mtd, part_probes, + host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, &host->partitions, 0); - if (nr_parts > 0) { - host->nr_partitions = nr_parts; - } else { + if (host->nr_partitions <= 0) { #endif /* * Check if partition info passed via command line -- cgit v1.2.3 From 593cd8711221c9661dbf9beb2fb42fecca03e693 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 29 Nov 2010 13:52:19 +0100 Subject: mtd: FSMC NAND use the PrimeCell identifier macros The FSMC actually has a standard ARM PrimeCell ID register, and the "revision" part of that register contains the thing that the code is looking at. Reuse the infrastructure from the AMBA bus abstraction and rid local defines. Signed-off-by: Linus Walleij Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsmc_nand.c | 23 ++++++++++++++++++++--- include/linux/mtd/fsmc.h | 19 ------------------- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 5af4b3c122f5..205b10b9f9b9 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static struct nand_ecclayout fsmc_ecc1_layout = { @@ -184,8 +185,9 @@ const char *part_probes[] = { "cmdlinepart", NULL }; #endif /** - * struct fsmc_nand_data - atructure for FSMC NAND device state + * struct fsmc_nand_data - structure for FSMC NAND device state * + * @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. * @partitions: Partition info for a NAND Flash. @@ -201,6 +203,7 @@ const char *part_probes[] = { "cmdlinepart", NULL }; * @regs_va: FSMC regs base address. */ struct fsmc_nand_data { + u32 pid; struct mtd_info mtd; struct nand_chip nand; struct mtd_partition *partitions; @@ -541,6 +544,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) struct fsmc_regs *regs; struct resource *res; int ret = 0; + u32 pid; + int i; if (!pdata) { dev_err(&pdev->dev, "platform data is NULL\n"); @@ -630,6 +635,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (ret) goto err_probe1; + /* + * This device ID is actually a common AMBA ID as used on the + * AMBA PrimeCell bus. However it is not a PrimeCell. + */ + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8); + host->pid = pid; + dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, " + "revision %02x, config %02x\n", + AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid), + AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); + host->bank = pdata->bank; host->select_chip = pdata->select_bank; regs = host->regs_va; @@ -657,7 +674,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); - if (get_fsmc_version(host->regs_va) == FSMC_VER8) { + if (AMBA_REV_BITS(host->pid) >= 8) { nand->ecc.read_page = fsmc_read_page_hwecc; nand->ecc.calculate = fsmc_read_hwecc_ecc4; nand->ecc.correct = fsmc_correct_data; @@ -677,7 +694,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) goto err_probe; } - if (get_fsmc_version(host->regs_va) == FSMC_VER8) { + if (AMBA_REV_BITS(host->pid) >= 8) { if (host->mtd.writesize == 512) { nand->ecc.layout = &fsmc_ecc4_sp_layout; host->ecc_place = &fsmc_ecc4_sp_place; diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index e210b87e6cd6..96e8e67a053e 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -115,25 +115,6 @@ struct fsmc_regs { #define FSMC_THOLD_4 (4 << 16) #define FSMC_THIZ_1 (1 << 24) -/* peripid2 register definitions */ -#define FSMC_REVISION_MSK (0xf) -#define FSMC_REVISION_SHFT (0x4) - -#define FSMC_VER1 1 -#define FSMC_VER2 2 -#define FSMC_VER3 3 -#define FSMC_VER4 4 -#define FSMC_VER5 5 -#define FSMC_VER6 6 -#define FSMC_VER7 7 -#define FSMC_VER8 8 - -static inline uint32_t get_fsmc_version(struct fsmc_regs *regs) -{ - return (readl(®s->peripid2) >> FSMC_REVISION_SHFT) & - FSMC_REVISION_MSK; -} - /* * There are 13 bytes of ecc for every 512 byte block in FSMC version 8 * and it has to be read consecutively and immediately after the 512 -- cgit v1.2.3 From 8a8f632d8534d0c403831341450bd8db9e842f05 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 2 Dec 2010 09:24:16 +0900 Subject: mtd: OneNAND: Fix 4KiB pagesize OOB handling Original 4KiB pagesize chip (SLC) doesn't support OOB operations at Spec. And it's also same at Flex-OneNAND. Remove the MLC macro if possible and use 4KiB pagesize macro since MLC has 4KiB pagesize. Signed-off-by: Kyungmin Park Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 4d6e6c54cc2c..c38bf9c54a11 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -400,8 +400,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); - if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) || - ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) /* It is always BufferRAM0 */ ONENAND_SET_BUFFERRAM0(this); else @@ -430,7 +429,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le case FLEXONENAND_CMD_RECOVER_LSB: case ONENAND_CMD_READ: case ONENAND_CMD_READOOB: - if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_4KB_PAGE(this)) /* It is always BufferRAM0 */ dataram = ONENAND_SET_BUFFERRAM0(this); else @@ -1353,7 +1352,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, stats = mtd->ecc_stats; - readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; while (read < len) { cond_resched(); @@ -1429,7 +1428,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, int ret; onenand_get_device(mtd, FL_READING); - ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? + ret = ONENAND_IS_4KB_PAGE(this) ? onenand_mlc_read_ops_nolock(mtd, from, &ops) : onenand_read_ops_nolock(mtd, from, &ops); onenand_release_device(mtd); @@ -1464,7 +1463,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, onenand_get_device(mtd, FL_READING); if (ops->datbuf) - ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? + ret = ONENAND_IS_4KB_PAGE(this) ? onenand_mlc_read_ops_nolock(mtd, from, ops) : onenand_read_ops_nolock(mtd, from, ops); else @@ -1558,7 +1557,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, column = from & (mtd->oobsize - 1); - readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; while (read < len) { cond_resched(); @@ -1612,7 +1611,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to u_char *oob_buf = this->oob_buf; int status, i, readcmd; - readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; this->command(mtd, readcmd, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); @@ -2079,7 +2078,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, oobbuf = this->oob_buf; - oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; + oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; /* Loop until all data write */ while (written < len) { @@ -2098,7 +2097,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, memcpy(oobbuf + column, buf, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); - if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) { + if (ONENAND_IS_4KB_PAGE(this)) { /* Set main area of DataRAM to 0xff*/ memset(this->page_buf, 0xff, mtd->writesize); this->write_bufferram(mtd, ONENAND_DATARAM, @@ -3041,7 +3040,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? + ret = ONENAND_IS_4KB_PAGE(this) ? onenand_mlc_read_ops_nolock(mtd, from, &ops) : onenand_read_ops_nolock(mtd, from, &ops); @@ -3413,7 +3412,11 @@ static void onenand_check_features(struct mtd_info *mtd) break; } - if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) + /* The MLC has 4KiB pagesize. */ + if (ONENAND_IS_MLC(this)) + this->options |= ONENAND_HAS_4KB_PAGE; + + if (ONENAND_IS_4KB_PAGE(this)) this->options &= ~ONENAND_HAS_2PLANE; if (FLEXONENAND(this)) { @@ -3847,7 +3850,7 @@ static int onenand_probe(struct mtd_info *mtd) /* The data buffer size is equal to page size */ mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); /* We use the full BufferRAM */ - if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_4KB_PAGE(this)) mtd->writesize <<= 1; mtd->oobsize = mtd->writesize >> 5; -- cgit v1.2.3 From 01039e4e63a8ea0d66fcfc71d7b99769bbbed9d6 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Thu, 2 Dec 2010 15:28:38 +0200 Subject: mtd: onenand: bugfix for 2x mode bad block handling This bug becomes visible in 2x mode when chip->writesize is different from mtd->writesize (= 2 * chip->writesize). At this case the bad block information is read from the first and the third physical pages instead of the first and the second as specification states. Signed-off-by: Roman Tereshonkov Acked-by: Kyungmin Park Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_bbt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 01ab5b3c453b..905209bf9465 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -91,13 +91,15 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (j = 0; j < len; j++) { /* No need to read pages fully, * just read required OOB bytes */ - ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops); + ret = onenand_bbt_read_oob(mtd, + from + j * this->writesize + bd->offs, &ops); /* If it is a initial bad block, just ignore it */ if (ret == ONENAND_BBT_READ_FATAL_ERROR) return -EIO; - if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { + if (ret || check_short_pattern(&buf[j * scanlen], + scanlen, this->writesize, bd)) { bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); -- cgit v1.2.3 From 4ccb3b4497ce01fab4933704fe21581e30fda1a5 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 3 Dec 2010 16:36:34 +0000 Subject: mtd: nand: Fix integer overflow in ONFI detection of chips >= 4GiB Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 75d199e4f25b..33550c43acc2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2894,7 +2894,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, mtd->writesize = le32_to_cpu(p->byte_per_page); mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; + chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; busw = 0; if (le16_to_cpu(p->features) & 1) busw = NAND_BUSWIDTH_16; -- cgit v1.2.3 From 1daa38d379932bde0d2036c2e10ced3e8842b74f Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 3 Dec 2010 09:05:08 +0000 Subject: staging/vme_user: fix usage of the slave resources after they've been freed buf_unalloc() frees the memory buffers allocated with vme_alloc_consistent. The associated VME resource is needed in both vme_alloc_consistent and vme_free_consistent; however the slave VME resources are being freed before the calls to vme_free_consistent are made, which means the buffers are never returned. Fix this by freeing the VME resources only after the consistent buffers have been returned. Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 36381489b797..dc7175bdfcf9 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -829,8 +829,8 @@ err_master: err_slave: while (i > SLAVE_MINOR) { i--; - vme_slave_free(image[i].resource); buf_unalloc(i); + vme_slave_free(image[i].resource); } err_class: cdev_del(vme_user_cdev); @@ -855,8 +855,8 @@ static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot) for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0); - vme_slave_free(image[i].resource); buf_unalloc(i); + vme_slave_free(image[i].resource); } /* Unregister device driver */ -- cgit v1.2.3 From 4740a0846069f6d4cbba9e328a9d92e6dd76110d Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 3 Dec 2010 13:44:15 +0000 Subject: staging/vme/vme_user: use __dev{init, exit} for .probe and .remove Signed-off-by: Emilio G. Cota [martyn.welch@ge.com: Fixed checkpatch line length warnings] Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index dc7175bdfcf9..db445ed164c6 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -135,8 +135,8 @@ static ssize_t vme_user_write(struct file *, const char __user *, size_t, static loff_t vme_user_llseek(struct file *, loff_t, int); static long vme_user_unlocked_ioctl(struct file *, unsigned int, unsigned long); -static int __init vme_user_probe(struct device *, int, int); -static int __exit vme_user_remove(struct device *, int, int); +static int __devinit vme_user_probe(struct device *, int, int); +static int __devexit vme_user_remove(struct device *, int, int); static struct file_operations vme_user_fops = { .open = vme_user_open, @@ -596,7 +596,7 @@ static void buf_unalloc(int num) static struct vme_driver vme_user_driver = { .name = driver_name, .probe = vme_user_probe, - .remove = vme_user_remove, + .remove = __devexit_p(vme_user_remove), }; @@ -666,7 +666,8 @@ err_nocard: * as practical. We will therefore reserve the buffers and request the images * here so that we don't have to do it later. */ -static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot) +static int __devinit vme_user_probe(struct device *dev, int cur_bus, + int cur_slot) { int i, err; char name[12]; @@ -841,7 +842,8 @@ err_dev: return err; } -static int __exit vme_user_remove(struct device *dev, int cur_bus, int cur_slot) +static int __devexit vme_user_remove(struct device *dev, int cur_bus, + int cur_slot) { int i; -- cgit v1.2.3 From b62c99b17c2c513eaf6b77a76907a13a1beb86d3 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Fri, 3 Dec 2010 14:20:51 +0000 Subject: staging/vme_user: add missing calls to vme_master_free calls in .remove Signed-off-by: Emilio G. Cota Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index db445ed164c6..a571173249cf 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -852,8 +852,10 @@ static int __devexit vme_user_remove(struct device *dev, int cur_bus, device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); class_destroy(vme_user_sysfs_class); - for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) + for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) { kfree(image[i].kern_buf); + vme_master_free(image[i].resource); + } for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { vme_slave_set(image[i].resource, 0, 0, 0, 0, VME_A32, 0); -- cgit v1.2.3 From 3d44661ad1f6336345a9f7765afef6d0aeac543e Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Wed, 1 Dec 2010 21:38:31 +0100 Subject: staging: brcm80211: added firmware validation Fix for https://bugzilla.kernel.org/show_bug.cgi?id=21872 New function wl_check_firmwares() checks validity of all firmware images loaded from user space. Signed-off-by: Roland Vossen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wl_mac80211.c | 54 ++++++++++++++++++++++++- drivers/staging/brcm80211/sys/wl_ucode.h | 4 ++ drivers/staging/brcm80211/sys/wl_ucode_loader.c | 4 ++ 3 files changed, 60 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 364b34986621..d41212bca633 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -1776,8 +1776,7 @@ static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) wl->fw.hdr_num_entries[i])); } wl->fw.fw_cnt = i; - wl_ucode_data_init(wl); - return 0; + return wl_ucode_data_init(wl); } void wl_ucode_free_buf(void *p) @@ -1793,3 +1792,54 @@ static void wl_release_fw(struct wl_info *wl) release_firmware(wl->fw.fw_hdr[i]); } } + + +/* + * checks validity of all firmware images loaded from user space + */ +int wl_check_firmwares(struct wl_info *wl) +{ + int i; + int entry; + int rc = 0; + const struct firmware *fw; + const struct firmware *fw_hdr; + struct wl_fw_hdr *ucode_hdr; + for (i = 0; i < WL_MAX_FW && rc == 0; i++) { + fw = wl->fw.fw_bin[i]; + fw_hdr = wl->fw.fw_hdr[i]; + if (fw == NULL && fw_hdr == NULL) { + break; + } else if (fw == NULL || fw_hdr == NULL) { + WL_ERROR(("%s: invalid bin/hdr fw\n", __func__)); + rc = -EBADF; + } else if (fw_hdr->size % sizeof(struct wl_fw_hdr)) { + WL_ERROR(("%s: non integral fw hdr file size %d/%d\n", + __func__, fw_hdr->size, + sizeof(struct wl_fw_hdr))); + rc = -EBADF; + } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { + WL_ERROR(("%s: out of bounds fw file size %d\n", + __func__, fw->size)); + rc = -EBADF; + } else { + /* check if ucode section overruns firmware image */ + ucode_hdr = (struct wl_fw_hdr *)fw_hdr->data; + for (entry = 0; entry < wl->fw.hdr_num_entries[i] && rc; + entry++, ucode_hdr++) { + if (ucode_hdr->offset + ucode_hdr->len > + fw->size) { + WL_ERROR(("%s: conflicting bin/hdr\n", + __func__)); + rc = -EBADF; + } + } + } + } + if (rc == 0 && wl->fw.fw_cnt != i) { + WL_ERROR(("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt)); + rc = -EBADF; + } + return rc; +} + diff --git a/drivers/staging/brcm80211/sys/wl_ucode.h b/drivers/staging/brcm80211/sys/wl_ucode.h index b797ab661195..2a0f4028f6f3 100644 --- a/drivers/staging/brcm80211/sys/wl_ucode.h +++ b/drivers/staging/brcm80211/sys/wl_ucode.h @@ -14,6 +14,9 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define MIN_FW_SIZE 40000 /* minimum firmware file size in bytes */ +#define MAX_FW_SIZE 150000 + typedef struct d11init { u16 addr; u16 size; @@ -43,3 +46,4 @@ extern int wl_ucode_init_buf(struct wl_info *wl, void **pbuf, unsigned int idx); extern int wl_ucode_init_uint(struct wl_info *wl, unsigned *data, unsigned int idx); extern void wl_ucode_free_buf(void *); +extern int wl_check_firmwares(struct wl_info *wl); diff --git a/drivers/staging/brcm80211/sys/wl_ucode_loader.c b/drivers/staging/brcm80211/sys/wl_ucode_loader.c index acd24726b0f0..23e10f3dec0d 100644 --- a/drivers/staging/brcm80211/sys/wl_ucode_loader.c +++ b/drivers/staging/brcm80211/sys/wl_ucode_loader.c @@ -39,6 +39,10 @@ u32 *bcm43xx_bomminor; int wl_ucode_data_init(struct wl_info *wl) { + int rc; + rc = wl_check_firmwares(wl); + if (rc < 0) + return rc; wl_ucode_init_buf(wl, (void **)&d11lcn0bsinitvals24, D11LCN0BSINITVALS24); wl_ucode_init_buf(wl, (void **)&d11lcn0initvals24, D11LCN0INITVALS24); -- cgit v1.2.3 From e2c8e425baa01a4c8e6ae1b90194ed3d3cde0c66 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Thu, 11 Nov 2010 20:16:29 +0800 Subject: fsldma: add support to 36-bit physical address Expand the dma_mask of fsldma device to 36-bit, indicating that the DMA engine can deal with 36-bit physical address and does not need the SWIOTLB to create bounce buffer for it when doing dma_map_*(). Signed-off-by: Li Yang Acked-by: Kumar Gala Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 286c3ac6bdcc..531230b87976 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1,7 +1,7 @@ /* * Freescale MPC85xx, MPC83xx DMA Engine support * - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved. * * Author: * Zhang Wei , Jul 2007 @@ -1322,6 +1322,8 @@ static int __devinit fsldma_of_probe(struct platform_device *op, fdev->common.device_control = fsl_dma_device_control; fdev->common.dev = &op->dev; + dma_set_mask(&(op->dev), DMA_BIT_MASK(36)); + dev_set_drvdata(&op->dev, fdev); /* -- cgit v1.2.3 From 0be035f3485379d812d617ee7eaa255cde97dbfa Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 2 Dec 2010 17:14:30 +0800 Subject: intel_mid_dma: add support for single item scatter-gather list Current driver's device_prep_slave_sg can't be used by DMAC2 even the sg list contains one item, this patch will enable DMAC2 to use this API. Signed-off-by: Feng Tang Acked-by: Vinod Koul Signed-off-by: Dan Williams --- drivers/dma/intel_mid_dma.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 41941d05bfb9..0c0feb8834d0 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -664,11 +664,20 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy( /*calculate CTL_LO*/ ctl_lo.ctl_lo = 0; ctl_lo.ctlx.int_en = 1; - ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width; - ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width; ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst; ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst; + /* + * Here we need some translation from "enum dma_slave_buswidth" + * to the format for our dma controller + * standard intel_mid_dmac's format + * 1 Byte 0b000 + * 2 Bytes 0b001 + * 4 Bytes 0b010 + */ + ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2; + ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2; + if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) { ctl_lo.ctlx.tt_fc = 0; ctl_lo.ctlx.sinc = 0; @@ -746,8 +755,18 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg( BUG_ON(!mids); if (!midc->dma->pimr_mask) { - pr_debug("MDMA: SG list is not supported by this controller\n"); - return NULL; + /* We can still handle sg list with only one item */ + if (sg_len == 1) { + txd = intel_mid_dma_prep_memcpy(chan, + mids->dma_slave.dst_addr, + mids->dma_slave.src_addr, + sgl->length, + flags); + return txd; + } else { + pr_warn("MDMA: SG list is not supported by this controller\n"); + return NULL; + } } pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n", @@ -758,6 +777,7 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg( pr_err("MDMA: Prep memcpy failed\n"); return NULL; } + desc = to_intel_mid_dma_desc(txd); desc->dirn = direction; ctl_lo.ctl_lo = desc->ctl_lo; -- cgit v1.2.3 From 17fe6981109e995f36723e4880a97d48fa38920a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 3 Dec 2010 20:17:19 +0000 Subject: drm/i915/lvds: Connect the PWM to the LVDS pipe ... and do not just assume to always use pipe B. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 23247b235e68..d07055c4d84f 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1012,10 +1012,18 @@ bool intel_lvds_init(struct drm_device *dev) out: if (HAS_PCH_SPLIT(dev)) { u32 pwm; - /* make sure PWM is enabled */ + + pipe = (I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT) ? 1 : 0; + + /* make sure PWM is enabled and locked to the LVDS pipe */ pwm = I915_READ(BLC_PWM_CPU_CTL2); - pwm |= (PWM_ENABLE | PWM_PIPE_B); - I915_WRITE(BLC_PWM_CPU_CTL2, pwm); + if (pipe == 0 && (pwm & PWM_PIPE_B)) + I915_WRITE(BLC_PWM_CPU_CTL2, pwm & ~PWM_ENABLE); + if (pipe) + pwm |= PWM_PIPE_B; + else + pwm &= ~PWM_PIPE_B; + I915_WRITE(BLC_PWM_CPU_CTL2, pwm | PWM_ENABLE); pwm = I915_READ(BLC_PWM_PCH_CTL1); pwm |= PWM_PCH_ENABLE; -- cgit v1.2.3 From a589b9f429ac0e5bcdebda0f74ee313d39d69b7f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 3 Dec 2010 21:13:16 +0000 Subject: drm/i915: Explain why we need to write DPLL twice ... it's because setting the Pixel Multiply bits only takes effect once the PLL is enabled and stable. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f7962b741c94..e3b8d0dc7a7d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4089,13 +4089,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } I915_WRITE(DPLL_MD(pipe), temp); } else { - /* write it again -- the BIOS does, after all */ + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ I915_WRITE(dpll_reg, dpll); } - - /* Wait for the clocks to stabilize. */ - POSTING_READ(dpll_reg); - udelay(150); } intel_crtc->lowfreq_avail = false; -- cgit v1.2.3 From c1858123dba4a9e40355363ac7a153ea23a5315d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 3 Dec 2010 21:35:48 +0000 Subject: drm/i915: Enable CB tuning of the Display PLL Magic numbers from the specs. This is supposed to allow the PLL some variance to improve jitter performance and VCO headroom across manufacturing and environmental variations. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 998457063d5e..06175e98c5bb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2712,6 +2712,7 @@ #define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B) #define PCH_FPA0 0xc6040 +#define FP_CB_TUNE (0x3<<22) #define PCH_FPA1 0xc6044 #define PCH_FPB0 0xc6048 #define PCH_FPB1 0xc604c diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e3b8d0dc7a7d..f2aa76bd72c0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3857,6 +3857,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, reduced_clock.m2; } + /* Enable autotuning of the PLL clock (if permissible) */ + if (HAS_PCH_SPLIT(dev)) { + int factor = 21; + + if (is_lvds) { + if ((dev_priv->lvds_use_ssc && + dev_priv->lvds_ssc_freq == 100) || + (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + factor = 25; + } else if (is_sdvo && is_tv) + factor = 20; + + if (clock.m1 < factor * clock.n) + fp |= FP_CB_TUNE; + } + dpll = 0; if (!HAS_PCH_SPLIT(dev)) dpll = DPLL_VGA_MODE_DIS; @@ -4071,7 +4087,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll); /* Wait for the clocks to stabilize. */ -- cgit v1.2.3 From f684f5b48cd27a031928c137531aace728d765a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Dec 2010 17:22:41 +0000 Subject: drm/i915: Re-enable RC6 for power-savings. Let's see if we've successfully cleared up all the bugs from last time... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f2aa76bd72c0..3063edd2456f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5864,7 +5864,6 @@ void intel_init_clock_gating(struct drm_device *dev) _3D_CHICKEN2_WM_READ_PIPELINED << 16 | _3D_CHICKEN2_WM_READ_PIPELINED); } - return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; I915_WRITE(RENCLK_GATE_D1, 0); -- cgit v1.2.3 From 4add75c43f39573edc884d46b7c2b7414f01171a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Dec 2010 17:49:46 +0000 Subject: drm/i915: Allow LVDS to be on pipe A for Ironlake+ Previously we enabled this for gen4, only to have to revert it due to it causing a large number of spurious wakeups. Try again hoping that the hardware has become more sane in the mean time... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index d07055c4d84f..6d1106eafcfd 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -907,6 +907,8 @@ bool intel_lvds_init(struct drm_device *dev) intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT); intel_encoder->crtc_mask = (1 << 1); + if (INTEL_INFO(dev)->gen >= 5) + intel_encoder->crtc_mask |= (1 << 0); drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; -- cgit v1.2.3 From 340479aac697bc73e225c122a9753d4964eeda3f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Dec 2010 18:17:15 +0000 Subject: drm/i915: Be paranoid and bail on resetting if we can't take the lock. This will declare the machine wedged, but is better than truly wedging the machine. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1a15b7886b8c..64844e2e9f86 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -440,7 +440,8 @@ int i915_reset(struct drm_device *dev, u8 flags) bool need_display = true; int ret; - mutex_lock(&dev->struct_mutex); + if (!mutex_trylock(&dev->struct_mutex)) + return -EBUSY; i915_gem_reset(dev); -- cgit v1.2.3 From 1ec14ad3132702694f2e1a90b30641cf111183b9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Dec 2010 11:30:53 +0000 Subject: drm/i915: Implement GPU semaphores for inter-ring synchronisation on SNB The bulk of the change is to convert the growing list of rings into an array so that the relationship between the rings and the semaphore sync registers can be easily computed. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 75 +++--- drivers/gpu/drm/i915/i915_dma.c | 60 +++-- drivers/gpu/drm/i915/i915_drv.c | 6 +- drivers/gpu/drm/i915/i915_drv.h | 48 ++-- drivers/gpu/drm/i915/i915_gem.c | 86 +++--- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 94 +++++-- drivers/gpu/drm/i915/i915_irq.c | 209 ++++++++------- drivers/gpu/drm/i915/i915_reg.h | 19 +- drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_opregion.c | 8 +- drivers/gpu/drm/i915/intel_overlay.c | 8 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 415 ++++++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 41 ++- drivers/gpu/drm/i915/intel_tv.c | 14 +- 14 files changed, 648 insertions(+), 439 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3c9d4b876865..aedb02157474 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -339,10 +339,10 @@ static int i915_gem_request_info(struct seq_file *m, void *data) return ret; count = 0; - if (!list_empty(&dev_priv->render_ring.request_list)) { + if (!list_empty(&dev_priv->ring[RCS].request_list)) { seq_printf(m, "Render requests:\n"); list_for_each_entry(gem_request, - &dev_priv->render_ring.request_list, + &dev_priv->ring[RCS].request_list, list) { seq_printf(m, " %d @ %d\n", gem_request->seqno, @@ -350,10 +350,10 @@ static int i915_gem_request_info(struct seq_file *m, void *data) } count++; } - if (!list_empty(&dev_priv->bsd_ring.request_list)) { + if (!list_empty(&dev_priv->ring[VCS].request_list)) { seq_printf(m, "BSD requests:\n"); list_for_each_entry(gem_request, - &dev_priv->bsd_ring.request_list, + &dev_priv->ring[VCS].request_list, list) { seq_printf(m, " %d @ %d\n", gem_request->seqno, @@ -361,10 +361,10 @@ static int i915_gem_request_info(struct seq_file *m, void *data) } count++; } - if (!list_empty(&dev_priv->blt_ring.request_list)) { + if (!list_empty(&dev_priv->ring[BCS].request_list)) { seq_printf(m, "BLT requests:\n"); list_for_each_entry(gem_request, - &dev_priv->blt_ring.request_list, + &dev_priv->ring[BCS].request_list, list) { seq_printf(m, " %d @ %d\n", gem_request->seqno, @@ -398,15 +398,14 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + int ret, i; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; - i915_ring_seqno_info(m, &dev_priv->render_ring); - i915_ring_seqno_info(m, &dev_priv->bsd_ring); - i915_ring_seqno_info(m, &dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + i915_ring_seqno_info(m, &dev_priv->ring[i]); mutex_unlock(&dev->struct_mutex); @@ -419,7 +418,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + int ret, i; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -458,9 +457,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } seq_printf(m, "Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - i915_ring_seqno_info(m, &dev_priv->render_ring); - i915_ring_seqno_info(m, &dev_priv->bsd_ring); - i915_ring_seqno_info(m, &dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + i915_ring_seqno_info(m, &dev_priv->ring[i]); mutex_unlock(&dev->struct_mutex); return 0; @@ -503,13 +501,7 @@ static int i915_hws_info(struct seq_file *m, void *data) volatile u32 *hws; int i; - switch ((uintptr_t)node->info_ent->data) { - case RING_RENDER: ring = &dev_priv->render_ring; break; - case RING_BSD: ring = &dev_priv->bsd_ring; break; - case RING_BLT: ring = &dev_priv->blt_ring; break; - default: return -EINVAL; - } - + ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; hws = (volatile u32 *)ring->status_page.page_addr; if (hws == NULL) return 0; @@ -569,17 +561,11 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) struct intel_ring_buffer *ring; int ret; - switch ((uintptr_t)node->info_ent->data) { - case RING_RENDER: ring = &dev_priv->render_ring; break; - case RING_BSD: ring = &dev_priv->bsd_ring; break; - case RING_BLT: ring = &dev_priv->blt_ring; break; - default: return -EINVAL; - } - ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; if (!ring->obj) { seq_printf(m, "No ringbuffer setup\n"); } else { @@ -603,21 +589,20 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - switch ((uintptr_t)node->info_ent->data) { - case RING_RENDER: ring = &dev_priv->render_ring; break; - case RING_BSD: ring = &dev_priv->bsd_ring; break; - case RING_BLT: ring = &dev_priv->blt_ring; break; - default: return -EINVAL; - } - + ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; if (ring->size == 0) - return 0; + return 0; seq_printf(m, "Ring %s:\n", ring->name); seq_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR); seq_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR); seq_printf(m, " Size : %08x\n", ring->size); seq_printf(m, " Active : %08x\n", intel_ring_get_active_head(ring)); + seq_printf(m, " NOPID : %08x\n", I915_READ_NOPID(ring)); + if (IS_GEN6(dev)) { + seq_printf(m, " Sync 0 : %08x\n", I915_READ_SYNC_0(ring)); + seq_printf(m, " Sync 1 : %08x\n", I915_READ_SYNC_1(ring)); + } seq_printf(m, " Control : %08x\n", I915_READ_CTL(ring)); seq_printf(m, " Start : %08x\n", I915_READ_START(ring)); @@ -1177,15 +1162,15 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_seqno", i915_gem_seqno_info, 0}, {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, {"i915_gem_interrupt", i915_interrupt_info, 0}, - {"i915_gem_hws", i915_hws_info, 0, (void *)RING_RENDER}, - {"i915_gem_hws_blt", i915_hws_info, 0, (void *)RING_BLT}, - {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)RING_BSD}, - {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_RENDER}, - {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_RENDER}, - {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BSD}, - {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BSD}, - {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BLT}, - {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BLT}, + {"i915_gem_hws", i915_hws_info, 0, (void *)RCS}, + {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS}, + {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS}, + {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RCS}, + {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RCS}, + {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)VCS}, + {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS}, + {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS}, + {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS}, {"i915_batchbuffers", i915_batchbuffer_info, 0}, {"i915_error_state", i915_error_state, 0}, {"i915_rstdby_delays", i915_rstdby_delays, 0}, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9a22da9b2083..664300986fb4 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -49,6 +49,8 @@ static int i915_init_phys_hws(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + /* Program Hardware Status Page */ dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE); @@ -57,11 +59,10 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - dev_priv->render_ring.status_page.page_addr - = dev_priv->status_page_dmah->vaddr; + ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); + memset(ring->status_page.page_addr, 0, PAGE_SIZE); if (INTEL_INFO(dev)->gen >= 4) dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & @@ -79,13 +80,15 @@ static int i915_init_phys_hws(struct drm_device *dev) static void i915_free_hws(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev_priv); + if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); dev_priv->status_page_dmah = NULL; } - if (dev_priv->render_ring.status_page.gfx_addr) { - dev_priv->render_ring.status_page.gfx_addr = 0; + if (ring->status_page.gfx_addr) { + ring->status_page.gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); } @@ -97,7 +100,7 @@ void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; - struct intel_ring_buffer *ring = &dev_priv->render_ring; + struct intel_ring_buffer *ring = LP_RING(dev_priv); /* * We should never lose context on the ring with modesetting @@ -123,6 +126,8 @@ void i915_kernel_lost_context(struct drm_device * dev) static int i915_dma_cleanup(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; + int i; + /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. @@ -131,9 +136,8 @@ static int i915_dma_cleanup(struct drm_device * dev) drm_irq_uninstall(dev); mutex_lock(&dev->struct_mutex); - intel_cleanup_ring_buffer(&dev_priv->render_ring); - intel_cleanup_ring_buffer(&dev_priv->bsd_ring); - intel_cleanup_ring_buffer(&dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + intel_cleanup_ring_buffer(&dev_priv->ring[i]); mutex_unlock(&dev->struct_mutex); /* Clear the HWS virtual address at teardown */ @@ -147,6 +151,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + struct intel_ring_buffer *ring = LP_RING(dev_priv); master_priv->sarea = drm_getsarea(dev); if (master_priv->sarea) { @@ -157,24 +162,24 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (dev_priv->render_ring.obj != NULL) { + if (ring->obj != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); return -EINVAL; } - dev_priv->render_ring.size = init->ring_size; + ring->size = init->ring_size; - dev_priv->render_ring.map.offset = init->ring_start; - dev_priv->render_ring.map.size = init->ring_size; - dev_priv->render_ring.map.type = 0; - dev_priv->render_ring.map.flags = 0; - dev_priv->render_ring.map.mtrr = 0; + ring->map.offset = init->ring_start; + ring->map.size = init->ring_size; + ring->map.type = 0; + ring->map.flags = 0; + ring->map.mtrr = 0; - drm_core_ioremap_wc(&dev_priv->render_ring.map, dev); + drm_core_ioremap_wc(&ring->map, dev); - if (dev_priv->render_ring.map.handle == NULL) { + if (ring->map.handle == NULL) { i915_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); @@ -182,7 +187,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } } - dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle; + ring->virtual_start = ring->map.handle; dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; @@ -201,12 +206,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) static int i915_dma_resume(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev_priv); - struct intel_ring_buffer *ring; DRM_DEBUG_DRIVER("%s\n", __func__); - ring = &dev_priv->render_ring; - if (ring->map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); @@ -326,7 +329,7 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) drm_i915_private_t *dev_priv = dev->dev_private; int i, ret; - if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8) + if ((dwords+1) * sizeof(int) >= LP_RING(dev_priv)->size - 8) return -EINVAL; for (i = 0; i < dwords;) { @@ -565,13 +568,12 @@ static int i915_dispatch_flip(struct drm_device * dev) return 0; } -static int i915_quiescent(struct drm_device * dev) +static int i915_quiescent(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = LP_RING(dev->dev_private); i915_kernel_lost_context(dev); - return intel_wait_ring_buffer(&dev_priv->render_ring, - dev_priv->render_ring.size - 8); + return intel_wait_ring_buffer(ring, ring->size - 8); } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -828,7 +830,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_hws_addr_t *hws = data; - struct intel_ring_buffer *ring = &dev_priv->render_ring; + struct intel_ring_buffer *ring = LP_RING(dev_priv); if (!I915_NEED_GFX_HWS(dev)) return -EINVAL; @@ -1978,7 +1980,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!IS_I945G(dev) && !IS_I945GM(dev)) pci_enable_msi(dev->pdev); - spin_lock_init(&dev_priv->user_irq_lock); + spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->error_lock); dev_priv->trace_irq_seqno = 0; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 64844e2e9f86..413a040386a9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -487,11 +487,11 @@ int i915_reset(struct drm_device *dev, u8 flags) !dev_priv->mm.suspended) { dev_priv->mm.suspended = 0; - dev_priv->render_ring.init(&dev_priv->render_ring); + dev_priv->ring[RCS].init(&dev_priv->ring[RCS]); if (HAS_BSD(dev)) - dev_priv->bsd_ring.init(&dev_priv->bsd_ring); + dev_priv->ring[VCS].init(&dev_priv->ring[VCS]); if (HAS_BLT(dev)) - dev_priv->blt_ring.init(&dev_priv->blt_ring); + dev_priv->ring[BCS].init(&dev_priv->ring[BCS]); mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index af9ff40b135b..8b19b5806230 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -269,9 +269,7 @@ typedef struct drm_i915_private { } *gmbus; struct pci_dev *bridge_dev; - struct intel_ring_buffer render_ring; - struct intel_ring_buffer bsd_ring; - struct intel_ring_buffer blt_ring; + struct intel_ring_buffer ring[I915_NUM_RINGS]; uint32_t next_seqno; drm_dma_handle_t *status_page_dmah; @@ -290,19 +288,15 @@ typedef struct drm_i915_private { int page_flipping; atomic_t irq_received; - /** Protects user_irq_refcount and irq_mask_reg */ - spinlock_t user_irq_lock; u32 trace_irq_seqno; + + /* protects the irq masks */ + spinlock_t irq_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ - u32 irq_mask_reg; u32 pipestat[2]; - /** splitted irq regs for graphics and display engine on Ironlake, - irq_mask_reg is still used for display irq. */ - u32 gt_irq_mask_reg; - u32 gt_irq_enable_reg; - u32 de_irq_enable_reg; - u32 pch_irq_mask_reg; - u32 pch_irq_enable_reg; + u32 irq_mask; + u32 gt_irq_mask; + u32 pch_irq_mask; u32 hotplug_supported_mask; struct work_struct hotplug_work; @@ -1104,7 +1098,8 @@ int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, bool interruptible); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring); + struct intel_ring_buffer *ring, + u32 seqno); /** * Returns true if seq1 is later than seq2. @@ -1272,6 +1267,17 @@ extern void intel_display_print_error_state(struct seq_file *m, struct intel_display_error_state *error); #endif +#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) + +#define BEGIN_LP_RING(n) \ + intel_ring_begin(LP_RING(dev_priv), (n)) + +#define OUT_RING(x) \ + intel_ring_emit(LP_RING(dev_priv), x) + +#define ADVANCE_LP_RING() \ + intel_ring_advance(LP_RING(dev_priv)) + /** * Lock test for when it's just for synchronization of ring access. * @@ -1279,8 +1285,7 @@ extern void intel_display_print_error_state(struct seq_file *m, * has access to the ring. */ #define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \ - if (((drm_i915_private_t *)dev->dev_private)->render_ring.obj \ - == NULL) \ + if (LP_RING(dev->dev_private)->obj == NULL) \ LOCK_TEST_WITH_RETURN(dev, file); \ } while (0) @@ -1366,15 +1371,6 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) } } -#define BEGIN_LP_RING(n) \ - intel_ring_begin(&dev_priv->render_ring, (n)) - -#define OUT_RING(x) \ - intel_ring_emit(&dev_priv->render_ring, x) - -#define ADVANCE_LP_RING() \ - intel_ring_advance(&dev_priv->render_ring) - /** * Reads a dword out of the status page, which is written to from the command * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or @@ -1391,7 +1387,7 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) * The area from dword 0x20 to 0x3ff is available for driver usage. */ #define READ_HWSP(dev_priv, reg) (((volatile u32 *)\ - (dev_priv->render_ring.status_page.page_addr))[reg]) + (LP_RING(dev_priv)->status_page.page_addr))[reg]) #define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) #define I915_GEM_HWS_INDEX 0x20 #define I915_BREADCRUMB_INDEX 0x21 diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d99212fe54ed..eeed2e99d247 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1561,11 +1561,11 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + u32 seqno) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t seqno = i915_gem_next_request_seqno(dev, ring); BUG_ON(ring == NULL); obj->ring = ring; @@ -1679,7 +1679,8 @@ i915_gem_process_flushing_list(struct drm_device *dev, obj->base.write_domain = 0; list_del_init(&obj->gpu_write_list); - i915_gem_object_move_to_active(obj, ring); + i915_gem_object_move_to_active(obj, ring, + i915_gem_next_request_seqno(dev, ring)); trace_i915_gem_object_change_domain(obj, obj->base.read_domains, @@ -1804,10 +1805,10 @@ void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; + int i; - i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring); - i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring); - i915_gem_reset_ring_lists(dev_priv, &dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + i915_gem_reset_ring_lists(dev_priv, &dev_priv->ring[i]); /* Remove anything from the flushing lists. The GPU cache is likely * to be lost on reset along with the data, so simply move the @@ -1846,6 +1847,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; + int i; if (!ring->status_page.page_addr || list_empty(&ring->request_list)) @@ -1854,6 +1856,11 @@ i915_gem_retire_requests_ring(struct drm_device *dev, WARN_ON(i915_verify_lists(dev)); seqno = ring->get_seqno(ring); + + for (i = 0; i < I915_NUM_RINGS; i++) + if (seqno >= ring->sync_seqno[i]) + ring->sync_seqno[i] = 0; + while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -1892,7 +1899,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, if (unlikely (dev_priv->trace_irq_seqno && i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) { - ring->user_irq_put(ring); + ring->irq_put(ring); dev_priv->trace_irq_seqno = 0; } @@ -1903,6 +1910,7 @@ void i915_gem_retire_requests(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + int i; if (!list_empty(&dev_priv->mm.deferred_free_list)) { struct drm_i915_gem_object *obj, *next; @@ -1918,9 +1926,8 @@ i915_gem_retire_requests(struct drm_device *dev) i915_gem_free_object_tail(obj); } - i915_gem_retire_requests_ring(dev, &dev_priv->render_ring); - i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring); - i915_gem_retire_requests_ring(dev, &dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + i915_gem_retire_requests_ring(dev, &dev_priv->ring[i]); } static void @@ -1942,9 +1949,9 @@ i915_gem_retire_work_handler(struct work_struct *work) i915_gem_retire_requests(dev); if (!dev_priv->mm.suspended && - (!list_empty(&dev_priv->render_ring.request_list) || - !list_empty(&dev_priv->bsd_ring.request_list) || - !list_empty(&dev_priv->blt_ring.request_list))) + (!list_empty(&dev_priv->ring[RCS].request_list) || + !list_empty(&dev_priv->ring[VCS].request_list) || + !list_empty(&dev_priv->ring[BCS].request_list))) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } @@ -1993,7 +2000,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, trace_i915_gem_request_wait_begin(dev, seqno); ring->waiting_seqno = seqno; - ring->user_irq_get(ring); + ring->irq_get(ring); if (interruptible) ret = wait_event_interruptible(ring->irq_queue, i915_seqno_passed(ring->get_seqno(ring), seqno) @@ -2003,7 +2010,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, i915_seqno_passed(ring->get_seqno(ring), seqno) || atomic_read(&dev_priv->mm.wedged)); - ring->user_irq_put(ring); + ring->irq_put(ring); ring->waiting_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); @@ -2159,7 +2166,7 @@ i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; - int ret; + int ret, i; lists_empty = (list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->mm.active_list)); @@ -2167,17 +2174,11 @@ i915_gpu_idle(struct drm_device *dev) return 0; /* Flush everything onto the inactive list. */ - ret = i915_ring_idle(dev, &dev_priv->render_ring); - if (ret) - return ret; - - ret = i915_ring_idle(dev, &dev_priv->bsd_ring); - if (ret) - return ret; - - ret = i915_ring_idle(dev, &dev_priv->blt_ring); - if (ret) - return ret; + for (i = 0; i < I915_NUM_RINGS; i++) { + ret = i915_ring_idle(dev, &dev_priv->ring[i]); + if (ret) + return ret; + } return 0; } @@ -3153,11 +3154,11 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) * generation is designed to be run atomically and so is * lockless. */ - ring->user_irq_get(ring); + ring->irq_get(ring); ret = wait_event_interruptible(ring->irq_queue, i915_seqno_passed(ring->get_seqno(ring), seqno) || atomic_read(&dev_priv->mm.wedged)); - ring->user_irq_put(ring); + ring->irq_put(ring); if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) ret = -EIO; @@ -3584,9 +3585,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev) return 0; cleanup_bsd_ring: - intel_cleanup_ring_buffer(&dev_priv->bsd_ring); + intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); cleanup_render_ring: - intel_cleanup_ring_buffer(&dev_priv->render_ring); + intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); return ret; } @@ -3594,10 +3595,10 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + int i; - intel_cleanup_ring_buffer(&dev_priv->render_ring); - intel_cleanup_ring_buffer(&dev_priv->bsd_ring); - intel_cleanup_ring_buffer(&dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + intel_cleanup_ring_buffer(&dev_priv->ring[i]); } int @@ -3605,7 +3606,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + int ret, i; if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; @@ -3625,14 +3626,12 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, } BUG_ON(!list_empty(&dev_priv->mm.active_list)); - BUG_ON(!list_empty(&dev_priv->render_ring.active_list)); - BUG_ON(!list_empty(&dev_priv->bsd_ring.active_list)); - BUG_ON(!list_empty(&dev_priv->blt_ring.active_list)); BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); - BUG_ON(!list_empty(&dev_priv->render_ring.request_list)); - BUG_ON(!list_empty(&dev_priv->bsd_ring.request_list)); - BUG_ON(!list_empty(&dev_priv->blt_ring.request_list)); + for (i = 0; i < I915_NUM_RINGS; i++) { + BUG_ON(!list_empty(&dev_priv->ring[i].active_list)); + BUG_ON(!list_empty(&dev_priv->ring[i].request_list)); + } mutex_unlock(&dev->struct_mutex); ret = drm_irq_install(dev); @@ -3695,9 +3694,8 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list); INIT_LIST_HEAD(&dev_priv->mm.gtt_list); - init_ring_lists(&dev_priv->render_ring); - init_ring_lists(&dev_priv->bsd_ring); - init_ring_lists(&dev_priv->blt_ring); + for (i = 0; i < I915_NUM_RINGS; i++) + init_ring_lists(&dev_priv->ring[i]); for (i = 0; i < 16; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9bdc495e17bb..6fc9cc485781 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -632,23 +632,59 @@ i915_gem_execbuffer_flush(struct drm_device *dev, uint32_t flush_rings) { drm_i915_private_t *dev_priv = dev->dev_private; + int i; if (flush_domains & I915_GEM_DOMAIN_CPU) intel_gtt_chipset_flush(); if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { - if (flush_rings & RING_RENDER) - i915_gem_flush_ring(dev, &dev_priv->render_ring, - invalidate_domains, flush_domains); - if (flush_rings & RING_BSD) - i915_gem_flush_ring(dev, &dev_priv->bsd_ring, - invalidate_domains, flush_domains); - if (flush_rings & RING_BLT) - i915_gem_flush_ring(dev, &dev_priv->blt_ring, - invalidate_domains, flush_domains); + for (i = 0; i < I915_NUM_RINGS; i++) + if (flush_rings & (1 << i)) + i915_gem_flush_ring(dev, &dev_priv->ring[i], + invalidate_domains, + flush_domains); } } +static int +i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *to) +{ + struct intel_ring_buffer *from = obj->ring; + u32 seqno; + int ret, idx; + + if (from == NULL || to == from) + return 0; + + if (INTEL_INFO(obj->base.dev)->gen < 6) + return i915_gem_object_wait_rendering(obj, true); + + idx = intel_ring_sync_index(from, to); + + seqno = obj->last_rendering_seqno; + if (seqno <= from->sync_seqno[idx]) + return 0; + + if (seqno == from->outstanding_lazy_request) { + struct drm_i915_gem_request *request; + + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + + ret = i915_add_request(obj->base.dev, NULL, request, from); + if (ret) { + kfree(request); + return ret; + } + + seqno = request->seqno; + } + + from->sync_seqno[idx] = seqno; + return intel_ring_sync(to, from, seqno - 1); +} static int i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, @@ -678,12 +714,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, } list_for_each_entry(obj, objects, exec_list) { - /* XXX replace with semaphores */ - if (obj->ring && ring != obj->ring) { - ret = i915_gem_object_wait_rendering(obj, true); - if (ret) - return ret; - } + ret = i915_gem_execbuffer_sync_rings(obj, ring); + if (ret) + return ret; } return 0; @@ -769,7 +802,8 @@ i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, static void i915_gem_execbuffer_move_to_active(struct list_head *objects, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + u32 seqno) { struct drm_i915_gem_object *obj; @@ -778,7 +812,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, obj->base.write_domain = obj->base.pending_write_domain; obj->fenced_gpu_access = obj->pending_fenced_gpu_access; - i915_gem_object_move_to_active(obj, ring); + i915_gem_object_move_to_active(obj, ring, seqno); if (obj->base.write_domain) { obj->dirty = 1; obj->pending_gpu_write = true; @@ -833,6 +867,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; u32 exec_start, exec_len; + u32 seqno; int ret, i; if (!i915_gem_check_execbuffer(args)) { @@ -851,21 +886,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, switch (args->flags & I915_EXEC_RING_MASK) { case I915_EXEC_DEFAULT: case I915_EXEC_RENDER: - ring = &dev_priv->render_ring; + ring = &dev_priv->ring[RCS]; break; case I915_EXEC_BSD: if (!HAS_BSD(dev)) { DRM_ERROR("execbuf with invalid ring (BSD)\n"); return -EINVAL; } - ring = &dev_priv->bsd_ring; + ring = &dev_priv->ring[VCS]; break; case I915_EXEC_BLT: if (!HAS_BLT(dev)) { DRM_ERROR("execbuf with invalid ring (BLT)\n"); return -EINVAL; } - ring = &dev_priv->blt_ring; + ring = &dev_priv->ring[BCS]; break; default: DRM_ERROR("execbuf with unknown ring: %d\n", @@ -879,7 +914,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (args->num_cliprects != 0) { - if (ring != &dev_priv->render_ring) { + if (ring != &dev_priv->ring[RCS]) { DRM_ERROR("clip rectangles are only valid with the render ring\n"); return -EINVAL; } @@ -972,6 +1007,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; + seqno = i915_gem_next_request_seqno(dev, ring); + for (i = 0; i < I915_NUM_RINGS-1; i++) { + if (seqno < ring->sync_seqno[i]) { + /* The GPU can not handle its semaphore value wrapping, + * so every billion or so execbuffers, we need to stall + * the GPU in order to reset the counters. + */ + ret = i915_gpu_idle(dev); + if (ret) + goto err; + + BUG_ON(ring->sync_seqno[i]); + } + } + exec_start = batch_obj->gtt_offset + args->batch_start_offset; exec_len = args->batch_len; if (cliprects) { @@ -992,7 +1042,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - i915_gem_execbuffer_move_to_active(&objects, ring); + i915_gem_execbuffer_move_to_active(&objects, ring, seqno); i915_gem_execbuffer_retire_commands(dev, file, ring); err: diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9aa1e1dc5fd5..5e831b7eb3f1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -67,9 +67,9 @@ void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) { - if ((dev_priv->gt_irq_mask_reg & mask) != 0) { - dev_priv->gt_irq_mask_reg &= ~mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + if ((dev_priv->gt_irq_mask & mask) != 0) { + dev_priv->gt_irq_mask &= ~mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); POSTING_READ(GTIMR); } } @@ -77,9 +77,9 @@ ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) { - if ((dev_priv->gt_irq_mask_reg & mask) != mask) { - dev_priv->gt_irq_mask_reg |= mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + if ((dev_priv->gt_irq_mask & mask) != mask) { + dev_priv->gt_irq_mask |= mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); POSTING_READ(GTIMR); } } @@ -88,9 +88,9 @@ ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { - if ((dev_priv->irq_mask_reg & mask) != 0) { - dev_priv->irq_mask_reg &= ~mask; - I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + if ((dev_priv->irq_mask & mask) != 0) { + dev_priv->irq_mask &= ~mask; + I915_WRITE(DEIMR, dev_priv->irq_mask); POSTING_READ(DEIMR); } } @@ -98,9 +98,9 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) static inline void ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { - if ((dev_priv->irq_mask_reg & mask) != mask) { - dev_priv->irq_mask_reg |= mask; - I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + if ((dev_priv->irq_mask & mask) != mask) { + dev_priv->irq_mask |= mask; + I915_WRITE(DEIMR, dev_priv->irq_mask); POSTING_READ(DEIMR); } } @@ -108,9 +108,9 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) { - if ((dev_priv->irq_mask_reg & mask) != 0) { - dev_priv->irq_mask_reg &= ~mask; - I915_WRITE(IMR, dev_priv->irq_mask_reg); + if ((dev_priv->irq_mask & mask) != 0) { + dev_priv->irq_mask &= ~mask; + I915_WRITE(IMR, dev_priv->irq_mask); POSTING_READ(IMR); } } @@ -118,9 +118,9 @@ i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) { - if ((dev_priv->irq_mask_reg & mask) != mask) { - dev_priv->irq_mask_reg |= mask; - I915_WRITE(IMR, dev_priv->irq_mask_reg); + if ((dev_priv->irq_mask & mask) != mask) { + dev_priv->irq_mask |= mask; + I915_WRITE(IMR, dev_priv->irq_mask); POSTING_READ(IMR); } } @@ -163,9 +163,12 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) /** * intel_enable_asle - enable ASLE interrupt for OpRegion */ -void intel_enable_asle (struct drm_device *dev) +void intel_enable_asle(struct drm_device *dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) ironlake_enable_display_irq(dev_priv, DE_GSE); @@ -176,6 +179,8 @@ void intel_enable_asle (struct drm_device *dev) i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); } + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } /** @@ -344,12 +349,12 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) READ_BREADCRUMB(dev_priv); } - if (gt_iir & GT_PIPE_NOTIFY) - notify_ring(dev, &dev_priv->render_ring); + if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) + notify_ring(dev, &dev_priv->ring[RCS]); if (gt_iir & bsd_usr_interrupt) - notify_ring(dev, &dev_priv->bsd_ring); - if (HAS_BLT(dev) && gt_iir & GT_BLT_USER_INTERRUPT) - notify_ring(dev, &dev_priv->blt_ring); + notify_ring(dev, &dev_priv->ring[VCS]); + if (gt_iir & GT_BLT_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[BCS]); if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); @@ -640,8 +645,7 @@ static void i915_capture_error_state(struct drm_device *dev) DRM_DEBUG_DRIVER("generating error event\n"); - error->seqno = - dev_priv->render_ring.get_seqno(&dev_priv->render_ring); + error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); error->pipeastat = I915_READ(PIPEASTAT); @@ -656,16 +660,16 @@ static void i915_capture_error_state(struct drm_device *dev) error->bcs_ipeir = I915_READ(BCS_IPEIR); error->bcs_instdone = I915_READ(BCS_INSTDONE); error->bcs_seqno = 0; - if (dev_priv->blt_ring.get_seqno) - error->bcs_seqno = dev_priv->blt_ring.get_seqno(&dev_priv->blt_ring); + if (dev_priv->ring[BCS].get_seqno) + error->bcs_seqno = dev_priv->ring[BCS].get_seqno(&dev_priv->ring[BCS]); error->vcs_acthd = I915_READ(VCS_ACTHD); error->vcs_ipehr = I915_READ(VCS_IPEHR); error->vcs_ipeir = I915_READ(VCS_IPEIR); error->vcs_instdone = I915_READ(VCS_INSTDONE); error->vcs_seqno = 0; - if (dev_priv->bsd_ring.get_seqno) - error->vcs_seqno = dev_priv->bsd_ring.get_seqno(&dev_priv->bsd_ring); + if (dev_priv->ring[VCS].get_seqno) + error->vcs_seqno = dev_priv->ring[VCS].get_seqno(&dev_priv->ring[VCS]); } if (INTEL_INFO(dev)->gen >= 4) { error->ipeir = I915_READ(IPEIR_I965); @@ -684,7 +688,7 @@ static void i915_capture_error_state(struct drm_device *dev) } i915_gem_record_fences(dev, error); - bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->render_ring); + bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->ring[RCS]); /* Grab the current batchbuffer, most likely to have crashed. */ batchbuffer[0] = NULL; @@ -748,7 +752,7 @@ static void i915_capture_error_state(struct drm_device *dev) /* Record the ringbuffer */ error->ringbuffer = i915_error_object_create(dev, - dev_priv->render_ring.obj); + dev_priv->ring[RCS].obj); /* Record buffers on the active and pinned lists. */ error->active_bo = NULL; @@ -949,11 +953,11 @@ void i915_handle_error(struct drm_device *dev, bool wedged) /* * Wakeup waiting processes so they don't hang */ - wake_up_all(&dev_priv->render_ring.irq_queue); + wake_up_all(&dev_priv->ring[RCS].irq_queue); if (HAS_BSD(dev)) - wake_up_all(&dev_priv->bsd_ring.irq_queue); + wake_up_all(&dev_priv->ring[VCS].irq_queue); if (HAS_BLT(dev)) - wake_up_all(&dev_priv->blt_ring.irq_queue); + wake_up_all(&dev_priv->ring[BCS].irq_queue); } queue_work(dev_priv->wq, &dev_priv->error_work); @@ -1035,7 +1039,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) * It doesn't set the bit in iir again, but it still produces * interrupts (for non-MSI). */ - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); pipea_stats = I915_READ(PIPEASTAT); pipeb_stats = I915_READ(PIPEBSTAT); @@ -1058,7 +1062,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE(PIPEBSTAT, pipeb_stats); irq_received = 1; } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); if (!irq_received) break; @@ -1091,9 +1095,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_USER_INTERRUPT) - notify_ring(dev, &dev_priv->render_ring); - if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) - notify_ring(dev, &dev_priv->bsd_ring); + notify_ring(dev, &dev_priv->ring[RCS]); + if (iir & I915_BSD_USER_INTERRUPT) + notify_ring(dev, &dev_priv->ring[VCS]); if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) { intel_prepare_page_flip(dev, 0); @@ -1180,10 +1184,10 @@ static int i915_emit_irq(struct drm_device * dev) void i915_trace_irq_get(struct drm_device *dev, u32 seqno) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + struct intel_ring_buffer *ring = LP_RING(dev_priv); if (dev_priv->trace_irq_seqno == 0) - render_ring->user_irq_get(render_ring); + ring->irq_get(ring); dev_priv->trace_irq_seqno = seqno; } @@ -1193,7 +1197,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int ret = 0; - struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + struct intel_ring_buffer *ring = LP_RING(dev_priv); DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); @@ -1207,10 +1211,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - render_ring->user_irq_get(render_ring); - DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ, + ring->irq_get(ring); + DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - render_ring->user_irq_put(render_ring); + ring->irq_put(ring); if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", @@ -1229,7 +1233,7 @@ int i915_irq_emit(struct drm_device *dev, void *data, drm_i915_irq_emit_t *emit = data; int result; - if (!dev_priv || !dev_priv->render_ring.virtual_start) { + if (!dev_priv || !LP_RING(dev_priv)->virtual_start) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } @@ -1275,9 +1279,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) if (!i915_pipe_enabled(dev, pipe)) return -EINVAL; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) - ironlake_enable_display_irq(dev_priv, (pipe == 0) ? + ironlake_enable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); else if (INTEL_INFO(dev)->gen >= 4) i915_enable_pipestat(dev_priv, pipe, @@ -1285,7 +1289,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) else i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); return 0; } @@ -1297,15 +1301,15 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) - ironlake_disable_display_irq(dev_priv, (pipe == 0) ? + ironlake_disable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); else i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE | PIPE_START_VBLANK_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } void i915_enable_interrupt (struct drm_device *dev) @@ -1397,6 +1401,27 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) return false; } +static bool kick_ring(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp = I915_READ_CTL(ring); + if (tmp & RING_WAIT) { + DRM_ERROR("Kicking stuck wait on %s\n", + ring->name); + I915_WRITE_CTL(ring, tmp); + return true; + } + if (IS_GEN6(dev) && + (tmp & RING_WAIT_SEMAPHORE)) { + DRM_ERROR("Kicking stuck semaphore on %s\n", + ring->name); + I915_WRITE_CTL(ring, tmp); + return true; + } + return false; +} + /** * This is called when the chip hasn't reported back with completed * batchbuffers in a long time. The first time this is called we simply record @@ -1411,9 +1436,9 @@ void i915_hangcheck_elapsed(unsigned long data) bool err = false; /* If all work is done then ACTHD clearly hasn't advanced. */ - if (i915_hangcheck_ring_idle(&dev_priv->render_ring, &err) && - i915_hangcheck_ring_idle(&dev_priv->bsd_ring, &err) && - i915_hangcheck_ring_idle(&dev_priv->blt_ring, &err)) { + if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) && + i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) && + i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) { dev_priv->hangcheck_count = 0; if (err) goto repeat; @@ -1442,12 +1467,17 @@ void i915_hangcheck_elapsed(unsigned long data) * and break the hang. This should work on * all but the second generation chipsets. */ - struct intel_ring_buffer *ring = &dev_priv->render_ring; - u32 tmp = I915_READ_CTL(ring); - if (tmp & RING_WAIT) { - I915_WRITE_CTL(ring, tmp); + + if (kick_ring(&dev_priv->ring[RCS])) + goto repeat; + + if (HAS_BSD(dev) && + kick_ring(&dev_priv->ring[VCS])) + goto repeat; + + if (HAS_BLT(dev) && + kick_ring(&dev_priv->ring[BCS])) goto repeat; - } } i915_handle_error(dev, true); @@ -1498,37 +1528,37 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; - u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT; + u32 render_irqs; u32 hotplug_mask; - dev_priv->irq_mask_reg = ~display_mask; - dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK; + dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); - I915_WRITE(DEIMR, dev_priv->irq_mask_reg); - I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); + I915_WRITE(DEIMR, dev_priv->irq_mask); + I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK); POSTING_READ(DEIER); - if (IS_GEN6(dev)) { - render_mask = - GT_PIPE_NOTIFY | - GT_GEN6_BSD_USER_INTERRUPT | - GT_BLT_USER_INTERRUPT; - } - - dev_priv->gt_irq_mask_reg = ~render_mask; - dev_priv->gt_irq_enable_reg = render_mask; + dev_priv->gt_irq_mask = ~0; I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); if (IS_GEN6(dev)) { - I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT); - I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT); + I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_USER_INTERRUPT); + I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_USER_INTERRUPT); I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT); } - I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); + if (IS_GEN6(dev)) + render_irqs = + GT_USER_INTERRUPT | + GT_GEN6_BSD_USER_INTERRUPT | + GT_BLT_USER_INTERRUPT; + else + render_irqs = + GT_PIPE_NOTIFY | + GT_BSD_USER_INTERRUPT; + I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); if (HAS_PCH_CPT(dev)) { @@ -1539,12 +1569,11 @@ static int ironlake_irq_postinstall(struct drm_device *dev) SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; } - dev_priv->pch_irq_mask_reg = ~hotplug_mask; - dev_priv->pch_irq_enable_reg = hotplug_mask; + dev_priv->pch_irq_mask = ~hotplug_mask; I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask_reg); - I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg); + I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); + I915_WRITE(SDEIER, hotplug_mask); POSTING_READ(SDEIER); if (IS_IRONLAKE_M(dev)) { @@ -1594,11 +1623,11 @@ int i915_driver_irq_postinstall(struct drm_device *dev) u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; u32 error_mask; - DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue); + DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue); if (HAS_BSD(dev)) - DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue); + DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue); if (HAS_BLT(dev)) - DRM_INIT_WAITQUEUE(&dev_priv->blt_ring.irq_queue); + DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue); dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; @@ -1606,7 +1635,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) return ironlake_irq_postinstall(dev); /* Unmask the interrupts that we always want on. */ - dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; + dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX; dev_priv->pipestat[0] = 0; dev_priv->pipestat[1] = 0; @@ -1615,7 +1644,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) /* Enable in IER... */ enable_mask |= I915_DISPLAY_PORT_INTERRUPT; /* and unmask in IMR */ - dev_priv->irq_mask_reg &= ~I915_DISPLAY_PORT_INTERRUPT; + dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT; } /* @@ -1633,7 +1662,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) } I915_WRITE(EMR, error_mask); - I915_WRITE(IMR, dev_priv->irq_mask_reg); + I915_WRITE(IMR, dev_priv->irq_mask); I915_WRITE(IER, enable_mask); POSTING_READ(IER); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 06175e98c5bb..3e03094cf148 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -176,6 +176,11 @@ #define MI_BATCH_NON_SECURE (1) #define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) +#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ +#define MI_SEMAPHORE_GLOBAL_GTT (1<<22) +#define MI_SEMAPHORE_UPDATE (1<<21) +#define MI_SEMAPHORE_COMPARE (1<<20) +#define MI_SEMAPHORE_REGISTER (1<<18) /* * 3D instructions used by the kernel */ @@ -276,9 +281,12 @@ #define RING_HEAD(base) ((base)+0x34) #define RING_START(base) ((base)+0x38) #define RING_CTL(base) ((base)+0x3c) +#define RING_SYNC_0(base) ((base)+0x40) +#define RING_SYNC_1(base) ((base)+0x44) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) #define RING_ACTHD(base) ((base)+0x74) +#define RING_NOPID(base) ((base)+0x94) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 @@ -293,6 +301,7 @@ #define RING_INVALID 0x00000000 #define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ #define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ +#define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */ #if 0 #define PRB0_TAIL 0x02030 #define PRB0_HEAD 0x02034 @@ -347,6 +356,14 @@ # define VS_TIMER_DISPATCH (1 << 6) # define MI_FLUSH_ENABLE (1 << 11) +#define GFX_MODE 0x02520 +#define GFX_RUN_LIST_ENABLE (1<<15) +#define GFX_TLB_INVALIDATE_ALWAYS (1<<13) +#define GFX_SURFACE_FAULT_ENABLE (1<<12) +#define GFX_REPLAY_MODE (1<<11) +#define GFX_PSMI_GRANULARITY (1<<10) +#define GFX_PPGTT_ENABLE (1<<9) + #define SCPD0 0x0209c /* 915+ only */ #define IER 0x020a0 #define IIR 0x020a4 @@ -498,7 +515,7 @@ #define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3) #define GEN6_BSD_IMR 0x120a8 -#define GEN6_BSD_IMR_USER_INTERRUPT (1 << 12) +#define GEN6_BSD_USER_INTERRUPT (1 << 12) #define GEN6_BSD_RNCID 0x12198 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3063edd2456f..0b6272a2edfc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1998,7 +1998,7 @@ static void intel_clear_scanline_wait(struct drm_device *dev) /* Can't break the hang on i8xx */ return; - ring = &dev_priv->render_ring; + ring = LP_RING(dev_priv); tmp = I915_READ_CTL(ring); if (tmp & RING_WAIT) I915_WRITE_CTL(ring, tmp); @@ -5124,7 +5124,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, obj = intel_fb->obj; mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(dev, obj, &dev_priv->render_ring); + ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) goto cleanup_work; diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 9b0d9a867aea..f295a7aaadf9 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -273,14 +273,8 @@ void intel_opregion_enable_asle(struct drm_device *dev) struct opregion_asle *asle = dev_priv->opregion.asle; if (asle) { - if (IS_MOBILE(dev)) { - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + if (IS_MOBILE(dev)) intel_enable_asle(dev); - spin_unlock_irqrestore(&dev_priv->user_irq_lock, - irqflags); - } asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | ASLE_PFMB_EN; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index d0c1add393a3..3fbb98b948d6 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -221,7 +221,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, int ret; BUG_ON(overlay->last_flip_req); - ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring); + ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv)); if (ret) { kfree(request); return ret; @@ -230,7 +230,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, overlay->flip_tail = tail; ret = i915_do_wait_request(dev, overlay->last_flip_req, true, - &dev_priv->render_ring); + LP_RING(dev_priv)); if (ret) return ret; @@ -364,7 +364,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, OUT_RING(flip_addr); ADVANCE_LP_RING(); - ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring); + ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv)); if (ret) { kfree(request); return ret; @@ -454,7 +454,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, return 0; ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible, &dev_priv->render_ring); + interruptible, LP_RING(dev_priv)); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 21871b0766e2..f71db0cf4909 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -203,6 +203,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) if (ring->space < 0) ring->space += ring->size; } + return 0; } @@ -281,17 +282,18 @@ cleanup_pipe_control(struct intel_ring_buffer *ring) static int init_render_ring(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret = init_ring_common(ring); if (INTEL_INFO(dev)->gen > 3) { - drm_i915_private_t *dev_priv = dev->dev_private; int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; if (IS_GEN6(dev)) mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; I915_WRITE(MI_MODE, mode); } - if (HAS_PIPE_CONTROL(dev)) { + if (INTEL_INFO(dev)->gen >= 6) { + } else if (HAS_PIPE_CONTROL(dev)) { ret = init_pipe_control(ring); if (ret) return ret; @@ -308,6 +310,80 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring) cleanup_pipe_control(ring); } +static void +update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int id; + + /* + * cs -> 1 = vcs, 0 = bcs + * vcs -> 1 = bcs, 0 = cs, + * bcs -> 1 = cs, 0 = vcs. + */ + id = ring - dev_priv->ring; + id += 2 - i; + id %= 3; + + intel_ring_emit(ring, + MI_SEMAPHORE_MBOX | + MI_SEMAPHORE_REGISTER | + MI_SEMAPHORE_UPDATE); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, + RING_SYNC_0(dev_priv->ring[id].mmio_base) + 4*i); +} + +static int +gen6_add_request(struct intel_ring_buffer *ring, + u32 *result) +{ + u32 seqno; + int ret; + + ret = intel_ring_begin(ring, 10); + if (ret) + return ret; + + seqno = i915_gem_get_seqno(ring->dev); + update_semaphore(ring, 0, seqno); + update_semaphore(ring, 1, seqno); + + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_USER_INTERRUPT); + intel_ring_advance(ring); + + *result = seqno; + return 0; +} + +int +intel_ring_sync(struct intel_ring_buffer *ring, + struct intel_ring_buffer *to, + u32 seqno) +{ + int ret; + + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; + + intel_ring_emit(ring, + MI_SEMAPHORE_MBOX | + MI_SEMAPHORE_REGISTER | + intel_ring_sync_index(ring, to) << 17 | + MI_SEMAPHORE_COMPARE); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + + return 0; +} + #define PIPE_CONTROL_FLUSH(ring__, addr__) \ do { \ intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ @@ -317,131 +393,128 @@ do { \ intel_ring_emit(ring__, 0); \ } while (0) -/** - * Creates a new sequence number, emitting a write of it to the status page - * plus an interrupt, which will trigger i915_user_interrupt_handler. - * - * Must be called with struct_lock held. - * - * Returned sequence numbers are nonzero on success. - */ static int -render_ring_add_request(struct intel_ring_buffer *ring, - u32 *result) +pc_render_add_request(struct intel_ring_buffer *ring, + u32 *result) { struct drm_device *dev = ring->dev; u32 seqno = i915_gem_get_seqno(dev); struct pipe_control *pc = ring->private; + u32 scratch_addr = pc->gtt_offset + 128; int ret; - if (IS_GEN6(dev)) { - ret = intel_ring_begin(ring, 6); - if (ret) - return ret; - - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | 3); - intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - } else if (HAS_PIPE_CONTROL(dev)) { - u32 scratch_addr = pc->gtt_offset + 128; + /* + * Workaround qword write incoherence by flushing the + * PIPE_NOTIFY buffers out to memory before requesting + * an interrupt. + */ + ret = intel_ring_begin(ring, 32); + if (ret) + return ret; - /* - * Workaround qword write incoherence by flushing the - * PIPE_NOTIFY buffers out to memory before requesting - * an interrupt. - */ - ret = intel_ring_begin(ring, 32); - if (ret) - return ret; + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - } else { - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; + *result = seqno; + return 0; +} - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); +static int +render_ring_add_request(struct intel_ring_buffer *ring, + u32 *result) +{ + struct drm_device *dev = ring->dev; + u32 seqno = i915_gem_get_seqno(dev); + int ret; - intel_ring_emit(ring, MI_USER_INTERRUPT); - } + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; + intel_ring_emit(ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, MI_USER_INTERRUPT); intel_ring_advance(ring); + *result = seqno; return 0; } static u32 -render_ring_get_seqno(struct intel_ring_buffer *ring) +ring_get_seqno(struct intel_ring_buffer *ring) { - struct drm_device *dev = ring->dev; - if (HAS_PIPE_CONTROL(dev)) { - struct pipe_control *pc = ring->private; - return pc->cpu_page[0]; - } else - return intel_read_status_page(ring, I915_GEM_HWS_INDEX); + return intel_read_status_page(ring, I915_GEM_HWS_INDEX); +} + +static u32 +pc_render_get_seqno(struct intel_ring_buffer *ring) +{ + struct pipe_control *pc = ring->private; + return pc->cpu_page[0]; } static void -render_ring_get_user_irq(struct intel_ring_buffer *ring) +render_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++ring->user_irq_refcount == 1)) { + if (dev->irq_enabled && ++ring->irq_refcount == 1) { + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + if (HAS_PCH_SPLIT(dev)) - ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); + ironlake_enable_graphics_irq(dev_priv, + GT_PIPE_NOTIFY | GT_USER_INTERRUPT); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } static void -render_ring_put_user_irq(struct intel_ring_buffer *ring) +render_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - BUG_ON(dev->irq_enabled && ring->user_irq_refcount <= 0); - if (dev->irq_enabled && (--ring->user_irq_refcount == 0)) { + BUG_ON(dev->irq_enabled && ring->irq_refcount == 0); + if (dev->irq_enabled && --ring->irq_refcount == 0) { + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) - ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); + ironlake_disable_graphics_irq(dev_priv, + GT_USER_INTERRUPT | + GT_PIPE_NOTIFY); else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } void intel_ring_setup_status_page(struct intel_ring_buffer *ring) @@ -459,6 +532,9 @@ bsd_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + return; + if (intel_ring_begin(ring, 2) == 0) { intel_ring_emit(ring, MI_FLUSH); intel_ring_emit(ring, MI_NOOP); @@ -491,20 +567,45 @@ ring_add_request(struct intel_ring_buffer *ring, } static void -bsd_ring_get_user_irq(struct intel_ring_buffer *ring) +ring_get_irq(struct intel_ring_buffer *ring, u32 flag) { - /* do nothing */ + struct drm_device *dev = ring->dev; + + if (dev->irq_enabled && ++ring->irq_refcount == 1) { + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ironlake_enable_graphics_irq(dev_priv, flag); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } } + static void -bsd_ring_put_user_irq(struct intel_ring_buffer *ring) +ring_put_irq(struct intel_ring_buffer *ring, u32 flag) { - /* do nothing */ + struct drm_device *dev = ring->dev; + + if (dev->irq_enabled && --ring->irq_refcount == 0) { + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ironlake_disable_graphics_irq(dev_priv, flag); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } } -static u32 -ring_status_page_get_seqno(struct intel_ring_buffer *ring) + +static void +bsd_ring_get_irq(struct intel_ring_buffer *ring) { - return intel_read_status_page(ring, I915_GEM_HWS_INDEX); + ring_get_irq(ring, GT_BSD_USER_INTERRUPT); +} +static void +bsd_ring_put_irq(struct intel_ring_buffer *ring) +{ + ring_put_irq(ring, GT_BSD_USER_INTERRUPT); } static int @@ -817,9 +918,9 @@ static const struct intel_ring_buffer render_ring = { .write_tail = ring_write_tail, .flush = render_ring_flush, .add_request = render_ring_add_request, - .get_seqno = render_ring_get_seqno, - .user_irq_get = render_ring_get_user_irq, - .user_irq_put = render_ring_put_user_irq, + .get_seqno = ring_get_seqno, + .irq_get = render_ring_get_irq, + .irq_put = render_ring_put_irq, .dispatch_execbuffer = render_ring_dispatch_execbuffer, .cleanup = render_ring_cleanup, }; @@ -835,9 +936,9 @@ static const struct intel_ring_buffer bsd_ring = { .write_tail = ring_write_tail, .flush = bsd_ring_flush, .add_request = ring_add_request, - .get_seqno = ring_status_page_get_seqno, - .user_irq_get = bsd_ring_get_user_irq, - .user_irq_put = bsd_ring_put_user_irq, + .get_seqno = ring_get_seqno, + .irq_get = bsd_ring_get_irq, + .irq_put = bsd_ring_put_irq, .dispatch_execbuffer = ring_dispatch_execbuffer, }; @@ -868,6 +969,9 @@ static void gen6_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + return; + if (intel_ring_begin(ring, 4) == 0) { intel_ring_emit(ring, MI_FLUSH_DW); intel_ring_emit(ring, 0); @@ -895,33 +999,46 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, return 0; } +static void +gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring) +{ + ring_get_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); +} + +static void +gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) +{ + ring_put_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); +} + /* ring buffer for Video Codec for Gen6+ */ static const struct intel_ring_buffer gen6_bsd_ring = { - .name = "gen6 bsd ring", - .id = RING_BSD, - .mmio_base = GEN6_BSD_RING_BASE, - .size = 32 * PAGE_SIZE, - .init = init_ring_common, - .write_tail = gen6_bsd_ring_write_tail, - .flush = gen6_ring_flush, - .add_request = ring_add_request, - .get_seqno = ring_status_page_get_seqno, - .user_irq_get = bsd_ring_get_user_irq, - .user_irq_put = bsd_ring_put_user_irq, - .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, + .name = "gen6 bsd ring", + .id = RING_BSD, + .mmio_base = GEN6_BSD_RING_BASE, + .size = 32 * PAGE_SIZE, + .init = init_ring_common, + .write_tail = gen6_bsd_ring_write_tail, + .flush = gen6_ring_flush, + .add_request = gen6_add_request, + .get_seqno = ring_get_seqno, + .irq_get = gen6_bsd_ring_get_irq, + .irq_put = gen6_bsd_ring_put_irq, + .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, }; /* Blitter support (SandyBridge+) */ static void -blt_ring_get_user_irq(struct intel_ring_buffer *ring) +blt_ring_get_irq(struct intel_ring_buffer *ring) { - /* do nothing */ + ring_get_irq(ring, GT_BLT_USER_INTERRUPT); } + static void -blt_ring_put_user_irq(struct intel_ring_buffer *ring) +blt_ring_put_irq(struct intel_ring_buffer *ring) { - /* do nothing */ + ring_put_irq(ring, GT_BLT_USER_INTERRUPT); } @@ -994,6 +1111,9 @@ static void blt_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + return; + if (blt_ring_begin(ring, 4) == 0) { intel_ring_emit(ring, MI_FLUSH_DW); intel_ring_emit(ring, 0); @@ -1003,30 +1123,6 @@ static void blt_ring_flush(struct intel_ring_buffer *ring, } } -static int -blt_ring_add_request(struct intel_ring_buffer *ring, - u32 *result) -{ - u32 seqno; - int ret; - - ret = blt_ring_begin(ring, 4); - if (ret) - return ret; - - seqno = i915_gem_get_seqno(ring->dev); - - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); - - DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); - *result = seqno; - return 0; -} - static void blt_ring_cleanup(struct intel_ring_buffer *ring) { if (!ring->private) @@ -1045,10 +1141,10 @@ static const struct intel_ring_buffer gen6_blt_ring = { .init = blt_ring_init, .write_tail = ring_write_tail, .flush = blt_ring_flush, - .add_request = blt_ring_add_request, - .get_seqno = ring_status_page_get_seqno, - .user_irq_get = blt_ring_get_user_irq, - .user_irq_put = blt_ring_put_user_irq, + .add_request = gen6_add_request, + .get_seqno = ring_get_seqno, + .irq_get = blt_ring_get_irq, + .irq_put = blt_ring_put_irq, .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, .cleanup = blt_ring_cleanup, }; @@ -1056,36 +1152,43 @@ static const struct intel_ring_buffer gen6_blt_ring = { int intel_init_render_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; - dev_priv->render_ring = render_ring; + *ring = render_ring; + if (INTEL_INFO(dev)->gen >= 6) { + ring->add_request = gen6_add_request; + } else if (HAS_PIPE_CONTROL(dev)) { + ring->add_request = pc_render_add_request; + ring->get_seqno = pc_render_get_seqno; + } if (!I915_NEED_GFX_HWS(dev)) { - dev_priv->render_ring.status_page.page_addr - = dev_priv->status_page_dmah->vaddr; - memset(dev_priv->render_ring.status_page.page_addr, - 0, PAGE_SIZE); + ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; + memset(ring->status_page.page_addr, 0, PAGE_SIZE); } - return intel_init_ring_buffer(dev, &dev_priv->render_ring); + return intel_init_ring_buffer(dev, ring); } int intel_init_bsd_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[VCS]; if (IS_GEN6(dev)) - dev_priv->bsd_ring = gen6_bsd_ring; + *ring = gen6_bsd_ring; else - dev_priv->bsd_ring = bsd_ring; + *ring = bsd_ring; - return intel_init_ring_buffer(dev, &dev_priv->bsd_ring); + return intel_init_ring_buffer(dev, ring); } int intel_init_blt_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[BCS]; - dev_priv->blt_ring = gen6_blt_ring; + *ring = gen6_blt_ring; - return intel_init_ring_buffer(dev, &dev_priv->blt_ring); + return intel_init_ring_buffer(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8e3526777926..6a3822bc6af2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -1,6 +1,13 @@ #ifndef _INTEL_RINGBUFFER_H_ #define _INTEL_RINGBUFFER_H_ +enum { + RCS = 0x0, + VCS, + BCS, + I915_NUM_RINGS, +}; + struct intel_hw_status_page { u32 __iomem *page_addr; unsigned int gfx_addr; @@ -21,7 +28,10 @@ struct intel_hw_status_page { #define I915_READ_CTL(ring) I915_RING_READ(RING_CTL(ring->mmio_base)) #define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val) -struct drm_i915_gem_execbuffer2; +#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID(ring->mmio_base)) +#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0(ring->mmio_base)) +#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1(ring->mmio_base)) + struct intel_ring_buffer { const char *name; enum intel_ring_id { @@ -42,9 +52,10 @@ struct intel_ring_buffer { u32 irq_seqno; /* last seq seem at irq time */ u32 waiting_seqno; - int user_irq_refcount; - void (*user_irq_get)(struct intel_ring_buffer *ring); - void (*user_irq_put)(struct intel_ring_buffer *ring); + u32 sync_seqno[I915_NUM_RINGS-1]; + u32 irq_refcount; + void (*irq_get)(struct intel_ring_buffer *ring); + void (*irq_put)(struct intel_ring_buffer *ring); int (*init)(struct intel_ring_buffer *ring); @@ -98,6 +109,25 @@ struct intel_ring_buffer { void *private; }; +static inline u32 +intel_ring_sync_index(struct intel_ring_buffer *ring, + struct intel_ring_buffer *other) +{ + int idx; + + /* + * cs -> 0 = vcs, 1 = bcs + * vcs -> 0 = bcs, 1 = cs, + * bcs -> 0 = cs, 1 = vcs. + */ + + idx = (other - ring) - 1; + if (idx < 0) + idx += I915_NUM_RINGS; + + return idx; +} + static inline u32 intel_read_status_page(struct intel_ring_buffer *ring, int reg) @@ -119,6 +149,9 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring, void intel_ring_advance(struct intel_ring_buffer *ring); u32 intel_ring_get_seqno(struct intel_ring_buffer *ring); +int intel_ring_sync(struct intel_ring_buffer *ring, + struct intel_ring_buffer *to, + u32 seqno); int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 2f7681989316..93206e4eaa6f 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1245,10 +1245,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv) int type; /* Disable TV interrupts around load detect or we'll recurse */ - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - i915_disable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, 0, + PIPE_HOTPLUG_INTERRUPT_ENABLE | PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); save_tv_dac = tv_dac = I915_READ(TV_DAC); save_tv_ctl = tv_ctl = I915_READ(TV_CTL); @@ -1301,10 +1302,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv) I915_WRITE(TV_CTL, save_tv_ctl); /* Restore interrupt config */ - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, 0, + PIPE_HOTPLUG_INTERRUPT_ENABLE | PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); return type; } -- cgit v1.2.3 From f7746f0e1f271fbc64b57c29873c47f73e28e5a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Dec 2010 23:48:40 +0000 Subject: drm/i915: Enable self-refresh for Ironlake We disabled this a while ago as it was inexplicably broken. However, it now appears to work... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b6272a2edfc..83446b55f731 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3456,7 +3456,7 @@ static void ironlake_update_wm(struct drm_device *dev, * display plane is used. */ tmp = 0; - if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) { + if (enabled == 1) { unsigned long line_time_us; int small, large, plane_fbc; int sr_clock, entries; -- cgit v1.2.3 From 160b1543cdae83e9f8914ac7afc3d2bd686140af Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 14:54:05 +0000 Subject: drm/i915/dp: Trivial code tidy Locally scope the crtc to where it is used. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1d8d068bc473..2c9601f2f208 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1374,7 +1374,6 @@ intel_dp_link_down(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); uint32_t DP = intel_dp->DP; DRM_DEBUG_KMS("\n"); @@ -1401,6 +1400,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) DP |= DP_LINK_TRAIN_OFF; if (!HAS_PCH_CPT(dev) && (DP & DP_PIPEB_SELECT)) { + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + /* Hardware workaround: leaving our transcoder select * set to transcoder B while it's off will prevent the * corresponding HDMI output on transcoder A. @@ -1415,8 +1416,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - intel_wait_for_vblank(intel_dp->base.base.dev, - intel_crtc->pipe); + intel_wait_for_vblank(dev, intel_crtc->pipe); } I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); -- cgit v1.2.3 From 88f23b8fa3e6357c423af24ec31c661fc12f884b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 15:08:31 +0000 Subject: drm/i915: Avoid using PIPE_CONTROL on Ironlake The workaround is hideous and we are using the STORE_DWORD on all other generations on all other rings, so use for the gen5 render ring as well. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 4 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 159 +------------------------------- 2 files changed, 4 insertions(+), 159 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5e831b7eb3f1..02e4dd82f754 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -349,7 +349,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) READ_BREADCRUMB(dev_priv); } - if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) + if (gt_iir & GT_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[RCS]); if (gt_iir & bsd_usr_interrupt) notify_ring(dev, &dev_priv->ring[VCS]); @@ -1556,7 +1556,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) GT_BLT_USER_INTERRUPT; else render_irqs = - GT_PIPE_NOTIFY | + GT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f71db0cf4909..0ee78525959a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -207,78 +207,6 @@ static int init_ring_common(struct intel_ring_buffer *ring) return 0; } -/* - * 965+ support PIPE_CONTROL commands, which provide finer grained control - * over cache flushing. - */ -struct pipe_control { - struct drm_i915_gem_object *obj; - volatile u32 *cpu_page; - u32 gtt_offset; -}; - -static int -init_pipe_control(struct intel_ring_buffer *ring) -{ - struct pipe_control *pc; - struct drm_i915_gem_object *obj; - int ret; - - if (ring->private) - return 0; - - pc = kmalloc(sizeof(*pc), GFP_KERNEL); - if (!pc) - return -ENOMEM; - - obj = i915_gem_alloc_object(ring->dev, 4096); - if (obj == NULL) { - DRM_ERROR("Failed to allocate seqno page\n"); - ret = -ENOMEM; - goto err; - } - obj->agp_type = AGP_USER_CACHED_MEMORY; - - ret = i915_gem_object_pin(obj, 4096, true); - if (ret) - goto err_unref; - - pc->gtt_offset = obj->gtt_offset; - pc->cpu_page = kmap(obj->pages[0]); - if (pc->cpu_page == NULL) - goto err_unpin; - - pc->obj = obj; - ring->private = pc; - return 0; - -err_unpin: - i915_gem_object_unpin(obj); -err_unref: - drm_gem_object_unreference(&obj->base); -err: - kfree(pc); - return ret; -} - -static void -cleanup_pipe_control(struct intel_ring_buffer *ring) -{ - struct pipe_control *pc = ring->private; - struct drm_i915_gem_object *obj; - - if (!ring->private) - return; - - obj = pc->obj; - kunmap(obj->pages[0]); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - - kfree(pc); - ring->private = NULL; -} - static int init_render_ring(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -292,24 +220,9 @@ static int init_render_ring(struct intel_ring_buffer *ring) I915_WRITE(MI_MODE, mode); } - if (INTEL_INFO(dev)->gen >= 6) { - } else if (HAS_PIPE_CONTROL(dev)) { - ret = init_pipe_control(ring); - if (ret) - return ret; - } - return ret; } -static void render_ring_cleanup(struct intel_ring_buffer *ring) -{ - if (!ring->private) - return; - - cleanup_pipe_control(ring); -} - static void update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno) { @@ -384,62 +297,6 @@ intel_ring_sync(struct intel_ring_buffer *ring, return 0; } -#define PIPE_CONTROL_FLUSH(ring__, addr__) \ -do { \ - intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ - PIPE_CONTROL_DEPTH_STALL | 2); \ - intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT); \ - intel_ring_emit(ring__, 0); \ - intel_ring_emit(ring__, 0); \ -} while (0) - -static int -pc_render_add_request(struct intel_ring_buffer *ring, - u32 *result) -{ - struct drm_device *dev = ring->dev; - u32 seqno = i915_gem_get_seqno(dev); - struct pipe_control *pc = ring->private; - u32 scratch_addr = pc->gtt_offset + 128; - int ret; - - /* - * Workaround qword write incoherence by flushing the - * PIPE_NOTIFY buffers out to memory before requesting - * an interrupt. - */ - ret = intel_ring_begin(ring, 32); - if (ret) - return ret; - - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(ring, scratch_addr); - intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | - PIPE_CONTROL_NOTIFY); - intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); - - *result = seqno; - return 0; -} - static int render_ring_add_request(struct intel_ring_buffer *ring, u32 *result) @@ -468,13 +325,6 @@ ring_get_seqno(struct intel_ring_buffer *ring) return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } -static u32 -pc_render_get_seqno(struct intel_ring_buffer *ring) -{ - struct pipe_control *pc = ring->private; - return pc->cpu_page[0]; -} - static void render_ring_get_irq(struct intel_ring_buffer *ring) { @@ -488,7 +338,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring) if (HAS_PCH_SPLIT(dev)) ironlake_enable_graphics_irq(dev_priv, - GT_PIPE_NOTIFY | GT_USER_INTERRUPT); + GT_USER_INTERRUPT); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); @@ -509,8 +359,7 @@ render_ring_put_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) ironlake_disable_graphics_irq(dev_priv, - GT_USER_INTERRUPT | - GT_PIPE_NOTIFY); + GT_USER_INTERRUPT); else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -922,7 +771,6 @@ static const struct intel_ring_buffer render_ring = { .irq_get = render_ring_get_irq, .irq_put = render_ring_put_irq, .dispatch_execbuffer = render_ring_dispatch_execbuffer, - .cleanup = render_ring_cleanup, }; /* ring buffer for bit-stream decoder */ @@ -1157,9 +1005,6 @@ int intel_init_render_ring_buffer(struct drm_device *dev) *ring = render_ring; if (INTEL_INFO(dev)->gen >= 6) { ring->add_request = gen6_add_request; - } else if (HAS_PIPE_CONTROL(dev)) { - ring->add_request = pc_render_add_request; - ring->get_seqno = pc_render_get_seqno; } if (!I915_NEED_GFX_HWS(dev)) { -- cgit v1.2.3 From 3c8cdf9b60b98c5b408e2cfbcab3160e25e5af5a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 16:45:02 +0000 Subject: drm/i915: Power Context register is only available for gen4 mobiles The ability to save the hardware context upon powering down the render clock through PWRCTXA is only available on a couple of gen4 chipsets. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a95c69392afc..aba1c33f6407 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5973,7 +5973,7 @@ void intel_init_clock_gating(struct drm_device *dev) "Disable RC6\n"); } - if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { + if (IS_GEN4(dev) && IS_MOBILE(dev)) { if (dev_priv->pwrctx == NULL) dev_priv->pwrctx = intel_alloc_context_page(dev); if (dev_priv->pwrctx) { -- cgit v1.2.3 From e3c4e5dd5ad1993a3687862c982272f8f00cae30 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 16:49:51 +0000 Subject: drm/i915: caps.has_rc6 is no longer used, remove it. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 1 - drivers/gpu/drm/i915/i915_drv.c | 6 +++--- drivers/gpu/drm/i915/i915_drv.h | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aedb02157474..22821994b35a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -73,7 +73,6 @@ static int i915_capabilities(struct seq_file *m, void *data) B(is_broadwater); B(is_crestline); B(has_fbc); - B(has_rc6); B(has_pipe_cxsr); B(has_hotplug); B(cursor_needs_physical); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 413a040386a9..91a3ad2cf942 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -111,7 +111,7 @@ static const struct intel_device_info intel_i965g_info = { static const struct intel_device_info intel_i965gm_info = { .gen = 4, .is_crestline = 1, - .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, .has_overlay = 1, .supports_tv = 1, }; @@ -130,7 +130,7 @@ static const struct intel_device_info intel_g45_info = { static const struct intel_device_info intel_gm45_info = { .gen = 4, .is_g4x = 1, - .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, + .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, .supports_tv = 1, .has_bsd_ring = 1, @@ -150,7 +150,7 @@ static const struct intel_device_info intel_ironlake_d_info = { static const struct intel_device_info intel_ironlake_m_info = { .gen = 5, .is_mobile = 1, - .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1, + .need_gfx_hws = 1, .has_hotplug = 1, .has_fbc = 0, /* disabled due to buggy hardware */ .has_bsd_ring = 1, }; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8b19b5806230..d9b54a27ccf8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -223,7 +223,6 @@ struct intel_device_info { u8 is_broadwater : 1; u8 is_crestline : 1; u8 has_fbc : 1; - u8 has_rc6 : 1; u8 has_pipe_cxsr : 1; u8 has_hotplug : 1; u8 cursor_needs_physical : 1; @@ -930,7 +929,6 @@ enum intel_chip_family { #define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2) #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) -#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6) #define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev)) #define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev)) -- cgit v1.2.3 From 9b3826bf8420e7280d9fffa233d93a7b85dcb1db Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 17:11:54 +0000 Subject: drm/i915: Ignore fenced commands for gpu access on gen4 Userspace should not have been declaring that it needed fenced GPU access with gen4+ as those GPUs have no fenced commands, but to be on the safe side it is easier to ignore userspace in case they did. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6fc9cc485781..1b2ceacd64f0 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -432,6 +432,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_i915_gem_object *obj; struct drm_i915_gem_exec_object2 *entry; int ret, retry; + bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; /* Attempt to pin all of the buffers into the GTT. * This is done in 3 phases: @@ -460,6 +461,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, } need_fence = + has_fenced_gpu_access && entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; need_mappable = @@ -484,6 +486,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, bool need_fence; need_fence = + has_fenced_gpu_access && entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; @@ -498,18 +501,20 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, break; } - if (need_fence) { - ret = i915_gem_object_get_fence(obj, ring, 1); - if (ret) - break; - } else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE && - obj->tiling_mode == I915_TILING_NONE) { - /* XXX pipelined! */ - ret = i915_gem_object_put_fence(obj); - if (ret) - break; + if (has_fenced_gpu_access) { + if (need_fence) { + ret = i915_gem_object_get_fence(obj, ring, 1); + if (ret) + break; + } else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode == I915_TILING_NONE) { + /* XXX pipelined! */ + ret = i915_gem_object_put_fence(obj); + if (ret) + break; + } + obj->pending_fenced_gpu_access = need_fence; } - obj->pending_fenced_gpu_access = need_fence; entry->offset = obj->gtt_offset; entry++; -- cgit v1.2.3 From 0cdab21f9a1fca50dd27e488839f5a6578e333b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 17:27:06 +0000 Subject: drm/i915: Uncouple render/power ctx before suspending Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_suspend.c | 4 ++- drivers/gpu/drm/i915/intel_display.c | 55 ++++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 3 +- 3 files changed, 36 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 011325e51e3a..a311809f3c80 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -820,6 +820,8 @@ int i915_save_state(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) ironlake_disable_drps(dev); + intel_disable_clock_gating(dev); + /* Cache mode state */ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); @@ -863,7 +865,7 @@ int i915_restore_state(struct drm_device *dev) } /* Clock gating state */ - intel_init_clock_gating(dev); + intel_enable_clock_gating(dev); if (HAS_PCH_SPLIT(dev)) { ironlake_enable_drps(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aba1c33f6407..31fc1d797f8f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5828,7 +5828,7 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } -void intel_init_clock_gating(struct drm_device *dev) +void intel_enable_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5985,6 +5985,33 @@ void intel_init_clock_gating(struct drm_device *dev) } } +void intel_disable_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->renderctx) { + struct drm_i915_gem_object *obj = dev_priv->renderctx; + + I915_WRITE(CCID, 0); + POSTING_READ(CCID); + + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + dev_priv->renderctx = NULL; + } + + if (dev_priv->pwrctx) { + struct drm_i915_gem_object *obj = dev_priv->pwrctx; + + I915_WRITE(PWRCTXA, 0); + POSTING_READ(PWRCTXA); + + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + dev_priv->pwrctx = NULL; + } +} + /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) { @@ -6211,7 +6238,7 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); - intel_init_clock_gating(dev); + intel_enable_clock_gating(dev); /* Just disable it once at startup */ i915_disable_vga(dev); @@ -6252,31 +6279,11 @@ void intel_modeset_cleanup(struct drm_device *dev) if (dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - if (dev_priv->renderctx) { - struct drm_i915_gem_object *obj = dev_priv->renderctx; - - I915_WRITE(CCID, obj->gtt_offset &~ CCID_EN); - POSTING_READ(CCID); - - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - dev_priv->renderctx = NULL; - } - - if (dev_priv->pwrctx) { - struct drm_i915_gem_object *obj = dev_priv->pwrctx; - - I915_WRITE(PWRCTXA, obj->gtt_offset &~ PWRCTX_EN); - POSTING_READ(PWRCTXA); - - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - dev_priv->pwrctx = NULL; - } - if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); + intel_disable_clock_gating(dev); + mutex_unlock(&dev->struct_mutex); /* Disable the irq before mode object teardown, for the irq might diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7273c9e7e0dc..acdea6549ec4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -294,7 +294,8 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno); -extern void intel_init_clock_gating(struct drm_device *dev); +extern void intel_enable_clock_gating(struct drm_device *dev); +extern void intel_disable_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev); -- cgit v1.2.3 From 6bda10d152735c22baf1dcd92937420b4b0a359a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Dec 2010 21:04:18 +0000 Subject: drm/i915: Completely disable fence pipelining. I'm still seeing tiling corruption of PutImage and CopyArea (I think) under mutter on pnv, so obviously the pipelining logic is deeply flawed. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index eeed2e99d247..8685b9279029 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2484,6 +2484,9 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *reg; int ret; + /* XXX disable pipelining. There are bugs. Shocking. */ + pipelined = NULL; + /* Just update our place in the LRU if our fence is getting reused. */ if (obj->fence_reg != I915_FENCE_REG_NONE) { reg = &dev_priv->fence_regs[obj->fence_reg]; @@ -2556,9 +2559,8 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, if (old->tiling_mode) i915_gem_release_mmap(old); - /* XXX The pipelined change over appears to be incoherent. */ ret = i915_gem_object_flush_fence(old, - NULL, //pipelined, + pipelined, interruptible); if (ret) { drm_gem_object_unreference(&old->base); -- cgit v1.2.3 From 0ac74c6b3386f0413baf48f6d61850650e0dc4ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Dec 2010 14:36:02 +0000 Subject: drm/i915: Only emit a flush if there is an outstanding gpu write Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8685b9279029..e7733333767d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2154,8 +2154,9 @@ static int i915_ring_idle(struct drm_device *dev, if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list)) return 0; - i915_gem_flush_ring(dev, ring, - I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + if (!list_empty(&ring->gpu_write_list)) + i915_gem_flush_ring(dev, ring, + I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); return i915_wait_request(dev, i915_gem_next_request_seqno(dev, ring), ring); -- cgit v1.2.3 From 0be732841fb925b6f1242211ea211c022b6ac26c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Dec 2010 14:36:27 +0000 Subject: drm/i915: Wait for the bo if a display flip is pipelined on the other ring Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e7733333767d..b57ce033e42a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2926,7 +2926,7 @@ i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, i915_gem_object_flush_gpu_write_domain(obj); /* Currently, we are always called from an non-interruptible context. */ - if (!pipelined) { + if (pipelined != obj->ring) { ret = i915_gem_object_wait_rendering(obj, false); if (ret) return ret; -- cgit v1.2.3 From 98ede2ed46cef38e98c8341d410323895f60570e Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 16:30:36 -0800 Subject: staging: brcm80211: OSLREGOPS is unused, remove checks for it. Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/osl.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 2368c80db60a..b543bbbae3da 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -128,8 +128,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define bcopy(src, dst, len) memcpy((dst), (src), (len)) /* register access macros */ -#if defined(OSLREGOPS) -#else #ifndef IL_BIGENDIAN #ifndef __mips__ #define R_REG(osh, r) (\ @@ -220,8 +218,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, } while (0) #endif /* IL_BIGENDIAN */ -#endif /* OSLREGOPS */ - #define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) #define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -- cgit v1.2.3 From 7a9b48b3d3e0f373dc996efde56a5bff0944d8de Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 16:30:37 -0800 Subject: staging: brcm80211: Move osl_pub into osl Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/osl.h | 20 ++++++++------------ drivers/staging/brcm80211/include/siutils.h | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 6 +++--- drivers/staging/brcm80211/util/linux_osl.c | 8 ++++---- drivers/staging/brcm80211/util/siutils.c | 2 +- 5 files changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index b543bbbae3da..2cea5c122c3a 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -17,14 +17,10 @@ #ifndef _osl_h_ #define _osl_h_ -struct osl_pubinfo { - uint pktalloced; /* Number of allocated packet buffers */ - bool mmbus; /* Bus supports memory-mapped registers */ -}; - /* osl handle type forward declaration */ struct osl_info { - struct osl_pubinfo pub; + uint pktalloced; /* Number of allocated packet buffers */ + bool mmbus; /* Bus supports memory-mapped registers */ uint magic; void *pdev; uint bustype; @@ -106,10 +102,10 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #if defined(BCMSDIO) #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) \ - if (((struct osl_pubinfo *)(osh))->mmbus) \ + if ((osh)->mmbus) \ mmap_op else bus_op #define SELECT_BUS_READ(osh, mmap_op, bus_op) \ - (((struct osl_pubinfo *)(osh))->mmbus) ? mmap_op : bus_op + ((osh)->mmbus) ? mmap_op : bus_op #else #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) mmap_op #define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op @@ -255,7 +251,7 @@ extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); #ifdef BRCM_FULLMAC static inline void * -osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) +osl_pkt_frmnative(struct osl_info *osh, struct sk_buff *skb) { struct sk_buff *nskb; @@ -265,10 +261,10 @@ osl_pkt_frmnative(struct osl_pubinfo *osh, struct sk_buff *skb) return (void *)skb; } #define PKTFRMNATIVE(osh, skb) \ - osl_pkt_frmnative(((struct osl_pubinfo *)osh), (struct sk_buff*)(skb)) + osl_pkt_frmnative((osh), (struct sk_buff *)(skb)) static inline struct sk_buff * -osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) +osl_pkt_tonative(struct osl_info *osh, void *pkt) { struct sk_buff *nskb; @@ -278,7 +274,7 @@ osl_pkt_tonative(struct osl_pubinfo *osh, void *pkt) return (struct sk_buff *)pkt; } #define PKTTONATIVE(osh, pkt) \ - osl_pkt_tonative((struct osl_pubinfo *)(osh), (pkt)) + osl_pkt_tonative((osh), (pkt)) #else /* !BRCM_FULLMAC */ #define PKTSETSKIPCT(osh, skb) #define PKTCLRSKIPCT(osh, skb) diff --git a/drivers/staging/brcm80211/include/siutils.h b/drivers/staging/brcm80211/include/siutils.h index d6115cdd94f6..a935092d02df 100644 --- a/drivers/staging/brcm80211/include/siutils.h +++ b/drivers/staging/brcm80211/include/siutils.h @@ -128,7 +128,7 @@ extern uint si_coreid(si_t *sih); extern uint si_flag(si_t *sih); extern uint si_coreidx(si_t *sih); extern uint si_corerev(si_t *sih); -extern void *si_osh(si_t *sih); +struct osl_info *si_osh(si_t *sih); extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); extern void si_write_wrapperreg(si_t *sih, u32 offset, u32 val); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 9aae3405aa11..fcd3bd18f27c 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -2733,9 +2733,9 @@ uint wlc_down(wlc_info_t *wlc) /* Verify all packets are flushed from the driver */ - if (wlc->osh->pub.pktalloced != 0) { + if (wlc->osh->pktalloced != 0) { WL_ERROR(("%d packets not freed at wlc_down!!!!!!\n", - wlc->osh->pub.pktalloced)); + wlc->osh->pktalloced)); } #ifdef BCMDBG /* Since all the packets should have been freed, @@ -6935,7 +6935,7 @@ wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p); WLCNTINCR(wlc->pub->_cnt->ieee_rx); - osh->pub.pktalloced--; + osh->pktalloced--; return; } diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 6a06d61568b9..2efce7aeec78 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -53,14 +53,14 @@ struct osl_info *osl_attach(void *pdev, uint bustype) case PCI_BUS: case SI_BUS: case PCMCIA_BUS: - osh->pub.mmbus = true; + osh->mmbus = true; break; case JTAG_BUS: case SDIO_BUS: case USB_BUS: case SPI_BUS: case RPC_BUS: - osh->pub.mmbus = false; + osh->mmbus = false; break; default: ASSERT(false); @@ -88,7 +88,7 @@ void *BCMFASTPATH osl_pktget(struct osl_info *osh, uint len) skb_put(skb, len); skb->priority = 0; - osh->pub.pktalloced++; + osh->pktalloced++; } return (void *)skb; @@ -119,7 +119,7 @@ void BCMFASTPATH osl_pktfree(struct osl_info *osh, void *p, bool send) */ dev_kfree_skb(skb); - osh->pub.pktalloced--; + osh->pktalloced--; nest++; skb = nskb; } diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 29d2d68354f6..59167122943c 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -729,7 +729,7 @@ void si_detach(si_t *sih) kfree(sii); } -void *si_osh(si_t *sih) +struct osl_info *si_osh(si_t *sih) { si_info_t *sii; -- cgit v1.2.3 From ec7957049668b4fcf755cd8a085cfe258d77fc9b Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 16:30:38 -0800 Subject: staging: brcm80211: Remove unused softmac macros Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/osl.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 2cea5c122c3a..f722db59173e 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -275,10 +275,6 @@ osl_pkt_tonative(struct osl_info *osh, void *pkt) } #define PKTTONATIVE(osh, pkt) \ osl_pkt_tonative((osh), (pkt)) -#else /* !BRCM_FULLMAC */ -#define PKTSETSKIPCT(osh, skb) -#define PKTCLRSKIPCT(osh, skb) -#define PKTSKIPCT(osh, skb) #endif /* BRCM_FULLMAC */ #define PKTSUMNEEDED(skb) \ -- cgit v1.2.3 From 411ee44ad30b2a8c99c3b225a3cf381ec37b000e Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 16:30:39 -0800 Subject: staging: brcm80211: move fullmac-only code from osl to fullmac files Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 9 +++++++ drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 26 ++++++++++++++++++ drivers/staging/brcm80211/include/osl.h | 37 -------------------------- 3 files changed, 35 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c index 2fa77cb53040..b3fc2a3eb957 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c @@ -298,6 +298,15 @@ done: return ret; } +#define PKTSUMNEEDED(skb) \ + (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL) +#define PKTSETSUMGOOD(skb, x) \ + (((struct sk_buff *)(skb))->ip_summed = \ + ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) + +/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because + skb->ip_summed is overloaded */ + int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, void *params, int plen, void *arg, int len, bool set) diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 7f66d7a84b6e..a114deed3134 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1052,6 +1052,32 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf) return ret; } +static inline void * +osl_pkt_frmnative(struct osl_info *osh, struct sk_buff *skb) +{ + struct sk_buff *nskb; + + for (nskb = skb; nskb; nskb = nskb->next) + osh->pktalloced++; + + return (void *)skb; +} +#define PKTFRMNATIVE(osh, skb) \ + osl_pkt_frmnative((osh), (struct sk_buff *)(skb)) + +static inline struct sk_buff * +osl_pkt_tonative(struct osl_info *osh, void *pkt) +{ + struct sk_buff *nskb; + + for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) + osh->pktalloced--; + + return (struct sk_buff *)pkt; +} +#define PKTTONATIVE(osh, pkt) \ + osl_pkt_tonative((osh), (pkt)) + static int dhd_start_xmit(struct sk_buff *skb, struct net_device *net) { int ret; diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index f722db59173e..4e7d07e38782 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -249,43 +249,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, extern void *osl_pktget(struct osl_info *osh, uint len); extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); -#ifdef BRCM_FULLMAC -static inline void * -osl_pkt_frmnative(struct osl_info *osh, struct sk_buff *skb) -{ - struct sk_buff *nskb; - - for (nskb = skb; nskb; nskb = nskb->next) - osh->pktalloced++; - - return (void *)skb; -} -#define PKTFRMNATIVE(osh, skb) \ - osl_pkt_frmnative((osh), (struct sk_buff *)(skb)) - -static inline struct sk_buff * -osl_pkt_tonative(struct osl_info *osh, void *pkt) -{ - struct sk_buff *nskb; - - for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) - osh->pktalloced--; - - return (struct sk_buff *)pkt; -} -#define PKTTONATIVE(osh, pkt) \ - osl_pkt_tonative((osh), (pkt)) -#endif /* BRCM_FULLMAC */ - -#define PKTSUMNEEDED(skb) \ - (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL) -#define PKTSETSUMGOOD(skb, x) \ - (((struct sk_buff *)(skb))->ip_summed = \ - ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) -/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because - skb->ip_summed is overloaded */ - - #define SET_REG(osh, r, mask, val) \ W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) -- cgit v1.2.3 From 8968af14f8e2d636fa5b4c055e240c1f359b8716 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 18:00:24 -0800 Subject: staging: brcm80211: move dma specific macros from osl to dma code Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmutils.h | 8 ++++++++ drivers/staging/brcm80211/include/osl.h | 23 ----------------------- drivers/staging/brcm80211/util/hnddma.c | 16 ++++++++++++---- drivers/staging/brcm80211/util/siutils.c | 2 +- 4 files changed, 21 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h index e673dfd21622..3628fd6a997b 100644 --- a/drivers/staging/brcm80211/include/bcmutils.h +++ b/drivers/staging/brcm80211/include/bcmutils.h @@ -361,6 +361,14 @@ extern struct sk_buff *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); #define CEIL(x, y) (((x) + ((y)-1)) / (y)) #define ISPOWEROF2(x) ((((x)-1)&(x)) == 0) +/* map physical to virtual I/O */ +#if !defined(CONFIG_MMC_MSM7X00A) +#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), \ + (unsigned long)(size)) +#else +#define REG_MAP(pa, size) (void *)(0) +#endif + /* bit map related macros */ #ifndef setbit #ifndef NBBY /* the BSD family defines NBBY */ diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 4e7d07e38782..b066f1473468 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -219,29 +219,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define bcopy(src, dst, len) memcpy((dst), (src), (len)) -/* uncached/cached virtual address */ -#ifdef __mips__ -#include -#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va))) -#define OSL_CACHED(va) ((void *)KSEG0ADDR((va))) -#else -#define OSL_UNCACHED(va) ((void *)va) -#define OSL_CACHED(va) ((void *)va) -#endif /* mips */ - -/* map/unmap physical to virtual I/O */ -#if !defined(CONFIG_MMC_MSM7X00A) -#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), \ - (unsigned long)(size)) -#else -#define REG_MAP(pa, size) (void *)(0) -#endif /* !defined(CONFIG_MMC_MSM7X00A */ -#define REG_UNMAP(va) iounmap((va)) - -#define R_SM(r) (*(r)) -#define W_SM(r, v) (*(r) = (v)) -#define BZERO_SM(r, len) memset((r), '\0', (len)) - /* packet primitives */ #define PKTGET(osh, len, send) osl_pktget((osh), (len)) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index 996998d805e0..0c8a1d25d98b 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -29,6 +29,10 @@ #include #include +#if defined(__mips__) +#include +#endif + /* debug/trace */ #ifdef BCMDBG #define DMA_ERROR(args) \ @@ -69,6 +73,9 @@ static uint dma_msg_level; #define DI_INFO(dmah) ((dma_info_t *)dmah) +#define R_SM(r) (*(r)) +#define W_SM(r, v) (*(r) = (v)) + /* dma engine software state */ typedef struct dma_info { struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t, @@ -903,7 +910,7 @@ static void _dma_rxinit(dma_info_t *di) /* clear rx descriptor ring */ if (DMA64_ENAB(di) && DMA64_MODE(di)) { - BZERO_SM((void *)di->rxd64, + memset((void *)di->rxd64, '\0', (di->nrxd * sizeof(dma64dd_t))); /* DMA engine with out alignment requirement requires table to be inited @@ -917,7 +924,7 @@ static void _dma_rxinit(dma_info_t *di) if (di->aligndesc_4k) _dma_ddtable_init(di, DMA_RX, di->rxdpa); } else if (DMA32_ENAB(di)) { - BZERO_SM((void *)di->rxd32, + memset((void *)di->rxd32, '\0', (di->nrxd * sizeof(dma32dd_t))); _dma_rxenable(di); _dma_ddtable_init(di, DMA_RX, di->rxdpa); @@ -993,6 +1000,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); #if defined(__mips__) +#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va))) if (!len) { while (!(len = *(u16 *) OSL_UNCACHED(head->data))) udelay(1); @@ -1436,7 +1444,7 @@ static void dma32_txinit(dma_info_t *di) di->hnddma.txavail = di->ntxd - 1; /* clear tx descriptor ring */ - BZERO_SM((void *)di->txd32, (di->ntxd * sizeof(dma32dd_t))); + memset((void *)di->txd32, '\0', (di->ntxd * sizeof(dma32dd_t))); if ((di->hnddma.dmactrlflags & DMA_CTRL_PEN) == 0) control |= XC_PD; @@ -1992,7 +2000,7 @@ static void dma64_txinit(dma_info_t *di) di->hnddma.txavail = di->ntxd - 1; /* clear tx descriptor ring */ - BZERO_SM((void *)di->txd64, (di->ntxd * sizeof(dma64dd_t))); + memset((void *)di->txd64, '\0', (di->ntxd * sizeof(dma64dd_t))); /* DMA engine with out alignment requirement requires table to be inited * before enabling the engine diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index 59167122943c..b66de9b35a5a 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -710,7 +710,7 @@ void si_detach(si_t *sih) if (sih->bustype == SI_BUS) for (idx = 0; idx < SI_MAXCORES; idx++) if (sii->regs[idx]) { - REG_UNMAP(sii->regs[idx]); + iounmap(sii->regs[idx]); sii->regs[idx] = NULL; } -- cgit v1.2.3 From 326a67977c15715d627525deade9e859f5cd5646 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 18:00:25 -0800 Subject: staging: brcm80211: migrate register ops macros to bcmutils.h Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/bcmutils.h | 8 +++++++- drivers/staging/brcm80211/include/osl.h | 6 ------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/bcmutils.h b/drivers/staging/brcm80211/include/bcmutils.h index 3628fd6a997b..a8f76d8199ff 100644 --- a/drivers/staging/brcm80211/include/bcmutils.h +++ b/drivers/staging/brcm80211/include/bcmutils.h @@ -369,7 +369,13 @@ extern struct sk_buff *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); #define REG_MAP(pa, size) (void *)(0) #endif -/* bit map related macros */ +/* Register operations */ +#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) +#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) + +#define SET_REG(osh, r, mask, val) \ + W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) + #ifndef setbit #ifndef NBBY /* the BSD family defines NBBY */ #define NBBY 8 /* 8 bits per byte */ diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index b066f1473468..c99920b52e9d 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -214,9 +214,6 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, } while (0) #endif /* IL_BIGENDIAN */ -#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) - #define bcopy(src, dst, len) memcpy((dst), (src), (len)) /* packet primitives */ @@ -226,7 +223,4 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, extern void *osl_pktget(struct osl_info *osh, uint len); extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); -#define SET_REG(osh, r, mask, val) \ - W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) - #endif /* _osl_h_ */ -- cgit v1.2.3 From e63449b7171fa19d1d2404179665d5ed146e8990 Mon Sep 17 00:00:00 2001 From: Brett Rudley Date: Fri, 3 Dec 2010 18:00:26 -0800 Subject: staging: brcm80211: Removing cruft from osl.h Signed-off-by: Brett Rudley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/osl.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index c99920b52e9d..54fdfd609729 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -29,15 +29,6 @@ struct osl_info { typedef struct osl_dmainfo osldma_t; -#ifdef BCMSDIO -/* Drivers use REGOPSSET() to register register read/write funcitons */ -typedef unsigned int (*osl_rreg_fn_t) (void *ctx, void *reg, unsigned int size); -typedef void (*osl_wreg_fn_t) (void *ctx, void *reg, unsigned int val, - unsigned int size); -#endif /* BCMSDIO */ - -#include - extern struct osl_info *osl_attach(void *pdev, uint bustype); extern void osl_detach(struct osl_info *osh); -- cgit v1.2.3 From c6a9e1fc715763175842014a83a9ea70f7e19ace Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Sat, 4 Dec 2010 08:38:02 +0100 Subject: staging: brcm80211: replaced wlc_info_t by struct wlc_info. Part of code cleanup effort. Global replace of wlc_info_t with struct wlc_info. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_alloc.c | 11 +- drivers/staging/brcm80211/sys/wlc_alloc.h | 6 +- drivers/staging/brcm80211/sys/wlc_ampdu.c | 29 +- drivers/staging/brcm80211/sys/wlc_ampdu.h | 4 +- drivers/staging/brcm80211/sys/wlc_antsel.c | 4 +- drivers/staging/brcm80211/sys/wlc_antsel.h | 3 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 74 ++--- drivers/staging/brcm80211/sys/wlc_bmac.h | 6 +- drivers/staging/brcm80211/sys/wlc_bsscfg.h | 3 +- drivers/staging/brcm80211/sys/wlc_channel.c | 30 +- drivers/staging/brcm80211/sys/wlc_event.h | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 452 ++++++++++++++------------- drivers/staging/brcm80211/sys/wlc_mac80211.h | 185 +++++------ drivers/staging/brcm80211/sys/wlc_pub.h | 8 +- drivers/staging/brcm80211/sys/wlc_scb.h | 2 +- drivers/staging/brcm80211/sys/wlc_stf.c | 54 ++-- drivers/staging/brcm80211/sys/wlc_stf.h | 31 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 18 files changed, 460 insertions(+), 446 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 659ebd0ee2de..980945a065fd 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -156,7 +156,7 @@ void wlc_bsscfg_mfree(struct osl_info *osh, wlc_bsscfg_t *cfg) kfree(cfg); } -void wlc_bsscfg_ID_assign(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg) +void wlc_bsscfg_ID_assign(struct wlc_info *wlc, wlc_bsscfg_t *bsscfg) { bsscfg->ID = wlc->next_bsscfg_ID; wlc->next_bsscfg_ID++; @@ -165,12 +165,13 @@ void wlc_bsscfg_ID_assign(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg) /* * The common driver entry routine. Error codes should be unique */ -wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, +struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, uint devid) { - wlc_info_t *wlc; + struct wlc_info *wlc; - wlc = (wlc_info_t *) wlc_calloc(osh, unit, sizeof(wlc_info_t)); + wlc = (struct wlc_info *) wlc_calloc(osh, unit, + sizeof(struct wlc_info)); if (wlc == NULL) { *err = 1002; goto fail; @@ -301,7 +302,7 @@ wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, return NULL; } -void wlc_detach_mfree(wlc_info_t *wlc, struct osl_info *osh) +void wlc_detach_mfree(struct wlc_info *wlc, struct osl_info *osh) { if (wlc == NULL) return; diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.h b/drivers/staging/brcm80211/sys/wlc_alloc.h index eedf62912698..ac34f782b400 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.h +++ b/drivers/staging/brcm80211/sys/wlc_alloc.h @@ -16,9 +16,9 @@ extern void *wlc_calloc(struct osl_info *osh, uint unit, uint size); -extern wlc_info_t *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, - uint devid); -extern void wlc_detach_mfree(wlc_info_t *wlc, struct osl_info *osh); +extern struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, + uint *err, uint devid); +extern void wlc_detach_mfree(struct wlc_info *wlc, struct osl_info *osh); struct wlc_bsscfg; extern struct wlc_bsscfg *wlc_bsscfg_malloc(struct osl_info *osh, uint unit); diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 86563b5860a2..9e1816b88108 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -98,7 +98,7 @@ typedef struct wlc_fifo_info { /* AMPDU module specific state */ struct ampdu_info { - wlc_info_t *wlc; /* pointer to main wlc structure */ + struct wlc_info *wlc; /* pointer to main wlc structure */ int scb_handle; /* scb cubby handle to retrieve data from scb */ u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */ u8 ba_tx_wsize; /* Tx ba window size (in pdu) */ @@ -131,7 +131,7 @@ struct ampdu_info { #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid])) static void wlc_ffpld_init(ampdu_info_t *ampdu); -static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int f); +static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f); static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f); static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu, @@ -149,7 +149,7 @@ static void wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, tx_status_t *txs, u32 frmtxstatus, u32 frmtxstatus2); -static inline u16 pkt_txh_seqnum(wlc_info_t *wlc, struct sk_buff *p) +static inline u16 pkt_txh_seqnum(struct wlc_info *wlc, struct sk_buff *p) { d11txh_t *txh; struct dot11_header *h; @@ -158,7 +158,7 @@ static inline u16 pkt_txh_seqnum(wlc_info_t *wlc, struct sk_buff *p) return ltoh16(h->seq) >> SEQNUM_SHIFT; } -ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc) +ampdu_info_t *wlc_ampdu_attach(struct wlc_info *wlc) { ampdu_info_t *ampdu; int i; @@ -317,7 +317,7 @@ static void wlc_ffpld_init(ampdu_info_t *ampdu) * Return 1 if pre-loading not active, -1 if not an underflow event, * 0 if pre-loading module took care of the event. */ -static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid) +static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) { ampdu_info_t *ampdu = wlc->ampdu; u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false); @@ -491,7 +491,7 @@ int BCMFASTPATH wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, int prec) { - wlc_info_t *wlc; + struct wlc_info *wlc; struct osl_info *osh; struct sk_buff *p, *pkt[AMPDU_MAX_MPDU]; u8 tid, ndelim; @@ -889,7 +889,7 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, tx_status_t *txs) { scb_ampdu_t *scb_ampdu; - wlc_info_t *wlc = ampdu->wlc; + struct wlc_info *wlc = ampdu->wlc; scb_ampdu_tid_ini_t *ini; u32 s1 = 0, s2 = 0; struct ieee80211_tx_info *tx_info; @@ -932,11 +932,8 @@ wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini); } -void rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info, - tx_status_t *txs, u8 mcs); - void -rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info, +rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info, tx_status_t *txs, u8 mcs) { struct ieee80211_tx_rate *txrate = tx_info->status.rates; @@ -957,7 +954,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, u32 s1, u32 s2) { scb_ampdu_t *scb_ampdu; - wlc_info_t *wlc = ampdu->wlc; + struct wlc_info *wlc = ampdu->wlc; scb_ampdu_tid_ini_t *ini; u8 bitmap[8], queue, tid; d11txh_t *txh; @@ -1226,7 +1223,7 @@ static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu, int wlc_ampdu_set(ampdu_info_t *ampdu, bool on) { - wlc_info_t *wlc = ampdu->wlc; + struct wlc_info *wlc = ampdu->wlc; wlc->pub->_ampdu = false; @@ -1313,7 +1310,7 @@ wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb, return 0; } -void wlc_ampdu_macaddr_upd(wlc_info_t *wlc) +void wlc_ampdu_macaddr_upd(struct wlc_info *wlc) { char template[T_RAM_ACCESS_SZ * 2]; @@ -1324,14 +1321,14 @@ void wlc_ampdu_macaddr_upd(wlc_info_t *wlc) template); } -bool wlc_aggregatable(wlc_info_t *wlc, u8 tid) +bool wlc_aggregatable(struct wlc_info *wlc, u8 tid) { return wlc->ampdu->ini_enable[tid]; } void wlc_ampdu_shm_upd(ampdu_info_t *ampdu) { - wlc_info_t *wlc = ampdu->wlc; + struct wlc_info *wlc = ampdu->wlc; /* Extend ucode internal watchdog timer to match larger received frames */ if ((ampdu->rx_factor & HT_PARAMS_RX_FACTOR_MASK) == diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.h b/drivers/staging/brcm80211/sys/wlc_ampdu.h index c86411beac11..4c3358da89e5 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.h +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.h @@ -17,7 +17,7 @@ #ifndef _wlc_ampdu_h_ #define _wlc_ampdu_h_ -extern ampdu_info_t *wlc_ampdu_attach(wlc_info_t *wlc); +extern ampdu_info_t *wlc_ampdu_attach(struct wlc_info *wlc); extern void wlc_ampdu_detach(ampdu_info_t *ampdu); extern bool wlc_ampdu_cap(ampdu_info_t *ampdu); extern int wlc_ampdu_set(ampdu_info_t *ampdu, bool on); @@ -26,7 +26,7 @@ extern int wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, extern void wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, tx_status_t *txs); extern void wlc_ampdu_reset(ampdu_info_t *ampdu); -extern void wlc_ampdu_macaddr_upd(wlc_info_t *wlc); +extern void wlc_ampdu_macaddr_upd(struct wlc_info *wlc); extern void wlc_ampdu_shm_upd(ampdu_info_t *ampdu); extern u8 wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb, diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index 4e4571a098f7..ee577c8c80f5 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -93,7 +93,7 @@ const u8 mimo_2x3_div_antselid_tbl[16] = { 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */ }; -antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, struct osl_info *osh, +antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, wlc_pub_t *pub, wlc_hw_info_t *wlc_hw) { antsel_info_t *asi; @@ -297,7 +297,7 @@ static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg) /* boardlevel antenna selection: ucode interface control */ static int wlc_antsel_cfgupd(antsel_info_t *asi, wlc_antselcfg_t *antsel) { - wlc_info_t *wlc = asi->wlc; + struct wlc_info *wlc = asi->wlc; u8 ant_cfg; u16 mimo_antsel; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.h b/drivers/staging/brcm80211/sys/wlc_antsel.h index f3361f8106e8..30c66dda77ee 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.h +++ b/drivers/staging/brcm80211/sys/wlc_antsel.h @@ -16,7 +16,8 @@ #ifndef _wlc_antsel_h_ #define _wlc_antsel_h_ -extern antsel_info_t *wlc_antsel_attach(wlc_info_t *wlc, struct osl_info *osh, +extern antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, + struct osl_info *osh, wlc_pub_t *pub, wlc_hw_info_t *wlc_hw); extern void wlc_antsel_detach(antsel_info_t *asi); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 79ee24f3b07f..2abee6f527f9 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -113,7 +113,7 @@ static u16 xmtfifo_sz[][NFIFO] = { }; static void wlc_clkctl_clk(wlc_hw_info_t *wlc, uint mode); -static void wlc_coreinit(wlc_info_t *wlc); +static void wlc_coreinit(struct wlc_info *wlc); /* used by wlc_wakeucode_init() */ static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits); @@ -130,7 +130,7 @@ static bool wlc_bmac_txstatus(wlc_hw_info_t *wlc, bool bound, bool *fatal); static bool wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound); /* used by wlc_down() */ -static void wlc_flushqueues(wlc_info_t *wlc); +static void wlc_flushqueues(struct wlc_info *wlc); static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs); static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw); @@ -141,25 +141,25 @@ static u16 wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset, u32 sel); static void wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v, u32 sel); -static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme); +static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme); static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw); static void wlc_ucode_bsinit(wlc_hw_info_t *wlc_hw); static bool wlc_validboardtype(wlc_hw_info_t *wlc); static bool wlc_isgoodchip(wlc_hw_info_t *wlc_hw); static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw); -static void wlc_mhfdef(wlc_info_t *wlc, u16 *mhfs, u16 mhf2_init); +static void wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init); static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw); static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw); static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw); -static u32 wlc_wlintrsoff(wlc_info_t *wlc); -static void wlc_wlintrsrestore(wlc_info_t *wlc, u32 macintmask); -static void wlc_gpio_init(wlc_info_t *wlc); +static u32 wlc_wlintrsoff(struct wlc_info *wlc); +static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask); +static void wlc_gpio_init(struct wlc_info *wlc); static void wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn, int len); static void wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn, int len); -static void wlc_bmac_bsinit(wlc_info_t *wlc, chanspec_t chanspec); -static u32 wlc_setband_inact(wlc_info_t *wlc, uint bandunit); +static void wlc_bmac_bsinit(struct wlc_info *wlc, chanspec_t chanspec); +static u32 wlc_setband_inact(struct wlc_info *wlc, uint bandunit); static void wlc_bmac_setband(wlc_hw_info_t *wlc_hw, uint bandunit, chanspec_t chanspec); static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot); @@ -231,7 +231,7 @@ static void WLBANDINITFN(wlc_ucode_bsinit) (wlc_hw_info_t *wlc_hw) } /* switch to new band but leave it inactive */ -static u32 WLBANDINITFN(wlc_setband_inact) (wlc_info_t *wlc, uint bandunit) +static u32 WLBANDINITFN(wlc_setband_inact) (struct wlc_info *wlc, uint bandunit) { wlc_hw_info_t *wlc_hw = wlc->hw; u32 macintmask; @@ -322,7 +322,7 @@ wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound) * Return true if another dpc needs to be re-scheduled. false otherwise. * Param 'bounded' indicates if applicable loops should be bounded. */ -bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded) +bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) { u32 macintstatus; wlc_hw_info_t *wlc_hw = wlc->hw; @@ -451,7 +451,7 @@ bool BCMFASTPATH wlc_dpc(wlc_info_t *wlc, bool bounded) /* common low-level watchdog code */ void wlc_bmac_watchdog(void *arg) { - wlc_info_t *wlc = (wlc_info_t *) arg; + struct wlc_info *wlc = (struct wlc_info *) arg; wlc_hw_info_t *wlc_hw = wlc->hw; WL_TRACE(("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit)); @@ -564,7 +564,7 @@ int wlc_bmac_state_get(wlc_hw_info_t *wlc_hw, wlc_bmac_state_t *state) return 0; } -static bool wlc_bmac_attach_dmapio(wlc_info_t *wlc, uint j, bool wme) +static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme) { uint i; char name[8]; @@ -700,7 +700,7 @@ static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw) * initialize software state for each core and band * put the whole chip in reset(driver down state), no clock */ -int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, +int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, bool piomode, struct osl_info *osh, void *regsva, uint bustype, void *btparam) { @@ -1045,7 +1045,7 @@ int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, uint unit, */ void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw) { - wlc_info_t *wlc = wlc_hw->wlc; + struct wlc_info *wlc = wlc_hw->wlc; /* set default sw macintmask value */ wlc->defmacintmask = DEF_MACINTMASK; @@ -1065,7 +1065,7 @@ void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw) /* * low level detach */ -int wlc_bmac_detach(wlc_info_t *wlc) +int wlc_bmac_detach(struct wlc_info *wlc) { uint i; wlc_hwband_t *band; @@ -1137,7 +1137,7 @@ wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, bool mute) { u32 macintmask; bool fastclk; - wlc_info_t *wlc = wlc_hw->wlc; + struct wlc_info *wlc = wlc_hw->wlc; WL_TRACE(("wl%d: wlc_bmac_init\n", wlc_hw->unit)); @@ -1349,7 +1349,7 @@ int wlc_bmac_bandtype(wlc_hw_info_t *wlc_hw) return wlc_hw->band->bandtype; } -void *wlc_cur_phy(wlc_info_t *wlc) +void *wlc_cur_phy(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; return (void *)wlc_hw->band->pi; @@ -1453,7 +1453,7 @@ static void wlc_clkctl_clk(wlc_hw_info_t *wlc_hw, uint mode) /* set initial host flags value */ static void -wlc_mhfdef(wlc_info_t *wlc, u16 *mhfs, u16 mhf2_init) +wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init) { wlc_hw_info_t *wlc_hw = wlc->hw; @@ -1912,7 +1912,7 @@ wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn, int len, static void WLBANDINITFN(wlc_bmac_upd_synthpu) (wlc_hw_info_t *wlc_hw) { u16 v; - wlc_info_t *wlc = wlc_hw->wlc; + struct wlc_info *wlc = wlc_hw->wlc; /* update SYNTHPU_DLY */ if (WLCISLCNPHY(wlc->band)) { @@ -1928,7 +1928,7 @@ static void WLBANDINITFN(wlc_bmac_upd_synthpu) (wlc_hw_info_t *wlc_hw) /* band-specific init */ static void -WLBANDINITFN(wlc_bmac_bsinit) (wlc_info_t *wlc, chanspec_t chanspec) +WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec) { wlc_hw_info_t *wlc_hw = wlc->hw; @@ -2080,7 +2080,7 @@ void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw) static void WLBANDINITFN(wlc_bmac_setband) (wlc_hw_info_t *wlc_hw, uint bandunit, chanspec_t chanspec) { - wlc_info_t *wlc = wlc_hw->wlc; + struct wlc_info *wlc = wlc_hw->wlc; u32 macintmask; ASSERT(NBANDS_HW(wlc_hw) > 1); @@ -2471,7 +2471,7 @@ static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw) * config other core registers * init dma */ -static void wlc_coreinit(wlc_info_t *wlc) +static void wlc_coreinit(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs; @@ -2713,7 +2713,7 @@ void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode) } /* Initialize GPIOs that are controlled by D11 core */ -static void wlc_gpio_init(wlc_info_t *wlc) +static void wlc_gpio_init(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs; @@ -2780,7 +2780,7 @@ static void wlc_gpio_init(wlc_info_t *wlc) static void wlc_ucode_download(wlc_hw_info_t *wlc_hw) { - wlc_info_t *wlc; + struct wlc_info *wlc; wlc = wlc_hw->wlc; if (wlc_hw->ucode_loaded) @@ -2960,7 +2960,7 @@ void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw) } } -void wlc_intrson(wlc_info_t *wlc) +void wlc_intrson(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; ASSERT(wlc->defmacintmask); @@ -2973,7 +2973,7 @@ void wlc_intrson(wlc_info_t *wlc) * but also because per-port code may require sync with valid interrupt. */ -static u32 wlc_wlintrsoff(wlc_info_t *wlc) +static u32 wlc_wlintrsoff(struct wlc_info *wlc) { if (!wlc->hw->up) return 0; @@ -2981,7 +2981,7 @@ static u32 wlc_wlintrsoff(wlc_info_t *wlc) return wl_intrsoff(wlc->wl); } -static void wlc_wlintrsrestore(wlc_info_t *wlc, u32 macintmask) +static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask) { if (!wlc->hw->up) return; @@ -2989,7 +2989,7 @@ static void wlc_wlintrsrestore(wlc_info_t *wlc, u32 macintmask) wl_intrsrestore(wlc->wl, macintmask); } -u32 wlc_intrsoff(wlc_info_t *wlc) +u32 wlc_intrsoff(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; u32 macintmask; @@ -3008,7 +3008,7 @@ u32 wlc_intrsoff(wlc_info_t *wlc) return wlc->macintstatus ? 0 : macintmask; } -void wlc_intrsrestore(wlc_info_t *wlc, u32 macintmask) +void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask) { wlc_hw_info_t *wlc_hw = wlc->hw; if (!wlc_hw->clk) @@ -3167,7 +3167,7 @@ void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo) * 0 if the interrupt is not for us, or we are in some special cases; * device interrupt status bits otherwise. */ -static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr) +static inline u32 wlc_intstatus(struct wlc_info *wlc, bool in_isr) { wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; @@ -3257,7 +3257,7 @@ static inline u32 wlc_intstatus(wlc_info_t *wlc, bool in_isr) /* Update wlc->macintstatus and wlc->intstatus[]. */ /* Return true if they are updated successfully. false otherwise */ -bool wlc_intrsupd(wlc_info_t *wlc) +bool wlc_intrsupd(struct wlc_info *wlc) { u32 macintstatus; @@ -3282,7 +3282,7 @@ bool wlc_intrsupd(wlc_info_t *wlc) * *wantdpc will be set to true if further wlc_dpc() processing is required, * false otherwise. */ -bool BCMFASTPATH wlc_isr(wlc_info_t *wlc, bool *wantdpc) +bool BCMFASTPATH wlc_isr(struct wlc_info *wlc, bool *wantdpc) { wlc_hw_info_t *wlc_hw = wlc->hw; u32 macintstatus; @@ -3371,7 +3371,7 @@ static bool BCMFASTPATH wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal) { bool morepending = false; - wlc_info_t *wlc = wlc_hw->wlc; + struct wlc_info *wlc = wlc_hw->wlc; WL_TRACE(("wl%d: wlc_bmac_txstatus\n", wlc_hw->unit)); @@ -3432,7 +3432,7 @@ wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal) return morepending; } -void wlc_suspend_mac_and_wait(wlc_info_t *wlc) +void wlc_suspend_mac_and_wait(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; @@ -3496,7 +3496,7 @@ void wlc_suspend_mac_and_wait(wlc_info_t *wlc) ASSERT(!(mc & MCTL_EN_MAC)); } -void wlc_enable_mac(wlc_info_t *wlc) +void wlc_enable_mac(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; @@ -3872,7 +3872,7 @@ void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want) } } -static void wlc_flushqueues(wlc_info_t *wlc) +static void wlc_flushqueues(struct wlc_info *wlc) { wlc_hw_info_t *wlc_hw = wlc->hw; uint i; diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.h b/drivers/staging/brcm80211/sys/wlc_bmac.h index c705f667469c..03ad275cfc58 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.h +++ b/drivers/staging/brcm80211/sys/wlc_bmac.h @@ -57,7 +57,7 @@ typedef struct wlc_bmac_revinfo { } band[MAXBANDS]; } wlc_bmac_revinfo_t; -/* dup state between BMAC(wlc_hw_info_t) and HIGH(wlc_info_t) driver */ +/* dup state between BMAC(wlc_hw_info_t) and HIGH(struct wlc_info) driver */ typedef struct wlc_bmac_state { u32 machwcap; /* mac hw capibility */ u32 preamble_ovr; /* preamble override */ @@ -130,10 +130,10 @@ typedef enum { WLCHW_STATE_LAST } wlc_bmac_state_id_t; -extern int wlc_bmac_attach(wlc_info_t *wlc, u16 vendor, u16 device, +extern int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, bool piomode, struct osl_info *osh, void *regsva, uint bustype, void *btparam); -extern int wlc_bmac_detach(wlc_info_t *wlc); +extern int wlc_bmac_detach(struct wlc_info *wlc); extern void wlc_bmac_watchdog(void *arg); extern void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw); diff --git a/drivers/staging/brcm80211/sys/wlc_bsscfg.h b/drivers/staging/brcm80211/sys/wlc_bsscfg.h index ae5542ab0334..d6a1971c69a0 100644 --- a/drivers/staging/brcm80211/sys/wlc_bsscfg.h +++ b/drivers/staging/brcm80211/sys/wlc_bsscfg.h @@ -34,7 +34,8 @@ typedef struct wlc_bsscfg wlc_bsscfg_t; #define MAXMACLIST 64 /* max # source MAC matches */ #define BCN_TEMPLATE_COUNT 2 -/* Iterator for "associated" STA bss configs: (wlc_info_t *wlc, int idx, wlc_bsscfg_t *cfg) */ +/* Iterator for "associated" STA bss configs: + (struct wlc_info *wlc, int idx, wlc_bsscfg_t *cfg) */ #define FOREACH_AS_STA(wlc, idx, cfg) \ for (idx = 0; (int) idx < WLC_MAXBSSCFG; idx++) \ if ((cfg = (wlc)->bsscfg[idx]) && BSSCFG_STA(cfg) && cfg->associated) diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index bb82a8c008a4..e367ed4f1e91 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -45,7 +45,7 @@ typedef struct wlc_cm_band { struct wlc_cm_info { wlc_pub_t *pub; - wlc_info_t *wlc; + struct wlc_info *wlc; char srom_ccode[WLC_CNTRY_BUF_SZ]; /* Country Code in SROM */ uint srom_regrev; /* Regulatory Rev for the SROM ccode */ const country_info_t *country; /* current country def */ @@ -606,7 +606,7 @@ const locale_mimo_info_t *wlc_get_mimo_5g(u8 locale_idx) return g_mimo_5g_table[locale_idx]; } -wlc_cm_info_t *wlc_channel_mgr_attach(wlc_info_t *wlc) +wlc_cm_info_t *wlc_channel_mgr_attach(struct wlc_info *wlc) { wlc_cm_info_t *wlc_cm; char country_abbrev[WLC_CNTRY_BUF_SZ]; @@ -664,7 +664,7 @@ const char *wlc_channel_country_abbrev(wlc_cm_info_t *wlc_cm) u8 wlc_channel_locale_flags(wlc_cm_info_t *wlc_cm) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; return wlc_cm->bandstate[wlc->band->bandunit].locale_flags; } @@ -755,7 +755,7 @@ wlc_set_country_common(wlc_cm_info_t *wlc_cm, { const locale_mimo_info_t *li_mimo; const locale_info_t *locale; - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; char prev_country_abbrev[WLC_CNTRY_BUF_SZ]; ASSERT(country != NULL); @@ -819,7 +819,7 @@ static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm, char *mapped_ccode, uint *mapped_regrev) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; const country_info_t *country; uint srom_regrev = wlc_cm->srom_regrev; const char *srom_ccode = wlc_cm->srom_ccode; @@ -903,7 +903,7 @@ static const country_info_t *wlc_country_lookup_direct(const char *ccode, static int wlc_channels_init(wlc_cm_info_t *wlc_cm, const country_info_t *country) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; uint i, j; wlcband_t *band; const locale_info_t *li; @@ -957,7 +957,7 @@ wlc_channels_init(wlc_cm_info_t *wlc_cm, const country_info_t *country) */ static void wlc_channels_commit(wlc_cm_info_t *wlc_cm) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; uint chan; struct txpwr_limits txpwr; @@ -1003,7 +1003,7 @@ static void wlc_channels_commit(wlc_cm_info_t *wlc_cm) /* reset the quiet channels vector to the union of the restricted and radar channel sets */ void wlc_quiet_channels_reset(wlc_cm_info_t *wlc_cm) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; uint i, j; wlcband_t *band; const chanvec_t *chanvec; @@ -1041,7 +1041,7 @@ bool wlc_quiet_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chspec) */ bool wlc_valid_channel20_db(wlc_cm_info_t *wlc_cm, uint val) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; return VALID_CHANNEL20(wlc, val) || (!wlc->bandlocked @@ -1059,7 +1059,7 @@ wlc_valid_channel20_in_band(wlc_cm_info_t *wlc_cm, uint bandunit, uint val) /* Is the channel valid for the current locale and current band? */ bool wlc_valid_channel20(wlc_cm_info_t *wlc_cm, uint val) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; return ((val < MAXCHANNEL) && isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec, @@ -1069,7 +1069,7 @@ bool wlc_valid_channel20(wlc_cm_info_t *wlc_cm, uint val) /* Is the 40 MHz allowed for the current locale and specified band? */ bool wlc_valid_40chanspec_in_band(wlc_cm_info_t *wlc_cm, uint bandunit) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; return (((wlc_cm->bandstate[bandunit]. locale_flags & (WLC_NO_MIMO | WLC_NO_40MHZ)) == 0) @@ -1167,7 +1167,7 @@ void wlc_channel_set_chanspec(wlc_cm_info_t *wlc_cm, chanspec_t chanspec, u8 local_constraint_qdbm) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; struct txpwr_limits txpwr; wlc_channel_reg_limits(wlc_cm, chanspec, &txpwr); @@ -1184,7 +1184,7 @@ int wlc_channel_set_txpower_limit(wlc_cm_info_t *wlc_cm, u8 local_constraint_qdbm) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; struct txpwr_limits txpwr; wlc_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr); @@ -1304,7 +1304,7 @@ void wlc_channel_reg_limits(wlc_cm_info_t *wlc_cm, chanspec_t chanspec, txpwr_limits_t *txpwr) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; uint i; uint chan; int maxpwr; @@ -1533,7 +1533,7 @@ static bool wlc_japan_ccode(const char *ccode) static bool wlc_valid_chanspec_ext(wlc_cm_info_t *wlc_cm, chanspec_t chspec, bool dualband) { - wlc_info_t *wlc = wlc_cm->wlc; + struct wlc_info *wlc = wlc_cm->wlc; u8 channel = CHSPEC_CHANNEL(chspec); /* check the chanspec */ diff --git a/drivers/staging/brcm80211/sys/wlc_event.h b/drivers/staging/brcm80211/sys/wlc_event.h index e443dae258b7..7c8e49550f2d 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.h +++ b/drivers/staging/brcm80211/sys/wlc_event.h @@ -38,7 +38,7 @@ extern int wlc_eventq_query_ind(wlc_eventq_t *eq, void *bitvect); extern int wlc_eventq_test_ind(wlc_eventq_t *eq, int et); extern int wlc_eventq_set_ind(wlc_eventq_t *eq, uint et, bool on); extern void wlc_eventq_flush(wlc_eventq_t *eq); -extern void wlc_assign_event_msg(wlc_info_t *wlc, wl_event_msg_t *msg, +extern void wlc_assign_event_msg(struct wlc_info *wlc, wl_event_msg_t *msg, const wlc_event_t *e, u8 *data, u32 len); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index fcd3bd18f27c..3e31f893fcc3 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -120,7 +120,7 @@ uint wl_msg_level = #ifdef BCMDBG /* pointer to most recently allocated wl/wlc */ -static wlc_info_t *wlc_info_dbg = (wlc_info_t *) (NULL); +static struct wlc_info *wlc_info_dbg = (struct wlc_info *) (NULL); #endif /* IOVar table */ @@ -221,7 +221,7 @@ static const u8 acbitmap2maxprio[] = { #define WLC_REPLAY_CNTRS_VALUE WPA_CAP_16_REPLAY_CNTRS /* local prototypes */ -static u16 BCMFASTPATH wlc_d11hdrs_mac80211(wlc_info_t *wlc, +static u16 BCMFASTPATH wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, struct sk_buff *p, struct scb *scb, uint frag, @@ -230,76 +230,76 @@ static u16 BCMFASTPATH wlc_d11hdrs_mac80211(wlc_info_t *wlc, wsec_key_t *key, ratespec_t rspec_override); -static void wlc_bss_default_init(wlc_info_t *wlc); -static void wlc_ucode_mac_upd(wlc_info_t *wlc); -static ratespec_t mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, - u32 int_val); -static void wlc_tx_prec_map_init(wlc_info_t *wlc); +static void wlc_bss_default_init(struct wlc_info *wlc); +static void wlc_ucode_mac_upd(struct wlc_info *wlc); +static ratespec_t mac80211_wlc_set_nrate(struct wlc_info *wlc, + wlcband_t *cur_band, u32 int_val); +static void wlc_tx_prec_map_init(struct wlc_info *wlc); static void wlc_watchdog(void *arg); static void wlc_watchdog_by_timer(void *arg); -static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg); -static int wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val, +static int wlc_set_rateset(struct wlc_info *wlc, wlc_rateset_t *rs_arg); +static int wlc_iovar_rangecheck(struct wlc_info *wlc, u32 val, const bcm_iovar_t *vi); -static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc); +static u8 wlc_local_constraint_qdbm(struct wlc_info *wlc); /* send and receive */ -static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, struct osl_info *osh); -static void wlc_txq_free(wlc_info_t *wlc, struct osl_info *osh, +static wlc_txq_info_t *wlc_txq_alloc(struct wlc_info *wlc, + struct osl_info *osh); +static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh, wlc_txq_info_t *qi); -static void wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, +static void wlc_txflowcontrol_signal(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on, int prio); -static void wlc_txflowcontrol_reset(wlc_info_t *wlc); -static u16 wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, +static void wlc_txflowcontrol_reset(struct wlc_info *wlc); +static u16 wlc_compute_airtime(struct wlc_info *wlc, ratespec_t rspec, uint length); static void wlc_compute_cck_plcp(ratespec_t rate, uint length, u8 *plcp); static void wlc_compute_ofdm_plcp(ratespec_t rate, uint length, u8 *plcp); static void wlc_compute_mimo_plcp(ratespec_t rate, uint length, u8 *plcp); -static u16 wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, +static u16 wlc_compute_frame_dur(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type, uint next_frag_len); -static void wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, - struct sk_buff *p); -static uint wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t rate, +static void wlc_recvctl(struct wlc_info *wlc, struct osl_info *osh, + d11rxhdr_t *rxh, struct sk_buff *p); +static uint wlc_calc_frame_len(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type, uint dur); -static uint wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rate, +static uint wlc_calc_ack_time(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type); -static uint wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rate, +static uint wlc_calc_cts_time(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type); /* interrupt, up/down, band */ -static void wlc_setband(wlc_info_t *wlc, uint bandunit); -static chanspec_t wlc_init_chanspec(wlc_info_t *wlc); -static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec); -static void wlc_bsinit(wlc_info_t *wlc); -static int wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM, +static void wlc_setband(struct wlc_info *wlc, uint bandunit); +static chanspec_t wlc_init_chanspec(struct wlc_info *wlc); +static void wlc_bandinit_ordered(struct wlc_info *wlc, chanspec_t chanspec); +static void wlc_bsinit(struct wlc_info *wlc); +static int wlc_duty_cycle_set(struct wlc_info *wlc, int duty_cycle, bool isOFDM, bool writeToShm); -static void wlc_radio_hwdisable_upd(wlc_info_t *wlc); -static bool wlc_radio_monitor_start(wlc_info_t *wlc); +static void wlc_radio_hwdisable_upd(struct wlc_info *wlc); +static bool wlc_radio_monitor_start(struct wlc_info *wlc); static void wlc_radio_timer(void *arg); -static void wlc_radio_enable(wlc_info_t *wlc); -static void wlc_radio_upd(wlc_info_t *wlc); +static void wlc_radio_enable(struct wlc_info *wlc); +static void wlc_radio_upd(struct wlc_info *wlc); /* scan, association, BSS */ -static uint wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rate, +static uint wlc_calc_ba_time(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type); -static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap); -static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val); -void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode); -static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val); -static void wlc_war16165(wlc_info_t *wlc, bool tx); +static void wlc_update_mimo_band_bwcap(struct wlc_info *wlc, u8 bwcap); +static void wlc_ht_update_sgi_rx(struct wlc_info *wlc, int val); +static void wlc_ht_update_ldpc(struct wlc_info *wlc, s8 val); +static void wlc_war16165(struct wlc_info *wlc, bool tx); static void wlc_process_eventq(void *arg); -static void wlc_wme_retries_write(wlc_info_t *wlc); -static bool wlc_attach_stf_ant_init(wlc_info_t *wlc); -static uint wlc_attach_module(wlc_info_t *wlc); -static void wlc_detach_module(wlc_info_t *wlc); -static void wlc_timers_deinit(wlc_info_t *wlc); -static void wlc_down_led_upd(wlc_info_t *wlc); -static uint wlc_down_del_timer(wlc_info_t *wlc); -static void wlc_ofdm_rateset_war(wlc_info_t *wlc); -static int _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, +static void wlc_wme_retries_write(struct wlc_info *wlc); +static bool wlc_attach_stf_ant_init(struct wlc_info *wlc); +static uint wlc_attach_module(struct wlc_info *wlc); +static void wlc_detach_module(struct wlc_info *wlc); +static void wlc_timers_deinit(struct wlc_info *wlc); +static void wlc_down_led_upd(struct wlc_info *wlc); +static uint wlc_down_del_timer(struct wlc_info *wlc); +static void wlc_ofdm_rateset_war(struct wlc_info *wlc); +static int _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif); #if defined(BCMDBG) -void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr) +void wlc_get_rcmta(struct wlc_info *wlc, int idx, struct ether_addr *addr) { d11regs_t *regs = wlc->regs; u32 v32; @@ -327,14 +327,14 @@ void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr) #endif /* defined(BCMDBG) */ /* keep the chip awake if needed */ -bool wlc_stay_awake(wlc_info_t *wlc) +bool wlc_stay_awake(struct wlc_info *wlc) { return true; } /* conditions under which the PM bit should be set in outgoing frames and STAY_AWAKE is meaningful */ -bool wlc_ps_allowed(wlc_info_t *wlc) +bool wlc_ps_allowed(struct wlc_info *wlc) { int idx; wlc_bsscfg_t *cfg; @@ -361,7 +361,7 @@ bool wlc_ps_allowed(wlc_info_t *wlc) return true; } -void wlc_reset(wlc_info_t *wlc) +void wlc_reset(struct wlc_info *wlc) { WL_TRACE(("wl%d: wlc_reset\n", wlc->pub->unit)); @@ -382,7 +382,7 @@ void wlc_reset(wlc_info_t *wlc) } -void wlc_fatal_error(wlc_info_t *wlc) +void wlc_fatal_error(struct wlc_info *wlc) { WL_ERROR(("wl%d: fatal error, reinitializing\n", wlc->pub->unit)); wl_init(wlc->wl); @@ -393,7 +393,7 @@ void wlc_fatal_error(wlc_info_t *wlc) * if other configurations are in conflict (bandlocked, 11n mode disabled, * invalid channel for current country, etc.) */ -static chanspec_t wlc_init_chanspec(wlc_info_t *wlc) +static chanspec_t wlc_init_chanspec(struct wlc_info *wlc) { chanspec_t chanspec = 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | @@ -409,7 +409,7 @@ static chanspec_t wlc_init_chanspec(wlc_info_t *wlc) struct scb global_scb; -static void wlc_init_scb(wlc_info_t *wlc, struct scb *scb) +static void wlc_init_scb(struct wlc_info *wlc, struct scb *scb) { int i; scb->flags = SCB_WMECAP | SCB_HTCAP; @@ -417,7 +417,7 @@ static void wlc_init_scb(wlc_info_t *wlc, struct scb *scb) scb->seqnum[i] = 0; } -void wlc_init(wlc_info_t *wlc) +void wlc_init(struct wlc_info *wlc) { d11regs_t *regs; chanspec_t chanspec; @@ -551,13 +551,13 @@ void wlc_init(wlc_info_t *wlc) } } -void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc) +void wlc_mac_bcn_promisc_change(struct wlc_info *wlc, bool promisc) { wlc->bcnmisc_monitor = promisc; wlc_mac_bcn_promisc(wlc); } -void wlc_mac_bcn_promisc(wlc_info_t *wlc) +void wlc_mac_bcn_promisc(struct wlc_info *wlc) { if ((AP_ENAB(wlc->pub) && (N_ENAB(wlc->pub) || wlc->band->gmode)) || wlc->bcnmisc_ibss || wlc->bcnmisc_scan || wlc->bcnmisc_monitor) @@ -567,7 +567,7 @@ void wlc_mac_bcn_promisc(wlc_info_t *wlc) } /* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */ -void wlc_mac_promisc(wlc_info_t *wlc) +void wlc_mac_promisc(struct wlc_info *wlc) { u32 promisc_bits = 0; @@ -589,7 +589,7 @@ void wlc_mac_promisc(wlc_info_t *wlc) } /* check if hps and wake states of sw and hw are in sync */ -bool wlc_ps_check(wlc_info_t *wlc) +bool wlc_ps_check(struct wlc_info *wlc) { bool res = true; bool hps, wake; @@ -637,7 +637,7 @@ bool wlc_ps_check(wlc_info_t *wlc) } /* push sw hps and wake state through hardware */ -void wlc_set_ps_ctrl(wlc_info_t *wlc) +void wlc_set_ps_ctrl(struct wlc_info *wlc) { u32 v1, v2; bool hps, wake; @@ -672,7 +672,7 @@ void wlc_set_ps_ctrl(wlc_info_t *wlc) int wlc_set_mac(wlc_bsscfg_t *cfg) { int err = 0; - wlc_info_t *wlc = cfg->wlc; + struct wlc_info *wlc = cfg->wlc; if (cfg == wlc->cfg) { /* enter the MAC addr into the RXE match registers */ @@ -689,7 +689,7 @@ int wlc_set_mac(wlc_bsscfg_t *cfg) */ void wlc_set_bssid(wlc_bsscfg_t *cfg) { - wlc_info_t *wlc = cfg->wlc; + struct wlc_info *wlc = cfg->wlc; /* if primary config, we need to update BSSID in RXE match registers */ if (cfg == wlc->cfg) { @@ -706,7 +706,7 @@ void wlc_set_bssid(wlc_bsscfg_t *cfg) * Suspend the the MAC and update the slot timing * for standard 11b/g (20us slots) or shortslot 11g (9us slots). */ -void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot) +void wlc_switch_shortslot(struct wlc_info *wlc, bool shortslot) { int idx; wlc_bsscfg_t *cfg; @@ -734,7 +734,7 @@ void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot) wlc_bmac_set_shortslot(wlc->hw, shortslot); } -static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc) +static u8 wlc_local_constraint_qdbm(struct wlc_info *wlc) { u8 local; s16 local_max; @@ -761,7 +761,7 @@ static u8 wlc_local_constraint_qdbm(wlc_info_t *wlc) } /* propagate home chanspec to all bsscfgs in case bsscfg->current_bss->chanspec is referenced */ -void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec) +void wlc_set_home_chanspec(struct wlc_info *wlc, chanspec_t chanspec) { if (wlc->home_chanspec != chanspec) { int idx; @@ -779,7 +779,7 @@ void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec) } } -static void wlc_set_phy_chanspec(wlc_info_t *wlc, chanspec_t chanspec) +static void wlc_set_phy_chanspec(struct wlc_info *wlc, chanspec_t chanspec) { /* Save our copy of the chanspec */ wlc->chanspec = chanspec; @@ -798,7 +798,7 @@ static void wlc_set_phy_chanspec(wlc_info_t *wlc, chanspec_t chanspec) } -void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec) +void wlc_set_chanspec(struct wlc_info *wlc, chanspec_t chanspec) { uint bandunit; bool switchband = false; @@ -853,7 +853,7 @@ void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec) } #if defined(BCMDBG) -static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len) +static int wlc_get_current_txpwr(struct wlc_info *wlc, void *pwr, uint len) { txpwr_limits_t txpwr; tx_power_t power; @@ -1022,7 +1022,7 @@ static int wlc_get_current_txpwr(wlc_info_t *wlc, void *pwr, uint len) } #endif /* defined(BCMDBG) */ -static u32 wlc_watchdog_backup_bi(wlc_info_t *wlc) +static u32 wlc_watchdog_backup_bi(struct wlc_info *wlc) { u32 bi; bi = 2 * wlc->cfg->current_bss->dtim_period * @@ -1041,7 +1041,7 @@ static u32 wlc_watchdog_backup_bi(wlc_info_t *wlc) /* Change to run the watchdog either from a periodic timer or from tbtt handler. * Call watchdog from tbtt handler if tbtt is true, watchdog timer otherwise. */ -void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt) +void wlc_watchdog_upd(struct wlc_info *wlc, bool tbtt) { /* make sure changing watchdog driver is allowed */ if (!wlc->pub->up || !wlc->pub->align_wd_tbtt) @@ -1070,7 +1070,7 @@ void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt) } } -ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs) +ratespec_t wlc_lowest_basic_rspec(struct wlc_info *wlc, wlc_rateset_t *rs) { ratespec_t lowest_basic_rspec; uint i; @@ -1098,7 +1098,7 @@ ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs) * ratespec CCK ant = wlc->stf->txant * OFDM ant = 3 */ -void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc, ratespec_t bcn_rspec) +void wlc_beacon_phytxctl_txant_upd(struct wlc_info *wlc, ratespec_t bcn_rspec) { u16 phyctl; u16 phytxant = wlc->stf->phytxant; @@ -1117,7 +1117,7 @@ void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc, ratespec_t bcn_rspec) /* centralized protection config change function to simplify debugging, no consistency checking * this should be called only on changes to avoid overhead in periodic function */ -void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val) +void wlc_protection_upd(struct wlc_info *wlc, uint idx, int val) { WL_TRACE(("wlc_protection_upd: idx %d, val %d\n", idx, val)); @@ -1163,7 +1163,7 @@ void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val) } -static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val) +static void wlc_ht_update_sgi_rx(struct wlc_info *wlc, int val) { wlc->ht_cap.cap &= ~(HT_CAP_SHORT_GI_20 | HT_CAP_SHORT_GI_40); wlc->ht_cap.cap |= (val & WLC_N_SGI_20) ? HT_CAP_SHORT_GI_20 : 0; @@ -1175,7 +1175,7 @@ static void wlc_ht_update_sgi_rx(wlc_info_t *wlc, int val) } } -static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val) +static void wlc_ht_update_ldpc(struct wlc_info *wlc, s8 val) { wlc->stf->ldpc = val; @@ -1194,7 +1194,7 @@ static void wlc_ht_update_ldpc(wlc_info_t *wlc, s8 val) * ucode, hwmac update * Channel dependent updates for ucode and hw */ -static void wlc_ucode_mac_upd(wlc_info_t *wlc) +static void wlc_ucode_mac_upd(struct wlc_info *wlc) { /* enable or disable any active IBSSs depending on whether or not * we are on the home channel @@ -1221,7 +1221,7 @@ static void wlc_ucode_mac_upd(wlc_info_t *wlc) wlc_mac_promisc(wlc); } -static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec) +static void wlc_bandinit_ordered(struct wlc_info *wlc, chanspec_t chanspec) { wlc_rateset_t default_rateset; uint parkband; @@ -1268,7 +1268,7 @@ static void wlc_bandinit_ordered(wlc_info_t *wlc, chanspec_t chanspec) } /* band-specific init */ -static void WLBANDINITFN(wlc_bsinit) (wlc_info_t *wlc) +static void WLBANDINITFN(wlc_bsinit) (struct wlc_info *wlc) { WL_TRACE(("wl%d: wlc_bsinit: bandunit %d\n", wlc->pub->unit, wlc->band->bandunit)); @@ -1286,7 +1286,7 @@ static void WLBANDINITFN(wlc_bsinit) (wlc_info_t *wlc) } /* switch to and initialize new band */ -static void WLBANDINITFN(wlc_setband) (wlc_info_t *wlc, uint bandunit) +static void WLBANDINITFN(wlc_setband) (struct wlc_info *wlc, uint bandunit) { int idx; wlc_bsscfg_t *cfg; @@ -1311,7 +1311,7 @@ static void WLBANDINITFN(wlc_setband) (wlc_info_t *wlc, uint bandunit) } /* Initialize a WME Parameter Info Element with default STA parameters from WMM Spec, Table 12 */ -void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe) +void wlc_wme_initparams_sta(struct wlc_info *wlc, wme_param_ie_t *pe) { static const wme_param_ie_t stadef = { WME_OUI, @@ -1336,7 +1336,7 @@ void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe) memcpy(pe, &stadef, sizeof(*pe)); } -void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend) +void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg, bool suspend) { int i; shm_acparams_t acp_shm; @@ -1417,7 +1417,7 @@ void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, bool suspend) void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend) { - wlc_info_t *wlc = cfg->wlc; + struct wlc_info *wlc = cfg->wlc; uint aci, i, j; edcf_acparam_t *edcf_acp; shm_acparams_t acp_shm; @@ -1506,7 +1506,7 @@ void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend) } -bool wlc_timers_init(wlc_info_t *wlc, int unit) +bool wlc_timers_init(struct wlc_info *wlc, int unit) { wlc->wdtimer = wl_init_timer(wlc->wl, wlc_watchdog_by_timer, wlc, "watchdog"); @@ -1533,7 +1533,7 @@ bool wlc_timers_init(wlc_info_t *wlc, int unit) * Initialize wlc_info default values ... * may get overrides later in this function */ -void wlc_info_init(wlc_info_t *wlc, int unit) +void wlc_info_init(struct wlc_info *wlc, int unit) { int i; /* Assume the device is there until proven otherwise */ @@ -1644,7 +1644,7 @@ void wlc_info_init(wlc_info_t *wlc, int unit) wlc->pr80838_war = true; } -static bool wlc_state_bmac_sync(wlc_info_t *wlc) +static bool wlc_state_bmac_sync(struct wlc_info *wlc) { wlc_bmac_state_t state_bmac; @@ -1658,7 +1658,7 @@ static bool wlc_state_bmac_sync(wlc_info_t *wlc) return true; } -static uint wlc_attach_module(wlc_info_t *wlc) +static uint wlc_attach_module(struct wlc_info *wlc) { uint err = 0; uint unit; @@ -1699,7 +1699,7 @@ static uint wlc_attach_module(wlc_info_t *wlc) wlc_pub_t *wlc_pub(void *wlc) { - return ((wlc_info_t *) wlc)->pub; + return ((struct wlc_info *) wlc)->pub; } #define CHIP_SUPPORTS_11N(wlc) 1 @@ -1711,7 +1711,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, struct osl_info *osh, void *regsva, uint bustype, void *btparam, uint *perr) { - wlc_info_t *wlc; + struct wlc_info *wlc; uint err = 0; uint j; wlc_pub_t *pub; @@ -1757,8 +1757,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, || (WPA_CAP_4_REPLAY_CNTRS == WLC_REPLAY_CNTRS_VALUE && 4 == WLC_NUMRXIVS)); - /* allocate wlc_info_t state and its substructures */ - wlc = (wlc_info_t *) wlc_attach_malloc(osh, unit, &err, device); + /* allocate struct wlc_info state and its substructures */ + wlc = (struct wlc_info *) wlc_attach_malloc(osh, unit, &err, device); if (wlc == NULL) goto fail; wlc->osh = osh; @@ -1779,7 +1779,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, /* By default restrict TKIP associations from 11n STA's */ wlc->ht_wsec_restriction = WLC_HT_TKIP_RESTRICT; - /* populate wlc_info_t with default values */ + /* populate struct wlc_info with default values */ wlc_info_init(wlc, unit); /* update sta/ap related parameters */ @@ -2016,7 +2016,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, return NULL; } -static void wlc_attach_antgain_init(wlc_info_t *wlc) +static void wlc_attach_antgain_init(struct wlc_info *wlc) { uint unit; unit = wlc->pub->unit; @@ -2047,7 +2047,7 @@ static void wlc_attach_antgain_init(wlc_info_t *wlc) } } -static bool wlc_attach_stf_ant_init(wlc_info_t *wlc) +static bool wlc_attach_stf_ant_init(struct wlc_info *wlc) { int aa; uint unit; @@ -2087,7 +2087,7 @@ static bool wlc_attach_stf_ant_init(wlc_info_t *wlc) } -static void wlc_timers_deinit(wlc_info_t *wlc) +static void wlc_timers_deinit(struct wlc_info *wlc) { /* free timer state */ if (wlc->wdtimer) { @@ -2100,7 +2100,7 @@ static void wlc_timers_deinit(wlc_info_t *wlc) } } -static void wlc_detach_module(wlc_info_t *wlc) +static void wlc_detach_module(struct wlc_info *wlc) { if (wlc->asi) { wlc_antsel_detach(wlc->asi); @@ -2123,7 +2123,7 @@ static void wlc_detach_module(wlc_info_t *wlc) * One exception is sb register access, which is possible if crystal is turned on * After "down" state, driver should avoid software timer with the exception of radio_monitor. */ -uint wlc_detach(wlc_info_t *wlc) +uint wlc_detach(struct wlc_info *wlc) { uint i; uint callbacks = 0; @@ -2200,7 +2200,7 @@ uint wlc_detach(wlc_info_t *wlc) } /* update state that depends on the current value of "ap" */ -void wlc_ap_upd(wlc_info_t *wlc) +void wlc_ap_upd(struct wlc_info *wlc) { if (AP_ENAB(wlc->pub)) wlc->PLCPHdr_override = WLC_PLCP_AUTO; /* AP: short not allowed, but not enforced */ @@ -2215,7 +2215,7 @@ void wlc_ap_upd(wlc_info_t *wlc) } /* read hwdisable state and propagate to wlc flag */ -static void wlc_radio_hwdisable_upd(wlc_info_t *wlc) +static void wlc_radio_hwdisable_upd(struct wlc_info *wlc) { if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off) return; @@ -2228,17 +2228,17 @@ static void wlc_radio_hwdisable_upd(wlc_info_t *wlc) } /* return true if Minimum Power Consumption should be entered, false otherwise */ -bool wlc_is_non_delay_mpc(wlc_info_t *wlc) +bool wlc_is_non_delay_mpc(struct wlc_info *wlc) { return false; } -bool wlc_ismpc(wlc_info_t *wlc) +bool wlc_ismpc(struct wlc_info *wlc) { return (wlc->mpc_delay_off == 0) && (wlc_is_non_delay_mpc(wlc)); } -void wlc_radio_mpc_upd(wlc_info_t *wlc) +void wlc_radio_mpc_upd(struct wlc_info *wlc) { bool mpc_radio, radio_state; @@ -2294,7 +2294,7 @@ void wlc_radio_mpc_upd(wlc_info_t *wlc) * centralized radio disable/enable function, * invoke radio enable/disable after updating hwradio status */ -static void wlc_radio_upd(wlc_info_t *wlc) +static void wlc_radio_upd(struct wlc_info *wlc) { if (wlc->pub->radio_disabled) wlc_radio_disable(wlc); @@ -2303,7 +2303,7 @@ static void wlc_radio_upd(wlc_info_t *wlc) } /* maintain LED behavior in down state */ -static void wlc_down_led_upd(wlc_info_t *wlc) +static void wlc_down_led_upd(struct wlc_info *wlc) { ASSERT(!wlc->pub->up); @@ -2316,7 +2316,7 @@ static void wlc_down_led_upd(wlc_info_t *wlc) } } -void wlc_radio_disable(wlc_info_t *wlc) +void wlc_radio_disable(struct wlc_info *wlc) { if (!wlc->pub->up) { wlc_down_led_upd(wlc); @@ -2327,7 +2327,7 @@ void wlc_radio_disable(wlc_info_t *wlc) wl_down(wlc->wl); } -static void wlc_radio_enable(wlc_info_t *wlc) +static void wlc_radio_enable(struct wlc_info *wlc) { if (wlc->pub->up) return; @@ -2343,7 +2343,7 @@ static void wlc_radio_enable(wlc_info_t *wlc) /* periodical query hw radio button while driver is "down" */ static void wlc_radio_timer(void *arg) { - wlc_info_t *wlc = (wlc_info_t *) arg; + struct wlc_info *wlc = (struct wlc_info *) arg; if (DEVICEREMOVED(wlc)) { WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__)); @@ -2361,7 +2361,7 @@ static void wlc_radio_timer(void *arg) wlc_radio_upd(wlc); } -static bool wlc_radio_monitor_start(wlc_info_t *wlc) +static bool wlc_radio_monitor_start(struct wlc_info *wlc) { /* Don't start the timer if HWRADIO feature is disabled */ if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO)) @@ -2373,7 +2373,7 @@ static bool wlc_radio_monitor_start(wlc_info_t *wlc) return true; } -bool wlc_radio_monitor_stop(wlc_info_t *wlc) +bool wlc_radio_monitor_stop(struct wlc_info *wlc) { if (!wlc->radio_monitor) return true; @@ -2387,7 +2387,7 @@ bool wlc_radio_monitor_stop(wlc_info_t *wlc) } /* bring the driver down, but don't reset hardware */ -void wlc_out(wlc_info_t *wlc) +void wlc_out(struct wlc_info *wlc) { wlc_bmac_set_noreset(wlc->hw, true); wlc_radio_upd(wlc); @@ -2408,7 +2408,7 @@ void wlc_out(wlc_info_t *wlc) * if there is no packet pending for the FIFO, then the corresponding prec bits should be set * in prec_map. Of course, ignore this rule when block_datafifo is set */ -static bool wlc_tx_prec_map_verify(wlc_info_t *wlc) +static bool wlc_tx_prec_map_verify(struct wlc_info *wlc) { /* For non-WME, both fifos have overlapping prec_map. So it's an error only if both * fail the check. @@ -2430,7 +2430,7 @@ static bool wlc_tx_prec_map_verify(wlc_info_t *wlc) static void wlc_watchdog_by_timer(void *arg) { - wlc_info_t *wlc = (wlc_info_t *) arg; + struct wlc_info *wlc = (struct wlc_info *) arg; wlc_watchdog(arg); if (WLC_WATCHDOG_TBTT(wlc)) { /* set to normal osl watchdog period */ @@ -2443,7 +2443,7 @@ static void wlc_watchdog_by_timer(void *arg) /* common watchdog code */ static void wlc_watchdog(void *arg) { - wlc_info_t *wlc = (wlc_info_t *) arg; + struct wlc_info *wlc = (struct wlc_info *) arg; int i; wlc_bsscfg_t *cfg; @@ -2523,7 +2523,7 @@ static void wlc_watchdog(void *arg) } /* make interface operational */ -int wlc_up(wlc_info_t *wlc) +int wlc_up(struct wlc_info *wlc) { WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__)); @@ -2631,7 +2631,7 @@ int wlc_up(wlc_info_t *wlc) } /* Initialize the base precedence map for dequeueing from txq based on WME settings */ -static void wlc_tx_prec_map_init(wlc_info_t *wlc) +static void wlc_tx_prec_map_init(struct wlc_info *wlc) { wlc->tx_prec_map = WLC_PREC_BMP_ALL; memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16)); @@ -2650,7 +2650,7 @@ static void wlc_tx_prec_map_init(wlc_info_t *wlc) } } -static uint wlc_down_del_timer(wlc_info_t *wlc) +static uint wlc_down_del_timer(struct wlc_info *wlc) { uint callbacks = 0; @@ -2662,7 +2662,7 @@ static uint wlc_down_del_timer(wlc_info_t *wlc) * disable the hardware, free any transient buffer state. * Return a count of the number of driver callbacks still pending. */ -uint wlc_down(wlc_info_t *wlc) +uint wlc_down(struct wlc_info *wlc) { uint callbacks = 0; @@ -2749,7 +2749,7 @@ uint wlc_down(wlc_info_t *wlc) } /* Set the current gmode configuration */ -int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config) +int wlc_set_gmode(struct wlc_info *wlc, u8 gmode, bool config) { int ret = 0; uint i; @@ -2899,7 +2899,7 @@ int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config) return ret; } -static int wlc_nmode_validate(wlc_info_t *wlc, s32 nmode) +static int wlc_nmode_validate(struct wlc_info *wlc, s32 nmode) { int err = 0; @@ -2923,7 +2923,7 @@ static int wlc_nmode_validate(wlc_info_t *wlc, s32 nmode) return err; } -int wlc_set_nmode(wlc_info_t *wlc, s32 nmode) +int wlc_set_nmode(struct wlc_info *wlc, s32 nmode) { uint i; int err; @@ -2982,7 +2982,7 @@ int wlc_set_nmode(wlc_info_t *wlc, s32 nmode) return err; } -static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg) +static int wlc_set_rateset(struct wlc_info *wlc, wlc_rateset_t *rs_arg) { wlc_rateset_t rs, new; uint bandunit; @@ -3025,18 +3025,18 @@ static int wlc_set_rateset(wlc_info_t *wlc, wlc_rateset_t *rs_arg) } /* simplified integer set interface for common ioctl handler */ -int wlc_set(wlc_info_t *wlc, int cmd, int arg) +int wlc_set(struct wlc_info *wlc, int cmd, int arg) { return wlc_ioctl(wlc, cmd, (void *)&arg, sizeof(arg), NULL); } /* simplified integer get interface for common ioctl handler */ -int wlc_get(wlc_info_t *wlc, int cmd, int *arg) +int wlc_get(struct wlc_info *wlc, int cmd, int *arg) { return wlc_ioctl(wlc, cmd, arg, sizeof(int), NULL); } -static void wlc_ofdm_rateset_war(wlc_info_t *wlc) +static void wlc_ofdm_rateset_war(struct wlc_info *wlc) { u8 r; bool war = false; @@ -3052,14 +3052,16 @@ static void wlc_ofdm_rateset_war(wlc_info_t *wlc) } int -wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) +wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, + struct wlc_if *wlcif) { return _wlc_ioctl(wlc, cmd, arg, len, wlcif); } /* common ioctl handler. return: 0=ok, -1=error, positive=particular error */ static int -_wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) +_wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, + struct wlc_if *wlcif) { int val, *pval; bool bool_val; @@ -4220,7 +4222,7 @@ _wlc_ioctl(wlc_info_t *wlc, int cmd, void *arg, int len, struct wlc_if *wlcif) #if defined(BCMDBG) /* consolidated register access ioctl error checking */ -int wlc_iocregchk(wlc_info_t *wlc, uint band) +int wlc_iocregchk(struct wlc_info *wlc, uint band) { /* if band is specified, it must be the current band */ if ((band != WLC_BAND_AUTO) && (band != (uint) wlc->band->bandtype)) @@ -4240,7 +4242,7 @@ int wlc_iocregchk(wlc_info_t *wlc, uint band) #if defined(BCMDBG) /* For some ioctls, make sure that the pi pointer matches the current phy */ -int wlc_iocpichk(wlc_info_t *wlc, uint phytype) +int wlc_iocpichk(struct wlc_info *wlc, uint phytype) { if (wlc->band->phytype != phytype) return BCME_BADBAND; @@ -4274,21 +4276,21 @@ static const bcm_iovar_t *wlc_iovar_lookup(const bcm_iovar_t *table, } /* simplified integer get interface for common WLC_GET_VAR ioctl handler */ -int wlc_iovar_getint(wlc_info_t *wlc, const char *name, int *arg) +int wlc_iovar_getint(struct wlc_info *wlc, const char *name, int *arg) { return wlc_iovar_op(wlc, name, NULL, 0, arg, sizeof(s32), IOV_GET, NULL); } /* simplified integer set interface for common WLC_SET_VAR ioctl handler */ -int wlc_iovar_setint(wlc_info_t *wlc, const char *name, int arg) +int wlc_iovar_setint(struct wlc_info *wlc, const char *name, int arg) { return wlc_iovar_op(wlc, name, NULL, 0, (void *)&arg, sizeof(arg), IOV_SET, NULL); } /* simplified s8 get interface for common WLC_GET_VAR ioctl handler */ -int wlc_iovar_gets8(wlc_info_t *wlc, const char *name, s8 *arg) +int wlc_iovar_gets8(struct wlc_info *wlc, const char *name, s8 *arg) { int iovar_int; int err; @@ -4311,7 +4313,7 @@ int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars, const char *name, void *hdl, iovar_fn_t i_fn, watchdog_fn_t w_fn, down_fn_t d_fn) { - wlc_info_t *wlc = (wlc_info_t *) pub->wlc; + struct wlc_info *wlc = (struct wlc_info *) pub->wlc; int i; ASSERT(name != NULL); @@ -4339,7 +4341,7 @@ int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars, /* unregister module callbacks */ int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl) { - wlc_info_t *wlc = (wlc_info_t *) pub->wlc; + struct wlc_info *wlc = (struct wlc_info *) pub->wlc; int i; if (wlc == NULL) @@ -4360,7 +4362,7 @@ int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl) } /* Write WME tunable parameters for retransmit/max rate from wlc struct to ucode */ -static void wlc_wme_retries_write(wlc_info_t *wlc) +static void wlc_wme_retries_write(struct wlc_info *wlc) { int ac; @@ -4382,7 +4384,7 @@ static void wlc_wme_retries_write(wlc_info_t *wlc) * All pointers may point into the same buffer. */ int -wlc_iovar_op(wlc_info_t *wlc, const char *name, +wlc_iovar_op(struct wlc_info *wlc, const char *name, void *params, int p_len, void *arg, int len, bool set, struct wlc_if *wlcif) { @@ -4456,7 +4458,7 @@ int wlc_iovar_check(wlc_pub_t *pub, const bcm_iovar_t *vi, void *arg, int len, bool set) { - wlc_info_t *wlc = (wlc_info_t *) pub->wlc; + struct wlc_info *wlc = (struct wlc_info *) pub->wlc; int err = 0; s32 int_val = 0; @@ -4524,7 +4526,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, const char *name, void *params, uint p_len, void *arg, int len, int val_size, struct wlc_if *wlcif) { - wlc_info_t *wlc = hdl; + struct wlc_info *wlc = hdl; wlc_bsscfg_t *bsscfg; int err = 0; s32 int_val = 0; @@ -4628,7 +4630,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, } static int -wlc_iovar_rangecheck(wlc_info_t *wlc, u32 val, const bcm_iovar_t *vi) +wlc_iovar_rangecheck(struct wlc_info *wlc, u32 val, const bcm_iovar_t *vi) { int err = 0; u32 min_val = 0; @@ -4725,7 +4727,7 @@ void wlc_print_txstatus(tx_status_t *txs) #define MACSTATUPD(name) \ wlc_ctrupd_cache(macstats.name, &wlc->core->macstat_snapshot->name, &wlc->pub->_cnt->name) -void wlc_statsupd(wlc_info_t *wlc) +void wlc_statsupd(struct wlc_info *wlc) { int i; #ifdef BCMDBG @@ -4977,7 +4979,7 @@ int wlc_format_ssid(char *buf, const unsigned char ssid[], uint ssid_len) } #endif /* defined(BCMDBG) */ -u16 wlc_rate_shm_offset(wlc_info_t *wlc, u8 rate) +u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate) { return wlc_bmac_rate_shm_offset(wlc->hw, rate); } @@ -4994,13 +4996,13 @@ u16 wlc_rate_shm_offset(wlc_info_t *wlc, u8 rate) * Returns true if packet consumed (queued), false if not. */ bool BCMFASTPATH -wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec) +wlc_prec_enq(struct wlc_info *wlc, struct pktq *q, void *pkt, int prec) { return wlc_prec_enq_head(wlc, q, pkt, prec, false); } bool BCMFASTPATH -wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, struct sk_buff *pkt, +wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q, struct sk_buff *pkt, int prec, bool head) { struct sk_buff *p; @@ -5067,7 +5069,7 @@ wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, struct sk_buff *pkt, void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, uint prec) { - wlc_info_t *wlc = (wlc_info_t *) ctx; + struct wlc_info *wlc = (struct wlc_info *) ctx; wlc_txq_info_t *qi = wlc->active_queue; /* Check me */ struct pktq *q = &qi->q; int prio; @@ -5105,7 +5107,7 @@ void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, } bool BCMFASTPATH -wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, +wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw) { u8 prio; @@ -5141,7 +5143,7 @@ wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, return 0; } -void BCMFASTPATH wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi) +void BCMFASTPATH wlc_send_q(struct wlc_info *wlc, wlc_txq_info_t *qi) { struct sk_buff *pkt[DOT11_MAXNUMFRAGS]; int prec; @@ -5216,7 +5218,7 @@ void BCMFASTPATH wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi) * for MC frames so is used as part of the sequence number. */ static inline u16 -bcmc_fid_generate(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh) +bcmc_fid_generate(struct wlc_info *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh) { u16 frameid; @@ -5230,7 +5232,7 @@ bcmc_fid_generate(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, d11txh_t *txh) } void BCMFASTPATH -wlc_txfifo(wlc_info_t *wlc, uint fifo, struct sk_buff *p, bool commit, +wlc_txfifo(struct wlc_info *wlc, uint fifo, struct sk_buff *p, bool commit, s8 txpktpend) { u16 frameid = INVALIDFID; @@ -5270,7 +5272,7 @@ wlc_txfifo(wlc_info_t *wlc, uint fifo, struct sk_buff *p, bool commit, } static u16 -wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, uint length) +wlc_compute_airtime(struct wlc_info *wlc, ratespec_t rspec, uint length) { u16 usec = 0; uint mac_rate = RSPEC2RATE(rspec); @@ -5315,7 +5317,7 @@ wlc_compute_airtime(wlc_info_t *wlc, ratespec_t rspec, uint length) } void BCMFASTPATH -wlc_compute_plcp(wlc_info_t *wlc, ratespec_t rspec, uint length, u8 *plcp) +wlc_compute_plcp(struct wlc_info *wlc, ratespec_t rspec, uint length, u8 *plcp) { if (IS_MCS(rspec)) { wlc_compute_mimo_plcp(rspec, length, plcp); @@ -5439,7 +5441,7 @@ static void wlc_compute_cck_plcp(ratespec_t rspec, uint length, u8 *plcp) * preamble_type use short/GF or long/MM PLCP header */ static u16 BCMFASTPATH -wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type, +wlc_compute_frame_dur(struct wlc_info *wlc, ratespec_t rate, u8 preamble_type, uint next_frag_len) { u16 dur, sifs; @@ -5473,7 +5475,7 @@ wlc_compute_frame_dur(wlc_info_t *wlc, ratespec_t rate, u8 preamble_type, * frame_len next MPDU frame length in bytes */ u16 BCMFASTPATH -wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, ratespec_t rts_rate, +wlc_compute_rtscts_dur(struct wlc_info *wlc, bool cts_only, ratespec_t rts_rate, ratespec_t frame_rate, u8 rts_preamble_type, u8 frame_preamble_type, uint frame_len, bool ba) { @@ -5504,7 +5506,7 @@ wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, ratespec_t rts_rate, return dur; } -static bool wlc_phy_rspec_check(wlc_info_t *wlc, u16 bw, ratespec_t rspec) +static bool wlc_phy_rspec_check(struct wlc_info *wlc, u16 bw, ratespec_t rspec) { if (IS_MCS(rspec)) { uint mcs = rspec & RSPEC_RATE_MASK; @@ -5530,7 +5532,7 @@ static bool wlc_phy_rspec_check(wlc_info_t *wlc, u16 bw, ratespec_t rspec) return true; } -u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec) +u16 BCMFASTPATH wlc_phytxctl1_calc(struct wlc_info *wlc, ratespec_t rspec) { u16 phyctl1 = 0; u16 bw; @@ -5587,7 +5589,7 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec) } ratespec_t BCMFASTPATH -wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, bool use_rspec, +wlc_rspec_to_rts_rspec(struct wlc_info *wlc, ratespec_t rspec, bool use_rspec, u16 mimo_ctlchbw) { ratespec_t rts_rspec = 0; @@ -5643,7 +5645,7 @@ wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, bool use_rspec, * */ static u16 BCMFASTPATH -wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, +wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, struct sk_buff *p, struct scb *scb, uint frag, uint nfrags, uint queue, uint next_frag_len, wsec_key_t *key, ratespec_t rspec_override) @@ -6309,7 +6311,7 @@ wlc_d11hdrs_mac80211(wlc_info_t *wlc, struct ieee80211_hw *hw, return 0; } -void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs) +void wlc_tbtt(struct wlc_info *wlc, d11regs_t *regs) { wlc_bsscfg_t *cfg = wlc->cfg; @@ -6345,19 +6347,19 @@ void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs) } /* GP timer is a freerunning 32 bit counter, decrements at 1 us rate */ -void wlc_hwtimer_gptimer_set(wlc_info_t *wlc, uint us) +void wlc_hwtimer_gptimer_set(struct wlc_info *wlc, uint us) { ASSERT(wlc->pub->corerev >= 3); /* no gptimer in earlier revs */ W_REG(wlc->osh, &wlc->regs->gptimer, us); } -void wlc_hwtimer_gptimer_abort(wlc_info_t *wlc) +void wlc_hwtimer_gptimer_abort(struct wlc_info *wlc) { ASSERT(wlc->pub->corerev >= 3); W_REG(wlc->osh, &wlc->regs->gptimer, 0); } -static void wlc_hwtimer_gptimer_cb(wlc_info_t *wlc) +static void wlc_hwtimer_gptimer_cb(struct wlc_info *wlc) { /* when interrupt is generated, the counter is loaded with last value * written and continue to decrement. So it has to be cleaned first @@ -6370,7 +6372,7 @@ static void wlc_hwtimer_gptimer_cb(wlc_info_t *wlc) * POLICY: no macinstatus change, no bounding loop. * All dpc bounding should be handled in BMAC dpc, like txstatus and rxint */ -void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus) +void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus) { d11regs_t *regs = wlc->regs; #ifdef BCMDBG @@ -6463,7 +6465,7 @@ void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus) ASSERT(wlc_ps_check(wlc)); } -static void *wlc_15420war(wlc_info_t *wlc, uint queue) +static void *wlc_15420war(struct wlc_info *wlc, uint queue) { hnddma_t *di; void *p; @@ -6493,7 +6495,7 @@ static void *wlc_15420war(wlc_info_t *wlc, uint queue) return p; } -static void wlc_war16165(wlc_info_t *wlc, bool tx) +static void wlc_war16165(struct wlc_info *wlc, bool tx) { if (tx) { /* the post-increment is used in STAY_AWAKE macro */ @@ -6509,7 +6511,7 @@ static void wlc_war16165(wlc_info_t *wlc, bool tx) /* process an individual tx_status_t */ /* WLC_HIGH_API */ bool BCMFASTPATH -wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) +wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) { struct sk_buff *p; uint queue; @@ -6676,7 +6678,7 @@ wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2) } void BCMFASTPATH -wlc_txfifo_complete(wlc_info_t *wlc, uint fifo, s8 txpktpend) +wlc_txfifo_complete(struct wlc_info *wlc, uint fifo, s8 txpktpend) { TXPKTPENDDEC(wlc, fifo, txpktpend); WL_TRACE(("wlc_txfifo_complete, pktpend dec %d to %d\n", txpktpend, @@ -6780,7 +6782,7 @@ u32 wlc_calc_tbtt_offset(u32 bp, u32 tsf_h, u32 tsf_l) } /* Update beacon listen interval in shared memory */ -void wlc_bcn_li_upd(wlc_info_t *wlc) +void wlc_bcn_li_upd(struct wlc_info *wlc) { if (AP_ENAB(wlc->pub)) return; @@ -6794,7 +6796,7 @@ void wlc_bcn_li_upd(wlc_info_t *wlc) } static void -prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, struct sk_buff *p, +prep_mac80211_status(struct wlc_info *wlc, d11rxhdr_t *rxh, struct sk_buff *p, struct ieee80211_rx_status *rx_status) { u32 tsf_l, tsf_h; @@ -6904,7 +6906,7 @@ prep_mac80211_status(wlc_info_t *wlc, d11rxhdr_t *rxh, struct sk_buff *p, } static void -wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, +wlc_recvctl(struct wlc_info *wlc, struct osl_info *osh, d11rxhdr_t *rxh, struct sk_buff *p) { int len_mpdu; @@ -6939,7 +6941,7 @@ wlc_recvctl(wlc_info_t *wlc, struct osl_info *osh, d11rxhdr_t *rxh, return; } -void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list) +void wlc_bss_list_free(struct wlc_info *wlc, wlc_bss_list_t *bss_list) { uint index; wlc_bss_info_t *bi; @@ -6968,7 +6970,7 @@ void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list) * Param 'bound' indicates max. # frames to process before break out. */ /* WLC_HIGH_API */ -void BCMFASTPATH wlc_recv(wlc_info_t *wlc, struct sk_buff *p) +void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) { d11rxhdr_t *rxh; struct dot11_header *h; @@ -7064,7 +7066,7 @@ void BCMFASTPATH wlc_recv(wlc_info_t *wlc, struct sk_buff *p) * len = 3(nsyms + nstream + 3) - 3 */ u16 BCMFASTPATH -wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, uint mac_len) +wlc_calc_lsig_len(struct wlc_info *wlc, ratespec_t ratespec, uint mac_len) { uint nsyms, len = 0, kNdps; @@ -7105,7 +7107,7 @@ wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, uint mac_len) /* calculate frame duration of a given rate and length, return time in usec unit */ uint BCMFASTPATH -wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type, +wlc_calc_frame_time(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type, uint mac_len) { uint nsyms, dur = 0, Ndps, kNdps; @@ -7175,7 +7177,7 @@ wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type, /* The opposite of wlc_calc_frame_time */ static uint -wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type, +wlc_calc_frame_len(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type, uint dur) { uint nsyms, mac_len, Ndps, kNdps; @@ -7221,7 +7223,7 @@ wlc_calc_frame_len(wlc_info_t *wlc, ratespec_t ratespec, u8 preamble_type, } static uint -wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type) +wlc_calc_ba_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) { WL_TRACE(("wl%d: wlc_calc_ba_time: rspec 0x%x, preamble_type %d\n", wlc->pub->unit, rspec, preamble_type)); @@ -7238,7 +7240,7 @@ wlc_calc_ba_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type) } static uint BCMFASTPATH -wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type) +wlc_calc_ack_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) { uint dur = 0; @@ -7258,7 +7260,7 @@ wlc_calc_ack_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type) } static uint -wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type) +wlc_calc_cts_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) { WL_TRACE(("wl%d: wlc_calc_cts_time: ratespec 0x%x, preamble_type %d\n", wlc->pub->unit, rspec, preamble_type)); @@ -7266,7 +7268,7 @@ wlc_calc_cts_time(wlc_info_t *wlc, ratespec_t rspec, u8 preamble_type) } /* derive wlc->band->basic_rate[] table from 'rateset' */ -void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset) +void wlc_rate_lookup_init(struct wlc_info *wlc, wlc_rateset_t *rateset) { u8 rate; u8 mandatory; @@ -7355,7 +7357,7 @@ void wlc_rate_lookup_init(wlc_info_t *wlc, wlc_rateset_t *rateset) } } -static void wlc_write_rate_shm(wlc_info_t *wlc, u8 rate, u8 basic_rate) +static void wlc_write_rate_shm(struct wlc_info *wlc, u8 rate, u8 basic_rate) { u8 phy_rate, index; u8 basic_phy_rate, basic_index; @@ -7388,7 +7390,7 @@ static void wlc_write_rate_shm(wlc_info_t *wlc, u8 rate, u8 basic_rate) wlc_write_shm(wlc, (basic_table + index * 2), basic_ptr); } -static const wlc_rateset_t *wlc_rateset_get_hwrs(wlc_info_t *wlc) +static const wlc_rateset_t *wlc_rateset_get_hwrs(struct wlc_info *wlc) { const wlc_rateset_t *rs_dflt; @@ -7405,7 +7407,7 @@ static const wlc_rateset_t *wlc_rateset_get_hwrs(wlc_info_t *wlc) return rs_dflt; } -void wlc_set_ratetable(wlc_info_t *wlc) +void wlc_set_ratetable(struct wlc_info *wlc) { const wlc_rateset_t *rs_dflt; wlc_rateset_t rs; @@ -7441,7 +7443,8 @@ void wlc_set_ratetable(wlc_info_t *wlc) * Return true if the specified rate is supported by the specified band. * WLC_BAND_AUTO indicates the current band. */ -bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rspec, int band, bool verbose) +bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rspec, int band, + bool verbose) { wlc_rateset_t *hw_rateset; uint i; @@ -7474,7 +7477,7 @@ bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rspec, int band, bool verbose) return false; } -static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap) +static void wlc_update_mimo_band_bwcap(struct wlc_info *wlc, u8 bwcap) { uint i; wlcband_t *band; @@ -7501,7 +7504,7 @@ static void wlc_update_mimo_band_bwcap(wlc_info_t *wlc, u8 bwcap) wlc->mimo_band_bwcap = bwcap; } -void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len) +void wlc_mod_prb_rsp_rate_table(struct wlc_info *wlc, uint frame_len) { const wlc_rateset_t *rs_dflt; wlc_rateset_t rs; @@ -7544,8 +7547,8 @@ void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len) } u16 -wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec, bool short_preamble, - bool phydelay) +wlc_compute_bcntsfoff(struct wlc_info *wlc, ratespec_t rspec, + bool short_preamble, bool phydelay) { uint bcntsfoff = 0; @@ -7591,7 +7594,7 @@ wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec, bool short_preamble, * and included up to, but not including, the 4 byte FCS. */ static void -wlc_bcn_prb_template(wlc_info_t *wlc, uint type, ratespec_t bcn_rspec, +wlc_bcn_prb_template(struct wlc_info *wlc, uint type, ratespec_t bcn_rspec, wlc_bsscfg_t *cfg, u16 *buf, int *len) { cck_phy_hdr_t *plcp; @@ -7658,7 +7661,7 @@ int wlc_get_header_len() * template updated. * Otherwise, it updates the hardware template. */ -void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg) +void wlc_bss_update_beacon(struct wlc_info *wlc, wlc_bsscfg_t *cfg) { int len = BCN_TMPL_LEN; @@ -7711,7 +7714,7 @@ void wlc_bss_update_beacon(wlc_info_t *wlc, wlc_bsscfg_t *cfg) /* * Update all beacons for the system. */ -void wlc_update_beacon(wlc_info_t *wlc) +void wlc_update_beacon(struct wlc_info *wlc) { int idx; wlc_bsscfg_t *bsscfg; @@ -7724,7 +7727,7 @@ void wlc_update_beacon(wlc_info_t *wlc) } /* Write ssid into shared memory */ -void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg) +void wlc_shm_ssid_upd(struct wlc_info *wlc, wlc_bsscfg_t *cfg) { u8 *ssidptr = cfg->SSID; u16 base = M_SSID; @@ -7740,7 +7743,7 @@ void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg) wlc_write_shm(wlc, M_SSIDLEN, (u16) cfg->SSID_len); } -void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend) +void wlc_update_probe_resp(struct wlc_info *wlc, bool suspend) { int idx; wlc_bsscfg_t *bsscfg; @@ -7753,7 +7756,7 @@ void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend) } void -wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend) +wlc_bss_update_probe_resp(struct wlc_info *wlc, wlc_bsscfg_t *cfg, bool suspend) { u16 prb_resp[BCN_TMPL_LEN / 2]; int len = BCN_TMPL_LEN; @@ -7794,7 +7797,7 @@ wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, bool suspend) } /* prepares pdu for transmission. returns BCM error codes */ -int wlc_prep_pdu(wlc_info_t *wlc, struct sk_buff *pdu, uint *fifop) +int wlc_prep_pdu(struct wlc_info *wlc, struct sk_buff *pdu, uint *fifop) { struct osl_info *osh; uint fifo; @@ -7833,7 +7836,7 @@ int wlc_prep_pdu(wlc_info_t *wlc, struct sk_buff *pdu, uint *fifop) } /* init tx reported rate mechanism */ -void wlc_reprate_init(wlc_info_t *wlc) +void wlc_reprate_init(struct wlc_info *wlc) { int i; wlc_bsscfg_t *bsscfg; @@ -7853,7 +7856,7 @@ void wlc_bsscfg_reprate_init(wlc_bsscfg_t *bsscfg) /* Retrieve a consolidated set of revision information, * typically for the WLC_GET_REVINFO ioctl */ -int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len) +int wlc_get_revision_info(struct wlc_info *wlc, void *buf, uint len) { wlc_rev_info_t *rinfo = (wlc_rev_info_t *) buf; @@ -7887,7 +7890,7 @@ int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len) return BCME_OK; } -void wlc_default_rateset(wlc_info_t *wlc, wlc_rateset_t *rs) +void wlc_default_rateset(struct wlc_info *wlc, wlc_rateset_t *rs) { wlc_rateset_default(rs, NULL, wlc->band->phytype, wlc->band->bandtype, false, RATE_MASK_FULL, (bool) N_ENAB(wlc->pub), @@ -7895,7 +7898,7 @@ void wlc_default_rateset(wlc_info_t *wlc, wlc_rateset_t *rs) wlc->stf->txstreams); } -static void wlc_bss_default_init(wlc_info_t *wlc) +static void wlc_bss_default_init(struct wlc_info *wlc) { chanspec_t chanspec; wlcband_t *band; @@ -7933,7 +7936,7 @@ static void wlc_bss_default_init(wlc_info_t *wlc) /* Deferred event processing */ static void wlc_process_eventq(void *arg) { - wlc_info_t *wlc = (wlc_info_t *) arg; + struct wlc_info *wlc = (struct wlc_info *) arg; wlc_event_t *etmp; while ((etmp = wlc_eventq_deq(wlc->eventq))) { @@ -7959,7 +7962,7 @@ wlc_uint64_sub(u32 *a_high, u32 *a_low, u32 b_high, u32 b_low) } static ratespec_t -mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val) +mac80211_wlc_set_nrate(struct wlc_info *wlc, wlcband_t *cur_band, u32 int_val) { u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT; u8 rate = int_val & NRATE_RATE_MASK; @@ -8073,7 +8076,7 @@ mac80211_wlc_set_nrate(wlc_info_t *wlc, wlcband_t *cur_band, u32 int_val) /* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */ static int -wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM, +wlc_duty_cycle_set(struct wlc_info *wlc, int duty_cycle, bool isOFDM, bool writeToShm) { int idle_busy_ratio_x_16 = 0; @@ -8102,7 +8105,7 @@ wlc_duty_cycle_set(wlc_info_t *wlc, int duty_cycle, bool isOFDM, /* Read a single u16 from shared memory. * SHM 'offset' needs to be an even address */ -u16 wlc_read_shm(wlc_info_t *wlc, uint offset) +u16 wlc_read_shm(struct wlc_info *wlc, uint offset) { return wlc_bmac_read_shm(wlc->hw, offset); } @@ -8110,7 +8113,7 @@ u16 wlc_read_shm(wlc_info_t *wlc, uint offset) /* Write a single u16 to shared memory. * SHM 'offset' needs to be an even address */ -void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v) +void wlc_write_shm(struct wlc_info *wlc, uint offset, u16 v) { wlc_bmac_write_shm(wlc->hw, offset, v); } @@ -8119,7 +8122,7 @@ void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v) * SHM 'offset' needs to be an even address and * Range length 'len' must be an even number of bytes */ -void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len) +void wlc_set_shm(struct wlc_info *wlc, uint offset, u16 v, int len) { /* offset and len need to be even */ ASSERT((offset & 1) == 0); @@ -8135,7 +8138,7 @@ void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len) * SHM 'offset' needs to be an even address and * Buffer length 'len' must be an even number of bytes */ -void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf, int len) +void wlc_copyto_shm(struct wlc_info *wlc, uint offset, const void *buf, int len) { /* offset and len need to be even */ ASSERT((offset & 1) == 0); @@ -8151,7 +8154,7 @@ void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf, int len) * SHM 'offset' needs to be an even address and * Buffer length 'len' must be an even number of bytes */ -void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len) +void wlc_copyfrom_shm(struct wlc_info *wlc, uint offset, void *buf, int len) { /* offset and len need to be even */ ASSERT((offset & 1) == 0); @@ -8164,71 +8167,73 @@ void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len) } /* wrapper BMAC functions to for HIGH driver access */ -void wlc_mctrl(wlc_info_t *wlc, u32 mask, u32 val) +void wlc_mctrl(struct wlc_info *wlc, u32 mask, u32 val) { wlc_bmac_mctrl(wlc->hw, mask, val); } -void wlc_corereset(wlc_info_t *wlc, u32 flags) +void wlc_corereset(struct wlc_info *wlc, u32 flags) { wlc_bmac_corereset(wlc->hw, flags); } -void wlc_mhf(wlc_info_t *wlc, u8 idx, u16 mask, u16 val, int bands) +void wlc_mhf(struct wlc_info *wlc, u8 idx, u16 mask, u16 val, int bands) { wlc_bmac_mhf(wlc->hw, idx, mask, val, bands); } -u16 wlc_mhf_get(wlc_info_t *wlc, u8 idx, int bands) +u16 wlc_mhf_get(struct wlc_info *wlc, u8 idx, int bands) { return wlc_bmac_mhf_get(wlc->hw, idx, bands); } -int wlc_xmtfifo_sz_get(wlc_info_t *wlc, uint fifo, uint *blocks) +int wlc_xmtfifo_sz_get(struct wlc_info *wlc, uint fifo, uint *blocks) { return wlc_bmac_xmtfifo_sz_get(wlc->hw, fifo, blocks); } -void wlc_write_template_ram(wlc_info_t *wlc, int offset, int len, void *buf) +void wlc_write_template_ram(struct wlc_info *wlc, int offset, int len, + void *buf) { wlc_bmac_write_template_ram(wlc->hw, offset, len, buf); } -void wlc_write_hw_bcntemplates(wlc_info_t *wlc, void *bcn, int len, bool both) +void wlc_write_hw_bcntemplates(struct wlc_info *wlc, void *bcn, int len, + bool both) { wlc_bmac_write_hw_bcntemplates(wlc->hw, bcn, len, both); } void -wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, +wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset, const struct ether_addr *addr) { wlc_bmac_set_addrmatch(wlc->hw, match_reg_offset, addr); } -void wlc_set_rcmta(wlc_info_t *wlc, int idx, const struct ether_addr *addr) +void wlc_set_rcmta(struct wlc_info *wlc, int idx, const struct ether_addr *addr) { wlc_bmac_set_rcmta(wlc->hw, idx, addr); } -void wlc_read_tsf(wlc_info_t *wlc, u32 *tsf_l_ptr, u32 *tsf_h_ptr) +void wlc_read_tsf(struct wlc_info *wlc, u32 *tsf_l_ptr, u32 *tsf_h_ptr) { wlc_bmac_read_tsf(wlc->hw, tsf_l_ptr, tsf_h_ptr); } -void wlc_set_cwmin(wlc_info_t *wlc, u16 newmin) +void wlc_set_cwmin(struct wlc_info *wlc, u16 newmin) { wlc->band->CWmin = newmin; wlc_bmac_set_cwmin(wlc->hw, newmin); } -void wlc_set_cwmax(wlc_info_t *wlc, u16 newmax) +void wlc_set_cwmax(struct wlc_info *wlc, u16 newmax) { wlc->band->CWmax = newmax; wlc_bmac_set_cwmax(wlc->hw, newmax); } -void wlc_fifoerrors(wlc_info_t *wlc) +void wlc_fifoerrors(struct wlc_info *wlc) { wlc_bmac_fifoerrors(wlc->hw); @@ -8236,16 +8241,16 @@ void wlc_fifoerrors(wlc_info_t *wlc) /* Search mem rw utilities */ -void wlc_pllreq(wlc_info_t *wlc, bool set, mbool req_bit) +void wlc_pllreq(struct wlc_info *wlc, bool set, mbool req_bit) { wlc_bmac_pllreq(wlc->hw, set, req_bit); } -void wlc_reset_bmac_done(wlc_info_t *wlc) +void wlc_reset_bmac_done(struct wlc_info *wlc) { } -void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode) +void wlc_ht_mimops_cap_update(struct wlc_info *wlc, u8 mimops_mode) { wlc->ht_cap.cap &= ~HT_CAP_MIMO_PS_MASK; wlc->ht_cap.cap |= (mimops_mode << HT_CAP_MIMO_PS_SHIFT); @@ -8258,7 +8263,7 @@ void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode) /* check for the particular priority flow control bit being set */ bool -wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *q, int prio) +wlc_txflowcontrol_prio_isset(struct wlc_info *wlc, wlc_txq_info_t *q, int prio) { uint prio_mask; @@ -8273,7 +8278,8 @@ wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *q, int prio) } /* propogate the flow control to all interfaces using the given tx queue */ -void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, int prio) +void wlc_txflowcontrol(struct wlc_info *wlc, wlc_txq_info_t *qi, + bool on, int prio) { uint prio_bits; uint cur_bits; @@ -8315,7 +8321,7 @@ void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, int prio) } void -wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, +wlc_txflowcontrol_override(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on, uint override) { uint prev_override; @@ -8362,7 +8368,7 @@ wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, } } -static void wlc_txflowcontrol_reset(wlc_info_t *wlc) +static void wlc_txflowcontrol_reset(struct wlc_info *wlc) { wlc_txq_info_t *qi; @@ -8375,7 +8381,7 @@ static void wlc_txflowcontrol_reset(wlc_info_t *wlc) } static void -wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, +wlc_txflowcontrol_signal(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on, int prio) { wlc_if_t *wlcif; @@ -8386,7 +8392,7 @@ wlc_txflowcontrol_signal(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, } } -static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, struct osl_info *osh) +static wlc_txq_info_t *wlc_txq_alloc(struct wlc_info *wlc, struct osl_info *osh) { wlc_txq_info_t *qi, *p; @@ -8416,7 +8422,7 @@ static wlc_txq_info_t *wlc_txq_alloc(wlc_info_t *wlc, struct osl_info *osh) return qi; } -static void wlc_txq_free(wlc_info_t *wlc, struct osl_info *osh, +static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh, wlc_txq_info_t *qi) { wlc_txq_info_t *p; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 2a6cf2ab19dd..b246a7c22ab0 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -350,7 +350,7 @@ typedef struct wlcband { typedef void (*cb_fn_t) (void *); /* tx completion callback takes 3 args */ -typedef void (*pkcb_fn_t) (wlc_info_t *wlc, uint txstatus, void *arg); +typedef void (*pkcb_fn_t) (struct wlc_info *wlc, uint txstatus, void *arg); typedef struct pkt_cb { pkcb_fn_t fn; /* function to call when tx frame completes */ @@ -421,7 +421,7 @@ typedef struct wlc_hwband { struct wlc_hw_info { struct osl_info *osh; /* pointer to os handle */ bool _piomode; /* true if pio mode */ - wlc_info_t *wlc; + struct wlc_info *wlc; /* fifo */ hnddma_t *di[NFIFO]; /* hnddma handles, per fifo */ @@ -782,7 +782,7 @@ struct wlc_info { /* antsel module specific state */ struct antsel_info { - wlc_info_t *wlc; /* pointer to main wlc structure */ + struct wlc_info *wlc; /* pointer to main wlc structure */ wlc_pub_t *pub; /* pointer to public fn */ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board @@ -815,44 +815,45 @@ struct antsel_info { #define WLC_IS_MATCH_SSID(wlc, ssid1, ssid2, len1, len2) \ ((len1 == len2) && !memcmp(ssid1, ssid2, len1)) -extern void wlc_high_dpc(wlc_info_t *wlc, u32 macintstatus); -extern void wlc_fatal_error(wlc_info_t *wlc); -extern void wlc_bmac_rpc_watchdog(wlc_info_t *wlc); -extern void wlc_recv(wlc_info_t *wlc, struct sk_buff *p); -extern bool wlc_dotxstatus(wlc_info_t *wlc, tx_status_t *txs, u32 frm_tx2); -extern void wlc_txfifo(wlc_info_t *wlc, uint fifo, struct sk_buff *p, +extern void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus); +extern void wlc_fatal_error(struct wlc_info *wlc); +extern void wlc_bmac_rpc_watchdog(struct wlc_info *wlc); +extern void wlc_recv(struct wlc_info *wlc, struct sk_buff *p); +extern bool wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2); +extern void wlc_txfifo(struct wlc_info *wlc, uint fifo, struct sk_buff *p, bool commit, s8 txpktpend); -extern void wlc_txfifo_complete(wlc_info_t *wlc, uint fifo, s8 txpktpend); +extern void wlc_txfifo_complete(struct wlc_info *wlc, uint fifo, s8 txpktpend); extern void wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, uint prec); -extern void wlc_info_init(wlc_info_t *wlc, int unit); +extern void wlc_info_init(struct wlc_info *wlc, int unit); extern void wlc_print_txstatus(tx_status_t *txs); -extern int wlc_xmtfifo_sz_get(wlc_info_t *wlc, uint fifo, uint *blocks); -extern void wlc_write_template_ram(wlc_info_t *wlc, int offset, int len, +extern int wlc_xmtfifo_sz_get(struct wlc_info *wlc, uint fifo, uint *blocks); +extern void wlc_write_template_ram(struct wlc_info *wlc, int offset, int len, void *buf); -extern void wlc_write_hw_bcntemplates(wlc_info_t *wlc, void *bcn, int len, +extern void wlc_write_hw_bcntemplates(struct wlc_info *wlc, void *bcn, int len, bool both); #if defined(BCMDBG) -extern void wlc_get_rcmta(wlc_info_t *wlc, int idx, struct ether_addr *addr); +extern void wlc_get_rcmta(struct wlc_info *wlc, int idx, + struct ether_addr *addr); #endif -extern void wlc_set_rcmta(wlc_info_t *wlc, int idx, +extern void wlc_set_rcmta(struct wlc_info *wlc, int idx, const struct ether_addr *addr); -extern void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, +extern void wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset, const struct ether_addr *addr); -extern void wlc_read_tsf(wlc_info_t *wlc, u32 *tsf_l_ptr, +extern void wlc_read_tsf(struct wlc_info *wlc, u32 *tsf_l_ptr, u32 *tsf_h_ptr); -extern void wlc_set_cwmin(wlc_info_t *wlc, u16 newmin); -extern void wlc_set_cwmax(wlc_info_t *wlc, u16 newmax); -extern void wlc_fifoerrors(wlc_info_t *wlc); -extern void wlc_pllreq(wlc_info_t *wlc, bool set, mbool req_bit); -extern void wlc_reset_bmac_done(wlc_info_t *wlc); -extern void wlc_protection_upd(wlc_info_t *wlc, uint idx, int val); -extern void wlc_hwtimer_gptimer_set(wlc_info_t *wlc, uint us); -extern void wlc_hwtimer_gptimer_abort(wlc_info_t *wlc); +extern void wlc_set_cwmin(struct wlc_info *wlc, u16 newmin); +extern void wlc_set_cwmax(struct wlc_info *wlc, u16 newmax); +extern void wlc_fifoerrors(struct wlc_info *wlc); +extern void wlc_pllreq(struct wlc_info *wlc, bool set, mbool req_bit); +extern void wlc_reset_bmac_done(struct wlc_info *wlc); +extern void wlc_protection_upd(struct wlc_info *wlc, uint idx, int val); +extern void wlc_hwtimer_gptimer_set(struct wlc_info *wlc, uint us); +extern void wlc_hwtimer_gptimer_abort(struct wlc_info *wlc); #if defined(BCMDBG) extern void wlc_print_rxh(d11rxhdr_t *rxh); -extern void wlc_print_hdrs(wlc_info_t *wlc, const char *prefix, u8 *frame, +extern void wlc_print_hdrs(struct wlc_info *wlc, const char *prefix, u8 *frame, d11txh_t *txh, d11rxhdr_t *rxh, uint len); extern void wlc_print_txdesc(d11txh_t *txh); #endif @@ -863,79 +864,83 @@ extern void wlc_print_dot11_mac_hdr(u8 *buf, int len); extern void wlc_setxband(wlc_hw_info_t *wlc_hw, uint bandunit); extern void wlc_coredisable(wlc_hw_info_t *wlc_hw); -extern bool wlc_valid_rate(wlc_info_t *wlc, ratespec_t rate, int band, +extern bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rate, int band, bool verbose); -extern void wlc_ap_upd(wlc_info_t *wlc); +extern void wlc_ap_upd(struct wlc_info *wlc); /* helper functions */ -extern void wlc_shm_ssid_upd(wlc_info_t *wlc, wlc_bsscfg_t *cfg); -extern int wlc_set_gmode(wlc_info_t *wlc, u8 gmode, bool config); +extern void wlc_shm_ssid_upd(struct wlc_info *wlc, wlc_bsscfg_t *cfg); +extern int wlc_set_gmode(struct wlc_info *wlc, u8 gmode, bool config); -extern void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc); -extern void wlc_mac_bcn_promisc(wlc_info_t *wlc); -extern void wlc_mac_promisc(wlc_info_t *wlc); -extern void wlc_txflowcontrol(wlc_info_t *wlc, wlc_txq_info_t *qi, bool on, +extern void wlc_mac_bcn_promisc_change(struct wlc_info *wlc, bool promisc); +extern void wlc_mac_bcn_promisc(struct wlc_info *wlc); +extern void wlc_mac_promisc(struct wlc_info *wlc); +extern void wlc_txflowcontrol(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on, int prio); -extern void wlc_txflowcontrol_override(wlc_info_t *wlc, wlc_txq_info_t *qi, +extern void wlc_txflowcontrol_override(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on, uint override); -extern bool wlc_txflowcontrol_prio_isset(wlc_info_t *wlc, wlc_txq_info_t *qi, - int prio); -extern void wlc_send_q(wlc_info_t *wlc, wlc_txq_info_t *qi); -extern int wlc_prep_pdu(wlc_info_t *wlc, struct sk_buff *pdu, uint *fifo); +extern bool wlc_txflowcontrol_prio_isset(struct wlc_info *wlc, + wlc_txq_info_t *qi, int prio); +extern void wlc_send_q(struct wlc_info *wlc, wlc_txq_info_t *qi); +extern int wlc_prep_pdu(struct wlc_info *wlc, struct sk_buff *pdu, uint *fifo); -extern u16 wlc_calc_lsig_len(wlc_info_t *wlc, ratespec_t ratespec, +extern u16 wlc_calc_lsig_len(struct wlc_info *wlc, ratespec_t ratespec, uint mac_len); -extern ratespec_t wlc_rspec_to_rts_rspec(wlc_info_t *wlc, ratespec_t rspec, +extern ratespec_t wlc_rspec_to_rts_rspec(struct wlc_info *wlc, ratespec_t rspec, bool use_rspec, u16 mimo_ctlchbw); -extern u16 wlc_compute_rtscts_dur(wlc_info_t *wlc, bool cts_only, +extern u16 wlc_compute_rtscts_dur(struct wlc_info *wlc, bool cts_only, ratespec_t rts_rate, ratespec_t frame_rate, u8 rts_preamble_type, u8 frame_preamble_type, uint frame_len, bool ba); -extern void wlc_tbtt(wlc_info_t *wlc, d11regs_t *regs); +extern void wlc_tbtt(struct wlc_info *wlc, d11regs_t *regs); #if defined(BCMDBG) -extern void wlc_dump_ie(wlc_info_t *wlc, bcm_tlv_t *ie, struct bcmstrbuf *b); +extern void wlc_dump_ie(struct wlc_info *wlc, bcm_tlv_t *ie, + struct bcmstrbuf *b); #endif -extern bool wlc_ps_check(wlc_info_t *wlc); -extern void wlc_reprate_init(wlc_info_t *wlc); +extern bool wlc_ps_check(struct wlc_info *wlc); +extern void wlc_reprate_init(struct wlc_info *wlc); extern void wlc_bsscfg_reprate_init(wlc_bsscfg_t *bsscfg); extern void wlc_uint64_sub(u32 *a_high, u32 *a_low, u32 b_high, u32 b_low); extern u32 wlc_calc_tbtt_offset(u32 bi, u32 tsf_h, u32 tsf_l); /* Shared memory access */ -extern void wlc_write_shm(wlc_info_t *wlc, uint offset, u16 v); -extern u16 wlc_read_shm(wlc_info_t *wlc, uint offset); -extern void wlc_set_shm(wlc_info_t *wlc, uint offset, u16 v, int len); -extern void wlc_copyto_shm(wlc_info_t *wlc, uint offset, const void *buf, +extern void wlc_write_shm(struct wlc_info *wlc, uint offset, u16 v); +extern u16 wlc_read_shm(struct wlc_info *wlc, uint offset); +extern void wlc_set_shm(struct wlc_info *wlc, uint offset, u16 v, int len); +extern void wlc_copyto_shm(struct wlc_info *wlc, uint offset, const void *buf, int len); -extern void wlc_copyfrom_shm(wlc_info_t *wlc, uint offset, void *buf, int len); +extern void wlc_copyfrom_shm(struct wlc_info *wlc, uint offset, void *buf, + int len); -extern void wlc_update_beacon(wlc_info_t *wlc); -extern void wlc_bss_update_beacon(wlc_info_t *wlc, struct wlc_bsscfg *bsscfg); +extern void wlc_update_beacon(struct wlc_info *wlc); +extern void wlc_bss_update_beacon(struct wlc_info *wlc, + struct wlc_bsscfg *bsscfg); -extern void wlc_update_probe_resp(wlc_info_t *wlc, bool suspend); -extern void wlc_bss_update_probe_resp(wlc_info_t *wlc, wlc_bsscfg_t *cfg, +extern void wlc_update_probe_resp(struct wlc_info *wlc, bool suspend); +extern void wlc_bss_update_probe_resp(struct wlc_info *wlc, wlc_bsscfg_t *cfg, bool suspend); -extern bool wlc_ismpc(wlc_info_t *wlc); -extern bool wlc_is_non_delay_mpc(wlc_info_t *wlc); -extern void wlc_radio_mpc_upd(wlc_info_t *wlc); -extern bool wlc_prec_enq(wlc_info_t *wlc, struct pktq *q, void *pkt, int prec); -extern bool wlc_prec_enq_head(wlc_info_t *wlc, struct pktq *q, +extern bool wlc_ismpc(struct wlc_info *wlc); +extern bool wlc_is_non_delay_mpc(struct wlc_info *wlc); +extern void wlc_radio_mpc_upd(struct wlc_info *wlc); +extern bool wlc_prec_enq(struct wlc_info *wlc, struct pktq *q, void *pkt, + int prec); +extern bool wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q, struct sk_buff *pkt, int prec, bool head); -extern u16 wlc_phytxctl1_calc(wlc_info_t *wlc, ratespec_t rspec); -extern void wlc_compute_plcp(wlc_info_t *wlc, ratespec_t rate, uint length, +extern u16 wlc_phytxctl1_calc(struct wlc_info *wlc, ratespec_t rspec); +extern void wlc_compute_plcp(struct wlc_info *wlc, ratespec_t rate, uint length, u8 *plcp); -extern uint wlc_calc_frame_time(wlc_info_t *wlc, ratespec_t ratespec, +extern uint wlc_calc_frame_time(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type, uint mac_len); -extern void wlc_set_chanspec(wlc_info_t *wlc, chanspec_t chanspec); +extern void wlc_set_chanspec(struct wlc_info *wlc, chanspec_t chanspec); -extern bool wlc_timers_init(wlc_info_t *wlc, int unit); +extern bool wlc_timers_init(struct wlc_info *wlc, int unit); extern const bcm_iovar_t wlc_iovars[]; @@ -944,36 +949,38 @@ extern int wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, int len, int val_size, wlc_if_t *wlcif); #if defined(BCMDBG) -extern void wlc_print_ies(wlc_info_t *wlc, u8 *ies, uint ies_len); +extern void wlc_print_ies(struct wlc_info *wlc, u8 *ies, uint ies_len); #endif -extern int wlc_set_nmode(wlc_info_t *wlc, s32 nmode); -extern void wlc_ht_mimops_cap_update(wlc_info_t *wlc, u8 mimops_mode); -extern void wlc_mimops_action_ht_send(wlc_info_t *wlc, wlc_bsscfg_t *bsscfg, - u8 mimops_mode); +extern int wlc_set_nmode(struct wlc_info *wlc, s32 nmode); +extern void wlc_ht_mimops_cap_update(struct wlc_info *wlc, u8 mimops_mode); +extern void wlc_mimops_action_ht_send(struct wlc_info *wlc, + wlc_bsscfg_t *bsscfg, u8 mimops_mode); -extern void wlc_switch_shortslot(wlc_info_t *wlc, bool shortslot); +extern void wlc_switch_shortslot(struct wlc_info *wlc, bool shortslot); extern void wlc_set_bssid(wlc_bsscfg_t *cfg); extern void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend); -extern void wlc_set_ratetable(wlc_info_t *wlc); +extern void wlc_set_ratetable(struct wlc_info *wlc); extern int wlc_set_mac(wlc_bsscfg_t *cfg); -extern void wlc_beacon_phytxctl_txant_upd(wlc_info_t *wlc, +extern void wlc_beacon_phytxctl_txant_upd(struct wlc_info *wlc, ratespec_t bcn_rate); -extern void wlc_mod_prb_rsp_rate_table(wlc_info_t *wlc, uint frame_len); -extern ratespec_t wlc_lowest_basic_rspec(wlc_info_t *wlc, wlc_rateset_t *rs); -extern u16 wlc_compute_bcntsfoff(wlc_info_t *wlc, ratespec_t rspec, +extern void wlc_mod_prb_rsp_rate_table(struct wlc_info *wlc, uint frame_len); +extern ratespec_t wlc_lowest_basic_rspec(struct wlc_info *wlc, + wlc_rateset_t *rs); +extern u16 wlc_compute_bcntsfoff(struct wlc_info *wlc, ratespec_t rspec, bool short_preamble, bool phydelay); -extern void wlc_radio_disable(wlc_info_t *wlc); -extern void wlc_bcn_li_upd(wlc_info_t *wlc); - -extern int wlc_get_revision_info(wlc_info_t *wlc, void *buf, uint len); -extern void wlc_out(wlc_info_t *wlc); -extern void wlc_set_home_chanspec(wlc_info_t *wlc, chanspec_t chanspec); -extern void wlc_watchdog_upd(wlc_info_t *wlc, bool tbtt); -extern bool wlc_ps_allowed(wlc_info_t *wlc); -extern bool wlc_stay_awake(wlc_info_t *wlc); -extern void wlc_wme_initparams_sta(wlc_info_t *wlc, wme_param_ie_t *pe); - -extern void wlc_bss_list_free(wlc_info_t *wlc, wlc_bss_list_t *bss_list); +extern void wlc_radio_disable(struct wlc_info *wlc); +extern void wlc_bcn_li_upd(struct wlc_info *wlc); + +extern int wlc_get_revision_info(struct wlc_info *wlc, void *buf, uint len); +extern void wlc_out(struct wlc_info *wlc); +extern void wlc_set_home_chanspec(struct wlc_info *wlc, chanspec_t chanspec); +extern void wlc_watchdog_upd(struct wlc_info *wlc, bool tbtt); +extern bool wlc_ps_allowed(struct wlc_info *wlc); +extern bool wlc_stay_awake(struct wlc_info *wlc); +extern void wlc_wme_initparams_sta(struct wlc_info *wlc, wme_param_ie_t *pe); + +extern void wlc_bss_list_free(struct wlc_info *wlc, wlc_bss_list_t *bss_list); +extern void wlc_ht_mimops_cap_update(struct wlc_info *wlc, u8 mimops_mode); #endif /* _wlc_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index ea796cb40b7a..1530efe15f97 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -512,7 +512,7 @@ extern bool wlc_isr(struct wlc_info *wlc, bool *wantdpc); extern bool wlc_dpc(struct wlc_info *wlc, bool bounded); extern bool wlc_send80211_raw(struct wlc_info *wlc, wlc_if_t *wlcif, void *p, uint ac); -extern bool wlc_sendpkt_mac80211(wlc_info_t *wlc, struct sk_buff *sdu, +extern bool wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw); extern int wlc_iovar_op(struct wlc_info *wlc, const char *name, void *params, int p_len, void *arg, int len, bool set, @@ -522,10 +522,10 @@ extern int wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, /* helper functions */ extern void wlc_statsupd(struct wlc_info *wlc); extern int wlc_get_header_len(void); -extern void wlc_mac_bcn_promisc_change(wlc_info_t *wlc, bool promisc); -extern void wlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, +extern void wlc_mac_bcn_promisc_change(struct wlc_info *wlc, bool promisc); +extern void wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset, const struct ether_addr *addr); -extern void wlc_wme_setparams(wlc_info_t *wlc, u16 aci, void *arg, +extern void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg, bool suspend); extern wlc_pub_t *wlc_pub(void *wlc); diff --git a/drivers/staging/brcm80211/sys/wlc_scb.h b/drivers/staging/brcm80211/sys/wlc_scb.h index ce26c740e6c1..fe84e993b52a 100644 --- a/drivers/staging/brcm80211/sys/wlc_scb.h +++ b/drivers/staging/brcm80211/sys/wlc_scb.h @@ -19,7 +19,7 @@ #include -extern bool wlc_aggregatable(wlc_info_t *wlc, u8 tid); +extern bool wlc_aggregatable(struct wlc_info *wlc, u8 tid); #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */ /* structure to store per-tid state for the ampdu initiator */ diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c index 2bca0526b44c..ee090746b088 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.c +++ b/drivers/staging/brcm80211/sys/wlc_stf.c @@ -44,14 +44,14 @@ #define WLC_STF_SS_STBC_RX(wlc) (WLCISNPHY(wlc->band) && \ NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6)) -static s8 wlc_stf_stbc_rx_get(wlc_info_t *wlc); -static bool wlc_stf_stbc_tx_set(wlc_info_t *wlc, s32 int_val); -static int wlc_stf_txcore_set(wlc_info_t *wlc, u8 Nsts, u8 val); -static int wlc_stf_spatial_policy_set(wlc_info_t *wlc, int val); -static void wlc_stf_stbc_rx_ht_update(wlc_info_t *wlc, int val); +static s8 wlc_stf_stbc_rx_get(struct wlc_info *wlc); +static bool wlc_stf_stbc_tx_set(struct wlc_info *wlc, s32 int_val); +static int wlc_stf_txcore_set(struct wlc_info *wlc, u8 Nsts, u8 val); +static int wlc_stf_spatial_policy_set(struct wlc_info *wlc, int val); +static void wlc_stf_stbc_rx_ht_update(struct wlc_info *wlc, int val); -static void _wlc_stf_phy_txant_upd(wlc_info_t *wlc); -static u16 _wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec); +static void _wlc_stf_phy_txant_upd(struct wlc_info *wlc); +static u16 _wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec); #define NSTS_1 1 #define NSTS_2 2 @@ -65,7 +65,7 @@ const u8 txcore_default[5] = { (0x0f) /* For Nsts = 4, enable all cores */ }; -static void wlc_stf_stbc_rx_ht_update(wlc_info_t *wlc, int val) +static void wlc_stf_stbc_rx_ht_update(struct wlc_info *wlc, int val) { ASSERT((val == HT_CAP_RX_STBC_NO) || (val == HT_CAP_RX_STBC_ONE_STREAM)); @@ -86,7 +86,7 @@ static void wlc_stf_stbc_rx_ht_update(wlc_info_t *wlc, int val) } /* every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to turn on/off txchain */ -void wlc_tempsense_upd(wlc_info_t *wlc) +void wlc_tempsense_upd(struct wlc_info *wlc) { wlc_phy_t *pi = wlc->band->pi; uint active_chains, txchain; @@ -110,7 +110,7 @@ void wlc_tempsense_upd(wlc_info_t *wlc) } void -wlc_stf_ss_algo_channel_get(wlc_info_t *wlc, u16 *ss_algo_channel, +wlc_stf_ss_algo_channel_get(struct wlc_info *wlc, u16 *ss_algo_channel, chanspec_t chanspec) { tx_power_t power; @@ -151,12 +151,12 @@ wlc_stf_ss_algo_channel_get(wlc_info_t *wlc, u16 *ss_algo_channel, setbit(ss_algo_channel, PHY_TXC1_MODE_STBC); } -static s8 wlc_stf_stbc_rx_get(wlc_info_t *wlc) +static s8 wlc_stf_stbc_rx_get(struct wlc_info *wlc) { return (wlc->ht_cap.cap & HT_CAP_RX_STBC_MASK) >> HT_CAP_RX_STBC_SHIFT; } -static bool wlc_stf_stbc_tx_set(wlc_info_t *wlc, s32 int_val) +static bool wlc_stf_stbc_tx_set(struct wlc_info *wlc, s32 int_val) { if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON)) { return false; @@ -177,7 +177,7 @@ static bool wlc_stf_stbc_tx_set(wlc_info_t *wlc, s32 int_val) return true; } -bool wlc_stf_stbc_rx_set(wlc_info_t *wlc, s32 int_val) +bool wlc_stf_stbc_rx_set(struct wlc_info *wlc, s32 int_val) { if ((int_val != HT_CAP_RX_STBC_NO) && (int_val != HT_CAP_RX_STBC_ONE_STREAM)) { @@ -194,7 +194,7 @@ bool wlc_stf_stbc_rx_set(wlc_info_t *wlc, s32 int_val) return true; } -static int wlc_stf_txcore_set(wlc_info_t *wlc, u8 Nsts, u8 core_mask) +static int wlc_stf_txcore_set(struct wlc_info *wlc, u8 Nsts, u8 core_mask) { WL_TRACE(("wl%d: %s: Nsts %d core_mask %x\n", wlc->pub->unit, __func__, Nsts, core_mask)); @@ -231,7 +231,7 @@ static int wlc_stf_txcore_set(wlc_info_t *wlc, u8 Nsts, u8 core_mask) return BCME_OK; } -static int wlc_stf_spatial_policy_set(wlc_info_t *wlc, int val) +static int wlc_stf_spatial_policy_set(struct wlc_info *wlc, int val) { int i; u8 core_mask = 0; @@ -247,7 +247,7 @@ static int wlc_stf_spatial_policy_set(wlc_info_t *wlc, int val) return BCME_OK; } -int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force) +int wlc_stf_txchain_set(struct wlc_info *wlc, s32 int_val, bool force) { u8 txchain = (u8) int_val; u8 txstreams; @@ -307,7 +307,7 @@ int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force) return BCME_OK; } -int wlc_stf_rxchain_set(wlc_info_t *wlc, s32 int_val) +int wlc_stf_rxchain_set(struct wlc_info *wlc, s32 int_val) { u8 rxchain_cnt; u8 rxchain = (u8) int_val; @@ -371,7 +371,7 @@ int wlc_stf_rxchain_set(wlc_info_t *wlc, s32 int_val) } /* update wlc->stf->ss_opmode which represents the operational stf_ss mode we're using */ -int wlc_stf_ss_update(wlc_info_t *wlc, wlcband_t *band) +int wlc_stf_ss_update(struct wlc_info *wlc, wlcband_t *band) { int ret_code = 0; u8 prev_stf_ss; @@ -406,7 +406,7 @@ int wlc_stf_ss_update(wlc_info_t *wlc, wlcband_t *band) return ret_code; } -int wlc_stf_attach(wlc_info_t *wlc) +int wlc_stf_attach(struct wlc_info *wlc) { wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO; wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD; @@ -429,11 +429,11 @@ int wlc_stf_attach(wlc_info_t *wlc) return 0; } -void wlc_stf_detach(wlc_info_t *wlc) +void wlc_stf_detach(struct wlc_info *wlc) { } -int wlc_stf_ant_txant_validate(wlc_info_t *wlc, s8 val) +int wlc_stf_ant_txant_validate(struct wlc_info *wlc, s8 val) { int bcmerror = BCME_OK; @@ -480,7 +480,7 @@ int wlc_stf_ant_txant_validate(wlc_info_t *wlc, s8 val) * do tx-antenna selection for SISO transmissions * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 means both cores active */ -static void _wlc_stf_phy_txant_upd(wlc_info_t *wlc) +static void _wlc_stf_phy_txant_upd(struct wlc_info *wlc) { s8 txant; @@ -521,12 +521,12 @@ static void _wlc_stf_phy_txant_upd(wlc_info_t *wlc) wlc_bmac_txant_set(wlc->hw, wlc->stf->phytxant); } -void wlc_stf_phy_txant_upd(wlc_info_t *wlc) +void wlc_stf_phy_txant_upd(struct wlc_info *wlc) { _wlc_stf_phy_txant_upd(wlc); } -void wlc_stf_phy_chain_calc(wlc_info_t *wlc) +void wlc_stf_phy_chain_calc(struct wlc_info *wlc) { /* get available rx/tx chains */ wlc->stf->hw_txchain = (u8) getintvar(wlc->pub->vars, "txchain"); @@ -563,7 +563,7 @@ void wlc_stf_phy_chain_calc(wlc_info_t *wlc) wlc_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION); } -static u16 _wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec) +static u16 _wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec) { u16 phytxant = wlc->stf->phytxant; @@ -576,12 +576,12 @@ static u16 _wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec) return phytxant; } -u16 wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec) +u16 wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec) { return _wlc_stf_phytxchain_sel(wlc, rspec); } -u16 wlc_stf_d11hdrs_phyctl_txant(wlc_info_t *wlc, ratespec_t rspec) +u16 wlc_stf_d11hdrs_phyctl_txant(struct wlc_info *wlc, ratespec_t rspec) { u16 phytxant = wlc->stf->phytxant; u16 mask = PHY_TXC_ANT_MASK; diff --git a/drivers/staging/brcm80211/sys/wlc_stf.h b/drivers/staging/brcm80211/sys/wlc_stf.h index ee9b02a119bb..8de6382e620d 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.h +++ b/drivers/staging/brcm80211/sys/wlc_stf.h @@ -20,23 +20,24 @@ #define MIN_SPATIAL_EXPANSION 0 #define MAX_SPATIAL_EXPANSION 1 -extern int wlc_stf_attach(wlc_info_t *wlc); -extern void wlc_stf_detach(wlc_info_t *wlc); +extern int wlc_stf_attach(struct wlc_info *wlc); +extern void wlc_stf_detach(struct wlc_info *wlc); -extern void wlc_tempsense_upd(wlc_info_t *wlc); -extern void wlc_stf_ss_algo_channel_get(wlc_info_t *wlc, +extern void wlc_tempsense_upd(struct wlc_info *wlc); +extern void wlc_stf_ss_algo_channel_get(struct wlc_info *wlc, u16 *ss_algo_channel, chanspec_t chanspec); -extern int wlc_stf_ss_update(wlc_info_t *wlc, struct wlcband *band); -extern void wlc_stf_phy_txant_upd(wlc_info_t *wlc); -extern int wlc_stf_txchain_set(wlc_info_t *wlc, s32 int_val, bool force); -extern int wlc_stf_rxchain_set(wlc_info_t *wlc, s32 int_val); -extern bool wlc_stf_stbc_rx_set(wlc_info_t *wlc, s32 int_val); +extern int wlc_stf_ss_update(struct wlc_info *wlc, struct wlcband *band); +extern void wlc_stf_phy_txant_upd(struct wlc_info *wlc); +extern int wlc_stf_txchain_set(struct wlc_info *wlc, s32 int_val, bool force); +extern int wlc_stf_rxchain_set(struct wlc_info *wlc, s32 int_val); +extern bool wlc_stf_stbc_rx_set(struct wlc_info *wlc, s32 int_val); -extern int wlc_stf_ant_txant_validate(wlc_info_t *wlc, s8 val); -extern void wlc_stf_phy_txant_upd(wlc_info_t *wlc); -extern void wlc_stf_phy_chain_calc(wlc_info_t *wlc); -extern u16 wlc_stf_phytxchain_sel(wlc_info_t *wlc, ratespec_t rspec); -extern u16 wlc_stf_d11hdrs_phyctl_txant(wlc_info_t *wlc, ratespec_t rspec); -extern u16 wlc_stf_spatial_expansion_get(wlc_info_t *wlc, ratespec_t rspec); +extern int wlc_stf_ant_txant_validate(struct wlc_info *wlc, s8 val); +extern void wlc_stf_phy_txant_upd(struct wlc_info *wlc); +extern void wlc_stf_phy_chain_calc(struct wlc_info *wlc); +extern u16 wlc_stf_phytxchain_sel(struct wlc_info *wlc, ratespec_t rspec); +extern u16 wlc_stf_d11hdrs_phyctl_txant(struct wlc_info *wlc, ratespec_t rspec); +extern u16 wlc_stf_spatial_expansion_get(struct wlc_info *wlc, + ratespec_t rspec); #endif /* _wlc_stf_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index dffba3e8b62f..52f888690530 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -19,7 +19,7 @@ /* forward declarations */ -typedef struct wlc_info wlc_info_t; +struct wlc_info; typedef struct wlc_hw_info wlc_hw_info_t; typedef struct wlc_if wlc_if_t; typedef struct wl_if wl_if_t; -- cgit v1.2.3 From f09e02322ed36feafba6e3a6373e0bcd93730ce6 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 4 Dec 2010 16:35:42 +0100 Subject: staging: brcm80211: remove macro usage for sk_buff allocation PKTGET macro calls osl_pktget. This function has been renamed to pkt_buf_get_skb as it comprises of functionality additional to dev_alloc_skb function and to get rid of the OSL concept in this driver. Reviewed-by: Brett Rudley Reviewed-by: Dowan Kim Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 8 ++++---- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 24 +++++++++++------------ drivers/staging/brcm80211/include/osl.h | 3 +-- drivers/staging/brcm80211/util/hnddma.c | 2 +- drivers/staging/brcm80211/util/linux_osl.c | 4 ++-- 5 files changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 2e02d5e58415..b8eb589cdaab 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -1039,9 +1039,9 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, if (pkt == NULL) { sd_data(("%s: Creating new %s Packet, len=%d\n", __func__, write ? "TX" : "RX", buflen_u)); - mypkt = PKTGET(sd->osh, buflen_u, write ? true : false); + mypkt = pkt_buf_get_skb(sd->osh, buflen_u); if (!mypkt) { - sd_err(("%s: PKTGET failed: len %d\n", + sd_err(("%s: pkt_buf_get_skb failed: len %d\n", __func__, buflen_u)); return SDIOH_API_RC_FAIL; } @@ -1066,9 +1066,9 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, sd_data(("%s: Creating aligned %s Packet, len=%d\n", __func__, write ? "TX" : "RX", pkt->len)); - mypkt = PKTGET(sd->osh, pkt->len, write ? true : false); + mypkt = pkt_buf_get_skb(sd->osh, pkt->len); if (!mypkt) { - sd_err(("%s: PKTGET failed: len %d\n", + sd_err(("%s: pkt_buf_get_skb failed: len %d\n", __func__, pkt->len)); return SDIOH_API_RC_FAIL; } diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 6b41d1f1b764..c054f0d50152 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -936,7 +936,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, DHD_INFO(("%s: insufficient headroom %d for %d pad\n", __func__, skb_headroom(pkt), pad)); bus->dhd->tx_realloc++; - new = PKTGET(osh, (pkt->len + DHD_SDALIGN), true); + new = pkt_buf_get_skb(osh, (pkt->len + DHD_SDALIGN)); if (!new) { DHD_ERROR(("%s: couldn't allocate new %d-byte " "packet\n", @@ -3240,9 +3240,9 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) } /* Allocate/chain packet for next subframe */ - pnext = PKTGET(osh, sublen + DHD_SDALIGN, false); + pnext = pkt_buf_get_skb(osh, sublen + DHD_SDALIGN); if (pnext == NULL) { - DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", + DHD_ERROR(("%s: pkt_buf_get_skb failed, num %d len %d\n", __func__, num, sublen)); break; } @@ -3680,7 +3680,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) */ /* Allocate a packet buffer */ dhd_os_sdlock_rxq(bus->dhd); - pkt = PKTGET(osh, rdlen + DHD_SDALIGN, false); + pkt = pkt_buf_get_skb(osh, rdlen + DHD_SDALIGN); if (!pkt) { if (bus->bus == SPI_BUS) { bus->usebufpool = false; @@ -3726,7 +3726,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } else { /* Give up on data, request rtx of events */ - DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " "expected rxseq %d\n", + DHD_ERROR(("%s (nextlen): pkt_buf_get_skb failed: len %d rdlen %d " "expected rxseq %d\n", __func__, len, rdlen, rxseq)); /* Just go try again w/normal header read */ @@ -4091,10 +4091,10 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) } dhd_os_sdlock_rxq(bus->dhd); - pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), false); + pkt = pkt_buf_get_skb(osh, (rdlen + firstread + DHD_SDALIGN)); if (!pkt) { /* Give up on data, request rtx of events */ - DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", + DHD_ERROR(("%s: pkt_buf_get_skb failed: rdlen %d chan %d\n", __func__, rdlen, chan)); bus->dhd->rx_dropped++; dhd_os_sdunlock_rxq(bus->dhd); @@ -4663,11 +4663,11 @@ static void dhdsdio_pktgen(dhd_bus_t *bus) /* Allocate an appropriate-sized packet */ len = bus->pktgen_len; - pkt = PKTGET(osh, + pkt = pkt_buf_get_skb(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), true); if (!pkt) { - DHD_ERROR(("%s: PKTGET failed!\n", __func__)); + DHD_ERROR(("%s: pkt_buf_get_skb failed!\n", __func__)); break; } PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), @@ -4743,10 +4743,10 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start) struct osl_info *osh = bus->dhd->osh; /* Allocate the packet */ - pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, + pkt = pkt_buf_get_skb(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, true); if (!pkt) { - DHD_ERROR(("%s: PKTGET failed!\n", __func__)); + DHD_ERROR(("%s: pkt_buf_get_skb failed!\n", __func__)); return; } PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); @@ -5008,7 +5008,7 @@ extern int dhd_bus_console_in(dhd_pub_t *dhdp, unsigned char *msg, uint msglen) /* Bump dongle by sending an empty event pkt. * sdpcm_sendup (RX) checks for virtual console input. */ - pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, true); + pkt = pkt_buf_get_skb(bus->dhd->osh, 4 + SDPCM_RESERVE); if ((pkt != NULL) && bus->clkstate == CLK_AVAIL) dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, true); diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 54fdfd609729..4d5893a70dd2 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -208,10 +208,9 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define bcopy(src, dst, len) memcpy((dst), (src), (len)) /* packet primitives */ -#define PKTGET(osh, len, send) osl_pktget((osh), (len)) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -extern void *osl_pktget(struct osl_info *osh, uint len); +extern struct sk_buff *pkt_buf_get_skb(struct osl_info *osh, uint len); extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); #endif /* _osl_h_ */ diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index 0c8a1d25d98b..a7805a88b5fe 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -1094,7 +1094,7 @@ static bool BCMFASTPATH _dma_rxfill(dma_info_t *di) size to be allocated */ - p = osl_pktget(di->osh, di->rxbufsize + extra_offset); + p = pkt_buf_get_skb(di->osh, di->rxbufsize + extra_offset); if (p == NULL) { DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index 2efce7aeec78..cd78edbcf43f 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -79,7 +79,7 @@ void osl_detach(struct osl_info *osh) kfree(osh); } -void *BCMFASTPATH osl_pktget(struct osl_info *osh, uint len) +struct sk_buff *BCMFASTPATH pkt_buf_get_skb(struct osl_info *osh, uint len) { struct sk_buff *skb; @@ -91,7 +91,7 @@ void *BCMFASTPATH osl_pktget(struct osl_info *osh, uint len) osh->pktalloced++; } - return (void *)skb; + return skb; } /* Free the driver packet. Free the tag if present */ -- cgit v1.2.3 From 8538576474e162e4967532a80305d17e871f2fa5 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 4 Dec 2010 16:35:43 +0100 Subject: staging: brcm80211: remove macro usage for sk_buff release PKTFREE macro calls osl_pktfree. This function has been renamed to pkt_buf_free_skb as it comprises of functionality additional to dev_kfree_skb(_any) function and to get rid of the OSL concept in this driver. Reviewed-by: Brett Rudley Reviewed-by: Dowan Kim Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 4 +- drivers/staging/brcm80211/brcmfmac/dhd_common.c | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 50 +++++++++++------------ drivers/staging/brcm80211/include/osl.h | 4 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 8 ++-- drivers/staging/brcm80211/util/bcmutils.c | 4 +- drivers/staging/brcm80211/util/hnddma.c | 17 +++----- drivers/staging/brcm80211/util/linux_osl.c | 5 +-- 9 files changed, 44 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index b8eb589cdaab..d399b5c76f94 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -1057,7 +1057,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, if (!write) bcopy(mypkt->data, buffer, buflen_u); - PKTFREE(sd->osh, mypkt, write ? true : false); + pkt_buf_free_skb(sd->osh, mypkt, write ? true : false); } else if (((u32) (pkt->data) & DMA_ALIGN_MASK) != 0) { /* Case 2: We have a packet, but it is unaligned. */ @@ -1084,7 +1084,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, if (!write) bcopy(mypkt->data, pkt->data, mypkt->len); - PKTFREE(sd->osh, mypkt, write ? true : false); + pkt_buf_free_skb(sd->osh, mypkt, write ? true : false); } else { /* case 3: We have a packet and it is aligned. */ sd_data(("%s: Aligned %s Packet, direct DMA\n", diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c index ce5f9134055c..324d020b864e 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c @@ -368,7 +368,7 @@ bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, struct sk_buff *pkt, ASSERT(p); } - PKTFREE(dhdp->osh, p, true); + pkt_buf_free_skb(dhdp->osh, p, true); } /* Enqueue */ diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index c054f0d50152..3edce44978a1 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -144,7 +144,7 @@ * bufpool was present for gspi bus. */ #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ - PKTFREE(bus->dhd->osh, pkt, false); + pkt_buf_free_skb(bus->dhd->osh, pkt, false); DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); @@ -948,7 +948,7 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, struct sk_buff *pkt, uint chan, PKTALIGN(osh, new, pkt->len, DHD_SDALIGN); bcopy(pkt->data, new->data, pkt->len); if (free_pkt) - PKTFREE(osh, pkt, true); + pkt_buf_free_skb(osh, pkt, true); /* free the pkt if canned one is not used */ free_pkt = true; pkt = new; @@ -1061,7 +1061,7 @@ done: dhd_os_sdlock(bus->dhd); if (free_pkt) - PKTFREE(osh, pkt, true); + pkt_buf_free_skb(osh, pkt, true); return ret; } @@ -1112,7 +1112,7 @@ int dhd_bus_txdata(struct dhd_bus *bus, struct sk_buff *pkt) if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == false) { skb_pull(pkt, SDPCM_HDRLEN); dhd_txcomplete(bus->dhd, pkt, false); - PKTFREE(osh, pkt, true); + pkt_buf_free_skb(osh, pkt, true); DHD_ERROR(("%s: out of bus->txq !!!\n", __func__)); ret = BCME_NORESOURCE; } else { @@ -2882,10 +2882,10 @@ void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) /* Clear any held glomming stuff */ if (bus->glomd) - PKTFREE(osh, bus->glomd, false); + pkt_buf_free_skb(osh, bus->glomd, false); if (bus->glom) - PKTFREE(osh, bus->glom, false); + pkt_buf_free_skb(osh, bus->glom, false); bus->glom = bus->glomd = NULL; @@ -3276,13 +3276,13 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) pfirst = pnext = NULL; } else { if (pfirst) - PKTFREE(osh, pfirst, false); + pkt_buf_free_skb(osh, pfirst, false); bus->glom = NULL; num = 0; } /* Done with descriptor packet */ - PKTFREE(osh, bus->glomd, false); + pkt_buf_free_skb(osh, bus->glomd, false); bus->glomd = NULL; bus->nextlen = 0; @@ -3351,7 +3351,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) bus->glomerr = 0; dhdsdio_rxfail(bus, true, false); dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, false); + pkt_buf_free_skb(osh, bus->glom, false); dhd_os_sdunlock_rxq(bus->dhd); bus->rxglomfail++; bus->glom = NULL; @@ -3480,7 +3480,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) bus->glomerr = 0; dhdsdio_rxfail(bus, true, false); dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, false); + pkt_buf_free_skb(osh, bus->glom, false); dhd_os_sdunlock_rxq(bus->dhd); bus->rxglomfail++; bus->glom = NULL; @@ -3528,7 +3528,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) skb_pull(pfirst, doff); if (pfirst->len == 0) { - PKTFREE(bus->dhd->osh, pfirst, false); + pkt_buf_free_skb(bus->dhd->osh, pfirst, false); if (plast) { plast->next = pnext; } else { @@ -3541,7 +3541,7 @@ static u8 dhdsdio_rxglom(dhd_bus_t *bus, u8 rxseq) DHD_ERROR(("%s: rx protocol error\n", __func__)); bus->dhd->rx_errors++; - PKTFREE(osh, pfirst, false); + pkt_buf_free_skb(osh, pfirst, false); if (plast) { plast->next = pnext; } else { @@ -3753,7 +3753,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if (sdret < 0) { DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", __func__, rdlen, sdret)); - PKTFREE(bus->dhd->osh, pkt, false); + pkt_buf_free_skb(bus->dhd->osh, pkt, false); bus->dhd->rx_errors++; dhd_os_sdunlock_rxq(bus->dhd); /* Force retry w/normal header read. @@ -3901,7 +3901,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) doff); if (bus->usebufpool) { dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, + pkt_buf_free_skb(bus->dhd->osh, pkt, false); dhd_os_sdunlock_rxq(bus->dhd); } @@ -4127,7 +4127,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) ? "data" : "test")), sdret)); dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, false); + pkt_buf_free_skb(bus->dhd->osh, pkt, false); dhd_os_sdunlock_rxq(bus->dhd); bus->dhd->rx_errors++; dhdsdio_rxfail(bus, true, RETRYCHAN(chan)); @@ -4180,13 +4180,13 @@ deliver: if (pkt->len == 0) { dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, false); + pkt_buf_free_skb(bus->dhd->osh, pkt, false); dhd_os_sdunlock_rxq(bus->dhd); continue; } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) { DHD_ERROR(("%s: rx protocol error\n", __func__)); dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, false); + pkt_buf_free_skb(bus->dhd->osh, pkt, false); dhd_os_sdunlock_rxq(bus->dhd); bus->dhd->rx_errors++; continue; @@ -4694,7 +4694,7 @@ static void dhdsdio_pktgen(dhd_bus_t *bus) default: DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); - PKTFREE(osh, pkt, true); + pkt_buf_free_skb(osh, pkt, true); bus->pktgen_count = 0; return; } @@ -4779,7 +4779,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) if (pktlen < SDPCM_TEST_HDRLEN) { DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); return; } @@ -4797,7 +4797,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, " "pktlen %d seq %d" " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); return; } } @@ -4812,14 +4812,14 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) bus->pktgen_sent++; } else { bus->pktgen_fail++; - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); } bus->pktgen_rcvd++; break; case SDPCM_TEST_ECHORSP: if (bus->ext_loop) { - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); bus->pktgen_rcvd++; break; } @@ -4832,12 +4832,12 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) break; } } - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); bus->pktgen_rcvd++; break; case SDPCM_TEST_DISCARD: - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); bus->pktgen_rcvd++; break; @@ -4847,7 +4847,7 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, struct sk_buff *pkt, uint seq) DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, " "pktlen %d seq %d" " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, false); + pkt_buf_free_skb(osh, pkt, false); break; } diff --git a/drivers/staging/brcm80211/include/osl.h b/drivers/staging/brcm80211/include/osl.h index 4d5893a70dd2..b28235618d8b 100644 --- a/drivers/staging/brcm80211/include/osl.h +++ b/drivers/staging/brcm80211/include/osl.h @@ -208,9 +208,7 @@ extern void osl_dma_unmap(struct osl_info *osh, uint pa, uint size, #define bcopy(src, dst, len) memcpy((dst), (src), (len)) /* packet primitives */ -#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) - extern struct sk_buff *pkt_buf_get_skb(struct osl_info *osh, uint len); -extern void osl_pktfree(struct osl_info *osh, void *skb, bool send); +extern void pkt_buf_free_skb(struct osl_info *osh, struct sk_buff *skb, bool send); #endif /* _osl_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 2abee6f527f9..59bfeb063650 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -3336,7 +3336,7 @@ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw) fatal = wlc_bmac_dotxstatus(wlc_hw, txs, 0); - PKTFREE(osh, status_p, false); + pkt_buf_free_skb(osh, status_p, false); } if (fatal) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 3e31f893fcc3..d3246b754c41 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -5052,7 +5052,7 @@ wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q, struct sk_buff *pkt, } ASSERT(0); - PKTFREE(wlc->osh, p, true); + pkt_buf_free_skb(wlc->osh, p, true); WLCNTINCR(wlc->pub->_cnt->txnobuf); } @@ -5085,7 +5085,7 @@ void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, wlc->pub->unit)); /* ASSERT(9 == 8); *//* XXX we might hit this condtion in case packet flooding from mac80211 stack */ - PKTFREE(wlc->osh, sdu, true); + pkt_buf_free_skb(wlc->osh, sdu, true); WLCNTINCR(wlc->pub->_cnt->txnobuf); } @@ -6671,7 +6671,7 @@ wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) fatal: ASSERT(0); if (p) - PKTFREE(osh, p, true); + pkt_buf_free_skb(osh, p, true); return true; @@ -7056,7 +7056,7 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) return; toss: - PKTFREE(osh, p, false); + pkt_buf_free_skb(osh, p, false); } /* calculate frame duration for Mixed-mode L-SIG spoofing, return diff --git a/drivers/staging/brcm80211/util/bcmutils.c b/drivers/staging/brcm80211/util/bcmutils.c index 9c4d46764aca..fd30cc6fb7f8 100644 --- a/drivers/staging/brcm80211/util/bcmutils.c +++ b/drivers/staging/brcm80211/util/bcmutils.c @@ -198,7 +198,7 @@ void pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir) while (p) { q->head = p->prev; p->prev = NULL; - PKTFREE(osh, p, dir); + pkt_buf_free_skb(osh, p, dir); q->len--; pq->len--; p = q->head; @@ -232,7 +232,7 @@ pktq_pflush(struct osl_info *osh, struct pktq *pq, int prec, bool dir, else prev->prev = p->prev; p->prev = NULL; - PKTFREE(osh, p, dir); + pkt_buf_free_skb(osh, p, dir); q->len--; pq->len--; p = (head ? q->head : prev->prev); diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index a7805a88b5fe..cf9e469af988 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -1046,7 +1046,7 @@ static void *BCMFASTPATH _dma_rx(dma_info_t *di) if ((di->hnddma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len)); - PKTFREE(di->osh, head, false); + pkt_buf_free_skb(di->osh, head, false); di->hnddma.rxgiants++; goto next_frame; } @@ -1230,15 +1230,10 @@ static void _dma_rxreclaim(dma_info_t *di) { void *p; - /* "unused local" warning suppression for OSLs that - * define PKTFREE() without using the di->osh arg - */ - di = di; - DMA_TRACE(("%s: dma_rxreclaim\n", di->name)); while ((p = _dma_getnextrxp(di, true))) - PKTFREE(di->osh, p, false); + pkt_buf_free_skb(di->osh, p, false); } static void *BCMFASTPATH _dma_getnextrxp(dma_info_t *di, bool forceall) @@ -1501,7 +1496,7 @@ static void dma32_txreclaim(dma_info_t *di, txd_range_t range) return; while ((p = dma32_getnexttxp(di, range))) - PKTFREE(di->osh, p, true); + pkt_buf_free_skb(di->osh, p, true); } static bool dma32_txstopped(dma_info_t *di) @@ -1772,7 +1767,7 @@ static int dma32_txfast(dma_info_t *di, struct sk_buff *p0, bool commit) outoftxd: DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name)); - PKTFREE(di->osh, p0, true); + pkt_buf_free_skb(di->osh, p0, true); di->hnddma.txavail = 0; di->hnddma.txnobuf++; return -1; @@ -2071,7 +2066,7 @@ static void BCMFASTPATH dma64_txreclaim(dma_info_t *di, txd_range_t range) while ((p = dma64_getnexttxp(di, range))) { /* For unframed data, we don't have any packets to free */ if (!(di->hnddma.dmactrlflags & DMA_CTRL_UNFRAMED)) - PKTFREE(di->osh, p, true); + pkt_buf_free_skb(di->osh, p, true); } } @@ -2422,7 +2417,7 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, struct sk_buff *p0, outoftxd: DMA_ERROR(("%s: dma_txfast: out of txds !!!\n", di->name)); - PKTFREE(di->osh, p0, true); + pkt_buf_free_skb(di->osh, p0, true); di->hnddma.txavail = 0; di->hnddma.txnobuf++; return -1; diff --git a/drivers/staging/brcm80211/util/linux_osl.c b/drivers/staging/brcm80211/util/linux_osl.c index cd78edbcf43f..e6716e823baa 100644 --- a/drivers/staging/brcm80211/util/linux_osl.c +++ b/drivers/staging/brcm80211/util/linux_osl.c @@ -95,12 +95,11 @@ struct sk_buff *BCMFASTPATH pkt_buf_get_skb(struct osl_info *osh, uint len) } /* Free the driver packet. Free the tag if present */ -void BCMFASTPATH osl_pktfree(struct osl_info *osh, void *p, bool send) +void BCMFASTPATH pkt_buf_free_skb(struct osl_info *osh, struct sk_buff *skb, bool send) { - struct sk_buff *skb, *nskb; + struct sk_buff *nskb; int nest = 0; - skb = (struct sk_buff *)p; ASSERT(skb); /* perversion: we use skb->next to chain multi-skb packets */ -- cgit v1.2.3 From e304151f150104412c9a304dffd6dc5c160ea336 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Mon, 6 Dec 2010 22:42:48 +0100 Subject: staging: brcm80211: replaced wlc_hw_info_t by struct wlc_hw_info Part of code cleanup effort. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_alloc.c | 6 +- drivers/staging/brcm80211/sys/wlc_antsel.c | 2 +- drivers/staging/brcm80211/sys/wlc_antsel.h | 2 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 308 ++++++++++++++------------- drivers/staging/brcm80211/sys/wlc_bmac.h | 162 +++++++------- drivers/staging/brcm80211/sys/wlc_mac80211.h | 6 +- drivers/staging/brcm80211/sys/wlc_phy_shim.c | 4 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 8 files changed, 252 insertions(+), 240 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 980945a065fd..a568e978f6c6 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -187,10 +187,10 @@ struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, } wlc->pub->wlc = wlc; - /* allocate wlc_hw_info_t state structure */ + /* allocate struct wlc_hw_info state structure */ - wlc->hw = (wlc_hw_info_t *)wlc_calloc(osh, unit, - sizeof(wlc_hw_info_t)); + wlc->hw = (struct wlc_hw_info *)wlc_calloc(osh, unit, + sizeof(struct wlc_hw_info)); if (wlc->hw == NULL) { *err = 1005; goto fail; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index ee577c8c80f5..9533b5687302 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -95,7 +95,7 @@ const u8 mimo_2x3_div_antselid_tbl[16] = { antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, wlc_pub_t *pub, - wlc_hw_info_t *wlc_hw) { + struct wlc_hw_info *wlc_hw) { antsel_info_t *asi; asi = kzalloc(sizeof(antsel_info_t), GFP_ATOMIC); diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.h b/drivers/staging/brcm80211/sys/wlc_antsel.h index 30c66dda77ee..763986dd226e 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.h +++ b/drivers/staging/brcm80211/sys/wlc_antsel.h @@ -19,7 +19,7 @@ extern antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, wlc_pub_t *pub, - wlc_hw_info_t *wlc_hw); + struct wlc_hw_info *wlc_hw); extern void wlc_antsel_detach(antsel_info_t *asi); extern void wlc_antsel_init(antsel_info_t *asi); extern void wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel, diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 59bfeb063650..4042d5e9d205 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -112,64 +112,65 @@ static u16 xmtfifo_sz[][NFIFO] = { {9, 58, 22, 14, 14, 5}, /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ }; -static void wlc_clkctl_clk(wlc_hw_info_t *wlc, uint mode); +static void wlc_clkctl_clk(struct wlc_hw_info *wlc, uint mode); static void wlc_coreinit(struct wlc_info *wlc); /* used by wlc_wakeucode_init() */ -static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits); -static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[], +static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits); +static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[], const uint nbytes); -static void wlc_ucode_download(wlc_hw_info_t *wlc); -static void wlc_ucode_txant_set(wlc_hw_info_t *wlc_hw); +static void wlc_ucode_download(struct wlc_hw_info *wlc); +static void wlc_ucode_txant_set(struct wlc_hw_info *wlc_hw); /* used by wlc_dpc() */ -static bool wlc_bmac_dotxstatus(wlc_hw_info_t *wlc, tx_status_t *txs, +static bool wlc_bmac_dotxstatus(struct wlc_hw_info *wlc, tx_status_t *txs, u32 s2); -static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc); -static bool wlc_bmac_txstatus(wlc_hw_info_t *wlc, bool bound, bool *fatal); -static bool wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound); +static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc); +static bool wlc_bmac_txstatus(struct wlc_hw_info *wlc, bool bound, bool *fatal); +static bool wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound); /* used by wlc_down() */ static void wlc_flushqueues(struct wlc_info *wlc); -static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs); -static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw); -static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw); +static void wlc_write_mhf(struct wlc_hw_info *wlc_hw, u16 *mhfs); +static void wlc_mctrl_reset(struct wlc_hw_info *wlc_hw); +static void wlc_corerev_fifofixup(struct wlc_hw_info *wlc_hw); /* Low Level Prototypes */ -static u16 wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset, +static u16 wlc_bmac_read_objmem(struct wlc_hw_info *wlc_hw, uint offset, u32 sel); -static void wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v, - u32 sel); +static void wlc_bmac_write_objmem(struct wlc_hw_info *wlc_hw, uint offset, + u16 v, u32 sel); static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme); -static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw); -static void wlc_ucode_bsinit(wlc_hw_info_t *wlc_hw); -static bool wlc_validboardtype(wlc_hw_info_t *wlc); -static bool wlc_isgoodchip(wlc_hw_info_t *wlc_hw); -static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw); +static void wlc_bmac_detach_dmapio(struct wlc_hw_info *wlc_hw); +static void wlc_ucode_bsinit(struct wlc_hw_info *wlc_hw); +static bool wlc_validboardtype(struct wlc_hw_info *wlc); +static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw); +static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw); static void wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init); -static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw); -static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw); -static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw); +static void wlc_mctrl_write(struct wlc_hw_info *wlc_hw); +static void wlc_ucode_mute_override_set(struct wlc_hw_info *wlc_hw); +static void wlc_ucode_mute_override_clear(struct wlc_hw_info *wlc_hw); static u32 wlc_wlintrsoff(struct wlc_info *wlc); static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask); static void wlc_gpio_init(struct wlc_info *wlc); -static void wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn, +static void wlc_write_hw_bcntemplate0(struct wlc_hw_info *wlc_hw, void *bcn, int len); -static void wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn, +static void wlc_write_hw_bcntemplate1(struct wlc_hw_info *wlc_hw, void *bcn, int len); static void wlc_bmac_bsinit(struct wlc_info *wlc, chanspec_t chanspec); static u32 wlc_setband_inact(struct wlc_info *wlc, uint bandunit); -static void wlc_bmac_setband(wlc_hw_info_t *wlc_hw, uint bandunit, +static void wlc_bmac_setband(struct wlc_hw_info *wlc_hw, uint bandunit, chanspec_t chanspec); -static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot); -static void wlc_upd_ofdm_pctl1_table(wlc_hw_info_t *wlc_hw); -static u16 wlc_bmac_ofdm_ratetable_offset(wlc_hw_info_t *wlc_hw, +static void wlc_bmac_update_slot_timing(struct wlc_hw_info *wlc_hw, + bool shortslot); +static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info *wlc_hw); +static u16 wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info *wlc_hw, u8 rate); /* === Low Level functions === */ -void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot) +void wlc_bmac_set_shortslot(struct wlc_hw_info *wlc_hw, bool shortslot) { wlc_hw->shortslot = shortslot; @@ -185,7 +186,8 @@ void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot) * or shortslot 11g (9us slots) * The PSM needs to be suspended for this call. */ -static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot) +static void wlc_bmac_update_slot_timing(struct wlc_hw_info *wlc_hw, + bool shortslot) { struct osl_info *osh; d11regs_t *regs; @@ -204,7 +206,7 @@ static void wlc_bmac_update_slot_timing(wlc_hw_info_t *wlc_hw, bool shortslot) } } -static void WLBANDINITFN(wlc_ucode_bsinit) (wlc_hw_info_t *wlc_hw) +static void WLBANDINITFN(wlc_ucode_bsinit) (struct wlc_hw_info *wlc_hw) { /* init microcode host flags */ wlc_write_mhf(wlc_hw, wlc_hw->band->mhfs); @@ -233,7 +235,7 @@ static void WLBANDINITFN(wlc_ucode_bsinit) (wlc_hw_info_t *wlc_hw) /* switch to new band but leave it inactive */ static u32 WLBANDINITFN(wlc_setband_inact) (struct wlc_info *wlc, uint bandunit) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; u32 macintmask; u32 tmp; @@ -268,7 +270,7 @@ static u32 WLBANDINITFN(wlc_setband_inact) (struct wlc_info *wlc, uint bandunit) * Param 'bound' indicates max. # frames to process before break out. */ static bool BCMFASTPATH -wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound) +wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound) { struct sk_buff *p; struct sk_buff *head = NULL; @@ -325,7 +327,7 @@ wlc_bmac_recv(wlc_hw_info_t *wlc_hw, uint fifo, bool bound) bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) { u32 macintstatus; - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; bool fatal = false; @@ -452,7 +454,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) void wlc_bmac_watchdog(void *arg) { struct wlc_info *wlc = (struct wlc_info *) arg; - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; WL_TRACE(("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit)); @@ -475,8 +477,8 @@ void wlc_bmac_watchdog(void *arg) } void -wlc_bmac_set_chanspec(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, bool mute, - struct txpwr_limits *txpwr) +wlc_bmac_set_chanspec(struct wlc_hw_info *wlc_hw, chanspec_t chanspec, + bool mute, struct txpwr_limits *txpwr) { uint bandunit; @@ -519,7 +521,8 @@ wlc_bmac_set_chanspec(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, bool mute, } } -int wlc_bmac_revinfo_get(wlc_hw_info_t *wlc_hw, wlc_bmac_revinfo_t *revinfo) +int wlc_bmac_revinfo_get(struct wlc_hw_info *wlc_hw, + wlc_bmac_revinfo_t *revinfo) { si_t *sih = wlc_hw->sih; uint idx; @@ -557,7 +560,7 @@ int wlc_bmac_revinfo_get(wlc_hw_info_t *wlc_hw, wlc_bmac_revinfo_t *revinfo) return 0; } -int wlc_bmac_state_get(wlc_hw_info_t *wlc_hw, wlc_bmac_state_t *state) +int wlc_bmac_state_get(struct wlc_hw_info *wlc_hw, wlc_bmac_state_t *state) { state->machwcap = wlc_hw->machwcap; @@ -570,7 +573,7 @@ static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme) char name[8]; /* ucode host flag 2 needed for pio mode, independent of band and fifo */ u16 pio_mhf2 = 0; - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; uint unit = wlc_hw->unit; wlc_tunables_t *tune = wlc->pub->tunables; @@ -682,7 +685,7 @@ static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme) return true; } -static void wlc_bmac_detach_dmapio(wlc_hw_info_t *wlc_hw) +static void wlc_bmac_detach_dmapio(struct wlc_hw_info *wlc_hw) { uint j; @@ -704,7 +707,7 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, bool piomode, struct osl_info *osh, void *regsva, uint bustype, void *btparam) { - wlc_hw_info_t *wlc_hw; + struct wlc_hw_info *wlc_hw; d11regs_t *regs; char *macaddr = NULL; char *vars; @@ -727,7 +730,7 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, wlc_hw->band = wlc_hw->bandstate[0]; wlc_hw->_piomode = piomode; - /* populate wlc_hw_info_t with default values */ + /* populate struct wlc_hw_info with default values */ wlc_bmac_info_init(wlc_hw); /* @@ -1043,7 +1046,7 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, * may get overrides later in this function * BMAC_NOTES, move low out and resolve the dangling ones */ -void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw) +void wlc_bmac_info_init(struct wlc_hw_info *wlc_hw) { struct wlc_info *wlc = wlc_hw->wlc; @@ -1069,7 +1072,7 @@ int wlc_bmac_detach(struct wlc_info *wlc) { uint i; wlc_hwband_t *band; - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; int callbacks; callbacks = 0; @@ -1116,7 +1119,7 @@ int wlc_bmac_detach(struct wlc_info *wlc) } -void wlc_bmac_reset(wlc_hw_info_t *wlc_hw) +void wlc_bmac_reset(struct wlc_hw_info *wlc_hw) { WL_TRACE(("wl%d: wlc_bmac_reset\n", wlc_hw->unit)); @@ -1133,7 +1136,7 @@ void wlc_bmac_reset(wlc_hw_info_t *wlc_hw) } void -wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, +wlc_bmac_init(struct wlc_hw_info *wlc_hw, chanspec_t chanspec, bool mute) { u32 macintmask; bool fastclk; @@ -1184,7 +1187,7 @@ wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, wlc_clkctl_clk(wlc_hw, CLK_DYNAMIC); } -int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw) +int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw) { uint coremask; @@ -1232,7 +1235,7 @@ int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw) return 0; } -int wlc_bmac_up_finish(wlc_hw_info_t *wlc_hw) +int wlc_bmac_up_finish(struct wlc_hw_info *wlc_hw) { WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__)); @@ -1246,7 +1249,7 @@ int wlc_bmac_up_finish(wlc_hw_info_t *wlc_hw) return 0; } -int wlc_bmac_down_prep(wlc_hw_info_t *wlc_hw) +int wlc_bmac_down_prep(struct wlc_hw_info *wlc_hw) { bool dev_gone; uint callbacks = 0; @@ -1274,7 +1277,7 @@ int wlc_bmac_down_prep(wlc_hw_info_t *wlc_hw) return callbacks; } -int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw) +int wlc_bmac_down_finish(struct wlc_hw_info *wlc_hw) { uint callbacks = 0; bool dev_gone; @@ -1318,7 +1321,7 @@ int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw) return callbacks; } -void wlc_bmac_wait_for_wake(wlc_hw_info_t *wlc_hw) +void wlc_bmac_wait_for_wake(struct wlc_hw_info *wlc_hw) { if (D11REV_IS(wlc_hw->corerev, 4)) /* no slowclock */ udelay(5); @@ -1334,29 +1337,30 @@ void wlc_bmac_wait_for_wake(wlc_hw_info_t *wlc_hw) ASSERT(wlc_bmac_read_shm(wlc_hw, M_UCODE_DBGST) != DBGST_ASLEEP); } -void wlc_bmac_hw_etheraddr(wlc_hw_info_t *wlc_hw, struct ether_addr *ea) +void wlc_bmac_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea) { bcopy(&wlc_hw->etheraddr, ea, ETHER_ADDR_LEN); } -void wlc_bmac_set_hw_etheraddr(wlc_hw_info_t *wlc_hw, struct ether_addr *ea) +void wlc_bmac_set_hw_etheraddr(struct wlc_hw_info *wlc_hw, + struct ether_addr *ea) { bcopy(ea, &wlc_hw->etheraddr, ETHER_ADDR_LEN); } -int wlc_bmac_bandtype(wlc_hw_info_t *wlc_hw) +int wlc_bmac_bandtype(struct wlc_hw_info *wlc_hw) { return wlc_hw->band->bandtype; } void *wlc_cur_phy(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; return (void *)wlc_hw->band->pi; } /* control chip clock to save power, enable dynamic clock or force fast clock */ -static void wlc_clkctl_clk(wlc_hw_info_t *wlc_hw, uint mode) +static void wlc_clkctl_clk(struct wlc_hw_info *wlc_hw, uint mode) { if (PMUCTL_ENAB(wlc_hw->sih)) { /* new chips with PMU, CCS_FORCEHT will distribute the HT clock on backplane, @@ -1455,7 +1459,7 @@ static void wlc_clkctl_clk(wlc_hw_info_t *wlc_hw, uint mode) static void wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; memset(mhfs, 0, MHFMAX * sizeof(u16)); @@ -1483,7 +1487,7 @@ wlc_mhfdef(struct wlc_info *wlc, u16 *mhfs, u16 mhf2_init) * WLC_BAND_ALL <--- All bands */ void -wlc_bmac_mhf(wlc_hw_info_t *wlc_hw, u8 idx, u16 mask, u16 val, +wlc_bmac_mhf(struct wlc_hw_info *wlc_hw, u8 idx, u16 mask, u16 val, int bands) { u16 save; @@ -1537,7 +1541,7 @@ wlc_bmac_mhf(wlc_hw_info_t *wlc_hw, u8 idx, u16 mask, u16 val, } } -u16 wlc_bmac_mhf_get(wlc_hw_info_t *wlc_hw, u8 idx, int bands) +u16 wlc_bmac_mhf_get(struct wlc_hw_info *wlc_hw, u8 idx, int bands) { wlc_hwband_t *band; ASSERT(idx < MHFMAX); @@ -1563,7 +1567,7 @@ u16 wlc_bmac_mhf_get(wlc_hw_info_t *wlc_hw, u8 idx, int bands) return band->mhfs[idx]; } -static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs) +static void wlc_write_mhf(struct wlc_hw_info *wlc_hw, u16 *mhfs) { u8 idx; u16 addr[] = { @@ -1581,7 +1585,7 @@ static void wlc_write_mhf(wlc_hw_info_t *wlc_hw, u16 *mhfs) /* set the maccontrol register to desired reset state and * initialize the sw cache of the register */ -static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw) +static void wlc_mctrl_reset(struct wlc_hw_info *wlc_hw) { /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */ wlc_hw->maccontrol = 0; @@ -1592,7 +1596,7 @@ static void wlc_mctrl_reset(wlc_hw_info_t *wlc_hw) } /* set or clear maccontrol bits */ -void wlc_bmac_mctrl(wlc_hw_info_t *wlc_hw, u32 mask, u32 val) +void wlc_bmac_mctrl(struct wlc_hw_info *wlc_hw, u32 mask, u32 val) { u32 maccontrol; u32 new_maccontrol; @@ -1614,7 +1618,7 @@ void wlc_bmac_mctrl(wlc_hw_info_t *wlc_hw, u32 mask, u32 val) } /* write the software state of maccontrol and overrides to the maccontrol register */ -static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw) +static void wlc_mctrl_write(struct wlc_hw_info *wlc_hw) { u32 maccontrol = wlc_hw->maccontrol; @@ -1631,7 +1635,7 @@ static void wlc_mctrl_write(wlc_hw_info_t *wlc_hw) W_REG(wlc_hw->osh, &wlc_hw->regs->maccontrol, maccontrol); } -void wlc_ucode_wake_override_set(wlc_hw_info_t *wlc_hw, u32 override_bit) +void wlc_ucode_wake_override_set(struct wlc_hw_info *wlc_hw, u32 override_bit) { ASSERT((wlc_hw->wake_override & override_bit) == 0); @@ -1648,7 +1652,7 @@ void wlc_ucode_wake_override_set(wlc_hw_info_t *wlc_hw, u32 override_bit) return; } -void wlc_ucode_wake_override_clear(wlc_hw_info_t *wlc_hw, u32 override_bit) +void wlc_ucode_wake_override_clear(struct wlc_hw_info *wlc_hw, u32 override_bit) { ASSERT(wlc_hw->wake_override & override_bit); @@ -1669,7 +1673,7 @@ void wlc_ucode_wake_override_clear(wlc_hw_info_t *wlc_hw, u32 override_bit) * STA 0 1 <--- This will ensure no beacons * IBSS 0 0 */ -static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw) +static void wlc_ucode_mute_override_set(struct wlc_hw_info *wlc_hw) { wlc_hw->mute_override = 1; @@ -1685,7 +1689,7 @@ static void wlc_ucode_mute_override_set(wlc_hw_info_t *wlc_hw) } /* Clear the override on AP and INFRA bits */ -static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw) +static void wlc_ucode_mute_override_clear(struct wlc_hw_info *wlc_hw) { if (wlc_hw->mute_override == 0) return; @@ -1705,7 +1709,7 @@ static void wlc_ucode_mute_override_clear(wlc_hw_info_t *wlc_hw) * Write a MAC address to the rcmta structure */ void -wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx, +wlc_bmac_set_rcmta(struct wlc_hw_info *wlc_hw, int idx, const struct ether_addr *addr) { d11regs_t *regs = wlc_hw->regs; @@ -1738,7 +1742,7 @@ wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx, * Write a MAC address to the given match reg offset in the RXE match engine. */ void -wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset, +wlc_bmac_set_addrmatch(struct wlc_hw_info *wlc_hw, int match_reg_offset, const struct ether_addr *addr) { d11regs_t *regs; @@ -1767,7 +1771,7 @@ wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset, } void -wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len, +wlc_bmac_write_template_ram(struct wlc_hw_info *wlc_hw, int offset, int len, void *buf) { d11regs_t *regs; @@ -1810,7 +1814,7 @@ wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, int len, } } -void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin) +void wlc_bmac_set_cwmin(struct wlc_hw_info *wlc_hw, u16 newmin) { struct osl_info *osh; @@ -1822,7 +1826,7 @@ void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin) W_REG(osh, &wlc_hw->regs->objdata, newmin); } -void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax) +void wlc_bmac_set_cwmax(struct wlc_hw_info *wlc_hw, u16 newmax) { struct osl_info *osh; @@ -1834,7 +1838,7 @@ void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax) W_REG(osh, &wlc_hw->regs->objdata, newmax); } -void wlc_bmac_bw_set(wlc_hw_info_t *wlc_hw, u16 bw) +void wlc_bmac_bw_set(struct wlc_hw_info *wlc_hw, u16 bw) { bool fastclk; u32 tmp; @@ -1859,7 +1863,7 @@ void wlc_bmac_bw_set(wlc_hw_info_t *wlc_hw, u16 bw) } static void -wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn, int len) +wlc_write_hw_bcntemplate0(struct wlc_hw_info *wlc_hw, void *bcn, int len) { d11regs_t *regs = wlc_hw->regs; @@ -1873,7 +1877,7 @@ wlc_write_hw_bcntemplate0(wlc_hw_info_t *wlc_hw, void *bcn, int len) } static void -wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn, int len) +wlc_write_hw_bcntemplate1(struct wlc_hw_info *wlc_hw, void *bcn, int len) { d11regs_t *regs = wlc_hw->regs; @@ -1888,7 +1892,7 @@ wlc_write_hw_bcntemplate1(wlc_hw_info_t *wlc_hw, void *bcn, int len) /* mac is assumed to be suspended at this point */ void -wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn, int len, +wlc_bmac_write_hw_bcntemplates(struct wlc_hw_info *wlc_hw, void *bcn, int len, bool both) { d11regs_t *regs = wlc_hw->regs; @@ -1909,7 +1913,7 @@ wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn, int len, } } -static void WLBANDINITFN(wlc_bmac_upd_synthpu) (wlc_hw_info_t *wlc_hw) +static void WLBANDINITFN(wlc_bmac_upd_synthpu) (struct wlc_hw_info *wlc_hw) { u16 v; struct wlc_info *wlc = wlc_hw->wlc; @@ -1930,7 +1934,7 @@ static void WLBANDINITFN(wlc_bmac_upd_synthpu) (wlc_hw_info_t *wlc_hw) static void WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; WL_TRACE(("wl%d: wlc_bmac_bsinit: bandunit %d\n", wlc_hw->unit, wlc_hw->band->bandunit)); @@ -1967,7 +1971,7 @@ WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec) wlc_bmac_upd_synthpu(wlc_hw); } -void wlc_bmac_core_phy_clk(wlc_hw_info_t *wlc_hw, bool clk) +void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk) { WL_TRACE(("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw->unit, clk)); @@ -1992,7 +1996,7 @@ void wlc_bmac_core_phy_clk(wlc_hw_info_t *wlc_hw, bool clk) } /* Perform a soft reset of the PHY PLL */ -void wlc_bmac_core_phypll_reset(wlc_hw_info_t *wlc_hw) +void wlc_bmac_core_phypll_reset(struct wlc_hw_info *wlc_hw) { WL_TRACE(("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw->unit)); @@ -2013,7 +2017,7 @@ void wlc_bmac_core_phypll_reset(wlc_hw_info_t *wlc_hw) /* light way to turn on phy clock without reset for NPHY only * refer to wlc_bmac_core_phy_clk for full version */ -void wlc_bmac_phyclk_fgc(wlc_hw_info_t *wlc_hw, bool clk) +void wlc_bmac_phyclk_fgc(struct wlc_hw_info *wlc_hw, bool clk) { /* support(necessary for NPHY and HYPHY) only */ if (!WLCISNPHY(wlc_hw->band)) @@ -2026,7 +2030,7 @@ void wlc_bmac_phyclk_fgc(wlc_hw_info_t *wlc_hw, bool clk) } -void wlc_bmac_macphyclk_set(wlc_hw_info_t *wlc_hw, bool clk) +void wlc_bmac_macphyclk_set(struct wlc_hw_info *wlc_hw, bool clk) { if (ON == clk) si_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE); @@ -2034,7 +2038,7 @@ void wlc_bmac_macphyclk_set(wlc_hw_info_t *wlc_hw, bool clk) si_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0); } -void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw) +void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw) { wlc_phy_t *pih = wlc_hw->band->pi; u32 phy_bw_clkbits; @@ -2078,7 +2082,7 @@ void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw) /* switch to and initialize new band */ static void -WLBANDINITFN(wlc_bmac_setband) (wlc_hw_info_t *wlc_hw, uint bandunit, +WLBANDINITFN(wlc_bmac_setband) (struct wlc_hw_info *wlc_hw, uint bandunit, chanspec_t chanspec) { struct wlc_info *wlc = wlc_hw->wlc; u32 macintmask; @@ -2120,7 +2124,7 @@ WLBANDINITFN(wlc_bmac_setband) (wlc_hw_info_t *wlc_hw, uint bandunit, } /* low-level band switch utility routine */ -void WLBANDINITFN(wlc_setxband) (wlc_hw_info_t *wlc_hw, uint bandunit) +void WLBANDINITFN(wlc_setxband) (struct wlc_hw_info *wlc_hw, uint bandunit) { WL_TRACE(("wl%d: wlc_setxband: bandunit %d\n", wlc_hw->unit, bandunit)); @@ -2136,7 +2140,7 @@ void WLBANDINITFN(wlc_setxband) (wlc_hw_info_t *wlc_hw, uint bandunit) } } -static bool wlc_isgoodchip(wlc_hw_info_t *wlc_hw) +static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw) { /* reject unsupported corerev */ @@ -2148,7 +2152,7 @@ static bool wlc_isgoodchip(wlc_hw_info_t *wlc_hw) return true; } -static bool wlc_validboardtype(wlc_hw_info_t *wlc_hw) +static bool wlc_validboardtype(struct wlc_hw_info *wlc_hw) { bool goodboard = true; uint boardrev = wlc_hw->boardrev; @@ -2172,7 +2176,7 @@ static bool wlc_validboardtype(wlc_hw_info_t *wlc_hw) return goodboard; } -static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw) +static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw) { const char *varname = "macaddr"; char *macaddr; @@ -2201,7 +2205,7 @@ static char *wlc_get_macaddr(wlc_hw_info_t *wlc_hw) * this function could be called when driver is down and w/o clock * it operates on different registers depending on corerev and boardflag. */ -bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw) +bool wlc_bmac_radio_read_hwdisabled(struct wlc_hw_info *wlc_hw) { bool v, clk, xtal; u32 resetbits = 0, flags = 0; @@ -2247,7 +2251,7 @@ bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw) } /* Initialize just the hardware when coming out of POR or S3/S5 system states */ -void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw) +void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw) { if (wlc_hw->wlc->pub->hw_up) return; @@ -2289,7 +2293,7 @@ void wlc_bmac_hw_up(wlc_hw_info_t *wlc_hw) } } -static bool wlc_dma_rxreset(wlc_hw_info_t *wlc_hw, uint fifo) +static bool wlc_dma_rxreset(struct wlc_hw_info *wlc_hw, uint fifo) { hnddma_t *di = wlc_hw->di[fifo]; struct osl_info *osh; @@ -2322,7 +2326,7 @@ static bool wlc_dma_rxreset(wlc_hw_info_t *wlc_hw, uint fifo) * clear software macintstatus for fresh new start * one testing hack wlc_hw->noreset will bypass the d11/phy reset */ -void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags) +void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags) { d11regs_t *regs; uint i; @@ -2411,7 +2415,7 @@ void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags) * txfifo sizes needs to be modified(increased) since the newer cores * have more memory. */ -static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw) +static void wlc_corerev_fifofixup(struct wlc_hw_info *wlc_hw) { d11regs_t *regs = wlc_hw->regs; u16 fifo_nu; @@ -2473,7 +2477,7 @@ static void wlc_corerev_fifofixup(wlc_hw_info_t *wlc_hw) */ static void wlc_coreinit(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; d11regs_t *regs; u32 sflags; uint bcnint_us; @@ -2682,7 +2686,7 @@ static void wlc_coreinit(struct wlc_info *wlc) * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889 */ -void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode) +void wlc_bmac_switch_macfreq(struct wlc_hw_info *wlc_hw, u8 spurmode) { d11regs_t *regs; struct osl_info *osh; @@ -2715,7 +2719,7 @@ void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode) /* Initialize GPIOs that are controlled by D11 core */ static void wlc_gpio_init(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; d11regs_t *regs; u32 gc, gm; struct osl_info *osh; @@ -2778,7 +2782,7 @@ static void wlc_gpio_init(struct wlc_info *wlc) si_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY); } -static void wlc_ucode_download(wlc_hw_info_t *wlc_hw) +static void wlc_ucode_download(struct wlc_hw_info *wlc_hw) { struct wlc_info *wlc; wlc = wlc_hw->wlc; @@ -2806,7 +2810,7 @@ static void wlc_ucode_download(wlc_hw_info_t *wlc_hw) } } -static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[], +static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[], const uint nbytes) { struct osl_info *osh; d11regs_t *regs = wlc_hw->regs; @@ -2827,7 +2831,7 @@ static void wlc_ucode_write(wlc_hw_info_t *wlc_hw, const u32 ucode[], W_REG(osh, ®s->objdata, ucode[i]); } -static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits) +static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits) { int i; struct osl_info *osh; @@ -2850,7 +2854,7 @@ static void wlc_write_inits(wlc_hw_info_t *wlc_hw, const d11init_t *inits) } } -static void wlc_ucode_txant_set(wlc_hw_info_t *wlc_hw) +static void wlc_ucode_txant_set(struct wlc_hw_info *wlc_hw) { u16 phyctl; u16 phytxant = wlc_hw->bmac_phytxant; @@ -2867,7 +2871,7 @@ static void wlc_ucode_txant_set(wlc_hw_info_t *wlc_hw) wlc_bmac_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl); } -void wlc_bmac_txant_set(wlc_hw_info_t *wlc_hw, u16 phytxant) +void wlc_bmac_txant_set(struct wlc_hw_info *wlc_hw, u16 phytxant) { /* update sw state */ wlc_hw->bmac_phytxant = phytxant; @@ -2879,12 +2883,12 @@ void wlc_bmac_txant_set(wlc_hw_info_t *wlc_hw, u16 phytxant) } -u16 wlc_bmac_get_txant(wlc_hw_info_t *wlc_hw) +u16 wlc_bmac_get_txant(struct wlc_hw_info *wlc_hw) { return (u16) wlc_hw->wlc->stf->txant; } -void wlc_bmac_antsel_type_set(wlc_hw_info_t *wlc_hw, u8 antsel_type) +void wlc_bmac_antsel_type_set(struct wlc_hw_info *wlc_hw, u8 antsel_type) { wlc_hw->antsel_type = antsel_type; @@ -2892,7 +2896,7 @@ void wlc_bmac_antsel_type_set(wlc_hw_info_t *wlc_hw, u8 antsel_type) wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type); } -void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw) +void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw) { bool fatal = false; uint unit; @@ -2962,7 +2966,7 @@ void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw) void wlc_intrson(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; ASSERT(wlc->defmacintmask); wlc->macintmask = wlc->defmacintmask; W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, wlc->macintmask); @@ -2991,7 +2995,7 @@ static void wlc_wlintrsrestore(struct wlc_info *wlc, u32 macintmask) u32 wlc_intrsoff(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; u32 macintmask; if (!wlc_hw->clk) @@ -3010,7 +3014,7 @@ u32 wlc_intrsoff(struct wlc_info *wlc) void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; if (!wlc_hw->clk) return; @@ -3018,7 +3022,7 @@ void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask) W_REG(wlc_hw->osh, &wlc_hw->regs->macintmask, wlc->macintmask); } -void wlc_bmac_mute(wlc_hw_info_t *wlc_hw, bool on, mbool flags) +void wlc_bmac_mute(struct wlc_hw_info *wlc_hw, bool on, mbool flags) { struct ether_addr null_ether_addr = { {0, 0, 0, 0, 0, 0} }; @@ -3054,12 +3058,12 @@ void wlc_bmac_mute(wlc_hw_info_t *wlc_hw, bool on, mbool flags) wlc_ucode_mute_override_clear(wlc_hw); } -void wlc_bmac_set_deaf(wlc_hw_info_t *wlc_hw, bool user_flag) +void wlc_bmac_set_deaf(struct wlc_hw_info *wlc_hw, bool user_flag) { wlc_phy_set_deaf(wlc_hw->band->pi, user_flag); } -int wlc_bmac_xmtfifo_sz_get(wlc_hw_info_t *wlc_hw, uint fifo, uint *blocks) +int wlc_bmac_xmtfifo_sz_get(struct wlc_hw_info *wlc_hw, uint fifo, uint *blocks) { if (fifo >= NFIFO) return BCME_RANGE; @@ -3069,7 +3073,7 @@ int wlc_bmac_xmtfifo_sz_get(wlc_hw_info_t *wlc_hw, uint fifo, uint *blocks) return 0; } -int wlc_bmac_xmtfifo_sz_set(wlc_hw_info_t *wlc_hw, uint fifo, uint blocks) +int wlc_bmac_xmtfifo_sz_set(struct wlc_hw_info *wlc_hw, uint fifo, uint blocks) { if (fifo >= NFIFO || blocks > 299) return BCME_RANGE; @@ -3089,7 +3093,7 @@ int wlc_bmac_xmtfifo_sz_set(wlc_hw_info_t *wlc_hw, uint fifo, uint blocks) * be pulling data into a tx fifo, by the time the MAC acks the suspend * request. */ -bool wlc_bmac_tx_fifo_suspended(wlc_hw_info_t *wlc_hw, uint tx_fifo) +bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info *wlc_hw, uint tx_fifo) { /* check that a suspend has been requested and is no longer pending */ @@ -3108,7 +3112,7 @@ bool wlc_bmac_tx_fifo_suspended(wlc_hw_info_t *wlc_hw, uint tx_fifo) return false; } -void wlc_bmac_tx_fifo_suspend(wlc_hw_info_t *wlc_hw, uint tx_fifo) +void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info *wlc_hw, uint tx_fifo) { u8 fifo = 1 << tx_fifo; @@ -3139,7 +3143,7 @@ void wlc_bmac_tx_fifo_suspend(wlc_hw_info_t *wlc_hw, uint tx_fifo) } } -void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo) +void wlc_bmac_tx_fifo_resume(struct wlc_hw_info *wlc_hw, uint tx_fifo) { /* BMAC_NOTE: WLC_TX_FIFO_ENAB is done in wlc_dpc() for DMA case but need to be done * here for PIO otherwise the watchdog will catch the inconsistency and fire @@ -3169,7 +3173,7 @@ void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo) */ static inline u32 wlc_intstatus(struct wlc_info *wlc, bool in_isr) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; u32 macintstatus; u32 intstatus_rxfifo, intstatus_txsfifo; @@ -3284,7 +3288,7 @@ bool wlc_intrsupd(struct wlc_info *wlc) */ bool BCMFASTPATH wlc_isr(struct wlc_info *wlc, bool *wantdpc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; u32 macintstatus; *wantdpc = false; @@ -3313,7 +3317,7 @@ bool BCMFASTPATH wlc_isr(struct wlc_info *wlc, bool *wantdpc) } /* process tx completion events for corerev < 5 */ -static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw) +static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc_hw) { struct sk_buff *status_p; tx_status_t *txs; @@ -3349,7 +3353,7 @@ static bool wlc_bmac_txstatus_corerev4(wlc_hw_info_t *wlc_hw) } static bool BCMFASTPATH -wlc_bmac_dotxstatus(wlc_hw_info_t *wlc_hw, tx_status_t *txs, u32 s2) +wlc_bmac_dotxstatus(struct wlc_hw_info *wlc_hw, tx_status_t *txs, u32 s2) { /* discard intermediate indications for ucode with one legitimate case: * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent @@ -3368,7 +3372,7 @@ wlc_bmac_dotxstatus(wlc_hw_info_t *wlc_hw, tx_status_t *txs, u32 s2) * Return true if more tx status need to be processed. false otherwise. */ static bool BCMFASTPATH -wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal) +wlc_bmac_txstatus(struct wlc_hw_info *wlc_hw, bool bound, bool *fatal) { bool morepending = false; struct wlc_info *wlc = wlc_hw->wlc; @@ -3434,7 +3438,7 @@ wlc_bmac_txstatus(wlc_hw_info_t *wlc_hw, bool bound, bool *fatal) void wlc_suspend_mac_and_wait(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; u32 mc, mi; struct osl_info *osh; @@ -3498,7 +3502,7 @@ void wlc_suspend_mac_and_wait(struct wlc_info *wlc) void wlc_enable_mac(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; d11regs_t *regs = wlc_hw->regs; u32 mc, mi; struct osl_info *osh; @@ -3535,7 +3539,7 @@ void wlc_enable_mac(struct wlc_info *wlc) wlc_ucode_wake_override_clear(wlc_hw, WLC_WAKE_OVERRIDE_MACSUSPEND); } -void wlc_bmac_ifsctl_edcrs_set(wlc_hw_info_t *wlc_hw, bool abie, bool isht) +void wlc_bmac_ifsctl_edcrs_set(struct wlc_hw_info *wlc_hw, bool abie, bool isht) { if (!(WLCISNPHY(wlc_hw->band) && (D11REV_GE(wlc_hw->corerev, 16)))) return; @@ -3571,7 +3575,7 @@ void wlc_bmac_ifsctl_edcrs_set(wlc_hw_info_t *wlc_hw, bool abie, bool isht) } } -static void wlc_upd_ofdm_pctl1_table(wlc_hw_info_t *wlc_hw) +static void wlc_upd_ofdm_pctl1_table(struct wlc_hw_info *wlc_hw) { u8 rate; u8 rates[8] = { @@ -3605,7 +3609,7 @@ static void wlc_upd_ofdm_pctl1_table(wlc_hw_info_t *wlc_hw) } } -static u16 wlc_bmac_ofdm_ratetable_offset(wlc_hw_info_t *wlc_hw, u8 rate) +static u16 wlc_bmac_ofdm_ratetable_offset(struct wlc_hw_info *wlc_hw, u8 rate) { uint i; u8 plcp_rate = 0; @@ -3638,7 +3642,7 @@ static u16 wlc_bmac_ofdm_ratetable_offset(wlc_hw_info_t *wlc_hw, u8 rate) return 2 * wlc_bmac_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2)); } -void wlc_bmac_band_stf_ss_set(wlc_hw_info_t *wlc_hw, u8 stf_mode) +void wlc_bmac_band_stf_ss_set(struct wlc_hw_info *wlc_hw, u8 stf_mode) { wlc_hw->hw_stf_ss_opmode = stf_mode; @@ -3647,7 +3651,7 @@ void wlc_bmac_band_stf_ss_set(wlc_hw_info_t *wlc_hw, u8 stf_mode) } void BCMFASTPATH -wlc_bmac_read_tsf(wlc_hw_info_t *wlc_hw, u32 *tsf_l_ptr, +wlc_bmac_read_tsf(struct wlc_hw_info *wlc_hw, u32 *tsf_l_ptr, u32 *tsf_h_ptr) { d11regs_t *regs = wlc_hw->regs; @@ -3659,7 +3663,7 @@ wlc_bmac_read_tsf(wlc_hw_info_t *wlc_hw, u32 *tsf_l_ptr, return; } -bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw) +bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw) { d11regs_t *regs; u32 w, val; @@ -3754,7 +3758,7 @@ bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw) #define PHYPLL_WAIT_US 100000 -void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on) +void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on) { d11regs_t *regs; struct osl_info *osh; @@ -3813,7 +3817,7 @@ void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on) } } -void wlc_coredisable(wlc_hw_info_t *wlc_hw) +void wlc_coredisable(struct wlc_hw_info *wlc_hw) { bool dev_gone; @@ -3853,7 +3857,7 @@ void wlc_coredisable(wlc_hw_info_t *wlc_hw) } /* power both the pll and external oscillator on/off */ -void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want) +void wlc_bmac_xtal(struct wlc_hw_info *wlc_hw, bool want) { WL_TRACE(("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw->unit, want)); @@ -3874,7 +3878,7 @@ void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want) static void wlc_flushqueues(struct wlc_info *wlc) { - wlc_hw_info_t *wlc_hw = wlc->hw; + struct wlc_hw_info *wlc_hw = wlc->hw; uint i; wlc->txpend16165war = 0; @@ -3894,12 +3898,12 @@ static void wlc_flushqueues(struct wlc_info *wlc) dma_rxreclaim(wlc_hw->di[RX_TXSTATUS_FIFO]); } -u16 wlc_bmac_read_shm(wlc_hw_info_t *wlc_hw, uint offset) +u16 wlc_bmac_read_shm(struct wlc_hw_info *wlc_hw, uint offset) { return wlc_bmac_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL); } -void wlc_bmac_write_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v) +void wlc_bmac_write_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v) { wlc_bmac_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL); } @@ -3908,7 +3912,7 @@ void wlc_bmac_write_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v) * SHM 'offset' needs to be an even address and * Buffer length 'len' must be an even number of bytes */ -void wlc_bmac_set_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v, int len) +void wlc_bmac_set_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v, int len) { int i; @@ -3925,7 +3929,7 @@ void wlc_bmac_set_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v, int len) } static u16 -wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset, u32 sel) +wlc_bmac_read_objmem(struct wlc_hw_info *wlc_hw, uint offset, u32 sel) { d11regs_t *regs = wlc_hw->regs; volatile u16 *objdata_lo = (volatile u16 *)®s->objdata; @@ -3946,7 +3950,7 @@ wlc_bmac_read_objmem(wlc_hw_info_t *wlc_hw, uint offset, u32 sel) } static void -wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v, u32 sel) +wlc_bmac_write_objmem(struct wlc_hw_info *wlc_hw, uint offset, u16 v, u32 sel) { d11regs_t *regs = wlc_hw->regs; volatile u16 *objdata_lo = (volatile u16 *)®s->objdata; @@ -3969,7 +3973,7 @@ wlc_bmac_write_objmem(wlc_hw_info_t *wlc_hw, uint offset, u16 v, u32 sel) * 'sel' selects the type of memory */ void -wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw, uint offset, const void *buf, +wlc_bmac_copyto_objmem(struct wlc_hw_info *wlc_hw, uint offset, const void *buf, int len, u32 sel) { u16 v; @@ -3995,7 +3999,7 @@ wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw, uint offset, const void *buf, * 'sel' selects the type of memory */ void -wlc_bmac_copyfrom_objmem(wlc_hw_info_t *wlc_hw, uint offset, void *buf, +wlc_bmac_copyfrom_objmem(struct wlc_hw_info *wlc_hw, uint offset, void *buf, int len, u32 sel) { u16 v; @@ -4016,7 +4020,7 @@ wlc_bmac_copyfrom_objmem(wlc_hw_info_t *wlc_hw, uint offset, void *buf, } } -void wlc_bmac_copyfrom_vars(wlc_hw_info_t *wlc_hw, char **buf, uint *len) +void wlc_bmac_copyfrom_vars(struct wlc_hw_info *wlc_hw, char **buf, uint *len) { WL_TRACE(("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n", wlc_hw->vars_size)); @@ -4025,7 +4029,7 @@ void wlc_bmac_copyfrom_vars(wlc_hw_info_t *wlc_hw, char **buf, uint *len) *len = wlc_hw->vars_size; } -void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL, u16 LRL) +void wlc_bmac_retrylimit_upd(struct wlc_hw_info *wlc_hw, u16 SRL, u16 LRL) { wlc_hw->SRL = SRL; wlc_hw->LRL = LRL; @@ -4043,17 +4047,17 @@ void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL, u16 LRL) } } -void wlc_bmac_set_noreset(wlc_hw_info_t *wlc_hw, bool noreset_flag) +void wlc_bmac_set_noreset(struct wlc_hw_info *wlc_hw, bool noreset_flag) { wlc_hw->noreset = noreset_flag; } -void wlc_bmac_set_ucode_loaded(wlc_hw_info_t *wlc_hw, bool ucode_loaded) +void wlc_bmac_set_ucode_loaded(struct wlc_hw_info *wlc_hw, bool ucode_loaded) { wlc_hw->ucode_loaded = ucode_loaded; } -void wlc_bmac_pllreq(wlc_hw_info_t *wlc_hw, bool set, mbool req_bit) +void wlc_bmac_pllreq(struct wlc_hw_info *wlc_hw, bool set, mbool req_bit) { ASSERT(req_bit); @@ -4084,7 +4088,7 @@ void wlc_bmac_pllreq(wlc_hw_info_t *wlc_hw, bool set, mbool req_bit) return; } -void wlc_bmac_set_clk(wlc_hw_info_t *wlc_hw, bool on) +void wlc_bmac_set_clk(struct wlc_hw_info *wlc_hw, bool on) { if (on) { /* power up pll and oscillator */ @@ -4106,7 +4110,7 @@ void wlc_bmac_set_clk(wlc_hw_info_t *wlc_hw, bool on) } /* this will be true for all ai chips */ -bool wlc_bmac_taclear(wlc_hw_info_t *wlc_hw, bool ta_ok) +bool wlc_bmac_taclear(struct wlc_hw_info *wlc_hw, bool ta_ok) { return true; } @@ -4114,7 +4118,7 @@ bool wlc_bmac_taclear(wlc_hw_info_t *wlc_hw, bool ta_ok) /* Lower down relevant GPIOs like LED when going down w/o * doing PCI config cycles or touching interrupts */ -void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw) +void wlc_gpio_fast_deinit(struct wlc_hw_info *wlc_hw) { if ((wlc_hw == NULL) || (wlc_hw->sih == NULL)) return; @@ -4132,7 +4136,7 @@ void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw) return; } -bool wlc_bmac_radio_hw(wlc_hw_info_t *wlc_hw, bool enable) +bool wlc_bmac_radio_hw(struct wlc_hw_info *wlc_hw, bool enable) { /* Do not access Phy registers if core is not up */ if (si_iscoreup(wlc_hw->sih) == false) @@ -4167,7 +4171,7 @@ bool wlc_bmac_radio_hw(wlc_hw_info_t *wlc_hw, bool enable) return true; } -u16 wlc_bmac_rate_shm_offset(wlc_hw_info_t *wlc_hw, u8 rate) +u16 wlc_bmac_rate_shm_offset(struct wlc_hw_info *wlc_hw, u8 rate) { u16 table_ptr; u8 phy_rate, index; @@ -4191,12 +4195,12 @@ u16 wlc_bmac_rate_shm_offset(wlc_hw_info_t *wlc_hw, u8 rate) return 2 * wlc_bmac_read_shm(wlc_hw, table_ptr + (index * 2)); } -void wlc_bmac_set_txpwr_percent(wlc_hw_info_t *wlc_hw, u8 val) +void wlc_bmac_set_txpwr_percent(struct wlc_hw_info *wlc_hw, u8 val) { wlc_phy_txpwr_percent_set(wlc_hw->band->pi, val); } -void wlc_bmac_antsel_set(wlc_hw_info_t *wlc_hw, u32 antsel_avail) +void wlc_bmac_antsel_set(struct wlc_hw_info *wlc_hw, u32 antsel_avail) { wlc_hw->antsel_avail = antsel_avail; } diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.h b/drivers/staging/brcm80211/sys/wlc_bmac.h index 03ad275cfc58..98150aaff3a3 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.h +++ b/drivers/staging/brcm80211/sys/wlc_bmac.h @@ -57,7 +57,8 @@ typedef struct wlc_bmac_revinfo { } band[MAXBANDS]; } wlc_bmac_revinfo_t; -/* dup state between BMAC(wlc_hw_info_t) and HIGH(struct wlc_info) driver */ +/* dup state between BMAC(struct wlc_hw_info) and HIGH(struct wlc_info) + driver */ typedef struct wlc_bmac_state { u32 machwcap; /* mac hw capibility */ u32 preamble_ovr; /* preamble override */ @@ -135,131 +136,138 @@ extern int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, void *regsva, uint bustype, void *btparam); extern int wlc_bmac_detach(struct wlc_info *wlc); extern void wlc_bmac_watchdog(void *arg); -extern void wlc_bmac_info_init(wlc_hw_info_t *wlc_hw); +extern void wlc_bmac_info_init(struct wlc_hw_info *wlc_hw); /* up/down, reset, clk */ -extern void wlc_bmac_xtal(wlc_hw_info_t *wlc_hw, bool want); +extern void wlc_bmac_xtal(struct wlc_hw_info *wlc_hw, bool want); -extern void wlc_bmac_copyto_objmem(wlc_hw_info_t *wlc_hw, +extern void wlc_bmac_copyto_objmem(struct wlc_hw_info *wlc_hw, uint offset, const void *buf, int len, u32 sel); -extern void wlc_bmac_copyfrom_objmem(wlc_hw_info_t *wlc_hw, uint offset, +extern void wlc_bmac_copyfrom_objmem(struct wlc_hw_info *wlc_hw, uint offset, void *buf, int len, u32 sel); #define wlc_bmac_copyfrom_shm(wlc_hw, offset, buf, len) \ wlc_bmac_copyfrom_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL) #define wlc_bmac_copyto_shm(wlc_hw, offset, buf, len) \ wlc_bmac_copyto_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL) -extern void wlc_bmac_core_phy_clk(wlc_hw_info_t *wlc_hw, bool clk); -extern void wlc_bmac_core_phypll_reset(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_core_phypll_ctl(wlc_hw_info_t *wlc_hw, bool on); -extern void wlc_bmac_phyclk_fgc(wlc_hw_info_t *wlc_hw, bool clk); -extern void wlc_bmac_macphyclk_set(wlc_hw_info_t *wlc_hw, bool clk); -extern void wlc_bmac_phy_reset(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags); -extern void wlc_bmac_reset(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_init(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, +extern void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk); +extern void wlc_bmac_core_phypll_reset(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on); +extern void wlc_bmac_phyclk_fgc(struct wlc_hw_info *wlc_hw, bool clk); +extern void wlc_bmac_macphyclk_set(struct wlc_hw_info *wlc_hw, bool clk); +extern void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags); +extern void wlc_bmac_reset(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_init(struct wlc_hw_info *wlc_hw, chanspec_t chanspec, bool mute); -extern int wlc_bmac_up_prep(wlc_hw_info_t *wlc_hw); -extern int wlc_bmac_up_finish(wlc_hw_info_t *wlc_hw); -extern int wlc_bmac_down_prep(wlc_hw_info_t *wlc_hw); -extern int wlc_bmac_down_finish(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_corereset(wlc_hw_info_t *wlc_hw, u32 flags); -extern void wlc_bmac_switch_macfreq(wlc_hw_info_t *wlc_hw, u8 spurmode); +extern int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw); +extern int wlc_bmac_up_finish(struct wlc_hw_info *wlc_hw); +extern int wlc_bmac_down_prep(struct wlc_hw_info *wlc_hw); +extern int wlc_bmac_down_finish(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags); +extern void wlc_bmac_switch_macfreq(struct wlc_hw_info *wlc_hw, u8 spurmode); /* chanspec, ucode interface */ -extern int wlc_bmac_bandtype(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_set_chanspec(wlc_hw_info_t *wlc_hw, chanspec_t chanspec, +extern int wlc_bmac_bandtype(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_set_chanspec(struct wlc_hw_info *wlc_hw, + chanspec_t chanspec, bool mute, struct txpwr_limits *txpwr); -extern void wlc_bmac_txfifo(wlc_hw_info_t *wlc_hw, uint fifo, void *p, +extern void wlc_bmac_txfifo(struct wlc_hw_info *wlc_hw, uint fifo, void *p, bool commit, u16 frameid, u8 txpktpend); -extern int wlc_bmac_xmtfifo_sz_get(wlc_hw_info_t *wlc_hw, uint fifo, +extern int wlc_bmac_xmtfifo_sz_get(struct wlc_hw_info *wlc_hw, uint fifo, uint *blocks); -extern void wlc_bmac_mhf(wlc_hw_info_t *wlc_hw, u8 idx, u16 mask, +extern void wlc_bmac_mhf(struct wlc_hw_info *wlc_hw, u8 idx, u16 mask, u16 val, int bands); -extern void wlc_bmac_mctrl(wlc_hw_info_t *wlc_hw, u32 mask, u32 val); -extern u16 wlc_bmac_mhf_get(wlc_hw_info_t *wlc_hw, u8 idx, int bands); -extern int wlc_bmac_xmtfifo_sz_set(wlc_hw_info_t *wlc_hw, uint fifo, +extern void wlc_bmac_mctrl(struct wlc_hw_info *wlc_hw, u32 mask, u32 val); +extern u16 wlc_bmac_mhf_get(struct wlc_hw_info *wlc_hw, u8 idx, int bands); +extern int wlc_bmac_xmtfifo_sz_set(struct wlc_hw_info *wlc_hw, uint fifo, uint blocks); -extern void wlc_bmac_txant_set(wlc_hw_info_t *wlc_hw, u16 phytxant); -extern u16 wlc_bmac_get_txant(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_antsel_type_set(wlc_hw_info_t *wlc_hw, u8 antsel_type); -extern int wlc_bmac_revinfo_get(wlc_hw_info_t *wlc_hw, +extern void wlc_bmac_txant_set(struct wlc_hw_info *wlc_hw, u16 phytxant); +extern u16 wlc_bmac_get_txant(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_antsel_type_set(struct wlc_hw_info *wlc_hw, + u8 antsel_type); +extern int wlc_bmac_revinfo_get(struct wlc_hw_info *wlc_hw, wlc_bmac_revinfo_t *revinfo); -extern int wlc_bmac_state_get(wlc_hw_info_t *wlc_hw, wlc_bmac_state_t *state); -extern void wlc_bmac_write_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v); -extern u16 wlc_bmac_read_shm(wlc_hw_info_t *wlc_hw, uint offset); -extern void wlc_bmac_set_shm(wlc_hw_info_t *wlc_hw, uint offset, u16 v, +extern int wlc_bmac_state_get(struct wlc_hw_info *wlc_hw, + wlc_bmac_state_t *state); +extern void wlc_bmac_write_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v); +extern u16 wlc_bmac_read_shm(struct wlc_hw_info *wlc_hw, uint offset); +extern void wlc_bmac_set_shm(struct wlc_hw_info *wlc_hw, uint offset, u16 v, int len); -extern void wlc_bmac_write_template_ram(wlc_hw_info_t *wlc_hw, int offset, +extern void wlc_bmac_write_template_ram(struct wlc_hw_info *wlc_hw, int offset, int len, void *buf); -extern void wlc_bmac_copyfrom_vars(wlc_hw_info_t *wlc_hw, char **buf, +extern void wlc_bmac_copyfrom_vars(struct wlc_hw_info *wlc_hw, char **buf, uint *len); -extern void wlc_bmac_process_ps_switch(wlc_hw_info_t *wlc, +extern void wlc_bmac_process_ps_switch(struct wlc_hw_info *wlc, struct ether_addr *ea, s8 ps_on); -extern void wlc_bmac_hw_etheraddr(wlc_hw_info_t *wlc_hw, +extern void wlc_bmac_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea); -extern void wlc_bmac_set_hw_etheraddr(wlc_hw_info_t *wlc_hw, +extern void wlc_bmac_set_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea); -extern bool wlc_bmac_validate_chip_access(wlc_hw_info_t *wlc_hw); +extern bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw); -extern bool wlc_bmac_radio_read_hwdisabled(wlc_hw_info_t *wlc_hw); -extern void wlc_bmac_set_shortslot(wlc_hw_info_t *wlc_hw, bool shortslot); -extern void wlc_bmac_mute(wlc_hw_info_t *wlc_hw, bool want, mbool flags); -extern void wlc_bmac_set_deaf(wlc_hw_info_t *wlc_hw, bool user_flag); -extern void wlc_bmac_band_stf_ss_set(wlc_hw_info_t *wlc_hw, u8 stf_mode); +extern bool wlc_bmac_radio_read_hwdisabled(struct wlc_hw_info *wlc_hw); +extern void wlc_bmac_set_shortslot(struct wlc_hw_info *wlc_hw, bool shortslot); +extern void wlc_bmac_mute(struct wlc_hw_info *wlc_hw, bool want, mbool flags); +extern void wlc_bmac_set_deaf(struct wlc_hw_info *wlc_hw, bool user_flag); +extern void wlc_bmac_band_stf_ss_set(struct wlc_hw_info *wlc_hw, u8 stf_mode); -extern void wlc_bmac_wait_for_wake(wlc_hw_info_t *wlc_hw); -extern bool wlc_bmac_tx_fifo_suspended(wlc_hw_info_t *wlc_hw, uint tx_fifo); -extern void wlc_bmac_tx_fifo_suspend(wlc_hw_info_t *wlc_hw, uint tx_fifo); -extern void wlc_bmac_tx_fifo_resume(wlc_hw_info_t *wlc_hw, uint tx_fifo); +extern void wlc_bmac_wait_for_wake(struct wlc_hw_info *wlc_hw); +extern bool wlc_bmac_tx_fifo_suspended(struct wlc_hw_info *wlc_hw, + uint tx_fifo); +extern void wlc_bmac_tx_fifo_suspend(struct wlc_hw_info *wlc_hw, uint tx_fifo); +extern void wlc_bmac_tx_fifo_resume(struct wlc_hw_info *wlc_hw, uint tx_fifo); -extern void wlc_ucode_wake_override_set(wlc_hw_info_t *wlc_hw, +extern void wlc_ucode_wake_override_set(struct wlc_hw_info *wlc_hw, u32 override_bit); -extern void wlc_ucode_wake_override_clear(wlc_hw_info_t *wlc_hw, +extern void wlc_ucode_wake_override_clear(struct wlc_hw_info *wlc_hw, u32 override_bit); -extern void wlc_bmac_set_rcmta(wlc_hw_info_t *wlc_hw, int idx, +extern void wlc_bmac_set_rcmta(struct wlc_hw_info *wlc_hw, int idx, const struct ether_addr *addr); -extern void wlc_bmac_set_addrmatch(wlc_hw_info_t *wlc_hw, int match_reg_offset, +extern void wlc_bmac_set_addrmatch(struct wlc_hw_info *wlc_hw, + int match_reg_offset, const struct ether_addr *addr); -extern void wlc_bmac_write_hw_bcntemplates(wlc_hw_info_t *wlc_hw, void *bcn, - int len, bool both); +extern void wlc_bmac_write_hw_bcntemplates(struct wlc_hw_info *wlc_hw, + void *bcn, int len, bool both); -extern void wlc_bmac_read_tsf(wlc_hw_info_t *wlc_hw, u32 *tsf_l_ptr, +extern void wlc_bmac_read_tsf(struct wlc_hw_info *wlc_hw, u32 *tsf_l_ptr, u32 *tsf_h_ptr); -extern void wlc_bmac_set_cwmin(wlc_hw_info_t *wlc_hw, u16 newmin); -extern void wlc_bmac_set_cwmax(wlc_hw_info_t *wlc_hw, u16 newmax); -extern void wlc_bmac_set_noreset(wlc_hw_info_t *wlc, bool noreset_flag); -extern void wlc_bmac_set_ucode_loaded(wlc_hw_info_t *wlc, bool ucode_loaded); +extern void wlc_bmac_set_cwmin(struct wlc_hw_info *wlc_hw, u16 newmin); +extern void wlc_bmac_set_cwmax(struct wlc_hw_info *wlc_hw, u16 newmax); +extern void wlc_bmac_set_noreset(struct wlc_hw_info *wlc, bool noreset_flag); +extern void wlc_bmac_set_ucode_loaded(struct wlc_hw_info *wlc, + bool ucode_loaded); -extern void wlc_bmac_retrylimit_upd(wlc_hw_info_t *wlc_hw, u16 SRL, +extern void wlc_bmac_retrylimit_upd(struct wlc_hw_info *wlc_hw, u16 SRL, u16 LRL); -extern void wlc_bmac_fifoerrors(wlc_hw_info_t *wlc_hw); +extern void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw); /* API for BMAC driver (e.g. wlc_phy.c etc) */ -extern void wlc_bmac_bw_set(wlc_hw_info_t *wlc_hw, u16 bw); -extern void wlc_bmac_pllreq(wlc_hw_info_t *wlc_hw, bool set, mbool req_bit); -extern void wlc_bmac_set_clk(wlc_hw_info_t *wlc_hw, bool on); -extern bool wlc_bmac_taclear(wlc_hw_info_t *wlc_hw, bool ta_ok); +extern void wlc_bmac_bw_set(struct wlc_hw_info *wlc_hw, u16 bw); +extern void wlc_bmac_pllreq(struct wlc_hw_info *wlc_hw, bool set, + mbool req_bit); +extern void wlc_bmac_set_clk(struct wlc_hw_info *wlc_hw, bool on); +extern bool wlc_bmac_taclear(struct wlc_hw_info *wlc_hw, bool ta_ok); extern void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw); -extern void wlc_bmac_dump(wlc_hw_info_t *wlc_hw, struct bcmstrbuf *b, +extern void wlc_bmac_dump(struct wlc_hw_info *wlc_hw, struct bcmstrbuf *b, wlc_bmac_dump_id_t dump_id); -extern void wlc_gpio_fast_deinit(wlc_hw_info_t *wlc_hw); +extern void wlc_gpio_fast_deinit(struct wlc_hw_info *wlc_hw); -extern bool wlc_bmac_radio_hw(wlc_hw_info_t *wlc_hw, bool enable); -extern u16 wlc_bmac_rate_shm_offset(wlc_hw_info_t *wlc_hw, u8 rate); +extern bool wlc_bmac_radio_hw(struct wlc_hw_info *wlc_hw, bool enable); +extern u16 wlc_bmac_rate_shm_offset(struct wlc_hw_info *wlc_hw, u8 rate); -extern void wlc_bmac_assert_type_set(wlc_hw_info_t *wlc_hw, u32 type); -extern void wlc_bmac_set_txpwr_percent(wlc_hw_info_t *wlc_hw, u8 val); -extern void wlc_bmac_blink_sync(wlc_hw_info_t *wlc_hw, u32 led_pins); -extern void wlc_bmac_ifsctl_edcrs_set(wlc_hw_info_t *wlc_hw, bool abie, +extern void wlc_bmac_assert_type_set(struct wlc_hw_info *wlc_hw, u32 type); +extern void wlc_bmac_set_txpwr_percent(struct wlc_hw_info *wlc_hw, u8 val); +extern void wlc_bmac_blink_sync(struct wlc_hw_info *wlc_hw, u32 led_pins); +extern void wlc_bmac_ifsctl_edcrs_set(struct wlc_hw_info *wlc_hw, bool abie, bool isht); -extern void wlc_bmac_antsel_set(wlc_hw_info_t *wlc_hw, u32 antsel_avail); +extern void wlc_bmac_antsel_set(struct wlc_hw_info *wlc_hw, u32 antsel_avail); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index b246a7c22ab0..791e9178267e 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -512,7 +512,7 @@ struct wlc_info { struct wl_info *wl; /* pointer to os-specific private state */ d11regs_t *regs; /* pointer to device registers */ - wlc_hw_info_t *hw; /* HW related state used primarily by BMAC */ + struct wlc_hw_info *hw; /* HW related state used primarily by BMAC */ /* clock */ int clkreq_override; /* setting for clkreq for PCIE : Auto, 0, 1 */ @@ -861,8 +861,8 @@ extern void wlc_print_txdesc(d11txh_t *txh); extern void wlc_print_dot11_mac_hdr(u8 *buf, int len); #endif -extern void wlc_setxband(wlc_hw_info_t *wlc_hw, uint bandunit); -extern void wlc_coredisable(wlc_hw_info_t *wlc_hw); +extern void wlc_setxband(struct wlc_hw_info *wlc_hw, uint bandunit); +extern void wlc_coredisable(struct wlc_hw_info *wlc_hw); extern bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rate, int band, bool verbose); diff --git a/drivers/staging/brcm80211/sys/wlc_phy_shim.c b/drivers/staging/brcm80211/sys/wlc_phy_shim.c index 201ecdb319cd..5dcaa7d70045 100644 --- a/drivers/staging/brcm80211/sys/wlc_phy_shim.c +++ b/drivers/staging/brcm80211/sys/wlc_phy_shim.c @@ -59,12 +59,12 @@ /* PHY SHIM module specific state */ struct wlc_phy_shim_info { - wlc_hw_info_t *wlc_hw; /* pointer to main wlc_hw structure */ + struct wlc_hw_info *wlc_hw; /* pointer to main wlc_hw structure */ void *wlc; /* pointer to main wlc structure */ void *wl; /* pointer to os-specific private state */ }; -wlc_phy_shim_info_t *wlc_phy_shim_attach(wlc_hw_info_t *wlc_hw, +wlc_phy_shim_info_t *wlc_phy_shim_attach(struct wlc_hw_info *wlc_hw, void *wl, void *wlc) { wlc_phy_shim_info_t *physhim = NULL; diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 52f888690530..e5c8600c6298 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -20,7 +20,7 @@ /* forward declarations */ struct wlc_info; -typedef struct wlc_hw_info wlc_hw_info_t; +struct wlc_hw_info; typedef struct wlc_if wlc_if_t; typedef struct wl_if wl_if_t; typedef struct led_info led_info_t; -- cgit v1.2.3 From 85c0b1760a7c259679d188bef58866fc641deca5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:01:16 +0300 Subject: Staging: Beceem: add USB id for BCSM250 Mobile WiMAX Signed-off-by: Dan Carpenter Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 1 + drivers/staging/bcm/InterfaceInit.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 7ffbfecaa117..4a9d8c0d5de7 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -4,6 +4,7 @@ static struct usb_device_id InterfaceUsbtable[] = { { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) }, { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) }, diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h index 091cf78d63a1..058315a64c05 100644 --- a/drivers/staging/bcm/InterfaceInit.h +++ b/drivers/staging/bcm/InterfaceInit.h @@ -8,6 +8,7 @@ #define BCM_USB_PRODUCT_ID_T3 0x0300 #define BCM_USB_PRODUCT_ID_T3B 0x0210 #define BCM_USB_PRODUCT_ID_T3L 0x0220 +#define BCM_USB_PRODUCT_ID_SM250 0xbccd #define BCM_USB_PRODUCT_ID_SYM 0x15E #define BCM_USB_PRODUCT_ID_1901 0xe017 #define BCM_USB_PRODUCT_ID_226 0x0132 -- cgit v1.2.3 From 2a314742d300edc2010d50a006c77ceb04c75119 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:01:41 +0300 Subject: Staging: Beceem: use lower case "int" instead of "INT" This patch changes: INT => int ULONG => unsigned long VOID => void Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 4a9d8c0d5de7..5d113334d067 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -21,11 +21,11 @@ static const u32 default_msg = | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; -static INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter); +static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter); -static VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) +static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) { - INT i = 0; + int i = 0; // Wake up the wait_queue... if(psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { @@ -70,9 +70,9 @@ static VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) AdapterFree(psIntfAdapter->psAdapter); } -static VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) +static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) { - ULONG ulReg = 0; + unsigned long ulReg = 0; // Program EP2 MAX_PKT_SIZE ulReg = ntohl(EP2_MPS_REG); @@ -335,7 +335,7 @@ static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter) static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) { - INT value = 0; + int value = 0; UINT status = STATUS_SUCCESS; status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter); @@ -444,14 +444,14 @@ static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descrip return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd)); } -static INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) +static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) { struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; size_t buffer_size; - ULONG value; - INT retval = 0; - INT usedIntOutForBulkTransfer = 0 ; + unsigned long value; + int retval = 0; + int usedIntOutForBulkTransfer = 0 ; BOOLEAN bBcm16 = FALSE; UINT uiData = 0; -- cgit v1.2.3 From c2a0b162dbce1534cf4e71914597419ae83a70d9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:02:11 +0300 Subject: Staging: Beceem: white space changes to InterfaceInit.c This patch only changes: 1) spaces, tabs, and newline characters. 2) comment styles. The compiled object file is the same before and after except for line number changes. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 535 ++++++++++++++++-------------------- 1 file changed, 236 insertions(+), 299 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 5d113334d067..844e5faacca0 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -1,14 +1,14 @@ #include "headers.h" static struct usb_device_id InterfaceUsbtable[] = { - { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, - { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) }, - { } + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) }, + { } }; MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); @@ -17,51 +17,48 @@ module_param(debug, uint, 0600); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); static const u32 default_msg = - NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK - | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR - | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; + NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK + | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter); static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) { int i = 0; - // Wake up the wait_queue... - if(psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) - { + + /* Wake up the wait_queue... */ + if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { psIntfAdapter->psAdapter->DriverState = DRIVER_HALT; wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event); } reset_card_proc(psIntfAdapter->psAdapter); - //worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms - //to accertain the device is not being accessed. After this No RDM/WRM should be made. - while(psIntfAdapter->psAdapter->DeviceAccess) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Device is being Accessed \n"); + /* + * worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms + * to accertain the device is not being accessed. After this No RDM/WRM should be made. + */ + while (psIntfAdapter->psAdapter->DeviceAccess) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Device is being Accessed \n"); msleep(100); } /* Free interrupt URB */ - //psIntfAdapter->psAdapter->device_removed = TRUE; - if(psIntfAdapter->psInterruptUrb) - { + /* psIntfAdapter->psAdapter->device_removed = TRUE; */ + if (psIntfAdapter->psInterruptUrb) { usb_free_urb(psIntfAdapter->psInterruptUrb); } /* Free transmit URBs */ - for(i = 0; i < MAXIMUM_USB_TCB; i++) - { - if(psIntfAdapter->asUsbTcb[i].urb != NULL) - { + for (i = 0; i < MAXIMUM_USB_TCB; i++) { + if (psIntfAdapter->asUsbTcb[i].urb != NULL) { usb_free_urb(psIntfAdapter->asUsbTcb[i].urb); psIntfAdapter->asUsbTcb[i].urb = NULL; } } /* Free receive URB and buffers */ - for(i = 0; i < MAXIMUM_USB_RCB; i++) - { - if (psIntfAdapter->asUsbRcb[i].urb != NULL) - { + for (i = 0; i < MAXIMUM_USB_RCB; i++) { + if (psIntfAdapter->asUsbRcb[i].urb != NULL) { kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer); usb_free_urb(psIntfAdapter->asUsbRcb[i].urb); psIntfAdapter->asUsbRcb[i].urb = NULL; @@ -74,84 +71,77 @@ static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) { unsigned long ulReg = 0; -// Program EP2 MAX_PKT_SIZE + /* Program EP2 MAX_PKT_SIZE */ ulReg = ntohl(EP2_MPS_REG); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x128,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE); ulReg = ntohl(EP2_MPS); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x12C,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE); ulReg = ntohl(EP2_CFG_REG); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x132,4,TRUE); - if(((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) - { + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE); + if (((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) { ulReg = ntohl(EP2_CFG_INT); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x136,4,TRUE); - } - else - { -// USE BULK EP as TX in FS mode. + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE); + } else { + /* USE BULK EP as TX in FS mode. */ ulReg = ntohl(EP2_CFG_BULK); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x136,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE); } - -// Program EP4 MAX_PKT_SIZE. + /* Program EP4 MAX_PKT_SIZE. */ ulReg = ntohl(EP4_MPS_REG); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x13C,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE); ulReg = ntohl(EP4_MPS); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x140,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE); -// Program TX EP as interrupt (Alternate Setting) - if( rdmalt(Adapter,0x0F0110F8, (PUINT)&ulReg,4)) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP is failing"); - return ; + /* Program TX EP as interrupt(Alternate Setting) */ + if (rdmalt(Adapter, 0x0F0110F8, (PUINT)&ulReg, 4)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP is failing"); + return; } ulReg |= 0x6; ulReg = ntohl(ulReg); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1CC,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE); ulReg = ntohl(EP4_CFG_REG); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1C8,4,TRUE); -// Program ISOCHRONOUS EP size to zero. + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE); + /* Program ISOCHRONOUS EP size to zero. */ ulReg = ntohl(ISO_MPS_REG); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1D2,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE); ulReg = ntohl(ISO_MPS); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1D6,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE); -// Update EEPROM Version. -// Read 4 bytes from 508 and modify 511 and 510. -// - ReadBeceemEEPROM(Adapter,0x1FC,(PUINT)&ulReg); + /* + * Update EEPROM Version. + * Read 4 bytes from 508 and modify 511 and 510. + */ + ReadBeceemEEPROM(Adapter, 0x1FC, (PUINT)&ulReg); ulReg &= 0x0101FFFF; - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1FC,4,TRUE); -// -//Update length field if required. Also make the string NULL terminated. -// - ReadBeceemEEPROM(Adapter,0xA8,(PUINT)&ulReg); - if((ulReg&0x00FF0000)>>16 > 0x30) - { + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE); + + /* Update length field if required. Also make the string NULL terminated. */ + + ReadBeceemEEPROM(Adapter, 0xA8, (PUINT)&ulReg); + if ((ulReg&0x00FF0000)>>16 > 0x30) { ulReg = (ulReg&0xFF00FFFF)|(0x30<<16); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0xA8,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE); } - ReadBeceemEEPROM(Adapter,0x148,(PUINT)&ulReg); - if((ulReg&0x00FF0000)>>16 > 0x30) - { + ReadBeceemEEPROM(Adapter, 0x148, (PUINT)&ulReg); + if ((ulReg&0x00FF0000)>>16 > 0x30) { ulReg = (ulReg&0xFF00FFFF)|(0x30<<16); - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x148,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE); } ulReg = 0; - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x122,4,TRUE); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE); ulReg = 0; - BeceemEEPROMBulkWrite(Adapter,(PUCHAR)&ulReg,0x1C2,4,TRUE); - + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE); } static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev (intf); + struct usb_device *udev = interface_to_usbdev(intf); int retval; PMINI_ADAPTER psAdapter; PS_INTERFACE_ADAPTER psIntfAdapter; @@ -159,7 +149,7 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Reserve one extra queue for the bit-bucket */ ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1); - if(ndev == NULL) { + if (ndev == NULL) { dev_err(&udev->dev, DRV_NAME ": no memory for device\n"); return -ENOMEM; } @@ -170,12 +160,13 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) psAdapter->dev = ndev; psAdapter->msg_enable = netif_msg_init(debug, default_msg); - /* Init default driver debug state */ + /* Init default driver debug state */ psAdapter->stDebugState.debug_level = DBG_LVL_CURR; psAdapter->stDebugState.type = DBG_TYPE_INITEXIT; - /* Technically, one can start using BCM_DEBUG_PRINT after this point. + /* + * Technically, one can start using BCM_DEBUG_PRINT after this point. * However, realize that by default the Type/Subtype bitmaps are all zero now; * so no prints will actually appear until the TestApp turns on debug paths via * the ioctl(); so practically speaking, in early init, no logging happens. @@ -186,12 +177,11 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) * Further, we turn this OFF once init_module() completes. */ - psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff; + psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff; BCM_SHOW_DEBUG_BITMAP(psAdapter); retval = InitAdapter(psAdapter); - if(retval) - { + if (retval) { dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n"); AdapterFree(psAdapter); return retval; @@ -199,10 +189,9 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Allocate interface adapter structure */ psIntfAdapter = kzalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL); - if (psIntfAdapter == NULL) - { + if (psIntfAdapter == NULL) { dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n"); - AdapterFree (psAdapter); + AdapterFree(psAdapter); return -ENOMEM; } @@ -213,84 +202,78 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) psIntfAdapter->interface = intf; usb_set_intfdata(intf, psIntfAdapter); - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p",psIntfAdapter); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p", psIntfAdapter); retval = InterfaceAdapterInit(psIntfAdapter); - if(retval) - { + if (retval) { /* If the Firmware/Cfg File is not present - * then return success, let the application - * download the files. - */ - if(-ENOENT == retval){ - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "File Not Found, Use App to Download\n"); + * then return success, let the application + * download the files. + */ + if (-ENOENT == retval) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "File Not Found, Use App to Download\n"); return STATUS_SUCCESS; } - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapterInit Failed \n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapterInit Failed \n"); usb_set_intfdata(intf, NULL); - udev = interface_to_usbdev (intf); + udev = interface_to_usbdev(intf); usb_put_dev(udev); InterfaceAdapterFree(psIntfAdapter); - return retval ; + return retval; } - if(psAdapter->chip_id > T3) - { - uint32_t uiNackZeroLengthInt=4; - if(wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt))) - { + if (psAdapter->chip_id > T3) { + uint32_t uiNackZeroLengthInt = 4; + + if (wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt))) { return -EIO; } } /* Check whether the USB-Device Supports remote Wake-Up */ - if(USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) - { + if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) { /* If Suspend then only support dynamic suspend */ - if(psAdapter->bDoSuspend) - { + if (psAdapter->bDoSuspend) { #ifdef CONFIG_PM udev->autosuspend_delay = 0; intf->needs_remote_wakeup = 1; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) - udev->autosuspend_disabled = 0; + udev->autosuspend_disabled = 0; #else usb_enable_autosuspend(udev); #endif - device_init_wakeup(&intf->dev,1); + device_init_wakeup(&intf->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) - usb_autopm_disable(intf); + usb_autopm_disable(intf); #endif INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend); - BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n"); #endif - } - else - { + } else { intf->needs_remote_wakeup = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) - udev->autosuspend_disabled = 1; + udev->autosuspend_disabled = 1; #else usb_disable_autosuspend(udev); #endif } } - psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0; - return retval; + psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0; + return retval; } -static void usbbcm_disconnect (struct usb_interface *intf) +static void usbbcm_disconnect(struct usb_interface *intf) { PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); PMINI_ADAPTER psAdapter; - struct usb_device *udev = interface_to_usbdev (intf); + struct usb_device *udev = interface_to_usbdev(intf); - if(psIntfAdapter == NULL) + if (psIntfAdapter == NULL) return; psAdapter = psIntfAdapter->psAdapter; netif_device_detach(psAdapter->dev); - if(psAdapter->bDoSuspend) + if (psAdapter->bDoSuspend) intf->needs_remote_wakeup = 0; psAdapter->device_removed = TRUE ; @@ -302,28 +285,24 @@ static void usbbcm_disconnect (struct usb_interface *intf) static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter) { int i = 0; - for(i = 0; i < MAXIMUM_USB_TCB; i++) - { - if((psIntfAdapter->asUsbTcb[i].urb = - usb_alloc_urb(0, GFP_KERNEL)) == NULL) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cant allocate Tx urb for index %d", i); + + for (i = 0; i < MAXIMUM_USB_TCB; i++) { + if ((psIntfAdapter->asUsbTcb[i].urb = + usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Tx urb for index %d", i); return -ENOMEM; } } - for(i = 0; i < MAXIMUM_USB_RCB; i++) - { + for (i = 0; i < MAXIMUM_USB_RCB; i++) { if ((psIntfAdapter->asUsbRcb[i].urb = - usb_alloc_urb(0, GFP_KERNEL)) == NULL) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx urb for index %d", i); + usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx urb for index %d", i); return -ENOMEM; } - if((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = - kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx buffer for index %d", i); + if ((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = + kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx buffer for index %d", i); return -ENOMEM; } psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE; @@ -331,37 +310,33 @@ static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter) return 0; } - - static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) { int value = 0; UINT status = STATUS_SUCCESS; status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter); - if(status != STATUS_SUCCESS) - { + if (status != STATUS_SUCCESS) { pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n"); return status; } - if(TRUE == psIntfAdapter->psAdapter->fw_download_done) - { - if(StartInterruptUrb(psIntfAdapter)) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB"); + if (TRUE == psIntfAdapter->psAdapter->fw_download_done) { + if (StartInterruptUrb(psIntfAdapter)) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB"); } - //now register the cntrl interface. - //after downloading the f/w waiting for 5 sec to get the mailbox interrupt. + /* + * now register the cntrl interface. + * after downloading the f/w waiting for 5 sec to get the mailbox interrupt. + */ psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE; value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue, psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ); - if(value == 0) + if (value == 0) pr_err(DRV_NAME ": Mailbox Interrupt has not reached to Driver..\n"); - if(register_control_device_interface(psIntfAdapter->psAdapter) < 0) - { + if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) { pr_err(DRV_NAME ": Register Control Device failed...\n"); return -EIO; } @@ -462,13 +437,12 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->psAdapter->interface_rdm = BcmRDM; psIntfAdapter->psAdapter->interface_wrm = BcmWRM; - if(rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (PUINT)&(psIntfAdapter->psAdapter->chip_id), sizeof(UINT)) < 0) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n"); + if (rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (PUINT)&(psIntfAdapter->psAdapter->chip_id), sizeof(UINT)) < 0) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n"); return STATUS_FAILURE; } - if(0xbece3200==(psIntfAdapter->psAdapter->chip_id&~(0xF0))) + if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0))) psIntfAdapter->psAdapter->chip_id &= ~0xF0; dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n", @@ -476,80 +450,70 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) iface_desc = psIntfAdapter->interface->cur_altsetting; - if(psIntfAdapter->psAdapter->chip_id == T3B) - { - // - //T3B device will have EEPROM,check if EEPROM is proper and BCM16 can be done or not. - // - BeceemEEPROMBulkRead(psIntfAdapter->psAdapter,&uiData,0x0,4); - if(uiData == BECM) + if (psIntfAdapter->psAdapter->chip_id == T3B) { + /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */ + BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4); + if (uiData == BECM) bBcm16 = TRUE; dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n", psIntfAdapter->interface->num_altsetting); - if(bBcm16 == TRUE) - { - //selecting alternate setting one as a default setting for High Speed modem. - if(psIntfAdapter->bHighSpeedDevice) - retval= usb_set_interface(psIntfAdapter->udev,DEFAULT_SETTING_0,ALTERNATE_SETTING_1); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM16 is Applicable on this dongle"); - if(retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) - { + if (bBcm16 == TRUE) { + /* selecting alternate setting one as a default setting for High Speed modem. */ + if (psIntfAdapter->bHighSpeedDevice) + retval= usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM16 is Applicable on this dongle"); + if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) { usedIntOutForBulkTransfer = EP2 ; endpoint = &iface_desc->endpoint[EP2].desc; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Interface altsetting got failed or Moemd is configured to FS.hence will work on default setting 0 \n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Interface altsetting got failed or Moemd is configured to FS.hence will work on default setting 0 \n"); /* - If Modem is high speed device EP2 should be INT OUT End point - If Mode is FS then EP2 should be bulk end point - */ - if(((psIntfAdapter->bHighSpeedDevice ==TRUE ) && (bcm_usb_endpoint_is_int_out(endpoint)== FALSE)) - ||((psIntfAdapter->bHighSpeedDevice == FALSE)&& (bcm_usb_endpoint_is_bulk_out(endpoint)== FALSE))) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Configuring the EEPROM "); - //change the EP2, EP4 to INT OUT end point + * If Modem is high speed device EP2 should be INT OUT End point + * If Mode is FS then EP2 should be bulk end point + */ + if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE)) + || ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Configuring the EEPROM "); + /* change the EP2, EP4 to INT OUT end point */ ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); /* - It resets the device and if any thing gets changed in USB descriptor it will show fail and - re-enumerate the device - */ + * It resets the device and if any thing gets changed + * in USB descriptor it will show fail and re-enumerate + * the device + */ retval = usb_reset_device(psIntfAdapter->udev); - if(retval) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n"); + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n"); return retval ; } } - if((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) - { - // Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. + if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) { + /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */ UINT _uiData = ntohl(EP2_CFG_INT); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Reverting Bulk to INT as it is FS MODE"); - BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter,(PUCHAR)&_uiData,0x136,4,TRUE); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Reverting Bulk to INT as it is FS MODE"); + BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE); } - } - else - { + } else { usedIntOutForBulkTransfer = EP4 ; endpoint = &iface_desc->endpoint[EP4].desc; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting"); - if( bcm_usb_endpoint_is_int_out(endpoint) == FALSE) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, " Dongle does not have BCM16 Fix"); - //change the EP2, EP4 to INT OUT end point and use EP4 in altsetting + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting"); + if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, " Dongle does not have BCM16 Fix"); + /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */ ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); /* - It resets the device and if any thing gets changed in USB descriptor it will show fail and - re-enumerate the device - */ + * It resets the device and if any thing gets changed in + * USB descriptor it will show fail and re-enumerate the + * device + */ retval = usb_reset_device(psIntfAdapter->udev); - if(retval) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n"); - return retval ; + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n"); + return retval; } } @@ -559,84 +523,65 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) iface_desc = psIntfAdapter->interface->cur_altsetting; - for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) - { + for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) { endpoint = &iface_desc->endpoint[value].desc; - if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) - { - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - psIntfAdapter->sBulkIn.bulk_in_size = buffer_size; - psIntfAdapter->sBulkIn.bulk_in_endpointAddr = - endpoint->bEndpointAddress; - psIntfAdapter->sBulkIn.bulk_in_pipe = + if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) { + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sBulkIn.bulk_in_size = buffer_size; + psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress; + psIntfAdapter->sBulkIn.bulk_in_pipe = usb_rcvbulkpipe(psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_endpointAddr); - } - - if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) - { + } - psIntfAdapter->sBulkOut.bulk_out_endpointAddr = - endpoint->bEndpointAddress; - psIntfAdapter->sBulkOut.bulk_out_pipe = - usb_sndbulkpipe(psIntfAdapter->udev, - psIntfAdapter->sBulkOut.bulk_out_endpointAddr); - } - - if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) - { - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - psIntfAdapter->sIntrIn.int_in_size = buffer_size; - psIntfAdapter->sIntrIn.int_in_endpointAddr = - endpoint->bEndpointAddress; - psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval; - psIntfAdapter->sIntrIn.int_in_buffer = - kmalloc(buffer_size, GFP_KERNEL); - if (!psIntfAdapter->sIntrIn.int_in_buffer) { - dev_err(&psIntfAdapter->udev->dev, - "could not allocate interrupt_in_buffer\n"); - return -EINVAL; - } - } - - if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) - { - - if( !psIntfAdapter->sBulkOut.bulk_out_endpointAddr && - (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) - { - //use first intout end point as a bulk out end point - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - psIntfAdapter->sBulkOut.bulk_out_size = buffer_size; - //printk("\nINT OUT Endpoing buffer size :%x endpoint :%x\n", buffer_size, value +1); - psIntfAdapter->sBulkOut.bulk_out_endpointAddr = - endpoint->bEndpointAddress; - psIntfAdapter->sBulkOut.bulk_out_pipe = - usb_sndintpipe(psIntfAdapter->udev, + if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) { + psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress; + psIntfAdapter->sBulkOut.bulk_out_pipe = + usb_sndbulkpipe(psIntfAdapter->udev, psIntfAdapter->sBulkOut.bulk_out_endpointAddr); - psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval; + } - } - else if(value == EP6) - { - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - psIntfAdapter->sIntrOut.int_out_size = buffer_size; - psIntfAdapter->sIntrOut.int_out_endpointAddr = - endpoint->bEndpointAddress; - psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval; - psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size, - GFP_KERNEL); - if (!psIntfAdapter->sIntrOut.int_out_buffer) - { + if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) { + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sIntrIn.int_in_size = buffer_size; + psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress; + psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval; + psIntfAdapter->sIntrIn.int_in_buffer = + kmalloc(buffer_size, GFP_KERNEL); + if (!psIntfAdapter->sIntrIn.int_in_buffer) { dev_err(&psIntfAdapter->udev->dev, - "could not allocate interrupt_out_buffer\n"); + "could not allocate interrupt_in_buffer\n"); + return -EINVAL; + } + } + + if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) { + if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && + (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) { + /* use first intout end point as a bulk out end point */ + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sBulkOut.bulk_out_size = buffer_size; + psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress; + psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev, + psIntfAdapter->sBulkOut.bulk_out_endpointAddr); + psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval; + } else if (value == EP6) { + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sIntrOut.int_out_size = buffer_size; + psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress; + psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval; + psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size, GFP_KERNEL); + if (!psIntfAdapter->sIntrOut.int_out_buffer) { + dev_err(&psIntfAdapter->udev->dev, + "could not allocate interrupt_out_buffer\n"); return -EINVAL; + } } - } - } + } } - usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter); + + usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter); psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload; psIntfAdapter->psAdapter->bcm_file_readback_from_chip = @@ -645,58 +590,51 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) retval = CreateInterruptUrb(psIntfAdapter); - if(retval) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cannot create interrupt urb"); + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cannot create interrupt urb"); return retval; } retval = AllocUsbCb(psIntfAdapter); - if(retval) - { + if (retval) { return retval; } - return device_run(psIntfAdapter); } -static int InterfaceSuspend (struct usb_interface *intf, pm_message_t message) +static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message) { PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); psIntfAdapter->bSuspended = TRUE; - if(TRUE == psIntfAdapter->bPreparingForBusSuspend) - { + if (TRUE == psIntfAdapter->bPreparingForBusSuspend) { psIntfAdapter->bPreparingForBusSuspend = FALSE; - if(psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) - { + if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) { psIntfAdapter->psAdapter->IdleMode = TRUE ; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Idle Mode.."); - } - else - { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Idle Mode.."); + } else { psIntfAdapter->psAdapter->bShutStatus = TRUE; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Shutdown Mode.."); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Shutdown Mode.."); } } psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE; - //Signaling the control pkt path + /* Signaling the control pkt path */ wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue); return 0; } -static int InterfaceResume (struct usb_interface *intf) +static int InterfaceResume(struct usb_interface *intf) { - PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); + PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); printk("=================================\n"); mdelay(100); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) - intf->pm_usage_cnt =1 ; + intf->pm_usage_cnt =1 ; #endif psIntfAdapter->bSuspended = FALSE; @@ -706,18 +644,17 @@ static int InterfaceResume (struct usb_interface *intf) } static struct usb_driver usbbcm_driver = { - .name = "usbbcm", - .probe = usbbcm_device_probe, - .disconnect = usbbcm_disconnect, - .suspend = InterfaceSuspend, - .resume = InterfaceResume, - .id_table = InterfaceUsbtable, - .supports_autosuspend = 1, + .name = "usbbcm", + .probe = usbbcm_device_probe, + .disconnect = usbbcm_disconnect, + .suspend = InterfaceSuspend, + .resume = InterfaceResume, + .id_table = InterfaceUsbtable, + .supports_autosuspend = 1, }; struct class *bcm_class; - static __init int bcm_init(void) { printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION); @@ -734,7 +671,7 @@ static __init int bcm_init(void) static __exit void bcm_exit(void) { - class_destroy (bcm_class); + class_destroy(bcm_class); usb_deregister(&usbbcm_driver); } @@ -744,4 +681,4 @@ module_exit(bcm_exit); MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_LICENSE ("GPL"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From cd0b0ebfbe134b9c98fa8e628732b0e41b2cb48c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:02:36 +0300 Subject: Staging: Beceem: remove old kernel compatibility code This drops compatability for everything from 2.4 to 2.6.35. Now it only works on the latest kernel. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 15 +-------------- drivers/staging/bcm/InterfaceTx.c | 11 ----------- drivers/staging/bcm/Misc.c | 2 -- drivers/staging/bcm/headers.h | 2 -- 4 files changed, 1 insertion(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 844e5faacca0..dd829409a8c8 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -235,25 +235,14 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) #ifdef CONFIG_PM udev->autosuspend_delay = 0; intf->needs_remote_wakeup = 1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) - udev->autosuspend_disabled = 0; -#else usb_enable_autosuspend(udev); -#endif device_init_wakeup(&intf->dev, 1); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) - usb_autopm_disable(intf); -#endif INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend); BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n"); #endif } else { intf->needs_remote_wakeup = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) - udev->autosuspend_disabled = 1; -#else usb_disable_autosuspend(udev); -#endif } } @@ -633,9 +622,7 @@ static int InterfaceResume(struct usb_interface *intf) PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); printk("=================================\n"); mdelay(100); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) - intf->pm_usage_cnt =1 ; -#endif + psIntfAdapter->bSuspended = FALSE; StartInterruptUrb(psIntfAdapter); diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c index f434b899a0d0..a842de9de6b5 100644 --- a/drivers/staging/bcm/InterfaceTx.c +++ b/drivers/staging/bcm/InterfaceTx.c @@ -102,13 +102,8 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) } err_exit : -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) - usb_buffer_free(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); -#else usb_free_coherent(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); -#endif } @@ -139,14 +134,8 @@ static int TransmitTcb(PS_INTERFACE_ADAPTER psIntfAdapter, PUSB_TCB pTcb, PVOID struct urb *urb = pTcb->urb; int retval = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) - urb->transfer_buffer = usb_buffer_alloc(psIntfAdapter->udev, len, - GFP_ATOMIC, &urb->transfer_dma); -#else urb->transfer_buffer = usb_alloc_coherent(psIntfAdapter->udev, len, GFP_ATOMIC, &urb->transfer_dma); -#endif - if (!urb->transfer_buffer) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Error allocating memory\n"); diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index 9588fbe101d9..f585aae9cf8b 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -233,9 +233,7 @@ static int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */ goto exit_download; } oldfs=get_fs();set_fs(get_ds()); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) vfs_llseek(flp, 0, 0); -#endif set_fs(oldfs); if(Adapter->bcm_file_readback_from_chip(Adapter->pvInterfaceAdapter, flp, loc)) diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index 473f11eebf7c..1148e5e22eb9 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -35,9 +35,7 @@ #include #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #include -#endif #include #include #include -- cgit v1.2.3 From 6b74705e15d5c87181008f1ac984df7faaad55c9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:02:55 +0300 Subject: Staging: Beceem: use after free in bcm_exit() We can't call class_destroy() until after the driver has been deregistered. It leads to a NULL deref on module unload. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index dd829409a8c8..b4d22562d060 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -658,9 +658,8 @@ static __init int bcm_init(void) static __exit void bcm_exit(void) { - class_destroy(bcm_class); - usb_deregister(&usbbcm_driver); + class_destroy(bcm_class); } module_init(bcm_init); -- cgit v1.2.3 From 07a7f68800a490bc1140de778e196f66ef4596d9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:03:13 +0300 Subject: Staging: Beceem: improve debug printk statements These are just small changes. Some grammar and wording changes. I added new lines to the end of all the print statements. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 66 ++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index b4d22562d060..d236b2a054e5 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -40,7 +40,7 @@ static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) */ while (psIntfAdapter->psAdapter->DeviceAccess) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Device is being Accessed \n"); + "Device is being accessed.\n"); msleep(100); } /* Free interrupt URB */ @@ -96,7 +96,8 @@ static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) /* Program TX EP as interrupt(Alternate Setting) */ if (rdmalt(Adapter, 0x0F0110F8, (PUINT)&ulReg, 4)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP is failing"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "reading of Tx EP failed\n"); return; } ulReg |= 0x6; @@ -202,7 +203,8 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) psIntfAdapter->interface = intf; usb_set_intfdata(intf, psIntfAdapter); - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p", psIntfAdapter); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "psIntfAdapter 0x%p\n", psIntfAdapter); retval = InterfaceAdapterInit(psIntfAdapter); if (retval) { /* If the Firmware/Cfg File is not present @@ -210,10 +212,12 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) * download the files. */ if (-ENOENT == retval) { - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "File Not Found, Use App to Download\n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "File Not Found. Use app to download.\n"); return STATUS_SUCCESS; } - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapterInit Failed \n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "InterfaceAdapterInit failed.\n"); usb_set_intfdata(intf, NULL); udev = interface_to_usbdev(intf); usb_put_dev(udev); @@ -238,7 +242,8 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_enable_autosuspend(udev); device_init_wakeup(&intf->dev, 1); INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend); - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Enabling USB Auto-Suspend\n"); #endif } else { intf->needs_remote_wakeup = 0; @@ -278,7 +283,8 @@ static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter) for (i = 0; i < MAXIMUM_USB_TCB; i++) { if ((psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Tx urb for index %d", i); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Tx urb for index %d\n", i); return -ENOMEM; } } @@ -286,12 +292,14 @@ static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter) for (i = 0; i < MAXIMUM_USB_RCB; i++) { if ((psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx urb for index %d", i); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Rx urb for index %d\n", i); return -ENOMEM; } if ((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx buffer for index %d", i); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Rx buffer for index %d\n", i); return -ENOMEM; } psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE; @@ -311,7 +319,8 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) } if (TRUE == psIntfAdapter->psAdapter->fw_download_done) { if (StartInterruptUrb(psIntfAdapter)) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Cannot send interrupt in URB\n"); } /* @@ -323,10 +332,10 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ); if (value == 0) - pr_err(DRV_NAME ": Mailbox Interrupt has not reached to Driver..\n"); + pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n"); if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) { - pr_err(DRV_NAME ": Register Control Device failed...\n"); + pr_err(DRV_NAME ": Register Control Device failed.\n"); return -EIO; } } @@ -452,18 +461,21 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) /* selecting alternate setting one as a default setting for High Speed modem. */ if (psIntfAdapter->bHighSpeedDevice) retval= usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM16 is Applicable on this dongle"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "BCM16 is applicable on this dongle\n"); if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) { usedIntOutForBulkTransfer = EP2 ; endpoint = &iface_desc->endpoint[EP2].desc; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Interface altsetting got failed or Moemd is configured to FS.hence will work on default setting 0 \n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n"); /* * If Modem is high speed device EP2 should be INT OUT End point * If Mode is FS then EP2 should be bulk end point */ if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE)) || ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Configuring the EEPROM "); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Configuring the EEPROM\n"); /* change the EP2, EP4 to INT OUT end point */ ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); @@ -474,7 +486,8 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) */ retval = usb_reset_device(psIntfAdapter->udev); if (retval) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "reset failed. Re-enumerating the device.\n"); return retval ; } @@ -482,15 +495,18 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) { /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */ UINT _uiData = ntohl(EP2_CFG_INT); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Reverting Bulk to INT as it is FS MODE"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Reverting Bulk to INT as it is in Full Speed mode.\n"); BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE); } } else { usedIntOutForBulkTransfer = EP4 ; endpoint = &iface_desc->endpoint[EP4].desc; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Choosing AltSetting as a default setting.\n"); if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, " Dongle does not have BCM16 Fix"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Dongle does not have BCM16 Fix.\n"); /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */ ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); @@ -501,7 +517,8 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) */ retval = usb_reset_device(psIntfAdapter->udev); if (retval) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "reset failed. Re-enumerating the device.\n"); return retval; } @@ -580,7 +597,8 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) retval = CreateInterruptUrb(psIntfAdapter); if (retval) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cannot create interrupt urb"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "Cannot create interrupt urb\n"); return retval; } @@ -603,10 +621,12 @@ static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message) if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) { psIntfAdapter->psAdapter->IdleMode = TRUE ; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Idle Mode.."); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Host Entered in PMU Idle Mode.\n"); } else { psIntfAdapter->psAdapter->bShutStatus = TRUE; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Shutdown Mode.."); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "Host Entered in PMU Shutdown Mode.\n"); } } psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE; -- cgit v1.2.3 From 37db526463a5ad1c96cd803d49fddbf069bbf9b9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 10:03:38 +0300 Subject: Staging: Beceem: more checkpatch.pl changes to InterfaceInit.c The only checkpatch.pl issues remaining still remaining are line length complaints. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/bcm/InterfaceInit.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index d236b2a054e5..082b5e5c01e8 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -45,9 +45,7 @@ static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) } /* Free interrupt URB */ /* psIntfAdapter->psAdapter->device_removed = TRUE; */ - if (psIntfAdapter->psInterruptUrb) { - usb_free_urb(psIntfAdapter->psInterruptUrb); - } + usb_free_urb(psIntfAdapter->psInterruptUrb); /* Free transmit URBs */ for (i = 0; i < MAXIMUM_USB_TCB; i++) { @@ -70,6 +68,7 @@ static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter) static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) { unsigned long ulReg = 0; + int ret; /* Program EP2 MAX_PKT_SIZE */ ulReg = ntohl(EP2_MPS_REG); @@ -95,7 +94,8 @@ static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter) BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE); /* Program TX EP as interrupt(Alternate Setting) */ - if (rdmalt(Adapter, 0x0F0110F8, (PUINT)&ulReg, 4)) { + ret = rdmalt(Adapter, 0x0F0110F8, (u32 *)&ulReg, sizeof(u32)); + if (ret) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP failed\n"); return; @@ -227,9 +227,9 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) if (psAdapter->chip_id > T3) { uint32_t uiNackZeroLengthInt = 4; - if (wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt))) { - return -EIO; - } + retval = wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt)); + if (retval) + return retval; } /* Check whether the USB-Device Supports remote Wake-Up */ @@ -435,9 +435,11 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) psIntfAdapter->psAdapter->interface_rdm = BcmRDM; psIntfAdapter->psAdapter->interface_wrm = BcmWRM; - if (rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (PUINT)&(psIntfAdapter->psAdapter->chip_id), sizeof(UINT)) < 0) { + retval = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, + (u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32)); + if (retval) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n"); - return STATUS_FAILURE; + return retval; } if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0))) @@ -603,9 +605,8 @@ static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter) } retval = AllocUsbCb(psIntfAdapter); - if (retval) { + if (retval) return retval; - } return device_run(psIntfAdapter); } @@ -640,7 +641,6 @@ static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message) static int InterfaceResume(struct usb_interface *intf) { PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf); - printk("=================================\n"); mdelay(100); psIntfAdapter->bSuspended = FALSE; -- cgit v1.2.3 From d2aaba455fed75f231fe30fccfd25bcb8d8ff305 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:44 -0800 Subject: staging: hv: Convert camel case struct fields in vstorage.h to lowercase Convert camel case struct fields in vstorage.h to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/storvsc.c | 133 +++++++++++++++++++++--------------------- drivers/staging/hv/vstorage.h | 106 ++++++++++++++++----------------- 2 files changed, 120 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 525c8ee46f07..96b4ed986118 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -204,8 +204,8 @@ static int StorVscChannelInit(struct hv_device *Device) goto nomem; } - vstorPacket->Operation = VStorOperationBeginInitialization; - vstorPacket->Flags = REQUEST_COMPLETION_FLAG; + vstorPacket->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; + vstorPacket->flags = REQUEST_COMPLETION_FLAG; /*SpinlockAcquire(gDriverExt.packetListLock); INSERT_TAIL_LIST(&gDriverExt.packetList, &packet->listEntry.entry); @@ -226,11 +226,11 @@ static int StorVscChannelInit(struct hv_device *Device) osd_waitevent_wait(request->WaitEvent); - if (vstorPacket->Operation != VStorOperationCompleteIo || - vstorPacket->Status != 0) { + if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || + vstorPacket->status != 0) { DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->Operation, vstorPacket->Status); + vstorPacket->operation, vstorPacket->status); goto Cleanup; } @@ -238,11 +238,11 @@ static int StorVscChannelInit(struct hv_device *Device) /* reuse the packet for version range supported */ memset(vstorPacket, 0, sizeof(struct vstor_packet)); - vstorPacket->Operation = VStorOperationQueryProtocolVersion; - vstorPacket->Flags = REQUEST_COMPLETION_FLAG; + vstorPacket->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; + vstorPacket->flags = REQUEST_COMPLETION_FLAG; - vstorPacket->Version.MajorMinor = VMSTOR_PROTOCOL_VERSION_CURRENT; - FILL_VMSTOR_REVISION(vstorPacket->Version.Revision); + vstorPacket->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT; + FILL_VMSTOR_REVISION(vstorPacket->version.revision); ret = vmbus_sendpacket(Device->channel, vstorPacket, sizeof(struct vstor_packet), @@ -258,11 +258,11 @@ static int StorVscChannelInit(struct hv_device *Device) osd_waitevent_wait(request->WaitEvent); /* TODO: Check returned version */ - if (vstorPacket->Operation != VStorOperationCompleteIo || - vstorPacket->Status != 0) { + if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || + vstorPacket->status != 0) { DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->Operation, vstorPacket->Status); + vstorPacket->operation, vstorPacket->status); goto Cleanup; } @@ -270,9 +270,9 @@ static int StorVscChannelInit(struct hv_device *Device) DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION..."); memset(vstorPacket, 0, sizeof(struct vstor_packet)); - vstorPacket->Operation = VStorOperationQueryProperties; - vstorPacket->Flags = REQUEST_COMPLETION_FLAG; - vstorPacket->StorageChannelProperties.PortNumber = + vstorPacket->operation = VSTOR_OPERATION_QUERY_PROPERTIES; + vstorPacket->flags = REQUEST_COMPLETION_FLAG; + vstorPacket->storage_channel_properties.port_number = storDevice->PortNumber; ret = vmbus_sendpacket(Device->channel, vstorPacket, @@ -290,26 +290,27 @@ static int StorVscChannelInit(struct hv_device *Device) osd_waitevent_wait(request->WaitEvent); /* TODO: Check returned version */ - if (vstorPacket->Operation != VStorOperationCompleteIo || - vstorPacket->Status != 0) { + if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || + vstorPacket->status != 0) { DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->Operation, vstorPacket->Status); + vstorPacket->operation, vstorPacket->status); goto Cleanup; } - storDevice->PathId = vstorPacket->StorageChannelProperties.PathId; - storDevice->TargetId = vstorPacket->StorageChannelProperties.TargetId; + storDevice->PathId = vstorPacket->storage_channel_properties.path_id; + storDevice->TargetId + = vstorPacket->storage_channel_properties.target_id; DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x", - vstorPacket->StorageChannelProperties.Flags, - vstorPacket->StorageChannelProperties.MaxTransferBytes); + vstorPacket->storage_channel_properties.flags, + vstorPacket->storage_channel_properties.max_transfer_bytes); DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION..."); memset(vstorPacket, 0, sizeof(struct vstor_packet)); - vstorPacket->Operation = VStorOperationEndInitialization; - vstorPacket->Flags = REQUEST_COMPLETION_FLAG; + vstorPacket->operation = VSTOR_OPERATION_END_INITIALIZATION; + vstorPacket->flags = REQUEST_COMPLETION_FLAG; ret = vmbus_sendpacket(Device->channel, vstorPacket, sizeof(struct vstor_packet), @@ -325,11 +326,11 @@ static int StorVscChannelInit(struct hv_device *Device) osd_waitevent_wait(request->WaitEvent); - if (vstorPacket->Operation != VStorOperationCompleteIo || - vstorPacket->Status != 0) { + if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || + vstorPacket->status != 0) { DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->Operation, vstorPacket->Status); + vstorPacket->operation, vstorPacket->status); goto Cleanup; } @@ -359,7 +360,7 @@ static void StorVscOnIOCompletion(struct hv_device *Device, DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p " "completed bytes xfer %u", RequestExt, - VStorPacket->VmSrb.DataTransferLength); + VStorPacket->vm_srb.data_transfer_length); /* ASSERT(RequestExt != NULL); */ /* ASSERT(RequestExt->Request != NULL); */ @@ -369,36 +370,36 @@ static void StorVscOnIOCompletion(struct hv_device *Device, /* ASSERT(request->OnIOCompletion != NULL); */ /* Copy over the status...etc */ - request->Status = VStorPacket->VmSrb.ScsiStatus; + request->Status = VStorPacket->vm_srb.scsi_status; - if (request->Status != 0 || VStorPacket->VmSrb.SrbStatus != 1) { + if (request->Status != 0 || VStorPacket->vm_srb.srb_status != 1) { DPRINT_WARN(STORVSC, "cmd 0x%x scsi status 0x%x srb status 0x%x\n", - request->Cdb[0], VStorPacket->VmSrb.ScsiStatus, - VStorPacket->VmSrb.SrbStatus); + request->Cdb[0], VStorPacket->vm_srb.scsi_status, + VStorPacket->vm_srb.srb_status); } if ((request->Status & 0xFF) == 0x02) { /* CHECK_CONDITION */ - if (VStorPacket->VmSrb.SrbStatus & 0x80) { + if (VStorPacket->vm_srb.srb_status & 0x80) { /* autosense data available */ DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data " "valid - len %d\n", RequestExt, - VStorPacket->VmSrb.SenseInfoLength); + VStorPacket->vm_srb.sense_info_length); - /* ASSERT(VStorPacket->VmSrb.SenseInfoLength <= */ + /* ASSERT(VStorPacket->vm_srb.sense_info_length <= */ /* request->SenseBufferSize); */ memcpy(request->SenseBuffer, - VStorPacket->VmSrb.SenseData, - VStorPacket->VmSrb.SenseInfoLength); + VStorPacket->vm_srb.sense_data, + VStorPacket->vm_srb.sense_info_length); request->SenseBufferSize = - VStorPacket->VmSrb.SenseInfoLength; + VStorPacket->vm_srb.sense_info_length; } } /* TODO: */ - request->BytesXfer = VStorPacket->VmSrb.DataTransferLength; + request->BytesXfer = VStorPacket->vm_srb.data_transfer_length; request->OnIOCompletion(request); @@ -411,19 +412,19 @@ static void StorVscOnReceive(struct hv_device *Device, struct vstor_packet *VStorPacket, struct storvsc_request_extension *RequestExt) { - switch (VStorPacket->Operation) { - case VStorOperationCompleteIo: + switch (VStorPacket->operation) { + case VSTOR_OPERATION_COMPLETE_IO: DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION"); StorVscOnIOCompletion(Device, VStorPacket, RequestExt); break; - case VStorOperationRemoveDevice: + case VSTOR_OPERATION_REMOVE_DEVICE: DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION"); /* TODO: */ break; default: DPRINT_INFO(STORVSC, "Unknown operation received - %d", - VStorPacket->Operation); + VStorPacket->operation); break; } } @@ -506,7 +507,7 @@ static int StorVscConnectToVsp(struct hv_device *Device) StorVscOnChannelCallback, Device); DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d", - props.PathId, props.TargetId, props.MaxTransferBytes); + props.path_id, props.target_id, props.max_transfer_bytes); if (ret != 0) { DPRINT_ERR(STORVSC, "unable to open channel: %d", ret); @@ -628,9 +629,9 @@ int StorVscOnHostReset(struct hv_device *Device) goto Cleanup; } - vstorPacket->Operation = VStorOperationResetBus; - vstorPacket->Flags = REQUEST_COMPLETION_FLAG; - vstorPacket->VmSrb.PathId = storDevice->PathId; + vstorPacket->operation = VSTOR_OPERATION_RESET_BUS; + vstorPacket->flags = REQUEST_COMPLETION_FLAG; + vstorPacket->vm_srb.path_id = storDevice->PathId; ret = vmbus_sendpacket(Device->channel, vstorPacket, sizeof(struct vstor_packet), @@ -697,35 +698,35 @@ static int StorVscOnIORequest(struct hv_device *Device, memset(vstorPacket, 0 , sizeof(struct vstor_packet)); - vstorPacket->Flags |= REQUEST_COMPLETION_FLAG; + vstorPacket->flags |= REQUEST_COMPLETION_FLAG; - vstorPacket->VmSrb.Length = sizeof(struct vmscsi_request); + vstorPacket->vm_srb.length = sizeof(struct vmscsi_request); - vstorPacket->VmSrb.PortNumber = Request->Host; - vstorPacket->VmSrb.PathId = Request->Bus; - vstorPacket->VmSrb.TargetId = Request->TargetId; - vstorPacket->VmSrb.Lun = Request->LunId; + vstorPacket->vm_srb.port_number = Request->Host; + vstorPacket->vm_srb.path_id = Request->Bus; + vstorPacket->vm_srb.target_id = Request->TargetId; + vstorPacket->vm_srb.lun = Request->LunId; - vstorPacket->VmSrb.SenseInfoLength = SENSE_BUFFER_SIZE; + vstorPacket->vm_srb.sense_info_length = SENSE_BUFFER_SIZE; /* Copy over the scsi command descriptor block */ - vstorPacket->VmSrb.CdbLength = Request->CdbLen; - memcpy(&vstorPacket->VmSrb.Cdb, Request->Cdb, Request->CdbLen); + vstorPacket->vm_srb.cdb_length = Request->CdbLen; + memcpy(&vstorPacket->vm_srb.cdb, Request->Cdb, Request->CdbLen); - vstorPacket->VmSrb.DataIn = Request->Type; - vstorPacket->VmSrb.DataTransferLength = Request->DataBuffer.Length; + vstorPacket->vm_srb.data_in = Request->Type; + vstorPacket->vm_srb.data_transfer_length = Request->DataBuffer.Length; - vstorPacket->Operation = VStorOperationExecuteSRB; + vstorPacket->operation = VSTOR_OPERATION_EXECUTE_SRB; DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, " "lun %d senselen %d cdblen %d", - vstorPacket->VmSrb.Length, - vstorPacket->VmSrb.PortNumber, - vstorPacket->VmSrb.PathId, - vstorPacket->VmSrb.TargetId, - vstorPacket->VmSrb.Lun, - vstorPacket->VmSrb.SenseInfoLength, - vstorPacket->VmSrb.CdbLength); + vstorPacket->vm_srb.length, + vstorPacket->vm_srb.port_number, + vstorPacket->vm_srb.path_id, + vstorPacket->vm_srb.target_id, + vstorPacket->vm_srb.lun, + vstorPacket->vm_srb.sense_info_length, + vstorPacket->vm_srb.cdb_length); if (requestExtension->Request->DataBuffer.Length) { ret = vmbus_sendpacket_multipagebuffer(Device->channel, diff --git a/drivers/staging/hv/vstorage.h b/drivers/staging/hv/vstorage.h index 4ea597d7a7d7..ae8be84394d5 100644 --- a/drivers/staging/hv/vstorage.h +++ b/drivers/staging/hv/vstorage.h @@ -27,15 +27,17 @@ #define REVISION_STRING(REVISION_) #REVISION_ #define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \ -{ \ - char *revisionString = REVISION_STRING($Revision : 6 $) + 11; \ - RESULT_LVALUE_ = 0; \ - while (*revisionString >= '0' && *revisionString <= '9') { \ - RESULT_LVALUE_ *= 10; \ - RESULT_LVALUE_ += *revisionString - '0'; \ - revisionString++; \ - } \ -} + do { \ + char *revision_string \ + = REVISION_STRING($Rev : 6 $) + 6; \ + RESULT_LVALUE_ = 0; \ + while (*revision_string >= '0' \ + && *revision_string <= '9') { \ + RESULT_LVALUE_ *= 10; \ + RESULT_LVALUE_ += *revision_string - '0'; \ + revision_string++; \ + } \ + } while (0) /* Major/minor macros. Minor version is in LSB, meaning that earlier flat */ /* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */ @@ -65,17 +67,17 @@ /* Packet structure describing virtual storage requests. */ enum vstor_packet_operation { - VStorOperationCompleteIo = 1, - VStorOperationRemoveDevice = 2, - VStorOperationExecuteSRB = 3, - VStorOperationResetLun = 4, - VStorOperationResetAdapter = 5, - VStorOperationResetBus = 6, - VStorOperationBeginInitialization = 7, - VStorOperationEndInitialization = 8, - VStorOperationQueryProtocolVersion = 9, - VStorOperationQueryProperties = 10, - VStorOperationMaximum = 10 + VSTOR_OPERATION_COMPLETE_IO = 1, + VSTOR_OPERATION_REMOVE_DEVICE = 2, + VSTOR_OPERATION_EXECUTE_SRB = 3, + VSTOR_OPERATION_RESET_LUN = 4, + VSTOR_OPERATION_RESET_ADAPTER = 5, + VSTOR_OPERATION_RESET_BUS = 6, + VSTOR_OPERATION_BEGIN_INITIALIZATION = 7, + VSTOR_OPERATION_END_INITIALIZATION = 8, + VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9, + VSTOR_OPERATION_QUERY_PROPERTIES = 10, + VSTOR_OPERATION_MAXIMUM = 10 }; /* @@ -89,31 +91,29 @@ enum vstor_packet_operation { #define SENSE_BUFFER_SIZE 0x12 #endif -#define MAX_DATA_BUFFER_LENGTH_WITH_PADDING 0x14 +#define MAX_DATA_BUF_LEN_WITH_PADDING 0x14 struct vmscsi_request { - unsigned short Length; - unsigned char SrbStatus; - unsigned char ScsiStatus; + unsigned short length; + unsigned char srb_status; + unsigned char scsi_status; - unsigned char PortNumber; - unsigned char PathId; - unsigned char TargetId; - unsigned char Lun; + unsigned char port_number; + unsigned char path_id; + unsigned char target_id; + unsigned char lun; - unsigned char CdbLength; - unsigned char SenseInfoLength; - unsigned char DataIn; - unsigned char Reserved; + unsigned char cdb_length; + unsigned char sense_info_length; + unsigned char data_in; + unsigned char reserved; - unsigned int DataTransferLength; + unsigned int data_transfer_length; union { - unsigned char Cdb[CDB16GENERIC_LENGTH]; - - unsigned char SenseData[SENSE_BUFFER_SIZE]; - - unsigned char ReservedArray[MAX_DATA_BUFFER_LENGTH_WITH_PADDING]; + unsigned char cdb[CDB16GENERIC_LENGTH]; + unsigned char sense_data[SENSE_BUFFER_SIZE]; + unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING]; }; } __attribute((packed)); @@ -123,24 +123,24 @@ struct vmscsi_request { * properties of the channel. */ struct vmstorage_channel_properties { - unsigned short ProtocolVersion; - unsigned char PathId; - unsigned char TargetId; + unsigned short protocol_version; + unsigned char path_id; + unsigned char target_id; /* Note: port number is only really known on the client side */ - unsigned int PortNumber; - unsigned int Flags; - unsigned int MaxTransferBytes; + unsigned int port_number; + unsigned int flags; + unsigned int max_transfer_bytes; /* This id is unique for each channel and will correspond with */ /* vendor specific data in the inquirydata */ - unsigned long long UniqueId; + unsigned long long unique_id; } __attribute__((packed)); /* This structure is sent during the storage protocol negotiations. */ struct vmstorage_protocol_version { /* Major (MSW) and minor (LSW) version numbers. */ - unsigned short MajorMinor; + unsigned short major_minor; /* * Revision number is auto-incremented whenever this file is changed @@ -148,7 +148,7 @@ struct vmstorage_protocol_version { * definitely indicate incompatibility--but it does indicate mismatched * builds. */ - unsigned short Revision; + unsigned short revision; } __attribute__((packed)); /* Channel Property Flags */ @@ -157,13 +157,13 @@ struct vmstorage_protocol_version { struct vstor_packet { /* Requested operation type */ - enum vstor_packet_operation Operation; + enum vstor_packet_operation operation; /* Flags - see below for values */ - unsigned int Flags; + unsigned int flags; /* Status of the request returned from the server side. */ - unsigned int Status; + unsigned int status; /* Data payload area */ union { @@ -171,13 +171,13 @@ struct vstor_packet { * Structure used to forward SCSI commands from the * client to the server. */ - struct vmscsi_request VmSrb; + struct vmscsi_request vm_srb; /* Structure used to query channel properties. */ - struct vmstorage_channel_properties StorageChannelProperties; + struct vmstorage_channel_properties storage_channel_properties; /* Used during version negotiations. */ - struct vmstorage_protocol_version Version; + struct vmstorage_protocol_version version; }; } __attribute__((packed)); -- cgit v1.2.3 From 8a046024a7cbbe9e4c16f4e34dda0f0dbcbc6723 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:45 -0800 Subject: staging: hv: Convert camel case struct fields in storvsc_api.h to lowercase Convert camel case struct fields in vstorage.h to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/blkvsc.c | 20 +++---- drivers/staging/hv/blkvsc_drv.c | 115 ++++++++++++++++++++------------------- drivers/staging/hv/storvsc.c | 67 ++++++++++++----------- drivers/staging/hv/storvsc_api.h | 50 ++++++++--------- drivers/staging/hv/storvsc_drv.c | 91 ++++++++++++++++--------------- 5 files changed, 175 insertions(+), 168 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c index d5b0abd771ab..9ac04c385b15 100644 --- a/drivers/staging/hv/blkvsc.c +++ b/drivers/staging/hv/blkvsc.c @@ -51,12 +51,12 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) * id. For IDE devices, the device instance id is formatted as * * - - 8899 - 000000000000. */ - deviceInfo->PathId = Device->deviceInstance.data[3] << 24 | + deviceInfo->path_id = Device->deviceInstance.data[3] << 24 | Device->deviceInstance.data[2] << 16 | Device->deviceInstance.data[1] << 8 | Device->deviceInstance.data[0]; - deviceInfo->TargetId = Device->deviceInstance.data[5] << 8 | + deviceInfo->target_id = Device->deviceInstance.data[5] << 8 | Device->deviceInstance.data[4]; return ret; @@ -75,7 +75,7 @@ int BlkVscInitialize(struct hv_driver *Driver) Driver->name = gBlkDriverName; memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(struct hv_guid)); - storDriver->RequestExtSize = sizeof(struct storvsc_request_extension); + storDriver->request_ext_size = sizeof(struct storvsc_request_extension); /* * Divide the ring buffer data size (which is 1 page less than the ring @@ -83,20 +83,20 @@ int BlkVscInitialize(struct hv_driver *Driver) * by the max request size (which is * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) */ - storDriver->MaxOutstandingRequestsPerChannel = - ((storDriver->RingBufferSize - PAGE_SIZE) / + storDriver->max_outstanding_req_per_channel = + ((storDriver->ring_buffer_size - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(struct vstor_packet) + sizeof(u64), sizeof(u64))); DPRINT_INFO(BLKVSC, "max io outstd %u", - storDriver->MaxOutstandingRequestsPerChannel); + storDriver->max_outstanding_req_per_channel); /* Setup the dispatch table */ - storDriver->Base.OnDeviceAdd = BlkVscOnDeviceAdd; - storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove; - storDriver->Base.OnCleanup = StorVscOnCleanup; - storDriver->OnIORequest = StorVscOnIORequest; + storDriver->base.OnDeviceAdd = BlkVscOnDeviceAdd; + storDriver->base.OnDeviceRemove = StorVscOnDeviceRemove; + storDriver->base.OnCleanup = StorVscOnCleanup; + storDriver->on_io_request = StorVscOnIORequest; return ret; } diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c index 3f81ca591064..d65d69e3ebc2 100644 --- a/drivers/staging/hv/blkvsc_drv.c +++ b/drivers/staging/hv/blkvsc_drv.c @@ -177,13 +177,13 @@ static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx; int ret; - storvsc_drv_obj->RingBufferSize = blkvsc_ringbuffer_size; + storvsc_drv_obj->ring_buffer_size = blkvsc_ringbuffer_size; /* Callback to client driver to complete the initialization */ - drv_init(&storvsc_drv_obj->Base); + drv_init(&storvsc_drv_obj->base); - drv_ctx->driver.name = storvsc_drv_obj->Base.name; - memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType, + drv_ctx->driver.name = storvsc_drv_obj->base.name; + memcpy(&drv_ctx->class_id, &storvsc_drv_obj->base.deviceType, sizeof(struct hv_guid)); drv_ctx->probe = blkvsc_probe; @@ -230,8 +230,8 @@ static void blkvsc_drv_exit(void) device_unregister(current_dev); } - if (storvsc_drv_obj->Base.OnCleanup) - storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base); + if (storvsc_drv_obj->base.OnCleanup) + storvsc_drv_obj->base.OnCleanup(&storvsc_drv_obj->base); vmbus_child_driver_unregister(drv_ctx); @@ -262,7 +262,7 @@ static int blkvsc_probe(struct device *device) DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter"); - if (!storvsc_drv_obj->Base.OnDeviceAdd) { + if (!storvsc_drv_obj->base.OnDeviceAdd) { DPRINT_ERR(BLKVSC_DRV, "OnDeviceAdd() not set"); ret = -1; goto Cleanup; @@ -284,7 +284,7 @@ static int blkvsc_probe(struct device *device) blkdev->request_pool = kmem_cache_create(dev_name(&device_ctx->device), sizeof(struct blkvsc_request) + - storvsc_drv_obj->RequestExtSize, 0, + storvsc_drv_obj->request_ext_size, 0, SLAB_HWCACHE_ALIGN, NULL); if (!blkdev->request_pool) { ret = -ENOMEM; @@ -293,7 +293,7 @@ static int blkvsc_probe(struct device *device) /* Call to the vsc driver to add the device */ - ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj, &device_info); + ret = storvsc_drv_obj->base.OnDeviceAdd(device_obj, &device_info); if (ret != 0) { DPRINT_ERR(BLKVSC_DRV, "unable to add blkvsc device"); goto Cleanup; @@ -301,9 +301,9 @@ static int blkvsc_probe(struct device *device) blkdev->device_ctx = device_ctx; /* this identified the device 0 or 1 */ - blkdev->target = device_info.TargetId; + blkdev->target = device_info.target_id; /* this identified the ide ctrl 0 or 1 */ - blkdev->path = device_info.PathId; + blkdev->path = device_info.path_id; dev_set_drvdata(device, blkdev); @@ -391,7 +391,7 @@ static int blkvsc_probe(struct device *device) return ret; Remove: - storvsc_drv_obj->Base.OnDeviceRemove(device_obj); + storvsc_drv_obj->base.OnDeviceRemove(device_obj); Cleanup: if (blkdev) { @@ -459,9 +459,9 @@ static int blkvsc_do_flush(struct block_device_context *blkdev) blkvsc_req->req = NULL; blkvsc_req->write = 0; - blkvsc_req->request.DataBuffer.PfnArray[0] = 0; - blkvsc_req->request.DataBuffer.Offset = 0; - blkvsc_req->request.DataBuffer.Length = 0; + blkvsc_req->request.data_buffer.PfnArray[0] = 0; + blkvsc_req->request.data_buffer.Offset = 0; + blkvsc_req->request.data_buffer.Length = 0; blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE; blkvsc_req->cmd_len = 10; @@ -506,9 +506,9 @@ static int blkvsc_do_inquiry(struct block_device_context *blkdev) blkvsc_req->req = NULL; blkvsc_req->write = 0; - blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf); - blkvsc_req->request.DataBuffer.Offset = 0; - blkvsc_req->request.DataBuffer.Length = 64; + blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf); + blkvsc_req->request.data_buffer.Offset = 0; + blkvsc_req->request.data_buffer.Length = 64; blkvsc_req->cmnd[0] = INQUIRY; blkvsc_req->cmnd[1] = 0x1; /* Get product data */ @@ -593,9 +593,9 @@ static int blkvsc_do_read_capacity(struct block_device_context *blkdev) blkvsc_req->req = NULL; blkvsc_req->write = 0; - blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf); - blkvsc_req->request.DataBuffer.Offset = 0; - blkvsc_req->request.DataBuffer.Length = 8; + blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf); + blkvsc_req->request.data_buffer.Offset = 0; + blkvsc_req->request.data_buffer.Length = 8; blkvsc_req->cmnd[0] = READ_CAPACITY; blkvsc_req->cmd_len = 16; @@ -614,7 +614,7 @@ static int blkvsc_do_read_capacity(struct block_device_context *blkdev) wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond); /* check error */ - if (blkvsc_req->request.Status) { + if (blkvsc_req->request.status) { scsi_normalize_sense(blkvsc_req->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr); @@ -670,9 +670,9 @@ static int blkvsc_do_read_capacity16(struct block_device_context *blkdev) blkvsc_req->req = NULL; blkvsc_req->write = 0; - blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf); - blkvsc_req->request.DataBuffer.Offset = 0; - blkvsc_req->request.DataBuffer.Length = 12; + blkvsc_req->request.data_buffer.PfnArray[0] = page_to_pfn(page_buf); + blkvsc_req->request.data_buffer.Offset = 0; + blkvsc_req->request.data_buffer.Length = 12; blkvsc_req->cmnd[0] = 0x9E; /* READ_CAPACITY16; */ blkvsc_req->cmd_len = 16; @@ -691,7 +691,7 @@ static int blkvsc_do_read_capacity16(struct block_device_context *blkdev) wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond); /* check error */ - if (blkvsc_req->request.Status) { + if (blkvsc_req->request.status) { scsi_normalize_sense(blkvsc_req->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (sense_hdr.asc == 0x3A) { @@ -741,14 +741,14 @@ static int blkvsc_remove(struct device *device) DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n"); - if (!storvsc_drv_obj->Base.OnDeviceRemove) + if (!storvsc_drv_obj->base.OnDeviceRemove) return -1; /* * Call to the vsc driver to let it know that the device is being * removed */ - ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj); + ret = storvsc_drv_obj->base.OnDeviceRemove(device_obj); if (ret != 0) { /* TODO: */ DPRINT_ERR(BLKVSC_DRV, @@ -865,38 +865,38 @@ static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req, (blkvsc_req->write) ? "WRITE" : "READ", (unsigned long) blkvsc_req->sector_start, blkvsc_req->sector_count, - blkvsc_req->request.DataBuffer.Offset, - blkvsc_req->request.DataBuffer.Length); + blkvsc_req->request.data_buffer.Offset, + blkvsc_req->request.data_buffer.Length); #if 0 - for (i = 0; i < (blkvsc_req->request.DataBuffer.Length >> 12); i++) { + for (i = 0; i < (blkvsc_req->request.data_buffer.Length >> 12); i++) { DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - " "req %p pfn[%d] %llx\n", blkvsc_req, i, - blkvsc_req->request.DataBuffer.PfnArray[i]); + blkvsc_req->request.data_buffer.PfnArray[i]); } #endif storvsc_req = &blkvsc_req->request; - storvsc_req->Extension = (void *)((unsigned long)blkvsc_req + + storvsc_req->extension = (void *)((unsigned long)blkvsc_req + sizeof(struct blkvsc_request)); - storvsc_req->Type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE; + storvsc_req->type = blkvsc_req->write ? WRITE_TYPE : READ_TYPE; - storvsc_req->OnIOCompletion = request_completion; - storvsc_req->Context = blkvsc_req; + storvsc_req->on_io_completion = request_completion; + storvsc_req->context = blkvsc_req; - storvsc_req->Host = blkdev->port; - storvsc_req->Bus = blkdev->path; - storvsc_req->TargetId = blkdev->target; - storvsc_req->LunId = 0; /* this is not really used at all */ + storvsc_req->host = blkdev->port; + storvsc_req->bus = blkdev->path; + storvsc_req->target_id = blkdev->target; + storvsc_req->lun_id = 0; /* this is not really used at all */ - storvsc_req->CdbLen = blkvsc_req->cmd_len; - storvsc_req->Cdb = blkvsc_req->cmnd; + storvsc_req->cdb_len = blkvsc_req->cmd_len; + storvsc_req->cdb = blkvsc_req->cmnd; - storvsc_req->SenseBuffer = blkvsc_req->sense_buffer; - storvsc_req->SenseBufferSize = SCSI_SENSE_BUFFERSIZE; + storvsc_req->sense_buffer = blkvsc_req->sense_buffer; + storvsc_req->sense_buffer_size = SCSI_SENSE_BUFFERSIZE; - ret = storvsc_drv_obj->OnIORequest(&blkdev->device_ctx->device_obj, + ret = storvsc_drv_obj->on_io_request(&blkdev->device_ctx->device_obj, &blkvsc_req->request); if (ret == 0) blkdev->num_outstanding_reqs++; @@ -992,8 +992,10 @@ static int blkvsc_do_request(struct block_device_context *blkdev, blkvsc_req->dev = blkdev; blkvsc_req->req = req; - blkvsc_req->request.DataBuffer.Offset = bvec->bv_offset; - blkvsc_req->request.DataBuffer.Length = 0; + blkvsc_req->request.data_buffer.Offset + = bvec->bv_offset; + blkvsc_req->request.data_buffer.Length + = 0; /* Add to the group */ blkvsc_req->group = group; @@ -1007,8 +1009,11 @@ static int blkvsc_do_request(struct block_device_context *blkdev, } /* Add the curr bvec/segment to the curr blkvsc_req */ - blkvsc_req->request.DataBuffer.PfnArray[databuf_idx] = page_to_pfn(bvec->bv_page); - blkvsc_req->request.DataBuffer.Length += bvec->bv_len; + blkvsc_req->request.data_buffer. + PfnArray[databuf_idx] + = page_to_pfn(bvec->bv_page); + blkvsc_req->request.data_buffer.Length + += bvec->bv_len; prev_bvec = bvec; @@ -1073,7 +1078,7 @@ static int blkvsc_do_request(struct block_device_context *blkdev, static void blkvsc_cmd_completion(struct hv_storvsc_request *request) { struct blkvsc_request *blkvsc_req = - (struct blkvsc_request *)request->Context; + (struct blkvsc_request *)request->context; struct block_device_context *blkdev = (struct block_device_context *)blkvsc_req->dev; struct scsi_sense_hdr sense_hdr; @@ -1083,7 +1088,7 @@ static void blkvsc_cmd_completion(struct hv_storvsc_request *request) blkdev->num_outstanding_reqs--; - if (blkvsc_req->request.Status) + if (blkvsc_req->request.status) if (scsi_normalize_sense(blkvsc_req->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr)) scsi_print_sense_hdr("blkvsc", &sense_hdr); @@ -1095,7 +1100,7 @@ static void blkvsc_cmd_completion(struct hv_storvsc_request *request) static void blkvsc_request_completion(struct hv_storvsc_request *request) { struct blkvsc_request *blkvsc_req = - (struct blkvsc_request *)request->Context; + (struct blkvsc_request *)request->context; struct block_device_context *blkdev = (struct block_device_context *)blkvsc_req->dev; unsigned long flags; @@ -1110,7 +1115,7 @@ static void blkvsc_request_completion(struct hv_storvsc_request *request) (blkvsc_req->write) ? "WRITE" : "READ", (unsigned long)blkvsc_req->sector_start, blkvsc_req->sector_count, - blkvsc_req->request.DataBuffer.Length, + blkvsc_req->request.data_buffer.Length, blkvsc_req->group->outstanding, blkdev->num_outstanding_reqs); @@ -1137,7 +1142,7 @@ static void blkvsc_request_completion(struct hv_storvsc_request *request) list_del(&comp_req->req_entry); if (!__blk_end_request(comp_req->req, - (!comp_req->request.Status ? 0 : -EIO), + (!comp_req->request.status ? 0 : -EIO), comp_req->sector_count * blkdev->sector_size)) { /* * All the sectors have been xferred ie the @@ -1195,7 +1200,7 @@ static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev) if (comp_req->req) { ret = __blk_end_request(comp_req->req, - (!comp_req->request.Status ? 0 : -EIO), + (!comp_req->request.status ? 0 : -EIO), comp_req->sector_count * blkdev->sector_size); diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 96b4ed986118..c4346c63ed56 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -370,16 +370,16 @@ static void StorVscOnIOCompletion(struct hv_device *Device, /* ASSERT(request->OnIOCompletion != NULL); */ /* Copy over the status...etc */ - request->Status = VStorPacket->vm_srb.scsi_status; + request->status = VStorPacket->vm_srb.scsi_status; - if (request->Status != 0 || VStorPacket->vm_srb.srb_status != 1) { + if (request->status != 0 || VStorPacket->vm_srb.srb_status != 1) { DPRINT_WARN(STORVSC, "cmd 0x%x scsi status 0x%x srb status 0x%x\n", - request->Cdb[0], VStorPacket->vm_srb.scsi_status, + request->cdb[0], VStorPacket->vm_srb.scsi_status, VStorPacket->vm_srb.srb_status); } - if ((request->Status & 0xFF) == 0x02) { + if ((request->status & 0xFF) == 0x02) { /* CHECK_CONDITION */ if (VStorPacket->vm_srb.srb_status & 0x80) { /* autosense data available */ @@ -389,19 +389,19 @@ static void StorVscOnIOCompletion(struct hv_device *Device, /* ASSERT(VStorPacket->vm_srb.sense_info_length <= */ /* request->SenseBufferSize); */ - memcpy(request->SenseBuffer, + memcpy(request->sense_buffer, VStorPacket->vm_srb.sense_data, VStorPacket->vm_srb.sense_info_length); - request->SenseBufferSize = + request->sense_buffer_size = VStorPacket->vm_srb.sense_info_length; } } /* TODO: */ - request->BytesXfer = VStorPacket->vm_srb.data_transfer_length; + request->bytes_xfer = VStorPacket->vm_srb.data_transfer_length; - request->OnIOCompletion(request); + request->on_io_completion(request); atomic_dec(&storDevice->NumOutstandingRequests); @@ -501,7 +501,8 @@ static int StorVscConnectToVsp(struct hv_device *Device) /* Open the channel */ ret = vmbus_open(Device->channel, - storDriver->RingBufferSize, storDriver->RingBufferSize, + storDriver->ring_buffer_size, + storDriver->ring_buffer_size, (void *)&props, sizeof(struct vmstorage_channel_properties), StorVscOnChannelCallback, Device); @@ -551,13 +552,13 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) storChannel->PathId = props->PathId; storChannel->TargetId = props->TargetId; */ - storDevice->PortNumber = deviceInfo->PortNumber; + storDevice->PortNumber = deviceInfo->port_number; /* Send it back up */ ret = StorVscConnectToVsp(Device); /* deviceInfo->PortNumber = storDevice->PortNumber; */ - deviceInfo->PathId = storDevice->PathId; - deviceInfo->TargetId = storDevice->TargetId; + deviceInfo->path_id = storDevice->PathId; + deviceInfo->target_id = storDevice->TargetId; DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n", storDevice->PortNumber, storDevice->PathId, @@ -672,7 +673,7 @@ static int StorVscOnIORequest(struct hv_device *Device, int ret = 0; requestExtension = - (struct storvsc_request_extension *)Request->Extension; + (struct storvsc_request_extension *)Request->extension; vstorPacket = &requestExtension->VStorPacket; storDevice = GetStorDevice(Device); @@ -681,8 +682,8 @@ static int StorVscOnIORequest(struct hv_device *Device, requestExtension); DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d", - Request, Request->DataBuffer.Length, Request->Bus, - Request->TargetId, Request->LunId, Request->CdbLen); + Request, Request->data_buffer.Length, Request->bus, + Request->target_id, Request->lun_id, Request->cdb_len); if (!storDevice) { DPRINT_ERR(STORVSC, "unable to get stor device..." @@ -702,19 +703,19 @@ static int StorVscOnIORequest(struct hv_device *Device, vstorPacket->vm_srb.length = sizeof(struct vmscsi_request); - vstorPacket->vm_srb.port_number = Request->Host; - vstorPacket->vm_srb.path_id = Request->Bus; - vstorPacket->vm_srb.target_id = Request->TargetId; - vstorPacket->vm_srb.lun = Request->LunId; + vstorPacket->vm_srb.port_number = Request->host; + vstorPacket->vm_srb.path_id = Request->bus; + vstorPacket->vm_srb.target_id = Request->target_id; + vstorPacket->vm_srb.lun = Request->lun_id; vstorPacket->vm_srb.sense_info_length = SENSE_BUFFER_SIZE; /* Copy over the scsi command descriptor block */ - vstorPacket->vm_srb.cdb_length = Request->CdbLen; - memcpy(&vstorPacket->vm_srb.cdb, Request->Cdb, Request->CdbLen); + vstorPacket->vm_srb.cdb_length = Request->cdb_len; + memcpy(&vstorPacket->vm_srb.cdb, Request->cdb, Request->cdb_len); - vstorPacket->vm_srb.data_in = Request->Type; - vstorPacket->vm_srb.data_transfer_length = Request->DataBuffer.Length; + vstorPacket->vm_srb.data_in = Request->type; + vstorPacket->vm_srb.data_transfer_length = Request->data_buffer.Length; vstorPacket->operation = VSTOR_OPERATION_EXECUTE_SRB; @@ -728,9 +729,9 @@ static int StorVscOnIORequest(struct hv_device *Device, vstorPacket->vm_srb.sense_info_length, vstorPacket->vm_srb.cdb_length); - if (requestExtension->Request->DataBuffer.Length) { + if (requestExtension->Request->data_buffer.Length) { ret = vmbus_sendpacket_multipagebuffer(Device->channel, - &requestExtension->Request->DataBuffer, + &requestExtension->Request->data_buffer, vstorPacket, sizeof(struct vstor_packet), (unsigned long)requestExtension); @@ -785,7 +786,7 @@ int StorVscInitialize(struct hv_driver *Driver) memcpy(&Driver->deviceType, &gStorVscDeviceType, sizeof(struct hv_guid)); - storDriver->RequestExtSize = sizeof(struct storvsc_request_extension); + storDriver->request_ext_size = sizeof(struct storvsc_request_extension); /* * Divide the ring buffer data size (which is 1 page less @@ -793,22 +794,22 @@ int StorVscInitialize(struct hv_driver *Driver) * the ring buffer indices) by the max request size (which is * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) */ - storDriver->MaxOutstandingRequestsPerChannel = - ((storDriver->RingBufferSize - PAGE_SIZE) / + storDriver->max_outstanding_req_per_channel = + ((storDriver->ring_buffer_size - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(struct vstor_packet) + sizeof(u64), sizeof(u64))); DPRINT_INFO(STORVSC, "max io %u, currently %u\n", - storDriver->MaxOutstandingRequestsPerChannel, + storDriver->max_outstanding_req_per_channel, STORVSC_MAX_IO_REQUESTS); /* Setup the dispatch table */ - storDriver->Base.OnDeviceAdd = StorVscOnDeviceAdd; - storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove; - storDriver->Base.OnCleanup = StorVscOnCleanup; + storDriver->base.OnDeviceAdd = StorVscOnDeviceAdd; + storDriver->base.OnDeviceRemove = StorVscOnDeviceRemove; + storDriver->base.OnCleanup = StorVscOnCleanup; - storDriver->OnIORequest = StorVscOnIORequest; + storDriver->on_io_request = StorVscOnIORequest; return 0; } diff --git a/drivers/staging/hv/storvsc_api.h b/drivers/staging/hv/storvsc_api.h index 8505a1c5f9ee..46f031e0afc6 100644 --- a/drivers/staging/hv/storvsc_api.h +++ b/drivers/staging/hv/storvsc_api.h @@ -53,58 +53,58 @@ enum storvsc_request_type{ }; struct hv_storvsc_request { - enum storvsc_request_type Type; - u32 Host; - u32 Bus; - u32 TargetId; - u32 LunId; - u8 *Cdb; - u32 CdbLen; - u32 Status; - u32 BytesXfer; + enum storvsc_request_type type; + u32 host; + u32 bus; + u32 target_id; + u32 lun_id; + u8 *cdb; + u32 cdb_len; + u32 status; + u32 bytes_xfer; - unsigned char *SenseBuffer; - u32 SenseBufferSize; + unsigned char *sense_buffer; + u32 sense_buffer_size; - void *Context; + void *context; - void (*OnIOCompletion)(struct hv_storvsc_request *Request); + void (*on_io_completion)(struct hv_storvsc_request *request); /* This points to the memory after DataBuffer */ - void *Extension; + void *extension; - struct hv_multipage_buffer DataBuffer; + struct hv_multipage_buffer data_buffer; }; /* Represents the block vsc driver */ struct storvsc_driver_object { /* Must be the first field */ /* Which is a bug FIXME! */ - struct hv_driver Base; + struct hv_driver base; /* Set by caller (in bytes) */ - u32 RingBufferSize; + u32 ring_buffer_size; /* Allocate this much private extension for each I/O request */ - u32 RequestExtSize; + u32 request_ext_size; /* Maximum # of requests in flight per channel/device */ - u32 MaxOutstandingRequestsPerChannel; + u32 max_outstanding_req_per_channel; /* Specific to this driver */ - int (*OnIORequest)(struct hv_device *Device, - struct hv_storvsc_request *Request); + int (*on_io_request)(struct hv_device *device, + struct hv_storvsc_request *request); }; struct storvsc_device_info { - unsigned int PortNumber; - unsigned char PathId; - unsigned char TargetId; + unsigned int port_number; + unsigned char path_id; + unsigned char target_id; }; /* Interface */ int StorVscInitialize(struct hv_driver *driver); -int StorVscOnHostReset(struct hv_device *Device); +int StorVscOnHostReset(struct hv_device *device); int BlkVscInitialize(struct hv_driver *driver); #endif /* _STORVSC_API_H_ */ diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index 41d9acf4cd61..68a8853fa9ca 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -141,28 +141,28 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv.drv_obj; struct driver_context *drv_ctx = &g_storvsc_drv.drv_ctx; - storvsc_drv_obj->RingBufferSize = storvsc_ringbuffer_size; + storvsc_drv_obj->ring_buffer_size = storvsc_ringbuffer_size; /* Callback to client driver to complete the initialization */ - drv_init(&storvsc_drv_obj->Base); + drv_init(&storvsc_drv_obj->base); DPRINT_INFO(STORVSC_DRV, "request extension size %u, max outstanding reqs %u", - storvsc_drv_obj->RequestExtSize, - storvsc_drv_obj->MaxOutstandingRequestsPerChannel); + storvsc_drv_obj->request_ext_size, + storvsc_drv_obj->max_outstanding_req_per_channel); - if (storvsc_drv_obj->MaxOutstandingRequestsPerChannel < + if (storvsc_drv_obj->max_outstanding_req_per_channel < STORVSC_MAX_IO_REQUESTS) { DPRINT_ERR(STORVSC_DRV, "The number of outstanding io requests (%d) " "is larger than that supported (%d) internally.", STORVSC_MAX_IO_REQUESTS, - storvsc_drv_obj->MaxOutstandingRequestsPerChannel); + storvsc_drv_obj->max_outstanding_req_per_channel); return -1; } - drv_ctx->driver.name = storvsc_drv_obj->Base.name; - memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType, + drv_ctx->driver.name = storvsc_drv_obj->base.name; + memcpy(&drv_ctx->class_id, &storvsc_drv_obj->base.deviceType, sizeof(struct hv_guid)); drv_ctx->probe = storvsc_probe; @@ -207,8 +207,8 @@ static void storvsc_drv_exit(void) device_unregister(current_dev); } - if (storvsc_drv_obj->Base.OnCleanup) - storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base); + if (storvsc_drv_obj->base.OnCleanup) + storvsc_drv_obj->base.OnCleanup(&storvsc_drv_obj->base); vmbus_child_driver_unregister(drv_ctx); return; @@ -232,7 +232,7 @@ static int storvsc_probe(struct device *device) struct host_device_context *host_device_ctx; struct storvsc_device_info device_info; - if (!storvsc_drv_obj->Base.OnDeviceAdd) + if (!storvsc_drv_obj->base.OnDeviceAdd) return -1; host = scsi_host_alloc(&scsi_driver, @@ -253,7 +253,7 @@ static int storvsc_probe(struct device *device) host_device_ctx->request_pool = kmem_cache_create(dev_name(&device_ctx->device), sizeof(struct storvsc_cmd_request) + - storvsc_drv_obj->RequestExtSize, 0, + storvsc_drv_obj->request_ext_size, 0, SLAB_HWCACHE_ALIGN, NULL); if (!host_device_ctx->request_pool) { @@ -261,9 +261,9 @@ static int storvsc_probe(struct device *device) return -ENOMEM; } - device_info.PortNumber = host->host_no; + device_info.port_number = host->host_no; /* Call to the vsc driver to add the device */ - ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj, + ret = storvsc_drv_obj->base.OnDeviceAdd(device_obj, (void *)&device_info); if (ret != 0) { DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device"); @@ -273,8 +273,8 @@ static int storvsc_probe(struct device *device) } /* host_device_ctx->port = device_info.PortNumber; */ - host_device_ctx->path = device_info.PathId; - host_device_ctx->target = device_info.TargetId; + host_device_ctx->path = device_info.path_id; + host_device_ctx->target = device_info.target_id; /* max # of devices per target */ host->max_lun = STORVSC_MAX_LUNS_PER_TARGET; @@ -288,7 +288,7 @@ static int storvsc_probe(struct device *device) if (ret != 0) { DPRINT_ERR(STORVSC_DRV, "unable to add scsi host device"); - storvsc_drv_obj->Base.OnDeviceRemove(device_obj); + storvsc_drv_obj->base.OnDeviceRemove(device_obj); kmem_cache_destroy(host_device_ctx->request_pool); scsi_host_put(host); @@ -318,14 +318,14 @@ static int storvsc_remove(struct device *device) (struct host_device_context *)host->hostdata; - if (!storvsc_drv_obj->Base.OnDeviceRemove) + if (!storvsc_drv_obj->base.OnDeviceRemove) return -1; /* * Call to the vsc driver to let it know that the device is being * removed */ - ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj); + ret = storvsc_drv_obj->base.OnDeviceRemove(device_obj); if (ret != 0) { /* TODO: */ DPRINT_ERR(STORVSC, "unable to remove vsc device (ret %d)", @@ -351,7 +351,7 @@ static int storvsc_remove(struct device *device) static void storvsc_commmand_completion(struct hv_storvsc_request *request) { struct storvsc_cmd_request *cmd_request = - (struct storvsc_cmd_request *)request->Context; + (struct storvsc_cmd_request *)request->context; struct scsi_cmnd *scmnd = cmd_request->cmd; struct host_device_context *host_device_ctx = (struct host_device_context *)scmnd->device->host->hostdata; @@ -376,16 +376,17 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request) cmd_request->bounce_sgl_count); } - scmnd->result = request->Status; + scmnd->result = request->status; if (scmnd->result) { if (scsi_normalize_sense(scmnd->sense_buffer, - request->SenseBufferSize, &sense_hdr)) + request->sense_buffer_size, &sense_hdr)) scsi_print_sense_hdr("storvsc", &sense_hdr); } - /* ASSERT(request->BytesXfer <= request->DataBuffer.Length); */ - scsi_set_resid(scmnd, request->DataBuffer.Length - request->BytesXfer); + /* ASSERT(request->BytesXfer <= request->data_buffer.Length); */ + scsi_set_resid(scmnd, + request->data_buffer.Length - request->bytes_xfer); scsi_done_fn = scmnd->scsi_done; @@ -658,42 +659,42 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd, request = &cmd_request->request; - request->Extension = + request->extension = (void *)((unsigned long)cmd_request + request_size); DPRINT_DBG(STORVSC_DRV, "req %p size %d ext %d", request, request_size, - storvsc_drv_obj->RequestExtSize); + storvsc_drv_obj->request_ext_size); /* Build the SRB */ switch (scmnd->sc_data_direction) { case DMA_TO_DEVICE: - request->Type = WRITE_TYPE; + request->type = WRITE_TYPE; break; case DMA_FROM_DEVICE: - request->Type = READ_TYPE; + request->type = READ_TYPE; break; default: - request->Type = UNKNOWN_TYPE; + request->type = UNKNOWN_TYPE; break; } - request->OnIOCompletion = storvsc_commmand_completion; - request->Context = cmd_request;/* scmnd; */ + request->on_io_completion = storvsc_commmand_completion; + request->context = cmd_request;/* scmnd; */ /* request->PortId = scmnd->device->channel; */ - request->Host = host_device_ctx->port; - request->Bus = scmnd->device->channel; - request->TargetId = scmnd->device->id; - request->LunId = scmnd->device->lun; + request->host = host_device_ctx->port; + request->bus = scmnd->device->channel; + request->target_id = scmnd->device->id; + request->lun_id = scmnd->device->lun; /* ASSERT(scmnd->cmd_len <= 16); */ - request->CdbLen = scmnd->cmd_len; - request->Cdb = scmnd->cmnd; + request->cdb_len = scmnd->cmd_len; + request->cdb = scmnd->cmnd; - request->SenseBuffer = scmnd->sense_buffer; - request->SenseBufferSize = SCSI_SENSE_BUFFERSIZE; + request->sense_buffer = scmnd->sense_buffer; + request->sense_buffer_size = SCSI_SENSE_BUFFERSIZE; - request->DataBuffer.Length = scsi_bufflen(scmnd); + request->data_buffer.Length = scsi_bufflen(scmnd); if (scsi_sg_count(scmnd)) { sgl = (struct scatterlist *)scsi_sglist(scmnd); sg_count = scsi_sg_count(scmnd); @@ -734,25 +735,25 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd, sg_count = cmd_request->bounce_sgl_count; } - request->DataBuffer.Offset = sgl[0].offset; + request->data_buffer.Offset = sgl[0].offset; for (i = 0; i < sg_count; i++) { DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n", i, sgl[i].length, sgl[i].offset); - request->DataBuffer.PfnArray[i] = + request->data_buffer.PfnArray[i] = page_to_pfn(sg_page((&sgl[i]))); } } else if (scsi_sglist(scmnd)) { /* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */ - request->DataBuffer.Offset = + request->data_buffer.Offset = virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1); - request->DataBuffer.PfnArray[0] = + request->data_buffer.PfnArray[0] = virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; } retry_request: /* Invokes the vsc to start an IO */ - ret = storvsc_drv_obj->OnIORequest(&device_ctx->device_obj, + ret = storvsc_drv_obj->on_io_request(&device_ctx->device_obj, &cmd_request->request); if (ret == -1) { /* no more space */ -- cgit v1.2.3 From eb4f3e0aa6bef825b964159923e38a0e4c027084 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:46 -0800 Subject: staging: hv: Convert camel case functions in storvsc_api.h to lowercase Convert camel case functions in storvsc_api.h to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/blkvsc.c | 2 +- drivers/staging/hv/blkvsc_drv.c | 2 +- drivers/staging/hv/storvsc.c | 6 +++--- drivers/staging/hv/storvsc_api.h | 6 +++--- drivers/staging/hv/storvsc_drv.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c index 9ac04c385b15..e62c922f11cb 100644 --- a/drivers/staging/hv/blkvsc.c +++ b/drivers/staging/hv/blkvsc.c @@ -62,7 +62,7 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) return ret; } -int BlkVscInitialize(struct hv_driver *Driver) +int blk_vsc_initialize(struct hv_driver *Driver) { struct storvsc_driver_object *storDriver; int ret = 0; diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c index d65d69e3ebc2..b3d05fcfe6d2 100644 --- a/drivers/staging/hv/blkvsc_drv.c +++ b/drivers/staging/hv/blkvsc_drv.c @@ -1487,7 +1487,7 @@ static int __init blkvsc_init(void) DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing...."); - ret = blkvsc_drv_init(BlkVscInitialize); + ret = blkvsc_drv_init(blk_vsc_initialize); return ret; } diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index c4346c63ed56..770413183306 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -605,7 +605,7 @@ static int StorVscOnDeviceRemove(struct hv_device *Device) return 0; } -int StorVscOnHostReset(struct hv_device *Device) +int stor_vsc_on_host_reset(struct hv_device *Device) { struct storvsc_device *storDevice; struct storvsc_request_extension *request; @@ -762,9 +762,9 @@ static void StorVscOnCleanup(struct hv_driver *Driver) } /* - * StorVscInitialize - Main entry point + * stor_vsc_initialize - Main entry point */ -int StorVscInitialize(struct hv_driver *Driver) +int stor_vsc_initialize(struct hv_driver *Driver) { struct storvsc_driver_object *storDriver; diff --git a/drivers/staging/hv/storvsc_api.h b/drivers/staging/hv/storvsc_api.h index 46f031e0afc6..fbf57556d890 100644 --- a/drivers/staging/hv/storvsc_api.h +++ b/drivers/staging/hv/storvsc_api.h @@ -103,8 +103,8 @@ struct storvsc_device_info { }; /* Interface */ -int StorVscInitialize(struct hv_driver *driver); -int StorVscOnHostReset(struct hv_device *device); -int BlkVscInitialize(struct hv_driver *driver); +int stor_vsc_initialize(struct hv_driver *driver); +int stor_vsc_on_host_reset(struct hv_device *device); +int blk_vsc_initialize(struct hv_driver *driver); #endif /* _STORVSC_API_H_ */ diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index 68a8853fa9ca..b8c5cdde324a 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -844,7 +844,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) scmnd->device, &device_ctx->device_obj); /* Invokes the vsc to reset the host/bus */ - ret = StorVscOnHostReset(&device_ctx->device_obj); + ret = stor_vsc_on_host_reset(&device_ctx->device_obj); if (ret != 0) return ret; @@ -939,7 +939,7 @@ static int __init storvsc_init(void) int ret; DPRINT_INFO(STORVSC_DRV, "Storvsc initializing...."); - ret = storvsc_drv_init(StorVscInitialize); + ret = storvsc_drv_init(stor_vsc_initialize); return ret; } -- cgit v1.2.3 From 3d8cdf22b314f84cc4ae85ed650ccd37150a7562 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:47 -0800 Subject: staging: hv: Convert camel case struct fields in storvsc.c to lowercase Convert camel cased struct fields in storvsc.c to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/storvsc.c | 133 ++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 770413183306..3b6e63aa4554 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -34,43 +34,43 @@ struct storvsc_request_extension { /* LIST_ENTRY ListEntry; */ - struct hv_storvsc_request *Request; - struct hv_device *Device; + struct hv_storvsc_request *request; + struct hv_device *device; /* Synchronize the request/response if needed */ - struct osd_waitevent *WaitEvent; + struct osd_waitevent *wait_event; - struct vstor_packet VStorPacket; + struct vstor_packet vstor_packet; }; /* A storvsc device is a device object that contains a vmbus channel */ struct storvsc_device { - struct hv_device *Device; + struct hv_device *device; /* 0 indicates the device is being destroyed */ - atomic_t RefCount; + atomic_t ref_count; - atomic_t NumOutstandingRequests; + atomic_t num_outstanding_requests; /* * Each unique Port/Path/Target represents 1 channel ie scsi * controller. In reality, the pathid, targetid is always 0 * and the port is set by us */ - unsigned int PortNumber; - unsigned char PathId; - unsigned char TargetId; + unsigned int port_number; + unsigned char path_id; + unsigned char target_id; /* LIST_ENTRY OutstandingRequestList; */ /* HANDLE OutstandingRequestLock; */ /* Used for vsc/vsp channel reset process */ - struct storvsc_request_extension InitRequest; - struct storvsc_request_extension ResetRequest; + struct storvsc_request_extension init_request; + struct storvsc_request_extension reset_request; }; -static const char *gDriverName = "storvsc"; +static const char *g_driver_name = "storvsc"; /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ static const struct hv_guid gStorVscDeviceType = { @@ -90,10 +90,10 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device) return NULL; /* Set to 2 to allow both inbound and outbound traffics */ - /* (ie GetStorDevice() and MustGetStorDevice()) to proceed. */ - atomic_cmpxchg(&storDevice->RefCount, 0, 2); + /* (ie get_stor_device() and must_get_stor_device()) to proceed. */ + atomic_cmpxchg(&storDevice->ref_count, 0, 2); - storDevice->Device = Device; + storDevice->device = Device; Device->Extension = storDevice; return storDevice; @@ -101,7 +101,7 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device) static inline void FreeStorDevice(struct storvsc_device *Device) { - /* ASSERT(atomic_read(&Device->RefCount) == 0); */ + /* ASSERT(atomic_read(&Device->ref_count) == 0); */ kfree(Device); } @@ -111,8 +111,8 @@ static inline struct storvsc_device *GetStorDevice(struct hv_device *Device) struct storvsc_device *storDevice; storDevice = (struct storvsc_device *)Device->Extension; - if (storDevice && atomic_read(&storDevice->RefCount) > 1) - atomic_inc(&storDevice->RefCount); + if (storDevice && atomic_read(&storDevice->ref_count) > 1) + atomic_inc(&storDevice->ref_count); else storDevice = NULL; @@ -125,8 +125,8 @@ static inline struct storvsc_device *MustGetStorDevice(struct hv_device *Device) struct storvsc_device *storDevice; storDevice = (struct storvsc_device *)Device->Extension; - if (storDevice && atomic_read(&storDevice->RefCount)) - atomic_inc(&storDevice->RefCount); + if (storDevice && atomic_read(&storDevice->ref_count)) + atomic_inc(&storDevice->ref_count); else storDevice = NULL; @@ -140,8 +140,8 @@ static inline void PutStorDevice(struct hv_device *Device) storDevice = (struct storvsc_device *)Device->Extension; /* ASSERT(storDevice); */ - atomic_dec(&storDevice->RefCount); - /* ASSERT(atomic_read(&storDevice->RefCount)); */ + atomic_dec(&storDevice->ref_count); + /* ASSERT(atomic_read(&storDevice->ref_count)); */ } /* Drop ref count to 1 to effectively disable GetStorDevice() */ @@ -153,7 +153,7 @@ static inline struct storvsc_device *ReleaseStorDevice(struct hv_device *Device) /* ASSERT(storDevice); */ /* Busy wait until the ref drop to 2, then set it to 1 */ - while (atomic_cmpxchg(&storDevice->RefCount, 2, 1) != 2) + while (atomic_cmpxchg(&storDevice->ref_count, 2, 1) != 2) udelay(100); return storDevice; @@ -169,7 +169,7 @@ static inline struct storvsc_device *FinalReleaseStorDevice( /* ASSERT(storDevice); */ /* Busy wait until the ref drop to 1, then set it to 0 */ - while (atomic_cmpxchg(&storDevice->RefCount, 1, 0) != 1) + while (atomic_cmpxchg(&storDevice->ref_count, 1, 0) != 1) udelay(100); Device->Extension = NULL; @@ -190,16 +190,16 @@ static int StorVscChannelInit(struct hv_device *Device) return -1; } - request = &storDevice->InitRequest; - vstorPacket = &request->VStorPacket; + request = &storDevice->init_request; + vstorPacket = &request->vstor_packet; /* * Now, initiate the vsc/vsp initialization protocol on the open * channel */ memset(request, 0, sizeof(struct storvsc_request_extension)); - request->WaitEvent = osd_waitevent_create(); - if (!request->WaitEvent) { + request->wait_event = osd_waitevent_create(); + if (!request->wait_event) { ret = -ENOMEM; goto nomem; } @@ -224,7 +224,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->wait_event); if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || vstorPacket->status != 0) { @@ -255,7 +255,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->wait_event); /* TODO: Check returned version */ if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || @@ -273,7 +273,7 @@ static int StorVscChannelInit(struct hv_device *Device) vstorPacket->operation = VSTOR_OPERATION_QUERY_PROPERTIES; vstorPacket->flags = REQUEST_COMPLETION_FLAG; vstorPacket->storage_channel_properties.port_number = - storDevice->PortNumber; + storDevice->port_number; ret = vmbus_sendpacket(Device->channel, vstorPacket, sizeof(struct vstor_packet), @@ -287,7 +287,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->wait_event); /* TODO: Check returned version */ if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || @@ -298,8 +298,8 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - storDevice->PathId = vstorPacket->storage_channel_properties.path_id; - storDevice->TargetId + storDevice->path_id = vstorPacket->storage_channel_properties.path_id; + storDevice->target_id = vstorPacket->storage_channel_properties.target_id; DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x", @@ -324,7 +324,7 @@ static int StorVscChannelInit(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->wait_event); if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || vstorPacket->status != 0) { @@ -337,8 +337,8 @@ static int StorVscChannelInit(struct hv_device *Device) DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****"); Cleanup: - kfree(request->WaitEvent); - request->WaitEvent = NULL; + kfree(request->wait_event); + request->wait_event = NULL; nomem: PutStorDevice(Device); return ret; @@ -365,7 +365,7 @@ static void StorVscOnIOCompletion(struct hv_device *Device, /* ASSERT(RequestExt != NULL); */ /* ASSERT(RequestExt->Request != NULL); */ - request = RequestExt->Request; + request = RequestExt->request; /* ASSERT(request->OnIOCompletion != NULL); */ @@ -403,7 +403,7 @@ static void StorVscOnIOCompletion(struct hv_device *Device, request->on_io_completion(request); - atomic_dec(&storDevice->NumOutstandingRequests); + atomic_dec(&storDevice->num_outstanding_requests); PutStorDevice(Device); } @@ -463,18 +463,18 @@ static void StorVscOnChannelCallback(void *context) /* ASSERT(request);c */ /* if (vstorPacket.Flags & SYNTHETIC_FLAG) */ - if ((request == &storDevice->InitRequest) || - (request == &storDevice->ResetRequest)) { + if ((request == &storDevice->init_request) || + (request == &storDevice->reset_request)) { /* DPRINT_INFO(STORVSC, * "reset completion - operation " * "%u status %u", * vstorPacket.Operation, * vstorPacket.Status); */ - memcpy(&request->VStorPacket, packet, + memcpy(&request->vstor_packet, packet, sizeof(struct vstor_packet)); - osd_waitevent_set(request->WaitEvent); + osd_waitevent_set(request->wait_event); } else { StorVscOnReceive(device, (struct vstor_packet *)packet, @@ -522,6 +522,7 @@ static int StorVscConnectToVsp(struct hv_device *Device) /* * StorVscOnDeviceAdd - Callback when the device belonging to this driver is added + * is added */ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) { @@ -552,17 +553,17 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) storChannel->PathId = props->PathId; storChannel->TargetId = props->TargetId; */ - storDevice->PortNumber = deviceInfo->port_number; + storDevice->port_number = deviceInfo->port_number; /* Send it back up */ ret = StorVscConnectToVsp(Device); /* deviceInfo->PortNumber = storDevice->PortNumber; */ - deviceInfo->path_id = storDevice->PathId; - deviceInfo->target_id = storDevice->TargetId; + deviceInfo->path_id = storDevice->path_id; + deviceInfo->target_id = storDevice->target_id; DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n", - storDevice->PortNumber, storDevice->PathId, - storDevice->TargetId); + storDevice->port_number, storDevice->path_id, + storDevice->target_id); Cleanup: return ret; @@ -585,9 +586,9 @@ static int StorVscOnDeviceRemove(struct hv_device *Device) * only allow inbound traffic (responses) to proceed so that * outstanding requests can be completed. */ - while (atomic_read(&storDevice->NumOutstandingRequests)) { + while (atomic_read(&storDevice->num_outstanding_requests)) { DPRINT_INFO(STORVSC, "waiting for %d requests to complete...", - atomic_read(&storDevice->NumOutstandingRequests)); + atomic_read(&storDevice->num_outstanding_requests)); udelay(100); } @@ -621,22 +622,22 @@ int stor_vsc_on_host_reset(struct hv_device *Device) return -1; } - request = &storDevice->ResetRequest; - vstorPacket = &request->VStorPacket; + request = &storDevice->reset_request; + vstorPacket = &request->vstor_packet; - request->WaitEvent = osd_waitevent_create(); - if (!request->WaitEvent) { + request->wait_event = osd_waitevent_create(); + if (!request->wait_event) { ret = -ENOMEM; goto Cleanup; } vstorPacket->operation = VSTOR_OPERATION_RESET_BUS; vstorPacket->flags = REQUEST_COMPLETION_FLAG; - vstorPacket->vm_srb.path_id = storDevice->PathId; + vstorPacket->vm_srb.path_id = storDevice->path_id; ret = vmbus_sendpacket(Device->channel, vstorPacket, sizeof(struct vstor_packet), - (unsigned long)&storDevice->ResetRequest, + (unsigned long)&storDevice->reset_request, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) { @@ -646,9 +647,9 @@ int stor_vsc_on_host_reset(struct hv_device *Device) } /* FIXME: Add a timeout */ - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->wait_event); - kfree(request->WaitEvent); + kfree(request->wait_event); DPRINT_INFO(STORVSC, "host adapter reset completed"); /* @@ -674,7 +675,7 @@ static int StorVscOnIORequest(struct hv_device *Device, requestExtension = (struct storvsc_request_extension *)Request->extension; - vstorPacket = &requestExtension->VStorPacket; + vstorPacket = &requestExtension->vstor_packet; storDevice = GetStorDevice(Device); DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, " @@ -694,8 +695,8 @@ static int StorVscOnIORequest(struct hv_device *Device, /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, Request->Cdb, * Request->CdbLen); */ - requestExtension->Request = Request; - requestExtension->Device = Device; + requestExtension->request = Request; + requestExtension->device = Device; memset(vstorPacket, 0 , sizeof(struct vstor_packet)); @@ -729,9 +730,9 @@ static int StorVscOnIORequest(struct hv_device *Device, vstorPacket->vm_srb.sense_info_length, vstorPacket->vm_srb.cdb_length); - if (requestExtension->Request->data_buffer.Length) { + if (requestExtension->request->data_buffer.Length) { ret = vmbus_sendpacket_multipagebuffer(Device->channel, - &requestExtension->Request->data_buffer, + &requestExtension->request->data_buffer, vstorPacket, sizeof(struct vstor_packet), (unsigned long)requestExtension); @@ -748,7 +749,7 @@ static int StorVscOnIORequest(struct hv_device *Device, vstorPacket, ret); } - atomic_inc(&storDevice->NumOutstandingRequests); + atomic_inc(&storDevice->num_outstanding_requests); PutStorDevice(Device); return ret; @@ -782,7 +783,7 @@ int stor_vsc_initialize(struct hv_driver *Driver) /* Make sure we are at least 2 pages since 1 page is used for control */ /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */ - Driver->name = gDriverName; + Driver->name = g_driver_name; memcpy(&Driver->deviceType, &gStorVscDeviceType, sizeof(struct hv_guid)); -- cgit v1.2.3 From 02e37db7148a5ee98a742a0ff2f7e3acc406049b Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:48 -0800 Subject: staging: hv: Convert camel case function names in storvsc.c to lowercase Convert camel case function names in storvsc.c to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/blkvsc.c | 8 ++-- drivers/staging/hv/storvsc.c | 91 +++++++++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c index e62c922f11cb..208492ca781e 100644 --- a/drivers/staging/hv/blkvsc.c +++ b/drivers/staging/hv/blkvsc.c @@ -42,7 +42,7 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) deviceInfo = (struct storvsc_device_info *)AdditionalInfo; - ret = StorVscOnDeviceAdd(Device, AdditionalInfo); + ret = stor_vsc_on_device_add(Device, AdditionalInfo); if (ret != 0) return ret; @@ -94,9 +94,9 @@ int blk_vsc_initialize(struct hv_driver *Driver) /* Setup the dispatch table */ storDriver->base.OnDeviceAdd = BlkVscOnDeviceAdd; - storDriver->base.OnDeviceRemove = StorVscOnDeviceRemove; - storDriver->base.OnCleanup = StorVscOnCleanup; - storDriver->on_io_request = StorVscOnIORequest; + storDriver->base.OnDeviceRemove = stor_vsc_on_device_remove; + storDriver->base.OnCleanup = stor_vsc_on_cleanup; + storDriver->on_io_request = stor_vsc_on_io_request; return ret; } diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 3b6e63aa4554..6643038aa24d 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -81,7 +81,7 @@ static const struct hv_guid gStorVscDeviceType = { }; -static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device) +static inline struct storvsc_device *alloc_stor_device(struct hv_device *Device) { struct storvsc_device *storDevice; @@ -99,14 +99,14 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device) return storDevice; } -static inline void FreeStorDevice(struct storvsc_device *Device) +static inline void free_stor_device(struct storvsc_device *Device) { /* ASSERT(atomic_read(&Device->ref_count) == 0); */ kfree(Device); } /* Get the stordevice object iff exists and its refcount > 1 */ -static inline struct storvsc_device *GetStorDevice(struct hv_device *Device) +static inline struct storvsc_device *get_stor_device(struct hv_device *Device) { struct storvsc_device *storDevice; @@ -120,7 +120,8 @@ static inline struct storvsc_device *GetStorDevice(struct hv_device *Device) } /* Get the stordevice object iff exists and its refcount > 0 */ -static inline struct storvsc_device *MustGetStorDevice(struct hv_device *Device) +static inline struct storvsc_device *must_get_stor_device( + struct hv_device *Device) { struct storvsc_device *storDevice; @@ -133,7 +134,7 @@ static inline struct storvsc_device *MustGetStorDevice(struct hv_device *Device) return storDevice; } -static inline void PutStorDevice(struct hv_device *Device) +static inline void put_stor_device(struct hv_device *Device) { struct storvsc_device *storDevice; @@ -144,8 +145,9 @@ static inline void PutStorDevice(struct hv_device *Device) /* ASSERT(atomic_read(&storDevice->ref_count)); */ } -/* Drop ref count to 1 to effectively disable GetStorDevice() */ -static inline struct storvsc_device *ReleaseStorDevice(struct hv_device *Device) +/* Drop ref count to 1 to effectively disable get_stor_device() */ +static inline struct storvsc_device *release_stor_device( + struct hv_device *Device) { struct storvsc_device *storDevice; @@ -160,7 +162,7 @@ static inline struct storvsc_device *ReleaseStorDevice(struct hv_device *Device) } /* Drop ref count to 0. No one can use StorDevice object. */ -static inline struct storvsc_device *FinalReleaseStorDevice( +static inline struct storvsc_device *final_release_stor_device( struct hv_device *Device) { struct storvsc_device *storDevice; @@ -176,14 +178,14 @@ static inline struct storvsc_device *FinalReleaseStorDevice( return storDevice; } -static int StorVscChannelInit(struct hv_device *Device) +static int stor_vsc_channel_init(struct hv_device *Device) { struct storvsc_device *storDevice; struct storvsc_request_extension *request; struct vstor_packet *vstorPacket; int ret; - storDevice = GetStorDevice(Device); + storDevice = get_stor_device(Device); if (!storDevice) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); @@ -340,18 +342,18 @@ Cleanup: kfree(request->wait_event); request->wait_event = NULL; nomem: - PutStorDevice(Device); + put_stor_device(Device); return ret; } -static void StorVscOnIOCompletion(struct hv_device *Device, +static void stor_vsc_on_io_completion(struct hv_device *Device, struct vstor_packet *VStorPacket, struct storvsc_request_extension *RequestExt) { struct hv_storvsc_request *request; struct storvsc_device *storDevice; - storDevice = MustGetStorDevice(Device); + storDevice = must_get_stor_device(Device); if (!storDevice) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); @@ -405,17 +407,17 @@ static void StorVscOnIOCompletion(struct hv_device *Device, atomic_dec(&storDevice->num_outstanding_requests); - PutStorDevice(Device); + put_stor_device(Device); } -static void StorVscOnReceive(struct hv_device *Device, +static void stor_vsc_on_receive(struct hv_device *Device, struct vstor_packet *VStorPacket, struct storvsc_request_extension *RequestExt) { switch (VStorPacket->operation) { case VSTOR_OPERATION_COMPLETE_IO: DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION"); - StorVscOnIOCompletion(Device, VStorPacket, RequestExt); + stor_vsc_on_io_completion(Device, VStorPacket, RequestExt); break; case VSTOR_OPERATION_REMOVE_DEVICE: DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION"); @@ -429,7 +431,7 @@ static void StorVscOnReceive(struct hv_device *Device, } } -static void StorVscOnChannelCallback(void *context) +static void stor_vsc_on_channel_callback(void *context) { struct hv_device *device = (struct hv_device *)context; struct storvsc_device *storDevice; @@ -441,7 +443,7 @@ static void StorVscOnChannelCallback(void *context) /* ASSERT(device); */ - storDevice = MustGetStorDevice(device); + storDevice = must_get_stor_device(device); if (!storDevice) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); @@ -476,7 +478,7 @@ static void StorVscOnChannelCallback(void *context) osd_waitevent_set(request->wait_event); } else { - StorVscOnReceive(device, + stor_vsc_on_receive(device, (struct vstor_packet *)packet, request); } @@ -486,11 +488,11 @@ static void StorVscOnChannelCallback(void *context) } } while (1); - PutStorDevice(device); + put_stor_device(device); return; } -static int StorVscConnectToVsp(struct hv_device *Device) +static int stor_vsc_connect_to_vsp(struct hv_device *Device) { struct vmstorage_channel_properties props; struct storvsc_driver_object *storDriver; @@ -505,7 +507,7 @@ static int StorVscConnectToVsp(struct hv_device *Device) storDriver->ring_buffer_size, (void *)&props, sizeof(struct vmstorage_channel_properties), - StorVscOnChannelCallback, Device); + stor_vsc_on_channel_callback, Device); DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d", props.path_id, props.target_id, props.max_transfer_bytes); @@ -515,16 +517,17 @@ static int StorVscConnectToVsp(struct hv_device *Device) return -1; } - ret = StorVscChannelInit(Device); + ret = stor_vsc_channel_init(Device); return ret; } /* - * StorVscOnDeviceAdd - Callback when the device belonging to this driver is added + * stor_vsc_on_device_add - Callback when the device belonging to this driver * is added */ -static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) +static int stor_vsc_on_device_add(struct hv_device *Device, + void *AdditionalInfo) { struct storvsc_device *storDevice; /* struct vmstorage_channel_properties *props; */ @@ -532,7 +535,7 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) int ret = 0; deviceInfo = (struct storvsc_device_info *)AdditionalInfo; - storDevice = AllocStorDevice(Device); + storDevice = alloc_stor_device(Device); if (!storDevice) { ret = -1; goto Cleanup; @@ -555,7 +558,7 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) storDevice->port_number = deviceInfo->port_number; /* Send it back up */ - ret = StorVscConnectToVsp(Device); + ret = stor_vsc_connect_to_vsp(Device); /* deviceInfo->PortNumber = storDevice->PortNumber; */ deviceInfo->path_id = storDevice->path_id; @@ -570,16 +573,16 @@ Cleanup: } /* - * StorVscOnDeviceRemove - Callback when the our device is being removed + * stor_vsc_on_device_remove - Callback when the our device is being removed */ -static int StorVscOnDeviceRemove(struct hv_device *Device) +static int stor_vsc_on_device_remove(struct hv_device *Device) { struct storvsc_device *storDevice; DPRINT_INFO(STORVSC, "disabling storage device (%p)...", Device->Extension); - storDevice = ReleaseStorDevice(Device); + storDevice = release_stor_device(Device); /* * At this point, all outbound traffic should be disable. We @@ -595,14 +598,14 @@ static int StorVscOnDeviceRemove(struct hv_device *Device) DPRINT_INFO(STORVSC, "removing storage device (%p)...", Device->Extension); - storDevice = FinalReleaseStorDevice(Device); + storDevice = final_release_stor_device(Device); DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", storDevice); /* Close the channel */ vmbus_close(Device->channel); - FreeStorDevice(storDevice); + free_stor_device(storDevice); return 0; } @@ -615,7 +618,7 @@ int stor_vsc_on_host_reset(struct hv_device *Device) DPRINT_INFO(STORVSC, "resetting host adapter..."); - storDevice = GetStorDevice(Device); + storDevice = get_stor_device(Device); if (!storDevice) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); @@ -658,14 +661,14 @@ int stor_vsc_on_host_reset(struct hv_device *Device) */ Cleanup: - PutStorDevice(Device); + put_stor_device(Device); return ret; } /* - * StorVscOnIORequest - Callback to initiate an I/O request + * stor_vsc_on_io_request - Callback to initiate an I/O request */ -static int StorVscOnIORequest(struct hv_device *Device, +static int stor_vsc_on_io_request(struct hv_device *Device, struct hv_storvsc_request *Request) { struct storvsc_device *storDevice; @@ -676,7 +679,7 @@ static int StorVscOnIORequest(struct hv_device *Device, requestExtension = (struct storvsc_request_extension *)Request->extension; vstorPacket = &requestExtension->vstor_packet; - storDevice = GetStorDevice(Device); + storDevice = get_stor_device(Device); DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, " "Extension %p", Device, storDevice, Request, @@ -751,14 +754,14 @@ static int StorVscOnIORequest(struct hv_device *Device, atomic_inc(&storDevice->num_outstanding_requests); - PutStorDevice(Device); + put_stor_device(Device); return ret; } /* - * StorVscOnCleanup - Perform any cleanup when the driver is removed + * stor_vsc_on_cleanup - Perform any cleanup when the driver is removed */ -static void StorVscOnCleanup(struct hv_driver *Driver) +static void stor_vsc_on_cleanup(struct hv_driver *Driver) { } @@ -806,11 +809,11 @@ int stor_vsc_initialize(struct hv_driver *Driver) STORVSC_MAX_IO_REQUESTS); /* Setup the dispatch table */ - storDriver->base.OnDeviceAdd = StorVscOnDeviceAdd; - storDriver->base.OnDeviceRemove = StorVscOnDeviceRemove; - storDriver->base.OnCleanup = StorVscOnCleanup; + storDriver->base.OnDeviceAdd = stor_vsc_on_device_add; + storDriver->base.OnDeviceRemove = stor_vsc_on_device_remove; + storDriver->base.OnCleanup = stor_vsc_on_cleanup; - storDriver->on_io_request = StorVscOnIORequest; + storDriver->on_io_request = stor_vsc_on_io_request; return 0; } -- cgit v1.2.3 From f638859e3203d1ae933e7f2114cca68f1ac407db Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:49 -0800 Subject: staging: hv: Convert camel case local variables in storvsc.c to lowercase Convert camel case local variables in storvsc.c to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/storvsc.c | 496 ++++++++++++++++++++++--------------------- 1 file changed, 249 insertions(+), 247 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 6643038aa24d..9295113e09b9 100644 --- a/drivers/staging/hv/storvsc.c +++ b/drivers/staging/hv/storvsc.c @@ -50,7 +50,7 @@ struct storvsc_device { /* 0 indicates the device is being destroyed */ atomic_t ref_count; - atomic_t num_outstanding_requests; + atomic_t num_outstanding_req; /* * Each unique Port/Path/Target represents 1 channel ie scsi @@ -81,119 +81,119 @@ static const struct hv_guid gStorVscDeviceType = { }; -static inline struct storvsc_device *alloc_stor_device(struct hv_device *Device) +static inline struct storvsc_device *alloc_stor_device(struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); - if (!storDevice) + stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); + if (!stor_device) return NULL; /* Set to 2 to allow both inbound and outbound traffics */ /* (ie get_stor_device() and must_get_stor_device()) to proceed. */ - atomic_cmpxchg(&storDevice->ref_count, 0, 2); + atomic_cmpxchg(&stor_device->ref_count, 0, 2); - storDevice->device = Device; - Device->Extension = storDevice; + stor_device->device = device; + device->Extension = stor_device; - return storDevice; + return stor_device; } -static inline void free_stor_device(struct storvsc_device *Device) +static inline void free_stor_device(struct storvsc_device *device) { - /* ASSERT(atomic_read(&Device->ref_count) == 0); */ - kfree(Device); + /* ASSERT(atomic_read(&device->ref_count) == 0); */ + kfree(device); } /* Get the stordevice object iff exists and its refcount > 1 */ -static inline struct storvsc_device *get_stor_device(struct hv_device *Device) +static inline struct storvsc_device *get_stor_device(struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = (struct storvsc_device *)Device->Extension; - if (storDevice && atomic_read(&storDevice->ref_count) > 1) - atomic_inc(&storDevice->ref_count); + stor_device = (struct storvsc_device *)device->Extension; + if (stor_device && atomic_read(&stor_device->ref_count) > 1) + atomic_inc(&stor_device->ref_count); else - storDevice = NULL; + stor_device = NULL; - return storDevice; + return stor_device; } /* Get the stordevice object iff exists and its refcount > 0 */ static inline struct storvsc_device *must_get_stor_device( - struct hv_device *Device) + struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = (struct storvsc_device *)Device->Extension; - if (storDevice && atomic_read(&storDevice->ref_count)) - atomic_inc(&storDevice->ref_count); + stor_device = (struct storvsc_device *)device->Extension; + if (stor_device && atomic_read(&stor_device->ref_count)) + atomic_inc(&stor_device->ref_count); else - storDevice = NULL; + stor_device = NULL; - return storDevice; + return stor_device; } -static inline void put_stor_device(struct hv_device *Device) +static inline void put_stor_device(struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = (struct storvsc_device *)Device->Extension; - /* ASSERT(storDevice); */ + stor_device = (struct storvsc_device *)device->Extension; + /* ASSERT(stor_device); */ - atomic_dec(&storDevice->ref_count); - /* ASSERT(atomic_read(&storDevice->ref_count)); */ + atomic_dec(&stor_device->ref_count); + /* ASSERT(atomic_read(&stor_device->ref_count)); */ } /* Drop ref count to 1 to effectively disable get_stor_device() */ static inline struct storvsc_device *release_stor_device( - struct hv_device *Device) + struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = (struct storvsc_device *)Device->Extension; - /* ASSERT(storDevice); */ + stor_device = (struct storvsc_device *)device->Extension; + /* ASSERT(stor_device); */ /* Busy wait until the ref drop to 2, then set it to 1 */ - while (atomic_cmpxchg(&storDevice->ref_count, 2, 1) != 2) + while (atomic_cmpxchg(&stor_device->ref_count, 2, 1) != 2) udelay(100); - return storDevice; + return stor_device; } -/* Drop ref count to 0. No one can use StorDevice object. */ +/* Drop ref count to 0. No one can use stor_device object. */ static inline struct storvsc_device *final_release_stor_device( - struct hv_device *Device) + struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = (struct storvsc_device *)Device->Extension; - /* ASSERT(storDevice); */ + stor_device = (struct storvsc_device *)device->Extension; + /* ASSERT(stor_device); */ /* Busy wait until the ref drop to 1, then set it to 0 */ - while (atomic_cmpxchg(&storDevice->ref_count, 1, 0) != 1) + while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1) udelay(100); - Device->Extension = NULL; - return storDevice; + device->Extension = NULL; + return stor_device; } -static int stor_vsc_channel_init(struct hv_device *Device) +static int stor_vsc_channel_init(struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; struct storvsc_request_extension *request; - struct vstor_packet *vstorPacket; + struct vstor_packet *vstor_packet; int ret; - storDevice = get_stor_device(Device); - if (!storDevice) { + stor_device = get_stor_device(device); + if (!stor_device) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); return -1; } - request = &storDevice->init_request; - vstorPacket = &request->vstor_packet; + request = &stor_device->init_request; + vstor_packet = &request->vstor_packet; /* * Now, initiate the vsc/vsp initialization protocol on the open @@ -206,8 +206,8 @@ static int stor_vsc_channel_init(struct hv_device *Device) goto nomem; } - vstorPacket->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; - vstorPacket->flags = REQUEST_COMPLETION_FLAG; + vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; /*SpinlockAcquire(gDriverExt.packetListLock); INSERT_TAIL_LIST(&gDriverExt.packetList, &packet->listEntry.entry); @@ -215,7 +215,7 @@ static int stor_vsc_channel_init(struct hv_device *Device) DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION..."); - ret = vmbus_sendpacket(Device->channel, vstorPacket, + ret = vmbus_sendpacket(device->channel, vstor_packet, sizeof(struct vstor_packet), (unsigned long)request, VmbusPacketTypeDataInBand, @@ -228,25 +228,25 @@ static int stor_vsc_channel_init(struct hv_device *Device) osd_waitevent_wait(request->wait_event); - if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || - vstorPacket->status != 0) { + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || + vstor_packet->status != 0) { DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->operation, vstorPacket->status); + vstor_packet->operation, vstor_packet->status); goto Cleanup; } DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION..."); /* reuse the packet for version range supported */ - memset(vstorPacket, 0, sizeof(struct vstor_packet)); - vstorPacket->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; - vstorPacket->flags = REQUEST_COMPLETION_FLAG; + memset(vstor_packet, 0, sizeof(struct vstor_packet)); + vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstorPacket->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT; - FILL_VMSTOR_REVISION(vstorPacket->version.revision); + vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT; + FILL_VMSTOR_REVISION(vstor_packet->version.revision); - ret = vmbus_sendpacket(Device->channel, vstorPacket, + ret = vmbus_sendpacket(device->channel, vstor_packet, sizeof(struct vstor_packet), (unsigned long)request, VmbusPacketTypeDataInBand, @@ -260,24 +260,24 @@ static int stor_vsc_channel_init(struct hv_device *Device) osd_waitevent_wait(request->wait_event); /* TODO: Check returned version */ - if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || - vstorPacket->status != 0) { + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || + vstor_packet->status != 0) { DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->operation, vstorPacket->status); + vstor_packet->operation, vstor_packet->status); goto Cleanup; } /* Query channel properties */ DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION..."); - memset(vstorPacket, 0, sizeof(struct vstor_packet)); - vstorPacket->operation = VSTOR_OPERATION_QUERY_PROPERTIES; - vstorPacket->flags = REQUEST_COMPLETION_FLAG; - vstorPacket->storage_channel_properties.port_number = - storDevice->port_number; + memset(vstor_packet, 0, sizeof(struct vstor_packet)); + vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; + vstor_packet->storage_channel_properties.port_number = + stor_device->port_number; - ret = vmbus_sendpacket(Device->channel, vstorPacket, + ret = vmbus_sendpacket(device->channel, vstor_packet, sizeof(struct vstor_packet), (unsigned long)request, VmbusPacketTypeDataInBand, @@ -292,29 +292,29 @@ static int stor_vsc_channel_init(struct hv_device *Device) osd_waitevent_wait(request->wait_event); /* TODO: Check returned version */ - if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || - vstorPacket->status != 0) { + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || + vstor_packet->status != 0) { DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->operation, vstorPacket->status); + vstor_packet->operation, vstor_packet->status); goto Cleanup; } - storDevice->path_id = vstorPacket->storage_channel_properties.path_id; - storDevice->target_id - = vstorPacket->storage_channel_properties.target_id; + stor_device->path_id = vstor_packet->storage_channel_properties.path_id; + stor_device->target_id + = vstor_packet->storage_channel_properties.target_id; DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x", - vstorPacket->storage_channel_properties.flags, - vstorPacket->storage_channel_properties.max_transfer_bytes); + vstor_packet->storage_channel_properties.flags, + vstor_packet->storage_channel_properties.max_transfer_bytes); DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION..."); - memset(vstorPacket, 0, sizeof(struct vstor_packet)); - vstorPacket->operation = VSTOR_OPERATION_END_INITIALIZATION; - vstorPacket->flags = REQUEST_COMPLETION_FLAG; + memset(vstor_packet, 0, sizeof(struct vstor_packet)); + vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; - ret = vmbus_sendpacket(Device->channel, vstorPacket, + ret = vmbus_sendpacket(device->channel, vstor_packet, sizeof(struct vstor_packet), (unsigned long)request, VmbusPacketTypeDataInBand, @@ -328,11 +328,11 @@ static int stor_vsc_channel_init(struct hv_device *Device) osd_waitevent_wait(request->wait_event); - if (vstorPacket->operation != VSTOR_OPERATION_COMPLETE_IO || - vstorPacket->status != 0) { + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || + vstor_packet->status != 0) { DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed " "(op %d status 0x%x)", - vstorPacket->operation, vstorPacket->status); + vstor_packet->operation, vstor_packet->status); goto Cleanup; } @@ -342,82 +342,82 @@ Cleanup: kfree(request->wait_event); request->wait_event = NULL; nomem: - put_stor_device(Device); + put_stor_device(device); return ret; } -static void stor_vsc_on_io_completion(struct hv_device *Device, - struct vstor_packet *VStorPacket, - struct storvsc_request_extension *RequestExt) +static void stor_vsc_on_io_completion(struct hv_device *device, + struct vstor_packet *vstor_packet, + struct storvsc_request_extension *request_ext) { struct hv_storvsc_request *request; - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; - storDevice = must_get_stor_device(Device); - if (!storDevice) { + stor_device = must_get_stor_device(device); + if (!stor_device) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); return; } DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p " - "completed bytes xfer %u", RequestExt, - VStorPacket->vm_srb.data_transfer_length); + "completed bytes xfer %u", request_ext, + vstor_packet->vm_srb.data_transfer_length); - /* ASSERT(RequestExt != NULL); */ - /* ASSERT(RequestExt->Request != NULL); */ + /* ASSERT(request_ext != NULL); */ + /* ASSERT(request_ext->request != NULL); */ - request = RequestExt->request; + request = request_ext->request; /* ASSERT(request->OnIOCompletion != NULL); */ /* Copy over the status...etc */ - request->status = VStorPacket->vm_srb.scsi_status; + request->status = vstor_packet->vm_srb.scsi_status; - if (request->status != 0 || VStorPacket->vm_srb.srb_status != 1) { + if (request->status != 0 || vstor_packet->vm_srb.srb_status != 1) { DPRINT_WARN(STORVSC, "cmd 0x%x scsi status 0x%x srb status 0x%x\n", - request->cdb[0], VStorPacket->vm_srb.scsi_status, - VStorPacket->vm_srb.srb_status); + request->cdb[0], vstor_packet->vm_srb.scsi_status, + vstor_packet->vm_srb.srb_status); } if ((request->status & 0xFF) == 0x02) { /* CHECK_CONDITION */ - if (VStorPacket->vm_srb.srb_status & 0x80) { + if (vstor_packet->vm_srb.srb_status & 0x80) { /* autosense data available */ DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data " - "valid - len %d\n", RequestExt, - VStorPacket->vm_srb.sense_info_length); + "valid - len %d\n", request_ext, + vstor_packet->vm_srb.sense_info_length); - /* ASSERT(VStorPacket->vm_srb.sense_info_length <= */ + /* ASSERT(vstor_packet->vm_srb.sense_info_length <= */ /* request->SenseBufferSize); */ memcpy(request->sense_buffer, - VStorPacket->vm_srb.sense_data, - VStorPacket->vm_srb.sense_info_length); + vstor_packet->vm_srb.sense_data, + vstor_packet->vm_srb.sense_info_length); request->sense_buffer_size = - VStorPacket->vm_srb.sense_info_length; + vstor_packet->vm_srb.sense_info_length; } } /* TODO: */ - request->bytes_xfer = VStorPacket->vm_srb.data_transfer_length; + request->bytes_xfer = vstor_packet->vm_srb.data_transfer_length; request->on_io_completion(request); - atomic_dec(&storDevice->num_outstanding_requests); + atomic_dec(&stor_device->num_outstanding_req); - put_stor_device(Device); + put_stor_device(device); } -static void stor_vsc_on_receive(struct hv_device *Device, - struct vstor_packet *VStorPacket, - struct storvsc_request_extension *RequestExt) +static void stor_vsc_on_receive(struct hv_device *device, + struct vstor_packet *vstor_packet, + struct storvsc_request_extension *request_ext) { - switch (VStorPacket->operation) { + switch (vstor_packet->operation) { case VSTOR_OPERATION_COMPLETE_IO: DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION"); - stor_vsc_on_io_completion(Device, VStorPacket, RequestExt); + stor_vsc_on_io_completion(device, vstor_packet, request_ext); break; case VSTOR_OPERATION_REMOVE_DEVICE: DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION"); @@ -426,7 +426,7 @@ static void stor_vsc_on_receive(struct hv_device *Device, default: DPRINT_INFO(STORVSC, "Unknown operation received - %d", - VStorPacket->operation); + vstor_packet->operation); break; } } @@ -434,17 +434,17 @@ static void stor_vsc_on_receive(struct hv_device *Device, static void stor_vsc_on_channel_callback(void *context) { struct hv_device *device = (struct hv_device *)context; - struct storvsc_device *storDevice; - u32 bytesRecvd; - u64 requestId; + struct storvsc_device *stor_device; + u32 bytes_recvd; + u64 request_id; unsigned char packet[ALIGN_UP(sizeof(struct vstor_packet), 8)]; struct storvsc_request_extension *request; int ret; /* ASSERT(device); */ - storDevice = must_get_stor_device(device); - if (!storDevice) { + stor_device = must_get_stor_device(device); + if (!stor_device) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); return; @@ -453,25 +453,26 @@ static void stor_vsc_on_channel_callback(void *context) do { ret = vmbus_recvpacket(device->channel, packet, ALIGN_UP(sizeof(struct vstor_packet), 8), - &bytesRecvd, &requestId); - if (ret == 0 && bytesRecvd > 0) { + &bytes_recvd, &request_id); + if (ret == 0 && bytes_recvd > 0) { DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx", - bytesRecvd, requestId); + bytes_recvd, request_id); - /* ASSERT(bytesRecvd == sizeof(struct vstor_packet)); */ + /* ASSERT(bytes_recvd == + sizeof(struct vstor_packet)); */ request = (struct storvsc_request_extension *) - (unsigned long)requestId; + (unsigned long)request_id; /* ASSERT(request);c */ - /* if (vstorPacket.Flags & SYNTHETIC_FLAG) */ - if ((request == &storDevice->init_request) || - (request == &storDevice->reset_request)) { + /* if (vstor_packet.Flags & SYNTHETIC_FLAG) */ + if ((request == &stor_device->init_request) || + (request == &stor_device->reset_request)) { /* DPRINT_INFO(STORVSC, * "reset completion - operation " * "%u status %u", - * vstorPacket.Operation, - * vstorPacket.Status); */ + * vstor_packet.Operation, + * vstor_packet.Status); */ memcpy(&request->vstor_packet, packet, sizeof(struct vstor_packet)); @@ -492,22 +493,22 @@ static void stor_vsc_on_channel_callback(void *context) return; } -static int stor_vsc_connect_to_vsp(struct hv_device *Device) +static int stor_vsc_connect_to_vsp(struct hv_device *device) { struct vmstorage_channel_properties props; - struct storvsc_driver_object *storDriver; + struct storvsc_driver_object *stor_driver; int ret; - storDriver = (struct storvsc_driver_object *)Device->Driver; + stor_driver = (struct storvsc_driver_object *)device->Driver; memset(&props, 0, sizeof(struct vmstorage_channel_properties)); /* Open the channel */ - ret = vmbus_open(Device->channel, - storDriver->ring_buffer_size, - storDriver->ring_buffer_size, + ret = vmbus_open(device->channel, + stor_driver->ring_buffer_size, + stor_driver->ring_buffer_size, (void *)&props, sizeof(struct vmstorage_channel_properties), - stor_vsc_on_channel_callback, Device); + stor_vsc_on_channel_callback, device); DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d", props.path_id, props.target_id, props.max_transfer_bytes); @@ -517,7 +518,7 @@ static int stor_vsc_connect_to_vsp(struct hv_device *Device) return -1; } - ret = stor_vsc_channel_init(Device); + ret = stor_vsc_channel_init(device); return ret; } @@ -526,17 +527,17 @@ static int stor_vsc_connect_to_vsp(struct hv_device *Device) * stor_vsc_on_device_add - Callback when the device belonging to this driver * is added */ -static int stor_vsc_on_device_add(struct hv_device *Device, - void *AdditionalInfo) +static int stor_vsc_on_device_add(struct hv_device *device, + void *additional_info) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; /* struct vmstorage_channel_properties *props; */ - struct storvsc_device_info *deviceInfo; + struct storvsc_device_info *device_info; int ret = 0; - deviceInfo = (struct storvsc_device_info *)AdditionalInfo; - storDevice = alloc_stor_device(Device); - if (!storDevice) { + device_info = (struct storvsc_device_info *)additional_info; + stor_device = alloc_stor_device(device); + if (!stor_device) { ret = -1; goto Cleanup; } @@ -556,17 +557,17 @@ static int stor_vsc_on_device_add(struct hv_device *Device, storChannel->PathId = props->PathId; storChannel->TargetId = props->TargetId; */ - storDevice->port_number = deviceInfo->port_number; + stor_device->port_number = device_info->port_number; /* Send it back up */ - ret = stor_vsc_connect_to_vsp(Device); + ret = stor_vsc_connect_to_vsp(device); - /* deviceInfo->PortNumber = storDevice->PortNumber; */ - deviceInfo->path_id = storDevice->path_id; - deviceInfo->target_id = storDevice->target_id; + /* device_info->PortNumber = stor_device->PortNumber; */ + device_info->path_id = stor_device->path_id; + device_info->target_id = stor_device->target_id; DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n", - storDevice->port_number, storDevice->path_id, - storDevice->target_id); + stor_device->port_number, stor_device->path_id, + stor_device->target_id); Cleanup: return ret; @@ -575,58 +576,58 @@ Cleanup: /* * stor_vsc_on_device_remove - Callback when the our device is being removed */ -static int stor_vsc_on_device_remove(struct hv_device *Device) +static int stor_vsc_on_device_remove(struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; DPRINT_INFO(STORVSC, "disabling storage device (%p)...", - Device->Extension); + device->Extension); - storDevice = release_stor_device(Device); + stor_device = release_stor_device(device); /* * At this point, all outbound traffic should be disable. We * only allow inbound traffic (responses) to proceed so that * outstanding requests can be completed. */ - while (atomic_read(&storDevice->num_outstanding_requests)) { + while (atomic_read(&stor_device->num_outstanding_req)) { DPRINT_INFO(STORVSC, "waiting for %d requests to complete...", - atomic_read(&storDevice->num_outstanding_requests)); + atomic_read(&stor_device->num_outstanding_req)); udelay(100); } DPRINT_INFO(STORVSC, "removing storage device (%p)...", - Device->Extension); + device->Extension); - storDevice = final_release_stor_device(Device); + stor_device = final_release_stor_device(device); - DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", storDevice); + DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", stor_device); /* Close the channel */ - vmbus_close(Device->channel); + vmbus_close(device->channel); - free_stor_device(storDevice); + free_stor_device(stor_device); return 0; } -int stor_vsc_on_host_reset(struct hv_device *Device) +int stor_vsc_on_host_reset(struct hv_device *device) { - struct storvsc_device *storDevice; + struct storvsc_device *stor_device; struct storvsc_request_extension *request; - struct vstor_packet *vstorPacket; + struct vstor_packet *vstor_packet; int ret; DPRINT_INFO(STORVSC, "resetting host adapter..."); - storDevice = get_stor_device(Device); - if (!storDevice) { + stor_device = get_stor_device(device); + if (!stor_device) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); return -1; } - request = &storDevice->reset_request; - vstorPacket = &request->vstor_packet; + request = &stor_device->reset_request; + vstor_packet = &request->vstor_packet; request->wait_event = osd_waitevent_create(); if (!request->wait_event) { @@ -634,18 +635,18 @@ int stor_vsc_on_host_reset(struct hv_device *Device) goto Cleanup; } - vstorPacket->operation = VSTOR_OPERATION_RESET_BUS; - vstorPacket->flags = REQUEST_COMPLETION_FLAG; - vstorPacket->vm_srb.path_id = storDevice->path_id; + vstor_packet->operation = VSTOR_OPERATION_RESET_BUS; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; + vstor_packet->vm_srb.path_id = stor_device->path_id; - ret = vmbus_sendpacket(Device->channel, vstorPacket, + ret = vmbus_sendpacket(device->channel, vstor_packet, sizeof(struct vstor_packet), - (unsigned long)&storDevice->reset_request, + (unsigned long)&stor_device->reset_request, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) { DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d", - vstorPacket, ret); + vstor_packet, ret); goto Cleanup; } @@ -661,118 +662,118 @@ int stor_vsc_on_host_reset(struct hv_device *Device) */ Cleanup: - put_stor_device(Device); + put_stor_device(device); return ret; } /* * stor_vsc_on_io_request - Callback to initiate an I/O request */ -static int stor_vsc_on_io_request(struct hv_device *Device, - struct hv_storvsc_request *Request) +static int stor_vsc_on_io_request(struct hv_device *device, + struct hv_storvsc_request *request) { - struct storvsc_device *storDevice; - struct storvsc_request_extension *requestExtension; - struct vstor_packet *vstorPacket; + struct storvsc_device *stor_device; + struct storvsc_request_extension *request_extension; + struct vstor_packet *vstor_packet; int ret = 0; - requestExtension = - (struct storvsc_request_extension *)Request->extension; - vstorPacket = &requestExtension->vstor_packet; - storDevice = get_stor_device(Device); + request_extension = + (struct storvsc_request_extension *)request->extension; + vstor_packet = &request_extension->vstor_packet; + stor_device = get_stor_device(device); DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, " - "Extension %p", Device, storDevice, Request, - requestExtension); + "Extension %p", device, stor_device, request, + request_extension); DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d", - Request, Request->data_buffer.Length, Request->bus, - Request->target_id, Request->lun_id, Request->cdb_len); + request, request->data_buffer.Length, request->bus, + request->target_id, request->lun_id, request->cdb_len); - if (!storDevice) { + if (!stor_device) { DPRINT_ERR(STORVSC, "unable to get stor device..." "device being destroyed?"); return -2; } - /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, Request->Cdb, - * Request->CdbLen); */ + /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, request->Cdb, + * request->CdbLen); */ - requestExtension->request = Request; - requestExtension->device = Device; + request_extension->request = request; + request_extension->device = device; - memset(vstorPacket, 0 , sizeof(struct vstor_packet)); + memset(vstor_packet, 0 , sizeof(struct vstor_packet)); - vstorPacket->flags |= REQUEST_COMPLETION_FLAG; + vstor_packet->flags |= REQUEST_COMPLETION_FLAG; - vstorPacket->vm_srb.length = sizeof(struct vmscsi_request); + vstor_packet->vm_srb.length = sizeof(struct vmscsi_request); - vstorPacket->vm_srb.port_number = Request->host; - vstorPacket->vm_srb.path_id = Request->bus; - vstorPacket->vm_srb.target_id = Request->target_id; - vstorPacket->vm_srb.lun = Request->lun_id; + vstor_packet->vm_srb.port_number = request->host; + vstor_packet->vm_srb.path_id = request->bus; + vstor_packet->vm_srb.target_id = request->target_id; + vstor_packet->vm_srb.lun = request->lun_id; - vstorPacket->vm_srb.sense_info_length = SENSE_BUFFER_SIZE; + vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE; /* Copy over the scsi command descriptor block */ - vstorPacket->vm_srb.cdb_length = Request->cdb_len; - memcpy(&vstorPacket->vm_srb.cdb, Request->cdb, Request->cdb_len); + vstor_packet->vm_srb.cdb_length = request->cdb_len; + memcpy(&vstor_packet->vm_srb.cdb, request->cdb, request->cdb_len); - vstorPacket->vm_srb.data_in = Request->type; - vstorPacket->vm_srb.data_transfer_length = Request->data_buffer.Length; + vstor_packet->vm_srb.data_in = request->type; + vstor_packet->vm_srb.data_transfer_length = request->data_buffer.Length; - vstorPacket->operation = VSTOR_OPERATION_EXECUTE_SRB; + vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB; DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, " "lun %d senselen %d cdblen %d", - vstorPacket->vm_srb.length, - vstorPacket->vm_srb.port_number, - vstorPacket->vm_srb.path_id, - vstorPacket->vm_srb.target_id, - vstorPacket->vm_srb.lun, - vstorPacket->vm_srb.sense_info_length, - vstorPacket->vm_srb.cdb_length); - - if (requestExtension->request->data_buffer.Length) { - ret = vmbus_sendpacket_multipagebuffer(Device->channel, - &requestExtension->request->data_buffer, - vstorPacket, + vstor_packet->vm_srb.length, + vstor_packet->vm_srb.port_number, + vstor_packet->vm_srb.path_id, + vstor_packet->vm_srb.target_id, + vstor_packet->vm_srb.lun, + vstor_packet->vm_srb.sense_info_length, + vstor_packet->vm_srb.cdb_length); + + if (request_extension->request->data_buffer.Length) { + ret = vmbus_sendpacket_multipagebuffer(device->channel, + &request_extension->request->data_buffer, + vstor_packet, sizeof(struct vstor_packet), - (unsigned long)requestExtension); + (unsigned long)request_extension); } else { - ret = vmbus_sendpacket(Device->channel, vstorPacket, + ret = vmbus_sendpacket(device->channel, vstor_packet, sizeof(struct vstor_packet), - (unsigned long)requestExtension, + (unsigned long)request_extension, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); } if (ret != 0) { DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d", - vstorPacket, ret); + vstor_packet, ret); } - atomic_inc(&storDevice->num_outstanding_requests); + atomic_inc(&stor_device->num_outstanding_req); - put_stor_device(Device); + put_stor_device(device); return ret; } /* * stor_vsc_on_cleanup - Perform any cleanup when the driver is removed */ -static void stor_vsc_on_cleanup(struct hv_driver *Driver) +static void stor_vsc_on_cleanup(struct hv_driver *driver) { } /* * stor_vsc_initialize - Main entry point */ -int stor_vsc_initialize(struct hv_driver *Driver) +int stor_vsc_initialize(struct hv_driver *driver) { - struct storvsc_driver_object *storDriver; + struct storvsc_driver_object *stor_driver; - storDriver = (struct storvsc_driver_object *)Driver; + stor_driver = (struct storvsc_driver_object *)driver; DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd " "sizeof(struct storvsc_request_extension)=%zd " @@ -784,13 +785,14 @@ int stor_vsc_initialize(struct hv_driver *Driver) sizeof(struct vmscsi_request)); /* Make sure we are at least 2 pages since 1 page is used for control */ - /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */ + /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */ - Driver->name = g_driver_name; - memcpy(&Driver->deviceType, &gStorVscDeviceType, + driver->name = g_driver_name; + memcpy(&driver->deviceType, &gStorVscDeviceType, sizeof(struct hv_guid)); - storDriver->request_ext_size = sizeof(struct storvsc_request_extension); + stor_driver->request_ext_size = + sizeof(struct storvsc_request_extension); /* * Divide the ring buffer data size (which is 1 page less @@ -798,22 +800,22 @@ int stor_vsc_initialize(struct hv_driver *Driver) * the ring buffer indices) by the max request size (which is * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) */ - storDriver->max_outstanding_req_per_channel = - ((storDriver->ring_buffer_size - PAGE_SIZE) / + stor_driver->max_outstanding_req_per_channel = + ((stor_driver->ring_buffer_size - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(struct vstor_packet) + sizeof(u64), sizeof(u64))); DPRINT_INFO(STORVSC, "max io %u, currently %u\n", - storDriver->max_outstanding_req_per_channel, + stor_driver->max_outstanding_req_per_channel, STORVSC_MAX_IO_REQUESTS); /* Setup the dispatch table */ - storDriver->base.OnDeviceAdd = stor_vsc_on_device_add; - storDriver->base.OnDeviceRemove = stor_vsc_on_device_remove; - storDriver->base.OnCleanup = stor_vsc_on_cleanup; + stor_driver->base.OnDeviceAdd = stor_vsc_on_device_add; + stor_driver->base.OnDeviceRemove = stor_vsc_on_device_remove; + stor_driver->base.OnCleanup = stor_vsc_on_cleanup; - storDriver->on_io_request = stor_vsc_on_io_request; + stor_driver->on_io_request = stor_vsc_on_io_request; return 0; } -- cgit v1.2.3 From 2e6484acd28bb5223942d2608387af3ec9bf56f1 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:50 -0800 Subject: staging: hv: Convert camel case function names in blkvsc.c to lowercase Convert camel case function names in blkvsc.c to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/blkvsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c index 208492ca781e..4f4a65c09a94 100644 --- a/drivers/staging/hv/blkvsc.c +++ b/drivers/staging/hv/blkvsc.c @@ -35,7 +35,7 @@ static const struct hv_guid gBlkVscDeviceType = { } }; -static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) +static int blk_vsc_on_device_add(struct hv_device *Device, void *AdditionalInfo) { struct storvsc_device_info *deviceInfo; int ret = 0; @@ -93,7 +93,7 @@ int blk_vsc_initialize(struct hv_driver *Driver) storDriver->max_outstanding_req_per_channel); /* Setup the dispatch table */ - storDriver->base.OnDeviceAdd = BlkVscOnDeviceAdd; + storDriver->base.OnDeviceAdd = blk_vsc_on_device_add; storDriver->base.OnDeviceRemove = stor_vsc_on_device_remove; storDriver->base.OnCleanup = stor_vsc_on_cleanup; storDriver->on_io_request = stor_vsc_on_io_request; -- cgit v1.2.3 From 03fa6fc5a68242ddd7cc3ba4255fe6f65b21ce41 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 6 Dec 2010 12:26:51 -0800 Subject: staging: hv: Convert camel case local variables in blkvsc.c to lowercase Convert camel case local variables in blkvsc.c to lowercase Signed-off-by: Abhishek Kane Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/blkvsc.c | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/blkvsc.c b/drivers/staging/hv/blkvsc.c index 4f4a65c09a94..bc16d9172eb2 100644 --- a/drivers/staging/hv/blkvsc.c +++ b/drivers/staging/hv/blkvsc.c @@ -25,24 +25,24 @@ #include "osd.h" #include "storvsc.c" -static const char *gBlkDriverName = "blkvsc"; +static const char *g_blk_driver_name = "blkvsc"; /* {32412632-86cb-44a2-9b5c-50d1417354f5} */ -static const struct hv_guid gBlkVscDeviceType = { +static const struct hv_guid g_blk_device_type = { .data = { 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 } }; -static int blk_vsc_on_device_add(struct hv_device *Device, void *AdditionalInfo) +static int blk_vsc_on_device_add(struct hv_device *device, void *additional_info) { - struct storvsc_device_info *deviceInfo; + struct storvsc_device_info *device_info; int ret = 0; - deviceInfo = (struct storvsc_device_info *)AdditionalInfo; + device_info = (struct storvsc_device_info *)additional_info; - ret = stor_vsc_on_device_add(Device, AdditionalInfo); + ret = stor_vsc_on_device_add(device, additional_info); if (ret != 0) return ret; @@ -51,31 +51,31 @@ static int blk_vsc_on_device_add(struct hv_device *Device, void *AdditionalInfo) * id. For IDE devices, the device instance id is formatted as * * - - 8899 - 000000000000. */ - deviceInfo->path_id = Device->deviceInstance.data[3] << 24 | - Device->deviceInstance.data[2] << 16 | - Device->deviceInstance.data[1] << 8 | - Device->deviceInstance.data[0]; + device_info->path_id = device->deviceInstance.data[3] << 24 | + device->deviceInstance.data[2] << 16 | + device->deviceInstance.data[1] << 8 | + device->deviceInstance.data[0]; - deviceInfo->target_id = Device->deviceInstance.data[5] << 8 | - Device->deviceInstance.data[4]; + device_info->target_id = device->deviceInstance.data[5] << 8 | + device->deviceInstance.data[4]; return ret; } -int blk_vsc_initialize(struct hv_driver *Driver) +int blk_vsc_initialize(struct hv_driver *driver) { - struct storvsc_driver_object *storDriver; + struct storvsc_driver_object *stor_driver; int ret = 0; - storDriver = (struct storvsc_driver_object *)Driver; + stor_driver = (struct storvsc_driver_object *)driver; /* Make sure we are at least 2 pages since 1 page is used for control */ - /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */ + /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */ - Driver->name = gBlkDriverName; - memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(struct hv_guid)); + driver->name = g_blk_driver_name; + memcpy(&driver->deviceType, &g_blk_device_type, sizeof(struct hv_guid)); - storDriver->request_ext_size = sizeof(struct storvsc_request_extension); + stor_driver->request_ext_size = sizeof(struct storvsc_request_extension); /* * Divide the ring buffer data size (which is 1 page less than the ring @@ -83,20 +83,20 @@ int blk_vsc_initialize(struct hv_driver *Driver) * by the max request size (which is * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) */ - storDriver->max_outstanding_req_per_channel = - ((storDriver->ring_buffer_size - PAGE_SIZE) / + stor_driver->max_outstanding_req_per_channel = + ((stor_driver->ring_buffer_size - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(struct vstor_packet) + sizeof(u64), sizeof(u64))); DPRINT_INFO(BLKVSC, "max io outstd %u", - storDriver->max_outstanding_req_per_channel); + stor_driver->max_outstanding_req_per_channel); /* Setup the dispatch table */ - storDriver->base.OnDeviceAdd = blk_vsc_on_device_add; - storDriver->base.OnDeviceRemove = stor_vsc_on_device_remove; - storDriver->base.OnCleanup = stor_vsc_on_cleanup; - storDriver->on_io_request = stor_vsc_on_io_request; + stor_driver->base.OnDeviceAdd = blk_vsc_on_device_add; + stor_driver->base.OnDeviceRemove = stor_vsc_on_device_remove; + stor_driver->base.OnCleanup = stor_vsc_on_cleanup; + stor_driver->on_io_request = stor_vsc_on_io_request; return ret; } -- cgit v1.2.3 From 1a8e8fab790ea7af81b8f964fdec706ad1ec2271 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Mon, 6 Dec 2010 17:51:41 +0300 Subject: HID: Fix race between disconnect and hiddev_ioctl A USB HID device can be disconnected at any time. If this happens right before or while hiddev_ioctl is in progress, the hiddev_ioctl tries to access invalid hiddev->hid pointer. When the hid device is disconnected, the hiddev_disconnect() ends up with a call to hid_device_release() which frees hid_device, but doesn't set the hiddev->hid pointer to NULL. If the deallocated memory region has been re-used by the kernel, this can cause a crash or memory corruption. Since disconnect can happen at any time, we can't initialize struct hid_device *hid = hiddev->hid at the beginning of ioctl and then use it. This change checks hiddev->exist flag while holding the existancelock and uses hid_device only if it exists. Signed-off-by: Valentine Barshak Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 168 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 131 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index fedd88df9a18..ffee7f205fd5 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -586,7 +586,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; - struct hid_device *hid = hiddev->hid; + struct hid_device *hid; struct usb_device *dev; struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; @@ -594,26 +594,33 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; - struct usbhid_device *usbhid = hid->driver_data; + struct usbhid_device *usbhid; void __user *user_arg = (void __user *)arg; int i, r; - + /* Called without BKL by compat methods so no BKL taken */ /* FIXME: Who or what stop this racing with a disconnect ?? */ - if (!hiddev->exist || !hid) + if (!hiddev->exist) return -EIO; - dev = hid_to_usb_dev(hid); - switch (cmd) { case HIDIOCGVERSION: return put_user(HID_VERSION, (int __user *)arg); case HIDIOCAPPLICATION: - if (arg < 0 || arg >= hid->maxapplication) - return -EINVAL; + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + if (arg < 0 || arg >= hid->maxapplication) { + r = -EINVAL; + goto ret_unlock; + } for (i = 0; i < hid->maxcollection; i++) if (hid->collection[i].type == @@ -621,11 +628,22 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; if (i == hid->maxcollection) - return -EINVAL; - - return hid->collection[i].usage; + r = -EINVAL; + else + r = hid->collection[i].usage; + goto ret_unlock; case HIDIOCGDEVINFO: + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + dev = hid_to_usb_dev(hid); + usbhid = hid->driver_data; + dinfo.bustype = BUS_USB; dinfo.busnum = dev->bus->busnum; dinfo.devnum = dev->devnum; @@ -634,6 +652,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) dinfo.product = le16_to_cpu(dev->descriptor.idProduct); dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); dinfo.num_applications = hid->maxapplication; + mutex_unlock(&hiddev->existancelock); + if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) return -EFAULT; @@ -667,6 +687,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) r = hiddev_ioctl_string(hiddev, cmd, user_arg); else r = -ENODEV; +ret_unlock: mutex_unlock(&hiddev->existancelock); return r; @@ -676,6 +697,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_unlock(&hiddev->existancelock); return -ENODEV; } + hid = hiddev->hid; usbhid_init_reports(hid); mutex_unlock(&hiddev->existancelock); @@ -688,14 +710,21 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) return -EINVAL; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - mutex_lock(&hiddev->existancelock); - if (hiddev->exist) { - usbhid_submit_report(hid, report, USB_DIR_IN); - usbhid_wait_io(hid); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + report = hiddev_lookup_report(hid, &rinfo); + if (report == NULL) { + r = -EINVAL; + goto ret_unlock; } + + usbhid_submit_report(hid, report, USB_DIR_IN); + usbhid_wait_io(hid); mutex_unlock(&hiddev->existancelock); return 0; @@ -707,14 +736,21 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (rinfo.report_type == HID_REPORT_TYPE_INPUT) return -EINVAL; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; - mutex_lock(&hiddev->existancelock); - if (hiddev->exist) { - usbhid_submit_report(hid, report, USB_DIR_OUT); - usbhid_wait_io(hid); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + report = hiddev_lookup_report(hid, &rinfo); + if (report == NULL) { + r = -EINVAL; + goto ret_unlock; } + + usbhid_submit_report(hid, report, USB_DIR_OUT); + usbhid_wait_io(hid); mutex_unlock(&hiddev->existancelock); return 0; @@ -723,10 +759,21 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) return -EFAULT; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + report = hiddev_lookup_report(hid, &rinfo); + if (report == NULL) { + r = -EINVAL; + goto ret_unlock; + } rinfo.num_fields = report->maxfield; + mutex_unlock(&hiddev->existancelock); if (copy_to_user(user_arg, &rinfo, sizeof(rinfo))) return -EFAULT; @@ -738,11 +785,23 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EFAULT; rinfo.report_type = finfo.report_type; rinfo.report_id = finfo.report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } - if (finfo.field_index >= report->maxfield) - return -EINVAL; + hid = hiddev->hid; + report = hiddev_lookup_report(hid, &rinfo); + if (report == NULL) { + r = -EINVAL; + goto ret_unlock; + } + + if (finfo.field_index >= report->maxfield) { + r = -EINVAL; + goto ret_unlock; + } field = report->field[finfo.field_index]; memset(&finfo, 0, sizeof(finfo)); @@ -760,6 +819,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) finfo.physical_maximum = field->physical_maximum; finfo.unit_exponent = field->unit_exponent; finfo.unit = field->unit; + mutex_unlock(&hiddev->existancelock); if (copy_to_user(user_arg, &finfo, sizeof(finfo))) return -EFAULT; @@ -785,12 +845,22 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) return -EFAULT; - if (cinfo.index >= hid->maxcollection) - return -EINVAL; + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + if (cinfo.index >= hid->maxcollection) { + r = -EINVAL; + goto ret_unlock; + } cinfo.type = hid->collection[cinfo.index].type; cinfo.usage = hid->collection[cinfo.index].usage; cinfo.level = hid->collection[cinfo.index].level; + mutex_lock(&hiddev->existancelock); if (copy_to_user(user_arg, &cinfo, sizeof(cinfo))) return -EFAULT; @@ -803,24 +873,48 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { int len; - if (!hid->name) - return 0; + + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + if (!hid->name) { + r = 0; + goto ret_unlock; + } + len = strlen(hid->name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(user_arg, hid->name, len) ? + r = copy_to_user(user_arg, hid->name, len) ? -EFAULT : len; + goto ret_unlock; } if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { int len; - if (!hid->phys) - return 0; + + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; + if (!hid->phys) { + r = 0; + goto ret_unlock; + } + len = strlen(hid->phys) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(user_arg, hid->phys, len) ? + r = copy_to_user(user_arg, hid->phys, len) ? -EFAULT : len; + goto ret_unlock; } } return -EINVAL; -- cgit v1.2.3 From 33d6eb570b1f3fe5ba93cef465c5be66535c2c9a Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Mon, 6 Dec 2010 18:16:11 +0300 Subject: HID: Consolidate device existence checks in hiddev_ioctl Currently, if the device has been removed before hiddev_ioctl(), the -EIO is returned. If it's removed while hiddev_ioctl() is in progress, some commands are still processed fine, others return -ENODEV. This change takes the "existancelock" before processing ioctl commands and releases it at the end. If the device has been removed, always returns -ENODEV. Signed-off-by: Valentine Barshak Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 287 ++++++++++++++++---------------------------- 1 file changed, 103 insertions(+), 184 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index ffee7f205fd5..a9935f6709f7 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -587,221 +587,167 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid; - struct usb_device *dev; struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; - struct usbhid_device *usbhid; void __user *user_arg = (void __user *)arg; - int i, r; + int i, r = -EINVAL; /* Called without BKL by compat methods so no BKL taken */ - /* FIXME: Who or what stop this racing with a disconnect ?? */ - if (!hiddev->exist) - return -EIO; + mutex_lock(&hiddev->existancelock); + if (!hiddev->exist) { + r = -ENODEV; + goto ret_unlock; + } + + hid = hiddev->hid; switch (cmd) { case HIDIOCGVERSION: - return put_user(HID_VERSION, (int __user *)arg); + r = put_user(HID_VERSION, (int __user *)arg) ? + -EFAULT : 0; + break; case HIDIOCAPPLICATION: - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; - } - - hid = hiddev->hid; - if (arg < 0 || arg >= hid->maxapplication) { - r = -EINVAL; - goto ret_unlock; - } + if (arg < 0 || arg >= hid->maxapplication) + break; for (i = 0; i < hid->maxcollection; i++) if (hid->collection[i].type == HID_COLLECTION_APPLICATION && arg-- == 0) break; - if (i == hid->maxcollection) - r = -EINVAL; - else + if (i < hid->maxcollection) r = hid->collection[i].usage; - goto ret_unlock; + break; case HIDIOCGDEVINFO: - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; + { + struct usb_device *dev = hid_to_usb_dev(hid); + struct usbhid_device *usbhid = hid->driver_data; + + dinfo.bustype = BUS_USB; + dinfo.busnum = dev->bus->busnum; + dinfo.devnum = dev->devnum; + dinfo.ifnum = usbhid->ifnum; + dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); + dinfo.product = le16_to_cpu(dev->descriptor.idProduct); + dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); + dinfo.num_applications = hid->maxapplication; + + r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ? + -EFAULT : 0; + break; } - hid = hiddev->hid; - dev = hid_to_usb_dev(hid); - usbhid = hid->driver_data; - - dinfo.bustype = BUS_USB; - dinfo.busnum = dev->bus->busnum; - dinfo.devnum = dev->devnum; - dinfo.ifnum = usbhid->ifnum; - dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); - dinfo.product = le16_to_cpu(dev->descriptor.idProduct); - dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); - dinfo.num_applications = hid->maxapplication; - mutex_unlock(&hiddev->existancelock); - - if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) - return -EFAULT; - - return 0; - case HIDIOCGFLAG: - if (put_user(list->flags, (int __user *)arg)) - return -EFAULT; - - return 0; + r = put_user(list->flags, (int __user *)arg) ? + -EFAULT : 0; + break; case HIDIOCSFLAG: { int newflags; - if (get_user(newflags, (int __user *)arg)) - return -EFAULT; + + if (get_user(newflags, (int __user *)arg)) { + r = -EFAULT; + break; + } if ((newflags & ~HIDDEV_FLAGS) != 0 || ((newflags & HIDDEV_FLAG_REPORT) != 0 && (newflags & HIDDEV_FLAG_UREF) == 0)) - return -EINVAL; + break; list->flags = newflags; - return 0; + r = 0; + break; } case HIDIOCGSTRING: - mutex_lock(&hiddev->existancelock); - if (hiddev->exist) - r = hiddev_ioctl_string(hiddev, cmd, user_arg); - else - r = -ENODEV; -ret_unlock: - mutex_unlock(&hiddev->existancelock); - return r; + r = hiddev_ioctl_string(hiddev, cmd, user_arg); + break; case HIDIOCINITREPORT: - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - mutex_unlock(&hiddev->existancelock); - return -ENODEV; - } - hid = hiddev->hid; usbhid_init_reports(hid); - mutex_unlock(&hiddev->existancelock); - - return 0; + r = 0; + break; case HIDIOCGREPORT: - if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) - return -EFAULT; + if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { + r = -EFAULT; + break; + } if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) - return -EINVAL; + break; - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; - } - - hid = hiddev->hid; report = hiddev_lookup_report(hid, &rinfo); - if (report == NULL) { - r = -EINVAL; - goto ret_unlock; - } + if (report == NULL) + break; usbhid_submit_report(hid, report, USB_DIR_IN); usbhid_wait_io(hid); - mutex_unlock(&hiddev->existancelock); - return 0; + r = 0; + break; case HIDIOCSREPORT: - if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) - return -EFAULT; + if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { + r = -EFAULT; + break; + } if (rinfo.report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; - - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; - } + break; - hid = hiddev->hid; report = hiddev_lookup_report(hid, &rinfo); - if (report == NULL) { - r = -EINVAL; - goto ret_unlock; - } + if (report == NULL) + break; usbhid_submit_report(hid, report, USB_DIR_OUT); usbhid_wait_io(hid); - mutex_unlock(&hiddev->existancelock); - return 0; + r = 0; + break; case HIDIOCGREPORTINFO: - if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) - return -EFAULT; - - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; + if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) { + r = -EFAULT; + break; } - hid = hiddev->hid; report = hiddev_lookup_report(hid, &rinfo); - if (report == NULL) { - r = -EINVAL; - goto ret_unlock; - } + if (report == NULL) + break; rinfo.num_fields = report->maxfield; - mutex_unlock(&hiddev->existancelock); - - if (copy_to_user(user_arg, &rinfo, sizeof(rinfo))) - return -EFAULT; - return 0; + r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ? + -EFAULT : 0; + break; case HIDIOCGFIELDINFO: - if (copy_from_user(&finfo, user_arg, sizeof(finfo))) - return -EFAULT; + if (copy_from_user(&finfo, user_arg, sizeof(finfo))) { + r = -EFAULT; + break; + } + rinfo.report_type = finfo.report_type; rinfo.report_id = finfo.report_id; - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; - } - hid = hiddev->hid; report = hiddev_lookup_report(hid, &rinfo); - if (report == NULL) { - r = -EINVAL; - goto ret_unlock; - } + if (report == NULL) + break; - if (finfo.field_index >= report->maxfield) { - r = -EINVAL; - goto ret_unlock; - } + if (finfo.field_index >= report->maxfield) + break; field = report->field[finfo.field_index]; memset(&finfo, 0, sizeof(finfo)); @@ -819,12 +765,10 @@ ret_unlock: finfo.physical_maximum = field->physical_maximum; finfo.unit_exponent = field->unit_exponent; finfo.unit = field->unit; - mutex_unlock(&hiddev->existancelock); - if (copy_to_user(user_arg, &finfo, sizeof(finfo))) - return -EFAULT; - - return 0; + r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ? + -EFAULT : 0; + break; case HIDIOCGUCODE: /* fall through */ @@ -833,57 +777,36 @@ ret_unlock: case HIDIOCGUSAGES: case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: - mutex_lock(&hiddev->existancelock); - if (hiddev->exist) - r = hiddev_ioctl_usage(hiddev, cmd, user_arg); - else - r = -ENODEV; - mutex_unlock(&hiddev->existancelock); - return r; + r = hiddev_ioctl_usage(hiddev, cmd, user_arg); + break; case HIDIOCGCOLLECTIONINFO: - if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) - return -EFAULT; - - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; + if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) { + r = -EFAULT; + break; } - hid = hiddev->hid; - if (cinfo.index >= hid->maxcollection) { - r = -EINVAL; - goto ret_unlock; - } + if (cinfo.index >= hid->maxcollection) + break; cinfo.type = hid->collection[cinfo.index].type; cinfo.usage = hid->collection[cinfo.index].usage; cinfo.level = hid->collection[cinfo.index].level; - mutex_lock(&hiddev->existancelock); - if (copy_to_user(user_arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; + r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ? + -EFAULT : 0; + break; default: - if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) - return -EINVAL; + break; if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { int len; - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; - } - - hid = hiddev->hid; if (!hid->name) { r = 0; - goto ret_unlock; + break; } len = strlen(hid->name) + 1; @@ -891,22 +814,15 @@ ret_unlock: len = _IOC_SIZE(cmd); r = copy_to_user(user_arg, hid->name, len) ? -EFAULT : len; - goto ret_unlock; + break; } if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { int len; - mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) { - r = -ENODEV; - goto ret_unlock; - } - - hid = hiddev->hid; if (!hid->phys) { r = 0; - goto ret_unlock; + break; } len = strlen(hid->phys) + 1; @@ -914,10 +830,13 @@ ret_unlock: len = _IOC_SIZE(cmd); r = copy_to_user(user_arg, hid->phys, len) ? -EFAULT : len; - goto ret_unlock; + break; } } - return -EINVAL; + +ret_unlock: + mutex_unlock(&hiddev->existancelock); + return r; } #ifdef CONFIG_COMPAT -- cgit v1.2.3 From c57802706aad9f179f2219415717896b3c177845 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Dec 2010 23:04:14 +0000 Subject: drm/i915: Disable renderctx powersaving support for Ironlake ... still causes a failure during suspend. Reported-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 31fc1d797f8f..1ccf2ad7cd88 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5952,7 +5952,7 @@ void intel_enable_clock_gating(struct drm_device *dev) * GPU can automatically power down the render unit if given a page * to save state. */ - if (IS_IRONLAKE_M(dev)) { + if (IS_IRONLAKE_M(dev) && 0) { /* XXX causes a failure during suspend */ if (dev_priv->renderctx == NULL) dev_priv->renderctx = intel_alloc_context_page(dev); if (dev_priv->renderctx) { -- cgit v1.2.3 From ca130c2267d0719c92ed188e15082d6baad6c046 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 20 Nov 2010 14:42:57 +0100 Subject: drm/nv04-nv40: Give "gpuobj->cinst" the same meaning as on nv50. No functional changes, just simplify some code paths a bit. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 6 +----- drivers/gpu/drm/nouveau/nouveau_ramht.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 6 ------ 3 files changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 924653c30783..2fb7e9d47500 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -202,11 +202,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (gpuobj->pinst != ~0) gpuobj->pinst += ramin->start; - if (dev_priv->card_type < NV_50) - gpuobj->cinst = gpuobj->pinst; - else - gpuobj->cinst = ramin->start; - + gpuobj->cinst = ramin->start; gpuobj->vinst = ramin->start + chan->ramin->vinst; gpuobj->node = ramin; } else { diff --git a/drivers/gpu/drm/nouveau/nouveau_ramht.c b/drivers/gpu/drm/nouveau/nouveau_ramht.c index d4a2adc927d8..bef3e6910418 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ramht.c +++ b/drivers/gpu/drm/nouveau/nouveau_ramht.c @@ -104,12 +104,12 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle, nouveau_gpuobj_ref(gpuobj, &entry->gpuobj); if (dev_priv->card_type < NV_40) { - ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) | + ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->pinst >> 4) | (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); } else if (dev_priv->card_type < NV_50) { - ctx = (gpuobj->cinst >> 4) | + ctx = (gpuobj->pinst >> 4) | (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); } else { diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index db32644f6114..a0bf130b02d3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -241,12 +241,6 @@ nouveau_sgdma_init(struct drm_device *dev) } if (dev_priv->card_type < NV_50) { - /* special case, allocated from global instmem heap so - * cinst is invalid, we use it on all channels though so - * cinst needs to be valid, set it the same as pinst - */ - gpuobj->cinst = gpuobj->pinst; - nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY | (1 << 12) /* PT present */ | (0 << 13) /* PT *not* linear */ | -- cgit v1.2.3 From 38cf189fa13e988f85efb6de26315e762cecc260 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 20 Nov 2010 14:43:51 +0100 Subject: drm/nv04-nv10: Don't re-enable FIFO access multiple times after IRQ dispatch. nvxx_graph_isr is already taking care of it. In some cases this could've made you miss PGRAPH interrupts (e.g. when you were supposed to get several IRQs of the same kind in a row). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_graph.c | 3 --- drivers/gpu/drm/nouveau/nv10_graph.c | 12 ------------ 2 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 0bc616d35eb6..af75015068d6 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -373,7 +373,6 @@ nv04_graph_context_switch(struct drm_device *dev) struct nouveau_channel *chan = NULL; int chid; - pgraph->fifo_access(dev, false); nouveau_wait_for_idle(dev); /* If previous context is valid, we need to save it */ @@ -384,8 +383,6 @@ nv04_graph_context_switch(struct drm_device *dev) chan = dev_priv->channels.ptr[chid]; if (chan) nv04_graph_load_context(chan); - - pgraph->fifo_access(dev, true); } static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg) diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c index 536b39e4a9e2..8c92edb7bbcd 100644 --- a/drivers/gpu/drm/nouveau/nv10_graph.c +++ b/drivers/gpu/drm/nouveau/nv10_graph.c @@ -794,11 +794,9 @@ static void nv10_graph_context_switch(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_channel *chan = NULL; int chid; - pgraph->fifo_access(dev, false); nouveau_wait_for_idle(dev); /* If previous context is valid, we need to save it */ @@ -809,8 +807,6 @@ nv10_graph_context_switch(struct drm_device *dev) chan = dev_priv->channels.ptr[chid]; if (chan && chan->pgraph_ctx) nv10_graph_load_context(chan); - - pgraph->fifo_access(dev, true); } #define NV_WRITE_CTX(reg, val) do { \ @@ -980,8 +976,6 @@ nv17_graph_mthd_lma_window(struct nouveau_channel *chan, struct drm_device *dev = chan->dev; struct graph_state *ctx = chan->pgraph_ctx; struct pipe_state *pipe = &ctx->pipe_state; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; uint32_t xfmode0, xfmode1; int i; @@ -1048,8 +1042,6 @@ nv17_graph_mthd_lma_window(struct nouveau_channel *chan, nouveau_wait_for_idle(dev); - pgraph->fifo_access(dev, true); - return 0; } @@ -1058,8 +1050,6 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) { struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; nouveau_wait_for_idle(dev); @@ -1068,8 +1058,6 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, nv_wr32(dev, 0x004006b0, nv_rd32(dev, 0x004006b0) | 0x8 << 24); - pgraph->fifo_access(dev, true); - return 0; } -- cgit v1.2.3 From 6dccd311dd4b104b3bc53cb67aef414141d11c9f Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 18 Nov 2010 23:57:46 +0100 Subject: drm/nouveau: Synchronize with the user channel before GPU object destruction. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There have been reports of PFIFO cache errors during context take down (fdo bug 31637). They are caused by some GPU objects being taken out while the channel is still potentially processing commands. Make sure that all the previous rendering has landed before releasing a GPU object. Reported-by: Grzesiek Sójka Reported-by: Patrice Mandin Signed-off-by: Francisco Jerez Acked-by: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 36 +++++++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_drv.c | 16 ++------------ drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_object.c | 3 +++ 4 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 0f33132fba3b..3e49babd62ac 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -284,7 +284,6 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; unsigned long flags; - int ret; /* decrement the refcount, and we're done if there's still refs */ if (likely(!atomic_dec_and_test(&chan->users))) { @@ -297,19 +296,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) nouveau_debugfs_channel_fini(chan); /* give it chance to idle */ - nouveau_fence_update(chan); - if (chan->fence.sequence != chan->fence.sequence_ack) { - struct nouveau_fence *fence = NULL; - - ret = nouveau_fence_new(chan, &fence, true); - if (ret == 0) { - ret = nouveau_fence_wait(fence, false, false); - nouveau_fence_unref(&fence); - } - - if (ret) - NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); - } + nouveau_channel_idle(chan); /* ensure all outstanding fences are signaled. they should be if the * above attempts at idling were OK, but if we failed this'll tell TTM @@ -388,6 +375,27 @@ nouveau_channel_ref(struct nouveau_channel *chan, *pchan = chan; } +void +nouveau_channel_idle(struct nouveau_channel *chan) +{ + struct drm_device *dev = chan->dev; + struct nouveau_fence *fence = NULL; + int ret; + + nouveau_fence_update(chan); + + if (chan->fence.sequence != chan->fence.sequence_ack) { + ret = nouveau_fence_new(chan, &fence, true); + if (!ret) { + ret = nouveau_fence_wait(fence, false, false); + nouveau_fence_unref(&fence); + } + + if (ret) + NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); + } +} + /* cleans up all the fifos from file_priv */ void nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 7ff5b4369f03..a48c7da133d2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -197,22 +197,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) NV_INFO(dev, "Idling channels...\n"); for (i = 0; i < pfifo->channels; i++) { - struct nouveau_fence *fence = NULL; - chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->pushbuf_bo) - continue; - - ret = nouveau_fence_new(chan, &fence, true); - if (ret == 0) { - ret = nouveau_fence_wait(fence, false, false); - nouveau_fence_unref(&fence); - } - if (ret) { - NV_ERROR(dev, "Failed to idle channel %d for suspend\n", - chan->id); - } + if (chan && chan->pushbuf_bo) + nouveau_channel_idle(chan); } pgraph->fifo_access(dev, false); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a52b1da32031..d001453e857b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -847,6 +847,7 @@ extern void nouveau_channel_put_unlocked(struct nouveau_channel **); extern void nouveau_channel_put(struct nouveau_channel **); extern void nouveau_channel_ref(struct nouveau_channel *chan, struct nouveau_channel **pchan); +extern void nouveau_channel_idle(struct nouveau_channel *chan); /* nouveau_object.c */ #define NVOBJ_CLASS(d,c,e) do { \ diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 2fb7e9d47500..24540862a23f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -1017,6 +1017,9 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, if (IS_ERR(chan)) return PTR_ERR(chan); + /* Synchronize with the user channel */ + nouveau_channel_idle(chan); + ret = nouveau_ramht_remove(chan, objfree->handle); nouveau_channel_put(&chan); return ret; -- cgit v1.2.3 From a3d487ea5463a9c091b7f9b836b860cf3d82e641 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 20 Nov 2010 22:11:22 +0100 Subject: drm/nouveau: Use WC memory on the AGP GART. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index f4ee43db00aa..f6f51b4259e7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -424,8 +424,9 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, switch (dev_priv->gart_info.type) { case NOUVEAU_GART_AGP: man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED; - man->default_caching = TTM_PL_FLAG_UNCACHED; + man->available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; break; case NOUVEAU_GART_SGDMA: man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | -- cgit v1.2.3 From 395a31ec7ed9b02c5412f4405acbd6fceacca0fc Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 25 Nov 2010 16:37:17 +0100 Subject: drm/nouveau: Spin for a bit in nouveau_fence_wait() before yielding the CPU. Sleeping doesn't pay off for very short delays in comparison with the minimum granularity of schedule_timeout(). Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 2579fc69d182..abfeff19488e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -218,6 +218,7 @@ int __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) { unsigned long timeout = jiffies + (3 * DRM_HZ); + unsigned long sleep_time = jiffies + 1; int ret = 0; while (1) { @@ -231,7 +232,7 @@ __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (lazy) + if (lazy && time_after_eq(jiffies, sleep_time)) schedule_timeout(1); if (intr && signal_pending(current)) { -- cgit v1.2.3 From d908175cca901b95ba1628428b216e6e7188e8fb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 22 Nov 2010 16:05:54 +1000 Subject: drm/nouveau: make fifo.create_context() responsible for mapping control regs The regs belong to PFIFO, they're different for pretty much the same generations we need different PFIFO control for, and NVC0 is going to be even more different than the rest. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 22 +--------------------- drivers/gpu/drm/nouveau/nv04_fifo.c | 9 +++++++++ drivers/gpu/drm/nouveau/nv10_fifo.c | 5 +++++ drivers/gpu/drm/nouveau/nv40_fifo.c | 5 +++++ drivers/gpu/drm/nouveau/nv50_fifo.c | 9 +++++++++ 5 files changed, 29 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 3e49babd62ac..a3d33a582a98 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -113,7 +113,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_channel *chan; unsigned long flags; - int user, ret; + int ret; /* allocate and lock channel structure */ chan = kzalloc(sizeof(*chan), GFP_KERNEL); @@ -160,23 +160,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, } nouveau_dma_pre_init(chan); - - /* Locate channel's user control regs */ - if (dev_priv->card_type < NV_40) - user = NV03_USER(chan->id); - else - if (dev_priv->card_type < NV_50) - user = NV40_USER(chan->id); - else - user = NV50_USER(chan->id); - - chan->user = ioremap(pci_resource_start(dev->pdev, 0) + user, - PAGE_SIZE); - if (!chan->user) { - NV_ERROR(dev, "ioremap of regs failed.\n"); - nouveau_channel_put(&chan); - return -ENOMEM; - } chan->user_put = 0x40; chan->user_get = 0x44; @@ -356,9 +339,6 @@ nouveau_channel_del(struct kref *ref) struct nouveau_channel *chan = container_of(ref, struct nouveau_channel, ref); - if (chan->user) - iounmap(chan->user); - kfree(chan); } diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index a32ba8ccaae6..f89d104698df 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -129,6 +129,11 @@ nv04_fifo_create_context(struct nouveau_channel *chan) if (ret) return ret; + chan->user = ioremap(pci_resource_start(dev->pdev, 0) + + NV03_USER(chan->id), PAGE_SIZE); + if (!chan->user) + return -ENOMEM; + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); /* Setup initial state */ @@ -173,6 +178,10 @@ nv04_fifo_destroy_context(struct nouveau_channel *chan) spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); /* Free the channel resources */ + if (chan->user) { + iounmap(chan->user); + chan->user = NULL; + } nouveau_gpuobj_ref(NULL, &chan->ramfc); } diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c index acb9216e6d0a..d2ecbff4bee1 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c @@ -53,6 +53,11 @@ nv10_fifo_create_context(struct nouveau_channel *chan) if (ret) return ret; + chan->user = ioremap(pci_resource_start(dev->pdev, 0) + + NV03_USER(chan->id), PAGE_SIZE); + if (!chan->user) + return -ENOMEM; + /* Fill entries that are seen filled in dumps of nvidia driver just * after channel's is put into DMA mode */ diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index f6b3580c685a..c86e4d4e9b96 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -47,6 +47,11 @@ nv40_fifo_create_context(struct nouveau_channel *chan) if (ret) return ret; + chan->user = ioremap(pci_resource_start(dev->pdev, 0) + + NV40_USER(chan->id), PAGE_SIZE); + if (!chan->user) + return -ENOMEM; + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); nv_wi32(dev, fc + 0, chan->pushbuf_base); diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index ed18952ae7f4..7add3dfde3df 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -261,6 +261,11 @@ nv50_fifo_create_context(struct nouveau_channel *chan) } ramfc = chan->ramfc; + chan->user = ioremap(pci_resource_start(dev->pdev, 0) + + NV50_USER(chan->id), PAGE_SIZE); + if (!chan->user) + return -ENOMEM; + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4); @@ -327,6 +332,10 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); /* Free the channel resources */ + if (chan->user) { + iounmap(chan->user); + chan->user = NULL; + } nouveau_gpuobj_ref(NULL, &ramfc); nouveau_gpuobj_ref(NULL, &chan->cache); } -- cgit v1.2.3 From ceac30999dfb00ee7b56cfea8b28ef50999a3c95 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2010 10:10:24 +1000 Subject: drm/nouveau: implicitly insert non-DMA objects into RAMHT Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dma.c | 10 ++---- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +- drivers/gpu/drm/nouveau/nouveau_fence.c | 7 +--- drivers/gpu/drm/nouveau/nouveau_object.c | 59 +++++++++++++++----------------- drivers/gpu/drm/nouveau/nv04_fbcon.c | 34 ++++++------------ drivers/gpu/drm/nouveau/nv50_fbcon.c | 10 ++---- 6 files changed, 43 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 82581e600dcd..6ff77cedc008 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -59,17 +59,11 @@ nouveau_dma_init(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *obj = NULL; int ret, i; /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ - ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ? - 0x0039 : 0x5039, &obj); - if (ret) - return ret; - - ret = nouveau_ramht_insert(chan, NvM2MF, obj); - nouveau_gpuobj_ref(NULL, &obj); + ret = nouveau_gpuobj_gr_new(chan, NvM2MF, dev_priv->card_type < NV_50 ? + 0x0039 : 0x5039); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index d001453e857b..bbf19861b6c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -887,8 +887,7 @@ extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst, extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, uint64_t offset, uint64_t size, int access, int target, struct nouveau_gpuobj **); -extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, - struct nouveau_gpuobj **); +extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, u32 handle, int class); extern int nv50_gpuobj_dma_new(struct nouveau_channel *, int class, u64 base, u64 size, int target, int access, u32 type, u32 comp, struct nouveau_gpuobj **pobj); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index abfeff19488e..3d50d5c3b0fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -438,12 +438,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) int ret; /* Create an NV_SW object for various sync purposes */ - ret = nouveau_gpuobj_gr_new(chan, NV_SW, &obj); - if (ret) - return ret; - - ret = nouveau_ramht_insert(chan, NvSw, obj); - nouveau_gpuobj_ref(NULL, &obj); + ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 24540862a23f..3518ebba6fbd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -608,13 +608,9 @@ static int nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj_ret) { - struct drm_nouveau_private *dev_priv; + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct nouveau_gpuobj *gpuobj; - if (!chan || !gpuobj_ret || *gpuobj_ret != NULL) - return -EINVAL; - dev_priv = chan->dev->dev_private; - gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); if (!gpuobj) return -ENOMEM; @@ -632,12 +628,12 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, } int -nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, - struct nouveau_gpuobj **gpuobj) +nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct drm_device *dev = chan->dev; struct nouveau_gpuobj_class *oc; + struct nouveau_gpuobj *gpuobj; int ret; NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class); @@ -651,10 +647,12 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, return -EINVAL; found: - if (oc->engine == NVOBJ_ENGINE_SW) - return nouveau_gpuobj_sw_new(chan, class, gpuobj); - switch (oc->engine) { + case NVOBJ_ENGINE_SW: + ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj); + if (ret) + return ret; + goto insert; case NVOBJ_ENGINE_GR: if (dev_priv->card_type >= NV_50 && !chan->ramin_grctx) { struct nouveau_pgraph_engine *pgraph = @@ -681,41 +679,47 @@ found: nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, - gpuobj); + &gpuobj); if (ret) { NV_ERROR(dev, "error creating gpuobj: %d\n", ret); return ret; } if (dev_priv->card_type >= NV_50) { - nv_wo32(*gpuobj, 0, class); - nv_wo32(*gpuobj, 20, 0x00010000); + nv_wo32(gpuobj, 0, class); + nv_wo32(gpuobj, 20, 0x00010000); } else { switch (class) { case NV_CLASS_NULL: - nv_wo32(*gpuobj, 0, 0x00001030); - nv_wo32(*gpuobj, 4, 0xFFFFFFFF); + nv_wo32(gpuobj, 0, 0x00001030); + nv_wo32(gpuobj, 4, 0xFFFFFFFF); break; default: if (dev_priv->card_type >= NV_40) { - nv_wo32(*gpuobj, 0, class); + nv_wo32(gpuobj, 0, class); #ifdef __BIG_ENDIAN - nv_wo32(*gpuobj, 8, 0x01000000); + nv_wo32(gpuobj, 8, 0x01000000); #endif } else { #ifdef __BIG_ENDIAN - nv_wo32(*gpuobj, 0, class | 0x00080000); + nv_wo32(gpuobj, 0, class | 0x00080000); #else - nv_wo32(*gpuobj, 0, class); + nv_wo32(gpuobj, 0, class); #endif } } } dev_priv->engine.instmem.flush(dev); - (*gpuobj)->engine = oc->engine; - (*gpuobj)->class = oc->id; - return 0; + gpuobj->engine = oc->engine; + gpuobj->class = oc->id; + +insert: + ret = nouveau_ramht_insert(chan, handle, gpuobj); + if (ret) + NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret); + nouveau_gpuobj_ref(NULL, &gpuobj); + return ret; } static int @@ -971,7 +975,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_nouveau_grobj_alloc *init = data; - struct nouveau_gpuobj *gr = NULL; struct nouveau_channel *chan; int ret; @@ -987,18 +990,10 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, goto out; } - ret = nouveau_gpuobj_gr_new(chan, init->class, &gr); + ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class); if (ret) { NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", ret, init->channel, init->handle); - goto out; - } - - ret = nouveau_ramht_insert(chan, init->handle, gr); - nouveau_gpuobj_ref(NULL, &gr); - if (ret) { - NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n", - ret, init->channel, init->handle); } out: diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index a32804e7d202..7a1189371096 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -137,22 +137,6 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) return 0; } -static int -nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *obj = NULL; - int ret; - - ret = nouveau_gpuobj_gr_new(dev_priv->channel, class, &obj); - if (ret) - return ret; - - ret = nouveau_ramht_insert(dev_priv->channel, handle, obj); - nouveau_gpuobj_ref(NULL, &obj); - return ret; -} - int nv04_fbcon_accel_init(struct fb_info *info) { @@ -192,29 +176,31 @@ nv04_fbcon_accel_init(struct fb_info *info) return -EINVAL; } - ret = nv04_fbcon_grobj_new(dev, dev_priv->card_type >= NV_10 ? - 0x0062 : 0x0042, NvCtxSurf2D); + ret = nouveau_gpuobj_gr_new(chan, NvCtxSurf2D, + dev_priv->card_type >= NV_10 ? + 0x0062 : 0x0042); if (ret) return ret; - ret = nv04_fbcon_grobj_new(dev, 0x0019, NvClipRect); + ret = nouveau_gpuobj_gr_new(chan, NvClipRect, 0x0019); if (ret) return ret; - ret = nv04_fbcon_grobj_new(dev, 0x0043, NvRop); + ret = nouveau_gpuobj_gr_new(chan, NvRop, 0x0043); if (ret) return ret; - ret = nv04_fbcon_grobj_new(dev, 0x0044, NvImagePatt); + ret = nouveau_gpuobj_gr_new(chan, NvImagePatt, 0x0044); if (ret) return ret; - ret = nv04_fbcon_grobj_new(dev, 0x004a, NvGdiRect); + ret = nouveau_gpuobj_gr_new(chan, NvGdiRect, 0x004a); if (ret) return ret; - ret = nv04_fbcon_grobj_new(dev, dev_priv->chipset >= 0x11 ? - 0x009f : 0x005f, NvImageBlit); + ret = nouveau_gpuobj_gr_new(chan, NvImageBlit, + dev_priv->chipset >= 0x11 ? + 0x009f : 0x005f); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 6edf9dca35ca..156731993907 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -134,9 +134,8 @@ nv50_fbcon_accel_init(struct fb_info *info) struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; - struct nouveau_gpuobj *eng2d = NULL; - uint64_t fb; int ret, format; + uint64_t fb; fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base; @@ -167,12 +166,7 @@ nv50_fbcon_accel_init(struct fb_info *info) return -EINVAL; } - ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d); - if (ret) - return ret; - - ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d); - nouveau_gpuobj_ref(NULL, &eng2d); + ret = nouveau_gpuobj_gr_new(dev_priv->channel, Nv2D, 0x502d); if (ret) return ret; -- cgit v1.2.3 From 12fb9525075982bc65cfd71427dd7afdf47bafed Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 Nov 2010 14:32:56 +1000 Subject: drm/nouveau: introduce a util function to wait on reg != val Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 10 +++++++--- drivers/gpu/drm/nouveau/nouveau_hw.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_state.c | 22 ++++++++++++++++++++-- drivers/gpu/drm/nouveau/nv04_dac.c | 12 ++++++------ 4 files changed, 35 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index bbf19861b6c8..e82dff4008c9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -795,8 +795,10 @@ extern int nouveau_ioctl_getparam(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_setparam(struct drm_device *, void *data, struct drm_file *); -extern bool nouveau_wait_until(struct drm_device *, uint64_t timeout, - uint32_t reg, uint32_t mask, uint32_t val); +extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout, + uint32_t reg, uint32_t mask, uint32_t val); +extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout, + uint32_t reg, uint32_t mask, uint32_t val); extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); @@ -1434,7 +1436,9 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) } #define nv_wait(dev, reg, mask, val) \ - nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val)) + nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) +#define nv_wait_ne(dev, reg, mask, val) \ + nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) /* PRAMIN access */ static inline u32 nv_ri32(struct drm_device *dev, unsigned offset) diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c index 6ba640e7a7e9..053edf9d2f67 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hw.c +++ b/drivers/gpu/drm/nouveau/nouveau_hw.c @@ -999,8 +999,8 @@ nv_load_state_ext(struct drm_device *dev, int head, if (dev_priv->card_type == NV_10) { /* Not waiting for vertical retrace before modifying CRE_53/CRE_54 causes lockups. */ - nouveau_wait_until(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); - nouveau_wait_until(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); + nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); + nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); } wr_cio_state(dev, head, regp, NV_CIO_CRE_53); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e779e9320453..e0811f93243d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1126,8 +1126,9 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, } /* Wait until (value(reg) & mask) == val, up until timeout has hit */ -bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout, - uint32_t reg, uint32_t mask, uint32_t val) +bool +nouveau_wait_eq(struct drm_device *dev, uint64_t timeout, + uint32_t reg, uint32_t mask, uint32_t val) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; @@ -1141,6 +1142,23 @@ bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout, return false; } +/* Wait until (value(reg) & mask) != val, up until timeout has hit */ +bool +nouveau_wait_ne(struct drm_device *dev, uint64_t timeout, + uint32_t reg, uint32_t mask, uint32_t val) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + uint64_t start = ptimer->read(dev); + + do { + if ((nv_rd32(dev, reg) & mask) != val) + return true; + } while (ptimer->read(dev) - start < timeout); + + return false; +} + /* Waits for PGRAPH to go completely idle */ bool nouveau_wait_for_idle(struct drm_device *dev) { diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index ba6423f2ffcc..e000455e06d0 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -74,14 +74,14 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2]) * use a 10ms timeout (guards against crtc being inactive, in * which case blank state would never change) */ - if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, - 0x00000001, 0x00000000)) + if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, + 0x00000001, 0x00000000)) return -EBUSY; - if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, - 0x00000001, 0x00000001)) + if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, + 0x00000001, 0x00000001)) return -EBUSY; - if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, - 0x00000001, 0x00000000)) + if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, + 0x00000001, 0x00000000)) return -EBUSY; udelay(100); -- cgit v1.2.3 From a0fd9b9f68cd7a5952eae3c5b3c5a3bc0eadfd44 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 26 Nov 2010 10:32:22 +1000 Subject: drm/nouveau: no need to zero dma objects, we fill them completely anyway Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 3518ebba6fbd..5cc3f7e59fa1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -460,8 +460,7 @@ nv50_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, u64 size, struct drm_device *dev = chan->dev; int ret; - ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, pobj); + ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_FREE, pobj); if (ret) return ret; @@ -536,9 +535,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, flags0 |= (base & 0x00000fff) << 20; flags2 |= (base & 0xfffff000); - ret = nouveau_gpuobj_new(dev, chan, (dev_priv->card_type >= NV_40) ? - 32 : 16, 16, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &obj); + ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); if (ret) return ret; -- cgit v1.2.3 From 7a45d764a8e3177f0c9cd4a0be9f2ab7965e55cb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 22 Nov 2010 08:50:27 +1000 Subject: drm/nouveau: wrap calls to ttm_bo_validate() This will be used later to fixup bo.offset with a buffer's fixed GPU virtual address. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 20 +++++++++++++++++--- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_gem.c | 3 +-- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index f6f51b4259e7..a7883e7db344 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -242,7 +242,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) nouveau_bo_placement_set(nvbo, memtype, 0); - ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false); + ret = nouveau_bo_validate(nvbo, false, false, false); if (ret == 0) { switch (bo->mem.mem_type) { case TTM_PL_VRAM: @@ -278,7 +278,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); - ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false); + ret = nouveau_bo_validate(nvbo, false, false, false); if (ret == 0) { switch (bo->mem.mem_type) { case TTM_PL_VRAM: @@ -317,6 +317,20 @@ nouveau_bo_unmap(struct nouveau_bo *nvbo) ttm_bo_kunmap(&nvbo->kmap); } +int +nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu) +{ + int ret; + + ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, interruptible, + no_wait_reserve, no_wait_gpu); + if (ret) + return ret; + + return 0; +} + u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index) { @@ -937,7 +951,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) nvbo->placement.fpfn = 0; nvbo->placement.lpfn = dev_priv->fb_mappable_pages; nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0); - return ttm_bo_validate(bo, &nvbo->placement, false, true, false); + return nouveau_bo_validate(nvbo, false, true, false); } void diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e82dff4008c9..22abe8579912 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1285,6 +1285,8 @@ extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); extern void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *); +extern int nouveau_bo_validate(struct nouveau_bo *, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu); /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 9886b644f27d..0adb2a85c143 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -358,8 +358,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, } nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; - ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, - true, false, false); + ret = nouveau_bo_validate(nvbo, true, false, false); nvbo->channel = NULL; if (unlikely(ret)) { if (ret != -ERESTARTSYS) -- cgit v1.2.3 From a8b214f007e299225d3fcf10c46f7fc603c275fa Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 3 Dec 2010 09:05:20 +1000 Subject: drm/nouveau: fix use of drm_mm_node in semaphore object At some point in the future, this bo won't necessarily be backed by a drm_mm_node, so use the start/size fields of the ttm_mem_reg instead. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 3d50d5c3b0fe..01290d2952ae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -450,12 +450,11 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) /* Create a DMA object for the shared cross-channel sync area. */ if (USE_SEMA(dev)) { - struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node; + struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, mem->start << PAGE_SHIFT, - mem->size << PAGE_SHIFT, - NV_MEM_ACCESS_RW, + mem->size, NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM, &obj); if (ret) return ret; -- cgit v1.2.3 From 937c3471cc8b7ef8f9e382d9e4ec232db151ea7b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 8 Dec 2010 02:35:45 +0100 Subject: drm/nouveau: Avoid potential race between nouveau_fence_update() and context takedown. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 01290d2952ae..374a9793b85f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -77,14 +77,17 @@ nouveau_fence_update(struct nouveau_channel *chan) spin_lock(&chan->fence.lock); - if (USE_REFCNT(dev)) - sequence = nvchan_rd32(chan, 0x48); - else - sequence = atomic_read(&chan->fence.last_sequence_irq); - - if (chan->fence.sequence_ack == sequence) - goto out; - chan->fence.sequence_ack = sequence; + /* Fetch the last sequence if the channel is still up and running */ + if (likely(!list_empty(&chan->fence.pending))) { + if (USE_REFCNT(dev)) + sequence = nvchan_rd32(chan, 0x48); + else + sequence = atomic_read(&chan->fence.last_sequence_irq); + + if (chan->fence.sequence_ack == sequence) + goto out; + chan->fence.sequence_ack = sequence; + } list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { sequence = fence->sequence; -- cgit v1.2.3 From 573a2a37e8648a3249426c816f51e7ef50f6f73e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Aug 2010 15:26:04 +1000 Subject: drm/nv50: implement custom vram mm This is required on nv50 as we need to be able to have more precise control over physical VRAM allocations to avoid buffer corruption when using buffers of mixed memory types. This removes some nasty overallocation/alignment that we were previously using to "control" this problem. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 5 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 43 +----- drivers/gpu/drm/nouveau/nouveau_drv.h | 10 ++ drivers/gpu/drm/nouveau/nouveau_mem.c | 201 ++++++++++++++---------- drivers/gpu/drm/nouveau/nouveau_mm.c | 271 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_mm.h | 61 ++++++++ drivers/gpu/drm/nouveau/nv50_instmem.c | 1 + drivers/gpu/drm/nouveau/nv50_vram.c | 180 ++++++++++++++++++++++ 8 files changed, 650 insertions(+), 122 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nouveau_mm.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_mm.h create mode 100644 drivers/gpu/drm/nouveau/nv50_vram.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 7ea9a1154ca8..26fdd12561b6 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -9,7 +9,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \ nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ - nouveau_dp.o nouveau_ramht.o \ + nouveau_dp.o nouveau_ramht.o nouveau_mm.o \ nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ @@ -26,7 +26,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ nv10_gpio.o nv50_gpio.o \ nv50_calc.o \ - nv04_pm.o nv50_pm.o nva3_pm.o + nv04_pm.o nv50_pm.o nva3_pm.o \ + nv50_vram.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index a7883e7db344..5a71ca4346c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -57,42 +57,7 @@ nouveau_bo_fixup_align(struct drm_device *dev, { struct drm_nouveau_private *dev_priv = dev->dev_private; - /* - * Some of the tile_flags have a periodic structure of N*4096 bytes, - * align to to that as well as the page size. Align the size to the - * appropriate boundaries. This does imply that sizes are rounded up - * 3-7 pages, so be aware of this and do not waste memory by allocating - * many small buffers. - */ - if (dev_priv->card_type == NV_50) { - uint32_t block_size = dev_priv->vram_size >> 15; - int i; - - switch (tile_flags) { - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7a00: - if (is_power_of_2(block_size)) { - for (i = 1; i < 10; i++) { - *align = 12 * i * block_size; - if (!(*align % 65536)) - break; - } - } else { - for (i = 1; i < 10; i++) { - *align = 8 * i * block_size; - if (!(*align % 65536)) - break; - } - } - *size = roundup(*size, *align); - break; - default: - break; - } - - } else { + if (dev_priv->card_type < NV_50) { if (tile_mode) { if (dev_priv->chipset >= 0x40) { *align = 65536; @@ -115,7 +80,6 @@ nouveau_bo_fixup_align(struct drm_device *dev, /* ALIGN works only on powers of two. */ *size = roundup(*size, PAGE_SIZE); - if (dev_priv->card_type == NV_50) { *size = roundup(*size, 65536); *align = max(65536, *align); @@ -422,7 +386,10 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->default_caching = TTM_PL_FLAG_CACHED; break; case TTM_PL_VRAM: - man->func = &ttm_bo_manager_func; + if (dev_priv->card_type == NV_50) + man->func = &nouveau_vram_manager; + else + man->func = &ttm_bo_manager_func; man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 22abe8579912..1305e2c94201 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -66,6 +66,15 @@ struct nouveau_grctx; #define NV50_VM_BLOCK (512*1024*1024ULL) #define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK) +struct nouveau_vram { + struct drm_device *dev; + + struct list_head regions; + u32 memtype; + u64 offset; + u64 size; +}; + struct nouveau_tile_reg { bool used; uint32_t addr; @@ -821,6 +830,7 @@ extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt, uint64_t phys); extern void nv50_mem_vm_unbind(struct drm_device *, uint64_t virt, uint32_t size); +extern const struct ttm_mem_type_manager_func nouveau_vram_manager; /* nouveau_notifier.c */ extern int nouveau_notifier_init_channel(struct nouveau_channel *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 549f59052881..dbeb9e5f6b22 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -36,6 +36,7 @@ #include "nouveau_drv.h" #include "nouveau_pm.h" +#include "nouveau_mm.h" /* * NV10-NV40 tiling helpers @@ -333,61 +334,6 @@ nouveau_mem_detect_nforce(struct drm_device *dev) return 0; } -static void -nv50_vram_preinit(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - int i, parts, colbits, rowbitsa, rowbitsb, banks; - u64 rowsize, predicted; - u32 r0, r4, rt, ru; - - r0 = nv_rd32(dev, 0x100200); - r4 = nv_rd32(dev, 0x100204); - rt = nv_rd32(dev, 0x100250); - ru = nv_rd32(dev, 0x001540); - NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); - - for (i = 0, parts = 0; i < 8; i++) { - if (ru & (0x00010000 << i)) - parts++; - } - - colbits = (r4 & 0x0000f000) >> 12; - rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; - rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; - banks = ((r4 & 0x01000000) ? 8 : 4); - - rowsize = parts * banks * (1 << colbits) * 8; - predicted = rowsize << rowbitsa; - if (r0 & 0x00000004) - predicted += rowsize << rowbitsb; - - if (predicted != dev_priv->vram_size) { - NV_WARN(dev, "memory controller reports %dMiB VRAM\n", - (u32)(dev_priv->vram_size >> 20)); - NV_WARN(dev, "we calculated %dMiB VRAM\n", - (u32)(predicted >> 20)); - } - - dev_priv->vram_rblock_size = rowsize >> 12; - if (rt & 1) - dev_priv->vram_rblock_size *= 3; - - NV_DEBUG(dev, "rblock %lld bytes\n", - (u64)dev_priv->vram_rblock_size << 12); -} - -static void -nvaa_vram_preinit(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - - /* To our knowledge, there's no large scale reordering of pages - * that occurs on IGP chipsets. - */ - dev_priv->vram_rblock_size = 1; -} - static int nouveau_mem_detect(struct drm_device *dev) { @@ -404,22 +350,8 @@ nouveau_mem_detect(struct drm_device *dev) dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; } else if (dev_priv->card_type < NV_C0) { - dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); - dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; - dev_priv->vram_size &= 0xffffffff00ll; - - switch (dev_priv->chipset) { - case 0xaa: - case 0xac: - case 0xaf: - dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); - dev_priv->vram_sys_base <<= 12; - nvaa_vram_preinit(dev); - break; - default: - nv50_vram_preinit(dev); - break; - } + if (nv50_vram_init(dev)) + return -ENOMEM; } else { dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; dev_priv->vram_size *= nv_rd32(dev, 0x121c74); @@ -568,10 +500,6 @@ nouveau_mem_vram_init(struct drm_device *dev) if (ret) return ret; - ret = nouveau_mem_detect(dev); - if (ret) - return ret; - dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); ret = nouveau_ttm_global_init(dev_priv); @@ -587,13 +515,6 @@ nouveau_mem_vram_init(struct drm_device *dev) return ret; } - dev_priv->fb_available_size = dev_priv->vram_size; - dev_priv->fb_mappable_pages = dev_priv->fb_available_size; - if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) - dev_priv->fb_mappable_pages = - pci_resource_len(dev->pdev, 1); - dev_priv->fb_mappable_pages >>= PAGE_SHIFT; - /* reserve space at end of VRAM for PRAMIN */ if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 || dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) @@ -604,6 +525,17 @@ nouveau_mem_vram_init(struct drm_device *dev) else dev_priv->ramin_rsvd_vram = (512 * 1024); + /* initialise gpu-specific vram backend */ + ret = nouveau_mem_detect(dev); + if (ret) + return ret; + + dev_priv->fb_available_size = dev_priv->vram_size; + dev_priv->fb_mappable_pages = dev_priv->fb_available_size; + if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) + dev_priv->fb_mappable_pages = pci_resource_len(dev->pdev, 1); + dev_priv->fb_mappable_pages >>= PAGE_SHIFT; + dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; dev_priv->fb_aper_free = dev_priv->fb_available_size; @@ -820,3 +752,108 @@ nouveau_mem_timing_fini(struct drm_device *dev) kfree(mem->timing); } + +static int +nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long p_size) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct nouveau_mm *mm; + u32 b_size; + int ret; + + p_size = (p_size << PAGE_SHIFT) >> 12; + b_size = dev_priv->vram_rblock_size >> 12; + + ret = nouveau_mm_init(&mm, 0, p_size, b_size); + if (ret) + return ret; + + man->priv = mm; + return 0; +} + +static int +nouveau_vram_manager_fini(struct ttm_mem_type_manager *man) +{ + struct nouveau_mm *mm = man->priv; + int ret; + + ret = nouveau_mm_fini(&mm); + if (ret) + return ret; + + man->priv = NULL; + return 0; +} + +static void +nouveau_vram_manager_del(struct ttm_mem_type_manager *man, + struct ttm_mem_reg *mem) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct drm_device *dev = dev_priv->dev; + + nv50_vram_del(dev, (struct nouveau_vram **)&mem->mm_node); +} + +static int +nouveau_vram_manager_new(struct ttm_mem_type_manager *man, + struct ttm_buffer_object *bo, + struct ttm_placement *placement, + struct ttm_mem_reg *mem) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct drm_device *dev = dev_priv->dev; + struct nouveau_bo *nvbo = nouveau_bo(bo); + struct nouveau_vram *vram; + int ret; + + ret = nv50_vram_new(dev, mem->num_pages << PAGE_SHIFT, 65536, 0, + (nvbo->tile_flags >> 8) & 0x7f, &vram); + if (ret) + return ret; + + mem->mm_node = vram; + mem->start = vram->offset >> PAGE_SHIFT; + return 0; +} + +void +nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) +{ + struct ttm_bo_global *glob = man->bdev->glob; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *r; + u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {}; + int i; + + mutex_lock(&mm->mutex); + list_for_each_entry(r, &mm->nodes, nl_entry) { + printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n", + prefix, r->free ? "free" : "used", r->type, + ((u64)r->offset << 12), + (((u64)r->offset + r->length) << 12)); + total += r->length; + ttotal[r->type] += r->length; + if (r->free) + tfree[r->type] += r->length; + else + tused[r->type] += r->length; + } + mutex_unlock(&mm->mutex); + + printk(KERN_DEBUG "%s total: 0x%010llx\n", prefix, total << 12); + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%s type %d: 0x%010llx, " + "used 0x%010llx, free 0x%010llx\n", prefix, + i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12); + } +} + +const struct ttm_mem_type_manager_func nouveau_vram_manager = { + nouveau_vram_manager_init, + nouveau_vram_manager_fini, + nouveau_vram_manager_new, + nouveau_vram_manager_del, + nouveau_vram_manager_debug +}; diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c new file mode 100644 index 000000000000..cdbb11eb701b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_mm.c @@ -0,0 +1,271 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_mm.h" + +static inline void +region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) +{ + list_del(&a->nl_entry); + list_del(&a->fl_entry); + kfree(a); +} + +static struct nouveau_mm_node * +region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) +{ + struct nouveau_mm_node *b; + + if (a->length == size) + return a; + + b = kmalloc(sizeof(*b), GFP_KERNEL); + if (unlikely(b == NULL)) + return NULL; + + b->offset = a->offset; + b->length = size; + b->free = a->free; + b->type = a->type; + a->offset += size; + a->length -= size; + list_add_tail(&b->nl_entry, &a->nl_entry); + if (b->free) + list_add_tail(&b->fl_entry, &a->fl_entry); + return b; +} + +static struct nouveau_mm_node * +nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this) +{ + struct nouveau_mm_node *prev, *next; + + /* try to merge with free adjacent entries of same type */ + prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry); + if (this->nl_entry.prev != &rmm->nodes) { + if (prev->free && prev->type == this->type) { + prev->length += this->length; + region_put(rmm, this); + this = prev; + } + } + + next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); + if (this->nl_entry.next != &rmm->nodes) { + if (next->free && next->type == this->type) { + next->offset = this->offset; + next->length += this->length; + region_put(rmm, this); + this = next; + } + } + + return this; +} + +void +nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) +{ + u32 block_s, block_l; + + this->free = true; + list_add(&this->fl_entry, &rmm->free); + this = nouveau_mm_merge(rmm, this); + + /* any entirely free blocks now? we'll want to remove typing + * on them now so they can be use for any memory allocation + */ + block_s = roundup(this->offset, rmm->block_size); + if (block_s + rmm->block_size > this->offset + this->length) + return; + + /* split off any still-typed region at the start */ + if (block_s != this->offset) { + if (!region_split(rmm, this, block_s - this->offset)) + return; + } + + /* split off the soon-to-be-untyped block(s) */ + block_l = rounddown(this->length, rmm->block_size); + if (block_l != this->length) { + this = region_split(rmm, this, block_l); + if (!this) + return; + } + + /* mark as having no type, and retry merge with any adjacent + * untyped blocks + */ + this->type = 0; + nouveau_mm_merge(rmm, this); +} + +int +nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, + u32 align, struct nouveau_mm_node **pnode) +{ + struct nouveau_mm_node *this, *tmp, *next; + u32 splitoff, avail, alloc; + + list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) { + next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); + if (this->nl_entry.next == &rmm->nodes) + next = NULL; + + /* skip wrongly typed blocks */ + if (this->type && this->type != type) + continue; + + /* account for alignment */ + splitoff = this->offset & (align - 1); + if (splitoff) + splitoff = align - splitoff; + + if (this->length <= splitoff) + continue; + + /* determine total memory available from this, and + * the next block (if appropriate) + */ + avail = this->length; + if (next && next->free && (!next->type || next->type == type)) + avail += next->length; + + avail -= splitoff; + + /* determine allocation size */ + if (size_nc) { + alloc = min(avail, size); + alloc = rounddown(alloc, size_nc); + if (alloc == 0) + continue; + } else { + alloc = size; + if (avail < alloc) + continue; + } + + /* untyped block, split off a chunk that's a multiple + * of block_size and type it + */ + if (!this->type) { + u32 block = roundup(alloc + splitoff, rmm->block_size); + if (this->length < block) + continue; + + this = region_split(rmm, this, block); + if (!this) + return -ENOMEM; + + this->type = type; + } + + /* stealing memory from adjacent block */ + if (alloc > this->length) { + u32 amount = alloc - (this->length - splitoff); + + if (!next->type) { + amount = roundup(amount, rmm->block_size); + + next = region_split(rmm, next, amount); + if (!next) + return -ENOMEM; + + next->type = type; + } + + this->length += amount; + next->offset += amount; + next->length -= amount; + if (!next->length) { + list_del(&next->nl_entry); + list_del(&next->fl_entry); + kfree(next); + } + } + + if (splitoff) { + if (!region_split(rmm, this, splitoff)) + return -ENOMEM; + } + + this = region_split(rmm, this, alloc); + if (this == NULL) + return -ENOMEM; + + this->free = false; + list_del(&this->fl_entry); + *pnode = this; + return 0; + } + + return -ENOMEM; +} + +int +nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) +{ + struct nouveau_mm *rmm; + struct nouveau_mm_node *heap; + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return -ENOMEM; + heap->free = true; + heap->offset = roundup(offset, block); + heap->length = rounddown(offset + length, block) - heap->offset; + + rmm = kzalloc(sizeof(*rmm), GFP_KERNEL); + if (!rmm) { + kfree(heap); + return -ENOMEM; + } + rmm->block_size = block; + mutex_init(&rmm->mutex); + INIT_LIST_HEAD(&rmm->nodes); + INIT_LIST_HEAD(&rmm->free); + list_add(&heap->nl_entry, &rmm->nodes); + list_add(&heap->fl_entry, &rmm->free); + + *prmm = rmm; + return 0; +} + +int +nouveau_mm_fini(struct nouveau_mm **prmm) +{ + struct nouveau_mm *rmm = *prmm; + struct nouveau_mm_node *heap = + list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry); + + if (!list_is_singular(&rmm->nodes)) + return -EBUSY; + + kfree(heap); + kfree(rmm); + *prmm = NULL; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h new file mode 100644 index 000000000000..7e8f8bd86d47 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h @@ -0,0 +1,61 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#ifndef __NOUVEAU_REGION_H__ +#define __NOUVEAU_REGION_H__ + +struct nouveau_mm_node { + struct list_head nl_entry; + struct list_head fl_entry; + struct list_head rl_entry; + + bool free; + int type; + + u32 offset; + u32 length; +}; + +struct nouveau_mm { + struct list_head nodes; + struct list_head free; + + struct mutex mutex; + + u32 block_size; +}; + +int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block); +int nouveau_mm_fini(struct nouveau_mm **); +int nouveau_mm_pre(struct nouveau_mm *); +int nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc, + u32 align, struct nouveau_mm_node **); +void nouveau_mm_put(struct nouveau_mm *, struct nouveau_mm_node *); + +int nv50_vram_init(struct drm_device *); +int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, + u32 memtype, struct nouveau_vram **); +void nv50_vram_del(struct drm_device *, struct nouveau_vram **); + +#endif diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 87160952a30b..1e7d50397e4a 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -325,6 +325,7 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) 0, 0x0000, true, false, &node->vram); if (ret) { NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); + WARN_ON(1); return ret; } diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c new file mode 100644 index 000000000000..6e753356cd94 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv50_vram.c @@ -0,0 +1,180 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_mm.h" + +static int types[0x80] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 +}; + +void +nv50_vram_del(struct drm_device *dev, struct nouveau_vram **pvram) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *this; + struct nouveau_vram *vram; + + vram = *pvram; + *pvram = NULL; + if (unlikely(vram == NULL)) + return; + + mutex_lock(&mm->mutex); + while (!list_empty(&vram->regions)) { + this = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); + + list_del(&this->rl_entry); + nouveau_mm_put(mm, this); + } + mutex_unlock(&mm->mutex); + + kfree(vram); +} + +int +nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, + u32 type, struct nouveau_vram **pvram) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *r; + struct nouveau_vram *vram; + int ret; + + if (!types[type]) + return -EINVAL; + size >>= 12; + align >>= 12; + size_nc >>= 12; + + vram = kzalloc(sizeof(*vram), GFP_KERNEL); + if (!vram) + return -ENOMEM; + + INIT_LIST_HEAD(&vram->regions); + vram->dev = dev_priv->dev; + vram->memtype = type; + vram->size = size; + + mutex_lock(&mm->mutex); + do { + ret = nouveau_mm_get(mm, types[type], size, size_nc, align, &r); + if (ret) { + mutex_unlock(&mm->mutex); + nv50_vram_del(dev, &vram); + return ret; + } + + list_add_tail(&r->rl_entry, &vram->regions); + size -= r->length; + } while (size); + mutex_unlock(&mm->mutex); + + r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); + vram->offset = (u64)r->offset << 12; + *pvram = vram; + return 0; +} + +static u32 +nv50_vram_rblock(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i, parts, colbits, rowbitsa, rowbitsb, banks; + u64 rowsize, predicted; + u32 r0, r4, rt, ru, rblock_size; + + r0 = nv_rd32(dev, 0x100200); + r4 = nv_rd32(dev, 0x100204); + rt = nv_rd32(dev, 0x100250); + ru = nv_rd32(dev, 0x001540); + NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); + + for (i = 0, parts = 0; i < 8; i++) { + if (ru & (0x00010000 << i)) + parts++; + } + + colbits = (r4 & 0x0000f000) >> 12; + rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; + rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; + banks = ((r4 & 0x01000000) ? 8 : 4); + + rowsize = parts * banks * (1 << colbits) * 8; + predicted = rowsize << rowbitsa; + if (r0 & 0x00000004) + predicted += rowsize << rowbitsb; + + if (predicted != dev_priv->vram_size) { + NV_WARN(dev, "memory controller reports %dMiB VRAM\n", + (u32)(dev_priv->vram_size >> 20)); + NV_WARN(dev, "we calculated %dMiB VRAM\n", + (u32)(predicted >> 20)); + } + + rblock_size = rowsize; + if (rt & 1) + rblock_size *= 3; + + NV_DEBUG(dev, "rblock %d bytes\n", rblock_size); + return rblock_size; +} + +int +nv50_vram_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + dev_priv->vram_size = nv_rd32(dev, 0x10020c); + dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; + dev_priv->vram_size &= 0xffffffff00ULL; + + switch (dev_priv->chipset) { + case 0xaa: + case 0xac: + case 0xaf: + dev_priv->vram_sys_base = (u64)nv_rd32(dev, 0x100e10) << 12; + dev_priv->vram_rblock_size = 4096; + break; + default: + dev_priv->vram_rblock_size = nv50_vram_rblock(dev); + break; + } + + return 0; +} -- cgit v1.2.3 From a11c3198c9ba38d81e25b65e3908d531feba1372 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 27 Aug 2010 10:00:25 +1000 Subject: drm/nv50: import new vm code Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 5 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 9 +- drivers/gpu/drm/nouveau/nouveau_mem.c | 5 +- drivers/gpu/drm/nouveau/nouveau_object.c | 2 +- drivers/gpu/drm/nouveau/nouveau_vm.c | 421 +++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_vm.h | 107 ++++++++ drivers/gpu/drm/nouveau/nv50_fifo.c | 3 +- drivers/gpu/drm/nouveau/nv50_graph.c | 5 +- drivers/gpu/drm/nouveau/nv50_instmem.c | 12 +- drivers/gpu/drm/nouveau/nv50_vm.c | 164 ++++++++++++ drivers/gpu/drm/nouveau/nv84_crypt.c | 3 +- 11 files changed, 714 insertions(+), 22 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nouveau_vm.c create mode 100644 drivers/gpu/drm/nouveau/nouveau_vm.h create mode 100644 drivers/gpu/drm/nouveau/nv50_vm.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 26fdd12561b6..b1d8941e04d8 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -9,8 +9,9 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \ nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ - nouveau_dp.o nouveau_ramht.o nouveau_mm.o \ + nouveau_dp.o nouveau_ramht.o \ nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \ + nouveau_mm.o nouveau_vm.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \ @@ -27,7 +28,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv10_gpio.o nv50_gpio.o \ nv50_calc.o \ nv04_pm.o nv50_pm.o nva3_pm.o \ - nv50_vram.o + nv50_vram.o nv50_vm.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1305e2c94201..ce1dde4a65d6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -153,6 +153,7 @@ enum nouveau_flags { #define NVOBJ_ENGINE_DISPLAY 0xcafe0001 #define NVOBJ_ENGINE_INT 0xdeadbeef +#define NVOBJ_FLAG_DONT_MAP (1 << 0) #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) #define NVOBJ_FLAG_ZERO_FREE (1 << 2) @@ -1213,7 +1214,6 @@ extern int nv50_instmem_map(struct nouveau_gpuobj *); extern void nv50_instmem_unmap(struct nouveau_gpuobj *); extern void nv50_instmem_flush(struct drm_device *); extern void nv84_instmem_flush(struct drm_device *); -extern void nv50_vm_flush(struct drm_device *, int engine); /* nvc0_instmem.c */ extern int nvc0_instmem_init(struct drm_device *); @@ -1564,10 +1564,11 @@ nv_match_device(struct drm_device *dev, unsigned device, } /* memory type/access flags, do not match hardware values */ -#define NV_MEM_ACCESS_RO 1 -#define NV_MEM_ACCESS_WO 2 +#define NV_MEM_ACCESS_RO 1 +#define NV_MEM_ACCESS_WO 2 #define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO) -#define NV_MEM_ACCESS_VM 4 +#define NV_MEM_ACCESS_SYS 4 +#define NV_MEM_ACCESS_VM 8 #define NV_MEM_TARGET_VRAM 0 #define NV_MEM_TARGET_PCI 1 diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index dbeb9e5f6b22..2d02401e8227 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -37,6 +37,7 @@ #include "nouveau_drv.h" #include "nouveau_pm.h" #include "nouveau_mm.h" +#include "nouveau_vm.h" /* * NV10-NV40 tiling helpers @@ -201,7 +202,7 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, dev_priv->engine.instmem.flush(dev); dev_priv->engine.fifo.tlb_flush(dev); dev_priv->engine.graph.tlb_flush(dev); - nv50_vm_flush(dev, 6); + nv50_vm_flush_engine(dev, 6); return 0; } @@ -234,7 +235,7 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) dev_priv->engine.instmem.flush(dev); dev_priv->engine.fifo.tlb_flush(dev); dev_priv->engine.graph.tlb_flush(dev); - nv50_vm_flush(dev, 6); + nv50_vm_flush_engine(dev, 6); } /* diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 5cc3f7e59fa1..dd1859f7d8b0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -213,7 +213,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, } ret = -ENOSYS; - if (dev_priv->ramin_available) + if (!(flags & NVOBJ_FLAG_DONT_MAP)) ret = instmem->map(gpuobj); if (ret) gpuobj->pinst = ~0; diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c new file mode 100644 index 000000000000..07ab1749cf7d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_vm.c @@ -0,0 +1,421 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_mm.h" +#include "nouveau_vm.h" + +void +nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) +{ + struct nouveau_vm *vm = vma->vm; + struct nouveau_mm_node *r; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 pde = (offset >> vm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vm->pgt_bits - bits); + u32 end, len; + + list_for_each_entry(r, &vram->regions, rl_entry) { + u64 phys = (u64)r->offset << 12; + u32 num = r->length >> bits; + + while (num) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj; + + end = (pte + num); + if (unlikely(end >= max)) + end = max; + len = end - pte; + + vm->map(vma, pgt, vram, pte, len, phys); + + num -= len; + pte += len; + if (unlikely(end >= max)) { + pde++; + pte = 0; + } + } + } + + vm->flush(vm); +} + +void +nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_vram *vram) +{ + nouveau_vm_map_at(vma, 0, vram); +} + +void +nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, + dma_addr_t *list) +{ + struct nouveau_vm *vm = vma->vm; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 num = length >> vma->node->type; + u32 pde = (offset >> vm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vm->pgt_bits - bits); + u32 end, len; + + while (num) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj; + + end = (pte + num); + if (unlikely(end >= max)) + end = max; + len = end - pte; + + vm->map_sg(vma, pgt, pte, list, len); + + num -= len; + pte += len; + list += len; + if (unlikely(end >= max)) { + pde++; + pte = 0; + } + } + + vm->flush(vm); +} + +void +nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length) +{ + struct nouveau_vm *vm = vma->vm; + u32 offset = vma->node->offset + (delta >> 12); + u32 bits = vma->node->type - 12; + u32 num = length >> vma->node->type; + u32 pde = (offset >> vm->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits; + u32 max = 1 << (vm->pgt_bits - bits); + u32 end, len; + + while (num) { + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj; + + end = (pte + num); + if (unlikely(end >= max)) + end = max; + len = end - pte; + + vm->unmap(pgt, pte, len); + + num -= len; + pte += len; + if (unlikely(end >= max)) { + pde++; + pte = 0; + } + } + + vm->flush(vm); +} + +void +nouveau_vm_unmap(struct nouveau_vma *vma) +{ + nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12); +} + +static void +nouveau_vm_unmap_pgt(struct nouveau_vm *vm, u32 fpde, u32 lpde) +{ + struct nouveau_vm_pgd *vpgd; + struct nouveau_vm_pgt *vpgt; + struct nouveau_gpuobj *pgt; + u32 pde; + + for (pde = fpde; pde <= lpde; pde++) { + vpgt = &vm->pgt[pde - vm->fpde]; + if (--vpgt->refcount) + continue; + + list_for_each_entry(vpgd, &vm->pgd_list, head) { + vm->unmap_pgt(vpgd->obj, pde); + } + + pgt = vpgt->obj; + vpgt->obj = NULL; + + mutex_unlock(&vm->mm->mutex); + nouveau_gpuobj_ref(NULL, &pgt); + mutex_lock(&vm->mm->mutex); + } +} + +static int +nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) +{ + struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; + struct nouveau_vm_pgd *vpgd; + struct nouveau_gpuobj *pgt; + u32 pgt_size; + int ret; + + pgt_size = (1 << (vm->pgt_bits + 12)) >> type; + pgt_size *= 8; + + mutex_unlock(&vm->mm->mutex); + ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &pgt); + mutex_lock(&vm->mm->mutex); + if (unlikely(ret)) + return ret; + + /* someone beat us to filling the PDE while we didn't have the lock */ + if (unlikely(vpgt->refcount++)) { + mutex_unlock(&vm->mm->mutex); + nouveau_gpuobj_ref(NULL, &pgt); + mutex_lock(&vm->mm->mutex); + return 0; + } + + list_for_each_entry(vpgd, &vm->pgd_list, head) { + vm->map_pgt(vpgd->obj, type, pde, pgt); + } + + vpgt->page_shift = type; + vpgt->obj = pgt; + return 0; +} + +int +nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, + u32 access, struct nouveau_vma *vma) +{ + u32 align = (1 << page_shift) >> 12; + u32 msize = size >> 12; + u32 fpde, lpde, pde; + int ret; + + mutex_lock(&vm->mm->mutex); + ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node); + if (unlikely(ret != 0)) { + mutex_unlock(&vm->mm->mutex); + return ret; + } + + fpde = (vma->node->offset >> vm->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; + for (pde = fpde; pde <= lpde; pde++) { + struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; + + if (likely(vpgt->refcount)) { + vpgt->refcount++; + continue; + } + + ret = nouveau_vm_map_pgt(vm, pde, vma->node->type); + if (ret) { + if (pde != fpde) + nouveau_vm_unmap_pgt(vm, fpde, pde - 1); + nouveau_mm_put(vm->mm, vma->node); + mutex_unlock(&vm->mm->mutex); + vma->node = NULL; + return ret; + } + } + mutex_unlock(&vm->mm->mutex); + + vma->vm = vm; + vma->offset = (u64)vma->node->offset << 12; + vma->access = access; + return 0; +} + +void +nouveau_vm_put(struct nouveau_vma *vma) +{ + struct nouveau_vm *vm = vma->vm; + u32 fpde, lpde; + + if (unlikely(vma->node == NULL)) + return; + fpde = (vma->node->offset >> vm->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; + + mutex_lock(&vm->mm->mutex); + nouveau_mm_put(vm->mm, vma->node); + vma->node = NULL; + nouveau_vm_unmap_pgt(vm, fpde, lpde); + mutex_unlock(&vm->mm->mutex); +} + +int +nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, + u8 pgt_bits, u8 spg_shift, u8 lpg_shift, + struct nouveau_vm **pvm) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_vm *vm; + u64 mm_length = (offset + length) - mm_offset; + u32 block; + int ret; + + vm = kzalloc(sizeof(*vm), GFP_KERNEL); + if (!vm) + return -ENOMEM; + + if (dev_priv->card_type == NV_50) { + vm->map_pgt = nv50_vm_map_pgt; + vm->unmap_pgt = nv50_vm_unmap_pgt; + vm->map = nv50_vm_map; + vm->map_sg = nv50_vm_map_sg; + vm->unmap = nv50_vm_unmap; + vm->flush = nv50_vm_flush; + } else { + kfree(vm); + return -ENOSYS; + } + + vm->fpde = offset >> pgt_bits; + vm->lpde = (offset + length - 1) >> pgt_bits; + vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL); + if (!vm->pgt) { + kfree(vm); + return -ENOMEM; + } + + INIT_LIST_HEAD(&vm->pgd_list); + vm->dev = dev; + vm->refcount = 1; + vm->pgt_bits = pgt_bits - 12; + vm->spg_shift = spg_shift; + vm->lpg_shift = lpg_shift; + + block = (1 << pgt_bits); + if (length < block) + block = length; + + ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12, + block >> 12); + if (ret) { + kfree(vm); + return ret; + } + + *pvm = vm; + return 0; +} + +static int +nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) +{ + struct nouveau_vm_pgd *vpgd; + int i; + + if (!pgd) + return 0; + + vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL); + if (!vpgd) + return -ENOMEM; + + nouveau_gpuobj_ref(pgd, &vpgd->obj); + + mutex_lock(&vm->mm->mutex); + for (i = vm->fpde; i <= vm->lpde; i++) { + struct nouveau_vm_pgt *vpgt = &vm->pgt[i - vm->fpde]; + + if (!vpgt->obj) { + vm->unmap_pgt(pgd, i); + continue; + } + + vm->map_pgt(pgd, vpgt->page_shift, i, vpgt->obj); + } + list_add(&vpgd->head, &vm->pgd_list); + mutex_unlock(&vm->mm->mutex); + return 0; +} + +static void +nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) +{ + struct nouveau_vm_pgd *vpgd, *tmp; + + if (!pgd) + return; + + mutex_lock(&vm->mm->mutex); + list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { + if (vpgd->obj != pgd) + continue; + + list_del(&vpgd->head); + nouveau_gpuobj_ref(NULL, &vpgd->obj); + kfree(vpgd); + } + mutex_unlock(&vm->mm->mutex); +} + +static void +nouveau_vm_del(struct nouveau_vm *vm) +{ + struct nouveau_vm_pgd *vpgd, *tmp; + + list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { + nouveau_vm_unlink(vm, vpgd->obj); + } + WARN_ON(nouveau_mm_fini(&vm->mm) != 0); + + kfree(vm->pgt); + kfree(vm); +} + +int +nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr, + struct nouveau_gpuobj *pgd) +{ + struct nouveau_vm *vm; + int ret; + + vm = ref; + if (vm) { + ret = nouveau_vm_link(vm, pgd); + if (ret) + return ret; + + vm->refcount++; + } + + vm = *ptr; + *ptr = ref; + + if (vm) { + nouveau_vm_unlink(vm, pgd); + + if (--vm->refcount == 0) + nouveau_vm_del(vm); + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h new file mode 100644 index 000000000000..b6755cfa7b71 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_vm.h @@ -0,0 +1,107 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#ifndef __NOUVEAU_VM_H__ +#define __NOUVEAU_VM_H__ + +#include "drmP.h" + +#include "nouveau_drv.h" +#include "nouveau_mm.h" + +struct nouveau_vm_pgt { + struct nouveau_gpuobj *obj; + u32 page_shift; + u32 refcount; +}; + +struct nouveau_vm_pgd { + struct list_head head; + struct nouveau_gpuobj *obj; +}; + +struct nouveau_vma { + struct nouveau_vm *vm; + struct nouveau_mm_node *node; + u64 offset; + u32 access; +}; + +struct nouveau_vm { + struct drm_device *dev; + struct nouveau_mm *mm; + int refcount; + + struct list_head pgd_list; + atomic_t pgraph_refs; + atomic_t pcrypt_refs; + + struct nouveau_vm_pgt *pgt; + u32 fpde; + u32 lpde; + + u32 pgt_bits; + u8 spg_shift; + u8 lpg_shift; + + void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 type, u32 pde, + struct nouveau_gpuobj *pgt); + void (*unmap_pgt)(struct nouveau_gpuobj *pgd, u32 pde); + void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *, + struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); + void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *, + u32 pte, dma_addr_t *, u32 cnt); + void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt); + void (*flush)(struct nouveau_vm *); +}; + +/* nouveau_vm.c */ +int nouveau_vm_new(struct drm_device *, u64 offset, u64 length, u64 mm_offset, + u8 pgt_bits, u8 spg_shift, u8 lpg_shift, + struct nouveau_vm **); +int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **, + struct nouveau_gpuobj *pgd); +int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift, + u32 access, struct nouveau_vma *); +void nouveau_vm_put(struct nouveau_vma *); +void nouveau_vm_map(struct nouveau_vma *, struct nouveau_vram *); +void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_vram *); +void nouveau_vm_unmap(struct nouveau_vma *); +void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length); +void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, + dma_addr_t *); + +/* nv50_vm.c */ +void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 type, u32 pde, + struct nouveau_gpuobj *pgt); +void nv50_vm_unmap_pgt(struct nouveau_gpuobj *pgd, u32 pde); +void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, + struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); +void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, + u32 pte, dma_addr_t *, u32 cnt); +void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); +void nv50_vm_flush(struct nouveau_vm *); +void nv50_vm_flush_engine(struct drm_device *, int engine); + +#endif diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index 7add3dfde3df..8dd04c5dac67 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -28,6 +28,7 @@ #include "drm.h" #include "nouveau_drv.h" #include "nouveau_ramht.h" +#include "nouveau_vm.h" static void nv50_fifo_playlist_update(struct drm_device *dev) @@ -498,5 +499,5 @@ nv50_fifo_unload_context(struct drm_device *dev) void nv50_fifo_tlb_flush(struct drm_device *dev) { - nv50_vm_flush(dev, 5); + nv50_vm_flush_engine(dev, 5); } diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index b3900788c66d..f5fd1b296d27 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -30,6 +30,7 @@ #include "nouveau_ramht.h" #include "nouveau_grctx.h" #include "nouveau_dma.h" +#include "nouveau_vm.h" #include "nv50_evo.h" static int nv50_graph_register(struct drm_device *); @@ -468,7 +469,7 @@ nv50_graph_register(struct drm_device *dev) void nv50_graph_tlb_flush(struct drm_device *dev) { - nv50_vm_flush(dev, 0); + nv50_vm_flush_engine(dev, 0); } void @@ -511,7 +512,7 @@ nv86_graph_tlb_flush(struct drm_device *dev) nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); } - nv50_vm_flush(dev, 0); + nv50_vm_flush_engine(dev, 0); nv_mask(dev, 0x400500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 1e7d50397e4a..4eb2f0835e27 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -27,7 +27,9 @@ #include "drmP.h" #include "drm.h" + #include "nouveau_drv.h" +#include "nouveau_vm.h" struct nv50_instmem_priv { uint32_t save1700[5]; /* 0x1700->0x1710 */ @@ -404,7 +406,7 @@ nv50_instmem_map(struct nouveau_gpuobj *gpuobj) } dev_priv->engine.instmem.flush(dev); - nv50_vm_flush(dev, 6); + nv50_vm_flush_engine(dev, 6); node->ramin = ramin; gpuobj->pinst = ramin->start; @@ -454,11 +456,3 @@ nv84_instmem_flush(struct drm_device *dev) NV_ERROR(dev, "PRAMIN flush timeout\n"); } -void -nv50_vm_flush(struct drm_device *dev, int engine) -{ - nv_wr32(dev, 0x100c80, (engine << 16) | 1); - if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) - NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); -} - diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c new file mode 100644 index 000000000000..ab6c3d0ce32e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -0,0 +1,164 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" +#include "nouveau_vm.h" + +void +nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 type, u32 pde, + struct nouveau_gpuobj *pgt) +{ + struct drm_nouveau_private *dev_priv = pgd->dev->dev_private; + u32 coverage = (pgt->size >> 3) << type; + u64 phys; + + phys = pgt->vinst; + phys |= 0x01; /* present */ + phys |= (type == 12) ? 0x02 : 0x00; /* 4KiB pages */ + if (dev_priv->vram_sys_base) { + phys += dev_priv->vram_sys_base; + phys |= 0x30; + } + + if (coverage <= 32 * 1024 * 1024) + phys |= 0x60; + else if (coverage <= 64 * 1024 * 1024) + phys |= 0x40; + else if (coverage < 128 * 1024 * 1024) + phys |= 0x20; + + nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); + nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); +} + +void +nv50_vm_unmap_pgt(struct nouveau_gpuobj *pgd, u32 pde) +{ + nv_wo32(pgd, (pde * 8) + 0, 0x00000000); + nv_wo32(pgd, (pde * 8) + 4, 0xdeadcafe); +} + +static inline u64 +nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + u64 phys, u32 memtype, u32 target) +{ + struct drm_nouveau_private *dev_priv = pgt->dev->dev_private; + + phys |= 1; /* present */ + phys |= (u64)memtype << 40; + + /* IGPs don't have real VRAM, re-target to stolen system memory */ + if (target == 0 && dev_priv->vram_sys_base) { + phys += dev_priv->vram_sys_base; + target = 3; + } + + phys |= target << 4; + + if (vma->access & NV_MEM_ACCESS_SYS) + phys |= (1 << 6); + + if (!(vma->access & NV_MEM_ACCESS_WO)) + phys |= (1 << 3); + + return phys; +} + +void +nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) +{ + u32 block, i; + + phys = nv50_vm_addr(vma, pgt, phys, mem->memtype, 0); + pte <<= 3; + cnt <<= 3; + + while (cnt) { + u32 offset_h = upper_32_bits(phys); + u32 offset_l = lower_32_bits(phys); + + for (i = 7; i >= 0; i--) { + block = 1 << (i + 3); + if (cnt >= block && !(pte & (block - 1))) + break; + } + offset_l |= (i << 7); + + phys += block << (vma->node->type - 3); + cnt -= block; + + while (block) { + nv_wo32(pgt, pte + 0, offset_l); + nv_wo32(pgt, pte + 4, offset_h); + pte += 8; + block -= 8; + } + } +} + +void +nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + u32 pte, dma_addr_t *list, u32 cnt) +{ + pte <<= 3; + while (cnt--) { + u64 phys = nv50_vm_addr(vma, pgt, (u64)*list++, 0, 2); + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + pte += 8; + } +} + +void +nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + pte <<= 3; + while (cnt--) { + nv_wo32(pgt, pte + 0, 0x00000000); + nv_wo32(pgt, pte + 4, 0x00000000); + pte += 8; + } +} + +void +nv50_vm_flush(struct nouveau_vm *vm) +{ + struct drm_nouveau_private *dev_priv = vm->dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + + pinstmem->flush(vm->dev); + + nv50_vm_flush_engine(vm->dev, 6); +} + +void +nv50_vm_flush_engine(struct drm_device *dev, int engine) +{ + nv_wr32(dev, 0x100c80, (engine << 16) | 1); + if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) + NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); +} diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c index 780bb1d66f95..a333e5905346 100644 --- a/drivers/gpu/drm/nouveau/nv84_crypt.c +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -25,6 +25,7 @@ #include "drmP.h" #include "nouveau_drv.h" #include "nouveau_util.h" +#include "nouveau_vm.h" static void nv84_crypt_isr(struct drm_device *); @@ -84,7 +85,7 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan) void nv84_crypt_tlb_flush(struct drm_device *dev) { - nv50_vm_flush(dev, 0x0a); + nv50_vm_flush_engine(dev, 0x0a); } int -- cgit v1.2.3 From f869ef882382a4b6cb42d259e399aeec3781d4bb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 11:53:16 +1000 Subject: drm/nv50: implement BAR1/BAR3 management on top of new VM code Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 46 +++++- drivers/gpu/drm/nouveau/nouveau_drv.h | 10 ++ drivers/gpu/drm/nouveau/nv50_instmem.c | 258 ++++++++++++++------------------- drivers/gpu/drm/nouveau/nv50_vm.c | 1 - 4 files changed, 162 insertions(+), 153 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5a71ca4346c8..4d142031d542 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -32,6 +32,8 @@ #include "nouveau_drm.h" #include "nouveau_drv.h" #include "nouveau_dma.h" +#include "nouveau_mm.h" +#include "nouveau_vm.h" #include #include @@ -386,10 +388,13 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->default_caching = TTM_PL_FLAG_CACHED; break; case TTM_PL_VRAM: - if (dev_priv->card_type == NV_50) + if (dev_priv->card_type == NV_50) { man->func = &nouveau_vram_manager; - else + man->io_reserve_fastpath = false; + man->use_io_reserve_lru = true; + } else { man->func = &ttm_bo_manager_func; + } man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | @@ -858,6 +863,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev); struct drm_device *dev = dev_priv->dev; + int ret; mem->bus.addr = NULL; mem->bus.offset = 0; @@ -880,9 +886,32 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) #endif break; case TTM_PL_VRAM: - mem->bus.offset = mem->start << PAGE_SHIFT; + { + struct nouveau_vram *vram = mem->mm_node; + + if (!dev_priv->bar1_vm) { + mem->bus.offset = mem->start << PAGE_SHIFT; + mem->bus.base = pci_resource_start(dev->pdev, 1); + mem->bus.is_iomem = true; + break; + } + + ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, 12, + NV_MEM_ACCESS_RW, &vram->bar_vma); + if (ret) + return ret; + + nouveau_vm_map(&vram->bar_vma, vram); + if (ret) { + nouveau_vm_put(&vram->bar_vma); + return ret; + } + + mem->bus.offset = vram->bar_vma.offset; + mem->bus.offset -= 0x0020000000ULL; mem->bus.base = pci_resource_start(dev->pdev, 1); mem->bus.is_iomem = true; + } break; default: return -EINVAL; @@ -893,6 +922,17 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) static void nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { + struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev); + struct nouveau_vram *vram = mem->mm_node; + + if (!dev_priv->bar1_vm || mem->mem_type != TTM_PL_VRAM) + return; + + if (!vram->bar_vma.node) + return; + + nouveau_vm_unmap(&vram->bar_vma); + nouveau_vm_put(&vram->bar_vma); } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index ce1dde4a65d6..452a8652a498 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -55,7 +55,10 @@ struct nouveau_fpriv { #include "nouveau_reg.h" #include "nouveau_bios.h" #include "nouveau_util.h" + struct nouveau_grctx; +struct nouveau_vram; +#include "nouveau_vm.h" #define MAX_NUM_DCB_ENTRIES 16 @@ -69,6 +72,8 @@ struct nouveau_grctx; struct nouveau_vram { struct drm_device *dev; + struct nouveau_vma bar_vma; + struct list_head regions; u32 memtype; u64 offset; @@ -244,6 +249,7 @@ struct nouveau_channel { void *pgraph_ctx; /* NV50 VM */ + struct nouveau_vm *vm; struct nouveau_gpuobj *vm_pd; struct nouveau_gpuobj *vm_gart_pt; struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; @@ -701,6 +707,10 @@ struct drm_nouveau_private { uint64_t fb_aper_free; int fb_mtrr; + /* BAR control (NV50-) */ + struct nouveau_vm *bar1_vm; + struct nouveau_vm *bar3_vm; + /* G8x/G9x virtual address space */ uint64_t vm_gart_base; uint64_t vm_gart_size; diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 4eb2f0835e27..4ba8f74e77b1 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -31,12 +31,16 @@ #include "nouveau_drv.h" #include "nouveau_vm.h" +#define BAR1_VM_BASE 0x0020000000ULL +#define BAR1_VM_SIZE pci_resource_len(dev->pdev, 1) +#define BAR3_VM_BASE 0x0000000000ULL +#define BAR3_VM_SIZE pci_resource_len(dev->pdev, 3) + struct nv50_instmem_priv { uint32_t save1700[5]; /* 0x1700->0x1710 */ - struct nouveau_gpuobj *pramin_pt; - struct nouveau_gpuobj *pramin_bar; - struct nouveau_gpuobj *fb_bar; + struct nouveau_gpuobj *bar1_dmaobj; + struct nouveau_gpuobj *bar3_dmaobj; }; static void @@ -50,6 +54,7 @@ nv50_channel_del(struct nouveau_channel **pchan) return; nouveau_gpuobj_ref(NULL, &chan->ramfc); + nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); nouveau_gpuobj_ref(NULL, &chan->vm_pd); if (chan->ramin_heap.free_stack.next) drm_mm_takedown(&chan->ramin_heap); @@ -58,14 +63,14 @@ nv50_channel_del(struct nouveau_channel **pchan) } static int -nv50_channel_new(struct drm_device *dev, u32 size, +nv50_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, struct nouveau_channel **pchan) { struct drm_nouveau_private *dev_priv = dev->dev_private; u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200; struct nouveau_channel *chan; - int ret; + int ret, i; chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) @@ -94,6 +99,17 @@ nv50_channel_new(struct drm_device *dev, u32 size, return ret; } + for (i = 0; i < 0x4000; i += 8) { + nv_wo32(chan->vm_pd, i + 0, 0x00000000); + nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe); + } + + ret = nouveau_vm_ref(vm, &chan->vm, chan->vm_pd); + if (ret) { + nv50_channel_del(&chan); + return ret; + } + ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : chan->ramin->pinst + fc, chan->ramin->vinst + fc, 0x100, @@ -113,6 +129,7 @@ nv50_instmem_init(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_instmem_priv *priv; struct nouveau_channel *chan; + struct nouveau_vm *vm; int ret, i; u32 tmp; @@ -129,53 +146,75 @@ nv50_instmem_init(struct drm_device *dev) ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size); if (ret) { NV_ERROR(dev, "Failed to init RAMIN heap\n"); - return -ENOMEM; + goto error; } - /* we need a channel to plug into the hw to control the BARs */ - ret = nv50_channel_new(dev, 128*1024, &dev_priv->channels.ptr[0]); + /* BAR3 */ + ret = nouveau_vm_new(dev, BAR3_VM_BASE, BAR3_VM_SIZE, BAR3_VM_BASE, + 29, 12, 16, &dev_priv->bar3_vm); if (ret) - return ret; - chan = dev_priv->channels.ptr[127] = dev_priv->channels.ptr[0]; + goto error; - /* allocate page table for PRAMIN BAR */ - ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, - &priv->pramin_pt); + ret = nouveau_gpuobj_new(dev, NULL, (BAR3_VM_SIZE >> 12) * 8, + 0x1000, NVOBJ_FLAG_DONT_MAP | + NVOBJ_FLAG_ZERO_ALLOC, + &dev_priv->bar3_vm->pgt[0].obj); if (ret) - return ret; + goto error; + dev_priv->bar3_vm->pgt[0].page_shift = 12; + dev_priv->bar3_vm->pgt[0].refcount = 1; - nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63); - nv_wo32(chan->vm_pd, 0x0004, 0); + nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj); - /* DMA object for PRAMIN BAR */ - ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar); + ret = nv50_channel_new(dev, 128 * 1024, dev_priv->bar3_vm, &chan); if (ret) - return ret; - nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000); - nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1); - nv_wo32(priv->pramin_bar, 0x08, 0x00000000); - nv_wo32(priv->pramin_bar, 0x0c, 0x00000000); - nv_wo32(priv->pramin_bar, 0x10, 0x00000000); - nv_wo32(priv->pramin_bar, 0x14, 0x00000000); + goto error; + dev_priv->channels.ptr[0] = dev_priv->channels.ptr[127] = chan; - nv50_instmem_map(chan->ramin); + ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR3_VM_BASE, BAR3_VM_SIZE, + NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM, + NV_MEM_TYPE_VM, NV_MEM_COMP_VM, + &priv->bar3_dmaobj); + if (ret) + goto error; - /* poke regs... */ nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); - nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4)); + nv_wr32(dev, 0x00170c, 0x80000000 | (priv->bar3_dmaobj->cinst >> 4)); tmp = nv_ri32(dev, 0); nv_wi32(dev, 0, ~tmp); if (nv_ri32(dev, 0) != ~tmp) { NV_ERROR(dev, "PRAMIN readback failed\n"); - return -EIO; + ret = -EIO; + goto error; } nv_wi32(dev, 0, tmp); dev_priv->ramin_available = true; + /* BAR1 */ + ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, + 29, 12, 16, &vm); + if (ret) + goto error; + + ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, chan->vm_pd); + if (ret) + goto error; + nouveau_vm_ref(NULL, &vm, NULL); + + ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR1_VM_BASE, BAR1_VM_SIZE, + NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM, + NV_MEM_TYPE_VM, NV_MEM_COMP_VM, + &priv->bar1_dmaobj); + if (ret) + goto error; + + nv_wr32(dev, 0x001708, 0x80000000 | (priv->bar1_dmaobj->cinst >> 4)); + for (i = 0; i < 8; i++) + nv_wr32(dev, 0x1900 + (i*4), 0); + /* Determine VM layout */ dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); dev_priv->vm_gart_size = NV50_VM_BLOCK; @@ -200,38 +239,19 @@ nv50_instmem_init(struct drm_device *dev) for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8, 0, NVOBJ_FLAG_ZERO_ALLOC, - &chan->vm_vram_pt[i]); + &dev_priv->vm_vram_pt[i]); if (ret) { NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret); dev_priv->vm_vram_pt_nr = i; return ret; } - dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; - - nv_wo32(chan->vm_pd, 0x10 + (i*8), - chan->vm_vram_pt[i]->vinst | 0x61); - nv_wo32(chan->vm_pd, 0x14 + (i*8), 0); } - /* DMA object for FB BAR */ - ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar); - if (ret) - return ret; - nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); - nv_wo32(priv->fb_bar, 0x04, 0x40000000 + - pci_resource_len(dev->pdev, 1) - 1); - nv_wo32(priv->fb_bar, 0x08, 0x40000000); - nv_wo32(priv->fb_bar, 0x0c, 0x00000000); - nv_wo32(priv->fb_bar, 0x10, 0x00000000); - nv_wo32(priv->fb_bar, 0x14, 0x00000000); - - dev_priv->engine.instmem.flush(dev); - - nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4)); - for (i = 0; i < 8; i++) - nv_wr32(dev, 0x1900 + (i*4), 0); - return 0; + +error: + nv50_instmem_takedown(dev); + return ret; } void @@ -249,23 +269,25 @@ nv50_instmem_takedown(struct drm_device *dev) dev_priv->ramin_available = false; - /* Restore state from before init */ + for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) + nouveau_gpuobj_ref(NULL, &dev_priv->vm_vram_pt[i]); + dev_priv->vm_vram_pt_nr = 0; + for (i = 0x1700; i <= 0x1710; i += 4) nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); - nouveau_gpuobj_ref(NULL, &priv->fb_bar); - nouveau_gpuobj_ref(NULL, &priv->pramin_bar); - nouveau_gpuobj_ref(NULL, &priv->pramin_pt); + nouveau_gpuobj_ref(NULL, &priv->bar3_dmaobj); + nouveau_gpuobj_ref(NULL, &priv->bar1_dmaobj); - /* Destroy dummy channel */ - if (chan) { - for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) - nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); - dev_priv->vm_vram_pt_nr = 0; + nouveau_vm_ref(NULL, &dev_priv->bar1_vm, chan->vm_pd); + dev_priv->channels.ptr[127] = 0; + nv50_channel_del(&dev_priv->channels.ptr[0]); - nv50_channel_del(&dev_priv->channels.ptr[0]); - dev_priv->channels.ptr[127] = NULL; - } + nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj); + nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); + + if (dev_priv->ramin_heap.free_stack.next) + drm_mm_takedown(&dev_priv->ramin_heap); dev_priv->engine.instmem.priv = NULL; kfree(priv); @@ -293,9 +315,9 @@ nv50_instmem_resume(struct drm_device *dev) nv_wr32(dev, NV50_PUNK_UNK1710, 0); nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) | NV50_PUNK_BAR_CFG_BASE_VALID); - nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) | + nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->bar1_dmaobj->cinst >> 4) | NV50_PUNK_BAR1_CTXDMA_VALID); - nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) | + nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->bar3_dmaobj->cinst >> 4) | NV50_PUNK_BAR3_CTXDMA_VALID); for (i = 0; i < 8; i++) @@ -305,8 +327,7 @@ nv50_instmem_resume(struct drm_device *dev) } struct nv50_gpuobj_node { - struct nouveau_bo *vram; - struct drm_mm_node *ramin; + struct nouveau_vram *vram; u32 align; }; @@ -323,23 +344,17 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) return -ENOMEM; node->align = align; - ret = nouveau_bo_new(dev, NULL, size, align, TTM_PL_FLAG_VRAM, - 0, 0x0000, true, false, &node->vram); - if (ret) { - NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); - WARN_ON(1); - return ret; - } + size = (size + 4095) & ~4095; + align = max(align, (u32)4096); - ret = nouveau_bo_pin(node->vram, TTM_PL_FLAG_VRAM); + ret = nv50_vram_new(dev, size, align, 0, 0, &node->vram); if (ret) { - NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); - nouveau_bo_ref(NULL, &node->vram); + kfree(node); return ret; } - gpuobj->vinst = node->vram->bo.mem.start << PAGE_SHIFT; - gpuobj->size = node->vram->bo.mem.num_pages << PAGE_SHIFT; + gpuobj->vinst = node->vram->offset; + gpuobj->size = size; gpuobj->node = node; return 0; } @@ -347,13 +362,13 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) void nv50_instmem_put(struct nouveau_gpuobj *gpuobj) { + struct drm_device *dev = gpuobj->dev; struct nv50_gpuobj_node *node; node = gpuobj->node; gpuobj->node = NULL; - nouveau_bo_unpin(node->vram); - nouveau_bo_ref(NULL, &node->vram); + nv50_vram_del(dev, &node->vram); kfree(node); } @@ -361,83 +376,28 @@ int nv50_instmem_map(struct nouveau_gpuobj *gpuobj) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; - struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; struct nv50_gpuobj_node *node = gpuobj->node; - struct drm_device *dev = gpuobj->dev; - struct drm_mm_node *ramin = NULL; - u32 pte, pte_end; - u64 vram; - - do { - if (drm_mm_pre_get(&dev_priv->ramin_heap)) - return -ENOMEM; - - spin_lock(&dev_priv->ramin_lock); - ramin = drm_mm_search_free(&dev_priv->ramin_heap, gpuobj->size, - node->align, 0); - if (ramin == NULL) { - spin_unlock(&dev_priv->ramin_lock); - return -ENOMEM; - } - - ramin = drm_mm_get_block_atomic(ramin, gpuobj->size, node->align); - spin_unlock(&dev_priv->ramin_lock); - } while (ramin == NULL); - - pte = (ramin->start >> 12) << 1; - pte_end = ((ramin->size >> 12) << 1) + pte; - vram = gpuobj->vinst; - - NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", - ramin->start, pte, pte_end); - NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); - - vram |= 1; - if (dev_priv->vram_sys_base) { - vram += dev_priv->vram_sys_base; - vram |= 0x30; - } - - while (pte < pte_end) { - nv_wo32(priv->pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); - nv_wo32(priv->pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); - vram += 0x1000; - pte += 2; - } - dev_priv->engine.instmem.flush(dev); + int ret; - nv50_vm_flush_engine(dev, 6); + ret = nouveau_vm_get(dev_priv->bar3_vm, gpuobj->size, 12, + NV_MEM_ACCESS_RW, &node->vram->bar_vma); + if (ret) + return ret; - node->ramin = ramin; - gpuobj->pinst = ramin->start; + nouveau_vm_map(&node->vram->bar_vma, node->vram); + gpuobj->pinst = node->vram->bar_vma.offset; return 0; } void nv50_instmem_unmap(struct nouveau_gpuobj *gpuobj) { - struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; - struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; struct nv50_gpuobj_node *node = gpuobj->node; - u32 pte, pte_end; - if (!node->ramin || !dev_priv->ramin_available) - return; - - pte = (node->ramin->start >> 12) << 1; - pte_end = ((node->ramin->size >> 12) << 1) + pte; - - while (pte < pte_end) { - nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000); - nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000); - pte += 2; + if (node->vram->bar_vma.node) { + nouveau_vm_unmap(&node->vram->bar_vma); + nouveau_vm_put(&node->vram->bar_vma); } - dev_priv->engine.instmem.flush(gpuobj->dev); - - spin_lock(&dev_priv->ramin_lock); - drm_mm_put_block(node->ramin); - node->ramin = NULL; - spin_unlock(&dev_priv->ramin_lock); } void diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index ab6c3d0ce32e..efc63c0b0d92 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -151,7 +151,6 @@ nv50_vm_flush(struct nouveau_vm *vm) struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; pinstmem->flush(vm->dev); - nv50_vm_flush_engine(vm->dev, 6); } -- cgit v1.2.3 From 4c1361429841344ce4d164492ee7620cf3286eb7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 11:54:21 +1000 Subject: drm/nv50: implement global channel address space on new VM code As of this commit, it's guaranteed that if an object is in VRAM that its GPU virtual address will be constant. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 41 ++++++++------ drivers/gpu/drm/nouveau/nouveau_channel.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.c | 8 +-- drivers/gpu/drm/nouveau/nouveau_drv.h | 17 +----- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 +- drivers/gpu/drm/nouveau/nouveau_mem.c | 94 ------------------------------- drivers/gpu/drm/nouveau/nouveau_object.c | 47 ++++------------ drivers/gpu/drm/nouveau/nv50_crtc.c | 6 +- drivers/gpu/drm/nouveau/nv50_fbcon.c | 13 ++--- drivers/gpu/drm/nouveau/nv50_graph.c | 3 + drivers/gpu/drm/nouveau/nv50_instmem.c | 48 +++++----------- drivers/gpu/drm/nouveau/nv50_vm.c | 17 +++++- drivers/gpu/drm/nouveau/nv84_crypt.c | 2 + 13 files changed, 86 insertions(+), 216 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 4d142031d542..203e75de4128 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -49,6 +49,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) DRM_ERROR("bo %p still attached to GEM object\n", bo); nv10_mem_put_tile_region(dev, nvbo->tile, NULL); + nouveau_vm_put(&nvbo->vma); kfree(nvbo); } @@ -113,6 +114,15 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, &align, &size); align >>= PAGE_SHIFT; + if (!nvbo->no_vm && dev_priv->chan_vm) { + ret = nouveau_vm_get(dev_priv->chan_vm, size, 16, + NV_MEM_ACCESS_RW, &nvbo->vma); + if (ret) { + kfree(nvbo); + return ret; + } + } + nouveau_bo_placement_set(nvbo, flags, 0); nvbo->channel = chan; @@ -125,6 +135,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, } nvbo->channel = NULL; + if (nvbo->vma.node) { + if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) + nvbo->bo.offset = nvbo->vma.offset; + } + *pnvbo = nvbo; return 0; } @@ -294,6 +309,11 @@ nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible, if (ret) return ret; + if (nvbo->vma.node) { + if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) + nvbo->bo.offset = nvbo->vma.offset; + } + return 0; } @@ -400,10 +420,7 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; - if (dev_priv->card_type == NV_50) - man->gpu_offset = 0x40000000; - else - man->gpu_offset = 0; + man->gpu_offset = 0; break; case TTM_PL_TT: man->func = &ttm_bo_manager_func; @@ -507,12 +524,12 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, dst_offset = new_mem->start << PAGE_SHIFT; if (!nvbo->no_vm) { if (old_mem->mem_type == TTM_PL_VRAM) - src_offset += dev_priv->vm_vram_base; + src_offset = nvbo->vma.offset; else src_offset += dev_priv->vm_gart_base; if (new_mem->mem_type == TTM_PL_VRAM) - dst_offset += dev_priv->vm_vram_base; + dst_offset = nvbo->vma.offset; else dst_offset += dev_priv->vm_gart_base; } @@ -756,7 +773,6 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, struct drm_device *dev = dev_priv->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); uint64_t offset; - int ret; if (nvbo->no_vm || new_mem->mem_type != TTM_PL_VRAM) { /* Nothing to do. */ @@ -766,15 +782,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, offset = new_mem->start << PAGE_SHIFT; - if (dev_priv->card_type == NV_50) { - ret = nv50_mem_vm_bind_linear(dev, - offset + dev_priv->vm_vram_base, - new_mem->size, - nouveau_bo_tile_layout(nvbo), - offset); - if (ret) - return ret; - + if (dev_priv->chan_vm) { + nouveau_vm_map(&nvbo->vma, new_mem->mm_node); } else if (dev_priv->card_type >= NV_10) { *new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size, nvbo->tile_mode, diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index a3d33a582a98..6f37995aee2d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -39,7 +39,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, - dev_priv->vm_end, NV_MEM_ACCESS_RO, + (1ULL << 40), NV_MEM_ACCESS_RO, NV_MEM_TARGET_VM, &pushbuf); chan->pushbuf_base = pb->bo.offset; } else diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index a48c7da133d2..bb170570938b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -339,13 +339,11 @@ nouveau_pci_resume(struct pci_dev *pdev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + u32 offset = nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT; - nv_crtc->cursor.set_offset(nv_crtc, - nv_crtc->cursor.nvbo->bo.offset - - dev_priv->vm_vram_base); - + nv_crtc->cursor.set_offset(nv_crtc, offset); nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x, - nv_crtc->cursor_saved_y); + nv_crtc->cursor_saved_y); } /* Force CLUT to get re-loaded during modeset */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 452a8652a498..dce9a5f6f6c4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -65,10 +65,6 @@ struct nouveau_vram; #define NOUVEAU_MAX_CHANNEL_NR 128 #define NOUVEAU_MAX_TILE_NR 15 -#define NV50_VM_MAX_VRAM (2*1024*1024*1024ULL) -#define NV50_VM_BLOCK (512*1024*1024ULL) -#define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK) - struct nouveau_vram { struct drm_device *dev; @@ -106,6 +102,7 @@ struct nouveau_bo { struct nouveau_channel *channel; + struct nouveau_vma vma; bool mappable; bool no_vm; @@ -252,7 +249,6 @@ struct nouveau_channel { struct nouveau_vm *vm; struct nouveau_gpuobj *vm_pd; struct nouveau_gpuobj *vm_gart_pt; - struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; /* Objects */ struct nouveau_gpuobj *ramin; /* Private instmem */ @@ -712,13 +708,9 @@ struct drm_nouveau_private { struct nouveau_vm *bar3_vm; /* G8x/G9x virtual address space */ + struct nouveau_vm *chan_vm; uint64_t vm_gart_base; uint64_t vm_gart_size; - uint64_t vm_vram_base; - uint64_t vm_vram_size; - uint64_t vm_end; - struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; - int vm_vram_pt_nr; struct nvbios vbios; @@ -836,11 +828,6 @@ extern struct nouveau_tile_reg *nv10_mem_set_tiling( extern void nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile, struct nouveau_fence *fence); -extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt, - uint32_t size, uint32_t flags, - uint64_t phys); -extern void nv50_mem_vm_unbind(struct drm_device *, uint64_t virt, - uint32_t size); extern const struct ttm_mem_type_manager_func nouveau_vram_manager; /* nouveau_notifier.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 0fce4eb914d5..ea861c915149 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -338,8 +338,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, FBINFO_HWACCEL_IMAGEBLIT; info->flags |= FBINFO_CAN_FORCE_OUTPUT; info->fbops = &nouveau_fbcon_sw_ops; - info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - - dev_priv->vm_vram_base; + info->fix.smem_start = dev->mode_config.fb_base + + (nvbo->bo.mem.start << PAGE_SHIFT); info->fix.smem_len = size; info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 2d02401e8227..4d2d3de97ee9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -144,100 +144,6 @@ nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, return found; } -/* - * NV50 VM helpers - */ -int -nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, - uint32_t flags, uint64_t phys) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *pgt; - unsigned block; - int i; - - virt = ((virt - dev_priv->vm_vram_base) >> 16) << 1; - size = (size >> 16) << 1; - - phys |= ((uint64_t)flags << 32); - phys |= 1; - if (dev_priv->vram_sys_base) { - phys += dev_priv->vram_sys_base; - phys |= 0x30; - } - - while (size) { - unsigned offset_h = upper_32_bits(phys); - unsigned offset_l = lower_32_bits(phys); - unsigned pte, end; - - for (i = 7; i >= 0; i--) { - block = 1 << (i + 1); - if (size >= block && !(virt & (block - 1))) - break; - } - offset_l |= (i << 7); - - phys += block << 15; - size -= block; - - while (block) { - pgt = dev_priv->vm_vram_pt[virt >> 14]; - pte = virt & 0x3ffe; - - end = pte + block; - if (end > 16384) - end = 16384; - block -= (end - pte); - virt += (end - pte); - - while (pte < end) { - nv_wo32(pgt, (pte * 4) + 0, offset_l); - nv_wo32(pgt, (pte * 4) + 4, offset_h); - pte += 2; - } - } - } - - dev_priv->engine.instmem.flush(dev); - dev_priv->engine.fifo.tlb_flush(dev); - dev_priv->engine.graph.tlb_flush(dev); - nv50_vm_flush_engine(dev, 6); - return 0; -} - -void -nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *pgt; - unsigned pages, pte, end; - - virt -= dev_priv->vm_vram_base; - pages = (size >> 16) << 1; - - while (pages) { - pgt = dev_priv->vm_vram_pt[virt >> 29]; - pte = (virt & 0x1ffe0000ULL) >> 15; - - end = pte + pages; - if (end > 16384) - end = 16384; - pages -= (end - pte); - virt += (end - pte) << 15; - - while (pte < end) { - nv_wo32(pgt, (pte * 4), 0); - pte++; - } - } - - dev_priv->engine.instmem.flush(dev); - dev_priv->engine.fifo.tlb_flush(dev); - dev_priv->engine.graph.tlb_flush(dev); - nv50_vm_flush_engine(dev, 6); -} - /* * Cleanup everything */ diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index dd1859f7d8b0..573fd7316d63 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -35,6 +35,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nouveau_ramht.h" +#include "nouveau_vm.h" struct nouveau_gpuobj_method { struct list_head head; @@ -770,9 +771,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; struct nouveau_gpuobj *vram = NULL, *tt = NULL; - int ret, i; + int ret; NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); @@ -783,16 +783,14 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, return ret; } - /* NV50 VM + /* NV50/NVC0 VM * - Allocate per-channel page-directory - * - Map GART and VRAM into the channel's address space at the - * locations determined during init. + * - Link with shared channel VM */ - if (dev_priv->card_type >= NV_50) { + if (dev_priv->chan_vm) { u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; u64 vm_vinst = chan->ramin->vinst + pgd_offs; u32 vm_pinst = chan->ramin->pinst; - u32 pde; if (vm_pinst != ~0) vm_pinst += pgd_offs; @@ -801,29 +799,9 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, 0, &chan->vm_pd); if (ret) return ret; - for (i = 0; i < 0x4000; i += 8) { - nv_wo32(chan->vm_pd, i + 0, 0x00000000); - nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe); - } - - nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, - &chan->vm_gart_pt); - pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8; - nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3); - nv_wo32(chan->vm_pd, pde + 4, 0x00000000); - - pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8; - for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { - nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i], - &chan->vm_vram_pt[i]); - - nv_wo32(chan->vm_pd, pde + 0, - chan->vm_vram_pt[i]->vinst | 0x61); - nv_wo32(chan->vm_pd, pde + 4, 0x00000000); - pde += 8; - } - instmem->flush(dev); + nouveau_vm_ref(dev_priv->chan_vm, &chan->vm, chan->vm_pd); + chan->vm->map_pgt(chan->vm_pd, 12, 1, dev_priv->gart_info.sg_ctxdma); } /* RAMHT */ @@ -846,8 +824,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, /* VRAM ctxdma */ if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->vm_end, - NV_MEM_ACCESS_RW, + 0, (1ULL << 40), NV_MEM_ACCESS_RW, NV_MEM_TARGET_VM, &vram); if (ret) { NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); @@ -874,8 +851,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, /* TT memory ctxdma */ if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->vm_end, - NV_MEM_ACCESS_RW, + 0, (1ULL << 40), NV_MEM_ACCESS_RW, NV_MEM_TARGET_VM, &tt); } else { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, @@ -902,9 +878,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, void nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct drm_device *dev = chan->dev; - int i; NV_DEBUG(dev, "ch%d\n", chan->id); @@ -913,10 +887,9 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) nouveau_ramht_ref(NULL, &chan->ramht, chan); + nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); nouveau_gpuobj_ref(NULL, &chan->vm_pd); nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt); - for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) - nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); if (chan->ramin_heap.free_stack.next) drm_mm_takedown(&chan->ramin_heap); diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index f3570cc45017..2c346f797285 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -345,7 +345,6 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t buffer_handle, uint32_t width, uint32_t height) { struct drm_device *dev = crtc->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_bo *cursor = NULL; struct drm_gem_object *gem; @@ -374,8 +373,7 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, nouveau_bo_unmap(cursor); - nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset - - dev_priv->vm_vram_base); + nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT); nv_crtc->cursor.show(nv_crtc, true); out: @@ -548,7 +546,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, return -EINVAL; } - nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base; + nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT; nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) { diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 156731993907..6d38cb1488ae 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -3,6 +3,7 @@ #include "nouveau_dma.h" #include "nouveau_ramht.h" #include "nouveau_fbcon.h" +#include "nouveau_mm.h" int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) @@ -134,10 +135,8 @@ nv50_fbcon_accel_init(struct fb_info *info) struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; + struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo; int ret, format; - uint64_t fb; - - fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base; switch (info->var.bits_per_pixel) { case 8: @@ -224,8 +223,8 @@ nv50_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.line_length); OUT_RING(chan, info->var.xres_virtual); OUT_RING(chan, info->var.yres_virtual); - OUT_RING(chan, upper_32_bits(fb)); - OUT_RING(chan, lower_32_bits(fb)); + OUT_RING(chan, upper_32_bits(nvbo->vma.offset)); + OUT_RING(chan, lower_32_bits(nvbo->vma.offset)); BEGIN_RING(chan, NvSub2D, 0x0230, 2); OUT_RING(chan, format); OUT_RING(chan, 1); @@ -233,8 +232,8 @@ nv50_fbcon_accel_init(struct fb_info *info) OUT_RING(chan, info->fix.line_length); OUT_RING(chan, info->var.xres_virtual); OUT_RING(chan, info->var.yres_virtual); - OUT_RING(chan, upper_32_bits(fb)); - OUT_RING(chan, lower_32_bits(fb)); + OUT_RING(chan, upper_32_bits(nvbo->vma.offset)); + OUT_RING(chan, lower_32_bits(nvbo->vma.offset)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index f5fd1b296d27..c510e74acf4d 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -246,6 +246,7 @@ nv50_graph_create_context(struct nouveau_channel *chan) nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12); dev_priv->engine.instmem.flush(dev); + atomic_inc(&chan->vm->pgraph_refs); return 0; } @@ -277,6 +278,8 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); + + atomic_dec(&chan->vm->pgraph_refs); } static int diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 4ba8f74e77b1..08202fd682e4 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -131,6 +131,7 @@ nv50_instmem_init(struct drm_device *dev) struct nouveau_channel *chan; struct nouveau_vm *vm; int ret, i; + u64 nongart_o; u32 tmp; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -215,37 +216,18 @@ nv50_instmem_init(struct drm_device *dev) for (i = 0; i < 8; i++) nv_wr32(dev, 0x1900 + (i*4), 0); - /* Determine VM layout */ - dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); - dev_priv->vm_gart_size = NV50_VM_BLOCK; - - dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; - dev_priv->vm_vram_size = dev_priv->vram_size; - if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) - dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; - dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); - dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; - - dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; - - NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", - dev_priv->vm_gart_base, - dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); - NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", - dev_priv->vm_vram_base, - dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); - - /* VRAM page table(s), mapped into VM at +1GiB */ - for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { - ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8, - 0, NVOBJ_FLAG_ZERO_ALLOC, - &dev_priv->vm_vram_pt[i]); - if (ret) { - NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret); - dev_priv->vm_vram_pt_nr = i; - return ret; - } - } + /* Create shared channel VM, space is reserved for GART mappings at + * the beginning of this address space, it's managed separately + * because TTM makes life painful + */ + dev_priv->vm_gart_base = 0x0020000000ULL; + dev_priv->vm_gart_size = 512 * 1024 * 1024; + nongart_o = dev_priv->vm_gart_base + dev_priv->vm_gart_size; + + ret = nouveau_vm_new(dev, 0, (1ULL << 40), nongart_o, + 29, 12, 16, &dev_priv->chan_vm); + if (ret) + return ret; return 0; @@ -269,9 +251,7 @@ nv50_instmem_takedown(struct drm_device *dev) dev_priv->ramin_available = false; - for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) - nouveau_gpuobj_ref(NULL, &dev_priv->vm_vram_pt[i]); - dev_priv->vm_vram_pt_nr = 0; + nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL); for (i = 0x1700; i <= 0x1710; i += 4) nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index efc63c0b0d92..eebab95f59b2 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -149,9 +149,24 @@ nv50_vm_flush(struct nouveau_vm *vm) { struct drm_nouveau_private *dev_priv = vm->dev->dev_private; struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; pinstmem->flush(vm->dev); - nv50_vm_flush_engine(vm->dev, 6); + + /* BAR */ + if (vm != dev_priv->chan_vm) { + nv50_vm_flush_engine(vm->dev, 6); + return; + } + + pfifo->tlb_flush(vm->dev); + + if (atomic_read(&vm->pgraph_refs)) + pgraph->tlb_flush(vm->dev); + if (atomic_read(&vm->pcrypt_refs)) + pcrypt->tlb_flush(vm->dev); } void diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c index a333e5905346..ec18ae1c3886 100644 --- a/drivers/gpu/drm/nouveau/nv84_crypt.c +++ b/drivers/gpu/drm/nouveau/nv84_crypt.c @@ -53,6 +53,7 @@ nv84_crypt_create_context(struct nouveau_channel *chan) nv_wo32(ramin, 0xb4, 0); dev_priv->engine.instmem.flush(dev); + atomic_inc(&chan->vm->pcrypt_refs); return 0; } @@ -80,6 +81,7 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan) nv_wr32(dev, 0x10200c, 0x00000010); nouveau_gpuobj_ref(NULL, &chan->crypt_ctx); + atomic_dec(&chan->vm->pcrypt_refs); } void -- cgit v1.2.3 From bfd83aca5a1c4cc07fb18d96ed8660f2c338a8f3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 12 Nov 2010 15:12:51 +1000 Subject: drm/nv50: enable 4KiB pages for small vram allocations Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 41 ++++++++++++++++++++--------------- drivers/gpu/drm/nouveau/nouveau_mem.c | 3 ++- 2 files changed, 25 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 203e75de4128..bc28aeada8c3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -54,39 +54,45 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) } static void -nouveau_bo_fixup_align(struct drm_device *dev, - uint32_t tile_mode, uint32_t tile_flags, - int *align, int *size) +nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, int *size, + int *page_shift) { - struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); if (dev_priv->card_type < NV_50) { - if (tile_mode) { + if (nvbo->tile_mode) { if (dev_priv->chipset >= 0x40) { *align = 65536; - *size = roundup(*size, 64 * tile_mode); + *size = roundup(*size, 64 * nvbo->tile_mode); } else if (dev_priv->chipset >= 0x30) { *align = 32768; - *size = roundup(*size, 64 * tile_mode); + *size = roundup(*size, 64 * nvbo->tile_mode); } else if (dev_priv->chipset >= 0x20) { *align = 16384; - *size = roundup(*size, 64 * tile_mode); + *size = roundup(*size, 64 * nvbo->tile_mode); } else if (dev_priv->chipset >= 0x10) { *align = 16384; - *size = roundup(*size, 32 * tile_mode); + *size = roundup(*size, 32 * nvbo->tile_mode); } } + } else { + if (likely(dev_priv->chan_vm)) { + if (*size > 256 * 1024) + *page_shift = dev_priv->chan_vm->lpg_shift; + else + *page_shift = dev_priv->chan_vm->spg_shift; + } else { + *page_shift = 12; + } + + *size = roundup(*size, (1 << *page_shift)); + *align = max((1 << *page_shift), *align); } - /* ALIGN works only on powers of two. */ *size = roundup(*size, PAGE_SIZE); - if (dev_priv->card_type == NV_50) { - *size = roundup(*size, 65536); - *align = max(65536, *align); - } } int @@ -97,7 +103,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_bo *nvbo; - int ret = 0; + int ret = 0, page_shift = 0; nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); if (!nvbo) @@ -110,12 +116,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, nvbo->tile_flags = tile_flags; nvbo->bo.bdev = &dev_priv->ttm.bdev; - nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), - &align, &size); + nouveau_bo_fixup_align(nvbo, &align, &size, &page_shift); align >>= PAGE_SHIFT; if (!nvbo->no_vm && dev_priv->chan_vm) { - ret = nouveau_vm_get(dev_priv->chan_vm, size, 16, + ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, NV_MEM_ACCESS_RW, &nvbo->vma); if (ret) { kfree(nvbo); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 4d2d3de97ee9..3a531d53de4d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -715,7 +715,8 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct nouveau_vram *vram; int ret; - ret = nv50_vram_new(dev, mem->num_pages << PAGE_SHIFT, 65536, 0, + ret = nv50_vram_new(dev, mem->num_pages << PAGE_SHIFT, + mem->page_alignment << PAGE_SHIFT, 0, (nvbo->tile_flags >> 8) & 0x7f, &vram); if (ret) return ret; -- cgit v1.2.3 From 5f6fdca570b13a8a2c9cab9ab6edfc17487049cf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 12 Nov 2010 15:13:59 +1000 Subject: drm/nv50: enable non-contig vram allocations where requested Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 3a531d53de4d..5a1809480388 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -713,10 +713,14 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct drm_device *dev = dev_priv->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_vram *vram; + u32 size_nc = 0; int ret; + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) + size_nc = 1 << nvbo->vma.node->type; + ret = nv50_vram_new(dev, mem->num_pages << PAGE_SHIFT, - mem->page_alignment << PAGE_SHIFT, 0, + mem->page_alignment << PAGE_SHIFT, size_nc, (nvbo->tile_flags >> 8) & 0x7f, &vram); if (ret) return ret; -- cgit v1.2.3 From b571fe21f5c24760368b3fb927af5a7384d7721b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Nov 2010 10:13:05 +1000 Subject: drm/nv50: tidy up PCIEGART implementation Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 7 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 +- drivers/gpu/drm/nouveau/nouveau_object.c | 4 +- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 147 +++++++++++++++---------------- drivers/gpu/drm/nouveau/nv50_instmem.c | 12 +-- 5 files changed, 79 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index bc28aeada8c3..42d1ad62b381 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -425,7 +425,6 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; - man->gpu_offset = 0; break; case TTM_PL_TT: man->func = &ttm_bo_manager_func; @@ -441,13 +440,13 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, TTM_MEMTYPE_FLAG_CMA; man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_CACHED; + man->gpu_offset = dev_priv->gart_info.aper_base; break; default: NV_ERROR(dev, "Unknown GART type: %d\n", dev_priv->gart_info.type); return -EINVAL; } - man->gpu_offset = dev_priv->vm_gart_base; break; default: NV_ERROR(dev, "Unsupported memory type %u\n", (unsigned)type); @@ -531,12 +530,12 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, if (old_mem->mem_type == TTM_PL_VRAM) src_offset = nvbo->vma.offset; else - src_offset += dev_priv->vm_gart_base; + src_offset += dev_priv->gart_info.aper_base; if (new_mem->mem_type == TTM_PL_VRAM) dst_offset = nvbo->vma.offset; else - dst_offset += dev_priv->vm_gart_base; + dst_offset += dev_priv->gart_info.aper_base; } ret = RING_SPACE(chan, 3); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index dce9a5f6f6c4..4c5fc9c9912b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -248,7 +248,6 @@ struct nouveau_channel { /* NV50 VM */ struct nouveau_vm *vm; struct nouveau_gpuobj *vm_pd; - struct nouveau_gpuobj *vm_gart_pt; /* Objects */ struct nouveau_gpuobj *ramin; /* Private instmem */ @@ -684,6 +683,7 @@ struct drm_nouveau_private { uint64_t aper_free; struct nouveau_gpuobj *sg_ctxdma; + struct nouveau_vma vma; } gart_info; /* nv10-nv40 tiling regions */ @@ -709,8 +709,6 @@ struct drm_nouveau_private { /* G8x/G9x virtual address space */ struct nouveau_vm *chan_vm; - uint64_t vm_gart_base; - uint64_t vm_gart_size; struct nvbios vbios; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 573fd7316d63..d1bed40dc449 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -433,7 +433,7 @@ nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class, flags0 |= 0x00030000; break; case NV_MEM_TARGET_GART: - base += dev_priv->vm_gart_base; + base += dev_priv->gart_info.aper_base; default: flags0 &= ~0x00100000; break; @@ -801,7 +801,6 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, return ret; nouveau_vm_ref(dev_priv->chan_vm, &chan->vm, chan->vm_pd); - chan->vm->map_pgt(chan->vm_pd, 12, 1, dev_priv->gart_info.sg_ctxdma); } /* RAMHT */ @@ -889,7 +888,6 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); nouveau_gpuobj_ref(NULL, &chan->vm_pd); - nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt); if (chan->ramin_heap.free_stack.next) drm_mm_takedown(&chan->ramin_heap); diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index a0bf130b02d3..b57201ab538e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -14,7 +14,7 @@ struct nouveau_sgdma_be { dma_addr_t *pages; unsigned nr_pages; - unsigned pte_start; + u64 offset; bool bound; }; @@ -74,18 +74,6 @@ nouveau_sgdma_clear(struct ttm_backend *be) } } -static inline unsigned -nouveau_sgdma_pte(struct drm_device *dev, uint64_t offset) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - unsigned pte = (offset >> NV_CTXDMA_PAGE_SHIFT); - - if (dev_priv->card_type < NV_50) - return pte + 2; - - return pte << 1; -} - static int nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) { @@ -97,32 +85,17 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) NV_DEBUG(dev, "pg=0x%lx\n", mem->start); - pte = nouveau_sgdma_pte(nvbe->dev, mem->start << PAGE_SHIFT); - nvbe->pte_start = pte; + nvbe->offset = mem->start << PAGE_SHIFT; + pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2; for (i = 0; i < nvbe->nr_pages; i++) { dma_addr_t dma_offset = nvbe->pages[i]; uint32_t offset_l = lower_32_bits(dma_offset); - uint32_t offset_h = upper_32_bits(dma_offset); - - for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { - if (dev_priv->card_type < NV_50) { - nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3); - pte += 1; - } else { - nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21); - nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff); - pte += 2; - } + for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) { + nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3); dma_offset += NV_CTXDMA_PAGE_SIZE; } } - dev_priv->engine.instmem.flush(nvbe->dev); - - if (dev_priv->card_type == NV_50) { - dev_priv->engine.fifo.tlb_flush(dev); - dev_priv->engine.graph.tlb_flush(dev); - } nvbe->bound = true; return 0; @@ -142,24 +115,10 @@ nouveau_sgdma_unbind(struct ttm_backend *be) if (!nvbe->bound) return 0; - pte = nvbe->pte_start; + pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2; for (i = 0; i < nvbe->nr_pages; i++) { - for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { - if (dev_priv->card_type < NV_50) { - nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); - pte += 1; - } else { - nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); - nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000); - pte += 2; - } - } - } - dev_priv->engine.instmem.flush(nvbe->dev); - - if (dev_priv->card_type == NV_50) { - dev_priv->engine.fifo.tlb_flush(dev); - dev_priv->engine.graph.tlb_flush(dev); + for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) + nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); } nvbe->bound = false; @@ -182,6 +141,35 @@ nouveau_sgdma_destroy(struct ttm_backend *be) } } +static int +nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) +{ + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; + + nvbe->offset = mem->start << PAGE_SHIFT; + + nouveau_vm_map_sg(&dev_priv->gart_info.vma, nvbe->offset, + nvbe->nr_pages << PAGE_SHIFT, nvbe->pages); + nvbe->bound = true; + return 0; +} + +static int +nv50_sgdma_unbind(struct ttm_backend *be) +{ + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; + + if (!nvbe->bound) + return 0; + + nouveau_vm_unmap_at(&dev_priv->gart_info.vma, nvbe->offset, + nvbe->nr_pages << PAGE_SHIFT); + nvbe->bound = false; + return 0; +} + static struct ttm_backend_func nouveau_sgdma_backend = { .populate = nouveau_sgdma_populate, .clear = nouveau_sgdma_clear, @@ -190,23 +178,30 @@ static struct ttm_backend_func nouveau_sgdma_backend = { .destroy = nouveau_sgdma_destroy }; +static struct ttm_backend_func nv50_sgdma_backend = { + .populate = nouveau_sgdma_populate, + .clear = nouveau_sgdma_clear, + .bind = nv50_sgdma_bind, + .unbind = nv50_sgdma_unbind, + .destroy = nouveau_sgdma_destroy +}; + struct ttm_backend * nouveau_sgdma_init_ttm(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_sgdma_be *nvbe; - if (!dev_priv->gart_info.sg_ctxdma) - return NULL; - nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL); if (!nvbe) return NULL; nvbe->dev = dev; - nvbe->backend.func = &nouveau_sgdma_backend; - + if (dev_priv->card_type < NV_50) + nvbe->backend.func = &nouveau_sgdma_backend; + else + nvbe->backend.func = &nv50_sgdma_backend; return &nvbe->backend; } @@ -226,21 +221,15 @@ nouveau_sgdma_init(struct drm_device *dev) obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; obj_size += 8; /* ctxdma header */ - } else { - /* 1 entire VM page table */ - aper_size = (512 * 1024 * 1024); - obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 8; - } - ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, - NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &gpuobj); - if (ret) { - NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); - return ret; - } + ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ZERO_FREE, &gpuobj); + if (ret) { + NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); + return ret; + } - if (dev_priv->card_type < NV_50) { nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY | (1 << 12) /* PT present */ | (0 << 13) /* PT *not* linear */ | @@ -249,18 +238,23 @@ nouveau_sgdma_init(struct drm_device *dev) nv_wo32(gpuobj, 4, aper_size - 1); for (i = 2; i < 2 + (aper_size >> 12); i++) nv_wo32(gpuobj, i * 4, 0x00000000); - } else { - for (i = 0; i < obj_size; i += 8) { - nv_wo32(gpuobj, i + 0, 0x00000000); - nv_wo32(gpuobj, i + 4, 0x00000000); - } + + dev_priv->gart_info.sg_ctxdma = gpuobj; + dev_priv->gart_info.aper_base = 0; + dev_priv->gart_info.aper_size = aper_size; + } else + if (dev_priv->chan_vm) { + ret = nouveau_vm_get(dev_priv->chan_vm, 512 * 1024 * 1024, + 12, NV_MEM_ACCESS_RW, + &dev_priv->gart_info.vma); + if (ret) + return ret; + + dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset; + dev_priv->gart_info.aper_size = 512 * 1024 * 1024; } - dev_priv->engine.instmem.flush(dev); dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; - dev_priv->gart_info.aper_base = 0; - dev_priv->gart_info.aper_size = aper_size; - dev_priv->gart_info.sg_ctxdma = gpuobj; return 0; } @@ -270,6 +264,7 @@ nouveau_sgdma_takedown(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma); + nouveau_vm_put(&dev_priv->gart_info.vma); } int diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 08202fd682e4..ec102bda8446 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -131,7 +131,6 @@ nv50_instmem_init(struct drm_device *dev) struct nouveau_channel *chan; struct nouveau_vm *vm; int ret, i; - u64 nongart_o; u32 tmp; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -216,15 +215,10 @@ nv50_instmem_init(struct drm_device *dev) for (i = 0; i < 8; i++) nv_wr32(dev, 0x1900 + (i*4), 0); - /* Create shared channel VM, space is reserved for GART mappings at - * the beginning of this address space, it's managed separately - * because TTM makes life painful + /* Create shared channel VM, space is reserved at the beginning + * to catch "NULL pointer" references */ - dev_priv->vm_gart_base = 0x0020000000ULL; - dev_priv->vm_gart_size = 512 * 1024 * 1024; - nongart_o = dev_priv->vm_gart_base + dev_priv->vm_gart_size; - - ret = nouveau_vm_new(dev, 0, (1ULL << 40), nongart_o, + ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL, 29, 12, 16, &dev_priv->chan_vm); if (ret) return ret; -- cgit v1.2.3 From 34cf01bc4b8021cef62cbd79224577c13d01b106 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 22 Nov 2010 10:48:51 +1000 Subject: drm/nouveau: allow gpuobj vinst to be a virtual address when necessary Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nv50_instmem.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 4c5fc9c9912b..2cd87e6b54b7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -158,6 +158,7 @@ enum nouveau_flags { #define NVOBJ_FLAG_DONT_MAP (1 << 0) #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) #define NVOBJ_FLAG_ZERO_FREE (1 << 2) +#define NVOBJ_FLAG_VM (1 << 3) #define NVOBJ_CINST_GLOBAL 0xdeadbeef diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index ec102bda8446..e2efd6f22ffb 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -302,6 +302,7 @@ nv50_instmem_resume(struct drm_device *dev) struct nv50_gpuobj_node { struct nouveau_vram *vram; + struct nouveau_vma chan_vma; u32 align; }; @@ -310,6 +311,7 @@ int nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) { struct drm_device *dev = gpuobj->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_gpuobj_node *node = NULL; int ret; @@ -328,8 +330,23 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) } gpuobj->vinst = node->vram->offset; - gpuobj->size = size; - gpuobj->node = node; + + if (gpuobj->flags & NVOBJ_FLAG_VM) { + ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, + NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, + &node->chan_vma); + if (ret) { + nv50_vram_del(dev, &node->vram); + kfree(node); + return ret; + } + + nouveau_vm_map(&node->chan_vma, node->vram); + gpuobj->vinst = node->chan_vma.offset; + } + + gpuobj->size = size; + gpuobj->node = node; return 0; } @@ -342,6 +359,10 @@ nv50_instmem_put(struct nouveau_gpuobj *gpuobj) node = gpuobj->node; gpuobj->node = NULL; + if (node->chan_vma.node) { + nouveau_vm_unmap(&node->chan_vma); + nouveau_vm_put(&node->chan_vma); + } nv50_vram_del(dev, &node->vram); kfree(node); } -- cgit v1.2.3 From 60d2a88ae896ae51c76f8b15c2f4b762d5b00864 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 6 Dec 2010 15:28:54 +1000 Subject: drm/nouveau: kick vram functions out into an "engine" NVC0 will be able to share some of nv50's paths this way. This also makes it the card-specific vram code responsible for deciding if a given set of tile_flags is valid, rather than duplicating the allowed types in nv50_vram.c and nouveau_gem.c Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 12 +++++++++ drivers/gpu/drm/nouveau/nouveau_gem.c | 30 +++------------------ drivers/gpu/drm/nouveau/nouveau_mem.c | 47 ++++++++++++++++++--------------- drivers/gpu/drm/nouveau/nouveau_mm.h | 1 + drivers/gpu/drm/nouveau/nouveau_state.c | 16 +++++++++++ drivers/gpu/drm/nouveau/nv50_instmem.c | 9 ++++--- drivers/gpu/drm/nouveau/nv50_vram.c | 10 +++++++ 7 files changed, 74 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 2cd87e6b54b7..f8931b2d129b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -501,6 +501,15 @@ struct nouveau_crypt_engine { void (*tlb_flush)(struct drm_device *dev); }; +struct nouveau_vram_engine { + int (*init)(struct drm_device *); + int (*get)(struct drm_device *, u64, u32 align, u32 size_nc, + u32 type, struct nouveau_vram **); + void (*put)(struct drm_device *, struct nouveau_vram **); + + bool (*flags_valid)(struct drm_device *, u32 tile_flags); +}; + struct nouveau_engine { struct nouveau_instmem_engine instmem; struct nouveau_mc_engine mc; @@ -512,6 +521,7 @@ struct nouveau_engine { struct nouveau_gpio_engine gpio; struct nouveau_pm_engine pm; struct nouveau_crypt_engine crypt; + struct nouveau_vram_engine vram; }; struct nouveau_pll_vals { @@ -821,6 +831,8 @@ extern void nouveau_mem_gart_fini(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); extern int nouveau_mem_reset_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); +extern int nouveau_mem_detect(struct drm_device *); +extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags); extern struct nouveau_tile_reg *nv10_mem_set_tiling( struct drm_device *dev, uint32_t addr, uint32_t size, uint32_t pitch, uint32_t flags); diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 0adb2a85c143..506c508b7eda 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -103,32 +103,6 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep) return 0; } -static bool -nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - - if (dev_priv->card_type >= NV_50) { - switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { - case 0x0000: - case 0x1800: - case 0x2800: - case 0x4800: - case 0x7000: - case 0x7400: - case 0x7a00: - case 0xe000: - return true; - } - } else { - if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) - return true; - } - - NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); - return false; -} - int nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -150,8 +124,10 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, if (!flags || req->info.domain & NOUVEAU_GEM_DOMAIN_CPU) flags |= TTM_PL_FLAG_SYSTEM; - if (!nouveau_gem_tile_flags_valid(dev, req->info.tile_flags)) + if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) { + NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; + } if (req->channel_hint) { chan = nouveau_channel_get(dev, file_priv, req->channel_hint); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 5a1809480388..224181193a1f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -241,7 +241,7 @@ nouveau_mem_detect_nforce(struct drm_device *dev) return 0; } -static int +int nouveau_mem_detect(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -255,26 +255,25 @@ nouveau_mem_detect(struct drm_device *dev) if (dev_priv->card_type < NV_50) { dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; - } else - if (dev_priv->card_type < NV_C0) { - if (nv50_vram_init(dev)) - return -ENOMEM; } else { dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; dev_priv->vram_size *= nv_rd32(dev, 0x121c74); } - NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); - if (dev_priv->vram_sys_base) { - NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", - dev_priv->vram_sys_base); - } - if (dev_priv->vram_size) return 0; return -ENOMEM; } +bool +nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags) +{ + if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) + return true; + + return false; +} + #if __OS_HAS_AGP static unsigned long get_agp_mode(struct drm_device *dev, unsigned long mode) @@ -432,11 +431,16 @@ nouveau_mem_vram_init(struct drm_device *dev) else dev_priv->ramin_rsvd_vram = (512 * 1024); - /* initialise gpu-specific vram backend */ - ret = nouveau_mem_detect(dev); + ret = dev_priv->engine.vram.init(dev); if (ret) return ret; + NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); + if (dev_priv->vram_sys_base) { + NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", + dev_priv->vram_sys_base); + } + dev_priv->fb_available_size = dev_priv->vram_size; dev_priv->fb_mappable_pages = dev_priv->fb_available_size; if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) @@ -698,9 +702,10 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct drm_device *dev = dev_priv->dev; - nv50_vram_del(dev, (struct nouveau_vram **)&mem->mm_node); + vram->put(dev, (struct nouveau_vram **)&mem->mm_node); } static int @@ -710,30 +715,30 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct drm_device *dev = dev_priv->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); - struct nouveau_vram *vram; + struct nouveau_vram *node; u32 size_nc = 0; int ret; if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) size_nc = 1 << nvbo->vma.node->type; - ret = nv50_vram_new(dev, mem->num_pages << PAGE_SHIFT, - mem->page_alignment << PAGE_SHIFT, size_nc, - (nvbo->tile_flags >> 8) & 0x7f, &vram); + ret = vram->get(dev, mem->num_pages << PAGE_SHIFT, + mem->page_alignment << PAGE_SHIFT, size_nc, + (nvbo->tile_flags >> 8) & 0xff, &node); if (ret) return ret; - mem->mm_node = vram; - mem->start = vram->offset >> PAGE_SHIFT; + mem->mm_node = node; + mem->start = node->offset >> PAGE_SHIFT; return 0; } void nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) { - struct ttm_bo_global *glob = man->bdev->glob; struct nouveau_mm *mm = man->priv; struct nouveau_mm_node *r; u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {}; diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h index 7e8f8bd86d47..250e642de0a7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h @@ -57,5 +57,6 @@ int nv50_vram_init(struct drm_device *); int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, u32 memtype, struct nouveau_vram **); void nv50_vram_del(struct drm_device *, struct nouveau_vram **); +bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e0811f93243d..8eac943e8fd2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -100,6 +100,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_set = nv04_pm_clock_set; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; break; case 0x10: engine->instmem.init = nv04_instmem_init; @@ -157,6 +159,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_set = nv04_pm_clock_set; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; break; case 0x20: engine->instmem.init = nv04_instmem_init; @@ -214,6 +218,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.clock_set = nv04_pm_clock_set; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; break; case 0x30: engine->instmem.init = nv04_instmem_init; @@ -273,6 +279,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.voltage_set = nouveau_voltage_gpio_set; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; break; case 0x40: case 0x60: @@ -334,6 +342,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->pm.temp_get = nv40_temp_get; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; break; case 0x50: case 0x80: /* gotta love NVIDIA's consistency.. */ @@ -444,6 +454,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->crypt.takedown = nouveau_stub_takedown; break; } + engine->vram.init = nv50_vram_init; + engine->vram.get = nv50_vram_new; + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nv50_vram_flags_valid; break; case 0xC0: engine->instmem.init = nvc0_instmem_init; @@ -495,6 +509,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.irq_enable = nv50_gpio_irq_enable; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; + engine->vram.init = nouveau_mem_detect; + engine->vram.flags_valid = nouveau_mem_flags_valid; break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index e2efd6f22ffb..38f30270cb9f 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -312,6 +312,7 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) { struct drm_device *dev = gpuobj->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct nv50_gpuobj_node *node = NULL; int ret; @@ -323,7 +324,7 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) size = (size + 4095) & ~4095; align = max(align, (u32)4096); - ret = nv50_vram_new(dev, size, align, 0, 0, &node->vram); + ret = vram->get(dev, size, align, 0, 0, &node->vram); if (ret) { kfree(node); return ret; @@ -336,7 +337,7 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, &node->chan_vma); if (ret) { - nv50_vram_del(dev, &node->vram); + vram->put(dev, &node->vram); kfree(node); return ret; } @@ -354,6 +355,8 @@ void nv50_instmem_put(struct nouveau_gpuobj *gpuobj) { struct drm_device *dev = gpuobj->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; struct nv50_gpuobj_node *node; node = gpuobj->node; @@ -363,7 +366,7 @@ nv50_instmem_put(struct nouveau_gpuobj *gpuobj) nouveau_vm_unmap(&node->chan_vma); nouveau_vm_put(&node->chan_vma); } - nv50_vram_del(dev, &node->vram); + vram->put(dev, &node->vram); kfree(node); } diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c index 6e753356cd94..47489ed0a5a8 100644 --- a/drivers/gpu/drm/nouveau/nv50_vram.c +++ b/drivers/gpu/drm/nouveau/nv50_vram.c @@ -37,6 +37,16 @@ static int types[0x80] = { 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 }; +bool +nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags) +{ + int type = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8; + + if (likely(type < sizeof(types) && types[type])) + return true; + return false; +} + void nv50_vram_del(struct drm_device *dev, struct nouveau_vram **pvram) { -- cgit v1.2.3 From fd70b6cd780742b97f525415bf5e4fb24a4bb6d8 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 8 Dec 2010 02:37:12 +0100 Subject: drm/nv04-nv40: Fix up PCI(E) GART DMA object bus address calculation. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 ++-- drivers/gpu/drm/nouveau/nouveau_object.c | 8 ++------ drivers/gpu/drm/nouveau/nouveau_sgdma.c | 16 ++++++---------- 3 files changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index f8931b2d129b..8f13906185b2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -934,8 +934,8 @@ extern void nouveau_irq_uninstall(struct drm_device *); /* nouveau_sgdma.c */ extern int nouveau_sgdma_init(struct drm_device *); extern void nouveau_sgdma_takedown(struct drm_device *); -extern int nouveau_sgdma_get_page(struct drm_device *, uint32_t offset, - uint32_t *page); +extern uint32_t nouveau_sgdma_get_physical(struct drm_device *, + uint32_t offset); extern struct ttm_backend *nouveau_sgdma_init_ttm(struct drm_device *); /* nouveau_debugfs.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index d1bed40dc449..55c9fdcfa67f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -478,7 +478,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct drm_device *dev = chan->dev; struct nouveau_gpuobj *obj; - u32 page_addr, flags0, flags2; + u32 flags0, flags2; int ret; if (dev_priv->card_type >= NV_50) { @@ -495,12 +495,8 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, base += dev_priv->gart_info.aper_base; } else if (base != 0) { - ret = nouveau_sgdma_get_page(dev, base, &page_addr); - if (ret) - return ret; - + base = nouveau_sgdma_get_physical(dev, base); target = NV_MEM_TARGET_PCI; - base = page_addr; } else { nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index b57201ab538e..9a250eb53098 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -267,19 +267,15 @@ nouveau_sgdma_takedown(struct drm_device *dev) nouveau_vm_put(&dev_priv->gart_info.vma); } -int -nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) +uint32_t +nouveau_sgdma_get_physical(struct drm_device *dev, uint32_t offset) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; - int pte; + int pte = (offset >> NV_CTXDMA_PAGE_SHIFT) + 2; - pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2; - if (dev_priv->card_type < NV_50) { - *page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK; - return 0; - } + BUG_ON(dev_priv->card_type >= NV_50); - NV_ERROR(dev, "Unimplemented on NV50\n"); - return -EINVAL; + return (nv_ro32(gpuobj, 4 * pte) & ~NV_CTXDMA_PAGE_MASK) | + (offset & NV_CTXDMA_PAGE_MASK); } -- cgit v1.2.3 From 5bea7660bba973dc5e8e9d92b11fb1dd5b524ebf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 7 Dec 2010 23:02:48 -0800 Subject: HID: add hid_hw_open/close/power() handlers Instead of exposing the guts of hid->ll_driver relationship to HID sub-drivers provide these helpers to encapsulate the details. Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 4 ++-- drivers/hid/hid-picolcd.c | 6 +++--- drivers/hid/hid-roccat.c | 26 ++++++++++---------------- drivers/hid/hidraw.c | 21 +++++++++------------ include/linux/hid.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 834ef47b76d6..b718f7144ce1 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -772,14 +772,14 @@ static int hidinput_open(struct input_dev *dev) { struct hid_device *hid = input_get_drvdata(dev); - return hid->ll_driver->open(hid); + return hid_hw_open(hid); } static void hidinput_close(struct input_dev *dev) { struct hid_device *hid = input_get_drvdata(dev); - hid->ll_driver->close(hid); + hid_hw_close(hid); } /* diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index bc2e07740628..38565fee7bf1 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -2635,7 +2635,7 @@ static int picolcd_probe(struct hid_device *hdev, goto err_cleanup_data; } - error = hdev->ll_driver->open(hdev); + error = hid_hw_open(hdev); if (error) { dev_err(&hdev->dev, "failed to open input interrupt pipe for key and IR events\n"); goto err_cleanup_hid_hw; @@ -2668,7 +2668,7 @@ err_cleanup_sysfs2: err_cleanup_sysfs1: device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); err_cleanup_hid_ll: - hdev->ll_driver->close(hdev); + hid_hw_close(hdev); err_cleanup_hid_hw: hid_hw_stop(hdev); err_cleanup_data: @@ -2699,7 +2699,7 @@ static void picolcd_remove(struct hid_device *hdev) picolcd_exit_devfs(data); device_remove_file(&hdev->dev, &dev_attr_operation_mode); device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); - hdev->ll_driver->close(hdev); + hid_hw_close(hdev); hid_hw_stop(hdev); hid_set_drvdata(hdev, NULL); diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index 5a6879e235ac..a9d9b29ff47f 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -173,19 +173,15 @@ static int roccat_open(struct inode *inode, struct file *file) if (!device->open++) { /* power on device on adding first reader */ - if (device->hid->ll_driver->power) { - error = device->hid->ll_driver->power(device->hid, - PM_HINT_FULLON); - if (error < 0) { - --device->open; - goto exit_err; - } + error = hid_hw_power(device->hid, PM_HINT_FULLON); + if (error < 0) { + --device->open; + goto exit_err; } - error = device->hid->ll_driver->open(device->hid); + + error = hid_hw_open(device->hid); if (error < 0) { - if (device->hid->ll_driver->power) - device->hid->ll_driver->power(device->hid, - PM_HINT_NORMAL); + hid_hw_power(device->hid, PM_HINT_NORMAL); --device->open; goto exit_err; } @@ -231,10 +227,8 @@ static int roccat_release(struct inode *inode, struct file *file) if (!--device->open) { /* removing last reader */ if (device->exist) { - if (device->hid->ll_driver->power) - device->hid->ll_driver->power(device->hid, - PM_HINT_NORMAL); - device->hid->ll_driver->close(device->hid); + hid_hw_power(device->hid, PM_HINT_NORMAL); + hid_hw_close(device->hid); } else { kfree(device); } @@ -370,7 +364,7 @@ void roccat_disconnect(int minor) device_destroy(roccat_class, MKDEV(roccat_major, minor)); if (device->open) { - device->hid->ll_driver->close(device->hid); + hid_hw_close(device->hid); wake_up_interruptible(&device->wait); } else { kfree(device); diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 8a4b32dca9f7..5aefe73cf795 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -193,15 +193,13 @@ static int hidraw_open(struct inode *inode, struct file *file) dev = hidraw_table[minor]; if (!dev->open++) { - if (dev->hid->ll_driver->power) { - err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON); - if (err < 0) - goto out_unlock; - } - err = dev->hid->ll_driver->open(dev->hid); + err = hid_hw_power(dev->hid, PM_HINT_FULLON); + if (err < 0) + goto out_unlock; + + err = hid_hw_open(dev->hid); if (err < 0) { - if (dev->hid->ll_driver->power) - dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL); + hid_hw_power(dev->hid, PM_HINT_NORMAL); dev->open--; } } @@ -230,9 +228,8 @@ static int hidraw_release(struct inode * inode, struct file * file) dev = hidraw_table[minor]; if (!--dev->open) { if (list->hidraw->exist) { - if (dev->hid->ll_driver->power) - dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL); - dev->hid->ll_driver->close(dev->hid); + hid_hw_power(dev->hid, PM_HINT_NORMAL); + hid_hw_close(dev->hid); } else { kfree(list->hidraw); } @@ -434,7 +431,7 @@ void hidraw_disconnect(struct hid_device *hid) device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); if (hidraw->open) { - hid->ll_driver->close(hid); + hid_hw_close(hid); wake_up_interruptible(&hidraw->wait); } else { kfree(hidraw); diff --git a/include/linux/hid.h b/include/linux/hid.h index bb0f56f5c01e..e2af195d8b46 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -820,6 +820,49 @@ static inline void hid_hw_stop(struct hid_device *hdev) hdev->ll_driver->stop(hdev); } +/** + * hid_hw_open - signal underlaying HW to start delivering events + * + * @hdev: hid device + * + * Tell underlying HW to start delivering events from the device. + * This function should be called sometime after successful call + * to hid_hiw_start(). + */ +static inline int __must_check hid_hw_open(struct hid_device *hdev) +{ + return hdev->ll_driver->open(hdev); +} + +/** + * hid_hw_close - signal underlaying HW to stop delivering events + * + * @hdev: hid device + * + * This function indicates that we are not interested in the events + * from this device anymore. Delivery of events may or may not stop, + * depending on the number of users still outstanding. + */ +static inline void hid_hw_close(struct hid_device *hdev) +{ + hdev->ll_driver->close(hdev); +} + +/** + * hid_hw_power - requests underlying HW to go into given power mode + * + * @hdev: hid device + * @level: requested power level (one of %PM_HINT_* defines) + * + * This function requests underlying hardware to enter requested power + * mode. + */ + +static inline int hid_hw_power(struct hid_device *hdev, int level) +{ + return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0; +} + void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, int interrupt); -- cgit v1.2.3 From 1226056d9608d241db4b558a0d88a347ad5c66ae Mon Sep 17 00:00:00 2001 From: "Chen, Chien-Chia" Date: Wed, 8 Dec 2010 14:20:33 -0800 Subject: Staging: rt3090: Fix RT3090 scan AP function Fix RT3090 scan AP function. This patch fixes the rt3090 wireless module failed to scan AP around due to Windows driver causing rt3090 module unable to scan AP in Linux. Acked-by: Lee, Chun-Yi Signed-off-by: Chen, Chien-Chia Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/chips/rt3090.c | 3 ++- drivers/staging/rt2860/chips/rt30xx.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/chips/rt3090.c b/drivers/staging/rt2860/chips/rt3090.c index 156eb36e56f2..334720ee1345 100644 --- a/drivers/staging/rt2860/chips/rt3090.c +++ b/drivers/staging/rt2860/chips/rt3090.c @@ -52,7 +52,8 @@ void NICInitRT3090RFRegisters(struct rt_rtmp_adapter *pAd) if (IS_RT3090(pAd)) { /* Init RF calibration */ /* Driver should toggle RF R30 bit7 before init RF registers */ - u32 RfReg = 0, data; + u8 RfReg; + u32 data; RT30xxReadRFRegister(pAd, RF_R30, (u8 *)&RfReg); RfReg |= 0x80; diff --git a/drivers/staging/rt2860/chips/rt30xx.c b/drivers/staging/rt2860/chips/rt30xx.c index c8f728257197..e610d39bdca7 100644 --- a/drivers/staging/rt2860/chips/rt30xx.c +++ b/drivers/staging/rt2860/chips/rt30xx.c @@ -54,7 +54,7 @@ struct rt_reg_pair RT30xx_RFRegTable[] = { , {RF_R06, 0x02} , - {RF_R07, 0x70} + {RF_R07, 0x60} , {RF_R09, 0x0F} , -- cgit v1.2.3 From 0dedc37070ba1eabb2d1c7aa7899c7a9100ecf30 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:35 +0100 Subject: staging: brcm80211: removed unused typedefs Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/wlioctl.h | 1 - drivers/staging/brcm80211/sys/wlc_types.h | 9 --------- 2 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/wlioctl.h b/drivers/staging/brcm80211/include/wlioctl.h index 45e02e5293eb..9be793c5f10c 100644 --- a/drivers/staging/brcm80211/include/wlioctl.h +++ b/drivers/staging/brcm80211/include/wlioctl.h @@ -559,7 +559,6 @@ typedef struct wl_led_info { u8 activehi; } wl_led_info_t; - /* R_REG and W_REG struct passed through ioctl */ typedef struct { u32 byteoff; /* byte offset of the field in d11regs_t */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index e5c8600c6298..837f72badecd 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -23,17 +23,8 @@ struct wlc_info; struct wlc_hw_info; typedef struct wlc_if wlc_if_t; typedef struct wl_if wl_if_t; -typedef struct led_info led_info_t; -typedef struct bmac_led bmac_led_t; -typedef struct bmac_led_info bmac_led_info_t; -typedef struct scb_module scb_module_t; -typedef struct ba_info ba_info_t; typedef struct ampdu_info ampdu_info_t; -typedef struct ratesel_info ratesel_info_t; typedef struct wlc_ap_info wlc_ap_info_t; -typedef struct wlc_auth_info wlc_auth_info_t; -typedef struct supplicant supplicant_t; -typedef struct authenticator authenticator_t; typedef struct antsel_info antsel_info_t; typedef struct bmac_pmq bmac_pmq_t; -- cgit v1.2.3 From 41224eb2dfe76fffc95cf9613c5bb2f4a518ddbf Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:36 +0100 Subject: staging: brcm80211: removed unused macro's and typedefs from wpa.h Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/proto/wpa.h | 94 --------------------------- 1 file changed, 94 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/proto/wpa.h b/drivers/staging/brcm80211/include/proto/wpa.h index ec84c9f2b5ee..10c2fb62df09 100644 --- a/drivers/staging/brcm80211/include/proto/wpa.h +++ b/drivers/staging/brcm80211/include/proto/wpa.h @@ -19,95 +19,7 @@ #include -#include - -#define DOT11_RC_INVALID_WPA_IE 13 -#define DOT11_RC_MIC_FAILURE 14 -#define DOT11_RC_4WH_TIMEOUT 15 -#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 -#define DOT11_RC_WPA_IE_MISMATCH 17 -#define DOT11_RC_INVALID_MC_CIPHER 18 -#define DOT11_RC_INVALID_UC_CIPHER 19 -#define DOT11_RC_INVALID_AKMP 20 -#define DOT11_RC_BAD_WPA_VERSION 21 -#define DOT11_RC_INVALID_WPA_CAP 22 -#define DOT11_RC_8021X_AUTH_FAIL 23 - #define WPA2_PMKID_LEN 16 - -typedef BWL_PRE_PACKED_STRUCT struct { - u8 tag; - u8 length; - u8 oui[3]; - u8 oui_type; - BWL_PRE_PACKED_STRUCT struct { - u8 low; - u8 high; - } BWL_POST_PACKED_STRUCT version; -} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; -#define WPA_IE_OUITYPE_LEN 4 -#define WPA_IE_FIXED_LEN 8 -#define WPA_IE_TAG_FIXED_LEN 6 - -typedef BWL_PRE_PACKED_STRUCT struct { - u8 tag; - u8 length; - BWL_PRE_PACKED_STRUCT struct { - u8 low; - u8 high; - } BWL_POST_PACKED_STRUCT version; -} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; -#define WPA_RSN_IE_FIXED_LEN 4 -#define WPA_RSN_IE_TAG_FIXED_LEN 2 -typedef u8 wpa_pmkid_t[WPA2_PMKID_LEN]; - -typedef BWL_PRE_PACKED_STRUCT struct { - u8 oui[3]; - u8 type; -} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; -#define WPA_SUITE_LEN 4 - -typedef BWL_PRE_PACKED_STRUCT struct { - BWL_PRE_PACKED_STRUCT struct { - u8 low; - u8 high; - } BWL_POST_PACKED_STRUCT count; - wpa_suite_t list[1]; -} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; -#define WPA_IE_SUITE_COUNT_LEN 2 -typedef BWL_PRE_PACKED_STRUCT struct { - BWL_PRE_PACKED_STRUCT struct { - u8 low; - u8 high; - } BWL_POST_PACKED_STRUCT count; - wpa_pmkid_t list[1]; -} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; - -#define WPA_CIPHER_NONE 0 -#define WPA_CIPHER_WEP_40 1 -#define WPA_CIPHER_TKIP 2 -#define WPA_CIPHER_AES_OCB 3 -#define WPA_CIPHER_AES_CCM 4 -#define WPA_CIPHER_WEP_104 5 - -#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ - (cipher) == WPA_CIPHER_WEP_40 || \ - (cipher) == WPA_CIPHER_WEP_104 || \ - (cipher) == WPA_CIPHER_TKIP || \ - (cipher) == WPA_CIPHER_AES_OCB || \ - (cipher) == WPA_CIPHER_AES_CCM) - -#define WPA_TKIP_CM_DETECT 60 -#define WPA_TKIP_CM_BLOCK 60 - -#define RSN_CAP_LEN 2 - -#define RSN_CAP_PREAUTH 0x0001 -#define RSN_CAP_NOPAIRWISE 0x0002 -#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C -#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 -#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 -#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 #define RSN_CAP_1_REPLAY_CNTR 0 #define RSN_CAP_2_REPLAY_CNTRS 1 #define RSN_CAP_4_REPLAY_CNTRS 2 @@ -118,10 +30,4 @@ typedef BWL_PRE_PACKED_STRUCT struct { #define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT #define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK -#define WPA_CAP_LEN RSN_CAP_LEN - -#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH - -#include - #endif /* _proto_wpa_h_ */ -- cgit v1.2.3 From 4dc79de1e39957575a784cf79bb214e54a42d44e Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:37 +0100 Subject: staging: brcm80211: replaced typedef wlc_if_t by struct wlc_if Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.h | 6 +++--- drivers/staging/brcm80211/sys/wlc_pub.h | 4 ++-- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index d3246b754c41..11cc6539850c 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -8384,7 +8384,7 @@ static void wlc_txflowcontrol_signal(struct wlc_info *wlc, wlc_txq_info_t *qi, bool on, int prio) { - wlc_if_t *wlcif; + struct wlc_if *wlcif; for (wlcif = wlc->wlcif_list; wlcif != NULL; wlcif = wlcif->next) { if (wlcif->qi == qi && wlcif->flags & WLC_IF_LINKED) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 791e9178267e..81efffff391c 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -383,7 +383,7 @@ typedef struct dumpcb_s { /* virtual interface */ struct wlc_if { - wlc_if_t *next; + struct wlc_if *next; u8 type; /* WLC_IFTYPE_BSS or WLC_IFTYPE_WDS */ u8 index; /* assigned in wl_add_if(), index of the wlif if any, * not necessarily corresponding to bsscfg._idx or @@ -768,7 +768,7 @@ struct wlc_info { u16 next_bsscfg_ID; - wlc_if_t *wlcif_list; /* linked list of wlc_if structs */ + struct wlc_if *wlcif_list; /* linked list of wlc_if structs */ wlc_txq_info_t *active_queue; /* txq for the currently active transmit context */ u32 mpc_dur; /* total time (ms) in mpc mode except for the * portion since radio is turned off last time @@ -946,7 +946,7 @@ extern const bcm_iovar_t wlc_iovars[]; extern int wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, const char *name, void *params, uint p_len, void *arg, - int len, int val_size, wlc_if_t *wlcif); + int len, int val_size, struct wlc_if *wlcif); #if defined(BCMDBG) extern void wlc_print_ies(struct wlc_info *wlc, u8 *ies, uint ies_len); diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index 1530efe15f97..80331e8a81ea 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -510,8 +510,8 @@ extern void wlc_intrsrestore(struct wlc_info *wlc, u32 macintmask); extern bool wlc_intrsupd(struct wlc_info *wlc); extern bool wlc_isr(struct wlc_info *wlc, bool *wantdpc); extern bool wlc_dpc(struct wlc_info *wlc, bool bounded); -extern bool wlc_send80211_raw(struct wlc_info *wlc, wlc_if_t *wlcif, void *p, - uint ac); +extern bool wlc_send80211_raw(struct wlc_info *wlc, struct wlc_if *wlcif, + void *p, uint ac); extern bool wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu, struct ieee80211_hw *hw); extern int wlc_iovar_op(struct wlc_info *wlc, const char *name, void *params, diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 837f72badecd..764bc4960699 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -21,7 +21,7 @@ struct wlc_info; struct wlc_hw_info; -typedef struct wlc_if wlc_if_t; +struct wlc_if; typedef struct wl_if wl_if_t; typedef struct ampdu_info ampdu_info_t; typedef struct wlc_ap_info wlc_ap_info_t; -- cgit v1.2.3 From 1f2fd4531d37553e4613f8f5e79cf199f47a82d2 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:38 +0100 Subject: staging: brcm80211: replaced typedef ampdu_info_t by struct ampdu_info Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_ampdu.c | 66 ++++++++++++++-------------- drivers/staging/brcm80211/sys/wlc_ampdu.h | 20 ++++----- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 4 files changed, 46 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 9e1816b88108..c0883d01c51b 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -130,22 +130,24 @@ struct ampdu_info { #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu)) #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid])) -static void wlc_ffpld_init(ampdu_info_t *ampdu); +static void wlc_ffpld_init(struct ampdu_info *ampdu); static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f); -static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f); +static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f); -static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu, +static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid, bool override); -static void ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, +static void ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, + scb_ampdu_t *scb_ampdu, u8 tid, bool force); -static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur); -static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb); -static void scb_ampdu_update_config_all(ampdu_info_t *ampdu); +static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur); +static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb); +static void scb_ampdu_update_config_all(struct ampdu_info *ampdu); #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0) -static void wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, +static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, + struct scb *scb, struct sk_buff *p, tx_status_t *txs, u32 frmtxstatus, u32 frmtxstatus2); @@ -158,9 +160,9 @@ static inline u16 pkt_txh_seqnum(struct wlc_info *wlc, struct sk_buff *p) return ltoh16(h->seq) >> SEQNUM_SHIFT; } -ampdu_info_t *wlc_ampdu_attach(struct wlc_info *wlc) +struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc) { - ampdu_info_t *ampdu; + struct ampdu_info *ampdu; int i; /* some code depends on packed structures */ @@ -170,7 +172,7 @@ ampdu_info_t *wlc_ampdu_attach(struct wlc_info *wlc) ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU); ASSERT(wlc->pub->tunables->ampdunummpdu > 0); - ampdu = kzalloc(sizeof(ampdu_info_t), GFP_ATOMIC); + ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC); if (!ampdu) { WL_ERROR(("wl%d: wlc_ampdu_attach: out of mem\n", wlc->pub->unit)); return NULL; @@ -219,7 +221,7 @@ ampdu_info_t *wlc_ampdu_attach(struct wlc_info *wlc) return ampdu; } -void wlc_ampdu_detach(ampdu_info_t *ampdu) +void wlc_ampdu_detach(struct ampdu_info *ampdu) { int i; @@ -237,7 +239,7 @@ void wlc_ampdu_detach(ampdu_info_t *ampdu) kfree(ampdu); } -void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb) +void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb) { scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb); u8 tid; @@ -253,12 +255,12 @@ void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb) /* reset the ampdu state machine so that it can gracefully handle packets that were * freed from the dma and tx queues during reinit */ -void wlc_ampdu_reset(ampdu_info_t *ampdu) +void wlc_ampdu_reset(struct ampdu_info *ampdu) { WL_NONE(("%s: Entering\n", __func__)); } -static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb) +static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb) { scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb); int i; @@ -288,12 +290,12 @@ static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb) ASSERT(scb_ampdu->release); } -void scb_ampdu_update_config_all(ampdu_info_t *ampdu) +void scb_ampdu_update_config_all(struct ampdu_info *ampdu) { scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb); } -static void wlc_ffpld_init(ampdu_info_t *ampdu) +static void wlc_ffpld_init(struct ampdu_info *ampdu) { int i, j; wlc_fifo_info_t *fifo; @@ -319,7 +321,7 @@ static void wlc_ffpld_init(ampdu_info_t *ampdu) */ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) { - ampdu_info_t *ampdu = wlc->ampdu; + struct ampdu_info *ampdu = wlc->ampdu; u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false); u32 txunfl_ratio; u8 max_mpdu; @@ -437,7 +439,7 @@ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) return 0; } -static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f) +static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f) { int i; u32 phy_rate, dma_rate, tmp; @@ -470,7 +472,7 @@ static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f) } static void BCMFASTPATH -wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, +wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p, uint prec) { scb_ampdu_t *scb_ampdu; @@ -488,8 +490,8 @@ wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, } int BCMFASTPATH -wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, - int prec) +wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, + struct sk_buff **pdu, int prec) { struct wlc_info *wlc; struct osl_info *osh; @@ -885,8 +887,8 @@ wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, struct sk_buff **pdu, } void BCMFASTPATH -wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, struct sk_buff *p, - tx_status_t *txs) +wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, + struct sk_buff *p, tx_status_t *txs) { scb_ampdu_t *scb_ampdu; struct wlc_info *wlc = ampdu->wlc; @@ -949,7 +951,7 @@ rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info, #define SHORTNAME "AMPDU status" static void BCMFASTPATH -wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, +wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p, tx_status_t *txs, u32 s1, u32 s2) { @@ -1173,7 +1175,7 @@ wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, } static void -ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, u8 tid, +ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid, bool force) { scb_ampdu_tid_ini_t *ini; @@ -1195,7 +1197,7 @@ ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, u8 tid, } /* initialize the initiator code for tid */ -static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu, +static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid, bool override) { @@ -1221,7 +1223,7 @@ static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu, return ini; } -int wlc_ampdu_set(ampdu_info_t *ampdu, bool on) +int wlc_ampdu_set(struct ampdu_info *ampdu, bool on) { struct wlc_info *wlc = ampdu->wlc; @@ -1244,7 +1246,7 @@ int wlc_ampdu_set(ampdu_info_t *ampdu, bool on) return 0; } -bool wlc_ampdu_cap(ampdu_info_t *ampdu) +bool wlc_ampdu_cap(struct ampdu_info *ampdu) { if (WLC_PHY_11N_CAP(ampdu->wlc->band)) return true; @@ -1252,7 +1254,7 @@ bool wlc_ampdu_cap(ampdu_info_t *ampdu) return false; } -static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur) +static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur) { u32 rate, mcs; @@ -1274,7 +1276,7 @@ static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur) } u8 BCMFASTPATH -wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb, +wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb, ratespec_t rspec, int phylen) { scb_ampdu_t *scb_ampdu; @@ -1326,7 +1328,7 @@ bool wlc_aggregatable(struct wlc_info *wlc, u8 tid) return wlc->ampdu->ini_enable[tid]; } -void wlc_ampdu_shm_upd(ampdu_info_t *ampdu) +void wlc_ampdu_shm_upd(struct ampdu_info *ampdu) { struct wlc_info *wlc = ampdu->wlc; diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.h b/drivers/staging/brcm80211/sys/wlc_ampdu.h index 4c3358da89e5..03457f63f2ab 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.h +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.h @@ -17,20 +17,20 @@ #ifndef _wlc_ampdu_h_ #define _wlc_ampdu_h_ -extern ampdu_info_t *wlc_ampdu_attach(struct wlc_info *wlc); -extern void wlc_ampdu_detach(ampdu_info_t *ampdu); -extern bool wlc_ampdu_cap(ampdu_info_t *ampdu); -extern int wlc_ampdu_set(ampdu_info_t *ampdu, bool on); -extern int wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, +extern struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc); +extern void wlc_ampdu_detach(struct ampdu_info *ampdu); +extern bool wlc_ampdu_cap(struct ampdu_info *ampdu); +extern int wlc_ampdu_set(struct ampdu_info *ampdu, bool on); +extern int wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, struct sk_buff **aggp, int prec); -extern void wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, +extern void wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p, tx_status_t *txs); -extern void wlc_ampdu_reset(ampdu_info_t *ampdu); +extern void wlc_ampdu_reset(struct ampdu_info *ampdu); extern void wlc_ampdu_macaddr_upd(struct wlc_info *wlc); -extern void wlc_ampdu_shm_upd(ampdu_info_t *ampdu); +extern void wlc_ampdu_shm_upd(struct ampdu_info *ampdu); -extern u8 wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb, +extern u8 wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb, ratespec_t rspec, int phylen); -extern void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb); +extern void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb); #endif /* _wlc_ampdu_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 81efffff391c..59a8d6beca1b 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -548,7 +548,7 @@ struct wlc_info { u8 txpwr_local_constraint; /* local power contraint in dB */ - ampdu_info_t *ampdu; /* ampdu module handler */ + struct ampdu_info *ampdu; /* ampdu module handler */ antsel_info_t *asi; /* antsel module handler */ wlc_cm_info_t *cmi; /* channel manager module handler */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 764bc4960699..9c18a7f592d3 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -23,7 +23,7 @@ struct wlc_info; struct wlc_hw_info; struct wlc_if; typedef struct wl_if wl_if_t; -typedef struct ampdu_info ampdu_info_t; +struct ampdu_info; typedef struct wlc_ap_info wlc_ap_info_t; typedef struct antsel_info antsel_info_t; typedef struct bmac_pmq bmac_pmq_t; -- cgit v1.2.3 From 0e4934748948b5886c965fe56207b41d3abd58e7 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:39 +0100 Subject: staging: brcm80211: replaced typedef wlc_ap_info_t by struct wlc_ap_info Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 59a8d6beca1b..1d5149ee1207 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -749,7 +749,7 @@ struct wlc_info { ac_bitmap_t apsd_trigger_ac; /* Permissible Acess Category in which APSD Null * Trigger frames can be send */ - wlc_ap_info_t *ap; + struct wlc_ap_info *ap; u8 htphy_membership; /* HT PHY membership */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 9c18a7f592d3..9634a66582ac 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -24,7 +24,7 @@ struct wlc_hw_info; struct wlc_if; typedef struct wl_if wl_if_t; struct ampdu_info; -typedef struct wlc_ap_info wlc_ap_info_t; +struct wlc_ap_info; typedef struct antsel_info antsel_info_t; typedef struct bmac_pmq bmac_pmq_t; -- cgit v1.2.3 From 299f8a4658e055d9f9713f7bed45860474544e68 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:40 +0100 Subject: staging: brcm80211: replaced typedef antsel_info_t by struct antsel_info Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_antsel.c | 32 +++++++++++++++------------- drivers/staging/brcm80211/sys/wlc_antsel.h | 11 +++++----- drivers/staging/brcm80211/sys/wlc_mac80211.h | 7 ++++-- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 4 files changed, 29 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index 9533b5687302..aaf9985a1995 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -63,10 +63,11 @@ #define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */ /* static functions */ -static int wlc_antsel_cfgupd(antsel_info_t *asi, wlc_antselcfg_t *antsel); -static u8 wlc_antsel_id2antcfg(antsel_info_t *asi, u8 id); -static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg); -static void wlc_antsel_init_cfg(antsel_info_t *asi, wlc_antselcfg_t *antsel, +static int wlc_antsel_cfgupd(struct antsel_info *asi, wlc_antselcfg_t *antsel); +static u8 wlc_antsel_id2antcfg(struct antsel_info *asi, u8 id); +static u16 wlc_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg); +static void wlc_antsel_init_cfg(struct antsel_info *asi, + wlc_antselcfg_t *antsel, bool auto_sel); const u16 mimo_2x4_div_antselpat_tbl[] = { @@ -93,12 +94,13 @@ const u8 mimo_2x3_div_antselid_tbl[16] = { 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */ }; -antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, +struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc, + struct osl_info *osh, wlc_pub_t *pub, struct wlc_hw_info *wlc_hw) { - antsel_info_t *asi; + struct antsel_info *asi; - asi = kzalloc(sizeof(antsel_info_t), GFP_ATOMIC); + asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); if (!asi) { WL_ERROR(("wl%d: wlc_antsel_attach: out of mem\n", pub->unit)); return NULL; @@ -157,7 +159,7 @@ antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, return asi; } -void wlc_antsel_detach(antsel_info_t *asi) +void wlc_antsel_detach(struct antsel_info *asi) { if (!asi) return; @@ -165,7 +167,7 @@ void wlc_antsel_detach(antsel_info_t *asi) kfree(asi); } -void wlc_antsel_init(antsel_info_t *asi) +void wlc_antsel_init(struct antsel_info *asi) { if ((asi->antsel_type == ANTSEL_2x3) || (asi->antsel_type == ANTSEL_2x4)) @@ -174,7 +176,7 @@ void wlc_antsel_init(antsel_info_t *asi) /* boardlevel antenna selection: init antenna selection structure */ static void -wlc_antsel_init_cfg(antsel_info_t *asi, wlc_antselcfg_t *antsel, +wlc_antsel_init_cfg(struct antsel_info *asi, wlc_antselcfg_t *antsel, bool auto_sel) { if (asi->antsel_type == ANTSEL_2x3) { @@ -205,7 +207,7 @@ wlc_antsel_init_cfg(antsel_info_t *asi, wlc_antselcfg_t *antsel, } void BCMFASTPATH -wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel, +wlc_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel, u8 antselid, u8 fbantselid, u8 *antcfg, u8 *fbantcfg) { @@ -237,7 +239,7 @@ wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel, } /* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */ -u8 wlc_antsel_antsel2id(antsel_info_t *asi, u16 antsel) +u8 wlc_antsel_antsel2id(struct antsel_info *asi, u16 antsel) { u8 antselid = 0; @@ -256,7 +258,7 @@ u8 wlc_antsel_antsel2id(antsel_info_t *asi, u16 antsel) } /* boardlevel antenna selection: convert id to ant_cfg */ -static u8 wlc_antsel_id2antcfg(antsel_info_t *asi, u8 id) +static u8 wlc_antsel_id2antcfg(struct antsel_info *asi, u8 id) { u8 antcfg = ANT_SELCFG_DEF_2x2; @@ -275,7 +277,7 @@ static u8 wlc_antsel_id2antcfg(antsel_info_t *asi, u8 id) } /* boardlevel antenna selection: convert ant_cfg to mimo_antsel (ucode interface) */ -static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg) +static u16 wlc_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg) { u8 idx = WLC_ANTIDX_11N(WLC_ANTSEL_11N(ant_cfg)); u16 mimo_antsel = 0; @@ -295,7 +297,7 @@ static u16 wlc_antsel_antcfg2antsel(antsel_info_t *asi, u8 ant_cfg) } /* boardlevel antenna selection: ucode interface control */ -static int wlc_antsel_cfgupd(antsel_info_t *asi, wlc_antselcfg_t *antsel) +static int wlc_antsel_cfgupd(struct antsel_info *asi, wlc_antselcfg_t *antsel) { struct wlc_info *wlc = asi->wlc; u8 ant_cfg; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.h b/drivers/staging/brcm80211/sys/wlc_antsel.h index 763986dd226e..ba38a2aedbd9 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.h +++ b/drivers/staging/brcm80211/sys/wlc_antsel.h @@ -16,14 +16,15 @@ #ifndef _wlc_antsel_h_ #define _wlc_antsel_h_ -extern antsel_info_t *wlc_antsel_attach(struct wlc_info *wlc, +extern struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, wlc_pub_t *pub, struct wlc_hw_info *wlc_hw); -extern void wlc_antsel_detach(antsel_info_t *asi); -extern void wlc_antsel_init(antsel_info_t *asi); -extern void wlc_antsel_antcfg_get(antsel_info_t *asi, bool usedef, bool sel, +extern void wlc_antsel_detach(struct antsel_info *asi); +extern void wlc_antsel_init(struct antsel_info *asi); +extern void wlc_antsel_antcfg_get(struct antsel_info *asi, bool usedef, + bool sel, u8 id, u8 fbid, u8 *antcfg, u8 *fbantcfg); -extern u8 wlc_antsel_antsel2id(antsel_info_t *asi, u16 antsel); +extern u8 wlc_antsel_antsel2id(struct antsel_info *asi, u16 antsel); #endif /* _wlc_antsel_h_ */ diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 1d5149ee1207..2ad37f612f00 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -487,7 +487,10 @@ struct wlc_hw_info { u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board */ - u32 antsel_avail; /* put antsel_info_t here if more info is needed */ + u32 antsel_avail; /* + * put struct antsel_info here if more info is + * needed + */ }; /* TX Queue information @@ -549,7 +552,7 @@ struct wlc_info { struct ampdu_info *ampdu; /* ampdu module handler */ - antsel_info_t *asi; /* antsel module handler */ + struct antsel_info *asi; /* antsel module handler */ wlc_cm_info_t *cmi; /* channel manager module handler */ void *btparam; /* bus type specific cookie */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 9634a66582ac..284e7c350c81 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -25,7 +25,7 @@ struct wlc_if; typedef struct wl_if wl_if_t; struct ampdu_info; struct wlc_ap_info; -typedef struct antsel_info antsel_info_t; +struct antsel_info; typedef struct bmac_pmq bmac_pmq_t; struct d11init; -- cgit v1.2.3 From d65ddb58325ba2c4fef70f6c9ff542df81e5cdb3 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:41 +0100 Subject: staging: brcm80211: replaced typedef bmac_pmq_t by struct bmac_pmq Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 2ad37f612f00..bfd9ad4118ad 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -476,7 +476,7 @@ struct wlc_hw_info { bool forcefastclk; /* true if the h/w is forcing the use of fast clk */ bool clk; /* core is out of reset and has clock */ bool sbclk; /* sb has clock */ - bmac_pmq_t *bmac_pmq; /* bmac PM states derived from ucode PMQ */ + struct bmac_pmq *bmac_pmq; /* bmac PM states derived from ucode PMQ */ bool phyclk; /* phy is out of reset and has clock */ bool dma_lpbk; /* core is in DMA loopback */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 284e7c350c81..5f63c48b00fd 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -26,7 +26,7 @@ typedef struct wl_if wl_if_t; struct ampdu_info; struct wlc_ap_info; struct antsel_info; -typedef struct bmac_pmq bmac_pmq_t; +struct bmac_pmq; struct d11init; -- cgit v1.2.3 From 6cdeaef203155bd7f12d362e5345323cfecde58a Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:42 +0100 Subject: staging: brcm80211: replaced typedef wl_if_t by struct wl_if Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wl_mac80211.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index d41212bca633..1e7a29d006be 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -98,7 +98,7 @@ struct ieee80211_tkip_data { u8 rx_hdr[16], tx_hdr[16]; }; -#define WL_DEV_IF(dev) ((wl_if_t *)netdev_priv(dev)) +#define WL_DEV_IF(dev) ((struct wl_if *)netdev_priv(dev)) #define WL_INFO(dev) ((struct wl_info *)(WL_DEV_IF(dev)->wl)) static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev); static void wl_release_fw(struct wl_info *wl); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index bfd9ad4118ad..2054e346eab4 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -390,7 +390,7 @@ struct wlc_if { * AID2PVBMAP(scb). */ u8 flags; /* flags for the interface */ - wl_if_t *wlif; /* pointer to wlif */ + struct wl_if *wlif; /* pointer to wlif */ struct wlc_txq_info *qi; /* pointer to associated tx queue */ union { struct scb *scb; /* pointer to scb if WLC_IFTYPE_WDS */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 5f63c48b00fd..7e2e198334ca 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -22,7 +22,7 @@ struct wlc_info; struct wlc_hw_info; struct wlc_if; -typedef struct wl_if wl_if_t; +struct wl_if; struct ampdu_info; struct wlc_ap_info; struct antsel_info; -- cgit v1.2.3 From 17d766510b9630cfa723a6711e314565a048c234 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:43 +0100 Subject: staging: brcm80211: replaced typedef hnddma_t by struct hnddma_pub Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/hnddma.h | 89 ++++++++++++++-------------- drivers/staging/brcm80211/sys/wlc_bmac.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_types.h | 2 +- drivers/staging/brcm80211/util/hnddma.c | 8 +-- 6 files changed, 53 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/hnddma.h b/drivers/staging/brcm80211/include/hnddma.h index 05dd9ba19858..4c5462baf11e 100644 --- a/drivers/staging/brcm80211/include/hnddma.h +++ b/drivers/staging/brcm80211/include/hnddma.h @@ -19,7 +19,7 @@ #ifndef _hnddma_pub_ #define _hnddma_pub_ -typedef const struct hnddma_pub hnddma_t; +struct hnddma_pub; #endif /* _hnddma_pub_ */ /* range param for dma_getnexttxp() and dma_txreclaim */ @@ -30,52 +30,54 @@ typedef enum txd_range { } txd_range_t; /* dma function type */ -typedef void (*di_detach_t) (hnddma_t *dmah); -typedef bool(*di_txreset_t) (hnddma_t *dmah); -typedef bool(*di_rxreset_t) (hnddma_t *dmah); -typedef bool(*di_rxidle_t) (hnddma_t *dmah); -typedef void (*di_txinit_t) (hnddma_t *dmah); -typedef bool(*di_txenabled_t) (hnddma_t *dmah); -typedef void (*di_rxinit_t) (hnddma_t *dmah); -typedef void (*di_txsuspend_t) (hnddma_t *dmah); -typedef void (*di_txresume_t) (hnddma_t *dmah); -typedef bool(*di_txsuspended_t) (hnddma_t *dmah); -typedef bool(*di_txsuspendedidle_t) (hnddma_t *dmah); -typedef int (*di_txfast_t) (hnddma_t *dmah, struct sk_buff *p, bool commit); -typedef int (*di_txunframed_t) (hnddma_t *dmah, void *p, uint len, +typedef void (*di_detach_t) (struct hnddma_pub *dmah); +typedef bool(*di_txreset_t) (struct hnddma_pub *dmah); +typedef bool(*di_rxreset_t) (struct hnddma_pub *dmah); +typedef bool(*di_rxidle_t) (struct hnddma_pub *dmah); +typedef void (*di_txinit_t) (struct hnddma_pub *dmah); +typedef bool(*di_txenabled_t) (struct hnddma_pub *dmah); +typedef void (*di_rxinit_t) (struct hnddma_pub *dmah); +typedef void (*di_txsuspend_t) (struct hnddma_pub *dmah); +typedef void (*di_txresume_t) (struct hnddma_pub *dmah); +typedef bool(*di_txsuspended_t) (struct hnddma_pub *dmah); +typedef bool(*di_txsuspendedidle_t) (struct hnddma_pub *dmah); +typedef int (*di_txfast_t) (struct hnddma_pub *dmah, struct sk_buff *p, + bool commit); +typedef int (*di_txunframed_t) (struct hnddma_pub *dmah, void *p, uint len, bool commit); -typedef void *(*di_getpos_t) (hnddma_t *di, bool direction); -typedef void (*di_fifoloopbackenable_t) (hnddma_t *dmah); -typedef bool(*di_txstopped_t) (hnddma_t *dmah); -typedef bool(*di_rxstopped_t) (hnddma_t *dmah); -typedef bool(*di_rxenable_t) (hnddma_t *dmah); -typedef bool(*di_rxenabled_t) (hnddma_t *dmah); -typedef void *(*di_rx_t) (hnddma_t *dmah); -typedef bool(*di_rxfill_t) (hnddma_t *dmah); -typedef void (*di_txreclaim_t) (hnddma_t *dmah, txd_range_t range); -typedef void (*di_rxreclaim_t) (hnddma_t *dmah); -typedef unsigned long (*di_getvar_t) (hnddma_t *dmah, const char *name); -typedef void *(*di_getnexttxp_t) (hnddma_t *dmah, txd_range_t range); -typedef void *(*di_getnextrxp_t) (hnddma_t *dmah, bool forceall); -typedef void *(*di_peeknexttxp_t) (hnddma_t *dmah); -typedef void *(*di_peeknextrxp_t) (hnddma_t *dmah); -typedef void (*di_rxparam_get_t) (hnddma_t *dmah, u16 *rxoffset, +typedef void *(*di_getpos_t) (struct hnddma_pub *di, bool direction); +typedef void (*di_fifoloopbackenable_t) (struct hnddma_pub *dmah); +typedef bool(*di_txstopped_t) (struct hnddma_pub *dmah); +typedef bool(*di_rxstopped_t) (struct hnddma_pub *dmah); +typedef bool(*di_rxenable_t) (struct hnddma_pub *dmah); +typedef bool(*di_rxenabled_t) (struct hnddma_pub *dmah); +typedef void *(*di_rx_t) (struct hnddma_pub *dmah); +typedef bool(*di_rxfill_t) (struct hnddma_pub *dmah); +typedef void (*di_txreclaim_t) (struct hnddma_pub *dmah, txd_range_t range); +typedef void (*di_rxreclaim_t) (struct hnddma_pub *dmah); +typedef unsigned long (*di_getvar_t) (struct hnddma_pub *dmah, + const char *name); +typedef void *(*di_getnexttxp_t) (struct hnddma_pub *dmah, txd_range_t range); +typedef void *(*di_getnextrxp_t) (struct hnddma_pub *dmah, bool forceall); +typedef void *(*di_peeknexttxp_t) (struct hnddma_pub *dmah); +typedef void *(*di_peeknextrxp_t) (struct hnddma_pub *dmah); +typedef void (*di_rxparam_get_t) (struct hnddma_pub *dmah, u16 *rxoffset, u16 *rxbufsize); -typedef void (*di_txblock_t) (hnddma_t *dmah); -typedef void (*di_txunblock_t) (hnddma_t *dmah); -typedef uint(*di_txactive_t) (hnddma_t *dmah); -typedef void (*di_txrotate_t) (hnddma_t *dmah); -typedef void (*di_counterreset_t) (hnddma_t *dmah); -typedef uint(*di_ctrlflags_t) (hnddma_t *dmah, uint mask, uint flags); -typedef char *(*di_dump_t) (hnddma_t *dmah, struct bcmstrbuf *b, +typedef void (*di_txblock_t) (struct hnddma_pub *dmah); +typedef void (*di_txunblock_t) (struct hnddma_pub *dmah); +typedef uint(*di_txactive_t) (struct hnddma_pub *dmah); +typedef void (*di_txrotate_t) (struct hnddma_pub *dmah); +typedef void (*di_counterreset_t) (struct hnddma_pub *dmah); +typedef uint(*di_ctrlflags_t) (struct hnddma_pub *dmah, uint mask, uint flags); +typedef char *(*di_dump_t) (struct hnddma_pub *dmah, struct bcmstrbuf *b, bool dumpring); -typedef char *(*di_dumptx_t) (hnddma_t *dmah, struct bcmstrbuf *b, +typedef char *(*di_dumptx_t) (struct hnddma_pub *dmah, struct bcmstrbuf *b, bool dumpring); -typedef char *(*di_dumprx_t) (hnddma_t *dmah, struct bcmstrbuf *b, +typedef char *(*di_dumprx_t) (struct hnddma_pub *dmah, struct bcmstrbuf *b, bool dumpring); -typedef uint(*di_rxactive_t) (hnddma_t *dmah); -typedef uint(*di_txpending_t) (hnddma_t *dmah); -typedef uint(*di_txcommitted_t) (hnddma_t *dmah); +typedef uint(*di_rxactive_t) (struct hnddma_pub *dmah); +typedef uint(*di_txpending_t) (struct hnddma_pub *dmah); +typedef uint(*di_txcommitted_t) (struct hnddma_pub *dmah); /* dma opsvec */ typedef struct di_fcn_s { @@ -141,7 +143,8 @@ struct hnddma_pub { uint txnobuf; /* tx out of dma descriptors */ }; -extern hnddma_t *dma_attach(struct osl_info *osh, char *name, si_t *sih, +extern struct hnddma_pub *dma_attach(struct osl_info *osh, char *name, + si_t *sih, void *dmaregstx, void *dmaregsrx, uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, uint nrxpost, uint rxoffset, uint *msg_level); diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 4042d5e9d205..dff4f6bf77e2 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -2295,7 +2295,7 @@ void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw) static bool wlc_dma_rxreset(struct wlc_hw_info *wlc_hw, uint fifo) { - hnddma_t *di = wlc_hw->di[fifo]; + struct hnddma_pub *di = wlc_hw->di[fifo]; struct osl_info *osh; if (D11REV_LT(wlc_hw->corerev, 12)) { diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 11cc6539850c..32e7538e6d8a 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -6467,7 +6467,7 @@ void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus) static void *wlc_15420war(struct wlc_info *wlc, uint queue) { - hnddma_t *di; + struct hnddma_pub *di; void *p; ASSERT(queue < NFIFO); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index 2054e346eab4..b8bfbe6ce71d 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -424,7 +424,7 @@ struct wlc_hw_info { struct wlc_info *wlc; /* fifo */ - hnddma_t *di[NFIFO]; /* hnddma handles, per fifo */ + struct hnddma_pub *di[NFIFO]; /* hnddma handles, per fifo */ uint unit; /* device instance number */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 7e2e198334ca..175ef1e42af2 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -32,7 +32,7 @@ struct d11init; #ifndef _hnddma_pub_ #define _hnddma_pub_ -typedef const struct hnddma_pub hnddma_t; +struct hnddma_pub; #endif /* _hnddma_pub_ */ #endif /* _wlc_types_h_ */ diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index cf9e469af988..d08869239d5b 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -78,9 +78,7 @@ static uint dma_msg_level; /* dma engine software state */ typedef struct dma_info { - struct hnddma_pub hnddma; /* exported structure, don't use hnddma_t, - * which could be const - */ + struct hnddma_pub hnddma; /* exported structure */ uint *msg_level; /* message level pointer */ char name[MAXNAMEL]; /* callers name for diag msgs */ @@ -376,7 +374,7 @@ static const di_fcn_t dma32proc = { 39 }; -hnddma_t *dma_attach(struct osl_info *osh, char *name, si_t *sih, +struct hnddma_pub *dma_attach(struct osl_info *osh, char *name, si_t *sih, void *dmaregstx, void *dmaregsrx, uint ntxd, uint nrxd, uint rxbufsize, int rxextheadroom, uint nrxpost, uint rxoffset, uint *msg_level) @@ -578,7 +576,7 @@ hnddma_t *dma_attach(struct osl_info *osh, char *name, si_t *sih, } } - return (hnddma_t *) di; + return (struct hnddma_pub *) di; fail: _dma_detach(di); -- cgit v1.2.3 From f077f7185ce19adc234b96c6f9fb815301770c26 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:44 +0100 Subject: staging: brcm80211: replaced typedef wlcband_t by struct wlcband Code cleanup. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_alloc.c | 8 ++++---- drivers/staging/brcm80211/sys/wlc_channel.c | 6 +++--- drivers/staging/brcm80211/sys/wlc_mac80211.c | 11 ++++++----- drivers/staging/brcm80211/sys/wlc_mac80211.h | 9 +++++---- drivers/staging/brcm80211/sys/wlc_stf.c | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index a568e978f6c6..09a1efd7b430 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -267,8 +267,8 @@ struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, goto fail; } - wlc->bandstate[0] = (wlcband_t *)wlc_calloc(osh, unit, - (sizeof(wlcband_t) * MAXBANDS)); + wlc->bandstate[0] = (struct wlcband *)wlc_calloc(osh, unit, + (sizeof(struct wlcband)*MAXBANDS)); if (wlc->bandstate[0] == NULL) { *err = 1025; goto fail; @@ -277,8 +277,8 @@ struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, for (i = 1; i < MAXBANDS; i++) { wlc->bandstate[i] = - (wlcband_t *) ((unsigned long)wlc->bandstate[0] + - (sizeof(wlcband_t) * i)); + (struct wlcband *) ((unsigned long)wlc->bandstate[0] + + (sizeof(struct wlcband)*i)); } } diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index e367ed4f1e91..741e13af7b67 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -905,7 +905,7 @@ wlc_channels_init(wlc_cm_info_t *wlc_cm, const country_info_t *country) { struct wlc_info *wlc = wlc_cm->wlc; uint i, j; - wlcband_t *band; + struct wlcband *band; const locale_info_t *li; chanvec_t sup_chan; const locale_mimo_info_t *li_mimo; @@ -1005,7 +1005,7 @@ void wlc_quiet_channels_reset(wlc_cm_info_t *wlc_cm) { struct wlc_info *wlc = wlc_cm->wlc; uint i, j; - wlcband_t *band; + struct wlcband *band; const chanvec_t *chanvec; memset(&wlc_cm->quiet_channels, 0, sizeof(chanvec_t)); @@ -1310,7 +1310,7 @@ wlc_channel_reg_limits(wlc_cm_info_t *wlc_cm, chanspec_t chanspec, int maxpwr; int delta; const country_info_t *country; - wlcband_t *band; + struct wlcband *band; const locale_info_t *li; int conducted_max; int conducted_ofdm_max; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 32e7538e6d8a..b25b5bd6a110 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -233,7 +233,7 @@ static u16 BCMFASTPATH wlc_d11hdrs_mac80211(struct wlc_info *wlc, static void wlc_bss_default_init(struct wlc_info *wlc); static void wlc_ucode_mac_upd(struct wlc_info *wlc); static ratespec_t mac80211_wlc_set_nrate(struct wlc_info *wlc, - wlcband_t *cur_band, u32 int_val); + struct wlcband *cur_band, u32 int_val); static void wlc_tx_prec_map_init(struct wlc_info *wlc); static void wlc_watchdog(void *arg); static void wlc_watchdog_by_timer(void *arg); @@ -2764,7 +2764,7 @@ int wlc_set_gmode(struct wlc_info *wlc, u8 gmode, bool config) bool preamble_restrict = false; /* Restrict association to stations that support short * preambles */ - wlcband_t *band; + struct wlcband *band; /* if N-support is enabled, allow Gmode set as long as requested * Gmode is not GMODE_LEGACY_B @@ -7480,7 +7480,7 @@ bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rspec, int band, static void wlc_update_mimo_band_bwcap(struct wlc_info *wlc, u8 bwcap) { uint i; - wlcband_t *band; + struct wlcband *band; for (i = 0; i < NBANDS(wlc); i++) { if (IS_SINGLEBAND_5G(wlc->deviceid)) @@ -7901,7 +7901,7 @@ void wlc_default_rateset(struct wlc_info *wlc, wlc_rateset_t *rs) static void wlc_bss_default_init(struct wlc_info *wlc) { chanspec_t chanspec; - wlcband_t *band; + struct wlcband *band; wlc_bss_info_t *bi = wlc->default_bss; /* init default and target BSS with some sane initial values */ @@ -7962,7 +7962,8 @@ wlc_uint64_sub(u32 *a_high, u32 *a_low, u32 b_high, u32 b_low) } static ratespec_t -mac80211_wlc_set_nrate(struct wlc_info *wlc, wlcband_t *cur_band, u32 int_val) +mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band, + u32 int_val) { u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT; u8 rate = int_val & NRATE_RATE_MASK; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index b8bfbe6ce71d..acd854886df6 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -315,7 +315,7 @@ typedef struct wlccore { /* * band state (phy+ana+radio) */ -typedef struct wlcband { +struct wlcband { int bandtype; /* WLC_BAND_2G, WLC_BAND_5G */ uint bandunit; /* bandstate[] index */ @@ -344,7 +344,7 @@ typedef struct wlcband { u16 CWmin; /* The minimum size of contention window, in unit of aSlotTime */ u16 CWmax; /* The maximum size of contention window, in unit of aSlotTime */ u16 bcntsfoff; /* beacon tsf offset */ -} wlcband_t; +}; /* generic function callback takes just one arg */ typedef void (*cb_fn_t) (void *); @@ -533,9 +533,10 @@ struct wlc_info { /* multiband */ wlccore_t *core; /* pointer to active io core */ - wlcband_t *band; /* pointer to active per-band state */ + struct wlcband *band; /* pointer to active per-band state */ wlccore_t *corestate; /* per-core state (one per hw core) */ - wlcband_t *bandstate[MAXBANDS]; /* per-band state (one per phy/radio) */ + /* per-band state (one per phy/radio): */ + struct wlcband *bandstate[MAXBANDS]; bool war16165; /* PCI slow clock 16165 war flag */ diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c index ee090746b088..01ac0d2b3cdb 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.c +++ b/drivers/staging/brcm80211/sys/wlc_stf.c @@ -371,7 +371,7 @@ int wlc_stf_rxchain_set(struct wlc_info *wlc, s32 int_val) } /* update wlc->stf->ss_opmode which represents the operational stf_ss mode we're using */ -int wlc_stf_ss_update(struct wlc_info *wlc, wlcband_t *band) +int wlc_stf_ss_update(struct wlc_info *wlc, struct wlcband *band) { int ret_code = 0; u8 prev_stf_ss; -- cgit v1.2.3 From c41c858f695b6626e2fc0729edc0dd26b091f354 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:45 +0100 Subject: staging: brcm80211: replaced typedef wlccore_t by struct wlccore Code cleanup Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_alloc.c | 3 ++- drivers/staging/brcm80211/sys/wlc_mac80211.h | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 09a1efd7b430..7d04d532a024 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -282,7 +282,8 @@ struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, } } - wlc->corestate = (wlccore_t *)wlc_calloc(osh, unit, sizeof(wlccore_t)); + wlc->corestate = (struct wlccore *)wlc_calloc(osh, unit, + sizeof(struct wlccore)); if (wlc->corestate == NULL) { *err = 1026; goto fail; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index acd854886df6..ba2b953800e3 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -302,7 +302,7 @@ typedef struct wlc_stf { /* * core state (mac) */ -typedef struct wlccore { +struct wlccore { uint coreidx; /* # sb enumerated core */ /* fifo */ @@ -310,7 +310,7 @@ typedef struct wlccore { s16 txpktpend[NFIFO]; /* tx admission control */ macstat_t *macstat_snapshot; /* mac hw prev read values */ -} wlccore_t; +}; /* * band state (phy+ana+radio) @@ -532,9 +532,9 @@ struct wlc_info { bool clk; /* core is out of reset and has clock */ /* multiband */ - wlccore_t *core; /* pointer to active io core */ + struct wlccore *core; /* pointer to active io core */ struct wlcband *band; /* pointer to active per-band state */ - wlccore_t *corestate; /* per-core state (one per hw core) */ + struct wlccore *corestate; /* per-core state (one per hw core) */ /* per-band state (one per phy/radio): */ struct wlcband *bandstate[MAXBANDS]; -- cgit v1.2.3 From 08db27dc8d829e6df007cd079fdfa83584f66544 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Tue, 7 Dec 2010 17:45:46 +0100 Subject: staging: brcm80211: replaced typedef wlc_pub_t by struct wlc_pub Code cleanup Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wl_mac80211.h | 2 +- drivers/staging/brcm80211/sys/wlc_alloc.c | 18 +++++++++--------- drivers/staging/brcm80211/sys/wlc_antsel.c | 4 ++-- drivers/staging/brcm80211/sys/wlc_antsel.h | 2 +- drivers/staging/brcm80211/sys/wlc_channel.c | 4 ++-- drivers/staging/brcm80211/sys/wlc_event.c | 5 +++-- drivers/staging/brcm80211/sys/wlc_event.h | 3 ++- drivers/staging/brcm80211/sys/wlc_mac80211.c | 10 +++++----- drivers/staging/brcm80211/sys/wlc_mac80211.h | 4 ++-- drivers/staging/brcm80211/sys/wlc_pub.h | 14 ++++++++------ 10 files changed, 35 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.h b/drivers/staging/brcm80211/sys/wl_mac80211.h index 87a8128d1b3c..bb39b7705947 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.h +++ b/drivers/staging/brcm80211/sys/wl_mac80211.h @@ -60,7 +60,7 @@ struct wl_firmware { }; struct wl_info { - wlc_pub_t *pub; /* pointer to public wlc state */ + struct wlc_pub *pub; /* pointer to public wlc state */ void *wlc; /* pointer to private common os-independent data */ struct osl_info *osh; /* pointer to os handler */ u32 magic; diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 7d04d532a024..9af2d17a40c0 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -32,9 +32,9 @@ #include #include -static wlc_pub_t *wlc_pub_malloc(struct osl_info *osh, uint unit, uint *err, - uint devid); -static void wlc_pub_mfree(struct osl_info *osh, wlc_pub_t *pub); +static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit, + uint *err, uint devid); +static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub); static void wlc_tunables_init(wlc_tunables_t *tunables, uint devid); void *wlc_calloc(struct osl_info *osh, uint unit, uint size) @@ -65,12 +65,12 @@ void wlc_tunables_init(wlc_tunables_t *tunables, uint devid) tunables->txsbnd = TXSBND; } -static wlc_pub_t *wlc_pub_malloc(struct osl_info *osh, uint unit, uint *err, - uint devid) +static struct wlc_pub *wlc_pub_malloc(struct osl_info *osh, uint unit, + uint *err, uint devid) { - wlc_pub_t *pub; + struct wlc_pub *pub; - pub = (wlc_pub_t *) wlc_calloc(osh, unit, sizeof(wlc_pub_t)); + pub = (struct wlc_pub *) wlc_calloc(osh, unit, sizeof(struct wlc_pub)); if (pub == NULL) { *err = 1001; goto fail; @@ -100,7 +100,7 @@ static wlc_pub_t *wlc_pub_malloc(struct osl_info *osh, uint unit, uint *err, return NULL; } -static void wlc_pub_mfree(struct osl_info *osh, wlc_pub_t *pub) +static void wlc_pub_mfree(struct osl_info *osh, struct wlc_pub *pub) { if (pub == NULL) return; @@ -179,7 +179,7 @@ struct wlc_info *wlc_attach_malloc(struct osl_info *osh, uint unit, uint *err, wlc->hwrxoff = WL_HWRXOFF; - /* allocate wlc_pub_t state structure */ + /* allocate struct wlc_pub state structure */ wlc->pub = wlc_pub_malloc(osh, unit, err, devid); if (wlc->pub == NULL) { *err = 1003; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index aaf9985a1995..27558fa02ba7 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -96,8 +96,8 @@ const u8 mimo_2x3_div_antselid_tbl[16] = { struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, - wlc_pub_t *pub, - struct wlc_hw_info *wlc_hw) { + struct wlc_pub *pub, + struct wlc_hw_info *wlc_hw) { struct antsel_info *asi; asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.h b/drivers/staging/brcm80211/sys/wlc_antsel.h index ba38a2aedbd9..8875b5848665 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.h +++ b/drivers/staging/brcm80211/sys/wlc_antsel.h @@ -18,7 +18,7 @@ #define _wlc_antsel_h_ extern struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc, struct osl_info *osh, - wlc_pub_t *pub, + struct wlc_pub *pub, struct wlc_hw_info *wlc_hw); extern void wlc_antsel_detach(struct antsel_info *asi); extern void wlc_antsel_init(struct antsel_info *asi); diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index 741e13af7b67..33041e36585c 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -44,7 +44,7 @@ typedef struct wlc_cm_band { } wlc_cm_band_t; struct wlc_cm_info { - wlc_pub_t *pub; + struct wlc_pub *pub; struct wlc_info *wlc; char srom_ccode[WLC_CNTRY_BUF_SZ]; /* Country Code in SROM */ uint srom_regrev; /* Regulatory Rev for the SROM ccode */ @@ -611,7 +611,7 @@ wlc_cm_info_t *wlc_channel_mgr_attach(struct wlc_info *wlc) wlc_cm_info_t *wlc_cm; char country_abbrev[WLC_CNTRY_BUF_SZ]; const country_info_t *country; - wlc_pub_t *pub = wlc->pub; + struct wlc_pub *pub = wlc->pub; char *ccode; WL_TRACE(("wl%d: wlc_channel_mgr_attach\n", wlc->pub->unit)); diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c index e4ab077bf87f..9b503d839aae 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.c +++ b/drivers/staging/brcm80211/sys/wlc_event.c @@ -47,7 +47,7 @@ struct wlc_eventq { wlc_event_t *tail; struct wlc_info *wlc; void *wl; - wlc_pub_t *pub; + struct wlc_pub *pub; bool tpending; bool workpending; struct wl_timer *timer; @@ -58,7 +58,8 @@ struct wlc_eventq { /* * Export functions */ -wlc_eventq_t *wlc_eventq_attach(wlc_pub_t *pub, struct wlc_info *wlc, void *wl, +wlc_eventq_t *wlc_eventq_attach(struct wlc_pub *pub, struct wlc_info *wlc, + void *wl, wlc_eventq_cb_t cb) { wlc_eventq_t *eq; diff --git a/drivers/staging/brcm80211/sys/wlc_event.h b/drivers/staging/brcm80211/sys/wlc_event.h index 7c8e49550f2d..e75582dcdd93 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.h +++ b/drivers/staging/brcm80211/sys/wlc_event.h @@ -21,7 +21,8 @@ typedef struct wlc_eventq wlc_eventq_t; typedef void (*wlc_eventq_cb_t) (void *arg); -extern wlc_eventq_t *wlc_eventq_attach(wlc_pub_t *pub, struct wlc_info *wlc, +extern wlc_eventq_t *wlc_eventq_attach(struct wlc_pub *pub, + struct wlc_info *wlc, void *wl, wlc_eventq_cb_t cb); extern int wlc_eventq_detach(wlc_eventq_t *eq); extern int wlc_eventq_down(wlc_eventq_t *eq); diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index b25b5bd6a110..eb4013dab36c 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -1697,7 +1697,7 @@ static uint wlc_attach_module(struct wlc_info *wlc) return err; } -wlc_pub_t *wlc_pub(void *wlc) +struct wlc_pub *wlc_pub(void *wlc) { return ((struct wlc_info *) wlc)->pub; } @@ -1714,7 +1714,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, struct wlc_info *wlc; uint err = 0; uint j; - wlc_pub_t *pub; + struct wlc_pub *pub; wlc_txq_info_t *qi; uint n_disabled; @@ -4309,7 +4309,7 @@ int wlc_iovar_gets8(struct wlc_info *wlc, const char *name, s8 *arg) * calling function must keep 'iovars' until wlc_module_unregister is called. * 'iovar' must have the last entry's name field being NULL as terminator. */ -int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars, +int wlc_module_register(struct wlc_pub *pub, const bcm_iovar_t *iovars, const char *name, void *hdl, iovar_fn_t i_fn, watchdog_fn_t w_fn, down_fn_t d_fn) { @@ -4339,7 +4339,7 @@ int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars, } /* unregister module callbacks */ -int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl) +int wlc_module_unregister(struct wlc_pub *pub, const char *name, void *hdl) { struct wlc_info *wlc = (struct wlc_info *) pub->wlc; int i; @@ -4455,7 +4455,7 @@ wlc_iovar_op(struct wlc_info *wlc, const char *name, } int -wlc_iovar_check(wlc_pub_t *pub, const bcm_iovar_t *vi, void *arg, int len, +wlc_iovar_check(struct wlc_pub *pub, const bcm_iovar_t *vi, void *arg, int len, bool set) { struct wlc_info *wlc = (struct wlc_info *) pub->wlc; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index ba2b953800e3..d3def7448bf7 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -510,7 +510,7 @@ typedef struct wlc_txq_info { * Principal common (os-independent) software data structure. */ struct wlc_info { - wlc_pub_t *pub; /* pointer to wlc public state */ + struct wlc_pub *pub; /* pointer to wlc public state */ struct osl_info *osh; /* pointer to os handle */ struct wl_info *wl; /* pointer to os-specific private state */ d11regs_t *regs; /* pointer to device registers */ @@ -787,7 +787,7 @@ struct wlc_info { /* antsel module specific state */ struct antsel_info { struct wlc_info *wlc; /* pointer to main wlc structure */ - wlc_pub_t *pub; /* pointer to public fn */ + struct wlc_pub *pub; /* pointer to public fn */ u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board */ diff --git a/drivers/staging/brcm80211/sys/wlc_pub.h b/drivers/staging/brcm80211/sys/wlc_pub.h index 80331e8a81ea..146a6904a39b 100644 --- a/drivers/staging/brcm80211/sys/wlc_pub.h +++ b/drivers/staging/brcm80211/sys/wlc_pub.h @@ -251,7 +251,7 @@ typedef int (*iovar_fn_t) (void *handle, const bcm_iovar_t *vi, * Public portion of "common" os-independent state structure. * The wlc handle points at this. */ -typedef struct wlc_pub { +struct wlc_pub { void *wlc; struct ieee80211_hw *ieee_hw; @@ -330,7 +330,7 @@ typedef struct wlc_pub { bool _lmacproto; /* lmac protocol module included and enabled */ bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */ bool _ampdumac; /* mac assist ampdu enabled or not */ -} wlc_pub_t; +}; /* wl_monitor rx status per packet */ typedef struct wl_rxsts { @@ -528,7 +528,7 @@ extern void wlc_set_addrmatch(struct wlc_info *wlc, int match_reg_offset, extern void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg, bool suspend); -extern wlc_pub_t *wlc_pub(void *wlc); +extern struct wlc_pub *wlc_pub(void *wlc); /* common functions for every port */ extern int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw); @@ -554,13 +554,15 @@ extern void wlc_scb_ratesel_init_all(struct wlc_info *wlc); /* ioctl */ extern int wlc_iovar_gets8(struct wlc_info *wlc, const char *name, s8 *arg); -extern int wlc_iovar_check(wlc_pub_t *pub, const bcm_iovar_t *vi, void *arg, +extern int wlc_iovar_check(struct wlc_pub *pub, const bcm_iovar_t *vi, + void *arg, int len, bool set); -extern int wlc_module_register(wlc_pub_t *pub, const bcm_iovar_t *iovars, +extern int wlc_module_register(struct wlc_pub *pub, const bcm_iovar_t *iovars, const char *name, void *hdl, iovar_fn_t iovar_fn, watchdog_fn_t watchdog_fn, down_fn_t down_fn); -extern int wlc_module_unregister(wlc_pub_t *pub, const char *name, void *hdl); +extern int wlc_module_unregister(struct wlc_pub *pub, const char *name, + void *hdl); extern void wlc_event_if(struct wlc_info *wlc, struct wlc_bsscfg *cfg, wlc_event_t *e, const struct ether_addr *addr); extern void wlc_suspend_mac_and_wait(struct wlc_info *wlc); -- cgit v1.2.3 From baffa2f609863b879703c4b757d63558b2caebdb Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Wed, 8 Dec 2010 20:16:02 +0100 Subject: staging: brcm80211: removed unused struct wlc_ap_info Code cleanup, reaction on the email from Dan Carpenter. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.h | 2 -- drivers/staging/brcm80211/sys/wlc_types.h | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.h b/drivers/staging/brcm80211/sys/wlc_mac80211.h index d3def7448bf7..5df996b78911 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.h +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.h @@ -753,8 +753,6 @@ struct wlc_info { ac_bitmap_t apsd_trigger_ac; /* Permissible Acess Category in which APSD Null * Trigger frames can be send */ - struct wlc_ap_info *ap; - u8 htphy_membership; /* HT PHY membership */ bool _regulatory_domain; /* 802.11d enabled? */ diff --git a/drivers/staging/brcm80211/sys/wlc_types.h b/drivers/staging/brcm80211/sys/wlc_types.h index 175ef1e42af2..df6e04c6ac58 100644 --- a/drivers/staging/brcm80211/sys/wlc_types.h +++ b/drivers/staging/brcm80211/sys/wlc_types.h @@ -24,7 +24,6 @@ struct wlc_hw_info; struct wlc_if; struct wl_if; struct ampdu_info; -struct wlc_ap_info; struct antsel_info; struct bmac_pmq; -- cgit v1.2.3 From fb657461abf6842b8f7603370ff349f42814ac5b Mon Sep 17 00:00:00 2001 From: Henry Ptasinski Date: Wed, 8 Dec 2010 13:18:04 -0800 Subject: staging: brcm80211: fix documentation on installing firmware Fix the documentation to have the current firmware filenames and use the correct path. Signed-off-by: Henry Ptasinski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/README | 10 ++-------- drivers/staging/brcm80211/brcmfmac/README | 5 +++-- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/README b/drivers/staging/brcm80211/README index a27bb0b4f581..99e67669f26b 100644 --- a/drivers/staging/brcm80211/README +++ b/drivers/staging/brcm80211/README @@ -43,14 +43,8 @@ Firmware is available from the Linux firmware repository at: http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git https://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git -For all chips, copy brcm/bcm43xx-0-610-809-0.fw and -brcm/bcm43xx_hdr-0-610-809-0.fw to /lib/firmware/brcm (or wherever firmware is -normally installed on the system). In the /lib/firmware/brcm directory, then -create the following symlinks: - - ln -s bcm43xx-0-610-809-0.fw bcm43xx-0.fw - ln -s bcm43xx_hdr-0-610-809-0.fw bcm43xx_hdr-0.fw - +For all chips, copy brcm/bcm43xx-0.fw and brcm/bcm43xx_hdr-0.fw to +/lib/firmware/brcm (or wherever firmware is normally installed on your system). Currently supported chips ============== diff --git a/drivers/staging/brcm80211/brcmfmac/README b/drivers/staging/brcm80211/brcmfmac/README index 43601fa8b17e..be29e4236920 100644 --- a/drivers/staging/brcm80211/brcmfmac/README +++ b/drivers/staging/brcm80211/brcmfmac/README @@ -25,8 +25,9 @@ Firmware is available from the Linux firmware repository at: http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git https://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git -For 4329 chip, copy brcm/bcm4329-fullmac-4-218-248-5.bin and -bcm4329-fullmac-4-218-248-5.txt to /lib/firmware/brcm +For 4329 chip, copy brcm/bcm4329-fullmac-4.bin and brcm/bcm4329-fullmac-4.txt +to /lib/firmware/brcm (or wherever firmware is normally installed on your +system). Contact Info: ============= -- cgit v1.2.3 From 597a1e7cccc9a5a0c47629267ac4b23bf8654578 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 7 Dec 2010 23:38:02 +0100 Subject: staging/line6: Fix sparse warning 'Using plain integer as NULL pointer' This patch fixes the warning generated by sparse: "Using plain integer as NULL pointer" by replacing the offending 0s with NULL. Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/line6/capture.c | 2 +- drivers/staging/line6/midi.c | 4 ++-- drivers/staging/line6/playback.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c index 1e3bb1406331..9647154a4923 100644 --- a/drivers/staging/line6/capture.c +++ b/drivers/staging/line6/capture.c @@ -147,7 +147,7 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) const int bytes_per_frame = line6pcm->properties->bytes_per_frame; int frames = fsize / bytes_per_frame; - if (runtime == 0) + if (runtime == NULL) return; if (line6pcm->pos_in_done + frames > runtime->buffer_size) { diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c index ab67e889d2c4..e554a2da643a 100644 --- a/drivers/staging/line6/midi.c +++ b/drivers/staging/line6/midi.c @@ -127,7 +127,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, urb = usb_alloc_urb(0, GFP_ATOMIC); - if (urb == 0) { + if (urb == NULL) { dev_err(line6->ifcdev, "Out of memory\n"); return -ENOMEM; } @@ -137,7 +137,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, transfer_buffer = kmalloc(length, GFP_ATOMIC); - if (transfer_buffer == 0) { + if (transfer_buffer == NULL) { usb_free_urb(urb); dev_err(line6->ifcdev, "Out of memory\n"); return -ENOMEM; diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c index 29940fd1671b..10c543836583 100644 --- a/drivers/staging/line6/playback.c +++ b/drivers/staging/line6/playback.c @@ -246,7 +246,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); - if (line6pcm->prev_fbuf != 0) { + if (line6pcm->prev_fbuf != NULL) { #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE if (line6pcm->flags & MASK_PCM_IMPULSE) { create_impulse_test_signal(line6pcm, urb_out, -- cgit v1.2.3 From be3e5b32462790b91c14d5869fbabaf5bfe7c901 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 7 Dec 2010 23:44:33 +0100 Subject: staging/zram: Fix sparse warning 'Using plain integer as NULL pointer' This patch fixes the warning generated by sparse: "Using plain integer as NULL pointer" by replacing the offending 0s with NULL. Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/zram/xvmalloc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/zram/xvmalloc.c b/drivers/staging/zram/xvmalloc.c index 3fdbb8ada827..b64406739d05 100644 --- a/drivers/staging/zram/xvmalloc.c +++ b/drivers/staging/zram/xvmalloc.c @@ -187,7 +187,7 @@ static void insert_block(struct xv_pool *pool, struct page *page, u32 offset, slindex = get_index_for_insert(block->size); flindex = slindex / BITS_PER_LONG; - block->link.prev_page = 0; + block->link.prev_page = NULL; block->link.prev_offset = 0; block->link.next_page = pool->freelist[slindex].page; block->link.next_offset = pool->freelist[slindex].offset; @@ -217,7 +217,7 @@ static void remove_block_head(struct xv_pool *pool, pool->freelist[slindex].page = block->link.next_page; pool->freelist[slindex].offset = block->link.next_offset; - block->link.prev_page = 0; + block->link.prev_page = NULL; block->link.prev_offset = 0; if (!pool->freelist[slindex].page) { @@ -232,7 +232,7 @@ static void remove_block_head(struct xv_pool *pool, */ tmpblock = get_ptr_atomic(pool->freelist[slindex].page, pool->freelist[slindex].offset, KM_USER1); - tmpblock->link.prev_page = 0; + tmpblock->link.prev_page = NULL; tmpblock->link.prev_offset = 0; put_ptr_atomic(tmpblock, KM_USER1); } -- cgit v1.2.3 From 982cf00412a890ca738c2d78528b652ca431ad1a Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Tue, 30 Nov 2010 23:54:46 +0000 Subject: of/address: Use propper endianess in get_flags This patch changes u32 to __be32 for all "ranges", "prop" and "addr" and such. Those variables are pointing to the device tree which containts intergers in big endian format. Most functions are doing it right because of_read_number() is doing the right thing for them. of_bus_isa_get_flags(), of_bus_pci_get_flags() and of_bus_isa_map() were accessing the data directly and were doing it wrong. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Benjamin Herrenschmidt Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/prom.h | 2 +- drivers/of/address.c | 54 +++++++++++++++++++++-------------------- include/linux/of_address.h | 6 ++--- 3 files changed, 32 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index ae26f2efd089..ab34f6072095 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -42,7 +42,7 @@ extern void pci_create_OF_bus_map(void); /* Translate a DMA address from device space to CPU space */ extern u64 of_translate_dma_address(struct device_node *dev, - const u32 *in_addr); + const __be32 *in_addr); #ifdef CONFIG_PCI extern unsigned long pci_address_to_pio(phys_addr_t address); diff --git a/drivers/of/address.c b/drivers/of/address.c index 3a1c7e70b192..b4559c58c095 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -12,13 +12,13 @@ (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, +static int __of_address_to_resource(struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, struct resource *r); /* Debug utility */ #ifdef DEBUG -static void of_dump_addr(const char *s, const u32 *addr, int na) +static void of_dump_addr(const char *s, const __be32 *addr, int na) { printk(KERN_DEBUG "%s", s); while (na--) @@ -26,7 +26,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na) printk("\n"); } #else -static void of_dump_addr(const char *s, const u32 *addr, int na) { } +static void of_dump_addr(const char *s, const __be32 *addr, int na) { } #endif /* Callbacks for bus specific translators */ @@ -36,10 +36,10 @@ struct of_bus { int (*match)(struct device_node *parent); void (*count_cells)(struct device_node *child, int *addrc, int *sizec); - u64 (*map)(u32 *addr, const u32 *range, + u64 (*map)(u32 *addr, const __be32 *range, int na, int ns, int pna); int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(const u32 *addr); + unsigned int (*get_flags)(const __be32 *addr); }; /* @@ -55,7 +55,7 @@ static void of_bus_default_count_cells(struct device_node *dev, *sizec = of_n_size_cells(dev); } -static u64 of_bus_default_map(u32 *addr, const u32 *range, +static u64 of_bus_default_map(u32 *addr, const __be32 *range, int na, int ns, int pna) { u64 cp, s, da; @@ -85,7 +85,7 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na) return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned int of_bus_default_get_flags(const __be32 *addr) { return IORESOURCE_MEM; } @@ -110,10 +110,10 @@ static void of_bus_pci_count_cells(struct device_node *np, *sizec = 2; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned int of_bus_pci_get_flags(const __be32 *addr) { unsigned int flags = 0; - u32 w = addr[0]; + u32 w = be32_to_cpup(addr); switch((w >> 24) & 0x03) { case 0x01: @@ -129,7 +129,8 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) return flags; } -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) +static u64 of_bus_pci_map(u32 *addr, const __be32 *range, int na, int ns, + int pna) { u64 cp, s, da; unsigned int af, rf; @@ -160,7 +161,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, +const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags) { const __be32 *prop; @@ -207,7 +208,7 @@ EXPORT_SYMBOL(of_get_pci_address); int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) { - const u32 *addrp; + const __be32 *addrp; u64 size; unsigned int flags; @@ -237,12 +238,13 @@ static void of_bus_isa_count_cells(struct device_node *child, *sizec = 1; } -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna) +static u64 of_bus_isa_map(u32 *addr, const __be32 *range, int na, int ns, + int pna) { u64 cp, s, da; /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x00000001) + if ((addr[0] ^ range[0]) & cpu_to_be32(1)) return OF_BAD_ADDR; /* Read address values, skipping high cell */ @@ -264,10 +266,10 @@ static int of_bus_isa_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -static unsigned int of_bus_isa_get_flags(const u32 *addr) +static unsigned int of_bus_isa_get_flags(const __be32 *addr) { unsigned int flags = 0; - u32 w = addr[0]; + u32 w = be32_to_cpup(addr); if (w & 1) flags |= IORESOURCE_IO; @@ -330,7 +332,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, struct of_bus *pbus, u32 *addr, int na, int ns, int pna, const char *rprop) { - const u32 *ranges; + const __be32 *ranges; unsigned int rlen; int rone; u64 offset = OF_BAD_ADDR; @@ -398,7 +400,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things */ -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, +u64 __of_translate_address(struct device_node *dev, const __be32 *in_addr, const char *rprop) { struct device_node *parent = NULL; @@ -475,22 +477,22 @@ u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, return result; } -u64 of_translate_address(struct device_node *dev, const u32 *in_addr) +u64 of_translate_address(struct device_node *dev, const __be32 *in_addr) { return __of_translate_address(dev, in_addr, "ranges"); } EXPORT_SYMBOL(of_translate_address); -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr) +u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) { return __of_translate_address(dev, in_addr, "dma-ranges"); } EXPORT_SYMBOL(of_translate_dma_address); -const u32 *of_get_address(struct device_node *dev, int index, u64 *size, +const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { - const u32 *prop; + const __be32 *prop; unsigned int psize; struct device_node *parent; struct of_bus *bus; @@ -525,8 +527,8 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, +static int __of_address_to_resource(struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, struct resource *r) { u64 taddr; @@ -564,7 +566,7 @@ static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, int of_address_to_resource(struct device_node *dev, int index, struct resource *r) { - const u32 *addrp; + const __be32 *addrp; u64 size; unsigned int flags; diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 8aea06f0564c..2feda6ee6140 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -3,7 +3,7 @@ #include #include -extern u64 of_translate_address(struct device_node *np, const u32 *addr); +extern u64 of_translate_address(struct device_node *np, const __be32 *addr); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); extern void __iomem *of_iomap(struct device_node *device, int index); @@ -21,7 +21,7 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } #endif #ifdef CONFIG_PCI -extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, +extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); @@ -32,7 +32,7 @@ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, return -ENOSYS; } -static inline const u32 *of_get_pci_address(struct device_node *dev, +static inline const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags) { return NULL; -- cgit v1.2.3 From 98b14d6b290d96b24ae993ceaccc59b2aa4b130c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 5 Dec 2010 05:05:37 +0000 Subject: powerpc/powermac: Make auto-loading of therm_pm72 possible The therm_pm72 driver, used on the PowerMac G5 range, cannot be auto-loaded, since the driver itself creates both the device node and the driver instance. Moving the device node creation to the platform setup code and adding the necessary MODULE_DEVICE_TABLE() information allows the driver to be automatically loaded by udev on any semi-modern distribution. It "fixes" a major source of problem on G5 machines where the driver wasn't explicitely loaded by default, and the system would automatically shutdown under load. Tested on an Xserve G5. Signed-off-by: Marc Zyngier Cc: Benjamin Herrenschmidt Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powermac/setup.c | 9 +++++++++ drivers/macintosh/therm_pm72.c | 30 +++++------------------------- 2 files changed, 14 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 9deb274841f1..d5aceb7fb125 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -506,6 +506,15 @@ static int __init pmac_declare_of_platform_devices(void) of_platform_device_create(np, "smu", NULL); of_node_put(np); } + np = of_find_node_by_type(NULL, "fcu"); + if (np == NULL) { + /* Some machines have strangely broken device-tree */ + np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e"); + } + if (np) { + of_platform_device_create(np, "temperature", NULL); + of_node_put(np); + } return 0; } diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 44549272333c..2e041fd0a00c 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -2213,6 +2213,9 @@ static void fcu_lookup_fans(struct device_node *fcu_node) static int fcu_of_probe(struct platform_device* dev, const struct of_device_id *match) { state = state_detached; + of_dev = dev; + + dev_info(&dev->dev, "PowerMac G5 Thermal control driver %s\n", VERSION); /* Lookup the fans in the device tree */ fcu_lookup_fans(dev->dev.of_node); @@ -2235,6 +2238,7 @@ static const struct of_device_id fcu_match[] = }, {}, }; +MODULE_DEVICE_TABLE(of, fcu_match); static struct of_platform_driver fcu_of_platform_driver = { @@ -2252,8 +2256,6 @@ static struct of_platform_driver fcu_of_platform_driver = */ static int __init therm_pm72_init(void) { - struct device_node *np; - rackmac = of_machine_is_compatible("RackMac3,1"); if (!of_machine_is_compatible("PowerMac7,2") && @@ -2261,34 +2263,12 @@ static int __init therm_pm72_init(void) !rackmac) return -ENODEV; - printk(KERN_INFO "PowerMac G5 Thermal control driver %s\n", VERSION); - - np = of_find_node_by_type(NULL, "fcu"); - if (np == NULL) { - /* Some machines have strangely broken device-tree */ - np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e"); - if (np == NULL) { - printk(KERN_ERR "Can't find FCU in device-tree !\n"); - return -ENODEV; - } - } - of_dev = of_platform_device_create(np, "temperature", NULL); - if (of_dev == NULL) { - printk(KERN_ERR "Can't register FCU platform device !\n"); - return -ENODEV; - } - - of_register_platform_driver(&fcu_of_platform_driver); - - return 0; + return of_register_platform_driver(&fcu_of_platform_driver); } static void __exit therm_pm72_exit(void) { of_unregister_platform_driver(&fcu_of_platform_driver); - - if (of_dev) - of_device_unregister(of_dev); } module_init(therm_pm72_init); -- cgit v1.2.3 From 6a66bbd693c12f71697c61207aa18bc5a12da0ab Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Wed, 8 Dec 2010 15:08:04 -0800 Subject: HID: magicmouse: Don't report REL_{X,Y} for Magic Trackpad With the recent switch to having the hid layer handle standard axis initialization, the Magic Trackpad now reports relative axes. This would be fine in the normal mode, but the driver puts the device in multitouch mode where no relative events are generated. Also, userspace software depends on accurate axis information for device type detection. Thus, ignoring the relative axes from the Magic Trackpad is best. Signed-off-by: Chase Douglas Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index e6dc15171664..ed732b746c96 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -433,6 +433,11 @@ static int magicmouse_input_mapping(struct hid_device *hdev, if (!msc->input) msc->input = hi->input; + /* Magic Trackpad does not give relative data after switching to MT */ + if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD && + field->flags & HID_MAIN_ITEM_RELATIVE) + return -1; + return 0; } -- cgit v1.2.3 From ff7ea4c04012e01a9a50c5e42dabdaf0794734ce Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 09:43:41 +0000 Subject: drm/i915: Re-arm the idle timers if the device is still busy Don't post a downclocking task if the device is still active when the idle timer fires. A pathological process could queue up several seconds worth of processing and then go to sleep, during which time the idle timer would kick in and downclock the GPU. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ccf2ad7cd88..6d4faff8121b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4758,8 +4758,14 @@ static void intel_gpu_idle_timer(unsigned long arg) struct drm_device *dev = (struct drm_device *)arg; drm_i915_private_t *dev_priv = dev->dev_private; - dev_priv->busy = false; + if (!list_empty(&dev_priv->mm.active_list)) { + /* Still processing requests, so just re-arm the timer. */ + mod_timer(&dev_priv->idle_timer, jiffies + + msecs_to_jiffies(GPU_IDLE_TIMEOUT)); + return; + } + dev_priv->busy = false; queue_work(dev_priv->wq, &dev_priv->idle_work); } @@ -4770,9 +4776,17 @@ static void intel_crtc_idle_timer(unsigned long arg) struct intel_crtc *intel_crtc = (struct intel_crtc *)arg; struct drm_crtc *crtc = &intel_crtc->base; drm_i915_private_t *dev_priv = crtc->dev->dev_private; + struct intel_framebuffer *intel_fb; - intel_crtc->busy = false; + intel_fb = to_intel_framebuffer(crtc->fb); + if (intel_fb && intel_fb->obj->active) { + /* The framebuffer is still being accessed by the GPU. */ + mod_timer(&intel_crtc->idle_timer, jiffies + + msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); + return; + } + intel_crtc->busy = false; queue_work(dev_priv->wq, &dev_priv->idle_work); } -- cgit v1.2.3 From 67731b87e9572801c41f8fe779750babdd362416 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 10:38:14 +0000 Subject: drm/i915: Eliminate drm_gem_object_lookup during relocation As we provide a list of all objects that will be accessed from the batchbuffer, we can build a lut of the handles associated with those objects for this invocation and use that to avoid the overhead of looking up those objects again for every relocation. The cost of building and searching a small hash table is much less than that of acquiring a spinlock, searching a radix tree and manipulating an atomic refcnt per relocation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 6 ++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 150 +++++++++++++++++++++++------ 2 files changed, 129 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d9b54a27ccf8..b8a55008a1b5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -788,6 +788,12 @@ struct drm_i915_gem_object { struct scatterlist *sg_list; int num_sg; + /** + * Used for performing relocations during execbuffer insertion. + */ + struct hlist_node exec_node; + unsigned long exec_handle; + /** * Current offset of the object in GTT space. * diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1b2ceacd64f0..3305ae528de4 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -207,9 +207,67 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, cd->flush_rings |= ring->id; } +struct eb_objects { + int and; + struct hlist_head buckets[0]; +}; + +static struct eb_objects * +eb_create(int size) +{ + struct eb_objects *eb; + int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; + while (count > size) + count >>= 1; + eb = kzalloc(count*sizeof(struct hlist_head) + + sizeof(struct eb_objects), + GFP_KERNEL); + if (eb == NULL) + return eb; + + eb->and = count - 1; + return eb; +} + +static void +eb_reset(struct eb_objects *eb) +{ + memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); +} + +static void +eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj) +{ + hlist_add_head(&obj->exec_node, + &eb->buckets[obj->exec_handle & eb->and]); +} + +static struct drm_i915_gem_object * +eb_get_object(struct eb_objects *eb, unsigned long handle) +{ + struct hlist_head *head; + struct hlist_node *node; + struct drm_i915_gem_object *obj; + + head = &eb->buckets[handle & eb->and]; + hlist_for_each(node, head) { + obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); + if (obj->exec_handle == handle) + return obj; + } + + return NULL; +} + +static void +eb_destroy(struct eb_objects *eb) +{ + kfree(eb); +} + static int i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, + struct eb_objects *eb, struct drm_i915_gem_exec_object2 *entry, struct drm_i915_gem_relocation_entry *reloc) { @@ -218,9 +276,9 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, uint32_t target_offset; int ret = -EINVAL; - target_obj = drm_gem_object_lookup(dev, file_priv, - reloc->target_handle); - if (target_obj == NULL) + /* we've already hold a reference to all valid objects */ + target_obj = &eb_get_object(eb, reloc->target_handle)->base; + if (unlikely(target_obj == NULL)) return -ENOENT; target_offset = to_intel_bo(target_obj)->gtt_offset; @@ -246,7 +304,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, if (target_offset == 0) { DRM_ERROR("No GTT space found for object %d\n", reloc->target_handle); - goto err; + return ret; } /* Validate that the target is in a valid r/w GPU domain */ @@ -258,7 +316,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, (int) reloc->offset, reloc->read_domains, reloc->write_domain); - goto err; + return ret; } if (reloc->write_domain & I915_GEM_DOMAIN_CPU || reloc->read_domains & I915_GEM_DOMAIN_CPU) { @@ -269,7 +327,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, (int) reloc->offset, reloc->read_domains, reloc->write_domain); - goto err; + return ret; } if (reloc->write_domain && target_obj->pending_write_domain && reloc->write_domain != target_obj->pending_write_domain) { @@ -280,7 +338,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, (int) reloc->offset, reloc->write_domain, target_obj->pending_write_domain); - goto err; + return ret; } target_obj->pending_read_domains |= reloc->read_domains; @@ -290,7 +348,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, * more work needs to be done. */ if (target_offset == reloc->presumed_offset) - goto out; + return 0; /* Check that the relocation address is valid... */ if (reloc->offset > obj->base.size - 4) { @@ -299,14 +357,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, obj, reloc->target_handle, (int) reloc->offset, (int) obj->base.size); - goto err; + return ret; } if (reloc->offset & 3) { DRM_ERROR("Relocation not 4-byte aligned: " "obj %p target %d offset %d.\n", obj, reloc->target_handle, (int) reloc->offset); - goto err; + return ret; } /* and points to somewhere within the target object. */ @@ -316,7 +374,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, obj, reloc->target_handle, (int) reloc->delta, (int) target_obj->size); - goto err; + return ret; } reloc->delta += target_offset; @@ -334,7 +392,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret) - goto err; + return ret; /* Map the page containing the relocation we're going to perform. */ reloc->offset += obj->gtt_offset; @@ -349,16 +407,12 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, /* and update the user's relocation entry */ reloc->presumed_offset = target_offset; -out: - ret = 0; -err: - drm_gem_object_unreference(target_obj); - return ret; + return 0; } static int i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, + struct eb_objects *eb, struct drm_i915_gem_exec_object2 *entry) { struct drm_i915_gem_relocation_entry __user *user_relocs; @@ -373,7 +427,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, sizeof(reloc))) return -EFAULT; - ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &reloc); + ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &reloc); if (ret) return ret; @@ -388,14 +442,14 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, - struct drm_file *file_priv, + struct eb_objects *eb, struct drm_i915_gem_exec_object2 *entry, struct drm_i915_gem_relocation_entry *relocs) { int i, ret; for (i = 0; i < entry->relocation_count; i++) { - ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &relocs[i]); + ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &relocs[i]); if (ret) return ret; } @@ -405,7 +459,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, - struct drm_file *file, + struct eb_objects *eb, struct list_head *objects, struct drm_i915_gem_exec_object2 *exec) { @@ -415,7 +469,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, list_for_each_entry(obj, objects, exec_list) { obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate_object(obj, file, exec++); + ret = i915_gem_execbuffer_relocate_object(obj, eb, exec++); if (ret) return ret; } @@ -560,6 +614,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, struct intel_ring_buffer *ring, struct list_head *objects, + struct eb_objects *eb, struct drm_i915_gem_exec_object2 *exec, int count) { @@ -567,6 +622,15 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_i915_gem_object *obj; int i, total, ret; + /* We may process another execbuffer during the unlock... */ + while (list_empty(objects)) { + obj = list_first_entry(objects, + struct drm_i915_gem_object, + exec_list); + list_del_init(&obj->exec_list); + drm_gem_object_unreference(&obj->base); + } + mutex_unlock(&dev->struct_mutex); total = 0; @@ -601,6 +665,26 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; } + /* reacquire the objects */ + INIT_LIST_HEAD(objects); + eb_reset(eb); + for (i = 0; i < count; i++) { + struct drm_i915_gem_object *obj; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, + exec[i].handle)); + if (obj == NULL) { + DRM_ERROR("Invalid object handle %d at index %d\n", + exec[i].handle, i); + ret = -ENOENT; + goto err; + } + + list_add_tail(&obj->exec_list, objects); + obj->exec_handle = exec[i].handle; + eb_add_object(eb, obj); + } + ret = i915_gem_execbuffer_reserve(ring, file, objects, exec); if (ret) goto err; @@ -609,7 +693,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, list_for_each_entry(obj, objects, exec_list) { obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate_object_slow(obj, file, + ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, exec, reloc + total); if (ret) @@ -868,6 +952,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; struct list_head objects; + struct eb_objects *eb; struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; @@ -950,6 +1035,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } + eb = eb_create(args->buffer_count); + if (eb == NULL) { + mutex_unlock(&dev->struct_mutex); + ret = -ENOMEM; + goto pre_mutex_err; + } + /* Look up object handles */ INIT_LIST_HEAD(&objects); for (i = 0; i < args->buffer_count; i++) { @@ -973,6 +1065,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } list_add_tail(&obj->exec_list, &objects); + obj->exec_handle = exec[i].handle; + eb_add_object(eb, obj); } /* Move the objects en-masse into the GTT, evicting if necessary. */ @@ -981,11 +1075,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, file, &objects, exec); + ret = i915_gem_execbuffer_relocate(dev, eb, &objects, exec); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, - &objects, exec, + &objects, eb, + exec, args->buffer_count); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } @@ -1051,6 +1146,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_execbuffer_retire_commands(dev, file, ring); err: + eb_destroy(eb); while (!list_empty(&objects)) { struct drm_i915_gem_object *obj; -- cgit v1.2.3 From b8f7ab1788f23d79084f051bb9ae3cb02b55bff3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 10:43:06 +0000 Subject: drm/i915: Mark the user reloc error paths as unlikely Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3305ae528de4..fda0dc858a1f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -301,14 +301,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, /* The target buffer should have appeared before us in the * exec_object list, so it should have a GTT space bound by now. */ - if (target_offset == 0) { + if (unlikely(target_offset == 0)) { DRM_ERROR("No GTT space found for object %d\n", reloc->target_handle); return ret; } /* Validate that the target is in a valid r/w GPU domain */ - if (reloc->write_domain & (reloc->write_domain - 1)) { + if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { DRM_ERROR("reloc with multiple write domains: " "obj %p target %d offset %d " "read %08x write %08x", @@ -318,8 +318,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, reloc->write_domain); return ret; } - if (reloc->write_domain & I915_GEM_DOMAIN_CPU || - reloc->read_domains & I915_GEM_DOMAIN_CPU) { + if (unlikely((reloc->write_domain | reloc->read_domains) & I915_GEM_DOMAIN_CPU)) { DRM_ERROR("reloc with read/write CPU domains: " "obj %p target %d offset %d " "read %08x write %08x", @@ -329,8 +328,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, reloc->write_domain); return ret; } - if (reloc->write_domain && target_obj->pending_write_domain && - reloc->write_domain != target_obj->pending_write_domain) { + if (unlikely(reloc->write_domain && target_obj->pending_write_domain && + reloc->write_domain != target_obj->pending_write_domain)) { DRM_ERROR("Write domain conflict: " "obj %p target %d offset %d " "new %08x old %08x\n", @@ -351,7 +350,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, return 0; /* Check that the relocation address is valid... */ - if (reloc->offset > obj->base.size - 4) { + if (unlikely(reloc->offset > obj->base.size - 4)) { DRM_ERROR("Relocation beyond object bounds: " "obj %p target %d offset %d size %d.\n", obj, reloc->target_handle, @@ -359,7 +358,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, (int) obj->base.size); return ret; } - if (reloc->offset & 3) { + if (unlikely(reloc->offset & 3)) { DRM_ERROR("Relocation not 4-byte aligned: " "obj %p target %d offset %d.\n", obj, reloc->target_handle, @@ -368,7 +367,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, } /* and points to somewhere within the target object. */ - if (reloc->delta >= target_obj->size) { + if (unlikely(reloc->delta >= target_obj->size)) { DRM_ERROR("Relocation beyond target object bounds: " "obj %p target %d delta %d size %d.\n", obj, reloc->target_handle, -- cgit v1.2.3 From 4a19d02e0a8cd8799e5d150d8eb74861e1a4cdec Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 13:31:49 +0000 Subject: drm/i915: driver.suspend and .resume are always set So we can remove the repeated initialisation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 91a3ad2cf942..ad28b21f4d03 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -700,11 +700,6 @@ static int __init i915_init(void) driver.driver_features &= ~DRIVER_MODESET; #endif - if (!(driver.driver_features & DRIVER_MODESET)) { - driver.suspend = i915_suspend; - driver.resume = i915_resume; - } - return drm_init(&driver); } -- cgit v1.2.3 From d1c3b177b9940541e89015a726ac279caf1a21f3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 14:26:19 +0000 Subject: drm/i915: Restore GTT mapping first upon resume As suggested by Daniel Vetter, this is a safeguard should any of the registers cause reference to PTE entries. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ad28b21f4d03..2be344a8e93b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -304,13 +304,18 @@ static int i915_drm_thaw(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int error = 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + mutex_lock(&dev->struct_mutex); + i915_gem_restore_gtt_mappings(dev); + mutex_unlock(&dev->struct_mutex); + } + i915_restore_state(dev); intel_opregion_setup(dev); /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { mutex_lock(&dev->struct_mutex); - i915_gem_restore_gtt_mappings(dev); dev_priv->mm.suspended = 0; error = i915_gem_init_ringbuffer(dev); -- cgit v1.2.3 From a8e93126a6f10d0a14ba8407ec112b1b3a5e2e97 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 14:28:54 +0000 Subject: drm/i915/gtt: Clear the cachelines upon resume Required for my pineview system to not barf after resuming. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 71c2b0f3747b..86673e77d7cb 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -35,6 +35,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) struct drm_i915_gem_object *obj; list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + i915_gem_clflush_object(obj); + if (dev_priv->mm.gtt->needs_dmar) { BUG_ON(!obj->sg_list); @@ -51,7 +53,6 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) obj->agp_type); } - /* Be paranoid and flush the chipset cache. */ intel_gtt_chipset_flush(); } -- cgit v1.2.3 From eb43f4af7ecb7d51ba44f5e96bf74eedf1c27d62 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 17:32:24 +0000 Subject: drm/i915: Terminate the FORCE WAKE after we have finished reading Once we have read the value out of the GT power well, we need to remove the FORCE WAKE bit to allow the system to auto-power down. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 21 ++++++++++++--------- drivers/gpu/drm/i915/i915_reg.h | 1 + 3 files changed, 35 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2be344a8e93b..5f20cd988612 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -244,6 +244,28 @@ void intel_detect_pch (struct drm_device *dev) } } +void __gen6_force_wake_get(struct drm_i915_private *dev_priv) +{ + int count; + + count = 0; + while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1)) + udelay(10); + + I915_WRITE_NOTRACE(FORCEWAKE, 1); + POSTING_READ(FORCEWAKE); + + count = 0; + while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0) + udelay(10); +} + +void __gen6_force_wake_put(struct drm_i915_private *dev_priv) +{ + I915_WRITE_NOTRACE(FORCEWAKE, 0); + POSTING_READ(FORCEWAKE); +} + static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b8a55008a1b5..30780f2cab6f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1341,17 +1341,20 @@ __i915_write(64, q) * must be set to prevent GT core from power down and stale values being * returned. */ +void __gen6_force_wake_get(struct drm_i915_private *dev_priv); +void __gen6_force_wake_put (struct drm_i915_private *dev_priv); static inline u32 i915_safe_read(struct drm_i915_private *dev_priv, u32 reg) { - if (IS_GEN6(dev_priv->dev)) { - I915_WRITE_NOTRACE(FORCEWAKE, 1); - POSTING_READ(FORCEWAKE); - /* XXX How long do we really need to wait here? - * Will different registers/engines require different periods? - */ - udelay(100); - } - return I915_READ(reg); + u32 val; + + if (dev_priv->info->gen >= 6) { + __gen6_force_wake_get(dev_priv); + val = I915_READ(reg); + __gen6_force_wake_put(dev_priv); + } else + val = I915_READ(reg); + + return val; } static inline void diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3e03094cf148..2a36e05f1b85 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3115,4 +3115,5 @@ #define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22) #define FORCEWAKE 0xA18C +#define FORCEWAKE_ACK 0x130090 #endif /* _I915_REG_H_ */ -- cgit v1.2.3 From 8fd2685911cb6c140e6d0588ac04990ce65d4537 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Dec 2010 18:40:43 +0000 Subject: drm/i915: Enable RC6 autodownclocking on Sandybridge Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 59 ++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 89 ++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2a36e05f1b85..b284c13fd632 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -283,6 +283,7 @@ #define RING_CTL(base) ((base)+0x3c) #define RING_SYNC_0(base) ((base)+0x40) #define RING_SYNC_1(base) ((base)+0x44) +#define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) #define RING_ACTHD(base) ((base)+0x74) @@ -3116,4 +3117,62 @@ #define FORCEWAKE 0xA18C #define FORCEWAKE_ACK 0x130090 + +#define GEN6_RC_NORMAL_FREQ 0xA008 +#define GEN6_TURBO_DISABLE (1<<31) +#define GEN6_FREQUENCY(x) ((x)<<25) +#define GEN6_OFFSET(x) ((x)<<19) +#define GEN6_AGGRESSIVE_TURBO (0<<15) +#define GEN6_RC_VIDEO_FREQ 0xA00C +#define GEN6_RC_CONTROL 0xA090 +#define GEN6_RC_CTL_RC6pp_ENABLE (1<<16) +#define GEN6_RC_CTL_RC6p_ENABLE (1<<17) +#define GEN6_RC_CTL_RC6_ENABLE (1<<18) +#define GEN6_RC_CTL_RC1e_ENABLE (1<<20) +#define GEN6_RC_CTL_RC7_ENABLE (1<<22) +#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) +#define GEN6_RC_CTL_HW_ENABLE (1<<31) +#define GEN6_RP_DOWN_TIMEOUT 0xA010 +#define GEN6_RP_INTERRUPT_LIMITS 0xA014 +#define GEN6_RP_CONTROL 0xA024 +#define GEN6_RP_MEDIA_TURBO (1<<11) +#define GEN6_RP_USE_NORMAL_FREQ (1<<9) +#define GEN6_RP_MEDIA_IS_GFX (1<<8) +#define GEN6_RP_ENABLE (1<<7) +#define GEN6_RP_UP_BUSY_MAX (0x2<<3) +#define GEN6_RP_DOWN_BUSY_MIN (0x2<<0) +#define GEN6_RP_UP_THRESHOLD 0xA02C +#define GEN6_RP_DOWN_THRESHOLD 0xA030 +#define GEN6_RP_UP_EI 0xA068 +#define GEN6_RP_DOWN_EI 0xA06C +#define GEN6_RP_IDLE_HYSTERSIS 0xA070 +#define GEN6_RC_STATE 0xA094 +#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098 +#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C +#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0 +#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8 +#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC +#define GEN6_RC_SLEEP 0xA0B0 +#define GEN6_RC1e_THRESHOLD 0xA0B4 +#define GEN6_RC6_THRESHOLD 0xA0B8 +#define GEN6_RC6p_THRESHOLD 0xA0BC +#define GEN6_RC6pp_THRESHOLD 0xA0C0 + +#define GEN6_PMISR 0x44020 +#define GEN6_PMIMR 0x44024 +#define GEN6_PMIIR 0x44028 +#define GEN6_PMIER 0x4402C +#define GEN6_PM_MBOX_EVENT (1<<25) +#define GEN6_PM_THERMAL_EVENT (1<<24) +#define GEN6_PM_RP_DOWN_TIMEOUT (1<<6) +#define GEN6_PM_RP_UP_THRESHOLD (1<<5) +#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) +#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) +#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) + +#define GEN6_PCODE_MAILBOX 0x138124 +#define GEN6_PCODE_READY (1<<31) +#define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x9 +#define GEN6_PCODE_DATA 0x138128 + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6d4faff8121b..17c213fef0ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5842,6 +5842,91 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } +static void gen6_enable_rc6(struct drm_i915_private *dev_priv) +{ + int i; + + /* Here begins a magic sequence of register writes to enable + * auto-downclocking. + * + * Perhaps there might be some value in exposing these to + * userspace... + */ + I915_WRITE(GEN6_RC_STATE, 0); + __gen6_force_wake_get(dev_priv); + + /* disable the counters and set determistic thresholds */ + I915_WRITE(GEN6_RC_CONTROL, 0); + + I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30); + I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30); + I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); + I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); + + for (i = 0; i < I915_NUM_RINGS; i++) + I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10); + + I915_WRITE(GEN6_RC_SLEEP, 0); + I915_WRITE(GEN6_RC1e_THRESHOLD, 1000); + I915_WRITE(GEN6_RC6_THRESHOLD, 50000); + I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); + I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ + + I915_WRITE(GEN6_RC_CONTROL, + GEN6_RC_CTL_RC6p_ENABLE | + GEN6_RC_CTL_RC6_ENABLE | + GEN6_RC_CTL_HW_ENABLE); + + I915_WRITE(GEN6_RC_NORMAL_FREQ, + GEN6_FREQUENCY(10) | + GEN6_OFFSET(0) | + GEN6_AGGRESSIVE_TURBO); + I915_WRITE(GEN6_RC_VIDEO_FREQ, + GEN6_FREQUENCY(12)); + + I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + 18 << 24 | + 6 << 16); + I915_WRITE(GEN6_RP_UP_THRESHOLD, 90000); + I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 100000); + I915_WRITE(GEN6_RP_UP_EI, 100000); + I915_WRITE(GEN6_RP_DOWN_EI, 300000); + I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); + I915_WRITE(GEN6_RP_CONTROL, + GEN6_RP_MEDIA_TURBO | + GEN6_RP_USE_NORMAL_FREQ | + GEN6_RP_MEDIA_IS_GFX | + GEN6_RP_ENABLE | + GEN6_RP_UP_BUSY_MAX | + GEN6_RP_DOWN_BUSY_MIN); + + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); + + I915_WRITE(GEN6_PCODE_DATA, 0); + I915_WRITE(GEN6_PCODE_MAILBOX, + GEN6_PCODE_READY | + GEN6_PCODE_WRITE_MIN_FREQ_TABLE); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + + /* requires MSI enabled */ + I915_WRITE(GEN6_PMIER, + GEN6_PM_MBOX_EVENT | + GEN6_PM_THERMAL_EVENT | + GEN6_PM_RP_DOWN_TIMEOUT | + GEN6_PM_RP_UP_THRESHOLD | + GEN6_PM_RP_DOWN_THRESHOLD | + GEN6_PM_RP_UP_EI_EXPIRED | + GEN6_PM_RP_DOWN_EI_EXPIRED); + + __gen6_force_wake_put(dev_priv); +} + void intel_enable_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5924,6 +6009,7 @@ void intel_enable_clock_gating(struct drm_device *dev) _3D_CHICKEN2_WM_READ_PIPELINED << 16 | _3D_CHICKEN2_WM_READ_PIPELINED); } + } else if (IS_G4X(dev)) { uint32_t dspclk_gate; I915_WRITE(RENCLK_GATE_D1, 0); @@ -5997,6 +6083,9 @@ void intel_enable_clock_gating(struct drm_device *dev) I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); } } + + if (IS_GEN6(dev)) + gen6_enable_rc6(dev_priv); } void intel_disable_clock_gating(struct drm_device *dev) -- cgit v1.2.3 From d1b758ebc2a82d738092cb42e742470f9d0ea53e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 9 Dec 2010 14:53:29 -0500 Subject: xen/irq: Cleanup the find_unbound_irq The "find_unbound_irq" is a bit unusual - it allocates virtual IRQ (event channels) in reverse order. This means starting at the "top" of the available IRQs (nr_irqs) down to the GSI/MSI IRQs (nr_irqs_gsi). Lets document this and also make the variables easier to understand. Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 31af0ac31a98..4d4a23d4c9f6 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -405,15 +405,21 @@ static int find_unbound_irq(void) { struct irq_data *data; int irq, res; - int start = get_nr_hw_irqs(); + int bottom = get_nr_hw_irqs(); + int top = nr_irqs-1; - if (start == nr_irqs) + if (bottom == nr_irqs) goto no_irqs; - /* nr_irqs is a magic value. Must not use it.*/ - for (irq = nr_irqs-1; irq > start; irq--) { + /* This loop starts from the top of IRQ space and goes down. + * We need this b/c if we have a PCI device in a Xen PV guest + * we do not have an IO-APIC (though the backend might have them) + * mapped in. To not have a collision of physical IRQs with the Xen + * event channels start at the top of the IRQ space for virtual IRQs. + */ + for (irq = top; irq > bottom; irq--) { data = irq_get_irq_data(irq); - /* only 0->15 have init'd desc; handle irq > 16 */ + /* only 15->0 have init'd desc; handle irq > 16 */ if (!data) break; if (data->chip == &no_irq_chip) @@ -424,7 +430,7 @@ static int find_unbound_irq(void) return irq; } - if (irq == start) + if (irq == bottom) goto no_irqs; res = irq_alloc_desc_at(irq, -1); -- cgit v1.2.3 From 1f0613158ea14b399fd7a16470630a729ba9d0c3 Mon Sep 17 00:00:00 2001 From: "Chen, Chien-Chia" Date: Thu, 9 Dec 2010 10:52:08 +0800 Subject: Staging: rt2860: fix previous patch error Somehow Greg messed up the last patch and missed a chunk. This patch contains the missing chunk. Acked-by: Lee, Chun-Yi Signed-off-by: Chen, Chien-Chia Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/chips/rt30xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/chips/rt30xx.c b/drivers/staging/rt2860/chips/rt30xx.c index e610d39bdca7..354debfe1477 100644 --- a/drivers/staging/rt2860/chips/rt30xx.c +++ b/drivers/staging/rt2860/chips/rt30xx.c @@ -442,7 +442,7 @@ void RT30xxReverseRFSleepModeSetup(struct rt_rtmp_adapter *pAd) /* VCO_IC, RF R7 register Bit 4 & Bit 5 to 1 */ RT30xxReadRFRegister(pAd, RF_R07, &RFValue); - RFValue |= 0x30; + RFValue |= 0x20; RT30xxWriteRFRegister(pAd, RF_R07, RFValue); /* Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 1 */ -- cgit v1.2.3 From 310d605293f0ab6dc9c7fe7a3cb5c850c60527b4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 9 Dec 2010 16:01:07 +0100 Subject: staging: brcm80211: Remove redundant unlikely() IS_ERR() already implies unlikely(), so it can be omitted here. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index 0d7aa4adbb77..edf300d4ae70 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -3196,7 +3196,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) } WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func())); wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev); - if (unlikely(IS_ERR(wdev))) + if (IS_ERR(wdev)) return -ENOMEM; wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); -- cgit v1.2.3 From 2cea0cf284048b03a06e4370709cd751ddb9354e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Dec 2010 01:40:30 +0900 Subject: Staging: vme_ca91cx42: use DEFINE_PCI_DEVICE_TABLE Convert 'const struct pci_device_id xxx[]' to 'DEFINE_PCI_DEVICE_TABLE(xxx)'. Signed-off-by: Namhyung Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_ca91cx42.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index 3ddc93ba7049..42de83e6f1d9 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -44,7 +44,7 @@ static int geoid; static char driver_name[] = "vme_ca91cx42"; -static const struct pci_device_id ca91cx42_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ca91cx42_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) }, { }, }; -- cgit v1.2.3 From 270b64bb4cf27a2ad7819bad89d8c9d8a66ba1b8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Dec 2010 01:40:29 +0900 Subject: Staging: vme_tsi148: use DEFINE_PCI_DEVICE_TABLE Convert 'const struct pci_device_id xxx[]' to 'DEFINE_PCI_DEVICE_TABLE(xxx)'. Signed-off-by: Namhyung Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/bridges/vme_tsi148.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 9550b4a8f93a..26ea42fa784d 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -46,7 +46,7 @@ static int geoid; static char driver_name[] = "vme_tsi148"; -static const struct pci_device_id tsi148_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) }, { }, }; -- cgit v1.2.3 From abb9eb75a34cbd34ee4e9160ac349eff91b926d8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Dec 2010 01:40:28 +0900 Subject: Staging: phison: use DEFINE_PCI_DEVICE_TABLE Convert 'const struct pci_device_id xxx[]' to 'DEFINE_PCI_DEVICE_TABLE(xxx)'. Signed-off-by: Namhyung Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/phison/phison.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/phison/phison.c b/drivers/staging/phison/phison.c index 677152044f45..683657cb21f5 100644 --- a/drivers/staging/phison/phison.c +++ b/drivers/staging/phison/phison.c @@ -69,7 +69,7 @@ static int phison_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } -static const struct pci_device_id phison_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(phison_pci_tbl) = { { PCI_VENDOR_ID_PHISON, PCI_DEVICE_ID_PS5000, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { 0, }, -- cgit v1.2.3 From 94ab896367d5d6e0bc3064852569c1ff9658ec9c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Dec 2010 01:40:26 +0900 Subject: Staging: cx25821: use DEFINE_PCI_DEVICE_TABLE Convert 'const struct pci_device_id xxx[]' to 'DEFINE_PCI_DEVICE_TABLE(xxx)'. Signed-off-by: Namhyung Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/cx25821/cx25821-alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c index 2a01dc057b2c..1f2e819c4320 100644 --- a/drivers/staging/cx25821/cx25821-alsa.c +++ b/drivers/staging/cx25821/cx25821-alsa.c @@ -629,7 +629,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, * Only boards with eeprom and byte 1 at eeprom=1 have it */ -static const struct pci_device_id cx25821_audio_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} }; -- cgit v1.2.3 From 5eaa53de2d9acd9dbcf737b247a0bb0788e79fdf Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Dec 2010 01:40:27 +0900 Subject: Staging: rtl8192e: use DEFINE_PCI_DEVICE_TABLE Convert 'const struct pci_device_id xxx[]' to 'DEFINE_PCI_DEVICE_TABLE(xxx)'. Signed-off-by: Namhyung Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/r8192E_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c index b7d08605fd00..fac4eee28e4e 100644 --- a/drivers/staging/rtl8192e/r8192E_core.c +++ b/drivers/staging/rtl8192e/r8192E_core.c @@ -89,7 +89,7 @@ u32 rt_global_debug_component = // COMP_INTR | COMP_ERR ; //always open err flags on -static const struct pci_device_id rtl8192_pci_id_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(rtl8192_pci_id_tbl) = { #ifdef RTL8190P /* Realtek */ /* Dlink */ -- cgit v1.2.3 From 6f475b71605c7ebf6f5b06b8e4dc58f672b4f9b5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 10 Dec 2010 01:40:25 +0900 Subject: Staging: sm7xx: use DEFINE_PCI_DEVICE_TABLE Convert 'const struct pci_device_id xxx[]' to 'DEFINE_PCI_DEVICE_TABLE(xxx)'. Signed-off-by: Namhyung Kim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xx/smtcfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c index 24f47d6388f4..f4b163f7338a 100644 --- a/drivers/staging/sm7xx/smtcfb.c +++ b/drivers/staging/sm7xx/smtcfb.c @@ -996,7 +996,7 @@ failed_free: /* Jason (08/11/2009) PCI_DRV wrapper essential structs */ -static const struct pci_device_id smtcfb_pci_table[] = { +static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = { {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -- cgit v1.2.3 From 0e0792fef4ea8e9f8f90819ad97918f61e467855 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Thu, 9 Dec 2010 19:36:08 +0100 Subject: staging: brcm80211: removed ap related comments Code cleanup, reaction on the 2nd email from Dan Carpenter. Signed-off-by: Roland Vossen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/sys/wlc_mac80211.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index eb4013dab36c..e4a4365f4bf7 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -2177,13 +2177,6 @@ uint wlc_detach(struct wlc_info *wlc) /* Detach from iovar manager */ wlc_module_unregister(wlc->pub, "wlc_iovars", wlc); - /* - if (wlc->ap) { - wlc_ap_detach(wlc->ap); - wlc->ap = NULL; - } - */ - while (wlc->tx_queues != NULL) { wlc_txq_free(wlc, wlc->osh, wlc->tx_queues); } -- cgit v1.2.3 From 372058f1b4b3603a7e0c26f38d6eb20a3dd8c453 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 9 Dec 2010 09:38:34 -0800 Subject: staging: solo6010 depends on I2C This driver uses i2c interfaces, so it should depend on I2C (unless someone wants to break it into pieces or make it more config-dependent). drivers/staging/solo6x10/solo6010-i2c.c:47: error: implicit declaration of function 'i2c_transfer' drivers/staging/solo6x10/solo6010-i2c.c:299: error: implicit declaration of function 'i2c_add_adapter' drivers/staging/solo6x10/solo6010-i2c.c:310: error: implicit declaration of function 'i2c_del_adapter' Signed-off-by: Randy Dunlap Cc: Ben Collins Signed-off-by: Greg Kroah-Hartman --- drivers/staging/solo6x10/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig index de60ac841b7e..2cf77c940860 100644 --- a/drivers/staging/solo6x10/Kconfig +++ b/drivers/staging/solo6x10/Kconfig @@ -1,6 +1,6 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" - depends on PCI && VIDEO_DEV && SND + depends on PCI && VIDEO_DEV && SND && I2C select VIDEOBUF_DMA_SG ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec -- cgit v1.2.3 From 9119dee1ce32453dfe24656091d69f8d57397fe0 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:46 +0100 Subject: staging: ft1000: Convert char device to debugfs. Character device was used only for debugging purposes. Convert it to debugfs functionality. For every plugged device create new directory with one file. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 68 +++++++++++++++++------- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 1 + drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 8 +++ 3 files changed, 57 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 1aec926c993c..1238b7759e5b 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -37,7 +37,7 @@ #include #include #include - +#include #include "ft1000_usb.h" //#include "ft1000_ioctl.h" @@ -156,9 +156,11 @@ int ft1000_CreateDevice(struct ft1000_device *dev) struct ft1000_info *info = netdev_priv(dev->net); int result; int i; + struct dentry *dir, *file; + struct ft1000_debug_dirs *tmp; // make a new device name - sprintf(info->DeviceName, "%s%d", "FT100", info->CardNumber); + sprintf(info->DeviceName, "%s%d", "FT1000_", info->CardNumber); DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt); DEBUG("DeviceCreated = %x\n", info->DeviceCreated); @@ -179,21 +181,31 @@ int ft1000_CreateDevice(struct ft1000_device *dev) DEBUG("ft1000_CreateDevice: \"%s\" device registration\n", info->DeviceName); info->DeviceMajor = 0; - result = register_chrdev(info->DeviceMajor, info->DeviceName, &ft1000fops); - if (result < 0) - { - DEBUG("ft1000_CreateDevice: unable to get major %d\n", info->DeviceMajor); - return result; - } + tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL); + if (tmp == NULL) { + result = -1; + goto fail; + } - DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName); + dir = debugfs_create_dir(info->DeviceName, 0); + if (IS_ERR(dir)) { + result = PTR_ERR(dir); + goto debug_dir_fail; + } - // save a dynamic device major number - if (info->DeviceMajor == 0) - { - info->DeviceMajor = result; - DEBUG("ft1000_PcdCreateDevice: device major = %d\n", info->DeviceMajor); - } + file = debugfs_create_file("device", S_IRUGO | S_IWUGO, dir, + NULL, &ft1000fops); + if (IS_ERR(file)) { + result = PTR_ERR(file); + goto debug_file_fail; + } + + tmp->dent = dir; + tmp->file = file; + tmp->int_number = info->CardNumber; + list_add(&(tmp->list), &(info->nodes.list)); + + DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName); // initialize application information @@ -243,7 +255,14 @@ int ft1000_CreateDevice(struct ft1000_device *dev) info->DeviceCreated = TRUE; ft1000_flarion_cnt++; - return result; + return 0; + +debug_file_fail: + debugfs_remove(dir); +debug_dir_fail: + kfree(tmp); +fail: + return result; } //--------------------------------------------------------------------------- @@ -259,10 +278,11 @@ int ft1000_CreateDevice(struct ft1000_device *dev) void ft1000_DestroyDevice(struct net_device *dev) { struct ft1000_info *info = netdev_priv(dev); - int result = 0; int i; struct dpram_blk *pdpram_blk; struct dpram_blk *ptr; + struct list_head *pos, *q; + struct ft1000_debug_dirs *dir; DEBUG("ft1000_chdev:ft1000_DestroyDevice called\n"); @@ -271,9 +291,17 @@ void ft1000_DestroyDevice(struct net_device *dev) if (info->DeviceCreated) { ft1000_flarion_cnt--; - unregister_chrdev(info->DeviceMajor, info->DeviceName); - DEBUG("ft1000_DestroyDevice: unregistered device \"%s\", result = %d\n", - info->DeviceName, result); + list_for_each_safe(pos, q, &info->nodes.list) { + dir = list_entry(pos, struct ft1000_debug_dirs, list); + if (dir->int_number == info->CardNumber) { + debugfs_remove(dir->file); + debugfs_remove(dir->dent); + list_del(pos); + kfree(dir); + } + } + DEBUG("ft1000_DestroyDevice: unregistered device \"%s\"\n", + info->DeviceName); // Make sure we free any memory reserve for slow Queue for (i=0; iprov_list); + INIT_LIST_HEAD(&pInfo->nodes.list); //mbelian #ifdef HAVE_NET_DEVICE_OPS netdev->netdev_ops = &ftnet_ops; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index a07db26441f1..5bead6314985 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -473,6 +473,13 @@ struct ft1000_device // struct net_device_stats stats; //mbelian } __attribute__ ((packed)); +struct ft1000_debug_dirs { + struct list_head list; + struct dentry *dent; + struct dentry *file; + int int_number; +}; + struct ft1000_info { struct ft1000_device *pFt1000Dev; struct net_device_stats stats; @@ -508,6 +515,7 @@ struct ft1000_info { u8 CardNumber; u8 DeviceName[15]; int DeviceMajor; + struct ft1000_debug_dirs nodes; int registered; int mediastate; int dhcpflg; -- cgit v1.2.3 From 6d96940b2de8f8ac2bc938ea9249ed380cf906e0 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:47 +0100 Subject: staging: ft1000: Fix private data pointer usage. Assign private data pointer to device for usage in file operations. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 1238b7759e5b..8b735e489878 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -347,12 +347,15 @@ void ft1000_DestroyDevice(struct net_device *dev) static int ft1000_ChOpen (struct inode *Inode, struct file *File) { struct ft1000_info *info; + struct ft1000_device *dev = (struct ft1000_device *)Inode->i_private; int i,num; DEBUG("ft1000_ChOpen called\n"); num = (MINOR(Inode->i_rdev) & 0xf); DEBUG("ft1000_ChOpen: minor number=%d\n", num); + info = File->private_data = netdev_priv(dev->net); + for (i=0; i<5; i++) DEBUG("pdevobj[%d]=%p\n", i, pdevobj[i]); //aelias [+] reason: down @@ -393,8 +396,6 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File) info->app_info[i].nTxMsgReject = 0; info->app_info[i].nRxMsgMiss = 0; - File->private_data = pdevobj[num]->net; - nonseekable_open(Inode, File); return 0; } -- cgit v1.2.3 From e34dc580dc4a76106755b88ada5903eaa427c9f4 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:48 +0100 Subject: staging: ft1000: Remove unused pdevobj array. We don't need to store pointer to device in some local array because we always pass to debugfs correct device pointer. So remove it. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 8b735e489878..0871e43159c6 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -51,10 +51,6 @@ static long ft1000_ChIoctl(struct file *File, unsigned int Command, unsigned long Argument); static int ft1000_ChRelease (struct inode *Inode, struct file *File); -// Global pointer to device object -static struct ft1000_device *pdevobj[MAX_NUM_CARDS + 2]; -//static devfs_handle_t ft1000Handle[MAX_NUM_CARDS]; - // List to free receive command buffer pool struct list_head freercvpool; @@ -165,11 +161,6 @@ int ft1000_CreateDevice(struct ft1000_device *dev) DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt); DEBUG("DeviceCreated = %x\n", info->DeviceCreated); - //save the device info to global array - pdevobj[info->CardNumber] = dev; - - DEBUG("ft1000_CreateDevice: ******SAVED pdevobj[%d]=%p\n", info->CardNumber, pdevobj[info->CardNumber]); //aelias [+] reason:up - if (info->DeviceCreated) { DEBUG("ft1000_CreateDevice: \"%s\" already registered\n", info->DeviceName); @@ -327,8 +318,6 @@ void ft1000_DestroyDevice(struct net_device *dev) // devfs_unregister(ft1000Handle[info->CardNumber]); info->DeviceCreated = FALSE; - - pdevobj[info->CardNumber] = NULL; } @@ -356,18 +345,6 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File) info = File->private_data = netdev_priv(dev->net); - for (i=0; i<5; i++) - DEBUG("pdevobj[%d]=%p\n", i, pdevobj[i]); //aelias [+] reason: down - - if ( pdevobj[num] != NULL ) - //info = (struct ft1000_info *)(pdevobj[num]->net->priv); - info = netdev_priv(pdevobj[num]->net); - else - { - DEBUG("ft1000_ChOpen: can not find device object %d\n", num); - return -1; - } - DEBUG("f_owner = %p number of application = %d\n", (&File->f_owner), info->appcnt ); // Check if maximum number of application exceeded -- cgit v1.2.3 From 67e9f9e26b7d8862ec2e2a3ac0e56590088e9281 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:49 +0100 Subject: staging: ft1000: Remove unused variable. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 1 - drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 1 - drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 0871e43159c6..4e5c8a3bc888 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -170,7 +170,6 @@ int ft1000_CreateDevice(struct ft1000_device *dev) // register the device DEBUG("ft1000_CreateDevice: \"%s\" device registration\n", info->DeviceName); - info->DeviceMajor = 0; tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL); if (tmp == NULL) { diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 22536da75011..69f920fdc12a 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -835,7 +835,6 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev) pInfo->mediastate = 0; pInfo->fifo_cnt = 0; pInfo->DeviceCreated = FALSE; - pInfo->DeviceMajor = 0; pInfo->CurrentInterruptEnableMask = ISR_DEFAULT_MASK; pInfo->InterruptsEnabled = FALSE; pInfo->CardReady = 0; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 5bead6314985..2c89d14807fb 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -514,7 +514,6 @@ struct ft1000_info { int NetDevRegDone; u8 CardNumber; u8 DeviceName[15]; - int DeviceMajor; struct ft1000_debug_dirs nodes; int registered; int mediastate; -- cgit v1.2.3 From 4d791234f484002d57f634e3d90ca2cd51ed144e Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:50 +0100 Subject: staging: ft1000: Fix camelcase functions and variables. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 156 +++++++++++------------ drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 4 +- 4 files changed, 82 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 4e5c8a3bc888..85f67e564f36 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -45,11 +45,11 @@ static int ft1000_flarion_cnt = 0; //need to looking usage of ft1000Handle -static int ft1000_ChOpen (struct inode *Inode, struct file *File); -static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait); -static long ft1000_ChIoctl(struct file *File, unsigned int Command, - unsigned long Argument); -static int ft1000_ChRelease (struct inode *Inode, struct file *File); +static int ft1000_open (struct inode *inode, struct file *file); +static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait); +static long ft1000_ioctl(struct file *file, unsigned int command, + unsigned long argument); +static int ft1000_release (struct inode *inode, struct file *file); // List to free receive command buffer pool struct list_head freercvpool; @@ -67,10 +67,10 @@ int numofmsgbuf = 0; // static struct file_operations ft1000fops = { - .unlocked_ioctl = ft1000_ChIoctl, - .poll = ft1000_ChPoll, - .open = ft1000_ChOpen, - .release = ft1000_ChRelease, + .unlocked_ioctl = ft1000_ioctl, + .poll = ft1000_poll_dev, + .open = ft1000_open, + .release = ft1000_release, .llseek = no_llseek, }; @@ -147,7 +147,7 @@ void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist) // Notes: Only called by init_module(). // //--------------------------------------------------------------------------- -int ft1000_CreateDevice(struct ft1000_device *dev) +int ft1000_create_dev(struct ft1000_device *dev) { struct ft1000_info *info = netdev_priv(dev->net); int result; @@ -265,7 +265,7 @@ fail: // Notes: Only called by cleanup_module(). // //--------------------------------------------------------------------------- -void ft1000_DestroyDevice(struct net_device *dev) +void ft1000_destroy_dev(struct net_device *dev) { struct ft1000_info *info = netdev_priv(dev); int i; @@ -323,7 +323,7 @@ void ft1000_DestroyDevice(struct net_device *dev) } //--------------------------------------------------------------------------- -// Function: ft1000_ChOpen +// Function: ft1000_open // // Parameters: // @@ -332,19 +332,19 @@ void ft1000_DestroyDevice(struct net_device *dev) // Notes: // //--------------------------------------------------------------------------- -static int ft1000_ChOpen (struct inode *Inode, struct file *File) +static int ft1000_open (struct inode *inode, struct file *file) { struct ft1000_info *info; - struct ft1000_device *dev = (struct ft1000_device *)Inode->i_private; + struct ft1000_device *dev = (struct ft1000_device *)inode->i_private; int i,num; - DEBUG("ft1000_ChOpen called\n"); - num = (MINOR(Inode->i_rdev) & 0xf); - DEBUG("ft1000_ChOpen: minor number=%d\n", num); + DEBUG("ft1000_open called\n"); + num = (MINOR(inode->i_rdev) & 0xf); + DEBUG("ft1000_open: minor number=%d\n", num); - info = File->private_data = netdev_priv(dev->net); + info = file->private_data = netdev_priv(dev->net); - DEBUG("f_owner = %p number of application = %d\n", (&File->f_owner), info->appcnt ); + DEBUG("f_owner = %p number of application = %d\n", (&file->f_owner), info->appcnt ); // Check if maximum number of application exceeded if (info->appcnt > MAX_NUM_APP) { @@ -366,19 +366,19 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File) } info->appcnt++; - info->app_info[i].fileobject = &File->f_owner; + info->app_info[i].fileobject = &file->f_owner; info->app_info[i].nTxMsg = 0; info->app_info[i].nRxMsg = 0; info->app_info[i].nTxMsgReject = 0; info->app_info[i].nRxMsgMiss = 0; - nonseekable_open(Inode, File); + nonseekable_open(inode, file); return 0; } //--------------------------------------------------------------------------- -// Function: ft1000_ChPoll +// Function: ft1000_poll_dev // // Parameters: // @@ -388,15 +388,15 @@ static int ft1000_ChOpen (struct inode *Inode, struct file *File) // //--------------------------------------------------------------------------- -static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait) +static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait) { struct net_device *dev = file->private_data; struct ft1000_info *info; int i; - //DEBUG("ft1000_ChPoll called\n"); + //DEBUG("ft1000_poll_dev called\n"); if (ft1000_flarion_cnt == 0) { - DEBUG("FT1000:ft1000_ChPoll called when ft1000_flarion_cnt is zero\n"); + DEBUG("FT1000:ft1000_poll_dev called when ft1000_flarion_cnt is zero\n"); return (-EBADF); } @@ -405,30 +405,30 @@ static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait) // Search for matching file object for (i=0; iapp_info[i].fileobject == &file->f_owner) { - //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id); + //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); break; } } // Could not find application info block if (i == MAX_NUM_APP) { - DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n"); + DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n"); return ( -EACCES ); } if (list_empty(&info->app_info[i].app_sqlist) == 0) { - DEBUG("FT1000:ft1000_ChPoll:Message detected in slow queue\n"); + DEBUG("FT1000:ft1000_poll_dev:Message detected in slow queue\n"); return(POLLIN | POLLRDNORM | POLLPRI); } poll_wait (file, &info->app_info[i].wait_dpram_msg, wait); - //DEBUG("FT1000:ft1000_ChPoll:Polling for data from DSP\n"); + //DEBUG("FT1000:ft1000_poll_dev:Polling for data from DSP\n"); return (0); } //--------------------------------------------------------------------------- -// Function: ft1000_ChIoctl +// Function: ft1000_ioctl // // Parameters: // @@ -437,10 +437,10 @@ static unsigned int ft1000_ChPoll(struct file *file, poll_table *wait) // Notes: // //--------------------------------------------------------------------------- -static long ft1000_ChIoctl (struct file *File, unsigned int Command, - unsigned long Argument) +static long ft1000_ioctl (struct file *file, unsigned int command, + unsigned long argument) { - void __user *argp = (void __user *)Argument; + void __user *argp = (void __user *)argument; struct net_device *dev; struct ft1000_info *info; struct ft1000_device *ft1000dev; @@ -462,25 +462,25 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, unsigned short ledStat=0; unsigned short conStat=0; - //DEBUG("ft1000_ChIoctl called\n"); + //DEBUG("ft1000_ioctl called\n"); if (ft1000_flarion_cnt == 0) { - DEBUG("FT1000:ft1000_ChIoctl called when ft1000_flarion_cnt is zero\n"); + DEBUG("FT1000:ft1000_ioctl called when ft1000_flarion_cnt is zero\n"); return (-EBADF); } - //DEBUG("FT1000:ft1000_ChIoctl:Command = 0x%x Argument = 0x%8x\n", Command, (u32)Argument); + //DEBUG("FT1000:ft1000_ioctl:command = 0x%x argument = 0x%8x\n", command, (u32)argument); - dev = File->private_data; + dev = file->private_data; info = netdev_priv(dev); ft1000dev = info->pFt1000Dev; - cmd = _IOC_NR(Command); - //DEBUG("FT1000:ft1000_ChIoctl:cmd = 0x%x\n", cmd); + cmd = _IOC_NR(command); + //DEBUG("FT1000:ft1000_ioctl:cmd = 0x%x\n", cmd); // process the command switch (cmd) { case IOCTL_REGISTER_CMD: - DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_REGISTER called\n"); + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_REGISTER called\n"); result = get_user(tempword, (__u16 __user*)argp); if (result) { DEBUG("result = %d failed to get_user\n", result); @@ -489,9 +489,9 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, if (tempword == DSPBCMSGID) { // Search for matching file object for (i=0; iapp_info[i].fileobject == &File->f_owner) { + if ( info->app_info[i].fileobject == &file->f_owner) { info->app_info[i].DspBCMsgFlag = 1; - DEBUG("FT1000:ft1000_ChIoctl:Registered for broadcast messages\n"); + DEBUG("FT1000:ft1000_ioctl:Registered for broadcast messages\n"); break; } } @@ -499,34 +499,34 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, break; case IOCTL_GET_VER_CMD: - DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_VER called\n"); + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_VER called\n"); get_ver_data.drv_ver = FT1000_DRV_VER; if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data)) ) { - DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); + DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); result = -EFAULT; break; } - DEBUG("FT1000:ft1000_ChIoctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver); + DEBUG("FT1000:ft1000_ioctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver); break; case IOCTL_CONNECT: // Connect Message - DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_CONNECT\n"); + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_CONNECT\n"); ConnectionMsg[79] = 0xfc; CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c); break; case IOCTL_DISCONNECT: // Disconnect Message - DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_DISCONNECT\n"); + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_DISCONNECT\n"); ConnectionMsg[79] = 0xfd; CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c); break; case IOCTL_GET_DSP_STAT_CMD: - //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DSP_STAT called\n"); + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DSP_STAT called\n"); memset(&get_stat_data, 0, sizeof(get_stat_data)); memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ); memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ); @@ -536,10 +536,10 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, if (info->ProgConStat != 0xFF) { ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); get_stat_data.LedStat = ntohs(ledStat); - DEBUG("FT1000:ft1000_ChIoctl: LedStat = 0x%x\n", get_stat_data.LedStat); + DEBUG("FT1000:ft1000_ioctl: LedStat = 0x%x\n", get_stat_data.LedStat); ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); get_stat_data.ConStat = ntohs(conStat); - DEBUG("FT1000:ft1000_ChIoctl: ConStat = 0x%x\n", get_stat_data.ConStat); + DEBUG("FT1000:ft1000_ioctl: ConStat = 0x%x\n", get_stat_data.ConStat); } else { get_stat_data.ConStat = 0x0f; @@ -554,7 +554,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm); DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm); if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data)) ) { - DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); + DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); result = -EFAULT; break; } @@ -572,7 +572,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, u16 app_index; u16 status; - //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_SET_DPRAM called\n"); + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_SET_DPRAM called\n"); if (ft1000_flarion_cnt == 0) { @@ -591,15 +591,15 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, if (info->CardReady) { - //DEBUG("FT1000:ft1000_ChIoctl: try to SET_DPRAM \n"); + //DEBUG("FT1000:ft1000_ioctl: try to SET_DPRAM \n"); // Get the length field to see how many bytes to copy result = get_user(msgsz, (__u16 __user *)argp); msgsz = ntohs (msgsz); - //DEBUG("FT1000:ft1000_ChIoctl: length of message = %d\n", msgsz); + //DEBUG("FT1000:ft1000_ioctl: length of message = %d\n", msgsz); if (msgsz > MAX_CMD_SQSIZE) { - DEBUG("FT1000:ft1000_ChIoctl: bad message length = %d\n", msgsz); + DEBUG("FT1000:ft1000_ioctl: bad message length = %d\n", msgsz); result = -EINVAL; break; } @@ -609,7 +609,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, if (!dpram_data) break; - //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)Argument, msgsz+2) ) { + //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)argument, msgsz+2) ) { if ( copy_from_user(dpram_data, argp, msgsz+2) ) { DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); result = -EFAULT; @@ -624,7 +624,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, #endif // Check if this message came from a registered application for (i=0; iapp_info[i].fileobject == &File->f_owner) { + if ( info->app_info[i].fileobject == &file->f_owner) { break; } } @@ -639,14 +639,14 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, // Check message qtype type which is the lower byte within qos_class //qtype = ntohs(dpram_command.dpram_blk.pseudohdr.qos_class) & 0xff; qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff; - //DEBUG("FT1000_ft1000_ChIoctl: qtype = %d\n", qtype); + //DEBUG("FT1000_ft1000_ioctl: qtype = %d\n", qtype); if (qtype) { } else { // Put message into Slow Queue // Only put a message into the DPRAM if msg doorbell is available status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); - //DEBUG("FT1000_ft1000_ChIoctl: READ REGISTER tempword=%x\n", tempword); + //DEBUG("FT1000_ft1000_ioctl: READ REGISTER tempword=%x\n", tempword); if (tempword & FT1000_DB_DPRAM_TX) { // Suspend for 2ms and try again due to DSP doorbell busy mdelay(2); @@ -662,7 +662,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, mdelay(3); status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); if (tempword & FT1000_DB_DPRAM_TX) { - DEBUG("FT1000:ft1000_ChIoctl:Doorbell not available\n"); + DEBUG("FT1000:ft1000_ioctl:Doorbell not available\n"); result = -ENOTTY; kfree(dpram_data); break; @@ -672,7 +672,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, } } - //DEBUG("FT1000_ft1000_ChIoctl: finished reading register\n"); + //DEBUG("FT1000_ft1000_ioctl: finished reading register\n"); // Make sure we are within the limits of the slow queue memory limitation if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) { @@ -719,7 +719,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, } } else { - DEBUG("FT1000:ft1000_ChIoctl: Card not ready take messages\n"); + DEBUG("FT1000:ft1000_ioctl: Card not ready take messages\n"); result = -EACCES; } kfree(dpram_data); @@ -732,7 +732,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, IOCTL_DPRAM_BLK __user *pioctl_dpram; int msglen; - //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM called\n"); + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM called\n"); if (ft1000_flarion_cnt == 0) { return (-EBADF); @@ -740,15 +740,15 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, // Search for matching file object for (i=0; iapp_info[i].fileobject == &File->f_owner) { - //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id); + if ( info->app_info[i].fileobject == &file->f_owner) { + //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); break; } } // Could not find application info block if (i == MAX_NUM_APP) { - DEBUG("FT1000:ft1000_ChIoctl:Could not find application info block\n"); + DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n"); result = -EBADF; break; } @@ -756,22 +756,22 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, result = 0; pioctl_dpram = argp; if (list_empty(&info->app_info[i].app_sqlist) == 0) { - //DEBUG("FT1000:ft1000_ChIoctl:Message detected in slow queue\n"); + //DEBUG("FT1000:ft1000_ioctl:Message detected in slow queue\n"); spin_lock_irqsave(&free_buff_lock, flags); pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); list_del(&pdpram_blk->list); info->app_info[i].NumOfMsg--; - //DEBUG("FT1000:ft1000_ChIoctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg); + //DEBUG("FT1000:ft1000_ioctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg); spin_unlock_irqrestore(&free_buff_lock, flags); msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ; result = get_user(msglen, &pioctl_dpram->total_len); if (result) break; msglen = htons(msglen); - //DEBUG("FT1000:ft1000_ChIoctl:msg length = %x\n", msglen); + //DEBUG("FT1000:ft1000_ioctl:msg length = %x\n", msglen); if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen)) { - DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); + DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); result = -EFAULT; break; } @@ -779,12 +779,12 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, ft1000_free_buffer(pdpram_blk, &freercvpool); result = msglen; } - //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_GET_DPRAM no message\n"); + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM no message\n"); } break; default: - DEBUG("FT1000:ft1000_ChIoctl:unknown command: 0x%x\n", Command); + DEBUG("FT1000:ft1000_ioctl:unknown command: 0x%x\n", command); result = -ENOTTY; break; } @@ -793,7 +793,7 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, } //--------------------------------------------------------------------------- -// Function: ft1000_ChRelease +// Function: ft1000_release // // Parameters: // @@ -802,16 +802,16 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command, // Notes: // //--------------------------------------------------------------------------- -static int ft1000_ChRelease (struct inode *Inode, struct file *File) +static int ft1000_release (struct inode *inode, struct file *file) { struct ft1000_info *info; struct net_device *dev; int i; struct dpram_blk *pdpram_blk; - DEBUG("ft1000_ChRelease called\n"); + DEBUG("ft1000_release called\n"); - dev = File->private_data; + dev = file->private_data; info = netdev_priv(dev); if (ft1000_flarion_cnt == 0) { @@ -821,8 +821,8 @@ static int ft1000_ChRelease (struct inode *Inode, struct file *File) // Search for matching file object for (i=0; iapp_info[i].fileobject == &File->f_owner) { - //DEBUG("FT1000:ft1000_ChIoctl: Message is for AppId = %d\n", info->app_info[i].app_id); + if ( info->app_info[i].fileobject == &file->f_owner) { + //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); break; } } diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 69f920fdc12a..7456787481c8 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -952,7 +952,7 @@ int reg_ft1000_netdev(struct ft1000_device *ft1000dev, struct usb_interface *int //Create character device, implemented by Jim - ft1000_CreateDevice(ft1000dev); + ft1000_create_dev(ft1000dev); DEBUG ("reg_ft1000_netdev returned\n"); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index d71ac30629f5..7dfed41b02ac 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -231,7 +231,7 @@ static void ft1000_disconnect(struct usb_interface *interface) if (pft1000info->pFt1000Dev->net) { DEBUG("ft1000_disconnect: destroy char driver\n"); - ft1000_DestroyDevice(pft1000info->pFt1000Dev->net); + ft1000_destroy_dev(pft1000info->pFt1000Dev->net); unregister_netdev(pft1000info->pFt1000Dev->net); DEBUG ("ft1000_disconnect: network device unregisterd\n"); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 2c89d14807fb..045ef30b79a1 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -579,8 +579,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng extern struct list_head freercvpool; extern spinlock_t free_buff_lock; // lock to arbitrate free buffer list for receive command data -int ft1000_CreateDevice(struct ft1000_device *dev); -void ft1000_DestroyDevice(struct net_device *dev); +int ft1000_create_dev(struct ft1000_device *dev); +void ft1000_destroy_dev(struct net_device *dev); extern void CardSendCommand(struct ft1000_device *ft1000dev, void *ptempbuffer, int size); struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist); -- cgit v1.2.3 From c82632d247ce839bfb001723ad1988d30d9febb9 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:51 +0100 Subject: staging: ft1000: Remove dead code. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 61 +----------------------- 1 file changed, 1 insertion(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 85f67e564f36..58aee36498e4 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -39,12 +39,9 @@ #include #include #include "ft1000_usb.h" -//#include "ft1000_ioctl.h" static int ft1000_flarion_cnt = 0; -//need to looking usage of ft1000Handle - static int ft1000_open (struct inode *inode, struct file *file); static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait); static long ft1000_ioctl(struct file *file, unsigned int command, @@ -59,9 +56,6 @@ spinlock_t free_buff_lock; int numofmsgbuf = 0; -// Global variable to indicate that all provisioning data is sent to DSP -//bool fProvComplete; - // // Table of entry-point routines for char device // @@ -197,29 +191,6 @@ int ft1000_create_dev(struct ft1000_device *dev) DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName); - // initialize application information - -// if (ft1000_flarion_cnt == 0) { -// -// DEBUG("Initialize free_buff_lock and freercvpool\n"); -// spin_lock_init(&free_buff_lock); -// -// // initialize a list of buffers to be use for queuing up receive command data -// INIT_LIST_HEAD (&freercvpool); -// -// // create list of free buffers -// for (i=0; ipbuffer = kmalloc ( MAX_CMD_SQSIZE, GFP_KERNEL ); -// // link provisioning data -// list_add_tail (&pdpram_blk->list, &freercvpool); -// } -// numofmsgbuf = NUM_OF_FREE_BUFFERS; -// } - - // initialize application information info->appcnt = 0; for (i=0; iapp_info[i].app_sqlist); } - - - -// ft1000Handle[info->CardNumber] = devfs_register(NULL, info->DeviceName, DEVFS_FL_AUTO_DEVNUM, 0, 0, -// S_IFCHR | S_IRUGO | S_IWUGO, &ft1000fops, NULL); - - info->DeviceCreated = TRUE; ft1000_flarion_cnt++; @@ -313,9 +277,6 @@ void ft1000_destroy_dev(struct net_device *dev) kfree(ptr); } } - -// devfs_unregister(ft1000Handle[info->CardNumber]); - info->DeviceCreated = FALSE; } @@ -609,19 +570,11 @@ static long ft1000_ioctl (struct file *file, unsigned int command, if (!dpram_data) break; - //if ( copy_from_user(&(dpram_command.dpram_blk), (PIOCTL_DPRAM_BLK)argument, msgsz+2) ) { if ( copy_from_user(dpram_data, argp, msgsz+2) ) { DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); result = -EFAULT; } else { -#if 0 - // whc - for debugging only - ptr = (char *)&dpram_data; - for (i=0; iapp_info[i].fileobject == &file->f_owner) { @@ -637,7 +590,6 @@ static long ft1000_ioctl (struct file *file, unsigned int command, app_index = i; // Check message qtype type which is the lower byte within qos_class - //qtype = ntohs(dpram_command.dpram_blk.pseudohdr.qos_class) & 0xff; qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff; //DEBUG("FT1000_ft1000_ioctl: qtype = %d\n", qtype); if (qtype) { @@ -677,7 +629,6 @@ static long ft1000_ioctl (struct file *file, unsigned int command, // Make sure we are within the limits of the slow queue memory limitation if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) { // Need to put sequence number plus new checksum for message - //pmsg = (u16 *)&dpram_command.dpram_blk.pseudohdr; pmsg = (u16 *)&dpram_data->pseudohdr; ppseudo_hdr = (struct pseudo_hdr *)pmsg; total_len = msgsz+2; @@ -697,17 +648,7 @@ static long ft1000_ioctl (struct file *file, unsigned int command, } pmsg++; ppseudo_hdr = (struct pseudo_hdr *)pmsg; -#if 0 - ptr = dpram_data; - DEBUG("FT1000:ft1000_ChIoctl: Command Send\n"); - for (i=0; iapp_info[app_index].nTxMsg++; -- cgit v1.2.3 From 05371d1861df75c7d89985760c9ce75fc806f4b8 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:52 +0100 Subject: staging: ft1000: Remove unused headers. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index 58aee36498e4..d249c8ae4f46 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -27,16 +27,12 @@ #include #include #include -#include #include #include #include #include -#include -#include #include -#include #include #include "ft1000_usb.h" -- cgit v1.2.3 From 115884118a65c18af290476e44ca6c76a2c0a694 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 11:26:53 +0100 Subject: staging: ft1000: Fix debug messages. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index d249c8ae4f46..da76f11a552f 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -148,18 +148,18 @@ int ft1000_create_dev(struct ft1000_device *dev) // make a new device name sprintf(info->DeviceName, "%s%d", "FT1000_", info->CardNumber); - DEBUG("ft1000_CreateDevice: number of instance = %d\n", ft1000_flarion_cnt); + DEBUG("%s: number of instance = %d\n", __func__, ft1000_flarion_cnt); DEBUG("DeviceCreated = %x\n", info->DeviceCreated); if (info->DeviceCreated) { - DEBUG("ft1000_CreateDevice: \"%s\" already registered\n", info->DeviceName); + DEBUG("%s: \"%s\" already registered\n", __func__, info->DeviceName); return -EIO; } // register the device - DEBUG("ft1000_CreateDevice: \"%s\" device registration\n", info->DeviceName); + DEBUG("%s: \"%s\" debugfs device registration\n", __func__, info->DeviceName); tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL); if (tmp == NULL) { @@ -185,7 +185,7 @@ int ft1000_create_dev(struct ft1000_device *dev) tmp->int_number = info->CardNumber; list_add(&(tmp->list), &(info->nodes.list)); - DEBUG("ft1000_CreateDevice: registered char device \"%s\"\n", info->DeviceName); + DEBUG("%s: registered debugfs directory \"%s\"\n", __func__, info->DeviceName); // initialize application information info->appcnt = 0; @@ -234,7 +234,7 @@ void ft1000_destroy_dev(struct net_device *dev) struct list_head *pos, *q; struct ft1000_debug_dirs *dir; - DEBUG("ft1000_chdev:ft1000_DestroyDevice called\n"); + DEBUG("%s called\n", __func__); @@ -250,7 +250,7 @@ void ft1000_destroy_dev(struct net_device *dev) kfree(dir); } } - DEBUG("ft1000_DestroyDevice: unregistered device \"%s\"\n", + DEBUG("%s: unregistered device \"%s\"\n", __func__, info->DeviceName); // Make sure we free any memory reserve for slow Queue @@ -295,7 +295,7 @@ static int ft1000_open (struct inode *inode, struct file *file) struct ft1000_device *dev = (struct ft1000_device *)inode->i_private; int i,num; - DEBUG("ft1000_open called\n"); + DEBUG("%s called\n", __func__); num = (MINOR(inode->i_rdev) & 0xf); DEBUG("ft1000_open: minor number=%d\n", num); -- cgit v1.2.3 From 5fd866fb6401cf6a912e75e1b9c4b906bf42434e Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:47 +0100 Subject: staging: ft1000: Fix proc initialization handling. Cleaning proc entries when error occures was not handled correctly. So fix and also add proper cleaning. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 40 ++++++++++++++++--------- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index 105846d104ff..dbd4a1ce9f55 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -193,32 +193,44 @@ static struct notifier_block ft1000_netdev_notifier = { }; -void -ft1000InitProc (struct net_device *dev) +int ft1000InitProc(struct net_device *dev) { struct ft1000_info *info; struct proc_dir_entry *ft1000_proc_file; - info = netdev_priv(dev); + int ret = 0; + info = netdev_priv(dev); info->ft1000_proc_dir = proc_mkdir (FT1000_PROC_DIR, FTNET_PROC); - if (info->ft1000_proc_dir == NULL) - { - remove_proc_entry (FT1000_PROC_DIR, FTNET_PROC); - } - + if (info->ft1000_proc_dir == NULL) { + printk(KERN_WARNING "Unable to create %s dir.\n", + FT1000_PROC_DIR); + ret = -EINVAL; + goto fail; + } ft1000_proc_file = create_proc_read_entry (dev->name, 0644, info->ft1000_proc_dir, ft1000ReadProc, dev); - if (ft1000_proc_file == NULL) - { - remove_proc_entry (info->netdevname, info->ft1000_proc_dir); - } + if (ft1000_proc_file == NULL) { + printk(KERN_WARNING "Unable to create /proc entry.\n"); + ret = -EINVAL; + goto fail_entry; + } snprintf (info->netdevname, IFNAMSIZ, "%s", dev->name); - register_netdevice_notifier (&ft1000_netdev_notifier); - return; + ret = register_netdevice_notifier(&ft1000_netdev_notifier); + if (ret) + goto fail_notif; + + return 0; + +fail_notif: + remove_proc_entry(info->netdevname, info->ft1000_proc_dir); +fail_entry: + remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC); +fail: + return ret; } void diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 045ef30b79a1..4a91469e64ff 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -594,7 +594,7 @@ struct usb_interface; int reg_ft1000_netdev(struct ft1000_device *ft1000dev, struct usb_interface *intf); int ft1000_poll(void* dev_id); -void ft1000InitProc(struct net_device *dev); +int ft1000InitProc(struct net_device *dev); void ft1000CleanupProc(struct ft1000_info *info); -- cgit v1.2.3 From 04c6620117488c0ccc612da5f2bcbcde025e9301 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:48 +0100 Subject: staging: ft1000: Fix coding style. Fix coding style in ft1000CleanupProc and ft1000InitProc functions. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index dbd4a1ce9f55..f197523d0604 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -196,12 +196,12 @@ static struct notifier_block ft1000_netdev_notifier = { int ft1000InitProc(struct net_device *dev) { struct ft1000_info *info; - struct proc_dir_entry *ft1000_proc_file; + struct proc_dir_entry *ft1000_proc_file; int ret = 0; info = netdev_priv(dev); - info->ft1000_proc_dir = proc_mkdir (FT1000_PROC_DIR, FTNET_PROC); + info->ft1000_proc_dir = proc_mkdir(FT1000_PROC_DIR, FTNET_PROC); if (info->ft1000_proc_dir == NULL) { printk(KERN_WARNING "Unable to create %s dir.\n", FT1000_PROC_DIR); @@ -209,16 +209,18 @@ int ft1000InitProc(struct net_device *dev) goto fail; } - ft1000_proc_file = - create_proc_read_entry (dev->name, 0644, info->ft1000_proc_dir, - ft1000ReadProc, dev); + ft1000_proc_file = + create_proc_read_entry(dev->name, 0644, + info->ft1000_proc_dir, ft1000ReadProc, dev); + if (ft1000_proc_file == NULL) { printk(KERN_WARNING "Unable to create /proc entry.\n"); ret = -EINVAL; goto fail_entry; } - snprintf (info->netdevname, IFNAMSIZ, "%s", dev->name); + snprintf(info->netdevname, IFNAMSIZ, "%s", dev->name); + ret = register_netdevice_notifier(&ft1000_netdev_notifier); if (ret) goto fail_notif; @@ -233,12 +235,9 @@ fail: return ret; } -void -ft1000CleanupProc(struct ft1000_info *info) +void ft1000CleanupProc(struct ft1000_info *info) { - remove_proc_entry (info->netdevname, info->ft1000_proc_dir); - remove_proc_entry (FT1000_PROC_DIR, FTNET_PROC); - unregister_netdevice_notifier (&ft1000_netdev_notifier); - - return; + remove_proc_entry(info->netdevname, info->ft1000_proc_dir); + remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC); + unregister_netdevice_notifier(&ft1000_netdev_notifier); } -- cgit v1.2.3 From 1c46282421c8b31b37323f7b007c4562ce17578c Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:49 +0100 Subject: staging: ft1000: Use return value for ft1000InitProc. Add checking for return value ft1000InitProc and cleanup if something fail. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 7dfed41b02ac..0e1fc3f1e055 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -198,12 +198,17 @@ static int ft1000_probe(struct usb_interface *interface, if (ret) goto err_thread; - pft1000info->NetDevRegDone = 1; + ret = ft1000InitProc(ft1000dev->net); + if (ret) + goto err_proc; - ft1000InitProc(ft1000dev->net); + pft1000info->NetDevRegDone = 1; return 0; +err_proc: + unregister_netdev(ft1000dev->net); + free_netdev(ft1000dev->net); err_thread: kthread_stop(pft1000info->pPollThread); err_load: -- cgit v1.2.3 From 92914cc8bb6d2d710d102051c9bb7566b0ac75a0 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:50 +0100 Subject: staging: ft1000: Fix coding style in ft1000NotifyProc. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 31 ++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index f197523d0604..c3fca23d551c 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -166,30 +166,29 @@ ft1000ReadProc (char *page, char **start, off_t off, int count, int *eof, } static int -ft1000NotifyProc (struct notifier_block *this, unsigned long event, void *ptr) +ft1000NotifyProc(struct notifier_block *this, unsigned long event, void *ptr) { - struct net_device *dev = ptr; + struct net_device *dev = ptr; struct ft1000_info *info; - struct proc_dir_entry *ft1000_proc_file; + struct proc_dir_entry *ft1000_proc_file; -info = netdev_priv(dev); + info = netdev_priv(dev); + switch (event) { + case NETDEV_CHANGENAME: + remove_proc_entry(info->netdevname, info->ft1000_proc_dir); + ft1000_proc_file = create_proc_read_entry(dev->name, 0644, + info->ft1000_proc_dir, + ft1000ReadProc, dev); + snprintf(info->netdevname, IFNAMSIZ, "%s", dev->name); + break; + } - switch (event) - { - case NETDEV_CHANGENAME: - remove_proc_entry (info->netdevname, info->ft1000_proc_dir); - ft1000_proc_file = create_proc_read_entry (dev->name, 0644, - info->ft1000_proc_dir, - ft1000ReadProc, dev); - snprintf (info->netdevname, IFNAMSIZ, "%s", dev->name); - break; - } - return NOTIFY_DONE; + return NOTIFY_DONE; } static struct notifier_block ft1000_netdev_notifier = { - .notifier_call = ft1000NotifyProc + .notifier_call = ft1000NotifyProc, }; -- cgit v1.2.3 From 85d47cff4ea2ab0d5380ba649ac4515d1a5bcf23 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:51 +0100 Subject: staging: ft1000: Coding style fix in ft1000ReadProc. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 216 ++++++++++++------------ 1 file changed, 106 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index c3fca23d551c..773316fcecd7 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -43,126 +43,122 @@ u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, u16 indx, static int -ft1000ReadProc (char *page, char **start, off_t off, int count, int *eof, +ft1000ReadProc(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct net_device *dev; - int len; - int i; - unsigned short ledStat; - unsigned short conStat; + struct net_device *dev; + int len; + int i; + unsigned short ledStat; + unsigned short conStat; struct ft1000_info *info; - char *status[] = { "Idle (Disconnect)", "Searching", "Active (Connected)", - "Waiting for L2", "Sleep", "No Coverage", "", "" - }; - - char *signal[] = { "", "*", "**", "***", "****" }; - int strength; - int quality; - struct timeval tv; - time_t delta; - - dev = (struct net_device *) data; + char *status[] = { + "Idle (Disconnect)", + "Searching", + "Active (Connected)", + "Waiting for L2", + "Sleep", + "No Coverage", + "", + "", + }; + + char *signal[] = { "", "*", "**", "***", "****" }; + int strength; + int quality; + struct timeval tv; + time_t delta; + + dev = (struct net_device *) data; info = netdev_priv(dev); - if (off > 0) - { - *eof = 1; - return 0; - } + if (off > 0) { + *eof = 1; + return 0; + } - if (info->ProgConStat != 0xFF) - { - ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_LED, + if (info->ProgConStat != 0xFF) { + ft1000_read_dpram16(info->pFt1000Dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); - info->LedStat = ntohs (ledStat); - - ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_CON_STATE, - (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); - info->ConStat = ntohs (conStat); - do_gettimeofday (&tv); - delta = (tv.tv_sec - info->ConTm); - } - else - { - info->ConStat = 0xf; - delta = 0; - } - - - - i = (info->LedStat) & 0xf; - switch (i) - { - case 0x1: - strength = 1; - break; - case 0x3: - strength = 2; - break; - case 0x7: - strength = 3; - break; - case 0xf: - strength = 4; - break; - default: - strength = 0; - } - - i = (info->LedStat >> 8) & 0xf; - switch (i) - { - case 0x1: - quality = 1; - break; - case 0x3: - quality = 2; - break; - case 0x7: - quality = 3; - break; - case 0xf: - quality = 4; - break; - default: - quality = 0; - } - - - len = 0; - PUTM_TO_PAGE (len, page, "Connection Time: %02ld:%02ld:%02ld\n", - ((delta / 3600) % 24), ((delta / 60) % 60), (delta % 60)); - PUTM_TO_PAGE (len, page, "Connection Time[s]: %ld\n", delta); - PUTM_TO_PAGE (len, page, "Asic ID: %s\n", - (info->AsicID) == - ELECTRABUZZ_ID ? "ELECTRABUZZ ASIC" : "MAGNEMITE ASIC"); - PUTX_TO_PAGE (len, page, "SKU: ", SKUSZ, info->Sku); - PUTX_TO_PAGE (len, page, "EUI64: ", EUISZ, info->eui64); - PUTD_TO_PAGE (len, page, "DSP version number: ", DSPVERSZ, info->DspVer); - PUTX_TO_PAGE (len, page, "Hardware Serial Number: ", HWSERNUMSZ, - info->HwSerNum); - PUTX_TO_PAGE (len, page, "Caliberation Version: ", CALVERSZ, - info->RfCalVer); - PUTD_TO_PAGE (len, page, "Caliberation Date: ", CALDATESZ, info->RfCalDate); - PUTM_TO_PAGE (len, page, "Media State: %s\n", - (info->mediastate) ? "link" : "no link"); - PUTM_TO_PAGE (len, page, "Connection Status: %s\n", - status[((info->ConStat) & 0x7)]); - PUTM_TO_PAGE (len, page, "RX packets: %ld\n", info->stats.rx_packets); - PUTM_TO_PAGE (len, page, "TX packets: %ld\n", info->stats.tx_packets); - PUTM_TO_PAGE (len, page, "RX bytes: %ld\n", info->stats.rx_bytes); - PUTM_TO_PAGE (len, page, "TX bytes: %ld\n", info->stats.tx_bytes); - PUTM_TO_PAGE (len, page, "Signal Strength: %s\n", signal[strength]); - PUTM_TO_PAGE (len, page, "Signal Quality: %s\n", signal[quality]); - - - - - return len; + info->LedStat = ntohs(ledStat); + + ft1000_read_dpram16(info->pFt1000Dev, FT1000_MAG_DSP_CON_STATE, + (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); + info->ConStat = ntohs(conStat); + do_gettimeofday(&tv); + delta = (tv.tv_sec - info->ConTm); + } else { + info->ConStat = 0xf; + delta = 0; + } + + i = (info->LedStat) & 0xf; + switch (i) { + case 0x1: + strength = 1; + break; + case 0x3: + strength = 2; + break; + case 0x7: + strength = 3; + break; + case 0xf: + strength = 4; + break; + default: + strength = 0; + } + + i = (info->LedStat >> 8) & 0xf; + switch (i) { + case 0x1: + quality = 1; + break; + case 0x3: + quality = 2; + break; + case 0x7: + quality = 3; + break; + case 0xf: + quality = 4; + break; + default: + quality = 0; + } + + len = 0; + PUTM_TO_PAGE(len, page, "Connection Time: %02ld:%02ld:%02ld\n", + ((delta / 3600) % 24), ((delta / 60) % 60), (delta % 60)); + PUTM_TO_PAGE(len, page, "Connection Time[s]: %ld\n", delta); + PUTM_TO_PAGE(len, page, "Asic ID: %s\n", + (info->AsicID) == + ELECTRABUZZ_ID ? "ELECTRABUZZ ASIC" : "MAGNEMITE ASIC"); + PUTX_TO_PAGE(len, page, "SKU: ", SKUSZ, info->Sku); + PUTX_TO_PAGE(len, page, "EUI64: ", EUISZ, info->eui64); + PUTD_TO_PAGE(len, page, "DSP version number: ", DSPVERSZ, info->DspVer); + PUTX_TO_PAGE(len, page, "Hardware Serial Number: ", HWSERNUMSZ, + info->HwSerNum); + PUTX_TO_PAGE(len, page, "Caliberation Version: ", CALVERSZ, + info->RfCalVer); + PUTD_TO_PAGE(len, page, "Caliberation Date: ", CALDATESZ, + info->RfCalDate); + PUTM_TO_PAGE(len, page, "Media State: %s\n", + (info->mediastate) ? "link" : "no link"); + PUTM_TO_PAGE(len, page, "Connection Status: %s\n", + status[((info->ConStat) & 0x7)]); + PUTM_TO_PAGE(len, page, "RX packets: %ld\n", info->stats.rx_packets); + PUTM_TO_PAGE(len, page, "TX packets: %ld\n", info->stats.tx_packets); + PUTM_TO_PAGE(len, page, "RX bytes: %ld\n", info->stats.rx_bytes); + PUTM_TO_PAGE(len, page, "TX bytes: %ld\n", info->stats.tx_bytes); + PUTM_TO_PAGE(len, page, "Signal Strength: %s\n", signal[strength]); + PUTM_TO_PAGE(len, page, "Signal Quality: %s\n", signal[quality]); + + return len; } static int -- cgit v1.2.3 From 96ff77f7350576d1b25908b59f15d2ab5222c432 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:52 +0100 Subject: staging: ft1000: Fix coding style. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index 773316fcecd7..bd28a6bfa86a 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -14,23 +14,19 @@ #define PUTX_TO_PAGE(len,page,message,size,var) \ len += snprintf(page+len, PAGE_SIZE - len, message); \ - for(i = 0; i < (size - 1); i++) \ - { \ + for (i = 0; i < (size - 1); i++) {\ len += snprintf(page+len, PAGE_SIZE - len, "%02x:", var[i]); \ } \ len += snprintf(page+len, PAGE_SIZE - len, "%02x\n", var[i]) #define PUTD_TO_PAGE(len,page,message,size,var) \ len += snprintf(page+len, PAGE_SIZE - len, message); \ - for(i = 0; i < (size - 1); i++) \ - { \ + for (i = 0; i < (size - 1); i++) {\ len += snprintf(page+len, PAGE_SIZE - len, "%d.", var[i]); \ } \ len += snprintf(page+len, PAGE_SIZE - len, "%d\n", var[i]) - - //#ifdef INIT_NET_NS #define FTNET_PROC init_net.proc_net //#else -- cgit v1.2.3 From e2398c61272f378b257b3107fdb960e0b642eeb6 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:53 +0100 Subject: staging: ft1000: Remove dead code. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index bd28a6bfa86a..da706f84df64 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -27,11 +27,7 @@ len += snprintf(page+len, PAGE_SIZE - len, "%d\n", var[i]) -//#ifdef INIT_NET_NS #define FTNET_PROC init_net.proc_net -//#else -//#define FTNET_PROC proc_net -//#endif u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, u16 indx, -- cgit v1.2.3 From c5e61563e26b5a43646393c5f5020d172b2767c7 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 9 Dec 2010 16:13:54 +0100 Subject: staging: ft1000: Add file header to ft1000_proc.c Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index da706f84df64..0f271c281b85 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -1,3 +1,24 @@ +/* + * ft1000_proc.c - ft1000 proc interface + * + * Copyright (C) 2009-2010 Quintec + * (C) 2010 Open-nandra + * + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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 -- cgit v1.2.3 From f15662755f7eb3db4a416d52af24771cc208e7b0 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:30:03 -0800 Subject: Staging: sep: remove virtual address being passed to user space application Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 23 +++++------------------ drivers/staging/sep/sep_driver_api.h | 14 +------------- 2 files changed, 6 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index f2c216df362e..a5c0443b4efc 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -2541,12 +2541,9 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, * This function sets the bus and virtual addresses of the static pool * and returns the virtual address */ -static int sep_get_static_pool_addr_handler(struct sep_device *sep, - unsigned long arg) +static int sep_get_static_pool_addr_handler(struct sep_device *sep) { - struct stat_pool_addr_struct command_args; u32 *static_pool_addr = NULL; - unsigned long addr_hold; dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler start\n"); @@ -2554,21 +2551,11 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, SEP_DRIVER_SYSTEM_RAR_MEMORY_OFFSET_IN_BYTES); static_pool_addr[0] = SEP_STATIC_POOL_VAL_TOKEN; - static_pool_addr[1] = sep->shared_bus + + static_pool_addr[1] = (u32)sep->shared_bus + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; - addr_hold = (unsigned long) - (sep->shared_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES); - command_args.static_virt_address = (aligned_u64)addr_hold; - - dev_dbg(&sep->pdev->dev, "static pool: physical %x virtual %x\n", - (u32)static_pool_addr[1], - (u32)command_args.static_virt_address); - - /* Send the parameters to user application */ - if (copy_to_user((void __user *) arg, &command_args, - sizeof(struct stat_pool_addr_struct))) - return -EFAULT; + dev_dbg(&sep->pdev->dev, "static pool: physical %x\n", + (u32)static_pool_addr[1]); dev_dbg(&sep->pdev->dev, "sep_get_static_pool_addr_handler end\n"); @@ -3064,7 +3051,7 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; case SEP_IOCGETSTATICPOOLADDR: /* Get the physical and virtual addresses of the static pool */ - error = sep_get_static_pool_addr_handler(sep, arg); + error = sep_get_static_pool_addr_handler(sep); break; case SEP_IOCENDTRANSACTION: error = sep_end_transaction_handler(sep); diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h index 1207722d8b6a..5508769fc5df 100644 --- a/drivers/staging/sep/sep_driver_api.h +++ b/drivers/staging/sep/sep_driver_api.h @@ -114,18 +114,6 @@ struct bld_syn_tab_struct { }; -/* - * command struct for static pool addresses - * Please note that this is a kernel virtual - * address; this will be removed at the next - * release of the Discretix middleware - */ -struct stat_pool_addr_struct { - /* virtual address of the static pool */ - aligned_u64 static_virt_address; -}; - - /* command struct for getting caller id value and address */ struct caller_id_struct { /* pid of the process */ @@ -275,7 +263,7 @@ struct sep_lli_entry { /* get the static pool area addersses (physical and virtual) */ #define SEP_IOCGETSTATICPOOLADDR \ - _IOR(SEP_IOC_MAGIC_NUMBER, 8, struct stat_pool_addr_struct) + _IO(SEP_IOC_MAGIC_NUMBER, 8) /* start sep command */ #define SEP_IOCSEPSTART \ -- cgit v1.2.3 From e957b063abdf0f005ba2c298345c75aa7ac4c22a Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:30:17 -0800 Subject: Staging: sep: remove spaces at end of lines Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index a5c0443b4efc..241b1b1bcaed 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -275,7 +275,7 @@ end_function: * @filp: file handle to SEP device * * Open method for the SEP device. Called when userspace opens - * the SEP device node. + * the SEP device node. * * Returns zero on success otherwise an error code. */ @@ -1811,7 +1811,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, info_entry_ptr->bus_address = sep_shared_area_virt_to_bus(sep, in_lli_table_ptr); - info_entry_ptr->block_size = + info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); } @@ -2164,7 +2164,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, error = sep_lock_user_pages(sep, app_virt_in_addr, data_size, &lli_in_array, SEP_DRIVER_IN_FLAG); if (error) { - dev_warn(&sep->pdev->dev, + dev_warn(&sep->pdev->dev, "sep_lock_user_pages for input virtual buffer failed\n"); goto end_function; } @@ -2808,7 +2808,7 @@ static int sep_end_transaction_handler(struct sep_device *sep) } /** - * sep_prepare_dcb_handler - prepare a control block + * sep_prepare_dcb_handler - prepare a control block * @sep: pointer to struct sep_device * @arg: pointer to user parameters * @@ -2873,7 +2873,7 @@ static int sep_free_dcb_handler(struct sep_device *sep) } /** - * sep_rar_prepare_output_msg_handler - prepare an output message + * sep_rar_prepare_output_msg_handler - prepare an output message * @sep: pointer to struct sep_device * @arg: pointer to user parameters * @@ -3557,7 +3557,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, if (error == 0) /* Success */ return 0; - + end_function_free_irq: free_irq(pdev->irq, sep); @@ -3626,7 +3626,7 @@ static int __init sep_init(void) /** - * sep_exit - called to unload driver + * sep_exit - called to unload driver * * Drop the misc devices then remove and unmap the various resources * that are not released by the driver remove method. -- cgit v1.2.3 From b0daf59c5fc9ac6c65645ffb40156f5d5a0052a4 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:30:31 -0800 Subject: Staging: sep: sram_addr is 32 bit; this is not a kernel address, but device internal value This does not have to be 64 bits wide Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h index 5508769fc5df..fbbfa2396555 100644 --- a/drivers/staging/sep/sep_driver_api.h +++ b/drivers/staging/sep/sep_driver_api.h @@ -61,7 +61,7 @@ struct init_struct { u32 message_size_in_words; /* offset of the init message in the sep sram */ - aligned_u64 sep_sram_addr; + u32 sep_sram_addr; /* -not used- resident size in bytes*/ u32 unused_resident_size_in_bytes; -- cgit v1.2.3 From 843f65c669c1164897dc5ef79c0df00cb66490bf Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:31:18 -0800 Subject: Staging: sep: clean up error checking in probe function Add pci_disable Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 241b1b1bcaed..821d3b7c6477 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -3437,7 +3437,8 @@ static int __devinit sep_probe(struct pci_dev *pdev, if (sep_dev == NULL) { dev_warn(&pdev->dev, "can't kmalloc the sep_device structure\n"); - return -ENOMEM; + error = -ENOMEM; + goto end_function_disable_device; } /* @@ -3448,7 +3449,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, */ sep = sep_dev; - sep->pdev = pdev; + sep->pdev = pci_dev_get(pdev); init_waitqueue_head(&sep->event); init_waitqueue_head(&sep->event_request_daemon); @@ -3466,23 +3467,23 @@ static int __devinit sep_probe(struct pci_dev *pdev, sep->reg_physical_addr = pci_resource_start(sep->pdev, 0); if (!sep->reg_physical_addr) { dev_warn(&sep->pdev->dev, "Error getting register start\n"); - pci_dev_put(sep->pdev); - return -ENODEV; + error = -ENODEV; + goto end_function_free_sep_dev; } sep->reg_physical_end = pci_resource_end(sep->pdev, 0); if (!sep->reg_physical_end) { dev_warn(&sep->pdev->dev, "Error getting register end\n"); - pci_dev_put(sep->pdev); - return -ENODEV; + error = -ENODEV; + goto end_function_free_sep_dev; } sep->reg_addr = ioremap_nocache(sep->reg_physical_addr, (size_t)(sep->reg_physical_end - sep->reg_physical_addr + 1)); if (!sep->reg_addr) { dev_warn(&sep->pdev->dev, "Error getting register virtual\n"); - pci_dev_put(sep->pdev); - return -ENODEV; + error = -ENODEV; + goto end_function_free_sep_dev; } dev_dbg(&sep->pdev->dev, @@ -3573,9 +3574,15 @@ end_function_deallocate_sep_shared_area: end_function_error: iounmap(sep->reg_addr); + +end_function_free_sep_dev: + pci_dev_put(sep_dev->pdev); kfree(sep_dev); sep_dev = NULL; +end_function_disable_device: + pci_disable_device(pdev); + end_function: return error; } -- cgit v1.2.3 From 08740c97e191d4d5bb1f472a6ec0fa24ebdbc8bc Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:31:31 -0800 Subject: Staging: sep: initialize driver copy of send and receive count with device Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 821d3b7c6477..c8008244d3f9 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -3538,6 +3538,11 @@ static int __devinit sep_probe(struct pci_dev *pdev, /* Set the IMR register - open only GPR 2 */ sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); + /* Read send/receive counters from SEP */ + sep->reply_ct = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); + sep->reply_ct &= 0x3FFFFFFF; + sep->send_ct = sep->reply_ct; + dev_dbg(&sep->pdev->dev, "about to call request_irq\n"); /* Get the interrupt line */ error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, -- cgit v1.2.3 From 0dd12c44510c342282145c8048b447a13ce78a32 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:31:43 -0800 Subject: Staging: sep: remove code for Moorestown device The Moorestown (older device) will be added to driver later. Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 110 ++++++------------------------- drivers/staging/sep/sep_driver_hw_defs.h | 1 - 2 files changed, 20 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index c8008244d3f9..5a54f984e28e 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -940,9 +940,7 @@ static int sep_send_command_handler(struct sep_device *sep) } sep_set_time(sep); - /* Only Medfield has caller id */ - if (sep->mrst == 0) - sep_set_current_caller_id(sep); + sep_set_current_caller_id(sep); sep_dump_message(sep); @@ -3057,8 +3055,6 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) error = sep_end_transaction_handler(sep); break; case SEP_IOCREALLOCEXTCACHE: - if (sep->mrst) - error = -ENODEV; if (sep->pdev->revision == 0) /* Only for old chip */ error = sep_realloc_ext_cache_handler(sep, arg); else @@ -3237,55 +3233,6 @@ static irqreturn_t sep_inthandler(int irq, void *dev_id) return int_error; } -/** - * sep_callback - RAR callback - * @sep_context_pointer: pointer to struct sep_device - * - * Function that is called by rar_register when it is ready with - * a region (only for Moorestown) - */ -static int sep_callback(unsigned long sep_context_pointer) -{ - int error; - struct sep_device *sep = (struct sep_device *)sep_context_pointer; - dma_addr_t rar_end_address; - - dev_dbg(&sep->pdev->dev, "callback start\n"); - - error = rar_get_address(RAR_TYPE_IMAGE, &sep->rar_bus, - &rar_end_address); - - if (error) { - dev_warn(&sep->pdev->dev, "mrst can't get rar region\n"); - goto end_function; - } - - sep->rar_size = (size_t)(rar_end_address - sep->rar_bus + 1); - - if (!request_mem_region(sep->rar_bus, sep->rar_size, - "sep_sec_driver")) { - dev_warn(&sep->pdev->dev, - "request mem region for mrst failed\n"); - error = -1; - goto end_function; - } - - sep->rar_addr = ioremap_nocache(sep->rar_bus, sep->rar_size); - if (!sep->rar_addr) { - dev_warn(&sep->pdev->dev, - "ioremap nocache for mrst rar failed\n"); - error = -ENOMEM; - goto end_function; - } - dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx, size is %zx\n", - sep->rar_addr, (unsigned long long)sep->rar_bus, - sep->rar_size); - -end_function: - dev_dbg(&sep->pdev->dev, "callback end\n"); - return error; -} - /** * sep_reconfig_shared_area - reconfigure shared area * @sep: pointer to struct sep_device @@ -3390,16 +3337,14 @@ static int sep_register_driver_with_fs(struct sep_device *sep) return ret_val; } - if (!sep->mrst) { - ret_val = misc_register(&sep->miscdev_daemon); - if (ret_val) { - dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n", - ret_val); - misc_deregister(&sep->miscdev_sep); - misc_deregister(&sep->miscdev_singleton); + ret_val = misc_register(&sep->miscdev_daemon); + if (ret_val) { + dev_warn(&sep->pdev->dev, "misc reg fails for dmn %x\n", + ret_val); + misc_deregister(&sep->miscdev_sep); + misc_deregister(&sep->miscdev_singleton); - return ret_val; - } + return ret_val; } return ret_val; } @@ -3457,9 +3402,6 @@ static int __devinit sep_probe(struct pci_dev *pdev, mutex_init(&sep->sep_mutex); mutex_init(&sep->ioctl_mutex); - if (pdev->device == MRST_PCI_DEVICE_ID) - sep->mrst = 1; - dev_dbg(&sep->pdev->dev, "PCI obtained, device being prepared\n"); dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision); @@ -3505,31 +3447,20 @@ static int __devinit sep_probe(struct pci_dev *pdev, goto end_function_error; } - /* The next section depends on type of unit */ - if (sep->mrst) { - error = register_rar(RAR_TYPE_IMAGE, &sep_callback, - (unsigned long)sep); - if (error) { - dev_dbg(&sep->pdev->dev, - "error register_rar\n"); - goto end_function_deallocate_sep_shared_area; - } - } else { - sep->rar_size = FAKE_RAR_SIZE; - sep->rar_addr = dma_alloc_coherent(NULL, - sep->rar_size, &sep->rar_bus, GFP_KERNEL); - if (sep->rar_addr == NULL) { - dev_warn(&sep->pdev->dev, "can't allocate mfld rar\n"); - error = -ENOMEM; - goto end_function_deallocate_sep_shared_area; - } - - dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx," - " size is %zx\n", sep->rar_addr, - (unsigned long long)sep->rar_bus, - sep->rar_size); + sep->rar_size = FAKE_RAR_SIZE; + sep->rar_addr = dma_alloc_coherent(NULL, + sep->rar_size, &sep->rar_bus, GFP_KERNEL); + if (sep->rar_addr == NULL) { + dev_warn(&sep->pdev->dev, "can't allocate mfld rar\n"); + error = -ENOMEM; + goto end_function_deallocate_sep_shared_area; } + dev_dbg(&sep->pdev->dev, "rar start is %p, phy is %llx," + " size is %zx\n", sep->rar_addr, + (unsigned long long)sep->rar_bus, + sep->rar_size); + dev_dbg(&sep->pdev->dev, "about to write IMR and ICR REG_ADDR\n"); /* Clear ICR register */ @@ -3610,7 +3541,6 @@ static void sep_remove(struct pci_dev *pdev) } static DEFINE_PCI_DEVICE_TABLE(sep_pci_id_tbl) = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MRST_PCI_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MFLD_PCI_DEVICE_ID)}, {0} }; diff --git a/drivers/staging/sep/sep_driver_hw_defs.h b/drivers/staging/sep/sep_driver_hw_defs.h index 29addd7b5dd3..300f90963de3 100644 --- a/drivers/staging/sep/sep_driver_hw_defs.h +++ b/drivers/staging/sep/sep_driver_hw_defs.h @@ -33,7 +33,6 @@ #define SEP_DRIVER_HW_DEFS__H /* PCI ID's */ -#define MRST_PCI_DEVICE_ID 0x080c #define MFLD_PCI_DEVICE_ID 0x0826 /*----------------------- */ -- cgit v1.2.3 From 8f9346a091ac523afa73643aae69f74f0f8a6e80 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:31:57 -0800 Subject: Staging: sep: remove completed items in TODO Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/TODO | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO index 371ee279f327..089c2406345e 100644 --- a/drivers/staging/sep/TODO +++ b/drivers/staging/sep/TODO @@ -1,12 +1,5 @@ Todo's so far (from Alan Cox) -- Fix firmware loading - Done 09/10 M. Allyn -- Get firmware into firmware git tree - Firmware is non open source -- Review and tidy each algorithm function - Done 09/10 M. Allyn - Check whether it can be plugged into any of the kernel crypto API interfaces - Crypto API 'glue' is still not ready to submit -- Do something about the magic shared memory interface and replace it - with something saner (in Linux terms) - Done 09/10 M. Allyn - Clean up unused ioctls - Needs vendor help - Clean up unused fields in ioctl structures - Needs vendor help -- 64 bit size to be used for all user space addresses passed - to ioctl - Done 10/10 M. Allyn -- cgit v1.2.3 From be38efe11748684d54ff86810443979a59b96cfc Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:32:13 -0800 Subject: Staging: sep: limit time to wait for reconfig shared area complete Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 9 ++++++++- drivers/staging/sep/sep_driver_config.h | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 5a54f984e28e..83475eb77ad8 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include "../memrar/memrar.h" @@ -3244,6 +3245,9 @@ static int sep_reconfig_shared_area(struct sep_device *sep) { int ret_val; + /* use to limit waiting for SEP */ + unsigned long end_time; + dev_dbg(&sep->pdev->dev, "reconfig shared area start\n"); /* Send the new SHARED MESSAGE AREA to the SEP */ @@ -3255,7 +3259,10 @@ static int sep_reconfig_shared_area(struct sep_device *sep) /* Poll for SEP response */ ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - while (ret_val != 0xffffffff && ret_val != sep->shared_bus) + end_time = jiffies + (WAIT_TIME * HZ); + + while ((time_before(jiffies, end_time)) && (ret_val != 0xffffffff) && + (ret_val != sep->shared_bus)) ret_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); /* Check the return value (register) */ diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h index b96045f178cd..92338c0f6bd2 100644 --- a/drivers/staging/sep/sep_driver_config.h +++ b/drivers/staging/sep/sep_driver_config.h @@ -230,5 +230,7 @@ held by the proccess (struct file) */ /* the token that defines the data pool pointers address */ #define SEP_EXT_CACHE_ADDR_VAL_TOKEN 0xBABABABA +/* Time limit for SEP to finish */ +#define WAIT_TIME 10 #endif /* SEP DRIVER CONFIG */ -- cgit v1.2.3 From c100fa4d6142271cc6d228fd84a5da2390ec5ec1 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:32:26 -0800 Subject: Staging: sep: reduce 64 and 32 bit compile warnings Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 101 ++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 83475eb77ad8..903d6106c0d3 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -91,7 +91,7 @@ static int sep_load_firmware(struct sep_device *sep) char *res_name = "resident.image.bin"; char *extapp_name = "extapp.image.bin"; int error ; - unsigned int work1, work2, work3; + unsigned long work1, work2, work3; /* Set addresses and load resident */ sep->resident_bus = sep->rar_bus; @@ -115,13 +115,13 @@ static int sep_load_firmware(struct sep_device *sep) sep->resident_size); /* Set addresses for dcache (no loading needed) */ - work1 = (unsigned int)sep->resident_bus; - work2 = (unsigned int)sep->resident_size; + work1 = (unsigned long)sep->resident_bus; + work2 = (unsigned long)sep->resident_size; work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000; sep->dcache_bus = (dma_addr_t)work3; - work1 = (unsigned int)sep->resident_addr; - work2 = (unsigned int)sep->resident_size; + work1 = (unsigned long)sep->resident_addr; + work2 = (unsigned long)sep->resident_size; work3 = (work1 + work2 + (1024 * 4)) & 0xfffff000; sep->dcache_addr = (void *)work3; @@ -831,7 +831,7 @@ static unsigned long sep_set_time(struct sep_device *sep) * Inserts the data into the caller id table. Note that this function * falls under the ioctl lock */ -static int sep_set_caller_id_handler(struct sep_device *sep, u32 arg) +static int sep_set_caller_id_handler(struct sep_device *sep, unsigned long arg) { void __user *hash; int error = 0; @@ -1063,7 +1063,7 @@ end_function: * the kernel (when ioctl is not used) */ static int sep_lock_kernel_pages(struct sep_device *sep, - u32 kernel_virt_addr, + unsigned long kernel_virt_addr, u32 data_size, struct sep_lli_entry **lli_array_ptr, int in_out_flag) @@ -1076,8 +1076,8 @@ static int sep_lock_kernel_pages(struct sep_device *sep, struct sep_dma_map *map_array; dev_dbg(&sep->pdev->dev, "sep_lock_kernel_pages start\n"); - dev_dbg(&sep->pdev->dev, "kernel_virt_addr is %08x\n", - kernel_virt_addr); + dev_dbg(&sep->pdev->dev, "kernel_virt_addr is %08lx\n", + (unsigned long)kernel_virt_addr); dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size); lli_array = kmalloc(sizeof(struct sep_lli_entry), GFP_ATOMIC); @@ -1530,8 +1530,8 @@ static dma_addr_t sep_shared_area_virt_to_bus(struct sep_device *sep, static void *sep_shared_area_bus_to_virt(struct sep_device *sep, dma_addr_t bus_address) { - dev_dbg(&sep->pdev->dev, "shared bus to virt b=%x v=%x\n", - (u32)bus_address, (u32)(sep->shared_addr + + dev_dbg(&sep->pdev->dev, "shared bus to virt b=%lx v=%lx\n", + (unsigned long)bus_address, (unsigned long)(sep->shared_addr + (size_t)(bus_address - sep->shared_bus))); return sep->shared_addr + (size_t)(bus_address - sep->shared_bus); @@ -1556,7 +1556,7 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "sep_debug_print_lli_tables start\n"); - while ((unsigned long) lli_table_ptr != 0xffffffff) { + while ((unsigned long) lli_table_ptr->bus_address != 0xffffffff) { dev_dbg(&sep->pdev->dev, "lli table %08lx, table_data_size is %lu\n", table_count, table_data_size); @@ -1590,18 +1590,16 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, table_data_size = lli_table_ptr->block_size & 0xffffff; num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff; - lli_table_ptr = (struct sep_lli_entry *) - (lli_table_ptr->bus_address); dev_dbg(&sep->pdev->dev, "phys table_data_size is %lu num_table_entries is" - " %lu lli_table_ptr is%lu\n", table_data_size, - num_table_entries, (unsigned long)lli_table_ptr); + " %lu bus_address is%lu\n", table_data_size, + num_table_entries, (unsigned long)lli_table_ptr->bus_address); - if ((unsigned long)lli_table_ptr != 0xffffffff) + if ((unsigned long)lli_table_ptr->bus_address != 0xffffffff) lli_table_ptr = (struct sep_lli_entry *) sep_shared_bus_to_virt(sep, - (unsigned long)lli_table_ptr); + (unsigned long)lli_table_ptr->bus_address); table_count++; } @@ -1701,7 +1699,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, /* Number of entries in lli table */ u32 num_entries_in_table = 0; /* Next table address */ - u32 lli_table_alloc_addr = 0; + void *lli_table_alloc_addr = 0; dev_dbg(&sep->pdev->dev, "sep_prepare_input_dma_table start\n"); dev_dbg(&sep->pdev->dev, "data_size is %x\n", data_size); @@ -1712,7 +1710,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = 0; /* Set the kernel address for first table to be allocated */ - lli_table_alloc_addr = (u32)(sep->shared_addr + + lli_table_alloc_addr = (void *)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + sep->num_lli_tables_created * sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); @@ -1759,7 +1757,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; if (lli_table_alloc_addr > - ((u32)sep->shared_addr + + ((void *)sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) { @@ -1874,7 +1872,7 @@ static int sep_construct_dma_tables_from_lli( u32 *table_data_size_ptr) { /* Points to the area where next lli table can be allocated */ - u32 lli_table_alloc_addr = 0; + void *lli_table_alloc_addr = 0; /* Input lli table */ struct sep_lli_entry *in_lli_table_ptr = NULL; /* Output lli table */ @@ -1903,7 +1901,7 @@ static int sep_construct_dma_tables_from_lli( dev_dbg(&sep->pdev->dev, "sep_construct_dma_tables_from_lli start\n"); /* Initiate to point after the message area */ - lli_table_alloc_addr = (u32)(sep->shared_addr + + lli_table_alloc_addr = (void *)(sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + (sep->num_lli_tables_created * (sizeof(struct sep_lli_entry) * @@ -1925,7 +1923,7 @@ static int sep_construct_dma_tables_from_lli( /* Check if the DMA table area limit was overrun */ if ((lli_table_alloc_addr + sizeof(struct sep_lli_entry) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP) > - ((u32)sep->shared_addr + + ((void *)sep->shared_addr + SYNCHRONIC_DMA_TABLES_AREA_OFFSET_BYTES + SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES)) { @@ -2251,13 +2249,13 @@ end_function: * are in 32 bit format; the SEP is a 32 bit device */ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, - u32 app_in_address, - u32 app_out_address, - u32 data_in_size, - u32 block_size, - u32 tail_block_size, - bool isapplet, - bool is_kva) + unsigned long app_in_address, + unsigned long app_out_address, + u32 data_in_size, + u32 block_size, + u32 tail_block_size, + bool isapplet, + bool is_kva) { int error = 0; /* Size of tail */ @@ -2366,7 +2364,7 @@ static int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, * according to tail data size */ dcb_table_ptr->out_vr_tail_pt = - app_out_address + data_in_size + (u32)app_out_address + data_in_size - tail_size; /* Save the real tail data size */ @@ -2467,8 +2465,8 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, } error = sep_prepare_input_output_dma_table_in_dcb(sep, - command_args.app_in_address, - command_args.app_out_address, + (unsigned long)command_args.app_in_address, + (unsigned long)command_args.app_out_address, command_args.data_in_size, command_args.block_size, 0x0, @@ -2495,6 +2493,8 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, int error = 0; int error_temp = 0; struct sep_dcblock *dcb_table_ptr; + unsigned long pt_hold; + void *tail_pt; dev_dbg(&sep->pdev->dev, "sep_free_dma_tables_and_dcb start\n"); @@ -2507,13 +2507,15 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, /* Go over each DCB and see if tail pointer must be updated */ for (i = 0; i < sep->nr_dcb_creat; i++, dcb_table_ptr++) { if (dcb_table_ptr->out_vr_tail_pt) { + pt_hold = (unsigned long)dcb_table_ptr->out_vr_tail_pt; + tail_pt = (void *)pt_hold; if (is_kva == true) { - memcpy((void *)dcb_table_ptr->out_vr_tail_pt, + memcpy(tail_pt, dcb_table_ptr->tail_data, dcb_table_ptr->tail_data_size); } else { error_temp = copy_to_user( - (void *)dcb_table_ptr->out_vr_tail_pt, + tail_pt, dcb_table_ptr->tail_data, dcb_table_ptr->tail_data_size); } @@ -2841,7 +2843,8 @@ static int sep_prepare_dcb_handler(struct sep_device *sep, unsigned long arg) command_args.tail_block_size); error = sep_prepare_input_output_dma_table_in_dcb(sep, - command_args.app_in_address, command_args.app_out_address, + (unsigned long)command_args.app_in_address, + (unsigned long)command_args.app_out_address, command_args.data_in_size, command_args.block_size, command_args.tail_block_size, true, false); @@ -2971,30 +2974,6 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) dev_dbg(&sep->pdev->dev, "ioctl start\n"); dev_dbg(&sep->pdev->dev, "cmd is %x\n", cmd); - dev_dbg(&sep->pdev->dev, - "SEP_IOCSENDSEPCOMMAND is %x\n", SEP_IOCSENDSEPCOMMAND); - dev_dbg(&sep->pdev->dev, - "SEP_IOCALLOCDATAPOLL is %x\n", SEP_IOCALLOCDATAPOLL); - dev_dbg(&sep->pdev->dev, - "SEP_IOCCREATESYMDMATABLE is %x\n", SEP_IOCCREATESYMDMATABLE); - dev_dbg(&sep->pdev->dev, - "SEP_IOCFREEDMATABLEDATA is %x\n", SEP_IOCFREEDMATABLEDATA); - dev_dbg(&sep->pdev->dev, - "SEP_IOCSEPSTART is %x\n", SEP_IOCSEPSTART); - dev_dbg(&sep->pdev->dev, - "SEP_IOCSEPINIT is %x\n", SEP_IOCSEPINIT); - dev_dbg(&sep->pdev->dev, - "SEP_IOCGETSTATICPOOLADDR is %x\n", SEP_IOCGETSTATICPOOLADDR); - dev_dbg(&sep->pdev->dev, - "SEP_IOCENDTRANSACTION is %x\n", SEP_IOCENDTRANSACTION); - dev_dbg(&sep->pdev->dev, - "SEP_IOCREALLOCEXTCACHE is %x\n", SEP_IOCREALLOCEXTCACHE); - dev_dbg(&sep->pdev->dev, - "SEP_IOCRARPREPAREMESSAGE is %x\n", SEP_IOCRARPREPAREMESSAGE); - dev_dbg(&sep->pdev->dev, - "SEP_IOCPREPAREDCB is %x\n", SEP_IOCPREPAREDCB); - dev_dbg(&sep->pdev->dev, - "SEP_IOCFREEDCB is %x\n", SEP_IOCFREEDCB); /* Make sure we own this device */ mutex_lock(&sep->sep_mutex); -- cgit v1.2.3 From 653bf0cfa55896b74d8cbe7e561401813ca359ad Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:32:38 -0800 Subject: Staging: sep: ensure that caller id buffer is little endian Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 8 ++++++++ drivers/staging/sep/sep_driver_config.h | 3 +++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 903d6106c0d3..bb42b048f46a 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -897,6 +897,7 @@ end_function: static int sep_set_current_caller_id(struct sep_device *sep) { int i; + u32 *hash_buf_ptr; dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id start\n"); dev_dbg(&sep->pdev->dev, "current process is %d\n", current->pid); @@ -915,6 +916,13 @@ static int sep_set_current_caller_id(struct sep_device *sep) break; } } + /* Ensure data is in little endian */ + hash_buf_ptr = (u32 *)sep->shared_addr + + SEP_CALLER_ID_OFFSET_BYTES; + + for (i = 0; i < SEP_CALLER_ID_HASH_SIZE_IN_WORDS; i++) + hash_buf_ptr[i] = cpu_to_le32(hash_buf_ptr[i]); + dev_dbg(&sep->pdev->dev, "sep_set_current_caller_id end\n"); return 0; } diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h index 92338c0f6bd2..b18625d2f7f4 100644 --- a/drivers/staging/sep/sep_driver_config.h +++ b/drivers/staging/sep/sep_driver_config.h @@ -201,6 +201,9 @@ held by the proccess (struct file) */ /* size of the caller id hash (sha2) */ #define SEP_CALLER_ID_HASH_SIZE_IN_BYTES 32 +/* size of the caller id hash (sha2) in 32 bit words */ +#define SEP_CALLER_ID_HASH_SIZE_IN_WORDS 8 + /* maximum number of entries in the caller id table */ #define SEP_CALLER_ID_TABLE_NUM_ENTRIES 20 -- cgit v1.2.3 From fd599985e649c71162495d307a2fd1bbddc258e4 Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Thu, 9 Dec 2010 09:32:53 -0800 Subject: Staging: sep: eliminate kernel crash due to null parameter in dma_alloc_coherent Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index bb42b048f46a..2681fcf0c34d 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -3442,7 +3442,7 @@ static int __devinit sep_probe(struct pci_dev *pdev, } sep->rar_size = FAKE_RAR_SIZE; - sep->rar_addr = dma_alloc_coherent(NULL, + sep->rar_addr = dma_alloc_coherent(&sep->pdev->dev, sep->rar_size, &sep->rar_bus, GFP_KERNEL); if (sep->rar_addr == NULL) { dev_warn(&sep->pdev->dev, "can't allocate mfld rar\n"); -- cgit v1.2.3 From 88ab8a8445838785e38af378740ab57f8cb6cb8a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Sat, 4 Dec 2010 00:17:55 +0200 Subject: Staging: comedi: Fix coding style issues in drivers.c This patch fixes line over 80 characters warning issues found in file drivers.c Signed-off-by: Xenofon Foukas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index ef24a530278b..dca861ee0466 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -117,8 +117,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) for (driv = comedi_drivers; driv; driv = driv->next) { if (!try_module_get(driv->module)) { - printk - (KERN_INFO "comedi: failed to increment module count, skipping\n"); + printk(KERN_INFO "comedi: failed to increment module count, skipping\n"); continue; } if (driv->num_names) { @@ -205,9 +204,8 @@ int comedi_driver_unregister(struct comedi_driver *driver) mutex_lock(&dev->mutex); if (dev->attached && dev->driver == driver) { if (dev->use_count) - printk - (KERN_WARNING "BUG! detaching device with use_count=%d\n", - dev->use_count); + printk(KERN_WARNING "BUG! detaching device with use_count=%d\n", + dev->use_count); comedi_device_detach(dev); } mutex_unlock(&dev->mutex); @@ -442,7 +440,9 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned i; for (i = 0; i < async->n_buf_pages; ++i) { if (async->buf_page_list[i].virt_addr) { - clear_bit(PG_reserved, &(virt_to_page(async->buf_page_list[i].virt_addr)->flags)); + clear_bit(PG_reserved, + &(virt_to_page(async->buf_page_list[i]. + virt_addr)->flags)); if (s->async_dma_dir != DMA_NONE) { dma_free_coherent(dev->hw_dev, PAGE_SIZE, @@ -494,8 +494,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, break; set_bit(PG_reserved, - &(virt_to_page(async->buf_page_list[i].virt_addr)->flags)); - pages[i] = virt_to_page(async->buf_page_list[i].virt_addr); + &(virt_to_page(async->buf_page_list[i]. + virt_addr)->flags)); + pages[i] = virt_to_page(async->buf_page_list[i]. + virt_addr); } } if (i == n_pages) { @@ -512,7 +514,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, NULL) { break; } - clear_bit(PG_reserved, &(virt_to_page(async->buf_page_list[i].virt_addr)->flags)); + clear_bit(PG_reserved, + &(virt_to_page(async-> + buf_page_list[i]. + virt_addr)->flags)); if (s->async_dma_dir != DMA_NONE) { dma_free_coherent(dev->hw_dev, PAGE_SIZE, @@ -644,8 +649,7 @@ unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes) { if ((int)(async->buf_write_count + nbytes - async->buf_write_alloc_count) > 0) { - printk - (KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n"); + printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n"); nbytes = async->buf_write_alloc_count - async->buf_write_count; } async->buf_write_count += nbytes; -- cgit v1.2.3 From 4291ee305e9bb0699504a66f0e2b7aefcf0512a5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 9 Dec 2010 19:29:03 -0800 Subject: HID: Add and use hid_: dev_ equivalents Neaten current uses of dev_ by adding and using hid specific hid_ macros. Convert existing uses of dev_ uses to hid_. Convert hid-pidff printk uses to hid_. Remove err_hid and use hid_err instead. Add missing newlines to logging messages where necessary. Coalesce format strings. Add and use pr_fmt(fmt) KBUILD_MODNAME ": " fmt Other miscellaneous changes: Add const struct hid_device * argument to hid-core functions extract() and implement() so hid_ can be used by them. Fix bad indentation in hid-core hid_input_field function that calls extract() function above. Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- drivers/hid/hid-3m-pct.c | 2 +- drivers/hid/hid-a4tech.c | 6 +- drivers/hid/hid-apple.c | 14 ++-- drivers/hid/hid-axff.c | 14 ++-- drivers/hid/hid-belkin.c | 4 +- drivers/hid/hid-cando.c | 2 +- drivers/hid/hid-cherry.c | 3 +- drivers/hid/hid-core.c | 64 +++++++++------- drivers/hid/hid-cypress.c | 4 +- drivers/hid/hid-debug.c | 4 +- drivers/hid/hid-drff.c | 14 ++-- drivers/hid/hid-egalax.c | 2 +- drivers/hid/hid-elecom.c | 3 +- drivers/hid/hid-emsff.c | 13 ++-- drivers/hid/hid-gaff.c | 13 ++-- drivers/hid/hid-input.c | 2 +- drivers/hid/hid-kye.c | 4 +- drivers/hid/hid-lg.c | 15 ++-- drivers/hid/hid-lg2ff.c | 9 +-- drivers/hid/hid-lg3ff.c | 9 +-- drivers/hid/hid-lg4ff.c | 9 +-- drivers/hid/hid-lgff.c | 8 +- drivers/hid/hid-magicmouse.c | 15 ++-- drivers/hid/hid-microsoft.c | 7 +- drivers/hid/hid-monterey.c | 3 +- drivers/hid/hid-mosart.c | 2 +- drivers/hid/hid-ntrig.c | 9 +-- drivers/hid/hid-ortek.c | 3 +- drivers/hid/hid-petalynx.c | 7 +- drivers/hid/hid-picolcd.c | 45 ++++++----- drivers/hid/hid-pl.c | 16 ++-- drivers/hid/hid-prodikeys.c | 21 +++--- drivers/hid/hid-quanta.c | 2 +- drivers/hid/hid-roccat-kone.c | 22 +++--- drivers/hid/hid-roccat-pyra.c | 20 +++-- drivers/hid/hid-roccat.c | 10 +-- drivers/hid/hid-samsung.c | 8 +- drivers/hid/hid-sjoy.c | 16 ++-- drivers/hid/hid-sony.c | 11 ++- drivers/hid/hid-stantum.c | 2 +- drivers/hid/hid-sunplus.c | 3 +- drivers/hid/hid-tmff.c | 27 +++---- drivers/hid/hid-wacom.c | 26 ++++--- drivers/hid/hid-zpff.c | 11 ++- drivers/hid/hid-zydacron.c | 11 ++- drivers/hid/hidraw.c | 12 +-- drivers/hid/usbhid/hid-core.c | 48 ++++++------ drivers/hid/usbhid/hid-pidff.c | 164 +++++++++++++++++++---------------------- drivers/hid/usbhid/hiddev.c | 2 +- drivers/hid/usbhid/usbkbd.c | 24 +++--- include/linux/hid.h | 32 ++++++-- 51 files changed, 398 insertions(+), 399 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c index 02d8cd3b1b1b..4546c123eb77 100644 --- a/drivers/hid/hid-3m-pct.c +++ b/drivers/hid/hid-3m-pct.c @@ -274,7 +274,7 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id) md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL); if (!md) { - dev_err(&hdev->dev, "cannot allocate 3M data\n"); + hid_err(hdev, "cannot allocate 3M data\n"); return -ENOMEM; } hid_set_drvdata(hdev, md); diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c index 1666c1684e79..902d1dfeb1b5 100644 --- a/drivers/hid/hid-a4tech.c +++ b/drivers/hid/hid-a4tech.c @@ -93,7 +93,7 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id) a4 = kzalloc(sizeof(*a4), GFP_KERNEL); if (a4 == NULL) { - dev_err(&hdev->dev, "can't alloc device descriptor\n"); + hid_err(hdev, "can't alloc device descriptor\n"); ret = -ENOMEM; goto err_free; } @@ -104,13 +104,13 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 8aa71750a23c..61aa71233392 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -16,6 +16,8 @@ * any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -280,8 +282,8 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 && rdesc[53] == 0x65 && rdesc[59] == 0x65) { - dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report " - "descriptor\n"); + hid_info(hdev, + "fixing up MacBook JIS keyboard report descriptor\n"); rdesc[53] = rdesc[59] = 0xe7; } return rdesc; @@ -351,7 +353,7 @@ static int apple_probe(struct hid_device *hdev, asc = kzalloc(sizeof(*asc), GFP_KERNEL); if (asc == NULL) { - dev_err(&hdev->dev, "can't alloc apple descriptor\n"); + hid_err(hdev, "can't alloc apple descriptor\n"); return -ENOMEM; } @@ -361,7 +363,7 @@ static int apple_probe(struct hid_device *hdev, ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } @@ -372,7 +374,7 @@ static int apple_probe(struct hid_device *hdev, ret = hid_hw_start(hdev, connect_mask); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } @@ -512,7 +514,7 @@ static int __init apple_init(void) ret = hid_register_driver(&apple_driver); if (ret) - printk(KERN_ERR "can't register apple driver\n"); + pr_err("can't register apple driver\n"); return ret; } diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c index f42ee140738a..e5b961d6ff22 100644 --- a/drivers/hid/hid-axff.c +++ b/drivers/hid/hid-axff.c @@ -73,14 +73,14 @@ static int axff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output reports found\n"); + hid_err(hid, "no output reports found\n"); return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); if (report->maxfield < 4) { - dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield); + hid_err(hid, "no fields in the report: %d\n", report->maxfield); return -ENODEV; } @@ -101,7 +101,7 @@ static int axff_init(struct hid_device *hid) axff->report->field[3]->value[0] = 0x00; usbhid_submit_report(hid, axff->report, USB_DIR_OUT); - dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun\n"); + hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun\n"); return 0; @@ -114,17 +114,17 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) { int error; - dev_dbg(&hdev->dev, "ACRUX HID hardware probe..."); + dev_dbg(&hdev->dev, "ACRUX HID hardware probe...\n"); error = hid_parse(hdev); if (error) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); return error; } error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (error) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); return error; } @@ -134,7 +134,7 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) * Do not fail device initialization completely as device * may still be partially operable, just warn. */ - dev_warn(&hdev->dev, + hid_warn(hdev, "Failed to enable force feedback support, error: %d\n", error); } diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c index 4ce7aa3a519f..a1a765a5b08a 100644 --- a/drivers/hid/hid-belkin.c +++ b/drivers/hid/hid-belkin.c @@ -56,14 +56,14 @@ static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0)); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c index 5925bdcd417d..375b50929a50 100644 --- a/drivers/hid/hid-cando.c +++ b/drivers/hid/hid-cando.c @@ -207,7 +207,7 @@ static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id) td = kmalloc(sizeof(struct cando_data), GFP_KERNEL); if (!td) { - dev_err(&hdev->dev, "cannot allocate Cando Touch data\n"); + hid_err(hdev, "cannot allocate Cando Touch data\n"); return -ENOMEM; } hid_set_drvdata(hdev, td); diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index e880086c2311..888ece68a47c 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c @@ -30,8 +30,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { - dev_info(&hdev->dev, "fixing up Cherry Cymotion report " - "descriptor\n"); + hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n"); rdesc[11] = rdesc[16] = 0xff; rdesc[12] = rdesc[17] = 0x03; } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 396f8c7e0076..1fd5e331fa8d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -14,6 +14,8 @@ * any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -672,7 +674,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start, if (dispatch_type[item.type](parser, &item)) { dbg_hid("item %u %u %u %u parsing failed\n", - item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); + item.format, (unsigned)item.size, + (unsigned)item.type, (unsigned)item.tag); goto err; } @@ -737,13 +740,14 @@ static u32 s32ton(__s32 value, unsigned n) * Search linux-kernel and linux-usb-devel archives for "hid-core extract". */ -static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) +static __inline__ __u32 extract(const struct hid_device *hid, __u8 *report, + unsigned offset, unsigned n) { u64 x; if (n > 32) - printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n", - n, current->comm); + hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n", + n, current->comm); report += offset >> 3; /* adjust byte index */ offset &= 7; /* now only need bit offset into one byte */ @@ -760,18 +764,19 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) * endianness of register values by considering a register * a "cached" copy of the little endiad bit stream. */ -static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) +static __inline__ void implement(const struct hid_device *hid, __u8 *report, + unsigned offset, unsigned n, __u32 value) { u64 x; u64 m = (1ULL << n) - 1; if (n > 32) - printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n", - n, current->comm); + hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n", + __func__, n, current->comm); if (value > m) - printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n", - value, current->comm); + hid_warn(hid, "%s() called with too large value %d! (%s)\n", + __func__, value, current->comm); WARN_ON(value > m); value &= m; @@ -892,13 +897,16 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, for (n = 0; n < count; n++) { - value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : - extract(data, offset + n * size, size); + value[n] = min < 0 ? + snto32(extract(hid, data, offset + n * size, size), + size) : + extract(hid, data, offset + n * size, size); - if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ - && value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - goto exit; + /* Ignore report if ErrorRollOver */ + if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && + value[n] >= min && value[n] <= max && + field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) + goto exit; } for (n = 0; n < count; n++) { @@ -928,7 +936,8 @@ exit: * Output the field into the report. */ -static void hid_output_field(struct hid_field *field, __u8 *data) +static void hid_output_field(const struct hid_device *hid, + struct hid_field *field, __u8 *data) { unsigned count = field->report_count; unsigned offset = field->report_offset; @@ -937,9 +946,11 @@ static void hid_output_field(struct hid_field *field, __u8 *data) for (n = 0; n < count; n++) { if (field->logical_minimum < 0) /* signed values */ - implement(data, offset + n * size, size, s32ton(field->value[n], size)); + implement(hid, data, offset + n * size, size, + s32ton(field->value[n], size)); else /* unsigned values */ - implement(data, offset + n * size, size, field->value[n]); + implement(hid, data, offset + n * size, size, + field->value[n]); } } @@ -956,7 +967,7 @@ void hid_output_report(struct hid_report *report, __u8 *data) memset(data, 0, ((report->size - 1) >> 3) + 1); for (n = 0; n < report->maxfield; n++) - hid_output_field(report->field[n], data); + hid_output_field(report->device, report->field[n], data); } EXPORT_SYMBOL_GPL(hid_output_report); @@ -1169,8 +1180,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) hdev->claimed |= HID_CLAIMED_HIDRAW; if (!hdev->claimed) { - dev_err(&hdev->dev, "claimed by neither input, hiddev nor " - "hidraw\n"); + hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n"); return -ENODEV; } @@ -1210,9 +1220,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) bus = ""; } - dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n", - buf, bus, hdev->version >> 8, hdev->version & 0xff, - type, hdev->name, hdev->phys); + hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n", + buf, bus, hdev->version >> 8, hdev->version & 0xff, + type, hdev->name, hdev->phys); return 0; } @@ -1956,12 +1966,12 @@ static int __init hid_init(void) int ret; if (hid_debug) - printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n" - "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n"); + pr_warn("hid_debug is now used solely for parser and driver debugging.\n" + "debugfs is now used for inspecting the device (report descriptor, reports)\n"); ret = bus_register(&hid_bus_type); if (ret) { - printk(KERN_ERR "HID: can't register hid bus\n"); + pr_err("can't register hid bus\n"); goto err; } diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 4cd0e2345991..2f0be4c66af7 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -107,13 +107,13 @@ static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 75c5e23d09d2..555382fc7417 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -26,6 +26,8 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -393,7 +395,7 @@ char *hid_resolv_usage(unsigned usage, struct seq_file *f) { buf = resolv_usage_page(usage >> 16, f); if (IS_ERR(buf)) { - printk(KERN_ERR "error allocating HID debug buffer\n"); + pr_err("error allocating HID debug buffer\n"); return NULL; } diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-drff.c index 968b04f9b796..afcf3d67eb02 100644 --- a/drivers/hid/hid-drff.c +++ b/drivers/hid/hid-drff.c @@ -96,18 +96,18 @@ static int drff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output reports found\n"); + hid_err(hid, "no output reports found\n"); return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); if (report->maxfield < 1) { - dev_err(&hid->dev, "no fields in the report\n"); + hid_err(hid, "no fields in the report\n"); return -ENODEV; } if (report->field[0]->report_count < 7) { - dev_err(&hid->dev, "not enough values in the field\n"); + hid_err(hid, "not enough values in the field\n"); return -ENODEV; } @@ -133,8 +133,8 @@ static int drff_init(struct hid_device *hid) drff->report->field[0]->value[6] = 0x00; usbhid_submit_report(hid, drff->report, USB_DIR_OUT); - dev_info(&hid->dev, "Force Feedback for DragonRise Inc. game " - "controllers by Richard Walmsley \n"); + hid_info(hid, "Force Feedback for DragonRise Inc. " + "game controllers by Richard Walmsley \n"); return 0; } @@ -153,13 +153,13 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c index 54b017ad258d..bbab6cff3518 100644 --- a/drivers/hid/hid-egalax.c +++ b/drivers/hid/hid-egalax.c @@ -223,7 +223,7 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id) td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL); if (!td) { - dev_err(&hdev->dev, "cannot allocate eGalax data\n"); + hid_err(hdev, "cannot allocate eGalax data\n"); return -ENOMEM; } hid_set_drvdata(hdev, td); diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 6e31f305397d..79d0c61e7214 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -24,8 +24,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) { - dev_info(&hdev->dev, "Fixing up Elecom BM084 " - "report descriptor.\n"); + hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n"); rdesc[47] = 0x00; } return rdesc; diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c index c61b192d7cff..81877c67caea 100644 --- a/drivers/hid/hid-emsff.c +++ b/drivers/hid/hid-emsff.c @@ -68,18 +68,18 @@ static int emsff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output reports found\n"); + hid_err(hid, "no output reports found\n"); return -ENODEV; } report = list_first_entry(report_list, struct hid_report, list); if (report->maxfield < 1) { - dev_err(&hid->dev, "no fields in the report\n"); + hid_err(hid, "no fields in the report\n"); return -ENODEV; } if (report->field[0]->report_count < 7) { - dev_err(&hid->dev, "not enough values in the field\n"); + hid_err(hid, "not enough values in the field\n"); return -ENODEV; } @@ -105,8 +105,7 @@ static int emsff_init(struct hid_device *hid) emsff->report->field[0]->value[6] = 0x00; usbhid_submit_report(hid, emsff->report, USB_DIR_OUT); - dev_info(&hid->dev, "force feedback for EMS based devices by " - "Ignaz Forster \n"); + hid_info(hid, "force feedback for EMS based devices by Ignaz Forster \n"); return 0; } @@ -117,13 +116,13 @@ static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c index 88dfcf49a5d7..279ba530003c 100644 --- a/drivers/hid/hid-gaff.c +++ b/drivers/hid/hid-gaff.c @@ -87,7 +87,7 @@ static int gaff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output reports found\n"); + hid_err(hid, "no output reports found\n"); return -ENODEV; } @@ -95,12 +95,12 @@ static int gaff_init(struct hid_device *hid) report = list_entry(report_ptr, struct hid_report, list); if (report->maxfield < 1) { - dev_err(&hid->dev, "no fields in the report\n"); + hid_err(hid, "no fields in the report\n"); return -ENODEV; } if (report->field[0]->report_count < 6) { - dev_err(&hid->dev, "not enough values in the field\n"); + hid_err(hid, "not enough values in the field\n"); return -ENODEV; } @@ -128,8 +128,7 @@ static int gaff_init(struct hid_device *hid) usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); - dev_info(&hid->dev, "Force Feedback for GreenAsia 0x12" - " devices by Lukasz Lubojanski \n"); + hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski \n"); return 0; } @@ -148,13 +147,13 @@ static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index b718f7144ce1..a1a2206714fc 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -826,7 +826,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) if (!hidinput || !input_dev) { kfree(hidinput); input_free_device(input_dev); - err_hid("Out of memory during hid input probe"); + hid_err(hid, "Out of memory during hid input probe\n"); goto out_unwind; } diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index 817247ee006c..f2ba9efc3a53 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -32,8 +32,8 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[65] == 0x29 && rdesc[66] == 0x0f && rdesc[71] == 0x75 && rdesc[72] == 0x08 && rdesc[73] == 0x95 && rdesc[74] == 0x01) { - dev_info(&hdev->dev, "fixing up Kye/Genius Ergo Mouse report " - "descriptor\n"); + hid_info(hdev, + "fixing up Kye/Genius Ergo Mouse report descriptor\n"); rdesc[62] = 0x09; rdesc[64] = 0x04; rdesc[66] = 0x07; diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index b629fba5a057..aef4104da141 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -53,23 +53,22 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { - dev_info(&hdev->dev, "fixing up Logitech keyboard report " - "descriptor\n"); + hid_info(hdev, + "fixing up Logitech keyboard report descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { - dev_info(&hdev->dev, "fixing up rel/abs in Logitech " - "report descriptor\n"); + hid_info(hdev, + "fixing up rel/abs in Logitech report descriptor\n"); rdesc[33] = rdesc[50] = 0x02; } if ((quirks & LG_FF4) && *rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B && rdesc[47] == 0x05 && rdesc[48] == 0x09) { - dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless " - "button descriptor\n"); + hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n"); rdesc[41] = 0x05; rdesc[42] = 0x09; rdesc[47] = 0x95; @@ -288,7 +287,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } @@ -297,7 +296,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_hw_start(hdev, connect_mask); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c index 4258253c36b3..3c31bc650e5d 100644 --- a/drivers/hid/hid-lg2ff.c +++ b/drivers/hid/hid-lg2ff.c @@ -72,18 +72,18 @@ int lg2ff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output report found\n"); + hid_err(hid, "no output report found\n"); return -ENODEV; } report = list_entry(report_list->next, struct hid_report, list); if (report->maxfield < 1) { - dev_err(&hid->dev, "output report is empty\n"); + hid_err(hid, "output report is empty\n"); return -ENODEV; } if (report->field[0]->report_count < 7) { - dev_err(&hid->dev, "not enough values in the field\n"); + hid_err(hid, "not enough values in the field\n"); return -ENODEV; } @@ -110,8 +110,7 @@ int lg2ff_init(struct hid_device *hid) usbhid_submit_report(hid, report, USB_DIR_OUT); - dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by " - "Anssi Hannula \n"); + hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula \n"); return 0; } diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c index 4002832ee4af..f98644c26c1d 100644 --- a/drivers/hid/hid-lg3ff.c +++ b/drivers/hid/hid-lg3ff.c @@ -141,20 +141,20 @@ int lg3ff_init(struct hid_device *hid) /* Find the report to use */ if (list_empty(report_list)) { - err_hid("No output report found"); + hid_err(hid, "No output report found\n"); return -1; } /* Check that the report looks ok */ report = list_entry(report_list->next, struct hid_report, list); if (!report) { - err_hid("NULL output report"); + hid_err(hid, "NULL output report\n"); return -1; } field = report->field[0]; if (!field) { - err_hid("NULL field"); + hid_err(hid, "NULL field\n"); return -1; } @@ -169,8 +169,7 @@ int lg3ff_init(struct hid_device *hid) if (test_bit(FF_AUTOCENTER, dev->ffbit)) dev->ff->set_autocenter = hid_lg3ff_set_autocenter; - dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by " - "Gary Stein \n"); + hid_info(hid, "Force feedback for Logitech Flight System G940 by Gary Stein \n"); return 0; } diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 7eef5a2ce948..fa550c8e1d1b 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -101,20 +101,20 @@ int lg4ff_init(struct hid_device *hid) /* Find the report to use */ if (list_empty(report_list)) { - err_hid("No output report found"); + hid_err(hid, "No output report found\n"); return -1; } /* Check that the report looks ok */ report = list_entry(report_list->next, struct hid_report, list); if (!report) { - err_hid("NULL output report"); + hid_err(hid, "NULL output report\n"); return -1; } field = report->field[0]; if (!field) { - err_hid("NULL field"); + hid_err(hid, "NULL field\n"); return -1; } @@ -129,8 +129,7 @@ int lg4ff_init(struct hid_device *hid) if (test_bit(FF_AUTOCENTER, dev->ffbit)) dev->ff->set_autocenter = hid_lg4ff_set_autocenter; - dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by " - "Simon Wood \n"); + hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood \n"); return 0; } diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 61142b76a9b1..90d0ef2c92be 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -27,6 +27,8 @@ * e-mail - mail your message to */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -146,7 +148,7 @@ int lgff_init(struct hid_device* hid) /* Find the report to use */ if (list_empty(report_list)) { - err_hid("No output report found"); + hid_err(hid, "No output report found\n"); return -1; } @@ -154,7 +156,7 @@ int lgff_init(struct hid_device* hid) report = list_entry(report_list->next, struct hid_report, list); field = report->field[0]; if (!field) { - err_hid("NULL field"); + hid_err(hid, "NULL field\n"); return -1; } @@ -176,7 +178,7 @@ int lgff_init(struct hid_device* hid) if ( test_bit(FF_AUTOCENTER, dev->ffbit) ) dev->ff->set_autocenter = hid_lgff_set_autocenter; - printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux \n"); + pr_info("Force feedback for Logitech force feedback devices by Johann Deneux \n"); return 0; } diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index e6dc15171664..11306b3d9c56 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -12,6 +12,8 @@ * any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -446,7 +448,7 @@ static int magicmouse_probe(struct hid_device *hdev, msc = kzalloc(sizeof(*msc), GFP_KERNEL); if (msc == NULL) { - dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n"); + hid_err(hdev, "can't alloc magicmouse descriptor\n"); return -ENOMEM; } @@ -459,13 +461,13 @@ static int magicmouse_probe(struct hid_device *hdev, ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "magicmouse hid parse failed\n"); + hid_err(hdev, "magicmouse hid parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "magicmouse hw start failed\n"); + hid_err(hdev, "magicmouse hw start failed\n"); goto err_free; } @@ -486,7 +488,7 @@ static int magicmouse_probe(struct hid_device *hdev, } if (!report) { - dev_err(&hdev->dev, "unable to register touch report\n"); + hid_err(hdev, "unable to register touch report\n"); ret = -ENOMEM; goto err_stop_hw; } @@ -495,8 +497,7 @@ static int magicmouse_probe(struct hid_device *hdev, ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), HID_FEATURE_REPORT); if (ret != sizeof(feature)) { - dev_err(&hdev->dev, "unable to request touch data (%d)\n", - ret); + hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } @@ -540,7 +541,7 @@ static int __init magicmouse_init(void) ret = hid_register_driver(&magicmouse_driver); if (ret) - printk(KERN_ERR "can't register magicmouse driver\n"); + pr_err("can't register magicmouse driver\n"); return ret; } diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index dc618c33d0a2..0f6fc54dc196 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -40,8 +40,7 @@ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { - dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver " - "Model 1028 report descriptor\n"); + hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); rdesc[557] = 0x35; rdesc[559] = 0x45; } @@ -155,14 +154,14 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ? HID_CONNECT_HIDINPUT_FORCE : 0)); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index c95c31e2d869..dedf757781ae 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c @@ -26,8 +26,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { - dev_info(&hdev->dev, "fixing up button/consumer in HID report " - "descriptor\n"); + hid_info(hdev, "fixing up button/consumer in HID report descriptor\n"); rdesc[30] = 0x0c; } return rdesc; diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index ac5421d568f1..0668685380d5 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -199,7 +199,7 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL); if (!td) { - dev_err(&hdev->dev, "cannot allocate MosArt data\n"); + hid_err(hdev, "cannot allocate MosArt data\n"); return -ENOMEM; } td->valid = false; diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 69169efa1e16..beb403421e72 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -130,8 +130,7 @@ static void ntrig_report_version(struct hid_device *hdev) if (ret == 8) { ret = ntrig_version_string(&data[2], buf); - dev_info(&hdev->dev, - "Firmware version: %s (%02x%02x %02x%02x)\n", + hid_info(hdev, "Firmware version: %s (%02x%02x %02x%02x)\n", buf, data[2], data[3], data[4], data[5]); } @@ -831,7 +830,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL); if (!nd) { - dev_err(&hdev->dev, "cannot allocate N-Trig data\n"); + hid_err(hdev, "cannot allocate N-Trig data\n"); return -ENOMEM; } @@ -850,13 +849,13 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c index 2e79716dca31..e90edfc63051 100644 --- a/drivers/hid/hid-ortek.c +++ b/drivers/hid/hid-ortek.c @@ -23,8 +23,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) { - dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 " - "report descriptor.\n"); + hid_info(hdev, "Fixing up Ortek WKB-2000 report descriptor\n"); rdesc[55] = 0x92; } return rdesc; diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index 308d6ae48a3e..f1ea3ff8a98d 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c @@ -29,8 +29,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && rdesc[41] == 0x00 && rdesc[59] == 0x26 && rdesc[60] == 0xf9 && rdesc[61] == 0x00) { - dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report " - "descriptor\n"); + hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n"); rdesc[60] = 0xfa; rdesc[40] = 0xfa; } @@ -77,13 +76,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 38565fee7bf1..e4ce47156106 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -253,7 +253,7 @@ static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int di if (report->id == id) return report; } - dev_warn(&hdev->dev, "No report with id 0x%x found\n", id); + hid_warn(hdev, "No report with id 0x%x found\n", id); return NULL; } @@ -1329,7 +1329,7 @@ static int picolcd_check_version(struct hid_device *hdev) verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0); if (!verinfo) { - dev_err(&hdev->dev, "no version response from PicoLCD"); + hid_err(hdev, "no version response from PicoLCD\n"); return -ENODEV; } @@ -1337,14 +1337,14 @@ static int picolcd_check_version(struct hid_device *hdev) data->version[0] = verinfo->raw_data[1]; data->version[1] = verinfo->raw_data[0]; if (data->status & PICOLCD_BOOTLOADER) { - dev_info(&hdev->dev, "PicoLCD, bootloader version %d.%d\n", - verinfo->raw_data[1], verinfo->raw_data[0]); + hid_info(hdev, "PicoLCD, bootloader version %d.%d\n", + verinfo->raw_data[1], verinfo->raw_data[0]); } else { - dev_info(&hdev->dev, "PicoLCD, firmware version %d.%d\n", - verinfo->raw_data[1], verinfo->raw_data[0]); + hid_info(hdev, "PicoLCD, firmware version %d.%d\n", + verinfo->raw_data[1], verinfo->raw_data[0]); } } else { - dev_err(&hdev->dev, "confused, got unexpected version response from PicoLCD\n"); + hid_err(hdev, "confused, got unexpected version response from PicoLCD\n"); ret = -EINVAL; } kfree(verinfo); @@ -2328,8 +2328,7 @@ static void picolcd_init_devfs(struct picolcd_data *data, (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0), hdev->debug_dir, data, &picolcd_debug_flash_fops); } else if (flash_r || flash_w) - dev_warn(&hdev->dev, "Unexpected FLASH access reports, " - "please submit rdesc for review\n"); + hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n"); } static void picolcd_exit_devfs(struct picolcd_data *data) @@ -2457,13 +2456,13 @@ static int picolcd_init_keys(struct picolcd_data *data, return -ENODEV; if (report->maxfield != 1 || report->field[0]->report_count != 2 || report->field[0]->report_size != 8) { - dev_err(&hdev->dev, "unsupported KEY_STATE report"); + hid_err(hdev, "unsupported KEY_STATE report\n"); return -EINVAL; } idev = input_allocate_device(); if (idev == NULL) { - dev_err(&hdev->dev, "failed to allocate input device"); + hid_err(hdev, "failed to allocate input device\n"); return -ENOMEM; } input_set_drvdata(idev, hdev); @@ -2485,7 +2484,7 @@ static int picolcd_init_keys(struct picolcd_data *data, input_set_capability(idev, EV_KEY, data->keycode[i]); error = input_register_device(idev); if (error) { - dev_err(&hdev->dev, "error registering the input device"); + hid_err(hdev, "error registering the input device\n"); input_free_device(idev); return error; } @@ -2522,9 +2521,8 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) return error; if (data->version[0] != 0 && data->version[1] != 3) - dev_info(&hdev->dev, "Device with untested firmware revision, " - "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", - dev_name(&hdev->dev)); + hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", + dev_name(&hdev->dev)); /* Setup keypad input device */ error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev)); @@ -2581,9 +2579,8 @@ static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data return error; if (data->version[0] != 1 && data->version[1] != 0) - dev_info(&hdev->dev, "Device with untested bootloader revision, " - "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", - dev_name(&hdev->dev)); + hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", + dev_name(&hdev->dev)); picolcd_init_devfs(data, NULL, NULL, picolcd_out_report(REPORT_BL_READ_MEMORY, hdev), @@ -2605,7 +2602,7 @@ static int picolcd_probe(struct hid_device *hdev, */ data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); if (data == NULL) { - dev_err(&hdev->dev, "can't allocate space for Minibox PicoLCD device data\n"); + hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n"); error = -ENOMEM; goto err_no_cleanup; } @@ -2621,7 +2618,7 @@ static int picolcd_probe(struct hid_device *hdev, /* Parse the device reports and start it up */ error = hid_parse(hdev); if (error) { - dev_err(&hdev->dev, "device report parse failed\n"); + hid_err(hdev, "device report parse failed\n"); goto err_cleanup_data; } @@ -2631,25 +2628,25 @@ static int picolcd_probe(struct hid_device *hdev, error = hid_hw_start(hdev, 0); hdev->claimed = 0; if (error) { - dev_err(&hdev->dev, "hardware start failed\n"); + hid_err(hdev, "hardware start failed\n"); goto err_cleanup_data; } error = hid_hw_open(hdev); if (error) { - dev_err(&hdev->dev, "failed to open input interrupt pipe for key and IR events\n"); + hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n"); goto err_cleanup_hid_hw; } error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); if (error) { - dev_err(&hdev->dev, "failed to create sysfs attributes\n"); + hid_err(hdev, "failed to create sysfs attributes\n"); goto err_cleanup_hid_ll; } error = device_create_file(&hdev->dev, &dev_attr_operation_mode); if (error) { - dev_err(&hdev->dev, "failed to create sysfs attributes\n"); + hid_err(hdev, "failed to create sysfs attributes\n"); goto err_cleanup_sysfs1; } diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 9f41e2bd8483..06e5300d43d2 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -103,7 +103,7 @@ static int plff_init(struct hid_device *hid) */ if (list_empty(report_list)) { - dev_err(&hid->dev, "no output reports found\n"); + hid_err(hid, "no output reports found\n"); return -ENODEV; } @@ -112,14 +112,13 @@ static int plff_init(struct hid_device *hid) report_ptr = report_ptr->next; if (report_ptr == report_list) { - dev_err(&hid->dev, "required output report is " - "missing\n"); + hid_err(hid, "required output report is missing\n"); return -ENODEV; } report = list_entry(report_ptr, struct hid_report, list); if (report->maxfield < 1) { - dev_err(&hid->dev, "no fields in the report\n"); + hid_err(hid, "no fields in the report\n"); return -ENODEV; } @@ -137,7 +136,7 @@ static int plff_init(struct hid_device *hid) weak = &report->field[3]->value[0]; debug("detected 4-field device"); } else { - dev_err(&hid->dev, "not enough fields or values\n"); + hid_err(hid, "not enough fields or values\n"); return -ENODEV; } @@ -164,8 +163,7 @@ static int plff_init(struct hid_device *hid) usbhid_submit_report(hid, plff->report, USB_DIR_OUT); } - dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia " - "devices by Anssi Hannula \n"); + hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula \n"); return 0; } @@ -185,13 +183,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index 5f0fa6c1bf87..ab19f2905d27 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -16,6 +16,8 @@ * any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -285,11 +287,11 @@ static int pcmidi_get_output_report(struct pcmidi_snd *pm) continue; if (report->maxfield < 1) { - dev_err(&hdev->dev, "output report is empty\n"); + hid_err(hdev, "output report is empty\n"); break; } if (report->field[0]->report_count != 2) { - dev_err(&hdev->dev, "field count too low\n"); + hid_err(hdev, "field count too low\n"); break; } pm->pcmidi_report6 = report; @@ -746,8 +748,8 @@ static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (*rsize == 178 && rdesc[111] == 0x06 && rdesc[112] == 0x00 && rdesc[113] == 0xff) { - dev_info(&hdev->dev, "fixing up pc-midi keyboard report " - "descriptor\n"); + hid_info(hdev, + "fixing up pc-midi keyboard report descriptor\n"); rdesc[144] = 0x18; /* report 4: was 0x10 report count */ } @@ -805,7 +807,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) pk = kzalloc(sizeof(*pk), GFP_KERNEL); if (pk == NULL) { - dev_err(&hdev->dev, "prodikeys: can't alloc descriptor\n"); + hid_err(hdev, "can't alloc descriptor\n"); return -ENOMEM; } @@ -813,8 +815,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) pm = kzalloc(sizeof(*pm), GFP_KERNEL); if (pm == NULL) { - dev_err(&hdev->dev, - "prodikeys: can't alloc descriptor\n"); + hid_err(hdev, "can't alloc descriptor\n"); ret = -ENOMEM; goto err_free; } @@ -827,7 +828,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "prodikeys: hid parse failed\n"); + hid_err(hdev, "hid parse failed\n"); goto err_free; } @@ -837,7 +838,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "prodikeys: hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } @@ -896,7 +897,7 @@ static int pk_init(void) ret = hid_register_driver(&pk_driver); if (ret) - printk(KERN_ERR "can't register prodikeys driver\n"); + pr_err("can't register prodikeys driver\n"); return ret; } diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c index 54d3db50605b..87a54df4d4ac 100644 --- a/drivers/hid/hid-quanta.c +++ b/drivers/hid/hid-quanta.c @@ -195,7 +195,7 @@ static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id) td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL); if (!td) { - dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n"); + hid_err(hdev, "cannot allocate Quanta Touch data\n"); return -ENOMEM; } td->valid = false; diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index f77695762cb5..73199de2e37f 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -90,8 +90,7 @@ static int kone_check_write(struct usb_device *usb_dev) kfree(data); return 0; } else { /* unknown answer */ - dev_err(&usb_dev->dev, "got retval %d when checking write\n", - *data); + hid_err(usb_dev, "got retval %d when checking write\n", *data); kfree(data); return -EIO; } @@ -556,7 +555,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev, retval = kone_set_settings(usb_dev, &kone->settings); if (retval) { - dev_err(&usb_dev->dev, "couldn't set tcu state\n"); + hid_err(usb_dev, "couldn't set tcu state\n"); /* * try to reread valid settings into buffer overwriting * first error code @@ -570,7 +569,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev, retval = size; exit_no_settings: - dev_err(&usb_dev->dev, "couldn't read settings\n"); + hid_err(usb_dev, "couldn't read settings\n"); exit_unlock: mutex_unlock(&kone->kone_lock); return retval; @@ -818,21 +817,20 @@ static int kone_init_specials(struct hid_device *hdev) kone = kzalloc(sizeof(*kone), GFP_KERNEL); if (!kone) { - dev_err(&hdev->dev, "can't alloc device descriptor\n"); + hid_err(hdev, "can't alloc device descriptor\n"); return -ENOMEM; } hid_set_drvdata(hdev, kone); retval = kone_init_kone_device_struct(usb_dev, kone); if (retval) { - dev_err(&hdev->dev, - "couldn't init struct kone_device\n"); + hid_err(hdev, "couldn't init struct kone_device\n"); goto exit_free; } retval = roccat_connect(hdev); if (retval < 0) { - dev_err(&hdev->dev, "couldn't init char dev\n"); + hid_err(hdev, "couldn't init char dev\n"); /* be tolerant about not getting chrdev */ } else { kone->roccat_claimed = 1; @@ -841,7 +839,7 @@ static int kone_init_specials(struct hid_device *hdev) retval = kone_create_sysfs_attributes(intf); if (retval) { - dev_err(&hdev->dev, "cannot create sysfs files\n"); + hid_err(hdev, "cannot create sysfs files\n"); goto exit_free; } } else { @@ -876,19 +874,19 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id) retval = hid_parse(hdev); if (retval) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto exit; } retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (retval) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto exit; } retval = kone_init_specials(hdev); if (retval) { - dev_err(&hdev->dev, "couldn't install mouse\n"); + hid_err(hdev, "couldn't install mouse\n"); goto exit_stop; } diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 9bf23047892a..e7b4affe2664 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -87,9 +87,8 @@ static int pyra_receive_control_status(struct usb_device *usb_dev) control.value == 1) return 0; else { - dev_err(&usb_dev->dev, "receive control status: " - "unknown response 0x%x 0x%x\n", - control.request, control.value); + hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n", + control.request, control.value); return -EINVAL; } } @@ -770,21 +769,20 @@ static int pyra_init_specials(struct hid_device *hdev) pyra = kzalloc(sizeof(*pyra), GFP_KERNEL); if (!pyra) { - dev_err(&hdev->dev, "can't alloc device descriptor\n"); + hid_err(hdev, "can't alloc device descriptor\n"); return -ENOMEM; } hid_set_drvdata(hdev, pyra); retval = pyra_init_pyra_device_struct(usb_dev, pyra); if (retval) { - dev_err(&hdev->dev, - "couldn't init struct pyra_device\n"); + hid_err(hdev, "couldn't init struct pyra_device\n"); goto exit_free; } retval = roccat_connect(hdev); if (retval < 0) { - dev_err(&hdev->dev, "couldn't init char dev\n"); + hid_err(hdev, "couldn't init char dev\n"); } else { pyra->chrdev_minor = retval; pyra->roccat_claimed = 1; @@ -792,7 +790,7 @@ static int pyra_init_specials(struct hid_device *hdev) retval = pyra_create_sysfs_attributes(intf); if (retval) { - dev_err(&hdev->dev, "cannot create sysfs files\n"); + hid_err(hdev, "cannot create sysfs files\n"); goto exit_free; } } else { @@ -826,19 +824,19 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id) retval = hid_parse(hdev); if (retval) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto exit; } retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (retval) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto exit; } retval = pyra_init_specials(hdev); if (retval) { - dev_err(&hdev->dev, "couldn't install mouse\n"); + hid_err(hdev, "couldn't install mouse\n"); goto exit_stop; } return 0; diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index a9d9b29ff47f..4bc7a93dc1f5 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -21,6 +21,8 @@ * It is inspired by hidraw, but uses only one circular buffer for all readers. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -165,8 +167,7 @@ static int roccat_open(struct inode *inode, struct file *file) mutex_lock(&device->readers_lock); if (!device) { - printk(KERN_EMERG "roccat device with minor %d doesn't exist\n", - minor); + pr_emerg("roccat device with minor %d doesn't exist\n", minor); error = -ENODEV; goto exit_err; } @@ -214,8 +215,7 @@ static int roccat_release(struct inode *inode, struct file *file) device = devices[minor]; if (!device) { mutex_unlock(&devices_lock); - printk(KERN_EMERG "roccat device with minor %d doesn't exist\n", - minor); + pr_emerg("roccat device with minor %d doesn't exist\n", minor); return -ENODEV; } @@ -392,7 +392,7 @@ static int __init roccat_init(void) roccat_major = MAJOR(dev_id); if (retval < 0) { - printk(KERN_WARNING "roccat: can't get major number\n"); + pr_warn("can't get major number\n"); return retval; } diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 35894444e000..3c1fd8af5e0c 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c @@ -57,8 +57,8 @@ static inline void samsung_irda_dev_trace(struct hid_device *hdev, unsigned int rsize) { - dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report " - "descriptor\n", rsize); + hid_info(hdev, "fixing up Samsung IrDA %d byte report descriptor\n", + rsize); } static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -160,7 +160,7 @@ static int samsung_probe(struct hid_device *hdev, ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } @@ -174,7 +174,7 @@ static int samsung_probe(struct hid_device *hdev, ret = hid_hw_start(hdev, cmask); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c index e10a7687ebf2..16f7cafc9695 100644 --- a/drivers/hid/hid-sjoy.c +++ b/drivers/hid/hid-sjoy.c @@ -74,26 +74,25 @@ static int sjoyff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output reports found\n"); + hid_err(hid, "no output reports found\n"); return -ENODEV; } report_ptr = report_ptr->next; if (report_ptr == report_list) { - dev_err(&hid->dev, "required output report is " - "missing\n"); + hid_err(hid, "required output report is missing\n"); return -ENODEV; } report = list_entry(report_ptr, struct hid_report, list); if (report->maxfield < 1) { - dev_err(&hid->dev, "no fields in the report\n"); + hid_err(hid, "no fields in the report\n"); return -ENODEV; } if (report->field[0]->report_count < 3) { - dev_err(&hid->dev, "not enough values in the field\n"); + hid_err(hid, "not enough values in the field\n"); return -ENODEV; } @@ -117,8 +116,7 @@ static int sjoyff_init(struct hid_device *hid) sjoyff->report->field[0]->value[2] = 0x00; usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT); - dev_info(&hid->dev, - "Force feedback for SmartJoy PLUS PS2/USB adapter\n"); + hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n"); return 0; } @@ -135,13 +133,13 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 677bb3da10e8..68d7b36e31e4 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -40,8 +40,7 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, if ((sc->quirks & VAIO_RDESC_CONSTANT) && *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { - dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report " - "descriptor\n"); + hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n"); rdesc[55] = 0x06; } return rdesc; @@ -89,7 +88,7 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) (3 << 8) | 0xf2, ifnum, buf, 17, USB_CTRL_GET_TIMEOUT); if (ret < 0) - dev_err(&hdev->dev, "can't set operational mode\n"); + hid_err(hdev, "can't set operational mode\n"); kfree(buf); @@ -110,7 +109,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) sc = kzalloc(sizeof(*sc), GFP_KERNEL); if (sc == NULL) { - dev_err(&hdev->dev, "can't alloc sony descriptor\n"); + hid_err(hdev, "can't alloc sony descriptor\n"); return -ENOMEM; } @@ -119,14 +118,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c index 3171be28c3d5..b2be1d11916b 100644 --- a/drivers/hid/hid-stantum.c +++ b/drivers/hid/hid-stantum.c @@ -222,7 +222,7 @@ static int stantum_probe(struct hid_device *hdev, sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL); if (!sd) { - dev_err(&hdev->dev, "cannot allocate Stantum data\n"); + hid_err(hdev, "cannot allocate Stantum data\n"); return -ENOMEM; } sd->valid = false; diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index 164ed568f6cf..d484a0043dd4 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c @@ -27,8 +27,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, { if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && rdesc[106] == 0x03) { - dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop " - "report descriptor\n"); + hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n"); rdesc[105] = rdesc[110] = 0x03; rdesc[106] = rdesc[111] = 0x21; } diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 15434c814793..356a98fcb365 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -151,28 +151,23 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits) switch (field->usage[0].hid) { case THRUSTMASTER_USAGE_FF: if (field->report_count < 2) { - dev_warn(&hid->dev, "ignoring FF field " - "with report_count < 2\n"); + hid_warn(hid, "ignoring FF field with report_count < 2\n"); continue; } if (field->logical_maximum == field->logical_minimum) { - dev_warn(&hid->dev, "ignoring FF field " - "with logical_maximum " - "== logical_minimum\n"); + hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n"); continue; } if (tmff->report && tmff->report != report) { - dev_warn(&hid->dev, "ignoring FF field " - "in other report\n"); + hid_warn(hid, "ignoring FF field in other report\n"); continue; } if (tmff->ff_field && tmff->ff_field != field) { - dev_warn(&hid->dev, "ignoring " - "duplicate FF field\n"); + hid_warn(hid, "ignoring duplicate FF field\n"); continue; } @@ -185,16 +180,15 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits) break; default: - dev_warn(&hid->dev, "ignoring unknown output " - "usage %08x\n", - field->usage[0].hid); + hid_warn(hid, "ignoring unknown output usage %08x\n", + field->usage[0].hid); continue; } } } if (!tmff->report) { - dev_err(&hid->dev, "can't find FF field in output reports\n"); + hid_err(hid, "can't find FF field in output reports\n"); error = -ENODEV; goto fail; } @@ -203,8 +197,7 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits) if (error) goto fail; - dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx " - "Verituse "); + hid_info(hid, "force feedback for ThrustMaster devices by Zinx Verituse \n"); return 0; fail: @@ -224,13 +217,13 @@ static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 94caae731381..06888323828c 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -18,6 +18,8 @@ * any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -141,8 +143,8 @@ static void wacom_poke(struct hid_device *hdev, u8 speed) * Note that if the raw queries fail, it's not a hard failure and it * is safe to continue */ - dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n", - rep_data[0], ret); + hid_warn(hdev, "failed to poke device, command %d, err %d\n", + rep_data[0], ret); return; } @@ -312,7 +314,7 @@ static int wacom_probe(struct hid_device *hdev, wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); if (wdata == NULL) { - dev_err(&hdev->dev, "can't alloc wacom descriptor\n"); + hid_err(hdev, "can't alloc wacom descriptor\n"); return -ENOMEM; } @@ -321,20 +323,20 @@ static int wacom_probe(struct hid_device *hdev, /* Parse the HID report now */ ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } ret = device_create_file(&hdev->dev, &dev_attr_speed); if (ret) - dev_warn(&hdev->dev, - "can't create sysfs speed attribute err: %d\n", ret); + hid_warn(hdev, + "can't create sysfs speed attribute err: %d\n", ret); /* Set Wacom mode 2 with high reporting speed */ wacom_poke(hdev, 1); @@ -349,8 +351,8 @@ static int wacom_probe(struct hid_device *hdev, ret = power_supply_register(&hdev->dev, &wdata->battery); if (ret) { - dev_warn(&hdev->dev, - "can't create sysfs battery attribute, err: %d\n", ret); + hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n", + ret); /* * battery attribute is not critical for the tablet, but if it * failed then there is no need to create ac attribute @@ -367,8 +369,8 @@ static int wacom_probe(struct hid_device *hdev, ret = power_supply_register(&hdev->dev, &wdata->ac); if (ret) { - dev_warn(&hdev->dev, - "can't create ac battery attribute, err: %d\n", ret); + hid_warn(hdev, + "can't create ac battery attribute, err: %d\n", ret); /* * ac attribute is not critical for the tablet, but if it * failed then we don't want to battery attribute to exist @@ -454,7 +456,7 @@ static int __init wacom_init(void) ret = hid_register_driver(&wacom_driver); if (ret) - printk(KERN_ERR "can't register wacom driver\n"); + pr_err("can't register wacom driver\n"); return ret; } diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index b7acceabba80..f31fab012f2f 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -75,14 +75,14 @@ static int zpff_init(struct hid_device *hid) int error; if (list_empty(report_list)) { - dev_err(&hid->dev, "no output report found\n"); + hid_err(hid, "no output report found\n"); return -ENODEV; } report = list_entry(report_list->next, struct hid_report, list); if (report->maxfield < 4) { - dev_err(&hid->dev, "not enough fields in report\n"); + hid_err(hid, "not enough fields in report\n"); return -ENODEV; } @@ -105,8 +105,7 @@ static int zpff_init(struct hid_device *hid) zpff->report->field[3]->value[0] = 0x00; usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); - dev_info(&hid->dev, "force feedback for Zeroplus based devices by " - "Anssi Hannula \n"); + hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula \n"); return 0; } @@ -123,13 +122,13 @@ static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); if (ret) { - dev_err(&hdev->dev, "hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err; } diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c index aac1f9273149..e90371508fd2 100644 --- a/drivers/hid/hid-zydacron.c +++ b/drivers/hid/hid-zydacron.c @@ -34,9 +34,8 @@ static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff && rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff && rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) { - dev_info(&hdev->dev, - "fixing up zydacron remote control report " - "descriptor\n"); + hid_info(hdev, + "fixing up zydacron remote control report descriptor\n"); rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c; rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00; } @@ -172,7 +171,7 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id) zc = kzalloc(sizeof(*zc), GFP_KERNEL); if (zc == NULL) { - dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n"); + hid_err(hdev, "can't alloc descriptor\n"); return -ENOMEM; } @@ -180,13 +179,13 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = hid_parse(hdev); if (ret) { - dev_err(&hdev->dev, "zydacron: parse failed\n"); + hid_err(hdev, "parse failed\n"); goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { - dev_err(&hdev->dev, "zydacron: hw start failed\n"); + hid_err(hdev, "hw start failed\n"); goto err_free; } diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 5aefe73cf795..eb16cd143e2a 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -19,6 +19,8 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -123,15 +125,15 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t } if (count > HID_MAX_BUFFER_SIZE) { - printk(KERN_WARNING "hidraw: pid %d passed too large report\n", - task_pid_nr(current)); + hid_warn(dev, "pid %d passed too large report\n", + task_pid_nr(current)); ret = -EINVAL; goto out; } if (count < 2) { - printk(KERN_WARNING "hidraw: pid %d passed too short report\n", - task_pid_nr(current)); + hid_warn(dev, "pid %d passed too short report\n", + task_pid_nr(current)); ret = -EINVAL; goto out; } @@ -450,7 +452,7 @@ int __init hidraw_init(void) hidraw_major = MAJOR(dev_id); if (result < 0) { - printk(KERN_WARNING "hidraw: can't get major number\n"); + pr_warn("can't get major number\n"); result = 0; goto out; } diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 5489eab3a6bd..276758f53ab5 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -136,10 +136,10 @@ static void hid_reset(struct work_struct *work) hid_io_error(hid); break; default: - err_hid("can't reset device, %s-%s/input%d, status %d", - hid_to_usb_dev(hid)->bus->bus_name, - hid_to_usb_dev(hid)->devpath, - usbhid->ifnum, rc); + hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n", + hid_to_usb_dev(hid)->bus->bus_name, + hid_to_usb_dev(hid)->devpath, + usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: case -ENODEV: @@ -278,18 +278,18 @@ static void hid_irq_in(struct urb *urb) hid_io_error(hid); return; default: /* error */ - dev_warn(&urb->dev->dev, "input irq status %d " - "received\n", urb->status); + hid_warn(urb->dev, "input irq status %d received\n", + urb->status); } status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { - err_hid("can't resubmit intr, %s-%s/input%d, status %d", - hid_to_usb_dev(hid)->bus->bus_name, - hid_to_usb_dev(hid)->devpath, - usbhid->ifnum, status); + hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n", + hid_to_usb_dev(hid)->bus->bus_name, + hid_to_usb_dev(hid)->devpath, + usbhid->ifnum, status); hid_io_error(hid); } } @@ -313,7 +313,7 @@ static int hid_submit_out(struct hid_device *hid) dbg_hid("submitting out urb\n"); if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { - err_hid("usb_submit_urb(out) failed"); + hid_err(hid, "usb_submit_urb(out) failed\n"); return -1; } usbhid->last_out = jiffies; @@ -375,7 +375,7 @@ static int hid_submit_ctrl(struct hid_device *hid) usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { - err_hid("usb_submit_urb(ctrl) failed"); + hid_err(hid, "usb_submit_urb(ctrl) failed\n"); return -1; } usbhid->last_ctrl = jiffies; @@ -413,8 +413,8 @@ static void hid_irq_out(struct urb *urb) case -ENOENT: break; default: /* error */ - dev_warn(&urb->dev->dev, "output irq status %d " - "received\n", urb->status); + hid_warn(urb->dev, "output irq status %d received\n", + urb->status); } spin_lock_irqsave(&usbhid->lock, flags); @@ -466,8 +466,7 @@ static void hid_ctrl(struct urb *urb) case -EPIPE: /* report not available */ break; default: /* error */ - dev_warn(&urb->dev->dev, "ctrl urb status %d " - "received\n", status); + hid_warn(urb->dev, "ctrl urb status %d received\n", status); } if (unplug) @@ -501,13 +500,13 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { - dev_warn(&hid->dev, "output queue full\n"); + hid_warn(hid, "output queue full\n"); return; } usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC); if (!usbhid->out[usbhid->outhead].raw_report) { - dev_warn(&hid->dev, "output queueing failed\n"); + hid_warn(hid, "output queueing failed\n"); return; } hid_output_report(report, usbhid->out[usbhid->outhead].raw_report); @@ -532,14 +531,14 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re } if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { - dev_warn(&hid->dev, "control queue full\n"); + hid_warn(hid, "control queue full\n"); return; } if (dir == USB_DIR_OUT) { usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC); if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) { - dev_warn(&hid->dev, "control queueing failed\n"); + hid_warn(hid, "control queueing failed\n"); return; } hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report); @@ -590,7 +589,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un return -1; if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { - dev_warn(&dev->dev, "event field not found\n"); + hid_warn(dev, "event field not found\n"); return -1; } @@ -722,7 +721,7 @@ void usbhid_init_reports(struct hid_device *hid) } if (err) - dev_warn(&hid->dev, "timeout initializing reports\n"); + hid_warn(hid, "timeout initializing reports\n"); } /* @@ -1140,8 +1139,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * if (usb_endpoint_is_int_in(&interface->endpoint[n].desc)) has_in++; if (!has_in) { - dev_err(&intf->dev, "couldn't find an input interrupt " - "endpoint\n"); + hid_err(intf, "couldn't find an input interrupt endpoint\n"); return -ENODEV; } @@ -1213,7 +1211,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * ret = hid_add_device(hid); if (ret) { if (ret != -ENODEV) - dev_err(&intf->dev, "can't add hid device: %d\n", ret); + hid_err(intf, "can't add hid device: %d\n", ret); goto err_free; } diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index ef381d79cfa8..f91c136821f7 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -22,7 +22,7 @@ /* #define DEBUG */ -#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg) +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -220,7 +220,7 @@ static int pidff_rescale_signed(int i, struct hid_field *field) static void pidff_set(struct pidff_usage *usage, u16 value) { usage->value[0] = pidff_rescale(value, 0xffff, usage->field); - debug("calculated from %d to %d", value, usage->value[0]); + pr_debug("calculated from %d to %d\n", value, usage->value[0]); } static void pidff_set_signed(struct pidff_usage *usage, s16 value) @@ -235,7 +235,7 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value) usage->value[0] = pidff_rescale(value, 0x7fff, usage->field); } - debug("calculated from %d to %d", value, usage->value[0]); + pr_debug("calculated from %d to %d\n", value, usage->value[0]); } /* @@ -259,8 +259,9 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length; pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length; - debug("attack %u => %d", envelope->attack_level, - pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); + hid_dbg(pidff->hid, "attack %u => %d\n", + envelope->attack_level, + pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], USB_DIR_OUT); @@ -466,33 +467,33 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) pidff->create_new_effect_type->value[0] = efnum; usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], USB_DIR_OUT); - debug("create_new_effect sent, type: %d", efnum); + hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum); pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; pidff->block_load_status->value[0] = 0; usbhid_wait_io(pidff->hid); for (j = 0; j < 60; j++) { - debug("pid_block_load requested"); + hid_dbg(pidff->hid, "pid_block_load requested\n"); usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], USB_DIR_IN); usbhid_wait_io(pidff->hid); if (pidff->block_load_status->value[0] == pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { - debug("device reported free memory: %d bytes", - pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? - pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); + hid_dbg(pidff->hid, "device reported free memory: %d bytes\n", + pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? + pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); return 0; } if (pidff->block_load_status->value[0] == pidff->status_id[PID_BLOCK_LOAD_FULL]) { - debug("not enough memory free: %d bytes", - pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? + hid_dbg(pidff->hid, "not enough memory free: %d bytes\n", + pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); return -ENOSPC; } } - printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n"); + hid_err(pidff->hid, "pid_block_load failed 60 times\n"); return -EIO; } @@ -546,7 +547,8 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id) struct pidff_device *pidff = dev->ff->private; int pid_id = pidff->pid_id[effect_id]; - debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]); + hid_dbg(pidff->hid, "starting to erase %d/%d\n", + effect_id, pidff->pid_id[effect_id]); /* Wait for the queue to clear. We do not want a full fifo to prevent the effect removal. */ usbhid_wait_io(pidff->hid); @@ -604,8 +606,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, type_id = PID_SAW_DOWN; break; default: - printk(KERN_ERR - "hid-pidff: invalid waveform\n"); + hid_err(pidff->hid, "invalid waveform\n"); return -EINVAL; } @@ -696,7 +697,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, break; default: - printk(KERN_ERR "hid-pidff: invalid type\n"); + hid_err(pidff->hid, "invalid type\n"); return -EINVAL; } @@ -704,7 +705,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, pidff->pid_id[effect->id] = pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; - debug("uploaded"); + hid_dbg(pidff->hid, "uploaded\n"); return 0; } @@ -770,14 +771,14 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, for (i = 0; i < report->maxfield; i++) { if (report->field[i]->maxusage != report->field[i]->report_count) { - debug("maxusage and report_count do not match, " - "skipping"); + pr_debug("maxusage and report_count do not match, skipping\n"); continue; } for (j = 0; j < report->field[i]->maxusage; j++) { if (report->field[i]->usage[j].hid == (HID_UP_PID | table[k])) { - debug("found %d at %d->%d", k, i, j); + pr_debug("found %d at %d->%d\n", + k, i, j); usage[k].field = report->field[i]; usage[k].value = &report->field[i]->value[j]; @@ -789,7 +790,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, break; } if (!found && strict) { - debug("failed to locate %d", k); + pr_debug("failed to locate %d\n", k); return -1; } } @@ -826,8 +827,8 @@ static void pidff_find_reports(struct hid_device *hid, int report_type, continue; ret = pidff_check_usage(report->field[0]->logical); if (ret != -1) { - debug("found usage 0x%02x from field->logical", - pidff_reports[ret]); + hid_dbg(hid, "found usage 0x%02x from field->logical\n", + pidff_reports[ret]); pidff->reports[ret] = report; continue; } @@ -845,8 +846,9 @@ static void pidff_find_reports(struct hid_device *hid, int report_type, continue; ret = pidff_check_usage(hid->collection[i - 1].usage); if (ret != -1 && !pidff->reports[ret]) { - debug("found usage 0x%02x from collection array", - pidff_reports[ret]); + hid_dbg(hid, + "found usage 0x%02x from collection array\n", + pidff_reports[ret]); pidff->reports[ret] = report; } } @@ -861,7 +863,7 @@ static int pidff_reports_ok(struct pidff_device *pidff) for (i = 0; i <= PID_REQUIRED_REPORTS; i++) { if (!pidff->reports[i]) { - debug("%d missing", i); + hid_dbg(pidff->hid, "%d missing\n", i); return 0; } } @@ -884,8 +886,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report, report->field[i]->logical_minimum == 1) return report->field[i]; else { - printk(KERN_ERR "hid-pidff: logical_minimum " - "is not 1 as it should be\n"); + pr_err("logical_minimum is not 1 as it should be\n"); return NULL; } } @@ -924,7 +925,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld, */ static int pidff_find_special_fields(struct pidff_device *pidff) { - debug("finding special fields"); + hid_dbg(pidff->hid, "finding special fields\n"); pidff->create_new_effect_type = pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT], @@ -945,32 +946,30 @@ static int pidff_find_special_fields(struct pidff_device *pidff) pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION], 0x78, 1); - debug("search done"); + hid_dbg(pidff->hid, "search done\n"); if (!pidff->create_new_effect_type || !pidff->set_effect_type) { - printk(KERN_ERR "hid-pidff: effect lists not found\n"); + hid_err(pidff->hid, "effect lists not found\n"); return -1; } if (!pidff->effect_direction) { - printk(KERN_ERR "hid-pidff: direction field not found\n"); + hid_err(pidff->hid, "direction field not found\n"); return -1; } if (!pidff->device_control) { - printk(KERN_ERR "hid-pidff: device control field not found\n"); + hid_err(pidff->hid, "device control field not found\n"); return -1; } if (!pidff->block_load_status) { - printk(KERN_ERR - "hid-pidff: block load status field not found\n"); + hid_err(pidff->hid, "block load status field not found\n"); return -1; } if (!pidff->effect_operation_status) { - printk(KERN_ERR - "hid-pidff: effect operation field not found\n"); + hid_err(pidff->hid, "effect operation field not found\n"); return -1; } @@ -982,23 +981,22 @@ static int pidff_find_special_fields(struct pidff_device *pidff) if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type, effect_types)) { - printk(KERN_ERR "hid-pidff: no effect types found\n"); + hid_err(pidff->hid, "no effect types found\n"); return -1; } if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status, block_load_status) != sizeof(pidff_block_load_status)) { - printk(KERN_ERR - "hidpidff: block load status identifiers not found\n"); + hid_err(pidff->hid, + "block load status identifiers not found\n"); return -1; } if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status, effect_operation_status) != sizeof(pidff_effect_operation_status)) { - printk(KERN_ERR - "hidpidff: effect operation identifiers not found\n"); + hid_err(pidff->hid, "effect operation identifiers not found\n"); return -1; } @@ -1017,8 +1015,8 @@ static int pidff_find_effects(struct pidff_device *pidff, int pidff_type = pidff->type_id[i]; if (pidff->set_effect_type->usage[pidff_type].hid != pidff->create_new_effect_type->usage[pidff_type].hid) { - printk(KERN_ERR "hid-pidff: " - "effect type number %d is invalid\n", i); + hid_err(pidff->hid, + "effect type number %d is invalid\n", i); return -1; } } @@ -1073,27 +1071,23 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) int envelope_ok = 0; if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) { - printk(KERN_ERR - "hid-pidff: unknown set_effect report layout\n"); + hid_err(pidff->hid, "unknown set_effect report layout\n"); return -ENODEV; } PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0); if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) { - printk(KERN_ERR - "hid-pidff: unknown pid_block_load report layout\n"); + hid_err(pidff->hid, "unknown pid_block_load report layout\n"); return -ENODEV; } if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) { - printk(KERN_ERR - "hid-pidff: unknown effect_operation report layout\n"); + hid_err(pidff->hid, "unknown effect_operation report layout\n"); return -ENODEV; } if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) { - printk(KERN_ERR - "hid-pidff: unknown pid_block_free report layout\n"); + hid_err(pidff->hid, "unknown pid_block_free report layout\n"); return -ENODEV; } @@ -1105,27 +1099,26 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) if (!envelope_ok) { if (test_and_clear_bit(FF_CONSTANT, dev->ffbit)) - printk(KERN_WARNING "hid-pidff: " - "has constant effect but no envelope\n"); + hid_warn(pidff->hid, + "has constant effect but no envelope\n"); if (test_and_clear_bit(FF_RAMP, dev->ffbit)) - printk(KERN_WARNING "hid-pidff: " - "has ramp effect but no envelope\n"); + hid_warn(pidff->hid, + "has ramp effect but no envelope\n"); if (test_and_clear_bit(FF_PERIODIC, dev->ffbit)) - printk(KERN_WARNING "hid-pidff: " - "has periodic effect but no envelope\n"); + hid_warn(pidff->hid, + "has periodic effect but no envelope\n"); } if (test_bit(FF_CONSTANT, dev->ffbit) && PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) { - printk(KERN_WARNING - "hid-pidff: unknown constant effect layout\n"); + hid_warn(pidff->hid, "unknown constant effect layout\n"); clear_bit(FF_CONSTANT, dev->ffbit); } if (test_bit(FF_RAMP, dev->ffbit) && PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) { - printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n"); + hid_warn(pidff->hid, "unknown ramp effect layout\n"); clear_bit(FF_RAMP, dev->ffbit); } @@ -1134,8 +1127,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) test_bit(FF_FRICTION, dev->ffbit) || test_bit(FF_INERTIA, dev->ffbit)) && PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) { - printk(KERN_WARNING - "hid-pidff: unknown condition effect layout\n"); + hid_warn(pidff->hid, "unknown condition effect layout\n"); clear_bit(FF_SPRING, dev->ffbit); clear_bit(FF_DAMPER, dev->ffbit); clear_bit(FF_FRICTION, dev->ffbit); @@ -1144,8 +1136,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) if (test_bit(FF_PERIODIC, dev->ffbit) && PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) { - printk(KERN_WARNING - "hid-pidff: unknown periodic effect layout\n"); + hid_warn(pidff->hid, "unknown periodic effect layout\n"); clear_bit(FF_PERIODIC, dev->ffbit); } @@ -1184,12 +1175,12 @@ static void pidff_reset(struct pidff_device *pidff) if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { if (i++ > 20) { - printk(KERN_WARNING "hid-pidff: device reports " - "%d simultaneous effects\n", - pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); + hid_warn(pidff->hid, + "device reports %d simultaneous effects\n", + pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); break; } - debug("pid_pool requested again"); + hid_dbg(pidff->hid, "pid_pool requested again\n"); usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); usbhid_wait_io(hid); @@ -1215,7 +1206,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff, error = pidff_request_effect_upload(pidff, 1); if (error) { - printk(KERN_ERR "hid-pidff: upload request failed\n"); + hid_err(pidff->hid, "upload request failed\n"); return error; } @@ -1224,8 +1215,8 @@ static int pidff_check_autocenter(struct pidff_device *pidff, pidff_autocenter(pidff, 0xffff); set_bit(FF_AUTOCENTER, dev->ffbit); } else { - printk(KERN_NOTICE "hid-pidff: " - "device has unknown autocenter control method\n"); + hid_notice(pidff->hid, + "device has unknown autocenter control method\n"); } pidff_erase_pid(pidff, @@ -1248,10 +1239,10 @@ int hid_pidff_init(struct hid_device *hid) int max_effects; int error; - debug("starting pid init"); + hid_dbg(hid, "starting pid init\n"); if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) { - debug("not a PID device, no output report"); + hid_dbg(hid, "not a PID device, no output report\n"); return -ENODEV; } @@ -1265,7 +1256,7 @@ int hid_pidff_init(struct hid_device *hid) pidff_find_reports(hid, HID_FEATURE_REPORT, pidff); if (!pidff_reports_ok(pidff)) { - debug("reports not ok, aborting"); + hid_dbg(hid, "reports not ok, aborting\n"); error = -ENODEV; goto fail; } @@ -1278,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid) if (test_bit(FF_GAIN, dev->ffbit)) { pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); - usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], - USB_DIR_OUT); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN], + USB_DIR_OUT); } error = pidff_check_autocenter(pidff, dev); @@ -1290,23 +1281,23 @@ int hid_pidff_init(struct hid_device *hid) pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum - pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1; - debug("max effects is %d", max_effects); + hid_dbg(hid, "max effects is %d\n", max_effects); if (max_effects > PID_EFFECTS_MAX) max_effects = PID_EFFECTS_MAX; if (pidff->pool[PID_SIMULTANEOUS_MAX].value) - debug("max simultaneous effects is %d", - pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); + hid_dbg(hid, "max simultaneous effects is %d\n", + pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); if (pidff->pool[PID_RAM_POOL_SIZE].value) - debug("device memory size is %d bytes", - pidff->pool[PID_RAM_POOL_SIZE].value[0]); + hid_dbg(hid, "device memory size is %d bytes\n", + pidff->pool[PID_RAM_POOL_SIZE].value[0]); if (pidff->pool[PID_DEVICE_MANAGED_POOL].value && pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) { - printk(KERN_NOTICE "hid-pidff: " - "device does not support device managed pool\n"); + hid_notice(hid, + "device does not support device managed pool\n"); goto fail; } @@ -1322,8 +1313,7 @@ int hid_pidff_init(struct hid_device *hid) ff->set_autocenter = pidff_set_autocenter; ff->playback = pidff_playback; - printk(KERN_INFO "Force feedback for USB HID PID devices by " - "Anssi Hannula \n"); + hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula \n"); return 0; diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index a9935f6709f7..fb78f75d49a9 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -906,7 +906,7 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hiddev->exist = 1; retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { - err_hid("Not able to get a minor for this device."); + hid_err(hid, "Not able to get a minor for this device\n"); hid->hiddev = NULL; kfree(hiddev); return -1; diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index a948605564fb..065817329f03 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -24,6 +24,8 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -104,16 +106,18 @@ static void usb_kbd_irq(struct urb *urb) if (usb_kbd_keycode[kbd->old[i]]) input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); else - dev_info(&urb->dev->dev, - "Unknown key (scancode %#x) released.\n", kbd->old[i]); + hid_info(urb->dev, + "Unknown key (scancode %#x) released.\n", + kbd->old[i]); } if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { if (usb_kbd_keycode[kbd->new[i]]) input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); else - dev_info(&urb->dev->dev, - "Unknown key (scancode %#x) released.\n", kbd->new[i]); + hid_info(urb->dev, + "Unknown key (scancode %#x) released.\n", + kbd->new[i]); } } @@ -124,9 +128,9 @@ static void usb_kbd_irq(struct urb *urb) resubmit: i = usb_submit_urb (urb, GFP_ATOMIC); if (i) - err_hid ("can't resubmit intr, %s-%s/input0, status %d", - kbd->usbdev->bus->bus_name, - kbd->usbdev->devpath, i); + hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d", + kbd->usbdev->bus->bus_name, + kbd->usbdev->devpath, i); } static int usb_kbd_event(struct input_dev *dev, unsigned int type, @@ -150,7 +154,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type, *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) - err_hid("usb_submit_urb(leds) failed"); + pr_err("usb_submit_urb(leds) failed\n"); return 0; } @@ -160,7 +164,7 @@ static void usb_kbd_led(struct urb *urb) struct usb_kbd *kbd = urb->context; if (urb->status) - dev_warn(&urb->dev->dev, "led urb status %d received\n", + hid_warn(urb->dev, "led urb status %d received\n", urb->status); if (*(kbd->leds) == kbd->newleds) @@ -169,7 +173,7 @@ static void usb_kbd_led(struct urb *urb) *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) - err_hid("usb_submit_urb(leds) failed"); + hid_err(urb->dev, "usb_submit_urb(leds) failed\n"); } static int usb_kbd_open(struct input_dev *dev) diff --git a/include/linux/hid.h b/include/linux/hid.h index e2af195d8b46..20b9801f669b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -881,12 +881,32 @@ int hid_pidff_init(struct hid_device *hid); #define hid_pidff_init NULL #endif -#define dbg_hid(format, arg...) if (hid_debug) \ - printk(KERN_DEBUG "%s: " format ,\ - __FILE__ , ## arg) -#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ - __FILE__ , ## arg) -#endif /* HID_FF */ +#define dbg_hid(format, arg...) \ +do { \ + if (hid_debug) \ + printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \ +} while (0) + +#define hid_printk(level, hid, fmt, arg...) \ + dev_printk(level, &(hid)->dev, fmt, ##arg) +#define hid_emerg(hid, fmt, arg...) \ + dev_emerg(&(hid)->dev, fmt, ##arg) +#define hid_crit(hid, fmt, arg...) \ + dev_crit(&(hid)->dev, fmt, ##arg) +#define hid_alert(hid, fmt, arg...) \ + dev_alert(&(hid)->dev, fmt, ##arg) +#define hid_err(hid, fmt, arg...) \ + dev_err(&(hid)->dev, fmt, ##arg) +#define hid_notice(hid, fmt, arg...) \ + dev_notice(&(hid)->dev, fmt, ##arg) +#define hid_warn(hid, fmt, arg...) \ + dev_warn(&(hid)->dev, fmt, ##arg) +#define hid_info(hid, fmt, arg...) \ + dev_info(&(hid)->dev, fmt, ##arg) +#define hid_dbg(hid, fmt, arg...) \ + dev_dbg(&(hid)->dev, fmt, ##arg) + +#endif /* __KERNEL__ */ #endif -- cgit v1.2.3 From fe2580204d8bbcd18540736a283ed0b784c6a024 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 9 Dec 2010 19:29:04 -0800 Subject: HID: Use vzalloc for vmalloc/memset(,0...) Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1fd5e331fa8d..5ddace093f0f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -654,13 +654,12 @@ int hid_parse_report(struct hid_device *device, __u8 *start, return -ENOMEM; device->rsize = size; - parser = vmalloc(sizeof(struct hid_parser)); + parser = vzalloc(sizeof(struct hid_parser)); if (!parser) { ret = -ENOMEM; goto err; } - memset(parser, 0, sizeof(struct hid_parser)); parser->device = device; end = start + size; -- cgit v1.2.3 From 16ee4cc82b5dbb81a5dbfedcdb268b9467fe4605 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 9 Dec 2010 19:29:05 -0800 Subject: HID: Remove superfluous __inline__ Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5ddace093f0f..e6b90622e4eb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -739,8 +739,8 @@ static u32 s32ton(__s32 value, unsigned n) * Search linux-kernel and linux-usb-devel archives for "hid-core extract". */ -static __inline__ __u32 extract(const struct hid_device *hid, __u8 *report, - unsigned offset, unsigned n) +static __u32 extract(const struct hid_device *hid, __u8 *report, + unsigned offset, unsigned n) { u64 x; @@ -763,8 +763,8 @@ static __inline__ __u32 extract(const struct hid_device *hid, __u8 *report, * endianness of register values by considering a register * a "cached" copy of the little endiad bit stream. */ -static __inline__ void implement(const struct hid_device *hid, __u8 *report, - unsigned offset, unsigned n, __u32 value) +static void implement(const struct hid_device *hid, __u8 *report, + unsigned offset, unsigned n, __u32 value) { u64 x; u64 m = (1ULL << n) - 1; @@ -792,7 +792,7 @@ static __inline__ void implement(const struct hid_device *hid, __u8 *report, * Search an array for a value. */ -static __inline__ int search(__s32 *array, __s32 value, unsigned n) +static int search(__s32 *array, __s32 value, unsigned n) { while (n--) { if (*array++ == value) -- cgit v1.2.3 From a3789a1783d37f2772ba5046b26416c98dfe1bfa Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 9 Dec 2010 19:29:07 -0800 Subject: HID: Hoist assigns from ifs Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e6b90622e4eb..86b7155632fb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -61,7 +61,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type, if (report_enum->report_id_hash[id]) return report_enum->report_id_hash[id]; - if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) + report = kzalloc(sizeof(struct hid_report), GFP_KERNEL); + if (!report) return NULL; if (id != 0) @@ -92,8 +93,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned return NULL; } - if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned), GFP_KERNEL))) return NULL; + field = kzalloc((sizeof(struct hid_field) + + usages * sizeof(struct hid_usage) + + values * sizeof(unsigned)), GFP_KERNEL); + if (!field) + return NULL; field->index = report->maxfield++; report->field[field->index] = field; @@ -211,7 +215,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign unsigned offset; int i; - if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { + report = hid_register_report(parser->device, report_type, parser->global.report_id); + if (!report) { dbg_hid("hid_register_report failed\n"); return -1; } @@ -229,7 +234,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign usages = max_t(int, parser->local.usage_index, parser->global.report_count); - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) + field = hid_register_field(report, usages, parser->global.report_count); + if (!field) return 0; field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); @@ -891,7 +897,8 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __s32 max = field->logical_maximum; __s32 *value; - if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) + value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC); + if (!value) return; for (n = 0; n < count; n++) { -- cgit v1.2.3 From 504499f22c08a03e2e19dc88d31aa0ecd2ac815e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 9 Dec 2010 19:29:08 -0800 Subject: HID: simplify an index check in hid_lookup_collection Save the struct hid_collection * in a temporary to shorten the generated code a bit and perhaps improve readability. $ size drivers/hid/hid-core.o* text data bss dec hex filename 16460 78 8 16546 40a2 drivers/hid/hid-core.o.new 16469 78 8 16555 40ab drivers/hid/hid-core.o.old Signed-off-by: Joe Perches Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 86b7155632fb..d4c1906313d2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -178,10 +178,14 @@ static int close_collection(struct hid_parser *parser) static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) { + struct hid_collection *collection = parser->device->collection; int n; - for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->device->collection[parser->collection_stack[n]].type == type) - return parser->device->collection[parser->collection_stack[n]].usage; + + for (n = parser->collection_stack_ptr - 1; n >= 0; n--) { + unsigned index = parser->collection_stack[n]; + if (collection[index].type == type) + return collection[index].usage; + } return 0; /* we know nothing about this usage type */ } -- cgit v1.2.3 From a34f0b31398020e2d3be653eb695bd17a9cf3b55 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 10 Dec 2010 14:55:42 +0100 Subject: fix comment typos concerning "consistent" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- arch/arm/mach-msm/include/mach/entry-macro-qgic.S | 2 +- arch/m68k/mac/psc.c | 2 +- drivers/net/via-velocity.c | 2 +- drivers/net/wimax/i2400m/i2400m.h | 2 +- drivers/scsi/megaraid/megaraid_mm.c | 2 +- fs/jbd/transaction.c | 2 +- fs/jbd2/transaction.c | 2 +- net/ipv6/af_inet6.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S index 4dc99aa65d07..12467157afb9 100644 --- a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S +++ b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S @@ -26,7 +26,7 @@ * The interrupt numbering scheme is defined in the * interrupt controller spec. To wit: * - * Migrated the code from ARM MP port to be more consistant + * Migrated the code from ARM MP port to be more consistent * with interrupt processing , the following still holds true * however, all interrupts are treated the same regardless of * if they are local IPI or PPI diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index ba6ccab64018..a4c3eb60706e 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -88,7 +88,7 @@ void __init psc_init(void) /* * The PSC is always at the same spot, but using psc - * keeps things consisant with the psc_xxxx functions. + * keeps things consistent with the psc_xxxx functions. */ psc = (void *) PSC_BASE; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index cab96ad49e60..09cac704fdd7 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -898,7 +898,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) set_mii_flow_control(vptr); /* - Check if new status is consisent with current status + Check if new status is consistent with current status if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) || (mii_status==curr_status)) { vptr->mii_status=mii_check_media_mode(vptr->mac_regs); diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 8cde3a52d225..a2dbc94f6232 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -186,7 +186,7 @@ enum { * struct i2400m_poke_table - Hardware poke table for the Intel 2400m * * This structure will be used to create a device specific poke table - * to put the device in a consistant state at boot time. + * to put the device in a consistent state at boot time. * * @address: The device address to poke * diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index a7008c0c24f9..25506c777381 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -224,7 +224,7 @@ mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd, { int err; - /* inconsistant: mraid_mm_compat_ioctl doesn't take the BKL */ + /* inconsistent: mraid_mm_compat_ioctl doesn't take the BKL */ mutex_lock(&mraid_mm_mutex); err = mraid_mm_ioctl(filep, cmd, arg); mutex_unlock(&mraid_mm_mutex); diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 846a3f314111..5b2e4c30a2a1 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -207,7 +207,7 @@ repeat_locked: * the committing transaction. Really, we only need to give it * committing_transaction->t_outstanding_credits plus "enough" for * the log control blocks. - * Also, this test is inconsitent with the matching one in + * Also, this test is inconsistent with the matching one in * journal_extend(). */ if (__log_space_left(journal) < jbd_space_needed(journal)) { diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 6bf0a242613e..c7934900dcdd 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -251,7 +251,7 @@ repeat: * the committing transaction. Really, we only need to give it * committing_transaction->t_outstanding_credits plus "enough" for * the log control blocks. - * Also, this test is inconsitent with the matching one in + * Also, this test is inconsistent with the matching one in * jbd2_journal_extend(). */ if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 54e8e42f7a88..0935c5a42b1f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -300,7 +300,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) goto out; } - /* Reproduce AF_INET checks to make the bindings consitant */ + /* Reproduce AF_INET checks to make the bindings consistent */ v4addr = addr->sin6_addr.s6_addr32[3]; chk_addr_ret = inet_addr_type(net, v4addr); if (!sysctl_ip_nonlocal_bind && -- cgit v1.2.3 From e91eb2ff1f713837caebbb86a06974cd4b3e8e46 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 10 Dec 2010 15:41:18 +0300 Subject: Staging: rtl8192u: add missing curly braces The if condition was ignored in the original code and we just used the default channel. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 12858880f95f..20f8c347cae4 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -509,9 +509,10 @@ void ieee80211_softmac_scan_wq(struct work_struct *work) if (watchdog++ > MAX_CHANNEL_NUMBER) { //if current channel is not in channel map, set to default channel. - if (!channel_map[ieee->current_network.channel]); + if (!channel_map[ieee->current_network.channel]) { ieee->current_network.channel = 6; goto out; /* no good chans */ + } } }while(!channel_map[ieee->current_network.channel]); if (ieee->scanning == 0 ) -- cgit v1.2.3 From bc657f6e9130108651915fe37624e47638c46e0f Mon Sep 17 00:00:00 2001 From: Mark Allyn Date: Fri, 10 Dec 2010 07:37:48 -0800 Subject: staging: sep: fix comments in sep_get_static_pool_addr_handler Original comments were inaccurate Signed-off-by: Mark Allyn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 2681fcf0c34d..ac5d56943d4b 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -2545,10 +2545,8 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, /** * sep_get_static_pool_addr_handler - get static pool address * @sep: pointer to struct sep_device - * @arg: parameters from user space application * * This function sets the bus and virtual addresses of the static pool - * and returns the virtual address */ static int sep_get_static_pool_addr_handler(struct sep_device *sep) { @@ -3036,7 +3034,7 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) error = -EPERM; /* Not permitted on new chip */ break; case SEP_IOCGETSTATICPOOLADDR: - /* Get the physical and virtual addresses of the static pool */ + /* Inform the SEP the bus address of the static pool */ error = sep_get_static_pool_addr_handler(sep); break; case SEP_IOCENDTRANSACTION: -- cgit v1.2.3 From b8b739941eb57ec4c5fc87a73e7e7b554cf395fb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 10 Dec 2010 10:46:30 -0800 Subject: Staging: cxt1e1: rename global log_level variable The driver should not have such a generic global variable name. Reported-by: Zimny Lech Cc: Bob Beers Signed-off-by: Greg Kroah-Hartman --- drivers/staging/cxt1e1/comet.c | 8 ++-- drivers/staging/cxt1e1/functions.c | 8 ++-- drivers/staging/cxt1e1/hwprobe.c | 4 +- drivers/staging/cxt1e1/linux.c | 18 ++++----- drivers/staging/cxt1e1/musycc.c | 58 ++++++++++++++-------------- drivers/staging/cxt1e1/pmcc4_drv.c | 38 +++++++++--------- drivers/staging/cxt1e1/sbecom_inline_linux.h | 4 +- 7 files changed, 69 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c index dcbe6b628455..52224cdc967d 100644 --- a/drivers/staging/cxt1e1/comet.c +++ b/drivers/staging/cxt1e1/comet.c @@ -29,7 +29,7 @@ #endif -extern int log_level; +extern int cxt1e1_log_level; #define COMET_NUM_SAMPLES 24 /* Number of entries in the waveform table */ #define COMET_NUM_UNITS 5 /* Number of points per entry in table */ @@ -292,12 +292,12 @@ init_comet (void *ci, comet_t * comet, u_int32_t port_mode, int clockmaster, * i.e.FPMODE=0 (@0x20) */ if ((moreParams & CFG_CLK_PORT_MASK) == CFG_CLK_PORT_INTERNAL) { - if (log_level >= LOG_SBEBUG12) + if (cxt1e1_log_level >= LOG_SBEBUG12) pr_info(">> %s: clockmaster internal clock\n", __func__); pci_write_32 ((u_int32_t *) &comet->tx_time, 0x0d); /* internal oscillator */ } else /* external clock source */ { - if (log_level >= LOG_SBEBUG12) + if (cxt1e1_log_level >= LOG_SBEBUG12) pr_info(">> %s: clockmaster external clock\n", __func__); pci_write_32 ((u_int32_t *) &comet->tx_time, 0x09); /* loop timing * (external) */ @@ -312,7 +312,7 @@ init_comet (void *ci, comet_t * comet, u_int32_t port_mode, int clockmaster, pci_write_32 ((u_int32_t *) &comet->brif_cfg, 0x21); /* Slave Mode (CMODE=1) */ pci_write_32 ((u_int32_t *) &comet->brif_fpcfg, 0x20); /* Slave Mode i.e. * FPMODE=1 (@0x20) */ - if (log_level >= LOG_SBEBUG12) + if (cxt1e1_log_level >= LOG_SBEBUG12) pr_info(">> %s: clockslave internal clock\n", __func__); pci_write_32 ((u_int32_t *) &comet->tx_time, 0x0d); /* oscillator timing */ } diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c index ab399c2f7488..d9a9aa3571d9 100644 --- a/drivers/staging/cxt1e1/functions.c +++ b/drivers/staging/cxt1e1/functions.c @@ -54,7 +54,7 @@ static int dummy = 0; #endif -extern int log_level; +extern int cxt1e1_log_level; extern int drvr_state; @@ -67,7 +67,7 @@ pci_read_32 (u_int32_t *p) FLUSH_PCI_READ (); v = le32_to_cpu (*p); - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); return v; #else @@ -80,7 +80,7 @@ void pci_write_32 (u_int32_t *p, u_int32_t v) { #ifdef FLOW_DEBUG - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); #endif *p = cpu_to_le32 (v); @@ -118,7 +118,7 @@ watchdog_func (unsigned long arg) if (drvr_state != SBE_DRVR_AVAILABLE) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_warning("%s: drvr not available (%x)\n", __func__, drvr_state); return; } diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c index 89200e7af26c..c517cc22f391 100644 --- a/drivers/staging/cxt1e1/hwprobe.c +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -37,7 +37,7 @@ #define STATIC static #endif -extern int log_level; +extern int cxt1e1_log_level; extern int error_flag; extern int drvr_state; @@ -143,7 +143,7 @@ hdw_sn_get (hdw_info_t * hi, int brdno) if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk) { /* bad crc, data is suspect */ - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: EEPROM cksum error\n", hi->devname); hi->mfg_info_sts = EEPROM_CRCERR; } else diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index c7930287e3db..0f78f8962751 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -108,9 +108,9 @@ extern int unregister_hdlc_device_v7 (hdlc_device *); #endif int error_flag; /* module load error reporting */ -int log_level = LOG_ERROR; +int cxt1e1_log_level = LOG_ERROR; int log_level_default = LOG_ERROR; -module_param(log_level, int, 0444); +module_param(cxt1e1_log_level, int, 0444); int cxt1e1_max_mru = MUSYCC_MRU; int max_mru_default = MUSYCC_MRU; @@ -497,7 +497,7 @@ create_chan (struct net_device * ndev, ci_t * ci, rtnl_lock (); /* needed due to Ioctl calling sequence */ if (ret) { - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: create_chan[%d] registration error = %d.\n", ci->devname, cp->channum, ret); free_netdev (dev); /* cleanup */ @@ -722,11 +722,11 @@ do_get_chan_stats (struct net_device * ndev, void *data) STATIC status_t do_set_loglevel (struct net_device * ndev, void *data) { - unsigned int log_level; + unsigned int cxt1e1_log_level; - if (copy_from_user (&log_level, data, sizeof (int))) + if (copy_from_user (&cxt1e1_log_level, data, sizeof (int))) return -EFAULT; - sbecom_set_loglevel (log_level); + sbecom_set_loglevel (cxt1e1_log_level); return 0; } @@ -1115,9 +1115,9 @@ c4_mod_init (void) return -rtn; /* installation failure - see system log */ /* housekeeping notifications */ - if (log_level != log_level_default) - pr_info("NOTE: driver parameter changed from default %d to %d.\n", - log_level_default, log_level); + if (cxt1e1_log_level != log_level_default) + pr_info("NOTE: driver parameter changed from default %d to %d.\n", + log_level_default, cxt1e1_log_level); if (cxt1e1_max_mru != max_mru_default) pr_info("NOTE: driver parameter changed from default %d to %d.\n", max_mru_default, cxt1e1_max_mru); diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index fc15610f6974..f274c77fb3fc 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -97,7 +97,7 @@ char SBEid_pmcc4_musyccc[] = /* global driver variables */ extern ci_t *c4_list; extern int drvr_state; -extern int log_level; +extern int cxt1e1_log_level; extern int cxt1e1_max_mru; extern int cxt1e1_max_mtu; @@ -627,7 +627,7 @@ rewrite: if ((r != req) && (req != SR_CHIP_RESET) && (++rcnt <= MUSYCC_SR_RETRY_CNT)) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: %d - reissue srv req/last %x/%x (hdw reads %x), Chan %d.\n", pi->up->devname, rcnt, req, pi->sr_last, r, (pi->portnum * MUSYCC_NCHANS) + (req & 0x1f)); @@ -951,7 +951,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) ch = pi->chan[gchan]; if (ch == 0 || ch->state != UP) { - if (log_level >= LOG_ERROR) + if (cxt1e1_log_level >= LOG_ERROR) pr_info("%s: intr: xmit EOM on uninitialized channel %d\n", pi->up->devname, gchan); } @@ -1002,7 +1002,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) } if (status & MUSYCC_TX_OWNED) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) { pr_info("%s: Port %d Chan %2d - unexpected TX msg ownership intr (md %p sts %x)\n", pi->up->devname, pi->portnum, ch->channum, @@ -1016,7 +1016,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) break; /* Not our mdesc, done */ } else { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: Port %d Chan %2d - recovered TX msg ownership [%d] (md %p sts %x)\n", pi->up->devname, pi->portnum, ch->channum, readCount, md, status); } @@ -1054,7 +1054,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) } md->status = 0; #ifdef RLD_TXFULL_DEBUG - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) pr_info("~~ tx_eom: tx_full %x txd_free %d -> %d\n", ch->tx_full, ch->txd_free, ch->txd_free + 1); #endif @@ -1063,7 +1063,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) if ((ch->p.chan_mode != CFG_CH_PROTO_TRANS) && (status & EOBIRQ_ENABLE)) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: Mode (%x) incorrect EOB status (%x)\n", pi->up->devname, ch->p.chan_mode, status); if ((status & EOMIRQ_ENABLE) == 0) @@ -1094,7 +1094,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) { #ifdef RLD_TXFULL_DEBUG - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) pr_info("tx_eom[%d]: enable xmit tx_full no more, txd_free %d txd_num/2 %d\n", ch->channum, ch->txd_free, ch->txd_num / 2); @@ -1108,7 +1108,7 @@ musycc_bh_tx_eom (mpi_t * pi, int gchan) #ifdef RLD_TXFULL_DEBUG else if (ch->tx_full) { - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) pr_info("tx_eom[%d]: bypass TX enable though room available? (txd_free %d txd_num/2 %d)\n", ch->channum, ch->txd_free, ch->txd_num / 2); @@ -1138,7 +1138,7 @@ musycc_bh_rx_eom (mpi_t * pi, int gchan) ch = pi->chan[gchan]; if (ch == 0 || ch->state != UP) { - if (log_level > LOG_ERROR) + if (cxt1e1_log_level > LOG_ERROR) pr_info("%s: intr: receive EOM on uninitialized channel %d\n", pi->up->devname, gchan); return; @@ -1269,7 +1269,7 @@ musycc_intr_th_handler (void *devp) if (nextInt != INTRPTS_NEXTINT (ci->intlog.this_status_new)) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) { pr_info("%s: note - updated ISD from %08x to %08x\n", ci->devname, status, @@ -1337,11 +1337,11 @@ musycc_intr_th_handler (void *devp) ci->intlog.last_status_new = ci->intlog.this_status_new; ci->intlog.this_status_new = currInt; - if ((log_level >= LOG_WARN) && (status & INTRPTS_INTFULL_M)) + if ((cxt1e1_log_level >= LOG_WARN) && (status & INTRPTS_INTFULL_M)) { pr_info("%s: Interrupt queue full condition occurred\n", ci->devname); } - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("%s: interrupts pending, isd @ 0x%p: %x curr %d cnt %d NEXT %d\n", ci->devname, &ci->reg->isd, status, nextInt, intCnt, (intCnt + nextInt) & (INT_QUEUE_SIZE - 1)); @@ -1448,7 +1448,7 @@ musycc_intr_bh_tasklet (ci_t * ci) if ((currInt == badInt) || (currInt == badInt2)) /* catch failure of Bug * Fix checking */ { - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: Illegal Interrupt Detected @ 0x%p, mod %d.)\n", ci->devname, &ci->iqd_p[headx], headx); @@ -1483,7 +1483,7 @@ musycc_intr_bh_tasklet (ci_t * ci) ci->iqd_p[headx] = __constant_cpu_to_le32 (INT_EMPTY_ENTRY); FLUSH_MEM_WRITE (); - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) { if (err != 0) pr_info(" %08x -> err: %2d,", currInt, err); @@ -1497,7 +1497,7 @@ musycc_intr_bh_tasklet (ci_t * ci) switch (event) { case EVE_SACK: /* Service Request Acknowledge */ - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) { volatile u_int32_t r; @@ -1534,7 +1534,7 @@ musycc_intr_bh_tasklet (ci_t * ci) } break; default: - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: unexpected interrupt event: %d, iqd[%d]: %08x, port: %d\n", ci->devname, event, headx, currInt, group); break; @@ -1573,9 +1573,9 @@ musycc_intr_bh_tasklet (ci_t * ci) { #ifdef RLD_TRANS_DEBUG - if (1 || log_level >= LOG_MONITOR) + if (1 || cxt1e1_log_level >= LOG_MONITOR) #else - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) #endif { pr_info("%s: TX buffer underflow [ONR] on channel %d, mode %x QStopped %x free %d\n", @@ -1605,7 +1605,7 @@ musycc_intr_bh_tasklet (ci_t * ci) ch->s.rx_over_errors++; ch->ch_start_rx = CH_START_RX_ONR; - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) { pr_info("%s: RX buffer overflow [ONR] on channel %d, mode %x\n", ci->devname, ch->channum, ch->p.chan_mode); @@ -1623,7 +1623,7 @@ musycc_intr_bh_tasklet (ci_t * ci) * Per MUSYCC manual, Section 6.4.8.3 [Transmit Errors], * this BUFF error requires Transmit channel reactivation. */ - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: TX buffer underrun [BUFF] on channel %d, mode %x\n", ci->devname, ch->channum, ch->p.chan_mode); } else /* RX buffer overrun */ @@ -1636,7 +1636,7 @@ musycc_intr_bh_tasklet (ci_t * ci) * space for this channel. Receive channel reactivation is * not required, but data has been lost. */ - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: RX buffer overrun [BUFF] on channel %d, mode %x\n", ci->devname, ch->channum, ch->p.chan_mode); /* @@ -1658,7 +1658,7 @@ musycc_intr_bh_tasklet (ci_t * ci) } /* switch on err */ /* Check for interrupt lost condition */ - if ((currInt & INTRPT_ILOST_M) && (log_level >= LOG_ERROR)) + if ((currInt & INTRPT_ILOST_M) && (cxt1e1_log_level >= LOG_ERROR)) { pr_info("%s: Interrupt queue overflow - ILOST asserted\n", ci->devname); @@ -1667,7 +1667,7 @@ musycc_intr_bh_tasklet (ci_t * ci) FLUSH_MEM_WRITE (); FLUSH_MEM_READ (); } /* while */ - if ((log_level >= LOG_MONITOR2) && (ci->iqp_headx != ci->iqp_tailx)) + if ((cxt1e1_log_level >= LOG_MONITOR2) && (ci->iqp_headx != ci->iqp_tailx)) { int bh; @@ -1821,9 +1821,9 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token) return EROFS; /* how else to flag unwritable state ? */ #ifdef RLD_TRANS_DEBUGx - if (1 || log_level >= LOG_MONITOR2) + if (1 || cxt1e1_log_level >= LOG_MONITOR2) #else - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) #endif { pr_info("++ start_xmt[%d]: state %x start %x full %d free %d required %d stopped %x\n", @@ -1846,7 +1846,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token) if (txd_need_cnt == 0) { - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) pr_info("%s channel %d: no TX data in User buffer\n", ci->devname, channum); OS_mem_token_free (mem_token); return 0; /* no data to send */ @@ -1857,7 +1857,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token) if (txd_need_cnt > ch->txd_num) /* never enough descriptors for this * large a buffer */ { - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) { pr_info("start_xmit: discarding buffer, insufficient descriptor cnt %d, need %d.\n", ch->txd_num, txd_need_cnt + 1); @@ -1874,7 +1874,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token) /************************************************************/ if (txd_need_cnt > ch->txd_free) { - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) { pr_info("start_xmit[%d]: EBUSY - need more descriptors, have %d of %d need %d\n", channum, ch->txd_free, ch->txd_num, txd_need_cnt); diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c index 5c8a3eb0cfc3..341e7a92f099 100644 --- a/drivers/staging/cxt1e1/pmcc4_drv.c +++ b/drivers/staging/cxt1e1/pmcc4_drv.c @@ -135,7 +135,7 @@ void musycc_serv_req (mpi_t *, u_int32_t); void musycc_update_timeslots (mpi_t *); extern void musycc_update_tx_thp (mch_t *); -extern int log_level; +extern int cxt1e1_log_level; extern int cxt1e1_max_mru; extern int cxt1e1_max_mtu; extern int max_rxdesc_used, max_rxdesc_default; @@ -168,12 +168,12 @@ sbecom_set_loglevel (int d) * for card 0 only */ } else { - if (log_level != d) + if (cxt1e1_log_level != d) { - pr_info("log level changed from %d to %d\n", log_level, d); - log_level = d; /* set new */ + pr_info("log level changed from %d to %d\n", cxt1e1_log_level, d); + cxt1e1_log_level = d; /* set new */ } else - pr_info("log level is %d\n", log_level); + pr_info("log level is %d\n", cxt1e1_log_level); } } @@ -513,7 +513,7 @@ checkPorts (ci_t * ci) if ((value == 0x1c) || (value == 0x19) || (value == 0x12)) c4_loop_port (ci, portnum, COMET_MDIAG_LBOFF); /* take port out of any * loopbk mode */ - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) if (value != 0x3f) pr_warning("%s: BOC value = %x on Port %d\n", ci->devname, value, portnum); @@ -533,7 +533,7 @@ c4_watchdog (ci_t * ci) { if (drvr_state != SBE_DRVR_AVAILABLE) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("drvr not available (%x)\n", drvr_state); return; } @@ -794,19 +794,19 @@ c4_loop_port (ci_t * ci, int portnum, u_int8_t cmd) } pci_write_32 ((u_int32_t *) &comet->mdiag, cmd); - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: loopback mode changed to %2x from %2x on Port %d\n", ci->devname, cmd, loopValue, portnum); loopValue = pci_read_32 ((u_int32_t *) &comet->mdiag) & COMET_MDIAG_LBMASK; if (loopValue != cmd) { - if (log_level >= LOG_ERROR) + if (cxt1e1_log_level >= LOG_ERROR) pr_info("%s: write to loop register failed, unknown state for Port %d\n", ci->devname, portnum); } } else { - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: loopback already in that mode (%2x)\n", ci->devname, loopValue); } @@ -997,7 +997,7 @@ c4_set_port (ci_t * ci, int portnum) pi = &ci->port[portnum]; pp = &ci->port[portnum].p; e1mode = IS_FRAME_ANY_E1 (pp->port_mode); - if (log_level >= LOG_MONITOR2) + if (cxt1e1_log_level >= LOG_MONITOR2) { pr_info("%s: c4_set_port[%d]: entered, e1mode = %x, openchans %d.\n", ci->devname, @@ -1278,12 +1278,12 @@ c4_fifo_alloc (mpi_t * pi, int chan, int *len) } if (max != *len) { - if (log_level >= LOG_WARN) + if (cxt1e1_log_level >= LOG_WARN) pr_info("%s: wanted to allocate %d fifo space, but got only %d\n", pi->up->devname, *len, max); *len = max; } - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("%s: allocated %d fifo at %d for channel %d/%d\n", pi->up->devname, max, start, chan, pi->p.portnum); for (i = maxstart; i < (maxstart + max); i++) @@ -1296,7 +1296,7 @@ c4_fifo_free (mpi_t * pi, int chan) { int i; - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("%s: deallocated fifo for channel %d/%d\n", pi->up->devname, chan, pi->p.portnum); for (i = 0; i < 32; i++) @@ -1321,7 +1321,7 @@ c4_chan_up (ci_t * ci, int channum) return ENOENT; if (ch->state == UP) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: channel already UP, graceful early exit\n", ci->devname); return 0; @@ -1334,7 +1334,7 @@ c4_chan_up (ci_t * ci, int channum) { if (ch->p.bitmask[i] & pi->tsm[i]) { - if (1 || log_level >= LOG_WARN) + if (1 || cxt1e1_log_level >= LOG_WARN) { pr_info("%s: c4_chan_up[%d] EINVAL (attempt to cfg in-use or unavailable TimeSlot[%d])\n", ci->devname, channum, i); @@ -1351,7 +1351,7 @@ c4_chan_up (ci_t * ci, int channum) nbuf = nts / 8 ? nts / 8 : 1; if (!nbuf) { - /* if( log_level >= LOG_WARN) */ + /* if( cxt1e1_log_level >= LOG_WARN) */ pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n", ci->devname, channum); return ENOBUFS; /* this should not happen */ @@ -1420,7 +1420,7 @@ c4_chan_up (ci_t * ci, int channum) #if 0 /* DEBUG INFO */ - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: mode %x rxnum %d (rxused %d def %d) txnum %d (txused %d def %d)\n", ci->devname, ch->p.chan_mode, rxnum, max_rxdesc_used, max_rxdesc_default, @@ -1451,7 +1451,7 @@ c4_chan_up (ci_t * ci, int channum) if (!(m = OS_mem_token_alloc (cxt1e1_max_mru))) { - if (log_level >= LOG_MONITOR) + if (cxt1e1_log_level >= LOG_MONITOR) pr_info("%s: c4_chan_up[%d] - token alloc failure, size = %d.\n", ci->devname, channum, cxt1e1_max_mru); goto errfree; diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h index 5a72cb5cff42..501a331ded5b 100644 --- a/drivers/staging/cxt1e1/sbecom_inline_linux.h +++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h @@ -86,7 +86,7 @@ pci_read_32 (u_int32_t *p) FLUSH_PCI_READ (); v = le32_to_cpu (*p); - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); return v; #else @@ -99,7 +99,7 @@ static inline void pci_write_32 (u_int32_t *p, u_int32_t v) { #ifdef FLOW_DEBUG - if (log_level >= LOG_DEBUG) + if (cxt1e1_log_level >= LOG_DEBUG) pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); #endif *p = cpu_to_le32 (v); -- cgit v1.2.3 From 64d74c6cbe52fbec90ead8f3bf53bfb10a1540d5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 10 Dec 2010 10:55:27 -0800 Subject: Staging: ft1000: fix world writable debugfs file You should not be able to write to a debugfs file from any user. Cc: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c index da76f11a552f..e39809229d46 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c @@ -173,7 +173,7 @@ int ft1000_create_dev(struct ft1000_device *dev) goto debug_dir_fail; } - file = debugfs_create_file("device", S_IRUGO | S_IWUGO, dir, + file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir, NULL, &ft1000fops); if (IS_ERR(file)) { result = PTR_ERR(file); -- cgit v1.2.3 From 983bbfd091be5b3e1a729f31cce29431fbff2d27 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 10 Dec 2010 10:56:18 -0800 Subject: Staging: iio: fix up world writable sysfs files. You should not be able to write to sysfs files from any user. Cc: Graf Yang Cc: Michael Hennerich Cc: Jonathan Cameron Cc: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/resolver/ad2s1210.c | 28 ++++++++++++++-------------- drivers/staging/iio/sysfs.h | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 34fb21aa8b07..c12f64cc40df 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -661,19 +661,19 @@ error_ret: static IIO_CONST_ATTR(description, "Variable Resolution, 10-Bit to 16Bit R/D\n\ Converter with Reference Oscillator"); -static IIO_DEVICE_ATTR(raw_io, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(raw_io, S_IRUGO | S_IWUSR, ad2s1210_show_raw, ad2s1210_store_raw, 0); -static IIO_DEVICE_ATTR(reset, S_IWUGO, +static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, ad2s1210_store_softreset, 0); -static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR, ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); -static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR, ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); -static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUSR, ad2s1210_show_control, ad2s1210_store_control, 0); -static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUSR, ad2s1210_show_resolution, ad2s1210_store_resolution, 0); -static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, ad2s1210_show_fault, ad2s1210_clear_fault, 0); static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s1210_show_pos, NULL, 0); @@ -681,19 +681,19 @@ static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s1210_show_vel, NULL, 0); static IIO_DEVICE_ATTR(pos_vel, S_IRUGO, ad2s1210_show_pos_vel, NULL, 0); -static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_LOS_THRD); -static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_OVR_THRD); -static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_MIS_THRD); -static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MAX_THRD); -static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MIN_THRD); -static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_HIGH_THRD); -static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUGO, +static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR, ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_LOW_THRD); static struct attribute *ad2s1210_attributes[] = { diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h index 18bdaac2509d..24b74ddcd083 100644 --- a/drivers/staging/iio/sysfs.h +++ b/drivers/staging/iio/sysfs.h @@ -111,7 +111,7 @@ struct iio_const_attr { * IIO_DEV_ATTR_RESET: resets the device **/ #define IIO_DEV_ATTR_RESET(_store) \ - IIO_DEVICE_ATTR(reset, S_IWUGO, NULL, _store, 0) + IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, _store, 0) /** * IIO_CONST_ATTR_NAME - constant identifier -- cgit v1.2.3 From 6610e0893b8bc6f59b14fed7f089c5997f035f88 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 23 Sep 2010 15:07:34 -0700 Subject: RTC: Rework RTC code to use timerqueue for events This patch reworks a large portion of the generic RTC code to in-effect virtualize the rtc interrupt code. The current RTC interface is very much a raw hardware interface. Via the proc, /dev/, or sysfs interfaces, applciations can set the hardware to trigger interrupts in one of three modes: AIE: Alarm interrupt UIE: Update interrupt (ie: once per second) PIE: Periodic interrupt (sub-second irqs) The problem with this interface is that it limits the RTC hardware so it can only be used by one application at a time. The purpose of this patch is to extend the RTC code so that we can multiplex multiple applications event needs onto a single RTC device. This is done by utilizing the timerqueue infrastructure to manage a list of events, which cause the RTC hardware to be programmed to fire an interrupt for the next event in the list. In order to preserve the functionality of the exsting proc,/dev/ and sysfs interfaces, we emulate the different interrupt modes as follows: AIE: We create a rtc_timer dedicated to AIE mode interrupts. There is only one per device, so we don't change existing interface semantics. UIE: Again, a dedicated rtc_timer, set for periodic mode, is used to emulate UIE interrupts. Again, only one per device. PIE: Since PIE mode interrupts fire faster then the RTC's clock read granularity, we emulate PIE mode interrupts using a hrtimer. Again, one per device. With this patch, the rtctest.c application in Documentation/rtc.txt passes fine on x86 hardware. However, there may very well still be bugs, so greatly I'd appreciate any feedback or testing! Signed-off-by: John Stultz LKML Reference: <1290136329-18291-4-git-send-email-john.stultz@linaro.org> Acked-by: Alessandro Zummo Reviewed-by: Thomas Gleixner CC: Alessandro Zummo CC: Thomas Gleixner CC: Richard Cochran --- drivers/rtc/class.c | 13 ++ drivers/rtc/interface.c | 574 +++++++++++++++++++++++++++++------------------- drivers/rtc/rtc-lib.c | 28 +++ include/linux/rtc.h | 43 +++- 4 files changed, 428 insertions(+), 230 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 565562ba6ac9..95d2b82762d6 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "rtc-core.h" @@ -152,6 +153,18 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, spin_lock_init(&rtc->irq_task_lock); init_waitqueue_head(&rtc->irq_queue); + /* Init timerqueue */ + timerqueue_init_head(&rtc->timerqueue); + INIT_WORK(&rtc->irqwork, rtctimer_do_work); + /* Init aie timer */ + rtctimer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc); + /* Init uie timer */ + rtctimer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc); + /* Init pie timer */ + hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + rtc->pie_timer.function = rtc_pie_update_irq; + rtc->pie_enabled = 0; + strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); dev_set_name(&rtc->dev, "rtc%d", id); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a0c816238aa9..c81c50b497b7 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -14,15 +14,11 @@ #include #include #include +#include -int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) +static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) { int err; - - err = mutex_lock_interruptible(&rtc->ops_lock); - if (err) - return err; - if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->read_time) @@ -31,7 +27,18 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) memset(tm, 0, sizeof(struct rtc_time)); err = rtc->ops->read_time(rtc->dev.parent, tm); } + return err; +} + +int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + int err; + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + err = __rtc_read_time(rtc, tm); mutex_unlock(&rtc->ops_lock); return err; } @@ -106,188 +113,54 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) } EXPORT_SYMBOL_GPL(rtc_set_mmss); -static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; - - if (rtc->ops == NULL) - err = -ENODEV; - else if (!rtc->ops->read_alarm) - err = -EINVAL; - else { - memset(alarm, 0, sizeof(struct rtc_wkalrm)); - err = rtc->ops->read_alarm(rtc->dev.parent, alarm); - } - + alarm->enabled = rtc->aie_timer.enabled; + if (alarm->enabled) + alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); mutex_unlock(&rtc->ops_lock); - return err; + + return 0; } +EXPORT_SYMBOL_GPL(rtc_read_alarm); -int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { + struct rtc_time tm; + long now, scheduled; int err; - struct rtc_time before, now; - int first_time = 1; - unsigned long t_now, t_alm; - enum { none, day, month, year } missing = none; - unsigned days; - - /* The lower level RTC driver may return -1 in some fields, - * creating invalid alarm->time values, for reasons like: - * - * - The hardware may not be capable of filling them in; - * many alarms match only on time-of-day fields, not - * day/month/year calendar data. - * - * - Some hardware uses illegal values as "wildcard" match - * values, which non-Linux firmware (like a BIOS) may try - * to set up as e.g. "alarm 15 minutes after each hour". - * Linux uses only oneshot alarms. - * - * When we see that here, we deal with it by using values from - * a current RTC timestamp for any missing (-1) values. The - * RTC driver prevents "periodic alarm" modes. - * - * But this can be racey, because some fields of the RTC timestamp - * may have wrapped in the interval since we read the RTC alarm, - * which would lead to us inserting inconsistent values in place - * of the -1 fields. - * - * Reading the alarm and timestamp in the reverse sequence - * would have the same race condition, and not solve the issue. - * - * So, we must first read the RTC timestamp, - * then read the RTC alarm value, - * and then read a second RTC timestamp. - * - * If any fields of the second timestamp have changed - * when compared with the first timestamp, then we know - * our timestamp may be inconsistent with that used by - * the low-level rtc_read_alarm_internal() function. - * - * So, when the two timestamps disagree, we just loop and do - * the process again to get a fully consistent set of values. - * - * This could all instead be done in the lower level driver, - * but since more than one lower level RTC implementation needs it, - * then it's probably best best to do it here instead of there.. - */ - /* Get the "before" timestamp */ - err = rtc_read_time(rtc, &before); - if (err < 0) + err = rtc_valid_tm(&alarm->time); + if (err) return err; - do { - if (!first_time) - memcpy(&before, &now, sizeof(struct rtc_time)); - first_time = 0; - - /* get the RTC alarm values, which may be incomplete */ - err = rtc_read_alarm_internal(rtc, alarm); - if (err) - return err; - if (!alarm->enabled) - return 0; - - /* full-function RTCs won't have such missing fields */ - if (rtc_valid_tm(&alarm->time) == 0) - return 0; - - /* get the "after" timestamp, to detect wrapped fields */ - err = rtc_read_time(rtc, &now); - if (err < 0) - return err; - - /* note that tm_sec is a "don't care" value here: */ - } while ( before.tm_min != now.tm_min - || before.tm_hour != now.tm_hour - || before.tm_mon != now.tm_mon - || before.tm_year != now.tm_year); - - /* Fill in the missing alarm fields using the timestamp; we - * know there's at least one since alarm->time is invalid. - */ - if (alarm->time.tm_sec == -1) - alarm->time.tm_sec = now.tm_sec; - if (alarm->time.tm_min == -1) - alarm->time.tm_min = now.tm_min; - if (alarm->time.tm_hour == -1) - alarm->time.tm_hour = now.tm_hour; - - /* For simplicity, only support date rollover for now */ - if (alarm->time.tm_mday == -1) { - alarm->time.tm_mday = now.tm_mday; - missing = day; - } - if (alarm->time.tm_mon == -1) { - alarm->time.tm_mon = now.tm_mon; - if (missing == none) - missing = month; - } - if (alarm->time.tm_year == -1) { - alarm->time.tm_year = now.tm_year; - if (missing == none) - missing = year; - } - - /* with luck, no rollover is needed */ - rtc_tm_to_time(&now, &t_now); - rtc_tm_to_time(&alarm->time, &t_alm); - if (t_now < t_alm) - goto done; - - switch (missing) { + rtc_tm_to_time(&alarm->time, &scheduled); - /* 24 hour rollover ... if it's now 10am Monday, an alarm that - * that will trigger at 5am will do so at 5am Tuesday, which - * could also be in the next month or year. This is a common - * case, especially for PCs. - */ - case day: - dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); - t_alm += 24 * 60 * 60; - rtc_time_to_tm(t_alm, &alarm->time); - break; - - /* Month rollover ... if it's the 31th, an alarm on the 3rd will - * be next month. An alarm matching on the 30th, 29th, or 28th - * may end up in the month after that! Many newer PCs support - * this type of alarm. + /* Make sure we're not setting alarms in the past */ + err = __rtc_read_time(rtc, &tm); + rtc_tm_to_time(&tm, &now); + if (scheduled <= now) + return -ETIME; + /* + * XXX - We just checked to make sure the alarm time is not + * in the past, but there is still a race window where if + * the is alarm set for the next second and the second ticks + * over right here, before we set the alarm. */ - case month: - dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); - do { - if (alarm->time.tm_mon < 11) - alarm->time.tm_mon++; - else { - alarm->time.tm_mon = 0; - alarm->time.tm_year++; - } - days = rtc_month_days(alarm->time.tm_mon, - alarm->time.tm_year); - } while (days < alarm->time.tm_mday); - break; - - /* Year rollover ... easy except for leap years! */ - case year: - dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); - do { - alarm->time.tm_year++; - } while (rtc_valid_tm(&alarm->time) != 0); - break; - - default: - dev_warn(&rtc->dev, "alarm rollover not handled\n"); - } -done: - return 0; + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->set_alarm) + err = -EINVAL; + else + err = rtc->ops->set_alarm(rtc->dev.parent, alarm); + + return err; } -EXPORT_SYMBOL_GPL(rtc_read_alarm); int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { @@ -300,16 +173,18 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; - - if (!rtc->ops) - err = -ENODEV; - else if (!rtc->ops->set_alarm) - err = -EINVAL; - else - err = rtc->ops->set_alarm(rtc->dev.parent, alarm); - + if (rtc->aie_timer.enabled) { + rtctimer_remove(rtc, &rtc->aie_timer); + rtc->aie_timer.enabled = 0; + } + rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); + rtc->aie_timer.period = ktime_set(0, 0); + if (alarm->enabled) { + rtc->aie_timer.enabled = 1; + rtctimer_enqueue(rtc, &rtc->aie_timer); + } mutex_unlock(&rtc->ops_lock); - return err; + return 0; } EXPORT_SYMBOL_GPL(rtc_set_alarm); @@ -319,6 +194,16 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (err) return err; + if (rtc->aie_timer.enabled != enabled) { + if (enabled) { + rtc->aie_timer.enabled = 1; + rtctimer_enqueue(rtc, &rtc->aie_timer); + } else { + rtctimer_remove(rtc, &rtc->aie_timer); + rtc->aie_timer.enabled = 0; + } + } + if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->alarm_irq_enable) @@ -337,52 +222,53 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (err) return err; -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - if (enabled == 0 && rtc->uie_irq_active) { - mutex_unlock(&rtc->ops_lock); - return rtc_dev_update_irq_enable_emul(rtc, enabled); + /* make sure we're changing state */ + if (rtc->uie_rtctimer.enabled == enabled) + goto out; + + if (enabled) { + struct rtc_time tm; + ktime_t now, onesec; + + __rtc_read_time(rtc, &tm); + onesec = ktime_set(1, 0); + now = rtc_tm_to_ktime(tm); + rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); + rtc->uie_rtctimer.period = ktime_set(1, 0); + rtc->uie_rtctimer.enabled = 1; + rtctimer_enqueue(rtc, &rtc->uie_rtctimer); + } else { + rtctimer_remove(rtc, &rtc->uie_rtctimer); + rtc->uie_rtctimer.enabled = 0; } -#endif - - if (!rtc->ops) - err = -ENODEV; - else if (!rtc->ops->update_irq_enable) - err = -EINVAL; - else - err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled); +out: mutex_unlock(&rtc->ops_lock); - -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - /* - * Enable emulation if the driver did not provide - * the update_irq_enable function pointer or if returned - * -EINVAL to signal that it has been configured without - * interrupts or that are not available at the moment. - */ - if (err == -EINVAL) - err = rtc_dev_update_irq_enable_emul(rtc, enabled); -#endif return err; + } EXPORT_SYMBOL_GPL(rtc_update_irq_enable); + /** - * rtc_update_irq - report RTC periodic, alarm, and/or update irqs - * @rtc: the rtc device - * @num: how many irqs are being reported (usually one) - * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF - * Context: any + * rtc_handle_legacy_irq - AIE, UIE and PIE event hook + * @rtc: pointer to the rtc device + * + * This function is called when an AIE, UIE or PIE mode interrupt + * has occured (or been emulated). + * + * Triggers the registered irq_task function callback. */ -void rtc_update_irq(struct rtc_device *rtc, - unsigned long num, unsigned long events) +static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) { unsigned long flags; + /* mark one irq of the appropriate mode */ spin_lock_irqsave(&rtc->irq_lock, flags); - rtc->irq_data = (rtc->irq_data + (num << 8)) | events; + rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); spin_unlock_irqrestore(&rtc->irq_lock, flags); + /* call the task func */ spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task) rtc->irq_task->func(rtc->irq_task->private_data); @@ -391,6 +277,69 @@ void rtc_update_irq(struct rtc_device *rtc, wake_up_interruptible(&rtc->irq_queue); kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); } + + +/** + * rtc_aie_update_irq - AIE mode rtctimer hook + * @private: pointer to the rtc_device + * + * This functions is called when the aie_timer expires. + */ +void rtc_aie_update_irq(void *private) +{ + struct rtc_device *rtc = (struct rtc_device *)private; + rtc_handle_legacy_irq(rtc, 1, RTC_AF); +} + + +/** + * rtc_uie_update_irq - UIE mode rtctimer hook + * @private: pointer to the rtc_device + * + * This functions is called when the uie_timer expires. + */ +void rtc_uie_update_irq(void *private) +{ + struct rtc_device *rtc = (struct rtc_device *)private; + rtc_handle_legacy_irq(rtc, 1, RTC_UF); +} + + +/** + * rtc_pie_update_irq - PIE mode hrtimer hook + * @timer: pointer to the pie mode hrtimer + * + * This function is used to emulate PIE mode interrupts + * using an hrtimer. This function is called when the periodic + * hrtimer expires. + */ +enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) +{ + struct rtc_device *rtc; + ktime_t period; + int count; + rtc = container_of(timer, struct rtc_device, pie_timer); + + period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); + count = hrtimer_forward_now(timer, period); + + rtc_handle_legacy_irq(rtc, count, RTC_PF); + + return HRTIMER_RESTART; +} + +/** + * rtc_update_irq - Triggered when a RTC interrupt occurs. + * @rtc: the rtc device + * @num: how many irqs are being reported (usually one) + * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF + * Context: any + */ +void rtc_update_irq(struct rtc_device *rtc, + unsigned long num, unsigned long events) +{ + schedule_work(&rtc->irqwork); +} EXPORT_SYMBOL_GPL(rtc_update_irq); static int __rtc_match(struct device *dev, void *data) @@ -477,18 +426,20 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled int err = 0; unsigned long flags; - if (rtc->ops->irq_set_state == NULL) - return -ENXIO; - spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; if (rtc->irq_task != task) err = -EACCES; - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - if (err == 0) - err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); + if (enabled) { + ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); + hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&rtc->pie_timer); + } + rtc->pie_enabled = enabled; + spin_unlock_irqrestore(&rtc->irq_task_lock, flags); return err; } @@ -509,21 +460,194 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) int err = 0; unsigned long flags; - if (rtc->ops->irq_set_freq == NULL) - return -ENXIO; - spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; if (rtc->irq_task != task) err = -EACCES; - spin_unlock_irqrestore(&rtc->irq_task_lock, flags); - if (err == 0) { - err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); - if (err == 0) - rtc->irq_freq = freq; + rtc->irq_freq = freq; + if (rtc->pie_enabled) { + ktime_t period; + hrtimer_cancel(&rtc->pie_timer); + period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); + hrtimer_start(&rtc->pie_timer, period, + HRTIMER_MODE_REL); + } } + spin_unlock_irqrestore(&rtc->irq_task_lock, flags); return err; } EXPORT_SYMBOL_GPL(rtc_irq_set_freq); + +/** + * rtctimer_enqueue - Adds a rtc_timer to the rtc_device timerqueue + * @rtc rtc device + * @timer timer being added. + * + * Enqueues a timer onto the rtc devices timerqueue and sets + * the next alarm event appropriately. + * + * Must hold ops_lock for proper serialization of timerqueue + */ +void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) +{ + timerqueue_add(&rtc->timerqueue, &timer->node); + if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { + struct rtc_wkalrm alarm; + int err; + alarm.time = rtc_ktime_to_tm(timer->node.expires); + alarm.enabled = 1; + err = __rtc_set_alarm(rtc, &alarm); + if (err == -ETIME) + schedule_work(&rtc->irqwork); + } +} + +/** + * rtctimer_remove - Removes a rtc_timer from the rtc_device timerqueue + * @rtc rtc device + * @timer timer being removed. + * + * Removes a timer onto the rtc devices timerqueue and sets + * the next alarm event appropriately. + * + * Must hold ops_lock for proper serialization of timerqueue + */ +void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer) +{ + struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); + timerqueue_del(&rtc->timerqueue, &timer->node); + + if (next == &timer->node) { + struct rtc_wkalrm alarm; + int err; + next = timerqueue_getnext(&rtc->timerqueue); + if (!next) + return; + alarm.time = rtc_ktime_to_tm(next->expires); + alarm.enabled = 1; + err = __rtc_set_alarm(rtc, &alarm); + if (err == -ETIME) + schedule_work(&rtc->irqwork); + } +} + +/** + * rtctimer_do_work - Expires rtc timers + * @rtc rtc device + * @timer timer being removed. + * + * Expires rtc timers. Reprograms next alarm event if needed. + * Called via worktask. + * + * Serializes access to timerqueue via ops_lock mutex + */ +void rtctimer_do_work(struct work_struct *work) +{ + struct rtc_timer *timer; + struct timerqueue_node *next; + ktime_t now; + struct rtc_time tm; + + struct rtc_device *rtc = + container_of(work, struct rtc_device, irqwork); + + mutex_lock(&rtc->ops_lock); +again: + __rtc_read_time(rtc, &tm); + now = rtc_tm_to_ktime(tm); + while ((next = timerqueue_getnext(&rtc->timerqueue))) { + if (next->expires.tv64 > now.tv64) + break; + + /* expire timer */ + timer = container_of(next, struct rtc_timer, node); + timerqueue_del(&rtc->timerqueue, &timer->node); + timer->enabled = 0; + if (timer->task.func) + timer->task.func(timer->task.private_data); + + /* Re-add/fwd periodic timers */ + if (ktime_to_ns(timer->period)) { + timer->node.expires = ktime_add(timer->node.expires, + timer->period); + timer->enabled = 1; + timerqueue_add(&rtc->timerqueue, &timer->node); + } + } + + /* Set next alarm */ + if (next) { + struct rtc_wkalrm alarm; + int err; + alarm.time = rtc_ktime_to_tm(next->expires); + alarm.enabled = 1; + err = __rtc_set_alarm(rtc, &alarm); + if (err == -ETIME) + goto again; + } + + mutex_unlock(&rtc->ops_lock); +} + + +/* rtctimer_init - Initializes an rtc_timer + * @timer: timer to be intiialized + * @f: function pointer to be called when timer fires + * @data: private data passed to function pointer + * + * Kernel interface to initializing an rtc_timer. + */ +void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) +{ + timerqueue_init(&timer->node); + timer->enabled = 0; + timer->task.func = f; + timer->task.private_data = data; +} + +/* rtctimer_start - Sets an rtc_timer to fire in the future + * @ rtc: rtc device to be used + * @ timer: timer being set + * @ expires: time at which to expire the timer + * @ period: period that the timer will recur + * + * Kernel interface to set an rtc_timer + */ +int rtctimer_start(struct rtc_device *rtc, struct rtc_timer* timer, + ktime_t expires, ktime_t period) +{ + int ret = 0; + mutex_lock(&rtc->ops_lock); + if (timer->enabled) + rtctimer_remove(rtc, timer); + + timer->node.expires = expires; + timer->period = period; + + timer->enabled = 1; + rtctimer_enqueue(rtc, timer); + + mutex_unlock(&rtc->ops_lock); + return ret; +} + +/* rtctimer_cancel - Stops an rtc_timer + * @ rtc: rtc device to be used + * @ timer: timer being set + * + * Kernel interface to cancel an rtc_timer + */ +int rtctimer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) +{ + int ret = 0; + mutex_lock(&rtc->ops_lock); + if (timer->enabled) + rtctimer_remove(rtc, timer); + timer->enabled = 0; + mutex_unlock(&rtc->ops_lock); + return ret; +} + + diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 773851f338b8..075f1708deae 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -117,4 +117,32 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) } EXPORT_SYMBOL(rtc_tm_to_time); +/* + * Convert rtc_time to ktime + */ +ktime_t rtc_tm_to_ktime(struct rtc_time tm) +{ + time_t time; + rtc_tm_to_time(&tm, &time); + return ktime_set(time, 0); +} +EXPORT_SYMBOL_GPL(rtc_tm_to_ktime); + +/* + * Convert ktime to rtc_time + */ +struct rtc_time rtc_ktime_to_tm(ktime_t kt) +{ + struct timespec ts; + struct rtc_time ret; + + ts = ktime_to_timespec(kt); + /* Round up any ns */ + if (ts.tv_nsec) + ts.tv_sec++; + rtc_time_to_tm(ts.tv_sec, &ret); + return ret; +} +EXPORT_SYMBOL_GPL(rtc_ktime_to_tm); + MODULE_LICENSE("GPL"); diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 14dbc83ded20..a3421abca703 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -107,12 +107,17 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year extern int rtc_valid_tm(struct rtc_time *tm); extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); +ktime_t rtc_tm_to_ktime(struct rtc_time tm); +struct rtc_time rtc_ktime_to_tm(ktime_t kt); + #include #include #include #include #include +#include +#include extern struct class *rtc_class; @@ -151,7 +156,19 @@ struct rtc_class_ops { }; #define RTC_DEVICE_NAME_SIZE 20 -struct rtc_task; +typedef struct rtc_task { + void (*func)(void *private_data); + void *private_data; +} rtc_task_t; + + +struct rtc_timer { + struct rtc_task task; + struct timerqueue_node node; + ktime_t period; + int enabled; +}; + /* flags */ #define RTC_DEV_BUSY 0 @@ -179,6 +196,15 @@ struct rtc_device spinlock_t irq_task_lock; int irq_freq; int max_user_freq; + + struct timerqueue_head timerqueue; + struct rtc_timer aie_timer; + struct rtc_timer uie_rtctimer; + struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */ + int pie_enabled; + struct work_struct irqwork; + + #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL struct work_struct uie_task; struct timer_list uie_timer; @@ -224,15 +250,22 @@ extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled); extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled); -typedef struct rtc_task { - void (*func)(void *private_data); - void *private_data; -} rtc_task_t; +void rtc_aie_update_irq(void *private); +void rtc_uie_update_irq(void *private); +enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer); int rtc_register(rtc_task_t *task); int rtc_unregister(rtc_task_t *task); int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); +void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer); +void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer); +void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data); +int rtctimer_start(struct rtc_device *rtc, struct rtc_timer* timer, + ktime_t expires, ktime_t period); +int rtctimer_cancel(struct rtc_device *rtc, struct rtc_timer* timer); +void rtctimer_do_work(struct work_struct *work); + static inline bool is_leap_year(unsigned int year) { return (!(year % 4) && (year % 100)) || !(year % 400); -- cgit v1.2.3 From 042620a018afcfba1d678062b62e463b9e43a68d Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 14 Oct 2010 16:22:33 -0700 Subject: RTC: Remove UIE emulation Since we provide UIE interrupts via a rtc_timer, the old emulation code can be removed. Signed-off-by: John Stultz LKML Reference: <1290136329-18291-5-git-send-email-john.stultz@linaro.org> Acked-by: Alessandro Zummo Reviewed-by: Thomas Gleixner CC: Alessandro Zummo CC: Thomas Gleixner CC: Richard Cochran --- drivers/rtc/rtc-dev.c | 104 -------------------------------------------------- include/linux/rtc.h | 12 ------ 2 files changed, 116 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 62227cd52410..212b16edafc0 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -46,105 +46,6 @@ static int rtc_dev_open(struct inode *inode, struct file *file) return err; } -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL -/* - * Routine to poll RTC seconds field for change as often as possible, - * after first RTC_UIE use timer to reduce polling - */ -static void rtc_uie_task(struct work_struct *work) -{ - struct rtc_device *rtc = - container_of(work, struct rtc_device, uie_task); - struct rtc_time tm; - int num = 0; - int err; - - err = rtc_read_time(rtc, &tm); - - spin_lock_irq(&rtc->irq_lock); - if (rtc->stop_uie_polling || err) { - rtc->uie_task_active = 0; - } else if (rtc->oldsecs != tm.tm_sec) { - num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; - rtc->oldsecs = tm.tm_sec; - rtc->uie_timer.expires = jiffies + HZ - (HZ/10); - rtc->uie_timer_active = 1; - rtc->uie_task_active = 0; - add_timer(&rtc->uie_timer); - } else if (schedule_work(&rtc->uie_task) == 0) { - rtc->uie_task_active = 0; - } - spin_unlock_irq(&rtc->irq_lock); - if (num) - rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF); -} -static void rtc_uie_timer(unsigned long data) -{ - struct rtc_device *rtc = (struct rtc_device *)data; - unsigned long flags; - - spin_lock_irqsave(&rtc->irq_lock, flags); - rtc->uie_timer_active = 0; - rtc->uie_task_active = 1; - if ((schedule_work(&rtc->uie_task) == 0)) - rtc->uie_task_active = 0; - spin_unlock_irqrestore(&rtc->irq_lock, flags); -} - -static int clear_uie(struct rtc_device *rtc) -{ - spin_lock_irq(&rtc->irq_lock); - if (rtc->uie_irq_active) { - rtc->stop_uie_polling = 1; - if (rtc->uie_timer_active) { - spin_unlock_irq(&rtc->irq_lock); - del_timer_sync(&rtc->uie_timer); - spin_lock_irq(&rtc->irq_lock); - rtc->uie_timer_active = 0; - } - if (rtc->uie_task_active) { - spin_unlock_irq(&rtc->irq_lock); - flush_scheduled_work(); - spin_lock_irq(&rtc->irq_lock); - } - rtc->uie_irq_active = 0; - } - spin_unlock_irq(&rtc->irq_lock); - return 0; -} - -static int set_uie(struct rtc_device *rtc) -{ - struct rtc_time tm; - int err; - - err = rtc_read_time(rtc, &tm); - if (err) - return err; - spin_lock_irq(&rtc->irq_lock); - if (!rtc->uie_irq_active) { - rtc->uie_irq_active = 1; - rtc->stop_uie_polling = 0; - rtc->oldsecs = tm.tm_sec; - rtc->uie_task_active = 1; - if (schedule_work(&rtc->uie_task) == 0) - rtc->uie_task_active = 0; - } - rtc->irq_data = 0; - spin_unlock_irq(&rtc->irq_lock); - return 0; -} - -int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) -{ - if (enabled) - return set_uie(rtc); - else - return clear_uie(rtc); -} -EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); - -#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ static ssize_t rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -493,11 +394,6 @@ void rtc_dev_prepare(struct rtc_device *rtc) rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - INIT_WORK(&rtc->uie_task, rtc_uie_task); - setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); -#endif - cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; } diff --git a/include/linux/rtc.h b/include/linux/rtc.h index a3421abca703..44e18a2523a3 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -203,18 +203,6 @@ struct rtc_device struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */ int pie_enabled; struct work_struct irqwork; - - -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - struct work_struct uie_task; - struct timer_list uie_timer; - /* Those fields are protected by rtc->irq_lock */ - unsigned int oldsecs; - unsigned int uie_irq_active:1; - unsigned int stop_uie_polling:1; - unsigned int uie_task_active:1; - unsigned int uie_timer_active:1; -#endif }; #define to_rtc_device(d) container_of(d, struct rtc_device, dev) -- cgit v1.2.3 From c4ffafa51bb0bea648a4ca119033a95057799c9d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 11 Dec 2010 17:51:36 +0100 Subject: HID: hid-picolcd: don't use flush_scheduled_work() flush_scheduled_work() is deprecated and scheduled to be removed. Directly flush picolcd_fb_cleanup on exit instead. Signed-off-by: Tejun Heo Cc: Jiri Kosina Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index e4ce47156106..ed0e066b7f07 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -2750,7 +2750,7 @@ static void __exit picolcd_exit(void) { hid_unregister_driver(&picolcd_driver); #ifdef CONFIG_HID_PICOLCD_FB - flush_scheduled_work(); + flush_work_sync(&picolcd_fb_cleanup); WARN_ON(fb_pending); #endif } -- cgit v1.2.3 From 60a74a6ff86b4e90b9558956589390efdeb4e924 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 23 Oct 2010 13:18:56 +0200 Subject: firewire: nosy: char device is not seekable Amend .open handler accordingly and remove the .llseek handler. .llseek = NULL means no_llseek (return error) since commit 776c163b1b93. The only client that uses this interface is nosy-dump in linux/tools/firewire and it knows not to seek in this char dev. Signed-off-by: Stefan Richter --- drivers/firewire/nosy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index bf184fb59a5e..0618145376ad 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -302,7 +302,7 @@ nosy_open(struct inode *inode, struct file *file) file->private_data = client; - return 0; + return nonseekable_open(inode, file); fail: kfree(client); lynx_put(lynx); @@ -405,7 +405,6 @@ static const struct file_operations nosy_ops = { .poll = nosy_poll, .open = nosy_open, .release = nosy_release, - .llseek = noop_llseek, }; #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ -- cgit v1.2.3 From 5878730be4e3d0c9527d6f2f688874e38acacc98 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 30 Oct 2010 14:08:27 -0700 Subject: firewire: core: Update WARN uses Add missing newlines. Signed-off-by: Joe Perches Signed-off-by: Stefan Richter --- drivers/firewire/core-transaction.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index b42a0bde8494..ad864d8cd5e4 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -250,7 +250,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, break; default: - WARN(1, "wrong tcode %d", tcode); + WARN(1, "wrong tcode %d\n", tcode); } common: packet->speed = speed; @@ -638,7 +638,7 @@ int fw_get_response_length(struct fw_request *r) } default: - WARN(1, "wrong tcode %d", tcode); + WARN(1, "wrong tcode %d\n", tcode); return 0; } } @@ -694,7 +694,7 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header, break; default: - WARN(1, "wrong tcode %d", tcode); + WARN(1, "wrong tcode %d\n", tcode); } response->payload_mapped = false; -- cgit v1.2.3 From 5a7743edac3d720a52e721229938d21d40f045ce Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Dec 2010 15:07:40 +0000 Subject: regulator: Update LDO2 for WM8958 LDO2 has a slightly different range of supported voltages on WM8958 so update the selector<->voltage mappings to match. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- drivers/regulator/wm8994-regulator.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 03713bc66e4a..21fefef02a43 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -131,10 +131,19 @@ static struct regulator_ops wm8994_ldo1_ops = { static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, unsigned int selector) { + struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); + if (selector > WM8994_LDO2_MAX_SELECTOR) return -EINVAL; - return (selector * 100000) + 900000; + switch (ldo->wm8994->type) { + case WM8994: + return (selector * 100000) + 900000; + case WM8958: + return (selector * 100000) + 1000000; + default: + return -EINVAL; + } } static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) @@ -157,7 +166,17 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; - selector = (min_uV - 900000) / 100000; + switch (ldo->wm8994->type) { + case WM8994: + selector = (min_uV - 900000) / 100000; + break; + case WM8958: + selector = (min_uV - 1000000) / 100000; + break; + default: + return -EINVAL; + } + v = wm8994_ldo2_list_voltage(rdev, selector); if (v < 0 || v > max_uV) return -EINVAL; -- cgit v1.2.3 From 448d40140196b33f63a0a3f3f8bcad8f14c9c432 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Mon, 13 Dec 2010 10:39:20 +0100 Subject: staging: ft1000: Always extract device number from netdev name. Using gCardIndex as global variable was not correctly used because for every plugged device was set to 0 in init_ft1000_netdev. Remove global definition. Use it locally and for every plugged device extract number from net device name. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 7456787481c8..643a63794ade 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -41,7 +41,6 @@ static int ft1000_chkcard (struct ft1000_device *dev); //Jim static u8 tempbuffer[1600]; -static unsigned long gCardIndex; #define MAX_RCV_LOOP 100 @@ -773,8 +772,7 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev) int i, ret_val; struct list_head *cur, *tmp; char card_nr[2]; - - gCardIndex=0; //mbelian + unsigned long gCardIndex = 0; DEBUG("Enter init_ft1000_netdev...\n"); @@ -794,9 +792,6 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev) dev_alloc_name(netdev, netdev->name); - //for the first inserted card, decide the card index beginning number, in case there are existing network interfaces - if ( gCardIndex == 0 ) - { DEBUG("init_ft1000_netdev: network device name is %s\n", netdev->name); if ( strncmp(netdev->name,"eth", 3) == 0) { @@ -816,13 +811,6 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev) ret_val = -ENXIO; goto err_net; } - } - else - { - //not the first inserted card, increase card number by 1 - pInfo->CardNumber = gCardIndex; - /*DEBUG("card number = %d\n", pInfo->CardNumber);*/ //mbelian - } memset(&pInfo->stats, 0, sizeof(struct net_device_stats) ); -- cgit v1.2.3 From ed271e049d4e0bf8c6586c9626964a01d1c62fa2 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 10 Dec 2010 21:07:25 +0200 Subject: Staging: comedi: Fix coding style issues in ni_tiocmd.c This patch fixes the following issues in ni_tiocmd.c: WARNING: braces {} are not necessary for any arm of this statement WARNING: braces {} are not necessary for single statement blocks WARNING: printk() should include KERN_ facility level WARNING: line over 80 characters __func__ should be used instead of gcc specific __FUNCTION__ ERROR: that open brace { should be on the previous line WARNING: EXPORT_SYMBOL(foo); should immediately follow its function/variable Signed-off-by: Xenofon Foukas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_tiocmd.c | 71 ++++++++++++++---------------- 1 file changed, 33 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index b0d44b547a69..a9611587460a 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -62,11 +62,10 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, unsigned input_select_bits = 0; if (enable) { - if (read_not_write) { + if (read_not_write) input_select_bits |= Gi_Read_Acknowledges_Irq; - } else { + else input_select_bits |= Gi_Write_Acknowledges_Irq; - } } ni_tio_set_bits(counter, NITIO_Gi_Input_Select_Reg(counter->counter_index), @@ -84,9 +83,8 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, gi_dma_config_bits |= Gi_DMA_Enable_Bit; gi_dma_config_bits |= Gi_DMA_Int_Bit; } - if (read_not_write == 0) { + if (read_not_write == 0) gi_dma_config_bits |= Gi_DMA_Write_Bit; - } ni_tio_set_bits(counter, NITIO_Gi_DMA_Config_Reg(counter-> counter_index), @@ -174,7 +172,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) static int ni_tio_output_cmd(struct ni_gpct *counter, struct comedi_async *async) { - printk("ni_tio: output commands not yet implemented.\n"); + printk(KERN_ERR "ni_tio: output commands not yet implemented.\n"); return -ENOTSUPP; counter->mite_chan->dir = COMEDI_OUTPUT; @@ -198,9 +196,8 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async) set_gate_source = 1; gate_source = cmd->convert_arg; } - if (set_gate_source) { + if (set_gate_source) retval = ni_tio_set_gate_src(counter, 0, gate_source); - } if (cmd->flags & TRIG_WAKE_EOS) { ni_tio_set_bits(counter, NITIO_Gi_Interrupt_Enable_Reg(counter-> @@ -221,22 +218,21 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) spin_lock_irqsave(&counter->lock, flags); if (counter->mite_chan == NULL) { - printk - ("ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n"); + printk(KERN_ERR "ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n"); retval = -EIO; } else { retval = ni_tio_cmd_setup(counter, async); if (retval == 0) { - if (cmd->flags & CMDF_WRITE) { + if (cmd->flags & CMDF_WRITE) retval = ni_tio_output_cmd(counter, async); - } else { + else retval = ni_tio_input_cmd(counter, async); - } } } spin_unlock_irqrestore(&counter->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(ni_tio_cmd); int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) { @@ -342,6 +338,7 @@ int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) return 0; } +EXPORT_SYMBOL_GPL(ni_tio_cmdtest); int ni_tio_cancel(struct ni_gpct *counter) { @@ -349,9 +346,8 @@ int ni_tio_cancel(struct ni_gpct *counter) ni_tio_arm(counter, 0, 0); spin_lock_irqsave(&counter->lock, flags); - if (counter->mite_chan) { + if (counter->mite_chan) mite_dma_disarm(counter->mite_chan); - } spin_unlock_irqrestore(&counter->lock, flags); ni_tio_configure_dma(counter, 0, 0); @@ -361,10 +357,11 @@ int ni_tio_cancel(struct ni_gpct *counter) 0x0); return 0; } +EXPORT_SYMBOL_GPL(ni_tio_cancel); - /* During buffered input counter operation for e-series, the gate interrupt is acked - automatically by the dma controller, due to the Gi_Read/Write_Acknowledges_IRQ bits - in the input select register. */ + /* During buffered input counter operation for e-series, the gate + interrupt is acked automatically by the dma controller, due to the + Gi_Read/Write_Acknowledges_IRQ bits in the input select register. */ static int should_ack_gate(struct ni_gpct *counter) { unsigned long flags; @@ -372,7 +369,10 @@ static int should_ack_gate(struct ni_gpct *counter) switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: - case ni_gpct_variant_660x: /* not sure if 660x really supports gate interrupts (the bits are not listed in register-level manual) */ + /* not sure if 660x really supports gate + interrupts (the bits are not listed + in register-level manual) */ + case ni_gpct_variant_660x: return 1; break; case ni_gpct_variant_e_series: @@ -416,7 +416,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) { ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index); if (gate_error) { - /*660x don't support automatic acknowledgement of gate interrupt via dma read/write + /*660x don't support automatic acknowledgement + of gate interrupt via dma read/write and report bogus gate errors */ if (counter->counter_dev->variant != ni_gpct_variant_660x) { @@ -429,9 +430,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, if (tc_error) *tc_error = 1; } - if (gi_status & Gi_TC_Bit) { + if (gi_status & Gi_TC_Bit) ack |= Gi_TC_Interrupt_Ack_Bit; - } if (gi_status & Gi_Gate_Interrupt_Bit) { if (should_ack_gate(counter)) ack |= Gi_Gate_Interrupt_Ack_Bit; @@ -452,13 +452,14 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, NITIO_Gxx_Joint_Status2_Reg (counter->counter_index)) & Gi_Permanent_Stale_Bit(counter->counter_index)) { - printk("%s: Gi_Permanent_Stale_Data detected.\n", - __FUNCTION__); + printk(KERN_INFO "%s: Gi_Permanent_Stale_Data detected.\n", + __func__); if (perm_stale_data) *perm_stale_data = 1; } } } +EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm); void ni_tio_handle_interrupt(struct ni_gpct *counter, struct comedi_subdevice *s) @@ -472,20 +473,19 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error, &perm_stale_data, NULL); if (gate_error) { - printk("%s: Gi_Gate_Error detected.\n", __FUNCTION__); + printk(KERN_NOTICE "%s: Gi_Gate_Error detected.\n", __func__); s->async->events |= COMEDI_CB_OVERFLOW; } - if (perm_stale_data) { + if (perm_stale_data) s->async->events |= COMEDI_CB_ERROR; - } switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: if (read_register(counter, - NITIO_Gi_DMA_Status_Reg - (counter->counter_index)) & Gi_DRQ_Error_Bit) - { - printk("%s: Gi_DRQ_Error detected.\n", __FUNCTION__); + NITIO_Gi_DMA_Status_Reg + (counter->counter_index)) & Gi_DRQ_Error_Bit) { + printk(KERN_NOTICE "%s: Gi_DRQ_Error detected.\n", + __func__); s->async->events |= COMEDI_CB_OVERFLOW; } break; @@ -506,6 +506,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, mite_sync_input_dma(counter->mite_chan, s->async); spin_unlock_irqrestore(&counter->lock, flags); } +EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt); void ni_tio_set_mite_channel(struct ni_gpct *counter, struct mite_channel *mite_chan) @@ -516,6 +517,7 @@ void ni_tio_set_mite_channel(struct ni_gpct *counter, counter->mite_chan = mite_chan; spin_unlock_irqrestore(&counter->lock, flags); } +EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel); static int __init ni_tiocmd_init_module(void) { @@ -529,10 +531,3 @@ static void __exit ni_tiocmd_cleanup_module(void) } module_exit(ni_tiocmd_cleanup_module); - -EXPORT_SYMBOL_GPL(ni_tio_cmd); -EXPORT_SYMBOL_GPL(ni_tio_cmdtest); -EXPORT_SYMBOL_GPL(ni_tio_cancel); -EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt); -EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel); -EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm); -- cgit v1.2.3 From 6292817d58637f85dd623cfe563c7f5ec4f4c470 Mon Sep 17 00:00:00 2001 From: Ruben Smits Date: Sat, 11 Dec 2010 08:26:18 +0100 Subject: staging: comedi: add support for newer jr3 1-channel pci board add DEVICE_ID to table Signed-off-by: Ruben Smits Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/jr3_pci.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 8b383ee959b2..5c6c72744167 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -54,6 +54,7 @@ Devices: [JR3] PCI force sensor board (jr3_pci) #define PCI_VENDOR_ID_JR3 0x1762 #define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 +#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111 #define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 #define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 #define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 @@ -73,6 +74,8 @@ static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { { PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { + PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL, @@ -807,6 +810,10 @@ static int jr3_pci_attach(struct comedi_device *dev, devpriv->n_channels = 1; } break; + case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW:{ + devpriv->n_channels = 1; + } + break; case PCI_DEVICE_ID_JR3_2_CHANNEL:{ devpriv->n_channels = 2; } -- cgit v1.2.3 From ced17a68b727d8509a4bde0b2ee7d0d120371e66 Mon Sep 17 00:00:00 2001 From: "L. Alberto Giménez" Date: Sun, 12 Dec 2010 18:56:29 +0100 Subject: Staging: rt2860: Clean spaces before tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix checkpatch complains Signed-off-by: L. Alberto Giménez Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/oid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/oid.h b/drivers/staging/rt2860/oid.h index eaa3fe005088..5a25f0d3cfeb 100644 --- a/drivers/staging/rt2860/oid.h +++ b/drivers/staging/rt2860/oid.h @@ -88,7 +88,7 @@ #define MAX_NUMBER_OF_DLS_ENTRY 4 #define RT_QUERY_SIGNAL_CONTEXT 0x0402 -#define RT_SET_IAPP_PID 0x0404 +#define RT_SET_IAPP_PID 0x0404 #define RT_SET_APD_PID 0x0405 #define RT_SET_DEL_MAC_ENTRY 0x0406 #define RT_QUERY_EVENT_TABLE 0x0407 -- cgit v1.2.3 From e1b8a37ede8b47dbad002ec61a67706b70b23ccf Mon Sep 17 00:00:00 2001 From: "L. Alberto Giménez" Date: Sun, 12 Dec 2010 18:56:30 +0100 Subject: Staging: rt2860: Avoid extern in .c file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rt28xx_close and rt28xx_open are already declared in a file included in rt_config.h, so there is no need to declare them again. Signed-off-by: L. Alberto Giménez Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/pci_main_dev.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/pci_main_dev.c b/drivers/staging/rt2860/pci_main_dev.c index c35c804a083e..cd028e7a8f91 100644 --- a/drivers/staging/rt2860/pci_main_dev.c +++ b/drivers/staging/rt2860/pci_main_dev.c @@ -51,9 +51,6 @@ MODULE_ALIAS("rt3090sta"); /* */ /* Function declarations */ /* */ -extern int rt28xx_close(IN struct net_device *net_dev); -extern int rt28xx_open(struct net_device *net_dev); - static void __devexit rt2860_remove_one(struct pci_dev *pci_dev); static int __devinit rt2860_probe(struct pci_dev *pci_dev, const struct pci_device_id *ent); -- cgit v1.2.3 From 85799a37553f89b23797ec4f69e45f6c5e9109df Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:03:54 -0800 Subject: staging: hv: Convert camel cased variables in netvsc.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc.c | 852 +++++++++++++++++++++++--------------------- 1 file changed, 445 insertions(+), 407 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index 8022781a9b13..1c1ee57482a5 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -31,141 +31,141 @@ /* Globals */ -static const char *gDriverName = "netvsc"; +static const char *driver_name = "netvsc"; /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ -static const struct hv_guid gNetVscDeviceType = { +static const struct hv_guid netvsc_device_type = { .data = { 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E } }; -static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo); +static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info); -static int NetVscOnDeviceRemove(struct hv_device *Device); +static int NetVscOnDeviceRemove(struct hv_device *device); -static void NetVscOnCleanup(struct hv_driver *Driver); +static void NetVscOnCleanup(struct hv_driver *driver); static void NetVscOnChannelCallback(void *context); -static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device); +static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *device); -static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device); +static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *device); -static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice); +static int NetVscDestroySendBuffer(struct netvsc_device *net_device); -static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice); +static int NetVscDestroyReceiveBuffer(struct netvsc_device *net_device); -static int NetVscConnectToVsp(struct hv_device *Device); +static int NetVscConnectToVsp(struct hv_device *device); -static void NetVscOnSendCompletion(struct hv_device *Device, - struct vmpacket_descriptor *Packet); +static void NetVscOnSendCompletion(struct hv_device *device, + struct vmpacket_descriptor *packet); -static int NetVscOnSend(struct hv_device *Device, - struct hv_netvsc_packet *Packet); +static int NetVscOnSend(struct hv_device *device, + struct hv_netvsc_packet *packet); -static void NetVscOnReceive(struct hv_device *Device, - struct vmpacket_descriptor *Packet); +static void NetVscOnReceive(struct hv_device *device, + struct vmpacket_descriptor *packet); -static void NetVscOnReceiveCompletion(void *Context); +static void NetVscOnReceiveCompletion(void *context); -static void NetVscSendReceiveCompletion(struct hv_device *Device, - u64 TransactionId); +static void NetVscSendReceiveCompletion(struct hv_device *device, + u64 transaction_id); -static struct netvsc_device *AllocNetDevice(struct hv_device *Device) +static struct netvsc_device *AllocNetDevice(struct hv_device *device) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; - netDevice = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL); - if (!netDevice) + net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL); + if (!net_device) return NULL; /* Set to 2 to allow both inbound and outbound traffic */ - atomic_cmpxchg(&netDevice->RefCount, 0, 2); + atomic_cmpxchg(&net_device->RefCount, 0, 2); - netDevice->Device = Device; - Device->Extension = netDevice; + net_device->Device = device; + device->Extension = net_device; - return netDevice; + return net_device; } -static void FreeNetDevice(struct netvsc_device *Device) +static void FreeNetDevice(struct netvsc_device *device) { - WARN_ON(atomic_read(&Device->RefCount) == 0); - Device->Device->Extension = NULL; - kfree(Device); + WARN_ON(atomic_read(&device->RefCount) == 0); + device->Device->Extension = NULL; + kfree(device); } /* Get the net device object iff exists and its refcount > 1 */ -static struct netvsc_device *GetOutboundNetDevice(struct hv_device *Device) +static struct netvsc_device *GetOutboundNetDevice(struct hv_device *device) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; - netDevice = Device->Extension; - if (netDevice && atomic_read(&netDevice->RefCount) > 1) - atomic_inc(&netDevice->RefCount); + net_device = device->Extension; + if (net_device && atomic_read(&net_device->RefCount) > 1) + atomic_inc(&net_device->RefCount); else - netDevice = NULL; + net_device = NULL; - return netDevice; + return net_device; } /* Get the net device object iff exists and its refcount > 0 */ -static struct netvsc_device *GetInboundNetDevice(struct hv_device *Device) +static struct netvsc_device *GetInboundNetDevice(struct hv_device *device) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; - netDevice = Device->Extension; - if (netDevice && atomic_read(&netDevice->RefCount)) - atomic_inc(&netDevice->RefCount); + net_device = device->Extension; + if (net_device && atomic_read(&net_device->RefCount)) + atomic_inc(&net_device->RefCount); else - netDevice = NULL; + net_device = NULL; - return netDevice; + return net_device; } -static void PutNetDevice(struct hv_device *Device) +static void PutNetDevice(struct hv_device *device) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; - netDevice = Device->Extension; + net_device = device->Extension; /* ASSERT(netDevice); */ - atomic_dec(&netDevice->RefCount); + atomic_dec(&net_device->RefCount); } -static struct netvsc_device *ReleaseOutboundNetDevice(struct hv_device *Device) +static struct netvsc_device *ReleaseOutboundNetDevice(struct hv_device *device) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; - netDevice = Device->Extension; - if (netDevice == NULL) + net_device = device->Extension; + if (net_device == NULL) return NULL; /* Busy wait until the ref drop to 2, then set it to 1 */ - while (atomic_cmpxchg(&netDevice->RefCount, 2, 1) != 2) + while (atomic_cmpxchg(&net_device->RefCount, 2, 1) != 2) udelay(100); - return netDevice; + return net_device; } -static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *Device) +static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *device) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; - netDevice = Device->Extension; - if (netDevice == NULL) + net_device = device->Extension; + if (net_device == NULL) return NULL; /* Busy wait until the ref drop to 1, then set it to 0 */ - while (atomic_cmpxchg(&netDevice->RefCount, 1, 0) != 1) + while (atomic_cmpxchg(&net_device->RefCount, 1, 0) != 1) udelay(100); - Device->Extension = NULL; - return netDevice; + device->Extension = NULL; + return net_device; } /* @@ -185,8 +185,8 @@ int NetVscInitialize(struct hv_driver *drv) /* Make sure we are at least 2 pages since 1 page is used for control */ /* ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); */ - drv->name = gDriverName; - memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(struct hv_guid)); + drv->name = driver_name; + memcpy(&drv->deviceType, &netvsc_device_type, sizeof(struct hv_guid)); /* Make sure it is set by the caller */ /* FIXME: These probably should still be tested in some way */ @@ -204,14 +204,14 @@ int NetVscInitialize(struct hv_driver *drv) return 0; } -static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) +static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *device) { int ret = 0; - struct netvsc_device *netDevice; - struct nvsp_message *initPacket; + struct netvsc_device *net_device; + struct nvsp_message *init_packet; - netDevice = GetOutboundNetDevice(Device); - if (!netDevice) { + net_device = GetOutboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); return -1; @@ -220,12 +220,12 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) /* page-size grandularity */ /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */ - netDevice->ReceiveBuffer = - osd_page_alloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT); - if (!netDevice->ReceiveBuffer) { + net_device->ReceiveBuffer = + osd_page_alloc(net_device->ReceiveBufferSize >> PAGE_SHIFT); + if (!net_device->ReceiveBuffer) { DPRINT_ERR(NETVSC, "unable to allocate receive buffer of size %d", - netDevice->ReceiveBufferSize); + net_device->ReceiveBufferSize); ret = -1; goto Cleanup; } @@ -240,9 +240,9 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) * channel. Note: This call uses the vmbus connection rather * than the channel to establish the gpadl handle. */ - ret = vmbus_establish_gpadl(Device->channel, netDevice->ReceiveBuffer, - netDevice->ReceiveBufferSize, - &netDevice->ReceiveBufferGpadlHandle); + ret = vmbus_establish_gpadl(device->channel, net_device->ReceiveBuffer, + net_device->ReceiveBufferSize, + &net_device->ReceiveBufferGpadlHandle); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to establish receive buffer's gpadl"); @@ -254,18 +254,20 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) /* Notify the NetVsp of the gpadl handle */ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer..."); - initPacket = &netDevice->ChannelInitPacket; + init_packet = &net_device->ChannelInitPacket; - memset(initPacket, 0, sizeof(struct nvsp_message)); + memset(init_packet, 0, sizeof(struct nvsp_message)); - initPacket->Header.MessageType = NvspMessage1TypeSendReceiveBuffer; - initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->ReceiveBufferGpadlHandle; - initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; + init_packet->Header.MessageType = NvspMessage1TypeSendReceiveBuffer; + init_packet->Messages.Version1Messages.SendReceiveBuffer. + GpadlHandle = net_device->ReceiveBufferGpadlHandle; + init_packet->Messages.Version1Messages. + SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; /* Send the gpadl notification request */ - ret = vmbus_sendpacket(Device->channel, initPacket, + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)initPacket, + (unsigned long)init_packet, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) { @@ -274,13 +276,15 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(netDevice->ChannelInitEvent); + osd_waitevent_wait(net_device->ChannelInitEvent); /* Check the response */ - if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess) { + if (init_packet->Messages.Version1Messages. + SendReceiveBufferComplete.Status != NvspStatusSuccess) { DPRINT_ERR(NETVSC, "Unable to complete receive buffer " "initialzation with NetVsp - status %d", - initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status); + init_packet->Messages.Version1Messages. + SendReceiveBufferComplete.Status); ret = -1; goto Cleanup; } @@ -289,32 +293,36 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) /* ASSERT(netDevice->ReceiveSectionCount == 0); */ /* ASSERT(netDevice->ReceiveSections == NULL); */ - netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections; + net_device->ReceiveSectionCount = init_packet->Messages. + Version1Messages.SendReceiveBufferComplete.NumSections; - netDevice->ReceiveSections = kmalloc(netDevice->ReceiveSectionCount * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL); - if (netDevice->ReceiveSections == NULL) { + net_device->ReceiveSections = kmalloc(net_device->ReceiveSectionCount + * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL); + if (net_device->ReceiveSections == NULL) { ret = -1; goto Cleanup; } - memcpy(netDevice->ReceiveSections, - initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Sections, - netDevice->ReceiveSectionCount * sizeof(struct nvsp_1_receive_buffer_section)); + memcpy(net_device->ReceiveSections, + init_packet->Messages.Version1Messages. + SendReceiveBufferComplete.Sections, + net_device->ReceiveSectionCount * + sizeof(struct nvsp_1_receive_buffer_section)); DPRINT_INFO(NETVSC, "Receive sections info (count %d, offset %d, " "endoffset %d, suballoc size %d, num suballocs %d)", - netDevice->ReceiveSectionCount, - netDevice->ReceiveSections[0].Offset, - netDevice->ReceiveSections[0].EndOffset, - netDevice->ReceiveSections[0].SubAllocationSize, - netDevice->ReceiveSections[0].NumSubAllocations); + net_device->ReceiveSectionCount, + net_device->ReceiveSections[0].Offset, + net_device->ReceiveSections[0].EndOffset, + net_device->ReceiveSections[0].SubAllocationSize, + net_device->ReceiveSections[0].NumSubAllocations); /* * For 1st release, there should only be 1 section that represents the * entire receive buffer */ - if (netDevice->ReceiveSectionCount != 1 || - netDevice->ReceiveSections->Offset != 0) { + if (net_device->ReceiveSectionCount != 1 || + net_device->ReceiveSections->Offset != 0) { ret = -1; goto Cleanup; } @@ -322,26 +330,26 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device) goto Exit; Cleanup: - NetVscDestroyReceiveBuffer(netDevice); + NetVscDestroyReceiveBuffer(net_device); Exit: - PutNetDevice(Device); + PutNetDevice(device); return ret; } -static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) +static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *device) { int ret = 0; - struct netvsc_device *netDevice; - struct nvsp_message *initPacket; + struct netvsc_device *net_device; + struct nvsp_message *init_packet; - netDevice = GetOutboundNetDevice(Device); - if (!netDevice) { + net_device = GetOutboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); return -1; } - if (netDevice->SendBufferSize <= 0) { + if (net_device->SendBufferSize <= 0) { ret = -EINVAL; goto Cleanup; } @@ -349,11 +357,11 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) /* page-size grandularity */ /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */ - netDevice->SendBuffer = - osd_page_alloc(netDevice->SendBufferSize >> PAGE_SHIFT); - if (!netDevice->SendBuffer) { + net_device->SendBuffer = + osd_page_alloc(net_device->SendBufferSize >> PAGE_SHIFT); + if (!net_device->SendBuffer) { DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", - netDevice->SendBufferSize); + net_device->SendBufferSize); ret = -1; goto Cleanup; } @@ -367,9 +375,9 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) * channel. Note: This call uses the vmbus connection rather * than the channel to establish the gpadl handle. */ - ret = vmbus_establish_gpadl(Device->channel, netDevice->SendBuffer, - netDevice->SendBufferSize, - &netDevice->SendBufferGpadlHandle); + ret = vmbus_establish_gpadl(device->channel, net_device->SendBuffer, + net_device->SendBufferSize, + &net_device->SendBufferGpadlHandle); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl"); goto Cleanup; @@ -380,18 +388,20 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) /* Notify the NetVsp of the gpadl handle */ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer..."); - initPacket = &netDevice->ChannelInitPacket; + init_packet = &net_device->ChannelInitPacket; - memset(initPacket, 0, sizeof(struct nvsp_message)); + memset(init_packet, 0, sizeof(struct nvsp_message)); - initPacket->Header.MessageType = NvspMessage1TypeSendSendBuffer; - initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->SendBufferGpadlHandle; - initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID; + init_packet->Header.MessageType = NvspMessage1TypeSendSendBuffer; + init_packet->Messages.Version1Messages.SendReceiveBuffer. + GpadlHandle = net_device->SendBufferGpadlHandle; + init_packet->Messages.Version1Messages.SendReceiveBuffer.Id = + NETVSC_SEND_BUFFER_ID; /* Send the gpadl notification request */ - ret = vmbus_sendpacket(Device->channel, initPacket, + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)initPacket, + (unsigned long)init_packet, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret != 0) { @@ -400,32 +410,35 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(netDevice->ChannelInitEvent); + osd_waitevent_wait(net_device->ChannelInitEvent); /* Check the response */ - if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess) { + if (init_packet->Messages.Version1Messages. + SendSendBufferComplete.Status != NvspStatusSuccess) { DPRINT_ERR(NETVSC, "Unable to complete send buffer " "initialzation with NetVsp - status %d", - initPacket->Messages.Version1Messages.SendSendBufferComplete.Status); + init_packet->Messages.Version1Messages. + SendSendBufferComplete.Status); ret = -1; goto Cleanup; } - netDevice->SendSectionSize = initPacket->Messages.Version1Messages.SendSendBufferComplete.SectionSize; + net_device->SendSectionSize = init_packet-> + Messages.Version1Messages.SendSendBufferComplete.SectionSize; goto Exit; Cleanup: - NetVscDestroySendBuffer(netDevice); + NetVscDestroySendBuffer(net_device); Exit: - PutNetDevice(Device); + PutNetDevice(device); return ret; } -static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice) +static int NetVscDestroyReceiveBuffer(struct netvsc_device *net_device) { - struct nvsp_message *revokePacket; + struct nvsp_message *revoke_packet; int ret = 0; /* @@ -434,20 +447,23 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice) * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need * to send a revoke msg here */ - if (NetDevice->ReceiveSectionCount) { + if (net_device->ReceiveSectionCount) { DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeReceiveBuffer..."); /* Send the revoke receive buffer */ - revokePacket = &NetDevice->RevokePacket; - memset(revokePacket, 0, sizeof(struct nvsp_message)); + revoke_packet = &net_device->RevokePacket; + memset(revoke_packet, 0, sizeof(struct nvsp_message)); - revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer; - revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; + revoke_packet->Header.MessageType = + NvspMessage1TypeRevokeReceiveBuffer; + revoke_packet->Messages.Version1Messages. + RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; - ret = vmbus_sendpacket(NetDevice->Device->channel, revokePacket, + ret = vmbus_sendpacket(net_device->Device->channel, + revoke_packet, sizeof(struct nvsp_message), - (unsigned long)revokePacket, + (unsigned long)revoke_packet, VmbusPacketTypeDataInBand, 0); /* * If we failed here, we might as well return and @@ -461,11 +477,11 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice) } /* Teardown the gpadl on the vsp end */ - if (NetDevice->ReceiveBufferGpadlHandle) { + if (net_device->ReceiveBufferGpadlHandle) { DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL..."); - ret = vmbus_teardown_gpadl(NetDevice->Device->channel, - NetDevice->ReceiveBufferGpadlHandle); + ret = vmbus_teardown_gpadl(net_device->Device->channel, + net_device->ReceiveBufferGpadlHandle); /* If we failed here, we might as well return and have a leak rather than continue and a bugchk */ if (ret != 0) { @@ -473,30 +489,30 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice) "unable to teardown receive buffer's gpadl"); return -1; } - NetDevice->ReceiveBufferGpadlHandle = 0; + net_device->ReceiveBufferGpadlHandle = 0; } - if (NetDevice->ReceiveBuffer) { + if (net_device->ReceiveBuffer) { DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); /* Free up the receive buffer */ - osd_page_free(NetDevice->ReceiveBuffer, - NetDevice->ReceiveBufferSize >> PAGE_SHIFT); - NetDevice->ReceiveBuffer = NULL; + osd_page_free(net_device->ReceiveBuffer, + net_device->ReceiveBufferSize >> PAGE_SHIFT); + net_device->ReceiveBuffer = NULL; } - if (NetDevice->ReceiveSections) { - NetDevice->ReceiveSectionCount = 0; - kfree(NetDevice->ReceiveSections); - NetDevice->ReceiveSections = NULL; + if (net_device->ReceiveSections) { + net_device->ReceiveSectionCount = 0; + kfree(net_device->ReceiveSections); + net_device->ReceiveSections = NULL; } return ret; } -static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice) +static int NetVscDestroySendBuffer(struct netvsc_device *net_device) { - struct nvsp_message *revokePacket; + struct nvsp_message *revoke_packet; int ret = 0; /* @@ -505,20 +521,23 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice) * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need * to send a revoke msg here */ - if (NetDevice->SendSectionSize) { + if (net_device->SendSectionSize) { DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeSendBuffer..."); /* Send the revoke send buffer */ - revokePacket = &NetDevice->RevokePacket; - memset(revokePacket, 0, sizeof(struct nvsp_message)); + revoke_packet = &net_device->RevokePacket; + memset(revoke_packet, 0, sizeof(struct nvsp_message)); - revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer; - revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID; + revoke_packet->Header.MessageType = + NvspMessage1TypeRevokeSendBuffer; + revoke_packet->Messages.Version1Messages. + RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID; - ret = vmbus_sendpacket(NetDevice->Device->channel, revokePacket, + ret = vmbus_sendpacket(net_device->Device->channel, + revoke_packet, sizeof(struct nvsp_message), - (unsigned long)revokePacket, + (unsigned long)revoke_packet, VmbusPacketTypeDataInBand, 0); /* * If we failed here, we might as well return and have a leak @@ -532,10 +551,10 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice) } /* Teardown the gpadl on the vsp end */ - if (NetDevice->SendBufferGpadlHandle) { + if (net_device->SendBufferGpadlHandle) { DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL..."); - ret = vmbus_teardown_gpadl(NetDevice->Device->channel, - NetDevice->SendBufferGpadlHandle); + ret = vmbus_teardown_gpadl(net_device->Device->channel, + net_device->SendBufferGpadlHandle); /* * If we failed here, we might as well return and have a leak @@ -546,49 +565,51 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice) "gpadl"); return -1; } - NetDevice->SendBufferGpadlHandle = 0; + net_device->SendBufferGpadlHandle = 0; } - if (NetDevice->SendBuffer) { + if (net_device->SendBuffer) { DPRINT_INFO(NETVSC, "Freeing up send buffer..."); /* Free up the receive buffer */ - osd_page_free(NetDevice->SendBuffer, - NetDevice->SendBufferSize >> PAGE_SHIFT); - NetDevice->SendBuffer = NULL; + osd_page_free(net_device->SendBuffer, + net_device->SendBufferSize >> PAGE_SHIFT); + net_device->SendBuffer = NULL; } return ret; } -static int NetVscConnectToVsp(struct hv_device *Device) +static int NetVscConnectToVsp(struct hv_device *device) { int ret; - struct netvsc_device *netDevice; - struct nvsp_message *initPacket; - int ndisVersion; + struct netvsc_device *net_device; + struct nvsp_message *init_packet; + int ndis_version; - netDevice = GetOutboundNetDevice(Device); - if (!netDevice) { + net_device = GetOutboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); return -1; } - initPacket = &netDevice->ChannelInitPacket; + init_packet = &net_device->ChannelInitPacket; - memset(initPacket, 0, sizeof(struct nvsp_message)); - initPacket->Header.MessageType = NvspMessageTypeInit; - initPacket->Messages.InitMessages.Init.MinProtocolVersion = NVSP_MIN_PROTOCOL_VERSION; - initPacket->Messages.InitMessages.Init.MaxProtocolVersion = NVSP_MAX_PROTOCOL_VERSION; + memset(init_packet, 0, sizeof(struct nvsp_message)); + init_packet->Header.MessageType = NvspMessageTypeInit; + init_packet->Messages.InitMessages.Init.MinProtocolVersion = + NVSP_MIN_PROTOCOL_VERSION; + init_packet->Messages.InitMessages.Init.MaxProtocolVersion = + NVSP_MAX_PROTOCOL_VERSION; DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit..."); /* Send the init request */ - ret = vmbus_sendpacket(Device->channel, initPacket, + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)initPacket, + (unsigned long)init_packet, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); @@ -597,47 +618,52 @@ static int NetVscConnectToVsp(struct hv_device *Device) goto Cleanup; } - osd_waitevent_wait(netDevice->ChannelInitEvent); + osd_waitevent_wait(net_device->ChannelInitEvent); /* Now, check the response */ /* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */ DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)", - initPacket->Messages.InitMessages.InitComplete.Status, - initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength); + init_packet->Messages.InitMessages.InitComplete.Status, + init_packet->Messages.InitMessages. + InitComplete.MaximumMdlChainLength); - if (initPacket->Messages.InitMessages.InitComplete.Status != + if (init_packet->Messages.InitMessages.InitComplete.Status != NvspStatusSuccess) { DPRINT_ERR(NETVSC, "unable to initialize with netvsp (status 0x%x)", - initPacket->Messages.InitMessages.InitComplete.Status); + init_packet->Messages.InitMessages.InitComplete.Status); ret = -1; goto Cleanup; } - if (initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) { + if (init_packet->Messages.InitMessages.InitComplete. + NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) { DPRINT_ERR(NETVSC, "unable to initialize with netvsp " "(version expected 1 got %d)", - initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion); + init_packet->Messages.InitMessages. + InitComplete.NegotiatedProtocolVersion); ret = -1; goto Cleanup; } DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion..."); /* Send the ndis version */ - memset(initPacket, 0, sizeof(struct nvsp_message)); + memset(init_packet, 0, sizeof(struct nvsp_message)); - ndisVersion = 0x00050000; + ndis_version = 0x00050000; - initPacket->Header.MessageType = NvspMessage1TypeSendNdisVersion; - initPacket->Messages.Version1Messages.SendNdisVersion.NdisMajorVersion = - (ndisVersion & 0xFFFF0000) >> 16; - initPacket->Messages.Version1Messages.SendNdisVersion.NdisMinorVersion = - ndisVersion & 0xFFFF; + init_packet->Header.MessageType = NvspMessage1TypeSendNdisVersion; + init_packet->Messages.Version1Messages. + SendNdisVersion.NdisMajorVersion = + (ndis_version & 0xFFFF0000) >> 16; + init_packet->Messages.Version1Messages. + SendNdisVersion.NdisMinorVersion = + ndis_version & 0xFFFF; /* Send the init request */ - ret = vmbus_sendpacket(Device->channel, initPacket, + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), - (unsigned long)initPacket, + (unsigned long)init_packet, VmbusPacketTypeDataInBand, 0); if (ret != 0) { DPRINT_ERR(NETVSC, @@ -654,48 +680,48 @@ static int NetVscConnectToVsp(struct hv_device *Device) /* osd_waitevent_wait(NetVscChannel->ChannelInitEvent); */ /* Post the big receive buffer to NetVSP */ - ret = NetVscInitializeReceiveBufferWithNetVsp(Device); + ret = NetVscInitializeReceiveBufferWithNetVsp(device); if (ret == 0) - ret = NetVscInitializeSendBufferWithNetVsp(Device); + ret = NetVscInitializeSendBufferWithNetVsp(device); Cleanup: - PutNetDevice(Device); + PutNetDevice(device); return ret; } -static void NetVscDisconnectFromVsp(struct netvsc_device *NetDevice) +static void NetVscDisconnectFromVsp(struct netvsc_device *net_device) { - NetVscDestroyReceiveBuffer(NetDevice); - NetVscDestroySendBuffer(NetDevice); + NetVscDestroyReceiveBuffer(net_device); + NetVscDestroySendBuffer(net_device); } /* * NetVscOnDeviceAdd - Callback when the device belonging to this driver is added */ -static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) +static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info) { int ret = 0; int i; - struct netvsc_device *netDevice; + struct netvsc_device *net_device; struct hv_netvsc_packet *packet, *pos; - struct netvsc_driver *netDriver = - (struct netvsc_driver *)Device->Driver; + struct netvsc_driver *net_driver = + (struct netvsc_driver *)device->Driver; - netDevice = AllocNetDevice(Device); - if (!netDevice) { + net_device = AllocNetDevice(device); + if (!net_device) { ret = -1; goto Cleanup; } - DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", netDevice); + DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", net_device); /* Initialize the NetVSC channel extension */ - netDevice->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE; - spin_lock_init(&netDevice->receive_packet_list_lock); + net_device->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE; + spin_lock_init(&net_device->receive_packet_list_lock); - netDevice->SendBufferSize = NETVSC_SEND_BUFFER_SIZE; + net_device->SendBufferSize = NETVSC_SEND_BUFFER_SIZE; - INIT_LIST_HEAD(&netDevice->ReceivePacketList); + INIT_LIST_HEAD(&net_device->ReceivePacketList); for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { packet = kzalloc(sizeof(struct hv_netvsc_packet) + @@ -708,18 +734,18 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) break; } list_add_tail(&packet->ListEntry, - &netDevice->ReceivePacketList); + &net_device->ReceivePacketList); } - netDevice->ChannelInitEvent = osd_waitevent_create(); - if (!netDevice->ChannelInitEvent) { + net_device->ChannelInitEvent = osd_waitevent_create(); + if (!net_device->ChannelInitEvent) { ret = -ENOMEM; goto Cleanup; } /* Open the channel */ - ret = vmbus_open(Device->channel, netDriver->RingBufferSize, - netDriver->RingBufferSize, NULL, 0, - NetVscOnChannelCallback, Device); + ret = vmbus_open(device->channel, net_driver->RingBufferSize, + net_driver->RingBufferSize, NULL, 0, + NetVscOnChannelCallback, device); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to open channel: %d", ret); @@ -731,7 +757,7 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***"); /* Connect with the NetVsp */ - ret = NetVscConnectToVsp(Device); + ret = NetVscConnectToVsp(device); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret); ret = -1; @@ -745,24 +771,24 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) close: /* Now, we can close the channel safely */ - vmbus_close(Device->channel); + vmbus_close(device->channel); Cleanup: - if (netDevice) { - kfree(netDevice->ChannelInitEvent); + if (net_device) { + kfree(net_device->ChannelInitEvent); list_for_each_entry_safe(packet, pos, - &netDevice->ReceivePacketList, + &net_device->ReceivePacketList, ListEntry) { list_del(&packet->ListEntry); kfree(packet); } - ReleaseOutboundNetDevice(Device); - ReleaseInboundNetDevice(Device); + ReleaseOutboundNetDevice(device); + ReleaseInboundNetDevice(device); - FreeNetDevice(netDevice); + FreeNetDevice(net_device); } return ret; @@ -771,53 +797,53 @@ Cleanup: /* * NetVscOnDeviceRemove - Callback when the root bus device is removed */ -static int NetVscOnDeviceRemove(struct hv_device *Device) +static int NetVscOnDeviceRemove(struct hv_device *device) { - struct netvsc_device *netDevice; - struct hv_netvsc_packet *netvscPacket, *pos; + struct netvsc_device *net_device; + struct hv_netvsc_packet *netvsc_packet, *pos; DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...", - Device->Extension); + device->Extension); /* Stop outbound traffic ie sends and receives completions */ - netDevice = ReleaseOutboundNetDevice(Device); - if (!netDevice) { + net_device = ReleaseOutboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "No net device present!!"); return -1; } /* Wait for all send completions */ - while (atomic_read(&netDevice->NumOutstandingSends)) { + while (atomic_read(&net_device->NumOutstandingSends)) { DPRINT_INFO(NETVSC, "waiting for %d requests to complete...", - atomic_read(&netDevice->NumOutstandingSends)); + atomic_read(&net_device->NumOutstandingSends)); udelay(100); } DPRINT_INFO(NETVSC, "Disconnecting from netvsp..."); - NetVscDisconnectFromVsp(netDevice); + NetVscDisconnectFromVsp(net_device); DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...", - Device->Extension); + device->Extension); /* Stop inbound traffic ie receives and sends completions */ - netDevice = ReleaseInboundNetDevice(Device); + net_device = ReleaseInboundNetDevice(device); /* At this point, no one should be accessing netDevice except in here */ - DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice); + DPRINT_INFO(NETVSC, "net device (%p) safe to remove", net_device); /* Now, we can close the channel safely */ - vmbus_close(Device->channel); + vmbus_close(device->channel); /* Release all resources */ - list_for_each_entry_safe(netvscPacket, pos, - &netDevice->ReceivePacketList, ListEntry) { - list_del(&netvscPacket->ListEntry); - kfree(netvscPacket); + list_for_each_entry_safe(netvsc_packet, pos, + &net_device->ReceivePacketList, ListEntry) { + list_del(&netvsc_packet->ListEntry); + kfree(netvsc_packet); } - kfree(netDevice->ChannelInitEvent); - FreeNetDevice(netDevice); + kfree(net_device->ChannelInitEvent); + FreeNetDevice(net_device); return 0; } @@ -828,69 +854,72 @@ static void NetVscOnCleanup(struct hv_driver *drv) { } -static void NetVscOnSendCompletion(struct hv_device *Device, - struct vmpacket_descriptor *Packet) +static void NetVscOnSendCompletion(struct hv_device *device, + struct vmpacket_descriptor *packet) { - struct netvsc_device *netDevice; - struct nvsp_message *nvspPacket; - struct hv_netvsc_packet *nvscPacket; + struct netvsc_device *net_device; + struct nvsp_message *nvsp_packet; + struct hv_netvsc_packet *nvsc_packet; - netDevice = GetInboundNetDevice(Device); - if (!netDevice) { + net_device = GetInboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); return; } - nvspPacket = (struct nvsp_message *)((unsigned long)Packet + (Packet->DataOffset8 << 3)); + nvsp_packet = (struct nvsp_message *)((unsigned long)packet + + (packet->DataOffset8 << 3)); DPRINT_DBG(NETVSC, "send completion packet - type %d", - nvspPacket->Header.MessageType); + nvsp_packet->Header.MessageType); - if ((nvspPacket->Header.MessageType == NvspMessageTypeInitComplete) || - (nvspPacket->Header.MessageType == + if ((nvsp_packet->Header.MessageType == NvspMessageTypeInitComplete) || + (nvsp_packet->Header.MessageType == NvspMessage1TypeSendReceiveBufferComplete) || - (nvspPacket->Header.MessageType == + (nvsp_packet->Header.MessageType == NvspMessage1TypeSendSendBufferComplete)) { /* Copy the response back */ - memcpy(&netDevice->ChannelInitPacket, nvspPacket, + memcpy(&net_device->ChannelInitPacket, nvsp_packet, sizeof(struct nvsp_message)); - osd_waitevent_set(netDevice->ChannelInitEvent); - } else if (nvspPacket->Header.MessageType == + osd_waitevent_set(net_device->ChannelInitEvent); + } else if (nvsp_packet->Header.MessageType == NvspMessage1TypeSendRNDISPacketComplete) { /* Get the send context */ - nvscPacket = (struct hv_netvsc_packet *)(unsigned long)Packet->TransactionId; + nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) + packet->TransactionId; /* ASSERT(nvscPacket); */ /* Notify the layer above us */ - nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext); + nvsc_packet->Completion.Send.OnSendCompletion( + nvsc_packet->Completion.Send.SendCompletionContext); - atomic_dec(&netDevice->NumOutstandingSends); + atomic_dec(&net_device->NumOutstandingSends); } else { DPRINT_ERR(NETVSC, "Unknown send completion packet type - " - "%d received!!", nvspPacket->Header.MessageType); + "%d received!!", nvsp_packet->Header.MessageType); } - PutNetDevice(Device); + PutNetDevice(device); } -static int NetVscOnSend(struct hv_device *Device, - struct hv_netvsc_packet *Packet) +static int NetVscOnSend(struct hv_device *device, + struct hv_netvsc_packet *packet) { - struct netvsc_device *netDevice; + struct netvsc_device *net_device; int ret = 0; struct nvsp_message sendMessage; - netDevice = GetOutboundNetDevice(Device); - if (!netDevice) { + net_device = GetOutboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "net device (%p) shutting down..." - "ignoring outbound packets", netDevice); + "ignoring outbound packets", net_device); return -2; } sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket; - if (Packet->IsDataPacket) { + if (packet->IsDataPacket) { /* 0 is RMC_DATA; */ sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0; } else { @@ -902,17 +931,17 @@ static int NetVscOnSend(struct hv_device *Device, sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF; sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0; - if (Packet->PageBufferCount) { - ret = vmbus_sendpacket_pagebuffer(Device->channel, - Packet->PageBuffers, - Packet->PageBufferCount, + if (packet->PageBufferCount) { + ret = vmbus_sendpacket_pagebuffer(device->channel, + packet->PageBuffers, + packet->PageBufferCount, &sendMessage, sizeof(struct nvsp_message), - (unsigned long)Packet); + (unsigned long)packet); } else { - ret = vmbus_sendpacket(Device->channel, &sendMessage, + ret = vmbus_sendpacket(device->channel, &sendMessage, sizeof(struct nvsp_message), - (unsigned long)Packet, + (unsigned long)packet, VmbusPacketTypeDataInBand, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); @@ -920,31 +949,31 @@ static int NetVscOnSend(struct hv_device *Device, if (ret != 0) DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", - Packet, ret); + packet, ret); - atomic_inc(&netDevice->NumOutstandingSends); - PutNetDevice(Device); + atomic_inc(&net_device->NumOutstandingSends); + PutNetDevice(device); return ret; } -static void NetVscOnReceive(struct hv_device *Device, - struct vmpacket_descriptor *Packet) +static void NetVscOnReceive(struct hv_device *device, + struct vmpacket_descriptor *packet) { - struct netvsc_device *netDevice; - struct vmtransfer_page_packet_header *vmxferpagePacket; - struct nvsp_message *nvspPacket; - struct hv_netvsc_packet *netvscPacket = NULL; + struct netvsc_device *net_device; + struct vmtransfer_page_packet_header *vmxferpage_packet; + struct nvsp_message *nvsp_packet; + struct hv_netvsc_packet *netvsc_packet = NULL; unsigned long start; - unsigned long end, endVirtual; + unsigned long end, end_virtual; /* struct netvsc_driver *netvscDriver; */ - struct xferpage_packet *xferpagePacket = NULL; + struct xferpage_packet *xferpage_packet = NULL; int i, j; - int count = 0, bytesRemain = 0; + int count = 0, bytes_remain = 0; unsigned long flags; LIST_HEAD(listHead); - netDevice = GetInboundNetDevice(Device); - if (!netDevice) { + net_device = GetInboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); return; @@ -954,39 +983,40 @@ static void NetVscOnReceive(struct hv_device *Device, * All inbound packets other than send completion should be xfer page * packet */ - if (Packet->Type != VmbusPacketTypeDataUsingTransferPages) { + if (packet->Type != VmbusPacketTypeDataUsingTransferPages) { DPRINT_ERR(NETVSC, "Unknown packet type received - %d", - Packet->Type); - PutNetDevice(Device); + packet->Type); + PutNetDevice(device); return; } - nvspPacket = (struct nvsp_message *)((unsigned long)Packet + - (Packet->DataOffset8 << 3)); + nvsp_packet = (struct nvsp_message *)((unsigned long)packet + + (packet->DataOffset8 << 3)); /* Make sure this is a valid nvsp packet */ - if (nvspPacket->Header.MessageType != NvspMessage1TypeSendRNDISPacket) { + if (nvsp_packet->Header.MessageType != + NvspMessage1TypeSendRNDISPacket) { DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", - nvspPacket->Header.MessageType); - PutNetDevice(Device); + nvsp_packet->Header.MessageType); + PutNetDevice(device); return; } DPRINT_DBG(NETVSC, "NVSP packet received - type %d", - nvspPacket->Header.MessageType); + nvsp_packet->Header.MessageType); - vmxferpagePacket = (struct vmtransfer_page_packet_header *)Packet; + vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet; - if (vmxferpagePacket->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) { + if (vmxferpage_packet->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) { DPRINT_ERR(NETVSC, "Invalid xfer page set id - " "expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, - vmxferpagePacket->TransferPageSetId); - PutNetDevice(Device); + vmxferpage_packet->TransferPageSetId); + PutNetDevice(device); return; } DPRINT_DBG(NETVSC, "xfer page - range count %d", - vmxferpagePacket->RangeCount); + vmxferpage_packet->RangeCount); /* * Grab free packets (range count + 1) to represent this xfer @@ -994,13 +1024,13 @@ static void NetVscOnReceive(struct hv_device *Device, * We grab it here so that we know exactly how many we can * fulfil */ - spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags); - while (!list_empty(&netDevice->ReceivePacketList)) { - list_move_tail(netDevice->ReceivePacketList.next, &listHead); - if (++count == vmxferpagePacket->RangeCount + 1) + spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); + while (!list_empty(&net_device->ReceivePacketList)) { + list_move_tail(net_device->ReceivePacketList.next, &listHead); + if (++count == vmxferpage_packet->RangeCount + 1) break; } - spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, flags); + spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); /* * We need at least 2 netvsc pkts (1 to represent the xfer @@ -1010,129 +1040,137 @@ static void NetVscOnReceive(struct hv_device *Device, if (count < 2) { DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. " "Dropping this xfer page packet completely!", - count, vmxferpagePacket->RangeCount + 1); + count, vmxferpage_packet->RangeCount + 1); /* Return it to the freelist */ - spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags); + spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); for (i = count; i != 0; i--) { list_move_tail(listHead.next, - &netDevice->ReceivePacketList); + &net_device->ReceivePacketList); } - spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, + spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); - NetVscSendReceiveCompletion(Device, - vmxferpagePacket->d.TransactionId); + NetVscSendReceiveCompletion(device, + vmxferpage_packet->d.TransactionId); - PutNetDevice(Device); + PutNetDevice(device); return; } /* Remove the 1st packet to represent the xfer page packet itself */ - xferpagePacket = (struct xferpage_packet *)listHead.next; - list_del(&xferpagePacket->ListEntry); + xferpage_packet = (struct xferpage_packet *)listHead.next; + list_del(&xferpage_packet->ListEntry); /* This is how much we can satisfy */ - xferpagePacket->Count = count - 1; + xferpage_packet->Count = count - 1; /* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */ /* vmxferpagePacket->RangeCount); */ - if (xferpagePacket->Count != vmxferpagePacket->RangeCount) { + if (xferpage_packet->Count != vmxferpage_packet->RangeCount) { DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer " - "page...got %d", vmxferpagePacket->RangeCount, - xferpagePacket->Count); + "page...got %d", vmxferpage_packet->RangeCount, + xferpage_packet->Count); } /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ for (i = 0; i < (count - 1); i++) { - netvscPacket = (struct hv_netvsc_packet *)listHead.next; - list_del(&netvscPacket->ListEntry); + netvsc_packet = (struct hv_netvsc_packet *)listHead.next; + list_del(&netvsc_packet->ListEntry); /* Initialize the netvsc packet */ - netvscPacket->XferPagePacket = xferpagePacket; - netvscPacket->Completion.Recv.OnReceiveCompletion = + netvsc_packet->XferPagePacket = xferpage_packet; + netvsc_packet->Completion.Recv.OnReceiveCompletion = NetVscOnReceiveCompletion; - netvscPacket->Completion.Recv.ReceiveCompletionContext = - netvscPacket; - netvscPacket->Device = Device; + netvsc_packet->Completion.Recv.ReceiveCompletionContext = + netvsc_packet; + netvsc_packet->Device = device; /* Save this so that we can send it back */ - netvscPacket->Completion.Recv.ReceiveCompletionTid = - vmxferpagePacket->d.TransactionId; + netvsc_packet->Completion.Recv.ReceiveCompletionTid = + vmxferpage_packet->d.TransactionId; - netvscPacket->TotalDataBufferLength = - vmxferpagePacket->Ranges[i].ByteCount; - netvscPacket->PageBufferCount = 1; + netvsc_packet->TotalDataBufferLength = + vmxferpage_packet->Ranges[i].ByteCount; + netvsc_packet->PageBufferCount = 1; /* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */ /* vmxferpagePacket->Ranges[i].ByteCount < */ /* netDevice->ReceiveBufferSize); */ - netvscPacket->PageBuffers[0].Length = - vmxferpagePacket->Ranges[i].ByteCount; + netvsc_packet->PageBuffers[0].Length = + vmxferpage_packet->Ranges[i].ByteCount; - start = virt_to_phys((void *)((unsigned long)netDevice->ReceiveBuffer + vmxferpagePacket->Ranges[i].ByteOffset)); + start = virt_to_phys((void *)((unsigned long)net_device-> + ReceiveBuffer + vmxferpage_packet->Ranges[i].ByteOffset)); - netvscPacket->PageBuffers[0].Pfn = start >> PAGE_SHIFT; - endVirtual = (unsigned long)netDevice->ReceiveBuffer - + vmxferpagePacket->Ranges[i].ByteOffset - + vmxferpagePacket->Ranges[i].ByteCount - 1; - end = virt_to_phys((void *)endVirtual); + netvsc_packet->PageBuffers[0].Pfn = start >> PAGE_SHIFT; + end_virtual = (unsigned long)net_device->ReceiveBuffer + + vmxferpage_packet->Ranges[i].ByteOffset + + vmxferpage_packet->Ranges[i].ByteCount - 1; + end = virt_to_phys((void *)end_virtual); /* Calculate the page relative offset */ - netvscPacket->PageBuffers[0].Offset = - vmxferpagePacket->Ranges[i].ByteOffset & (PAGE_SIZE - 1); + netvsc_packet->PageBuffers[0].Offset = + vmxferpage_packet->Ranges[i].ByteOffset & + (PAGE_SIZE - 1); if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) { /* Handle frame across multiple pages: */ - netvscPacket->PageBuffers[0].Length = - (netvscPacket->PageBuffers[0].Pfn << PAGE_SHIFT) + netvsc_packet->PageBuffers[0].Length = + (netvsc_packet->PageBuffers[0].Pfn << + PAGE_SHIFT) + PAGE_SIZE - start; - bytesRemain = netvscPacket->TotalDataBufferLength - - netvscPacket->PageBuffers[0].Length; + bytes_remain = netvsc_packet->TotalDataBufferLength - + netvsc_packet->PageBuffers[0].Length; for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) { - netvscPacket->PageBuffers[j].Offset = 0; - if (bytesRemain <= PAGE_SIZE) { - netvscPacket->PageBuffers[j].Length = bytesRemain; - bytesRemain = 0; + netvsc_packet->PageBuffers[j].Offset = 0; + if (bytes_remain <= PAGE_SIZE) { + netvsc_packet->PageBuffers[j].Length = + bytes_remain; + bytes_remain = 0; } else { - netvscPacket->PageBuffers[j].Length = PAGE_SIZE; - bytesRemain -= PAGE_SIZE; + netvsc_packet->PageBuffers[j].Length = + PAGE_SIZE; + bytes_remain -= PAGE_SIZE; } - netvscPacket->PageBuffers[j].Pfn = - virt_to_phys((void *)(endVirtual - bytesRemain)) >> PAGE_SHIFT; - netvscPacket->PageBufferCount++; - if (bytesRemain == 0) + netvsc_packet->PageBuffers[j].Pfn = + virt_to_phys((void *)(end_virtual - + bytes_remain)) >> PAGE_SHIFT; + netvsc_packet->PageBufferCount++; + if (bytes_remain == 0) break; } /* ASSERT(bytesRemain == 0); */ } DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => " "(pfn %llx, offset %u, len %u)", i, - vmxferpagePacket->Ranges[i].ByteOffset, - vmxferpagePacket->Ranges[i].ByteCount, - netvscPacket->PageBuffers[0].Pfn, - netvscPacket->PageBuffers[0].Offset, - netvscPacket->PageBuffers[0].Length); + vmxferpage_packet->Ranges[i].ByteOffset, + vmxferpage_packet->Ranges[i].ByteCount, + netvsc_packet->PageBuffers[0].Pfn, + netvsc_packet->PageBuffers[0].Offset, + netvsc_packet->PageBuffers[0].Length); /* Pass it to the upper layer */ - ((struct netvsc_driver *)Device->Driver)->OnReceiveCallback(Device, netvscPacket); + ((struct netvsc_driver *)device->Driver)-> + OnReceiveCallback(device, netvsc_packet); - NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext); + NetVscOnReceiveCompletion(netvsc_packet-> + Completion.Recv.ReceiveCompletionContext); } /* ASSERT(list_empty(&listHead)); */ - PutNetDevice(Device); + PutNetDevice(device); } -static void NetVscSendReceiveCompletion(struct hv_device *Device, - u64 TransactionId) +static void NetVscSendReceiveCompletion(struct hv_device *device, + u64 transaction_id) { struct nvsp_message recvcompMessage; int retries = 0; int ret; DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx", - TransactionId); + transaction_id); recvcompMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacketComplete; @@ -1142,8 +1180,8 @@ static void NetVscSendReceiveCompletion(struct hv_device *Device, retry_send_cmplt: /* Send the completion */ - ret = vmbus_sendpacket(Device->channel, &recvcompMessage, - sizeof(struct nvsp_message), TransactionId, + ret = vmbus_sendpacket(device->channel, &recvcompMessage, + sizeof(struct nvsp_message), transaction_id, VmbusPacketTypeCompletion, 0); if (ret == 0) { /* success */ @@ -1152,7 +1190,7 @@ retry_send_cmplt: /* no more room...wait a bit and attempt to retry 3 times */ retries++; DPRINT_ERR(NETVSC, "unable to send receive completion pkt " - "(tid %llx)...retrying %d", TransactionId, retries); + "(tid %llx)...retrying %d", transaction_id, retries); if (retries < 4) { udelay(100); @@ -1160,22 +1198,22 @@ retry_send_cmplt: } else { DPRINT_ERR(NETVSC, "unable to send receive completion " "pkt (tid %llx)...give up retrying", - TransactionId); + transaction_id); } } else { DPRINT_ERR(NETVSC, "unable to send receive completion pkt - " - "%llx", TransactionId); + "%llx", transaction_id); } } /* Send a receive completion packet to RNDIS device (ie NetVsp) */ -static void NetVscOnReceiveCompletion(void *Context) +static void NetVscOnReceiveCompletion(void *context) { - struct hv_netvsc_packet *packet = Context; + struct hv_netvsc_packet *packet = context; struct hv_device *device = (struct hv_device *)packet->Device; - struct netvsc_device *netDevice; - u64 transactionId = 0; - bool fSendReceiveComp = false; + struct netvsc_device *net_device; + u64 transaction_id = 0; + bool fsend_receive_comp = false; unsigned long flags; /* ASSERT(packet->XferPagePacket); */ @@ -1185,15 +1223,15 @@ static void NetVscOnReceiveCompletion(void *Context) * send out receive completion, we are using GetInboundNetDevice() * since we may have disable outbound traffic already. */ - netDevice = GetInboundNetDevice(device); - if (!netDevice) { + net_device = GetInboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); return; } /* Overloading use of the lock. */ - spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags); + spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); /* ASSERT(packet->XferPagePacket->Count > 0); */ packet->XferPagePacket->Count--; @@ -1203,31 +1241,31 @@ static void NetVscOnReceiveCompletion(void *Context) * Return the xfer page packet itself to the freelist */ if (packet->XferPagePacket->Count == 0) { - fSendReceiveComp = true; - transactionId = packet->Completion.Recv.ReceiveCompletionTid; + fsend_receive_comp = true; + transaction_id = packet->Completion.Recv.ReceiveCompletionTid; list_add_tail(&packet->XferPagePacket->ListEntry, - &netDevice->ReceivePacketList); + &net_device->ReceivePacketList); } /* Put the packet back */ - list_add_tail(&packet->ListEntry, &netDevice->ReceivePacketList); - spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, flags); + list_add_tail(&packet->ListEntry, &net_device->ReceivePacketList); + spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); /* Send a receive completion for the xfer page packet */ - if (fSendReceiveComp) - NetVscSendReceiveCompletion(device, transactionId); + if (fsend_receive_comp) + NetVscSendReceiveCompletion(device, transaction_id); PutNetDevice(device); } -static void NetVscOnChannelCallback(void *Context) +static void NetVscOnChannelCallback(void *context) { int ret; - struct hv_device *device = Context; - struct netvsc_device *netDevice; - u32 bytesRecvd; - u64 requestId; + struct hv_device *device = context; + struct netvsc_device *net_device; + u32 bytes_recvd; + u64 request_id; unsigned char *packet; struct vmpacket_descriptor *desc; unsigned char *buffer; @@ -1241,20 +1279,20 @@ static void NetVscOnChannelCallback(void *Context) return; buffer = packet; - netDevice = GetInboundNetDevice(device); - if (!netDevice) { + net_device = GetInboundNetDevice(device); + if (!net_device) { DPRINT_ERR(NETVSC, "net device (%p) shutting down..." - "ignoring inbound packets", netDevice); + "ignoring inbound packets", net_device); goto out; } do { ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, - &bytesRecvd, &requestId); + &bytes_recvd, &request_id); if (ret == 0) { - if (bytesRecvd > 0) { + if (bytes_recvd > 0) { DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx", - bytesRecvd, requestId); + bytes_recvd, request_id); desc = (struct vmpacket_descriptor *)buffer; switch (desc->Type) { @@ -1270,8 +1308,8 @@ static void NetVscOnChannelCallback(void *Context) DPRINT_ERR(NETVSC, "unhandled packet type %d, " "tid %llx len %d\n", - desc->Type, requestId, - bytesRecvd); + desc->Type, request_id, + bytes_recvd); break; } @@ -1293,16 +1331,16 @@ static void NetVscOnChannelCallback(void *Context) } } else if (ret == -2) { /* Handle large packet */ - buffer = kmalloc(bytesRecvd, GFP_ATOMIC); + buffer = kmalloc(bytes_recvd, GFP_ATOMIC); if (buffer == NULL) { /* Try again next time around */ DPRINT_ERR(NETVSC, "unable to allocate buffer of size " - "(%d)!!", bytesRecvd); + "(%d)!!", bytes_recvd); break; } - bufferlen = bytesRecvd; + bufferlen = bytes_recvd; } } while (1); -- cgit v1.2.3 From 5a71ae303c0f82968d93d86724c1d94d753b34d7 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:03:55 -0800 Subject: staging: hv: Convert camel cased functions in netvsc.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc.c | 173 ++++++++++++++++++++-------------------- drivers/staging/hv/netvsc_api.h | 2 +- drivers/staging/hv/netvsc_drv.c | 2 +- 3 files changed, 90 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index 1c1ee57482a5..781d7bd37102 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -41,40 +41,40 @@ static const struct hv_guid netvsc_device_type = { } }; -static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info); +static int netvsc_device_add(struct hv_device *device, void *additional_info); -static int NetVscOnDeviceRemove(struct hv_device *device); +static int netvsc_device_remove(struct hv_device *device); -static void NetVscOnCleanup(struct hv_driver *driver); +static void netvsc_cleanup(struct hv_driver *driver); -static void NetVscOnChannelCallback(void *context); +static void netvsc_channel_cb(void *context); -static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *device); +static int netvsc_init_send_buf(struct hv_device *device); -static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *device); +static int netvsc_init_recv_buf(struct hv_device *device); -static int NetVscDestroySendBuffer(struct netvsc_device *net_device); +static int netvsc_destroy_send_buf(struct netvsc_device *net_device); -static int NetVscDestroyReceiveBuffer(struct netvsc_device *net_device); +static int netvsc_destroy_recv_buf(struct netvsc_device *net_device); -static int NetVscConnectToVsp(struct hv_device *device); +static int netvsc_connect_vsp(struct hv_device *device); -static void NetVscOnSendCompletion(struct hv_device *device, +static void netvsc_send_completion(struct hv_device *device, struct vmpacket_descriptor *packet); -static int NetVscOnSend(struct hv_device *device, +static int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet); -static void NetVscOnReceive(struct hv_device *device, +static void netvsc_receive(struct hv_device *device, struct vmpacket_descriptor *packet); -static void NetVscOnReceiveCompletion(void *context); +static void netvsc_receive_completion(void *context); -static void NetVscSendReceiveCompletion(struct hv_device *device, +static void netvsc_send_recv_completion(struct hv_device *device, u64 transaction_id); -static struct netvsc_device *AllocNetDevice(struct hv_device *device) +static struct netvsc_device *alloc_net_device(struct hv_device *device) { struct netvsc_device *net_device; @@ -91,7 +91,7 @@ static struct netvsc_device *AllocNetDevice(struct hv_device *device) return net_device; } -static void FreeNetDevice(struct netvsc_device *device) +static void free_net_device(struct netvsc_device *device) { WARN_ON(atomic_read(&device->RefCount) == 0); device->Device->Extension = NULL; @@ -100,7 +100,7 @@ static void FreeNetDevice(struct netvsc_device *device) /* Get the net device object iff exists and its refcount > 1 */ -static struct netvsc_device *GetOutboundNetDevice(struct hv_device *device) +static struct netvsc_device *get_outbound_net_device(struct hv_device *device) { struct netvsc_device *net_device; @@ -114,7 +114,7 @@ static struct netvsc_device *GetOutboundNetDevice(struct hv_device *device) } /* Get the net device object iff exists and its refcount > 0 */ -static struct netvsc_device *GetInboundNetDevice(struct hv_device *device) +static struct netvsc_device *get_inbound_net_device(struct hv_device *device) { struct netvsc_device *net_device; @@ -127,7 +127,7 @@ static struct netvsc_device *GetInboundNetDevice(struct hv_device *device) return net_device; } -static void PutNetDevice(struct hv_device *device) +static void put_net_device(struct hv_device *device) { struct netvsc_device *net_device; @@ -137,7 +137,8 @@ static void PutNetDevice(struct hv_device *device) atomic_dec(&net_device->RefCount); } -static struct netvsc_device *ReleaseOutboundNetDevice(struct hv_device *device) +static struct netvsc_device *release_outbound_net_device( + struct hv_device *device) { struct netvsc_device *net_device; @@ -152,7 +153,8 @@ static struct netvsc_device *ReleaseOutboundNetDevice(struct hv_device *device) return net_device; } -static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *device) +static struct netvsc_device *release_inbound_net_device( + struct hv_device *device) { struct netvsc_device *net_device; @@ -169,9 +171,9 @@ static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *device) } /* - * NetVscInitialize - Main entry point + * netvsc_initialize - Main entry point */ -int NetVscInitialize(struct hv_driver *drv) +int netvsc_initialize(struct hv_driver *drv) { struct netvsc_driver *driver = (struct netvsc_driver *)drv; @@ -194,23 +196,23 @@ int NetVscInitialize(struct hv_driver *drv) /* ASSERT(driver->OnLinkStatusChanged); */ /* Setup the dispatch table */ - driver->Base.OnDeviceAdd = NetVscOnDeviceAdd; - driver->Base.OnDeviceRemove = NetVscOnDeviceRemove; - driver->Base.OnCleanup = NetVscOnCleanup; + driver->Base.OnDeviceAdd = netvsc_device_add; + driver->Base.OnDeviceRemove = netvsc_device_remove; + driver->Base.OnCleanup = netvsc_cleanup; - driver->OnSend = NetVscOnSend; + driver->OnSend = netvsc_send; RndisFilterInit(driver); return 0; } -static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *device) +static int netvsc_init_recv_buf(struct hv_device *device) { int ret = 0; struct netvsc_device *net_device; struct nvsp_message *init_packet; - net_device = GetOutboundNetDevice(device); + net_device = get_outbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); @@ -330,20 +332,20 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *device) goto Exit; Cleanup: - NetVscDestroyReceiveBuffer(net_device); + netvsc_destroy_recv_buf(net_device); Exit: - PutNetDevice(device); + put_net_device(device); return ret; } -static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *device) +static int netvsc_init_send_buf(struct hv_device *device) { int ret = 0; struct netvsc_device *net_device; struct nvsp_message *init_packet; - net_device = GetOutboundNetDevice(device); + net_device = get_outbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); @@ -429,14 +431,14 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *device) goto Exit; Cleanup: - NetVscDestroySendBuffer(net_device); + netvsc_destroy_send_buf(net_device); Exit: - PutNetDevice(device); + put_net_device(device); return ret; } -static int NetVscDestroyReceiveBuffer(struct netvsc_device *net_device) +static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) { struct nvsp_message *revoke_packet; int ret = 0; @@ -510,7 +512,7 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *net_device) return ret; } -static int NetVscDestroySendBuffer(struct netvsc_device *net_device) +static int netvsc_destroy_send_buf(struct netvsc_device *net_device) { struct nvsp_message *revoke_packet; int ret = 0; @@ -581,14 +583,14 @@ static int NetVscDestroySendBuffer(struct netvsc_device *net_device) } -static int NetVscConnectToVsp(struct hv_device *device) +static int netvsc_connect_vsp(struct hv_device *device) { int ret; struct netvsc_device *net_device; struct nvsp_message *init_packet; int ndis_version; - net_device = GetOutboundNetDevice(device); + net_device = get_outbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); @@ -680,25 +682,26 @@ static int NetVscConnectToVsp(struct hv_device *device) /* osd_waitevent_wait(NetVscChannel->ChannelInitEvent); */ /* Post the big receive buffer to NetVSP */ - ret = NetVscInitializeReceiveBufferWithNetVsp(device); + ret = netvsc_init_recv_buf(device); if (ret == 0) - ret = NetVscInitializeSendBufferWithNetVsp(device); + ret = netvsc_init_send_buf(device); Cleanup: - PutNetDevice(device); + put_net_device(device); return ret; } static void NetVscDisconnectFromVsp(struct netvsc_device *net_device) { - NetVscDestroyReceiveBuffer(net_device); - NetVscDestroySendBuffer(net_device); + netvsc_destroy_recv_buf(net_device); + netvsc_destroy_send_buf(net_device); } /* - * NetVscOnDeviceAdd - Callback when the device belonging to this driver is added + * netvsc_device_add - Callback when the device belonging to this + * driver is added */ -static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info) +static int netvsc_device_add(struct hv_device *device, void *additional_info) { int ret = 0; int i; @@ -707,7 +710,7 @@ static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info) struct netvsc_driver *net_driver = (struct netvsc_driver *)device->Driver; - net_device = AllocNetDevice(device); + net_device = alloc_net_device(device); if (!net_device) { ret = -1; goto Cleanup; @@ -745,7 +748,7 @@ static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info) /* Open the channel */ ret = vmbus_open(device->channel, net_driver->RingBufferSize, net_driver->RingBufferSize, NULL, 0, - NetVscOnChannelCallback, device); + netvsc_channel_cb, device); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to open channel: %d", ret); @@ -757,7 +760,7 @@ static int NetVscOnDeviceAdd(struct hv_device *device, void *additional_info) DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***"); /* Connect with the NetVsp */ - ret = NetVscConnectToVsp(device); + ret = netvsc_connect_vsp(device); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret); ret = -1; @@ -785,19 +788,19 @@ Cleanup: kfree(packet); } - ReleaseOutboundNetDevice(device); - ReleaseInboundNetDevice(device); + release_outbound_net_device(device); + release_inbound_net_device(device); - FreeNetDevice(net_device); + free_net_device(net_device); } return ret; } /* - * NetVscOnDeviceRemove - Callback when the root bus device is removed + * netvsc_device_remove - Callback when the root bus device is removed */ -static int NetVscOnDeviceRemove(struct hv_device *device) +static int netvsc_device_remove(struct hv_device *device) { struct netvsc_device *net_device; struct hv_netvsc_packet *netvsc_packet, *pos; @@ -806,7 +809,7 @@ static int NetVscOnDeviceRemove(struct hv_device *device) device->Extension); /* Stop outbound traffic ie sends and receives completions */ - net_device = ReleaseOutboundNetDevice(device); + net_device = release_outbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "No net device present!!"); return -1; @@ -827,7 +830,7 @@ static int NetVscOnDeviceRemove(struct hv_device *device) device->Extension); /* Stop inbound traffic ie receives and sends completions */ - net_device = ReleaseInboundNetDevice(device); + net_device = release_inbound_net_device(device); /* At this point, no one should be accessing netDevice except in here */ DPRINT_INFO(NETVSC, "net device (%p) safe to remove", net_device); @@ -843,25 +846,25 @@ static int NetVscOnDeviceRemove(struct hv_device *device) } kfree(net_device->ChannelInitEvent); - FreeNetDevice(net_device); + free_net_device(net_device); return 0; } /* - * NetVscOnCleanup - Perform any cleanup when the driver is removed + * netvsc_cleanup - Perform any cleanup when the driver is removed */ -static void NetVscOnCleanup(struct hv_driver *drv) +static void netvsc_cleanup(struct hv_driver *drv) { } -static void NetVscOnSendCompletion(struct hv_device *device, +static void netvsc_send_completion(struct hv_device *device, struct vmpacket_descriptor *packet) { struct netvsc_device *net_device; struct nvsp_message *nvsp_packet; struct hv_netvsc_packet *nvsc_packet; - net_device = GetInboundNetDevice(device); + net_device = get_inbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); @@ -900,10 +903,10 @@ static void NetVscOnSendCompletion(struct hv_device *device, "%d received!!", nvsp_packet->Header.MessageType); } - PutNetDevice(device); + put_net_device(device); } -static int NetVscOnSend(struct hv_device *device, +static int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet) { struct netvsc_device *net_device; @@ -911,7 +914,7 @@ static int NetVscOnSend(struct hv_device *device, struct nvsp_message sendMessage; - net_device = GetOutboundNetDevice(device); + net_device = get_outbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "net device (%p) shutting down..." "ignoring outbound packets", net_device); @@ -952,11 +955,11 @@ static int NetVscOnSend(struct hv_device *device, packet, ret); atomic_inc(&net_device->NumOutstandingSends); - PutNetDevice(device); + put_net_device(device); return ret; } -static void NetVscOnReceive(struct hv_device *device, +static void netvsc_receive(struct hv_device *device, struct vmpacket_descriptor *packet) { struct netvsc_device *net_device; @@ -972,7 +975,7 @@ static void NetVscOnReceive(struct hv_device *device, unsigned long flags; LIST_HEAD(listHead); - net_device = GetInboundNetDevice(device); + net_device = get_inbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); @@ -986,7 +989,7 @@ static void NetVscOnReceive(struct hv_device *device, if (packet->Type != VmbusPacketTypeDataUsingTransferPages) { DPRINT_ERR(NETVSC, "Unknown packet type received - %d", packet->Type); - PutNetDevice(device); + put_net_device(device); return; } @@ -998,7 +1001,7 @@ static void NetVscOnReceive(struct hv_device *device, NvspMessage1TypeSendRNDISPacket) { DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", nvsp_packet->Header.MessageType); - PutNetDevice(device); + put_net_device(device); return; } @@ -1011,7 +1014,7 @@ static void NetVscOnReceive(struct hv_device *device, DPRINT_ERR(NETVSC, "Invalid xfer page set id - " "expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, vmxferpage_packet->TransferPageSetId); - PutNetDevice(device); + put_net_device(device); return; } @@ -1051,10 +1054,10 @@ static void NetVscOnReceive(struct hv_device *device, spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); - NetVscSendReceiveCompletion(device, + netvsc_send_recv_completion(device, vmxferpage_packet->d.TransactionId); - PutNetDevice(device); + put_net_device(device); return; } @@ -1081,7 +1084,7 @@ static void NetVscOnReceive(struct hv_device *device, /* Initialize the netvsc packet */ netvsc_packet->XferPagePacket = xferpage_packet; netvsc_packet->Completion.Recv.OnReceiveCompletion = - NetVscOnReceiveCompletion; + netvsc_receive_completion; netvsc_packet->Completion.Recv.ReceiveCompletionContext = netvsc_packet; netvsc_packet->Device = device; @@ -1153,16 +1156,16 @@ static void NetVscOnReceive(struct hv_device *device, ((struct netvsc_driver *)device->Driver)-> OnReceiveCallback(device, netvsc_packet); - NetVscOnReceiveCompletion(netvsc_packet-> + netvsc_receive_completion(netvsc_packet-> Completion.Recv.ReceiveCompletionContext); } /* ASSERT(list_empty(&listHead)); */ - PutNetDevice(device); + put_net_device(device); } -static void NetVscSendReceiveCompletion(struct hv_device *device, +static void netvsc_send_recv_completion(struct hv_device *device, u64 transaction_id) { struct nvsp_message recvcompMessage; @@ -1207,7 +1210,7 @@ retry_send_cmplt: } /* Send a receive completion packet to RNDIS device (ie NetVsp) */ -static void NetVscOnReceiveCompletion(void *context) +static void netvsc_receive_completion(void *context) { struct hv_netvsc_packet *packet = context; struct hv_device *device = (struct hv_device *)packet->Device; @@ -1223,7 +1226,7 @@ static void NetVscOnReceiveCompletion(void *context) * send out receive completion, we are using GetInboundNetDevice() * since we may have disable outbound traffic already. */ - net_device = GetInboundNetDevice(device); + net_device = get_inbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "unable to get net device..." "device being destroyed?"); @@ -1254,12 +1257,12 @@ static void NetVscOnReceiveCompletion(void *context) /* Send a receive completion for the xfer page packet */ if (fsend_receive_comp) - NetVscSendReceiveCompletion(device, transaction_id); + netvsc_send_recv_completion(device, transaction_id); - PutNetDevice(device); + put_net_device(device); } -static void NetVscOnChannelCallback(void *context) +static void netvsc_channel_cb(void *context) { int ret; struct hv_device *device = context; @@ -1279,7 +1282,7 @@ static void NetVscOnChannelCallback(void *context) return; buffer = packet; - net_device = GetInboundNetDevice(device); + net_device = get_inbound_net_device(device); if (!net_device) { DPRINT_ERR(NETVSC, "net device (%p) shutting down..." "ignoring inbound packets", net_device); @@ -1297,11 +1300,11 @@ static void NetVscOnChannelCallback(void *context) desc = (struct vmpacket_descriptor *)buffer; switch (desc->Type) { case VmbusPacketTypeCompletion: - NetVscOnSendCompletion(device, desc); + netvsc_send_completion(device, desc); break; case VmbusPacketTypeDataUsingTransferPages: - NetVscOnReceive(device, desc); + netvsc_receive(device, desc); break; default: @@ -1344,7 +1347,7 @@ static void NetVscOnChannelCallback(void *context) } } while (1); - PutNetDevice(device); + put_net_device(device); out: kfree(buffer); return; diff --git a/drivers/staging/hv/netvsc_api.h b/drivers/staging/hv/netvsc_api.h index 4b5b3ac458c8..dbf154acd967 100644 --- a/drivers/staging/hv/netvsc_api.h +++ b/drivers/staging/hv/netvsc_api.h @@ -109,7 +109,7 @@ struct netvsc_device_info { }; /* Interface */ -int NetVscInitialize(struct hv_driver *drv); +int netvsc_initialize(struct hv_driver *drv); int RndisFilterOnOpen(struct hv_device *Device); int RndisFilterOnClose(struct hv_device *Device); diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index f527e5f24f56..cd3eef04e59e 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -539,7 +539,7 @@ static int __init netvsc_init(void) if (!dmi_check_system(hv_netvsc_dmi_table)) return -ENODEV; - return netvsc_drv_init(NetVscInitialize); + return netvsc_drv_init(netvsc_initialize); } static void __exit netvsc_exit(void) -- cgit v1.2.3 From c2a4efddc73bfd44479fc8d84dadbb352c4efb07 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:03:56 -0800 Subject: staging: hv: Convert camel cased variables in rndis_filter.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/rndis_filter.c | 582 +++++++++++++++++++------------------- 1 file changed, 296 insertions(+), 286 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index b85c82542421..28b7e7e59f0a 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -32,7 +32,7 @@ /* Data types */ struct rndis_filter_driver_object { /* The original driver */ - struct netvsc_driver InnerDriver; + struct netvsc_driver inner_drv; }; enum rndis_device_state { @@ -43,61 +43,61 @@ enum rndis_device_state { }; struct rndis_device { - struct netvsc_device *NetDevice; + struct netvsc_device *net_dev; - enum rndis_device_state State; - u32 LinkStatus; - atomic_t NewRequestId; + enum rndis_device_state state; + u32 link_stat; + atomic_t new_req_id; spinlock_t request_lock; - struct list_head RequestList; + struct list_head req_list; - unsigned char HwMacAddr[ETH_ALEN]; + unsigned char hw_mac_adr[ETH_ALEN]; }; struct rndis_request { - struct list_head ListEntry; - struct osd_waitevent *WaitEvent; + struct list_head list_ent; + struct osd_waitevent *waitevent; /* * FIXME: We assumed a fixed size response here. If we do ever need to * handle a bigger response, we can either define a max response * message or add a response buffer variable above this field */ - struct rndis_message ResponseMessage; + struct rndis_message response_msg; /* Simplify allocation by having a netvsc packet inline */ - struct hv_netvsc_packet Packet; - struct hv_page_buffer Buffer; + struct hv_netvsc_packet pkt; + struct hv_page_buffer buf; /* FIXME: We assumed a fixed size request here. */ - struct rndis_message RequestMessage; + struct rndis_message request_msg; }; struct rndis_filter_packet { - void *CompletionContext; - void (*OnCompletion)(void *context); - struct rndis_message Message; + void *completion_ctx; + void (*completion)(void *context); + struct rndis_message msg; }; -static int RndisFilterOnDeviceAdd(struct hv_device *Device, - void *AdditionalInfo); +static int RndisFilterOnDeviceAdd(struct hv_device *dev, + void *additional_info); -static int RndisFilterOnDeviceRemove(struct hv_device *Device); +static int RndisFilterOnDeviceRemove(struct hv_device *dev); -static void RndisFilterOnCleanup(struct hv_driver *Driver); +static void RndisFilterOnCleanup(struct hv_driver *drv); -static int RndisFilterOnSend(struct hv_device *Device, - struct hv_netvsc_packet *Packet); +static int RndisFilterOnSend(struct hv_device *dev, + struct hv_netvsc_packet *pkt); -static void RndisFilterOnSendCompletion(void *Context); +static void RndisFilterOnSendCompletion(void *ctx); -static void RndisFilterOnSendRequestCompletion(void *Context); +static void RndisFilterOnSendRequestCompletion(void *ctx); /* The one and only */ -static struct rndis_filter_driver_object gRndisFilter; +static struct rndis_filter_driver_object rndis_filter; static struct rndis_device *GetRndisDevice(void) { @@ -109,19 +109,19 @@ static struct rndis_device *GetRndisDevice(void) spin_lock_init(&device->request_lock); - INIT_LIST_HEAD(&device->RequestList); + INIT_LIST_HEAD(&device->req_list); - device->State = RNDIS_DEV_UNINITIALIZED; + device->state = RNDIS_DEV_UNINITIALIZED; return device; } -static struct rndis_request *GetRndisRequest(struct rndis_device *Device, - u32 MessageType, - u32 MessageLength) +static struct rndis_request *GetRndisRequest(struct rndis_device *dev, + u32 msg_type, + u32 msg_len) { struct rndis_request *request; - struct rndis_message *rndisMessage; + struct rndis_message *rndis_msg; struct rndis_set_request *set; unsigned long flags; @@ -129,61 +129,61 @@ static struct rndis_request *GetRndisRequest(struct rndis_device *Device, if (!request) return NULL; - request->WaitEvent = osd_waitevent_create(); - if (!request->WaitEvent) { + request->waitevent = osd_waitevent_create(); + if (!request->waitevent) { kfree(request); return NULL; } - rndisMessage = &request->RequestMessage; - rndisMessage->NdisMessageType = MessageType; - rndisMessage->MessageLength = MessageLength; + rndis_msg = &request->request_msg; + rndis_msg->NdisMessageType = msg_type; + rndis_msg->MessageLength = msg_len; /* * Set the request id. This field is always after the rndis header for * request/response packet types so we just used the SetRequest as a * template */ - set = &rndisMessage->Message.SetRequest; - set->RequestId = atomic_inc_return(&Device->NewRequestId); + set = &rndis_msg->Message.SetRequest; + set->RequestId = atomic_inc_return(&dev->new_req_id); /* Add to the request list */ - spin_lock_irqsave(&Device->request_lock, flags); - list_add_tail(&request->ListEntry, &Device->RequestList); - spin_unlock_irqrestore(&Device->request_lock, flags); + spin_lock_irqsave(&dev->request_lock, flags); + list_add_tail(&request->list_ent, &dev->req_list); + spin_unlock_irqrestore(&dev->request_lock, flags); return request; } -static void PutRndisRequest(struct rndis_device *Device, - struct rndis_request *Request) +static void PutRndisRequest(struct rndis_device *dev, + struct rndis_request *req) { unsigned long flags; - spin_lock_irqsave(&Device->request_lock, flags); - list_del(&Request->ListEntry); - spin_unlock_irqrestore(&Device->request_lock, flags); + spin_lock_irqsave(&dev->request_lock, flags); + list_del(&req->list_ent); + spin_unlock_irqrestore(&dev->request_lock, flags); - kfree(Request->WaitEvent); - kfree(Request); + kfree(req->waitevent); + kfree(req); } -static void DumpRndisMessage(struct rndis_message *RndisMessage) +static void DumpRndisMessage(struct rndis_message *rndis_msg) { - switch (RndisMessage->NdisMessageType) { + switch (rndis_msg->NdisMessageType) { case REMOTE_NDIS_PACKET_MSG: DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, " "data offset %u data len %u, # oob %u, " "oob offset %u, oob len %u, pkt offset %u, " "pkt len %u", - RndisMessage->MessageLength, - RndisMessage->Message.Packet.DataOffset, - RndisMessage->Message.Packet.DataLength, - RndisMessage->Message.Packet.NumOOBDataElements, - RndisMessage->Message.Packet.OOBDataOffset, - RndisMessage->Message.Packet.OOBDataLength, - RndisMessage->Message.Packet.PerPacketInfoOffset, - RndisMessage->Message.Packet.PerPacketInfoLength); + rndis_msg->MessageLength, + rndis_msg->Message.Packet.DataOffset, + rndis_msg->Message.Packet.DataLength, + rndis_msg->Message.Packet.NumOOBDataElements, + rndis_msg->Message.Packet.OOBDataOffset, + rndis_msg->Message.Packet.OOBDataLength, + rndis_msg->Message.Packet.PerPacketInfoOffset, + rndis_msg->Message.Packet.PerPacketInfoLength); break; case REMOTE_NDIS_INITIALIZE_CMPLT: @@ -191,147 +191,157 @@ static void DumpRndisMessage(struct rndis_message *RndisMessage) "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " "device flags %d, max xfer size 0x%x, max pkts %u, " "pkt aligned %u)", - RndisMessage->MessageLength, - RndisMessage->Message.InitializeComplete.RequestId, - RndisMessage->Message.InitializeComplete.Status, - RndisMessage->Message.InitializeComplete.MajorVersion, - RndisMessage->Message.InitializeComplete.MinorVersion, - RndisMessage->Message.InitializeComplete.DeviceFlags, - RndisMessage->Message.InitializeComplete.MaxTransferSize, - RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage, - RndisMessage->Message.InitializeComplete.PacketAlignmentFactor); + rndis_msg->MessageLength, + rndis_msg->Message.InitializeComplete.RequestId, + rndis_msg->Message.InitializeComplete.Status, + rndis_msg->Message.InitializeComplete.MajorVersion, + rndis_msg->Message.InitializeComplete.MinorVersion, + rndis_msg->Message.InitializeComplete.DeviceFlags, + rndis_msg->Message.InitializeComplete.MaxTransferSize, + rndis_msg->Message.InitializeComplete. + MaxPacketsPerMessage, + rndis_msg->Message.InitializeComplete. + PacketAlignmentFactor); break; case REMOTE_NDIS_QUERY_CMPLT: DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT " "(len %u, id 0x%x, status 0x%x, buf len %u, " "buf offset %u)", - RndisMessage->MessageLength, - RndisMessage->Message.QueryComplete.RequestId, - RndisMessage->Message.QueryComplete.Status, - RndisMessage->Message.QueryComplete.InformationBufferLength, - RndisMessage->Message.QueryComplete.InformationBufferOffset); + rndis_msg->MessageLength, + rndis_msg->Message.QueryComplete.RequestId, + rndis_msg->Message.QueryComplete.Status, + rndis_msg->Message.QueryComplete. + InformationBufferLength, + rndis_msg->Message.QueryComplete. + InformationBufferOffset); break; case REMOTE_NDIS_SET_CMPLT: DPRINT_DBG(NETVSC, "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)", - RndisMessage->MessageLength, - RndisMessage->Message.SetComplete.RequestId, - RndisMessage->Message.SetComplete.Status); + rndis_msg->MessageLength, + rndis_msg->Message.SetComplete.RequestId, + rndis_msg->Message.SetComplete.Status); break; case REMOTE_NDIS_INDICATE_STATUS_MSG: DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG " "(len %u, status 0x%x, buf len %u, buf offset %u)", - RndisMessage->MessageLength, - RndisMessage->Message.IndicateStatus.Status, - RndisMessage->Message.IndicateStatus.StatusBufferLength, - RndisMessage->Message.IndicateStatus.StatusBufferOffset); + rndis_msg->MessageLength, + rndis_msg->Message.IndicateStatus.Status, + rndis_msg->Message.IndicateStatus.StatusBufferLength, + rndis_msg->Message.IndicateStatus.StatusBufferOffset); break; default: DPRINT_DBG(NETVSC, "0x%x (len %u)", - RndisMessage->NdisMessageType, - RndisMessage->MessageLength); + rndis_msg->NdisMessageType, + rndis_msg->MessageLength); break; } } -static int RndisFilterSendRequest(struct rndis_device *Device, - struct rndis_request *Request) +static int RndisFilterSendRequest(struct rndis_device *dev, + struct rndis_request *req) { int ret; struct hv_netvsc_packet *packet; /* Setup the packet to send it */ - packet = &Request->Packet; + packet = &req->pkt; packet->IsDataPacket = false; - packet->TotalDataBufferLength = Request->RequestMessage.MessageLength; + packet->TotalDataBufferLength = req->request_msg.MessageLength; packet->PageBufferCount = 1; - packet->PageBuffers[0].Pfn = virt_to_phys(&Request->RequestMessage) >> + packet->PageBuffers[0].Pfn = virt_to_phys(&req->request_msg) >> PAGE_SHIFT; - packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength; + packet->PageBuffers[0].Length = req->request_msg.MessageLength; packet->PageBuffers[0].Offset = - (unsigned long)&Request->RequestMessage & (PAGE_SIZE - 1); + (unsigned long)&req->request_msg & (PAGE_SIZE - 1); - packet->Completion.Send.SendCompletionContext = Request;/* packet; */ + packet->Completion.Send.SendCompletionContext = req;/* packet; */ packet->Completion.Send.OnSendCompletion = RndisFilterOnSendRequestCompletion; - packet->Completion.Send.SendCompletionTid = (unsigned long)Device; + packet->Completion.Send.SendCompletionTid = (unsigned long)dev; - ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet); + ret = rndis_filter.inner_drv.OnSend(dev->net_dev->Device, packet); return ret; } -static void RndisFilterReceiveResponse(struct rndis_device *Device, - struct rndis_message *Response) +static void RndisFilterReceiveResponse(struct rndis_device *dev, + struct rndis_message *resp) { struct rndis_request *request = NULL; bool found = false; unsigned long flags; - spin_lock_irqsave(&Device->request_lock, flags); - list_for_each_entry(request, &Device->RequestList, ListEntry) { + spin_lock_irqsave(&dev->request_lock, flags); + list_for_each_entry(request, &dev->req_list, list_ent) { /* * All request/response message contains RequestId as the 1st * field */ - if (request->RequestMessage.Message.InitializeRequest.RequestId - == Response->Message.InitializeComplete.RequestId) { + if (request->request_msg.Message.InitializeRequest.RequestId + == resp->Message.InitializeComplete.RequestId) { DPRINT_DBG(NETVSC, "found rndis request for " "this response (id 0x%x req type 0x%x res " "type 0x%x)", - request->RequestMessage.Message.InitializeRequest.RequestId, - request->RequestMessage.NdisMessageType, - Response->NdisMessageType); + request->request_msg.Message. + InitializeRequest.RequestId, + request->request_msg.NdisMessageType, + resp->NdisMessageType); found = true; break; } } - spin_unlock_irqrestore(&Device->request_lock, flags); + spin_unlock_irqrestore(&dev->request_lock, flags); if (found) { - if (Response->MessageLength <= sizeof(struct rndis_message)) { - memcpy(&request->ResponseMessage, Response, - Response->MessageLength); + if (resp->MessageLength <= sizeof(struct rndis_message)) { + memcpy(&request->response_msg, resp, + resp->MessageLength); } else { DPRINT_ERR(NETVSC, "rndis response buffer overflow " "detected (size %u max %zu)", - Response->MessageLength, + resp->MessageLength, sizeof(struct rndis_filter_packet)); - if (Response->NdisMessageType == + if (resp->NdisMessageType == REMOTE_NDIS_RESET_CMPLT) { /* does not have a request id field */ - request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW; + request->response_msg.Message.ResetComplete. + Status = STATUS_BUFFER_OVERFLOW; } else { - request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW; + request->response_msg.Message. + InitializeComplete.Status = + STATUS_BUFFER_OVERFLOW; } } - osd_waitevent_set(request->WaitEvent); + osd_waitevent_set(request->waitevent); } else { DPRINT_ERR(NETVSC, "no rndis request found for this response " "(id 0x%x res type 0x%x)", - Response->Message.InitializeComplete.RequestId, - Response->NdisMessageType); + resp->Message.InitializeComplete.RequestId, + resp->NdisMessageType); } } -static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device, - struct rndis_message *Response) +static void RndisFilterReceiveIndicateStatus(struct rndis_device *dev, + struct rndis_message *resp) { struct rndis_indicate_status *indicate = - &Response->Message.IndicateStatus; + &resp->Message.IndicateStatus; if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) { - gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1); + rndis_filter.inner_drv.OnLinkStatusChanged( + dev->net_dev->Device, 1); } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) { - gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0); + rndis_filter.inner_drv.OnLinkStatusChanged( + dev->net_dev->Device, 0); } else { /* * TODO: @@ -339,18 +349,18 @@ static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device, } } -static void RndisFilterReceiveData(struct rndis_device *Device, - struct rndis_message *Message, - struct hv_netvsc_packet *Packet) +static void RndisFilterReceiveData(struct rndis_device *dev, + struct rndis_message *msg, + struct hv_netvsc_packet *pkt) { - struct rndis_packet *rndisPacket; - u32 dataOffset; + struct rndis_packet *rndis_pkt; + u32 data_offset; /* empty ethernet frame ?? */ /* ASSERT(Packet->PageBuffers[0].Length > */ /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */ - rndisPacket = &Message->Message.Packet; + rndis_pkt = &msg->Message.Packet; /* * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this @@ -358,48 +368,48 @@ static void RndisFilterReceiveData(struct rndis_device *Device, */ /* Remove the rndis header and pass it back up the stack */ - dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset; + data_offset = RNDIS_HEADER_SIZE + rndis_pkt->DataOffset; - Packet->TotalDataBufferLength -= dataOffset; - Packet->PageBuffers[0].Offset += dataOffset; - Packet->PageBuffers[0].Length -= dataOffset; + pkt->TotalDataBufferLength -= data_offset; + pkt->PageBuffers[0].Offset += data_offset; + pkt->PageBuffers[0].Length -= data_offset; - Packet->IsDataPacket = true; + pkt->IsDataPacket = true; - gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, - Packet); + rndis_filter.inner_drv.OnReceiveCallback(dev->net_dev->Device, + pkt); } -static int RndisFilterOnReceive(struct hv_device *Device, - struct hv_netvsc_packet *Packet) +static int RndisFilterOnReceive(struct hv_device *dev, + struct hv_netvsc_packet *pkt) { - struct netvsc_device *netDevice = Device->Extension; - struct rndis_device *rndisDevice; - struct rndis_message rndisMessage; - struct rndis_message *rndisHeader; + struct netvsc_device *net_dev = dev->Extension; + struct rndis_device *rndis_dev; + struct rndis_message rndis_msg; + struct rndis_message *rndis_hdr; - if (!netDevice) + if (!net_dev) return -EINVAL; /* Make sure the rndis device state is initialized */ - if (!netDevice->Extension) { + if (!net_dev->Extension) { DPRINT_ERR(NETVSC, "got rndis message but no rndis device..." "dropping this message!"); return -1; } - rndisDevice = (struct rndis_device *)netDevice->Extension; - if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) { + rndis_dev = (struct rndis_device *)net_dev->Extension; + if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { DPRINT_ERR(NETVSC, "got rndis message but rndis device " "uninitialized...dropping this message!"); return -1; } - rndisHeader = (struct rndis_message *)kmap_atomic( - pfn_to_page(Packet->PageBuffers[0].Pfn), KM_IRQ0); + rndis_hdr = (struct rndis_message *)kmap_atomic( + pfn_to_page(pkt->PageBuffers[0].Pfn), KM_IRQ0); - rndisHeader = (void *)((unsigned long)rndisHeader + - Packet->PageBuffers[0].Offset); + rndis_hdr = (void *)((unsigned long)rndis_hdr + + pkt->PageBuffers[0].Offset); /* Make sure we got a valid rndis message */ /* @@ -408,39 +418,39 @@ static int RndisFilterOnReceive(struct hv_device *Device, * range shows 52 bytes * */ #if 0 - if (Packet->TotalDataBufferLength != rndisHeader->MessageLength) { - kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, + if (pkt->TotalDataBufferLength != rndis_hdr->MessageLength) { + kunmap_atomic(rndis_hdr - pkt->PageBuffers[0].Offset, KM_IRQ0); DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u " "bytes got %u)...dropping this message!", - rndisHeader->MessageLength, - Packet->TotalDataBufferLength); + rndis_hdr->MessageLength, + pkt->TotalDataBufferLength); return -1; } #endif - if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && - (rndisHeader->MessageLength > sizeof(struct rndis_message))) { + if ((rndis_hdr->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && + (rndis_hdr->MessageLength > sizeof(struct rndis_message))) { DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow " "detected (got %u, max %zu)...marking it an error!", - rndisHeader->MessageLength, + rndis_hdr->MessageLength, sizeof(struct rndis_message)); } - memcpy(&rndisMessage, rndisHeader, - (rndisHeader->MessageLength > sizeof(struct rndis_message)) ? + memcpy(&rndis_msg, rndis_hdr, + (rndis_hdr->MessageLength > sizeof(struct rndis_message)) ? sizeof(struct rndis_message) : - rndisHeader->MessageLength); + rndis_hdr->MessageLength); - kunmap_atomic(rndisHeader - Packet->PageBuffers[0].Offset, KM_IRQ0); + kunmap_atomic(rndis_hdr - pkt->PageBuffers[0].Offset, KM_IRQ0); - DumpRndisMessage(&rndisMessage); + DumpRndisMessage(&rndis_msg); - switch (rndisMessage.NdisMessageType) { + switch (rndis_msg.NdisMessageType) { case REMOTE_NDIS_PACKET_MSG: /* data msg */ - RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet); + RndisFilterReceiveData(rndis_dev, &rndis_msg, pkt); break; case REMOTE_NDIS_INITIALIZE_CMPLT: @@ -449,37 +459,37 @@ static int RndisFilterOnReceive(struct hv_device *Device, /* case REMOTE_NDIS_RESET_CMPLT: */ /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */ /* completion msgs */ - RndisFilterReceiveResponse(rndisDevice, &rndisMessage); + RndisFilterReceiveResponse(rndis_dev, &rndis_msg); break; case REMOTE_NDIS_INDICATE_STATUS_MSG: /* notification msgs */ - RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage); + RndisFilterReceiveIndicateStatus(rndis_dev, &rndis_msg); break; default: DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", - rndisMessage.NdisMessageType, - rndisMessage.MessageLength); + rndis_msg.NdisMessageType, + rndis_msg.MessageLength); break; } return 0; } -static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid, - void *Result, u32 *ResultSize) +static int RndisFilterQueryDevice(struct rndis_device *dev, u32 oid, + void *result, u32 *result_size) { struct rndis_request *request; - u32 inresultSize = *ResultSize; + u32 inresult_size = *result_size; struct rndis_query_request *query; - struct rndis_query_complete *queryComplete; + struct rndis_query_complete *query_complete; int ret = 0; - if (!Result) + if (!result) return -EINVAL; - *ResultSize = 0; - request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, + *result_size = 0; + request = GetRndisRequest(dev, REMOTE_NDIS_QUERY_MSG, RNDIS_MESSAGE_SIZE(struct rndis_query_request)); if (!request) { ret = -1; @@ -487,71 +497,71 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid, } /* Setup the rndis query */ - query = &request->RequestMessage.Message.QueryRequest; - query->Oid = Oid; + query = &request->request_msg.Message.QueryRequest; + query->Oid = oid; query->InformationBufferOffset = sizeof(struct rndis_query_request); query->InformationBufferLength = 0; query->DeviceVcHandle = 0; - ret = RndisFilterSendRequest(Device, request); + ret = RndisFilterSendRequest(dev, request); if (ret != 0) goto Cleanup; - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->waitevent); /* Copy the response back */ - queryComplete = &request->ResponseMessage.Message.QueryComplete; + query_complete = &request->response_msg.Message.QueryComplete; - if (queryComplete->InformationBufferLength > inresultSize) { + if (query_complete->InformationBufferLength > inresult_size) { ret = -1; goto Cleanup; } - memcpy(Result, - (void *)((unsigned long)queryComplete + - queryComplete->InformationBufferOffset), - queryComplete->InformationBufferLength); + memcpy(result, + (void *)((unsigned long)query_complete + + query_complete->InformationBufferOffset), + query_complete->InformationBufferLength); - *ResultSize = queryComplete->InformationBufferLength; + *result_size = query_complete->InformationBufferLength; Cleanup: if (request) - PutRndisRequest(Device, request); + PutRndisRequest(dev, request); return ret; } -static int RndisFilterQueryDeviceMac(struct rndis_device *Device) +static int RndisFilterQueryDeviceMac(struct rndis_device *dev) { u32 size = ETH_ALEN; - return RndisFilterQueryDevice(Device, + return RndisFilterQueryDevice(dev, RNDIS_OID_802_3_PERMANENT_ADDRESS, - Device->HwMacAddr, &size); + dev->hw_mac_adr, &size); } -static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *Device) +static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *dev) { u32 size = sizeof(u32); - return RndisFilterQueryDevice(Device, + return RndisFilterQueryDevice(dev, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, - &Device->LinkStatus, &size); + &dev->link_stat, &size); } -static int RndisFilterSetPacketFilter(struct rndis_device *Device, - u32 NewFilter) +static int RndisFilterSetPacketFilter(struct rndis_device *dev, + u32 new_filter) { struct rndis_request *request; struct rndis_set_request *set; - struct rndis_set_complete *setComplete; + struct rndis_set_complete *set_complete; u32 status; int ret; /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */ /* sizeof(struct rndis_message)); */ - request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, + request = GetRndisRequest(dev, REMOTE_NDIS_SET_MSG, RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32)); if (!request) { @@ -560,19 +570,19 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device, } /* Setup the rndis set */ - set = &request->RequestMessage.Message.SetRequest; + set = &request->request_msg.Message.SetRequest; set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; set->InformationBufferLength = sizeof(u32); set->InformationBufferOffset = sizeof(struct rndis_set_request); memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), - &NewFilter, sizeof(u32)); + &new_filter, sizeof(u32)); - ret = RndisFilterSendRequest(Device, request); + ret = RndisFilterSendRequest(dev, request); if (ret != 0) goto Cleanup; - ret = osd_waitevent_waitex(request->WaitEvent, 2000/*2sec*/); + ret = osd_waitevent_waitex(request->waitevent, 2000/*2sec*/); if (!ret) { ret = -1; DPRINT_ERR(NETVSC, "timeout before we got a set response..."); @@ -584,27 +594,27 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device, } else { if (ret > 0) ret = 0; - setComplete = &request->ResponseMessage.Message.SetComplete; - status = setComplete->Status; + set_complete = &request->response_msg.Message.SetComplete; + status = set_complete->Status; } Cleanup: if (request) - PutRndisRequest(Device, request); + PutRndisRequest(dev, request); Exit: return ret; } -int RndisFilterInit(struct netvsc_driver *Driver) +int RndisFilterInit(struct netvsc_driver *drv) { DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd", sizeof(struct rndis_filter_packet)); - Driver->RequestExtSize = sizeof(struct rndis_filter_packet); + drv->RequestExtSize = sizeof(struct rndis_filter_packet); /* Driver->Context = rndisDriver; */ - memset(&gRndisFilter, 0, sizeof(struct rndis_filter_driver_object)); + memset(&rndis_filter, 0, sizeof(struct rndis_filter_driver_object)); /*rndisDriver->Driver = Driver; @@ -612,38 +622,38 @@ int RndisFilterInit(struct netvsc_driver *Driver) rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ /* Save the original dispatch handlers before we override it */ - gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd; - gRndisFilter.InnerDriver.Base.OnDeviceRemove = - Driver->Base.OnDeviceRemove; - gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup; + rndis_filter.inner_drv.Base.OnDeviceAdd = drv->Base.OnDeviceAdd; + rndis_filter.inner_drv.Base.OnDeviceRemove = + drv->Base.OnDeviceRemove; + rndis_filter.inner_drv.Base.OnCleanup = drv->Base.OnCleanup; /* ASSERT(Driver->OnSend); */ /* ASSERT(Driver->OnReceiveCallback); */ - gRndisFilter.InnerDriver.OnSend = Driver->OnSend; - gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback; - gRndisFilter.InnerDriver.OnLinkStatusChanged = - Driver->OnLinkStatusChanged; + rndis_filter.inner_drv.OnSend = drv->OnSend; + rndis_filter.inner_drv.OnReceiveCallback = drv->OnReceiveCallback; + rndis_filter.inner_drv.OnLinkStatusChanged = + drv->OnLinkStatusChanged; /* Override */ - Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; - Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; - Driver->Base.OnCleanup = RndisFilterOnCleanup; - Driver->OnSend = RndisFilterOnSend; + drv->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; + drv->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; + drv->Base.OnCleanup = RndisFilterOnCleanup; + drv->OnSend = RndisFilterOnSend; /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ - Driver->OnReceiveCallback = RndisFilterOnReceive; + drv->OnReceiveCallback = RndisFilterOnReceive; return 0; } -static int RndisFilterInitDevice(struct rndis_device *Device) +static int RndisFilterInitDevice(struct rndis_device *dev) { struct rndis_request *request; struct rndis_initialize_request *init; - struct rndis_initialize_complete *initComplete; + struct rndis_initialize_complete *init_complete; u32 status; int ret; - request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, + request = GetRndisRequest(dev, REMOTE_NDIS_INITIALIZE_MSG, RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); if (!request) { ret = -1; @@ -651,103 +661,103 @@ static int RndisFilterInitDevice(struct rndis_device *Device) } /* Setup the rndis set */ - init = &request->RequestMessage.Message.InitializeRequest; + init = &request->request_msg.Message.InitializeRequest; init->MajorVersion = RNDIS_MAJOR_VERSION; init->MinorVersion = RNDIS_MINOR_VERSION; /* FIXME: Use 1536 - rounded ethernet frame size */ init->MaxTransferSize = 2048; - Device->State = RNDIS_DEV_INITIALIZING; + dev->state = RNDIS_DEV_INITIALIZING; - ret = RndisFilterSendRequest(Device, request); + ret = RndisFilterSendRequest(dev, request); if (ret != 0) { - Device->State = RNDIS_DEV_UNINITIALIZED; + dev->state = RNDIS_DEV_UNINITIALIZED; goto Cleanup; } - osd_waitevent_wait(request->WaitEvent); + osd_waitevent_wait(request->waitevent); - initComplete = &request->ResponseMessage.Message.InitializeComplete; - status = initComplete->Status; + init_complete = &request->response_msg.Message.InitializeComplete; + status = init_complete->Status; if (status == RNDIS_STATUS_SUCCESS) { - Device->State = RNDIS_DEV_INITIALIZED; + dev->state = RNDIS_DEV_INITIALIZED; ret = 0; } else { - Device->State = RNDIS_DEV_UNINITIALIZED; + dev->state = RNDIS_DEV_UNINITIALIZED; ret = -1; } Cleanup: if (request) - PutRndisRequest(Device, request); + PutRndisRequest(dev, request); return ret; } -static void RndisFilterHaltDevice(struct rndis_device *Device) +static void RndisFilterHaltDevice(struct rndis_device *dev) { struct rndis_request *request; struct rndis_halt_request *halt; /* Attempt to do a rndis device halt */ - request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, + request = GetRndisRequest(dev, REMOTE_NDIS_HALT_MSG, RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); if (!request) goto Cleanup; /* Setup the rndis set */ - halt = &request->RequestMessage.Message.HaltRequest; - halt->RequestId = atomic_inc_return(&Device->NewRequestId); + halt = &request->request_msg.Message.HaltRequest; + halt->RequestId = atomic_inc_return(&dev->new_req_id); /* Ignore return since this msg is optional. */ - RndisFilterSendRequest(Device, request); + RndisFilterSendRequest(dev, request); - Device->State = RNDIS_DEV_UNINITIALIZED; + dev->state = RNDIS_DEV_UNINITIALIZED; Cleanup: if (request) - PutRndisRequest(Device, request); + PutRndisRequest(dev, request); return; } -static int RndisFilterOpenDevice(struct rndis_device *Device) +static int RndisFilterOpenDevice(struct rndis_device *dev) { int ret; - if (Device->State != RNDIS_DEV_INITIALIZED) + if (dev->state != RNDIS_DEV_INITIALIZED) return 0; - ret = RndisFilterSetPacketFilter(Device, + ret = RndisFilterSetPacketFilter(dev, NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_DIRECTED); if (ret == 0) - Device->State = RNDIS_DEV_DATAINITIALIZED; + dev->state = RNDIS_DEV_DATAINITIALIZED; return ret; } -static int RndisFilterCloseDevice(struct rndis_device *Device) +static int RndisFilterCloseDevice(struct rndis_device *dev) { int ret; - if (Device->State != RNDIS_DEV_DATAINITIALIZED) + if (dev->state != RNDIS_DEV_DATAINITIALIZED) return 0; - ret = RndisFilterSetPacketFilter(Device, 0); + ret = RndisFilterSetPacketFilter(dev, 0); if (ret == 0) - Device->State = RNDIS_DEV_INITIALIZED; + dev->state = RNDIS_DEV_INITIALIZED; return ret; } -static int RndisFilterOnDeviceAdd(struct hv_device *Device, - void *AdditionalInfo) +static int RndisFilterOnDeviceAdd(struct hv_device *dev, + void *additional_info) { int ret; struct netvsc_device *netDevice; struct rndis_device *rndisDevice; - struct netvsc_device_info *deviceInfo = AdditionalInfo; + struct netvsc_device_info *deviceInfo = additional_info; rndisDevice = GetRndisDevice(); if (!rndisDevice) @@ -760,7 +770,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device, * NOTE! Once the channel is created, we may get a receive callback * (RndisFilterOnReceive()) before this call is completed */ - ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo); + ret = rndis_filter.inner_drv.Base.OnDeviceAdd(dev, additional_info); if (ret != 0) { kfree(rndisDevice); return ret; @@ -768,12 +778,12 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device, /* Initialize the rndis device */ - netDevice = Device->Extension; + netDevice = dev->Extension; /* ASSERT(netDevice); */ /* ASSERT(netDevice->Device); */ netDevice->Extension = rndisDevice; - rndisDevice->NetDevice = netDevice; + rndisDevice->net_dev = netDevice; /* Send the rndis initialization message */ ret = RndisFilterInitDevice(rndisDevice); @@ -793,43 +803,43 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device, } DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM", - rndisDevice, rndisDevice->HwMacAddr); + rndisDevice, rndisDevice->hw_mac_adr); - memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, ETH_ALEN); + memcpy(deviceInfo->MacAddr, rndisDevice->hw_mac_adr, ETH_ALEN); RndisFilterQueryDeviceLinkStatus(rndisDevice); - deviceInfo->LinkState = rndisDevice->LinkStatus; + deviceInfo->LinkState = rndisDevice->link_stat; DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, ((deviceInfo->LinkState) ? ("down") : ("up"))); return ret; } -static int RndisFilterOnDeviceRemove(struct hv_device *Device) +static int RndisFilterOnDeviceRemove(struct hv_device *dev) { - struct netvsc_device *netDevice = Device->Extension; - struct rndis_device *rndisDevice = netDevice->Extension; + struct netvsc_device *net_dev = dev->Extension; + struct rndis_device *rndis_dev = net_dev->Extension; /* Halt and release the rndis device */ - RndisFilterHaltDevice(rndisDevice); + RndisFilterHaltDevice(rndis_dev); - kfree(rndisDevice); - netDevice->Extension = NULL; + kfree(rndis_dev); + net_dev->Extension = NULL; /* Pass control to inner driver to remove the device */ - gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device); + rndis_filter.inner_drv.Base.OnDeviceRemove(dev); return 0; } -static void RndisFilterOnCleanup(struct hv_driver *Driver) +static void RndisFilterOnCleanup(struct hv_driver *drv) { } -int RndisFilterOnOpen(struct hv_device *Device) +int RndisFilterOnOpen(struct hv_device *dev) { - struct netvsc_device *netDevice = Device->Extension; + struct netvsc_device *netDevice = dev->Extension; if (!netDevice) return -EINVAL; @@ -837,9 +847,9 @@ int RndisFilterOnOpen(struct hv_device *Device) return RndisFilterOpenDevice(netDevice->Extension); } -int RndisFilterOnClose(struct hv_device *Device) +int RndisFilterOnClose(struct hv_device *dev) { - struct netvsc_device *netDevice = Device->Extension; + struct netvsc_device *netDevice = dev->Extension; if (!netDevice) return -EINVAL; @@ -847,8 +857,8 @@ int RndisFilterOnClose(struct hv_device *Device) return RndisFilterCloseDevice(netDevice->Extension); } -static int RndisFilterOnSend(struct hv_device *Device, - struct hv_netvsc_packet *Packet) +static int RndisFilterOnSend(struct hv_device *dev, + struct hv_netvsc_packet *pkt) { int ret; struct rndis_filter_packet *filterPacket; @@ -857,62 +867,62 @@ static int RndisFilterOnSend(struct hv_device *Device, u32 rndisMessageSize; /* Add the rndis header */ - filterPacket = (struct rndis_filter_packet *)Packet->Extension; + filterPacket = (struct rndis_filter_packet *)pkt->Extension; /* ASSERT(filterPacket); */ memset(filterPacket, 0, sizeof(struct rndis_filter_packet)); - rndisMessage = &filterPacket->Message; + rndisMessage = &filterPacket->msg; rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; - rndisMessage->MessageLength = Packet->TotalDataBufferLength + + rndisMessage->MessageLength = pkt->TotalDataBufferLength + rndisMessageSize; rndisPacket = &rndisMessage->Message.Packet; rndisPacket->DataOffset = sizeof(struct rndis_packet); - rndisPacket->DataLength = Packet->TotalDataBufferLength; + rndisPacket->DataLength = pkt->TotalDataBufferLength; - Packet->IsDataPacket = true; - Packet->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; - Packet->PageBuffers[0].Offset = + pkt->IsDataPacket = true; + pkt->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; + pkt->PageBuffers[0].Offset = (unsigned long)rndisMessage & (PAGE_SIZE-1); - Packet->PageBuffers[0].Length = rndisMessageSize; + pkt->PageBuffers[0].Length = rndisMessageSize; /* Save the packet send completion and context */ - filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion; - filterPacket->CompletionContext = - Packet->Completion.Send.SendCompletionContext; + filterPacket->completion = pkt->Completion.Send.OnSendCompletion; + filterPacket->completion_ctx = + pkt->Completion.Send.SendCompletionContext; /* Use ours */ - Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; - Packet->Completion.Send.SendCompletionContext = filterPacket; + pkt->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; + pkt->Completion.Send.SendCompletionContext = filterPacket; - ret = gRndisFilter.InnerDriver.OnSend(Device, Packet); + ret = rndis_filter.inner_drv.OnSend(dev, pkt); if (ret != 0) { /* * Reset the completion to originals to allow retries from * above */ - Packet->Completion.Send.OnSendCompletion = - filterPacket->OnCompletion; - Packet->Completion.Send.SendCompletionContext = - filterPacket->CompletionContext; + pkt->Completion.Send.OnSendCompletion = + filterPacket->completion; + pkt->Completion.Send.SendCompletionContext = + filterPacket->completion_ctx; } return ret; } -static void RndisFilterOnSendCompletion(void *Context) +static void RndisFilterOnSendCompletion(void *ctx) { - struct rndis_filter_packet *filterPacket = Context; + struct rndis_filter_packet *filterPacket = ctx; /* Pass it back to the original handler */ - filterPacket->OnCompletion(filterPacket->CompletionContext); + filterPacket->completion(filterPacket->completion_ctx); } -static void RndisFilterOnSendRequestCompletion(void *Context) +static void RndisFilterOnSendRequestCompletion(void *ctx) { /* Noop */ } -- cgit v1.2.3 From 9c26aa0d763a8390177f50ae841148706a249793 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:03:57 -0800 Subject: staging: hv: Convert camel cased functions in rndis_filter.c to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc.c | 2 +- drivers/staging/hv/netvsc_api.h | 4 +- drivers/staging/hv/netvsc_drv.c | 4 +- drivers/staging/hv/rndis_filter.c | 132 +++++++++++++++++++------------------- drivers/staging/hv/rndis_filter.h | 2 +- 5 files changed, 72 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index 781d7bd37102..5c327fc0d1fd 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -202,7 +202,7 @@ int netvsc_initialize(struct hv_driver *drv) driver->OnSend = netvsc_send; - RndisFilterInit(driver); + rndis_filter_init(driver); return 0; } diff --git a/drivers/staging/hv/netvsc_api.h b/drivers/staging/hv/netvsc_api.h index dbf154acd967..315271d69914 100644 --- a/drivers/staging/hv/netvsc_api.h +++ b/drivers/staging/hv/netvsc_api.h @@ -110,7 +110,7 @@ struct netvsc_device_info { /* Interface */ int netvsc_initialize(struct hv_driver *drv); -int RndisFilterOnOpen(struct hv_device *Device); -int RndisFilterOnClose(struct hv_device *Device); +int rndis_filter_open(struct hv_device *dev); +int rndis_filter_close(struct hv_device *dev); #endif /* _NETVSC_API_H_ */ diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index cd3eef04e59e..e47681e7be82 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -81,7 +81,7 @@ static int netvsc_open(struct net_device *net) if (netif_carrier_ok(net)) { /* Open up the device */ - ret = RndisFilterOnOpen(device_obj); + ret = rndis_filter_open(device_obj); if (ret != 0) { DPRINT_ERR(NETVSC_DRV, "unable to open device (ret %d).", ret); @@ -104,7 +104,7 @@ static int netvsc_close(struct net_device *net) netif_stop_queue(net); - ret = RndisFilterOnClose(device_obj); + ret = rndis_filter_close(device_obj); if (ret != 0) DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index 28b7e7e59f0a..e560f380adb5 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -81,25 +81,25 @@ struct rndis_filter_packet { }; -static int RndisFilterOnDeviceAdd(struct hv_device *dev, +static int rndis_filte_device_add(struct hv_device *dev, void *additional_info); -static int RndisFilterOnDeviceRemove(struct hv_device *dev); +static int rndis_filter_device_remove(struct hv_device *dev); -static void RndisFilterOnCleanup(struct hv_driver *drv); +static void rndis_filter_cleanup(struct hv_driver *drv); -static int RndisFilterOnSend(struct hv_device *dev, +static int rndis_filter_send(struct hv_device *dev, struct hv_netvsc_packet *pkt); -static void RndisFilterOnSendCompletion(void *ctx); +static void rndis_filter_send_completion(void *ctx); -static void RndisFilterOnSendRequestCompletion(void *ctx); +static void rndis_filter_send_request_completion(void *ctx); /* The one and only */ static struct rndis_filter_driver_object rndis_filter; -static struct rndis_device *GetRndisDevice(void) +static struct rndis_device *get_rndis_device(void) { struct rndis_device *device; @@ -116,7 +116,7 @@ static struct rndis_device *GetRndisDevice(void) return device; } -static struct rndis_request *GetRndisRequest(struct rndis_device *dev, +static struct rndis_request *get_rndis_request(struct rndis_device *dev, u32 msg_type, u32 msg_len) { @@ -155,7 +155,7 @@ static struct rndis_request *GetRndisRequest(struct rndis_device *dev, return request; } -static void PutRndisRequest(struct rndis_device *dev, +static void put_rndis_request(struct rndis_device *dev, struct rndis_request *req) { unsigned long flags; @@ -168,7 +168,7 @@ static void PutRndisRequest(struct rndis_device *dev, kfree(req); } -static void DumpRndisMessage(struct rndis_message *rndis_msg) +static void dump_rndis_message(struct rndis_message *rndis_msg) { switch (rndis_msg->NdisMessageType) { case REMOTE_NDIS_PACKET_MSG: @@ -242,7 +242,7 @@ static void DumpRndisMessage(struct rndis_message *rndis_msg) } } -static int RndisFilterSendRequest(struct rndis_device *dev, +static int rndis_filter_send_request(struct rndis_device *dev, struct rndis_request *req) { int ret; @@ -263,14 +263,14 @@ static int RndisFilterSendRequest(struct rndis_device *dev, packet->Completion.Send.SendCompletionContext = req;/* packet; */ packet->Completion.Send.OnSendCompletion = - RndisFilterOnSendRequestCompletion; + rndis_filter_send_request_completion; packet->Completion.Send.SendCompletionTid = (unsigned long)dev; ret = rndis_filter.inner_drv.OnSend(dev->net_dev->Device, packet); return ret; } -static void RndisFilterReceiveResponse(struct rndis_device *dev, +static void rndis_filter_receive_response(struct rndis_device *dev, struct rndis_message *resp) { struct rndis_request *request = NULL; @@ -330,7 +330,7 @@ static void RndisFilterReceiveResponse(struct rndis_device *dev, } } -static void RndisFilterReceiveIndicateStatus(struct rndis_device *dev, +static void rndis_filter_receive_indicate_status(struct rndis_device *dev, struct rndis_message *resp) { struct rndis_indicate_status *indicate = @@ -349,7 +349,7 @@ static void RndisFilterReceiveIndicateStatus(struct rndis_device *dev, } } -static void RndisFilterReceiveData(struct rndis_device *dev, +static void rndis_filter_receive_data(struct rndis_device *dev, struct rndis_message *msg, struct hv_netvsc_packet *pkt) { @@ -380,7 +380,7 @@ static void RndisFilterReceiveData(struct rndis_device *dev, pkt); } -static int RndisFilterOnReceive(struct hv_device *dev, +static int rndis_filter_receive(struct hv_device *dev, struct hv_netvsc_packet *pkt) { struct netvsc_device *net_dev = dev->Extension; @@ -445,12 +445,12 @@ static int RndisFilterOnReceive(struct hv_device *dev, kunmap_atomic(rndis_hdr - pkt->PageBuffers[0].Offset, KM_IRQ0); - DumpRndisMessage(&rndis_msg); + dump_rndis_message(&rndis_msg); switch (rndis_msg.NdisMessageType) { case REMOTE_NDIS_PACKET_MSG: /* data msg */ - RndisFilterReceiveData(rndis_dev, &rndis_msg, pkt); + rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt); break; case REMOTE_NDIS_INITIALIZE_CMPLT: @@ -459,12 +459,12 @@ static int RndisFilterOnReceive(struct hv_device *dev, /* case REMOTE_NDIS_RESET_CMPLT: */ /* case REMOTE_NDIS_KEEPALIVE_CMPLT: */ /* completion msgs */ - RndisFilterReceiveResponse(rndis_dev, &rndis_msg); + rndis_filter_receive_response(rndis_dev, &rndis_msg); break; case REMOTE_NDIS_INDICATE_STATUS_MSG: /* notification msgs */ - RndisFilterReceiveIndicateStatus(rndis_dev, &rndis_msg); + rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg); break; default: DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", @@ -476,7 +476,7 @@ static int RndisFilterOnReceive(struct hv_device *dev, return 0; } -static int RndisFilterQueryDevice(struct rndis_device *dev, u32 oid, +static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, void *result, u32 *result_size) { struct rndis_request *request; @@ -489,7 +489,7 @@ static int RndisFilterQueryDevice(struct rndis_device *dev, u32 oid, return -EINVAL; *result_size = 0; - request = GetRndisRequest(dev, REMOTE_NDIS_QUERY_MSG, + request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG, RNDIS_MESSAGE_SIZE(struct rndis_query_request)); if (!request) { ret = -1; @@ -503,7 +503,7 @@ static int RndisFilterQueryDevice(struct rndis_device *dev, u32 oid, query->InformationBufferLength = 0; query->DeviceVcHandle = 0; - ret = RndisFilterSendRequest(dev, request); + ret = rndis_filter_send_request(dev, request); if (ret != 0) goto Cleanup; @@ -526,30 +526,30 @@ static int RndisFilterQueryDevice(struct rndis_device *dev, u32 oid, Cleanup: if (request) - PutRndisRequest(dev, request); + put_rndis_request(dev, request); return ret; } -static int RndisFilterQueryDeviceMac(struct rndis_device *dev) +static int rndis_filter_query_device_mac(struct rndis_device *dev) { u32 size = ETH_ALEN; - return RndisFilterQueryDevice(dev, + return rndis_filter_query_device(dev, RNDIS_OID_802_3_PERMANENT_ADDRESS, dev->hw_mac_adr, &size); } -static int RndisFilterQueryDeviceLinkStatus(struct rndis_device *dev) +static int rndis_filter_query_device_link_status(struct rndis_device *dev) { u32 size = sizeof(u32); - return RndisFilterQueryDevice(dev, + return rndis_filter_query_device(dev, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &dev->link_stat, &size); } -static int RndisFilterSetPacketFilter(struct rndis_device *dev, +static int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) { struct rndis_request *request; @@ -561,7 +561,7 @@ static int RndisFilterSetPacketFilter(struct rndis_device *dev, /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */ /* sizeof(struct rndis_message)); */ - request = GetRndisRequest(dev, REMOTE_NDIS_SET_MSG, + request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG, RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32)); if (!request) { @@ -578,7 +578,7 @@ static int RndisFilterSetPacketFilter(struct rndis_device *dev, memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), &new_filter, sizeof(u32)); - ret = RndisFilterSendRequest(dev, request); + ret = rndis_filter_send_request(dev, request); if (ret != 0) goto Cleanup; @@ -600,12 +600,12 @@ static int RndisFilterSetPacketFilter(struct rndis_device *dev, Cleanup: if (request) - PutRndisRequest(dev, request); + put_rndis_request(dev, request); Exit: return ret; } -int RndisFilterInit(struct netvsc_driver *drv) +int rndis_filter_init(struct netvsc_driver *drv) { DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd", sizeof(struct rndis_filter_packet)); @@ -635,17 +635,17 @@ int RndisFilterInit(struct netvsc_driver *drv) drv->OnLinkStatusChanged; /* Override */ - drv->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; - drv->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; - drv->Base.OnCleanup = RndisFilterOnCleanup; - drv->OnSend = RndisFilterOnSend; + drv->Base.OnDeviceAdd = rndis_filte_device_add; + drv->Base.OnDeviceRemove = rndis_filter_device_remove; + drv->Base.OnCleanup = rndis_filter_cleanup; + drv->OnSend = rndis_filter_send; /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ - drv->OnReceiveCallback = RndisFilterOnReceive; + drv->OnReceiveCallback = rndis_filter_receive; return 0; } -static int RndisFilterInitDevice(struct rndis_device *dev) +static int rndis_filter_init_device(struct rndis_device *dev) { struct rndis_request *request; struct rndis_initialize_request *init; @@ -653,7 +653,7 @@ static int RndisFilterInitDevice(struct rndis_device *dev) u32 status; int ret; - request = GetRndisRequest(dev, REMOTE_NDIS_INITIALIZE_MSG, + request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG, RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); if (!request) { ret = -1; @@ -669,7 +669,7 @@ static int RndisFilterInitDevice(struct rndis_device *dev) dev->state = RNDIS_DEV_INITIALIZING; - ret = RndisFilterSendRequest(dev, request); + ret = rndis_filter_send_request(dev, request); if (ret != 0) { dev->state = RNDIS_DEV_UNINITIALIZED; goto Cleanup; @@ -689,18 +689,18 @@ static int RndisFilterInitDevice(struct rndis_device *dev) Cleanup: if (request) - PutRndisRequest(dev, request); + put_rndis_request(dev, request); return ret; } -static void RndisFilterHaltDevice(struct rndis_device *dev) +static void rndis_filter_halt_device(struct rndis_device *dev) { struct rndis_request *request; struct rndis_halt_request *halt; /* Attempt to do a rndis device halt */ - request = GetRndisRequest(dev, REMOTE_NDIS_HALT_MSG, + request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG, RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); if (!request) goto Cleanup; @@ -710,24 +710,24 @@ static void RndisFilterHaltDevice(struct rndis_device *dev) halt->RequestId = atomic_inc_return(&dev->new_req_id); /* Ignore return since this msg is optional. */ - RndisFilterSendRequest(dev, request); + rndis_filter_send_request(dev, request); dev->state = RNDIS_DEV_UNINITIALIZED; Cleanup: if (request) - PutRndisRequest(dev, request); + put_rndis_request(dev, request); return; } -static int RndisFilterOpenDevice(struct rndis_device *dev) +static int rndis_filter_open_device(struct rndis_device *dev) { int ret; if (dev->state != RNDIS_DEV_INITIALIZED) return 0; - ret = RndisFilterSetPacketFilter(dev, + ret = rndis_filter_set_packet_filter(dev, NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_DIRECTED); @@ -737,21 +737,21 @@ static int RndisFilterOpenDevice(struct rndis_device *dev) return ret; } -static int RndisFilterCloseDevice(struct rndis_device *dev) +static int rndis_filter_close_device(struct rndis_device *dev) { int ret; if (dev->state != RNDIS_DEV_DATAINITIALIZED) return 0; - ret = RndisFilterSetPacketFilter(dev, 0); + ret = rndis_filter_set_packet_filter(dev, 0); if (ret == 0) dev->state = RNDIS_DEV_INITIALIZED; return ret; } -static int RndisFilterOnDeviceAdd(struct hv_device *dev, +static int rndis_filte_device_add(struct hv_device *dev, void *additional_info) { int ret; @@ -759,7 +759,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *dev, struct rndis_device *rndisDevice; struct netvsc_device_info *deviceInfo = additional_info; - rndisDevice = GetRndisDevice(); + rndisDevice = get_rndis_device(); if (!rndisDevice) return -1; @@ -786,7 +786,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *dev, rndisDevice->net_dev = netDevice; /* Send the rndis initialization message */ - ret = RndisFilterInitDevice(rndisDevice); + ret = rndis_filter_init_device(rndisDevice); if (ret != 0) { /* * TODO: If rndis init failed, we will need to shut down the @@ -795,7 +795,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *dev, } /* Get the mac address */ - ret = RndisFilterQueryDeviceMac(rndisDevice); + ret = rndis_filter_query_device_mac(rndisDevice); if (ret != 0) { /* * TODO: shutdown rndis device and the channel @@ -807,7 +807,7 @@ static int RndisFilterOnDeviceAdd(struct hv_device *dev, memcpy(deviceInfo->MacAddr, rndisDevice->hw_mac_adr, ETH_ALEN); - RndisFilterQueryDeviceLinkStatus(rndisDevice); + rndis_filter_query_device_link_status(rndisDevice); deviceInfo->LinkState = rndisDevice->link_stat; DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, @@ -816,13 +816,13 @@ static int RndisFilterOnDeviceAdd(struct hv_device *dev, return ret; } -static int RndisFilterOnDeviceRemove(struct hv_device *dev) +static int rndis_filter_device_remove(struct hv_device *dev) { struct netvsc_device *net_dev = dev->Extension; struct rndis_device *rndis_dev = net_dev->Extension; /* Halt and release the rndis device */ - RndisFilterHaltDevice(rndis_dev); + rndis_filter_halt_device(rndis_dev); kfree(rndis_dev); net_dev->Extension = NULL; @@ -833,31 +833,31 @@ static int RndisFilterOnDeviceRemove(struct hv_device *dev) return 0; } -static void RndisFilterOnCleanup(struct hv_driver *drv) +static void rndis_filter_cleanup(struct hv_driver *drv) { } -int RndisFilterOnOpen(struct hv_device *dev) +int rndis_filter_open(struct hv_device *dev) { struct netvsc_device *netDevice = dev->Extension; if (!netDevice) return -EINVAL; - return RndisFilterOpenDevice(netDevice->Extension); + return rndis_filter_open_device(netDevice->Extension); } -int RndisFilterOnClose(struct hv_device *dev) +int rndis_filter_close(struct hv_device *dev) { struct netvsc_device *netDevice = dev->Extension; if (!netDevice) return -EINVAL; - return RndisFilterCloseDevice(netDevice->Extension); + return rndis_filter_close_device(netDevice->Extension); } -static int RndisFilterOnSend(struct hv_device *dev, +static int rndis_filter_send(struct hv_device *dev, struct hv_netvsc_packet *pkt) { int ret; @@ -895,7 +895,7 @@ static int RndisFilterOnSend(struct hv_device *dev, pkt->Completion.Send.SendCompletionContext; /* Use ours */ - pkt->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; + pkt->Completion.Send.OnSendCompletion = rndis_filter_send_completion; pkt->Completion.Send.SendCompletionContext = filterPacket; ret = rndis_filter.inner_drv.OnSend(dev, pkt); @@ -913,7 +913,7 @@ static int RndisFilterOnSend(struct hv_device *dev, return ret; } -static void RndisFilterOnSendCompletion(void *ctx) +static void rndis_filter_send_completion(void *ctx) { struct rndis_filter_packet *filterPacket = ctx; @@ -922,7 +922,7 @@ static void RndisFilterOnSendCompletion(void *ctx) } -static void RndisFilterOnSendRequestCompletion(void *ctx) +static void rndis_filter_send_request_completion(void *ctx) { /* Noop */ } diff --git a/drivers/staging/hv/rndis_filter.h b/drivers/staging/hv/rndis_filter.h index 764b9bf3e5dc..4da18f3cbade 100644 --- a/drivers/staging/hv/rndis_filter.h +++ b/drivers/staging/hv/rndis_filter.h @@ -50,6 +50,6 @@ /* Interface */ -extern int RndisFilterInit(struct netvsc_driver *driver); +extern int rndis_filter_init(struct netvsc_driver *driver); #endif /* _RNDISFILTER_H_ */ -- cgit v1.2.3 From 72a2f5bd53bf83302f4dcfe8500d4ec440545d27 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:03:58 -0800 Subject: staging: hv: Convert camel cased struct fields in netvsc_api.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc.c | 104 +++++++++++++++++------------------ drivers/staging/hv/netvsc_api.h | 58 ++++++++++---------- drivers/staging/hv/netvsc_drv.c | 74 ++++++++++++------------- drivers/staging/hv/rndis_filter.c | 112 +++++++++++++++++++------------------- 4 files changed, 174 insertions(+), 174 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index 5c327fc0d1fd..d678bf5329ef 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -196,11 +196,11 @@ int netvsc_initialize(struct hv_driver *drv) /* ASSERT(driver->OnLinkStatusChanged); */ /* Setup the dispatch table */ - driver->Base.OnDeviceAdd = netvsc_device_add; - driver->Base.OnDeviceRemove = netvsc_device_remove; - driver->Base.OnCleanup = netvsc_cleanup; + driver->base.OnDeviceAdd = netvsc_device_add; + driver->base.OnDeviceRemove = netvsc_device_remove; + driver->base.OnCleanup = netvsc_cleanup; - driver->OnSend = netvsc_send; + driver->send = netvsc_send; rndis_filter_init(driver); return 0; @@ -736,7 +736,7 @@ static int netvsc_device_add(struct hv_device *device, void *additional_info) NETVSC_RECEIVE_PACKETLIST_COUNT, i); break; } - list_add_tail(&packet->ListEntry, + list_add_tail(&packet->list_ent, &net_device->ReceivePacketList); } net_device->ChannelInitEvent = osd_waitevent_create(); @@ -746,8 +746,8 @@ static int netvsc_device_add(struct hv_device *device, void *additional_info) } /* Open the channel */ - ret = vmbus_open(device->channel, net_driver->RingBufferSize, - net_driver->RingBufferSize, NULL, 0, + ret = vmbus_open(device->channel, net_driver->ring_buf_size, + net_driver->ring_buf_size, NULL, 0, netvsc_channel_cb, device); if (ret != 0) { @@ -783,8 +783,8 @@ Cleanup: list_for_each_entry_safe(packet, pos, &net_device->ReceivePacketList, - ListEntry) { - list_del(&packet->ListEntry); + list_ent) { + list_del(&packet->list_ent); kfree(packet); } @@ -840,8 +840,8 @@ static int netvsc_device_remove(struct hv_device *device) /* Release all resources */ list_for_each_entry_safe(netvsc_packet, pos, - &net_device->ReceivePacketList, ListEntry) { - list_del(&netvsc_packet->ListEntry); + &net_device->ReceivePacketList, list_ent) { + list_del(&netvsc_packet->list_ent); kfree(netvsc_packet); } @@ -894,8 +894,8 @@ static void netvsc_send_completion(struct hv_device *device, /* ASSERT(nvscPacket); */ /* Notify the layer above us */ - nvsc_packet->Completion.Send.OnSendCompletion( - nvsc_packet->Completion.Send.SendCompletionContext); + nvsc_packet->completion.send.send_completion( + nvsc_packet->completion.send.send_completion_ctx); atomic_dec(&net_device->NumOutstandingSends); } else { @@ -922,7 +922,7 @@ static int netvsc_send(struct hv_device *device, } sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket; - if (packet->IsDataPacket) { + if (packet->is_data_pkt) { /* 0 is RMC_DATA; */ sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0; } else { @@ -934,10 +934,10 @@ static int netvsc_send(struct hv_device *device, sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF; sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0; - if (packet->PageBufferCount) { + if (packet->page_buf_cnt) { ret = vmbus_sendpacket_pagebuffer(device->channel, - packet->PageBuffers, - packet->PageBufferCount, + packet->page_buf, + packet->page_buf_cnt, &sendMessage, sizeof(struct nvsp_message), (unsigned long)packet); @@ -1063,82 +1063,82 @@ static void netvsc_receive(struct hv_device *device, /* Remove the 1st packet to represent the xfer page packet itself */ xferpage_packet = (struct xferpage_packet *)listHead.next; - list_del(&xferpage_packet->ListEntry); + list_del(&xferpage_packet->list_ent); /* This is how much we can satisfy */ - xferpage_packet->Count = count - 1; + xferpage_packet->count = count - 1; /* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */ /* vmxferpagePacket->RangeCount); */ - if (xferpage_packet->Count != vmxferpage_packet->RangeCount) { + if (xferpage_packet->count != vmxferpage_packet->RangeCount) { DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer " "page...got %d", vmxferpage_packet->RangeCount, - xferpage_packet->Count); + xferpage_packet->count); } /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ for (i = 0; i < (count - 1); i++) { netvsc_packet = (struct hv_netvsc_packet *)listHead.next; - list_del(&netvsc_packet->ListEntry); + list_del(&netvsc_packet->list_ent); /* Initialize the netvsc packet */ - netvsc_packet->XferPagePacket = xferpage_packet; - netvsc_packet->Completion.Recv.OnReceiveCompletion = + netvsc_packet->xfer_page_pkt = xferpage_packet; + netvsc_packet->completion.recv.recv_completion = netvsc_receive_completion; - netvsc_packet->Completion.Recv.ReceiveCompletionContext = + netvsc_packet->completion.recv.recv_completion_ctx = netvsc_packet; - netvsc_packet->Device = device; + netvsc_packet->device = device; /* Save this so that we can send it back */ - netvsc_packet->Completion.Recv.ReceiveCompletionTid = + netvsc_packet->completion.recv.recv_completion_tid = vmxferpage_packet->d.TransactionId; - netvsc_packet->TotalDataBufferLength = + netvsc_packet->total_data_buflen = vmxferpage_packet->Ranges[i].ByteCount; - netvsc_packet->PageBufferCount = 1; + netvsc_packet->page_buf_cnt = 1; /* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */ /* vmxferpagePacket->Ranges[i].ByteCount < */ /* netDevice->ReceiveBufferSize); */ - netvsc_packet->PageBuffers[0].Length = + netvsc_packet->page_buf[0].Length = vmxferpage_packet->Ranges[i].ByteCount; start = virt_to_phys((void *)((unsigned long)net_device-> ReceiveBuffer + vmxferpage_packet->Ranges[i].ByteOffset)); - netvsc_packet->PageBuffers[0].Pfn = start >> PAGE_SHIFT; + netvsc_packet->page_buf[0].Pfn = start >> PAGE_SHIFT; end_virtual = (unsigned long)net_device->ReceiveBuffer + vmxferpage_packet->Ranges[i].ByteOffset + vmxferpage_packet->Ranges[i].ByteCount - 1; end = virt_to_phys((void *)end_virtual); /* Calculate the page relative offset */ - netvsc_packet->PageBuffers[0].Offset = + netvsc_packet->page_buf[0].Offset = vmxferpage_packet->Ranges[i].ByteOffset & (PAGE_SIZE - 1); if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) { /* Handle frame across multiple pages: */ - netvsc_packet->PageBuffers[0].Length = - (netvsc_packet->PageBuffers[0].Pfn << + netvsc_packet->page_buf[0].Length = + (netvsc_packet->page_buf[0].Pfn << PAGE_SHIFT) + PAGE_SIZE - start; - bytes_remain = netvsc_packet->TotalDataBufferLength - - netvsc_packet->PageBuffers[0].Length; + bytes_remain = netvsc_packet->total_data_buflen - + netvsc_packet->page_buf[0].Length; for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) { - netvsc_packet->PageBuffers[j].Offset = 0; + netvsc_packet->page_buf[j].Offset = 0; if (bytes_remain <= PAGE_SIZE) { - netvsc_packet->PageBuffers[j].Length = + netvsc_packet->page_buf[j].Length = bytes_remain; bytes_remain = 0; } else { - netvsc_packet->PageBuffers[j].Length = + netvsc_packet->page_buf[j].Length = PAGE_SIZE; bytes_remain -= PAGE_SIZE; } - netvsc_packet->PageBuffers[j].Pfn = + netvsc_packet->page_buf[j].Pfn = virt_to_phys((void *)(end_virtual - bytes_remain)) >> PAGE_SHIFT; - netvsc_packet->PageBufferCount++; + netvsc_packet->page_buf_cnt++; if (bytes_remain == 0) break; } @@ -1148,16 +1148,16 @@ static void netvsc_receive(struct hv_device *device, "(pfn %llx, offset %u, len %u)", i, vmxferpage_packet->Ranges[i].ByteOffset, vmxferpage_packet->Ranges[i].ByteCount, - netvsc_packet->PageBuffers[0].Pfn, - netvsc_packet->PageBuffers[0].Offset, - netvsc_packet->PageBuffers[0].Length); + netvsc_packet->page_buf[0].Pfn, + netvsc_packet->page_buf[0].Offset, + netvsc_packet->page_buf[0].Length); /* Pass it to the upper layer */ ((struct netvsc_driver *)device->Driver)-> - OnReceiveCallback(device, netvsc_packet); + recv_cb(device, netvsc_packet); netvsc_receive_completion(netvsc_packet-> - Completion.Recv.ReceiveCompletionContext); + completion.recv.recv_completion_ctx); } /* ASSERT(list_empty(&listHead)); */ @@ -1213,7 +1213,7 @@ retry_send_cmplt: static void netvsc_receive_completion(void *context) { struct hv_netvsc_packet *packet = context; - struct hv_device *device = (struct hv_device *)packet->Device; + struct hv_device *device = (struct hv_device *)packet->device; struct netvsc_device *net_device; u64 transaction_id = 0; bool fsend_receive_comp = false; @@ -1237,22 +1237,22 @@ static void netvsc_receive_completion(void *context) spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); /* ASSERT(packet->XferPagePacket->Count > 0); */ - packet->XferPagePacket->Count--; + packet->xfer_page_pkt->count--; /* * Last one in the line that represent 1 xfer page packet. * Return the xfer page packet itself to the freelist */ - if (packet->XferPagePacket->Count == 0) { + if (packet->xfer_page_pkt->count == 0) { fsend_receive_comp = true; - transaction_id = packet->Completion.Recv.ReceiveCompletionTid; - list_add_tail(&packet->XferPagePacket->ListEntry, + transaction_id = packet->completion.recv.recv_completion_tid; + list_add_tail(&packet->xfer_page_pkt->list_ent, &net_device->ReceivePacketList); } /* Put the packet back */ - list_add_tail(&packet->ListEntry, &net_device->ReceivePacketList); + list_add_tail(&packet->list_ent, &net_device->ReceivePacketList); spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); /* Send a receive completion for the xfer page packet */ diff --git a/drivers/staging/hv/netvsc_api.h b/drivers/staging/hv/netvsc_api.h index 315271d69914..ac40db56e1fa 100644 --- a/drivers/staging/hv/netvsc_api.h +++ b/drivers/staging/hv/netvsc_api.h @@ -32,10 +32,10 @@ struct hv_netvsc_packet; /* Represent the xfer page packet which contains 1 or more netvsc packet */ struct xferpage_packet { - struct list_head ListEntry; + struct list_head list_ent; /* # of netvsc packets this xfer packet contains */ - u32 Count; + u32 count; }; /* The number of pages which are enough to cover jumbo frame buffer. */ @@ -47,65 +47,65 @@ struct xferpage_packet { */ struct hv_netvsc_packet { /* Bookkeeping stuff */ - struct list_head ListEntry; + struct list_head list_ent; - struct hv_device *Device; - bool IsDataPacket; + struct hv_device *device; + bool is_data_pkt; /* * Valid only for receives when we break a xfer page packet * into multiple netvsc packets */ - struct xferpage_packet *XferPagePacket; + struct xferpage_packet *xfer_page_pkt; union { struct{ - u64 ReceiveCompletionTid; - void *ReceiveCompletionContext; - void (*OnReceiveCompletion)(void *context); - } Recv; + u64 recv_completion_tid; + void *recv_completion_ctx; + void (*recv_completion)(void *context); + } recv; struct{ - u64 SendCompletionTid; - void *SendCompletionContext; - void (*OnSendCompletion)(void *context); - } Send; - } Completion; + u64 send_completion_tid; + void *send_completion_ctx; + void (*send_completion)(void *context); + } send; + } completion; - /* This points to the memory after PageBuffers */ - void *Extension; + /* This points to the memory after page_buf */ + void *extension; - u32 TotalDataBufferLength; + u32 total_data_buflen; /* Points to the send/receive buffer where the ethernet frame is */ - u32 PageBufferCount; - struct hv_page_buffer PageBuffers[NETVSC_PACKET_MAXPAGE]; + u32 page_buf_cnt; + struct hv_page_buffer page_buf[NETVSC_PACKET_MAXPAGE]; }; /* Represents the net vsc driver */ struct netvsc_driver { /* Must be the first field */ /* Which is a bug FIXME! */ - struct hv_driver Base; + struct hv_driver base; - u32 RingBufferSize; - u32 RequestExtSize; + u32 ring_buf_size; + u32 req_ext_size; /* * This is set by the caller to allow us to callback when we * receive a packet from the "wire" */ - int (*OnReceiveCallback)(struct hv_device *dev, + int (*recv_cb)(struct hv_device *dev, struct hv_netvsc_packet *packet); - void (*OnLinkStatusChanged)(struct hv_device *dev, u32 Status); + void (*link_status_change)(struct hv_device *dev, u32 Status); /* Specific to this driver */ - int (*OnSend)(struct hv_device *dev, struct hv_netvsc_packet *packet); + int (*send)(struct hv_device *dev, struct hv_netvsc_packet *packet); - void *Context; + void *ctx; }; struct netvsc_device_info { - unsigned char MacAddr[6]; - bool LinkState; /* 0 - link up, 1 - link down */ + unsigned char mac_adr[6]; + bool link_state; /* 0 - link up, 1 - link down */ }; /* Interface */ diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index e47681e7be82..0147b407512c 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -115,7 +115,7 @@ static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct sk_buff *skb = (struct sk_buff *) - (unsigned long)packet->Completion.Send.SendCompletionTid; + (unsigned long)packet->completion.send.send_completion_tid; kfree(packet); @@ -154,7 +154,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + (num_pages * sizeof(struct hv_page_buffer)) + - net_drv_obj->RequestExtSize, GFP_ATOMIC); + net_drv_obj->req_ext_size, GFP_ATOMIC); if (!packet) { /* out of memory, silently drop packet */ DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet"); @@ -164,40 +164,40 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) return NETDEV_TX_OK; } - packet->Extension = (void *)(unsigned long)packet + + packet->extension = (void *)(unsigned long)packet + sizeof(struct hv_netvsc_packet) + (num_pages * sizeof(struct hv_page_buffer)); /* Setup the rndis header */ - packet->PageBufferCount = num_pages; + packet->page_buf_cnt = num_pages; /* TODO: Flush all write buffers/ memory fence ??? */ /* wmb(); */ /* Initialize it from the skb */ - packet->TotalDataBufferLength = skb->len; + packet->total_data_buflen = skb->len; /* Start filling in the page buffers starting after RNDIS buffer. */ - packet->PageBuffers[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; - packet->PageBuffers[1].Offset + packet->page_buf[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; + packet->page_buf[1].Offset = (unsigned long)skb->data & (PAGE_SIZE - 1); - packet->PageBuffers[1].Length = skb_headlen(skb); + packet->page_buf[1].Length = skb_headlen(skb); /* Additional fragments are after SKB data */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - packet->PageBuffers[i+2].Pfn = page_to_pfn(f->page); - packet->PageBuffers[i+2].Offset = f->page_offset; - packet->PageBuffers[i+2].Length = f->size; + packet->page_buf[i+2].Pfn = page_to_pfn(f->page); + packet->page_buf[i+2].Offset = f->page_offset; + packet->page_buf[i+2].Length = f->size; } /* Set the completion routine */ - packet->Completion.Send.OnSendCompletion = netvsc_xmit_completion; - packet->Completion.Send.SendCompletionContext = packet; - packet->Completion.Send.SendCompletionTid = (unsigned long)skb; + packet->completion.send.send_completion = netvsc_xmit_completion; + packet->completion.send.send_completion_ctx = packet; + packet->completion.send.send_completion_tid = (unsigned long)skb; - ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj, + ret = net_drv_obj->send(&net_device_ctx->device_ctx->device_obj, packet); if (ret == 0) { net->stats.tx_bytes += skb->len; @@ -263,7 +263,7 @@ static int netvsc_recv_callback(struct hv_device *device_obj, } /* Allocate a skb - TODO direct I/O to pages? */ - skb = netdev_alloc_skb_ip_align(net, packet->TotalDataBufferLength); + skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen); if (unlikely(!skb)) { ++net->stats.rx_dropped; return 0; @@ -276,17 +276,17 @@ static int netvsc_recv_callback(struct hv_device *device_obj, * Copy to skb. This copy is needed here since the memory pointed by * hv_netvsc_packet cannot be deallocated */ - for (i = 0; i < packet->PageBufferCount; i++) { - data = kmap_atomic(pfn_to_page(packet->PageBuffers[i].Pfn), + for (i = 0; i < packet->page_buf_cnt; i++) { + data = kmap_atomic(pfn_to_page(packet->page_buf[i].Pfn), KM_IRQ1); data = (void *)(unsigned long)data + - packet->PageBuffers[i].Offset; + packet->page_buf[i].Offset; - memcpy(skb_put(skb, packet->PageBuffers[i].Length), data, - packet->PageBuffers[i].Length); + memcpy(skb_put(skb, packet->page_buf[i].Length), data, + packet->page_buf[i].Length); kunmap_atomic((void *)((unsigned long)data - - packet->PageBuffers[i].Offset), KM_IRQ1); + packet->page_buf[i].Offset), KM_IRQ1); } local_irq_restore(flags); @@ -349,7 +349,7 @@ static int netvsc_probe(struct device *device) struct netvsc_device_info device_info; int ret; - if (!net_drv_obj->Base.OnDeviceAdd) + if (!net_drv_obj->base.OnDeviceAdd) return -1; net = alloc_etherdev(sizeof(struct net_device_context)); @@ -366,7 +366,7 @@ static int netvsc_probe(struct device *device) dev_set_drvdata(device, net); /* Notify the netvsc driver of the new device */ - ret = net_drv_obj->Base.OnDeviceAdd(device_obj, &device_info); + ret = net_drv_obj->base.OnDeviceAdd(device_obj, &device_info); if (ret != 0) { free_netdev(net); dev_set_drvdata(device, NULL); @@ -385,10 +385,10 @@ static int netvsc_probe(struct device *device) * out of sync with the device's link status */ if (!netif_carrier_ok(net)) - if (!device_info.LinkState) + if (!device_info.link_state) netif_carrier_on(net); - memcpy(net->dev_addr, device_info.MacAddr, ETH_ALEN); + memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); net->netdev_ops = &device_ops; @@ -401,7 +401,7 @@ static int netvsc_probe(struct device *device) ret = register_netdev(net); if (ret != 0) { /* Remove the device and release the resource */ - net_drv_obj->Base.OnDeviceRemove(device_obj); + net_drv_obj->base.OnDeviceRemove(device_obj); free_netdev(net); } @@ -425,7 +425,7 @@ static int netvsc_remove(struct device *device) return 0; } - if (!net_drv_obj->Base.OnDeviceRemove) + if (!net_drv_obj->base.OnDeviceRemove) return -1; /* Stop outbound asap */ @@ -438,7 +438,7 @@ static int netvsc_remove(struct device *device) * Call to the vsc driver to let it know that the device is being * removed */ - ret = net_drv_obj->Base.OnDeviceRemove(device_obj); + ret = net_drv_obj->base.OnDeviceRemove(device_obj); if (ret != 0) { /* TODO: */ DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret); @@ -484,8 +484,8 @@ static void netvsc_drv_exit(void) device_unregister(current_dev); } - if (netvsc_drv_obj->Base.OnCleanup) - netvsc_drv_obj->Base.OnCleanup(&netvsc_drv_obj->Base); + if (netvsc_drv_obj->base.OnCleanup) + netvsc_drv_obj->base.OnCleanup(&netvsc_drv_obj->base); vmbus_child_driver_unregister(drv_ctx); @@ -498,15 +498,15 @@ static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx; int ret; - net_drv_obj->RingBufferSize = ring_size * PAGE_SIZE; - net_drv_obj->OnReceiveCallback = netvsc_recv_callback; - net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback; + net_drv_obj->ring_buf_size = ring_size * PAGE_SIZE; + net_drv_obj->recv_cb = netvsc_recv_callback; + net_drv_obj->link_status_change = netvsc_linkstatus_callback; /* Callback to client driver to complete the initialization */ - drv_init(&net_drv_obj->Base); + drv_init(&net_drv_obj->base); - drv_ctx->driver.name = net_drv_obj->Base.name; - memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType, + drv_ctx->driver.name = net_drv_obj->base.name; + memcpy(&drv_ctx->class_id, &net_drv_obj->base.deviceType, sizeof(struct hv_guid)); drv_ctx->probe = netvsc_probe; diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index e560f380adb5..dffcc0397917 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -251,22 +251,22 @@ static int rndis_filter_send_request(struct rndis_device *dev, /* Setup the packet to send it */ packet = &req->pkt; - packet->IsDataPacket = false; - packet->TotalDataBufferLength = req->request_msg.MessageLength; - packet->PageBufferCount = 1; + packet->is_data_pkt = false; + packet->total_data_buflen = req->request_msg.MessageLength; + packet->page_buf_cnt = 1; - packet->PageBuffers[0].Pfn = virt_to_phys(&req->request_msg) >> + packet->page_buf[0].Pfn = virt_to_phys(&req->request_msg) >> PAGE_SHIFT; - packet->PageBuffers[0].Length = req->request_msg.MessageLength; - packet->PageBuffers[0].Offset = + packet->page_buf[0].Length = req->request_msg.MessageLength; + packet->page_buf[0].Offset = (unsigned long)&req->request_msg & (PAGE_SIZE - 1); - packet->Completion.Send.SendCompletionContext = req;/* packet; */ - packet->Completion.Send.OnSendCompletion = + packet->completion.send.send_completion_ctx = req;/* packet; */ + packet->completion.send.send_completion = rndis_filter_send_request_completion; - packet->Completion.Send.SendCompletionTid = (unsigned long)dev; + packet->completion.send.send_completion_tid = (unsigned long)dev; - ret = rndis_filter.inner_drv.OnSend(dev->net_dev->Device, packet); + ret = rndis_filter.inner_drv.send(dev->net_dev->Device, packet); return ret; } @@ -337,10 +337,10 @@ static void rndis_filter_receive_indicate_status(struct rndis_device *dev, &resp->Message.IndicateStatus; if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) { - rndis_filter.inner_drv.OnLinkStatusChanged( + rndis_filter.inner_drv.link_status_change( dev->net_dev->Device, 1); } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) { - rndis_filter.inner_drv.OnLinkStatusChanged( + rndis_filter.inner_drv.link_status_change( dev->net_dev->Device, 0); } else { /* @@ -370,13 +370,13 @@ static void rndis_filter_receive_data(struct rndis_device *dev, /* Remove the rndis header and pass it back up the stack */ data_offset = RNDIS_HEADER_SIZE + rndis_pkt->DataOffset; - pkt->TotalDataBufferLength -= data_offset; - pkt->PageBuffers[0].Offset += data_offset; - pkt->PageBuffers[0].Length -= data_offset; + pkt->total_data_buflen -= data_offset; + pkt->page_buf[0].Offset += data_offset; + pkt->page_buf[0].Length -= data_offset; - pkt->IsDataPacket = true; + pkt->is_data_pkt = true; - rndis_filter.inner_drv.OnReceiveCallback(dev->net_dev->Device, + rndis_filter.inner_drv.recv_cb(dev->net_dev->Device, pkt); } @@ -406,10 +406,10 @@ static int rndis_filter_receive(struct hv_device *dev, } rndis_hdr = (struct rndis_message *)kmap_atomic( - pfn_to_page(pkt->PageBuffers[0].Pfn), KM_IRQ0); + pfn_to_page(pkt->page_buf[0].Pfn), KM_IRQ0); rndis_hdr = (void *)((unsigned long)rndis_hdr + - pkt->PageBuffers[0].Offset); + pkt->page_buf[0].Offset); /* Make sure we got a valid rndis message */ /* @@ -418,14 +418,14 @@ static int rndis_filter_receive(struct hv_device *dev, * range shows 52 bytes * */ #if 0 - if (pkt->TotalDataBufferLength != rndis_hdr->MessageLength) { - kunmap_atomic(rndis_hdr - pkt->PageBuffers[0].Offset, + if (pkt->total_data_buflen != rndis_hdr->MessageLength) { + kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset, KM_IRQ0); DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u " "bytes got %u)...dropping this message!", rndis_hdr->MessageLength, - pkt->TotalDataBufferLength); + pkt->total_data_buflen); return -1; } #endif @@ -443,7 +443,7 @@ static int rndis_filter_receive(struct hv_device *dev, sizeof(struct rndis_message) : rndis_hdr->MessageLength); - kunmap_atomic(rndis_hdr - pkt->PageBuffers[0].Offset, KM_IRQ0); + kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset, KM_IRQ0); dump_rndis_message(&rndis_msg); @@ -610,7 +610,7 @@ int rndis_filter_init(struct netvsc_driver *drv) DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd", sizeof(struct rndis_filter_packet)); - drv->RequestExtSize = sizeof(struct rndis_filter_packet); + drv->req_ext_size = sizeof(struct rndis_filter_packet); /* Driver->Context = rndisDriver; */ @@ -622,25 +622,25 @@ int rndis_filter_init(struct netvsc_driver *drv) rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ /* Save the original dispatch handlers before we override it */ - rndis_filter.inner_drv.Base.OnDeviceAdd = drv->Base.OnDeviceAdd; - rndis_filter.inner_drv.Base.OnDeviceRemove = - drv->Base.OnDeviceRemove; - rndis_filter.inner_drv.Base.OnCleanup = drv->Base.OnCleanup; + rndis_filter.inner_drv.base.OnDeviceAdd = drv->base.OnDeviceAdd; + rndis_filter.inner_drv.base.OnDeviceRemove = + drv->base.OnDeviceRemove; + rndis_filter.inner_drv.base.OnCleanup = drv->base.OnCleanup; /* ASSERT(Driver->OnSend); */ /* ASSERT(Driver->OnReceiveCallback); */ - rndis_filter.inner_drv.OnSend = drv->OnSend; - rndis_filter.inner_drv.OnReceiveCallback = drv->OnReceiveCallback; - rndis_filter.inner_drv.OnLinkStatusChanged = - drv->OnLinkStatusChanged; + rndis_filter.inner_drv.send = drv->send; + rndis_filter.inner_drv.recv_cb = drv->recv_cb; + rndis_filter.inner_drv.link_status_change = + drv->link_status_change; /* Override */ - drv->Base.OnDeviceAdd = rndis_filte_device_add; - drv->Base.OnDeviceRemove = rndis_filter_device_remove; - drv->Base.OnCleanup = rndis_filter_cleanup; - drv->OnSend = rndis_filter_send; + drv->base.OnDeviceAdd = rndis_filte_device_add; + drv->base.OnDeviceRemove = rndis_filter_device_remove; + drv->base.OnCleanup = rndis_filter_cleanup; + drv->send = rndis_filter_send; /* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */ - drv->OnReceiveCallback = rndis_filter_receive; + drv->recv_cb = rndis_filter_receive; return 0; } @@ -770,7 +770,7 @@ static int rndis_filte_device_add(struct hv_device *dev, * NOTE! Once the channel is created, we may get a receive callback * (RndisFilterOnReceive()) before this call is completed */ - ret = rndis_filter.inner_drv.Base.OnDeviceAdd(dev, additional_info); + ret = rndis_filter.inner_drv.base.OnDeviceAdd(dev, additional_info); if (ret != 0) { kfree(rndisDevice); return ret; @@ -805,13 +805,13 @@ static int rndis_filte_device_add(struct hv_device *dev, DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM", rndisDevice, rndisDevice->hw_mac_adr); - memcpy(deviceInfo->MacAddr, rndisDevice->hw_mac_adr, ETH_ALEN); + memcpy(deviceInfo->mac_adr, rndisDevice->hw_mac_adr, ETH_ALEN); rndis_filter_query_device_link_status(rndisDevice); - deviceInfo->LinkState = rndisDevice->link_stat; + deviceInfo->link_state = rndisDevice->link_stat; DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, - ((deviceInfo->LinkState) ? ("down") : ("up"))); + ((deviceInfo->link_state) ? ("down") : ("up"))); return ret; } @@ -828,7 +828,7 @@ static int rndis_filter_device_remove(struct hv_device *dev) net_dev->Extension = NULL; /* Pass control to inner driver to remove the device */ - rndis_filter.inner_drv.Base.OnDeviceRemove(dev); + rndis_filter.inner_drv.base.OnDeviceRemove(dev); return 0; } @@ -867,7 +867,7 @@ static int rndis_filter_send(struct hv_device *dev, u32 rndisMessageSize; /* Add the rndis header */ - filterPacket = (struct rndis_filter_packet *)pkt->Extension; + filterPacket = (struct rndis_filter_packet *)pkt->extension; /* ASSERT(filterPacket); */ memset(filterPacket, 0, sizeof(struct rndis_filter_packet)); @@ -876,37 +876,37 @@ static int rndis_filter_send(struct hv_device *dev, rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; - rndisMessage->MessageLength = pkt->TotalDataBufferLength + + rndisMessage->MessageLength = pkt->total_data_buflen + rndisMessageSize; rndisPacket = &rndisMessage->Message.Packet; rndisPacket->DataOffset = sizeof(struct rndis_packet); - rndisPacket->DataLength = pkt->TotalDataBufferLength; + rndisPacket->DataLength = pkt->total_data_buflen; - pkt->IsDataPacket = true; - pkt->PageBuffers[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; - pkt->PageBuffers[0].Offset = + pkt->is_data_pkt = true; + pkt->page_buf[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; + pkt->page_buf[0].Offset = (unsigned long)rndisMessage & (PAGE_SIZE-1); - pkt->PageBuffers[0].Length = rndisMessageSize; + pkt->page_buf[0].Length = rndisMessageSize; /* Save the packet send completion and context */ - filterPacket->completion = pkt->Completion.Send.OnSendCompletion; + filterPacket->completion = pkt->completion.send.send_completion; filterPacket->completion_ctx = - pkt->Completion.Send.SendCompletionContext; + pkt->completion.send.send_completion_ctx; /* Use ours */ - pkt->Completion.Send.OnSendCompletion = rndis_filter_send_completion; - pkt->Completion.Send.SendCompletionContext = filterPacket; + pkt->completion.send.send_completion = rndis_filter_send_completion; + pkt->completion.send.send_completion_ctx = filterPacket; - ret = rndis_filter.inner_drv.OnSend(dev, pkt); + ret = rndis_filter.inner_drv.send(dev, pkt); if (ret != 0) { /* * Reset the completion to originals to allow retries from * above */ - pkt->Completion.Send.OnSendCompletion = + pkt->completion.send.send_completion = filterPacket->completion; - pkt->Completion.Send.SendCompletionContext = + pkt->completion.send.send_completion_ctx = filterPacket->completion_ctx; } -- cgit v1.2.3 From 53d21fdbf4d38dcfe27173d746acf74ea1a19958 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:03:59 -0800 Subject: staging: hv: Convert camel cased struct fields in netvsc.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc.c | 340 +++++++++++++++++++------------------- drivers/staging/hv/netvsc.h | 164 +++++++++--------- drivers/staging/hv/netvsc_api.h | 2 +- drivers/staging/hv/rndis_filter.c | 22 +-- 4 files changed, 265 insertions(+), 263 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc.c b/drivers/staging/hv/netvsc.c index d678bf5329ef..df9cd131e953 100644 --- a/drivers/staging/hv/netvsc.c +++ b/drivers/staging/hv/netvsc.c @@ -83,9 +83,9 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device) return NULL; /* Set to 2 to allow both inbound and outbound traffic */ - atomic_cmpxchg(&net_device->RefCount, 0, 2); + atomic_cmpxchg(&net_device->refcnt, 0, 2); - net_device->Device = device; + net_device->dev = device; device->Extension = net_device; return net_device; @@ -93,8 +93,8 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device) static void free_net_device(struct netvsc_device *device) { - WARN_ON(atomic_read(&device->RefCount) == 0); - device->Device->Extension = NULL; + WARN_ON(atomic_read(&device->refcnt) == 0); + device->dev->Extension = NULL; kfree(device); } @@ -105,8 +105,8 @@ static struct netvsc_device *get_outbound_net_device(struct hv_device *device) struct netvsc_device *net_device; net_device = device->Extension; - if (net_device && atomic_read(&net_device->RefCount) > 1) - atomic_inc(&net_device->RefCount); + if (net_device && atomic_read(&net_device->refcnt) > 1) + atomic_inc(&net_device->refcnt); else net_device = NULL; @@ -119,8 +119,8 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device) struct netvsc_device *net_device; net_device = device->Extension; - if (net_device && atomic_read(&net_device->RefCount)) - atomic_inc(&net_device->RefCount); + if (net_device && atomic_read(&net_device->refcnt)) + atomic_inc(&net_device->refcnt); else net_device = NULL; @@ -134,7 +134,7 @@ static void put_net_device(struct hv_device *device) net_device = device->Extension; /* ASSERT(netDevice); */ - atomic_dec(&net_device->RefCount); + atomic_dec(&net_device->refcnt); } static struct netvsc_device *release_outbound_net_device( @@ -147,7 +147,7 @@ static struct netvsc_device *release_outbound_net_device( return NULL; /* Busy wait until the ref drop to 2, then set it to 1 */ - while (atomic_cmpxchg(&net_device->RefCount, 2, 1) != 2) + while (atomic_cmpxchg(&net_device->refcnt, 2, 1) != 2) udelay(100); return net_device; @@ -163,7 +163,7 @@ static struct netvsc_device *release_inbound_net_device( return NULL; /* Busy wait until the ref drop to 1, then set it to 0 */ - while (atomic_cmpxchg(&net_device->RefCount, 1, 0) != 1) + while (atomic_cmpxchg(&net_device->refcnt, 1, 0) != 1) udelay(100); device->Extension = NULL; @@ -222,12 +222,12 @@ static int netvsc_init_recv_buf(struct hv_device *device) /* page-size grandularity */ /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */ - net_device->ReceiveBuffer = - osd_page_alloc(net_device->ReceiveBufferSize >> PAGE_SHIFT); - if (!net_device->ReceiveBuffer) { + net_device->recv_buf = + osd_page_alloc(net_device->recv_buf_size >> PAGE_SHIFT); + if (!net_device->recv_buf) { DPRINT_ERR(NETVSC, "unable to allocate receive buffer of size %d", - net_device->ReceiveBufferSize); + net_device->recv_buf_size); ret = -1; goto Cleanup; } @@ -242,9 +242,9 @@ static int netvsc_init_recv_buf(struct hv_device *device) * channel. Note: This call uses the vmbus connection rather * than the channel to establish the gpadl handle. */ - ret = vmbus_establish_gpadl(device->channel, net_device->ReceiveBuffer, - net_device->ReceiveBufferSize, - &net_device->ReceiveBufferGpadlHandle); + ret = vmbus_establish_gpadl(device->channel, net_device->recv_buf, + net_device->recv_buf_size, + &net_device->recv_buf_gpadl_handle); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to establish receive buffer's gpadl"); @@ -256,15 +256,15 @@ static int netvsc_init_recv_buf(struct hv_device *device) /* Notify the NetVsp of the gpadl handle */ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer..."); - init_packet = &net_device->ChannelInitPacket; + init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); - init_packet->Header.MessageType = NvspMessage1TypeSendReceiveBuffer; - init_packet->Messages.Version1Messages.SendReceiveBuffer. - GpadlHandle = net_device->ReceiveBufferGpadlHandle; - init_packet->Messages.Version1Messages. - SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; + init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; + init_packet->msg.v1_msg.send_recv_buf. + gpadl_handle = net_device->recv_buf_gpadl_handle; + init_packet->msg.v1_msg. + send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, @@ -278,15 +278,15 @@ static int netvsc_init_recv_buf(struct hv_device *device) goto Cleanup; } - osd_waitevent_wait(net_device->ChannelInitEvent); + osd_waitevent_wait(net_device->channel_init_event); /* Check the response */ - if (init_packet->Messages.Version1Messages. - SendReceiveBufferComplete.Status != NvspStatusSuccess) { + if (init_packet->msg.v1_msg. + send_recv_buf_complete.status != NVSP_STAT_SUCCESS) { DPRINT_ERR(NETVSC, "Unable to complete receive buffer " "initialzation with NetVsp - status %d", - init_packet->Messages.Version1Messages. - SendReceiveBufferComplete.Status); + init_packet->msg.v1_msg. + send_recv_buf_complete.status); ret = -1; goto Cleanup; } @@ -295,36 +295,36 @@ static int netvsc_init_recv_buf(struct hv_device *device) /* ASSERT(netDevice->ReceiveSectionCount == 0); */ /* ASSERT(netDevice->ReceiveSections == NULL); */ - net_device->ReceiveSectionCount = init_packet->Messages. - Version1Messages.SendReceiveBufferComplete.NumSections; + net_device->recv_section_cnt = init_packet->msg. + v1_msg.send_recv_buf_complete.num_sections; - net_device->ReceiveSections = kmalloc(net_device->ReceiveSectionCount + net_device->recv_section = kmalloc(net_device->recv_section_cnt * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL); - if (net_device->ReceiveSections == NULL) { + if (net_device->recv_section == NULL) { ret = -1; goto Cleanup; } - memcpy(net_device->ReceiveSections, - init_packet->Messages.Version1Messages. - SendReceiveBufferComplete.Sections, - net_device->ReceiveSectionCount * + memcpy(net_device->recv_section, + init_packet->msg.v1_msg. + send_recv_buf_complete.sections, + net_device->recv_section_cnt * sizeof(struct nvsp_1_receive_buffer_section)); DPRINT_INFO(NETVSC, "Receive sections info (count %d, offset %d, " "endoffset %d, suballoc size %d, num suballocs %d)", - net_device->ReceiveSectionCount, - net_device->ReceiveSections[0].Offset, - net_device->ReceiveSections[0].EndOffset, - net_device->ReceiveSections[0].SubAllocationSize, - net_device->ReceiveSections[0].NumSubAllocations); + net_device->recv_section_cnt, + net_device->recv_section[0].offset, + net_device->recv_section[0].end_offset, + net_device->recv_section[0].sub_alloc_size, + net_device->recv_section[0].num_sub_allocs); /* * For 1st release, there should only be 1 section that represents the * entire receive buffer */ - if (net_device->ReceiveSectionCount != 1 || - net_device->ReceiveSections->Offset != 0) { + if (net_device->recv_section_cnt != 1 || + net_device->recv_section->offset != 0) { ret = -1; goto Cleanup; } @@ -351,7 +351,7 @@ static int netvsc_init_send_buf(struct hv_device *device) "device being destroyed?"); return -1; } - if (net_device->SendBufferSize <= 0) { + if (net_device->send_buf_size <= 0) { ret = -EINVAL; goto Cleanup; } @@ -359,11 +359,11 @@ static int netvsc_init_send_buf(struct hv_device *device) /* page-size grandularity */ /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */ - net_device->SendBuffer = - osd_page_alloc(net_device->SendBufferSize >> PAGE_SHIFT); - if (!net_device->SendBuffer) { + net_device->send_buf = + osd_page_alloc(net_device->send_buf_size >> PAGE_SHIFT); + if (!net_device->send_buf) { DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", - net_device->SendBufferSize); + net_device->send_buf_size); ret = -1; goto Cleanup; } @@ -377,9 +377,9 @@ static int netvsc_init_send_buf(struct hv_device *device) * channel. Note: This call uses the vmbus connection rather * than the channel to establish the gpadl handle. */ - ret = vmbus_establish_gpadl(device->channel, net_device->SendBuffer, - net_device->SendBufferSize, - &net_device->SendBufferGpadlHandle); + ret = vmbus_establish_gpadl(device->channel, net_device->send_buf, + net_device->send_buf_size, + &net_device->send_buf_gpadl_handle); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl"); goto Cleanup; @@ -390,14 +390,14 @@ static int netvsc_init_send_buf(struct hv_device *device) /* Notify the NetVsp of the gpadl handle */ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer..."); - init_packet = &net_device->ChannelInitPacket; + init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); - init_packet->Header.MessageType = NvspMessage1TypeSendSendBuffer; - init_packet->Messages.Version1Messages.SendReceiveBuffer. - GpadlHandle = net_device->SendBufferGpadlHandle; - init_packet->Messages.Version1Messages.SendReceiveBuffer.Id = + init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; + init_packet->msg.v1_msg.send_recv_buf. + gpadl_handle = net_device->send_buf_gpadl_handle; + init_packet->msg.v1_msg.send_recv_buf.id = NETVSC_SEND_BUFFER_ID; /* Send the gpadl notification request */ @@ -412,21 +412,21 @@ static int netvsc_init_send_buf(struct hv_device *device) goto Cleanup; } - osd_waitevent_wait(net_device->ChannelInitEvent); + osd_waitevent_wait(net_device->channel_init_event); /* Check the response */ - if (init_packet->Messages.Version1Messages. - SendSendBufferComplete.Status != NvspStatusSuccess) { + if (init_packet->msg.v1_msg. + send_send_buf_complete.status != NVSP_STAT_SUCCESS) { DPRINT_ERR(NETVSC, "Unable to complete send buffer " "initialzation with NetVsp - status %d", - init_packet->Messages.Version1Messages. - SendSendBufferComplete.Status); + init_packet->msg.v1_msg. + send_send_buf_complete.status); ret = -1; goto Cleanup; } - net_device->SendSectionSize = init_packet-> - Messages.Version1Messages.SendSendBufferComplete.SectionSize; + net_device->send_section_size = init_packet-> + msg.v1_msg.send_send_buf_complete.section_size; goto Exit; @@ -449,20 +449,20 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need * to send a revoke msg here */ - if (net_device->ReceiveSectionCount) { + if (net_device->recv_section_cnt) { DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeReceiveBuffer..."); /* Send the revoke receive buffer */ - revoke_packet = &net_device->RevokePacket; + revoke_packet = &net_device->revoke_packet; memset(revoke_packet, 0, sizeof(struct nvsp_message)); - revoke_packet->Header.MessageType = - NvspMessage1TypeRevokeReceiveBuffer; - revoke_packet->Messages.Version1Messages. - RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; + revoke_packet->hdr.msg_type = + NVSP_MSG1_TYPE_REVOKE_RECV_BUF; + revoke_packet->msg.v1_msg. + revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; - ret = vmbus_sendpacket(net_device->Device->channel, + ret = vmbus_sendpacket(net_device->dev->channel, revoke_packet, sizeof(struct nvsp_message), (unsigned long)revoke_packet, @@ -479,11 +479,11 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) } /* Teardown the gpadl on the vsp end */ - if (net_device->ReceiveBufferGpadlHandle) { + if (net_device->recv_buf_gpadl_handle) { DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL..."); - ret = vmbus_teardown_gpadl(net_device->Device->channel, - net_device->ReceiveBufferGpadlHandle); + ret = vmbus_teardown_gpadl(net_device->dev->channel, + net_device->recv_buf_gpadl_handle); /* If we failed here, we might as well return and have a leak rather than continue and a bugchk */ if (ret != 0) { @@ -491,22 +491,22 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) "unable to teardown receive buffer's gpadl"); return -1; } - net_device->ReceiveBufferGpadlHandle = 0; + net_device->recv_buf_gpadl_handle = 0; } - if (net_device->ReceiveBuffer) { + if (net_device->recv_buf) { DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); /* Free up the receive buffer */ - osd_page_free(net_device->ReceiveBuffer, - net_device->ReceiveBufferSize >> PAGE_SHIFT); - net_device->ReceiveBuffer = NULL; + osd_page_free(net_device->recv_buf, + net_device->recv_buf_size >> PAGE_SHIFT); + net_device->recv_buf = NULL; } - if (net_device->ReceiveSections) { - net_device->ReceiveSectionCount = 0; - kfree(net_device->ReceiveSections); - net_device->ReceiveSections = NULL; + if (net_device->recv_section) { + net_device->recv_section_cnt = 0; + kfree(net_device->recv_section); + net_device->recv_section = NULL; } return ret; @@ -523,20 +523,20 @@ static int netvsc_destroy_send_buf(struct netvsc_device *net_device) * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need * to send a revoke msg here */ - if (net_device->SendSectionSize) { + if (net_device->send_section_size) { DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeSendBuffer..."); /* Send the revoke send buffer */ - revoke_packet = &net_device->RevokePacket; + revoke_packet = &net_device->revoke_packet; memset(revoke_packet, 0, sizeof(struct nvsp_message)); - revoke_packet->Header.MessageType = - NvspMessage1TypeRevokeSendBuffer; - revoke_packet->Messages.Version1Messages. - RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID; + revoke_packet->hdr.msg_type = + NVSP_MSG1_TYPE_REVOKE_SEND_BUF; + revoke_packet->msg.v1_msg. + revoke_send_buf.id = NETVSC_SEND_BUFFER_ID; - ret = vmbus_sendpacket(net_device->Device->channel, + ret = vmbus_sendpacket(net_device->dev->channel, revoke_packet, sizeof(struct nvsp_message), (unsigned long)revoke_packet, @@ -553,10 +553,10 @@ static int netvsc_destroy_send_buf(struct netvsc_device *net_device) } /* Teardown the gpadl on the vsp end */ - if (net_device->SendBufferGpadlHandle) { + if (net_device->send_buf_gpadl_handle) { DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL..."); - ret = vmbus_teardown_gpadl(net_device->Device->channel, - net_device->SendBufferGpadlHandle); + ret = vmbus_teardown_gpadl(net_device->dev->channel, + net_device->send_buf_gpadl_handle); /* * If we failed here, we might as well return and have a leak @@ -567,16 +567,16 @@ static int netvsc_destroy_send_buf(struct netvsc_device *net_device) "gpadl"); return -1; } - net_device->SendBufferGpadlHandle = 0; + net_device->send_buf_gpadl_handle = 0; } - if (net_device->SendBuffer) { + if (net_device->send_buf) { DPRINT_INFO(NETVSC, "Freeing up send buffer..."); /* Free up the receive buffer */ - osd_page_free(net_device->SendBuffer, - net_device->SendBufferSize >> PAGE_SHIFT); - net_device->SendBuffer = NULL; + osd_page_free(net_device->send_buf, + net_device->send_buf_size >> PAGE_SHIFT); + net_device->send_buf = NULL; } return ret; @@ -597,13 +597,13 @@ static int netvsc_connect_vsp(struct hv_device *device) return -1; } - init_packet = &net_device->ChannelInitPacket; + init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); - init_packet->Header.MessageType = NvspMessageTypeInit; - init_packet->Messages.InitMessages.Init.MinProtocolVersion = + init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; + init_packet->msg.init_msg.init.min_protocol_ver = NVSP_MIN_PROTOCOL_VERSION; - init_packet->Messages.InitMessages.Init.MaxProtocolVersion = + init_packet->msg.init_msg.init.max_protocol_ver = NVSP_MAX_PROTOCOL_VERSION; DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit..."); @@ -620,30 +620,30 @@ static int netvsc_connect_vsp(struct hv_device *device) goto Cleanup; } - osd_waitevent_wait(net_device->ChannelInitEvent); + osd_waitevent_wait(net_device->channel_init_event); /* Now, check the response */ /* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */ DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)", - init_packet->Messages.InitMessages.InitComplete.Status, - init_packet->Messages.InitMessages. - InitComplete.MaximumMdlChainLength); + init_packet->msg.init_msg.init_complete.status, + init_packet->msg.init_msg. + init_complete.max_mdl_chain_len); - if (init_packet->Messages.InitMessages.InitComplete.Status != - NvspStatusSuccess) { + if (init_packet->msg.init_msg.init_complete.status != + NVSP_STAT_SUCCESS) { DPRINT_ERR(NETVSC, "unable to initialize with netvsp (status 0x%x)", - init_packet->Messages.InitMessages.InitComplete.Status); + init_packet->msg.init_msg.init_complete.status); ret = -1; goto Cleanup; } - if (init_packet->Messages.InitMessages.InitComplete. - NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) { + if (init_packet->msg.init_msg.init_complete. + negotiated_protocol_ver != NVSP_PROTOCOL_VERSION_1) { DPRINT_ERR(NETVSC, "unable to initialize with netvsp " "(version expected 1 got %d)", - init_packet->Messages.InitMessages. - InitComplete.NegotiatedProtocolVersion); + init_packet->msg.init_msg. + init_complete.negotiated_protocol_ver); ret = -1; goto Cleanup; } @@ -654,12 +654,12 @@ static int netvsc_connect_vsp(struct hv_device *device) ndis_version = 0x00050000; - init_packet->Header.MessageType = NvspMessage1TypeSendNdisVersion; - init_packet->Messages.Version1Messages. - SendNdisVersion.NdisMajorVersion = + init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER; + init_packet->msg.v1_msg. + send_ndis_ver.ndis_major_ver = (ndis_version & 0xFFFF0000) >> 16; - init_packet->Messages.Version1Messages. - SendNdisVersion.NdisMinorVersion = + init_packet->msg.v1_msg. + send_ndis_ver.ndis_minor_ver = ndis_version & 0xFFFF; /* Send the init request */ @@ -719,12 +719,12 @@ static int netvsc_device_add(struct hv_device *device, void *additional_info) DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", net_device); /* Initialize the NetVSC channel extension */ - net_device->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE; - spin_lock_init(&net_device->receive_packet_list_lock); + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; + spin_lock_init(&net_device->recv_pkt_list_lock); - net_device->SendBufferSize = NETVSC_SEND_BUFFER_SIZE; + net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE; - INIT_LIST_HEAD(&net_device->ReceivePacketList); + INIT_LIST_HEAD(&net_device->recv_pkt_list); for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { packet = kzalloc(sizeof(struct hv_netvsc_packet) + @@ -737,10 +737,10 @@ static int netvsc_device_add(struct hv_device *device, void *additional_info) break; } list_add_tail(&packet->list_ent, - &net_device->ReceivePacketList); + &net_device->recv_pkt_list); } - net_device->ChannelInitEvent = osd_waitevent_create(); - if (!net_device->ChannelInitEvent) { + net_device->channel_init_event = osd_waitevent_create(); + if (!net_device->channel_init_event) { ret = -ENOMEM; goto Cleanup; } @@ -779,10 +779,10 @@ close: Cleanup: if (net_device) { - kfree(net_device->ChannelInitEvent); + kfree(net_device->channel_init_event); list_for_each_entry_safe(packet, pos, - &net_device->ReceivePacketList, + &net_device->recv_pkt_list, list_ent) { list_del(&packet->list_ent); kfree(packet); @@ -816,9 +816,9 @@ static int netvsc_device_remove(struct hv_device *device) } /* Wait for all send completions */ - while (atomic_read(&net_device->NumOutstandingSends)) { + while (atomic_read(&net_device->num_outstanding_sends)) { DPRINT_INFO(NETVSC, "waiting for %d requests to complete...", - atomic_read(&net_device->NumOutstandingSends)); + atomic_read(&net_device->num_outstanding_sends)); udelay(100); } @@ -840,12 +840,12 @@ static int netvsc_device_remove(struct hv_device *device) /* Release all resources */ list_for_each_entry_safe(netvsc_packet, pos, - &net_device->ReceivePacketList, list_ent) { + &net_device->recv_pkt_list, list_ent) { list_del(&netvsc_packet->list_ent); kfree(netvsc_packet); } - kfree(net_device->ChannelInitEvent); + kfree(net_device->channel_init_event); free_net_device(net_device); return 0; } @@ -875,19 +875,19 @@ static void netvsc_send_completion(struct hv_device *device, (packet->DataOffset8 << 3)); DPRINT_DBG(NETVSC, "send completion packet - type %d", - nvsp_packet->Header.MessageType); + nvsp_packet->hdr.msg_type); - if ((nvsp_packet->Header.MessageType == NvspMessageTypeInitComplete) || - (nvsp_packet->Header.MessageType == - NvspMessage1TypeSendReceiveBufferComplete) || - (nvsp_packet->Header.MessageType == - NvspMessage1TypeSendSendBufferComplete)) { + if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) || + (nvsp_packet->hdr.msg_type == + NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) || + (nvsp_packet->hdr.msg_type == + NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE)) { /* Copy the response back */ - memcpy(&net_device->ChannelInitPacket, nvsp_packet, + memcpy(&net_device->channel_init_pkt, nvsp_packet, sizeof(struct nvsp_message)); - osd_waitevent_set(net_device->ChannelInitEvent); - } else if (nvsp_packet->Header.MessageType == - NvspMessage1TypeSendRNDISPacketComplete) { + osd_waitevent_set(net_device->channel_init_event); + } else if (nvsp_packet->hdr.msg_type == + NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) { /* Get the send context */ nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) packet->TransactionId; @@ -897,10 +897,10 @@ static void netvsc_send_completion(struct hv_device *device, nvsc_packet->completion.send.send_completion( nvsc_packet->completion.send.send_completion_ctx); - atomic_dec(&net_device->NumOutstandingSends); + atomic_dec(&net_device->num_outstanding_sends); } else { DPRINT_ERR(NETVSC, "Unknown send completion packet type - " - "%d received!!", nvsp_packet->Header.MessageType); + "%d received!!", nvsp_packet->hdr.msg_type); } put_net_device(device); @@ -921,18 +921,19 @@ static int netvsc_send(struct hv_device *device, return -2; } - sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket; + sendMessage.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT; if (packet->is_data_pkt) { /* 0 is RMC_DATA; */ - sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0; + sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 0; } else { /* 1 is RMC_CONTROL; */ - sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1; + sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 1; } /* Not using send buffer section */ - sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF; - sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0; + sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_index = + 0xFFFFFFFF; + sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0; if (packet->page_buf_cnt) { ret = vmbus_sendpacket_pagebuffer(device->channel, @@ -954,7 +955,7 @@ static int netvsc_send(struct hv_device *device, DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", packet, ret); - atomic_inc(&net_device->NumOutstandingSends); + atomic_inc(&net_device->num_outstanding_sends); put_net_device(device); return ret; } @@ -997,16 +998,16 @@ static void netvsc_receive(struct hv_device *device, (packet->DataOffset8 << 3)); /* Make sure this is a valid nvsp packet */ - if (nvsp_packet->Header.MessageType != - NvspMessage1TypeSendRNDISPacket) { + if (nvsp_packet->hdr.msg_type != + NVSP_MSG1_TYPE_SEND_RNDIS_PKT) { DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", - nvsp_packet->Header.MessageType); + nvsp_packet->hdr.msg_type); put_net_device(device); return; } DPRINT_DBG(NETVSC, "NVSP packet received - type %d", - nvsp_packet->Header.MessageType); + nvsp_packet->hdr.msg_type); vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet; @@ -1027,13 +1028,13 @@ static void netvsc_receive(struct hv_device *device, * We grab it here so that we know exactly how many we can * fulfil */ - spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); - while (!list_empty(&net_device->ReceivePacketList)) { - list_move_tail(net_device->ReceivePacketList.next, &listHead); + spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); + while (!list_empty(&net_device->recv_pkt_list)) { + list_move_tail(net_device->recv_pkt_list.next, &listHead); if (++count == vmxferpage_packet->RangeCount + 1) break; } - spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); + spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); /* * We need at least 2 netvsc pkts (1 to represent the xfer @@ -1046,12 +1047,12 @@ static void netvsc_receive(struct hv_device *device, count, vmxferpage_packet->RangeCount + 1); /* Return it to the freelist */ - spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); + spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); for (i = count; i != 0; i--) { list_move_tail(listHead.next, - &net_device->ReceivePacketList); + &net_device->recv_pkt_list); } - spin_unlock_irqrestore(&net_device->receive_packet_list_lock, + spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); netvsc_send_recv_completion(device, @@ -1104,10 +1105,10 @@ static void netvsc_receive(struct hv_device *device, vmxferpage_packet->Ranges[i].ByteCount; start = virt_to_phys((void *)((unsigned long)net_device-> - ReceiveBuffer + vmxferpage_packet->Ranges[i].ByteOffset)); + recv_buf + vmxferpage_packet->Ranges[i].ByteOffset)); netvsc_packet->page_buf[0].Pfn = start >> PAGE_SHIFT; - end_virtual = (unsigned long)net_device->ReceiveBuffer + end_virtual = (unsigned long)net_device->recv_buf + vmxferpage_packet->Ranges[i].ByteOffset + vmxferpage_packet->Ranges[i].ByteCount - 1; end = virt_to_phys((void *)end_virtual); @@ -1175,11 +1176,12 @@ static void netvsc_send_recv_completion(struct hv_device *device, DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx", transaction_id); - recvcompMessage.Header.MessageType = - NvspMessage1TypeSendRNDISPacketComplete; + recvcompMessage.hdr.msg_type = + NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE; /* FIXME: Pass in the status */ - recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess; + recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = + NVSP_STAT_SUCCESS; retry_send_cmplt: /* Send the completion */ @@ -1234,7 +1236,7 @@ static void netvsc_receive_completion(void *context) } /* Overloading use of the lock. */ - spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); + spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); /* ASSERT(packet->XferPagePacket->Count > 0); */ packet->xfer_page_pkt->count--; @@ -1247,13 +1249,13 @@ static void netvsc_receive_completion(void *context) fsend_receive_comp = true; transaction_id = packet->completion.recv.recv_completion_tid; list_add_tail(&packet->xfer_page_pkt->list_ent, - &net_device->ReceivePacketList); + &net_device->recv_pkt_list); } /* Put the packet back */ - list_add_tail(&packet->list_ent, &net_device->ReceivePacketList); - spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); + list_add_tail(&packet->list_ent, &net_device->recv_pkt_list); + spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); /* Send a receive completion for the xfer page packet */ if (fsend_receive_comp) diff --git a/drivers/staging/hv/netvsc.h b/drivers/staging/hv/netvsc.h index c71dce5b3f7c..932a77ccdc04 100644 --- a/drivers/staging/hv/netvsc.h +++ b/drivers/staging/hv/netvsc.h @@ -38,48 +38,48 @@ #define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 enum { - NvspMessageTypeNone = 0, + NVSP_MSG_TYPE_NONE = 0, /* Init Messages */ - NvspMessageTypeInit = 1, - NvspMessageTypeInitComplete = 2, + NVSP_MSG_TYPE_INIT = 1, + NVSP_MSG_TYPE_INIT_COMPLETE = 2, - NvspVersionMessageStart = 100, + NVSP_VERSION_MSG_START = 100, /* Version 1 Messages */ - NvspMessage1TypeSendNdisVersion = NvspVersionMessageStart, + NVSP_MSG1_TYPE_SEND_NDIS_VER = NVSP_VERSION_MSG_START, - NvspMessage1TypeSendReceiveBuffer, - NvspMessage1TypeSendReceiveBufferComplete, - NvspMessage1TypeRevokeReceiveBuffer, + NVSP_MSG1_TYPE_SEND_RECV_BUF, + NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE, + NVSP_MSG1_TYPE_REVOKE_RECV_BUF, - NvspMessage1TypeSendSendBuffer, - NvspMessage1TypeSendSendBufferComplete, - NvspMessage1TypeRevokeSendBuffer, + NVSP_MSG1_TYPE_SEND_SEND_BUF, + NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE, + NVSP_MSG1_TYPE_REVOKE_SEND_BUF, - NvspMessage1TypeSendRNDISPacket, - NvspMessage1TypeSendRNDISPacketComplete, + NVSP_MSG1_TYPE_SEND_RNDIS_PKT, + NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE, /* * This should be set to the number of messages for the version with * the maximum number of messages. */ - NvspNumMessagePerVersion = 9, + NVSP_NUM_MSG_PER_VERSION = 9, }; enum { - NvspStatusNone = 0, - NvspStatusSuccess, - NvspStatusFailure, - NvspStatusProtocolVersionRangeTooNew, - NvspStatusProtocolVersionRangeTooOld, - NvspStatusInvalidRndisPacket, - NvspStatusBusy, - NvspStatusMax, + NVSP_STAT_NONE = 0, + NVSP_STAT_SUCCESS, + NVSP_STAT_FAIL, + NVSP_STAT_PROTOCOL_TOO_NEW, + NVSP_STAT_PROTOCOL_TOO_OLD, + NVSP_STAT_INVALID_RNDIS_PKT, + NVSP_STAT_BUSY, + NVSP_STAT_MAX, }; struct nvsp_message_header { - u32 MessageType; + u32 msg_type; }; /* Init Messages */ @@ -90,8 +90,8 @@ struct nvsp_message_header { * versioning (i.e. this message will be the same for ever). */ struct nvsp_message_init { - u32 MinProtocolVersion; - u32 MaxProtocolVersion; + u32 min_protocol_ver; + u32 max_protocol_ver; } __attribute__((packed)); /* @@ -100,14 +100,14 @@ struct nvsp_message_init { * (i.e. this message will be the same for ever). */ struct nvsp_message_init_complete { - u32 NegotiatedProtocolVersion; - u32 MaximumMdlChainLength; - u32 Status; + u32 negotiated_protocol_ver; + u32 max_mdl_chain_len; + u32 status; } __attribute__((packed)); union nvsp_message_init_uber { - struct nvsp_message_init Init; - struct nvsp_message_init_complete InitComplete; + struct nvsp_message_init init; + struct nvsp_message_init_complete init_complete; } __attribute__((packed)); /* Version 1 Messages */ @@ -117,8 +117,8 @@ union nvsp_message_init_uber { * can use this information when handling OIDs sent by the VSC. */ struct nvsp_1_message_send_ndis_version { - u32 NdisMajorVersion; - u32 NdisMinorVersion; + u32 ndis_major_ver; + u32 ndis_minor_ver; } __attribute__((packed)); /* @@ -126,15 +126,15 @@ struct nvsp_1_message_send_ndis_version { * can then use the receive buffer to send data to the VSC. */ struct nvsp_1_message_send_receive_buffer { - u32 GpadlHandle; - u16 Id; + u32 gpadl_handle; + u16 id; } __attribute__((packed)); struct nvsp_1_receive_buffer_section { - u32 Offset; - u32 SubAllocationSize; - u32 NumSubAllocations; - u32 EndOffset; + u32 offset; + u32 sub_alloc_size; + u32 num_sub_allocs; + u32 end_offset; } __attribute__((packed)); /* @@ -143,8 +143,8 @@ struct nvsp_1_receive_buffer_section { * buffer. */ struct nvsp_1_message_send_receive_buffer_complete { - u32 Status; - u32 NumSections; + u32 status; + u32 num_sections; /* * The receive buffer is split into two parts, a large suballocation @@ -165,7 +165,7 @@ struct nvsp_1_message_send_receive_buffer_complete { * LargeOffset SmallOffset */ - struct nvsp_1_receive_buffer_section Sections[1]; + struct nvsp_1_receive_buffer_section sections[1]; } __attribute__((packed)); /* @@ -174,7 +174,7 @@ struct nvsp_1_message_send_receive_buffer_complete { * again. */ struct nvsp_1_message_revoke_receive_buffer { - u16 Id; + u16 id; }; /* @@ -182,8 +182,8 @@ struct nvsp_1_message_revoke_receive_buffer { * can then use the send buffer to send data to the VSP. */ struct nvsp_1_message_send_send_buffer { - u32 GpadlHandle; - u16 Id; + u32 gpadl_handle; + u16 id; } __attribute__((packed)); /* @@ -192,7 +192,7 @@ struct nvsp_1_message_send_send_buffer { * buffer. */ struct nvsp_1_message_send_send_buffer_complete { - u32 Status; + u32 status; /* * The VSC gets to choose the size of the send buffer and the VSP gets @@ -200,7 +200,7 @@ struct nvsp_1_message_send_send_buffer_complete { * dynamic reconfigurations when the cost of GPA-direct buffers * decreases. */ - u32 SectionSize; + u32 section_size; } __attribute__((packed)); /* @@ -208,7 +208,7 @@ struct nvsp_1_message_send_send_buffer_complete { * completes this transaction, the vsp should never use the send buffer again. */ struct nvsp_1_message_revoke_send_buffer { - u16 Id; + u16 id; }; /* @@ -221,7 +221,7 @@ struct nvsp_1_message_send_rndis_packet { * channels of communication. However, the Network VSP only has one. * Therefore, the channel travels with the RNDIS packet. */ - u32 ChannelType; + u32 channel_type; /* * This field is used to send part or all of the data through a send @@ -229,8 +229,8 @@ struct nvsp_1_message_send_rndis_packet { * index is 0xFFFFFFFF, then the send buffer is not being used and all * of the data was sent through other VMBus mechanisms. */ - u32 SendBufferSectionIndex; - u32 SendBufferSectionSize; + u32 send_buf_section_index; + u32 send_buf_section_size; } __attribute__((packed)); /* @@ -239,35 +239,35 @@ struct nvsp_1_message_send_rndis_packet { * message cannot use any resources associated with the original RNDIS packet. */ struct nvsp_1_message_send_rndis_packet_complete { - u32 Status; + u32 status; }; union nvsp_1_message_uber { - struct nvsp_1_message_send_ndis_version SendNdisVersion; + struct nvsp_1_message_send_ndis_version send_ndis_ver; - struct nvsp_1_message_send_receive_buffer SendReceiveBuffer; + struct nvsp_1_message_send_receive_buffer send_recv_buf; struct nvsp_1_message_send_receive_buffer_complete - SendReceiveBufferComplete; - struct nvsp_1_message_revoke_receive_buffer RevokeReceiveBuffer; + send_recv_buf_complete; + struct nvsp_1_message_revoke_receive_buffer revoke_recv_buf; - struct nvsp_1_message_send_send_buffer SendSendBuffer; - struct nvsp_1_message_send_send_buffer_complete SendSendBufferComplete; - struct nvsp_1_message_revoke_send_buffer RevokeSendBuffer; + struct nvsp_1_message_send_send_buffer send_send_buf; + struct nvsp_1_message_send_send_buffer_complete send_send_buf_complete; + struct nvsp_1_message_revoke_send_buffer revoke_send_buf; - struct nvsp_1_message_send_rndis_packet SendRNDISPacket; + struct nvsp_1_message_send_rndis_packet send_rndis_pkt; struct nvsp_1_message_send_rndis_packet_complete - SendRNDISPacketComplete; + send_rndis_pkt_complete; } __attribute__((packed)); union nvsp_all_messages { - union nvsp_message_init_uber InitMessages; - union nvsp_1_message_uber Version1Messages; + union nvsp_message_init_uber init_msg; + union nvsp_1_message_uber v1_msg; } __attribute__((packed)); /* ALL Messages */ struct nvsp_message { - struct nvsp_message_header Header; - union nvsp_all_messages Messages; + struct nvsp_message_header hdr; + union nvsp_all_messages msg; } __attribute__((packed)); @@ -293,39 +293,39 @@ struct nvsp_message { /* Per netvsc channel-specific */ struct netvsc_device { - struct hv_device *Device; + struct hv_device *dev; - atomic_t RefCount; - atomic_t NumOutstandingSends; + atomic_t refcnt; + atomic_t num_outstanding_sends; /* * List of free preallocated hv_netvsc_packet to represent receive * packet */ - struct list_head ReceivePacketList; - spinlock_t receive_packet_list_lock; + struct list_head recv_pkt_list; + spinlock_t recv_pkt_list_lock; /* Send buffer allocated by us but manages by NetVSP */ - void *SendBuffer; - u32 SendBufferSize; - u32 SendBufferGpadlHandle; - u32 SendSectionSize; + void *send_buf; + u32 send_buf_size; + u32 send_buf_gpadl_handle; + u32 send_section_size; /* Receive buffer allocated by us but manages by NetVSP */ - void *ReceiveBuffer; - u32 ReceiveBufferSize; - u32 ReceiveBufferGpadlHandle; - u32 ReceiveSectionCount; - struct nvsp_1_receive_buffer_section *ReceiveSections; + void *recv_buf; + u32 recv_buf_size; + u32 recv_buf_gpadl_handle; + u32 recv_section_cnt; + struct nvsp_1_receive_buffer_section *recv_section; /* Used for NetVSP initialization protocol */ - struct osd_waitevent *ChannelInitEvent; - struct nvsp_message ChannelInitPacket; + struct osd_waitevent *channel_init_event; + struct nvsp_message channel_init_pkt; - struct nvsp_message RevokePacket; + struct nvsp_message revoke_packet; /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */ /* Holds rndis device info */ - void *Extension; + void *extension; }; #endif /* _NETVSC_H_ */ diff --git a/drivers/staging/hv/netvsc_api.h b/drivers/staging/hv/netvsc_api.h index ac40db56e1fa..b4bed3636594 100644 --- a/drivers/staging/hv/netvsc_api.h +++ b/drivers/staging/hv/netvsc_api.h @@ -95,7 +95,7 @@ struct netvsc_driver { */ int (*recv_cb)(struct hv_device *dev, struct hv_netvsc_packet *packet); - void (*link_status_change)(struct hv_device *dev, u32 Status); + void (*link_status_change)(struct hv_device *dev, u32 status); /* Specific to this driver */ int (*send)(struct hv_device *dev, struct hv_netvsc_packet *packet); diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index dffcc0397917..63d24c6fadf0 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -266,7 +266,7 @@ static int rndis_filter_send_request(struct rndis_device *dev, rndis_filter_send_request_completion; packet->completion.send.send_completion_tid = (unsigned long)dev; - ret = rndis_filter.inner_drv.send(dev->net_dev->Device, packet); + ret = rndis_filter.inner_drv.send(dev->net_dev->dev, packet); return ret; } @@ -338,10 +338,10 @@ static void rndis_filter_receive_indicate_status(struct rndis_device *dev, if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) { rndis_filter.inner_drv.link_status_change( - dev->net_dev->Device, 1); + dev->net_dev->dev, 1); } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) { rndis_filter.inner_drv.link_status_change( - dev->net_dev->Device, 0); + dev->net_dev->dev, 0); } else { /* * TODO: @@ -376,7 +376,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, pkt->is_data_pkt = true; - rndis_filter.inner_drv.recv_cb(dev->net_dev->Device, + rndis_filter.inner_drv.recv_cb(dev->net_dev->dev, pkt); } @@ -392,13 +392,13 @@ static int rndis_filter_receive(struct hv_device *dev, return -EINVAL; /* Make sure the rndis device state is initialized */ - if (!net_dev->Extension) { + if (!net_dev->extension) { DPRINT_ERR(NETVSC, "got rndis message but no rndis device..." "dropping this message!"); return -1; } - rndis_dev = (struct rndis_device *)net_dev->Extension; + rndis_dev = (struct rndis_device *)net_dev->extension; if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { DPRINT_ERR(NETVSC, "got rndis message but rndis device " "uninitialized...dropping this message!"); @@ -782,7 +782,7 @@ static int rndis_filte_device_add(struct hv_device *dev, /* ASSERT(netDevice); */ /* ASSERT(netDevice->Device); */ - netDevice->Extension = rndisDevice; + netDevice->extension = rndisDevice; rndisDevice->net_dev = netDevice; /* Send the rndis initialization message */ @@ -819,13 +819,13 @@ static int rndis_filte_device_add(struct hv_device *dev, static int rndis_filter_device_remove(struct hv_device *dev) { struct netvsc_device *net_dev = dev->Extension; - struct rndis_device *rndis_dev = net_dev->Extension; + struct rndis_device *rndis_dev = net_dev->extension; /* Halt and release the rndis device */ rndis_filter_halt_device(rndis_dev); kfree(rndis_dev); - net_dev->Extension = NULL; + net_dev->extension = NULL; /* Pass control to inner driver to remove the device */ rndis_filter.inner_drv.base.OnDeviceRemove(dev); @@ -844,7 +844,7 @@ int rndis_filter_open(struct hv_device *dev) if (!netDevice) return -EINVAL; - return rndis_filter_open_device(netDevice->Extension); + return rndis_filter_open_device(netDevice->extension); } int rndis_filter_close(struct hv_device *dev) @@ -854,7 +854,7 @@ int rndis_filter_close(struct hv_device *dev) if (!netDevice) return -EINVAL; - return rndis_filter_close_device(netDevice->Extension); + return rndis_filter_close_device(netDevice->extension); } static int rndis_filter_send(struct hv_device *dev, -- cgit v1.2.3 From a388eb1727c15a7da1f64fcf16e60fcb7aca40bd Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 10 Dec 2010 12:04:00 -0800 Subject: staging: hv: Convert camel cased struct fields in rndis.h to lower cases Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/rndis.h | 353 +++++++++++++++++++------------------- drivers/staging/hv/rndis_filter.c | 204 +++++++++++----------- 2 files changed, 279 insertions(+), 278 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/rndis.h b/drivers/staging/hv/rndis.h index 723e1f15b90d..014de047b86d 100644 --- a/drivers/staging/hv/rndis.h +++ b/drivers/staging/hv/rndis.h @@ -288,24 +288,24 @@ #define RNDIS_DF_RAW_DATA 0x00000004 /* Remote NDIS medium types. */ -#define RNdisMedium802_3 0x00000000 -#define RNdisMedium802_5 0x00000001 -#define RNdisMediumFddi 0x00000002 -#define RNdisMediumWan 0x00000003 -#define RNdisMediumLocalTalk 0x00000004 -#define RNdisMediumArcnetRaw 0x00000006 -#define RNdisMediumArcnet878_2 0x00000007 -#define RNdisMediumAtm 0x00000008 -#define RNdisMediumWirelessWan 0x00000009 -#define RNdisMediumIrda 0x0000000a -#define RNdisMediumCoWan 0x0000000b +#define RNDIS_MEDIUM_802_3 0x00000000 +#define RNDIS_MEDIUM_802_5 0x00000001 +#define RNDIS_MEDIUM_FDDI 0x00000002 +#define RNDIS_MEDIUM_WAN 0x00000003 +#define RNDIS_MEDIUM_LOCAL_TALK 0x00000004 +#define RNDIS_MEDIUM_ARCNET_RAW 0x00000006 +#define RNDIS_MEDIUM_ARCNET_878_2 0x00000007 +#define RNDIS_MEDIUM_ATM 0x00000008 +#define RNDIS_MEDIUM_WIRELESS_WAN 0x00000009 +#define RNDIS_MEDIUM_IRDA 0x0000000a +#define RNDIS_MEDIUM_CO_WAN 0x0000000b /* Not a real medium, defined as an upper-bound */ -#define RNdisMediumMax 0x0000000d +#define RNDIS_MEDIUM_MAX 0x0000000d /* Remote NDIS medium connection states. */ -#define RNdisMediaStateConnected 0x00000000 -#define RNdisMediaStateDisconnected 0x00000001 +#define RNDIS_MEDIA_STATE_CONNECTED 0x00000000 +#define RNDIS_MEDIA_STATE_DISCONNECTED 0x00000001 /* Remote NDIS version numbers */ #define RNDIS_MAJOR_VERSION 0x00000001 @@ -314,106 +314,106 @@ /* NdisInitialize message */ struct rndis_initialize_request { - u32 RequestId; - u32 MajorVersion; - u32 MinorVersion; - u32 MaxTransferSize; + u32 req_id; + u32 major_ver; + u32 minor_ver; + u32 max_xfer_size; }; /* Response to NdisInitialize */ struct rndis_initialize_complete { - u32 RequestId; - u32 Status; - u32 MajorVersion; - u32 MinorVersion; - u32 DeviceFlags; - u32 Medium; - u32 MaxPacketsPerMessage; - u32 MaxTransferSize; - u32 PacketAlignmentFactor; - u32 AFListOffset; - u32 AFListSize; + u32 req_id; + u32 status; + u32 major_ver; + u32 minor_ver; + u32 dev_flags; + u32 medium; + u32 max_pkt_per_msg; + u32 max_xfer_size; + u32 pkt_alignment_factor; + u32 af_list_offset; + u32 af_list_size; }; /* Call manager devices only: Information about an address family */ /* supported by the device is appended to the response to NdisInitialize. */ struct rndis_co_address_family { - u32 AddressFamily; - u32 MajorVersion; - u32 MinorVersion; + u32 address_family; + u32 major_ver; + u32 minor_ver; }; /* NdisHalt message */ struct rndis_halt_request { - u32 RequestId; + u32 req_id; }; /* NdisQueryRequest message */ struct rndis_query_request { - u32 RequestId; - u32 Oid; - u32 InformationBufferLength; - u32 InformationBufferOffset; - u32 DeviceVcHandle; + u32 req_id; + u32 oid; + u32 info_buflen; + u32 info_buf_offset; + u32 dev_vc_handle; }; /* Response to NdisQueryRequest */ struct rndis_query_complete { - u32 RequestId; - u32 Status; - u32 InformationBufferLength; - u32 InformationBufferOffset; + u32 req_id; + u32 status; + u32 info_buflen; + u32 info_buf_offset; }; /* NdisSetRequest message */ struct rndis_set_request { - u32 RequestId; - u32 Oid; - u32 InformationBufferLength; - u32 InformationBufferOffset; - u32 DeviceVcHandle; + u32 req_id; + u32 oid; + u32 info_buflen; + u32 info_buf_offset; + u32 dev_vc_handle; }; /* Response to NdisSetRequest */ struct rndis_set_complete { - u32 RequestId; - u32 Status; + u32 req_id; + u32 status; }; /* NdisReset message */ struct rndis_reset_request { - u32 Reserved; + u32 reserved; }; /* Response to NdisReset */ struct rndis_reset_complete { - u32 Status; - u32 AddressingReset; + u32 status; + u32 addressing_reset; }; /* NdisMIndicateStatus message */ struct rndis_indicate_status { - u32 Status; - u32 StatusBufferLength; - u32 StatusBufferOffset; + u32 status; + u32 status_buflen; + u32 status_buf_offset; }; /* Diagnostic information passed as the status buffer in */ /* struct rndis_indicate_status messages signifying error conditions. */ struct rndis_diagnostic_info { - u32 DiagStatus; - u32 ErrorOffset; + u32 diag_status; + u32 error_offset; }; /* NdisKeepAlive message */ struct rndis_keepalive_request { - u32 RequestId; + u32 req_id; }; /* Response to NdisKeepAlive */ struct rndis_keepalive_complete { - u32 RequestId; - u32 Status; + u32 req_id; + u32 status; }; /* @@ -422,39 +422,39 @@ struct rndis_keepalive_complete { * to 0 for connectionless data, otherwise it contains the VC handle. */ struct rndis_packet { - u32 DataOffset; - u32 DataLength; - u32 OOBDataOffset; - u32 OOBDataLength; - u32 NumOOBDataElements; - u32 PerPacketInfoOffset; - u32 PerPacketInfoLength; - u32 VcHandle; - u32 Reserved; + u32 data_offset; + u32 data_len; + u32 oob_data_offset; + u32 oob_data_len; + u32 num_oob_data_elements; + u32 per_pkt_info_offset; + u32 per_pkt_info_len; + u32 vc_handle; + u32 reserved; }; /* Optional Out of Band data associated with a Data message. */ struct rndis_oobd { - u32 Size; - u32 Type; - u32 ClassInformationOffset; + u32 size; + u32 type; + u32 class_info_offset; }; /* Packet extension field contents associated with a Data message. */ struct rndis_per_packet_info { - u32 Size; - u32 Type; - u32 PerPacketInformationOffset; + u32 size; + u32 type; + u32 per_pkt_info_offset; }; /* Format of Information buffer passed in a SetRequest for the OID */ /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ struct rndis_config_parameter_info { - u32 ParameterNameOffset; - u32 ParameterNameLength; - u32 ParameterType; - u32 ParameterValueOffset; - u32 ParameterValueLength; + u32 parameter_name_offset; + u32 parameter_name_length; + u32 parameter_type; + u32 parameter_value_offset; + u32 parameter_value_length; }; /* Values for ParameterType in struct rndis_config_parameter_info */ @@ -466,187 +466,188 @@ struct rndis_config_parameter_info { /* CoNdisMiniportCreateVc message */ struct rcondis_mp_create_vc { - u32 RequestId; - u32 NdisVcHandle; + u32 req_id; + u32 ndis_vc_handle; }; /* Response to CoNdisMiniportCreateVc */ struct rcondis_mp_create_vc_complete { - u32 RequestId; - u32 DeviceVcHandle; - u32 Status; + u32 req_id; + u32 dev_vc_handle; + u32 status; }; /* CoNdisMiniportDeleteVc message */ struct rcondis_mp_delete_vc { - u32 RequestId; - u32 DeviceVcHandle; + u32 req_id; + u32 dev_vc_handle; }; /* Response to CoNdisMiniportDeleteVc */ struct rcondis_mp_delete_vc_complete { - u32 RequestId; - u32 Status; + u32 req_id; + u32 status; }; /* CoNdisMiniportQueryRequest message */ struct rcondis_mp_query_request { - u32 RequestId; - u32 RequestType; - u32 Oid; - u32 DeviceVcHandle; - u32 InformationBufferLength; - u32 InformationBufferOffset; + u32 req_id; + u32 request_type; + u32 oid; + u32 dev_vc_handle; + u32 info_buflen; + u32 info_buf_offset; }; /* CoNdisMiniportSetRequest message */ struct rcondis_mp_set_request { - u32 RequestId; - u32 RequestType; - u32 Oid; - u32 DeviceVcHandle; - u32 InformationBufferLength; - u32 InformationBufferOffset; + u32 req_id; + u32 request_type; + u32 oid; + u32 dev_vc_handle; + u32 info_buflen; + u32 info_buf_offset; }; /* CoNdisIndicateStatus message */ struct rcondis_indicate_status { - u32 NdisVcHandle; - u32 Status; - u32 StatusBufferLength; - u32 StatusBufferOffset; + u32 ndis_vc_handle; + u32 status; + u32 status_buflen; + u32 status_buf_offset; }; /* CONDIS Call/VC parameters */ struct rcondis_specific_parameters { - u32 ParameterType; - u32 ParameterLength; - u32 ParameterOffset; + u32 parameter_type; + u32 parameter_length; + u32 parameter_lffset; }; struct rcondis_media_parameters { - u32 Flags; - u32 Reserved1; - u32 Reserved2; - struct rcondis_specific_parameters MediaSpecific; + u32 flags; + u32 reserved1; + u32 reserved2; + struct rcondis_specific_parameters media_specific; }; struct rndis_flowspec { - u32 TokenRate; - u32 TokenBucketSize; - u32 PeakBandwidth; - u32 Latency; - u32 DelayVariation; - u32 ServiceType; - u32 MaxSduSize; - u32 MinimumPolicedSize; + u32 token_rate; + u32 token_bucket_size; + u32 peak_bandwidth; + u32 latency; + u32 delay_variation; + u32 service_type; + u32 max_sdu_size; + u32 minimum_policed_size; }; struct rcondis_call_manager_parameters { - struct rndis_flowspec Transmit; - struct rndis_flowspec Receive; - struct rcondis_specific_parameters CallMgrSpecific; + struct rndis_flowspec transmit; + struct rndis_flowspec receive; + struct rcondis_specific_parameters call_mgr_specific; }; /* CoNdisMiniportActivateVc message */ struct rcondis_mp_activate_vc_request { - u32 RequestId; - u32 Flags; - u32 DeviceVcHandle; - u32 MediaParamsOffset; - u32 MediaParamsLength; - u32 CallMgrParamsOffset; - u32 CallMgrParamsLength; + u32 req_id; + u32 flags; + u32 dev_vc_handle; + u32 media_params_offset; + u32 media_params_length; + u32 call_mgr_params_offset; + u32 call_mgr_params_length; }; /* Response to CoNdisMiniportActivateVc */ struct rcondis_mp_activate_vc_complete { - u32 RequestId; - u32 Status; + u32 req_id; + u32 status; }; /* CoNdisMiniportDeactivateVc message */ struct rcondis_mp_deactivate_vc_request { - u32 RequestId; - u32 Flags; - u32 DeviceVcHandle; + u32 req_id; + u32 flags; + u32 dev_vc_handle; }; /* Response to CoNdisMiniportDeactivateVc */ struct rcondis_mp_deactivate_vc_complete { - u32 RequestId; - u32 Status; + u32 req_id; + u32 status; }; /* union with all of the RNDIS messages */ union rndis_message_container { - struct rndis_packet Packet; - struct rndis_initialize_request InitializeRequest; - struct rndis_halt_request HaltRequest; - struct rndis_query_request QueryRequest; - struct rndis_set_request SetRequest; - struct rndis_reset_request ResetRequest; - struct rndis_keepalive_request KeepaliveRequest; - struct rndis_indicate_status IndicateStatus; - struct rndis_initialize_complete InitializeComplete; - struct rndis_query_complete QueryComplete; - struct rndis_set_complete SetComplete; - struct rndis_reset_complete ResetComplete; - struct rndis_keepalive_complete KeepaliveComplete; - struct rcondis_mp_create_vc CoMiniportCreateVc; - struct rcondis_mp_delete_vc CoMiniportDeleteVc; - struct rcondis_indicate_status CoIndicateStatus; - struct rcondis_mp_activate_vc_request CoMiniportActivateVc; - struct rcondis_mp_deactivate_vc_request CoMiniportDeactivateVc; - struct rcondis_mp_create_vc_complete CoMiniportCreateVcComplete; - struct rcondis_mp_delete_vc_complete CoMiniportDeleteVcComplete; - struct rcondis_mp_activate_vc_complete CoMiniportActivateVcComplete; - struct rcondis_mp_deactivate_vc_complete CoMiniportDeactivateVcComplete; + struct rndis_packet pkt; + struct rndis_initialize_request init_req; + struct rndis_halt_request halt_req; + struct rndis_query_request query_req; + struct rndis_set_request set_req; + struct rndis_reset_request reset_req; + struct rndis_keepalive_request keep_alive_req; + struct rndis_indicate_status indicate_status; + struct rndis_initialize_complete init_complete; + struct rndis_query_complete query_complete; + struct rndis_set_complete set_complete; + struct rndis_reset_complete reset_complete; + struct rndis_keepalive_complete keep_alive_complete; + struct rcondis_mp_create_vc co_miniport_create_vc; + struct rcondis_mp_delete_vc co_miniport_delete_vc; + struct rcondis_indicate_status co_indicate_status; + struct rcondis_mp_activate_vc_request co_miniport_activate_vc; + struct rcondis_mp_deactivate_vc_request co_miniport_deactivate_vc; + struct rcondis_mp_create_vc_complete co_miniport_create_vc_complete; + struct rcondis_mp_delete_vc_complete co_miniport_delete_vc_complete; + struct rcondis_mp_activate_vc_complete co_miniport_activate_vc_complete; + struct rcondis_mp_deactivate_vc_complete + co_miniport_deactivate_vc_complete; }; /* Remote NDIS message format */ struct rndis_message { - u32 NdisMessageType; + u32 ndis_msg_type; /* Total length of this message, from the beginning */ /* of the sruct rndis_message, in bytes. */ - u32 MessageLength; + u32 msg_len; /* Actual message */ - union rndis_message_container Message; + union rndis_message_container msg; }; /* Handy macros */ /* get the size of an RNDIS message. Pass in the message type, */ /* struct rndis_set_request, struct rndis_packet for example */ -#define RNDIS_MESSAGE_SIZE(Message) \ - (sizeof(Message) + (sizeof(struct rndis_message) - \ +#define RNDIS_MESSAGE_SIZE(msg) \ + (sizeof(msg) + (sizeof(struct rndis_message) - \ sizeof(union rndis_message_container))) /* get pointer to info buffer with message pointer */ -#define MESSAGE_TO_INFO_BUFFER(Message) \ - (((unsigned char *)(Message)) + Message->InformationBufferOffset) +#define MESSAGE_TO_INFO_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->info_buf_offset) /* get pointer to status buffer with message pointer */ -#define MESSAGE_TO_STATUS_BUFFER(Message) \ - (((unsigned char *)(Message)) + Message->StatusBufferOffset) +#define MESSAGE_TO_STATUS_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->status_buf_offset) /* get pointer to OOBD buffer with message pointer */ -#define MESSAGE_TO_OOBD_BUFFER(Message) \ - (((unsigned char *)(Message)) + Message->OOBDataOffset) +#define MESSAGE_TO_OOBD_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->oob_data_offset) /* get pointer to data buffer with message pointer */ -#define MESSAGE_TO_DATA_BUFFER(Message) \ - (((unsigned char *)(Message)) + Message->PerPacketInfoOffset) +#define MESSAGE_TO_DATA_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->per_pkt_info_offset) /* get pointer to contained message from NDIS_MESSAGE pointer */ -#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(RndisMessage) \ - ((void *) &RndisMessage->Message) +#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(rndis_msg) \ + ((void *) &rndis_msg->msg) /* get pointer to contained message from NDIS_MESSAGE pointer */ -#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(RndisMessage) \ - ((void *) RndisMessage) +#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(rndis_msg) \ + ((void *) rndis_msg) #endif /* _RNDIS_H_ */ diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index 63d24c6fadf0..53676dcbf381 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -136,16 +136,16 @@ static struct rndis_request *get_rndis_request(struct rndis_device *dev, } rndis_msg = &request->request_msg; - rndis_msg->NdisMessageType = msg_type; - rndis_msg->MessageLength = msg_len; + rndis_msg->ndis_msg_type = msg_type; + rndis_msg->msg_len = msg_len; /* * Set the request id. This field is always after the rndis header for * request/response packet types so we just used the SetRequest as a * template */ - set = &rndis_msg->Message.SetRequest; - set->RequestId = atomic_inc_return(&dev->new_req_id); + set = &rndis_msg->msg.set_req; + set->req_id = atomic_inc_return(&dev->new_req_id); /* Add to the request list */ spin_lock_irqsave(&dev->request_lock, flags); @@ -170,20 +170,20 @@ static void put_rndis_request(struct rndis_device *dev, static void dump_rndis_message(struct rndis_message *rndis_msg) { - switch (rndis_msg->NdisMessageType) { + switch (rndis_msg->ndis_msg_type) { case REMOTE_NDIS_PACKET_MSG: DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, " "data offset %u data len %u, # oob %u, " "oob offset %u, oob len %u, pkt offset %u, " "pkt len %u", - rndis_msg->MessageLength, - rndis_msg->Message.Packet.DataOffset, - rndis_msg->Message.Packet.DataLength, - rndis_msg->Message.Packet.NumOOBDataElements, - rndis_msg->Message.Packet.OOBDataOffset, - rndis_msg->Message.Packet.OOBDataLength, - rndis_msg->Message.Packet.PerPacketInfoOffset, - rndis_msg->Message.Packet.PerPacketInfoLength); + rndis_msg->msg_len, + rndis_msg->msg.pkt.data_offset, + rndis_msg->msg.pkt.data_len, + rndis_msg->msg.pkt.num_oob_data_elements, + rndis_msg->msg.pkt.oob_data_offset, + rndis_msg->msg.pkt.oob_data_len, + rndis_msg->msg.pkt.per_pkt_info_offset, + rndis_msg->msg.pkt.per_pkt_info_len); break; case REMOTE_NDIS_INITIALIZE_CMPLT: @@ -191,53 +191,53 @@ static void dump_rndis_message(struct rndis_message *rndis_msg) "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " "device flags %d, max xfer size 0x%x, max pkts %u, " "pkt aligned %u)", - rndis_msg->MessageLength, - rndis_msg->Message.InitializeComplete.RequestId, - rndis_msg->Message.InitializeComplete.Status, - rndis_msg->Message.InitializeComplete.MajorVersion, - rndis_msg->Message.InitializeComplete.MinorVersion, - rndis_msg->Message.InitializeComplete.DeviceFlags, - rndis_msg->Message.InitializeComplete.MaxTransferSize, - rndis_msg->Message.InitializeComplete. - MaxPacketsPerMessage, - rndis_msg->Message.InitializeComplete. - PacketAlignmentFactor); + rndis_msg->msg_len, + rndis_msg->msg.init_complete.req_id, + rndis_msg->msg.init_complete.status, + rndis_msg->msg.init_complete.major_ver, + rndis_msg->msg.init_complete.minor_ver, + rndis_msg->msg.init_complete.dev_flags, + rndis_msg->msg.init_complete.max_xfer_size, + rndis_msg->msg.init_complete. + max_pkt_per_msg, + rndis_msg->msg.init_complete. + pkt_alignment_factor); break; case REMOTE_NDIS_QUERY_CMPLT: DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT " "(len %u, id 0x%x, status 0x%x, buf len %u, " "buf offset %u)", - rndis_msg->MessageLength, - rndis_msg->Message.QueryComplete.RequestId, - rndis_msg->Message.QueryComplete.Status, - rndis_msg->Message.QueryComplete. - InformationBufferLength, - rndis_msg->Message.QueryComplete. - InformationBufferOffset); + rndis_msg->msg_len, + rndis_msg->msg.query_complete.req_id, + rndis_msg->msg.query_complete.status, + rndis_msg->msg.query_complete. + info_buflen, + rndis_msg->msg.query_complete. + info_buf_offset); break; case REMOTE_NDIS_SET_CMPLT: DPRINT_DBG(NETVSC, "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)", - rndis_msg->MessageLength, - rndis_msg->Message.SetComplete.RequestId, - rndis_msg->Message.SetComplete.Status); + rndis_msg->msg_len, + rndis_msg->msg.set_complete.req_id, + rndis_msg->msg.set_complete.status); break; case REMOTE_NDIS_INDICATE_STATUS_MSG: DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG " "(len %u, status 0x%x, buf len %u, buf offset %u)", - rndis_msg->MessageLength, - rndis_msg->Message.IndicateStatus.Status, - rndis_msg->Message.IndicateStatus.StatusBufferLength, - rndis_msg->Message.IndicateStatus.StatusBufferOffset); + rndis_msg->msg_len, + rndis_msg->msg.indicate_status.status, + rndis_msg->msg.indicate_status.status_buflen, + rndis_msg->msg.indicate_status.status_buf_offset); break; default: DPRINT_DBG(NETVSC, "0x%x (len %u)", - rndis_msg->NdisMessageType, - rndis_msg->MessageLength); + rndis_msg->ndis_msg_type, + rndis_msg->msg_len); break; } } @@ -252,12 +252,12 @@ static int rndis_filter_send_request(struct rndis_device *dev, packet = &req->pkt; packet->is_data_pkt = false; - packet->total_data_buflen = req->request_msg.MessageLength; + packet->total_data_buflen = req->request_msg.msg_len; packet->page_buf_cnt = 1; packet->page_buf[0].Pfn = virt_to_phys(&req->request_msg) >> PAGE_SHIFT; - packet->page_buf[0].Length = req->request_msg.MessageLength; + packet->page_buf[0].Length = req->request_msg.msg_len; packet->page_buf[0].Offset = (unsigned long)&req->request_msg & (PAGE_SIZE - 1); @@ -283,15 +283,15 @@ static void rndis_filter_receive_response(struct rndis_device *dev, * All request/response message contains RequestId as the 1st * field */ - if (request->request_msg.Message.InitializeRequest.RequestId - == resp->Message.InitializeComplete.RequestId) { + if (request->request_msg.msg.init_req.req_id + == resp->msg.init_complete.req_id) { DPRINT_DBG(NETVSC, "found rndis request for " "this response (id 0x%x req type 0x%x res " "type 0x%x)", - request->request_msg.Message. - InitializeRequest.RequestId, - request->request_msg.NdisMessageType, - resp->NdisMessageType); + request->request_msg.msg. + init_req.req_id, + request->request_msg.ndis_msg_type, + resp->ndis_msg_type); found = true; break; @@ -300,23 +300,23 @@ static void rndis_filter_receive_response(struct rndis_device *dev, spin_unlock_irqrestore(&dev->request_lock, flags); if (found) { - if (resp->MessageLength <= sizeof(struct rndis_message)) { + if (resp->msg_len <= sizeof(struct rndis_message)) { memcpy(&request->response_msg, resp, - resp->MessageLength); + resp->msg_len); } else { DPRINT_ERR(NETVSC, "rndis response buffer overflow " "detected (size %u max %zu)", - resp->MessageLength, + resp->msg_len, sizeof(struct rndis_filter_packet)); - if (resp->NdisMessageType == + if (resp->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) { /* does not have a request id field */ - request->response_msg.Message.ResetComplete. - Status = STATUS_BUFFER_OVERFLOW; + request->response_msg.msg.reset_complete. + status = STATUS_BUFFER_OVERFLOW; } else { - request->response_msg.Message. - InitializeComplete.Status = + request->response_msg.msg. + init_complete.status = STATUS_BUFFER_OVERFLOW; } } @@ -325,8 +325,8 @@ static void rndis_filter_receive_response(struct rndis_device *dev, } else { DPRINT_ERR(NETVSC, "no rndis request found for this response " "(id 0x%x res type 0x%x)", - resp->Message.InitializeComplete.RequestId, - resp->NdisMessageType); + resp->msg.init_complete.req_id, + resp->ndis_msg_type); } } @@ -334,12 +334,12 @@ static void rndis_filter_receive_indicate_status(struct rndis_device *dev, struct rndis_message *resp) { struct rndis_indicate_status *indicate = - &resp->Message.IndicateStatus; + &resp->msg.indicate_status; - if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) { + if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { rndis_filter.inner_drv.link_status_change( dev->net_dev->dev, 1); - } else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) { + } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { rndis_filter.inner_drv.link_status_change( dev->net_dev->dev, 0); } else { @@ -360,7 +360,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, /* ASSERT(Packet->PageBuffers[0].Length > */ /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */ - rndis_pkt = &msg->Message.Packet; + rndis_pkt = &msg->msg.pkt; /* * FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this @@ -368,7 +368,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, */ /* Remove the rndis header and pass it back up the stack */ - data_offset = RNDIS_HEADER_SIZE + rndis_pkt->DataOffset; + data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset; pkt->total_data_buflen -= data_offset; pkt->page_buf[0].Offset += data_offset; @@ -418,36 +418,36 @@ static int rndis_filter_receive(struct hv_device *dev, * range shows 52 bytes * */ #if 0 - if (pkt->total_data_buflen != rndis_hdr->MessageLength) { + if (pkt->total_data_buflen != rndis_hdr->msg_len) { kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset, KM_IRQ0); DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u " "bytes got %u)...dropping this message!", - rndis_hdr->MessageLength, + rndis_hdr->msg_len, pkt->total_data_buflen); return -1; } #endif - if ((rndis_hdr->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && - (rndis_hdr->MessageLength > sizeof(struct rndis_message))) { + if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) && + (rndis_hdr->msg_len > sizeof(struct rndis_message))) { DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow " "detected (got %u, max %zu)...marking it an error!", - rndis_hdr->MessageLength, + rndis_hdr->msg_len, sizeof(struct rndis_message)); } memcpy(&rndis_msg, rndis_hdr, - (rndis_hdr->MessageLength > sizeof(struct rndis_message)) ? + (rndis_hdr->msg_len > sizeof(struct rndis_message)) ? sizeof(struct rndis_message) : - rndis_hdr->MessageLength); + rndis_hdr->msg_len); kunmap_atomic(rndis_hdr - pkt->page_buf[0].Offset, KM_IRQ0); dump_rndis_message(&rndis_msg); - switch (rndis_msg.NdisMessageType) { + switch (rndis_msg.ndis_msg_type) { case REMOTE_NDIS_PACKET_MSG: /* data msg */ rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt); @@ -468,8 +468,8 @@ static int rndis_filter_receive(struct hv_device *dev, break; default: DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", - rndis_msg.NdisMessageType, - rndis_msg.MessageLength); + rndis_msg.ndis_msg_type, + rndis_msg.msg_len); break; } @@ -497,11 +497,11 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, } /* Setup the rndis query */ - query = &request->request_msg.Message.QueryRequest; - query->Oid = oid; - query->InformationBufferOffset = sizeof(struct rndis_query_request); - query->InformationBufferLength = 0; - query->DeviceVcHandle = 0; + query = &request->request_msg.msg.query_req; + query->oid = oid; + query->info_buf_offset = sizeof(struct rndis_query_request); + query->info_buflen = 0; + query->dev_vc_handle = 0; ret = rndis_filter_send_request(dev, request); if (ret != 0) @@ -510,19 +510,19 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, osd_waitevent_wait(request->waitevent); /* Copy the response back */ - query_complete = &request->response_msg.Message.QueryComplete; + query_complete = &request->response_msg.msg.query_complete; - if (query_complete->InformationBufferLength > inresult_size) { + if (query_complete->info_buflen > inresult_size) { ret = -1; goto Cleanup; } memcpy(result, (void *)((unsigned long)query_complete + - query_complete->InformationBufferOffset), - query_complete->InformationBufferLength); + query_complete->info_buf_offset), + query_complete->info_buflen); - *result_size = query_complete->InformationBufferLength; + *result_size = query_complete->info_buflen; Cleanup: if (request) @@ -570,10 +570,10 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev, } /* Setup the rndis set */ - set = &request->request_msg.Message.SetRequest; - set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; - set->InformationBufferLength = sizeof(u32); - set->InformationBufferOffset = sizeof(struct rndis_set_request); + set = &request->request_msg.msg.set_req; + set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; + set->info_buflen = sizeof(u32); + set->info_buf_offset = sizeof(struct rndis_set_request); memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request), &new_filter, sizeof(u32)); @@ -594,8 +594,8 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev, } else { if (ret > 0) ret = 0; - set_complete = &request->response_msg.Message.SetComplete; - status = set_complete->Status; + set_complete = &request->response_msg.msg.set_complete; + status = set_complete->status; } Cleanup: @@ -661,11 +661,11 @@ static int rndis_filter_init_device(struct rndis_device *dev) } /* Setup the rndis set */ - init = &request->request_msg.Message.InitializeRequest; - init->MajorVersion = RNDIS_MAJOR_VERSION; - init->MinorVersion = RNDIS_MINOR_VERSION; + init = &request->request_msg.msg.init_req; + init->major_ver = RNDIS_MAJOR_VERSION; + init->minor_ver = RNDIS_MINOR_VERSION; /* FIXME: Use 1536 - rounded ethernet frame size */ - init->MaxTransferSize = 2048; + init->max_xfer_size = 2048; dev->state = RNDIS_DEV_INITIALIZING; @@ -677,8 +677,8 @@ static int rndis_filter_init_device(struct rndis_device *dev) osd_waitevent_wait(request->waitevent); - init_complete = &request->response_msg.Message.InitializeComplete; - status = init_complete->Status; + init_complete = &request->response_msg.msg.init_complete; + status = init_complete->status; if (status == RNDIS_STATUS_SUCCESS) { dev->state = RNDIS_DEV_INITIALIZED; ret = 0; @@ -706,8 +706,8 @@ static void rndis_filter_halt_device(struct rndis_device *dev) goto Cleanup; /* Setup the rndis set */ - halt = &request->request_msg.Message.HaltRequest; - halt->RequestId = atomic_inc_return(&dev->new_req_id); + halt = &request->request_msg.msg.halt_req; + halt->req_id = atomic_inc_return(&dev->new_req_id); /* Ignore return since this msg is optional. */ rndis_filter_send_request(dev, request); @@ -875,13 +875,13 @@ static int rndis_filter_send(struct hv_device *dev, rndisMessage = &filterPacket->msg; rndisMessageSize = RNDIS_MESSAGE_SIZE(struct rndis_packet); - rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; - rndisMessage->MessageLength = pkt->total_data_buflen + + rndisMessage->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; + rndisMessage->msg_len = pkt->total_data_buflen + rndisMessageSize; - rndisPacket = &rndisMessage->Message.Packet; - rndisPacket->DataOffset = sizeof(struct rndis_packet); - rndisPacket->DataLength = pkt->total_data_buflen; + rndisPacket = &rndisMessage->msg.pkt; + rndisPacket->data_offset = sizeof(struct rndis_packet); + rndisPacket->data_len = pkt->total_data_buflen; pkt->is_data_pkt = true; pkt->page_buf[0].Pfn = virt_to_phys(rndisMessage) >> PAGE_SHIFT; -- cgit v1.2.3 From 7a39d8b82165462729d09066bddb395a19025acd Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 26 Nov 2010 08:57:31 +0100 Subject: firewire: ohci: Asynchronous Reception rewrite Move the AR DMA descriptors out of the buffer pages, and map the buffer pages linearly into the kernel's address space. This allows the driver to ignore any page boundaries in the DMA data and thus to avoid any copying around of packet payloads. This fixes the bug where S800 packets that are so big (> 4080 bytes) that they can be split over three pages were not handled correctly. Due to the changed algorithm, we can now use arbitrarily many buffer pages, which improves performance because the controller can more easily unload its DMA FIFO. Furthermore, using streaming DMA mappings should improve perfomance on architectures where coherent DMA mappings are not cacheable. Even on other architectures, the caching behaviour should be improved slightly because the CPU no longer writes to the buffer pages. v2: Detect the last filled buffer page by searching the descriptor's residual count value fields in order (like in the old code), instead of going backwards through the transfer status fields; it looks as if some controllers do not set the latter correctly. v3: Fix an old resume bug that would now make the handler run into a BUG_ON, and replace that check with more useful error handling. Increase the buffer size for better performance with non-TI chips. Signed-off-by: Clemens Ladisch Maxim Levitsky writes: Works almost perfectly. I can still see RCODE_BUSY errors sometimes, not very often though. 64K here eliminates these errors completely. This is most likely due to nouveau drivers and lowest perf level I use to lower card temperature. That increases latencies too much I think. Besides that the IO is just perfect. Tested-by: Maxim Levitsky Signed-off-by: Stefan Richter --- drivers/firewire/Kconfig | 2 +- drivers/firewire/ohci.c | 411 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 278 insertions(+), 135 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 40a222e19b2d..68f942cb30f2 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -19,7 +19,7 @@ config FIREWIRE config FIREWIRE_OHCI tristate "OHCI-1394 controllers" - depends on PCI && FIREWIRE + depends on PCI && FIREWIRE && MMU help Enable this driver if you have a FireWire controller based on the OHCI specification. For all practical purposes, this diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index e3c8b60bd86b..be0a01d8cef3 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -80,17 +81,23 @@ struct descriptor { #define COMMAND_PTR(regs) ((regs) + 12) #define CONTEXT_MATCH(regs) ((regs) + 16) -struct ar_buffer { - struct descriptor descriptor; - struct ar_buffer *next; - __le32 data[0]; -}; +#define AR_BUFFER_SIZE (32*1024) +#define AR_BUFFERS_MIN DIV_ROUND_UP(AR_BUFFER_SIZE, PAGE_SIZE) +/* we need at least two pages for proper list management */ +#define AR_BUFFERS (AR_BUFFERS_MIN >= 2 ? AR_BUFFERS_MIN : 2) + +#define MAX_ASYNC_PAYLOAD 4096 +#define MAX_AR_PACKET_SIZE (16 + MAX_ASYNC_PAYLOAD + 4) +#define AR_WRAPAROUND_PAGES DIV_ROUND_UP(MAX_AR_PACKET_SIZE, PAGE_SIZE) struct ar_context { struct fw_ohci *ohci; - struct ar_buffer *current_buffer; - struct ar_buffer *last_buffer; + struct page *pages[AR_BUFFERS]; + void *buffer; + struct descriptor *descriptors; + dma_addr_t descriptors_bus; void *pointer; + unsigned int last_buffer_index; u32 regs; struct tasklet_struct tasklet; }; @@ -594,59 +601,155 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr, return ret; } -static void ar_context_link_page(struct ar_context *ctx, - struct ar_buffer *ab, dma_addr_t ab_bus) +static inline dma_addr_t ar_buffer_bus(struct ar_context *ctx, unsigned int i) +{ + return page_private(ctx->pages[i]); +} + +static void ar_context_link_page(struct ar_context *ctx, unsigned int index) { - size_t offset; + struct descriptor *d; - ab->next = NULL; - memset(&ab->descriptor, 0, sizeof(ab->descriptor)); - ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | - DESCRIPTOR_STATUS | - DESCRIPTOR_BRANCH_ALWAYS); - offset = offsetof(struct ar_buffer, data); - ab->descriptor.req_count = cpu_to_le16(PAGE_SIZE - offset); - ab->descriptor.data_address = cpu_to_le32(ab_bus + offset); - ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset); - ab->descriptor.branch_address = 0; + d = &ctx->descriptors[index]; + d->branch_address &= cpu_to_le32(~0xf); + d->res_count = cpu_to_le16(PAGE_SIZE); + d->transfer_status = 0; wmb(); /* finish init of new descriptors before branch_address update */ - ctx->last_buffer->descriptor.branch_address = cpu_to_le32(ab_bus | 1); - ctx->last_buffer->next = ab; - ctx->last_buffer = ab; + d = &ctx->descriptors[ctx->last_buffer_index]; + d->branch_address |= cpu_to_le32(1); + + ctx->last_buffer_index = index; reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); flush_writes(ctx->ohci); } -static int ar_context_add_page(struct ar_context *ctx) +static void ar_context_release(struct ar_context *ctx) { - struct device *dev = ctx->ohci->card.device; - struct ar_buffer *ab; - dma_addr_t uninitialized_var(ab_bus); + unsigned int i; - ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC); - if (ab == NULL) - return -ENOMEM; + if (ctx->descriptors) + dma_free_coherent(ctx->ohci->card.device, + AR_BUFFERS * sizeof(struct descriptor), + ctx->descriptors, ctx->descriptors_bus); - ar_context_link_page(ctx, ab, ab_bus); + if (ctx->buffer) + vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES); - return 0; + for (i = 0; i < AR_BUFFERS; i++) + if (ctx->pages[i]) { + dma_unmap_page(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(ctx->pages[i]); + } } -static void ar_context_release(struct ar_context *ctx) +static void ar_context_abort(struct ar_context *ctx, const char *error_msg) { - struct ar_buffer *ab, *ab_next; - size_t offset; - dma_addr_t ab_bus; + if (reg_read(ctx->ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) { + reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + flush_writes(ctx->ohci); - for (ab = ctx->current_buffer; ab; ab = ab_next) { - ab_next = ab->next; - offset = offsetof(struct ar_buffer, data); - ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset; - dma_free_coherent(ctx->ohci->card.device, PAGE_SIZE, - ab, ab_bus); + fw_error("AR error: %s; DMA stopped\n", error_msg); } + /* FIXME: restart? */ +} + +static inline unsigned int ar_next_buffer_index(unsigned int index) +{ + return (index + 1) % AR_BUFFERS; +} + +static inline unsigned int ar_prev_buffer_index(unsigned int index) +{ + return (index - 1 + AR_BUFFERS) % AR_BUFFERS; +} + +static inline unsigned int ar_first_buffer_index(struct ar_context *ctx) +{ + return ar_next_buffer_index(ctx->last_buffer_index); +} + +/* + * We search for the buffer that contains the last AR packet DMA data written + * by the controller. + */ +static unsigned int ar_search_last_active_buffer(struct ar_context *ctx, + unsigned int *buffer_offset) +{ + unsigned int i, next_i, last = ctx->last_buffer_index; + __le16 res_count, next_res_count; + + i = ar_first_buffer_index(ctx); + res_count = ACCESS_ONCE(ctx->descriptors[i].res_count); + + /* A buffer that is not yet completely filled must be the last one. */ + while (i != last && res_count == 0) { + + /* Peek at the next descriptor. */ + next_i = ar_next_buffer_index(i); + rmb(); /* read descriptors in order */ + next_res_count = ACCESS_ONCE( + ctx->descriptors[next_i].res_count); + /* + * If the next descriptor is still empty, we must stop at this + * descriptor. + */ + if (next_res_count == cpu_to_le16(PAGE_SIZE)) { + /* + * The exception is when the DMA data for one packet is + * split over three buffers; in this case, the middle + * buffer's descriptor might be never updated by the + * controller and look still empty, and we have to peek + * at the third one. + */ + if (MAX_AR_PACKET_SIZE > PAGE_SIZE && i != last) { + next_i = ar_next_buffer_index(next_i); + rmb(); + next_res_count = ACCESS_ONCE( + ctx->descriptors[next_i].res_count); + if (next_res_count != cpu_to_le16(PAGE_SIZE)) + goto next_buffer_is_active; + } + + break; + } + +next_buffer_is_active: + i = next_i; + res_count = next_res_count; + } + + rmb(); /* read res_count before the DMA data */ + + *buffer_offset = PAGE_SIZE - le16_to_cpu(res_count); + if (*buffer_offset > PAGE_SIZE) { + *buffer_offset = 0; + ar_context_abort(ctx, "corrupted descriptor"); + } + + return i; +} + +static void ar_sync_buffers_for_cpu(struct ar_context *ctx, + unsigned int end_buffer_index, + unsigned int end_buffer_offset) +{ + unsigned int i; + + i = ar_first_buffer_index(ctx); + while (i != end_buffer_index) { + dma_sync_single_for_cpu(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + PAGE_SIZE, DMA_FROM_DEVICE); + i = ar_next_buffer_index(i); + } + if (end_buffer_offset > 0) + dma_sync_single_for_cpu(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + end_buffer_offset, DMA_FROM_DEVICE); } #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) @@ -689,6 +792,10 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.header[3] = cond_le32_to_cpu(buffer[3]); p.header_length = 16; p.payload_length = p.header[3] >> 16; + if (p.payload_length > MAX_ASYNC_PAYLOAD) { + ar_context_abort(ctx, "invalid packet length"); + return NULL; + } break; case TCODE_WRITE_RESPONSE: @@ -699,9 +806,8 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) break; default: - /* FIXME: Stop context, discard everything, and restart? */ - p.header_length = 0; - p.payload_length = 0; + ar_context_abort(ctx, "invalid tcode"); + return NULL; } p.payload = (void *) buffer + p.header_length; @@ -751,121 +857,152 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) return buffer + length + 1; } +static void *handle_ar_packets(struct ar_context *ctx, void *p, void *end) +{ + void *next; + + while (p < end) { + next = handle_ar_packet(ctx, p); + if (!next) + return p; + p = next; + } + + return p; +} + +static void ar_recycle_buffers(struct ar_context *ctx, unsigned int end_buffer) +{ + unsigned int i; + + i = ar_first_buffer_index(ctx); + while (i != end_buffer) { + dma_sync_single_for_device(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + PAGE_SIZE, DMA_FROM_DEVICE); + ar_context_link_page(ctx, i); + i = ar_next_buffer_index(i); + } +} + static void ar_context_tasklet(unsigned long data) { struct ar_context *ctx = (struct ar_context *)data; - struct ar_buffer *ab; - struct descriptor *d; - void *buffer, *end; - __le16 res_count; + unsigned int end_buffer_index, end_buffer_offset; + void *p, *end; - ab = ctx->current_buffer; - d = &ab->descriptor; + p = ctx->pointer; + if (!p) + return; - res_count = ACCESS_ONCE(d->res_count); - if (res_count == 0) { - size_t size, size2, rest, pktsize, size3, offset; - dma_addr_t start_bus; - void *start; + end_buffer_index = ar_search_last_active_buffer(ctx, + &end_buffer_offset); + ar_sync_buffers_for_cpu(ctx, end_buffer_index, end_buffer_offset); + end = ctx->buffer + end_buffer_index * PAGE_SIZE + end_buffer_offset; + if (end_buffer_index < ar_first_buffer_index(ctx)) { /* - * This descriptor is finished and we may have a - * packet split across this and the next buffer. We - * reuse the page for reassembling the split packet. + * The filled part of the overall buffer wraps around; handle + * all packets up to the buffer end here. If the last packet + * wraps around, its tail will be visible after the buffer end + * because the buffer start pages are mapped there again. */ + void *buffer_end = ctx->buffer + AR_BUFFERS * PAGE_SIZE; + p = handle_ar_packets(ctx, p, buffer_end); + if (p < buffer_end) + goto error; + /* adjust p to point back into the actual buffer */ + p -= AR_BUFFERS * PAGE_SIZE; + } - offset = offsetof(struct ar_buffer, data); - start = ab; - start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; - buffer = ab->data; - - ab = ab->next; - d = &ab->descriptor; - size = start + PAGE_SIZE - ctx->pointer; - /* valid buffer data in the next page */ - rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); - /* what actually fits in this page */ - size2 = min(rest, (size_t)PAGE_SIZE - offset - size); - memmove(buffer, ctx->pointer, size); - memcpy(buffer + size, ab->data, size2); - - while (size > 0) { - void *next = handle_ar_packet(ctx, buffer); - pktsize = next - buffer; - if (pktsize >= size) { - /* - * We have handled all the data that was - * originally in this page, so we can now - * continue in the next page. - */ - buffer = next; - break; - } - /* move the next packet to the start of the buffer */ - memmove(buffer, next, size + size2 - pktsize); - size -= pktsize; - /* fill up this page again */ - size3 = min(rest - size2, - (size_t)PAGE_SIZE - offset - size - size2); - memcpy(buffer + size + size2, - (void *) ab->data + size2, size3); - size2 += size3; - } - - if (rest > 0) { - /* handle the packets that are fully in the next page */ - buffer = (void *) ab->data + - (buffer - (start + offset + size)); - end = (void *) ab->data + rest; + p = handle_ar_packets(ctx, p, end); + if (p != end) { + if (p > end) + ar_context_abort(ctx, "inconsistent descriptor"); + goto error; + } - while (buffer < end) - buffer = handle_ar_packet(ctx, buffer); + ctx->pointer = p; + ar_recycle_buffers(ctx, end_buffer_index); - ctx->current_buffer = ab; - ctx->pointer = end; + return; - ar_context_link_page(ctx, start, start_bus); - } else { - ctx->pointer = start + PAGE_SIZE; - } - } else { - buffer = ctx->pointer; - ctx->pointer = end = - (void *) ab + PAGE_SIZE - le16_to_cpu(res_count); - - while (buffer < end) - buffer = handle_ar_packet(ctx, buffer); - } +error: + ctx->pointer = NULL; } static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs) { - struct ar_buffer ab; + unsigned int i; + dma_addr_t dma_addr; + struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES]; + struct descriptor *d; ctx->regs = regs; ctx->ohci = ohci; - ctx->last_buffer = &ab; tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx); - ar_context_add_page(ctx); - ar_context_add_page(ctx); - ctx->current_buffer = ab.next; - ctx->pointer = ctx->current_buffer->data; + for (i = 0; i < AR_BUFFERS; i++) { + ctx->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32); + if (!ctx->pages[i]) + goto out_of_memory; + dma_addr = dma_map_page(ohci->card.device, ctx->pages[i], + 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(ohci->card.device, dma_addr)) { + __free_page(ctx->pages[i]); + ctx->pages[i] = NULL; + goto out_of_memory; + } + set_page_private(ctx->pages[i], dma_addr); + } + + for (i = 0; i < AR_BUFFERS; i++) + pages[i] = ctx->pages[i]; + for (i = 0; i < AR_WRAPAROUND_PAGES; i++) + pages[AR_BUFFERS + i] = ctx->pages[i]; + ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES, + -1, PAGE_KERNEL_RO); + if (!ctx->buffer) + goto out_of_memory; + + ctx->descriptors = + dma_alloc_coherent(ohci->card.device, + AR_BUFFERS * sizeof(struct descriptor), + &ctx->descriptors_bus, + GFP_KERNEL); + if (!ctx->descriptors) + goto out_of_memory; + + for (i = 0; i < AR_BUFFERS; i++) { + d = &ctx->descriptors[i]; + d->req_count = cpu_to_le16(PAGE_SIZE); + d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | + DESCRIPTOR_STATUS | + DESCRIPTOR_BRANCH_ALWAYS); + d->data_address = cpu_to_le32(ar_buffer_bus(ctx, i)); + d->branch_address = cpu_to_le32(ctx->descriptors_bus + + ar_next_buffer_index(i) * sizeof(struct descriptor)); + } return 0; + +out_of_memory: + ar_context_release(ctx); + + return -ENOMEM; } static void ar_context_run(struct ar_context *ctx) { - struct ar_buffer *ab = ctx->current_buffer; - dma_addr_t ab_bus; - size_t offset; + unsigned int i; + + for (i = 0; i < AR_BUFFERS; i++) + ar_context_link_page(ctx, i); - offset = offsetof(struct ar_buffer, data); - ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset; + ctx->pointer = ctx->buffer; - reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab_bus | 1); + reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1); reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); flush_writes(ctx->ohci); } @@ -2955,11 +3092,15 @@ static int __devinit pci_probe(struct pci_dev *dev, if (param_quirks) ohci->quirks = param_quirks; - ar_context_init(&ohci->ar_request_ctx, ohci, - OHCI1394_AsReqRcvContextControlSet); + err = ar_context_init(&ohci->ar_request_ctx, ohci, + OHCI1394_AsReqRcvContextControlSet); + if (err < 0) + goto fail_iounmap; - ar_context_init(&ohci->ar_response_ctx, ohci, - OHCI1394_AsRspRcvContextControlSet); + err = ar_context_init(&ohci->ar_response_ctx, ohci, + OHCI1394_AsRspRcvContextControlSet); + if (err < 0) + goto fail_arreq_ctx; context_init(&ohci->at_request_ctx, ohci, OHCI1394_AsReqTrContextControlSet, handle_at_packet); @@ -3024,7 +3165,9 @@ static int __devinit pci_probe(struct pci_dev *dev, context_release(&ohci->at_response_ctx); context_release(&ohci->at_request_ctx); ar_context_release(&ohci->ar_response_ctx); + fail_arreq_ctx: ar_context_release(&ohci->ar_request_ctx); + fail_iounmap: pci_iounmap(dev, ohci->registers); fail_iomem: pci_release_region(dev, 0); -- cgit v1.2.3 From c088ab30ebf184afae01d919c77cebcfdce39df3 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 30 Nov 2010 08:24:01 +0100 Subject: firewire: ohci: fix AT context initialization error handling Add proper error handling for the context_init() calls. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index be0a01d8cef3..3775364f1b51 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3102,11 +3102,15 @@ static int __devinit pci_probe(struct pci_dev *dev, if (err < 0) goto fail_arreq_ctx; - context_init(&ohci->at_request_ctx, ohci, - OHCI1394_AsReqTrContextControlSet, handle_at_packet); + err = context_init(&ohci->at_request_ctx, ohci, + OHCI1394_AsReqTrContextControlSet, handle_at_packet); + if (err < 0) + goto fail_arrsp_ctx; - context_init(&ohci->at_response_ctx, ohci, - OHCI1394_AsRspTrContextControlSet, handle_at_packet); + err = context_init(&ohci->at_response_ctx, ohci, + OHCI1394_AsRspTrContextControlSet, handle_at_packet); + if (err < 0) + goto fail_atreq_ctx; reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); ohci->ir_context_channels = ~0ULL; @@ -3163,7 +3167,9 @@ static int __devinit pci_probe(struct pci_dev *dev, kfree(ohci->ir_context_list); kfree(ohci->it_context_list); context_release(&ohci->at_response_ctx); + fail_atreq_ctx: context_release(&ohci->at_request_ctx); + fail_arrsp_ctx: ar_context_release(&ohci->ar_response_ctx); fail_arreq_ctx: ar_context_release(&ohci->ar_request_ctx); -- cgit v1.2.3 From e597e9898abe45beff4696159c7fe5c96f53e581 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 30 Nov 2010 08:24:19 +0100 Subject: firewire: ohci: flush MMIO writes in the interrupt handler Make sure that interrupt event clear bit writes are executed before the interrupt handler returns. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 3775364f1b51..276324d741df 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1856,7 +1856,8 @@ static irqreturn_t irq_handler(int irq, void *data) spin_lock(&ohci->lock); update_bus_time(ohci); spin_unlock(&ohci->lock); - } + } else + flush_writes(ohci); return IRQ_HANDLED; } -- cgit v1.2.3 From 8327b37b18addfc6f8cf41a2f1a4490b656377b9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 30 Nov 2010 08:24:32 +0100 Subject: firewire: ohci: properly clear posted write errors To remove the error information from the controller's queue and to allow more posted writes, the driver has to read the failed posted write address before clearing the postedWriteErr interrupt bit. Signed-off-by: Clemens Ladisch (Stefan R:) The spec is somewhat fuzzy about the actual requirements. To err on the safe side, let's do these two read accesses. Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 276324d741df..0031ec6e1f00 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1790,8 +1790,12 @@ static irqreturn_t irq_handler(int irq, void *data) if (!event || !~event) return IRQ_NONE; - /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */ - reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); + /* + * busReset and postedWriteErr must not be cleared yet + * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1) + */ + reg_write(ohci, OHCI1394_IntEventClear, + event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr)); log_irqs(event); if (event & OHCI1394_selfIDComplete) @@ -1831,8 +1835,13 @@ static irqreturn_t irq_handler(int irq, void *data) fw_error("Register access failure - " "please notify linux1394-devel@lists.sf.net\n"); - if (unlikely(event & OHCI1394_postedWriteErr)) + if (unlikely(event & OHCI1394_postedWriteErr)) { + reg_read(ohci, OHCI1394_PostedWriteAddressHi); + reg_read(ohci, OHCI1394_PostedWriteAddressLo); + reg_write(ohci, OHCI1394_IntEventClear, + OHCI1394_postedWriteErr); fw_error("PCI posted write error\n"); + } if (unlikely(event & OHCI1394_cycleTooLong)) { if (printk_ratelimit()) -- cgit v1.2.3 From 5b06db166c4d38638980283505259fa165d4f369 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 30 Nov 2010 08:24:47 +0100 Subject: firewire: make PHY packet header format consistent Change the header of PHY packets to be sent to include a pseudo transaction code. This makes the header consistent with that of received PHY packets, and allows at_context_queue_packet() and log_ar_at_event() to see the packet type directly instead of having to deduce it from the header length or even from the header contents. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/core-cdev.c | 7 +++--- drivers/firewire/core-transaction.c | 7 +++--- drivers/firewire/core.h | 4 +++- drivers/firewire/ohci.c | 44 ++++++++++++++++++------------------- 4 files changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 14bb7b7b5dd7..48ae712e2101 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1501,9 +1501,10 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) e->client = client; e->p.speed = SCODE_100; e->p.generation = a->generation; - e->p.header[0] = a->data[0]; - e->p.header[1] = a->data[1]; - e->p.header_length = 8; + e->p.header[0] = TCODE_LINK_INTERNAL << 4; + e->p.header[1] = a->data[0]; + e->p.header[2] = a->data[1]; + e->p.header_length = 12; e->p.callback = outbound_phy_packet_callback; e->phy_packet.closure = a->closure; e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT; diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index ad864d8cd5e4..9e81cc54abd2 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -423,7 +423,8 @@ static void transmit_phy_packet_callback(struct fw_packet *packet, } static struct fw_packet phy_config_packet = { - .header_length = 8, + .header_length = 12, + .header[0] = TCODE_LINK_INTERNAL << 4, .payload_length = 0, .speed = SCODE_100, .callback = transmit_phy_packet_callback, @@ -451,8 +452,8 @@ void fw_send_phy_config(struct fw_card *card, mutex_lock(&phy_config_mutex); - phy_config_packet.header[0] = data; - phy_config_packet.header[1] = ~data; + phy_config_packet.header[1] = data; + phy_config_packet.header[2] = ~data; phy_config_packet.generation = generation; INIT_COMPLETION(phy_config_done); diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index e6239f971be6..f8dfcf1c6cbe 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -215,9 +215,11 @@ static inline bool is_next_generation(int new_generation, int old_generation) /* -transaction */ +#define TCODE_LINK_INTERNAL 0xe + #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) -#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == 0xe) +#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == TCODE_LINK_INTERNAL) #define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) #define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) #define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 0031ec6e1f00..29259f3a30bb 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -418,10 +418,6 @@ static const char *tcodes[] = { [0xc] = "-reserved-", [0xd] = "-reserved-", [0xe] = "link internal", [0xf] = "-reserved-", }; -static const char *phys[] = { - [0x0] = "phy config packet", [0x1] = "link-on packet", - [0x2] = "self-id packet", [0x3] = "-reserved-", -}; static void log_ar_at_event(char dir, int speed, u32 *header, int evt) { @@ -440,12 +436,6 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) return; } - if (header[0] == ~header[1]) { - fw_notify("A%c %s, %s, %08x\n", - dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]); - return; - } - switch (tcode) { case 0x0: case 0x6: case 0x8: snprintf(specific, sizeof(specific), " = %08x", @@ -460,9 +450,13 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) } switch (tcode) { - case 0xe: case 0xa: + case 0xa: fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]); break; + case 0xe: + fw_notify("A%c %s, PHY %08x %08x\n", + dir, evts[evt], header[1], header[2]); + break; case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: fw_notify("A%c spd %x tl %02x, " "%04x -> %04x, %s, " @@ -1250,21 +1244,27 @@ static int at_context_queue_packet(struct context *ctx, /* * The DMA format for asyncronous link packets is different * from the IEEE1394 layout, so shift the fields around - * accordingly. If header_length is 8, it's a PHY packet, to - * which we need to prepend an extra quadlet. + * accordingly. */ + tcode = (packet->header[0] >> 4) & 0x0f; header = (__le32 *) &d[1]; - switch (packet->header_length) { - case 16: - case 12: + switch (tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_WRITE_RESPONSE: + case TCODE_READ_QUADLET_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_READ_QUADLET_RESPONSE: + case TCODE_READ_BLOCK_RESPONSE: + case TCODE_LOCK_REQUEST: + case TCODE_LOCK_RESPONSE: header[0] = cpu_to_le32((packet->header[0] & 0xffff) | (packet->speed << 16)); header[1] = cpu_to_le32((packet->header[1] & 0xffff) | (packet->header[0] & 0xffff0000)); header[2] = cpu_to_le32(packet->header[2]); - tcode = (packet->header[0] >> 4) & 0x0f; if (TCODE_IS_BLOCK_PACKET(tcode)) header[3] = cpu_to_le32(packet->header[3]); else @@ -1273,18 +1273,18 @@ static int at_context_queue_packet(struct context *ctx, d[0].req_count = cpu_to_le16(packet->header_length); break; - case 8: + case TCODE_LINK_INTERNAL: header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) | (packet->speed << 16)); - header[1] = cpu_to_le32(packet->header[0]); - header[2] = cpu_to_le32(packet->header[1]); + header[1] = cpu_to_le32(packet->header[1]); + header[2] = cpu_to_le32(packet->header[2]); d[0].req_count = cpu_to_le16(12); - if (is_ping_packet(packet->header)) + if (is_ping_packet(&packet->header[1])) d[0].control |= cpu_to_le16(DESCRIPTOR_PING); break; - case 4: + case TCODE_STREAM_DATA: header[0] = cpu_to_le32((packet->header[0] & 0xffff) | (packet->speed << 16)); header[1] = cpu_to_le32(packet->header[0] & 0xffff0000); -- cgit v1.2.3 From 2dd5bed59356e03610bebe1a37c397788df50b9b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 30 Nov 2010 08:25:05 +0100 Subject: firewire: ohci: optimize iso context checks in the interrupt handler When the isochRx/isochTx bit is clear, we do not need to read the corresponding iso interrupt event register. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 29259f3a30bb..01b3bc9154a6 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1813,22 +1813,28 @@ static irqreturn_t irq_handler(int irq, void *data) if (event & OHCI1394_respTxComplete) tasklet_schedule(&ohci->at_response_ctx.tasklet); - iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event); - - while (iso_event) { - i = ffs(iso_event) - 1; - tasklet_schedule(&ohci->ir_context_list[i].context.tasklet); - iso_event &= ~(1 << i); + if (event & OHCI1394_isochRx) { + iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event); + + while (iso_event) { + i = ffs(iso_event) - 1; + tasklet_schedule( + &ohci->ir_context_list[i].context.tasklet); + iso_event &= ~(1 << i); + } } - iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event); + if (event & OHCI1394_isochTx) { + iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event); - while (iso_event) { - i = ffs(iso_event) - 1; - tasklet_schedule(&ohci->it_context_list[i].context.tasklet); - iso_event &= ~(1 << i); + while (iso_event) { + i = ffs(iso_event) - 1; + tasklet_schedule( + &ohci->it_context_list[i].context.tasklet); + iso_event &= ~(1 << i); + } } if (unlikely(event & OHCI1394_regAccessFail)) -- cgit v1.2.3 From ec766a7970126f99665992c0b0b10bd60a4d6208 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 30 Nov 2010 08:25:17 +0100 Subject: firewire: ohci: use common buffer for self IDs and AR descriptors The buffers used for the selfIDs packets and the AR request and response descriptors end up using three pages because dma_alloc_coherent() allocates at least one page per call. However, these data structures would all fit into 4 KB, so we can save space by using a common buffer for them. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 66 +++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 01b3bc9154a6..eb7b591e1c1b 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -193,6 +193,9 @@ struct fw_ohci { struct mutex phy_reg_mutex; + void *misc_buffer; + dma_addr_t misc_buffer_bus; + struct ar_context ar_request_ctx; struct ar_context ar_response_ctx; struct context at_request_ctx; @@ -623,11 +626,6 @@ static void ar_context_release(struct ar_context *ctx) { unsigned int i; - if (ctx->descriptors) - dma_free_coherent(ctx->ohci->card.device, - AR_BUFFERS * sizeof(struct descriptor), - ctx->descriptors, ctx->descriptors_bus); - if (ctx->buffer) vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES); @@ -925,8 +923,8 @@ error: ctx->pointer = NULL; } -static int ar_context_init(struct ar_context *ctx, - struct fw_ohci *ohci, u32 regs) +static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, + unsigned int descriptors_offset, u32 regs) { unsigned int i; dma_addr_t dma_addr; @@ -960,13 +958,8 @@ static int ar_context_init(struct ar_context *ctx, if (!ctx->buffer) goto out_of_memory; - ctx->descriptors = - dma_alloc_coherent(ohci->card.device, - AR_BUFFERS * sizeof(struct descriptor), - &ctx->descriptors_bus, - GFP_KERNEL); - if (!ctx->descriptors) - goto out_of_memory; + ctx->descriptors = ohci->misc_buffer + descriptors_offset; + ctx->descriptors_bus = ohci->misc_buffer_bus + descriptors_offset; for (i = 0; i < AR_BUFFERS; i++) { d = &ctx->descriptors[i]; @@ -3108,12 +3101,28 @@ static int __devinit pci_probe(struct pci_dev *dev, if (param_quirks) ohci->quirks = param_quirks; - err = ar_context_init(&ohci->ar_request_ctx, ohci, + /* + * Because dma_alloc_coherent() allocates at least one page, + * we save space by using a common buffer for the AR request/ + * response descriptors and the self IDs buffer. + */ + BUILD_BUG_ON(AR_BUFFERS * sizeof(struct descriptor) > PAGE_SIZE/4); + BUILD_BUG_ON(SELF_ID_BUF_SIZE > PAGE_SIZE/2); + ohci->misc_buffer = dma_alloc_coherent(ohci->card.device, + PAGE_SIZE, + &ohci->misc_buffer_bus, + GFP_KERNEL); + if (!ohci->misc_buffer) { + err = -ENOMEM; + goto fail_iounmap; + } + + err = ar_context_init(&ohci->ar_request_ctx, ohci, 0, OHCI1394_AsReqRcvContextControlSet); if (err < 0) - goto fail_iounmap; + goto fail_misc_buf; - err = ar_context_init(&ohci->ar_response_ctx, ohci, + err = ar_context_init(&ohci->ar_response_ctx, ohci, PAGE_SIZE/4, OHCI1394_AsRspRcvContextControlSet); if (err < 0) goto fail_arreq_ctx; @@ -3148,15 +3157,8 @@ static int __devinit pci_probe(struct pci_dev *dev, goto fail_contexts; } - /* self-id dma buffer allocation */ - ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device, - SELF_ID_BUF_SIZE, - &ohci->self_id_bus, - GFP_KERNEL); - if (ohci->self_id_cpu == NULL) { - err = -ENOMEM; - goto fail_contexts; - } + ohci->self_id_cpu = ohci->misc_buffer + PAGE_SIZE/2; + ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2; bus_options = reg_read(ohci, OHCI1394_BusOptions); max_receive = (bus_options >> 12) & 0xf; @@ -3166,7 +3168,7 @@ static int __devinit pci_probe(struct pci_dev *dev, err = fw_card_add(&ohci->card, max_receive, link_speed, guid); if (err) - goto fail_self_id; + goto fail_contexts; version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; fw_notify("Added fw-ohci device %s, OHCI v%x.%x, " @@ -3176,9 +3178,6 @@ static int __devinit pci_probe(struct pci_dev *dev, return 0; - fail_self_id: - dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, - ohci->self_id_cpu, ohci->self_id_bus); fail_contexts: kfree(ohci->ir_context_list); kfree(ohci->it_context_list); @@ -3189,6 +3188,9 @@ static int __devinit pci_probe(struct pci_dev *dev, ar_context_release(&ohci->ar_response_ctx); fail_arreq_ctx: ar_context_release(&ohci->ar_request_ctx); + fail_misc_buf: + dma_free_coherent(ohci->card.device, PAGE_SIZE, + ohci->misc_buffer, ohci->misc_buffer_bus); fail_iounmap: pci_iounmap(dev, ohci->registers); fail_iomem: @@ -3228,10 +3230,10 @@ static void pci_remove(struct pci_dev *dev) if (ohci->config_rom) dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, ohci->config_rom, ohci->config_rom_bus); - dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, - ohci->self_id_cpu, ohci->self_id_bus); ar_context_release(&ohci->ar_request_ctx); ar_context_release(&ohci->ar_response_ctx); + dma_free_coherent(ohci->card.device, PAGE_SIZE, + ohci->misc_buffer, ohci->misc_buffer_bus); context_release(&ohci->at_request_ctx); context_release(&ohci->at_response_ctx); kfree(ohci->it_context_list); -- cgit v1.2.3 From 8662b6b029636c35e5876e184d90daf6b0072667 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 29 Nov 2010 04:09:49 +0200 Subject: firewire: ohci: restore GUID on resume. Some lousy BIOSes, e.g. my Aspire 5720 BIOS forget to restore the GUID register on resume from RAM. Fix that by setting it to the last value that was read from it. Signed-off-by: Maxim Levitsky Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index eb7b591e1c1b..3a908038ff62 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3284,6 +3284,13 @@ static int pci_resume(struct pci_dev *dev) return err; } + /* Some systems don't setup GUID register on resume from ram */ + if (!reg_read(ohci, OHCI1394_GUIDLo) && + !reg_read(ohci, OHCI1394_GUIDHi)) { + reg_write(ohci, OHCI1394_GUIDLo, (u32)ohci->card.guid); + reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32)); + } + return ohci_enable(&ohci->card, NULL, 0); } #endif -- cgit v1.2.3 From dd23736e092035b71df1117482b71fdfb5634239 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 29 Nov 2010 04:09:50 +0200 Subject: firewire: ohci: restart iso DMA contexts on resume from low power mode Restore iso channels DMA so that iso channels could continue to work after resume from RAM/disk. Signed-off-by: Maxim Levitsky Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 54 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 3a908038ff62..5e5d5d3d43d1 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -18,6 +18,7 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include #include @@ -153,6 +154,7 @@ struct context { descriptor_callback_t callback; struct tasklet_struct tasklet; + bool active; }; #define IT_HEADER_SY(v) ((v) << 0) @@ -168,6 +170,9 @@ struct iso_context { int excess_bytes; void *header; size_t header_length; + + u8 sync; + u8 tags; }; #define CONFIG_ROM_SIZE 1024 @@ -184,7 +189,8 @@ struct fw_ohci { u32 bus_time; bool is_root; bool csr_state_setclear_abdicate; - + int n_ir; + int n_it; /* * Spinlock for accessing fw_ohci data. Never call out of * this driver with this lock held. @@ -1161,6 +1167,7 @@ static struct descriptor *context_get_descriptors(struct context *ctx, static void context_run(struct context *ctx, u32 extra) { struct fw_ohci *ohci = ctx->ohci; + ctx->active = true; reg_write(ohci, COMMAND_PTR(ctx->regs), le32_to_cpu(ctx->last->branch_address)); @@ -1192,6 +1199,7 @@ static void context_stop(struct context *ctx) u32 reg; int i; + ctx->active = false; reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); flush_writes(ctx->ohci); @@ -2641,6 +2649,10 @@ static int ohci_start_iso(struct fw_iso_context *base, reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); context_run(&ctx->context, control); + + ctx->sync = sync; + ctx->tags = tags; + break; } @@ -2738,6 +2750,26 @@ static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels) return ret; } +#ifdef CONFIG_PM +static void ohci_resume_iso_dma(struct fw_ohci *ohci) +{ + int i; + struct iso_context *ctx; + + for (i = 0 ; i < ohci->n_ir ; i++) { + ctx = &ohci->ir_context_list[i]; + if (ctx->context.active) + ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); + } + + for (i = 0 ; i < ohci->n_it ; i++) { + ctx = &ohci->it_context_list[i]; + if (ctx->context.active) + ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); + } +} +#endif + static int queue_iso_transmit(struct iso_context *ctx, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, @@ -3047,7 +3079,7 @@ static int __devinit pci_probe(struct pci_dev *dev, struct fw_ohci *ohci; u32 bus_options, max_receive, link_speed, version; u64 guid; - int i, err, n_ir, n_it; + int i, err; size_t size; ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); @@ -3141,15 +3173,15 @@ static int __devinit pci_probe(struct pci_dev *dev, ohci->ir_context_channels = ~0ULL; ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); - n_ir = hweight32(ohci->ir_context_mask); - size = sizeof(struct iso_context) * n_ir; + ohci->n_ir = hweight32(ohci->ir_context_mask); + size = sizeof(struct iso_context) * ohci->n_ir; ohci->ir_context_list = kzalloc(size, GFP_KERNEL); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); - n_it = hweight32(ohci->it_context_mask); - size = sizeof(struct iso_context) * n_it; + ohci->n_it = hweight32(ohci->it_context_mask); + size = sizeof(struct iso_context) * ohci->n_it; ohci->it_context_list = kzalloc(size, GFP_KERNEL); if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) { @@ -3174,7 +3206,7 @@ static int __devinit pci_probe(struct pci_dev *dev, fw_notify("Added fw-ohci device %s, OHCI v%x.%x, " "%d IR + %d IT contexts, quirks 0x%x\n", dev_name(&dev->dev), version >> 16, version & 0xff, - n_ir, n_it, ohci->quirks); + ohci->n_ir, ohci->n_it, ohci->quirks); return 0; @@ -3291,7 +3323,13 @@ static int pci_resume(struct pci_dev *dev) reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32)); } - return ohci_enable(&ohci->card, NULL, 0); + err = ohci_enable(&ohci->card, NULL, 0); + + if (err) + return err; + + ohci_resume_iso_dma(ohci); + return 0; } #endif -- cgit v1.2.3 From c4d6fd40df38eb4c187565d48807f5f902481ba8 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 29 Nov 2010 04:09:53 +0200 Subject: firewire: net: ratelimit error messages Unfortunately its easy to trigger such error messages by removing the cable while sending streams of data over the link. Such errors are normal, and therefore this patch stops firewire-net from flooding the kernel log with these errors, by combining series of same errors together. Signed-off-by: Maxim Levitsky (Stefan R:) Eventually we should remove this logging when firewire-net and related firewire-ohci facilities have been stabilized. Signed-off-by: Stefan Richter --- drivers/firewire/net.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 1a467a91fb0b..ea31e3084d67 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -996,15 +996,23 @@ static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask) static void fwnet_write_complete(struct fw_card *card, int rcode, void *payload, size_t length, void *data) { - struct fwnet_packet_task *ptask; - - ptask = data; + struct fwnet_packet_task *ptask = data; + static unsigned long j; + static int last_rcode, errors_skipped; if (rcode == RCODE_COMPLETE) { fwnet_transmit_packet_done(ptask); } else { - fw_error("fwnet_write_complete: failed: %x\n", rcode); fwnet_transmit_packet_failed(ptask); + + if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) { + fw_error("fwnet_write_complete: " + "failed: %x (skipped %d)\n", rcode, errors_skipped); + + errors_skipped = 0; + last_rcode = rcode; + } else + errors_skipped++; } } -- cgit v1.2.3 From 96c8f06a0fb359a9a89701a7afab6d837e466ab0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Dec 2010 22:45:48 +0100 Subject: rtc: Namespace fixup rtctimer_* is already occupied by sound/core/rtctimer.c. Instead of fiddling with that, rename the new functions to rtc_timer_* which reads nicer anyway. Signed-off-by: Thomas Gleixner Cc: John Stultz --- drivers/rtc/class.c | 6 +++--- drivers/rtc/interface.c | 42 +++++++++++++++++++++--------------------- include/linux/rtc.h | 12 ++++++------ 3 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 95d2b82762d6..3243832a17cd 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -155,11 +155,11 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, /* Init timerqueue */ timerqueue_init_head(&rtc->timerqueue); - INIT_WORK(&rtc->irqwork, rtctimer_do_work); + INIT_WORK(&rtc->irqwork, rtc_timer_do_work); /* Init aie timer */ - rtctimer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc); + rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc); /* Init uie timer */ - rtctimer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc); + rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc); /* Init pie timer */ hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); rtc->pie_timer.function = rtc_pie_update_irq; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index c81c50b497b7..90384b9f6b2c 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -174,14 +174,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) if (err) return err; if (rtc->aie_timer.enabled) { - rtctimer_remove(rtc, &rtc->aie_timer); + rtc_timer_remove(rtc, &rtc->aie_timer); rtc->aie_timer.enabled = 0; } rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); rtc->aie_timer.period = ktime_set(0, 0); if (alarm->enabled) { rtc->aie_timer.enabled = 1; - rtctimer_enqueue(rtc, &rtc->aie_timer); + rtc_timer_enqueue(rtc, &rtc->aie_timer); } mutex_unlock(&rtc->ops_lock); return 0; @@ -197,9 +197,9 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (rtc->aie_timer.enabled != enabled) { if (enabled) { rtc->aie_timer.enabled = 1; - rtctimer_enqueue(rtc, &rtc->aie_timer); + rtc_timer_enqueue(rtc, &rtc->aie_timer); } else { - rtctimer_remove(rtc, &rtc->aie_timer); + rtc_timer_remove(rtc, &rtc->aie_timer); rtc->aie_timer.enabled = 0; } } @@ -236,9 +236,9 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); rtc->uie_rtctimer.period = ktime_set(1, 0); rtc->uie_rtctimer.enabled = 1; - rtctimer_enqueue(rtc, &rtc->uie_rtctimer); + rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); } else { - rtctimer_remove(rtc, &rtc->uie_rtctimer); + rtc_timer_remove(rtc, &rtc->uie_rtctimer); rtc->uie_rtctimer.enabled = 0; } @@ -481,7 +481,7 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) EXPORT_SYMBOL_GPL(rtc_irq_set_freq); /** - * rtctimer_enqueue - Adds a rtc_timer to the rtc_device timerqueue + * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue * @rtc rtc device * @timer timer being added. * @@ -490,7 +490,7 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq); * * Must hold ops_lock for proper serialization of timerqueue */ -void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) +void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) { timerqueue_add(&rtc->timerqueue, &timer->node); if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { @@ -505,7 +505,7 @@ void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) } /** - * rtctimer_remove - Removes a rtc_timer from the rtc_device timerqueue + * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device * @timer timer being removed. * @@ -514,7 +514,7 @@ void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) * * Must hold ops_lock for proper serialization of timerqueue */ -void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer) +void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) { struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); timerqueue_del(&rtc->timerqueue, &timer->node); @@ -534,7 +534,7 @@ void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer) } /** - * rtctimer_do_work - Expires rtc timers + * rtc_timer_do_work - Expires rtc timers * @rtc rtc device * @timer timer being removed. * @@ -543,7 +543,7 @@ void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer) * * Serializes access to timerqueue via ops_lock mutex */ -void rtctimer_do_work(struct work_struct *work) +void rtc_timer_do_work(struct work_struct *work) { struct rtc_timer *timer; struct timerqueue_node *next; @@ -592,14 +592,14 @@ again: } -/* rtctimer_init - Initializes an rtc_timer +/* rtc_timer_init - Initializes an rtc_timer * @timer: timer to be intiialized * @f: function pointer to be called when timer fires * @data: private data passed to function pointer * * Kernel interface to initializing an rtc_timer. */ -void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) +void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) { timerqueue_init(&timer->node); timer->enabled = 0; @@ -607,7 +607,7 @@ void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) timer->task.private_data = data; } -/* rtctimer_start - Sets an rtc_timer to fire in the future +/* rtc_timer_start - Sets an rtc_timer to fire in the future * @ rtc: rtc device to be used * @ timer: timer being set * @ expires: time at which to expire the timer @@ -615,36 +615,36 @@ void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) * * Kernel interface to set an rtc_timer */ -int rtctimer_start(struct rtc_device *rtc, struct rtc_timer* timer, +int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, ktime_t expires, ktime_t period) { int ret = 0; mutex_lock(&rtc->ops_lock); if (timer->enabled) - rtctimer_remove(rtc, timer); + rtc_timer_remove(rtc, timer); timer->node.expires = expires; timer->period = period; timer->enabled = 1; - rtctimer_enqueue(rtc, timer); + rtc_timer_enqueue(rtc, timer); mutex_unlock(&rtc->ops_lock); return ret; } -/* rtctimer_cancel - Stops an rtc_timer +/* rtc_timer_cancel - Stops an rtc_timer * @ rtc: rtc device to be used * @ timer: timer being set * * Kernel interface to cancel an rtc_timer */ -int rtctimer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) +int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) { int ret = 0; mutex_lock(&rtc->ops_lock); if (timer->enabled) - rtctimer_remove(rtc, timer); + rtc_timer_remove(rtc, timer); timer->enabled = 0; mutex_unlock(&rtc->ops_lock); return ret; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 44e18a2523a3..3c995b4d742c 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -246,13 +246,13 @@ int rtc_register(rtc_task_t *task); int rtc_unregister(rtc_task_t *task); int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); -void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer); -void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer); -void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data); -int rtctimer_start(struct rtc_device *rtc, struct rtc_timer* timer, +void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer); +void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer); +void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data); +int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, ktime_t expires, ktime_t period); -int rtctimer_cancel(struct rtc_device *rtc, struct rtc_timer* timer); -void rtctimer_do_work(struct work_struct *work); +int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer); +void rtc_timer_do_work(struct work_struct *work); static inline bool is_leap_year(unsigned int year) { -- cgit v1.2.3 From f59c55d04b43bd72df8efa692dd07224fe94d1ac Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Tue, 7 Dec 2010 10:22:30 +0800 Subject: ACPI, APEI, Add APEI generic error status printing support In APEI, Hardware error information reported by firmware to Linux kernel is in the data structure of APEI generic error status (struct acpi_hes_generic_status). While now printk is used by Linux kernel to report hardware error information to user space. So, this patch adds printing support for the data structure, so that the corresponding hardware error information can be reported to user space via printk. PCIe AER information printing is not implemented yet. Will refactor the original PCIe AER information printing code to avoid code duplicating. The output format is as follow: := APEI generic hardware error status severity: , section: , severity: , flags:
fru_id: fru_text: section_type:
* := recoverable | fatal | corrected | info
# := [primary][, containment warning][, reset][, threshold exceeded]\ [, resource not accessible][, latent error]
:= generic processor error | memory error | \ PCIe error | unknown,
:= | | \ | := [processor_type: , ] [processor_isa: , ] [error_type: ] [operation: , ] [flags: ] [level: ] [version_info: ] [processor_id: ] [target_address: ] [requestor_id: ] [responder_id: ] [IP: ] * := IA32/X64 | IA64 * := IA32 | IA64 | X64 # := [cache error][, TLB error][, bus error][, micro-architectural error] * := unknown or generic | data read | data write | \ instruction execution # := [restartable][, precise IP][, overflow][, corrected] := [error_status: ] [physical_address: ] [physical_address_mask: ] [node: ] [card: ] [module: ] [bank: ] [device: ] [row: ] [column: ] [bit_position: ] [requestor_id: ] [responder_id: ] [target_id: ] [error_type: , ] * := unknown | no error | single-bit ECC | multi-bit ECC | \ single-symbol chipkill ECC | multi-symbol chipkill ECC | master abort | \ target abort | parity error | watchdog timeout | invalid address | \ mirror Broken | memory sparing | scrub corrected error | \ scrub uncorrected error := [port_type: , ] [version: .] [command: , status: ] [device_id: ::. slot: secondary_bus: vendor_id: , device_id: class_code: ] [serial number: , ] [bridge: secondary_status: , control: ] * := PCIe end point | legacy PCI end point | \ unknown | unknown | root port | upstream switch port | \ downstream switch port | PCIe to PCI/PCI-X bridge | \ PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \ root complex event collector Where, [] designate corresponding content is optional All description with * has the following format: field: , Where value of should be the position of "string" in description. Otherwise, will be "unknown". All description with # has the following format: field: Where each string in corresponding to one set bit of . The bit position is the position of "string" in description. For more detailed explanation of every field, please refer to UEFI specification version 2.3 or later, section Appendix N: Common Platform Error Record. Signed-off-by: Huang Ying Signed-off-by: Len Brown --- Documentation/acpi/apei/output_format.txt | 122 ++++++++++++ drivers/acpi/apei/apei-internal.h | 2 + drivers/acpi/apei/cper.c | 311 ++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 Documentation/acpi/apei/output_format.txt (limited to 'drivers') diff --git a/Documentation/acpi/apei/output_format.txt b/Documentation/acpi/apei/output_format.txt new file mode 100644 index 000000000000..9146952c612a --- /dev/null +++ b/Documentation/acpi/apei/output_format.txt @@ -0,0 +1,122 @@ + APEI output format + ~~~~~~~~~~~~~~~~~~ + +APEI uses printk as hardware error reporting interface, the output +format is as follow. + + := +APEI generic hardware error status +severity: , +section: , severity: , +flags: +
+fru_id: +fru_text: +section_type:
+
+ +* := recoverable | fatal | corrected | info + +
# := +[primary][, containment warning][, reset][, threshold exceeded]\ +[, resource not accessible][, latent error] + +
:= generic processor error | memory error | \ +PCIe error | unknown, + +
:= + | | \ + | + + := +[processor_type: , ] +[processor_isa: , ] +[error_type: +] +[operation: , ] +[flags: +] +[level: ] +[version_info: ] +[processor_id: ] +[target_address: ] +[requestor_id: ] +[responder_id: ] +[IP: ] + +* := IA32/X64 | IA64 + +* := IA32 | IA64 | X64 + +# := +[cache error][, TLB error][, bus error][, micro-architectural error] + +* := unknown or generic | data read | data write | \ +instruction execution + +# := +[restartable][, precise IP][, overflow][, corrected] + + := +[error_status: ] +[physical_address: ] +[physical_address_mask: ] +[node: ] +[card: ] +[module: ] +[bank: ] +[device: ] +[row: ] +[column: ] +[bit_position: ] +[requestor_id: ] +[responder_id: ] +[target_id: ] +[error_type: , ] + +* := +unknown | no error | single-bit ECC | multi-bit ECC | \ +single-symbol chipkill ECC | multi-symbol chipkill ECC | master abort | \ +target abort | parity error | watchdog timeout | invalid address | \ +mirror Broken | memory sparing | scrub corrected error | \ +scrub uncorrected error + + := +[port_type: , ] +[version: .] +[command: , status: ] +[device_id: ::. +slot: +secondary_bus: +vendor_id: , device_id: +class_code: ] +[serial number: , ] +[bridge: secondary_status: , control: ] + +* := PCIe end point | legacy PCI end point | \ +unknown | unknown | root port | upstream switch port | \ +downstream switch port | PCIe to PCI/PCI-X bridge | \ +PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \ +root complex event collector + +Where, [] designate corresponding content is optional + +All description with * has the following format: + +field: , + +Where value of should be the position of "string" in description. Otherwise, will be "unknown". + +All description with # has the following format: + +field: + + +Where each string in corresponding to one set bit of +. The bit position is the position of "string" in description. + +For more detailed explanation of every field, please refer to UEFI +specification version 2.3 or later, section Appendix N: Common +Platform Error Record. diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 18df1e940276..ef0581f2094d 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -109,6 +109,8 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus) return sizeof(*estatus) + estatus->data_length; } +void apei_estatus_print(const char *pfx, + const struct acpi_hest_generic_status *estatus); int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus); int apei_estatus_check(const struct acpi_hest_generic_status *estatus); #endif diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c index f4cf2fc4c8c1..31464a006d76 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/acpi/apei/cper.c @@ -46,6 +46,317 @@ u64 cper_next_record_id(void) } EXPORT_SYMBOL_GPL(cper_next_record_id); +static const char *cper_severity_strs[] = { + "recoverable", + "fatal", + "corrected", + "info", +}; + +static const char *cper_severity_str(unsigned int severity) +{ + return severity < ARRAY_SIZE(cper_severity_strs) ? + cper_severity_strs[severity] : "unknown"; +} + +/* + * cper_print_bits - print strings for set bits + * @pfx: prefix for each line, including log level and prefix string + * @bits: bit mask + * @strs: string array, indexed by bit position + * @strs_size: size of the string array: @strs + * + * For each set bit in @bits, print the corresponding string in @strs. + * If the output length is longer than 80, multiple line will be + * printed, with @pfx is printed at the beginning of each line. + */ +static void cper_print_bits(const char *pfx, unsigned int bits, + const char *strs[], unsigned int strs_size) +{ + int i, len = 0; + const char *str; + char buf[84]; + + for (i = 0; i < strs_size; i++) { + if (!(bits & (1U << i))) + continue; + str = strs[i]; + if (len && len + strlen(str) + 2 > 80) { + printk("%s\n", buf); + len = 0; + } + if (!len) + len = snprintf(buf, sizeof(buf), "%s%s", pfx, str); + else + len += snprintf(buf+len, sizeof(buf)-len, ", %s", str); + } + if (len) + printk("%s\n", buf); +} + +static const char *cper_proc_type_strs[] = { + "IA32/X64", + "IA64", +}; + +static const char *cper_proc_isa_strs[] = { + "IA32", + "IA64", + "X64", +}; + +static const char *cper_proc_error_type_strs[] = { + "cache error", + "TLB error", + "bus error", + "micro-architectural error", +}; + +static const char *cper_proc_op_strs[] = { + "unknown or generic", + "data read", + "data write", + "instruction execution", +}; + +static const char *cper_proc_flag_strs[] = { + "restartable", + "precise IP", + "overflow", + "corrected", +}; + +static void cper_print_proc_generic(const char *pfx, + const struct cper_sec_proc_generic *proc) +{ + if (proc->validation_bits & CPER_PROC_VALID_TYPE) + printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, + proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ? + cper_proc_type_strs[proc->proc_type] : "unknown"); + if (proc->validation_bits & CPER_PROC_VALID_ISA) + printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, + proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ? + cper_proc_isa_strs[proc->proc_isa] : "unknown"); + if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { + printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); + cper_print_bits(pfx, proc->proc_error_type, + cper_proc_error_type_strs, + ARRAY_SIZE(cper_proc_error_type_strs)); + } + if (proc->validation_bits & CPER_PROC_VALID_OPERATION) + printk("%s""operation: %d, %s\n", pfx, proc->operation, + proc->operation < ARRAY_SIZE(cper_proc_op_strs) ? + cper_proc_op_strs[proc->operation] : "unknown"); + if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { + printk("%s""flags: 0x%02x\n", pfx, proc->flags); + cper_print_bits(pfx, proc->flags, cper_proc_flag_strs, + ARRAY_SIZE(cper_proc_flag_strs)); + } + if (proc->validation_bits & CPER_PROC_VALID_LEVEL) + printk("%s""level: %d\n", pfx, proc->level); + if (proc->validation_bits & CPER_PROC_VALID_VERSION) + printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version); + if (proc->validation_bits & CPER_PROC_VALID_ID) + printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id); + if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS) + printk("%s""target_address: 0x%016llx\n", + pfx, proc->target_addr); + if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID) + printk("%s""requestor_id: 0x%016llx\n", + pfx, proc->requestor_id); + if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID) + printk("%s""responder_id: 0x%016llx\n", + pfx, proc->responder_id); + if (proc->validation_bits & CPER_PROC_VALID_IP) + printk("%s""IP: 0x%016llx\n", pfx, proc->ip); +} + +static const char *cper_mem_err_type_strs[] = { + "unknown", + "no error", + "single-bit ECC", + "multi-bit ECC", + "single-symbol chipkill ECC", + "multi-symbol chipkill ECC", + "master abort", + "target abort", + "parity error", + "watchdog timeout", + "invalid address", + "mirror Broken", + "memory sparing", + "scrub corrected error", + "scrub uncorrected error", +}; + +static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) +{ + if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) + printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); + if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) + printk("%s""physical_address: 0x%016llx\n", + pfx, mem->physical_addr); + if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK) + printk("%s""physical_address_mask: 0x%016llx\n", + pfx, mem->physical_addr_mask); + if (mem->validation_bits & CPER_MEM_VALID_NODE) + printk("%s""node: %d\n", pfx, mem->node); + if (mem->validation_bits & CPER_MEM_VALID_CARD) + printk("%s""card: %d\n", pfx, mem->card); + if (mem->validation_bits & CPER_MEM_VALID_MODULE) + printk("%s""module: %d\n", pfx, mem->module); + if (mem->validation_bits & CPER_MEM_VALID_BANK) + printk("%s""bank: %d\n", pfx, mem->bank); + if (mem->validation_bits & CPER_MEM_VALID_DEVICE) + printk("%s""device: %d\n", pfx, mem->device); + if (mem->validation_bits & CPER_MEM_VALID_ROW) + printk("%s""row: %d\n", pfx, mem->row); + if (mem->validation_bits & CPER_MEM_VALID_COLUMN) + printk("%s""column: %d\n", pfx, mem->column); + if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) + printk("%s""bit_position: %d\n", pfx, mem->bit_pos); + if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) + printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id); + if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) + printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id); + if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) + printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id); + if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { + u8 etype = mem->error_type; + printk("%s""error_type: %d, %s\n", pfx, etype, + etype < ARRAY_SIZE(cper_mem_err_type_strs) ? + cper_mem_err_type_strs[etype] : "unknown"); + } +} + +static const char *cper_pcie_port_type_strs[] = { + "PCIe end point", + "legacy PCI end point", + "unknown", + "unknown", + "root port", + "upstream switch port", + "downstream switch port", + "PCIe to PCI/PCI-X bridge", + "PCI/PCI-X to PCIe bridge", + "root complex integrated endpoint device", + "root complex event collector", +}; + +static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie) +{ + if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) + printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, + pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? + cper_pcie_port_type_strs[pcie->port_type] : "unknown"); + if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) + printk("%s""version: %d.%d\n", pfx, + pcie->version.major, pcie->version.minor); + if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS) + printk("%s""command: 0x%04x, status: 0x%04x\n", pfx, + pcie->command, pcie->status); + if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) { + const __u8 *p; + printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx, + pcie->device_id.segment, pcie->device_id.bus, + pcie->device_id.device, pcie->device_id.function); + printk("%s""slot: %d\n", pfx, + pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT); + printk("%s""secondary_bus: 0x%02x\n", pfx, + pcie->device_id.secondary_bus); + printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx, + pcie->device_id.vendor_id, pcie->device_id.device_id); + p = pcie->device_id.class_code; + printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]); + } + if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER) + printk("%s""serial number: 0x%04x, 0x%04x\n", pfx, + pcie->serial_number.lower, pcie->serial_number.upper); + if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS) + printk( + "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", + pfx, pcie->bridge.secondary_status, pcie->bridge.control); +} + +static const char *apei_estatus_section_flag_strs[] = { + "primary", + "containment warning", + "reset", + "threshold exceeded", + "resource not accessible", + "latent error", +}; + +static void apei_estatus_print_section( + const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no) +{ + uuid_le *sec_type = (uuid_le *)gdata->section_type; + __u16 severity; + + severity = gdata->error_severity; + printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity, + cper_severity_str(severity)); + printk("%s""flags: 0x%02x\n", pfx, gdata->flags); + cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs, + ARRAY_SIZE(apei_estatus_section_flag_strs)); + if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) + printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id); + if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) + printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); + + if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { + struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); + printk("%s""section_type: general processor error\n", pfx); + if (gdata->error_data_length >= sizeof(*proc_err)) + cper_print_proc_generic(pfx, proc_err); + else + goto err_section_too_small; + } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { + struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); + printk("%s""section_type: memory error\n", pfx); + if (gdata->error_data_length >= sizeof(*mem_err)) + cper_print_mem(pfx, mem_err); + else + goto err_section_too_small; + } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { + struct cper_sec_pcie *pcie = (void *)(gdata + 1); + printk("%s""section_type: PCIe error\n", pfx); + if (gdata->error_data_length >= sizeof(*pcie)) + cper_print_pcie(pfx, pcie); + else + goto err_section_too_small; + } else + printk("%s""section type: unknown, %pUl\n", pfx, sec_type); + + return; + +err_section_too_small: + pr_err(FW_WARN "error section length is too small\n"); +} + +void apei_estatus_print(const char *pfx, + const struct acpi_hest_generic_status *estatus) +{ + struct acpi_hest_generic_data *gdata; + unsigned int data_len, gedata_len; + int sec_no = 0; + __u16 severity; + + printk("%s""APEI generic hardware error status\n", pfx); + severity = estatus->error_severity; + printk("%s""severity: %d, %s\n", pfx, severity, + cper_severity_str(severity)); + data_len = estatus->data_length; + gdata = (struct acpi_hest_generic_data *)(estatus + 1); + while (data_len > sizeof(*gdata)) { + gedata_len = gdata->error_data_length; + apei_estatus_print_section(pfx, gdata, sec_no); + data_len -= gedata_len + sizeof(*gdata); + sec_no++; + } +} +EXPORT_SYMBOL_GPL(apei_estatus_print); + int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus) { if (estatus->data_length && -- cgit v1.2.3 From 32c361f574f85fa47600d84900598e2efc99082e Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Tue, 7 Dec 2010 10:22:31 +0800 Subject: ACPI, APEI, Report GHES error information via printk printk is one of the methods to report hardware errors to user space. This patch implements hardware error reporting for GHES via printk. Signed-off-by: Huang Ying Signed-off-by: Len Brown --- drivers/acpi/apei/ghes.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 0d505e59214d..51905d07a4d9 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -255,11 +256,26 @@ static void ghes_do_proc(struct ghes *ghes) } #endif } +} - if (!processed && printk_ratelimit()) - pr_warning(GHES_PFX - "Unknown error record from generic hardware error source: %d\n", - ghes->generic->header.source_id); +static void ghes_print_estatus(const char *pfx, struct ghes *ghes) +{ + /* Not more than 2 messages every 5 seconds */ + static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2); + + if (pfx == NULL) { + if (ghes_severity(ghes->estatus->error_severity) <= + GHES_SEV_CORRECTED) + pfx = KERN_WARNING HW_ERR; + else + pfx = KERN_ERR HW_ERR; + } + if (__ratelimit(&ratelimit)) { + printk( + "%s""Hardware error from APEI Generic Hardware Error Source: %d\n", + pfx, ghes->generic->header.source_id); + apei_estatus_print(pfx, ghes->estatus); + } } static int ghes_proc(struct ghes *ghes) @@ -269,6 +285,7 @@ static int ghes_proc(struct ghes *ghes) rc = ghes_read_estatus(ghes, 0); if (rc) goto out; + ghes_print_estatus(NULL, ghes); ghes_do_proc(ghes); out: -- cgit v1.2.3 From cef6e8a3790d6bdc305496629c357a56001d59a6 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 6 Dec 2010 15:04:15 +0800 Subject: ACPI processor: remove processor throttling control procfs I/F Remove deprecated ACPI process procfs I/F for throttling control. This is because the t-state control should only be done in kernel, when system is in a overheating state. Now users can only change the processor t-state indirectly, by poking the cooling device sysfs I/F of the processor. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 4 -- drivers/acpi/processor_driver.c | 75 +----------------------- drivers/acpi/processor_throttling.c | 114 ------------------------------------ 3 files changed, 1 insertion(+), 192 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 3f3489c5ca8c..5959077be0a4 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -53,10 +53,6 @@ config ACPI_PROCFS they have been replaced by functions in /sys. The deprecated files (and their replacements) include: - /proc/acpi/processor/*/throttling (/sys/class/thermal/ - cooling_device*/*) - /proc/acpi/video/*/brightness (/sys/class/backlight/) - /proc/acpi/thermal_zone/*/* (/sys/class/thermal/) This option has no effect on /proc/acpi/ files and functions which do not yet exist in /sys. diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 85e48047d7b0..29572debc65d 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -40,10 +40,6 @@ #include #include #include -#ifdef CONFIG_ACPI_PROCFS -#include -#include -#endif #include #include #include @@ -246,53 +242,6 @@ static int acpi_processor_errata(struct acpi_processor *pr) return result; } -#ifdef CONFIG_ACPI_PROCFS -static struct proc_dir_entry *acpi_processor_dir = NULL; - -static int __cpuinit acpi_processor_add_fs(struct acpi_device *device) -{ - struct proc_dir_entry *entry = NULL; - - - if (!acpi_device_dir(device)) { - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), - acpi_processor_dir); - if (!acpi_device_dir(device)) - return -ENODEV; - } - - /* 'throttling' [R/W] */ - entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device), - &acpi_processor_throttling_fops, - acpi_driver_data(device)); - if (!entry) - return -EIO; - return 0; -} -static int acpi_processor_remove_fs(struct acpi_device *device) -{ - - if (acpi_device_dir(device)) { - remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, - acpi_device_dir(device)); - remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); - acpi_device_dir(device) = NULL; - } - - return 0; -} -#else -static inline int acpi_processor_add_fs(struct acpi_device *device) -{ - return 0; -} -static inline int acpi_processor_remove_fs(struct acpi_device *device) -{ - return 0; -} -#endif /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -537,14 +486,10 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) per_cpu(processors, pr->id) = pr; - result = acpi_processor_add_fs(device); - if (result) - goto err_free_cpumask; - sysdev = get_cpu_sysdev(pr->id); if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { result = -EFAULT; - goto err_remove_fs; + goto err_free_cpumask; } #ifdef CONFIG_CPU_FREQ @@ -590,8 +535,6 @@ err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); err_power_exit: acpi_processor_power_exit(pr, device); -err_remove_fs: - acpi_processor_remove_fs(device); err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); @@ -620,8 +563,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type) sysfs_remove_link(&device->dev.kobj, "sysdev"); - acpi_processor_remove_fs(device); - if (pr->cdev) { sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); sysfs_remove_link(&pr->cdev->device.kobj, "device"); @@ -854,12 +795,6 @@ static int __init acpi_processor_init(void) memset(&errata, 0, sizeof(errata)); -#ifdef CONFIG_ACPI_PROCFS - acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); - if (!acpi_processor_dir) - return -ENOMEM; -#endif - if (!cpuidle_register_driver(&acpi_idle_driver)) { printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", acpi_idle_driver.name); @@ -885,10 +820,6 @@ static int __init acpi_processor_init(void) out_cpuidle: cpuidle_unregister_driver(&acpi_idle_driver); -#ifdef CONFIG_ACPI_PROCFS - remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); -#endif - return result; } @@ -907,10 +838,6 @@ static void __exit acpi_processor_exit(void) cpuidle_unregister_driver(&acpi_idle_driver); -#ifdef CONFIG_ACPI_PROCFS - remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); -#endif - return; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ff3632717c51..4a0eec5dd24a 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -32,10 +32,6 @@ #include #include #include -#ifdef CONFIG_ACPI_PROCFS -#include -#include -#endif #include #include @@ -1216,113 +1212,3 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) return result; } -#ifdef CONFIG_ACPI_PROCFS -/* proc interface */ -static int acpi_processor_throttling_seq_show(struct seq_file *seq, - void *offset) -{ - struct acpi_processor *pr = seq->private; - int i = 0; - int result = 0; - - if (!pr) - goto end; - - if (!(pr->throttling.state_count > 0)) { - seq_puts(seq, "\n"); - goto end; - } - - result = acpi_processor_get_throttling(pr); - - if (result) { - seq_puts(seq, - "Could not determine current throttling state.\n"); - goto end; - } - - seq_printf(seq, "state count: %d\n" - "active state: T%d\n" - "state available: T%d to T%d\n", - pr->throttling.state_count, pr->throttling.state, - pr->throttling_platform_limit, - pr->throttling.state_count - 1); - - seq_puts(seq, "states:\n"); - if (pr->throttling.acpi_processor_get_throttling == - acpi_processor_get_throttling_fadt) { - for (i = 0; i < pr->throttling.state_count; i++) - seq_printf(seq, " %cT%d: %02d%%\n", - (i == pr->throttling.state ? '*' : ' '), i, - (pr->throttling.states[i].performance ? pr-> - throttling.states[i].performance / 10 : 0)); - } else { - for (i = 0; i < pr->throttling.state_count; i++) - seq_printf(seq, " %cT%d: %02d%%\n", - (i == pr->throttling.state ? '*' : ' '), i, - (int)pr->throttling.states_tss[i]. - freqpercentage); - } - - end: - return 0; -} - -static int acpi_processor_throttling_open_fs(struct inode *inode, - struct file *file) -{ - return single_open(file, acpi_processor_throttling_seq_show, - PDE(inode)->data); -} - -static ssize_t acpi_processor_write_throttling(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - int result = 0; - struct seq_file *m = file->private_data; - struct acpi_processor *pr = m->private; - char state_string[5] = ""; - char *charp = NULL; - size_t state_val = 0; - char tmpbuf[5] = ""; - - if (!pr || (count > sizeof(state_string) - 1)) - return -EINVAL; - - if (copy_from_user(state_string, buffer, count)) - return -EFAULT; - - state_string[count] = '\0'; - if ((count > 0) && (state_string[count-1] == '\n')) - state_string[count-1] = '\0'; - - charp = state_string; - if ((state_string[0] == 't') || (state_string[0] == 'T')) - charp++; - - state_val = simple_strtoul(charp, NULL, 0); - if (state_val >= pr->throttling.state_count) - return -EINVAL; - - snprintf(tmpbuf, 5, "%zu", state_val); - - if (strcmp(tmpbuf, charp) != 0) - return -EINVAL; - - result = acpi_processor_set_throttling(pr, state_val, false); - if (result) - return result; - - return count; -} - -const struct file_operations acpi_processor_throttling_fops = { - .owner = THIS_MODULE, - .open = acpi_processor_throttling_open_fs, - .read = seq_read, - .write = acpi_processor_write_throttling, - .llseek = seq_lseek, - .release = single_release, -}; -#endif -- cgit v1.2.3 From 677bd810eedce61edf15452491781ff046b92edc Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 6 Dec 2010 15:04:21 +0800 Subject: ACPI video: remove output switching control Remove the ACPI video output switching control as it never works. With the patch applied, ACPI video driver still catches the video output notification, but it does nothing but raises the notification to userspace. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- Documentation/kernel-parameters.txt | 5 --- drivers/acpi/video.c | 86 ------------------------------------- drivers/acpi/video_detect.c | 57 ++---------------------- drivers/gpu/drm/Kconfig | 1 - drivers/gpu/stub/Kconfig | 1 - 5 files changed, 4 insertions(+), 146 deletions(-) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index cdd2a6e8a3b7..f91fc5a65034 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -199,11 +199,6 @@ and is between 256 and 4096 characters. It is defined in the file unusable. The "log_buf_len" parameter may be useful if you need to capture more output. - acpi_display_output= [HW,ACPI] - acpi_display_output=vendor - acpi_display_output=video - See above. - acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs default in APIC mode diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5cd0228d2daa..81766ebec843 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -172,9 +171,6 @@ struct acpi_video_device_cap { u8 _BQC:1; /* Get current brightness level */ u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ u8 _DDC:1; /*Return the EDID for this device */ - u8 _DCS:1; /*Return status of output device */ - u8 _DGS:1; /*Query graphics state */ - u8 _DSS:1; /*Device state set */ }; struct acpi_video_brightness_flags { @@ -202,7 +198,6 @@ struct acpi_video_device { struct acpi_video_device_brightness *brightness; struct backlight_device *backlight; struct thermal_cooling_device *cooling_dev; - struct output_device *output_dev; }; static const char device_decode[][30] = { @@ -226,10 +221,6 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); static int acpi_video_switch_brightness(struct acpi_video_device *device, int event); -static int acpi_video_device_get_state(struct acpi_video_device *device, - unsigned long long *state); -static int acpi_video_output_get(struct output_device *od); -static int acpi_video_device_set_state(struct acpi_video_device *device, int state); /*backlight device sysfs support*/ static int acpi_video_get_brightness(struct backlight_device *bd) @@ -265,30 +256,6 @@ static struct backlight_ops acpi_backlight_ops = { .update_status = acpi_video_set_brightness, }; -/*video output device sysfs support*/ -static int acpi_video_output_get(struct output_device *od) -{ - unsigned long long state; - struct acpi_video_device *vd = - (struct acpi_video_device *)dev_get_drvdata(&od->dev); - acpi_video_device_get_state(vd, &state); - return (int)state; -} - -static int acpi_video_output_set(struct output_device *od) -{ - unsigned long state = od->request_state; - struct acpi_video_device *vd= - (struct acpi_video_device *)dev_get_drvdata(&od->dev); - return acpi_video_device_set_state(vd, state); -} - -static struct output_properties acpi_output_properties = { - .set_state = acpi_video_output_set, - .get_status = acpi_video_output_get, -}; - - /* thermal cooling device callbacks */ static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned long *state) @@ -344,34 +311,6 @@ static struct thermal_cooling_device_ops video_cooling_ops = { Video Management -------------------------------------------------------------------------- */ -/* device */ - -static int -acpi_video_device_get_state(struct acpi_video_device *device, - unsigned long long *state) -{ - int status; - - status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state); - - return status; -} - -static int -acpi_video_device_set_state(struct acpi_video_device *device, int state) -{ - int status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; - unsigned long long ret; - - - arg0.integer.value = state; - status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret); - - return status; -} - static int acpi_video_device_lcd_query_levels(struct acpi_video_device *device, union acpi_object **levels) @@ -831,15 +770,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { device->cap._DDC = 1; } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) { - device->cap._DCS = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) { - device->cap._DGS = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) { - device->cap._DSS = 1; - } if (acpi_video_backlight_support()) { struct backlight_properties props; @@ -904,21 +834,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) printk(KERN_ERR PREFIX "Create sysfs link\n"); } - - if (acpi_video_display_switch_support()) { - - if (device->cap._DCS && device->cap._DSS) { - static int count; - char *name; - name = kasprintf(GFP_KERNEL, "acpi_video%d", count); - if (!name) - return; - count++; - device->output_dev = video_output_register(name, - NULL, device, &acpi_output_properties); - kfree(name); - } - } } /* @@ -1452,7 +1367,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) thermal_cooling_device_unregister(device->cooling_dev); device->cooling_dev = NULL; } - video_output_unregister(device->output_dev); return 0; } diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index b83676126598..42d3d72dae85 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -17,15 +17,14 @@ * capabilities the graphics cards plugged in support. The check for general * video capabilities will be triggered by the first caller of * acpi_video_get_capabilities(NULL); which will happen when the first - * backlight (or display output) switching supporting driver calls: + * backlight switching supporting driver calls: * acpi_video_backlight_support(); * * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) * are available, video.ko should be used to handle the device. * * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi, - * sony_acpi,... can take care about backlight brightness and display output - * switching. + * sony_acpi,... can take care about backlight brightness. * * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) * this file will not be compiled, acpi_video_get_capabilities() and @@ -83,11 +82,6 @@ long acpi_is_video_device(struct acpi_device *device) if (!device) return 0; - /* Is this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) || - ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) - video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; - /* Is this device able to retrieve a video ROM ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) video_caps |= ACPI_VIDEO_ROM_AVAILABLE; @@ -161,8 +155,6 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle) * * if (dmi_name_in_vendors("XY")) { * acpi_video_support |= - * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR; - * acpi_video_support |= * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; *} */ @@ -212,33 +204,8 @@ int acpi_video_backlight_support(void) EXPORT_SYMBOL(acpi_video_backlight_support); /* - * Returns true if video.ko can do display output switching. - * This does not work well/at all with binary graphics drivers - * which disable system io ranges and do it on their own. - */ -int acpi_video_display_switch_support(void) -{ - if (!acpi_video_caps_checked) - acpi_video_get_capabilities(NULL); - - if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR) - return 0; - else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO) - return 1; - - if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR) - return 0; - else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO) - return 1; - - return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING; -} -EXPORT_SYMBOL(acpi_video_display_switch_support); - -/* - * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video - * To force that backlight or display output switching is processed by vendor - * specific acpi drivers or video.ko driver. + * Use acpi_backlight=vendor/video to force that backlight switching + * is processed by vendor specific acpi drivers or video.ko driver. */ static int __init acpi_backlight(char *str) { @@ -255,19 +222,3 @@ static int __init acpi_backlight(char *str) return 1; } __setup("acpi_backlight=", acpi_backlight); - -static int __init acpi_display_output(char *str) -{ - if (str == NULL || *str == '\0') - return 1; - else { - if (!strcmp("vendor", str)) - acpi_video_support |= - ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR; - if (!strcmp("video", str)) - acpi_video_support |= - ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; - } - return 1; -} -__setup("acpi_display_output=", acpi_display_output); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 7af443672626..64828a7db77b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -107,7 +107,6 @@ config DRM_I915 select FB_CFB_IMAGEBLIT # i915 depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick - select VIDEO_OUTPUT_CONTROL if ACPI select BACKLIGHT_CLASS_DEVICE if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig index 0e1edd7311ff..09aea5f1556d 100644 --- a/drivers/gpu/stub/Kconfig +++ b/drivers/gpu/stub/Kconfig @@ -3,7 +3,6 @@ config STUB_POULSBO depends on PCI # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick - select VIDEO_OUTPUT_CONTROL if ACPI select BACKLIGHT_CLASS_DEVICE if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI -- cgit v1.2.3 From 82069552555cf951d9ade5c1aec61dd40b0765b5 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 6 Dec 2010 15:04:24 +0800 Subject: ACPI video: check cap._DDC flag before getting EDID cap._DDC is defined but never used. Check this flag now and don't try to get EDID for video output devices with this flag cleared. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/video.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 81766ebec843..177b4ddc3479 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1275,6 +1275,9 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, if (!video_device) continue; + if (!video_device->cap._DDC) + continue; + if (type) { switch (type) { case ACPI_VIDEO_DISPLAY_CRT: -- cgit v1.2.3 From 99fd1895ef603f1a0fa9af478c96c637a7b4529d Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 6 Dec 2010 15:04:27 +0800 Subject: ACPI video: introduce module parameter video.use_bios_initial_backlight Introduce module parameter video.use_bios_initial_backlight. Some BIOSes claim they use the minimum backlight at boot, and this may bring dimming screen after boot. https://bugzilla.kernel.org/show_bug.cgi?id=21212 use video.use_bios_initl_backlight=0 to use the maximum backlight level after boot. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/video.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5cd0228d2daa..89f19a8fc726 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -81,6 +81,13 @@ module_param(brightness_switch_enabled, bool, 0644); static int allow_duplicates; module_param(allow_duplicates, bool, 0644); +/* + * Some BIOSes claim they use minimum backlight at boot, + * and this may bring dimming screen after boot + */ +static int use_bios_initial_backlight = 1; +module_param(use_bios_initial_backlight, bool, 0644); + static int register_count = 0; static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); @@ -766,9 +773,11 @@ acpi_video_init_brightness(struct acpi_video_device *device) * when invoked for the first time, i.e. level_old is invalid. * set the backlight to max_level in this case */ - for (i = 2; i < br->count; i++) - if (level_old == br->levels[i]) - level = level_old; + if (use_bios_initial_backlight) { + for (i = 2; i < br->count; i++) + if (level_old == br->levels[i]) + level = level_old; + } goto set_level; } -- cgit v1.2.3 From 16f4232ce4d6855361b4eb56262f4a202295c978 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 8 Dec 2010 10:10:16 +0800 Subject: IPMI: Add one interface to get more info of low-level IPMI device The IPMI smi_watcher will be used to catch the IPMI interface as they come or go. In order to communicate with the correct IPMI device, it should be confirmed whether it is what we wanted especially on the system with multiple IPMI devices. But the new_smi callback function of smi_watcher provides very limited info(only the interface number and dev pointer) and there is no detailed info about the low level interface. For example: which mechansim registers the IPMI interface(ACPI, PCI, DMI and so on). This is to add one interface that can get more info of low-level IPMI device. For example: the ACPI device handle will be returned for the pnp_acpi IPMI device. Signed-off-by: Zhao Yakui Signed-off-by: Corey Minyard Signed-off-by: Len Brown --- drivers/char/ipmi/ipmi_msghandler.c | 27 ++++++++++++++++++++++++++ drivers/char/ipmi/ipmi_si_intf.c | 20 +++++++++++++++---- include/linux/ipmi.h | 38 +++++++++++++++++++++++++++++++++++++ include/linux/ipmi_smi.h | 8 ++++++++ 4 files changed, 89 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 2fe72f8edf44..38223e93aa98 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -970,6 +970,33 @@ out_kfree: } EXPORT_SYMBOL(ipmi_create_user); +int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) +{ + int rv = 0; + ipmi_smi_t intf; + struct ipmi_smi_handlers *handlers; + + mutex_lock(&ipmi_interfaces_mutex); + list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { + if (intf->intf_num == if_num) + goto found; + } + /* Not found, return an error */ + rv = -EINVAL; + mutex_unlock(&ipmi_interfaces_mutex); + return rv; + +found: + handlers = intf->handlers; + rv = -ENOSYS; + if (handlers->get_smi_info) + rv = handlers->get_smi_info(intf->send_info, data); + mutex_unlock(&ipmi_interfaces_mutex); + + return rv; +} +EXPORT_SYMBOL(ipmi_get_smi_info); + static void free_user(struct kref *ref) { ipmi_user_t user = container_of(ref, struct ipmi_user, refcount); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 035da9e64a17..945ae4d5d21f 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include "ipmi_si_sm.h" @@ -107,10 +108,6 @@ enum si_type { }; static char *si_to_str[] = { "kcs", "smic", "bt" }; -enum ipmi_addr_src { - SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS, - SI_PCI, SI_DEVICETREE, SI_DEFAULT -}; static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI", "ACPI", "SMBIOS", "PCI", "device-tree", "default" }; @@ -291,6 +288,7 @@ struct smi_info { struct task_struct *thread; struct list_head link; + union ipmi_smi_info_union addr_info; }; #define smi_inc_stat(smi, stat) \ @@ -1186,6 +1184,18 @@ static int smi_start_processing(void *send_info, return 0; } +static int get_smi_info(void *send_info, struct ipmi_smi_info *data) +{ + struct smi_info *smi = send_info; + + data->addr_src = smi->addr_source; + data->dev = smi->dev; + data->addr_info = smi->addr_info; + get_device(smi->dev); + + return 0; +} + static void set_maintenance_mode(void *send_info, int enable) { struct smi_info *smi_info = send_info; @@ -1197,6 +1207,7 @@ static void set_maintenance_mode(void *send_info, int enable) static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, + .get_smi_info = get_smi_info, .sender = sender, .request_events = request_events, .set_maintenance_mode = set_maintenance_mode, @@ -2156,6 +2167,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, printk(KERN_INFO PFX "probing via ACPI\n"); handle = acpi_dev->handle; + info->addr_info.acpi_info.acpi_handle = handle; /* _IFT tells us the interface type: KCS, BT, etc */ status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 65aae34759de..045f2f275cd0 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -454,6 +454,44 @@ unsigned int ipmi_addr_length(int addr_type); /* Validate that the given IPMI address is valid. */ int ipmi_validate_addr(struct ipmi_addr *addr, int len); +/* + * How did the IPMI driver find out about the device? + */ +enum ipmi_addr_src { + SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS, + SI_PCI, SI_DEVICETREE, SI_DEFAULT +}; + +union ipmi_smi_info_union { + /* + * the acpi_info element is defined for the SI_ACPI + * address type + */ + struct { + void *acpi_handle; + } acpi_info; +}; + +struct ipmi_smi_info { + enum ipmi_addr_src addr_src; + + /* + * Base device for the interface. Don't forget to put this when + * you are done. + */ + struct device *dev; + + /* + * The addr_info provides more detailed info for some IPMI + * devices, depending on the addr_src. Currently only SI_ACPI + * info is provided. + */ + union ipmi_smi_info_union addr_info; +}; + +/* This is to get the private info of ipmi_smi_t */ +extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data); + #endif /* __KERNEL__ */ diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 4b48318ac542..906590aa6907 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -39,6 +39,7 @@ #include #include #include +#include /* This files describes the interface for IPMI system management interface drivers to bind into the IPMI message handler. */ @@ -86,6 +87,13 @@ struct ipmi_smi_handlers { int (*start_processing)(void *send_info, ipmi_smi_t new_intf); + /* + * Get the detailed private info of the low level interface and store + * it into the structure of ipmi_smi_data. For example: the + * ACPI device handle will be returned for the pnp_acpi IPMI device. + */ + int (*get_smi_info)(void *send_info, struct ipmi_smi_info *data); + /* Called to enqueue an SMI message to be sent. This operation is not allowed to fail. If an error occurs, it should report back the error in a received message. It may -- cgit v1.2.3 From e92b297cc72ade7a58eaec7e01c906d856f8ab6e Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 8 Dec 2010 10:10:18 +0800 Subject: IPMI/ACPI: Add the IPMI opregion driver to enable ACPI to access BMC controller ACPI 4.0 spec adds the ACPI IPMI opregion, which means that the ACPI AML code can also communicate with the BMC controller. This is to install the ACPI IPMI opregion and enable the ACPI to access the BMC controller through the IPMI message. It will create IPMI user interface for every IPMI device detected in ACPI namespace and install the corresponding IPMI opregion space handler. Then it can enable ACPI to access the BMC controller through the IPMI message. The following describes how to process the IPMI request in IPMI space handler: 1. format the IPMI message based on the request in AML code. IPMI system address. Now the address type is SYSTEM_INTERFACE_ADDR_TYPE IPMI net function & command IPMI message payload 2. send the IPMI message by using the function of ipmi_request_settime 3. wait for the completion of IPMI message. It can be done in different routes: One is in handled in IPMI user recv callback function. Another is handled in timeout function. 4. format the IPMI response and return it to ACPI AML code. At the same time it also addes the module dependency. The ACPI IPMI opregion will depend on the IPMI subsystem. Signed-off-by: Zhao Yakui cc: Bjorn Helgaas Signed-off-by: Corey Minyard Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 11 + drivers/acpi/Makefile | 1 + drivers/acpi/acpi_ipmi.c | 525 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 537 insertions(+) create mode 100644 drivers/acpi/acpi_ipmi.c (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 3f3489c5ca8c..a0c03658b2ea 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -209,6 +209,17 @@ config ACPI_PROCESSOR To compile this driver as a module, choose M here: the module will be called processor. +config ACPI_IPMI + tristate "IPMI" + depends on EXPERIMENTAL && IPMI_SI && IPMI_HANDLER + default n + help + This driver enables the ACPI to access the BMC controller. And it + uses the IPMI request/response message to communicate with BMC + controller, which can be found on on the server. + + To compile this driver as a module, choose M here: + the module will be called as acpi_ipmi. config ACPI_HOTPLUG_CPU bool diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3d031d02e54b..df4c4f030388 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -69,5 +69,6 @@ processor-y += processor_idle.o processor_thermal.o processor-$(CONFIG_CPU_FREQ) += processor_perflib.o obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o +obj-$(CONFIG_ACPI_IPMI) += acpi_ipmi.o obj-$(CONFIG_ACPI_APEI) += apei/ diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c new file mode 100644 index 000000000000..f40acef80269 --- /dev/null +++ b/drivers/acpi/acpi_ipmi.c @@ -0,0 +1,525 @@ +/* + * acpi_ipmi.c - ACPI IPMI opregion + * + * Copyright (C) 2010 Intel Corporation + * Copyright (C) 2010 Zhao Yakui + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Zhao Yakui"); +MODULE_DESCRIPTION("ACPI IPMI Opregion driver"); +MODULE_LICENSE("GPL"); + +#define IPMI_FLAGS_HANDLER_INSTALL 0 + +#define ACPI_IPMI_OK 0 +#define ACPI_IPMI_TIMEOUT 0x10 +#define ACPI_IPMI_UNKNOWN 0x07 +/* the IPMI timeout is 5s */ +#define IPMI_TIMEOUT (5 * HZ) + +struct acpi_ipmi_device { + /* the device list attached to driver_data.ipmi_devices */ + struct list_head head; + /* the IPMI request message list */ + struct list_head tx_msg_list; + struct mutex tx_msg_lock; + acpi_handle handle; + struct pnp_dev *pnp_dev; + ipmi_user_t user_interface; + int ipmi_ifnum; /* IPMI interface number */ + long curr_msgid; + unsigned long flags; + struct ipmi_smi_info smi_data; +}; + +struct ipmi_driver_data { + struct list_head ipmi_devices; + struct ipmi_smi_watcher bmc_events; + struct ipmi_user_hndl ipmi_hndlrs; + struct mutex ipmi_lock; +}; + +struct acpi_ipmi_msg { + struct list_head head; + /* + * General speaking the addr type should be SI_ADDR_TYPE. And + * the addr channel should be BMC. + * In fact it can also be IPMB type. But we will have to + * parse it from the Netfn command buffer. It is so complex + * that it is skipped. + */ + struct ipmi_addr addr; + long tx_msgid; + /* it is used to track whether the IPMI message is finished */ + struct completion tx_complete; + struct kernel_ipmi_msg tx_message; + int msg_done; + /* tx data . And copy it from ACPI object buffer */ + u8 tx_data[64]; + int tx_len; + u8 rx_data[64]; + int rx_len; + struct acpi_ipmi_device *device; +}; + +/* IPMI request/response buffer per ACPI 4.0, sec 5.5.2.4.3.2 */ +struct acpi_ipmi_buffer { + u8 status; + u8 length; + u8 data[64]; +}; + +static void ipmi_register_bmc(int iface, struct device *dev); +static void ipmi_bmc_gone(int iface); +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device); +static void acpi_remove_ipmi_device(struct acpi_ipmi_device *ipmi_device); + +static struct ipmi_driver_data driver_data = { + .ipmi_devices = LIST_HEAD_INIT(driver_data.ipmi_devices), + .bmc_events = { + .owner = THIS_MODULE, + .new_smi = ipmi_register_bmc, + .smi_gone = ipmi_bmc_gone, + }, + .ipmi_hndlrs = { + .ipmi_recv_hndl = ipmi_msg_handler, + }, +}; + +static struct acpi_ipmi_msg *acpi_alloc_ipmi_msg(struct acpi_ipmi_device *ipmi) +{ + struct acpi_ipmi_msg *ipmi_msg; + struct pnp_dev *pnp_dev = ipmi->pnp_dev; + + ipmi_msg = kzalloc(sizeof(struct acpi_ipmi_msg), GFP_KERNEL); + if (!ipmi_msg) { + dev_warn(&pnp_dev->dev, "Can't allocate memory for ipmi_msg\n"); + return NULL; + } + init_completion(&ipmi_msg->tx_complete); + INIT_LIST_HEAD(&ipmi_msg->head); + ipmi_msg->device = ipmi; + return ipmi_msg; +} + +#define IPMI_OP_RGN_NETFN(offset) ((offset >> 8) & 0xff) +#define IPMI_OP_RGN_CMD(offset) (offset & 0xff) +static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg, + acpi_physical_address address, + acpi_integer *value) +{ + struct kernel_ipmi_msg *msg; + struct acpi_ipmi_buffer *buffer; + struct acpi_ipmi_device *device; + + msg = &tx_msg->tx_message; + /* + * IPMI network function and command are encoded in the address + * within the IPMI OpRegion; see ACPI 4.0, sec 5.5.2.4.3. + */ + msg->netfn = IPMI_OP_RGN_NETFN(address); + msg->cmd = IPMI_OP_RGN_CMD(address); + msg->data = tx_msg->tx_data; + /* + * value is the parameter passed by the IPMI opregion space handler. + * It points to the IPMI request message buffer + */ + buffer = (struct acpi_ipmi_buffer *)value; + /* copy the tx message data */ + msg->data_len = buffer->length; + memcpy(tx_msg->tx_data, buffer->data, msg->data_len); + /* + * now the default type is SYSTEM_INTERFACE and channel type is BMC. + * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE, + * the addr type should be changed to IPMB. Then we will have to parse + * the IPMI request message buffer to get the IPMB address. + * If so, please fix me. + */ + tx_msg->addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + tx_msg->addr.channel = IPMI_BMC_CHANNEL; + tx_msg->addr.data[0] = 0; + + /* Get the msgid */ + device = tx_msg->device; + mutex_lock(&device->tx_msg_lock); + device->curr_msgid++; + tx_msg->tx_msgid = device->curr_msgid; + mutex_unlock(&device->tx_msg_lock); +} + +static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, + acpi_integer *value, int rem_time) +{ + struct acpi_ipmi_buffer *buffer; + + /* + * value is also used as output parameter. It represents the response + * IPMI message returned by IPMI command. + */ + buffer = (struct acpi_ipmi_buffer *)value; + if (!rem_time && !msg->msg_done) { + buffer->status = ACPI_IPMI_TIMEOUT; + return; + } + /* + * If the flag of msg_done is not set or the recv length is zero, it + * means that the IPMI command is not executed correctly. + * The status code will be ACPI_IPMI_UNKNOWN. + */ + if (!msg->msg_done || !msg->rx_len) { + buffer->status = ACPI_IPMI_UNKNOWN; + return; + } + /* + * If the IPMI response message is obtained correctly, the status code + * will be ACPI_IPMI_OK + */ + buffer->status = ACPI_IPMI_OK; + buffer->length = msg->rx_len; + memcpy(buffer->data, msg->rx_data, msg->rx_len); +} + +static void ipmi_flush_tx_msg(struct acpi_ipmi_device *ipmi) +{ + struct acpi_ipmi_msg *tx_msg, *temp; + int count = HZ / 10; + struct pnp_dev *pnp_dev = ipmi->pnp_dev; + + list_for_each_entry_safe(tx_msg, temp, &ipmi->tx_msg_list, head) { + /* wake up the sleep thread on the Tx msg */ + complete(&tx_msg->tx_complete); + } + + /* wait for about 100ms to flush the tx message list */ + while (count--) { + if (list_empty(&ipmi->tx_msg_list)) + break; + schedule_timeout(1); + } + if (!list_empty(&ipmi->tx_msg_list)) + dev_warn(&pnp_dev->dev, "tx msg list is not NULL\n"); +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + struct acpi_ipmi_device *ipmi_device = user_msg_data; + int msg_found = 0; + struct acpi_ipmi_msg *tx_msg; + struct pnp_dev *pnp_dev = ipmi_device->pnp_dev; + + if (msg->user != ipmi_device->user_interface) { + dev_warn(&pnp_dev->dev, "Unexpected response is returned. " + "returned user %p, expected user %p\n", + msg->user, ipmi_device->user_interface); + ipmi_free_recv_msg(msg); + return; + } + mutex_lock(&ipmi_device->tx_msg_lock); + list_for_each_entry(tx_msg, &ipmi_device->tx_msg_list, head) { + if (msg->msgid == tx_msg->tx_msgid) { + msg_found = 1; + break; + } + } + + mutex_unlock(&ipmi_device->tx_msg_lock); + if (!msg_found) { + dev_warn(&pnp_dev->dev, "Unexpected response (msg id %ld) is " + "returned.\n", msg->msgid); + ipmi_free_recv_msg(msg); + return; + } + + if (msg->msg.data_len) { + /* copy the response data to Rx_data buffer */ + memcpy(tx_msg->rx_data, msg->msg_data, msg->msg.data_len); + tx_msg->rx_len = msg->msg.data_len; + tx_msg->msg_done = 1; + } + complete(&tx_msg->tx_complete); + ipmi_free_recv_msg(msg); +}; + +static void ipmi_register_bmc(int iface, struct device *dev) +{ + struct acpi_ipmi_device *ipmi_device, *temp; + struct pnp_dev *pnp_dev; + ipmi_user_t user; + int err; + struct ipmi_smi_info smi_data; + acpi_handle handle; + + err = ipmi_get_smi_info(iface, &smi_data); + + if (err) + return; + + if (smi_data.addr_src != SI_ACPI) { + put_device(smi_data.dev); + return; + } + + handle = smi_data.addr_info.acpi_info.acpi_handle; + + mutex_lock(&driver_data.ipmi_lock); + list_for_each_entry(temp, &driver_data.ipmi_devices, head) { + /* + * if the corresponding ACPI handle is already added + * to the device list, don't add it again. + */ + if (temp->handle == handle) + goto out; + } + + ipmi_device = kzalloc(sizeof(*ipmi_device), GFP_KERNEL); + + if (!ipmi_device) + goto out; + + pnp_dev = to_pnp_dev(smi_data.dev); + ipmi_device->handle = handle; + ipmi_device->pnp_dev = pnp_dev; + + err = ipmi_create_user(iface, &driver_data.ipmi_hndlrs, + ipmi_device, &user); + if (err) { + dev_warn(&pnp_dev->dev, "Can't create IPMI user interface\n"); + kfree(ipmi_device); + goto out; + } + acpi_add_ipmi_device(ipmi_device); + ipmi_device->user_interface = user; + ipmi_device->ipmi_ifnum = iface; + mutex_unlock(&driver_data.ipmi_lock); + memcpy(&ipmi_device->smi_data, &smi_data, sizeof(struct ipmi_smi_info)); + return; + +out: + mutex_unlock(&driver_data.ipmi_lock); + put_device(smi_data.dev); + return; +} + +static void ipmi_bmc_gone(int iface) +{ + struct acpi_ipmi_device *ipmi_device, *temp; + + mutex_lock(&driver_data.ipmi_lock); + list_for_each_entry_safe(ipmi_device, temp, + &driver_data.ipmi_devices, head) { + if (ipmi_device->ipmi_ifnum != iface) + continue; + + acpi_remove_ipmi_device(ipmi_device); + put_device(ipmi_device->smi_data.dev); + kfree(ipmi_device); + break; + } + mutex_unlock(&driver_data.ipmi_lock); +} +/* -------------------------------------------------------------------------- + * Address Space Management + * -------------------------------------------------------------------------- */ +/* + * This is the IPMI opregion space handler. + * @function: indicates the read/write. In fact as the IPMI message is driven + * by command, only write is meaningful. + * @address: This contains the netfn/command of IPMI request message. + * @bits : not used. + * @value : it is an in/out parameter. It points to the IPMI message buffer. + * Before the IPMI message is sent, it represents the actual request + * IPMI message. After the IPMI message is finished, it represents + * the response IPMI message returned by IPMI command. + * @handler_context: IPMI device context. + */ + +static acpi_status +acpi_ipmi_space_handler(u32 function, acpi_physical_address address, + u32 bits, acpi_integer *value, + void *handler_context, void *region_context) +{ + struct acpi_ipmi_msg *tx_msg; + struct acpi_ipmi_device *ipmi_device = handler_context; + int err, rem_time; + acpi_status status; + /* + * IPMI opregion message. + * IPMI message is firstly written to the BMC and system software + * can get the respsonse. So it is unmeaningful for the read access + * of IPMI opregion. + */ + if ((function & ACPI_IO_MASK) == ACPI_READ) + return AE_TYPE; + + if (!ipmi_device->user_interface) + return AE_NOT_EXIST; + + tx_msg = acpi_alloc_ipmi_msg(ipmi_device); + if (!tx_msg) + return AE_NO_MEMORY; + + acpi_format_ipmi_msg(tx_msg, address, value); + mutex_lock(&ipmi_device->tx_msg_lock); + list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list); + mutex_unlock(&ipmi_device->tx_msg_lock); + err = ipmi_request_settime(ipmi_device->user_interface, + &tx_msg->addr, + tx_msg->tx_msgid, + &tx_msg->tx_message, + NULL, 0, 0, 0); + if (err) { + status = AE_ERROR; + goto end_label; + } + rem_time = wait_for_completion_timeout(&tx_msg->tx_complete, + IPMI_TIMEOUT); + acpi_format_ipmi_response(tx_msg, value, rem_time); + status = AE_OK; + +end_label: + mutex_lock(&ipmi_device->tx_msg_lock); + list_del(&tx_msg->head); + mutex_unlock(&ipmi_device->tx_msg_lock); + kfree(tx_msg); + return status; +} + +static void ipmi_remove_space_handler(struct acpi_ipmi_device *ipmi) +{ + if (!test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags)) + return; + + acpi_remove_address_space_handler(ipmi->handle, + ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler); + + clear_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags); +} + +static int ipmi_install_space_handler(struct acpi_ipmi_device *ipmi) +{ + acpi_status status; + + if (test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags)) + return 0; + + status = acpi_install_address_space_handler(ipmi->handle, + ACPI_ADR_SPACE_IPMI, + &acpi_ipmi_space_handler, + NULL, ipmi); + if (ACPI_FAILURE(status)) { + struct pnp_dev *pnp_dev = ipmi->pnp_dev; + dev_warn(&pnp_dev->dev, "Can't register IPMI opregion space " + "handle\n"); + return -EINVAL; + } + set_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags); + return 0; +} + +static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device) +{ + + INIT_LIST_HEAD(&ipmi_device->head); + + mutex_init(&ipmi_device->tx_msg_lock); + INIT_LIST_HEAD(&ipmi_device->tx_msg_list); + ipmi_install_space_handler(ipmi_device); + + list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices); +} + +static void acpi_remove_ipmi_device(struct acpi_ipmi_device *ipmi_device) +{ + /* + * If the IPMI user interface is created, it should be + * destroyed. + */ + if (ipmi_device->user_interface) { + ipmi_destroy_user(ipmi_device->user_interface); + ipmi_device->user_interface = NULL; + } + /* flush the Tx_msg list */ + if (!list_empty(&ipmi_device->tx_msg_list)) + ipmi_flush_tx_msg(ipmi_device); + + list_del(&ipmi_device->head); + ipmi_remove_space_handler(ipmi_device); +} + +static int __init acpi_ipmi_init(void) +{ + int result = 0; + + if (acpi_disabled) + return result; + + mutex_init(&driver_data.ipmi_lock); + + result = ipmi_smi_watcher_register(&driver_data.bmc_events); + + return result; +} + +static void __exit acpi_ipmi_exit(void) +{ + struct acpi_ipmi_device *ipmi_device, *temp; + + if (acpi_disabled) + return; + + ipmi_smi_watcher_unregister(&driver_data.bmc_events); + + /* + * When one smi_watcher is unregistered, it is only deleted + * from the smi_watcher list. But the smi_gone callback function + * is not called. So explicitly uninstall the ACPI IPMI oregion + * handler and free it. + */ + mutex_lock(&driver_data.ipmi_lock); + list_for_each_entry_safe(ipmi_device, temp, + &driver_data.ipmi_devices, head) { + acpi_remove_ipmi_device(ipmi_device); + put_device(ipmi_device->smi_data.dev); + kfree(ipmi_device); + } + mutex_unlock(&driver_data.ipmi_lock); +} + +module_init(acpi_ipmi_init); +module_exit(acpi_ipmi_exit); -- cgit v1.2.3 From ad6d42670279da8f33f633f8a96a67cd7ef3b1da Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 14 Dec 2010 11:38:18 +0100 Subject: HID: hid-mosart: ignore buttons report This commit allows the device to be recognized as a touchscreen, and not a touchpad by xf86-input-evdev. The device has 2 modes. The first one is an emulation of a touchscreen by sending left and right button, and the second mode is the one used in dual-touch (sending trackingID, touch and else). That's why there is a hid report containing left and right buttons (9000001 and 9000002). The point is that xorg relies on these fields to determine if it's a touchpad or a touchscreen. Clearing the report (return -1) makes xorg detecting it out of the box as a quite pleasant (dual)touchscreen. Signed-off-by: Benjamin Tissoires Acked-by: Chase Douglas Signed-off-by: Jiri Kosina --- drivers/hid/hid-mosart.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index ac5421d568f1..acd8a4983c09 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -90,6 +90,10 @@ static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi, case 0xff000000: /* ignore HID features */ return -1; + + case HID_UP_BUTTON: + /* ignore buttons */ + return -1; } return 0; -- cgit v1.2.3 From c25bcd340033bf5b8dc30c16a99e64259f099446 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 13 Dec 2010 15:59:13 +0100 Subject: HID: hid-mosart: support suspend/resume The device has 2 modes. The first one is an emulation of a touchscreen by sending left and right button, and the second mode is the one used in dual-touch (sending trackingID, touch and else). In case of a suspend/resume, the device switch back to the first mode described above (with left and right buttons). This adds a hook in .reset_resume for the device to be switched to the correct mode (I just copied the code in mosart_probe). Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-mosart.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index acd8a4983c09..15d03811f96a 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -234,6 +234,19 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } +#ifdef CONFIG_PM +static int mosart_reset_resume(struct hid_device *hdev) +{ + struct hid_report_enum *re = hdev->report_enum + + HID_FEATURE_REPORT; + struct hid_report *r = re->report_id_hash[7]; + + r->field[0]->value[0] = 0x02; + usbhid_submit_report(hdev, r, USB_DIR_OUT); + return 0; +} +#endif + static void mosart_remove(struct hid_device *hdev) { hid_hw_stop(hdev); @@ -262,6 +275,9 @@ static struct hid_driver mosart_driver = { .input_mapped = mosart_input_mapped, .usage_table = mosart_grabbed_usages, .event = mosart_event, +#ifdef CONFIG_PM + .reset_resume = mosart_reset_resume, +#endif }; static int __init mosart_init(void) -- cgit v1.2.3 From b13c2b96bf15b9dd0f1a45fd788f3a3025c5aec6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Dec 2010 16:54:50 +0000 Subject: drm/i915/ringbuffer: Make IRQ refcnting atomic In order to enforce the correct memory barriers for irq get/put, we need to perform the actual counting using atomic operations. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 37 ++++++++++++++------------- drivers/gpu/drm/i915/i915_irq.c | 17 +++++++------ drivers/gpu/drm/i915/intel_ringbuffer.c | 44 +++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +-- 4 files changed, 56 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 27fa2a1b26a5..726c2ccd674c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2000,17 +2000,19 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, trace_i915_gem_request_wait_begin(dev, seqno); ring->waiting_seqno = seqno; - ring->irq_get(ring); - if (interruptible) - ret = wait_event_interruptible(ring->irq_queue, - i915_seqno_passed(ring->get_seqno(ring), seqno) - || atomic_read(&dev_priv->mm.wedged)); - else - wait_event(ring->irq_queue, - i915_seqno_passed(ring->get_seqno(ring), seqno) - || atomic_read(&dev_priv->mm.wedged)); + ret = -ENODEV; + if (ring->irq_get(ring)) { + if (interruptible) + ret = wait_event_interruptible(ring->irq_queue, + i915_seqno_passed(ring->get_seqno(ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); + else + wait_event(ring->irq_queue, + i915_seqno_passed(ring->get_seqno(ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); - ring->irq_put(ring); + ring->irq_put(ring); + } ring->waiting_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); @@ -3157,14 +3159,15 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) * generation is designed to be run atomically and so is * lockless. */ - ring->irq_get(ring); - ret = wait_event_interruptible(ring->irq_queue, - i915_seqno_passed(ring->get_seqno(ring), seqno) - || atomic_read(&dev_priv->mm.wedged)); - ring->irq_put(ring); + if (ring->irq_get(ring)) { + ret = wait_event_interruptible(ring->irq_queue, + i915_seqno_passed(ring->get_seqno(ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); + ring->irq_put(ring); - if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) - ret = -EIO; + if (ret == 0 && atomic_read(&dev_priv->mm.wedged)) + ret = -EIO; + } } if (ret == 0) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 02e4dd82f754..2ddb98b5c90f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1186,10 +1186,9 @@ void i915_trace_irq_get(struct drm_device *dev, u32 seqno) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct intel_ring_buffer *ring = LP_RING(dev_priv); - if (dev_priv->trace_irq_seqno == 0) - ring->irq_get(ring); - - dev_priv->trace_irq_seqno = seqno; + if (dev_priv->trace_irq_seqno == 0 && + ring->irq_get(ring)) + dev_priv->trace_irq_seqno = seqno; } static int i915_wait_irq(struct drm_device * dev, int irq_nr) @@ -1211,10 +1210,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - ring->irq_get(ring); - DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ, - READ_BREADCRUMB(dev_priv) >= irq_nr); - ring->irq_put(ring); + ret = -ENODEV; + if (ring->irq_get(ring)) { + DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ, + READ_BREADCRUMB(dev_priv) >= irq_nr); + ring->irq_put(ring); + } if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 74b99718a1fb..a3fd993e0de0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -327,25 +327,28 @@ ring_get_seqno(struct intel_ring_buffer *ring) return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } -static void +static bool render_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; - if (dev->irq_enabled && ++ring->irq_refcount == 1) { + if (!dev->irq_enabled) + return false; + + if (atomic_inc_return(&ring->irq_refcount) == 1) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - if (HAS_PCH_SPLIT(dev)) ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } + + return true; } static void @@ -353,8 +356,7 @@ render_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; - BUG_ON(dev->irq_enabled && ring->irq_refcount == 0); - if (dev->irq_enabled && --ring->irq_refcount == 0) { + if (atomic_dec_and_test(&ring->irq_refcount)) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; @@ -417,12 +419,15 @@ ring_add_request(struct intel_ring_buffer *ring, return 0; } -static void +static bool ring_get_irq(struct intel_ring_buffer *ring, u32 flag) { struct drm_device *dev = ring->dev; - if (dev->irq_enabled && ++ring->irq_refcount == 1) { + if (!dev->irq_enabled) + return false; + + if (atomic_inc_return(&ring->irq_refcount) == 1) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; @@ -430,6 +435,8 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag) ironlake_enable_graphics_irq(dev_priv, flag); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } + + return true; } static void @@ -437,7 +444,7 @@ ring_put_irq(struct intel_ring_buffer *ring, u32 flag) { struct drm_device *dev = ring->dev; - if (dev->irq_enabled && --ring->irq_refcount == 0) { + if (atomic_dec_and_test(&ring->irq_refcount)) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; @@ -447,16 +454,15 @@ ring_put_irq(struct intel_ring_buffer *ring, u32 flag) } } - -static void +static bool bsd_ring_get_irq(struct intel_ring_buffer *ring) { - ring_get_irq(ring, GT_BSD_USER_INTERRUPT); + return ring_get_irq(ring, GT_BSD_USER_INTERRUPT); } static void bsd_ring_put_irq(struct intel_ring_buffer *ring) { - ring_put_irq(ring, GT_BSD_USER_INTERRUPT); + ring_put_irq(ring, GT_BSD_USER_INTERRUPT); } static int @@ -846,16 +852,16 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, return 0; } -static void +static bool gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring) { - ring_get_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); + return ring_get_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); } static void gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) { - ring_put_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); + ring_put_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); } /* ring buffer for Video Codec for Gen6+ */ @@ -876,16 +882,16 @@ static const struct intel_ring_buffer gen6_bsd_ring = { /* Blitter support (SandyBridge+) */ -static void +static bool blt_ring_get_irq(struct intel_ring_buffer *ring) { - ring_get_irq(ring, GT_BLT_USER_INTERRUPT); + return ring_get_irq(ring, GT_BLT_USER_INTERRUPT); } static void blt_ring_put_irq(struct intel_ring_buffer *ring) { - ring_put_irq(ring, GT_BLT_USER_INTERRUPT); + ring_put_irq(ring, GT_BLT_USER_INTERRUPT); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9652e4600b5e..8e2e357ad6ee 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -54,8 +54,8 @@ struct intel_ring_buffer { u32 irq_seqno; /* last seq seem at irq time */ u32 waiting_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; - u32 irq_refcount; - void (*irq_get)(struct intel_ring_buffer *ring); + atomic_t irq_refcount; + bool __must_check (*irq_get)(struct intel_ring_buffer *ring); void (*irq_put)(struct intel_ring_buffer *ring); int (*init)(struct intel_ring_buffer *ring); -- cgit v1.2.3 From b5ba177d8d71f011c23b1cabec99fdaddae65c4d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Dec 2010 12:17:15 +0000 Subject: drm/i915: Poll for seqno completion if IRQ is disabled Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32288 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 726c2ccd674c..5a0fbe59dd5b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2000,7 +2000,6 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, trace_i915_gem_request_wait_begin(dev, seqno); ring->waiting_seqno = seqno; - ret = -ENODEV; if (ring->irq_get(ring)) { if (interruptible) ret = wait_event_interruptible(ring->irq_queue, @@ -2012,7 +2011,10 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, || atomic_read(&dev_priv->mm.wedged)); ring->irq_put(ring); - } + } else if (wait_for(i915_seqno_passed(ring->get_seqno(ring), + seqno) || + atomic_read(&dev_priv->mm.wedged), 3000)) + ret = -EBUSY; ring->waiting_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); -- cgit v1.2.3 From 1874542d952bbea01997191aee868b472555fd9a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 14 Dec 2010 11:56:56 +0100 Subject: HID: replace offsets values with their corresponding BTN_* defines Instead of using magic values, use their corresponding BTN_* defines from linux/input.h. Signed-off-by: Florian Fainelli Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c0757821b1fc..e60fdb88101f 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -319,21 +319,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel switch (field->application) { case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; + case HID_GD_POINTER: code += BTN_MOUSE; break; case HID_GD_JOYSTICK: if (code <= 0xf) code += BTN_JOYSTICK; else code += BTN_TRIGGER_HAPPY; break; - case HID_GD_GAMEPAD: code += 0x130; break; + case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break; default: switch (field->physical) { case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: code += 0x100; + case HID_GD_POINTER: code += BTN_MOUSE; break; + case HID_GD_JOYSTICK: code += BTN_JOYSTICK; break; + case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break; + default: code += BTN_MISC; } } -- cgit v1.2.3 From 1b894b59247728b02d6363d458088cf438f5ec92 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Dec 2010 20:04:54 +0000 Subject: drm/i915: Pass clock limits down to PLL matcher As we already know the limits for the hardware clock, pass it down rather than recomputing them for each match. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17c213fef0ec..f2d50141e0c2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -642,26 +642,23 @@ static const intel_limit_t intel_limits_ironlake_display_port = { .find_pll = intel_find_pll_ironlake_dp, }; -static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc) +static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, + int refclk) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; - int refclk = 120; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if (dev_priv->lvds_use_ssc && dev_priv->lvds_ssc_freq == 100) - refclk = 100; - if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) { /* LVDS dual channel */ - if (refclk == 100) + if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; else limit = &intel_limits_ironlake_dual_lvds; } else { - if (refclk == 100) + if (refclk == 100000) limit = &intel_limits_ironlake_single_lvds_100m; else limit = &intel_limits_ironlake_single_lvds; @@ -702,13 +699,13 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) return limit; } -static const intel_limit_t *intel_limit(struct drm_crtc *crtc) +static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk) { struct drm_device *dev = crtc->dev; const intel_limit_t *limit; if (HAS_PCH_SPLIT(dev)) - limit = intel_ironlake_limit(crtc); + limit = intel_ironlake_limit(crtc, refclk); else if (IS_G4X(dev)) { limit = intel_g4x_limit(crtc); } else if (IS_PINEVIEW(dev)) { @@ -773,11 +770,10 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type) * the given connectors. */ -static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) +static bool intel_PLL_is_valid(struct drm_device *dev, + const intel_limit_t *limit, + const intel_clock_t *clock) { - const intel_limit_t *limit = intel_limit (crtc); - struct drm_device *dev = crtc->dev; - if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) INTELPllInvalid ("p1 out of range\n"); if (clock->p < limit->p.min || limit->p.max < clock->p) @@ -849,8 +845,8 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int this_err; intel_clock(dev, refclk, &clock); - - if (!intel_PLL_is_valid(crtc, &clock)) + if (!intel_PLL_is_valid(dev, limit, + &clock)) continue; this_err = abs(clock.dot - target); @@ -912,9 +908,11 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int this_err; intel_clock(dev, refclk, &clock); - if (!intel_PLL_is_valid(crtc, &clock)) + if (!intel_PLL_is_valid(dev, limit, + &clock)) continue; - this_err = abs(clock.dot - target) ; + + this_err = abs(clock.dot - target); if (this_err < err_most) { *best_clock = clock; err_most = this_err; @@ -3655,7 +3653,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * refclk, or FALSE. The returned values represent the clock equation: * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. */ - limit = intel_limit(crtc); + limit = intel_limit(crtc, refclk); ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); -- cgit v1.2.3 From c6df541c00e53a4fdff7a130d4365f848075adcc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Dec 2010 09:56:50 +0000 Subject: Revert "drm/i915: Avoid using PIPE_CONTROL on Ironlake" Restore PIPE_CONTROL once again just for Ironlake, as it appears that MI_USER_INTERRUPT does not have the same coherency guarantees, that is on Ironlake the interrupt following a GPU write is not guaranteed to arrive after the write is coherent from the CPU, as it does on the other generations. Reported-by: Zhenyu Wang Reported-by: Shuang He Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32402 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 3 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 162 +++++++++++++++++++++++++++++++- 2 files changed, 162 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2ddb98b5c90f..e4a2e2c3dbe3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -349,7 +349,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) READ_BREADCRUMB(dev_priv); } - if (gt_iir & GT_USER_INTERRUPT) + if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) notify_ring(dev, &dev_priv->ring[RCS]); if (gt_iir & bsd_usr_interrupt) notify_ring(dev, &dev_priv->ring[VCS]); @@ -1558,6 +1558,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) else render_irqs = GT_USER_INTERRUPT | + GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT; I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a3fd993e0de0..56bc95c056dd 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -209,6 +209,78 @@ static int init_ring_common(struct intel_ring_buffer *ring) return 0; } +/* + * 965+ support PIPE_CONTROL commands, which provide finer grained control + * over cache flushing. + */ +struct pipe_control { + struct drm_i915_gem_object *obj; + volatile u32 *cpu_page; + u32 gtt_offset; +}; + +static int +init_pipe_control(struct intel_ring_buffer *ring) +{ + struct pipe_control *pc; + struct drm_i915_gem_object *obj; + int ret; + + if (ring->private) + return 0; + + pc = kmalloc(sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + obj = i915_gem_alloc_object(ring->dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate seqno page\n"); + ret = -ENOMEM; + goto err; + } + obj->agp_type = AGP_USER_CACHED_MEMORY; + + ret = i915_gem_object_pin(obj, 4096, true); + if (ret) + goto err_unref; + + pc->gtt_offset = obj->gtt_offset; + pc->cpu_page = kmap(obj->pages[0]); + if (pc->cpu_page == NULL) + goto err_unpin; + + pc->obj = obj; + ring->private = pc; + return 0; + +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(&obj->base); +err: + kfree(pc); + return ret; +} + +static void +cleanup_pipe_control(struct intel_ring_buffer *ring) +{ + struct pipe_control *pc = ring->private; + struct drm_i915_gem_object *obj; + + if (!ring->private) + return; + + obj = pc->obj; + kunmap(obj->pages[0]); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + + kfree(pc); + ring->private = NULL; +} + static int init_render_ring(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -222,9 +294,24 @@ static int init_render_ring(struct intel_ring_buffer *ring) I915_WRITE(MI_MODE, mode); } + if (INTEL_INFO(dev)->gen >= 6) { + } else if (IS_GEN5(dev)) { + ret = init_pipe_control(ring); + if (ret) + return ret; + } + return ret; } +static void render_ring_cleanup(struct intel_ring_buffer *ring) +{ + if (!ring->private) + return; + + cleanup_pipe_control(ring); +} + static void update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno) { @@ -299,6 +386,65 @@ intel_ring_sync(struct intel_ring_buffer *ring, return 0; } +#define PIPE_CONTROL_FLUSH(ring__, addr__) \ +do { \ + intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ + PIPE_CONTROL_DEPTH_STALL | 2); \ + intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT); \ + intel_ring_emit(ring__, 0); \ + intel_ring_emit(ring__, 0); \ +} while (0) + +static int +pc_render_add_request(struct intel_ring_buffer *ring, + u32 *result) +{ + struct drm_device *dev = ring->dev; + u32 seqno = i915_gem_get_seqno(dev); + struct pipe_control *pc = ring->private; + u32 scratch_addr = pc->gtt_offset + 128; + int ret; + + /* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently + * incoherent with writes to memory, i.e. completely fubar, + * so we need to use PIPE_NOTIFY instead. + * + * However, we also need to workaround the qword write + * incoherence by flushing the 6 PIPE_NOTIFY buffers out to + * memory before requesting an interrupt. + */ + ret = intel_ring_begin(ring, 32); + if (ret) + return ret; + + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(ring, scratch_addr); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, seqno); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + + *result = seqno; + return 0; +} + static int render_ring_add_request(struct intel_ring_buffer *ring, u32 *result) @@ -327,6 +473,13 @@ ring_get_seqno(struct intel_ring_buffer *ring) return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } +static u32 +pc_render_get_seqno(struct intel_ring_buffer *ring) +{ + struct pipe_control *pc = ring->private; + return pc->cpu_page[0]; +} + static bool render_ring_get_irq(struct intel_ring_buffer *ring) { @@ -342,7 +495,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) ironlake_enable_graphics_irq(dev_priv, - GT_USER_INTERRUPT); + GT_PIPE_NOTIFY | GT_USER_INTERRUPT); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -363,7 +516,8 @@ render_ring_put_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) ironlake_disable_graphics_irq(dev_priv, - GT_USER_INTERRUPT); + GT_USER_INTERRUPT | + GT_PIPE_NOTIFY); else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -776,6 +930,7 @@ static const struct intel_ring_buffer render_ring = { .irq_get = render_ring_get_irq, .irq_put = render_ring_put_irq, .dispatch_execbuffer = render_ring_dispatch_execbuffer, + .cleanup = render_ring_cleanup, }; /* ring buffer for bit-stream decoder */ @@ -1010,6 +1165,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev) *ring = render_ring; if (INTEL_INFO(dev)->gen >= 6) { ring->add_request = gen6_add_request; + } else if (IS_GEN5(dev)) { + ring->add_request = pc_render_add_request; + ring->get_seqno = pc_render_get_seqno; } if (!I915_NEED_GFX_HWS(dev)) { -- cgit v1.2.3 From b7f1de289c50beb4998611ba5373e539efd0f79f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Dec 2010 16:09:31 +0000 Subject: drm/i915: Wait for vblank before unpinning old fb Be paranoid and ensure that the vblank has passed and the scanout has switched to the new fb, before unpinning the old one and possibly tearing down its PTEs. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f2d50141e0c2..840bfc3ae719 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1626,8 +1626,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - if (old_fb) + if (old_fb) { + intel_wait_for_vblank(dev, intel_crtc->pipe); i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj); + } mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 1398261a2e84c537c409259cfe9db3d0abcd9f99 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Wed, 15 Dec 2010 15:42:31 +0800 Subject: drm/i915: Add self-refresh support on Sandybridge Add the support of memory self-refresh on Sandybridge, which is now support 3 levels of watermarks and the source of the latency values for watermarks has changed. On Sandybridge, the LP0 WM value is not hardcoded any more. All the latency value is now should be extracted from MCHBAR SSKPD register. And the MCHBAR base address is changed, too. For the WM values, if any calculated watermark values is larger than the maximum value that can be programmed into the associated watermark register, that watermark must be disabled. Signed-off-by: Yuanhan Liu [ickle: remove duplicate compute routines and fixup for checkpatch] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 40 +++++ drivers/gpu/drm/i915/intel_display.c | 310 +++++++++++++++++++++++++++++++++-- 3 files changed, 334 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 22821994b35a..864e75d762e6 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -933,7 +933,7 @@ static int i915_sr_status(struct seq_file *m, void *unused) drm_i915_private_t *dev_priv = dev->dev_private; bool sr_enabled = false; - if (IS_GEN5(dev)) + if (HAS_PCH_SPLIT(dev)) sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN; else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev)) sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b284c13fd632..61ef98db9ff0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -596,6 +596,8 @@ #define ILK_DISPLAY_CHICKEN1 0x42000 #define ILK_FBCQ_DIS (1<<22) +#define ILK_PABSTRETCH_DIS (1<<21) + /* * GPIO regs @@ -955,6 +957,8 @@ */ #define MCHBAR_MIRROR_BASE 0x10000 +#define MCHBAR_MIRROR_BASE_SNB 0x140000 + /** 915-945 and GM965 MCH register controlling DRAM channel access */ #define DCC 0x10200 #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) @@ -2346,6 +2350,40 @@ #define ILK_FIFO_LINE_SIZE 64 +/* define the WM info on Sandybridge */ +#define SNB_DISPLAY_FIFO 128 +#define SNB_DISPLAY_MAXWM 0x7f /* bit 16:22 */ +#define SNB_DISPLAY_DFTWM 8 +#define SNB_CURSOR_FIFO 32 +#define SNB_CURSOR_MAXWM 0x1f /* bit 4:0 */ +#define SNB_CURSOR_DFTWM 8 + +#define SNB_DISPLAY_SR_FIFO 512 +#define SNB_DISPLAY_MAX_SRWM 0x1ff /* bit 16:8 */ +#define SNB_DISPLAY_DFT_SRWM 0x3f +#define SNB_CURSOR_SR_FIFO 64 +#define SNB_CURSOR_MAX_SRWM 0x3f /* bit 5:0 */ +#define SNB_CURSOR_DFT_SRWM 8 + +#define SNB_FBC_MAX_SRWM 0xf /* bit 23:20 */ + +#define SNB_FIFO_LINE_SIZE 64 + + +/* the address where we get all kinds of latency value */ +#define SSKPD 0x5d10 +#define SSKPD_WM_MASK 0x3f +#define SSKPD_WM0_SHIFT 0 +#define SSKPD_WM1_SHIFT 8 +#define SSKPD_WM2_SHIFT 16 +#define SSKPD_WM3_SHIFT 24 + +#define SNB_LATENCY(shift) (I915_READ(MCHBAR_MIRROR_BASE_SNB + SSKPD) >> (shift) & SSKPD_WM_MASK) +#define SNB_READ_WM0_LATENCY() SNB_LATENCY(SSKPD_WM0_SHIFT) +#define SNB_READ_WM1_LATENCY() SNB_LATENCY(SSKPD_WM1_SHIFT) +#define SNB_READ_WM2_LATENCY() SNB_LATENCY(SSKPD_WM2_SHIFT) +#define SNB_READ_WM3_LATENCY() SNB_LATENCY(SSKPD_WM3_SHIFT) + /* * The two pipe frame counter registers are not synchronized, so * reading a stable value is somewhat tricky. The following code @@ -2651,6 +2689,8 @@ #define ILK_VSDPFD_FULL (1<<21) #define ILK_DSPCLK_GATE 0x42020 #define ILK_DPARB_CLK_GATE (1<<5) +#define ILK_DPFD_CLK_GATE (1<<7) + /* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */ #define ILK_CLK_FBC (1<<7) #define ILK_DPFC_DIS1 (1<<8) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 840bfc3ae719..eaf2bc6b537d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2845,6 +2845,39 @@ static struct intel_watermark_params ironlake_cursor_srwm_info = { ILK_FIFO_LINE_SIZE }; +static struct intel_watermark_params sandybridge_display_wm_info = { + SNB_DISPLAY_FIFO, + SNB_DISPLAY_MAXWM, + SNB_DISPLAY_DFTWM, + 2, + SNB_FIFO_LINE_SIZE +}; + +static struct intel_watermark_params sandybridge_cursor_wm_info = { + SNB_CURSOR_FIFO, + SNB_CURSOR_MAXWM, + SNB_CURSOR_DFTWM, + 2, + SNB_FIFO_LINE_SIZE +}; + +static struct intel_watermark_params sandybridge_display_srwm_info = { + SNB_DISPLAY_SR_FIFO, + SNB_DISPLAY_MAX_SRWM, + SNB_DISPLAY_DFT_SRWM, + 2, + SNB_FIFO_LINE_SIZE +}; + +static struct intel_watermark_params sandybridge_cursor_srwm_info = { + SNB_CURSOR_SR_FIFO, + SNB_CURSOR_MAX_SRWM, + SNB_CURSOR_DFT_SRWM, + 2, + SNB_FIFO_LINE_SIZE +}; + + /** * intel_calculate_wm - calculate watermark level * @clock_in_khz: pixel clock @@ -3378,6 +3411,10 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, static bool ironlake_compute_wm0(struct drm_device *dev, int pipe, + const struct intel_watermark_params *display, + int display_latency, + const struct intel_watermark_params *cursor, + int cursor_latency, int *plane_wm, int *cursor_wm) { @@ -3395,22 +3432,20 @@ static bool ironlake_compute_wm0(struct drm_device *dev, pixel_size = crtc->fb->bits_per_pixel / 8; /* Use the small buffer method to calculate plane watermark */ - entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000; - entries = DIV_ROUND_UP(entries, - ironlake_display_wm_info.cacheline_size); - *plane_wm = entries + ironlake_display_wm_info.guard_size; - if (*plane_wm > (int)ironlake_display_wm_info.max_wm) - *plane_wm = ironlake_display_wm_info.max_wm; + entries = ((clock * pixel_size / 1000) * display_latency * 100) / 1000; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *plane_wm = entries + display->guard_size; + if (*plane_wm > (int)display->max_wm) + *plane_wm = display->max_wm; /* Use the large buffer method to calculate cursor watermark */ line_time_us = ((htotal * 1000) / clock); - line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; + line_count = (cursor_latency * 100 / line_time_us + 1000) / 1000; entries = line_count * 64 * pixel_size; - entries = DIV_ROUND_UP(entries, - ironlake_cursor_wm_info.cacheline_size); - *cursor_wm = entries + ironlake_cursor_wm_info.guard_size; - if (*cursor_wm > ironlake_cursor_wm_info.max_wm) - *cursor_wm = ironlake_cursor_wm_info.max_wm; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + if (*cursor_wm > (int)cursor->max_wm) + *cursor_wm = (int)cursor->max_wm; return true; } @@ -3425,7 +3460,12 @@ static void ironlake_update_wm(struct drm_device *dev, int tmp; enabled = 0; - if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) { + if (ironlake_compute_wm0(dev, 0, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { I915_WRITE(WM0_PIPEA_ILK, (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); DRM_DEBUG_KMS("FIFO watermarks For pipe A -" @@ -3434,7 +3474,12 @@ static void ironlake_update_wm(struct drm_device *dev, enabled++; } - if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) { + if (ironlake_compute_wm0(dev, 1, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { I915_WRITE(WM0_PIPEB_ILK, (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); DRM_DEBUG_KMS("FIFO watermarks For pipe B -" @@ -3500,6 +3545,197 @@ static void ironlake_update_wm(struct drm_device *dev, /* XXX setup WM2 and WM3 */ } +/* + * Check the wm result. + * + * If any calculated watermark values is larger than the maximum value that + * can be programmed into the associated watermark register, that watermark + * must be disabled. + * + * Also return true if all of those watermark values is 0, which is set by + * sandybridge_compute_srwm, to indicate the latency is ZERO. + */ +static bool sandybridge_check_srwm(struct drm_device *dev, int level, + int fbc_wm, int display_wm, int cursor_wm) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," + " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); + + if (fbc_wm > SNB_FBC_MAX_SRWM) { + DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", + fbc_wm, SNB_FBC_MAX_SRWM, level); + + /* fbc has it's own way to disable FBC WM */ + I915_WRITE(DISP_ARB_CTL, + I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); + return false; + } + + if (display_wm > SNB_DISPLAY_MAX_SRWM) { + DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", + display_wm, SNB_DISPLAY_MAX_SRWM, level); + return false; + } + + if (cursor_wm > SNB_CURSOR_MAX_SRWM) { + DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", + cursor_wm, SNB_CURSOR_MAX_SRWM, level); + return false; + } + + if (!(fbc_wm || display_wm || cursor_wm)) { + DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); + return false; + } + + return true; +} + +/* + * Compute watermark values of WM[1-3], + */ +static bool sandybridge_compute_srwm(struct drm_device *dev, int level, + int hdisplay, int htotal, int pixel_size, + int clock, int latency_ns, int *fbc_wm, + int *display_wm, int *cursor_wm) +{ + + unsigned long line_time_us; + int small, large; + int entries; + int line_count, line_size; + + if (!latency_ns) { + *fbc_wm = *display_wm = *cursor_wm = 0; + return false; + } + + line_time_us = (htotal * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = hdisplay * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), + sandybridge_display_srwm_info.cacheline_size); + *display_wm = entries + sandybridge_display_srwm_info.guard_size; + + /* + * Spec said: + * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 + */ + *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; + + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, + sandybridge_cursor_srwm_info.cacheline_size); + *cursor_wm = entries + sandybridge_cursor_srwm_info.guard_size; + + return sandybridge_check_srwm(dev, level, + *fbc_wm, *display_wm, *cursor_wm); +} + +static void sandybridge_update_wm(struct drm_device *dev, + int planea_clock, int planeb_clock, + int hdisplay, int htotal, + int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY(); + int fbc_wm, plane_wm, cursor_wm, enabled; + int clock; + + enabled = 0; + if (ironlake_compute_wm0(dev, 0, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEA_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled++; + } + + if (ironlake_compute_wm0(dev, 1, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEB_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled++; + } + + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + * + * SNB support 3 levels of watermark. + * + * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, + * and disabled in the descending order + * + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (enabled != 1) + return; + + clock = planea_clock ? planea_clock : planeb_clock; + + /* WM1 */ + if (!sandybridge_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, + clock, SNB_READ_WM1_LATENCY() * 500, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!sandybridge_compute_srwm(dev, 2, + hdisplay, htotal, pixel_size, + clock, SNB_READ_WM2_LATENCY() * 500, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM3 */ + if (!sandybridge_compute_srwm(dev, 3, + hdisplay, htotal, pixel_size, + clock, SNB_READ_WM3_LATENCY() * 500, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM3_LP_ILK, + WM3_LP_EN | + (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); +} + /** * intel_update_watermarks - update FIFO watermark values based on current modes * @@ -5975,9 +6211,9 @@ void intel_enable_clock_gating(struct drm_device *dev) I915_WRITE(DISP_ARB_CTL, (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); } /* * Based on the document from hardware guys the following bits @@ -6010,6 +6246,38 @@ void intel_enable_clock_gating(struct drm_device *dev) _3D_CHICKEN2_WM_READ_PIPELINED); } + if (IS_GEN6(dev)) { + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* + * According to the spec the following bits should be + * set in order to enable memory self-refresh and fbc: + * The bit21 and bit22 of 0x42000 + * The bit21 and bit22 of 0x42004 + * The bit5 and bit7 of 0x42020 + * The bit14 of 0x70180 + * The bit14 of 0x71180 + */ + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE | + ILK_DPFD_CLK_GATE); + + I915_WRITE(DSPACNTR, + I915_READ(DSPACNTR) | + DISPPLANE_TRICKLE_FEED_DISABLE); + I915_WRITE(DSPBCNTR, + I915_READ(DSPBCNTR) | + DISPPLANE_TRICKLE_FEED_DISABLE); + } } else if (IS_G4X(dev)) { uint32_t dspclk_gate; I915_WRITE(RENCLK_GATE_D1, 0); @@ -6176,6 +6444,14 @@ static void intel_init_display(struct drm_device *dev) "Disable CxSR\n"); dev_priv->display.update_wm = NULL; } + } else if (IS_GEN6(dev)) { + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } } else dev_priv->display.update_wm = NULL; } else if (IS_PINEVIEW(dev)) { -- cgit v1.2.3 From 9c04f015ebc2cc2cca5a4a576deb82a311578edc Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Wed, 15 Dec 2010 15:42:32 +0800 Subject: drm/i915: Add frame buffer compression on Sandybridge Add frame buffer compression on Sandybridge. The method is similar to Ironlake, except that two new registers of type GTTMMADR must be written with the right fence info. Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 10 ++++++++++ drivers/gpu/drm/i915/intel_display.c | 8 +++++++- 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e9fb8953c606..3f7b20392e26 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1078,7 +1078,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) if (!cfb_base) goto err_fb; - if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) { + if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) { compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen, 4096, 4096, 0); if (compressed_llb) @@ -1096,7 +1096,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) intel_disable_fbc(dev); dev_priv->compressed_fb = compressed_fb; - if (IS_IRONLAKE_M(dev)) + if (HAS_PCH_SPLIT(dev)) I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); else if (IS_GM45(dev)) { I915_WRITE(DPFC_CB_BASE, compressed_fb->start); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5f20cd988612..bdb29b2a01ed 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -165,6 +165,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { static const struct intel_device_info intel_sandybridge_m_info = { .gen = 6, .is_mobile = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_fbc = 1, .has_bsd_ring = 1, .has_blt_ring = 1, }; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 61ef98db9ff0..820e9dfaadc7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -599,6 +599,16 @@ #define ILK_PABSTRETCH_DIS (1<<21) +/* + * Framebuffer compression for Sandybridge + * + * The following two registers are of type GTTMMADR + */ +#define SNB_DPFC_CTL_SA 0x100100 +#define SNB_CPU_FENCE_ENABLE (1<<29) +#define DPFC_CPU_FENCE_OFFSET 0x100104 + + /* * GPIO regs */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eaf2bc6b537d..8645a974a499 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1262,6 +1262,12 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); + if (IS_GEN6(dev)) { + I915_WRITE(SNB_DPFC_CTL_SA, + SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + } + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); } @@ -6395,7 +6401,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.dpms = i9xx_crtc_dpms; if (I915_HAS_FBC(dev)) { - if (IS_IRONLAKE_M(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->display.fbc_enabled = ironlake_fbc_enabled; dev_priv->display.enable_fbc = ironlake_enable_fbc; dev_priv->display.disable_fbc = ironlake_disable_fbc; -- cgit v1.2.3 From c45aadabb961501b3e64bc92d0bf12fdce26d37d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Thu, 16 Dec 2010 10:30:35 +1000 Subject: drm/nv50: fix a couple of vm init issues Fixes overwriting the first page table entry when testing that the PRAMIN BAR can be correctly read/written, and adds an additional bar flush after poking the BAR3 control regs. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_instmem.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 38f30270cb9f..adac4da98f7e 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -182,16 +182,17 @@ nv50_instmem_init(struct drm_device *dev) nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); nv_wr32(dev, 0x00170c, 0x80000000 | (priv->bar3_dmaobj->cinst >> 4)); - tmp = nv_ri32(dev, 0); - nv_wi32(dev, 0, ~tmp); - if (nv_ri32(dev, 0) != ~tmp) { + dev_priv->engine.instmem.flush(dev); + dev_priv->ramin_available = true; + + tmp = nv_ro32(chan->ramin, 0); + nv_wo32(chan->ramin, 0, ~tmp); + if (nv_ro32(chan->ramin, 0) != ~tmp) { NV_ERROR(dev, "PRAMIN readback failed\n"); ret = -EIO; goto error; } - nv_wi32(dev, 0, tmp); - - dev_priv->ramin_available = true; + nv_wo32(chan->ramin, 0, tmp); /* BAR1 */ ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, -- cgit v1.2.3 From 99ee7fac189893c90145a22b86bbcfdc98f69a9c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 23 Nov 2010 11:47:49 +1000 Subject: drm/radeon: add initial tracepoint support. this adds a bo create, and fence seq tracking tracepoints. This is just an initial set to play around with, we should investigate what others we need would be useful. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 5 +- drivers/gpu/drm/radeon/radeon_fence.c | 4 ++ drivers/gpu/drm/radeon/radeon_object.c | 2 + drivers/gpu/drm/radeon/radeon_trace.h | 82 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_trace_points.c | 9 +++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/radeon/radeon_trace.h create mode 100644 drivers/gpu/drm/radeon/radeon_trace_points.c (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 6cae4f2028d2..e97e6f842699 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -65,10 +65,13 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ - evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o + evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ + radeon_trace_points.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o radeon-$(CONFIG_ACPI) += radeon_acpi.o obj-$(CONFIG_DRM_RADEON)+= radeon.o + +CFLAGS_radeon_trace_points.o := -I$(src) \ No newline at end of file diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index daacb281dfaf..171b0b2e3a64 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -38,6 +38,7 @@ #include "drm.h" #include "radeon_reg.h" #include "radeon.h" +#include "radeon_trace.h" int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) { @@ -57,6 +58,7 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) } else radeon_fence_ring_emit(rdev, fence); + trace_radeon_fence_emit(rdev->ddev, fence->seq); fence->emited = true; list_del(&fence->list); list_add_tail(&fence->list, &rdev->fence_drv.emited); @@ -213,6 +215,7 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) retry: /* save current sequence used to check for GPU lockup */ seq = rdev->fence_drv.last_seq; + trace_radeon_fence_wait_begin(rdev->ddev, seq); if (intr) { radeon_irq_kms_sw_irq_get(rdev); r = wait_event_interruptible_timeout(rdev->fence_drv.queue, @@ -227,6 +230,7 @@ retry: radeon_fence_signaled(fence), timeout); radeon_irq_kms_sw_irq_put(rdev); } + trace_radeon_fence_wait_end(rdev->ddev, seq); if (unlikely(!radeon_fence_signaled(fence))) { /* we were interrupted for some reason and fence isn't * isn't signaled yet, resume wait diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index a8594d289bcf..8bdf0ba2983a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -34,6 +34,7 @@ #include #include "radeon_drm.h" #include "radeon.h" +#include "radeon_trace.h" int radeon_ttm_init(struct radeon_device *rdev); @@ -137,6 +138,7 @@ retry: list_add_tail(&bo->list, &rdev->gem.objects); mutex_unlock(&bo->rdev->gem.mutex); } + trace_radeon_bo_create(bo); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_trace.h b/drivers/gpu/drm/radeon/radeon_trace.h new file mode 100644 index 000000000000..eafd8160a155 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_trace.h @@ -0,0 +1,82 @@ +#if !defined(_RADEON_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _RADEON_TRACE_H_ + +#include +#include +#include + +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM radeon +#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) +#define TRACE_INCLUDE_FILE radeon_trace + +TRACE_EVENT(radeon_bo_create, + TP_PROTO(struct radeon_bo *bo), + TP_ARGS(bo), + TP_STRUCT__entry( + __field(struct radeon_bo *, bo) + __field(u32, pages) + ), + + TP_fast_assign( + __entry->bo = bo; + __entry->pages = bo->tbo.num_pages; + ), + TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages) +); + +DECLARE_EVENT_CLASS(radeon_fence_request, + + TP_PROTO(struct drm_device *dev, u32 seqno), + + TP_ARGS(dev, seqno), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u32, seqno) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->seqno = seqno; + ), + + TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno) +); + +DEFINE_EVENT(radeon_fence_request, radeon_fence_emit, + + TP_PROTO(struct drm_device *dev, u32 seqno), + + TP_ARGS(dev, seqno) +); + +DEFINE_EVENT(radeon_fence_request, radeon_fence_retire, + + TP_PROTO(struct drm_device *dev, u32 seqno), + + TP_ARGS(dev, seqno) +); + +DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin, + + TP_PROTO(struct drm_device *dev, u32 seqno), + + TP_ARGS(dev, seqno) +); + +DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_end, + + TP_PROTO(struct drm_device *dev, u32 seqno), + + TP_ARGS(dev, seqno) +); + +#endif + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include diff --git a/drivers/gpu/drm/radeon/radeon_trace_points.c b/drivers/gpu/drm/radeon/radeon_trace_points.c new file mode 100644 index 000000000000..8175993df84d --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_trace_points.c @@ -0,0 +1,9 @@ +/* Copyright Red Hat Inc 2010. + * Author : Dave Airlie + */ +#include +#include "radeon_drm.h" +#include "radeon.h" + +#define CREATE_TRACE_POINTS +#include "radeon_trace.h" -- cgit v1.2.3 From b921bae2eedc806b118a03d986cf0be9ffd3af40 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 16 Dec 2010 14:47:46 +1000 Subject: drm/ttm: delay freeing of old node during move_memcpy until after iounmap Drivers using their own implementation of io_mem_reserve/io_mem_free are likely to store the tracking information for the map in mem.mm_node, so it can't be freed while still mapped. Signed-off-by: Ben Skeggs Reviewed-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index a89839f83f6c..77dbf408c0d0 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -370,7 +370,6 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, } mb(); out2: - ttm_bo_free_old_node(bo); old_copy = *old_mem; *old_mem = *new_mem; new_mem->mm_node = NULL; @@ -385,6 +384,7 @@ out1: ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); out: ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); + ttm_bo_mem_put(bo, &old_copy); return ret; } EXPORT_SYMBOL(ttm_bo_move_memcpy); -- cgit v1.2.3 From b4183e301ac1dfaf93e3e92fd70a0c3203c5a27d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 15 Dec 2010 11:04:10 -0500 Subject: drm/radeon/kms: fix vram start calculation on ontario (v2) Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 6 ++++++ drivers/gpu/drm/radeon/evergreend.h | 1 + drivers/gpu/drm/radeon/rv770.c | 13 +------------ drivers/gpu/drm/radeon/rv770d.h | 1 - 4 files changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 522d29b37007..f7d7477daffb 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1134,6 +1134,12 @@ static void evergreen_mc_program(struct radeon_device *rdev) rdev->mc.vram_end >> 12); } WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + if (rdev->flags & RADEON_IS_IGP) { + tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF; + tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24; + tmp |= ((rdev->mc.vram_start >> 20) & 0xF) << 20; + WREG32(MC_FUS_VM_FB_OFFSET, tmp); + } tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 87fcaba76695..5b869ce86917 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -202,6 +202,7 @@ #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 #define MC_VM_FB_LOCATION 0x2024 +#define MC_FUS_VM_FB_OFFSET 0x2898 #define MC_VM_MB_L1_TLB0_CNTL 0x2234 #define MC_VM_MB_L1_TLB1_CNTL 0x2238 #define MC_VM_MB_L1_TLB2_CNTL 0x223C diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 7c2e0b19a558..645aa1fd7611 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -271,12 +271,6 @@ static void rv770_mc_program(struct radeon_device *rdev) rdev->mc.vram_end >> 12); } WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); - if (rdev->flags & RADEON_IS_IGP) { - tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF; - tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24; - tmp |= ((rdev->mc.vram_start >> 20) & 0xF) << 20; - WREG32(MC_FUS_VM_FB_OFFSET, tmp); - } tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); @@ -1074,12 +1068,7 @@ void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) mc->mc_vram_size >> 20, mc->vram_start, mc->vram_end, mc->real_vram_size >> 20); } else { - u64 base = 0; - if (rdev->flags & RADEON_IS_IGP) { - base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24; - base |= RREG32(MC_FUS_VM_FB_OFFSET) & 0x00F00000; - } - radeon_vram_location(rdev, &rdev->mc, base); + radeon_vram_location(rdev, &rdev->mc, 0); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, mc); } diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 98f9ad256d3d..fc77e1e1a179 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -158,7 +158,6 @@ #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 #define MC_VM_FB_LOCATION 0x2024 -#define MC_FUS_VM_FB_OFFSET 0x2898 #define MC_VM_MB_L1_TLB0_CNTL 0x2234 #define MC_VM_MB_L1_TLB1_CNTL 0x2238 #define MC_VM_MB_L1_TLB2_CNTL 0x223C -- cgit v1.2.3 From b08ebe7e776e5be0271ed1e1bbb384e1f29dd117 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 3 Dec 2010 15:34:16 -0500 Subject: drm/radeon/kms: properly print ontario chip id Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index dd93c9c94144..3952cf3d0ee9 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -81,6 +81,7 @@ static const char radeon_family_name[][16] = { "JUNIPER", "CYPRESS", "HEMLOCK", + "PALM", "LAST", }; -- cgit v1.2.3 From 2d9217296bfa6fdc0d3707264076e5296faffdbd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 8 Dec 2010 20:57:38 +0100 Subject: cdrom: add ->check_events() support In principle, cdrom just needs to pass through ->check_events() but CDROM_MEDIA_CHANGED ioctl makes things a bit more complex. Just as with ->media_changed() support, cdrom code needs to buffer the events and serve them to ioctl and vfs as requested. As the code has to deal with both ->check_events() and ->media_changed(), and vfs and ioctl event buffering, this patch adds check_events caching on top of the existing cdi->mc_flags buffering. It may be a good idea to deprecate CDROM_MEDIA_CHANGED ioctl and remove all this mess. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/cdrom/cdrom.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++--- include/linux/cdrom.h | 6 ++++++ 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index af13c62dc473..1ea8f8d363c6 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1348,7 +1348,10 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) if (!CDROM_CAN(CDC_SELECT_DISC)) return -EDRIVE_CANT_DO_THIS; - (void) cdi->ops->media_changed(cdi, slot); + if (cdi->ops->check_events) + cdi->ops->check_events(cdi, 0, slot); + else + cdi->ops->media_changed(cdi, slot); if (slot == CDSL_NONE) { /* set media changed bits, on both queues */ @@ -1392,6 +1395,41 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) return slot; } +/* + * As cdrom implements an extra ioctl consumer for media changed + * event, it needs to buffer ->check_events() output, such that event + * is not lost for both the usual VFS and ioctl paths. + * cdi->{vfs|ioctl}_events are used to buffer pending events for each + * path. + * + * XXX: Locking is non-existent. cdi->ops->check_events() can be + * called in parallel and buffering fields are accessed without any + * exclusion. The original media_changed code had the same problem. + * It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl + * and remove this cruft altogether. It doesn't have much usefulness + * at this point. + */ +static void cdrom_update_events(struct cdrom_device_info *cdi, + unsigned int clearing) +{ + unsigned int events; + + events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT); + cdi->vfs_events |= events; + cdi->ioctl_events |= events; +} + +unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing) +{ + unsigned int events; + + cdrom_update_events(cdi, clearing); + events = cdi->vfs_events; + cdi->vfs_events = 0; + return events; +} + /* We want to make media_changed accessible to the user through an * ioctl. The main problem now is that we must double-buffer the * low-level implementation, to assure that the VFS and the user both @@ -1403,15 +1441,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue) { unsigned int mask = (1 << (queue & 1)); int ret = !!(cdi->mc_flags & mask); + bool changed; if (!CDROM_CAN(CDC_MEDIA_CHANGED)) - return ret; + return ret; + /* changed since last call? */ - if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { + if (cdi->ops->check_events) { + BUG_ON(!queue); /* shouldn't be called from VFS path */ + cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE); + changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE; + cdi->ioctl_events = 0; + } else + changed = cdi->ops->media_changed(cdi, CDSL_CURRENT); + + if (changed) { cdi->mc_flags = 0x3; /* set bit on both queues */ ret |= 1; cdi->media_written = 0; } + cdi->mc_flags &= ~mask; /* clear bit */ return ret; } diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 78e904796622..35eae4b67503 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -946,6 +946,8 @@ struct cdrom_device_info { /* device-related storage */ unsigned int options : 30; /* options flags */ unsigned mc_flags : 2; /* media change buffer flags */ + unsigned int vfs_events; /* cached events for vfs path */ + unsigned int ioctl_events; /* cached events for ioctl path */ int use_count; /* number of times device opened */ char name[20]; /* name of the device type */ /* per-device flags */ @@ -965,6 +967,8 @@ struct cdrom_device_ops { int (*open) (struct cdrom_device_info *, int); void (*release) (struct cdrom_device_info *); int (*drive_status) (struct cdrom_device_info *, int); + unsigned int (*check_events) (struct cdrom_device_info *cdi, + unsigned int clearing, int slot); int (*media_changed) (struct cdrom_device_info *, int); int (*tray_move) (struct cdrom_device_info *, int); int (*lock_door) (struct cdrom_device_info *, int); @@ -993,6 +997,8 @@ extern int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, extern void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode); extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg); +extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); extern int cdrom_media_changed(struct cdrom_device_info *); extern int register_cdrom(struct cdrom_device_info *cdi); -- cgit v1.2.3 From 638428ece619495edc9579b1e21493eb00f9687c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 9 Dec 2010 11:18:42 +0100 Subject: scsi: fix TUR error handling in sr_media_change() sr_test_unit_ready() returns 0 iff TUR succeeded - IOW, when media is present and the device is actually ready, so the return value wouldn't be zero when TUR ends with sense data. sr_media_change() incorrectly tests (retval || (scsi_sense_valid(sshdr)...)) when it tries to test whether TUR failed without sense data or with sense data indicating media-not-present. Fix the test using scsi_status_is_good() and update comments. - Fixed a comment typo spotted by Eike. Signed-off-by: Tejun Heo Cc: Rolf Eike Beer Signed-off-by: Jens Axboe --- drivers/scsi/sr.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d7b383c96d5d..c7e29bdec2cd 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -214,13 +214,17 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); retval = sr_test_unit_ready(cd->device, sshdr); - if (retval || (scsi_sense_valid(sshdr) && - /* 0x3a is medium not present */ - sshdr->asc == 0x3a)) { - /* Media not present or unable to test, unit probably not - * ready. This usually means there is no disc in the drive. - * Mark as changed, and we will figure it out later once - * the drive is available again. + /* + * Media is considered to be present if TUR succeeds or fails with + * sense data indicating something other than media-not-present + * (ASC 0x3a). + */ + if (!scsi_status_is_good(retval) && + (!scsi_sense_valid(sshdr) || sshdr->asc == 0x3a)) { + /* + * Probably no media in the device. Mark as changed, and + * we will figure it out later once the drive is available + * again. */ cd->device->changed = 1; /* This will force a flush, if called from check_disk_change */ -- cgit v1.2.3 From 9f8a2c23c6c1140f515f601265c4dff7522110b7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 8 Dec 2010 20:57:40 +0100 Subject: scsi: replace sr_test_unit_ready() with scsi_test_unit_ready() The usage of TUR has been confusing involving several different commits updating different parts over time. Currently, the only differences between scsi_test_unit_ready() and sr_test_unit_ready() are, * scsi_test_unit_ready() also sets sdev->changed on NOT_READY. * scsi_test_unit_ready() returns 0 if TUR ended with UNIT_ATTENTION or NOT_READY. Due to the above two differences, sr is using its own sr_test_unit_ready(), but sd - the sole user of the above extra handling - doesn't even need them. Where scsi_test_unit_ready() is used in sd_media_changed(), the code is looking for device ready w/ media present state which is true iff TUR succeeds w/o sense data or UA, and when the device is not ready for whatever reason sd_media_changed() explicitly marks media as missing so there's no reason to set sdev->changed automatically from scsi_test_unit_ready() on NOT_READY. Drop both special handlings from scsi_test_unit_ready(), which makes it equivalant to sr_test_unit_ready(), and replace sr_test_unit_ready() with scsi_test_unit_ready(). Also, drop the unnecessary explicit NOT_READY check from sd_media_changed(). Checking return value is enough for testing device readiness. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 13 +------------ drivers/scsi/sd.c | 10 +--------- drivers/scsi/sr.c | 31 +++---------------------------- drivers/scsi/sr.h | 1 - drivers/scsi/sr_ioctl.c | 2 +- 5 files changed, 6 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index eafeeda6e194..13bf89145b18 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1984,8 +1984,7 @@ EXPORT_SYMBOL(scsi_mode_sense); * in. * * Returns zero if unsuccessful or an error if TUR failed. For - * removable media, a return of NOT_READY or UNIT_ATTENTION is - * translated to success, with the ->changed flag updated. + * removable media, UNIT_ATTENTION sets ->changed flag. **/ int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, @@ -2012,16 +2011,6 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, } while (scsi_sense_valid(sshdr) && sshdr->sense_key == UNIT_ATTENTION && --retries); - if (!sshdr) - /* could not allocate sense buffer, so can't process it */ - return result; - - if (sdev->removable && scsi_sense_valid(sshdr) && - (sshdr->sense_key == UNIT_ATTENTION || - sshdr->sense_key == NOT_READY)) { - sdev->changed = 1; - result = 0; - } if (!sshdr_external) kfree(sshdr); return result; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b9ab3a590e4b..8d488a9fef00 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1045,15 +1045,7 @@ static int sd_media_changed(struct gendisk *disk) sshdr); } - /* - * Unable to test, unit probably not ready. This usually - * means there is no disc in the drive. Mark as changed, - * and we will figure it out later once the drive is - * available again. - */ - if (retval || (scsi_sense_valid(sshdr) && - /* 0x3a is medium not present */ - sshdr->asc == 0x3a)) { + if (retval) { set_media_not_present(sdkp); retval = 1; goto out; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index c7e29bdec2cd..310b3fac6313 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -165,32 +165,6 @@ static void scsi_cd_put(struct scsi_cd *cd) mutex_unlock(&sr_ref_mutex); } -/* identical to scsi_test_unit_ready except that it doesn't - * eat the NOT_READY returns for removable media */ -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) -{ - int retries = MAX_RETRIES; - int the_result; - u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; - - /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION - * conditions are gone, or a timeout happens - */ - do { - the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, - 0, sshdr, SR_TIMEOUT, - retries--, NULL); - if (scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION) - sdev->changed = 1; - - } while (retries > 0 && - (!scsi_status_is_good(the_result) || - (scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION))); - return the_result; -} - /* * This function checks to see if the media has been changed in the * CDROM drive. It is possible that we have already sensed a change, @@ -213,7 +187,8 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) } sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - retval = sr_test_unit_ready(cd->device, sshdr); + retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + sshdr); /* * Media is considered to be present if TUR succeeds or fails with * sense data indicating something other than media-not-present @@ -784,7 +759,7 @@ static void get_capabilities(struct scsi_cd *cd) } /* eat unit attentions */ - sr_test_unit_ready(cd->device, &sshdr); + scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 1e144dfdbd4b..81fbc0b78a52 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed); int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); int sr_is_xa(Scsi_CD *); -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr); /* sr_vendor.c */ void sr_vendor_init(Scsi_CD *); diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 3cd8ffbad577..8be30554119b 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -307,7 +307,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot) /* we have no changer support */ return -EINVAL; } - if (0 == sr_test_unit_ready(cd->device, &sshdr)) + if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) return CDS_DISC_OK; /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ -- cgit v1.2.3 From 93aae17af1172c40c6f74b7294e93a90c3cfaa5d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 16 Dec 2010 17:52:17 +0100 Subject: sr: implement sr_check_events() Replace sr_media_change() with sr_check_events(). It normally only uses GET_EVENT_STATUS_NOTIFICATION to check both media change and eject request. If @clearing includes DISK_EVENT_MEDIA_CHANGE, it issues TUR and compares whether media presence has changed. The SCSI specific media change uevent is kept for compatibility. sr_media_change() was doing both media change check and revalidation. The revalidation part is split into sr_block_revalidate_disk(). Signed-off-by: Tejun Heo Cc: Kay Sievers Signed-off-by: Jens Axboe --- drivers/scsi/sr.c | 149 ++++++++++++++++++++++++++++++++++------------------ drivers/scsi/sr.h | 2 +- include/scsi/scsi.h | 1 + 3 files changed, 99 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 310b3fac6313..be6baf8ad704 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -104,14 +104,15 @@ static void sr_release(struct cdrom_device_info *); static void get_sectorsize(struct scsi_cd *); static void get_capabilities(struct scsi_cd *); -static int sr_media_change(struct cdrom_device_info *, int); +static unsigned int sr_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int slot); static int sr_packet(struct cdrom_device_info *, struct packet_command *); static struct cdrom_device_ops sr_dops = { .open = sr_open, .release = sr_release, .drive_status = sr_drive_status, - .media_changed = sr_media_change, + .check_events = sr_check_events, .tray_move = sr_tray_move, .lock_door = sr_lock_door, .select_speed = sr_select_speed, @@ -165,69 +166,96 @@ static void scsi_cd_put(struct scsi_cd *cd) mutex_unlock(&sr_ref_mutex); } +static unsigned int sr_get_events(struct scsi_device *sdev) +{ + u8 buf[8]; + u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION, + 1, /* polled */ + 0, 0, /* reserved */ + 1 << 4, /* notification class: media */ + 0, 0, /* reserved */ + 0, sizeof(buf), /* allocation length */ + 0, /* control */ + }; + struct event_header *eh = (void *)buf; + struct media_event_desc *med = (void *)(buf + 4); + struct scsi_sense_hdr sshdr; + int result; + + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), + &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) + return DISK_EVENT_MEDIA_CHANGE; + + if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) + return 0; + + if (eh->nea || eh->notification_class != 0x4) + return 0; + + if (med->media_event_code == 1) + return DISK_EVENT_EJECT_REQUEST; + else if (med->media_event_code == 2) + return DISK_EVENT_MEDIA_CHANGE; + return 0; +} + /* - * This function checks to see if the media has been changed in the - * CDROM drive. It is possible that we have already sensed a change, - * or the drive may have sensed one and not yet reported it. We must - * be ready for either case. This function always reports the current - * value of the changed bit. If flag is 0, then the changed bit is reset. - * This function could be done as an ioctl, but we would need to have - * an inode for that to work, and we do not always have one. + * This function checks to see if the media has been changed or eject + * button has been pressed. It is possible that we have already + * sensed a change, or the drive may have sensed one and not yet + * reported it. The past events are accumulated in sdev->changed and + * returned together with the current state. */ - -static int sr_media_change(struct cdrom_device_info *cdi, int slot) +static unsigned int sr_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int slot) { struct scsi_cd *cd = cdi->handle; - int retval; - struct scsi_sense_hdr *sshdr; + bool last_present; + struct scsi_sense_hdr sshdr; + unsigned int events; + int ret; - if (CDSL_CURRENT != slot) { - /* no changer support */ - return -EINVAL; - } + /* no changer support */ + if (CDSL_CURRENT != slot) + return 0; + + events = sr_get_events(cd->device); + /* + * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE + * is being cleared. Note that there are devices which hang + * if asked to execute TUR repeatedly. + */ + if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) + goto skip_tur; + + /* let's see whether the media is there with TUR */ + last_present = cd->media_present; + ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); - sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, - sshdr); /* * Media is considered to be present if TUR succeeds or fails with * sense data indicating something other than media-not-present * (ASC 0x3a). */ - if (!scsi_status_is_good(retval) && - (!scsi_sense_valid(sshdr) || sshdr->asc == 0x3a)) { - /* - * Probably no media in the device. Mark as changed, and - * we will figure it out later once the drive is available - * again. - */ - cd->device->changed = 1; - /* This will force a flush, if called from check_disk_change */ - retval = 1; - goto out; - }; + cd->media_present = scsi_status_is_good(ret) || + (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); - retval = cd->device->changed; - cd->device->changed = 0; - /* If the disk changed, the capacity will now be different, - * so we force a re-read of this information */ - if (retval) { - /* check multisession offset etc */ - sr_cd_check(cdi); - get_sectorsize(cd); + if (last_present != cd->media_present) + events |= DISK_EVENT_MEDIA_CHANGE; +skip_tur: + if (cd->device->changed) { + events |= DISK_EVENT_MEDIA_CHANGE; + cd->device->changed = 0; } -out: - /* Notify userspace, that media has changed. */ - if (retval != cd->previous_state) + /* for backward compatibility */ + if (events & DISK_EVENT_MEDIA_CHANGE) sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); - cd->previous_state = retval; - kfree(sshdr); - - return retval; + return events; } - + /* * sr_done is the interrupt routine for the device driver. * @@ -512,10 +540,25 @@ out: return ret; } -static int sr_block_media_changed(struct gendisk *disk) +static unsigned int sr_block_check_events(struct gendisk *disk, + unsigned int clearing) { struct scsi_cd *cd = scsi_cd(disk); - return cdrom_media_changed(&cd->cdi); + return cdrom_check_events(&cd->cdi, clearing); +} + +static int sr_block_revalidate_disk(struct gendisk *disk) +{ + struct scsi_cd *cd = scsi_cd(disk); + struct scsi_sense_hdr sshdr; + + /* if the unit is not ready, nothing more to do */ + if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) + return 0; + + sr_cd_check(&cd->cdi); + get_sectorsize(cd); + return 0; } static const struct block_device_operations sr_bdops = @@ -524,7 +567,8 @@ static const struct block_device_operations sr_bdops = .open = sr_block_open, .release = sr_block_release, .ioctl = sr_block_ioctl, - .media_changed = sr_block_media_changed, + .check_events = sr_block_check_events, + .revalidate_disk = sr_block_revalidate_disk, /* * No compat_ioctl for now because sr_block_ioctl never * seems to pass arbitary ioctls down to host drivers. @@ -597,6 +641,7 @@ static int sr_probe(struct device *dev) sprintf(disk->disk_name, "sr%d", minor); disk->fops = &sr_bdops; disk->flags = GENHD_FL_CD; + disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); @@ -606,7 +651,7 @@ static int sr_probe(struct device *dev) cd->disk = disk; cd->capacity = 0x1fffff; cd->device->changed = 1; /* force recheck CD type */ - cd->previous_state = 1; + cd->media_present = 1; cd->use = 1; cd->readcd_known = 0; cd->readcd_cdda = 0; diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 81fbc0b78a52..e036f1dc83c8 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -40,7 +40,7 @@ typedef struct scsi_cd { unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ unsigned readcd_cdda:1; /* reading audio data using READ_CD */ - unsigned previous_state:1; /* media has changed */ + unsigned media_present:1; /* media is present */ struct cdrom_device_info cdi; /* We hold gendisk and scsi_device references on probe and use * the refs on this kref to decide when to release them */ diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 216af8538cc9..86758618d4f8 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -104,6 +104,7 @@ struct scsi_cmnd; #define UNMAP 0x42 #define READ_TOC 0x43 #define READ_HEADER 0x44 +#define GET_EVENT_STATUS_NOTIFICATION 0x4a #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d #define XDWRITEREAD_10 0x53 -- cgit v1.2.3 From c8d2e937355d02db3055c2fc203e5f017297ee1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 8 Dec 2010 20:57:42 +0100 Subject: sd: implement sd_check_events() Replace sd_media_change() with sd_check_events(). sd used to set the changed state whenever the device is not ready, which can cause event loop while the device is not ready. Media presence handling code is changed such that the changed state is set iff the media presence actually changes. UA still always sets the changed state and NOT_READY always (at least where it used to set ->changed) clears media presence, so no event is lost. Signed-off-by: Tejun Heo Cc: Kay Sievers Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 87 ++++++++++++++++++++++++++++++------------------------- drivers/scsi/sd.h | 1 - 2 files changed, 47 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8d488a9fef00..b179b0e39a3b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -991,30 +991,50 @@ out: static void set_media_not_present(struct scsi_disk *sdkp) { + if (sdkp->media_present) + sdkp->device->changed = 1; sdkp->media_present = 0; sdkp->capacity = 0; - sdkp->device->changed = 1; +} + +static int media_not_present(struct scsi_disk *sdkp, + struct scsi_sense_hdr *sshdr) +{ + if (!scsi_sense_valid(sshdr)) + return 0; + + /* not invoked for commands that could return deferred errors */ + switch (sshdr->sense_key) { + case UNIT_ATTENTION: + sdkp->device->changed = 1; + /* fall through */ + case NOT_READY: + /* medium not present */ + if (sshdr->asc == 0x3A) { + set_media_not_present(sdkp); + return 1; + } + } + return 0; } /** - * sd_media_changed - check if our medium changed - * @disk: kernel device descriptor + * sd_check_events - check media events + * @disk: kernel device descriptor + * @clearing: disk events currently being cleared * - * Returns 0 if not applicable or no change; 1 if change + * Returns mask of DISK_EVENT_*. * * Note: this function is invoked from the block subsystem. **/ -static int sd_media_changed(struct gendisk *disk) +static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; struct scsi_sense_hdr *sshdr = NULL; int retval; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); - - if (!sdp->removable) - return 0; + SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); /* * If the device is offline, don't send any commands - just pretend as @@ -1024,7 +1044,6 @@ static int sd_media_changed(struct gendisk *disk) */ if (!scsi_device_online(sdp)) { set_media_not_present(sdkp); - retval = 1; goto out; } @@ -1045,26 +1064,30 @@ static int sd_media_changed(struct gendisk *disk) sshdr); } - if (retval) { + /* failed to execute TUR, assume media not present */ + if (host_byte(retval)) { set_media_not_present(sdkp); - retval = 1; goto out; } + if (media_not_present(sdkp, sshdr)) + goto out; + /* * For removable scsi disk we have to recognise the presence - * of a disk in the drive. This is kept in the struct scsi_disk - * struct and tested at open ! Daniel Roche (dan@lectra.fr) + * of a disk in the drive. */ + if (!sdkp->media_present) + sdp->changed = 1; sdkp->media_present = 1; - - retval = sdp->changed; - sdp->changed = 0; out: - if (retval != sdkp->previous_state) + /* for backward compatibility */ + if (sdp->changed) sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); - sdkp->previous_state = retval; kfree(sshdr); + + retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; + sdp->changed = 0; return retval; } @@ -1157,7 +1180,7 @@ static const struct block_device_operations sd_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl, #endif - .media_changed = sd_media_changed, + .check_events = sd_check_events, .revalidate_disk = sd_revalidate_disk, .unlock_native_capacity = sd_unlock_native_capacity, }; @@ -1293,23 +1316,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) return good_bytes; } -static int media_not_present(struct scsi_disk *sdkp, - struct scsi_sense_hdr *sshdr) -{ - - if (!scsi_sense_valid(sshdr)) - return 0; - /* not invoked for commands that could return deferred errors */ - if (sshdr->sense_key != NOT_READY && - sshdr->sense_key != UNIT_ATTENTION) - return 0; - if (sshdr->asc != 0x3A) /* medium not present */ - return 0; - - set_media_not_present(sdkp); - return 1; -} - /* * spinup disk - called only in sd_revalidate_disk() */ @@ -1484,7 +1490,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, */ if (sdp->removable && sense_valid && sshdr->sense_key == NOT_READY) - sdp->changed = 1; + set_media_not_present(sdkp); /* * We used to set media_present to 0 here to indicate no media @@ -2339,8 +2345,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_EXT_DEVT; - if (sdp->removable) + if (sdp->removable) { gd->flags |= GENHD_FL_REMOVABLE; + gd->events |= DISK_EVENT_MEDIA_CHANGE; + } add_disk(gd); sd_dif_config_host(sdkp); @@ -2422,7 +2430,6 @@ static int sd_probe(struct device *dev) sdkp->disk = gd; sdkp->index = index; atomic_set(&sdkp->openers, 0); - sdkp->previous_state = 1; if (!sdp->request_queue->rq_timeout) { if (sdp->type != TYPE_MOD) diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 55488faf0815..c9d8f6ca49e2 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -55,7 +55,6 @@ struct scsi_disk { u8 media_present; u8 write_prot; u8 protection_type;/* Data Integrity Field */ - unsigned previous_state : 1; unsigned ATO : 1; /* state of disk ATO bit */ unsigned WCE : 1; /* state of disk WCE bit */ unsigned RCD : 1; /* state of disk RCD bit, unused */ -- cgit v1.2.3 From 30a7caabbb8e8702b9cf453fee83f773d8b3430d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 16 Dec 2010 17:58:50 +0100 Subject: cdrom: export cdrom_check_events() It's used by sr, so we need to export it. Signed-off-by: Jens Axboe --- drivers/cdrom/cdrom.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 1ea8f8d363c6..14033a36bcd0 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1429,6 +1429,7 @@ unsigned int cdrom_check_events(struct cdrom_device_info *cdi, cdi->vfs_events = 0; return events; } +EXPORT_SYMBOL(cdrom_check_events); /* We want to make media_changed accessible to the user through an * ioctl. The main problem now is that we must double-buffer the -- cgit v1.2.3 From 3be305fd7c0d07cdbb175467b4fe706ea10eb732 Mon Sep 17 00:00:00 2001 From: "L. Alberto Giménez" Date: Tue, 14 Dec 2010 02:01:54 +0100 Subject: Staging: rt2860: include KERN_* in printk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix checkpatch complains. Signed-off-by: L. Alberto Giménez Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/common/ee_efuse.c | 15 +++++++++++---- drivers/staging/rt2860/pci_main_dev.c | 2 +- drivers/staging/rt2860/rt_linux.c | 21 ++++++++++----------- drivers/staging/rt2860/rt_main_dev.c | 2 +- drivers/staging/rt2860/rt_usb.c | 32 ++++++++++++++++---------------- drivers/staging/rt2860/usb_main_dev.c | 12 ++++++------ 6 files changed, 45 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/common/ee_efuse.c b/drivers/staging/rt2860/common/ee_efuse.c index 03412f5bc990..fed0ba452271 100644 --- a/drivers/staging/rt2860/common/ee_efuse.c +++ b/drivers/staging/rt2860/common/ee_efuse.c @@ -264,7 +264,7 @@ int set_eFuseGetFreeBlockCount_Proc(struct rt_rtmp_adapter *pAd, char *arg) if (i == EFUSE_USAGE_MAP_END) efusefreenum = 0; } - printk("efuseFreeNumber is %d\n", efusefreenum); + printk(KERN_DEBUG "efuseFreeNumber is %d\n", efusefreenum); return TRUE; } @@ -274,16 +274,23 @@ int set_eFusedump_Proc(struct rt_rtmp_adapter *pAd, char *arg) int i = 0; if (!pAd->bUseEfuse) return FALSE; + + printk(KERN_DEBUG "Block 0: "); + for (i = 0; i < EFUSE_USAGE_MAP_END / 2; i++) { InBuf[0] = 2 * i; InBuf[1] = 2; InBuf[2] = 0x0; eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); - if (i % 4 == 0) - printk("\nBlock %x:", i / 8); - printk("%04x ", InBuf[2]); + if (i && i % 4 == 0) { + printk(KERN_CONT "\n"); + printk(KERN_DEBUG "Block %x:", i / 8); + } + printk(KERN_CONT "%04x ", InBuf[2]); } + printk(KERN_CONT "\n"); + return TRUE; } diff --git a/drivers/staging/rt2860/pci_main_dev.c b/drivers/staging/rt2860/pci_main_dev.c index cd028e7a8f91..25fbb1880ff2 100644 --- a/drivers/staging/rt2860/pci_main_dev.c +++ b/drivers/staging/rt2860/pci_main_dev.c @@ -203,7 +203,7 @@ static int rt2860_resume(struct pci_dev *pci_dev) /* initialize device before it's used by a driver */ if (pci_enable_device(pci_dev)) { - printk("pci enable fail!\n"); + printk(KERN_ERR "rt2860: pci enable fail!\n"); return 0; } diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c index 0bbd04a71a6a..728864e18a18 100644 --- a/drivers/staging/rt2860/rt_linux.c +++ b/drivers/staging/rt2860/rt_linux.c @@ -321,7 +321,7 @@ int RTMPCloneNdisPacket(struct rt_rtmp_adapter *pAd, RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); - printk("###Clone###\n"); + printk(KERN_DEBUG "###Clone###\n"); return NDIS_STATUS_SUCCESS; } @@ -343,9 +343,8 @@ int RTMPAllocateNdisPacket(struct rt_rtmp_adapter *pAd, RTMP_PKT_TAIL_PADDING); if (pPacket == NULL) { *ppPacket = NULL; -#ifdef DEBUG - printk("RTMPAllocateNdisPacket Fail\n"); -#endif + pr_devel("RTMPAllocateNdisPacket Fail\n"); + return NDIS_STATUS_FAILURE; } /* 2. clone the frame content */ @@ -601,15 +600,15 @@ void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) return; pt = pSrcBufVA; - printk("%s: %p, len = %d\n", str, pSrcBufVA, SrcBufLen); + printk(KERN_DEBUG "%s: %p, len = %d\n", str, pSrcBufVA, SrcBufLen); for (x = 0; x < SrcBufLen; x++) { if (x % 16 == 0) - printk("0x%04x : ", x); - printk("%02x ", ((unsigned char)pt[x])); + printk(KERN_DEBUG "0x%04x : ", x); + printk(KERN_DEBUG "%02x ", ((unsigned char)pt[x])); if (x % 16 == 15) - printk("\n"); + printk(KERN_DEBUG "\n"); } - printk("\n"); + printk(KERN_DEBUG "\n"); } /* @@ -926,7 +925,7 @@ int RtmpOSIRQRequest(struct net_device *pNetDev) request_irq(_pObj->pci_dev->irq, rt2860_interrupt, SA_SHIRQ, (net_dev)->name, (net_dev)); if (retval != 0) - printk("RT2860: request_irq ERROR(%d)\n", retval); + printk(KERN_ERR "rt2860: request_irq ERROR(%d)\n", retval); } return retval; @@ -1022,7 +1021,7 @@ int RtmpOSTaskKill(struct rt_rtmp_os_task *pTask) } #else CHECK_PID_LEGALITY(pTask->taskPID) { - printk("Terminate the task(%s) with pid(%d)!\n", + printk(KERN_INFO "Terminate the task(%s) with pid(%d)!\n", pTask->taskName, GET_PID_NUMBER(pTask->taskPID)); mb(); pTask->task_killed = 1; diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c index e8648219e0b5..701561d6b6fd 100644 --- a/drivers/staging/rt2860/rt_main_dev.c +++ b/drivers/staging/rt2860/rt_main_dev.c @@ -421,7 +421,7 @@ int rt28xx_open(struct net_device *dev) { u32 reg = 0; RTMP_IO_READ32(pAd, 0x1300, ®); /* clear garbage interrupts */ - printk("0x1300 = %08x\n", reg); + printk(KERN_DEBUG "0x1300 = %08x\n", reg); } { diff --git a/drivers/staging/rt2860/rt_usb.c b/drivers/staging/rt2860/rt_usb.c index 580a20dd6e9d..eb037d2e04a2 100644 --- a/drivers/staging/rt2860/rt_usb.c +++ b/drivers/staging/rt2860/rt_usb.c @@ -41,25 +41,25 @@ void dump_urb(struct urb *purb) { - printk("urb :0x%08lx\n", (unsigned long)purb); - printk("\tdev :0x%08lx\n", (unsigned long)purb->dev); - printk("\t\tdev->state :0x%d\n", purb->dev->state); - printk("\tpipe :0x%08x\n", purb->pipe); - printk("\tstatus :%d\n", purb->status); - printk("\ttransfer_flags :0x%08x\n", purb->transfer_flags); - printk("\ttransfer_buffer :0x%08lx\n", + printk(KERN_DEBUG "urb :0x%08lx\n", (unsigned long)purb); + printk(KERN_DEBUG "\tdev :0x%08lx\n", (unsigned long)purb->dev); + printk(KERN_DEBUG "\t\tdev->state :0x%d\n", purb->dev->state); + printk(KERN_DEBUG "\tpipe :0x%08x\n", purb->pipe); + printk(KERN_DEBUG "\tstatus :%d\n", purb->status); + printk(KERN_DEBUG "\ttransfer_flags :0x%08x\n", purb->transfer_flags); + printk(KERN_DEBUG "\ttransfer_buffer :0x%08lx\n", (unsigned long)purb->transfer_buffer); - printk("\ttransfer_buffer_length:%d\n", purb->transfer_buffer_length); - printk("\tactual_length :%d\n", purb->actual_length); - printk("\tsetup_packet :0x%08lx\n", + printk(KERN_DEBUG "\ttransfer_buffer_length:%d\n", purb->transfer_buffer_length); + printk(KERN_DEBUG "\tactual_length :%d\n", purb->actual_length); + printk(KERN_DEBUG "\tsetup_packet :0x%08lx\n", (unsigned long)purb->setup_packet); - printk("\tstart_frame :%d\n", purb->start_frame); - printk("\tnumber_of_packets :%d\n", purb->number_of_packets); - printk("\tinterval :%d\n", purb->interval); - printk("\terror_count :%d\n", purb->error_count); - printk("\tcontext :0x%08lx\n", + printk(KERN_DEBUG "\tstart_frame :%d\n", purb->start_frame); + printk(KERN_DEBUG "\tnumber_of_packets :%d\n", purb->number_of_packets); + printk(KERN_DEBUG "\tinterval :%d\n", purb->interval); + printk(KERN_DEBUG "\terror_count :%d\n", purb->error_count); + printk(KERN_DEBUG "\tcontext :0x%08lx\n", (unsigned long)purb->context); - printk("\tcomplete :0x%08lx\n\n", + printk(KERN_DEBUG "\tcomplete :0x%08lx\n\n", (unsigned long)purb->complete); } diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c index c8cdbc234eba..ee68d51caa4e 100644 --- a/drivers/staging/rt2860/usb_main_dev.c +++ b/drivers/staging/rt2860/usb_main_dev.c @@ -233,7 +233,7 @@ BOOLEAN RT28XXChipsetCheck(IN void *_dev_p) for (i = 0; i < rtusb_usb_id_len; i++) { if (dev_p->descriptor.idVendor == rtusb_usb_id[i].idVendor && dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) { - printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", + printk(KERN_INFO "rt2870: idVendor = 0x%x, idProduct = 0x%x\n", dev_p->descriptor.idVendor, dev_p->descriptor.idProduct); break; @@ -241,7 +241,7 @@ BOOLEAN RT28XXChipsetCheck(IN void *_dev_p) } if (i == rtusb_usb_id_len) { - printk("rt2870: Error! Device Descriptor not matching!\n"); + printk(KERN_ERR "rt2870: Error! Device Descriptor not matching!\n"); return FALSE; } @@ -323,7 +323,7 @@ static BOOLEAN USBDevConfigInit(IN struct usb_device *dev, if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) { printk - ("%s: Could not find both bulk-in and bulk-out endpoints\n", + (KERN_ERR "%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__); return FALSE; } @@ -423,7 +423,7 @@ static int rt2870_resume(struct usb_interface *intf) /* Init driver module */ int __init rtusb_init(void) { - printk("rtusb init --->\n"); + printk(KERN_DEBUG "rtusb init --->\n"); return usb_register(&rtusb_driver); } @@ -431,7 +431,7 @@ int __init rtusb_init(void) void __exit rtusb_exit(void) { usb_deregister(&rtusb_driver); - printk("<--- rtusb exit\n"); + printk(KERN_DEBUG "<--- rtusb exit\n"); } module_init(rtusb_init); @@ -814,7 +814,7 @@ static void rt2870_disconnect(struct usb_device *dev, struct rt_rtmp_adapter *pA dev->bus->bus_name, dev->devpath)); if (!pAd) { usb_put_dev(dev); - printk("rtusb_disconnect: pAd == NULL!\n"); + printk(KERN_ERR "rtusb_disconnect: pAd == NULL!\n"); return; } RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); -- cgit v1.2.3 From 8c3d90921604951e306a898669c46a88578c5848 Mon Sep 17 00:00:00 2001 From: "L. Alberto Giménez" Date: Tue, 14 Dec 2010 02:01:55 +0100 Subject: Staging: rt2860: Sanitize DBGPRINT_ERR macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleaner implementation. Avoids the need of the double parenthesis to call the macro. Signed-off-by: L. Alberto Giménez Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/chip/rtmp_phy.h | 14 +++++++------- drivers/staging/rt2860/common/ba_action.c | 6 +++--- drivers/staging/rt2860/common/cmm_data.c | 2 +- drivers/staging/rt2860/common/cmm_mac_pci.c | 10 +++++----- drivers/staging/rt2860/common/cmm_mac_usb.c | 2 +- drivers/staging/rt2860/common/cmm_wpa.c | 22 +++++++++------------- drivers/staging/rt2860/common/mlme.c | 13 ++++++------- drivers/staging/rt2860/common/rt_rf.c | 3 +-- drivers/staging/rt2860/common/rtmp_init.c | 24 ++++++++++-------------- drivers/staging/rt2860/common/rtmp_mcu.c | 4 ++-- drivers/staging/rt2860/common/spectrum.c | 2 +- drivers/staging/rt2860/rt_linux.h | 6 +----- drivers/staging/rt2860/sta/assoc.c | 2 +- drivers/staging/rt2860/sta/auth.c | 3 +-- drivers/staging/rt2860/sta/connect.c | 3 +-- drivers/staging/rt2860/sta/rtmp_data.c | 2 +- drivers/staging/rt2860/sta/sync.c | 6 +++--- 17 files changed, 54 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rt2860/chip/rtmp_phy.h b/drivers/staging/rt2860/chip/rtmp_phy.h index 9f924ea6ca35..98454df30a22 100644 --- a/drivers/staging/rt2860/chip/rtmp_phy.h +++ b/drivers/staging/rt2860/chip/rtmp_phy.h @@ -247,7 +247,7 @@ } \ } \ if (BbpCsr.field.Busy == BUSY) { \ - DBGPRINT_ERR(("BBP(viaMCU=%d) read R%d fail\n", (_bViaMCU), _bbpID)); \ + DBGPRINT_ERR("BBP(viaMCU=%d) read R%d fail\n", (_bViaMCU), _bbpID); \ *(_pV) = (_pAd)->BbpWriteLatch[_bbpID]; \ if ((_bViaMCU) == TRUE) { \ RTMP_IO_READ32(_pAd, _regID, &BbpCsr.word); \ @@ -336,11 +336,11 @@ } \ } \ } else { \ - DBGPRINT_ERR((" , brt30xxBanMcuCmd = %d, Read BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I))); \ + DBGPRINT_ERR(" , brt30xxBanMcuCmd = %d, Read BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I)); \ *(_pV) = (_A)->BbpWriteLatch[_I]; \ } \ if ((BbpCsr.field.Busy == BUSY) || ((_A)->bPCIclkOff == TRUE)) { \ - DBGPRINT_ERR(("BBP read R%d=0x%x fail\n", _I, BbpCsr.word)); \ + DBGPRINT_ERR("BBP read R%d=0x%x fail\n", _I, BbpCsr.word); \ *(_pV) = (_A)->BbpWriteLatch[_I]; \ } \ } @@ -378,7 +378,7 @@ break; \ } \ if (_busyCnt == MAX_BUSY_COUNT) { \ - DBGPRINT_ERR(("BBP write R%d fail\n", _bbpID)); \ + DBGPRINT_ERR("BBP write R%d fail\n", _bbpID); \ if ((_bViaMCU) == TRUE) { \ RTMP_IO_READ32(_pAd, H2M_BBP_AGENT, &BbpCsr.word); \ BbpCsr.field.Busy = 0; \ @@ -459,15 +459,15 @@ break; \ } \ } else { \ - DBGPRINT_ERR((" brt30xxBanMcuCmd = %d. Write BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I))); \ + DBGPRINT_ERR(" brt30xxBanMcuCmd = %d. Write BBP %d \n", (_A)->brt30xxBanMcuCmd, (_I)); \ } \ if ((BusyCnt == MAX_BUSY_COUNT) || ((_A)->bPCIclkOff == TRUE)) { \ if (BusyCnt == MAX_BUSY_COUNT) \ (_A)->AccessBBPFailCount++; \ - DBGPRINT_ERR(("BBP write R%d=0x%x fail. BusyCnt= %d.bPCIclkOff = %d. \n", _I, BbpCsr.word, BusyCnt, (_A)->bPCIclkOff)); \ + DBGPRINT_ERR("BBP write R%d=0x%x fail. BusyCnt= %d.bPCIclkOff = %d. \n", _I, BbpCsr.word, BusyCnt, (_A)->bPCIclkOff); \ } \ } else { \ - DBGPRINT_ERR(("****** BBP_Write_Latch Buffer exceeds max boundry ****** \n")); \ + DBGPRINT_ERR("****** BBP_Write_Latch Buffer exceeds max boundry ****** \n"); \ } \ } #endif /* RTMP_MAC_PCI // */ diff --git a/drivers/staging/rt2860/common/ba_action.c b/drivers/staging/rt2860/common/ba_action.c index ed8854b902d1..b046c2b814c5 100644 --- a/drivers/staging/rt2860/common/ba_action.c +++ b/drivers/staging/rt2860/common/ba_action.c @@ -1270,13 +1270,13 @@ BOOLEAN CntlEnqueueForRecv(struct rt_rtmp_adapter *pAd, /* First check the size, it MUST not exceed the mlme queue size */ if (MsgLen > MGMT_DMA_BUFFER_SIZE) { - DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); + DBGPRINT_ERR("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen); return FALSE; } else if (MsgLen != sizeof(struct rt_frame_ba_req)) { - DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); + DBGPRINT_ERR("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen); return FALSE; } else if (MsgLen != sizeof(struct rt_frame_ba_req)) { - DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); + DBGPRINT_ERR("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen); return FALSE; } diff --git a/drivers/staging/rt2860/common/cmm_data.c b/drivers/staging/rt2860/common/cmm_data.c index 93a53479d766..2204c2bda386 100644 --- a/drivers/staging/rt2860/common/cmm_data.c +++ b/drivers/staging/rt2860/common/cmm_data.c @@ -1366,7 +1366,7 @@ void RTMPResumeMsduTransmission(struct rt_rtmp_adapter *pAd) /* R66 should not be 0 */ if (pAd->BbpTuning.R66CurrentValue == 0) { pAd->BbpTuning.R66CurrentValue = 0x38; - DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n")); + DBGPRINT_ERR("RTMPResumeMsduTransmission, R66CurrentValue=0...\n"); } RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, diff --git a/drivers/staging/rt2860/common/cmm_mac_pci.c b/drivers/staging/rt2860/common/cmm_mac_pci.c index e26ba4942877..850f0fbc6d90 100644 --- a/drivers/staging/rt2860/common/cmm_mac_pci.c +++ b/drivers/staging/rt2860/common/cmm_mac_pci.c @@ -89,7 +89,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd) if (pAd->TxDescRing[num].AllocVa == NULL) { ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; - DBGPRINT_ERR(("Failed to allocate a big buffer\n")); + DBGPRINT_ERR("Failed to allocate a big buffer\n"); Status = NDIS_STATUS_RESOURCES; break; } @@ -121,7 +121,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd) if (pAd->TxBufSpace[num].AllocVa == NULL) { ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; - DBGPRINT_ERR(("Failed to allocate a big buffer\n")); + DBGPRINT_ERR("Failed to allocate a big buffer\n"); Status = NDIS_STATUS_RESOURCES; break; } @@ -197,7 +197,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd) if (pAd->MgmtDescRing.AllocVa == NULL) { ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; - DBGPRINT_ERR(("Failed to allocate a big buffer\n")); + DBGPRINT_ERR("Failed to allocate a big buffer\n"); Status = NDIS_STATUS_RESOURCES; break; } @@ -251,7 +251,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd) if (pAd->RxDescRing.AllocVa == NULL) { ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; - DBGPRINT_ERR(("Failed to allocate a big buffer\n")); + DBGPRINT_ERR("Failed to allocate a big buffer\n"); Status = NDIS_STATUS_RESOURCES; break; } @@ -304,7 +304,7 @@ int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd) /* Error handling */ if (pDmaBuf->AllocVa == NULL) { ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; - DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n")); + DBGPRINT_ERR("Failed to allocate RxRing's 1st buffer\n"); Status = NDIS_STATUS_RESOURCES; break; } diff --git a/drivers/staging/rt2860/common/cmm_mac_usb.c b/drivers/staging/rt2860/common/cmm_mac_usb.c index 72731cbb81df..64a65a460c29 100644 --- a/drivers/staging/rt2860/common/cmm_mac_usb.c +++ b/drivers/staging/rt2860/common/cmm_mac_usb.c @@ -236,7 +236,7 @@ int NICInitTransmit(struct rt_rtmp_adapter *pAd) os_alloc_mem(pAd, (u8 **) (&pAd->MgmtDescRing.AllocVa), pAd->MgmtDescRing.AllocSize); if (pAd->MgmtDescRing.AllocVa == NULL) { - DBGPRINT_ERR(("Failed to allocate a big buffer for MgmtDescRing!\n")); + DBGPRINT_ERR("Failed to allocate a big buffer for MgmtDescRing!\n"); Status = NDIS_STATUS_RESOURCES; goto out1; } diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c index e37b64b6a608..0040f45b629b 100644 --- a/drivers/staging/rt2860/common/cmm_wpa.c +++ b/drivers/staging/rt2860/common/cmm_wpa.c @@ -2794,7 +2794,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, /* Check length */ if ((len <= 0) || (pEid->Len != len)) { - DBGPRINT_ERR(("%s : The length is invalid\n", __func__)); + DBGPRINT_ERR("%s : The length is invalid\n", __func__); return NULL; } /* Check WPA or WPA2 */ @@ -2803,14 +2803,13 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, u16 ucount; if (len < sizeof(struct rt_rsnie)) { - DBGPRINT_ERR(("%s : The length is too short for WPA\n", - __func__)); + DBGPRINT_ERR("%s : The length is too short for WPA\n", __func__); return NULL; } /* Get the count of pairwise cipher */ ucount = cpu2le16(pRsnie->ucount); if (ucount > 2) { - DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount)); + DBGPRINT_ERR("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount); return NULL; } /* Get the group cipher */ @@ -2836,14 +2835,13 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, isWPA2 = TRUE; if (len < sizeof(struct rt_rsnie2)) { - DBGPRINT_ERR(("%s : The length is too short for WPA2\n", - __func__)); + DBGPRINT_ERR("%s : The length is too short for WPA2\n", __func__); return NULL; } /* Get the count of pairwise cipher */ ucount = cpu2le16(pRsnie->ucount); if (ucount > 2) { - DBGPRINT_ERR(("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount)); + DBGPRINT_ERR("%s : The count(%d) of pairwise cipher is invlaid\n", __func__, ucount); return NULL; } /* Get the group cipher */ @@ -2863,7 +2861,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, offset = sizeof(struct rt_rsnie2) + (4 * (ucount - 1)); } else { - DBGPRINT_ERR(("%s : Unknown IE (%d)\n", __func__, pEid->Eid)); + DBGPRINT_ERR("%s : Unknown IE (%d)\n", __func__, pEid->Eid); return NULL; } @@ -2872,8 +2870,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, len -= offset; if (len < sizeof(struct rt_rsnie_auth)) { - DBGPRINT_ERR(("%s : The length of RSNIE is too short\n", - __func__)); + DBGPRINT_ERR("%s : The length of RSNIE is too short\n", __func__); return NULL; } /* pointer to AKM count */ @@ -2882,8 +2879,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, /* Get the count of pairwise cipher */ acount = cpu2le16(pAkm->acount); if (acount > 2) { - DBGPRINT_ERR(("%s : The count(%d) of AKM is invlaid\n", - __func__, acount)); + DBGPRINT_ERR("%s : The count(%d) of AKM is invlaid\n", __func__, acount); return NULL; } /* Get the AKM suite */ @@ -2910,7 +2906,7 @@ u8 *GetSuiteFromRSNIE(u8 *rsnie, return pBuf; } } else { - DBGPRINT_ERR(("%s : it can't get any more information beyond AKM \n", __func__)); + DBGPRINT_ERR("%s : it can't get any more information beyond AKM \n", __func__); return NULL; } diff --git a/drivers/staging/rt2860/common/mlme.c b/drivers/staging/rt2860/common/mlme.c index 7300c6e9c175..d9c3fd5c2166 100644 --- a/drivers/staging/rt2860/common/mlme.c +++ b/drivers/staging/rt2860/common/mlme.c @@ -550,7 +550,7 @@ void MlmeHandler(struct rt_rtmp_adapter *pAd) Elem->MsgLen = 0; } else { - DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); + DBGPRINT_ERR("MlmeHandler: MlmeQueue empty\n"); } } @@ -4698,8 +4698,7 @@ BOOLEAN MlmeEnqueue(struct rt_rtmp_adapter *pAd, /* First check the size, it MUST not exceed the mlme queue size */ if (MsgLen > MGMT_DMA_BUFFER_SIZE) { - DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", - MsgLen)); + DBGPRINT_ERR("MlmeEnqueue: msg too large, size = %ld \n", MsgLen); return FALSE; } @@ -4762,12 +4761,12 @@ BOOLEAN MlmeEnqueueForRecv(struct rt_rtmp_adapter *pAd, if (RTMP_TEST_FLAG (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) { - DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); + DBGPRINT_ERR("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"); return FALSE; } /* First check the size, it MUST not exceed the mlme queue size */ if (MsgLen > MGMT_DMA_BUFFER_SIZE) { - DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); + DBGPRINT_ERR("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen); return FALSE; } @@ -4777,7 +4776,7 @@ BOOLEAN MlmeEnqueueForRecv(struct rt_rtmp_adapter *pAd, { if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) { - DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType)); + DBGPRINT_ERR("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType); return FALSE; } } @@ -4867,7 +4866,7 @@ void MlmeRestartStateMachine(struct rt_rtmp_adapter *pAd) Elem->MsgLen = 0; } else { - DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n")); + DBGPRINT_ERR("MlmeRestartStateMachine: MlmeQueue empty\n"); } } #endif /* RTMP_MAC_PCI // */ diff --git a/drivers/staging/rt2860/common/rt_rf.c b/drivers/staging/rt2860/common/rt_rf.c index 519121d81040..2895447ffc48 100644 --- a/drivers/staging/rt2860/common/rt_rf.c +++ b/drivers/staging/rt2860/common/rt_rf.c @@ -131,8 +131,7 @@ int RT30xxReadRFRegister(struct rt_rtmp_adapter *pAd, } } if (rfcsr.field.RF_CSR_KICK == BUSY) { - DBGPRINT_ERR(("RF read R%d=0x%x fail, i[%d], k[%d]\n", regID, - rfcsr.word, i, k)); + DBGPRINT_ERR("RF read R%d=0x%x fail, i[%d], k[%d]\n", regID, rfcsr.word, i, k); return STATUS_UNSUCCESSFUL; } diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c index 3628e85802e3..d359a14f5d4d 100644 --- a/drivers/staging/rt2860/common/rtmp_init.c +++ b/drivers/staging/rt2860/common/rtmp_init.c @@ -169,14 +169,14 @@ int RTMPAllocAdapterBlock(void *handle, pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG); if (pBeaconBuf == NULL) { Status = NDIS_STATUS_FAILURE; - DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n")); + DBGPRINT_ERR("Failed to allocate memory - BeaconBuf!\n"); break; } NdisZeroMemory(pBeaconBuf, MAX_BEACON_SIZE); Status = AdapterBlockAllocateMemory(handle, (void **) & pAd); if (Status != NDIS_STATUS_SUCCESS) { - DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n")); + DBGPRINT_ERR("Failed to allocate memory - ADAPTER\n"); break; } pAd->BeaconBuf = pBeaconBuf; @@ -785,8 +785,7 @@ void NICReadEEPROMParameters(struct rt_rtmp_adapter *pAd, u8 *mac_addr) Version.field.Version, Version.field.FaeReleaseNumber)); if (Version.field.Version > VALID_EEPROM_VERSION) { - DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n", - Version.field.Version, VALID_EEPROM_VERSION)); + DBGPRINT_ERR("E2PROM: WRONG VERSION 0x%x, should be %d\n", Version.field.Version, VALID_EEPROM_VERSION); /*pAd->SystemErrorBitmap |= 0x00000001; // hard-code default value when no proper E2PROM installed @@ -2911,7 +2910,7 @@ void RTMPSetTimer(struct rt_ralink_timer *pTimer, unsigned long Value) RTMP_OS_Add_Timer(&pTimer->TimerObj, Value); } } else { - DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n")); + DBGPRINT_ERR("RTMPSetTimer failed, Timer hasn't been initialize!\n"); } } @@ -2947,7 +2946,7 @@ void RTMPModTimer(struct rt_ralink_timer *pTimer, unsigned long Value) RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value); } } else { - DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n")); + DBGPRINT_ERR("RTMPModTimer failed, Timer hasn't been initialize!\n"); } } @@ -2989,7 +2988,7 @@ void RTMPCancelTimer(struct rt_ralink_timer *pTimer, OUT BOOLEAN * pCancelled) RtmpTimerQRemove(pTimer->pAd, pTimer); #endif /* RTMP_TIMER_TASK_SUPPORT // */ } else { - DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n")); + DBGPRINT_ERR("RTMPCancelTimer failed, Timer hasn't been initialize!\n"); } } @@ -3251,8 +3250,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd, /* Load 8051 firmware */ Status = NICLoadFirmware(pAd); if (Status != NDIS_STATUS_SUCCESS) { - DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n", - Status)); + DBGPRINT_ERR("NICLoadFirmware failed, Status[=0x%08x]\n", Status); goto err1; } @@ -3268,8 +3266,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd, Status = RTMPAllocTxRxRingMemory(pAd); if (Status != NDIS_STATUS_SUCCESS) { - DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", - Status)); + DBGPRINT_ERR("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status); goto err1; } @@ -3284,7 +3281,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd, Status = MlmeInit(pAd); if (Status != NDIS_STATUS_SUCCESS) { - DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status)); + DBGPRINT_ERR("MlmeInit failed, Status[=0x%08x]\n", Status); goto err2; } /* Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default */ @@ -3309,8 +3306,7 @@ int rt28xx_init(struct rt_rtmp_adapter *pAd, /* */ Status = NICInitializeAdapter(pAd, TRUE); if (Status != NDIS_STATUS_SUCCESS) { - DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n", - Status)); + DBGPRINT_ERR("NICInitializeAdapter failed, Status[=0x%08x]\n", Status); if (Status != NDIS_STATUS_SUCCESS) goto err3; } diff --git a/drivers/staging/rt2860/common/rtmp_mcu.c b/drivers/staging/rt2860/common/rtmp_mcu.c index 844d4b987b78..80fa4160ed62 100644 --- a/drivers/staging/rt2860/common/rtmp_mcu.c +++ b/drivers/staging/rt2860/common/rtmp_mcu.c @@ -267,7 +267,7 @@ int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd, } while (i++ < 100); if (i > 100) { - DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); + DBGPRINT_ERR("H2M_MAILBOX still hold by MCU. command fail\n"); return FALSE; } @@ -296,7 +296,7 @@ int RtmpAsicSendCommandToMcu(struct rt_rtmp_adapter *pAd, #ifdef RTMP_MAC_PCI #endif /* RTMP_MAC_PCI // */ { - DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); + DBGPRINT_ERR("H2M_MAILBOX still hold by MCU. command fail\n"); } return FALSE; } diff --git a/drivers/staging/rt2860/common/spectrum.c b/drivers/staging/rt2860/common/spectrum.c index 2d5f847e6cc6..1dfb802aab9a 100644 --- a/drivers/staging/rt2860/common/spectrum.c +++ b/drivers/staging/rt2860/common/spectrum.c @@ -1837,7 +1837,7 @@ static void PeerChSwAnnAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_ } if (index >= pAd->ChannelListNum) { - DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); + DBGPRINT_ERR("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum); } } } diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h index a449b0bb85f1..92ff5438e777 100644 --- a/drivers/staging/rt2860/rt_linux.h +++ b/drivers/staging/rt2860/rt_linux.h @@ -423,11 +423,7 @@ do{ \ #define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt) -#define DBGPRINT_ERR(Fmt) \ -{ \ - printk("ERROR! "); \ - printk Fmt; \ -} +#define DBGPRINT_ERR(fmt, args...) printk(KERN_ERR fmt, ##args) #define DBGPRINT_S(Status, Fmt) \ { \ diff --git a/drivers/staging/rt2860/sta/assoc.c b/drivers/staging/rt2860/sta/assoc.c index ab0a83bf76ef..59e931c3190d 100644 --- a/drivers/staging/rt2860/sta/assoc.c +++ b/drivers/staging/rt2860/sta/assoc.c @@ -1055,7 +1055,7 @@ void AssocPostProc(struct rt_rtmp_adapter *pAd, u8 *pAddr2, u16 CapabilityInfo, /* Set New WPA information */ Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); if (Idx == BSS_NOT_FOUND) { - DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n")); + DBGPRINT_ERR("ASSOC - Can't find BSS after receiving Assoc response\n"); } else { /* Init variable */ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0; diff --git a/drivers/staging/rt2860/sta/auth.c b/drivers/staging/rt2860/sta/auth.c index a2bfafddb20e..23ea00b896b0 100644 --- a/drivers/staging/rt2860/sta/auth.c +++ b/drivers/staging/rt2860/sta/auth.c @@ -509,8 +509,7 @@ BOOLEAN AUTH_ReqSend(struct rt_rtmp_adapter *pAd, RTMPSetTimer(pAuthTimer, Timeout); return TRUE; } else { - DBGPRINT_ERR(("%s - MlmeAuthReqAction() sanity check failed\n", - pSMName)); + DBGPRINT_ERR("%s - MlmeAuthReqAction() sanity check failed\n", pSMName); return FALSE; } diff --git a/drivers/staging/rt2860/sta/connect.c b/drivers/staging/rt2860/sta/connect.c index 4b2c84e6509e..4996258f6ecd 100644 --- a/drivers/staging/rt2860/sta/connect.c +++ b/drivers/staging/rt2860/sta/connect.c @@ -215,8 +215,7 @@ void MlmeCntlMachinePerformAction(struct rt_rtmp_adapter *pAd, break; #endif /* RTMP_MAC_USB // */ default: - DBGPRINT_ERR(("ERROR! CNTL - Illegal message type(=%ld)", - Elem->MsgType)); + DBGPRINT_ERR("ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType); break; } } diff --git a/drivers/staging/rt2860/sta/rtmp_data.c b/drivers/staging/rt2860/sta/rtmp_data.c index d7c2012be8a5..e82c6b669eb2 100644 --- a/drivers/staging/rt2860/sta/rtmp_data.c +++ b/drivers/staging/rt2860/sta/rtmp_data.c @@ -645,7 +645,7 @@ void STAHandleRxMgmtFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) /* First check the size, it MUST not exceed the mlme queue size */ if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) { - DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); + DBGPRINT_ERR("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount); break; } diff --git a/drivers/staging/rt2860/sta/sync.c b/drivers/staging/rt2860/sta/sync.c index 05007d9c9b69..7054ba1323d0 100644 --- a/drivers/staging/rt2860/sta/sync.c +++ b/drivers/staging/rt2860/sta/sync.c @@ -284,7 +284,7 @@ void MlmeScanReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *E DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ScanNextChannel(pAd); } else { - DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n")); + DBGPRINT_ERR("SYNC - MlmeScanReqAction() sanity check fail\n"); pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; Status = MLME_INVALID_FORMAT; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, @@ -536,7 +536,7 @@ void MlmeStartReqAction(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem * MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); } else { - DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n")); + DBGPRINT_ERR("SYNC - MlmeStartReqAction() sanity check fail.\n"); pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; Status = MLME_INVALID_FORMAT; MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, @@ -1208,7 +1208,7 @@ void PeerBeacon(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) } if (index >= pAd->ChannelListNum) { - DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); + DBGPRINT_ERR("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum); } } /* if the ssid matched & bssid unmatched, we should select the bssid with large value. */ -- cgit v1.2.3 From dab56ffe9acc59a6cbe8f857a95adf75f42970b9 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 14 Dec 2010 09:42:27 +0100 Subject: staging: ft1000: Fix camelcase function names. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_proc.c | 4 ++-- drivers/staging/ft1000/ft1000-usb/ft1000_usb.c | 4 ++-- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c index 0f271c281b85..b87542abbe86 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c @@ -201,7 +201,7 @@ static struct notifier_block ft1000_netdev_notifier = { }; -int ft1000InitProc(struct net_device *dev) +int ft1000_init_proc(struct net_device *dev) { struct ft1000_info *info; struct proc_dir_entry *ft1000_proc_file; @@ -243,7 +243,7 @@ fail: return ret; } -void ft1000CleanupProc(struct ft1000_info *info) +void ft1000_cleanup_proc(struct ft1000_info *info) { remove_proc_entry(info->netdevname, info->ft1000_proc_dir); remove_proc_entry(FT1000_PROC_DIR, FTNET_PROC); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c index 0e1fc3f1e055..79482ac1c489 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.c @@ -198,7 +198,7 @@ static int ft1000_probe(struct usb_interface *interface, if (ret) goto err_thread; - ret = ft1000InitProc(ft1000dev->net); + ret = ft1000_init_proc(ft1000dev->net); if (ret) goto err_proc; @@ -228,7 +228,7 @@ static void ft1000_disconnect(struct usb_interface *interface) DEBUG("In disconnect pft1000info=%p\n", pft1000info); if (pft1000info) { - ft1000CleanupProc(pft1000info); + ft1000_cleanup_proc(pft1000info); if (pft1000info->pPollThread) kthread_stop(pft1000info->pPollThread); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 4a91469e64ff..a143e9ca4f08 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -594,8 +594,8 @@ struct usb_interface; int reg_ft1000_netdev(struct ft1000_device *ft1000dev, struct usb_interface *intf); int ft1000_poll(void* dev_id); -int ft1000InitProc(struct net_device *dev); -void ft1000CleanupProc(struct ft1000_info *info); +int ft1000_init_proc(struct net_device *dev); +void ft1000_cleanup_proc(struct ft1000_info *info); -- cgit v1.2.3 From c346541f3d8c6e90b6aadc0511c27a6de15fdee5 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 14 Dec 2010 09:42:28 +0100 Subject: staging: ft1000: Rename ft1000_chdev.c to ft1000_debug.c. Name of old file was misleading because it is currently updated to debugfs so change also file name. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/Makefile | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c | 784 ----------------------- drivers/staging/ft1000/ft1000-usb/ft1000_debug.c | 784 +++++++++++++++++++++++ 3 files changed, 785 insertions(+), 785 deletions(-) delete mode 100644 drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c create mode 100644 drivers/staging/ft1000/ft1000-usb/ft1000_debug.c (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/Makefile b/drivers/staging/ft1000/ft1000-usb/Makefile index dd87ecd7918e..f0f524015888 100644 --- a/drivers/staging/ft1000/ft1000-usb/Makefile +++ b/drivers/staging/ft1000/ft1000-usb/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_FT1000_USB) += ft1000.o -ft1000-y := ft1000_chdev.o ft1000_download.o ft1000_hw.o ft1000_proc.o ft1000_usb.o +ft1000-y := ft1000_debug.o ft1000_download.o ft1000_hw.o ft1000_proc.o ft1000_usb.o diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c b/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c deleted file mode 100644 index e39809229d46..000000000000 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c +++ /dev/null @@ -1,784 +0,0 @@ -//--------------------------------------------------------------------------- -// FT1000 driver for Flarion Flash OFDM NIC Device -// -// Copyright (C) 2006 Flarion Technologies, All rights reserved. -// -// 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. -//--------------------------------------------------------------------------- -// -// File: ft1000_chdev.c -// -// Description: Custom character device dispatch routines. -// -// History: -// 8/29/02 Whc Ported to Linux. -// 6/05/06 Whc Porting to Linux 2.6.9 -// -//--------------------------------------------------------------------------- -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "ft1000_usb.h" - -static int ft1000_flarion_cnt = 0; - -static int ft1000_open (struct inode *inode, struct file *file); -static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait); -static long ft1000_ioctl(struct file *file, unsigned int command, - unsigned long argument); -static int ft1000_release (struct inode *inode, struct file *file); - -// List to free receive command buffer pool -struct list_head freercvpool; - -// lock to arbitrate free buffer list for receive command data -spinlock_t free_buff_lock; - -int numofmsgbuf = 0; - -// -// Table of entry-point routines for char device -// -static struct file_operations ft1000fops = -{ - .unlocked_ioctl = ft1000_ioctl, - .poll = ft1000_poll_dev, - .open = ft1000_open, - .release = ft1000_release, - .llseek = no_llseek, -}; - -//--------------------------------------------------------------------------- -// Function: ft1000_get_buffer -// -// Parameters: -// -// Returns: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- -struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist) -{ - unsigned long flags; - struct dpram_blk *ptr; - - spin_lock_irqsave(&free_buff_lock, flags); - // Check if buffer is available - if ( list_empty(bufflist) ) { - DEBUG("ft1000_get_buffer: No more buffer - %d\n", numofmsgbuf); - ptr = NULL; - } - else { - numofmsgbuf--; - ptr = list_entry(bufflist->next, struct dpram_blk, list); - list_del(&ptr->list); - //DEBUG("ft1000_get_buffer: number of free msg buffers = %d\n", numofmsgbuf); - } - spin_unlock_irqrestore(&free_buff_lock, flags); - - return ptr; -} - - - - -//--------------------------------------------------------------------------- -// Function: ft1000_free_buffer -// -// Parameters: -// -// Returns: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- -void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist) -{ - unsigned long flags; - - spin_lock_irqsave(&free_buff_lock, flags); - // Put memory back to list - list_add_tail(&pdpram_blk->list, plist); - numofmsgbuf++; - //DEBUG("ft1000_free_buffer: number of free msg buffers = %d\n", numofmsgbuf); - spin_unlock_irqrestore(&free_buff_lock, flags); -} - -//--------------------------------------------------------------------------- -// Function: ft1000_CreateDevice -// -// Parameters: dev - pointer to adapter object -// -// Returns: 0 if successful -// -// Description: Creates a private char device. -// -// Notes: Only called by init_module(). -// -//--------------------------------------------------------------------------- -int ft1000_create_dev(struct ft1000_device *dev) -{ - struct ft1000_info *info = netdev_priv(dev->net); - int result; - int i; - struct dentry *dir, *file; - struct ft1000_debug_dirs *tmp; - - // make a new device name - sprintf(info->DeviceName, "%s%d", "FT1000_", info->CardNumber); - - DEBUG("%s: number of instance = %d\n", __func__, ft1000_flarion_cnt); - DEBUG("DeviceCreated = %x\n", info->DeviceCreated); - - if (info->DeviceCreated) - { - DEBUG("%s: \"%s\" already registered\n", __func__, info->DeviceName); - return -EIO; - } - - - // register the device - DEBUG("%s: \"%s\" debugfs device registration\n", __func__, info->DeviceName); - - tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL); - if (tmp == NULL) { - result = -1; - goto fail; - } - - dir = debugfs_create_dir(info->DeviceName, 0); - if (IS_ERR(dir)) { - result = PTR_ERR(dir); - goto debug_dir_fail; - } - - file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir, - NULL, &ft1000fops); - if (IS_ERR(file)) { - result = PTR_ERR(file); - goto debug_file_fail; - } - - tmp->dent = dir; - tmp->file = file; - tmp->int_number = info->CardNumber; - list_add(&(tmp->list), &(info->nodes.list)); - - DEBUG("%s: registered debugfs directory \"%s\"\n", __func__, info->DeviceName); - - // initialize application information - info->appcnt = 0; - for (i=0; iapp_info[i].nTxMsg = 0; - info->app_info[i].nRxMsg = 0; - info->app_info[i].nTxMsgReject = 0; - info->app_info[i].nRxMsgMiss = 0; - info->app_info[i].fileobject = NULL; - info->app_info[i].app_id = i+1; - info->app_info[i].DspBCMsgFlag = 0; - info->app_info[i].NumOfMsg = 0; - init_waitqueue_head(&info->app_info[i].wait_dpram_msg); - INIT_LIST_HEAD (&info->app_info[i].app_sqlist); - } - - info->DeviceCreated = TRUE; - ft1000_flarion_cnt++; - - return 0; - -debug_file_fail: - debugfs_remove(dir); -debug_dir_fail: - kfree(tmp); -fail: - return result; -} - -//--------------------------------------------------------------------------- -// Function: ft1000_DestroyDeviceDEBUG -// -// Parameters: dev - pointer to adapter object -// -// Description: Destroys a private char device. -// -// Notes: Only called by cleanup_module(). -// -//--------------------------------------------------------------------------- -void ft1000_destroy_dev(struct net_device *dev) -{ - struct ft1000_info *info = netdev_priv(dev); - int i; - struct dpram_blk *pdpram_blk; - struct dpram_blk *ptr; - struct list_head *pos, *q; - struct ft1000_debug_dirs *dir; - - DEBUG("%s called\n", __func__); - - - - if (info->DeviceCreated) - { - ft1000_flarion_cnt--; - list_for_each_safe(pos, q, &info->nodes.list) { - dir = list_entry(pos, struct ft1000_debug_dirs, list); - if (dir->int_number == info->CardNumber) { - debugfs_remove(dir->file); - debugfs_remove(dir->dent); - list_del(pos); - kfree(dir); - } - } - DEBUG("%s: unregistered device \"%s\"\n", __func__, - info->DeviceName); - - // Make sure we free any memory reserve for slow Queue - for (i=0; iapp_info[i].app_sqlist) == 0) { - pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); - list_del(&pdpram_blk->list); - ft1000_free_buffer(pdpram_blk, &freercvpool); - - } - wake_up_interruptible(&info->app_info[i].wait_dpram_msg); - } - - // Remove buffer allocated for receive command data - if (ft1000_flarion_cnt == 0) { - while (list_empty(&freercvpool) == 0) { - ptr = list_entry(freercvpool.next, struct dpram_blk, list); - list_del(&ptr->list); - kfree(ptr->pbuffer); - kfree(ptr); - } - } - info->DeviceCreated = FALSE; - } - - -} - -//--------------------------------------------------------------------------- -// Function: ft1000_open -// -// Parameters: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- -static int ft1000_open (struct inode *inode, struct file *file) -{ - struct ft1000_info *info; - struct ft1000_device *dev = (struct ft1000_device *)inode->i_private; - int i,num; - - DEBUG("%s called\n", __func__); - num = (MINOR(inode->i_rdev) & 0xf); - DEBUG("ft1000_open: minor number=%d\n", num); - - info = file->private_data = netdev_priv(dev->net); - - DEBUG("f_owner = %p number of application = %d\n", (&file->f_owner), info->appcnt ); - - // Check if maximum number of application exceeded - if (info->appcnt > MAX_NUM_APP) { - DEBUG("Maximum number of application exceeded\n"); - return -EACCES; - } - - // Search for available application info block - for (i=0; iapp_info[i].fileobject == NULL) ) { - break; - } - } - - // Fail due to lack of application info block - if (i == MAX_NUM_APP) { - DEBUG("Could not find an application info block\n"); - return -EACCES; - } - - info->appcnt++; - info->app_info[i].fileobject = &file->f_owner; - info->app_info[i].nTxMsg = 0; - info->app_info[i].nRxMsg = 0; - info->app_info[i].nTxMsgReject = 0; - info->app_info[i].nRxMsgMiss = 0; - - nonseekable_open(inode, file); - return 0; -} - - -//--------------------------------------------------------------------------- -// Function: ft1000_poll_dev -// -// Parameters: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- - -static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait) -{ - struct net_device *dev = file->private_data; - struct ft1000_info *info; - int i; - - //DEBUG("ft1000_poll_dev called\n"); - if (ft1000_flarion_cnt == 0) { - DEBUG("FT1000:ft1000_poll_dev called when ft1000_flarion_cnt is zero\n"); - return (-EBADF); - } - - info = netdev_priv(dev); - - // Search for matching file object - for (i=0; iapp_info[i].fileobject == &file->f_owner) { - //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); - break; - } - } - - // Could not find application info block - if (i == MAX_NUM_APP) { - DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n"); - return ( -EACCES ); - } - - if (list_empty(&info->app_info[i].app_sqlist) == 0) { - DEBUG("FT1000:ft1000_poll_dev:Message detected in slow queue\n"); - return(POLLIN | POLLRDNORM | POLLPRI); - } - - poll_wait (file, &info->app_info[i].wait_dpram_msg, wait); - //DEBUG("FT1000:ft1000_poll_dev:Polling for data from DSP\n"); - - return (0); -} - -//--------------------------------------------------------------------------- -// Function: ft1000_ioctl -// -// Parameters: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- -static long ft1000_ioctl (struct file *file, unsigned int command, - unsigned long argument) -{ - void __user *argp = (void __user *)argument; - struct net_device *dev; - struct ft1000_info *info; - struct ft1000_device *ft1000dev; - int result=0; - int cmd; - int i; - u16 tempword; - unsigned long flags; - struct timeval tv; - IOCTL_GET_VER get_ver_data; - IOCTL_GET_DSP_STAT get_stat_data; - u8 ConnectionMsg[] = {0x00,0x44,0x10,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x93,0x64, - 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x02,0x37,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x7f,0x00, - 0x00,0x01,0x00,0x00}; - - unsigned short ledStat=0; - unsigned short conStat=0; - - //DEBUG("ft1000_ioctl called\n"); - - if (ft1000_flarion_cnt == 0) { - DEBUG("FT1000:ft1000_ioctl called when ft1000_flarion_cnt is zero\n"); - return (-EBADF); - } - - //DEBUG("FT1000:ft1000_ioctl:command = 0x%x argument = 0x%8x\n", command, (u32)argument); - - dev = file->private_data; - info = netdev_priv(dev); - ft1000dev = info->pFt1000Dev; - cmd = _IOC_NR(command); - //DEBUG("FT1000:ft1000_ioctl:cmd = 0x%x\n", cmd); - - // process the command - switch (cmd) { - case IOCTL_REGISTER_CMD: - DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_REGISTER called\n"); - result = get_user(tempword, (__u16 __user*)argp); - if (result) { - DEBUG("result = %d failed to get_user\n", result); - break; - } - if (tempword == DSPBCMSGID) { - // Search for matching file object - for (i=0; iapp_info[i].fileobject == &file->f_owner) { - info->app_info[i].DspBCMsgFlag = 1; - DEBUG("FT1000:ft1000_ioctl:Registered for broadcast messages\n"); - break; - } - } - } - break; - - case IOCTL_GET_VER_CMD: - DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_VER called\n"); - - get_ver_data.drv_ver = FT1000_DRV_VER; - - if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data)) ) { - DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); - result = -EFAULT; - break; - } - - DEBUG("FT1000:ft1000_ioctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver); - - break; - case IOCTL_CONNECT: - // Connect Message - DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_CONNECT\n"); - ConnectionMsg[79] = 0xfc; - CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c); - - break; - case IOCTL_DISCONNECT: - // Disconnect Message - DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_DISCONNECT\n"); - ConnectionMsg[79] = 0xfd; - CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c); - break; - case IOCTL_GET_DSP_STAT_CMD: - //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DSP_STAT called\n"); - memset(&get_stat_data, 0, sizeof(get_stat_data)); - memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ); - memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ); - memcpy(get_stat_data.Sku, info->Sku, SKUSZ); - memcpy(get_stat_data.eui64, info->eui64, EUISZ); - - if (info->ProgConStat != 0xFF) { - ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); - get_stat_data.LedStat = ntohs(ledStat); - DEBUG("FT1000:ft1000_ioctl: LedStat = 0x%x\n", get_stat_data.LedStat); - ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); - get_stat_data.ConStat = ntohs(conStat); - DEBUG("FT1000:ft1000_ioctl: ConStat = 0x%x\n", get_stat_data.ConStat); - } - else { - get_stat_data.ConStat = 0x0f; - } - - - get_stat_data.nTxPkts = info->stats.tx_packets; - get_stat_data.nRxPkts = info->stats.rx_packets; - get_stat_data.nTxBytes = info->stats.tx_bytes; - get_stat_data.nRxBytes = info->stats.rx_bytes; - do_gettimeofday ( &tv ); - get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm); - DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm); - if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data)) ) { - DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); - result = -EFAULT; - break; - } - DEBUG("ft1000_chioctl: GET_DSP_STAT succeed\n"); - break; - case IOCTL_SET_DPRAM_CMD: - { - IOCTL_DPRAM_BLK *dpram_data = NULL; - //IOCTL_DPRAM_COMMAND dpram_command; - u16 qtype; - u16 msgsz; - struct pseudo_hdr *ppseudo_hdr; - u16 *pmsg; - u16 total_len; - u16 app_index; - u16 status; - - //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_SET_DPRAM called\n"); - - - if (ft1000_flarion_cnt == 0) { - return (-EBADF); - } - - if (info->DrvMsgPend) { - return (-ENOTTY); - } - - if ( (info->DspAsicReset) || (info->fProvComplete == 0) ) { - return (-EACCES); - } - - info->fAppMsgPend = 1; - - if (info->CardReady) { - - //DEBUG("FT1000:ft1000_ioctl: try to SET_DPRAM \n"); - - // Get the length field to see how many bytes to copy - result = get_user(msgsz, (__u16 __user *)argp); - msgsz = ntohs (msgsz); - //DEBUG("FT1000:ft1000_ioctl: length of message = %d\n", msgsz); - - if (msgsz > MAX_CMD_SQSIZE) { - DEBUG("FT1000:ft1000_ioctl: bad message length = %d\n", msgsz); - result = -EINVAL; - break; - } - - result = -ENOMEM; - dpram_data = kmalloc(msgsz + 2, GFP_KERNEL); - if (!dpram_data) - break; - - if ( copy_from_user(dpram_data, argp, msgsz+2) ) { - DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); - result = -EFAULT; - } - else { - // Check if this message came from a registered application - for (i=0; iapp_info[i].fileobject == &file->f_owner) { - break; - } - } - if (i==MAX_NUM_APP) { - DEBUG("FT1000:No matching application fileobject\n"); - result = -EINVAL; - kfree(dpram_data); - break; - } - app_index = i; - - // Check message qtype type which is the lower byte within qos_class - qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff; - //DEBUG("FT1000_ft1000_ioctl: qtype = %d\n", qtype); - if (qtype) { - } - else { - // Put message into Slow Queue - // Only put a message into the DPRAM if msg doorbell is available - status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); - //DEBUG("FT1000_ft1000_ioctl: READ REGISTER tempword=%x\n", tempword); - if (tempword & FT1000_DB_DPRAM_TX) { - // Suspend for 2ms and try again due to DSP doorbell busy - mdelay(2); - status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); - if (tempword & FT1000_DB_DPRAM_TX) { - // Suspend for 1ms and try again due to DSP doorbell busy - mdelay(1); - status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); - if (tempword & FT1000_DB_DPRAM_TX) { - status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); - if (tempword & FT1000_DB_DPRAM_TX) { - // Suspend for 3ms and try again due to DSP doorbell busy - mdelay(3); - status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); - if (tempword & FT1000_DB_DPRAM_TX) { - DEBUG("FT1000:ft1000_ioctl:Doorbell not available\n"); - result = -ENOTTY; - kfree(dpram_data); - break; - } - } - } - } - } - - //DEBUG("FT1000_ft1000_ioctl: finished reading register\n"); - - // Make sure we are within the limits of the slow queue memory limitation - if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) { - // Need to put sequence number plus new checksum for message - pmsg = (u16 *)&dpram_data->pseudohdr; - ppseudo_hdr = (struct pseudo_hdr *)pmsg; - total_len = msgsz+2; - if (total_len & 0x1) { - total_len++; - } - - // Insert slow queue sequence number - ppseudo_hdr->seq_num = info->squeseqnum++; - ppseudo_hdr->portsrc = info->app_info[app_index].app_id; - // Calculate new checksum - ppseudo_hdr->checksum = *pmsg++; - //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum); - for (i=1; i<7; i++) { - ppseudo_hdr->checksum ^= *pmsg++; - //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum); - } - pmsg++; - ppseudo_hdr = (struct pseudo_hdr *)pmsg; - CardSendCommand(ft1000dev,(unsigned short*)dpram_data,total_len+2); - - - info->app_info[app_index].nTxMsg++; - } - else { - result = -EINVAL; - } - } - } - } - else { - DEBUG("FT1000:ft1000_ioctl: Card not ready take messages\n"); - result = -EACCES; - } - kfree(dpram_data); - - } - break; - case IOCTL_GET_DPRAM_CMD: - { - struct dpram_blk *pdpram_blk; - IOCTL_DPRAM_BLK __user *pioctl_dpram; - int msglen; - - //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM called\n"); - - if (ft1000_flarion_cnt == 0) { - return (-EBADF); - } - - // Search for matching file object - for (i=0; iapp_info[i].fileobject == &file->f_owner) { - //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); - break; - } - } - - // Could not find application info block - if (i == MAX_NUM_APP) { - DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n"); - result = -EBADF; - break; - } - - result = 0; - pioctl_dpram = argp; - if (list_empty(&info->app_info[i].app_sqlist) == 0) { - //DEBUG("FT1000:ft1000_ioctl:Message detected in slow queue\n"); - spin_lock_irqsave(&free_buff_lock, flags); - pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); - list_del(&pdpram_blk->list); - info->app_info[i].NumOfMsg--; - //DEBUG("FT1000:ft1000_ioctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg); - spin_unlock_irqrestore(&free_buff_lock, flags); - msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ; - result = get_user(msglen, &pioctl_dpram->total_len); - if (result) - break; - msglen = htons(msglen); - //DEBUG("FT1000:ft1000_ioctl:msg length = %x\n", msglen); - if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen)) - { - DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); - result = -EFAULT; - break; - } - - ft1000_free_buffer(pdpram_blk, &freercvpool); - result = msglen; - } - //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM no message\n"); - } - break; - - default: - DEBUG("FT1000:ft1000_ioctl:unknown command: 0x%x\n", command); - result = -ENOTTY; - break; - } - info->fAppMsgPend = 0; - return result; -} - -//--------------------------------------------------------------------------- -// Function: ft1000_release -// -// Parameters: -// -// Description: -// -// Notes: -// -//--------------------------------------------------------------------------- -static int ft1000_release (struct inode *inode, struct file *file) -{ - struct ft1000_info *info; - struct net_device *dev; - int i; - struct dpram_blk *pdpram_blk; - - DEBUG("ft1000_release called\n"); - - dev = file->private_data; - info = netdev_priv(dev); - - if (ft1000_flarion_cnt == 0) { - info->appcnt--; - return (-EBADF); - } - - // Search for matching file object - for (i=0; iapp_info[i].fileobject == &file->f_owner) { - //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); - break; - } - } - - if (i==MAX_NUM_APP) - return 0; - - while (list_empty(&info->app_info[i].app_sqlist) == 0) { - DEBUG("Remove and free memory queue up on slow queue\n"); - pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); - list_del(&pdpram_blk->list); - ft1000_free_buffer(pdpram_blk, &freercvpool); - } - - // initialize application information - info->appcnt--; - DEBUG("ft1000_chdev:%s:appcnt = %d\n", __FUNCTION__, info->appcnt); - info->app_info[i].fileobject = NULL; - - return 0; -} - diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c new file mode 100644 index 000000000000..e39809229d46 --- /dev/null +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c @@ -0,0 +1,784 @@ +//--------------------------------------------------------------------------- +// FT1000 driver for Flarion Flash OFDM NIC Device +// +// Copyright (C) 2006 Flarion Technologies, All rights reserved. +// +// 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. +//--------------------------------------------------------------------------- +// +// File: ft1000_chdev.c +// +// Description: Custom character device dispatch routines. +// +// History: +// 8/29/02 Whc Ported to Linux. +// 6/05/06 Whc Porting to Linux 2.6.9 +// +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ft1000_usb.h" + +static int ft1000_flarion_cnt = 0; + +static int ft1000_open (struct inode *inode, struct file *file); +static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait); +static long ft1000_ioctl(struct file *file, unsigned int command, + unsigned long argument); +static int ft1000_release (struct inode *inode, struct file *file); + +// List to free receive command buffer pool +struct list_head freercvpool; + +// lock to arbitrate free buffer list for receive command data +spinlock_t free_buff_lock; + +int numofmsgbuf = 0; + +// +// Table of entry-point routines for char device +// +static struct file_operations ft1000fops = +{ + .unlocked_ioctl = ft1000_ioctl, + .poll = ft1000_poll_dev, + .open = ft1000_open, + .release = ft1000_release, + .llseek = no_llseek, +}; + +//--------------------------------------------------------------------------- +// Function: ft1000_get_buffer +// +// Parameters: +// +// Returns: +// +// Description: +// +// Notes: +// +//--------------------------------------------------------------------------- +struct dpram_blk *ft1000_get_buffer(struct list_head *bufflist) +{ + unsigned long flags; + struct dpram_blk *ptr; + + spin_lock_irqsave(&free_buff_lock, flags); + // Check if buffer is available + if ( list_empty(bufflist) ) { + DEBUG("ft1000_get_buffer: No more buffer - %d\n", numofmsgbuf); + ptr = NULL; + } + else { + numofmsgbuf--; + ptr = list_entry(bufflist->next, struct dpram_blk, list); + list_del(&ptr->list); + //DEBUG("ft1000_get_buffer: number of free msg buffers = %d\n", numofmsgbuf); + } + spin_unlock_irqrestore(&free_buff_lock, flags); + + return ptr; +} + + + + +//--------------------------------------------------------------------------- +// Function: ft1000_free_buffer +// +// Parameters: +// +// Returns: +// +// Description: +// +// Notes: +// +//--------------------------------------------------------------------------- +void ft1000_free_buffer(struct dpram_blk *pdpram_blk, struct list_head *plist) +{ + unsigned long flags; + + spin_lock_irqsave(&free_buff_lock, flags); + // Put memory back to list + list_add_tail(&pdpram_blk->list, plist); + numofmsgbuf++; + //DEBUG("ft1000_free_buffer: number of free msg buffers = %d\n", numofmsgbuf); + spin_unlock_irqrestore(&free_buff_lock, flags); +} + +//--------------------------------------------------------------------------- +// Function: ft1000_CreateDevice +// +// Parameters: dev - pointer to adapter object +// +// Returns: 0 if successful +// +// Description: Creates a private char device. +// +// Notes: Only called by init_module(). +// +//--------------------------------------------------------------------------- +int ft1000_create_dev(struct ft1000_device *dev) +{ + struct ft1000_info *info = netdev_priv(dev->net); + int result; + int i; + struct dentry *dir, *file; + struct ft1000_debug_dirs *tmp; + + // make a new device name + sprintf(info->DeviceName, "%s%d", "FT1000_", info->CardNumber); + + DEBUG("%s: number of instance = %d\n", __func__, ft1000_flarion_cnt); + DEBUG("DeviceCreated = %x\n", info->DeviceCreated); + + if (info->DeviceCreated) + { + DEBUG("%s: \"%s\" already registered\n", __func__, info->DeviceName); + return -EIO; + } + + + // register the device + DEBUG("%s: \"%s\" debugfs device registration\n", __func__, info->DeviceName); + + tmp = kmalloc(sizeof(struct ft1000_debug_dirs), GFP_KERNEL); + if (tmp == NULL) { + result = -1; + goto fail; + } + + dir = debugfs_create_dir(info->DeviceName, 0); + if (IS_ERR(dir)) { + result = PTR_ERR(dir); + goto debug_dir_fail; + } + + file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir, + NULL, &ft1000fops); + if (IS_ERR(file)) { + result = PTR_ERR(file); + goto debug_file_fail; + } + + tmp->dent = dir; + tmp->file = file; + tmp->int_number = info->CardNumber; + list_add(&(tmp->list), &(info->nodes.list)); + + DEBUG("%s: registered debugfs directory \"%s\"\n", __func__, info->DeviceName); + + // initialize application information + info->appcnt = 0; + for (i=0; iapp_info[i].nTxMsg = 0; + info->app_info[i].nRxMsg = 0; + info->app_info[i].nTxMsgReject = 0; + info->app_info[i].nRxMsgMiss = 0; + info->app_info[i].fileobject = NULL; + info->app_info[i].app_id = i+1; + info->app_info[i].DspBCMsgFlag = 0; + info->app_info[i].NumOfMsg = 0; + init_waitqueue_head(&info->app_info[i].wait_dpram_msg); + INIT_LIST_HEAD (&info->app_info[i].app_sqlist); + } + + info->DeviceCreated = TRUE; + ft1000_flarion_cnt++; + + return 0; + +debug_file_fail: + debugfs_remove(dir); +debug_dir_fail: + kfree(tmp); +fail: + return result; +} + +//--------------------------------------------------------------------------- +// Function: ft1000_DestroyDeviceDEBUG +// +// Parameters: dev - pointer to adapter object +// +// Description: Destroys a private char device. +// +// Notes: Only called by cleanup_module(). +// +//--------------------------------------------------------------------------- +void ft1000_destroy_dev(struct net_device *dev) +{ + struct ft1000_info *info = netdev_priv(dev); + int i; + struct dpram_blk *pdpram_blk; + struct dpram_blk *ptr; + struct list_head *pos, *q; + struct ft1000_debug_dirs *dir; + + DEBUG("%s called\n", __func__); + + + + if (info->DeviceCreated) + { + ft1000_flarion_cnt--; + list_for_each_safe(pos, q, &info->nodes.list) { + dir = list_entry(pos, struct ft1000_debug_dirs, list); + if (dir->int_number == info->CardNumber) { + debugfs_remove(dir->file); + debugfs_remove(dir->dent); + list_del(pos); + kfree(dir); + } + } + DEBUG("%s: unregistered device \"%s\"\n", __func__, + info->DeviceName); + + // Make sure we free any memory reserve for slow Queue + for (i=0; iapp_info[i].app_sqlist) == 0) { + pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); + list_del(&pdpram_blk->list); + ft1000_free_buffer(pdpram_blk, &freercvpool); + + } + wake_up_interruptible(&info->app_info[i].wait_dpram_msg); + } + + // Remove buffer allocated for receive command data + if (ft1000_flarion_cnt == 0) { + while (list_empty(&freercvpool) == 0) { + ptr = list_entry(freercvpool.next, struct dpram_blk, list); + list_del(&ptr->list); + kfree(ptr->pbuffer); + kfree(ptr); + } + } + info->DeviceCreated = FALSE; + } + + +} + +//--------------------------------------------------------------------------- +// Function: ft1000_open +// +// Parameters: +// +// Description: +// +// Notes: +// +//--------------------------------------------------------------------------- +static int ft1000_open (struct inode *inode, struct file *file) +{ + struct ft1000_info *info; + struct ft1000_device *dev = (struct ft1000_device *)inode->i_private; + int i,num; + + DEBUG("%s called\n", __func__); + num = (MINOR(inode->i_rdev) & 0xf); + DEBUG("ft1000_open: minor number=%d\n", num); + + info = file->private_data = netdev_priv(dev->net); + + DEBUG("f_owner = %p number of application = %d\n", (&file->f_owner), info->appcnt ); + + // Check if maximum number of application exceeded + if (info->appcnt > MAX_NUM_APP) { + DEBUG("Maximum number of application exceeded\n"); + return -EACCES; + } + + // Search for available application info block + for (i=0; iapp_info[i].fileobject == NULL) ) { + break; + } + } + + // Fail due to lack of application info block + if (i == MAX_NUM_APP) { + DEBUG("Could not find an application info block\n"); + return -EACCES; + } + + info->appcnt++; + info->app_info[i].fileobject = &file->f_owner; + info->app_info[i].nTxMsg = 0; + info->app_info[i].nRxMsg = 0; + info->app_info[i].nTxMsgReject = 0; + info->app_info[i].nRxMsgMiss = 0; + + nonseekable_open(inode, file); + return 0; +} + + +//--------------------------------------------------------------------------- +// Function: ft1000_poll_dev +// +// Parameters: +// +// Description: +// +// Notes: +// +//--------------------------------------------------------------------------- + +static unsigned int ft1000_poll_dev(struct file *file, poll_table *wait) +{ + struct net_device *dev = file->private_data; + struct ft1000_info *info; + int i; + + //DEBUG("ft1000_poll_dev called\n"); + if (ft1000_flarion_cnt == 0) { + DEBUG("FT1000:ft1000_poll_dev called when ft1000_flarion_cnt is zero\n"); + return (-EBADF); + } + + info = netdev_priv(dev); + + // Search for matching file object + for (i=0; iapp_info[i].fileobject == &file->f_owner) { + //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); + break; + } + } + + // Could not find application info block + if (i == MAX_NUM_APP) { + DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n"); + return ( -EACCES ); + } + + if (list_empty(&info->app_info[i].app_sqlist) == 0) { + DEBUG("FT1000:ft1000_poll_dev:Message detected in slow queue\n"); + return(POLLIN | POLLRDNORM | POLLPRI); + } + + poll_wait (file, &info->app_info[i].wait_dpram_msg, wait); + //DEBUG("FT1000:ft1000_poll_dev:Polling for data from DSP\n"); + + return (0); +} + +//--------------------------------------------------------------------------- +// Function: ft1000_ioctl +// +// Parameters: +// +// Description: +// +// Notes: +// +//--------------------------------------------------------------------------- +static long ft1000_ioctl (struct file *file, unsigned int command, + unsigned long argument) +{ + void __user *argp = (void __user *)argument; + struct net_device *dev; + struct ft1000_info *info; + struct ft1000_device *ft1000dev; + int result=0; + int cmd; + int i; + u16 tempword; + unsigned long flags; + struct timeval tv; + IOCTL_GET_VER get_ver_data; + IOCTL_GET_DSP_STAT get_stat_data; + u8 ConnectionMsg[] = {0x00,0x44,0x10,0x20,0x80,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x93,0x64, + 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x02,0x37,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x7f,0x00, + 0x00,0x01,0x00,0x00}; + + unsigned short ledStat=0; + unsigned short conStat=0; + + //DEBUG("ft1000_ioctl called\n"); + + if (ft1000_flarion_cnt == 0) { + DEBUG("FT1000:ft1000_ioctl called when ft1000_flarion_cnt is zero\n"); + return (-EBADF); + } + + //DEBUG("FT1000:ft1000_ioctl:command = 0x%x argument = 0x%8x\n", command, (u32)argument); + + dev = file->private_data; + info = netdev_priv(dev); + ft1000dev = info->pFt1000Dev; + cmd = _IOC_NR(command); + //DEBUG("FT1000:ft1000_ioctl:cmd = 0x%x\n", cmd); + + // process the command + switch (cmd) { + case IOCTL_REGISTER_CMD: + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_REGISTER called\n"); + result = get_user(tempword, (__u16 __user*)argp); + if (result) { + DEBUG("result = %d failed to get_user\n", result); + break; + } + if (tempword == DSPBCMSGID) { + // Search for matching file object + for (i=0; iapp_info[i].fileobject == &file->f_owner) { + info->app_info[i].DspBCMsgFlag = 1; + DEBUG("FT1000:ft1000_ioctl:Registered for broadcast messages\n"); + break; + } + } + } + break; + + case IOCTL_GET_VER_CMD: + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_VER called\n"); + + get_ver_data.drv_ver = FT1000_DRV_VER; + + if (copy_to_user(argp, &get_ver_data, sizeof(get_ver_data)) ) { + DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); + result = -EFAULT; + break; + } + + DEBUG("FT1000:ft1000_ioctl:driver version = 0x%x\n",(unsigned int)get_ver_data.drv_ver); + + break; + case IOCTL_CONNECT: + // Connect Message + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_CONNECT\n"); + ConnectionMsg[79] = 0xfc; + CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c); + + break; + case IOCTL_DISCONNECT: + // Disconnect Message + DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_DISCONNECT\n"); + ConnectionMsg[79] = 0xfd; + CardSendCommand(ft1000dev, (unsigned short *)ConnectionMsg, 0x4c); + break; + case IOCTL_GET_DSP_STAT_CMD: + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DSP_STAT called\n"); + memset(&get_stat_data, 0, sizeof(get_stat_data)); + memcpy(get_stat_data.DspVer, info->DspVer, DSPVERSZ); + memcpy(get_stat_data.HwSerNum, info->HwSerNum, HWSERNUMSZ); + memcpy(get_stat_data.Sku, info->Sku, SKUSZ); + memcpy(get_stat_data.eui64, info->eui64, EUISZ); + + if (info->ProgConStat != 0xFF) { + ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); + get_stat_data.LedStat = ntohs(ledStat); + DEBUG("FT1000:ft1000_ioctl: LedStat = 0x%x\n", get_stat_data.LedStat); + ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); + get_stat_data.ConStat = ntohs(conStat); + DEBUG("FT1000:ft1000_ioctl: ConStat = 0x%x\n", get_stat_data.ConStat); + } + else { + get_stat_data.ConStat = 0x0f; + } + + + get_stat_data.nTxPkts = info->stats.tx_packets; + get_stat_data.nRxPkts = info->stats.rx_packets; + get_stat_data.nTxBytes = info->stats.tx_bytes; + get_stat_data.nRxBytes = info->stats.rx_bytes; + do_gettimeofday ( &tv ); + get_stat_data.ConTm = (u32)(tv.tv_sec - info->ConTm); + DEBUG("Connection Time = %d\n", (int)get_stat_data.ConTm); + if (copy_to_user(argp, &get_stat_data, sizeof(get_stat_data)) ) { + DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); + result = -EFAULT; + break; + } + DEBUG("ft1000_chioctl: GET_DSP_STAT succeed\n"); + break; + case IOCTL_SET_DPRAM_CMD: + { + IOCTL_DPRAM_BLK *dpram_data = NULL; + //IOCTL_DPRAM_COMMAND dpram_command; + u16 qtype; + u16 msgsz; + struct pseudo_hdr *ppseudo_hdr; + u16 *pmsg; + u16 total_len; + u16 app_index; + u16 status; + + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_SET_DPRAM called\n"); + + + if (ft1000_flarion_cnt == 0) { + return (-EBADF); + } + + if (info->DrvMsgPend) { + return (-ENOTTY); + } + + if ( (info->DspAsicReset) || (info->fProvComplete == 0) ) { + return (-EACCES); + } + + info->fAppMsgPend = 1; + + if (info->CardReady) { + + //DEBUG("FT1000:ft1000_ioctl: try to SET_DPRAM \n"); + + // Get the length field to see how many bytes to copy + result = get_user(msgsz, (__u16 __user *)argp); + msgsz = ntohs (msgsz); + //DEBUG("FT1000:ft1000_ioctl: length of message = %d\n", msgsz); + + if (msgsz > MAX_CMD_SQSIZE) { + DEBUG("FT1000:ft1000_ioctl: bad message length = %d\n", msgsz); + result = -EINVAL; + break; + } + + result = -ENOMEM; + dpram_data = kmalloc(msgsz + 2, GFP_KERNEL); + if (!dpram_data) + break; + + if ( copy_from_user(dpram_data, argp, msgsz+2) ) { + DEBUG("FT1000:ft1000_ChIoctl: copy fault occurred\n"); + result = -EFAULT; + } + else { + // Check if this message came from a registered application + for (i=0; iapp_info[i].fileobject == &file->f_owner) { + break; + } + } + if (i==MAX_NUM_APP) { + DEBUG("FT1000:No matching application fileobject\n"); + result = -EINVAL; + kfree(dpram_data); + break; + } + app_index = i; + + // Check message qtype type which is the lower byte within qos_class + qtype = ntohs(dpram_data->pseudohdr.qos_class) & 0xff; + //DEBUG("FT1000_ft1000_ioctl: qtype = %d\n", qtype); + if (qtype) { + } + else { + // Put message into Slow Queue + // Only put a message into the DPRAM if msg doorbell is available + status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); + //DEBUG("FT1000_ft1000_ioctl: READ REGISTER tempword=%x\n", tempword); + if (tempword & FT1000_DB_DPRAM_TX) { + // Suspend for 2ms and try again due to DSP doorbell busy + mdelay(2); + status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); + if (tempword & FT1000_DB_DPRAM_TX) { + // Suspend for 1ms and try again due to DSP doorbell busy + mdelay(1); + status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); + if (tempword & FT1000_DB_DPRAM_TX) { + status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); + if (tempword & FT1000_DB_DPRAM_TX) { + // Suspend for 3ms and try again due to DSP doorbell busy + mdelay(3); + status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_DOORBELL); + if (tempword & FT1000_DB_DPRAM_TX) { + DEBUG("FT1000:ft1000_ioctl:Doorbell not available\n"); + result = -ENOTTY; + kfree(dpram_data); + break; + } + } + } + } + } + + //DEBUG("FT1000_ft1000_ioctl: finished reading register\n"); + + // Make sure we are within the limits of the slow queue memory limitation + if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) { + // Need to put sequence number plus new checksum for message + pmsg = (u16 *)&dpram_data->pseudohdr; + ppseudo_hdr = (struct pseudo_hdr *)pmsg; + total_len = msgsz+2; + if (total_len & 0x1) { + total_len++; + } + + // Insert slow queue sequence number + ppseudo_hdr->seq_num = info->squeseqnum++; + ppseudo_hdr->portsrc = info->app_info[app_index].app_id; + // Calculate new checksum + ppseudo_hdr->checksum = *pmsg++; + //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum); + for (i=1; i<7; i++) { + ppseudo_hdr->checksum ^= *pmsg++; + //DEBUG("checksum = 0x%x\n", ppseudo_hdr->checksum); + } + pmsg++; + ppseudo_hdr = (struct pseudo_hdr *)pmsg; + CardSendCommand(ft1000dev,(unsigned short*)dpram_data,total_len+2); + + + info->app_info[app_index].nTxMsg++; + } + else { + result = -EINVAL; + } + } + } + } + else { + DEBUG("FT1000:ft1000_ioctl: Card not ready take messages\n"); + result = -EACCES; + } + kfree(dpram_data); + + } + break; + case IOCTL_GET_DPRAM_CMD: + { + struct dpram_blk *pdpram_blk; + IOCTL_DPRAM_BLK __user *pioctl_dpram; + int msglen; + + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM called\n"); + + if (ft1000_flarion_cnt == 0) { + return (-EBADF); + } + + // Search for matching file object + for (i=0; iapp_info[i].fileobject == &file->f_owner) { + //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); + break; + } + } + + // Could not find application info block + if (i == MAX_NUM_APP) { + DEBUG("FT1000:ft1000_ioctl:Could not find application info block\n"); + result = -EBADF; + break; + } + + result = 0; + pioctl_dpram = argp; + if (list_empty(&info->app_info[i].app_sqlist) == 0) { + //DEBUG("FT1000:ft1000_ioctl:Message detected in slow queue\n"); + spin_lock_irqsave(&free_buff_lock, flags); + pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); + list_del(&pdpram_blk->list); + info->app_info[i].NumOfMsg--; + //DEBUG("FT1000:ft1000_ioctl:NumOfMsg for app %d = %d\n", i, info->app_info[i].NumOfMsg); + spin_unlock_irqrestore(&free_buff_lock, flags); + msglen = ntohs(*(u16 *)pdpram_blk->pbuffer) + PSEUDOSZ; + result = get_user(msglen, &pioctl_dpram->total_len); + if (result) + break; + msglen = htons(msglen); + //DEBUG("FT1000:ft1000_ioctl:msg length = %x\n", msglen); + if(copy_to_user (&pioctl_dpram->pseudohdr, pdpram_blk->pbuffer, msglen)) + { + DEBUG("FT1000:ft1000_ioctl: copy fault occurred\n"); + result = -EFAULT; + break; + } + + ft1000_free_buffer(pdpram_blk, &freercvpool); + result = msglen; + } + //DEBUG("FT1000:ft1000_ioctl: IOCTL_FT1000_GET_DPRAM no message\n"); + } + break; + + default: + DEBUG("FT1000:ft1000_ioctl:unknown command: 0x%x\n", command); + result = -ENOTTY; + break; + } + info->fAppMsgPend = 0; + return result; +} + +//--------------------------------------------------------------------------- +// Function: ft1000_release +// +// Parameters: +// +// Description: +// +// Notes: +// +//--------------------------------------------------------------------------- +static int ft1000_release (struct inode *inode, struct file *file) +{ + struct ft1000_info *info; + struct net_device *dev; + int i; + struct dpram_blk *pdpram_blk; + + DEBUG("ft1000_release called\n"); + + dev = file->private_data; + info = netdev_priv(dev); + + if (ft1000_flarion_cnt == 0) { + info->appcnt--; + return (-EBADF); + } + + // Search for matching file object + for (i=0; iapp_info[i].fileobject == &file->f_owner) { + //DEBUG("FT1000:ft1000_ioctl: Message is for AppId = %d\n", info->app_info[i].app_id); + break; + } + } + + if (i==MAX_NUM_APP) + return 0; + + while (list_empty(&info->app_info[i].app_sqlist) == 0) { + DEBUG("Remove and free memory queue up on slow queue\n"); + pdpram_blk = list_entry(info->app_info[i].app_sqlist.next, struct dpram_blk, list); + list_del(&pdpram_blk->list); + ft1000_free_buffer(pdpram_blk, &freercvpool); + } + + // initialize application information + info->appcnt--; + DEBUG("ft1000_chdev:%s:appcnt = %d\n", __FUNCTION__, info->appcnt); + info->app_info[i].fileobject = NULL; + + return 0; +} + -- cgit v1.2.3 From 0ce72ea3b2f29e5755b095a5b217b9bab8386a03 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 14 Dec 2010 14:02:54 +0100 Subject: staging: ft1000: Fix camelcase variable names. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- .../staging/ft1000/ft1000-usb/ft1000_download.c | 204 ++++++++++----------- 1 file changed, 102 insertions(+), 102 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index e4905ad2badc..17546d8ec08d 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -772,26 +772,26 @@ static u32 write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 ** u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLength) { - u16 Status = STATUS_SUCCESS; - u32 uiState; + u16 status = STATUS_SUCCESS; + u32 state; u16 handshake; - struct pseudo_hdr *pHdr; - u16 usHdrLength; + struct pseudo_hdr *pseudo_header; + u16 pseudo_header_len; long word_length; u16 request; u16 temp; u16 tempword; - struct dsp_file_hdr *pFileHdr5; - struct dsp_image_info *pDspImageInfoV6 = NULL; + struct dsp_file_hdr *file_hdr; + struct dsp_image_info *dsp_img_info = NULL; long requested_version; - bool bGoodVersion; - struct drv_msg *pMailBoxData; - u16 *pUsData = NULL; - u16 *pUsFile = NULL; - u8 *pUcFile = NULL; - u8 *pBootEnd = NULL, *pCodeEnd= NULL; - int imageN; + bool correct_version; + struct drv_msg *mailbox_data; + u16 *data = NULL; + u16 *s_file = NULL; + u8 *c_file = NULL; + u8 *boot_end = NULL, *code_end= NULL; + int image; long loader_code_address, loader_code_size = 0; long run_address = 0, run_size = 0; @@ -814,24 +814,24 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng // Get version id of file, at first 4 bytes of file, for newer files. // - uiState = STATE_START_DWNLD; + state = STATE_START_DWNLD; - pFileHdr5 = (struct dsp_file_hdr *)pFileStart; + file_hdr = (struct dsp_file_hdr *)pFileStart; ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); - pUsFile = (u16 *)(pFileStart + pFileHdr5->loader_offset); - pUcFile = (u8 *)(pFileStart + pFileHdr5->loader_offset); + s_file = (u16 *)(pFileStart + file_hdr->loader_offset); + c_file = (u8 *)(pFileStart + file_hdr->loader_offset); - pBootEnd = (u8 *)(pFileStart + pFileHdr5->loader_code_end); + boot_end = (u8 *)(pFileStart + file_hdr->loader_code_end); - loader_code_address = pFileHdr5->loader_code_address; - loader_code_size = pFileHdr5->loader_code_size; - bGoodVersion = FALSE; + loader_code_address = file_hdr->loader_code_address; + loader_code_size = file_hdr->loader_code_size; + correct_version = FALSE; - while ((Status == STATUS_SUCCESS) && (uiState != STATE_DONE_FILE)) + while ((status == STATUS_SUCCESS) && (state != STATE_DONE_FILE)) { - switch (uiState) + switch (state) { case STATE_START_DWNLD: DEBUG("FT1000:STATE_START_DWNLD\n"); @@ -848,10 +848,10 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng else { DEBUG("FT1000:download:Download error: Handshake failed\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; } - uiState = STATE_BOOT_DWNLD; + state = STATE_BOOT_DWNLD; break; @@ -878,11 +878,11 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng case REQUEST_DONE_BL: DEBUG("FT1000:REQUEST_DONE_BL\n"); /* Reposition ptrs to beginning of code section */ - pUsFile = (u16 *)(pBootEnd); - pUcFile = (u8 *)(pBootEnd); - //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile); - //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile); - uiState = STATE_CODE_DWNLD; + s_file = (u16 *)(boot_end); + c_file = (u8 *)(boot_end); + //DEBUG("FT1000:download:s_file = 0x%8x\n", (int)s_file); + //DEBUG("FT1000:download:c_file = 0x%8x\n", (int)c_file); + state = STATE_CODE_DWNLD; pft1000info->fcodeldr = 1; break; case REQUEST_CODE_SEGMENT: @@ -893,17 +893,17 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng if (word_length > MAX_LENGTH) { DEBUG("FT1000:download:Download error: Max length exceeded\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } - if ( (word_length*2 + pUcFile) > pBootEnd) + if ( (word_length*2 + c_file) > boot_end) { /* * Error, beyond boot code range. */ DEBUG("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundry.\n", (int)word_length); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } /* @@ -914,12 +914,12 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng word_length++; word_length = word_length / 2; - Status = write_blk(ft1000dev, &pUsFile, &pUcFile, word_length); - //DEBUG("write_blk returned %d\n", Status); + status = write_blk(ft1000dev, &s_file, &c_file, word_length); + //DEBUG("write_blk returned %d\n", status); break; default: DEBUG("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n",request); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } if (pft1000info->usbboot) @@ -930,7 +930,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng else { DEBUG("FT1000:download:Download error: Handshake failed\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; } break; @@ -959,7 +959,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng break; case REQUEST_RUN_ADDRESS: DEBUG("FT1000:download: REQUEST_RUN_ADDRESS\n"); - if (bGoodVersion) + if (correct_version) { DEBUG("FT1000:download:run_address = 0x%8x\n", (int)run_address); put_request_value(ft1000dev, run_address); @@ -967,13 +967,13 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng else { DEBUG("FT1000:download:Download error: Got Run address request before image offset request.\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } break; case REQUEST_CODE_LENGTH: DEBUG("FT1000:download:REQUEST_CODE_LENGTH\n"); - if (bGoodVersion) + if (correct_version) { DEBUG("FT1000:download:run_size = 0x%8x\n", (int)run_size); put_request_value(ft1000dev, run_size); @@ -981,23 +981,23 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng else { DEBUG("FT1000:download:Download error: Got Size request before image offset request.\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } break; case REQUEST_DONE_CL: pft1000info->usbboot = 3; /* Reposition ptrs to beginning of provisioning section */ - pUsFile = (u16 *)(pFileStart + pFileHdr5->commands_offset); - pUcFile = (u8 *)(pFileStart + pFileHdr5->commands_offset); - uiState = STATE_DONE_DWNLD; + s_file = (u16 *)(pFileStart + file_hdr->commands_offset); + c_file = (u8 *)(pFileStart + file_hdr->commands_offset); + state = STATE_DONE_DWNLD; break; case REQUEST_CODE_SEGMENT: //DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n"); - if (!bGoodVersion) + if (!correct_version) { DEBUG("FT1000:download:Download error: Got Code Segment request before image offset request.\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } #if 0 @@ -1011,17 +1011,17 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng #endif { DEBUG("FT1000:download:Download error: Max length exceeded\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } - if ( (word_length*2 + pUcFile) > pCodeEnd) + if ( (word_length*2 + c_file) > code_end) { /* * Error, beyond boot code range. */ DEBUG("FT1000:download:Download error: Requested len=%d exceeds DSP code boundry.\n", (int)word_length); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } /* @@ -1032,7 +1032,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng word_length++; word_length = word_length / 2; - write_blk_fifo (ft1000dev, &pUsFile, &pUcFile, word_length); + write_blk_fifo (ft1000dev, &s_file, &c_file, word_length); if (pft1000info->usbboot == 0) pft1000info->usbboot++; if (pft1000info->usbboot == 1) { @@ -1047,13 +1047,13 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng // Convert length from byte count to word count. Make sure we round up. word_length = (long)(pft1000info->DSPInfoBlklen + 1)/2; put_request_value(ft1000dev, word_length); - pMailBoxData = (struct drv_msg *)&(pft1000info->DSPInfoBlk[0]); + mailbox_data = (struct drv_msg *)&(pft1000info->DSPInfoBlk[0]); /* * Position ASIC DPRAM auto-increment pointer. */ - pUsData = (u16 *)&pMailBoxData->data[0]; + data = (u16 *)&mailbox_data->data[0]; dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; if (word_length & 0x1) word_length++; @@ -1064,22 +1064,22 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng for (; word_length > 0; word_length--) /* In words */ { - templong = *pUsData++; - templong |= (*pUsData++ << 16); - Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong); + templong = *data++; + templong |= (*data++ << 16); + status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong); } break; case REQUEST_VERSION_INFO: DEBUG("FT1000:download:REQUEST_VERSION_INFO\n"); - word_length = pFileHdr5->version_data_size; + word_length = file_hdr->version_data_size; put_request_value(ft1000dev, word_length); /* * Position ASIC DPRAM auto-increment pointer. */ - pUsFile = (u16 *)(pFileStart + pFileHdr5->version_data_offset); + s_file = (u16 *)(pFileStart + file_hdr->version_data_offset); dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; @@ -1092,59 +1092,59 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng for (; word_length > 0; word_length--) /* In words */ { - templong = ntohs(*pUsFile++); - temp = ntohs(*pUsFile++); + templong = ntohs(*s_file++); + temp = ntohs(*s_file++); templong |= (temp << 16); - Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong); + status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong); } break; case REQUEST_CODE_BY_VERSION: DEBUG("FT1000:download:REQUEST_CODE_BY_VERSION\n"); - bGoodVersion = FALSE; + correct_version = FALSE; requested_version = get_request_value(ft1000dev); - pDspImageInfoV6 = (struct dsp_image_info *)(pFileStart + sizeof(struct dsp_file_hdr )); + dsp_img_info = (struct dsp_image_info *)(pFileStart + sizeof(struct dsp_file_hdr )); - for (imageN = 0; imageN < pFileHdr5->nDspImages; imageN++) + for (image = 0; image < file_hdr->nDspImages; image++) { - temp = (u16)(pDspImageInfoV6->version); + temp = (u16)(dsp_img_info->version); templong = temp; - temp = (u16)(pDspImageInfoV6->version >> 16); + temp = (u16)(dsp_img_info->version >> 16); templong |= (temp << 16); if (templong == (u32)requested_version) { - bGoodVersion = TRUE; - DEBUG("FT1000:download: bGoodVersion is TRUE\n"); - pUsFile = (u16 *)(pFileStart + pDspImageInfoV6->begin_offset); - pUcFile = (u8 *)(pFileStart + pDspImageInfoV6->begin_offset); - pCodeEnd = (u8 *)(pFileStart + pDspImageInfoV6->end_offset); - run_address = pDspImageInfoV6->run_address; - run_size = pDspImageInfoV6->image_size; - image_chksum = (u32)pDspImageInfoV6->checksum; + correct_version = TRUE; + DEBUG("FT1000:download: correct_version is TRUE\n"); + s_file = (u16 *)(pFileStart + dsp_img_info->begin_offset); + c_file = (u8 *)(pFileStart + dsp_img_info->begin_offset); + code_end = (u8 *)(pFileStart + dsp_img_info->end_offset); + run_address = dsp_img_info->run_address; + run_size = dsp_img_info->image_size; + image_chksum = (u32)dsp_img_info->checksum; break; } - pDspImageInfoV6++; + dsp_img_info++; } //end of for - if (!bGoodVersion) + if (!correct_version) { /* * Error, beyond boot code range. */ DEBUG("FT1000:download:Download error: Bad Version Request = 0x%x.\n",(int)requested_version); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } break; default: DEBUG("FT1000:download:Download error: Bad request type=%d in CODE download state.\n",request); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } if (pft1000info->usbboot) @@ -1155,94 +1155,94 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32 FileLeng else { DEBUG("FT1000:download:Download error: Handshake failed\n"); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; } break; case STATE_DONE_DWNLD: DEBUG("FT1000:download:Code loader is done...\n"); - uiState = STATE_SECTION_PROV; + state = STATE_SECTION_PROV; break; case STATE_SECTION_PROV: DEBUG("FT1000:download:STATE_SECTION_PROV\n"); - pHdr = (struct pseudo_hdr *)pUcFile; + pseudo_header = (struct pseudo_hdr *)c_file; - if (pHdr->checksum == hdr_checksum(pHdr)) + if (pseudo_header->checksum == hdr_checksum(pseudo_header)) { - if (pHdr->portdest != 0x80 /* Dsp OAM */) + if (pseudo_header->portdest != 0x80 /* Dsp OAM */) { - uiState = STATE_DONE_PROV; + state = STATE_DONE_PROV; break; } - usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */ + pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */ // Get buffer for provisioning data - pbuffer = kmalloc((usHdrLength + sizeof(struct pseudo_hdr)), GFP_ATOMIC); + pbuffer = kmalloc((pseudo_header_len + sizeof(struct pseudo_hdr)), GFP_ATOMIC); if (pbuffer) { - memcpy(pbuffer, (void *)pUcFile, (u32)(usHdrLength + sizeof(struct pseudo_hdr))); + memcpy(pbuffer, (void *)c_file, (u32)(pseudo_header_len + sizeof(struct pseudo_hdr))); // link provisioning data pprov_record = kmalloc(sizeof(struct prov_record), GFP_ATOMIC); if (pprov_record) { pprov_record->pprov_data = pbuffer; list_add_tail (&pprov_record->list, &pft1000info->prov_list); // Move to next entry if available - pUcFile = (u8 *)((unsigned long)pUcFile + (u32)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); - if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) { - uiState = STATE_DONE_FILE; + c_file = (u8 *)((unsigned long)c_file + (u32)((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); + if ( (unsigned long)(c_file) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) { + state = STATE_DONE_FILE; } } else { kfree(pbuffer); - Status = STATUS_FAILURE; + status = STATUS_FAILURE; } } else { - Status = STATUS_FAILURE; + status = STATUS_FAILURE; } } else { /* Checksum did not compute */ - Status = STATUS_FAILURE; + status = STATUS_FAILURE; } - DEBUG("ft1000:download: after STATE_SECTION_PROV, uiState = %d, Status= %d\n", uiState, Status); + DEBUG("ft1000:download: after STATE_SECTION_PROV, state = %d, status= %d\n", state, status); break; case STATE_DONE_PROV: DEBUG("FT1000:download:STATE_DONE_PROV\n"); - uiState = STATE_DONE_FILE; + state = STATE_DONE_FILE; break; default: - Status = STATUS_FAILURE; + status = STATUS_FAILURE; break; } /* End Switch */ - if (Status != STATUS_SUCCESS) { + if (status != STATUS_SUCCESS) { break; } /**** // Check if Card is present - Status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); - if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { + status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); + if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { break; } - Status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); - if ( (Status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { + status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); + if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { break; } ****/ } /* End while */ - DEBUG("Download exiting with status = 0x%8x\n", Status); + DEBUG("Download exiting with status = 0x%8x\n", status); ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL); - return Status; + return status; } -- cgit v1.2.3 From 91cda632ebc6ea84fd7a45efb6d4452c34985731 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 14 Dec 2010 14:02:55 +0100 Subject: staging: ft1000: Fix kernel panic when use ioctl. During ioctl testing was observed kernel panic beuase file->private_data pointer was not correctly set when debugfs file was created. Add correct pointer setup. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_debug.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c index e39809229d46..149ba59f96bf 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c @@ -174,7 +174,7 @@ int ft1000_create_dev(struct ft1000_device *dev) } file = debugfs_create_file("device", S_IRUGO | S_IWUSR, dir, - NULL, &ft1000fops); + dev, &ft1000fops); if (IS_ERR(file)) { result = PTR_ERR(file); goto debug_file_fail; @@ -398,7 +398,6 @@ static long ft1000_ioctl (struct file *file, unsigned int command, unsigned long argument) { void __user *argp = (void __user *)argument; - struct net_device *dev; struct ft1000_info *info; struct ft1000_device *ft1000dev; int result=0; @@ -428,9 +427,8 @@ static long ft1000_ioctl (struct file *file, unsigned int command, //DEBUG("FT1000:ft1000_ioctl:command = 0x%x argument = 0x%8x\n", command, (u32)argument); - dev = file->private_data; - info = netdev_priv(dev); - ft1000dev = info->pFt1000Dev; + info = file->private_data; + ft1000dev = info->pFt1000Dev; cmd = _IOC_NR(command); //DEBUG("FT1000:ft1000_ioctl:cmd = 0x%x\n", cmd); -- cgit v1.2.3 From 3555a4c35e59c0217983f5df0cfe39a9fa65c2df Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 15 Dec 2010 00:14:30 +0200 Subject: Staging: comedi: Fix coding style issues in ii_pci20kc.c This patch fixes the following issues in file ii_pci20kc.c: WARNING: please, no space before tabs WARNING: unnecessary whitespace before a quoted newline WARNING: line over 80 characters Signed-off-by: Xenofon Foukas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ii_pci20kc.c | 66 ++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 39a6a850d63c..e4711ef54719 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -19,7 +19,7 @@ * - 16 bit * * only ONE PCI-20341 module possible - * only ONE PCI-20006 module possible + * only ONE PCI-20006 module possible * no extern trigger implemented * * NOT WORKING (but soon) only 4 on-board differential channels supported @@ -83,11 +83,11 @@ options for PCI-20341M: #include "../comedidev.h" #define PCI20000_ID 0x1d -#define PCI20341_ID 0x77 -#define PCI20006_ID 0xe3 +#define PCI20341_ID 0x77 +#define PCI20006_ID 0xe3 #define PCI20xxx_EMPTY_ID 0xff -#define PCI20000_OFFSET 0x100 +#define PCI20000_OFFSET 0x100 #define PCI20000_MODULES 3 #define PCI20000_DIO_0 0x80 @@ -246,7 +246,7 @@ static int pci20xxx_attach(struct comedi_device *dev, pci20006_init(dev, s, it->options[2 * i + 2], it->options[2 * i + 3]); printk(KERN_INFO "comedi%d: " - "ii_pci20kc PCI-20006 module in slot %d \n", + "ii_pci20kc PCI-20006 module in slot %d\n", dev->minor, i + 1); break; case PCI20341_ID: @@ -255,7 +255,7 @@ static int pci20xxx_attach(struct comedi_device *dev, pci20341_init(dev, s, it->options[2 * i + 2], it->options[2 * i + 3]); printk(KERN_INFO "comedi%d: " - "ii_pci20kc PCI-20341 module in slot %d \n", + "ii_pci20kc PCI-20341 module in slot %d\n", dev->minor, i + 1); break; default: @@ -376,9 +376,20 @@ static int pci20341_insn_read(struct comedi_device *dev, static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 }; static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 }; -static const struct comedi_lrange range_bipolar0_5 = { 1, {BIP_RANGE(0.5)} }; -static const struct comedi_lrange range_bipolar0_05 = { 1, {BIP_RANGE(0.05)} }; -static const struct comedi_lrange range_bipolar0_025 = { 1, {BIP_RANGE(0.025)} }; +static const struct comedi_lrange range_bipolar0_5 = { + 1, + {BIP_RANGE(0.5)} +}; + +static const struct comedi_lrange range_bipolar0_05 = { + 1, + {BIP_RANGE(0.05)} +}; + +static const struct comedi_lrange range_bipolar0_025 = { + 1, + {BIP_RANGE(0.025)} +}; static const struct comedi_lrange *const pci20341_ranges[] = { &range_bipolar5, @@ -408,12 +419,18 @@ static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, s->maxdata = 0xffff; s->range_table = pci20341_ranges[opt0]; - option = sdp->pci20341.timebase | PCI20341_REPMODE; /* depends on gain, trigger, repetition mode */ - - writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG); /* initialize Module */ - writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS); /* set Pacer */ - writeb(option, sdp->iobase + PCI20341_OPT_REG); /* option register */ - writeb(sdp->pci20341.settling_time, sdp->iobase + PCI20341_SET_TIME_REG); /* settling time counter */ + /* depends on gain, trigger, repetition mode */ + option = sdp->pci20341.timebase | PCI20341_REPMODE; + + /* initialize Module */ + writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG); + /* set Pacer */ + writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS); + /* option register */ + writeb(option, sdp->iobase + PCI20341_OPT_REG); + /* settling time counter */ + writeb(sdp->pci20341.settling_time, + sdp->iobase + PCI20341_SET_TIME_REG); /* trigger not implemented */ return 0; } @@ -429,11 +446,15 @@ static int pci20341_insn_read(struct comedi_device *dev, unsigned int clb; /* channel list byte */ unsigned int boarddata; - writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG); /* write number of input channels */ + /* write number of input channels */ + writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG); clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3) | CR_CHAN(insn->chanspec); writeb(clb, sdp->iobase + PCI20341_CHAN_LIST); - writeb(0x00, sdp->iobase + PCI20341_CC_RESET); /* reset settling time counter and trigger delay counter */ + + /* reset settling time counter and trigger delay counter */ + writeb(0x00, sdp->iobase + PCI20341_CC_RESET); + writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET); /* generate Pacer */ @@ -444,9 +465,12 @@ static int pci20341_insn_read(struct comedi_device *dev, * the whole interrupt stuff */ j = 0; - readb(sdp->iobase + PCI20341_SOFT_PACER); /* generate Pacer */ + /* generate Pacer */ + readb(sdp->iobase + PCI20341_SOFT_PACER); + eoc = readb(sdp->iobase + PCI20341_STATUS_REG); - while ((eoc < 0x80) && j < 100) { /* poll Interrupt Flag */ + /* poll Interrupt Flag */ + while ((eoc < 0x80) && j < 100) { j++; eoc = readb(sdp->iobase + PCI20341_STATUS_REG); } @@ -460,7 +484,9 @@ static int pci20341_insn_read(struct comedi_device *dev, lo = readb(sdp->iobase + PCI20341_LDATA); hi = readb(sdp->iobase + PCI20341_LDATA + 1); boarddata = lo + 0x100 * hi; - data[i] = (short)((boarddata + 0x8000) & 0xffff); /* board-data -> comedi-data */ + + /* board-data -> comedi-data */ + data[i] = (short)((boarddata + 0x8000) & 0xffff); } return i; -- cgit v1.2.3 From c9c62f4e2c9b526c5cbade3f3a61f126e6587c16 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 15 Dec 2010 19:44:20 +0200 Subject: Staging: comedi: Fix checkpatch.pl issues in file s526.c This patch fixes the following issues in s526.c: WARNING: printk() should include KERN_ facility level WARNING: line over 80 characters ERROR: do not use C99 // comments WARNING: space prohibited between function name and open parenthesis '(' WARNING: braces {} are not necessary for any arm of this statement WARNING: suspect code indent for conditional statements (16, 16) Signed-off-by: Xenofon Foukas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/s526.c | 139 ++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 3607aaee4af6..2b34daedc3d7 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -114,7 +114,7 @@ static const int s526_ports[] = { }; struct counter_mode_register_t { -#if defined (__LITTLE_ENDIAN_BITFIELD) +#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned short coutSource:1; unsigned short coutPolarity:1; unsigned short autoLoadResetRcap:3; @@ -207,7 +207,9 @@ static const struct s526_board s526_boards[] = { /* this structure is for data unique to this hardware driver. If several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device struct. */ + feel free to suggest moving the variable to the struct comedi_device + struct. +*/ struct s526_private { int data; @@ -304,7 +306,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* int subdev_channel = 0; */ union cmReg cmReg; - printk("comedi%d: s526: ", dev->minor); + printk(KERN_INFO "comedi%d: s526: ", dev->minor); iobase = it->options[0]; if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) { @@ -317,7 +319,8 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) /*** make it a little quieter, exw, 8/29/06 for (i = 0; i < S526_NUM_PORTS; i++) { - printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); + printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), + inw(ADDR_REG(s526_ports[i]))); } ***/ @@ -402,7 +405,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - printk("attached\n"); + printk(KERN_INFO "attached\n"); return 1; @@ -411,7 +414,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* One-shot (software trigger) */ cmReg.reg.coutSource = 0; /* out RCAP */ cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 1; /* Auto load 0:disabled, 1:enabled */ + cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ cmReg.reg.ctEnableCtrl = 2; /* Hardware */ cmReg.reg.clockSource = 2; /* Internal */ @@ -426,10 +429,12 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ - - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */ + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Load the counter from PR0 */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Reset RCAP (fires one-shot) */ + outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); #else @@ -447,11 +452,12 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) cmReg.reg.reserved = 0; n = 0; - printk("Mode reg=0x%04x, 0x%04lx\n", cmReg.value, ADDR_CHAN_REG(REG_C0M, - n)); + printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", + cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); udelay(1000); - printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n))); + printk(KERN_INFO "Read back mode reg=0x%04x\n", + inw(ADDR_CHAN_REG(REG_C0M, n))); /* Load the pre-load register high word */ /* value = (short) (0x55); */ @@ -466,20 +472,23 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { - outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); /* Reset the counter */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); /* Load the counter from PR0 */ + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); + /* Load the counter from PR0 */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); } outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); udelay(1000); - printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n))); + printk(KERN_INFO "Read back mode reg=0x%04x\n", + inw(ADDR_CHAN_REG(REG_C0M, n))); #endif - printk("Current registres:\n"); + printk(KERN_INFO "Current registres:\n"); for (i = 0; i < S526_NUM_PORTS; i++) { - printk("0x%02lx: 0x%04x\n", ADDR_REG(s526_ports[i]), - inw(ADDR_REG(s526_ports[i]))); + printk(KERN_INFO "0x%02lx: 0x%04x\n", + ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); } return 1; } @@ -494,7 +503,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) */ static int s526_detach(struct comedi_device *dev) { - printk("comedi%d: s526: remove\n", dev->minor); + printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor); if (dev->iobase > 0) release_region(dev->iobase, S526_IOSIZE); @@ -513,7 +522,7 @@ static int s526_gpct_rinsn(struct comedi_device *dev, /* Check if (n > 0) */ if (insn->n <= 0) { - printk("s526: INSN_READ: n should be > 0\n"); + printk(KERN_ERR "s526: INSN_READ: n should be > 0\n"); return -EINVAL; } /* Read the low word first */ @@ -522,7 +531,8 @@ static int s526_gpct_rinsn(struct comedi_device *dev, datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); data[i] = (int)(datahigh & 0x00FF); data[i] = (data[i] << 16) | (datalow & 0xFFFF); -/* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow); */ + /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", + counter_channel, data[i], datahigh, datalow); */ } return i; } @@ -536,7 +546,8 @@ static int s526_gpct_insn_config(struct comedi_device *dev, short value; union cmReg cmReg; -/* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel); */ + /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", + subdev_channel); */ for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { devpriv->s526_gpct_config[subdev_channel].data[i] = @@ -554,7 +565,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[2]: Pre-load Register Value data[3]: Conter Control Register */ - printk("s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); + printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); devpriv->s526_gpct_config[subdev_channel].app = PositionMeasurement; @@ -563,7 +574,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, /* One-shot (software trigger) */ cmReg.reg.coutSource = 0; /* out RCAP */ cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ + cmReg.reg.autoLoadResetRcap = 0;/* Auto load disabled */ cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ cmReg.reg.ctEnableCtrl = 2; /* Hardware */ cmReg.reg.clockSource = 2; /* Internal */ @@ -578,10 +589,13 @@ static int s526_gpct_insn_config(struct comedi_device *dev, outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Load the counter from PR0 */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */ + /* Reset RCAP (fires one-shot) */ + outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); #endif @@ -594,30 +608,34 @@ static int s526_gpct_insn_config(struct comedi_device *dev, /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ -/* outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); Load the counter from PR0 */ + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Load the counter from PR0 + * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + */ } #else - cmReg.reg.countDirCtrl = 0; /* 0 quadrature, 1 software control */ + /* 0 quadrature, 1 software control */ + cmReg.reg.countDirCtrl = 0; /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ - if (insn->data[1] == GPCT_X2) { + if (insn->data[1] == GPCT_X2) cmReg.reg.clockSource = 1; - } else if (insn->data[1] == GPCT_X4) { + else if (insn->data[1] == GPCT_X4) cmReg.reg.clockSource = 2; - } else { + else cmReg.reg.clockSource = 0; - } /* When to take into account the indexpulse: */ - if (insn->data[2] == GPCT_IndexPhaseLowLow) { + /*if (insn->data[2] == GPCT_IndexPhaseLowLow) { } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { - } + }*/ /* Take into account the index pulse? */ if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) - cmReg.reg.autoLoadResetRcap = 4; /* Auto load with INDEX^ */ + /* Auto load with INDEX^ */ + cmReg.reg.autoLoadResetRcap = 4; /* Set Counter Mode Register */ cmReg.value = (short)(insn->data[1] & 0xFFFF); @@ -638,8 +656,10 @@ static int s526_gpct_insn_config(struct comedi_device *dev, } /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Load the counter from PR0 */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); } #endif break; @@ -652,7 +672,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n"); + printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n"); devpriv->s526_gpct_config[subdev_channel].app = SinglePulseGeneration; @@ -697,7 +717,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n"); + printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n"); devpriv->s526_gpct_config[subdev_channel].app = PulseTrainGeneration; @@ -735,7 +755,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, break; default: - printk("s526: unsupported GPCT_insn_config\n"); + printk(KERN_ERR "s526: unsupported GPCT_insn_config\n"); return -EINVAL; break; } @@ -751,20 +771,21 @@ static int s526_gpct_winsn(struct comedi_device *dev, short value; union cmReg cmReg; - printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel); + printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n", + subdev_channel); cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); - printk("s526: Counter Mode Register: %x\n", cmReg.value); + printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value); /* Check what Application of Counter this channel is configured for */ switch (devpriv->s526_gpct_config[subdev_channel].app) { case PositionMeasurement: - printk("S526: INSN_WRITE: PM\n"); + printk(KERN_INFO "S526: INSN_WRITE: PM\n"); outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, subdev_channel)); outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); break; case SinglePulseGeneration: - printk("S526: INSN_WRITE: SPG\n"); + printk(KERN_INFO "S526: INSN_WRITE: SPG\n"); outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, subdev_channel)); outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); @@ -777,14 +798,14 @@ static int s526_gpct_winsn(struct comedi_device *dev, The above periods must be expressed as a multiple of the pulse frequency on the selected source */ - printk("S526: INSN_WRITE: PTG\n"); + printk(KERN_INFO "S526: INSN_WRITE: PTG\n"); if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) { (devpriv->s526_gpct_config[subdev_channel]).data[0] = insn->data[0]; (devpriv->s526_gpct_config[subdev_channel]).data[1] = insn->data[1]; } else { - printk("s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n", + printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n", insn->data[0], insn->data[1]); return -EINVAL; } @@ -873,7 +894,7 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, if (i == TIMEOUT) { /* printk() should be used instead of printk() * whenever the code can be called from real-time. */ - printk("s526: ADC(0x%04x) timeout\n", + printk(KERN_ERR "s526: ADC(0x%04x) timeout\n", inw(ADDR_REG(REG_ISR))); return -ETIMEDOUT; } @@ -906,11 +927,14 @@ static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; i++) { /* a typical programming sequence */ -/* outw(data[i], dev->iobase + REG_ADD); write the data to preload register */ - outw(data[i], ADDR_REG(REG_ADD)); /* write the data to preload register */ + /* write the data to preload register + * outw(data[i], dev->iobase + REG_ADD); + */ + /* write the data to preload register */ + outw(data[i], ADDR_REG(REG_ADD)); devpriv->ao_readback[chan] = data[i]; /* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ - outw(val + 1, ADDR_REG(REG_DAC)); /* starts the D/A conversion. */ + outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/ } /* return the number of samples read/written */ @@ -954,7 +978,7 @@ static int s526_dio_insn_bits(struct comedi_device *dev, /* on return, data[1] contains the value of the digital * input and output lines. */ - data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ + data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ /* or we could just return the software copy of the output values if * it was a purely digital output subdevice */ /* data[1]=s->state & 0xFF; */ @@ -969,7 +993,7 @@ static int s526_dio_insn_config(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int group, mask; - printk("S526 DIO insn_config\n"); + printk(KERN_INFO "S526 DIO insn_config\n"); /* The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec @@ -980,11 +1004,12 @@ static int s526_dio_insn_config(struct comedi_device *dev, mask = 0xF << (group << 2); switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: - s->state |= 1 << (group + 10); // bit 10/11 set the group 1/2's mode + /* bit 10/11 set the group 1/2's mode */ + s->state |= 1 << (group + 10); s->io_bits |= mask; break; case INSN_CONFIG_DIO_INPUT: - s->state &= ~(1 << (group + 10));// 1 is output, 0 is input. + s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */ s->io_bits &= ~mask; break; case INSN_CONFIG_DIO_QUERY: -- cgit v1.2.3 From ee417a79567030ce726e9627aa52779e47c49ff0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:56:57 -0800 Subject: staging: brcm80211: Remove unused #defines ETHER__LOCALADDR Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/proto/ethernet.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index cc17b428dd3f..a8981f610347 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -62,13 +62,6 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { u8 octet[ETHER_ADDR_LEN]; } BWL_POST_PACKED_STRUCT; -#define ETHER_SET_LOCALADDR(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] | 2)) -#define ETHER_IS_LOCALADDR(ea) (((u8 *)(ea))[0] & 2) -#define ETHER_CLR_LOCALADDR(ea) (((u8 *)(ea))[0] = \ - (((u8 *)(ea))[0] & 0xd)) -#define ETHER_TOGGLE_LOCALADDR(ea) (((u8 *)(ea))[0] = \ - (((u8 *)(ea))[0] ^ 2)) - #define ETHER_SET_UNICAST(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] & ~1)) #define ETHER_ISMULTI(ea) (((const u8 *)(ea))[0] & 1) -- cgit v1.2.3 From 3ca5ada504a41d9a8afd1e25f85f11d1761efa5f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:56:58 -0800 Subject: staging: brcm80211: Convert ETHER_IS_MULTI to is_multicast_ether_addr Use the standard kernel function. Change callers to add .octet to addressing to avoid warnings. Add #include where necessary. Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 2 +- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 2 +- drivers/staging/brcm80211/include/proto/ethernet.h | 2 -- drivers/staging/brcm80211/sys/wlc_mac80211.c | 16 ++++++++++------ drivers/staging/brcm80211/util/bcmsrom.c | 11 ++++++----- 6 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index a114deed3134..b37539cd2902 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1032,7 +1032,7 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf) u8 *pktdata = (u8 *) (pktbuf->data); struct ether_header *eh = (struct ether_header *)pktdata; - if (ETHER_ISMULTI(eh->ether_dhost)) + if (is_multicast_ether_addr(eh->ether_dhost)) dhdp->tx_multicast++; if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) atomic_inc(&dhd->pend_8021x_cnt); diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index edf300d4ae70..59f7ca53364b 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -1532,7 +1532,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, key.index = (u32) key_idx; /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */ - if (!ETHER_ISMULTI(mac_addr)) + if (!is_multicast_ether_addr(mac_addr)) memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); key.len = (u32) params->key_len; /* check for key index change */ diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index d8600bfc304e..2e0eab121e97 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -2548,7 +2548,7 @@ wl_iw_set_encodeext(struct net_device *dev, key.len = iwe->key_len; - if (!ETHER_ISMULTI(iwe->addr.sa_data)) + if (!is_multicast_ether_addr(iwe->addr.sa_data)) bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index a8981f610347..a2353a50874e 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -64,8 +64,6 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { #define ETHER_SET_UNICAST(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] & ~1)) -#define ETHER_ISMULTI(ea) (((const u8 *)(ea))[0] & 1) - #define ether_cmp(a, b) (!(((short *)a)[0] == ((short *)b)[0]) | \ !(((short *)a)[1] == ((short *)b)[1]) | \ !(((short *)a)[2] == ((short *)b)[2])) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index e4a4365f4bf7..24bf64d66227 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -15,6 +15,7 @@ */ #include #include +#include #include #include #include @@ -5802,7 +5803,8 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, ASSERT(RSPEC_ACTIVE(rspec[k])); rspec[k] = WLC_RATE_1M; } else { - if (WLANTSEL_ENAB(wlc) && !ETHER_ISMULTI(&h->a1)) { + if (WLANTSEL_ENAB(wlc) && + !is_multicast_ether_addr(h->a1.octet)) { /* set tx antenna config */ wlc_antsel_antcfg_get(wlc->asi, false, false, 0, 0, &antcfg, &fbantcfg); @@ -5963,7 +5965,8 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, plcp[0]; /* DUR field for main rate */ - if ((fc != FC_PS_POLL) && !ETHER_ISMULTI(&h->a1) && !use_rifs) { + if ((fc != FC_PS_POLL) && + !is_multicast_ether_addr(h->a1.octet) && !use_rifs) { durid = wlc_compute_frame_dur(wlc, rspec[0], preamble_type[0], next_frag_len); @@ -5981,7 +5984,7 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, /* DUR field for fallback rate */ if (fc == FC_PS_POLL) txh->FragDurFallback = h->durid; - else if (ETHER_ISMULTI(&h->a1) || use_rifs) + else if (is_multicast_ether_addr(h->a1.octet) || use_rifs) txh->FragDurFallback = 0; else { durid = wlc_compute_frame_dur(wlc, rspec[1], @@ -5993,7 +5996,7 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, if (frag == 0) mcl |= TXC_STARTMSDU; - if (!ETHER_ISMULTI(&h->a1)) + if (!is_multicast_ether_addr(h->a1.octet)) mcl |= TXC_IMMEDACK; if (BAND_5G(wlc->band->bandtype)) @@ -6222,7 +6225,7 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) { uint frag_dur, dur, dur_fallback; - ASSERT(!ETHER_ISMULTI(&h->a1)); + ASSERT(!is_multicast_ether_addr(h->a1.octet)); /* WME: Update TXOP threshold */ if ((!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) && (frag == 0)) { @@ -7023,7 +7026,8 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) if (!is_amsdu) { /* CTS and ACK CTL frames are w/o a2 */ if (FC_TYPE(fc) == FC_TYPE_DATA || FC_TYPE(fc) == FC_TYPE_MNG) { - if ((ETHER_ISNULLADDR(&h->a2) || ETHER_ISMULTI(&h->a2))) { + if ((ETHER_ISNULLADDR(&h->a2) || + is_multicast_ether_addr(h->a2.octet))) { WL_ERROR(("wl%d: %s: dropping a frame with " "invalid src mac address, a2: %pM\n", wlc->pub->unit, __func__, &h->a2)); diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 3a0beb93c0b6..8393d58bab57 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -15,6 +15,7 @@ */ #include #include +#include #include #include #include @@ -499,10 +500,10 @@ int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, break; default: /* set macaddr if HNBU_MACADDR not seen yet */ - if (eabuf[0] == '\0' - && cis[i] == LAN_NID - && !(ETHER_ISNULLADDR(&cis[i + 2])) - && !(ETHER_ISMULTI(&cis[i + 2]))) { + if (eabuf[0] == '\0' && + cis[i] == LAN_NID && + !(ETHER_ISNULLADDR(&cis[i + 2])) && + !is_multicast_ether_addr(&cis[i + 2])) { ASSERT(cis[i + 1] == ETHER_ADDR_LEN); snprintf(eabuf, sizeof(eabuf), @@ -974,7 +975,7 @@ int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, case HNBU_MACADDR: if (!(ETHER_ISNULLADDR(&cis[i + 1])) && - !(ETHER_ISMULTI(&cis[i + 1]))) { + !is_multicast_ether_addr(&cis[i + 1])) { snprintf(eabuf, sizeof(eabuf), "%pM", &cis[i + 1]); -- cgit v1.2.3 From 47c6de7d37619d105de0367aece9ab10288225bc Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:56:59 -0800 Subject: staging: brcm80211: Remove unused ether_ #defines and struct These are unused, just remove them. Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/proto/ethernet.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index a2353a50874e..1b352c5e29b8 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -64,17 +64,7 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { #define ETHER_SET_UNICAST(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] & ~1)) -#define ether_cmp(a, b) (!(((short *)a)[0] == ((short *)b)[0]) | \ - !(((short *)a)[1] == ((short *)b)[1]) | \ - !(((short *)a)[2] == ((short *)b)[2])) - -#define ether_copy(s, d) { \ - ((short *)d)[0] = ((short *)s)[0]; \ - ((short *)d)[1] = ((short *)s)[1]; \ - ((short *)d)[2] = ((short *)s)[2]; } - static const struct ether_addr ether_bcast = { {255, 255, 255, 255, 255, 255} }; -static const struct ether_addr ether_null = { {0, 0, 0, 0, 0, 0} }; #define ETHER_ISBCAST(ea) ((((u8 *)(ea))[0] & \ ((u8 *)(ea))[1] & \ -- cgit v1.2.3 From ed9568687e82c56017ca1aacf6eda9902939bf4a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:57:00 -0800 Subject: staging: brcm80211: Convert ETHER_IS to is__ether_addr Use the normal kernel calls and remove the #defines for ETHER_IS_BCAST and ETHER_IS_NULLADDR. Add #include for etherdevice.h where necessary. Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 3 ++- drivers/staging/brcm80211/include/proto/ethernet.h | 13 ------------- drivers/staging/brcm80211/sys/wlc_bmac.c | 5 +++-- drivers/staging/brcm80211/sys/wlc_mac80211.c | 6 +++--- drivers/staging/brcm80211/util/bcmsrom.c | 4 ++-- 5 files changed, 10 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index 2e0eab121e97..abf5d743b373 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -772,7 +772,8 @@ wl_iw_set_wap(struct net_device *dev, return -EINVAL; } - if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { + if (is_broadcast_ether_addr(awrq->sa_data) || + is_zero_ether_addr(awrq->sa_data)) { scb_val_t scbval; memset(&scbval, 0, sizeof(scb_val_t)); (void)dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index 1b352c5e29b8..086b9b962125 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -66,19 +66,6 @@ BWL_PRE_PACKED_STRUCT struct ether_addr { static const struct ether_addr ether_bcast = { {255, 255, 255, 255, 255, 255} }; -#define ETHER_ISBCAST(ea) ((((u8 *)(ea))[0] & \ - ((u8 *)(ea))[1] & \ - ((u8 *)(ea))[2] & \ - ((u8 *)(ea))[3] & \ - ((u8 *)(ea))[4] & \ - ((u8 *)(ea))[5]) == 0xff) -#define ETHER_ISNULLADDR(ea) ((((u8 *)(ea))[0] | \ - ((u8 *)(ea))[1] | \ - ((u8 *)(ea))[2] | \ - ((u8 *)(ea))[3] | \ - ((u8 *)(ea))[4] | \ - ((u8 *)(ea))[5]) == 0) - #define ETHER_MOVE_HDR(d, s) \ do { \ struct ether_header t; \ diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index dff4f6bf77e2..2baacfd3ba91 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1022,8 +1023,8 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, goto fail; } bcm_ether_atoe(macaddr, &wlc_hw->etheraddr); - if (ETHER_ISBCAST((char *)&wlc_hw->etheraddr) || - ETHER_ISNULLADDR((char *)&wlc_hw->etheraddr)) { + if (is_broadcast_ether_addr(wlc_hw->etheraddr.octet) || + is_zero_ether_addr(wlc_hw->etheraddr.octet)) { WL_ERROR(("wl%d: wlc_bmac_attach: bad macaddr %s\n", unit, macaddr)); err = 22; diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 24bf64d66227..daa67c9641a8 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -3633,8 +3633,8 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, u16 lo; u32 hi; /* group keys in WPA-NONE (IBSS only, AES and TKIP) use a global TXIV */ - if ((bsscfg->WPA_auth & WPA_AUTH_NONE) - && ETHER_ISNULLADDR(&key->ea)) { + if ((bsscfg->WPA_auth & WPA_AUTH_NONE) && + is_zero_ether_addr(key->ea.octet)) { lo = bsscfg->wpa_none_txiv.lo; hi = bsscfg->wpa_none_txiv.hi; } else { @@ -7026,7 +7026,7 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) if (!is_amsdu) { /* CTS and ACK CTL frames are w/o a2 */ if (FC_TYPE(fc) == FC_TYPE_DATA || FC_TYPE(fc) == FC_TYPE_MNG) { - if ((ETHER_ISNULLADDR(&h->a2) || + if ((is_zero_ether_addr(h->a2.octet) || is_multicast_ether_addr(h->a2.octet))) { WL_ERROR(("wl%d: %s: dropping a frame with " "invalid src mac address, a2: %pM\n", diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 8393d58bab57..668dac6d4415 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -502,7 +502,7 @@ int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, /* set macaddr if HNBU_MACADDR not seen yet */ if (eabuf[0] == '\0' && cis[i] == LAN_NID && - !(ETHER_ISNULLADDR(&cis[i + 2])) && + !is_zero_ether_addr(&cis[i + 2]) && !is_multicast_ether_addr(&cis[i + 2])) { ASSERT(cis[i + 1] == ETHER_ADDR_LEN); @@ -974,7 +974,7 @@ int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, break; case HNBU_MACADDR: - if (!(ETHER_ISNULLADDR(&cis[i + 1])) && + if (!is_zero_ether_addr(&cis[i + 1]) && !is_multicast_ether_addr(&cis[i + 1])) { snprintf(eabuf, sizeof(eabuf), "%pM", &cis[i + 1]); -- cgit v1.2.3 From b8d6307894a73a10be6395b8ed3ffb3cb9255f9d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:57:01 -0800 Subject: staging: brcm80211: Convert ETHER_ADDR_LEN to ETH_ALEN Add an #include of to include/proto/ethernet.h Convert ETHER_ADDR_LEN, remove the #define for ETHER_ADDR_LEN. Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_cdc.c | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_common.c | 8 +-- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 26 +++++----- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 36 +++++++------- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h | 2 +- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 58 +++++++++++----------- drivers/staging/brcm80211/include/proto/ethernet.h | 17 ++++--- drivers/staging/brcm80211/sys/wl_mac80211.c | 2 +- drivers/staging/brcm80211/sys/wlc_ampdu.c | 2 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 4 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 18 +++---- drivers/staging/brcm80211/util/bcmsrom.c | 2 +- 12 files changed, 89 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c index b3fc2a3eb957..b7b527f5024c 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c @@ -477,7 +477,7 @@ int dhd_prot_init(dhd_pub_t *dhd) dhd_os_proto_unblock(dhd); return ret; } - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); + memcpy(dhd->mac.octet, buf, ETH_ALEN); dhd_os_proto_unblock(dhd); diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c index 324d020b864e..3dbf72eebd4a 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c @@ -1256,7 +1256,7 @@ int dhd_preinit_ioctls(dhd_pub_t *dhd) */ ret = dhd_custom_get_mac_address(ea_addr.octet); if (!ret) { - bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, + bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETH_ALEN, buf, sizeof(buf)); ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf)); if (ret < 0) { @@ -1264,7 +1264,7 @@ int dhd_preinit_ioctls(dhd_pub_t *dhd) __func__, ret)); } else memcpy(dhd->mac.octet, (void *)&ea_addr, - ETHER_ADDR_LEN); + ETH_ALEN); } #endif /* GET_CUSTOM_MAC_ENABLE */ @@ -1534,7 +1534,7 @@ int dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip) break; if (!memcmp - (bi->BSSID.octet, addr, ETHER_ADDR_LEN)) { + (bi->BSSID.octet, addr, ETH_ALEN)) { DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] " "%X:%X:%X:%X:%X:%X\n", __func__, l, i, bi->BSSID.octet[0], @@ -1672,7 +1672,7 @@ int dhd_iscan_request(void *dhdp, u16 action) char buf[WLC_IOCTL_SMLEN]; memset(¶ms, 0, sizeof(wl_iscan_params_t)); - memcpy(¶ms.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + memcpy(¶ms.params.bssid, ðer_bcast, ETH_ALEN); params.params.bss_type = DOT11_BSSTYPE_ANY; params.params.scan_type = DOT11_SCANTYPE_ACTIVE; diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index b37539cd2902..ec6202b117f9 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -210,7 +210,7 @@ typedef struct dhd_if { int idx; /* iface idx in dongle */ int state; /* interface state */ uint subunit; /* subunit */ - u8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ + u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ bool attached; /* Delayed attachment when unset */ bool txflowcontrol; /* Per interface flow control indicator */ char name[IFNAMSIZ]; /* linux interface name */ @@ -708,7 +708,7 @@ static void _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) /* Send down the multicast list first. */ - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); + buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN); bufp = buf = kmalloc(buflen, GFP_ATOMIC); if (!bufp) { DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", @@ -726,8 +726,8 @@ static void _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) netdev_for_each_mc_addr(ha, dev) { if (!cnt) break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; + memcpy(bufp, ha->addr, ETH_ALEN); + bufp += ETH_ALEN; cnt--; } @@ -811,7 +811,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) DHD_TRACE(("%s enter\n", __func__)); if (!bcm_mkiovar - ("cur_etheraddr", (char *)addr, ETHER_ADDR_LEN, buf, 32)) { + ("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) { DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx))); return -1; @@ -827,7 +827,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); } else { - memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); + memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN); } return ret; @@ -997,7 +997,7 @@ static int dhd_set_mac_address(struct net_device *dev, void *addr) return -1; ASSERT(dhd->sysioc_tsk); - memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); + memcpy(&dhd->macvalue, sa->sa_data, ETH_ALEN); dhd->set_macaddress = true; up(&dhd->sysioc_sem); @@ -1028,7 +1028,7 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf) return -ENODEV; /* Update multicast statistic */ - if (pktbuf->len >= ETHER_ADDR_LEN) { + if (pktbuf->len >= ETH_ALEN) { u8 *pktdata = (u8 *) (pktbuf->data); struct ether_header *eh = (struct ether_header *)pktdata; @@ -1866,7 +1866,7 @@ static int dhd_open(struct net_device *net) } atomic_set(&dhd->pend_8021x_cnt, 0); - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + memcpy(net->dev_addr, dhd->pub.mac.octet, ETH_ALEN); #ifdef TOE /* Get current TOE mode from dongle */ @@ -1922,7 +1922,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, dhd->iflist[ifidx] = ifp; strlcpy(ifp->name, name, IFNAMSIZ); if (mac_addr != NULL) - memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); + memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); if (handle == NULL) { ifp->state = WLC_E_IF_ADD; @@ -2281,7 +2281,7 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) { dhd_info_t *dhd = (dhd_info_t *) dhdp->info; struct net_device *net; - u8 temp_addr[ETHER_ADDR_LEN] = { + u8 temp_addr[ETH_ALEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33}; DHD_TRACE(("%s: ifidx %d\n", __func__, ifidx)); @@ -2299,7 +2299,7 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) */ if (ifidx != 0) { /* for virtual interfaces use the primary MAC */ - memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + memcpy(temp_addr, dhd->pub.mac.octet, ETH_ALEN); } @@ -2327,7 +2327,7 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx) dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen; - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + memcpy(net->dev_addr, temp_addr, ETH_ALEN); if (register_netdev(net) != 0) { DHD_ERROR(("%s: couldn't register the net device\n", diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index 59f7ca53364b..1e92f2e230fe 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -648,7 +648,7 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid) { - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + memcpy(¶ms->bssid, ðer_bcast, ETH_ALEN); params->bss_type = DOT11_BSSTYPE_ANY; params->scan_type = 0; params->nprobes = -1; @@ -1044,9 +1044,9 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, join_params.ssid.SSID_len = htod32(params->ssid_len); if (params->bssid) memcpy(&join_params.params.bssid, params->bssid, - ETHER_ADDR_LEN); + ETH_ALEN); else - memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); + memset(&join_params.params.bssid, 0, ETH_ALEN); err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params)); @@ -1373,7 +1373,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID); - memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); WL_DBG(("join_param_size %d\n", join_params_size)); @@ -1406,7 +1406,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, act = *(bool *) wl_read_prof(wl, WL_PROF_ACT); if (likely(act)) { scbval.val = reason_code; - memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN); + memcpy(&scbval.ea, &wl->bssid, ETH_ALEN); scbval.val = htod32(scbval.val); err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); @@ -1533,7 +1533,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */ if (!is_multicast_ether_addr(mac_addr)) - memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); + memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); key.len = (u32) params->key_len; /* check for key index change */ if (key.len == 0) { @@ -1826,7 +1826,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); if (unlikely - (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) { + (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETH_ALEN))) { WL_ERR(("Wrong Mac address\n")); return -ENOENT; } @@ -2029,11 +2029,11 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN)) + ETH_ALEN)) break; if (i < WL_NUM_PMKIDS_MAX) { memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, - ETHER_ADDR_LEN); + ETH_ALEN); memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); if (i == wl->pmk_list->pmkids.npmkid) @@ -2064,7 +2064,7 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, int i; CHECK_SYS_UP(); - memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); + memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", @@ -2076,7 +2076,7 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) if (!memcmp (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN)) + ETH_ALEN)) break; if ((wl->pmk_list->pmkids.npmkid > 0) @@ -2085,7 +2085,7 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) { memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, &wl->pmk_list->pmkids.pmkid[i + 1].BSSID, - ETHER_ADDR_LEN); + ETH_ALEN); memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, &wl->pmk_list->pmkids.pmkid[i + 1].PMKID, WPA2_PMKID_LEN); @@ -2284,7 +2284,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) else band = wiphy->bands[IEEE80211_BAND_5GHZ]; notif_bss_info->rssi = bi->RSSI; - memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(mgmt->bssid, &bi->BSSID, ETH_ALEN); mgmt_type = wl->active_scan ? IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { @@ -2579,7 +2579,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl) goto update_bss_info_out; } bi = (struct wl_bss_info *)(wl->extra_buf + 4); - if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETHER_ADDR_LEN))) { + if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETH_ALEN))) { err = -EIO; goto update_bss_info_out; } @@ -2631,7 +2631,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, s32 err = 0; wl_get_assoc_ies(wl); - memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + memcpy(&wl->bssid, &e->addr, ETH_ALEN); wl_update_bss_info(wl); cfg80211_roamed(ndev, (u8 *)&wl->bssid, @@ -2652,7 +2652,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, s32 err = 0; wl_get_assoc_ies(wl); - memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + memcpy(&wl->bssid, &e->addr, ETH_ALEN); wl_update_bss_info(wl); if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) { cfg80211_connect_result(ndev, @@ -3926,9 +3926,9 @@ wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, break; case WL_PROF_BSSID: if (data) - memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN); + memcpy(wl->profile->bssid, data, ETH_ALEN); else - memset(wl->profile->bssid, 0, ETHER_ADDR_LEN); + memset(wl->profile->bssid, 0, ETH_ALEN); break; case WL_PROF_SEC: memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec)); diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h index 770e63f0c8ef..1069e65f8ce6 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h @@ -237,7 +237,7 @@ struct wl_ibss { struct wl_profile { u32 mode; struct wlc_ssid ssid; - u8 bssid[ETHER_ADDR_LEN]; + u8 bssid[ETH_ALEN]; u16 beacon_interval; u8 dtim_period; struct wl_security sec; diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index abf5d743b373..14580b2ea198 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -347,7 +347,7 @@ wl_iw_config_commit(struct net_device *dev, return 0; memset(&bssid, 0, sizeof(struct sockaddr)); - error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN); + error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN); if (error) { WL_ERROR(("%s: WLC_REASSOC to %s failed\n", __func__, ssid.SSID)); @@ -691,7 +691,7 @@ wl_iw_set_spy(struct net_device *dev, iw->spy_num = min_t(int, ARRAY_SIZE(iw->spy_addr), dwrq->length); for (i = 0; i < iw->spy_num; i++) - memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); + memcpy(&iw->spy_addr[i], addr[i].sa_data, ETH_ALEN); memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); return 0; @@ -713,7 +713,7 @@ wl_iw_get_spy(struct net_device *dev, dwrq->length = iw->spy_num; for (i = 0; i < iw->spy_num; i++) { - memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); + memcpy(addr[i].sa_data, &iw->spy_addr[i], ETH_ALEN); addr[i].sa_family = AF_UNIX; memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); iw->spy_qual[i].updated = 0; @@ -786,7 +786,7 @@ wl_iw_set_wap(struct net_device *dev, memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); - memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN); + memcpy(&join_params.params.bssid, awrq->sa_data, ETH_ALEN); WL_TRACE(("%s target_channel=%d\n", __func__, g_wl_iw_params.target_channel)); @@ -816,9 +816,9 @@ wl_iw_get_wap(struct net_device *dev, WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); awrq->sa_family = ARPHRD_ETHER; - memset(awrq->sa_data, 0, ETHER_ADDR_LEN); + memset(awrq->sa_data, 0, ETH_ALEN); - (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); + (void)dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETH_ALEN); return 0; } @@ -841,7 +841,7 @@ wl_iw_mlme(struct net_device *dev, } scbval.val = mlme->reason_code; - bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); + bcopy(&mlme->addr.sa_data, &scbval.ea, ETH_ALEN); if (mlme->cmd == IW_MLME_DISASSOC) { scbval.val = htod32(scbval.val); @@ -912,7 +912,7 @@ wl_iw_get_aplist(struct net_device *dev, if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) continue; - memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETH_ALEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); @@ -986,7 +986,7 @@ wl_iw_iscan_get_aplist(struct net_device *dev, continue; memcpy(addr[dwrq->length].sa_data, &bi->BSSID, - ETHER_ADDR_LEN); + ETH_ALEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); @@ -1017,7 +1017,7 @@ static int wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) { int err = 0; - memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); + memcpy(¶ms->bssid, ðer_bcast, ETH_ALEN); params->bss_type = DOT11_BSSTYPE_ANY; params->scan_type = 0; params->nprobes = -1; @@ -1516,7 +1516,7 @@ wl_iw_get_scan_prep(wl_scan_results_t *list, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETH_ALEN); event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); @@ -1780,14 +1780,14 @@ wl_iw_iscan_get_scan(struct net_device *dev, ASSERT(((unsigned long)bi + dtoh32(bi->length)) <= ((unsigned long)list + WLC_IW_ISCAN_MAXLEN)); - if (event + ETHER_ADDR_LEN + bi->SSID_len + + if (event + ETH_ALEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end) return -E2BIG; iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, - ETHER_ADDR_LEN); + ETH_ALEN); event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); @@ -1924,7 +1924,7 @@ wl_iw_set_essid(struct net_device *dev, memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len); join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); - memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); @@ -2551,7 +2551,7 @@ wl_iw_set_encodeext(struct net_device *dev, if (!is_multicast_ether_addr(iwe->addr.sa_data)) bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, - ETHER_ADDR_LEN); + ETH_ALEN); if (key.len == 0) { if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { @@ -2657,7 +2657,7 @@ wl_iw_set_pmksa(struct net_device *dev, pmkidptr = &pmkid; bcopy(&iwpmksa->bssid.sa_data[0], - &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); + &pmkidptr->pmkid[0].BSSID, ETH_ALEN); bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); @@ -2671,7 +2671,7 @@ wl_iw_set_pmksa(struct net_device *dev, for (i = 0; i < pmkid_list.pmkids.npmkid; i++) if (!memcmp (&iwpmksa->bssid.sa_data[0], - &pmkid_list.pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) + &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN)) break; if ((pmkid_list.pmkids.npmkid > 0) @@ -2680,7 +2680,7 @@ wl_iw_set_pmksa(struct net_device *dev, for (; i < (pmkid_list.pmkids.npmkid - 1); i++) { bcopy(&pmkid_list.pmkids.pmkid[i + 1].BSSID, &pmkid_list.pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN); + ETH_ALEN); bcopy(&pmkid_list.pmkids.pmkid[i + 1].PMKID, &pmkid_list.pmkids.pmkid[i].PMKID, WPA2_PMKID_LEN); @@ -2694,12 +2694,12 @@ wl_iw_set_pmksa(struct net_device *dev, for (i = 0; i < pmkid_list.pmkids.npmkid; i++) if (!memcmp (&iwpmksa->bssid.sa_data[0], - &pmkid_list.pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) + &pmkid_list.pmkids.pmkid[i].BSSID, ETH_ALEN)) break; if (i < MAXPMKID) { bcopy(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID, - ETHER_ADDR_LEN); + ETH_ALEN); bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID, WPA2_PMKID_LEN); @@ -3395,34 +3395,34 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) switch (event_type) { case WLC_E_TXFAIL: cmd = IWEVTXDROP; - memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); + memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN); wrqu.addr.sa_family = ARPHRD_ETHER; break; #if WIRELESS_EXT > 14 case WLC_E_JOIN: case WLC_E_ASSOC_IND: case WLC_E_REASSOC_IND: - memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); + memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN); wrqu.addr.sa_family = ARPHRD_ETHER; cmd = IWEVREGISTERED; break; case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: cmd = SIOCGIWAP; - memset(wrqu.addr.sa_data, 0, ETHER_ADDR_LEN); + memset(wrqu.addr.sa_data, 0, ETH_ALEN); wrqu.addr.sa_family = ARPHRD_ETHER; - memset(&extra, 0, ETHER_ADDR_LEN); + memset(&extra, 0, ETH_ALEN); break; case WLC_E_LINK: case WLC_E_NDIS_LINK: cmd = SIOCGIWAP; if (!(flags & WLC_EVENT_MSG_LINK)) { - memset(wrqu.addr.sa_data, 0, ETHER_ADDR_LEN); - memset(&extra, 0, ETHER_ADDR_LEN); + memset(wrqu.addr.sa_data, 0, ETH_ALEN); + memset(&extra, 0, ETH_ALEN); WAKE_LOCK_TIMEOUT(iw->pub, WAKE_LOCK_LINK_DOWN_TMOUT, 20 * HZ); } else { - memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); + memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN); WL_TRACE(("Link UP\n")); } @@ -3465,7 +3465,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) else micerrevt->flags |= IW_MICFAILURE_PAIRWISE; memcpy(micerrevt->src_addr.sa_data, &e->addr, - ETHER_ADDR_LEN); + ETH_ALEN); micerrevt->src_addr.sa_family = ARPHRD_ETHER; break; @@ -3495,7 +3495,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) IW_PMKID_CAND_PREAUTH; bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, - ETHER_ADDR_LEN); + ETH_ALEN); #ifndef SANDGATE2G wireless_send_event(dev, cmd, &wrqu, extra); diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index 086b9b962125..a8638db431db 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -17,12 +17,13 @@ #ifndef _NET_ETHERNET_H_ #define _NET_ETHERNET_H_ +#include + #include -#define ETHER_ADDR_LEN 6 #define ETHER_TYPE_LEN 2 #define ETHER_CRC_LEN 4 -#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) +#define ETHER_HDR_LEN (ETH_ALEN * 2 + ETHER_TYPE_LEN) #define ETHER_MIN_LEN 64 #define ETHER_MIN_DATA 46 #define ETHER_MAX_LEN 1518 @@ -36,9 +37,9 @@ #define ETHER_TYPE_802_1X 0x888e #define ETHER_TYPE_802_1X_PREAUTH 0x88c7 -#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) -#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) -#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) +#define ETHER_DEST_OFFSET (0 * ETH_ALEN) +#define ETHER_SRC_OFFSET (1 * ETH_ALEN) +#define ETHER_TYPE_OFFSET (2 * ETH_ALEN) #define ETHER_IS_VALID_LEN(foo) \ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) @@ -53,13 +54,13 @@ } BWL_PRE_PACKED_STRUCT struct ether_header { - u8 ether_dhost[ETHER_ADDR_LEN]; - u8 ether_shost[ETHER_ADDR_LEN]; + u8 ether_dhost[ETH_ALEN]; + u8 ether_shost[ETH_ALEN]; u16 ether_type; } BWL_POST_PACKED_STRUCT; BWL_PRE_PACKED_STRUCT struct ether_addr { - u8 octet[ETHER_ADDR_LEN]; + u8 octet[ETH_ALEN]; } BWL_POST_PACKED_STRUCT; #define ETHER_SET_UNICAST(ea) (((u8 *)(ea))[0] = (((u8 *)(ea))[0] & ~1)) diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 1e7a29d006be..4ae99749ac70 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -749,7 +749,7 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, goto fail; } - bcopy(&wl->pub->cur_etheraddr, perm, ETHER_ADDR_LEN); + bcopy(&wl->pub->cur_etheraddr, perm, ETH_ALEN); ASSERT(is_valid_ether_addr(perm)); SET_IEEE80211_PERM_ADDR(hw, perm); diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index c0883d01c51b..0419c528e40e 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -1318,7 +1318,7 @@ void wlc_ampdu_macaddr_upd(struct wlc_info *wlc) /* driver needs to write the ta in the template; ta is at offset 16 */ memset(template, 0, sizeof(template)); - bcopy((char *)wlc->pub->cur_etheraddr.octet, template, ETHER_ADDR_LEN); + bcopy((char *)wlc->pub->cur_etheraddr.octet, template, ETH_ALEN); wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2), template); } diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 2baacfd3ba91..0c2625dc440b 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -1340,13 +1340,13 @@ void wlc_bmac_wait_for_wake(struct wlc_hw_info *wlc_hw) void wlc_bmac_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea) { - bcopy(&wlc_hw->etheraddr, ea, ETHER_ADDR_LEN); + bcopy(&wlc_hw->etheraddr, ea, ETH_ALEN); } void wlc_bmac_set_hw_etheraddr(struct wlc_hw_info *wlc_hw, struct ether_addr *ea) { - bcopy(ea, &wlc_hw->etheraddr, ETHER_ADDR_LEN); + bcopy(ea, &wlc_hw->etheraddr, ETH_ALEN); } int wlc_bmac_bandtype(struct wlc_hw_info *wlc_hw) diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index daa67c9641a8..407f5ec55230 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -1726,7 +1726,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, ASSERT(WSEC_MAX_DEFAULT_KEYS == WLC_DEFAULT_KEYS); /* some code depends on packed structures */ - ASSERT(sizeof(struct ether_addr) == ETHER_ADDR_LEN); + ASSERT(sizeof(struct ether_addr) == ETH_ALEN); ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN); ASSERT(sizeof(d11regs_t) == SI_CORE_SIZE); ASSERT(sizeof(ofdm_phy_hdr_t) == D11_PHY_HDR_LEN); @@ -1839,7 +1839,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, wlc_bmac_hw_etheraddr(wlc->hw, &wlc->perm_etheraddr); bcopy((char *)&wlc->perm_etheraddr, (char *)&pub->cur_etheraddr, - ETHER_ADDR_LEN); + ETH_ALEN); for (j = 0; j < NBANDS(wlc); j++) { /* Use band 1 for single band 11a */ @@ -3598,7 +3598,7 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, key.flags |= WL_PRIMARY_KEY; bcopy(src_key->ea.octet, key.ea.octet, - ETHER_ADDR_LEN); + ETH_ALEN); } bcopy((char *)&key, arg, sizeof(key)); @@ -6031,7 +6031,7 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, txh->TxFesTimeFallback = htol16(0); /* TxFrameRA */ - bcopy((char *)&h->a1, (char *)&txh->TxFrameRA, ETHER_ADDR_LEN); + bcopy((char *)&h->a1, (char *)&txh->TxFrameRA, ETH_ALEN); /* TxFrameID */ txh->TxFrameID = htol16(frameid); @@ -6118,11 +6118,11 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, if (use_cts) { rts->fc = htol16(FC_CTS); - bcopy((char *)&h->a2, (char *)&rts->ra, ETHER_ADDR_LEN); + bcopy((char *)&h->a2, (char *)&rts->ra, ETH_ALEN); } else { rts->fc = htol16((u16) FC_RTS); bcopy((char *)&h->a1, (char *)&rts->ra, - 2 * ETHER_ADDR_LEN); + 2 * ETH_ALEN); } /* mainrate @@ -7639,9 +7639,9 @@ wlc_bcn_prb_template(struct wlc_info *wlc, uint type, ratespec_t bcn_rspec, /* A1 filled in by MAC for prb resp, broadcast for bcn */ if (type == FC_BEACON) bcopy((const char *)ðer_bcast, (char *)&h->da, - ETHER_ADDR_LEN); - bcopy((char *)&cfg->cur_etheraddr, (char *)&h->sa, ETHER_ADDR_LEN); - bcopy((char *)&cfg->BSSID, (char *)&h->bssid, ETHER_ADDR_LEN); + ETH_ALEN); + bcopy((char *)&cfg->cur_etheraddr, (char *)&h->sa, ETH_ALEN); + bcopy((char *)&cfg->BSSID, (char *)&h->bssid, ETH_ALEN); /* SEQ filled in by MAC */ diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index 668dac6d4415..19d45026a5ee 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -505,7 +505,7 @@ int srom_parsecis(struct osl_info *osh, u8 *pcis[], uint ciscnt, char **vars, !is_zero_ether_addr(&cis[i + 2]) && !is_multicast_ether_addr(&cis[i + 2])) { ASSERT(cis[i + 1] == - ETHER_ADDR_LEN); + ETH_ALEN); snprintf(eabuf, sizeof(eabuf), "%pM", &cis[i + 2]); -- cgit v1.2.3 From d659a3ec838866482779f594c4520f553468c492 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:57:02 -0800 Subject: staging: brcm80211: Remove ETHER_HDR_LEN, use ETH_HLEN Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/proto/ethernet.h | 1 - drivers/staging/brcm80211/sys/wlc_mac80211.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index a8638db431db..888165e1ab5c 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -23,7 +23,6 @@ #define ETHER_TYPE_LEN 2 #define ETHER_CRC_LEN 4 -#define ETHER_HDR_LEN (ETH_ALEN * 2 + ETHER_TYPE_LEN) #define ETHER_MIN_LEN 64 #define ETHER_MIN_DATA 46 #define ETHER_MAX_LEN 1518 diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 407f5ec55230..8a89b5fe8e60 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -1727,7 +1727,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, /* some code depends on packed structures */ ASSERT(sizeof(struct ether_addr) == ETH_ALEN); - ASSERT(sizeof(struct ether_header) == ETHER_HDR_LEN); + ASSERT(sizeof(struct ether_header) == ETH_HLEN); ASSERT(sizeof(d11regs_t) == SI_CORE_SIZE); ASSERT(sizeof(ofdm_phy_hdr_t) == D11_PHY_HDR_LEN); ASSERT(sizeof(cck_phy_hdr_t) == D11_PHY_HDR_LEN); -- cgit v1.2.3 From d7ec915abc98795a4cb88e369e2918696dd0ea01 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:57:03 -0800 Subject: staging: brcm80211: Remove unused ETHER_TYPE_ #defines Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/include/proto/ethernet.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index 888165e1ab5c..ad55b565c847 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -28,13 +28,8 @@ #define ETHER_MAX_LEN 1518 #define ETHER_MAX_DATA 1500 -#define ETHER_TYPE_MIN 0x0600 -#define ETHER_TYPE_IP 0x0800 -#define ETHER_TYPE_ARP 0x0806 -#define ETHER_TYPE_8021Q 0x8100 #define ETHER_TYPE_BRCM 0x886c #define ETHER_TYPE_802_1X 0x888e -#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 #define ETHER_DEST_OFFSET (0 * ETH_ALEN) #define ETHER_SRC_OFFSET (1 * ETH_ALEN) -- cgit v1.2.3 From fcbdbed01633bac6271708d86d569e06ed3e4c34 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Dec 2010 16:57:04 -0800 Subject: staging: brcm80211: Convert ETHER_TYPE_802_1X to ETH_P_PAE Remove now unused #define. Signed-off-by: Joe Perches Acked-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 4 ++-- drivers/staging/brcm80211/include/proto/ethernet.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index ec6202b117f9..db4508378775 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -1034,7 +1034,7 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, struct sk_buff *pktbuf) if (is_multicast_ether_addr(eh->ether_dhost)) dhdp->tx_multicast++; - if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) + if (ntoh16(eh->ether_type) == ETH_P_PAE) atomic_inc(&dhd->pend_8021x_cnt); } @@ -1262,7 +1262,7 @@ void dhd_txcomplete(dhd_pub_t *dhdp, struct sk_buff *txp, bool success) eh = (struct ether_header *)(txp->data); type = ntoh16(eh->ether_type); - if (type == ETHER_TYPE_802_1X) + if (type == ETH_P_PAE) atomic_dec(&dhd->pend_8021x_cnt); } diff --git a/drivers/staging/brcm80211/include/proto/ethernet.h b/drivers/staging/brcm80211/include/proto/ethernet.h index ad55b565c847..567407de020e 100644 --- a/drivers/staging/brcm80211/include/proto/ethernet.h +++ b/drivers/staging/brcm80211/include/proto/ethernet.h @@ -29,7 +29,6 @@ #define ETHER_MAX_DATA 1500 #define ETHER_TYPE_BRCM 0x886c -#define ETHER_TYPE_802_1X 0x888e #define ETHER_DEST_OFFSET (0 * ETH_ALEN) #define ETHER_SRC_OFFSET (1 * ETH_ALEN) -- cgit v1.2.3 From f8ce33bbd57a0c9c302ebb273fd963c5efb1a264 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Dec 2010 17:04:00 +0100 Subject: Staging: IIO: Direct digital synthesis abi documentation Changes since RFC/v1: IIO: Apply list review feedback: Apply list review feedback: Restructure documentation according to list feedback. Rename attributes to fit IIO convention used in other drivers. Fix typos. Provide ddsX_out_enable as opposed to ddsX_out_disable Changes since v2: IIO: sysfs-bus-iio-dds: Apply more list review feedback Fix mixture of X and [n] notation for indices. Fix some wording in the descriptions. Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- .../staging/iio/Documentation/sysfs-bus-iio-dds | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 drivers/staging/iio/Documentation/sysfs-bus-iio-dds (limited to 'drivers') diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds new file mode 100644 index 000000000000..ffdd5478a35d --- /dev/null +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds @@ -0,0 +1,93 @@ + +What: /sys/bus/iio/devices/.../ddsX_freqY +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Stores frequency into tuning word Y. + There will be more than one ddsX_freqY file, which allows for + pin controlled FSK Frequency Shift Keying + (ddsX_pincontrol_freq_en is active) or the user can control + the desired active tuning word by writing Y to the + ddsX_freqsymbol file. + +What: /sys/bus/iio/devices/.../ddsX_freqY_scale +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Scale to be applied to ddsX_freqY in order to obtain the + desired value in Hz. If shared across all frequency registers + Y is not present. It is also possible X is not present if + shared across all channels. + +What: /sys/bus/iio/devices/.../ddsX_freqsymbol +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the active output frequency tuning word. The value + corresponds to the Y in ddsX_freqY. To exit this mode the user + can write ddsX_pincontrol_freq_en or ddsX_out_enable file. + +What: /sys/bus/iio/devices/.../ddsX_phaseY +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Stores phase into Y. + There will be more than one ddsX_phaseY file, which allows for + pin controlled PSK Phase Shift Keying + (ddsX_pincontrol_phase_en is active) or the user can + control the desired phase Y which is added to the phase + accumulator output by writing Y to the en_phase file. + +What: /sys/bus/iio/devices/.../ddsX_phaseY_scale +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Scale to be applied to ddsX_phaseY in order to obtain the + desired value in rad. If shared across all phase registers + Y is not present. It is also possible X is not present if + shared across all channels. + +What: /sys/bus/iio/devices/.../ddsX_phasesymbol +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the active phase Y which is added to the phase + accumulator output. The value corresponds to the Y in + ddsX_phaseY. To exit this mode the user can write + ddsX_pincontrol_phase_en or disable file. + +What: /sys/bus/iio/devices/.../ddsX_pincontrol_en +What: /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en +What: /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + ddsX_pincontrol_en: Both, the active frequency and phase is + controlled by the respective phase and frequency control inputs. + In case the device in question allows to independent controls, + then there are dedicated files (ddsX_pincontrol_freq_en, + ddsX_pincontrol_phase_en). + +What: /sys/bus/iio/devices/.../ddsX_out_enable +What: /sys/bus/iio/devices/.../ddsX_outY_enable +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + ddsX_outY_enable controls signal generation on output Y of + channel X. Y may be suppressed if all channels are + controlled together. + +What: /sys/bus/iio/devices/.../ddsX_outY_wavetype +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the output waveform. + (sine, triangle, ramp, square, ...) + For a list of available output waveform options read + available_output_modes. + +What: /sys/bus/iio/devices/.../ddsX_outY_wavetype_available +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + Lists all available output waveform options. -- cgit v1.2.3 From 4851d97d87c8dfa8c97037965690cdefe99a767d Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Dec 2010 17:04:01 +0100 Subject: Staging: IIO: dds.h convenience macros Changes since RFC/v1: IIO: Apply list review feedback Apply list review feedback: Rename attributes to fit IIO convention used in other drivers. Provide ddsX_out_enable as opposed to ddsX_out_disable. Fix typos. Changes since v2: IIO: dds.h: Apply more list review feedback Fix mixture of X and [n] notation for indices. Remove duplicated descriptions. Add store methods to some dds convenience macros. Signed-off-by: Michael Hennerich Reviewed-by: Jonathan Cameron Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/dds.h | 110 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 drivers/staging/iio/dds/dds.h (limited to 'drivers') diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h new file mode 100644 index 000000000000..d8ac3a93baf6 --- /dev/null +++ b/drivers/staging/iio/dds/dds.h @@ -0,0 +1,110 @@ +/* + * dds.h - sysfs attributes associated with DDS devices + * + * Copyright (c) 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +/** + * /sys/bus/iio/devices/.../ddsX_freqY + */ + +#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \ + _mode, _show, _store, _addr) + +/** + * /sys/bus/iio/devices/.../ddsX_freqY_scale + */ + +#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \ + IIO_CONST_ATTR(dds##_channel##_freq_scale, _string) + +/** + * /sys/bus/iio/devices/.../ddsX_freqsymbol + */ + +#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_phaseY + */ + +#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \ + _mode, _show, _store, _addr) + +/** + * /sys/bus/iio/devices/.../ddsX_phaseY_scale + */ + +#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \ + IIO_CONST_ATTR(dds##_channel##_phase_scale, _string) + +/** + * /sys/bus/iio/devices/.../ddsX_phasesymbol + */ + +#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_pincontrol_en + */ + +#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\ + IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en + */ + +#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\ + IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en + */ + +#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\ + IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_out_enable + */ + +#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_out_enable, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_outY_enable + */ + +#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \ + _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_outY_wavetype + */ + +#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \ + IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \ + S_IWUSR, NULL, _store, _addr); + +/** + * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available + */ + +#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\ + IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\ + _modes); -- cgit v1.2.3 From 12b9d5bf76bfa20d3207ef24fca9c8254a586a58 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 14 Dec 2010 17:04:02 +0100 Subject: Staging: IIO: DDS: AD9833 / AD9834 driver Changes since RFC/v1: IIO: Apply list review feedback Apply list review feedback: Rename attributes to fit IIO convention used in other drivers. Fix typos. Provide ddsX_out_enable as opposed to ddsX_out_disable. Use proper __devexit marking. Use strict_strtoul() to avoid negatives. Changes since v2: IIO: ad9834.c: Apply more list review feedback Update use of dds convenience macros. Fix tabbing. Remove superfluous brackets. Keep output disabled after probe. Remove unnecessary code. Signed-off-by: Michael Hennerich Reviewed-by: Datta Shubhrajyoti Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/dds/Kconfig | 10 + drivers/staging/iio/dds/Makefile | 1 + drivers/staging/iio/dds/ad9834.c | 477 +++++++++++++++++++++++++++++++++++++++ drivers/staging/iio/dds/ad9834.h | 112 +++++++++ 4 files changed, 600 insertions(+) create mode 100644 drivers/staging/iio/dds/ad9834.c create mode 100644 drivers/staging/iio/dds/ad9834.h (limited to 'drivers') diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig index 7969be29b0eb..a047da62daf0 100644 --- a/drivers/staging/iio/dds/Kconfig +++ b/drivers/staging/iio/dds/Kconfig @@ -17,6 +17,16 @@ config AD9832 Say yes here to build support for Analog Devices DDS chip ad9832 and ad9835, provides direct access via sysfs. +config AD9834 + tristate "Analog Devices ad9833/4/ driver" + depends on SPI + help + Say yes here to build support for Analog Devices DDS chip + AD9833 and AD9834, provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad9834. + config AD9850 tristate "Analog Devices ad9850/1 driver" depends on SPI diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile index 6f274acb0fcf..147746176b9b 100644 --- a/drivers/staging/iio/dds/Makefile +++ b/drivers/staging/iio/dds/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_AD5930) += ad5930.o obj-$(CONFIG_AD9832) += ad9832.o +obj-$(CONFIG_AD9834) += ad9834.o obj-$(CONFIG_AD9850) += ad9850.o obj-$(CONFIG_AD9852) += ad9852.o obj-$(CONFIG_AD9910) += ad9910.o diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c new file mode 100644 index 000000000000..eb1a681874f9 --- /dev/null +++ b/drivers/staging/iio/dds/ad9834.c @@ -0,0 +1,477 @@ +/* + * AD9834 SPI DAC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../iio.h" +#include "../sysfs.h" +#include "dds.h" + +#include "ad9834.h" + +static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) +{ + unsigned long long freqreg = (u64) fout * (u64) (1 << AD9834_FREQ_BITS); + do_div(freqreg, mclk); + return freqreg; +} + +static int ad9834_write_frequency(struct ad9834_state *st, + unsigned long addr, unsigned long fout) +{ + unsigned long regval; + + if (fout > (st->mclk / 2)) + return -EINVAL; + + regval = ad9834_calc_freqreg(st->mclk, fout); + + st->freq_data[0] = cpu_to_be16(addr | (regval & + RES_MASK(AD9834_FREQ_BITS / 2))); + st->freq_data[1] = cpu_to_be16(addr | ((regval >> + (AD9834_FREQ_BITS / 2)) & + RES_MASK(AD9834_FREQ_BITS / 2))); + + return spi_sync(st->spi, &st->freq_msg);; +} + +static int ad9834_write_phase(struct ad9834_state *st, + unsigned long addr, unsigned long phase) +{ + if (phase > (1 << AD9834_PHASE_BITS)) + return -EINVAL; + st->data = cpu_to_be16(addr | phase); + + return spi_sync(st->spi, &st->msg); +} + +static ssize_t ad9834_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad9834_state *st = dev_info->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret; + long val; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + goto error_ret; + + mutex_lock(&dev_info->mlock); + switch (this_attr->address) { + case AD9834_REG_FREQ0: + case AD9834_REG_FREQ1: + ret = ad9834_write_frequency(st, this_attr->address, val); + break; + case AD9834_REG_PHASE0: + case AD9834_REG_PHASE1: + ret = ad9834_write_phase(st, this_attr->address, val); + break; + case AD9834_OPBITEN: + if (st->control & AD9834_MODE) { + ret = -EINVAL; /* AD9843 reserved mode */ + break; + } + + if (val) + st->control |= AD9834_OPBITEN; + else + st->control &= ~AD9834_OPBITEN; + + st->data = cpu_to_be16(AD9834_REG_CMD | st->control); + ret = spi_sync(st->spi, &st->msg); + break; + case AD9834_PIN_SW: + if (val) + st->control |= AD9834_PIN_SW; + else + st->control &= ~AD9834_PIN_SW; + st->data = cpu_to_be16(AD9834_REG_CMD | st->control); + ret = spi_sync(st->spi, &st->msg); + break; + case AD9834_FSEL: + case AD9834_PSEL: + if (val == 0) + st->control &= ~(this_attr->address | AD9834_PIN_SW); + else if (val == 1) { + st->control |= this_attr->address; + st->control &= ~AD9834_PIN_SW; + } else { + ret = -EINVAL; + break; + } + st->data = cpu_to_be16(AD9834_REG_CMD | st->control); + ret = spi_sync(st->spi, &st->msg); + break; + case AD9834_RESET: + if (val) + st->control &= ~AD9834_RESET; + else + st->control |= AD9834_RESET; + + st->data = cpu_to_be16(AD9834_REG_CMD | st->control); + ret = spi_sync(st->spi, &st->msg); + break; + default: + ret = -ENODEV; + } + mutex_unlock(&dev_info->mlock); + +error_ret: + return ret ? ret : len; +} + +static ssize_t ad9834_store_wavetype(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad9834_state *st = dev_info->dev_data; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret = 0; + bool is_ad9833 = st->devid == ID_AD9833; + + mutex_lock(&dev_info->mlock); + + switch (this_attr->address) { + case 0: + if (sysfs_streq(buf, "sine")) { + st->control &= ~AD9834_MODE; + if (is_ad9833) + st->control &= ~AD9834_OPBITEN; + } else if (sysfs_streq(buf, "triangle")) { + if (is_ad9833) { + st->control &= ~AD9834_OPBITEN; + st->control |= AD9834_MODE; + } else if (st->control & AD9834_OPBITEN) { + ret = -EINVAL; /* AD9843 reserved mode */ + } else { + st->control |= AD9834_MODE; + } + } else if (is_ad9833 && sysfs_streq(buf, "square")) { + st->control &= ~AD9834_MODE; + st->control |= AD9834_OPBITEN; + } else { + ret = -EINVAL; + } + + break; + case 1: + if (sysfs_streq(buf, "square") && + !(st->control & AD9834_MODE)) { + st->control &= ~AD9834_MODE; + st->control |= AD9834_OPBITEN; + } else { + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + if (!ret) { + st->data = cpu_to_be16(AD9834_REG_CMD | st->control); + ret = spi_sync(st->spi, &st->msg); + } + mutex_unlock(&dev_info->mlock); + + return ret ? ret : len; +} + +static ssize_t ad9834_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad9834_state *st = iio_dev_get_devdata(dev_info); + + return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); +} +static IIO_DEVICE_ATTR(name, S_IRUGO, ad9834_show_name, NULL, 0); + +static ssize_t ad9834_show_out0_wavetype_available(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad9834_state *st = iio_dev_get_devdata(dev_info); + char *str; + + if (st->devid == ID_AD9833) + str = "sine triangle square"; + else if (st->control & AD9834_OPBITEN) + str = "sine"; + else + str = "sine triangle"; + + return sprintf(buf, "%s\n", str); +} + + +static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO, + ad9834_show_out0_wavetype_available, NULL, 0); + +static ssize_t ad9834_show_out1_wavetype_available(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad9834_state *st = iio_dev_get_devdata(dev_info); + char *str; + + if (st->control & AD9834_MODE) + str = ""; + else + str = "square"; + + return sprintf(buf, "%s\n", str); +} + +static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO, + ad9834_show_out1_wavetype_available, NULL, 0); + +/** + * see dds.h for further information + */ + +static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0); +static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1); +static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL); +static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ + +static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0); +static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1); +static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL); +static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ + +static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL, + ad9834_write, AD9834_PIN_SW); +static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET); +static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL, + ad9834_write, AD9834_OPBITEN); +static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); +static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); + +static struct attribute *ad9834_attributes[] = { + &iio_dev_attr_dds0_freq0.dev_attr.attr, + &iio_dev_attr_dds0_freq1.dev_attr.attr, + &iio_const_attr_dds0_freq_scale.dev_attr.attr, + &iio_dev_attr_dds0_phase0.dev_attr.attr, + &iio_dev_attr_dds0_phase1.dev_attr.attr, + &iio_const_attr_dds0_phase_scale.dev_attr.attr, + &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr, + &iio_dev_attr_dds0_freqsymbol.dev_attr.attr, + &iio_dev_attr_dds0_phasesymbol.dev_attr.attr, + &iio_dev_attr_dds0_out_enable.dev_attr.attr, + &iio_dev_attr_dds0_out1_enable.dev_attr.attr, + &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr, + &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr, + &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr, + &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static mode_t ad9834_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad9834_state *st = iio_dev_get_devdata(dev_info); + + mode_t mode = attr->mode; + + if (st->devid == ID_AD9834) + return mode; + + if ((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) || + (attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) || + (attr == + &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr)) + mode = 0; + + return mode; +} + +static const struct attribute_group ad9834_attribute_group = { + .attrs = ad9834_attributes, + .is_visible = ad9834_attr_is_visible, +}; + +static int __devinit ad9834_probe(struct spi_device *spi) +{ + struct ad9834_platform_data *pdata = spi->dev.platform_data; + struct ad9834_state *st; + int ret; + + if (!pdata) { + dev_dbg(&spi->dev, "no platform data?\n"); + return -ENODEV; + } + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + st->reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + } + + st->mclk = pdata->mclk; + + spi_set_drvdata(spi, st); + + st->spi = spi; + st->devid = spi_get_device_id(spi)->driver_data; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->attrs = &ad9834_attribute_group; + st->indio_dev->dev_data = (void *) st; + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + /* Setup default messages */ + + st->xfer.tx_buf = &st->data; + st->xfer.len = 2; + + spi_message_init(&st->msg); + spi_message_add_tail(&st->xfer, &st->msg); + + st->freq_xfer[0].tx_buf = &st->freq_data[0]; + st->freq_xfer[0].len = 2; + st->freq_xfer[0].cs_change = 1; + st->freq_xfer[1].tx_buf = &st->freq_data[1]; + st->freq_xfer[1].len = 2; + + spi_message_init(&st->freq_msg); + spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg); + spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg); + + st->control = AD9834_B28 | AD9834_RESET; + + if (!pdata->en_div2) + st->control |= AD9834_DIV2; + + if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834)) + st->control |= AD9834_SIGN_PIB; + + st->data = cpu_to_be16(AD9834_REG_CMD | st->control); + ret = spi_sync(st->spi, &st->msg); + if (ret) { + dev_err(&spi->dev, "device init failed\n"); + goto error_free_device; + } + + ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0); + if (ret) + goto error_free_device; + + ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1); + if (ret) + goto error_free_device; + + ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0); + if (ret) + goto error_free_device; + + ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1); + if (ret) + goto error_free_device; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_free_device; + + return 0; + +error_free_device: + iio_free_device(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static int __devexit ad9834_remove(struct spi_device *spi) +{ + struct ad9834_state *st = spi_get_drvdata(spi); + + iio_device_unregister(st->indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + return 0; +} + +static const struct spi_device_id ad9834_id[] = { + {"ad9833", ID_AD9833}, + {"ad9834", ID_AD9834}, + {} +}; + +static struct spi_driver ad9834_driver = { + .driver = { + .name = "ad9834", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad9834_probe, + .remove = __devexit_p(ad9834_remove), + .id_table = ad9834_id, +}; + +static int __init ad9834_init(void) +{ + return spi_register_driver(&ad9834_driver); +} +module_init(ad9834_init); + +static void __exit ad9834_exit(void) +{ + spi_unregister_driver(&ad9834_driver); +} +module_exit(ad9834_exit); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD9833/AD9834 DDS"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad9834"); diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/dds/ad9834.h new file mode 100644 index 000000000000..0fc3b8859e9e --- /dev/null +++ b/drivers/staging/iio/dds/ad9834.h @@ -0,0 +1,112 @@ +/* + * AD9834 SPI DDS driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_DDS_AD9834_H_ +#define IIO_DDS_AD9834_H_ + +/* Registers */ + +#define AD9834_REG_CMD (0 << 14) +#define AD9834_REG_FREQ0 (1 << 14) +#define AD9834_REG_FREQ1 (2 << 14) +#define AD9834_REG_PHASE0 (6 << 13) +#define AD9834_REG_PHASE1 (7 << 13) + +/* Command Control Bits */ + +#define AD9834_B28 (1 << 13) +#define AD9834_HLB (1 << 12) +#define AD9834_FSEL (1 << 11) +#define AD9834_PSEL (1 << 10) +#define AD9834_PIN_SW (1 << 9) +#define AD9834_RESET (1 << 8) +#define AD9834_SLEEP1 (1 << 7) +#define AD9834_SLEEP12 (1 << 6) +#define AD9834_OPBITEN (1 << 5) +#define AD9834_SIGN_PIB (1 << 4) +#define AD9834_DIV2 (1 << 3) +#define AD9834_MODE (1 << 1) + +#define AD9834_FREQ_BITS 28 +#define AD9834_PHASE_BITS 12 + +#define RES_MASK(bits) ((1 << (bits)) - 1) + +/** + * struct ad9834_state - driver instance specific data + * @indio_dev: the industrial I/O device + * @spi: spi_device + * @reg: supply regulator + * @mclk: external master clock + * @control: cached control word + * @xfer: default spi transfer + * @msg: default spi message + * @freq_xfer: tuning word spi transfer + * @freq_msg: tuning word spi message + * @data: spi transmit buffer + * @freq_data: tuning word spi transmit buffer + */ + +struct ad9834_state { + struct iio_dev *indio_dev; + struct spi_device *spi; + struct regulator *reg; + unsigned int mclk; + unsigned short control; + unsigned short devid; + struct spi_transfer xfer; + struct spi_message msg; + struct spi_transfer freq_xfer[2]; + struct spi_message freq_msg; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + unsigned short data ____cacheline_aligned; + unsigned short freq_data[2] ; +}; + + +/* + * TODO: struct ad7887_platform_data needs to go into include/linux/iio + */ + +/** + * struct ad9834_platform_data - platform specific information + * @mclk: master clock in Hz + * @freq0: power up freq0 tuning word in Hz + * @freq1: power up freq1 tuning word in Hz + * @phase0: power up phase0 value [0..4095] correlates with 0..2PI + * @phase1: power up phase1 value [0..4095] correlates with 0..2PI + * @en_div2: digital output/2 is passed to the SIGN BIT OUT pin + * @en_signbit_msb_out: the MSB (or MSB/2) of the DAC data is connected to the + * SIGN BIT OUT pin. en_div2 controls whether it is the MSB + * or MSB/2 that is output. if en_signbit_msb_out=false, + * the on-board comparator is connected to SIGN BIT OUT + */ + +struct ad9834_platform_data { + unsigned int mclk; + unsigned int freq0; + unsigned int freq1; + unsigned short phase0; + unsigned short phase1; + bool en_div2; + bool en_signbit_msb_out; +}; + +/** + * ad9834_supported_device_ids: + */ + +enum ad9834_supported_device_ids { + ID_AD9833, + ID_AD9834, +}; + +#endif /* IIO_DDS_AD9834_H_ */ -- cgit v1.2.3 From f4528696d803749892eac27422a6fd7748cffee1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 14 Dec 2010 12:51:52 -0800 Subject: staging: brcm80211: Fix WL_ logging macros These macros use the equivalent of "#define WL_(x) printk x" which requires an extra level of parentheses. Convert the macros to use the normal WL_(fmt, args...) style and remove the extra parentheses from the uses. Add format argument verification using no_printk as appropriate. Couple of spelling typo fixes in the formats and argument alignment at the same time. Also coalesced long formats. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- .../staging/brcm80211/brcmfmac/dhd_custom_gpio.c | 34 +- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 518 ++++++++++----------- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h | 46 +- drivers/staging/brcm80211/brcmfmac/wl_iw.c | 480 ++++++++++--------- drivers/staging/brcm80211/brcmfmac/wl_iw.h | 2 +- drivers/staging/brcm80211/sys/wl_dbg.h | 72 +-- drivers/staging/brcm80211/sys/wl_mac80211.c | 247 +++++----- drivers/staging/brcm80211/sys/wlc_alloc.c | 2 +- drivers/staging/brcm80211/sys/wlc_ampdu.c | 99 ++-- drivers/staging/brcm80211/sys/wlc_antsel.c | 4 +- drivers/staging/brcm80211/sys/wlc_bmac.c | 285 +++++++----- drivers/staging/brcm80211/sys/wlc_channel.c | 45 +- drivers/staging/brcm80211/sys/wlc_event.c | 4 +- drivers/staging/brcm80211/sys/wlc_mac80211.c | 340 +++++++------- drivers/staging/brcm80211/sys/wlc_phy_shim.c | 3 +- drivers/staging/brcm80211/sys/wlc_stf.c | 12 +- 16 files changed, 1136 insertions(+), 1057 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c index bb3c7b8c4b98..c3f18bb3b27c 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c @@ -24,8 +24,8 @@ #include #include -#define WL_ERROR(x) printf x -#define WL_TRACE(x) +#define WL_ERROR(fmt, args...) printk(fmt, ##args) +#define WL_TRACE(fmt, args...) no_printk(fmt, ##args) #ifdef CUSTOMER_HW extern void bcm_wlan_power_off(int); @@ -67,13 +67,13 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) #endif if (dhd_oob_gpio_num < 0) { - WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined\n", - __func__)); + WL_ERROR("%s: ERROR customer specific Host GPIO is NOT defined\n", + __func__); return dhd_oob_gpio_num; } - WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", - __func__, dhd_oob_gpio_num)); + WL_ERROR("%s: customer specific Host GPIO number is (%d)\n", + __func__, dhd_oob_gpio_num); #if defined CUSTOMER_HW host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num); @@ -93,40 +93,40 @@ void dhd_customer_gpio_wlan_ctrl(int onoff) { switch (onoff) { case WLAN_RESET_OFF: - WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n", - __func__)); + WL_TRACE("%s: call customer specific GPIO to insert WLAN RESET\n", + __func__); #ifdef CUSTOMER_HW bcm_wlan_power_off(2); #endif /* CUSTOMER_HW */ #ifdef CUSTOMER_HW2 wifi_set_power(0, 0); #endif - WL_ERROR(("=========== WLAN placed in RESET ========\n")); + WL_ERROR("=========== WLAN placed in RESET ========\n"); break; case WLAN_RESET_ON: - WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n", - __func__)); + WL_TRACE("%s: callc customer specific GPIO to remove WLAN RESET\n", + __func__); #ifdef CUSTOMER_HW bcm_wlan_power_on(2); #endif /* CUSTOMER_HW */ #ifdef CUSTOMER_HW2 wifi_set_power(1, 0); #endif - WL_ERROR(("=========== WLAN going back to live ========\n")); + WL_ERROR("=========== WLAN going back to live ========\n"); break; case WLAN_POWER_OFF: - WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n", - __func__)); + WL_TRACE("%s: call customer specific GPIO to turn off WL_REG_ON\n", + __func__); #ifdef CUSTOMER_HW bcm_wlan_power_off(1); #endif /* CUSTOMER_HW */ break; case WLAN_POWER_ON: - WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n", - __func__)); + WL_TRACE("%s: call customer specific GPIO to turn on WL_REG_ON\n", + __func__); #ifdef CUSTOMER_HW bcm_wlan_power_on(1); #endif /* CUSTOMER_HW */ @@ -140,7 +140,7 @@ void dhd_customer_gpio_wlan_ctrl(int onoff) /* Function to get custom MAC address */ int dhd_custom_get_mac_address(unsigned char *buf) { - WL_TRACE(("%s Enter\n", __func__)); + WL_TRACE("%s Enter\n", __func__); if (!buf) return -EINVAL; diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index 1e92f2e230fe..991463f4a7f4 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -337,7 +337,7 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl); struct wl_iface *ci; \ if (unlikely(!(wl_cfg80211_dev && \ (ci = wl_get_drvdata(wl_cfg80211_dev))))) { \ - WL_ERR(("wl_cfg80211_dev is unavailable\n")); \ + WL_ERR("wl_cfg80211_dev is unavailable\n"); \ BUG(); \ } \ ci_to_wl(ci); \ @@ -347,8 +347,8 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl); do { \ struct wl_priv *wl = wiphy_to_wl(wiphy); \ if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \ - WL_INFO(("device is not ready : status (%d)\n", \ - (int)wl->status)); \ + WL_INFO("device is not ready : status (%d)\n", \ + (int)wl->status); \ return -EIO; \ } \ } while (0) @@ -613,8 +613,8 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: - WL_ERR(("type (%d) : currently we do not support this type\n", - type)); + WL_ERR("type (%d) : currently we do not support this type\n", + type); return -EOPNOTSUPP; case NL80211_IFTYPE_ADHOC: wl->conf->mode = WL_MODE_IBSS; @@ -630,15 +630,15 @@ wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, ap = htod32(ap); wdev = ndev->ieee80211_ptr; wdev->iftype = type; - WL_DBG(("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra)); + WL_DBG("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra); err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); if (unlikely(err)) { - WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + WL_ERR("WLC_SET_INFRA error (%d)\n", err); return err; } err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)); if (unlikely(err)) { - WL_ERR(("WLC_SET_AP error (%d)\n", err)); + WL_ERR("WLC_SET_AP error (%d)\n", err); return err; } @@ -717,9 +717,9 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action) iscan->ioctl_buf, WLC_IOCTL_SMLEN); if (unlikely(err)) { if (err == -EBUSY) { - WL_INFO(("system busy : iscan canceled\n")); + WL_INFO("system busy : iscan canceled\n"); } else { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); } } kfree(params); @@ -743,7 +743,7 @@ static s32 wl_do_iscan(struct wl_priv *wl) err = wl_dev_ioctl(wl_to_ndev(wl), WLC_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); if (unlikely(err)) { - WL_DBG(("error (%d)\n", err)); + WL_DBG("error (%d)\n", err); return err; } wl_set_mpc(ndev, 0); @@ -769,12 +769,12 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, s32 err = 0; if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) { - WL_ERR(("Scanning already : status (%d)\n", (int)wl->status)); + WL_ERR("Scanning already : status (%d)\n", (int)wl->status); return -EAGAIN; } if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) { - WL_ERR(("Scanning being aborted : status (%d)\n", - (int)wl->status)); + WL_ERR("Scanning being aborted : status (%d)\n", + (int)wl->status); return -EAGAIN; } @@ -806,26 +806,26 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, else goto scan_out; } else { - WL_DBG(("ssid \"%s\", ssid_len (%d)\n", - ssids->ssid, ssids->ssid_len)); + WL_DBG("ssid \"%s\", ssid_len (%d)\n", + ssids->ssid, ssids->ssid_len); memset(&sr->ssid, 0, sizeof(sr->ssid)); sr->ssid.SSID_len = min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); if (sr->ssid.SSID_len) { memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); - WL_DBG(("Specific scan ssid=\"%s\" len=%d\n", - sr->ssid.SSID, sr->ssid.SSID_len)); + WL_DBG("Specific scan ssid=\"%s\" len=%d\n", + sr->ssid.SSID, sr->ssid.SSID_len); spec_scan = true; } else { - WL_DBG(("Broadcast scan\n")); + WL_DBG("Broadcast scan\n"); } - WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); + WL_DBG("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len); passive_scan = wl->active_scan ? 0 : 1; err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan)); if (unlikely(err)) { - WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); + WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); goto scan_out; } wl_set_mpc(ndev, 0); @@ -833,10 +833,10 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, sizeof(sr->ssid)); if (err) { if (err == -EBUSY) { - WL_INFO(("system busy : scan for \"%s\" " - "canceled\n", sr->ssid.SSID)); + WL_INFO("system busy : scan for \"%s\" canceled\n", + sr->ssid.SSID); } else { - WL_ERR(("WLC_SCAN error (%d)\n", err)); + WL_ERR("WLC_SCAN error (%d)\n", err); } wl_set_mpc(ndev, 1); goto scan_out; @@ -860,7 +860,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, CHECK_SYS_UP(); err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); if (unlikely(err)) { - WL_DBG(("scan error (%d)\n", err)); + WL_DBG("scan error (%d)\n", err); return err; } @@ -879,7 +879,7 @@ static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); } return err; @@ -902,7 +902,7 @@ wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) BUG_ON(unlikely(!len)); err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); } *retval = dtoh32(var.val); @@ -915,7 +915,7 @@ static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold); if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); + WL_ERR("Error (%d)\n", err); return err; } return err; @@ -927,7 +927,7 @@ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold); if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); + WL_ERR("Error (%d)\n", err); return err; } return err; @@ -941,7 +941,7 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) retry = htod32(retry); err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry)); if (unlikely(err)) { - WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); + WL_ERR("cmd (%d) , error (%d)\n", cmd, err); return err; } return err; @@ -1001,7 +1001,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); if (params->bssid) { - WL_ERR(("Invalid bssid\n")); + WL_ERR("Invalid bssid\n"); return -EOPNOTSUPP; } bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); @@ -1027,7 +1027,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, } if (bss) { wl->ibss_starter = false; - WL_DBG(("Found IBSS\n")); + WL_DBG("Found IBSS\n"); } else { wl->ibss_starter = true; } @@ -1051,7 +1051,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params)); if (unlikely(err)) { - WL_ERR(("Error (%d)\n", err)); + WL_ERR("Error (%d)\n", err); return err; } return err; @@ -1082,10 +1082,10 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; else val = WPA_AUTH_DISABLED; - WL_DBG(("setting wpa_auth to 0x%0x\n", val)); + WL_DBG("setting wpa_auth to 0x%0x\n", val); err = wl_dev_intvar_set(dev, "wpa_auth", val); if (unlikely(err)) { - WL_ERR(("set wpa_auth failed (%d)\n", err)); + WL_ERR("set wpa_auth failed (%d)\n", err); return err; } sec = wl_read_prof(wl, WL_PROF_SEC); @@ -1104,27 +1104,27 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: val = 0; - WL_DBG(("open system\n")); + WL_DBG("open system\n"); break; case NL80211_AUTHTYPE_SHARED_KEY: val = 1; - WL_DBG(("shared key\n")); + WL_DBG("shared key\n"); break; case NL80211_AUTHTYPE_AUTOMATIC: val = 2; - WL_DBG(("automatic\n")); + WL_DBG("automatic\n"); break; case NL80211_AUTHTYPE_NETWORK_EAP: - WL_DBG(("network eap\n")); + WL_DBG("network eap\n"); default: val = 2; - WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); + WL_ERR("invalid auth type (%d)\n", sme->auth_type); break; } err = wl_dev_intvar_set(dev, "auth", val); if (unlikely(err)) { - WL_ERR(("set auth failed (%d)\n", err)); + WL_ERR("set auth failed (%d)\n", err); return err; } sec = wl_read_prof(wl, WL_PROF_SEC); @@ -1157,8 +1157,8 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) pval = AES_ENABLED; break; default: - WL_ERR(("invalid cipher pairwise (%d)\n", - sme->crypto.ciphers_pairwise[0])); + WL_ERR("invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0]); return -EINVAL; } } @@ -1178,16 +1178,16 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) gval = AES_ENABLED; break; default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); + WL_ERR("invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } - WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); + WL_DBG("pval (%d) gval (%d)\n", pval, gval); err = wl_dev_intvar_set(dev, "wsec", pval | gval); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } @@ -1209,7 +1209,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) if (sme->crypto.n_akm_suites) { err = wl_dev_intvar_get(dev, "wpa_auth", &val); if (unlikely(err)) { - WL_ERR(("could not get wpa_auth (%d)\n", err)); + WL_ERR("could not get wpa_auth (%d)\n", err); return err; } if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { @@ -1221,8 +1221,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) val = WPA_AUTH_PSK; break; default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); + WL_ERR("invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { @@ -1234,16 +1234,16 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) val = WPA2_AUTH_PSK; break; default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); + WL_ERR("invalid cipher group (%d)\n", + sme->crypto.cipher_group); return -EINVAL; } } - WL_DBG(("setting wpa_auth to %d\n", val)); + WL_DBG("setting wpa_auth to %d\n", val); err = wl_dev_intvar_set(dev, "wpa_auth", val); if (unlikely(err)) { - WL_ERR(("could not set wpa_auth (%d)\n", err)); + WL_ERR("could not set wpa_auth (%d)\n", err); return err; } } @@ -1263,11 +1263,11 @@ wl_set_set_sharedkey(struct net_device *dev, s32 val; s32 err = 0; - WL_DBG(("key len (%d)\n", sme->key_len)); + WL_DBG("key len (%d)\n", sme->key_len); if (sme->key_len) { sec = wl_read_prof(wl, WL_PROF_SEC); - WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", - sec->wpa_versions, sec->cipher_pairwise)); + WL_DBG("wpa_versions 0x%x cipher_pairwise 0x%x\n", + sec->wpa_versions, sec->cipher_pairwise); if (! (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) @@ -1277,7 +1277,7 @@ wl_set_set_sharedkey(struct net_device *dev, key.len = (u32) sme->key_len; key.index = (u32) sme->key_idx; if (unlikely(key.len > sizeof(key.data))) { - WL_ERR(("Too long key length (%u)\n", key.len)); + WL_ERR("Too long key length (%u)\n", key.len); return -EINVAL; } memcpy(key.data, sme->key, key.len); @@ -1290,27 +1290,27 @@ wl_set_set_sharedkey(struct net_device *dev, key.algo = CRYPTO_ALGO_WEP128; break; default: - WL_ERR(("Invalid algorithm (%d)\n", - sme->crypto.ciphers_pairwise[0])); + WL_ERR("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0]); return -EINVAL; } /* Set the new key/index */ - WL_DBG(("key length (%d) key index (%d) algo (%d)\n", - key.len, key.index, key.algo)); - WL_DBG(("key \"%s\"\n", key.data)); + WL_DBG("key length (%d) key index (%d) algo (%d)\n", + key.len, key.index, key.algo); + WL_DBG("key \"%s\"\n", key.data); swap_key_from_BE(&key); err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + WL_ERR("WLC_SET_KEY error (%d)\n", err); return err; } if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { - WL_DBG(("set auth_type to shared key\n")); + WL_DBG("set auth_type to shared key\n"); val = 1; /* shared key */ err = wl_dev_intvar_set(dev, "auth", val); if (unlikely(err)) { - WL_ERR(("set auth failed (%d)\n", err)); + WL_ERR("set auth failed (%d)\n", err); return err; } } @@ -1332,15 +1332,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); if (unlikely(!sme->ssid)) { - WL_ERR(("Invalid ssid\n")); + WL_ERR("Invalid ssid\n"); return -EOPNOTSUPP; } if (chan) { wl->channel = ieee80211_frequency_to_channel(chan->center_freq); - WL_DBG(("channel (%d), center_req (%d)\n", wl->channel, - chan->center_freq)); + WL_DBG("channel (%d), center_req (%d)\n", + wl->channel, chan->center_freq); } - WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); + WL_DBG("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); err = wl_set_wpa_version(dev, sme); if (unlikely(err)) return err; @@ -1376,15 +1376,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); - WL_DBG(("join_param_size %d\n", join_params_size)); + WL_DBG("join_param_size %d\n", join_params_size); if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { - WL_DBG(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, - join_params.ssid.SSID_len)); + WL_DBG("ssid \"%s\", len (%d)\n", + join_params.ssid.SSID, join_params.ssid.SSID_len); } err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } set_bit(WL_STATUS_CONNECTING, &wl->status); @@ -1401,7 +1401,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, bool act = false; s32 err = 0; - WL_DBG(("Reason %d\n", reason_code)); + WL_DBG("Reason %d\n", reason_code); CHECK_SYS_UP(); act = *(bool *) wl_read_prof(wl, WL_PROF_ACT); if (likely(act)) { @@ -1411,7 +1411,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } } @@ -1436,13 +1436,13 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, break; case NL80211_TX_POWER_LIMITED: if (dbm < 0) { - WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); + WL_ERR("TX_POWER_LIMITED - dbm is negative\n"); return -EINVAL; } break; case NL80211_TX_POWER_FIXED: if (dbm < 0) { - WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); + WL_ERR("TX_POWER_FIXED - dbm is negative\n"); return -EINVAL; } break; @@ -1452,7 +1452,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, disable = htod32(disable); err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable)); if (unlikely(err)) { - WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); + WL_ERR("WLC_SET_RADIO error (%d)\n", err); return err; } @@ -1463,7 +1463,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, err = wl_dev_intvar_set(ndev, "qtxpower", (s32) (bcm_mw_to_qdbm(txpwrmw))); if (unlikely(err)) { - WL_ERR(("qtxpower error (%d)\n", err)); + WL_ERR("qtxpower error (%d)\n", err); return err; } wl->conf->tx_power = dbm; @@ -1482,7 +1482,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) CHECK_SYS_UP(); err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); @@ -1499,12 +1499,12 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, s32 wsec; s32 err = 0; - WL_DBG(("key index (%d)\n", key_idx)); + WL_DBG("key index (%d)\n", key_idx); CHECK_SYS_UP(); err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)); if (unlikely(err)) { - WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + WL_ERR("WLC_GET_WSEC error (%d)\n", err); return err; } wsec = dtoh32(wsec); @@ -1515,7 +1515,7 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, sizeof(index)); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); } } return err; @@ -1541,16 +1541,16 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, swap_key_from_BE(&key); err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); if (unlikely(err)) { - WL_ERR(("key delete error (%d)\n", err)); + WL_ERR("key delete error (%d)\n", err); return err; } } else { if (key.len > sizeof(key.data)) { - WL_ERR(("Invalid key length (%d)\n", key.len)); + WL_ERR("Invalid key length (%d)\n", key.len); return -EINVAL; } - WL_DBG(("Setting the key index %d\n", key.index)); + WL_DBG("Setting the key index %d\n", key.index); memcpy(key.data, params->key, key.len); if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { @@ -1574,26 +1574,26 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: key.algo = CRYPTO_ALGO_WEP1; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + WL_DBG("WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: key.algo = CRYPTO_ALGO_WEP128; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + WL_DBG("WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: key.algo = CRYPTO_ALGO_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + WL_DBG("WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + WL_DBG("WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + WL_DBG("WLAN_CIPHER_SUITE_CCMP\n"); break; default: - WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + WL_ERR("Invalid cipher (0x%x)\n", params->cipher); return -EINVAL; } swap_key_from_BE(&key); @@ -1601,7 +1601,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, dhd_wait_pend8021x(dev); err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + WL_ERR("WLC_SET_KEY error (%d)\n", err); return err; } } @@ -1618,7 +1618,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, s32 wsec; s32 err = 0; - WL_DBG(("key index (%d)\n", key_idx)); + WL_DBG("key index (%d)\n", key_idx); CHECK_SYS_UP(); if (mac_addr) @@ -1629,7 +1629,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, key.index = (u32) key_idx; if (unlikely(key.len > sizeof(key.data))) { - WL_ERR(("Too long key length (%u)\n", key.len)); + WL_ERR("Too long key length (%u)\n", key.len); return -EINVAL; } memcpy(key.data, params->key, key.len); @@ -1638,26 +1638,26 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: key.algo = CRYPTO_ALGO_WEP1; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + WL_DBG("WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: key.algo = CRYPTO_ALGO_WEP128; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + WL_DBG("WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: key.algo = CRYPTO_ALGO_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + WL_DBG("WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + WL_DBG("WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: key.algo = CRYPTO_ALGO_AES_CCM; - WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); + WL_DBG("WLAN_CIPHER_SUITE_CCMP\n"); break; default: - WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); + WL_ERR("Invalid cipher (0x%x)\n", params->cipher); return -EINVAL; } @@ -1665,21 +1665,21 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, swap_key_from_BE(&key); err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); if (unlikely(err)) { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + WL_ERR("WLC_SET_KEY error (%d)\n", err); return err; } val = WEP_ENABLED; err = wl_dev_intvar_get(dev, "wsec", &wsec); if (unlikely(err)) { - WL_ERR(("get wsec error (%d)\n", err)); + WL_ERR("get wsec error (%d)\n", err); return err; } wsec &= ~(WEP_ENABLED); wsec |= val; err = wl_dev_intvar_set(dev, "wsec", wsec); if (unlikely(err)) { - WL_ERR(("set wsec error (%d)\n", err)); + WL_ERR("set wsec error (%d)\n", err); return err; } @@ -1687,7 +1687,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, val = htod32(val); err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)); if (unlikely(err)) { - WL_ERR(("WLC_SET_AUTH error (%d)\n", err)); + WL_ERR("WLC_SET_AUTH error (%d)\n", err); return err; } return err; @@ -1709,7 +1709,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, key.flags = WL_PRIMARY_KEY; key.algo = CRYPTO_ALGO_OFF; - WL_DBG(("key index (%d)\n", key_idx)); + WL_DBG("key index (%d)\n", key_idx); /* Set the new key/index */ swap_key_from_BE(&key); err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); @@ -1717,10 +1717,10 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (err == -EINVAL) { if (key.index >= DOT11_MAX_DEFAULT_KEYS) { /* we ignore this key index in this case */ - WL_DBG(("invalid key index (%d)\n", key_idx)); + WL_DBG("invalid key index (%d)\n", key_idx); } } else { - WL_ERR(("WLC_SET_KEY error (%d)\n", err)); + WL_ERR("WLC_SET_KEY error (%d)\n", err); } return err; } @@ -1728,14 +1728,14 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, val = 0; err = wl_dev_intvar_get(dev, "wsec", &wsec); if (unlikely(err)) { - WL_ERR(("get wsec error (%d)\n", err)); + WL_ERR("get wsec error (%d)\n", err); return err; } wsec &= ~(WEP_ENABLED); wsec |= val; err = wl_dev_intvar_set(dev, "wsec", wsec); if (unlikely(err)) { - WL_ERR(("set wsec error (%d)\n", err)); + WL_ERR("set wsec error (%d)\n", err); return err; } @@ -1743,7 +1743,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, val = htod32(val); err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)); if (unlikely(err)) { - WL_ERR(("WLC_SET_AUTH error (%d)\n", err)); + WL_ERR("WLC_SET_AUTH error (%d)\n", err); return err; } return err; @@ -1761,7 +1761,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, s32 wsec; s32 err = 0; - WL_DBG(("key index (%d)\n", key_idx)); + WL_DBG("key index (%d)\n", key_idx); CHECK_SYS_UP(); memset(&key, 0, sizeof(key)); @@ -1773,7 +1773,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)); if (unlikely(err)) { - WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); + WL_ERR("WLC_GET_WSEC error (%d)\n", err); return err; } wsec = dtoh32(wsec); @@ -1782,22 +1782,22 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, sec = wl_read_prof(wl, WL_PROF_SEC); if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + WL_DBG("WLAN_CIPHER_SUITE_WEP40\n"); } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + WL_DBG("WLAN_CIPHER_SUITE_WEP104\n"); } break; case TKIP_ENABLED: params.cipher = WLAN_CIPHER_SUITE_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + WL_DBG("WLAN_CIPHER_SUITE_TKIP\n"); break; case AES_ENABLED: params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + WL_DBG("WLAN_CIPHER_SUITE_AES_CMAC\n"); break; default: - WL_ERR(("Invalid algo (0x%x)\n", wsec)); + WL_ERR("Invalid algo (0x%x)\n", wsec); return -EINVAL; } @@ -1809,7 +1809,7 @@ static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx) { - WL_INFO(("Not supported\n")); + WL_INFO("Not supported\n"); CHECK_SYS_UP(); return -EOPNOTSUPP; } @@ -1827,19 +1827,19 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); if (unlikely (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETH_ALEN))) { - WL_ERR(("Wrong Mac address\n")); + WL_ERR("Wrong Mac address\n"); return -ENOENT; } /* Report the current tx rate */ err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)); if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); + WL_ERR("Could not get rate (%d)\n", err); } else { rate = dtoh32(rate); sinfo->filled |= STATION_INFO_TX_BITRATE; sinfo->txrate.legacy = rate * 5; - WL_DBG(("Rate %d Mbps\n", (rate / 2))); + WL_DBG("Rate %d Mbps\n", rate / 2); } if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { @@ -1847,13 +1847,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); if (unlikely(err)) { - WL_ERR(("Could not get rssi (%d)\n", err)); + WL_ERR("Could not get rssi (%d)\n", err); return err; } rssi = dtoh32(scb_val.val); sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = rssi; - WL_DBG(("RSSI %d dBm\n", rssi)); + WL_DBG("RSSI %d dBm\n", rssi); } return err; @@ -1869,13 +1869,13 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); pm = enabled ? PM_FAST : PM_OFF; pm = htod32(pm); - WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); + WL_DBG("power save %s\n", (pm ? "enabled" : "disabled")); err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); if (unlikely(err)) { if (err == -ENODEV) - WL_DBG(("net_device is not ready yet\n")); + WL_DBG("net_device is not ready yet\n"); else - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } return err; @@ -1927,7 +1927,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)); if (unlikely(err)) { - WL_ERR(("could not get current rateset (%d)\n", err)); + WL_ERR("could not get current rateset (%d)\n", err); return err; } @@ -1947,7 +1947,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, rate = val / 500000; } - WL_DBG(("rate %d mbps\n", (rate / 2))); + WL_DBG("rate %d mbps\n", rate / 2); /* * @@ -1957,7 +1957,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, err_bg = wl_dev_intvar_set(dev, "bg_rate", rate); err_a = wl_dev_intvar_set(dev, "a_rate", rate); if (unlikely(err_bg && err_a)) { - WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a)); + WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a); return err_bg | err_a; } @@ -2002,12 +2002,12 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, { int i, j; - WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); + WL_DBG("No of elements %d\n", pmk_list->pmkids.npmkid); for (i = 0; i < pmk_list->pmkids.npmkid; i++) { - WL_DBG(("PMKID[%d]: %pM =\n", i, - &pmk_list->pmkids.pmkid[i].BSSID)); + WL_DBG("PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID); for (j = 0; j < WPA2_PMKID_LEN; j++) { - WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); + WL_DBG("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); } } if (likely(!err)) { @@ -2041,12 +2041,12 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, } else { err = -EINVAL; } - WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID)); + WL_DBG("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID); for (i = 0; i < WPA2_PMKID_LEN; i++) { - WL_DBG(("%02x\n", - wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid]. - PMKID[i])); + WL_DBG("%02x\n", + wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid]. + PMKID[i]); } err = wl_update_pmklist(dev, wl->pmk_list, err); @@ -2067,10 +2067,10 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); - WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", - &pmkid.pmkid[0].BSSID)); + WL_DBG("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID); for (i = 0; i < WPA2_PMKID_LEN; i++) { - WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); + WL_DBG("%02x\n", pmkid.pmkid[0].PMKID[i]); } for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) @@ -2163,13 +2163,13 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); + WL_ERR("Could not allocate wireless device\n"); return ERR_PTR(-ENOMEM); } wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface); if (unlikely(!wdev->wiphy)) { - WL_ERR(("Couldn not allocate wiphy device\n")); + WL_ERR("Couldn not allocate wiphy device\n"); err = -ENOMEM; goto wiphy_new_out; } @@ -2199,7 +2199,7 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, #endif /* !WL_POWERSAVE_DISABLED */ err = wiphy_register(wdev->wiphy); if (unlikely(err < 0)) { - WL_ERR(("Couldn not register wiphy device (%d)\n", err)); + WL_ERR("Couldn not register wiphy device (%d)\n", err); goto wiphy_register_out; } return wdev; @@ -2218,7 +2218,7 @@ static void wl_free_wdev(struct wl_priv *wl) struct wireless_dev *wdev = wl_to_wdev(wl); if (unlikely(!wdev)) { - WL_ERR(("wdev is invalid\n")); + WL_ERR("wdev is invalid\n"); return; } wiphy_unregister(wdev->wiphy); @@ -2236,11 +2236,11 @@ static s32 wl_inform_bss(struct wl_priv *wl) bss_list = wl->bss_list; if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) { - WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n", - bss_list->version)); + WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version); return -EOPNOTSUPP; } - WL_DBG(("scanned AP count (%d)\n", bss_list->count)); + WL_DBG("scanned AP count (%d)\n", bss_list->count); bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { err = wl_inform_single_bss(wl, bi); @@ -2265,14 +2265,14 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) s32 err = 0; if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { - WL_DBG(("Beacon is larger than buffer. Discarding\n")); + WL_DBG("Beacon is larger than buffer. Discarding\n"); return err; } notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX, GFP_KERNEL); if (unlikely(!notif_bss_info)) { - WL_ERR(("notif_bss_info alloc failed\n")); + WL_ERR("notif_bss_info alloc failed\n"); return -ENOMEM; } mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; @@ -2316,17 +2316,17 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) freq = ieee80211_channel_to_frequency(notif_bss_info->channel); channel = ieee80211_get_channel(wiphy, freq); - WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n", - bi->SSID, - notif_bss_info->rssi, notif_bss_info->channel, - mgmt->u.beacon.capab_info, &bi->BSSID)); + WL_DBG("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n", + bi->SSID, + notif_bss_info->rssi, notif_bss_info->channel, + mgmt->u.beacon.capab_info, &bi->BSSID); signal = notif_bss_info->rssi * 100; if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt, le16_to_cpu (notif_bss_info->frame_len), signal, GFP_KERNEL))) { - WL_ERR(("cfg80211_inform_bss_frame error\n")); + WL_ERR("cfg80211_inform_bss_frame error\n"); kfree(notif_bss_info); return -EINVAL; } @@ -2394,12 +2394,12 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_is_ibssmode(wl)) { cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); - WL_DBG(("joined in IBSS network\n")); + WL_DBG("joined in IBSS network\n"); } else { wl_bss_connect_done(wl, ndev, e, data, true); - WL_DBG(("joined in BSS network \"%s\"\n", - ((struct wlc_ssid *) - wl_read_prof(wl, WL_PROF_SSID))->SSID)); + WL_DBG("joined in BSS network \"%s\"\n", + ((struct wlc_ssid *) + wl_read_prof(wl, WL_PROF_SSID))->SSID); } act = true; wl_update_prof(wl, e, &act, WL_PROF_ACT); @@ -2454,7 +2454,7 @@ wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, WL_IOCTL_LEN_MAX); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } memcpy(buf, wl->ioctl_buf, buf_len); @@ -2474,7 +2474,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl) err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf, WL_ASSOC_INFO_MAX); if (unlikely(err)) { - WL_ERR(("could not get assoc info (%d)\n", err)); + WL_ERR("could not get assoc info (%d)\n", err); return err; } assoc_info = (struct wl_assoc_ielen *)wl->extra_buf; @@ -2484,7 +2484,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl) err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); if (unlikely(err)) { - WL_ERR(("could not get assoc req (%d)\n", err)); + WL_ERR("could not get assoc req (%d)\n", err); return err; } conn_info->req_ie_len = req_len; @@ -2498,7 +2498,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl) err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); if (unlikely(err)) { - WL_ERR(("could not get assoc resp (%d)\n", err)); + WL_ERR("could not get assoc resp (%d)\n", err); return err; } conn_info->resp_ie_len = resp_len; @@ -2508,8 +2508,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl) conn_info->resp_ie_len = 0; conn_info->resp_ie = NULL; } - WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, - conn_info->resp_ie_len)); + WL_DBG("req len (%d) resp len (%d)\n", + conn_info->req_ie_len, conn_info->resp_ie_len); return err; } @@ -2542,8 +2542,8 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); - WL_DBG(("join_params->params.chanspec_list[0]= %#X, channel %d, chanspec %#X\n", - join_params->params.chanspec_list[0], ch, chanspec)); + WL_DBG("join_params->params.chanspec_list[0]= %#X, channel %d, chanspec %#X\n", + join_params->params.chanspec_list[0], ch, chanspec); } } @@ -2570,12 +2570,12 @@ static s32 wl_update_bss_info(struct wl_priv *wl) rtnl_lock(); if (unlikely(!bss)) { - WL_DBG(("Could not find the AP\n")); + WL_DBG("Could not find the AP\n"); *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO, wl->extra_buf, WL_EXTRA_BUF_MAX); if (unlikely(err)) { - WL_ERR(("Could not get bss info %d\n", err)); + WL_ERR("Could not get bss info %d\n", err); goto update_bss_info_out; } bi = (struct wl_bss_info *)(wl->extra_buf + 4); @@ -2591,7 +2591,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl) ie_len = bi->ie_length; beacon_interval = cpu_to_le16(bi->beacon_period); } else { - WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); + WL_DBG("Found the AP in the list - BSSID %pM\n", bss->bssid); ie = bss->information_elements; ie_len = bss->len_information_elements; beacon_interval = bss->beacon_interval; @@ -2610,7 +2610,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl) err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_DTIMPRD, &dtim_period, sizeof(dtim_period)); if (unlikely(err)) { - WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); + WL_ERR("WLC_GET_DTIMPRD error (%d)\n", err); goto update_bss_info_out; } } @@ -2637,7 +2637,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, (u8 *)&wl->bssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); - WL_DBG(("Report roaming result\n")); + WL_DBG("Report roaming result\n"); set_bit(WL_STATUS_CONNECTED, &wl->status); @@ -2663,15 +2663,15 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, conn_info->resp_ie_len, completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); - WL_DBG(("Report connect result - connection %s\n", - completed ? "succeeded" : "failed")); + WL_DBG("Report connect result - connection %s\n", + completed ? "succeeded" : "failed"); } else { cfg80211_roamed(ndev, (u8 *)&wl->bssid, conn_info->req_ie, conn_info->req_ie_len, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); - WL_DBG(("Report roaming result\n")); + WL_DBG("Report roaming result\n"); } set_bit(WL_STATUS_CONNECTED, &wl->status); @@ -2711,7 +2711,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, return wl_wakeup_iscan(wl_to_iscan(wl)); if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { - WL_ERR(("Scan complete while device not scanning\n")); + WL_ERR("Scan complete while device not scanning\n"); return -EINVAL; } if (unlikely(!wl->scan_request)) { @@ -2720,14 +2720,14 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, sizeof(channel_inform)); if (unlikely(err)) { - WL_ERR(("scan busy (%d)\n", err)); + WL_ERR("scan busy (%d)\n", err); goto scan_done_out; } channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); if (unlikely(channel_inform.scan_channel)) { - WL_DBG(("channel_inform.scan_channel (%d)\n", - channel_inform.scan_channel)); + WL_DBG("channel_inform.scan_channel (%d)\n", + channel_inform.scan_channel); } wl->bss_list = wl->scan_results; bss_list = wl->bss_list; @@ -2735,7 +2735,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, bss_list->buflen = htod32(len); err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len); if (unlikely(err)) { - WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); + WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); err = -EINVAL; goto scan_done_out; } @@ -2791,52 +2791,52 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) { wl->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); if (unlikely(!wl->scan_results)) { - WL_ERR(("Scan results alloc failed\n")); + WL_ERR("Scan results alloc failed\n"); goto init_priv_mem_out; } wl->conf = kzalloc(sizeof(*wl->conf), GFP_KERNEL); if (unlikely(!wl->conf)) { - WL_ERR(("wl_conf alloc failed\n")); + WL_ERR("wl_conf alloc failed\n"); goto init_priv_mem_out; } wl->profile = kzalloc(sizeof(*wl->profile), GFP_KERNEL); if (unlikely(!wl->profile)) { - WL_ERR(("wl_profile alloc failed\n")); + WL_ERR("wl_profile alloc failed\n"); goto init_priv_mem_out; } wl->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); if (unlikely(!wl->bss_info)) { - WL_ERR(("Bss information alloc failed\n")); + WL_ERR("Bss information alloc failed\n"); goto init_priv_mem_out; } wl->scan_req_int = kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); if (unlikely(!wl->scan_req_int)) { - WL_ERR(("Scan req alloc failed\n")); + WL_ERR("Scan req alloc failed\n"); goto init_priv_mem_out; } wl->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); if (unlikely(!wl->ioctl_buf)) { - WL_ERR(("Ioctl buf alloc failed\n")); + WL_ERR("Ioctl buf alloc failed\n"); goto init_priv_mem_out; } wl->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); if (unlikely(!wl->extra_buf)) { - WL_ERR(("Extra buf alloc failed\n")); + WL_ERR("Extra buf alloc failed\n"); goto init_priv_mem_out; } wl->iscan = kzalloc(sizeof(*wl->iscan), GFP_KERNEL); if (unlikely(!wl->iscan)) { - WL_ERR(("Iscan buf alloc failed\n")); + WL_ERR("Iscan buf alloc failed\n"); goto init_priv_mem_out; } wl->fw = kzalloc(sizeof(*wl->fw), GFP_KERNEL); if (unlikely(!wl->fw)) { - WL_ERR(("fw object alloc failed\n")); + WL_ERR("fw object alloc failed\n"); goto init_priv_mem_out; } wl->pmk_list = kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); if (unlikely(!wl->pmk_list)) { - WL_ERR(("pmk list alloc failed\n")); + WL_ERR("pmk list alloc failed\n"); goto init_priv_mem_out; } @@ -2878,7 +2878,7 @@ static s32 wl_create_event_handler(struct wl_priv *wl) wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler"); if (IS_ERR(wl->event_tsk)) { wl->event_tsk = NULL; - WL_ERR(("failed to create event thread\n")); + WL_ERR("failed to create event thread\n"); return -ENOMEM; } return 0; @@ -2911,7 +2911,7 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) struct net_device *ndev = wl_to_ndev(wl); if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { - WL_ERR(("Scan complete while device not scanning\n")); + WL_ERR("Scan complete while device not scanning\n"); return; } if (likely(wl->scan_request)) { @@ -2925,7 +2925,7 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan) { if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { - WL_DBG(("wake up iscan\n")); + WL_DBG("wake up iscan\n"); up(&iscan->sync); return 0; } @@ -2955,14 +2955,14 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, WL_ISCAN_BUF_MAX); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } results->buflen = dtoh32(results->buflen); results->version = dtoh32(results->version); results->count = dtoh32(results->count); - WL_DBG(("results->count = %d\n", results->count)); - WL_DBG(("results->buflen = %d\n", results->buflen)); + WL_DBG("results->count = %d\n", results->count); + WL_DBG("results->buflen = %d\n", results->buflen); *status = dtoh32(list_buf->status); *bss_list = results; @@ -3047,7 +3047,7 @@ static s32 wl_iscan_thread(void *data) err = wl_get_iscan_results(iscan, &status, &wl->bss_list); if (unlikely(err)) { status = WL_SCAN_RESULTS_ABORTED; - WL_ERR(("Abort iscan\n")); + WL_ERR("Abort iscan\n"); } rtnl_unlock(); el->handler[status] (wl); @@ -3056,7 +3056,7 @@ static s32 wl_iscan_thread(void *data) del_timer_sync(&iscan->timer); iscan->timer_on = 0; } - WL_DBG(("%s was terminated\n", __func__)); + WL_DBG("%s was terminated\n", __func__); return 0; } @@ -3067,7 +3067,7 @@ static void wl_iscan_timer(unsigned long data) if (iscan) { iscan->timer_on = 0; - WL_DBG(("timer expired\n")); + WL_DBG("timer expired\n"); wl_wakeup_iscan(iscan); } } @@ -3082,7 +3082,7 @@ static s32 wl_invoke_iscan(struct wl_priv *wl) sema_init(&iscan->sync, 0); iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); if (IS_ERR(iscan->tsk)) { - WL_ERR(("Could not create iscan thread\n")); + WL_ERR("Could not create iscan thread\n"); iscan->tsk = NULL; return -ENOMEM; } @@ -3117,7 +3117,7 @@ static s32 wl_init_iscan(struct wl_priv *wl) sema_init(&iscan->sync, 0); iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); if (IS_ERR(iscan->tsk)) { - WL_ERR(("Could not create iscan thread\n")); + WL_ERR("Could not create iscan thread\n"); iscan->tsk = NULL; return -ENOMEM; } @@ -3186,15 +3186,15 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) s32 err = 0; if (unlikely(!ndev)) { - WL_ERR(("ndev is invaild\n")); + WL_ERR("ndev is invalid\n"); return -ENODEV; } wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL); if (unlikely(!wl_cfg80211_dev)) { - WL_ERR(("wl_cfg80211_dev is invalid\n")); + WL_ERR("wl_cfg80211_dev is invalid\n"); return -ENOMEM; } - WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func())); + WL_DBG("func %p\n", wl_cfg80211_get_sdio_func()); wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev); if (IS_ERR(wdev)) return -ENOMEM; @@ -3210,7 +3210,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) wdev->netdev = ndev; err = wl_init_priv(wl); if (unlikely(err)) { - WL_ERR(("Failed to init iwm_priv (%d)\n", err)); + WL_ERR("Failed to init iwm_priv (%d)\n", err); goto cfg80211_attach_out; } wl_set_drvdata(wl_cfg80211_dev, ci); @@ -3255,19 +3255,19 @@ static s32 wl_event_handler(void *data) break; e = wl_deq_event(wl); if (unlikely(!e)) { - WL_ERR(("eqeue empty..\n")); + WL_ERR("event queue empty...\n"); BUG(); } - WL_DBG(("event type (%d)\n", e->etype)); + WL_DBG("event type (%d)\n", e->etype); if (wl->el.handler[e->etype]) { wl->el.handler[e->etype] (wl, wl_to_ndev(wl), &e->emsg, e->edata); } else { - WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); + WL_DBG("Unknown Event (%d): ignoring\n", e->etype); } wl_put_event(e); } - WL_DBG(("%s was terminated\n", __func__)); + WL_DBG("%s was terminated\n", __func__); return 0; } @@ -3280,7 +3280,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? wl_dbg_estr[event_type] : (s8 *) "Unknown"; #endif /* (WL_DBG_LEVEL > 0) */ - WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); + WL_DBG("event_type (%d):" "WLC_E_" "%s\n", event_type, estr); if (likely(!wl_enq_event(wl, event_type, e, data))) wl_wakeup_event(wl); } @@ -3335,7 +3335,7 @@ wl_enq_event(struct wl_priv *wl, u32 event, const wl_event_msg_t *msg, e = kzalloc(sizeof(struct wl_event_q), GFP_KERNEL); if (unlikely(!e)) { - WL_ERR(("event alloc failed\n")); + WL_ERR("event alloc failed\n"); return -ENOMEM; } @@ -3379,8 +3379,8 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype) switch (iftype) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: - WL_ERR(("type (%d) : currently we do not support this mode\n", - iftype)); + WL_ERR("type (%d) : currently we do not support this mode\n", + iftype); err = -EINVAL; return err; case NL80211_IFTYPE_ADHOC: @@ -3390,20 +3390,20 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype) break; default: err = -EINVAL; - WL_ERR(("invalid type (%d)\n", iftype)); + WL_ERR("invalid type (%d)\n", iftype); return err; } infra = htod32(infra); ap = htod32(ap); - WL_DBG(("%s ap (%d), infra (%d)\n", ndev->name, ap, infra)); + WL_DBG("%s ap (%d), infra (%d)\n", ndev->name, ap, infra); err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); if (unlikely(err)) { - WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); + WL_ERR("WLC_SET_INFRA error (%d)\n", err); return err; } err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)); if (unlikely(err)) { - WL_ERR(("WLC_SET_AP error (%d)\n", err)); + WL_ERR("WLC_SET_AP error (%d)\n", err); return err; } @@ -3425,7 +3425,7 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) err = wl_dev_ioctl(ndev, WLC_UP, &up, sizeof(up)); if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); + WL_ERR("WLC_UP error (%d)\n", err); } return err; } @@ -3436,7 +3436,7 @@ static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) err = wl_dev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode)); if (unlikely(err)) { - WL_ERR(("WLC_SET_PM error (%d)\n", err)); + WL_ERR("WLC_SET_PM error (%d)\n", err); } return err; } @@ -3453,14 +3453,14 @@ wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) sizeof(iovbuf)); err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (unlikely(err)) { - WL_ERR(("txglomalign error (%d)\n", err)); + WL_ERR("txglomalign error (%d)\n", err); goto dongle_glom_out; } /* disable glom option per default */ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (unlikely(err)) { - WL_ERR(("txglom error (%d)\n", err)); + WL_ERR("txglom error (%d)\n", err); goto dongle_glom_out; } dongle_glom_out: @@ -3481,7 +3481,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) sizeof(iovbuf)); err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (unlikely(err)) { - WL_ERR(("bcn_timeout error (%d)\n", err)); + WL_ERR("bcn_timeout error (%d)\n", err); goto dongle_rom_out; } } @@ -3490,7 +3490,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (unlikely(err)) { - WL_ERR(("roam_off error (%d)\n", err)); + WL_ERR("roam_off error (%d)\n", err); goto dongle_rom_out; } dongle_rom_out: @@ -3510,7 +3510,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) sizeof(iovbuf)); err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); if (unlikely(err)) { - WL_ERR(("Get event_msgs error (%d)\n", err)); + WL_ERR("Get event_msgs error (%d)\n", err); goto dongle_eventmsg_out; } memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); @@ -3538,7 +3538,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) sizeof(iovbuf)); err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (unlikely(err)) { - WL_ERR(("Set event_msgs error (%d)\n", err)); + WL_ERR("Set event_msgs error (%d)\n", err); goto dongle_eventmsg_out; } @@ -3556,9 +3556,9 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, sizeof(scan_assoc_time)); if (err) { if (err == -EOPNOTSUPP) { - WL_INFO(("Scan assoc time is not supported\n")); + WL_INFO("Scan assoc time is not supported\n"); } else { - WL_ERR(("Scan assoc time error (%d)\n", err)); + WL_ERR("Scan assoc time error (%d)\n", err); } goto dongle_scantime_out; } @@ -3566,9 +3566,9 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, sizeof(scan_unassoc_time)); if (err) { if (err == -EOPNOTSUPP) { - WL_INFO(("Scan unassoc time is not supported\n")); + WL_INFO("Scan unassoc time is not supported\n"); } else { - WL_ERR(("Scan unassoc time error (%d)\n", err)); + WL_ERR("Scan unassoc time error (%d)\n", err); } goto dongle_scantime_out; } @@ -3589,9 +3589,9 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (err) { if (err == -EOPNOTSUPP) - WL_INFO(("arpoe is not supported\n")); + WL_INFO("arpoe is not supported\n"); else - WL_ERR(("arpoe error (%d)\n", err)); + WL_ERR("arpoe error (%d)\n", err); goto dongle_offload_out; } @@ -3599,9 +3599,9 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (err) { if (err == -EOPNOTSUPP) - WL_INFO(("arp_ol is not supported\n")); + WL_INFO("arp_ol is not supported\n"); else - WL_ERR(("arp_ol error (%d)\n", err)); + WL_ERR("arp_ol error (%d)\n", err); goto dongle_offload_out; } @@ -3614,12 +3614,12 @@ static s32 wl_pattern_atoh(s8 *src, s8 *dst) { int i; if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { - WL_ERR(("Mask invalid format. Needs to start with 0x\n")); + WL_ERR("Mask invalid format. Needs to start with 0x\n"); return -1; } src = src + 2; /* Skip past 0x */ if (strlen(src) % 2 != 0) { - WL_ERR(("Mask invalid format. Needs to be of even length\n")); + WL_ERR("Mask invalid format. Needs to be of even length\n"); return -1; } for (i = 0; *src != '\0'; i++) { @@ -3678,7 +3678,7 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) mask_and_pattern[mask_size])); if (mask_size != pattern_size) { - WL_ERR(("Mask and pattern not the same size\n")); + WL_ERR("Mask and pattern not the same size\n"); err = -EINVAL; goto dongle_filter_out; } @@ -3698,9 +3698,9 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) err = wl_dev_ioctl(ndev, WLC_SET_VAR, buf, buf_len); if (err) { if (err == -EOPNOTSUPP) { - WL_INFO(("filter not supported\n")); + WL_INFO("filter not supported\n"); } else { - WL_ERR(("filter (%d)\n", err)); + WL_ERR("filter (%d)\n", err); } goto dongle_filter_out; } @@ -3711,9 +3711,9 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); if (err) { if (err == -EOPNOTSUPP) { - WL_INFO(("filter_mode not supported\n")); + WL_INFO("filter_mode not supported\n"); } else { - WL_ERR(("filter_mode (%d)\n", err)); + WL_ERR("filter_mode (%d)\n", err); } goto dongle_filter_out; } @@ -3794,12 +3794,12 @@ static s32 wl_update_wiphybands(struct wl_priv *wl) err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_PHYLIST, &phy_list, sizeof(phy_list)); if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); + WL_ERR("error (%d)\n", err); return err; } phy = ((char *)&phy_list)[1]; - WL_DBG(("%c phy\n", phy)); + WL_DBG("%c phy\n", phy); if (phy == 'n' || phy == 'a') { wiphy = wl_to_wiphy(wl); wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; @@ -3905,7 +3905,7 @@ static void *wl_read_prof(struct wl_priv *wl, s32 item) case WL_PROF_SSID: return &wl->profile->ssid; } - WL_ERR(("invalid item (%d)\n", item)); + WL_ERR("invalid item (%d)\n", item); return NULL; } @@ -3943,7 +3943,7 @@ wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, wl->profile->dtim_period = *(u8 *)data; break; default: - WL_ERR(("unsupported item (%d)\n", item)); + WL_ERR("unsupported item (%d)\n", item); err = -EOPNOTSUPP; break; } @@ -3985,7 +3985,7 @@ static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) s32 err = 0; if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) { - WL_ERR(("ei crosses buffer boundary\n")); + WL_ERR("ei crosses buffer boundary\n"); return -ENOSPC; } ie->buf[ie->offset] = t; @@ -4002,7 +4002,7 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) s32 err = 0; if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { - WL_ERR(("ei_stream crosses buffer boundary\n")); + WL_ERR("ei_stream crosses buffer boundary\n"); return -ENOSPC; } memcpy(&ie->buf[ie->offset], ie_stream, ie_size); @@ -4017,7 +4017,7 @@ static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size) s32 err = 0; if (unlikely(ie->offset > dst_size)) { - WL_ERR(("dst_size is not enough\n")); + WL_ERR("dst_size is not enough\n"); return -ENOSPC; } memcpy(dst, &ie->buf[0], ie->offset); @@ -4117,37 +4117,37 @@ void *wl_cfg80211_request_fw(s8 *file_name) const struct firmware *fw_entry = NULL; s32 err = 0; - WL_DBG(("file name : \"%s\"\n", file_name)); + WL_DBG("file name : \"%s\"\n", file_name); wl = WL_PRIV_GET(); if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) { err = request_firmware(&wl->fw->fw_entry, file_name, &wl_cfg80211_get_sdio_func()->dev); if (unlikely(err)) { - WL_ERR(("Could not download fw (%d)\n", err)); + WL_ERR("Could not download fw (%d)\n", err); goto req_fw_out; } set_bit(WL_FW_LOADING_DONE, &wl->fw->status); fw_entry = wl->fw->fw_entry; if (fw_entry) { - WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size, - fw_entry->data)); + WL_DBG("fw size (%zd), data (%p)\n", + fw_entry->size, fw_entry->data); } } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) { err = request_firmware(&wl->fw->fw_entry, file_name, &wl_cfg80211_get_sdio_func()->dev); if (unlikely(err)) { - WL_ERR(("Could not download nvram (%d)\n", err)); + WL_ERR("Could not download nvram (%d)\n", err); goto req_fw_out; } set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status); fw_entry = wl->fw->fw_entry; if (fw_entry) { - WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size, - fw_entry->data)); + WL_DBG("nvram size (%zd), data (%p)\n", + fw_entry->size, fw_entry->data); } } else { - WL_DBG(("Downloading already done. Nothing to do more\n")); + WL_DBG("Downloading already done. Nothing to do more\n"); err = -EPERM; } @@ -4183,10 +4183,10 @@ static void wl_set_mpc(struct net_device *ndev, int mpc) err = wl_dev_intvar_set(ndev, "mpc", mpc); if (unlikely(err)) { - WL_ERR(("fail to set mpc\n")); + WL_ERR("fail to set mpc\n"); return; } - WL_DBG(("MPC : %d\n", mpc)); + WL_DBG("MPC : %d\n", mpc); } static int wl_debugfs_add_netdev_params(struct wl_priv *wl) diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h index 1069e65f8ce6..482691be210a 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h @@ -54,34 +54,36 @@ struct wl_ibss; #define WL_DBG_LEVEL 1 /* 0 invalidates all debug messages. default is 1 */ -#define WL_ERR(args) \ -do { \ - if (wl_dbg_level & WL_DBG_ERR) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "ERROR @%s : ", __func__); \ - printk args; \ - } \ - } \ +#define WL_ERR(fmt, args...) \ +do { \ + if (wl_dbg_level & WL_DBG_ERR) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "ERROR @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ } while (0) -#define WL_INFO(args) \ -do { \ - if (wl_dbg_level & WL_DBG_INFO) { \ - if (net_ratelimit()) { \ - printk(KERN_ERR "INFO @%s : ", __func__); \ - printk args; \ - } \ - } \ + +#define WL_INFO(fmt, args...) \ +do { \ + if (wl_dbg_level & WL_DBG_INFO) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "INFO @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ } while (0) + #if (WL_DBG_LEVEL > 0) -#define WL_DBG(args) \ -do { \ +#define WL_DBG(fmt, args...) \ +do { \ if (wl_dbg_level & WL_DBG_DBG) { \ - printk(KERN_ERR "DEBUG @%s :", __func__); \ - printk args; \ - } \ + printk(KERN_ERR "DEBUG @%s :" fmt, \ + __func__, ##args); \ + } \ } while (0) #else /* !(WL_DBG_LEVEL > 0) */ -#define WL_DBG(args) +#define WL_DBG(fmt, args...) noprintk(fmt, ##args) #endif /* (WL_DBG_LEVEL > 0) */ #define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */ diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.c b/drivers/staging/brcm80211/brcmfmac/wl_iw.c index 14580b2ea198..db6e68eab290 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.c @@ -39,12 +39,11 @@ typedef const struct si_pub si_t; #include #include -#define WL_ERROR(x) printf x -#define WL_TRACE(x) -#define WL_ASSOC(x) -#define WL_INFORM(x) -#define WL_WSEC(x) -#define WL_SCAN(x) +#define WL_ERROR(fmt, args...) printk(fmt, ##args) +#define WL_TRACE(fmt, args...) no_printk(fmt, ##args) +#define WL_INFORM(fmt, args...) no_printk(fmt, ##args) +#define WL_WSEC(fmt, args...) no_printk(fmt, ##args) +#define WL_SCAN(fmt, args...) no_printk(fmt, ##args) #include @@ -187,12 +186,12 @@ static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len) int ret = -EINVAL; if (!dev) { - WL_ERROR(("%s: dev is null\n", __func__)); + WL_ERROR("%s: dev is null\n", __func__); return ret; } - WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, " - "len:%d ,\n", __func__, current->pid, cmd, arg, len)); + WL_INFORM("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d\n", + __func__, current->pid, cmd, arg, len); if (g_onoff == G_WLAN_SET_ON) { memset(&ioc, 0, sizeof(ioc)); @@ -205,7 +204,7 @@ static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len) ret = dev_open(dev); if (ret) { - WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret)); + WL_ERROR("%s: Error dev_open: %d\n", __func__, ret); return ret; } @@ -214,7 +213,7 @@ static int dev_wlc_ioctl(struct net_device *dev, int cmd, void *arg, int len) ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); set_fs(fs); } else { - WL_TRACE(("%s: call after driver stop : ignored\n", __func__)); + WL_TRACE("%s: call after driver stop : ignored\n", __func__); } return ret; } @@ -335,7 +334,7 @@ wl_iw_config_commit(struct net_device *dev, int error; struct sockaddr bssid; - WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name)); + WL_TRACE("%s: SIOCSIWCOMMIT\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); if (error) @@ -349,8 +348,8 @@ wl_iw_config_commit(struct net_device *dev, memset(&bssid, 0, sizeof(struct sockaddr)); error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETH_ALEN); if (error) { - WL_ERROR(("%s: WLC_REASSOC to %s failed\n", __func__, - ssid.SSID)); + WL_ERROR("%s: WLC_REASSOC to %s failed\n", + __func__, ssid.SSID); return error; } @@ -361,7 +360,7 @@ static int wl_iw_get_name(struct net_device *dev, struct iw_request_info *info, char *cwrq, char *extra) { - WL_TRACE(("%s: SIOCGIWNAME\n", dev->name)); + WL_TRACE("%s: SIOCGIWNAME\n", dev->name); strcpy(cwrq, "IEEE 802.11-DS"); @@ -375,7 +374,7 @@ wl_iw_set_freq(struct net_device *dev, int error, chan; uint sf = 0; - WL_TRACE(("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name)); + WL_TRACE("\n %s %s: SIOCSIWFREQ\n", __func__, dev->name); if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { chan = fwrq->m; @@ -410,7 +409,7 @@ wl_iw_get_freq(struct net_device *dev, channel_info_t ci; int error; - WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); + WL_TRACE("%s: SIOCGIWFREQ\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)); if (error) @@ -427,7 +426,7 @@ wl_iw_set_mode(struct net_device *dev, { int infra = 0, ap = 0, error = 0; - WL_TRACE(("%s: SIOCSIWMODE\n", dev->name)); + WL_TRACE("%s: SIOCSIWMODE\n", dev->name); switch (*uwrq) { case IW_MODE_MASTER: @@ -462,7 +461,7 @@ wl_iw_get_mode(struct net_device *dev, { int error, infra = 0, ap = 0; - WL_TRACE(("%s: SIOCGIWMODE\n", dev->name)); + WL_TRACE("%s: SIOCGIWMODE\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra)); if (error) @@ -501,14 +500,14 @@ wl_iw_get_range(struct net_device *dev, {30, 60, 90, 120, 180, 240, 270, 300} }; - WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); + WL_TRACE("%s: SIOCGIWRANGE\n", dev->name); if (!extra) return -EINVAL; channels = kmalloc((MAXCHANNEL + 1) * 4, GFP_KERNEL); if (!channels) { - WL_ERROR(("Could not alloc channels\n")); + WL_ERROR("Could not alloc channels\n"); return -ENOMEM; } list = (wl_u32_list_t *) channels; @@ -684,7 +683,7 @@ wl_iw_set_spy(struct net_device *dev, struct sockaddr *addr = (struct sockaddr *)extra; int i; - WL_TRACE(("%s: SIOCSIWSPY\n", dev->name)); + WL_TRACE("%s: SIOCSIWSPY\n", dev->name); if (!extra) return -EINVAL; @@ -706,7 +705,7 @@ wl_iw_get_spy(struct net_device *dev, struct iw_quality *qual = (struct iw_quality *)&addr[iw->spy_num]; int i; - WL_TRACE(("%s: SIOCGIWSPY\n", dev->name)); + WL_TRACE("%s: SIOCGIWSPY\n", dev->name); if (!extra) return -EINVAL; @@ -751,8 +750,8 @@ wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); - WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n", - __func__, join_params->params.chanspec_list[0])); + WL_TRACE("%s join_params->params.chanspec_list[0]= %X\n", + __func__, join_params->params.chanspec_list[0]); } return 1; } @@ -765,10 +764,10 @@ wl_iw_set_wap(struct net_device *dev, wl_join_params_t join_params; int join_params_size; - WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); + WL_TRACE("%s: SIOCSIWAP\n", dev->name); if (awrq->sa_family != ARPHRD_ETHER) { - WL_ERROR(("Invalid Header...sa_family\n")); + WL_ERROR("Invalid Header...sa_family\n"); return -EINVAL; } @@ -788,21 +787,21 @@ wl_iw_set_wap(struct net_device *dev, join_params.ssid.SSID_len = htod32(g_ssid.SSID_len); memcpy(&join_params.params.bssid, awrq->sa_data, ETH_ALEN); - WL_TRACE(("%s target_channel=%d\n", __func__, - g_wl_iw_params.target_channel)); + WL_TRACE("%s target_channel=%d\n", + __func__, g_wl_iw_params.target_channel); wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size); error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); if (error) { - WL_ERROR(("%s Invalid ioctl data=%d\n", __func__, error)); + WL_ERROR("%s Invalid ioctl data=%d\n", __func__, error); } if (g_ssid.SSID_len) { - WL_TRACE(("%s: join SSID=%s BSSID=%pM ch=%d\n", - __func__, g_ssid.SSID, awrq->sa_data, - g_wl_iw_params.target_channel)); + WL_TRACE("%s: join SSID=%s BSSID=%pM ch=%d\n", + __func__, g_ssid.SSID, awrq->sa_data, + g_wl_iw_params.target_channel); } memset(&g_ssid, 0, sizeof(g_ssid)); @@ -813,7 +812,7 @@ static int wl_iw_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); + WL_TRACE("%s: SIOCGIWAP\n", dev->name); awrq->sa_family = ARPHRD_ETHER; memset(awrq->sa_data, 0, ETH_ALEN); @@ -832,11 +831,11 @@ wl_iw_mlme(struct net_device *dev, scb_val_t scbval; int error = -EINVAL; - WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name)); + WL_TRACE("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name); mlme = (struct iw_mlme *)extra; if (mlme == NULL) { - WL_ERROR(("Invalid ioctl data.\n")); + WL_ERROR("Invalid ioctl data\n"); return error; } @@ -854,7 +853,7 @@ wl_iw_mlme(struct net_device *dev, dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scb_val_t)); } else { - WL_ERROR(("Invalid ioctl data.\n")); + WL_ERROR("Invalid ioctl data\n"); return error; } @@ -875,7 +874,7 @@ wl_iw_get_aplist(struct net_device *dev, int error, i; uint buflen = dwrq->length; - WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); + WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name); if (!extra) return -EINVAL; @@ -887,7 +886,7 @@ wl_iw_get_aplist(struct net_device *dev, list->buflen = htod32(buflen); error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen); if (error) { - WL_ERROR(("%d: Scan results error %d\n", __LINE__, error)); + WL_ERROR("%d: Scan results error %d\n", __LINE__, error); kfree(list); return error; } @@ -895,8 +894,8 @@ wl_iw_get_aplist(struct net_device *dev, list->version = dtoh32(list->version); list->count = dtoh32(list->count); if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", - __func__, list->version)); + WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __func__, list->version); kfree(list); return -EINVAL; } @@ -953,13 +952,13 @@ wl_iw_iscan_get_aplist(struct net_device *dev, wl_bss_info_t *bi = NULL; int i; - WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); + WL_TRACE("%s: SIOCGIWAPLIST\n", dev->name); if (!extra) return -EINVAL; if ((!iscan) || (!iscan->sysioc_tsk)) { - WL_ERROR(("%s error\n", __func__)); + WL_ERROR("%s error\n", __func__); return 0; } @@ -967,9 +966,8 @@ wl_iw_iscan_get_aplist(struct net_device *dev, while (buf) { list = &((wl_iscan_results_t *) buf->iscan_buf)->results; if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != " - "WL_BSS_INFO_VERSION\n", - __func__, list->version)); + WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __func__, list->version); return -EINVAL; } @@ -1044,15 +1042,15 @@ static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, u16 action) iscan->iscan_ex_params_p->action = htod16(action); iscan->iscan_ex_params_p->scan_duration = htod16(0); - WL_SCAN(("%s : nprobes=%d\n", __func__, - iscan->iscan_ex_params_p->params.nprobes)); - WL_SCAN(("active_time=%d\n", - iscan->iscan_ex_params_p->params.active_time)); - WL_SCAN(("passive_time=%d\n", - iscan->iscan_ex_params_p->params.passive_time)); - WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time)); - WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type)); - WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type)); + WL_SCAN("%s : nprobes=%d\n", + __func__, iscan->iscan_ex_params_p->params.nprobes); + WL_SCAN("active_time=%d\n", + iscan->iscan_ex_params_p->params.active_time); + WL_SCAN("passive_time=%d\n", + iscan->iscan_ex_params_p->params.passive_time); + WL_SCAN("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time); + WL_SCAN("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type); + WL_SCAN("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type); (void)dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, iscan->iscan_ex_param_size, iscan->ioctlbuf, @@ -1067,7 +1065,7 @@ static void wl_iw_timerfunc(unsigned long data) if (iscan) { iscan->timer_on = 0; if (iscan->iscan_state != ISCAN_STATE_IDLE) { - WL_TRACE(("timer trigger\n")); + WL_TRACE("timer trigger\n"); up(&iscan->sysioc_sem); } } @@ -1102,8 +1100,8 @@ static u32 wl_iw_iscan_get(iscan_info_t *iscan) } else { buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL); if (!buf) { - WL_ERROR(("%s can't alloc iscan_buf_t : going to abort " - "currect iscan\n", __func__)); + WL_ERROR("%s can't alloc iscan_buf_t : going to abort current iscan\n", + __func__); MUTEX_UNLOCK_WL_SCAN_SET(); return WL_SCAN_RESULTS_NO_MEM; } @@ -1136,11 +1134,11 @@ static u32 wl_iw_iscan_get(iscan_info_t *iscan) results->buflen = dtoh32(results->buflen); results->version = dtoh32(results->version); results->count = dtoh32(results->count); - WL_TRACE(("results->count = %d\n", results->count)); - WL_TRACE(("results->buflen = %d\n", results->buflen)); + WL_TRACE("results->count = %d\n", results->count); + WL_TRACE("results->buflen = %d\n", results->buflen); status = dtoh32(list_buf->status); } else { - WL_ERROR(("%s returns error %d\n", __func__, res)); + WL_ERROR("%s returns error %d\n", __func__, res); status = WL_SCAN_RESULTS_NO_MEM; } MUTEX_UNLOCK_WL_SCAN_SET(); @@ -1149,8 +1147,8 @@ static u32 wl_iw_iscan_get(iscan_info_t *iscan) static void wl_iw_force_specific_scan(iscan_info_t *iscan) { - WL_TRACE(("%s force Specific SCAN for %s\n", __func__, - g_specific_ssid.SSID)); + WL_TRACE("%s force Specific SCAN for %s\n", + __func__, g_specific_ssid.SSID); rtnl_lock(); (void)dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, @@ -1167,7 +1165,7 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan) memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); - WL_TRACE(("Send Event ISCAN complete\n")); + WL_TRACE("Send Event ISCAN complete\n"); #endif } @@ -1191,8 +1189,8 @@ static int _iscan_sysioc_thread(void *data) status = wl_iw_iscan_get(iscan); rtnl_unlock(); if (g_scan_specified_ssid && (iscan_pass_abort == true)) { - WL_TRACE(("%s Get results from specific scan " - "status = %d\n", __func__, status)); + WL_TRACE("%s Get results from specific scan status = %d\n", + __func__, status); wl_iw_send_scan_complete(iscan); iscan_pass_abort = false; status = -1; @@ -1200,7 +1198,7 @@ static int _iscan_sysioc_thread(void *data) switch (status) { case WL_SCAN_RESULTS_PARTIAL: - WL_TRACE(("iscanresults incomplete\n")); + WL_TRACE("iscanresults incomplete\n"); rtnl_lock(); wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); rtnl_unlock(); @@ -1209,18 +1207,18 @@ static int _iscan_sysioc_thread(void *data) iscan->timer_on = 1; break; case WL_SCAN_RESULTS_SUCCESS: - WL_TRACE(("iscanresults complete\n")); + WL_TRACE("iscanresults complete\n"); iscan->iscan_state = ISCAN_STATE_IDLE; wl_iw_send_scan_complete(iscan); break; case WL_SCAN_RESULTS_PENDING: - WL_TRACE(("iscanresults pending\n")); + WL_TRACE("iscanresults pending\n"); mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); iscan->timer_on = 1; break; case WL_SCAN_RESULTS_ABORTED: - WL_TRACE(("iscanresults aborted\n")); + WL_TRACE("iscanresults aborted\n"); iscan->iscan_state = ISCAN_STATE_IDLE; if (g_scan_specified_ssid == 0) wl_iw_send_scan_complete(iscan); @@ -1230,12 +1228,12 @@ static int _iscan_sysioc_thread(void *data) } break; case WL_SCAN_RESULTS_NO_MEM: - WL_TRACE(("iscanresults can't alloc memory: skip\n")); + WL_TRACE("iscanresults can't alloc memory: skip\n"); iscan->iscan_state = ISCAN_STATE_IDLE; break; default: - WL_TRACE(("iscanresults returned unknown status %d\n", - status)); + WL_TRACE("iscanresults returned unknown status %d\n", + status); break; } } @@ -1254,11 +1252,11 @@ wl_iw_set_scan(struct net_device *dev, union iwreq_data *wrqu, char *extra) { int error; - WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name)); + WL_TRACE("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __func__, dev->name); g_set_essid_before_scan = false; #if defined(CSCAN) - WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__)); + WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__); return -EINVAL; #endif @@ -1275,9 +1273,8 @@ wl_iw_set_scan(struct net_device *dev, if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { struct iw_scan_req *req = (struct iw_scan_req *)extra; if (g_scan_specified_ssid) { - WL_TRACE(("%s Specific SCAN is not done ignore " - "scan for = %s\n", - __func__, req->essid)); + WL_TRACE("%s Specific SCAN is not done ignore scan for = %s\n", + __func__, req->essid); return -EBUSY; } else { g_specific_ssid.SSID_len = min_t(size_t, @@ -1288,9 +1285,9 @@ wl_iw_set_scan(struct net_device *dev, g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len); g_scan_specified_ssid = 1; - WL_TRACE(("### Specific scan ssid=%s len=%d\n", - g_specific_ssid.SSID, - g_specific_ssid.SSID_len)); + WL_TRACE("### Specific scan ssid=%s len=%d\n", + g_specific_ssid.SSID, + g_specific_ssid.SSID_len); } } } @@ -1298,8 +1295,8 @@ wl_iw_set_scan(struct net_device *dev, error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)); if (error) { - WL_TRACE(("#### Set SCAN for %s failed with %d\n", - g_specific_ssid.SSID, error)); + WL_TRACE("#### Set SCAN for %s failed with %d\n", + g_specific_ssid.SSID, error); g_scan_specified_ssid = 0; return -EBUSY; } @@ -1318,7 +1315,7 @@ int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) wl_iw_set_event_mask(dev); - WL_TRACE(("+++: Set Broadcast ISCAN\n")); + WL_TRACE("+++: Set Broadcast ISCAN\n"); memset(&ssid, 0, sizeof(ssid)); iscan->list_cur = iscan->list_hdr; @@ -1347,20 +1344,20 @@ wl_iw_iscan_set_scan(struct net_device *dev, wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; - WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name)); + WL_TRACE("%s: SIOCSIWSCAN : ISCAN\n", dev->name); #if defined(CSCAN) - WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __func__)); + WL_ERROR("%s: Scan from SIOCGIWSCAN not supported\n", __func__); return -EINVAL; #endif if (g_onoff == G_WLAN_SET_OFF) { - WL_TRACE(("%s: driver is not up yet after START\n", __func__)); + WL_TRACE("%s: driver is not up yet after START\n", __func__); return 0; } #ifdef PNO_SUPPORT if (dhd_dev_get_pno_status(dev)) { - WL_ERROR(("%s: Scan called when PNO is active\n", __func__)); + WL_ERROR("%s: Scan called when PNO is active\n", __func__); } #endif @@ -1368,8 +1365,8 @@ wl_iw_iscan_set_scan(struct net_device *dev, return wl_iw_set_scan(dev, info, wrqu, extra); if (g_scan_specified_ssid) { - WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", - __func__)); + WL_TRACE("%s Specific SCAN already running ignoring BC scan\n", + __func__); return EBUSY; } @@ -1387,8 +1384,8 @@ wl_iw_iscan_set_scan(struct net_device *dev, g_scan_specified_ssid = 0; if (iscan->iscan_state == ISCAN_STATE_SCANING) { - WL_TRACE(("%s ISCAN already in progress \n", - __func__)); + WL_TRACE("%s ISCAN already in progress\n", + __func__); return 0; } } @@ -1502,9 +1499,8 @@ wl_iw_get_scan_prep(wl_scan_results_t *list, for (i = 0; i < list->count && i < IW_MAX_AP; i++) { if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != " - "WL_BSS_INFO_VERSION\n", - __func__, list->version)); + WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __func__, list->version); return ret; } @@ -1512,7 +1508,7 @@ wl_iw_get_scan_prep(wl_scan_results_t *list, dtoh32(bi->length)) : list-> bss_info; - WL_TRACE(("%s : %s\n", __func__, bi->SSID)); + WL_TRACE("%s : %s\n", __func__, bi->SSID); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; @@ -1591,11 +1587,11 @@ wl_iw_get_scan_prep(wl_scan_results_t *list, ret = event - extra; if (ret < 0) { - WL_ERROR(("==> Wrong size\n")); + WL_ERROR("==> Wrong size\n"); ret = 0; } - WL_TRACE(("%s: size=%d bytes prepared\n", __func__, - (unsigned int)(event - extra))); + WL_TRACE("%s: size=%d bytes prepared\n", + __func__, (unsigned int)(event - extra)); return (uint)ret; } @@ -1615,10 +1611,10 @@ wl_iw_get_scan(struct net_device *dev, iscan_buf_t *p_buf; #endif - WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user)); + WL_TRACE("%s: buflen_from_user %d:\n", dev->name, buflen_from_user); if (!extra) { - WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name)); + WL_TRACE("%s: wl_iw_get_scan return -EINVAL\n", dev->name); return -EINVAL; } @@ -1632,8 +1628,8 @@ wl_iw_get_scan(struct net_device *dev, if (g_scan_specified_ssid) { list = kmalloc(len, GFP_KERNEL); if (!list) { - WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", - dev->name)); + WL_TRACE("%s: wl_iw_get_scan return -ENOMEM\n", + dev->name); g_scan_specified_ssid = 0; return -ENOMEM; } @@ -1643,8 +1639,8 @@ wl_iw_get_scan(struct net_device *dev, list->buflen = htod32(len); error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len); if (error) { - WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, - __func__, error)); + WL_ERROR("%s: %s : Scan_results ERROR %d\n", + dev->name, __func__, error); dwrq->length = len; if (g_scan_specified_ssid) { g_scan_specified_ssid = 0; @@ -1657,8 +1653,8 @@ wl_iw_get_scan(struct net_device *dev, list->count = dtoh32(list->count); if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", - __func__, list->version)); + WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __func__, list->version); if (g_scan_specified_ssid) { g_scan_specified_ssid = 0; kfree(list); @@ -1667,8 +1663,8 @@ wl_iw_get_scan(struct net_device *dev, } if (g_scan_specified_ssid) { - WL_TRACE(("%s: Specified scan APs in the list =%d\n", - __func__, list->count)); + WL_TRACE("%s: Specified scan APs in the list =%d\n", + __func__, list->count); len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user); @@ -1679,8 +1675,8 @@ wl_iw_get_scan(struct net_device *dev, while (p_buf != iscan->list_cur) { list_merge = &((wl_iscan_results_t *) p_buf->iscan_buf)->results; - WL_TRACE(("%s: Bcast APs list=%d\n", __func__, - list_merge->count)); + WL_TRACE("%s: Bcast APs list=%d\n", + __func__, list_merge->count); if (list_merge->count > 0) len_ret += (__u16) wl_iw_get_scan_prep(list_merge, @@ -1690,8 +1686,8 @@ wl_iw_get_scan(struct net_device *dev, } #else list_merge = (wl_scan_results_t *) g_scan; - WL_TRACE(("%s: Bcast APs list=%d\n", __func__, - list_merge->count)); + WL_TRACE("%s: Bcast APs list=%d\n", + __func__, list_merge->count); if (list_merge->count > 0) len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, @@ -1715,8 +1711,8 @@ wl_iw_get_scan(struct net_device *dev, dwrq->length = len; dwrq->flags = 0; - WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__, - dwrq->length, list->count)); + WL_TRACE("%s return to WE %d bytes APs=%d\n", + __func__, dwrq->length, list->count); return 0; } @@ -1737,26 +1733,26 @@ wl_iw_iscan_get_scan(struct net_device *dev, u32 counter = 0; u8 channel; - WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __func__, - dwrq->length)); + WL_TRACE("%s %s buflen_from_user %d:\n", + dev->name, __func__, dwrq->length); if (!extra) { - WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", - dev->name)); + WL_TRACE("%s: INVALID SIOCGIWSCAN GET bad parameter\n", + dev->name); return -EINVAL; } if ((!iscan) || (!iscan->sysioc_tsk)) { - WL_ERROR(("%ssysioc_tsk\n", __func__)); + WL_ERROR("%ssysioc_tsk\n", __func__); return wl_iw_get_scan(dev, info, dwrq, extra); } if (iscan->iscan_state == ISCAN_STATE_SCANING) { - WL_TRACE(("%s: SIOCGIWSCAN GET still scanning\n", dev->name)); + WL_TRACE("%s: SIOCGIWSCAN GET still scanning\n", dev->name); return -EAGAIN; } - WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name)); + WL_TRACE("%s: SIOCGIWSCAN GET broadcast results\n", dev->name); apcnt = 0; p_buf = iscan->list_hdr; while (p_buf != iscan->list_cur) { @@ -1765,9 +1761,8 @@ wl_iw_iscan_get_scan(struct net_device *dev, counter += list->count; if (list->version != WL_BSS_INFO_VERSION) { - WL_ERROR(("%s : list->version %d != " - "WL_BSS_INFO_VERSION\n", - __func__, list->version)); + WL_ERROR("%s : list->version %d != WL_BSS_INFO_VERSION\n", + __func__, list->version); return -EINVAL; } @@ -1877,8 +1872,8 @@ wl_iw_iscan_get_scan(struct net_device *dev, dwrq->length = event - extra; dwrq->flags = 0; - WL_TRACE(("%s return to WE %d bytes APs=%d\n", __func__, - dwrq->length, counter)); + WL_TRACE("%s return to WE %d bytes APs=%d\n", + __func__, dwrq->length, counter); if (!dwrq->length) return -EAGAIN; @@ -1896,7 +1891,7 @@ wl_iw_set_essid(struct net_device *dev, wl_join_params_t join_params; int join_params_size; - WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); + WL_TRACE("%s: SIOCSIWESSID\n", dev->name); if (g_set_essid_before_scan) return -EAGAIN; @@ -1932,11 +1927,11 @@ wl_iw_set_essid(struct net_device *dev, error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); if (error) - WL_ERROR(("Invalid ioctl data=%d\n", error)); + WL_ERROR("Invalid ioctl data=%d\n", error); if (g_ssid.SSID_len) { - WL_TRACE(("%s: join SSID=%s ch=%d\n", __func__, - g_ssid.SSID, g_wl_iw_params.target_channel)); + WL_TRACE("%s: join SSID=%s ch=%d\n", + __func__, g_ssid.SSID, g_wl_iw_params.target_channel); } return 0; } @@ -1949,14 +1944,14 @@ wl_iw_get_essid(struct net_device *dev, wlc_ssid_t ssid; int error; - WL_TRACE(("%s: SIOCGIWESSID\n", dev->name)); + WL_TRACE("%s: SIOCGIWESSID\n", dev->name); if (!extra) return -EINVAL; error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)); if (error) { - WL_ERROR(("Error getting the SSID\n")); + WL_ERROR("Error getting the SSID\n"); return error; } @@ -1977,7 +1972,7 @@ wl_iw_set_nick(struct net_device *dev, { wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev); - WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); + WL_TRACE("%s: SIOCSIWNICKN\n", dev->name); if (!extra) return -EINVAL; @@ -1997,7 +1992,7 @@ wl_iw_get_nick(struct net_device *dev, { wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev); - WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); + WL_TRACE("%s: SIOCGIWNICKN\n", dev->name); if (!extra) return -EINVAL; @@ -2015,7 +2010,7 @@ wl_iw_set_rate(struct net_device *dev, wl_rateset_t rateset; int error, rate, i, error_bg, error_a; - WL_TRACE(("%s: SIOCSIWRATE\n", dev->name)); + WL_TRACE("%s: SIOCSIWRATE\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)); @@ -2064,7 +2059,7 @@ wl_iw_get_rate(struct net_device *dev, { int error, rate; - WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); + WL_TRACE("%s: SIOCGIWRATE\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)); if (error) @@ -2081,7 +2076,7 @@ wl_iw_set_rts(struct net_device *dev, { int error, rts; - WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); + WL_TRACE("%s: SIOCSIWRTS\n", dev->name); if (vwrq->disabled) rts = DOT11_DEFAULT_RTS_LEN; @@ -2103,7 +2098,7 @@ wl_iw_get_rts(struct net_device *dev, { int error, rts; - WL_TRACE(("%s: SIOCGIWRTS\n", dev->name)); + WL_TRACE("%s: SIOCGIWRTS\n", dev->name); error = dev_wlc_intvar_get(dev, "rtsthresh", &rts); if (error) @@ -2122,7 +2117,7 @@ wl_iw_set_frag(struct net_device *dev, { int error, frag; - WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name)); + WL_TRACE("%s: SIOCSIWFRAG\n", dev->name); if (vwrq->disabled) frag = DOT11_DEFAULT_FRAG_LEN; @@ -2144,7 +2139,7 @@ wl_iw_get_frag(struct net_device *dev, { int error, fragthreshold; - WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name)); + WL_TRACE("%s: SIOCGIWFRAG\n", dev->name); error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold); if (error) @@ -2164,7 +2159,7 @@ wl_iw_set_txpow(struct net_device *dev, { int error, disable; u16 txpwrmw; - WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); + WL_TRACE("%s: SIOCSIWTXPOW\n", dev->name); disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; disable += WL_RADIO_SW_DISABLE << 16; @@ -2201,7 +2196,7 @@ wl_iw_get_txpow(struct net_device *dev, int error, disable, txpwrdbm; u8 result; - WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name)); + WL_TRACE("%s: SIOCGIWTXPOW\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable)); if (error) @@ -2230,7 +2225,7 @@ wl_iw_set_retry(struct net_device *dev, { int error, lrl, srl; - WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); + WL_TRACE("%s: SIOCSIWRETRY\n", dev->name); if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) return -EINVAL; @@ -2278,7 +2273,7 @@ wl_iw_get_retry(struct net_device *dev, { int error, lrl, srl; - WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); + WL_TRACE("%s: SIOCGIWRETRY\n", dev->name); vwrq->disabled = 0; @@ -2318,7 +2313,7 @@ wl_iw_set_encode(struct net_device *dev, wl_wsec_key_t key; int error, val, wsec; - WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name)); + WL_TRACE("%s: SIOCSIWENCODE\n", dev->name); memset(&key, 0, sizeof(key)); @@ -2410,7 +2405,7 @@ wl_iw_get_encode(struct net_device *dev, wl_wsec_key_t key; int error, val, wsec, auth; - WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name)); + WL_TRACE("%s: SIOCGIWENCODE\n", dev->name); memset(&key, 0, sizeof(wl_wsec_key_t)); @@ -2466,7 +2461,7 @@ wl_iw_set_power(struct net_device *dev, { int error, pm; - WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name)); + WL_TRACE("%s: SIOCSIWPOWER\n", dev->name); pm = vwrq->disabled ? PM_OFF : PM_MAX; @@ -2485,7 +2480,7 @@ wl_iw_get_power(struct net_device *dev, { int error, pm; - WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name)); + WL_TRACE("%s: SIOCGIWPOWER\n", dev->name); error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)); if (error) @@ -2504,7 +2499,7 @@ wl_iw_set_wpaie(struct net_device *dev, struct iw_request_info *info, struct iw_point *iwp, char *extra) { - WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name)); + WL_TRACE("%s: SIOCSIWGENIE\n", dev->name); CHECK_EXTRA_FOR_NULL(extra); @@ -2517,7 +2512,7 @@ static int wl_iw_get_wpaie(struct net_device *dev, struct iw_request_info *info, struct iw_point *iwp, char *extra) { - WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name)); + WL_TRACE("%s: SIOCGIWGENIE\n", dev->name); iwp->length = 64; dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); return 0; @@ -2532,7 +2527,7 @@ wl_iw_set_encodeext(struct net_device *dev, int error; struct iw_encode_ext *iwe; - WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); + WL_TRACE("%s: SIOCSIWENCODEEXT\n", dev->name); CHECK_EXTRA_FOR_NULL(extra); @@ -2555,8 +2550,8 @@ wl_iw_set_encodeext(struct net_device *dev, if (key.len == 0) { if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - WL_WSEC(("Changing the the primary Key to %d\n", - key.index)); + WL_WSEC("Changing the the primary Key to %d\n", + key.index); key.index = htod32(key.index); error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &key.index, sizeof(key.index)); @@ -2570,9 +2565,9 @@ wl_iw_set_encodeext(struct net_device *dev, if (iwe->key_len > sizeof(key.data)) return -EINVAL; - WL_WSEC(("Setting the key index %d\n", key.index)); + WL_WSEC("Setting the key index %d\n", key.index); if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - WL_WSEC(("key is a Primary Key\n")); + WL_WSEC("key is a Primary Key\n"); key.flags = WL_PRIMARY_KEY; } @@ -2639,14 +2634,14 @@ wl_iw_set_pmksa(struct net_device *dev, uint i; int ret = 0; - WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name)); + WL_WSEC("%s: SIOCSIWPMKSA\n", dev->name); CHECK_EXTRA_FOR_NULL(extra); iwpmksa = (struct iw_pmksa *)extra; if (iwpmksa->cmd == IW_PMKSA_FLUSH) { - WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); + WL_WSEC("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"); memset((char *)&pmkid_list, 0, sizeof(pmkid_list)); } @@ -2661,11 +2656,11 @@ wl_iw_set_pmksa(struct net_device *dev, bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); - WL_WSEC(("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: " - "%pM = ", &pmkidptr->pmkid[0].BSSID)); + WL_WSEC("wl_iw_set_pmksa:IW_PMKSA_REMOVE:PMKID: %pM = ", + &pmkidptr->pmkid[0].BSSID); for (j = 0; j < WPA2_PMKID_LEN; j++) - WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j])); - WL_WSEC(("\n")); + WL_WSEC("%02x ", pmkidptr->pmkid[0].PMKID[j]); + WL_WSEC("\n"); } for (i = 0; i < pmkid_list.pmkids.npmkid; i++) @@ -2711,25 +2706,25 @@ wl_iw_set_pmksa(struct net_device *dev, uint j; uint k; k = pmkid_list.pmkids.npmkid; - WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ", - &pmkid_list.pmkids.pmkid[k].BSSID)); + WL_WSEC("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %pM = ", + &pmkid_list.pmkids.pmkid[k].BSSID); for (j = 0; j < WPA2_PMKID_LEN; j++) - WL_WSEC(("%02x ", - pmkid_list.pmkids.pmkid[k].PMKID[j])); - WL_WSEC(("\n")); + WL_WSEC("%02x ", + pmkid_list.pmkids.pmkid[k].PMKID[j]); + WL_WSEC("\n"); } } - WL_WSEC(("PRINTING pmkid LIST - No of elements %d\n", - pmkid_list.pmkids.npmkid)); + WL_WSEC("PRINTING pmkid LIST - No of elements %d\n", + pmkid_list.pmkids.npmkid); for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { uint j; - WL_WSEC(("PMKID[%d]: %pM = ", i, - &pmkid_list.pmkids.pmkid[i].BSSID)); + WL_WSEC("PMKID[%d]: %pM = ", + i, &pmkid_list.pmkids.pmkid[i].BSSID); for (j = 0; j < WPA2_PMKID_LEN; j++) - WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j])); - WL_WSEC(("\n")); + WL_WSEC("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]); + WL_WSEC("\n"); } - WL_WSEC(("\n")); + WL_WSEC("\n"); if (!ret) ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, @@ -2743,7 +2738,7 @@ wl_iw_get_encodeext(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name)); + WL_TRACE("%s: SIOCGIWENCODEEXT\n", dev->name); return 0; } @@ -2758,13 +2753,13 @@ wl_iw_set_wpaauth(struct net_device *dev, int val = 0; wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev); - WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); + WL_TRACE("%s: SIOCSIWAUTH\n", dev->name); paramid = vwrq->flags & IW_AUTH_INDEX; paramval = vwrq->value; - WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", - dev->name, paramid, paramval)); + WL_TRACE("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", + dev->name, paramid, paramval); switch (paramid) { case IW_AUTH_WPA_VERSION: @@ -2774,8 +2769,8 @@ wl_iw_set_wpaauth(struct net_device *dev, val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; else if (paramval & IW_AUTH_WPA_VERSION_WPA2) val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; - WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __func__, - __LINE__, val)); + WL_INFORM("%s: %d: setting wpa_auth to 0x%0x\n", + __func__, __LINE__, val); error = dev_wlc_intvar_set(dev, "wpa_auth", val); if (error) return error; @@ -2798,20 +2793,19 @@ wl_iw_set_wpaauth(struct net_device *dev, } if (iw->privacy_invoked && !val) { - WL_WSEC(("%s: %s: 'Privacy invoked' true but clearing " - "wsec, assuming " "we're a WPS enrollee\n", - dev->name, __func__)); + WL_WSEC("%s: %s: 'Privacy invoked' true but clearing wsec, assuming we're a WPS enrollee\n", + dev->name, __func__); error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", true); if (error) { - WL_WSEC(("Failed to set is_WPS_enrollee\n")); + WL_WSEC("Failed to set is_WPS_enrollee\n"); return error; } } else if (val) { error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", false); if (error) { - WL_WSEC(("Failed to clear is_WPS_enrollee\n")); + WL_WSEC("Failed to clear is_WPS_enrollee\n"); return error; } } @@ -2838,8 +2832,8 @@ wl_iw_set_wpaauth(struct net_device *dev, else val = WPA2_AUTH_UNSPECIFIED; } - WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __func__, - __LINE__, val)); + WL_INFORM("%s: %d: setting wpa_auth to %d\n", + __func__, __LINE__, val); error = dev_wlc_intvar_set(dev, "wpa_auth", val); if (error) return error; @@ -2851,7 +2845,7 @@ wl_iw_set_wpaauth(struct net_device *dev, break; case IW_AUTH_80211_AUTH_ALG: - WL_INFORM(("Setting the D11auth %d\n", paramval)); + WL_INFORM("Setting the D11auth %d\n", paramval); if (paramval == IW_AUTH_ALG_OPEN_SYSTEM) val = 0; else if (paramval == IW_AUTH_ALG_SHARED_KEY) @@ -2880,8 +2874,8 @@ wl_iw_set_wpaauth(struct net_device *dev, dev_wlc_intvar_set(dev, "wsec", val); } val = 0; - WL_INFORM(("%s: %d: setting wpa_auth to %d\n", - __func__, __LINE__, val)); + WL_INFORM("%s: %d: setting wpa_auth to %d\n", + __func__, __LINE__, val); dev_wlc_intvar_set(dev, "wpa_auth", 0); return error; } @@ -2898,7 +2892,7 @@ wl_iw_set_wpaauth(struct net_device *dev, #if WIRELESS_EXT > 17 case IW_AUTH_ROAMING_CONTROL: - WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__)); + WL_INFORM("%s: IW_AUTH_ROAMING_CONTROL\n", __func__); break; case IW_AUTH_PRIVACY_INVOKED: { @@ -2909,8 +2903,7 @@ wl_iw_set_wpaauth(struct net_device *dev, error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", false); if (error) { - WL_WSEC(("Failed to clear iovar " - "is_WPS_enrollee\n")); + WL_WSEC("Failed to clear iovar is_WPS_enrollee\n"); return error; } } else { @@ -2924,8 +2917,7 @@ wl_iw_set_wpaauth(struct net_device *dev, "is_WPS_enrollee", true); if (error) { - WL_WSEC(("Failed to set iovar " - "is_WPS_enrollee\n")); + WL_WSEC("Failed to set iovar is_WPS_enrollee\n"); return error; } } else { @@ -2933,8 +2925,7 @@ wl_iw_set_wpaauth(struct net_device *dev, "is_WPS_enrollee", false); if (error) { - WL_WSEC(("Failed to clear " - "is_WPS_enrollee\n")); + WL_WSEC("Failed to clear is_WPS_enrollee\n"); return error; } } @@ -2961,7 +2952,7 @@ wl_iw_get_wpaauth(struct net_device *dev, int val; wl_iw_t *iw = *(wl_iw_t **) netdev_priv(dev); - WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name)); + WL_TRACE("%s: SIOCGIWAUTH\n", dev->name); paramid = vwrq->flags & IW_AUTH_INDEX; @@ -3041,7 +3032,7 @@ wl_iw_get_wpaauth(struct net_device *dev, break; #if WIRELESS_EXT > 17 case IW_AUTH_ROAMING_CONTROL: - WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __func__)); + WL_ERROR("%s: IW_AUTH_ROAMING_CONTROL\n", __func__); break; case IW_AUTH_PRIVACY_INVOKED: paramval = iw->privacy_invoked; @@ -3158,19 +3149,19 @@ int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) char *extra = NULL; int token_size = 1, max_tokens = 0, ret = 0; - WL_TRACE(("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n", - __func__, cmd)); + WL_TRACE("\n%s, cmd:%x alled via dhd->do_ioctl()entry point\n", + __func__, cmd); if (cmd < SIOCIWFIRST || IW_IOCTL_IDX(cmd) >= ARRAY_SIZE(wl_iw_handler)) { - WL_ERROR(("%s: error in cmd=%x : out of range\n", __func__, - cmd)); + WL_ERROR("%s: error in cmd=%x : out of range\n", + __func__, cmd); return -EOPNOTSUPP; } handler = wl_iw_handler[IW_IOCTL_IDX(cmd)]; if (!handler) { - WL_ERROR(("%s: error in cmd=%x : not supported\n", - __func__, cmd)); + WL_ERROR("%s: error in cmd=%x : not supported\n", + __func__, cmd); return -EOPNOTSUPP; } @@ -3235,9 +3226,8 @@ int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (max_tokens && wrq->u.data.pointer) { if (wrq->u.data.length > max_tokens) { - WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d " - "> max_tokens=%d\n", - __func__, cmd, wrq->u.data.length, max_tokens)); + WL_ERROR("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n", + __func__, cmd, wrq->u.data.length, max_tokens); return -E2BIG; } extra = kmalloc(max_tokens * token_size, GFP_KERNEL); @@ -3340,7 +3330,7 @@ wl_iw_conn_status_str(u32 event_type, u32 status, u32 reason, memset(stringBuf, 0, buflen); snprintf(stringBuf, buflen, "%s %s %02d %02d", name, cause, status, reason); - WL_INFORM(("Connection status: %s\n", stringBuf)); + WL_INFORM("Connection status: %s\n", stringBuf); return true; } else { return false; @@ -3384,13 +3374,13 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) iw = 0; if (!dev) { - WL_ERROR(("%s: dev is null\n", __func__)); + WL_ERROR("%s: dev is null\n", __func__); return; } iw = *(wl_iw_t **) netdev_priv(dev); - WL_TRACE(("%s: dev=%s event=%d\n", __func__, dev->name, event_type)); + WL_TRACE("%s: dev=%s event=%d\n", __func__, dev->name, event_type); switch (event_type) { case WLC_E_TXFAIL: @@ -3423,7 +3413,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) 20 * HZ); } else { memcpy(wrqu.addr.sa_data, &e->addr, ETH_ALEN); - WL_TRACE(("Link UP\n")); + WL_TRACE("Link UP\n"); } wrqu.addr.sa_family = ARPHRD_ETHER; @@ -3434,8 +3424,8 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) wrqu.data.length = datalen + 1; extra[0] = WLC_E_ACTION_FRAME; memcpy(&extra[1], data, datalen); - WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", - wrqu.data.length)); + WL_TRACE("WLC_E_ACTION_FRAME len %d\n", + wrqu.data.length); } break; @@ -3516,13 +3506,13 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) } else { cmd = SIOCGIWSCAN; wrqu.data.length = strlen(extra); - WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific " - "scan %d\n", g_iscan->iscan_state)); + WL_TRACE("Event WLC_E_SCAN_COMPLETE from specific scan %d\n", + g_iscan->iscan_state); } #else cmd = SIOCGIWSCAN; wrqu.data.length = strlen(extra); - WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n")); + WL_TRACE("Event WLC_E_SCAN_COMPLETE\n"); #endif break; @@ -3530,9 +3520,9 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) { wlc_ssid_t *ssid; ssid = (wlc_ssid_t *) data; - WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : " - "find %s len=%d\n", __func__, PNO_EVENT_UP, - ssid->SSID, ssid->SSID_len)); + WL_ERROR("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", + __func__, PNO_EVENT_UP, + ssid->SSID, ssid->SSID_len); WAKE_LOCK_TIMEOUT(iw->pub, WAKE_LOCK_PNO_FIND_TMOUT, 20 * HZ); cmd = IWEVCUSTOM; @@ -3543,7 +3533,7 @@ void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data) break; default: - WL_TRACE(("Unknown Event %d: ignoring\n", event_type)); + WL_TRACE("Unknown Event %d: ignoring\n", event_type); break; } #ifndef SANDGATE2G @@ -3584,7 +3574,7 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) goto done; phy_noise = dtoh32(phy_noise); - WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise)); + WL_TRACE("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise); memset(&scb_val, 0, sizeof(scb_val_t)); res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)); @@ -3592,7 +3582,7 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) goto done; rssi = dtoh32(scb_val.val); - WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi)); + WL_TRACE("wl_iw_get_wireless_stats rssi=%d\n", rssi); if (rssi <= WL_IW_RSSI_NO_SIGNAL) wstats->qual.qual = 0; else if (rssi <= WL_IW_RSSI_VERY_LOW) @@ -3615,23 +3605,21 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) #endif #if WIRELESS_EXT > 11 - WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", - (int)sizeof(wl_cnt_t))); + WL_TRACE("wl_iw_get_wireless_stats counters=%zu\n", sizeof(wl_cnt_t)); memset(&cnt, 0, sizeof(wl_cnt_t)); res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); if (res) { - WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", - res)); + WL_ERROR("wl_iw_get_wireless_stats counters failed error=%d\n", + res); goto done; } cnt.version = dtoh16(cnt.version); if (cnt.version != WL_CNT_T_VERSION) { - WL_TRACE(("\tIncorrect version of counters struct: expected " - "%d; got %d\n", - WL_CNT_T_VERSION, cnt.version)); + WL_TRACE("\tIncorrect version of counters struct: expected %d; got %d\n", + WL_CNT_T_VERSION, cnt.version); goto done; } @@ -3642,22 +3630,22 @@ wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant); wstats->miss.beacon = 0; - WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", - dtoh32(cnt.txframe), dtoh32(cnt.txbyte))); - WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", - dtoh32(cnt.rxfrmtoolong))); - WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", - dtoh32(cnt.rxbadplcp))); - WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", - dtoh32(cnt.rxundec))); - WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", - dtoh32(cnt.rxfragerr))); - WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", - dtoh32(cnt.txfail))); - WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", - dtoh32(cnt.rxrunt))); - WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", - dtoh32(cnt.rxgiant))); + WL_TRACE("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", + dtoh32(cnt.txframe), dtoh32(cnt.txbyte)); + WL_TRACE("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", + dtoh32(cnt.rxfrmtoolong)); + WL_TRACE("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", + dtoh32(cnt.rxbadplcp)); + WL_TRACE("wl_iw_get_wireless_stats counters rxundec=%d\n", + dtoh32(cnt.rxundec)); + WL_TRACE("wl_iw_get_wireless_stats counters rxfragerr=%d\n", + dtoh32(cnt.rxfragerr)); + WL_TRACE("wl_iw_get_wireless_stats counters txfail=%d\n", + dtoh32(cnt.txfail)); + WL_TRACE("wl_iw_get_wireless_stats counters rxrunt=%d\n", + dtoh32(cnt.rxrunt)); + WL_TRACE("wl_iw_get_wireless_stats counters rxgiant=%d\n", + dtoh32(cnt.rxgiant)); #endif /* WIRELESS_EXT > 11 */ done: diff --git a/drivers/staging/brcm80211/brcmfmac/wl_iw.h b/drivers/staging/brcm80211/brcmfmac/wl_iw.h index edbf61f30b47..c8637c50dc17 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_iw.h +++ b/drivers/staging/brcm80211/brcmfmac/wl_iw.h @@ -78,7 +78,7 @@ typedef struct wl_iw_extra_params { #define CHECK_EXTRA_FOR_NULL(extra) \ if (!extra) { \ - WL_ERROR(("%s: error : extra is null pointer\n", __func__)); \ + WL_ERROR("%s: error : extra is null pointer\n", __func__); \ return -EINVAL; \ } diff --git a/drivers/staging/brcm80211/sys/wl_dbg.h b/drivers/staging/brcm80211/sys/wl_dbg.h index e63b27ebad5e..54af257598c2 100644 --- a/drivers/staging/brcm80211/sys/wl_dbg.h +++ b/drivers/staging/brcm80211/sys/wl_dbg.h @@ -20,15 +20,20 @@ /* wl_msg_level is a bit vector with defs in wlioctl.h */ extern u32 wl_msg_level; -#define WL_PRINT(args) printf args -#define WL_NONE(args) +#define WL_NONE(fmt, args...) no_printk(fmt, ##args) + +#define WL_PRINT(level, fmt, args...) \ +do { \ + if (wl_msg_level & level) \ + printk(fmt, ##args); \ +} while (0) #ifdef BCMDBG -#define WL_ERROR(args) do {if ((wl_msg_level & WL_ERROR_VAL)) WL_PRINT(args); } while (0) -#define WL_TRACE(args) do {if (wl_msg_level & WL_TRACE_VAL) WL_PRINT(args); } while (0) -#define WL_AMPDU(args) do {if (wl_msg_level & WL_AMPDU_VAL) WL_PRINT(args); } while (0) -#define WL_FFPLD(args) do {if (wl_msg_level & WL_FFPLD_VAL) WL_PRINT(args); } while (0) +#define WL_ERROR(fmt, args...) WL_PRINT(WL_ERROR_VAL, fmt, ##args) +#define WL_TRACE(fmt, args...) WL_PRINT(WL_TRACE_VAL, fmt, ##args) +#define WL_AMPDU(fmt, args...) WL_PRINT(WL_AMPDU_VAL, fmt, ##args) +#define WL_FFPLD(fmt, args...) WL_PRINT(WL_FFPLD_VAL, fmt, ##args) #define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL) @@ -44,35 +49,50 @@ extern u32 wl_msg_level; extern u32 wl_ampdu_dbg; -#define WL_AMPDU_UPDN(args) do {if (wl_ampdu_dbg & WL_AMPDU_UPDN_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_RX(args) do {if (wl_ampdu_dbg & WL_AMPDU_RX_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_ERR(args) do {if (wl_ampdu_dbg & WL_AMPDU_ERR_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_TX(args) do {if (wl_ampdu_dbg & WL_AMPDU_TX_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_CTL(args) do {if (wl_ampdu_dbg & WL_AMPDU_CTL_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_HW(args) do {if (wl_ampdu_dbg & WL_AMPDU_HW_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_HWTXS(args) do {if (wl_ampdu_dbg & WL_AMPDU_HWTXS_VAL) {WL_AMPDU(args); } } while (0) -#define WL_AMPDU_HWDBG(args) do {if (wl_ampdu_dbg & WL_AMPDU_HWDBG_VAL) {WL_AMPDU(args); } } while (0) +#define WL_AMPDU_PRINT(level, fmt, args...) \ +do { \ + if (wl_ampdu_dbg & level) { \ + WL_AMPDU(fmt, ##args); \ + } \ +} while (0) + +#define WL_AMPDU_UPDN(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_UPDN_VAL, fmt, ##args) +#define WL_AMPDU_RX(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_RX_VAL, fmt, ##args) +#define WL_AMPDU_ERR(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_ERR_VAL, fmt, ##args) +#define WL_AMPDU_TX(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_TX_VAL, fmt, ##args) +#define WL_AMPDU_CTL(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_CTL_VAL, fmt, ##args) +#define WL_AMPDU_HW(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_HW_VAL, fmt, ##args) +#define WL_AMPDU_HWTXS(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_HWTXS_VAL, fmt, ##args) +#define WL_AMPDU_HWDBG(fmt, args...) \ + WL_AMPDU_PRINT(WL_AMPDU_HWDBG_VAL, fmt, ##args) #define WL_AMPDU_ERR_ON() (wl_ampdu_dbg & WL_AMPDU_ERR_VAL) #define WL_AMPDU_HW_ON() (wl_ampdu_dbg & WL_AMPDU_HW_VAL) #define WL_AMPDU_HWTXS_ON() (wl_ampdu_dbg & WL_AMPDU_HWTXS_VAL) #else /* BCMDBG */ -#define WL_ERROR(args) -#define WL_TRACE(args) -#define WL_AMPDU(args) -#define WL_FFPLD(args) +#define WL_ERROR(fmt, args...) no_printk(fmt, ##args) +#define WL_TRACE(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU(fmt, args...) no_printk(fmt, ##args) +#define WL_FFPLD(fmt, args...) no_printk(fmt, ##args) #define WL_ERROR_ON() 0 -#define WL_AMPDU_UPDN(args) -#define WL_AMPDU_RX(args) -#define WL_AMPDU_ERR(args) -#define WL_AMPDU_TX(args) -#define WL_AMPDU_CTL(args) -#define WL_AMPDU_HW(args) -#define WL_AMPDU_HWTXS(args) -#define WL_AMPDU_HWDBG(args) +#define WL_AMPDU_UPDN(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_RX(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_ERR(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_TX(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_CTL(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_HW(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_HWTXS(fmt, args...) no_printk(fmt, ##args) +#define WL_AMPDU_HWDBG(fmt, args...) no_printk(fmt, ##args) #define WL_AMPDU_ERR_ON() 0 #define WL_AMPDU_HW_ON() 0 #define WL_AMPDU_HWTXS_ON() 0 diff --git a/drivers/staging/brcm80211/sys/wl_mac80211.c b/drivers/staging/brcm80211/sys/wl_mac80211.c index 4ae99749ac70..bdd629d72a75 100644 --- a/drivers/staging/brcm80211/sys/wl_mac80211.c +++ b/drivers/staging/brcm80211/sys/wl_mac80211.c @@ -179,7 +179,7 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct wl_info *wl = hw->priv; WL_LOCK(wl); if (!wl->pub->up) { - WL_ERROR(("ops->tx called while down\n")); + WL_ERROR("ops->tx called while down\n"); status = -ENETDOWN; goto done; } @@ -192,8 +192,10 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl_ops_start(struct ieee80211_hw *hw) { struct wl_info *wl = hw->priv; - /* struct ieee80211_channel *curchan = hw->conf.channel; */ - WL_NONE(("%s : Initial channel: %d\n", __func__, curchan->hw_value)); + /* + struct ieee80211_channel *curchan = hw->conf.channel; + WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value); + */ WL_LOCK(wl); ieee80211_wake_queues(hw); @@ -226,8 +228,8 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_WDS && vif->type != NL80211_IFTYPE_ADHOC) { - WL_ERROR(("%s: Attempt to add type %d, only STA for now\n", - __func__, vif->type)); + WL_ERROR("%s: Attempt to add type %d, only STA for now\n", + __func__, vif->type); return -EOPNOTSUPP; } @@ -237,7 +239,7 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) WL_UNLOCK(wl); if (err != 0) - WL_ERROR(("%s: wl_up() returned %d\n", __func__, err)); + WL_ERROR("%s: wl_up() returned %d\n", __func__, err); return err; } @@ -263,8 +265,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan, break; case NL80211_CHAN_HT40MINUS: case NL80211_CHAN_HT40PLUS: - WL_ERROR(("%s: Need to implement 40 Mhz Channels!\n", - __func__)); + WL_ERROR("%s: Need to implement 40 Mhz Channels!\n", __func__); break; } @@ -281,12 +282,12 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) int new_int; if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { - WL_NONE(("%s: Setting listen interval to %d\n", - __func__, conf->listen_interval)); + WL_NONE("%s: Setting listen interval to %d\n", + __func__, conf->listen_interval); if (wlc_iovar_setint (wl->wlc, "bcn_li_bcn", conf->listen_interval)) { - WL_ERROR(("%s: Error setting listen_interval\n", - __func__)); + WL_ERROR("%s: Error setting listen_interval\n", + __func__); err = -EIO; goto config_out; } @@ -294,41 +295,42 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed) ASSERT(new_int == conf->listen_interval); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) - WL_NONE(("Need to set monitor mode\n")); + WL_NONE("Need to set monitor mode\n"); if (changed & IEEE80211_CONF_CHANGE_PS) - WL_NONE(("Need to set Power-save mode\n")); + WL_NONE("Need to set Power-save mode\n"); if (changed & IEEE80211_CONF_CHANGE_POWER) { - WL_NONE(("%s: Setting tx power to %d dbm\n", __func__, - conf->power_level)); + WL_NONE("%s: Setting tx power to %d dbm\n", + __func__, conf->power_level); if (wlc_iovar_setint (wl->wlc, "qtxpower", conf->power_level * 4)) { - WL_ERROR(("%s: Error setting power_level\n", __func__)); + WL_ERROR("%s: Error setting power_level\n", __func__); err = -EIO; goto config_out; } wlc_iovar_getint(wl->wlc, "qtxpower", &new_int); if (new_int != (conf->power_level * 4)) - WL_ERROR(("%s: Power level req != actual, %d %d\n", - __func__, conf->power_level * 4, new_int)); + WL_ERROR("%s: Power level req != actual, %d %d\n", + __func__, conf->power_level * 4, new_int); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { err = ieee_set_channel(hw, conf->channel, conf->channel_type); } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - WL_NONE(("%s: srl %d, lrl %d\n", __func__, - conf->short_frame_max_tx_count, - conf->long_frame_max_tx_count)); + WL_NONE("%s: srl %d, lrl %d\n", + __func__, + conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); if (wlc_set (wl->wlc, WLC_SET_SRL, conf->short_frame_max_tx_count) < 0) { - WL_ERROR(("%s: Error setting srl\n", __func__)); + WL_ERROR("%s: Error setting srl\n", __func__); err = -EIO; goto config_out; } if (wlc_set(wl->wlc, WLC_SET_LRL, conf->long_frame_max_tx_count) < 0) { - WL_ERROR(("%s: Error setting lrl\n", __func__)); + WL_ERROR("%s: Error setting lrl\n", __func__); err = -EIO; goto config_out; } @@ -348,24 +350,24 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { - WL_ERROR(("Associated:\t%s\n", info->assoc ? "True" : "False")); + WL_ERROR("Associated:\t%s\n", info->assoc ? "True" : "False"); /* association status changed (associated/disassociated) * also implies a change in the AID. */ } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - WL_NONE(("Use_cts_prot:\t%s Implement me\n", - info->use_cts_prot ? "True" : "False")); + WL_NONE("Use_cts_prot:\t%s Implement me\n", + info->use_cts_prot ? "True" : "False"); /* CTS protection changed */ } if (changed & BSS_CHANGED_ERP_PREAMBLE) { - WL_NONE(("Short preamble:\t%s Implement me\n", - info->use_short_preamble ? "True" : "False")); + WL_NONE("Short preamble:\t%s Implement me\n", + info->use_short_preamble ? "True" : "False"); /* preamble changed */ } if (changed & BSS_CHANGED_ERP_SLOT) { - WL_NONE(("Changing short slot:\t%s\n", - info->use_short_slot ? "True" : "False")); + WL_NONE("Changing short slot:\t%s\n", + info->use_short_slot ? "True" : "False"); if (info->use_short_slot) val = 1; else @@ -375,34 +377,34 @@ wl_ops_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - WL_NONE(("%s: HT mode - Implement me\n", __func__)); + WL_NONE("%s: HT mode - Implement me\n", __func__); /* 802.11n parameters changed */ } if (changed & BSS_CHANGED_BASIC_RATES) { - WL_NONE(("Need to change Basic Rates:\t0x%x! Implement me\n", - (u32) info->basic_rates)); + WL_NONE("Need to change Basic Rates:\t0x%x! Implement me\n", + (u32) info->basic_rates); /* Basic rateset changed */ } if (changed & BSS_CHANGED_BEACON_INT) { - WL_NONE(("Beacon Interval:\t%d Implement me\n", - info->beacon_int)); + WL_NONE("Beacon Interval:\t%d Implement me\n", + info->beacon_int); /* Beacon interval changed */ } if (changed & BSS_CHANGED_BSSID) { - WL_NONE(("new BSSID:\taid %d bss:%pM\n", info->aid, - info->bssid)); + WL_NONE("new BSSID:\taid %d bss:%pM\n", + info->aid, info->bssid); /* BSSID changed, for whatever reason (IBSS and managed mode) */ /* FIXME: need to store bssid in bsscfg */ wlc_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, (struct ether_addr *)info->bssid); } if (changed & BSS_CHANGED_BEACON) { - WL_ERROR(("BSS_CHANGED_BEACON\n")); + WL_ERROR("BSS_CHANGED_BEACON\n"); /* Beacon data changed, retrieve new beacon (beaconing modes) */ } if (changed & BSS_CHANGED_BEACON_ENABLED) { - WL_ERROR(("Beacon enabled:\t%s\n", - info->enable_beacon ? "True" : "False")); + WL_ERROR("Beacon enabled:\t%s\n", + info->enable_beacon ? "True" : "False"); /* Beaconing should be enabled/disabled (beaconing modes) */ } return; @@ -418,19 +420,19 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, changed_flags &= MAC_FILTERS; *total_flags &= MAC_FILTERS; if (changed_flags & FIF_PROMISC_IN_BSS) - WL_ERROR(("FIF_PROMISC_IN_BSS\n")); + WL_ERROR("FIF_PROMISC_IN_BSS\n"); if (changed_flags & FIF_ALLMULTI) - WL_ERROR(("FIF_ALLMULTI\n")); + WL_ERROR("FIF_ALLMULTI\n"); if (changed_flags & FIF_FCSFAIL) - WL_ERROR(("FIF_FCSFAIL\n")); + WL_ERROR("FIF_FCSFAIL\n"); if (changed_flags & FIF_PLCPFAIL) - WL_ERROR(("FIF_PLCPFAIL\n")); + WL_ERROR("FIF_PLCPFAIL\n"); if (changed_flags & FIF_CONTROL) - WL_ERROR(("FIF_CONTROL\n")); + WL_ERROR("FIF_CONTROL\n"); if (changed_flags & FIF_OTHER_BSS) - WL_ERROR(("FIF_OTHER_BSS\n")); + WL_ERROR("FIF_OTHER_BSS\n"); if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - WL_NONE(("FIF_BCN_PRBRESP_PROMISC\n")); + WL_NONE("FIF_BCN_PRBRESP_PROMISC\n"); WL_LOCK(wl); if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; @@ -447,25 +449,25 @@ wl_ops_configure_filter(struct ieee80211_hw *hw, static int wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { - WL_ERROR(("%s: Enter\n", __func__)); + WL_ERROR("%s: Enter\n", __func__); return 0; } static void wl_ops_sw_scan_start(struct ieee80211_hw *hw) { - WL_NONE(("Scan Start\n")); + WL_NONE("Scan Start\n"); return; } static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw) { - WL_NONE(("Scan Complete\n")); + WL_NONE("Scan Complete\n"); return; } static void wl_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf) { - WL_ERROR(("%s: Enter\n", __func__)); + WL_ERROR("%s: Enter\n", __func__); return; } @@ -473,13 +475,13 @@ static int wl_ops_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - WL_ERROR(("%s: Enter\n", __func__)); + WL_ERROR("%s: Enter\n", __func__); return 0; } static int wl_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - WL_ERROR(("%s: Enter\n", __func__)); + WL_ERROR("%s: Enter\n", __func__); return 0; } @@ -487,10 +489,10 @@ static void wl_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - WL_NONE(("%s: Enter\n", __func__)); + WL_NONE("%s: Enter\n", __func__); switch (cmd) { default: - WL_ERROR(("%s: Uknown cmd = %d\n", __func__, cmd)); + WL_ERROR("%s: Unknown cmd = %d\n", __func__, cmd); break; } return; @@ -502,9 +504,9 @@ wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, { struct wl_info *wl = hw->priv; - WL_NONE(("%s: Enter (WME config)\n", __func__)); - WL_NONE(("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue, - params->txop, params->cw_min, params->cw_max, params->aifs)); + WL_NONE("%s: Enter (WME config)\n", __func__); + WL_NONE("queue %d, txop %d, cwmin %d, cwmax %d, aifs %d\n", queue, + params->txop, params->cw_min, params->cw_max, params->aifs); WL_LOCK(wl); wlc_wme_setparams(wl->wlc, queue, (void *)params, true); @@ -515,7 +517,7 @@ wl_ops_conf_tx(struct ieee80211_hw *hw, u16 queue, static u64 wl_ops_get_tsf(struct ieee80211_hw *hw) { - WL_ERROR(("%s: Enter\n", __func__)); + WL_ERROR("%s: Enter\n", __func__); return 0; } @@ -558,7 +560,7 @@ static int wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - WL_NONE(("%s: Enter\n", __func__)); + WL_NONE("%s: Enter\n", __func__); return 0; } @@ -576,14 +578,14 @@ wl_ampdu_action(struct ieee80211_hw *hw, ASSERT(scb->magic == SCB_MAGIC); switch (action) { case IEEE80211_AMPDU_RX_START: - WL_NONE(("%s: action = IEEE80211_AMPDU_RX_START\n", __func__)); + WL_NONE("%s: action = IEEE80211_AMPDU_RX_START\n", __func__); break; case IEEE80211_AMPDU_RX_STOP: - WL_NONE(("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__)); + WL_NONE("%s: action = IEEE80211_AMPDU_RX_STOP\n", __func__); break; case IEEE80211_AMPDU_TX_START: if (!wlc_aggregatable(wl->wlc, tid)) { - /* WL_ERROR(("START: tid %d is not agg' able, return FAILURE to stack\n", tid)); */ + /* WL_ERROR("START: tid %d is not agg' able, return FAILURE to stack\n", tid); */ return -1; } /* XXX: Use the starting sequence number provided ... */ @@ -597,11 +599,11 @@ wl_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_OPERATIONAL: /* Not sure what to do here */ /* Power save wakeup */ - WL_NONE(("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n", - __func__)); + WL_NONE("%s: action = IEEE80211_AMPDU_TX_OPERATIONAL\n", + __func__); break; default: - WL_ERROR(("%s: Invalid command, ignoring\n", __func__)); + WL_ERROR("%s: Invalid command, ignoring\n", __func__); } return 0; @@ -632,8 +634,8 @@ static const struct ieee80211_ops wl_ops = { static int wl_set_hint(struct wl_info *wl, char *abbrev) { - WL_ERROR(("%s: Sending country code %c%c to MAC80211\n", __func__, - abbrev[0], abbrev[1])); + WL_ERROR("%s: Sending country code %c%c to MAC80211\n", + __func__, abbrev[0], abbrev[1]); return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); } @@ -663,7 +665,7 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, err = 0; if (unit < 0) { - WL_ERROR(("wl%d: unit number overflow, exiting\n", unit)); + WL_ERROR("wl%d: unit number overflow, exiting\n", unit); return NULL; } @@ -691,13 +693,13 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, /* Do nothing */ } else { bustype = PCI_BUS; - WL_TRACE(("force to PCI\n")); + WL_TRACE("force to PCI\n"); } wl->bcm_bustype = bustype; wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ); if (wl->regsva == NULL) { - WL_ERROR(("wl%d: ioremap() failed\n", unit)); + WL_ERROR("wl%d: ioremap() failed\n", unit); goto fail; } spin_lock_init(&wl->lock); @@ -729,13 +731,12 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, if (wlc_iovar_setint(wl->wlc, "mpc", 0)) { - WL_ERROR(("wl%d: Error setting MPC variable to 0\n", - unit)); + WL_ERROR("wl%d: Error setting MPC variable to 0\n", unit); } /* register our interrupt handler */ if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { - WL_ERROR(("wl%d: request_irq() failed\n", unit)); + WL_ERROR("wl%d: request_irq() failed\n", unit); goto fail; } wl->irq = irq; @@ -745,7 +746,7 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, NULL); if (ieee_hw_init(hw)) { - WL_ERROR(("wl%d: %s: ieee_hw_init failed!\n", unit, __func__)); + WL_ERROR("wl%d: %s: ieee_hw_init failed!\n", unit, __func__); goto fail; } @@ -755,8 +756,8 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, err = ieee80211_register_hw(hw); if (err) { - WL_ERROR(("%s: ieee80211_register_hw failed, status %d\n", - __func__, err)); + WL_ERROR("%s: ieee80211_register_hw failed, status %d\n", + __func__, err); } if (wl->pub->srom_ccode[0]) @@ -764,11 +765,11 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs, else err = wl_set_hint(wl, "US"); if (err) { - WL_ERROR(("%s: regulatory_hint failed, status %d\n", __func__, - err)); + WL_ERROR("%s: regulatory_hint failed, status %d\n", + __func__, err); } - WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver " - " (" PHY_VERSION_STR ")", unit)); + WL_ERROR("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver (" PHY_VERSION_STR ")", + unit); #ifdef BCMDBG printf(" (Compiled at " __TIME__ " on " __DATE__ ")"); @@ -964,9 +965,9 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; if (wlc_get(wl->wlc, WLC_GET_PHYLIST, (int *)&phy_list) < 0) { - WL_ERROR(("Phy list failed\n")); + WL_ERROR("Phy list failed\n"); } - WL_NONE(("%s: phylist = %c\n", __func__, phy_list[0])); + WL_NONE("%s: phylist = %c\n", __func__, phy_list[0]); if (phy_list[0] == 'n' || phy_list[0] == 'c') { if (phy_list[0] == 'c') { @@ -991,7 +992,7 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw) } } - WL_NONE(("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g)); + WL_NONE("%s: 2ghz = %d, 5ghz = %d\n", __func__, 1, has_5g); return 0; } @@ -1039,9 +1040,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ASSERT(pdev); - WL_TRACE(("%s: bus %d slot %d func %d irq %d\n", __func__, - pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), pdev->irq)); + WL_TRACE("%s: bus %d slot %d func %d irq %d\n", + __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || (((pdev->device & 0xff00) != 0x4300) && @@ -1051,9 +1052,9 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rc = pci_enable_device(pdev); if (rc) { - WL_ERROR(("%s: Cannot enable device %d-%d_%d\n", __func__, - pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn))); + WL_ERROR("%s: Cannot enable device %d-%d_%d\n", + __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); return -ENODEV; } pci_set_master(pdev); @@ -1064,7 +1065,7 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw = ieee80211_alloc_hw(sizeof(struct wl_info), &wl_ops); if (!hw) { - WL_ERROR(("%s: ieee80211_alloc_hw failed\n", __func__)); + WL_ERROR("%s: ieee80211_alloc_hw failed\n", __func__); rc = -ENOMEM; goto err_1; } @@ -1079,13 +1080,13 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) PCI_BUS, pdev, pdev->irq); if (!wl) { - WL_ERROR(("%s: %s: wl_attach failed!\n", - KBUILD_MODNAME, __func__)); + WL_ERROR("%s: %s: wl_attach failed!\n", + KBUILD_MODNAME, __func__); return -ENODEV; } return 0; err_1: - WL_ERROR(("%s: err_1: Major hoarkage\n", __func__)); + WL_ERROR("%s: err_1: Major hoarkage\n", __func__); return 0; } @@ -1095,12 +1096,12 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state) struct wl_info *wl; struct ieee80211_hw *hw; - WL_TRACE(("wl: wl_suspend\n")); + WL_TRACE("wl: wl_suspend\n"); hw = pci_get_drvdata(pdev); wl = HW_TO_WL(hw); if (!wl) { - WL_ERROR(("wl: wl_suspend: pci_get_drvdata failed\n")); + WL_ERROR("wl: wl_suspend: pci_get_drvdata failed\n"); return -ENODEV; } @@ -1120,11 +1121,11 @@ static int wl_resume(struct pci_dev *pdev) int err = 0; u32 val; - WL_TRACE(("wl: wl_resume\n")); + WL_TRACE("wl: wl_resume\n"); hw = pci_get_drvdata(pdev); wl = HW_TO_WL(hw); if (!wl) { - WL_ERROR(("wl: wl_resume: pci_get_drvdata failed\n")); + WL_ERROR("wl: wl_resume: pci_get_drvdata failed\n"); return -ENODEV; } @@ -1160,11 +1161,11 @@ static void wl_remove(struct pci_dev *pdev) hw = pci_get_drvdata(pdev); wl = HW_TO_WL(hw); if (!wl) { - WL_ERROR(("wl: wl_remove: pci_get_drvdata failed\n")); + WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n"); return; } if (!wlc_chipmatch(pdev->vendor, pdev->device)) { - WL_ERROR(("wl: wl_remove: wlc_chipmatch failed\n")); + WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n"); return; } if (wl->wlc) { @@ -1172,7 +1173,7 @@ static void wl_remove(struct pci_dev *pdev) WL_LOCK(wl); wl_down(wl); WL_UNLOCK(wl); - WL_NONE(("%s: Down\n", __func__)); + WL_NONE("%s: Down\n", __func__); } pci_disable_device(pdev); @@ -1334,12 +1335,12 @@ wl_start_int(struct wl_info *wl, struct ieee80211_hw *hw, struct sk_buff *skb) void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, int prio) { - WL_ERROR(("Shouldn't be here %s\n", __func__)); + WL_ERROR("Shouldn't be here %s\n", __func__); } void wl_init(struct wl_info *wl) { - WL_TRACE(("wl%d: wl_init\n", wl->pub->unit)); + WL_TRACE("wl%d: wl_init\n", wl->pub->unit); wl_reset(wl); @@ -1348,7 +1349,7 @@ void wl_init(struct wl_info *wl) uint wl_reset(struct wl_info *wl) { - WL_TRACE(("wl%d: wl_reset\n", wl->pub->unit)); + WL_TRACE("wl%d: wl_reset\n", wl->pub->unit); wlc_reset(wl->wlc); @@ -1494,12 +1495,12 @@ static void BCMFASTPATH wl_dpc(unsigned long data) static void wl_link_up(struct wl_info *wl, char *ifname) { - WL_ERROR(("wl%d: link up (%s)\n", wl->pub->unit, ifname)); + WL_ERROR("wl%d: link up (%s)\n", wl->pub->unit, ifname); } static void wl_link_down(struct wl_info *wl, char *ifname) { - WL_ERROR(("wl%d: link down (%s)\n", wl->pub->unit, ifname)); + WL_ERROR("wl%d: link down (%s)\n", wl->pub->unit, ifname); } void wl_event(struct wl_info *wl, char *ifname, wlc_event_t *e) @@ -1551,7 +1552,7 @@ wl_timer_t *wl_init_timer(struct wl_info *wl, void (*fn) (void *arg), void *arg, t = kmalloc(sizeof(wl_timer_t), GFP_ATOMIC); if (!t) { - WL_ERROR(("wl%d: wl_init_timer: out of memory\n", wl->pub->unit)); + WL_ERROR("wl%d: wl_init_timer: out of memory\n", wl->pub->unit); return 0; } @@ -1582,8 +1583,8 @@ void wl_add_timer(struct wl_info *wl, wl_timer_t *t, uint ms, int periodic) { #ifdef BCMDBG if (t->set) { - WL_ERROR(("%s: Already set. Name: %s, per %d\n", - __func__, t->name, periodic)); + WL_ERROR("%s: Already set. Name: %s, per %d\n", + __func__, t->name, periodic); } #endif ASSERT(!t->set); @@ -1752,7 +1753,7 @@ static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) break; sprintf(fw_name, "%s-%d.fw", wl_firmwares[i], UCODE_LOADER_API_VER); - WL_NONE(("request fw %s\n", fw_name)); + WL_NONE("request fw %s\n", fw_name); status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); if (status) { printf("%s: fail to load firmware %s\n", @@ -1760,7 +1761,7 @@ static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) wl_release_fw(wl); return status; } - WL_NONE(("request fw %s\n", fw_name)); + WL_NONE("request fw %s\n", fw_name); sprintf(fw_name, "%s_hdr-%d.fw", wl_firmwares[i], UCODE_LOADER_API_VER); status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); @@ -1772,8 +1773,8 @@ static int wl_request_fw(struct wl_info *wl, struct pci_dev *pdev) } wl->fw.hdr_num_entries[i] = wl->fw.fw_hdr[i]->size / (sizeof(struct wl_fw_hdr)); - WL_NONE(("request fw %s find: %d entries\n", fw_name, - wl->fw.hdr_num_entries[i])); + WL_NONE("request fw %s find: %d entries\n", + fw_name, wl->fw.hdr_num_entries[i]); } wl->fw.fw_cnt = i; return wl_ucode_data_init(wl); @@ -1811,16 +1812,16 @@ int wl_check_firmwares(struct wl_info *wl) if (fw == NULL && fw_hdr == NULL) { break; } else if (fw == NULL || fw_hdr == NULL) { - WL_ERROR(("%s: invalid bin/hdr fw\n", __func__)); + WL_ERROR("%s: invalid bin/hdr fw\n", __func__); rc = -EBADF; } else if (fw_hdr->size % sizeof(struct wl_fw_hdr)) { - WL_ERROR(("%s: non integral fw hdr file size %d/%d\n", - __func__, fw_hdr->size, - sizeof(struct wl_fw_hdr))); + WL_ERROR("%s: non integral fw hdr file size %d/%zu\n", + __func__, fw_hdr->size, + sizeof(struct wl_fw_hdr)); rc = -EBADF; } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { - WL_ERROR(("%s: out of bounds fw file size %d\n", - __func__, fw->size)); + WL_ERROR("%s: out of bounds fw file size %d\n", + __func__, fw->size); rc = -EBADF; } else { /* check if ucode section overruns firmware image */ @@ -1829,15 +1830,15 @@ int wl_check_firmwares(struct wl_info *wl) entry++, ucode_hdr++) { if (ucode_hdr->offset + ucode_hdr->len > fw->size) { - WL_ERROR(("%s: conflicting bin/hdr\n", - __func__)); + WL_ERROR("%s: conflicting bin/hdr\n", + __func__); rc = -EBADF; } } } } if (rc == 0 && wl->fw.fw_cnt != i) { - WL_ERROR(("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt)); + WL_ERROR("%s: invalid fw_cnt=%d\n", __func__, wl->fw.fw_cnt); rc = -EBADF; } return rc; diff --git a/drivers/staging/brcm80211/sys/wlc_alloc.c b/drivers/staging/brcm80211/sys/wlc_alloc.c index 9af2d17a40c0..746439e8fd57 100644 --- a/drivers/staging/brcm80211/sys/wlc_alloc.c +++ b/drivers/staging/brcm80211/sys/wlc_alloc.c @@ -43,7 +43,7 @@ void *wlc_calloc(struct osl_info *osh, uint unit, uint size) item = kzalloc(size, GFP_ATOMIC); if (item == NULL) - WL_ERROR(("wl%d: %s: out of memory\n", unit, __func__)); + WL_ERROR("wl%d: %s: out of memory\n", unit, __func__); return item; } diff --git a/drivers/staging/brcm80211/sys/wlc_ampdu.c b/drivers/staging/brcm80211/sys/wlc_ampdu.c index 0419c528e40e..d749917f5912 100644 --- a/drivers/staging/brcm80211/sys/wlc_ampdu.c +++ b/drivers/staging/brcm80211/sys/wlc_ampdu.c @@ -174,7 +174,8 @@ struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc) ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC); if (!ampdu) { - WL_ERROR(("wl%d: wlc_ampdu_attach: out of mem\n", wlc->pub->unit)); + WL_ERROR("wl%d: wlc_ampdu_attach: out of mem\n", + wlc->pub->unit); return NULL; } ampdu->wlc = wlc; @@ -244,7 +245,7 @@ void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb) scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb); u8 tid; - WL_AMPDU_UPDN(("scb_ampdu_cleanup: enter\n")); + WL_AMPDU_UPDN("scb_ampdu_cleanup: enter\n"); ASSERT(scb_ampdu); for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) { @@ -257,7 +258,7 @@ void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb) */ void wlc_ampdu_reset(struct ampdu_info *ampdu) { - WL_NONE(("%s: Entering\n", __func__)); + WL_NONE("%s: Entering\n", __func__); } static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb) @@ -338,7 +339,7 @@ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid])); new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl); if (new_txunfl == 0) { - WL_FFPLD(("check_txunfl : TX status FRAG set but no tx underflows\n")); + WL_FFPLD("check_txunfl : TX status FRAG set but no tx underflows\n"); return -1; } fifo->prev_txfunfl = cur_txunfl; @@ -348,7 +349,7 @@ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) /* check if fifo is big enough */ if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) { - WL_FFPLD(("check_txunfl : get xmtfifo_sz failed.\n")); + WL_FFPLD("check_txunfl : get xmtfifo_sz failed\n"); return -1; } @@ -362,8 +363,8 @@ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) if (fifo->accum_txfunfl < 10) return 0; - WL_FFPLD(("ampdu_count %d tx_underflows %d\n", - current_ampdu_cnt, fifo->accum_txfunfl)); + WL_FFPLD("ampdu_count %d tx_underflows %d\n", + current_ampdu_cnt, fifo->accum_txfunfl); /* compute the current ratio of tx unfl per ampdu. @@ -416,8 +417,8 @@ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size)) / (max_mpdu * FFPLD_MPDU_SIZE)) * 100; - WL_FFPLD(("DMA estimated transfer rate %d; pre-load size %d\n", - fifo->dmaxferrate, fifo->ampdu_pld_size)); + WL_FFPLD("DMA estimated transfer rate %d; pre-load size %d\n", + fifo->dmaxferrate, fifo->ampdu_pld_size); } else { /* decrease ampdu size */ @@ -552,7 +553,7 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, wlc_ampdu_agg(ampdu, scb, p, tid); if (wlc->block_datafifo) { - WL_ERROR(("%s: Fifo blocked\n", __func__)); + WL_ERROR("%s: Fifo blocked\n", __func__); return BCME_BUSY; } rr_retry_limit = ampdu->rr_retry_limit_tid[tid]; @@ -567,7 +568,7 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { err = wlc_prep_pdu(wlc, p, &fifo); } else { - WL_ERROR(("%s: AMPDU flag is off!\n", __func__)); + WL_ERROR("%s: AMPDU flag is off!\n", __func__); *pdu = NULL; err = 0; break; @@ -575,14 +576,16 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, if (err) { if (err == BCME_BUSY) { - WL_ERROR(("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n", wlc->pub->unit, seq)); + WL_ERROR("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n", + wlc->pub->unit, seq); WLCNTINCR(ampdu->cnt->sduretry); *pdu = p; break; } /* error in the packet; reject it */ - WL_AMPDU_ERR(("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n", wlc->pub->unit, seq)); + WL_AMPDU_ERR("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n", + wlc->pub->unit, seq); WLCNTINCR(ampdu->cnt->sdurejected); *pdu = NULL; @@ -624,8 +627,8 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; seg_cnt += 1; - WL_AMPDU_TX(("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n", - wlc->pub->unit, count, len)); + WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n", + wlc->pub->unit, count, len); /* * aggregateable mpdu. For ucode/hw agg, @@ -656,7 +659,8 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, dma_len += (u16) pkttotlen(osh, p); - WL_AMPDU_TX(("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n", wlc->pub->unit, ampdu_len, seg_cnt, ndelim)); + WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n", + wlc->pub->unit, ampdu_len, seg_cnt, ndelim); txh->MacTxControlLow = htol16(mcl); @@ -686,8 +690,8 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, min(scb_ampdu->max_rxlen, ampdu->max_txlen[mcs][is40][sgi]); - WL_NONE(("sendampdu: sgi %d, is40 %d, mcs %d\n", sgi, - is40, mcs)); + WL_NONE("sendampdu: sgi %d, is40 %d, mcs %d\n", + sgi, is40, mcs); maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */ @@ -730,13 +734,14 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, /* test whether to add more */ if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) && (count == f->mcs2ampdu_table[mcs])) { - WL_AMPDU_ERR(("wl%d: PR 37644: stopping ampdu at %d for mcs %d", wlc->pub->unit, count, mcs)); + WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n", + wlc->pub->unit, count, mcs); break; } if (count == scb_ampdu->max_pdu) { - WL_NONE(("Stop taking from q, reached %d deep\n", - scb_ampdu->max_pdu)); + WL_NONE("Stop taking from q, reached %d deep\n", + scb_ampdu->max_pdu); break; } @@ -754,15 +759,16 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, if ((plen + ampdu_len) > maxlen) { p = NULL; - WL_ERROR(("%s: Bogus plen #1\n", - __func__)); + WL_ERROR("%s: Bogus plen #1\n", + __func__); ASSERT(3 == 4); continue; } /* check if there are enough descriptors available */ if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) { - WL_ERROR(("%s: No fifo space !!!!!!\n", __func__)); + WL_ERROR("%s: No fifo space !!!!!!\n", + __func__); p = NULL; continue; } @@ -869,13 +875,14 @@ wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi, WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback); } - WL_AMPDU_TX(("wl%d: wlc_sendampdu: count %d ampdu_len %d\n", - wlc->pub->unit, count, ampdu_len)); + WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n", + wlc->pub->unit, count, ampdu_len); /* inform rate_sel if it this is a rate probe pkt */ frameid = ltoh16(txh->TxFrameID); if (frameid & TXFID_RATE_PROBE_MASK) { - WL_ERROR(("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n", __func__)); + WL_ERROR("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n", + __func__); } for (i = 0; i < count; i++) wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1), @@ -1029,13 +1036,16 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, if (supr_status) { update_rate = false; if (supr_status == TX_STATUS_SUPR_BADCH) { - WL_ERROR(("%s: Pkt tx suppressed, illegal channel possibly %d\n", __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec))); + WL_ERROR("%s: Pkt tx suppressed, illegal channel possibly %d\n", + __func__, + CHSPEC_CHANNEL(wlc->default_bss->chanspec)); } else { if (supr_status == TX_STATUS_SUPR_FRAG) - WL_NONE(("%s: AMPDU frag err\n", - __func__)); + WL_NONE("%s: AMPDU frag err\n", + __func__); else - WL_ERROR(("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n", __func__, supr_status)); + WL_ERROR("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n", + __func__, supr_status); } /* no need to retry for badch; will fail again */ if (supr_status == TX_STATUS_SUPR_BADCH || @@ -1059,7 +1069,8 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, } else if (txs->phyerr) { update_rate = false; WLCNTINCR(wlc->pub->_cnt->txphyerr); - WL_ERROR(("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n", wlc->pub->unit, txs->phyerr)); + WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n", + wlc->pub->unit, txs->phyerr); #ifdef BCMDBG if (WL_ERROR_ON()) { @@ -1091,10 +1102,9 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, if (ba_recd) { bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX); - WL_AMPDU_TX(("%s: tid %d seq is %d, start_seq is %d, " - "bindex is %d set %d, index %d\n", - __func__, tid, seq, start_seq, bindex, - isset(bitmap, bindex), index)); + WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n", + __func__, tid, seq, start_seq, bindex, + isset(bitmap, bindex), index); /* if acked then clear bit and free packet */ if ((bindex < AMPDU_TX_BA_MAX_WSIZE) @@ -1147,7 +1157,8 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, IEEE80211_TX_STAT_AMPDU_NO_BACK; skb_pull(p, D11_PHY_HDR_LEN); skb_pull(p, D11_TXH_LEN); - WL_ERROR(("%s: BA Timeout, seq %d, in_transit %d\n", SHORTNAME, seq, ini->tx_in_transit)); + WL_ERROR("%s: BA Timeout, seq %d, in_transit %d\n", + SHORTNAME, seq, ini->tx_in_transit); ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); } @@ -1183,8 +1194,8 @@ ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid, if (!ini) return; - WL_AMPDU_CTL(("wl%d: ampdu_cleanup_tid_ini: tid %d\n", - ampdu->wlc->pub->unit, tid)); + WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n", + ampdu->wlc->pub->unit, tid); if (ini->tx_in_transit && !force) return; @@ -1210,7 +1221,7 @@ static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu, /* check for per-tid control of ampdu */ if (!ampdu->ini_enable[tid]) { - WL_ERROR(("%s: Rejecting tid %d\n", __func__, tid)); + WL_ERROR("%s: Rejecting tid %d\n", __func__, tid); return NULL; } @@ -1231,13 +1242,13 @@ int wlc_ampdu_set(struct ampdu_info *ampdu, bool on) if (on) { if (!N_ENAB(wlc->pub)) { - WL_AMPDU_ERR(("wl%d: driver not nmode enabled\n", - wlc->pub->unit)); + WL_AMPDU_ERR("wl%d: driver not nmode enabled\n", + wlc->pub->unit); return BCME_UNSUPPORTED; } if (!wlc_ampdu_cap(ampdu)) { - WL_AMPDU_ERR(("wl%d: device not ampdu capable\n", - wlc->pub->unit)); + WL_AMPDU_ERR("wl%d: device not ampdu capable\n", + wlc->pub->unit); return BCME_UNSUPPORTED; } wlc->pub->_ampdu = on; diff --git a/drivers/staging/brcm80211/sys/wlc_antsel.c b/drivers/staging/brcm80211/sys/wlc_antsel.c index 27558fa02ba7..402ddf8f3371 100644 --- a/drivers/staging/brcm80211/sys/wlc_antsel.c +++ b/drivers/staging/brcm80211/sys/wlc_antsel.c @@ -102,7 +102,7 @@ struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc, asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); if (!asi) { - WL_ERROR(("wl%d: wlc_antsel_attach: out of mem\n", pub->unit)); + WL_ERROR("wl%d: wlc_antsel_attach: out of mem\n", pub->unit); return NULL; } @@ -131,7 +131,7 @@ struct antsel_info *wlc_antsel_attach(struct wlc_info *wlc, asi->antsel_avail = false; } else { asi->antsel_avail = false; - WL_ERROR(("wlc_antsel_attach: 2o3 board cfg invalid\n")); + WL_ERROR("wlc_antsel_attach: 2o3 board cfg invalid\n"); ASSERT(0); } break; diff --git a/drivers/staging/brcm80211/sys/wlc_bmac.c b/drivers/staging/brcm80211/sys/wlc_bmac.c index 0c2625dc440b..69f600affa46 100644 --- a/drivers/staging/brcm80211/sys/wlc_bmac.c +++ b/drivers/staging/brcm80211/sys/wlc_bmac.c @@ -217,18 +217,20 @@ static void WLBANDINITFN(wlc_ucode_bsinit) (struct wlc_hw_info *wlc_hw) if (WLCISNPHY(wlc_hw->band)) { wlc_write_inits(wlc_hw, d11n0bsinitvals16); } else { - WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } } else { if (D11REV_IS(wlc_hw->corerev, 24)) { if (WLCISLCNPHY(wlc_hw->band)) { wlc_write_inits(wlc_hw, d11lcn0bsinitvals24); } else - WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, + wlc_hw->corerev); } else { - WL_ERROR(("%s: wl%d: unsupported corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } } } @@ -240,7 +242,7 @@ static u32 WLBANDINITFN(wlc_setband_inact) (struct wlc_info *wlc, uint bandunit) u32 macintmask; u32 tmp; - WL_TRACE(("wl%d: wlc_setband_inact\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_setband_inact\n", wlc_hw->unit); ASSERT(bandunit != wlc_hw->band->bandunit); ASSERT(si_iscoreup(wlc_hw->sih)); @@ -281,7 +283,7 @@ wlc_bmac_recv(struct wlc_hw_info *wlc_hw, uint fifo, bool bound) u32 tsf_h, tsf_l; wlc_d11rxhdr_t *wlc_rxhdr = NULL; - WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__); /* gather received frames */ while ((p = dma_rx(wlc_hw->di[fifo]))) { @@ -333,7 +335,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) bool fatal = false; if (DEVICEREMOVED(wlc)) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__); wl_down(wlc->wl); return false; } @@ -342,8 +344,8 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) macintstatus = wlc->macintstatus; wlc->macintstatus = 0; - WL_TRACE(("wl%d: wlc_dpc: macintstatus 0x%x\n", wlc_hw->unit, - macintstatus)); + WL_TRACE("wl%d: wlc_dpc: macintstatus 0x%x\n", + wlc_hw->unit, macintstatus); if (macintstatus & MI_PRQ) { /* Process probe request FIFO */ @@ -366,7 +368,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) if (wlc_bmac_txstatus(wlc->hw, bounded, &fatal)) wlc->macintstatus |= MI_TFS; if (fatal) { - WL_ERROR(("MI_TFS: fatal\n")); + WL_ERROR("MI_TFS: fatal\n"); goto fatal; } } @@ -376,7 +378,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) /* ATIM window end */ if (macintstatus & MI_ATIMWINEND) { - WL_TRACE(("wlc_isr: end of ATIM window\n")); + WL_TRACE("wlc_isr: end of ATIM window\n"); OR_REG(wlc_hw->osh, ®s->maccommand, wlc->qvalid); wlc->qvalid = 0; @@ -397,7 +399,7 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) /* TX FIFO suspend/flush completion */ if (macintstatus & MI_TXSTOP) { if (wlc_bmac_tx_fifo_suspended(wlc_hw, TX_DATA_FIFO)) { - /* WL_ERROR(("dpc: fifo_suspend_comlete\n")); */ + /* WL_ERROR("dpc: fifo_suspend_comlete\n"); */ } } @@ -407,7 +409,8 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) } if (macintstatus & MI_GP0) { - WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now)); + WL_ERROR("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", + wlc_hw->unit, wlc_hw->now); printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", __func__, wlc_hw->sih->chip, @@ -429,7 +432,8 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) u32 rfd = R_REG(wlc_hw->osh, ®s->phydebug) & PDBG_RFD; #endif - WL_ERROR(("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", wlc_hw->unit, rfd)); + WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", + wlc_hw->unit, rfd); WLCNTINCR(wlc->pub->_cnt->rfdisable); } @@ -457,7 +461,7 @@ void wlc_bmac_watchdog(void *arg) struct wlc_info *wlc = (struct wlc_info *) arg; struct wlc_hw_info *wlc_hw = wlc->hw; - WL_TRACE(("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_watchdog\n", wlc_hw->unit); if (!wlc_hw->up) return; @@ -483,8 +487,8 @@ wlc_bmac_set_chanspec(struct wlc_hw_info *wlc_hw, chanspec_t chanspec, { uint bandunit; - WL_TRACE(("wl%d: wlc_bmac_set_chanspec 0x%x\n", wlc_hw->unit, - chanspec)); + WL_TRACE("wl%d: wlc_bmac_set_chanspec 0x%x\n", + wlc_hw->unit, chanspec); wlc_hw->chanspec = chanspec; @@ -594,7 +598,8 @@ static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme) dma_addrwidth(wlc_hw->sih, DMAREG(wlc_hw, DMA_TX, 0)); if (!wl_alloc_dma_resources(wlc_hw->wlc->wl, addrwidth)) { - WL_ERROR(("wl%d: wlc_attach: alloc_dma_resources failed\n", unit)); + WL_ERROR("wl%d: wlc_attach: alloc_dma_resources failed\n", + unit); return false; } @@ -667,8 +672,7 @@ static bool wlc_bmac_attach_dmapio(struct wlc_info *wlc, uint j, bool wme) /* Cleaner to leave this as if with AP defined */ if (dma_attach_err) { - WL_ERROR(("wl%d: wlc_attach: dma_attach failed\n", - unit)); + WL_ERROR("wl%d: wlc_attach: dma_attach failed\n", unit); return false; } @@ -717,8 +721,8 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, bool wme = false; shared_phy_params_t sha_params; - WL_TRACE(("wl%d: wlc_bmac_attach: vendor 0x%x device 0x%x\n", unit, - vendor, device)); + WL_TRACE("wl%d: wlc_bmac_attach: vendor 0x%x device 0x%x\n", + unit, vendor, device); ASSERT(sizeof(wlc_d11rxhdr_t) <= WL_HWRXOFF); @@ -742,7 +746,7 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, wlc_hw->sih = si_attach((uint) device, osh, regsva, bustype, btparam, &wlc_hw->vars, &wlc_hw->vars_size); if (wlc_hw->sih == NULL) { - WL_ERROR(("wl%d: wlc_bmac_attach: si_attach failed\n", unit)); + WL_ERROR("wl%d: wlc_bmac_attach: si_attach failed\n", unit); err = 11; goto fail; } @@ -762,21 +766,22 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, var = getvar(vars, "vendid"); if (var) { vendor = (u16) simple_strtoul(var, NULL, 0); - WL_ERROR(("Overriding vendor id = 0x%x\n", vendor)); + WL_ERROR("Overriding vendor id = 0x%x\n", vendor); } var = getvar(vars, "devid"); if (var) { u16 devid = (u16) simple_strtoul(var, NULL, 0); if (devid != 0xffff) { device = devid; - WL_ERROR(("Overriding device id = 0x%x\n", - device)); + WL_ERROR("Overriding device id = 0x%x\n", + device); } } /* verify again the device is supported */ if (!wlc_chipmatch(vendor, device)) { - WL_ERROR(("wl%d: wlc_bmac_attach: Unsupported vendor/device (0x%x/0x%x)\n", unit, vendor, device)); + WL_ERROR("wl%d: wlc_bmac_attach: Unsupported vendor/device (0x%x/0x%x)\n", + unit, vendor, device); err = 12; goto fail; } @@ -811,7 +816,8 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, wlc_bmac_corereset(wlc_hw, WLC_USE_COREFLAGS); if (!wlc_bmac_validate_chip_access(wlc_hw)) { - WL_ERROR(("wl%d: wlc_bmac_attach: validate_chip_access failed\n", unit)); + WL_ERROR("wl%d: wlc_bmac_attach: validate_chip_access failed\n", + unit); err = 14; goto fail; } @@ -823,7 +829,8 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, j = BOARDREV_PROMOTED; wlc_hw->boardrev = (u16) j; if (!wlc_validboardtype(wlc_hw)) { - WL_ERROR(("wl%d: wlc_bmac_attach: Unsupported Broadcom board type (0x%x)" " or revision level (0x%x)\n", unit, wlc_hw->sih->boardtype, wlc_hw->boardrev)); + WL_ERROR("wl%d: wlc_bmac_attach: Unsupported Broadcom board type (0x%x)" " or revision level (0x%x)\n", + unit, wlc_hw->sih->boardtype, wlc_hw->boardrev); err = 15; goto fail; } @@ -865,8 +872,8 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc); if (wlc_hw->physhim == NULL) { - WL_ERROR(("wl%d: wlc_bmac_attach: wlc_phy_shim_attach failed\n", - unit)); + WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_shim_attach failed\n", + unit); err = 25; goto fail; } @@ -933,7 +940,8 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, wlc_hw->band->pi = wlc_phy_attach(wlc_hw->phy_sh, (void *)regs, wlc_hw->band->bandtype, vars); if (wlc_hw->band->pi == NULL) { - WL_ERROR(("wl%d: wlc_bmac_attach: wlc_phy_attach failed\n", unit)); + WL_ERROR("wl%d: wlc_bmac_attach: wlc_phy_attach failed\n", + unit); err = 17; goto fail; } @@ -963,7 +971,9 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, goto bad_phy; } else { bad_phy: - WL_ERROR(("wl%d: wlc_bmac_attach: unsupported phy type/rev (%d/%d)\n", unit, wlc_hw->band->phytype, wlc_hw->band->phyrev)); + WL_ERROR("wl%d: wlc_bmac_attach: unsupported phy type/rev (%d/%d)\n", + unit, + wlc_hw->band->phytype, wlc_hw->band->phyrev); err = 18; goto fail; } @@ -1018,27 +1028,27 @@ int wlc_bmac_attach(struct wlc_info *wlc, u16 vendor, u16 device, uint unit, /* init etheraddr state variables */ macaddr = wlc_get_macaddr(wlc_hw); if (macaddr == NULL) { - WL_ERROR(("wl%d: wlc_bmac_attach: macaddr not found\n", unit)); + WL_ERROR("wl%d: wlc_bmac_attach: macaddr not found\n", unit); err = 21; goto fail; } bcm_ether_atoe(macaddr, &wlc_hw->etheraddr); if (is_broadcast_ether_addr(wlc_hw->etheraddr.octet) || is_zero_ether_addr(wlc_hw->etheraddr.octet)) { - WL_ERROR(("wl%d: wlc_bmac_attach: bad macaddr %s\n", unit, - macaddr)); + WL_ERROR("wl%d: wlc_bmac_attach: bad macaddr %s\n", + unit, macaddr); err = 22; goto fail; } - WL_ERROR(("%s:: deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", - __func__, wlc_hw->deviceid, wlc_hw->_nbands, - wlc_hw->sih->boardtype, macaddr)); + WL_ERROR("%s:: deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", + __func__, wlc_hw->deviceid, wlc_hw->_nbands, + wlc_hw->sih->boardtype, macaddr); return err; fail: - WL_ERROR(("wl%d: wlc_bmac_attach: failed with err %d\n", unit, err)); + WL_ERROR("wl%d: wlc_bmac_attach: failed with err %d\n", unit, err); return err; } @@ -1122,7 +1132,7 @@ int wlc_bmac_detach(struct wlc_info *wlc) void wlc_bmac_reset(struct wlc_hw_info *wlc_hw) { - WL_TRACE(("wl%d: wlc_bmac_reset\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_reset\n", wlc_hw->unit); WLCNTINCR(wlc_hw->wlc->pub->_cnt->reset); @@ -1143,7 +1153,7 @@ wlc_bmac_init(struct wlc_hw_info *wlc_hw, chanspec_t chanspec, bool fastclk; struct wlc_info *wlc = wlc_hw->wlc; - WL_TRACE(("wl%d: wlc_bmac_init\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_init\n", wlc_hw->unit); /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; @@ -1192,7 +1202,7 @@ int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw) { uint coremask; - WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__); ASSERT(wlc_hw->wlc->pub->hw_up && wlc_hw->wlc->macintmask == 0); @@ -1238,7 +1248,7 @@ int wlc_bmac_up_prep(struct wlc_hw_info *wlc_hw) int wlc_bmac_up_finish(struct wlc_hw_info *wlc_hw) { - WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__); wlc_hw->up = true; wlc_phy_hw_state_upd(wlc_hw->band->pi, true); @@ -1255,7 +1265,7 @@ int wlc_bmac_down_prep(struct wlc_hw_info *wlc_hw) bool dev_gone; uint callbacks = 0; - WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__); if (!wlc_hw->up) return callbacks; @@ -1283,7 +1293,7 @@ int wlc_bmac_down_finish(struct wlc_hw_info *wlc_hw) uint callbacks = 0; bool dev_gone; - WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__); if (!wlc_hw->up) return callbacks; @@ -1719,7 +1729,7 @@ wlc_bmac_set_rcmta(struct wlc_hw_info *wlc_hw, int idx, u16 mac_l; struct osl_info *osh; - WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__); ASSERT(wlc_hw->corerev > 4); @@ -1752,7 +1762,7 @@ wlc_bmac_set_addrmatch(struct wlc_hw_info *wlc_hw, int match_reg_offset, u16 mac_h; struct osl_info *osh; - WL_TRACE(("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_set_addrmatch\n", wlc_hw->unit); ASSERT((match_reg_offset < RCM_SIZE) || (wlc_hw->corerev == 4)); @@ -1783,7 +1793,7 @@ wlc_bmac_write_template_ram(struct wlc_hw_info *wlc_hw, int offset, int len, #endif /* IL_BIGENDIAN */ struct osl_info *osh; - WL_TRACE(("wl%d: wlc_bmac_write_template_ram\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_write_template_ram\n", wlc_hw->unit); regs = wlc_hw->regs; osh = wlc_hw->osh; @@ -1937,8 +1947,8 @@ WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec) { struct wlc_hw_info *wlc_hw = wlc->hw; - WL_TRACE(("wl%d: wlc_bmac_bsinit: bandunit %d\n", wlc_hw->unit, - wlc_hw->band->bandunit)); + WL_TRACE("wl%d: wlc_bmac_bsinit: bandunit %d\n", + wlc_hw->unit, wlc_hw->band->bandunit); /* sanity check */ if (PHY_TYPE(R_REG(wlc_hw->osh, &wlc_hw->regs->phyversion)) != @@ -1974,7 +1984,7 @@ WLBANDINITFN(wlc_bmac_bsinit) (struct wlc_info *wlc, chanspec_t chanspec) void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk) { - WL_TRACE(("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw->unit, clk)); + WL_TRACE("wl%d: wlc_bmac_core_phy_clk: clk %d\n", wlc_hw->unit, clk); wlc_hw->phyclk = clk; @@ -1999,7 +2009,7 @@ void wlc_bmac_core_phy_clk(struct wlc_hw_info *wlc_hw, bool clk) /* Perform a soft reset of the PHY PLL */ void wlc_bmac_core_phypll_reset(struct wlc_hw_info *wlc_hw) { - WL_TRACE(("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_core_phypll_reset\n", wlc_hw->unit); si_corereg(wlc_hw->sih, SI_CC_IDX, offsetof(chipcregs_t, chipcontrol_addr), ~0, 0); @@ -2045,7 +2055,7 @@ void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw) u32 phy_bw_clkbits; bool phy_in_reset = false; - WL_TRACE(("wl%d: wlc_bmac_phy_reset\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_phy_reset\n", wlc_hw->unit); if (pih == NULL) return; @@ -2127,7 +2137,7 @@ WLBANDINITFN(wlc_bmac_setband) (struct wlc_hw_info *wlc_hw, uint bandunit, /* low-level band switch utility routine */ void WLBANDINITFN(wlc_setxband) (struct wlc_hw_info *wlc_hw, uint bandunit) { - WL_TRACE(("wl%d: wlc_setxband: bandunit %d\n", wlc_hw->unit, bandunit)); + WL_TRACE("wl%d: wlc_setxband: bandunit %d\n", wlc_hw->unit, bandunit); wlc_hw->band = wlc_hw->bandstate[bandunit]; @@ -2146,7 +2156,7 @@ static bool wlc_isgoodchip(struct wlc_hw_info *wlc_hw) /* reject unsupported corerev */ if (!VALID_COREREV(wlc_hw->corerev)) { - WL_ERROR(("unsupported core rev %d\n", wlc_hw->corerev)); + WL_ERROR("unsupported core rev %d\n", wlc_hw->corerev); return false; } @@ -2194,7 +2204,8 @@ static char *wlc_get_macaddr(struct wlc_hw_info *wlc_hw) macaddr = getvar(wlc_hw->vars, varname); if (macaddr == NULL) { - WL_ERROR(("wl%d: wlc_get_macaddr: macaddr getvar(%s) not found\n", wlc_hw->unit, varname)); + WL_ERROR("wl%d: wlc_get_macaddr: macaddr getvar(%s) not found\n", + wlc_hw->unit, varname); } return macaddr; @@ -2257,7 +2268,7 @@ void wlc_bmac_hw_up(struct wlc_hw_info *wlc_hw) if (wlc_hw->wlc->pub->hw_up) return; - WL_TRACE(("wl%d: %s:\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc_hw->unit, __func__); /* * Enable pll and xtal, initialize the power control registers, @@ -2312,7 +2323,8 @@ static bool wlc_dma_rxreset(struct wlc_hw_info *wlc_hw, uint fifo) 50000); if (!rxidle && (rcv_frm_cnt != 0)) - WL_ERROR(("wl%d: %s: rxdma[%d] not idle && rcv_frm_cnt(%d) not zero\n", wlc_hw->unit, __func__, fifo, rcv_frm_cnt)); + WL_ERROR("wl%d: %s: rxdma[%d] not idle && rcv_frm_cnt(%d) not zero\n", + wlc_hw->unit, __func__, fifo, rcv_frm_cnt); mdelay(2); } @@ -2337,7 +2349,7 @@ void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags) if (flags == WLC_USE_COREFLAGS) flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0); - WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__); regs = wlc_hw->regs; @@ -2350,17 +2362,20 @@ void wlc_bmac_corereset(struct wlc_hw_info *wlc_hw, u32 flags) if (si_iscoreup(wlc_hw->sih)) { for (i = 0; i < NFIFO; i++) if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) { - WL_ERROR(("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, i)); + WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", + wlc_hw->unit, __func__, i); } if ((wlc_hw->di[RX_FIFO]) && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) { - WL_ERROR(("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, RX_FIFO)); + WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n", + wlc_hw->unit, __func__, RX_FIFO); } if (D11REV_IS(wlc_hw->corerev, 4) && wlc_hw->di[RX_TXSTATUS_FIFO] && (!wlc_dma_rxreset(wlc_hw, RX_TXSTATUS_FIFO))) { - WL_ERROR(("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n", wlc_hw->unit, __func__, RX_TXSTATUS_FIFO)); + WL_ERROR("wl%d: %s: dma_rxreset[%d]: cannot stop dma\n", + wlc_hw->unit, __func__, RX_TXSTATUS_FIFO); } } /* if noreset, just stop the psm and return */ @@ -2491,7 +2506,7 @@ static void wlc_coreinit(struct wlc_info *wlc) regs = wlc_hw->regs; osh = wlc_hw->osh; - WL_TRACE(("wl%d: wlc_coreinit\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_coreinit\n", wlc_hw->unit); /* reset PSM */ wlc_bmac_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE)); @@ -2514,8 +2529,8 @@ static void wlc_coreinit(struct wlc_info *wlc) SPINWAIT(((R_REG(osh, ®s->macintstatus) & MI_MACSSPNDD) == 0), 1000 * 1000); if ((R_REG(osh, ®s->macintstatus) & MI_MACSSPNDD) == 0) - WL_ERROR(("wl%d: wlc_coreinit: ucode did not self-suspend!\n", - wlc_hw->unit)); + WL_ERROR("wl%d: wlc_coreinit: ucode did not self-suspend!\n", + wlc_hw->unit); wlc_gpio_init(wlc); @@ -2525,18 +2540,18 @@ static void wlc_coreinit(struct wlc_info *wlc) if (WLCISNPHY(wlc_hw->band)) wlc_write_inits(wlc_hw, d11n0initvals16); else - WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } else if (D11REV_IS(wlc_hw->corerev, 24)) { if (WLCISLCNPHY(wlc_hw->band)) { wlc_write_inits(wlc_hw, d11lcn0initvals24); } else { - WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } } else { - WL_ERROR(("%s: wl%d: unsupported corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } /* For old ucode, txfifo sizes needs to be modified(increased) for Corerev >= 9 */ @@ -2578,7 +2593,8 @@ static void wlc_coreinit(struct wlc_info *wlc) err = -1; } if (err != 0) { - WL_ERROR(("wlc_coreinit: txfifo mismatch: ucode size %d driver size %d index %d\n", buf[i], wlc_hw->xmtfifo_sz[i], i)); + WL_ERROR("wlc_coreinit: txfifo mismatch: ucode size %d driver size %d index %d\n", + buf[i], wlc_hw->xmtfifo_sz[i], i); /* DO NOT ASSERT corerev < 4 even there is a mismatch * shmem, since driver don't overwrite those chip and * ucode initialize data will be used. @@ -2797,16 +2813,16 @@ static void wlc_ucode_download(struct wlc_hw_info *wlc_hw) bcm43xx_16_mimosz); wlc_hw->ucode_loaded = true; } else - WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } else if (D11REV_IS(wlc_hw->corerev, 24)) { if (WLCISLCNPHY(wlc_hw->band)) { wlc_ucode_write(wlc_hw, bcm43xx_24_lcn, bcm43xx_24_lcnsz); wlc_hw->ucode_loaded = true; } else { - WL_ERROR(("%s: wl%d: unsupported phy in corerev %d\n", - __func__, wlc_hw->unit, wlc_hw->corerev)); + WL_ERROR("%s: wl%d: unsupported phy in corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); } } } @@ -2820,7 +2836,7 @@ static void wlc_ucode_write(struct wlc_hw_info *wlc_hw, const u32 ucode[], osh = wlc_hw->osh; - WL_TRACE(("wl%d: wlc_ucode_write\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_ucode_write\n", wlc_hw->unit); ASSERT(IS_ALIGNED(nbytes, sizeof(u32))); @@ -2838,7 +2854,7 @@ static void wlc_write_inits(struct wlc_hw_info *wlc_hw, const d11init_t *inits) struct osl_info *osh; volatile u8 *base; - WL_TRACE(("wl%d: wlc_write_inits\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_write_inits\n", wlc_hw->unit); osh = wlc_hw->osh; base = (volatile u8 *)wlc_hw->regs; @@ -2914,44 +2930,45 @@ void wlc_bmac_fifoerrors(struct wlc_hw_info *wlc_hw) if (!intstatus) continue; - WL_TRACE(("wl%d: wlc_bmac_fifoerrors: intstatus%d 0x%x\n", unit, - idx, intstatus)); + WL_TRACE("wl%d: wlc_bmac_fifoerrors: intstatus%d 0x%x\n", + unit, idx, intstatus); if (intstatus & I_RO) { - WL_ERROR(("wl%d: fifo %d: receive fifo overflow\n", - unit, idx)); + WL_ERROR("wl%d: fifo %d: receive fifo overflow\n", + unit, idx); WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxoflo); fatal = true; } if (intstatus & I_PC) { - WL_ERROR(("wl%d: fifo %d: descriptor error\n", unit, - idx)); + WL_ERROR("wl%d: fifo %d: descriptor error\n", + unit, idx); WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmade); fatal = true; } if (intstatus & I_PD) { - WL_ERROR(("wl%d: fifo %d: data error\n", unit, idx)); + WL_ERROR("wl%d: fifo %d: data error\n", unit, idx); WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmada); fatal = true; } if (intstatus & I_DE) { - WL_ERROR(("wl%d: fifo %d: descriptor protocol error\n", - unit, idx)); + WL_ERROR("wl%d: fifo %d: descriptor protocol error\n", + unit, idx); WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmape); fatal = true; } if (intstatus & I_RU) { - WL_ERROR(("wl%d: fifo %d: receive descriptor underflow\n", unit, idx)); + WL_ERROR("wl%d: fifo %d: receive descriptor underflow\n", + idx, unit); WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxuflo[idx]); } if (intstatus & I_XU) { - WL_ERROR(("wl%d: fifo %d: transmit fifo underflow\n", - idx, unit)); + WL_ERROR("wl%d: fifo %d: transmit fifo underflow\n", + idx, unit); WLCNTINCR(wlc_hw->wlc->pub->_cnt->txuflo); fatal = true; } @@ -3185,7 +3202,7 @@ static inline u32 wlc_intstatus(struct wlc_info *wlc, bool in_isr) /* macintstatus includes a DMA interrupt summary bit */ macintstatus = R_REG(osh, ®s->macintstatus); - WL_TRACE(("wl%d: macintstatus: 0x%x\n", wlc_hw->unit, macintstatus)); + WL_TRACE("wl%d: macintstatus: 0x%x\n", wlc_hw->unit, macintstatus); /* detect cardbus removed, in power down(suspend) and in reset */ if (DEVICEREMOVED(wlc)) @@ -3225,7 +3242,9 @@ static inline u32 wlc_intstatus(struct wlc_info *wlc, bool in_isr) R_REG(osh, ®s->intctrlregs[RX_TXSTATUS_FIFO]. intstatus); - WL_TRACE(("wl%d: intstatus_rxfifo 0x%x, intstatus_txsfifo 0x%x\n", wlc_hw->unit, intstatus_rxfifo, intstatus_txsfifo)); + WL_TRACE("wl%d: intstatus_rxfifo 0x%x, intstatus_txsfifo 0x%x\n", + wlc_hw->unit, + intstatus_rxfifo, intstatus_txsfifo); /* defer unsolicited interrupt hints */ intstatus_rxfifo &= DEF_RXINTMASK; @@ -3301,7 +3320,7 @@ bool BCMFASTPATH wlc_isr(struct wlc_info *wlc, bool *wantdpc) macintstatus = wlc_intstatus(wlc, true); if (macintstatus == 0xffffffff) - WL_ERROR(("DEVICEREMOVED detected in the ISR code path.\n")); + WL_ERROR("DEVICEREMOVED detected in the ISR code path\n"); /* it is not for us */ if (macintstatus == 0) @@ -3325,7 +3344,7 @@ static bool wlc_bmac_txstatus_corerev4(struct wlc_hw_info *wlc_hw) struct osl_info *osh; bool fatal = false; - WL_TRACE(("wl%d: wlc_txstatusrecv\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_txstatusrecv\n", wlc_hw->unit); osh = wlc_hw->osh; @@ -3378,7 +3397,7 @@ wlc_bmac_txstatus(struct wlc_hw_info *wlc_hw, bool bound, bool *fatal) bool morepending = false; struct wlc_info *wlc = wlc_hw->wlc; - WL_TRACE(("wl%d: wlc_bmac_txstatus\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_txstatus\n", wlc_hw->unit); if (D11REV_IS(wlc_hw->corerev, 4)) { /* to retire soon */ @@ -3403,8 +3422,8 @@ wlc_bmac_txstatus(struct wlc_hw_info *wlc_hw, bool bound, bool *fatal) && (s1 = R_REG(osh, ®s->frmtxstatus)) & TXS_V) { if (s1 == 0xffffffff) { - WL_ERROR(("wl%d: %s: dead chip\n", - wlc_hw->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", + wlc_hw->unit, __func__); ASSERT(s1 != 0xffffffff); return morepending; } @@ -3444,8 +3463,8 @@ void wlc_suspend_mac_and_wait(struct wlc_info *wlc) u32 mc, mi; struct osl_info *osh; - WL_TRACE(("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n", wlc_hw->unit, - wlc_hw->band->bandunit)); + WL_TRACE("wl%d: wlc_suspend_mac_and_wait: bandunit %d\n", + wlc_hw->unit, wlc_hw->band->bandunit); /* * Track overlapping suspend requests @@ -3462,7 +3481,7 @@ void wlc_suspend_mac_and_wait(struct wlc_info *wlc) mc = R_REG(osh, ®s->maccontrol); if (mc == 0xffffffff) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__); wl_down(wlc->wl); return; } @@ -3472,7 +3491,7 @@ void wlc_suspend_mac_and_wait(struct wlc_info *wlc) mi = R_REG(osh, ®s->macintstatus); if (mi == 0xffffffff) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__); wl_down(wlc->wl); return; } @@ -3484,15 +3503,18 @@ void wlc_suspend_mac_and_wait(struct wlc_info *wlc) WLC_MAX_MAC_SUSPEND); if (!(R_REG(osh, ®s->macintstatus) & MI_MACSSPNDD)) { - WL_ERROR(("wl%d: wlc_suspend_mac_and_wait: waited %d uS and " - "MI_MACSSPNDD is still not on.\n", - wlc_hw->unit, WLC_MAX_MAC_SUSPEND)); - WL_ERROR(("wl%d: psmdebug 0x%08x, phydebug 0x%08x, psm_brc 0x%04x\n", wlc_hw->unit, R_REG(osh, ®s->psmdebug), R_REG(osh, ®s->phydebug), R_REG(osh, ®s->psm_brc))); + WL_ERROR("wl%d: wlc_suspend_mac_and_wait: waited %d uS and MI_MACSSPNDD is still not on.\n", + wlc_hw->unit, WLC_MAX_MAC_SUSPEND); + WL_ERROR("wl%d: psmdebug 0x%08x, phydebug 0x%08x, psm_brc 0x%04x\n", + wlc_hw->unit, + R_REG(osh, ®s->psmdebug), + R_REG(osh, ®s->phydebug), + R_REG(osh, ®s->psm_brc)); } mc = R_REG(osh, ®s->maccontrol); if (mc == 0xffffffff) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc_hw->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc_hw->unit, __func__); wl_down(wlc->wl); return; } @@ -3508,8 +3530,8 @@ void wlc_enable_mac(struct wlc_info *wlc) u32 mc, mi; struct osl_info *osh; - WL_TRACE(("wl%d: wlc_enable_mac: bandunit %d\n", wlc_hw->unit, - wlc->band->bandunit)); + WL_TRACE("wl%d: wlc_enable_mac: bandunit %d\n", + wlc_hw->unit, wlc->band->bandunit); /* * Track overlapping suspend requests @@ -3671,7 +3693,7 @@ bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw) volatile u16 *reg16; struct osl_info *osh; - WL_TRACE(("wl%d: validate_chip_access\n", wlc_hw->unit)); + WL_TRACE("wl%d: validate_chip_access\n", wlc_hw->unit); regs = wlc_hw->regs; osh = wlc_hw->osh; @@ -3691,7 +3713,8 @@ bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw) (void)R_REG(osh, ®s->objaddr); val = R_REG(osh, ®s->objdata); if (val != (u32) 0xaa5555aa) { - WL_ERROR(("wl%d: validate_chip_access: SHM = 0x%x, expected 0xaa5555aa\n", wlc_hw->unit, val)); + WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0xaa5555aa\n", + wlc_hw->unit, val); return false; } @@ -3703,7 +3726,8 @@ bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw) (void)R_REG(osh, ®s->objaddr); val = R_REG(osh, ®s->objdata); if (val != (u32) 0x55aaaa55) { - WL_ERROR(("wl%d: validate_chip_access: SHM = 0x%x, expected 0x55aaaa55\n", wlc_hw->unit, val)); + WL_ERROR("wl%d: validate_chip_access: SHM = 0x%x, expected 0x55aaaa55\n", + wlc_hw->unit, val); return false; } @@ -3733,12 +3757,14 @@ bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw) /* verify with the 16 bit registers that have no side effects */ val = R_REG(osh, ®s->tsf_cfpstrt_l); if (val != (uint) 0xBBBB) { - WL_ERROR(("wl%d: validate_chip_access: tsf_cfpstrt_l = 0x%x, expected" " 0x%x\n", wlc_hw->unit, val, 0xBBBB)); + WL_ERROR("wl%d: validate_chip_access: tsf_cfpstrt_l = 0x%x, expected 0x%x\n", + wlc_hw->unit, val, 0xBBBB); return false; } val = R_REG(osh, ®s->tsf_cfpstrt_h); if (val != (uint) 0xCCCC) { - WL_ERROR(("wl%d: validate_chip_access: tsf_cfpstrt_h = 0x%x, expected" " 0x%x\n", wlc_hw->unit, val, 0xCCCC)); + WL_ERROR("wl%d: validate_chip_access: tsf_cfpstrt_h = 0x%x, expected 0x%x\n", + wlc_hw->unit, val, 0xCCCC); return false; } @@ -3750,7 +3776,10 @@ bool wlc_bmac_validate_chip_access(struct wlc_hw_info *wlc_hw) w = R_REG(osh, ®s->maccontrol); if ((w != (MCTL_IHR_EN | MCTL_WAKE)) && (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) { - WL_ERROR(("wl%d: validate_chip_access: maccontrol = 0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w, (MCTL_IHR_EN | MCTL_WAKE), (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))); + WL_ERROR("wl%d: validate_chip_access: maccontrol = 0x%x, expected 0x%x or 0x%x\n", + wlc_hw->unit, w, + (MCTL_IHR_EN | MCTL_WAKE), + (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE)); return false; } @@ -3765,7 +3794,7 @@ void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on) struct osl_info *osh; u32 tmp; - WL_TRACE(("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw->unit)); + WL_TRACE("wl%d: wlc_bmac_core_phypll_ctl\n", wlc_hw->unit); tmp = 0; regs = wlc_hw->regs; @@ -3786,8 +3815,8 @@ void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on) tmp = R_REG(osh, ®s->clk_ctl_st); if ((tmp & (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT)) { - WL_ERROR(("%s: turn on PHY PLL failed\n", - __func__)); + WL_ERROR("%s: turn on PHY PLL failed\n", + __func__); ASSERT(0); } } else { @@ -3804,8 +3833,8 @@ void wlc_bmac_core_phypll_ctl(struct wlc_hw_info *wlc_hw, bool on) (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) != (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) { - WL_ERROR(("%s: turn on PHY PLL failed\n", - __func__)); + WL_ERROR("%s: turn on PHY PLL failed\n", + __func__); ASSERT(0); } } @@ -3822,7 +3851,7 @@ void wlc_coredisable(struct wlc_hw_info *wlc_hw) { bool dev_gone; - WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__); ASSERT(!wlc_hw->up); @@ -3860,7 +3889,7 @@ void wlc_coredisable(struct wlc_hw_info *wlc_hw) /* power both the pll and external oscillator on/off */ void wlc_bmac_xtal(struct wlc_hw_info *wlc_hw, bool want) { - WL_TRACE(("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw->unit, want)); + WL_TRACE("wl%d: wlc_bmac_xtal: want %d\n", wlc_hw->unit, want); /* dont power down if plldown is false or we must poll hw radio disable */ if (!want && wlc_hw->pllreq) @@ -3889,8 +3918,8 @@ static void wlc_flushqueues(struct wlc_info *wlc) if (wlc_hw->di[i]) { dma_txreclaim(wlc_hw->di[i], HNDDMA_RANGE_ALL); TXPKTPENDCLR(wlc, i); - WL_TRACE(("wlc_flushqueues: pktpend fifo %d cleared\n", - i)); + WL_TRACE("wlc_flushqueues: pktpend fifo %d cleared\n", + i); } /* free any posted rx packets */ @@ -4023,8 +4052,8 @@ wlc_bmac_copyfrom_objmem(struct wlc_hw_info *wlc_hw, uint offset, void *buf, void wlc_bmac_copyfrom_vars(struct wlc_hw_info *wlc_hw, char **buf, uint *len) { - WL_TRACE(("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n", - wlc_hw->vars_size)); + WL_TRACE("wlc_bmac_copyfrom_vars, nvram vars totlen=%d\n", + wlc_hw->vars_size); *buf = wlc_hw->vars; *len = wlc_hw->vars_size; @@ -4133,7 +4162,7 @@ void wlc_gpio_fast_deinit(struct wlc_hw_info *wlc_hw) (wlc_hw->sih->buscorerev >= 13))))) return; - WL_TRACE(("wl%d: %s\n", wlc_hw->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc_hw->unit, __func__); return; } diff --git a/drivers/staging/brcm80211/sys/wlc_channel.c b/drivers/staging/brcm80211/sys/wlc_channel.c index 33041e36585c..a35c15214880 100644 --- a/drivers/staging/brcm80211/sys/wlc_channel.c +++ b/drivers/staging/brcm80211/sys/wlc_channel.c @@ -567,8 +567,8 @@ struct chan20_info chan20_info[] = { const locale_info_t *wlc_get_locale_2g(u8 locale_idx) { if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) { - WL_ERROR(("%s: locale 2g index size out of range %d\n", - __func__, locale_idx)); + WL_ERROR("%s: locale 2g index size out of range %d\n", + __func__, locale_idx); ASSERT(locale_idx < ARRAY_SIZE(g_locale_2g_table)); return NULL; } @@ -578,8 +578,8 @@ const locale_info_t *wlc_get_locale_2g(u8 locale_idx) const locale_info_t *wlc_get_locale_5g(u8 locale_idx) { if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) { - WL_ERROR(("%s: locale 5g index size out of range %d\n", - __func__, locale_idx)); + WL_ERROR("%s: locale 5g index size out of range %d\n", + __func__, locale_idx); ASSERT(locale_idx < ARRAY_SIZE(g_locale_5g_table)); return NULL; } @@ -589,8 +589,8 @@ const locale_info_t *wlc_get_locale_5g(u8 locale_idx) const locale_mimo_info_t *wlc_get_mimo_2g(u8 locale_idx) { if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) { - WL_ERROR(("%s: mimo 2g index size out of range %d\n", __func__, - locale_idx)); + WL_ERROR("%s: mimo 2g index size out of range %d\n", + __func__, locale_idx); return NULL; } return g_mimo_2g_table[locale_idx]; @@ -599,8 +599,8 @@ const locale_mimo_info_t *wlc_get_mimo_2g(u8 locale_idx) const locale_mimo_info_t *wlc_get_mimo_5g(u8 locale_idx) { if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) { - WL_ERROR(("%s: mimo 5g index size out of range %d\n", __func__, - locale_idx)); + WL_ERROR("%s: mimo 5g index size out of range %d\n", + __func__, locale_idx); return NULL; } return g_mimo_5g_table[locale_idx]; @@ -614,11 +614,11 @@ wlc_cm_info_t *wlc_channel_mgr_attach(struct wlc_info *wlc) struct wlc_pub *pub = wlc->pub; char *ccode; - WL_TRACE(("wl%d: wlc_channel_mgr_attach\n", wlc->pub->unit)); + WL_TRACE("wl%d: wlc_channel_mgr_attach\n", wlc->pub->unit); wlc_cm = kzalloc(sizeof(wlc_cm_info_t), GFP_ATOMIC); if (wlc_cm == NULL) { - WL_ERROR(("wl%d: %s: out of memory", pub->unit, __func__)); + WL_ERROR("wl%d: %s: out of memory", pub->unit, __func__); return NULL; } wlc_cm->pub = pub; @@ -629,8 +629,9 @@ wlc_cm_info_t *wlc_channel_mgr_attach(struct wlc_info *wlc) ccode = getvar(wlc->pub->vars, "ccode"); if (ccode) { strncpy(wlc->pub->srom_ccode, ccode, WLC_CNTRY_BUF_SZ - 1); - WL_NONE(("%s: SROM country code is %c%c\n", __func__, - wlc->pub->srom_ccode[0], wlc->pub->srom_ccode[1])); + WL_NONE("%s: SROM country code is %c%c\n", + __func__, + wlc->pub->srom_ccode[0], wlc->pub->srom_ccode[1]); } /* internal country information which must match regulatory constraints in firmware */ @@ -716,7 +717,9 @@ wlc_set_countrycode_rev(wlc_cm_info_t *wlc_cm, char mapped_ccode[WLC_CNTRY_BUF_SZ]; uint mapped_regrev; - WL_NONE(("%s: (country_abbrev \"%s\", ccode \"%s\", regrev %d) SPROM \"%s\"/%u\n", __func__, country_abbrev, ccode, regrev, wlc_cm->srom_ccode, wlc_cm->srom_regrev)); + WL_NONE("%s: (country_abbrev \"%s\", ccode \"%s\", regrev %d) SPROM \"%s\"/%u\n", + __func__, country_abbrev, ccode, regrev, + wlc_cm->srom_ccode, wlc_cm->srom_regrev); /* if regrev is -1, lookup the mapped country code, * otherwise use the ccode and regrev directly @@ -827,8 +830,8 @@ static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm, /* check for currently supported ccode size */ if (strlen(ccode) > (WLC_CNTRY_BUF_SZ - 1)) { - WL_ERROR(("wl%d: %s: ccode \"%s\" too long for match\n", - wlc->pub->unit, __func__, ccode)); + WL_ERROR("wl%d: %s: ccode \"%s\" too long for match\n", + wlc->pub->unit, __func__, ccode); return NULL; } @@ -843,7 +846,7 @@ static const country_info_t *wlc_countrycode_map(wlc_cm_info_t *wlc_cm, if (!strcmp(srom_ccode, ccode)) { *mapped_regrev = srom_regrev; mapped = 0; - WL_ERROR(("srom_code == ccode %s\n", __func__)); + WL_ERROR("srom_code == ccode %s\n", __func__); ASSERT(0); } else { mapped = @@ -895,7 +898,7 @@ static const country_info_t *wlc_country_lookup_direct(const char *ccode, } } - WL_ERROR(("%s: Returning NULL\n", __func__)); + WL_ERROR("%s: Returning NULL\n", __func__); ASSERT(0); return NULL; } @@ -974,7 +977,9 @@ static void wlc_channels_commit(wlc_cm_info_t *wlc_cm) if (chan == INVCHANNEL) { /* country/locale with no valid channels, set the radio disable bit */ mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); - WL_ERROR(("wl%d: %s: no valid channel for \"%s\" nbands %d bandlocked %d\n", wlc->pub->unit, __func__, wlc_cm->country_abbrev, NBANDS(wlc), wlc->bandlocked)); + WL_ERROR("wl%d: %s: no valid channel for \"%s\" nbands %d bandlocked %d\n", + wlc->pub->unit, __func__, + wlc_cm->country_abbrev, NBANDS(wlc), wlc->bandlocked); } else if (mboolisset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE)) { @@ -1538,8 +1543,8 @@ wlc_valid_chanspec_ext(wlc_cm_info_t *wlc_cm, chanspec_t chspec, bool dualband) /* check the chanspec */ if (wf_chspec_malformed(chspec)) { - WL_ERROR(("wl%d: malformed chanspec 0x%x\n", wlc->pub->unit, - chspec)); + WL_ERROR("wl%d: malformed chanspec 0x%x\n", + wlc->pub->unit, chspec); ASSERT(0); return false; } diff --git a/drivers/staging/brcm80211/sys/wlc_event.c b/drivers/staging/brcm80211/sys/wlc_event.c index 9b503d839aae..dabd7094cd73 100644 --- a/drivers/staging/brcm80211/sys/wlc_event.c +++ b/drivers/staging/brcm80211/sys/wlc_event.c @@ -75,8 +75,8 @@ wlc_eventq_t *wlc_eventq_attach(struct wlc_pub *pub, struct wlc_info *wlc, eq->timer = wl_init_timer(eq->wl, wlc_timer_cb, eq, "eventq"); if (!eq->timer) { - WL_ERROR(("wl%d: wlc_eventq_attach: timer failed\n", - pub->unit)); + WL_ERROR("wl%d: wlc_eventq_attach: timer failed\n", + pub->unit); kfree(eq); return NULL; } diff --git a/drivers/staging/brcm80211/sys/wlc_mac80211.c b/drivers/staging/brcm80211/sys/wlc_mac80211.c index 8a89b5fe8e60..1d5d01ac0a9b 100644 --- a/drivers/staging/brcm80211/sys/wlc_mac80211.c +++ b/drivers/staging/brcm80211/sys/wlc_mac80211.c @@ -306,7 +306,7 @@ void wlc_get_rcmta(struct wlc_info *wlc, int idx, struct ether_addr *addr) u32 v32; struct osl_info *osh; - WL_TRACE(("wl%d: %s\n", WLCWLUNIT(wlc), __func__)); + WL_TRACE("wl%d: %s\n", WLCWLUNIT(wlc), __func__); ASSERT(wlc->pub->corerev > 4); @@ -364,7 +364,7 @@ bool wlc_ps_allowed(struct wlc_info *wlc) void wlc_reset(struct wlc_info *wlc) { - WL_TRACE(("wl%d: wlc_reset\n", wlc->pub->unit)); + WL_TRACE("wl%d: wlc_reset\n", wlc->pub->unit); wlc->check_for_unaligned_tbtt = false; @@ -385,7 +385,7 @@ void wlc_reset(struct wlc_info *wlc) void wlc_fatal_error(struct wlc_info *wlc) { - WL_ERROR(("wl%d: fatal error, reinitializing\n", wlc->pub->unit)); + WL_ERROR("wl%d: fatal error, reinitializing\n", wlc->pub->unit); wl_init(wlc->wl); } @@ -426,7 +426,7 @@ void wlc_init(struct wlc_info *wlc) wlc_bsscfg_t *bsscfg; bool mute = false; - WL_TRACE(("wl%d: wlc_init\n", wlc->pub->unit)); + WL_TRACE("wl%d: wlc_init\n", wlc->pub->unit); regs = wlc->regs; @@ -605,8 +605,8 @@ bool wlc_ps_check(struct wlc_info *wlc) * to avoid assert */ if (tmp == 0xffffffff) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, - __func__)); + WL_ERROR("wl%d: %s: dead chip\n", + wlc->pub->unit, __func__); return DEVICEREMOVED(wlc); } @@ -615,7 +615,8 @@ bool wlc_ps_check(struct wlc_info *wlc) if (hps != ((tmp & MCTL_HPS) != 0)) { int idx; wlc_bsscfg_t *cfg; - WL_ERROR(("wl%d: hps not sync, sw %d, maccontrol 0x%x\n", wlc->pub->unit, hps, tmp)); + WL_ERROR("wl%d: hps not sync, sw %d, maccontrol 0x%x\n", + wlc->pub->unit, hps, tmp); FOREACH_BSS(wlc, idx, cfg) { if (!BSSCFG_STA(cfg)) continue; @@ -629,7 +630,8 @@ bool wlc_ps_check(struct wlc_info *wlc) wake = STAY_AWAKE(wlc) || wlc->hw->wake_override; wake_ok = (wake == ((tmp & MCTL_WAKE) != 0)); if (hps && !wake_ok) { - WL_ERROR(("wl%d: wake not sync, sw %d maccontrol 0x%x\n", wlc->pub->unit, wake, tmp)); + WL_ERROR("wl%d: wake not sync, sw %d maccontrol 0x%x\n", + wlc->pub->unit, wake, tmp); res = false; } } @@ -647,8 +649,8 @@ void wlc_set_ps_ctrl(struct wlc_info *wlc) hps = PS_ALLOWED(wlc); wake = hps ? (STAY_AWAKE(wlc)) : true; - WL_TRACE(("wl%d: wlc_set_ps_ctrl: hps %d wake %d\n", wlc->pub->unit, - hps, wake)); + WL_TRACE("wl%d: wlc_set_ps_ctrl: hps %d wake %d\n", + wlc->pub->unit, hps, wake); v1 = R_REG(wlc->osh, &wlc->regs->maccontrol); v2 = 0; @@ -806,8 +808,8 @@ void wlc_set_chanspec(struct wlc_info *wlc, chanspec_t chanspec) chanspec_t old_chanspec = wlc->chanspec; if (!wlc_valid_chanspec_db(wlc->cmi, chanspec)) { - WL_ERROR(("wl%d: %s: Bad channel %d\n", - wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec))); + WL_ERROR("wl%d: %s: Bad channel %d\n", + wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)); ASSERT(wlc_valid_chanspec_db(wlc->cmi, chanspec)); return; } @@ -818,7 +820,9 @@ void wlc_set_chanspec(struct wlc_info *wlc, chanspec_t chanspec) if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) { switchband = true; if (wlc->bandlocked) { - WL_ERROR(("wl%d: %s: chspec %d band is locked!\n", wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec))); + WL_ERROR("wl%d: %s: chspec %d band is locked!\n", + wlc->pub->unit, __func__, + CHSPEC_CHANNEL(chanspec)); return; } /* BMAC_NOTE: should the setband call come after the wlc_bmac_chanspec() ? @@ -1120,7 +1124,7 @@ void wlc_beacon_phytxctl_txant_upd(struct wlc_info *wlc, ratespec_t bcn_rspec) */ void wlc_protection_upd(struct wlc_info *wlc, uint idx, int val) { - WL_TRACE(("wlc_protection_upd: idx %d, val %d\n", idx, val)); + WL_TRACE("wlc_protection_upd: idx %d, val %d\n", idx, val); switch (idx) { case WLC_PROT_G_SPEC: @@ -1228,7 +1232,7 @@ static void wlc_bandinit_ordered(struct wlc_info *wlc, chanspec_t chanspec) uint parkband; uint i, band_order[2]; - WL_TRACE(("wl%d: wlc_bandinit_ordered\n", wlc->pub->unit)); + WL_TRACE("wl%d: wlc_bandinit_ordered\n", wlc->pub->unit); /* * We might have been bandlocked during down and the chip power-cycled (hibernate). * figure out the right band to park on @@ -1271,8 +1275,8 @@ static void wlc_bandinit_ordered(struct wlc_info *wlc, chanspec_t chanspec) /* band-specific init */ static void WLBANDINITFN(wlc_bsinit) (struct wlc_info *wlc) { - WL_TRACE(("wl%d: wlc_bsinit: bandunit %d\n", wlc->pub->unit, - wlc->band->bandunit)); + WL_TRACE("wl%d: wlc_bsinit: bandunit %d\n", + wlc->pub->unit, wlc->band->bandunit); /* write ucode ACK/CTS rate table */ wlc_set_ratetable(wlc); @@ -1348,7 +1352,7 @@ void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg, bool suspend) /* Only apply params if the core is out of reset and has clocks */ if (!wlc->clk) { - WL_ERROR(("wl%d: %s : no-clock\n", wlc->pub->unit, __func__)); + WL_ERROR("wl%d: %s : no-clock\n", wlc->pub->unit, __func__); return; } @@ -1380,8 +1384,8 @@ void wlc_wme_setparams(struct wlc_info *wlc, u16 aci, void *arg, bool suspend) if (acp_shm.aifs < EDCF_AIFSN_MIN || acp_shm.aifs > EDCF_AIFSN_MAX) { - WL_ERROR(("wl%d: wlc_edcf_setparams: bad aifs %d\n", - wlc->pub->unit, acp_shm.aifs)); + WL_ERROR("wl%d: wlc_edcf_setparams: bad aifs %d\n", + wlc->pub->unit, acp_shm.aifs); continue; } @@ -1464,8 +1468,8 @@ void wlc_edcf_setparams(wlc_bsscfg_t *cfg, bool suspend) if (acp_shm.aifs < EDCF_AIFSN_MIN || acp_shm.aifs > EDCF_AIFSN_MAX) { - WL_ERROR(("wl%d: wlc_edcf_setparams: bad aifs %d\n", - wlc->pub->unit, acp_shm.aifs)); + WL_ERROR("wl%d: wlc_edcf_setparams: bad aifs %d\n", + wlc->pub->unit, acp_shm.aifs); continue; } @@ -1512,15 +1516,14 @@ bool wlc_timers_init(struct wlc_info *wlc, int unit) wlc->wdtimer = wl_init_timer(wlc->wl, wlc_watchdog_by_timer, wlc, "watchdog"); if (!wlc->wdtimer) { - WL_ERROR(("wl%d: wl_init_timer for wdtimer failed\n", unit)); + WL_ERROR("wl%d: wl_init_timer for wdtimer failed\n", unit); goto fail; } wlc->radio_timer = wl_init_timer(wlc->wl, wlc_radio_timer, wlc, "radio"); if (!wlc->radio_timer) { - WL_ERROR(("wl%d: wl_init_timer for radio_timer failed\n", - unit)); + WL_ERROR("wl%d: wl_init_timer for radio_timer failed\n", unit); goto fail; } @@ -1667,15 +1670,14 @@ static uint wlc_attach_module(struct wlc_info *wlc) wlc->asi = wlc_antsel_attach(wlc, wlc->osh, wlc->pub, wlc->hw); if (wlc->asi == NULL) { - WL_ERROR(("wl%d: wlc_attach: wlc_antsel_attach failed\n", - unit)); + WL_ERROR("wl%d: wlc_attach: wlc_antsel_attach failed\n", unit); err = 44; goto fail; } wlc->ampdu = wlc_ampdu_attach(wlc); if (wlc->ampdu == NULL) { - WL_ERROR(("wl%d: wlc_attach: wlc_ampdu_attach failed\n", unit)); + WL_ERROR("wl%d: wlc_attach: wlc_ampdu_attach failed\n", unit); err = 50; goto fail; } @@ -1684,13 +1686,13 @@ static uint wlc_attach_module(struct wlc_info *wlc) wlc->eventq = wlc_eventq_attach(wlc->pub, wlc, wlc->wl, wlc_process_eventq); if (wlc->eventq == NULL) { - WL_ERROR(("wl%d: wlc_attach: wlc_eventq_attachfailed\n", unit)); + WL_ERROR("wl%d: wlc_attach: wlc_eventq_attachfailed\n", unit); err = 57; goto fail; } if ((wlc_stf_attach(wlc) != 0)) { - WL_ERROR(("wl%d: wlc_attach: wlc_stf_attach failed\n", unit)); + WL_ERROR("wl%d: wlc_attach: wlc_stf_attach failed\n", unit); err = 68; goto fail; } @@ -1719,8 +1721,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, wlc_txq_info_t *qi; uint n_disabled; - WL_NONE(("wl%d: %s: vendor 0x%x device 0x%x\n", unit, __func__, vendor, - device)); + WL_NONE("wl%d: %s: vendor 0x%x device 0x%x\n", + unit, __func__, vendor, device); ASSERT(WSEC_MAX_RCMTA_KEYS <= WSEC_MAX_KEYS); ASSERT(WSEC_MAX_DEFAULT_KEYS == WLC_DEFAULT_KEYS); @@ -1897,7 +1899,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, goto fail; if (!wlc_timers_init(wlc, unit)) { - WL_ERROR(("wl%d: %s: wlc_init_timer failed\n", unit, __func__)); + WL_ERROR("wl%d: %s: wlc_init_timer failed\n", unit, __func__); err = 32; goto fail; } @@ -1905,8 +1907,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, /* depend on rateset, gmode */ wlc->cmi = wlc_channel_mgr_attach(wlc); if (!wlc->cmi) { - WL_ERROR(("wl%d: %s: wlc_channel_mgr_attach failed\n", unit, - __func__)); + WL_ERROR("wl%d: %s: wlc_channel_mgr_attach failed\n", + unit, __func__); err = 33; goto fail; } @@ -1921,8 +1923,8 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, /* allocate our initial queue */ qi = wlc_txq_alloc(wlc, osh); if (qi == NULL) { - WL_ERROR(("wl%d: %s: failed to malloc tx queue\n", unit, - __func__)); + WL_ERROR("wl%d: %s: failed to malloc tx queue\n", + unit, __func__); err = 100; goto fail; } @@ -2008,7 +2010,7 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode, return (void *)wlc; fail: - WL_ERROR(("wl%d: %s: failed with err %d\n", unit, __func__, err)); + WL_ERROR("wl%d: %s: failed with err %d\n", unit, __func__, err); if (wlc) wlc_detach(wlc); @@ -2026,7 +2028,8 @@ static void wlc_attach_antgain_init(struct wlc_info *wlc) /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */ wlc->band->antgain = 8; } else if (wlc->band->antgain == -1) { - WL_ERROR(("wl%d: %s: Invalid antennas available in srom, using 2dB\n", unit, __func__)); + WL_ERROR("wl%d: %s: Invalid antennas available in srom, using 2dB\n", + unit, __func__); wlc->band->antgain = 8; } else { s8 gain, fract; @@ -2065,7 +2068,8 @@ static bool wlc_attach_stf_ant_init(struct wlc_info *wlc) aa = (s8) getintvar(vars, (BAND_5G(bandtype) ? "aa1" : "aa0")); if ((aa < 1) || (aa > 15)) { - WL_ERROR(("wl%d: %s: Invalid antennas available in srom (0x%x), using 3.\n", unit, __func__, aa)); + WL_ERROR("wl%d: %s: Invalid antennas available in srom (0x%x), using 3\n", + unit, __func__, aa); aa = 3; } @@ -2132,7 +2136,7 @@ uint wlc_detach(struct wlc_info *wlc) if (wlc == NULL) return 0; - WL_TRACE(("wl%d: %s\n", wlc->pub->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc->pub->unit, __func__); ASSERT(!wlc->pub->up); @@ -2340,7 +2344,7 @@ static void wlc_radio_timer(void *arg) struct wlc_info *wlc = (struct wlc_info *) arg; if (DEVICEREMOVED(wlc)) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc->pub->unit, __func__); wl_down(wlc->wl); return; } @@ -2441,13 +2445,13 @@ static void wlc_watchdog(void *arg) int i; wlc_bsscfg_t *cfg; - WL_TRACE(("wl%d: wlc_watchdog\n", wlc->pub->unit)); + WL_TRACE("wl%d: wlc_watchdog\n", wlc->pub->unit); if (!wlc->pub->up) return; if (DEVICEREMOVED(wlc)) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc->pub->unit, __func__); wl_down(wlc->wl); return; } @@ -2519,7 +2523,7 @@ static void wlc_watchdog(void *arg) /* make interface operational */ int wlc_up(struct wlc_info *wlc) { - WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc->pub->unit, __func__); /* HW is turned off so don't try to access it */ if (wlc->pub->hw_off || DEVICEREMOVED(wlc)) @@ -2564,7 +2568,8 @@ int wlc_up(struct wlc_info *wlc) if (!BSSCFG_STA(bsscfg) || !bsscfg->enable || !bsscfg->BSS) continue; - WL_ERROR(("wl%d.%d: wlc_up: rfdisable -> " "wlc_bsscfg_disable()\n", wlc->pub->unit, idx)); + WL_ERROR("wl%d.%d: wlc_up: rfdisable -> " "wlc_bsscfg_disable()\n", + wlc->pub->unit, idx); } } } else @@ -2664,12 +2669,12 @@ uint wlc_down(struct wlc_info *wlc) bool dev_gone = false; wlc_txq_info_t *qi; - WL_TRACE(("wl%d: %s:\n", wlc->pub->unit, __func__)); + WL_TRACE("wl%d: %s:\n", wlc->pub->unit, __func__); /* check if we are already in the going down path */ if (wlc->going_down) { - WL_ERROR(("wl%d: %s: Driver going down so return\n", - wlc->pub->unit, __func__)); + WL_ERROR("wl%d: %s: Driver going down so return\n", + wlc->pub->unit, __func__); return 0; } if (!wlc->pub->up) @@ -2728,8 +2733,8 @@ uint wlc_down(struct wlc_info *wlc) /* Verify all packets are flushed from the driver */ if (wlc->osh->pktalloced != 0) { - WL_ERROR(("%d packets not freed at wlc_down!!!!!!\n", - wlc->osh->pktalloced)); + WL_ERROR("%d packets not freed at wlc_down!!!!!!\n", + wlc->osh->pktalloced); } #ifdef BCMDBG /* Since all the packets should have been freed, @@ -2826,8 +2831,8 @@ int wlc_set_gmode(struct wlc_info *wlc, u8 gmode, bool config) default: /* Error */ - WL_ERROR(("wl%d: %s: invalid gmode %d\n", wlc->pub->unit, - __func__, gmode)); + WL_ERROR("wl%d: %s: invalid gmode %d\n", + wlc->pub->unit, __func__, gmode); return BCME_UNSUPPORTED; } @@ -3082,7 +3087,7 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, /* If the device is turned off, then it's not "removed" */ if (!wlc->pub->hw_off && DEVICEREMOVED(wlc)) { - WL_ERROR(("wl%d: %s: dead chip\n", wlc->pub->unit, __func__)); + WL_ERROR("wl%d: %s: dead chip\n", wlc->pub->unit, __func__); wl_down(wlc->wl); return BCME_ERROR; } @@ -3102,8 +3107,8 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, bool_val = val != 0; if (cmd != WLC_SET_CHANNEL) - WL_NONE(("WLC_IOCTL: cmd %d val 0x%x (%d) len %d\n", cmd, - (uint) val, val, len)); + WL_NONE("WLC_IOCTL: cmd %d val 0x%x (%d) len %d\n", + cmd, (uint)val, val, len); bcmerror = 0; regs = wlc->regs; @@ -3123,8 +3128,8 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, default: if ((arg == NULL) || (len <= 0)) { - WL_ERROR(("wl%d: %s: Command %d needs arguments\n", - wlc->pub->unit, __func__, cmd)); + WL_ERROR("wl%d: %s: Command %d needs arguments\n", + wlc->pub->unit, __func__, cmd); bcmerror = BCME_BADARG; goto done; } @@ -3457,8 +3462,8 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, /* 4322 supports antdiv in phy, no need to set it to ucode */ if (WLCISNPHY(wlc->band) && D11REV_IS(wlc->pub->corerev, 16)) { - WL_ERROR(("wl%d: can't set ucantdiv for 4322\n", - wlc->pub->unit)); + WL_ERROR("wl%d: can't set ucantdiv for 4322\n", + wlc->pub->unit); bcmerror = BCME_UNSUPPORTED; } else wlc_mhf(wlc, MHF1, MHF1_ANTDIV, @@ -3555,8 +3560,8 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, if ((radiomask == 0) || (radiomask & ~validbits) || (radioval & ~validbits) || ((radioval & ~radiomask) != 0)) { - WL_ERROR(("SET_RADIO with wrong bits 0x%x\n", - val)); + WL_ERROR("SET_RADIO with wrong bits 0x%x\n", + val); bcmerror = BCME_RANGE; break; } @@ -4192,7 +4197,7 @@ _wlc_ioctl(struct wlc_info *wlc, int cmd, void *arg, int len, #endif case WLC_LAST: - WL_ERROR(("%s: WLC_LAST\n", __func__)); + WL_ERROR("%s: WLC_LAST\n", __func__); } done: @@ -4402,8 +4407,8 @@ wlc_iovar_op(struct wlc_info *wlc, const char *name, if (!set && (len == sizeof(int)) && !(IS_ALIGNED((unsigned long)(arg), (uint) sizeof(int)))) { - WL_ERROR(("wl%d: %s unaligned get ptr for %s\n", - wlc->pub->unit, __func__, name)); + WL_ERROR("wl%d: %s unaligned get ptr for %s\n", + wlc->pub->unit, __func__, name); ASSERT(0); } @@ -4530,7 +4535,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, bool bool_val2; wlc_bss_info_t *current_bss; - WL_TRACE(("wl%d: %s\n", wlc->pub->unit, __func__)); + WL_TRACE("wl%d: %s\n", wlc->pub->unit, __func__); bsscfg = NULL; current_bss = NULL; @@ -4553,8 +4558,8 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, bool_val = (int_val != 0) ? true : false; bool_val2 = (int_val2 != 0) ? true : false; - WL_TRACE(("wl%d: %s: id %d\n", wlc->pub->unit, __func__, - IOV_ID(actionid))); + WL_TRACE("wl%d: %s: id %d\n", + wlc->pub->unit, __func__, IOV_ID(actionid)); /* Do the actual parameter implementation */ switch (actionid) { @@ -4612,7 +4617,7 @@ wlc_doiovar(void *hdl, const bcm_iovar_t *vi, u32 actionid, break; default: - WL_ERROR(("wl%d: %s: unsupported\n", wlc->pub->unit, __func__)); + WL_ERROR("wl%d: %s: unsupported\n", wlc->pub->unit, __func__); err = BCME_UNSUPPORTED; break; } @@ -4747,8 +4752,8 @@ void wlc_statsupd(struct wlc_info *wlc) /* check for rx fifo 0 overflow */ delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl); if (delta) - WL_ERROR(("wl%d: %u rx fifo 0 overflows!\n", wlc->pub->unit, - delta)); + WL_ERROR("wl%d: %u rx fifo 0 overflows!\n", + wlc->pub->unit, delta); /* check for tx fifo underflows */ for (i = 0; i < NFIFO; i++) { @@ -4756,8 +4761,8 @@ void wlc_statsupd(struct wlc_info *wlc) (u16) (wlc->core->macstat_snapshot->txfunfl[i] - txfunfl[i]); if (delta) - WL_ERROR(("wl%d: %u tx fifo %d underflows!\n", - wlc->pub->unit, delta, i)); + WL_ERROR("wl%d: %u tx fifo %d underflows!\n", + wlc->pub->unit, delta, i); } #endif /* BCMDBG */ @@ -4806,7 +4811,7 @@ void wlc_statsupd(struct wlc_info *wlc) bool wlc_chipmatch(u16 vendor, u16 device) { if (vendor != VENDOR_BROADCOM) { - WL_ERROR(("wlc_chipmatch: unknown vendor id %04x\n", vendor)); + WL_ERROR("wlc_chipmatch: unknown vendor id %04x\n", vendor); return false; } @@ -4818,7 +4823,7 @@ bool wlc_chipmatch(u16 vendor, u16 device) if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID)) return true; - WL_ERROR(("wlc_chipmatch: unknown device id %04x\n", device)); + WL_ERROR("wlc_chipmatch: unknown device id %04x\n", device); return false; } @@ -5009,8 +5014,8 @@ wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q, struct sk_buff *pkt, p = pktq_peek_tail(q, &eprec); ASSERT(p != NULL); if (eprec > prec) { - WL_ERROR(("%s: Failing: eprec %d > prec %d\n", __func__, - eprec, prec)); + WL_ERROR("%s: Failing: eprec %d > prec %d\n", + __func__, eprec, prec); return false; } } @@ -5026,8 +5031,8 @@ wlc_prec_enq_head(struct wlc_info *wlc, struct pktq *q, struct sk_buff *pkt, /* Refuse newer packet unless configured to discard oldest */ if (eprec == prec && !discard_oldest) { - WL_ERROR(("%s: No where to go, prec == %d\n", __func__, - prec)); + WL_ERROR("%s: No where to go, prec == %d\n", + __func__, prec); return false; } @@ -5075,8 +5080,8 @@ void BCMFASTPATH wlc_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu, if (!wlc_prec_enq(wlc, q, sdu, prec)) { if (!EDCF_ENAB(wlc->pub) || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) - WL_ERROR(("wl%d: wlc_txq_enq: txq overflow\n", - wlc->pub->unit)); + WL_ERROR("wl%d: wlc_txq_enq: txq overflow\n", + wlc->pub->unit); /* ASSERT(9 == 8); *//* XXX we might hit this condtion in case packet flooding from mac80211 stack */ pkt_buf_free_skb(wlc->osh, sdu, true); @@ -5252,8 +5257,8 @@ wlc_txfifo(struct wlc_info *wlc, uint fifo, struct sk_buff *p, bool commit, */ if (commit) { TXPKTPENDINC(wlc, fifo, txpktpend); - WL_TRACE(("wlc_txfifo, pktpend inc %d to %d\n", txpktpend, - TXPKTPENDGET(wlc, fifo))); + WL_TRACE("wlc_txfifo, pktpend inc %d to %d\n", + txpktpend, TXPKTPENDGET(wlc, fifo)); } /* Commit BCMC sequence number in the SHM frame ID location */ @@ -5261,7 +5266,7 @@ wlc_txfifo(struct wlc_info *wlc, uint fifo, struct sk_buff *p, bool commit, BCMCFID(wlc, frameid); if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) { - WL_ERROR(("wlc_txfifo: fatal, toss frames !!!\n")); + WL_ERROR("wlc_txfifo: fatal, toss frames !!!\n"); } } @@ -5301,7 +5306,8 @@ wlc_compute_airtime(struct wlc_info *wlc, ratespec_t rspec, uint length) usec = (length << 3) / 11; break; default: - WL_ERROR(("wl%d: wlc_compute_airtime: unsupported rspec 0x%x\n", wlc->pub->unit, rspec)); + WL_ERROR("wl%d: wlc_compute_airtime: unsupported rspec 0x%x\n", + wlc->pub->unit, rspec); ASSERT((const char *)"Bad phy_rate" == NULL); break; } @@ -5397,7 +5403,7 @@ static void wlc_cck_plcp_set(int rate_500, uint length, u8 *plcp) break; default: - WL_ERROR(("wlc_cck_plcp_set: unsupported rate %d\n", rate_500)); + WL_ERROR("wlc_cck_plcp_set: unsupported rate %d\n", rate_500); rate_500 = WLC_RATE_1M; usec = length << 3; break; @@ -5537,7 +5543,8 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(struct wlc_info *wlc, ratespec_t rspec) bw = RSPEC_GET_BW(rspec); /* 10Mhz is not supported yet */ if (bw < PHY_TXC1_BW_20MHZ) { - WL_ERROR(("wlc_phytxctl1_calc: bw %d is not supported yet, set to 20L\n", bw)); + WL_ERROR("wlc_phytxctl1_calc: bw %d is not supported yet, set to 20L\n", + bw); bw = PHY_TXC1_BW_20MHZ; } @@ -5562,7 +5569,7 @@ u16 BCMFASTPATH wlc_phytxctl1_calc(struct wlc_info *wlc, ratespec_t rspec) /* get the phyctl byte from rate phycfg table */ phycfg = wlc_rate_legacy_phyctl(RSPEC2RATE(rspec)); if (phycfg == -1) { - WL_ERROR(("wlc_phytxctl1_calc: wrong legacy OFDM/CCK rate\n")); + WL_ERROR("wlc_phytxctl1_calc: wrong legacy OFDM/CCK rate\n"); ASSERT(0); phycfg = 0; } @@ -5722,8 +5729,8 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, /* non-AP STA should never use BCMC queue */ ASSERT(queue != TX_BCMC_FIFO); if (queue == TX_BCMC_FIFO) { - WL_ERROR(("wl%d: %s: ASSERT queue == TX_BCMC!\n", - WLCWLUNIT(wlc), __func__)); + WL_ERROR("wl%d: %s: ASSERT queue == TX_BCMC!\n", + WLCWLUNIT(wlc), __func__); frameid = bcmc_fid_generate(wlc, NULL, txh); } else { /* Increment the counter for first fragment */ @@ -5901,7 +5908,8 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) && (!IS_MCS(rspec[k]))) { - WL_ERROR(("wl%d: %s: IEEE80211_TX_RC_MCS != IS_MCS(rspec)\n", WLCWLUNIT(wlc), __func__)); + WL_ERROR("wl%d: %s: IEEE80211_TX_RC_MCS != IS_MCS(rspec)\n", + WLCWLUNIT(wlc), __func__); ASSERT(0 && "Rate mismatch"); } @@ -6295,12 +6303,16 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, } } } else - WL_ERROR(("wl%d: %s txop invalid for rate %d\n", - wlc->pub->unit, fifo_names[queue], - RSPEC2RATE(rspec[0]))); + WL_ERROR("wl%d: %s txop invalid for rate %d\n", + wlc->pub->unit, fifo_names[queue], + RSPEC2RATE(rspec[0])); if (dur > wlc->edcf_txop[ac]) - WL_ERROR(("wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", wlc->pub->unit, __func__, fifo_names[queue], phylen, wlc->fragthresh[queue], dur, wlc->edcf_txop[ac])); + WL_ERROR("wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", + wlc->pub->unit, __func__, + fifo_names[queue], + phylen, wlc->fragthresh[queue], + dur, wlc->edcf_txop[ac]); } } @@ -6406,8 +6418,8 @@ void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus) if (macintstatus & ~(MI_TBTT | MI_TXSTOP)) { bcm_format_flags(int_flags, macintstatus, flagstr, sizeof(flagstr)); - WL_TRACE(("wl%d: macintstatus 0x%x %s\n", wlc->pub->unit, - macintstatus, flagstr)); + WL_TRACE("wl%d: macintstatus 0x%x %s\n", + wlc->pub->unit, macintstatus, flagstr); } #endif /* BCMDBG */ @@ -6422,7 +6434,8 @@ void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus) wlc_tbtt(wlc, regs); if (macintstatus & MI_GP0) { - WL_ERROR(("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", wlc->pub->unit, wlc->pub->now)); + WL_ERROR("wl%d: PSM microcode watchdog fired at %d (seconds). Resetting.\n", + wlc->pub->unit, wlc->pub->now); printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", __func__, wlc->pub->sih->chip, @@ -6440,7 +6453,9 @@ void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus) } if (macintstatus & MI_RFDISABLE) { - WL_ERROR(("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", wlc->pub->unit, R_REG(wlc->osh, ®s->phydebug) & PDBG_RFD)); + WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", + wlc->pub->unit, + R_REG(wlc->osh, ®s->phydebug) & PDBG_RFD); /* delay the cleanup to wl_down in IBSS case */ if ((R_REG(wlc->osh, ®s->phydebug) & PDBG_RFD)) { int idx; @@ -6449,7 +6464,8 @@ void wlc_high_dpc(struct wlc_info *wlc, u32 macintstatus) if (!BSSCFG_STA(bsscfg) || !bsscfg->enable || !bsscfg->BSS) continue; - WL_ERROR(("wl%d: wlc_dpc: rfdisable -> wlc_bsscfg_disable()\n", wlc->pub->unit)); + WL_ERROR("wl%d: wlc_dpc: rfdisable -> wlc_bsscfg_disable()\n", + wlc->pub->unit); } } } @@ -6485,7 +6501,8 @@ static void *wlc_15420war(struct wlc_info *wlc, uint queue) if (dma_txactive(wlc->hw->di[queue]) == 0) { WLCNTINCR(wlc->pub->_cnt->txdmawar); if (!dma_txreset(di)) - WL_ERROR(("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", wlc->pub->unit, __func__, queue)); + WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n", + wlc->pub->unit, __func__, queue); dma_txinit(di); } return p; @@ -6538,7 +6555,7 @@ wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) ((txs-> status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT)); - WL_ERROR(("%s: INTERMEDIATE but not AMPDU\n", __func__)); + WL_ERROR("%s: INTERMEDIATE but not AMPDU\n", __func__); return false; } @@ -6563,8 +6580,8 @@ wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) mcl = ltoh16(txh->MacTxControlLow); if (txs->phyerr) { - WL_ERROR(("phyerr 0x%x, rate 0x%x\n", txs->phyerr, - txh->MainRates)); + WL_ERROR("phyerr 0x%x, rate 0x%x\n", + txs->phyerr, txh->MainRates); wlc_print_txdesc(txh); wlc_print_txstatus(txs); } @@ -6595,8 +6612,8 @@ wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) supr_status = txs->status & TX_STATUS_SUPR_MASK; if (supr_status == TX_STATUS_SUPR_BADCH) - WL_NONE(("%s: Pkt tx suppressed, possibly channel %d\n", - __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec))); + WL_NONE("%s: Pkt tx suppressed, possibly channel %d\n", + __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)); tx_rts = htol16(txh->MacTxControlLow) & TXC_SENDRTS; tx_frame_count = @@ -6607,7 +6624,7 @@ wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) lastframe = (fc & FC_MOREFRAG) == 0; if (!lastframe) { - WL_ERROR(("Not last frame!\n")); + WL_ERROR("Not last frame!\n"); } else { u16 sfbl, lfbl; ieee80211_tx_info_clear_status(tx_info); @@ -6658,8 +6675,8 @@ wlc_dotxstatus(struct wlc_info *wlc, tx_status_t *txs, u32 frm_tx2) ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); WLCNTINCR(wlc->pub->_cnt->ieee_tx_status); } else { - WL_ERROR(("%s: Not last frame => not calling tx_status\n", - __func__)); + WL_ERROR("%s: Not last frame => not calling tx_status\n", + __func__); } return false; @@ -6677,8 +6694,8 @@ void BCMFASTPATH wlc_txfifo_complete(struct wlc_info *wlc, uint fifo, s8 txpktpend) { TXPKTPENDDEC(wlc, fifo, txpktpend); - WL_TRACE(("wlc_txfifo_complete, pktpend dec %d to %d\n", txpktpend, - TXPKTPENDGET(wlc, fifo))); + WL_TRACE("wlc_txfifo_complete, pktpend dec %d to %d\n", + txpktpend, TXPKTPENDGET(wlc, fifo)); /* There is more room; mark precedences related to this FIFO sendable */ WLC_TX_FIFO_ENAB(wlc, fifo); @@ -6872,19 +6889,19 @@ prep_mac80211_status(struct wlc_info *wlc, d11rxhdr_t *rxh, struct sk_buff *p, rx_status->rate_idx = 11; break; default: - WL_ERROR(("%s: Unknown rate\n", __func__)); + WL_ERROR("%s: Unknown rate\n", __func__); } /* Determine short preamble and rate_idx */ preamble = 0; if (IS_CCK(rspec)) { if (rxh->PhyRxStatus_0 & PRXS0_SHORTH) - WL_ERROR(("Short CCK\n")); + WL_ERROR("Short CCK\n"); rx_status->flag |= RX_FLAG_SHORTPRE; } else if (IS_OFDM(rspec)) { rx_status->flag |= RX_FLAG_SHORTPRE; } else { - WL_ERROR(("%s: Unknown modulation\n", __func__)); + WL_ERROR("%s: Unknown modulation\n", __func__); } } @@ -6893,11 +6910,11 @@ prep_mac80211_status(struct wlc_info *wlc, d11rxhdr_t *rxh, struct sk_buff *p, if (rxh->RxStatus1 & RXS_DECERR) { rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; - WL_ERROR(("%s: RX_FLAG_FAILED_PLCP_CRC\n", __func__)); + WL_ERROR("%s: RX_FLAG_FAILED_PLCP_CRC\n", __func__); } if (rxh->RxStatus1 & RXS_FCSERR) { rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - WL_ERROR(("%s: RX_FLAG_FAILED_FCS_CRC\n", __func__)); + WL_ERROR("%s: RX_FLAG_FAILED_FCS_CRC\n", __func__); } } @@ -6943,7 +6960,7 @@ void wlc_bss_list_free(struct wlc_info *wlc, wlc_bss_list_t *bss_list) wlc_bss_info_t *bi; if (!bss_list) { - WL_ERROR(("%s: Attempting to free NULL list\n", __func__)); + WL_ERROR("%s: Attempting to free NULL list\n", __func__); return; } /* inspect all BSS descriptor */ @@ -6975,7 +6992,7 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) uint len; bool is_amsdu; - WL_TRACE(("wl%d: wlc_recv\n", wlc->pub->unit)); + WL_TRACE("wl%d: wlc_recv\n", wlc->pub->unit); osh = wlc->osh; @@ -6992,8 +7009,8 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) if (rxh->RxStatus1 & RXS_PBPRES) { if (p->len < 2) { WLCNTINCR(wlc->pub->_cnt->rxrunt); - WL_ERROR(("wl%d: wlc_recv: rcvd runt of len %d\n", - wlc->pub->unit, p->len)); + WL_ERROR("wl%d: wlc_recv: rcvd runt of len %d\n", + wlc->pub->unit, p->len); goto toss; } skb_pull(p, 2); @@ -7004,10 +7021,10 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) if (rxh->RxStatus1 & RXS_FCSERR) { if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { - WL_ERROR(("FCSERR while scanning******* - tossing\n")); + WL_ERROR("FCSERR while scanning******* - tossing\n"); goto toss; } else { - WL_ERROR(("RCSERR!!!\n")); + WL_ERROR("RCSERR!!!\n"); goto toss; } } @@ -7028,9 +7045,8 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) if (FC_TYPE(fc) == FC_TYPE_DATA || FC_TYPE(fc) == FC_TYPE_MNG) { if ((is_zero_ether_addr(h->a2.octet) || is_multicast_ether_addr(h->a2.octet))) { - WL_ERROR(("wl%d: %s: dropping a frame with " - "invalid src mac address, a2: %pM\n", - wlc->pub->unit, __func__, &h->a2)); + WL_ERROR("wl%d: %s: dropping a frame with invalid src mac address, a2: %pM\n", + wlc->pub->unit, __func__, &h->a2); WLCNTINCR(wlc->pub->_cnt->rxbadsrcmac); goto toss; } @@ -7045,7 +7061,7 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) } if (is_amsdu) { - WL_ERROR(("%s: is_amsdu causing toss\n", __func__)); + WL_ERROR("%s: is_amsdu causing toss\n", __func__); goto toss; } @@ -7067,8 +7083,8 @@ wlc_calc_lsig_len(struct wlc_info *wlc, ratespec_t ratespec, uint mac_len) { uint nsyms, len = 0, kNdps; - WL_TRACE(("wl%d: wlc_calc_lsig_len: rate %d, len%d\n", wlc->pub->unit, - RSPEC2RATE(ratespec), mac_len)); + WL_TRACE("wl%d: wlc_calc_lsig_len: rate %d, len%d\n", + wlc->pub->unit, RSPEC2RATE(ratespec), mac_len); if (IS_MCS(ratespec)) { uint mcs = ratespec & RSPEC_RATE_MASK; @@ -7112,11 +7128,12 @@ wlc_calc_frame_time(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type, if (rate == 0) { ASSERT(0); - WL_ERROR(("wl%d: WAR: using rate of 1 mbps\n", wlc->pub->unit)); + WL_ERROR("wl%d: WAR: using rate of 1 mbps\n", wlc->pub->unit); rate = WLC_RATE_1M; } - WL_TRACE(("wl%d: wlc_calc_frame_time: rspec 0x%x, preamble_type %d, len%d\n", wlc->pub->unit, ratespec, preamble_type, mac_len)); + WL_TRACE("wl%d: wlc_calc_frame_time: rspec 0x%x, preamble_type %d, len%d\n", + wlc->pub->unit, ratespec, preamble_type, mac_len); if (IS_MCS(ratespec)) { uint mcs = ratespec & RSPEC_RATE_MASK; @@ -7180,7 +7197,8 @@ wlc_calc_frame_len(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type, uint nsyms, mac_len, Ndps, kNdps; uint rate = RSPEC2RATE(ratespec); - WL_TRACE(("wl%d: wlc_calc_frame_len: rspec 0x%x, preamble_type %d, dur %d\n", wlc->pub->unit, ratespec, preamble_type, dur)); + WL_TRACE("wl%d: wlc_calc_frame_len: rspec 0x%x, preamble_type %d, dur %d\n", + wlc->pub->unit, ratespec, preamble_type, dur); if (IS_MCS(ratespec)) { uint mcs = ratespec & RSPEC_RATE_MASK; @@ -7222,8 +7240,8 @@ wlc_calc_frame_len(struct wlc_info *wlc, ratespec_t ratespec, u8 preamble_type, static uint wlc_calc_ba_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) { - WL_TRACE(("wl%d: wlc_calc_ba_time: rspec 0x%x, preamble_type %d\n", - wlc->pub->unit, rspec, preamble_type)); + WL_TRACE("wl%d: wlc_calc_ba_time: rspec 0x%x, preamble_type %d\n", + wlc->pub->unit, rspec, preamble_type); /* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than * or equal to the rate of the immediately previous frame in the FES */ @@ -7241,8 +7259,8 @@ wlc_calc_ack_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) { uint dur = 0; - WL_TRACE(("wl%d: wlc_calc_ack_time: rspec 0x%x, preamble_type %d\n", - wlc->pub->unit, rspec, preamble_type)); + WL_TRACE("wl%d: wlc_calc_ack_time: rspec 0x%x, preamble_type %d\n", + wlc->pub->unit, rspec, preamble_type); /* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than * or equal to the rate of the immediately previous frame in the FES */ @@ -7259,8 +7277,8 @@ wlc_calc_ack_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) static uint wlc_calc_cts_time(struct wlc_info *wlc, ratespec_t rspec, u8 preamble_type) { - WL_TRACE(("wl%d: wlc_calc_cts_time: ratespec 0x%x, preamble_type %d\n", - wlc->pub->unit, rspec, preamble_type)); + WL_TRACE("wl%d: wlc_calc_cts_time: ratespec 0x%x, preamble_type %d\n", + wlc->pub->unit, rspec, preamble_type); return wlc_calc_ack_time(wlc, rspec, preamble_type); } @@ -7289,7 +7307,8 @@ void wlc_rate_lookup_init(struct wlc_info *wlc, wlc_rateset_t *rateset) rate = (rateset->rates[i] & RATE_MASK); if (rate > WLC_MAXRATE) { - WL_ERROR(("wlc_rate_lookup_init: invalid rate 0x%X in rate set\n", rateset->rates[i])); + WL_ERROR("wlc_rate_lookup_init: invalid rate 0x%X in rate set\n", + rateset->rates[i]); continue; } @@ -7468,7 +7487,8 @@ bool wlc_valid_rate(struct wlc_info *wlc, ratespec_t rspec, int band, return true; error: if (verbose) { - WL_ERROR(("wl%d: wlc_valid_rate: rate spec 0x%x not in hw_rateset\n", wlc->pub->unit, rspec)); + WL_ERROR("wl%d: wlc_valid_rate: rate spec 0x%x not in hw_rateset\n", + wlc->pub->unit, rspec); } return false; @@ -7550,8 +7570,8 @@ wlc_compute_bcntsfoff(struct wlc_info *wlc, ratespec_t rspec, uint bcntsfoff = 0; if (IS_MCS(rspec)) { - WL_ERROR(("wl%d: recd beacon with mcs rate; rspec 0x%x\n", - wlc->pub->unit, rspec)); + WL_ERROR("wl%d: recd beacon with mcs rate; rspec 0x%x\n", + wlc->pub->unit, rspec); } else if (IS_OFDM(rspec)) { /* tx delay from MAC through phy to air (2.1 usec) + * phy header time (preamble + PLCP SIGNAL == 20 usec) + @@ -7979,8 +7999,8 @@ mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band, if (N_ENAB(wlc->pub) && ismcs) { /* mcs only allowed when nmode */ if (stf > PHY_TXC1_MODE_SDM) { - WL_ERROR(("wl%d: %s: Invalid stf\n", WLCWLUNIT(wlc), - __func__)); + WL_ERROR("wl%d: %s: Invalid stf\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } @@ -7990,8 +8010,8 @@ mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band, if (!CHSPEC_IS40(wlc->home_chanspec) || ((stf != PHY_TXC1_MODE_SISO) && (stf != PHY_TXC1_MODE_CDD))) { - WL_ERROR(("wl%d: %s: Invalid mcs 32\n", - WLCWLUNIT(wlc), __func__)); + WL_ERROR("wl%d: %s: Invalid mcs 32\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } @@ -7999,7 +8019,8 @@ mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band, } else if (rate > HIGHEST_SINGLE_STREAM_MCS) { /* mcs > 7 must use stf SDM */ if (stf != PHY_TXC1_MODE_SDM) { - WL_TRACE(("wl%d: %s: enabling SDM mode for mcs %d\n", WLCWLUNIT(wlc), __func__, rate)); + WL_TRACE("wl%d: %s: enabling SDM mode for mcs %d\n", + WLCWLUNIT(wlc), __func__, rate); stf = PHY_TXC1_MODE_SDM; } } else { @@ -8007,37 +8028,37 @@ mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band, if ((stf > PHY_TXC1_MODE_STBC) || (!WLC_STBC_CAP_PHY(wlc) && (stf == PHY_TXC1_MODE_STBC))) { - WL_ERROR(("wl%d: %s: Invalid STBC\n", - WLCWLUNIT(wlc), __func__)); + WL_ERROR("wl%d: %s: Invalid STBC\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } } } else if (IS_OFDM(rate)) { if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) { - WL_ERROR(("wl%d: %s: Invalid OFDM\n", WLCWLUNIT(wlc), - __func__)); + WL_ERROR("wl%d: %s: Invalid OFDM\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } } else if (IS_CCK(rate)) { if ((cur_band->bandtype != WLC_BAND_2G) || (stf != PHY_TXC1_MODE_SISO)) { - WL_ERROR(("wl%d: %s: Invalid CCK\n", WLCWLUNIT(wlc), - __func__)); + WL_ERROR("wl%d: %s: Invalid CCK\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } } else { - WL_ERROR(("wl%d: %s: Unknown rate type\n", WLCWLUNIT(wlc), - __func__)); + WL_ERROR("wl%d: %s: Unknown rate type\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } /* make sure multiple antennae are available for non-siso rates */ if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) { - WL_ERROR(("wl%d: %s: SISO antenna but !SISO request\n", - WLCWLUNIT(wlc), __func__)); + WL_ERROR("wl%d: %s: SISO antenna but !SISO request\n", + WLCWLUNIT(wlc), __func__); bcmerror = BCME_RANGE; goto done; } @@ -8068,7 +8089,7 @@ mac80211_wlc_set_nrate(struct wlc_info *wlc, struct wlcband *cur_band, return rspec; done: - WL_ERROR(("Hoark\n")); + WL_ERROR("Hoark\n"); return rate; } @@ -8082,8 +8103,7 @@ wlc_duty_cycle_set(struct wlc_info *wlc, int duty_cycle, bool isOFDM, isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM : M_TX_IDLE_BUSY_RATIO_X_16_CCK; if (duty_cycle > 100 || duty_cycle < 0) { - WL_ERROR(("wl%d: duty cycle value off limit\n", - wlc->pub->unit)); + WL_ERROR("wl%d: duty cycle value off limit\n", wlc->pub->unit); return BCME_RANGE; } if (duty_cycle) @@ -8282,7 +8302,7 @@ void wlc_txflowcontrol(struct wlc_info *wlc, wlc_txq_info_t *qi, uint prio_bits; uint cur_bits; - WL_ERROR(("%s: flow contro kicks in\n", __func__)); + WL_ERROR("%s: flow control kicks in\n", __func__); if (prio == ALLPRIO) { prio_bits = TXQ_STOP_FOR_PRIOFC_MASK; diff --git a/drivers/staging/brcm80211/sys/wlc_phy_shim.c b/drivers/staging/brcm80211/sys/wlc_phy_shim.c index 5dcaa7d70045..8bd4ede4c92a 100644 --- a/drivers/staging/brcm80211/sys/wlc_phy_shim.c +++ b/drivers/staging/brcm80211/sys/wlc_phy_shim.c @@ -70,7 +70,8 @@ wlc_phy_shim_info_t *wlc_phy_shim_attach(struct wlc_hw_info *wlc_hw, physhim = kzalloc(sizeof(wlc_phy_shim_info_t), GFP_ATOMIC); if (!physhim) { - WL_ERROR(("wl%d: wlc_phy_shim_attach: out of mem\n", wlc_hw->unit)); + WL_ERROR("wl%d: wlc_phy_shim_attach: out of mem\n", + wlc_hw->unit); return NULL; } physhim->wlc_hw = wlc_hw; diff --git a/drivers/staging/brcm80211/sys/wlc_stf.c b/drivers/staging/brcm80211/sys/wlc_stf.c index 01ac0d2b3cdb..8975b09a7438 100644 --- a/drivers/staging/brcm80211/sys/wlc_stf.c +++ b/drivers/staging/brcm80211/sys/wlc_stf.c @@ -196,8 +196,8 @@ bool wlc_stf_stbc_rx_set(struct wlc_info *wlc, s32 int_val) static int wlc_stf_txcore_set(struct wlc_info *wlc, u8 Nsts, u8 core_mask) { - WL_TRACE(("wl%d: %s: Nsts %d core_mask %x\n", - wlc->pub->unit, __func__, Nsts, core_mask)); + WL_TRACE("wl%d: %s: Nsts %d core_mask %x\n", + wlc->pub->unit, __func__, Nsts, core_mask); ASSERT((Nsts > 0) && (Nsts <= MAX_STREAMS_SUPPORTED)); @@ -236,7 +236,7 @@ static int wlc_stf_spatial_policy_set(struct wlc_info *wlc, int val) int i; u8 core_mask = 0; - WL_TRACE(("wl%d: %s: val %x\n", wlc->pub->unit, __func__, val)); + WL_TRACE("wl%d: %s: val %x\n", wlc->pub->unit, __func__, val); wlc->stf->spatial_policy = (s8) val; for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) { @@ -278,13 +278,15 @@ int wlc_stf_txchain_set(struct wlc_info *wlc, s32 int_val, bool force) if (RSPEC_STF(wlc->bandstate[i]->rspec_override) != PHY_TXC1_MODE_SISO) { wlc->bandstate[i]->rspec_override = 0; - WL_ERROR(("%s(): temp sense override non-SISO" " rspec_override.\n", __func__)); + WL_ERROR("%s(): temp sense override non-SISO rspec_override\n", + __func__); } if (RSPEC_STF (wlc->bandstate[i]->mrspec_override) != PHY_TXC1_MODE_SISO) { wlc->bandstate[i]->mrspec_override = 0; - WL_ERROR(("%s(): temp sense override non-SISO" " mrspec_override.\n", __func__)); + WL_ERROR("%s(): temp sense override non-SISO mrspec_override\n", + __func__); } } } -- cgit v1.2.3 From bf6506f60c46c8a709df534408cc6d470df657ff Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Wed, 15 Dec 2010 20:48:08 +0200 Subject: staging: hv: convert vmbus_on_msg_dpc to not call osd_schedule_callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The additional abstraction is unneeded. This also fixes a sleeping while atomic issue as osd_schedule_callback can sleep which is not allowed for vmbus_on_msg_dpc running in a tasklet. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16701 Reviewed-By: Hank Janssen Cc: Haiyang Zhang Signed-off-by: Timo Teräs Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel_mgmt.c | 4 ---- drivers/staging/hv/vmbus_drv.c | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index 0f4d6093f674..6f393e7d8e25 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -753,7 +753,6 @@ void vmbus_onmessage(void *context) hdr->msgtype, size); print_hex_dump_bytes("", DUMP_PREFIX_NONE, (unsigned char *)msg->u.payload, size); - kfree(msg); return; } @@ -762,9 +761,6 @@ void vmbus_onmessage(void *context) else DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->msgtype); - - /* Free the msg that was allocated in VmbusOnMsgDPC() */ - kfree(msg); } /* diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index d794b603bf17..84fdb64d3ceb 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -203,6 +203,21 @@ static void VmbusOnCleanup(struct hv_driver *drv) hv_cleanup(); } +struct onmessage_work_context { + struct work_struct work; + struct hv_message msg; +}; + +static void vmbus_onmessage_work(struct work_struct *work) +{ + struct onmessage_work_context *ctx; + + ctx = container_of(work, struct onmessage_work_context, + work); + vmbus_onmessage(&ctx->msg); + kfree(ctx); +} + /* * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior */ @@ -212,20 +227,19 @@ static void vmbus_on_msg_dpc(struct hv_driver *drv) void *page_addr = hv_context.synic_message_page[cpu]; struct hv_message *msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; - struct hv_message *copied; + struct onmessage_work_context *ctx; while (1) { if (msg->header.message_type == HVMSG_NONE) { /* no msg */ break; } else { - copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC); - if (copied == NULL) + ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); + if (ctx == NULL) continue; - - osd_schedule_callback(gVmbusConnection.WorkQueue, - vmbus_onmessage, - (void *)copied); + INIT_WORK(&ctx->work, vmbus_onmessage_work); + memcpy(&ctx->msg, msg, sizeof(*msg)); + queue_work(gVmbusConnection.WorkQueue, &ctx->work); } msg->header.message_type = HVMSG_NONE; -- cgit v1.2.3 From 4b2f9abea52af3782d349080fca5e189b0693792 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Wed, 15 Dec 2010 20:48:09 +0200 Subject: staging: hv: convert channel_mgmt.c to not call osd_schedule_callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The additional abstraction is unneeded. The three calls are assumed to not be pending simultaneously: - vmbus_onoffer queues work exactly once when a new channel is created, the channel is not attached to lists until the work is executed - vmbus_onoffer_rescind is received only when the channel is active it is enough to process the work once - free_channel is called exactly once when the channel is getting destroyed; I assumed that vmbus_process_rescind_offer cannot be pending while free_channel is called Reviewed-By: Hank Janssen Cc: Haiyang Zhang Signed-off-by: Timo Teräs Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel_mgmt.c | 52 ++++++++++++++++++++++----------------- drivers/staging/hv/channel_mgmt.h | 1 + 2 files changed, 31 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index 6f393e7d8e25..d44d5c39f68b 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -263,9 +263,11 @@ static struct vmbus_channel *alloc_channel(void) /* * release_hannel - Release the vmbus channel object itself */ -static inline void release_channel(void *context) +static void release_channel(struct work_struct *work) { - struct vmbus_channel *channel = context; + struct vmbus_channel *channel = container_of(work, + struct vmbus_channel, + work); DPRINT_DBG(VMBUS, "releasing channel (%p)", channel); destroy_workqueue(channel->controlwq); @@ -286,8 +288,8 @@ void free_channel(struct vmbus_channel *channel) * workqueue/thread context * ie we can't destroy ourselves. */ - osd_schedule_callback(gVmbusConnection.WorkQueue, release_channel, - channel); + INIT_WORK(&channel->work, release_channel); + queue_work(gVmbusConnection.WorkQueue, &channel->work); } @@ -308,20 +310,37 @@ static void count_hv_channel(void) spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags); } +/* + * vmbus_process_rescind_offer - + * Rescind the offer by initiating a device removal + */ +static void vmbus_process_rescind_offer(struct work_struct *work) +{ + struct vmbus_channel *channel = container_of(work, + struct vmbus_channel, + work); + + vmbus_child_device_unregister(channel->device_obj); +} /* * vmbus_process_offer - Process the offer by creating a channel/device * associated with this offer */ -static void vmbus_process_offer(void *context) +static void vmbus_process_offer(struct work_struct *work) { - struct vmbus_channel *newchannel = context; + struct vmbus_channel *newchannel = container_of(work, + struct vmbus_channel, + work); struct vmbus_channel *channel; bool fnew = true; int ret; int cnt; unsigned long flags; + /* The next possible work is rescind handling */ + INIT_WORK(&newchannel->work, vmbus_process_rescind_offer); + /* Make sure this is a new offer */ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags); @@ -405,17 +424,6 @@ static void vmbus_process_offer(void *context) } } -/* - * vmbus_process_rescind_offer - - * Rescind the offer by initiating a device removal - */ -static void vmbus_process_rescind_offer(void *context) -{ - struct vmbus_channel *channel = context; - - vmbus_child_device_unregister(channel->device_obj); -} - /* * vmbus_onoffer - Handler for channel offers from vmbus in parent partition. * @@ -490,8 +498,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) newchannel->monitor_bit = (u8)offer->monitorid % 32; /* TODO: Make sure the offer comes from our parent partition */ - osd_schedule_callback(newchannel->controlwq, vmbus_process_offer, - newchannel); + INIT_WORK(&newchannel->work, vmbus_process_offer); + queue_work(newchannel->controlwq, &newchannel->work); } /* @@ -512,9 +520,9 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) return; } - osd_schedule_callback(channel->controlwq, - vmbus_process_rescind_offer, - channel); + /* work is initialized for vmbus_process_rescind_offer() from + * vmbus_process_offer() where the channel got created */ + queue_work(channel->controlwq, &channel->work); } /* diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h index 12f30aff152d..de6b2a0ebf70 100644 --- a/drivers/staging/hv/channel_mgmt.h +++ b/drivers/staging/hv/channel_mgmt.h @@ -231,6 +231,7 @@ struct vmbus_channel { struct hv_device *device_obj; struct timer_list poll_timer; /* SA-111 workaround */ + struct work_struct work; enum vmbus_channel_state state; -- cgit v1.2.3 From 244ba85606b567e6e990d2fac61e3bde5ff8f0ad Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Wed, 15 Dec 2010 20:48:10 +0200 Subject: staging: hv: remove unneeded osd_schedule_callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No one calls it anymore, so remove it. Reviewed-By: Hank Janssen Cc: Haiyang Zhang Signed-off-by: Timo Teräs Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/osd.c | 34 ---------------------------------- drivers/staging/hv/osd.h | 4 ---- 2 files changed, 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c index b699ee27f07f..b5a3940331b3 100644 --- a/drivers/staging/hv/osd.c +++ b/drivers/staging/hv/osd.c @@ -43,12 +43,6 @@ #include #include "osd.h" -struct osd_callback_struct { - struct work_struct work; - void (*callback)(void *); - void *data; -}; - void *osd_virtual_alloc_exec(unsigned int size) { #ifdef __x86_64__ @@ -198,31 +192,3 @@ int osd_waitevent_waitex(struct osd_waitevent *wait_event, u32 timeout_in_ms) return ret; } EXPORT_SYMBOL_GPL(osd_waitevent_waitex); - -static void osd_callback_work(struct work_struct *work) -{ - struct osd_callback_struct *cb = container_of(work, - struct osd_callback_struct, - work); - (cb->callback)(cb->data); - kfree(cb); -} - -int osd_schedule_callback(struct workqueue_struct *wq, - void (*func)(void *), - void *data) -{ - struct osd_callback_struct *cb; - - cb = kmalloc(sizeof(*cb), GFP_KERNEL); - if (!cb) { - printk(KERN_ERR "unable to allocate memory in osd_schedule_callback\n"); - return -1; - } - - cb->callback = func; - cb->data = data; - INIT_WORK(&cb->work, osd_callback_work); - return queue_work(wq, &cb->work); -} - diff --git a/drivers/staging/hv/osd.h b/drivers/staging/hv/osd.h index cae126ff6b9a..870ef0768833 100644 --- a/drivers/staging/hv/osd.h +++ b/drivers/staging/hv/osd.h @@ -63,8 +63,4 @@ extern int osd_waitevent_wait(struct osd_waitevent *wait_event); extern int osd_waitevent_waitex(struct osd_waitevent *wait_event, u32 timeout_in_ms); -int osd_schedule_callback(struct workqueue_struct *wq, - void (*func)(void *), - void *data); - #endif /* _OSD_H_ */ -- cgit v1.2.3 From 45241e50e3e741ee2a148693888b48e90e806de9 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Mon, 13 Dec 2010 16:23:36 -0800 Subject: Staging: hv: Use only one txf buffer per channel and kmalloc/GFP_KERNEL on initialize Correct issue with not checking kmalloc return value. This fix now only uses one receive buffer for all hv_utils channels, and will do only one kmalloc on init and will return with a -ENOMEM if kmalloc fails on initialize. And properly clean up memory on failure. Thanks to Evgeniy Polyakov for pointing this out. And thanks to Jesper Juhl and Ky Srinivasan for suggesting a better implementation of my original patch. Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Reviewed-by: Jesper Juhl Cc: Evgeniy Polyakov Cc: Jesper Juhl Cc: Ky Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/hv_utils.c | 87 +++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c index 53e1e290b0f1..0074581f20e8 100644 --- a/drivers/staging/hv/hv_utils.c +++ b/drivers/staging/hv/hv_utils.c @@ -38,12 +38,14 @@ #include "vmbus_api.h" #include "utils.h" +static u8 *shut_txf_buf; +static u8 *time_txf_buf; +static u8 *hbeat_txf_buf; static void shutdown_onchannelcallback(void *context) { struct vmbus_channel *channel = context; - u8 *buf; - u32 buflen, recvlen; + u32 recvlen; u64 requestid; u8 execute_shutdown = false; @@ -52,24 +54,23 @@ static void shutdown_onchannelcallback(void *context) struct icmsg_hdr *icmsghdrp; struct icmsg_negotiate *negop = NULL; - buflen = PAGE_SIZE; - buf = kmalloc(buflen, GFP_ATOMIC); - - vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid); + vmbus_recvpacket(channel, shut_txf_buf, + PAGE_SIZE, &recvlen, &requestid); if (recvlen > 0) { DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld", recvlen, requestid); - icmsghdrp = (struct icmsg_hdr *)&buf[ + icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[ sizeof(struct vmbuspipe_hdr)]; if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - prep_negotiate_resp(icmsghdrp, negop, buf); + prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf); } else { - shutdown_msg = (struct shutdown_msg_data *)&buf[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; + shutdown_msg = + (struct shutdown_msg_data *)&shut_txf_buf[ + sizeof(struct vmbuspipe_hdr) + + sizeof(struct icmsg_hdr)]; switch (shutdown_msg->flags) { case 0: @@ -93,13 +94,11 @@ static void shutdown_onchannelcallback(void *context) icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; - vmbus_sendpacket(channel, buf, + vmbus_sendpacket(channel, shut_txf_buf, recvlen, requestid, VmbusPacketTypeDataInBand, 0); } - kfree(buf); - if (execute_shutdown == true) orderly_poweroff(false); } @@ -150,28 +149,25 @@ static inline void adj_guesttime(u64 hosttime, u8 flags) static void timesync_onchannelcallback(void *context) { struct vmbus_channel *channel = context; - u8 *buf; - u32 buflen, recvlen; + u32 recvlen; u64 requestid; struct icmsg_hdr *icmsghdrp; struct ictimesync_data *timedatap; - buflen = PAGE_SIZE; - buf = kmalloc(buflen, GFP_ATOMIC); - - vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid); + vmbus_recvpacket(channel, time_txf_buf, + PAGE_SIZE, &recvlen, &requestid); if (recvlen > 0) { DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld", recvlen, requestid); - icmsghdrp = (struct icmsg_hdr *)&buf[ + icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[ sizeof(struct vmbuspipe_hdr)]; if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - prep_negotiate_resp(icmsghdrp, NULL, buf); + prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf); } else { - timedatap = (struct ictimesync_data *)&buf[ + timedatap = (struct ictimesync_data *)&time_txf_buf[ sizeof(struct vmbuspipe_hdr) + sizeof(struct icmsg_hdr)]; adj_guesttime(timedatap->parenttime, timedatap->flags); @@ -180,12 +176,10 @@ static void timesync_onchannelcallback(void *context) icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; - vmbus_sendpacket(channel, buf, + vmbus_sendpacket(channel, time_txf_buf, recvlen, requestid, VmbusPacketTypeDataInBand, 0); } - - kfree(buf); } /* @@ -196,30 +190,28 @@ static void timesync_onchannelcallback(void *context) static void heartbeat_onchannelcallback(void *context) { struct vmbus_channel *channel = context; - u8 *buf; - u32 buflen, recvlen; + u32 recvlen; u64 requestid; struct icmsg_hdr *icmsghdrp; struct heartbeat_msg_data *heartbeat_msg; - buflen = PAGE_SIZE; - buf = kmalloc(buflen, GFP_ATOMIC); - - vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid); + vmbus_recvpacket(channel, hbeat_txf_buf, + PAGE_SIZE, &recvlen, &requestid); if (recvlen > 0) { DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld", recvlen, requestid); - icmsghdrp = (struct icmsg_hdr *)&buf[ + icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[ sizeof(struct vmbuspipe_hdr)]; if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - prep_negotiate_resp(icmsghdrp, NULL, buf); + prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf); } else { - heartbeat_msg = (struct heartbeat_msg_data *)&buf[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; + heartbeat_msg = + (struct heartbeat_msg_data *)&hbeat_txf_buf[ + sizeof(struct vmbuspipe_hdr) + + sizeof(struct icmsg_hdr)]; DPRINT_DBG(VMBUS, "heartbeat seq = %lld", heartbeat_msg->seq_num); @@ -230,12 +222,10 @@ static void heartbeat_onchannelcallback(void *context) icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; - vmbus_sendpacket(channel, buf, + vmbus_sendpacket(channel, hbeat_txf_buf, recvlen, requestid, VmbusPacketTypeDataInBand, 0); } - - kfree(buf); } static const struct pci_device_id __initconst @@ -268,6 +258,19 @@ static int __init init_hyperv_utils(void) if (!dmi_check_system(hv_utils_dmi_table)) return -ENODEV; + shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + + if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) { + printk(KERN_INFO + "Unable to allocate memory for receive buffer\n"); + kfree(shut_txf_buf); + kfree(time_txf_buf); + kfree(hbeat_txf_buf); + return -ENOMEM; + } + hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback = &shutdown_onchannelcallback; hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback; @@ -298,6 +301,10 @@ static void exit_hyperv_utils(void) hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback = &chn_cb_negotiate; hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate; + + kfree(shut_txf_buf); + kfree(time_txf_buf); + kfree(hbeat_txf_buf); } module_init(init_hyperv_utils); -- cgit v1.2.3 From 0af7e4dff50454905092d468e91c1ef92e10e6b4 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Wed, 8 Dec 2010 04:07:19 +0100 Subject: drm/i915: Add support for precise vblank timestamping (v2) v2: Change IS_IRONLAKE to IS_GEN5 to adapt to 2.6.37 This patch adds new functions for use by the drm core: .get_vblank_timestamp() provides a precise timestamp for the end of the most recent (or current) vblank interval of a given crtc, as needed for the DRI2 implementation of the OML_sync_control extension. It is a thin wrapper around the drm function drm_calc_vbltimestamp_from_scanoutpos() which does almost all the work. .get_scanout_position() provides the current horizontal and vertical video scanout position and "in vblank" status of a given crtc, as needed by the drm for use by drm_calc_vbltimestamp_from_scanoutpos(). The patch modifies the pageflip completion routine to use these precise vblank timestamps as the timestamps for pageflip completion events. This code has been only tested on a HP-Mini Netbook with Atom processor and Intel 945GME gpu. The codepath for (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) gpu's has not been tested so far due to lack of hardware. Signed-off-by: Mario Kleiner Acked-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 7 +++ drivers/gpu/drm/i915/i915_irq.c | 86 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 29 +++++++++--- 5 files changed, 119 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index bdb29b2a01ed..9eee6cf7901e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -652,6 +652,8 @@ static struct drm_driver driver = { .device_is_agp = i915_driver_device_is_agp, .enable_vblank = i915_enable_vblank, .disable_vblank = i915_disable_vblank, + .get_vblank_timestamp = i915_get_vblank_timestamp, + .get_scanout_position = i915_get_crtc_scanoutpos, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 30780f2cab6f..53dfc8398a96 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1019,6 +1019,13 @@ void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); void intel_enable_asle (struct drm_device *dev); +int i915_get_vblank_timestamp(struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags); + +int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, + int *vpos, int *hpos); #ifdef CONFIG_DEBUG_FS extern void i915_destroy_error_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e4a2e2c3dbe3..adf983f01dda 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -248,6 +248,92 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) return I915_READ(reg); } +int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, + int *vpos, int *hpos) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 vbl = 0, position = 0; + int vbl_start, vbl_end, htotal, vtotal; + bool in_vbl = true; + int ret = 0; + + if (!i915_pipe_enabled(dev, pipe)) { + DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " + "pipe %d\n", pipe); + return 0; + } + + /* Get vtotal. */ + vtotal = 1 + ((I915_READ(VTOTAL(pipe)) >> 16) & 0x1fff); + + if (INTEL_INFO(dev)->gen >= 4) { + /* No obvious pixelcount register. Only query vertical + * scanout position from Display scan line register. + */ + position = I915_READ(PIPEDSL(pipe)); + + /* Decode into vertical scanout position. Don't have + * horizontal scanout position. + */ + *vpos = position & 0x1fff; + *hpos = 0; + } else { + /* Have access to pixelcount since start of frame. + * We can split this into vertical and horizontal + * scanout position. + */ + position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; + + htotal = 1 + ((I915_READ(HTOTAL(pipe)) >> 16) & 0x1fff); + *vpos = position / htotal; + *hpos = position - (*vpos * htotal); + } + + /* Query vblank area. */ + vbl = I915_READ(VBLANK(pipe)); + + /* Test position against vblank region. */ + vbl_start = vbl & 0x1fff; + vbl_end = (vbl >> 16) & 0x1fff; + + if ((*vpos < vbl_start) || (*vpos > vbl_end)) + in_vbl = false; + + /* Inside "upper part" of vblank area? Apply corrective offset: */ + if (in_vbl && (*vpos >= vbl_start)) + *vpos = *vpos - vtotal; + + /* Readouts valid? */ + if (vbl > 0) + ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE; + + /* In vblank? */ + if (in_vbl) + ret |= DRM_SCANOUTPOS_INVBL; + + return ret; +} + +int i915_get_vblank_timestamp(struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags) +{ + struct drm_crtc *drmcrtc; + + if (crtc < 0 || crtc >= dev->num_crtcs) { + DRM_ERROR("Invalid crtc %d\n", crtc); + return -EINVAL; + } + + /* Get drm_crtc to timestamp: */ + drmcrtc = intel_get_crtc_for_pipe(dev, crtc); + + /* Helper routine in DRM core does all the work: */ + return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, + vblank_time, flags, drmcrtc); +} + /* * Handle hotplug events outside the interrupt handler proper. */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 820e9dfaadc7..c2231f7d2d97 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2253,6 +2253,7 @@ #define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC) #define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF) #define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL) +#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, PIPEAFRAMEPIXEL, PIPEBFRAMEPIXEL) #define DSPARB 0x70030 #define DSPARB_CSTART_MASK (0x7f << 7) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8645a974a499..0c201d684584 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5252,7 +5252,8 @@ static void intel_unpin_work_fn(struct work_struct *__work) } static void do_intel_finish_page_flip(struct drm_device *dev, - struct drm_crtc *crtc) + struct drm_crtc *crtc, + int called_before_vblirq) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5274,19 +5275,33 @@ static void do_intel_finish_page_flip(struct drm_device *dev, } intel_crtc->unpin_work = NULL; - drm_vblank_put(dev, intel_crtc->pipe); if (work->event) { e = work->event; - do_gettimeofday(&now); - e->event.sequence = drm_vblank_count(dev, intel_crtc->pipe); + e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &now); + + /* Called before vblank count and timestamps have + * been updated for the vblank interval of flip + * completion? Need to increment vblank count and + * add one videorefresh duration to returned timestamp + * to account for this. + */ + if (called_before_vblirq) { + e->event.sequence++; + now = ns_to_timeval(timeval_to_ns(&now) + + crtc->framedur_ns); + } + e->event.tv_sec = now.tv_sec; e->event.tv_usec = now.tv_usec; + list_add_tail(&e->base.link, &e->base.file_priv->event_list); wake_up_interruptible(&e->base.file_priv->event_wait); } + drm_vblank_put(dev, intel_crtc->pipe); + spin_unlock_irqrestore(&dev->event_lock, flags); obj = work->old_fb_obj; @@ -5306,7 +5321,8 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - do_intel_finish_page_flip(dev, crtc); + /* Called after drm_handle_vblank has run for finish vblank. */ + do_intel_finish_page_flip(dev, crtc, 0); } void intel_finish_page_flip_plane(struct drm_device *dev, int plane) @@ -5314,7 +5330,8 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane]; - do_intel_finish_page_flip(dev, crtc); + /* Called before drm_handle_vblank has run for finish vblank. */ + do_intel_finish_page_flip(dev, crtc, 1); } void intel_prepare_page_flip(struct drm_device *dev, int plane) -- cgit v1.2.3 From 49b14a5ca26fc18bafe33bd9704a1a1cea681fbf Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Thu, 9 Dec 2010 07:00:07 +0100 Subject: drm/i915: Add Guess-o-matic for pageflip timestamping. This patch changes the strategy for pageflip completion timestamping. It detects if the pageflip completion routine gets executed before or after drm_handle_vblank, and thereby decides if the returned vblank count and timestamp must be incremented by 1 frame(duration) or not. It compares the current system time at invocation against the current vblank timestamp. If the difference is more than 0.9 video refresh interval durations then it assumes the vblank timestamp and count are outdated and need to be incremented and does so. Otherwise it assumes a delayed pageflip irq and doesn't correct the timestamp and count. Advantage of this patch: Pageflip timestamping becomes more robust against implementation errors and is maintenance free for future GPU's. Disadvantage: A few dozen (hundred?) nsecs extra time spent in pageflip irq handler for each flip, compared to hard-coded per-gpu settings? Signed-off-by: Mario Kleiner Acked-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0c201d684584..fe6538297872 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5252,21 +5252,22 @@ static void intel_unpin_work_fn(struct work_struct *__work) } static void do_intel_finish_page_flip(struct drm_device *dev, - struct drm_crtc *crtc, - int called_before_vblirq) + struct drm_crtc *crtc) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; struct drm_i915_gem_object *obj; struct drm_pending_vblank_event *e; - struct timeval now; + struct timeval tnow, tvbl; unsigned long flags; /* Ignore early vblank irqs */ if (intel_crtc == NULL) return; + do_gettimeofday(&tnow); + spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { @@ -5278,22 +5279,29 @@ static void do_intel_finish_page_flip(struct drm_device *dev, if (work->event) { e = work->event; - e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &now); + e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl); /* Called before vblank count and timestamps have * been updated for the vblank interval of flip * completion? Need to increment vblank count and * add one videorefresh duration to returned timestamp - * to account for this. + * to account for this. We assume this happened if we + * get called over 0.9 frame durations after the last + * timestamped vblank. + * + * This calculation can not be used with vrefresh rates + * below 5Hz (10Hz to be on the safe side) without + * promoting to 64 integers. */ - if (called_before_vblirq) { + if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) > + 9 * crtc->framedur_ns) { e->event.sequence++; - now = ns_to_timeval(timeval_to_ns(&now) + - crtc->framedur_ns); + tvbl = ns_to_timeval(timeval_to_ns(&tvbl) + + crtc->framedur_ns); } - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + e->event.tv_sec = tvbl.tv_sec; + e->event.tv_usec = tvbl.tv_usec; list_add_tail(&e->base.link, &e->base.file_priv->event_list); @@ -5321,8 +5329,7 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - /* Called after drm_handle_vblank has run for finish vblank. */ - do_intel_finish_page_flip(dev, crtc, 0); + do_intel_finish_page_flip(dev, crtc); } void intel_finish_page_flip_plane(struct drm_device *dev, int plane) @@ -5330,8 +5337,7 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane]; - /* Called before drm_handle_vblank has run for finish vblank. */ - do_intel_finish_page_flip(dev, crtc, 1); + do_intel_finish_page_flip(dev, crtc); } void intel_prepare_page_flip(struct drm_device *dev, int plane) -- cgit v1.2.3 From 6714afb108b4973a07413ec58cb300b6d90b8df4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Dec 2010 04:10:51 +0000 Subject: drm/i915/sdvo: Border and stall select became test bits in gen5 This is even more important as those bits will be moved in future. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 27e63abf2a73..6c0bb18a26e8 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1045,7 +1045,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* Set the SDVO control regs. */ if (INTEL_INFO(dev)->gen >= 4) { - sdvox = SDVO_BORDER_ENABLE; + sdvox = 0; + if (INTEL_INFO(dev)->gen < 5) + sdvox |= SDVO_BORDER_ENABLE; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) sdvox |= SDVO_VSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) @@ -1075,7 +1077,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL) + if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL && + INTEL_INFO(dev)->gen < 5) sdvox |= SDVO_STALL_SELECT; intel_sdvo_write_sdvox(intel_sdvo, sdvox); } -- cgit v1.2.3 From 63d5e5a727240b317b0c2fa2abeb32b367aea196 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 16 Dec 2010 23:28:17 +0100 Subject: Staging: batman-adv: Remove batman-adv from staging batman-adv is now moved to net/batman-adv/ and can be removed from staging. Signed-off-by: Sven Eckelmann Cc: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/batman-adv/Kconfig | 26 - drivers/staging/batman-adv/Makefile | 39 - drivers/staging/batman-adv/README | 240 ---- drivers/staging/batman-adv/TODO | 10 - drivers/staging/batman-adv/aggregation.c | 273 ---- drivers/staging/batman-adv/aggregation.h | 43 - drivers/staging/batman-adv/bat_debugfs.c | 360 ----- drivers/staging/batman-adv/bat_debugfs.h | 33 - drivers/staging/batman-adv/bat_sysfs.c | 593 --------- drivers/staging/batman-adv/bat_sysfs.h | 42 - drivers/staging/batman-adv/bitarray.c | 201 --- drivers/staging/batman-adv/bitarray.h | 47 - drivers/staging/batman-adv/gateway_client.c | 477 ------- drivers/staging/batman-adv/gateway_client.h | 36 - drivers/staging/batman-adv/gateway_common.c | 177 --- drivers/staging/batman-adv/gateway_common.h | 38 - drivers/staging/batman-adv/hard-interface.c | 652 --------- drivers/staging/batman-adv/hard-interface.h | 53 - drivers/staging/batman-adv/hash.c | 83 -- drivers/staging/batman-adv/hash.h | 259 ---- drivers/staging/batman-adv/icmp_socket.c | 357 ----- drivers/staging/batman-adv/icmp_socket.h | 34 - drivers/staging/batman-adv/main.c | 187 --- drivers/staging/batman-adv/main.h | 180 --- drivers/staging/batman-adv/originator.c | 546 -------- drivers/staging/batman-adv/originator.h | 64 - drivers/staging/batman-adv/packet.h | 136 -- drivers/staging/batman-adv/ring_buffer.c | 52 - drivers/staging/batman-adv/ring_buffer.h | 28 - drivers/staging/batman-adv/routing.c | 1393 -------------------- drivers/staging/batman-adv/routing.h | 48 - drivers/staging/batman-adv/send.c | 586 -------- drivers/staging/batman-adv/send.h | 41 - drivers/staging/batman-adv/soft-interface.c | 697 ---------- drivers/staging/batman-adv/soft-interface.h | 35 - .../staging/batman-adv/sysfs-class-net-batman-adv | 14 - drivers/staging/batman-adv/sysfs-class-net-mesh | 69 - drivers/staging/batman-adv/translation-table.c | 528 -------- drivers/staging/batman-adv/translation-table.h | 45 - drivers/staging/batman-adv/types.h | 271 ---- drivers/staging/batman-adv/unicast.c | 343 ----- drivers/staging/batman-adv/unicast.h | 35 - drivers/staging/batman-adv/vis.c | 903 ------------- drivers/staging/batman-adv/vis.h | 37 - 46 files changed, 10314 deletions(-) delete mode 100644 drivers/staging/batman-adv/Kconfig delete mode 100644 drivers/staging/batman-adv/Makefile delete mode 100644 drivers/staging/batman-adv/README delete mode 100644 drivers/staging/batman-adv/TODO delete mode 100644 drivers/staging/batman-adv/aggregation.c delete mode 100644 drivers/staging/batman-adv/aggregation.h delete mode 100644 drivers/staging/batman-adv/bat_debugfs.c delete mode 100644 drivers/staging/batman-adv/bat_debugfs.h delete mode 100644 drivers/staging/batman-adv/bat_sysfs.c delete mode 100644 drivers/staging/batman-adv/bat_sysfs.h delete mode 100644 drivers/staging/batman-adv/bitarray.c delete mode 100644 drivers/staging/batman-adv/bitarray.h delete mode 100644 drivers/staging/batman-adv/gateway_client.c delete mode 100644 drivers/staging/batman-adv/gateway_client.h delete mode 100644 drivers/staging/batman-adv/gateway_common.c delete mode 100644 drivers/staging/batman-adv/gateway_common.h delete mode 100644 drivers/staging/batman-adv/hard-interface.c delete mode 100644 drivers/staging/batman-adv/hard-interface.h delete mode 100644 drivers/staging/batman-adv/hash.c delete mode 100644 drivers/staging/batman-adv/hash.h delete mode 100644 drivers/staging/batman-adv/icmp_socket.c delete mode 100644 drivers/staging/batman-adv/icmp_socket.h delete mode 100644 drivers/staging/batman-adv/main.c delete mode 100644 drivers/staging/batman-adv/main.h delete mode 100644 drivers/staging/batman-adv/originator.c delete mode 100644 drivers/staging/batman-adv/originator.h delete mode 100644 drivers/staging/batman-adv/packet.h delete mode 100644 drivers/staging/batman-adv/ring_buffer.c delete mode 100644 drivers/staging/batman-adv/ring_buffer.h delete mode 100644 drivers/staging/batman-adv/routing.c delete mode 100644 drivers/staging/batman-adv/routing.h delete mode 100644 drivers/staging/batman-adv/send.c delete mode 100644 drivers/staging/batman-adv/send.h delete mode 100644 drivers/staging/batman-adv/soft-interface.c delete mode 100644 drivers/staging/batman-adv/soft-interface.h delete mode 100644 drivers/staging/batman-adv/sysfs-class-net-batman-adv delete mode 100644 drivers/staging/batman-adv/sysfs-class-net-mesh delete mode 100644 drivers/staging/batman-adv/translation-table.c delete mode 100644 drivers/staging/batman-adv/translation-table.h delete mode 100644 drivers/staging/batman-adv/types.h delete mode 100644 drivers/staging/batman-adv/unicast.c delete mode 100644 drivers/staging/batman-adv/unicast.h delete mode 100644 drivers/staging/batman-adv/vis.c delete mode 100644 drivers/staging/batman-adv/vis.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index f2d9fe8cde5f..923e28f83208 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -129,8 +129,6 @@ source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" -source "drivers/staging/batman-adv/Kconfig" - source "drivers/staging/samsung-laptop/Kconfig" source "drivers/staging/sm7xx/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 10c72bb1940d..4e6797f6444a 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ -obj-$(CONFIG_BATMAN_ADV) += batman-adv/ obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/ obj-$(CONFIG_FB_SM7XX) += sm7xx/ obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig deleted file mode 100644 index 8553f3517454..000000000000 --- a/drivers/staging/batman-adv/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -# -# B.A.T.M.A.N meshing protocol -# - -config BATMAN_ADV - tristate "B.A.T.M.A.N. Advanced Meshing Protocol" - depends on NET - default n - ---help--- - - B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is - a routing protocol for multi-hop ad-hoc mesh networks. The - networks may be wired or wireless. See - http://www.open-mesh.org/ for more information and user space - tools. - -config BATMAN_ADV_DEBUG - bool "B.A.T.M.A.N. debugging" - depends on BATMAN_ADV != n - ---help--- - - This is an option for use by developers; most people should - say N here. This enables compilation of support for - outputting debugging information to the kernel log. The - output is controlled via the module parameter debug. - diff --git a/drivers/staging/batman-adv/Makefile b/drivers/staging/batman-adv/Makefile deleted file mode 100644 index d936aeccd194..000000000000 --- a/drivers/staging/batman-adv/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: -# -# Marek Lindner, Simon Wunderlich -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of version 2 of the GNU General Public -# License as published by the Free Software Foundation. -# -# This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA -# - -obj-$(CONFIG_BATMAN_ADV) += batman-adv.o -batman-adv-y += aggregation.o -batman-adv-y += bat_debugfs.o -batman-adv-y += bat_sysfs.o -batman-adv-y += bitarray.o -batman-adv-y += gateway_client.o -batman-adv-y += gateway_common.o -batman-adv-y += hard-interface.o -batman-adv-y += hash.o -batman-adv-y += icmp_socket.o -batman-adv-y += main.o -batman-adv-y += originator.o -batman-adv-y += ring_buffer.o -batman-adv-y += routing.o -batman-adv-y += send.o -batman-adv-y += soft-interface.o -batman-adv-y += translation-table.o -batman-adv-y += unicast.o -batman-adv-y += vis.o diff --git a/drivers/staging/batman-adv/README b/drivers/staging/batman-adv/README deleted file mode 100644 index 77f0cdd5b0dd..000000000000 --- a/drivers/staging/batman-adv/README +++ /dev/null @@ -1,240 +0,0 @@ -[state: 21-11-2010] - -BATMAN-ADV ----------- - -Batman advanced is a new approach to wireless networking which -does no longer operate on the IP basis. Unlike the batman daemon, -which exchanges information using UDP packets and sets routing -tables, batman-advanced operates on ISO/OSI Layer 2 only and uses -and routes (or better: bridges) Ethernet Frames. It emulates a -virtual network switch of all nodes participating. Therefore all -nodes appear to be link local, thus all higher operating proto- -cols won't be affected by any changes within the network. You can -run almost any protocol above batman advanced, prominent examples -are: IPv4, IPv6, DHCP, IPX. - -Batman advanced was implemented as a Linux kernel driver to re- -duce the overhead to a minimum. It does not depend on any (other) -network driver, and can be used on wifi as well as ethernet lan, -vpn, etc ... (anything with ethernet-style layer 2). - -CONFIGURATION -------------- - -Load the batman-adv module into your kernel: - -# insmod batman-adv.ko - -The module is now waiting for activation. You must add some in- -terfaces on which batman can operate. After loading the module -batman advanced will scan your systems interfaces to search for -compatible interfaces. Once found, it will create subfolders in -the /sys directories of each supported interface, e.g. - -# ls /sys/class/net/eth0/batman_adv/ -# iface_status mesh_iface - -If an interface does not have the "batman_adv" subfolder it prob- -ably is not supported. Not supported interfaces are: loopback, -non-ethernet and batman's own interfaces. - -Note: After the module was loaded it will continuously watch for -new interfaces to verify the compatibility. There is no need to -reload the module if you plug your USB wifi adapter into your ma- -chine after batman advanced was initially loaded. - -To activate a given interface simply write "bat0" into its -"mesh_iface" file inside the batman_adv subfolder: - -# echo bat0 > /sys/class/net/eth0/batman_adv/mesh_iface - -Repeat this step for all interfaces you wish to add. Now batman -starts using/broadcasting on this/these interface(s). - -By reading the "iface_status" file you can check its status: - -# cat /sys/class/net/eth0/batman_adv/iface_status -# active - -To deactivate an interface you have to write "none" into its -"mesh_iface" file: - -# echo none > /sys/class/net/eth0/batman_adv/mesh_iface - - -All mesh wide settings can be found in batman's own interface -folder: - -# ls /sys/class/net/bat0/mesh/ -# aggregated_ogms bonding fragmentation orig_interval -# vis_mode - - -There is a special folder for debugging informations: - -# ls /sys/kernel/debug/batman_adv/bat0/ -# originators socket transtable_global transtable_local -# vis_data - - -Some of the files contain all sort of status information regard- -ing the mesh network. For example, you can view the table of -originators (mesh participants) with: - -# cat /sys/kernel/debug/batman_adv/bat0/originators - -Other files allow to change batman's behaviour to better fit your -requirements. For instance, you can check the current originator -interval (value in milliseconds which determines how often batman -sends its broadcast packets): - -# cat /sys/class/net/bat0/mesh/orig_interval -# 1000 - -and also change its value: - -# echo 3000 > /sys/class/net/bat0/mesh/orig_interval - -In very mobile scenarios, you might want to adjust the originator -interval to a lower value. This will make the mesh more respon- -sive to topology changes, but will also increase the overhead. - - -USAGE ------ - -To make use of your newly created mesh, batman advanced provides -a new interface "bat0" which you should use from this point on. -All interfaces added to batman advanced are not relevant any -longer because batman handles them for you. Basically, one "hands -over" the data by using the batman interface and batman will make -sure it reaches its destination. - -The "bat0" interface can be used like any other regular inter- -face. It needs an IP address which can be either statically con- -figured or dynamically (by using DHCP or similar services): - -# NodeA: ifconfig bat0 192.168.0.1 -# NodeB: ifconfig bat0 192.168.0.2 -# NodeB: ping 192.168.0.1 - -Note: In order to avoid problems remove all IP addresses previ- -ously assigned to interfaces now used by batman advanced, e.g. - -# ifconfig eth0 0.0.0.0 - - -VISUALIZATION -------------- - -If you want topology visualization, at least one mesh node must -be configured as VIS-server: - -# echo "server" > /sys/class/net/bat0/mesh/vis_mode - -Each node is either configured as "server" or as "client" (de- -fault: "client"). Clients send their topology data to the server -next to them, and server synchronize with other servers. If there -is no server configured (default) within the mesh, no topology -information will be transmitted. With these "synchronizing -servers", there can be 1 or more vis servers sharing the same (or -at least very similar) data. - -When configured as server, you can get a topology snapshot of -your mesh: - -# cat /sys/kernel/debug/batman_adv/bat0/vis_data - -This raw output is intended to be easily parsable and convertable -with other tools. Have a look at the batctl README if you want a -vis output in dot or json format for instance and how those out- -puts could then be visualised in an image. - -The raw format consists of comma separated values per entry where -each entry is giving information about a certain source inter- -face. Each entry can/has to have the following values: --> "mac" - mac address of an originator's source interface - (each line begins with it) --> "TQ mac value" - src mac's link quality towards mac address - of a neighbor originator's interface which - is being used for routing --> "HNA mac" - HNA announced by source mac --> "PRIMARY" - this is a primary interface --> "SEC mac" - secondary mac address of source - (requires preceding PRIMARY) - -The TQ value has a range from 4 to 255 with 255 being the best. -The HNA entries are showing which hosts are connected to the mesh -via bat0 or being bridged into the mesh network. The PRIMARY/SEC -values are only applied on primary interfaces - - -LOGGING/DEBUGGING ------------------ - -All error messages, warnings and information messages are sent to -the kernel log. Depending on your operating system distribution -this can be read in one of a number of ways. Try using the com- -mands: dmesg, logread, or looking in the files /var/log/kern.log -or /var/log/syslog. All batman-adv messages are prefixed with -"batman-adv:" So to see just these messages try - -# dmesg | grep batman-adv - -When investigating problems with your mesh network it is some- -times necessary to see more detail debug messages. This must be -enabled when compiling the batman-adv module. When building bat- -man-adv as part of kernel, use "make menuconfig" and enable the -option "B.A.T.M.A.N. debugging". - -Those additional debug messages can be accessed using a special -file in debugfs - -# cat /sys/kernel/debug/batman_adv/bat0/log - -The additional debug output is by default disabled. It can be en- -abled during run time. Following log_levels are defined: - -0 - All debug output disabled -1 - Enable messages related to routing / flooding / broadcasting -2 - Enable route or hna added / changed / deleted -3 - Enable all messages - -The debug output can be changed at runtime using the file -/sys/class/net/bat0/mesh/log_level. e.g. - -# echo 2 > /sys/class/net/bat0/mesh/log_level - -will enable debug messages for when routes or HNAs change. - - -BATCTL ------- - -As batman advanced operates on layer 2 all hosts participating in -the virtual switch are completely transparent for all protocols -above layer 2. Therefore the common diagnosis tools do not work -as expected. To overcome these problems batctl was created. At -the moment the batctl contains ping, traceroute, tcpdump and -interfaces to the kernel module settings. - -For more information, please see the manpage (man batctl). - -batctl is available on http://www.open-mesh.org/ - - -CONTACT -------- - -Please send us comments, experiences, questions, anything :) - -IRC: #batman on irc.freenode.org -Mailing-list: b.a.t.m.a.n@b.a.t.m.a.n@lists.open-mesh.org - (optional subscription at - https://lists.open-mesh.org/mm/listinfo/b.a.t.m.a.n) - -You can also contact the Authors: - -Marek Lindner -Simon Wunderlich diff --git a/drivers/staging/batman-adv/TODO b/drivers/staging/batman-adv/TODO deleted file mode 100644 index ba69ba3ab62d..000000000000 --- a/drivers/staging/batman-adv/TODO +++ /dev/null @@ -1,10 +0,0 @@ - * Request a new review - * Process the comments from the review - * Move into mainline proper - -Please send all patches to: - Marek Lindner - Simon Wunderlich - Sven Eckelmann - b.a.t.m.a.n@lists.open-mesh.org - Greg Kroah-Hartman diff --git a/drivers/staging/batman-adv/aggregation.c b/drivers/staging/batman-adv/aggregation.c deleted file mode 100644 index 0c92e3b35abf..000000000000 --- a/drivers/staging/batman-adv/aggregation.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "aggregation.h" -#include "send.h" -#include "routing.h" - -/* calculate the size of the hna information for a given packet */ -static int hna_len(struct batman_packet *batman_packet) -{ - return batman_packet->num_hna * ETH_ALEN; -} - -/* return true if new_packet can be aggregated with forw_packet */ -static bool can_aggregate_with(struct batman_packet *new_batman_packet, - int packet_len, - unsigned long send_time, - bool directlink, - struct batman_if *if_incoming, - struct forw_packet *forw_packet) -{ - struct batman_packet *batman_packet = - (struct batman_packet *)forw_packet->skb->data; - int aggregated_bytes = forw_packet->packet_len + packet_len; - - /** - * we can aggregate the current packet to this aggregated packet - * if: - * - * - the send time is within our MAX_AGGREGATION_MS time - * - the resulting packet wont be bigger than - * MAX_AGGREGATION_BYTES - */ - - if (time_before(send_time, forw_packet->send_time) && - time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS), - forw_packet->send_time) && - (aggregated_bytes <= MAX_AGGREGATION_BYTES)) { - - /** - * check aggregation compatibility - * -> direct link packets are broadcasted on - * their interface only - * -> aggregate packet if the current packet is - * a "global" packet as well as the base - * packet - */ - - /* packets without direct link flag and high TTL - * are flooded through the net */ - if ((!directlink) && - (!(batman_packet->flags & DIRECTLINK)) && - (batman_packet->ttl != 1) && - - /* own packets originating non-primary - * interfaces leave only that interface */ - ((!forw_packet->own) || - (forw_packet->if_incoming->if_num == 0))) - return true; - - /* if the incoming packet is sent via this one - * interface only - we still can aggregate */ - if ((directlink) && - (new_batman_packet->ttl == 1) && - (forw_packet->if_incoming == if_incoming) && - - /* packets from direct neighbors or - * own secondary interface packets - * (= secondary interface packets in general) */ - (batman_packet->flags & DIRECTLINK || - (forw_packet->own && - forw_packet->if_incoming->if_num != 0))) - return true; - } - - return false; -} - -#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) -/* create a new aggregated packet and add this packet to it */ -static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, - unsigned long send_time, bool direct_link, - struct batman_if *if_incoming, - int own_packet) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct forw_packet *forw_packet_aggr; - unsigned char *skb_buff; - - /* own packet should always be scheduled */ - if (!own_packet) { - if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) { - bat_dbg(DBG_BATMAN, bat_priv, - "batman packet queue full\n"); - return; - } - } - - forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); - if (!forw_packet_aggr) { - if (!own_packet) - atomic_inc(&bat_priv->batman_queue_left); - return; - } - - if ((atomic_read(&bat_priv->aggregated_ogms)) && - (packet_len < MAX_AGGREGATION_BYTES)) - forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + - sizeof(struct ethhdr)); - else - forw_packet_aggr->skb = dev_alloc_skb(packet_len + - sizeof(struct ethhdr)); - - if (!forw_packet_aggr->skb) { - if (!own_packet) - atomic_inc(&bat_priv->batman_queue_left); - kfree(forw_packet_aggr); - return; - } - skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr)); - - INIT_HLIST_NODE(&forw_packet_aggr->list); - - skb_buff = skb_put(forw_packet_aggr->skb, packet_len); - forw_packet_aggr->packet_len = packet_len; - memcpy(skb_buff, packet_buff, packet_len); - - forw_packet_aggr->own = own_packet; - forw_packet_aggr->if_incoming = if_incoming; - forw_packet_aggr->num_packets = 0; - forw_packet_aggr->direct_link_flags = 0; - forw_packet_aggr->send_time = send_time; - - /* save packet direct link flag status */ - if (direct_link) - forw_packet_aggr->direct_link_flags |= 1; - - /* add new packet to packet list */ - spin_lock_bh(&bat_priv->forw_bat_list_lock); - hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); - spin_unlock_bh(&bat_priv->forw_bat_list_lock); - - /* start timer for this packet */ - INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, - send_outstanding_bat_packet); - queue_delayed_work(bat_event_workqueue, - &forw_packet_aggr->delayed_work, - send_time - jiffies); -} - -/* aggregate a new packet into the existing aggregation */ -static void aggregate(struct forw_packet *forw_packet_aggr, - unsigned char *packet_buff, - int packet_len, - bool direct_link) -{ - unsigned char *skb_buff; - - skb_buff = skb_put(forw_packet_aggr->skb, packet_len); - memcpy(skb_buff, packet_buff, packet_len); - forw_packet_aggr->packet_len += packet_len; - forw_packet_aggr->num_packets++; - - /* save packet direct link flag status */ - if (direct_link) - forw_packet_aggr->direct_link_flags |= - (1 << forw_packet_aggr->num_packets); -} - -void add_bat_packet_to_list(struct bat_priv *bat_priv, - unsigned char *packet_buff, int packet_len, - struct batman_if *if_incoming, char own_packet, - unsigned long send_time) -{ - /** - * _aggr -> pointer to the packet we want to aggregate with - * _pos -> pointer to the position in the queue - */ - struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; - struct hlist_node *tmp_node; - struct batman_packet *batman_packet = - (struct batman_packet *)packet_buff; - bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; - - /* find position for the packet in the forward queue */ - spin_lock_bh(&bat_priv->forw_bat_list_lock); - /* own packets are not to be aggregated */ - if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { - hlist_for_each_entry(forw_packet_pos, tmp_node, - &bat_priv->forw_bat_list, list) { - if (can_aggregate_with(batman_packet, - packet_len, - send_time, - direct_link, - if_incoming, - forw_packet_pos)) { - forw_packet_aggr = forw_packet_pos; - break; - } - } - } - - /* nothing to aggregate with - either aggregation disabled or no - * suitable aggregation packet found */ - if (forw_packet_aggr == NULL) { - /* the following section can run without the lock */ - spin_unlock_bh(&bat_priv->forw_bat_list_lock); - - /** - * if we could not aggregate this packet with one of the others - * we hold it back for a while, so that it might be aggregated - * later on - */ - if ((!own_packet) && - (atomic_read(&bat_priv->aggregated_ogms))) - send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); - - new_aggregated_packet(packet_buff, packet_len, - send_time, direct_link, - if_incoming, own_packet); - } else { - aggregate(forw_packet_aggr, - packet_buff, packet_len, - direct_link); - spin_unlock_bh(&bat_priv->forw_bat_list_lock); - } -} - -/* unpack the aggregated packets and process them one by one */ -void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, - int packet_len, struct batman_if *if_incoming) -{ - struct batman_packet *batman_packet; - int buff_pos = 0; - unsigned char *hna_buff; - - batman_packet = (struct batman_packet *)packet_buff; - - do { - /* network to host order for our 32bit seqno, and the - orig_interval. */ - batman_packet->seqno = ntohl(batman_packet->seqno); - - hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN; - receive_bat_packet(ethhdr, batman_packet, - hna_buff, hna_len(batman_packet), - if_incoming); - - buff_pos += BAT_PACKET_LEN + hna_len(batman_packet); - batman_packet = (struct batman_packet *) - (packet_buff + buff_pos); - } while (aggregated_packet(buff_pos, packet_len, - batman_packet->num_hna)); -} diff --git a/drivers/staging/batman-adv/aggregation.h b/drivers/staging/batman-adv/aggregation.h deleted file mode 100644 index 71a91b3da913..000000000000 --- a/drivers/staging/batman-adv/aggregation.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_AGGREGATION_H_ -#define _NET_BATMAN_ADV_AGGREGATION_H_ - -#include "main.h" - -/* is there another aggregated packet here? */ -static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) -{ - int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN); - - return (next_buff_pos <= packet_len) && - (next_buff_pos <= MAX_AGGREGATION_BYTES); -} - -void add_bat_packet_to_list(struct bat_priv *bat_priv, - unsigned char *packet_buff, int packet_len, - struct batman_if *if_incoming, char own_packet, - unsigned long send_time); -void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, - int packet_len, struct batman_if *if_incoming); - -#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */ diff --git a/drivers/staging/batman-adv/bat_debugfs.c b/drivers/staging/batman-adv/bat_debugfs.c deleted file mode 100644 index 0ae81d07f102..000000000000 --- a/drivers/staging/batman-adv/bat_debugfs.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" - -#include - -#include "bat_debugfs.h" -#include "translation-table.h" -#include "originator.h" -#include "hard-interface.h" -#include "gateway_common.h" -#include "gateway_client.h" -#include "soft-interface.h" -#include "vis.h" -#include "icmp_socket.h" - -static struct dentry *bat_debugfs; - -#ifdef CONFIG_BATMAN_ADV_DEBUG -#define LOG_BUFF_MASK (log_buff_len-1) -#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) - -static int log_buff_len = LOG_BUF_LEN; - -static void emit_log_char(struct debug_log *debug_log, char c) -{ - LOG_BUFF(debug_log->log_end) = c; - debug_log->log_end++; - - if (debug_log->log_end - debug_log->log_start > log_buff_len) - debug_log->log_start = debug_log->log_end - log_buff_len; -} - -static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) -{ - int printed_len; - va_list args; - static char debug_log_buf[256]; - char *p; - - if (!debug_log) - return 0; - - spin_lock_bh(&debug_log->lock); - va_start(args, fmt); - printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), - fmt, args); - va_end(args); - - for (p = debug_log_buf; *p != 0; p++) - emit_log_char(debug_log, *p); - - spin_unlock_bh(&debug_log->lock); - - wake_up(&debug_log->queue_wait); - - return 0; -} - -int debug_log(struct bat_priv *bat_priv, char *fmt, ...) -{ - va_list args; - char tmp_log_buf[256]; - - va_start(args, fmt); - vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); - fdebug_log(bat_priv->debug_log, "[%10u] %s", - (jiffies / HZ), tmp_log_buf); - va_end(args); - - return 0; -} - -static int log_open(struct inode *inode, struct file *file) -{ - nonseekable_open(inode, file); - file->private_data = inode->i_private; - inc_module_count(); - return 0; -} - -static int log_release(struct inode *inode, struct file *file) -{ - dec_module_count(); - return 0; -} - -static ssize_t log_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct bat_priv *bat_priv = file->private_data; - struct debug_log *debug_log = bat_priv->debug_log; - int error, i = 0; - char c; - - if ((file->f_flags & O_NONBLOCK) && - !(debug_log->log_end - debug_log->log_start)) - return -EAGAIN; - - if ((!buf) || (count < 0)) - return -EINVAL; - - if (count == 0) - return 0; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - error = wait_event_interruptible(debug_log->queue_wait, - (debug_log->log_start - debug_log->log_end)); - - if (error) - return error; - - spin_lock_bh(&debug_log->lock); - - while ((!error) && (i < count) && - (debug_log->log_start != debug_log->log_end)) { - c = LOG_BUFF(debug_log->log_start); - - debug_log->log_start++; - - spin_unlock_bh(&debug_log->lock); - - error = __put_user(c, buf); - - spin_lock_bh(&debug_log->lock); - - buf++; - i++; - - } - - spin_unlock_bh(&debug_log->lock); - - if (!error) - return i; - - return error; -} - -static unsigned int log_poll(struct file *file, poll_table *wait) -{ - struct bat_priv *bat_priv = file->private_data; - struct debug_log *debug_log = bat_priv->debug_log; - - poll_wait(file, &debug_log->queue_wait, wait); - - if (debug_log->log_end - debug_log->log_start) - return POLLIN | POLLRDNORM; - - return 0; -} - -static const struct file_operations log_fops = { - .open = log_open, - .release = log_release, - .read = log_read, - .poll = log_poll, - .llseek = no_llseek, -}; - -static int debug_log_setup(struct bat_priv *bat_priv) -{ - struct dentry *d; - - if (!bat_priv->debug_dir) - goto err; - - bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC); - if (!bat_priv->debug_log) - goto err; - - spin_lock_init(&bat_priv->debug_log->lock); - init_waitqueue_head(&bat_priv->debug_log->queue_wait); - - d = debugfs_create_file("log", S_IFREG | S_IRUSR, - bat_priv->debug_dir, bat_priv, &log_fops); - if (d) - goto err; - - return 0; - -err: - return 1; -} - -static void debug_log_cleanup(struct bat_priv *bat_priv) -{ - kfree(bat_priv->debug_log); - bat_priv->debug_log = NULL; -} -#else /* CONFIG_BATMAN_ADV_DEBUG */ -static int debug_log_setup(struct bat_priv *bat_priv) -{ - bat_priv->debug_log = NULL; - return 0; -} - -static void debug_log_cleanup(struct bat_priv *bat_priv) -{ - return; -} -#endif - -static int originators_open(struct inode *inode, struct file *file) -{ - struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, orig_seq_print_text, net_dev); -} - -static int gateways_open(struct inode *inode, struct file *file) -{ - struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, gw_client_seq_print_text, net_dev); -} - -static int softif_neigh_open(struct inode *inode, struct file *file) -{ - struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, softif_neigh_seq_print_text, net_dev); -} - -static int transtable_global_open(struct inode *inode, struct file *file) -{ - struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, hna_global_seq_print_text, net_dev); -} - -static int transtable_local_open(struct inode *inode, struct file *file) -{ - struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, hna_local_seq_print_text, net_dev); -} - -static int vis_data_open(struct inode *inode, struct file *file) -{ - struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, vis_seq_print_text, net_dev); -} - -struct bat_debuginfo { - struct attribute attr; - const struct file_operations fops; -}; - -#define BAT_DEBUGINFO(_name, _mode, _open) \ -struct bat_debuginfo bat_debuginfo_##_name = { \ - .attr = { .name = __stringify(_name), \ - .mode = _mode, }, \ - .fops = { .owner = THIS_MODULE, \ - .open = _open, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ - } \ -}; - -static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); -static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); -static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); -static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); -static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); -static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); - -static struct bat_debuginfo *mesh_debuginfos[] = { - &bat_debuginfo_originators, - &bat_debuginfo_gateways, - &bat_debuginfo_softif_neigh, - &bat_debuginfo_transtable_global, - &bat_debuginfo_transtable_local, - &bat_debuginfo_vis_data, - NULL, -}; - -void debugfs_init(void) -{ - bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); - if (bat_debugfs == ERR_PTR(-ENODEV)) - bat_debugfs = NULL; -} - -void debugfs_destroy(void) -{ - if (bat_debugfs) { - debugfs_remove_recursive(bat_debugfs); - bat_debugfs = NULL; - } -} - -int debugfs_add_meshif(struct net_device *dev) -{ - struct bat_priv *bat_priv = netdev_priv(dev); - struct bat_debuginfo **bat_debug; - struct dentry *file; - - if (!bat_debugfs) - goto out; - - bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); - if (!bat_priv->debug_dir) - goto out; - - bat_socket_setup(bat_priv); - debug_log_setup(bat_priv); - - for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { - file = debugfs_create_file(((*bat_debug)->attr).name, - S_IFREG | ((*bat_debug)->attr).mode, - bat_priv->debug_dir, - dev, &(*bat_debug)->fops); - if (!file) { - bat_err(dev, "Can't add debugfs file: %s/%s\n", - dev->name, ((*bat_debug)->attr).name); - goto rem_attr; - } - } - - return 0; -rem_attr: - debugfs_remove_recursive(bat_priv->debug_dir); - bat_priv->debug_dir = NULL; -out: -#ifdef CONFIG_DEBUG_FS - return -ENOMEM; -#else - return 0; -#endif /* CONFIG_DEBUG_FS */ -} - -void debugfs_del_meshif(struct net_device *dev) -{ - struct bat_priv *bat_priv = netdev_priv(dev); - - debug_log_cleanup(bat_priv); - - if (bat_debugfs) { - debugfs_remove_recursive(bat_priv->debug_dir); - bat_priv->debug_dir = NULL; - } -} diff --git a/drivers/staging/batman-adv/bat_debugfs.h b/drivers/staging/batman-adv/bat_debugfs.h deleted file mode 100644 index 72df532b7d5f..000000000000 --- a/drivers/staging/batman-adv/bat_debugfs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - - -#ifndef _NET_BATMAN_ADV_DEBUGFS_H_ -#define _NET_BATMAN_ADV_DEBUGFS_H_ - -#define DEBUGFS_BAT_SUBDIR "batman_adv" - -void debugfs_init(void); -void debugfs_destroy(void); -int debugfs_add_meshif(struct net_device *dev); -void debugfs_del_meshif(struct net_device *dev); - -#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c deleted file mode 100644 index cd7bb51825f1..000000000000 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright (C) 2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "bat_sysfs.h" -#include "translation-table.h" -#include "originator.h" -#include "hard-interface.h" -#include "gateway_common.h" -#include "gateway_client.h" -#include "vis.h" - -#define to_dev(obj) container_of(obj, struct device, kobj) -#define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent)) -#define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj)) - -/* Use this, if you have customized show and store functions */ -#define BAT_ATTR(_name, _mode, _show, _store) \ -struct bat_attribute bat_attr_##_name = { \ - .attr = {.name = __stringify(_name), \ - .mode = _mode }, \ - .show = _show, \ - .store = _store, \ -}; - -#define BAT_ATTR_STORE_BOOL(_name, _post_func) \ -ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ - char *buff, size_t count) \ -{ \ - struct net_device *net_dev = kobj_to_netdev(kobj); \ - struct bat_priv *bat_priv = netdev_priv(net_dev); \ - return __store_bool_attr(buff, count, _post_func, attr, \ - &bat_priv->_name, net_dev); \ -} - -#define BAT_ATTR_SHOW_BOOL(_name) \ -ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ - char *buff) \ -{ \ - struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ - return sprintf(buff, "%s\n", \ - atomic_read(&bat_priv->_name) == 0 ? \ - "disabled" : "enabled"); \ -} \ - -/* Use this, if you are going to turn a [name] in bat_priv on or off */ -#define BAT_ATTR_BOOL(_name, _mode, _post_func) \ - static BAT_ATTR_STORE_BOOL(_name, _post_func) \ - static BAT_ATTR_SHOW_BOOL(_name) \ - static BAT_ATTR(_name, _mode, show_##_name, store_##_name) - - -#define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ -ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ - char *buff, size_t count) \ -{ \ - struct net_device *net_dev = kobj_to_netdev(kobj); \ - struct bat_priv *bat_priv = netdev_priv(net_dev); \ - return __store_uint_attr(buff, count, _min, _max, _post_func, \ - attr, &bat_priv->_name, net_dev); \ -} - -#define BAT_ATTR_SHOW_UINT(_name) \ -ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ - char *buff) \ -{ \ - struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ - return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ -} \ - -/* Use this, if you are going to set [name] in bat_priv to unsigned integer - * values only */ -#define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ - static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ - static BAT_ATTR_SHOW_UINT(_name) \ - static BAT_ATTR(_name, _mode, show_##_name, store_##_name) - - -static int store_bool_attr(char *buff, size_t count, - struct net_device *net_dev, - char *attr_name, atomic_t *attr) -{ - int enabled = -1; - - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - if ((strncmp(buff, "1", 2) == 0) || - (strncmp(buff, "enable", 7) == 0) || - (strncmp(buff, "enabled", 8) == 0)) - enabled = 1; - - if ((strncmp(buff, "0", 2) == 0) || - (strncmp(buff, "disable", 8) == 0) || - (strncmp(buff, "disabled", 9) == 0)) - enabled = 0; - - if (enabled < 0) { - bat_info(net_dev, - "%s: Invalid parameter received: %s\n", - attr_name, buff); - return -EINVAL; - } - - if (atomic_read(attr) == enabled) - return count; - - bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, - atomic_read(attr) == 1 ? "enabled" : "disabled", - enabled == 1 ? "enabled" : "disabled"); - - atomic_set(attr, (unsigned)enabled); - return count; -} - -static inline ssize_t __store_bool_attr(char *buff, size_t count, - void (*post_func)(struct net_device *), - struct attribute *attr, - atomic_t *attr_store, struct net_device *net_dev) -{ - int ret; - - ret = store_bool_attr(buff, count, net_dev, (char *)attr->name, - attr_store); - if (post_func && ret) - post_func(net_dev); - - return ret; -} - -static int store_uint_attr(char *buff, size_t count, - struct net_device *net_dev, char *attr_name, - unsigned int min, unsigned int max, atomic_t *attr) -{ - unsigned long uint_val; - int ret; - - ret = strict_strtoul(buff, 10, &uint_val); - if (ret) { - bat_info(net_dev, - "%s: Invalid parameter received: %s\n", - attr_name, buff); - return -EINVAL; - } - - if (uint_val < min) { - bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", - attr_name, uint_val, min); - return -EINVAL; - } - - if (uint_val > max) { - bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", - attr_name, uint_val, max); - return -EINVAL; - } - - if (atomic_read(attr) == uint_val) - return count; - - bat_info(net_dev, "%s: Changing from: %i to: %lu\n", - attr_name, atomic_read(attr), uint_val); - - atomic_set(attr, uint_val); - return count; -} - -static inline ssize_t __store_uint_attr(char *buff, size_t count, - int min, int max, - void (*post_func)(struct net_device *), - struct attribute *attr, - atomic_t *attr_store, struct net_device *net_dev) -{ - int ret; - - ret = store_uint_attr(buff, count, net_dev, (char *)attr->name, - min, max, attr_store); - if (post_func && ret) - post_func(net_dev); - - return ret; -} - -static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct bat_priv *bat_priv = kobj_to_batpriv(kobj); - int vis_mode = atomic_read(&bat_priv->vis_mode); - - return sprintf(buff, "%s\n", - vis_mode == VIS_TYPE_CLIENT_UPDATE ? - "client" : "server"); -} - -static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) -{ - struct net_device *net_dev = kobj_to_netdev(kobj); - struct bat_priv *bat_priv = netdev_priv(net_dev); - unsigned long val; - int ret, vis_mode_tmp = -1; - - ret = strict_strtoul(buff, 10, &val); - - if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || - (strncmp(buff, "client", 6) == 0) || - (strncmp(buff, "off", 3) == 0)) - vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; - - if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || - (strncmp(buff, "server", 6) == 0)) - vis_mode_tmp = VIS_TYPE_SERVER_SYNC; - - if (vis_mode_tmp < 0) { - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - bat_info(net_dev, - "Invalid parameter for 'vis mode' setting received: " - "%s\n", buff); - return -EINVAL; - } - - if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) - return count; - - bat_info(net_dev, "Changing vis mode from: %s to: %s\n", - atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? - "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? - "client" : "server"); - - atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); - return count; -} - -static void post_gw_deselect(struct net_device *net_dev) -{ - struct bat_priv *bat_priv = netdev_priv(net_dev); - gw_deselect(bat_priv); -} - -static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct bat_priv *bat_priv = kobj_to_batpriv(kobj); - int bytes_written; - - switch (atomic_read(&bat_priv->gw_mode)) { - case GW_MODE_CLIENT: - bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); - break; - case GW_MODE_SERVER: - bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); - break; - default: - bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); - break; - } - - return bytes_written; -} - -static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) -{ - struct net_device *net_dev = kobj_to_netdev(kobj); - struct bat_priv *bat_priv = netdev_priv(net_dev); - char *curr_gw_mode_str; - int gw_mode_tmp = -1; - - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) - gw_mode_tmp = GW_MODE_OFF; - - if (strncmp(buff, GW_MODE_CLIENT_NAME, - strlen(GW_MODE_CLIENT_NAME)) == 0) - gw_mode_tmp = GW_MODE_CLIENT; - - if (strncmp(buff, GW_MODE_SERVER_NAME, - strlen(GW_MODE_SERVER_NAME)) == 0) - gw_mode_tmp = GW_MODE_SERVER; - - if (gw_mode_tmp < 0) { - bat_info(net_dev, - "Invalid parameter for 'gw mode' setting received: " - "%s\n", buff); - return -EINVAL; - } - - if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) - return count; - - switch (atomic_read(&bat_priv->gw_mode)) { - case GW_MODE_CLIENT: - curr_gw_mode_str = GW_MODE_CLIENT_NAME; - break; - case GW_MODE_SERVER: - curr_gw_mode_str = GW_MODE_SERVER_NAME; - break; - default: - curr_gw_mode_str = GW_MODE_OFF_NAME; - break; - } - - bat_info(net_dev, "Changing gw mode from: %s to: %s\n", - curr_gw_mode_str, buff); - - gw_deselect(bat_priv); - atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); - return count; -} - -static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct bat_priv *bat_priv = kobj_to_batpriv(kobj); - int down, up; - int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); - - gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); - return sprintf(buff, "%i%s/%i%s\n", - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); -} - -static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) -{ - struct net_device *net_dev = kobj_to_netdev(kobj); - - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - return gw_bandwidth_set(net_dev, buff, count); -} - -BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); -BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); -BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); -static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); -static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); -BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); -BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); -BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, - post_gw_deselect); -static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, - store_gw_bwidth); -#ifdef CONFIG_BATMAN_ADV_DEBUG -BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); -#endif - -static struct bat_attribute *mesh_attrs[] = { - &bat_attr_aggregated_ogms, - &bat_attr_bonding, - &bat_attr_fragmentation, - &bat_attr_vis_mode, - &bat_attr_gw_mode, - &bat_attr_orig_interval, - &bat_attr_hop_penalty, - &bat_attr_gw_sel_class, - &bat_attr_gw_bandwidth, -#ifdef CONFIG_BATMAN_ADV_DEBUG - &bat_attr_log_level, -#endif - NULL, -}; - -int sysfs_add_meshif(struct net_device *dev) -{ - struct kobject *batif_kobject = &dev->dev.kobj; - struct bat_priv *bat_priv = netdev_priv(dev); - struct bat_attribute **bat_attr; - int err; - - bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, - batif_kobject); - if (!bat_priv->mesh_obj) { - bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, - SYSFS_IF_MESH_SUBDIR); - goto out; - } - - for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) { - err = sysfs_create_file(bat_priv->mesh_obj, - &((*bat_attr)->attr)); - if (err) { - bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", - dev->name, SYSFS_IF_MESH_SUBDIR, - ((*bat_attr)->attr).name); - goto rem_attr; - } - } - - return 0; - -rem_attr: - for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) - sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); - - kobject_put(bat_priv->mesh_obj); - bat_priv->mesh_obj = NULL; -out: - return -ENOMEM; -} - -void sysfs_del_meshif(struct net_device *dev) -{ - struct bat_priv *bat_priv = netdev_priv(dev); - struct bat_attribute **bat_attr; - - for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) - sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); - - kobject_put(bat_priv->mesh_obj); - bat_priv->mesh_obj = NULL; -} - -static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct net_device *net_dev = kobj_to_netdev(kobj); - struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); - ssize_t length; - - if (!batman_if) - return 0; - - length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? - "none" : batman_if->soft_iface->name); - - kref_put(&batman_if->refcount, hardif_free_ref); - - return length; -} - -static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, - char *buff, size_t count) -{ - struct net_device *net_dev = kobj_to_netdev(kobj); - struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); - int status_tmp = -1; - int ret; - - if (!batman_if) - return count; - - if (buff[count - 1] == '\n') - buff[count - 1] = '\0'; - - if (strlen(buff) >= IFNAMSIZ) { - pr_err("Invalid parameter for 'mesh_iface' setting received: " - "interface name too long '%s'\n", buff); - kref_put(&batman_if->refcount, hardif_free_ref); - return -EINVAL; - } - - if (strncmp(buff, "none", 4) == 0) - status_tmp = IF_NOT_IN_USE; - else - status_tmp = IF_I_WANT_YOU; - - if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && - (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { - kref_put(&batman_if->refcount, hardif_free_ref); - return count; - } - - if (status_tmp == IF_NOT_IN_USE) { - rtnl_lock(); - hardif_disable_interface(batman_if); - rtnl_unlock(); - kref_put(&batman_if->refcount, hardif_free_ref); - return count; - } - - /* if the interface already is in use */ - if (batman_if->if_status != IF_NOT_IN_USE) { - rtnl_lock(); - hardif_disable_interface(batman_if); - rtnl_unlock(); - } - - ret = hardif_enable_interface(batman_if, buff); - kref_put(&batman_if->refcount, hardif_free_ref); - - return ret; -} - -static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, - char *buff) -{ - struct net_device *net_dev = kobj_to_netdev(kobj); - struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); - ssize_t length; - - if (!batman_if) - return 0; - - switch (batman_if->if_status) { - case IF_TO_BE_REMOVED: - length = sprintf(buff, "disabling\n"); - break; - case IF_INACTIVE: - length = sprintf(buff, "inactive\n"); - break; - case IF_ACTIVE: - length = sprintf(buff, "active\n"); - break; - case IF_TO_BE_ACTIVATED: - length = sprintf(buff, "enabling\n"); - break; - case IF_NOT_IN_USE: - default: - length = sprintf(buff, "not in use\n"); - break; - } - - kref_put(&batman_if->refcount, hardif_free_ref); - - return length; -} - -static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, - show_mesh_iface, store_mesh_iface); -static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); - -static struct bat_attribute *batman_attrs[] = { - &bat_attr_mesh_iface, - &bat_attr_iface_status, - NULL, -}; - -int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) -{ - struct kobject *hardif_kobject = &dev->dev.kobj; - struct bat_attribute **bat_attr; - int err; - - *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR, - hardif_kobject); - - if (!*hardif_obj) { - bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, - SYSFS_IF_BAT_SUBDIR); - goto out; - } - - for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) { - err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); - if (err) { - bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", - dev->name, SYSFS_IF_BAT_SUBDIR, - ((*bat_attr)->attr).name); - goto rem_attr; - } - } - - return 0; - -rem_attr: - for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) - sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); -out: - return -ENOMEM; -} - -void sysfs_del_hardif(struct kobject **hardif_obj) -{ - kobject_put(*hardif_obj); - *hardif_obj = NULL; -} diff --git a/drivers/staging/batman-adv/bat_sysfs.h b/drivers/staging/batman-adv/bat_sysfs.h deleted file mode 100644 index 7f186c007b4f..000000000000 --- a/drivers/staging/batman-adv/bat_sysfs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - - -#ifndef _NET_BATMAN_ADV_SYSFS_H_ -#define _NET_BATMAN_ADV_SYSFS_H_ - -#define SYSFS_IF_MESH_SUBDIR "mesh" -#define SYSFS_IF_BAT_SUBDIR "batman_adv" - -struct bat_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, struct attribute *attr, - char *buf); - ssize_t (*store)(struct kobject *kobj, struct attribute *attr, - char *buf, size_t count); -}; - -int sysfs_add_meshif(struct net_device *dev); -void sysfs_del_meshif(struct net_device *dev); -int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev); -void sysfs_del_hardif(struct kobject **hardif_obj); - -#endif /* _NET_BATMAN_ADV_SYSFS_H_ */ diff --git a/drivers/staging/batman-adv/bitarray.c b/drivers/staging/batman-adv/bitarray.c deleted file mode 100644 index 814274fbaa2f..000000000000 --- a/drivers/staging/batman-adv/bitarray.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: - * - * Simon Wunderlich, Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "bitarray.h" - -#include - -/* returns true if the corresponding bit in the given seq_bits indicates true - * and curr_seqno is within range of last_seqno */ -uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint32_t last_seqno, - uint32_t curr_seqno) -{ - int32_t diff, word_offset, word_num; - - diff = last_seqno - curr_seqno; - if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) { - return 0; - } else { - /* which word */ - word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE; - /* which position in the selected word */ - word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE; - - if (seq_bits[word_num] & 1 << word_offset) - return 1; - else - return 0; - } -} - -/* turn corresponding bit on, so we can remember that we got the packet */ -void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n) -{ - int32_t word_offset, word_num; - - /* if too old, just drop it */ - if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE) - return; - - /* which word */ - word_num = n / WORD_BIT_SIZE; - /* which position in the selected word */ - word_offset = n % WORD_BIT_SIZE; - - seq_bits[word_num] |= 1 << word_offset; /* turn the position on */ -} - -/* shift the packet array by n places. */ -static void bit_shift(TYPE_OF_WORD *seq_bits, int32_t n) -{ - int32_t word_offset, word_num; - int32_t i; - - if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE) - return; - - word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */ - word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */ - - for (i = NUM_WORDS - 1; i > word_num; i--) { - /* going from old to new, so we don't overwrite the data we copy - * from. - * - * left is high, right is low: FEDC BA98 7654 3210 - * ^^ ^^ - * vvvv - * ^^^^ = from, vvvvv =to, we'd have word_num==1 and - * word_offset==WORD_BIT_SIZE/2 ????? in this example. - * (=24 bits) - * - * our desired output would be: 9876 5432 1000 0000 - * */ - - seq_bits[i] = - (seq_bits[i - word_num] << word_offset) + - /* take the lower port from the left half, shift it left - * to its final position */ - (seq_bits[i - word_num - 1] >> - (WORD_BIT_SIZE-word_offset)); - /* and the upper part of the right half and shift it left to - * it's position */ - /* for our example that would be: word[0] = 9800 + 0076 = - * 9876 */ - } - /* now for our last word, i==word_num, we only have the it's "left" - * half. that's the 1000 word in our example.*/ - - seq_bits[i] = (seq_bits[i - word_num] << word_offset); - - /* pad the rest with 0, if there is anything */ - i--; - - for (; i >= 0; i--) - seq_bits[i] = 0; -} - -static void bit_reset_window(TYPE_OF_WORD *seq_bits) -{ - int i; - for (i = 0; i < NUM_WORDS; i++) - seq_bits[i] = 0; -} - - -/* receive and process one packet within the sequence number window. - * - * returns: - * 1 if the window was moved (either new or very old) - * 0 if the window was not moved/shifted. - */ -char bit_get_packet(void *priv, TYPE_OF_WORD *seq_bits, - int32_t seq_num_diff, int8_t set_mark) -{ - struct bat_priv *bat_priv = (struct bat_priv *)priv; - - /* sequence number is slightly older. We already got a sequence number - * higher than this one, so we just mark it. */ - - if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) { - if (set_mark) - bit_mark(seq_bits, -seq_num_diff); - return 0; - } - - /* sequence number is slightly newer, so we shift the window and - * set the mark if required */ - - if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) { - bit_shift(seq_bits, seq_num_diff); - - if (set_mark) - bit_mark(seq_bits, 0); - return 1; - } - - /* sequence number is much newer, probably missed a lot of packets */ - - if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE) - || (seq_num_diff < EXPECTED_SEQNO_RANGE)) { - bat_dbg(DBG_BATMAN, bat_priv, - "We missed a lot of packets (%i) !\n", - seq_num_diff - 1); - bit_reset_window(seq_bits); - if (set_mark) - bit_mark(seq_bits, 0); - return 1; - } - - /* received a much older packet. The other host either restarted - * or the old packet got delayed somewhere in the network. The - * packet should be dropped without calling this function if the - * seqno window is protected. */ - - if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) - || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { - - bat_dbg(DBG_BATMAN, bat_priv, - "Other host probably restarted!\n"); - - bit_reset_window(seq_bits); - if (set_mark) - bit_mark(seq_bits, 0); - - return 1; - } - - /* never reached */ - return 0; -} - -/* count the hamming weight, how many good packets did we receive? just count - * the 1's. - */ -int bit_packet_count(TYPE_OF_WORD *seq_bits) -{ - int i, hamming = 0; - - for (i = 0; i < NUM_WORDS; i++) - hamming += hweight_long(seq_bits[i]); - - return hamming; -} diff --git a/drivers/staging/batman-adv/bitarray.h b/drivers/staging/batman-adv/bitarray.h deleted file mode 100644 index 77b1e61847e8..000000000000 --- a/drivers/staging/batman-adv/bitarray.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: - * - * Simon Wunderlich, Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_BITARRAY_H_ -#define _NET_BATMAN_ADV_BITARRAY_H_ - -/* you should choose something big, if you don't want to waste cpu - * and keep the type in sync with bit_packet_count */ -#define TYPE_OF_WORD unsigned long -#define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 8) - -/* returns true if the corresponding bit in the given seq_bits indicates true - * and curr_seqno is within range of last_seqno */ -uint8_t get_bit_status(TYPE_OF_WORD *seq_bits, uint32_t last_seqno, - uint32_t curr_seqno); - -/* turn corresponding bit on, so we can remember that we got the packet */ -void bit_mark(TYPE_OF_WORD *seq_bits, int32_t n); - - -/* receive and process one packet, returns 1 if received seq_num is considered - * new, 0 if old */ -char bit_get_packet(void *priv, TYPE_OF_WORD *seq_bits, - int32_t seq_num_diff, int8_t set_mark); - -/* count the hamming weight, how many good packets did we receive? */ -int bit_packet_count(TYPE_OF_WORD *seq_bits); - -#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */ diff --git a/drivers/staging/batman-adv/gateway_client.c b/drivers/staging/batman-adv/gateway_client.c deleted file mode 100644 index 0065ffb8d96d..000000000000 --- a/drivers/staging/batman-adv/gateway_client.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "gateway_client.h" -#include "gateway_common.h" -#include "hard-interface.h" -#include -#include -#include -#include - -static void gw_node_free_ref(struct kref *refcount) -{ - struct gw_node *gw_node; - - gw_node = container_of(refcount, struct gw_node, refcount); - kfree(gw_node); -} - -static void gw_node_free_rcu(struct rcu_head *rcu) -{ - struct gw_node *gw_node; - - gw_node = container_of(rcu, struct gw_node, rcu); - kref_put(&gw_node->refcount, gw_node_free_ref); -} - -void *gw_get_selected(struct bat_priv *bat_priv) -{ - struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; - - if (!curr_gateway_tmp) - return NULL; - - return curr_gateway_tmp->orig_node; -} - -void gw_deselect(struct bat_priv *bat_priv) -{ - struct gw_node *gw_node = bat_priv->curr_gw; - - bat_priv->curr_gw = NULL; - - if (gw_node) - kref_put(&gw_node->refcount, gw_node_free_ref); -} - -static struct gw_node *gw_select(struct bat_priv *bat_priv, - struct gw_node *new_gw_node) -{ - struct gw_node *curr_gw_node = bat_priv->curr_gw; - - if (new_gw_node) - kref_get(&new_gw_node->refcount); - - bat_priv->curr_gw = new_gw_node; - return curr_gw_node; -} - -void gw_election(struct bat_priv *bat_priv) -{ - struct hlist_node *node; - struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL; - uint8_t max_tq = 0; - uint32_t max_gw_factor = 0, tmp_gw_factor = 0; - int down, up; - - /** - * The batman daemon checks here if we already passed a full originator - * cycle in order to make sure we don't choose the first gateway we - * hear about. This check is based on the daemon's uptime which we - * don't have. - **/ - if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) - return; - - if (bat_priv->curr_gw) - return; - - rcu_read_lock(); - if (hlist_empty(&bat_priv->gw_list)) { - rcu_read_unlock(); - - if (bat_priv->curr_gw) { - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - gw_deselect(bat_priv); - } - - return; - } - - hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { - if (!gw_node->orig_node->router) - continue; - - if (gw_node->deleted) - continue; - - switch (atomic_read(&bat_priv->gw_sel_class)) { - case 1: /* fast connection */ - gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, - &down, &up); - - tmp_gw_factor = (gw_node->orig_node->router->tq_avg * - gw_node->orig_node->router->tq_avg * - down * 100 * 100) / - (TQ_LOCAL_WINDOW_SIZE * - TQ_LOCAL_WINDOW_SIZE * 64); - - if ((tmp_gw_factor > max_gw_factor) || - ((tmp_gw_factor == max_gw_factor) && - (gw_node->orig_node->router->tq_avg > max_tq))) - curr_gw_tmp = gw_node; - break; - - default: /** - * 2: stable connection (use best statistic) - * 3: fast-switch (use best statistic but change as - * soon as a better gateway appears) - * XX: late-switch (use best statistic but change as - * soon as a better gateway appears which has - * $routing_class more tq points) - **/ - if (gw_node->orig_node->router->tq_avg > max_tq) - curr_gw_tmp = gw_node; - break; - } - - if (gw_node->orig_node->router->tq_avg > max_tq) - max_tq = gw_node->orig_node->router->tq_avg; - - if (tmp_gw_factor > max_gw_factor) - max_gw_factor = tmp_gw_factor; - } - - if (bat_priv->curr_gw != curr_gw_tmp) { - if ((bat_priv->curr_gw) && (!curr_gw_tmp)) - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - else if ((!bat_priv->curr_gw) && (curr_gw_tmp)) - bat_dbg(DBG_BATMAN, bat_priv, - "Adding route to gateway %pM " - "(gw_flags: %i, tq: %i)\n", - curr_gw_tmp->orig_node->orig, - curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); - else - bat_dbg(DBG_BATMAN, bat_priv, - "Changing route to gateway %pM " - "(gw_flags: %i, tq: %i)\n", - curr_gw_tmp->orig_node->orig, - curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); - - old_gw_node = gw_select(bat_priv, curr_gw_tmp); - } - - rcu_read_unlock(); - - /* the kfree() has to be outside of the rcu lock */ - if (old_gw_node) - kref_put(&old_gw_node->refcount, gw_node_free_ref); -} - -void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) -{ - struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; - uint8_t gw_tq_avg, orig_tq_avg; - - if (!curr_gateway_tmp) - return; - - if (!curr_gateway_tmp->orig_node) - goto deselect; - - if (!curr_gateway_tmp->orig_node->router) - goto deselect; - - /* this node already is the gateway */ - if (curr_gateway_tmp->orig_node == orig_node) - return; - - if (!orig_node->router) - return; - - gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; - orig_tq_avg = orig_node->router->tq_avg; - - /* the TQ value has to be better */ - if (orig_tq_avg < gw_tq_avg) - return; - - /** - * if the routing class is greater than 3 the value tells us how much - * greater the TQ value of the new gateway must be - **/ - if ((atomic_read(&bat_priv->gw_sel_class) > 3) && - (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class))) - return; - - bat_dbg(DBG_BATMAN, bat_priv, - "Restarting gateway selection: better gateway found (tq curr: " - "%i, tq new: %i)\n", - gw_tq_avg, orig_tq_avg); - -deselect: - gw_deselect(bat_priv); -} - -static void gw_node_add(struct bat_priv *bat_priv, - struct orig_node *orig_node, uint8_t new_gwflags) -{ - struct gw_node *gw_node; - int down, up; - - gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); - if (!gw_node) - return; - - memset(gw_node, 0, sizeof(struct gw_node)); - INIT_HLIST_NODE(&gw_node->list); - gw_node->orig_node = orig_node; - kref_init(&gw_node->refcount); - - spin_lock_bh(&bat_priv->gw_list_lock); - hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list); - spin_unlock_bh(&bat_priv->gw_list_lock); - - gw_bandwidth_to_kbit(new_gwflags, &down, &up); - bat_dbg(DBG_BATMAN, bat_priv, - "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", - orig_node->orig, new_gwflags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); -} - -void gw_node_update(struct bat_priv *bat_priv, - struct orig_node *orig_node, uint8_t new_gwflags) -{ - struct hlist_node *node; - struct gw_node *gw_node; - - rcu_read_lock(); - hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { - if (gw_node->orig_node != orig_node) - continue; - - bat_dbg(DBG_BATMAN, bat_priv, - "Gateway class of originator %pM changed from " - "%i to %i\n", - orig_node->orig, gw_node->orig_node->gw_flags, - new_gwflags); - - gw_node->deleted = 0; - - if (new_gwflags == 0) { - gw_node->deleted = jiffies; - bat_dbg(DBG_BATMAN, bat_priv, - "Gateway %pM removed from gateway list\n", - orig_node->orig); - - if (gw_node == bat_priv->curr_gw) { - rcu_read_unlock(); - gw_deselect(bat_priv); - return; - } - } - - rcu_read_unlock(); - return; - } - rcu_read_unlock(); - - if (new_gwflags == 0) - return; - - gw_node_add(bat_priv, orig_node, new_gwflags); -} - -void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) -{ - return gw_node_update(bat_priv, orig_node, 0); -} - -void gw_node_purge(struct bat_priv *bat_priv) -{ - struct gw_node *gw_node; - struct hlist_node *node, *node_tmp; - unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; - - spin_lock_bh(&bat_priv->gw_list_lock); - - hlist_for_each_entry_safe(gw_node, node, node_tmp, - &bat_priv->gw_list, list) { - if (((!gw_node->deleted) || - (time_before(jiffies, gw_node->deleted + timeout))) && - atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) - continue; - - if (bat_priv->curr_gw == gw_node) - gw_deselect(bat_priv); - - hlist_del_rcu(&gw_node->list); - call_rcu(&gw_node->rcu, gw_node_free_rcu); - } - - - spin_unlock_bh(&bat_priv->gw_list_lock); -} - -static int _write_buffer_text(struct bat_priv *bat_priv, - struct seq_file *seq, struct gw_node *gw_node) -{ - int down, up; - - gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); - - return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", - (bat_priv->curr_gw == gw_node ? "=>" : " "), - gw_node->orig_node->orig, - gw_node->orig_node->router->tq_avg, - gw_node->orig_node->router->addr, - gw_node->orig_node->router->if_incoming->net_dev->name, - gw_node->orig_node->gw_flags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); -} - -int gw_client_seq_print_text(struct seq_file *seq, void *offset) -{ - struct net_device *net_dev = (struct net_device *)seq->private; - struct bat_priv *bat_priv = netdev_priv(net_dev); - struct gw_node *gw_node; - struct hlist_node *node; - int gw_count = 0; - - if (!bat_priv->primary_if) { - - return seq_printf(seq, "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", - net_dev->name); - } - - if (bat_priv->primary_if->if_status != IF_ACTIVE) { - - return seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", - net_dev->name); - } - - seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " - "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", - "Gateway", "#", TQ_MAX_VALUE, "Nexthop", - "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); - - rcu_read_lock(); - hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { - if (gw_node->deleted) - continue; - - if (!gw_node->orig_node->router) - continue; - - _write_buffer_text(bat_priv, seq, gw_node); - gw_count++; - } - rcu_read_unlock(); - - if (gw_count == 0) - seq_printf(seq, "No gateways in range ...\n"); - - return 0; -} - -int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) -{ - struct ethhdr *ethhdr; - struct iphdr *iphdr; - struct ipv6hdr *ipv6hdr; - struct udphdr *udphdr; - unsigned int header_len = 0; - - if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) - return 0; - - /* check for ethernet header */ - if (!pskb_may_pull(skb, header_len + ETH_HLEN)) - return 0; - ethhdr = (struct ethhdr *)skb->data; - header_len += ETH_HLEN; - - /* check for initial vlan header */ - if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { - if (!pskb_may_pull(skb, header_len + VLAN_HLEN)) - return 0; - ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); - header_len += VLAN_HLEN; - } - - /* check for ip header */ - switch (ntohs(ethhdr->h_proto)) { - case ETH_P_IP: - if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) - return 0; - iphdr = (struct iphdr *)(skb->data + header_len); - header_len += iphdr->ihl * 4; - - /* check for udp header */ - if (iphdr->protocol != IPPROTO_UDP) - return 0; - - break; - case ETH_P_IPV6: - if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr))) - return 0; - ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); - header_len += sizeof(struct ipv6hdr); - - /* check for udp header */ - if (ipv6hdr->nexthdr != IPPROTO_UDP) - return 0; - - break; - default: - return 0; - } - - if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) - return 0; - udphdr = (struct udphdr *)(skb->data + header_len); - header_len += sizeof(struct udphdr); - - /* check for bootp port */ - if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && - (ntohs(udphdr->dest) != 67)) - return 0; - - if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && - (ntohs(udphdr->dest) != 547)) - return 0; - - if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) - return -1; - - if (!bat_priv->curr_gw) - return 0; - - return 1; -} diff --git a/drivers/staging/batman-adv/gateway_client.h b/drivers/staging/batman-adv/gateway_client.h deleted file mode 100644 index 4585e6549844..000000000000 --- a/drivers/staging/batman-adv/gateway_client.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ -#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ - -void gw_deselect(struct bat_priv *bat_priv); -void gw_election(struct bat_priv *bat_priv); -void *gw_get_selected(struct bat_priv *bat_priv); -void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); -void gw_node_update(struct bat_priv *bat_priv, - struct orig_node *orig_node, uint8_t new_gwflags); -void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); -void gw_node_purge(struct bat_priv *bat_priv); -int gw_client_seq_print_text(struct seq_file *seq, void *offset); -int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); - -#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/drivers/staging/batman-adv/gateway_common.c b/drivers/staging/batman-adv/gateway_common.c deleted file mode 100644 index b962982f017e..000000000000 --- a/drivers/staging/batman-adv/gateway_common.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "gateway_common.h" -#include "gateway_client.h" - -/* calculates the gateway class from kbit */ -static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) -{ - int mdown = 0, tdown, tup, difference; - uint8_t sbit, part; - - *gw_srv_class = 0; - difference = 0x0FFFFFFF; - - /* test all downspeeds */ - for (sbit = 0; sbit < 2; sbit++) { - for (part = 0; part < 16; part++) { - tdown = 32 * (sbit + 2) * (1 << part); - - if (abs(tdown - down) < difference) { - *gw_srv_class = (sbit << 7) + (part << 3); - difference = abs(tdown - down); - mdown = tdown; - } - } - } - - /* test all upspeeds */ - difference = 0x0FFFFFFF; - - for (part = 0; part < 8; part++) { - tup = ((part + 1) * (mdown)) / 8; - - if (abs(tup - up) < difference) { - *gw_srv_class = (*gw_srv_class & 0xF8) | part; - difference = abs(tup - up); - } - } -} - -/* returns the up and downspeeds in kbit, calculated from the class */ -void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) -{ - char sbit = (gw_srv_class & 0x80) >> 7; - char dpart = (gw_srv_class & 0x78) >> 3; - char upart = (gw_srv_class & 0x07); - - if (!gw_srv_class) { - *down = 0; - *up = 0; - return; - } - - *down = 32 * (sbit + 2) * (1 << dpart); - *up = ((upart + 1) * (*down)) / 8; -} - -static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, - long *up, long *down) -{ - int ret, multi = 1; - char *slash_ptr, *tmp_ptr; - - slash_ptr = strchr(buff, '/'); - if (slash_ptr) - *slash_ptr = 0; - - if (strlen(buff) > 4) { - tmp_ptr = buff + strlen(buff) - 4; - - if (strnicmp(tmp_ptr, "mbit", 4) == 0) - multi = 1024; - - if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || - (multi > 1)) - *tmp_ptr = '\0'; - } - - ret = strict_strtoul(buff, 10, down); - if (ret) { - bat_err(net_dev, - "Download speed of gateway mode invalid: %s\n", - buff); - return false; - } - - *down *= multi; - - /* we also got some upload info */ - if (slash_ptr) { - multi = 1; - - if (strlen(slash_ptr + 1) > 4) { - tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); - - if (strnicmp(tmp_ptr, "mbit", 4) == 0) - multi = 1024; - - if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || - (multi > 1)) - *tmp_ptr = '\0'; - } - - ret = strict_strtoul(slash_ptr + 1, 10, up); - if (ret) { - bat_err(net_dev, - "Upload speed of gateway mode invalid: " - "%s\n", slash_ptr + 1); - return false; - } - - *up *= multi; - } - - return true; -} - -ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) -{ - struct bat_priv *bat_priv = netdev_priv(net_dev); - long gw_bandwidth_tmp = 0, up = 0, down = 0; - bool ret; - - ret = parse_gw_bandwidth(net_dev, buff, &up, &down); - if (!ret) - goto end; - - if ((!down) || (down < 256)) - down = 2000; - - if (!up) - up = down / 5; - - kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); - - /** - * the gw bandwidth we guessed above might not match the given - * speeds, hence we need to calculate it back to show the number - * that is going to be propagated - **/ - gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, - (int *)&down, (int *)&up); - - gw_deselect(bat_priv); - bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " - "(propagating: %ld%s/%ld%s)\n", - atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); - - atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); - -end: - return count; -} diff --git a/drivers/staging/batman-adv/gateway_common.h b/drivers/staging/batman-adv/gateway_common.h deleted file mode 100644 index 5e728d0b7959..000000000000 --- a/drivers/staging/batman-adv/gateway_common.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_ -#define _NET_BATMAN_ADV_GATEWAY_COMMON_H_ - -enum gw_modes { - GW_MODE_OFF, - GW_MODE_CLIENT, - GW_MODE_SERVER, -}; - -#define GW_MODE_OFF_NAME "off" -#define GW_MODE_CLIENT_NAME "client" -#define GW_MODE_SERVER_NAME "server" - -void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); -ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count); - -#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c deleted file mode 100644 index c3c7b7ac0946..000000000000 --- a/drivers/staging/batman-adv/hard-interface.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "hard-interface.h" -#include "soft-interface.h" -#include "send.h" -#include "translation-table.h" -#include "routing.h" -#include "bat_sysfs.h" -#include "originator.h" -#include "hash.h" - -#include - -/* protect update critical side of if_list - but not the content */ -static DEFINE_SPINLOCK(if_list_lock); - -static void hardif_free_rcu(struct rcu_head *rcu) -{ - struct batman_if *batman_if; - - batman_if = container_of(rcu, struct batman_if, rcu); - dev_put(batman_if->net_dev); - kref_put(&batman_if->refcount, hardif_free_ref); -} - -struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev) -{ - struct batman_if *batman_if; - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->net_dev == net_dev) - goto out; - } - - batman_if = NULL; - -out: - if (batman_if) - kref_get(&batman_if->refcount); - - rcu_read_unlock(); - return batman_if; -} - -static int is_valid_iface(struct net_device *net_dev) -{ - if (net_dev->flags & IFF_LOOPBACK) - return 0; - - if (net_dev->type != ARPHRD_ETHER) - return 0; - - if (net_dev->addr_len != ETH_ALEN) - return 0; - - /* no batman over batman */ -#ifdef HAVE_NET_DEVICE_OPS - if (net_dev->netdev_ops->ndo_start_xmit == interface_tx) - return 0; -#else - if (net_dev->hard_start_xmit == interface_tx) - return 0; -#endif - - /* Device is being bridged */ - /* if (net_dev->priv_flags & IFF_BRIDGE_PORT) - return 0; */ - - return 1; -} - -static struct batman_if *get_active_batman_if(struct net_device *soft_iface) -{ - struct batman_if *batman_if; - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->soft_iface != soft_iface) - continue; - - if (batman_if->if_status == IF_ACTIVE) - goto out; - } - - batman_if = NULL; - -out: - if (batman_if) - kref_get(&batman_if->refcount); - - rcu_read_unlock(); - return batman_if; -} - -static void update_primary_addr(struct bat_priv *bat_priv) -{ - struct vis_packet *vis_packet; - - vis_packet = (struct vis_packet *) - bat_priv->my_vis_info->skb_packet->data; - memcpy(vis_packet->vis_orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - memcpy(vis_packet->sender_orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); -} - -static void set_primary_if(struct bat_priv *bat_priv, - struct batman_if *batman_if) -{ - struct batman_packet *batman_packet; - struct batman_if *old_if; - - if (batman_if) - kref_get(&batman_if->refcount); - - old_if = bat_priv->primary_if; - bat_priv->primary_if = batman_if; - - if (old_if) - kref_put(&old_if->refcount, hardif_free_ref); - - if (!bat_priv->primary_if) - return; - - batman_packet = (struct batman_packet *)(batman_if->packet_buff); - batman_packet->flags = PRIMARIES_FIRST_HOP; - batman_packet->ttl = TTL; - - update_primary_addr(bat_priv); - - /*** - * hacky trick to make sure that we send the HNA information via - * our new primary interface - */ - atomic_set(&bat_priv->hna_local_changed, 1); -} - -static bool hardif_is_iface_up(struct batman_if *batman_if) -{ - if (batman_if->net_dev->flags & IFF_UP) - return true; - - return false; -} - -static void update_mac_addresses(struct batman_if *batman_if) -{ - memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, - batman_if->net_dev->dev_addr, ETH_ALEN); - memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender, - batman_if->net_dev->dev_addr, ETH_ALEN); -} - -static void check_known_mac_addr(struct net_device *net_dev) -{ - struct batman_if *batman_if; - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if ((batman_if->if_status != IF_ACTIVE) && - (batman_if->if_status != IF_TO_BE_ACTIVATED)) - continue; - - if (batman_if->net_dev == net_dev) - continue; - - if (!compare_orig(batman_if->net_dev->dev_addr, - net_dev->dev_addr)) - continue; - - pr_warning("The newly added mac address (%pM) already exists " - "on: %s\n", net_dev->dev_addr, - batman_if->net_dev->name); - pr_warning("It is strongly recommended to keep mac addresses " - "unique to avoid problems!\n"); - } - rcu_read_unlock(); -} - -int hardif_min_mtu(struct net_device *soft_iface) -{ - struct bat_priv *bat_priv = netdev_priv(soft_iface); - struct batman_if *batman_if; - /* allow big frames if all devices are capable to do so - * (have MTU > 1500 + BAT_HEADER_LEN) */ - int min_mtu = ETH_DATA_LEN; - - if (atomic_read(&bat_priv->fragmentation)) - goto out; - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if ((batman_if->if_status != IF_ACTIVE) && - (batman_if->if_status != IF_TO_BE_ACTIVATED)) - continue; - - if (batman_if->soft_iface != soft_iface) - continue; - - min_mtu = min_t(int, batman_if->net_dev->mtu - BAT_HEADER_LEN, - min_mtu); - } - rcu_read_unlock(); -out: - return min_mtu; -} - -/* adjusts the MTU if a new interface with a smaller MTU appeared. */ -void update_min_mtu(struct net_device *soft_iface) -{ - int min_mtu; - - min_mtu = hardif_min_mtu(soft_iface); - if (soft_iface->mtu != min_mtu) - soft_iface->mtu = min_mtu; -} - -static void hardif_activate_interface(struct batman_if *batman_if) -{ - struct bat_priv *bat_priv; - - if (batman_if->if_status != IF_INACTIVE) - return; - - bat_priv = netdev_priv(batman_if->soft_iface); - - update_mac_addresses(batman_if); - batman_if->if_status = IF_TO_BE_ACTIVATED; - - /** - * the first active interface becomes our primary interface or - * the next active interface after the old primay interface was removed - */ - if (!bat_priv->primary_if) - set_primary_if(bat_priv, batman_if); - - bat_info(batman_if->soft_iface, "Interface activated: %s\n", - batman_if->net_dev->name); - - update_min_mtu(batman_if->soft_iface); - return; -} - -static void hardif_deactivate_interface(struct batman_if *batman_if) -{ - if ((batman_if->if_status != IF_ACTIVE) && - (batman_if->if_status != IF_TO_BE_ACTIVATED)) - return; - - batman_if->if_status = IF_INACTIVE; - - bat_info(batman_if->soft_iface, "Interface deactivated: %s\n", - batman_if->net_dev->name); - - update_min_mtu(batman_if->soft_iface); -} - -int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) -{ - struct bat_priv *bat_priv; - struct batman_packet *batman_packet; - - if (batman_if->if_status != IF_NOT_IN_USE) - goto out; - - batman_if->soft_iface = dev_get_by_name(&init_net, iface_name); - - if (!batman_if->soft_iface) { - batman_if->soft_iface = softif_create(iface_name); - - if (!batman_if->soft_iface) - goto err; - - /* dev_get_by_name() increases the reference counter for us */ - dev_hold(batman_if->soft_iface); - } - - bat_priv = netdev_priv(batman_if->soft_iface); - batman_if->packet_len = BAT_PACKET_LEN; - batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC); - - if (!batman_if->packet_buff) { - bat_err(batman_if->soft_iface, "Can't add interface packet " - "(%s): out of memory\n", batman_if->net_dev->name); - goto err; - } - - batman_packet = (struct batman_packet *)(batman_if->packet_buff); - batman_packet->packet_type = BAT_PACKET; - batman_packet->version = COMPAT_VERSION; - batman_packet->flags = 0; - batman_packet->ttl = 2; - batman_packet->tq = TQ_MAX_VALUE; - batman_packet->num_hna = 0; - - batman_if->if_num = bat_priv->num_ifaces; - bat_priv->num_ifaces++; - batman_if->if_status = IF_INACTIVE; - orig_hash_add_if(batman_if, bat_priv->num_ifaces); - - batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN); - batman_if->batman_adv_ptype.func = batman_skb_recv; - batman_if->batman_adv_ptype.dev = batman_if->net_dev; - kref_get(&batman_if->refcount); - dev_add_pack(&batman_if->batman_adv_ptype); - - atomic_set(&batman_if->seqno, 1); - atomic_set(&batman_if->frag_seqno, 1); - bat_info(batman_if->soft_iface, "Adding interface: %s\n", - batman_if->net_dev->name); - - if (atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < - ETH_DATA_LEN + BAT_HEADER_LEN) - bat_info(batman_if->soft_iface, - "The MTU of interface %s is too small (%i) to handle " - "the transport of batman-adv packets. Packets going " - "over this interface will be fragmented on layer2 " - "which could impact the performance. Setting the MTU " - "to %zi would solve the problem.\n", - batman_if->net_dev->name, batman_if->net_dev->mtu, - ETH_DATA_LEN + BAT_HEADER_LEN); - - if (!atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < - ETH_DATA_LEN + BAT_HEADER_LEN) - bat_info(batman_if->soft_iface, - "The MTU of interface %s is too small (%i) to handle " - "the transport of batman-adv packets. If you experience" - " problems getting traffic through try increasing the " - "MTU to %zi.\n", - batman_if->net_dev->name, batman_if->net_dev->mtu, - ETH_DATA_LEN + BAT_HEADER_LEN); - - if (hardif_is_iface_up(batman_if)) - hardif_activate_interface(batman_if); - else - bat_err(batman_if->soft_iface, "Not using interface %s " - "(retrying later): interface not active\n", - batman_if->net_dev->name); - - /* begin scheduling originator messages on that interface */ - schedule_own_packet(batman_if); - -out: - return 0; - -err: - return -ENOMEM; -} - -void hardif_disable_interface(struct batman_if *batman_if) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - - if (batman_if->if_status == IF_ACTIVE) - hardif_deactivate_interface(batman_if); - - if (batman_if->if_status != IF_INACTIVE) - return; - - bat_info(batman_if->soft_iface, "Removing interface: %s\n", - batman_if->net_dev->name); - dev_remove_pack(&batman_if->batman_adv_ptype); - kref_put(&batman_if->refcount, hardif_free_ref); - - bat_priv->num_ifaces--; - orig_hash_del_if(batman_if, bat_priv->num_ifaces); - - if (batman_if == bat_priv->primary_if) { - struct batman_if *new_if; - - new_if = get_active_batman_if(batman_if->soft_iface); - set_primary_if(bat_priv, new_if); - - if (new_if) - kref_put(&new_if->refcount, hardif_free_ref); - } - - kfree(batman_if->packet_buff); - batman_if->packet_buff = NULL; - batman_if->if_status = IF_NOT_IN_USE; - - /* delete all references to this batman_if */ - purge_orig_ref(bat_priv); - purge_outstanding_packets(bat_priv, batman_if); - dev_put(batman_if->soft_iface); - - /* nobody uses this interface anymore */ - if (!bat_priv->num_ifaces) - softif_destroy(batman_if->soft_iface); - - batman_if->soft_iface = NULL; -} - -static struct batman_if *hardif_add_interface(struct net_device *net_dev) -{ - struct batman_if *batman_if; - int ret; - - ret = is_valid_iface(net_dev); - if (ret != 1) - goto out; - - dev_hold(net_dev); - - batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC); - if (!batman_if) { - pr_err("Can't add interface (%s): out of memory\n", - net_dev->name); - goto release_dev; - } - - ret = sysfs_add_hardif(&batman_if->hardif_obj, net_dev); - if (ret) - goto free_if; - - batman_if->if_num = -1; - batman_if->net_dev = net_dev; - batman_if->soft_iface = NULL; - batman_if->if_status = IF_NOT_IN_USE; - INIT_LIST_HEAD(&batman_if->list); - kref_init(&batman_if->refcount); - - check_known_mac_addr(batman_if->net_dev); - - spin_lock(&if_list_lock); - list_add_tail_rcu(&batman_if->list, &if_list); - spin_unlock(&if_list_lock); - - /* extra reference for return */ - kref_get(&batman_if->refcount); - return batman_if; - -free_if: - kfree(batman_if); -release_dev: - dev_put(net_dev); -out: - return NULL; -} - -static void hardif_remove_interface(struct batman_if *batman_if) -{ - /* first deactivate interface */ - if (batman_if->if_status != IF_NOT_IN_USE) - hardif_disable_interface(batman_if); - - if (batman_if->if_status != IF_NOT_IN_USE) - return; - - batman_if->if_status = IF_TO_BE_REMOVED; - synchronize_rcu(); - sysfs_del_hardif(&batman_if->hardif_obj); - call_rcu(&batman_if->rcu, hardif_free_rcu); -} - -void hardif_remove_interfaces(void) -{ - struct batman_if *batman_if, *batman_if_tmp; - struct list_head if_queue; - - INIT_LIST_HEAD(&if_queue); - - spin_lock(&if_list_lock); - list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { - list_del_rcu(&batman_if->list); - list_add_tail(&batman_if->list, &if_queue); - } - spin_unlock(&if_list_lock); - - rtnl_lock(); - list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) { - hardif_remove_interface(batman_if); - } - rtnl_unlock(); -} - -static int hard_if_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct net_device *net_dev = (struct net_device *)ptr; - struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); - struct bat_priv *bat_priv; - - if (!batman_if && event == NETDEV_REGISTER) - batman_if = hardif_add_interface(net_dev); - - if (!batman_if) - goto out; - - switch (event) { - case NETDEV_UP: - hardif_activate_interface(batman_if); - break; - case NETDEV_GOING_DOWN: - case NETDEV_DOWN: - hardif_deactivate_interface(batman_if); - break; - case NETDEV_UNREGISTER: - spin_lock(&if_list_lock); - list_del_rcu(&batman_if->list); - spin_unlock(&if_list_lock); - - hardif_remove_interface(batman_if); - break; - case NETDEV_CHANGEMTU: - if (batman_if->soft_iface) - update_min_mtu(batman_if->soft_iface); - break; - case NETDEV_CHANGEADDR: - if (batman_if->if_status == IF_NOT_IN_USE) - goto hardif_put; - - check_known_mac_addr(batman_if->net_dev); - update_mac_addresses(batman_if); - - bat_priv = netdev_priv(batman_if->soft_iface); - if (batman_if == bat_priv->primary_if) - update_primary_addr(bat_priv); - break; - default: - break; - }; - -hardif_put: - kref_put(&batman_if->refcount, hardif_free_ref); -out: - return NOTIFY_DONE; -} - -/* receive a packet with the batman ethertype coming on a hard - * interface */ -int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *orig_dev) -{ - struct bat_priv *bat_priv; - struct batman_packet *batman_packet; - struct batman_if *batman_if; - int ret; - - batman_if = container_of(ptype, struct batman_if, batman_adv_ptype); - skb = skb_share_check(skb, GFP_ATOMIC); - - /* skb was released by skb_share_check() */ - if (!skb) - goto err_out; - - /* packet should hold at least type and version */ - if (unlikely(!pskb_may_pull(skb, 2))) - goto err_free; - - /* expect a valid ethernet header here. */ - if (unlikely(skb->mac_len != sizeof(struct ethhdr) - || !skb_mac_header(skb))) - goto err_free; - - if (!batman_if->soft_iface) - goto err_free; - - bat_priv = netdev_priv(batman_if->soft_iface); - - if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) - goto err_free; - - /* discard frames on not active interfaces */ - if (batman_if->if_status != IF_ACTIVE) - goto err_free; - - batman_packet = (struct batman_packet *)skb->data; - - if (batman_packet->version != COMPAT_VERSION) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: incompatible batman version (%i)\n", - batman_packet->version); - goto err_free; - } - - /* all receive handlers return whether they received or reused - * the supplied skb. if not, we have to free the skb. */ - - switch (batman_packet->packet_type) { - /* batman originator packet */ - case BAT_PACKET: - ret = recv_bat_packet(skb, batman_if); - break; - - /* batman icmp packet */ - case BAT_ICMP: - ret = recv_icmp_packet(skb, batman_if); - break; - - /* unicast packet */ - case BAT_UNICAST: - ret = recv_unicast_packet(skb, batman_if); - break; - - /* fragmented unicast packet */ - case BAT_UNICAST_FRAG: - ret = recv_ucast_frag_packet(skb, batman_if); - break; - - /* broadcast packet */ - case BAT_BCAST: - ret = recv_bcast_packet(skb, batman_if); - break; - - /* vis packet */ - case BAT_VIS: - ret = recv_vis_packet(skb, batman_if); - break; - default: - ret = NET_RX_DROP; - } - - if (ret == NET_RX_DROP) - kfree_skb(skb); - - /* return NET_RX_SUCCESS in any case as we - * most probably dropped the packet for - * routing-logical reasons. */ - - return NET_RX_SUCCESS; - -err_free: - kfree_skb(skb); -err_out: - return NET_RX_DROP; -} - -struct notifier_block hard_if_notifier = { - .notifier_call = hard_if_event, -}; diff --git a/drivers/staging/batman-adv/hard-interface.h b/drivers/staging/batman-adv/hard-interface.h deleted file mode 100644 index 30ec3b8db459..000000000000 --- a/drivers/staging/batman-adv/hard-interface.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_ -#define _NET_BATMAN_ADV_HARD_INTERFACE_H_ - -#define IF_NOT_IN_USE 0 -#define IF_TO_BE_REMOVED 1 -#define IF_INACTIVE 2 -#define IF_ACTIVE 3 -#define IF_TO_BE_ACTIVATED 4 -#define IF_I_WANT_YOU 5 - -extern struct notifier_block hard_if_notifier; - -struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev); -int hardif_enable_interface(struct batman_if *batman_if, char *iface_name); -void hardif_disable_interface(struct batman_if *batman_if); -void hardif_remove_interfaces(void); -int batman_skb_recv(struct sk_buff *skb, - struct net_device *dev, - struct packet_type *ptype, - struct net_device *orig_dev); -int hardif_min_mtu(struct net_device *soft_iface); -void update_min_mtu(struct net_device *soft_iface); - -static inline void hardif_free_ref(struct kref *refcount) -{ - struct batman_if *batman_if; - - batman_if = container_of(refcount, struct batman_if, refcount); - kfree(batman_if); -} - -#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --git a/drivers/staging/batman-adv/hash.c b/drivers/staging/batman-adv/hash.c deleted file mode 100644 index 8605e2fd0427..000000000000 --- a/drivers/staging/batman-adv/hash.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: - * - * Simon Wunderlich, Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "hash.h" - -/* clears the hash */ -static void hash_init(struct hashtable_t *hash) -{ - int i; - - hash->elements = 0; - - for (i = 0 ; i < hash->size; i++) - INIT_HLIST_HEAD(&hash->table[i]); -} - -/* free only the hashtable and the hash itself. */ -void hash_destroy(struct hashtable_t *hash) -{ - kfree(hash->table); - kfree(hash); -} - -/* allocates and clears the hash */ -struct hashtable_t *hash_new(int size) -{ - struct hashtable_t *hash; - - hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC); - - if (hash == NULL) - return NULL; - - hash->size = size; - hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC); - - if (hash->table == NULL) { - kfree(hash); - return NULL; - } - - hash_init(hash); - - return hash; -} - -/* remove bucket (this might be used in hash_iterate() if you already found the - * bucket you want to delete and don't need the overhead to find it again with - * hash_remove(). But usually, you don't want to use this function, as it - * fiddles with hash-internals. */ -void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t) -{ - void *data_save; - struct element_t *bucket; - - bucket = hlist_entry(hash_it_t->walk, struct element_t, hlist); - data_save = bucket->data; - - hlist_del(hash_it_t->walk); - kfree(bucket); - hash->elements--; - - return data_save; -} diff --git a/drivers/staging/batman-adv/hash.h b/drivers/staging/batman-adv/hash.h deleted file mode 100644 index 0b61c6e3e7cf..000000000000 --- a/drivers/staging/batman-adv/hash.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: - * - * Simon Wunderlich, Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_HASH_H_ -#define _NET_BATMAN_ADV_HASH_H_ - -#include - -#define HASHIT(name) struct hash_it_t name = { \ - .index = 0, .walk = NULL, \ - .safe = NULL} - -/* callback to a compare function. should - * compare 2 element datas for their keys, - * return 0 if same and not 0 if not - * same */ -typedef int (*hashdata_compare_cb)(void *, void *); - -/* the hashfunction, should return an index - * based on the key in the data of the first - * argument and the size the second */ -typedef int (*hashdata_choose_cb)(void *, int); -typedef void (*hashdata_free_cb)(void *, void *); - -struct element_t { - void *data; /* pointer to the data */ - struct hlist_node hlist; /* bucket list pointer */ -}; - -struct hash_it_t { - size_t index; - struct hlist_node *walk; - struct hlist_node *safe; -}; - -struct hashtable_t { - struct hlist_head *table; /* the hashtable itself, with the buckets */ - int elements; /* number of elements registered */ - int size; /* size of hashtable */ -}; - -/* allocates and clears the hash */ -struct hashtable_t *hash_new(int size); - -/* remove bucket (this might be used in hash_iterate() if you already found the - * bucket you want to delete and don't need the overhead to find it again with - * hash_remove(). But usually, you don't want to use this function, as it - * fiddles with hash-internals. */ -void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t); - -/* free only the hashtable and the hash itself. */ -void hash_destroy(struct hashtable_t *hash); - -/* remove the hash structure. if hashdata_free_cb != NULL, this function will be - * called to remove the elements inside of the hash. if you don't remove the - * elements, memory might be leaked. */ -static inline void hash_delete(struct hashtable_t *hash, - hashdata_free_cb free_cb, void *arg) -{ - struct hlist_head *head; - struct hlist_node *walk, *safe; - struct element_t *bucket; - int i; - - for (i = 0; i < hash->size; i++) { - head = &hash->table[i]; - - hlist_for_each_safe(walk, safe, head) { - bucket = hlist_entry(walk, struct element_t, hlist); - if (free_cb != NULL) - free_cb(bucket->data, arg); - - hlist_del(walk); - kfree(bucket); - } - } - - hash_destroy(hash); -} - -/* adds data to the hashtable. returns 0 on success, -1 on error */ -static inline int hash_add(struct hashtable_t *hash, - hashdata_compare_cb compare, - hashdata_choose_cb choose, void *data) -{ - int index; - struct hlist_head *head; - struct hlist_node *walk, *safe; - struct element_t *bucket; - - if (!hash) - return -1; - - index = choose(data, hash->size); - head = &hash->table[index]; - - hlist_for_each_safe(walk, safe, head) { - bucket = hlist_entry(walk, struct element_t, hlist); - if (compare(bucket->data, data)) - return -1; - } - - /* no duplicate found in list, add new element */ - bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); - - if (bucket == NULL) - return -1; - - bucket->data = data; - hlist_add_head(&bucket->hlist, head); - - hash->elements++; - return 0; -} - -/* removes data from hash, if found. returns pointer do data on success, so you - * can remove the used structure yourself, or NULL on error . data could be the - * structure you use with just the key filled, we just need the key for - * comparing. */ -static inline void *hash_remove(struct hashtable_t *hash, - hashdata_compare_cb compare, - hashdata_choose_cb choose, void *data) -{ - struct hash_it_t hash_it_t; - struct element_t *bucket; - struct hlist_head *head; - - hash_it_t.index = choose(data, hash->size); - head = &hash->table[hash_it_t.index]; - - hlist_for_each(hash_it_t.walk, head) { - bucket = hlist_entry(hash_it_t.walk, struct element_t, hlist); - if (compare(bucket->data, data)) - return hash_remove_bucket(hash, &hash_it_t); - } - - return NULL; -} - -/* finds data, based on the key in keydata. returns the found data on success, - * or NULL on error */ -static inline void *hash_find(struct hashtable_t *hash, - hashdata_compare_cb compare, - hashdata_choose_cb choose, void *keydata) -{ - int index; - struct hlist_head *head; - struct hlist_node *walk; - struct element_t *bucket; - - if (!hash) - return NULL; - - index = choose(keydata , hash->size); - head = &hash->table[index]; - - hlist_for_each(walk, head) { - bucket = hlist_entry(walk, struct element_t, hlist); - if (compare(bucket->data, keydata)) - return bucket->data; - } - - return NULL; -} - -/* resize the hash, returns the pointer to the new hash or NULL on - * error. removes the old hash on success */ -static inline struct hashtable_t *hash_resize(struct hashtable_t *hash, - hashdata_choose_cb choose, - int size) -{ - struct hashtable_t *new_hash; - struct hlist_head *head, *new_head; - struct hlist_node *walk, *safe; - struct element_t *bucket; - int i, new_index; - - /* initialize a new hash with the new size */ - new_hash = hash_new(size); - - if (new_hash == NULL) - return NULL; - - /* copy the elements */ - for (i = 0; i < hash->size; i++) { - head = &hash->table[i]; - - hlist_for_each_safe(walk, safe, head) { - bucket = hlist_entry(walk, struct element_t, hlist); - - new_index = choose(bucket->data, size); - new_head = &new_hash->table[new_index]; - - hlist_del(walk); - hlist_add_head(walk, new_head); - } - } - - hash_destroy(hash); - - return new_hash; -} - -/* iterate though the hash. First element is selected if an iterator - * initialized with HASHIT() is supplied as iter. Use the returned - * (or supplied) iterator to access the elements until hash_iterate returns - * NULL. */ -static inline struct hash_it_t *hash_iterate(struct hashtable_t *hash, - struct hash_it_t *iter) -{ - if (!hash) - return NULL; - if (!iter) - return NULL; - - iter->walk = iter->safe; - - /* we search for the next head with list entries */ - if (!iter->walk) { - while (iter->index < hash->size) { - if (hlist_empty(&hash->table[iter->index])) - iter->index++; - else { - iter->walk = hash->table[iter->index].first; - - /* search next time */ - ++iter->index; - break; - } - } - } - - /* return iter when we found bucket otherwise null */ - if (!iter->walk) - return NULL; - - iter->safe = iter->walk->next; - return iter; -} - -#endif /* _NET_BATMAN_ADV_HASH_H_ */ diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c deleted file mode 100644 index a933ca609b74..000000000000 --- a/drivers/staging/batman-adv/icmp_socket.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include -#include -#include "icmp_socket.h" -#include "send.h" -#include "types.h" -#include "hash.h" -#include "originator.h" -#include "hard-interface.h" - - -static struct socket_client *socket_client_hash[256]; - -static void bat_socket_add_packet(struct socket_client *socket_client, - struct icmp_packet_rr *icmp_packet, - size_t icmp_len); - -void bat_socket_init(void) -{ - memset(socket_client_hash, 0, sizeof(socket_client_hash)); -} - -static int bat_socket_open(struct inode *inode, struct file *file) -{ - unsigned int i; - struct socket_client *socket_client; - - nonseekable_open(inode, file); - - socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL); - - if (!socket_client) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) { - if (!socket_client_hash[i]) { - socket_client_hash[i] = socket_client; - break; - } - } - - if (i == ARRAY_SIZE(socket_client_hash)) { - pr_err("Error - can't add another packet client: " - "maximum number of clients reached\n"); - kfree(socket_client); - return -EXFULL; - } - - INIT_LIST_HEAD(&socket_client->queue_list); - socket_client->queue_len = 0; - socket_client->index = i; - socket_client->bat_priv = inode->i_private; - spin_lock_init(&socket_client->lock); - init_waitqueue_head(&socket_client->queue_wait); - - file->private_data = socket_client; - - inc_module_count(); - return 0; -} - -static int bat_socket_release(struct inode *inode, struct file *file) -{ - struct socket_client *socket_client = file->private_data; - struct socket_packet *socket_packet; - struct list_head *list_pos, *list_pos_tmp; - - spin_lock_bh(&socket_client->lock); - - /* for all packets in the queue ... */ - list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) { - socket_packet = list_entry(list_pos, - struct socket_packet, list); - - list_del(list_pos); - kfree(socket_packet); - } - - socket_client_hash[socket_client->index] = NULL; - spin_unlock_bh(&socket_client->lock); - - kfree(socket_client); - dec_module_count(); - - return 0; -} - -static ssize_t bat_socket_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct socket_client *socket_client = file->private_data; - struct socket_packet *socket_packet; - size_t packet_len; - int error; - - if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0)) - return -EAGAIN; - - if ((!buf) || (count < sizeof(struct icmp_packet))) - return -EINVAL; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - error = wait_event_interruptible(socket_client->queue_wait, - socket_client->queue_len); - - if (error) - return error; - - spin_lock_bh(&socket_client->lock); - - socket_packet = list_first_entry(&socket_client->queue_list, - struct socket_packet, list); - list_del(&socket_packet->list); - socket_client->queue_len--; - - spin_unlock_bh(&socket_client->lock); - - error = __copy_to_user(buf, &socket_packet->icmp_packet, - socket_packet->icmp_len); - - packet_len = socket_packet->icmp_len; - kfree(socket_packet); - - if (error) - return -EFAULT; - - return packet_len; -} - -static ssize_t bat_socket_write(struct file *file, const char __user *buff, - size_t len, loff_t *off) -{ - struct socket_client *socket_client = file->private_data; - struct bat_priv *bat_priv = socket_client->bat_priv; - struct sk_buff *skb; - struct icmp_packet_rr *icmp_packet; - - struct orig_node *orig_node; - struct batman_if *batman_if; - size_t packet_len = sizeof(struct icmp_packet); - uint8_t dstaddr[ETH_ALEN]; - - if (len < sizeof(struct icmp_packet)) { - bat_dbg(DBG_BATMAN, bat_priv, - "Error - can't send packet from char device: " - "invalid packet size\n"); - return -EINVAL; - } - - if (!bat_priv->primary_if) - return -EFAULT; - - if (len >= sizeof(struct icmp_packet_rr)) - packet_len = sizeof(struct icmp_packet_rr); - - skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); - if (!skb) - return -ENOMEM; - - skb_reserve(skb, sizeof(struct ethhdr)); - icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); - - if (!access_ok(VERIFY_READ, buff, packet_len)) { - len = -EFAULT; - goto free_skb; - } - - if (__copy_from_user(icmp_packet, buff, packet_len)) { - len = -EFAULT; - goto free_skb; - } - - if (icmp_packet->packet_type != BAT_ICMP) { - bat_dbg(DBG_BATMAN, bat_priv, - "Error - can't send packet from char device: " - "got bogus packet type (expected: BAT_ICMP)\n"); - len = -EINVAL; - goto free_skb; - } - - if (icmp_packet->msg_type != ECHO_REQUEST) { - bat_dbg(DBG_BATMAN, bat_priv, - "Error - can't send packet from char device: " - "got bogus message type (expected: ECHO_REQUEST)\n"); - len = -EINVAL; - goto free_skb; - } - - icmp_packet->uid = socket_client->index; - - if (icmp_packet->version != COMPAT_VERSION) { - icmp_packet->msg_type = PARAMETER_PROBLEM; - icmp_packet->ttl = COMPAT_VERSION; - bat_socket_add_packet(socket_client, icmp_packet, packet_len); - goto free_skb; - } - - if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) - goto dst_unreach; - - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - icmp_packet->dst)); - - if (!orig_node) - goto unlock; - - if (!orig_node->router) - goto unlock; - - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - - spin_unlock_bh(&bat_priv->orig_hash_lock); - - if (!batman_if) - goto dst_unreach; - - if (batman_if->if_status != IF_ACTIVE) - goto dst_unreach; - - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - - if (packet_len == sizeof(struct icmp_packet_rr)) - memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN); - - - send_skb_packet(skb, batman_if, dstaddr); - - goto out; - -unlock: - spin_unlock_bh(&bat_priv->orig_hash_lock); -dst_unreach: - icmp_packet->msg_type = DESTINATION_UNREACHABLE; - bat_socket_add_packet(socket_client, icmp_packet, packet_len); -free_skb: - kfree_skb(skb); -out: - return len; -} - -static unsigned int bat_socket_poll(struct file *file, poll_table *wait) -{ - struct socket_client *socket_client = file->private_data; - - poll_wait(file, &socket_client->queue_wait, wait); - - if (socket_client->queue_len > 0) - return POLLIN | POLLRDNORM; - - return 0; -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - .open = bat_socket_open, - .release = bat_socket_release, - .read = bat_socket_read, - .write = bat_socket_write, - .poll = bat_socket_poll, - .llseek = no_llseek, -}; - -int bat_socket_setup(struct bat_priv *bat_priv) -{ - struct dentry *d; - - if (!bat_priv->debug_dir) - goto err; - - d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, - bat_priv->debug_dir, bat_priv, &fops); - if (d) - goto err; - - return 0; - -err: - return 1; -} - -static void bat_socket_add_packet(struct socket_client *socket_client, - struct icmp_packet_rr *icmp_packet, - size_t icmp_len) -{ - struct socket_packet *socket_packet; - - socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC); - - if (!socket_packet) - return; - - INIT_LIST_HEAD(&socket_packet->list); - memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len); - socket_packet->icmp_len = icmp_len; - - spin_lock_bh(&socket_client->lock); - - /* while waiting for the lock the socket_client could have been - * deleted */ - if (!socket_client_hash[icmp_packet->uid]) { - spin_unlock_bh(&socket_client->lock); - kfree(socket_packet); - return; - } - - list_add_tail(&socket_packet->list, &socket_client->queue_list); - socket_client->queue_len++; - - if (socket_client->queue_len > 100) { - socket_packet = list_first_entry(&socket_client->queue_list, - struct socket_packet, list); - - list_del(&socket_packet->list); - kfree(socket_packet); - socket_client->queue_len--; - } - - spin_unlock_bh(&socket_client->lock); - - wake_up(&socket_client->queue_wait); -} - -void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet, - size_t icmp_len) -{ - struct socket_client *hash = socket_client_hash[icmp_packet->uid]; - - if (hash) - bat_socket_add_packet(hash, icmp_packet, icmp_len); -} diff --git a/drivers/staging/batman-adv/icmp_socket.h b/drivers/staging/batman-adv/icmp_socket.h deleted file mode 100644 index bf9b348cde27..000000000000 --- a/drivers/staging/batman-adv/icmp_socket.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_ -#define _NET_BATMAN_ADV_ICMP_SOCKET_H_ - -#include "types.h" - -#define ICMP_SOCKET "socket" - -void bat_socket_init(void); -int bat_socket_setup(struct bat_priv *bat_priv); -void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet, - size_t icmp_len); - -#endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */ diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c deleted file mode 100644 index b827f6a158cb..000000000000 --- a/drivers/staging/batman-adv/main.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "bat_sysfs.h" -#include "bat_debugfs.h" -#include "routing.h" -#include "send.h" -#include "originator.h" -#include "soft-interface.h" -#include "icmp_socket.h" -#include "translation-table.h" -#include "hard-interface.h" -#include "gateway_client.h" -#include "types.h" -#include "vis.h" -#include "hash.h" - -struct list_head if_list; - -unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -struct workqueue_struct *bat_event_workqueue; - -static int __init batman_init(void) -{ - INIT_LIST_HEAD(&if_list); - - /* the name should not be longer than 10 chars - see - * http://lwn.net/Articles/23634/ */ - bat_event_workqueue = create_singlethread_workqueue("bat_events"); - - if (!bat_event_workqueue) - return -ENOMEM; - - bat_socket_init(); - debugfs_init(); - - register_netdevice_notifier(&hard_if_notifier); - - pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) " - "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR, - COMPAT_VERSION); - - return 0; -} - -static void __exit batman_exit(void) -{ - debugfs_destroy(); - unregister_netdevice_notifier(&hard_if_notifier); - hardif_remove_interfaces(); - - flush_workqueue(bat_event_workqueue); - destroy_workqueue(bat_event_workqueue); - bat_event_workqueue = NULL; - - rcu_barrier(); -} - -int mesh_init(struct net_device *soft_iface) -{ - struct bat_priv *bat_priv = netdev_priv(soft_iface); - - spin_lock_init(&bat_priv->orig_hash_lock); - spin_lock_init(&bat_priv->forw_bat_list_lock); - spin_lock_init(&bat_priv->forw_bcast_list_lock); - spin_lock_init(&bat_priv->hna_lhash_lock); - spin_lock_init(&bat_priv->hna_ghash_lock); - spin_lock_init(&bat_priv->gw_list_lock); - spin_lock_init(&bat_priv->vis_hash_lock); - spin_lock_init(&bat_priv->vis_list_lock); - spin_lock_init(&bat_priv->softif_neigh_lock); - - INIT_HLIST_HEAD(&bat_priv->forw_bat_list); - INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); - INIT_HLIST_HEAD(&bat_priv->gw_list); - INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); - - if (originator_init(bat_priv) < 1) - goto err; - - if (hna_local_init(bat_priv) < 1) - goto err; - - if (hna_global_init(bat_priv) < 1) - goto err; - - hna_local_add(soft_iface, soft_iface->dev_addr); - - if (vis_init(bat_priv) < 1) - goto err; - - atomic_set(&bat_priv->mesh_state, MESH_ACTIVE); - goto end; - -err: - pr_err("Unable to allocate memory for mesh information structures: " - "out of mem ?\n"); - mesh_free(soft_iface); - return -1; - -end: - return 0; -} - -void mesh_free(struct net_device *soft_iface) -{ - struct bat_priv *bat_priv = netdev_priv(soft_iface); - - atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING); - - purge_outstanding_packets(bat_priv, NULL); - - vis_quit(bat_priv); - - gw_node_purge(bat_priv); - originator_free(bat_priv); - - hna_local_free(bat_priv); - hna_global_free(bat_priv); - - softif_neigh_purge(bat_priv); - - atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); -} - -void inc_module_count(void) -{ - try_module_get(THIS_MODULE); -} - -void dec_module_count(void) -{ - module_put(THIS_MODULE); -} - -int is_my_mac(uint8_t *addr) -{ - struct batman_if *batman_if; - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->if_status != IF_ACTIVE) - continue; - - if (compare_orig(batman_if->net_dev->dev_addr, addr)) { - rcu_read_unlock(); - return 1; - } - } - rcu_read_unlock(); - return 0; - -} - -module_init(batman_init); -module_exit(batman_exit); - -MODULE_LICENSE("GPL"); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); -#ifdef REVISION_VERSION -MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION); -#else -MODULE_VERSION(SOURCE_VERSION); -#endif diff --git a/drivers/staging/batman-adv/main.h b/drivers/staging/batman-adv/main.h deleted file mode 100644 index 6b60c33a8b77..000000000000 --- a/drivers/staging/batman-adv/main.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_MAIN_H_ -#define _NET_BATMAN_ADV_MAIN_H_ - -/* Kernel Programming */ -#define LINUX - -#define DRIVER_AUTHOR "Marek Lindner , " \ - "Simon Wunderlich " -#define DRIVER_DESC "B.A.T.M.A.N. advanced" -#define DRIVER_DEVICE "batman-adv" - -#define SOURCE_VERSION "next" - - -/* B.A.T.M.A.N. parameters */ - -#define TQ_MAX_VALUE 255 -#define JITTER 20 -#define TTL 50 /* Time To Live of broadcast messages */ - -#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no - * valid packet comes in -> TODO: check - * influence on TQ_LOCAL_WINDOW_SIZE */ -#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */ - -#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator - * messages in squence numbers (should be a - * multiple of our word size) */ -#define TQ_GLOBAL_WINDOW_SIZE 5 -#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 -#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 -#define TQ_TOTAL_BIDRECT_LIMIT 1 - -#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) - -#define PACKBUFF_SIZE 2000 -#define LOG_BUF_LEN 8192 /* has to be a power of 2 */ - -#define VIS_INTERVAL 5000 /* 5 seconds */ - -/* how much worse secondary interfaces may be to - * to be considered as bonding candidates */ - -#define BONDING_TQ_THRESHOLD 50 - -#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or - * change the size of - * forw_packet->direct_link_flags */ -#define MAX_AGGREGATION_MS 100 - -#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ - -#define RESET_PROTECTION_MS 30000 -#define EXPECTED_SEQNO_RANGE 65536 -/* don't reset again within 30 seconds */ - -#define MESH_INACTIVE 0 -#define MESH_ACTIVE 1 -#define MESH_DEACTIVATING 2 - -#define BCAST_QUEUE_LEN 256 -#define BATMAN_QUEUE_LEN 256 - -/* - * Debug Messages - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before - * kernel messages */ - -#define DBG_BATMAN 1 /* all messages related to routing / flooding / - * broadcasting / etc */ -#define DBG_ROUTES 2 /* route or hna added / changed / deleted */ -#define DBG_ALL 3 - -#define LOG_BUF_LEN 8192 /* has to be a power of 2 */ - - -/* - * Vis - */ - -/* #define VIS_SUBCLUSTERS_DISABLED */ - -/* - * Kernel headers - */ - -#include /* mutex */ -#include /* needed by all modules */ -#include /* netdevice */ -#include /* ethernet address classifaction */ -#include /* ethernet header */ -#include /* poll_table */ -#include /* kernel threads */ -#include /* schedule types */ -#include /* workqueue */ -#include -#include /* struct sock */ -#include -#include -#include "types.h" - -#ifndef REVISION_VERSION -#define REVISION_VERSION_STR "" -#else -#define REVISION_VERSION_STR " "REVISION_VERSION -#endif - -extern struct list_head if_list; - -extern unsigned char broadcast_addr[]; -extern struct workqueue_struct *bat_event_workqueue; - -int mesh_init(struct net_device *soft_iface); -void mesh_free(struct net_device *soft_iface); -void inc_module_count(void); -void dec_module_count(void); -int is_my_mac(uint8_t *addr); - -#ifdef CONFIG_BATMAN_ADV_DEBUG -int debug_log(struct bat_priv *bat_priv, char *fmt, ...); - -#define bat_dbg(type, bat_priv, fmt, arg...) \ - do { \ - if (atomic_read(&bat_priv->log_level) & type) \ - debug_log(bat_priv, fmt, ## arg); \ - } \ - while (0) -#else /* !CONFIG_BATMAN_ADV_DEBUG */ -static inline void bat_dbg(char type __attribute__((unused)), - struct bat_priv *bat_priv __attribute__((unused)), - char *fmt __attribute__((unused)), ...) -{ -} -#endif - -#define bat_warning(net_dev, fmt, arg...) \ - do { \ - struct net_device *_netdev = (net_dev); \ - struct bat_priv *_batpriv = netdev_priv(_netdev); \ - bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ - pr_warning("%s: " fmt, _netdev->name, ## arg); \ - } while (0) -#define bat_info(net_dev, fmt, arg...) \ - do { \ - struct net_device *_netdev = (net_dev); \ - struct bat_priv *_batpriv = netdev_priv(_netdev); \ - bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ - pr_info("%s: " fmt, _netdev->name, ## arg); \ - } while (0) -#define bat_err(net_dev, fmt, arg...) \ - do { \ - struct net_device *_netdev = (net_dev); \ - struct bat_priv *_batpriv = netdev_priv(_netdev); \ - bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ - pr_err("%s: " fmt, _netdev->name, ## arg); \ - } while (0) - -#endif /* _NET_BATMAN_ADV_MAIN_H_ */ diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c deleted file mode 100644 index 89ec02100a3b..000000000000 --- a/drivers/staging/batman-adv/originator.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -/* increase the reference counter for this originator */ - -#include "main.h" -#include "originator.h" -#include "hash.h" -#include "translation-table.h" -#include "routing.h" -#include "gateway_client.h" -#include "hard-interface.h" -#include "unicast.h" -#include "soft-interface.h" - -static void purge_orig(struct work_struct *work); - -static void start_purge_timer(struct bat_priv *bat_priv) -{ - INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig); - queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ); -} - -int originator_init(struct bat_priv *bat_priv) -{ - if (bat_priv->orig_hash) - return 1; - - spin_lock_bh(&bat_priv->orig_hash_lock); - bat_priv->orig_hash = hash_new(128); - - if (!bat_priv->orig_hash) - goto err; - - spin_unlock_bh(&bat_priv->orig_hash_lock); - start_purge_timer(bat_priv); - return 1; - -err: - spin_unlock_bh(&bat_priv->orig_hash_lock); - return 0; -} - -struct neigh_node * -create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, - uint8_t *neigh, struct batman_if *if_incoming) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct neigh_node *neigh_node; - - bat_dbg(DBG_BATMAN, bat_priv, - "Creating new last-hop neighbor of originator\n"); - - neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC); - if (!neigh_node) - return NULL; - - INIT_LIST_HEAD(&neigh_node->list); - - memcpy(neigh_node->addr, neigh, ETH_ALEN); - neigh_node->orig_node = orig_neigh_node; - neigh_node->if_incoming = if_incoming; - - list_add_tail(&neigh_node->list, &orig_node->neigh_list); - return neigh_node; -} - -static void free_orig_node(void *data, void *arg) -{ - struct list_head *list_pos, *list_pos_tmp; - struct neigh_node *neigh_node; - struct orig_node *orig_node = (struct orig_node *)data; - struct bat_priv *bat_priv = (struct bat_priv *)arg; - - /* for all neighbors towards this originator ... */ - list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { - neigh_node = list_entry(list_pos, struct neigh_node, list); - - list_del(list_pos); - kfree(neigh_node); - } - - frag_list_free(&orig_node->frag_list); - hna_global_del_orig(bat_priv, orig_node, "originator timed out"); - - kfree(orig_node->bcast_own); - kfree(orig_node->bcast_own_sum); - kfree(orig_node); -} - -void originator_free(struct bat_priv *bat_priv) -{ - if (!bat_priv->orig_hash) - return; - - cancel_delayed_work_sync(&bat_priv->orig_work); - - spin_lock_bh(&bat_priv->orig_hash_lock); - hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv); - bat_priv->orig_hash = NULL; - spin_unlock_bh(&bat_priv->orig_hash_lock); -} - -/* this function finds or creates an originator entry for the given - * address if it does not exits */ -struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) -{ - struct orig_node *orig_node; - struct hashtable_t *swaphash; - int size; - int hash_added; - - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - addr)); - - if (orig_node) - return orig_node; - - bat_dbg(DBG_BATMAN, bat_priv, - "Creating new originator: %pM\n", addr); - - orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC); - if (!orig_node) - return NULL; - - INIT_LIST_HEAD(&orig_node->neigh_list); - - memcpy(orig_node->orig, addr, ETH_ALEN); - orig_node->router = NULL; - orig_node->hna_buff = NULL; - orig_node->bcast_seqno_reset = jiffies - 1 - - msecs_to_jiffies(RESET_PROTECTION_MS); - orig_node->batman_seqno_reset = jiffies - 1 - - msecs_to_jiffies(RESET_PROTECTION_MS); - - size = bat_priv->num_ifaces * sizeof(TYPE_OF_WORD) * NUM_WORDS; - - orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); - if (!orig_node->bcast_own) - goto free_orig_node; - - size = bat_priv->num_ifaces * sizeof(uint8_t); - orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); - - INIT_LIST_HEAD(&orig_node->frag_list); - orig_node->last_frag_packet = 0; - - if (!orig_node->bcast_own_sum) - goto free_bcast_own; - - hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig, - orig_node); - if (hash_added < 0) - goto free_bcast_own_sum; - - if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) { - swaphash = hash_resize(bat_priv->orig_hash, choose_orig, - bat_priv->orig_hash->size * 2); - - if (!swaphash) - bat_dbg(DBG_BATMAN, bat_priv, - "Couldn't resize orig hash table\n"); - else - bat_priv->orig_hash = swaphash; - } - - return orig_node; -free_bcast_own_sum: - kfree(orig_node->bcast_own_sum); -free_bcast_own: - kfree(orig_node->bcast_own); -free_orig_node: - kfree(orig_node); - return NULL; -} - -static bool purge_orig_neighbors(struct bat_priv *bat_priv, - struct orig_node *orig_node, - struct neigh_node **best_neigh_node) -{ - struct list_head *list_pos, *list_pos_tmp; - struct neigh_node *neigh_node; - bool neigh_purged = false; - - *best_neigh_node = NULL; - - /* for all neighbors towards this originator ... */ - list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { - neigh_node = list_entry(list_pos, struct neigh_node, list); - - if ((time_after(jiffies, - neigh_node->last_valid + PURGE_TIMEOUT * HZ)) || - (neigh_node->if_incoming->if_status == IF_INACTIVE) || - (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) { - - if (neigh_node->if_incoming->if_status == - IF_TO_BE_REMOVED) - bat_dbg(DBG_BATMAN, bat_priv, - "neighbor purge: originator %pM, " - "neighbor: %pM, iface: %s\n", - orig_node->orig, neigh_node->addr, - neigh_node->if_incoming->net_dev->name); - else - bat_dbg(DBG_BATMAN, bat_priv, - "neighbor timeout: originator %pM, " - "neighbor: %pM, last_valid: %lu\n", - orig_node->orig, neigh_node->addr, - (neigh_node->last_valid / HZ)); - - neigh_purged = true; - list_del(list_pos); - kfree(neigh_node); - } else { - if ((*best_neigh_node == NULL) || - (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) - *best_neigh_node = neigh_node; - } - } - return neigh_purged; -} - -static bool purge_orig_node(struct bat_priv *bat_priv, - struct orig_node *orig_node) -{ - struct neigh_node *best_neigh_node; - - if (time_after(jiffies, - orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) { - - bat_dbg(DBG_BATMAN, bat_priv, - "Originator timeout: originator %pM, last_valid %lu\n", - orig_node->orig, (orig_node->last_valid / HZ)); - return true; - } else { - if (purge_orig_neighbors(bat_priv, orig_node, - &best_neigh_node)) { - update_routes(bat_priv, orig_node, - best_neigh_node, - orig_node->hna_buff, - orig_node->hna_buff_len); - /* update bonding candidates, we could have lost - * some candidates. */ - update_bonding_candidates(bat_priv, orig_node); - } - } - - return false; -} - -static void _purge_orig(struct bat_priv *bat_priv) -{ - HASHIT(hashit); - struct element_t *bucket; - struct orig_node *orig_node; - - spin_lock_bh(&bat_priv->orig_hash_lock); - - /* for all origins... */ - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - - if (purge_orig_node(bat_priv, orig_node)) { - if (orig_node->gw_flags) - gw_node_delete(bat_priv, orig_node); - hash_remove_bucket(bat_priv->orig_hash, &hashit); - free_orig_node(orig_node, bat_priv); - } - - if (time_after(jiffies, (orig_node->last_frag_packet + - msecs_to_jiffies(FRAG_TIMEOUT)))) - frag_list_free(&orig_node->frag_list); - } - - spin_unlock_bh(&bat_priv->orig_hash_lock); - - gw_node_purge(bat_priv); - gw_election(bat_priv); - - softif_neigh_purge(bat_priv); -} - -static void purge_orig(struct work_struct *work) -{ - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); - struct bat_priv *bat_priv = - container_of(delayed_work, struct bat_priv, orig_work); - - _purge_orig(bat_priv); - start_purge_timer(bat_priv); -} - -void purge_orig_ref(struct bat_priv *bat_priv) -{ - _purge_orig(bat_priv); -} - -int orig_seq_print_text(struct seq_file *seq, void *offset) -{ - HASHIT(hashit); - struct element_t *bucket; - struct net_device *net_dev = (struct net_device *)seq->private; - struct bat_priv *bat_priv = netdev_priv(net_dev); - struct orig_node *orig_node; - struct neigh_node *neigh_node; - int batman_count = 0; - int last_seen_secs; - int last_seen_msecs; - - if ((!bat_priv->primary_if) || - (bat_priv->primary_if->if_status != IF_ACTIVE)) { - if (!bat_priv->primary_if) - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); - - return seq_printf(seq, "BATMAN mesh %s " - "disabled - primary interface not active\n", - net_dev->name); - } - - seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", - SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); - seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", - "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", - "outgoingIF", "Potential nexthops"); - - spin_lock_bh(&bat_priv->orig_hash_lock); - - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - - if (!orig_node->router) - continue; - - if (orig_node->router->tq_avg == 0) - continue; - - last_seen_secs = jiffies_to_msecs(jiffies - - orig_node->last_valid) / 1000; - last_seen_msecs = jiffies_to_msecs(jiffies - - orig_node->last_valid) % 1000; - - seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", - orig_node->orig, last_seen_secs, last_seen_msecs, - orig_node->router->tq_avg, orig_node->router->addr, - orig_node->router->if_incoming->net_dev->name); - - list_for_each_entry(neigh_node, &orig_node->neigh_list, list) { - seq_printf(seq, " %pM (%3i)", neigh_node->addr, - neigh_node->tq_avg); - } - - seq_printf(seq, "\n"); - batman_count++; - } - - spin_unlock_bh(&bat_priv->orig_hash_lock); - - if ((batman_count == 0)) - seq_printf(seq, "No batman nodes in range ...\n"); - - return 0; -} - -static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) -{ - void *data_ptr; - - data_ptr = kmalloc(max_if_num * sizeof(TYPE_OF_WORD) * NUM_WORDS, - GFP_ATOMIC); - if (!data_ptr) { - pr_err("Can't resize orig: out of memory\n"); - return -1; - } - - memcpy(data_ptr, orig_node->bcast_own, - (max_if_num - 1) * sizeof(TYPE_OF_WORD) * NUM_WORDS); - kfree(orig_node->bcast_own); - orig_node->bcast_own = data_ptr; - - data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); - if (!data_ptr) { - pr_err("Can't resize orig: out of memory\n"); - return -1; - } - - memcpy(data_ptr, orig_node->bcast_own_sum, - (max_if_num - 1) * sizeof(uint8_t)); - kfree(orig_node->bcast_own_sum); - orig_node->bcast_own_sum = data_ptr; - - return 0; -} - -int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - struct orig_node *orig_node; - HASHIT(hashit); - struct element_t *bucket; - - /* resize all orig nodes because orig_node->bcast_own(_sum) depend on - * if_num */ - spin_lock_bh(&bat_priv->orig_hash_lock); - - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - - if (orig_node_add_if(orig_node, max_if_num) == -1) - goto err; - } - - spin_unlock_bh(&bat_priv->orig_hash_lock); - return 0; - -err: - spin_unlock_bh(&bat_priv->orig_hash_lock); - return -ENOMEM; -} - -static int orig_node_del_if(struct orig_node *orig_node, - int max_if_num, int del_if_num) -{ - void *data_ptr = NULL; - int chunk_size; - - /* last interface was removed */ - if (max_if_num == 0) - goto free_bcast_own; - - chunk_size = sizeof(TYPE_OF_WORD) * NUM_WORDS; - data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC); - if (!data_ptr) { - pr_err("Can't resize orig: out of memory\n"); - return -1; - } - - /* copy first part */ - memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size); - - /* copy second part */ - memcpy(data_ptr + del_if_num * chunk_size, - orig_node->bcast_own + ((del_if_num + 1) * chunk_size), - (max_if_num - del_if_num) * chunk_size); - -free_bcast_own: - kfree(orig_node->bcast_own); - orig_node->bcast_own = data_ptr; - - if (max_if_num == 0) - goto free_own_sum; - - data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); - if (!data_ptr) { - pr_err("Can't resize orig: out of memory\n"); - return -1; - } - - memcpy(data_ptr, orig_node->bcast_own_sum, - del_if_num * sizeof(uint8_t)); - - memcpy(data_ptr + del_if_num * sizeof(uint8_t), - orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)), - (max_if_num - del_if_num) * sizeof(uint8_t)); - -free_own_sum: - kfree(orig_node->bcast_own_sum); - orig_node->bcast_own_sum = data_ptr; - - return 0; -} - -int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - struct batman_if *batman_if_tmp; - struct orig_node *orig_node; - HASHIT(hashit); - struct element_t *bucket; - int ret; - - /* resize all orig nodes because orig_node->bcast_own(_sum) depend on - * if_num */ - spin_lock_bh(&bat_priv->orig_hash_lock); - - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - - ret = orig_node_del_if(orig_node, max_if_num, - batman_if->if_num); - - if (ret == -1) - goto err; - } - - /* renumber remaining batman interfaces _inside_ of orig_hash_lock */ - rcu_read_lock(); - list_for_each_entry_rcu(batman_if_tmp, &if_list, list) { - if (batman_if_tmp->if_status == IF_NOT_IN_USE) - continue; - - if (batman_if == batman_if_tmp) - continue; - - if (batman_if->soft_iface != batman_if_tmp->soft_iface) - continue; - - if (batman_if_tmp->if_num > batman_if->if_num) - batman_if_tmp->if_num--; - } - rcu_read_unlock(); - - batman_if->if_num = -1; - spin_unlock_bh(&bat_priv->orig_hash_lock); - return 0; - -err: - spin_unlock_bh(&bat_priv->orig_hash_lock); - return -ENOMEM; -} diff --git a/drivers/staging/batman-adv/originator.h b/drivers/staging/batman-adv/originator.h deleted file mode 100644 index d474ceb2a4eb..000000000000 --- a/drivers/staging/batman-adv/originator.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_ -#define _NET_BATMAN_ADV_ORIGINATOR_H_ - -int originator_init(struct bat_priv *bat_priv); -void originator_free(struct bat_priv *bat_priv); -void purge_orig_ref(struct bat_priv *bat_priv); -struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); -struct neigh_node * -create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, - uint8_t *neigh, struct batman_if *if_incoming); -int orig_seq_print_text(struct seq_file *seq, void *offset); -int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); -int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); - - -/* returns 1 if they are the same originator */ -static inline int compare_orig(void *data1, void *data2) -{ - return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); -} - -/* hashfunction to choose an entry in a hash table of given size */ -/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ -static inline int choose_orig(void *data, int32_t size) -{ - unsigned char *key = data; - uint32_t hash = 0; - size_t i; - - for (i = 0; i < 6; i++) { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - - return hash % size; -} - -#endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ diff --git a/drivers/staging/batman-adv/packet.h b/drivers/staging/batman-adv/packet.h deleted file mode 100644 index b49fdf70a6d5..000000000000 --- a/drivers/staging/batman-adv/packet.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_PACKET_H_ -#define _NET_BATMAN_ADV_PACKET_H_ - -#define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ - -#define BAT_PACKET 0x01 -#define BAT_ICMP 0x02 -#define BAT_UNICAST 0x03 -#define BAT_BCAST 0x04 -#define BAT_VIS 0x05 -#define BAT_UNICAST_FRAG 0x06 - -/* this file is included by batctl which needs these defines */ -#define COMPAT_VERSION 12 -#define DIRECTLINK 0x40 -#define VIS_SERVER 0x20 -#define PRIMARIES_FIRST_HOP 0x10 - -/* ICMP message types */ -#define ECHO_REPLY 0 -#define DESTINATION_UNREACHABLE 3 -#define ECHO_REQUEST 8 -#define TTL_EXCEEDED 11 -#define PARAMETER_PROBLEM 12 - -/* vis defines */ -#define VIS_TYPE_SERVER_SYNC 0 -#define VIS_TYPE_CLIENT_UPDATE 1 - -/* fragmentation defines */ -#define UNI_FRAG_HEAD 0x01 - -struct batman_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ - uint8_t tq; - uint32_t seqno; - uint8_t orig[6]; - uint8_t prev_sender[6]; - uint8_t ttl; - uint8_t num_hna; - uint8_t gw_flags; /* flags related to gateway class */ - uint8_t align; -} __attribute__((packed)); - -#define BAT_PACKET_LEN sizeof(struct batman_packet) - -struct icmp_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t msg_type; /* see ICMP message types above */ - uint8_t ttl; - uint8_t dst[6]; - uint8_t orig[6]; - uint16_t seqno; - uint8_t uid; -} __attribute__((packed)); - -#define BAT_RR_LEN 16 - -/* icmp_packet_rr must start with all fields from imcp_packet - * as this is assumed by code that handles ICMP packets */ -struct icmp_packet_rr { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t msg_type; /* see ICMP message types above */ - uint8_t ttl; - uint8_t dst[6]; - uint8_t orig[6]; - uint16_t seqno; - uint8_t uid; - uint8_t rr_cur; - uint8_t rr[BAT_RR_LEN][ETH_ALEN]; -} __attribute__((packed)); - -struct unicast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t dest[6]; - uint8_t ttl; -} __attribute__((packed)); - -struct unicast_frag_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t dest[6]; - uint8_t ttl; - uint8_t flags; - uint8_t orig[6]; - uint16_t seqno; -} __attribute__((packed)); - -struct bcast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t orig[6]; - uint8_t ttl; - uint32_t seqno; -} __attribute__((packed)); - -struct vis_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t vis_type; /* which type of vis-participant sent this? */ - uint8_t entries; /* number of entries behind this struct */ - uint32_t seqno; /* sequence number */ - uint8_t ttl; /* TTL */ - uint8_t vis_orig[6]; /* originator that informs about its - * neighbors */ - uint8_t target_orig[6]; /* who should receive this packet */ - uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ -} __attribute__((packed)); - -#endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/drivers/staging/batman-adv/ring_buffer.c b/drivers/staging/batman-adv/ring_buffer.c deleted file mode 100644 index defd37c9be1f..000000000000 --- a/drivers/staging/batman-adv/ring_buffer.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "ring_buffer.h" - -void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value) -{ - lq_recv[*lq_index] = value; - *lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE; -} - -uint8_t ring_buffer_avg(uint8_t lq_recv[]) -{ - uint8_t *ptr; - uint16_t count = 0, i = 0, sum = 0; - - ptr = lq_recv; - - while (i < TQ_GLOBAL_WINDOW_SIZE) { - if (*ptr != 0) { - count++; - sum += *ptr; - } - - i++; - ptr++; - } - - if (count == 0) - return 0; - - return (uint8_t)(sum / count); -} diff --git a/drivers/staging/batman-adv/ring_buffer.h b/drivers/staging/batman-adv/ring_buffer.h deleted file mode 100644 index 6b0cb9aaeba5..000000000000 --- a/drivers/staging/batman-adv/ring_buffer.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_RING_BUFFER_H_ -#define _NET_BATMAN_ADV_RING_BUFFER_H_ - -void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value); -uint8_t ring_buffer_avg(uint8_t lq_recv[]); - -#endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */ diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c deleted file mode 100644 index d8b0c5a6d5df..000000000000 --- a/drivers/staging/batman-adv/routing.c +++ /dev/null @@ -1,1393 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "routing.h" -#include "send.h" -#include "hash.h" -#include "soft-interface.h" -#include "hard-interface.h" -#include "icmp_socket.h" -#include "translation-table.h" -#include "originator.h" -#include "types.h" -#include "ring_buffer.h" -#include "vis.h" -#include "aggregation.h" -#include "gateway_common.h" -#include "gateway_client.h" -#include "unicast.h" - -void slide_own_bcast_window(struct batman_if *batman_if) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - HASHIT(hashit); - struct element_t *bucket; - struct orig_node *orig_node; - TYPE_OF_WORD *word; - - spin_lock_bh(&bat_priv->orig_hash_lock); - - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]); - - bit_get_packet(bat_priv, word, 1, 0); - orig_node->bcast_own_sum[batman_if->if_num] = - bit_packet_count(word); - } - - spin_unlock_bh(&bat_priv->orig_hash_lock); -} - -static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, - unsigned char *hna_buff, int hna_buff_len) -{ - if ((hna_buff_len != orig_node->hna_buff_len) || - ((hna_buff_len > 0) && - (orig_node->hna_buff_len > 0) && - (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { - - if (orig_node->hna_buff_len > 0) - hna_global_del_orig(bat_priv, orig_node, - "originator changed hna"); - - if ((hna_buff_len > 0) && (hna_buff != NULL)) - hna_global_add_orig(bat_priv, orig_node, - hna_buff, hna_buff_len); - } -} - -static void update_route(struct bat_priv *bat_priv, - struct orig_node *orig_node, - struct neigh_node *neigh_node, - unsigned char *hna_buff, int hna_buff_len) -{ - /* route deleted */ - if ((orig_node->router != NULL) && (neigh_node == NULL)) { - - bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", - orig_node->orig); - hna_global_del_orig(bat_priv, orig_node, - "originator timed out"); - - /* route added */ - } else if ((orig_node->router == NULL) && (neigh_node != NULL)) { - - bat_dbg(DBG_ROUTES, bat_priv, - "Adding route towards: %pM (via %pM)\n", - orig_node->orig, neigh_node->addr); - hna_global_add_orig(bat_priv, orig_node, - hna_buff, hna_buff_len); - - /* route changed */ - } else { - bat_dbg(DBG_ROUTES, bat_priv, - "Changing route towards: %pM " - "(now via %pM - was via %pM)\n", - orig_node->orig, neigh_node->addr, - orig_node->router->addr); - } - - orig_node->router = neigh_node; -} - - -void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, - struct neigh_node *neigh_node, unsigned char *hna_buff, - int hna_buff_len) -{ - - if (orig_node == NULL) - return; - - if (orig_node->router != neigh_node) - update_route(bat_priv, orig_node, neigh_node, - hna_buff, hna_buff_len); - /* may be just HNA changed */ - else - update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); -} - -static int is_bidirectional_neigh(struct orig_node *orig_node, - struct orig_node *orig_neigh_node, - struct batman_packet *batman_packet, - struct batman_if *if_incoming) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; - unsigned char total_count; - - if (orig_node == orig_neigh_node) { - list_for_each_entry(tmp_neigh_node, - &orig_node->neigh_list, - list) { - - if (compare_orig(tmp_neigh_node->addr, - orig_neigh_node->orig) && - (tmp_neigh_node->if_incoming == if_incoming)) - neigh_node = tmp_neigh_node; - } - - if (!neigh_node) - neigh_node = create_neighbor(orig_node, - orig_neigh_node, - orig_neigh_node->orig, - if_incoming); - /* create_neighbor failed, return 0 */ - if (!neigh_node) - return 0; - - neigh_node->last_valid = jiffies; - } else { - /* find packet count of corresponding one hop neighbor */ - list_for_each_entry(tmp_neigh_node, - &orig_neigh_node->neigh_list, list) { - - if (compare_orig(tmp_neigh_node->addr, - orig_neigh_node->orig) && - (tmp_neigh_node->if_incoming == if_incoming)) - neigh_node = tmp_neigh_node; - } - - if (!neigh_node) - neigh_node = create_neighbor(orig_neigh_node, - orig_neigh_node, - orig_neigh_node->orig, - if_incoming); - /* create_neighbor failed, return 0 */ - if (!neigh_node) - return 0; - } - - orig_node->last_valid = jiffies; - - /* pay attention to not get a value bigger than 100 % */ - total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > - neigh_node->real_packet_count ? - neigh_node->real_packet_count : - orig_neigh_node->bcast_own_sum[if_incoming->if_num]); - - /* if we have too few packets (too less data) we set tq_own to zero */ - /* if we receive too few packets it is not considered bidirectional */ - if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || - (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) - orig_neigh_node->tq_own = 0; - else - /* neigh_node->real_packet_count is never zero as we - * only purge old information when getting new - * information */ - orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / - neigh_node->real_packet_count; - - /* - * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does - * affect the nearly-symmetric links only a little, but - * punishes asymmetric links more. This will give a value - * between 0 and TQ_MAX_VALUE - */ - orig_neigh_node->tq_asym_penalty = - TQ_MAX_VALUE - - (TQ_MAX_VALUE * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * - (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / - (TQ_LOCAL_WINDOW_SIZE * - TQ_LOCAL_WINDOW_SIZE * - TQ_LOCAL_WINDOW_SIZE); - - batman_packet->tq = ((batman_packet->tq * - orig_neigh_node->tq_own * - orig_neigh_node->tq_asym_penalty) / - (TQ_MAX_VALUE * TQ_MAX_VALUE)); - - bat_dbg(DBG_BATMAN, bat_priv, - "bidirectional: " - "orig = %-15pM neigh = %-15pM => own_bcast = %2i, " - "real recv = %2i, local tq: %3i, asym_penalty: %3i, " - "total tq: %3i\n", - orig_node->orig, orig_neigh_node->orig, total_count, - neigh_node->real_packet_count, orig_neigh_node->tq_own, - orig_neigh_node->tq_asym_penalty, batman_packet->tq); - - /* if link has the minimum required transmission quality - * consider it bidirectional */ - if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) - return 1; - - return 0; -} - -static void update_orig(struct bat_priv *bat_priv, - struct orig_node *orig_node, - struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - struct batman_if *if_incoming, - unsigned char *hna_buff, int hna_buff_len, - char is_duplicate) -{ - struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; - int tmp_hna_buff_len; - - bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " - "Searching and updating originator entry of received packet\n"); - - list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { - if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && - (tmp_neigh_node->if_incoming == if_incoming)) { - neigh_node = tmp_neigh_node; - continue; - } - - if (is_duplicate) - continue; - - ring_buffer_set(tmp_neigh_node->tq_recv, - &tmp_neigh_node->tq_index, 0); - tmp_neigh_node->tq_avg = - ring_buffer_avg(tmp_neigh_node->tq_recv); - } - - if (!neigh_node) { - struct orig_node *orig_tmp; - - orig_tmp = get_orig_node(bat_priv, ethhdr->h_source); - if (!orig_tmp) - return; - - neigh_node = create_neighbor(orig_node, orig_tmp, - ethhdr->h_source, if_incoming); - if (!neigh_node) - return; - } else - bat_dbg(DBG_BATMAN, bat_priv, - "Updating existing last-hop neighbor of originator\n"); - - orig_node->flags = batman_packet->flags; - neigh_node->last_valid = jiffies; - - ring_buffer_set(neigh_node->tq_recv, - &neigh_node->tq_index, - batman_packet->tq); - neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); - - if (!is_duplicate) { - orig_node->last_ttl = batman_packet->ttl; - neigh_node->last_ttl = batman_packet->ttl; - } - - tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? - batman_packet->num_hna * ETH_ALEN : hna_buff_len); - - /* if this neighbor already is our next hop there is nothing - * to change */ - if (orig_node->router == neigh_node) - goto update_hna; - - /* if this neighbor does not offer a better TQ we won't consider it */ - if ((orig_node->router) && - (orig_node->router->tq_avg > neigh_node->tq_avg)) - goto update_hna; - - /* if the TQ is the same and the link not more symetric we - * won't consider it either */ - if ((orig_node->router) && - ((neigh_node->tq_avg == orig_node->router->tq_avg) && - (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] - >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) - goto update_hna; - - update_routes(bat_priv, orig_node, neigh_node, - hna_buff, tmp_hna_buff_len); - goto update_gw; - -update_hna: - update_routes(bat_priv, orig_node, orig_node->router, - hna_buff, tmp_hna_buff_len); - -update_gw: - if (orig_node->gw_flags != batman_packet->gw_flags) - gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); - - orig_node->gw_flags = batman_packet->gw_flags; - - /* restart gateway selection if fast or late switching was enabled */ - if ((orig_node->gw_flags) && - (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && - (atomic_read(&bat_priv->gw_sel_class) > 2)) - gw_check_election(bat_priv, orig_node); -} - -/* checks whether the host restarted and is in the protection time. - * returns: - * 0 if the packet is to be accepted - * 1 if the packet is to be ignored. - */ -static int window_protected(struct bat_priv *bat_priv, - int32_t seq_num_diff, - unsigned long *last_reset) -{ - if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) - || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { - if (time_after(jiffies, *last_reset + - msecs_to_jiffies(RESET_PROTECTION_MS))) { - - *last_reset = jiffies; - bat_dbg(DBG_BATMAN, bat_priv, - "old packet received, start protection\n"); - - return 0; - } else - return 1; - } - return 0; -} - -/* processes a batman packet for all interfaces, adjusts the sequence number and - * finds out whether it is a duplicate. - * returns: - * 1 the packet is a duplicate - * 0 the packet has not yet been received - * -1 the packet is old and has been received while the seqno window - * was protected. Caller should drop it. - */ -static char count_real_packets(struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - struct batman_if *if_incoming) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct orig_node *orig_node; - struct neigh_node *tmp_neigh_node; - char is_duplicate = 0; - int32_t seq_diff; - int need_update = 0; - int set_mark; - - orig_node = get_orig_node(bat_priv, batman_packet->orig); - if (orig_node == NULL) - return 0; - - seq_diff = batman_packet->seqno - orig_node->last_real_seqno; - - /* signalize caller that the packet is to be dropped. */ - if (window_protected(bat_priv, seq_diff, - &orig_node->batman_seqno_reset)) - return -1; - - list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { - - is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, - orig_node->last_real_seqno, - batman_packet->seqno); - - if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && - (tmp_neigh_node->if_incoming == if_incoming)) - set_mark = 1; - else - set_mark = 0; - - /* if the window moved, set the update flag. */ - need_update |= bit_get_packet(bat_priv, - tmp_neigh_node->real_bits, - seq_diff, set_mark); - - tmp_neigh_node->real_packet_count = - bit_packet_count(tmp_neigh_node->real_bits); - } - - if (need_update) { - bat_dbg(DBG_BATMAN, bat_priv, - "updating last_seqno: old %d, new %d\n", - orig_node->last_real_seqno, batman_packet->seqno); - orig_node->last_real_seqno = batman_packet->seqno; - } - - return is_duplicate; -} - -/* copy primary address for bonding */ -static void mark_bonding_address(struct bat_priv *bat_priv, - struct orig_node *orig_node, - struct orig_node *orig_neigh_node, - struct batman_packet *batman_packet) - -{ - if (batman_packet->flags & PRIMARIES_FIRST_HOP) - memcpy(orig_neigh_node->primary_addr, - orig_node->orig, ETH_ALEN); - - return; -} - -/* mark possible bond.candidates in the neighbor list */ -void update_bonding_candidates(struct bat_priv *bat_priv, - struct orig_node *orig_node) -{ - int candidates; - int interference_candidate; - int best_tq; - struct neigh_node *tmp_neigh_node, *tmp_neigh_node2; - struct neigh_node *first_candidate, *last_candidate; - - /* update the candidates for this originator */ - if (!orig_node->router) { - orig_node->bond.candidates = 0; - return; - } - - best_tq = orig_node->router->tq_avg; - - /* update bond.candidates */ - - candidates = 0; - - /* mark other nodes which also received "PRIMARIES FIRST HOP" packets - * as "bonding partner" */ - - /* first, zero the list */ - list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { - tmp_neigh_node->next_bond_candidate = NULL; - } - - first_candidate = NULL; - last_candidate = NULL; - list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { - - /* only consider if it has the same primary address ... */ - if (memcmp(orig_node->orig, - tmp_neigh_node->orig_node->primary_addr, - ETH_ALEN) != 0) - continue; - - /* ... and is good enough to be considered */ - if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) - continue; - - /* check if we have another candidate with the same - * mac address or interface. If we do, we won't - * select this candidate because of possible interference. */ - - interference_candidate = 0; - list_for_each_entry(tmp_neigh_node2, - &orig_node->neigh_list, list) { - - if (tmp_neigh_node2 == tmp_neigh_node) - continue; - - /* we only care if the other candidate is even - * considered as candidate. */ - if (tmp_neigh_node2->next_bond_candidate == NULL) - continue; - - - if ((tmp_neigh_node->if_incoming == - tmp_neigh_node2->if_incoming) - || (memcmp(tmp_neigh_node->addr, - tmp_neigh_node2->addr, ETH_ALEN) == 0)) { - - interference_candidate = 1; - break; - } - } - /* don't care further if it is an interference candidate */ - if (interference_candidate) - continue; - - if (first_candidate == NULL) { - first_candidate = tmp_neigh_node; - tmp_neigh_node->next_bond_candidate = first_candidate; - } else - tmp_neigh_node->next_bond_candidate = last_candidate; - - last_candidate = tmp_neigh_node; - - candidates++; - } - - if (candidates > 0) { - first_candidate->next_bond_candidate = last_candidate; - orig_node->bond.selected = first_candidate; - } - - orig_node->bond.candidates = candidates; -} - -void receive_bat_packet(struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - unsigned char *hna_buff, int hna_buff_len, - struct batman_if *if_incoming) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct batman_if *batman_if; - struct orig_node *orig_neigh_node, *orig_node; - char has_directlink_flag; - char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; - char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; - char is_duplicate; - uint32_t if_incoming_seqno; - - /* Silently drop when the batman packet is actually not a - * correct packet. - * - * This might happen if a packet is padded (e.g. Ethernet has a - * minimum frame length of 64 byte) and the aggregation interprets - * it as an additional length. - * - * TODO: A more sane solution would be to have a bit in the - * batman_packet to detect whether the packet is the last - * packet in an aggregation. Here we expect that the padding - * is always zero (or not 0x01) - */ - if (batman_packet->packet_type != BAT_PACKET) - return; - - /* could be changed by schedule_own_packet() */ - if_incoming_seqno = atomic_read(&if_incoming->seqno); - - has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); - - is_single_hop_neigh = (compare_orig(ethhdr->h_source, - batman_packet->orig) ? 1 : 0); - - bat_dbg(DBG_BATMAN, bat_priv, - "Received BATMAN packet via NB: %pM, IF: %s [%pM] " - "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " - "TTL %d, V %d, IDF %d)\n", - ethhdr->h_source, if_incoming->net_dev->name, - if_incoming->net_dev->dev_addr, batman_packet->orig, - batman_packet->prev_sender, batman_packet->seqno, - batman_packet->tq, batman_packet->ttl, batman_packet->version, - has_directlink_flag); - - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->if_status != IF_ACTIVE) - continue; - - if (batman_if->soft_iface != if_incoming->soft_iface) - continue; - - if (compare_orig(ethhdr->h_source, - batman_if->net_dev->dev_addr)) - is_my_addr = 1; - - if (compare_orig(batman_packet->orig, - batman_if->net_dev->dev_addr)) - is_my_orig = 1; - - if (compare_orig(batman_packet->prev_sender, - batman_if->net_dev->dev_addr)) - is_my_oldorig = 1; - - if (compare_orig(ethhdr->h_source, broadcast_addr)) - is_broadcast = 1; - } - rcu_read_unlock(); - - if (batman_packet->version != COMPAT_VERSION) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: incompatible batman version (%i)\n", - batman_packet->version); - return; - } - - if (is_my_addr) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: received my own broadcast (sender: %pM" - ")\n", - ethhdr->h_source); - return; - } - - if (is_broadcast) { - bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " - "ignoring all packets with broadcast source addr (sender: %pM" - ")\n", ethhdr->h_source); - return; - } - - if (is_my_orig) { - TYPE_OF_WORD *word; - int offset; - - orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source); - - if (!orig_neigh_node) - return; - - /* neighbor has to indicate direct link and it has to - * come via the corresponding interface */ - /* if received seqno equals last send seqno save new - * seqno for bidirectional check */ - if (has_directlink_flag && - compare_orig(if_incoming->net_dev->dev_addr, - batman_packet->orig) && - (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { - offset = if_incoming->if_num * NUM_WORDS; - word = &(orig_neigh_node->bcast_own[offset]); - bit_mark(word, 0); - orig_neigh_node->bcast_own_sum[if_incoming->if_num] = - bit_packet_count(word); - } - - bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " - "originator packet from myself (via neighbor)\n"); - return; - } - - if (is_my_oldorig) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: ignoring all rebroadcast echos (sender: " - "%pM)\n", ethhdr->h_source); - return; - } - - orig_node = get_orig_node(bat_priv, batman_packet->orig); - if (orig_node == NULL) - return; - - is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming); - - if (is_duplicate == -1) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: packet within seqno protection time " - "(sender: %pM)\n", ethhdr->h_source); - return; - } - - if (batman_packet->tq == 0) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: originator packet with tq equal 0\n"); - return; - } - - /* avoid temporary routing loops */ - if ((orig_node->router) && - (orig_node->router->orig_node->router) && - (compare_orig(orig_node->router->addr, - batman_packet->prev_sender)) && - !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && - (compare_orig(orig_node->router->addr, - orig_node->router->orig_node->router->addr))) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: ignoring all rebroadcast packets that " - "may make me loop (sender: %pM)\n", ethhdr->h_source); - return; - } - - /* if sender is a direct neighbor the sender mac equals - * originator mac */ - orig_neigh_node = (is_single_hop_neigh ? - orig_node : - get_orig_node(bat_priv, ethhdr->h_source)); - if (orig_neigh_node == NULL) - return; - - /* drop packet if sender is not a direct neighbor and if we - * don't route towards it */ - if (!is_single_hop_neigh && - (orig_neigh_node->router == NULL)) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: OGM via unknown neighbor!\n"); - return; - } - - is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node, - batman_packet, if_incoming); - - /* update ranking if it is not a duplicate or has the same - * seqno and similar ttl as the non-duplicate */ - if (is_bidirectional && - (!is_duplicate || - ((orig_node->last_real_seqno == batman_packet->seqno) && - (orig_node->last_ttl - 3 <= batman_packet->ttl)))) - update_orig(bat_priv, orig_node, ethhdr, batman_packet, - if_incoming, hna_buff, hna_buff_len, is_duplicate); - - mark_bonding_address(bat_priv, orig_node, - orig_neigh_node, batman_packet); - update_bonding_candidates(bat_priv, orig_node); - - /* is single hop (direct) neighbor */ - if (is_single_hop_neigh) { - - /* mark direct link on incoming interface */ - schedule_forward_packet(orig_node, ethhdr, batman_packet, - 1, hna_buff_len, if_incoming); - - bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " - "rebroadcast neighbor packet with direct link flag\n"); - return; - } - - /* multihop originator */ - if (!is_bidirectional) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: not received via bidirectional link\n"); - return; - } - - if (is_duplicate) { - bat_dbg(DBG_BATMAN, bat_priv, - "Drop packet: duplicate packet received\n"); - return; - } - - bat_dbg(DBG_BATMAN, bat_priv, - "Forwarding packet: rebroadcast originator packet\n"); - schedule_forward_packet(orig_node, ethhdr, batman_packet, - 0, hna_buff_len, if_incoming); -} - -int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - struct ethhdr *ethhdr; - - /* drop packet if it has not necessary minimum size */ - if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) - return NET_RX_DROP; - - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* packet with broadcast indication but unicast recipient */ - if (!is_broadcast_ether_addr(ethhdr->h_dest)) - return NET_RX_DROP; - - /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) - return NET_RX_DROP; - - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, 0) < 0) - return NET_RX_DROP; - - /* keep skb linear */ - if (skb_linearize(skb) < 0) - return NET_RX_DROP; - - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - spin_lock_bh(&bat_priv->orig_hash_lock); - receive_aggr_bat_packet(ethhdr, - skb->data, - skb_headlen(skb), - batman_if); - spin_unlock_bh(&bat_priv->orig_hash_lock); - - kfree_skb(skb); - return NET_RX_SUCCESS; -} - -static int recv_my_icmp_packet(struct bat_priv *bat_priv, - struct sk_buff *skb, size_t icmp_len) -{ - struct orig_node *orig_node; - struct icmp_packet_rr *icmp_packet; - struct ethhdr *ethhdr; - struct batman_if *batman_if; - int ret; - uint8_t dstaddr[ETH_ALEN]; - - icmp_packet = (struct icmp_packet_rr *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* add data to device queue */ - if (icmp_packet->msg_type != ECHO_REQUEST) { - bat_socket_receive_packet(icmp_packet, icmp_len); - return NET_RX_DROP; - } - - if (!bat_priv->primary_if) - return NET_RX_DROP; - - /* answer echo request (ping) */ - /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - icmp_packet->orig)); - ret = NET_RX_DROP; - - if ((orig_node != NULL) && - (orig_node->router != NULL)) { - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); - - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; - - icmp_packet = (struct icmp_packet_rr *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - icmp_packet->msg_type = ECHO_REPLY; - icmp_packet->ttl = TTL; - - send_skb_packet(skb, batman_if, dstaddr); - ret = NET_RX_SUCCESS; - - } else - spin_unlock_bh(&bat_priv->orig_hash_lock); - - return ret; -} - -static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, - struct sk_buff *skb, size_t icmp_len) -{ - struct orig_node *orig_node; - struct icmp_packet *icmp_packet; - struct ethhdr *ethhdr; - struct batman_if *batman_if; - int ret; - uint8_t dstaddr[ETH_ALEN]; - - icmp_packet = (struct icmp_packet *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* send TTL exceeded if packet is an echo request (traceroute) */ - if (icmp_packet->msg_type != ECHO_REQUEST) { - pr_debug("Warning - can't forward icmp packet from %pM to " - "%pM: ttl exceeded\n", icmp_packet->orig, - icmp_packet->dst); - return NET_RX_DROP; - } - - if (!bat_priv->primary_if) - return NET_RX_DROP; - - /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - icmp_packet->orig)); - ret = NET_RX_DROP; - - if ((orig_node != NULL) && - (orig_node->router != NULL)) { - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); - - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; - - icmp_packet = (struct icmp_packet *) skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - icmp_packet->msg_type = TTL_EXCEEDED; - icmp_packet->ttl = TTL; - - send_skb_packet(skb, batman_if, dstaddr); - ret = NET_RX_SUCCESS; - - } else - spin_unlock_bh(&bat_priv->orig_hash_lock); - - return ret; -} - - -int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) -{ - struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct icmp_packet_rr *icmp_packet; - struct ethhdr *ethhdr; - struct orig_node *orig_node; - struct batman_if *batman_if; - int hdr_size = sizeof(struct icmp_packet); - int ret; - uint8_t dstaddr[ETH_ALEN]; - - /** - * we truncate all incoming icmp packets if they don't match our size - */ - if (skb->len >= sizeof(struct icmp_packet_rr)) - hdr_size = sizeof(struct icmp_packet_rr); - - /* drop packet if it has not necessary minimum size */ - if (unlikely(!pskb_may_pull(skb, hdr_size))) - return NET_RX_DROP; - - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* packet with unicast indication but broadcast recipient */ - if (is_broadcast_ether_addr(ethhdr->h_dest)) - return NET_RX_DROP; - - /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) - return NET_RX_DROP; - - /* not for me */ - if (!is_my_mac(ethhdr->h_dest)) - return NET_RX_DROP; - - icmp_packet = (struct icmp_packet_rr *)skb->data; - - /* add record route information if not full */ - if ((hdr_size == sizeof(struct icmp_packet_rr)) && - (icmp_packet->rr_cur < BAT_RR_LEN)) { - memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), - ethhdr->h_dest, ETH_ALEN); - icmp_packet->rr_cur++; - } - - /* packet for me */ - if (is_my_mac(icmp_packet->dst)) - return recv_my_icmp_packet(bat_priv, skb, hdr_size); - - /* TTL exceeded */ - if (icmp_packet->ttl < 2) - return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size); - - ret = NET_RX_DROP; - - /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - icmp_packet->dst)); - - if ((orig_node != NULL) && - (orig_node->router != NULL)) { - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); - - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; - - icmp_packet = (struct icmp_packet_rr *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* decrement ttl */ - icmp_packet->ttl--; - - /* route it */ - send_skb_packet(skb, batman_if, dstaddr); - ret = NET_RX_SUCCESS; - - } else - spin_unlock_bh(&bat_priv->orig_hash_lock); - - return ret; -} - -/* find a suitable router for this originator, and use - * bonding if possible. */ -struct neigh_node *find_router(struct bat_priv *bat_priv, - struct orig_node *orig_node, - struct batman_if *recv_if) -{ - struct orig_node *primary_orig_node; - struct orig_node *router_orig; - struct neigh_node *router, *first_candidate, *best_router; - static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; - int bonding_enabled; - - if (!orig_node) - return NULL; - - if (!orig_node->router) - return NULL; - - /* without bonding, the first node should - * always choose the default router. */ - - bonding_enabled = atomic_read(&bat_priv->bonding); - - if ((!recv_if) && (!bonding_enabled)) - return orig_node->router; - - router_orig = orig_node->router->orig_node; - - /* if we have something in the primary_addr, we can search - * for a potential bonding candidate. */ - if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0) - return orig_node->router; - - /* find the orig_node which has the primary interface. might - * even be the same as our router_orig in many cases */ - - if (memcmp(router_orig->primary_addr, - router_orig->orig, ETH_ALEN) == 0) { - primary_orig_node = router_orig; - } else { - primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, - choose_orig, - router_orig->primary_addr); - - if (!primary_orig_node) - return orig_node->router; - } - - /* with less than 2 candidates, we can't do any - * bonding and prefer the original router. */ - - if (primary_orig_node->bond.candidates < 2) - return orig_node->router; - - - /* all nodes between should choose a candidate which - * is is not on the interface where the packet came - * in. */ - first_candidate = primary_orig_node->bond.selected; - router = first_candidate; - - if (bonding_enabled) { - /* in the bonding case, send the packets in a round - * robin fashion over the remaining interfaces. */ - do { - /* recv_if == NULL on the first node. */ - if (router->if_incoming != recv_if) - break; - - router = router->next_bond_candidate; - } while (router != first_candidate); - - primary_orig_node->bond.selected = router->next_bond_candidate; - - } else { - /* if bonding is disabled, use the best of the - * remaining candidates which are not using - * this interface. */ - best_router = first_candidate; - - do { - /* recv_if == NULL on the first node. */ - if ((router->if_incoming != recv_if) && - (router->tq_avg > best_router->tq_avg)) - best_router = router; - - router = router->next_bond_candidate; - } while (router != first_candidate); - - router = best_router; - } - - return router; -} - -static int check_unicast_packet(struct sk_buff *skb, int hdr_size) -{ - struct ethhdr *ethhdr; - - /* drop packet if it has not necessary minimum size */ - if (unlikely(!pskb_may_pull(skb, hdr_size))) - return -1; - - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* packet with unicast indication but broadcast recipient */ - if (is_broadcast_ether_addr(ethhdr->h_dest)) - return -1; - - /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) - return -1; - - /* not for me */ - if (!is_my_mac(ethhdr->h_dest)) - return -1; - - return 0; -} - -int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - int hdr_size) -{ - struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct orig_node *orig_node; - struct neigh_node *router; - struct batman_if *batman_if; - uint8_t dstaddr[ETH_ALEN]; - struct unicast_packet *unicast_packet; - struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); - int ret; - struct sk_buff *new_skb; - - unicast_packet = (struct unicast_packet *)skb->data; - - /* TTL exceeded */ - if (unicast_packet->ttl < 2) { - pr_debug("Warning - can't forward unicast packet from %pM to " - "%pM: ttl exceeded\n", ethhdr->h_source, - unicast_packet->dest); - return NET_RX_DROP; - } - - /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - unicast_packet->dest)); - - router = find_router(bat_priv, orig_node, recv_if); - - if (!router) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - - batman_if = router->if_incoming; - memcpy(dstaddr, router->addr, ETH_ALEN); - - spin_unlock_bh(&bat_priv->orig_hash_lock); - - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; - - unicast_packet = (struct unicast_packet *)skb->data; - - if (unicast_packet->packet_type == BAT_UNICAST && - atomic_read(&bat_priv->fragmentation) && - skb->len > batman_if->net_dev->mtu) - return frag_send_skb(skb, bat_priv, batman_if, - dstaddr); - - if (unicast_packet->packet_type == BAT_UNICAST_FRAG && - 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) { - - ret = frag_reassemble_skb(skb, bat_priv, &new_skb); - - if (ret == NET_RX_DROP) - return NET_RX_DROP; - - /* packet was buffered for late merge */ - if (!new_skb) - return NET_RX_SUCCESS; - - skb = new_skb; - unicast_packet = (struct unicast_packet *)skb->data; - } - - /* decrement ttl */ - unicast_packet->ttl--; - - /* route it */ - send_skb_packet(skb, batman_if, dstaddr); - - return NET_RX_SUCCESS; -} - -int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) -{ - struct unicast_packet *unicast_packet; - int hdr_size = sizeof(struct unicast_packet); - - if (check_unicast_packet(skb, hdr_size) < 0) - return NET_RX_DROP; - - unicast_packet = (struct unicast_packet *)skb->data; - - /* packet for me */ - if (is_my_mac(unicast_packet->dest)) { - interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); - return NET_RX_SUCCESS; - } - - return route_unicast_packet(skb, recv_if, hdr_size); -} - -int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) -{ - struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct unicast_frag_packet *unicast_packet; - int hdr_size = sizeof(struct unicast_frag_packet); - struct sk_buff *new_skb = NULL; - int ret; - - if (check_unicast_packet(skb, hdr_size) < 0) - return NET_RX_DROP; - - unicast_packet = (struct unicast_frag_packet *)skb->data; - - /* packet for me */ - if (is_my_mac(unicast_packet->dest)) { - - ret = frag_reassemble_skb(skb, bat_priv, &new_skb); - - if (ret == NET_RX_DROP) - return NET_RX_DROP; - - /* packet was buffered for late merge */ - if (!new_skb) - return NET_RX_SUCCESS; - - interface_rx(recv_if->soft_iface, new_skb, recv_if, - sizeof(struct unicast_packet)); - return NET_RX_SUCCESS; - } - - return route_unicast_packet(skb, recv_if, hdr_size); -} - - -int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) -{ - struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct orig_node *orig_node; - struct bcast_packet *bcast_packet; - struct ethhdr *ethhdr; - int hdr_size = sizeof(struct bcast_packet); - int32_t seq_diff; - - /* drop packet if it has not necessary minimum size */ - if (unlikely(!pskb_may_pull(skb, hdr_size))) - return NET_RX_DROP; - - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* packet with broadcast indication but unicast recipient */ - if (!is_broadcast_ether_addr(ethhdr->h_dest)) - return NET_RX_DROP; - - /* packet with broadcast sender address */ - if (is_broadcast_ether_addr(ethhdr->h_source)) - return NET_RX_DROP; - - /* ignore broadcasts sent by myself */ - if (is_my_mac(ethhdr->h_source)) - return NET_RX_DROP; - - bcast_packet = (struct bcast_packet *)skb->data; - - /* ignore broadcasts originated by myself */ - if (is_my_mac(bcast_packet->orig)) - return NET_RX_DROP; - - if (bcast_packet->ttl < 2) - return NET_RX_DROP; - - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - bcast_packet->orig)); - - if (orig_node == NULL) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } - - /* check whether the packet is a duplicate */ - if (get_bit_status(orig_node->bcast_bits, - orig_node->last_bcast_seqno, - ntohl(bcast_packet->seqno))) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } - - seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno; - - /* check whether the packet is old and the host just restarted. */ - if (window_protected(bat_priv, seq_diff, - &orig_node->bcast_seqno_reset)) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } - - /* mark broadcast in flood history, update window position - * if required. */ - if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) - orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); - - spin_unlock_bh(&bat_priv->orig_hash_lock); - /* rebroadcast packet */ - add_bcast_packet_to_list(bat_priv, skb); - - /* broadcast for me */ - interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); - - return NET_RX_SUCCESS; -} - -int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if) -{ - struct vis_packet *vis_packet; - struct ethhdr *ethhdr; - struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - int hdr_size = sizeof(struct vis_packet); - - /* keep skb linear */ - if (skb_linearize(skb) < 0) - return NET_RX_DROP; - - if (unlikely(!pskb_may_pull(skb, hdr_size))) - return NET_RX_DROP; - - vis_packet = (struct vis_packet *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - /* not for me */ - if (!is_my_mac(ethhdr->h_dest)) - return NET_RX_DROP; - - /* ignore own packets */ - if (is_my_mac(vis_packet->vis_orig)) - return NET_RX_DROP; - - if (is_my_mac(vis_packet->sender_orig)) - return NET_RX_DROP; - - switch (vis_packet->vis_type) { - case VIS_TYPE_SERVER_SYNC: - receive_server_sync_packet(bat_priv, vis_packet, - skb_headlen(skb)); - break; - - case VIS_TYPE_CLIENT_UPDATE: - receive_client_update_packet(bat_priv, vis_packet, - skb_headlen(skb)); - break; - - default: /* ignore unknown packet */ - break; - } - - /* We take a copy of the data in the packet, so we should - always free the skbuf. */ - return NET_RX_DROP; -} diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h deleted file mode 100644 index f108f230bfdb..000000000000 --- a/drivers/staging/batman-adv/routing.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_ROUTING_H_ -#define _NET_BATMAN_ADV_ROUTING_H_ - -#include "types.h" - -void slide_own_bcast_window(struct batman_if *batman_if); -void receive_bat_packet(struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - unsigned char *hna_buff, int hna_buff_len, - struct batman_if *if_incoming); -void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, - struct neigh_node *neigh_node, unsigned char *hna_buff, - int hna_buff_len); -int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, - int hdr_size); -int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); -int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); -int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); -int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if); -int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if); -int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if); -struct neigh_node *find_router(struct bat_priv *bat_priv, - struct orig_node *orig_node, struct batman_if *recv_if); -void update_bonding_candidates(struct bat_priv *bat_priv, - struct orig_node *orig_node); - -#endif /* _NET_BATMAN_ADV_ROUTING_H_ */ diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c deleted file mode 100644 index 36945dc5a44b..000000000000 --- a/drivers/staging/batman-adv/send.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "send.h" -#include "routing.h" -#include "translation-table.h" -#include "soft-interface.h" -#include "hard-interface.h" -#include "types.h" -#include "vis.h" -#include "aggregation.h" -#include "gateway_common.h" -#include "originator.h" - - -static void send_outstanding_bcast_packet(struct work_struct *work); - -/* apply hop penalty for a normal link */ -static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) -{ - int hop_penalty = atomic_read(&bat_priv->hop_penalty); - return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); -} - -/* when do we schedule our own packet to be sent */ -static unsigned long own_send_time(struct bat_priv *bat_priv) -{ - return jiffies + msecs_to_jiffies( - atomic_read(&bat_priv->orig_interval) - - JITTER + (random32() % 2*JITTER)); -} - -/* when do we schedule a forwarded packet to be sent */ -static unsigned long forward_send_time(struct bat_priv *bat_priv) -{ - return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); -} - -/* send out an already prepared packet to the given address via the - * specified batman interface */ -int send_skb_packet(struct sk_buff *skb, - struct batman_if *batman_if, - uint8_t *dst_addr) -{ - struct ethhdr *ethhdr; - - if (batman_if->if_status != IF_ACTIVE) - goto send_skb_err; - - if (unlikely(!batman_if->net_dev)) - goto send_skb_err; - - if (!(batman_if->net_dev->flags & IFF_UP)) { - pr_warning("Interface %s is not up - can't send packet via " - "that interface!\n", batman_if->net_dev->name); - goto send_skb_err; - } - - /* push to the ethernet header. */ - if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0) - goto send_skb_err; - - skb_reset_mac_header(skb); - - ethhdr = (struct ethhdr *) skb_mac_header(skb); - memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN); - memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); - ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); - - skb_set_network_header(skb, ETH_HLEN); - skb->priority = TC_PRIO_CONTROL; - skb->protocol = __constant_htons(ETH_P_BATMAN); - - skb->dev = batman_if->net_dev; - - /* dev_queue_xmit() returns a negative result on error. However on - * congestion and traffic shaping, it drops and returns NET_XMIT_DROP - * (which is > 0). This will not be treated as an error. */ - - return dev_queue_xmit(skb); -send_skb_err: - kfree_skb(skb); - return NET_XMIT_DROP; -} - -/* Send a packet to a given interface */ -static void send_packet_to_if(struct forw_packet *forw_packet, - struct batman_if *batman_if) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - char *fwd_str; - uint8_t packet_num; - int16_t buff_pos; - struct batman_packet *batman_packet; - struct sk_buff *skb; - - if (batman_if->if_status != IF_ACTIVE) - return; - - packet_num = 0; - buff_pos = 0; - batman_packet = (struct batman_packet *)forw_packet->skb->data; - - /* adjust all flags and log packets */ - while (aggregated_packet(buff_pos, - forw_packet->packet_len, - batman_packet->num_hna)) { - - /* we might have aggregated direct link packets with an - * ordinary base packet */ - if ((forw_packet->direct_link_flags & (1 << packet_num)) && - (forw_packet->if_incoming == batman_if)) - batman_packet->flags |= DIRECTLINK; - else - batman_packet->flags &= ~DIRECTLINK; - - fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? - "Sending own" : - "Forwarding")); - bat_dbg(DBG_BATMAN, bat_priv, - "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," - " IDF %s) on interface %s [%pM]\n", - fwd_str, (packet_num > 0 ? "aggregated " : ""), - batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->tq, batman_packet->ttl, - (batman_packet->flags & DIRECTLINK ? - "on" : "off"), - batman_if->net_dev->name, batman_if->net_dev->dev_addr); - - buff_pos += sizeof(struct batman_packet) + - (batman_packet->num_hna * ETH_ALEN); - packet_num++; - batman_packet = (struct batman_packet *) - (forw_packet->skb->data + buff_pos); - } - - /* create clone because function is called more than once */ - skb = skb_clone(forw_packet->skb, GFP_ATOMIC); - if (skb) - send_skb_packet(skb, batman_if, broadcast_addr); -} - -/* send a batman packet */ -static void send_packet(struct forw_packet *forw_packet) -{ - struct batman_if *batman_if; - struct net_device *soft_iface; - struct bat_priv *bat_priv; - struct batman_packet *batman_packet = - (struct batman_packet *)(forw_packet->skb->data); - unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); - - if (!forw_packet->if_incoming) { - pr_err("Error - can't forward packet: incoming iface not " - "specified\n"); - return; - } - - soft_iface = forw_packet->if_incoming->soft_iface; - bat_priv = netdev_priv(soft_iface); - - if (forw_packet->if_incoming->if_status != IF_ACTIVE) - return; - - /* multihomed peer assumed */ - /* non-primary OGMs are only broadcasted on their interface */ - if ((directlink && (batman_packet->ttl == 1)) || - (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) { - - /* FIXME: what about aggregated packets ? */ - bat_dbg(DBG_BATMAN, bat_priv, - "%s packet (originator %pM, seqno %d, TTL %d) " - "on interface %s [%pM]\n", - (forw_packet->own ? "Sending own" : "Forwarding"), - batman_packet->orig, ntohl(batman_packet->seqno), - batman_packet->ttl, - forw_packet->if_incoming->net_dev->name, - forw_packet->if_incoming->net_dev->dev_addr); - - /* skb is only used once and than forw_packet is free'd */ - send_skb_packet(forw_packet->skb, forw_packet->if_incoming, - broadcast_addr); - forw_packet->skb = NULL; - - return; - } - - /* broadcast on every interface */ - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->soft_iface != soft_iface) - continue; - - send_packet_to_if(forw_packet, batman_if); - } - rcu_read_unlock(); -} - -static void rebuild_batman_packet(struct bat_priv *bat_priv, - struct batman_if *batman_if) -{ - int new_len; - unsigned char *new_buff; - struct batman_packet *batman_packet; - - new_len = sizeof(struct batman_packet) + - (bat_priv->num_local_hna * ETH_ALEN); - new_buff = kmalloc(new_len, GFP_ATOMIC); - - /* keep old buffer if kmalloc should fail */ - if (new_buff) { - memcpy(new_buff, batman_if->packet_buff, - sizeof(struct batman_packet)); - batman_packet = (struct batman_packet *)new_buff; - - batman_packet->num_hna = hna_local_fill_buffer(bat_priv, - new_buff + sizeof(struct batman_packet), - new_len - sizeof(struct batman_packet)); - - kfree(batman_if->packet_buff); - batman_if->packet_buff = new_buff; - batman_if->packet_len = new_len; - } -} - -void schedule_own_packet(struct batman_if *batman_if) -{ - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); - unsigned long send_time; - struct batman_packet *batman_packet; - int vis_server; - - if ((batman_if->if_status == IF_NOT_IN_USE) || - (batman_if->if_status == IF_TO_BE_REMOVED)) - return; - - vis_server = atomic_read(&bat_priv->vis_mode); - - /** - * the interface gets activated here to avoid race conditions between - * the moment of activating the interface in - * hardif_activate_interface() where the originator mac is set and - * outdated packets (especially uninitialized mac addresses) in the - * packet queue - */ - if (batman_if->if_status == IF_TO_BE_ACTIVATED) - batman_if->if_status = IF_ACTIVE; - - /* if local hna has changed and interface is a primary interface */ - if ((atomic_read(&bat_priv->hna_local_changed)) && - (batman_if == bat_priv->primary_if)) - rebuild_batman_packet(bat_priv, batman_if); - - /** - * NOTE: packet_buff might just have been re-allocated in - * rebuild_batman_packet() - */ - batman_packet = (struct batman_packet *)batman_if->packet_buff; - - /* change sequence number to network order */ - batman_packet->seqno = - htonl((uint32_t)atomic_read(&batman_if->seqno)); - - if (vis_server == VIS_TYPE_SERVER_SYNC) - batman_packet->flags |= VIS_SERVER; - else - batman_packet->flags &= ~VIS_SERVER; - - if ((batman_if == bat_priv->primary_if) && - (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) - batman_packet->gw_flags = - (uint8_t)atomic_read(&bat_priv->gw_bandwidth); - else - batman_packet->gw_flags = 0; - - atomic_inc(&batman_if->seqno); - - slide_own_bcast_window(batman_if); - send_time = own_send_time(bat_priv); - add_bat_packet_to_list(bat_priv, - batman_if->packet_buff, - batman_if->packet_len, - batman_if, 1, send_time); -} - -void schedule_forward_packet(struct orig_node *orig_node, - struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - uint8_t directlink, int hna_buff_len, - struct batman_if *if_incoming) -{ - struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - unsigned char in_tq, in_ttl, tq_avg = 0; - unsigned long send_time; - - if (batman_packet->ttl <= 1) { - bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); - return; - } - - in_tq = batman_packet->tq; - in_ttl = batman_packet->ttl; - - batman_packet->ttl--; - memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); - - /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast - * of our best tq value */ - if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { - - /* rebroadcast ogm of best ranking neighbor as is */ - if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) { - batman_packet->tq = orig_node->router->tq_avg; - - if (orig_node->router->last_ttl) - batman_packet->ttl = orig_node->router->last_ttl - - 1; - } - - tq_avg = orig_node->router->tq_avg; - } - - /* apply hop penalty */ - batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); - - bat_dbg(DBG_BATMAN, bat_priv, - "Forwarding packet: tq_orig: %i, tq_avg: %i, " - "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", - in_tq, tq_avg, batman_packet->tq, in_ttl - 1, - batman_packet->ttl); - - batman_packet->seqno = htonl(batman_packet->seqno); - - /* switch of primaries first hop flag when forwarding */ - batman_packet->flags &= ~PRIMARIES_FIRST_HOP; - if (directlink) - batman_packet->flags |= DIRECTLINK; - else - batman_packet->flags &= ~DIRECTLINK; - - send_time = forward_send_time(bat_priv); - add_bat_packet_to_list(bat_priv, - (unsigned char *)batman_packet, - sizeof(struct batman_packet) + hna_buff_len, - if_incoming, 0, send_time); -} - -static void forw_packet_free(struct forw_packet *forw_packet) -{ - if (forw_packet->skb) - kfree_skb(forw_packet->skb); - kfree(forw_packet); -} - -static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, - struct forw_packet *forw_packet, - unsigned long send_time) -{ - INIT_HLIST_NODE(&forw_packet->list); - - /* add new packet to packet list */ - spin_lock_bh(&bat_priv->forw_bcast_list_lock); - hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list); - spin_unlock_bh(&bat_priv->forw_bcast_list_lock); - - /* start timer for this packet */ - INIT_DELAYED_WORK(&forw_packet->delayed_work, - send_outstanding_bcast_packet); - queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work, - send_time); -} - -#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) -/* add a broadcast packet to the queue and setup timers. broadcast packets - * are sent multiple times to increase probability for beeing received. - * - * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on - * errors. - * - * The skb is not consumed, so the caller should make sure that the - * skb is freed. */ -int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) -{ - struct forw_packet *forw_packet; - struct bcast_packet *bcast_packet; - - if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) { - bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n"); - goto out; - } - - if (!bat_priv->primary_if) - goto out; - - forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); - - if (!forw_packet) - goto out_and_inc; - - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) - goto packet_free; - - /* as we have a copy now, it is safe to decrease the TTL */ - bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->ttl--; - - skb_reset_mac_header(skb); - - forw_packet->skb = skb; - forw_packet->if_incoming = bat_priv->primary_if; - - /* how often did we send the bcast packet ? */ - forw_packet->num_packets = 0; - - _add_bcast_packet_to_list(bat_priv, forw_packet, 1); - return NETDEV_TX_OK; - -packet_free: - kfree(forw_packet); -out_and_inc: - atomic_inc(&bat_priv->bcast_queue_left); -out: - return NETDEV_TX_BUSY; -} - -static void send_outstanding_bcast_packet(struct work_struct *work) -{ - struct batman_if *batman_if; - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); - struct forw_packet *forw_packet = - container_of(delayed_work, struct forw_packet, delayed_work); - struct sk_buff *skb1; - struct net_device *soft_iface = forw_packet->if_incoming->soft_iface; - struct bat_priv *bat_priv = netdev_priv(soft_iface); - - spin_lock_bh(&bat_priv->forw_bcast_list_lock); - hlist_del(&forw_packet->list); - spin_unlock_bh(&bat_priv->forw_bcast_list_lock); - - if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) - goto out; - - /* rebroadcast packet */ - rcu_read_lock(); - list_for_each_entry_rcu(batman_if, &if_list, list) { - if (batman_if->soft_iface != soft_iface) - continue; - - /* send a copy of the saved skb */ - skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC); - if (skb1) - send_skb_packet(skb1, batman_if, broadcast_addr); - } - rcu_read_unlock(); - - forw_packet->num_packets++; - - /* if we still have some more bcasts to send */ - if (forw_packet->num_packets < 3) { - _add_bcast_packet_to_list(bat_priv, forw_packet, - ((5 * HZ) / 1000)); - return; - } - -out: - forw_packet_free(forw_packet); - atomic_inc(&bat_priv->bcast_queue_left); -} - -void send_outstanding_bat_packet(struct work_struct *work) -{ - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); - struct forw_packet *forw_packet = - container_of(delayed_work, struct forw_packet, delayed_work); - struct bat_priv *bat_priv; - - bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface); - spin_lock_bh(&bat_priv->forw_bat_list_lock); - hlist_del(&forw_packet->list); - spin_unlock_bh(&bat_priv->forw_bat_list_lock); - - if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) - goto out; - - send_packet(forw_packet); - - /** - * we have to have at least one packet in the queue - * to determine the queues wake up time unless we are - * shutting down - */ - if (forw_packet->own) - schedule_own_packet(forw_packet->if_incoming); - -out: - /* don't count own packet */ - if (!forw_packet->own) - atomic_inc(&bat_priv->batman_queue_left); - - forw_packet_free(forw_packet); -} - -void purge_outstanding_packets(struct bat_priv *bat_priv, - struct batman_if *batman_if) -{ - struct forw_packet *forw_packet; - struct hlist_node *tmp_node, *safe_tmp_node; - - if (batman_if) - bat_dbg(DBG_BATMAN, bat_priv, - "purge_outstanding_packets(): %s\n", - batman_if->net_dev->name); - else - bat_dbg(DBG_BATMAN, bat_priv, - "purge_outstanding_packets()\n"); - - /* free bcast list */ - spin_lock_bh(&bat_priv->forw_bcast_list_lock); - hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, - &bat_priv->forw_bcast_list, list) { - - /** - * if purge_outstanding_packets() was called with an argmument - * we delete only packets belonging to the given interface - */ - if ((batman_if) && - (forw_packet->if_incoming != batman_if)) - continue; - - spin_unlock_bh(&bat_priv->forw_bcast_list_lock); - - /** - * send_outstanding_bcast_packet() will lock the list to - * delete the item from the list - */ - cancel_delayed_work_sync(&forw_packet->delayed_work); - spin_lock_bh(&bat_priv->forw_bcast_list_lock); - } - spin_unlock_bh(&bat_priv->forw_bcast_list_lock); - - /* free batman packet list */ - spin_lock_bh(&bat_priv->forw_bat_list_lock); - hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, - &bat_priv->forw_bat_list, list) { - - /** - * if purge_outstanding_packets() was called with an argmument - * we delete only packets belonging to the given interface - */ - if ((batman_if) && - (forw_packet->if_incoming != batman_if)) - continue; - - spin_unlock_bh(&bat_priv->forw_bat_list_lock); - - /** - * send_outstanding_bat_packet() will lock the list to - * delete the item from the list - */ - cancel_delayed_work_sync(&forw_packet->delayed_work); - spin_lock_bh(&bat_priv->forw_bat_list_lock); - } - spin_unlock_bh(&bat_priv->forw_bat_list_lock); -} diff --git a/drivers/staging/batman-adv/send.h b/drivers/staging/batman-adv/send.h deleted file mode 100644 index c4cefa8e4f85..000000000000 --- a/drivers/staging/batman-adv/send.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_SEND_H_ -#define _NET_BATMAN_ADV_SEND_H_ - -#include "types.h" - -int send_skb_packet(struct sk_buff *skb, - struct batman_if *batman_if, - uint8_t *dst_addr); -void schedule_own_packet(struct batman_if *batman_if); -void schedule_forward_packet(struct orig_node *orig_node, - struct ethhdr *ethhdr, - struct batman_packet *batman_packet, - uint8_t directlink, int hna_buff_len, - struct batman_if *if_outgoing); -int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb); -void send_outstanding_bat_packet(struct work_struct *work); -void purge_outstanding_packets(struct bat_priv *bat_priv, - struct batman_if *batman_if); - -#endif /* _NET_BATMAN_ADV_SEND_H_ */ diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c deleted file mode 100644 index e89ede192ed0..000000000000 --- a/drivers/staging/batman-adv/soft-interface.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "soft-interface.h" -#include "hard-interface.h" -#include "routing.h" -#include "send.h" -#include "bat_debugfs.h" -#include "translation-table.h" -#include "types.h" -#include "hash.h" -#include "gateway_common.h" -#include "gateway_client.h" -#include "send.h" -#include "bat_sysfs.h" -#include -#include -#include -#include -#include "unicast.h" -#include "routing.h" - - -static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); -static void bat_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info); -static u32 bat_get_msglevel(struct net_device *dev); -static void bat_set_msglevel(struct net_device *dev, u32 value); -static u32 bat_get_link(struct net_device *dev); -static u32 bat_get_rx_csum(struct net_device *dev); -static int bat_set_rx_csum(struct net_device *dev, u32 data); - -static const struct ethtool_ops bat_ethtool_ops = { - .get_settings = bat_get_settings, - .get_drvinfo = bat_get_drvinfo, - .get_msglevel = bat_get_msglevel, - .set_msglevel = bat_set_msglevel, - .get_link = bat_get_link, - .get_rx_csum = bat_get_rx_csum, - .set_rx_csum = bat_set_rx_csum -}; - -int my_skb_head_push(struct sk_buff *skb, unsigned int len) -{ - int result; - - /** - * TODO: We must check if we can release all references to non-payload - * data using skb_header_release in our skbs to allow skb_cow_header to - * work optimally. This means that those skbs are not allowed to read - * or write any data which is before the current position of skb->data - * after that call and thus allow other skbs with the same data buffer - * to write freely in that area. - */ - result = skb_cow_head(skb, len); - if (result < 0) - return result; - - skb_push(skb, len); - return 0; -} - -static void softif_neigh_free_ref(struct kref *refcount) -{ - struct softif_neigh *softif_neigh; - - softif_neigh = container_of(refcount, struct softif_neigh, refcount); - kfree(softif_neigh); -} - -static void softif_neigh_free_rcu(struct rcu_head *rcu) -{ - struct softif_neigh *softif_neigh; - - softif_neigh = container_of(rcu, struct softif_neigh, rcu); - kref_put(&softif_neigh->refcount, softif_neigh_free_ref); -} - -void softif_neigh_purge(struct bat_priv *bat_priv) -{ - struct softif_neigh *softif_neigh, *softif_neigh_tmp; - struct hlist_node *node, *node_tmp; - - spin_lock_bh(&bat_priv->softif_neigh_lock); - - hlist_for_each_entry_safe(softif_neigh, node, node_tmp, - &bat_priv->softif_neigh_list, list) { - - if ((!time_after(jiffies, softif_neigh->last_seen + - msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && - (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) - continue; - - hlist_del_rcu(&softif_neigh->list); - - if (bat_priv->softif_neigh == softif_neigh) { - bat_dbg(DBG_ROUTES, bat_priv, - "Current mesh exit point '%pM' vanished " - "(vid: %d).\n", - softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = NULL; - kref_put(&softif_neigh_tmp->refcount, - softif_neigh_free_ref); - } - - call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); - } - - spin_unlock_bh(&bat_priv->softif_neigh_lock); -} - -static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, - uint8_t *addr, short vid) -{ - struct softif_neigh *softif_neigh; - struct hlist_node *node; - - rcu_read_lock(); - hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) { - if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) - continue; - - if (softif_neigh->vid != vid) - continue; - - softif_neigh->last_seen = jiffies; - goto found; - } - - softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); - if (!softif_neigh) - goto out; - - memcpy(softif_neigh->addr, addr, ETH_ALEN); - softif_neigh->vid = vid; - softif_neigh->last_seen = jiffies; - kref_init(&softif_neigh->refcount); - - INIT_HLIST_NODE(&softif_neigh->list); - spin_lock_bh(&bat_priv->softif_neigh_lock); - hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); - spin_unlock_bh(&bat_priv->softif_neigh_lock); - -found: - kref_get(&softif_neigh->refcount); -out: - rcu_read_unlock(); - return softif_neigh; -} - -int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) -{ - struct net_device *net_dev = (struct net_device *)seq->private; - struct bat_priv *bat_priv = netdev_priv(net_dev); - struct softif_neigh *softif_neigh; - struct hlist_node *node; - size_t buf_size, pos; - char *buff; - - if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); - } - - seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); - - buf_size = 1; - /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ - rcu_read_lock(); - hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) - buf_size += 30; - rcu_read_unlock(); - - buff = kmalloc(buf_size, GFP_ATOMIC); - if (!buff) - return -ENOMEM; - - buff[0] = '\0'; - pos = 0; - - rcu_read_lock(); - hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) { - pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", - bat_priv->softif_neigh == softif_neigh - ? "=>" : " ", softif_neigh->addr, - softif_neigh->vid); - } - rcu_read_unlock(); - - seq_printf(seq, "%s", buff); - kfree(buff); - return 0; -} - -static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, - short vid) -{ - struct bat_priv *bat_priv = netdev_priv(dev); - struct ethhdr *ethhdr = (struct ethhdr *)skb->data; - struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh, *softif_neigh_tmp; - - if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) - batman_packet = (struct batman_packet *) - (skb->data + ETH_HLEN + VLAN_HLEN); - else - batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); - - if (batman_packet->version != COMPAT_VERSION) - goto err; - - if (batman_packet->packet_type != BAT_PACKET) - goto err; - - if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) - goto err; - - if (is_my_mac(batman_packet->orig)) - goto err; - - softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); - - if (!softif_neigh) - goto err; - - if (bat_priv->softif_neigh == softif_neigh) - goto out; - - /* we got a neighbor but its mac is 'bigger' than ours */ - if (memcmp(bat_priv->primary_if->net_dev->dev_addr, - softif_neigh->addr, ETH_ALEN) < 0) - goto out; - - /* switch to new 'smallest neighbor' */ - if ((bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, - ETH_ALEN) < 0)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Changing mesh exit point from %pM (vid: %d) " - "to %pM (vid: %d).\n", - bat_priv->softif_neigh->addr, - bat_priv->softif_neigh->vid, - softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = softif_neigh; - kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); - /* we need to hold the additional reference */ - goto err; - } - - /* close own batX device and use softif_neigh as exit node */ - if ((!bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Setting mesh exit point to %pM (vid: %d).\n", - softif_neigh->addr, softif_neigh->vid); - bat_priv->softif_neigh = softif_neigh; - /* we need to hold the additional reference */ - goto err; - } - -out: - kref_put(&softif_neigh->refcount, softif_neigh_free_ref); -err: - kfree_skb(skb); - return; -} - -static int interface_open(struct net_device *dev) -{ - netif_start_queue(dev); - return 0; -} - -static int interface_release(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -static struct net_device_stats *interface_stats(struct net_device *dev) -{ - struct bat_priv *bat_priv = netdev_priv(dev); - return &bat_priv->stats; -} - -static int interface_set_mac_addr(struct net_device *dev, void *p) -{ - struct bat_priv *bat_priv = netdev_priv(dev); - struct sockaddr *addr = p; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - /* only modify hna-table if it has been initialised before */ - if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { - hna_local_remove(bat_priv, dev->dev_addr, - "mac address changed"); - hna_local_add(dev, addr->sa_data); - } - - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); - return 0; -} - -static int interface_change_mtu(struct net_device *dev, int new_mtu) -{ - /* check ranges */ - if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev))) - return -EINVAL; - - dev->mtu = new_mtu; - - return 0; -} - -int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) -{ - struct ethhdr *ethhdr = (struct ethhdr *)skb->data; - struct bat_priv *bat_priv = netdev_priv(soft_iface); - struct bcast_packet *bcast_packet; - struct vlan_ethhdr *vhdr; - int data_len = skb->len, ret; - short vid = -1; - bool do_bcast = false; - - if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) - goto dropped; - - soft_iface->trans_start = jiffies; - - switch (ntohs(ethhdr->h_proto)) { - case ETH_P_8021Q: - vhdr = (struct vlan_ethhdr *)skb->data; - vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; - - if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) - break; - - /* fall through */ - case ETH_P_BATMAN: - softif_batman_recv(skb, soft_iface, vid); - goto end; - } - - /** - * if we have a another chosen mesh exit node in range - * it will transport the packets to the mesh - */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) - goto dropped; - - /* TODO: check this for locks */ - hna_local_add(soft_iface, ethhdr->h_source); - - if (is_multicast_ether_addr(ethhdr->h_dest)) { - ret = gw_is_target(bat_priv, skb); - - if (ret < 0) - goto dropped; - - if (ret == 0) - do_bcast = true; - } - - /* ethernet packet should be broadcasted */ - if (do_bcast) { - if (!bat_priv->primary_if) - goto dropped; - - if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) - goto dropped; - - bcast_packet = (struct bcast_packet *)skb->data; - bcast_packet->version = COMPAT_VERSION; - bcast_packet->ttl = TTL; - - /* batman packet type: broadcast */ - bcast_packet->packet_type = BAT_BCAST; - - /* hw address of first interface is the orig mac because only - * this mac is known throughout the mesh */ - memcpy(bcast_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - - /* set broadcast sequence number */ - bcast_packet->seqno = - htonl(atomic_inc_return(&bat_priv->bcast_seqno)); - - add_bcast_packet_to_list(bat_priv, skb); - - /* a copy is stored in the bcast list, therefore removing - * the original skb. */ - kfree_skb(skb); - - /* unicast packet */ - } else { - ret = unicast_send_skb(skb, bat_priv); - if (ret != 0) - goto dropped_freed; - } - - bat_priv->stats.tx_packets++; - bat_priv->stats.tx_bytes += data_len; - goto end; - -dropped: - kfree_skb(skb); -dropped_freed: - bat_priv->stats.tx_dropped++; -end: - return NETDEV_TX_OK; -} - -void interface_rx(struct net_device *soft_iface, - struct sk_buff *skb, struct batman_if *recv_if, - int hdr_size) -{ - struct bat_priv *bat_priv = netdev_priv(soft_iface); - struct unicast_packet *unicast_packet; - struct ethhdr *ethhdr; - struct vlan_ethhdr *vhdr; - short vid = -1; - int ret; - - /* check if enough space is available for pulling, and pull */ - if (!pskb_may_pull(skb, hdr_size)) - goto dropped; - - skb_pull_rcsum(skb, hdr_size); - skb_reset_mac_header(skb); - - ethhdr = (struct ethhdr *)skb_mac_header(skb); - - switch (ntohs(ethhdr->h_proto)) { - case ETH_P_8021Q: - vhdr = (struct vlan_ethhdr *)skb->data; - vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; - - if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) - break; - - /* fall through */ - case ETH_P_BATMAN: - goto dropped; - } - - /** - * if we have a another chosen mesh exit node in range - * it will transport the packets to the non-mesh network - */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { - skb_push(skb, hdr_size); - unicast_packet = (struct unicast_packet *)skb->data; - - if ((unicast_packet->packet_type != BAT_UNICAST) && - (unicast_packet->packet_type != BAT_UNICAST_FRAG)) - goto dropped; - - skb_reset_mac_header(skb); - - memcpy(unicast_packet->dest, - bat_priv->softif_neigh->addr, ETH_ALEN); - ret = route_unicast_packet(skb, recv_if, hdr_size); - if (ret == NET_RX_DROP) - goto dropped; - - goto out; - } - - /* skb->dev & skb->pkt_type are set here */ - if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) - goto dropped; - skb->protocol = eth_type_trans(skb, soft_iface); - - /* should not be neccesary anymore as we use skb_pull_rcsum() - * TODO: please verify this and remove this TODO - * -- Dec 21st 2009, Simon Wunderlich */ - -/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/ - - bat_priv->stats.rx_packets++; - bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); - - soft_iface->last_rx = jiffies; - - netif_rx(skb); - return; - -dropped: - kfree_skb(skb); -out: - return; -} - -#ifdef HAVE_NET_DEVICE_OPS -static const struct net_device_ops bat_netdev_ops = { - .ndo_open = interface_open, - .ndo_stop = interface_release, - .ndo_get_stats = interface_stats, - .ndo_set_mac_address = interface_set_mac_addr, - .ndo_change_mtu = interface_change_mtu, - .ndo_start_xmit = interface_tx, - .ndo_validate_addr = eth_validate_addr -}; -#endif - -static void interface_setup(struct net_device *dev) -{ - struct bat_priv *priv = netdev_priv(dev); - char dev_addr[ETH_ALEN]; - - ether_setup(dev); - -#ifdef HAVE_NET_DEVICE_OPS - dev->netdev_ops = &bat_netdev_ops; -#else - dev->open = interface_open; - dev->stop = interface_release; - dev->get_stats = interface_stats; - dev->set_mac_address = interface_set_mac_addr; - dev->change_mtu = interface_change_mtu; - dev->hard_start_xmit = interface_tx; -#endif - dev->destructor = free_netdev; - - /** - * can't call min_mtu, because the needed variables - * have not been initialized yet - */ - dev->mtu = ETH_DATA_LEN; - dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the - * skbuff for our header */ - - /* generate random address */ - random_ether_addr(dev_addr); - memcpy(dev->dev_addr, dev_addr, ETH_ALEN); - - SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); - - memset(priv, 0, sizeof(struct bat_priv)); -} - -struct net_device *softif_create(char *name) -{ - struct net_device *soft_iface; - struct bat_priv *bat_priv; - int ret; - - soft_iface = alloc_netdev(sizeof(struct bat_priv) , name, - interface_setup); - - if (!soft_iface) { - pr_err("Unable to allocate the batman interface: %s\n", name); - goto out; - } - - ret = register_netdev(soft_iface); - if (ret < 0) { - pr_err("Unable to register the batman interface '%s': %i\n", - name, ret); - goto free_soft_iface; - } - - bat_priv = netdev_priv(soft_iface); - - atomic_set(&bat_priv->aggregated_ogms, 1); - atomic_set(&bat_priv->bonding, 0); - atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); - atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); - atomic_set(&bat_priv->gw_sel_class, 20); - atomic_set(&bat_priv->gw_bandwidth, 41); - atomic_set(&bat_priv->orig_interval, 1000); - atomic_set(&bat_priv->hop_penalty, 10); - atomic_set(&bat_priv->log_level, 0); - atomic_set(&bat_priv->fragmentation, 1); - atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); - atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN); - - atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); - atomic_set(&bat_priv->bcast_seqno, 1); - atomic_set(&bat_priv->hna_local_changed, 0); - - bat_priv->primary_if = NULL; - bat_priv->num_ifaces = 0; - bat_priv->softif_neigh = NULL; - - ret = sysfs_add_meshif(soft_iface); - if (ret < 0) - goto unreg_soft_iface; - - ret = debugfs_add_meshif(soft_iface); - if (ret < 0) - goto unreg_sysfs; - - ret = mesh_init(soft_iface); - if (ret < 0) - goto unreg_debugfs; - - return soft_iface; - -unreg_debugfs: - debugfs_del_meshif(soft_iface); -unreg_sysfs: - sysfs_del_meshif(soft_iface); -unreg_soft_iface: - unregister_netdev(soft_iface); - return NULL; - -free_soft_iface: - free_netdev(soft_iface); -out: - return NULL; -} - -void softif_destroy(struct net_device *soft_iface) -{ - debugfs_del_meshif(soft_iface); - sysfs_del_meshif(soft_iface); - mesh_free(soft_iface); - unregister_netdevice(soft_iface); -} - -/* ethtool */ -static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - cmd->supported = 0; - cmd->advertising = 0; - cmd->speed = SPEED_10; - cmd->duplex = DUPLEX_FULL; - cmd->port = PORT_TP; - cmd->phy_address = 0; - cmd->transceiver = XCVR_INTERNAL; - cmd->autoneg = AUTONEG_DISABLE; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - - return 0; -} - -static void bat_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, "B.A.T.M.A.N. advanced"); - strcpy(info->version, SOURCE_VERSION); - strcpy(info->fw_version, "N/A"); - strcpy(info->bus_info, "batman"); -} - -static u32 bat_get_msglevel(struct net_device *dev) -{ - return -EOPNOTSUPP; -} - -static void bat_set_msglevel(struct net_device *dev, u32 value) -{ -} - -static u32 bat_get_link(struct net_device *dev) -{ - return 1; -} - -static u32 bat_get_rx_csum(struct net_device *dev) -{ - return 0; -} - -static int bat_set_rx_csum(struct net_device *dev, u32 data) -{ - return -EOPNOTSUPP; -} diff --git a/drivers/staging/batman-adv/soft-interface.h b/drivers/staging/batman-adv/soft-interface.h deleted file mode 100644 index 02b77334d10d..000000000000 --- a/drivers/staging/batman-adv/soft-interface.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_ -#define _NET_BATMAN_ADV_SOFT_INTERFACE_H_ - -int my_skb_head_push(struct sk_buff *skb, unsigned int len); -int softif_neigh_seq_print_text(struct seq_file *seq, void *offset); -void softif_neigh_purge(struct bat_priv *bat_priv); -int interface_tx(struct sk_buff *skb, struct net_device *soft_iface); -void interface_rx(struct net_device *soft_iface, - struct sk_buff *skb, struct batman_if *recv_if, - int hdr_size); -struct net_device *softif_create(char *name); -void softif_destroy(struct net_device *soft_iface); - -#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ diff --git a/drivers/staging/batman-adv/sysfs-class-net-batman-adv b/drivers/staging/batman-adv/sysfs-class-net-batman-adv deleted file mode 100644 index 38dd762def4b..000000000000 --- a/drivers/staging/batman-adv/sysfs-class-net-batman-adv +++ /dev/null @@ -1,14 +0,0 @@ - -What: /sys/class/net//batman-adv/mesh_iface -Date: May 2010 -Contact: Marek Lindner -Description: - The /sys/class/net//batman-adv/mesh_iface file - displays the batman mesh interface this - currently is associated with. - -What: /sys/class/net//batman-adv/iface_status -Date: May 2010 -Contact: Marek Lindner -Description: - Indicates the status of as it is seen by batman. diff --git a/drivers/staging/batman-adv/sysfs-class-net-mesh b/drivers/staging/batman-adv/sysfs-class-net-mesh deleted file mode 100644 index 748fe1701d25..000000000000 --- a/drivers/staging/batman-adv/sysfs-class-net-mesh +++ /dev/null @@ -1,69 +0,0 @@ - -What: /sys/class/net//mesh/aggregated_ogms -Date: May 2010 -Contact: Marek Lindner -Description: - Indicates whether the batman protocol messages of the - mesh shall be aggregated or not. - -What: /sys/class/net//mesh/bonding -Date: June 2010 -Contact: Simon Wunderlich -Description: - Indicates whether the data traffic going through the - mesh will be sent using multiple interfaces at the - same time (if available). - -What: /sys/class/net//mesh/fragmentation -Date: October 2010 -Contact: Andreas Langer -Description: - Indicates whether the data traffic going through the - mesh will be fragmented or silently discarded if the - packet size exceeds the outgoing interface MTU. - -What: /sys/class/net//mesh/gw_bandwidth -Date: October 2010 -Contact: Marek Lindner -Description: - Defines the bandwidth which is propagated by this - node if gw_mode was set to 'server'. - -What: /sys/class/net//mesh/gw_mode -Date: October 2010 -Contact: Marek Lindner -Description: - Defines the state of the gateway features. Can be - either 'off', 'client' or 'server'. - -What: /sys/class/net//mesh/gw_sel_class -Date: October 2010 -Contact: Marek Lindner -Description: - Defines the selection criteria this node will use - to choose a gateway if gw_mode was set to 'client'. - -What: /sys/class/net//mesh/orig_interval -Date: May 2010 -Contact: Marek Lindner -Description: - Defines the interval in milliseconds in which batman - sends its protocol messages. - -What: /sys/class/net//mesh/hop_penalty -Date: Oct 2010 -Contact: Linus Lüssing -Description: - Defines the penalty which will be applied to an - originator message's tq-field on every hop. - -What: /sys/class/net//mesh/vis_mode -Date: May 2010 -Contact: Marek Lindner -Description: - Each batman node only maintains information about its - own local neighborhood, therefore generating graphs - showing the topology of the entire mesh is not easily - feasible without having a central instance to collect - the local topologies from all nodes. This file allows - to activate the collecting (server) mode. diff --git a/drivers/staging/batman-adv/translation-table.c b/drivers/staging/batman-adv/translation-table.c deleted file mode 100644 index 4b0a1079347b..000000000000 --- a/drivers/staging/batman-adv/translation-table.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "translation-table.h" -#include "soft-interface.h" -#include "types.h" -#include "hash.h" -#include "originator.h" - -static void hna_local_purge(struct work_struct *work); -static void _hna_global_del_orig(struct bat_priv *bat_priv, - struct hna_global_entry *hna_global_entry, - char *message); - -static void hna_local_start_timer(struct bat_priv *bat_priv) -{ - INIT_DELAYED_WORK(&bat_priv->hna_work, hna_local_purge); - queue_delayed_work(bat_event_workqueue, &bat_priv->hna_work, 10 * HZ); -} - -int hna_local_init(struct bat_priv *bat_priv) -{ - if (bat_priv->hna_local_hash) - return 1; - - bat_priv->hna_local_hash = hash_new(128); - - if (!bat_priv->hna_local_hash) - return 0; - - atomic_set(&bat_priv->hna_local_changed, 0); - hna_local_start_timer(bat_priv); - - return 1; -} - -void hna_local_add(struct net_device *soft_iface, uint8_t *addr) -{ - struct bat_priv *bat_priv = netdev_priv(soft_iface); - struct hna_local_entry *hna_local_entry; - struct hna_global_entry *hna_global_entry; - struct hashtable_t *swaphash; - int required_bytes; - - spin_lock_bh(&bat_priv->hna_lhash_lock); - hna_local_entry = - ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, - compare_orig, choose_orig, - addr)); - spin_unlock_bh(&bat_priv->hna_lhash_lock); - - if (hna_local_entry) { - hna_local_entry->last_seen = jiffies; - return; - } - - /* only announce as many hosts as possible in the batman-packet and - space in batman_packet->num_hna That also should give a limit to - MAC-flooding. */ - required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN; - required_bytes += BAT_PACKET_LEN; - - if ((required_bytes > ETH_DATA_LEN) || - (atomic_read(&bat_priv->aggregated_ogms) && - required_bytes > MAX_AGGREGATION_BYTES) || - (bat_priv->num_local_hna + 1 > 255)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Can't add new local hna entry (%pM): " - "number of local hna entries exceeds packet size\n", - addr); - return; - } - - bat_dbg(DBG_ROUTES, bat_priv, - "Creating new local hna entry: %pM\n", addr); - - hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); - if (!hna_local_entry) - return; - - memcpy(hna_local_entry->addr, addr, ETH_ALEN); - hna_local_entry->last_seen = jiffies; - - /* the batman interface mac address should never be purged */ - if (compare_orig(addr, soft_iface->dev_addr)) - hna_local_entry->never_purge = 1; - else - hna_local_entry->never_purge = 0; - - spin_lock_bh(&bat_priv->hna_lhash_lock); - - hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig, - hna_local_entry); - bat_priv->num_local_hna++; - atomic_set(&bat_priv->hna_local_changed, 1); - - if (bat_priv->hna_local_hash->elements * 4 > - bat_priv->hna_local_hash->size) { - swaphash = hash_resize(bat_priv->hna_local_hash, choose_orig, - bat_priv->hna_local_hash->size * 2); - - if (!swaphash) - pr_err("Couldn't resize local hna hash table\n"); - else - bat_priv->hna_local_hash = swaphash; - } - - spin_unlock_bh(&bat_priv->hna_lhash_lock); - - /* remove address from global hash if present */ - spin_lock_bh(&bat_priv->hna_ghash_lock); - - hna_global_entry = ((struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, - compare_orig, choose_orig, addr)); - - if (hna_global_entry) - _hna_global_del_orig(bat_priv, hna_global_entry, - "local hna received"); - - spin_unlock_bh(&bat_priv->hna_ghash_lock); -} - -int hna_local_fill_buffer(struct bat_priv *bat_priv, - unsigned char *buff, int buff_len) -{ - struct hna_local_entry *hna_local_entry; - struct element_t *bucket; - HASHIT(hashit); - int i = 0; - - spin_lock_bh(&bat_priv->hna_lhash_lock); - - while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - - if (buff_len < (i + 1) * ETH_ALEN) - break; - - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - hna_local_entry = bucket->data; - memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN); - - i++; - } - - /* if we did not get all new local hnas see you next time ;-) */ - if (i == bat_priv->num_local_hna) - atomic_set(&bat_priv->hna_local_changed, 0); - - spin_unlock_bh(&bat_priv->hna_lhash_lock); - return i; -} - -int hna_local_seq_print_text(struct seq_file *seq, void *offset) -{ - struct net_device *net_dev = (struct net_device *)seq->private; - struct bat_priv *bat_priv = netdev_priv(net_dev); - struct hna_local_entry *hna_local_entry; - HASHIT(hashit); - HASHIT(hashit_count); - struct element_t *bucket; - size_t buf_size, pos; - char *buff; - - if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); - } - - seq_printf(seq, "Locally retrieved addresses (from %s) " - "announced via HNA:\n", - net_dev->name); - - spin_lock_bh(&bat_priv->hna_lhash_lock); - - buf_size = 1; - /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ - while (hash_iterate(bat_priv->hna_local_hash, &hashit_count)) - buf_size += 21; - - buff = kmalloc(buf_size, GFP_ATOMIC); - if (!buff) { - spin_unlock_bh(&bat_priv->hna_lhash_lock); - return -ENOMEM; - } - buff[0] = '\0'; - pos = 0; - - while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - hna_local_entry = bucket->data; - - pos += snprintf(buff + pos, 22, " * %pM\n", - hna_local_entry->addr); - } - - spin_unlock_bh(&bat_priv->hna_lhash_lock); - - seq_printf(seq, "%s", buff); - kfree(buff); - return 0; -} - -static void _hna_local_del(void *data, void *arg) -{ - struct bat_priv *bat_priv = (struct bat_priv *)arg; - - kfree(data); - bat_priv->num_local_hna--; - atomic_set(&bat_priv->hna_local_changed, 1); -} - -static void hna_local_del(struct bat_priv *bat_priv, - struct hna_local_entry *hna_local_entry, - char *message) -{ - bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", - hna_local_entry->addr, message); - - hash_remove(bat_priv->hna_local_hash, compare_orig, choose_orig, - hna_local_entry->addr); - _hna_local_del(hna_local_entry, bat_priv); -} - -void hna_local_remove(struct bat_priv *bat_priv, - uint8_t *addr, char *message) -{ - struct hna_local_entry *hna_local_entry; - - spin_lock_bh(&bat_priv->hna_lhash_lock); - - hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, - addr); - if (hna_local_entry) - hna_local_del(bat_priv, hna_local_entry, message); - - spin_unlock_bh(&bat_priv->hna_lhash_lock); -} - -static void hna_local_purge(struct work_struct *work) -{ - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); - struct bat_priv *bat_priv = - container_of(delayed_work, struct bat_priv, hna_work); - struct hna_local_entry *hna_local_entry; - HASHIT(hashit); - struct element_t *bucket; - unsigned long timeout; - - spin_lock_bh(&bat_priv->hna_lhash_lock); - - while (hash_iterate(bat_priv->hna_local_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - hna_local_entry = bucket->data; - - timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ; - - if ((!hna_local_entry->never_purge) && - time_after(jiffies, timeout)) - hna_local_del(bat_priv, hna_local_entry, - "address timed out"); - } - - spin_unlock_bh(&bat_priv->hna_lhash_lock); - hna_local_start_timer(bat_priv); -} - -void hna_local_free(struct bat_priv *bat_priv) -{ - if (!bat_priv->hna_local_hash) - return; - - cancel_delayed_work_sync(&bat_priv->hna_work); - hash_delete(bat_priv->hna_local_hash, _hna_local_del, bat_priv); - bat_priv->hna_local_hash = NULL; -} - -int hna_global_init(struct bat_priv *bat_priv) -{ - if (bat_priv->hna_global_hash) - return 1; - - bat_priv->hna_global_hash = hash_new(128); - - if (!bat_priv->hna_global_hash) - return 0; - - return 1; -} - -void hna_global_add_orig(struct bat_priv *bat_priv, - struct orig_node *orig_node, - unsigned char *hna_buff, int hna_buff_len) -{ - struct hna_global_entry *hna_global_entry; - struct hna_local_entry *hna_local_entry; - struct hashtable_t *swaphash; - int hna_buff_count = 0; - unsigned char *hna_ptr; - - while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { - spin_lock_bh(&bat_priv->hna_ghash_lock); - - hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); - hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, compare_orig, - choose_orig, hna_ptr); - - if (!hna_global_entry) { - spin_unlock_bh(&bat_priv->hna_ghash_lock); - - hna_global_entry = - kmalloc(sizeof(struct hna_global_entry), - GFP_ATOMIC); - - if (!hna_global_entry) - break; - - memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); - - bat_dbg(DBG_ROUTES, bat_priv, - "Creating new global hna entry: " - "%pM (via %pM)\n", - hna_global_entry->addr, orig_node->orig); - - spin_lock_bh(&bat_priv->hna_ghash_lock); - hash_add(bat_priv->hna_global_hash, compare_orig, - choose_orig, hna_global_entry); - - } - - hna_global_entry->orig_node = orig_node; - spin_unlock_bh(&bat_priv->hna_ghash_lock); - - /* remove address from local hash if present */ - spin_lock_bh(&bat_priv->hna_lhash_lock); - - hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); - hna_local_entry = (struct hna_local_entry *) - hash_find(bat_priv->hna_local_hash, compare_orig, - choose_orig, hna_ptr); - - if (hna_local_entry) - hna_local_del(bat_priv, hna_local_entry, - "global hna received"); - - spin_unlock_bh(&bat_priv->hna_lhash_lock); - - hna_buff_count++; - } - - /* initialize, and overwrite if malloc succeeds */ - orig_node->hna_buff = NULL; - orig_node->hna_buff_len = 0; - - if (hna_buff_len > 0) { - orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC); - if (orig_node->hna_buff) { - memcpy(orig_node->hna_buff, hna_buff, hna_buff_len); - orig_node->hna_buff_len = hna_buff_len; - } - } - - spin_lock_bh(&bat_priv->hna_ghash_lock); - - if (bat_priv->hna_global_hash->elements * 4 > - bat_priv->hna_global_hash->size) { - swaphash = hash_resize(bat_priv->hna_global_hash, choose_orig, - bat_priv->hna_global_hash->size * 2); - - if (!swaphash) - pr_err("Couldn't resize global hna hash table\n"); - else - bat_priv->hna_global_hash = swaphash; - } - - spin_unlock_bh(&bat_priv->hna_ghash_lock); -} - -int hna_global_seq_print_text(struct seq_file *seq, void *offset) -{ - struct net_device *net_dev = (struct net_device *)seq->private; - struct bat_priv *bat_priv = netdev_priv(net_dev); - struct hna_global_entry *hna_global_entry; - HASHIT(hashit); - HASHIT(hashit_count); - struct element_t *bucket; - size_t buf_size, pos; - char *buff; - - if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); - } - - seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", - net_dev->name); - - spin_lock_bh(&bat_priv->hna_ghash_lock); - - buf_size = 1; - /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ - while (hash_iterate(bat_priv->hna_global_hash, &hashit_count)) - buf_size += 43; - - buff = kmalloc(buf_size, GFP_ATOMIC); - if (!buff) { - spin_unlock_bh(&bat_priv->hna_ghash_lock); - return -ENOMEM; - } - buff[0] = '\0'; - pos = 0; - - while (hash_iterate(bat_priv->hna_global_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - hna_global_entry = bucket->data; - - pos += snprintf(buff + pos, 44, - " * %pM via %pM\n", hna_global_entry->addr, - hna_global_entry->orig_node->orig); - } - - spin_unlock_bh(&bat_priv->hna_ghash_lock); - - seq_printf(seq, "%s", buff); - kfree(buff); - return 0; -} - -static void _hna_global_del_orig(struct bat_priv *bat_priv, - struct hna_global_entry *hna_global_entry, - char *message) -{ - bat_dbg(DBG_ROUTES, bat_priv, - "Deleting global hna entry %pM (via %pM): %s\n", - hna_global_entry->addr, hna_global_entry->orig_node->orig, - message); - - hash_remove(bat_priv->hna_global_hash, compare_orig, choose_orig, - hna_global_entry->addr); - kfree(hna_global_entry); -} - -void hna_global_del_orig(struct bat_priv *bat_priv, - struct orig_node *orig_node, char *message) -{ - struct hna_global_entry *hna_global_entry; - int hna_buff_count = 0; - unsigned char *hna_ptr; - - if (orig_node->hna_buff_len == 0) - return; - - spin_lock_bh(&bat_priv->hna_ghash_lock); - - while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { - hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); - hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, compare_orig, - choose_orig, hna_ptr); - - if ((hna_global_entry) && - (hna_global_entry->orig_node == orig_node)) - _hna_global_del_orig(bat_priv, hna_global_entry, - message); - - hna_buff_count++; - } - - spin_unlock_bh(&bat_priv->hna_ghash_lock); - - orig_node->hna_buff_len = 0; - kfree(orig_node->hna_buff); - orig_node->hna_buff = NULL; -} - -static void hna_global_del(void *data, void *arg) -{ - kfree(data); -} - -void hna_global_free(struct bat_priv *bat_priv) -{ - if (!bat_priv->hna_global_hash) - return; - - hash_delete(bat_priv->hna_global_hash, hna_global_del, NULL); - bat_priv->hna_global_hash = NULL; -} - -struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) -{ - struct hna_global_entry *hna_global_entry; - - spin_lock_bh(&bat_priv->hna_ghash_lock); - hna_global_entry = (struct hna_global_entry *) - hash_find(bat_priv->hna_global_hash, - compare_orig, choose_orig, addr); - spin_unlock_bh(&bat_priv->hna_ghash_lock); - - if (!hna_global_entry) - return NULL; - - return hna_global_entry->orig_node; -} diff --git a/drivers/staging/batman-adv/translation-table.h b/drivers/staging/batman-adv/translation-table.h deleted file mode 100644 index 10c4c5c319b6..000000000000 --- a/drivers/staging/batman-adv/translation-table.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ -#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ - -#include "types.h" - -int hna_local_init(struct bat_priv *bat_priv); -void hna_local_add(struct net_device *soft_iface, uint8_t *addr); -void hna_local_remove(struct bat_priv *bat_priv, - uint8_t *addr, char *message); -int hna_local_fill_buffer(struct bat_priv *bat_priv, - unsigned char *buff, int buff_len); -int hna_local_seq_print_text(struct seq_file *seq, void *offset); -void hna_local_free(struct bat_priv *bat_priv); -int hna_global_init(struct bat_priv *bat_priv); -void hna_global_add_orig(struct bat_priv *bat_priv, - struct orig_node *orig_node, - unsigned char *hna_buff, int hna_buff_len); -int hna_global_seq_print_text(struct seq_file *seq, void *offset); -void hna_global_del_orig(struct bat_priv *bat_priv, - struct orig_node *orig_node, char *message); -void hna_global_free(struct bat_priv *bat_priv); -struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr); - -#endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h deleted file mode 100644 index 1d0084995c7c..000000000000 --- a/drivers/staging/batman-adv/types.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: - * - * Marek Lindner, Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - - - -#ifndef _NET_BATMAN_ADV_TYPES_H_ -#define _NET_BATMAN_ADV_TYPES_H_ - -#include "packet.h" -#include "bitarray.h" - -#define BAT_HEADER_LEN (sizeof(struct ethhdr) + \ - ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \ - sizeof(struct unicast_packet) : \ - sizeof(struct bcast_packet)))) - - -struct batman_if { - struct list_head list; - int16_t if_num; - char if_status; - struct net_device *net_dev; - atomic_t seqno; - atomic_t frag_seqno; - unsigned char *packet_buff; - int packet_len; - struct kobject *hardif_obj; - struct kref refcount; - struct packet_type batman_adv_ptype; - struct net_device *soft_iface; - struct rcu_head rcu; -}; - -/** - * orig_node - structure for orig_list maintaining nodes of mesh - * @primary_addr: hosts primary interface address - * @last_valid: when last packet from this node was received - * @bcast_seqno_reset: time when the broadcast seqno window was reset - * @batman_seqno_reset: time when the batman seqno window was reset - * @gw_flags: flags related to gateway class - * @flags: for now only VIS_SERVER flag - * @last_real_seqno: last and best known squence number - * @last_ttl: ttl of last received packet - * @last_bcast_seqno: last broadcast sequence number received by this host - * - * @candidates: how many candidates are available - * @selected: next bonding candidate - */ -struct orig_node { - uint8_t orig[ETH_ALEN]; - uint8_t primary_addr[ETH_ALEN]; - struct neigh_node *router; - TYPE_OF_WORD *bcast_own; - uint8_t *bcast_own_sum; - uint8_t tq_own; - int tq_asym_penalty; - unsigned long last_valid; - unsigned long bcast_seqno_reset; - unsigned long batman_seqno_reset; - uint8_t gw_flags; - uint8_t flags; - unsigned char *hna_buff; - int16_t hna_buff_len; - uint32_t last_real_seqno; - uint8_t last_ttl; - TYPE_OF_WORD bcast_bits[NUM_WORDS]; - uint32_t last_bcast_seqno; - struct list_head neigh_list; - struct list_head frag_list; - unsigned long last_frag_packet; - struct { - uint8_t candidates; - struct neigh_node *selected; - } bond; -}; - -struct gw_node { - struct hlist_node list; - struct orig_node *orig_node; - unsigned long deleted; - struct kref refcount; - struct rcu_head rcu; -}; - -/** - * neigh_node - * @last_valid: when last packet via this neighbor was received - */ -struct neigh_node { - struct list_head list; - uint8_t addr[ETH_ALEN]; - uint8_t real_packet_count; - uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE]; - uint8_t tq_index; - uint8_t tq_avg; - uint8_t last_ttl; - struct neigh_node *next_bond_candidate; - unsigned long last_valid; - TYPE_OF_WORD real_bits[NUM_WORDS]; - struct orig_node *orig_node; - struct batman_if *if_incoming; -}; - - -struct bat_priv { - atomic_t mesh_state; - struct net_device_stats stats; - atomic_t aggregated_ogms; /* boolean */ - atomic_t bonding; /* boolean */ - atomic_t fragmentation; /* boolean */ - atomic_t vis_mode; /* VIS_TYPE_* */ - atomic_t gw_mode; /* GW_MODE_* */ - atomic_t gw_sel_class; /* uint */ - atomic_t gw_bandwidth; /* gw bandwidth */ - atomic_t orig_interval; /* uint */ - atomic_t hop_penalty; /* uint */ - atomic_t log_level; /* uint */ - atomic_t bcast_seqno; - atomic_t bcast_queue_left; - atomic_t batman_queue_left; - char num_ifaces; - struct hlist_head softif_neigh_list; - struct softif_neigh *softif_neigh; - struct debug_log *debug_log; - struct batman_if *primary_if; - struct kobject *mesh_obj; - struct dentry *debug_dir; - struct hlist_head forw_bat_list; - struct hlist_head forw_bcast_list; - struct hlist_head gw_list; - struct list_head vis_send_list; - struct hashtable_t *orig_hash; - struct hashtable_t *hna_local_hash; - struct hashtable_t *hna_global_hash; - struct hashtable_t *vis_hash; - spinlock_t orig_hash_lock; /* protects orig_hash */ - spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ - spinlock_t forw_bcast_list_lock; /* protects */ - spinlock_t hna_lhash_lock; /* protects hna_local_hash */ - spinlock_t hna_ghash_lock; /* protects hna_global_hash */ - spinlock_t gw_list_lock; /* protects gw_list */ - spinlock_t vis_hash_lock; /* protects vis_hash */ - spinlock_t vis_list_lock; /* protects vis_info::recv_list */ - spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ - int16_t num_local_hna; - atomic_t hna_local_changed; - struct delayed_work hna_work; - struct delayed_work orig_work; - struct delayed_work vis_work; - struct gw_node *curr_gw; - struct vis_info *my_vis_info; -}; - -struct socket_client { - struct list_head queue_list; - unsigned int queue_len; - unsigned char index; - spinlock_t lock; /* protects queue_list, queue_len, index */ - wait_queue_head_t queue_wait; - struct bat_priv *bat_priv; -}; - -struct socket_packet { - struct list_head list; - size_t icmp_len; - struct icmp_packet_rr icmp_packet; -}; - -struct hna_local_entry { - uint8_t addr[ETH_ALEN]; - unsigned long last_seen; - char never_purge; -}; - -struct hna_global_entry { - uint8_t addr[ETH_ALEN]; - struct orig_node *orig_node; -}; - -/** - * forw_packet - structure for forw_list maintaining packets to be - * send/forwarded - */ -struct forw_packet { - struct hlist_node list; - unsigned long send_time; - uint8_t own; - struct sk_buff *skb; - uint16_t packet_len; - uint32_t direct_link_flags; - uint8_t num_packets; - struct delayed_work delayed_work; - struct batman_if *if_incoming; -}; - -/* While scanning for vis-entries of a particular vis-originator - * this list collects its interfaces to create a subgraph/cluster - * out of them later - */ -struct if_list_entry { - uint8_t addr[ETH_ALEN]; - bool primary; - struct hlist_node list; -}; - -struct debug_log { - char log_buff[LOG_BUF_LEN]; - unsigned long log_start; - unsigned long log_end; - spinlock_t lock; /* protects log_buff, log_start and log_end */ - wait_queue_head_t queue_wait; -}; - -struct frag_packet_list_entry { - struct list_head list; - uint16_t seqno; - struct sk_buff *skb; -}; - -struct vis_info { - unsigned long first_seen; - struct list_head recv_list; - /* list of server-neighbors we received a vis-packet - * from. we should not reply to them. */ - struct list_head send_list; - struct kref refcount; - struct bat_priv *bat_priv; - /* this packet might be part of the vis send queue. */ - struct sk_buff *skb_packet; - /* vis_info may follow here*/ -} __attribute__((packed)); - -struct vis_info_entry { - uint8_t src[ETH_ALEN]; - uint8_t dest[ETH_ALEN]; - uint8_t quality; /* quality = 0 means HNA */ -} __attribute__((packed)); - -struct recvlist_node { - struct list_head list; - uint8_t mac[ETH_ALEN]; -}; - -struct softif_neigh { - struct hlist_node list; - uint8_t addr[ETH_ALEN]; - unsigned long last_seen; - short vid; - struct kref refcount; - struct rcu_head rcu; -}; - -#endif /* _NET_BATMAN_ADV_TYPES_H_ */ diff --git a/drivers/staging/batman-adv/unicast.c b/drivers/staging/batman-adv/unicast.c deleted file mode 100644 index dc2e28bed844..000000000000 --- a/drivers/staging/batman-adv/unicast.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2010 B.A.T.M.A.N. contributors: - * - * Andreas Langer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "unicast.h" -#include "send.h" -#include "soft-interface.h" -#include "gateway_client.h" -#include "originator.h" -#include "hash.h" -#include "translation-table.h" -#include "routing.h" -#include "hard-interface.h" - - -static struct sk_buff *frag_merge_packet(struct list_head *head, - struct frag_packet_list_entry *tfp, - struct sk_buff *skb) -{ - struct unicast_frag_packet *up = - (struct unicast_frag_packet *)skb->data; - struct sk_buff *tmp_skb; - struct unicast_packet *unicast_packet; - int hdr_len = sizeof(struct unicast_packet), - uni_diff = sizeof(struct unicast_frag_packet) - hdr_len; - - /* set skb to the first part and tmp_skb to the second part */ - if (up->flags & UNI_FRAG_HEAD) { - tmp_skb = tfp->skb; - } else { - tmp_skb = skb; - skb = tfp->skb; - } - - skb_pull(tmp_skb, sizeof(struct unicast_frag_packet)); - if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) { - /* free buffered skb, skb will be freed later */ - kfree_skb(tfp->skb); - return NULL; - } - - /* move free entry to end */ - tfp->skb = NULL; - tfp->seqno = 0; - list_move_tail(&tfp->list, head); - - memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len); - kfree_skb(tmp_skb); - - memmove(skb->data + uni_diff, skb->data, hdr_len); - unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); - unicast_packet->packet_type = BAT_UNICAST; - - return skb; -} - -static void frag_create_entry(struct list_head *head, struct sk_buff *skb) -{ - struct frag_packet_list_entry *tfp; - struct unicast_frag_packet *up = - (struct unicast_frag_packet *)skb->data; - - /* free and oldest packets stand at the end */ - tfp = list_entry((head)->prev, typeof(*tfp), list); - kfree_skb(tfp->skb); - - tfp->seqno = ntohs(up->seqno); - tfp->skb = skb; - list_move(&tfp->list, head); - return; -} - -static int frag_create_buffer(struct list_head *head) -{ - int i; - struct frag_packet_list_entry *tfp; - - for (i = 0; i < FRAG_BUFFER_SIZE; i++) { - tfp = kmalloc(sizeof(struct frag_packet_list_entry), - GFP_ATOMIC); - if (!tfp) { - frag_list_free(head); - return -ENOMEM; - } - tfp->skb = NULL; - tfp->seqno = 0; - INIT_LIST_HEAD(&tfp->list); - list_add(&tfp->list, head); - } - - return 0; -} - -static struct frag_packet_list_entry *frag_search_packet(struct list_head *head, - struct unicast_frag_packet *up) -{ - struct frag_packet_list_entry *tfp; - struct unicast_frag_packet *tmp_up = NULL; - uint16_t search_seqno; - - if (up->flags & UNI_FRAG_HEAD) - search_seqno = ntohs(up->seqno)+1; - else - search_seqno = ntohs(up->seqno)-1; - - list_for_each_entry(tfp, head, list) { - - if (!tfp->skb) - continue; - - if (tfp->seqno == ntohs(up->seqno)) - goto mov_tail; - - tmp_up = (struct unicast_frag_packet *)tfp->skb->data; - - if (tfp->seqno == search_seqno) { - - if ((tmp_up->flags & UNI_FRAG_HEAD) != - (up->flags & UNI_FRAG_HEAD)) - return tfp; - else - goto mov_tail; - } - } - return NULL; - -mov_tail: - list_move_tail(&tfp->list, head); - return NULL; -} - -void frag_list_free(struct list_head *head) -{ - struct frag_packet_list_entry *pf, *tmp_pf; - - if (!list_empty(head)) { - - list_for_each_entry_safe(pf, tmp_pf, head, list) { - kfree_skb(pf->skb); - list_del(&pf->list); - kfree(pf); - } - } - return; -} - -/* frag_reassemble_skb(): - * returns NET_RX_DROP if the operation failed - skb is left intact - * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL) - * or the skb could be reassembled (skb_new will point to the new packet and - * skb was freed) - */ -int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct sk_buff **new_skb) -{ - struct orig_node *orig_node; - struct frag_packet_list_entry *tmp_frag_entry; - int ret = NET_RX_DROP; - struct unicast_frag_packet *unicast_packet = - (struct unicast_frag_packet *)skb->data; - - *new_skb = NULL; - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - unicast_packet->orig)); - - if (!orig_node) { - pr_debug("couldn't find originator in orig_hash\n"); - goto out; - } - - orig_node->last_frag_packet = jiffies; - - if (list_empty(&orig_node->frag_list) && - frag_create_buffer(&orig_node->frag_list)) { - pr_debug("couldn't create frag buffer\n"); - goto out; - } - - tmp_frag_entry = frag_search_packet(&orig_node->frag_list, - unicast_packet); - - if (!tmp_frag_entry) { - frag_create_entry(&orig_node->frag_list, skb); - ret = NET_RX_SUCCESS; - goto out; - } - - *new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry, - skb); - /* if not, merge failed */ - if (*new_skb) - ret = NET_RX_SUCCESS; -out: - spin_unlock_bh(&bat_priv->orig_hash_lock); - - return ret; -} - -int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[]) -{ - struct unicast_packet tmp_uc, *unicast_packet; - struct sk_buff *frag_skb; - struct unicast_frag_packet *frag1, *frag2; - int uc_hdr_len = sizeof(struct unicast_packet); - int ucf_hdr_len = sizeof(struct unicast_frag_packet); - int data_len = skb->len; - - if (!bat_priv->primary_if) - goto dropped; - - unicast_packet = (struct unicast_packet *) skb->data; - - memcpy(&tmp_uc, unicast_packet, uc_hdr_len); - frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); - skb_split(skb, frag_skb, data_len / 2); - - if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || - my_skb_head_push(frag_skb, ucf_hdr_len) < 0) - goto drop_frag; - - frag1 = (struct unicast_frag_packet *)skb->data; - frag2 = (struct unicast_frag_packet *)frag_skb->data; - - memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet)); - - frag1->ttl--; - frag1->version = COMPAT_VERSION; - frag1->packet_type = BAT_UNICAST_FRAG; - - memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); - - frag1->flags |= UNI_FRAG_HEAD; - frag2->flags &= ~UNI_FRAG_HEAD; - - frag1->seqno = htons((uint16_t)atomic_inc_return( - &batman_if->frag_seqno)); - frag2->seqno = htons((uint16_t)atomic_inc_return( - &batman_if->frag_seqno)); - - send_skb_packet(skb, batman_if, dstaddr); - send_skb_packet(frag_skb, batman_if, dstaddr); - return NET_RX_SUCCESS; - -drop_frag: - kfree_skb(frag_skb); -dropped: - kfree_skb(skb); - return NET_RX_DROP; -} - -int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) -{ - struct ethhdr *ethhdr = (struct ethhdr *)skb->data; - struct unicast_packet *unicast_packet; - struct orig_node *orig_node; - struct batman_if *batman_if; - struct neigh_node *router; - int data_len = skb->len; - uint8_t dstaddr[6]; - - spin_lock_bh(&bat_priv->orig_hash_lock); - - /* get routing information */ - if (is_multicast_ether_addr(ethhdr->h_dest)) - orig_node = (struct orig_node *)gw_get_selected(bat_priv); - else - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, - choose_orig, - ethhdr->h_dest)); - - /* check for hna host */ - if (!orig_node) - orig_node = transtable_search(bat_priv, ethhdr->h_dest); - - router = find_router(bat_priv, orig_node, NULL); - - if (!router) - goto unlock; - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - - batman_if = router->if_incoming; - memcpy(dstaddr, router->addr, ETH_ALEN); - - spin_unlock_bh(&bat_priv->orig_hash_lock); - - if (batman_if->if_status != IF_ACTIVE) - goto dropped; - - if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) - goto dropped; - - unicast_packet = (struct unicast_packet *)skb->data; - - unicast_packet->version = COMPAT_VERSION; - /* batman packet type: unicast */ - unicast_packet->packet_type = BAT_UNICAST; - /* set unicast ttl */ - unicast_packet->ttl = TTL; - /* copy the destination for faster routing */ - memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); - - if (atomic_read(&bat_priv->fragmentation) && - data_len + sizeof(struct unicast_packet) > - batman_if->net_dev->mtu) { - /* send frag skb decreases ttl */ - unicast_packet->ttl++; - return frag_send_skb(skb, bat_priv, batman_if, - dstaddr); - } - send_skb_packet(skb, batman_if, dstaddr); - return 0; - -unlock: - spin_unlock_bh(&bat_priv->orig_hash_lock); -dropped: - kfree_skb(skb); - return 1; -} diff --git a/drivers/staging/batman-adv/unicast.h b/drivers/staging/batman-adv/unicast.h deleted file mode 100644 index e32b7867a9a4..000000000000 --- a/drivers/staging/batman-adv/unicast.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010 B.A.T.M.A.N. contributors: - * - * Andreas Langer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_UNICAST_H_ -#define _NET_BATMAN_ADV_UNICAST_H_ - -#define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */ -#define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */ - -int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct sk_buff **new_skb); -void frag_list_free(struct list_head *head); -int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); -int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[]); - -#endif /* _NET_BATMAN_ADV_UNICAST_H_ */ diff --git a/drivers/staging/batman-adv/vis.c b/drivers/staging/batman-adv/vis.c deleted file mode 100644 index 957a08624ff8..000000000000 --- a/drivers/staging/batman-adv/vis.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors: - * - * Simon Wunderlich - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#include "main.h" -#include "send.h" -#include "translation-table.h" -#include "vis.h" -#include "soft-interface.h" -#include "hard-interface.h" -#include "hash.h" -#include "originator.h" - -#define MAX_VIS_PACKET_SIZE 1000 - -/* Returns the smallest signed integer in two's complement with the sizeof x */ -#define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u))) - -/* Checks if a sequence number x is a predecessor/successor of y. - * they handle overflows/underflows and can correctly check for a - * predecessor/successor unless the variable sequence number has grown by - * more then 2**(bitwidth(x)-1)-1. - * This means that for a uint8_t with the maximum value 255, it would think: - * - when adding nothing - it is neither a predecessor nor a successor - * - before adding more than 127 to the starting value - it is a predecessor, - * - when adding 128 - it is neither a predecessor nor a successor, - * - after adding more than 127 to the starting value - it is a successor */ -#define seq_before(x, y) ({typeof(x) _dummy = (x - y); \ - _dummy > smallest_signed_int(_dummy); }) -#define seq_after(x, y) seq_before(y, x) - -static void start_vis_timer(struct bat_priv *bat_priv); - -/* free the info */ -static void free_info(struct kref *ref) -{ - struct vis_info *info = container_of(ref, struct vis_info, refcount); - struct bat_priv *bat_priv = info->bat_priv; - struct recvlist_node *entry, *tmp; - - list_del_init(&info->send_list); - spin_lock_bh(&bat_priv->vis_list_lock); - list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { - list_del(&entry->list); - kfree(entry); - } - - spin_unlock_bh(&bat_priv->vis_list_lock); - kfree_skb(info->skb_packet); -} - -/* Compare two vis packets, used by the hashing algorithm */ -static int vis_info_cmp(void *data1, void *data2) -{ - struct vis_info *d1, *d2; - struct vis_packet *p1, *p2; - d1 = data1; - d2 = data2; - p1 = (struct vis_packet *)d1->skb_packet->data; - p2 = (struct vis_packet *)d2->skb_packet->data; - return compare_orig(p1->vis_orig, p2->vis_orig); -} - -/* hash function to choose an entry in a hash table of given size */ -/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ -static int vis_info_choose(void *data, int size) -{ - struct vis_info *vis_info = data; - struct vis_packet *packet; - unsigned char *key; - uint32_t hash = 0; - size_t i; - - packet = (struct vis_packet *)vis_info->skb_packet->data; - key = packet->vis_orig; - for (i = 0; i < ETH_ALEN; i++) { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - - return hash % size; -} - -/* insert interface to the list of interfaces of one originator, if it - * does not already exist in the list */ -static void vis_data_insert_interface(const uint8_t *interface, - struct hlist_head *if_list, - bool primary) -{ - struct if_list_entry *entry; - struct hlist_node *pos; - - hlist_for_each_entry(entry, pos, if_list, list) { - if (compare_orig(entry->addr, (void *)interface)) - return; - } - - /* its a new address, add it to the list */ - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) - return; - memcpy(entry->addr, interface, ETH_ALEN); - entry->primary = primary; - hlist_add_head(&entry->list, if_list); -} - -static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list) -{ - struct if_list_entry *entry; - struct hlist_node *pos; - size_t len = 0; - - hlist_for_each_entry(entry, pos, if_list, list) { - if (entry->primary) - len += sprintf(buff + len, "PRIMARY, "); - else - len += sprintf(buff + len, "SEC %pM, ", entry->addr); - } - - return len; -} - -static size_t vis_data_count_prim_sec(struct hlist_head *if_list) -{ - struct if_list_entry *entry; - struct hlist_node *pos; - size_t count = 0; - - hlist_for_each_entry(entry, pos, if_list, list) { - if (entry->primary) - count += 9; - else - count += 23; - } - - return count; -} - -/* read an entry */ -static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, - uint8_t *src, bool primary) -{ - /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ - if (primary && entry->quality == 0) - return sprintf(buff, "HNA %pM, ", entry->dest); - else if (compare_orig(entry->src, src)) - return sprintf(buff, "TQ %pM %d, ", entry->dest, - entry->quality); - - return 0; -} - -int vis_seq_print_text(struct seq_file *seq, void *offset) -{ - HASHIT(hashit); - HASHIT(hashit_count); - struct element_t *bucket; - struct vis_info *info; - struct vis_packet *packet; - struct vis_info_entry *entries; - struct net_device *net_dev = (struct net_device *)seq->private; - struct bat_priv *bat_priv = netdev_priv(net_dev); - HLIST_HEAD(vis_if_list); - struct if_list_entry *entry; - struct hlist_node *pos, *n; - int i; - int vis_server = atomic_read(&bat_priv->vis_mode); - size_t buff_pos, buf_size; - char *buff; - - if ((!bat_priv->primary_if) || - (vis_server == VIS_TYPE_CLIENT_UPDATE)) - return 0; - - buf_size = 1; - /* Estimate length */ - spin_lock_bh(&bat_priv->vis_hash_lock); - while (hash_iterate(bat_priv->vis_hash, &hashit_count)) { - bucket = hlist_entry(hashit_count.walk, struct element_t, - hlist); - info = bucket->data; - packet = (struct vis_packet *)info->skb_packet->data; - entries = (struct vis_info_entry *) - ((char *)packet + sizeof(struct vis_packet)); - - for (i = 0; i < packet->entries; i++) { - if (entries[i].quality == 0) - continue; - vis_data_insert_interface(entries[i].src, &vis_if_list, - compare_orig(entries[i].src, packet->vis_orig)); - } - - hlist_for_each_entry(entry, pos, &vis_if_list, list) { - buf_size += 18 + 26 * packet->entries; - - /* add primary/secondary records */ - if (compare_orig(entry->addr, packet->vis_orig)) - buf_size += - vis_data_count_prim_sec(&vis_if_list); - - buf_size += 1; - } - - hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) { - hlist_del(&entry->list); - kfree(entry); - } - } - - buff = kmalloc(buf_size, GFP_ATOMIC); - if (!buff) { - spin_unlock_bh(&bat_priv->vis_hash_lock); - return -ENOMEM; - } - buff[0] = '\0'; - buff_pos = 0; - - while (hash_iterate(bat_priv->vis_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - info = bucket->data; - packet = (struct vis_packet *)info->skb_packet->data; - entries = (struct vis_info_entry *) - ((char *)packet + sizeof(struct vis_packet)); - - for (i = 0; i < packet->entries; i++) { - if (entries[i].quality == 0) - continue; - vis_data_insert_interface(entries[i].src, &vis_if_list, - compare_orig(entries[i].src, packet->vis_orig)); - } - - hlist_for_each_entry(entry, pos, &vis_if_list, list) { - buff_pos += sprintf(buff + buff_pos, "%pM,", - entry->addr); - - for (i = 0; i < packet->entries; i++) - buff_pos += vis_data_read_entry(buff + buff_pos, - &entries[i], - entry->addr, - entry->primary); - - /* add primary/secondary records */ - if (compare_orig(entry->addr, packet->vis_orig)) - buff_pos += - vis_data_read_prim_sec(buff + buff_pos, - &vis_if_list); - - buff_pos += sprintf(buff + buff_pos, "\n"); - } - - hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) { - hlist_del(&entry->list); - kfree(entry); - } - } - - spin_unlock_bh(&bat_priv->vis_hash_lock); - - seq_printf(seq, "%s", buff); - kfree(buff); - - return 0; -} - -/* add the info packet to the send list, if it was not - * already linked in. */ -static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info) -{ - if (list_empty(&info->send_list)) { - kref_get(&info->refcount); - list_add_tail(&info->send_list, &bat_priv->vis_send_list); - } -} - -/* delete the info packet from the send list, if it was - * linked in. */ -static void send_list_del(struct vis_info *info) -{ - if (!list_empty(&info->send_list)) { - list_del_init(&info->send_list); - kref_put(&info->refcount, free_info); - } -} - -/* tries to add one entry to the receive list. */ -static void recv_list_add(struct bat_priv *bat_priv, - struct list_head *recv_list, char *mac) -{ - struct recvlist_node *entry; - - entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); - if (!entry) - return; - - memcpy(entry->mac, mac, ETH_ALEN); - spin_lock_bh(&bat_priv->vis_list_lock); - list_add_tail(&entry->list, recv_list); - spin_unlock_bh(&bat_priv->vis_list_lock); -} - -/* returns 1 if this mac is in the recv_list */ -static int recv_list_is_in(struct bat_priv *bat_priv, - struct list_head *recv_list, char *mac) -{ - struct recvlist_node *entry; - - spin_lock_bh(&bat_priv->vis_list_lock); - list_for_each_entry(entry, recv_list, list) { - if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { - spin_unlock_bh(&bat_priv->vis_list_lock); - return 1; - } - } - spin_unlock_bh(&bat_priv->vis_list_lock); - return 0; -} - -/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, - * broken.. ). vis hash must be locked outside. is_new is set when the packet - * is newer than old entries in the hash. */ -static struct vis_info *add_packet(struct bat_priv *bat_priv, - struct vis_packet *vis_packet, - int vis_info_len, int *is_new, - int make_broadcast) -{ - struct vis_info *info, *old_info; - struct vis_packet *search_packet, *old_packet; - struct vis_info search_elem; - struct vis_packet *packet; - int hash_added; - - *is_new = 0; - /* sanity check */ - if (!bat_priv->vis_hash) - return NULL; - - /* see if the packet is already in vis_hash */ - search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet)); - if (!search_elem.skb_packet) - return NULL; - search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet, - sizeof(struct vis_packet)); - - memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); - old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - &search_elem); - kfree_skb(search_elem.skb_packet); - - if (old_info != NULL) { - old_packet = (struct vis_packet *)old_info->skb_packet->data; - if (!seq_after(ntohl(vis_packet->seqno), - ntohl(old_packet->seqno))) { - if (old_packet->seqno == vis_packet->seqno) { - recv_list_add(bat_priv, &old_info->recv_list, - vis_packet->sender_orig); - return old_info; - } else { - /* newer packet is already in hash. */ - return NULL; - } - } - /* remove old entry */ - hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - old_info); - send_list_del(old_info); - kref_put(&old_info->refcount, free_info); - } - - info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC); - if (!info) - return NULL; - - info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) + - vis_info_len + sizeof(struct ethhdr)); - if (!info->skb_packet) { - kfree(info); - return NULL; - } - skb_reserve(info->skb_packet, sizeof(struct ethhdr)); - packet = (struct vis_packet *)skb_put(info->skb_packet, - sizeof(struct vis_packet) + - vis_info_len); - - kref_init(&info->refcount); - INIT_LIST_HEAD(&info->send_list); - INIT_LIST_HEAD(&info->recv_list); - info->first_seen = jiffies; - info->bat_priv = bat_priv; - memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len); - - /* initialize and add new packet. */ - *is_new = 1; - - /* Make it a broadcast packet, if required */ - if (make_broadcast) - memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); - - /* repair if entries is longer than packet. */ - if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len) - packet->entries = vis_info_len / sizeof(struct vis_info_entry); - - recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); - - /* try to add it */ - hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - info); - if (hash_added < 0) { - /* did not work (for some reason) */ - kref_put(&old_info->refcount, free_info); - info = NULL; - } - - return info; -} - -/* handle the server sync packet, forward if needed. */ -void receive_server_sync_packet(struct bat_priv *bat_priv, - struct vis_packet *vis_packet, - int vis_info_len) -{ - struct vis_info *info; - int is_new, make_broadcast; - int vis_server = atomic_read(&bat_priv->vis_mode); - - make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC); - - spin_lock_bh(&bat_priv->vis_hash_lock); - info = add_packet(bat_priv, vis_packet, vis_info_len, - &is_new, make_broadcast); - if (!info) - goto end; - - /* only if we are server ourselves and packet is newer than the one in - * hash.*/ - if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) - send_list_add(bat_priv, info); -end: - spin_unlock_bh(&bat_priv->vis_hash_lock); -} - -/* handle an incoming client update packet and schedule forward if needed. */ -void receive_client_update_packet(struct bat_priv *bat_priv, - struct vis_packet *vis_packet, - int vis_info_len) -{ - struct vis_info *info; - struct vis_packet *packet; - int is_new; - int vis_server = atomic_read(&bat_priv->vis_mode); - int are_target = 0; - - /* clients shall not broadcast. */ - if (is_broadcast_ether_addr(vis_packet->target_orig)) - return; - - /* Are we the target for this VIS packet? */ - if (vis_server == VIS_TYPE_SERVER_SYNC && - is_my_mac(vis_packet->target_orig)) - are_target = 1; - - spin_lock_bh(&bat_priv->vis_hash_lock); - info = add_packet(bat_priv, vis_packet, vis_info_len, - &is_new, are_target); - - if (!info) - goto end; - /* note that outdated packets will be dropped at this point. */ - - packet = (struct vis_packet *)info->skb_packet->data; - - /* send only if we're the target server or ... */ - if (are_target && is_new) { - packet->vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */ - send_list_add(bat_priv, info); - - /* ... we're not the recipient (and thus need to forward). */ - } else if (!is_my_mac(packet->target_orig)) { - send_list_add(bat_priv, info); - } - -end: - spin_unlock_bh(&bat_priv->vis_hash_lock); -} - -/* Walk the originators and find the VIS server with the best tq. Set the packet - * address to its address and return the best_tq. - * - * Must be called with the originator hash locked */ -static int find_best_vis_server(struct bat_priv *bat_priv, - struct vis_info *info) -{ - HASHIT(hashit); - struct element_t *bucket; - struct orig_node *orig_node; - struct vis_packet *packet; - int best_tq = -1; - - packet = (struct vis_packet *)info->skb_packet->data; - - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - if ((orig_node) && (orig_node->router) && - (orig_node->flags & VIS_SERVER) && - (orig_node->router->tq_avg > best_tq)) { - best_tq = orig_node->router->tq_avg; - memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); - } - } - return best_tq; -} - -/* Return true if the vis packet is full. */ -static bool vis_packet_full(struct vis_info *info) -{ - struct vis_packet *packet; - packet = (struct vis_packet *)info->skb_packet->data; - - if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry) - < packet->entries + 1) - return true; - return false; -} - -/* generates a packet of own vis data, - * returns 0 on success, -1 if no packet could be generated */ -static int generate_vis_packet(struct bat_priv *bat_priv) -{ - HASHIT(hashit_local); - HASHIT(hashit_global); - struct element_t *bucket; - struct orig_node *orig_node; - struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; - struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; - struct vis_info_entry *entry; - struct hna_local_entry *hna_local_entry; - int best_tq = -1; - - info->first_seen = jiffies; - packet->vis_type = atomic_read(&bat_priv->vis_mode); - - spin_lock_bh(&bat_priv->orig_hash_lock); - memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); - packet->ttl = TTL; - packet->seqno = htonl(ntohl(packet->seqno) + 1); - packet->entries = 0; - skb_trim(info->skb_packet, sizeof(struct vis_packet)); - - if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { - best_tq = find_best_vis_server(bat_priv, info); - - if (best_tq < 0) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return -1; - } - } - - while (hash_iterate(bat_priv->orig_hash, &hashit_global)) { - bucket = hlist_entry(hashit_global.walk, struct element_t, - hlist); - orig_node = bucket->data; - - if (!orig_node->router) - continue; - - if (!compare_orig(orig_node->router->addr, orig_node->orig)) - continue; - - if (orig_node->router->if_incoming->if_status != IF_ACTIVE) - continue; - - if (orig_node->router->tq_avg < 1) - continue; - - /* fill one entry into buffer. */ - entry = (struct vis_info_entry *) - skb_put(info->skb_packet, sizeof(*entry)); - memcpy(entry->src, - orig_node->router->if_incoming->net_dev->dev_addr, - ETH_ALEN); - memcpy(entry->dest, orig_node->orig, ETH_ALEN); - entry->quality = orig_node->router->tq_avg; - packet->entries++; - - if (vis_packet_full(info)) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return 0; - } - } - - spin_unlock_bh(&bat_priv->orig_hash_lock); - - spin_lock_bh(&bat_priv->hna_lhash_lock); - while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) { - bucket = hlist_entry(hashit_local.walk, struct element_t, - hlist); - hna_local_entry = bucket->data; - entry = (struct vis_info_entry *)skb_put(info->skb_packet, - sizeof(*entry)); - memset(entry->src, 0, ETH_ALEN); - memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN); - entry->quality = 0; /* 0 means HNA */ - packet->entries++; - - if (vis_packet_full(info)) { - spin_unlock_bh(&bat_priv->hna_lhash_lock); - return 0; - } - } - - spin_unlock_bh(&bat_priv->hna_lhash_lock); - return 0; -} - -/* free old vis packets. Must be called with this vis_hash_lock - * held */ -static void purge_vis_packets(struct bat_priv *bat_priv) -{ - HASHIT(hashit); - struct element_t *bucket; - struct vis_info *info; - - while (hash_iterate(bat_priv->vis_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - info = bucket->data; - - /* never purge own data. */ - if (info == bat_priv->my_vis_info) - continue; - - if (time_after(jiffies, - info->first_seen + VIS_TIMEOUT * HZ)) { - hash_remove_bucket(bat_priv->vis_hash, &hashit); - send_list_del(info); - kref_put(&info->refcount, free_info); - } - } -} - -static void broadcast_vis_packet(struct bat_priv *bat_priv, - struct vis_info *info) -{ - HASHIT(hashit); - struct element_t *bucket; - struct orig_node *orig_node; - struct vis_packet *packet; - struct sk_buff *skb; - struct batman_if *batman_if; - uint8_t dstaddr[ETH_ALEN]; - - - spin_lock_bh(&bat_priv->orig_hash_lock); - packet = (struct vis_packet *)info->skb_packet->data; - - /* send to all routers in range. */ - while (hash_iterate(bat_priv->orig_hash, &hashit)) { - bucket = hlist_entry(hashit.walk, struct element_t, hlist); - orig_node = bucket->data; - - /* if it's a vis server and reachable, send it. */ - if ((!orig_node) || (!orig_node->router)) - continue; - if (!(orig_node->flags & VIS_SERVER)) - continue; - /* don't send it if we already received the packet from - * this node. */ - if (recv_list_is_in(bat_priv, &info->recv_list, - orig_node->orig)) - continue; - - memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); - - skb = skb_clone(info->skb_packet, GFP_ATOMIC); - if (skb) - send_skb_packet(skb, batman_if, dstaddr); - - spin_lock_bh(&bat_priv->orig_hash_lock); - - } - - spin_unlock_bh(&bat_priv->orig_hash_lock); -} - -static void unicast_vis_packet(struct bat_priv *bat_priv, - struct vis_info *info) -{ - struct orig_node *orig_node; - struct sk_buff *skb; - struct vis_packet *packet; - struct batman_if *batman_if; - uint8_t dstaddr[ETH_ALEN]; - - spin_lock_bh(&bat_priv->orig_hash_lock); - packet = (struct vis_packet *)info->skb_packet->data; - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - packet->target_orig)); - - if ((!orig_node) || (!orig_node->router)) - goto out; - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); - - skb = skb_clone(info->skb_packet, GFP_ATOMIC); - if (skb) - send_skb_packet(skb, batman_if, dstaddr); - - return; - -out: - spin_unlock_bh(&bat_priv->orig_hash_lock); -} - -/* only send one vis packet. called from send_vis_packets() */ -static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) -{ - struct vis_packet *packet; - - packet = (struct vis_packet *)info->skb_packet->data; - if (packet->ttl < 2) { - pr_debug("Error - can't send vis packet: ttl exceeded\n"); - return; - } - - memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, - ETH_ALEN); - packet->ttl--; - - if (is_broadcast_ether_addr(packet->target_orig)) - broadcast_vis_packet(bat_priv, info); - else - unicast_vis_packet(bat_priv, info); - packet->ttl++; /* restore TTL */ -} - -/* called from timer; send (and maybe generate) vis packet. */ -static void send_vis_packets(struct work_struct *work) -{ - struct delayed_work *delayed_work = - container_of(work, struct delayed_work, work); - struct bat_priv *bat_priv = - container_of(delayed_work, struct bat_priv, vis_work); - struct vis_info *info, *temp; - - spin_lock_bh(&bat_priv->vis_hash_lock); - purge_vis_packets(bat_priv); - - if (generate_vis_packet(bat_priv) == 0) { - /* schedule if generation was successful */ - send_list_add(bat_priv, bat_priv->my_vis_info); - } - - list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list, - send_list) { - - kref_get(&info->refcount); - spin_unlock_bh(&bat_priv->vis_hash_lock); - - if (bat_priv->primary_if) - send_vis_packet(bat_priv, info); - - spin_lock_bh(&bat_priv->vis_hash_lock); - send_list_del(info); - kref_put(&info->refcount, free_info); - } - spin_unlock_bh(&bat_priv->vis_hash_lock); - start_vis_timer(bat_priv); -} - -/* init the vis server. this may only be called when if_list is already - * initialized (e.g. bat0 is initialized, interfaces have been added) */ -int vis_init(struct bat_priv *bat_priv) -{ - struct vis_packet *packet; - int hash_added; - - if (bat_priv->vis_hash) - return 1; - - spin_lock_bh(&bat_priv->vis_hash_lock); - - bat_priv->vis_hash = hash_new(256); - if (!bat_priv->vis_hash) { - pr_err("Can't initialize vis_hash\n"); - goto err; - } - - bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC); - if (!bat_priv->my_vis_info) { - pr_err("Can't initialize vis packet\n"); - goto err; - } - - bat_priv->my_vis_info->skb_packet = dev_alloc_skb( - sizeof(struct vis_packet) + - MAX_VIS_PACKET_SIZE + - sizeof(struct ethhdr)); - if (!bat_priv->my_vis_info->skb_packet) - goto free_info; - - skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr)); - packet = (struct vis_packet *)skb_put( - bat_priv->my_vis_info->skb_packet, - sizeof(struct vis_packet)); - - /* prefill the vis info */ - bat_priv->my_vis_info->first_seen = jiffies - - msecs_to_jiffies(VIS_INTERVAL); - INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list); - INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list); - kref_init(&bat_priv->my_vis_info->refcount); - bat_priv->my_vis_info->bat_priv = bat_priv; - packet->version = COMPAT_VERSION; - packet->packet_type = BAT_VIS; - packet->ttl = TTL; - packet->seqno = 0; - packet->entries = 0; - - INIT_LIST_HEAD(&bat_priv->vis_send_list); - - hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - bat_priv->my_vis_info); - if (hash_added < 0) { - pr_err("Can't add own vis packet into hash\n"); - /* not in hash, need to remove it manually. */ - kref_put(&bat_priv->my_vis_info->refcount, free_info); - goto err; - } - - spin_unlock_bh(&bat_priv->vis_hash_lock); - start_vis_timer(bat_priv); - return 1; - -free_info: - kfree(bat_priv->my_vis_info); - bat_priv->my_vis_info = NULL; -err: - spin_unlock_bh(&bat_priv->vis_hash_lock); - vis_quit(bat_priv); - return 0; -} - -/* Decrease the reference count on a hash item info */ -static void free_info_ref(void *data, void *arg) -{ - struct vis_info *info = data; - - send_list_del(info); - kref_put(&info->refcount, free_info); -} - -/* shutdown vis-server */ -void vis_quit(struct bat_priv *bat_priv) -{ - if (!bat_priv->vis_hash) - return; - - cancel_delayed_work_sync(&bat_priv->vis_work); - - spin_lock_bh(&bat_priv->vis_hash_lock); - /* properly remove, kill timers ... */ - hash_delete(bat_priv->vis_hash, free_info_ref, NULL); - bat_priv->vis_hash = NULL; - bat_priv->my_vis_info = NULL; - spin_unlock_bh(&bat_priv->vis_hash_lock); -} - -/* schedule packets for (re)transmission */ -static void start_vis_timer(struct bat_priv *bat_priv) -{ - INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets); - queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work, - msecs_to_jiffies(VIS_INTERVAL)); -} diff --git a/drivers/staging/batman-adv/vis.h b/drivers/staging/batman-adv/vis.h deleted file mode 100644 index 2c3b33089a9b..000000000000 --- a/drivers/staging/batman-adv/vis.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors: - * - * Simon Wunderlich, Marek Lindner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * - */ - -#ifndef _NET_BATMAN_ADV_VIS_H_ -#define _NET_BATMAN_ADV_VIS_H_ - -#define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */ - -int vis_seq_print_text(struct seq_file *seq, void *offset); -void receive_server_sync_packet(struct bat_priv *bat_priv, - struct vis_packet *vis_packet, - int vis_info_len); -void receive_client_update_packet(struct bat_priv *bat_priv, - struct vis_packet *vis_packet, - int vis_info_len); -int vis_init(struct bat_priv *bat_priv); -void vis_quit(struct bat_priv *bat_priv); - -#endif /* _NET_BATMAN_ADV_VIS_H_ */ -- cgit v1.2.3 From a8adbe378b56acd5945df70753c7e8f6fe223304 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Fri, 17 Dec 2010 08:56:44 +0100 Subject: fs/splice: Pull buf->ops->confirm() from splice_from_pipe actors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch pulls calls to buf->ops->confirm() from all actors passed (also indirectly) to splice_from_pipe_feed(). Is avoiding the call to buf->ops->confirm() while splice()ing to /dev/null is an intentional optimization? No other user does that and this will remove this special case. Against current linux.git 6313e3c21743cc88bb5bd8aa72948ee1e83937b6. Signed-off-by: Michał Mirosław Signed-off-by: Jens Axboe --- drivers/block/loop.c | 4 ---- fs/nfsd/vfs.c | 4 ---- fs/splice.c | 43 ++++++++++++++----------------------------- 3 files changed, 14 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 7ea0bea2f7e3..c87b0840d2cb 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -397,10 +397,6 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, sector_t IV; int size, ret; - ret = buf->ops->confirm(pipe, buf); - if (unlikely(ret)) - return ret; - IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + (buf->offset >> 9); size = sd->len; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 184938fcff04..c6e08661adee 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -847,10 +847,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, size_t size; int ret; - ret = buf->ops->confirm(pipe, buf); - if (unlikely(ret)) - return ret; - size = sd->len; if (rqstp->rq_res.page_len == 0) { diff --git a/fs/splice.c b/fs/splice.c index 8f1dfaecc8f0..d2026382ac3e 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -682,19 +682,14 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe, { struct file *file = sd->u.file; loff_t pos = sd->pos; - int ret, more; - - ret = buf->ops->confirm(pipe, buf); - if (!ret) { - more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; - if (file->f_op && file->f_op->sendpage) - ret = file->f_op->sendpage(file, buf->page, buf->offset, - sd->len, &pos, more); - else - ret = -EINVAL; - } + int more; - return ret; + if (!likely(file->f_op && file->f_op->sendpage)) + return -EINVAL; + + more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; + return file->f_op->sendpage(file, buf->page, buf->offset, + sd->len, &pos, more); } /* @@ -727,13 +722,6 @@ int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, void *fsdata; int ret; - /* - * make sure the data in this buffer is uptodate - */ - ret = buf->ops->confirm(pipe, buf); - if (unlikely(ret)) - return ret; - offset = sd->pos & ~PAGE_CACHE_MASK; this_len = sd->len; @@ -805,12 +793,17 @@ int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, if (sd->len > sd->total_len) sd->len = sd->total_len; - ret = actor(pipe, buf, sd); - if (ret <= 0) { + ret = buf->ops->confirm(pipe, buf); + if (unlikely(ret)) { if (ret == -ENODATA) ret = 0; return ret; } + + ret = actor(pipe, buf, sd); + if (ret <= 0) + return ret; + buf->offset += ret; buf->len -= ret; @@ -1044,10 +1037,6 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, int ret; void *data; - ret = buf->ops->confirm(pipe, buf); - if (ret) - return ret; - data = buf->ops->map(pipe, buf, 0); ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos); buf->ops->unmap(pipe, buf, data); @@ -1507,10 +1496,6 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, char *src; int ret; - ret = buf->ops->confirm(pipe, buf); - if (unlikely(ret)) - return ret; - /* * See if we can use the atomic maps, by prefaulting in the * pages and doing an atomic copy -- cgit v1.2.3 From 9c3d2f7ffac34c62fea0b73e607707168a6f09b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Dec 2010 10:54:26 +0000 Subject: drm/i915: Enable EI mode for RCx decision making on Sandybridge And no I have no idea what the difference is either, just that is the recommendation. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fe6538297872..c79bee4b4d56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6141,6 +6141,7 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_RC6p_ENABLE | GEN6_RC_CTL_RC6_ENABLE | + GEN6_RC_CTL_EI_MODE(1) | GEN6_RC_CTL_HW_ENABLE); I915_WRITE(GEN6_RC_NORMAL_FREQ, -- cgit v1.2.3 From 3b8d8d91d51c7d15cda51052624169edf7b6dbc6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 17 Dec 2010 14:19:02 -0800 Subject: drm/i915: dynamic render p-state support for Sandy Bridge Add an interrupt handler for switching graphics frequencies and handling PM interrupts. This should allow for increased performance when busy and lower power consumption when idle. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 54 ++++++++++++++++++++++++++++++------ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 47 +++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_reg.h | 8 +++++- drivers/gpu/drm/i915/i915_suspend.c | 9 ++++-- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 7 files changed, 137 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 864e75d762e6..92f75782c332 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -797,15 +797,51 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u16 rgvswctl = I915_READ16(MEMSWCTL); - u16 rgvstat = I915_READ16(MEMSTAT_ILK); - - seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); - seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); - seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> - MEMSTAT_VID_SHIFT); - seq_printf(m, "Current P-state: %d\n", - (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); + + if (IS_GEN5(dev)) { + u16 rgvswctl = I915_READ16(MEMSWCTL); + u16 rgvstat = I915_READ16(MEMSTAT_ILK); + + seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); + seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); + seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> + MEMSTAT_VID_SHIFT); + seq_printf(m, "Current P-state: %d\n", + (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); + } else if (IS_GEN6(dev)) { + u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); + u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); + u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + int max_freq; + + /* RPSTAT1 is in the GT power well */ + __gen6_force_wake_get(dev_priv); + + seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); + seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1)); + seq_printf(m, "Render p-state ratio: %d\n", + (gt_perf_status & 0xff00) >> 8); + seq_printf(m, "Render p-state VID: %d\n", + gt_perf_status & 0xff); + seq_printf(m, "Render p-state limit: %d\n", + rp_state_limits & 0xff); + + max_freq = (rp_state_cap & 0xff0000) >> 16; + seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", + max_freq * 100); + + max_freq = (rp_state_cap & 0xff00) >> 8; + seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", + max_freq * 100); + + max_freq = rp_state_cap & 0xff; + seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", + max_freq * 100); + + __gen6_force_wake_put(dev_priv); + } else { + seq_printf(m, "no P-state info available\n"); + } return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 53dfc8398a96..2a653cc80395 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1264,6 +1264,7 @@ extern void intel_disable_fbc(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern bool intel_fbc_enabled(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); +extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index adf983f01dda..0dadc025b77b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -397,11 +397,49 @@ static void notify_ring(struct drm_device *dev, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } +static void gen6_pm_irq_handler(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u8 new_delay = dev_priv->cur_delay; + u32 pm_iir; + + pm_iir = I915_READ(GEN6_PMIIR); + if (!pm_iir) + return; + + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { + if (dev_priv->cur_delay != dev_priv->max_delay) + new_delay = dev_priv->cur_delay + 1; + if (new_delay > dev_priv->max_delay) + new_delay = dev_priv->max_delay; + } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) { + if (dev_priv->cur_delay != dev_priv->min_delay) + new_delay = dev_priv->cur_delay - 1; + if (new_delay < dev_priv->min_delay) { + new_delay = dev_priv->min_delay; + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + I915_READ(GEN6_RP_INTERRUPT_LIMITS) | + ((new_delay << 16) & 0x3f0000)); + } else { + /* Make sure we continue to get down interrupts + * until we hit the minimum frequency */ + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000); + } + + } + + gen6_set_rps(dev, new_delay); + dev_priv->cur_delay = new_delay; + + I915_WRITE(GEN6_PMIIR, pm_iir); +} + static irqreturn_t ironlake_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; - u32 de_iir, gt_iir, de_ier, pch_iir; + u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; u32 hotplug_mask; struct drm_i915_master_private *master_priv; u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT; @@ -417,8 +455,10 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); pch_iir = I915_READ(SDEIIR); + pm_iir = I915_READ(GEN6_PMIIR); - if (de_iir == 0 && gt_iir == 0 && pch_iir == 0) + if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && + (!IS_GEN6(dev) || pm_iir == 0)) goto done; if (HAS_PCH_CPT(dev)) @@ -470,6 +510,9 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) i915_handle_rps_change(dev); } + if (IS_GEN6(dev)) + gen6_pm_irq_handler(dev); + /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c2231f7d2d97..d60860ec8cf4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1188,6 +1188,10 @@ #define DDRMPLL1 0X12c20 #define PEG_BAND_GAP_DATA 0x14d68 +#define GEN6_GT_PERF_STATUS 0x145948 +#define GEN6_RP_STATE_LIMITS 0x145994 +#define GEN6_RP_STATE_CAP 0x145998 + /* * Logical Context regs */ @@ -3169,7 +3173,7 @@ #define FORCEWAKE 0xA18C #define FORCEWAKE_ACK 0x130090 -#define GEN6_RC_NORMAL_FREQ 0xA008 +#define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) #define GEN6_OFFSET(x) ((x)<<19) @@ -3185,6 +3189,7 @@ #define GEN6_RC_CTL_HW_ENABLE (1<<31) #define GEN6_RP_DOWN_TIMEOUT 0xA010 #define GEN6_RP_INTERRUPT_LIMITS 0xA014 +#define GEN6_RPSTAT1 0xA01C #define GEN6_RP_CONTROL 0xA024 #define GEN6_RP_MEDIA_TURBO (1<<11) #define GEN6_RP_USE_NORMAL_FREQ (1<<9) @@ -3208,6 +3213,7 @@ #define GEN6_RC6_THRESHOLD 0xA0B8 #define GEN6_RC6p_THRESHOLD 0xA0BC #define GEN6_RC6pp_THRESHOLD 0xA0C0 +#define GEN6_PMINTRMSK 0xA168 #define GEN6_PMISR 0x44020 #define GEN6_PMIMR 0x44024 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index a311809f3c80..f623efdb1151 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -817,8 +817,10 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveIMR = I915_READ(IMR); } - if (HAS_PCH_SPLIT(dev)) + if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); + if (IS_GEN6(dev)) + gen6_disable_rps(dev); intel_disable_clock_gating(dev); @@ -867,11 +869,14 @@ int i915_restore_state(struct drm_device *dev) /* Clock gating state */ intel_enable_clock_gating(dev); - if (HAS_PCH_SPLIT(dev)) { + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); intel_init_emon(dev); } + if (IS_GEN6(dev)) + gen6_enable_rps(dev_priv); + /* Cache mode state */ I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c79bee4b4d56..880659680d0a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6021,6 +6021,25 @@ void ironlake_disable_drps(struct drm_device *dev) } +void gen6_set_rps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 swreq; + + swreq = (val & 0x3ff) << 25; + I915_WRITE(GEN6_RPNSWREQ, swreq); +} + +void gen6_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_RPNSWREQ, 1 << 31); + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + I915_WRITE(GEN6_PMIER, 0); + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); +} + static unsigned long intel_pxfreq(u32 vidfreq) { unsigned long freq; @@ -6107,7 +6126,7 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } -static void gen6_enable_rc6(struct drm_i915_private *dev_priv) +void gen6_enable_rps(struct drm_i915_private *dev_priv) { int i; @@ -6120,7 +6139,7 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RC_STATE, 0); __gen6_force_wake_get(dev_priv); - /* disable the counters and set determistic thresholds */ + /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); @@ -6144,7 +6163,7 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv) GEN6_RC_CTL_EI_MODE(1) | GEN6_RC_CTL_HW_ENABLE); - I915_WRITE(GEN6_RC_NORMAL_FREQ, + I915_WRITE(GEN6_RPNSWREQ, GEN6_FREQUENCY(10) | GEN6_OFFSET(0) | GEN6_AGGRESSIVE_TURBO); @@ -6189,6 +6208,9 @@ static void gen6_enable_rc6(struct drm_i915_private *dev_priv) GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_DOWN_EI_EXPIRED); + I915_WRITE(GEN6_PMIMR, 0); + /* enable all PM interrupts */ + I915_WRITE(GEN6_PMINTRMSK, 0); __gen6_force_wake_put(dev_priv); } @@ -6381,9 +6403,6 @@ void intel_enable_clock_gating(struct drm_device *dev) I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); } } - - if (IS_GEN6(dev)) - gen6_enable_rc6(dev_priv); } void intel_disable_clock_gating(struct drm_device *dev) @@ -6657,6 +6676,9 @@ void intel_modeset_init(struct drm_device *dev) intel_init_emon(dev); } + if (IS_GEN6(dev)) + gen6_enable_rps(dev_priv); + INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); @@ -6690,6 +6712,8 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); + if (IS_GEN6(dev)) + gen6_disable_rps(dev); intel_disable_clock_gating(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index acdea6549ec4..d782ad9fd6db 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -298,6 +298,8 @@ extern void intel_enable_clock_gating(struct drm_device *dev); extern void intel_disable_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); +extern void gen6_enable_rps(struct drm_i915_private *dev_priv); +extern void gen6_disable_rps(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev); extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, -- cgit v1.2.3 From 18bb36f9fab5980efeff063755c037a622f0231c Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Wed, 8 Dec 2010 04:22:57 +0200 Subject: firewire: net: add carrier detection To make userland, e.g. NetworkManager work with firewire, we need to detect whether cable is plugged or not. Simple and correct way of doing that is just counting number of peers. No peers - no link and vice versa. Signed-off-by: Stefan Richter --- drivers/firewire/net.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index ea31e3084d67..7fd51c9e243d 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -178,6 +178,7 @@ struct fwnet_device { /* Number of tx datagrams that have been queued but not yet acked */ int queued_datagrams; + int peer_count; struct list_head peer_list; struct fw_card *card; @@ -1405,6 +1406,10 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu) return 0; } +static const struct ethtool_ops fwnet_ethtool_ops = { + .get_link = ethtool_op_get_link, +}; + static const struct net_device_ops fwnet_netdev_ops = { .ndo_open = fwnet_open, .ndo_stop = fwnet_stop, @@ -1423,6 +1428,8 @@ static void fwnet_init_dev(struct net_device *net) net->hard_header_len = FWNET_HLEN; net->type = ARPHRD_IEEE1394; net->tx_queue_len = FWNET_TX_QUEUE_LEN; + net->ethtool_ops = &fwnet_ethtool_ops; + } /* caller must hold fwnet_device_mutex */ @@ -1463,6 +1470,7 @@ static int fwnet_add_peer(struct fwnet_device *dev, spin_lock_irq(&dev->lock); list_add_tail(&peer->peer_link, &dev->peer_list); + dev->peer_count++; spin_unlock_irq(&dev->lock); return 0; @@ -1534,6 +1542,9 @@ static int fwnet_probe(struct device *_dev) unregister_netdev(net); list_del(&dev->dev_link); } + + if (dev->peer_count > 1) + netif_carrier_on(net); out: if (ret && allocated_netdev) free_netdev(net); @@ -1549,6 +1560,7 @@ static void fwnet_remove_peer(struct fwnet_peer *peer) spin_lock_irq(&peer->dev->lock); list_del(&peer->peer_link); + peer->dev->peer_count--; spin_unlock_irq(&peer->dev->lock); list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link) @@ -1568,6 +1580,11 @@ static int fwnet_remove(struct device *_dev) fwnet_remove_peer(peer); + /* If we serve just one node, that means we lost link + with outer world */ + if (dev->peer_count == 1) + netif_carrier_off(dev->netdev); + if (list_empty(&dev->peer_list)) { net = dev->netdev; unregister_netdev(net); -- cgit v1.2.3 From c16714704bb35165e5b85d927873dcc643772648 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 17 Dec 2010 22:22:33 +0100 Subject: firewire: net: set carrier state at ifup At ifup, carrier status would be shown on even if it actually was off. Also add an include for ethtool_ops rather than to rely on the one from netdevice.h. Note, we can alas not use fwnet_device_mutex to serialize access to dev->peer_count (as I originally wanted). This would cause a lock inversion: - fwnet_probe | takes fwnet_device_mutex + register_netdev | takes rtnl_mutex - devinet_ioctl | takes rtnl_mutex + fwnet_open | ...must not take fwnet_device_mutex Hence use the dev->lock spinlock for serialization. Signed-off-by: Stefan Richter --- drivers/firewire/net.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 7fd51c9e243d..c2e194c58667 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -178,8 +179,8 @@ struct fwnet_device { /* Number of tx datagrams that have been queued but not yet acked */ int queued_datagrams; - int peer_count; + int peer_count; struct list_head peer_list; struct fw_card *card; struct net_device *netdev; @@ -1222,6 +1223,14 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) return retval; } +static void set_carrier_state(struct fwnet_device *dev) +{ + if (dev->peer_count > 1) + netif_carrier_on(dev->netdev); + else + netif_carrier_off(dev->netdev); +} + /* ifup */ static int fwnet_open(struct net_device *net) { @@ -1235,6 +1244,10 @@ static int fwnet_open(struct net_device *net) } netif_start_queue(net); + spin_lock_irq(&dev->lock); + set_carrier_state(dev); + spin_unlock_irq(&dev->lock); + return 0; } @@ -1429,7 +1442,6 @@ static void fwnet_init_dev(struct net_device *net) net->type = ARPHRD_IEEE1394; net->tx_queue_len = FWNET_TX_QUEUE_LEN; net->ethtool_ops = &fwnet_ethtool_ops; - } /* caller must hold fwnet_device_mutex */ @@ -1471,6 +1483,7 @@ static int fwnet_add_peer(struct fwnet_device *dev, spin_lock_irq(&dev->lock); list_add_tail(&peer->peer_link, &dev->peer_list); dev->peer_count++; + set_carrier_state(dev); spin_unlock_irq(&dev->lock); return 0; @@ -1542,9 +1555,6 @@ static int fwnet_probe(struct device *_dev) unregister_netdev(net); list_del(&dev->dev_link); } - - if (dev->peer_count > 1) - netif_carrier_on(net); out: if (ret && allocated_netdev) free_netdev(net); @@ -1554,14 +1564,15 @@ static int fwnet_probe(struct device *_dev) return ret; } -static void fwnet_remove_peer(struct fwnet_peer *peer) +static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev) { struct fwnet_partial_datagram *pd, *pd_next; - spin_lock_irq(&peer->dev->lock); + spin_lock_irq(&dev->lock); list_del(&peer->peer_link); - peer->dev->peer_count--; - spin_unlock_irq(&peer->dev->lock); + dev->peer_count--; + set_carrier_state(dev); + spin_unlock_irq(&dev->lock); list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link) fwnet_pd_delete(pd); @@ -1578,12 +1589,7 @@ static int fwnet_remove(struct device *_dev) mutex_lock(&fwnet_device_mutex); - fwnet_remove_peer(peer); - - /* If we serve just one node, that means we lost link - with outer world */ - if (dev->peer_count == 1) - netif_carrier_off(dev->netdev); + fwnet_remove_peer(peer, dev); if (list_empty(&dev->peer_list)) { net = dev->netdev; -- cgit v1.2.3 From 3603b8eaccc8e41d3f355b3cadd662a3dd6699fd Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 20 Dec 2010 09:15:19 +0100 Subject: Fix compile warnings due to missing removal of a 'ret' variable Commit a8adbe3 forgot to remove the return variable, kill it. drivers/block/loop.c: In function 'lo_splice_actor': drivers/block/loop.c:398: warning: unused variable 'ret' [...] fs/nfsd/vfs.c: In function 'nfsd_splice_actor': fs/nfsd/vfs.c:848: warning: unused variable 'ret' Reported-by: Stephen Rothwell Signed-off-by: Jens Axboe --- drivers/block/loop.c | 2 +- fs/nfsd/vfs.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c87b0840d2cb..44e18c073c44 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -395,7 +395,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct loop_device *lo = p->lo; struct page *page = buf->page; sector_t IV; - int size, ret; + int size; IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + (buf->offset >> 9); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c6e08661adee..106ed482f119 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -845,7 +845,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct page **pp = rqstp->rq_respages + rqstp->rq_resused; struct page *page = buf->page; size_t size; - int ret; size = sd->len; -- cgit v1.2.3 From 72bfa19c8deb4d1db5ad068c34fd580cb295cbe8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 19 Dec 2010 11:42:05 +0000 Subject: drm/i915: Allow the application to choose the constant addressing mode The relative-to-general state default is useless as it means having to rewrite the streaming kernels for each batch. Relative-to-surface is more useful, as that stream usually needs to be rewritten for each batch. And absolute addressing mode, vital if you start streaming state, is also only available by adjusting the register... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 35 +++++++++++++++++++++++++++++- include/drm/i915_drm.h | 12 ++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3f7b20392e26..18746e6cb129 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -778,6 +778,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_COHERENT_RINGS: value = 1; break; + case I915_PARAM_HAS_EXEC_CONSTANTS: + value = INTEL_INFO(dev)->gen >= 4; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2a653cc80395..aac1bf332f75 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -258,6 +258,7 @@ typedef struct drm_i915_private { const struct intel_device_info *info; int has_gem; + int relative_constants_mode; void __iomem *regs; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5a0fbe59dd5b..c79c0b62ef60 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3735,6 +3735,8 @@ i915_gem_load(struct drm_device *dev) } } + dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL; + /* Old X drivers will take 0-2 for front, back, depth buffers */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index fda0dc858a1f..61129e6759eb 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -957,7 +957,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct intel_ring_buffer *ring; u32 exec_start, exec_len; u32 seqno; - int ret, i; + int ret, mode, i; if (!i915_gem_check_execbuffer(args)) { DRM_ERROR("execbuf with invalid offset/length\n"); @@ -997,6 +997,39 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, return -EINVAL; } + mode = args->flags & I915_EXEC_CONSTANTS_MASK; + switch (mode) { + case I915_EXEC_CONSTANTS_REL_GENERAL: + case I915_EXEC_CONSTANTS_ABSOLUTE: + case I915_EXEC_CONSTANTS_REL_SURFACE: + if (ring == &dev_priv->ring[RCS] && + mode != dev_priv->relative_constants_mode) { + if (INTEL_INFO(dev)->gen < 4) + return -EINVAL; + + if (INTEL_INFO(dev)->gen > 5 && + mode == I915_EXEC_CONSTANTS_REL_SURFACE) + return -EINVAL; + + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; + + intel_ring_emit(ring, MI_NOOP); + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, INSTPM); + intel_ring_emit(ring, + I915_EXEC_CONSTANTS_MASK << 16 | mode); + intel_ring_advance(ring); + + dev_priv->relative_constants_mode = mode; + } + break; + default: + DRM_ERROR("execbuf with unknown constants: %d\n", mode); + return -EINVAL; + } + if (args->buffer_count < 1) { DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); return -EINVAL; diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index a2776e2807a4..0039f1f97ad8 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -289,6 +289,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_BLT 11 #define I915_PARAM_HAS_RELAXED_FENCING 12 #define I915_PARAM_HAS_COHERENT_RINGS 13 +#define I915_PARAM_HAS_EXEC_CONSTANTS 14 typedef struct drm_i915_getparam { int param; @@ -635,6 +636,17 @@ struct drm_i915_gem_execbuffer2 { #define I915_EXEC_RENDER (1<<0) #define I915_EXEC_BSD (2<<0) #define I915_EXEC_BLT (3<<0) + +/* Used for switching the constants addressing mode on gen4+ RENDER ring. + * Gen6+ only supports relative addressing to dynamic state (default) and + * absolute addressing. + * + * These flags are ignored for the BSD and BLT rings. + */ +#define I915_EXEC_CONSTANTS_MASK (3<<6) +#define I915_EXEC_CONSTANTS_REL_GENERAL (0<<6) /* default */ +#define I915_EXEC_CONSTANTS_ABSOLUTE (1<<6) +#define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) /* gen4/5 only */ __u64 flags; __u64 rsvd1; __u64 rsvd2; -- cgit v1.2.3 From 5909a77ac62cc042f94bd262016cf468a2f96022 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Dec 2010 09:45:15 +0000 Subject: drm/i915: Undo "Uncouple render/power ctx before suspending" Manaul revert of 0cdab21f9a1fca50dd27e488839f5a6578e333b2, just to remove the call to disable the clock gatings and powerctx before suspend. Peter Clifton bisected a suspend failure on his gme45 and found this to be the culprit. As this was intended to be a fix for a similar suspend failure for Ironlake (it didn't work), undoing this patch should have no other side-effects. Reported-and-tested-by: Peter Clifton Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_suspend.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index f623efdb1151..410772466fa7 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -822,7 +822,9 @@ int i915_save_state(struct drm_device *dev) if (IS_GEN6(dev)) gen6_disable_rps(dev); + /* XXX disabling the clock gating breaks suspend on gm45 intel_disable_clock_gating(dev); + */ /* Cache mode state */ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); -- cgit v1.2.3 From d095e23206e6291cbde4b2937d1316a42d9e6440 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 20 Dec 2010 12:26:26 +0300 Subject: drm/nouveau: sizeof() vs ARRAY_SIZE() ARRAY_SIZE() was intended here, sizeof() is too large. Signed-off-by: Dan Carpenter Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_vram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c index 47489ed0a5a8..58e98ad36347 100644 --- a/drivers/gpu/drm/nouveau/nv50_vram.c +++ b/drivers/gpu/drm/nouveau/nv50_vram.c @@ -42,7 +42,7 @@ nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags) { int type = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8; - if (likely(type < sizeof(types) && types[type])) + if (likely(type < ARRAY_SIZE(types) && types[type])) return true; return false; } -- cgit v1.2.3 From 910d1b3a8cec4fef20f11eb39e9ec6ac6e964b0e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 21 Dec 2010 11:15:44 +1000 Subject: drm/nv50: fix smatch warning in nv50_vram.c Reported-by: Dan Carpenter Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index eebab95f59b2..7939387f7f80 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -91,7 +91,8 @@ void nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) { - u32 block, i; + u32 block; + int i; phys = nv50_vm_addr(vma, pgt, phys, mem->memtype, 0); pte <<= 3; -- cgit v1.2.3 From 147dc38e976f4dd6d888d585649e724a3e82a9b2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 16 Dec 2010 13:32:36 +1000 Subject: drm/nv50: add missing license header to nv50_fbcon.c Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_fbcon.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 6d38cb1488ae..791ded1c5c6d 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -1,3 +1,27 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + #include "drmP.h" #include "nouveau_drv.h" #include "nouveau_dma.h" -- cgit v1.2.3 From 6a5b3beff916a19e7672f8c0330b4f82ed367be2 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 20 Dec 2010 14:56:09 -0800 Subject: xenbus: Fix memory leak on release Pending responses were leaked on close. Signed-off-by: Daniel De Graaf Signed-off-by: Jan Beulich Signed-off-by: Jeremy Fitzhardinge --- drivers/xen/xenfs/xenbus.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index 55791dd1105f..8f6c7d4b3e4d 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -543,6 +543,7 @@ static int xenbus_file_release(struct inode *inode, struct file *filp) struct xenbus_file_priv *u = filp->private_data; struct xenbus_transaction_holder *trans, *tmp; struct watch_adapter *watch, *tmp_watch; + struct read_buffer *rb, *tmp_rb; /* * No need for locking here because there are no other users, @@ -561,6 +562,10 @@ static int xenbus_file_release(struct inode *inode, struct file *filp) free_watch_adapter(watch); } + list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) { + list_del(&rb->list); + kfree(rb); + } kfree(u); return 0; -- cgit v1.2.3 From 57084d05379fe5c081d024006129b0565a11855f Mon Sep 17 00:00:00 2001 From: James Simmons Date: Mon, 20 Dec 2010 19:10:39 +0000 Subject: drm/fb: Don't expose mmio for fbdev emulation layer For the fbdev api if the struct fb_var_screeninfo accel_flags field is set to FB_ACCELF_TEXT then userland applications can not mmap the mmio region. Since it is a bad idea for DRM drivers to expose the mmio region via the fbdev layer we always set the accel_flags to prevent this. Please apply. Signed-off-by: James Simmons Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 3 +++ drivers/gpu/drm/i915/intel_fb.c | 6 +----- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 ---- drivers/gpu/drm/radeon/radeon_fb.c | 2 -- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 3 --- 5 files changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d2849e4ea4d0..aa377115483b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -985,6 +985,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; info->fix.type_aux = 0; info->fix.xpanstep = 1; /* doing it in hw */ info->fix.ypanstep = 1; /* doing it in hw */ @@ -1005,6 +1007,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; info->var.bits_per_pixel = fb->bits_per_pixel; + info->var.accel_flags = FB_ACCELF_TEXT; info->var.xoffset = 0; info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index af2a1dddc28e..ced3eef8da07 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -68,7 +68,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, struct drm_gem_object *fbo = NULL; struct drm_i915_gem_object *obj_priv; struct device *device = &dev->pdev->dev; - int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0; + int size, ret; /* we don't do packed 24bpp */ if (sizes->surface_bpp == 24) @@ -156,10 +156,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev, drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); - /* FIXME: we really shouldn't expose mmio space at all */ - info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); - info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar); - info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; info->pixmap.access_align = 32; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index ea861c915149..9dbe1eff2ae5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -348,10 +348,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); - /* FIXME: we really shouldn't expose mmio space at all */ - info->fix.mmio_start = pci_resource_start(pdev, 1); - info->fix.mmio_len = pci_resource_len(pdev, 1); - /* Set aperture base/size for vesafb takeover */ info->apertures = dev_priv->apertures; if (!info->apertures) { diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index efa211898fe6..f7b4762fa6b6 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -247,8 +247,6 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; info->apertures->ranges[0].size = rdev->mc.real_vram_size; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; info->pixmap.access_align = 32; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 41d9a5b73c03..dd596f2bd6e8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -480,9 +480,6 @@ int vmw_fb_init(struct vmw_private *vmw_priv) info->fix.smem_start = 0; info->fix.smem_len = fb_size; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; - info->pseudo_palette = par->pseudo_palette; info->screen_base = par->vmalloc; info->screen_size = fb_size; -- cgit v1.2.3 From 21719b398b0e49d21c0b9083cffd552ba28ed4af Mon Sep 17 00:00:00 2001 From: Tijl Coosemans Date: Tue, 21 Dec 2010 12:54:52 +1000 Subject: drm/radeon: Definition of R_0003C2_GENMO_WT seems wrong In drivers/gpu/drm/radeon/r100d.h R_0003C2_GENMO_WT is defined as 0x3C0. I think this should be 0x3C2. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100d.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h index b121b6c678d4..eab91760fae0 100644 --- a/drivers/gpu/drm/radeon/r100d.h +++ b/drivers/gpu/drm/radeon/r100d.h @@ -551,7 +551,7 @@ #define S_000360_CUR2_LOCK(x) (((x) & 0x1) << 31) #define G_000360_CUR2_LOCK(x) (((x) >> 31) & 0x1) #define C_000360_CUR2_LOCK 0x7FFFFFFF -#define R_0003C2_GENMO_WT 0x0003C0 +#define R_0003C2_GENMO_WT 0x0003C2 #define S_0003C2_GENMO_MONO_ADDRESS_B(x) (((x) & 0x1) << 0) #define G_0003C2_GENMO_MONO_ADDRESS_B(x) (((x) >> 0) & 0x1) #define C_0003C2_GENMO_MONO_ADDRESS_B 0xFE -- cgit v1.2.3 From 48c36c8f9a3e881953bb72deb55623a53795a684 Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Sat, 18 Dec 2010 11:41:49 +0100 Subject: drm/radeon/kms: allow r500 US_FORMAT regs in the CS checker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add to the 2.8 bump for pageflip The purpose of these regs is to work around a TX hw bug in R520. Signed-off-by: Marek Olšák Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_drv.c | 2 +- drivers/gpu/drm/radeon/reg_srcs/rv515 | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index a92d2a5cea90..6fb1218f9d76 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -48,7 +48,7 @@ * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs - * 2.8.0 - pageflip support + * 2.8.0 - pageflip support, r500 US_FORMAT regs. */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 8 diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515 index b3f9f1d92005..ef422bbacfc1 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rv515 +++ b/drivers/gpu/drm/radeon/reg_srcs/rv515 @@ -304,6 +304,22 @@ rv515 0x6d40 0x4630 US_CODE_ADDR 0x4634 US_CODE_RANGE 0x4638 US_CODE_OFFSET +0x4640 US_FORMAT0_0 +0x4644 US_FORMAT0_1 +0x4648 US_FORMAT0_2 +0x464C US_FORMAT0_3 +0x4650 US_FORMAT0_4 +0x4654 US_FORMAT0_5 +0x4658 US_FORMAT0_6 +0x465C US_FORMAT0_7 +0x4660 US_FORMAT0_8 +0x4664 US_FORMAT0_9 +0x4668 US_FORMAT0_10 +0x466C US_FORMAT0_11 +0x4670 US_FORMAT0_12 +0x4674 US_FORMAT0_13 +0x4678 US_FORMAT0_14 +0x467C US_FORMAT0_15 0x46A4 US_OUT_FMT_0 0x46A8 US_OUT_FMT_1 0x46AC US_OUT_FMT_2 -- cgit v1.2.3 From b61c99de8e7905916d1508ba7c9a9c08656e169d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 16 Dec 2010 18:40:29 -0500 Subject: drm/radeon/kms: fix DCE4.1 dig routing (v2) Works more like DCE4.0 despite what the docs say. This fixes blank screen issues when changing crtc routing due to incorrect crtc to dig mapping. v2: only two DIGx blocks, routing is hardcoded based on link. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 54 +++++++++++++++----------------- 1 file changed, 25 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index e4e64a80b58d..55b84b8e6b29 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -910,15 +910,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else args.v3.ucLaneNum = 4; - if (ASIC_IS_DCE41(rdev)) { - args.v3.acConfig.ucEncoderSel = dig->dig_encoder; - if (dig->linkb) - args.v3.acConfig.ucLinkSel = 1; - } else { - if (dig->linkb) { - args.v3.acConfig.ucLinkSel = 1; - args.v3.acConfig.ucEncoderSel = 1; - } + if (dig->linkb) { + args.v3.acConfig.ucLinkSel = 1; + args.v3.acConfig.ucEncoderSel = 1; } /* Select the PLL for the PHY @@ -1535,32 +1529,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) struct radeon_encoder_atom_dig *dig; uint32_t dig_enc_in_use = 0; - /* on DCE41 and encoder can driver any phy so just crtc id */ - if (ASIC_IS_DCE41(rdev)) { - return radeon_crtc->crtc_id; - } - if (ASIC_IS_DCE4(rdev)) { dig = radeon_encoder->enc_priv; - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (ASIC_IS_DCE41(rdev)) { if (dig->linkb) return 1; else return 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - if (dig->linkb) - return 3; - else - return 2; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (dig->linkb) - return 5; - else - return 4; - break; + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (dig->linkb) + return 1; + else + return 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + if (dig->linkb) + return 3; + else + return 2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (dig->linkb) + return 5; + else + return 4; + break; + } } } -- cgit v1.2.3 From 7d6aa80c35bb1f706e2894100dcc51e19a83f913 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 20 Dec 2010 11:21:43 -0500 Subject: drm/radeon/kms/atom: clean up op_mask handler Readability cleanup and fix debugging output, no functional change. Reported-by: Frank Huang Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 8e421f644a54..9b0773b75e86 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -733,16 +733,16 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); - uint32_t dst, src1, src2, saved; + uint32_t dst, mask, src, saved; int dptr = *ptr; SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - SDEBUG(" src1: "); - src1 = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); - SDEBUG(" src2: "); - src2 = atom_get_src(ctx, attr, ptr); - dst &= src1; - dst |= src2; + mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); + SDEBUG(" mask: 0x%08x", mask); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst &= mask; + dst |= src; SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } -- cgit v1.2.3 From 3ce05168907c9b1358492a73badb0ff1603fb81d Mon Sep 17 00:00:00 2001 From: David Fries Date: Sun, 12 Dec 2010 12:39:22 -0600 Subject: drm/kms: load fbcon from drm_kms_helper Kconfig says fbcon is required by drm_kms_helper. If radeon, fbcon, and drm_kms_helper are all modules, radeon is auto loaded (by PCI id?), drm_kms_helper is loaded because of the module dependency, but fbcon isn't loaded leaving the console unusable. Since fbcon is required and there isn't an explicit module dependency, request the module to be loaded from drm_kms_helper. Signed-off-by: David Fries Cc: David Airlie Cc: dri-devel@lists.freedesktop.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index aa377115483b..5c4f9b9ecdc0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1533,3 +1533,24 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_hotplug_event); +/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EMBEDDED) + * but the module doesn't depend on any fb console symbols. At least + * attempt to load fbcon to avoid leaving the system without a usable console. + */ +#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EMBEDDED) +static int __init drm_fb_helper_modinit(void) +{ + const char *name = "fbcon"; + struct module *fbcon; + + mutex_lock(&module_mutex); + fbcon = find_module(name); + mutex_unlock(&module_mutex); + + if (!fbcon) + request_module_nowait(name); + return 0; +} + +module_init(drm_fb_helper_modinit); +#endif -- cgit v1.2.3 From 000fa7cf46479238f7b9f2d7763e41af5268b16a Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Fri, 10 Dec 2010 16:00:19 +0100 Subject: drm-vblank: Always return true vblank count of scheduled vblank event. This patch tries to make sure that the vbl.reply.sequence vblank count for a queued or emitted vblank event always corresponds to the true vblank count of queueing/emission, so the ddx can rely on the returned target_msc for consistency checks and implementation of swap_intervals in glXSwapBuffers(). Without this there is a small race-condition between the userspace ddx queueing a vblank event and the vblank counter incrementing before the event gets queued in the kernel. Signed-off-by: Mario Kleiner Acked-by: Jesse Barnes Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_irq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 4e82d0d3c378..55160d7c38b6 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1086,15 +1086,18 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->event.sequence = vblwait->request.sequence; if ((seq - vblwait->request.sequence) <= (1 << 23)) { + e->event.sequence = seq; e->event.tv_sec = now.tv_sec; e->event.tv_usec = now.tv_usec; drm_vblank_put(dev, e->pipe); list_add_tail(&e->base.link, &e->base.file_priv->event_list); wake_up_interruptible(&e->base.file_priv->event_wait); + vblwait->reply.sequence = seq; trace_drm_vblank_event_delivered(current->pid, pipe, vblwait->request.sequence); } else { list_add_tail(&e->base.link, &dev->vblank_event_list); + vblwait->reply.sequence = vblwait->request.sequence; } spin_unlock_irqrestore(&dev->event_lock, flags); -- cgit v1.2.3 From 7a868e18a4907dc8f1f05d99bcb9fd3fa8881ee4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 8 Dec 2010 22:13:05 -0500 Subject: drm/radeon/kms: use LCD physical size from vbios tables if available Some systems have the LCD width and height in mm available in the LCD info table. Use this info if there is no EDID to provide it. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 3 +++ drivers/gpu/drm/radeon/radeon_connectors.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index ac882639b3ed..35c5ff09040d 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1500,6 +1500,9 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct if (misc & ATOM_DOUBLE_CLOCK_MODE) lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN; + lvds->native_mode.width_mm = lvds_info->info.sLCDTiming.usImageHSize; + lvds->native_mode.height_mm = lvds_info->info.sLCDTiming.usImageVSize; + /* set crtc values */ drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3bef9f6d66fd..f3ba066ded20 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -472,6 +472,9 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) if (mode) { ret = 1; drm_mode_probed_add(connector, mode); + /* add the width/height from vbios tables if available */ + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; /* add scaled modes */ radeon_add_common_modes(encoder, connector); } -- cgit v1.2.3 From c324acd5032f516b8188da99d2ce05cf8d1294d6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 8 Dec 2010 22:13:06 -0500 Subject: drm/radeon/kms: parse the extended LCD info block This block may contain various additional LCD info such as physical size and a stored EDID. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 53 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_combios.c | 3 +- drivers/gpu/drm/radeon/radeon_display.c | 14 +++++++-- drivers/gpu/drm/radeon/radeon_mode.h | 2 +- 4 files changed, 67 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 35c5ff09040d..d6c611eee204 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1515,6 +1515,59 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct else lvds->linkb = false; + /* parse the lcd record table */ + if (lvds_info->info.usModePatchTableOffset) { + ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; + ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; + bool bad_record = false; + u8 *record = (u8 *)(mode_info->atom_context->bios + + data_offset + + lvds_info->info.usModePatchTableOffset); + while (*record != ATOM_RECORD_END_TYPE) { + switch (*record) { + case LCD_MODE_PATCH_RECORD_MODE_TYPE: + record += sizeof(ATOM_PATCH_RECORD_MODE); + break; + case LCD_RTS_RECORD_TYPE: + record += sizeof(ATOM_LCD_RTS_RECORD); + break; + case LCD_CAP_RECORD_TYPE: + record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); + break; + case LCD_FAKE_EDID_PATCH_RECORD_TYPE: + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; + if (fake_edid_record->ucFakeEDIDLength) { + struct edid *edid; + int edid_size = + max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength); + edid = kmalloc(edid_size, GFP_KERNEL); + if (edid) { + memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], + fake_edid_record->ucFakeEDIDLength); + + if (drm_edid_is_valid(edid)) + rdev->mode_info.bios_hardcoded_edid = edid; + else + kfree(edid); + } + } + record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD); + break; + case LCD_PANEL_RESOLUTION_RECORD_TYPE: + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; + lvds->native_mode.width_mm = panel_res_record->usHSize; + lvds->native_mode.height_mm = panel_res_record->usVSize; + record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); + break; + default: + DRM_ERROR("Bad LCD record %d\n", *record); + bad_record = true; + break; + } + if (bad_record) + break; + } + } } return lvds; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 3bddea5b5295..111a844c1ecb 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -471,8 +471,9 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) return true; } +/* this is used for atom LCDs as well */ struct edid * -radeon_combios_get_hardcoded_edid(struct radeon_device *rdev) +radeon_bios_get_hardcoded_edid(struct radeon_device *rdev) { if (rdev->mode_info.bios_hardcoded_edid) return rdev->mode_info.bios_hardcoded_edid; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 7b17e639ab32..acebbc76c2f9 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -679,9 +679,17 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (!radeon_connector->edid) { radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); } - /* some servers provide a hardcoded edid in rom for KVMs */ - if (!radeon_connector->edid) - radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev); + + if (!radeon_connector->edid) { + if (rdev->is_atom_bios) { + /* some laptops provide a hardcoded edid in rom for LCDs */ + if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || + (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) + radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); + } else + /* some servers provide a hardcoded edid in rom for KVMs */ + radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); + } if (radeon_connector->edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index f406f02bf14e..fd185f783a31 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -566,7 +566,7 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); extern struct edid * -radeon_combios_get_hardcoded_edid(struct radeon_device *rdev); +radeon_bios_get_hardcoded_edid(struct radeon_device *rdev); extern bool radeon_atom_get_clock_info(struct drm_device *dev); extern bool radeon_combios_get_clock_info(struct drm_device *dev); extern struct radeon_encoder_atom_dig * -- cgit v1.2.3 From 3ee0128140eed7d32b785a335099a2ec38258283 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 15 Dec 2010 11:04:39 +1000 Subject: drm/nouveau: modify vm to accomodate dual page tables for nvc0 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_vm.c | 59 ++++++++++++++++------------------ drivers/gpu/drm/nouveau/nouveau_vm.h | 16 ++++----- drivers/gpu/drm/nouveau/nv50_instmem.c | 16 ++++----- drivers/gpu/drm/nouveau/nv50_vm.c | 49 ++++++++++++++-------------- 4 files changed, 65 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c index 07ab1749cf7d..b023a64c27d8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vm.c @@ -32,6 +32,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) { struct nouveau_vm *vm = vma->vm; struct nouveau_mm_node *r; + int big = vma->node->type != vm->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 pde = (offset >> vm->pgt_bits) - vm->fpde; @@ -44,7 +45,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) u32 num = r->length >> bits; while (num) { - struct nouveau_gpuobj *pgt = vm->pgt[pde].obj; + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; end = (pte + num); if (unlikely(end >= max)) @@ -76,6 +77,7 @@ nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, dma_addr_t *list) { struct nouveau_vm *vm = vma->vm; + int big = vma->node->type != vm->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; @@ -85,7 +87,7 @@ nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, u32 end, len; while (num) { - struct nouveau_gpuobj *pgt = vm->pgt[pde].obj; + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; end = (pte + num); if (unlikely(end >= max)) @@ -110,6 +112,7 @@ void nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length) { struct nouveau_vm *vm = vma->vm; + int big = vma->node->type != vm->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; @@ -119,7 +122,7 @@ nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length) u32 end, len; while (num) { - struct nouveau_gpuobj *pgt = vm->pgt[pde].obj; + struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; end = (pte + num); if (unlikely(end >= max)) @@ -146,7 +149,7 @@ nouveau_vm_unmap(struct nouveau_vma *vma) } static void -nouveau_vm_unmap_pgt(struct nouveau_vm *vm, u32 fpde, u32 lpde) +nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) { struct nouveau_vm_pgd *vpgd; struct nouveau_vm_pgt *vpgt; @@ -155,16 +158,16 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, u32 fpde, u32 lpde) for (pde = fpde; pde <= lpde; pde++) { vpgt = &vm->pgt[pde - vm->fpde]; - if (--vpgt->refcount) + if (--vpgt->refcount[big]) continue; + pgt = vpgt->obj[big]; + vpgt->obj[big] = NULL; + list_for_each_entry(vpgd, &vm->pgd_list, head) { - vm->unmap_pgt(vpgd->obj, pde); + vm->map_pgt(vpgd->obj, pde, vpgt->obj); } - pgt = vpgt->obj; - vpgt->obj = NULL; - mutex_unlock(&vm->mm->mutex); nouveau_gpuobj_ref(NULL, &pgt); mutex_lock(&vm->mm->mutex); @@ -177,6 +180,7 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; struct nouveau_vm_pgd *vpgd; struct nouveau_gpuobj *pgt; + int big = (type != vm->spg_shift); u32 pgt_size; int ret; @@ -191,19 +195,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) return ret; /* someone beat us to filling the PDE while we didn't have the lock */ - if (unlikely(vpgt->refcount++)) { + if (unlikely(vpgt->refcount[big]++)) { mutex_unlock(&vm->mm->mutex); nouveau_gpuobj_ref(NULL, &pgt); mutex_lock(&vm->mm->mutex); return 0; } + vpgt->obj[big] = pgt; list_for_each_entry(vpgd, &vm->pgd_list, head) { - vm->map_pgt(vpgd->obj, type, pde, pgt); + vm->map_pgt(vpgd->obj, pde, vpgt->obj); } - vpgt->page_shift = type; - vpgt->obj = pgt; return 0; } @@ -227,16 +230,17 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; for (pde = fpde; pde <= lpde; pde++) { struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; + int big = (vma->node->type != vm->spg_shift); - if (likely(vpgt->refcount)) { - vpgt->refcount++; + if (likely(vpgt->refcount[big])) { + vpgt->refcount[big]++; continue; } ret = nouveau_vm_map_pgt(vm, pde, vma->node->type); if (ret) { if (pde != fpde) - nouveau_vm_unmap_pgt(vm, fpde, pde - 1); + nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); nouveau_mm_put(vm->mm, vma->node); mutex_unlock(&vm->mm->mutex); vma->node = NULL; @@ -263,21 +267,20 @@ nouveau_vm_put(struct nouveau_vma *vma) lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; mutex_lock(&vm->mm->mutex); + nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde); nouveau_mm_put(vm->mm, vma->node); vma->node = NULL; - nouveau_vm_unmap_pgt(vm, fpde, lpde); mutex_unlock(&vm->mm->mutex); } int nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, - u8 pgt_bits, u8 spg_shift, u8 lpg_shift, struct nouveau_vm **pvm) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_vm *vm; u64 mm_length = (offset + length) - mm_offset; - u32 block; + u32 block, pgt_bits; int ret; vm = kzalloc(sizeof(*vm), GFP_KERNEL); @@ -286,11 +289,13 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, if (dev_priv->card_type == NV_50) { vm->map_pgt = nv50_vm_map_pgt; - vm->unmap_pgt = nv50_vm_unmap_pgt; vm->map = nv50_vm_map; vm->map_sg = nv50_vm_map_sg; vm->unmap = nv50_vm_unmap; vm->flush = nv50_vm_flush; + vm->spg_shift = 12; + vm->lpg_shift = 16; + pgt_bits = 29; } else { kfree(vm); return -ENOSYS; @@ -308,8 +313,6 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, vm->dev = dev; vm->refcount = 1; vm->pgt_bits = pgt_bits - 12; - vm->spg_shift = spg_shift; - vm->lpg_shift = lpg_shift; block = (1 << pgt_bits); if (length < block) @@ -342,16 +345,8 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) nouveau_gpuobj_ref(pgd, &vpgd->obj); mutex_lock(&vm->mm->mutex); - for (i = vm->fpde; i <= vm->lpde; i++) { - struct nouveau_vm_pgt *vpgt = &vm->pgt[i - vm->fpde]; - - if (!vpgt->obj) { - vm->unmap_pgt(pgd, i); - continue; - } - - vm->map_pgt(pgd, vpgt->page_shift, i, vpgt->obj); - } + for (i = vm->fpde; i <= vm->lpde; i++) + vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); list_add(&vpgd->head, &vm->pgd_list); mutex_unlock(&vm->mm->mutex); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h index b6755cfa7b71..105b6f65f19d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.h +++ b/drivers/gpu/drm/nouveau/nouveau_vm.h @@ -31,9 +31,8 @@ #include "nouveau_mm.h" struct nouveau_vm_pgt { - struct nouveau_gpuobj *obj; - u32 page_shift; - u32 refcount; + struct nouveau_gpuobj *obj[2]; + u32 refcount[2]; }; struct nouveau_vm_pgd { @@ -65,9 +64,8 @@ struct nouveau_vm { u8 spg_shift; u8 lpg_shift; - void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 type, u32 pde, - struct nouveau_gpuobj *pgt); - void (*unmap_pgt)(struct nouveau_gpuobj *pgd, u32 pde); + void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *, struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *, @@ -78,7 +76,6 @@ struct nouveau_vm { /* nouveau_vm.c */ int nouveau_vm_new(struct drm_device *, u64 offset, u64 length, u64 mm_offset, - u8 pgt_bits, u8 spg_shift, u8 lpg_shift, struct nouveau_vm **); int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **, struct nouveau_gpuobj *pgd); @@ -93,9 +90,8 @@ void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, dma_addr_t *); /* nv50_vm.c */ -void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 type, u32 pde, - struct nouveau_gpuobj *pgt); -void nv50_vm_unmap_pgt(struct nouveau_gpuobj *pgd, u32 pde); +void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index adac4da98f7e..2e1b1cd19a4b 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -151,20 +151,19 @@ nv50_instmem_init(struct drm_device *dev) /* BAR3 */ ret = nouveau_vm_new(dev, BAR3_VM_BASE, BAR3_VM_SIZE, BAR3_VM_BASE, - 29, 12, 16, &dev_priv->bar3_vm); + &dev_priv->bar3_vm); if (ret) goto error; ret = nouveau_gpuobj_new(dev, NULL, (BAR3_VM_SIZE >> 12) * 8, 0x1000, NVOBJ_FLAG_DONT_MAP | NVOBJ_FLAG_ZERO_ALLOC, - &dev_priv->bar3_vm->pgt[0].obj); + &dev_priv->bar3_vm->pgt[0].obj[0]); if (ret) goto error; - dev_priv->bar3_vm->pgt[0].page_shift = 12; - dev_priv->bar3_vm->pgt[0].refcount = 1; + dev_priv->bar3_vm->pgt[0].refcount[0] = 1; - nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj); + nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); ret = nv50_channel_new(dev, 128 * 1024, dev_priv->bar3_vm, &chan); if (ret) @@ -195,8 +194,7 @@ nv50_instmem_init(struct drm_device *dev) nv_wo32(chan->ramin, 0, tmp); /* BAR1 */ - ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, - 29, 12, 16, &vm); + ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, &vm); if (ret) goto error; @@ -220,7 +218,7 @@ nv50_instmem_init(struct drm_device *dev) * to catch "NULL pointer" references */ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL, - 29, 12, 16, &dev_priv->chan_vm); + &dev_priv->chan_vm); if (ret) return ret; @@ -258,7 +256,7 @@ nv50_instmem_takedown(struct drm_device *dev) dev_priv->channels.ptr[127] = 0; nv50_channel_del(&dev_priv->channels.ptr[0]); - nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj); + nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); if (dev_priv->ramin_heap.free_stack.next) diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index 7939387f7f80..38e523e10995 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -28,39 +28,40 @@ #include "nouveau_vm.h" void -nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 type, u32 pde, - struct nouveau_gpuobj *pgt) +nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]) { struct drm_nouveau_private *dev_priv = pgd->dev->dev_private; - u32 coverage = (pgt->size >> 3) << type; - u64 phys; - - phys = pgt->vinst; - phys |= 0x01; /* present */ - phys |= (type == 12) ? 0x02 : 0x00; /* 4KiB pages */ - if (dev_priv->vram_sys_base) { - phys += dev_priv->vram_sys_base; - phys |= 0x30; + u64 phys = 0xdeadcafe00000000ULL; + u32 coverage = 0; + + if (pgt[0]) { + phys = 0x00000003 | pgt[0]->vinst; /* present, 4KiB pages */ + coverage = (pgt[0]->size >> 3) << 12; + } else + if (pgt[1]) { + phys = 0x00000001 | pgt[1]->vinst; /* present */ + coverage = (pgt[1]->size >> 3) << 16; } - if (coverage <= 32 * 1024 * 1024) - phys |= 0x60; - else if (coverage <= 64 * 1024 * 1024) - phys |= 0x40; - else if (coverage < 128 * 1024 * 1024) - phys |= 0x20; + if (phys & 1) { + if (dev_priv->vram_sys_base) { + phys += dev_priv->vram_sys_base; + phys |= 0x30; + } + + if (coverage <= 32 * 1024 * 1024) + phys |= 0x60; + else if (coverage <= 64 * 1024 * 1024) + phys |= 0x40; + else if (coverage < 128 * 1024 * 1024) + phys |= 0x20; + } nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); } -void -nv50_vm_unmap_pgt(struct nouveau_gpuobj *pgd, u32 pde) -{ - nv_wo32(pgd, (pde * 8) + 0, 0x00000000); - nv_wo32(pgd, (pde * 8) + 4, 0xdeadcafe); -} - static inline u64 nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, u64 phys, u32 memtype, u32 target) -- cgit v1.2.3 From 4c74eb7ff276813ee73943a3756b295675fb2865 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 10 Nov 2010 14:10:04 +1000 Subject: drm/nvc0: import initial vm backend Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 5 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_mem.c | 4 ++ drivers/gpu/drm/nouveau/nouveau_vm.c | 31 +++++++-- drivers/gpu/drm/nouveau/nouveau_vm.h | 10 +++ drivers/gpu/drm/nouveau/nvc0_vm.c | 123 ++++++++++++++++++++++++++++++++++ 7 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvc0_vm.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index b1d8941e04d8..e89d89593af1 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -28,7 +28,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv10_gpio.o nv50_gpio.o \ nv50_calc.o \ nv04_pm.o nv50_pm.o nva3_pm.o \ - nv50_vram.o nv50_vm.o + nv50_vram.o nv50_vm.o nvc0_vm.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 42d1ad62b381..d17ffea3c617 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -909,8 +909,9 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) break; } - ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, 12, - NV_MEM_ACCESS_RW, &vram->bar_vma); + ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, + vram->page_shift, NV_MEM_ACCESS_RW, + &vram->bar_vma); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 8f13906185b2..57da219fb18b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -69,6 +69,7 @@ struct nouveau_vram { struct drm_device *dev; struct nouveau_vma bar_vma; + u8 page_shift; struct list_head regions; u32 memtype; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 224181193a1f..07be1dd04530 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -731,6 +731,10 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, if (ret) return ret; + node->page_shift = 12; + if (nvbo->vma.node) + node->page_shift = nvbo->vma.node->type; + mem->mm_node = node; mem->start = node->offset >> PAGE_SHIFT; return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c index b023a64c27d8..97d82aedf86b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vm.c @@ -295,7 +295,34 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, vm->flush = nv50_vm_flush; vm->spg_shift = 12; vm->lpg_shift = 16; + pgt_bits = 29; + block = (1 << pgt_bits); + if (length < block) + block = length; + + } else + if (dev_priv->card_type == NV_C0) { + vm->map_pgt = nvc0_vm_map_pgt; + vm->map = nvc0_vm_map; + vm->map_sg = nvc0_vm_map_sg; + vm->unmap = nvc0_vm_unmap; + vm->flush = nvc0_vm_flush; + vm->spg_shift = 12; + vm->lpg_shift = 17; + pgt_bits = 27; + + /* Should be 4096 everywhere, this is a hack that's + * currently necessary to avoid an elusive bug that + * causes corruption when mixing small/large pages + */ + if (length < (1ULL << 40)) + block = 4096; + else { + block = (1 << pgt_bits); + if (length < block) + block = length; + } } else { kfree(vm); return -ENOSYS; @@ -314,10 +341,6 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, vm->refcount = 1; vm->pgt_bits = pgt_bits - 12; - block = (1 << pgt_bits); - if (length < block) - block = length; - ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12, block >> 12); if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h index 105b6f65f19d..e1193515771b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vm.h +++ b/drivers/gpu/drm/nouveau/nouveau_vm.h @@ -100,4 +100,14 @@ void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); void nv50_vm_flush(struct nouveau_vm *); void nv50_vm_flush_engine(struct drm_device *, int engine); +/* nvc0_vm.c */ +void nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); +void nvc0_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, + struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); +void nvc0_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, + u32 pte, dma_addr_t *, u32 cnt); +void nvc0_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); +void nvc0_vm_flush(struct nouveau_vm *); + #endif diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c new file mode 100644 index 000000000000..4b9251bb0ff4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -0,0 +1,123 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" + +#include "nouveau_drv.h" +#include "nouveau_vm.h" + +void +nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 index, + struct nouveau_gpuobj *pgt[2]) +{ + u32 pde[2] = { 0, 0 }; + + if (pgt[0]) + pde[1] = 0x00000001 | (pgt[0]->vinst >> 8); + if (pgt[1]) + pde[0] = 0x00000001 | (pgt[1]->vinst >> 8); + + nv_wo32(pgd, (index * 8) + 0, pde[0]); + nv_wo32(pgd, (index * 8) + 4, pde[1]); +} + +static inline u64 +nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) +{ + phys >>= 8; + + phys |= 0x00000001; /* present */ +// if (vma->access & NV_MEM_ACCESS_SYS) +// phys |= 0x00000002; + + phys |= ((u64)target << 32); + phys |= ((u64)memtype << 36); + + return phys; +} + +void +nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) +{ + u32 next = 1 << (vma->node->type - 8); + + phys = nvc0_vm_addr(vma, phys, mem->memtype, 0); + pte <<= 3; + while (cnt--) { + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + phys += next; + pte += 8; + } +} + +void +nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, + u32 pte, dma_addr_t *list, u32 cnt) +{ + pte <<= 3; + while (cnt--) { + u64 phys = nvc0_vm_addr(vma, *list++, 0, 5); + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + pte += 8; + } +} + +void +nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) +{ + pte <<= 3; + while (cnt--) { + nv_wo32(pgt, pte + 0, 0x00000000); + nv_wo32(pgt, pte + 4, 0x00000000); + pte += 8; + } +} + +void +nvc0_vm_flush(struct nouveau_vm *vm) +{ + struct drm_nouveau_private *dev_priv = vm->dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct drm_device *dev = vm->dev; + struct nouveau_vm_pgd *vpgd; + u32 r100c80, engine; + + pinstmem->flush(vm->dev); + + if (vm == dev_priv->chan_vm) + engine = 1; + else + engine = 5; + + list_for_each_entry(vpgd, &vm->pgd_list, head) { + r100c80 = nv_rd32(dev, 0x100c80); + nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8); + nv_wr32(dev, 0x100cbc, 0x80000000 | engine); + if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80)) + NV_ERROR(dev, "vm flush timeout eng %d\n", engine); + } +} -- cgit v1.2.3 From 8984e046153eb1d6b0b24626169f9c6e58232e1b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 15 Nov 2010 11:48:33 +1000 Subject: drm/nvc0: initial vm implementation, use for bar1/bar3 management Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 3 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 18 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 8 +- drivers/gpu/drm/nouveau/nouveau_mem.c | 3 - drivers/gpu/drm/nouveau/nouveau_mm.h | 5 + drivers/gpu/drm/nouveau/nouveau_state.c | 16 +- drivers/gpu/drm/nouveau/nvc0_instmem.c | 326 ++++++++++++++------------------ drivers/gpu/drm/nouveau/nvc0_vram.c | 91 +++++++++ 8 files changed, 266 insertions(+), 204 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvc0_vram.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index e89d89593af1..d9d22ffff81e 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -28,7 +28,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv10_gpio.o nv50_gpio.o \ nv50_calc.o \ nv04_pm.o nv50_pm.o nva3_pm.o \ - nv50_vram.o nv50_vm.o nvc0_vm.o + nv50_vram.o nvc0_vram.o \ + nv50_vm.o nvc0_vm.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index d17ffea3c617..6f3096a50297 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -120,6 +120,9 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, align >>= PAGE_SHIFT; if (!nvbo->no_vm && dev_priv->chan_vm) { + if (dev_priv->card_type == NV_C0) + page_shift = 12; + ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, NV_MEM_ACCESS_RW, &nvbo->vma); if (ret) { @@ -413,7 +416,7 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->default_caching = TTM_PL_FLAG_CACHED; break; case TTM_PL_VRAM: - if (dev_priv->card_type == NV_50) { + if (dev_priv->card_type >= NV_50) { man->func = &nouveau_vram_manager; man->io_reserve_fastpath = false; man->use_io_reserve_lru = true; @@ -901,6 +904,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) case TTM_PL_VRAM: { struct nouveau_vram *vram = mem->mm_node; + u8 page_shift; if (!dev_priv->bar1_vm) { mem->bus.offset = mem->start << PAGE_SHIFT; @@ -909,8 +913,13 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) break; } + if (dev_priv->card_type == NV_C0) + page_shift = vram->page_shift; + else + page_shift = 12; + ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, - vram->page_shift, NV_MEM_ACCESS_RW, + page_shift, NV_MEM_ACCESS_RW, &vram->bar_vma); if (ret) return ret; @@ -921,8 +930,9 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) return ret; } - mem->bus.offset = vram->bar_vma.offset; - mem->bus.offset -= 0x0020000000ULL; + mem->bus.offset = vram->bar_vma.offset; + if (dev_priv->card_type == NV_50) /*XXX*/ + mem->bus.offset -= 0x0020000000ULL; mem->bus.base = pci_resource_start(dev->pdev, 1); mem->bus.is_iomem = true; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 57da219fb18b..c1e85c4c7ac2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -842,6 +842,9 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_fence *fence); extern const struct ttm_mem_type_manager_func nouveau_vram_manager; +/* nvc0_vram.c */ +extern const struct ttm_mem_type_manager_func nvc0_vram_manager; + /* nouveau_notifier.c */ extern int nouveau_notifier_init_channel(struct nouveau_channel *); extern void nouveau_notifier_takedown_channel(struct nouveau_channel *); @@ -1229,11 +1232,6 @@ extern int nvc0_instmem_init(struct drm_device *); extern void nvc0_instmem_takedown(struct drm_device *); extern int nvc0_instmem_suspend(struct drm_device *); extern void nvc0_instmem_resume(struct drm_device *); -extern int nvc0_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); -extern void nvc0_instmem_put(struct nouveau_gpuobj *); -extern int nvc0_instmem_map(struct nouveau_gpuobj *); -extern void nvc0_instmem_unmap(struct nouveau_gpuobj *); -extern void nvc0_instmem_flush(struct drm_device *); /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 07be1dd04530..69044eb104bb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -255,9 +255,6 @@ nouveau_mem_detect(struct drm_device *dev) if (dev_priv->card_type < NV_50) { dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; - } else { - dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; - dev_priv->vram_size *= nv_rd32(dev, 0x121c74); } if (dev_priv->vram_size) diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h index 250e642de0a7..af3844933036 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h @@ -59,4 +59,9 @@ int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, void nv50_vram_del(struct drm_device *, struct nouveau_vram **); bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); +int nvc0_vram_init(struct drm_device *); +int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_vram **); +bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags); + #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 8eac943e8fd2..813790f4c7c7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -464,11 +464,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.takedown = nvc0_instmem_takedown; engine->instmem.suspend = nvc0_instmem_suspend; engine->instmem.resume = nvc0_instmem_resume; - engine->instmem.get = nvc0_instmem_get; - engine->instmem.put = nvc0_instmem_put; - engine->instmem.map = nvc0_instmem_map; - engine->instmem.unmap = nvc0_instmem_unmap; - engine->instmem.flush = nvc0_instmem_flush; + engine->instmem.get = nv50_instmem_get; + engine->instmem.put = nv50_instmem_put; + engine->instmem.map = nv50_instmem_map; + engine->instmem.unmap = nv50_instmem_unmap; + engine->instmem.flush = nv84_instmem_flush; engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; engine->timer.init = nv04_timer_init; @@ -509,8 +509,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->gpio.irq_enable = nv50_gpio_irq_enable; engine->crypt.init = nouveau_stub_init; engine->crypt.takedown = nouveau_stub_takedown; - engine->vram.init = nouveau_mem_detect; - engine->vram.flags_valid = nouveau_mem_flags_valid; + engine->vram.init = nvc0_vram_init; + engine->vram.get = nvc0_vram_new; + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nvc0_vram_flags_valid; break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 39232085193d..211099736553 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -25,233 +25,191 @@ #include "drmP.h" #include "nouveau_drv.h" +#include "nouveau_vm.h" -struct nvc0_gpuobj_node { - struct nouveau_bo *vram; - struct drm_mm_node *ramin; - u32 align; +struct nvc0_instmem_priv { + struct nouveau_gpuobj *bar1_pgd; + struct nouveau_channel *bar1; + struct nouveau_gpuobj *bar3_pgd; + struct nouveau_channel *bar3; }; int -nvc0_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) +nvc0_instmem_suspend(struct drm_device *dev) { - struct drm_device *dev = gpuobj->dev; - struct nvc0_gpuobj_node *node = NULL; - int ret; - - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - return -ENOMEM; - node->align = align; - - ret = nouveau_bo_new(dev, NULL, size, align, TTM_PL_FLAG_VRAM, - 0, 0x0000, true, false, &node->vram); - if (ret) { - NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); - return ret; - } - - ret = nouveau_bo_pin(node->vram, TTM_PL_FLAG_VRAM); - if (ret) { - NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); - nouveau_bo_ref(NULL, &node->vram); - return ret; - } + struct drm_nouveau_private *dev_priv = dev->dev_private; - gpuobj->vinst = node->vram->bo.mem.start << PAGE_SHIFT; - gpuobj->size = node->vram->bo.mem.num_pages << PAGE_SHIFT; - gpuobj->node = node; + dev_priv->ramin_available = false; return 0; } void -nvc0_instmem_put(struct nouveau_gpuobj *gpuobj) +nvc0_instmem_resume(struct drm_device *dev) { - struct nvc0_gpuobj_node *node; - - node = gpuobj->node; - gpuobj->node = NULL; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; - nouveau_bo_unpin(node->vram); - nouveau_bo_ref(NULL, &node->vram); - kfree(node); + nv_mask(dev, 0x100c80, 0x00000001, 0x00000000); + nv_wr32(dev, 0x001704, 0x80000000 | priv->bar1->ramin->vinst >> 12); + nv_wr32(dev, 0x001714, 0xc0000000 | priv->bar3->ramin->vinst >> 12); + dev_priv->ramin_available = true; } -int -nvc0_instmem_map(struct nouveau_gpuobj *gpuobj) +static void +nvc0_channel_del(struct nouveau_channel **pchan) { - struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; - struct nvc0_gpuobj_node *node = gpuobj->node; - struct drm_device *dev = gpuobj->dev; - struct drm_mm_node *ramin = NULL; - u32 pte, pte_end; - u64 vram; - - do { - if (drm_mm_pre_get(&dev_priv->ramin_heap)) - return -ENOMEM; - - spin_lock(&dev_priv->ramin_lock); - ramin = drm_mm_search_free(&dev_priv->ramin_heap, gpuobj->size, - node->align, 0); - if (ramin == NULL) { - spin_unlock(&dev_priv->ramin_lock); - return -ENOMEM; - } - - ramin = drm_mm_get_block_atomic(ramin, gpuobj->size, node->align); - spin_unlock(&dev_priv->ramin_lock); - } while (ramin == NULL); - - pte = (ramin->start >> 12) << 1; - pte_end = ((ramin->size >> 12) << 1) + pte; - vram = gpuobj->vinst; - - NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", - ramin->start, pte, pte_end); - NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); - - while (pte < pte_end) { - nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); - nv_wr32(dev, 0x702004 + (pte * 8), 0); - vram += 4096; - pte++; - } - dev_priv->engine.instmem.flush(dev); + struct nouveau_channel *chan; - if (1) { - u32 chan = nv_rd32(dev, 0x1700) << 16; - nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); - nv_wr32(dev, 0x100cbc, 0x80000005); - } + chan = *pchan; + *pchan = NULL; + if (!chan) + return; - node->ramin = ramin; - gpuobj->pinst = ramin->start; - return 0; + nouveau_vm_ref(NULL, &chan->vm, NULL); + if (chan->ramin_heap.free_stack.next) + drm_mm_takedown(&chan->ramin_heap); + nouveau_gpuobj_ref(NULL, &chan->ramin); + kfree(chan); } -void -nvc0_instmem_unmap(struct nouveau_gpuobj *gpuobj) +static int +nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, + struct nouveau_channel **pchan, + struct nouveau_gpuobj *pgd, u64 vm_size) { - struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; - struct nvc0_gpuobj_node *node = gpuobj->node; - u32 pte, pte_end; + struct nouveau_channel *chan; + int ret; - if (!node->ramin || !dev_priv->ramin_available) - return; + chan = kzalloc(sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + chan->dev = dev; - pte = (node->ramin->start >> 12) << 1; - pte_end = ((node->ramin->size >> 12) << 1) + pte; + ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); + if (ret) { + nvc0_channel_del(&chan); + return ret; + } - while (pte < pte_end) { - nv_wr32(gpuobj->dev, 0x702000 + (pte * 8), 0); - nv_wr32(gpuobj->dev, 0x702004 + (pte * 8), 0); - pte++; + ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000); + if (ret) { + nvc0_channel_del(&chan); + return ret; } - dev_priv->engine.instmem.flush(gpuobj->dev); - spin_lock(&dev_priv->ramin_lock); - drm_mm_put_block(node->ramin); - node->ramin = NULL; - spin_unlock(&dev_priv->ramin_lock); -} + ret = nouveau_vm_ref(vm, &chan->vm, NULL); + if (ret) { + nvc0_channel_del(&chan); + return ret; + } -void -nvc0_instmem_flush(struct drm_device *dev) -{ - nv_wr32(dev, 0x070000, 1); - if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) - NV_ERROR(dev, "PRAMIN flush timeout\n"); + nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst)); + nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst)); + nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1)); + nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1)); + + *pchan = chan; + return 0; } int -nvc0_instmem_suspend(struct drm_device *dev) +nvc0_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 *buf; - int i; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct pci_dev *pdev = dev->pdev; + struct nvc0_instmem_priv *priv; + struct nouveau_vm *vm = NULL; + int ret; - dev_priv->susres.ramin_copy = vmalloc(65536); - if (!dev_priv->susres.ramin_copy) + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - buf = dev_priv->susres.ramin_copy; - - for (i = 0; i < 65536; i += 4) - buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); + pinstmem->priv = priv; + + /* BAR3 VM */ + ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0, + &dev_priv->bar3_vm); + if (ret) + goto error; + + ret = nouveau_gpuobj_new(dev, NULL, + (pci_resource_len(pdev, 3) >> 12) * 8, 0, + NVOBJ_FLAG_DONT_MAP | + NVOBJ_FLAG_ZERO_ALLOC, + &dev_priv->bar3_vm->pgt[0].obj[0]); + if (ret) + goto error; + dev_priv->bar3_vm->pgt[0].refcount[0] = 1; + + nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); + + ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, + NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd); + if (ret) + goto error; + + ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd); + if (ret) + goto error; + nouveau_vm_ref(NULL, &vm, NULL); + + ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3, + priv->bar3_pgd, pci_resource_len(dev->pdev, 3)); + if (ret) + goto error; + + /* BAR1 VM */ + ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm); + if (ret) + goto error; + + ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, + NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd); + if (ret) + goto error; + + ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd); + if (ret) + goto error; + nouveau_vm_ref(NULL, &vm, NULL); + + ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1, + priv->bar1_pgd, pci_resource_len(dev->pdev, 1)); + if (ret) + goto error; + + nvc0_instmem_resume(dev); return 0; +error: + nvc0_instmem_takedown(dev); + return ret; } void -nvc0_instmem_resume(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 *buf = dev_priv->susres.ramin_copy; - u64 chan; - int i; - - chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; - nv_wr32(dev, 0x001700, chan >> 16); - - for (i = 0; i < 65536; i += 4) - nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); - vfree(dev_priv->susres.ramin_copy); - dev_priv->susres.ramin_copy = NULL; - - nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); -} - -int -nvc0_instmem_init(struct drm_device *dev) +nvc0_instmem_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; - int ret, i; - - dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; - chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; - imem = 4096 + 4096 + 32768; - - nv_wr32(dev, 0x001700, chan >> 16); - - /* channel setup */ - nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); - nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); - nv_wr32(dev, 0x700208, lower_32_bits(lim3)); - nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); - - /* point pgd -> pgt */ - nv_wr32(dev, 0x701000, 0); - nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); - - /* point pgt -> physical vram for channel */ - pgt3 = 0x2000; - for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { - nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); - nv_wr32(dev, 0x700004 + pgt3, 0); - } + struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; + struct nouveau_vm *vm = NULL; - /* clear rest of pgt */ - for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { - nv_wr32(dev, 0x700000 + pgt3, 0); - nv_wr32(dev, 0x700004 + pgt3, 0); - } + nvc0_instmem_suspend(dev); - /* point bar3 at the channel */ - nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); + nv_wr32(dev, 0x1704, 0x00000000); + nv_wr32(dev, 0x1714, 0x00000000); - /* Global PRAMIN heap */ - ret = drm_mm_init(&dev_priv->ramin_heap, imem, - dev_priv->ramin_size - imem); - if (ret) { - NV_ERROR(dev, "Failed to init RAMIN heap\n"); - return -ENOMEM; - } + nvc0_channel_del(&priv->bar1); + nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); + nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); - return 0; -} + nvc0_channel_del(&priv->bar3); + nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL); + nouveau_vm_ref(NULL, &vm, priv->bar3_pgd); + nouveau_gpuobj_ref(NULL, &priv->bar3_pgd); + nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); + nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); -void -nvc0_instmem_takedown(struct drm_device *dev) -{ + dev_priv->engine.instmem.priv = NULL; + kfree(priv); } diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c new file mode 100644 index 000000000000..41fcae5ffba4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_vram.c @@ -0,0 +1,91 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_mm.h" + +bool +nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) +{ + if (likely(!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))) + return true; + return false; +} + +int +nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, + u32 type, struct nouveau_vram **pvram) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *r; + struct nouveau_vram *vram; + int ret; + + size >>= 12; + align >>= 12; + ncmin >>= 12; + + vram = kzalloc(sizeof(*vram), GFP_KERNEL); + if (!vram) + return -ENOMEM; + + INIT_LIST_HEAD(&vram->regions); + vram->dev = dev_priv->dev; + vram->memtype = type; + vram->size = size; + + mutex_lock(&mm->mutex); + do { + ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r); + if (ret) { + mutex_unlock(&mm->mutex); + nv50_vram_del(dev, &vram); + return ret; + } + + list_add_tail(&r->rl_entry, &vram->regions); + size -= r->length; + } while (size); + mutex_unlock(&mm->mutex); + + r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); + vram->offset = (u64)r->offset << 12; + *pvram = vram; + return 0; +} + +int +nvc0_vram_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; + dev_priv->vram_size *= nv_rd32(dev, 0x121c74); + dev_priv->vram_rblock_size = 4096; + return 0; +} -- cgit v1.2.3 From 99805566d93d69b7daf2373aba9fae52a62396f4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 16 Nov 2010 14:58:42 +1000 Subject: drm/nvc0: create shared channel vm Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_instmem.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 211099736553..c09091749054 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -32,6 +32,7 @@ struct nvc0_instmem_priv { struct nouveau_channel *bar1; struct nouveau_gpuobj *bar3_pgd; struct nouveau_channel *bar3; + struct nouveau_gpuobj *chan_pgd; }; int @@ -179,6 +180,18 @@ nvc0_instmem_init(struct drm_device *dev) if (ret) goto error; + /* channel vm */ + ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &vm); + if (ret) + goto error; + + ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 0, &priv->chan_pgd); + if (ret) + goto error; + + nouveau_vm_ref(vm, &dev_priv->chan_vm, priv->chan_pgd); + nouveau_vm_ref(NULL, &vm, NULL); + nvc0_instmem_resume(dev); return 0; error: @@ -198,6 +211,9 @@ nvc0_instmem_takedown(struct drm_device *dev) nv_wr32(dev, 0x1704, 0x00000000); nv_wr32(dev, 0x1714, 0x00000000); + nouveau_vm_ref(NULL, &dev_priv->chan_vm, priv->chan_pgd); + nouveau_gpuobj_ref(NULL, &priv->chan_pgd); + nvc0_channel_del(&priv->bar1); nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); -- cgit v1.2.3 From 587107b690f567690982fb504047e7b0a6590344 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:07:21 +1000 Subject: drm/nvc0: reject the notifier_alloc ioctl Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_notifier.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index a050b7b69782..fe29d604b820 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -164,10 +164,15 @@ int nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_notifierobj_alloc *na = data; struct nouveau_channel *chan; int ret; + /* completely unnecessary for these chipsets... */ + if (unlikely(dev_priv->card_type >= NV_C0)) + return -EINVAL; + chan = nouveau_channel_get(dev, file_priv, na->channel); if (IS_ERR(chan)) return PTR_ERR(chan); -- cgit v1.2.3 From 7460d70355eb568817296d6d3364f72d72eeba70 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:10:23 +1000 Subject: drm/nvc0: gpuobj_new need only check validity and init the relevant engine Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 55c9fdcfa67f..c64fd971b867 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -643,10 +643,13 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class) found: switch (oc->engine) { case NVOBJ_ENGINE_SW: - ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj); - if (ret) - return ret; - goto insert; + if (dev_priv->card_type < NV_C0) { + ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj); + if (ret) + return ret; + goto insert; + } + break; case NVOBJ_ENGINE_GR: if (dev_priv->card_type >= NV_50 && !chan->ramin_grctx) { struct nouveau_pgraph_engine *pgraph = @@ -669,6 +672,10 @@ found: break; } + /* we're done if this is fermi */ + if (dev_priv->card_type >= NV_C0) + return 0; + ret = nouveau_gpuobj_new(dev, chan, nouveau_gpuobj_class_instmem_size(dev, class), 16, -- cgit v1.2.3 From effd6e066f406277254ad7603cf2c7465c4f114b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:15:05 +1000 Subject: drm/nvc0: implement channel structure initialisation Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_object.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index c64fd971b867..d77b1fcd19d4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -779,6 +779,25 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); + if (dev_priv->card_type == NV_C0) { + struct nouveau_vm *vm = dev_priv->chan_vm; + struct nouveau_vm_pgd *vpgd; + + ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, + &chan->ramin); + if (ret) + return ret; + + nouveau_vm_ref(vm, &chan->vm, NULL); + + vpgd = list_first_entry(&vm->pgd_list, struct nouveau_vm_pgd, head); + nv_wo32(chan->ramin, 0x0200, lower_32_bits(vpgd->obj->vinst)); + nv_wo32(chan->ramin, 0x0204, upper_32_bits(vpgd->obj->vinst)); + nv_wo32(chan->ramin, 0x0208, 0xffffffff); + nv_wo32(chan->ramin, 0x020c, 0x000000ff); + return 0; + } + /* Allocate a chunk of memory for per-channel object storage */ ret = nouveau_gpuobj_channel_init_pramin(chan); if (ret) { @@ -786,7 +805,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, return ret; } - /* NV50/NVC0 VM + /* NV50 VM * - Allocate per-channel page-directory * - Link with shared channel VM */ @@ -884,9 +903,6 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - if (!chan->ramht) - return; - nouveau_ramht_ref(NULL, &chan->ramht, chan); nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); -- cgit v1.2.3 From 5216782bf8c195de3befe0742a877c987dd3c4fd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:18:28 +1000 Subject: drm/nvc0: skip dma object creation for drm channel Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 813790f4c7c7..d5b17b6ccd3a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -552,6 +552,10 @@ nouveau_card_init_channel(struct drm_device *dev) if (ret) return ret; + /* no dma objects on fermi... */ + if (dev_priv->card_type >= NV_C0) + goto out_done; + ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->vram_size, NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM, @@ -576,6 +580,7 @@ nouveau_card_init_channel(struct drm_device *dev) if (ret) goto out_err; +out_done: mutex_unlock(&dev_priv->channel->mutex); return 0; -- cgit v1.2.3 From 96545299d7405d4c0f44b727718e263653fc11aa Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:26:24 +1000 Subject: drm/nvc0: fix channel dma init paths Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 20 ++++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_dma.c | 22 ++++++++++++++++------ drivers/gpu/drm/nouveau/nouveau_dma.h | 6 ++++++ 3 files changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 6f37995aee2d..e37977d02463 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -38,9 +38,14 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) int ret; if (dev_priv->card_type >= NV_50) { - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, - (1ULL << 40), NV_MEM_ACCESS_RO, - NV_MEM_TARGET_VM, &pushbuf); + if (dev_priv->card_type < NV_C0) { + ret = nouveau_gpuobj_dma_new(chan, + NV_CLASS_DMA_IN_MEMORY, 0, + (1ULL << 40), + NV_MEM_ACCESS_RO, + NV_MEM_TARGET_VM, + &pushbuf); + } chan->pushbuf_base = pb->bo.offset; } else if (pb->bo.mem.mem_type == TTM_PL_TT) { @@ -71,7 +76,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) nouveau_gpuobj_ref(pushbuf, &chan->pushbuf); nouveau_gpuobj_ref(NULL, &pushbuf); - return 0; + return ret; } static struct nouveau_bo * @@ -99,6 +104,13 @@ nouveau_channel_user_pushbuf_alloc(struct drm_device *dev) return NULL; } + ret = nouveau_bo_map(pushbuf); + if (ret) { + nouveau_bo_unpin(pushbuf); + nouveau_bo_ref(NULL, &pushbuf); + return NULL; + } + return pushbuf; } diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 6ff77cedc008..65699bfaaaea 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -36,7 +36,7 @@ nouveau_dma_pre_init(struct nouveau_channel *chan) struct drm_nouveau_private *dev_priv = chan->dev->dev_private; struct nouveau_bo *pushbuf = chan->pushbuf_bo; - if (dev_priv->card_type == NV_50) { + if (dev_priv->card_type >= NV_50) { const int ib_size = pushbuf->bo.mem.size / 2; chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2; @@ -61,6 +61,21 @@ nouveau_dma_init(struct nouveau_channel *chan) struct drm_nouveau_private *dev_priv = dev->dev_private; int ret, i; + if (dev_priv->card_type >= NV_C0) { + ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039); + if (ret) + return ret; + + ret = RING_SPACE(chan, 2); + if (ret) + return ret; + + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1); + OUT_RING (chan, 0x00009039); + FIRE_RING (chan); + return 0; + } + /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ ret = nouveau_gpuobj_gr_new(chan, NvM2MF, dev_priv->card_type < NV_50 ? 0x0039 : 0x5039); @@ -72,11 +87,6 @@ nouveau_dma_init(struct nouveau_channel *chan) if (ret) return ret; - /* Map push buffer */ - ret = nouveau_bo_map(chan->pushbuf_bo); - if (ret) - return ret; - /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index d578c21d3c8d..c118a331b5bc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -124,6 +124,12 @@ OUT_RING(struct nouveau_channel *chan, int data) extern void OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords); +static inline void +BEGIN_NVC0(struct nouveau_channel *chan, int op, int subc, int mthd, int size) +{ + OUT_RING(chan, (op << 28) | (size << 16) | (subc << 13) | (mthd >> 2)); +} + static inline void BEGIN_RING(struct nouveau_channel *chan, int subc, int mthd, int size) { -- cgit v1.2.3 From 529c4959129c7c425aaf3d5b6acc63edf76827ad Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:30:22 +1000 Subject: drm/nvc0: implement fencing Just simple REF_CNT fencing for the moment. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 374a9793b85f..88b2f29ca3e4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -32,7 +32,8 @@ #include "nouveau_dma.h" #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) -#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17) +#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \ + nouveau_private(dev)->card_type < NV_C0) struct nouveau_fence { struct nouveau_channel *channel; @@ -139,6 +140,7 @@ nouveau_fence_emit(struct nouveau_fence *fence) { struct nouveau_channel *chan = fence->channel; struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; ret = RING_SPACE(chan, 2); @@ -159,8 +161,15 @@ nouveau_fence_emit(struct nouveau_fence *fence) list_add_tail(&fence->entry, &chan->fence.pending); spin_unlock(&chan->fence.lock); - BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1); - OUT_RING(chan, fence->sequence); + if (USE_REFCNT(dev)) { + if (dev_priv->card_type < NV_C0) + BEGIN_RING(chan, NvSubSw, 0x0050, 1); + else + BEGIN_NVC0(chan, 2, NvSubSw, 0x0050, 1); + } else { + BEGIN_RING(chan, NvSubSw, 0x0150, 1); + } + OUT_RING (chan, fence->sequence); FIRE_RING(chan); return 0; @@ -445,11 +454,14 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) if (ret) return ret; - ret = RING_SPACE(chan, 2); - if (ret) - return ret; - BEGIN_RING(chan, NvSubSw, 0, 1); - OUT_RING(chan, NvSw); + /* we leave subchannel empty for nvc0 */ + if (dev_priv->card_type < NV_C0) { + ret = RING_SPACE(chan, 2); + if (ret) + return ret; + BEGIN_RING(chan, NvSubSw, 0, 1); + OUT_RING(chan, NvSw); + } /* Create a DMA object for the shared cross-channel sync area. */ if (USE_SEMA(dev)) { -- cgit v1.2.3 From b2b099388fa76f0be25431794d369d251a4002dd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:47:15 +1000 Subject: drm/nvc0: implement pfifo engine hooks Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 + drivers/gpu/drm/nouveau/nvc0_fifo.c | 359 ++++++++++++++++++++++++++++++++++ 2 files changed, 361 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c1e85c4c7ac2..6a2b3359f368 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -240,6 +240,7 @@ struct nouveau_channel { /* PFIFO context */ struct nouveau_gpuobj *ramfc; struct nouveau_gpuobj *cache; + void *fifo_priv; /* PGRAPH context */ /* XXX may be merge 2 pointers as private data ??? */ @@ -337,6 +338,7 @@ struct nouveau_fb_engine { }; struct nouveau_fifo_engine { + void *priv; int channels; struct nouveau_gpuobj *playlist[2]; diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c index 890c2b95fbc1..82a4ded5dae8 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fifo.c +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c @@ -25,6 +25,48 @@ #include "drmP.h" #include "nouveau_drv.h" +#include "nouveau_mm.h" + +static void nvc0_fifo_isr(struct drm_device *); + +struct nvc0_fifo_priv { + struct nouveau_gpuobj *playlist[2]; + int cur_playlist; + struct nouveau_vma user_vma; +}; + +struct nvc0_fifo_chan { + struct nouveau_bo *user; + struct nouveau_gpuobj *ramfc; +}; + +static void +nvc0_fifo_playlist_update(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nvc0_fifo_priv *priv = pfifo->priv; + struct nouveau_gpuobj *cur; + int i, p; + + cur = priv->playlist[priv->cur_playlist]; + priv->cur_playlist = !priv->cur_playlist; + + for (i = 0, p = 0; i < 128; i++) { + if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1)) + continue; + nv_wo32(cur, p + 0, i); + nv_wo32(cur, p + 4, 0x00000004); + p += 8; + } + pinstmem->flush(dev); + + nv_wr32(dev, 0x002270, cur->vinst >> 12); + nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3)); + if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000)) + NV_ERROR(dev, "PFIFO - playlist update failed\n"); +} void nvc0_fifo_disable(struct drm_device *dev) @@ -57,12 +99,135 @@ nvc0_fifo_channel_id(struct drm_device *dev) int nvc0_fifo_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nvc0_fifo_priv *priv = pfifo->priv; + struct nvc0_fifo_chan *fifoch; + u64 ib_virt, user_vinst; + int ret; + + chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL); + if (!chan->fifo_priv) + return -ENOMEM; + fifoch = chan->fifo_priv; + + /* allocate vram for control regs, map into polling area */ + ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM, + 0, 0, true, true, &fifoch->user); + if (ret) + goto error; + + ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM); + if (ret) { + nouveau_bo_ref(NULL, &fifoch->user); + goto error; + } + + user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT; + + ret = nouveau_bo_map(fifoch->user); + if (ret) { + nouveau_bo_unpin(fifoch->user); + nouveau_bo_ref(NULL, &fifoch->user); + goto error; + } + + nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000, + fifoch->user->bo.mem.mm_node); + + chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + + priv->user_vma.offset + (chan->id * 0x1000), + PAGE_SIZE); + if (!chan->user) { + ret = -ENOMEM; + goto error; + } + + ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4; + + /* zero channel regs */ + nouveau_bo_wr32(fifoch->user, 0x0040/4, 0); + nouveau_bo_wr32(fifoch->user, 0x0044/4, 0); + nouveau_bo_wr32(fifoch->user, 0x0048/4, 0); + nouveau_bo_wr32(fifoch->user, 0x004c/4, 0); + nouveau_bo_wr32(fifoch->user, 0x0050/4, 0); + nouveau_bo_wr32(fifoch->user, 0x0058/4, 0); + nouveau_bo_wr32(fifoch->user, 0x005c/4, 0); + nouveau_bo_wr32(fifoch->user, 0x0060/4, 0); + nouveau_bo_wr32(fifoch->user, 0x0088/4, 0); + nouveau_bo_wr32(fifoch->user, 0x008c/4, 0); + + /* ramfc */ + ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst, + chan->ramin->vinst, 0x100, + NVOBJ_FLAG_ZERO_ALLOC, &fifoch->ramfc); + if (ret) + goto error; + + nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst)); + nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst)); + nv_wo32(fifoch->ramfc, 0x10, 0x0000face); + nv_wo32(fifoch->ramfc, 0x30, 0xfffff902); + nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt)); + nv_wo32(fifoch->ramfc, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 | + upper_32_bits(ib_virt)); + nv_wo32(fifoch->ramfc, 0x54, 0x00000002); + nv_wo32(fifoch->ramfc, 0x84, 0x20400000); + nv_wo32(fifoch->ramfc, 0x94, 0x30000001); + nv_wo32(fifoch->ramfc, 0x9c, 0x00000100); + nv_wo32(fifoch->ramfc, 0xa4, 0x1f1f1f1f); + nv_wo32(fifoch->ramfc, 0xa8, 0x1f1f1f1f); + nv_wo32(fifoch->ramfc, 0xac, 0x0000001f); + nv_wo32(fifoch->ramfc, 0xb8, 0xf8000000); + nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */ + nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */ + pinstmem->flush(dev); + + nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 | + (chan->ramin->vinst >> 12)); + nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001); + nvc0_fifo_playlist_update(dev); return 0; + +error: + pfifo->destroy_context(chan); + return ret; } void nvc0_fifo_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct nvc0_fifo_chan *fifoch; + + nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000); + nv_wr32(dev, 0x002634, chan->id); + if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id)) + NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634)); + + nvc0_fifo_playlist_update(dev); + + nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000); + + if (chan->user) { + iounmap(chan->user); + chan->user = NULL; + } + + fifoch = chan->fifo_priv; + chan->fifo_priv = NULL; + if (!fifoch) + return; + + nouveau_gpuobj_ref(NULL, &fifoch->ramfc); + if (fifoch->user) { + nouveau_bo_unmap(fifoch->user); + nouveau_bo_unpin(fifoch->user); + nouveau_bo_ref(NULL, &fifoch->user); + } + kfree(fifoch); } int @@ -77,14 +242,208 @@ nvc0_fifo_unload_context(struct drm_device *dev) return 0; } +static void +nvc0_fifo_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nvc0_fifo_priv *priv; + + priv = pfifo->priv; + if (!priv) + return; + + nouveau_vm_put(&priv->user_vma); + nouveau_gpuobj_ref(NULL, &priv->playlist[1]); + nouveau_gpuobj_ref(NULL, &priv->playlist[0]); + kfree(priv); +} + void nvc0_fifo_takedown(struct drm_device *dev) { + nv_wr32(dev, 0x002140, 0x00000000); + nvc0_fifo_destroy(dev); +} + +static int +nvc0_fifo_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nvc0_fifo_priv *priv; + int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + pfifo->priv = priv; + + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0, + &priv->playlist[0]); + if (ret) + goto error; + + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0, + &priv->playlist[1]); + if (ret) + goto error; + + ret = nouveau_vm_get(dev_priv->bar1_vm, pfifo->channels * 0x1000, + 12, NV_MEM_ACCESS_RW, &priv->user_vma); + if (ret) + goto error; + + nouveau_irq_register(dev, 8, nvc0_fifo_isr); + NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ + return 0; + +error: + nvc0_fifo_destroy(dev); + return ret; } int nvc0_fifo_init(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; + struct nvc0_fifo_priv *priv; + int ret, i; + + if (!pfifo->priv) { + ret = nvc0_fifo_create(dev); + if (ret) + return ret; + } + priv = pfifo->priv; + + /* reset PFIFO, enable all available PSUBFIFO areas */ + nv_mask(dev, 0x000200, 0x00000100, 0x00000000); + nv_mask(dev, 0x000200, 0x00000100, 0x00000100); + nv_wr32(dev, 0x000204, 0xffffffff); + nv_wr32(dev, 0x002204, 0xffffffff); + + /* assign engines to subfifos */ + nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */ + nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */ + nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */ + nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */ + nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */ + nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */ + + /* PSUBFIFO[n] */ + for (i = 0; i < 3; i++) { + nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ + } + + nv_mask(dev, 0x002200, 0x00000001, 0x00000001); + nv_wr32(dev, 0x002254, 0x10000000 | priv->user_vma.offset >> 12); + + nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ + nv_wr32(dev, 0x002100, 0xffffffff); + nv_wr32(dev, 0x002140, 0xbfffffff); return 0; } +struct nouveau_enum nvc0_fifo_fault_unit[] = { + { 0, "PGRAPH" }, + { 3, "PEEPHOLE" }, + { 4, "BAR1" }, + { 5, "BAR3" }, + { 7, "PFIFO" }, + {} +}; + +struct nouveau_enum nvc0_fifo_fault_reason[] = { + { 0, "PT_NOT_PRESENT" }, + { 1, "PT_TOO_SHORT" }, + { 2, "PAGE_NOT_PRESENT" }, + { 3, "VM_LIMIT_EXCEEDED" }, + {} +}; + +struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { +/* { 0x00008000, "" } seen with null ib push */ + { 0x00200000, "ILLEGAL_MTHD" }, + { 0x00800000, "EMPTY_SUBC" }, + {} +}; + +static void +nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) +{ + u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10)); + u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10)); + u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10)); + u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10)); + + NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [", + (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo); + nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); + printk("] from "); + nouveau_enum_print(nvc0_fifo_fault_unit, unit); + printk(" on channel 0x%010llx\n", (u64)inst << 12); +} + +static void +nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) +{ + u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000)); + u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000)); + u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000)); + u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f; + u32 subc = (addr & 0x00070000); + u32 mthd = (addr & 0x00003ffc); + + NV_INFO(dev, "PSUBFIFO %d:", unit); + nouveau_bitfield_print(nvc0_fifo_subfifo_intr, stat); + NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n", + unit, chid, subc, mthd, data); + + nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(dev, 0x040108 + (unit * 0x2000), stat); +} + +static void +nvc0_fifo_isr(struct drm_device *dev) +{ + u32 stat = nv_rd32(dev, 0x002100); + + if (stat & 0x10000000) { + u32 units = nv_rd32(dev, 0x00259c); + u32 u = units; + + while (u) { + int i = ffs(u) - 1; + nvc0_fifo_isr_vm_fault(dev, i); + u &= ~(1 << i); + } + + nv_wr32(dev, 0x00259c, units); + stat &= ~0x10000000; + } + + if (stat & 0x20000000) { + u32 units = nv_rd32(dev, 0x0025a0); + u32 u = units; + + while (u) { + int i = ffs(u) - 1; + nvc0_fifo_isr_subfifo_intr(dev, i); + u &= ~(1 << i); + } + + nv_wr32(dev, 0x0025a0, units); + stat &= ~0x20000000; + } + + if (stat) { + NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); + nv_wr32(dev, 0x002100, stat); + } + + nv_wr32(dev, 0x2140, 0); +} -- cgit v1.2.3 From 966a5b7daa15e152bc2e1f0407939cc721fb5995 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:49:02 +1000 Subject: drm/nvc0: implement pgraph engine hooks Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nvc0_graph.c | 709 +++++++- drivers/gpu/drm/nouveau/nvc0_graph.h | 66 + drivers/gpu/drm/nouveau/nvc0_grctx.c | 2854 +++++++++++++++++++++++++++++++++ 6 files changed, 3631 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvc0_graph.h create mode 100644 drivers/gpu/drm/nouveau/nvc0_grctx.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index d9d22ffff81e..141771beb8e6 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -18,7 +18,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o nvc0_graph.o \ - nv40_grctx.o nv50_grctx.o \ + nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ nv84_crypt.o \ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6f3096a50297..5dc639e0c969 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -839,7 +839,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, } /* Software copy if the card isn't up and running yet. */ - if (!dev_priv->channel) { + if (!dev_priv->channel || dev_priv->card_type == NV_C0) { ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); goto out; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 6a2b3359f368..e81575687354 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -365,6 +365,7 @@ struct nouveau_pgraph_engine { bool accel_blocked; bool registered; int grctx_size; + void *priv; /* NV2x/NV3x context table (0x400780) */ struct nouveau_gpuobj *ctx_table; diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 717a5177a8d8..cf2f6aa920b4 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -22,9 +22,16 @@ * Authors: Ben Skeggs */ +#include + #include "drmP.h" #include "nouveau_drv.h" +#include "nouveau_mm.h" +#include "nvc0_graph.h" + +static void nvc0_graph_isr(struct drm_device *); +static int nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan); void nvc0_graph_fifo_access(struct drm_device *dev, bool enabled) @@ -37,39 +44,739 @@ nvc0_graph_channel(struct drm_device *dev) return NULL; } +static int +nvc0_graph_construct_context(struct nouveau_channel *chan) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + struct nvc0_graph_chan *grch = chan->pgraph_ctx; + struct drm_device *dev = chan->dev; + int ret, i; + u32 *ctx; + + ctx = kmalloc(priv->grctx_size, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + nvc0_graph_load_context(chan); + + nv_wo32(grch->grctx, 0x1c, 1); + nv_wo32(grch->grctx, 0x20, 0); + nv_wo32(grch->grctx, 0x28, 0); + nv_wo32(grch->grctx, 0x2c, 0); + dev_priv->engine.instmem.flush(dev); + + ret = nvc0_grctx_generate(chan); + if (ret) { + kfree(ctx); + return ret; + } + + ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst); + if (ret) { + kfree(ctx); + return ret; + } + + for (i = 0; i < priv->grctx_size; i += 4) + ctx[i / 4] = nv_ro32(grch->grctx, i); + + priv->grctx_vals = ctx; + return 0; +} + +static int +nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + struct nvc0_graph_chan *grch = chan->pgraph_ctx; + struct drm_device *dev = chan->dev; + int i = 0, gpc, tp, ret; + u32 magic; + + ret = nouveau_gpuobj_new(dev, NULL, 0x2000, 256, NVOBJ_FLAG_VM, + &grch->unk408004); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 256, NVOBJ_FLAG_VM, + &grch->unk40800c); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, NVOBJ_FLAG_VM, + &grch->unk418810); + if (ret) + return ret; + + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0, NVOBJ_FLAG_VM, + &grch->mmio); + if (ret) + return ret; + + + nv_wo32(grch->mmio, i++ * 4, 0x00408004); + nv_wo32(grch->mmio, i++ * 4, grch->unk408004->vinst >> 8); + nv_wo32(grch->mmio, i++ * 4, 0x00408008); + nv_wo32(grch->mmio, i++ * 4, 0x80000018); + + nv_wo32(grch->mmio, i++ * 4, 0x0040800c); + nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8); + nv_wo32(grch->mmio, i++ * 4, 0x00408010); + nv_wo32(grch->mmio, i++ * 4, 0x80000000); + + nv_wo32(grch->mmio, i++ * 4, 0x00418810); + nv_wo32(grch->mmio, i++ * 4, 0x80000000 | grch->unk418810->vinst >> 12); + nv_wo32(grch->mmio, i++ * 4, 0x00419848); + nv_wo32(grch->mmio, i++ * 4, 0x10000000 | grch->unk418810->vinst >> 12); + + nv_wo32(grch->mmio, i++ * 4, 0x00419004); + nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8); + nv_wo32(grch->mmio, i++ * 4, 0x00419008); + nv_wo32(grch->mmio, i++ * 4, 0x00000000); + + nv_wo32(grch->mmio, i++ * 4, 0x00418808); + nv_wo32(grch->mmio, i++ * 4, grch->unk408004->vinst >> 8); + nv_wo32(grch->mmio, i++ * 4, 0x0041880c); + nv_wo32(grch->mmio, i++ * 4, 0x80000018); + + magic = 0x02180000; + nv_wo32(grch->mmio, i++ * 4, 0x00405830); + nv_wo32(grch->mmio, i++ * 4, magic); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x02fc) { + u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800); + nv_wo32(grch->mmio, i++ * 4, reg); + nv_wo32(grch->mmio, i++ * 4, magic); + } + } + + grch->mmio_nr = i / 2; + return 0; +} + int nvc0_graph_create_context(struct nouveau_channel *chan) { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nvc0_graph_priv *priv = pgraph->priv; + struct nvc0_graph_chan *grch; + struct drm_device *dev = chan->dev; + struct nouveau_gpuobj *grctx; + int ret, i; + + chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL); + if (!chan->pgraph_ctx) + return -ENOMEM; + grch = chan->pgraph_ctx; + + ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256, + NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC, + &grch->grctx); + if (ret) + goto error; + chan->ramin_grctx = grch->grctx; + grctx = grch->grctx; + + ret = nvc0_graph_create_context_mmio_list(chan); + if (ret) + goto error; + + nv_wo32(chan->ramin, 0x0210, lower_32_bits(grctx->vinst) | 4); + nv_wo32(chan->ramin, 0x0214, upper_32_bits(grctx->vinst)); + pinstmem->flush(dev); + + if (!priv->grctx_vals) { + ret = nvc0_graph_construct_context(chan); + if (ret) + goto error; + } + + for (i = 0; i < priv->grctx_size; i += 4) + nv_wo32(grctx, i, priv->grctx_vals[i / 4]); + + nv_wo32(grctx, 0xf4, 0); + nv_wo32(grctx, 0xf8, 0); + nv_wo32(grctx, 0x10, grch->mmio_nr); + nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst)); + nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst)); + nv_wo32(grctx, 0x1c, 1); + nv_wo32(grctx, 0x20, 0); + nv_wo32(grctx, 0x28, 0); + nv_wo32(grctx, 0x2c, 0); + pinstmem->flush(dev); return 0; + +error: + pgraph->destroy_context(chan); + return ret; } void nvc0_graph_destroy_context(struct nouveau_channel *chan) { + struct nvc0_graph_chan *grch; + + grch = chan->pgraph_ctx; + chan->pgraph_ctx = NULL; + if (!grch) + return; + + nouveau_gpuobj_ref(NULL, &grch->mmio); + nouveau_gpuobj_ref(NULL, &grch->unk418810); + nouveau_gpuobj_ref(NULL, &grch->unk40800c); + nouveau_gpuobj_ref(NULL, &grch->unk408004); + nouveau_gpuobj_ref(NULL, &grch->grctx); + chan->ramin_grctx = NULL; } int nvc0_graph_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + + nv_wr32(dev, 0x409840, 0x00000030); + nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12); + nv_wr32(dev, 0x409504, 0x00000003); + if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010)) + NV_ERROR(dev, "PGRAPH: load_ctx timeout\n"); + + printk(KERN_ERR "load_ctx 0x%08x\n", nv_rd32(dev, 0x409b00)); + return 0; +} + +static int +nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan) +{ + nv_wr32(dev, 0x409840, 0x00000003); + nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12); + nv_wr32(dev, 0x409504, 0x00000009); + if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) { + NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n"); + return -EBUSY; + } + return 0; } int nvc0_graph_unload_context(struct drm_device *dev) { - return 0; + u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; + return nvc0_graph_unload_context_to(dev, inst); +} + +static void +nvc0_graph_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nvc0_graph_priv *priv; + + priv = pgraph->priv; + if (!priv) + return; + + nouveau_irq_unregister(dev, 12); + + nouveau_gpuobj_ref(NULL, &priv->unk4188b8); + nouveau_gpuobj_ref(NULL, &priv->unk4188b4); + + if (priv->grctx_vals) + kfree(priv->grctx_vals); + kfree(priv); } void nvc0_graph_takedown(struct drm_device *dev) { + nvc0_graph_destroy(dev); +} + +static int +nvc0_graph_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nvc0_graph_priv *priv; + int ret, gpc, i; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + pgraph->priv = priv; + + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); + if (ret) + goto error; + + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8); + if (ret) + goto error; + + for (i = 0; i < 0x1000; i += 4) { + nv_wo32(priv->unk4188b4, i, 0x00000010); + nv_wo32(priv->unk4188b8, i, 0x00000010); + } + + priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f; + priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16; + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608)); + priv->tp_total += priv->tp_nr[gpc]; + } + + /*XXX: these need figuring out... */ + switch (dev_priv->chipset) { + case 0xc0: + if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */ + priv->magic_not_rop_nr = 0x07; + priv->magic419bd0 = 0x0a360000; + priv->magic419be4 = 0x04c33a54; + /* filled values up to tp_total, the rest 0 */ + priv->magicgpc980[0] = 0x22111000; + priv->magicgpc980[1] = 0x00000233; + priv->magicgpc980[2] = 0x00000000; + priv->magicgpc980[3] = 0x00000000; + priv->magicgpc918 = 0x000ba2e9; + } else + if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */ + priv->magic_not_rop_nr = 0x05; + priv->magic419bd0 = 0x043c0000; + priv->magic419be4 = 0x09041208; + priv->magicgpc980[0] = 0x11110000; + priv->magicgpc980[1] = 0x00233222; + priv->magicgpc980[2] = 0x00000000; + priv->magicgpc980[3] = 0x00000000; + priv->magicgpc918 = 0x00092493; + } else + if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */ + priv->magic_not_rop_nr = 0x06; + priv->magic419bd0 = 0x023e0000; + priv->magic419be4 = 0x10414104; + priv->magicgpc980[0] = 0x11110000; + priv->magicgpc980[1] = 0x03332222; + priv->magicgpc980[2] = 0x00000000; + priv->magicgpc980[3] = 0x00000000; + priv->magicgpc918 = 0x00088889; + } + break; + case 0xc3: /* 450, 4/0/0/0, 2 */ + priv->magic_not_rop_nr = 0x03; + priv->magic419bd0 = 0x00500000; + priv->magic419be4 = 0x00000000; + priv->magicgpc980[0] = 0x00003210; + priv->magicgpc980[1] = 0x00000000; + priv->magicgpc980[2] = 0x00000000; + priv->magicgpc980[3] = 0x00000000; + priv->magicgpc918 = 0x00200000; + break; + case 0xc4: /* 460, 3/4/0/0, 4 */ + priv->magic_not_rop_nr = 0x01; + priv->magic419bd0 = 0x045c0000; + priv->magic419be4 = 0x09041208; + priv->magicgpc980[0] = 0x02321100; + priv->magicgpc980[1] = 0x00000000; + priv->magicgpc980[2] = 0x00000000; + priv->magicgpc980[3] = 0x00000000; + priv->magicgpc918 = 0x00124925; + break; + } + + if (!priv->magic419bd0) { + NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n", + priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2], + priv->tp_nr[3], priv->rop_nr); + /* use 0xc3's values... */ + priv->magic_not_rop_nr = 0x03; + priv->magic419bd0 = 0x00500000; + priv->magic419be4 = 0x00000000; + priv->magicgpc980[0] = 0x00003210; + priv->magicgpc980[1] = 0x00000000; + priv->magicgpc980[2] = 0x00000000; + priv->magicgpc980[3] = 0x00000000; + priv->magicgpc918 = 0x00200000; + } + + nouveau_irq_register(dev, 12, nvc0_graph_isr); + NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ + NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ + NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ + NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */ + return 0; + +error: + nvc0_graph_destroy(dev); + return ret; +} + +static void +nvc0_graph_init_obj418880(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nvc0_graph_priv *priv = pgraph->priv; + int i; + + nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000); + for (i = 0; i < 4; i++) + nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000); + nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->vinst >> 8); + nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->vinst >> 8); +} + +static void +nvc0_graph_init_regs(struct drm_device *dev) +{ + nv_wr32(dev, 0x400080, 0x003083c2); + nv_wr32(dev, 0x400088, 0x00006fe7); + nv_wr32(dev, 0x40008c, 0x00000000); + nv_wr32(dev, 0x400090, 0x00000030); + nv_wr32(dev, 0x40013c, 0x013901f7); + nv_wr32(dev, 0x400140, 0x00000100); + nv_wr32(dev, 0x400144, 0x00000000); + nv_wr32(dev, 0x400148, 0x00000110); + nv_wr32(dev, 0x400138, 0x00000000); + nv_wr32(dev, 0x400130, 0x00000000); + nv_wr32(dev, 0x400134, 0x00000000); + nv_wr32(dev, 0x400124, 0x00000002); +} + +static void +nvc0_graph_init_gpc_0(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + int gpc; + + // TP ROP UNKVAL(magic_not_rop_nr) + // 450: 4/0/0/0 2 3 + // 460: 3/4/0/0 4 1 + // 465: 3/4/4/0 4 7 + // 470: 3/3/4/4 5 5 + // 480: 3/4/4/4 6 6 + + // magicgpc918 + // 450: 00200000 00000000001000000000000000000000 + // 460: 00124925 00000000000100100100100100100101 + // 465: 000ba2e9 00000000000010111010001011101001 + // 470: 00092493 00000000000010010010010010010011 + // 480: 00088889 00000000000010001000100010001001 + + /* filled values up to tp_total, remainder 0 */ + // 450: 00003210 00000000 00000000 00000000 + // 460: 02321100 00000000 00000000 00000000 + // 465: 22111000 00000233 00000000 00000000 + // 470: 11110000 00233222 00000000 00000000 + // 480: 11110000 03332222 00000000 00000000 + + nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]); + nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]); + nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]); + nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | + priv->tp_nr[gpc]); + nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tp_total); + nv_wr32(dev, GPC_UNIT(gpc, 0x0918), priv->magicgpc918); + } + + nv_wr32(dev, GPC_BCAST(0x1bd4), priv->magicgpc918); + nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr); +} + +static void +nvc0_graph_init_units(struct drm_device *dev) +{ + nv_wr32(dev, 0x409c24, 0x000f0000); + nv_wr32(dev, 0x404000, 0xc0000000); /* DISPATCH */ + nv_wr32(dev, 0x404600, 0xc0000000); /* M2MF */ + nv_wr32(dev, 0x408030, 0xc0000000); + nv_wr32(dev, 0x40601c, 0xc0000000); + nv_wr32(dev, 0x404490, 0xc0000000); /* MACRO */ + nv_wr32(dev, 0x406018, 0xc0000000); + nv_wr32(dev, 0x405840, 0xc0000000); + nv_wr32(dev, 0x405844, 0x00ffffff); + nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008); + nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000); +} + +static void +nvc0_graph_init_gpc_1(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + int gpc, tp; + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { + nv_wr32(dev, TP_UNIT(gpc, tp, 0x508), 0xffffffff); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x50c), 0xffffffff); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x224), 0xc0000000); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x48c), 0xc0000000); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x084), 0xc0000000); + nv_wr32(dev, TP_UNIT(gpc, tp, 0xe44), 0x001ffffe); + nv_wr32(dev, TP_UNIT(gpc, tp, 0xe4c), 0x0000000f); + } + nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + } +} + +static void +nvc0_graph_init_rop(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + int rop; + + for (rop = 0; rop < priv->rop_nr; rop++) { + nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000); + nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff); + } +} + +static int +nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base, + const char *code_fw, const char *data_fw) +{ + const struct firmware *fw; + char name[32]; + int ret, i; + + snprintf(name, sizeof(name), "nouveau/%s", data_fw); + ret = request_firmware(&fw, name, &dev->pdev->dev); + if (ret) { + NV_ERROR(dev, "failed to load %s\n", data_fw); + return ret; + } + + nv_wr32(dev, fuc_base + 0x01c0, 0x01000000); + for (i = 0; i < fw->size / 4; i++) + nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]); + release_firmware(fw); + + snprintf(name, sizeof(name), "nouveau/%s", code_fw); + ret = request_firmware(&fw, name, &dev->pdev->dev); + if (ret) { + NV_ERROR(dev, "failed to load %s\n", code_fw); + return ret; + } + + nv_wr32(dev, fuc_base + 0x0180, 0x01000000); + for (i = 0; i < fw->size / 4; i++) { + if ((i & 0x3f) == 0) + nv_wr32(dev, fuc_base + 0x0188, i >> 6); + nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]); + } + release_firmware(fw); + + return 0; +} + +static int +nvc0_graph_init_ctxctl(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + u32 r000260; + int ret; + + /* load fuc microcode */ + r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); + ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d"); + if (ret == 0) + nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad"); + nv_wr32(dev, 0x000260, r000260); + + if (ret) + return ret; + + /* start both of them running */ + nv_wr32(dev, 0x409840, 0xffffffff); + nv_wr32(dev, 0x41a10c, 0x00000000); + nv_wr32(dev, 0x40910c, 0x00000000); + nv_wr32(dev, 0x41a100, 0x00000002); + nv_wr32(dev, 0x409100, 0x00000002); + if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001)) + NV_INFO(dev, "0x409800 wait failed\n"); + + nv_wr32(dev, 0x409840, 0xffffffff); + nv_wr32(dev, 0x409500, 0x7fffffff); + nv_wr32(dev, 0x409504, 0x00000021); + + nv_wr32(dev, 0x409840, 0xffffffff); + nv_wr32(dev, 0x409500, 0x00000000); + nv_wr32(dev, 0x409504, 0x00000010); + if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { + NV_ERROR(dev, "fuc09 req 0x10 timeout\n"); + return -EBUSY; + } + priv->grctx_size = nv_rd32(dev, 0x409800); + + nv_wr32(dev, 0x409840, 0xffffffff); + nv_wr32(dev, 0x409500, 0x00000000); + nv_wr32(dev, 0x409504, 0x00000016); + if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { + NV_ERROR(dev, "fuc09 req 0x16 timeout\n"); + return -EBUSY; + } + + nv_wr32(dev, 0x409840, 0xffffffff); + nv_wr32(dev, 0x409500, 0x00000000); + nv_wr32(dev, 0x409504, 0x00000025); + if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { + NV_ERROR(dev, "fuc09 req 0x25 timeout\n"); + return -EBUSY; + } + + return 0; } int nvc0_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nvc0_graph_priv *priv; + int ret; + dev_priv->engine.graph.accel_blocked = true; + + switch (dev_priv->chipset) { + case 0xc0: + case 0xc3: + case 0xc4: + break; + default: + NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n"); + if (nouveau_noaccel != 0) + return 0; + break; + } + + nv_mask(dev, 0x000200, 0x18001000, 0x00000000); + nv_mask(dev, 0x000200, 0x18001000, 0x18001000); + + if (!pgraph->priv) { + ret = nvc0_graph_create(dev); + if (ret) + return ret; + } + priv = pgraph->priv; + + nvc0_graph_init_obj418880(dev); + nvc0_graph_init_regs(dev); + //nvc0_graph_init_unitplemented_magics(dev); + nvc0_graph_init_gpc_0(dev); + //nvc0_graph_init_unitplemented_c242(dev); + + nv_wr32(dev, 0x400500, 0x00010001); + nv_wr32(dev, 0x400100, 0xffffffff); + nv_wr32(dev, 0x40013c, 0xffffffff); + + nvc0_graph_init_units(dev); + nvc0_graph_init_gpc_1(dev); + nvc0_graph_init_rop(dev); + + nv_wr32(dev, 0x400108, 0xffffffff); + nv_wr32(dev, 0x400138, 0xffffffff); + nv_wr32(dev, 0x400118, 0xffffffff); + nv_wr32(dev, 0x400130, 0xffffffff); + nv_wr32(dev, 0x40011c, 0xffffffff); + nv_wr32(dev, 0x400134, 0xffffffff); + nv_wr32(dev, 0x400054, 0x34ce3464); + + ret = nvc0_graph_init_ctxctl(dev); + if (ret) + return ret; + + dev_priv->engine.graph.accel_blocked = false; return 0; } +static struct nouveau_enum nvc0_graph_data_error[] = { + { 5, "INVALID_ENUM" }, + {} +}; + +static int +nvc0_graph_isr_chid(struct drm_device *dev, u64 inst) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; + unsigned long flags; + int i; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); + for (i = 0; i < dev_priv->engine.fifo.channels; i++) { + chan = dev_priv->channels.ptr[i]; + if (!chan || !chan->ramin) + continue; + + if (inst == chan->ramin->vinst) + break; + } + spin_unlock_irqrestore(&dev_priv->channels.lock, flags); + return i; +} + +static void +nvc0_graph_isr(struct drm_device *dev) +{ + u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; + u32 chid = nvc0_graph_isr_chid(dev, inst); + u32 stat = nv_rd32(dev, 0x400100); + u32 addr = nv_rd32(dev, 0x400704); + u32 mthd = (addr & 0x00003ffc); + u32 subc = (addr & 0x00070000) >> 16; + u32 data = nv_rd32(dev, 0x400708); + u32 code = nv_rd32(dev, 0x400110); + u32 class = nv_rd32(dev, 0x404200 + (subc * 4)); + + if (stat & 0x00000010) { + NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + chid, inst, subc, class, mthd, data); + nv_wr32(dev, 0x400100, 0x00000010); + stat &= ~0x00000010; + } + + if (stat & 0x00100000) { + NV_INFO(dev, "PGRAPH: DATA_ERROR ["); + nouveau_enum_print(nvc0_graph_data_error, code); + printk("] ch %d [0x%010llx] subc %d class 0x%04x " + "mthd 0x%04x data 0x%08x\n", + chid, inst, subc, class, mthd, data); + nv_wr32(dev, 0x400100, 0x00100000); + stat &= ~0x00100000; + } + + if (stat & 0x00080000) { + u32 ustat = nv_rd32(dev, 0x409c18); + + NV_INFO(dev, "PGRAPH: CTXCTRL ustat 0x%08x\n", ustat); + + nv_wr32(dev, 0x409c20, ustat); + nv_wr32(dev, 0x400100, 0x00080000); + stat &= ~0x00080000; + } + + if (stat) { + NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat); + nv_wr32(dev, 0x400100, stat); + } + + nv_wr32(dev, 0x400500, 0x00010001); +} diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h new file mode 100644 index 000000000000..1e1f24f3fd34 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_graph.h @@ -0,0 +1,66 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#ifndef __NVC0_GRAPH_H__ +#define __NVC0_GRAPH_H__ + +#define GPC_MAX 4 +#define TP_MAX 32 + +#define ROP_BCAST(r) (0x408800 + (r)) +#define ROP_UNIT(u,r) (0x410000 + (u) * 0x400 + (r)) +#define GPC_BCAST(r) (0x418000 + (r)) +#define GPC_UNIT(t,r) (0x500000 + (t) * 0x8000 + (r)) +#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) + +struct nvc0_graph_priv { + u8 gpc_nr; + u8 rop_nr; + u8 tp_nr[GPC_MAX]; + u8 tp_total; + + u32 grctx_size; + u32 *grctx_vals; + struct nouveau_gpuobj *unk4188b4; + struct nouveau_gpuobj *unk4188b8; + + u8 magic_not_rop_nr; + u32 magic419bd0; + u32 magic419be4; + u32 magicgpc980[4]; + u32 magicgpc918; +}; + +struct nvc0_graph_chan { + struct nouveau_gpuobj *grctx; + struct nouveau_gpuobj *unk408004; // 0x418810 too + struct nouveau_gpuobj *unk40800c; // 0x419004 too + struct nouveau_gpuobj *unk418810; // 0x419848 too + struct nouveau_gpuobj *mmio; + int mmio_nr; +}; + +int nvc0_grctx_generate(struct nouveau_channel *); + +#endif diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c new file mode 100644 index 000000000000..88fa6211ac19 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -0,0 +1,2854 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_mm.h" +#include "nvc0_graph.h" + +static void +nv_icmd(struct drm_device *dev, u32 icmd, u32 data) +{ + nv_wr32(dev, 0x400204, data); + nv_wr32(dev, 0x400200, icmd); + while (nv_rd32(dev, 0x400700) & 2) {} +} + +static void +nv_mthd(struct drm_device *dev, u32 class, u32 mthd, u32 data) +{ + nv_wr32(dev, 0x40448c, data); + nv_wr32(dev, 0x404488, 0x80000000 | (mthd << 14) | class); +} + +static void +nvc0_grctx_generate_9097(struct drm_device *dev) +{ + nv_mthd(dev, 0x9097, 0x0800, 0x00000000); + nv_mthd(dev, 0x9097, 0x0840, 0x00000000); + nv_mthd(dev, 0x9097, 0x0880, 0x00000000); + nv_mthd(dev, 0x9097, 0x08c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0900, 0x00000000); + nv_mthd(dev, 0x9097, 0x0940, 0x00000000); + nv_mthd(dev, 0x9097, 0x0980, 0x00000000); + nv_mthd(dev, 0x9097, 0x09c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0804, 0x00000000); + nv_mthd(dev, 0x9097, 0x0844, 0x00000000); + nv_mthd(dev, 0x9097, 0x0884, 0x00000000); + nv_mthd(dev, 0x9097, 0x08c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0904, 0x00000000); + nv_mthd(dev, 0x9097, 0x0944, 0x00000000); + nv_mthd(dev, 0x9097, 0x0984, 0x00000000); + nv_mthd(dev, 0x9097, 0x09c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0808, 0x00000400); + nv_mthd(dev, 0x9097, 0x0848, 0x00000400); + nv_mthd(dev, 0x9097, 0x0888, 0x00000400); + nv_mthd(dev, 0x9097, 0x08c8, 0x00000400); + nv_mthd(dev, 0x9097, 0x0908, 0x00000400); + nv_mthd(dev, 0x9097, 0x0948, 0x00000400); + nv_mthd(dev, 0x9097, 0x0988, 0x00000400); + nv_mthd(dev, 0x9097, 0x09c8, 0x00000400); + nv_mthd(dev, 0x9097, 0x080c, 0x00000300); + nv_mthd(dev, 0x9097, 0x084c, 0x00000300); + nv_mthd(dev, 0x9097, 0x088c, 0x00000300); + nv_mthd(dev, 0x9097, 0x08cc, 0x00000300); + nv_mthd(dev, 0x9097, 0x090c, 0x00000300); + nv_mthd(dev, 0x9097, 0x094c, 0x00000300); + nv_mthd(dev, 0x9097, 0x098c, 0x00000300); + nv_mthd(dev, 0x9097, 0x09cc, 0x00000300); + nv_mthd(dev, 0x9097, 0x0810, 0x000000cf); + nv_mthd(dev, 0x9097, 0x0850, 0x00000000); + nv_mthd(dev, 0x9097, 0x0890, 0x00000000); + nv_mthd(dev, 0x9097, 0x08d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0910, 0x00000000); + nv_mthd(dev, 0x9097, 0x0950, 0x00000000); + nv_mthd(dev, 0x9097, 0x0990, 0x00000000); + nv_mthd(dev, 0x9097, 0x09d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0814, 0x00000040); + nv_mthd(dev, 0x9097, 0x0854, 0x00000040); + nv_mthd(dev, 0x9097, 0x0894, 0x00000040); + nv_mthd(dev, 0x9097, 0x08d4, 0x00000040); + nv_mthd(dev, 0x9097, 0x0914, 0x00000040); + nv_mthd(dev, 0x9097, 0x0954, 0x00000040); + nv_mthd(dev, 0x9097, 0x0994, 0x00000040); + nv_mthd(dev, 0x9097, 0x09d4, 0x00000040); + nv_mthd(dev, 0x9097, 0x0818, 0x00000001); + nv_mthd(dev, 0x9097, 0x0858, 0x00000001); + nv_mthd(dev, 0x9097, 0x0898, 0x00000001); + nv_mthd(dev, 0x9097, 0x08d8, 0x00000001); + nv_mthd(dev, 0x9097, 0x0918, 0x00000001); + nv_mthd(dev, 0x9097, 0x0958, 0x00000001); + nv_mthd(dev, 0x9097, 0x0998, 0x00000001); + nv_mthd(dev, 0x9097, 0x09d8, 0x00000001); + nv_mthd(dev, 0x9097, 0x081c, 0x00000000); + nv_mthd(dev, 0x9097, 0x085c, 0x00000000); + nv_mthd(dev, 0x9097, 0x089c, 0x00000000); + nv_mthd(dev, 0x9097, 0x08dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x091c, 0x00000000); + nv_mthd(dev, 0x9097, 0x095c, 0x00000000); + nv_mthd(dev, 0x9097, 0x099c, 0x00000000); + nv_mthd(dev, 0x9097, 0x09dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0820, 0x00000000); + nv_mthd(dev, 0x9097, 0x0860, 0x00000000); + nv_mthd(dev, 0x9097, 0x08a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x08e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0920, 0x00000000); + nv_mthd(dev, 0x9097, 0x0960, 0x00000000); + nv_mthd(dev, 0x9097, 0x09a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x09e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x2700, 0x00000000); + nv_mthd(dev, 0x9097, 0x2720, 0x00000000); + nv_mthd(dev, 0x9097, 0x2740, 0x00000000); + nv_mthd(dev, 0x9097, 0x2760, 0x00000000); + nv_mthd(dev, 0x9097, 0x2780, 0x00000000); + nv_mthd(dev, 0x9097, 0x27a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x27c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x27e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x2704, 0x00000000); + nv_mthd(dev, 0x9097, 0x2724, 0x00000000); + nv_mthd(dev, 0x9097, 0x2744, 0x00000000); + nv_mthd(dev, 0x9097, 0x2764, 0x00000000); + nv_mthd(dev, 0x9097, 0x2784, 0x00000000); + nv_mthd(dev, 0x9097, 0x27a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x27c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x27e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x2708, 0x00000000); + nv_mthd(dev, 0x9097, 0x2728, 0x00000000); + nv_mthd(dev, 0x9097, 0x2748, 0x00000000); + nv_mthd(dev, 0x9097, 0x2768, 0x00000000); + nv_mthd(dev, 0x9097, 0x2788, 0x00000000); + nv_mthd(dev, 0x9097, 0x27a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x27c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x27e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x270c, 0x00000000); + nv_mthd(dev, 0x9097, 0x272c, 0x00000000); + nv_mthd(dev, 0x9097, 0x274c, 0x00000000); + nv_mthd(dev, 0x9097, 0x276c, 0x00000000); + nv_mthd(dev, 0x9097, 0x278c, 0x00000000); + nv_mthd(dev, 0x9097, 0x27ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x27cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x27ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x2710, 0x00014000); + nv_mthd(dev, 0x9097, 0x2730, 0x00014000); + nv_mthd(dev, 0x9097, 0x2750, 0x00014000); + nv_mthd(dev, 0x9097, 0x2770, 0x00014000); + nv_mthd(dev, 0x9097, 0x2790, 0x00014000); + nv_mthd(dev, 0x9097, 0x27b0, 0x00014000); + nv_mthd(dev, 0x9097, 0x27d0, 0x00014000); + nv_mthd(dev, 0x9097, 0x27f0, 0x00014000); + nv_mthd(dev, 0x9097, 0x2714, 0x00000040); + nv_mthd(dev, 0x9097, 0x2734, 0x00000040); + nv_mthd(dev, 0x9097, 0x2754, 0x00000040); + nv_mthd(dev, 0x9097, 0x2774, 0x00000040); + nv_mthd(dev, 0x9097, 0x2794, 0x00000040); + nv_mthd(dev, 0x9097, 0x27b4, 0x00000040); + nv_mthd(dev, 0x9097, 0x27d4, 0x00000040); + nv_mthd(dev, 0x9097, 0x27f4, 0x00000040); + nv_mthd(dev, 0x9097, 0x1c00, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c10, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c20, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c30, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c40, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c50, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c60, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c70, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c80, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c90, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ca0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cb0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cc0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cd0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ce0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cf0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c04, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c14, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c24, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c34, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c44, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c54, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c64, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c74, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c84, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c94, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ca4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cb4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cc4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cd4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ce4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cf4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c08, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c18, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c28, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c38, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c48, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c58, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c68, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c78, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c88, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c98, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ca8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cb8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cc8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cd8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ce8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cf8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c0c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c1c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c2c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c3c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c4c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c5c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c6c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c7c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1c9c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cac, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cbc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ccc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cdc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cec, 0x00000000); + nv_mthd(dev, 0x9097, 0x1cfc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d00, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d10, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d20, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d30, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d40, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d50, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d60, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d70, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d80, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d90, 0x00000000); + nv_mthd(dev, 0x9097, 0x1da0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1db0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dc0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dd0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1de0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1df0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d04, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d14, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d24, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d34, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d44, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d54, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d64, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d74, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d84, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d94, 0x00000000); + nv_mthd(dev, 0x9097, 0x1da4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1db4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dc4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dd4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1de4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1df4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d08, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d18, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d28, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d38, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d48, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d58, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d68, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d78, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d88, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d98, 0x00000000); + nv_mthd(dev, 0x9097, 0x1da8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1db8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dc8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dd8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1de8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1df8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d0c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d1c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d2c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d3c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d4c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d5c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d6c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d7c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1d9c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dac, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dbc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dcc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ddc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dec, 0x00000000); + nv_mthd(dev, 0x9097, 0x1dfc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f00, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f08, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f10, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f18, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f20, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f28, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f30, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f38, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f40, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f48, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f50, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f58, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f60, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f68, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f70, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f78, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f04, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f0c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f14, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f1c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f24, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f2c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f34, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f3c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f44, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f4c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f54, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f5c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f64, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f6c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f74, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f7c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f80, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f88, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f90, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f98, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fa0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fa8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fb0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fb8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fc0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fc8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fd0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fd8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fe0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fe8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ff0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ff8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f84, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f94, 0x00000000); + nv_mthd(dev, 0x9097, 0x1f9c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fa4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fac, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fb4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fbc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fc4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fcc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fd4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fdc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fe4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1fec, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ff4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1ffc, 0x00000000); + nv_mthd(dev, 0x9097, 0x2200, 0x00000022); + nv_mthd(dev, 0x9097, 0x2210, 0x00000022); + nv_mthd(dev, 0x9097, 0x2220, 0x00000022); + nv_mthd(dev, 0x9097, 0x2230, 0x00000022); + nv_mthd(dev, 0x9097, 0x2240, 0x00000022); + nv_mthd(dev, 0x9097, 0x2000, 0x00000000); + nv_mthd(dev, 0x9097, 0x2040, 0x00000011); + nv_mthd(dev, 0x9097, 0x2080, 0x00000020); + nv_mthd(dev, 0x9097, 0x20c0, 0x00000030); + nv_mthd(dev, 0x9097, 0x2100, 0x00000040); + nv_mthd(dev, 0x9097, 0x2140, 0x00000051); + nv_mthd(dev, 0x9097, 0x200c, 0x00000001); + nv_mthd(dev, 0x9097, 0x204c, 0x00000001); + nv_mthd(dev, 0x9097, 0x208c, 0x00000001); + nv_mthd(dev, 0x9097, 0x20cc, 0x00000001); + nv_mthd(dev, 0x9097, 0x210c, 0x00000001); + nv_mthd(dev, 0x9097, 0x214c, 0x00000001); + nv_mthd(dev, 0x9097, 0x2010, 0x00000000); + nv_mthd(dev, 0x9097, 0x2050, 0x00000000); + nv_mthd(dev, 0x9097, 0x2090, 0x00000001); + nv_mthd(dev, 0x9097, 0x20d0, 0x00000002); + nv_mthd(dev, 0x9097, 0x2110, 0x00000003); + nv_mthd(dev, 0x9097, 0x2150, 0x00000004); + nv_mthd(dev, 0x9097, 0x0380, 0x00000000); + nv_mthd(dev, 0x9097, 0x03a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x03c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x03e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0384, 0x00000000); + nv_mthd(dev, 0x9097, 0x03a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x03c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x03e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0388, 0x00000000); + nv_mthd(dev, 0x9097, 0x03a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x03c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x03e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x038c, 0x00000000); + nv_mthd(dev, 0x9097, 0x03ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x03cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x03ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x0700, 0x00000000); + nv_mthd(dev, 0x9097, 0x0710, 0x00000000); + nv_mthd(dev, 0x9097, 0x0720, 0x00000000); + nv_mthd(dev, 0x9097, 0x0730, 0x00000000); + nv_mthd(dev, 0x9097, 0x0704, 0x00000000); + nv_mthd(dev, 0x9097, 0x0714, 0x00000000); + nv_mthd(dev, 0x9097, 0x0724, 0x00000000); + nv_mthd(dev, 0x9097, 0x0734, 0x00000000); + nv_mthd(dev, 0x9097, 0x0708, 0x00000000); + nv_mthd(dev, 0x9097, 0x0718, 0x00000000); + nv_mthd(dev, 0x9097, 0x0728, 0x00000000); + nv_mthd(dev, 0x9097, 0x0738, 0x00000000); + nv_mthd(dev, 0x9097, 0x2800, 0x00000000); + nv_mthd(dev, 0x9097, 0x2804, 0x00000000); + nv_mthd(dev, 0x9097, 0x2808, 0x00000000); + nv_mthd(dev, 0x9097, 0x280c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2810, 0x00000000); + nv_mthd(dev, 0x9097, 0x2814, 0x00000000); + nv_mthd(dev, 0x9097, 0x2818, 0x00000000); + nv_mthd(dev, 0x9097, 0x281c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2820, 0x00000000); + nv_mthd(dev, 0x9097, 0x2824, 0x00000000); + nv_mthd(dev, 0x9097, 0x2828, 0x00000000); + nv_mthd(dev, 0x9097, 0x282c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2830, 0x00000000); + nv_mthd(dev, 0x9097, 0x2834, 0x00000000); + nv_mthd(dev, 0x9097, 0x2838, 0x00000000); + nv_mthd(dev, 0x9097, 0x283c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2840, 0x00000000); + nv_mthd(dev, 0x9097, 0x2844, 0x00000000); + nv_mthd(dev, 0x9097, 0x2848, 0x00000000); + nv_mthd(dev, 0x9097, 0x284c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2850, 0x00000000); + nv_mthd(dev, 0x9097, 0x2854, 0x00000000); + nv_mthd(dev, 0x9097, 0x2858, 0x00000000); + nv_mthd(dev, 0x9097, 0x285c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2860, 0x00000000); + nv_mthd(dev, 0x9097, 0x2864, 0x00000000); + nv_mthd(dev, 0x9097, 0x2868, 0x00000000); + nv_mthd(dev, 0x9097, 0x286c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2870, 0x00000000); + nv_mthd(dev, 0x9097, 0x2874, 0x00000000); + nv_mthd(dev, 0x9097, 0x2878, 0x00000000); + nv_mthd(dev, 0x9097, 0x287c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2880, 0x00000000); + nv_mthd(dev, 0x9097, 0x2884, 0x00000000); + nv_mthd(dev, 0x9097, 0x2888, 0x00000000); + nv_mthd(dev, 0x9097, 0x288c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2890, 0x00000000); + nv_mthd(dev, 0x9097, 0x2894, 0x00000000); + nv_mthd(dev, 0x9097, 0x2898, 0x00000000); + nv_mthd(dev, 0x9097, 0x289c, 0x00000000); + nv_mthd(dev, 0x9097, 0x28a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x28a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x28a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x28ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x28b0, 0x00000000); + nv_mthd(dev, 0x9097, 0x28b4, 0x00000000); + nv_mthd(dev, 0x9097, 0x28b8, 0x00000000); + nv_mthd(dev, 0x9097, 0x28bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x28c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x28c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x28c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x28cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x28d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x28d4, 0x00000000); + nv_mthd(dev, 0x9097, 0x28d8, 0x00000000); + nv_mthd(dev, 0x9097, 0x28dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x28e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x28e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x28e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x28ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x28f0, 0x00000000); + nv_mthd(dev, 0x9097, 0x28f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x28f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x28fc, 0x00000000); + nv_mthd(dev, 0x9097, 0x2900, 0x00000000); + nv_mthd(dev, 0x9097, 0x2904, 0x00000000); + nv_mthd(dev, 0x9097, 0x2908, 0x00000000); + nv_mthd(dev, 0x9097, 0x290c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2910, 0x00000000); + nv_mthd(dev, 0x9097, 0x2914, 0x00000000); + nv_mthd(dev, 0x9097, 0x2918, 0x00000000); + nv_mthd(dev, 0x9097, 0x291c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2920, 0x00000000); + nv_mthd(dev, 0x9097, 0x2924, 0x00000000); + nv_mthd(dev, 0x9097, 0x2928, 0x00000000); + nv_mthd(dev, 0x9097, 0x292c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2930, 0x00000000); + nv_mthd(dev, 0x9097, 0x2934, 0x00000000); + nv_mthd(dev, 0x9097, 0x2938, 0x00000000); + nv_mthd(dev, 0x9097, 0x293c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2940, 0x00000000); + nv_mthd(dev, 0x9097, 0x2944, 0x00000000); + nv_mthd(dev, 0x9097, 0x2948, 0x00000000); + nv_mthd(dev, 0x9097, 0x294c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2950, 0x00000000); + nv_mthd(dev, 0x9097, 0x2954, 0x00000000); + nv_mthd(dev, 0x9097, 0x2958, 0x00000000); + nv_mthd(dev, 0x9097, 0x295c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2960, 0x00000000); + nv_mthd(dev, 0x9097, 0x2964, 0x00000000); + nv_mthd(dev, 0x9097, 0x2968, 0x00000000); + nv_mthd(dev, 0x9097, 0x296c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2970, 0x00000000); + nv_mthd(dev, 0x9097, 0x2974, 0x00000000); + nv_mthd(dev, 0x9097, 0x2978, 0x00000000); + nv_mthd(dev, 0x9097, 0x297c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2980, 0x00000000); + nv_mthd(dev, 0x9097, 0x2984, 0x00000000); + nv_mthd(dev, 0x9097, 0x2988, 0x00000000); + nv_mthd(dev, 0x9097, 0x298c, 0x00000000); + nv_mthd(dev, 0x9097, 0x2990, 0x00000000); + nv_mthd(dev, 0x9097, 0x2994, 0x00000000); + nv_mthd(dev, 0x9097, 0x2998, 0x00000000); + nv_mthd(dev, 0x9097, 0x299c, 0x00000000); + nv_mthd(dev, 0x9097, 0x29a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x29a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x29a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x29ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x29b0, 0x00000000); + nv_mthd(dev, 0x9097, 0x29b4, 0x00000000); + nv_mthd(dev, 0x9097, 0x29b8, 0x00000000); + nv_mthd(dev, 0x9097, 0x29bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x29c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x29c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x29c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x29cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x29d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x29d4, 0x00000000); + nv_mthd(dev, 0x9097, 0x29d8, 0x00000000); + nv_mthd(dev, 0x9097, 0x29dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x29e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x29e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x29e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x29ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x29f0, 0x00000000); + nv_mthd(dev, 0x9097, 0x29f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x29f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x29fc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a00, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a20, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a40, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a60, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a80, 0x00000000); + nv_mthd(dev, 0x9097, 0x0aa0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ac0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ae0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b00, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b20, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b40, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b60, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b80, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ba0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bc0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0be0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a04, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a24, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a44, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a64, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a84, 0x00000000); + nv_mthd(dev, 0x9097, 0x0aa4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ac4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ae4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b04, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b24, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b44, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b64, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b84, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ba4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bc4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0be4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a08, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a28, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a48, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a68, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a88, 0x00000000); + nv_mthd(dev, 0x9097, 0x0aa8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ac8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ae8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b08, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b28, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b48, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b68, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b88, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ba8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bc8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0be8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a0c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a2c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a4c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a6c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0aac, 0x00000000); + nv_mthd(dev, 0x9097, 0x0acc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0aec, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b0c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b2c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b4c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b6c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bac, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bcc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bec, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a10, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a30, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a50, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a70, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a90, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ab0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ad0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0af0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b10, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b30, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b50, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b70, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b90, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bb0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bd0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bf0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a14, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a34, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a54, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a74, 0x00000000); + nv_mthd(dev, 0x9097, 0x0a94, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ab4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ad4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0af4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b14, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b34, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b54, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b74, 0x00000000); + nv_mthd(dev, 0x9097, 0x0b94, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bb4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bd4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0bf4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c00, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c10, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c20, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c30, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c40, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c50, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c60, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c70, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c80, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c90, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ca0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cb0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cc0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cd0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ce0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cf0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c04, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c14, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c24, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c34, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c44, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c54, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c64, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c74, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c84, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c94, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ca4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cb4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cc4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cd4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ce4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cf4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c08, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c18, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c28, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c38, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c48, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c58, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c68, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c78, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c88, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c98, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ca8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cb8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cc8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cd8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ce8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0cf8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0c0c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c1c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c2c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c3c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c4c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c5c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c6c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c7c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c8c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0c9c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0cac, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0cbc, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0ccc, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0cdc, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0cec, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0cfc, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0d00, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d08, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d10, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d18, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d20, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d28, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d30, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d38, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d04, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d0c, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d14, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d1c, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d24, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d2c, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d34, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d3c, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e00, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e10, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e20, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e30, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e40, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e50, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e60, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e70, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e80, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e90, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ea0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0eb0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ec0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ed0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ee0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ef0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0e04, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e14, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e24, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e34, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e44, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e54, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e64, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e74, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e84, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e94, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ea4, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0eb4, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ec4, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ed4, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ee4, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ef4, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e08, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e18, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e28, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e38, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e48, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e58, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e68, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e78, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e88, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0e98, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ea8, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0eb8, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ec8, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ed8, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ee8, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0ef8, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d40, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d48, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d50, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d58, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d44, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d4c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d54, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d5c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1e00, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e20, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e40, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e60, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e80, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ea0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ec0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ee0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e04, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e24, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e44, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e64, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e84, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ea4, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ec4, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ee4, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e08, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e28, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e48, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e68, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e88, 0x00000002); + nv_mthd(dev, 0x9097, 0x1ea8, 0x00000002); + nv_mthd(dev, 0x9097, 0x1ec8, 0x00000002); + nv_mthd(dev, 0x9097, 0x1ee8, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e0c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e2c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e4c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e6c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e8c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1eac, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ecc, 0x00000001); + nv_mthd(dev, 0x9097, 0x1eec, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e10, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e30, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e50, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e70, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e90, 0x00000001); + nv_mthd(dev, 0x9097, 0x1eb0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ed0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ef0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e14, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e34, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e54, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e74, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e94, 0x00000002); + nv_mthd(dev, 0x9097, 0x1eb4, 0x00000002); + nv_mthd(dev, 0x9097, 0x1ed4, 0x00000002); + nv_mthd(dev, 0x9097, 0x1ef4, 0x00000002); + nv_mthd(dev, 0x9097, 0x1e18, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e38, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e58, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e78, 0x00000001); + nv_mthd(dev, 0x9097, 0x1e98, 0x00000001); + nv_mthd(dev, 0x9097, 0x1eb8, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ed8, 0x00000001); + nv_mthd(dev, 0x9097, 0x1ef8, 0x00000001); + nv_mthd(dev, 0x9097, 0x3400, 0x00000000); + nv_mthd(dev, 0x9097, 0x3404, 0x00000000); + nv_mthd(dev, 0x9097, 0x3408, 0x00000000); + nv_mthd(dev, 0x9097, 0x340c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3410, 0x00000000); + nv_mthd(dev, 0x9097, 0x3414, 0x00000000); + nv_mthd(dev, 0x9097, 0x3418, 0x00000000); + nv_mthd(dev, 0x9097, 0x341c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3420, 0x00000000); + nv_mthd(dev, 0x9097, 0x3424, 0x00000000); + nv_mthd(dev, 0x9097, 0x3428, 0x00000000); + nv_mthd(dev, 0x9097, 0x342c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3430, 0x00000000); + nv_mthd(dev, 0x9097, 0x3434, 0x00000000); + nv_mthd(dev, 0x9097, 0x3438, 0x00000000); + nv_mthd(dev, 0x9097, 0x343c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3440, 0x00000000); + nv_mthd(dev, 0x9097, 0x3444, 0x00000000); + nv_mthd(dev, 0x9097, 0x3448, 0x00000000); + nv_mthd(dev, 0x9097, 0x344c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3450, 0x00000000); + nv_mthd(dev, 0x9097, 0x3454, 0x00000000); + nv_mthd(dev, 0x9097, 0x3458, 0x00000000); + nv_mthd(dev, 0x9097, 0x345c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3460, 0x00000000); + nv_mthd(dev, 0x9097, 0x3464, 0x00000000); + nv_mthd(dev, 0x9097, 0x3468, 0x00000000); + nv_mthd(dev, 0x9097, 0x346c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3470, 0x00000000); + nv_mthd(dev, 0x9097, 0x3474, 0x00000000); + nv_mthd(dev, 0x9097, 0x3478, 0x00000000); + nv_mthd(dev, 0x9097, 0x347c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3480, 0x00000000); + nv_mthd(dev, 0x9097, 0x3484, 0x00000000); + nv_mthd(dev, 0x9097, 0x3488, 0x00000000); + nv_mthd(dev, 0x9097, 0x348c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3490, 0x00000000); + nv_mthd(dev, 0x9097, 0x3494, 0x00000000); + nv_mthd(dev, 0x9097, 0x3498, 0x00000000); + nv_mthd(dev, 0x9097, 0x349c, 0x00000000); + nv_mthd(dev, 0x9097, 0x34a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x34a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x34a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x34ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x34b0, 0x00000000); + nv_mthd(dev, 0x9097, 0x34b4, 0x00000000); + nv_mthd(dev, 0x9097, 0x34b8, 0x00000000); + nv_mthd(dev, 0x9097, 0x34bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x34c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x34c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x34c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x34cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x34d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x34d4, 0x00000000); + nv_mthd(dev, 0x9097, 0x34d8, 0x00000000); + nv_mthd(dev, 0x9097, 0x34dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x34e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x34e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x34e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x34ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x34f0, 0x00000000); + nv_mthd(dev, 0x9097, 0x34f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x34f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x34fc, 0x00000000); + nv_mthd(dev, 0x9097, 0x3500, 0x00000000); + nv_mthd(dev, 0x9097, 0x3504, 0x00000000); + nv_mthd(dev, 0x9097, 0x3508, 0x00000000); + nv_mthd(dev, 0x9097, 0x350c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3510, 0x00000000); + nv_mthd(dev, 0x9097, 0x3514, 0x00000000); + nv_mthd(dev, 0x9097, 0x3518, 0x00000000); + nv_mthd(dev, 0x9097, 0x351c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3520, 0x00000000); + nv_mthd(dev, 0x9097, 0x3524, 0x00000000); + nv_mthd(dev, 0x9097, 0x3528, 0x00000000); + nv_mthd(dev, 0x9097, 0x352c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3530, 0x00000000); + nv_mthd(dev, 0x9097, 0x3534, 0x00000000); + nv_mthd(dev, 0x9097, 0x3538, 0x00000000); + nv_mthd(dev, 0x9097, 0x353c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3540, 0x00000000); + nv_mthd(dev, 0x9097, 0x3544, 0x00000000); + nv_mthd(dev, 0x9097, 0x3548, 0x00000000); + nv_mthd(dev, 0x9097, 0x354c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3550, 0x00000000); + nv_mthd(dev, 0x9097, 0x3554, 0x00000000); + nv_mthd(dev, 0x9097, 0x3558, 0x00000000); + nv_mthd(dev, 0x9097, 0x355c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3560, 0x00000000); + nv_mthd(dev, 0x9097, 0x3564, 0x00000000); + nv_mthd(dev, 0x9097, 0x3568, 0x00000000); + nv_mthd(dev, 0x9097, 0x356c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3570, 0x00000000); + nv_mthd(dev, 0x9097, 0x3574, 0x00000000); + nv_mthd(dev, 0x9097, 0x3578, 0x00000000); + nv_mthd(dev, 0x9097, 0x357c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3580, 0x00000000); + nv_mthd(dev, 0x9097, 0x3584, 0x00000000); + nv_mthd(dev, 0x9097, 0x3588, 0x00000000); + nv_mthd(dev, 0x9097, 0x358c, 0x00000000); + nv_mthd(dev, 0x9097, 0x3590, 0x00000000); + nv_mthd(dev, 0x9097, 0x3594, 0x00000000); + nv_mthd(dev, 0x9097, 0x3598, 0x00000000); + nv_mthd(dev, 0x9097, 0x359c, 0x00000000); + nv_mthd(dev, 0x9097, 0x35a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x35a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x35a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x35ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x35b0, 0x00000000); + nv_mthd(dev, 0x9097, 0x35b4, 0x00000000); + nv_mthd(dev, 0x9097, 0x35b8, 0x00000000); + nv_mthd(dev, 0x9097, 0x35bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x35c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x35c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x35c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x35cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x35d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x35d4, 0x00000000); + nv_mthd(dev, 0x9097, 0x35d8, 0x00000000); + nv_mthd(dev, 0x9097, 0x35dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x35e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x35e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x35e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x35ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x35f0, 0x00000000); + nv_mthd(dev, 0x9097, 0x35f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x35f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x35fc, 0x00000000); + nv_mthd(dev, 0x9097, 0x030c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1944, 0x00000000); + nv_mthd(dev, 0x9097, 0x1514, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d68, 0x0000ffff); + nv_mthd(dev, 0x9097, 0x121c, 0x0fac6881); + nv_mthd(dev, 0x9097, 0x0fac, 0x00000001); + nv_mthd(dev, 0x9097, 0x1538, 0x00000001); + nv_mthd(dev, 0x9097, 0x0fe0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0fe4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0fe8, 0x00000014); + nv_mthd(dev, 0x9097, 0x0fec, 0x00000040); + nv_mthd(dev, 0x9097, 0x0ff0, 0x00000000); + nv_mthd(dev, 0x9097, 0x179c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1228, 0x00000400); + nv_mthd(dev, 0x9097, 0x122c, 0x00000300); + nv_mthd(dev, 0x9097, 0x1230, 0x00010001); + nv_mthd(dev, 0x9097, 0x07f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x15b4, 0x00000001); + nv_mthd(dev, 0x9097, 0x15cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1534, 0x00000000); + nv_mthd(dev, 0x9097, 0x0fb0, 0x00000000); + nv_mthd(dev, 0x9097, 0x15d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x153c, 0x00000000); + nv_mthd(dev, 0x9097, 0x16b4, 0x00000003); + nv_mthd(dev, 0x9097, 0x0fbc, 0x0000ffff); + nv_mthd(dev, 0x9097, 0x0fc0, 0x0000ffff); + nv_mthd(dev, 0x9097, 0x0fc4, 0x0000ffff); + nv_mthd(dev, 0x9097, 0x0fc8, 0x0000ffff); + nv_mthd(dev, 0x9097, 0x0df8, 0x00000000); + nv_mthd(dev, 0x9097, 0x0dfc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1948, 0x00000000); + nv_mthd(dev, 0x9097, 0x1970, 0x00000001); + nv_mthd(dev, 0x9097, 0x161c, 0x000009f0); + nv_mthd(dev, 0x9097, 0x0dcc, 0x00000010); + nv_mthd(dev, 0x9097, 0x163c, 0x00000000); + nv_mthd(dev, 0x9097, 0x15e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1160, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1164, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1168, 0x25e00040); + nv_mthd(dev, 0x9097, 0x116c, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1170, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1174, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1178, 0x25e00040); + nv_mthd(dev, 0x9097, 0x117c, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1180, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1184, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1188, 0x25e00040); + nv_mthd(dev, 0x9097, 0x118c, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1190, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1194, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1198, 0x25e00040); + nv_mthd(dev, 0x9097, 0x119c, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11a0, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11a4, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11a8, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11ac, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11b0, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11b4, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11b8, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11bc, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11c0, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11c4, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11c8, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11cc, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11d0, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11d4, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11d8, 0x25e00040); + nv_mthd(dev, 0x9097, 0x11dc, 0x25e00040); + nv_mthd(dev, 0x9097, 0x1880, 0x00000000); + nv_mthd(dev, 0x9097, 0x1884, 0x00000000); + nv_mthd(dev, 0x9097, 0x1888, 0x00000000); + nv_mthd(dev, 0x9097, 0x188c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1890, 0x00000000); + nv_mthd(dev, 0x9097, 0x1894, 0x00000000); + nv_mthd(dev, 0x9097, 0x1898, 0x00000000); + nv_mthd(dev, 0x9097, 0x189c, 0x00000000); + nv_mthd(dev, 0x9097, 0x18a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x18a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x18a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x18ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x18b0, 0x00000000); + nv_mthd(dev, 0x9097, 0x18b4, 0x00000000); + nv_mthd(dev, 0x9097, 0x18b8, 0x00000000); + nv_mthd(dev, 0x9097, 0x18bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x18c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x18c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x18c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x18cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x18d0, 0x00000000); + nv_mthd(dev, 0x9097, 0x18d4, 0x00000000); + nv_mthd(dev, 0x9097, 0x18d8, 0x00000000); + nv_mthd(dev, 0x9097, 0x18dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x18e0, 0x00000000); + nv_mthd(dev, 0x9097, 0x18e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x18e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x18ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x18f0, 0x00000000); + nv_mthd(dev, 0x9097, 0x18f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x18f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x18fc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f84, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f88, 0x00000000); + nv_mthd(dev, 0x9097, 0x17c8, 0x00000000); + nv_mthd(dev, 0x9097, 0x17cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x17d0, 0x000000ff); + nv_mthd(dev, 0x9097, 0x17d4, 0xffffffff); + nv_mthd(dev, 0x9097, 0x17d8, 0x00000002); + nv_mthd(dev, 0x9097, 0x17dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x15f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x15f8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1434, 0x00000000); + nv_mthd(dev, 0x9097, 0x1438, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d74, 0x00000000); + nv_mthd(dev, 0x9097, 0x0dec, 0x00000001); + nv_mthd(dev, 0x9097, 0x13a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1318, 0x00000001); + nv_mthd(dev, 0x9097, 0x1644, 0x00000000); + nv_mthd(dev, 0x9097, 0x0748, 0x00000000); + nv_mthd(dev, 0x9097, 0x0de8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1648, 0x00000000); + nv_mthd(dev, 0x9097, 0x12a4, 0x00000000); + nv_mthd(dev, 0x9097, 0x1120, 0x00000000); + nv_mthd(dev, 0x9097, 0x1124, 0x00000000); + nv_mthd(dev, 0x9097, 0x1128, 0x00000000); + nv_mthd(dev, 0x9097, 0x112c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1118, 0x00000000); + nv_mthd(dev, 0x9097, 0x164c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1658, 0x00000000); + nv_mthd(dev, 0x9097, 0x1910, 0x00000290); + nv_mthd(dev, 0x9097, 0x1518, 0x00000000); + nv_mthd(dev, 0x9097, 0x165c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1520, 0x00000000); + nv_mthd(dev, 0x9097, 0x1604, 0x00000000); + nv_mthd(dev, 0x9097, 0x1570, 0x00000000); + nv_mthd(dev, 0x9097, 0x13b0, 0x3f800000); + nv_mthd(dev, 0x9097, 0x13b4, 0x3f800000); + nv_mthd(dev, 0x9097, 0x020c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1670, 0x30201000); + nv_mthd(dev, 0x9097, 0x1674, 0x70605040); + nv_mthd(dev, 0x9097, 0x1678, 0xb8a89888); + nv_mthd(dev, 0x9097, 0x167c, 0xf8e8d8c8); + nv_mthd(dev, 0x9097, 0x166c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1680, 0x00ffff00); + nv_mthd(dev, 0x9097, 0x12d0, 0x00000003); + nv_mthd(dev, 0x9097, 0x12d4, 0x00000002); + nv_mthd(dev, 0x9097, 0x1684, 0x00000000); + nv_mthd(dev, 0x9097, 0x1688, 0x00000000); + nv_mthd(dev, 0x9097, 0x0dac, 0x00001b02); + nv_mthd(dev, 0x9097, 0x0db0, 0x00001b02); + nv_mthd(dev, 0x9097, 0x0db4, 0x00000000); + nv_mthd(dev, 0x9097, 0x168c, 0x00000000); + nv_mthd(dev, 0x9097, 0x15bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x156c, 0x00000000); + nv_mthd(dev, 0x9097, 0x187c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1110, 0x00000001); + nv_mthd(dev, 0x9097, 0x0dc0, 0x00000000); + nv_mthd(dev, 0x9097, 0x0dc4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0dc8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1234, 0x00000000); + nv_mthd(dev, 0x9097, 0x1690, 0x00000000); + nv_mthd(dev, 0x9097, 0x12ac, 0x00000001); + nv_mthd(dev, 0x9097, 0x02c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0790, 0x00000000); + nv_mthd(dev, 0x9097, 0x0794, 0x00000000); + nv_mthd(dev, 0x9097, 0x0798, 0x00000000); + nv_mthd(dev, 0x9097, 0x079c, 0x00000000); + nv_mthd(dev, 0x9097, 0x07a0, 0x00000000); + nv_mthd(dev, 0x9097, 0x077c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1000, 0x00000010); + nv_mthd(dev, 0x9097, 0x10fc, 0x00000000); + nv_mthd(dev, 0x9097, 0x1290, 0x00000000); + nv_mthd(dev, 0x9097, 0x0218, 0x00000010); + nv_mthd(dev, 0x9097, 0x12d8, 0x00000000); + nv_mthd(dev, 0x9097, 0x12dc, 0x00000010); + nv_mthd(dev, 0x9097, 0x0d94, 0x00000001); + nv_mthd(dev, 0x9097, 0x155c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1560, 0x00000000); + nv_mthd(dev, 0x9097, 0x1564, 0x00001fff); + nv_mthd(dev, 0x9097, 0x1574, 0x00000000); + nv_mthd(dev, 0x9097, 0x1578, 0x00000000); + nv_mthd(dev, 0x9097, 0x157c, 0x003fffff); + nv_mthd(dev, 0x9097, 0x1354, 0x00000000); + nv_mthd(dev, 0x9097, 0x1664, 0x00000000); + nv_mthd(dev, 0x9097, 0x1610, 0x00000012); + nv_mthd(dev, 0x9097, 0x1608, 0x00000000); + nv_mthd(dev, 0x9097, 0x160c, 0x00000000); + nv_mthd(dev, 0x9097, 0x162c, 0x00000003); + nv_mthd(dev, 0x9097, 0x0210, 0x00000000); + nv_mthd(dev, 0x9097, 0x0320, 0x00000000); + nv_mthd(dev, 0x9097, 0x0324, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0328, 0x3f800000); + nv_mthd(dev, 0x9097, 0x032c, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0330, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0334, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0338, 0x3f800000); + nv_mthd(dev, 0x9097, 0x0750, 0x00000000); + nv_mthd(dev, 0x9097, 0x0760, 0x39291909); + nv_mthd(dev, 0x9097, 0x0764, 0x79695949); + nv_mthd(dev, 0x9097, 0x0768, 0xb9a99989); + nv_mthd(dev, 0x9097, 0x076c, 0xf9e9d9c9); + nv_mthd(dev, 0x9097, 0x0770, 0x30201000); + nv_mthd(dev, 0x9097, 0x0774, 0x70605040); + nv_mthd(dev, 0x9097, 0x0778, 0x00009080); + nv_mthd(dev, 0x9097, 0x0780, 0x39291909); + nv_mthd(dev, 0x9097, 0x0784, 0x79695949); + nv_mthd(dev, 0x9097, 0x0788, 0xb9a99989); + nv_mthd(dev, 0x9097, 0x078c, 0xf9e9d9c9); + nv_mthd(dev, 0x9097, 0x07d0, 0x30201000); + nv_mthd(dev, 0x9097, 0x07d4, 0x70605040); + nv_mthd(dev, 0x9097, 0x07d8, 0x00009080); + nv_mthd(dev, 0x9097, 0x037c, 0x00000001); + nv_mthd(dev, 0x9097, 0x0740, 0x00000000); + nv_mthd(dev, 0x9097, 0x0744, 0x00000000); + nv_mthd(dev, 0x9097, 0x2600, 0x00000000); + nv_mthd(dev, 0x9097, 0x1918, 0x00000000); + nv_mthd(dev, 0x9097, 0x191c, 0x00000900); + nv_mthd(dev, 0x9097, 0x1920, 0x00000405); + nv_mthd(dev, 0x9097, 0x1308, 0x00000001); + nv_mthd(dev, 0x9097, 0x1924, 0x00000000); + nv_mthd(dev, 0x9097, 0x13ac, 0x00000000); + nv_mthd(dev, 0x9097, 0x192c, 0x00000001); + nv_mthd(dev, 0x9097, 0x193c, 0x00002c1c); + nv_mthd(dev, 0x9097, 0x0d7c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x02c0, 0x00000001); + nv_mthd(dev, 0x9097, 0x1510, 0x00000000); + nv_mthd(dev, 0x9097, 0x1940, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ff4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0ff8, 0x00000000); + nv_mthd(dev, 0x9097, 0x194c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1950, 0x00000000); + nv_mthd(dev, 0x9097, 0x1968, 0x00000000); + nv_mthd(dev, 0x9097, 0x1590, 0x0000003f); + nv_mthd(dev, 0x9097, 0x07e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x07ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x07f0, 0x00000000); + nv_mthd(dev, 0x9097, 0x07f4, 0x00000000); + nv_mthd(dev, 0x9097, 0x196c, 0x00000011); + nv_mthd(dev, 0x9097, 0x197c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0fcc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0fd0, 0x00000000); + nv_mthd(dev, 0x9097, 0x02d8, 0x00000040); + nv_mthd(dev, 0x9097, 0x1980, 0x00000080); + nv_mthd(dev, 0x9097, 0x1504, 0x00000080); + nv_mthd(dev, 0x9097, 0x1984, 0x00000000); + nv_mthd(dev, 0x9097, 0x0300, 0x00000001); + nv_mthd(dev, 0x9097, 0x13a8, 0x00000000); + nv_mthd(dev, 0x9097, 0x12ec, 0x00000000); + nv_mthd(dev, 0x9097, 0x1310, 0x00000000); + nv_mthd(dev, 0x9097, 0x1314, 0x00000001); + nv_mthd(dev, 0x9097, 0x1380, 0x00000000); + nv_mthd(dev, 0x9097, 0x1384, 0x00000001); + nv_mthd(dev, 0x9097, 0x1388, 0x00000001); + nv_mthd(dev, 0x9097, 0x138c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1390, 0x00000001); + nv_mthd(dev, 0x9097, 0x1394, 0x00000000); + nv_mthd(dev, 0x9097, 0x139c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1398, 0x00000000); + nv_mthd(dev, 0x9097, 0x1594, 0x00000000); + nv_mthd(dev, 0x9097, 0x1598, 0x00000001); + nv_mthd(dev, 0x9097, 0x159c, 0x00000001); + nv_mthd(dev, 0x9097, 0x15a0, 0x00000001); + nv_mthd(dev, 0x9097, 0x15a4, 0x00000001); + nv_mthd(dev, 0x9097, 0x0f54, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f58, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f5c, 0x00000000); + nv_mthd(dev, 0x9097, 0x19bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f9c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0fa0, 0x00000000); + nv_mthd(dev, 0x9097, 0x12cc, 0x00000000); + nv_mthd(dev, 0x9097, 0x12e8, 0x00000000); + nv_mthd(dev, 0x9097, 0x130c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1360, 0x00000000); + nv_mthd(dev, 0x9097, 0x1364, 0x00000000); + nv_mthd(dev, 0x9097, 0x1368, 0x00000000); + nv_mthd(dev, 0x9097, 0x136c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1370, 0x00000000); + nv_mthd(dev, 0x9097, 0x1374, 0x00000000); + nv_mthd(dev, 0x9097, 0x1378, 0x00000000); + nv_mthd(dev, 0x9097, 0x137c, 0x00000000); + nv_mthd(dev, 0x9097, 0x133c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1340, 0x00000001); + nv_mthd(dev, 0x9097, 0x1344, 0x00000002); + nv_mthd(dev, 0x9097, 0x1348, 0x00000001); + nv_mthd(dev, 0x9097, 0x134c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1350, 0x00000002); + nv_mthd(dev, 0x9097, 0x1358, 0x00000001); + nv_mthd(dev, 0x9097, 0x12e4, 0x00000000); + nv_mthd(dev, 0x9097, 0x131c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1320, 0x00000000); + nv_mthd(dev, 0x9097, 0x1324, 0x00000000); + nv_mthd(dev, 0x9097, 0x1328, 0x00000000); + nv_mthd(dev, 0x9097, 0x19c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1140, 0x00000000); + nv_mthd(dev, 0x9097, 0x19c4, 0x00000000); + nv_mthd(dev, 0x9097, 0x19c8, 0x00001500); + nv_mthd(dev, 0x9097, 0x135c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f90, 0x00000000); + nv_mthd(dev, 0x9097, 0x19e0, 0x00000001); + nv_mthd(dev, 0x9097, 0x19e4, 0x00000001); + nv_mthd(dev, 0x9097, 0x19e8, 0x00000001); + nv_mthd(dev, 0x9097, 0x19ec, 0x00000001); + nv_mthd(dev, 0x9097, 0x19f0, 0x00000001); + nv_mthd(dev, 0x9097, 0x19f4, 0x00000001); + nv_mthd(dev, 0x9097, 0x19f8, 0x00000001); + nv_mthd(dev, 0x9097, 0x19fc, 0x00000001); + nv_mthd(dev, 0x9097, 0x19cc, 0x00000001); + nv_mthd(dev, 0x9097, 0x15b8, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a00, 0x00001111); + nv_mthd(dev, 0x9097, 0x1a04, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a08, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a0c, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a10, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a14, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a18, 0x00000000); + nv_mthd(dev, 0x9097, 0x1a1c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d6c, 0xffff0000); + nv_mthd(dev, 0x9097, 0x0d70, 0xffff0000); + nv_mthd(dev, 0x9097, 0x10f8, 0x00001010); + nv_mthd(dev, 0x9097, 0x0d80, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d84, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d88, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d8c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0d90, 0x00000000); + nv_mthd(dev, 0x9097, 0x0da0, 0x00000000); + nv_mthd(dev, 0x9097, 0x1508, 0x80000000); + nv_mthd(dev, 0x9097, 0x150c, 0x40000000); + nv_mthd(dev, 0x9097, 0x1668, 0x00000000); + nv_mthd(dev, 0x9097, 0x0318, 0x00000008); + nv_mthd(dev, 0x9097, 0x031c, 0x00000008); + nv_mthd(dev, 0x9097, 0x0d9c, 0x00000001); + nv_mthd(dev, 0x9097, 0x07dc, 0x00000000); + nv_mthd(dev, 0x9097, 0x074c, 0x00000055); + nv_mthd(dev, 0x9097, 0x1420, 0x00000003); + nv_mthd(dev, 0x9097, 0x17bc, 0x00000000); + nv_mthd(dev, 0x9097, 0x17c0, 0x00000000); + nv_mthd(dev, 0x9097, 0x17c4, 0x00000001); + nv_mthd(dev, 0x9097, 0x1008, 0x00000008); + nv_mthd(dev, 0x9097, 0x100c, 0x00000040); + nv_mthd(dev, 0x9097, 0x1010, 0x0000012c); + nv_mthd(dev, 0x9097, 0x0d60, 0x00000040); + nv_mthd(dev, 0x9097, 0x075c, 0x00000003); + nv_mthd(dev, 0x9097, 0x1018, 0x00000020); + nv_mthd(dev, 0x9097, 0x101c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1020, 0x00000020); + nv_mthd(dev, 0x9097, 0x1024, 0x00000001); + nv_mthd(dev, 0x9097, 0x1444, 0x00000000); + nv_mthd(dev, 0x9097, 0x1448, 0x00000000); + nv_mthd(dev, 0x9097, 0x144c, 0x00000000); + nv_mthd(dev, 0x9097, 0x0360, 0x20164010); + nv_mthd(dev, 0x9097, 0x0364, 0x00000020); + nv_mthd(dev, 0x9097, 0x0368, 0x00000000); + nv_mthd(dev, 0x9097, 0x0de4, 0x00000000); + nv_mthd(dev, 0x9097, 0x0204, 0x00000006); + nv_mthd(dev, 0x9097, 0x0208, 0x00000000); + nv_mthd(dev, 0x9097, 0x02cc, 0x003fffff); + nv_mthd(dev, 0x9097, 0x02d0, 0x00000c48); + nv_mthd(dev, 0x9097, 0x1220, 0x00000005); + nv_mthd(dev, 0x9097, 0x0fdc, 0x00000000); + nv_mthd(dev, 0x9097, 0x0f98, 0x00300008); + nv_mthd(dev, 0x9097, 0x1284, 0x04000080); + nv_mthd(dev, 0x9097, 0x1450, 0x00300008); + nv_mthd(dev, 0x9097, 0x1454, 0x04000080); + nv_mthd(dev, 0x9097, 0x0214, 0x00000000); + /* in trace, right after 0x90c0, not here */ + nv_mthd(dev, 0x9097, 0x3410, 0x80002006); +} + +static void +nvc0_grctx_generate_902d(struct drm_device *dev) +{ + nv_mthd(dev, 0x902d, 0x0200, 0x000000cf); + nv_mthd(dev, 0x902d, 0x0204, 0x00000001); + nv_mthd(dev, 0x902d, 0x0208, 0x00000020); + nv_mthd(dev, 0x902d, 0x020c, 0x00000001); + nv_mthd(dev, 0x902d, 0x0210, 0x00000000); + nv_mthd(dev, 0x902d, 0x0214, 0x00000080); + nv_mthd(dev, 0x902d, 0x0218, 0x00000100); + nv_mthd(dev, 0x902d, 0x021c, 0x00000100); + nv_mthd(dev, 0x902d, 0x0220, 0x00000000); + nv_mthd(dev, 0x902d, 0x0224, 0x00000000); + nv_mthd(dev, 0x902d, 0x0230, 0x000000cf); + nv_mthd(dev, 0x902d, 0x0234, 0x00000001); + nv_mthd(dev, 0x902d, 0x0238, 0x00000020); + nv_mthd(dev, 0x902d, 0x023c, 0x00000001); + nv_mthd(dev, 0x902d, 0x0244, 0x00000080); + nv_mthd(dev, 0x902d, 0x0248, 0x00000100); + nv_mthd(dev, 0x902d, 0x024c, 0x00000100); +} + +static void +nvc0_grctx_generate_9039(struct drm_device *dev) +{ + nv_mthd(dev, 0x9039, 0x030c, 0x00000000); + nv_mthd(dev, 0x9039, 0x0310, 0x00000000); + nv_mthd(dev, 0x9039, 0x0314, 0x00000000); + nv_mthd(dev, 0x9039, 0x0320, 0x00000000); + nv_mthd(dev, 0x9039, 0x0238, 0x00000000); + nv_mthd(dev, 0x9039, 0x023c, 0x00000000); + nv_mthd(dev, 0x9039, 0x0318, 0x00000000); + nv_mthd(dev, 0x9039, 0x031c, 0x00000000); +} + +static void +nvc0_grctx_generate_90c0(struct drm_device *dev) +{ + nv_mthd(dev, 0x90c0, 0x270c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x272c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x274c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x276c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x278c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x27ac, 0x00000000); + nv_mthd(dev, 0x90c0, 0x27cc, 0x00000000); + nv_mthd(dev, 0x90c0, 0x27ec, 0x00000000); + nv_mthd(dev, 0x90c0, 0x030c, 0x00000001); + nv_mthd(dev, 0x90c0, 0x1944, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0758, 0x00000100); + nv_mthd(dev, 0x90c0, 0x02c4, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0790, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0794, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0798, 0x00000000); + nv_mthd(dev, 0x90c0, 0x079c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x07a0, 0x00000000); + nv_mthd(dev, 0x90c0, 0x077c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0204, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0208, 0x00000000); + nv_mthd(dev, 0x90c0, 0x020c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0214, 0x00000000); + nv_mthd(dev, 0x90c0, 0x024c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x0d94, 0x00000001); + nv_mthd(dev, 0x90c0, 0x1608, 0x00000000); + nv_mthd(dev, 0x90c0, 0x160c, 0x00000000); + nv_mthd(dev, 0x90c0, 0x1664, 0x00000000); +} + +static void +nvc0_grctx_generate_dispatch(struct drm_device *dev) +{ + int i; + + nv_wr32(dev, 0x404004, 0x00000000); + nv_wr32(dev, 0x404008, 0x00000000); + nv_wr32(dev, 0x40400c, 0x00000000); + nv_wr32(dev, 0x404010, 0x00000000); + nv_wr32(dev, 0x404014, 0x00000000); + nv_wr32(dev, 0x404018, 0x00000000); + nv_wr32(dev, 0x40401c, 0x00000000); + nv_wr32(dev, 0x404020, 0x00000000); + nv_wr32(dev, 0x404024, 0x00000000); + nv_wr32(dev, 0x404028, 0x00000000); + nv_wr32(dev, 0x40402c, 0x00000000); + nv_wr32(dev, 0x404044, 0x00000000); + nv_wr32(dev, 0x404094, 0x00000000); + nv_wr32(dev, 0x404098, 0x00000000); + nv_wr32(dev, 0x40409c, 0x00000000); + nv_wr32(dev, 0x4040a0, 0x00000000); + nv_wr32(dev, 0x4040a4, 0x00000000); + nv_wr32(dev, 0x4040a8, 0x00000000); + nv_wr32(dev, 0x4040ac, 0x00000000); + nv_wr32(dev, 0x4040b0, 0x00000000); + nv_wr32(dev, 0x4040b4, 0x00000000); + nv_wr32(dev, 0x4040b8, 0x00000000); + nv_wr32(dev, 0x4040bc, 0x00000000); + nv_wr32(dev, 0x4040c0, 0x00000000); + nv_wr32(dev, 0x4040c4, 0x00000000); + nv_wr32(dev, 0x4040c8, 0xf0000087); + nv_wr32(dev, 0x4040d4, 0x00000000); + nv_wr32(dev, 0x4040d8, 0x00000000); + nv_wr32(dev, 0x4040dc, 0x00000000); + nv_wr32(dev, 0x4040e0, 0x00000000); + nv_wr32(dev, 0x4040e4, 0x00000000); + nv_wr32(dev, 0x4040e8, 0x00001000); + nv_wr32(dev, 0x4040f8, 0x00000000); + nv_wr32(dev, 0x404130, 0x00000000); + nv_wr32(dev, 0x404134, 0x00000000); + nv_wr32(dev, 0x404138, 0x20000040); + nv_wr32(dev, 0x404150, 0x0000002e); + nv_wr32(dev, 0x404154, 0x00000400); + nv_wr32(dev, 0x404158, 0x00000200); + nv_wr32(dev, 0x404164, 0x00000055); + nv_wr32(dev, 0x404168, 0x00000000); + nv_wr32(dev, 0x404174, 0x00000000); + nv_wr32(dev, 0x404178, 0x00000000); + nv_wr32(dev, 0x40417c, 0x00000000); + for (i = 0; i < 8; i++) + nv_wr32(dev, 0x404200 + (i * 4), 0x00000000); /* subc */ +} + +static void +nvc0_grctx_generate_macro(struct drm_device *dev) +{ + nv_wr32(dev, 0x404404, 0x00000000); + nv_wr32(dev, 0x404408, 0x00000000); + nv_wr32(dev, 0x40440c, 0x00000000); + nv_wr32(dev, 0x404410, 0x00000000); + nv_wr32(dev, 0x404414, 0x00000000); + nv_wr32(dev, 0x404418, 0x00000000); + nv_wr32(dev, 0x40441c, 0x00000000); + nv_wr32(dev, 0x404420, 0x00000000); + nv_wr32(dev, 0x404424, 0x00000000); + nv_wr32(dev, 0x404428, 0x00000000); + nv_wr32(dev, 0x40442c, 0x00000000); + nv_wr32(dev, 0x404430, 0x00000000); + nv_wr32(dev, 0x404434, 0x00000000); + nv_wr32(dev, 0x404438, 0x00000000); + nv_wr32(dev, 0x404460, 0x00000000); + nv_wr32(dev, 0x404464, 0x00000000); + nv_wr32(dev, 0x404468, 0x00ffffff); + nv_wr32(dev, 0x40446c, 0x00000000); + nv_wr32(dev, 0x404480, 0x00000001); + nv_wr32(dev, 0x404498, 0x00000001); +} + +static void +nvc0_grctx_generate_m2mf(struct drm_device *dev) +{ + nv_wr32(dev, 0x404604, 0x00000015); + nv_wr32(dev, 0x404608, 0x00000000); + nv_wr32(dev, 0x40460c, 0x00002e00); + nv_wr32(dev, 0x404610, 0x00000100); + nv_wr32(dev, 0x404618, 0x00000000); + nv_wr32(dev, 0x40461c, 0x00000000); + nv_wr32(dev, 0x404620, 0x00000000); + nv_wr32(dev, 0x404624, 0x00000000); + nv_wr32(dev, 0x404628, 0x00000000); + nv_wr32(dev, 0x40462c, 0x00000000); + nv_wr32(dev, 0x404630, 0x00000000); + nv_wr32(dev, 0x404634, 0x00000000); + nv_wr32(dev, 0x404638, 0x00000004); + nv_wr32(dev, 0x40463c, 0x00000000); + nv_wr32(dev, 0x404640, 0x00000000); + nv_wr32(dev, 0x404644, 0x00000000); + nv_wr32(dev, 0x404648, 0x00000000); + nv_wr32(dev, 0x40464c, 0x00000000); + nv_wr32(dev, 0x404650, 0x00000000); + nv_wr32(dev, 0x404654, 0x00000000); + nv_wr32(dev, 0x404658, 0x00000000); + nv_wr32(dev, 0x40465c, 0x007f0100); + nv_wr32(dev, 0x404660, 0x00000000); + nv_wr32(dev, 0x404664, 0x00000000); + nv_wr32(dev, 0x404668, 0x00000000); + nv_wr32(dev, 0x40466c, 0x00000000); + nv_wr32(dev, 0x404670, 0x00000000); + nv_wr32(dev, 0x404674, 0x00000000); + nv_wr32(dev, 0x404678, 0x00000000); + nv_wr32(dev, 0x40467c, 0x00000002); + nv_wr32(dev, 0x404680, 0x00000000); + nv_wr32(dev, 0x404684, 0x00000000); + nv_wr32(dev, 0x404688, 0x00000000); + nv_wr32(dev, 0x40468c, 0x00000000); + nv_wr32(dev, 0x404690, 0x00000000); + nv_wr32(dev, 0x404694, 0x00000000); + nv_wr32(dev, 0x404698, 0x00000000); + nv_wr32(dev, 0x40469c, 0x00000000); + nv_wr32(dev, 0x4046a0, 0x007f0080); + nv_wr32(dev, 0x4046a4, 0x00000000); + nv_wr32(dev, 0x4046a8, 0x00000000); + nv_wr32(dev, 0x4046ac, 0x00000000); + nv_wr32(dev, 0x4046b0, 0x00000000); + nv_wr32(dev, 0x4046b4, 0x00000000); + nv_wr32(dev, 0x4046b8, 0x00000000); + nv_wr32(dev, 0x4046bc, 0x00000000); + nv_wr32(dev, 0x4046c0, 0x00000000); + nv_wr32(dev, 0x4046c4, 0x00000000); + nv_wr32(dev, 0x4046c8, 0x00000000); + nv_wr32(dev, 0x4046cc, 0x00000000); + nv_wr32(dev, 0x4046d0, 0x00000000); + nv_wr32(dev, 0x4046d4, 0x00000000); + nv_wr32(dev, 0x4046d8, 0x00000000); + nv_wr32(dev, 0x4046dc, 0x00000000); + nv_wr32(dev, 0x4046e0, 0x00000000); + nv_wr32(dev, 0x4046e4, 0x00000000); + nv_wr32(dev, 0x4046e8, 0x00000000); + nv_wr32(dev, 0x4046f0, 0x00000000); + nv_wr32(dev, 0x4046f4, 0x00000000); +} + +static void +nvc0_grctx_generate_unk47xx(struct drm_device *dev) +{ + nv_wr32(dev, 0x404700, 0x00000000); + nv_wr32(dev, 0x404704, 0x00000000); + nv_wr32(dev, 0x404708, 0x00000000); + nv_wr32(dev, 0x40470c, 0x00000000); + nv_wr32(dev, 0x404710, 0x00000000); + nv_wr32(dev, 0x404714, 0x00000000); + nv_wr32(dev, 0x404718, 0x00000000); + nv_wr32(dev, 0x40471c, 0x00000000); + nv_wr32(dev, 0x404720, 0x00000000); + nv_wr32(dev, 0x404724, 0x00000000); + nv_wr32(dev, 0x404728, 0x00000000); + nv_wr32(dev, 0x40472c, 0x00000000); + nv_wr32(dev, 0x404730, 0x00000000); + nv_wr32(dev, 0x404734, 0x00000100); + nv_wr32(dev, 0x404738, 0x00000000); + nv_wr32(dev, 0x40473c, 0x00000000); + nv_wr32(dev, 0x404740, 0x00000000); + nv_wr32(dev, 0x404744, 0x00000000); + nv_wr32(dev, 0x404748, 0x00000000); + nv_wr32(dev, 0x40474c, 0x00000000); + nv_wr32(dev, 0x404750, 0x00000000); + nv_wr32(dev, 0x404754, 0x00000000); +} + +static void +nvc0_grctx_generate_unk58xx(struct drm_device *dev) +{ + nv_wr32(dev, 0x405800, 0x078000bf); + nv_wr32(dev, 0x405830, 0x02180000); + nv_wr32(dev, 0x405834, 0x00000000); + nv_wr32(dev, 0x405838, 0x00000000); + nv_wr32(dev, 0x405854, 0x00000000); + nv_wr32(dev, 0x405870, 0x00000001); + nv_wr32(dev, 0x405874, 0x00000001); + nv_wr32(dev, 0x405878, 0x00000001); + nv_wr32(dev, 0x40587c, 0x00000001); + nv_wr32(dev, 0x405a00, 0x00000000); + nv_wr32(dev, 0x405a04, 0x00000000); + nv_wr32(dev, 0x405a18, 0x00000000); +} + +static void +nvc0_grctx_generate_unk60xx(struct drm_device *dev) +{ + nv_wr32(dev, 0x406020, 0x000103c1); + nv_wr32(dev, 0x406028, 0x00000001); + nv_wr32(dev, 0x40602c, 0x00000001); + nv_wr32(dev, 0x406030, 0x00000001); + nv_wr32(dev, 0x406034, 0x00000001); +} + +static void +nvc0_grctx_generate_unk64xx(struct drm_device *dev) +{ + nv_wr32(dev, 0x4064a8, 0x00000000); + nv_wr32(dev, 0x4064ac, 0x00003fff); + nv_wr32(dev, 0x4064b4, 0x00000000); + nv_wr32(dev, 0x4064b8, 0x00000000); +} + +static void +nvc0_grctx_generate_unk78xx(struct drm_device *dev) +{ + nv_wr32(dev, 0x407804, 0x00000023); + nv_wr32(dev, 0x40780c, 0x0a418820); + nv_wr32(dev, 0x407810, 0x062080e6); + nv_wr32(dev, 0x407814, 0x020398a4); + nv_wr32(dev, 0x407818, 0x0e629062); + nv_wr32(dev, 0x40781c, 0x0a418820); + nv_wr32(dev, 0x407820, 0x000000e6); + nv_wr32(dev, 0x4078bc, 0x00000103); +} + +static void +nvc0_grctx_generate_unk80xx(struct drm_device *dev) +{ + nv_wr32(dev, 0x408000, 0x00000000); + nv_wr32(dev, 0x408004, 0x00000000); + nv_wr32(dev, 0x408008, 0x00000018); + nv_wr32(dev, 0x40800c, 0x00000000); + nv_wr32(dev, 0x408010, 0x00000000); + nv_wr32(dev, 0x408014, 0x00000069); + nv_wr32(dev, 0x408018, 0xe100e100); + nv_wr32(dev, 0x408064, 0x00000000); +} + +static void +nvc0_grctx_generate_rop(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + // ROPC_BROADCAST + nv_wr32(dev, 0x408800, 0x02802a3c); + nv_wr32(dev, 0x408804, 0x00000040); + nv_wr32(dev, 0x408808, 0x0003e00d); + switch (dev_priv->chipset) { + case 0xc0: + nv_wr32(dev, 0x408900, 0x0080b801); + break; + case 0xc3: + case 0xc4: + nv_wr32(dev, 0x408900, 0x3080b801); + break; + } + nv_wr32(dev, 0x408904, 0x02000001); + nv_wr32(dev, 0x408908, 0x00c80929); + nv_wr32(dev, 0x40890c, 0x00000000); + nv_wr32(dev, 0x408980, 0x0000011d); +} + +static void +nvc0_grctx_generate_gpc(struct drm_device *dev) +{ + int i; + + // GPC_BROADCAST + nv_wr32(dev, 0x418380, 0x00000016); + nv_wr32(dev, 0x418400, 0x38004e00); + nv_wr32(dev, 0x418404, 0x71e0ffff); + nv_wr32(dev, 0x418408, 0x00000000); + nv_wr32(dev, 0x41840c, 0x00001008); + nv_wr32(dev, 0x418410, 0x0fff0fff); + nv_wr32(dev, 0x418414, 0x00200fff); + nv_wr32(dev, 0x418450, 0x00000000); + nv_wr32(dev, 0x418454, 0x00000000); + nv_wr32(dev, 0x418458, 0x00000000); + nv_wr32(dev, 0x41845c, 0x00000000); + nv_wr32(dev, 0x418460, 0x00000000); + nv_wr32(dev, 0x418464, 0x00000000); + nv_wr32(dev, 0x418468, 0x00000001); + nv_wr32(dev, 0x41846c, 0x00000000); + nv_wr32(dev, 0x418470, 0x00000000); + nv_wr32(dev, 0x418600, 0x0000001f); + nv_wr32(dev, 0x418684, 0x0000000f); + nv_wr32(dev, 0x418700, 0x00000002); + nv_wr32(dev, 0x418704, 0x00000080); + nv_wr32(dev, 0x418708, 0x00000000); + nv_wr32(dev, 0x41870c, 0x07c80000); + nv_wr32(dev, 0x418710, 0x00000000); + nv_wr32(dev, 0x418800, 0x0006860a); + nv_wr32(dev, 0x418808, 0x00000000); + nv_wr32(dev, 0x41880c, 0x00000000); + nv_wr32(dev, 0x418810, 0x00000000); + nv_wr32(dev, 0x418828, 0x00008442); + nv_wr32(dev, 0x418830, 0x00000001); + nv_wr32(dev, 0x4188d8, 0x00000008); + nv_wr32(dev, 0x4188e0, 0x01000000); + nv_wr32(dev, 0x4188e8, 0x00000000); + nv_wr32(dev, 0x4188ec, 0x00000000); + nv_wr32(dev, 0x4188f0, 0x00000000); + nv_wr32(dev, 0x4188f4, 0x00000000); + nv_wr32(dev, 0x4188f8, 0x00000000); + nv_wr32(dev, 0x4188fc, 0x00100000); + nv_wr32(dev, 0x41891c, 0x00ff00ff); + nv_wr32(dev, 0x418924, 0x00000000); + nv_wr32(dev, 0x418928, 0x00ffff00); + nv_wr32(dev, 0x41892c, 0x0000ff00); + for (i = 0; i < 8; i++) { + nv_wr32(dev, 0x418a00 + (i * 0x20), 0x00000000); + nv_wr32(dev, 0x418a04 + (i * 0x20), 0x00000000); + nv_wr32(dev, 0x418a08 + (i * 0x20), 0x00000000); + nv_wr32(dev, 0x418a0c + (i * 0x20), 0x00010000); + nv_wr32(dev, 0x418a10 + (i * 0x20), 0x00000000); + nv_wr32(dev, 0x418a14 + (i * 0x20), 0x00000000); + nv_wr32(dev, 0x418a18 + (i * 0x20), 0x00000000); + } + nv_wr32(dev, 0x418b00, 0x00000000); + nv_wr32(dev, 0x418b08, 0x0a418820); + nv_wr32(dev, 0x418b0c, 0x062080e6); + nv_wr32(dev, 0x418b10, 0x020398a4); + nv_wr32(dev, 0x418b14, 0x0e629062); + nv_wr32(dev, 0x418b18, 0x0a418820); + nv_wr32(dev, 0x418b1c, 0x000000e6); + nv_wr32(dev, 0x418bb8, 0x00000103); + nv_wr32(dev, 0x418c08, 0x00000001); + nv_wr32(dev, 0x418c10, 0x00000000); + nv_wr32(dev, 0x418c14, 0x00000000); + nv_wr32(dev, 0x418c18, 0x00000000); + nv_wr32(dev, 0x418c1c, 0x00000000); + nv_wr32(dev, 0x418c20, 0x00000000); + nv_wr32(dev, 0x418c24, 0x00000000); + nv_wr32(dev, 0x418c28, 0x00000000); + nv_wr32(dev, 0x418c2c, 0x00000000); + nv_wr32(dev, 0x418c80, 0x20200004); + nv_wr32(dev, 0x418c8c, 0x00000001); + nv_wr32(dev, 0x419000, 0x00000780); + nv_wr32(dev, 0x419004, 0x00000000); + nv_wr32(dev, 0x419008, 0x00000000); + nv_wr32(dev, 0x419014, 0x00000004); +} + +static void +nvc0_grctx_generate_tp(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + // GPC_BROADCAST.TP_BROADCAST + nv_wr32(dev, 0x419848, 0x00000000); + nv_wr32(dev, 0x419864, 0x0000012a); + nv_wr32(dev, 0x419888, 0x00000000); + nv_wr32(dev, 0x419a00, 0x000001f0); + nv_wr32(dev, 0x419a04, 0x00000001); + nv_wr32(dev, 0x419a08, 0x00000023); + nv_wr32(dev, 0x419a0c, 0x00020000); + nv_wr32(dev, 0x419a10, 0x00000000); + nv_wr32(dev, 0x419a14, 0x00000200); + nv_wr32(dev, 0x419a1c, 0x00000000); + nv_wr32(dev, 0x419a20, 0x00000800); + if (dev_priv->chipset != 0xc0) + nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3 + nv_wr32(dev, 0x419b00, 0x0a418820); + nv_wr32(dev, 0x419b04, 0x062080e6); + nv_wr32(dev, 0x419b08, 0x020398a4); + nv_wr32(dev, 0x419b0c, 0x0e629062); + nv_wr32(dev, 0x419b10, 0x0a418820); + nv_wr32(dev, 0x419b14, 0x000000e6); + nv_wr32(dev, 0x419bd0, 0x00900103); + nv_wr32(dev, 0x419be0, 0x00000001); + nv_wr32(dev, 0x419be4, 0x00000000); + nv_wr32(dev, 0x419c00, 0x00000002); + nv_wr32(dev, 0x419c04, 0x00000006); + nv_wr32(dev, 0x419c08, 0x00000002); + nv_wr32(dev, 0x419c20, 0x00000000); + nv_wr32(dev, 0x419cbc, 0x28137606); + nv_wr32(dev, 0x419ce8, 0x00000000); + nv_wr32(dev, 0x419cf4, 0x00000183); + nv_wr32(dev, 0x419d20, 0x02180000); + nv_wr32(dev, 0x419d24, 0x00001fff); + nv_wr32(dev, 0x419e04, 0x00000000); + nv_wr32(dev, 0x419e08, 0x00000000); + nv_wr32(dev, 0x419e0c, 0x00000000); + nv_wr32(dev, 0x419e10, 0x00000002); + nv_wr32(dev, 0x419e44, 0x001beff2); + nv_wr32(dev, 0x419e48, 0x00000000); + nv_wr32(dev, 0x419e4c, 0x0000000f); + nv_wr32(dev, 0x419e50, 0x00000000); + nv_wr32(dev, 0x419e54, 0x00000000); + nv_wr32(dev, 0x419e58, 0x00000000); + nv_wr32(dev, 0x419e5c, 0x00000000); + nv_wr32(dev, 0x419e60, 0x00000000); + nv_wr32(dev, 0x419e64, 0x00000000); + nv_wr32(dev, 0x419e68, 0x00000000); + nv_wr32(dev, 0x419e6c, 0x00000000); + nv_wr32(dev, 0x419e70, 0x00000000); + nv_wr32(dev, 0x419e74, 0x00000000); + nv_wr32(dev, 0x419e78, 0x00000000); + nv_wr32(dev, 0x419e7c, 0x00000000); + nv_wr32(dev, 0x419e80, 0x00000000); + nv_wr32(dev, 0x419e84, 0x00000000); + nv_wr32(dev, 0x419e88, 0x00000000); + nv_wr32(dev, 0x419e8c, 0x00000000); + nv_wr32(dev, 0x419e90, 0x00000000); + nv_wr32(dev, 0x419e98, 0x00000000); + if (dev_priv->chipset != 0xc0) + nv_wr32(dev, 0x419ee0, 0x00011110); + nv_wr32(dev, 0x419f50, 0x00000000); + nv_wr32(dev, 0x419f54, 0x00000000); + if (dev_priv->chipset != 0xc0) + nv_wr32(dev, 0x419f58, 0x00000000); +} + +int +nvc0_grctx_generate(struct nouveau_channel *chan) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv; + struct nvc0_graph_chan *grch = chan->pgraph_ctx; + struct drm_device *dev = chan->dev; + int i, gpc, tp, id; + u32 r000260; + + r000260 = nv_rd32(dev, 0x000260); + nv_wr32(dev, 0x000260, r000260 & ~1); + nv_wr32(dev, 0x400208, 0x00000000); + + nvc0_grctx_generate_dispatch(dev); + nvc0_grctx_generate_macro(dev); + nvc0_grctx_generate_m2mf(dev); + nvc0_grctx_generate_unk47xx(dev); + nvc0_grctx_generate_unk58xx(dev); + nvc0_grctx_generate_unk60xx(dev); + nvc0_grctx_generate_unk64xx(dev); + nvc0_grctx_generate_unk78xx(dev); + nvc0_grctx_generate_unk80xx(dev); + nvc0_grctx_generate_rop(dev); + nvc0_grctx_generate_gpc(dev); + nvc0_grctx_generate_tp(dev); + + nv_wr32(dev, 0x404154, 0x00000000); + + /* fuc "mmio list" writes */ + for (i = 0; i < grch->mmio_nr * 8; i += 8) { + u32 reg = nv_ro32(grch->mmio, i + 0); + nv_wr32(dev, reg, nv_ro32(grch->mmio, i + 4)); + } + + for (tp = 0, id = 0; tp < 4; tp++) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + if (tp <= priv->tp_nr[gpc]) { + nv_wr32(dev, TP_UNIT(gpc, tp, 0x698), id); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x4e8), id); + nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tp * 4), id); + nv_wr32(dev, TP_UNIT(gpc, tp, 0x088), id); + id++; + } + + nv_wr32(dev, GPC_UNIT(gpc, 0x0c08), priv->tp_nr[gpc]); + nv_wr32(dev, GPC_UNIT(gpc, 0x0c8c), priv->tp_nr[gpc]); + } + } + + nv_wr32(dev, 0x406028, 0x00000443); + nv_wr32(dev, 0x405870, 0x00000443); + nv_wr32(dev, 0x40602c, 0x00000000); + nv_wr32(dev, 0x405874, 0x00000000); + nv_wr32(dev, 0x406030, 0x00000000); + nv_wr32(dev, 0x405878, 0x00000000); + nv_wr32(dev, 0x406034, 0x00000000); + nv_wr32(dev, 0x40587c, 0x00000000); + + if (1) { + const u8 chipset_tp_max[] = { 16, 0, 0, 4, 8 }; + u8 max = chipset_tp_max[dev_priv->chipset & 0x0f]; + u8 tpnr[GPC_MAX]; + u8 data[32]; + + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + memset(data, 0x1f, sizeof(data)); + + gpc = -1; + for (tp = 0; tp < priv->tp_total; tp++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpnr[gpc]); + tpnr[gpc]--; + data[tp] = gpc; + } + + for (i = 0; i < max / 4; i++) + nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + } + + if (1) { + u32 data[6] = {}; + u8 tpnr[GPC_MAX]; + + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + + for (tp = 0; tp < priv->tp_total; tp++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpnr[gpc]); + tpnr[gpc]--; + + data[tp / 6] |= gpc << ((tp % 6) * 5); + } + + for (; tp < 32; tp++) + data[tp / 6] |= 7 << ((tp % 6) * 5); + + // GPC_BROADCAST + nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) | + priv->magic_not_rop_nr); + for (i = 0; i < 6; i++) + nv_wr32(dev, 0x418b08 + (i * 4), data[i]); + + // GPC_BROADCAST.TP_BROADCAST + nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) | + priv->magic_not_rop_nr | + priv->magic419bd0); + nv_wr32(dev, 0x419be4, priv->magic419be4); + for (i = 0; i < 6; i++) + nv_wr32(dev, 0x419b00 + (i * 4), data[i]); + + // UNK78xx + nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) | + priv->magic_not_rop_nr); + for (i = 0; i < 6; i++) + nv_wr32(dev, 0x40780c + (i * 4), data[i]); + } + + if (1) { + u32 tp_mask = 0, tp_set = 0; + u8 tpnr[GPC_MAX]; + + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) + tp_mask |= ((1 << priv->tp_nr[gpc]) - 1) << (gpc * 8); + + gpc = -1; + for (i = 0, gpc = -1; i < 32; i++) { + int ltp = i * (priv->tp_total - 1) / 32; + + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpnr[gpc]); + tp = priv->tp_nr[gpc] - tpnr[gpc]--; + + tp_set |= 1 << ((gpc * 8) + tp); + + do { + nv_wr32(dev, 0x406800 + (i * 0x20), tp_set); + tp_set ^= tp_mask; + nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set); + tp_set ^= tp_mask; + } while (ltp == (++i * (priv->tp_total - 1) / 32)); + i--; + } + } + + nv_wr32(dev, 0x400208, 0x80000000); + + nv_icmd(dev, 0x00001000, 0x00000004); + nv_icmd(dev, 0x000000a9, 0x0000ffff); + nv_icmd(dev, 0x00000038, 0x0fac6881); + nv_icmd(dev, 0x0000003d, 0x00000001); + nv_icmd(dev, 0x000000e8, 0x00000400); + nv_icmd(dev, 0x000000e9, 0x00000400); + nv_icmd(dev, 0x000000ea, 0x00000400); + nv_icmd(dev, 0x000000eb, 0x00000400); + nv_icmd(dev, 0x000000ec, 0x00000400); + nv_icmd(dev, 0x000000ed, 0x00000400); + nv_icmd(dev, 0x000000ee, 0x00000400); + nv_icmd(dev, 0x000000ef, 0x00000400); + nv_icmd(dev, 0x00000078, 0x00000300); + nv_icmd(dev, 0x00000079, 0x00000300); + nv_icmd(dev, 0x0000007a, 0x00000300); + nv_icmd(dev, 0x0000007b, 0x00000300); + nv_icmd(dev, 0x0000007c, 0x00000300); + nv_icmd(dev, 0x0000007d, 0x00000300); + nv_icmd(dev, 0x0000007e, 0x00000300); + nv_icmd(dev, 0x0000007f, 0x00000300); + nv_icmd(dev, 0x00000050, 0x00000011); + nv_icmd(dev, 0x00000058, 0x00000008); + nv_icmd(dev, 0x00000059, 0x00000008); + nv_icmd(dev, 0x0000005a, 0x00000008); + nv_icmd(dev, 0x0000005b, 0x00000008); + nv_icmd(dev, 0x0000005c, 0x00000008); + nv_icmd(dev, 0x0000005d, 0x00000008); + nv_icmd(dev, 0x0000005e, 0x00000008); + nv_icmd(dev, 0x0000005f, 0x00000008); + nv_icmd(dev, 0x00000208, 0x00000001); + nv_icmd(dev, 0x00000209, 0x00000001); + nv_icmd(dev, 0x0000020a, 0x00000001); + nv_icmd(dev, 0x0000020b, 0x00000001); + nv_icmd(dev, 0x0000020c, 0x00000001); + nv_icmd(dev, 0x0000020d, 0x00000001); + nv_icmd(dev, 0x0000020e, 0x00000001); + nv_icmd(dev, 0x0000020f, 0x00000001); + nv_icmd(dev, 0x00000081, 0x00000001); + nv_icmd(dev, 0x00000085, 0x00000004); + nv_icmd(dev, 0x00000088, 0x00000400); + nv_icmd(dev, 0x00000090, 0x00000300); + nv_icmd(dev, 0x00000098, 0x00001001); + nv_icmd(dev, 0x000000e3, 0x00000001); + nv_icmd(dev, 0x000000da, 0x00000001); + nv_icmd(dev, 0x000000f8, 0x00000003); + nv_icmd(dev, 0x000000fa, 0x00000001); + nv_icmd(dev, 0x0000009f, 0x0000ffff); + nv_icmd(dev, 0x000000a0, 0x0000ffff); + nv_icmd(dev, 0x000000a1, 0x0000ffff); + nv_icmd(dev, 0x000000a2, 0x0000ffff); + nv_icmd(dev, 0x000000b1, 0x00000001); + nv_icmd(dev, 0x000000b2, 0x00000000); + nv_icmd(dev, 0x000000b3, 0x00000000); + nv_icmd(dev, 0x000000b4, 0x00000000); + nv_icmd(dev, 0x000000b5, 0x00000000); + nv_icmd(dev, 0x000000b6, 0x00000000); + nv_icmd(dev, 0x000000b7, 0x00000000); + nv_icmd(dev, 0x000000b8, 0x00000000); + nv_icmd(dev, 0x000000b9, 0x00000000); + nv_icmd(dev, 0x000000ba, 0x00000000); + nv_icmd(dev, 0x000000bb, 0x00000000); + nv_icmd(dev, 0x000000bc, 0x00000000); + nv_icmd(dev, 0x000000bd, 0x00000000); + nv_icmd(dev, 0x000000be, 0x00000000); + nv_icmd(dev, 0x000000bf, 0x00000000); + nv_icmd(dev, 0x000000c0, 0x00000000); + nv_icmd(dev, 0x000000c1, 0x00000000); + nv_icmd(dev, 0x000000c2, 0x00000000); + nv_icmd(dev, 0x000000c3, 0x00000000); + nv_icmd(dev, 0x000000c4, 0x00000000); + nv_icmd(dev, 0x000000c5, 0x00000000); + nv_icmd(dev, 0x000000c6, 0x00000000); + nv_icmd(dev, 0x000000c7, 0x00000000); + nv_icmd(dev, 0x000000c8, 0x00000000); + nv_icmd(dev, 0x000000c9, 0x00000000); + nv_icmd(dev, 0x000000ca, 0x00000000); + nv_icmd(dev, 0x000000cb, 0x00000000); + nv_icmd(dev, 0x000000cc, 0x00000000); + nv_icmd(dev, 0x000000cd, 0x00000000); + nv_icmd(dev, 0x000000ce, 0x00000000); + nv_icmd(dev, 0x000000cf, 0x00000000); + nv_icmd(dev, 0x000000d0, 0x00000000); + nv_icmd(dev, 0x000000d1, 0x00000000); + nv_icmd(dev, 0x000000d2, 0x00000000); + nv_icmd(dev, 0x000000d3, 0x00000000); + nv_icmd(dev, 0x000000d4, 0x00000000); + nv_icmd(dev, 0x000000d5, 0x00000000); + nv_icmd(dev, 0x000000d6, 0x00000000); + nv_icmd(dev, 0x000000d7, 0x00000000); + nv_icmd(dev, 0x000000d8, 0x00000000); + nv_icmd(dev, 0x000000d9, 0x00000000); + nv_icmd(dev, 0x00000210, 0x00000040); + nv_icmd(dev, 0x00000211, 0x00000040); + nv_icmd(dev, 0x00000212, 0x00000040); + nv_icmd(dev, 0x00000213, 0x00000040); + nv_icmd(dev, 0x00000214, 0x00000040); + nv_icmd(dev, 0x00000215, 0x00000040); + nv_icmd(dev, 0x00000216, 0x00000040); + nv_icmd(dev, 0x00000217, 0x00000040); + nv_icmd(dev, 0x00000218, 0x0000c080); + nv_icmd(dev, 0x00000219, 0x0000c080); + nv_icmd(dev, 0x0000021a, 0x0000c080); + nv_icmd(dev, 0x0000021b, 0x0000c080); + nv_icmd(dev, 0x0000021c, 0x0000c080); + nv_icmd(dev, 0x0000021d, 0x0000c080); + nv_icmd(dev, 0x0000021e, 0x0000c080); + nv_icmd(dev, 0x0000021f, 0x0000c080); + nv_icmd(dev, 0x000000ad, 0x0000013e); + nv_icmd(dev, 0x000000e1, 0x00000010); + nv_icmd(dev, 0x00000290, 0x00000000); + nv_icmd(dev, 0x00000291, 0x00000000); + nv_icmd(dev, 0x00000292, 0x00000000); + nv_icmd(dev, 0x00000293, 0x00000000); + nv_icmd(dev, 0x00000294, 0x00000000); + nv_icmd(dev, 0x00000295, 0x00000000); + nv_icmd(dev, 0x00000296, 0x00000000); + nv_icmd(dev, 0x00000297, 0x00000000); + nv_icmd(dev, 0x00000298, 0x00000000); + nv_icmd(dev, 0x00000299, 0x00000000); + nv_icmd(dev, 0x0000029a, 0x00000000); + nv_icmd(dev, 0x0000029b, 0x00000000); + nv_icmd(dev, 0x0000029c, 0x00000000); + nv_icmd(dev, 0x0000029d, 0x00000000); + nv_icmd(dev, 0x0000029e, 0x00000000); + nv_icmd(dev, 0x0000029f, 0x00000000); + nv_icmd(dev, 0x000003b0, 0x00000000); + nv_icmd(dev, 0x000003b1, 0x00000000); + nv_icmd(dev, 0x000003b2, 0x00000000); + nv_icmd(dev, 0x000003b3, 0x00000000); + nv_icmd(dev, 0x000003b4, 0x00000000); + nv_icmd(dev, 0x000003b5, 0x00000000); + nv_icmd(dev, 0x000003b6, 0x00000000); + nv_icmd(dev, 0x000003b7, 0x00000000); + nv_icmd(dev, 0x000003b8, 0x00000000); + nv_icmd(dev, 0x000003b9, 0x00000000); + nv_icmd(dev, 0x000003ba, 0x00000000); + nv_icmd(dev, 0x000003bb, 0x00000000); + nv_icmd(dev, 0x000003bc, 0x00000000); + nv_icmd(dev, 0x000003bd, 0x00000000); + nv_icmd(dev, 0x000003be, 0x00000000); + nv_icmd(dev, 0x000003bf, 0x00000000); + nv_icmd(dev, 0x000002a0, 0x00000000); + nv_icmd(dev, 0x000002a1, 0x00000000); + nv_icmd(dev, 0x000002a2, 0x00000000); + nv_icmd(dev, 0x000002a3, 0x00000000); + nv_icmd(dev, 0x000002a4, 0x00000000); + nv_icmd(dev, 0x000002a5, 0x00000000); + nv_icmd(dev, 0x000002a6, 0x00000000); + nv_icmd(dev, 0x000002a7, 0x00000000); + nv_icmd(dev, 0x000002a8, 0x00000000); + nv_icmd(dev, 0x000002a9, 0x00000000); + nv_icmd(dev, 0x000002aa, 0x00000000); + nv_icmd(dev, 0x000002ab, 0x00000000); + nv_icmd(dev, 0x000002ac, 0x00000000); + nv_icmd(dev, 0x000002ad, 0x00000000); + nv_icmd(dev, 0x000002ae, 0x00000000); + nv_icmd(dev, 0x000002af, 0x00000000); + nv_icmd(dev, 0x00000420, 0x00000000); + nv_icmd(dev, 0x00000421, 0x00000000); + nv_icmd(dev, 0x00000422, 0x00000000); + nv_icmd(dev, 0x00000423, 0x00000000); + nv_icmd(dev, 0x00000424, 0x00000000); + nv_icmd(dev, 0x00000425, 0x00000000); + nv_icmd(dev, 0x00000426, 0x00000000); + nv_icmd(dev, 0x00000427, 0x00000000); + nv_icmd(dev, 0x00000428, 0x00000000); + nv_icmd(dev, 0x00000429, 0x00000000); + nv_icmd(dev, 0x0000042a, 0x00000000); + nv_icmd(dev, 0x0000042b, 0x00000000); + nv_icmd(dev, 0x0000042c, 0x00000000); + nv_icmd(dev, 0x0000042d, 0x00000000); + nv_icmd(dev, 0x0000042e, 0x00000000); + nv_icmd(dev, 0x0000042f, 0x00000000); + nv_icmd(dev, 0x000002b0, 0x00000000); + nv_icmd(dev, 0x000002b1, 0x00000000); + nv_icmd(dev, 0x000002b2, 0x00000000); + nv_icmd(dev, 0x000002b3, 0x00000000); + nv_icmd(dev, 0x000002b4, 0x00000000); + nv_icmd(dev, 0x000002b5, 0x00000000); + nv_icmd(dev, 0x000002b6, 0x00000000); + nv_icmd(dev, 0x000002b7, 0x00000000); + nv_icmd(dev, 0x000002b8, 0x00000000); + nv_icmd(dev, 0x000002b9, 0x00000000); + nv_icmd(dev, 0x000002ba, 0x00000000); + nv_icmd(dev, 0x000002bb, 0x00000000); + nv_icmd(dev, 0x000002bc, 0x00000000); + nv_icmd(dev, 0x000002bd, 0x00000000); + nv_icmd(dev, 0x000002be, 0x00000000); + nv_icmd(dev, 0x000002bf, 0x00000000); + nv_icmd(dev, 0x00000430, 0x00000000); + nv_icmd(dev, 0x00000431, 0x00000000); + nv_icmd(dev, 0x00000432, 0x00000000); + nv_icmd(dev, 0x00000433, 0x00000000); + nv_icmd(dev, 0x00000434, 0x00000000); + nv_icmd(dev, 0x00000435, 0x00000000); + nv_icmd(dev, 0x00000436, 0x00000000); + nv_icmd(dev, 0x00000437, 0x00000000); + nv_icmd(dev, 0x00000438, 0x00000000); + nv_icmd(dev, 0x00000439, 0x00000000); + nv_icmd(dev, 0x0000043a, 0x00000000); + nv_icmd(dev, 0x0000043b, 0x00000000); + nv_icmd(dev, 0x0000043c, 0x00000000); + nv_icmd(dev, 0x0000043d, 0x00000000); + nv_icmd(dev, 0x0000043e, 0x00000000); + nv_icmd(dev, 0x0000043f, 0x00000000); + nv_icmd(dev, 0x000002c0, 0x00000000); + nv_icmd(dev, 0x000002c1, 0x00000000); + nv_icmd(dev, 0x000002c2, 0x00000000); + nv_icmd(dev, 0x000002c3, 0x00000000); + nv_icmd(dev, 0x000002c4, 0x00000000); + nv_icmd(dev, 0x000002c5, 0x00000000); + nv_icmd(dev, 0x000002c6, 0x00000000); + nv_icmd(dev, 0x000002c7, 0x00000000); + nv_icmd(dev, 0x000002c8, 0x00000000); + nv_icmd(dev, 0x000002c9, 0x00000000); + nv_icmd(dev, 0x000002ca, 0x00000000); + nv_icmd(dev, 0x000002cb, 0x00000000); + nv_icmd(dev, 0x000002cc, 0x00000000); + nv_icmd(dev, 0x000002cd, 0x00000000); + nv_icmd(dev, 0x000002ce, 0x00000000); + nv_icmd(dev, 0x000002cf, 0x00000000); + nv_icmd(dev, 0x000004d0, 0x00000000); + nv_icmd(dev, 0x000004d1, 0x00000000); + nv_icmd(dev, 0x000004d2, 0x00000000); + nv_icmd(dev, 0x000004d3, 0x00000000); + nv_icmd(dev, 0x000004d4, 0x00000000); + nv_icmd(dev, 0x000004d5, 0x00000000); + nv_icmd(dev, 0x000004d6, 0x00000000); + nv_icmd(dev, 0x000004d7, 0x00000000); + nv_icmd(dev, 0x000004d8, 0x00000000); + nv_icmd(dev, 0x000004d9, 0x00000000); + nv_icmd(dev, 0x000004da, 0x00000000); + nv_icmd(dev, 0x000004db, 0x00000000); + nv_icmd(dev, 0x000004dc, 0x00000000); + nv_icmd(dev, 0x000004dd, 0x00000000); + nv_icmd(dev, 0x000004de, 0x00000000); + nv_icmd(dev, 0x000004df, 0x00000000); + nv_icmd(dev, 0x00000720, 0x00000000); + nv_icmd(dev, 0x00000721, 0x00000000); + nv_icmd(dev, 0x00000722, 0x00000000); + nv_icmd(dev, 0x00000723, 0x00000000); + nv_icmd(dev, 0x00000724, 0x00000000); + nv_icmd(dev, 0x00000725, 0x00000000); + nv_icmd(dev, 0x00000726, 0x00000000); + nv_icmd(dev, 0x00000727, 0x00000000); + nv_icmd(dev, 0x00000728, 0x00000000); + nv_icmd(dev, 0x00000729, 0x00000000); + nv_icmd(dev, 0x0000072a, 0x00000000); + nv_icmd(dev, 0x0000072b, 0x00000000); + nv_icmd(dev, 0x0000072c, 0x00000000); + nv_icmd(dev, 0x0000072d, 0x00000000); + nv_icmd(dev, 0x0000072e, 0x00000000); + nv_icmd(dev, 0x0000072f, 0x00000000); + nv_icmd(dev, 0x000008c0, 0x00000000); + nv_icmd(dev, 0x000008c1, 0x00000000); + nv_icmd(dev, 0x000008c2, 0x00000000); + nv_icmd(dev, 0x000008c3, 0x00000000); + nv_icmd(dev, 0x000008c4, 0x00000000); + nv_icmd(dev, 0x000008c5, 0x00000000); + nv_icmd(dev, 0x000008c6, 0x00000000); + nv_icmd(dev, 0x000008c7, 0x00000000); + nv_icmd(dev, 0x000008c8, 0x00000000); + nv_icmd(dev, 0x000008c9, 0x00000000); + nv_icmd(dev, 0x000008ca, 0x00000000); + nv_icmd(dev, 0x000008cb, 0x00000000); + nv_icmd(dev, 0x000008cc, 0x00000000); + nv_icmd(dev, 0x000008cd, 0x00000000); + nv_icmd(dev, 0x000008ce, 0x00000000); + nv_icmd(dev, 0x000008cf, 0x00000000); + nv_icmd(dev, 0x00000890, 0x00000000); + nv_icmd(dev, 0x00000891, 0x00000000); + nv_icmd(dev, 0x00000892, 0x00000000); + nv_icmd(dev, 0x00000893, 0x00000000); + nv_icmd(dev, 0x00000894, 0x00000000); + nv_icmd(dev, 0x00000895, 0x00000000); + nv_icmd(dev, 0x00000896, 0x00000000); + nv_icmd(dev, 0x00000897, 0x00000000); + nv_icmd(dev, 0x00000898, 0x00000000); + nv_icmd(dev, 0x00000899, 0x00000000); + nv_icmd(dev, 0x0000089a, 0x00000000); + nv_icmd(dev, 0x0000089b, 0x00000000); + nv_icmd(dev, 0x0000089c, 0x00000000); + nv_icmd(dev, 0x0000089d, 0x00000000); + nv_icmd(dev, 0x0000089e, 0x00000000); + nv_icmd(dev, 0x0000089f, 0x00000000); + nv_icmd(dev, 0x000008e0, 0x00000000); + nv_icmd(dev, 0x000008e1, 0x00000000); + nv_icmd(dev, 0x000008e2, 0x00000000); + nv_icmd(dev, 0x000008e3, 0x00000000); + nv_icmd(dev, 0x000008e4, 0x00000000); + nv_icmd(dev, 0x000008e5, 0x00000000); + nv_icmd(dev, 0x000008e6, 0x00000000); + nv_icmd(dev, 0x000008e7, 0x00000000); + nv_icmd(dev, 0x000008e8, 0x00000000); + nv_icmd(dev, 0x000008e9, 0x00000000); + nv_icmd(dev, 0x000008ea, 0x00000000); + nv_icmd(dev, 0x000008eb, 0x00000000); + nv_icmd(dev, 0x000008ec, 0x00000000); + nv_icmd(dev, 0x000008ed, 0x00000000); + nv_icmd(dev, 0x000008ee, 0x00000000); + nv_icmd(dev, 0x000008ef, 0x00000000); + nv_icmd(dev, 0x000008a0, 0x00000000); + nv_icmd(dev, 0x000008a1, 0x00000000); + nv_icmd(dev, 0x000008a2, 0x00000000); + nv_icmd(dev, 0x000008a3, 0x00000000); + nv_icmd(dev, 0x000008a4, 0x00000000); + nv_icmd(dev, 0x000008a5, 0x00000000); + nv_icmd(dev, 0x000008a6, 0x00000000); + nv_icmd(dev, 0x000008a7, 0x00000000); + nv_icmd(dev, 0x000008a8, 0x00000000); + nv_icmd(dev, 0x000008a9, 0x00000000); + nv_icmd(dev, 0x000008aa, 0x00000000); + nv_icmd(dev, 0x000008ab, 0x00000000); + nv_icmd(dev, 0x000008ac, 0x00000000); + nv_icmd(dev, 0x000008ad, 0x00000000); + nv_icmd(dev, 0x000008ae, 0x00000000); + nv_icmd(dev, 0x000008af, 0x00000000); + nv_icmd(dev, 0x000008f0, 0x00000000); + nv_icmd(dev, 0x000008f1, 0x00000000); + nv_icmd(dev, 0x000008f2, 0x00000000); + nv_icmd(dev, 0x000008f3, 0x00000000); + nv_icmd(dev, 0x000008f4, 0x00000000); + nv_icmd(dev, 0x000008f5, 0x00000000); + nv_icmd(dev, 0x000008f6, 0x00000000); + nv_icmd(dev, 0x000008f7, 0x00000000); + nv_icmd(dev, 0x000008f8, 0x00000000); + nv_icmd(dev, 0x000008f9, 0x00000000); + nv_icmd(dev, 0x000008fa, 0x00000000); + nv_icmd(dev, 0x000008fb, 0x00000000); + nv_icmd(dev, 0x000008fc, 0x00000000); + nv_icmd(dev, 0x000008fd, 0x00000000); + nv_icmd(dev, 0x000008fe, 0x00000000); + nv_icmd(dev, 0x000008ff, 0x00000000); + nv_icmd(dev, 0x0000094c, 0x000000ff); + nv_icmd(dev, 0x0000094d, 0xffffffff); + nv_icmd(dev, 0x0000094e, 0x00000002); + nv_icmd(dev, 0x000002ec, 0x00000001); + nv_icmd(dev, 0x00000303, 0x00000001); + nv_icmd(dev, 0x000002e6, 0x00000001); + nv_icmd(dev, 0x00000466, 0x00000052); + nv_icmd(dev, 0x00000301, 0x3f800000); + nv_icmd(dev, 0x00000304, 0x30201000); + nv_icmd(dev, 0x00000305, 0x70605040); + nv_icmd(dev, 0x00000306, 0xb8a89888); + nv_icmd(dev, 0x00000307, 0xf8e8d8c8); + nv_icmd(dev, 0x0000030a, 0x00ffff00); + nv_icmd(dev, 0x0000030b, 0x0000001a); + nv_icmd(dev, 0x0000030c, 0x00000001); + nv_icmd(dev, 0x00000318, 0x00000001); + nv_icmd(dev, 0x00000340, 0x00000000); + nv_icmd(dev, 0x00000375, 0x00000001); + nv_icmd(dev, 0x00000351, 0x00000100); + nv_icmd(dev, 0x0000037d, 0x00000006); + nv_icmd(dev, 0x000003a0, 0x00000002); + nv_icmd(dev, 0x000003aa, 0x00000001); + nv_icmd(dev, 0x000003a9, 0x00000001); + nv_icmd(dev, 0x00000380, 0x00000001); + nv_icmd(dev, 0x00000360, 0x00000040); + nv_icmd(dev, 0x00000366, 0x00000000); + nv_icmd(dev, 0x00000367, 0x00000000); + nv_icmd(dev, 0x00000368, 0x00001fff); + nv_icmd(dev, 0x00000370, 0x00000000); + nv_icmd(dev, 0x00000371, 0x00000000); + nv_icmd(dev, 0x00000372, 0x003fffff); + nv_icmd(dev, 0x0000037a, 0x00000012); + nv_icmd(dev, 0x000005e0, 0x00000022); + nv_icmd(dev, 0x000005e1, 0x00000022); + nv_icmd(dev, 0x000005e2, 0x00000022); + nv_icmd(dev, 0x000005e3, 0x00000022); + nv_icmd(dev, 0x000005e4, 0x00000022); + nv_icmd(dev, 0x00000619, 0x00000003); + nv_icmd(dev, 0x00000811, 0x00000003); + nv_icmd(dev, 0x00000812, 0x00000004); + nv_icmd(dev, 0x00000813, 0x00000006); + nv_icmd(dev, 0x00000814, 0x00000008); + nv_icmd(dev, 0x00000815, 0x0000000b); + nv_icmd(dev, 0x00000800, 0x00000001); + nv_icmd(dev, 0x00000801, 0x00000001); + nv_icmd(dev, 0x00000802, 0x00000001); + nv_icmd(dev, 0x00000803, 0x00000001); + nv_icmd(dev, 0x00000804, 0x00000001); + nv_icmd(dev, 0x00000805, 0x00000001); + nv_icmd(dev, 0x00000632, 0x00000001); + nv_icmd(dev, 0x00000633, 0x00000002); + nv_icmd(dev, 0x00000634, 0x00000003); + nv_icmd(dev, 0x00000635, 0x00000004); + nv_icmd(dev, 0x00000654, 0x3f800000); + nv_icmd(dev, 0x00000657, 0x3f800000); + nv_icmd(dev, 0x00000655, 0x3f800000); + nv_icmd(dev, 0x00000656, 0x3f800000); + nv_icmd(dev, 0x000006cd, 0x3f800000); + nv_icmd(dev, 0x000007f5, 0x3f800000); + nv_icmd(dev, 0x000007dc, 0x39291909); + nv_icmd(dev, 0x000007dd, 0x79695949); + nv_icmd(dev, 0x000007de, 0xb9a99989); + nv_icmd(dev, 0x000007df, 0xf9e9d9c9); + nv_icmd(dev, 0x000007e8, 0x00003210); + nv_icmd(dev, 0x000007e9, 0x00007654); + nv_icmd(dev, 0x000007ea, 0x00000098); + nv_icmd(dev, 0x000007ec, 0x39291909); + nv_icmd(dev, 0x000007ed, 0x79695949); + nv_icmd(dev, 0x000007ee, 0xb9a99989); + nv_icmd(dev, 0x000007ef, 0xf9e9d9c9); + nv_icmd(dev, 0x000007f0, 0x00003210); + nv_icmd(dev, 0x000007f1, 0x00007654); + nv_icmd(dev, 0x000007f2, 0x00000098); + nv_icmd(dev, 0x000005a5, 0x00000001); + nv_icmd(dev, 0x00000980, 0x00000000); + nv_icmd(dev, 0x00000981, 0x00000000); + nv_icmd(dev, 0x00000982, 0x00000000); + nv_icmd(dev, 0x00000983, 0x00000000); + nv_icmd(dev, 0x00000984, 0x00000000); + nv_icmd(dev, 0x00000985, 0x00000000); + nv_icmd(dev, 0x00000986, 0x00000000); + nv_icmd(dev, 0x00000987, 0x00000000); + nv_icmd(dev, 0x00000988, 0x00000000); + nv_icmd(dev, 0x00000989, 0x00000000); + nv_icmd(dev, 0x0000098a, 0x00000000); + nv_icmd(dev, 0x0000098b, 0x00000000); + nv_icmd(dev, 0x0000098c, 0x00000000); + nv_icmd(dev, 0x0000098d, 0x00000000); + nv_icmd(dev, 0x0000098e, 0x00000000); + nv_icmd(dev, 0x0000098f, 0x00000000); + nv_icmd(dev, 0x00000990, 0x00000000); + nv_icmd(dev, 0x00000991, 0x00000000); + nv_icmd(dev, 0x00000992, 0x00000000); + nv_icmd(dev, 0x00000993, 0x00000000); + nv_icmd(dev, 0x00000994, 0x00000000); + nv_icmd(dev, 0x00000995, 0x00000000); + nv_icmd(dev, 0x00000996, 0x00000000); + nv_icmd(dev, 0x00000997, 0x00000000); + nv_icmd(dev, 0x00000998, 0x00000000); + nv_icmd(dev, 0x00000999, 0x00000000); + nv_icmd(dev, 0x0000099a, 0x00000000); + nv_icmd(dev, 0x0000099b, 0x00000000); + nv_icmd(dev, 0x0000099c, 0x00000000); + nv_icmd(dev, 0x0000099d, 0x00000000); + nv_icmd(dev, 0x0000099e, 0x00000000); + nv_icmd(dev, 0x0000099f, 0x00000000); + nv_icmd(dev, 0x000009a0, 0x00000000); + nv_icmd(dev, 0x000009a1, 0x00000000); + nv_icmd(dev, 0x000009a2, 0x00000000); + nv_icmd(dev, 0x000009a3, 0x00000000); + nv_icmd(dev, 0x000009a4, 0x00000000); + nv_icmd(dev, 0x000009a5, 0x00000000); + nv_icmd(dev, 0x000009a6, 0x00000000); + nv_icmd(dev, 0x000009a7, 0x00000000); + nv_icmd(dev, 0x000009a8, 0x00000000); + nv_icmd(dev, 0x000009a9, 0x00000000); + nv_icmd(dev, 0x000009aa, 0x00000000); + nv_icmd(dev, 0x000009ab, 0x00000000); + nv_icmd(dev, 0x000009ac, 0x00000000); + nv_icmd(dev, 0x000009ad, 0x00000000); + nv_icmd(dev, 0x000009ae, 0x00000000); + nv_icmd(dev, 0x000009af, 0x00000000); + nv_icmd(dev, 0x000009b0, 0x00000000); + nv_icmd(dev, 0x000009b1, 0x00000000); + nv_icmd(dev, 0x000009b2, 0x00000000); + nv_icmd(dev, 0x000009b3, 0x00000000); + nv_icmd(dev, 0x000009b4, 0x00000000); + nv_icmd(dev, 0x000009b5, 0x00000000); + nv_icmd(dev, 0x000009b6, 0x00000000); + nv_icmd(dev, 0x000009b7, 0x00000000); + nv_icmd(dev, 0x000009b8, 0x00000000); + nv_icmd(dev, 0x000009b9, 0x00000000); + nv_icmd(dev, 0x000009ba, 0x00000000); + nv_icmd(dev, 0x000009bb, 0x00000000); + nv_icmd(dev, 0x000009bc, 0x00000000); + nv_icmd(dev, 0x000009bd, 0x00000000); + nv_icmd(dev, 0x000009be, 0x00000000); + nv_icmd(dev, 0x000009bf, 0x00000000); + nv_icmd(dev, 0x000009c0, 0x00000000); + nv_icmd(dev, 0x000009c1, 0x00000000); + nv_icmd(dev, 0x000009c2, 0x00000000); + nv_icmd(dev, 0x000009c3, 0x00000000); + nv_icmd(dev, 0x000009c4, 0x00000000); + nv_icmd(dev, 0x000009c5, 0x00000000); + nv_icmd(dev, 0x000009c6, 0x00000000); + nv_icmd(dev, 0x000009c7, 0x00000000); + nv_icmd(dev, 0x000009c8, 0x00000000); + nv_icmd(dev, 0x000009c9, 0x00000000); + nv_icmd(dev, 0x000009ca, 0x00000000); + nv_icmd(dev, 0x000009cb, 0x00000000); + nv_icmd(dev, 0x000009cc, 0x00000000); + nv_icmd(dev, 0x000009cd, 0x00000000); + nv_icmd(dev, 0x000009ce, 0x00000000); + nv_icmd(dev, 0x000009cf, 0x00000000); + nv_icmd(dev, 0x000009d0, 0x00000000); + nv_icmd(dev, 0x000009d1, 0x00000000); + nv_icmd(dev, 0x000009d2, 0x00000000); + nv_icmd(dev, 0x000009d3, 0x00000000); + nv_icmd(dev, 0x000009d4, 0x00000000); + nv_icmd(dev, 0x000009d5, 0x00000000); + nv_icmd(dev, 0x000009d6, 0x00000000); + nv_icmd(dev, 0x000009d7, 0x00000000); + nv_icmd(dev, 0x000009d8, 0x00000000); + nv_icmd(dev, 0x000009d9, 0x00000000); + nv_icmd(dev, 0x000009da, 0x00000000); + nv_icmd(dev, 0x000009db, 0x00000000); + nv_icmd(dev, 0x000009dc, 0x00000000); + nv_icmd(dev, 0x000009dd, 0x00000000); + nv_icmd(dev, 0x000009de, 0x00000000); + nv_icmd(dev, 0x000009df, 0x00000000); + nv_icmd(dev, 0x000009e0, 0x00000000); + nv_icmd(dev, 0x000009e1, 0x00000000); + nv_icmd(dev, 0x000009e2, 0x00000000); + nv_icmd(dev, 0x000009e3, 0x00000000); + nv_icmd(dev, 0x000009e4, 0x00000000); + nv_icmd(dev, 0x000009e5, 0x00000000); + nv_icmd(dev, 0x000009e6, 0x00000000); + nv_icmd(dev, 0x000009e7, 0x00000000); + nv_icmd(dev, 0x000009e8, 0x00000000); + nv_icmd(dev, 0x000009e9, 0x00000000); + nv_icmd(dev, 0x000009ea, 0x00000000); + nv_icmd(dev, 0x000009eb, 0x00000000); + nv_icmd(dev, 0x000009ec, 0x00000000); + nv_icmd(dev, 0x000009ed, 0x00000000); + nv_icmd(dev, 0x000009ee, 0x00000000); + nv_icmd(dev, 0x000009ef, 0x00000000); + nv_icmd(dev, 0x000009f0, 0x00000000); + nv_icmd(dev, 0x000009f1, 0x00000000); + nv_icmd(dev, 0x000009f2, 0x00000000); + nv_icmd(dev, 0x000009f3, 0x00000000); + nv_icmd(dev, 0x000009f4, 0x00000000); + nv_icmd(dev, 0x000009f5, 0x00000000); + nv_icmd(dev, 0x000009f6, 0x00000000); + nv_icmd(dev, 0x000009f7, 0x00000000); + nv_icmd(dev, 0x000009f8, 0x00000000); + nv_icmd(dev, 0x000009f9, 0x00000000); + nv_icmd(dev, 0x000009fa, 0x00000000); + nv_icmd(dev, 0x000009fb, 0x00000000); + nv_icmd(dev, 0x000009fc, 0x00000000); + nv_icmd(dev, 0x000009fd, 0x00000000); + nv_icmd(dev, 0x000009fe, 0x00000000); + nv_icmd(dev, 0x000009ff, 0x00000000); + nv_icmd(dev, 0x00000468, 0x00000004); + nv_icmd(dev, 0x0000046c, 0x00000001); + nv_icmd(dev, 0x00000470, 0x00000000); + nv_icmd(dev, 0x00000471, 0x00000000); + nv_icmd(dev, 0x00000472, 0x00000000); + nv_icmd(dev, 0x00000473, 0x00000000); + nv_icmd(dev, 0x00000474, 0x00000000); + nv_icmd(dev, 0x00000475, 0x00000000); + nv_icmd(dev, 0x00000476, 0x00000000); + nv_icmd(dev, 0x00000477, 0x00000000); + nv_icmd(dev, 0x00000478, 0x00000000); + nv_icmd(dev, 0x00000479, 0x00000000); + nv_icmd(dev, 0x0000047a, 0x00000000); + nv_icmd(dev, 0x0000047b, 0x00000000); + nv_icmd(dev, 0x0000047c, 0x00000000); + nv_icmd(dev, 0x0000047d, 0x00000000); + nv_icmd(dev, 0x0000047e, 0x00000000); + nv_icmd(dev, 0x0000047f, 0x00000000); + nv_icmd(dev, 0x00000480, 0x00000000); + nv_icmd(dev, 0x00000481, 0x00000000); + nv_icmd(dev, 0x00000482, 0x00000000); + nv_icmd(dev, 0x00000483, 0x00000000); + nv_icmd(dev, 0x00000484, 0x00000000); + nv_icmd(dev, 0x00000485, 0x00000000); + nv_icmd(dev, 0x00000486, 0x00000000); + nv_icmd(dev, 0x00000487, 0x00000000); + nv_icmd(dev, 0x00000488, 0x00000000); + nv_icmd(dev, 0x00000489, 0x00000000); + nv_icmd(dev, 0x0000048a, 0x00000000); + nv_icmd(dev, 0x0000048b, 0x00000000); + nv_icmd(dev, 0x0000048c, 0x00000000); + nv_icmd(dev, 0x0000048d, 0x00000000); + nv_icmd(dev, 0x0000048e, 0x00000000); + nv_icmd(dev, 0x0000048f, 0x00000000); + nv_icmd(dev, 0x00000490, 0x00000000); + nv_icmd(dev, 0x00000491, 0x00000000); + nv_icmd(dev, 0x00000492, 0x00000000); + nv_icmd(dev, 0x00000493, 0x00000000); + nv_icmd(dev, 0x00000494, 0x00000000); + nv_icmd(dev, 0x00000495, 0x00000000); + nv_icmd(dev, 0x00000496, 0x00000000); + nv_icmd(dev, 0x00000497, 0x00000000); + nv_icmd(dev, 0x00000498, 0x00000000); + nv_icmd(dev, 0x00000499, 0x00000000); + nv_icmd(dev, 0x0000049a, 0x00000000); + nv_icmd(dev, 0x0000049b, 0x00000000); + nv_icmd(dev, 0x0000049c, 0x00000000); + nv_icmd(dev, 0x0000049d, 0x00000000); + nv_icmd(dev, 0x0000049e, 0x00000000); + nv_icmd(dev, 0x0000049f, 0x00000000); + nv_icmd(dev, 0x000004a0, 0x00000000); + nv_icmd(dev, 0x000004a1, 0x00000000); + nv_icmd(dev, 0x000004a2, 0x00000000); + nv_icmd(dev, 0x000004a3, 0x00000000); + nv_icmd(dev, 0x000004a4, 0x00000000); + nv_icmd(dev, 0x000004a5, 0x00000000); + nv_icmd(dev, 0x000004a6, 0x00000000); + nv_icmd(dev, 0x000004a7, 0x00000000); + nv_icmd(dev, 0x000004a8, 0x00000000); + nv_icmd(dev, 0x000004a9, 0x00000000); + nv_icmd(dev, 0x000004aa, 0x00000000); + nv_icmd(dev, 0x000004ab, 0x00000000); + nv_icmd(dev, 0x000004ac, 0x00000000); + nv_icmd(dev, 0x000004ad, 0x00000000); + nv_icmd(dev, 0x000004ae, 0x00000000); + nv_icmd(dev, 0x000004af, 0x00000000); + nv_icmd(dev, 0x000004b0, 0x00000000); + nv_icmd(dev, 0x000004b1, 0x00000000); + nv_icmd(dev, 0x000004b2, 0x00000000); + nv_icmd(dev, 0x000004b3, 0x00000000); + nv_icmd(dev, 0x000004b4, 0x00000000); + nv_icmd(dev, 0x000004b5, 0x00000000); + nv_icmd(dev, 0x000004b6, 0x00000000); + nv_icmd(dev, 0x000004b7, 0x00000000); + nv_icmd(dev, 0x000004b8, 0x00000000); + nv_icmd(dev, 0x000004b9, 0x00000000); + nv_icmd(dev, 0x000004ba, 0x00000000); + nv_icmd(dev, 0x000004bb, 0x00000000); + nv_icmd(dev, 0x000004bc, 0x00000000); + nv_icmd(dev, 0x000004bd, 0x00000000); + nv_icmd(dev, 0x000004be, 0x00000000); + nv_icmd(dev, 0x000004bf, 0x00000000); + nv_icmd(dev, 0x000004c0, 0x00000000); + nv_icmd(dev, 0x000004c1, 0x00000000); + nv_icmd(dev, 0x000004c2, 0x00000000); + nv_icmd(dev, 0x000004c3, 0x00000000); + nv_icmd(dev, 0x000004c4, 0x00000000); + nv_icmd(dev, 0x000004c5, 0x00000000); + nv_icmd(dev, 0x000004c6, 0x00000000); + nv_icmd(dev, 0x000004c7, 0x00000000); + nv_icmd(dev, 0x000004c8, 0x00000000); + nv_icmd(dev, 0x000004c9, 0x00000000); + nv_icmd(dev, 0x000004ca, 0x00000000); + nv_icmd(dev, 0x000004cb, 0x00000000); + nv_icmd(dev, 0x000004cc, 0x00000000); + nv_icmd(dev, 0x000004cd, 0x00000000); + nv_icmd(dev, 0x000004ce, 0x00000000); + nv_icmd(dev, 0x000004cf, 0x00000000); + nv_icmd(dev, 0x00000510, 0x3f800000); + nv_icmd(dev, 0x00000511, 0x3f800000); + nv_icmd(dev, 0x00000512, 0x3f800000); + nv_icmd(dev, 0x00000513, 0x3f800000); + nv_icmd(dev, 0x00000514, 0x3f800000); + nv_icmd(dev, 0x00000515, 0x3f800000); + nv_icmd(dev, 0x00000516, 0x3f800000); + nv_icmd(dev, 0x00000517, 0x3f800000); + nv_icmd(dev, 0x00000518, 0x3f800000); + nv_icmd(dev, 0x00000519, 0x3f800000); + nv_icmd(dev, 0x0000051a, 0x3f800000); + nv_icmd(dev, 0x0000051b, 0x3f800000); + nv_icmd(dev, 0x0000051c, 0x3f800000); + nv_icmd(dev, 0x0000051d, 0x3f800000); + nv_icmd(dev, 0x0000051e, 0x3f800000); + nv_icmd(dev, 0x0000051f, 0x3f800000); + nv_icmd(dev, 0x00000520, 0x000002b6); + nv_icmd(dev, 0x00000529, 0x00000001); + nv_icmd(dev, 0x00000530, 0xffff0000); + nv_icmd(dev, 0x00000531, 0xffff0000); + nv_icmd(dev, 0x00000532, 0xffff0000); + nv_icmd(dev, 0x00000533, 0xffff0000); + nv_icmd(dev, 0x00000534, 0xffff0000); + nv_icmd(dev, 0x00000535, 0xffff0000); + nv_icmd(dev, 0x00000536, 0xffff0000); + nv_icmd(dev, 0x00000537, 0xffff0000); + nv_icmd(dev, 0x00000538, 0xffff0000); + nv_icmd(dev, 0x00000539, 0xffff0000); + nv_icmd(dev, 0x0000053a, 0xffff0000); + nv_icmd(dev, 0x0000053b, 0xffff0000); + nv_icmd(dev, 0x0000053c, 0xffff0000); + nv_icmd(dev, 0x0000053d, 0xffff0000); + nv_icmd(dev, 0x0000053e, 0xffff0000); + nv_icmd(dev, 0x0000053f, 0xffff0000); + nv_icmd(dev, 0x00000585, 0x0000003f); + nv_icmd(dev, 0x00000576, 0x00000003); + nv_icmd(dev, 0x00000586, 0x00000040); + nv_icmd(dev, 0x00000582, 0x00000080); + nv_icmd(dev, 0x00000583, 0x00000080); + nv_icmd(dev, 0x000005c2, 0x00000001); + nv_icmd(dev, 0x00000638, 0x00000001); + nv_icmd(dev, 0x00000639, 0x00000001); + nv_icmd(dev, 0x0000063a, 0x00000002); + nv_icmd(dev, 0x0000063b, 0x00000001); + nv_icmd(dev, 0x0000063c, 0x00000001); + nv_icmd(dev, 0x0000063d, 0x00000002); + nv_icmd(dev, 0x0000063e, 0x00000001); + nv_icmd(dev, 0x000008b8, 0x00000001); + nv_icmd(dev, 0x000008b9, 0x00000001); + nv_icmd(dev, 0x000008ba, 0x00000001); + nv_icmd(dev, 0x000008bb, 0x00000001); + nv_icmd(dev, 0x000008bc, 0x00000001); + nv_icmd(dev, 0x000008bd, 0x00000001); + nv_icmd(dev, 0x000008be, 0x00000001); + nv_icmd(dev, 0x000008bf, 0x00000001); + nv_icmd(dev, 0x00000900, 0x00000001); + nv_icmd(dev, 0x00000901, 0x00000001); + nv_icmd(dev, 0x00000902, 0x00000001); + nv_icmd(dev, 0x00000903, 0x00000001); + nv_icmd(dev, 0x00000904, 0x00000001); + nv_icmd(dev, 0x00000905, 0x00000001); + nv_icmd(dev, 0x00000906, 0x00000001); + nv_icmd(dev, 0x00000907, 0x00000001); + nv_icmd(dev, 0x00000908, 0x00000002); + nv_icmd(dev, 0x00000909, 0x00000002); + nv_icmd(dev, 0x0000090a, 0x00000002); + nv_icmd(dev, 0x0000090b, 0x00000002); + nv_icmd(dev, 0x0000090c, 0x00000002); + nv_icmd(dev, 0x0000090d, 0x00000002); + nv_icmd(dev, 0x0000090e, 0x00000002); + nv_icmd(dev, 0x0000090f, 0x00000002); + nv_icmd(dev, 0x00000910, 0x00000001); + nv_icmd(dev, 0x00000911, 0x00000001); + nv_icmd(dev, 0x00000912, 0x00000001); + nv_icmd(dev, 0x00000913, 0x00000001); + nv_icmd(dev, 0x00000914, 0x00000001); + nv_icmd(dev, 0x00000915, 0x00000001); + nv_icmd(dev, 0x00000916, 0x00000001); + nv_icmd(dev, 0x00000917, 0x00000001); + nv_icmd(dev, 0x00000918, 0x00000001); + nv_icmd(dev, 0x00000919, 0x00000001); + nv_icmd(dev, 0x0000091a, 0x00000001); + nv_icmd(dev, 0x0000091b, 0x00000001); + nv_icmd(dev, 0x0000091c, 0x00000001); + nv_icmd(dev, 0x0000091d, 0x00000001); + nv_icmd(dev, 0x0000091e, 0x00000001); + nv_icmd(dev, 0x0000091f, 0x00000001); + nv_icmd(dev, 0x00000920, 0x00000002); + nv_icmd(dev, 0x00000921, 0x00000002); + nv_icmd(dev, 0x00000922, 0x00000002); + nv_icmd(dev, 0x00000923, 0x00000002); + nv_icmd(dev, 0x00000924, 0x00000002); + nv_icmd(dev, 0x00000925, 0x00000002); + nv_icmd(dev, 0x00000926, 0x00000002); + nv_icmd(dev, 0x00000927, 0x00000002); + nv_icmd(dev, 0x00000928, 0x00000001); + nv_icmd(dev, 0x00000929, 0x00000001); + nv_icmd(dev, 0x0000092a, 0x00000001); + nv_icmd(dev, 0x0000092b, 0x00000001); + nv_icmd(dev, 0x0000092c, 0x00000001); + nv_icmd(dev, 0x0000092d, 0x00000001); + nv_icmd(dev, 0x0000092e, 0x00000001); + nv_icmd(dev, 0x0000092f, 0x00000001); + nv_icmd(dev, 0x00000648, 0x00000001); + nv_icmd(dev, 0x00000649, 0x00000001); + nv_icmd(dev, 0x0000064a, 0x00000001); + nv_icmd(dev, 0x0000064b, 0x00000001); + nv_icmd(dev, 0x0000064c, 0x00000001); + nv_icmd(dev, 0x0000064d, 0x00000001); + nv_icmd(dev, 0x0000064e, 0x00000001); + nv_icmd(dev, 0x0000064f, 0x00000001); + nv_icmd(dev, 0x00000650, 0x00000001); + nv_icmd(dev, 0x00000658, 0x0000000f); + nv_icmd(dev, 0x000007ff, 0x0000000a); + nv_icmd(dev, 0x0000066a, 0x40000000); + nv_icmd(dev, 0x0000066b, 0x10000000); + nv_icmd(dev, 0x0000066c, 0xffff0000); + nv_icmd(dev, 0x0000066d, 0xffff0000); + nv_icmd(dev, 0x000007af, 0x00000008); + nv_icmd(dev, 0x000007b0, 0x00000008); + nv_icmd(dev, 0x000007f6, 0x00000001); + nv_icmd(dev, 0x000006b2, 0x00000055); + nv_icmd(dev, 0x000007ad, 0x00000003); + nv_icmd(dev, 0x00000937, 0x00000001); + nv_icmd(dev, 0x00000971, 0x00000008); + nv_icmd(dev, 0x00000972, 0x00000040); + nv_icmd(dev, 0x00000973, 0x0000012c); + nv_icmd(dev, 0x0000097c, 0x00000040); + nv_icmd(dev, 0x00000979, 0x00000003); + nv_icmd(dev, 0x00000975, 0x00000020); + nv_icmd(dev, 0x00000976, 0x00000001); + nv_icmd(dev, 0x00000977, 0x00000020); + nv_icmd(dev, 0x00000978, 0x00000001); + nv_icmd(dev, 0x00000957, 0x00000003); + nv_icmd(dev, 0x0000095e, 0x20164010); + nv_icmd(dev, 0x0000095f, 0x00000020); + nv_icmd(dev, 0x00000683, 0x00000006); + nv_icmd(dev, 0x00000685, 0x003fffff); + nv_icmd(dev, 0x00000687, 0x00000c48); + nv_icmd(dev, 0x000006a0, 0x00000005); + nv_icmd(dev, 0x00000840, 0x00300008); + nv_icmd(dev, 0x00000841, 0x04000080); + nv_icmd(dev, 0x00000842, 0x00300008); + nv_icmd(dev, 0x00000843, 0x04000080); + nv_icmd(dev, 0x00000818, 0x00000000); + nv_icmd(dev, 0x00000819, 0x00000000); + nv_icmd(dev, 0x0000081a, 0x00000000); + nv_icmd(dev, 0x0000081b, 0x00000000); + nv_icmd(dev, 0x0000081c, 0x00000000); + nv_icmd(dev, 0x0000081d, 0x00000000); + nv_icmd(dev, 0x0000081e, 0x00000000); + nv_icmd(dev, 0x0000081f, 0x00000000); + nv_icmd(dev, 0x00000848, 0x00000000); + nv_icmd(dev, 0x00000849, 0x00000000); + nv_icmd(dev, 0x0000084a, 0x00000000); + nv_icmd(dev, 0x0000084b, 0x00000000); + nv_icmd(dev, 0x0000084c, 0x00000000); + nv_icmd(dev, 0x0000084d, 0x00000000); + nv_icmd(dev, 0x0000084e, 0x00000000); + nv_icmd(dev, 0x0000084f, 0x00000000); + nv_icmd(dev, 0x00000850, 0x00000000); + nv_icmd(dev, 0x00000851, 0x00000000); + nv_icmd(dev, 0x00000852, 0x00000000); + nv_icmd(dev, 0x00000853, 0x00000000); + nv_icmd(dev, 0x00000854, 0x00000000); + nv_icmd(dev, 0x00000855, 0x00000000); + nv_icmd(dev, 0x00000856, 0x00000000); + nv_icmd(dev, 0x00000857, 0x00000000); + nv_icmd(dev, 0x00000738, 0x00000000); + nv_icmd(dev, 0x000006aa, 0x00000001); + nv_icmd(dev, 0x000006ab, 0x00000002); + nv_icmd(dev, 0x000006ac, 0x00000080); + nv_icmd(dev, 0x000006ad, 0x00000100); + nv_icmd(dev, 0x000006ae, 0x00000100); + nv_icmd(dev, 0x000006b1, 0x00000011); + nv_icmd(dev, 0x000006bb, 0x000000cf); + nv_icmd(dev, 0x000006ce, 0x2a712488); + nv_icmd(dev, 0x00000739, 0x4085c000); + nv_icmd(dev, 0x0000073a, 0x00000080); + nv_icmd(dev, 0x00000786, 0x80000100); + nv_icmd(dev, 0x0000073c, 0x00010100); + nv_icmd(dev, 0x0000073d, 0x02800000); + nv_icmd(dev, 0x00000787, 0x000000cf); + nv_icmd(dev, 0x0000078c, 0x00000008); + nv_icmd(dev, 0x00000792, 0x00000001); + nv_icmd(dev, 0x00000794, 0x00000001); + nv_icmd(dev, 0x00000795, 0x00000001); + nv_icmd(dev, 0x00000796, 0x00000001); + nv_icmd(dev, 0x00000797, 0x000000cf); + nv_icmd(dev, 0x00000836, 0x00000001); + nv_icmd(dev, 0x0000079a, 0x00000002); + nv_icmd(dev, 0x00000833, 0x04444480); + nv_icmd(dev, 0x000007a1, 0x00000001); + nv_icmd(dev, 0x000007a3, 0x00000001); + nv_icmd(dev, 0x000007a4, 0x00000001); + nv_icmd(dev, 0x000007a5, 0x00000001); + nv_icmd(dev, 0x00000831, 0x00000004); + nv_icmd(dev, 0x0000080c, 0x00000002); + nv_icmd(dev, 0x0000080d, 0x00000100); + nv_icmd(dev, 0x0000080e, 0x00000100); + nv_icmd(dev, 0x0000080f, 0x00000001); + nv_icmd(dev, 0x00000823, 0x00000002); + nv_icmd(dev, 0x00000824, 0x00000100); + nv_icmd(dev, 0x00000825, 0x00000100); + nv_icmd(dev, 0x00000826, 0x00000001); + nv_icmd(dev, 0x0000095d, 0x00000001); + nv_icmd(dev, 0x0000082b, 0x00000004); + nv_icmd(dev, 0x00000942, 0x00010001); + nv_icmd(dev, 0x00000943, 0x00000001); + nv_icmd(dev, 0x00000944, 0x00000022); + nv_icmd(dev, 0x000007c5, 0x00010001); + nv_icmd(dev, 0x00000834, 0x00000001); + nv_icmd(dev, 0x000007c7, 0x00000001); + nv_icmd(dev, 0x0000c1b0, 0x0000000f); + nv_icmd(dev, 0x0000c1b1, 0x0000000f); + nv_icmd(dev, 0x0000c1b2, 0x0000000f); + nv_icmd(dev, 0x0000c1b3, 0x0000000f); + nv_icmd(dev, 0x0000c1b4, 0x0000000f); + nv_icmd(dev, 0x0000c1b5, 0x0000000f); + nv_icmd(dev, 0x0000c1b6, 0x0000000f); + nv_icmd(dev, 0x0000c1b7, 0x0000000f); + nv_icmd(dev, 0x0000c1b8, 0x0fac6881); + nv_icmd(dev, 0x0000c1b9, 0x00fac688); + nv_icmd(dev, 0x0001e100, 0x00000001); + nv_icmd(dev, 0x00001000, 0x00000002); + nv_icmd(dev, 0x000006aa, 0x00000001); + nv_icmd(dev, 0x000006ad, 0x00000100); + nv_icmd(dev, 0x000006ae, 0x00000100); + nv_icmd(dev, 0x000006b1, 0x00000011); + nv_icmd(dev, 0x0000078c, 0x00000008); + nv_icmd(dev, 0x00000792, 0x00000001); + nv_icmd(dev, 0x00000794, 0x00000001); + nv_icmd(dev, 0x00000795, 0x00000001); + nv_icmd(dev, 0x00000796, 0x00000001); + nv_icmd(dev, 0x00000797, 0x000000cf); + nv_icmd(dev, 0x0000079a, 0x00000002); + nv_icmd(dev, 0x00000833, 0x04444480); + nv_icmd(dev, 0x000007a1, 0x00000001); + nv_icmd(dev, 0x000007a3, 0x00000001); + nv_icmd(dev, 0x000007a4, 0x00000001); + nv_icmd(dev, 0x000007a5, 0x00000001); + nv_icmd(dev, 0x00000831, 0x00000004); + nv_icmd(dev, 0x0001e100, 0x00000001); + nv_icmd(dev, 0x00001000, 0x00000014); + nv_icmd(dev, 0x00000351, 0x00000100); + nv_icmd(dev, 0x00000957, 0x00000003); + nv_icmd(dev, 0x0000095d, 0x00000001); + nv_icmd(dev, 0x0000082b, 0x00000004); + nv_icmd(dev, 0x00000942, 0x00010001); + nv_icmd(dev, 0x00000943, 0x00000001); + nv_icmd(dev, 0x000007c5, 0x00010001); + nv_icmd(dev, 0x00000834, 0x00000001); + nv_icmd(dev, 0x000007c7, 0x00000001); + nv_icmd(dev, 0x0001e100, 0x00000001); + nv_icmd(dev, 0x00001000, 0x00000001); + nv_icmd(dev, 0x0000080c, 0x00000002); + nv_icmd(dev, 0x0000080d, 0x00000100); + nv_icmd(dev, 0x0000080e, 0x00000100); + nv_icmd(dev, 0x0000080f, 0x00000001); + nv_icmd(dev, 0x00000823, 0x00000002); + nv_icmd(dev, 0x00000824, 0x00000100); + nv_icmd(dev, 0x00000825, 0x00000100); + nv_icmd(dev, 0x00000826, 0x00000001); + nv_icmd(dev, 0x0001e100, 0x00000001); + nv_wr32(dev, 0x400208, 0x00000000); + nv_wr32(dev, 0x404154, 0x00000400); + + nvc0_grctx_generate_9097(dev); + nvc0_grctx_generate_902d(dev); + nvc0_grctx_generate_9039(dev); + nvc0_grctx_generate_90c0(dev); + + nv_wr32(dev, 0x000260, r000260); + return 0; +} -- cgit v1.2.3 From ddbaf79a8b047dcccf766d0518626cdc0f43d58e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 24 Nov 2010 10:52:43 +1000 Subject: drm/nvc0: implement fbcon acceleration Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Makefile | 5 +- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 24 ++- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 6 + drivers/gpu/drm/nouveau/nvc0_fbcon.c | 271 ++++++++++++++++++++++++++++++++ 4 files changed, 300 insertions(+), 6 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvc0_fbcon.c (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 141771beb8e6..e12c97fd8db8 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -22,9 +22,10 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv84_crypt.o \ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ - nv50_cursor.o nv50_display.o nv50_fbcon.o \ + nv50_cursor.o nv50_display.o \ nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ - nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ + nv04_crtc.o nv04_display.o nv04_cursor.o \ + nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \ nv10_gpio.o nv50_gpio.o \ nv50_calc.o \ nv04_pm.o nv50_pm.o nva3_pm.o \ diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index ea861c915149..326eeda6ad7f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -68,6 +68,8 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_fillrect(info, rect); + else + ret = nvc0_fbcon_fillrect(info, rect); mutex_unlock(&dev_priv->channel->mutex); } @@ -98,6 +100,8 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_copyarea(info, image); + else + ret = nvc0_fbcon_copyarea(info, image); mutex_unlock(&dev_priv->channel->mutex); } @@ -128,6 +132,8 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_imageblit(info, image); + else + ret = nvc0_fbcon_imageblit(info, image); mutex_unlock(&dev_priv->channel->mutex); } @@ -163,10 +169,18 @@ nouveau_fbcon_sync(struct fb_info *info) return 0; } - BEGIN_RING(chan, 0, 0x0104, 1); - OUT_RING(chan, 0); - BEGIN_RING(chan, 0, 0x0100, 1); - OUT_RING(chan, 0); + if (dev_priv->card_type >= NV_C0) { + BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1); + OUT_RING (chan, 0); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1); + OUT_RING (chan, 0); + } else { + BEGIN_RING(chan, 0, 0x0104, 1); + OUT_RING (chan, 0); + BEGIN_RING(chan, 0, 0x0100, 1); + OUT_RING (chan, 0); + } + nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); FIRE_RING(chan); mutex_unlock(&chan->mutex); @@ -374,6 +388,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, else if (dev_priv->card_type < NV_C0) ret = nv50_fbcon_accel_init(info); + else + ret = nvc0_fbcon_accel_init(info); if (ret == 0) info->fbops = &nouveau_fbcon_ops; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 6b933f2c3a5b..b73c29f87fc3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -44,11 +44,17 @@ int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv04_fbcon_accel_init(struct fb_info *info); + int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); int nv50_fbcon_accel_init(struct fb_info *info); +int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); +int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); +int nvc0_fbcon_accel_init(struct fb_info *info); + void nouveau_fbcon_gpu_lockup(struct fb_info *info); int nouveau_fbcon_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c new file mode 100644 index 000000000000..cbb4a1ae20b1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c @@ -0,0 +1,271 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "drmP.h" +#include "nouveau_drv.h" +#include "nouveau_dma.h" +#include "nouveau_ramht.h" +#include "nouveau_fbcon.h" +#include "nouveau_mm.h" + +int +nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = dev_priv->channel; + int ret; + + ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11); + if (ret) + return ret; + + if (rect->rop != ROP_COPY) { + BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); + OUT_RING (chan, 1); + } + BEGIN_NVC0(chan, 2, NvSub2D, 0x0588, 1); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + OUT_RING (chan, ((uint32_t *)info->pseudo_palette)[rect->color]); + else + OUT_RING (chan, rect->color); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0600, 4); + OUT_RING (chan, rect->dx); + OUT_RING (chan, rect->dy); + OUT_RING (chan, rect->dx + rect->width); + OUT_RING (chan, rect->dy + rect->height); + if (rect->rop != ROP_COPY) { + BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); + OUT_RING (chan, 3); + } + FIRE_RING(chan); + return 0; +} + +int +nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = dev_priv->channel; + int ret; + + ret = RING_SPACE(chan, 12); + if (ret) + return ret; + + BEGIN_NVC0(chan, 2, NvSub2D, 0x0110, 1); + OUT_RING (chan, 0); + BEGIN_NVC0(chan, 2, NvSub2D, 0x08b0, 4); + OUT_RING (chan, region->dx); + OUT_RING (chan, region->dy); + OUT_RING (chan, region->width); + OUT_RING (chan, region->height); + BEGIN_NVC0(chan, 2, NvSub2D, 0x08d0, 4); + OUT_RING (chan, 0); + OUT_RING (chan, region->sx); + OUT_RING (chan, 0); + OUT_RING (chan, region->sy); + FIRE_RING(chan); + return 0; +} + +int +nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = dev_priv->channel; + uint32_t width, dwords, *data = (uint32_t *)image->data; + uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); + uint32_t *palette = info->pseudo_palette; + int ret; + + if (image->depth != 1) + return -ENODEV; + + ret = RING_SPACE(chan, 11); + if (ret) + return ret; + + width = ALIGN(image->width, 32); + dwords = (width * image->height) >> 5; + + BEGIN_NVC0(chan, 2, NvSub2D, 0x0814, 2); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + OUT_RING (chan, palette[image->bg_color] | mask); + OUT_RING (chan, palette[image->fg_color] | mask); + } else { + OUT_RING (chan, image->bg_color); + OUT_RING (chan, image->fg_color); + } + BEGIN_NVC0(chan, 2, NvSub2D, 0x0838, 2); + OUT_RING (chan, image->width); + OUT_RING (chan, image->height); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0850, 4); + OUT_RING (chan, 0); + OUT_RING (chan, image->dx); + OUT_RING (chan, 0); + OUT_RING (chan, image->dy); + + while (dwords) { + int push = dwords > 2047 ? 2047 : dwords; + + ret = RING_SPACE(chan, push + 1); + if (ret) + return ret; + + dwords -= push; + + BEGIN_NVC0(chan, 6, NvSub2D, 0x0860, push); + OUT_RINGp(chan, data, push); + data += push; + } + + FIRE_RING(chan); + return 0; +} + +int +nvc0_fbcon_accel_init(struct fb_info *info) +{ + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan = dev_priv->channel; + struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo; + int ret, format; + + ret = nouveau_gpuobj_gr_new(chan, 0x902d, 0x902d); + if (ret) + return ret; + + switch (info->var.bits_per_pixel) { + case 8: + format = 0xf3; + break; + case 15: + format = 0xf8; + break; + case 16: + format = 0xe8; + break; + case 32: + switch (info->var.transp.length) { + case 0: /* depth 24 */ + case 8: /* depth 32, just use 24.. */ + format = 0xe6; + break; + case 2: /* depth 30 */ + format = 0xd1; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + ret = RING_SPACE(chan, 60); + if (ret) { + WARN_ON(1); + nouveau_fbcon_gpu_lockup(info); + return ret; + } + + printk(KERN_ERR "fb vma 0x%010llx\n", nvbo->vma.offset); + + BEGIN_NVC0(chan, 2, NvSub2D, 0x0000, 1); + OUT_RING (chan, 0x0000902d); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0104, 2); + OUT_RING (chan, upper_32_bits(chan->notifier_bo->bo.offset)); + OUT_RING (chan, lower_32_bits(chan->notifier_bo->bo.offset)); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0290, 1); + OUT_RING (chan, 0); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0888, 1); + OUT_RING (chan, 1); + BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); + OUT_RING (chan, 3); + BEGIN_NVC0(chan, 2, NvSub2D, 0x02a0, 1); + OUT_RING (chan, 0x55); + BEGIN_NVC0(chan, 2, NvSub2D, 0x08c0, 4); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0580, 2); + OUT_RING (chan, 4); + OUT_RING (chan, format); + BEGIN_NVC0(chan, 2, NvSub2D, 0x02e8, 2); + OUT_RING (chan, 2); + OUT_RING (chan, 1); + + BEGIN_NVC0(chan, 2, NvSub2D, 0x0804, 1); + OUT_RING (chan, format); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0800, 1); + OUT_RING (chan, 1); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0808, 3); + OUT_RING (chan, 0); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + BEGIN_NVC0(chan, 2, NvSub2D, 0x081c, 1); + OUT_RING (chan, 1); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0840, 4); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0200, 10); + OUT_RING (chan, format); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + OUT_RING (chan, info->fix.line_length); + OUT_RING (chan, info->var.xres_virtual); + OUT_RING (chan, info->var.yres_virtual); + OUT_RING (chan, upper_32_bits(nvbo->vma.offset)); + OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0230, 10); + OUT_RING (chan, format); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + OUT_RING (chan, info->fix.line_length); + OUT_RING (chan, info->var.xres_virtual); + OUT_RING (chan, info->var.yres_virtual); + OUT_RING (chan, upper_32_bits(nvbo->vma.offset)); + OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); + FIRE_RING (chan); + + return 0; +} + -- cgit v1.2.3 From 6d86951a45013ac5b060c5e6307b11b7c685c76f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 8 Dec 2010 11:19:30 +1000 Subject: drm/nvc0: initial support for tiled buffer objects Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 3 -- drivers/gpu/drm/nouveau/nouveau_dma.h | 3 +- drivers/gpu/drm/nouveau/nv50_crtc.c | 18 +++++++----- drivers/gpu/drm/nouveau/nv50_evo.c | 53 ++++++++++++++++++++++++++--------- drivers/gpu/drm/nouveau/nvc0_vram.c | 10 ++++++- 5 files changed, 62 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5dc639e0c969..74d0ef41118d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -120,9 +120,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, align >>= PAGE_SHIFT; if (!nvbo->no_vm && dev_priv->chan_vm) { - if (dev_priv->card_type == NV_C0) - page_shift = 12; - ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, NV_MEM_ACCESS_RW, &nvbo->vma); if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index c118a331b5bc..c36f1763feaa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -77,7 +77,8 @@ enum { /* G80+ display objects */ NvEvoVRAM = 0x01000000, NvEvoFB16 = 0x01000001, - NvEvoFB32 = 0x01000002 + NvEvoFB32 = 0x01000002, + NvEvoVRAM_LP = 0x01000003 }; #define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 2c346f797285..9023c4dbb449 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -115,15 +115,16 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked) OUT_RING(evo, 0); BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1); if (dev_priv->chipset != 0x50) - if (nv_crtc->fb.tile_flags == 0x7a00) + if (nv_crtc->fb.tile_flags == 0x7a00 || + nv_crtc->fb.tile_flags == 0xfe00) OUT_RING(evo, NvEvoFB32); else if (nv_crtc->fb.tile_flags == 0x7000) OUT_RING(evo, NvEvoFB16); else - OUT_RING(evo, NvEvoVRAM); + OUT_RING(evo, NvEvoVRAM_LP); else - OUT_RING(evo, NvEvoVRAM); + OUT_RING(evo, NvEvoVRAM_LP); } nv_crtc->fb.blanked = blanked; @@ -555,13 +556,14 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, return ret; BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1); - if (nv_crtc->fb.tile_flags == 0x7a00) + if (nv_crtc->fb.tile_flags == 0x7a00 || + nv_crtc->fb.tile_flags == 0xfe00) OUT_RING(evo, NvEvoFB32); else if (nv_crtc->fb.tile_flags == 0x7000) OUT_RING(evo, NvEvoFB16); else - OUT_RING(evo, NvEvoVRAM); + OUT_RING(evo, NvEvoVRAM_LP); } ret = RING_SPACE(evo, 12); @@ -575,8 +577,10 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, if (!nv_crtc->fb.tile_flags) { OUT_RING(evo, drm_fb->pitch | (1 << 20)); } else { - OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | - fb->nvbo->tile_mode); + u32 tile_mode = fb->nvbo->tile_mode; + if (dev_priv->card_type >= NV_C0) + tile_mode >>= 4; + OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | tile_mode); } if (dev_priv->chipset == 0x50) OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format); diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index 887b2a97e2a2..14e24e906ee8 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -53,7 +53,8 @@ nv50_evo_channel_del(struct nouveau_channel **pevo) int nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, - u32 tile_flags, u32 magic_flags, u32 offset, u32 limit) + u32 tile_flags, u32 magic_flags, u32 offset, u32 limit, + u32 flags5) { struct drm_nouveau_private *dev_priv = evo->dev->dev_private; struct drm_device *dev = evo->dev; @@ -70,10 +71,7 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, nv_wo32(obj, 8, offset); nv_wo32(obj, 12, 0x00000000); nv_wo32(obj, 16, 0x00000000); - if (dev_priv->card_type < NV_C0) - nv_wo32(obj, 20, 0x00010000); - else - nv_wo32(obj, 20, 0x00020000); + nv_wo32(obj, 20, flags5); dev_priv->engine.instmem.flush(dev); ret = nouveau_ramht_insert(evo, name, obj); @@ -264,9 +262,31 @@ nv50_evo_create(struct drm_device *dev) } /* create some default objects for the scanout memtypes we support */ + if (dev_priv->card_type >= NV_C0) { + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0xfe, 0x19, + 0, 0xffffffff, 0x00000000); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, + 0, dev_priv->vram_size, 0x00020000); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19, + 0, dev_priv->vram_size, 0x00000000); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + } else if (dev_priv->chipset != 0x50) { ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19, - 0, 0xffffffff); + 0, 0xffffffff, 0x00010000); if (ret) { nv50_evo_channel_del(&dev_priv->evo); return ret; @@ -274,18 +294,25 @@ nv50_evo_create(struct drm_device *dev) ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0x7a, 0x19, - 0, 0xffffffff); + 0, 0xffffffff, 0x00010000); if (ret) { nv50_evo_channel_del(&dev_priv->evo); return ret; } - } - ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, - 0, dev_priv->vram_size); - if (ret) { - nv50_evo_channel_del(&dev_priv->evo); - return ret; + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, + 0, dev_priv->vram_size, 0x00010000); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } + + ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19, + 0, dev_priv->vram_size, 0x00010000); + if (ret) { + nv50_evo_channel_del(&dev_priv->evo); + return ret; + } } return 0; diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c index 41fcae5ffba4..858eda5dedd1 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vram.c +++ b/drivers/gpu/drm/nouveau/nvc0_vram.c @@ -29,8 +29,16 @@ bool nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) { - if (likely(!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))) + switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { + case 0x0000: + case 0xfe00: + case 0xdb00: + case 0x1100: return true; + default: + break; + } + return false; } -- cgit v1.2.3 From 183720b8af5301e2eab7f3163f03133c5a6ad6da Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 9 Dec 2010 15:17:10 +1000 Subject: drm/nvc0: accelerate ttm buffer moves Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 57 +++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 74d0ef41118d..a7fae26f4654 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -514,6 +514,58 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, return chan->vram_handle; } +static int +nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, + struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) +{ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct nouveau_bo *nvbo = nouveau_bo(bo); + u64 src_offset = old_mem->start << PAGE_SHIFT; + u64 dst_offset = new_mem->start << PAGE_SHIFT; + u32 page_count = new_mem->num_pages; + int ret; + + if (!nvbo->no_vm) { + if (old_mem->mem_type == TTM_PL_VRAM) + src_offset = nvbo->vma.offset; + else + src_offset += dev_priv->gart_info.aper_base; + + if (new_mem->mem_type == TTM_PL_VRAM) + dst_offset = nvbo->vma.offset; + else + dst_offset += dev_priv->gart_info.aper_base; + } + + page_count = new_mem->num_pages; + while (page_count) { + int line_count = (page_count > 2047) ? 2047 : page_count; + + ret = RING_SPACE(chan, 12); + if (ret) + return ret; + + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0238, 2); + OUT_RING (chan, upper_32_bits(dst_offset)); + OUT_RING (chan, lower_32_bits(dst_offset)); + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x030c, 6); + OUT_RING (chan, upper_32_bits(src_offset)); + OUT_RING (chan, lower_32_bits(src_offset)); + OUT_RING (chan, PAGE_SIZE); /* src_pitch */ + OUT_RING (chan, PAGE_SIZE); /* dst_pitch */ + OUT_RING (chan, PAGE_SIZE); /* line_length */ + OUT_RING (chan, line_count); + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0300, 1); + OUT_RING (chan, 0x00100110); + + page_count -= line_count; + src_offset += (PAGE_SIZE * line_count); + dst_offset += (PAGE_SIZE * line_count); + } + + return 0; +} + static int nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) @@ -690,7 +742,10 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, if (dev_priv->card_type < NV_50) ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem); else + if (dev_priv->card_type < NV_C0) ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem); + else + ret = nvc0_bo_move_m2mf(chan, bo, &bo->mem, new_mem); if (ret == 0) { ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, @@ -836,7 +891,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, } /* Software copy if the card isn't up and running yet. */ - if (!dev_priv->channel || dev_priv->card_type == NV_C0) { + if (!dev_priv->channel) { ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); goto out; } -- cgit v1.2.3 From 2e9ff5f5e4c6b034554f3539f29529265279102c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 18 Nov 2010 23:08:37 +0100 Subject: gpio-charger: Check result of kzalloc Since kzalloc can return NULL we have to check its result. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vasiliy Kulikov Signed-off-by: Dan Carpenter Signed-off-by: Anton Vorontsov --- drivers/power/gpio-charger.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index fccbe99b619c..8458cafcd2b2 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c @@ -87,6 +87,10 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) } gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); + if (!gpio_charger) { + dev_err(&pdev->dev, "Failed to alloc driver structure\n"); + return -ENOMEM; + } charger = &gpio_charger->charger; -- cgit v1.2.3 From 80577b8a478f3386d106464f2a2241b2d43571ce Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 18 Nov 2010 23:08:39 +0100 Subject: gpio-charger: Provide default name for the power_supply This patch sets a default name for the power_supply in case there was no name supplied through the platform_data. Signed-off-by: Lars-Peter Clausen Signed-off-by: Anton Vorontsov --- drivers/power/gpio-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index 8458cafcd2b2..43078e34428a 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c @@ -94,7 +94,7 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) charger = &gpio_charger->charger; - charger->name = pdata->name; + charger->name = pdata->name ? pdata->name : "gpio-charger"; charger->type = pdata->type; charger->properties = gpio_charger_properties; charger->num_properties = ARRAY_SIZE(gpio_charger_properties); -- cgit v1.2.3 From 26eb387265872b59566ddeed5e9bf142a6b9ff5b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 18 Nov 2010 23:08:38 +0100 Subject: gpio-charger: Fix potential race between irq handler and probe/remove This patch fixes a potential race between the irq handler and the probe and remove functions. The irq should not be requested before the chargers power_supply has been registered and has to be freed before the power_supply is unregistered, otherwise it is possible that the irq fires while the power_supply is not initialized yet or has already been freed. While we are at it replace request_irq with request_any_context_irq. Signed-off-by: Lars-Peter Clausen Signed-off-by: Anton Vorontsov --- drivers/power/gpio-charger.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index 43078e34428a..25b88ac1d44c 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c @@ -98,7 +98,7 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) charger->type = pdata->type; charger->properties = gpio_charger_properties; charger->num_properties = ARRAY_SIZE(gpio_charger_properties); - charger->get_property = gpio_charger_get_property; + charger->get_property = gpio_charger_get_property; charger->supplied_to = pdata->supplied_to; charger->num_supplicants = pdata->num_supplicants; @@ -113,9 +113,18 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) goto err_gpio_free; } + gpio_charger->pdata = pdata; + + ret = power_supply_register(&pdev->dev, charger); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register power supply: %d\n", + ret); + goto err_gpio_free; + } + irq = gpio_to_irq(pdata->gpio); if (irq > 0) { - ret = request_irq(irq, gpio_charger_irq, + ret = request_any_context_irq(irq, gpio_charger_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), charger); if (ret) @@ -124,21 +133,10 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev) gpio_charger->irq = irq; } - gpio_charger->pdata = pdata; - - ret = power_supply_register(&pdev->dev, charger); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register power supply: %d\n", ret); - goto err_irq_free; - } - platform_set_drvdata(pdev, gpio_charger); return 0; -err_irq_free: - if (gpio_charger->irq) - free_irq(gpio_charger->irq, charger); err_gpio_free: gpio_free(pdata->gpio); err_free: @@ -150,10 +148,11 @@ static int __devexit gpio_charger_remove(struct platform_device *pdev) { struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); - power_supply_unregister(&gpio_charger->charger); - if (gpio_charger->irq) free_irq(gpio_charger->irq, &gpio_charger->charger); + + power_supply_unregister(&gpio_charger->charger); + gpio_free(gpio_charger->pdata->gpio); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 3a2dbd611b38cf9a026c0099a85701ad183d1949 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 19 Nov 2010 21:41:58 +0300 Subject: power_supply: Fix use after free and memory leak device_unregister() might free its argument. This leads to freed memory use in kfree(). Also use put_device() instead of kfree() as dev may be already used in another layer after call to device_add(). Signed-off-by: Vasiliy Kulikov Signed-off-by: Anton Vorontsov --- drivers/power/power_supply_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 91606bb55318..f06bad047d76 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy) goto success; create_triggers_failed: - device_unregister(psy->dev); + device_del(dev); kobject_set_name_failed: device_add_failed: - kfree(dev); + put_device(dev); success: return rc; } -- cgit v1.2.3 From bc51e7ff521f28a7f14dc2f25307ad9101d1305a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 11 Dec 2010 17:51:45 +0100 Subject: power_supply: Don't use flush_scheduled_work() flush_scheduled_work() is deprecated and scheduled to be removed. In battery drivers, the work can be canceled on probe failure and removal and should be flushed on suspend. Replace flush_scheduled_work() usages with direct cancels and flushes. Signed-off-by: Tejun Heo Signed-off-by: Anton Vorontsov --- drivers/power/collie_battery.c | 13 ++++++------- drivers/power/intel_mid_battery.c | 2 +- drivers/power/power_supply_core.c | 2 +- drivers/power/tosa_battery.c | 13 ++++++------- drivers/power/wm97xx_battery.c | 4 ++-- drivers/power/z2_battery.c | 6 ++++-- 6 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c index 039f41ae217d..548d263b1ad0 100644 --- a/drivers/power/collie_battery.c +++ b/drivers/power/collie_battery.c @@ -295,7 +295,7 @@ static struct { static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) { /* flush all pending status updates */ - flush_scheduled_work(); + flush_work_sync(&bat_work); return 0; } @@ -362,7 +362,7 @@ err_psy_reg_bu: err_psy_reg_main: /* see comment in collie_bat_remove */ - flush_scheduled_work(); + cancel_work_sync(&bat_work); i--; err_gpio: @@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) power_supply_unregister(&collie_bat_main.psy); /* - * now flush all pending work. - * we won't get any more schedules, since all - * sources (isr and external_power_changed) - * are unregistered now. + * Now cancel the bat_work. We won't get any more schedules, + * since all sources (isr and external_power_changed) are + * unregistered now. */ - flush_scheduled_work(); + cancel_work_sync(&bat_work); for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) gpio_free(gpios[i].gpio); diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index 2a10cd361181..236147c3a5c6 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c @@ -767,7 +767,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev) power_supply_unregister(&pbi->usb); power_supply_unregister(&pbi->batt); - flush_scheduled_work(); + cancel_work_sync(&pbi->handler); kfree(pbi); return 0; } diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index f06bad047d76..970f7335d3a7 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register); void power_supply_unregister(struct power_supply *psy) { - flush_scheduled_work(); + cancel_work_sync(&psy->changed_work); power_supply_remove_triggers(psy); device_unregister(psy->dev); } diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c index ee04936b2db5..53f0d3524fcd 100644 --- a/drivers/power/tosa_battery.c +++ b/drivers/power/tosa_battery.c @@ -332,7 +332,7 @@ static struct { static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) { /* flush all pending status updates */ - flush_scheduled_work(); + flush_work_sync(&bat_work); return 0; } @@ -422,7 +422,7 @@ err_psy_reg_jacket: err_psy_reg_main: /* see comment in tosa_bat_remove */ - flush_scheduled_work(); + cancel_work_sync(&bat_work); i--; err_gpio: @@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev) power_supply_unregister(&tosa_bat_main.psy); /* - * now flush all pending work. - * we won't get any more schedules, since all - * sources (isr and external_power_changed) - * are unregistered now. + * Now cancel the bat_work. We won't get any more schedules, + * since all sources (isr and external_power_changed) are + * unregistered now. */ - flush_scheduled_work(); + cancel_work_sync(&bat_work); for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) gpio_free(gpios[i].gpio); diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c index 5071d85ec12d..156559e56fa5 100644 --- a/drivers/power/wm97xx_battery.c +++ b/drivers/power/wm97xx_battery.c @@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data) #ifdef CONFIG_PM static int wm97xx_bat_suspend(struct device *dev) { - flush_scheduled_work(); + flush_work_sync(&bat_work); return 0; } @@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev) free_irq(gpio_to_irq(pdata->charge_gpio), dev); gpio_free(pdata->charge_gpio); } - flush_scheduled_work(); + cancel_work_sync(&bat_work); power_supply_unregister(&bat_ps); kfree(prop); return 0; diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index 85064a9f649e..e5ed52d71937 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c @@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client) struct z2_charger *charger = i2c_get_clientdata(client); struct z2_battery_info *info = charger->info; - flush_scheduled_work(); + cancel_work_sync(&charger->bat_work); power_supply_unregister(&charger->batt_ps); kfree(charger->batt_ps.properties); @@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client) #ifdef CONFIG_PM static int z2_batt_suspend(struct i2c_client *client, pm_message_t state) { - flush_scheduled_work(); + struct z2_charger *charger = i2c_get_clientdata(client); + + flush_work_sync(&charger->bat_work); return 0; } -- cgit v1.2.3 From c66ae9bb4dcaac78cc5e30d0ce7ff2bf3dcb48d9 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Mon, 13 Dec 2010 12:26:21 +0200 Subject: s3c_adc_battery: Add gpio_inverted field to pdata Add support for inverted gpio_charge_finished values. This change is necessary for H1940 support. Signed-off-by: Vasily Khoruzhick Signed-off-by: Anton Vorontsov --- drivers/power/s3c_adc_battery.c | 12 +++++++++--- include/linux/s3c_adc_battery.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index fe16b482e912..7bc5bfe55ce9 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c @@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance) return volt_val + cur_val * impedance / 1000; } +static int charge_finished(struct s3c_adc_bat *bat) +{ + return bat->pdata->gpio_inverted ? + !gpio_get_value(bat->pdata->gpio_charge_finished) : + gpio_get_value(bat->pdata->gpio_charge_finished); +} + static int s3c_adc_bat_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy, if (bat->cable_plugged && ((bat->pdata->gpio_charge_finished < 0) || - !gpio_get_value(bat->pdata->gpio_charge_finished))) { + !charge_finished(bat))) { lut = bat->pdata->lut_acin; lut_size = bat->pdata->lut_acin_cnt; } @@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work) } } else { if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) { - is_charged = gpio_get_value( - main_bat.pdata->gpio_charge_finished); + is_charged = charge_finished(&main_bat); if (is_charged) { if (bat->pdata->disable_charger) bat->pdata->disable_charger(); diff --git a/include/linux/s3c_adc_battery.h b/include/linux/s3c_adc_battery.h index dbce22faa660..fbe58b7e63eb 100644 --- a/include/linux/s3c_adc_battery.h +++ b/include/linux/s3c_adc_battery.h @@ -14,6 +14,7 @@ struct s3c_adc_bat_pdata { void (*disable_charger)(void); int gpio_charge_finished; + int gpio_inverted; const struct s3c_adc_bat_thresh *lut_noac; unsigned int lut_noac_cnt; -- cgit v1.2.3 From 880981e49b90568ebb53428e231b43b8c1049ef9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 21 Dec 2010 16:16:13 -0500 Subject: drm/radeon/kms: disable bo moves using the blitter Blitting from vram to gart is problematic at the moment. Use the CPU for now to avoid buffer corruption. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f7d7477daffb..499122c8ccc9 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2782,6 +2782,11 @@ static int evergreen_startup(struct radeon_device *rdev) rdev->asic->copy = NULL; dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); } + /* XXX: ontario has problems blitting to gart at the moment */ + if (rdev->family == CHIP_PALM) { + rdev->asic->copy = NULL; + rdev->mc.active_vram_size = rdev->mc.visible_vram_size; + } /* allocate wb buffer */ r = radeon_wb_init(rdev); -- cgit v1.2.3 From f3dcab70e192b0489ac05cc554e0b1cedae46d1a Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 22 Dec 2010 02:44:49 +0300 Subject: jz4740-battery: Should include linux/io.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During test-build (with disabled 'depends on') I found that jz4740-battery driver lacks linux/io.h, which makes build break like this (on x86): CC [M] drivers/power/isp1704_charger.o jz4740-battery.c: In function 'jz_battery_read_voltage': jz4740-battery.c:84: error: implicit declaration of function 'readw’ jz4740-battery.c: In function 'jz_battery_probe': jz4740-battery.c:284: error: implicit declaration of function 'ioremap_nocache’ jz4740-battery.c:285: warning: assignment makes pointer from integer without a cast jz4740-battery.c:372: error: implicit declaration of function 'iounmap' make[2]: *** [drivers/power/jz4740-battery.o] Error 1 This patch fixes the issues, and thus makes it easier to build-test the driver for me. Signed-off-by: Anton Vorontsov --- drivers/power/jz4740-battery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index 5b4821593201..02414db6a94c 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 204663c48711ddceee09df46269cd34d49d1f7be Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Tue, 21 Dec 2010 21:27:34 +0100 Subject: drm/radeon/kms: add ARGB2101010 colorbuffer support for r500 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should be part of DRM 2.8.0. Signed-off-by: Marek Olšák Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 7 +++++++ drivers/gpu/drm/radeon/radeon_drv.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index cde1d3480d93..36b4f7b48d6a 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -787,6 +787,13 @@ static int r300_packet0_check(struct radeon_cs_parser *p, case 15: track->cb[i].cpp = 2; break; + case 5: + if (p->rdev->family < CHIP_RV515) { + DRM_ERROR("Invalid color buffer format (%d)!\n", + ((idx_value >> 21) & 0xF)); + return -EINVAL; + } + /* Pass through. */ case 6: track->cb[i].cpp = 4; break; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 6fb1218f9d76..520b776b09f4 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -48,7 +48,7 @@ * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs - * 2.8.0 - pageflip support, r500 US_FORMAT regs. + * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 8 -- cgit v1.2.3 From fcc57045d53edc35bcce456e60ac4aa802712934 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 22 Dec 2010 09:48:49 +0100 Subject: Revert "sd: implement sd_check_events()" This reverts commit c8d2e937355d02db3055c2fc203e5f017297ee1f. We run into merging problems with the SCSI tree, revert this one so it can be handled by a postmerge tree there. Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 87 +++++++++++++++++++++++++------------------------------ drivers/scsi/sd.h | 1 + 2 files changed, 41 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b179b0e39a3b..8d488a9fef00 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -991,50 +991,30 @@ out: static void set_media_not_present(struct scsi_disk *sdkp) { - if (sdkp->media_present) - sdkp->device->changed = 1; sdkp->media_present = 0; sdkp->capacity = 0; -} - -static int media_not_present(struct scsi_disk *sdkp, - struct scsi_sense_hdr *sshdr) -{ - if (!scsi_sense_valid(sshdr)) - return 0; - - /* not invoked for commands that could return deferred errors */ - switch (sshdr->sense_key) { - case UNIT_ATTENTION: - sdkp->device->changed = 1; - /* fall through */ - case NOT_READY: - /* medium not present */ - if (sshdr->asc == 0x3A) { - set_media_not_present(sdkp); - return 1; - } - } - return 0; + sdkp->device->changed = 1; } /** - * sd_check_events - check media events - * @disk: kernel device descriptor - * @clearing: disk events currently being cleared + * sd_media_changed - check if our medium changed + * @disk: kernel device descriptor * - * Returns mask of DISK_EVENT_*. + * Returns 0 if not applicable or no change; 1 if change * * Note: this function is invoked from the block subsystem. **/ -static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) +static int sd_media_changed(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; struct scsi_sense_hdr *sshdr = NULL; int retval; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); + SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); + + if (!sdp->removable) + return 0; /* * If the device is offline, don't send any commands - just pretend as @@ -1044,6 +1024,7 @@ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) */ if (!scsi_device_online(sdp)) { set_media_not_present(sdkp); + retval = 1; goto out; } @@ -1064,30 +1045,26 @@ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) sshdr); } - /* failed to execute TUR, assume media not present */ - if (host_byte(retval)) { + if (retval) { set_media_not_present(sdkp); + retval = 1; goto out; } - if (media_not_present(sdkp, sshdr)) - goto out; - /* * For removable scsi disk we have to recognise the presence - * of a disk in the drive. + * of a disk in the drive. This is kept in the struct scsi_disk + * struct and tested at open ! Daniel Roche (dan@lectra.fr) */ - if (!sdkp->media_present) - sdp->changed = 1; sdkp->media_present = 1; + + retval = sdp->changed; + sdp->changed = 0; out: - /* for backward compatibility */ - if (sdp->changed) + if (retval != sdkp->previous_state) sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); + sdkp->previous_state = retval; kfree(sshdr); - - retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; - sdp->changed = 0; return retval; } @@ -1180,7 +1157,7 @@ static const struct block_device_operations sd_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl, #endif - .check_events = sd_check_events, + .media_changed = sd_media_changed, .revalidate_disk = sd_revalidate_disk, .unlock_native_capacity = sd_unlock_native_capacity, }; @@ -1316,6 +1293,23 @@ static int sd_done(struct scsi_cmnd *SCpnt) return good_bytes; } +static int media_not_present(struct scsi_disk *sdkp, + struct scsi_sense_hdr *sshdr) +{ + + if (!scsi_sense_valid(sshdr)) + return 0; + /* not invoked for commands that could return deferred errors */ + if (sshdr->sense_key != NOT_READY && + sshdr->sense_key != UNIT_ATTENTION) + return 0; + if (sshdr->asc != 0x3A) /* medium not present */ + return 0; + + set_media_not_present(sdkp); + return 1; +} + /* * spinup disk - called only in sd_revalidate_disk() */ @@ -1490,7 +1484,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, */ if (sdp->removable && sense_valid && sshdr->sense_key == NOT_READY) - set_media_not_present(sdkp); + sdp->changed = 1; /* * We used to set media_present to 0 here to indicate no media @@ -2345,10 +2339,8 @@ static void sd_probe_async(void *data, async_cookie_t cookie) gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_EXT_DEVT; - if (sdp->removable) { + if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; - gd->events |= DISK_EVENT_MEDIA_CHANGE; - } add_disk(gd); sd_dif_config_host(sdkp); @@ -2430,6 +2422,7 @@ static int sd_probe(struct device *dev) sdkp->disk = gd; sdkp->index = index; atomic_set(&sdkp->openers, 0); + sdkp->previous_state = 1; if (!sdp->request_queue->rq_timeout) { if (sdp->type != TYPE_MOD) diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index c9d8f6ca49e2..55488faf0815 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -55,6 +55,7 @@ struct scsi_disk { u8 media_present; u8 write_prot; u8 protection_type;/* Data Integrity Field */ + unsigned previous_state : 1; unsigned ATO : 1; /* state of disk ATO bit */ unsigned WCE : 1; /* state of disk WCE bit */ unsigned RCD : 1; /* state of disk RCD bit, unused */ -- cgit v1.2.3 From 68229689b6dc950bea4b81dd60563884f4a7e1c5 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 22 Dec 2010 15:33:40 +0100 Subject: HID: usbhid: base runtime PM on modern API This patch doesn't alter functionality, but removes a dedicated kernel thread. Signed-off-by: Oliver Neukum Tested-by: Maulik Mankad Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 57 +++++++++++++++---------------------------- drivers/hid/usbhid/usbhid.h | 1 - 2 files changed, 19 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 276758f53ab5..b336dd84036f 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -67,7 +67,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " * Input submission and I/O error handler. */ static DEFINE_MUTEX(hid_open_mut); -static struct workqueue_struct *resumption_waker; static void hid_io_error(struct hid_device *hid); static int hid_submit_out(struct hid_device *hid); @@ -300,10 +299,19 @@ static int hid_submit_out(struct hid_device *hid) struct hid_report *report; char *raw_report; struct usbhid_device *usbhid = hid->driver_data; + int r; report = usbhid->out[usbhid->outtail].report; raw_report = usbhid->out[usbhid->outtail].raw_report; + r = usb_autopm_get_interface_async(usbhid->intf); + if (r < 0) + return -1; + + /* + * if the device hasn't been woken, we leave the output + * to resume() + */ if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); usbhid->urbout->dev = hid_to_usb_dev(hid); @@ -314,16 +322,10 @@ static int hid_submit_out(struct hid_device *hid) if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { hid_err(hid, "usb_submit_urb(out) failed\n"); + usb_autopm_put_interface_async(usbhid->intf); return -1; } usbhid->last_out = jiffies; - } else { - /* - * queue work to wake up the device. - * as the work queue is freezeable, this is safe - * with respect to STD and STR - */ - queue_work(resumption_waker, &usbhid->restart_work); } return 0; @@ -334,13 +336,16 @@ static int hid_submit_ctrl(struct hid_device *hid) struct hid_report *report; unsigned char dir; char *raw_report; - int len; + int len, r; struct usbhid_device *usbhid = hid->driver_data; report = usbhid->ctrl[usbhid->ctrltail].report; raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; dir = usbhid->ctrl[usbhid->ctrltail].dir; + r = usb_autopm_get_interface_async(usbhid->intf); + if (r < 0) + return -1; if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) { len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { @@ -375,17 +380,11 @@ static int hid_submit_ctrl(struct hid_device *hid) usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { + usb_autopm_put_interface_async(usbhid->intf); hid_err(hid, "usb_submit_urb(ctrl) failed\n"); return -1; } usbhid->last_ctrl = jiffies; - } else { - /* - * queue work to wake up the device. - * as the work queue is freezeable, this is safe - * with respect to STD and STR - */ - queue_work(resumption_waker, &usbhid->restart_work); } return 0; @@ -435,6 +434,7 @@ static void hid_irq_out(struct urb *urb) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->lock, flags); + usb_autopm_put_interface_async(usbhid->intf); wake_up(&usbhid->wait); } @@ -480,11 +480,13 @@ static void hid_ctrl(struct urb *urb) wake_up(&usbhid->wait); } spin_unlock(&usbhid->lock); + usb_autopm_put_interface_async(usbhid->intf); return; } clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); spin_unlock(&usbhid->lock); + usb_autopm_put_interface_async(usbhid->intf); wake_up(&usbhid->wait); } @@ -655,7 +657,7 @@ int usbhid_open(struct hid_device *hid) mutex_lock(&hid_open_mut); if (!hid->open++) { res = usb_autopm_get_interface(usbhid->intf); - /* the device must be awake to reliable request remote wakeup */ + /* the device must be awake to reliably request remote wakeup */ if (res < 0) { hid->open--; mutex_unlock(&hid_open_mut); @@ -856,18 +858,6 @@ static void usbhid_restart_queues(struct usbhid_device *usbhid) usbhid_restart_ctrl_queue(usbhid); } -static void __usbhid_restart_queues(struct work_struct *work) -{ - struct usbhid_device *usbhid = - container_of(work, struct usbhid_device, restart_work); - int r; - - r = usb_autopm_get_interface(usbhid->intf); - if (r < 0) - return; - usb_autopm_put_interface(usbhid->intf); -} - static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; @@ -1204,7 +1194,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * init_waitqueue_head(&usbhid->wait); INIT_WORK(&usbhid->reset_work, hid_reset); - INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues); setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); spin_lock_init(&usbhid->lock); @@ -1239,7 +1228,6 @@ static void usbhid_disconnect(struct usb_interface *intf) static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid) { del_timer_sync(&usbhid->io_retry); - cancel_work_sync(&usbhid->restart_work); cancel_work_sync(&usbhid->reset_work); } @@ -1260,7 +1248,6 @@ static int hid_pre_reset(struct usb_interface *intf) spin_lock_irq(&usbhid->lock); set_bit(HID_RESET_PENDING, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); - cancel_work_sync(&usbhid->restart_work); hid_cease_io(usbhid); return 0; @@ -1459,9 +1446,6 @@ static int __init hid_init(void) { int retval = -ENOMEM; - resumption_waker = create_freezeable_workqueue("usbhid_resumer"); - if (!resumption_waker) - goto no_queue; retval = hid_register_driver(&hid_usb_driver); if (retval) goto hid_register_fail; @@ -1479,8 +1463,6 @@ usb_register_fail: usbhid_quirks_init_fail: hid_unregister_driver(&hid_usb_driver); hid_register_fail: - destroy_workqueue(resumption_waker); -no_queue: return retval; } @@ -1489,7 +1471,6 @@ static void __exit hid_exit(void) usb_deregister(&hid_driver); usbhid_quirks_exit(); hid_unregister_driver(&hid_usb_driver); - destroy_workqueue(resumption_waker); } module_init(hid_init); diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 89d2e847dcc6..1673cac93d77 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -95,7 +95,6 @@ struct usbhid_device { unsigned long stop_retry; /* Time to give up, in jiffies */ unsigned int retry_delay; /* Delay length in ms */ struct work_struct reset_work; /* Task context for resets */ - struct work_struct restart_work; /* waking up for output to be done in a task */ wait_queue_head_t wait; /* For sleeping */ int ledcount; /* counting the number of active leds */ }; -- cgit v1.2.3 From 00aaaef9a51a1a25c5d6d52ce510772f149a0eb0 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 11 Nov 2010 15:46:54 +0800 Subject: PCI: MSI: Move MSI-X entry definition to pci_regs.h Then it can be used by others. Reviewed-by: Hidetoshi Seto Reviewed-by: Matthew Wilcox Signed-off-by: Sheng Yang Signed-off-by: Jesse Barnes --- drivers/pci/msi.h | 6 ------ include/linux/pci_regs.h | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index feff3bee6fe5..65c42f80f23e 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,12 +6,6 @@ #ifndef MSI_H #define MSI_H -#define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 -#define PCI_MSIX_ENTRY_DATA 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 - #define msi_control_reg(base) (base + PCI_MSI_FLAGS) #define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) #define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI) diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index af83076c31a6..b21d33e4bc2a 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -309,6 +309,13 @@ #define PCI_MSIX_PBA 8 #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) +/* MSI-X entry's format */ +#define PCI_MSIX_ENTRY_SIZE 16 +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 +#define PCI_MSIX_ENTRY_DATA 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 + /* CompactPCI Hotswap Register */ #define PCI_CHSWP_CSR 2 /* Control and Status Register */ -- cgit v1.2.3 From 8d805286968811223cca002134ba3d81244d5313 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 11 Nov 2010 15:46:55 +0800 Subject: PCI: Add mask bit definition for MSI-X table Then we can use it instead of magic number 1. Reviewed-by: Hidetoshi Seto Cc: Matthew Wilcox Signed-off-by: Sheng Yang Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 5 +++-- include/linux/pci_regs.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 7c24dcef2989..44b0aeee83e5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -168,8 +168,9 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag) u32 mask_bits = desc->masked; unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; - mask_bits &= ~1; - mask_bits |= flag; + mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; + if (flag) + mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT; writel(mask_bits, desc->mask_base + offset); return mask_bits; diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index b21d33e4bc2a..d4f2c80a6c3e 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -315,6 +315,7 @@ #define PCI_MSIX_ENTRY_UPPER_ADDR 4 #define PCI_MSIX_ENTRY_DATA 8 #define PCI_MSIX_ENTRY_VECTOR_CTRL 12 +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 /* CompactPCI Hotswap Register */ -- cgit v1.2.3 From 2f671e2dbff6eb5ef4e2600adbec550c13b8fe72 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 6 Dec 2010 14:00:56 -0500 Subject: PCI: Disable ASPM if BIOS asks us to We currently refuse to touch the ASPM registers if the BIOS tells us that ASPM isn't supported. This can cause problems if the BIOS has (for any reason) enabled ASPM on some devices anyway. Change the code such that we explicitly clear ASPM if the FADT indicates that ASPM isn't supported, and make sure we tidy up appropriately on device removal in order to deal with the hotplug case. If ASPM is disabled because the BIOS doesn't hand over control then we won't touch the registers. Signed-off-by: Matthew Garrett Signed-off-by: Jesse Barnes --- drivers/pci/pci-acpi.c | 1 + drivers/pci/pcie/aspm.c | 21 +++++++++++++++++---- include/linux/pci-aspm.h | 5 ++++- 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 24e19c594e57..d7ea699b8ddc 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -399,6 +399,7 @@ static int __init acpi_pci_init(void) if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); + pcie_clear_aspm(); pcie_no_aspm(); } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 71222814c1ec..3188cd96b338 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -68,7 +68,7 @@ struct pcie_link_state { struct aspm_latency acceptable[8]; }; -static int aspm_disabled, aspm_force; +static int aspm_disabled, aspm_force, aspm_clear_state; static DEFINE_MUTEX(aspm_lock); static LIST_HEAD(link_list); @@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable) { /* Don't enable Clock PM if the link is not Clock PM capable */ if (!link->clkpm_capable && enable) - return; + enable = 0; /* Need nothing if the specified equals to current state */ if (link->clkpm_enabled == enable) return; @@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) struct pci_dev *child; int pos; u32 reg32; + + if (aspm_clear_state) + return -EINVAL; + /* * Some functions in a slot might not all be PCIe functions, * very strange. Disable ASPM for the whole slot @@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) struct pcie_link_state *link; int blacklist = !!pcie_aspm_sanity_check(pdev); - if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state) + if (!pci_is_pcie(pdev) || pdev->link_state) return; if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; + if (aspm_disabled && !aspm_clear_state) + return; + /* VIA has a strange chipset, root port is under a bridge */ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && pdev->bus->self) @@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link, *root, *parent_link; - if (aspm_disabled || !pci_is_pcie(pdev) || + if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) || !parent || !parent->link_state) return; if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && @@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str) __setup("pcie_aspm=", pcie_aspm_disable); +void pcie_clear_aspm(void) +{ + if (!aspm_force) + aspm_clear_state = 1; +} + void pcie_no_aspm(void) { if (!aspm_force) diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h index 91ba0b338b47..ce6810512c66 100644 --- a/include/linux/pci-aspm.h +++ b/include/linux/pci-aspm.h @@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev); extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); extern void pci_disable_link_state(struct pci_dev *pdev, int state); +extern void pcie_clear_aspm(void); extern void pcie_no_aspm(void); #else static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) @@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { } - +static inline void pcie_clear_aspm(void) +{ +} static inline void pcie_no_aspm(void) { } -- cgit v1.2.3 From 1d3c16a818e992c199844954d95c17fd7ce6cbba Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Tue, 30 Nov 2010 17:43:26 -0600 Subject: PCI: make pci_restore_state return void pci_restore_state only ever returns 0, thus there is no benefit in having it return any value. Also, a large majority of the callers do not check the return code of pci_restore_state. Make the pci_restore_state a void return and avoid the overhead. Acked-by: Mauro Carvalho Chehab Signed-off-by: Jon Mason Signed-off-by: Jesse Barnes --- drivers/media/video/cafe_ccic.c | 4 +--- drivers/net/myri10ge/myri10ge.c | 4 +--- drivers/net/sfc/falcon.c | 25 +++++-------------------- drivers/net/skge.c | 4 +--- drivers/net/sky2.c | 5 +---- drivers/net/wireless/rt2x00/rt2x00pci.c | 4 ++-- drivers/pci/pci-driver.c | 3 ++- drivers/pci/pci.c | 7 ++----- drivers/scsi/ipr.c | 8 +------- drivers/scsi/pmcraid.c | 7 +------ drivers/staging/sm7xx/smtcfb.c | 2 +- include/linux/pci.h | 8 +++----- sound/pci/cs5535audio/cs5535audio_pm.c | 7 +------ 13 files changed, 22 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 0dfff50891e4..737bb877e962 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -2186,9 +2186,7 @@ static int cafe_pci_resume(struct pci_dev *pdev) struct cafe_camera *cam = to_cam(v4l2_dev); int ret = 0; - ret = pci_restore_state(pdev); - if (ret) - return ret; + pci_restore_state(pdev); ret = pci_enable_device(pdev); if (ret) { diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 8524cc40ec57..d3c4a374a92e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -3403,9 +3403,7 @@ static int myri10ge_resume(struct pci_dev *pdev) return -EIO; } - status = pci_restore_state(pdev); - if (status) - return status; + pci_restore_state(pdev); status = pci_enable_device(pdev); if (status) { diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 267019bb2b15..1763b9a7fd8e 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1066,22 +1066,9 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) /* Restore PCI configuration if needed */ if (method == RESET_TYPE_WORLD) { - if (efx_nic_is_dual_func(efx)) { - rc = pci_restore_state(nic_data->pci_dev2); - if (rc) { - netif_err(efx, drv, efx->net_dev, - "failed to restore PCI config for " - "the secondary function\n"); - goto fail3; - } - } - rc = pci_restore_state(efx->pci_dev); - if (rc) { - netif_err(efx, drv, efx->net_dev, - "failed to restore PCI config for the " - "primary function\n"); - goto fail4; - } + if (efx_nic_is_dual_func(efx)) + pci_restore_state(nic_data->pci_dev2); + pci_restore_state(efx->pci_dev); netif_dbg(efx, drv, efx->net_dev, "successfully restored PCI config\n"); } @@ -1092,7 +1079,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) rc = -ETIMEDOUT; netif_err(efx, hw, efx->net_dev, "timed out waiting for hardware reset\n"); - goto fail5; + goto fail3; } netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n"); @@ -1100,11 +1087,9 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) /* pci_save_state() and pci_restore_state() MUST be called in pairs */ fail2: -fail3: pci_restore_state(efx->pci_dev); fail1: -fail4: -fail5: +fail3: return rc; } diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 220e0398f1d5..61553af38e65 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -4087,9 +4087,7 @@ static int skge_resume(struct pci_dev *pdev) if (err) goto out; - err = pci_restore_state(pdev); - if (err) - goto out; + pci_restore_state(pdev); err = skge_reset(hw); if (err) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d6577084ce70..be3aee782760 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4969,10 +4969,7 @@ static int sky2_resume(struct pci_dev *pdev) if (err) goto out; - err = pci_restore_state(pdev); - if (err) - goto out; - + pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); /* Re-enable all clocks */ diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 2449d785cf8d..4fd4c33de6ae 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -356,12 +356,12 @@ int rt2x00pci_resume(struct pci_dev *pci_dev) struct rt2x00_dev *rt2x00dev = hw->priv; if (pci_set_power_state(pci_dev, PCI_D0) || - pci_enable_device(pci_dev) || - pci_restore_state(pci_dev)) { + pci_enable_device(pci_dev)) { ERROR(rt2x00dev, "Failed to resume device.\n"); return -EIO; } + pci_restore_state(pci_dev); return rt2x00lib_resume(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00pci_resume); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 8a6f797de8e5..80e551ee640b 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -449,7 +449,8 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev) return error; } - return pci_restore_state(pci_dev); + pci_restore_state(pci_dev); + return 0; } static void pci_pm_default_resume_early(struct pci_dev *pci_dev) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 710c8a29be0d..6762dcae90ab 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -937,14 +937,13 @@ pci_save_state(struct pci_dev *dev) * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with */ -int -pci_restore_state(struct pci_dev *dev) +void pci_restore_state(struct pci_dev *dev) { int i; u32 val; if (!dev->state_saved) - return 0; + return; /* PCI Express register must be restored first */ pci_restore_pcie_state(dev); @@ -968,8 +967,6 @@ pci_restore_state(struct pci_dev *dev) pci_restore_iov_state(dev); dev->state_saved = false; - - return 0; } static int do_pci_enable_device(struct pci_dev *dev, int bars) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5bbaee597e88..524d586c3147 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7487,16 +7487,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; volatile u32 int_reg; - int rc; ENTER; ioa_cfg->pdev->state_saved = true; - rc = pci_restore_state(ioa_cfg->pdev); - - if (rc != PCIBIOS_SUCCESSFUL) { - ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); - return IPR_RC_JOB_CONTINUE; - } + pci_restore_state(ioa_cfg->pdev); if (ipr_set_pcix_cmd_reg(ioa_cfg)) { ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 300d59f389da..321cf3ae8630 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -2228,12 +2228,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) /* Once either bist or pci reset is done, restore PCI config * space. If this fails, proceed with hard reset again */ - if (pci_restore_state(pinstance->pdev)) { - pmcraid_info("config-space error resetting again\n"); - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - pmcraid_reset_alert(cmd); - break; - } + pci_restore_state(pinstance->pdev); /* fail all pending commands */ pmcraid_fail_outstanding_cmds(pinstance); diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c index 24f47d6388f4..7162dee3b0d8 100644 --- a/drivers/staging/sm7xx/smtcfb.c +++ b/drivers/staging/sm7xx/smtcfb.c @@ -1071,7 +1071,7 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev) /* when resuming, restore pci data and fb cursor */ if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) { retv = pci_set_power_state(pdev, PCI_D0); - retv = pci_restore_state(pdev); + pci_restore_state(pdev); if (pci_enable_device(pdev)) return -1; pci_set_master(pdev); diff --git a/include/linux/pci.h b/include/linux/pci.h index 7454408c41b6..63cbadce337e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -806,7 +806,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size); /* Power management related routines */ int pci_save_state(struct pci_dev *dev); -int pci_restore_state(struct pci_dev *dev); +void pci_restore_state(struct pci_dev *dev); int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state); int pci_set_power_state(struct pci_dev *dev, pci_power_t state); pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); @@ -1168,10 +1168,8 @@ static inline int pci_save_state(struct pci_dev *dev) return 0; } -static inline int pci_restore_state(struct pci_dev *dev) -{ - return 0; -} +static inline void pci_restore_state(struct pci_dev *dev) +{ } static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index a3301cc4ab82..185b00088320 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -90,12 +90,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci) int i; pci_set_power_state(pci, PCI_D0); - if (pci_restore_state(pci) < 0) { - printk(KERN_ERR "cs5535audio: pci_restore_state failed, " - "disabling device\n"); - snd_card_disconnect(card); - return -EIO; - } + pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "cs5535audio: pci_enable_device failed, " "disabling device\n"); -- cgit v1.2.3 From 23ea3793fd368fd6a1ea20659699e280e2996658 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 15:02:31 -0800 Subject: PCI: fix __pci_device_probe kernel-doc warning Fix kernel-doc warning for __pci_device_probe(): Warning(drivers/pci/pci-driver.c:341): missing initial short description on line: * __pci_device_probe() Signed-off-by: Randy Dunlap Signed-off-by: Jesse Barnes --- drivers/pci/pci-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 80e551ee640b..88246dd46452 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -338,7 +338,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, } /** - * __pci_device_probe() + * __pci_device_probe - check if a driver wants to claim a specific PCI device * @drv: driver to call to check if it wants the PCI device * @pci_dev: PCI device being probed * -- cgit v1.2.3 From ee8abf783dd36f65440fd782ad16f9768631d998 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 17 Nov 2010 12:10:40 -0800 Subject: PCI: Skip id checking if no id is passed Will get warning when pci stub driver is built-in kenel like: pci-stub: invalid id string "" So stop early if no id is passed. Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes --- drivers/pci/pci-stub.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c index f7b68ca6cc98..4c0336b31caf 100644 --- a/drivers/pci/pci-stub.c +++ b/drivers/pci/pci-stub.c @@ -47,6 +47,10 @@ static int __init pci_stub_init(void) if (rc) return rc; + /* no ids passed actually */ + if (ids[0] == '\0') + return 0; + /* add ids specified in the module parameter */ p = ids; while ((id = strsep(&p, ","))) { -- cgit v1.2.3 From 99a0fadf561e1f553c08f0a29f8b2578f55dd5f0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 22 Dec 2010 10:06:36 +0100 Subject: PCI: pci-stub: ignore zero-length id parameters pci-stub uses strsep() to separate list of ids and generates a warning message when it fails to parse an id. However, not specifying the parameter results in ids set to an empty string. strsep() happily returns the empty string as the first token and thus triggers the warning message spuriously. Make the tokner ignore zero length ids. Reported-by: Chris Wright Reported-by: Prasad Joshi Cc: stable@kernel.org Signed-off-by: Jesse Barnes --- drivers/pci/pci-stub.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c index 4c0336b31caf..775e933c2225 100644 --- a/drivers/pci/pci-stub.c +++ b/drivers/pci/pci-stub.c @@ -58,6 +58,9 @@ static int __init pci_stub_init(void) subdevice = PCI_ANY_ID, class=0, class_mask=0; int fields; + if (!strlen(id)) + continue; + fields = sscanf(id, "%x:%x:%x:%x:%x:%x", &vendor, &device, &subvendor, &subdevice, &class, &class_mask); -- cgit v1.2.3 From fe31e69740eddc7316071ed5165fed6703c8cd12 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 19 Dec 2010 15:57:16 +0100 Subject: PCI/PCIe: Clear Root PME Status bits early during system resume I noticed that PCI Express PMEs don't work on my Toshiba Portege R500 after the system has been woken up from a sleep state by a PME (through Wake-on-LAN). After some investigation it turned out that the BIOS didn't clear the Root PME Status bit in the root port that received the wakeup PME and since the Requester ID was also set in the port's Root Status register, any subsequent PMEs didn't trigger interrupts. This problem can be avoided by clearing the Root PME Status bits in all PCI Express root ports during early resume. For this purpose, add an early resume routine to the PCIe port driver and make this driver be always registered, even if pci_ports_disable is set (in which case the driver's only function is to provide the early resume callback). Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pcie/pme.c | 27 ++++----------------------- drivers/pci/pcie/portdrv.h | 2 ++ drivers/pci/pcie/portdrv_core.c | 25 ++++++++++++++----------- drivers/pci/pcie/portdrv_pci.c | 37 +++++++++++++++++++++++++++++++++---- include/linux/pci_regs.h | 2 ++ 5 files changed, 55 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 2f3c90407227..073f0308c6b2 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -26,9 +26,6 @@ #include "../pci.h" #include "portdrv.h" -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ - /* * If this switch is set, MSI will not be used for PCIe PME signaling. This * causes the PCIe port driver to use INTx interrupts only, but it turns out @@ -73,22 +70,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) pci_write_config_word(dev, rtctl_pos, rtctl); } -/** - * pcie_pme_clear_status - Clear root port PME interrupt status. - * @dev: PCIe root port or event collector. - */ -static void pcie_pme_clear_status(struct pci_dev *dev) -{ - int rtsta_pos; - u32 rtsta; - - rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; - - pci_read_config_dword(dev, rtsta_pos, &rtsta); - rtsta |= PCI_EXP_RTSTA_PME; - pci_write_config_dword(dev, rtsta_pos, rtsta); -} - /** * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. * @bus: PCI bus to scan. @@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work) * Clear PME status of the port. If there are other * pending PMEs, the status will be set again. */ - pcie_pme_clear_status(port); + pcie_clear_root_pme_status(port); spin_unlock_irq(&data->lock); pcie_pme_handle_request(port, rtsta & 0xffff); @@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv) port = srv->port; pcie_pme_interrupt_enable(port, false); - pcie_pme_clear_status(port); + pcie_clear_root_pme_status(port); ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); if (ret) { @@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) spin_lock_irq(&data->lock); pcie_pme_interrupt_enable(port, false); - pcie_pme_clear_status(port); + pcie_clear_root_pme_status(port); data->noirq = true; spin_unlock_irq(&data->lock); @@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv) spin_lock_irq(&data->lock); data->noirq = false; - pcie_pme_clear_status(port); + pcie_clear_root_pme_status(port); pcie_pme_interrupt_enable(port, true); spin_unlock_irq(&data->lock); diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 7b5aba0a3291..8fcc03598b29 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -35,6 +35,8 @@ extern void pcie_port_bus_unregister(void); struct pci_dev; +extern void pcie_clear_root_pme_status(struct pci_dev *dev); + #ifdef CONFIG_PCIE_PME extern bool pcie_pme_msi_disabled; diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index a9c222d79ebc..5130d0d22390 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -241,17 +241,17 @@ static int get_port_device_capability(struct pci_dev *dev) int cap_mask; int err; + if (pcie_ports_disabled) + return 0; + err = pcie_port_platform_notify(dev, &cap_mask); - if (pcie_ports_auto) { - if (err) { - pcie_no_aspm(); - return 0; - } - } else { + if (!pcie_ports_auto) { cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP | PCIE_PORT_SERVICE_VC; if (pci_aer_available()) cap_mask |= PCIE_PORT_SERVICE_AER; + } else if (err) { + return 0; } pos = pci_pcie_cap(dev); @@ -349,15 +349,18 @@ int pcie_port_device_register(struct pci_dev *dev) int status, capabilities, i, nr_service; int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; - /* Get and check PCI Express port services */ - capabilities = get_port_device_capability(dev); - if (!capabilities) - return -ENODEV; - /* Enable PCI Express port device */ status = pci_enable_device(dev); if (status) return status; + + /* Get and check PCI Express port services */ + capabilities = get_port_device_capability(dev); + if (!capabilities) { + pcie_no_aspm(); + return 0; + } + pci_set_master(dev); /* * Initialize service irqs. Don't use service devices that diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index f9033e190fb6..e0610bda1dea 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup); /* global data */ +/** + * pcie_clear_root_pme_status - Clear root port PME interrupt status. + * @dev: PCIe root port or event collector. + */ +void pcie_clear_root_pme_status(struct pci_dev *dev) +{ + int rtsta_pos; + u32 rtsta; + + rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; + + pci_read_config_dword(dev, rtsta_pos, &rtsta); + rtsta |= PCI_EXP_RTSTA_PME; + pci_write_config_dword(dev, rtsta_pos, rtsta); +} + static int pcie_portdrv_restore_config(struct pci_dev *dev) { int retval; @@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) } #ifdef CONFIG_PM +static int pcie_port_resume_noirq(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + /* + * Some BIOSes forget to clear Root PME Status bits after system wakeup + * which breaks ACPI-based runtime wakeup on PCI Express, so clear those + * bits now just in case (shouldn't hurt). + */ + if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + pcie_clear_root_pme_status(pdev); + return 0; +} + static const struct dev_pm_ops pcie_portdrv_pm_ops = { .suspend = pcie_port_device_suspend, .resume = pcie_port_device_resume, @@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = { .thaw = pcie_port_device_resume, .poweroff = pcie_port_device_suspend, .restore = pcie_port_device_resume, + .resume_noirq = pcie_port_resume_noirq, }; #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) @@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void) { int retval; - if (pcie_ports_disabled) { - pcie_no_aspm(); - return -EACCES; - } + if (pcie_ports_disabled) + return pci_register_driver(&pcie_portdriver); dmi_check_system(pcie_portdrv_dmi_table); diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index d4f2c80a6c3e..5b7e6b1ba54f 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -504,6 +504,8 @@ #define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */ #define PCI_EXP_RTCAP 30 /* Root Capabilities */ #define PCI_EXP_RTSTA 32 /* Root Status */ +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ #define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ -- cgit v1.2.3 From 0131d8973c8b9bd9d40fee8fae24eab24821efdb Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 1 Dec 2010 10:54:46 +0100 Subject: of/address: use proper endianess in get_flags This patch changes u32 to __be32 for all "ranges", "prop" and "addr" and such. Those variables are pointing to the device tree which contains integers in big endian format. Most functions are doing it right because of_read_number() is doing the right thing for them. of_bus_isa_get_flags(), of_bus_pci_get_flags() and of_bus_isa_map() were accessing the data directly and were doing it wrong. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Benjamin Herrenschmidt Signed-off-by: Grant Likely --- arch/powerpc/include/asm/prom.h | 2 +- drivers/of/address.c | 54 +++++++++++++++++++++-------------------- include/linux/of_address.h | 6 ++--- 3 files changed, 32 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index 98264bf0a433..d72757585595 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -42,7 +42,7 @@ extern void pci_create_OF_bus_map(void); /* Translate a DMA address from device space to CPU space */ extern u64 of_translate_dma_address(struct device_node *dev, - const u32 *in_addr); + const __be32 *in_addr); #ifdef CONFIG_PCI extern unsigned long pci_address_to_pio(phys_addr_t address); diff --git a/drivers/of/address.c b/drivers/of/address.c index 3a1c7e70b192..b4559c58c095 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -12,13 +12,13 @@ (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, +static int __of_address_to_resource(struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, struct resource *r); /* Debug utility */ #ifdef DEBUG -static void of_dump_addr(const char *s, const u32 *addr, int na) +static void of_dump_addr(const char *s, const __be32 *addr, int na) { printk(KERN_DEBUG "%s", s); while (na--) @@ -26,7 +26,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na) printk("\n"); } #else -static void of_dump_addr(const char *s, const u32 *addr, int na) { } +static void of_dump_addr(const char *s, const __be32 *addr, int na) { } #endif /* Callbacks for bus specific translators */ @@ -36,10 +36,10 @@ struct of_bus { int (*match)(struct device_node *parent); void (*count_cells)(struct device_node *child, int *addrc, int *sizec); - u64 (*map)(u32 *addr, const u32 *range, + u64 (*map)(u32 *addr, const __be32 *range, int na, int ns, int pna); int (*translate)(u32 *addr, u64 offset, int na); - unsigned int (*get_flags)(const u32 *addr); + unsigned int (*get_flags)(const __be32 *addr); }; /* @@ -55,7 +55,7 @@ static void of_bus_default_count_cells(struct device_node *dev, *sizec = of_n_size_cells(dev); } -static u64 of_bus_default_map(u32 *addr, const u32 *range, +static u64 of_bus_default_map(u32 *addr, const __be32 *range, int na, int ns, int pna) { u64 cp, s, da; @@ -85,7 +85,7 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na) return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned int of_bus_default_get_flags(const __be32 *addr) { return IORESOURCE_MEM; } @@ -110,10 +110,10 @@ static void of_bus_pci_count_cells(struct device_node *np, *sizec = 2; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned int of_bus_pci_get_flags(const __be32 *addr) { unsigned int flags = 0; - u32 w = addr[0]; + u32 w = be32_to_cpup(addr); switch((w >> 24) & 0x03) { case 0x01: @@ -129,7 +129,8 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) return flags; } -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) +static u64 of_bus_pci_map(u32 *addr, const __be32 *range, int na, int ns, + int pna) { u64 cp, s, da; unsigned int af, rf; @@ -160,7 +161,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, +const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags) { const __be32 *prop; @@ -207,7 +208,7 @@ EXPORT_SYMBOL(of_get_pci_address); int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) { - const u32 *addrp; + const __be32 *addrp; u64 size; unsigned int flags; @@ -237,12 +238,13 @@ static void of_bus_isa_count_cells(struct device_node *child, *sizec = 1; } -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna) +static u64 of_bus_isa_map(u32 *addr, const __be32 *range, int na, int ns, + int pna) { u64 cp, s, da; /* Check address type match */ - if ((addr[0] ^ range[0]) & 0x00000001) + if ((addr[0] ^ range[0]) & cpu_to_be32(1)) return OF_BAD_ADDR; /* Read address values, skipping high cell */ @@ -264,10 +266,10 @@ static int of_bus_isa_translate(u32 *addr, u64 offset, int na) return of_bus_default_translate(addr + 1, offset, na - 1); } -static unsigned int of_bus_isa_get_flags(const u32 *addr) +static unsigned int of_bus_isa_get_flags(const __be32 *addr) { unsigned int flags = 0; - u32 w = addr[0]; + u32 w = be32_to_cpup(addr); if (w & 1) flags |= IORESOURCE_IO; @@ -330,7 +332,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, struct of_bus *pbus, u32 *addr, int na, int ns, int pna, const char *rprop) { - const u32 *ranges; + const __be32 *ranges; unsigned int rlen; int rone; u64 offset = OF_BAD_ADDR; @@ -398,7 +400,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things */ -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, +u64 __of_translate_address(struct device_node *dev, const __be32 *in_addr, const char *rprop) { struct device_node *parent = NULL; @@ -475,22 +477,22 @@ u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, return result; } -u64 of_translate_address(struct device_node *dev, const u32 *in_addr) +u64 of_translate_address(struct device_node *dev, const __be32 *in_addr) { return __of_translate_address(dev, in_addr, "ranges"); } EXPORT_SYMBOL(of_translate_address); -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr) +u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) { return __of_translate_address(dev, in_addr, "dma-ranges"); } EXPORT_SYMBOL(of_translate_dma_address); -const u32 *of_get_address(struct device_node *dev, int index, u64 *size, +const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { - const u32 *prop; + const __be32 *prop; unsigned int psize; struct device_node *parent; struct of_bus *bus; @@ -525,8 +527,8 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, - u64 size, unsigned int flags, +static int __of_address_to_resource(struct device_node *dev, + const __be32 *addrp, u64 size, unsigned int flags, struct resource *r) { u64 taddr; @@ -564,7 +566,7 @@ static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, int of_address_to_resource(struct device_node *dev, int index, struct resource *r) { - const u32 *addrp; + const __be32 *addrp; u64 size; unsigned int flags; diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 8aea06f0564c..2feda6ee6140 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -3,7 +3,7 @@ #include #include -extern u64 of_translate_address(struct device_node *np, const u32 *addr); +extern u64 of_translate_address(struct device_node *np, const __be32 *addr); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); extern void __iomem *of_iomap(struct device_node *device, int index); @@ -21,7 +21,7 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } #endif #ifdef CONFIG_PCI -extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, +extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); @@ -32,7 +32,7 @@ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, return -ENOSYS; } -static inline const u32 *of_get_pci_address(struct device_node *dev, +static inline const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags) { return NULL; -- cgit v1.2.3 From 194588604765ac803f98fb9d19a36f6b835f4620 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 27 Oct 2010 18:03:47 -0700 Subject: of/mdio: Fix some endianness problems. In of_mdiobus_register(), the __be32 *addr variable is dereferenced. This will not work on little-endian targets. Also since it is unsigned, checking for less than zero is redundant. Fix these two issues. Signed-off-by: David Daney [grant.likely@secretlab.ca: removed goto] Signed-off-by: Grant Likely --- drivers/of/of_mdio.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 1fce00eb421b..dcd7857784f2 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -52,27 +52,35 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) /* Loop over the child nodes and register a phy_device for each one */ for_each_child_of_node(np, child) { - const __be32 *addr; + const __be32 *paddr; + u32 addr; int len; /* A PHY must have a reg property in the range [0-31] */ - addr = of_get_property(child, "reg", &len); - if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) { + paddr = of_get_property(child, "reg", &len); + if (!paddr || len < sizeof(*paddr)) { dev_err(&mdio->dev, "%s has invalid PHY address\n", child->full_name); continue; } + addr = be32_to_cpup(paddr); + if (addr >= 32) { + dev_err(&mdio->dev, "%s PHY address %i is too large\n", + child->full_name, addr); + continue; + } + if (mdio->irq) { - mdio->irq[*addr] = irq_of_parse_and_map(child, 0); - if (!mdio->irq[*addr]) - mdio->irq[*addr] = PHY_POLL; + mdio->irq[addr] = irq_of_parse_and_map(child, 0); + if (!mdio->irq[addr]) + mdio->irq[addr] = PHY_POLL; } - phy = get_phy_device(mdio, be32_to_cpup(addr)); + phy = get_phy_device(mdio, addr); if (!phy || IS_ERR(phy)) { dev_err(&mdio->dev, "error probing PHY at address %i\n", - *addr); + addr); continue; } phy_scan_fixups(phy); @@ -91,7 +99,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) } dev_dbg(&mdio->dev, "registered phy %s at address %i\n", - child->name, *addr); + child->name, addr); } return 0; -- cgit v1.2.3 From 9ed030d728f3bd03b6e869357da02725afda19a7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 17 Nov 2010 13:00:48 +0100 Subject: misc/at24: parse device tree data Information about the pagesize and read-only-status may also come from the devicetree. Parse this data, too, and act accordingly. While we are here, change the initialization printout a bit. write_max is useful to know to detect performance bottlenecks, the rest is superfluous. Signed-off-by: Wolfram Sang Signed-off-by: Grant Likely --- Documentation/powerpc/dts-bindings/eeprom.txt | 28 +++++++++++++++++++++++ drivers/misc/eeprom/at24.c | 33 ++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 Documentation/powerpc/dts-bindings/eeprom.txt (limited to 'drivers') diff --git a/Documentation/powerpc/dts-bindings/eeprom.txt b/Documentation/powerpc/dts-bindings/eeprom.txt new file mode 100644 index 000000000000..4342c10de1bf --- /dev/null +++ b/Documentation/powerpc/dts-bindings/eeprom.txt @@ -0,0 +1,28 @@ +EEPROMs (I2C) + +Required properties: + + - compatible : should be "," + If there is no specific driver for , a generic + driver based on is selected. Possible types are: + 24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64, + 24c128, 24c256, 24c512, 24c1024, spd + + - reg : the I2C address of the EEPROM + +Optional properties: + + - pagesize : the length of the pagesize for writing. Please consult the + manual of your device, that value varies a lot. A wrong value + may result in data loss! If not specified, a safety value of + '1' is used which will be very slow. + + - read-only: this parameterless property disables writes to the eeprom + +Example: + +eeprom@52 { + compatible = "atmel,24c32"; + reg = <0x52>; + pagesize = <32>; +}; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 559b0b3c16c3..3a53efc28821 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -457,6 +458,27 @@ static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf, /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_OF +static void at24_get_ofdata(struct i2c_client *client, + struct at24_platform_data *chip) +{ + const __be32 *val; + struct device_node *node = client->dev.of_node; + + if (node) { + if (of_get_property(node, "read-only", NULL)) + chip->flags |= AT24_FLAG_READONLY; + val = of_get_property(node, "pagesize", NULL); + if (val) + chip->page_size = be32_to_cpup(val); + } +} +#else +static void at24_get_ofdata(struct i2c_client *client, + struct at24_platform_data *chip) +{ } +#endif /* CONFIG_OF */ + static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct at24_platform_data chip; @@ -485,6 +507,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) */ chip.page_size = 1; + /* update chipdata if OF is present */ + at24_get_ofdata(client, &chip); + chip.setup = NULL; chip.context = NULL; } @@ -597,19 +622,15 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, at24); - dev_info(&client->dev, "%zu byte %s EEPROM %s\n", + dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n", at24->bin.size, client->name, - writable ? "(writable)" : "(read-only)"); + writable ? "writable" : "read-only", at24->write_max); if (use_smbus == I2C_SMBUS_WORD_DATA || use_smbus == I2C_SMBUS_BYTE_DATA) { dev_notice(&client->dev, "Falling back to %s reads, " "performance will suffer\n", use_smbus == I2C_SMBUS_WORD_DATA ? "word" : "byte"); } - dev_dbg(&client->dev, - "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n", - chip.page_size, num_addresses, - at24->write_max, use_smbus); /* export data to kernel code */ if (chip.setup) -- cgit v1.2.3 From 45efe847971e6274a04eea75a0745d8015b54d37 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 17 Nov 2010 13:00:49 +0100 Subject: misc/at24: add more sanity checks for parameters Side-effects happen when passing 0 to either io_limit or page_size. Give an error in case of this misconfiguration. Signed-off-by: Wolfram Sang Signed-off-by: Grant Likely --- drivers/misc/eeprom/at24.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 3a53efc28821..ab1ad41786d1 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -517,6 +517,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!is_power_of_2(chip.byte_len)) dev_warn(&client->dev, "byte_len looks suspicious (no power of 2)!\n"); + if (!chip.page_size) { + dev_err(&client->dev, "page_size must not be 0!\n"); + err = -EINVAL; + goto err_out; + } if (!is_power_of_2(chip.page_size)) dev_warn(&client->dev, "page_size looks suspicious (no power of 2)!\n"); @@ -681,6 +686,11 @@ static struct i2c_driver at24_driver = { static int __init at24_init(void) { + if (!io_limit) { + pr_err("at24: io_limit must not be 0!\n"); + return -EINVAL; + } + io_limit = rounddown_pow_of_two(io_limit); return i2c_add_driver(&at24_driver); } -- cgit v1.2.3 From 6675bc056790b403d198a173498d377187754142 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 25 Nov 2010 23:41:19 +0100 Subject: PM / Runtime: Fix comments to match runtime callback code Commit 05aa55dddb9ee4045c320661068bea78dad6a6e5 changed routines to succeed if the driver handler is not defined. Comments were not updated. Signed-off-by: Aaro Koskinen Signed-off-by: Rafael J. Wysocki --- drivers/base/power/generic_ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 81f2c84697f4..3d2c3500069a 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); * * If PM operations are defined for the @dev's driver and they include * ->runtime_suspend(), execute it and return its error code. Otherwise, - * return -EINVAL. + * return 0. */ int pm_generic_runtime_suspend(struct device *dev) { @@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); * * If PM operations are defined for the @dev's driver and they include * ->runtime_resume(), execute it and return its error code. Otherwise, - * return -EINVAL. + * return 0. */ int pm_generic_runtime_resume(struct device *dev) { -- cgit v1.2.3 From c7b61de5b7b17f0df34dc7d2f8b9576f8bd36fce Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 1 Dec 2010 00:14:42 +0100 Subject: PM / Runtime: Add synchronous runtime interface for interrupt handlers (v3) This patch (as1431c) makes the synchronous runtime-PM interface suitable for use in interrupt handlers. Subsystems can call the new pm_runtime_irq_safe() function to tell the PM core that a device's runtime_suspend and runtime_resume callbacks should be invoked with interrupts disabled and the spinlock held. This permits the pm_runtime_get_sync() and the new pm_runtime_put_sync_suspend() routines to be called from within interrupt handlers. When a device is declared irq-safe in this way, the PM core increments the parent's usage count, so the parent will never be runtime suspended. This prevents difficult situations in which an irq-safe device can't resume because it is forced to wait for its non-irq-safe parent. Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.txt | 31 +++++++++++++++++++++++++ drivers/base/power/runtime.c | 47 ++++++++++++++++++++++++++++++-------- include/linux/pm.h | 1 + include/linux/pm_runtime.h | 7 ++++++ 4 files changed, 77 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 41cc7b30d7dd..ffe55ffa540a 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -50,6 +50,15 @@ type's callbacks are not defined) of given device. The bus type, device type and device class callbacks are referred to as subsystem-level callbacks in what follows. +By default, the callbacks are always invoked in process context with interrupts +enabled. However, subsystems can use the pm_runtime_irq_safe() helper function +to tell the PM core that a device's ->runtime_suspend() and ->runtime_resume() +callbacks should be invoked in atomic context with interrupts disabled +(->runtime_idle() is still invoked the default way). This implies that these +callback routines must not block or sleep, but it also means that the +synchronous helper functions listed at the end of Section 4 can be used within +an interrupt handler or in an atomic context. + The subsystem-level suspend callback is _entirely_ _responsible_ for handling the suspend of the device as appropriate, which may, but need not include executing the device driver's own ->runtime_suspend() callback (from the @@ -237,6 +246,10 @@ defined in include/linux/pm.h: Section 8); it may be modified only by the pm_runtime_no_callbacks() helper function + unsigned int irq_safe; + - indicates that the ->runtime_suspend() and ->runtime_resume() callbacks + will be invoked with the spinlock held and interrupts disabled + unsigned int use_autosuspend; - indicates that the device's driver supports delayed autosuspend (see Section 9); it may be modified only by the @@ -344,6 +357,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: - decrement the device's usage counter; if the result is 0 then run pm_runtime_idle(dev) and return its result + int pm_runtime_put_sync_suspend(struct device *dev); + - decrement the device's usage counter; if the result is 0 then run + pm_runtime_suspend(dev) and return its result + int pm_runtime_put_sync_autosuspend(struct device *dev); - decrement the device's usage counter; if the result is 0 then run pm_runtime_autosuspend(dev) and return its result @@ -397,6 +414,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: PM attributes from /sys/devices/.../power (or prevent them from being added when the device is registered) + void pm_runtime_irq_safe(struct device *dev); + - set the power.irq_safe flag for the device, causing the runtime-PM + suspend and resume callbacks (but not the idle callback) to be invoked + with interrupts disabled + void pm_runtime_mark_last_busy(struct device *dev); - set the power.last_busy field to the current time @@ -438,6 +460,15 @@ pm_runtime_suspended() pm_runtime_mark_last_busy() pm_runtime_autosuspend_expiration() +If pm_runtime_irq_safe() has been called for a device then the following helper +functions may also be used in interrupt context: + +pm_runtime_suspend() +pm_runtime_autosuspend() +pm_runtime_resume() +pm_runtime_get_sync() +pm_runtime_put_sync_suspend() + 5. Run-time PM Initialization, Device Probing and Removal Initially, the run-time PM is disabled for all devices, which means that the diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 02c652be83e7..656493a5e073 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -250,13 +250,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) if (!cb) return -ENOSYS; - spin_unlock_irq(&dev->power.lock); + if (dev->power.irq_safe) { + retval = cb(dev); + } else { + spin_unlock_irq(&dev->power.lock); - retval = cb(dev); + retval = cb(dev); - spin_lock_irq(&dev->power.lock); + spin_lock_irq(&dev->power.lock); + } dev->power.runtime_error = retval; - return retval; } @@ -404,7 +407,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) goto out; } - if (parent && !parent->power.ignore_children) { + if (parent && !parent->power.ignore_children && !dev->power.irq_safe) { spin_unlock_irq(&dev->power.lock); pm_request_idle(parent); @@ -527,10 +530,13 @@ static int rpm_resume(struct device *dev, int rpmflags) if (!parent && dev->parent) { /* - * Increment the parent's resume counter and resume it if - * necessary. + * Increment the parent's usage counter and resume it if + * necessary. Not needed if dev is irq-safe; then the + * parent is permanently resumed. */ parent = dev->parent; + if (dev->power.irq_safe) + goto skip_parent; spin_unlock(&dev->power.lock); pm_runtime_get_noresume(parent); @@ -553,6 +559,7 @@ static int rpm_resume(struct device *dev, int rpmflags) goto out; goto repeat; } + skip_parent: if (dev->power.no_callbacks) goto no_callback; /* Assume success. */ @@ -584,7 +591,7 @@ static int rpm_resume(struct device *dev, int rpmflags) rpm_idle(dev, RPM_ASYNC); out: - if (parent) { + if (parent && !dev->power.irq_safe) { spin_unlock_irq(&dev->power.lock); pm_runtime_put(parent); @@ -1065,7 +1072,6 @@ EXPORT_SYMBOL_GPL(pm_runtime_allow); * Set the power.no_callbacks flag, which tells the PM core that this * device is power-managed through its parent and has no run-time PM * callbacks of its own. The run-time sysfs attributes will be removed. - * */ void pm_runtime_no_callbacks(struct device *dev) { @@ -1077,6 +1083,27 @@ void pm_runtime_no_callbacks(struct device *dev) } EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks); +/** + * pm_runtime_irq_safe - Leave interrupts disabled during callbacks. + * @dev: Device to handle + * + * Set the power.irq_safe flag, which tells the PM core that the + * ->runtime_suspend() and ->runtime_resume() callbacks for this device should + * always be invoked with the spinlock held and interrupts disabled. It also + * causes the parent's usage counter to be permanently incremented, preventing + * the parent from runtime suspending -- otherwise an irq-safe child might have + * to wait for a non-irq-safe parent. + */ +void pm_runtime_irq_safe(struct device *dev) +{ + if (dev->parent) + pm_runtime_get_sync(dev->parent); + spin_lock_irq(&dev->power.lock); + dev->power.irq_safe = 1; + spin_unlock_irq(&dev->power.lock); +} +EXPORT_SYMBOL_GPL(pm_runtime_irq_safe); + /** * update_autosuspend - Handle a change to a device's autosuspend settings. * @dev: Device to handle. @@ -1199,4 +1226,6 @@ void pm_runtime_remove(struct device *dev) /* Change the status back to 'suspended' to match the initial status. */ if (dev->power.runtime_status == RPM_ACTIVE) pm_runtime_set_suspended(dev); + if (dev->power.irq_safe && dev->parent) + pm_runtime_put_sync(dev->parent); } diff --git a/include/linux/pm.h b/include/linux/pm.h index 40f3f45702ba..61f2066e6852 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -486,6 +486,7 @@ struct dev_pm_info { unsigned int run_wake:1; unsigned int runtime_auto:1; unsigned int no_callbacks:1; + unsigned int irq_safe:1; unsigned int use_autosuspend:1; unsigned int timer_autosuspends:1; enum rpm_request request; diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index d19f1cca7f74..e9cc049ccb62 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -40,6 +40,7 @@ extern int pm_generic_runtime_idle(struct device *dev); extern int pm_generic_runtime_suspend(struct device *dev); extern int pm_generic_runtime_resume(struct device *dev); extern void pm_runtime_no_callbacks(struct device *dev); +extern void pm_runtime_irq_safe(struct device *dev); extern void __pm_runtime_use_autosuspend(struct device *dev, bool use); extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev); @@ -124,6 +125,7 @@ static inline int pm_generic_runtime_idle(struct device *dev) { return 0; } static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } static inline void pm_runtime_no_callbacks(struct device *dev) {} +static inline void pm_runtime_irq_safe(struct device *dev) {} static inline void pm_runtime_mark_last_busy(struct device *dev) {} static inline void __pm_runtime_use_autosuspend(struct device *dev, @@ -196,6 +198,11 @@ static inline int pm_runtime_put_sync(struct device *dev) return __pm_runtime_idle(dev, RPM_GET_PUT); } +static inline int pm_runtime_put_sync_suspend(struct device *dev) +{ + return __pm_runtime_suspend(dev, RPM_GET_PUT); +} + static inline int pm_runtime_put_sync_autosuspend(struct device *dev) { return __pm_runtime_suspend(dev, RPM_GET_PUT | RPM_AUTO); -- cgit v1.2.3 From 1e75227ef0571031cd18536ab768ee35667ec5b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Dec 2010 22:58:05 +0100 Subject: PM: Prevent dpm_prepare() from returning errors unnecessarily Currently dpm_prepare() returns error code if it finds that a device being suspended has a pending runtime resume request. However, it should not do that if the checking for wakeup events is not enabled. On the other hand, if the checking for wakeup events is enabled, it can return error when a wakeup event is detected, regardless of its source. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ead3e79d6fcf..4747a1e8b44a 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../base.h" #include "power.h" @@ -1052,8 +1053,10 @@ static int dpm_prepare(pm_message_t state) mutex_unlock(&dpm_list_mtx); pm_runtime_get_noresume(dev); - if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) { - /* Wake-up requested during system sleep transition. */ + if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) + pm_wakeup_event(dev, 0); + + if (!pm_check_wakeup_events()) { pm_runtime_put_sync(dev); error = -EBUSY; } else { @@ -1068,8 +1071,8 @@ static int dpm_prepare(pm_message_t state) error = 0; continue; } - printk(KERN_ERR "PM: Failed to prepare device %s " - "for power transition: error %d\n", + printk(KERN_INFO "PM: Device %s not prepared " + "for power transition: code %d\n", kobject_name(&dev->kobj), error); put_device(dev); break; -- cgit v1.2.3 From a2867e08c8e3bdbc00caf56bc3bdde19ccc058e3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Dec 2010 22:58:31 +0100 Subject: PM / Wakeup: Replace pm_check_wakeup_events() with pm_wakeup_pending() To avoid confusion with the meaning and return value of pm_check_wakeup_events() replace it with pm_wakeup_pending() that will work the other way around (ie. return true when system-wide power transition should be aborted). Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 2 +- drivers/base/power/wakeup.c | 20 ++++++++++---------- include/linux/suspend.h | 4 ++-- kernel/power/hibernate.c | 4 ++-- kernel/power/process.c | 2 +- kernel/power/suspend.c | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 4747a1e8b44a..8a5258339ca2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1056,7 +1056,7 @@ static int dpm_prepare(pm_message_t state) if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) pm_wakeup_event(dev, 0); - if (!pm_check_wakeup_events()) { + if (pm_wakeup_pending()) { pm_runtime_put_sync(dev); error = -EBUSY; } else { diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 71c5528e1c35..8ec406d8f548 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -542,26 +542,26 @@ static void pm_wakeup_update_hit_counts(void) } /** - * pm_check_wakeup_events - Check for new wakeup events. + * pm_wakeup_pending - Check if power transition in progress should be aborted. * * Compare the current number of registered wakeup events with its preserved - * value from the past to check if new wakeup events have been registered since - * the old value was stored. Check if the current number of wakeup events being - * processed is zero. + * value from the past and return true if new wakeup events have been registered + * since the old value was stored. Also return true if the current number of + * wakeup events being processed is different from zero. */ -bool pm_check_wakeup_events(void) +bool pm_wakeup_pending(void) { unsigned long flags; - bool ret = true; + bool ret = false; spin_lock_irqsave(&events_lock, flags); if (events_check_enabled) { - ret = ((unsigned int)atomic_read(&event_count) == saved_count) - && !atomic_read(&events_in_progress); - events_check_enabled = ret; + ret = ((unsigned int)atomic_read(&event_count) != saved_count) + || atomic_read(&events_in_progress); + events_check_enabled = !ret; } spin_unlock_irqrestore(&events_lock, flags); - if (!ret) + if (ret) pm_wakeup_update_hit_counts(); return ret; } diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 26697514c5ec..144b34be5c32 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -292,7 +292,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb); /* drivers/base/power/wakeup.c */ extern bool events_check_enabled; -extern bool pm_check_wakeup_events(void); +extern bool pm_wakeup_pending(void); extern bool pm_get_wakeup_count(unsigned int *count); extern bool pm_save_wakeup_count(unsigned int count); #else /* !CONFIG_PM_SLEEP */ @@ -309,7 +309,7 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) #define pm_notifier(fn, pri) do { (void)(fn); } while (0) -static inline bool pm_check_wakeup_events(void) { return true; } +static inline bool pm_wakeup_pending(void) { return false; } #endif /* !CONFIG_PM_SLEEP */ extern struct mutex pm_mutex; diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index c9a98beffee4..870f72bc72ae 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -278,7 +278,7 @@ static int create_image(int platform_mode) goto Enable_irqs; } - if (hibernation_test(TEST_CORE) || !pm_check_wakeup_events()) + if (hibernation_test(TEST_CORE) || pm_wakeup_pending()) goto Power_up; in_suspend = 1; @@ -516,7 +516,7 @@ int hibernation_platform_enter(void) local_irq_disable(); sysdev_suspend(PMSG_HIBERNATE); - if (!pm_check_wakeup_events()) { + if (pm_wakeup_pending()) { error = -EAGAIN; goto Power_up; } diff --git a/kernel/power/process.c b/kernel/power/process.c index eb2c88a9e562..d6d2a10320e0 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -85,7 +85,7 @@ static int try_to_freeze_tasks(bool sig_only) if (!todo || time_after(jiffies, end_time)) break; - if (!pm_check_wakeup_events()) { + if (pm_wakeup_pending()) { wakeup = true; break; } diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index ecf770509d0d..5e644e3a6bf3 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -163,7 +163,7 @@ static int suspend_enter(suspend_state_t state) error = sysdev_suspend(PMSG_SUSPEND); if (!error) { - if (!suspend_test(TEST_CORE) && pm_check_wakeup_events()) { + if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { error = suspend_ops->enter(state); events_check_enabled = false; } -- cgit v1.2.3 From d83f905e126f8cbc5e4addc5d1a64aea785b732e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Dec 2010 23:14:26 +0100 Subject: PM: Use pm_wakeup_pending() in __device_suspend() Before starting to suspend a device in __device_suspend() check if there's a request to abort the power transition and return -EBUSY in that case. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 8a5258339ca2..fb4ca2870081 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -877,6 +877,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (async_error) goto End; + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto End; + } + if (dev->class) { if (dev->class->pm) { pm_dev_dbg(dev, state, "class "); -- cgit v1.2.3 From 2cbb3ce1ad19e66858a4284dd6c4bb958162c483 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 15 Dec 2010 00:17:29 +0100 Subject: PM: Avoid compiler warning in pm_noirq_op() The compiler complains that calltime may be uninitialized in pm_noirq_op(), so add extra initialization for that variable to avoid the warning. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fb4ca2870081..e6d628012654 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -304,7 +304,7 @@ static int pm_noirq_op(struct device *dev, pm_message_t state) { int error = 0; - ktime_t calltime, delta, rettime; + ktime_t calltime = ktime_set(0, 0), delta, rettime; if (initcall_debug) { pr_info("calling %s+ @ %i, parent: %s\n", -- cgit v1.2.3 From 8a43a9ab7b329aa8590f8a064df9bf8c80987507 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 16 Dec 2010 00:50:30 +0100 Subject: PM: Use a different list of devices for each stage of device suspend Instead of keeping all devices in the same list during system suspend and resume, regardless of what suspend-resume callbacks have been executed for them already, use separate lists of devices that have had their ->prepare(), ->suspend() and ->suspend_noirq() callbacks executed. This will allow us to simplify the core device suspend and resume routines. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 53 +++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index e6d628012654..b711867fa58e 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -42,6 +42,9 @@ */ LIST_HEAD(dpm_list); +LIST_HEAD(dpm_prepared_list); +LIST_HEAD(dpm_suspended_list); +LIST_HEAD(dpm_noirq_list); static DEFINE_MUTEX(dpm_list_mtx); static pm_message_t pm_transition; @@ -476,14 +479,12 @@ End: */ void dpm_resume_noirq(pm_message_t state) { - struct list_head list; ktime_t starttime = ktime_get(); - INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); transition_started = false; - while (!list_empty(&dpm_list)) { - struct device *dev = to_device(dpm_list.next); + while (!list_empty(&dpm_noirq_list)) { + struct device *dev = to_device(dpm_noirq_list.next); get_device(dev); if (dev->power.status > DPM_OFF) { @@ -499,10 +500,9 @@ void dpm_resume_noirq(pm_message_t state) pm_dev_err(dev, state, " early", error); } if (!list_empty(&dev->power.entry)) - list_move_tail(&dev->power.entry, &list); + list_move_tail(&dev->power.entry, &dpm_suspended_list); put_device(dev); } - list_splice(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); dpm_show_time(starttime, state, "early"); resume_device_irqs(); @@ -611,16 +611,14 @@ static bool is_async(struct device *dev) */ static void dpm_resume(pm_message_t state) { - struct list_head list; struct device *dev; ktime_t starttime = ktime_get(); - INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; - list_for_each_entry(dev, &dpm_list, power.entry) { + list_for_each_entry(dev, &dpm_suspended_list, power.entry) { if (dev->power.status < DPM_OFF) continue; @@ -631,8 +629,8 @@ static void dpm_resume(pm_message_t state) } } - while (!list_empty(&dpm_list)) { - dev = to_device(dpm_list.next); + while (!list_empty(&dpm_suspended_list)) { + dev = to_device(dpm_suspended_list.next); get_device(dev); if (dev->power.status >= DPM_OFF && !is_async(dev)) { int error; @@ -644,15 +642,11 @@ static void dpm_resume(pm_message_t state) mutex_lock(&dpm_list_mtx); if (error) pm_dev_err(dev, state, "", error); - } else if (dev->power.status == DPM_SUSPENDING) { - /* Allow new children of the device to be registered */ - dev->power.status = DPM_RESUMING; } if (!list_empty(&dev->power.entry)) - list_move_tail(&dev->power.entry, &list); + list_move_tail(&dev->power.entry, &dpm_prepared_list); put_device(dev); } - list_splice(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); async_synchronize_full(); dpm_show_time(starttime, state, NULL); @@ -699,8 +693,8 @@ static void dpm_complete(pm_message_t state) INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); transition_started = false; - while (!list_empty(&dpm_list)) { - struct device *dev = to_device(dpm_list.prev); + while (!list_empty(&dpm_prepared_list)) { + struct device *dev = to_device(dpm_prepared_list.prev); get_device(dev); if (dev->power.status > DPM_ON) { @@ -803,15 +797,13 @@ End: */ int dpm_suspend_noirq(pm_message_t state) { - struct list_head list; ktime_t starttime = ktime_get(); int error = 0; - INIT_LIST_HEAD(&list); suspend_device_irqs(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_list)) { - struct device *dev = to_device(dpm_list.prev); + while (!list_empty(&dpm_suspended_list)) { + struct device *dev = to_device(dpm_suspended_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); @@ -826,10 +818,9 @@ int dpm_suspend_noirq(pm_message_t state) } dev->power.status = DPM_OFF_IRQ; if (!list_empty(&dev->power.entry)) - list_move(&dev->power.entry, &list); + list_move(&dev->power.entry, &dpm_noirq_list); put_device(dev); } - list_splice_tail(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); if (error) dpm_resume_noirq(resume_event(state)); @@ -957,16 +948,14 @@ static int device_suspend(struct device *dev) */ static int dpm_suspend(pm_message_t state) { - struct list_head list; ktime_t starttime = ktime_get(); int error = 0; - INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; - while (!list_empty(&dpm_list)) { - struct device *dev = to_device(dpm_list.prev); + while (!list_empty(&dpm_prepared_list)) { + struct device *dev = to_device(dpm_prepared_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); @@ -980,12 +969,11 @@ static int dpm_suspend(pm_message_t state) break; } if (!list_empty(&dev->power.entry)) - list_move(&dev->power.entry, &list); + list_move(&dev->power.entry, &dpm_suspended_list); put_device(dev); if (async_error) break; } - list_splice(&list, dpm_list.prev); mutex_unlock(&dpm_list_mtx); async_synchronize_full(); if (!error) @@ -1044,10 +1032,8 @@ static int device_prepare(struct device *dev, pm_message_t state) */ static int dpm_prepare(pm_message_t state) { - struct list_head list; int error = 0; - INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); transition_started = true; while (!list_empty(&dpm_list)) { @@ -1084,10 +1070,9 @@ static int dpm_prepare(pm_message_t state) } dev->power.status = DPM_SUSPENDING; if (!list_empty(&dev->power.entry)) - list_move_tail(&dev->power.entry, &list); + list_move_tail(&dev->power.entry, &dpm_prepared_list); put_device(dev); } - list_splice(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); return error; } -- cgit v1.2.3 From 5b219a51fdceaf76e0e18da57c7efb9e5586e567 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 16 Dec 2010 00:51:08 +0100 Subject: PM: Remove redundant checks from core device resume routines Since a separate list of devices is used to link devices that have completed each stage of suspend (or resume), it is not necessary to check dev->power.status in the core device resume routines any more. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index b711867fa58e..bb5c8cb64174 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -485,22 +485,18 @@ void dpm_resume_noirq(pm_message_t state) transition_started = false; while (!list_empty(&dpm_noirq_list)) { struct device *dev = to_device(dpm_noirq_list.next); + int error; get_device(dev); - if (dev->power.status > DPM_OFF) { - int error; - - dev->power.status = DPM_OFF; - mutex_unlock(&dpm_list_mtx); + dev->power.status = DPM_OFF; + list_move_tail(&dev->power.entry, &dpm_suspended_list); + mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); + error = device_resume_noirq(dev, state); + if (error) + pm_dev_err(dev, state, " early", error); - mutex_lock(&dpm_list_mtx); - if (error) - pm_dev_err(dev, state, " early", error); - } - if (!list_empty(&dev->power.entry)) - list_move_tail(&dev->power.entry, &dpm_suspended_list); + mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); @@ -619,9 +615,6 @@ static void dpm_resume(pm_message_t state) async_error = 0; list_for_each_entry(dev, &dpm_suspended_list, power.entry) { - if (dev->power.status < DPM_OFF) - continue; - INIT_COMPLETION(dev->power.completion); if (is_async(dev)) { get_device(dev); @@ -632,16 +625,16 @@ static void dpm_resume(pm_message_t state) while (!list_empty(&dpm_suspended_list)) { dev = to_device(dpm_suspended_list.next); get_device(dev); - if (dev->power.status >= DPM_OFF && !is_async(dev)) { + if (!is_async(dev)) { int error; mutex_unlock(&dpm_list_mtx); error = device_resume(dev, state, false); - - mutex_lock(&dpm_list_mtx); if (error) pm_dev_err(dev, state, "", error); + + mutex_lock(&dpm_list_mtx); } if (!list_empty(&dev->power.entry)) list_move_tail(&dev->power.entry, &dpm_prepared_list); @@ -697,17 +690,14 @@ static void dpm_complete(pm_message_t state) struct device *dev = to_device(dpm_prepared_list.prev); get_device(dev); - if (dev->power.status > DPM_ON) { - dev->power.status = DPM_ON; - mutex_unlock(&dpm_list_mtx); + dev->power.status = DPM_ON; + list_move(&dev->power.entry, &list); + mutex_unlock(&dpm_list_mtx); - device_complete(dev, state); - pm_runtime_put_sync(dev); + device_complete(dev, state); + pm_runtime_put_sync(dev); - mutex_lock(&dpm_list_mtx); - } - if (!list_empty(&dev->power.entry)) - list_move(&dev->power.entry, &list); + mutex_lock(&dpm_list_mtx); put_device(dev); } list_splice(&list, &dpm_list); -- cgit v1.2.3 From b8c76f6aed0ab7df73a6410f3f82de2c831bb144 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 16 Dec 2010 00:51:21 +0100 Subject: PM: Replace the device power.status field with a bit field The device power.status field is too complicated for its purpose (storing the information about whether or not the device is in the "active" state from the PM core's point of view), so replace it with a bit field and modify all of its users accordingly. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 17 +++++------------ drivers/usb/core/driver.c | 7 +++---- include/linux/device.h | 4 ++-- include/linux/pm.h | 43 ++----------------------------------------- 4 files changed, 12 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index bb5c8cb64174..a90480baa850 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -63,7 +63,7 @@ static int async_error; */ void device_pm_init(struct device *dev) { - dev->power.status = DPM_ON; + dev->power.in_suspend = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -98,7 +98,7 @@ void device_pm_add(struct device *dev) kobject_name(&dev->kobj)); mutex_lock(&dpm_list_mtx); if (dev->parent) { - if (dev->parent->power.status >= DPM_SUSPENDING) + if (dev->parent->power.in_suspend) dev_warn(dev, "parent %s should not be sleeping\n", dev_name(dev->parent)); } else if (transition_started) { @@ -488,7 +488,6 @@ void dpm_resume_noirq(pm_message_t state) int error; get_device(dev); - dev->power.status = DPM_OFF; list_move_tail(&dev->power.entry, &dpm_suspended_list); mutex_unlock(&dpm_list_mtx); @@ -541,7 +540,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) dpm_wait(dev->parent, async); device_lock(dev); - dev->power.status = DPM_RESUMING; + dev->power.in_suspend = false; if (dev->bus) { if (dev->bus->pm) { @@ -690,7 +689,7 @@ static void dpm_complete(pm_message_t state) struct device *dev = to_device(dpm_prepared_list.prev); get_device(dev); - dev->power.status = DPM_ON; + dev->power.in_suspend = false; list_move(&dev->power.entry, &list); mutex_unlock(&dpm_list_mtx); @@ -806,7 +805,6 @@ int dpm_suspend_noirq(pm_message_t state) put_device(dev); break; } - dev->power.status = DPM_OFF_IRQ; if (!list_empty(&dev->power.entry)) list_move(&dev->power.entry, &dpm_noirq_list); put_device(dev); @@ -894,9 +892,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } } - if (!error) - dev->power.status = DPM_OFF; - End: device_unlock(dev); complete_all(&dev->power.completion); @@ -1030,7 +1025,6 @@ static int dpm_prepare(pm_message_t state) struct device *dev = to_device(dpm_list.next); get_device(dev); - dev->power.status = DPM_PREPARING; mutex_unlock(&dpm_list_mtx); pm_runtime_get_noresume(dev); @@ -1046,7 +1040,6 @@ static int dpm_prepare(pm_message_t state) mutex_lock(&dpm_list_mtx); if (error) { - dev->power.status = DPM_ON; if (error == -EAGAIN) { put_device(dev); error = 0; @@ -1058,7 +1051,7 @@ static int dpm_prepare(pm_message_t state) put_device(dev); break; } - dev->power.status = DPM_SUSPENDING; + dev->power.in_suspend = true; if (!list_empty(&dev->power.entry)) list_move_tail(&dev->power.entry, &dpm_prepared_list); put_device(dev); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c0e60fbcb048..4ec50224ee86 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -376,7 +376,7 @@ static int usb_unbind_interface(struct device *dev) * Just re-enable it without affecting the endpoint toggles. */ usb_enable_interface(udev, intf, false); - } else if (!error && intf->dev.power.status == DPM_ON) { + } else if (!error && !intf->dev.power.in_suspend) { r = usb_set_interface(udev, intf->altsetting[0]. desc.bInterfaceNumber, 0); if (r < 0) @@ -961,7 +961,7 @@ void usb_rebind_intf(struct usb_interface *intf) } /* Try to rebind the interface */ - if (intf->dev.power.status == DPM_ON) { + if (!intf->dev.power.in_suspend) { intf->needs_binding = 0; rc = device_attach(&intf->dev); if (rc < 0) @@ -1108,8 +1108,7 @@ static int usb_resume_interface(struct usb_device *udev, if (intf->condition == USB_INTERFACE_UNBOUND) { /* Carry out a deferred switch to altsetting 0 */ - if (intf->needs_altsetting0 && - intf->dev.power.status == DPM_ON) { + if (intf->needs_altsetting0 && !intf->dev.power.in_suspend) { usb_set_interface(udev, intf->altsetting[0]. desc.bInterfaceNumber, 0); intf->needs_altsetting0 = 0; diff --git a/include/linux/device.h b/include/linux/device.h index dd4895313468..45bc8c1669d2 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -508,13 +508,13 @@ static inline int device_is_registered(struct device *dev) static inline void device_enable_async_suspend(struct device *dev) { - if (dev->power.status == DPM_ON) + if (!dev->power.in_suspend) dev->power.async_suspend = true; } static inline void device_disable_async_suspend(struct device *dev) { - if (dev->power.status == DPM_ON) + if (!dev->power.in_suspend) dev->power.async_suspend = false; } diff --git a/include/linux/pm.h b/include/linux/pm.h index 61f2066e6852..c1756dfeb8c5 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -366,45 +366,6 @@ extern struct dev_pm_ops generic_subsys_pm_ops; #define PMSG_AUTO_RESUME ((struct pm_message) \ { .event = PM_EVENT_AUTO_RESUME, }) -/** - * Device power management states - * - * These state labels are used internally by the PM core to indicate the current - * status of a device with respect to the PM core operations. - * - * DPM_ON Device is regarded as operational. Set this way - * initially and when ->complete() is about to be called. - * Also set when ->prepare() fails. - * - * DPM_PREPARING Device is going to be prepared for a PM transition. Set - * when ->prepare() is about to be called. - * - * DPM_RESUMING Device is going to be resumed. Set when ->resume(), - * ->thaw(), or ->restore() is about to be called. - * - * DPM_SUSPENDING Device has been prepared for a power transition. Set - * when ->prepare() has just succeeded. - * - * DPM_OFF Device is regarded as inactive. Set immediately after - * ->suspend(), ->freeze(), or ->poweroff() has succeeded. - * Also set when ->resume()_noirq, ->thaw_noirq(), or - * ->restore_noirq() is about to be called. - * - * DPM_OFF_IRQ Device is in a "deep sleep". Set immediately after - * ->suspend_noirq(), ->freeze_noirq(), or - * ->poweroff_noirq() has just succeeded. - */ - -enum dpm_state { - DPM_INVALID, - DPM_ON, - DPM_PREPARING, - DPM_RESUMING, - DPM_SUSPENDING, - DPM_OFF, - DPM_OFF_IRQ, -}; - /** * Device run-time power management status. * @@ -463,8 +424,8 @@ struct wakeup_source; struct dev_pm_info { pm_message_t power_state; unsigned int can_wakeup:1; - unsigned async_suspend:1; - enum dpm_state status; /* Owned by the PM core */ + unsigned int async_suspend:1; + unsigned int in_suspend:1; /* Owned by the PM core */ spinlock_t lock; #ifdef CONFIG_PM_SLEEP struct list_head entry; -- cgit v1.2.3 From b64959e6158d6dcb640fc22d7f43b94ad1c91135 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 16 Dec 2010 17:11:45 +0100 Subject: PM: Permit registration of parentless devices during system suspend The registration of a new parentless device during system suspend will not lead to any complications affecting the PM core (the device will be effectively seen after the subsequent resume has completed), so remove the code used for detection of such events. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a90480baa850..11fe6ed75278 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -49,12 +49,6 @@ LIST_HEAD(dpm_noirq_list); static DEFINE_MUTEX(dpm_list_mtx); static pm_message_t pm_transition; -/* - * Set once the preparation of devices for a PM transition has started, reset - * before starting to resume devices. Protected by dpm_list_mtx. - */ -static bool transition_started; - static int async_error; /** @@ -97,19 +91,9 @@ void device_pm_add(struct device *dev) dev->bus ? dev->bus->name : "No Bus", kobject_name(&dev->kobj)); mutex_lock(&dpm_list_mtx); - if (dev->parent) { - if (dev->parent->power.in_suspend) - dev_warn(dev, "parent %s should not be sleeping\n", - dev_name(dev->parent)); - } else if (transition_started) { - /* - * We refuse to register parentless devices while a PM - * transition is in progress in order to avoid leaving them - * unhandled down the road - */ - dev_WARN(dev, "Parentless device registered during a PM transaction\n"); - } - + if (dev->parent && dev->parent->power.in_suspend) + dev_warn(dev, "parent %s should not be sleeping\n", + dev_name(dev->parent)); list_add_tail(&dev->power.entry, &dpm_list); mutex_unlock(&dpm_list_mtx); } @@ -482,7 +466,6 @@ void dpm_resume_noirq(pm_message_t state) ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - transition_started = false; while (!list_empty(&dpm_noirq_list)) { struct device *dev = to_device(dpm_noirq_list.next); int error; @@ -684,7 +667,6 @@ static void dpm_complete(pm_message_t state) INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); - transition_started = false; while (!list_empty(&dpm_prepared_list)) { struct device *dev = to_device(dpm_prepared_list.prev); @@ -1020,7 +1002,6 @@ static int dpm_prepare(pm_message_t state) int error = 0; mutex_lock(&dpm_list_mtx); - transition_started = true; while (!list_empty(&dpm_list)) { struct device *dev = to_device(dpm_list.next); -- cgit v1.2.3 From 5c1a07ab3e78ef68fc9ccf419c969e8ed88d7cb6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 24 Dec 2010 15:03:34 +0100 Subject: PM: Use dev_name() in core device suspend and resume routines Use dev_name() wherever applicable in drivers/base/power/main.c. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 11fe6ed75278..2a52270aeb30 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -88,8 +88,7 @@ void device_pm_unlock(void) void device_pm_add(struct device *dev) { pr_debug("PM: Adding info for %s:%s\n", - dev->bus ? dev->bus->name : "No Bus", - kobject_name(&dev->kobj)); + dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); mutex_lock(&dpm_list_mtx); if (dev->parent && dev->parent->power.in_suspend) dev_warn(dev, "parent %s should not be sleeping\n", @@ -105,8 +104,7 @@ void device_pm_add(struct device *dev) void device_pm_remove(struct device *dev) { pr_debug("PM: Removing info for %s:%s\n", - dev->bus ? dev->bus->name : "No Bus", - kobject_name(&dev->kobj)); + dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); complete_all(&dev->power.completion); mutex_lock(&dpm_list_mtx); list_del_init(&dev->power.entry); @@ -123,10 +121,8 @@ void device_pm_remove(struct device *dev) void device_pm_move_before(struct device *deva, struct device *devb) { pr_debug("PM: Moving %s:%s before %s:%s\n", - deva->bus ? deva->bus->name : "No Bus", - kobject_name(&deva->kobj), - devb->bus ? devb->bus->name : "No Bus", - kobject_name(&devb->kobj)); + deva->bus ? deva->bus->name : "No Bus", dev_name(deva), + devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); /* Delete deva from dpm_list and reinsert before devb. */ list_move_tail(&deva->power.entry, &devb->power.entry); } @@ -139,10 +135,8 @@ void device_pm_move_before(struct device *deva, struct device *devb) void device_pm_move_after(struct device *deva, struct device *devb) { pr_debug("PM: Moving %s:%s after %s:%s\n", - deva->bus ? deva->bus->name : "No Bus", - kobject_name(&deva->kobj), - devb->bus ? devb->bus->name : "No Bus", - kobject_name(&devb->kobj)); + deva->bus ? deva->bus->name : "No Bus", dev_name(deva), + devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); /* Delete deva from dpm_list and reinsert after devb. */ list_move(&deva->power.entry, &devb->power.entry); } @@ -154,8 +148,7 @@ void device_pm_move_after(struct device *deva, struct device *devb) void device_pm_move_last(struct device *dev) { pr_debug("PM: Moving %s:%s to end of list\n", - dev->bus ? dev->bus->name : "No Bus", - kobject_name(&dev->kobj)); + dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); list_move_tail(&dev->power.entry, &dpm_list); } @@ -393,7 +386,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info, int error) { printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n", - kobject_name(&dev->kobj), pm_verb(state.event), info, error); + dev_name(dev), pm_verb(state.event), info, error); } static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) @@ -1028,7 +1021,7 @@ static int dpm_prepare(pm_message_t state) } printk(KERN_INFO "PM: Device %s not prepared " "for power transition: code %d\n", - kobject_name(&dev->kobj), error); + dev_name(dev), error); put_device(dev); break; } -- cgit v1.2.3 From 4b31db8a16fa0d4d6a0fa42d044e7a4f4dad3641 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 24 Dec 2010 15:04:06 +0100 Subject: PM / Runtime: Generic resume shouldn't set RPM_ACTIVE unconditionally The __pm_generic_resume() function changes the given device's runtime PM status to RPM_ACTIVE if its driver's callback returns 0, but it only should do that if the rumtime PM is enabled for the device. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/generic_ops.c | 2 +- include/linux/pm_runtime.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 3d2c3500069a..42f97f925629 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -185,7 +185,7 @@ static int __pm_generic_resume(struct device *dev, int event) return 0; ret = callback(dev); - if (!ret) { + if (!ret && pm_runtime_enabled(dev)) { pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index e9cc049ccb62..d34f067e2a7f 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -82,6 +82,11 @@ static inline bool pm_runtime_suspended(struct device *dev) && !dev->power.disable_depth; } +static inline bool pm_runtime_enabled(struct device *dev) +{ + return !dev->power.disable_depth; +} + static inline void pm_runtime_mark_last_busy(struct device *dev) { ACCESS_ONCE(dev->power.last_busy) = jiffies; @@ -120,6 +125,7 @@ static inline void pm_runtime_put_noidle(struct device *dev) {} static inline bool device_run_wake(struct device *dev) { return false; } static inline void device_set_run_wake(struct device *dev, bool enable) {} static inline bool pm_runtime_suspended(struct device *dev) { return false; } +static inline bool pm_runtime_enabled(struct device *dev) { return false; } static inline int pm_generic_runtime_idle(struct device *dev) { return 0; } static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } -- cgit v1.2.3 From 3ae22e8c8ac39daf88ae32f047fb23825be7c646 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 25 Dec 2010 15:32:27 +0100 Subject: spi / PM: Support dev_pm_ops Allow SPI drivers to use runtime PM and other dev_pm_ops features by implementing dev_pm_ops for the bus. The existing bus specific suspend and resume functions will be called if a driver does not provide dev_pm_ops allowing for transition to the new model. Signed-off-by: Mark Brown Acked-by: Grant Likely Signed-off-by: Rafael J. Wysocki --- drivers/spi/spi.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b02d0cbce890..34bb17f03019 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -28,6 +28,7 @@ #include #include #include +#include static void spidev_release(struct device *dev) { @@ -100,9 +101,8 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } -#ifdef CONFIG_PM - -static int spi_suspend(struct device *dev, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int spi_legacy_suspend(struct device *dev, pm_message_t message) { int value = 0; struct spi_driver *drv = to_spi_driver(dev->driver); @@ -117,7 +117,7 @@ static int spi_suspend(struct device *dev, pm_message_t message) return value; } -static int spi_resume(struct device *dev) +static int spi_legacy_resume(struct device *dev) { int value = 0; struct spi_driver *drv = to_spi_driver(dev->driver); @@ -132,18 +132,94 @@ static int spi_resume(struct device *dev) return value; } +static int spi_pm_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_suspend(dev); + else + return spi_legacy_suspend(dev, PMSG_SUSPEND); +} + +static int spi_pm_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_resume(dev); + else + return spi_legacy_resume(dev); +} + +static int spi_pm_freeze(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_freeze(dev); + else + return spi_legacy_suspend(dev, PMSG_FREEZE); +} + +static int spi_pm_thaw(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_thaw(dev); + else + return spi_legacy_resume(dev); +} + +static int spi_pm_poweroff(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_poweroff(dev); + else + return spi_legacy_suspend(dev, PMSG_HIBERNATE); +} + +static int spi_pm_restore(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm) + return pm_generic_restore(dev); + else + return spi_legacy_resume(dev); +} #else -#define spi_suspend NULL -#define spi_resume NULL +#define spi_pm_suspend NULL +#define spi_pm_resume NULL +#define spi_pm_freeze NULL +#define spi_pm_thaw NULL +#define spi_pm_poweroff NULL +#define spi_pm_restore NULL #endif +static const struct dev_pm_ops spi_pm = { + .suspend = spi_pm_suspend, + .resume = spi_pm_resume, + .freeze = spi_pm_freeze, + .thaw = spi_pm_thaw, + .poweroff = spi_pm_poweroff, + .restore = spi_pm_restore, + SET_RUNTIME_PM_OPS( + pm_generic_runtime_suspend, + pm_generic_runtime_resume, + pm_generic_runtime_idle + ) +}; + struct bus_type spi_bus_type = { .name = "spi", .dev_attrs = spi_dev_attrs, .match = spi_match_device, .uevent = spi_uevent, - .suspend = spi_suspend, - .resume = spi_resume, + .pm = &spi_pm, }; EXPORT_SYMBOL_GPL(spi_bus_type); -- cgit v1.2.3 From c42988012ad9c1807b7c7a5ff855cd630094989b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 25 Dec 2010 16:17:32 +0000 Subject: drm/nouveau: Only select ACPI_VIDEO if its dependencies are met CONFIG_ACPI_VIDEO depends on more than just CONFIG_ACPI, so add those dependencies to the Kconfig select condition. The case where some dependencies fail to be satisfied should be handled correctly, because in that case the ACPI_VIDEO symbols we use are converted into static-inline stubs. Signed-off-by: Ben Hutchings Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 72730e9ca06c..21d6c29c2d21 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -10,7 +10,7 @@ config DRM_NOUVEAU select FB select FRAMEBUFFER_CONSOLE if !EMBEDDED select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT - select ACPI_VIDEO if ACPI + select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT help Choose this option for open-source nVidia support. -- cgit v1.2.3 From 8e91182bbdb8591be4835907d825a5b9a80495a9 Mon Sep 17 00:00:00 2001 From: Michel Hermier Date: Sat, 25 Dec 2010 16:58:56 +0100 Subject: drm/nouveau: Validate channel indices passed from userspace. When hacking the libdrm for improvements, I triggered a kernel crash related to the fact that the NOUVEAU_NOTIFIEROBJ_ALLOC ioctl calls nouveau_channel_get with an unchecked channel index. The patch ensures that the channel index is an unsigned and validates its value in nouveau_channel_get. Signed-off-by: Michel Hermier Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index e37977d02463..4d2f19420922 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -253,6 +253,9 @@ nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) struct nouveau_channel *chan; unsigned long flags; + if (unlikely(id < 0 || id >= NOUVEAU_MAX_CHANNEL_NR)) + return ERR_PTR(-EINVAL); + spin_lock_irqsave(&dev_priv->channels.lock, flags); chan = nouveau_channel_get_unlocked(dev_priv->channels.ptr[id]); spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -- cgit v1.2.3 From 86280a208825d55ba988420b6b0ed2d6b9ec80f8 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 27 Dec 2010 16:27:43 +0100 Subject: HID: picolcd: fix misuse of logical operation in place of bitop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC: Bruno Prémont CC: Jiri Kosina Signed-off-by: David Sterba Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index bc2e07740628..0aff3cdddd83 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -1544,7 +1544,7 @@ static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u, /* prepare buffer with info about what we want to read (addr & len) */ raw_data[0] = *off & 0xff; - raw_data[1] = (*off >> 8) && 0xff; + raw_data[1] = (*off >> 8) & 0xff; raw_data[2] = s < 20 ? s : 20; if (*off + raw_data[2] > 0xff) raw_data[2] = 0x100 - *off; @@ -1583,7 +1583,7 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, memset(raw_data, 0, sizeof(raw_data)); raw_data[0] = *off & 0xff; - raw_data[1] = (*off >> 8) && 0xff; + raw_data[1] = (*off >> 8) & 0xff; raw_data[2] = s < 20 ? s : 20; if (*off + raw_data[2] > 0xff) raw_data[2] = 0x100 - *off; -- cgit v1.2.3 From e7bf068aa3208d73e9dea817f6d975071ddd4336 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 27 Dec 2010 16:51:15 +0100 Subject: i7core_edac: fix typos in comments Signed-off-by: Jiri Kosina --- drivers/edac/i7core_edac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 362861c15779..81154ab296b6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1,6 +1,6 @@ /* Intel i7 core/Nehalem Memory Controller kernel module * - * This driver supports yhe memory controllers found on the Intel + * This driver supports the memory controllers found on the Intel * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx, * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield * and Westmere-EP. @@ -1271,7 +1271,7 @@ static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table) int i; /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses + * On Xeon 55xx, the Intel Quick Path Arch Generic Non-core pci buses * aren't announced by acpi. So, we need to use a legacy scan probing * to detect them */ @@ -1864,7 +1864,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (mce->mcgstatus & 1) i7core_check_error(mci); - /* Advice mcelog that the error were handled */ + /* Advise mcelog that the errors were handled */ return 1; } -- cgit v1.2.3 From bb9fb42029abcc90c265dbc40cab106421dd9348 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 28 Dec 2010 14:16:15 +0100 Subject: Revert conflicting V4L changes This is a partial revert of b595076a180a56d1bb1 ("tree-wide: fix comment/printk typos"), as it changes the code that no longer exists in linux-next. Reported-by: Stephen Rothwell Signed-off-by: Jiri Kosina --- drivers/media/video/zoran/zoran.h | 2 +- drivers/staging/stradis/stradis.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index b336259ce20c..27f05551183f 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -95,7 +95,7 @@ struct zoran_params { int quality; /* Measure for quality of compressed images. * Scales linearly with the size of the compressed images. - * Must be between 0 and 100, 100 is a compression + * Must be beetween 0 and 100, 100 is a compression * ratio of 1:4 */ int odd_even; /* Which field should come first ??? */ diff --git a/drivers/staging/stradis/stradis.c b/drivers/staging/stradis/stradis.c index 2e74355d1ea1..807dd7eb748f 100644 --- a/drivers/staging/stradis/stradis.c +++ b/drivers/staging/stradis/stradis.c @@ -745,7 +745,7 @@ static void set_out_format(struct saa7146 *saa, int mode) } } -/* Initialize bitmangler to map from a byte value to the mangled word that +/* Intialize bitmangler to map from a byte value to the mangled word that * must be output to program the Xilinx part through the DEBI port. * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0 * transfer FPGA code, init IBM chip, transfer IBM microcode -- cgit v1.2.3 From b1cd916ab96e5fcd16e2009410af2e8edfae2962 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 24 Dec 2010 09:33:33 +1000 Subject: drm/nvc0: kill off a couple more magics Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_graph.c | 14 +------------- drivers/gpu/drm/nouveau/nvc0_graph.h | 2 -- drivers/gpu/drm/nouveau/nvc0_grctx.c | 24 ++++++++++++++++++++---- 3 files changed, 21 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index cf2f6aa920b4..f03c17a10ab9 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -334,8 +334,6 @@ nvc0_graph_create(struct drm_device *dev) case 0xc0: if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */ priv->magic_not_rop_nr = 0x07; - priv->magic419bd0 = 0x0a360000; - priv->magic419be4 = 0x04c33a54; /* filled values up to tp_total, the rest 0 */ priv->magicgpc980[0] = 0x22111000; priv->magicgpc980[1] = 0x00000233; @@ -345,8 +343,6 @@ nvc0_graph_create(struct drm_device *dev) } else if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */ priv->magic_not_rop_nr = 0x05; - priv->magic419bd0 = 0x043c0000; - priv->magic419be4 = 0x09041208; priv->magicgpc980[0] = 0x11110000; priv->magicgpc980[1] = 0x00233222; priv->magicgpc980[2] = 0x00000000; @@ -355,8 +351,6 @@ nvc0_graph_create(struct drm_device *dev) } else if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */ priv->magic_not_rop_nr = 0x06; - priv->magic419bd0 = 0x023e0000; - priv->magic419be4 = 0x10414104; priv->magicgpc980[0] = 0x11110000; priv->magicgpc980[1] = 0x03332222; priv->magicgpc980[2] = 0x00000000; @@ -366,8 +360,6 @@ nvc0_graph_create(struct drm_device *dev) break; case 0xc3: /* 450, 4/0/0/0, 2 */ priv->magic_not_rop_nr = 0x03; - priv->magic419bd0 = 0x00500000; - priv->magic419be4 = 0x00000000; priv->magicgpc980[0] = 0x00003210; priv->magicgpc980[1] = 0x00000000; priv->magicgpc980[2] = 0x00000000; @@ -376,8 +368,6 @@ nvc0_graph_create(struct drm_device *dev) break; case 0xc4: /* 460, 3/4/0/0, 4 */ priv->magic_not_rop_nr = 0x01; - priv->magic419bd0 = 0x045c0000; - priv->magic419be4 = 0x09041208; priv->magicgpc980[0] = 0x02321100; priv->magicgpc980[1] = 0x00000000; priv->magicgpc980[2] = 0x00000000; @@ -386,14 +376,12 @@ nvc0_graph_create(struct drm_device *dev) break; } - if (!priv->magic419bd0) { + if (!priv->magic_not_rop_nr) { NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n", priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2], priv->tp_nr[3], priv->rop_nr); /* use 0xc3's values... */ priv->magic_not_rop_nr = 0x03; - priv->magic419bd0 = 0x00500000; - priv->magic419be4 = 0x00000000; priv->magicgpc980[0] = 0x00003210; priv->magicgpc980[1] = 0x00000000; priv->magicgpc980[2] = 0x00000000; diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h index 1e1f24f3fd34..40e26f9c56c4 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.h +++ b/drivers/gpu/drm/nouveau/nvc0_graph.h @@ -46,8 +46,6 @@ struct nvc0_graph_priv { struct nouveau_gpuobj *unk4188b8; u8 magic_not_rop_nr; - u32 magic419bd0; - u32 magic419be4; u32 magicgpc980[4]; u32 magicgpc918; }; diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c index 88fa6211ac19..fddfab73a58d 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grctx.c +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -1875,9 +1875,11 @@ nvc0_grctx_generate(struct nouveau_channel *chan) } if (1) { - u32 data[6] = {}; + u32 data[6] = {}, data2[2] = {}; u8 tpnr[GPC_MAX]; + u8 shift, ntpcv; + /* calculate first set of magics */ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); for (tp = 0; tp < priv->tp_total; tp++) { @@ -1892,6 +1894,20 @@ nvc0_grctx_generate(struct nouveau_channel *chan) for (; tp < 32; tp++) data[tp / 6] |= 7 << ((tp % 6) * 5); + /* and the second... */ + shift = 0; + ntpcv = priv->tp_total; + while (!(ntpcv & (1 << 4))) { + ntpcv <<= 1; + shift++; + } + + data2[0] = (ntpcv << 16); + data2[0] |= (shift << 21); + data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24); + for (i = 1; i < 7; i++) + data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); + // GPC_BROADCAST nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) | priv->magic_not_rop_nr); @@ -1900,9 +1916,9 @@ nvc0_grctx_generate(struct nouveau_channel *chan) // GPC_BROADCAST.TP_BROADCAST nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) | - priv->magic_not_rop_nr | - priv->magic419bd0); - nv_wr32(dev, 0x419be4, priv->magic419be4); + priv->magic_not_rop_nr | + data2[0]); + nv_wr32(dev, 0x419be4, data2[1]); for (i = 0; i < 6; i++) nv_wr32(dev, 0x419b00 + (i * 4), data[i]); -- cgit v1.2.3 From 93d0cd7b9e4855c12b3bb5c9367872476c78fef9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 29 Dec 2010 10:41:20 +1000 Subject: drm/nvc0: nuke left-over debug messages Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_fbcon.c | 2 -- drivers/gpu/drm/nouveau/nvc0_graph.c | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c index cbb4a1ae20b1..fa5d4c234383 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c +++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c @@ -200,8 +200,6 @@ nvc0_fbcon_accel_init(struct fb_info *info) return ret; } - printk(KERN_ERR "fb vma 0x%010llx\n", nvbo->vma.offset); - BEGIN_NVC0(chan, 2, NvSub2D, 0x0000, 1); OUT_RING (chan, 0x0000902d); BEGIN_NVC0(chan, 2, NvSub2D, 0x0104, 2); diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index f03c17a10ab9..c28bc7b04d27 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -244,7 +244,6 @@ nvc0_graph_load_context(struct nouveau_channel *chan) if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010)) NV_ERROR(dev, "PGRAPH: load_ctx timeout\n"); - printk(KERN_ERR "load_ctx 0x%08x\n", nv_rd32(dev, 0x409b00)); return 0; } -- cgit v1.2.3 From 6c39d116ba308ccf9007773a090ca6d20eb68459 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 29 Dec 2010 21:52:04 +1100 Subject: crypto: omap-sham - backlog handling fix Previous commit "removed redundant locking" introduced a bug in handling backlog. In certain cases, when async request complete callback will call complete() on -EINPROGRESS code, it will cause uncompleted requests. It does not happen in implementation similar to crypto test manager, but it will happen in implementation similar to dm-crypt. Backlog needs to be checked before dequeuing next request. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index eb988e7a2fd9..2e71123516e0 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -664,7 +664,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) static int omap_sham_handle_queue(struct omap_sham_dev *dd, struct ahash_request *req) { - struct crypto_async_request *async_req, *backlog = 0; + struct crypto_async_request *async_req, *backlog; struct omap_sham_reqctx *ctx; struct ahash_request *prev_req; unsigned long flags; @@ -677,11 +677,10 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, spin_unlock_irqrestore(&dd->lock, flags); return ret; } + backlog = crypto_get_backlog(&dd->queue); async_req = crypto_dequeue_request(&dd->queue); - if (async_req) { + if (async_req) dd->flags |= FLAGS_BUSY; - backlog = crypto_get_backlog(&dd->queue); - } spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) -- cgit v1.2.3 From 644a98453d5764f467b73f2e02df0d2688da1873 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 27 Dec 2010 13:42:20 +0900 Subject: fbdev: sh_mobile_hdmi: fixup compile error Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/video/sh_mobile_hdmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index d7df10315d8d..b19941d37ed4 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From e6ce1324e4f08b0d984340201a125806dae0e9a6 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:54:56 -0800 Subject: of/flattree: Add Kconfig for EARLY_FLATTREE The device tree code is now in two pieces: some which can be used generically on any platform which selects CONFIG_OF_FLATTREE, and some early which is used at boot time on only a few architectures. This patch segregates the early code so that only those architectures which care about it need compile it. This also means that some of the requirements in the early code (such as a cmd_line variable) that most architectures (e.g. X86) don't provide can be ignored. Signed-off-by: Stephen Neuendorffer [grant.likely@secretlab.ca: remove extra blank line addition] [grant.likely@secretlab.ca: fixed incorrect #ifdef CONFIG_EARLY_FLATTREE check] [grant.likely@secretlab.ca: Made OF_EARLY_FLATTREE select instead of depend on OF_FLATTREE] Signed-off-by: Grant Likely --- arch/microblaze/Kconfig | 2 +- arch/mips/Kconfig | 2 +- arch/powerpc/Kconfig | 2 +- drivers/of/Kconfig | 4 ++++ drivers/of/fdt.c | 4 ++++ 5 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 387d5ffdfd3a..5f5018a71a3d 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -14,7 +14,7 @@ config MICROBLAZE select HAVE_DMA_API_DEBUG select TRACING_SUPPORT select OF - select OF_FLATTREE + select OF_EARLY_FLATTREE config SWAP def_bool n diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0a9b5b8b2a19..f489ec30e071 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2218,7 +2218,7 @@ config SECCOMP config USE_OF bool "Flattened Device Tree support" select OF - select OF_FLATTREE + select OF_EARLY_FLATTREE help Include support for flattened device tree machine descriptions. diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index e625e9e034ae..48fb4790bfec 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -116,7 +116,7 @@ config PPC bool default y select OF - select OF_FLATTREE + select OF_EARLY_FLATTREE select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index e4b93a0a15d2..3c6e100a3ad0 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -19,6 +19,10 @@ config OF_FLATTREE bool select DTC +config OF_EARLY_FLATTREE + bool + select OF_FLATTREE + config OF_PROMTREE bool diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c1360e02f921..2ebacf14e7de 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -27,6 +27,8 @@ int __initdata dt_root_size_cells; struct boot_param_header *initial_boot_params; +#ifdef CONFIG_OF_EARLY_FLATTREE + char *find_flat_dt_string(u32 offset) { return ((char *)initial_boot_params) + @@ -604,3 +606,5 @@ void __init unflatten_device_tree(void) pr_debug(" <- unflatten_device_tree()\n"); } + +#endif /* CONFIG_OF_EARLY_FLATTREE */ -- cgit v1.2.3 From 9706a36e35c4ce04f28a62cfe1205b4e3b0dd13c Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:54:59 -0800 Subject: of/flattree: Add non-boottime device tree functions In preparation for providing run-time handling of device trees, factor out some of the basic functions so that they take an arbitrary blob, rather than relying on the single boot-time tree. V2: - functions have of_fdt_* names - removed find_flat_dt_string - blob argument is first Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 133 +++++++++++++++++++++++++++++-------------------- include/linux/of_fdt.h | 11 ++++ 2 files changed, 90 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 2ebacf14e7de..10eab21076ea 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -22,6 +22,82 @@ #include +char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) +{ + return ((char *)blob) + + be32_to_cpu(blob->off_dt_strings) + offset; +} + +/** + * of_fdt_get_property - Given a node in the given flat blob, return + * the property ptr + */ +void *of_fdt_get_property(struct boot_param_header *blob, + unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = be32_to_cpup((__be32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag == OF_DT_NOP) + continue; + if (tag != OF_DT_PROP) + return NULL; + + sz = be32_to_cpup((__be32 *)p); + noff = be32_to_cpup((__be32 *)(p + 4)); + p += 8; + if (be32_to_cpu(blob->version) < 0x10) + p = ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = of_fdt_get_string(blob, noff); + if (nstr == NULL) { + pr_warning("Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = ALIGN(p, 4); + } while (1); +} + +/** + * of_fdt_is_compatible - Return true if given node from the given blob has + * compat in its compatible list + * @blob: A device tree blob + * @node: node to test + * @compat: compatible string to compare with compatible list. + */ +int of_fdt_is_compatible(struct boot_param_header *blob, + unsigned long node, const char *compat) +{ + const char *cp; + unsigned long cplen, l; + + cp = of_fdt_get_property(blob, node, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + +/* Everything below here references initial_boot_params directly. */ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -29,12 +105,6 @@ struct boot_param_header *initial_boot_params; #ifdef CONFIG_OF_EARLY_FLATTREE -char *find_flat_dt_string(u32 offset) -{ - return ((char *)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_strings) + offset; -} - /** * of_scan_flat_dt - scan flattened tree blob and call callback on each. * @it: callback function @@ -123,38 +193,7 @@ unsigned long __init of_get_flat_dt_root(void) void *__init of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size) { - unsigned long p = node; - - do { - u32 tag = be32_to_cpup((__be32 *)p); - u32 sz, noff; - const char *nstr; - - p += 4; - if (tag == OF_DT_NOP) - continue; - if (tag != OF_DT_PROP) - return NULL; - - sz = be32_to_cpup((__be32 *)p); - noff = be32_to_cpup((__be32 *)(p + 4)); - p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = ALIGN(p, sz >= 8 ? 8 : 4); - - nstr = find_flat_dt_string(noff); - if (nstr == NULL) { - pr_warning("Can't find property index name !\n"); - return NULL; - } - if (strcmp(name, nstr) == 0) { - if (size) - *size = sz; - return (void *)p; - } - p += sz; - p = ALIGN(p, 4); - } while (1); + return of_fdt_get_property(initial_boot_params, node, name, size); } /** @@ -164,21 +203,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, */ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) { - const char *cp; - unsigned long cplen, l; - - cp = of_get_flat_dt_prop(node, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; + return of_fdt_is_compatible(initial_boot_params, node, compat); } static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, @@ -303,7 +328,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (be32_to_cpu(initial_boot_params->version) < 0x10) *p = ALIGN(*p, sz >= 8 ? 8 : 4); - pname = find_flat_dt_string(noff); + pname = of_fdt_get_string(initial_boot_params, noff); if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 7bbf5b328438..70c5b736f0a3 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -58,6 +58,17 @@ struct boot_param_header { }; #if defined(CONFIG_OF_FLATTREE) + +/* For scanning an arbitrary device-tree at any time */ +extern char *of_fdt_get_string(struct boot_param_header *blob, u32 offset); +extern void *of_fdt_get_property(struct boot_param_header *blob, + unsigned long node, + const char *name, + unsigned long *size); +extern int of_fdt_is_compatible(struct boot_param_header *blob, + unsigned long node, + const char *compat); + /* TBD: Temporary export of fdt globals - remove when code fully merged */ extern int __initdata dt_root_addr_cells; extern int __initdata dt_root_size_cells; -- cgit v1.2.3 From a40d6c4cf12d87980c10b230df435d0f56adc40b Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:55:00 -0800 Subject: of/flattree: Refactor unflatten_dt_node unflatten_dt_node is a helper function that does most of the work to convert a device tree blob into tree of device nodes. This code now uses a passed-in blob instead of using the single boot-time blob, allowing it to be called in more contexts. Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 10eab21076ea..cf74e546faf2 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -206,7 +206,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return of_fdt_is_compatible(initial_boot_params, node, compat); } -static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, +static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { void *res; @@ -220,16 +220,18 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree + * @blob: The parent device tree blob * @p: pointer to node in flat tree * @dad: Parent struct device_node * @allnextpp: pointer to ->allnext from last allocated device_node * @fpsize: Size of the node path up at the current depth. */ -unsigned long __init unflatten_dt_node(unsigned long mem, - unsigned long *p, - struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize) +unsigned long unflatten_dt_node(struct boot_param_header *blob, + unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp, + unsigned long fpsize) { struct device_node *np; struct property *pp, **prev_pp = NULL; @@ -325,10 +327,10 @@ unsigned long __init unflatten_dt_node(unsigned long mem, sz = be32_to_cpup((__be32 *)(*p)); noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) + if (be32_to_cpu(blob->version) < 0x10) *p = ALIGN(*p, sz >= 8 ? 8 : 4); - pname = of_fdt_get_string(initial_boot_params, noff); + pname = of_fdt_get_string(blob, noff); if (pname == NULL) { pr_info("Can't find property name in list !\n"); break; @@ -407,7 +409,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if (tag == OF_DT_NOP) *p += 4; else - mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); + mem = unflatten_dt_node(blob, mem, p, np, allnextpp, + fpsize); tag = be32_to_cpup((__be32 *)(*p)); } if (tag != OF_DT_END_NODE) { @@ -599,7 +602,8 @@ void __init unflatten_device_tree(void) /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + be32_to_cpu(initial_boot_params->off_dt_struct); - size = unflatten_dt_node(0, &start, NULL, NULL, 0); + size = unflatten_dt_node(initial_boot_params, 0, &start, + NULL, NULL, 0); size = (size | 3) + 1; pr_debug(" size is %lx, allocating...\n", size); @@ -616,7 +620,8 @@ void __init unflatten_device_tree(void) /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + be32_to_cpu(initial_boot_params->off_dt_struct); - unflatten_dt_node(mem, &start, NULL, &allnextp, 0); + unflatten_dt_node(initial_boot_params, mem, &start, + NULL, &allnextp, 0); if (be32_to_cpup((__be32 *)start) != OF_DT_END) pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) -- cgit v1.2.3 From 57d00ecf90cc9854973da2960012b734acc26e51 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:55:01 -0800 Subject: of/flattree: Reorder unflatten_dt_node Move unflatten_dt_node to be grouped with non-__init functions. Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 218 +++++++++++++++++++++++++++---------------------------- 1 file changed, 109 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index cf74e546faf2..71edc9cecd62 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -97,115 +97,6 @@ int of_fdt_is_compatible(struct boot_param_header *blob, return 0; } -/* Everything below here references initial_boot_params directly. */ -int __initdata dt_root_addr_cells; -int __initdata dt_root_size_cells; - -struct boot_param_header *initial_boot_params; - -#ifdef CONFIG_OF_EARLY_FLATTREE - -/** - * of_scan_flat_dt - scan flattened tree blob and call callback on each. - * @it: callback function - * @data: context data pointer - * - * This function is used to scan the flattened device-tree, it is - * used to extract the memory information at boot before we can - * unflatten the tree - */ -int __init of_scan_flat_dt(int (*it)(unsigned long node, - const char *uname, int depth, - void *data), - void *data) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - int rc = 0; - int depth = -1; - - do { - u32 tag = be32_to_cpup((__be32 *)p); - char *pathp; - - p += 4; - if (tag == OF_DT_END_NODE) { - depth--; - continue; - } - if (tag == OF_DT_NOP) - continue; - if (tag == OF_DT_END) - break; - if (tag == OF_DT_PROP) { - u32 sz = be32_to_cpup((__be32 *)p); - p += 8; - if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = ALIGN(p, sz >= 8 ? 8 : 4); - p += sz; - p = ALIGN(p, 4); - continue; - } - if (tag != OF_DT_BEGIN_NODE) { - pr_err("Invalid tag %x in flat device tree!\n", tag); - return -EINVAL; - } - depth++; - pathp = (char *)p; - p = ALIGN(p + strlen(pathp) + 1, 4); - if ((*pathp) == '/') { - char *lp, *np; - for (lp = NULL, np = pathp; *np; np++) - if ((*np) == '/') - lp = np+1; - if (lp != NULL) - pathp = lp; - } - rc = it(p, pathp, depth, data); - if (rc != 0) - break; - } while (1); - - return rc; -} - -/** - * of_get_flat_dt_root - find the root node in the flat blob - */ -unsigned long __init of_get_flat_dt_root(void) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - - while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) - p += 4; - BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); - p += 4; - return ALIGN(p + strlen((char *)p) + 1, 4); -} - -/** - * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr - * - * This function can be used within scan_flattened_dt callback to get - * access to properties - */ -void *__init of_get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size) -{ - return of_fdt_get_property(initial_boot_params, node, name, size); -} - -/** - * of_flat_dt_is_compatible - Return true if given node has compat in compatible list - * @node: node to test - * @compat: compatible string to compare with compatible list. - */ -int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) -{ - return of_fdt_is_compatible(initial_boot_params, node, compat); -} - static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { @@ -421,6 +312,115 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob, return mem; } +/* Everything below here references initial_boot_params directly. */ +int __initdata dt_root_addr_cells; +int __initdata dt_root_size_cells; + +struct boot_param_header *initial_boot_params; + +#ifdef CONFIG_OF_EARLY_FLATTREE + +/** + * of_scan_flat_dt - scan flattened tree blob and call callback on each. + * @it: callback function + * @data: context data pointer + * + * This function is used to scan the flattened device-tree, it is + * used to extract the memory information at boot before we can + * unflatten the tree + */ +int __init of_scan_flat_dt(int (*it)(unsigned long node, + const char *uname, int depth, + void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + be32_to_cpu(initial_boot_params->off_dt_struct); + int rc = 0; + int depth = -1; + + do { + u32 tag = be32_to_cpup((__be32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) { + depth--; + continue; + } + if (tag == OF_DT_NOP) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = be32_to_cpup((__be32 *)p); + p += 8; + if (be32_to_cpu(initial_boot_params->version) < 0x10) + p = ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + pr_err("Invalid tag %x in flat device tree!\n", tag); + return -EINVAL; + } + depth++; + pathp = (char *)p; + p = ALIGN(p + strlen(pathp) + 1, 4); + if ((*pathp) == '/') { + char *lp, *np; + for (lp = NULL, np = pathp; *np; np++) + if ((*np) == '/') + lp = np+1; + if (lp != NULL) + pathp = lp; + } + rc = it(p, pathp, depth, data); + if (rc != 0) + break; + } while (1); + + return rc; +} + +/** + * of_get_flat_dt_root - find the root node in the flat blob + */ +unsigned long __init of_get_flat_dt_root(void) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + be32_to_cpu(initial_boot_params->off_dt_struct); + + while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) + p += 4; + BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); + p += 4; + return ALIGN(p + strlen((char *)p) + 1, 4); +} + +/** + * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr + * + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +void *__init of_get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + return of_fdt_get_property(initial_boot_params, node, name, size); +} + +/** + * of_flat_dt_is_compatible - Return true if given node has compat in compatible list + * @node: node to test + * @compat: compatible string to compare with compatible list. + */ +int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) +{ + return of_fdt_is_compatible(initial_boot_params, node, compat); +} + #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree -- cgit v1.2.3 From fe14042358fac0673d4b6362a73796fd64379938 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Thu, 18 Nov 2010 15:55:02 -0800 Subject: of/flattree: Refactor unflatten_device_tree and add fdt_unflatten_tree unflatten_device_tree has two dependencies on things that happen during boot time. Firstly, it references the initial device tree directly. Secondly, it allocates memory using the early boot allocator. This patch factors out these dependencies and uses the new __unflatten_device_tree function to implement a driver-visible fdt_unflatten_tree function, which can be used to unflatten a blob after boot time. V2: - remove extra __va() call - make dt_alloc functions return void *. This doesn't fix the general strangeness in this code that constantly casts back and forth between unsigned long and __be32 * Signed-off-by: Stephen Neuendorffer Signed-off-by: Grant Likely --- drivers/of/fdt.c | 149 ++++++++++++++++++++++++++++++++----------------- include/linux/of_fdt.h | 2 + 2 files changed, 100 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 71edc9cecd62..8a90ee42071a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -11,10 +11,12 @@ #include #include +#include #include #include #include #include +#include #ifdef CONFIG_PPC #include @@ -312,6 +314,94 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob, return mem; } +/** + * __unflatten_device_tree - create tree of device_nodes from flat blob + * + * unflattens a device-tree, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + * @blob: The blob to expand + * @mynodes: The device_node tree created by the call + * @dt_alloc: An allocator that provides a virtual address to memory + * for the resulting tree + */ +void __unflatten_device_tree(struct boot_param_header *blob, + struct device_node **mynodes, + void * (*dt_alloc)(u64 size, u64 align)) +{ + unsigned long start, mem, size; + struct device_node **allnextp = mynodes; + + pr_debug(" -> unflatten_device_tree()\n"); + + if (!blob) { + pr_debug("No device tree pointer\n"); + return; + } + + pr_debug("Unflattening device tree:\n"); + pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); + pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); + pr_debug("version: %08x\n", be32_to_cpu(blob->version)); + + if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { + pr_err("Invalid device tree blob header\n"); + return; + } + + /* First pass, scan for size */ + start = ((unsigned long)blob) + + be32_to_cpu(blob->off_dt_struct); + size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); + size = (size | 3) + 1; + + pr_debug(" size is %lx, allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = (unsigned long) + dt_alloc(size + 4, __alignof__(struct device_node)); + + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); + + pr_debug(" unflattening %lx...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)blob) + + be32_to_cpu(blob->off_dt_struct); + unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); + if (be32_to_cpup((__be32 *)start) != OF_DT_END) + pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); + if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) + pr_warning("End of tree marker overwritten: %08x\n", + be32_to_cpu(((__be32 *)mem)[size / 4])); + *allnextp = NULL; + + pr_debug(" <- unflatten_device_tree()\n"); +} + +static void *kernel_tree_alloc(u64 size, u64 align) +{ + return kzalloc(size, GFP_KERNEL); +} + +/** + * of_fdt_unflatten_tree - create tree of device_nodes from flat blob + * + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + */ +void of_fdt_unflatten_tree(unsigned long *blob, + struct device_node **mynodes) +{ + struct boot_param_header *device_tree = + (struct boot_param_header *)blob; + __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); +} +EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); + /* Everything below here references initial_boot_params directly. */ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; @@ -569,6 +659,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, return 1; } +static void *__init early_device_tree_alloc(u64 size, u64 align) +{ + unsigned long mem = early_init_dt_alloc_memory_arch(size, align); + return __va(mem); +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -579,62 +675,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, */ void __init unflatten_device_tree(void) { - unsigned long start, mem, size; - struct device_node **allnextp = &allnodes; - - pr_debug(" -> unflatten_device_tree()\n"); - - if (!initial_boot_params) { - pr_debug("No device tree pointer\n"); - return; - } - - pr_debug("Unflattening device tree:\n"); - pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic)); - pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize)); - pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version)); - - if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { - pr_err("Invalid device tree blob header\n"); - return; - } - - /* First pass, scan for size */ - start = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - size = unflatten_dt_node(initial_boot_params, 0, &start, - NULL, NULL, 0); - size = (size | 3) + 1; - - pr_debug(" size is %lx, allocating...\n", size); - - /* Allocate memory for the expanded device tree */ - mem = early_init_dt_alloc_memory_arch(size + 4, - __alignof__(struct device_node)); - mem = (unsigned long) __va(mem); - - ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); - - pr_debug(" unflattening %lx...\n", mem); - - /* Second pass, do actual unflattening */ - start = ((unsigned long)initial_boot_params) + - be32_to_cpu(initial_boot_params->off_dt_struct); - unflatten_dt_node(initial_boot_params, mem, &start, - NULL, &allnextp, 0); - if (be32_to_cpup((__be32 *)start) != OF_DT_END) - pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); - if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) - pr_warning("End of tree marker overwritten: %08x\n", - be32_to_cpu(((__be32 *)mem)[size / 4])); - *allnextp = NULL; + __unflatten_device_tree(initial_boot_params, &allnodes, + early_device_tree_alloc); /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); - - pr_debug(" <- unflatten_device_tree()\n"); } #endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 70c5b736f0a3..9ce5dfd2186a 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -68,6 +68,8 @@ extern void *of_fdt_get_property(struct boot_param_header *blob, extern int of_fdt_is_compatible(struct boot_param_header *blob, unsigned long node, const char *compat); +extern void of_fdt_unflatten_tree(unsigned long *blob, + struct device_node **mynodes); /* TBD: Temporary export of fdt globals - remove when code fully merged */ extern int __initdata dt_root_addr_cells; -- cgit v1.2.3 From 73930a85cf38d72851305fcf640c07b4c13aa405 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 17 Nov 2010 17:50:23 -0600 Subject: of_serial: explicitly include of_irq.h On PPC, of_irq.h gets implicitly included, but on other platforms it does not. Signed-off-by: Rob Herring Signed-off-by: Grant Likely --- drivers/serial/of_serial.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 17849dcb9adc..5c7abe4c94dd 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From eae5e7f304222ee795936e9466110a9d5d5ec558 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 30 Dec 2010 11:40:07 +1000 Subject: drm/nvc0: parse a couple more PGRAPH_INTR Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_graph.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index c28bc7b04d27..8352d6b92cca 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -740,6 +740,14 @@ nvc0_graph_isr(struct drm_device *dev) stat &= ~0x00000010; } + if (stat & 0x00000020) { + NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d " + "class 0x%04x mthd 0x%04x data 0x%08x\n", + chid, inst, subc, class, mthd, data); + nv_wr32(dev, 0x400100, 0x00000020); + stat &= ~0x00000020; + } + if (stat & 0x00100000) { NV_INFO(dev, "PGRAPH: DATA_ERROR ["); nouveau_enum_print(nvc0_graph_data_error, code); @@ -750,6 +758,14 @@ nvc0_graph_isr(struct drm_device *dev) stat &= ~0x00100000; } + if (stat & 0x00200000) { + u32 trap = nv_rd32(dev, 0x400108); + NV_INFO(dev, "PGRAPH: TRAP ch %d status 0x%08x\n", chid, trap); + nv_wr32(dev, 0x400108, trap); + nv_wr32(dev, 0x400100, 0x00200000); + stat &= ~0x00200000; + } + if (stat & 0x00080000) { u32 ustat = nv_rd32(dev, 0x409c18); -- cgit v1.2.3 From 6effe39364f1212aa57e1b5f0bd0f388ebfe9b24 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 30 Dec 2010 11:48:03 +1000 Subject: drm/nv50: sync up gr data error names with rnn, use for nvc0 also Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nv50_graph.c | 49 ++++++++++++++++++++++++++++++----- drivers/gpu/drm/nouveau/nvc0_graph.c | 7 +---- 3 files changed, 44 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e81575687354..6d749b792088 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1189,6 +1189,7 @@ extern int nv50_graph_unload_context(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); extern void nv50_graph_tlb_flush(struct drm_device *dev); extern void nv86_graph_tlb_flush(struct drm_device *dev); +extern struct nouveau_enum nv50_data_error_names[]; /* nvc0_graph.c */ extern int nvc0_graph_init(struct drm_device *); diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index c510e74acf4d..2d7ea75a09d4 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -554,13 +554,48 @@ static struct nouveau_bitfield nv50_graph_trap_ccache[] = { }; /* There must be a *lot* of these. Will take some time to gather them up. */ -static struct nouveau_enum nv50_data_error_names[] = { - { 4, "INVALID_VALUE" }, - { 5, "INVALID_ENUM" }, - { 8, "INVALID_OBJECT" }, - { 0xc, "INVALID_BITFIELD" }, - { 0x28, "MP_NO_REG_SPACE" }, - { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, +struct nouveau_enum nv50_data_error_names[] = { + { 0x00000003, "INVALID_QUERY_OR_TEXTURE" }, + { 0x00000004, "INVALID_VALUE" }, + { 0x00000005, "INVALID_ENUM" }, + { 0x00000008, "INVALID_OBJECT" }, + { 0x00000009, "READ_ONLY_OBJECT" }, + { 0x0000000a, "SUPERVISOR_OBJECT" }, + { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT" }, + { 0x0000000c, "INVALID_BITFIELD" }, + { 0x0000000d, "BEGIN_END_ACTIVE" }, + { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT" }, + { 0x0000000f, "VIEWPORT_ID_NEEDS_GP" }, + { 0x00000010, "RT_DOUBLE_BIND" }, + { 0x00000011, "RT_TYPES_MISMATCH" }, + { 0x00000012, "RT_LINEAR_WITH_ZETA" }, + { 0x00000015, "FP_TOO_FEW_REGS" }, + { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH" }, + { 0x00000017, "RT_LINEAR_WITH_MSAA" }, + { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT" }, + { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT" }, + { 0x0000001a, "RT_INVALID_ALIGNMENT" }, + { 0x0000001b, "SAMPLER_OVER_LIMIT" }, + { 0x0000001c, "TEXTURE_OVER_LIMIT" }, + { 0x0000001e, "GP_TOO_MANY_OUTPUTS" }, + { 0x0000001f, "RT_BPP128_WITH_MS8" }, + { 0x00000021, "Z_OUT_OF_BOUNDS" }, + { 0x00000023, "XY_OUT_OF_BOUNDS" }, + { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED" }, + { 0x00000028, "CP_NO_REG_SPACE_STRIPED" }, + { 0x00000029, "CP_NO_REG_SPACE_PACKED" }, + { 0x0000002a, "CP_NOT_ENOUGH_WARPS" }, + { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH" }, + { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS" }, + { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS" }, + { 0x0000002e, "CP_NO_BLOCKDIM_LATCH" }, + { 0x00000031, "ENG2D_FORMAT_MISMATCH" }, + { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP" }, + { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT" }, + { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT" }, + { 0x00000046, "LAYER_ID_NEEDS_GP" }, + { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT" }, + { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT" }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 8352d6b92cca..43b44a4b3ab8 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -693,11 +693,6 @@ nvc0_graph_init(struct drm_device *dev) return 0; } -static struct nouveau_enum nvc0_graph_data_error[] = { - { 5, "INVALID_ENUM" }, - {} -}; - static int nvc0_graph_isr_chid(struct drm_device *dev, u64 inst) { @@ -750,7 +745,7 @@ nvc0_graph_isr(struct drm_device *dev) if (stat & 0x00100000) { NV_INFO(dev, "PGRAPH: DATA_ERROR ["); - nouveau_enum_print(nvc0_graph_data_error, code); + nouveau_enum_print(nv50_data_error_names, code); printk("] ch %d [0x%010llx] subc %d class 0x%04x " "mthd 0x%04x data 0x%08x\n", chid, inst, subc, class, mthd, data); -- cgit v1.2.3 From 2a55c9a7ff2a863f05a9b9c8519ef81737d4a3ef Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 30 Dec 2010 11:53:48 +1000 Subject: drm/nvc0: reserve only subc 0 for kernel use Current 3D driver expects this behaviour. While this could be changed, there's no compelling reason to reserve more than one subchannel for the DRM. If we ever need to use an object other then M2MF, we can just re-bind subchannel 0 as required. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 22 ++++++++++++++-------- drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 4d2f19420922..a57a1d2f3a11 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -446,14 +446,20 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, else init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - init->subchan[0].handle = NvM2MF; - if (dev_priv->card_type < NV_50) - init->subchan[0].grclass = 0x0039; - else - init->subchan[0].grclass = 0x5039; - init->subchan[1].handle = NvSw; - init->subchan[1].grclass = NV_SW; - init->nr_subchan = 2; + if (dev_priv->card_type < NV_C0) { + init->subchan[0].handle = NvM2MF; + if (dev_priv->card_type < NV_50) + init->subchan[0].grclass = 0x0039; + else + init->subchan[0].grclass = 0x5039; + init->subchan[1].handle = NvSw; + init->subchan[1].grclass = NV_SW; + init->nr_subchan = 2; + } else { + init->subchan[0].handle = 0x9039; + init->subchan[0].grclass = 0x9039; + init->nr_subchan = 1; + } /* Named memory object area */ ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 88b2f29ca3e4..221b8462ea37 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -165,7 +165,7 @@ nouveau_fence_emit(struct nouveau_fence *fence) if (dev_priv->card_type < NV_C0) BEGIN_RING(chan, NvSubSw, 0x0050, 1); else - BEGIN_NVC0(chan, 2, NvSubSw, 0x0050, 1); + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0050, 1); } else { BEGIN_RING(chan, NvSubSw, 0x0150, 1); } -- cgit v1.2.3 From 6504cf3412373f42b53a675363c056901c1596cf Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 27 Oct 2010 01:52:55 +0200 Subject: powerpc/512x: scatter/gather dma fix While testing mpc512x-dma driver with dmatest module I've found that I can hang the mpc512x-dma issuing request from multiple threads to the single channel. insmod dmatest.ko max_channels=1 threads_per_chan=16 After investigating this case I've managed to find that this happens if and only if we have more than one queued requests. In this case the driver tries to make use of hardware scatter/gather functionality. I've found two problems with scatter/gather: 1. When TCD is copied form RAM to the TCD register space with memcpy_io() e_sg bit eventually gets cleared. This results in only first TCD being executed. I've added setting of e_sg bit explicitly in the TCD registers. BTW, what is the correct way to do this? (How can I use setbits with bitfield structure?) After that hardware loads consecutive TCDs and we hit the second issue. 2. Existing code clears int_maj bit in the last TCD so we never get an interrupt on transfer completion. With these fixes my tests with many threads of single channel succeed but tests that use many channels simultaneously still don't work reliable. Signed-off-by: Ilya Yanok Acked-by: Wolfgang Denk Signed-off-by: Grant Likely --- drivers/dma/mpc512x_dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 4e9cbf300594..1bc04aa27b14 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -252,11 +252,13 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan) prev = mdesc; } - prev->tcd->start = 0; prev->tcd->int_maj = 1; /* Send first descriptor in chain into hardware */ memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd)); + + if (first != prev) + mdma->tcd[cid].e_sg = 1; out_8(&mdma->regs->dmassrt, cid); } -- cgit v1.2.3 From 2862559e8a1e7c47bb3003f0edbc9db9009dc32b Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 27 Oct 2010 01:52:56 +0200 Subject: powerpc/512x: fix the hanged dma transfer issue Current code clears interrupt active status _after_ submitting new transfers. This leaves a possibility of clearing the interrupt for this new transfer (if it is triggered fast enough) and thus lose this interrupt. We want to clear interrupt active status _before_ new transfers is submitted and for current channel only. Signed-off-by: Ilya Yanok Acked-by: Wolfgang Denk Signed-off-by: Grant Likely --- drivers/dma/mpc512x_dma.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 1bc04aa27b14..071752727718 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -276,6 +276,9 @@ static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, int off) spin_lock(&mchan->lock); + out_8(&mdma->regs->dmacint, ch + off); + out_8(&mdma->regs->dmacerr, ch + off); + /* Check error status */ if (es & (1 << ch)) list_for_each_entry(mdesc, &mchan->active, node) @@ -309,12 +312,6 @@ static irqreturn_t mpc_dma_irq(int irq, void *data) mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl), in_be32(&mdma->regs->dmaerrl), 0); - /* Ack interrupt on all channels */ - out_be32(&mdma->regs->dmainth, 0xFFFFFFFF); - out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF); - out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF); - out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF); - /* Schedule tasklet */ tasklet_schedule(&mdma->tasklet); -- cgit v1.2.3 From ba2eea251f815b3674cde13ecdba4772332bf56e Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 27 Oct 2010 01:52:57 +0200 Subject: powerpc/512x: add MPC8308 dma support MPC8308 has pretty much the same DMA controller as MPC5121 and this patch adds support for MPC8308 to the mpc512x_dma driver. Signed-off-by: Ilya Yanok Acked-by: Wolfgang Denk Signed-off-by: Grant Likely --- drivers/dma/Kconfig | 2 +- drivers/dma/mpc512x_dma.c | 95 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 72 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 6ee23592700a..ef138731c0ea 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -109,7 +109,7 @@ config FSL_DMA config MPC512X_DMA tristate "Freescale MPC512x built-in DMA engine support" - depends on PPC_MPC512x + depends on PPC_MPC512x || PPC_MPC831x select DMA_ENGINE ---help--- Enable support for the Freescale MPC512x built-in DMA engine. diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 071752727718..97b92ecb1427 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -1,6 +1,7 @@ /* * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008. * Copyright (C) Semihalf 2009 + * Copyright (C) Ilya Yanok, Emcraft Systems 2010 * * Written by Piotr Ziecik . Hardware description * (defines, structures and comments) was taken from MPC5121 DMA driver @@ -70,6 +71,8 @@ #define MPC_DMA_DMAES_SBE (1 << 1) #define MPC_DMA_DMAES_DBE (1 << 0) +#define MPC_DMA_DMAGPOR_SNOOP_ENABLE (1 << 6) + #define MPC_DMA_TSIZE_1 0x00 #define MPC_DMA_TSIZE_2 0x01 #define MPC_DMA_TSIZE_4 0x02 @@ -104,7 +107,10 @@ struct __attribute__ ((__packed__)) mpc_dma_regs { /* 0x30 */ u32 dmahrsh; /* DMA hw request status high(ch63~32) */ u32 dmahrsl; /* DMA hardware request status low(ch31~0) */ - u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */ + union { + u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */ + u32 dmagpor; /* (General purpose register on MPC8308) */ + }; u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */ /* 0x40 ~ 0xff */ u32 reserve0[48]; /* Reserved */ @@ -195,7 +201,9 @@ struct mpc_dma { struct mpc_dma_regs __iomem *regs; struct mpc_dma_tcd __iomem *tcd; int irq; + int irq2; uint error_status; + int is_mpc8308; /* Lock for error_status field in this structure */ spinlock_t error_status_lock; @@ -307,8 +315,10 @@ static irqreturn_t mpc_dma_irq(int irq, void *data) spin_unlock(&mdma->error_status_lock); /* Handle interrupt on each channel */ - mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth), + if (mdma->dma.chancnt > 32) { + mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth), in_be32(&mdma->regs->dmaerrh), 32); + } mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl), in_be32(&mdma->regs->dmaerrl), 0); @@ -562,6 +572,7 @@ static struct dma_async_tx_descriptor * mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) { + struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan); struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan); struct mpc_dma_desc *mdesc = NULL; struct mpc_dma_tcd *tcd; @@ -590,7 +601,8 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, tcd->dsize = MPC_DMA_TSIZE_32; tcd->soff = 32; tcd->doff = 32; - } else if (IS_ALIGNED(src | dst | len, 16)) { + } else if (!mdma->is_mpc8308 && IS_ALIGNED(src | dst | len, 16)) { + /* MPC8308 doesn't support 16 byte transfers */ tcd->ssize = MPC_DMA_TSIZE_16; tcd->dsize = MPC_DMA_TSIZE_16; tcd->soff = 16; @@ -650,6 +662,15 @@ static int __devinit mpc_dma_probe(struct platform_device *op, return -EINVAL; } + if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) { + mdma->is_mpc8308 = 1; + mdma->irq2 = irq_of_parse_and_map(dn, 1); + if (mdma->irq2 == NO_IRQ) { + dev_err(dev, "Error mapping IRQ!\n"); + return -EINVAL; + } + } + retval = of_address_to_resource(dn, 0, &res); if (retval) { dev_err(dev, "Error parsing memory region!\n"); @@ -680,11 +701,23 @@ static int __devinit mpc_dma_probe(struct platform_device *op, return -EINVAL; } + if (mdma->is_mpc8308) { + retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0, + DRV_NAME, mdma); + if (retval) { + dev_err(dev, "Error requesting IRQ2!\n"); + return -EINVAL; + } + } + spin_lock_init(&mdma->error_status_lock); dma = &mdma->dma; dma->dev = dev; - dma->chancnt = MPC_DMA_CHANNELS; + if (!mdma->is_mpc8308) + dma->chancnt = MPC_DMA_CHANNELS; + else + dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */ dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources; dma->device_free_chan_resources = mpc_dma_free_chan_resources; dma->device_issue_pending = mpc_dma_issue_pending; @@ -720,26 +753,40 @@ static int __devinit mpc_dma_probe(struct platform_device *op, * - Round-robin group arbitration, * - Round-robin channel arbitration. */ - out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG | - MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA); - - /* Disable hardware DMA requests */ - out_be32(&mdma->regs->dmaerqh, 0); - out_be32(&mdma->regs->dmaerql, 0); - - /* Disable error interrupts */ - out_be32(&mdma->regs->dmaeeih, 0); - out_be32(&mdma->regs->dmaeeil, 0); - - /* Clear interrupts status */ - out_be32(&mdma->regs->dmainth, 0xFFFFFFFF); - out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF); - out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF); - out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF); - - /* Route interrupts to IPIC */ - out_be32(&mdma->regs->dmaihsa, 0); - out_be32(&mdma->regs->dmailsa, 0); + if (!mdma->is_mpc8308) { + out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG | + MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA); + + /* Disable hardware DMA requests */ + out_be32(&mdma->regs->dmaerqh, 0); + out_be32(&mdma->regs->dmaerql, 0); + + /* Disable error interrupts */ + out_be32(&mdma->regs->dmaeeih, 0); + out_be32(&mdma->regs->dmaeeil, 0); + + /* Clear interrupts status */ + out_be32(&mdma->regs->dmainth, 0xFFFFFFFF); + out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF); + out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF); + out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF); + + /* Route interrupts to IPIC */ + out_be32(&mdma->regs->dmaihsa, 0); + out_be32(&mdma->regs->dmailsa, 0); + } else { + /* MPC8308 has 16 channels and lacks some registers */ + out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA); + + /* enable snooping */ + out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE); + /* Disable error interrupts */ + out_be32(&mdma->regs->dmaeeil, 0); + + /* Clear interrupts status */ + out_be32(&mdma->regs->dmaintl, 0xFFFF); + out_be32(&mdma->regs->dmaerrl, 0xFFFF); + } /* Register DMA engine */ dev_set_drvdata(dev, mdma); -- cgit v1.2.3 From a276991357c63bfb8d3ffdf5800054dba4f8d558 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Wed, 27 Oct 2010 01:52:58 +0200 Subject: powerpc/512x: try to free dma descriptors in case of allocation failure Currently completed descriptors are processed in the tasklet. This can lead to dead lock in case of CONFIG_NET_DMA enabled (new requests are submitted from softirq context and dma_memcpy_to_iovec() busy loops until the requests is submitted). To prevent this we should process completed descriptors from the allocation failure path in prepare_memcpy too. Signed-off-by: Ilya Yanok Cc: Piotr Ziecik Signed-off-by: Grant Likely --- drivers/dma/mpc512x_dma.c | 79 +++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 97b92ecb1427..59c270192ccc 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -328,19 +328,55 @@ static irqreturn_t mpc_dma_irq(int irq, void *data) return IRQ_HANDLED; } -/* DMA Tasklet */ -static void mpc_dma_tasklet(unsigned long data) +/* proccess completed descriptors */ +static void mpc_dma_process_completed(struct mpc_dma *mdma) { - struct mpc_dma *mdma = (void *)data; dma_cookie_t last_cookie = 0; struct mpc_dma_chan *mchan; struct mpc_dma_desc *mdesc; struct dma_async_tx_descriptor *desc; unsigned long flags; LIST_HEAD(list); - uint es; int i; + for (i = 0; i < mdma->dma.chancnt; i++) { + mchan = &mdma->channels[i]; + + /* Get all completed descriptors */ + spin_lock_irqsave(&mchan->lock, flags); + if (!list_empty(&mchan->completed)) + list_splice_tail_init(&mchan->completed, &list); + spin_unlock_irqrestore(&mchan->lock, flags); + + if (list_empty(&list)) + continue; + + /* Execute callbacks and run dependencies */ + list_for_each_entry(mdesc, &list, node) { + desc = &mdesc->desc; + + if (desc->callback) + desc->callback(desc->callback_param); + + last_cookie = desc->cookie; + dma_run_dependencies(desc); + } + + /* Free descriptors */ + spin_lock_irqsave(&mchan->lock, flags); + list_splice_tail_init(&list, &mchan->free); + mchan->completed_cookie = last_cookie; + spin_unlock_irqrestore(&mchan->lock, flags); + } +} + +/* DMA Tasklet */ +static void mpc_dma_tasklet(unsigned long data) +{ + struct mpc_dma *mdma = (void *)data; + unsigned long flags; + uint es; + spin_lock_irqsave(&mdma->error_status_lock, flags); es = mdma->error_status; mdma->error_status = 0; @@ -379,35 +415,7 @@ static void mpc_dma_tasklet(unsigned long data) dev_err(mdma->dma.dev, "- Destination Bus Error\n"); } - for (i = 0; i < mdma->dma.chancnt; i++) { - mchan = &mdma->channels[i]; - - /* Get all completed descriptors */ - spin_lock_irqsave(&mchan->lock, flags); - if (!list_empty(&mchan->completed)) - list_splice_tail_init(&mchan->completed, &list); - spin_unlock_irqrestore(&mchan->lock, flags); - - if (list_empty(&list)) - continue; - - /* Execute callbacks and run dependencies */ - list_for_each_entry(mdesc, &list, node) { - desc = &mdesc->desc; - - if (desc->callback) - desc->callback(desc->callback_param); - - last_cookie = desc->cookie; - dma_run_dependencies(desc); - } - - /* Free descriptors */ - spin_lock_irqsave(&mchan->lock, flags); - list_splice_tail_init(&list, &mchan->free); - mchan->completed_cookie = last_cookie; - spin_unlock_irqrestore(&mchan->lock, flags); - } + mpc_dma_process_completed(mdma); } /* Submit descriptor to hardware */ @@ -587,8 +595,11 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, } spin_unlock_irqrestore(&mchan->lock, iflags); - if (!mdesc) + if (!mdesc) { + /* try to free completed descriptors */ + mpc_dma_process_completed(mdma); return NULL; + } mdesc->error = 0; tcd = mdesc->tcd; -- cgit v1.2.3 From ec9c0883ea3aa90d6c6d6b16a64d0986f40baff0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 31 Dec 2010 12:10:49 +1000 Subject: drm/nvc0/pfifo: support for chipsets with only one PSUBFIFO (0xc1) Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_fifo.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c index 82a4ded5dae8..e6f92c541dba 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fifo.c +++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c @@ -33,6 +33,7 @@ struct nvc0_fifo_priv { struct nouveau_gpuobj *playlist[2]; int cur_playlist; struct nouveau_vma user_vma; + int spoon_nr; }; struct nvc0_fifo_chan { @@ -324,13 +325,18 @@ nvc0_fifo_init(struct drm_device *dev) nv_wr32(dev, 0x000204, 0xffffffff); nv_wr32(dev, 0x002204, 0xffffffff); + priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204)); + NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr); + /* assign engines to subfifos */ - nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */ - nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */ - nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */ - nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */ - nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */ - nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */ + if (priv->spoon_nr >= 3) { + nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */ + nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */ + nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */ + nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */ + nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */ + nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */ + } /* PSUBFIFO[n] */ for (i = 0; i < 3; i++) { -- cgit v1.2.3 From 680a48720f55d2f21cbf45c1f7ca38d6b73471dc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 31 Dec 2010 12:21:56 +1000 Subject: drm/nvc0/pgraph: more unit names Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_grctx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c index fddfab73a58d..a45cdc494502 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grctx.c +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -1557,7 +1557,7 @@ nvc0_grctx_generate_unk47xx(struct drm_device *dev) } static void -nvc0_grctx_generate_unk58xx(struct drm_device *dev) +nvc0_grctx_generate_shaders(struct drm_device *dev) { nv_wr32(dev, 0x405800, 0x078000bf); nv_wr32(dev, 0x405830, 0x02180000); @@ -1593,7 +1593,7 @@ nvc0_grctx_generate_unk64xx(struct drm_device *dev) } static void -nvc0_grctx_generate_unk78xx(struct drm_device *dev) +nvc0_grctx_generate_tpbus(struct drm_device *dev) { nv_wr32(dev, 0x407804, 0x00000023); nv_wr32(dev, 0x40780c, 0x0a418820); @@ -1606,7 +1606,7 @@ nvc0_grctx_generate_unk78xx(struct drm_device *dev) } static void -nvc0_grctx_generate_unk80xx(struct drm_device *dev) +nvc0_grctx_generate_ccache(struct drm_device *dev) { nv_wr32(dev, 0x408000, 0x00000000); nv_wr32(dev, 0x408004, 0x00000000); @@ -1811,11 +1811,11 @@ nvc0_grctx_generate(struct nouveau_channel *chan) nvc0_grctx_generate_macro(dev); nvc0_grctx_generate_m2mf(dev); nvc0_grctx_generate_unk47xx(dev); - nvc0_grctx_generate_unk58xx(dev); + nvc0_grctx_generate_shaders(dev); nvc0_grctx_generate_unk60xx(dev); nvc0_grctx_generate_unk64xx(dev); - nvc0_grctx_generate_unk78xx(dev); - nvc0_grctx_generate_unk80xx(dev); + nvc0_grctx_generate_tpbus(dev); + nvc0_grctx_generate_ccache(dev); nvc0_grctx_generate_rop(dev); nvc0_grctx_generate_gpc(dev); nvc0_grctx_generate_tp(dev); -- cgit v1.2.3 From 47a44d27ca246b815de2b4223daf86070315fb8d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 1 Jan 2011 12:26:23 +1000 Subject: drm/nvc0/pgraph: fix 0x406028/0x405870 init Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_grctx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c index a45cdc494502..b9e68b2d30aa 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grctx.c +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -1801,7 +1801,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) struct nvc0_graph_chan *grch = chan->pgraph_ctx; struct drm_device *dev = chan->dev; int i, gpc, tp, id; - u32 r000260; + u32 r000260, tmp; r000260 = nv_rd32(dev, 0x000260); nv_wr32(dev, 0x000260, r000260 & ~1); @@ -1843,8 +1843,12 @@ nvc0_grctx_generate(struct nouveau_channel *chan) } } - nv_wr32(dev, 0x406028, 0x00000443); - nv_wr32(dev, 0x405870, 0x00000443); + tmp = 0; + for (i = 0; i < priv->gpc_nr; i++) + tmp |= priv->tp_nr[i] << (i * 4); + nv_wr32(dev, 0x406028, tmp); + nv_wr32(dev, 0x405870, tmp); + nv_wr32(dev, 0x40602c, 0x00000000); nv_wr32(dev, 0x405874, 0x00000000); nv_wr32(dev, 0x406030, 0x00000000); -- cgit v1.2.3 From a4f740cf33f7f6c164bbde3c0cdbcc77b0c4997c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 30 Oct 2010 11:49:09 -0400 Subject: of/flattree: Add of_flat_dt_match() helper function This patch adds of_flat_dt_match() which tests a node for compatibility with a list of values and converts the relevant powerpc platform code to use it. This approach simplifies the board support code a bit. Signed-off-by: Grant Likely Reviewed-by: Stephen Neuendorffer --- arch/powerpc/platforms/40x/ppc40x_simple.c | 13 +++------- arch/powerpc/platforms/512x/mpc5121_generic.c | 13 ++-------- arch/powerpc/platforms/52xx/lite5200.c | 16 +++++------- arch/powerpc/platforms/52xx/media5200.c | 13 ++-------- arch/powerpc/platforms/52xx/mpc5200_simple.c | 13 ++-------- arch/powerpc/platforms/83xx/mpc830x_rdb.c | 13 ++++++---- arch/powerpc/platforms/83xx/mpc831x_rdb.c | 11 +++++--- arch/powerpc/platforms/83xx/mpc837x_rdb.c | 15 ++++++----- arch/powerpc/platforms/85xx/tqm85xx.c | 20 +++++++-------- drivers/of/fdt.c | 37 +++++++++++++++++++++++++-- include/linux/of_fdt.h | 3 +++ 11 files changed, 89 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index 546bbc229d19..2521d93ef136 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -50,7 +50,7 @@ machine_device_initcall(ppc40x_simple, ppc40x_device_probe); * Again, if your board needs to do things differently then create a * board.c file for it rather than adding it to this list. */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "amcc,acadia", "amcc,haleakala", "amcc,kilauea", @@ -60,14 +60,9 @@ static char *board[] __initdata = { static int __init ppc40x_probe(void) { - unsigned long root = of_get_flat_dt_root(); - int i = 0; - - for (i = 0; i < ARRAY_SIZE(board); i++) { - if (of_flat_dt_is_compatible(root, board[i])) { - ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); - return 1; - } + if (of_flat_dt_match(of_get_flat_dt_root(), board)) { + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC); + return 1; } return 0; diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c index e487eb06ec6b..926731f1ff01 100644 --- a/arch/powerpc/platforms/512x/mpc5121_generic.c +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c @@ -26,7 +26,7 @@ /* * list of supported boards */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "prt,prtlvt", NULL }; @@ -36,16 +36,7 @@ static char *board[] __initdata = { */ static int __init mpc5121_generic_probe(void) { - unsigned long node = of_get_flat_dt_root(); - int i = 0; - - while (board[i]) { - if (of_flat_dt_is_compatible(node, board[i])) - break; - i++; - } - - return board[i] != NULL; + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(mpc5121_generic) { diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index de55bc0584b5..01ffa64d2aa7 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -172,20 +172,18 @@ static void __init lite5200_setup_arch(void) mpc52xx_setup_pci(); } +static const char *board[] __initdata = { + "fsl,lite5200", + "fsl,lite5200b", + NULL, +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init lite5200_probe(void) { - unsigned long node = of_get_flat_dt_root(); - const char *model = of_get_flat_dt_prop(node, "model", NULL); - - if (!of_flat_dt_is_compatible(node, "fsl,lite5200") && - !of_flat_dt_is_compatible(node, "fsl,lite5200b")) - return 0; - pr_debug("%s board found\n", model ? model : "unknown"); - - return 1; + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(lite5200) { diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 0bac3a3dbecf..2c7780cb68e5 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -239,7 +239,7 @@ static void __init media5200_setup_arch(void) } /* list of the supported boards */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "fsl,media5200", NULL }; @@ -249,16 +249,7 @@ static char *board[] __initdata = { */ static int __init media5200_probe(void) { - unsigned long node = of_get_flat_dt_root(); - int i = 0; - - while (board[i]) { - if (of_flat_dt_is_compatible(node, board[i])) - break; - i++; - } - - return (board[i] != NULL); + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(media5200_platform) { diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index d45be5b5ad49..e36d6e232ae6 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -49,7 +49,7 @@ static void __init mpc5200_simple_setup_arch(void) } /* list of the supported boards */ -static char *board[] __initdata = { +static const char *board[] __initdata = { "intercontrol,digsy-mtc", "manroland,mucmc52", "manroland,uc101", @@ -66,16 +66,7 @@ static char *board[] __initdata = { */ static int __init mpc5200_simple_probe(void) { - unsigned long node = of_get_flat_dt_root(); - int i = 0; - - while (board[i]) { - if (of_flat_dt_is_compatible(node, board[i])) - break; - i++; - } - - return (board[i] != NULL); + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(mpc5200_simple_platform) { diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index 846831d495b5..661d354e4ff2 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -57,16 +57,19 @@ static void __init mpc830x_rdb_init_IRQ(void) ipic_set_default_priority(); } +struct const char *board[] __initdata = { + "MPC8308RDB", + "fsl,mpc8308rdb", + "denx,mpc8308_p1m", + NULL +} + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init mpc830x_rdb_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "MPC8308RDB") || - of_flat_dt_is_compatible(root, "fsl,mpc8308rdb") || - of_flat_dt_is_compatible(root, "denx,mpc8308_p1m"); + return of_flat_dt_match(of_get_flat_dt_root(), board); } static struct of_device_id __initdata of_bus_ids[] = { diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index ae525e4745d2..b54cd736a895 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -60,15 +60,18 @@ static void __init mpc831x_rdb_init_IRQ(void) ipic_set_default_priority(); } +struct const char *board[] __initdata = { + "MPC8313ERDB", + "fsl,mpc8315erdb", + NULL +} + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init mpc831x_rdb_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "MPC8313ERDB") || - of_flat_dt_is_compatible(root, "fsl,mpc8315erdb"); + return of_flat_dt_match(of_get_flat_dt_root(), board); } static struct of_device_id __initdata of_bus_ids[] = { diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 910caa6b5810..7bafbf2ec0f9 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -101,17 +101,20 @@ static void __init mpc837x_rdb_init_IRQ(void) ipic_set_default_priority(); } +static const char *board[] __initdata = { + "fsl,mpc8377rdb", + "fsl,mpc8378rdb", + "fsl,mpc8379rdb", + "fsl,mpc8377wlan", + NULL +}; + /* * Called very early, MMU is off, device-tree isn't unflattened */ static int __init mpc837x_rdb_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "fsl,mpc8377rdb") || - of_flat_dt_is_compatible(root, "fsl,mpc8378rdb") || - of_flat_dt_is_compatible(root, "fsl,mpc8379rdb") || - of_flat_dt_is_compatible(root, "fsl,mpc8377wlan"); + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(mpc837x_rdb) { diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 8f29bbce5360..5e847d0b47c8 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -186,21 +186,21 @@ static int __init declare_of_platform_devices(void) } machine_device_initcall(tqm85xx, declare_of_platform_devices); +static const char *board[] __initdata = { + "tqc,tqm8540", + "tqc,tqm8541", + "tqc,tqm8548", + "tqc,tqm8555", + "tqc,tqm8560", + NULL +}; + /* * Called very early, device-tree isn't unflattened */ static int __init tqm85xx_probe(void) { - unsigned long root = of_get_flat_dt_root(); - - if ((of_flat_dt_is_compatible(root, "tqc,tqm8540")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8541")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8548")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8555")) || - (of_flat_dt_is_compatible(root, "tqc,tqm8560"))) - return 1; - - return 0; + return of_flat_dt_match(of_get_flat_dt_root(), board); } define_machine(tqm85xx) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 8a90ee42071a..c787c3d95c60 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -78,19 +78,23 @@ void *of_fdt_get_property(struct boot_param_header *blob, * @blob: A device tree blob * @node: node to test * @compat: compatible string to compare with compatible list. + * + * On match, returns a non-zero value with smaller values returned for more + * specific compatible values. */ int of_fdt_is_compatible(struct boot_param_header *blob, unsigned long node, const char *compat) { const char *cp; - unsigned long cplen, l; + unsigned long cplen, l, score = 0; cp = of_fdt_get_property(blob, node, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { + score++; if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; + return score; l = strlen(cp) + 1; cp += l; cplen -= l; @@ -99,6 +103,27 @@ int of_fdt_is_compatible(struct boot_param_header *blob, return 0; } +/** + * of_fdt_match - Return true if node matches a list of compatible values + */ +int of_fdt_match(struct boot_param_header *blob, unsigned long node, + const char **compat) +{ + unsigned int tmp, score = 0; + + if (!compat) + return 0; + + while (*compat) { + tmp = of_fdt_is_compatible(blob, node, *compat); + if (tmp && (score == 0 || (tmp < score))) + score = tmp; + compat++; + } + + return score; +} + static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { @@ -511,6 +536,14 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) return of_fdt_is_compatible(initial_boot_params, node, compat); } +/** + * of_flat_dt_match - Return true if node matches a list of compatible values + */ +int __init of_flat_dt_match(unsigned long node, const char **compat) +{ + return of_fdt_match(initial_boot_params, node, compat); +} + #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 9ce5dfd2186a..ee96091f7d25 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -68,6 +68,8 @@ extern void *of_fdt_get_property(struct boot_param_header *blob, extern int of_fdt_is_compatible(struct boot_param_header *blob, unsigned long node, const char *compat); +extern int of_fdt_match(struct boot_param_header *blob, unsigned long node, + const char **compat); extern void of_fdt_unflatten_tree(unsigned long *blob, struct device_node **mynodes); @@ -84,6 +86,7 @@ extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, extern void *of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); +extern int of_flat_dt_match(unsigned long node, const char **matches); extern unsigned long of_get_flat_dt_root(void); extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, -- cgit v1.2.3 From 0fbf8ed976af5bb43cf9cf2492161eb9688fee0c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 2 Jan 2011 22:17:00 +0100 Subject: HID: hid-picolcd: Fix memory leak in picolcd_debug_out_report() We have a memory leak in drivers/hid/hid-picolcd.c::picolcd_debug_out_report() in an error path.. We are not always freeing the memory allocated to 'buff' - this patch makes sure we always kfree() what we allocate with kmalloc() when it is no longer needed. Signed-off-by: Jesper Juhl Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 0aff3cdddd83..abd0bdc84624 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -1867,6 +1867,7 @@ static void picolcd_debug_out_report(struct picolcd_data *data, report->id, raw_size); hid_debug_event(hdev, buff); if (raw_size + 5 > sizeof(raw_data)) { + kfree(buff); hid_debug_event(hdev, " TOO BIG\n"); return; } else { -- cgit v1.2.3 From e8a8b252fb37489f881957ab0f2f8ea9a2341dd1 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 2 Jan 2011 15:12:42 +0100 Subject: Fix spelling mistakes in comments milisecond -> millisecond meassge -> message Cc: Kalle Valo Cc: Jiri Kosina Cc: linux-kernel@vger.kernel.org Signed-off-by: Stefan Weil Signed-off-by: Jiri Kosina --- arch/arm/mach-bcmring/include/csp/tmrHw.h | 4 ++-- drivers/acpi/apei/einj.c | 2 +- drivers/acpi/apei/erst.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bios.c | 4 ++-- drivers/net/wireless/wl1251/acx.h | 4 ++-- drivers/net/wireless/wl1251/wl1251.h | 2 +- drivers/net/wireless/wl12xx/wl1271.h | 4 ++-- drivers/net/wireless/wl12xx/wl1271_acx.h | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-bcmring/include/csp/tmrHw.h b/arch/arm/mach-bcmring/include/csp/tmrHw.h index f1236d00cb97..2cbb530db8ea 100644 --- a/arch/arm/mach-bcmring/include/csp/tmrHw.h +++ b/arch/arm/mach-bcmring/include/csp/tmrHw.h @@ -76,7 +76,7 @@ tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId, /* [ IN ] Timer Id * certain time interval * * This function initializes a periodic timer to generate timer interrupt -* after every time interval in milisecond +* after every time interval in millisecond * * @return On success: Effective interval set in mili-second * On failure: 0 @@ -93,7 +93,7 @@ tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId, /* [ IN ] T * after certain time interval * * This function initializes a periodic timer to generate a single ticks after -* certain time interval in milisecond +* certain time interval in millisecond * * @return On success: Effective interval set in mili-second * On failure: 0 diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index cf29df69380b..096aebfe7f32 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -39,7 +39,7 @@ #define EINJ_PFX "EINJ: " #define SPIN_UNIT 100 /* 100ns */ -/* Firmware should respond within 1 miliseconds */ +/* Firmware should respond within 1 milliseconds */ #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) /* diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 5850d320404c..cf6db6b7662a 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -53,7 +53,7 @@ sizeof(struct acpi_table_erst))) #define SPIN_UNIT 100 /* 100ns */ -/* Firmware should respond within 1 miliseconds */ +/* Firmware should respond within 1 milliseconds */ #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) #define FIRMWARE_MAX_STALL 50 /* 50us */ diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b2293576f278..73c2dab0cba6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1927,7 +1927,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * offset (8 bit): opcode * offset + 1 (16 bit): time * - * Sleep for "time" miliseconds. + * Sleep for "time" milliseconds. */ unsigned time = ROM16(bios->data[offset + 1]); @@ -1935,7 +1935,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) if (!iexec->execute) return 3; - BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n", + BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n", offset, time); msleep(time); diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h index e54b21a4f8b1..efcc3aaca14f 100644 --- a/drivers/net/wireless/wl1251/acx.h +++ b/drivers/net/wireless/wl1251/acx.h @@ -1272,10 +1272,10 @@ struct wl1251_acx_tid_cfg { /* OBSOLETE */ #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) -/* Trace meassge on MBOX #A */ +/* Trace message on MBOX #A */ #define WL1251_ACX_INTR_TRACE_A BIT(7) -/* Trace meassge on MBOX #B */ +/* Trace message on MBOX #B */ #define WL1251_ACX_INTR_TRACE_B BIT(8) /* Command processing completion */ diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index e113d4c1fb35..47d2653baccd 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -418,7 +418,7 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_FW_NAME "wl1251-fw.bin" #define WL1251_NVS_NAME "wl1251-nvs.bin" -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ +#define WL1251_POWER_ON_SLEEP 10 /* in milliseconds */ #define WL1251_PART_DOWN_MEM_START 0x0 #define WL1251_PART_DOWN_MEM_SIZE 0x16800 diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 8a4cd763e5a2..046acb816d2f 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -506,7 +506,7 @@ int wl1271_plt_stop(struct wl1271 *wl); /* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power on in case is has been shut down shortly before */ -#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ -#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ +#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */ +#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */ #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index ebb341d36e8c..0ce845fb6629 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -47,9 +47,9 @@ #define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) /* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ #define WL1271_ACX_INTR_DATA BIT(6) -/* Trace meassge on MBOX #A */ +/* Trace message on MBOX #A */ #define WL1271_ACX_INTR_TRACE_A BIT(7) -/* Trace meassge on MBOX #B */ +/* Trace message on MBOX #B */ #define WL1271_ACX_INTR_TRACE_B BIT(8) #define WL1271_ACX_INTR_ALL 0xFFFFFFFF -- cgit v1.2.3 From eb78bd7d8a39415245a8d20ae3b464ddde68b20a Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Thu, 30 Dec 2010 15:08:03 -0800 Subject: media: comment typo fix diable -> disable. The below patch fixes a typo "diable" to "disable". Signed-off-by: Justin P. Mattock Acked-by: Mauro Carvalho Chehab Signed-off-by: Jiri Kosina --- drivers/media/video/cx18/cx23418.h | 2 +- drivers/media/video/tvp7002.c | 2 +- include/media/davinci/vpss.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 2c00980acfcb..7e40035028d2 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h @@ -177,7 +177,7 @@ IN[0] - Task handle. IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, 3 = 2D H/V separable, 4 = 2D symmetric non-separable - IN[2] - chroma type: 0 - diable, 1 = 1D horizontal + IN[2] - chroma type: 0 - disable, 1 = 1D horizontal ReturnCode - One of the ERR_CAPTURE_... */ #define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index e63b40f5a706..c799e4eb6fcd 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -789,7 +789,7 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, * Get the value of a TVP7002 decoder device register. * Returns zero when successful, -EINVAL if register read fails or * access to I2C client fails, -EPERM if the call is not allowed - * by diabled CAP_SYS_ADMIN. + * by disabled CAP_SYS_ADMIN. */ static int tvp7002_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) diff --git a/include/media/davinci/vpss.h b/include/media/davinci/vpss.h index c59cc029c74a..b586495bcd53 100644 --- a/include/media/davinci/vpss.h +++ b/include/media/davinci/vpss.h @@ -44,7 +44,7 @@ struct vpss_pg_frame_size { short pplen; }; -/* Used for enable/diable VPSS Clock */ +/* Used for enable/disable VPSS Clock */ enum vpss_clock_sel { /* DM355/DM365 */ VPSS_CCDC_CLOCK, -- cgit v1.2.3 From 62e45c14fb9a978dca6c7a5dc8372cc8ea2f42c8 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Thu, 30 Dec 2010 15:07:56 -0800 Subject: wireless: comment typo fix diable -> disable. The below patch fixes a typo "diable" to "disable". Please let me know if this is correct or not. Signed-off-by: Justin P. Mattock Acked-by: Larry Finger Signed-off-by: Jiri Kosina --- drivers/net/wireless/iwlwifi/iwl-agn-ict.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index a5dbfea1bfad..b5cb3be0eb4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -197,7 +197,7 @@ static irqreturn_t iwl_isr(int irq, void *data) none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq and no schedules tasklet. */ + /* only Re-enable if disabled by irq and no schedules tasklet. */ if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta) iwl_enable_interrupts(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c2636a7ab9ee..9b912c0b6e59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1316,7 +1316,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); @@ -1530,7 +1530,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 25fb3912342c..8700ab38d599 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1304,7 +1304,7 @@ irqreturn_t iwl_isr_legacy(int irq, void *data) none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); -- cgit v1.2.3 From 48e34d0f4f357bb24fa4c6f84a93b9b8349db722 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Thu, 30 Dec 2010 15:07:58 -0800 Subject: drivers: fix comment typo diable -> disable. The below patch fixes a typo "diable" to "disable" and also fixes another typo in a comment. Please let me know if this is correct or not. Signed-off-by: Justin P. Mattock Signed-off-by: Jiri Kosina --- drivers/isdn/mISDN/dsp_cmx.c | 2 +- drivers/scsi/lpfc/lpfc_init.c | 2 +- drivers/usb/gadget/langwell_udc.c | 4 ++-- drivers/usb/host/fhci-hcd.c | 4 ++-- drivers/usb/host/fhci-tds.c | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 76d9e673b4e1..309bacf1fadc 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -112,7 +112,7 @@ * Disable rx-data: * If cmx is realized in hardware, rx data will be disabled if requested by * the upper layer. If dtmf decoding is done by software and enabled, rx data - * will not be diabled but blocked to the upper layer. + * will not be disabled but blocked to the upper layer. * * HFC conference engine: * If it is possible to realize all features using hardware, hardware will be diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b3065791f303..a921f168df80 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7661,7 +7661,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) * the HBA. */ - /* HBA interrupt will be diabled after this call */ + /* HBA interrupt will be disabled after this call */ lpfc_sli_hba_down(phba); /* Stop kthread signal shall trigger work_done one more time */ kthread_stop(phba->worker_thread); diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index b8ec954c0692..dad278fe0555 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -3063,7 +3063,7 @@ static void langwell_udc_remove(struct pci_dev *pdev) kfree(dev->ep); - /* diable IRQ handler */ + /* disable IRQ handler */ if (dev->got_irq) free_irq(pdev->irq, dev); @@ -3383,7 +3383,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) /* disable interrupt and set controller to stop state */ langwell_udc_stop(dev); - /* diable IRQ handler */ + /* disable IRQ handler */ if (dev->got_irq) free_irq(pdev->irq, dev); dev->got_irq = 0; diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 20092a27a1e8..12fd184226f2 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -98,13 +98,13 @@ void fhci_usb_enable_interrupt(struct fhci_usb *usb) usb->intr_nesting_cnt--; } -/* diable the usb interrupt */ +/* disable the usb interrupt */ void fhci_usb_disable_interrupt(struct fhci_usb *usb) { struct fhci_hcd *fhci = usb->fhci; if (usb->intr_nesting_cnt == 0) { - /* diable the timer interrupt */ + /* disable the timer interrupt */ disable_irq_nosync(fhci->timer->irq); /* disable the usb interrupt */ diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index 7be548ca2183..38fe058fbe61 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -271,8 +271,8 @@ void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep, /* * Collect the submitted frames and inform the application about them - * It is also prepearing the TDs for new frames. If the Tx interrupts - * are diabled, the application should call that routine to get + * It is also preparing the TDs for new frames. If the Tx interrupts + * are disabled, the application should call that routine to get * confirmation about the submitted frames. Otherwise, the routine is * called frome the interrupt service routine during the Tx interrupt. * In that case the application is informed by calling the application -- cgit v1.2.3 From 236cdc7bc718566a7e7cb9f763b51a8dcad88cbe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 3 Jan 2011 11:56:38 -0600 Subject: of: make drivers depend on CONFIG_OF instead of CONFIG_PPC_OF Some OF drivers could likely be used on non-powerpc OF based platforms, so fix the kconfig depends to be CONFIG_OF instead of CONFIG_PPC_OF. Compile tested on ARM and sparc. Signed-off-by: Rob Herring Signed-off-by: Grant Likely --- drivers/mmc/host/Kconfig | 4 +++- drivers/mtd/Kconfig | 2 +- drivers/mtd/maps/Kconfig | 2 +- drivers/serial/Kconfig | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d618e8673996..e960a9300eb2 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -83,7 +83,7 @@ config MMC_RICOH_MMC config MMC_SDHCI_OF tristate "SDHCI support on OpenFirmware platforms" - depends on MMC_SDHCI && PPC_OF + depends on MMC_SDHCI && OF help This selects the OF support for Secure Digital Host Controller Interfaces. @@ -93,6 +93,7 @@ config MMC_SDHCI_OF config MMC_SDHCI_OF_ESDHC bool "SDHCI OF support for the Freescale eSDHC controller" depends on MMC_SDHCI_OF + depends on PPC_OF select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER help This selects the Freescale eSDHC controller support. @@ -102,6 +103,7 @@ config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_HLWD bool "SDHCI OF support for the Nintendo Wii SDHCI controllers" depends on MMC_SDHCI_OF + depends on PPC_OF select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER help This selects the Secure Digital Host Controller Interface (SDHCI) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 1e2cbf5d9aa1..b1f768917395 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -159,7 +159,7 @@ config MTD_AFS_PARTS config MTD_OF_PARTS tristate "Flash partition map based on OF description" - depends on (MICROBLAZE || PPC_OF) && MTD_PARTITIONS + depends on OF && MTD_PARTITIONS help This provides a partition parsing function which derives the partition map from the children of the flash node, diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index a0dd7bba9481..5d37d315fa98 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -72,7 +72,7 @@ config MTD_PHYSMAP_BANKWIDTH config MTD_PHYSMAP_OF tristate "Flash device in physical memory map based on OF description" - depends on (MICROBLAZE || PPC_OF) && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM) + depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM) help This provides a 'mapping' driver which allows the NOR Flash and ROM driver code to communicate with chips which are mapped diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index aff9dcd051c6..9d109f9a5c70 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1402,7 +1402,7 @@ config SERIAL_NETX_CONSOLE config SERIAL_OF_PLATFORM tristate "Serial port on Open Firmware platform bus" - depends on PPC_OF || MICROBLAZE + depends on OF depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL help If you have a PowerPC based system that has serial ports -- cgit v1.2.3 From da81c3b9825c826bfb06a4dcc0524c671985eb68 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 16 Nov 2010 14:33:50 -0600 Subject: of: Fixes for OF probing on little endian systems Fixes for sdhci-of and ipmi drivers. Auditing all drivers using of_get_property did not find other occurrences likely to be used on LE platforms. Signed-off-by: Rob Herring Signed-off-by: Grant Likely --- drivers/char/ipmi/ipmi_si_intf.c | 8 ++++---- drivers/mmc/host/sdhci-of-core.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 035da9e64a17..8cc4607cc86c 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2546,7 +2546,7 @@ static int __devinit ipmi_of_probe(struct platform_device *dev, { struct smi_info *info; struct resource resource; - const int *regsize, *regspacing, *regshift; + const __be32 *regsize, *regspacing, *regshift; struct device_node *np = dev->dev.of_node; int ret; int proplen; @@ -2599,9 +2599,9 @@ static int __devinit ipmi_of_probe(struct platform_device *dev, info->io.addr_data = resource.start; - info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE; - info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING; - info->io.regshift = regshift ? *regshift : 0; + info->io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; + info->io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; + info->io.regshift = regshift ? be32_to_cpup(regshift) : 0; info->irq = irq_of_parse_and_map(dev->dev.of_node, 0); info->dev = &dev->dev; diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index c51b71174c1d..fa19d849a920 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c @@ -122,7 +122,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev, struct sdhci_of_data *sdhci_of_data = match->data; struct sdhci_host *host; struct sdhci_of_host *of_host; - const u32 *clk; + const __be32 *clk; int size; int ret; @@ -166,7 +166,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev, clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) - of_host->clock = *clk; + of_host->clock = be32_to_cpup(clk); ret = sdhci_add_host(host); if (ret) -- cgit v1.2.3 From 82b662dc41027527675740de15344d1b4e34958e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 24 Dec 2010 14:40:15 +0100 Subject: firewire: ohci: flush AT contexts after bus reset for OHCI 1.2 The OHCI 1.2 (draft) specification, clause 7.2.3.3, allows and recommends that, after a bus reset, the controller does not flush all the packets in the AT queues. Therefore, the driver has to do this itself. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 5e5d5d3d43d1..3372cd187c25 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -125,6 +125,7 @@ struct context { struct fw_ohci *ohci; u32 regs; int total_allocation; + bool flushing; /* * List of page-sized buffers for storing DMA descriptors. @@ -1356,6 +1357,17 @@ static int at_context_queue_packet(struct context *ctx, return 0; } +static void at_context_flush(struct context *ctx) +{ + tasklet_disable(&ctx->tasklet); + + ctx->flushing = true; + context_tasklet((unsigned long)ctx); + ctx->flushing = false; + + tasklet_enable(&ctx->tasklet); +} + static int handle_at_packet(struct context *context, struct descriptor *d, struct descriptor *last) @@ -1365,7 +1377,7 @@ static int handle_at_packet(struct context *context, struct fw_ohci *ohci = context->ohci; int evt; - if (last->transfer_status == 0) + if (last->transfer_status == 0 && !context->flushing) /* This descriptor isn't done yet, stop iteration. */ return 0; @@ -1399,11 +1411,15 @@ static int handle_at_packet(struct context *context, break; case OHCI1394_evt_missing_ack: - /* - * Using a valid (current) generation count, but the - * node is not on the bus or not sending acks. - */ - packet->ack = RCODE_NO_ACK; + if (context->flushing) + packet->ack = RCODE_GENERATION; + else { + /* + * Using a valid (current) generation count, but the + * node is not on the bus or not sending acks. + */ + packet->ack = RCODE_NO_ACK; + } break; case ACK_COMPLETE + 0x10: @@ -1416,6 +1432,13 @@ static int handle_at_packet(struct context *context, packet->ack = evt - 0x10; break; + case OHCI1394_evt_no_status: + if (context->flushing) { + packet->ack = RCODE_GENERATION; + break; + } + /* fall through */ + default: packet->ack = RCODE_SEND_ERROR; break; @@ -1721,9 +1744,18 @@ static void bus_reset_tasklet(unsigned long data) /* FIXME: Document how the locking works. */ spin_lock_irqsave(&ohci->lock, flags); - ohci->generation = generation; + ohci->generation = -1; /* prevent AT packet queueing */ context_stop(&ohci->at_request_ctx); context_stop(&ohci->at_response_ctx); + + spin_unlock_irqrestore(&ohci->lock, flags); + + at_context_flush(&ohci->at_request_ctx); + at_context_flush(&ohci->at_response_ctx); + + spin_lock_irqsave(&ohci->lock, flags); + + ohci->generation = generation; reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); if (ohci->quirks & QUIRK_RESET_PACKET) -- cgit v1.2.3 From cd1e65044d4473cca9a01bae7b7938f065044a4b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 3 Jan 2011 15:51:11 -0700 Subject: of/device: Don't register disabled devices Device nodes with the property status="disabled" are not usable and so don't register them when parsing the device tree for devices. Signed-off-by: Grant Likely Cc: Hollis Blanchard Cc: Deepak Saxena Cc: Scott Wood , Cc: David Gibson Cc: Benjamin Herrenschmidt --- drivers/of/platform.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 5b4a07f1220e..c01cd1ac7617 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -633,6 +633,9 @@ EXPORT_SYMBOL(of_device_alloc); * @np: pointer to node to create device for * @bus_id: name to assign device * @parent: Linux device model parent device. + * + * Returns pointer to created platform device, or NULL if a device was not + * registered. Unavailable devices will not get registered. */ struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, @@ -640,6 +643,9 @@ struct platform_device *of_platform_device_create(struct device_node *np, { struct platform_device *dev; + if (!of_device_is_available(np)) + return NULL; + dev = of_device_alloc(np, bus_id, parent); if (!dev) return NULL; @@ -683,8 +689,9 @@ static int of_platform_bus_create(const struct device_node *bus, pr_debug(" create child: %s\n", child->full_name); dev = of_platform_device_create(child, NULL, parent); if (dev == NULL) - rc = -ENOMEM; - else if (!of_match_node(matches, child)) + continue; + + if (!of_match_node(matches, child)) continue; if (rc == 0) { pr_debug(" and sub busses\n"); @@ -733,10 +740,9 @@ int of_platform_bus_probe(struct device_node *root, if (of_match_node(matches, root)) { pr_debug(" root match, create all sub devices\n"); dev = of_platform_device_create(root, NULL, parent); - if (dev == NULL) { - rc = -ENOMEM; + if (dev == NULL) goto bail; - } + pr_debug(" create all sub busses\n"); rc = of_platform_bus_create(root, matches, &dev->dev); goto bail; @@ -748,9 +754,9 @@ int of_platform_bus_probe(struct device_node *root, pr_debug(" match: %s\n", child->full_name); dev = of_platform_device_create(child, NULL, parent); if (dev == NULL) - rc = -ENOMEM; - else - rc = of_platform_bus_create(child, matches, &dev->dev); + continue; + + rc = of_platform_bus_create(child, matches, &dev->dev); if (rc) { of_node_put(child); break; -- cgit v1.2.3 From 747fcc91cb5bade1f681b3a8d0e6d4f697d865fd Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Mon, 29 Nov 2010 12:33:39 +0200 Subject: i2c-iop3xx: add iomem annotation Eliminate unnecessary casts and the following sparse warnings: drivers/i2c/busses/i2c-iop3xx.c:65:9: warning: incorrect type in argument 1 (different base types) drivers/i2c/busses/i2c-iop3xx.c:65:9: expected void const volatile [noderef] * drivers/i2c/busses/i2c-iop3xx.c:65:9: got unsigned int [ the previous warning is repeated 18 times ] drivers/i2c/busses/i2c-iop3xx.c:456:33: warning: cast removes address space of expression Signed-off-by: Aaro Koskinen Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-iop3xx.c | 6 +++--- drivers/i2c/busses/i2c-iop3xx.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 112c61f7b8cd..f09c9319a2ba 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -409,7 +409,7 @@ iop3xx_i2c_remove(struct platform_device *pdev) IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE); __raw_writel(cr, adapter_data->ioaddr + CR_OFFSET); - iounmap((void __iomem*)adapter_data->ioaddr); + iounmap(adapter_data->ioaddr); release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); kfree(adapter_data); kfree(padapter); @@ -453,7 +453,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) /* set the adapter enumeration # */ adapter_data->id = i2c_id++; - adapter_data->ioaddr = (u32)ioremap(res->start, IOP3XX_I2C_IO_SIZE); + adapter_data->ioaddr = ioremap(res->start, IOP3XX_I2C_IO_SIZE); if (!adapter_data->ioaddr) { ret = -ENOMEM; goto release_region; @@ -498,7 +498,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) return 0; unmap: - iounmap((void __iomem*)adapter_data->ioaddr); + iounmap(adapter_data->ioaddr); release_region: release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h index 8485861f6a36..097e270955d0 100644 --- a/drivers/i2c/busses/i2c-iop3xx.h +++ b/drivers/i2c/busses/i2c-iop3xx.h @@ -97,7 +97,7 @@ #define IOP3XX_I2C_IO_SIZE 0x18 struct i2c_algo_iop3xx_data { - u32 ioaddr; + void __iomem *ioaddr; wait_queue_head_t waitq; spinlock_t lock; u32 SR_enabled, SR_received; -- cgit v1.2.3 From 049bb69d82e5f7f356949c1ae34a244b3338611b Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Wed, 24 Nov 2010 17:26:20 +0100 Subject: i2c-ocores: Adapt for device tree This patch adapts the i2c-ocores driver for being defined and configured via a device tree description. The device tree bits need to be protected by CONFIG_OF guards as this is still an optional feature. Signed-off-by: Jonas Bonn Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-ocores.c | 64 +++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 0070371b29f3..c05e8c44404a 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -210,6 +210,32 @@ static struct i2c_adapter ocores_adapter = { .algo = &ocores_algorithm, }; +#ifdef CONFIG_OF +static int ocores_i2c_of_probe(struct platform_device* pdev, + struct ocores_i2c* i2c) +{ + __be32* val; + + val = of_get_property(pdev->dev.of_node, "regstep", NULL); + if (!val) { + dev_err(&pdev->dev, "Missing required parameter 'regstep'"); + return -ENODEV; + } + i2c->regstep = be32_to_cpup(val); + + val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); + if (!val) { + dev_err(&pdev->dev, + "Missing required parameter 'clock-frequency'"); + return -ENODEV; + } + i2c->clock_khz = be32_to_cpup(val) / 1000; + + return 0; +} +#else +#define ocores_i2c_of_probe(pdev,i2c) -ENODEV +#endif static int __devinit ocores_i2c_probe(struct platform_device *pdev) { @@ -227,10 +253,6 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data; - if (!pdata) - return -ENODEV; - i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; @@ -249,8 +271,16 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) goto map_failed; } - i2c->regstep = pdata->regstep; - i2c->clock_khz = pdata->clock_khz; + pdata = pdev->dev.platform_data; + if (pdata) { + i2c->regstep = pdata->regstep; + i2c->clock_khz = pdata->clock_khz; + } else { + ret = ocores_i2c_of_probe(pdev, i2c); + if (ret) + return ret; + } + ocores_init(i2c); init_waitqueue_head(&i2c->wait); @@ -265,6 +295,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) i2c->adap = ocores_adapter; i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; +#ifdef CONFIG_OF + i2c->adap.dev.of_node = pdev->dev.of_node; +#endif /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); @@ -274,8 +307,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) } /* add in known devices to the bus */ - for (i = 0; i < pdata->num_devices; i++) - i2c_new_device(&i2c->adap, pdata->devices + i); + if (pdata) { + for (i = 0; i < pdata->num_devices; i++) + i2c_new_device(&i2c->adap, pdata->devices + i); + } return 0; @@ -344,6 +379,16 @@ static int ocores_i2c_resume(struct platform_device *pdev) #define ocores_i2c_resume NULL #endif +#ifdef CONFIG_OF +static struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); +#endif + /* work with hotplug and coldplug */ MODULE_ALIAS("platform:ocores-i2c"); @@ -355,6 +400,9 @@ static struct platform_driver ocores_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "ocores-i2c", +#ifdef CONFIG_OF + .of_match_table = ocores_i2c_match, +#endif }, }; -- cgit v1.2.3 From 47def5b80f087d033013c0609679812cfafd6b49 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Wed, 24 Nov 2010 17:26:21 +0100 Subject: i2c-ocores: Use devres for resource allocation This patch converts the i2c-cores driver to use devres routines for resource allocation. Signed-off-by: Jonas Bonn Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-ocores.c | 46 ++++++++++------------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index c05e8c44404a..dee0352737d7 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -253,22 +253,21 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; - if (!request_mem_region(res->start, resource_size(res), - pdev->name)) { + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Memory region busy\n"); - ret = -EBUSY; - goto request_mem_failed; + return -EBUSY; } - i2c->base = ioremap(res->start, resource_size(res)); + i2c->base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); if (!i2c->base) { dev_err(&pdev->dev, "Unable to map registers\n"); - ret = -EIO; - goto map_failed; + return -EIO; } pdata = pdev->dev.platform_data; @@ -284,10 +283,11 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) ocores_init(i2c); init_waitqueue_head(&i2c->wait); - ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c); + ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0, + pdev->name, i2c); if (ret) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto request_irq_failed; + return ret; } /* hook up driver to tree */ @@ -303,7 +303,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret) { dev_err(&pdev->dev, "Failed to add adapter\n"); - goto add_adapter_failed; + return ret; } /* add in known devices to the bus */ @@ -313,23 +313,11 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) } return 0; - -add_adapter_failed: - free_irq(res2->start, i2c); -request_irq_failed: - iounmap(i2c->base); -map_failed: - release_mem_region(res->start, resource_size(res)); -request_mem_failed: - kfree(i2c); - - return ret; } static int __devexit ocores_i2c_remove(struct platform_device* pdev) { struct ocores_i2c *i2c = platform_get_drvdata(pdev); - struct resource *res; /* disable i2c logic */ oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL) @@ -339,18 +327,6 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev) i2c_del_adapter(&i2c->adap); platform_set_drvdata(pdev, NULL); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res) - free_irq(res->start, i2c); - - iounmap(i2c->base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - - kfree(i2c); - return 0; } -- cgit v1.2.3 From d9240e612ba79287e29f2eac52f94a2016fb0914 Mon Sep 17 00:00:00 2001 From: Jonas Bonn Date: Wed, 24 Nov 2010 17:26:22 +0100 Subject: i2c-ocores: add some device tree documentation This puts some documentation for the device tree configuration at the head of the driver file. Hopefully this can get moved to a common area for this type of documentation at a later date; unfortunately, there isn't really such a place in the kernel tree at this time. Furthermore, the regstep and clock-frequency parameters are really bus parameters and should probably be passed to the driver in a better way. Consider that a TODO. Signed-off-by: Jonas Bonn Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-ocores.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index dee0352737d7..ef3bcb1ce864 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -9,6 +9,41 @@ * kind, whether express or implied. */ +/* + * Device tree configuration: + * + * Required properties: + * - compatible : "opencores,i2c-ocores" + * - reg : bus address start and address range size of device + * - interrupts : interrupt number + * - regstep : size of device registers in bytes + * - clock-frequency : frequency of bus clock in Hz + * + * Example: + * + * i2c0: ocores@a0000000 { + * compatible = "opencores,i2c-ocores"; + * reg = <0xa0000000 0x8>; + * interrupts = <10>; + * + * regstep = <1>; + * clock-frequency = <20000000>; + * + * -- Devices connected on this I2C bus get + * -- defined here; address- and size-cells + * -- apply to these child devices + * + * #address-cells = <1>; + * #size-cells = <0>; + * + * dummy@60 { + * compatible = "dummy"; + * reg = <60>; + * }; + * }; + * + */ + #include #include #include -- cgit v1.2.3 From e9bc8fa5df1c398890e0963afe07425d994240b7 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 9 Nov 2010 13:25:22 +0900 Subject: i2c-eg20t: add driver for Intel EG20T I2C driver for Intel EG20T PCH Signed-off-by: Tomoya MORINAGA Reviewed-by: Linus Walleij Signed-off-by: Qi Wang [ben-linux@fluff.org: reworded commit message] Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 8 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-eg20t.c | 900 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 909 insertions(+) create mode 100644 drivers/i2c/busses/i2c-eg20t.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3a6321cb8030..113505a6434e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -638,6 +638,14 @@ config I2C_XILINX This driver can also be built as a module. If so, the module will be called xilinx_i2c. +config I2C_EG20T + tristate "PCH I2C of Intel EG20T" + depends on PCI + help + This driver is for PCH(Platform controller Hub) I2C of EG20T which + is an IOH(Input/Output Hub) for x86 embedded processor. + This driver can access PCH I2C bus device. + comment "External I2C/SMBus adapter drivers" config I2C_PARPORT diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 84cb16ae6f9e..9d2d0ec7fb23 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o +obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c new file mode 100644 index 000000000000..2e067dd2ee51 --- /dev/null +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -0,0 +1,900 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + * + * 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; version 2 of the License. + * + * 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 +#include +#include +#include + +#define PCH_EVENT_SET 0 /* I2C Interrupt Event Set Status */ +#define PCH_EVENT_NONE 1 /* I2C Interrupt Event Clear Status */ +#define PCH_MAX_CLK 100000 /* Maximum Clock speed in MHz */ +#define PCH_BUFFER_MODE_ENABLE 0x0002 /* flag for Buffer mode enable */ +#define PCH_EEPROM_SW_RST_MODE_ENABLE 0x0008 /* EEPROM SW RST enable flag */ + +#define PCH_I2CSADR 0x00 /* I2C slave address register */ +#define PCH_I2CCTL 0x04 /* I2C control register */ +#define PCH_I2CSR 0x08 /* I2C status register */ +#define PCH_I2CDR 0x0C /* I2C data register */ +#define PCH_I2CMON 0x10 /* I2C bus monitor register */ +#define PCH_I2CBC 0x14 /* I2C bus transfer rate setup counter */ +#define PCH_I2CMOD 0x18 /* I2C mode register */ +#define PCH_I2CBUFSLV 0x1C /* I2C buffer mode slave address register */ +#define PCH_I2CBUFSUB 0x20 /* I2C buffer mode subaddress register */ +#define PCH_I2CBUFFOR 0x24 /* I2C buffer mode format register */ +#define PCH_I2CBUFCTL 0x28 /* I2C buffer mode control register */ +#define PCH_I2CBUFMSK 0x2C /* I2C buffer mode interrupt mask register */ +#define PCH_I2CBUFSTA 0x30 /* I2C buffer mode status register */ +#define PCH_I2CBUFLEV 0x34 /* I2C buffer mode level register */ +#define PCH_I2CESRFOR 0x38 /* EEPROM software reset mode format register */ +#define PCH_I2CESRCTL 0x3C /* EEPROM software reset mode ctrl register */ +#define PCH_I2CESRMSK 0x40 /* EEPROM software reset mode */ +#define PCH_I2CESRSTA 0x44 /* EEPROM software reset mode status register */ +#define PCH_I2CTMR 0x48 /* I2C timer register */ +#define PCH_I2CSRST 0xFC /* I2C reset register */ +#define PCH_I2CNF 0xF8 /* I2C noise filter register */ + +#define BUS_IDLE_TIMEOUT 20 +#define PCH_I2CCTL_I2CMEN 0x0080 +#define TEN_BIT_ADDR_DEFAULT 0xF000 +#define TEN_BIT_ADDR_MASK 0xF0 +#define PCH_START 0x0020 +#define PCH_ESR_START 0x0001 +#define PCH_BUFF_START 0x1 +#define PCH_REPSTART 0x0004 +#define PCH_ACK 0x0008 +#define PCH_GETACK 0x0001 +#define CLR_REG 0x0 +#define I2C_RD 0x1 +#define I2CMCF_BIT 0x0080 +#define I2CMIF_BIT 0x0002 +#define I2CMAL_BIT 0x0010 +#define I2CBMFI_BIT 0x0001 +#define I2CBMAL_BIT 0x0002 +#define I2CBMNA_BIT 0x0004 +#define I2CBMTO_BIT 0x0008 +#define I2CBMIS_BIT 0x0010 +#define I2CESRFI_BIT 0X0001 +#define I2CESRTO_BIT 0x0002 +#define I2CESRFIIE_BIT 0x1 +#define I2CESRTOIE_BIT 0x2 +#define I2CBMDZ_BIT 0x0040 +#define I2CBMAG_BIT 0x0020 +#define I2CMBB_BIT 0x0020 +#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \ + I2CBMTO_BIT | I2CBMIS_BIT) +#define I2C_ADDR_MSK 0xFF +#define I2C_MSB_2B_MSK 0x300 +#define FAST_MODE_CLK 400 +#define FAST_MODE_EN 0x0001 +#define SUB_ADDR_LEN_MAX 4 +#define BUF_LEN_MAX 32 +#define PCH_BUFFER_MODE 0x1 +#define EEPROM_SW_RST_MODE 0x0002 +#define NORMAL_INTR_ENBL 0x0300 +#define EEPROM_RST_INTR_ENBL (I2CESRFIIE_BIT | I2CESRTOIE_BIT) +#define EEPROM_RST_INTR_DISBL 0x0 +#define BUFFER_MODE_INTR_ENBL 0x001F +#define BUFFER_MODE_INTR_DISBL 0x0 +#define NORMAL_MODE 0x0 +#define BUFFER_MODE 0x1 +#define EEPROM_SR_MODE 0x2 +#define I2C_TX_MODE 0x0010 +#define PCH_BUF_TX 0xFFF7 +#define PCH_BUF_RD 0x0008 +#define I2C_ERROR_MASK (I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \ + I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT) +#define I2CMAL_EVENT 0x0001 +#define I2CMCF_EVENT 0x0002 +#define I2CBMFI_EVENT 0x0004 +#define I2CBMAL_EVENT 0x0008 +#define I2CBMNA_EVENT 0x0010 +#define I2CBMTO_EVENT 0x0020 +#define I2CBMIS_EVENT 0x0040 +#define I2CESRFI_EVENT 0x0080 +#define I2CESRTO_EVENT 0x0100 +#define PCI_DEVICE_ID_PCH_I2C 0x8817 + +#define pch_dbg(adap, fmt, arg...) \ + dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg) + +#define pch_err(adap, fmt, arg...) \ + dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg) + +#define pch_pci_err(pdev, fmt, arg...) \ + dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg) + +#define pch_pci_dbg(pdev, fmt, arg...) \ + dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg) + +/** + * struct i2c_algo_pch_data - for I2C driver functionalities + * @pch_adapter: stores the reference to i2c_adapter structure + * @p_adapter_info: stores the reference to adapter_info structure + * @pch_base_address: specifies the remapped base address + * @pch_buff_mode_en: specifies if buffer mode is enabled + * @pch_event_flag: specifies occurrence of interrupt events + * @pch_i2c_xfer_in_progress: specifies whether the transfer is completed + */ +struct i2c_algo_pch_data { + struct i2c_adapter pch_adapter; + struct adapter_info *p_adapter_info; + void __iomem *pch_base_address; + int pch_buff_mode_en; + u32 pch_event_flag; + bool pch_i2c_xfer_in_progress; +}; + +/** + * struct adapter_info - This structure holds the adapter information for the + PCH i2c controller + * @pch_data: stores a list of i2c_algo_pch_data + * @pch_i2c_suspended: specifies whether the system is suspended or not + * perhaps with more lines and words. + * + * pch_data has as many elements as maximum I2C channels + */ +struct adapter_info { + struct i2c_algo_pch_data pch_data; + bool pch_i2c_suspended; +}; + + +static int pch_i2c_speed = 100; /* I2C bus speed in Kbps */ +static int pch_clk = 50000; /* specifies I2C clock speed in KHz */ +static wait_queue_head_t pch_event; +static DEFINE_MUTEX(pch_mutex); + +static struct pci_device_id __devinitdata pch_pcidev_id[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)}, + {0,} +}; + +static irqreturn_t pch_i2c_handler(int irq, void *pData); + +static inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask) +{ + u32 val; + val = ioread32(addr + offset); + val |= bitmask; + iowrite32(val, addr + offset); +} + +static inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask) +{ + u32 val; + val = ioread32(addr + offset); + val &= (~bitmask); + iowrite32(val, addr + offset); +} + +/** + * pch_i2c_init() - hardware initialization of I2C module + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_init(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + u32 pch_i2cbc; + u32 pch_i2ctmr; + u32 reg_value; + + /* reset I2C controller */ + iowrite32(0x01, p + PCH_I2CSRST); + msleep(20); + iowrite32(0x0, p + PCH_I2CSRST); + + /* Initialize I2C registers */ + iowrite32(0x21, p + PCH_I2CNF); + + pch_setbit(adap->pch_base_address, PCH_I2CCTL, + PCH_I2CCTL_I2CMEN); + + if (pch_i2c_speed != 400) + pch_i2c_speed = 100; + + reg_value = PCH_I2CCTL_I2CMEN; + if (pch_i2c_speed == FAST_MODE_CLK) { + reg_value |= FAST_MODE_EN; + pch_dbg(adap, "Fast mode enabled\n"); + } + + if (pch_clk > PCH_MAX_CLK) + pch_clk = 62500; + + pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8; + /* Set transfer speed in I2CBC */ + iowrite32(pch_i2cbc, p + PCH_I2CBC); + + pch_i2ctmr = (pch_clk) / 8; + iowrite32(pch_i2ctmr, p + PCH_I2CTMR); + + reg_value |= NORMAL_INTR_ENBL; /* Enable interrupts in normal mode */ + iowrite32(reg_value, p + PCH_I2CCTL); + + pch_dbg(adap, + "I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts\n", + ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr); + + init_waitqueue_head(&pch_event); +} + +static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2) +{ + return cmp1.tv64 < cmp2.tv64; +} + +/** + * pch_i2c_wait_for_bus_idle() - check the status of bus. + * @adap: Pointer to struct i2c_algo_pch_data. + * @timeout: waiting time counter (us). + */ +static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, + s32 timeout) +{ + void __iomem *p = adap->pch_base_address; + + /* MAX timeout value is timeout*1000*1000nsec */ + ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000); + do { + if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) + break; + msleep(20); + } while (ktime_lt(ktime_get(), ns_val)); + + pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); + + if (timeout == 0) { + pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME); + return -ETIME; + } + + return 0; +} + +/** + * pch_i2c_start() - Generate I2C start condition in normal mode. + * @adap: Pointer to struct i2c_algo_pch_data. + * + * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1. + */ +static void pch_i2c_start(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); + pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START); +} + +/** + * pch_i2c_wait_for_xfer_complete() - initiates a wait for the tx complete event + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap) +{ + s32 ret; + ret = wait_event_timeout(pch_event, + (adap->pch_event_flag != 0), msecs_to_jiffies(50)); + if (ret < 0) { + pch_err(adap, "timeout: %x\n", adap->pch_event_flag); + return ret; + } + + if (ret == 0) { + pch_err(adap, "timeout: %x\n", adap->pch_event_flag); + return -ETIMEDOUT; + } + + if (adap->pch_event_flag & I2C_ERROR_MASK) { + pch_err(adap, "error bits set: %x\n", adap->pch_event_flag); + return -EIO; + } + + adap->pch_event_flag = 0; + + return 0; +} + +/** + * pch_i2c_getack() - to confirm ACK/NACK + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap) +{ + u32 reg_val; + void __iomem *p = adap->pch_base_address; + reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK; + + if (reg_val != 0) { + pch_err(adap, "return%d\n", -EPROTO); + return -EPROTO; + } + + return 0; +} + +/** + * pch_i2c_stop() - generate stop condition in normal mode. + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_stop(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); + /* clear the start bit */ + pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START); +} + +/** + * pch_i2c_repstart() - generate repeated start condition in normal mode + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_repstart(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); + pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART); +} + +/** + * pch_i2c_writebytes() - write data to I2C bus in normal mode + * @i2c_adap: Pointer to the struct i2c_adapter. + * @last: specifies whether last message or not. + * In the case of compound mode it will be 1 for last message, + * otherwise 0. + * @first: specifies whether first message or not. + * 1 for first message otherwise 0. + */ +static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, u32 last, u32 first) +{ + struct i2c_algo_pch_data *adap = i2c_adap->algo_data; + u8 *buf; + u32 length; + u32 addr; + u32 addr_2_msb; + u32 addr_8_lsb; + s32 wrcount; + void __iomem *p = adap->pch_base_address; + + length = msgs->len; + buf = msgs->buf; + addr = msgs->addr; + + /* enable master tx */ + pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE); + + pch_dbg(adap, "I2CCTL = %x msgs->len = %d\n", ioread32(p + PCH_I2CCTL), + length); + + if (first) { + if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME) + return -ETIME; + } + + if (msgs->flags & I2C_M_TEN) { + addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); + iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); + if (first) + pch_i2c_start(adap); + if (pch_i2c_wait_for_xfer_complete(adap) == 0 && + pch_i2c_getack(adap) == 0) { + addr_8_lsb = (addr & I2C_ADDR_MSK); + iowrite32(addr_8_lsb, p + PCH_I2CDR); + } else { + pch_i2c_stop(adap); + return -ETIME; + } + } else { + /* set 7 bit slave address and R/W bit as 0 */ + iowrite32(addr << 1, p + PCH_I2CDR); + if (first) + pch_i2c_start(adap); + } + + if ((pch_i2c_wait_for_xfer_complete(adap) == 0) && + (pch_i2c_getack(adap) == 0)) { + for (wrcount = 0; wrcount < length; ++wrcount) { + /* write buffer value to I2C data register */ + iowrite32(buf[wrcount], p + PCH_I2CDR); + pch_dbg(adap, "writing %x to Data register\n", + buf[wrcount]); + + if (pch_i2c_wait_for_xfer_complete(adap) != 0) + return -ETIME; + + if (pch_i2c_getack(adap)) + return -EIO; + } + + /* check if this is the last message */ + if (last) + pch_i2c_stop(adap); + else + pch_i2c_repstart(adap); + } else { + pch_i2c_stop(adap); + return -EIO; + } + + pch_dbg(adap, "return=%d\n", wrcount); + + return wrcount; +} + +/** + * pch_i2c_sendack() - send ACK + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_sendack(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); + pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK); +} + +/** + * pch_i2c_sendnack() - send NACK + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); + pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK); +} + +/** + * pch_i2c_readbytes() - read data from I2C bus in normal mode. + * @i2c_adap: Pointer to the struct i2c_adapter. + * @msgs: Pointer to i2c_msg structure. + * @last: specifies whether last message or not. + * @first: specifies whether first message or not. + */ +s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, + u32 last, u32 first) +{ + struct i2c_algo_pch_data *adap = i2c_adap->algo_data; + + u8 *buf; + u32 count; + u32 length; + u32 addr; + u32 addr_2_msb; + void __iomem *p = adap->pch_base_address; + + length = msgs->len; + buf = msgs->buf; + addr = msgs->addr; + + /* enable master reception */ + pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE); + + if (first) { + if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME) + return -ETIME; + } + + if (msgs->flags & I2C_M_TEN) { + addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD)); + iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); + + } else { + /* 7 address bits + R/W bit */ + addr = (((addr) << 1) | (I2C_RD)); + iowrite32(addr, p + PCH_I2CDR); + } + + /* check if it is the first message */ + if (first) + pch_i2c_start(adap); + + if ((pch_i2c_wait_for_xfer_complete(adap) == 0) && + (pch_i2c_getack(adap) == 0)) { + pch_dbg(adap, "return %d\n", 0); + + if (length == 0) { + pch_i2c_stop(adap); + ioread32(p + PCH_I2CDR); /* Dummy read needs */ + + count = length; + } else { + int read_index; + int loop; + pch_i2c_sendack(adap); + + /* Dummy read */ + for (loop = 1, read_index = 0; loop < length; loop++) { + buf[read_index] = ioread32(p + PCH_I2CDR); + + if (loop != 1) + read_index++; + + if (pch_i2c_wait_for_xfer_complete(adap) != 0) { + pch_i2c_stop(adap); + return -ETIME; + } + } /* end for */ + + pch_i2c_sendnack(adap); + + buf[read_index] = ioread32(p + PCH_I2CDR); + + if (length != 1) + read_index++; + + if (pch_i2c_wait_for_xfer_complete(adap) == 0) { + if (last) + pch_i2c_stop(adap); + else + pch_i2c_repstart(adap); + + buf[read_index++] = ioread32(p + PCH_I2CDR); + count = read_index; + } else { + count = -ETIME; + } + + } + } else { + count = -ETIME; + pch_i2c_stop(adap); + } + + return count; +} + +/** + * pch_i2c_cb_ch0() - Interrupt handler Call back function + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap) +{ + u32 sts; + void __iomem *p = adap->pch_base_address; + + sts = ioread32(p + PCH_I2CSR); + sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT); + if (sts & I2CMAL_BIT) + adap->pch_event_flag |= I2CMAL_EVENT; + + if (sts & I2CMCF_BIT) + adap->pch_event_flag |= I2CMCF_EVENT; + + /* clear the applicable bits */ + pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts); + + pch_dbg(adap, "PCH_I2CSR = %x\n", ioread32(p + PCH_I2CSR)); + + wake_up(&pch_event); +} + +/** + * pch_i2c_handler() - interrupt handler for the PCH I2C controller + * @irq: irq number. + * @pData: cookie passed back to the handler function. + */ +static irqreturn_t pch_i2c_handler(int irq, void *pData) +{ + s32 reg_val; + + struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData; + void __iomem *p = adap_data->pch_base_address; + u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE); + + if (mode != NORMAL_MODE) { + pch_err(adap_data, "I2C mode is not supported\n"); + return IRQ_NONE; + } + + reg_val = ioread32(p + PCH_I2CSR); + if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) + pch_i2c_cb_ch0(adap_data); + else + return IRQ_NONE; + + return IRQ_HANDLED; +} + +/** + * pch_i2c_xfer() - Reading adnd writing data through I2C bus + * @i2c_adap: Pointer to the struct i2c_adapter. + * @msgs: Pointer to i2c_msg structure. + * @num: number of messages. + */ +static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, s32 num) +{ + struct i2c_msg *pmsg; + u32 i = 0; + u32 status; + u32 msglen; + u32 subaddrlen; + s32 ret; + + struct i2c_algo_pch_data *adap = i2c_adap->algo_data; + + ret = mutex_lock_interruptible(&pch_mutex); + if (ret) + return -ERESTARTSYS; + + if (adap->p_adapter_info->pch_i2c_suspended) { + mutex_unlock(&pch_mutex); + return -EBUSY; + } + + pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d\n", + adap->p_adapter_info->pch_i2c_suspended); + /* transfer not completed */ + adap->pch_i2c_xfer_in_progress = true; + + pmsg = &msgs[0]; + pmsg->flags |= adap->pch_buff_mode_en; + status = pmsg->flags; + pch_dbg(adap, + "After invoking I2C_MODE_SEL :flag= 0x%x\n", status); + /* calculate sub address length and message length */ + /* these are applicable only for buffer mode */ + subaddrlen = pmsg->buf[0]; + /* calculate actual message length excluding + * the sub address fields */ + msglen = (pmsg->len) - (subaddrlen + 1); + if (status & (I2C_M_RD)) { + pch_dbg(adap, "invoking pch_i2c_readbytes\n"); + ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num), + (i == 0)); + } else { + pch_dbg(adap, "invoking pch_i2c_writebytes\n"); + ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num), + (i == 0)); + } + + adap->pch_i2c_xfer_in_progress = false; /* transfer completed */ + + mutex_unlock(&pch_mutex); + + return ret; +} + +/** + * pch_i2c_func() - return the functionality of the I2C driver + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static u32 pch_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; +} + +static struct i2c_algorithm pch_algorithm = { + .master_xfer = pch_i2c_xfer, + .functionality = pch_i2c_func +}; + +/** + * pch_i2c_disbl_int() - Disable PCH I2C interrupts + * @adap: Pointer to struct i2c_algo_pch_data. + */ +static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap) +{ + void __iomem *p = adap->pch_base_address; + + pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL); + + iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK); + + iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK); +} + +static int __devinit pch_i2c_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *base_addr; + s32 ret; + struct adapter_info *adap_info; + + pch_pci_dbg(pdev, "Entered.\n"); + + adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL); + if (adap_info == NULL) { + pch_pci_err(pdev, "Memory allocation FAILED\n"); + return -ENOMEM; + } + + ret = pci_enable_device(pdev); + if (ret) { + pch_pci_err(pdev, "pci_enable_device FAILED\n"); + goto err_pci_enable; + } + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + pch_pci_err(pdev, "pci_request_regions FAILED\n"); + goto err_pci_req; + } + + base_addr = pci_iomap(pdev, 1, 0); + + if (base_addr == NULL) { + pch_pci_err(pdev, "pci_iomap FAILED\n"); + ret = -ENOMEM; + goto err_pci_iomap; + } + + adap_info->pch_i2c_suspended = false; + + adap_info->pch_data.p_adapter_info = adap_info; + + adap_info->pch_data.pch_adapter.owner = THIS_MODULE; + adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON; + strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME); + adap_info->pch_data.pch_adapter.algo = &pch_algorithm; + adap_info->pch_data.pch_adapter.algo_data = + &adap_info->pch_data; + + /* (i * 0x80) + base_addr; */ + adap_info->pch_data.pch_base_address = base_addr; + + adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev; + + ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter)); + + if (ret) { + pch_pci_err(pdev, "i2c_add_adapter FAILED\n"); + goto err_i2c_add_adapter; + } + + pch_i2c_init(&adap_info->pch_data); + ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, + KBUILD_MODNAME, &adap_info->pch_data); + if (ret) { + pch_pci_err(pdev, "request_irq FAILED\n"); + goto err_request_irq; + } + + pci_set_drvdata(pdev, adap_info); + pch_pci_dbg(pdev, "returns %d.\n", ret); + return 0; + +err_request_irq: + i2c_del_adapter(&(adap_info->pch_data.pch_adapter)); +err_i2c_add_adapter: + pci_iounmap(pdev, base_addr); +err_pci_iomap: + pci_release_regions(pdev); +err_pci_req: + pci_disable_device(pdev); +err_pci_enable: + kfree(adap_info); + return ret; +} + +static void __devexit pch_i2c_remove(struct pci_dev *pdev) +{ + struct adapter_info *adap_info = pci_get_drvdata(pdev); + + pch_i2c_disbl_int(&adap_info->pch_data); + free_irq(pdev->irq, &adap_info->pch_data); + i2c_del_adapter(&(adap_info->pch_data.pch_adapter)); + + if (adap_info->pch_data.pch_base_address) { + pci_iounmap(pdev, adap_info->pch_data.pch_base_address); + adap_info->pch_data.pch_base_address = 0; + } + + pci_set_drvdata(pdev, NULL); + + pci_release_regions(pdev); + + pci_disable_device(pdev); + kfree(adap_info); +} + +#ifdef CONFIG_PM +static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int ret; + struct adapter_info *adap_info = pci_get_drvdata(pdev); + void __iomem *p = adap_info->pch_data.pch_base_address; + + adap_info->pch_i2c_suspended = true; + + while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) { + /* Wait until all channel transfers are completed */ + msleep(20); + } + /* Disable the i2c interrupts */ + pch_i2c_disbl_int(&adap_info->pch_data); + + pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x " + "invoked function pch_i2c_disbl_int successfully\n", + ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA), + ioread32(p + PCH_I2CESRSTA)); + + ret = pci_save_state(pdev); + + if (ret) { + pch_pci_err(pdev, "pci_save_state\n"); + return ret; + } + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int pch_i2c_resume(struct pci_dev *pdev) +{ + struct adapter_info *adap_info = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (pci_enable_device(pdev) < 0) { + pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED\n"); + return -EIO; + } + + pci_enable_wake(pdev, PCI_D3hot, 0); + + pch_i2c_init(&adap_info->pch_data); + + adap_info->pch_i2c_suspended = false; + + return 0; +} +#else +#define pch_i2c_suspend NULL +#define pch_i2c_resume NULL +#endif + +static struct pci_driver pch_pcidriver = { + .name = KBUILD_MODNAME, + .id_table = pch_pcidev_id, + .probe = pch_i2c_probe, + .remove = __devexit_p(pch_i2c_remove), + .suspend = pch_i2c_suspend, + .resume = pch_i2c_resume +}; + +static int __init pch_pci_init(void) +{ + return pci_register_driver(&pch_pcidriver); +} +module_init(pch_pci_init); + +static void __exit pch_pci_exit(void) +{ + pci_unregister_driver(&pch_pcidriver); +} +module_exit(pch_pci_exit); + +MODULE_DESCRIPTION("PCH I2C PCI Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tomoya MORINAGA. "); +module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); +module_param(pch_clk, int, (S_IRUSR | S_IWUSR)); -- cgit v1.2.3 From 6a91b558648cffa94227b4ff9c6c996930bbdfd2 Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Thu, 18 Nov 2010 12:04:20 +0200 Subject: i2c-omap: Set latency requirements only once for several messages Ordinary I2C read consist of two messages. First a write operation to tell register address and then read operation to get data. CPU wake up latency is set and removed twice in read case. Set latency requirement before the message processing loop and remove the requirement after the loop to remove latency adjustment operations between the messages. Signed-off-by: Samu Onkalo Acked-by: Kevin Hilman Acked-by: Paul Walmsley Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-omap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b33c78586bfc..3e9323effc7c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -616,12 +616,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, dev->latency); r = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); dev->buf_len = 0; if (r < 0) return r; @@ -672,12 +668,18 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); + for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); if (r != 0) break; } + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); + if (r == 0) r = num; -- cgit v1.2.3 From 6d779a4c3f97023fe329ef33aba25c8aaadf281b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Nov 2010 16:59:29 +0100 Subject: i2c-nomadik: fix regression on adapter name The Nomadik I2C adapter does not provide a name for the struct passed into i2c_add_numbered_adapter() causing a regression on 2.6.37-rc3 due to commit 2236baa75f704851d3cd3310569058151acb1f06 adding sanity checks for adapters. Fix this by providing a name proper. Cc: Jean Delvare Signed-off-by: Linus Walleij Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-nomadik.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index c9fffd0389fe..f7148fdd46e0 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -872,6 +872,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->algo = &nmk_i2c_algo; + snprintf(adap->name, sizeof(adap->name), + "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); /* fetch the controller id */ adap->nr = pdev->id; @@ -891,8 +893,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) goto err_init_hw; } - dev_dbg(&pdev->dev, "initialize I2C%d bus on virtual " - "base %p\n", pdev->id, dev->virtbase); + dev_info(&pdev->dev, "initialize %s on virtual " + "base %p\n", adap->name, dev->virtbase); ret = i2c_add_numbered_adapter(adap); if (ret) { -- cgit v1.2.3 From eda6bee6c7e67b5bd17bdbced0926f5687f686d5 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Fri, 26 Nov 2010 17:06:56 +0100 Subject: i2c-mv64xxx: send repeated START between messages in xfer As stated into file include/linux/i2c.h we must send a repeated START between messages in the same xfer groupset: * Except when I2C "protocol mangling" is used, all I2C adapters implement * the standard rules for I2C transactions. Each transaction begins with a * START. That is followed by the slave address, and a bit encoding read * versus write. Then follow all the data bytes, possibly including a byte * with SMBus PEC. The transfer terminates with a NAK, or when all those * bytes have been transferred and ACKed. If this is the last message in a * group, it is followed by a STOP. Otherwise it is followed by the next * @i2c_msg transaction segment, beginning with a (repeated) START. Signed-off-by: Rodolfo Giometti Signed-off-by: Mauro Barella Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-mv64xxx.c | 45 +++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 16242063144f..a9941c65f226 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -59,6 +59,7 @@ enum { MV64XXX_I2C_STATE_INVALID, MV64XXX_I2C_STATE_IDLE, MV64XXX_I2C_STATE_WAITING_FOR_START_COND, + MV64XXX_I2C_STATE_WAITING_FOR_RESTART, MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, @@ -70,6 +71,7 @@ enum { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, MV64XXX_I2C_ACTION_SEND_START, + MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_SEND_ADDR_1, MV64XXX_I2C_ACTION_SEND_ADDR_2, MV64XXX_I2C_ACTION_SEND_DATA, @@ -91,6 +93,7 @@ struct mv64xxx_i2c_data { u32 addr2; u32 bytes_left; u32 byte_posn; + u32 send_stop; u32 block; int rc; u32 freq_m; @@ -159,8 +162,15 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) if ((drv_data->bytes_left == 0) || (drv_data->aborting && (drv_data->byte_posn != 0))) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; + if (drv_data->send_stop) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; + drv_data->state = MV64XXX_I2C_STATE_IDLE; + } else { + drv_data->action = + MV64XXX_I2C_ACTION_SEND_RESTART; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_RESTART; + } } else { drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; drv_data->state = @@ -228,6 +238,15 @@ static void mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) { switch(drv_data->action) { + case MV64XXX_I2C_ACTION_SEND_RESTART: + drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->block = 0; + wake_up_interruptible(&drv_data->waitq); + break; + case MV64XXX_I2C_ACTION_CONTINUE: writel(drv_data->cntl_bits, drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); @@ -386,7 +405,8 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) } static int -mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) +mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, + int is_first, int is_last) { unsigned long flags; @@ -406,10 +426,18 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) drv_data->bytes_left--; } } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + if (is_first) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + } else { + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; + drv_data->state = + MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; + } } + drv_data->send_stop = is_last; drv_data->block = 1; mv64xxx_i2c_do_action(drv_data); spin_unlock_irqrestore(&drv_data->lock, flags); @@ -437,9 +465,12 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); int i, rc; - for (i=0; i Date: Thu, 11 Nov 2010 22:42:06 -0800 Subject: sparc: explicitly cast negative phandle checks to s32 When we switched sparc from using 'int's to 'phandle's (which is a u32), we neglected to do anything with the various checks for -1. For those tests, explicitly cast the phandles to s32. Signed-off-by: Andres Salomon Acked-by: David S. Miller Signed-off-by: Grant Likely --- arch/sparc/kernel/auxio_32.c | 2 +- arch/sparc/kernel/starfire.c | 2 +- arch/sparc/prom/init_32.c | 2 +- arch/sparc/prom/init_64.c | 4 ++-- arch/sparc/prom/tree_32.c | 19 ++++++++++--------- arch/sparc/prom/tree_64.c | 18 +++++++++--------- drivers/sbus/char/jsflash.c | 2 +- 7 files changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c index 35f48837871a..8505e0ac78ba 100644 --- a/arch/sparc/kernel/auxio_32.c +++ b/arch/sparc/kernel/auxio_32.c @@ -121,7 +121,7 @@ void __init auxio_power_probe(void) node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); node = prom_searchsiblings(node, "power"); - if (node == 0 || node == -1) + if (node == 0 || (s32)node == -1) return; /* Map the power control register. */ diff --git a/arch/sparc/kernel/starfire.c b/arch/sparc/kernel/starfire.c index a4446c0fb7a1..82281a566bb8 100644 --- a/arch/sparc/kernel/starfire.c +++ b/arch/sparc/kernel/starfire.c @@ -24,7 +24,7 @@ int this_is_starfire = 0; void check_if_starfire(void) { phandle ssnode = prom_finddevice("/ssp-serial"); - if (ssnode != 0 && ssnode != -1) + if (ssnode != 0 && (s32)ssnode != -1) this_is_starfire = 1; } diff --git a/arch/sparc/prom/init_32.c b/arch/sparc/prom/init_32.c index d342dba4dd54..0a601b300639 100644 --- a/arch/sparc/prom/init_32.c +++ b/arch/sparc/prom/init_32.c @@ -60,7 +60,7 @@ void __init prom_init(struct linux_romvec *rp) prom_nodeops = romvec->pv_nodeops; prom_root_node = prom_getsibling(0); - if((prom_root_node == 0) || (prom_root_node == -1)) + if ((prom_root_node == 0) || ((s32)prom_root_node == -1)) prom_halt(); if((((unsigned long) prom_nodeops) == 0) || diff --git a/arch/sparc/prom/init_64.c b/arch/sparc/prom/init_64.c index 3ff911e7d25b..200528bb0994 100644 --- a/arch/sparc/prom/init_64.c +++ b/arch/sparc/prom/init_64.c @@ -35,14 +35,14 @@ void __init prom_init(void *cif_handler, void *cif_stack) prom_cif_init(cif_handler, cif_stack); prom_chosen_node = prom_finddevice(prom_chosen_path); - if (!prom_chosen_node || prom_chosen_node == -1) + if (!prom_chosen_node || (s32)prom_chosen_node == -1) prom_halt(); prom_stdin = prom_getint(prom_chosen_node, "stdin"); prom_stdout = prom_getint(prom_chosen_node, "stdout"); node = prom_finddevice("/openprom"); - if (!node || node == -1) + if (!node || (s32)node == -1) prom_halt(); prom_getstring(node, "version", prom_version, sizeof(prom_version)); diff --git a/arch/sparc/prom/tree_32.c b/arch/sparc/prom/tree_32.c index 535e2e69ac1d..f1d0734c245e 100644 --- a/arch/sparc/prom/tree_32.c +++ b/arch/sparc/prom/tree_32.c @@ -40,11 +40,11 @@ phandle prom_getchild(phandle node) { phandle cnode; - if (node == -1) + if ((s32)node == -1) return 0; cnode = __prom_getchild(node); - if (cnode == 0 || cnode == -1) + if (cnode == 0 || (s32)cnode == -1) return 0; return cnode; @@ -72,11 +72,11 @@ phandle prom_getsibling(phandle node) { phandle sibnode; - if (node == -1) + if ((s32)node == -1) return 0; sibnode = __prom_getsibling(node); - if (sibnode == 0 || sibnode == -1) + if (sibnode == 0 || (s32)sibnode == -1) return 0; return sibnode; @@ -231,7 +231,7 @@ char *__prom_nextprop(phandle node, char * oprop) /* buffer is unused argument, but as v9 uses it, we need to have the same interface */ char *prom_firstprop(phandle node, char *bufer) { - if (node == 0 || node == -1) + if (node == 0 || (s32)node == -1) return ""; return __prom_nextprop(node, ""); @@ -244,7 +244,7 @@ EXPORT_SYMBOL(prom_firstprop); */ char *prom_nextprop(phandle node, char *oprop, char *buffer) { - if (node == 0 || node == -1) + if (node == 0 || (s32)node == -1) return ""; return __prom_nextprop(node, oprop); @@ -278,7 +278,7 @@ phandle prom_finddevice(char *name) if (d != s + 3 && (!*d || *d == '/') && d <= s + 3 + 8) { node2 = node; - while (node2 && node2 != -1) { + while (node2 && (s32)node2 != -1) { if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { node = node2; @@ -286,7 +286,7 @@ phandle prom_finddevice(char *name) } } node2 = prom_getsibling(node2); - if (!node2 || node2 == -1) + if (!node2 || (s32)node2 == -1) break; node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); } @@ -339,6 +339,7 @@ phandle prom_inst2pkg(int inst) node = (*romvec->pv_v2devops.v2_inst2pkg)(inst); restore_current(); spin_unlock_irqrestore(&prom_lock, flags); - if (node == -1) return 0; + if ((s32)node == -1) + return 0; return node; } diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index d93660048376..92204c3800b5 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -43,10 +43,10 @@ inline phandle prom_getchild(phandle node) { phandle cnode; - if (node == -1) + if ((s32)node == -1) return 0; cnode = __prom_getchild(node); - if (cnode == -1) + if ((s32)cnode == -1) return 0; return cnode; } @@ -56,10 +56,10 @@ inline phandle prom_getparent(phandle node) { phandle cnode; - if (node == -1) + if ((s32)node == -1) return 0; cnode = prom_node_to_node("parent", node); - if (cnode == -1) + if ((s32)cnode == -1) return 0; return cnode; } @@ -76,10 +76,10 @@ inline phandle prom_getsibling(phandle node) { phandle sibnode; - if (node == -1) + if ((s32)node == -1) return 0; sibnode = __prom_getsibling(node); - if (sibnode == -1) + if ((s32)sibnode == -1) return 0; return sibnode; @@ -240,7 +240,7 @@ inline char *prom_firstprop(phandle node, char *buffer) unsigned long args[7]; *buffer = 0; - if (node == -1) + if ((s32)node == -1) return buffer; args[0] = (unsigned long) prom_nextprop_name; @@ -266,7 +266,7 @@ inline char *prom_nextprop(phandle node, const char *oprop, char *buffer) unsigned long args[7]; char buf[32]; - if (node == -1) { + if ((s32)node == -1) { *buffer = 0; return buffer; } @@ -369,7 +369,7 @@ inline phandle prom_inst2pkg(int inst) p1275_cmd_direct(args); node = (int) args[4]; - if (node == -1) + if ((s32)node == -1) return 0; return node; } diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index a624f5af4320..e8566224fe4b 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -467,7 +467,7 @@ static int jsflash_init(void) node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "flash-memory"); - if (node != 0 && node != -1) { + if (node != 0 && (s32)node != -1) { if (prom_getproperty(node, "reg", (char *)®0, sizeof(reg0)) == -1) { printk("jsflash: no \"reg\" property\n"); -- cgit v1.2.3 From 672d8eafe38e9324055b8c0d0ad6e95c43b6d52a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 16 Nov 2010 14:33:51 -0600 Subject: ipmi: explicitly include of_address.h and of_irq.h of_address.h and of_irq.h are implicitly included on powerpc. Adding them fixes builds on non-powerpc platforms. Signed-off-by: Rob Herring Signed-off-by: Grant Likely --- drivers/char/ipmi/ipmi_si_intf.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 8cc4607cc86c..f27c04e18aaa 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -69,6 +69,8 @@ #ifdef CONFIG_PPC_OF #include #include +#include +#include #endif #define PFX "ipmi_si: " -- cgit v1.2.3 From 78dec56d6a56322e1b728d51f3a7def416d36b34 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 1 Jan 2011 15:15:40 +0100 Subject: firewire: ohci: flush AT contexts after bus reset - addendum Add comments - on why bus_reset_tasklet flushes AT queues, - that commit 76f73ca1b291 can possibly be reverted now. Signed-off-by: Stefan Richter Acked-by: Jarod Wilson --- drivers/firewire/ohci.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 3372cd187c25..cfe5afe359c6 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1336,6 +1336,8 @@ static int at_context_queue_packet(struct context *ctx, * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind * up stalling out. So we just bail out in software and try again * later, and everyone is happy. + * FIXME: Test of IntEvent.busReset may no longer be necessary since we + * flush AT queues in bus_reset_tasklet. * FIXME: Document how the locking works. */ if (ohci->generation != packet->generation || @@ -1750,6 +1752,11 @@ static void bus_reset_tasklet(unsigned long data) spin_unlock_irqrestore(&ohci->lock, flags); + /* + * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent + * packets in the AT queues and software needs to drain them. + * Some OHCI 1.1 controllers (JMicron) apparently require this too. + */ at_context_flush(&ohci->at_request_ctx); at_context_flush(&ohci->at_response_ctx); -- cgit v1.2.3 From 386a4153a2c1455e424f280d636efa3c91864466 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 24 Dec 2010 14:42:46 +0100 Subject: firewire: ohci: cache the context run bit The DMA context run control bit is entirely controlled by software, so it is safe to cache it. This allows the driver to avoid doing an additional MMIO read when queueing an AT packet. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index cfe5afe359c6..3ae84e2c5192 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -125,6 +125,7 @@ struct context { struct fw_ohci *ohci; u32 regs; int total_allocation; + bool running; bool flushing; /* @@ -1174,6 +1175,7 @@ static void context_run(struct context *ctx, u32 extra) le32_to_cpu(ctx->last->branch_address)); reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0); reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra); + ctx->running = true; flush_writes(ohci); } @@ -1202,6 +1204,7 @@ static void context_stop(struct context *ctx) ctx->active = false; reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + ctx->running = false; flush_writes(ctx->ohci); for (i = 0; i < 10; i++) { @@ -1232,7 +1235,6 @@ static int at_context_queue_packet(struct context *ctx, struct descriptor *d, *last; __le32 *header; int z, tcode; - u32 reg; d = context_get_descriptors(ctx, 4, &d_bus); if (d == NULL) { @@ -1351,9 +1353,7 @@ static int at_context_queue_packet(struct context *ctx, context_append(ctx, d, z, 4 - z); - /* If the context isn't already running, start it up. */ - reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); - if ((reg & CONTEXT_RUN) == 0) + if (!ctx->running) context_run(ctx, 0); return 0; -- cgit v1.2.3 From 693a50b511818e07a131efc944cba1a504b63d3d Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 1 Jan 2011 15:17:05 +0100 Subject: firewire: ohci: consolidate context status flags "firewire: ohci: restart iso DMA contexts on resume from low power mode" added the flag struct context.active and "firewire: ohci: cache the context run bit" added struct context.running. These flags contain the same information; combine them. Also, normalize whitespace in pci_resume(). Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 3ae84e2c5192..d77d120ddc25 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -156,7 +156,6 @@ struct context { descriptor_callback_t callback; struct tasklet_struct tasklet; - bool active; }; #define IT_HEADER_SY(v) ((v) << 0) @@ -1169,7 +1168,6 @@ static struct descriptor *context_get_descriptors(struct context *ctx, static void context_run(struct context *ctx, u32 extra) { struct fw_ohci *ohci = ctx->ohci; - ctx->active = true; reg_write(ohci, COMMAND_PTR(ctx->regs), le32_to_cpu(ctx->last->branch_address)); @@ -1202,7 +1200,6 @@ static void context_stop(struct context *ctx) u32 reg; int i; - ctx->active = false; reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); ctx->running = false; flush_writes(ctx->ohci); @@ -2797,13 +2794,13 @@ static void ohci_resume_iso_dma(struct fw_ohci *ohci) for (i = 0 ; i < ohci->n_ir ; i++) { ctx = &ohci->ir_context_list[i]; - if (ctx->context.active) + if (ctx->context.running) ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); } for (i = 0 ; i < ohci->n_it ; i++) { ctx = &ohci->it_context_list[i]; - if (ctx->context.active) + if (ctx->context.running) ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); } } @@ -3363,11 +3360,11 @@ static int pci_resume(struct pci_dev *dev) } err = ohci_enable(&ohci->card, NULL, 0); - if (err) return err; ohci_resume_iso_dma(ohci); + return 0; } #endif -- cgit v1.2.3 From 410cf2bd3dc6ec1ed9e1b36b25b9d7aa927ed14e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 13 Dec 2010 14:56:02 +0100 Subject: firewire: use split transaction timeout only for split transactions Instead of starting the split transaction timeout timer when any request is submitted, start it only when the destination's ACK_PENDING has been received. This prevents us from using a timeout that is too short, and, if the controller's AT queue is emptying very slowly, from cancelling a packet that has not yet been sent. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/core-transaction.c | 45 ++++++++++++++++++++++++++----------- include/linux/firewire.h | 2 +- 2 files changed, 33 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 9e81cc54abd2..d00f8ce902cc 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -72,6 +72,15 @@ #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) #define PHY_IDENTIFIER(id) ((id) << 30) +/* returns 0 if the split timeout handler is already running */ +static int try_cancel_split_timeout(struct fw_transaction *t) +{ + if (t->is_split_transaction) + return del_timer(&t->split_timeout_timer); + else + return 1; +} + static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode) { @@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction, spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t == transaction) { - if (!del_timer(&t->split_timeout_timer)) { + if (!try_cancel_split_timeout(t)) { spin_unlock_irqrestore(&card->lock, flags); goto timed_out; } @@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data) card->tlabel_mask &= ~(1ULL << t->tlabel); spin_unlock_irqrestore(&card->lock, flags); - card->driver->cancel_packet(card, &t->packet); - - /* - * At this point cancel_packet will never call the transaction - * callback, since we just took the transaction out of the list. - * So do it here. - */ t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); } +static void start_split_transaction_timeout(struct fw_transaction *t, + struct fw_card *card) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) { + spin_unlock_irqrestore(&card->lock, flags); + return; + } + + t->is_split_transaction = true; + mod_timer(&t->split_timeout_timer, + jiffies + card->split_timeout_jiffies); + + spin_unlock_irqrestore(&card->lock, flags); +} + static void transmit_complete_callback(struct fw_packet *packet, struct fw_card *card, int status) { @@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet, close_transaction(t, card, RCODE_COMPLETE); break; case ACK_PENDING: - t->timestamp = packet->timestamp; + start_split_transaction_timeout(t, card); break; case ACK_BUSY_X: case ACK_BUSY_A: @@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, t->node_id = destination_id; t->tlabel = tlabel; t->card = card; + t->is_split_transaction = false; setup_timer(&t->split_timeout_timer, split_transaction_timeout_callback, (unsigned long)t); - /* FIXME: start this timer later, relative to t->timestamp */ - mod_timer(&t->split_timeout_timer, - jiffies + card->split_timeout_jiffies); t->callback = callback; t->callback_data = callback_data; @@ -926,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t->node_id == source && t->tlabel == tlabel) { - if (!del_timer(&t->split_timeout_timer)) { + if (!try_cancel_split_timeout(t)) { spin_unlock_irqrestore(&card->lock, flags); goto timed_out; } diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 1cd637ef62d2..9a3f5f9383f6 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -302,9 +302,9 @@ struct fw_packet { struct fw_transaction { int node_id; /* The generation is implied; it is always the current. */ int tlabel; - int timestamp; struct list_head link; struct fw_card *card; + bool is_split_transaction; struct timer_list split_timeout_timer; struct fw_packet packet; -- cgit v1.2.3 From ae5e49c79c051ea1d5ca91cbd4a0d22189067ba3 Mon Sep 17 00:00:00 2001 From: Alan Ott Date: Tue, 4 Jan 2011 00:37:22 -0500 Subject: HID: hidraw: add compatibility ioctl() for 32-bit applications. Added the ioctl function to the compat_ioctl pointer in the file_operations struct. Before this, some ioctls would fail for 32-bit apps on 64-bit systems. Signed-off-by: Alan Ott Acked-by: Arnd Bergmann Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 68d087f63c02..468e87b53ed2 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -344,6 +344,9 @@ static const struct file_operations hidraw_ops = { .open = hidraw_open, .release = hidraw_release, .unlocked_ioctl = hidraw_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = hidraw_ioctl, +#endif .llseek = noop_llseek, }; -- cgit v1.2.3 From 41f2977d40798ce45f4da7a1291039ffbe9e1dbc Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 4 Jan 2011 15:37:16 +1100 Subject: crypto: mv_cesa - dont return PTR_ERR() of wrong pointer Fix a PTR_ERR() return of the wrong pointer Signed-off-by: Roel Kluin Signed-off-by: Herbert Xu --- drivers/crypto/mv_cesa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 7d279e578df5..c99305afa58a 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -857,7 +857,7 @@ static int mv_cra_hash_init(struct crypto_tfm *tfm, const char *base_hash_name, printk(KERN_WARNING MV_CESA "Base driver '%s' could not be loaded!\n", base_hash_name); - err = PTR_ERR(fallback_tfm); + err = PTR_ERR(base_hash); goto err_bad_base; } } -- cgit v1.2.3 From 17db7042b7ff77a4ae8b83ab42ec8286a9715a48 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 21 Dec 2010 16:05:39 -0500 Subject: drm/radeon/kms: implement gpu lockup check for evergreen Now that soft reset works, we can add this. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 26 ++++++++++++++++++++++++-- drivers/gpu/drm/radeon/radeon.h | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ec641ce64764..3ae63ceb9c33 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2085,8 +2085,30 @@ int evergreen_mc_init(struct radeon_device *rdev) bool evergreen_gpu_is_lockup(struct radeon_device *rdev) { - /* FIXME: implement for evergreen */ - return false; + u32 srbm_status; + u32 grbm_status; + u32 grbm_status_se0, grbm_status_se1; + struct r100_gpu_lockup *lockup = &rdev->config.evergreen.lockup; + int r; + + srbm_status = RREG32(SRBM_STATUS); + grbm_status = RREG32(GRBM_STATUS); + grbm_status_se0 = RREG32(GRBM_STATUS_SE0); + grbm_status_se1 = RREG32(GRBM_STATUS_SE1); + if (!(grbm_status & GUI_ACTIVE)) { + r100_gpu_lockup_update(lockup, &rdev->cp); + return false; + } + /* force CP activities */ + r = radeon_ring_lock(rdev, 2); + if (!r) { + /* PACKET2 NOP */ + radeon_ring_write(rdev, 0x80000000); + radeon_ring_write(rdev, 0x80000000); + radeon_ring_unlock_commit(rdev); + } + rdev->cp.rptr = RREG32(CP_RB_RPTR); + return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp); } static int evergreen_gpu_soft_reset(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 431d4186ddf0..d2697f8f2da8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1031,6 +1031,7 @@ struct evergreen_asic { unsigned tiling_npipes; unsigned tiling_group_size; unsigned tile_config; + struct r100_gpu_lockup lockup; }; union radeon_asic_config { -- cgit v1.2.3 From d49278e3351b34870cbffffc5067348a318e7b06 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 20 Dec 2010 18:31:38 +0100 Subject: dmaengine: dma40: Add support to split up large elements The maximum transfer size of the stedma40 is (64k-1) x data-width. If the transfer size of one element exceeds this limit the job is split up and sent as linked transfer. Signed-off-by: Per Forlin Signed-off-by: Dan Williams --- arch/arm/plat-nomadik/include/plat/ste_dma40.h | 8 + drivers/dma/ste_dma40.c | 191 +++++++++++++++---- drivers/dma/ste_dma40_ll.c | 246 +++++++++++++++++-------- drivers/dma/ste_dma40_ll.h | 36 ++-- 4 files changed, 351 insertions(+), 130 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h index 74b62f10d07f..4d6dd4c39b75 100644 --- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h +++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h @@ -13,6 +13,14 @@ #include #include +/* + * Maxium size for a single dma descriptor + * Size is limited to 16 bits. + * Size is in the units of addr-widths (1,2,4,8 bytes) + * Larger transfers will be split up to multiple linked desc + */ +#define STEDMA40_MAX_SEG_SIZE 0xFFFF + /* dev types for memcpy */ #define STEDMA40_DEV_DST_MEMORY (-1) #define STEDMA40_DEV_SRC_MEMORY (-1) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index fab68a553205..6e1d46a65d0e 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1,5 +1,6 @@ /* - * Copyright (C) ST-Ericsson SA 2007-2010 + * Copyright (C) Ericsson AB 2007-2008 + * Copyright (C) ST-Ericsson SA 2008-2010 * Author: Per Forlin for ST-Ericsson * Author: Jonas Aaberg for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 @@ -554,8 +555,66 @@ static struct d40_desc *d40_last_queued(struct d40_chan *d40c) return d; } -/* Support functions for logical channels */ +static int d40_psize_2_burst_size(bool is_log, int psize) +{ + if (is_log) { + if (psize == STEDMA40_PSIZE_LOG_1) + return 1; + } else { + if (psize == STEDMA40_PSIZE_PHY_1) + return 1; + } + + return 2 << psize; +} + +/* + * The dma only supports transmitting packages up to + * STEDMA40_MAX_SEG_SIZE << data_width. Calculate the total number of + * dma elements required to send the entire sg list + */ +static int d40_size_2_dmalen(int size, u32 data_width1, u32 data_width2) +{ + int dmalen; + u32 max_w = max(data_width1, data_width2); + u32 min_w = min(data_width1, data_width2); + u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w); + + if (seg_max > STEDMA40_MAX_SEG_SIZE) + seg_max -= (1 << max_w); + + if (!IS_ALIGNED(size, 1 << max_w)) + return -EINVAL; + + if (size <= seg_max) + dmalen = 1; + else { + dmalen = size / seg_max; + if (dmalen * seg_max < size) + dmalen++; + } + return dmalen; +} + +static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len, + u32 data_width1, u32 data_width2) +{ + struct scatterlist *sg; + int i; + int len = 0; + int ret; + + for_each_sg(sgl, sg, sg_len, i) { + ret = d40_size_2_dmalen(sg_dma_len(sg), + data_width1, data_width2); + if (ret < 0) + return ret; + len += ret; + } + return len; +} +/* Support functions for logical channels */ static int d40_channel_execute_command(struct d40_chan *d40c, enum d40_command command) @@ -1241,6 +1300,21 @@ static int d40_validate_conf(struct d40_chan *d40c, res = -EINVAL; } + if (d40_psize_2_burst_size(is_log, conf->src_info.psize) * + (1 << conf->src_info.data_width) != + d40_psize_2_burst_size(is_log, conf->dst_info.psize) * + (1 << conf->dst_info.data_width)) { + /* + * The DMAC hardware only supports + * src (burst x width) == dst (burst x width) + */ + + dev_err(&d40c->chan.dev->device, + "[%s] src (burst x width) != dst (burst x width)\n", + __func__); + res = -EINVAL; + } + return res; } @@ -1638,13 +1712,21 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, if (d40d == NULL) goto err; - d40d->lli_len = sgl_len; + d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len, + d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width); + if (d40d->lli_len < 0) { + dev_err(&d40c->chan.dev->device, + "[%s] Unaligned size\n", __func__); + goto err; + } + d40d->lli_current = 0; d40d->txd.flags = dma_flags; if (d40c->log_num != D40_PHY_CHAN) { - if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) { + if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; @@ -1654,15 +1736,17 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, sgl_len, d40d->lli_log.src, d40c->log_def.lcsp1, - d40c->dma_cfg.src_info.data_width); + d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width); (void) d40_log_sg_to_lli(sgl_dst, sgl_len, d40d->lli_log.dst, d40c->log_def.lcsp3, - d40c->dma_cfg.dst_info.data_width); + d40c->dma_cfg.dst_info.data_width, + d40c->dma_cfg.src_info.data_width); } else { - if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) { + if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; @@ -1675,6 +1759,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, virt_to_phys(d40d->lli_phy.src), d40c->src_def_cfg, d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width, d40c->dma_cfg.src_info.psize); if (res < 0) @@ -1687,6 +1772,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, virt_to_phys(d40d->lli_phy.dst), d40c->dst_def_cfg, d40c->dma_cfg.dst_info.data_width, + d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.psize); if (res < 0) @@ -1826,7 +1912,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); unsigned long flags; - int err = 0; if (d40c->phy_chan == NULL) { dev_err(&d40c->chan.dev->device, @@ -1844,6 +1929,15 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, } d40d->txd.flags = dma_flags; + d40d->lli_len = d40_size_2_dmalen(size, + d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width); + if (d40d->lli_len < 0) { + dev_err(&d40c->chan.dev->device, + "[%s] Unaligned size\n", __func__); + goto err; + } + dma_async_tx_descriptor_init(&d40d->txd, chan); @@ -1851,37 +1945,40 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, if (d40c->log_num != D40_PHY_CHAN) { - if (d40_pool_lli_alloc(d40d, 1, true) < 0) { + if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; } - d40d->lli_len = 1; d40d->lli_current = 0; - d40_log_fill_lli(d40d->lli_log.src, - src, - size, - d40c->log_def.lcsp1, - d40c->dma_cfg.src_info.data_width, - true); + if (d40_log_buf_to_lli(d40d->lli_log.src, + src, + size, + d40c->log_def.lcsp1, + d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width, + true) == NULL) + goto err; - d40_log_fill_lli(d40d->lli_log.dst, - dst, - size, - d40c->log_def.lcsp3, - d40c->dma_cfg.dst_info.data_width, - true); + if (d40_log_buf_to_lli(d40d->lli_log.dst, + dst, + size, + d40c->log_def.lcsp3, + d40c->dma_cfg.dst_info.data_width, + d40c->dma_cfg.src_info.data_width, + true) == NULL) + goto err; } else { - if (d40_pool_lli_alloc(d40d, 1, false) < 0) { + if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; } - err = d40_phy_fill_lli(d40d->lli_phy.src, + if (d40_phy_buf_to_lli(d40d->lli_phy.src, src, size, d40c->dma_cfg.src_info.psize, @@ -1889,11 +1986,11 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40c->src_def_cfg, true, d40c->dma_cfg.src_info.data_width, - false); - if (err) - goto err_fill_lli; + d40c->dma_cfg.dst_info.data_width, + false) == NULL) + goto err; - err = d40_phy_fill_lli(d40d->lli_phy.dst, + if (d40_phy_buf_to_lli(d40d->lli_phy.dst, dst, size, d40c->dma_cfg.dst_info.psize, @@ -1901,10 +1998,9 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40c->dst_def_cfg, true, d40c->dma_cfg.dst_info.data_width, - false); - - if (err) - goto err_fill_lli; + d40c->dma_cfg.src_info.data_width, + false) == NULL) + goto err; (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src, d40d->lli_pool.size, DMA_TO_DEVICE); @@ -1913,9 +2009,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, spin_unlock_irqrestore(&d40c->lock, flags); return &d40d->txd; -err_fill_lli: - dev_err(&d40c->chan.dev->device, - "[%s] Failed filling in PHY LLI\n", __func__); err: if (d40d) d40_desc_free(d40c, d40d); @@ -1945,13 +2038,21 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, dma_addr_t dev_addr = 0; int total_size; - if (d40_pool_lli_alloc(d40d, sg_len, true) < 0) { + d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len, + d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width); + if (d40d->lli_len < 0) { + dev_err(&d40c->chan.dev->device, + "[%s] Unaligned size\n", __func__); + return -EINVAL; + } + + if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); return -ENOMEM; } - d40d->lli_len = sg_len; d40d->lli_current = 0; if (direction == DMA_FROM_DEVICE) @@ -1993,13 +2094,21 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, dma_addr_t dst_dev_addr; int res; - if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) { + d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len, + d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width); + if (d40d->lli_len < 0) { + dev_err(&d40c->chan.dev->device, + "[%s] Unaligned size\n", __func__); + return -EINVAL; + } + + if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); return -ENOMEM; } - d40d->lli_len = sgl_len; d40d->lli_current = 0; if (direction == DMA_FROM_DEVICE) { @@ -2024,6 +2133,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, virt_to_phys(d40d->lli_phy.src), d40c->src_def_cfg, d40c->dma_cfg.src_info.data_width, + d40c->dma_cfg.dst_info.data_width, d40c->dma_cfg.src_info.psize); if (res < 0) return res; @@ -2035,6 +2145,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, virt_to_phys(d40d->lli_phy.dst), d40c->dst_def_cfg, d40c->dma_cfg.dst_info.data_width, + d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.psize); if (res < 0) return res; @@ -2244,6 +2355,8 @@ static void d40_set_runtime_config(struct dma_chan *chan, psize = STEDMA40_PSIZE_PHY_8; else if (config_maxburst >= 4) psize = STEDMA40_PSIZE_PHY_4; + else if (config_maxburst >= 2) + psize = STEDMA40_PSIZE_PHY_2; else psize = STEDMA40_PSIZE_PHY_1; } diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 8557cb88b255..0b096a38322d 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -1,6 +1,6 @@ /* * Copyright (C) ST-Ericsson SA 2007-2010 - * Author: Per Friden for ST-Ericsson + * Author: Per Forlin for ST-Ericsson * Author: Jonas Aaberg for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 */ @@ -122,15 +122,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg, *dst_cfg = dst; } -int d40_phy_fill_lli(struct d40_phy_lli *lli, - dma_addr_t data, - u32 data_size, - int psize, - dma_addr_t next_lli, - u32 reg_cfg, - bool term_int, - u32 data_width, - bool is_device) +static int d40_phy_fill_lli(struct d40_phy_lli *lli, + dma_addr_t data, + u32 data_size, + int psize, + dma_addr_t next_lli, + u32 reg_cfg, + bool term_int, + u32 data_width, + bool is_device) { int num_elems; @@ -139,13 +139,6 @@ int d40_phy_fill_lli(struct d40_phy_lli *lli, else num_elems = 2 << psize; - /* - * Size is 16bit. data_width is 8, 16, 32 or 64 bit - * Block large than 64 KiB must be split. - */ - if (data_size > (0xffff << data_width)) - return -EINVAL; - /* Must be aligned */ if (!IS_ALIGNED(data, 0x1 << data_width)) return -EINVAL; @@ -187,55 +180,118 @@ int d40_phy_fill_lli(struct d40_phy_lli *lli, return 0; } +static int d40_seg_size(int size, int data_width1, int data_width2) +{ + u32 max_w = max(data_width1, data_width2); + u32 min_w = min(data_width1, data_width2); + u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w); + + if (seg_max > STEDMA40_MAX_SEG_SIZE) + seg_max -= (1 << max_w); + + if (size <= seg_max) + return size; + + if (size <= 2 * seg_max) + return ALIGN(size / 2, 1 << max_w); + + return seg_max; +} + +struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, + dma_addr_t addr, + u32 size, + int psize, + dma_addr_t lli_phys, + u32 reg_cfg, + bool term_int, + u32 data_width1, + u32 data_width2, + bool is_device) +{ + int err; + dma_addr_t next = lli_phys; + int size_rest = size; + int size_seg = 0; + + do { + size_seg = d40_seg_size(size_rest, data_width1, data_width2); + size_rest -= size_seg; + + if (term_int && size_rest == 0) + next = 0; + else + next = ALIGN(next + sizeof(struct d40_phy_lli), + D40_LLI_ALIGN); + + err = d40_phy_fill_lli(lli, + addr, + size_seg, + psize, + next, + reg_cfg, + !next, + data_width1, + is_device); + + if (err) + goto err; + + lli++; + if (!is_device) + addr += size_seg; + } while (size_rest); + + return lli; + + err: + return NULL; +} + int d40_phy_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t target, - struct d40_phy_lli *lli, + struct d40_phy_lli *lli_sg, dma_addr_t lli_phys, u32 reg_cfg, - u32 data_width, + u32 data_width1, + u32 data_width2, int psize) { int total_size = 0; int i; struct scatterlist *current_sg = sg; - dma_addr_t next_lli_phys; dma_addr_t dst; - int err = 0; + struct d40_phy_lli *lli = lli_sg; + dma_addr_t l_phys = lli_phys; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); - /* If this scatter list entry is the last one, no next link */ - if (sg_len - 1 == i) - next_lli_phys = 0; - else - next_lli_phys = ALIGN(lli_phys + (i + 1) * - sizeof(struct d40_phy_lli), - D40_LLI_ALIGN); - if (target) dst = target; else dst = sg_phys(current_sg); - err = d40_phy_fill_lli(&lli[i], - dst, - sg_dma_len(current_sg), - psize, - next_lli_phys, - reg_cfg, - !next_lli_phys, - data_width, - target == dst); - if (err) - goto err; + l_phys = ALIGN(lli_phys + (lli - lli_sg) * + sizeof(struct d40_phy_lli), D40_LLI_ALIGN); + + lli = d40_phy_buf_to_lli(lli, + dst, + sg_dma_len(current_sg), + psize, + l_phys, + reg_cfg, + sg_len - 1 == i, + data_width1, + data_width2, + target == dst); + if (lli == NULL) + return -EINVAL; } return total_size; -err: - return err; } @@ -315,17 +371,20 @@ void d40_log_lli_lcla_write(struct d40_log_lli *lcla, writel(lli_dst->lcsp13, &lcla[1].lcsp13); } -void d40_log_fill_lli(struct d40_log_lli *lli, - dma_addr_t data, u32 data_size, - u32 reg_cfg, - u32 data_width, - bool addr_inc) +static void d40_log_fill_lli(struct d40_log_lli *lli, + dma_addr_t data, u32 data_size, + u32 reg_cfg, + u32 data_width, + bool addr_inc) { lli->lcsp13 = reg_cfg; /* The number of elements to transfer */ lli->lcsp02 = ((data_size >> data_width) << D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK; + + BUG_ON((data_size >> data_width) > STEDMA40_MAX_SEG_SIZE); + /* 16 LSBs address of the current element */ lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK; /* 16 MSBs address of the current element */ @@ -348,55 +407,94 @@ int d40_log_sg_to_dev(struct scatterlist *sg, int total_size = 0; struct scatterlist *current_sg = sg; int i; + struct d40_log_lli *lli_src = lli->src; + struct d40_log_lli *lli_dst = lli->dst; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); if (direction == DMA_TO_DEVICE) { - d40_log_fill_lli(&lli->src[i], - sg_phys(current_sg), - sg_dma_len(current_sg), - lcsp->lcsp1, src_data_width, - true); - d40_log_fill_lli(&lli->dst[i], - dev_addr, - sg_dma_len(current_sg), - lcsp->lcsp3, dst_data_width, - false); + lli_src = + d40_log_buf_to_lli(lli_src, + sg_phys(current_sg), + sg_dma_len(current_sg), + lcsp->lcsp1, src_data_width, + dst_data_width, + true); + lli_dst = + d40_log_buf_to_lli(lli_dst, + dev_addr, + sg_dma_len(current_sg), + lcsp->lcsp3, dst_data_width, + src_data_width, + false); } else { - d40_log_fill_lli(&lli->dst[i], - sg_phys(current_sg), - sg_dma_len(current_sg), - lcsp->lcsp3, dst_data_width, - true); - d40_log_fill_lli(&lli->src[i], - dev_addr, - sg_dma_len(current_sg), - lcsp->lcsp1, src_data_width, - false); + lli_dst = + d40_log_buf_to_lli(lli_dst, + sg_phys(current_sg), + sg_dma_len(current_sg), + lcsp->lcsp3, dst_data_width, + src_data_width, + true); + lli_src = + d40_log_buf_to_lli(lli_src, + dev_addr, + sg_dma_len(current_sg), + lcsp->lcsp1, src_data_width, + dst_data_width, + false); } } return total_size; } +struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, + dma_addr_t addr, + int size, + u32 lcsp13, /* src or dst*/ + u32 data_width1, + u32 data_width2, + bool addr_inc) +{ + struct d40_log_lli *lli = lli_sg; + int size_rest = size; + int size_seg = 0; + + do { + size_seg = d40_seg_size(size_rest, data_width1, data_width2); + size_rest -= size_seg; + + d40_log_fill_lli(lli, + addr, + size_seg, + lcsp13, data_width1, + addr_inc); + if (addr_inc) + addr += size_seg; + lli++; + } while (size_rest); + + return lli; +} + int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ - u32 data_width) + u32 data_width1, u32 data_width2) { int total_size = 0; struct scatterlist *current_sg = sg; int i; + struct d40_log_lli *lli = lli_sg; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); - - d40_log_fill_lli(&lli_sg[i], - sg_phys(current_sg), - sg_dma_len(current_sg), - lcsp13, data_width, - true); + lli = d40_log_buf_to_lli(lli, + sg_phys(current_sg), + sg_dma_len(current_sg), + lcsp13, + data_width1, data_width2, true); } return total_size; } diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 9e419b907544..9cc43495bea2 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -292,18 +292,20 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli, dma_addr_t lli_phys, u32 reg_cfg, - u32 data_width, + u32 data_width1, + u32 data_width2, int psize); -int d40_phy_fill_lli(struct d40_phy_lli *lli, - dma_addr_t data, - u32 data_size, - int psize, - dma_addr_t next_lli, - u32 reg_cfg, - bool term_int, - u32 data_width, - bool is_device); +struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, + dma_addr_t data, + u32 data_size, + int psize, + dma_addr_t next_lli, + u32 reg_cfg, + bool term_int, + u32 data_width1, + u32 data_width2, + bool is_device); void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, @@ -312,12 +314,12 @@ void d40_phy_lli_write(void __iomem *virtbase, /* Logical channels */ -void d40_log_fill_lli(struct d40_log_lli *lli, - dma_addr_t data, - u32 data_size, - u32 reg_cfg, - u32 data_width, - bool addr_inc); +struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, + dma_addr_t addr, + int size, + u32 lcsp13, /* src or dst*/ + u32 data_width1, u32 data_width2, + bool addr_inc); int d40_log_sg_to_dev(struct scatterlist *sg, int sg_len, @@ -332,7 +334,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ - u32 data_width); + u32 data_width1, u32 data_width2); void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, -- cgit v1.2.3 From e8b5e11df3d02e7bbd85c025cc705a8e67746f73 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:30:24 +0000 Subject: ARM: PL08x: fix spelling errors Correct mis-spellings in comments and printk strings. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index b605cc9ac3a2..3da49ed5f800 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -19,7 +19,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The full GNU General Public License is iin this distribution in the + * The full GNU General Public License is in this distribution in the * file called COPYING. * * Documentation: ARM DDI 0196G == PL080 @@ -82,7 +82,7 @@ /** * struct vendor_data - vendor-specific config parameters - * for PL08x derivates + * for PL08x derivatives * @name: the name of this specific variant * @channels: the number of channels available in this variant * @dualmaster: whether this version supports dual AHB masters @@ -96,10 +96,8 @@ struct vendor_data { /* * PL08X private data structures - * An LLI struct - see pl08x TRM - * Note that next uses bit[0] as a bus bit, - * start & end do not - their bus bit info - * is in cctl + * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit, + * start & end do not - their bus bit info is in cctl. */ struct lli { dma_addr_t src; @@ -152,7 +150,7 @@ struct pl08x_driver_data { /* Size (bytes) of each LLI buffer allocated for one transfer */ # define PL08X_LLI_TSFR_SIZE 0x2000 -/* Maximimum times we call dma_pool_alloc on this pool without freeing */ +/* Maximum times we call dma_pool_alloc on this pool without freeing */ #define PL08X_MAX_ALLOCS 0x40 #define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli)) #define PL08X_ALIGN 8 @@ -177,7 +175,7 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch) /* * Set the initial DMA register values i.e. those for the first LLI - * The next lli pointer and the configuration interrupt bit have + * The next LLI pointer and the configuration interrupt bit have * been set when the LLIs were constructed */ static void pl08x_set_cregs(struct pl08x_driver_data *pl08x, @@ -366,8 +364,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) while (clli) { bytes += get_bytes_in_cctl(llis_va[i].cctl); /* - * A clli of 0x00000000 will terminate the - * LLI list + * A LLI pointer of 0 terminates the LLI list */ clli = llis_va[i].next; i++; @@ -469,7 +466,7 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, { u32 retbits = cctl; - /* Remove all src, dst and transfersize bits */ + /* Remove all src, dst and transfer size bits */ retbits &= ~PL080_CONTROL_DWIDTH_MASK; retbits &= ~PL080_CONTROL_SWIDTH_MASK; retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK; @@ -701,7 +698,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * Choose bus to align to * - prefers destination bus if both available * - if fixed address on one bus chooses other - * - modifies cctl to choose an apropriate master + * - modifies cctl to choose an appropriate master */ pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, &mbus, &sbus, cctl); @@ -775,7 +772,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, target_len = max_bytes_per_lli; /* - * Set bus lengths for incrementing busses + * Set bus lengths for incrementing buses * to number of bytes which fill to next memory * boundary */ @@ -826,7 +823,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * So now we know how many bytes to transfer * to get to the nearest boundary - * The next lli will past the boundary + * The next LLI will past the boundary * - however we may be working to a boundary * on the slave bus * We need to ensure the master stays aligned @@ -884,7 +881,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, && (remainder); j++) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundardy, single byte (remain %08x)\n", + "%s align with boundary, single byte (remain %08x)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, @@ -907,7 +904,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, while (remainder) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundardy, single odd byte (remain %d)\n", + "%s align with boundary, single odd byte (remain %d)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1, cctl, &remainder); @@ -1367,8 +1364,8 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, * available to handle it whereas slave transfers may * have been denied due to platform channel muxing restrictions * and since there is no guarantee that this will ever be - * resolved, and since the signal must be aquired AFTER - * aquiring the physical channel, we will let them be NACK:ed + * resolved, and since the signal must be acquired AFTER + * acquiring the physical channel, we will let them be NACK:ed * with -EBUSY here. The drivers can alway retry the prep() * call if they are eager on doing this using DMA. */ @@ -1620,7 +1617,7 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) val = readl(pl08x->base + PL080_CONFIG); val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE); - /* We implictly clear bit 1 and that means little-endian mode */ + /* We implicitly clear bit 1 and that means little-endian mode */ val |= PL080_CONFIG_ENABLE; writel(val, pl08x->base + PL080_CONFIG); } @@ -2160,7 +2157,7 @@ static int __init pl08x_init(void) retval = amba_driver_register(&pl08x_amba_driver); if (retval) printk(KERN_WARNING DRIVER_NAME - "failed to register as an amba device (%d)\n", + "failed to register as an AMBA device (%d)\n", retval); return retval; } -- cgit v1.2.3 From 4440aacf3a171a0ab498feda58d100a320c5d9ff Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:30:44 +0000 Subject: ARM: PL08x: fix array overflow in dma_set_runtime_config() If maxburst was passed in as zero, we would overflow the burst_sizes[] array. Fix this by checking for this condition, and defaulting to single transfer 'bursts'. Improve the readability of the loop using a for() loop rather than a while() loop with the iterator initialized far from the loop. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 3da49ed5f800..0809810f9e7a 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1207,7 +1207,7 @@ static void dma_set_runtime_config(struct dma_chan *chan, u32 cctl = 0; /* Mask out all except src and dst channel */ u32 ccfg = cd->ccfg & 0x000003DEU; - int i = 0; + int i; /* Transfer direction */ plchan->runtime_direction = config->direction; @@ -1250,18 +1250,17 @@ static void dma_set_runtime_config(struct dma_chan *chan, /* * Now decide on a maxburst: - * If this channel will only request single transfers, set - * this down to ONE element. + * If this channel will only request single transfers, set this + * down to ONE element. Also select one element if no maxburst + * is specified. */ - if (plchan->cd->single) { + if (plchan->cd->single || maxburst == 0) { cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) | (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT); } else { - while (i < ARRAY_SIZE(burst_sizes)) { + for (i = 0; i < ARRAY_SIZE(burst_sizes); i++) if (burst_sizes[i].burstwords <= maxburst) break; - i++; - } cctl |= burst_sizes[i].reg; } -- cgit v1.2.3 From 91aa5fadb831e7b6ea473a526a6b49c6dc4819ce Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:31:04 +0000 Subject: ARM: PL08x: fix atomic_t usage and tx_submit() return value range The last_issued variable uses an atomic type, which is only incremented inside a protected region, and then read. Everywhere else only reads the value, so it isn't using atomic_t correctly, and it doesn't even need to. Moreover, the DMA engine code provides us with a variable for this already - chan.cookie. Use chan.cookie instead. Also, avoid negative dma_cookie_t values - negative returns from tx_submit() mean failure, yet in reality we always succeed. Restart from cookie 1, just like other DMA engine drivers do. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 18 +++++++++--------- include/linux/amba/pl08x.h | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 0809810f9e7a..5d9a15652dba 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -74,7 +74,6 @@ #include #include #include -#include #include #include @@ -1082,8 +1081,10 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) { struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan); - atomic_inc(&plchan->last_issued); - tx->cookie = atomic_read(&plchan->last_issued); + plchan->chan.cookie += 1; + if (plchan->chan.cookie < 0) + plchan->chan.cookie = 1; + tx->cookie = plchan->chan.cookie; /* This unlock follows the lock in the prep() function */ spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); @@ -1115,7 +1116,7 @@ pl08x_dma_tx_status(struct dma_chan *chan, enum dma_status ret; u32 bytesleft = 0; - last_used = atomic_read(&plchan->last_issued); + last_used = plchan->chan.cookie; last_complete = plchan->lc; ret = dma_async_is_complete(cookie, last_complete, last_used); @@ -1131,7 +1132,7 @@ pl08x_dma_tx_status(struct dma_chan *chan, /* * This cookie not complete yet */ - last_used = atomic_read(&plchan->last_issued); + last_used = plchan->chan.cookie; last_complete = plchan->lc; /* Get number of bytes left in the active transactions and queue */ @@ -1641,8 +1642,7 @@ static void pl08x_tasklet(unsigned long data) /* * Update last completed */ - plchan->lc = - (plchan->at->tx.cookie); + plchan->lc = plchan->at->tx.cookie; /* * Callback to signal completion @@ -1820,8 +1820,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, chan->name); chan->chan.device = dmadev; - atomic_set(&chan->last_issued, 0); - chan->lc = atomic_read(&chan->last_issued); + chan->chan.cookie = 0; + chan->lc = 0; spin_lock_init(&chan->lock); INIT_LIST_HEAD(&chan->desc_list); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 521a0f8974ac..4ae62b4684f9 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -174,7 +174,6 @@ struct pl08x_dma_chan { struct pl08x_channel_data *cd; dma_addr_t runtime_addr; enum dma_data_direction runtime_direction; - atomic_t last_issued; dma_cookie_t lc; struct list_head desc_list; struct pl08x_txd *at; -- cgit v1.2.3 From bf072af461c166964fb110cfcafccd752fbb4c64 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:31:24 +0000 Subject: ARM: PL08x: fix locking in tasklet Tasklets are run from an interruptible context. The slave DMA functions can be called from within IRQ handlers. Taking the spinlock without disabling interrupts allows an interrupt handler to run, which may try to take the spinlock again, resulting in deadlock. Fix this by using the irqsave spinlocks. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 5d9a15652dba..69cfb05e4d3c 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1627,11 +1627,12 @@ static void pl08x_tasklet(unsigned long data) struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; struct pl08x_phy_chan *phychan = plchan->phychan; struct pl08x_driver_data *pl08x = plchan->host; + unsigned long flags; if (!plchan) BUG(); - spin_lock(&plchan->lock); + spin_lock_irqsave(&plchan->lock, flags); if (plchan->at) { dma_async_tx_callback callback = @@ -1728,7 +1729,7 @@ static void pl08x_tasklet(unsigned long data) } } - spin_unlock(&plchan->lock); + spin_unlock_irqrestore(&plchan->lock, flags); } static irqreturn_t pl08x_irq(int irq, void *dev) -- cgit v1.2.3 From dafa73171be8dd31b485f5839e3376b1ca908e24 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:31:45 +0000 Subject: ARM: PL08x: fix a leak when preparing TXDs If we fail to allocate the LLI, the prep_* function will return NULL. However, the TXD we allocated will not be placed on any list, nor will it be freed - we'll just drop all references to it. Make sure we free it rather than leaking TXDs. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 69cfb05e4d3c..b3b3180ce561 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1332,9 +1332,10 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, int ret; num_llis = pl08x_fill_llis_for_desc(pl08x, txd); - - if (!num_llis) + if (!num_llis) { + kfree(txd); return -EINVAL; + } spin_lock_irqsave(&plchan->lock, plchan->lockflags); -- cgit v1.2.3 From 9c0bb43bbd02fba0b235f8993d1f175734fa8735 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:32:05 +0000 Subject: ARM: PL08x: fix missed spin-unlock in pl08x_issue_pending() pl08x_issue_pending() returns with the spinlock locked and interrupts disabled if the channel is waiting for a physical DMA to become free. This is wrong - especially as pl08x_issue_pending() is an API function as it leads to deadlocks. Fix it to always return with the spinlock unlocked. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index b3b3180ce561..9a8d44504c6a 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1294,15 +1294,11 @@ static void pl08x_issue_pending(struct dma_chan *chan) unsigned long flags; spin_lock_irqsave(&plchan->lock, flags); - /* Something is already active */ - if (plchan->at) { - spin_unlock_irqrestore(&plchan->lock, flags); - return; - } - - /* Didn't get a physical channel so waiting for it ... */ - if (plchan->state == PL08X_CHAN_WAITING) + /* Something is already active, or we're waiting for a channel... */ + if (plchan->at || plchan->state == PL08X_CHAN_WAITING) { + spin_unlock_irqrestore(&plchan->lock, flags); return; + } /* Take the first element in the queue and execute it */ if (!list_empty(&plchan->desc_list)) { -- cgit v1.2.3 From 98838f90d92f6f0abf6d6a99880c0ff3127633b8 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:32:26 +0000 Subject: ARM: PL08x: fix deadlock in terminate_all Trying to disable a tasklet while holding a spinlock which the tasklet will take is a recipe for deadlock - tasklet_disable() will wait for the tasklet to finish running, which it will never do. In any case, there is not a corresponding tasklet_enable(), so once the tasklet is disabled, it will never run again until reboot. It's safe to just remove the tasklet_disable() as we remove all current and pending descriptors before releasing this spinlock. This means that the tasklet will find no remaining work if it subsequently runs. The only remaining issue is that the callback for an already submitted txd may be in progress, or even called after terminate_all() returns. There's not much that can be done about that as waiting for the callback to complete before returning will also lead to deadlocks. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 9a8d44504c6a..4ca1eb122e07 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1560,8 +1560,6 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, pl08x_put_phy_channel(pl08x, plchan->phychan); plchan->phychan = NULL; } - /* Stop any pending tasklet */ - tasklet_disable(&plchan->tasklet); /* Dequeue jobs and free LLIs */ if (plchan->at) { pl08x_free_txd(pl08x, plchan->at); -- cgit v1.2.3 From 3e2a037c1de79af999a54581cbf1e8a5c933fd95 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:32:46 +0000 Subject: ARM: PL08x: fix sparse warnings drivers/dma/amba-pl08x.c:1895:40: warning: Unknown escape '%' drivers/dma/amba-pl08x.c:1903:40: warning: Unknown escape '%' drivers/dma/amba-pl08x.c:513:6: warning: symbol 'pl08x_choose_master_bus' was not declared. Should it be static? drivers/dma/amba-pl08x.c:604:5: warning: symbol 'pl08x_fill_llis_for_desc' was not declared. Should it be static? drivers/dma/amba-pl08x.c:1442:32: warning: symbol 'pl08x_prep_slave_sg' was not declared. Should it be static? Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4ca1eb122e07..74fa5a0f1490 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -510,7 +510,7 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, * this prefers the destination bus if both available * if fixed address on one bus the other will be chosen */ -void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, +static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) { @@ -545,7 +545,7 @@ void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, * Fills in one LLI for a certain transfer descriptor * and advance the counter */ -int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, +static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) { @@ -1439,7 +1439,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( return &txd->tx; } -struct dma_async_tx_descriptor *pl08x_prep_slave_sg( +static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction, unsigned long flags) @@ -1890,7 +1890,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "CHANNEL:\tSTATE:\n"); seq_printf(s, "--------\t------\n"); list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) { - seq_printf(s, "%s\t\t\%s\n", chan->name, + seq_printf(s, "%s\t\t%s\n", chan->name, pl08x_state_str(chan->state)); } @@ -1898,7 +1898,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "CHANNEL:\tSTATE:\n"); seq_printf(s, "--------\t------\n"); list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) { - seq_printf(s, "%s\t\t\%s\n", chan->name, + seq_printf(s, "%s\t\t%s\n", chan->name, pl08x_state_str(chan->state)); } -- cgit v1.2.3 From 9dc2c200a0551754f91e1b322dcb3d782cd709b2 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:33:06 +0000 Subject: ARM: PL08x: add comment explaining the flow control methods Explain the two flow control methods which the PL08x implements, along with the problem which peripheral flow control presents. This helps people understand why we are unable to use these DMA controllers with (eg) the MMCI. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 74fa5a0f1490..4b63fc39a6df 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -53,7 +53,23 @@ * * ASSUMES default (little) endianness for DMA transfers * - * Only DMAC flow control is implemented + * The PL08x has two flow control settings: + * - DMAC flow control: the transfer size defines the number of transfers + * which occur for the current LLI entry, and the DMAC raises TC at the + * end of every LLI entry. Observed behaviour shows the DMAC listening + * to both the BREQ and SREQ signals (contrary to documented), + * transferring data if either is active. The LBREQ and LSREQ signals + * are ignored. + * + * - Peripheral flow control: the transfer size is ignored (and should be + * zero). The data is transferred from the current LLI entry, until + * after the final transfer signalled by LBREQ or LSREQ. The DMAC + * will then move to the next LLI entry. + * + * Only the former works sanely with scatter lists, so we only implement + * the DMAC flow control method. However, peripherals which use the LBREQ + * and LSREQ signals (eg, MMCI) are unable to use this mode, which through + * these hardware restrictions prevents them from using scatter DMA. * * Global TODO: * - Break out common code from arch/arm/mach-s3c64xx and share -- cgit v1.2.3 From b05cd8f4c04a29eebfa65c45fabc78a02f16a782 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:33:26 +0000 Subject: ARM: PL08x: improve the announcement printk Include the revision number of the PL08x primecell in the boot-time printk to allow proper identification of the peripheral. Reformat the announcement printk format reflect what we do for other primecell drivers - generally "PLXXX revX at 0xNNNNNNNN irq X". Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4b63fc39a6df..75ab4e47a153 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -98,13 +98,11 @@ /** * struct vendor_data - vendor-specific config parameters * for PL08x derivatives - * @name: the name of this specific variant * @channels: the number of channels available in this variant * @dualmaster: whether this version supports dual AHB masters * or not. */ struct vendor_data { - char *name; u8 channels; bool dualmaster; }; @@ -2024,7 +2022,7 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) writel(0x000000FF, pl08x->base + PL080_TC_CLEAR); ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED, - vd->name, pl08x); + DRIVER_NAME, pl08x); if (ret) { dev_err(&adev->dev, "%s failed to request interrupt %d\n", __func__, adev->irq[0]); @@ -2095,8 +2093,9 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) amba_set_drvdata(adev, pl08x); init_pl08x_debugfs(pl08x); - dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n", - vd->name, adev->res.start); + dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n", + amba_part(adev), amba_rev(adev), + (unsigned long long)adev->res.start, adev->irq[0]); return 0; out_no_slave_reg: @@ -2123,13 +2122,11 @@ out_no_pl08x: /* PL080 has 8 channels and the PL080 have just 2 */ static struct vendor_data vendor_pl080 = { - .name = "PL080", .channels = 8, .dualmaster = true, }; static struct vendor_data vendor_pl081 = { - .name = "PL081", .channels = 2, .dualmaster = false, }; -- cgit v1.2.3 From 9c132992689d7d27a4e17545b6279db4e03c0943 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:33:47 +0000 Subject: ARM: PL08x: prefix hex numbers with 0x A driver which emits both decimal and hex numbers in its printk creates confusion as to what is what. Prefix hex numbers with 0x. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 75ab4e47a153..c61774a3630e 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -199,8 +199,8 @@ static void pl08x_set_cregs(struct pl08x_driver_data *pl08x, ; dev_vdbg(&pl08x->adev->dev, - "WRITE channel %d: csrc=%08x, cdst=%08x, " - "cctl=%08x, clli=%08x, ccfg=%08x\n", + "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " + "cctl=0x%08x, clli=0x%08x, ccfg=0x%08x\n", ch->id, ch->csrc, ch->cdst, @@ -731,7 +731,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, while (remainder) { dev_vdbg(&pl08x->adev->dev, "%s single byte LLIs for a transfer of " - "less than a bus width (remain %08x)\n", + "less than a bus width (remain 0x%08x)\n", __func__, remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); num_llis = @@ -747,7 +747,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, while ((mbus->addr) % (mbus->buswidth)) { dev_vdbg(&pl08x->adev->dev, "%s adjustment lli for less than bus width " - "(remain %08x)\n", + "(remain 0x%08x)\n", __func__, remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); num_llis = pl08x_fill_lli_for_desc @@ -865,7 +865,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (target_len != lli_len) { dev_vdbg(&pl08x->adev->dev, - "%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n", + "%s can't send what we want. Desired 0x%08x, lli of 0x%08x bytes in txd of 0x%08x\n", __func__, target_len, lli_len, txd->len); } @@ -875,7 +875,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, tsize); dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of size %08x (remainder %08x)\n", + "%s fill lli with single lli chunk of size 0x%08x (remainder 0x%08x)\n", __func__, lli_len, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, lli_len, cctl, @@ -894,7 +894,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, && (remainder); j++) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single byte (remain %08x)\n", + "%s align with boundary, single byte (remain 0x%08x)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, @@ -979,7 +979,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, for (i = 0; i < num_llis; i++) { dev_vdbg(&pl08x->adev->dev, - "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n", + "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n", i, &llis_va[i], llis_va[i].src, @@ -1289,7 +1289,7 @@ static void dma_set_runtime_config(struct dma_chan *chan, dev_dbg(&pl08x->adev->dev, "configured channel %s (%s) for %s, data width %d, " - "maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n", + "maxburst %d words, LE, CCTL=0x%08x, CCFG=0x%08x\n", dma_chan_name(chan), plchan->name, (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", addr_width, -- cgit v1.2.3 From 730404ac1c47403af67420705980c99e90bf182f Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:34:07 +0000 Subject: ARM: PL08x: remove unnecessary includes We don't need to include linux/pci.h as we aren't a PCI driver. We aren't doing any processor specific functions, so asm/processor.h is not required. asm/cacheflush.h shouldn't be used, we have the DMA API for this. DMA interfaces aren't required as we're only implementing the dmaengine API and not a platform-private DMA API. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c61774a3630e..d22d6280242d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -77,21 +77,16 @@ #include #include #include -#include #include #include #include -#include #include +#include #include #include #include #include -#include -#include -#include -#include #define DRIVER_NAME "pl08xdmac" -- cgit v1.2.3 From ad0a3ad33c96cbba98ba62116771fb836c551e60 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:34:27 +0000 Subject: ARM: PL08x: remove unnecessary NULL and BUG checks The tasklet always is initialized with a non-NULL data argument. It is not possible for it to be called with a NULL data argument (unless something is very wrong in the tasklet code - in which case lots of stuff will break). Therefore, as plchan can never be NULL, remove this unnecessary BUG check. In pl08x_tasklet(), we've already dereferenced plchan->at, so it can't be NULL here. Remove this unnecessary BUG check. pl08x_fill_llis_for_desc() and pl08x_free_txd() are always called with a non-NULL txd argument - either as a consequence of the code paths or as a result of other checks already in place. We don't need to repeat the non-NULL check in these functions. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index d22d6280242d..b721ed2e884d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -623,11 +623,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct lli *llis_va; struct lli *llis_bus; - if (!txd) { - dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__); - return 0; - } - txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); if (!txd->llis_va) { @@ -993,11 +988,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { - if (!txd) - dev_err(&pl08x->adev->dev, - "%s no descriptor to free\n", - __func__); - /* Free the LLI */ dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); @@ -1633,9 +1623,6 @@ static void pl08x_tasklet(unsigned long data) struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; - if (!plchan) - BUG(); - spin_lock_irqsave(&plchan->lock, flags); if (plchan->at) { @@ -1655,14 +1642,6 @@ static void pl08x_tasklet(unsigned long data) if (callback) callback(callback_param); - /* - * Device callbacks should NOT clear - * the current transaction on the channel - * Linus: sometimes they should? - */ - if (!plchan->at) - BUG(); - /* * Free the descriptor if it's not for a device * using a circular buffer -- cgit v1.2.3 From b58b6b5bedf4d5da7a0cb2dce3b42d010c3aef03 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:34:48 +0000 Subject: ARM: PL08x: remove circular buffer support The driver already won't initialize a channel with a circular buffer; the check in pl08x_prep_channel_resources() sees to that. Remove circular buffer support for the time being. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 71 ++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index b721ed2e884d..74b35910f295 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -927,39 +927,21 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, __func__, (u32) MAX_NUM_TSFR_LLIS); return 0; } + + llis_va = txd->llis_va; /* - * Decide whether this is a loop or a terminated transfer + * The final LLI terminates the LLI. */ - llis_va = txd->llis_va; - llis_bus = (struct lli *) txd->llis_bus; - - if (cd->circular_buffer) { - /* - * Loop the circular buffer so that the next element - * points back to the beginning of the LLI. - */ - llis_va[num_llis - 1].next = - (dma_addr_t)((unsigned int)&(llis_bus[0])); - } else { - /* - * On non-circular buffers, the final LLI terminates - * the LLI. - */ - llis_va[num_llis - 1].next = 0; - /* - * The final LLI element shall also fire an interrupt - */ - llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; - } + llis_va[num_llis - 1].next = 0; + /* + * The final LLI element shall also fire an interrupt + */ + llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; /* Now store the channel register values */ txd->csrc = llis_va[0].src; txd->cdst = llis_va[0].dst; - if (num_llis > 1) - txd->clli = llis_va[0].next; - else - txd->clli = 0; - + txd->clli = llis_va[0].next; txd->cctl = llis_va[0].cctl; /* ccfg will be set at physical channel allocation time */ @@ -1334,19 +1316,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, spin_lock_irqsave(&plchan->lock, plchan->lockflags); - /* - * If this device is not using a circular buffer then - * queue this new descriptor for transfer. - * The descriptor for a circular buffer continues - * to be used until the channel is freed. - */ - if (txd->cd->circular_buffer) - dev_err(&pl08x->adev->dev, - "%s attempting to queue a circular buffer\n", - __func__); - else - list_add_tail(&txd->node, - &plchan->desc_list); + list_add_tail(&txd->node, &plchan->desc_list); /* * See if we already have a physical channel allocated, @@ -1643,18 +1613,10 @@ static void pl08x_tasklet(unsigned long data) callback(callback_param); /* - * Free the descriptor if it's not for a device - * using a circular buffer - */ - if (!plchan->at->cd->circular_buffer) { - pl08x_free_txd(pl08x, plchan->at); - plchan->at = NULL; - } - /* - * else descriptor for circular - * buffers only freed when - * client has disabled dma + * Free the descriptor */ + pl08x_free_txd(pl08x, plchan->at); + plchan->at = NULL; } /* * If a new descriptor is queued, set it up @@ -1799,6 +1761,13 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, return -ENOMEM; } } + if (chan->cd->circular_buffer) { + dev_err(&pl08x->adev->dev, + "channel %s: circular buffers not supported\n", + chan->name); + kfree(chan); + continue; + } dev_info(&pl08x->adev->dev, "initialize virtual channel \"%s\"\n", chan->name); -- cgit v1.2.3 From f96ca9ec27159c1c8718aa8d0ed03051cd12e884 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:35:08 +0000 Subject: ARM: PL08x: constify vendor data pointers We should never modify the vendor data structure so make it const. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 74b35910f295..707fa081c9fa 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -132,7 +132,7 @@ struct pl08x_driver_data { struct dma_device memcpy; void __iomem *base; struct amba_device *adev; - struct vendor_data *vd; + const struct vendor_data *vd; struct pl08x_platform_data *pd; struct pl08x_phy_chan *phy_chans; struct dma_pool *pool; @@ -1891,7 +1891,7 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x) static int pl08x_probe(struct amba_device *adev, struct amba_id *id) { struct pl08x_driver_data *pl08x; - struct vendor_data *vd = id->data; + const struct vendor_data *vd = id->data; int ret = 0; int i; -- cgit v1.2.3 From 7cb72ad959b16ac594118977b7954a7d2ec7a052 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:35:28 +0000 Subject: ARM: PL08x: avoid 'void *' struct fields when we can type them properly Avoid using 'void *' struct fields when the structs are not defined in linux/amba/pl08x.h - instead, forward declare the struct names, and use these instead. This ensures we have proper typechecking. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 16 ++++++++-------- include/linux/amba/pl08x.h | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 707fa081c9fa..fada97873d7d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -107,7 +107,7 @@ struct vendor_data { * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit, * start & end do not - their bus bit info is in cctl. */ -struct lli { +struct pl08x_lli { dma_addr_t src; dma_addr_t dst; dma_addr_t next; @@ -160,7 +160,7 @@ struct pl08x_driver_data { /* Maximum times we call dma_pool_alloc on this pool without freeing */ #define PL08X_MAX_ALLOCS 0x40 -#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli)) +#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli)) #define PL08X_ALIGN 8 static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan) @@ -354,8 +354,8 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) * currently active transaction. */ if (ch && txd) { - struct lli *llis_va = txd->llis_va; - struct lli *llis_bus = (struct lli *) txd->llis_bus; + struct pl08x_lli *llis_va = txd->llis_va; + struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; u32 clli = readl(ch->base + PL080_CH_LLI); /* First get the bytes in the current active LLI */ @@ -558,8 +558,8 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) { - struct lli *llis_va = txd->llis_va; - struct lli *llis_bus = (struct lli *) txd->llis_bus; + struct pl08x_lli *llis_va = txd->llis_va; + struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); @@ -620,8 +620,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, u32 cctl; int max_bytes_per_lli; int total_bytes = 0; - struct lli *llis_va; - struct lli *llis_bus; + struct pl08x_lli *llis_va; + struct pl08x_lli *llis_bus; txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 4ae62b4684f9..3ecc20fce26a 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -22,6 +22,9 @@ #include #include +struct pl08x_lli; +struct pl08x_driver_data; + /** * struct pl08x_channel_data - data structure to pass info between * platform and PL08x driver regarding channel configuration @@ -179,7 +182,7 @@ struct pl08x_dma_chan { struct pl08x_txd *at; unsigned long lockflags; spinlock_t lock; - void *host; + struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; bool slave; struct pl08x_txd *waiting; -- cgit v1.2.3 From ac3cd20df9d74bb205bb34f69407477a884ff8a3 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:35:49 +0000 Subject: ARM: PL08x: consolidate common txd initialization Consolidate code which allocates and initializes txds. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index fada97873d7d..d47255ee9504 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1363,6 +1363,18 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return 0; } +static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) +{ + struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); + + if (txd) { + dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); + txd->tx.tx_submit = pl08x_tx_submit; + INIT_LIST_HEAD(&txd->node); + } + return txd; +} + /* * Initialize a descriptor to be used by memcpy submit */ @@ -1375,14 +1387,13 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( struct pl08x_txd *txd; int ret; - txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); + txd = pl08x_get_txd(plchan); if (!txd) { dev_err(&pl08x->adev->dev, "%s no memory for descriptor\n", __func__); return NULL; } - dma_async_tx_descriptor_init(&txd->tx, chan); txd->direction = DMA_NONE; txd->srcbus.addr = src; txd->dstbus.addr = dest; @@ -1391,12 +1402,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( txd->cd = &pl08x->pd->memcpy_channel; /* Both to be incremented or the code will break */ txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; - txd->tx.tx_submit = pl08x_tx_submit; - txd->tx.callback = NULL; - txd->tx.callback_param = NULL; txd->len = len; - INIT_LIST_HEAD(&txd->node); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; @@ -1430,14 +1437,12 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n", __func__, sgl->length, plchan->name); - txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); + txd = pl08x_get_txd(plchan); if (!txd) { dev_err(&pl08x->adev->dev, "%s no txd\n", __func__); return NULL; } - dma_async_tx_descriptor_init(&txd->tx, chan); - if (direction != plchan->runtime_direction) dev_err(&pl08x->adev->dev, "%s DMA setup does not match " "the direction configured for the PrimeCell\n", @@ -1467,11 +1472,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( return NULL; } txd->cd = plchan->cd; - txd->tx.tx_submit = pl08x_tx_submit; - txd->tx.callback = NULL; - txd->tx.callback_param = NULL; txd->len = sgl->length; - INIT_LIST_HEAD(&txd->node); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) -- cgit v1.2.3 From 8c8cc2b1040f51a2f89724edbf976774128339eb Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:36:09 +0000 Subject: ARM: PL08x: consolidate physical channel release code Consolidate duplicated channel release code into release_phy_channel() Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index d47255ee9504..e8967ff44fc2 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1058,6 +1058,18 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, return 0; } +static void release_phy_channel(struct pl08x_dma_chan *plchan) +{ + struct pl08x_driver_data *pl08x = plchan->host; + + if ((plchan->phychan->signal >= 0) && pl08x->pd->put_signal) { + pl08x->pd->put_signal(plchan); + plchan->phychan->signal = -1; + } + pl08x_put_phy_channel(pl08x, plchan->phychan); + plchan->phychan = NULL; +} + static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) { struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan); @@ -1522,13 +1534,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * Mark physical channel as free and free any slave * signal */ - if ((plchan->phychan->signal >= 0) && - pl08x->pd->put_signal) { - pl08x->pd->put_signal(plchan); - plchan->phychan->signal = -1; - } - pl08x_put_phy_channel(pl08x, plchan->phychan); - plchan->phychan = NULL; + release_phy_channel(plchan); } /* Dequeue jobs and free LLIs */ if (plchan->at) { @@ -1590,7 +1596,6 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) static void pl08x_tasklet(unsigned long data) { struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; - struct pl08x_phy_chan *phychan = plchan->phychan; struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; @@ -1642,12 +1647,7 @@ static void pl08x_tasklet(unsigned long data) * No more jobs, so free up the physical channel * Free any allocated signal on slave transfers too */ - if ((phychan->signal >= 0) && pl08x->pd->put_signal) { - pl08x->pd->put_signal(plchan); - phychan->signal = -1; - } - pl08x_put_phy_channel(pl08x, phychan); - plchan->phychan = NULL; + release_phy_channel(plchan); plchan->state = PL08X_CHAN_IDLE; /* -- cgit v1.2.3 From 19386b3234fdbe4d33492574d83e63a8dace18d3 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:36:29 +0000 Subject: ARM: PL08x: ensure loops use cpu_relax() Tight loops should use cpu_relax() to allow CPUs to reduce power consumption while waiting for events. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index e8967ff44fc2..78c84b3f903d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -191,7 +191,7 @@ static void pl08x_set_cregs(struct pl08x_driver_data *pl08x, { /* Wait for channel inactive */ while (pl08x_phy_channel_busy(ch)) - ; + cpu_relax(); dev_vdbg(&pl08x->adev->dev, "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " @@ -255,7 +255,7 @@ static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x, * Do not access config register until channel shows as disabled */ while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id)) - ; + cpu_relax(); /* * Do not access config register until channel shows as inactive @@ -288,7 +288,7 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) /* Wait for channel inactive */ while (pl08x_phy_channel_busy(ch)) - ; + cpu_relax(); } static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch) -- cgit v1.2.3 From 4c0df6a3ce8eb947647c7ed2640d0172936d8ef3 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:36:50 +0000 Subject: ARM: PL08x: don't assume that the LLI pointer has the bus bit clear We only want use the address of the LLI pointer when locating the corresponding structure in memory, so clear the master bus selection bit. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 78c84b3f903d..1081165d01a3 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -356,7 +356,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) if (ch && txd) { struct pl08x_lli *llis_va = txd->llis_va; struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; - u32 clli = readl(ch->base + PL080_CH_LLI); + u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2; /* First get the bytes in the current active LLI */ bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL)); -- cgit v1.2.3 From 56b618820c92a5efa2145fbbac373fffbb024a94 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:37:10 +0000 Subject: ARM: PL08x: don't try to use llis_bus as a pointer llis_bus is the DMA address of the LLI array. Casting it to be a pointer just to be able to use pointer arithmetic on it is not nice. We can trivially deal with the places where we do arithmetic on it, and it's actually cleaner this way. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 1081165d01a3..760b71eec84c 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -559,7 +559,7 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, u32 cctl, u32 *remainder) { struct pl08x_lli *llis_va = txd->llis_va; - struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; + dma_addr_t llis_bus = txd->llis_bus; BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); @@ -576,8 +576,7 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, * memory. So we don't manipulate this bit currently. */ - llis_va[num_llis].next = - (dma_addr_t)((u32) &(llis_bus[num_llis + 1])); + llis_va[num_llis].next = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); if (cctl & PL080_CONTROL_SRC_INCR) txd->srcbus.addr += len; @@ -621,7 +620,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, int max_bytes_per_lli; int total_bytes = 0; struct pl08x_lli *llis_va; - struct pl08x_lli *llis_bus; txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); @@ -971,8 +969,7 @@ static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { /* Free the LLI */ - dma_pool_free(pl08x->pool, txd->llis_va, - txd->llis_bus); + dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); pl08x->pool_ctr--; -- cgit v1.2.3 From cace658572ba5d1075f3891e823130a66f3e330f Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:37:31 +0000 Subject: ARM: PL08x: use 'size_t' for lengths Use size_t for variables denoting lengths throughout, and use the 'z' qualifier for printing the value. For safety, add a BUG_ON() in pl08x_fill_lli_for_desc() to catch the remainder potentially becoming negative. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 40 +++++++++++++++++----------------------- include/linux/amba/pl08x.h | 4 ++-- 2 files changed, 19 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 760b71eec84c..fa78697790c0 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -342,7 +342,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) struct pl08x_txd *txdi = NULL; struct pl08x_txd *txd; unsigned long flags; - u32 bytes = 0; + size_t bytes = 0; spin_lock_irqsave(&plchan->lock, flags); @@ -470,7 +470,7 @@ static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded) } static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, - u32 tsize) + size_t tsize) { u32 retbits = cctl; @@ -583,6 +583,8 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, if (cctl & PL080_CONTROL_DST_INCR) txd->dstbus.addr += len; + BUG_ON(*remainder < len); + *remainder -= len; return num_llis + 1; @@ -591,7 +593,7 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, /* * Return number of bytes to fill to boundary, or len */ -static inline u32 pl08x_pre_boundary(u32 addr, u32 len) +static inline size_t pl08x_pre_boundary(u32 addr, size_t len) { u32 boundary; @@ -614,11 +616,11 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, { struct pl08x_channel_data *cd = txd->cd; struct pl08x_bus_data *mbus, *sbus; - u32 remainder; + size_t remainder; int num_llis = 0; u32 cctl; - int max_bytes_per_lli; - int total_bytes = 0; + size_t max_bytes_per_lli; + size_t total_bytes = 0; struct pl08x_lli *llis_va; txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, @@ -686,13 +688,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) * PL080_CONTROL_TRANSFER_SIZE_MASK; dev_vdbg(&pl08x->adev->dev, - "%s max bytes per lli = %d\n", + "%s max bytes per lli = %zu\n", __func__, max_bytes_per_lli); /* We need to count this down to zero */ remainder = txd->len; dev_vdbg(&pl08x->adev->dev, - "%s remainder = %d\n", + "%s remainder = %zu\n", __func__, remainder); /* @@ -760,9 +762,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * width left */ while (remainder > (mbus->buswidth - 1)) { - int lli_len, target_len; - int tsize; - int odd_bytes; + size_t lli_len, target_len, tsize, odd_bytes; /* * If enough left try to send max possible, @@ -805,7 +805,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (lli_len <= 0) { dev_err(&pl08x->adev->dev, - "%s lli_len is %d, <= 0\n", + "%s lli_len is %zu, <= 0\n", __func__, lli_len); return 0; } @@ -853,7 +853,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (target_len != lli_len) { dev_vdbg(&pl08x->adev->dev, - "%s can't send what we want. Desired 0x%08x, lli of 0x%08x bytes in txd of 0x%08x\n", + "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n", __func__, target_len, lli_len, txd->len); } @@ -863,7 +863,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, tsize); dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of size 0x%08x (remainder 0x%08x)\n", + "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", __func__, lli_len, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, lli_len, cctl, @@ -882,7 +882,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, && (remainder); j++) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single byte (remain 0x%08x)\n", + "%s align with boundary, single byte (remain 0x%08zx)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, @@ -896,16 +896,10 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * Send any odd bytes */ - if (remainder < 0) { - dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n", - __func__, remainder); - return 0; - } - while (remainder) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single odd byte (remain %d)\n", + "%s align with boundary, single odd byte (remain %zu)\n", __func__, remainder); num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1, cctl, &remainder); @@ -914,7 +908,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } if (total_bytes != txd->len) { dev_err(&pl08x->adev->dev, - "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n", + "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", __func__, total_bytes, txd->len); return 0; } diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 3ecc20fce26a..2c834ed5f41f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -77,7 +77,7 @@ struct pl08x_bus_data { dma_addr_t addr; u8 maxwidth; u8 buswidth; - u32 fill_bytes; + size_t fill_bytes; }; /** @@ -113,7 +113,7 @@ struct pl08x_txd { enum dma_data_direction direction; struct pl08x_bus_data srcbus; struct pl08x_bus_data dstbus; - int len; + size_t len; dma_addr_t llis_bus; void *llis_va; struct pl08x_channel_data *cd; -- cgit v1.2.3 From e25761d72c80751c8741f5f93abab14232eef347 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:37:52 +0000 Subject: ARM: PL08x: use 'u32' for LLI structure members, not dma_addr_t Use 'u32' for the LLI structure members, which are defined by hardware to be 32-bit. dma_addr_t is much more vague about its actual size. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index fa78697790c0..a389df501f70 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -105,12 +105,13 @@ struct vendor_data { /* * PL08X private data structures * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit, - * start & end do not - their bus bit info is in cctl. + * start & end do not - their bus bit info is in cctl. Also note that these + * are fixed 32-bit quantities. */ struct pl08x_lli { - dma_addr_t src; - dma_addr_t dst; - dma_addr_t next; + u32 src; + u32 dst; + u32 next; u32 cctl; }; -- cgit v1.2.3 From bfddfb45056fa95a778f0baf463ac0f9fc926d5c Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:38:12 +0000 Subject: ARM: PL08x: rename lli.next to lli.lli The LLI pointer in the documentation is placed into the LLI register, so name it LLI rather than 'next'. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index a389df501f70..a897315261bc 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -111,7 +111,7 @@ struct vendor_data { struct pl08x_lli { u32 src; u32 dst; - u32 next; + u32 lli; u32 cctl; }; @@ -375,7 +375,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) /* * A LLI pointer of 0 terminates the LLI list */ - clli = llis_va[i].next; + clli = llis_va[i].lli; i++; } } @@ -577,7 +577,7 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, * memory. So we don't manipulate this bit currently. */ - llis_va[num_llis].next = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); + llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); if (cctl & PL080_CONTROL_SRC_INCR) txd->srcbus.addr += len; @@ -925,7 +925,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * The final LLI terminates the LLI. */ - llis_va[num_llis - 1].next = 0; + llis_va[num_llis - 1].lli = 0; /* * The final LLI element shall also fire an interrupt */ @@ -934,7 +934,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* Now store the channel register values */ txd->csrc = llis_va[0].src; txd->cdst = llis_va[0].dst; - txd->clli = llis_va[0].next; + txd->clli = llis_va[0].lli; txd->cctl = llis_va[0].cctl; /* ccfg will be set at physical channel allocation time */ @@ -950,7 +950,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, llis_va[i].src, llis_va[i].dst, llis_va[i].cctl, - llis_va[i].next + llis_va[i].lli ); } } -- cgit v1.2.3 From db9f136a60c8727c8e1c9c4f2494821caebf5a7b Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:38:32 +0000 Subject: ARM: PL08x: clean up LLI lookup As the LLI list is an array, we can use maths to locate which LLI index we're currently at, and then sum up the remaining LLI entries until we reach the end of the list. This makes the code much easier to read, and much less susceptible to falling off the end of the array. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index a897315261bc..202c9e2d2e9e 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -340,53 +340,56 @@ static inline u32 get_bytes_in_cctl(u32 cctl) static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) { struct pl08x_phy_chan *ch; - struct pl08x_txd *txdi = NULL; struct pl08x_txd *txd; unsigned long flags; size_t bytes = 0; spin_lock_irqsave(&plchan->lock, flags); - ch = plchan->phychan; txd = plchan->at; /* - * Next follow the LLIs to get the number of pending bytes in the - * currently active transaction. + * Follow the LLIs to get the number of remaining + * bytes in the currently active transaction. */ if (ch && txd) { - struct pl08x_lli *llis_va = txd->llis_va; - struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus; u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2; - /* First get the bytes in the current active LLI */ + /* First get the remaining bytes in the active transfer */ bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL)); if (clli) { - int i = 0; + struct pl08x_lli *llis_va = txd->llis_va; + dma_addr_t llis_bus = txd->llis_bus; + int index; - /* Forward to the LLI pointed to by clli */ - while ((clli != (u32) &(llis_bus[i])) && - (i < MAX_NUM_TSFR_LLIS)) - i++; + BUG_ON(clli < llis_bus || clli >= llis_bus + + sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS); + + /* + * Locate the next LLI - as this is an array, + * it's simple maths to find. + */ + index = (clli - llis_bus) / sizeof(struct pl08x_lli); + + for (; index < MAX_NUM_TSFR_LLIS; index++) { + bytes += get_bytes_in_cctl(llis_va[index].cctl); - while (clli) { - bytes += get_bytes_in_cctl(llis_va[i].cctl); /* * A LLI pointer of 0 terminates the LLI list */ - clli = llis_va[i].lli; - i++; + if (!llis_va[index].lli) + break; } } } /* Sum up all queued transactions */ if (!list_empty(&plchan->desc_list)) { + struct pl08x_txd *txdi; list_for_each_entry(txdi, &plchan->desc_list, node) { bytes += txdi->len; } - } spin_unlock_irqrestore(&plchan->lock, flags); -- cgit v1.2.3 From c885bee4f10323a1ff3f19e1aa2aa6f4e7f89dd8 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:38:52 +0000 Subject: ARM: PL08x: combine functions to start DMA into one function There is no need for pl08x_config_phychan_for_txd(), pl08x_set_cregs() and pl08x_enable_phy_chan() to be separate - they are always called in sequence. Combine them into one function. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 98 +++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 202c9e2d2e9e..c025a4b4bae4 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -185,37 +185,17 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch) /* * Set the initial DMA register values i.e. those for the first LLI * The next LLI pointer and the configuration interrupt bit have - * been set when the LLIs were constructed + * been set when the LLIs were constructed. Poke them into the hardware + * and start the transfer. */ -static void pl08x_set_cregs(struct pl08x_driver_data *pl08x, - struct pl08x_phy_chan *ch) +static void pl08x_start_txd(struct pl08x_dma_chan *plchan, + struct pl08x_txd *txd) { - /* Wait for channel inactive */ - while (pl08x_phy_channel_busy(ch)) - cpu_relax(); - - dev_vdbg(&pl08x->adev->dev, - "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " - "cctl=0x%08x, clli=0x%08x, ccfg=0x%08x\n", - ch->id, - ch->csrc, - ch->cdst, - ch->cctl, - ch->clli, - ch->ccfg); - - writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR); - writel(ch->cdst, ch->base + PL080_CH_DST_ADDR); - writel(ch->clli, ch->base + PL080_CH_LLI); - writel(ch->cctl, ch->base + PL080_CH_CONTROL); - writel(ch->ccfg, ch->base + PL080_CH_CONFIG); -} - -static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan) -{ - struct pl08x_channel_data *cd = plchan->cd; + struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_phy_chan *phychan = plchan->phychan; - struct pl08x_txd *txd = plchan->at; + u32 val; + + plchan->at = txd; /* Copy the basic control register calculated at transfer config */ phychan->csrc = txd->csrc; @@ -224,7 +204,7 @@ static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan) phychan->cctl = txd->cctl; /* Assign the signal to the proper control registers */ - phychan->ccfg = cd->ccfg; + phychan->ccfg = plchan->cd->ccfg; phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK; phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK; /* If it wasn't set from AMBA, ignore it */ @@ -240,32 +220,38 @@ static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan) phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK; /* Always enable terminal interrupts */ phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK; -} -/* - * Enable the DMA channel - * Assumes all other configuration bits have been set - * as desired before this code is called - */ -static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x, - struct pl08x_phy_chan *ch) -{ - u32 val; + /* Wait for channel inactive */ + while (pl08x_phy_channel_busy(phychan)) + cpu_relax(); - /* - * Do not access config register until channel shows as disabled - */ - while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id)) + dev_vdbg(&pl08x->adev->dev, + "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " + "cctl=0x%08x, clli=0x%08x, ccfg=0x%08x\n", + phychan->id, + phychan->csrc, + phychan->cdst, + phychan->cctl, + phychan->clli, + phychan->ccfg); + + writel(phychan->csrc, phychan->base + PL080_CH_SRC_ADDR); + writel(phychan->cdst, phychan->base + PL080_CH_DST_ADDR); + writel(phychan->clli, phychan->base + PL080_CH_LLI); + writel(phychan->cctl, phychan->base + PL080_CH_CONTROL); + writel(phychan->ccfg, phychan->base + PL080_CH_CONFIG); + + /* Enable the DMA channel */ + /* Do not access config register until channel shows as disabled */ + while (readl(pl08x->base + PL080_EN_CHAN) & (1 << phychan->id)) cpu_relax(); - /* - * Do not access config register until channel shows as inactive - */ - val = readl(ch->base + PL080_CH_CONFIG); + /* Do not access config register until channel shows as inactive */ + val = readl(phychan->base + PL080_CH_CONFIG); while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE)) - val = readl(ch->base + PL080_CH_CONFIG); + val = readl(phychan->base + PL080_CH_CONFIG); - writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG); + writel(val | PL080_CONFIG_ENABLE, phychan->base + PL080_CH_CONFIG); } /* @@ -1278,7 +1264,6 @@ static void dma_set_runtime_config(struct dma_chan *chan, static void pl08x_issue_pending(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); - struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; spin_lock_irqsave(&plchan->lock, flags); @@ -1296,13 +1281,9 @@ static void pl08x_issue_pending(struct dma_chan *chan) struct pl08x_txd, node); list_del(&next->node); - plchan->at = next; plchan->state = PL08X_CHAN_RUNNING; - /* Configure the physical channel for the active txd */ - pl08x_config_phychan_for_txd(plchan); - pl08x_set_cregs(pl08x, plchan->phychan); - pl08x_enable_phy_chan(pl08x, plchan->phychan); + pl08x_start_txd(plchan, next); } spin_unlock_irqrestore(&plchan->lock, flags); @@ -1630,11 +1611,8 @@ static void pl08x_tasklet(unsigned long data) struct pl08x_txd, node); list_del(&next->node); - plchan->at = next; - /* Configure the physical channel for the next txd */ - pl08x_config_phychan_for_txd(plchan); - pl08x_set_cregs(pl08x, plchan->phychan); - pl08x_enable_phy_chan(pl08x, plchan->phychan); + + pl08x_start_txd(plchan, next); } else { struct pl08x_dma_chan *waiting = NULL; -- cgit v1.2.3 From 19524d77ec34faf58d313ba34fb755ef6e159216 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:39:13 +0000 Subject: ARM: PL08x: avoid duplicating registers in txd and phychan structures As we now have all the code accessing the phychan {csrc,cdst,clli,cctl, ccfg} members in one function, there's no point storing the data into the struct. Get rid of the struct members. Re-order the register dump in the dev_dbg() to reflect the order we write the registers to the DMA device. The txd {csrc,cdst,clli,cctl} values are duplicates of the lli[0] values, so there's no point duplicating these either. Program the DMAC registers directly from the lli[0] values. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 57 ++++++++++++++++------------------------------ include/linux/amba/pl08x.h | 13 ----------- 2 files changed, 19 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c025a4b4bae4..a1a18bde6b7f 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -193,33 +193,25 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, { struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_phy_chan *phychan = plchan->phychan; - u32 val; + struct pl08x_lli *lli = &txd->llis_va[0]; + u32 val, ccfg; plchan->at = txd; - /* Copy the basic control register calculated at transfer config */ - phychan->csrc = txd->csrc; - phychan->cdst = txd->cdst; - phychan->clli = txd->clli; - phychan->cctl = txd->cctl; - /* Assign the signal to the proper control registers */ - phychan->ccfg = plchan->cd->ccfg; - phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK; - phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK; + ccfg = plchan->cd->ccfg; + ccfg &= ~(PL080_CONFIG_SRC_SEL_MASK | PL080_CONFIG_DST_SEL_MASK); + /* If it wasn't set from AMBA, ignore it */ if (txd->direction == DMA_TO_DEVICE) /* Select signal as destination */ - phychan->ccfg |= - (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT); + ccfg |= phychan->signal << PL080_CONFIG_DST_SEL_SHIFT; else if (txd->direction == DMA_FROM_DEVICE) /* Select signal as source */ - phychan->ccfg |= - (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT); - /* Always enable error interrupts */ - phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK; - /* Always enable terminal interrupts */ - phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK; + ccfg |= phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT; + + /* Always enable error and terminal interrupts */ + ccfg |= PL080_CONFIG_ERR_IRQ_MASK | PL080_CONFIG_TC_IRQ_MASK; /* Wait for channel inactive */ while (pl08x_phy_channel_busy(phychan)) @@ -227,19 +219,15 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, dev_vdbg(&pl08x->adev->dev, "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " - "cctl=0x%08x, clli=0x%08x, ccfg=0x%08x\n", - phychan->id, - phychan->csrc, - phychan->cdst, - phychan->cctl, - phychan->clli, - phychan->ccfg); - - writel(phychan->csrc, phychan->base + PL080_CH_SRC_ADDR); - writel(phychan->cdst, phychan->base + PL080_CH_DST_ADDR); - writel(phychan->clli, phychan->base + PL080_CH_LLI); - writel(phychan->cctl, phychan->base + PL080_CH_CONTROL); - writel(phychan->ccfg, phychan->base + PL080_CH_CONFIG); + "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n", + phychan->id, lli->src, lli->dst, lli->lli, lli->cctl, + ccfg); + + writel(lli->src, phychan->base + PL080_CH_SRC_ADDR); + writel(lli->dst, phychan->base + PL080_CH_DST_ADDR); + writel(lli->lli, phychan->base + PL080_CH_LLI); + writel(lli->cctl, phychan->base + PL080_CH_CONTROL); + writel(ccfg, phychan->base + PL080_CH_CONFIG); /* Enable the DMA channel */ /* Do not access config register until channel shows as disabled */ @@ -920,13 +908,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, */ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; - /* Now store the channel register values */ - txd->csrc = llis_va[0].src; - txd->cdst = llis_va[0].dst; - txd->clli = llis_va[0].lli; - txd->cctl = llis_va[0].cctl; - /* ccfg will be set at physical channel allocation time */ - #ifdef VERBOSE_DEBUG { int i; diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 2c834ed5f41f..29d974562df9 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -95,11 +95,6 @@ struct pl08x_phy_chan { spinlock_t lock; int signal; struct pl08x_dma_chan *serving; - u32 csrc; - u32 cdst; - u32 clli; - u32 cctl; - u32 ccfg; }; /** @@ -118,14 +113,6 @@ struct pl08x_txd { void *llis_va; struct pl08x_channel_data *cd; bool active; - /* - * Settings to be put into the physical channel when we - * trigger this txd - */ - u32 csrc; - u32 cdst; - u32 clli; - u32 cctl; }; /** -- cgit v1.2.3 From 4983a04fd2562986360b646b378f267308bc22c0 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:39:33 +0000 Subject: ARM: PL08x: move ccfg into txd structure The ccfg register is used to configure the channel parameters - the type and direction of transfer, the flow control signal and IRQ mask enables. The type and direction of transfer is known in the relevent prep_* function where a txd is created. The IRQ mask enables are always set, and the flow control signals are always set when we start processing a txd according to phychan->signal. If we store the ccfg value in the txd structure, we can avoid modifying platform data - and even having it in platform data at all. So, remove it from platform data too. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 28 ++++++++++++---------------- include/linux/amba/pl08x.h | 6 +++++- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index a1a18bde6b7f..75f9e2d4b032 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -194,15 +194,11 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_phy_chan *phychan = plchan->phychan; struct pl08x_lli *lli = &txd->llis_va[0]; - u32 val, ccfg; + u32 val, ccfg = txd->ccfg; plchan->at = txd; - /* Assign the signal to the proper control registers */ - ccfg = plchan->cd->ccfg; - ccfg &= ~(PL080_CONFIG_SRC_SEL_MASK | PL080_CONFIG_DST_SEL_MASK); - - /* If it wasn't set from AMBA, ignore it */ + /* Assign the flow control signal to this channel */ if (txd->direction == DMA_TO_DEVICE) /* Select signal as destination */ ccfg |= phychan->signal << PL080_CONFIG_DST_SEL_SHIFT; @@ -210,9 +206,6 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, /* Select signal as source */ ccfg |= phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT; - /* Always enable error and terminal interrupts */ - ccfg |= PL080_CONFIG_ERR_IRQ_MASK | PL080_CONFIG_TC_IRQ_MASK; - /* Wait for channel inactive */ while (pl08x_phy_channel_busy(phychan)) cpu_relax(); @@ -1161,8 +1154,6 @@ static void dma_set_runtime_config(struct dma_chan *chan, enum dma_slave_buswidth addr_width; u32 maxburst; u32 cctl = 0; - /* Mask out all except src and dst channel */ - u32 ccfg = cd->ccfg & 0x000003DEU; int i; /* Transfer direction */ @@ -1170,13 +1161,11 @@ static void dma_set_runtime_config(struct dma_chan *chan, if (config->direction == DMA_TO_DEVICE) { plchan->runtime_addr = config->dst_addr; cctl |= PL080_CONTROL_SRC_INCR; - ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; } else if (config->direction == DMA_FROM_DEVICE) { plchan->runtime_addr = config->src_addr; cctl |= PL080_CONTROL_DST_INCR; - ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { @@ -1226,16 +1215,15 @@ static void dma_set_runtime_config(struct dma_chan *chan, /* Modify the default channel data to fit PrimeCell request */ cd->cctl = cctl; - cd->ccfg = ccfg; dev_dbg(&pl08x->adev->dev, "configured channel %s (%s) for %s, data width %d, " - "maxburst %d words, LE, CCTL=0x%08x, CCFG=0x%08x\n", + "maxburst %d words, LE, CCTL=0x%08x\n", dma_chan_name(chan), plchan->name, (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", addr_width, maxburst, - cctl, ccfg); + cctl); } /* @@ -1340,6 +1328,10 @@ static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); txd->tx.tx_submit = pl08x_tx_submit; INIT_LIST_HEAD(&txd->node); + + /* Always enable error and terminal interrupts */ + txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK | + PL080_CONFIG_TC_IRQ_MASK; } return txd; } @@ -1369,6 +1361,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( /* Set platform data for m2m */ txd->cd = &pl08x->pd->memcpy_channel; + txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; + /* Both to be incremented or the code will break */ txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; txd->len = len; @@ -1424,12 +1418,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( */ txd->direction = direction; if (direction == DMA_TO_DEVICE) { + txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) txd->dstbus.addr = plchan->runtime_addr; else txd->dstbus.addr = plchan->cd->addr; } else if (direction == DMA_FROM_DEVICE) { + txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; if (plchan->runtime_addr) txd->srcbus.addr = plchan->runtime_addr; else diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 29d974562df9..8e74cb1845dd 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -58,7 +58,6 @@ struct pl08x_channel_data { int max_signal; u32 muxval; u32 cctl; - u32 ccfg; dma_addr_t addr; bool circular_buffer; bool single; @@ -113,6 +112,11 @@ struct pl08x_txd { void *llis_va; struct pl08x_channel_data *cd; bool active; + /* + * Settings to be put into the physical channel when we + * trigger this txd. Other registers are in llis_va[0]. + */ + u32 ccfg; }; /** -- cgit v1.2.3 From 09b3c323332206aaadfb7aa13efffa82e7719b35 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:39:53 +0000 Subject: ARM: PL08x: assign ccfg DMA request signal in prep_phy_channel() There is no need to wait until we start processing a tx descriptor before setting up the DMA request selection in the ccfg register. We know which channel and request will be used in prep_phy_channel(), so setup the ccfg request selection at txd creation time in prep_phy_channel(). Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 75f9e2d4b032..f0a29885cb83 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -194,18 +194,10 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_phy_chan *phychan = plchan->phychan; struct pl08x_lli *lli = &txd->llis_va[0]; - u32 val, ccfg = txd->ccfg; + u32 val; plchan->at = txd; - /* Assign the flow control signal to this channel */ - if (txd->direction == DMA_TO_DEVICE) - /* Select signal as destination */ - ccfg |= phychan->signal << PL080_CONFIG_DST_SEL_SHIFT; - else if (txd->direction == DMA_FROM_DEVICE) - /* Select signal as source */ - ccfg |= phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT; - /* Wait for channel inactive */ while (pl08x_phy_channel_busy(phychan)) cpu_relax(); @@ -214,13 +206,13 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n", phychan->id, lli->src, lli->dst, lli->lli, lli->cctl, - ccfg); + txd->ccfg); writel(lli->src, phychan->base + PL080_CH_SRC_ADDR); writel(lli->dst, phychan->base + PL080_CH_DST_ADDR); writel(lli->lli, phychan->base + PL080_CH_LLI); writel(lli->cctl, phychan->base + PL080_CH_CONTROL); - writel(ccfg, phychan->base + PL080_CH_CONFIG); + writel(txd->ccfg, phychan->base + PL080_CH_CONFIG); /* Enable the DMA channel */ /* Do not access config register until channel shows as disabled */ @@ -1001,6 +993,12 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, return -EBUSY; } ch->signal = ret; + + /* Assign the flow control signal to this channel */ + if (txd->direction == DMA_TO_DEVICE) + txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT; + else if (txd->direction == DMA_FROM_DEVICE) + txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT; } dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n", -- cgit v1.2.3 From 70b5ed6b6d72cd8b1a3d4b7b878a0dd132bec7ba Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:40:13 +0000 Subject: ARM: PL08x: move default cctl into txd structure Rather than modifying platform data while preparing a transfer, copy the cctl value into the txd structure and modify the value there. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 21 ++++++--------------- include/linux/amba/pl08x.h | 3 ++- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index f0a29885cb83..6d224d41be2d 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -577,7 +577,6 @@ static inline size_t pl08x_pre_boundary(u32 addr, size_t len) static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { - struct pl08x_channel_data *cd = txd->cd; struct pl08x_bus_data *mbus, *sbus; size_t remainder; int num_llis = 0; @@ -595,17 +594,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x->pool_ctr++; - /* - * Initialize bus values for this transfer - * from the passed optimal values - */ - if (!cd) { - dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__); - return 0; - } - - /* Get the default CCTL from the platform data */ - cctl = cd->cctl; + /* Get the default CCTL */ + cctl = txd->cctl; /* * On the PL080 we have two bus masters and we @@ -1358,11 +1348,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( txd->dstbus.addr = dest; /* Set platform data for m2m */ - txd->cd = &pl08x->pd->memcpy_channel; txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; + txd->cctl = pl08x->pd->memcpy_channel.cctl; /* Both to be incremented or the code will break */ - txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; + txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; txd->len = len; ret = pl08x_prep_channel_resources(plchan, txd); @@ -1415,6 +1405,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; + txd->cctl = plchan->cd->cctl; + if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->srcbus.addr = sgl->dma_address; @@ -1434,7 +1426,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( "%s direction unsupported\n", __func__); return NULL; } - txd->cd = plchan->cd; txd->len = sgl->length; ret = pl08x_prep_channel_resources(plchan, txd); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 8e74cb1845dd..8d9083067d3d 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -110,8 +110,9 @@ struct pl08x_txd { size_t len; dma_addr_t llis_bus; void *llis_va; - struct pl08x_channel_data *cd; bool active; + /* Default cctl value for LLIs */ + u32 cctl; /* * Settings to be put into the physical channel when we * trigger this txd. Other registers are in llis_va[0]. -- cgit v1.2.3 From 1cae78f12028eebdc9107eaf168add46e66fb3f8 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:40:33 +0000 Subject: ARM: PL08x: move cctl increment and protection setup to prep_slave_sg We don't need to initialize the cctl increment and protection values in the runtime_config method - we have all the inforamtion to setup these values in prep_slave_sg(). Move their initialization there. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 6d224d41be2d..72cc971e93e5 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1148,12 +1148,10 @@ static void dma_set_runtime_config(struct dma_chan *chan, plchan->runtime_direction = config->direction; if (config->direction == DMA_TO_DEVICE) { plchan->runtime_addr = config->dst_addr; - cctl |= PL080_CONTROL_SRC_INCR; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; } else if (config->direction == DMA_FROM_DEVICE) { plchan->runtime_addr = config->src_addr; - cctl |= PL080_CONTROL_DST_INCR; addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { @@ -1197,10 +1195,6 @@ static void dma_set_runtime_config(struct dma_chan *chan, cctl |= burst_sizes[i].reg; } - /* Access the cell in privileged mode, non-bufferable, non-cacheable */ - cctl &= ~PL080_CONTROL_PROT_MASK; - cctl |= PL080_CONTROL_PROT_SYS; - /* Modify the default channel data to fit PrimeCell request */ cd->cctl = cctl; @@ -1405,10 +1399,16 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; - txd->cctl = plchan->cd->cctl; + txd->cctl = plchan->cd->cctl & + ~(PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | + PL080_CONTROL_PROT_MASK); + + /* Access the cell in privileged mode, non-bufferable, non-cacheable */ + txd->cctl |= PL080_CONTROL_PROT_SYS; if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; + txd->cctl |= PL080_CONTROL_SRC_INCR; txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) txd->dstbus.addr = plchan->runtime_addr; @@ -1416,6 +1416,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( txd->dstbus.addr = plchan->cd->addr; } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; + txd->cctl |= PL080_CONTROL_DST_INCR; if (plchan->runtime_addr) txd->srcbus.addr = plchan->runtime_addr; else -- cgit v1.2.3 From c7da9a56d608145cc763bcfc9329b92c4244d8d9 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:40:53 +0000 Subject: ARM: PL08x: move AHB master port selection into prep_* functions As we initialize the default cctl value in the prep_* functions along with the increment settings, we don't need to repeat the selection of the AHB ports each time we create a LLI entry. Do this in the prep_* functions once per transfer. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 72cc971e93e5..4ee0ab19b1b6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -597,26 +597,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* Get the default CCTL */ cctl = txd->cctl; - /* - * On the PL080 we have two bus masters and we - * should select one for source and one for - * destination. We try to use AHB2 for the - * bus which does not increment (typically the - * peripheral) else we just choose something. - */ - cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2); - if (pl08x->vd->dualmaster) { - if (cctl & PL080_CONTROL_SRC_INCR) - /* Source increments, use AHB2 for destination */ - cctl |= PL080_CONTROL_DST_AHB2; - else if (cctl & PL080_CONTROL_DST_INCR) - /* Destination increments, use AHB2 for source */ - cctl |= PL080_CONTROL_SRC_AHB2; - else - /* Just pick something, source AHB1 dest AHB2 */ - cctl |= PL080_CONTROL_DST_AHB2; - } - /* Find maximum width of the source bus */ txd->srcbus.maxwidth = pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >> @@ -1340,14 +1320,25 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( txd->direction = DMA_NONE; txd->srcbus.addr = src; txd->dstbus.addr = dest; + txd->len = len; /* Set platform data for m2m */ txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd->cctl = pl08x->pd->memcpy_channel.cctl; + txd->cctl = pl08x->pd->memcpy_channel.cctl & + ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2); /* Both to be incremented or the code will break */ txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; - txd->len = len; + + /* + * On the PL080 we have two bus masters and we should select one for + * source and one for destination. We try to use AHB2 for the bus + * which does not increment (typically the peripheral) else we just + * choose something. + */ + if (pl08x->vd->dualmaster) + /* Source increments, use AHB2 for destination */ + txd->cctl |= PL080_CONTROL_DST_AHB2; ret = pl08x_prep_channel_resources(plchan, txd); if (ret) @@ -1399,8 +1390,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; + txd->len = sgl->length; + txd->cctl = plchan->cd->cctl & - ~(PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | + ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | + PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | PL080_CONTROL_PROT_MASK); /* Access the cell in privileged mode, non-bufferable, non-cacheable */ @@ -1409,6 +1403,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_SRC_INCR; + if (pl08x->vd->dualmaster) + /* Source increments, use AHB2 for destination */ + txd->cctl |= PL080_CONTROL_DST_AHB2; txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) txd->dstbus.addr = plchan->runtime_addr; @@ -1417,6 +1414,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_DST_INCR; + if (pl08x->vd->dualmaster) + /* Destination increments, use AHB2 for source */ + txd->cctl |= PL080_CONTROL_SRC_AHB2; if (plchan->runtime_addr) txd->srcbus.addr = plchan->runtime_addr; else @@ -1427,7 +1427,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( "%s direction unsupported\n", __func__); return NULL; } - txd->len = sgl->length; ret = pl08x_prep_channel_resources(plchan, txd); if (ret) -- cgit v1.2.3 From 30749cb4a40f02a199640011e5ab5c5f60b8482e Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:41:13 +0000 Subject: ARM: PL08x: allow AHB master port selection to be configured Platforms need to be able to control which AHB master interface is used, as each AHB master interface may be asymetric. Allow the interfaces used for fetching LLIs, memory, and each peripheral to be configured individually. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 77 ++++++++++++++++++++++++++-------------------- include/linux/amba/pl08x.h | 15 +++++++-- 2 files changed, 56 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4ee0ab19b1b6..986c12775b0b 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -126,6 +126,8 @@ struct pl08x_lli { * @phy_chans: array of data for the physical channels * @pool: a pool for the LLI descriptors * @pool_ctr: counter of LLIs in the pool + * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches + * @mem_buses: set to indicate memory transfers on AHB2. * @lock: a spinlock for this struct */ struct pl08x_driver_data { @@ -138,6 +140,8 @@ struct pl08x_driver_data { struct pl08x_phy_chan *phy_chans; struct dma_pool *pool; int pool_ctr; + u8 lli_buses; + u8 mem_buses; spinlock_t lock; }; @@ -526,20 +530,12 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); - llis_va[num_llis].cctl = cctl; - llis_va[num_llis].src = txd->srcbus.addr; - llis_va[num_llis].dst = txd->dstbus.addr; - - /* - * On versions with dual masters, you can optionally AND on - * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read - * in new LLIs with that controller, but we always try to - * choose AHB1 to point into memory. The idea is to have AHB2 - * fixed on the peripheral and AHB1 messing around in the - * memory. So we don't manipulate this bit currently. - */ - + llis_va[num_llis].cctl = cctl; + llis_va[num_llis].src = txd->srcbus.addr; + llis_va[num_llis].dst = txd->dstbus.addr; llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); + if (pl08x->lli_buses & PL08X_AHB2) + llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; if (cctl & PL080_CONTROL_SRC_INCR) txd->srcbus.addr += len; @@ -639,13 +635,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, &mbus, &sbus, cctl); - - /* - * The lowest bit of the LLI register - * is also used to indicate which master to - * use for reading the LLIs. - */ - if (txd->len < mbus->buswidth) { /* * Less than a bus width available @@ -1282,6 +1271,23 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return 0; } +/* + * Given the source and destination available bus masks, select which + * will be routed to each port. We try to have source and destination + * on separate ports, but always respect the allowable settings. + */ +static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) +{ + u32 cctl = 0; + + if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) + cctl |= PL080_CONTROL_DST_AHB2; + if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) + cctl |= PL080_CONTROL_SRC_AHB2; + + return cctl; +} + static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) { struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); @@ -1330,15 +1336,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( /* Both to be incremented or the code will break */ txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; - /* - * On the PL080 we have two bus masters and we should select one for - * source and one for destination. We try to use AHB2 for the bus - * which does not increment (typically the peripheral) else we just - * choose something. - */ if (pl08x->vd->dualmaster) - /* Source increments, use AHB2 for destination */ - txd->cctl |= PL080_CONTROL_DST_AHB2; + txd->cctl |= pl08x_select_bus(pl08x, + pl08x->mem_buses, pl08x->mem_buses); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) @@ -1359,6 +1359,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; + u8 src_buses, dst_buses; int ret; /* @@ -1403,31 +1404,31 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_SRC_INCR; - if (pl08x->vd->dualmaster) - /* Source increments, use AHB2 for destination */ - txd->cctl |= PL080_CONTROL_DST_AHB2; txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) txd->dstbus.addr = plchan->runtime_addr; else txd->dstbus.addr = plchan->cd->addr; + src_buses = pl08x->mem_buses; + dst_buses = plchan->cd->periph_buses; } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_DST_INCR; - if (pl08x->vd->dualmaster) - /* Destination increments, use AHB2 for source */ - txd->cctl |= PL080_CONTROL_SRC_AHB2; if (plchan->runtime_addr) txd->srcbus.addr = plchan->runtime_addr; else txd->srcbus.addr = plchan->cd->addr; txd->dstbus.addr = sgl->dma_address; + src_buses = plchan->cd->periph_buses; + dst_buses = pl08x->mem_buses; } else { dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); return NULL; } + txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); + ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; @@ -1879,6 +1880,14 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) pl08x->adev = adev; pl08x->vd = vd; + /* By default, AHB1 only. If dualmaster, from platform */ + pl08x->lli_buses = PL08X_AHB1; + pl08x->mem_buses = PL08X_AHB1; + if (pl08x->vd->dualmaster) { + pl08x->lli_buses = pl08x->pd->lli_buses; + pl08x->mem_buses = pl08x->pd->mem_buses; + } + /* A DMA memory pool for LLIs, align on 1-byte boundary */ pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev, PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 8d9083067d3d..f858651027fd 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -25,6 +25,12 @@ struct pl08x_lli; struct pl08x_driver_data; +/* Bitmasks for selecting AHB ports for DMA transfers */ +enum { + PL08X_AHB1 = (1 << 0), + PL08X_AHB2 = (1 << 1) +}; + /** * struct pl08x_channel_data - data structure to pass info between * platform and PL08x driver regarding channel configuration @@ -51,6 +57,8 @@ struct pl08x_driver_data; * round round round) * @single: the device connected to this channel will request single * DMA transfers, not bursts. (Bursts are default.) + * @periph_buses: the device connected to this channel is accessible via + * these buses (use PL08X_AHB1 | PL08X_AHB2). */ struct pl08x_channel_data { char *bus_id; @@ -61,6 +69,7 @@ struct pl08x_channel_data { dma_addr_t addr; bool circular_buffer; bool single; + u8 periph_buses; }; /** @@ -193,8 +202,8 @@ struct pl08x_dma_chan { * less than zero, else it returns the allocated signal number * @put_signal: indicate to the platform that this physical signal is not * running any DMA transfer and multiplexing can be recycled - * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the - * LLI addresses are on 0/1 Master 1/2. + * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2 + * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2 */ struct pl08x_platform_data { struct pl08x_channel_data *slave_channels; @@ -202,6 +211,8 @@ struct pl08x_platform_data { struct pl08x_channel_data memcpy_channel; int (*get_signal)(struct pl08x_dma_chan *); void (*put_signal)(struct pl08x_dma_chan *); + u8 lli_buses; + u8 mem_buses; }; #ifdef CONFIG_AMBA_PL08X -- cgit v1.2.3 From 858c21c0f380fb9c78f47f3e372f9baadc54dffe Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:41:34 +0000 Subject: ARM: PL08x: move callback outside spinlock'd region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling the callback handler with spinlocks in the tasklet held leads to deadlock when dmaengine functions are called: BUG: spinlock lockup on CPU#0, sh/417, c1870a08 Backtrace: ... [] (do_raw_spin_lock+0x0/0x154) from [] (_raw_spin_lock_irqsave+0x54/0x60) [] (_raw_spin_lock_irqsave+0x0/0x60) from [] (pl08x_prep_channel_resources+0x718/0x8b4) [] (pl08x_prep_channel_resources+0x0/0x8b4) from [] (pl08x_prep_slave_sg+0x120/0x19c) [] (pl08x_prep_slave_sg+0x0/0x19c) from [] (pl011_dma_tx_refill+0x164/0x224) [] (pl011_dma_tx_refill+0x0/0x224) from [] (pl011_dma_tx_callback+0x7c/0xc4) [] (pl011_dma_tx_callback+0x0/0xc4) from [] (pl08x_tasklet+0x60/0x368) [] (pl08x_tasklet+0x0/0x368) from [] (tasklet_action+0xa0/0x100) Dan quoted the documentation: > 2/ Completion callback routines cannot submit new operations.  This >    results in recursion in the synchronous case and spin_locks being >    acquired twice in the asynchronous case. but then followed up to say: > I should clarify, this is the async_memcpy() api requirement which is > not used outside of md/raid5. DMA drivers can and do allow new > submissions from callbacks, and the ones that do so properly move the > callback outside of the driver lock. So let's fix it by moving the callback out of the spinlocked region. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 986c12775b0b..660165dd945a 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1540,32 +1540,29 @@ static void pl08x_tasklet(unsigned long data) { struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; struct pl08x_driver_data *pl08x = plchan->host; + struct pl08x_txd *txd; + dma_async_tx_callback callback = NULL; + void *callback_param = NULL; unsigned long flags; spin_lock_irqsave(&plchan->lock, flags); - if (plchan->at) { - dma_async_tx_callback callback = - plchan->at->tx.callback; - void *callback_param = - plchan->at->tx.callback_param; + txd = plchan->at; + plchan->at = NULL; - /* - * Update last completed - */ - plchan->lc = plchan->at->tx.cookie; + if (txd) { + callback = txd->tx.callback; + callback_param = txd->tx.callback_param; /* - * Callback to signal completion + * Update last completed */ - if (callback) - callback(callback_param); + plchan->lc = txd->tx.cookie; /* * Free the descriptor */ - pl08x_free_txd(pl08x, plchan->at); - plchan->at = NULL; + pl08x_free_txd(pl08x, txd); } /* * If a new descriptor is queued, set it up @@ -1616,6 +1613,10 @@ static void pl08x_tasklet(unsigned long data) } spin_unlock_irqrestore(&plchan->lock, flags); + + /* Callback to signal completion */ + if (callback) + callback(callback_param); } static irqreturn_t pl08x_irq(int irq, void *dev) -- cgit v1.2.3 From 0059005f2cbf4847551b9ad9915ffffe23aef0b9 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:41:54 +0000 Subject: ARM: PL08x: make pl08x_fill_lli_for_desc() return void We don't need pl08x_fill_lli_for_desc() to return num_llis + 1 as we know that's what it always does. We can just pass in num_llis and use post-increment in the caller. This makes the code slightly easier to read. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 660165dd945a..f61940434669 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -521,9 +521,8 @@ static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, * Fills in one LLI for a certain transfer descriptor * and advance the counter */ -static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, - struct pl08x_txd *txd, int num_llis, int len, - u32 cctl, u32 *remainder) +static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, + struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) { struct pl08x_lli *llis_va = txd->llis_va; dma_addr_t llis_bus = txd->llis_bus; @@ -545,8 +544,6 @@ static int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, BUG_ON(*remainder < len); *remainder -= len; - - return num_llis + 1; } /* @@ -646,8 +643,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, "less than a bus width (remain 0x%08x)\n", __func__, remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - num_llis = - pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1, + pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, cctl, &remainder); total_bytes++; } @@ -662,8 +658,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, "(remain 0x%08x)\n", __func__, remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - num_llis = pl08x_fill_lli_for_desc - (pl08x, txd, num_llis, 1, cctl, &remainder); + pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, + cctl, &remainder); total_bytes++; } @@ -787,9 +783,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, dev_vdbg(&pl08x->adev->dev, "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", __func__, lli_len, remainder); - num_llis = pl08x_fill_lli_for_desc(pl08x, txd, - num_llis, lli_len, cctl, - &remainder); + pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, + lli_len, cctl, &remainder); total_bytes += lli_len; } @@ -806,10 +801,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, dev_vdbg(&pl08x->adev->dev, "%s align with boundary, single byte (remain 0x%08zx)\n", __func__, remainder); - num_llis = - pl08x_fill_lli_for_desc(pl08x, - txd, num_llis, 1, - cctl, &remainder); + pl08x_fill_lli_for_desc(pl08x, txd, + num_llis++, 1, cctl, + &remainder); total_bytes++; } } @@ -823,8 +817,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, dev_vdbg(&pl08x->adev->dev, "%s align with boundary, single odd byte (remain %zu)\n", __func__, remainder); - num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, - 1, cctl, &remainder); + pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, + cctl, &remainder); total_bytes++; } } -- cgit v1.2.3 From b61be8d728abad7fd98e62e98f22325f8f254b51 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:42:14 +0000 Subject: ARM: PL08x: ensure pl08x_pre_boundary() works for any value of addr pl08x_pre_boundary() was unsafe with addresses towards the top of memory space: boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1) << PL08X_BOUNDARY_SHIFT; This can overflow a 32-bit number, producing zero. When it does: if (boundary < addr + len) return boundary - addr; else return len; results in (boundary - addr) returning either a large positive value. Also if addr + len overflows, this calculation also fails. We can fix this trivially as the only thing we're actually interested in is the value of the least significant PL08X_BOUNDARY_SHIFT bits: boundary_len = PL08X_BOUNDARY_SIZE - (addr & (PL08X_BOUNDARY_SIZE - 1)); gives us the number of bytes before 'addr' becomes a multiple of PL08X_BOUNDARY_SIZE. We can then just take the min() of the two calculated lengths. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index f61940434669..7c327c315878 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -547,19 +547,15 @@ static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, } /* - * Return number of bytes to fill to boundary, or len + * Return number of bytes to fill to boundary, or len. + * This calculation works for any value of addr. */ static inline size_t pl08x_pre_boundary(u32 addr, size_t len) { - u32 boundary; + size_t boundary_len = PL08X_BOUNDARY_SIZE - + (addr & (PL08X_BOUNDARY_SIZE - 1)); - boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1) - << PL08X_BOUNDARY_SHIFT; - - if (boundary < addr + len) - return boundary - addr; - else - return len; + return min(boundary_len, len); } /* -- cgit v1.2.3 From d6cf7b597f7158616106068930d1c6203d9359eb Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:42:34 +0000 Subject: ARM: PL08x: use min() to calculate target_len Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 7c327c315878..91dd6bfcc30f 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -682,9 +682,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * If enough left try to send max possible, * otherwise try to send the remainder */ - target_len = remainder; - if (remainder > max_bytes_per_lli) - target_len = max_bytes_per_lli; + target_len = min(remainder, max_bytes_per_lli); /* * Set bus lengths for incrementing buses -- cgit v1.2.3 From 5f638b4f313e345bf02700910e581bccf71212f5 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:42:55 +0000 Subject: ARM: PL08x: fix fill_bytes calculation The number of bytes we want to fill into any LLI is the minimum of: - number of bytes remaining in the transfer - number of bytes we can transfer in a single LLI - number of bytes we can transfer without overflowing the source boundary - number of bytes we can transfer without overflowing the destination boundary The minimum of the first two is already calculated (target_len). We limit the boundary calculations to this number of bytes, which will then give us the number of bytes we can place into this LLI. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 91dd6bfcc30f..be7fa174d6c0 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -685,31 +685,25 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, target_len = min(remainder, max_bytes_per_lli); /* - * Set bus lengths for incrementing buses - * to number of bytes which fill to next memory - * boundary + * Set bus lengths for incrementing buses to the + * number of bytes which fill to next memory boundary, + * limiting on the target length calculated above. */ if (cctl & PL080_CONTROL_SRC_INCR) txd->srcbus.fill_bytes = - pl08x_pre_boundary( - txd->srcbus.addr, - remainder); + pl08x_pre_boundary(txd->srcbus.addr, + target_len); else - txd->srcbus.fill_bytes = - max_bytes_per_lli; + txd->srcbus.fill_bytes = target_len; if (cctl & PL080_CONTROL_DST_INCR) txd->dstbus.fill_bytes = - pl08x_pre_boundary( - txd->dstbus.addr, - remainder); + pl08x_pre_boundary(txd->dstbus.addr, + target_len); else - txd->dstbus.fill_bytes = - max_bytes_per_lli; + txd->dstbus.fill_bytes = target_len; - /* - * Find the nearest - */ + /* Find the nearest */ lli_len = min(txd->srcbus.fill_bytes, txd->dstbus.fill_bytes); -- cgit v1.2.3 From 542361f8e385355c68e263eba49d4306739b9220 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:43:15 +0000 Subject: ARM: PL08x: don't manipulate txd->srcbus or txd->dstbus during LLI fill Don't alter any txd->srcbus or txd->dstbus values while building the LLI list. This allows us to see the original dma_addr_t values passed in via the prep_memcpy() method. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 159 +++++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index be7fa174d6c0..39970c5038d6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -481,38 +481,45 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, return retbits; } +struct pl08x_lli_build_data { + struct pl08x_txd *txd; + struct pl08x_driver_data *pl08x; + struct pl08x_bus_data srcbus; + struct pl08x_bus_data dstbus; + size_t remainder; +}; + /* * Autoselect a master bus to use for the transfer * this prefers the destination bus if both available * if fixed address on one bus the other will be chosen */ -static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, - struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus, - struct pl08x_bus_data **sbus, u32 cctl) +static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, + struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) { if (!(cctl & PL080_CONTROL_DST_INCR)) { - *mbus = src_bus; - *sbus = dst_bus; + *mbus = &bd->srcbus; + *sbus = &bd->dstbus; } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { - *mbus = dst_bus; - *sbus = src_bus; + *mbus = &bd->dstbus; + *sbus = &bd->srcbus; } else { - if (dst_bus->buswidth == 4) { - *mbus = dst_bus; - *sbus = src_bus; - } else if (src_bus->buswidth == 4) { - *mbus = src_bus; - *sbus = dst_bus; - } else if (dst_bus->buswidth == 2) { - *mbus = dst_bus; - *sbus = src_bus; - } else if (src_bus->buswidth == 2) { - *mbus = src_bus; - *sbus = dst_bus; + if (bd->dstbus.buswidth == 4) { + *mbus = &bd->dstbus; + *sbus = &bd->srcbus; + } else if (bd->srcbus.buswidth == 4) { + *mbus = &bd->srcbus; + *sbus = &bd->dstbus; + } else if (bd->dstbus.buswidth == 2) { + *mbus = &bd->dstbus; + *sbus = &bd->srcbus; + } else if (bd->srcbus.buswidth == 2) { + *mbus = &bd->srcbus; + *sbus = &bd->dstbus; } else { - /* src_bus->buswidth == 1 */ - *mbus = dst_bus; - *sbus = src_bus; + /* bd->srcbus.buswidth == 1 */ + *mbus = &bd->dstbus; + *sbus = &bd->srcbus; } } } @@ -521,29 +528,29 @@ static void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, * Fills in one LLI for a certain transfer descriptor * and advance the counter */ -static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, - struct pl08x_txd *txd, int num_llis, int len, u32 cctl, u32 *remainder) +static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, + int num_llis, int len, u32 cctl) { - struct pl08x_lli *llis_va = txd->llis_va; - dma_addr_t llis_bus = txd->llis_bus; + struct pl08x_lli *llis_va = bd->txd->llis_va; + dma_addr_t llis_bus = bd->txd->llis_bus; BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); llis_va[num_llis].cctl = cctl; - llis_va[num_llis].src = txd->srcbus.addr; - llis_va[num_llis].dst = txd->dstbus.addr; + llis_va[num_llis].src = bd->srcbus.addr; + llis_va[num_llis].dst = bd->dstbus.addr; llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); - if (pl08x->lli_buses & PL08X_AHB2) + if (bd->pl08x->lli_buses & PL08X_AHB2) llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; if (cctl & PL080_CONTROL_SRC_INCR) - txd->srcbus.addr += len; + bd->srcbus.addr += len; if (cctl & PL080_CONTROL_DST_INCR) - txd->dstbus.addr += len; + bd->dstbus.addr += len; - BUG_ON(*remainder < len); + BUG_ON(bd->remainder < len); - *remainder -= len; + bd->remainder -= len; } /* @@ -567,7 +574,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { struct pl08x_bus_data *mbus, *sbus; - size_t remainder; + struct pl08x_lli_build_data bd; int num_llis = 0; u32 cctl; size_t max_bytes_per_lli; @@ -586,38 +593,43 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* Get the default CCTL */ cctl = txd->cctl; + bd.txd = txd; + bd.pl08x = pl08x; + bd.srcbus.addr = txd->srcbus.addr; + bd.dstbus.addr = txd->dstbus.addr; + /* Find maximum width of the source bus */ - txd->srcbus.maxwidth = + bd.srcbus.maxwidth = pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >> PL080_CONTROL_SWIDTH_SHIFT); /* Find maximum width of the destination bus */ - txd->dstbus.maxwidth = + bd.dstbus.maxwidth = pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> PL080_CONTROL_DWIDTH_SHIFT); /* Set up the bus widths to the maximum */ - txd->srcbus.buswidth = txd->srcbus.maxwidth; - txd->dstbus.buswidth = txd->dstbus.maxwidth; + bd.srcbus.buswidth = bd.srcbus.maxwidth; + bd.dstbus.buswidth = bd.dstbus.maxwidth; dev_vdbg(&pl08x->adev->dev, "%s source bus is %d bytes wide, dest bus is %d bytes wide\n", - __func__, txd->srcbus.buswidth, txd->dstbus.buswidth); + __func__, bd.srcbus.buswidth, bd.dstbus.buswidth); /* * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) */ - max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) * + max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * PL080_CONTROL_TRANSFER_SIZE_MASK; dev_vdbg(&pl08x->adev->dev, "%s max bytes per lli = %zu\n", __func__, max_bytes_per_lli); /* We need to count this down to zero */ - remainder = txd->len; + bd.remainder = txd->len; dev_vdbg(&pl08x->adev->dev, "%s remainder = %zu\n", - __func__, remainder); + __func__, bd.remainder); /* * Choose bus to align to @@ -625,22 +637,20 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * - if fixed address on one bus chooses other * - modifies cctl to choose an appropriate master */ - pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, - &mbus, &sbus, cctl); + pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); if (txd->len < mbus->buswidth) { /* * Less than a bus width available * - send as single bytes */ - while (remainder) { + while (bd.remainder) { dev_vdbg(&pl08x->adev->dev, "%s single byte LLIs for a transfer of " "less than a bus width (remain 0x%08x)\n", - __func__, remainder); + __func__, bd.remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, - cctl, &remainder); + pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); total_bytes++; } } else { @@ -652,10 +662,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, dev_vdbg(&pl08x->adev->dev, "%s adjustment lli for less than bus width " "(remain 0x%08x)\n", - __func__, remainder); + __func__, bd.remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, - cctl, &remainder); + pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); total_bytes++; } @@ -675,14 +684,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * Make largest possible LLIs until less than one bus * width left */ - while (remainder > (mbus->buswidth - 1)) { + while (bd.remainder > (mbus->buswidth - 1)) { size_t lli_len, target_len, tsize, odd_bytes; /* * If enough left try to send max possible, * otherwise try to send the remainder */ - target_len = min(remainder, max_bytes_per_lli); + target_len = min(bd.remainder, max_bytes_per_lli); /* * Set bus lengths for incrementing buses to the @@ -690,24 +699,24 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * limiting on the target length calculated above. */ if (cctl & PL080_CONTROL_SRC_INCR) - txd->srcbus.fill_bytes = - pl08x_pre_boundary(txd->srcbus.addr, + bd.srcbus.fill_bytes = + pl08x_pre_boundary(bd.srcbus.addr, target_len); else - txd->srcbus.fill_bytes = target_len; + bd.srcbus.fill_bytes = target_len; if (cctl & PL080_CONTROL_DST_INCR) - txd->dstbus.fill_bytes = - pl08x_pre_boundary(txd->dstbus.addr, + bd.dstbus.fill_bytes = + pl08x_pre_boundary(bd.dstbus.addr, target_len); else - txd->dstbus.fill_bytes = target_len; + bd.dstbus.fill_bytes = target_len; /* Find the nearest */ - lli_len = min(txd->srcbus.fill_bytes, - txd->dstbus.fill_bytes); + lli_len = min(bd.srcbus.fill_bytes, + bd.dstbus.fill_bytes); - BUG_ON(lli_len > remainder); + BUG_ON(lli_len > bd.remainder); if (lli_len <= 0) { dev_err(&pl08x->adev->dev, @@ -764,15 +773,15 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } cctl = pl08x_cctl_bits(cctl, - txd->srcbus.buswidth, - txd->dstbus.buswidth, + bd.srcbus.buswidth, + bd.dstbus.buswidth, tsize); dev_vdbg(&pl08x->adev->dev, "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", - __func__, lli_len, remainder); - pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, - lli_len, cctl, &remainder); + __func__, lli_len, bd.remainder); + pl08x_fill_lli_for_desc(&bd, num_llis++, + lli_len, cctl); total_bytes += lli_len; } @@ -784,14 +793,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, */ int j; for (j = 0; (j < mbus->buswidth) - && (remainder); j++) { + && (bd.remainder); j++) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, "%s align with boundary, single byte (remain 0x%08zx)\n", - __func__, remainder); - pl08x_fill_lli_for_desc(pl08x, txd, - num_llis++, 1, cctl, - &remainder); + __func__, bd.remainder); + pl08x_fill_lli_for_desc(&bd, + num_llis++, 1, cctl); total_bytes++; } } @@ -800,13 +808,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * Send any odd bytes */ - while (remainder) { + while (bd.remainder) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, "%s align with boundary, single odd byte (remain %zu)\n", - __func__, remainder); - pl08x_fill_lli_for_desc(pl08x, txd, num_llis++, 1, - cctl, &remainder); + __func__, bd.remainder); + pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); total_bytes++; } } -- cgit v1.2.3 From d7244e9a27a3da27d62aabf560ee828d7991493e Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:43:35 +0000 Subject: ARM: PL08x: shrink srcbus/dstbus in txd structure We only need to store the dma address. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 20 ++++++++++---------- include/linux/amba/pl08x.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 39970c5038d6..8d8d33ce5684 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -595,8 +595,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, bd.txd = txd; bd.pl08x = pl08x; - bd.srcbus.addr = txd->srcbus.addr; - bd.dstbus.addr = txd->dstbus.addr; + bd.srcbus.addr = txd->src_addr; + bd.dstbus.addr = txd->dst_addr; /* Find maximum width of the source bus */ bd.srcbus.maxwidth = @@ -1313,8 +1313,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( } txd->direction = DMA_NONE; - txd->srcbus.addr = src; - txd->dstbus.addr = dest; + txd->src_addr = src; + txd->dst_addr = dest; txd->len = len; /* Set platform data for m2m */ @@ -1393,21 +1393,21 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( if (direction == DMA_TO_DEVICE) { txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_SRC_INCR; - txd->srcbus.addr = sgl->dma_address; + txd->src_addr = sgl->dma_address; if (plchan->runtime_addr) - txd->dstbus.addr = plchan->runtime_addr; + txd->dst_addr = plchan->runtime_addr; else - txd->dstbus.addr = plchan->cd->addr; + txd->dst_addr = plchan->cd->addr; src_buses = pl08x->mem_buses; dst_buses = plchan->cd->periph_buses; } else if (direction == DMA_FROM_DEVICE) { txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; txd->cctl |= PL080_CONTROL_DST_INCR; if (plchan->runtime_addr) - txd->srcbus.addr = plchan->runtime_addr; + txd->src_addr = plchan->runtime_addr; else - txd->srcbus.addr = plchan->cd->addr; - txd->dstbus.addr = sgl->dma_address; + txd->src_addr = plchan->cd->addr; + txd->dst_addr = sgl->dma_address; src_buses = plchan->cd->periph_buses; dst_buses = pl08x->mem_buses; } else { diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index f858651027fd..4e9e71860e1c 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -114,8 +114,8 @@ struct pl08x_txd { struct dma_async_tx_descriptor tx; struct list_head node; enum dma_data_direction direction; - struct pl08x_bus_data srcbus; - struct pl08x_bus_data dstbus; + dma_addr_t src_addr; + dma_addr_t dst_addr; size_t len; dma_addr_t llis_bus; void *llis_va; -- cgit v1.2.3 From c04287948ec8308fceedda980373bc7d53620255 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:43:56 +0000 Subject: ARM: PL08x: store prep_* flags in async_tx structure Like other DMA engine drivers do, store the passed flags into the async_tx structure, so they can be checked when the operation completes. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 8d8d33ce5684..00058e30a9c3 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1277,12 +1277,14 @@ static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) return cctl; } -static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan) +static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, + unsigned long flags) { struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); if (txd) { dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); + txd->tx.flags = flags; txd->tx.tx_submit = pl08x_tx_submit; INIT_LIST_HEAD(&txd->node); @@ -1305,7 +1307,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( struct pl08x_txd *txd; int ret; - txd = pl08x_get_txd(plchan); + txd = pl08x_get_txd(plchan, flags); if (!txd) { dev_err(&pl08x->adev->dev, "%s no memory for descriptor\n", __func__); @@ -1363,7 +1365,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n", __func__, sgl->length, plchan->name); - txd = pl08x_get_txd(plchan); + txd = pl08x_get_txd(plchan, flags); if (!txd) { dev_err(&pl08x->adev->dev, "%s no txd\n", __func__); return NULL; -- cgit v1.2.3 From 3d992e1a6f8465db3921ef75bfc490fbd2f40cd3 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:44:16 +0000 Subject: ARM: PL08x: implement unmapping of memcpy buffers The DMA engine API requires DMA engine implementations to unmap buffers passed into the non-slave DMA methods unless the relevant completion flag is set. We aren't doing this, so implement this facility. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 52 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 00058e30a9c3..fb469dedcdf3 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1527,13 +1527,33 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) writel(val, pl08x->base + PL080_CONFIG); } +static void pl08x_unmap_buffers(struct pl08x_txd *txd) +{ + struct device *dev = txd->tx.chan->device->dev; + + if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(dev, txd->src_addr, txd->len, + DMA_TO_DEVICE); + else + dma_unmap_page(dev, txd->src_addr, txd->len, + DMA_TO_DEVICE); + } + if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(dev, txd->dst_addr, txd->len, + DMA_FROM_DEVICE); + else + dma_unmap_page(dev, txd->dst_addr, txd->len, + DMA_FROM_DEVICE); + } +} + static void pl08x_tasklet(unsigned long data) { struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; - dma_async_tx_callback callback = NULL; - void *callback_param = NULL; unsigned long flags; spin_lock_irqsave(&plchan->lock, flags); @@ -1542,18 +1562,10 @@ static void pl08x_tasklet(unsigned long data) plchan->at = NULL; if (txd) { - callback = txd->tx.callback; - callback_param = txd->tx.callback_param; - /* * Update last completed */ plchan->lc = txd->tx.cookie; - - /* - * Free the descriptor - */ - pl08x_free_txd(pl08x, txd); } /* * If a new descriptor is queued, set it up @@ -1605,9 +1617,23 @@ static void pl08x_tasklet(unsigned long data) spin_unlock_irqrestore(&plchan->lock, flags); - /* Callback to signal completion */ - if (callback) - callback(callback_param); + if (txd) { + dma_async_tx_callback callback = txd->tx.callback; + void *callback_param = txd->tx.callback_param; + + /* Don't try to unmap buffers on slave channels */ + if (!plchan->slave) + pl08x_unmap_buffers(txd); + + /* Free the descriptor */ + spin_lock_irqsave(&plchan->lock, flags); + pl08x_free_txd(pl08x, txd); + spin_unlock_irqrestore(&plchan->lock, flags); + + /* Callback to signal completion */ + if (callback) + callback(callback_param); + } } static irqreturn_t pl08x_irq(int irq, void *dev) -- cgit v1.2.3 From 15c17232fbd1f7687c740c3c26f9e7f337bd9e36 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:44:36 +0000 Subject: ARM: PL08x: rename 'desc_list' as 'pend_list' This 'desc_list' is actually a list of pending descriptors, so name it after its function (pending list) rather than what it contains (descriptors). Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 20 ++++++++++---------- include/linux/amba/pl08x.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index fb469dedcdf3..433b9e747f75 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -348,9 +348,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) } /* Sum up all queued transactions */ - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *txdi; - list_for_each_entry(txdi, &plchan->desc_list, node) { + list_for_each_entry(txdi, &plchan->pend_list, node) { bytes += txdi->len; } } @@ -880,9 +880,9 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, struct pl08x_txd *txdi = NULL; struct pl08x_txd *next; - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { list_for_each_entry_safe(txdi, - next, &plchan->desc_list, node) { + next, &plchan->pend_list, node) { list_del(&txdi->node); pl08x_free_txd(pl08x, txdi); } @@ -1183,10 +1183,10 @@ static void pl08x_issue_pending(struct dma_chan *chan) } /* Take the first element in the queue and execute it */ - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *next; - next = list_first_entry(&plchan->desc_list, + next = list_first_entry(&plchan->pend_list, struct pl08x_txd, node); list_del(&next->node); @@ -1213,7 +1213,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, spin_lock_irqsave(&plchan->lock, plchan->lockflags); - list_add_tail(&txd->node, &plchan->desc_list); + list_add_tail(&txd->node, &plchan->pend_list); /* * See if we already have a physical channel allocated, @@ -1571,10 +1571,10 @@ static void pl08x_tasklet(unsigned long data) * If a new descriptor is queued, set it up * plchan->at is NULL here */ - if (!list_empty(&plchan->desc_list)) { + if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *next; - next = list_first_entry(&plchan->desc_list, + next = list_first_entry(&plchan->pend_list, struct pl08x_txd, node); list_del(&next->node); @@ -1736,7 +1736,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, chan->lc = 0; spin_lock_init(&chan->lock); - INIT_LIST_HEAD(&chan->desc_list); + INIT_LIST_HEAD(&chan->pend_list); tasklet_init(&chan->tasklet, pl08x_tasklet, (unsigned long) chan); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 4e9e71860e1c..08a9024e2d2f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -158,7 +158,7 @@ enum pl08x_dma_chan_state { * @runtime_direction: current direction of this channel according to * runtime config * @lc: last completed transaction on this channel - * @desc_list: queued transactions pending on this channel + * @pend_list: queued transactions pending on this channel * @at: active transaction on this channel * @lockflags: sometimes we let a lock last between two function calls, * especially prep/submit, and then we need to store the IRQ flags @@ -179,7 +179,7 @@ struct pl08x_dma_chan { dma_addr_t runtime_addr; enum dma_data_direction runtime_direction; dma_cookie_t lc; - struct list_head desc_list; + struct list_head pend_list; struct pl08x_txd *at; unsigned long lockflags; spinlock_t lock; -- cgit v1.2.3 From 501e67e82dee68d0a594ec0549f3d6a2943c91f5 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:44:57 +0000 Subject: ARM: PL08x: put txd's on the pending list in pl08x_tx_submit() Don't place TXDs on the pending list when they're prepared - place them on the list when they're ready to be submitted. Also, only place memcpy requests in the wait state when they're submitted and don't have a physical channel associated. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 433b9e747f75..650e2bbc7aad 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -173,6 +173,11 @@ static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan) return container_of(chan, struct pl08x_dma_chan, chan); } +static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx) +{ + return container_of(tx, struct pl08x_txd, tx); +} + /* * Physical channel handling */ @@ -974,11 +979,27 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan) static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) { struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan); + struct pl08x_txd *txd = to_pl08x_txd(tx); plchan->chan.cookie += 1; if (plchan->chan.cookie < 0) plchan->chan.cookie = 1; tx->cookie = plchan->chan.cookie; + + /* Put this onto the pending list */ + list_add_tail(&txd->node, &plchan->pend_list); + + /* + * If there was no physical channel available for this memcpy, + * stack the request up and indicate that the channel is waiting + * for a free physical channel. + */ + if (!plchan->slave && !plchan->phychan) { + /* Do this memcpy whenever there is a channel ready */ + plchan->state = PL08X_CHAN_WAITING; + plchan->waiting = txd; + } + /* This unlock follows the lock in the prep() function */ spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); @@ -1213,8 +1234,6 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, spin_lock_irqsave(&plchan->lock, plchan->lockflags); - list_add_tail(&txd->node, &plchan->pend_list); - /* * See if we already have a physical channel allocated, * else this is the time to try to get one. @@ -1222,24 +1241,23 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, ret = prep_phy_channel(plchan, txd); if (ret) { /* - * No physical channel available, we will - * stack up the memcpy channels until there is a channel - * available to handle it whereas slave transfers may - * have been denied due to platform channel muxing restrictions - * and since there is no guarantee that this will ever be - * resolved, and since the signal must be acquired AFTER - * acquiring the physical channel, we will let them be NACK:ed - * with -EBUSY here. The drivers can alway retry the prep() - * call if they are eager on doing this using DMA. + * No physical channel was available. + * + * memcpy transfers can be sorted out at submission time. + * + * Slave transfers may have been denied due to platform + * channel muxing restrictions. Since there is no guarantee + * that this will ever be resolved, and the signal must be + * acquired AFTER acquiring the physical channel, we will let + * them be NACK:ed with -EBUSY here. The drivers can retry + * the prep() call if they are eager on doing this using DMA. */ if (plchan->slave) { pl08x_free_txd_list(pl08x, plchan); + pl08x_free_txd(pl08x, txd); spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); return -EBUSY; } - /* Do this memcpy whenever there is a channel ready */ - plchan->state = PL08X_CHAN_WAITING; - plchan->waiting = txd; } else /* * Else we're all set, paused and ready to roll, -- cgit v1.2.3 From 8087aacda040bdbf84940712d132ce80c30b9d5d Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:45:17 +0000 Subject: ARM: PL08x: introduce 'phychan_hold' to hold on to physical channels Introduce 'phychan_hold' to hold on to physical DMA channels while we're preparing a new descriptor for it. This will be incremented when we allocate a physical channel and set the MUX registers during the preparation of the TXD, and will only be decremented when the TXD is submitted. This prevents the physical channel being given up before the new TXD is placed on the queue. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 11 +++++++++++ include/linux/amba/pl08x.h | 3 +++ 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 650e2bbc7aad..bf6f7d02c9f6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -959,6 +959,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, ch->signal, plchan->name); + plchan->phychan_hold++; plchan->phychan = ch; return 0; @@ -998,6 +999,8 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) /* Do this memcpy whenever there is a channel ready */ plchan->state = PL08X_CHAN_WAITING; plchan->waiting = txd; + } else { + plchan->phychan_hold--; } /* This unlock follows the lock in the prep() function */ @@ -1585,6 +1588,7 @@ static void pl08x_tasklet(unsigned long data) */ plchan->lc = txd->tx.cookie; } + /* * If a new descriptor is queued, set it up * plchan->at is NULL here @@ -1598,6 +1602,12 @@ static void pl08x_tasklet(unsigned long data) list_del(&next->node); pl08x_start_txd(plchan, next); + } else if (plchan->phychan_hold) { + /* + * This channel is still in use - we have a new txd being + * prepared and will soon be queued. Don't give up the + * physical channel. + */ } else { struct pl08x_dma_chan *waiting = NULL; @@ -1625,6 +1635,7 @@ static void pl08x_tasklet(unsigned long data) ret = prep_phy_channel(waiting, waiting->waiting); BUG_ON(ret); + waiting->phychan_hold--; waiting->state = PL08X_CHAN_RUNNING; waiting->waiting = NULL; pl08x_issue_pending(&waiting->chan); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 08a9024e2d2f..95b76ea1829f 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -151,6 +151,8 @@ enum pl08x_dma_chan_state { * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel * @chan: wrappped abstract channel * @phychan: the physical channel utilized by this channel, if there is one + * @phychan_hold: if non-zero, hold on to the physical channel even if we + * have no pending entries * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel * @cd: channel platform data @@ -173,6 +175,7 @@ enum pl08x_dma_chan_state { struct pl08x_dma_chan { struct dma_chan chan; struct pl08x_phy_chan *phychan; + int phychan_hold; struct tasklet_struct tasklet; char *name; struct pl08x_channel_data *cd; -- cgit v1.2.3 From c370e594efe2993620d24d41a78f325102e99d1c Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:45:37 +0000 Subject: ARM: PL08x: fix locking between prepare function and submit function The PL08x driver holds on to the channel lock with interrupts disabled between the prepare and the subsequent submit API functions. This means that the locking state when the prepare function returns is dependent on whether it suceeeds or not. It did this to ensure that the physical channel wasn't released, and as it used to add the descriptor onto the pending list at prepare time rather than submit time. Now that we have reorganized the code to remove those reasons, we can now safely release the spinlock at the end of preparation and reacquire it in our submit function. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 28 +++++++++------------------- include/linux/amba/pl08x.h | 4 ---- 2 files changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index bf6f7d02c9f6..1c9f712520d6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -981,6 +981,9 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) { struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan); struct pl08x_txd *txd = to_pl08x_txd(tx); + unsigned long flags; + + spin_lock_irqsave(&plchan->lock, flags); plchan->chan.cookie += 1; if (plchan->chan.cookie < 0) @@ -1003,8 +1006,7 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) plchan->phychan_hold--; } - /* This unlock follows the lock in the prep() function */ - spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); + spin_unlock_irqrestore(&plchan->lock, flags); return tx->cookie; } @@ -1225,9 +1227,9 @@ static void pl08x_issue_pending(struct dma_chan *chan) static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, struct pl08x_txd *txd) { - int num_llis; struct pl08x_driver_data *pl08x = plchan->host; - int ret; + unsigned long flags; + int num_llis, ret; num_llis = pl08x_fill_llis_for_desc(pl08x, txd); if (!num_llis) { @@ -1235,7 +1237,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, return -EINVAL; } - spin_lock_irqsave(&plchan->lock, plchan->lockflags); + spin_lock_irqsave(&plchan->lock, flags); /* * See if we already have a physical channel allocated, @@ -1258,7 +1260,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, if (plchan->slave) { pl08x_free_txd_list(pl08x, plchan); pl08x_free_txd(pl08x, txd); - spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); + spin_unlock_irqrestore(&plchan->lock, flags); return -EBUSY; } } else @@ -1272,11 +1274,7 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, if (plchan->state == PL08X_CHAN_IDLE) plchan->state = PL08X_CHAN_PAUSED; - /* - * Notice that we leave plchan->lock locked on purpose: - * it will be unlocked in the subsequent tx_submit() - * call. This is a consequence of the current API. - */ + spin_unlock_irqrestore(&plchan->lock, flags); return 0; } @@ -1355,10 +1353,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; - /* - * NB: the channel lock is held at this point so tx_submit() - * must be called in direct succession. - */ return &txd->tx; } @@ -1444,10 +1438,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; - /* - * NB: the channel lock is held at this point so tx_submit() - * must be called in direct succession. - */ return &txd->tx; } diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 95b76ea1829f..933b4ed12be5 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -162,9 +162,6 @@ enum pl08x_dma_chan_state { * @lc: last completed transaction on this channel * @pend_list: queued transactions pending on this channel * @at: active transaction on this channel - * @lockflags: sometimes we let a lock last between two function calls, - * especially prep/submit, and then we need to store the IRQ flags - * in the channel state, here * @lock: a lock for this channel data * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc @@ -184,7 +181,6 @@ struct pl08x_dma_chan { dma_cookie_t lc; struct list_head pend_list; struct pl08x_txd *at; - unsigned long lockflags; spinlock_t lock; struct pl08x_driver_data *host; enum pl08x_dma_chan_state state; -- cgit v1.2.3 From f0fd944625b6e406dc273b8dffa16e0728c973e6 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:45:57 +0000 Subject: ARM: PL08x: allow dma_set_runtime_config() to return errors There are cases in dma_set_runtime_config() where we fail to perform the requested action - and we just issue a KERN_ERR message in that case. We have the facility to return an error to the caller, so that is what we should do. When we encounter an error due to invalid parameters, we should not modify driver state. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 1c9f712520d6..c7f7b82f6155 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1117,13 +1117,14 @@ static const struct burst_table burst_sizes[] = { }, }; -static void dma_set_runtime_config(struct dma_chan *chan, - struct dma_slave_config *config) +static int dma_set_runtime_config(struct dma_chan *chan, + struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_channel_data *cd = plchan->cd; enum dma_slave_buswidth addr_width; + dma_addr_t addr; u32 maxburst; u32 cctl = 0; int i; @@ -1131,17 +1132,17 @@ static void dma_set_runtime_config(struct dma_chan *chan, /* Transfer direction */ plchan->runtime_direction = config->direction; if (config->direction == DMA_TO_DEVICE) { - plchan->runtime_addr = config->dst_addr; + addr = config->dst_addr; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; } else if (config->direction == DMA_FROM_DEVICE) { - plchan->runtime_addr = config->src_addr; + addr = config->src_addr; addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { dev_err(&pl08x->adev->dev, "bad runtime_config: alien transfer direction\n"); - return; + return -EINVAL; } switch (addr_width) { @@ -1160,7 +1161,7 @@ static void dma_set_runtime_config(struct dma_chan *chan, default: dev_err(&pl08x->adev->dev, "bad runtime_config: alien address width\n"); - return; + return -EINVAL; } /* @@ -1179,6 +1180,8 @@ static void dma_set_runtime_config(struct dma_chan *chan, cctl |= burst_sizes[i].reg; } + plchan->runtime_addr = addr; + /* Modify the default channel data to fit PrimeCell request */ cd->cctl = cctl; @@ -1190,6 +1193,8 @@ static void dma_set_runtime_config(struct dma_chan *chan, addr_width, maxburst, cctl); + + return 0; } /* @@ -1452,10 +1457,8 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, /* Controls applicable to inactive channels */ if (cmd == DMA_SLAVE_CONFIG) { - dma_set_runtime_config(chan, - (struct dma_slave_config *) - arg); - return 0; + return dma_set_runtime_config(chan, + (struct dma_slave_config *)arg); } /* -- cgit v1.2.3 From b7f758659265c173380b792862aaad1c23c0e004 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 3 Jan 2011 22:46:17 +0000 Subject: ARM: PL08x: prevent dma_set_runtime_config() reconfiguring memcpy channels Prevent dma_set_runtime_config() being used to alter the configuration supplied by the platform for memcpy channel configuration. No one should be trying to change this configuration. Signed-off-by: Russell King Acked-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index c7f7b82f6155..bebc678ed4fc 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1129,6 +1129,9 @@ static int dma_set_runtime_config(struct dma_chan *chan, u32 cctl = 0; int i; + if (!plchan->slave) + return -EINVAL; + /* Transfer direction */ plchan->runtime_direction = config->direction; if (config->direction == DMA_TO_DEVICE) { -- cgit v1.2.3 From 6c2df40ec00e52a5fb0c691b0e79324b9015aaa4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Dec 2010 12:30:31 +1000 Subject: vga_switcheroo: print the IGD/DIS flag in the debugfs output. We really want to see this so we can confirm that we pick the right one. Signed-off-by: Dave Airlie --- drivers/gpu/vga/vga_switcheroo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index c8768f38511e..0a8678fe4d64 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -174,7 +174,8 @@ static int vga_switcheroo_show(struct seq_file *m, void *v) int i; mutex_lock(&vgasr_mutex); for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - seq_printf(m, "%d:%c:%s:%s\n", i, + seq_printf(m, "%d:%s:%c:%s:%s\n", i, + vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", vgasr_priv.clients[i].active ? '+' : ' ', vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off", pci_name(vgasr_priv.clients[i].pdev)); -- cgit v1.2.3 From 5cfb3c3a1013e7fca54c3624871755cdfd960b3b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Dec 2010 12:31:50 +1000 Subject: vga_switcheroo: make power switch handler optional At least on the nvidia mux the power switch seems to be executed by the ACPI PS0/PS3 methods so need to do it explicitly. Signed-off-by: Dave Airlie --- drivers/gpu/vga/vga_switcheroo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 0a8678fe4d64..c3c213b74478 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -191,9 +191,8 @@ static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file) static int vga_switchon(struct vga_switcheroo_client *client) { - int ret; - - ret = vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); + if (vgasr_priv.handler->power_state) + vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); /* call the driver callback to turn on device */ client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); client->pwr_state = VGA_SWITCHEROO_ON; @@ -204,7 +203,8 @@ static int vga_switchoff(struct vga_switcheroo_client *client) { /* call the driver callback to turn off device */ client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); - vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); + if (vgasr_priv.handler->power_state) + vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); client->pwr_state = VGA_SWITCHEROO_OFF; return 0; } -- cgit v1.2.3 From 851ab954daee0d8328e239a468835e36e6215182 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Dec 2010 12:35:52 +1000 Subject: vga_switcheroo: add debugging mux switch option. This allows the mux to be switched from userspace using MIGD/MDIS command to the switch. Signed-off-by: Dave Airlie --- drivers/gpu/vga/vga_switcheroo.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index c3c213b74478..463691a1650e 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -266,6 +266,7 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, const char *pdev_name; int i, ret; bool delay = false, can_switch; + bool just_mux = false; int client_id = -1; struct vga_switcheroo_client *client = NULL; @@ -320,6 +321,15 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, if (strncmp(usercmd, "DIS", 3) == 0) client_id = VGA_SWITCHEROO_DIS; + if (strncmp(usercmd, "MIGD", 3) == 0) { + just_mux = true; + client_id = VGA_SWITCHEROO_IGD; + } + if (strncmp(usercmd, "MDIS", 3) == 0) { + just_mux = true; + client_id = VGA_SWITCHEROO_DIS; + } + if (client_id == -1) goto out; @@ -331,6 +341,12 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, } vgasr_priv.delayed_switch_active = false; + + if (just_mux) { + ret = vgasr_priv.handler->switchto(client_id); + goto out; + } + /* okay we want a switch - test if devices are willing to switch */ can_switch = true; for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { -- cgit v1.2.3 From 5ccb377feaaff3daa1e9a179534bbd7550d78af6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 7 Dec 2010 13:56:26 +1000 Subject: drm/nouveau: add delayed switch complete callback. this just adds the callback on the delayed switch mechanism. Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_state.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index d5b17b6ccd3a..db4b410f4a8c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -1054,6 +1054,7 @@ err_out: void nouveau_lastclose(struct drm_device *dev) { + vga_switcheroo_process_delayed_switch(); } int nouveau_unload(struct drm_device *dev) -- cgit v1.2.3 From d1fbd923da0f982f12b61a44e74c2e1f74c6ef56 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Dec 2010 12:56:44 +1000 Subject: nouveau/acpi: improve detection of what is IGD and what is DIS. This improves the IGD/DIS picking using firstly if Intel, then if the bus is bus 0. There may be a correct way to do this, but I've no idea what it is. Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 119152606e4c..a54238058dc5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -130,10 +130,15 @@ static int nouveau_dsm_init(void) static int nouveau_dsm_get_client_id(struct pci_dev *pdev) { - if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) + /* easy option one - intel vendor ID means Integrated */ + if (pdev->vendor == PCI_VENDOR_ID_INTEL) return VGA_SWITCHEROO_IGD; - else - return VGA_SWITCHEROO_DIS; + + /* is this device on Bus 0? - this may need improving */ + if (pdev->bus->number == 0) + return VGA_SWITCHEROO_IGD; + + return VGA_SWITCHEROO_DIS; } static struct vga_switcheroo_handler nouveau_dsm_handler = { -- cgit v1.2.3 From 8d608aa6295242fe4c4b6105b8c59c6a5b232d89 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 7 Dec 2010 08:57:57 +1000 Subject: vga_switcheroo: add reprobe hook for fbcon to recheck connected outputs. This adds a hook after the mux is switched for the driver to reprobe the connected outputs. Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/nouveau/nouveau_state.c | 7 +++++++ drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/vga/vga_switcheroo.c | 6 ++++++ include/linux/vga_switcheroo.h | 1 + 5 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8cb7f93732c2..ec1f650f6fab 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1231,6 +1231,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ret = vga_switcheroo_register_client(dev->pdev, i915_switcheroo_set_state, + NULL, i915_switcheroo_can_switch); if (ret) goto cleanup_vga_client; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index db4b410f4a8c..1b87eee22fa9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -605,6 +605,12 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev, } } +static void nouveau_switcheroo_reprobe(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + nouveau_fbcon_output_poll_changed(dev); +} + static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); @@ -625,6 +631,7 @@ nouveau_card_init(struct drm_device *dev) vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, + nouveau_switcheroo_reprobe, nouveau_switcheroo_can_switch); /* Initialise internal driver API hooks */ diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 96f0eb484ce6..1a1017f0d9db 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -779,6 +779,7 @@ int radeon_device_init(struct radeon_device *rdev, vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); vga_switcheroo_register_client(rdev->pdev, radeon_switcheroo_set_state, + NULL, radeon_switcheroo_can_switch); r = radeon_init(rdev); diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 463691a1650e..2b8e1d25e8d0 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -33,6 +33,7 @@ struct vga_switcheroo_client { struct fb_info *fb_info; int pwr_state; void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state); + void (*reprobe)(struct pci_dev *pdev); bool (*can_switch)(struct pci_dev *pdev); int id; bool active; @@ -103,6 +104,7 @@ static void vga_switcheroo_enable(void) int vga_switcheroo_register_client(struct pci_dev *pdev, void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state), + void (*reprobe)(struct pci_dev *pdev), bool (*can_switch)(struct pci_dev *pdev)) { int index; @@ -117,6 +119,7 @@ int vga_switcheroo_register_client(struct pci_dev *pdev, vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON; vgasr_priv.clients[index].pdev = pdev; vgasr_priv.clients[index].set_gpu_state = set_gpu_state; + vgasr_priv.clients[index].reprobe = reprobe; vgasr_priv.clients[index].can_switch = can_switch; vgasr_priv.clients[index].id = -1; if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) @@ -251,6 +254,9 @@ static int vga_switchto(struct vga_switcheroo_client *new_client) if (ret) return ret; + if (new_client->reprobe) + new_client->reprobe(new_client->pdev); + if (active->pwr_state == VGA_SWITCHEROO_ON) vga_switchoff(active); diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h index ae9ab13b963d..f80fa9de5b82 100644 --- a/include/linux/vga_switcheroo.h +++ b/include/linux/vga_switcheroo.h @@ -33,6 +33,7 @@ struct vga_switcheroo_handler { void vga_switcheroo_unregister_client(struct pci_dev *dev); int vga_switcheroo_register_client(struct pci_dev *dev, void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state), + void (*reprobe)(struct pci_dev *dev), bool (*can_switch)(struct pci_dev *dev)); void vga_switcheroo_client_fb_set(struct pci_dev *dev, -- cgit v1.2.3 From 5bcf719b7db0f9366cedaf102b081f99b1c325ae Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 7 Dec 2010 09:20:40 +1000 Subject: drm/switcheroo: track state of switch in drivers. We need to track the state of the switch in drivers, so that after s/r we don't resume the card we've explicitly switched off before. Also don't allow a userspace open to occur if we've switched the gpu off. Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fops.c | 2 ++ drivers/gpu/drm/i915/i915_dma.c | 4 ++++ drivers/gpu/drm/i915/i915_drv.c | 12 +++++++++++- drivers/gpu/drm/nouveau/nouveau_drv.c | 6 ++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_state.c | 4 ++++ drivers/gpu/drm/radeon/radeon.h | 1 - drivers/gpu/drm/radeon/radeon_device.c | 12 ++++++------ drivers/gpu/drm/radeon/radeon_kms.c | 4 ---- include/drm/drmP.h | 6 +++++- 10 files changed, 40 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index a39794bac04b..2ec7d48fc4a8 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -236,6 +236,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, return -EBUSY; /* No exclusive opens */ if (!drm_cpu_valid()) return -EINVAL; + if (dev->switch_power_state != DRM_SWITCH_POWER_ON) + return -EINVAL; DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ec1f650f6fab..0568dbdc10ef 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1151,12 +1151,16 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { printk(KERN_INFO "i915: switched on\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; /* i915 resume handler doesn't set to D0 */ pci_set_power_state(dev->pdev, PCI_D0); i915_resume(dev); + dev->switch_power_state = DRM_SWITCH_POWER_ON; } else { printk(KERN_ERR "i915: switched off\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; i915_suspend(dev, pmm); + dev->switch_power_state = DRM_SWITCH_POWER_OFF; } } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9eee6cf7901e..872493331988 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -271,6 +271,8 @@ static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + drm_kms_helper_poll_disable(dev); + pci_save_state(dev->pdev); /* If KMS is active, we do the leavevt stuff here */ @@ -307,7 +309,9 @@ int i915_suspend(struct drm_device *dev, pm_message_t state) if (state.event == PM_EVENT_PRETHAW) return 0; - drm_kms_helper_poll_disable(dev); + + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; error = i915_drm_freeze(dev); if (error) @@ -361,6 +365,9 @@ int i915_resume(struct drm_device *dev) { int ret; + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + if (pci_enable_device(dev->pdev)) return -EIO; @@ -569,6 +576,9 @@ static int i915_pm_suspend(struct device *dev) return -ENODEV; } + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + error = i915_drm_freeze(drm_dev); if (error) return error; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index bb170570938b..13bb672a16f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -171,6 +171,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) if (pm_state.event == PM_EVENT_PRETHAW) return 0; + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + NV_INFO(dev, "Disabling fbcon acceleration...\n"); nouveau_fbcon_save_disable_accel(dev); @@ -254,6 +257,9 @@ nouveau_pci_resume(struct pci_dev *pdev) struct drm_crtc *crtc; int ret, i; + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + nouveau_fbcon_save_disable_accel(dev); NV_INFO(dev, "We're back, enabling device...\n"); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e81575687354..e59f5bcab1ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -753,6 +753,8 @@ struct drm_nouveau_private { struct nouveau_fbdev *nfbdev; struct apertures_struct *apertures; + + bool powered_down; }; static inline struct drm_nouveau_private * diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 1b87eee22fa9..a54fc431fe98 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -596,12 +596,16 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev, pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; nouveau_pci_resume(pdev); drm_kms_helper_poll_enable(dev); + dev->switch_power_state = DRM_SWITCH_POWER_ON; } else { printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(dev); nouveau_pci_suspend(pdev, pmm); + dev->switch_power_state = DRM_SWITCH_POWER_OFF; } } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d2697f8f2da8..140eaceab279 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1167,7 +1167,6 @@ struct radeon_device { uint8_t audio_status_bits; uint8_t audio_category_code; - bool powered_down; struct notifier_block acpi_nb; /* only one userspace can use Hyperz features at a time */ struct drm_file *hyperz_filp; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 1a1017f0d9db..4ee0c53b28a7 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -642,20 +642,20 @@ void radeon_check_arguments(struct radeon_device *rdev) static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { struct drm_device *dev = pci_get_drvdata(pdev); - struct radeon_device *rdev = dev->dev_private; pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { printk(KERN_INFO "radeon: switched on\n"); /* don't suspend or resume card normally */ - rdev->powered_down = false; + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; radeon_resume_kms(dev); + dev->switch_power_state = DRM_SWITCH_POWER_ON; drm_kms_helper_poll_enable(dev); } else { printk(KERN_INFO "radeon: switched off\n"); drm_kms_helper_poll_disable(dev); + dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; radeon_suspend_kms(dev, pmm); - /* don't suspend or resume card normally */ - rdev->powered_down = true; + dev->switch_power_state = DRM_SWITCH_POWER_OFF; } } @@ -842,7 +842,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) } rdev = dev->dev_private; - if (rdev->powered_down) + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; /* turn off display hw */ @@ -900,7 +900,7 @@ int radeon_resume_kms(struct drm_device *dev) struct drm_connector *connector; struct radeon_device *rdev = dev->dev_private; - if (rdev->powered_down) + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; acquire_console_sem(); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 4bf423ca4c12..b2686334d46b 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -203,10 +203,6 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) */ int radeon_driver_firstopen_kms(struct drm_device *dev) { - struct radeon_device *rdev = dev->dev_private; - - if (rdev->powered_down) - return -EINVAL; return 0; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0f14f94ed8f4..a4694c610330 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1121,9 +1121,13 @@ struct drm_device { spinlock_t object_name_lock; struct idr object_name_idr; /*@} */ - + int switch_power_state; }; +#define DRM_SWITCH_POWER_ON 0 +#define DRM_SWITCH_POWER_OFF 1 +#define DRM_SWITCH_POWER_CHANGING 2 + static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) { -- cgit v1.2.3 From 66b37c6777c4686f121fe4a83176e535a7f4b1af Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 7 Dec 2010 14:24:25 +1000 Subject: vga_switcheroo: split switching into two stages. stage 1: turn card on, switch boot vga pointer. stage 2: switch fbs, switch mux and power off old card. Signed-off-by: Dave Airlie --- drivers/gpu/vga/vga_switcheroo.c | 45 ++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 2b8e1d25e8d0..d2d8543686d3 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -212,7 +212,8 @@ static int vga_switchoff(struct vga_switcheroo_client *client) return 0; } -static int vga_switchto(struct vga_switcheroo_client *new_client) +/* stage one happens before delay */ +static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) { int ret; int i; @@ -239,10 +240,28 @@ static int vga_switchto(struct vga_switcheroo_client *new_client) vga_switchon(new_client); /* swap shadow resource to denote boot VGA device has changed so X starts on new device */ - active->active = false; - active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW; new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; + return 0; +} + +/* post delay */ +static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) +{ + int ret; + int i; + struct vga_switcheroo_client *active = NULL; + + for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { + if (vgasr_priv.clients[i].active == true) { + active = &vgasr_priv.clients[i]; + break; + } + } + if (!active) + return 0; + + active->active = false; if (new_client->fb_info) { struct fb_event event; @@ -368,18 +387,22 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, if (can_switch == true) { pdev_name = pci_name(client->pdev); - ret = vga_switchto(client); + ret = vga_switchto_stage1(client); + if (ret) + printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret); + + ret = vga_switchto_stage2(client); if (ret) - printk(KERN_ERR "vga_switcheroo: switching failed %d\n", ret); + printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret); + } else { printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id); vgasr_priv.delayed_switch_active = true; vgasr_priv.delayed_client_id = client_id; - /* we should at least power up the card to - make the switch faster */ - if (client->pwr_state == VGA_SWITCHEROO_OFF) - vga_switchon(client); + ret = vga_switchto_stage1(client); + if (ret) + printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret); } out: @@ -461,9 +484,9 @@ int vga_switcheroo_process_delayed_switch(void) goto err; pdev_name = pci_name(client->pdev); - ret = vga_switchto(client); + ret = vga_switchto_stage2(client); if (ret) - printk(KERN_ERR "vga_switcheroo: delayed switching failed %d\n", ret); + printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret); vgasr_priv.delayed_switch_active = false; err = 0; -- cgit v1.2.3 From f8b6e31e4e46bf514c27fce38783ed5615cca01d Mon Sep 17 00:00:00 2001 From: David Dillow Date: Fri, 26 Nov 2010 13:02:21 -0500 Subject: IB/srp: allow task management without a previous request We can only have one task management comment outstanding, so move the completion and status to the target port. This allows us to handle resets of a LUN without a corresponding request having been sent. Meanwhile, we don't need to play games with host_scribble, just use it as the pointer it is. This fixes a crash when we issue a bus reset using sg_reset. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=13893 Reported-by: Bart Van Assche Reviewed-by: Bart Van Assche Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 90 +++++++++++++------------------------ drivers/infiniband/ulp/srp/ib_srp.h | 10 ++--- 2 files changed, 37 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 1e1e347a7715..29429a13fd90 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -542,6 +542,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) { srp_unmap_data(req->scmnd, target, req); + req->scmnd = NULL; list_move_tail(&req->list, &target->free_reqs); } @@ -925,15 +926,13 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) target->req_lim += delta; - req = &target->req_ring[rsp->tag & ~SRP_TAG_TSK_MGMT]; - if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { - if (be32_to_cpu(rsp->resp_data_len) < 4) - req->tsk_status = -1; - else - req->tsk_status = rsp->data[3]; - complete(&req->done); + target->tsk_mgmt_status = -1; + if (be32_to_cpu(rsp->resp_data_len) >= 4) + target->tsk_mgmt_status = rsp->data[3]; + complete(&target->tsk_mgmt_done); } else { + req = &target->req_ring[rsp->tag]; scmnd = req->scmnd; if (!scmnd) shost_printk(KERN_ERR, target->scsi_host, @@ -953,13 +952,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); - if (!req->tsk_mgmt) { - scmnd->host_scribble = (void *) -1L; - scmnd->scsi_done(scmnd); - - srp_remove_req(target, req); - } else - req->cmd_done = 1; + scmnd->host_scribble = NULL; + scmnd->scsi_done(scmnd); + srp_remove_req(target, req); } spin_unlock_irqrestore(target->scsi_host->host_lock, flags); @@ -1155,7 +1150,7 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, scmnd->scsi_done = done; scmnd->result = 0; - scmnd->host_scribble = (void *) (long) req->index; + scmnd->host_scribble = (void *) req; cmd = iu->buf; memset(cmd, 0, sizeof *cmd); @@ -1167,8 +1162,6 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, req->scmnd = scmnd; req->cmd = iu; - req->cmd_done = 0; - req->tsk_mgmt = NULL; len = srp_map_data(scmnd, target, req); if (len < 0) { @@ -1442,7 +1435,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) } static int srp_send_tsk_mgmt(struct srp_target_port *target, - struct srp_request *req, u8 func) + u64 req_tag, unsigned int lun, u8 func) { struct ib_device *dev = target->srp_host->srp_dev->dev; struct srp_iu *iu; @@ -1451,12 +1444,10 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) { - req->scmnd->result = DID_BAD_TARGET << 16; + target->state == SRP_TARGET_REMOVED) goto out; - } - init_completion(&req->done); + init_completion(&target->tsk_mgmt_done); iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); if (!iu) @@ -1468,21 +1459,19 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, memset(tsk_mgmt, 0, sizeof *tsk_mgmt); tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); - tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; + tsk_mgmt->lun = cpu_to_be64((u64) lun << 48); + tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT; tsk_mgmt->tsk_mgmt_func = func; - tsk_mgmt->task_tag = req->index; + tsk_mgmt->task_tag = req_tag; ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, DMA_TO_DEVICE); if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) goto out; - req->tsk_mgmt = iu; - spin_unlock_irq(target->scsi_host->host_lock); - if (!wait_for_completion_timeout(&req->done, + if (!wait_for_completion_timeout(&target->tsk_mgmt_done, msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) return -1; @@ -1493,43 +1482,29 @@ out: return -1; } -static int srp_find_req(struct srp_target_port *target, - struct scsi_cmnd *scmnd, - struct srp_request **req) -{ - if (scmnd->host_scribble == (void *) -1L) - return -1; - - *req = &target->req_ring[(long) scmnd->host_scribble]; - - return 0; -} - static int srp_abort(struct scsi_cmnd *scmnd) { struct srp_target_port *target = host_to_target(scmnd->device->host); - struct srp_request *req; + struct srp_request *req = (struct srp_request *) scmnd->host_scribble; int ret = SUCCESS; shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); - if (target->qp_in_error) - return FAILED; - if (srp_find_req(target, scmnd, &req)) + if (!req || target->qp_in_error) return FAILED; - if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) + if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, + SRP_TSK_ABORT_TASK)) return FAILED; spin_lock_irq(target->scsi_host->host_lock); - if (req->cmd_done) { - srp_remove_req(target, req); - scmnd->scsi_done(scmnd); - } else if (!req->tsk_status) { - srp_remove_req(target, req); - scmnd->result = DID_ABORT << 16; - } else - ret = FAILED; + if (req->scmnd) { + if (!target->tsk_mgmt_status) { + srp_remove_req(target, req); + scmnd->result = DID_ABORT << 16; + } else + ret = FAILED; + } spin_unlock_irq(target->scsi_host->host_lock); @@ -1545,17 +1520,16 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) if (target->qp_in_error) return FAILED; - if (srp_find_req(target, scmnd, &req)) - return FAILED; - if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) + if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun, + SRP_TSK_LUN_RESET)) return FAILED; - if (req->tsk_status) + if (target->tsk_mgmt_status) return FAILED; spin_lock_irq(target->scsi_host->host_lock); list_for_each_entry_safe(req, tmp, &target->req_queue, list) - if (req->scmnd->device == scmnd->device) + if (req->scmnd && req->scmnd->device == scmnd->device) srp_reset_req(target, req); spin_unlock_irq(target->scsi_host->host_lock); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index ed0dce9e479f..f8b689a644b7 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -68,7 +68,8 @@ enum { SRP_TSK_MGMT_SQ_SIZE = 1, SRP_CMD_SQ_SIZE = SRP_REQ_SQ_SIZE - SRP_TSK_MGMT_SQ_SIZE, - SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1), + SRP_TAG_NO_REQ = ~0U, + SRP_TAG_TSK_MGMT = 1U << 31, SRP_FMR_SIZE = 256, SRP_FMR_POOL_SIZE = 1024, @@ -113,12 +114,8 @@ struct srp_request { struct list_head list; struct scsi_cmnd *scmnd; struct srp_iu *cmd; - struct srp_iu *tsk_mgmt; struct ib_pool_fmr *fmr; - struct completion done; short index; - u8 cmd_done; - u8 tsk_status; }; struct srp_target_port { @@ -165,6 +162,9 @@ struct srp_target_port { int status; enum srp_target_state state; int qp_in_error; + + struct completion tsk_mgmt_done; + u8 tsk_mgmt_status; }; struct srp_iu { -- cgit v1.2.3 From 9709f0e05b827049733f439de82a4a1688b37b86 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 26 Nov 2010 13:13:06 -0500 Subject: IB/srp: consolidate state change code Signed-off-by: Bart Van Assche [ broken out and small cleanups by David Dillow ] Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 45 ++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 29429a13fd90..def9e6b38459 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -441,18 +441,28 @@ static void srp_disconnect_target(struct srp_target_port *target) wait_for_completion(&target->done); } +static bool srp_change_state(struct srp_target_port *target, + enum srp_target_state old, + enum srp_target_state new) +{ + bool changed = false; + + spin_lock_irq(target->scsi_host->host_lock); + if (target->state == old) { + target->state = new; + changed = true; + } + spin_unlock_irq(target->scsi_host->host_lock); + return changed; +} + static void srp_remove_work(struct work_struct *work) { struct srp_target_port *target = container_of(work, struct srp_target_port, work); - spin_lock_irq(target->scsi_host->host_lock); - if (target->state != SRP_TARGET_DEAD) { - spin_unlock_irq(target->scsi_host->host_lock); + if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED)) return; - } - target->state = SRP_TARGET_REMOVED; - spin_unlock_irq(target->scsi_host->host_lock); spin_lock(&target->srp_host->target_lock); list_del(&target->list); @@ -560,13 +570,8 @@ static int srp_reconnect_target(struct srp_target_port *target) struct ib_wc wc; int ret; - spin_lock_irq(target->scsi_host->host_lock); - if (target->state != SRP_TARGET_LIVE) { - spin_unlock_irq(target->scsi_host->host_lock); + if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) return -EAGAIN; - } - target->state = SRP_TARGET_CONNECTING; - spin_unlock_irq(target->scsi_host->host_lock); srp_disconnect_target(target); /* @@ -605,13 +610,8 @@ static int srp_reconnect_target(struct srp_target_port *target) if (ret) goto err; - spin_lock_irq(target->scsi_host->host_lock); - if (target->state == SRP_TARGET_CONNECTING) { - ret = 0; - target->state = SRP_TARGET_LIVE; - } else + if (!srp_change_state(target, SRP_TARGET_CONNECTING, SRP_TARGET_LIVE)) ret = -EAGAIN; - spin_unlock_irq(target->scsi_host->host_lock); return ret; @@ -621,9 +621,12 @@ err: /* * We couldn't reconnect, so kill our target port off. - * However, we have to defer the real removal because we might - * be in the context of the SCSI error handler now, which - * would deadlock if we call scsi_remove_host(). + * However, we have to defer the real removal because we + * are in the context of the SCSI error handler now, which + * will deadlock if we call scsi_remove_host(). + * + * Schedule our work inside the lock to avoid a race with + * the flush_scheduled_work() in srp_remove_one(). */ spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_CONNECTING) { -- cgit v1.2.3 From dcb4cb85f4b7caac9769bce464fef16306a4758c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 26 Nov 2010 13:22:48 -0500 Subject: IB/srp: allow lockless work posting Only one CPU at a time will own an RX IU, so using the address of the IU as the work request cookie allows us to avoid taking a lock. We can similarly prepare the TX path for lockless posting by moving the free TX IUs to a list. This also removes the requirement that the queue sizes be a power of 2. Signed-off-by: Bart Van Assche [ broken out, small cleanups, and modified to avoid needing an extra field in the IU by David Dillow] Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 65 +++++++++++++++---------------------- drivers/infiniband/ulp/srp/ib_srp.h | 7 ++-- 2 files changed, 28 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index def9e6b38459..aa78d2615c8d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -568,7 +568,7 @@ static int srp_reconnect_target(struct srp_target_port *target) struct ib_qp_attr qp_attr; struct srp_request *req, *tmp; struct ib_wc wc; - int ret; + int i, ret; if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) return -EAGAIN; @@ -601,9 +601,9 @@ static int srp_reconnect_target(struct srp_target_port *target) srp_reset_req(target, req); spin_unlock_irq(target->scsi_host->host_lock); - target->rx_head = 0; - target->tx_head = 0; - target->tx_tail = 0; + list_del_init(&target->free_tx); + for (i = 0; i < SRP_SQ_SIZE; ++i) + list_move(&target->tx_ring[i]->list, &target->free_tx); target->qp_in_error = 0; ret = srp_connect_target(target); @@ -817,7 +817,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, /* * Must be called with target->scsi_host->host_lock held to protect - * req_lim and tx_head. Lock cannot be dropped between call here and + * req_lim and free_tx. Lock cannot be dropped between call here and * call to __srp_post_send(). * * Note: @@ -837,7 +837,7 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, srp_send_completion(target->send_cq, target); - if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) + if (list_empty(&target->free_tx)) return NULL; /* Initiator responses to target requests do not consume credits */ @@ -846,14 +846,14 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, return NULL; } - iu = target->tx_ring[target->tx_head & SRP_SQ_MASK]; + iu = list_first_entry(&target->free_tx, struct srp_iu, list); iu->type = iu_type; return iu; } /* * Must be called with target->scsi_host->host_lock held to protect - * req_lim and tx_head. + * req_lim and free_tx. */ static int __srp_post_send(struct srp_target_port *target, struct srp_iu *iu, int len) @@ -867,7 +867,7 @@ static int __srp_post_send(struct srp_target_port *target, list.lkey = target->srp_host->srp_dev->mr->lkey; wr.next = NULL; - wr.wr_id = target->tx_head & SRP_SQ_MASK; + wr.wr_id = (uintptr_t) iu; wr.sg_list = &list; wr.num_sge = 1; wr.opcode = IB_WR_SEND; @@ -876,7 +876,7 @@ static int __srp_post_send(struct srp_target_port *target, ret = ib_post_send(target->qp, &wr, &bad_wr); if (!ret) { - ++target->tx_head; + list_del(&iu->list); if (iu->type != SRP_IU_RSP) --target->req_lim; } @@ -884,36 +884,21 @@ static int __srp_post_send(struct srp_target_port *target, return ret; } -static int srp_post_recv(struct srp_target_port *target) +static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) { - unsigned long flags; - struct srp_iu *iu; - struct ib_sge list; struct ib_recv_wr wr, *bad_wr; - unsigned int next; - int ret; - - spin_lock_irqsave(target->scsi_host->host_lock, flags); - - next = target->rx_head & SRP_RQ_MASK; - wr.wr_id = next; - iu = target->rx_ring[next]; + struct ib_sge list; list.addr = iu->dma; list.length = iu->size; list.lkey = target->srp_host->srp_dev->mr->lkey; wr.next = NULL; + wr.wr_id = (uintptr_t) iu; wr.sg_list = &list; wr.num_sge = 1; - ret = ib_post_recv(target->qp, &wr, &bad_wr); - if (!ret) - ++target->rx_head; - - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); - - return ret; + return ib_post_recv(target->qp, &wr, &bad_wr); } static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) @@ -1030,14 +1015,11 @@ static void srp_process_aer_req(struct srp_target_port *target, static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) { - struct ib_device *dev; - struct srp_iu *iu; + struct ib_device *dev = target->srp_host->srp_dev->dev; + struct srp_iu *iu = (struct srp_iu *) wc->wr_id; int res; u8 opcode; - iu = target->rx_ring[wc->wr_id]; - - dev = target->srp_host->srp_dev->dev; ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, DMA_FROM_DEVICE); @@ -1078,7 +1060,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, DMA_FROM_DEVICE); - res = srp_post_recv(target); + res = srp_post_recv(target, iu); if (res != 0) shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed with error code %d\n", res); @@ -1107,6 +1089,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) { struct srp_target_port *target = target_ptr; struct ib_wc wc; + struct srp_iu *iu; while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { @@ -1117,7 +1100,8 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) break; } - ++target->tx_tail; + iu = (struct srp_iu *) wc.wr_id; + list_add(&iu->list, &target->free_tx); } } @@ -1212,6 +1196,8 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target) GFP_KERNEL, DMA_TO_DEVICE); if (!target->tx_ring[i]) goto err; + + list_add(&target->tx_ring[i]->list, &target->free_tx); } return 0; @@ -1373,7 +1359,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) break; for (i = 0; i < SRP_RQ_SIZE; i++) { - target->status = srp_post_recv(target); + struct srp_iu *iu = target->rx_ring[i]; + target->status = srp_post_recv(target, iu); if (target->status) break; } @@ -1965,6 +1952,7 @@ static ssize_t srp_create_target(struct device *dev, target->scsi_host = target_host; target->srp_host = host; + INIT_LIST_HEAD(&target->free_tx); INIT_LIST_HEAD(&target->free_reqs); INIT_LIST_HEAD(&target->req_queue); for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { @@ -2235,8 +2223,7 @@ static int __init srp_init_module(void) { int ret; - BUILD_BUG_ON_NOT_POWER_OF_2(SRP_SQ_SIZE); - BUILD_BUG_ON_NOT_POWER_OF_2(SRP_RQ_SIZE); + BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); if (srp_sg_tablesize > 255) { printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n"); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index f8b689a644b7..41ecb46adf15 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -59,10 +59,8 @@ enum { SRP_RQ_SHIFT = 6, SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, - SRP_RQ_MASK = SRP_RQ_SIZE - 1, SRP_SQ_SIZE = SRP_RQ_SIZE, - SRP_SQ_MASK = SRP_SQ_SIZE - 1, SRP_RSP_SQ_SIZE = 1, SRP_REQ_SQ_SIZE = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE, SRP_TSK_MGMT_SQ_SIZE = 1, @@ -144,11 +142,9 @@ struct srp_target_port { int zero_req_lim; - unsigned rx_head; struct srp_iu *rx_ring[SRP_RQ_SIZE]; - unsigned tx_head; - unsigned tx_tail; + struct list_head free_tx; struct srp_iu *tx_ring[SRP_SQ_SIZE]; struct list_head free_reqs; @@ -168,6 +164,7 @@ struct srp_target_port { }; struct srp_iu { + struct list_head list; u64 dma; void *buf; size_t size; -- cgit v1.2.3 From 2de06cc1f18d638cc7ab1169f61a8599045c2d4f Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 9 Feb 2009 12:05:51 -0800 Subject: xen: separate out frontend xenbus Impact: refactor Make a distinct frontend xenbus, in preparation for adding a backend xenbus. Signed-off-by: Ian Campbell Signed-off-by: Jeremy Fitzhardinge [corresponds to 2fd433a4188f in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git with adjustments to reflect changes in the code which is moved] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/Kconfig | 1 + drivers/xen/Kconfig | 3 + drivers/xen/xenbus/Makefile | 2 + drivers/xen/xenbus/xenbus_probe.c | 361 ++++++----------------------- drivers/xen/xenbus/xenbus_probe.h | 30 +-- drivers/xen/xenbus/xenbus_probe_frontend.c | 275 ++++++++++++++++++++++ 6 files changed, 367 insertions(+), 305 deletions(-) create mode 100644 drivers/xen/xenbus/xenbus_probe_frontend.c (limited to 'drivers') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4b9359a6f6ca..83c32cb72582 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -464,6 +464,7 @@ config XEN_BLKDEV_FRONTEND tristate "Xen virtual block device support" depends on XEN default y + select XEN_XENBUS_FRONTEND help This driver implements the front-end of the Xen virtual block device driver. It communicates with a back-end driver diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 6e6180ccd726..10b6bef2e217 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -62,6 +62,9 @@ config XEN_SYS_HYPERVISOR virtual environment, /sys/hypervisor will still be present, but will have no xen contents. +config XEN_XENBUS_FRONTEND + tristate + config XEN_PLATFORM_PCI tristate "xen platform pci device driver" depends on XEN_PVHVM diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile index 5571f5b84223..33e8cf8149b3 100644 --- a/drivers/xen/xenbus/Makefile +++ b/drivers/xen/xenbus/Makefile @@ -5,3 +5,5 @@ xenbus-objs += xenbus_client.o xenbus-objs += xenbus_comms.o xenbus-objs += xenbus_xs.o xenbus-objs += xenbus_probe.o + +obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index deb9c4ba3a93..d46205868b88 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -56,7 +56,6 @@ #include #include -#include #include #include "xenbus_comms.h" @@ -73,15 +72,6 @@ static unsigned long xen_store_mfn; static BLOCKING_NOTIFIER_HEAD(xenstore_chain); -static void wait_for_devices(struct xenbus_driver *xendrv); - -static int xenbus_probe_frontend(const char *type, const char *name); - -static void xenbus_dev_shutdown(struct device *_dev); - -static int xenbus_dev_suspend(struct device *dev, pm_message_t state); -static int xenbus_dev_resume(struct device *dev); - /* If something in array of ids matches this device, return it. */ static const struct xenbus_device_id * match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) @@ -102,8 +92,10 @@ int xenbus_match(struct device *_dev, struct device_driver *_drv) return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; } +EXPORT_SYMBOL_GPL(xenbus_match); + -static int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env) +int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env) { struct xenbus_device *dev = to_xenbus_device(_dev); @@ -112,25 +104,7 @@ static int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env) return 0; } - -/* device// => - */ -static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) -{ - nodename = strchr(nodename, '/'); - if (!nodename || strlen(nodename + 1) >= XEN_BUS_ID_SIZE) { - printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); - return -EINVAL; - } - - strlcpy(bus_id, nodename + 1, XEN_BUS_ID_SIZE); - if (!strchr(bus_id, '/')) { - printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); - return -EINVAL; - } - *strchr(bus_id, '/') = '-'; - return 0; -} - +EXPORT_SYMBOL_GPL(xenbus_uevent); static void free_otherend_details(struct xenbus_device *dev) { @@ -149,7 +123,28 @@ static void free_otherend_watch(struct xenbus_device *dev) } -int read_otherend_details(struct xenbus_device *xendev, +static int talk_to_otherend(struct xenbus_device *dev) +{ + struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); + + free_otherend_watch(dev); + free_otherend_details(dev); + + return drv->read_otherend_details(dev); +} + + + +static int watch_otherend(struct xenbus_device *dev) +{ + struct xen_bus_type *bus = container_of(dev->dev.bus, struct xen_bus_type, bus); + + return xenbus_watch_pathfmt(dev, &dev->otherend_watch, bus->otherend_changed, + "%s/%s", dev->otherend, "state"); +} + + +int xenbus_read_otherend_details(struct xenbus_device *xendev, char *id_node, char *path_node) { int err = xenbus_gather(XBT_NIL, xendev->nodename, @@ -174,39 +169,11 @@ int read_otherend_details(struct xenbus_device *xendev, return 0; } +EXPORT_SYMBOL_GPL(xenbus_read_otherend_details); - -static int read_backend_details(struct xenbus_device *xendev) -{ - return read_otherend_details(xendev, "backend-id", "backend"); -} - -static struct device_attribute xenbus_dev_attrs[] = { - __ATTR_NULL -}; - -/* Bus type for frontend drivers. */ -static struct xen_bus_type xenbus_frontend = { - .root = "device", - .levels = 2, /* device/type/ */ - .get_bus_id = frontend_bus_id, - .probe = xenbus_probe_frontend, - .bus = { - .name = "xen", - .match = xenbus_match, - .uevent = xenbus_uevent, - .probe = xenbus_dev_probe, - .remove = xenbus_dev_remove, - .shutdown = xenbus_dev_shutdown, - .dev_attrs = xenbus_dev_attrs, - - .suspend = xenbus_dev_suspend, - .resume = xenbus_dev_resume, - }, -}; - -static void otherend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) +void xenbus_otherend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len, + int ignore_on_shutdown) { struct xenbus_device *dev = container_of(watch, struct xenbus_device, otherend_watch); @@ -234,11 +201,7 @@ static void otherend_changed(struct xenbus_watch *watch, * work that can fail e.g., when the rootfs is gone. */ if (system_state > SYSTEM_RUNNING) { - struct xen_bus_type *bus = bus; - bus = container_of(dev->dev.bus, struct xen_bus_type, bus); - /* If we're frontend, drive the state machine to Closed. */ - /* This should cause the backend to release our resources. */ - if ((bus == &xenbus_frontend) && (state == XenbusStateClosing)) + if (ignore_on_shutdown && (state == XenbusStateClosing)) xenbus_frontend_closed(dev); return; } @@ -246,25 +209,7 @@ static void otherend_changed(struct xenbus_watch *watch, if (drv->otherend_changed) drv->otherend_changed(dev, state); } - - -static int talk_to_otherend(struct xenbus_device *dev) -{ - struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); - - free_otherend_watch(dev); - free_otherend_details(dev); - - return drv->read_otherend_details(dev); -} - - -static int watch_otherend(struct xenbus_device *dev) -{ - return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed, - "%s/%s", dev->otherend, "state"); -} - +EXPORT_SYMBOL_GPL(xenbus_otherend_changed); int xenbus_dev_probe(struct device *_dev) { @@ -310,6 +255,7 @@ fail: xenbus_switch_state(dev, XenbusStateClosed); return -ENODEV; } +EXPORT_SYMBOL_GPL(xenbus_dev_probe); int xenbus_dev_remove(struct device *_dev) { @@ -327,8 +273,9 @@ int xenbus_dev_remove(struct device *_dev) xenbus_switch_state(dev, XenbusStateClosed); return 0; } +EXPORT_SYMBOL_GPL(xenbus_dev_remove); -static void xenbus_dev_shutdown(struct device *_dev) +void xenbus_dev_shutdown(struct device *_dev) { struct xenbus_device *dev = to_xenbus_device(_dev); unsigned long timeout = 5*HZ; @@ -349,6 +296,7 @@ static void xenbus_dev_shutdown(struct device *_dev) out: put_device(&dev->dev); } +EXPORT_SYMBOL_GPL(xenbus_dev_shutdown); int xenbus_register_driver_common(struct xenbus_driver *drv, struct xen_bus_type *bus, @@ -362,25 +310,7 @@ int xenbus_register_driver_common(struct xenbus_driver *drv, return driver_register(&drv->driver); } - -int __xenbus_register_frontend(struct xenbus_driver *drv, - struct module *owner, const char *mod_name) -{ - int ret; - - drv->read_otherend_details = read_backend_details; - - ret = xenbus_register_driver_common(drv, &xenbus_frontend, - owner, mod_name); - if (ret) - return ret; - - /* If this driver is loaded as a module wait for devices to attach. */ - wait_for_devices(drv); - - return 0; -} -EXPORT_SYMBOL_GPL(__xenbus_register_frontend); +EXPORT_SYMBOL_GPL(xenbus_register_driver_common); void xenbus_unregister_driver(struct xenbus_driver *drv) { @@ -551,24 +481,7 @@ fail: kfree(xendev); return err; } - -/* device// */ -static int xenbus_probe_frontend(const char *type, const char *name) -{ - char *nodename; - int err; - - nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", - xenbus_frontend.root, type, name); - if (!nodename) - return -ENOMEM; - - DPRINTK("%s", nodename); - - err = xenbus_probe_node(&xenbus_frontend, type, nodename); - kfree(nodename); - return err; -} +EXPORT_SYMBOL_GPL(xenbus_probe_node); static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) { @@ -577,15 +490,23 @@ static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) unsigned int dir_n = 0; int i; + printk(KERN_CRIT "%s type %s\n", __func__, type); + dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n); - if (IS_ERR(dir)) + if (IS_ERR(dir)) { + printk(KERN_CRIT "%s failed xenbus_directory\n", __func__); return PTR_ERR(dir); + } for (i = 0; i < dir_n; i++) { - err = bus->probe(type, dir[i]); - if (err) + printk(KERN_CRIT "%s %d/%d %s\n", __func__, i+1,dir_n, dir[i]); + err = bus->probe(bus, type, dir[i]); + if (err) { + printk(KERN_CRIT "%s failed\n", __func__); break; + } } + printk("%s done\n", __func__); kfree(dir); return err; } @@ -596,18 +517,27 @@ int xenbus_probe_devices(struct xen_bus_type *bus) char **dir; unsigned int i, dir_n; + printk(KERN_CRIT "%s %s\n", __func__, bus->root); + dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); - if (IS_ERR(dir)) + if (IS_ERR(dir)) { + printk(KERN_CRIT "%s failed xenbus_directory\n", __func__); return PTR_ERR(dir); + } for (i = 0; i < dir_n; i++) { + printk(KERN_CRIT "%s %d/%d %s\n", __func__, i+1,dir_n, dir[i]); err = xenbus_probe_device_type(bus, dir[i]); - if (err) + if (err) { + printk(KERN_CRIT "%s failed\n", __func__); break; + } } + printk("%s done\n", __func__); kfree(dir); return err; } +EXPORT_SYMBOL_GPL(xenbus_probe_devices); static unsigned int char_count(const char *str, char c) { @@ -670,32 +600,17 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) } EXPORT_SYMBOL_GPL(xenbus_dev_changed); -static void frontend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - DPRINTK(""); - - xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); -} - -/* We watch for devices appearing and vanishing. */ -static struct xenbus_watch fe_watch = { - .node = "device", - .callback = frontend_changed, -}; - -static int xenbus_dev_suspend(struct device *dev, pm_message_t state) +int xenbus_dev_suspend(struct device *dev, pm_message_t state) { int err = 0; struct xenbus_driver *drv; - struct xenbus_device *xdev; + struct xenbus_device *xdev = container_of(dev, struct xenbus_device, dev); - DPRINTK(""); + DPRINTK("%s", xdev->nodename); if (dev->driver == NULL) return 0; drv = to_xenbus_driver(dev->driver); - xdev = container_of(dev, struct xenbus_device, dev); if (drv->suspend) err = drv->suspend(xdev, state); if (err) @@ -703,21 +618,19 @@ static int xenbus_dev_suspend(struct device *dev, pm_message_t state) "xenbus: suspend %s failed: %i\n", dev_name(dev), err); return 0; } +EXPORT_SYMBOL_GPL(xenbus_dev_suspend); -static int xenbus_dev_resume(struct device *dev) +int xenbus_dev_resume(struct device *dev) { int err; struct xenbus_driver *drv; - struct xenbus_device *xdev; + struct xenbus_device *xdev = container_of(dev, struct xenbus_device, dev); - DPRINTK(""); + DPRINTK("%s", xdev->nodename); if (dev->driver == NULL) return 0; - drv = to_xenbus_driver(dev->driver); - xdev = container_of(dev, struct xenbus_device, dev); - err = talk_to_otherend(xdev); if (err) { printk(KERN_WARNING @@ -748,6 +661,7 @@ static int xenbus_dev_resume(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(xenbus_dev_resume); /* A flag to determine if xenstored is 'ready' (i.e. has started) */ int xenstored_ready = 0; @@ -776,11 +690,6 @@ void xenbus_probe(struct work_struct *unused) { xenstored_ready = 1; - /* Enumerate devices in xenstore and watch for changes. */ - xenbus_probe_devices(&xenbus_frontend); - register_xenbus_watch(&fe_watch); - xenbus_backend_probe_and_watch(); - /* Notify others that xenstore is up */ blocking_notifier_call_chain(&xenstore_chain, 0, NULL); } @@ -811,15 +720,6 @@ static int __init xenbus_init(void) if (!xen_domain()) goto out_error; - /* Register ourselves with the kernel bus subsystem */ - err = bus_register(&xenbus_frontend.bus); - if (err) - goto out_error; - - err = xenbus_backend_bus_register(); - if (err) - goto out_unreg_front; - /* * Domain0 doesn't have a store_evtchn or store_mfn yet. */ @@ -874,7 +774,7 @@ static int __init xenbus_init(void) if (err) { printk(KERN_WARNING "XENBUS: Error initializing xenstore comms: %i\n", err); - goto out_unreg_back; + goto out_error; } #ifdef CONFIG_XEN_COMPAT_XENFS @@ -885,135 +785,16 @@ static int __init xenbus_init(void) proc_mkdir("xen", NULL); #endif + printk(KERN_CRIT "%s ok\n", __func__); return 0; - out_unreg_back: - xenbus_backend_bus_unregister(); - - out_unreg_front: - bus_unregister(&xenbus_frontend.bus); - out_error: if (page != 0) free_page(page); + return err; } postcore_initcall(xenbus_init); MODULE_LICENSE("GPL"); - -static int is_device_connecting(struct device *dev, void *data) -{ - struct xenbus_device *xendev = to_xenbus_device(dev); - struct device_driver *drv = data; - struct xenbus_driver *xendrv; - - /* - * A device with no driver will never connect. We care only about - * devices which should currently be in the process of connecting. - */ - if (!dev->driver) - return 0; - - /* Is this search limited to a particular driver? */ - if (drv && (dev->driver != drv)) - return 0; - - xendrv = to_xenbus_driver(dev->driver); - return (xendev->state < XenbusStateConnected || - (xendev->state == XenbusStateConnected && - xendrv->is_ready && !xendrv->is_ready(xendev))); -} - -static int exists_connecting_device(struct device_driver *drv) -{ - return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, - is_device_connecting); -} - -static int print_device_status(struct device *dev, void *data) -{ - struct xenbus_device *xendev = to_xenbus_device(dev); - struct device_driver *drv = data; - - /* Is this operation limited to a particular driver? */ - if (drv && (dev->driver != drv)) - return 0; - - if (!dev->driver) { - /* Information only: is this too noisy? */ - printk(KERN_INFO "XENBUS: Device with no driver: %s\n", - xendev->nodename); - } else if (xendev->state < XenbusStateConnected) { - enum xenbus_state rstate = XenbusStateUnknown; - if (xendev->otherend) - rstate = xenbus_read_driver_state(xendev->otherend); - printk(KERN_WARNING "XENBUS: Timeout connecting " - "to device: %s (local state %d, remote state %d)\n", - xendev->nodename, xendev->state, rstate); - } - - return 0; -} - -/* We only wait for device setup after most initcalls have run. */ -static int ready_to_wait_for_devices; - -/* - * On a 5-minute timeout, wait for all devices currently configured. We need - * to do this to guarantee that the filesystems and / or network devices - * needed for boot are available, before we can allow the boot to proceed. - * - * This needs to be on a late_initcall, to happen after the frontend device - * drivers have been initialised, but before the root fs is mounted. - * - * A possible improvement here would be to have the tools add a per-device - * flag to the store entry, indicating whether it is needed at boot time. - * This would allow people who knew what they were doing to accelerate their - * boot slightly, but of course needs tools or manual intervention to set up - * those flags correctly. - */ -static void wait_for_devices(struct xenbus_driver *xendrv) -{ - unsigned long start = jiffies; - struct device_driver *drv = xendrv ? &xendrv->driver : NULL; - unsigned int seconds_waited = 0; - - if (!ready_to_wait_for_devices || !xen_domain()) - return; - - while (exists_connecting_device(drv)) { - if (time_after(jiffies, start + (seconds_waited+5)*HZ)) { - if (!seconds_waited) - printk(KERN_WARNING "XENBUS: Waiting for " - "devices to initialise: "); - seconds_waited += 5; - printk("%us...", 300 - seconds_waited); - if (seconds_waited == 300) - break; - } - - schedule_timeout_interruptible(HZ/10); - } - - if (seconds_waited) - printk("\n"); - - bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, - print_device_status); -} - -#ifndef MODULE -static int __init boot_wait_for_devices(void) -{ - if (xen_hvm_domain() && !xen_platform_pci_unplug) - return -ENODEV; - - ready_to_wait_for_devices = 1; - wait_for_devices(NULL); - return 0; -} - -late_initcall(boot_wait_for_devices); -#endif diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index 6c5e3185a6a2..be390cef329f 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -36,26 +36,13 @@ #define XEN_BUS_ID_SIZE 20 -#ifdef CONFIG_XEN_BACKEND -extern void xenbus_backend_suspend(int (*fn)(struct device *, void *)); -extern void xenbus_backend_resume(int (*fn)(struct device *, void *)); -extern void xenbus_backend_probe_and_watch(void); -extern int xenbus_backend_bus_register(void); -extern void xenbus_backend_bus_unregister(void); -#else -static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {} -static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {} -static inline void xenbus_backend_probe_and_watch(void) {} -static inline int xenbus_backend_bus_register(void) { return 0; } -static inline void xenbus_backend_bus_unregister(void) {} -#endif - struct xen_bus_type { char *root; unsigned int levels; int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename); - int (*probe)(const char *type, const char *dir); + int (*probe)(struct xen_bus_type *bus, const char *type, const char *dir); + void (*otherend_changed)(struct xenbus_watch *watch, const char **vec, unsigned int len); struct bus_type bus; }; @@ -73,4 +60,17 @@ extern int xenbus_probe_devices(struct xen_bus_type *bus); extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); +extern int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env); +extern void xenbus_dev_shutdown(struct device *_dev); + +extern int xenbus_dev_suspend(struct device *dev, pm_message_t state); +extern int xenbus_dev_resume(struct device *dev); + +extern void xenbus_otherend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len, + int ignore_on_shutdown); + +extern int xenbus_read_otherend_details(struct xenbus_device *xendev, + char *id_node, char *path_node); + #endif diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c new file mode 100644 index 000000000000..04c4f0123521 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -0,0 +1,275 @@ +#define DPRINTK(fmt, args...) \ + pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \ + __func__, __LINE__, ##args) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "xenbus_comms.h" +#include "xenbus_probe.h" + + +/* device// => - */ +static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) +{ + nodename = strchr(nodename, '/'); + if (!nodename || strlen(nodename + 1) >= XEN_BUS_ID_SIZE) { + printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); + return -EINVAL; + } + + strlcpy(bus_id, nodename + 1, XEN_BUS_ID_SIZE); + if (!strchr(bus_id, '/')) { + printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); + return -EINVAL; + } + *strchr(bus_id, '/') = '-'; + return 0; +} + +/* device// */ +static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type, const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, name); + if (!nodename) + return -ENOMEM; + + DPRINTK("%s", nodename); + + err = xenbus_probe_node(bus, type, nodename); + kfree(nodename); + return err; +} + +static void backend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + xenbus_otherend_changed(watch, vec, len, 1); +} + +static struct device_attribute xenbus_frontend_dev_attrs[] = { + __ATTR_NULL +}; + +static struct xen_bus_type xenbus_frontend = { + .root = "device", + .levels = 2, /* device/type/ */ + .get_bus_id = frontend_bus_id, + .probe = xenbus_probe_frontend, + .otherend_changed = backend_changed, + .bus = { + .name = "xen", + .match = xenbus_match, + .uevent = xenbus_uevent, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, + .dev_attrs= xenbus_frontend_dev_attrs, + + .suspend = xenbus_dev_suspend, + .resume = xenbus_dev_resume, + }, +}; + +static void frontend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + DPRINTK(""); + + xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); +} + + +/* We watch for devices appearing and vanishing. */ +static struct xenbus_watch fe_watch = { + .node = "device", + .callback = frontend_changed, +}; + +static int read_backend_details(struct xenbus_device *xendev) +{ + return xenbus_read_otherend_details(xendev, "backend-id", "backend"); +} + +static int is_device_connecting(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct device_driver *drv = data; + struct xenbus_driver *xendrv; + + /* + * A device with no driver will never connect. We care only about + * devices which should currently be in the process of connecting. + */ + if (!dev->driver) + return 0; + + /* Is this search limited to a particular driver? */ + if (drv && (dev->driver != drv)) + return 0; + + xendrv = to_xenbus_driver(dev->driver); + return (xendev->state < XenbusStateConnected || + (xendev->state == XenbusStateConnected && + xendrv->is_ready && !xendrv->is_ready(xendev))); +} + +static int exists_connecting_device(struct device_driver *drv) +{ + return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, + is_device_connecting); +} + +static int print_device_status(struct device *dev, void *data) +{ + struct xenbus_device *xendev = to_xenbus_device(dev); + struct device_driver *drv = data; + + /* Is this operation limited to a particular driver? */ + if (drv && (dev->driver != drv)) + return 0; + + if (!dev->driver) { + /* Information only: is this too noisy? */ + printk(KERN_INFO "XENBUS: Device with no driver: %s\n", + xendev->nodename); + } else if (xendev->state < XenbusStateConnected) { + enum xenbus_state rstate = XenbusStateUnknown; + if (xendev->otherend) + rstate = xenbus_read_driver_state(xendev->otherend); + printk(KERN_WARNING "XENBUS: Timeout connecting " + "to device: %s (local state %d, remote state %d)\n", + xendev->nodename, xendev->state, rstate); + } + + return 0; +} + +/* We only wait for device setup after most initcalls have run. */ +static int ready_to_wait_for_devices; + +/* + * On a 5-minute timeout, wait for all devices currently configured. We need + * to do this to guarantee that the filesystems and / or network devices + * needed for boot are available, before we can allow the boot to proceed. + * + * This needs to be on a late_initcall, to happen after the frontend device + * drivers have been initialised, but before the root fs is mounted. + * + * A possible improvement here would be to have the tools add a per-device + * flag to the store entry, indicating whether it is needed at boot time. + * This would allow people who knew what they were doing to accelerate their + * boot slightly, but of course needs tools or manual intervention to set up + * those flags correctly. + */ +static void wait_for_devices(struct xenbus_driver *xendrv) +{ + unsigned long start = jiffies; + struct device_driver *drv = xendrv ? &xendrv->driver : NULL; + unsigned int seconds_waited = 0; + + if (!ready_to_wait_for_devices || !xen_domain()) + return; + + while (exists_connecting_device(drv)) { + if (time_after(jiffies, start + (seconds_waited+5)*HZ)) { + if (!seconds_waited) + printk(KERN_WARNING "XENBUS: Waiting for " + "devices to initialise: "); + seconds_waited += 5; + printk("%us...", 300 - seconds_waited); + if (seconds_waited == 300) + break; + } + + schedule_timeout_interruptible(HZ/10); + } + + if (seconds_waited) + printk("\n"); + + bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, + print_device_status); +} + +int __xenbus_register_frontend(struct xenbus_driver *drv, + struct module *owner, const char *mod_name) +{ + int ret; + + drv->read_otherend_details = read_backend_details; + + ret = xenbus_register_driver_common(drv, &xenbus_frontend, + owner, mod_name); + if (ret) + return ret; + + /* If this driver is loaded as a module wait for devices to attach. */ + wait_for_devices(drv); + + return 0; +} +EXPORT_SYMBOL_GPL(__xenbus_register_frontend); + +static int __init xenbus_probe_frontend_init(void) +{ + int err; + + DPRINTK(""); + + /* Register ourselves with the kernel bus subsystem */ + err = bus_register(&xenbus_frontend.bus); + if (err) { + printk(KERN_CRIT "%s didn't register bus!\n", __func__); + return err; + } + printk(KERN_CRIT "%s bus registered ok\n", __func__); + + if (!xen_initial_domain()) { + /* Enumerate devices in xenstore and watch for changes. */ + xenbus_probe_devices(&xenbus_frontend); + printk(KERN_CRIT "%s devices probed ok\n", __func__); + register_xenbus_watch(&fe_watch); + printk(KERN_CRIT "%s watch add ok ok\n", __func__); + printk(KERN_CRIT "%s all done\n", __func__); + } + + return 0; +} + +module_init(xenbus_probe_frontend_init); + +#ifndef MODULE +static int __init boot_wait_for_devices(void) +{ + if (xen_hvm_domain() && !xen_platform_pci_unplug) + return -ENODEV; + + ready_to_wait_for_devices = 1; + wait_for_devices(NULL); + return 0; +} + +late_initcall(boot_wait_for_devices); +#endif -- cgit v1.2.3 From df660251eb534649f90f9dcfe1da1cef4ea48a3e Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 9 Feb 2009 12:05:51 -0800 Subject: xen: add backend driver support Impact: backend device support Add the basic machinery to support backend drivers. Signed-off-by: Ian Campbell Signed-off-by: Jeremy Fitzhardinge [corresponds to 79727b851bac in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 8 + drivers/xen/xenbus/Makefile | 3 + drivers/xen/xenbus/xenbus_comms.c | 1 + drivers/xen/xenbus/xenbus_probe.c | 13 +- drivers/xen/xenbus/xenbus_probe.h | 1 - drivers/xen/xenbus/xenbus_probe_backend.c | 300 +++++++++++++++++++++++++++++ drivers/xen/xenbus/xenbus_probe_frontend.c | 39 +++- include/xen/xenbus.h | 2 +- 8 files changed, 345 insertions(+), 22 deletions(-) create mode 100644 drivers/xen/xenbus/xenbus_probe_backend.c (limited to 'drivers') diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 10b6bef2e217..84bf17bbb1cd 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -29,6 +29,14 @@ config XEN_DEV_EVTCHN firing. If in doubt, say yes. +config XEN_BACKEND + tristate "Backend driver support" + depends on XEN_DOM0 + default y + help + Support for backend device drivers that provide I/O services + to other virtual machines. + config XENFS tristate "Xen filesystem" default y diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile index 33e8cf8149b3..8dca685358b4 100644 --- a/drivers/xen/xenbus/Makefile +++ b/drivers/xen/xenbus/Makefile @@ -6,4 +6,7 @@ xenbus-objs += xenbus_comms.o xenbus-objs += xenbus_xs.o xenbus-objs += xenbus_probe.o +xenbus-be-objs-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o +xenbus-objs += $(xenbus-be-objs-y) + obj-$(CONFIG_XEN_XENBUS_FRONTEND) += xenbus_probe_frontend.o diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c index 090c61ee8fd0..700dc7714838 100644 --- a/drivers/xen/xenbus/xenbus_comms.c +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -49,6 +49,7 @@ static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); static irqreturn_t wake_waiting(int irq, void *unused) { if (unlikely(xenstored_ready == 0)) { + printk(KERN_CRIT "xenbus_probe wake_waiting\n"); xenstored_ready = 1; schedule_work(&probe_work); } diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index d46205868b88..b09eb17ba007 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -95,17 +95,6 @@ int xenbus_match(struct device *_dev, struct device_driver *_drv) EXPORT_SYMBOL_GPL(xenbus_match); -int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env) -{ - struct xenbus_device *dev = to_xenbus_device(_dev); - - if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype)) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(xenbus_uevent); - static void free_otherend_details(struct xenbus_device *dev) { kfree(dev->otherend); @@ -690,6 +679,8 @@ void xenbus_probe(struct work_struct *unused) { xenstored_ready = 1; + printk(KERN_CRIT "xenbus_probe wake_waiting\n"); + /* Notify others that xenstore is up */ blocking_notifier_call_chain(&xenstore_chain, 0, NULL); } diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index be390cef329f..0e5fc4c63eb2 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -60,7 +60,6 @@ extern int xenbus_probe_devices(struct xen_bus_type *bus); extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); -extern int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env); extern void xenbus_dev_shutdown(struct device *_dev); extern int xenbus_dev_suspend(struct device *dev, pm_message_t state); diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c new file mode 100644 index 000000000000..7459ccee3c8b --- /dev/null +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -0,0 +1,300 @@ +/****************************************************************************** + * Talks to Xen Store to figure out what devices we have (backend half). + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * Copyright (C) 2005, 2006 XenSource Ltd + * Copyright (C) 2007 Solarflare Communications, Inc. + * + * 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; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#define DPRINTK(fmt, args...) \ + pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \ + __func__, __LINE__, ##args) + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "xenbus_comms.h" +#include "xenbus_probe.h" + +/* backend/// => -- */ +static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) +{ + int domid, err; + const char *devid, *type, *frontend; + unsigned int typelen; + + type = strchr(nodename, '/'); + if (!type) + return -EINVAL; + type++; + typelen = strcspn(type, "/"); + if (!typelen || type[typelen] != '/') + return -EINVAL; + + devid = strrchr(nodename, '/') + 1; + + err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid, + "frontend", NULL, &frontend, + NULL); + if (err) + return err; + if (strlen(frontend) == 0) + err = -ERANGE; + if (!err && !xenbus_exists(XBT_NIL, frontend, "")) + err = -ENOENT; + kfree(frontend); + + if (err) + return err; + + if (snprintf(bus_id, XEN_BUS_ID_SIZE, + "%.*s-%i-%s", typelen, type, domid, devid) >= XEN_BUS_ID_SIZE) + return -ENOSPC; + return 0; +} + +static int xenbus_uevent_backend(struct device *dev, + struct kobj_uevent_env *env) +{ + struct xenbus_device *xdev; + struct xenbus_driver *drv; + struct xen_bus_type *bus; + + DPRINTK(""); + + if (dev == NULL) + return -ENODEV; + + xdev = to_xenbus_device(dev); + bus = container_of(xdev->dev.bus, struct xen_bus_type, bus); + if (xdev == NULL) + return -ENODEV; + + /* stuff we want to pass to /sbin/hotplug */ + if (add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype)) + return -ENOMEM; + + if (add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename)) + return -ENOMEM; + + if (add_uevent_var(env, "XENBUS_BASE_PATH=%s", bus->root)) + return -ENOMEM; + + if (dev->driver) { + drv = to_xenbus_driver(dev->driver); + if (drv && drv->uevent) + return drv->uevent(xdev, env); + } + + return 0; +} + +/* backend/// */ +static int xenbus_probe_backend_unit(struct xen_bus_type *bus, + const char *dir, + const char *type, + const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name); + if (!nodename) + return -ENOMEM; + + DPRINTK("%s\n", nodename); + + err = xenbus_probe_node(bus, type, nodename); + kfree(nodename); + return err; +} + +/* backend// */ +static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type, const char *domid) +{ + char *nodename; + int err = 0; + char **dir; + unsigned int i, dir_n = 0; + + DPRINTK(""); + + nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, domid); + if (!nodename) + return -ENOMEM; + + dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n); + if (IS_ERR(dir)) { + kfree(nodename); + return PTR_ERR(dir); + } + + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_backend_unit(bus, nodename, type, dir[i]); + if (err) + break; + } + kfree(dir); + kfree(nodename); + return err; +} + +static void frontend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + xenbus_otherend_changed(watch, vec, len, 0); +} + +static struct device_attribute xenbus_backend_dev_attrs[] = { + __ATTR_NULL +}; + +static struct xen_bus_type xenbus_backend = { + .root = "backend", + .levels = 3, /* backend/type// */ + .get_bus_id = backend_bus_id, + .probe = xenbus_probe_backend, + .otherend_changed = frontend_changed, + .bus = { + .name = "xen-backend", + .match = xenbus_match, + .uevent = xenbus_uevent_backend, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, + .dev_attrs = xenbus_backend_dev_attrs, + }, +}; + +static void backend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + DPRINTK(""); + + xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend); +} + +static struct xenbus_watch be_watch = { + .node = "backend", + .callback = backend_changed, +}; + +static int read_frontend_details(struct xenbus_device *xendev) +{ + return xenbus_read_otherend_details(xendev, "frontend-id", "frontend"); +} + +//void xenbus_backend_suspend(int (*fn)(struct device *, void *)) +//{ +// DPRINTK(""); +// bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); +//} + +//void xenbus_backend_resume(int (*fn)(struct device *, void *)) +//{ +// DPRINTK(""); +// bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); +//} + +//int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *)) +//{ +// return bus_for_each_dev(&xenbus_backend.bus, NULL, arg, fn); +//} +//EXPORT_SYMBOL_GPL(xenbus_for_each_backend); + +int xenbus_dev_is_online(struct xenbus_device *dev) +{ + int rc, val; + + rc = xenbus_scanf(XBT_NIL, dev->nodename, "online", "%d", &val); + if (rc != 1) + val = 0; /* no online node present */ + + return val; +} +EXPORT_SYMBOL_GPL(xenbus_dev_is_online); + +int __xenbus_register_backend(struct xenbus_driver *drv, + struct module *owner, const char *mod_name) +{ + drv->read_otherend_details = read_frontend_details; + + return xenbus_register_driver_common(drv, &xenbus_backend, + owner, mod_name); +} +EXPORT_SYMBOL_GPL(__xenbus_register_backend); + +static int backend_probe_and_watch(struct notifier_block *notifier, + unsigned long event, + void *data) +{ + /* Enumerate devices in xenstore and watch for changes. */ + xenbus_probe_devices(&xenbus_backend); + printk(KERN_CRIT "%s devices probed ok\n", __func__); + register_xenbus_watch(&be_watch); + printk(KERN_CRIT "%s watch add ok ok\n", __func__); + printk(KERN_CRIT "%s all done\n", __func__); + return NOTIFY_DONE; +} + +static int __init xenbus_probe_backend_init(void) +{ + static struct notifier_block xenstore_notifier = { + .notifier_call = backend_probe_and_watch + }; + int err; + + DPRINTK(""); + + /* Register ourselves with the kernel bus subsystem */ + err = bus_register(&xenbus_backend.bus); + if (err) { + printk(KERN_CRIT "%s didn't register bus!\n", __func__); + return err; + } + printk(KERN_CRIT "%s bus registered ok\n", __func__); + + register_xenstore_notifier(&xenstore_notifier); + + return 0; +} + +module_init(xenbus_probe_backend_init); diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 04c4f0123521..dd31d5a43b40 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -62,6 +62,17 @@ static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type, con return err; } +static int xenbus_uevent_frontend(struct device *_dev, struct kobj_uevent_env *env) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + + if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype)) + return -ENOMEM; + + return 0; +} + + static void backend_changed(struct xenbus_watch *watch, const char **vec, unsigned int len) { @@ -81,7 +92,7 @@ static struct xen_bus_type xenbus_frontend = { .bus = { .name = "xen", .match = xenbus_match, - .uevent = xenbus_uevent, + .uevent = xenbus_uevent_frontend, .probe = xenbus_dev_probe, .remove = xenbus_dev_remove, .shutdown = xenbus_dev_shutdown, @@ -232,8 +243,25 @@ int __xenbus_register_frontend(struct xenbus_driver *drv, } EXPORT_SYMBOL_GPL(__xenbus_register_frontend); +static int frontend_probe_and_watch(struct notifier_block *notifier, + unsigned long event, + void *data) +{ + /* Enumerate devices in xenstore and watch for changes. */ + xenbus_probe_devices(&xenbus_frontend); + printk(KERN_CRIT "%s devices probed ok\n", __func__); + register_xenbus_watch(&fe_watch); + printk(KERN_CRIT "%s watch add ok ok\n", __func__); + printk(KERN_CRIT "%s all done\n", __func__); + return NOTIFY_DONE; +} + + static int __init xenbus_probe_frontend_init(void) { + static struct notifier_block xenstore_notifier = { + .notifier_call = frontend_probe_and_watch + }; int err; DPRINTK(""); @@ -246,14 +274,7 @@ static int __init xenbus_probe_frontend_init(void) } printk(KERN_CRIT "%s bus registered ok\n", __func__); - if (!xen_initial_domain()) { - /* Enumerate devices in xenstore and watch for changes. */ - xenbus_probe_devices(&xenbus_frontend); - printk(KERN_CRIT "%s devices probed ok\n", __func__); - register_xenbus_watch(&fe_watch); - printk(KERN_CRIT "%s watch add ok ok\n", __func__); - printk(KERN_CRIT "%s all done\n", __func__); - } + register_xenstore_notifier(&xenstore_notifier); return 0; } diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h index 43e2d7d33976..7a1d15ff19b7 100644 --- a/include/xen/xenbus.h +++ b/include/xen/xenbus.h @@ -94,7 +94,7 @@ struct xenbus_driver { int (*remove)(struct xenbus_device *dev); int (*suspend)(struct xenbus_device *dev, pm_message_t state); int (*resume)(struct xenbus_device *dev); - int (*uevent)(struct xenbus_device *, char **, int, char *, int); + int (*uevent)(struct xenbus_device *, struct kobj_uevent_env *); struct device_driver driver; int (*read_otherend_details)(struct xenbus_device *dev); int (*is_ready)(struct xenbus_device *dev); -- cgit v1.2.3 From 74c2ee98385fe2653d6a817f6f74c18eec4c2424 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 9 Feb 2009 16:37:23 -0800 Subject: xen: remove xen/evtchn.h Impact: cleanup It's a usermode header for users of /dev/xen/evtchn. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to b60e48cec12f in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe_backend.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 7459ccee3c8b..3bd38123e69a 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include "xenbus_comms.h" -- cgit v1.2.3 From 806f5463d2598ea23a7a688c47c2774846fe7f2f Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 4 Mar 2009 22:31:45 -0800 Subject: xenbus/frontend: register bus earlier Impact: bugfix Make sure the frontend bus is registered early, before any drivers want to attach. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 1d5df318f87f in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe_frontend.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index dd31d5a43b40..ccd201f47927 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -278,8 +278,7 @@ static int __init xenbus_probe_frontend_init(void) return 0; } - -module_init(xenbus_probe_frontend_init); +subsys_initcall(xenbus_probe_frontend_init); #ifndef MODULE static int __init boot_wait_for_devices(void) -- cgit v1.2.3 From c3676e8462009d84dce89a454956460de3bfdca7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 4 Mar 2009 22:32:16 -0800 Subject: xen/xenbus: make sure backend bus is registered earlier Impact: bugfix Need to register it before any drivers want to attach. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to a7a9c3a942c6 in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe_backend.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 3bd38123e69a..a3cc5351fe29 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -295,5 +295,4 @@ static int __init xenbus_probe_backend_init(void) return 0; } - -module_init(xenbus_probe_backend_init); +subsys_initcall(xenbus_probe_backend_init); -- cgit v1.2.3 From 1b31a143450ea9b5e6168f3b21a02c4a6a63ad01 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 27 Mar 2009 16:29:44 -0700 Subject: xen/xenbus: make frontend bus GPL Make sure frontend xenbus has a GPL module license, so it can access all the xenbus symbols exported GPL only. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 525cbc8adcb5 in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe_frontend.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index ccd201f47927..3a4236524768 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -293,3 +293,5 @@ static int __init boot_wait_for_devices(void) late_initcall(boot_wait_for_devices); #endif + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7432e4bd0bcec9f18d9c94de8925b8a59d3edf94 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 29 Oct 2009 14:19:42 -0700 Subject: xen/xenbus: clean up error handling Don't report errors when booting on non-Xen, because its just confusing. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 8aa08376d6aa in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index b09eb17ba007..96bd1ef61ebe 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -242,7 +242,7 @@ int xenbus_dev_probe(struct device *_dev) fail: xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename); xenbus_switch_state(dev, XenbusStateClosed); - return -ENODEV; + return err; } EXPORT_SYMBOL_GPL(xenbus_dev_probe); @@ -709,7 +709,7 @@ static int __init xenbus_init(void) err = -ENODEV; if (!xen_domain()) - goto out_error; + return err; /* * Domain0 doesn't have a store_evtchn or store_mfn yet. -- cgit v1.2.3 From a16448e071ca80e599ea4f780242f40a0a213b07 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 29 Mar 2010 14:37:44 -0700 Subject: xen/xenbus: cleanup debug noise in xenbus_comms.c Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 6796c12281dc in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_comms.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c index 700dc7714838..090c61ee8fd0 100644 --- a/drivers/xen/xenbus/xenbus_comms.c +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -49,7 +49,6 @@ static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); static irqreturn_t wake_waiting(int irq, void *unused) { if (unlikely(xenstored_ready == 0)) { - printk(KERN_CRIT "xenbus_probe wake_waiting\n"); xenstored_ready = 1; schedule_work(&probe_work); } -- cgit v1.2.3 From a39bda27b35266beae945f48e0b6ab58d06a17d5 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 29 Mar 2010 14:38:12 -0700 Subject: xen/xenbus: clean up noise in xenbus_probe.c Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 01aded30aaef in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 96bd1ef61ebe..811923451218 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -479,23 +479,16 @@ static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) unsigned int dir_n = 0; int i; - printk(KERN_CRIT "%s type %s\n", __func__, type); - dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n); - if (IS_ERR(dir)) { - printk(KERN_CRIT "%s failed xenbus_directory\n", __func__); + if (IS_ERR(dir)) return PTR_ERR(dir); - } for (i = 0; i < dir_n; i++) { - printk(KERN_CRIT "%s %d/%d %s\n", __func__, i+1,dir_n, dir[i]); err = bus->probe(bus, type, dir[i]); - if (err) { - printk(KERN_CRIT "%s failed\n", __func__); + if (err) break; - } } - printk("%s done\n", __func__); + kfree(dir); return err; } @@ -506,23 +499,16 @@ int xenbus_probe_devices(struct xen_bus_type *bus) char **dir; unsigned int i, dir_n; - printk(KERN_CRIT "%s %s\n", __func__, bus->root); - dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); - if (IS_ERR(dir)) { - printk(KERN_CRIT "%s failed xenbus_directory\n", __func__); + if (IS_ERR(dir)) return PTR_ERR(dir); - } for (i = 0; i < dir_n; i++) { - printk(KERN_CRIT "%s %d/%d %s\n", __func__, i+1,dir_n, dir[i]); err = xenbus_probe_device_type(bus, dir[i]); - if (err) { - printk(KERN_CRIT "%s failed\n", __func__); + if (err) break; - } } - printk("%s done\n", __func__); + kfree(dir); return err; } @@ -679,8 +665,6 @@ void xenbus_probe(struct work_struct *unused) { xenstored_ready = 1; - printk(KERN_CRIT "xenbus_probe wake_waiting\n"); - /* Notify others that xenstore is up */ blocking_notifier_call_chain(&xenstore_chain, 0, NULL); } @@ -776,7 +760,6 @@ static int __init xenbus_init(void) proc_mkdir("xen", NULL); #endif - printk(KERN_CRIT "%s ok\n", __func__); return 0; out_error: -- cgit v1.2.3 From b5d33d088f45bb62fdaaf1755da05aa5524a3a8f Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 29 Mar 2010 14:38:35 -0700 Subject: xen/xenbus: clean up noise in xenbus_probe_backend.c Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 98b833aaf81e in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe_backend.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index a3cc5351fe29..9b9dd36bb1c4 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -267,10 +267,8 @@ static int backend_probe_and_watch(struct notifier_block *notifier, { /* Enumerate devices in xenstore and watch for changes. */ xenbus_probe_devices(&xenbus_backend); - printk(KERN_CRIT "%s devices probed ok\n", __func__); register_xenbus_watch(&be_watch); - printk(KERN_CRIT "%s watch add ok ok\n", __func__); - printk(KERN_CRIT "%s all done\n", __func__); + return NOTIFY_DONE; } @@ -285,11 +283,8 @@ static int __init xenbus_probe_backend_init(void) /* Register ourselves with the kernel bus subsystem */ err = bus_register(&xenbus_backend.bus); - if (err) { - printk(KERN_CRIT "%s didn't register bus!\n", __func__); + if (err) return err; - } - printk(KERN_CRIT "%s bus registered ok\n", __func__); register_xenstore_notifier(&xenstore_notifier); -- cgit v1.2.3 From 0ff4fdf065101504cd84ac36924fcdad6641a4f7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 29 Mar 2010 14:38:54 -0700 Subject: xen/xenbus: clean up noise in xenbus_probe_frontend.c Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to 616ff7a06a3f in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe_frontend.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 3a4236524768..60c311ab3190 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -249,10 +249,8 @@ static int frontend_probe_and_watch(struct notifier_block *notifier, { /* Enumerate devices in xenstore and watch for changes. */ xenbus_probe_devices(&xenbus_frontend); - printk(KERN_CRIT "%s devices probed ok\n", __func__); register_xenbus_watch(&fe_watch); - printk(KERN_CRIT "%s watch add ok ok\n", __func__); - printk(KERN_CRIT "%s all done\n", __func__); + return NOTIFY_DONE; } @@ -268,11 +266,8 @@ static int __init xenbus_probe_frontend_init(void) /* Register ourselves with the kernel bus subsystem */ err = bus_register(&xenbus_frontend.bus); - if (err) { - printk(KERN_CRIT "%s didn't register bus!\n", __func__); + if (err) return err; - } - printk(KERN_CRIT "%s bus registered ok\n", __func__); register_xenstore_notifier(&xenstore_notifier); -- cgit v1.2.3 From 7003087ce0fcdaf57a331b4ad627195a7f97245e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 27 Mar 2009 16:28:34 -0700 Subject: xen/netfront: select XEN_XENBUS_FRONTEND Make sure the Xen frontend xenbus is enabled. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ian Campbell [corresponds to c40912891c3b in git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/net/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4f1755bddf6b..cbf06359aa62 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2960,6 +2960,7 @@ config TILE_NET config XEN_NETDEV_FRONTEND tristate "Xen network device frontend driver" depends on XEN + select XEN_XENBUS_FRONTEND default y help The network device frontend driver allows the kernel to -- cgit v1.2.3 From 6bac7f9f9e8e549c18ec4b77c499a45a1fae61b9 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 10 Dec 2010 14:39:15 +0000 Subject: xen/xenbus: fixup checkpatch issues in xenbus_probe* Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 2 +- drivers/xen/xenbus/xenbus_probe.c | 12 ++++++--- drivers/xen/xenbus/xenbus_probe.h | 6 +++-- drivers/xen/xenbus/xenbus_probe_backend.c | 41 +++++++++--------------------- drivers/xen/xenbus/xenbus_probe_frontend.c | 28 ++++++++++---------- 5 files changed, 40 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 84bf17bbb1cd..554ed573c028 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -72,7 +72,7 @@ config XEN_SYS_HYPERVISOR config XEN_XENBUS_FRONTEND tristate - + config XEN_PLATFORM_PCI tristate "xen platform pci device driver" depends on XEN_PVHVM diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 811923451218..baa65e7fbbc7 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -126,9 +126,11 @@ static int talk_to_otherend(struct xenbus_device *dev) static int watch_otherend(struct xenbus_device *dev) { - struct xen_bus_type *bus = container_of(dev->dev.bus, struct xen_bus_type, bus); + struct xen_bus_type *bus = + container_of(dev->dev.bus, struct xen_bus_type, bus); - return xenbus_watch_pathfmt(dev, &dev->otherend_watch, bus->otherend_changed, + return xenbus_watch_pathfmt(dev, &dev->otherend_watch, + bus->otherend_changed, "%s/%s", dev->otherend, "state"); } @@ -579,7 +581,8 @@ int xenbus_dev_suspend(struct device *dev, pm_message_t state) { int err = 0; struct xenbus_driver *drv; - struct xenbus_device *xdev = container_of(dev, struct xenbus_device, dev); + struct xenbus_device *xdev + = container_of(dev, struct xenbus_device, dev); DPRINTK("%s", xdev->nodename); @@ -599,7 +602,8 @@ int xenbus_dev_resume(struct device *dev) { int err; struct xenbus_driver *drv; - struct xenbus_device *xdev = container_of(dev, struct xenbus_device, dev); + struct xenbus_device *xdev + = container_of(dev, struct xenbus_device, dev); DPRINTK("%s", xdev->nodename); diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index 0e5fc4c63eb2..24665812316a 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -41,8 +41,10 @@ struct xen_bus_type char *root; unsigned int levels; int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename); - int (*probe)(struct xen_bus_type *bus, const char *type, const char *dir); - void (*otherend_changed)(struct xenbus_watch *watch, const char **vec, unsigned int len); + int (*probe)(struct xen_bus_type *bus, const char *type, + const char *dir); + void (*otherend_changed)(struct xenbus_watch *watch, const char **vec, + unsigned int len); struct bus_type bus; }; diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 9b9dd36bb1c4..6cf467bf63ec 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -84,8 +84,8 @@ static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) if (err) return err; - if (snprintf(bus_id, XEN_BUS_ID_SIZE, - "%.*s-%i-%s", typelen, type, domid, devid) >= XEN_BUS_ID_SIZE) + if (snprintf(bus_id, XEN_BUS_ID_SIZE, "%.*s-%i-%s", + typelen, type, domid, devid) >= XEN_BUS_ID_SIZE) return -ENOSPC; return 0; } @@ -147,7 +147,8 @@ static int xenbus_probe_backend_unit(struct xen_bus_type *bus, } /* backend// */ -static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type, const char *domid) +static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type, + const char *domid) { char *nodename; int err = 0; @@ -188,18 +189,18 @@ static struct device_attribute xenbus_backend_dev_attrs[] = { static struct xen_bus_type xenbus_backend = { .root = "backend", - .levels = 3, /* backend/type// */ + .levels = 3, /* backend/type// */ .get_bus_id = backend_bus_id, .probe = xenbus_probe_backend, .otherend_changed = frontend_changed, .bus = { - .name = "xen-backend", - .match = xenbus_match, - .uevent = xenbus_uevent_backend, - .probe = xenbus_dev_probe, - .remove = xenbus_dev_remove, - .shutdown = xenbus_dev_shutdown, - .dev_attrs = xenbus_backend_dev_attrs, + .name = "xen-backend", + .match = xenbus_match, + .uevent = xenbus_uevent_backend, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, + .dev_attrs = xenbus_backend_dev_attrs, }, }; @@ -221,24 +222,6 @@ static int read_frontend_details(struct xenbus_device *xendev) return xenbus_read_otherend_details(xendev, "frontend-id", "frontend"); } -//void xenbus_backend_suspend(int (*fn)(struct device *, void *)) -//{ -// DPRINTK(""); -// bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); -//} - -//void xenbus_backend_resume(int (*fn)(struct device *, void *)) -//{ -// DPRINTK(""); -// bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); -//} - -//int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *)) -//{ -// return bus_for_each_dev(&xenbus_backend.bus, NULL, arg, fn); -//} -//EXPORT_SYMBOL_GPL(xenbus_for_each_backend); - int xenbus_dev_is_online(struct xenbus_device *dev) { int rc, val; diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 60c311ab3190..5bcc2d6cf129 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -46,7 +46,8 @@ static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) } /* device// */ -static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type, const char *name) +static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type, + const char *name) { char *nodename; int err; @@ -62,7 +63,8 @@ static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type, con return err; } -static int xenbus_uevent_frontend(struct device *_dev, struct kobj_uevent_env *env) +static int xenbus_uevent_frontend(struct device *_dev, + struct kobj_uevent_env *env) { struct xenbus_device *dev = to_xenbus_device(_dev); @@ -85,21 +87,21 @@ static struct device_attribute xenbus_frontend_dev_attrs[] = { static struct xen_bus_type xenbus_frontend = { .root = "device", - .levels = 2, /* device/type/ */ + .levels = 2, /* device/type/ */ .get_bus_id = frontend_bus_id, .probe = xenbus_probe_frontend, .otherend_changed = backend_changed, .bus = { - .name = "xen", - .match = xenbus_match, - .uevent = xenbus_uevent_frontend, - .probe = xenbus_dev_probe, - .remove = xenbus_dev_remove, - .shutdown = xenbus_dev_shutdown, - .dev_attrs= xenbus_frontend_dev_attrs, - - .suspend = xenbus_dev_suspend, - .resume = xenbus_dev_resume, + .name = "xen", + .match = xenbus_match, + .uevent = xenbus_uevent_frontend, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, + .dev_attrs = xenbus_frontend_dev_attrs, + + .suspend = xenbus_dev_suspend, + .resume = xenbus_dev_resume, }, }; -- cgit v1.2.3 From fce263c141faca8db85acb0524bdfdfae3ec0725 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 10 Dec 2010 22:33:15 -0500 Subject: xen/pci: Make xen-pcifront be dependent on XEN_XENBUS_FRONTEND Signed-off-by: Konrad Rzeszutek Wilk --- drivers/pci/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 5b1630e4e9e3..a9523fdc6911 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -45,6 +45,7 @@ config XEN_PCIDEV_FRONTEND depends on PCI && X86 && XEN select HOTPLUG select PCI_XEN + select XEN_XENBUS_FRONTEND default y help The PCI device frontend driver allows the kernel to import arbitrary -- cgit v1.2.3 From 329620a878cf89184b28500d37fa33cc870a3357 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sat, 21 Mar 2009 23:29:34 -0700 Subject: xen/xenbus: making backend support modular is too complex Impact: build fix Making the xenbus backend support a separate module is needlessly complex and causes build failures. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 554ed573c028..5a48ce996dea 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -30,7 +30,7 @@ config XEN_DEV_EVTCHN If in doubt, say yes. config XEN_BACKEND - tristate "Backend driver support" + bool "Backend driver support" depends on XEN_DOM0 default y help -- cgit v1.2.3 From 02cdfcf043c5c6ebcbbaba1c35130b5fbcb10867 Mon Sep 17 00:00:00 2001 From: David Milburn Date: Fri, 12 Nov 2010 15:38:21 -0600 Subject: [libata] new driver acard_ahci, for ATP8620 host controller Add support for Acard ATP8620 host controller. Based upon initial version by Jeff Garzik. Signed-off-by: David Milburn Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 8 + drivers/ata/Makefile | 1 + drivers/ata/acard-ahci.c | 528 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/ahci.h | 3 + drivers/ata/libahci.c | 11 +- 5 files changed, 545 insertions(+), 6 deletions(-) create mode 100644 drivers/ata/acard-ahci.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 36e2319264bd..e3e0e95c7aa5 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -90,6 +90,14 @@ config SATA_INIC162X help This option enables support for Initio 162x Serial ATA. +config SATA_ACARD_AHCI + tristate "ACard AHCI variant (ATP 8620)" + depends on PCI + help + This option enables support for Acard. + + If unsure, say N. + config SATA_SIL24 tristate "Silicon Image 3124/3132 SATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 2b67c900a459..27291aad6ca7 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_ATA) += libata.o # non-SFF interface obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o +obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c new file mode 100644 index 000000000000..339c210f03a6 --- /dev/null +++ b/drivers/ata/acard-ahci.c @@ -0,0 +1,528 @@ + +/* + * acard-ahci.c - ACard AHCI SATA support + * + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org + * on emails. + * + * Copyright 2010 Red Hat, Inc. + * + * + * 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, 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * AHCI hardware documentation: + * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf + * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +#define DRV_NAME "acard-ahci" +#define DRV_VERSION "1.0" + +/* + Received FIS structure limited to 80h. +*/ + +#define ACARD_AHCI_RX_FIS_SZ 128 + +enum { + AHCI_PCI_BAR = 5, +}; + +enum board_ids { + board_acard_ahci, +}; + +struct acard_sg { + __le32 addr; + __le32 addr_hi; + __le32 reserved; + __le32 size; /* bit 31 (EOT) max==0x10000 (64k) */ +}; + +static void acard_ahci_qc_prep(struct ata_queued_cmd *qc); +static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static int acard_ahci_port_start(struct ata_port *ap); +static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +#ifdef CONFIG_PM +static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); +static int acard_ahci_pci_device_resume(struct pci_dev *pdev); +#endif + +static struct scsi_host_template acard_ahci_sht = { + AHCI_SHT("acard-ahci"), +}; + +static struct ata_port_operations acard_ops = { + .inherits = &ahci_ops, + .qc_prep = acard_ahci_qc_prep, + .qc_fill_rtf = acard_ahci_qc_fill_rtf, + .port_start = acard_ahci_port_start, +}; + +#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + +static const struct ata_port_info acard_ahci_port_info[] = { + [board_acard_ahci] = + { + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &acard_ops, + }, +}; + +static const struct pci_device_id acard_ahci_pci_tbl[] = { + /* ACard */ + { PCI_VDEVICE(ARTOP, 0x000d), board_acard_ahci }, /* ATP8620 */ + + { } /* terminate list */ +}; + +static struct pci_driver acard_ahci_pci_driver = { + .name = DRV_NAME, + .id_table = acard_ahci_pci_tbl, + .probe = acard_ahci_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = acard_ahci_pci_device_suspend, + .resume = acard_ahci_pci_device_resume, +#endif +}; + +#ifdef CONFIG_PM +static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct ahci_host_priv *hpriv = host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 ctl; + + if (mesg.event & PM_EVENT_SUSPEND && + hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { + dev_printk(KERN_ERR, &pdev->dev, + "BIOS update required for suspend/resume\n"); + return -EIO; + } + + if (mesg.event & PM_EVENT_SLEEP) { + /* AHCI spec rev1.1 section 8.3.3: + * Software must disable interrupts prior to requesting a + * transition of the HBA to D3 state. + */ + ctl = readl(mmio + HOST_CTL); + ctl &= ~HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + } + + return ata_pci_device_suspend(pdev, mesg); +} + +static int acard_ahci_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc; + + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; + + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + } + + ata_host_resume(host); + + return 0; +} +#endif + +static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) +{ + int rc; + + if (using_dac && + !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "64-bit DMA enable failed\n"); + return rc; + } + } + } else { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit DMA enable failed\n"); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "32-bit consistent DMA enable failed\n"); + return rc; + } + } + return 0; +} + +static void acard_ahci_pci_print_info(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + u16 cc; + const char *scc_s; + + pci_read_config_word(pdev, 0x0a, &cc); + if (cc == PCI_CLASS_STORAGE_IDE) + scc_s = "IDE"; + else if (cc == PCI_CLASS_STORAGE_SATA) + scc_s = "SATA"; + else if (cc == PCI_CLASS_STORAGE_RAID) + scc_s = "RAID"; + else + scc_s = "unknown"; + + ahci_print_info(host, scc_s); +} + +static unsigned int acard_ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) +{ + struct scatterlist *sg; + struct acard_sg *acard_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; + unsigned int si, last_si = 0; + + VPRINTK("ENTER\n"); + + /* + * Next, the S/G list. + */ + for_each_sg(qc->sg, sg, qc->n_elem, si) { + dma_addr_t addr = sg_dma_address(sg); + u32 sg_len = sg_dma_len(sg); + + /* + * ACard note: + * We must set an end-of-table (EOT) bit, + * and the segment cannot exceed 64k (0x10000) + */ + acard_sg[si].addr = cpu_to_le32(addr & 0xffffffff); + acard_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); + acard_sg[si].size = cpu_to_le32(sg_len); + last_si = si; + } + + acard_sg[last_si].size |= cpu_to_le32(1 << 31); /* set EOT */ + + return si; +} + +static void acard_ahci_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ahci_port_priv *pp = ap->private_data; + int is_atapi = ata_is_atapi(qc->tf.protocol); + void *cmd_tbl; + u32 opts; + const u32 cmd_fis_len = 5; /* five dwords */ + unsigned int n_elem; + + /* + * Fill in command table information. First, the header, + * a SATA Register - Host to Device command FIS. + */ + cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; + + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); + if (is_atapi) { + memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); + memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); + } + + n_elem = 0; + if (qc->flags & ATA_QCFLAG_DMAMAP) + n_elem = acard_ahci_fill_sg(qc, cmd_tbl); + + /* + * Fill in command slot information. + * + * ACard note: prd table length not filled in + */ + opts = cmd_fis_len | (qc->dev->link->pmp << 12); + if (qc->tf.flags & ATA_TFLAG_WRITE) + opts |= AHCI_CMD_WRITE; + if (is_atapi) + opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; + + ahci_fill_cmd_slot(pp, qc->tag, opts); +} + +static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) +{ + struct ahci_port_priv *pp = qc->ap->private_data; + u8 *rx_fis = pp->rx_fis; + + if (pp->fbs_enabled) + rx_fis += qc->dev->link->pmp * ACARD_AHCI_RX_FIS_SZ; + + /* + * After a successful execution of an ATA PIO data-in command, + * the device doesn't send D2H Reg FIS to update the TF and + * the host should take TF and E_Status from the preceding PIO + * Setup FIS. + */ + if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && + !(qc->flags & ATA_QCFLAG_FAILED)) { + ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); + qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15]; + } else + ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); + + return true; +} + +static int acard_ahci_port_start(struct ata_port *ap) +{ + struct ahci_host_priv *hpriv = ap->host->private_data; + struct device *dev = ap->host->dev; + struct ahci_port_priv *pp; + void *mem; + dma_addr_t mem_dma; + size_t dma_sz, rx_fis_sz; + + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + + /* check FBS capability */ + if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) { + void __iomem *port_mmio = ahci_port_base(ap); + u32 cmd = readl(port_mmio + PORT_CMD); + if (cmd & PORT_CMD_FBSCP) + pp->fbs_supported = true; + else if (hpriv->flags & AHCI_HFLAG_YES_FBS) { + dev_printk(KERN_INFO, dev, + "port %d can do FBS, forcing FBSCP\n", + ap->port_no); + pp->fbs_supported = true; + } else + dev_printk(KERN_WARNING, dev, + "port %d is not capable of FBS\n", + ap->port_no); + } + + if (pp->fbs_supported) { + dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ; + rx_fis_sz = ACARD_AHCI_RX_FIS_SZ * 16; + } else { + dma_sz = AHCI_PORT_PRIV_DMA_SZ; + rx_fis_sz = ACARD_AHCI_RX_FIS_SZ; + } + + mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL); + if (!mem) + return -ENOMEM; + memset(mem, 0, dma_sz); + + /* + * First item in chunk of DMA memory: 32-slot command table, + * 32 bytes each in size + */ + pp->cmd_slot = mem; + pp->cmd_slot_dma = mem_dma; + + mem += AHCI_CMD_SLOT_SZ; + mem_dma += AHCI_CMD_SLOT_SZ; + + /* + * Second item: Received-FIS area + */ + pp->rx_fis = mem; + pp->rx_fis_dma = mem_dma; + + mem += rx_fis_sz; + mem_dma += rx_fis_sz; + + /* + * Third item: data area for storing a single command + * and its scatter-gather table + */ + pp->cmd_tbl = mem; + pp->cmd_tbl_dma = mem_dma; + + /* + * Save off initial list of interrupts to be enabled. + * This could be changed later + */ + pp->intr_mask = DEF_PORT_IRQ; + + ap->private_data = pp; + + /* engage engines, captain */ + return ahci_port_resume(ap); +} + +static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + unsigned int board_id = ent->driver_data; + struct ata_port_info pi = acard_ahci_port_info[board_id]; + const struct ata_port_info *ppi[] = { &pi, NULL }; + struct device *dev = &pdev->dev; + struct ahci_host_priv *hpriv; + struct ata_host *host; + int n_ports, i, rc; + + VPRINTK("ENTER\n"); + + WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + + /* acquire resources */ + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + /* AHCI controllers often implement SFF compatible interface. + * Grab all PCI BARs just in case. + */ + rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; + + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + hpriv->flags |= (unsigned long)pi.private_data; + + if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) + pci_enable_msi(pdev); + + hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; + + /* save initial config */ + ahci_save_initial_config(&pdev->dev, hpriv, 0, 0); + + /* prepare host */ + if (hpriv->cap & HOST_CAP_NCQ) + pi.flags |= ATA_FLAG_NCQ; + + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + + ahci_set_em_messages(hpriv, &pi); + + /* CAP.NP sometimes indicate the index of the last enabled + * port, at other times, that of the last possible port, so + * determining the maximum port number requires looking at + * both CAP.NP and port_map. + */ + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); + + host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); + if (!host) + return -ENOMEM; + host->private_data = hpriv; + + if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) + host->flags |= ATA_HOST_PARALLEL_SCAN; + else + printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n"); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, + 0x100 + ap->port_no * 0x80, "port"); + + /* set initial link pm policy */ + /* + ap->pm_policy = NOT_AVAILABLE; + */ + /* disabled/not-implemented port */ + if (!(hpriv->port_map & (1 << i))) + ap->ops = &ata_dummy_port_ops; + } + + /* initialize adapter */ + rc = acard_ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); + if (rc) + return rc; + + rc = ahci_reset_controller(host); + if (rc) + return rc; + + ahci_init_controller(host); + acard_ahci_pci_print_info(host); + + pci_set_master(pdev); + return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, + &acard_ahci_sht); +} + +static int __init acard_ahci_init(void) +{ + return pci_register_driver(&acard_ahci_pci_driver); +} + +static void __exit acard_ahci_exit(void) +{ + pci_unregister_driver(&acard_ahci_pci_driver); +} + +MODULE_AUTHOR("Jeff Garzik"); +MODULE_DESCRIPTION("ACard AHCI SATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, acard_ahci_pci_tbl); +MODULE_VERSION(DRV_VERSION); + +module_init(acard_ahci_init); +module_exit(acard_ahci_exit); diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 329cbbb91284..3e606c34f57b 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -311,6 +311,8 @@ extern struct device_attribute *ahci_sdev_attrs[]; extern struct ata_port_operations ahci_ops; +void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, + u32 opts); void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv, unsigned int force_port_map, @@ -326,6 +328,7 @@ int ahci_stop_engine(struct ata_port *ap); void ahci_start_engine(struct ata_port *ap); int ahci_check_ready(struct ata_link *link); int ahci_kick_engine(struct ata_port *ap); +int ahci_port_resume(struct ata_port *ap); void ahci_set_em_messages(struct ahci_host_priv *hpriv, struct ata_port_info *pi); int ahci_reset_em(struct ata_host *host); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index ebc08d65b3dd..26d452339e98 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -87,10 +87,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, static void ahci_postreset(struct ata_link *link, unsigned int *class); static void ahci_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); -static int ahci_port_resume(struct ata_port *ap); static void ahci_dev_config(struct ata_device *dev); -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, - u32 opts); #ifdef CONFIG_PM static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); #endif @@ -1133,8 +1130,8 @@ static unsigned int ahci_dev_classify(struct ata_port *ap) return ata_dev_classify(&tf); } -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, - u32 opts) +void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, + u32 opts) { dma_addr_t cmd_tbl_dma; @@ -1145,6 +1142,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); } +EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot); int ahci_kick_engine(struct ata_port *ap) { @@ -1918,7 +1916,7 @@ static void ahci_pmp_detach(struct ata_port *ap) writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } -static int ahci_port_resume(struct ata_port *ap) +int ahci_port_resume(struct ata_port *ap) { ahci_power_up(ap); ahci_start_port(ap); @@ -1930,6 +1928,7 @@ static int ahci_port_resume(struct ata_port *ap) return 0; } +EXPORT_SYMBOL_GPL(ahci_port_resume); #ifdef CONFIG_PM static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) -- cgit v1.2.3 From b27dcfb0670ea7352a67137f4ff7947c2a9f6892 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 17 Nov 2010 22:56:48 -0500 Subject: [libata] avoid needlessly passing around ptr to SCSI completion func It's stored in struct scsi_cmnd->scsi_done, making several 'done' parameters to functions redundant. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 60 ++++++++++++++++--------------------- drivers/scsi/ipr.c | 2 +- drivers/scsi/libsas/sas_scsi_host.c | 3 +- include/linux/libata.h | 6 ++-- 4 files changed, 29 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 66aa4bee80a6..5defc74973d7 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -346,12 +346,11 @@ struct device_attribute *ata_common_sdev_attrs[] = { }; EXPORT_SYMBOL_GPL(ata_common_sdev_attrs); -static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) +static void ata_scsi_invalid_field(struct scsi_cmnd *cmd) { ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); /* "Invalid field in cbd" */ - done(cmd); + cmd->scsi_done(cmd); } /** @@ -719,7 +718,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl); * ata_scsi_qc_new - acquire new ata_queued_cmd reference * @dev: ATA device to which the new command is attached * @cmd: SCSI command that originated this ATA command - * @done: SCSI command completion function * * Obtain a reference to an unused ata_queued_cmd structure, * which is the basic libata structure representing a single @@ -736,21 +734,20 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl); * Command allocated, or %NULL if none available. */ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, - struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) + struct scsi_cmnd *cmd) { struct ata_queued_cmd *qc; qc = ata_qc_new_init(dev); if (qc) { qc->scsicmd = cmd; - qc->scsidone = done; + qc->scsidone = cmd->scsi_done; qc->sg = scsi_sglist(cmd); qc->n_elem = scsi_sg_count(cmd); } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); - done(cmd); + cmd->scsi_done(cmd); } return qc; @@ -1735,7 +1732,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * ata_scsi_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed * @cmd: SCSI command to execute - * @done: SCSI command completion function * @xlat_func: Actor which translates @cmd to an ATA taskfile * * Our ->queuecommand() function has decided that the SCSI @@ -1759,7 +1755,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * needs to be deferred. */ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *), ata_xlat_func_t xlat_func) { struct ata_port *ap = dev->link->ap; @@ -1768,7 +1763,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, VPRINTK("ENTER\n"); - qc = ata_scsi_qc_new(dev, cmd, done); + qc = ata_scsi_qc_new(dev, cmd); if (!qc) goto err_mem; @@ -1804,14 +1799,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, early_finish: ata_qc_free(qc); - qc->scsidone(cmd); + cmd->scsi_done(cmd); DPRINTK("EXIT - early finish (good or error)\n"); return 0; err_did: ata_qc_free(qc); cmd->result = (DID_ERROR << 16); - qc->scsidone(cmd); + cmd->scsi_done(cmd); err_mem: DPRINTK("EXIT - internal\n"); return 0; @@ -3116,7 +3111,6 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, } static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, - void (*done)(struct scsi_cmnd *), struct ata_device *dev) { u8 scsi_op = scmd->cmnd[0]; @@ -3150,9 +3144,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, } if (xlat_func) - rc = ata_scsi_translate(dev, scmd, done, xlat_func); + rc = ata_scsi_translate(dev, scmd, xlat_func); else - ata_scsi_simulate(dev, scmd, done); + ata_scsi_simulate(dev, scmd); return rc; @@ -3160,7 +3154,7 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n", scmd->cmd_len, scsi_op, dev->cdb_len); scmd->result = DID_ERROR << 16; - done(scmd); + scmd->scsi_done(scmd); return 0; } @@ -3199,7 +3193,7 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) dev = ata_scsi_find_dev(ap, scsidev); if (likely(dev)) - rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev); + rc = __ata_scsi_queuecmd(cmd, dev); else { cmd->result = (DID_BAD_TARGET << 16); cmd->scsi_done(cmd); @@ -3214,7 +3208,6 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) * ata_scsi_simulate - simulate SCSI command on ATA device * @dev: the target device * @cmd: SCSI command being sent to device. - * @done: SCSI command completion function. * * Interprets and directly executes a select list of SCSI commands * that can be handled internally. @@ -3223,8 +3216,7 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) * spin_lock_irqsave(host lock) */ -void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) +void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) { struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; @@ -3233,17 +3225,17 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, args.dev = dev; args.id = dev->id; args.cmd = cmd; - args.done = done; + args.done = cmd->scsi_done; switch(scsicmd[0]) { /* TODO: worth improving? */ case FORMAT_UNIT: - ata_scsi_invalid_field(cmd, done); + ata_scsi_invalid_field(cmd); break; case INQUIRY: if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_scsi_invalid_field(cmd, done); + ata_scsi_invalid_field(cmd); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); else switch (scsicmd[2]) { @@ -3269,7 +3261,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2); break; default: - ata_scsi_invalid_field(cmd, done); + ata_scsi_invalid_field(cmd); break; } break; @@ -3281,7 +3273,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, case MODE_SELECT: /* unconditionally return */ case MODE_SELECT_10: /* bad-field-in-cdb */ - ata_scsi_invalid_field(cmd, done); + ata_scsi_invalid_field(cmd); break; case READ_CAPACITY: @@ -3292,7 +3284,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); else - ata_scsi_invalid_field(cmd, done); + ata_scsi_invalid_field(cmd); break; case REPORT_LUNS: @@ -3302,7 +3294,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, case REQUEST_SENSE: ata_scsi_set_sense(cmd, 0, 0, 0); cmd->result = (DRIVER_SENSE << 24); - done(cmd); + cmd->scsi_done(cmd); break; /* if we reach this, then writeback caching is disabled, @@ -3324,14 +3316,14 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) ata_scsi_rbuf_fill(&args, ata_scsiop_noop); else - ata_scsi_invalid_field(cmd, done); + ata_scsi_invalid_field(cmd); break; /* all other commands */ default: ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0); /* "Invalid command operation code" */ - done(cmd); + cmd->scsi_done(cmd); break; } } @@ -3858,7 +3850,6 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure); /** * ata_sas_queuecmd - Issue SCSI cdb to libata-managed device * @cmd: SCSI command to be sent - * @done: Completion function, called when command is complete * @ap: ATA port to which the command is being sent * * RETURNS: @@ -3866,18 +3857,17 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure); * 0 otherwise. */ -int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), - struct ata_port *ap) +int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap) { int rc = 0; ata_scsi_dump_cdb(ap, cmd); if (likely(ata_dev_enabled(ap->link.device))) - rc = __ata_scsi_queuecmd(cmd, done, ap->link.device); + rc = __ata_scsi_queuecmd(cmd, ap->link.device); else { cmd->result = (DID_BAD_TARGET << 16); - done(cmd); + cmd->scsi_done(cmd); } return rc; } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5bbaee597e88..2c71927aad64 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5743,7 +5743,7 @@ static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd, } if (ipr_is_gata(res) && res->sata_port) - return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap); + return ata_sas_queuecmd(scsi_cmd, res->sata_port->ap); ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ioarcb = &ipr_cmd->ioarcb; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 29251fabecc6..5815cbeb27a6 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -211,8 +211,7 @@ static int sas_queuecommand_lck(struct scsi_cmnd *cmd, unsigned long flags; spin_lock_irqsave(dev->sata_dev.ap->lock, flags); - res = ata_sas_queuecmd(cmd, scsi_done, - dev->sata_dev.ap); + res = ata_sas_queuecmd(cmd, dev->sata_dev.ap); spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); goto out; } diff --git a/include/linux/libata.h b/include/linux/libata.h index d947b1231662..c9c5d7ad1a2b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -996,8 +996,7 @@ extern int ata_sas_port_init(struct ata_port *); extern int ata_sas_port_start(struct ata_port *ap); extern void ata_sas_port_stop(struct ata_port *ap); extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *); -extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), - struct ata_port *ap); +extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap); extern int sata_scr_valid(struct ata_link *link); extern int sata_scr_read(struct ata_link *link, int reg, u32 *val); extern int sata_scr_write(struct ata_link *link, int reg, u32 val); @@ -1040,8 +1039,7 @@ extern unsigned int ata_do_dev_read_id(struct ata_device *dev, struct ata_taskfile *tf, u16 *id); extern void ata_qc_complete(struct ata_queued_cmd *qc); extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active); -extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)); +extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd); extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); -- cgit v1.2.3 From 2f299d5de02da3ffb1f9e1a05c91dcd1173ebd3c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 4 Jan 2011 17:42:20 -0500 Subject: drm/radeon/kms: adjust quirk for acer laptop Acer laptop (TravelMate 5730G) has an HDMI connector on the laptop and a DVI connector on the docking station and both share the same encoder, hpd pin, and ddc line. The bios connector table reflects this and is technically correct, however, we drop the DVI connector here since xrandr has no concept of encoders (only crtcs and connectors) and will try and drive both connectors with different crtcs which isn't possible on the hardware side and leaves no crtcs for LVDS or VGA. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=32732 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 45bc750e9ae2..6317d2c9e6d9 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -313,7 +313,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, uint16_t *line_mux, struct radeon_hpd *hpd) { - struct radeon_device *rdev = dev->dev_private; /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ if ((dev->pdev->device == 0x791e) && @@ -425,21 +424,23 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - /* Acer laptop reports DVI-D as DVI-I and hpd pins reversed */ + /* Acer laptop (Acer TravelMate 5730G) has an HDMI port + * on the laptop and a DVI port on the docking station and + * both share the same encoder, hpd pin, and ddc line. + * So while the bios table is technically correct, + * we drop the DVI port here since xrandr has no concept of + * encoders and will try and drive both connectors + * with different crtcs which isn't possible on the hardware + * side and leaves no crtcs for LVDS or VGA. + */ if ((dev->pdev->device == 0x95c4) && (dev->pdev->subsystem_vendor == 0x1025) && (dev->pdev->subsystem_device == 0x013c)) { - struct radeon_gpio_rec gpio; - if ((*connector_type == DRM_MODE_CONNECTOR_DVII) && (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) { - gpio = radeon_lookup_gpio(rdev, 6); - *hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio); + /* actually it's a DVI-D port not DVI-I */ *connector_type = DRM_MODE_CONNECTOR_DVID; - } else if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && - (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) { - gpio = radeon_lookup_gpio(rdev, 7); - *hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio); + return false; } } -- cgit v1.2.3 From 9eba4a93ce520a627e876b0d1851d4f78a701c2b Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Wed, 5 Jan 2011 05:46:48 +0100 Subject: drm/radeon/kms: manage r300 CMASK RAM access and allow CMASK clear MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CMASK RAM is for colorbuffer compression (used in conjunction with MSAA). Only one user (filp) can access it. The CMASK RAM access is managed in the same way as Hyper-Z, but there is a separate ioctl, because an app that uses MSAA does not necessarily have to use zbuffering. Signed-off-by: Marek Olšák Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 9 +++++++++ drivers/gpu/drm/radeon/r300d.h | 1 + drivers/gpu/drm/radeon/radeon.h | 3 ++- drivers/gpu/drm/radeon/radeon_drv.c | 2 +- drivers/gpu/drm/radeon/radeon_kms.c | 39 +++++++++++++++++++++++++------------ include/drm/radeon_drm.h | 1 + 6 files changed, 41 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 36b4f7b48d6a..23fee54c3b75 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -745,6 +745,11 @@ static int r300_packet0_check(struct radeon_cs_parser *p, break; case 0x4E00: /* RB3D_CCTL */ + if ((idx_value & (1 << 10)) && /* CMASK_ENABLE */ + p->rdev->cmask_filp != p->filp) { + DRM_ERROR("Invalid RB3D_CCTL: Cannot enable CMASK.\n"); + return -EINVAL; + } track->num_cb = ((idx_value >> 5) & 0x3) + 1; break; case 0x4E38: @@ -1206,6 +1211,10 @@ static int r300_packet3_check(struct radeon_cs_parser *p, if (p->rdev->hyperz_filp != p->filp) return -EINVAL; break; + case PACKET3_3D_CLEAR_CMASK: + if (p->rdev->cmask_filp != p->filp) + return -EINVAL; + break; case PACKET3_NOP: break; default: diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h index 0c036c60d9df..1f519a5ffb8c 100644 --- a/drivers/gpu/drm/radeon/r300d.h +++ b/drivers/gpu/drm/radeon/r300d.h @@ -54,6 +54,7 @@ #define PACKET3_3D_DRAW_IMMD_2 0x35 #define PACKET3_3D_DRAW_INDX_2 0x36 #define PACKET3_3D_CLEAR_HIZ 0x37 +#define PACKET3_3D_CLEAR_CMASK 0x38 #define PACKET3_BITBLT_MULTI 0x9B #define PACKET0(reg, n) (CP_PACKET0 | \ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 140eaceab279..a835d95021d1 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1168,8 +1168,9 @@ struct radeon_device { uint8_t audio_category_code; struct notifier_block acpi_nb; - /* only one userspace can use Hyperz features at a time */ + /* only one userspace can use Hyperz features or CMASK at a time */ struct drm_file *hyperz_filp; + struct drm_file *cmask_filp; /* i2c buses */ struct radeon_i2c_chan *i2c_bus[RADEON_MAX_I2C_BUS]; }; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 18225f21ee0f..be5cb4f28c29 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -48,7 +48,7 @@ * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs - * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf + * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 8 diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index b2686334d46b..28a53e4a925f 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -96,9 +96,27 @@ out: return r; } +static void radeon_set_filp_rights(struct drm_device *dev, + struct drm_file **owner, + struct drm_file *applier, + uint32_t *value) +{ + mutex_lock(&dev->struct_mutex); + if (*value == 1) { + /* wants rights */ + if (!*owner) + *owner = applier; + } else if (*value == 0) { + /* revokes rights */ + if (*owner == applier) + *owner = NULL; + } + *value = *owner == applier ? 1 : 0; + mutex_unlock(&dev->struct_mutex); +} /* - * Userspace get informations ioctl + * Userspace get information ioctl */ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { @@ -173,18 +191,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value); return -EINVAL; } - mutex_lock(&dev->struct_mutex); - if (value == 1) { - /* wants hyper-z */ - if (!rdev->hyperz_filp) - rdev->hyperz_filp = filp; - } else if (value == 0) { - /* revokes hyper-z */ - if (rdev->hyperz_filp == filp) - rdev->hyperz_filp = NULL; + radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, &value); + break; + case RADEON_INFO_WANT_CMASK: + /* The same logic as Hyper-Z. */ + if (value >= 2) { + DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", value); + return -EINVAL; } - value = rdev->hyperz_filp == filp ? 1 : 0; - mutex_unlock(&dev->struct_mutex); + radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value); break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 10f8b53bdd40..e95a86b8b689 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -906,6 +906,7 @@ struct drm_radeon_cs { #define RADEON_INFO_ACCEL_WORKING2 0x05 #define RADEON_INFO_TILING_CONFIG 0x06 #define RADEON_INFO_WANT_HYPERZ 0x07 +#define RADEON_INFO_WANT_CMASK 0x08 /* get access to CMASK on r300 */ struct drm_radeon_info { uint32_t request; -- cgit v1.2.3 From 32c87fca2fac490e34a9fa900b45f2fbb4faacf9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Jan 2011 14:49:32 +0100 Subject: drm/radeon: use system_wq instead of dev_priv->wq With cmwq, there's no reason for radeon to use a dedicated workqueue. Drop dev_priv->wq and use system_wq instead. Because radeon_driver_irq_uninstall_kms() may be called from unsleepable context, the work items can't be flushed from there. Instead, init and flush from radeon_irq_kms_init/fini(). While at it, simplify canceling/flushing of rdev->pm.dynpm_idle_work. Always initialize and sync cancel instead of being unnecessarily smart about it. Signed-off-by: Tejun Heo Acked-by: Alex Deucher Cc: dri-devel@lists.freedesktop.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/r100.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 1 - drivers/gpu/drm/radeon/radeon_device.c | 6 ----- drivers/gpu/drm/radeon/radeon_irq_kms.c | 5 ++-- drivers/gpu/drm/radeon/radeon_pm.c | 47 +++++++++++---------------------- drivers/gpu/drm/radeon/rs600.c | 2 +- 8 files changed, 23 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3ae63ceb9c33..eaf4fba90b72 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2756,7 +2756,7 @@ restart_ih: if (wptr != rdev->ih.wptr) goto restart_ih; if (queue_hotplug) - queue_work(rdev->wq, &rdev->hotplug_work); + schedule_work(&rdev->hotplug_work); rdev->ih.rptr = rptr; WREG32(IH_RB_RPTR, rdev->ih.rptr); spin_unlock_irqrestore(&rdev->ih.lock, flags); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 300b4a64d8fe..f637595b14e1 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -682,7 +682,7 @@ int r100_irq_process(struct radeon_device *rdev) /* reset gui idle ack. the status bit is broken */ rdev->irq.gui_idle_acked = false; if (queue_hotplug) - queue_work(rdev->wq, &rdev->hotplug_work); + schedule_work(&rdev->hotplug_work); if (rdev->msi_enabled) { switch (rdev->family) { case CHIP_RS400: diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index f95ca5b44396..279794c391e9 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3442,7 +3442,7 @@ restart_ih: if (wptr != rdev->ih.wptr) goto restart_ih; if (queue_hotplug) - queue_work(rdev->wq, &rdev->hotplug_work); + schedule_work(&rdev->hotplug_work); rdev->ih.rptr = rptr; WREG32(IH_RB_RPTR, rdev->ih.rptr); spin_unlock_irqrestore(&rdev->ih.lock, flags); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a835d95021d1..aff8080026a1 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1152,7 +1152,6 @@ struct radeon_device { struct r700_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ struct r600_ih ih; /* r6/700 interrupt ring */ - struct workqueue_struct *wq; struct work_struct hotplug_work; int num_crtc; /* number of crtcs */ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 4ee0c53b28a7..44cf0d707006 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -710,11 +710,6 @@ int radeon_device_init(struct radeon_device *rdev, init_waitqueue_head(&rdev->irq.vblank_queue); init_waitqueue_head(&rdev->irq.idle_queue); - /* setup workqueue */ - rdev->wq = create_workqueue("radeon"); - if (rdev->wq == NULL) - return -ENOMEM; - /* Set asic functions */ r = radeon_asic_init(rdev); if (r) @@ -813,7 +808,6 @@ void radeon_device_fini(struct radeon_device *rdev) /* evict vram memory */ radeon_bo_evict_vram(rdev); radeon_fini(rdev); - destroy_workqueue(rdev->wq); vga_switcheroo_unregister_client(rdev->pdev); vga_client_register(rdev->pdev, NULL, NULL, NULL); if (rdev->rio_mem) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index c6861bb751ad..a289646e8aa4 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -64,8 +64,6 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) struct radeon_device *rdev = dev->dev_private; unsigned i; - INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); - /* Disable *all* interrupts */ rdev->irq.sw_int = false; rdev->irq.gui_idle = false; @@ -114,6 +112,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev) { int r = 0; + INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); + spin_lock_init(&rdev->irq.sw_lock); r = drm_vblank_init(rdev->ddev, rdev->num_crtc); if (r) { @@ -152,6 +152,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) if (rdev->msi_enabled) pci_disable_msi(rdev->pdev); } + flush_work_sync(&rdev->hotplug_work); } void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 4de7776bd1c5..0afd26ccccfa 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -405,20 +405,13 @@ static ssize_t radeon_set_pm_method(struct device *dev, rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; mutex_unlock(&rdev->pm.mutex); } else if (strncmp("profile", buf, strlen("profile")) == 0) { - bool flush_wq = false; - mutex_lock(&rdev->pm.mutex); - if (rdev->pm.pm_method == PM_METHOD_DYNPM) { - cancel_delayed_work(&rdev->pm.dynpm_idle_work); - flush_wq = true; - } /* disable dynpm */ rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; rdev->pm.pm_method = PM_METHOD_PROFILE; mutex_unlock(&rdev->pm.mutex); - if (flush_wq) - flush_workqueue(rdev->wq); + cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); } else { DRM_ERROR("invalid power method!\n"); goto fail; @@ -524,18 +517,14 @@ static void radeon_hwmon_fini(struct radeon_device *rdev) void radeon_pm_suspend(struct radeon_device *rdev) { - bool flush_wq = false; - mutex_lock(&rdev->pm.mutex); if (rdev->pm.pm_method == PM_METHOD_DYNPM) { - cancel_delayed_work(&rdev->pm.dynpm_idle_work); if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED; - flush_wq = true; } mutex_unlock(&rdev->pm.mutex); - if (flush_wq) - flush_workqueue(rdev->wq); + + cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); } void radeon_pm_resume(struct radeon_device *rdev) @@ -550,8 +539,8 @@ void radeon_pm_resume(struct radeon_device *rdev) if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; - queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + schedule_delayed_work(&rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); } mutex_unlock(&rdev->pm.mutex); radeon_pm_compute_clocks(rdev); @@ -585,6 +574,9 @@ int radeon_pm_init(struct radeon_device *rdev) ret = radeon_hwmon_init(rdev); if (ret) return ret; + + INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); + if (rdev->pm.num_power_states > 1) { /* where's the best place to put these? */ ret = device_create_file(rdev->dev, &dev_attr_power_profile); @@ -598,8 +590,6 @@ int radeon_pm_init(struct radeon_device *rdev) rdev->acpi_nb.notifier_call = radeon_acpi_event; register_acpi_notifier(&rdev->acpi_nb); #endif - INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); - if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } @@ -613,25 +603,20 @@ int radeon_pm_init(struct radeon_device *rdev) void radeon_pm_fini(struct radeon_device *rdev) { if (rdev->pm.num_power_states > 1) { - bool flush_wq = false; - mutex_lock(&rdev->pm.mutex); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { rdev->pm.profile = PM_PROFILE_DEFAULT; radeon_pm_update_profile(rdev); radeon_pm_set_clocks(rdev); } else if (rdev->pm.pm_method == PM_METHOD_DYNPM) { - /* cancel work */ - cancel_delayed_work(&rdev->pm.dynpm_idle_work); - flush_wq = true; /* reset default clocks */ rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; radeon_pm_set_clocks(rdev); } mutex_unlock(&rdev->pm.mutex); - if (flush_wq) - flush_workqueue(rdev->wq); + + cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); device_remove_file(rdev->dev, &dev_attr_power_profile); device_remove_file(rdev->dev, &dev_attr_power_method); @@ -690,12 +675,12 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) radeon_pm_get_dynpm_state(rdev); radeon_pm_set_clocks(rdev); - queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + schedule_delayed_work(&rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; - queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + schedule_delayed_work(&rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n"); } } else { /* count == 0 */ @@ -800,8 +785,8 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work) radeon_pm_set_clocks(rdev); } - queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, - msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); + schedule_delayed_work(&rdev->pm.dynpm_idle_work, + msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); } mutex_unlock(&rdev->pm.mutex); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 9a85b1614c86..b4192acaab5f 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -692,7 +692,7 @@ int rs600_irq_process(struct radeon_device *rdev) /* reset gui idle ack. the status bit is broken */ rdev->irq.gui_idle_acked = false; if (queue_hotplug) - queue_work(rdev->wq, &rdev->hotplug_work); + schedule_work(&rdev->hotplug_work); if (rdev->msi_enabled) { switch (rdev->family) { case CHIP_RS600: -- cgit v1.2.3 From f598aa7593427ffe3a61e7767c34bd695a5e7ed0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 4 Jan 2011 00:43:39 -0500 Subject: drm/radeon/kms: add quirk for Mac Radeon HD 2600 card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: 屋国遥 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 6317d2c9e6d9..e4f7e3e82a50 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -387,6 +387,17 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, *line_mux = 0x90; } + /* mac rv630 */ + if ((dev->pdev->device == 0x9588) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x00a6)) { + if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) && + (*connector_type == DRM_MODE_CONNECTOR_DVII)) { + *connector_type = DRM_MODE_CONNECTOR_9PinDIN; + *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1; + } + } + /* ASUS HD 3600 XT board lists the DVI port as HDMI */ if ((dev->pdev->device == 0x9598) && (dev->pdev->subsystem_vendor == 0x1043) && -- cgit v1.2.3 From dffa18449a334cf436c1fabfb2fcf7d4240c994b Mon Sep 17 00:00:00 2001 From: Dennis Gilmore Date: Thu, 6 Jan 2011 17:15:31 +1100 Subject: crypto: n2 - use __devexit not __exit in n2_unregister_algs fixes fedora sparc build failure, thanks to kylem for helping with debugging Signed-off-by: Dennis Gilmore Acked-by: David S. Miller Signed-off-by: Herbert Xu --- drivers/crypto/n2_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 88ee01510ec0..337249155c05 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1542,7 +1542,7 @@ out: return err; } -static void __exit n2_unregister_algs(void) +static void __devexit n2_unregister_algs(void) { mutex_lock(&spu_lock); if (!--algs_registered) -- cgit v1.2.3 From eeb9cc015f91ff08453040dd5b2fde0dbaac90d3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 6 Jan 2011 22:10:15 +1000 Subject: drm/nvc0: fix init without firmware present Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_graph.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 43b44a4b3ab8..5feacd5d5fa4 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -584,7 +584,7 @@ nvc0_graph_init_ctxctl(struct drm_device *dev) r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d"); if (ret == 0) - nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad"); + ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad"); nv_wr32(dev, 0x000260, r000260); if (ret) @@ -686,10 +686,8 @@ nvc0_graph_init(struct drm_device *dev) nv_wr32(dev, 0x400054, 0x34ce3464); ret = nvc0_graph_init_ctxctl(dev); - if (ret) - return ret; - - dev_priv->engine.graph.accel_blocked = false; + if (ret == 0) + dev_priv->engine.graph.accel_blocked = false; return 0; } -- cgit v1.2.3 From beda1d49941765c0765e0f3cb95b4a86de67745d Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 14 Dec 2010 17:07:57 +0200 Subject: Revert "mtd: nand: add check for out of page read" This reverts commit e14feafbe0d5c6d64bb6fe4eba928cb57ac9a4c8. The commit limits the maximum amount of bytes which can be read at one go to the OOB size, which is incorrect, because mtd->read_oob() allows reading multiple pages at a time, see comment near "struct mtd_oob_ops" at include/linux/mtd/mtd.h. So this patch breaks ABI and hence, has to be reverted. Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 33550c43acc2..9c8da741dce0 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1782,13 +1782,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, else len = mtd->oobsize; - /* Do not allow read past end of page */ - if ((ops->ooboffs + readlen) > len) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to read " - "past end of page\n", __func__); - return -EINVAL; - } - if (unlikely(ops->ooboffs >= len)) { DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " "outside oob\n", __func__); @@ -2384,7 +2377,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; } - /* Do not allow write past end of device */ + /* Do not allow reads past end of device */ if (unlikely(to >= mtd->size || ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - -- cgit v1.2.3 From d983c54ebd875f5f6fd37c154195c1c456a7af70 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Mon, 6 Dec 2010 09:05:18 +0900 Subject: mtd: OneNAND: Fix multi block erase support at 4KiB pagesize Original 4KiB pagesize chip (SLC) doesn't support Multi block erase at Spec. Signed-off-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index c38bf9c54a11..88f23e3f3014 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -2492,7 +2492,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_ERASING); - if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { + if (ONENAND_IS_4KB_PAGE(this) || region || + instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { /* region is set for Flex-OneNAND (no mb erase) */ ret = onenand_block_by_block_erase(mtd, instr, region, block_size); -- cgit v1.2.3 From 75c52a49630a478ffe9c1473441779676817fce6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 11 Dec 2010 17:51:44 +0100 Subject: mtd: don't use flush_scheduled_work() flush_scheduled_work() is deprecated and scheduled to be removed. Directly flush cxt->work_{erase|write} on removal instead. Signed-off-by: Tejun Heo Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdoops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 1ee72f3f0512..8b102736b34a 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -396,7 +396,8 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); cxt->mtd = NULL; - flush_scheduled_work(); + flush_work_sync(&cxt->work_erase); + flush_work_sync(&cxt->work_write); } -- cgit v1.2.3 From 7e95d1f1714cb993bc5b7e3a3d532b715b32d80a Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 14 Dec 2010 21:09:40 +0100 Subject: mtd: nand: ams-delta: convert to platform driver In its current form, the driver may interfere with different hardware on different boards if built into the kernel, hence is not suitable for inclusion into a defconfig, inteded to be usable with multiple OMAP1 cpu and machine types. Convert it to a platform driver, that should be free from this issue. Created and tested against linux-2.6.37-rc5 on Amstrad Delta. Signed-off-by: Janusz Krzysztofik Acked-by: Tony Lindgren Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- arch/arm/mach-omap1/board-ams-delta.c | 6 ++++++ drivers/mtd/nand/ams-delta.c | 31 ++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 1d4163b9f0b7..81282f5e8b2d 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -181,6 +181,11 @@ static struct omap_board_config_kernel ams_delta_config[] = { { OMAP_TAG_LCD, &ams_delta_lcd_config }, }; +static struct platform_device ams_delta_nand_device = { + .name = "ams-delta-nand", + .id = -1 +}; + static struct resource ams_delta_kp_resources[] = { [0] = { .start = INT_KEYBOARD, @@ -263,6 +268,7 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = { }; static struct platform_device *ams_delta_devices[] __initdata = { + &ams_delta_nand_device, &ams_delta_kp_device, &ams_delta_lcd_device, &ams_delta_led_device, diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 2548e1065bf8..7d49f6a6b726 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -4,6 +4,7 @@ * Copyright (C) 2006 Jonathan McDowell * * Derived from drivers/mtd/toto.c + * Converted to platform driver by Janusz Krzysztofik * * 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 @@ -151,7 +152,7 @@ static int ams_delta_nand_ready(struct mtd_info *mtd) /* * Main initialization routine */ -static int __init ams_delta_init(void) +static int __devinit ams_delta_init(struct platform_device *pdev) { struct nand_chip *this; int err = 0; @@ -219,20 +220,40 @@ static int __init ams_delta_init(void) return err; } -module_init(ams_delta_init); - /* * Clean up routine */ -static void __exit ams_delta_cleanup(void) +static int __devexit ams_delta_cleanup(struct platform_device *pdev) { /* Release resources, unregister device */ nand_release(ams_delta_mtd); /* Free the MTD device structure */ kfree(ams_delta_mtd); + + return 0; +} + +static struct platform_driver ams_delta_nand_driver = { + .probe = ams_delta_init, + .remove = __devexit_p(ams_delta_cleanup), + .driver = { + .name = "ams-delta-nand", + .owner = THIS_MODULE, + }, +}; + +static int __init ams_delta_nand_init(void) +{ + return platform_driver_register(&ams_delta_nand_driver); +} +module_init(ams_delta_nand_init); + +static void __exit ams_delta_nand_exit(void) +{ + platform_driver_unregister(&ams_delta_nand_driver); } -module_exit(ams_delta_cleanup); +module_exit(ams_delta_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jonathan McDowell "); -- cgit v1.2.3 From 0b524fb9314dc852d6a029296545ddbb17709a8b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sun, 12 Dec 2010 00:23:32 -0800 Subject: mtd: nand: choose correct chip name (ONFI bug) We have the order of the conditional wrong for choosing the ONFI chip name vs. the ID table name. Without this fix, we will almost *always* choose a NULL string to print out instead of the correct one. This has already been suggested by Matthieu Castet. Signed-off-by: Brian Norris Acked-by: Florian Fainelli Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9c8da741dce0..c52ded31a12e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3157,7 +3157,7 @@ ident_done: printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, - chip->onfi_version ? type->name : chip->onfi_params.model); + chip->onfi_version ? chip->onfi_params.model : type->name); return type; } -- cgit v1.2.3 From b7b1a29d94c17e4341856381bccb4d17495bea60 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sun, 12 Dec 2010 00:23:33 -0800 Subject: mtd: nand: rearrange ONFI revision checking, add ONFI 2.3 In checking for the ONFI revision, the first conditional (for checking "unsupported" ONFI) seems unnecessary. All ONFI revisions should be backwards-compatible; even if this is not the case on some newer ONFI revision, it should simply fail the second version-checking if-else block (i.e., the bit-fields for 1.0, 2.0, etc. would not be set to 1). Thus, we move our "unsupported" condition after having checked each bit field. Also, it's simple enough to add a condition for ONFI revision 2.3. Note that this does *NOT* mean we handle all new features of ONFI versions above 1.0. Signed-off-by: Brian Norris Acked-by: Florian Fainelli Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index c52ded31a12e..5dd7ae4e4b23 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2865,20 +2865,24 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, /* check version */ val = le16_to_cpu(p->revision); - if (val == 1 || val > (1 << 4)) { - printk(KERN_INFO "%s: unsupported ONFI version: %d\n", - __func__, val); - return 0; - } - - if (val & (1 << 4)) + if (val & (1 << 5)) + chip->onfi_version = 23; + else if (val & (1 << 4)) chip->onfi_version = 22; else if (val & (1 << 3)) chip->onfi_version = 21; else if (val & (1 << 2)) chip->onfi_version = 20; - else + else if (val & (1 << 1)) chip->onfi_version = 10; + else + chip->onfi_version = 0; + + if (!chip->onfi_version) { + printk(KERN_INFO "%s: unsupported ONFI version: %d\n", + __func__, val); + return 0; + } sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->model, sizeof(p->model)); -- cgit v1.2.3 From 263a8c8635445c0ede3cb22c98a1a12da4672ebc Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 30 Dec 2009 07:40:16 +0100 Subject: mtd: OneNAND: OMAP2/3: add support for command line partitioning Add the ability to parse MTD partition information from the kernel command line. Note that a pointless BUG_ON is removed, as are redundant calls to 'del_mtd_partitions()' and 'del_mtd_device()' because they are also done by 'onenand_release()'. Finally note that 'add_mtd_device()' returns 1 on failure so the error condition was incorrect. Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/omap2.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index da25a90af4a4..324402fcdedc 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -65,6 +65,10 @@ struct omap2_onenand { int (*setup)(void __iomem *base, int freq); }; +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { "cmdlinepart", NULL, }; +#endif + static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) { struct omap2_onenand *c = data; @@ -730,13 +734,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) } #ifdef CONFIG_MTD_PARTITIONS - if (pdata->parts != NULL) - r = add_mtd_partitions(&c->mtd, pdata->parts, - pdata->nr_parts); + r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); + if (r > 0) + r = add_mtd_partitions(&c->mtd, c->parts, r); + else if (pdata->parts != NULL) + r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts); else #endif r = add_mtd_device(&c->mtd); - if (r < 0) + if (r) goto err_release_onenand; platform_set_drvdata(pdev, c); @@ -760,6 +766,7 @@ err_release_mem_region: err_free_cs: gpmc_cs_free(c->gpmc_cs); err_kfree: + kfree(c->parts); kfree(c); return r; @@ -769,17 +776,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) { struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); - BUG_ON(c == NULL); - -#ifdef CONFIG_MTD_PARTITIONS - if (c->parts) - del_mtd_partitions(&c->mtd); - else - del_mtd_device(&c->mtd); -#else - del_mtd_device(&c->mtd); -#endif - onenand_release(&c->mtd); if (c->dma_channel != -1) omap_free_dma(c->dma_channel); @@ -792,6 +788,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); gpmc_cs_free(c->gpmc_cs); + kfree(c->parts); kfree(c); return 0; -- cgit v1.2.3 From e0c1a921f62d22d1aa62c72ddb793f898945ff5a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 10 Dec 2010 12:04:20 +0200 Subject: mtd: OneNAND: lighten scary initial bad block messages Initial bad blocks are normal but the messages look like errors. Make the messages less scary, make the main message an informational message not a warning, make the message displaying registers a debug message and include the address there instead of in the informational message. Signed-off-by: Adrian Hunter Acked-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 22 ++++++++++++---------- drivers/mtd/onenand/onenand_bbt.c | 4 ++-- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 88f23e3f3014..2d7c90de3144 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1484,8 +1484,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) { struct onenand_chip *this = mtd->priv; unsigned long timeout; - unsigned int interrupt; - unsigned int ctrl; + unsigned int interrupt, ctrl, ecc, addr1, addr8; /* The 20 msec is enough */ timeout = jiffies + msecs_to_jiffies(20); @@ -1497,25 +1496,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) /* To get correct interrupt status in timeout case */ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); + addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1); + addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8); if (interrupt & ONENAND_INT_READ) { - int ecc = onenand_read_ecc(this); + ecc = onenand_read_ecc(this); if (ecc & ONENAND_ECC_2BIT_ALL) { - printk(KERN_WARNING "%s: ecc error = 0x%04x, " - "controller error 0x%04x\n", - __func__, ecc, ctrl); + printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x " + "intr 0x%04x addr1 %#x addr8 %#x\n", + __func__, ecc, ctrl, interrupt, addr1, addr8); return ONENAND_BBT_READ_ECC_ERROR; } } else { - printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", - __func__, ctrl, interrupt); + printk(KERN_ERR "%s: read timeout! ctrl 0x%04x " + "intr 0x%04x addr1 %#x addr8 %#x\n", + __func__, ctrl, interrupt, addr1, addr8); return ONENAND_BBT_READ_FATAL_ERROR; } /* Initial bad block case: 0x2400 or 0x0400 */ if (ctrl & ONENAND_CTRL_ERROR) { - printk(KERN_DEBUG "%s: controller error = 0x%04x\n", - __func__, ctrl); + printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x " + "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8); return ONENAND_BBT_READ_ERROR; } diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 905209bf9465..fc2c16a0fd1c 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -101,8 +101,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr if (ret || check_short_pattern(&buf[j * scanlen], scanlen, this->writesize, bd)) { bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", - i >> 1, (unsigned int) from); + printk(KERN_INFO "OneNAND eraseblock %d is an " + "initial bad block\n", i >> 1); mtd->ecc_stats.badblocks++; break; } -- cgit v1.2.3 From 494f45d55bf47d7130e8d9818e9a8965f6504462 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 15 Dec 2010 12:58:15 +0100 Subject: mtd: nand: ams-delta: select for built-in by default Now that the Amstrad Delta NAND driver is converted to a platform driver, which prevents it from interfering with other unrelated hardware in multiple OMAP1 cpu and machine configurations, it can be automatically configured for being built into the kernel if the Amstrad Delta board is also selected. Signed-off-by: Janusz Krzysztofik Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8229802b4346..c89592239bc7 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -96,6 +96,7 @@ config MTD_NAND_SPIA config MTD_NAND_AMS_DELTA tristate "NAND Flash device on Amstrad E3" depends on MACH_AMS_DELTA + default y help Support for NAND flash on Amstrad E3 (Delta). -- cgit v1.2.3 From dcf12463c3416b4a8fc84545233424df0a91e406 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 15 Dec 2010 12:59:32 +0100 Subject: mtd: m25p80: add debugging trace in sst_write Add a DEBUG(MTD_DEBUG_LEVEL2, ..) trace at beginning of sst_write() function as it is done in m25p80_write() function. Signed-off-by: Nicolas Ferre Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index eabe5fb071c6..9c59ff6b6926 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -497,6 +497,10 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int cmd_sz, ret; + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", + dev_name(&flash->spi->dev), __func__, "to", + (u32)to, len); + *retlen = 0; /* sanity checks */ -- cgit v1.2.3 From eaca491f75af5afa9265a6bdfcbbfff6837634ab Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 15 Dec 2010 15:43:44 +0100 Subject: mtd: nand: ams-delta: drop omap_read/write, use ioremap There is a common requirement for not using OMAP specific omap_readw() / omap_writew() function calls in drivers/, but replace them with readw() / writew() on ioremap()ped addresses passed from arch/ instead. The patch implements this idea for the Amstrad Delta NAND driver. To be able to use the modified driver, the board file is updated with the platform device I/O resource declaration, which is passed from there. Created and tested against linux-2.6.37-rc5, on top of recent patch 'MTD: NAND: ams-delta: convert to platform driver'. Signed-off-by: Janusz Krzysztofik Acked-by: Tony Lindgren Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- arch/arm/mach-omap1/board-ams-delta.c | 13 +++++++++- drivers/mtd/nand/ams-delta.c | 49 ++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 81282f5e8b2d..b75ff0b03853 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -181,9 +181,20 @@ static struct omap_board_config_kernel ams_delta_config[] = { { OMAP_TAG_LCD, &ams_delta_lcd_config }, }; +static struct resource ams_delta_nand_resources[] = { + [0] = { + .start = OMAP1_MPUIO_BASE, + .end = OMAP1_MPUIO_BASE + + OMAP_MPUIO_IO_CNTL + sizeof(u32) - 1, + .flags = IORESOURCE_MEM, + }, +}; + static struct platform_device ams_delta_nand_device = { .name = "ams-delta-nand", - .id = -1 + .id = -1, + .num_resources = ARRAY_SIZE(ams_delta_nand_resources), + .resource = ams_delta_nand_resources, }; static struct resource ams_delta_kp_resources[] = { diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 7d49f6a6b726..a067d090cb31 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -5,6 +5,7 @@ * * Derived from drivers/mtd/toto.c * Converted to platform driver by Janusz Krzysztofik + * Partially stolen from drivers/mtd/nand/plat_nand.c * * 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 @@ -63,9 +64,10 @@ static struct mtd_partition partition_info[] = { static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) { struct nand_chip *this = mtd->priv; + void __iomem *io_base = this->priv; - omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); - omap_writew(byte, this->IO_ADDR_W); + writew(0, io_base + OMAP_MPUIO_IO_CNTL); + writew(byte, this->IO_ADDR_W); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); ndelay(40); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, @@ -76,11 +78,12 @@ static u_char ams_delta_read_byte(struct mtd_info *mtd) { u_char res; struct nand_chip *this = mtd->priv; + void __iomem *io_base = this->priv; ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); ndelay(40); - omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); - res = omap_readw(this->IO_ADDR_R); + writew(~0, io_base + OMAP_MPUIO_IO_CNTL); + res = readw(this->IO_ADDR_R); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, AMS_DELTA_LATCH2_NAND_NRE); @@ -155,8 +158,13 @@ static int ams_delta_nand_ready(struct mtd_info *mtd) static int __devinit ams_delta_init(struct platform_device *pdev) { struct nand_chip *this; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + void __iomem *io_base; int err = 0; + if (!res) + return -ENXIO; + /* Allocate memory for MTD device structure and private data */ ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); @@ -178,9 +186,25 @@ static int __devinit ams_delta_init(struct platform_device *pdev) /* Link the private data with the MTD structure */ ams_delta_mtd->priv = this; + if (!request_mem_region(res->start, resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + err = -EBUSY; + goto out_free; + } + + io_base = ioremap(res->start, resource_size(res)); + if (io_base == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -EIO; + goto out_release_io; + } + + this->priv = io_base; + /* Set address of NAND IO lines */ - this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); - this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT); + this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; + this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; this->read_byte = ams_delta_read_byte; this->write_buf = ams_delta_write_buf; this->read_buf = ams_delta_read_buf; @@ -196,6 +220,8 @@ static int __devinit ams_delta_init(struct platform_device *pdev) this->chip_delay = 30; this->ecc.mode = NAND_ECC_SOFT; + platform_set_drvdata(pdev, io_base); + /* Set chip enabled, but */ ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | @@ -215,6 +241,11 @@ static int __devinit ams_delta_init(struct platform_device *pdev) goto out; out_mtd: + platform_set_drvdata(pdev, NULL); + iounmap(io_base); +out_release_io: + release_mem_region(res->start, resource_size(res)); +out_free: kfree(ams_delta_mtd); out: return err; @@ -225,9 +256,15 @@ static int __devinit ams_delta_init(struct platform_device *pdev) */ static int __devexit ams_delta_cleanup(struct platform_device *pdev) { + void __iomem *io_base = platform_get_drvdata(pdev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* Release resources, unregister device */ nand_release(ams_delta_mtd); + iounmap(io_base); + release_mem_region(res->start, resource_size(res)); + /* Free the MTD device structure */ kfree(ams_delta_mtd); -- cgit v1.2.3 From e637276370cb11068ab185c342eac5a78e5415b4 Mon Sep 17 00:00:00 2001 From: Guillaume LECERF Date: Fri, 17 Dec 2010 10:59:41 +0100 Subject: mtd: cfi_cmdset_0002: add support for Samsung K8D6x16UxM NOR chips These chips report CFI v0.0 [1], so extend cfi_fixup_major_minor() to patch all Samsung chips from 0.0 to 1.0. Discussed and tested by the OpenWRT people [2]. [1] http://www.samsung.com/global/system/business/semiconductor/product/2007/6/11/NORFlash/64Mbit/K8D6316UTM/ds_K8D6x16UxM_rev16.pdf [2] https://dev.openwrt.org/ticket/7348 Signed-off-by: Guillaume LECERF Acked-by: Wolfram Sang Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0002.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 9d68ab919f31..324fee4024a9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -392,9 +392,19 @@ static struct cfi_fixup fixup_table[] = { static void cfi_fixup_major_minor(struct cfi_private *cfi, struct cfi_pri_amdstd *extp) { - if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && - extp->MajorVersion == '0') - extp->MajorVersion = '1'; + if (cfi->mfr == CFI_MFR_SAMSUNG) { + if (extp->MajorVersion == '0' && extp->MinorVersion == '0') { + /* + * Samsung K8P2815UQB and K8D6x16UxM chips + * report major=0 / minor=0. + */ + printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu" + " Extended Query version to 1.%c\n", + extp->MinorVersion); + extp->MajorVersion = '1'; + } + } + /* * SST 38VF640x chips report major=0xFF / minor=0xFF. */ -- cgit v1.2.3 From e8953b7395089b917f30d0909f845664d5fafa4e Mon Sep 17 00:00:00 2001 From: Guillaume LECERF Date: Fri, 17 Dec 2010 10:59:47 +0100 Subject: mtd: cfi_cmdset_0002: add support for Samsung K8D3x16UxC NOR chips These chips report CFI v3.3 [1], so patch them on the fly to the more correct v1.3. Discussed and tested by the OpenWRT people [2]. [1] http://www.samsung.com/global/system/business/semiconductor/product/2007/6/11/NORFlash/32Mbit/K8D3216UBC/ds_K8D3x16UxC_rev17.pdf [2] https://dev.openwrt.org/ticket/866 Signed-off-by: Guillaume LECERF Acked-by: Wolfram Sang Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0002.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 324fee4024a9..a43ab45bdb18 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -393,10 +393,12 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, struct cfi_pri_amdstd *extp) { if (cfi->mfr == CFI_MFR_SAMSUNG) { - if (extp->MajorVersion == '0' && extp->MinorVersion == '0') { + if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') || + (extp->MajorVersion == '3' && extp->MinorVersion == '3')) { /* * Samsung K8P2815UQB and K8D6x16UxM chips * report major=0 / minor=0. + * K8D3x16UxC chips report major=3 / minor=3. */ printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu" " Extended Query version to 1.%c\n", -- cgit v1.2.3 From 24ac9a94f9e21ea71d877b0c80867d625b68bec2 Mon Sep 17 00:00:00 2001 From: Ralf Rösch Date: Thu, 30 Dec 2010 10:30:11 +0100 Subject: mtd: txx9ndfmc: limit transfer bytes to 512 (ECC provides 6 bytes max) See commit: c0cbfd0e81d879a950ba6f0df3f75ea30c5ab16e Using __nand_correct_data() helper function, this driver can read 512 byte (with 6 byte ECC) at a time. This is correct, but not more: With NAND chips providing page sizes > 512 Bytes chip->ecc.bytes are calculated > 6 in txx9ndfmc_nand_scan. According the data sheet there are (only) 6 bytes ECC available. After applying the patch a Hynix 512M*8 with 2KiB page size could be successfully formatted and used with an ubifs file system. Signed-off-by: Ralf Roesch Signed-off-by: Artem Bityutskiy Acked-by: Atsushi Nemoto Signed-off-by: David Woodhouse --- drivers/mtd/nand/txx9ndfmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 054a41c0ef4a..ca270a4881a4 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -277,8 +277,9 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) ret = nand_scan_ident(mtd, 1, NULL); if (!ret) { if (mtd->writesize >= 512) { - chip->ecc.size = mtd->writesize; - chip->ecc.bytes = 3 * (mtd->writesize / 256); + /* Hardware ECC 6 byte ECC per 512 Byte data */ + chip->ecc.size = 512; + chip->ecc.bytes = 6; } ret = nand_scan_tail(mtd); } -- cgit v1.2.3 From 8fffed8cfdd511056cb17c70f525017fbb643b94 Mon Sep 17 00:00:00 2001 From: Aleksandr Koltsoff Date: Tue, 4 Jan 2011 10:42:35 +0200 Subject: mtd: m25p80: Fix JEDEC ID for AT26DF321 The last byte of the ID should be zero for this chip. Was added in commit d0e8c47c58575b9131e786edb488fd029eba443e . Reported by Tomi Varjo. Signed-off-by: Aleksandr Koltsoff Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 9c59ff6b6926..e4eba6cc1b2e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -653,7 +653,7 @@ static const struct spi_device_id m25p_ids[] = { { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, + { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, /* EON -- en25pxx */ { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, -- cgit v1.2.3 From cf24dc85ff29a41abd8e73730e5feb22b2666bd3 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 19 Feb 2010 15:39:52 +0100 Subject: mtd: OneNAND: add enable / disable methods to onenand_chip Add enable / disable methods called from get_device() / release_device(). These can be used, for example, to allow the driver to prevent the voltage regulator from being put to sleep while OneNAND is in use. Signed-off-by: Adrian Hunter Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 4 ++++ include/linux/mtd/onenand.h | 2 ++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 2d7c90de3144..2edef5868ace 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -948,6 +948,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state) if (this->state == FL_READY) { this->state = new_state; spin_unlock(&this->chip_lock); + if (new_state != FL_PM_SUSPENDED && this->enable) + this->enable(mtd); break; } if (new_state == FL_PM_SUSPENDED) { @@ -974,6 +976,8 @@ static void onenand_release_device(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; + if (this->state != FL_PM_SUSPENDED && this->disable) + this->disable(mtd); /* Release the chip */ spin_lock(&this->chip_lock); this->state = FL_READY; diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 6da3fe314828..ae418e41d8f5 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -118,6 +118,8 @@ struct onenand_chip { int (*chip_probe)(struct mtd_info *mtd); int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); int (*scan_bbt)(struct mtd_info *mtd); + int (*enable)(struct mtd_info *mtd); + int (*disable)(struct mtd_info *mtd); struct completion complete; int irq; -- cgit v1.2.3 From 9ac4e613a88d7f6a7a9651d863e9c8f63b582718 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 19 Feb 2010 15:39:53 +0100 Subject: mtd: OneNAND: OMAP2/3: prevent regulator sleeping while OneNAND is in use Prevent OneNAND's voltage regulator from going to sleep while OneNAND is in use, by explicitly enabling and disabling the regulator as appropriate. Signed-off-by: Adrian Hunter Signed-off-by: David Woodhouse --- arch/arm/plat-omap/include/plat/onenand.h | 1 + drivers/mtd/onenand/omap2.c | 41 ++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/arm/plat-omap/include/plat/onenand.h b/arch/arm/plat-omap/include/plat/onenand.h index 72f433d7d827..affe87e9ece7 100644 --- a/arch/arm/plat-omap/include/plat/onenand.h +++ b/arch/arm/plat-omap/include/plat/onenand.h @@ -23,6 +23,7 @@ struct omap_onenand_platform_data { int (*onenand_setup)(void __iomem *, int freq); int dma_channel; u8 flags; + u8 regulator_can_sleep; }; #define ONENAND_MAX_PARTITIONS 8 diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 324402fcdedc..1a07bfcc70d4 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ struct omap2_onenand { int dma_channel; int freq; int (*setup)(void __iomem *base, int freq); + struct regulator *regulator; }; #ifdef CONFIG_MTD_PARTITIONS @@ -601,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev) memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); } +static int omap2_onenand_enable(struct mtd_info *mtd) +{ + int ret; + struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); + + ret = regulator_enable(c->regulator); + if (ret != 0) + dev_err(&c->pdev->dev, "cant enable regulator\n"); + + return ret; +} + +static int omap2_onenand_disable(struct mtd_info *mtd) +{ + int ret; + struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); + + ret = regulator_disable(c->regulator); + if (ret != 0) + dev_err(&c->pdev->dev, "cant disable regulator\n"); + + return ret; +} + static int __devinit omap2_onenand_probe(struct platform_device *pdev) { struct omap_onenand_platform_data *pdata; @@ -715,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) } } + if (pdata->regulator_can_sleep) { + c->regulator = regulator_get(&pdev->dev, "vonenand"); + if (IS_ERR(c->regulator)) { + dev_err(&pdev->dev, "Failed to get regulator\n"); + goto err_release_dma; + } + c->onenand.enable = omap2_onenand_enable; + c->onenand.disable = omap2_onenand_disable; + } + if ((r = onenand_scan(&c->mtd, 1)) < 0) - goto err_release_dma; + goto err_release_regulator; switch ((c->onenand.version_id >> 4) & 0xf) { case 0: @@ -751,6 +787,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) err_release_onenand: onenand_release(&c->mtd); +err_release_regulator: + regulator_put(c->regulator); err_release_dma: if (c->dma_channel != -1) omap_free_dma(c->dma_channel); @@ -777,6 +815,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); onenand_release(&c->mtd); + regulator_put(c->regulator); if (c->dma_channel != -1) omap_free_dma(c->dma_channel); omap2_onenand_shutdown(pdev); -- cgit v1.2.3 From d261c72ae03066dc4798c085e904f7dc996a10fb Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 16 Dec 2010 23:42:15 +0100 Subject: mtd: cfi: add writebufsize initialization Initialize mtd->writebufsize to the value obtained by CFI query command at probe time. Signed-off-by: Anatolij Gustschin Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 1 + drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++++ drivers/mtd/chips/cfi_cmdset_0020.c | 1 + 3 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 44cbfc093ecc..a8c3e1c9b02a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -455,6 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->writesize = 1; + mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index a43ab45bdb18..f072fcfde04e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -440,6 +440,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->writesize = 1; + mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; + + DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", + __func__, mtd->writebufsize); mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 314af1f5a370..c04b7658abe9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -238,6 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->resume = cfi_staa_resume; mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ + mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; map->fldrv = &cfi_staa_chipdrv; __module_get(THIS_MODULE); mtd->name = map->name; -- cgit v1.2.3 From cbcab65a17319246dc360f6b5fac5f7b474b9821 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 16 Dec 2010 23:42:16 +0100 Subject: mtd: nand: add mtd->writebufsize initialization Initialize mtd->writebufsize to be equal to mtd->writesize. Signed-off-by: Anatolij Gustschin Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5dd7ae4e4b23..4915067379b8 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3439,6 +3439,7 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->resume = nand_resume; mtd->block_isbad = nand_block_isbad; mtd->block_markbad = nand_block_markbad; + mtd->writebufsize = mtd->writesize; /* propagate ecc.layout to mtd_info */ mtd->ecclayout = chip->ecc.layout; -- cgit v1.2.3 From 25dcd29786d3fbd5751dc3c5b8109d930ea2d312 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 16 Dec 2010 23:42:17 +0100 Subject: mtd: onenand: add mtd->writebufsize initialization Initialize mtd->writebufsize to be equal to mtd->writesize. Signed-off-by: Anatolij Gustschin Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 2edef5868ace..bac41caa8df7 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -4080,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->block_isbad = onenand_block_isbad; mtd->block_markbad = onenand_block_markbad; mtd->owner = THIS_MODULE; + mtd->writebufsize = mtd->writesize; /* Unlock whole block */ this->unlock_all(mtd); -- cgit v1.2.3 From 7fa33ac0a7e24a1b8bd71be5c47a17423c62fbda Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 16 Dec 2010 23:42:18 +0100 Subject: mtd: initialize writebufsize in the MTD object of a partition Propagate the writebufsize to the partition's MTD object so that UBI can set correct value for it's minimal I/O size using the writebufsize field of MTD object of the partition. By previous patches we added proper writebufsize field initialization. Next patch can now change UBI to use this field for setting the minimal I/O size. Signed-off-by: Anatolij Gustschin Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdconcat.c | 1 + drivers/mtd/mtdpart.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index bf8de0943103..5f5777bd3f75 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -776,6 +776,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; + concat->mtd.writebufsize = subdev[0]->writebufsize; concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 1047ff0a4f55..b910a37baed8 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -384,6 +384,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.flags = master->flags & ~part->mask_flags; slave->mtd.size = part->size; slave->mtd.writesize = master->writesize; + slave->mtd.writebufsize = master->writebufsize; slave->mtd.oobsize = master->oobsize; slave->mtd.oobavail = master->oobavail; slave->mtd.subpage_sft = master->subpage_sft; -- cgit v1.2.3 From a121f643993474548fe98144514c50dd4f3dbe76 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 16 Dec 2010 23:42:19 +0100 Subject: UBI: use mtd->writebufsize to set minimal I/O unit size Previously we used mtd->writesize field to set UBI's minimal I/O unit size. This sometimes caused UBIFS recovery issues when mounting an uncleanly unmounted UBIFS partition on NOR flash since mtd->writesize is 1 byte for NOR flash. The MTD CFI driver however often performs writing multiple bytes in one programming operation using the chip's write buffer. We have to use the size of this write buffer as a minimal I/O unit size for UBI on NOR flash to fix the observed UBIFS recovery issues. Signed-off-by: Anatolij Gustschin Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/ubi/build.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 5ebe280225d6..f49e49dc5928 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -672,7 +672,33 @@ static int io_init(struct ubi_device *ubi) ubi->nor_flash = 1; } - ubi->min_io_size = ubi->mtd->writesize; + /* + * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize + * for these purposes, not @mtd->writesize. At the moment this does not + * matter for NAND, because currently @mtd->writebufsize is equivalent to + * @mtd->writesize for all NANDs. However, some CFI NOR flashes may + * have @mtd->writebufsize which is multiple of @mtd->writesize. + * + * The reason we use @mtd->writebufsize for @ubi->min_io_size is that + * UBI and UBIFS recovery algorithms rely on the fact that if there was + * an unclean power cut, then we can find offset of the last corrupted + * node, align the offset to @ubi->min_io_size, read the rest of the + * eraseblock starting from this offset, and check whether there are + * only 0xFF bytes. If yes, then we are probably dealing with a + * corruption caused by a power cut, if not, then this is probably some + * severe corruption. + * + * Thus, we have to use the maximum write unit size of the flash, which + * is @mtd->writebufsize, because @mtd->writesize is the minimum write + * size, not the maximum. + */ + if (ubi->mtd->type == MTD_NANDFLASH) + ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize); + else if (ubi->mtd->type == MTD_NORFLASH) + ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0); + + ubi->min_io_size = ubi->mtd->writebufsize; + ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; /* -- cgit v1.2.3 From 52d039fdaa78c5a9f9bc2940ad58d7ed76b8336d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Jan 2011 17:05:36 +0300 Subject: mtd: pxa3xx_nand: NULL dereference in pxa3xx_nand_probe "info->cmdset" gets dereferenced in __readid() so it needs to be initialized earlier in the function. This bug was introduced in 18c81b1828f8 "mtd: pxa3xx_nand: remove the flash info in driver structure". Cc: stable@kernel.org [2.6.37+] Reported-and-tested-by: Sven Neumann Signed-off-by: Dan Carpenter Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 17f8518cc5eb..ea2c288df3f6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -885,6 +885,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) /* set info fields needed to __readid */ info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->reg_ndcr = ndcr; + info->cmdset = &default_cmdset; if (__readid(info, &id)) return -ENODEV; @@ -915,7 +916,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); - info->cmdset = &default_cmdset; return 0; } -- cgit v1.2.3 From dfe63bb0ad9810db13aab0058caba97866e0a681 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Thu, 23 Dec 2010 16:40:37 +0000 Subject: drm: Update fbdev fb_fix_screeninfo If you change the color depth via fbset or some other framebuffer aware userland application struct fb_fix_screeninfo is not updated to this new information. This patch fixes this issue. Also the function is changed to just pass in struct drm_framebuffer so in the future we could use more fields. I'm hoping some day fix->smem* could be set here :-) Signed-off-by: James Simmons Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 41 +++++++++++++++++---------------- drivers/gpu/drm/i915/intel_fb.c | 1 - drivers/gpu/drm/nouveau/nouveau_fbcon.c | 1 - drivers/gpu/drm/radeon/radeon_fb.c | 2 -- include/drm/drm_fb_helper.h | 3 --- 5 files changed, 21 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 5c4f9b9ecdc0..0307d601f5e5 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -607,6 +607,25 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_fini); +void drm_fb_helper_fill_fix(struct fb_info *info, struct drm_framebuffer *fb) +{ + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = fb->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : + FB_VISUAL_TRUECOLOR; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; + info->fix.type_aux = 0; + info->fix.xpanstep = 1; /* doing it in hw */ + info->fix.ypanstep = 1; /* doing it in hw */ + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_NONE; + info->fix.type_aux = 0; + + info->fix.line_length = fb->pitch; + return; +} +EXPORT_SYMBOL(drm_fb_helper_fill_fix); + static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { @@ -816,6 +835,7 @@ int drm_fb_helper_set_par(struct fb_info *info) mutex_unlock(&dev->mode_config.mutex); return ret; } + drm_fb_helper_fill_fix(info, fb_helper->fb); } mutex_unlock(&dev->mode_config.mutex); @@ -953,6 +973,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (new_fb) { info->var.pixclock = 0; + drm_fb_helper_fill_fix(info, fb_helper->fb); if (register_framebuffer(info) < 0) { return -EINVAL; } @@ -979,26 +1000,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); -void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, - uint32_t depth) -{ - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : - FB_VISUAL_TRUECOLOR; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; - info->fix.type_aux = 0; - info->fix.xpanstep = 1; /* doing it in hw */ - info->fix.ypanstep = 1; /* doing it in hw */ - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.type_aux = 0; - - info->fix.line_length = pitch; - return; -} -EXPORT_SYMBOL(drm_fb_helper_fill_fix); - void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height) { diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 67738f32dfd4..701e830d0012 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -150,7 +150,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev, // memset(info->screen_base, 0, size); - drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); info->pixmap.size = 64*1024; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 6d56a54b6e2e..a26d04740c88 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -359,7 +359,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); info->screen_size = size; - drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); /* Set aperture base/size for vesafb takeover */ diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 66324b5bb5ba..ca32e9c1e91d 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -225,8 +225,6 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, strcpy(info->fix.id, "radeondrmfb"); - drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); - info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &radeonfb_ops; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index f22e7fe4b6db..aac27bd56e89 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -121,9 +121,6 @@ int drm_fb_helper_setcolreg(unsigned regno, void drm_fb_helper_restore(void); void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height); -void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, - uint32_t depth); - int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); -- cgit v1.2.3 From 0735ac1f2551d9f9d356126aaf3b1110150918e6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 7 Jan 2011 14:48:57 +1100 Subject: hwrng: via_rng - Fix asm constraints The inline asm to invoke xstore did not specify the constraints correctly. In particular, dx/di should have been marked as output registers as well as input as they're modified by xstore. Thanks to Mario Holbe for creating this patch and testing it. Tested-by: Mario 'BitKoenig' Holbe Signed-off-by: Herbert Xu --- drivers/char/hw_random/via-rng.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 794aacb715c1..7f86666bb393 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -81,8 +81,7 @@ static inline u32 xstore(u32 *addr, u32 edx_in) ts_state = irq_ts_save(); asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" - :"=m"(*addr), "=a"(eax_out) - :"D"(addr), "d"(edx_in)); + : "=m" (*addr), "=a" (eax_out), "+d" (edx_in), "+D" (addr)); irq_ts_restore(ts_state); return eax_out; -- cgit v1.2.3 From 21493088733e6e09dac6f54595a1b6b8ab1e68fd Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 7 Jan 2011 14:52:00 +1100 Subject: crypto: padlock - Move padlock.h into include/crypto This patch moves padlock.h from drivers/crypto into include/crypto so that it may be used by the via-rng driver. Signed-off-by: Herbert Xu --- drivers/crypto/padlock-aes.c | 2 +- drivers/crypto/padlock-sha.c | 8 +------- drivers/crypto/padlock.h | 23 ----------------------- include/crypto/padlock.h | 29 +++++++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 drivers/crypto/padlock.h create mode 100644 include/crypto/padlock.h (limited to 'drivers') diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 2e992bc8015b..2e56508754d0 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include "padlock.h" /* * Number of data blocks actually fetched for each xcrypt insn. diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index d3a27e0119bc..adf075b6b9a8 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -22,13 +23,6 @@ #include #include #include -#include "padlock.h" - -#ifdef CONFIG_64BIT -#define STACK_ALIGN 16 -#else -#define STACK_ALIGN 4 -#endif struct padlock_sha_desc { struct shash_desc fallback; diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h deleted file mode 100644 index b728e4518bd1..000000000000 --- a/drivers/crypto/padlock.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Driver for VIA PadLock - * - * Copyright (c) 2004 Michal Ludvig - * - * 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 _CRYPTO_PADLOCK_H -#define _CRYPTO_PADLOCK_H - -#define PADLOCK_ALIGNMENT 16 - -#define PFX "padlock: " - -#define PADLOCK_CRA_PRIORITY 300 -#define PADLOCK_COMPOSITE_PRIORITY 400 - -#endif /* _CRYPTO_PADLOCK_H */ diff --git a/include/crypto/padlock.h b/include/crypto/padlock.h new file mode 100644 index 000000000000..d2cfa2ef49e8 --- /dev/null +++ b/include/crypto/padlock.h @@ -0,0 +1,29 @@ +/* + * Driver for VIA PadLock + * + * Copyright (c) 2004 Michal Ludvig + * + * 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 _CRYPTO_PADLOCK_H +#define _CRYPTO_PADLOCK_H + +#define PADLOCK_ALIGNMENT 16 + +#define PFX KBUILD_MODNAME ": " + +#define PADLOCK_CRA_PRIORITY 300 +#define PADLOCK_COMPOSITE_PRIORITY 400 + +#ifdef CONFIG_64BIT +#define STACK_ALIGN 16 +#else +#define STACK_ALIGN 4 +#endif + +#endif /* _CRYPTO_PADLOCK_H */ -- cgit v1.2.3 From 55db8387a5e8d07407f0b7c6b2526417a2bc6243 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 7 Jan 2011 14:55:06 +1100 Subject: hwrng: via_rng - Fix memory scribbling on some CPUs It has been reported that on at least one Nano CPU the xstore instruction will write as many as 16 bytes of data to the output buffer. This causes memory corruption as we use rng->priv which is only 4-8 bytes long. This patch fixes this by using an intermediate buffer on the stack with at least 16 bytes and aligned to a 16-byte boundary. The problem was observed on the following processor: processor : 0 vendor_id : CentaurHauls cpu family : 6 model : 15 model name : VIA Nano processor U2250 (1.6GHz Capable) stepping : 3 cpu MHz : 1600.000 cache size : 1024 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 10 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush acpi mmx fxsr sse sse2 ss tm syscall nx lm constant_tsc up rep_good pni monitor vmx est tm2 ssse3 cx16 xtpr rng rng_en ace ace_en ace2 phe phe_en lahf_lm bogomips : 3192.08 clflush size : 64 cache_alignment : 128 address sizes : 36 bits physical, 48 bits virtual power management: Tested-by: Mario 'BitKoenig' Holbe Signed-off-by: Herbert Xu --- drivers/char/hw_random/via-rng.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 7f86666bb393..d0387a84eec1 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -24,6 +24,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include @@ -34,7 +35,6 @@ #include -#define PFX KBUILD_MODNAME ": " enum { @@ -89,8 +89,10 @@ static inline u32 xstore(u32 *addr, u32 edx_in) static int via_rng_data_present(struct hwrng *rng, int wait) { + char buf[16 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ + ((aligned(STACK_ALIGN))); + u32 *via_rng_datum = (u32 *)PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); u32 bytes_out; - u32 *via_rng_datum = (u32 *)(&rng->priv); int i; /* We choose the recommended 1-byte-per-instruction RNG rate, @@ -114,6 +116,7 @@ static int via_rng_data_present(struct hwrng *rng, int wait) break; udelay(10); } + rng->priv = *via_rng_datum; return bytes_out ? 1 : 0; } -- cgit v1.2.3 From e457acaed4c56a6831b82365e17e8f42f1ee129c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 4 Jan 2011 12:41:37 +1000 Subject: drm/nouveau: create grctx on the fly on all chipsets Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 10 ---------- drivers/gpu/drm/nouveau/nouveau_object.c | 3 ++- drivers/gpu/drm/nouveau/nv40_fifo.c | 1 - drivers/gpu/drm/nouveau/nv40_graph.c | 12 ++++++++++++ 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index a57a1d2f3a11..3960d66d7aba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -121,7 +121,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, uint32_t vram_handle, uint32_t gart_handle) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_channel *chan; unsigned long flags; @@ -202,15 +201,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, /* disable the fifo caches */ pfifo->reassign(dev, false); - /* Create a graphics context for new channel */ - if (dev_priv->card_type < NV_50) { - ret = pgraph->create_context(chan); - if (ret) { - nouveau_channel_put(&chan); - return ret; - } - } - /* Construct inital RAMFC for new channel */ ret = pfifo->create_context(chan); if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index d77b1fcd19d4..30b6544467ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -651,7 +651,8 @@ found: } break; case NVOBJ_ENGINE_GR: - if (dev_priv->card_type >= NV_50 && !chan->ramin_grctx) { + if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) || + (dev_priv->card_type < NV_20 && !chan->pgraph_ctx)) { struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index c86e4d4e9b96..49b9a35a9cd6 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -64,7 +64,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) NV_PFIFO_CACHE1_BIG_ENDIAN | #endif 0x30000000 /* no idea.. */); - nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4); nv_wi32(dev, fc + 60, 0x0001FFFF); /* enable the fifo dma operation */ diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 0618846a97ce..19ef92a0375a 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -62,6 +62,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; struct nouveau_grctx ctx = {}; + unsigned long flags; int ret; ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16, @@ -76,6 +77,17 @@ nv40_graph_create_context(struct nouveau_channel *chan) nv40_grctx_init(&ctx); nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst); + + /* init grctx pointer in ramfc, and on PFIFO if channel is + * already active there + */ + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); + nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4); + nv_mask(dev, 0x002500, 0x00000001, 0x00000000); + if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id) + nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4); + nv_mask(dev, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); return 0; } -- cgit v1.2.3 From 3313e3d4333ccbf8bd7c816775cfe9aca623bd8a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 18:49:34 -0500 Subject: drm/radeon/kms: add pcie get/set lane support for r6xx/r7xx/evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r300.c | 5 +- drivers/gpu/drm/radeon/r600.c | 118 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 8 +++ drivers/gpu/drm/radeon/radeon_asic.c | 14 ++--- drivers/gpu/drm/radeon/radeon_asic.h | 2 + drivers/gpu/drm/radeon/radeon_reg.h | 9 +++ 6 files changed, 145 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 23fee54c3b75..fae5e709f270 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -558,10 +558,7 @@ int rv370_get_pcie_lanes(struct radeon_device *rdev) /* FIXME wait for idle */ - if (rdev->family < CHIP_R600) - link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); - else - link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL); switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) { case RADEON_PCIE_LC_LINK_WIDTH_X0: diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 279794c391e9..60ad8c03081a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3531,3 +3531,121 @@ void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) } else WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); } + +void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes) +{ + u32 link_width_cntl, mask, target_reg; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + /* FIXME wait for idle */ + + switch (lanes) { + case 0: + mask = RADEON_PCIE_LC_LINK_WIDTH_X0; + break; + case 1: + mask = RADEON_PCIE_LC_LINK_WIDTH_X1; + break; + case 2: + mask = RADEON_PCIE_LC_LINK_WIDTH_X2; + break; + case 4: + mask = RADEON_PCIE_LC_LINK_WIDTH_X4; + break; + case 8: + mask = RADEON_PCIE_LC_LINK_WIDTH_X8; + break; + case 12: + mask = RADEON_PCIE_LC_LINK_WIDTH_X12; + break; + case 16: + default: + mask = RADEON_PCIE_LC_LINK_WIDTH_X16; + break; + } + + link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return; + + if (link_width_cntl & R600_PCIE_LC_UPCONFIGURE_DIS) + return; + + link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK | + RADEON_PCIE_LC_RECONFIG_NOW | + R600_PCIE_LC_RENEGOTIATE_EN | + R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE); + link_width_cntl |= mask; + + WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + + /* some northbridges can renegotiate the link rather than requiring + * a complete re-config. + * e.g., AMD 780/790 northbridges (pci ids: 0x5956, 0x5957, 0x5958, etc.) + */ + if (link_width_cntl & R600_PCIE_LC_RENEGOTIATION_SUPPORT) + link_width_cntl |= R600_PCIE_LC_RENEGOTIATE_EN | R600_PCIE_LC_UPCONFIGURE_SUPPORT; + else + link_width_cntl |= R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE; + + WREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl | + RADEON_PCIE_LC_RECONFIG_NOW)); + + if (rdev->family >= CHIP_RV770) + target_reg = R700_TARGET_AND_CURRENT_PROFILE_INDEX; + else + target_reg = R600_TARGET_AND_CURRENT_PROFILE_INDEX; + + /* wait for lane set to complete */ + link_width_cntl = RREG32(target_reg); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RREG32(target_reg); + +} + +int r600_get_pcie_lanes(struct radeon_device *rdev) +{ + u32 link_width_cntl; + + if (rdev->flags & RADEON_IS_IGP) + return 0; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return 0; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return 0; + + /* FIXME wait for idle */ + + link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) { + case RADEON_PCIE_LC_LINK_WIDTH_X0: + return 0; + case RADEON_PCIE_LC_LINK_WIDTH_X1: + return 1; + case RADEON_PCIE_LC_LINK_WIDTH_X2: + return 2; + case RADEON_PCIE_LC_LINK_WIDTH_X4: + return 4; + case RADEON_PCIE_LC_LINK_WIDTH_X8: + return 8; + case RADEON_PCIE_LC_LINK_WIDTH_X16: + default: + return 16; + } +} + diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index aff8080026a1..e9fb64c1e20b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1317,6 +1317,14 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); (rdev->family == CHIP_RV410) || \ (rdev->family == CHIP_RS400) || \ (rdev->family == CHIP_RS480)) +#define ASIC_IS_X2(rdev) ((rdev->ddev->pdev->device == 0x9441) || \ + (rdev->ddev->pdev->device == 0x9443) || \ + (rdev->ddev->pdev->device == 0x944B) || \ + (rdev->ddev->pdev->device == 0x9506) || \ + (rdev->ddev->pdev->device == 0x9509) || \ + (rdev->ddev->pdev->device == 0x950F) || \ + (rdev->ddev->pdev->device == 0x689C) || \ + (rdev->ddev->pdev->device == 0x689D)) #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) #define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600) || \ (rdev->family == CHIP_RS690) || \ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 3d73fe484f42..53c62404795d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -94,7 +94,7 @@ static void radeon_register_accessor_init(struct radeon_device *rdev) rdev->mc_rreg = &rs600_mc_rreg; rdev->mc_wreg = &rs600_mc_wreg; } - if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_RV740)) { + if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_HEMLOCK)) { rdev->pciep_rreg = &r600_pciep_rreg; rdev->pciep_wreg = &r600_pciep_wreg; } @@ -631,8 +631,8 @@ static struct radeon_asic r600_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = NULL, + .get_pcie_lanes = &r600_get_pcie_lanes, + .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, @@ -725,8 +725,8 @@ static struct radeon_asic rv770_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = &rv370_get_pcie_lanes, - .set_pcie_lanes = NULL, + .get_pcie_lanes = &r600_get_pcie_lanes, + .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = &radeon_atom_set_clock_gating, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, @@ -772,8 +772,8 @@ static struct radeon_asic evergreen_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, - .get_pcie_lanes = NULL, - .set_pcie_lanes = NULL, + .get_pcie_lanes = &r600_get_pcie_lanes, + .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, .clear_surface_reg = r600_clear_surface_reg, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 4970eda1bd41..9ac71b8d1b9d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -284,6 +284,8 @@ extern void r600_pm_misc(struct radeon_device *rdev); extern void r600_pm_init_profile(struct radeon_device *rdev); extern void rs780_pm_init_profile(struct radeon_device *rdev); extern void r600_pm_get_dynpm_state(struct radeon_device *rdev); +extern void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes); +extern int r600_get_pcie_lanes(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 0a310b7f71c3..3369ce984af1 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -320,6 +320,15 @@ # define RADEON_PCIE_LC_RECONFIG_NOW (1 << 8) # define RADEON_PCIE_LC_RECONFIG_LATER (1 << 9) # define RADEON_PCIE_LC_SHORT_RECONFIG_EN (1 << 10) +# define R600_PCIE_LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define R600_PCIE_LC_RENEGOTIATION_SUPPORT (1 << 9) +# define R600_PCIE_LC_RENEGOTIATE_EN (1 << 10) +# define R600_PCIE_LC_SHORT_RECONFIG_EN (1 << 11) +# define R600_PCIE_LC_UPCONFIGURE_SUPPORT (1 << 12) +# define R600_PCIE_LC_UPCONFIGURE_DIS (1 << 13) + +#define R600_TARGET_AND_CURRENT_PROFILE_INDEX 0x70c +#define R700_TARGET_AND_CURRENT_PROFILE_INDEX 0x66c #define RADEON_CACHE_CNTL 0x1724 #define RADEON_CACHE_LINE 0x0f0c /* PCI */ -- cgit v1.2.3 From 9e46a48df24f9698b34d28385b320c529851e5f7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 18:49:35 -0500 Subject: drm/radeon/kms: add support for gen2 pcie link speeds Supported on rv6xx/r7xx/evergreen. Cards come up in gen1 mode. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 53 +++++++++++++++++++ drivers/gpu/drm/radeon/evergreend.h | 38 ++++++++++++++ drivers/gpu/drm/radeon/r600.c | 102 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600d.h | 39 ++++++++++++++ drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/rv770.c | 76 +++++++++++++++++++++++++++ drivers/gpu/drm/radeon/rv770d.h | 38 ++++++++++++++ 7 files changed, 348 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index eaf4fba90b72..11344c76e216 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -39,6 +39,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +static void evergreen_pcie_gen2_enable(struct radeon_device *rdev); void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) { @@ -2767,6 +2768,9 @@ static int evergreen_startup(struct radeon_device *rdev) { int r; + /* enable pcie gen2 link */ + evergreen_pcie_gen2_enable(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -3049,3 +3053,52 @@ void evergreen_fini(struct radeon_device *rdev) rdev->bios = NULL; radeon_dummy_page_fini(rdev); } + +static void evergreen_pcie_gen2_enable(struct radeon_device *rdev) +{ + u32 link_width_cntl, speed_cntl; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) || + (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) { + + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_GEN2_EN_STRAP; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + } else { + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */ + if (1) + link_width_cntl |= LC_UPCONFIGURE_DIS; + else + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } +} diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 94140e142abb..b8da323f15c8 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -581,6 +581,44 @@ # define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) # define DC_HPDx_EN (1 << 28) +/* PCIE link stuff */ +#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ +#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ +# define LC_LINK_WIDTH_SHIFT 0 +# define LC_LINK_WIDTH_MASK 0x7 +# define LC_LINK_WIDTH_X0 0 +# define LC_LINK_WIDTH_X1 1 +# define LC_LINK_WIDTH_X2 2 +# define LC_LINK_WIDTH_X4 3 +# define LC_LINK_WIDTH_X8 4 +# define LC_LINK_WIDTH_X16 6 +# define LC_LINK_WIDTH_RD_SHIFT 4 +# define LC_LINK_WIDTH_RD_MASK 0x70 +# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define LC_RECONFIG_NOW (1 << 8) +# define LC_RENEGOTIATION_SUPPORT (1 << 9) +# define LC_RENEGOTIATE_EN (1 << 10) +# define LC_SHORT_RECONFIG_EN (1 << 11) +# define LC_UPCONFIGURE_SUPPORT (1 << 12) +# define LC_UPCONFIGURE_DIS (1 << 13) +#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ +# define LC_GEN2_EN_STRAP (1 << 0) +# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) +# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) +# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 +# define LC_CURRENT_DATA_RATE (1 << 11) +# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) +# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) +# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) +# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) +#define MM_CFGREGS_CNTL 0x544c +# define MM_WR_TO_CFG_EN (1 << 3) +#define LINK_CNTL2 0x88 /* F0 */ +# define TARGET_LINK_SPEED_MASK (0xf << 0) +# define SELECTABLE_DEEMPHASIS (1 << 6) + /* * PM4 */ diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 60ad8c03081a..6b50716267c0 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -94,6 +94,7 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev); void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +static void r600_pcie_gen2_enable(struct radeon_device *rdev); /* get temperature in millidegrees */ u32 rv6xx_get_temp(struct radeon_device *rdev) @@ -2379,6 +2380,9 @@ int r600_startup(struct radeon_device *rdev) { int r; + /* enable pcie gen2 link */ + r600_pcie_gen2_enable(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -3649,3 +3653,101 @@ int r600_get_pcie_lanes(struct radeon_device *rdev) } } +static void r600_pcie_gen2_enable(struct radeon_device *rdev) +{ + u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp; + u16 link_cntl2; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + /* only RV6xx+ chips are supported */ + if (rdev->family <= CHIP_R600) + return; + + /* 55 nm r6xx asics */ + if ((rdev->family == CHIP_RV670) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RV635)) { + /* advertise upconfig capability */ + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + if (link_width_cntl & LC_RENEGOTIATION_SUPPORT) { + lanes = (link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT; + link_width_cntl &= ~(LC_LINK_WIDTH_MASK | + LC_RECONFIG_ARC_MISSING_ESCAPE); + link_width_cntl |= lanes | LC_RECONFIG_NOW | LC_RENEGOTIATE_EN; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } else { + link_width_cntl |= LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } + } + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) && + (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) { + + /* 55 nm r6xx asics */ + if ((rdev->family == CHIP_RV670) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RV635)) { + WREG32(MM_CFGREGS_CNTL, 0x8); + link_cntl2 = RREG32(0x4088); + WREG32(MM_CFGREGS_CNTL, 0); + /* not supported yet */ + if (link_cntl2 & SELECTABLE_DEEMPHASIS) + return; + } + + speed_cntl &= ~LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK; + speed_cntl |= (0x3 << LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT); + speed_cntl &= ~LC_VOLTAGE_TIMER_SEL_MASK; + speed_cntl &= ~LC_FORCE_DIS_HW_SPEED_CHANGE; + speed_cntl |= LC_FORCE_EN_HW_SPEED_CHANGE; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + tmp = RREG32(0x541c); + WREG32(0x541c, tmp | 0x8); + WREG32(MM_CFGREGS_CNTL, MM_WR_TO_CFG_EN); + link_cntl2 = RREG16(0x4088); + link_cntl2 &= ~TARGET_LINK_SPEED_MASK; + link_cntl2 |= 0x2; + WREG16(0x4088, link_cntl2); + WREG32(MM_CFGREGS_CNTL, 0); + + if ((rdev->family == CHIP_RV670) || + (rdev->family == CHIP_RV620) || + (rdev->family == CHIP_RV635)) { + training_cntl = RREG32_PCIE_P(PCIE_LC_TRAINING_CNTL); + training_cntl &= ~LC_POINT_7_PLUS_EN; + WREG32_PCIE_P(PCIE_LC_TRAINING_CNTL, training_cntl); + } else { + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + } + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_GEN2_EN_STRAP; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + } else { + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */ + if (1) + link_width_cntl |= LC_UPCONFIGURE_DIS; + else + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } +} diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index c89cfa8e0c05..a5d898b4bad2 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -737,6 +737,45 @@ # define DxGRPH_PFLIP_INT_MASK (1 << 0) # define DxGRPH_PFLIP_INT_TYPE (1 << 8) +/* PCIE link stuff */ +#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ +# define LC_POINT_7_PLUS_EN (1 << 6) +#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ +# define LC_LINK_WIDTH_SHIFT 0 +# define LC_LINK_WIDTH_MASK 0x7 +# define LC_LINK_WIDTH_X0 0 +# define LC_LINK_WIDTH_X1 1 +# define LC_LINK_WIDTH_X2 2 +# define LC_LINK_WIDTH_X4 3 +# define LC_LINK_WIDTH_X8 4 +# define LC_LINK_WIDTH_X16 6 +# define LC_LINK_WIDTH_RD_SHIFT 4 +# define LC_LINK_WIDTH_RD_MASK 0x70 +# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define LC_RECONFIG_NOW (1 << 8) +# define LC_RENEGOTIATION_SUPPORT (1 << 9) +# define LC_RENEGOTIATE_EN (1 << 10) +# define LC_SHORT_RECONFIG_EN (1 << 11) +# define LC_UPCONFIGURE_SUPPORT (1 << 12) +# define LC_UPCONFIGURE_DIS (1 << 13) +#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ +# define LC_GEN2_EN_STRAP (1 << 0) +# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) +# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) +# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 +# define LC_CURRENT_DATA_RATE (1 << 11) +# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) +# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) +# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) +# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) +#define MM_CFGREGS_CNTL 0x544c +# define MM_WR_TO_CFG_EN (1 << 3) +#define LINK_CNTL2 0x88 /* F0 */ +# define TARGET_LINK_SPEED_MASK (0xf << 0) +# define SELECTABLE_DEEMPHASIS (1 << 6) + /* * PM4 */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e9fb64c1e20b..3e635c651900 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1244,6 +1244,8 @@ static inline void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v) */ #define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg)) #define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg)) +#define RREG16(reg) readw(((void __iomem *)rdev->rmmio) + (reg)) +#define WREG16(reg, v) writew(v, ((void __iomem *)rdev->rmmio) + (reg)) #define RREG32(reg) r100_mm_rreg(rdev, (reg)) #define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", r100_mm_rreg(rdev, (reg))) #define WREG32(reg, v) r100_mm_wreg(rdev, (reg), (v)) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 645aa1fd7611..3a264aa3a79a 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -41,6 +41,7 @@ static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +static void rv770_pcie_gen2_enable(struct radeon_device *rdev); u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { @@ -1124,6 +1125,9 @@ static int rv770_startup(struct radeon_device *rdev) { int r; + /* enable pcie gen2 link */ + rv770_pcie_gen2_enable(rdev); + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { r = r600_init_microcode(rdev); if (r) { @@ -1362,3 +1366,75 @@ void rv770_fini(struct radeon_device *rdev) rdev->bios = NULL; radeon_dummy_page_fini(rdev); } + +static void rv770_pcie_gen2_enable(struct radeon_device *rdev) +{ + u32 link_width_cntl, lanes, speed_cntl, tmp; + u16 link_cntl2; + + if (rdev->flags & RADEON_IS_IGP) + return; + + if (!(rdev->flags & RADEON_IS_PCIE)) + return; + + /* x2 cards have a special sequence */ + if (ASIC_IS_X2(rdev)) + return; + + /* advertise upconfig capability */ + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + if (link_width_cntl & LC_RENEGOTIATION_SUPPORT) { + lanes = (link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT; + link_width_cntl &= ~(LC_LINK_WIDTH_MASK | + LC_RECONFIG_ARC_MISSING_ESCAPE); + link_width_cntl |= lanes | LC_RECONFIG_NOW | + LC_RENEGOTIATE_EN | LC_UPCONFIGURE_SUPPORT; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } else { + link_width_cntl |= LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + if ((speed_cntl & LC_OTHER_SIDE_EVER_SENT_GEN2) && + (speed_cntl & LC_OTHER_SIDE_SUPPORTS_GEN2)) { + + tmp = RREG32(0x541c); + WREG32(0x541c, tmp | 0x8); + WREG32(MM_CFGREGS_CNTL, MM_WR_TO_CFG_EN); + link_cntl2 = RREG16(0x4088); + link_cntl2 &= ~TARGET_LINK_SPEED_MASK; + link_cntl2 |= 0x2; + WREG16(0x4088, link_cntl2); + WREG32(MM_CFGREGS_CNTL, 0); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_TARGET_LINK_SPEED_OVERRIDE_EN; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl &= ~LC_CLR_FAILED_SPD_CHANGE_CNT; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + speed_cntl = RREG32_PCIE_P(PCIE_LC_SPEED_CNTL); + speed_cntl |= LC_GEN2_EN_STRAP; + WREG32_PCIE_P(PCIE_LC_SPEED_CNTL, speed_cntl); + + } else { + link_width_cntl = RREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL); + /* XXX: only disable it if gen1 bridge vendor == 0x111d or 0x1106 */ + if (1) + link_width_cntl |= LC_UPCONFIGURE_DIS; + else + link_width_cntl &= ~LC_UPCONFIGURE_DIS; + WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + } +} diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index fc77e1e1a179..abc8cf5a3672 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -360,4 +360,42 @@ #define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c #define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c +/* PCIE link stuff */ +#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */ +#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */ +# define LC_LINK_WIDTH_SHIFT 0 +# define LC_LINK_WIDTH_MASK 0x7 +# define LC_LINK_WIDTH_X0 0 +# define LC_LINK_WIDTH_X1 1 +# define LC_LINK_WIDTH_X2 2 +# define LC_LINK_WIDTH_X4 3 +# define LC_LINK_WIDTH_X8 4 +# define LC_LINK_WIDTH_X16 6 +# define LC_LINK_WIDTH_RD_SHIFT 4 +# define LC_LINK_WIDTH_RD_MASK 0x70 +# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7) +# define LC_RECONFIG_NOW (1 << 8) +# define LC_RENEGOTIATION_SUPPORT (1 << 9) +# define LC_RENEGOTIATE_EN (1 << 10) +# define LC_SHORT_RECONFIG_EN (1 << 11) +# define LC_UPCONFIGURE_SUPPORT (1 << 12) +# define LC_UPCONFIGURE_DIS (1 << 13) +#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */ +# define LC_GEN2_EN_STRAP (1 << 0) +# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1) +# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5) +# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8) +# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3 +# define LC_CURRENT_DATA_RATE (1 << 11) +# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14) +# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21) +# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23) +# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24) +#define MM_CFGREGS_CNTL 0x544c +# define MM_WR_TO_CFG_EN (1 << 3) +#define LINK_CNTL2 0x88 /* F0 */ +# define TARGET_LINK_SPEED_MASK (0xf << 0) +# define SELECTABLE_DEEMPHASIS (1 << 6) + #endif -- cgit v1.2.3 From c46cb4dabddeda851d0d5faee64484f3783053e3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 19:12:37 -0500 Subject: drm/radeon/kms: set the MSB of the HDP slice size Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 11344c76e216..b5bc7d038fd9 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1147,7 +1147,7 @@ static void evergreen_mc_program(struct radeon_device *rdev) tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8)); - WREG32(HDP_NONSURFACE_INFO, (2 << 7)); + WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30)); WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF); if (rdev->flags & RADEON_IS_AGP) { WREG32(MC_VM_AGP_TOP, rdev->mc.gtt_end >> 16); -- cgit v1.2.3 From 32171d2297daa2fe90d6ef41c5424ca9ac5bd797 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 19:13:32 -0500 Subject: drm/radeon/kms: fix some typos in evergreen pm4 defines Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreend.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index b8da323f15c8..36d32d83d866 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -648,7 +648,7 @@ #define PACKET3_NOP 0x10 #define PACKET3_SET_BASE 0x11 #define PACKET3_CLEAR_STATE 0x12 -#define PACKET3_INDIRECT_BUFFER_SIZE 0x13 +#define PACKET3_INDEX_BUFFER_SIZE 0x13 #define PACKET3_DISPATCH_DIRECT 0x15 #define PACKET3_DISPATCH_INDIRECT 0x16 #define PACKET3_INDIRECT_BUFFER_END 0x17 @@ -689,14 +689,14 @@ # define PACKET3_CB8_DEST_BASE_ENA (1 << 15) # define PACKET3_CB9_DEST_BASE_ENA (1 << 16) # define PACKET3_CB10_DEST_BASE_ENA (1 << 17) -# define PACKET3_CB11_DEST_BASE_ENA (1 << 17) +# define PACKET3_CB11_DEST_BASE_ENA (1 << 18) # define PACKET3_FULL_CACHE_ENA (1 << 20) # define PACKET3_TC_ACTION_ENA (1 << 23) # define PACKET3_VC_ACTION_ENA (1 << 24) # define PACKET3_CB_ACTION_ENA (1 << 25) # define PACKET3_DB_ACTION_ENA (1 << 26) # define PACKET3_SH_ACTION_ENA (1 << 27) -# define PACKET3_SMX_ACTION_ENA (1 << 28) +# define PACKET3_SX_ACTION_ENA (1 << 28) #define PACKET3_ME_INITIALIZE 0x44 #define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16) #define PACKET3_COND_WRITE 0x45 -- cgit v1.2.3 From 633b91643f50779897bcab5e50d08a4fe4ba9f13 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:11 -0500 Subject: drm/radeon/kms: clean up ASIC_IS_DCE41() macro only fusion asics are dce4.1 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 3 ++- drivers/gpu/drm/radeon/radeon_encoders.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3e635c651900..396e30703e7a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1335,7 +1335,8 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) -#define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM)) +#define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM) && \ + (rdev->flags & RADEON_IS_IGP)) /* * BIOS helpers. diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 55b84b8e6b29..c83ad890e4d2 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1329,7 +1329,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) switch (mode) { case DRM_MODE_DPMS_ON: default: - if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) + if (ASIC_IS_DCE41(rdev)) action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT; else action = ATOM_ENABLE; @@ -1337,7 +1337,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) + if (ASIC_IS_DCE41(rdev)) action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT; else action = ATOM_DISABLE; @@ -1663,7 +1663,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, } if (ext_encoder) { - if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) { + if (ASIC_IS_DCE41(rdev)) { atombios_external_encoder_setup(encoder, ext_encoder, EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); atombios_external_encoder_setup(encoder, ext_encoder, -- cgit v1.2.3 From 1fe183050f71ba183fe2d693bbef5fa605723043 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:12 -0500 Subject: drm/radeon/kms: add NI chip families Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_device.c | 3 +++ drivers/gpu/drm/radeon/radeon_family.h | 3 +++ 3 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 396e30703e7a..73730fd1d0af 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1337,6 +1337,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) #define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM) && \ (rdev->flags & RADEON_IS_IGP)) +#define ASIC_IS_DCE5(rdev) ((rdev->family >= CHIP_BARTS)) /* * BIOS helpers. diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 44cf0d707006..e35343007229 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -82,6 +82,9 @@ static const char radeon_family_name[][16] = { "CYPRESS", "HEMLOCK", "PALM", + "BARTS", + "TURKS", + "CAICOS", "LAST", }; diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h index 4c222d5437d1..1ca55eb09ad3 100644 --- a/drivers/gpu/drm/radeon/radeon_family.h +++ b/drivers/gpu/drm/radeon/radeon_family.h @@ -81,6 +81,9 @@ enum radeon_family { CHIP_CYPRESS, CHIP_HEMLOCK, CHIP_PALM, + CHIP_BARTS, + CHIP_TURKS, + CHIP_CAICOS, CHIP_LAST, }; -- cgit v1.2.3 From 936b27cce8fdb8ca50a593714963862586285094 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:13 -0500 Subject: drm/radeon/kms: update display watermark calculations for DCE5 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b5bc7d038fd9..9c990c3f877f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -401,16 +401,28 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, case 0: case 4: default: - return 3840 * 2; + if (ASIC_IS_DCE5(rdev)) + return 4096 * 2; + else + return 3840 * 2; case 1: case 5: - return 5760 * 2; + if (ASIC_IS_DCE5(rdev)) + return 6144 * 2; + else + return 5760 * 2; case 2: case 6: - return 7680 * 2; + if (ASIC_IS_DCE5(rdev)) + return 8192 * 2; + else + return 7680 * 2; case 3: case 7: - return 1920 * 2; + if (ASIC_IS_DCE5(rdev)) + return 2048 * 2; + else + return 1920 * 2; } } -- cgit v1.2.3 From 881dd74ea731067f8fc81608e3a8914fdd66bc6d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:14 -0500 Subject: drm/radeon/kms: DCE5 supports 16k display surfaces Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index acebbc76c2f9..30d867c85825 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1119,7 +1119,10 @@ int radeon_modeset_init(struct radeon_device *rdev) rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs; - if (ASIC_IS_AVIVO(rdev)) { + if (ASIC_IS_DCE5(rdev)) { + rdev->ddev->mode_config.max_width = 16384; + rdev->ddev->mode_config.max_height = 16384; + } else if (ASIC_IS_AVIVO(rdev)) { rdev->ddev->mode_config.max_width = 8192; rdev->ddev->mode_config.max_height = 8192; } else { -- cgit v1.2.3 From f82b3ddc5fac044a28ab841bfd4ae48e2e43a21b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:15 -0500 Subject: drm/radeon/kms: DCE5 atom SetPixelClock updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 31 ++++++++++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_atombios.c | 25 +++++++++++++++++++------ 2 files changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9fbabaa6ee44..b3e5e7549008 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -673,9 +673,14 @@ union set_pixel_clock { PIXEL_CLOCK_PARAMETERS_V2 v2; PIXEL_CLOCK_PARAMETERS_V3 v3; PIXEL_CLOCK_PARAMETERS_V5 v5; + PIXEL_CLOCK_PARAMETERS_V6 v6; }; -static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) +/* on DCE5, make sure the voltage is high enough to support the + * required disp clk. + */ +static void atombios_crtc_set_dcpll(struct drm_crtc *crtc, + u32 dispclk) { struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; @@ -698,9 +703,16 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) * SetPixelClock provides the dividers */ args.v5.ucCRTC = ATOM_CRTC_INVALID; - args.v5.usPixelClock = rdev->clock.default_dispclk; + args.v5.usPixelClock = dispclk; args.v5.ucPpll = ATOM_DCPLL; break; + case 6: + /* if the default dcpll clock is specified, + * SetPixelClock provides the dividers + */ + args.v6.ulDispEngClkFreq = dispclk; + args.v6.ucPpll = ATOM_DCPLL; + break; default: DRM_ERROR("Unknown table version %d %d\n", frev, crev); return; @@ -784,6 +796,18 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc, args.v5.ucEncoderMode = encoder_mode; args.v5.ucPpll = pll_id; break; + case 6: + args.v6.ulCrtcPclkFreq.ucCRTC = crtc_id; + args.v6.ulCrtcPclkFreq.ulPixelClock = cpu_to_le32(clock / 10); + args.v6.ucRefDiv = ref_div; + args.v6.usFbDiv = cpu_to_le16(fb_div); + args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); + args.v6.ucPostDiv = post_div; + args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ + args.v6.ucTransmitterID = encoder_id; + args.v6.ucEncoderMode = encoder_mode; + args.v6.ucPpll = pll_id; + break; default: DRM_ERROR("Unknown table version %d %d\n", frev, crev); return; @@ -1377,7 +1401,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, rdev->clock.default_dispclk); if (ss_enabled) atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss); - atombios_crtc_set_dcpll(crtc); + /* XXX: DCE5, make sure voltage, dispclk is high enough */ + atombios_crtc_set_dcpll(crtc, rdev->clock.default_dispclk); if (ss_enabled) atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss); } diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index e4f7e3e82a50..11573d085e61 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1086,6 +1086,7 @@ union firmware_info { ATOM_FIRMWARE_INFO_V1_3 info_13; ATOM_FIRMWARE_INFO_V1_4 info_14; ATOM_FIRMWARE_INFO_V2_1 info_21; + ATOM_FIRMWARE_INFO_V2_2 info_22; }; bool radeon_atom_get_clock_info(struct drm_device *dev) @@ -1160,8 +1161,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) *p2pll = *p1pll; /* system clock */ - spll->reference_freq = - le16_to_cpu(firmware_info->info.usReferenceClock); + if (ASIC_IS_DCE4(rdev)) + spll->reference_freq = + le16_to_cpu(firmware_info->info_21.usCoreReferenceClock); + else + spll->reference_freq = + le16_to_cpu(firmware_info->info.usReferenceClock); spll->reference_div = 0; spll->pll_out_min = @@ -1183,8 +1188,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input); /* memory clock */ - mpll->reference_freq = - le16_to_cpu(firmware_info->info.usReferenceClock); + if (ASIC_IS_DCE4(rdev)) + mpll->reference_freq = + le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock); + else + mpll->reference_freq = + le16_to_cpu(firmware_info->info.usReferenceClock); mpll->reference_div = 0; mpll->pll_out_min = @@ -1213,8 +1222,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) if (ASIC_IS_DCE4(rdev)) { rdev->clock.default_dispclk = le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq); - if (rdev->clock.default_dispclk == 0) - rdev->clock.default_dispclk = 60000; /* 600 Mhz */ + if (rdev->clock.default_dispclk == 0) { + if (ASIC_IS_DCE5(rdev)) + rdev->clock.default_dispclk = 54000; /* 540 Mhz */ + else + rdev->clock.default_dispclk = 60000; /* 600 Mhz */ + } rdev->clock.dp_extclk = le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq); } -- cgit v1.2.3 From a572eaa3726968555451ba301ff8c61e90e8c278 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:16 -0500 Subject: drm/radeon/kms: DCE5 atom spread spectrum updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index b3e5e7549008..b0ab185b86f6 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -403,6 +403,7 @@ union atom_enable_ss { ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; + ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; }; static void atombios_crtc_program_ss(struct drm_crtc *crtc, @@ -417,7 +418,30 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc, memset(&args, 0, sizeof(args)); - if (ASIC_IS_DCE4(rdev)) { + if (ASIC_IS_DCE5(rdev)) { + args.v3.usSpreadSpectrumAmountFrac = 0; + args.v3.ucSpreadSpectrumType = ss->type; + switch (pll_id) { + case ATOM_PPLL1: + args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; + args.v3.usSpreadSpectrumAmount = ss->amount; + args.v3.usSpreadSpectrumStep = ss->step; + break; + case ATOM_PPLL2: + args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; + args.v3.usSpreadSpectrumAmount = ss->amount; + args.v3.usSpreadSpectrumStep = ss->step; + break; + case ATOM_DCPLL: + args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; + args.v3.usSpreadSpectrumAmount = 0; + args.v3.usSpreadSpectrumStep = 0; + break; + case ATOM_PPLL_INVALID: + return; + } + args.v2.ucEnable = enable; + } else if (ASIC_IS_DCE4(rdev)) { args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage); args.v2.ucSpreadSpectrumType = ss->type; switch (pll_id) { -- cgit v1.2.3 From a001182af807e2e0e1eb497dc5418d1220406d9b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:17 -0500 Subject: drm/radeon/kms: DCE5 atom transmitter control updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index c83ad890e4d2..76835b0397ab 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -712,7 +712,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) * - 2 DIG encoder blocks. * DIG1/2 can drive UNIPHY0/1/2 link A or link B * - * DCE 4.0 + * DCE 4.0/5.0 * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). * Supports up to 6 digital outputs * - 6 DIG encoder blocks. @@ -829,6 +829,7 @@ union dig_transmitter_control { DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; }; void @@ -923,10 +924,18 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); pll_id = radeon_crtc->pll_id; } - if (is_dp && rdev->clock.dp_extclk) - args.v3.acConfig.ucRefClkSource = 2; /* external src */ - else - args.v3.acConfig.ucRefClkSource = pll_id; + + if (ASIC_IS_DCE5(rdev)) { + if (is_dp && rdev->clock.dp_extclk) + args.v4.acConfig.ucRefClkSource = 3; /* external src */ + else + args.v4.acConfig.ucRefClkSource = pll_id; + } else { + if (is_dp && rdev->clock.dp_extclk) + args.v3.acConfig.ucRefClkSource = 2; /* external src */ + else + args.v3.acConfig.ucRefClkSource = pll_id; + } switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: -- cgit v1.2.3 From badbb57b93adda990b4e2420ddfdf834504a217e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:18 -0500 Subject: drm/radeon/kms: DCE5 atom dig encoder updates Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 76835b0397ab..989ba26135b8 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -743,6 +743,7 @@ union dig_encoder_control { DIG_ENCODER_CONTROL_PS_ALLOCATION v1; DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; + DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; }; void @@ -758,6 +759,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) uint8_t frev, crev; int dp_clock = 0; int dp_lane_count = 0; + int hpd_id = RADEON_HPD_NONE; if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -766,6 +768,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) dp_clock = dig_connector->dp_clock; dp_lane_count = dig_connector->dp_lane_count; + hpd_id = radeon_connector->hpd.hpd; } /* no dig encoder assigned */ @@ -790,19 +793,36 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); - if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dp_clock == 270000) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) || + (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) args.v1.ucLaneNum = dp_lane_count; - } else if (radeon_encoder->pixel_clock > 165000) + else if (radeon_encoder->pixel_clock > 165000) args.v1.ucLaneNum = 8; else args.v1.ucLaneNum = 4; - if (ASIC_IS_DCE4(rdev)) { + if (ASIC_IS_DCE5(rdev)) { + if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) || + (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) { + if (dp_clock == 270000) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; + else if (dp_clock == 540000) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; + } + args.v4.acConfig.ucDigSel = dig->dig_encoder; + args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR; + if (hpd_id == RADEON_HPD_NONE) + args.v4.ucHPD_ID = 0; + else + args.v4.ucHPD_ID = hpd_id + 1; + } else if (ASIC_IS_DCE4(rdev)) { + if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; args.v3.acConfig.ucDigSel = dig->dig_encoder; args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; } else { + if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; @@ -1538,6 +1558,7 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) struct radeon_encoder_atom_dig *dig; uint32_t dig_enc_in_use = 0; + /* DCE4/5 */ if (ASIC_IS_DCE4(rdev)) { dig = radeon_encoder->enc_priv; if (ASIC_IS_DCE41(rdev)) { -- cgit v1.2.3 From 69c74525c26a1b71116d9bd3a136bf1314a3e8cd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:19 -0500 Subject: drm/radeon/kms: dac dpms updates for DCE5 The DAC1OutputControl table was removed for DCE5. DAC1EncoderControl now handles everything. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 989ba26135b8..2e1d720fca06 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1227,6 +1227,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; int index = 0; bool is_dig = false; + bool is_dce5_dac = false; memset(&args, 0, sizeof(args)); @@ -1265,12 +1266,16 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) break; case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + if (ASIC_IS_DCE5(rdev)) + is_dce5_dac = true; + else { + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + } break; case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: @@ -1329,6 +1334,17 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); break; } + } else if (is_dce5_dac) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dac_setup(encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dac_setup(encoder, ATOM_DISABLE); + break; + } } else { switch (mode) { case DRM_MODE_DPMS_ON: -- cgit v1.2.3 From d07f4e83506712f31ad661415ea28d536a70a939 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:20 -0500 Subject: drm/radeon/kms: dvo dpms updates for DCE5 The DVOOutputControl table was removed for DCE5. DVOEncoderControl now handles everything. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 2e1d720fca06..3866c648423b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1228,6 +1228,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) int index = 0; bool is_dig = false; bool is_dce5_dac = false; + bool is_dce5_dvo = false; memset(&args, 0, sizeof(args)); @@ -1250,7 +1251,9 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - if (ASIC_IS_DCE3(rdev)) + if (ASIC_IS_DCE5(rdev)) + is_dce5_dvo = true; + else if (ASIC_IS_DCE3(rdev)) is_dig = true; else index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); @@ -1345,6 +1348,17 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) atombios_dac_setup(encoder, ATOM_DISABLE); break; } + } else if (is_dce5_dvo) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dvo_setup(encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dvo_setup(encoder, ATOM_DISABLE); + break; + } } else { switch (mode) { case DRM_MODE_DPMS_ON: -- cgit v1.2.3 From 36868bda88b92ce8a9aa8b3ee2e0d1e0de09cc19 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:21 -0500 Subject: drm/radeon/kms: parse DCE5 encoder caps when setting up encoders Needed to tell which DIG encoders are HBR2 capable for DP 1.2. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 44 +++++++++++++++++++++++++------- drivers/gpu/drm/radeon/radeon_encoders.c | 6 ++++- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 3 files changed, 41 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 11573d085e61..a2dfe257079c 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -37,7 +37,7 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, extern void radeon_link_encoder_connector(struct drm_device *dev); extern void radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, - uint32_t supported_device); + uint32_t supported_device, u16 caps); /* from radeon_connector.c */ extern void @@ -537,6 +537,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) u16 size, data_offset; u8 frev, crev; ATOM_CONNECTOR_OBJECT_TABLE *con_obj; + ATOM_ENCODER_OBJECT_TABLE *enc_obj; ATOM_OBJECT_TABLE *router_obj; ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; ATOM_OBJECT_HEADER *obj_header; @@ -561,6 +562,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *) (ctx->bios + data_offset + le16_to_cpu(obj_header->usConnectorObjectTableOffset)); + enc_obj = (ATOM_ENCODER_OBJECT_TABLE *) + (ctx->bios + data_offset + + le16_to_cpu(obj_header->usEncoderObjectTableOffset)); router_obj = (ATOM_OBJECT_TABLE *) (ctx->bios + data_offset + le16_to_cpu(obj_header->usRouterObjectTableOffset)); @@ -666,14 +670,35 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { - u16 encoder_obj = le16_to_cpu(path->usGraphicObjIds[j]); - - radeon_add_atom_encoder(dev, - encoder_obj, - le16_to_cpu - (path-> - usDeviceTag)); + for (k = 0; k < enc_obj->ucNumberOfObjects; k++) { + u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID); + if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) { + ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) + (ctx->bios + data_offset + + le16_to_cpu(enc_obj->asObjects[k].usRecordOffset)); + ATOM_ENCODER_CAP_RECORD *cap_record; + u16 caps = 0; + while (record->ucRecordType > 0 && + record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { + switch (record->ucRecordType) { + case ATOM_ENCODER_CAP_RECORD_TYPE: + cap_record =(ATOM_ENCODER_CAP_RECORD *) + record; + caps = le16_to_cpu(cap_record->usEncoderCap); + break; + } + record = (ATOM_COMMON_RECORD_HEADER *) + ((char *)record + record->ucRecordSize); + } + radeon_add_atom_encoder(dev, + encoder_obj, + le16_to_cpu + (path-> + usDeviceTag), + caps); + } + } } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) { for (k = 0; k < router_obj->ucNumberOfObjects; k++) { u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID); @@ -1007,7 +1032,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct radeon_get_encoder_enum(dev, (1 << i), dac), - (1 << i)); + (1 << i), + 0); else radeon_add_legacy_encoder(dev, radeon_get_encoder_enum(dev, diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3866c648423b..e7a948f60587 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -2046,7 +2046,10 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) } void -radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) +radeon_add_atom_encoder(struct drm_device *dev, + uint32_t encoder_enum, + uint32_t supported_device, + u16 caps) { struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; @@ -2089,6 +2092,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t radeon_encoder->rmx_type = RMX_OFF; radeon_encoder->underscan_type = UNDERSCAN_OFF; radeon_encoder->is_ext_encoder = false; + radeon_encoder->caps = caps; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_LVDS: diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index fd185f783a31..12bdeab91c86 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -379,6 +379,7 @@ struct radeon_encoder { int hdmi_audio_workaround; int hdmi_buffer_status; bool is_ext_encoder; + u16 caps; }; struct radeon_connector_atom_dig { -- cgit v1.2.3 From 4fddba1fd9df94caaa03956bf36e1a887a1c92a5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:22 -0500 Subject: drm/radeon/kms: handle NI thermal controller Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_atombios.c | 6 ++++++ drivers/gpu/drm/radeon/radeon_pm.c | 1 + 3 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 73730fd1d0af..5598f9559a64 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -739,6 +739,7 @@ enum radeon_int_thermal_type { THERMAL_TYPE_RV770, THERMAL_TYPE_EVERGREEN, THERMAL_TYPE_SUMO, + THERMAL_TYPE_NI, }; struct radeon_voltage { diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index a2dfe257079c..03f1c9a10ba4 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1891,6 +1891,7 @@ static const char *pp_lib_thermal_controller_names[] = { "Evergreen", "emc2103", "Sumo", + "Northern Islands", }; union power_info { @@ -2154,6 +2155,11 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO; + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_NI; } else if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || (controller->ucType == diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 0afd26ccccfa..7ad2e1a6991d 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -440,6 +440,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev, temp = rv770_get_temp(rdev); break; case THERMAL_TYPE_EVERGREEN: + case THERMAL_TYPE_NI: temp = evergreen_get_temp(rdev); break; case THERMAL_TYPE_SUMO: -- cgit v1.2.3 From c901bcddd09560b78f0a5f8081b86745cc553edf Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:23 -0500 Subject: drm/radeon/kms: add disabled vbios accessor for NI asics Some systems disable the vbios on secondary cards or cards that have been posted. This code re-enabled the vbios so the driver can load it. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_bios.c | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 8f2c7b50dcf5..1aba85cad1a8 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -131,6 +131,45 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) return true; } +static bool ni_read_disabled_bios(struct radeon_device *rdev) +{ + u32 bus_cntl; + u32 d1vga_control; + u32 d2vga_control; + u32 vga_render_control; + u32 rom_cntl; + bool r; + + bus_cntl = RREG32(R600_BUS_CNTL); + d1vga_control = RREG32(AVIVO_D1VGA_CONTROL); + d2vga_control = RREG32(AVIVO_D2VGA_CONTROL); + vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL); + rom_cntl = RREG32(R600_ROM_CNTL); + + /* enable the rom */ + WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS)); + /* Disable VGA mode */ + WREG32(AVIVO_D1VGA_CONTROL, + (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_D2VGA_CONTROL, + (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_VGA_RENDER_CONTROL, + (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE); + + r = radeon_read_bios(rdev); + + /* restore regs */ + WREG32(R600_BUS_CNTL, bus_cntl); + WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); + WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); + WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + WREG32(R600_ROM_CNTL, rom_cntl); + return r; +} + static bool r700_read_disabled_bios(struct radeon_device *rdev) { uint32_t viph_control; @@ -416,6 +455,8 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev) { if (rdev->flags & RADEON_IS_IGP) return igp_read_bios_from_vram(rdev); + else if (rdev->family >= CHIP_BARTS) + return ni_read_disabled_bios(rdev); else if (rdev->family >= CHIP_RV770) return r700_read_disabled_bios(rdev); else if (rdev->family >= CHIP_R600) -- cgit v1.2.3 From adb68fa2f79fbfb49a920c1b69d607a3ab4f985b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:24 -0500 Subject: drm/radeon/kms: fill gpu init for NI asics Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 9c990c3f877f..6a73867cf25c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1384,11 +1384,14 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, case CHIP_CEDAR: case CHIP_REDWOOD: case CHIP_PALM: + case CHIP_TURKS: + case CHIP_CAICOS: force_no_swizzle = false; break; case CHIP_CYPRESS: case CHIP_HEMLOCK: case CHIP_JUNIPER: + case CHIP_BARTS: default: force_no_swizzle = true; break; @@ -1502,6 +1505,7 @@ static void evergreen_program_channel_remap(struct radeon_device *rdev) switch (rdev->family) { case CHIP_HEMLOCK: case CHIP_CYPRESS: + case CHIP_BARTS: tcp_chan_steer_lo = 0x54763210; tcp_chan_steer_hi = 0x0000ba98; break; @@ -1509,6 +1513,8 @@ static void evergreen_program_channel_remap(struct radeon_device *rdev) case CHIP_REDWOOD: case CHIP_CEDAR: case CHIP_PALM: + case CHIP_TURKS: + case CHIP_CAICOS: default: tcp_chan_steer_lo = 0x76543210; tcp_chan_steer_hi = 0x0000ba98; @@ -1648,6 +1654,69 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.max_hw_contexts = 4; rdev->config.evergreen.sq_num_cf_insts = 1; + rdev->config.evergreen.sc_prim_fifo_size = 0x40; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_BARTS: + rdev->config.evergreen.num_ses = 2; + rdev->config.evergreen.max_pipes = 4; + rdev->config.evergreen.max_tile_pipes = 8; + rdev->config.evergreen.max_simds = 7; + rdev->config.evergreen.max_backends = 4 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 248; + rdev->config.evergreen.max_gs_threads = 32; + rdev->config.evergreen.max_stack_entries = 512; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 256; + rdev->config.evergreen.sx_max_export_pos_size = 64; + rdev->config.evergreen.sx_max_export_smx_size = 192; + rdev->config.evergreen.max_hw_contexts = 8; + rdev->config.evergreen.sq_num_cf_insts = 2; + + rdev->config.evergreen.sc_prim_fifo_size = 0x100; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_TURKS: + rdev->config.evergreen.num_ses = 1; + rdev->config.evergreen.max_pipes = 4; + rdev->config.evergreen.max_tile_pipes = 4; + rdev->config.evergreen.max_simds = 6; + rdev->config.evergreen.max_backends = 2 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 248; + rdev->config.evergreen.max_gs_threads = 32; + rdev->config.evergreen.max_stack_entries = 256; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 256; + rdev->config.evergreen.sx_max_export_pos_size = 64; + rdev->config.evergreen.sx_max_export_smx_size = 192; + rdev->config.evergreen.max_hw_contexts = 8; + rdev->config.evergreen.sq_num_cf_insts = 2; + + rdev->config.evergreen.sc_prim_fifo_size = 0x100; + rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; + rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; + break; + case CHIP_CAICOS: + rdev->config.evergreen.num_ses = 1; + rdev->config.evergreen.max_pipes = 4; + rdev->config.evergreen.max_tile_pipes = 2; + rdev->config.evergreen.max_simds = 2; + rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses; + rdev->config.evergreen.max_gprs = 256; + rdev->config.evergreen.max_threads = 192; + rdev->config.evergreen.max_gs_threads = 16; + rdev->config.evergreen.max_stack_entries = 256; + rdev->config.evergreen.sx_num_of_sets = 4; + rdev->config.evergreen.sx_max_export_size = 128; + rdev->config.evergreen.sx_max_export_pos_size = 32; + rdev->config.evergreen.sx_max_export_smx_size = 96; + rdev->config.evergreen.max_hw_contexts = 4; + rdev->config.evergreen.sq_num_cf_insts = 1; + rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; @@ -1931,6 +2000,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) switch (rdev->family) { case CHIP_CEDAR: case CHIP_PALM: + case CHIP_CAICOS: /* no vertex cache */ sq_config &= ~VC_ENABLE; break; @@ -1990,6 +2060,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) switch (rdev->family) { case CHIP_CEDAR: case CHIP_PALM: + case CHIP_CAICOS: vgt_cache_invalidation = CACHE_INVALIDATION(TC_ONLY); break; default: -- cgit v1.2.3 From 03f40090555bd3de9fc80aa4e805ac7fa9c39dfe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:25 -0500 Subject: drm/radeon/kms: add backend map workaround for barts Same as Cypress. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 6a73867cf25c..c40e5ad251dd 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1862,6 +1862,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) switch (rdev->family) { case CHIP_CYPRESS: case CHIP_HEMLOCK: + case CHIP_BARTS: gb_backend_map = 0x66442200; break; case CHIP_JUNIPER: -- cgit v1.2.3 From 9ace9f7b168fef492f731ba60da5c76bc0776e6d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:26 -0500 Subject: drm/radeon/kms: adjust default clock/vddc tracking for pm on DCE5 NI chips no longer load the MC ucode in the asic_init sequence so the asic comes up in a basic mode with low engine/memory clocks and a voltage. Once the MC ucode is loaded by the driver the card can be programmed to it's proper default clocks and voltage. As such the default clocks in the firmware info table as the post clocks, not the default running clocks. Track the default post clocks and default running clocks separately to handle this. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 3 +++ drivers/gpu/drm/radeon/radeon_atombios.c | 25 ++++++++++++++++--------- drivers/gpu/drm/radeon/radeon_pm.c | 18 ++++++++++-------- 3 files changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5598f9559a64..8c62b2f58923 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -823,6 +823,9 @@ struct radeon_pm { u32 current_sclk; u32 current_mclk; u32 current_vddc; + u32 default_sclk; + u32 default_mclk; + u32 default_vddc; struct radeon_i2c_chan *i2c_bus; /* selected pm method */ enum radeon_pm_method pm_method; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 03f1c9a10ba4..1573202a6418 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2249,15 +2249,22 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; - /* patch the table values with the default slck/mclk from firmware info */ - for (j = 0; j < mode_index; j++) { - rdev->pm.power_state[state_index].clock_info[j].mclk = - rdev->clock.default_mclk; - rdev->pm.power_state[state_index].clock_info[j].sclk = - rdev->clock.default_sclk; - if (vddc) - rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = - vddc; + if (ASIC_IS_DCE5(rdev)) { + /* NI chips post without MC ucode, so default clocks are strobe mode only */ + rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; + rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; + rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage; + } else { + /* patch the table values with the default slck/mclk from firmware info */ + for (j = 0; j < mode_index; j++) { + rdev->pm.power_state[state_index].clock_info[j].mclk = + rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[j].sclk = + rdev->clock.default_sclk; + if (vddc) + rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = + vddc; + } } } } diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 7ad2e1a6991d..9052d1e3a5fe 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -167,13 +167,13 @@ static void radeon_set_power_state(struct radeon_device *rdev) if (radeon_gui_idle(rdev)) { sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].sclk; - if (sclk > rdev->clock.default_sclk) - sclk = rdev->clock.default_sclk; + if (sclk > rdev->pm.default_sclk) + sclk = rdev->pm.default_sclk; mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].mclk; - if (mclk > rdev->clock.default_mclk) - mclk = rdev->clock.default_mclk; + if (mclk > rdev->pm.default_mclk) + mclk = rdev->pm.default_mclk; /* upvolt before raising clocks, downvolt after lowering clocks */ if (sclk < rdev->pm.current_sclk) @@ -534,8 +534,8 @@ void radeon_pm_resume(struct radeon_device *rdev) mutex_lock(&rdev->pm.mutex); rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; - rdev->pm.current_sclk = rdev->clock.default_sclk; - rdev->pm.current_mclk = rdev->clock.default_mclk; + rdev->pm.current_sclk = rdev->pm.default_sclk; + rdev->pm.current_mclk = rdev->pm.default_mclk; rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { @@ -558,6 +558,8 @@ int radeon_pm_init(struct radeon_device *rdev) rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; rdev->pm.dynpm_can_upclock = true; rdev->pm.dynpm_can_downclock = true; + rdev->pm.default_sclk = rdev->clock.default_sclk; + rdev->pm.default_mclk = rdev->clock.default_mclk; rdev->pm.current_sclk = rdev->clock.default_sclk; rdev->pm.current_mclk = rdev->clock.default_mclk; rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; @@ -804,9 +806,9 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private; - seq_printf(m, "default engine clock: %u0 kHz\n", rdev->clock.default_sclk); + seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); - seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); + seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk); if (rdev->asic->get_memory_clock) seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); if (rdev->pm.current_vddc) -- cgit v1.2.3 From 7d52785d2ac1a07bc012b76cb465c9a01d830a32 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:27 -0500 Subject: drm/radeon/kms: always use writeback/events for fences on NI Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e35343007229..26091d602b84 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -228,6 +228,11 @@ int radeon_wb_init(struct radeon_device *rdev) rdev->wb.use_event = true; } } + /* always use writeback/events on NI */ + if (ASIC_IS_DCE5(rdev)) { + rdev->wb.enabled = true; + rdev->wb.use_event = true; + } dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis"); -- cgit v1.2.3 From ff5b8562d965687261968d02762f9ae73e80a948 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:28 -0500 Subject: drm/radeon/kms: add bo blit support for NI Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_blit_kms.c | 69 ++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index 2ccd1f0545fe..b758dc7f2f2c 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -148,7 +148,8 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30); if ((rdev->family == CHIP_CEDAR) || - (rdev->family == CHIP_PALM)) + (rdev->family == CHIP_PALM) || + (rdev->family == CHIP_CAICOS)) cp_set_surface_sync(rdev, PACKET3_TC_ACTION_ENA, 48, gpu_addr); else @@ -353,10 +354,74 @@ set_default_state(struct radeon_device *rdev) num_hs_stack_entries = 42; num_ls_stack_entries = 42; break; + case CHIP_BARTS: + num_ps_gprs = 93; + num_vs_gprs = 46; + num_temp_gprs = 4; + num_gs_gprs = 31; + num_es_gprs = 31; + num_hs_gprs = 23; + num_ls_gprs = 23; + num_ps_threads = 128; + num_vs_threads = 20; + num_gs_threads = 20; + num_es_threads = 20; + num_hs_threads = 20; + num_ls_threads = 20; + num_ps_stack_entries = 85; + num_vs_stack_entries = 85; + num_gs_stack_entries = 85; + num_es_stack_entries = 85; + num_hs_stack_entries = 85; + num_ls_stack_entries = 85; + break; + case CHIP_TURKS: + num_ps_gprs = 93; + num_vs_gprs = 46; + num_temp_gprs = 4; + num_gs_gprs = 31; + num_es_gprs = 31; + num_hs_gprs = 23; + num_ls_gprs = 23; + num_ps_threads = 128; + num_vs_threads = 20; + num_gs_threads = 20; + num_es_threads = 20; + num_hs_threads = 20; + num_ls_threads = 20; + num_ps_stack_entries = 42; + num_vs_stack_entries = 42; + num_gs_stack_entries = 42; + num_es_stack_entries = 42; + num_hs_stack_entries = 42; + num_ls_stack_entries = 42; + break; + case CHIP_CAICOS: + num_ps_gprs = 93; + num_vs_gprs = 46; + num_temp_gprs = 4; + num_gs_gprs = 31; + num_es_gprs = 31; + num_hs_gprs = 23; + num_ls_gprs = 23; + num_ps_threads = 128; + num_vs_threads = 10; + num_gs_threads = 10; + num_es_threads = 10; + num_hs_threads = 10; + num_ls_threads = 10; + num_ps_stack_entries = 42; + num_vs_stack_entries = 42; + num_gs_stack_entries = 42; + num_es_stack_entries = 42; + num_hs_stack_entries = 42; + num_ls_stack_entries = 42; + break; } if ((rdev->family == CHIP_CEDAR) || - (rdev->family == CHIP_PALM)) + (rdev->family == CHIP_PALM) || + (rdev->family == CHIP_CAICOS)) sq_config = 0; else sq_config = VC_ENABLE; -- cgit v1.2.3 From 58c2e9f02ad09b4375eb11c1f65565a83310deca Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:29 -0500 Subject: drm/radeon/kms: add ni_reg.h This adds some new NI (northern islands) specific display register defines. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/ni_reg.h | 86 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_reg.h | 1 + 2 files changed, 87 insertions(+) create mode 100644 drivers/gpu/drm/radeon/ni_reg.h (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/ni_reg.h b/drivers/gpu/drm/radeon/ni_reg.h new file mode 100644 index 000000000000..5db7b7d6feb0 --- /dev/null +++ b/drivers/gpu/drm/radeon/ni_reg.h @@ -0,0 +1,86 @@ +/* + * Copyright 2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Alex Deucher + */ +#ifndef __NI_REG_H__ +#define __NI_REG_H__ + +/* northern islands - DCE5 */ + +#define NI_INPUT_GAMMA_CONTROL 0x6840 +# define NI_GRPH_INPUT_GAMMA_MODE(x) (((x) & 0x3) << 0) +# define NI_INPUT_GAMMA_USE_LUT 0 +# define NI_INPUT_GAMMA_BYPASS 1 +# define NI_INPUT_GAMMA_SRGB_24 2 +# define NI_INPUT_GAMMA_XVYCC_222 3 +# define NI_OVL_INPUT_GAMMA_MODE(x) (((x) & 0x3) << 4) + +#define NI_PRESCALE_GRPH_CONTROL 0x68b4 +# define NI_GRPH_PRESCALE_BYPASS (1 << 4) + +#define NI_PRESCALE_OVL_CONTROL 0x68c4 +# define NI_OVL_PRESCALE_BYPASS (1 << 4) + +#define NI_INPUT_CSC_CONTROL 0x68d4 +# define NI_INPUT_CSC_GRPH_MODE(x) (((x) & 0x3) << 0) +# define NI_INPUT_CSC_BYPASS 0 +# define NI_INPUT_CSC_PROG_COEFF 1 +# define NI_INPUT_CSC_PROG_SHARED_MATRIXA 2 +# define NI_INPUT_CSC_OVL_MODE(x) (((x) & 0x3) << 4) + +#define NI_OUTPUT_CSC_CONTROL 0x68f0 +# define NI_OUTPUT_CSC_GRPH_MODE(x) (((x) & 0x7) << 0) +# define NI_OUTPUT_CSC_BYPASS 0 +# define NI_OUTPUT_CSC_TV_RGB 1 +# define NI_OUTPUT_CSC_YCBCR_601 2 +# define NI_OUTPUT_CSC_YCBCR_709 3 +# define NI_OUTPUT_CSC_PROG_COEFF 4 +# define NI_OUTPUT_CSC_PROG_SHARED_MATRIXB 5 +# define NI_OUTPUT_CSC_OVL_MODE(x) (((x) & 0x7) << 4) + +#define NI_DEGAMMA_CONTROL 0x6960 +# define NI_GRPH_DEGAMMA_MODE(x) (((x) & 0x3) << 0) +# define NI_DEGAMMA_BYPASS 0 +# define NI_DEGAMMA_SRGB_24 1 +# define NI_DEGAMMA_XVYCC_222 2 +# define NI_OVL_DEGAMMA_MODE(x) (((x) & 0x3) << 4) +# define NI_ICON_DEGAMMA_MODE(x) (((x) & 0x3) << 8) +# define NI_CURSOR_DEGAMMA_MODE(x) (((x) & 0x3) << 12) + +#define NI_GAMUT_REMAP_CONTROL 0x6964 +# define NI_GRPH_GAMUT_REMAP_MODE(x) (((x) & 0x3) << 0) +# define NI_GAMUT_REMAP_BYPASS 0 +# define NI_GAMUT_REMAP_PROG_COEFF 1 +# define NI_GAMUT_REMAP_PROG_SHARED_MATRIXA 2 +# define NI_GAMUT_REMAP_PROG_SHARED_MATRIXB 3 +# define NI_OVL_GAMUT_REMAP_MODE(x) (((x) & 0x3) << 4) + +#define NI_REGAMMA_CONTROL 0x6a80 +# define NI_GRPH_REGAMMA_MODE(x) (((x) & 0x7) << 0) +# define NI_REGAMMA_BYPASS 0 +# define NI_REGAMMA_SRGB_24 1 +# define NI_REGAMMA_XVYCC_222 2 +# define NI_REGAMMA_PROG_A 3 +# define NI_REGAMMA_PROG_B 4 +# define NI_OVL_REGAMMA_MODE(x) (((x) & 0x7) << 4) + +#endif diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 3369ce984af1..3cd4dace57c7 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -55,6 +55,7 @@ #include "r500_reg.h" #include "r600_reg.h" #include "evergreen_reg.h" +#include "ni_reg.h" #define RADEON_MC_AGP_LOCATION 0x014c #define RADEON_MC_AGP_START_MASK 0x0000FFFF -- cgit v1.2.3 From fee298fd6f3d8bde5fc2912192d026c78ba81982 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:30 -0500 Subject: drm/radeon/kms: add support for DCE5 display LUTs The hardware supports advanced user defined color management but at the moment, there is no infrastructure in place to take advantage of it so for now we just support the legacy LUTs. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 68 +++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 30d867c85825..d26dabf878d9 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -68,7 +68,7 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); } -static void evergreen_crtc_load_lut(struct drm_crtc *crtc) +static void dce4_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -98,6 +98,66 @@ static void evergreen_crtc_load_lut(struct drm_crtc *crtc) } } +static void dce5_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + int i; + + DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id); + + WREG32(NI_INPUT_CSC_CONTROL + radeon_crtc->crtc_offset, + (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) | + NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS))); + WREG32(NI_PRESCALE_GRPH_CONTROL + radeon_crtc->crtc_offset, + NI_GRPH_PRESCALE_BYPASS); + WREG32(NI_PRESCALE_OVL_CONTROL + radeon_crtc->crtc_offset, + NI_OVL_PRESCALE_BYPASS); + WREG32(NI_INPUT_GAMMA_CONTROL + radeon_crtc->crtc_offset, + (NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) | + NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT))); + + WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0); + + WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); + WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); + WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); + + WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff); + WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff); + WREG32(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff); + + WREG32(EVERGREEN_DC_LUT_RW_MODE + radeon_crtc->crtc_offset, 0); + WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 0x00000007); + + WREG32(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, 0); + for (i = 0; i < 256; i++) { + WREG32(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset, + (radeon_crtc->lut_r[i] << 20) | + (radeon_crtc->lut_g[i] << 10) | + (radeon_crtc->lut_b[i] << 0)); + } + + WREG32(NI_DEGAMMA_CONTROL + radeon_crtc->crtc_offset, + (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | + NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | + NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | + NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS))); + WREG32(NI_GAMUT_REMAP_CONTROL + radeon_crtc->crtc_offset, + (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) | + NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS))); + WREG32(NI_REGAMMA_CONTROL + radeon_crtc->crtc_offset, + (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) | + NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS))); + WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset, + (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) | + NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); + /* XXX match this to the depth of the crtc fmt block, move to modeset? */ + WREG32(0x6940 + radeon_crtc->crtc_offset, 0); + +} + static void legacy_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -130,8 +190,10 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc) if (!crtc->enabled) return; - if (ASIC_IS_DCE4(rdev)) - evergreen_crtc_load_lut(crtc); + if (ASIC_IS_DCE5(rdev)) + dce5_crtc_load_lut(crtc); + else if (ASIC_IS_DCE4(rdev)) + dce4_crtc_load_lut(crtc); else if (ASIC_IS_AVIVO(rdev)) avivo_crtc_load_lut(crtc); else -- cgit v1.2.3 From 0af62b0168043896a042b005ff88caa77dd94d04 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:31 -0500 Subject: drm/radeon/kms: add ucode loader for NI The MC ucode is no longer loaded by the vbios tables as on previous asics. It now must be loaded by the driver. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/Makefile | 2 +- drivers/gpu/drm/radeon/evergreen.c | 21 ++- drivers/gpu/drm/radeon/ni.c | 316 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/nid.h | 41 +++++ drivers/gpu/drm/radeon/radeon.h | 4 + 5 files changed, 380 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/radeon/ni.c create mode 100644 drivers/gpu/drm/radeon/nid.h (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index e97e6f842699..e47eecfc2df4 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -66,7 +66,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ - radeon_trace_points.o + radeon_trace_points.o ni.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index c40e5ad251dd..4fb2101ee476 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2855,12 +2855,27 @@ static int evergreen_startup(struct radeon_device *rdev) /* enable pcie gen2 link */ evergreen_pcie_gen2_enable(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + r = btc_mc_load_microcode(rdev); if (r) { - DRM_ERROR("Failed to load firmware!\n"); + DRM_ERROR("Failed to load MC firmware!\n"); return r; } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } } evergreen_mc_program(rdev); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c new file mode 100644 index 000000000000..5e0bef80ad7f --- /dev/null +++ b/drivers/gpu/drm/radeon/ni.c @@ -0,0 +1,316 @@ +/* + * Copyright 2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Alex Deucher + */ +#include +#include +#include +#include "drmP.h" +#include "radeon.h" +#include "radeon_asic.h" +#include "radeon_drm.h" +#include "nid.h" +#include "atom.h" +#include "ni_reg.h" + +#define EVERGREEN_PFP_UCODE_SIZE 1120 +#define EVERGREEN_PM4_UCODE_SIZE 1376 +#define EVERGREEN_RLC_UCODE_SIZE 768 +#define BTC_MC_UCODE_SIZE 6024 + +/* Firmware Names */ +MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); +MODULE_FIRMWARE("radeon/BARTS_me.bin"); +MODULE_FIRMWARE("radeon/BARTS_mc.bin"); +MODULE_FIRMWARE("radeon/BTC_rlc.bin"); +MODULE_FIRMWARE("radeon/TURKS_pfp.bin"); +MODULE_FIRMWARE("radeon/TURKS_me.bin"); +MODULE_FIRMWARE("radeon/TURKS_mc.bin"); +MODULE_FIRMWARE("radeon/CAICOS_pfp.bin"); +MODULE_FIRMWARE("radeon/CAICOS_me.bin"); +MODULE_FIRMWARE("radeon/CAICOS_mc.bin"); + +#define BTC_IO_MC_REGS_SIZE 29 + +static const u32 barts_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { + {0x00000077, 0xff010100}, + {0x00000078, 0x00000000}, + {0x00000079, 0x00001434}, + {0x0000007a, 0xcc08ec08}, + {0x0000007b, 0x00040000}, + {0x0000007c, 0x000080c0}, + {0x0000007d, 0x09000000}, + {0x0000007e, 0x00210404}, + {0x00000081, 0x08a8e800}, + {0x00000082, 0x00030444}, + {0x00000083, 0x00000000}, + {0x00000085, 0x00000001}, + {0x00000086, 0x00000002}, + {0x00000087, 0x48490000}, + {0x00000088, 0x20244647}, + {0x00000089, 0x00000005}, + {0x0000008b, 0x66030000}, + {0x0000008c, 0x00006603}, + {0x0000008d, 0x00000100}, + {0x0000008f, 0x00001c0a}, + {0x00000090, 0xff000001}, + {0x00000094, 0x00101101}, + {0x00000095, 0x00000fff}, + {0x00000096, 0x00116fff}, + {0x00000097, 0x60010000}, + {0x00000098, 0x10010000}, + {0x00000099, 0x00006000}, + {0x0000009a, 0x00001000}, + {0x0000009f, 0x00946a00} +}; + +static const u32 turks_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { + {0x00000077, 0xff010100}, + {0x00000078, 0x00000000}, + {0x00000079, 0x00001434}, + {0x0000007a, 0xcc08ec08}, + {0x0000007b, 0x00040000}, + {0x0000007c, 0x000080c0}, + {0x0000007d, 0x09000000}, + {0x0000007e, 0x00210404}, + {0x00000081, 0x08a8e800}, + {0x00000082, 0x00030444}, + {0x00000083, 0x00000000}, + {0x00000085, 0x00000001}, + {0x00000086, 0x00000002}, + {0x00000087, 0x48490000}, + {0x00000088, 0x20244647}, + {0x00000089, 0x00000005}, + {0x0000008b, 0x66030000}, + {0x0000008c, 0x00006603}, + {0x0000008d, 0x00000100}, + {0x0000008f, 0x00001c0a}, + {0x00000090, 0xff000001}, + {0x00000094, 0x00101101}, + {0x00000095, 0x00000fff}, + {0x00000096, 0x00116fff}, + {0x00000097, 0x60010000}, + {0x00000098, 0x10010000}, + {0x00000099, 0x00006000}, + {0x0000009a, 0x00001000}, + {0x0000009f, 0x00936a00} +}; + +static const u32 caicos_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { + {0x00000077, 0xff010100}, + {0x00000078, 0x00000000}, + {0x00000079, 0x00001434}, + {0x0000007a, 0xcc08ec08}, + {0x0000007b, 0x00040000}, + {0x0000007c, 0x000080c0}, + {0x0000007d, 0x09000000}, + {0x0000007e, 0x00210404}, + {0x00000081, 0x08a8e800}, + {0x00000082, 0x00030444}, + {0x00000083, 0x00000000}, + {0x00000085, 0x00000001}, + {0x00000086, 0x00000002}, + {0x00000087, 0x48490000}, + {0x00000088, 0x20244647}, + {0x00000089, 0x00000005}, + {0x0000008b, 0x66030000}, + {0x0000008c, 0x00006603}, + {0x0000008d, 0x00000100}, + {0x0000008f, 0x00001c0a}, + {0x00000090, 0xff000001}, + {0x00000094, 0x00101101}, + {0x00000095, 0x00000fff}, + {0x00000096, 0x00116fff}, + {0x00000097, 0x60010000}, + {0x00000098, 0x10010000}, + {0x00000099, 0x00006000}, + {0x0000009a, 0x00001000}, + {0x0000009f, 0x00916a00} +}; + +int btc_mc_load_microcode(struct radeon_device *rdev) +{ + const __be32 *fw_data; + u32 mem_type, running, blackout = 0; + u32 *io_mc_regs; + int i; + + if (!rdev->mc_fw) + return -EINVAL; + + switch (rdev->family) { + case CHIP_BARTS: + io_mc_regs = (u32 *)&barts_io_mc_regs; + break; + case CHIP_TURKS: + io_mc_regs = (u32 *)&turks_io_mc_regs; + break; + case CHIP_CAICOS: + default: + io_mc_regs = (u32 *)&caicos_io_mc_regs; + break; + } + + mem_type = (RREG32(MC_SEQ_MISC0) & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT; + running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; + + if ((mem_type == MC_SEQ_MISC0_GDDR5_VALUE) && (running == 0)) { + if (running) { + blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); + WREG32(MC_SHARED_BLACKOUT_CNTL, 1); + } + + /* reset the engine and set to writable */ + WREG32(MC_SEQ_SUP_CNTL, 0x00000008); + WREG32(MC_SEQ_SUP_CNTL, 0x00000010); + + /* load mc io regs */ + for (i = 0; i < BTC_IO_MC_REGS_SIZE; i++) { + WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); + WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); + } + /* load the MC ucode */ + fw_data = (const __be32 *)rdev->mc_fw->data; + for (i = 0; i < BTC_MC_UCODE_SIZE; i++) + WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); + + /* put the engine back into the active state */ + WREG32(MC_SEQ_SUP_CNTL, 0x00000008); + WREG32(MC_SEQ_SUP_CNTL, 0x00000004); + WREG32(MC_SEQ_SUP_CNTL, 0x00000001); + + /* wait for training to complete */ + while (!(RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD)) + udelay(10); + + if (running) + WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); + } + + return 0; +} + +int ni_init_microcode(struct radeon_device *rdev) +{ + struct platform_device *pdev; + const char *chip_name; + const char *rlc_chip_name; + size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size; + char fw_name[30]; + int err; + + DRM_DEBUG("\n"); + + pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); + err = IS_ERR(pdev); + if (err) { + printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); + return -EINVAL; + } + + switch (rdev->family) { + case CHIP_BARTS: + chip_name = "BARTS"; + rlc_chip_name = "BTC"; + break; + case CHIP_TURKS: + chip_name = "TURKS"; + rlc_chip_name = "BTC"; + break; + case CHIP_CAICOS: + chip_name = "CAICOS"; + rlc_chip_name = "BTC"; + break; + default: BUG(); + } + + pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; + me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; + rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; + mc_req_size = BTC_MC_UCODE_SIZE * 4; + + DRM_INFO("Loading %s Microcode\n", chip_name); + + snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); + if (err) + goto out; + if (rdev->pfp_fw->size != pfp_req_size) { + printk(KERN_ERR + "ni_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->pfp_fw->size, fw_name); + err = -EINVAL; + goto out; + } + + snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); + if (err) + goto out; + if (rdev->me_fw->size != me_req_size) { + printk(KERN_ERR + "ni_cp: Bogus length %zu in firmware \"%s\"\n", + rdev->me_fw->size, fw_name); + err = -EINVAL; + } + + snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); + err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); + if (err) + goto out; + if (rdev->rlc_fw->size != rlc_req_size) { + printk(KERN_ERR + "ni_rlc: Bogus length %zu in firmware \"%s\"\n", + rdev->rlc_fw->size, fw_name); + err = -EINVAL; + } + + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); + if (err) + goto out; + if (rdev->mc_fw->size != mc_req_size) { + printk(KERN_ERR + "ni_mc: Bogus length %zu in firmware \"%s\"\n", + rdev->mc_fw->size, fw_name); + err = -EINVAL; + } +out: + platform_device_unregister(pdev); + + if (err) { + if (err != -EINVAL) + printk(KERN_ERR + "ni_cp: Failed to load firmware \"%s\"\n", + fw_name); + release_firmware(rdev->pfp_fw); + rdev->pfp_fw = NULL; + release_firmware(rdev->me_fw); + rdev->me_fw = NULL; + release_firmware(rdev->rlc_fw); + rdev->rlc_fw = NULL; + release_firmware(rdev->mc_fw); + rdev->mc_fw = NULL; + } + return err; +} + diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h new file mode 100644 index 000000000000..f7b445390e02 --- /dev/null +++ b/drivers/gpu/drm/radeon/nid.h @@ -0,0 +1,41 @@ +/* + * Copyright 2010 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Alex Deucher + */ +#ifndef NI_H +#define NI_H + +#define MC_SHARED_BLACKOUT_CNTL 0x20ac +#define MC_SEQ_SUP_CNTL 0x28c8 +#define RUN_MASK (1 << 0) +#define MC_SEQ_SUP_PGM 0x28cc +#define MC_IO_PAD_CNTL_D0 0x29d0 +#define MEM_FALL_OUT_CMD (1 << 8) +#define MC_SEQ_MISC0 0x2a00 +#define MC_SEQ_MISC0_GDDR5_SHIFT 28 +#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 +#define MC_SEQ_MISC0_GDDR5_VALUE 5 +#define MC_SEQ_IO_DEBUG_INDEX 0x2a44 +#define MC_SEQ_IO_DEBUG_DATA 0x2a48 + +#endif + diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8c62b2f58923..da21105488da 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1152,6 +1152,7 @@ struct radeon_device { const struct firmware *me_fw; /* all family ME firmware */ const struct firmware *pfp_fw; /* r6/700 PFP firmware */ const struct firmware *rlc_fw; /* r6/700 RLC firmware */ + const struct firmware *mc_fw; /* NI MC firmware */ struct r600_blit r600_blit; struct r700_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ @@ -1561,6 +1562,9 @@ extern int evergreen_irq_set(struct radeon_device *rdev); extern int evergreen_blit_init(struct radeon_device *rdev); extern void evergreen_blit_fini(struct radeon_device *rdev); +extern int ni_init_microcode(struct radeon_device *rdev); +extern int btc_mc_load_microcode(struct radeon_device *rdev); + /* radeon_acpi.c */ #if defined(CONFIG_ACPI) extern int radeon_acpi_init(struct radeon_device *rdev); -- cgit v1.2.3 From ed18a3603f5b466e0300fc5e0c349dbcce376861 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:32 -0500 Subject: drm/radeon/kms/ni: load default sclk/mclk/vddc at pm init The vbios only partially initializes the memory controller on NI, so now we need to load the MC ucode in the driver and set the default clocks once the ucode is loaded. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 9052d1e3a5fe..3b1b2bf9cdd5 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -530,6 +530,15 @@ void radeon_pm_suspend(struct radeon_device *rdev) void radeon_pm_resume(struct radeon_device *rdev) { + /* set up the default clocks if the MC ucode is loaded */ + if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { + if (rdev->pm.default_vddc) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc); + if (rdev->pm.default_sclk) + radeon_set_engine_clock(rdev, rdev->pm.default_sclk); + if (rdev->pm.default_mclk) + radeon_set_memory_clock(rdev, rdev->pm.default_mclk); + } /* asic init will reset the default power state */ mutex_lock(&rdev->pm.mutex); rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; @@ -571,6 +580,15 @@ int radeon_pm_init(struct radeon_device *rdev) radeon_combios_get_power_modes(rdev); radeon_pm_print_states(rdev); radeon_pm_init_profile(rdev); + /* set up the default clocks if the MC ucode is loaded */ + if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { + if (rdev->pm.default_vddc) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc); + if (rdev->pm.default_sclk) + radeon_set_engine_clock(rdev, rdev->pm.default_sclk); + if (rdev->pm.default_mclk) + radeon_set_memory_clock(rdev, rdev->pm.default_mclk); + } } /* set up the internal thermal sensor if applicable */ -- cgit v1.2.3 From a43b7665de7b1adbda5ce19d57cb65add0982c8f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:33 -0500 Subject: drm/radeon/kms: add radeon_asic struct for NI asics Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 53c62404795d..3a1b16186224 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -836,6 +836,52 @@ static struct radeon_asic sumo_asic = { .pm_get_dynpm_state = &r600_pm_get_dynpm_state, }; +static struct radeon_asic btc_asic = { + .init = &evergreen_init, + .fini = &evergreen_fini, + .suspend = &evergreen_suspend, + .resume = &evergreen_resume, + .cp_commit = &r600_cp_commit, + .gpu_is_lockup = &evergreen_gpu_is_lockup, + .asic_reset = &evergreen_asic_reset, + .vga_set_state = &r600_vga_set_state, + .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, + .gart_set_page = &rs600_gart_set_page, + .ring_test = &r600_ring_test, + .ring_ib_execute = &r600_ring_ib_execute, + .irq_set = &evergreen_irq_set, + .irq_process = &evergreen_irq_process, + .get_vblank_counter = &evergreen_get_vblank_counter, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &evergreen_cs_parse, + .copy_blit = &evergreen_copy_blit, + .copy_dma = &evergreen_copy_blit, + .copy = &evergreen_copy_blit, + .get_engine_clock = &radeon_atom_get_engine_clock, + .set_engine_clock = &radeon_atom_set_engine_clock, + .get_memory_clock = &radeon_atom_get_memory_clock, + .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = NULL, + .set_pcie_lanes = NULL, + .set_clock_gating = NULL, + .set_surface_reg = r600_set_surface_reg, + .clear_surface_reg = r600_clear_surface_reg, + .bandwidth_update = &evergreen_bandwidth_update, + .hpd_init = &evergreen_hpd_init, + .hpd_fini = &evergreen_hpd_fini, + .hpd_sense = &evergreen_hpd_sense, + .hpd_set_polarity = &evergreen_hpd_set_polarity, + .gui_idle = &r600_gui_idle, + .pm_misc = &evergreen_pm_misc, + .pm_prepare = &evergreen_pm_prepare, + .pm_finish = &evergreen_pm_finish, + .pm_init_profile = &r600_pm_init_profile, + .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .pre_page_flip = &evergreen_pre_page_flip, + .page_flip = &evergreen_page_flip, + .post_page_flip = &evergreen_post_page_flip, +}; + int radeon_asic_init(struct radeon_device *rdev) { radeon_register_accessor_init(rdev); @@ -923,6 +969,11 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_PALM: rdev->asic = &sumo_asic; break; + case CHIP_BARTS: + case CHIP_TURKS: + case CHIP_CAICOS: + rdev->asic = &btc_asic; + break; default: /* FIXME: not supported yet */ return -EINVAL; -- cgit v1.2.3 From 0d1014a2f2d1ad660caafae6f62796a93307867f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Jan 2011 21:19:34 -0500 Subject: drm/radeon/kms: don't enable pcie gen2 on NI yet Still needs to be implemented. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4fb2101ee476..7fe8ebdcdc0e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2853,7 +2853,8 @@ static int evergreen_startup(struct radeon_device *rdev) int r; /* enable pcie gen2 link */ - evergreen_pcie_gen2_enable(rdev); + if (!ASIC_IS_DCE5(rdev)) + evergreen_pcie_gen2_enable(rdev); if (ASIC_IS_DCE5(rdev)) { if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { -- cgit v1.2.3 From 26fcaf60fe3861409eb4c455c5c0d0f00f599b08 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 7 Jan 2011 01:42:31 +0100 Subject: PM: Fix oops in suspend/hibernate code related to failing ioremap() When ioremap() fails (which might happen for some reason), we nicely oops in suspend_nvs_save() due to NULL dereference by memcpy() in there. Fail gracefully instead. Signed-off-by: Jiri Slaby Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 5 ++--- include/linux/suspend.h | 4 ++-- kernel/power/nvs.c | 8 +++++++- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index febb153b5a68..d8bca6c90719 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -124,8 +124,7 @@ static int acpi_pm_freeze(void) static int acpi_pm_pre_suspend(void) { acpi_pm_freeze(); - suspend_nvs_save(); - return 0; + return suspend_nvs_save(); } /** @@ -151,7 +150,7 @@ static int acpi_pm_prepare(void) { int error = __acpi_pm_prepare(); if (!error) - acpi_pm_pre_suspend(); + error = acpi_pm_pre_suspend(); return error; } diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 26697514c5ec..acb7d911bb0c 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -262,7 +262,7 @@ static inline bool system_entering_hibernation(void) { return false; } extern int suspend_nvs_register(unsigned long start, unsigned long size); extern int suspend_nvs_alloc(void); extern void suspend_nvs_free(void); -extern void suspend_nvs_save(void); +extern int suspend_nvs_save(void); extern void suspend_nvs_restore(void); #else /* CONFIG_SUSPEND_NVS */ static inline int suspend_nvs_register(unsigned long a, unsigned long b) @@ -271,7 +271,7 @@ static inline int suspend_nvs_register(unsigned long a, unsigned long b) } static inline int suspend_nvs_alloc(void) { return 0; } static inline void suspend_nvs_free(void) {} -static inline void suspend_nvs_save(void) {} +static inline int suspend_nvs_save(void) {} static inline void suspend_nvs_restore(void) {} #endif /* CONFIG_SUSPEND_NVS */ diff --git a/kernel/power/nvs.c b/kernel/power/nvs.c index 1836db60bbb6..57c6fabbb6b6 100644 --- a/kernel/power/nvs.c +++ b/kernel/power/nvs.c @@ -105,7 +105,7 @@ int suspend_nvs_alloc(void) /** * suspend_nvs_save - save NVS memory regions */ -void suspend_nvs_save(void) +int suspend_nvs_save(void) { struct nvs_page *entry; @@ -114,8 +114,14 @@ void suspend_nvs_save(void) list_for_each_entry(entry, &nvs_list, node) if (entry->data) { entry->kaddr = ioremap(entry->phys_start, entry->size); + if (!entry->kaddr) { + suspend_nvs_free(); + return -ENOMEM; + } memcpy(entry->data, entry->kaddr, entry->size); } + + return 0; } /** -- cgit v1.2.3 From fea6f330cdd18f79d50bcdfbedb96d929a173e0d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Jan 2011 08:12:27 +0300 Subject: vga_switcheroo: comparing too few characters in strncmp() This is a copy-and-paste bug. We should be comparing 4 characters here instead of 3. Signed-off-by: Dan Carpenter Signed-off-by: Dave Airlie --- drivers/gpu/vga/vga_switcheroo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index d2d8543686d3..e01cacba685f 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -346,11 +346,11 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, if (strncmp(usercmd, "DIS", 3) == 0) client_id = VGA_SWITCHEROO_DIS; - if (strncmp(usercmd, "MIGD", 3) == 0) { + if (strncmp(usercmd, "MIGD", 4) == 0) { just_mux = true; client_id = VGA_SWITCHEROO_IGD; } - if (strncmp(usercmd, "MDIS", 3) == 0) { + if (strncmp(usercmd, "MDIS", 4) == 0) { just_mux = true; client_id = VGA_SWITCHEROO_DIS; } -- cgit v1.2.3 From 187f3da3d98a1740d71e1f5d4fb3c68df09ecca8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 28 Nov 2010 19:06:09 +0100 Subject: radeon: consolidate asic-specific function decls for pre-r600 Move them to radeon_asic.h together with the other asic specific stuff. Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon.h | 59 ------------------------------------ drivers/gpu/drm/radeon/radeon_asic.h | 53 ++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index da21105488da..e9486630a467 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1449,65 +1449,6 @@ extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc extern int radeon_resume_kms(struct drm_device *dev); extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); -/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ -extern void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_cp *cp); -extern bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_cp *cp); - -/* rv200,rv250,rv280 */ -extern void r200_set_safe_registers(struct radeon_device *rdev); - -/* r300,r350,rv350,rv370,rv380 */ -extern void r300_set_reg_safe(struct radeon_device *rdev); -extern void r300_mc_program(struct radeon_device *rdev); -extern void r300_mc_init(struct radeon_device *rdev); -extern void r300_clock_startup(struct radeon_device *rdev); -extern int r300_mc_wait_for_idle(struct radeon_device *rdev); -extern int rv370_pcie_gart_init(struct radeon_device *rdev); -extern void rv370_pcie_gart_fini(struct radeon_device *rdev); -extern int rv370_pcie_gart_enable(struct radeon_device *rdev); -extern void rv370_pcie_gart_disable(struct radeon_device *rdev); - -/* r420,r423,rv410 */ -extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg); -extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v); -extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev); -extern void r420_pipes_init(struct radeon_device *rdev); - -/* rv515 */ -struct rv515_mc_save { - u32 d1vga_control; - u32 d2vga_control; - u32 vga_render_control; - u32 vga_hdp_control; - u32 d1crtc_control; - u32 d2crtc_control; -}; -extern void rv515_bandwidth_avivo_update(struct radeon_device *rdev); -extern void rv515_vga_render_disable(struct radeon_device *rdev); -extern void rv515_set_safe_registers(struct radeon_device *rdev); -extern void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save); -extern void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save); -extern void rv515_clock_startup(struct radeon_device *rdev); -extern void rv515_debugfs(struct radeon_device *rdev); -extern int rv515_suspend(struct radeon_device *rdev); - -/* rs400 */ -extern int rs400_gart_init(struct radeon_device *rdev); -extern int rs400_gart_enable(struct radeon_device *rdev); -extern void rs400_gart_adjust_size(struct radeon_device *rdev); -extern void rs400_gart_disable(struct radeon_device *rdev); -extern void rs400_gart_fini(struct radeon_device *rdev); - -/* rs600 */ -extern void rs600_set_safe_registers(struct radeon_device *rdev); -extern int rs600_irq_set(struct radeon_device *rdev); -extern void rs600_irq_disable(struct radeon_device *rdev); - -/* rs690, rs740 */ -extern void rs690_line_buffer_adjust(struct radeon_device *rdev, - struct drm_display_mode *mode1, - struct drm_display_mode *mode2); - /* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */ extern bool r600_card_posted(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 9ac71b8d1b9d..e01f07718539 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -102,6 +102,11 @@ int r100_pci_gart_enable(struct radeon_device *rdev); void r100_pci_gart_disable(struct radeon_device *rdev); int r100_debugfs_mc_info_init(struct radeon_device *rdev); int r100_gui_wait_for_idle(struct radeon_device *rdev); +void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, + struct radeon_cp *cp); +bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, + struct r100_gpu_lockup *lockup, + struct radeon_cp *cp); void r100_ib_fini(struct radeon_device *rdev); int r100_ib_init(struct radeon_device *rdev); void r100_irq_disable(struct radeon_device *rdev); @@ -138,10 +143,11 @@ extern void r100_post_page_flip(struct radeon_device *rdev, int crtc); * r200,rv250,rs300,rv280 */ extern int r200_copy_dma(struct radeon_device *rdev, - uint64_t src_offset, - uint64_t dst_offset, - unsigned num_pages, + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_pages, struct radeon_fence *fence); +void r200_set_safe_registers(struct radeon_device *rdev); /* * r300,r350,rv350,rv380 @@ -162,6 +168,15 @@ extern uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg); extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int rv370_get_pcie_lanes(struct radeon_device *rdev); +extern void r300_set_reg_safe(struct radeon_device *rdev); +extern void r300_mc_program(struct radeon_device *rdev); +extern void r300_mc_init(struct radeon_device *rdev); +extern void r300_clock_startup(struct radeon_device *rdev); +extern int r300_mc_wait_for_idle(struct radeon_device *rdev); +extern int rv370_pcie_gart_init(struct radeon_device *rdev); +extern void rv370_pcie_gart_fini(struct radeon_device *rdev); +extern int rv370_pcie_gart_enable(struct radeon_device *rdev); +extern void rv370_pcie_gart_disable(struct radeon_device *rdev); /* * r420,r423,rv410 @@ -171,6 +186,10 @@ extern void r420_fini(struct radeon_device *rdev); extern int r420_suspend(struct radeon_device *rdev); extern int r420_resume(struct radeon_device *rdev); extern void r420_pm_init_profile(struct radeon_device *rdev); +extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg); +extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v); +extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev); +extern void r420_pipes_init(struct radeon_device *rdev); /* * rs400,rs480 @@ -183,6 +202,12 @@ void rs400_gart_tlb_flush(struct radeon_device *rdev); int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +int rs400_gart_init(struct radeon_device *rdev); +int rs400_gart_enable(struct radeon_device *rdev); +void rs400_gart_adjust_size(struct radeon_device *rdev); +void rs400_gart_disable(struct radeon_device *rdev); +void rs400_gart_fini(struct radeon_device *rdev); + /* * rs600. @@ -194,6 +219,7 @@ extern int rs600_suspend(struct radeon_device *rdev); extern int rs600_resume(struct radeon_device *rdev); int rs600_irq_set(struct radeon_device *rdev); int rs600_irq_process(struct radeon_device *rdev); +void rs600_irq_disable(struct radeon_device *rdev); u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc); void rs600_gart_tlb_flush(struct radeon_device *rdev); int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); @@ -211,6 +237,8 @@ extern void rs600_pm_finish(struct radeon_device *rdev); extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc); extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc); +void rs600_set_safe_registers(struct radeon_device *rdev); + /* * rs690,rs740 @@ -222,10 +250,21 @@ int rs690_suspend(struct radeon_device *rdev); uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs690_bandwidth_update(struct radeon_device *rdev); +void rs690_line_buffer_adjust(struct radeon_device *rdev, + struct drm_display_mode *mode1, + struct drm_display_mode *mode2); /* * rv515 */ +struct rv515_mc_save { + u32 d1vga_control; + u32 d2vga_control; + u32 vga_render_control; + u32 vga_hdp_control; + u32 d1crtc_control; + u32 d2crtc_control; +}; int rv515_init(struct radeon_device *rdev); void rv515_fini(struct radeon_device *rdev); uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); @@ -236,6 +275,14 @@ void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rv515_bandwidth_update(struct radeon_device *rdev); int rv515_resume(struct radeon_device *rdev); int rv515_suspend(struct radeon_device *rdev); +void rv515_bandwidth_avivo_update(struct radeon_device *rdev); +void rv515_vga_render_disable(struct radeon_device *rdev); +void rv515_set_safe_registers(struct radeon_device *rdev); +void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save); +void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save); +void rv515_clock_startup(struct radeon_device *rdev); +void rv515_debugfs(struct radeon_device *rdev); + /* * r520,rv530,rv560,rv570,r580 -- cgit v1.2.3 From 976513dbfc1547c7b1822566923058655f0c32fd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 7 Jan 2011 01:43:44 +0100 Subject: PM / ACPI: Move NVS saving and restoring code to drivers/acpi The saving of the ACPI NVS area during hibernation and suspend and restoring it during the subsequent resume is entirely specific to ACPI, so move it to drivers/acpi and drop the CONFIG_SUSPEND_NVS configuration option which is redundant. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- arch/x86/kernel/e820.c | 1 + drivers/acpi/Makefile | 2 +- drivers/acpi/internal.h | 8 +++ drivers/acpi/nvs.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 9 +++ include/linux/suspend.h | 17 ------ kernel/power/Kconfig | 5 -- kernel/power/Makefile | 1 - kernel/power/nvs.c | 142 ------------------------------------------------ 9 files changed, 161 insertions(+), 166 deletions(-) create mode 100644 drivers/acpi/nvs.c delete mode 100644 kernel/power/nvs.c (limited to 'drivers') diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 0c2b7ef7a34d..294f26da0c0c 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3d031d02e54b..9cc9f2c4da79 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -24,7 +24,7 @@ acpi-y += atomicio.o # sleep related files acpi-y += wakeup.o acpi-y += sleep.o -acpi-$(CONFIG_ACPI_SLEEP) += proc.o +acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o # diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a212bfeddf8c..7c23b76e8eca 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -82,8 +82,16 @@ extern int acpi_sleep_init(void); #ifdef CONFIG_ACPI_SLEEP int acpi_sleep_proc_init(void); +int suspend_nvs_alloc(void); +void suspend_nvs_free(void); +int suspend_nvs_save(void); +void suspend_nvs_restore(void); #else static inline int acpi_sleep_proc_init(void) { return 0; } +static inline int suspend_nvs_alloc(void) { return 0; } +static inline void suspend_nvs_free(void) {} +static inline int suspend_nvs_save(void) {} +static inline void suspend_nvs_restore(void) {} #endif #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c new file mode 100644 index 000000000000..57c6fabbb6b6 --- /dev/null +++ b/drivers/acpi/nvs.c @@ -0,0 +1,142 @@ +/* + * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory + * + * Copyright (C) 2008,2009 Rafael J. Wysocki , Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Platforms, like ACPI, may want us to save some memory used by them during + * suspend and to restore the contents of this memory during the subsequent + * resume. The code below implements a mechanism allowing us to do that. + */ + +struct nvs_page { + unsigned long phys_start; + unsigned int size; + void *kaddr; + void *data; + struct list_head node; +}; + +static LIST_HEAD(nvs_list); + +/** + * suspend_nvs_register - register platform NVS memory region to save + * @start - physical address of the region + * @size - size of the region + * + * The NVS region need not be page-aligned (both ends) and we arrange + * things so that the data from page-aligned addresses in this region will + * be copied into separate RAM pages. + */ +int suspend_nvs_register(unsigned long start, unsigned long size) +{ + struct nvs_page *entry, *next; + + while (size > 0) { + unsigned int nr_bytes; + + entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); + if (!entry) + goto Error; + + list_add_tail(&entry->node, &nvs_list); + entry->phys_start = start; + nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); + entry->size = (size < nr_bytes) ? size : nr_bytes; + + start += entry->size; + size -= entry->size; + } + return 0; + + Error: + list_for_each_entry_safe(entry, next, &nvs_list, node) { + list_del(&entry->node); + kfree(entry); + } + return -ENOMEM; +} + +/** + * suspend_nvs_free - free data pages allocated for saving NVS regions + */ +void suspend_nvs_free(void) +{ + struct nvs_page *entry; + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + free_page((unsigned long)entry->data); + entry->data = NULL; + if (entry->kaddr) { + iounmap(entry->kaddr); + entry->kaddr = NULL; + } + } +} + +/** + * suspend_nvs_alloc - allocate memory necessary for saving NVS regions + */ +int suspend_nvs_alloc(void) +{ + struct nvs_page *entry; + + list_for_each_entry(entry, &nvs_list, node) { + entry->data = (void *)__get_free_page(GFP_KERNEL); + if (!entry->data) { + suspend_nvs_free(); + return -ENOMEM; + } + } + return 0; +} + +/** + * suspend_nvs_save - save NVS memory regions + */ +int suspend_nvs_save(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Saving platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) { + entry->kaddr = ioremap(entry->phys_start, entry->size); + if (!entry->kaddr) { + suspend_nvs_free(); + return -ENOMEM; + } + memcpy(entry->data, entry->kaddr, entry->size); + } + + return 0; +} + +/** + * suspend_nvs_restore - restore NVS memory regions + * + * This function is going to be called with interrupts disabled, so it + * cannot iounmap the virtual addresses used to access the NVS region. + */ +void suspend_nvs_restore(void) +{ + struct nvs_page *entry; + + printk(KERN_INFO "PM: Restoring platform NVS memory\n"); + + list_for_each_entry(entry, &nvs_list, node) + if (entry->data) + memcpy(entry->kaddr, entry->data, entry->size); +} diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 67c91b4418b0..fa7ed6a983d0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -254,6 +254,15 @@ void __init acpi_old_suspend_ordering(void); void __init acpi_nvs_nosave(void); #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_ACPI_SLEEP +int suspend_nvs_register(unsigned long start, unsigned long size); +#else +static inline int suspend_nvs_register(unsigned long a, unsigned long b) +{ + return 0; +} +#endif + struct acpi_osc_context { char *uuid_str; /* uuid string */ int rev; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index acb7d911bb0c..0e288e3c37be 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -258,23 +258,6 @@ static inline int hibernate(void) { return -ENOSYS; } static inline bool system_entering_hibernation(void) { return false; } #endif /* CONFIG_HIBERNATION */ -#ifdef CONFIG_SUSPEND_NVS -extern int suspend_nvs_register(unsigned long start, unsigned long size); -extern int suspend_nvs_alloc(void); -extern void suspend_nvs_free(void); -extern int suspend_nvs_save(void); -extern void suspend_nvs_restore(void); -#else /* CONFIG_SUSPEND_NVS */ -static inline int suspend_nvs_register(unsigned long a, unsigned long b) -{ - return 0; -} -static inline int suspend_nvs_alloc(void) { return 0; } -static inline void suspend_nvs_free(void) {} -static inline int suspend_nvs_save(void) {} -static inline void suspend_nvs_restore(void) {} -#endif /* CONFIG_SUSPEND_NVS */ - #ifdef CONFIG_PM_SLEEP void save_processor_state(void); void restore_processor_state(void); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index a5aff3ebad38..265729966ece 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -100,13 +100,9 @@ config PM_SLEEP_ADVANCED_DEBUG depends on PM_ADVANCED_DEBUG default n -config SUSPEND_NVS - bool - config SUSPEND bool "Suspend to RAM and standby" depends on PM && ARCH_SUSPEND_POSSIBLE - select SUSPEND_NVS if HAS_IOMEM default y ---help--- Allow the system to enter sleep states in which main memory is @@ -140,7 +136,6 @@ config HIBERNATION depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE select LZO_COMPRESS select LZO_DECOMPRESS - select SUSPEND_NVS if HAS_IOMEM ---help--- Enable the suspend to disk (STD) functionality, which is usually called "hibernation" in user interfaces. STD checkpoints the diff --git a/kernel/power/Makefile b/kernel/power/Makefile index f9063c6b185d..120a15823325 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -10,6 +10,5 @@ obj-$(CONFIG_SUSPEND) += suspend.o obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \ block_io.o -obj-$(CONFIG_SUSPEND_NVS) += nvs.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o diff --git a/kernel/power/nvs.c b/kernel/power/nvs.c deleted file mode 100644 index 57c6fabbb6b6..000000000000 --- a/kernel/power/nvs.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory - * - * Copyright (C) 2008,2009 Rafael J. Wysocki , Novell Inc. - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include - -/* - * Platforms, like ACPI, may want us to save some memory used by them during - * suspend and to restore the contents of this memory during the subsequent - * resume. The code below implements a mechanism allowing us to do that. - */ - -struct nvs_page { - unsigned long phys_start; - unsigned int size; - void *kaddr; - void *data; - struct list_head node; -}; - -static LIST_HEAD(nvs_list); - -/** - * suspend_nvs_register - register platform NVS memory region to save - * @start - physical address of the region - * @size - size of the region - * - * The NVS region need not be page-aligned (both ends) and we arrange - * things so that the data from page-aligned addresses in this region will - * be copied into separate RAM pages. - */ -int suspend_nvs_register(unsigned long start, unsigned long size) -{ - struct nvs_page *entry, *next; - - while (size > 0) { - unsigned int nr_bytes; - - entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL); - if (!entry) - goto Error; - - list_add_tail(&entry->node, &nvs_list); - entry->phys_start = start; - nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK); - entry->size = (size < nr_bytes) ? size : nr_bytes; - - start += entry->size; - size -= entry->size; - } - return 0; - - Error: - list_for_each_entry_safe(entry, next, &nvs_list, node) { - list_del(&entry->node); - kfree(entry); - } - return -ENOMEM; -} - -/** - * suspend_nvs_free - free data pages allocated for saving NVS regions - */ -void suspend_nvs_free(void) -{ - struct nvs_page *entry; - - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) { - free_page((unsigned long)entry->data); - entry->data = NULL; - if (entry->kaddr) { - iounmap(entry->kaddr); - entry->kaddr = NULL; - } - } -} - -/** - * suspend_nvs_alloc - allocate memory necessary for saving NVS regions - */ -int suspend_nvs_alloc(void) -{ - struct nvs_page *entry; - - list_for_each_entry(entry, &nvs_list, node) { - entry->data = (void *)__get_free_page(GFP_KERNEL); - if (!entry->data) { - suspend_nvs_free(); - return -ENOMEM; - } - } - return 0; -} - -/** - * suspend_nvs_save - save NVS memory regions - */ -int suspend_nvs_save(void) -{ - struct nvs_page *entry; - - printk(KERN_INFO "PM: Saving platform NVS memory\n"); - - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) { - entry->kaddr = ioremap(entry->phys_start, entry->size); - if (!entry->kaddr) { - suspend_nvs_free(); - return -ENOMEM; - } - memcpy(entry->data, entry->kaddr, entry->size); - } - - return 0; -} - -/** - * suspend_nvs_restore - restore NVS memory regions - * - * This function is going to be called with interrupts disabled, so it - * cannot iounmap the virtual addresses used to access the NVS region. - */ -void suspend_nvs_restore(void) -{ - struct nvs_page *entry; - - printk(KERN_INFO "PM: Restoring platform NVS memory\n"); - - list_for_each_entry(entry, &nvs_list, node) - if (entry->data) - memcpy(entry->kaddr, entry->data, entry->size); -} -- cgit v1.2.3 From d146df18c13d16e321efa8ef9b57c95c3bec1722 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 7 Jan 2011 01:44:28 +0100 Subject: ACPI / PM: Update file information and the list of includes in nvs.c The file information and the list of include in drivers/acpi/nvs.c are outdated, so update them. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/nvs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 57c6fabbb6b6..7d648092427e 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -1,7 +1,7 @@ /* - * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory + * nvs.c - Routines for saving and restoring ACPI NVS memory region * - * Copyright (C) 2008,2009 Rafael J. Wysocki , Novell Inc. + * Copyright (C) 2008-2011 Rafael J. Wysocki , Novell Inc. * * This file is released under the GPLv2. */ @@ -11,7 +11,7 @@ #include #include #include -#include +#include /* * Platforms, like ACPI, may want us to save some memory used by them during -- cgit v1.2.3 From ca9b600be38c73b7d25acfb8b7e4e9a9e941d881 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 7 Jan 2011 01:45:58 +0100 Subject: ACPI / PM: Make suspend_nvs_save() use acpi_os_map_memory() It turns out that the NVS memory region that suspend_nvs_save() attempts to map has been already mapped by acpi_os_map_memory(), so suspend_nvs_save() should better use acpi_os_map_memory() for mapping memory to avoid conflicts. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/nvs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 7d648092427e..54b6ab8040a6 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * Platforms, like ACPI, may want us to save some memory used by them during @@ -79,7 +80,7 @@ void suspend_nvs_free(void) free_page((unsigned long)entry->data); entry->data = NULL; if (entry->kaddr) { - iounmap(entry->kaddr); + acpi_os_unmap_memory(entry->kaddr, entry->size); entry->kaddr = NULL; } } @@ -113,7 +114,8 @@ int suspend_nvs_save(void) list_for_each_entry(entry, &nvs_list, node) if (entry->data) { - entry->kaddr = ioremap(entry->phys_start, entry->size); + entry->kaddr = acpi_os_map_memory(entry->phys_start, + entry->size); if (!entry->kaddr) { suspend_nvs_free(); return -ENOMEM; -- cgit v1.2.3 From 6d5bbf00d251cc73223a71422d69e069dc2e0b8d Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 7 Jan 2011 01:46:40 +0100 Subject: ACPI: Use ioremap_cache() Although the temporary boot-time ACPI table mappings were set up with CPU caching enabled, the permanent table mappings and AML run-time region memory accesses were set up with ioremap(), which on x86 is a synonym for ioremap_nocache(). Changing this to ioremap_cache() improves performance as seen when accessing the tables via acpidump, or /sys/firmware/acpi/tables. It should also improve AML run-time performance. No change on ia64. Reported-by: Jack Steiner Signed-off-by: Len Brown Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/io.h | 5 +++++ drivers/acpi/osl.c | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h index cc8335eb3110..e5a6c3530c6c 100644 --- a/arch/ia64/include/asm/io.h +++ b/arch/ia64/include/asm/io.h @@ -426,6 +426,11 @@ extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size) extern void iounmap (volatile void __iomem *addr); extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size); extern void early_iounmap (volatile void __iomem *addr, unsigned long size); +static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size) +{ + return ioremap(phys_addr, size); +} + /* * String version of IO memory access ops: diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 055d7b701fff..3a7b4879fd99 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -320,7 +320,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) pg_off = round_down(phys, PAGE_SIZE); pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; - virt = ioremap(pg_off, pg_sz); + virt = ioremap_cache(pg_off, pg_sz); if (!virt) { kfree(map); return NULL; @@ -642,7 +642,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) virt_addr = acpi_map_vaddr_lookup(phys_addr, size); rcu_read_unlock(); if (!virt_addr) { - virt_addr = ioremap(phys_addr, size); + virt_addr = ioremap_cache(phys_addr, size); unmap = 1; } if (!value) @@ -678,7 +678,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) virt_addr = acpi_map_vaddr_lookup(phys_addr, size); rcu_read_unlock(); if (!virt_addr) { - virt_addr = ioremap(phys_addr, size); + virt_addr = ioremap_cache(phys_addr, size); unmap = 1; } -- cgit v1.2.3 From 9cd031441a4fd09273b7c2beb337d0b2683d104c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:32:23 +0100 Subject: ACPI / ACPICA: Fix global lock acquisition There are two problems with the ACPICA's current implementation of the global lock acquisition. First, acpi_ev_global_lock_handler(), which in fact is an interface to the outside of the kernel, doesn't validate its input, so it only works correctly if the other side (i.e. the ACPI firmware) is fully specification-compliant (as far as the global lock is concerned). Unfortunately, that's known not to be the case on some systems (i.e. we get spurious global lock signaling interrupts without the pending flag set on some systems). Second, acpi_ev_global_lock_handler() attempts to acquire the global lock on behalf of a thread waiting for it without checking if there actually is such a thread. Both of these shortcomings need to be addressed to prevent all possible race conditions from happening. Rework acpi_ev_global_lock_handler() so that it doesn't try to acquire the global lock and make it signal the availability of the global lock to the waiting thread instead. Make sure that the availability of the global lock can only be signaled when there is a thread waiting for it and that it can't be signaled more than once in a row (to keep acpi_gbl_global_lock_semaphore in balance). Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/acpica/evmisc.c | 94 ++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index fcaed9fb44ff..8e31bb5a973a 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -284,41 +284,41 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) * RETURN: ACPI_INTERRUPT_HANDLED * * DESCRIPTION: Invoked directly from the SCI handler when a global lock - * release interrupt occurs. Attempt to acquire the global lock, - * if successful, signal the thread waiting for the lock. + * release interrupt occurs. If there's a thread waiting for + * the global lock, signal it. * * NOTE: Assumes that the semaphore can be signaled from interrupt level. If * this is not possible for some reason, a separate thread will have to be * scheduled to do this. * ******************************************************************************/ +static u8 acpi_ev_global_lock_pending; +static spinlock_t _acpi_ev_global_lock_pending_lock; +#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock static u32 acpi_ev_global_lock_handler(void *context) { - u8 acquired = FALSE; + acpi_status status; + acpi_cpu_flags flags; - /* - * Attempt to get the lock. - * - * If we don't get it now, it will be marked pending and we will - * take another interrupt when it becomes free. - */ - ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); - if (acquired) { + flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock); - /* Got the lock, now wake all threads waiting for it */ + if (!acpi_ev_global_lock_pending) { + goto out; + } - acpi_gbl_global_lock_acquired = TRUE; - /* Send a unit to the semaphore */ + /* Send a unit to the semaphore */ - if (ACPI_FAILURE - (acpi_os_signal_semaphore - (acpi_gbl_global_lock_semaphore, 1))) { - ACPI_ERROR((AE_INFO, - "Could not signal Global Lock semaphore")); - } + status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore")); } + acpi_ev_global_lock_pending = FALSE; + + out: + acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags); + return (ACPI_INTERRUPT_HANDLED); } @@ -415,6 +415,7 @@ static int acpi_ev_global_lock_acquired; acpi_status acpi_ev_acquire_global_lock(u16 timeout) { + acpi_cpu_flags flags; acpi_status status = AE_OK; u8 acquired = FALSE; @@ -467,32 +468,47 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) return_ACPI_STATUS(AE_OK); } - /* Attempt to acquire the actual hardware lock */ + flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock); + + do { + + /* Attempt to acquire the actual hardware lock */ + + ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); + if (acquired) { + acpi_gbl_global_lock_acquired = TRUE; + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Acquired hardware Global Lock\n")); + break; + } - ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); - if (acquired) { + acpi_ev_global_lock_pending = TRUE; - /* We got the lock */ + acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags); + /* + * Did not get the lock. The pending bit was set above, and we + * must wait until we get the global lock released interrupt. + */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Acquired hardware Global Lock\n")); + "Waiting for hardware Global Lock\n")); - acpi_gbl_global_lock_acquired = TRUE; - return_ACPI_STATUS(AE_OK); - } + /* + * Wait for handshake with the global lock interrupt handler. + * This interface releases the interpreter if we must wait. + */ + status = acpi_ex_system_wait_semaphore( + acpi_gbl_global_lock_semaphore, + ACPI_WAIT_FOREVER); - /* - * Did not get the lock. The pending bit was set above, and we must now - * wait until we get the global lock released interrupt. - */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n")); + flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock); - /* - * Wait for handshake with the global lock interrupt handler. - * This interface releases the interpreter if we must wait. - */ - status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, - ACPI_WAIT_FOREVER); + } while (ACPI_SUCCESS(status)); + + acpi_ev_global_lock_pending = FALSE; + + acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags); return_ACPI_STATUS(status); } -- cgit v1.2.3 From b014f4f1aad3f25d5c7d877a394869645ea0c96b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:33:30 +0100 Subject: ACPI / PM: Do not enable multiple devices to wake up simultaneously If a device is enabled to wake up the system from sleep states via /proc/acpi/wakeup and there are other devices associated with the same wakeup GPE, all of these devices are automatically enabled to wake up the system. This isn't correct, because the fact the GPE is shared need not imply that wakeup power has to be enabled for all the devices at the same time (i.e. it is possible that one device will have its wakeup power enabled and it will wake up the system from a sleep state if the shared wakeup GPE is enabled, while another device having its wakeup power disabled will not wake up the system even though the GPE is enabled). Rework acpi_system_write_wakeup_device() so that it only enables wakeup for one device at a time. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/proc.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index afad67769db6..129effbb7bd4 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -341,7 +341,6 @@ acpi_system_write_wakeup_device(struct file *file, char strbuf[5]; char str[5] = ""; unsigned int len = count; - struct acpi_device *found_dev = NULL; if (len > 4) len = 4; @@ -363,33 +362,10 @@ acpi_system_write_wakeup_device(struct file *file, if (!strncmp(dev->pnp.bus_id, str, 4)) { dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0 : 1; - found_dev = dev; + physical_device_enable_wakeup(dev); break; } } - if (found_dev) { - physical_device_enable_wakeup(found_dev); - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct - acpi_device, - wakeup_list); - - if ((dev != found_dev) && - (dev->wakeup.gpe_number == - found_dev->wakeup.gpe_number) - && (dev->wakeup.gpe_device == - found_dev->wakeup.gpe_device)) { - printk(KERN_WARNING - "ACPI: '%s' and '%s' have the same GPE, " - "can't disable/enable one separately\n", - dev->pnp.bus_id, found_dev->pnp.bus_id); - dev->wakeup.state.enabled = - found_dev->wakeup.state.enabled; - physical_device_enable_wakeup(dev); - } - } - } mutex_unlock(&acpi_device_lock); return count; } -- cgit v1.2.3 From f2b56bc808addb908a5bf435d9b942c02af9a7c4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:34:22 +0100 Subject: ACPI / PM: Use device wakeup flags for handling ACPI wakeup devices There are ACPI devices (buttons and the laptop lid) that can wake up the system from sleep states and have no "physical" companion devices. The ACPI subsystem uses two flags, wakeup.state.enabled and wakeup.flags.always_enabled, for handling those devices, but they are not accessible through the standard device wakeup infrastructure. User space can only control them via the /proc/acpi/wakeup interface that is not really convenient (e.g. the way in which devices are enabled to wake up the system is not portable between different systems, because it requires one to know the devices' "names" used in the system's ACPI tables). To address this problem, use standard device wakeup flags instead of the special ACPI flags for handling those devices. In particular, use device_set_wakeup_capable() to mark the ACPI wakeup devices during initialization and use device_set_wakeup_enable() to allow or disallow them to wake up the system from sleep states. Rework the /proc/acpi/wakeup interface to take these changes into account. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/button.c | 4 ++-- drivers/acpi/proc.c | 19 +++++++++++++------ drivers/acpi/scan.c | 2 +- drivers/acpi/wakeup.c | 18 ++++++++++-------- 4 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 71ef9cd0735f..234c104fcdd8 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -426,7 +426,7 @@ static int acpi_button_add(struct acpi_device *device) acpi_enable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); device->wakeup.run_wake_count++; - device->wakeup.state.enabled = 1; + device_set_wakeup_enable(&device->dev, true); } printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); @@ -449,7 +449,7 @@ static int acpi_button_remove(struct acpi_device *device, int type) acpi_disable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); device->wakeup.run_wake_count--; - device->wakeup.state.enabled = 0; + device_set_wakeup_enable(&device->dev, false); } acpi_button_remove_fs(device); diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 129effbb7bd4..f5f986991b52 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -311,7 +311,9 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) dev->pnp.bus_id, (u32) dev->wakeup.sleep_state, dev->wakeup.flags.run_wake ? '*' : ' ', - dev->wakeup.state.enabled ? "enabled" : "disabled"); + (device_may_wakeup(&dev->dev) + || (ldev && device_may_wakeup(ldev))) ? + "enabled" : "disabled"); if (ldev) seq_printf(seq, "%s:%s", ldev->bus ? ldev->bus->name : "no-bus", @@ -328,8 +330,10 @@ static void physical_device_enable_wakeup(struct acpi_device *adev) { struct device *dev = acpi_get_physical_device(adev->handle); - if (dev && device_can_wakeup(dev)) - device_set_wakeup_enable(dev, adev->wakeup.state.enabled); + if (dev && device_can_wakeup(dev)) { + bool enable = !device_may_wakeup(dev); + device_set_wakeup_enable(dev, enable); + } } static ssize_t @@ -360,9 +364,12 @@ acpi_system_write_wakeup_device(struct file *file, continue; if (!strncmp(dev->pnp.bus_id, str, 4)) { - dev->wakeup.state.enabled = - dev->wakeup.state.enabled ? 0 : 1; - physical_device_enable_wakeup(dev); + if (device_can_wakeup(&dev->dev)) { + bool enable = !device_may_wakeup(&dev->dev); + device_set_wakeup_enable(&dev->dev, enable); + } else { + physical_device_enable_wakeup(dev); + } break; } } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 29ef505c487b..bf7acbff1f5f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -803,7 +803,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) { device->wakeup.flags.run_wake = 1; - device->wakeup.flags.always_enabled = 1; + device_set_wakeup_capable(&device->dev, true); return; } diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index f62a50c3ed34..f252d0de9922 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -37,11 +37,12 @@ void acpi_enable_wakeup_devices(u8 sleep_state) container_of(node, struct acpi_device, wakeup_list); if (!dev->wakeup.flags.valid - || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count) - || sleep_state > (u32) dev->wakeup.sleep_state) + || sleep_state > (u32) dev->wakeup.sleep_state + || !(device_may_wakeup(&dev->dev) + || dev->wakeup.prepare_count)) continue; - if (dev->wakeup.state.enabled) + if (device_may_wakeup(&dev->dev)) acpi_enable_wakeup_device_power(dev, sleep_state); /* The wake-up power should have been enabled already. */ @@ -63,14 +64,15 @@ void acpi_disable_wakeup_devices(u8 sleep_state) container_of(node, struct acpi_device, wakeup_list); if (!dev->wakeup.flags.valid - || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count) - || (sleep_state > (u32) dev->wakeup.sleep_state)) + || sleep_state > (u32) dev->wakeup.sleep_state + || !(device_may_wakeup(&dev->dev) + || dev->wakeup.prepare_count)) continue; acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_GPE_DISABLE); - if (dev->wakeup.state.enabled) + if (device_may_wakeup(&dev->dev)) acpi_disable_wakeup_device_power(dev); } } @@ -84,8 +86,8 @@ int __init acpi_wakeup_device_init(void) struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - if (dev->wakeup.flags.always_enabled) - dev->wakeup.state.enabled = 1; + if (device_can_wakeup(&dev->dev)) + device_set_wakeup_enable(&dev->dev, true); } mutex_unlock(&acpi_device_lock); return 0; -- cgit v1.2.3 From 7fa69baf29de8c77a6b32c054df2abb8f11f8aa4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:35:10 +0100 Subject: ACPI / PM: Drop special ACPI wakeup flags Drop special ACPI wakeup flags, wakeup.state.enabled and wakeup.flags.always_enabled, that aren't necessary any more after we've started to use standard device wakeup flags for handling ACPI wakeup devices. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/glue.c | 5 +---- include/acpi/acpi_bus.h | 6 ------ 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 78b0164c35b2..7c47ed55e528 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -167,11 +167,8 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) "firmware_node"); ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, "physical_node"); - if (acpi_dev->wakeup.flags.valid) { + if (acpi_dev->wakeup.flags.valid) device_set_wakeup_capable(dev, true); - device_set_wakeup_enable(dev, - acpi_dev->wakeup.state.enabled); - } } return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 359ef11725a6..f2499f572109 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -242,20 +242,14 @@ struct acpi_device_perf { struct acpi_device_wakeup_flags { u8 valid:1; /* Can successfully enable wakeup? */ u8 run_wake:1; /* Run-Wake GPE devices */ - u8 always_enabled:1; /* Run-wake devices that are always enabled */ u8 notifier_present:1; /* Wake-up notify handler has been installed */ }; -struct acpi_device_wakeup_state { - u8 enabled:1; -}; - struct acpi_device_wakeup { acpi_handle gpe_device; u64 gpe_number; u64 sleep_state; struct acpi_handle_list resources; - struct acpi_device_wakeup_state state; struct acpi_device_wakeup_flags flags; int prepare_count; int run_wake_count; -- cgit v1.2.3 From 1f83511bd8f44b8a9e2d82263b2c95f26a625fcc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:36:01 +0100 Subject: ACPI / PM: Report wakeup events from buttons Since ACPI buttons and lids can be configured to wake up the system from sleep states, report wakeup events from these devices. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/button.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 234c104fcdd8..76bbb78a5ad9 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -279,6 +279,9 @@ static int acpi_lid_send_state(struct acpi_device *device) input_report_switch(button->input, SW_LID, !state); input_sync(button->input); + if (state) + pm_wakeup_event(&device->dev, 0); + ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); if (ret == NOTIFY_DONE) ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, @@ -314,6 +317,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) input_sync(input); input_report_key(input, keycode, 0); input_sync(input); + + pm_wakeup_event(&device->dev, 0); } acpi_bus_generate_proc_event(device, event, ++button->pushed); -- cgit v1.2.3 From 7b330707dddab1ad772898c1c82516342a551173 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:37:01 +0100 Subject: ACPI / PM: Blacklist Averatec machine known to require acpi_sleep=nonvs Apparently, Averatec AV1020-ED2 does not resume correctly without acpi_sleep=nonvs, so add it to the ACPI sleep blacklist. References: https://bugzilla.kernel.org/show_bug.cgi?id=16396#c86 Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index febb153b5a68..ddc5cce508a1 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -435,6 +435,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), }, }, + { + .callback = init_nvs_nosave, + .ident = "Averatec AV1020-ED2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ -- cgit v1.2.3 From d5dc9ac3f6daf7df45c49e5a861c733a5f794c6b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 6 Jan 2011 23:01:02 -0800 Subject: Input: ad7879 - convert I2C to dev_pm_ops There is a general move towards the use of dev_pm_ops rather than bus specific suspend APIs as this simplifies both the bus and PM core implementations. Convert the ad7879-ts I2C support over. Compile tested only. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-i2c.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index d82a38ee9a3e..4e4e58cec6c8 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -10,14 +10,16 @@ #include #include #include +#include #include "ad7879.h" #define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */ #ifdef CONFIG_PM -static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message) +static int ad7879_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct ad7879 *ts = i2c_get_clientdata(client); ad7879_suspend(ts); @@ -25,17 +27,17 @@ static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message) return 0; } -static int ad7879_i2c_resume(struct i2c_client *client) +static int ad7879_i2c_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct ad7879 *ts = i2c_get_clientdata(client); ad7879_resume(ts); return 0; } -#else -# define ad7879_i2c_suspend NULL -# define ad7879_i2c_resume NULL + +static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume); #endif /* All registers are word-sized. @@ -117,11 +119,12 @@ static struct i2c_driver ad7879_i2c_driver = { .driver = { .name = "ad7879", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &ad7879_i2c_pm, +#endif }, .probe = ad7879_i2c_probe, .remove = __devexit_p(ad7879_i2c_remove), - .suspend = ad7879_i2c_suspend, - .resume = ad7879_i2c_resume, .id_table = ad7879_id, }; -- cgit v1.2.3 From 85012fff38302e0262f838431e853f8c09e754d5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 6 Jan 2011 23:01:02 -0800 Subject: Input: eeti_ts - convert to dev_pm_ops There is a general move towards the use of dev_pm_ops rather than bus specific suspend APIs as this simplifies both the bus and PM core implementations. Convert the eeti_ts driver over. Compile tested only by me, but Sven Neumann reports that the new code works. Signed-off-by: Mark Brown Tested-by: Sven Neumann Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 7a3a916f84a8..7f8f538a9806 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -261,8 +261,9 @@ static int __devexit eeti_ts_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) +static int eeti_ts_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct eeti_ts_priv *priv = i2c_get_clientdata(client); struct input_dev *input_dev = priv->input; @@ -279,8 +280,9 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int eeti_ts_resume(struct i2c_client *client) +static int eeti_ts_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct eeti_ts_priv *priv = i2c_get_clientdata(client); struct input_dev *input_dev = priv->input; @@ -296,9 +298,8 @@ static int eeti_ts_resume(struct i2c_client *client) return 0; } -#else -#define eeti_ts_suspend NULL -#define eeti_ts_resume NULL + +static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); #endif static const struct i2c_device_id eeti_ts_id[] = { @@ -310,11 +311,12 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id); static struct i2c_driver eeti_ts_driver = { .driver = { .name = "eeti_ts", +#ifdef CONFIG_PM + .pm = &eeti_ts_pm, +#endif }, .probe = eeti_ts_probe, .remove = __devexit_p(eeti_ts_remove), - .suspend = eeti_ts_suspend, - .resume = eeti_ts_resume, .id_table = eeti_ts_id, }; -- cgit v1.2.3 From 92b672e217ddf87e4181454f8200f0f06139cdbc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 6 Jan 2011 23:01:03 -0800 Subject: Input: mcs5000_ts - convert to dev_pm_ops There is a general move towards the use of dev_pm_ops rather than bus specific suspend APIs as this simplifies both the bus and PM core implementations. Convert the mcs5000_ts driver over. Compile tested only. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mcs5000_ts.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index 6ee9940aaf5b..2d84c80ceb66 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -261,25 +261,27 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg) +static int mcs5000_ts_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + /* Touch sleep mode */ i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP); return 0; } -static int mcs5000_ts_resume(struct i2c_client *client) +static int mcs5000_ts_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct mcs5000_ts_data *data = i2c_get_clientdata(client); mcs5000_ts_phys_init(data); return 0; } -#else -#define mcs5000_ts_suspend NULL -#define mcs5000_ts_resume NULL + +static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume); #endif static const struct i2c_device_id mcs5000_ts_id[] = { @@ -291,10 +293,11 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id); static struct i2c_driver mcs5000_ts_driver = { .probe = mcs5000_ts_probe, .remove = __devexit_p(mcs5000_ts_remove), - .suspend = mcs5000_ts_suspend, - .resume = mcs5000_ts_resume, .driver = { .name = "mcs5000_ts", +#ifdef CONFIG_PM + .pm = &mcs5000_ts_pm, +#endif }, .id_table = mcs5000_ts_id, }; -- cgit v1.2.3 From d72e64ec0b134d26a89c736394ee0b638513bed8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 6 Jan 2011 23:01:03 -0800 Subject: Input: migor_ts - convert to dev_pm_ops There is a general move towards the use of dev_pm_ops rather than bus specific suspend APIs as this simplifies both the bus and PM core implementations. Convert the migor_ts driver over. Compile tested only. Signed-off-by: Mark Brown Acked-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/migor_ts.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index defe5dd3627c..5803bd0c1cca 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -226,8 +227,9 @@ static int migor_ts_remove(struct i2c_client *client) return 0; } -static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg) +static int migor_ts_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); if (device_may_wakeup(&client->dev)) @@ -236,8 +238,9 @@ static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int migor_ts_resume(struct i2c_client *client) +static int migor_ts_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); if (device_may_wakeup(&client->dev)) @@ -246,6 +249,8 @@ static int migor_ts_resume(struct i2c_client *client) return 0; } +static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume); + static const struct i2c_device_id migor_ts_id[] = { { "migor_ts", 0 }, { } @@ -255,11 +260,10 @@ MODULE_DEVICE_TABLE(i2c, migor_ts); static struct i2c_driver migor_ts_driver = { .driver = { .name = "migor_ts", + .pm = &migor_ts_pm, }, .probe = migor_ts_probe, .remove = migor_ts_remove, - .suspend = migor_ts_suspend, - .resume = migor_ts_resume, .id_table = migor_ts_id, }; -- cgit v1.2.3 From 93f38e914183c9b7af248fab793153772996987c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 6 Jan 2011 23:01:03 -0800 Subject: Input: cy8ctmg110_ts - Convert to dev_pm_ops There is a general move towards the use of dev_pm_ops rather than bus specific suspend APIs as this simplifies both the bus and PM core implementations. Convert the cy8ctmg110_ts driver over. Compile tested only. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cy8ctmg110_ts.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index d0c3a7229adf..a93c5c26ab3f 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -280,8 +280,9 @@ err_free_mem: } #ifdef CONFIG_PM -static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg) +static int cy8ctmg110_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct cy8ctmg110 *ts = i2c_get_clientdata(client); if (device_may_wakeup(&client->dev)) @@ -293,8 +294,9 @@ static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int cy8ctmg110_resume(struct i2c_client *client) +static int cy8ctmg110_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct cy8ctmg110 *ts = i2c_get_clientdata(client); if (device_may_wakeup(&client->dev)) @@ -305,6 +307,8 @@ static int cy8ctmg110_resume(struct i2c_client *client) } return 0; } + +static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); #endif static int __devexit cy8ctmg110_remove(struct i2c_client *client) @@ -335,14 +339,13 @@ static struct i2c_driver cy8ctmg110_driver = { .driver = { .owner = THIS_MODULE, .name = CY8CTMG110_DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &cy8ctmg110_pm, +#endif }, .id_table = cy8ctmg110_idtable, .probe = cy8ctmg110_probe, .remove = __devexit_p(cy8ctmg110_remove), -#ifdef CONFIG_PM - .suspend = cy8ctmg110_suspend, - .resume = cy8ctmg110_resume, -#endif }; static int __init cy8ctmg110_init(void) -- cgit v1.2.3 From b7908c1035af7652cd613991b54dbff9c8b6bd3a Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Thu, 6 Jan 2011 20:41:42 +0100 Subject: block: trace event block fix unassigned field The "error" field in block_bio_complete is not assigned, leaving the memory area uninitialized (keeping garbage data). Pass an additional tracepoint argument to this event to initialize this field. Signed-off-by: Jeff Moyer Signed-off-by: Mathieu Desnoyers CC: Steven Rostedt CC: Frederic Weisbecker CC: Ingo Molnar CC: Thomas Gleixner CC: Li Zefan CC: Alan.Brunelle@hp.com Signed-off-by: Jens Axboe --- drivers/md/dm.c | 2 +- include/trace/events/block.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0a2b5516bc21..f48a2f359ac4 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -630,7 +630,7 @@ static void dec_pending(struct dm_io *io, int error) queue_io(md, bio); } else { /* done with normal IO or empty flush */ - trace_block_bio_complete(md->queue, bio); + trace_block_bio_complete(md->queue, bio, io_error); bio_endio(bio, io_error); } } diff --git a/include/trace/events/block.h b/include/trace/events/block.h index b56c65dc105d..aba421d68f6f 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -206,15 +206,16 @@ TRACE_EVENT(block_bio_bounce, * block_bio_complete - completed all work on the block operation * @q: queue holding the block operation * @bio: block operation completed + * @error: io error value * * This tracepoint indicates there is no further work to do on this * block IO operation @bio. */ TRACE_EVENT(block_bio_complete, - TP_PROTO(struct request_queue *q, struct bio *bio), + TP_PROTO(struct request_queue *q, struct bio *bio, int error), - TP_ARGS(q, bio), + TP_ARGS(q, bio, error), TP_STRUCT__entry( __field( dev_t, dev ) @@ -228,6 +229,7 @@ TRACE_EVENT(block_bio_complete, __entry->dev = bio->bi_bdev->bd_dev; __entry->sector = bio->bi_sector; __entry->nr_sector = bio->bi_size >> 9; + __entry->error = error; blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); ), -- cgit v1.2.3 From 07cfe0e7a820ecad078c04e9c2a102521709145d Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 6 Jan 2011 20:29:53 +0100 Subject: drm/nouveau: fix hwmon device binding Bind the hwmon structs to nouveau device kobj. This makes sure the hwmon files are created in the device subdir in line with all other hwmon drivers. Signed-off-by: Lucas Stach Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_pm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index d93814160bcf..fb846a3fef15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -422,8 +422,7 @@ nouveau_hwmon_init(struct drm_device *dev) return ret; } dev_set_drvdata(hwmon_dev, dev); - ret = sysfs_create_group(&hwmon_dev->kobj, - &hwmon_attrgroup); + ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); if (ret) { NV_ERROR(dev, "Unable to create hwmon sysfs file: %d\n", ret); -- cgit v1.2.3 From 673a6092ce5f5bec45619b7a7f89cfcf8bcf3c41 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Thu, 6 Jan 2011 16:18:48 -0500 Subject: x86: Convert some devices to use DIE_NMIUNKNOWN They are a handful of places in the code that register a die_notifier as a catch all in case no claims the NMI. Unfortunately, they trigger on events like DIE_NMI and DIE_NMI_IPI, which depending on when they registered may collide with other handlers that have the ability to determine if the NMI is theirs or not. The function unknown_nmi_error() makes one last effort to walk the die_chain when no one else has claimed the NMI before spitting out messages that the NMI is unknown. This is a better spot for these devices to execute any code without colliding with the other handlers. The two drivers modified are only compiled on x86 arches I believe, so they shouldn't be affected by other arches that may not have DIE_NMIUNKNOWN defined. Signed-off-by: Don Zickus Cc: Russ Anderson Cc: Corey Minyard Cc: openipmi-developer@lists.sourceforge.net Cc: dann frazier Signed-off-by: Peter Zijlstra LKML-Reference: <1294348732-15030-3-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/x2apic_uv_x.c | 2 +- drivers/char/ipmi/ipmi_watchdog.c | 2 +- drivers/watchdog/hpwdt.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index c1c52c341f40..927902d90fe6 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -639,7 +639,7 @@ void __cpuinit uv_cpu_init(void) */ int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data) { - if (reason != DIE_NMI_IPI) + if (reason != DIE_NMIUNKNOWN) return NOTIFY_OK; if (in_crash_kexec) diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index f4d334f2536e..320668f4c3aa 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1081,7 +1081,7 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) { struct die_args *args = data; - if (val != DIE_NMI) + if (val != DIE_NMIUNKNOWN) return NOTIFY_OK; /* Hack, if it's a memory or I/O error, ignore it. */ diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index dea7b5bf6e2c..24b966d5061a 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -469,7 +469,7 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, unsigned long rom_pl; static int die_nmi_called; - if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) + if (ulReason != DIE_NMIUNKNOWN) goto out; if (!hpwdt_nmi_decoding) -- cgit v1.2.3 From 5369c02d951afc72d68f5f85089160a63d31ca37 Mon Sep 17 00:00:00 2001 From: Sreedhara DS Date: Fri, 22 Oct 2010 15:43:55 +0100 Subject: intel_scu_ipc: Utility driver for intel scu ipc This driver implements ioctl and interfaces with intel scu ipc driver. It is used to access pmic/msic registers from user space and firmware update utility. Signed-off-by: Sreedhara DS [Extensive clean up and debug] Signed-off-by: Alan Cox Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 9 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_scu_ipc.c | 4 +- drivers/platform/x86/intel_scu_ipcutil.c | 133 +++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 drivers/platform/x86/intel_scu_ipcutil.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index faec777b1ed4..65ba62086ca8 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -576,6 +576,15 @@ config INTEL_SCU_IPC some embedded Intel x86 platforms. This is not needed for PC-type machines. +config INTEL_SCU_IPC_UTIL + tristate "Intel SCU IPC utility driver" + depends on INTEL_SCU_IPC + default y + ---help--- + The IPC Util driver provides an interface with the SCU enabling + low level access for debug work and updating the firmware. Say + N unless you will be doing this on an Intel MID platform. + config GPIO_INTEL_PMIC bool "Intel PMIC GPIO support" depends on INTEL_SCU_IPC && GPIOLIB diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 9950ccc940b5..4ec4ff8f9182 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o +obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o obj-$(CONFIG_INTEL_IPS) += intel_ips.o obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index ca35b0ce944a..1752ef006d26 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -497,7 +497,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); mutex_unlock(&ipclock); - return -1; + return -EIO; } mutex_unlock(&ipclock); return 0; @@ -642,7 +642,7 @@ update_end: if (status == IPC_FW_UPDATE_SUCCESS) return 0; - return -1; + return -EIO; } EXPORT_SYMBOL(intel_scu_ipc_fw_update); diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c new file mode 100644 index 000000000000..ba3231d0819e --- /dev/null +++ b/drivers/platform/x86/intel_scu_ipcutil.c @@ -0,0 +1,133 @@ +/* + * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism + * + * (C) Copyright 2008-2010 Intel Corporation + * Author: Sreedhara DS (sreedhara.ds@intel.com) + * + * 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; version 2 + * of the License. + * + * This driver provides ioctl interfaces to call intel scu ipc driver api + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 major; + +#define MAX_FW_SIZE 264192 + +/* ioctl commnds */ +#define INTE_SCU_IPC_REGISTER_READ 0 +#define INTE_SCU_IPC_REGISTER_WRITE 1 +#define INTE_SCU_IPC_REGISTER_UPDATE 2 +#define INTE_SCU_IPC_FW_UPDATE 0xA2 + +struct scu_ipc_data { + u32 count; /* No. of registers */ + u16 addr[5]; /* Register addresses */ + u8 data[5]; /* Register data */ + u8 mask; /* Valid for read-modify-write */ +}; + +/** + * scu_reg_access - implement register access ioctls + * @cmd: command we are doing (read/write/update) + * @data: kernel copy of ioctl data + * + * Allow the user to perform register accesses on the SCU via the + * kernel interface + */ + +static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) +{ + int count = data->count; + + if (count == 0 || count == 3 || count > 4) + return -EINVAL; + + switch (cmd) { + case INTE_SCU_IPC_REGISTER_READ: + return intel_scu_ipc_readv(data->addr, data->data, count); + case INTE_SCU_IPC_REGISTER_WRITE: + return intel_scu_ipc_writev(data->addr, data->data, count); + case INTE_SCU_IPC_REGISTER_UPDATE: + return intel_scu_ipc_update_register(data->addr[0], + data->data[0], data->mask); + default: + return -ENOTTY; + } +} + +/** + * scu_ipc_ioctl - control ioctls for the SCU + * @fp: file handle of the SCU device + * @cmd: ioctl coce + * @arg: pointer to user passed structure + * + * Support the I/O and firmware flashing interfaces of the SCU + */ +static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct scu_ipc_data data; + void __user *argp = (void __user *)arg; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (cmd == INTE_SCU_IPC_FW_UPDATE) { + u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL); + if (fwbuf == NULL) + return -ENOMEM; + if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) { + kfree(fwbuf); + return -EFAULT; + } + ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE); + kfree(fwbuf); + return ret; + } else { + if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) + return -EFAULT; + ret = scu_reg_access(cmd, &data); + if (ret < 0) + return ret; + if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) + return -EFAULT; + return 0; + } +} + +static const struct file_operations scu_ipc_fops = { + .unlocked_ioctl = scu_ipc_ioctl, +}; + +static int __init ipc_module_init(void) +{ + return register_chrdev(0, "intel_mid_scu", &scu_ipc_fops); +} + +static void __exit ipc_module_exit(void) +{ + unregister_chrdev(major, "intel_mid_scu"); +} + +module_init(ipc_module_init); +module_exit(ipc_module_exit); + +MODULE_LICENSE("GPL V2"); +MODULE_DESCRIPTION("Utility driver for intel scu ipc"); +MODULE_AUTHOR("Sreedhara "); -- cgit v1.2.3 From 3098064d3b4a9bf9d2855b2a89599ad77695e324 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 19:04:38 -0800 Subject: drivers/platform/x86: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: Matthew Garrett --- drivers/platform/x86/classmate-laptop.c | 2 +- drivers/platform/x86/thinkpad_acpi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 341cbfef93ee..d2b7720c0e6f 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -653,7 +653,7 @@ static void cmpc_keys_handler(struct acpi_device *dev, u32 event) if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes)) code = cmpc_keys_codes[event & 0x0F]; - inputdev = dev_get_drvdata(&dev->dev);; + inputdev = dev_get_drvdata(&dev->dev); input_report_key(inputdev, code, !(event & 0x10)); } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e8c21994b36d..f372dc7ae14e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6345,7 +6345,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) "as change notification\n"); tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | TP_ACPI_HKEY_BRGHTUP_MASK - | TP_ACPI_HKEY_BRGHTDWN_MASK);; + | TP_ACPI_HKEY_BRGHTDWN_MASK); return 0; } -- cgit v1.2.3 From 58f6425eb92f54943878b0b3f9c1e51f99c2cb72 Mon Sep 17 00:00:00 2001 From: Colin King Date: Fri, 19 Nov 2010 15:40:02 +0000 Subject: WMI: Cater for multiple events with same GUID WMI data blocks can contain WMI events with the same GUID but with different notifiy_ids, for example volume up/down hotkeys. This patch enables a single event handler to be registered and unregistered against all events with same GUID but different notify_ids. Since an event handler is passed the notify_id of an event it can can differentiate between the different events. The patch also ensures we only register and unregister a device per unique GUID. Signed-off-by: Colin Ian King Signed-off-by: Matthew Garrett --- drivers/platform/x86/wmi.c | 133 ++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index aecd9a9b549f..b8e5383eab0c 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -549,21 +549,34 @@ acpi_status wmi_install_notify_handler(const char *guid, wmi_notify_handler handler, void *data) { struct wmi_block *block; - acpi_status status; + acpi_status status = AE_NOT_EXIST; + char tmp[16], guid_input[16]; + struct list_head *p; if (!guid || !handler) return AE_BAD_PARAMETER; - if (!find_guid(guid, &block)) - return AE_NOT_EXIST; + wmi_parse_guid(guid, tmp); + wmi_swap_bytes(tmp, guid_input); - if (block->handler && block->handler != wmi_notify_debug) - return AE_ALREADY_ACQUIRED; + list_for_each(p, &wmi_block_list) { + acpi_status wmi_status; + block = list_entry(p, struct wmi_block, list); - block->handler = handler; - block->handler_data = data; + if (memcmp(block->gblock.guid, guid_input, 16) == 0) { + if (block->handler && + block->handler != wmi_notify_debug) + return AE_ALREADY_ACQUIRED; - status = wmi_method_enable(block, 1); + block->handler = handler; + block->handler_data = data; + + wmi_status = wmi_method_enable(block, 1); + if ((wmi_status != AE_OK) || + ((wmi_status == AE_OK) && (status == AE_NOT_EXIST))) + status = wmi_status; + } + } return status; } @@ -577,24 +590,40 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler); acpi_status wmi_remove_notify_handler(const char *guid) { struct wmi_block *block; - acpi_status status = AE_OK; + acpi_status status = AE_NOT_EXIST; + char tmp[16], guid_input[16]; + struct list_head *p; if (!guid) return AE_BAD_PARAMETER; - if (!find_guid(guid, &block)) - return AE_NOT_EXIST; + wmi_parse_guid(guid, tmp); + wmi_swap_bytes(tmp, guid_input); - if (!block->handler || block->handler == wmi_notify_debug) - return AE_NULL_ENTRY; + list_for_each(p, &wmi_block_list) { + acpi_status wmi_status; + block = list_entry(p, struct wmi_block, list); - if (debug_event) { - block->handler = wmi_notify_debug; - } else { - status = wmi_method_enable(block, 0); - block->handler = NULL; - block->handler_data = NULL; + if (memcmp(block->gblock.guid, guid_input, 16) == 0) { + if (!block->handler || + block->handler == wmi_notify_debug) + return AE_NULL_ENTRY; + + if (debug_event) { + block->handler = wmi_notify_debug; + status = AE_OK; + } else { + wmi_status = wmi_method_enable(block, 0); + block->handler = NULL; + block->handler_data = NULL; + if ((wmi_status != AE_OK) || + ((wmi_status == AE_OK) && + (status == AE_NOT_EXIST))) + status = wmi_status; + } + } } + return status; } EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); @@ -705,22 +734,11 @@ static struct class wmi_class = { .dev_attrs = wmi_dev_attrs, }; -static struct wmi_block *wmi_create_device(const struct guid_block *gblock, - acpi_handle handle) +static int wmi_create_device(const struct guid_block *gblock, + struct wmi_block *wblock, acpi_handle handle) { - struct wmi_block *wblock; - int error; char guid_string[37]; - wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); - if (!wblock) { - error = -ENOMEM; - goto err_out; - } - - wblock->handle = handle; - wblock->gblock = *gblock; - wblock->dev.class = &wmi_class; wmi_gtoa(gblock->guid, guid_string); @@ -728,17 +746,7 @@ static struct wmi_block *wmi_create_device(const struct guid_block *gblock, dev_set_drvdata(&wblock->dev, wblock); - error = device_register(&wblock->dev); - if (error) - goto err_free; - - list_add_tail(&wblock->list, &wmi_block_list); - return wblock; - -err_free: - kfree(wblock); -err_out: - return ERR_PTR(error); + return device_register(&wblock->dev); } static void wmi_free_devices(void) @@ -747,7 +755,8 @@ static void wmi_free_devices(void) /* Delete devices for all the GUIDs */ list_for_each_entry_safe(wblock, next, &wmi_block_list, list) - device_unregister(&wblock->dev); + if (wblock->dev.class) + device_unregister(&wblock->dev); } static bool guid_already_parsed(const char *guid_string) @@ -770,7 +779,6 @@ static acpi_status parse_wdg(acpi_handle handle) union acpi_object *obj; const struct guid_block *gblock; struct wmi_block *wblock; - char guid_string[37]; acpi_status status; int retval; u32 i, total; @@ -792,28 +800,31 @@ static acpi_status parse_wdg(acpi_handle handle) total = obj->buffer.length / sizeof(struct guid_block); for (i = 0; i < total; i++) { + if (debug_dump_wdg) + wmi_dump_wdg(&gblock[i]); + + wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); + if (!wblock) + return AE_NO_MEMORY; + + wblock->handle = handle; + wblock->gblock = gblock[i]; + /* Some WMI devices, like those for nVidia hooks, have a duplicate GUID. It's not clear what we should do in this - case yet, so for now, we'll just ignore the duplicate. - Anyone who wants to add support for that device can come - up with a better workaround for the mess then. + case yet, so for now, we'll just ignore the duplicate + for device creation. */ - if (guid_already_parsed(gblock[i].guid) == true) { - wmi_gtoa(gblock[i].guid, guid_string); - pr_info("Skipping duplicate GUID %s\n", guid_string); - continue; + if (!guid_already_parsed(gblock[i].guid)) { + retval = wmi_create_device(&gblock[i], wblock, handle); + if (retval) { + wmi_free_devices(); + break; + } } - if (debug_dump_wdg) - wmi_dump_wdg(&gblock[i]); - - wblock = wmi_create_device(&gblock[i], handle); - if (IS_ERR(wblock)) { - retval = PTR_ERR(wblock); - wmi_free_devices(); - break; - } + list_add_tail(&wblock->list, &wmi_block_list); if (debug_event) { wblock->handler = wmi_notify_debug; -- cgit v1.2.3 From 698e1641a37f833dd26ee2fde5eed426cd97880b Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Tue, 30 Nov 2010 16:30:43 -0200 Subject: classmate-laptop: little optimization for cmpc_rfkill_block We don't need to call bios/acpi (cmpc_set_rfkill_wlan) if the blocked state is already set to the same value (little optimization). This can happen for example if we initialize the module with same initial hardware state (rfkill core always call cmpc_rfkill_block on initialization here). Also GWRI method only accepts 0 or 1 for setting rfkill block, as can be seen on AML code from acpidump->DSDT from a classmate sample I have, so should be fine setting state only to 0 or 1 directly. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Matthew Garrett Acked-by: Thadeu Lima de Souza Cascardo --- drivers/platform/x86/classmate-laptop.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index d2b7720c0e6f..3dabd00b1d5a 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -522,18 +522,20 @@ static int cmpc_rfkill_block(void *data, bool blocked) acpi_status status; acpi_handle handle; unsigned long long state; + bool is_blocked; handle = data; status = cmpc_get_rfkill_wlan(handle, &state); if (ACPI_FAILURE(status)) return -ENODEV; - if (blocked) - state &= ~1; - else - state |= 1; - status = cmpc_set_rfkill_wlan(handle, state); - if (ACPI_FAILURE(status)) - return -ENODEV; + /* Check if we really need to call cmpc_set_rfkill_wlan */ + is_blocked = state & 1 ? false : true; + if (is_blocked != blocked) { + state = blocked ? 0 : 1; + status = cmpc_set_rfkill_wlan(handle, state); + if (ACPI_FAILURE(status)) + return -ENODEV; + } return 0; } -- cgit v1.2.3 From 72135d21b587debcbcc57e0dbcc8bcfa4dacb661 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 6 Dec 2010 16:46:19 -0500 Subject: classmate-laptop: add missing input_sync call Add missing input_sync call in cmpc_keys_handler function. Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Matthew Garrett Acked-by: Thadeu Lima de Souza Cascardo --- drivers/platform/x86/classmate-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 3dabd00b1d5a..911135425224 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -657,6 +657,7 @@ static void cmpc_keys_handler(struct acpi_device *dev, u32 event) code = cmpc_keys_codes[event & 0x0F]; inputdev = dev_get_drvdata(&dev->dev); input_report_key(inputdev, code, !(event & 0x10)); + input_sync(inputdev); } static void cmpc_keys_idev_init(struct input_dev *inputdev) -- cgit v1.2.3 From 27c136c8738f6bec10c26aaf0a486f19edef7bf7 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:05 +0100 Subject: eeepc-wmi: rework eeepc_wmi_init and eeepc_wmi_exit The old code was using platform_driver.probe to initialize eeepc_wmi context. That's a mistake because if probe fail, eeepc_platform_register() won't tell anyone, and chaos will happen. Wrap add and remove code inside eeepc_wmi_add() / eeepc_wmi_remove(), and try to use the static platform_device only in eeepc_wmi_init() and eeepc_wmi_exit() The code is now very similar to eeepc-laptop, except eeepc_laptop_add and eeepc_laptop_remove are called from acpi_driver, not module init/exit functions, but WMI doesn't provide such functionalities (yet ?). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 135 +++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0d50fbbe2478..dfbb295326be 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -86,8 +86,10 @@ struct bios_args { struct eeepc_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; + struct platform_device *platform_device; }; +/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ static struct platform_device *platform_device; static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) @@ -101,7 +103,7 @@ static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) eeepc->inputdev->name = "Eee PC WMI hotkeys"; eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; eeepc->inputdev->id.bustype = BUS_HOST; - eeepc->inputdev->dev.parent = &platform_device->dev; + eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); if (err) @@ -234,7 +236,7 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 15; bd = backlight_device_register(EEEPC_WMI_FILE, - &platform_device->dev, eeepc, + &eeepc->platform_device->dev, eeepc, &eeepc_wmi_bl_ops, &props); if (IS_ERR(bd)) { pr_err("Could not register backlight device\n"); @@ -337,49 +339,99 @@ static int eeepc_wmi_sysfs_init(struct platform_device *device) return 0; error_sysfs: - eeepc_wmi_sysfs_exit(platform_device); + eeepc_wmi_sysfs_exit(device); return retval; } -static int __devinit eeepc_wmi_platform_probe(struct platform_device *device) +/* + * Platform device + */ +static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) { - struct eeepc_wmi *eeepc; int err; + + eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); + if (!eeepc->platform_device) + return -ENOMEM; + platform_set_drvdata(eeepc->platform_device, eeepc); + + err = platform_device_add(eeepc->platform_device); + if (err) + goto fail_platform_device; + + err = eeepc_wmi_sysfs_init(eeepc->platform_device); + if (err) + goto fail_sysfs; + return 0; + +fail_sysfs: + platform_device_del(eeepc->platform_device); +fail_platform_device: + platform_device_put(eeepc->platform_device); + return err; +} + +static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) +{ + eeepc_wmi_sysfs_exit(eeepc->platform_device); + platform_device_unregister(eeepc->platform_device); +} + +/* + * WMI Driver + */ +static struct platform_device * __init eeepc_wmi_add(void) +{ + struct eeepc_wmi *eeepc; acpi_status status; + int err; - eeepc = platform_get_drvdata(device); + eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); + if (!eeepc) + return ERR_PTR(-ENOMEM); + + /* + * Register the platform device first. It is used as a parent for the + * sub-devices below. + */ + err = eeepc_wmi_platform_init(eeepc); + if (err) + goto fail_platform; err = eeepc_wmi_input_init(eeepc); if (err) - goto error_input; + goto fail_input; if (!acpi_video_backlight_support()) { err = eeepc_wmi_backlight_init(eeepc); if (err) - goto error_backlight; + goto fail_backlight; } else pr_info("Backlight controlled by ACPI video driver\n"); status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, - eeepc_wmi_notify, eeepc); + eeepc_wmi_notify, eeepc); if (ACPI_FAILURE(status)) { pr_err("Unable to register notify handler - %d\n", status); err = -ENODEV; - goto error_wmi; + goto fail_wmi_handler; } - return 0; + return eeepc->platform_device; -error_wmi: +fail_wmi_handler: eeepc_wmi_backlight_exit(eeepc); -error_backlight: +fail_backlight: eeepc_wmi_input_exit(eeepc); -error_input: - return err; +fail_input: + eeepc_wmi_platform_exit(eeepc); +fail_platform: + kfree(eeepc); + return ERR_PTR(err); } -static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) +static int eeepc_wmi_remove(struct platform_device *device) { struct eeepc_wmi *eeepc; @@ -387,7 +439,9 @@ static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); eeepc_wmi_backlight_exit(eeepc); eeepc_wmi_input_exit(eeepc); + eeepc_wmi_platform_exit(eeepc); + kfree(eeepc); return 0; } @@ -396,13 +450,10 @@ static struct platform_driver platform_driver = { .name = EEEPC_WMI_FILE, .owner = THIS_MODULE, }, - .probe = eeepc_wmi_platform_probe, - .remove = __devexit_p(eeepc_wmi_platform_remove), }; static int __init eeepc_wmi_init(void) { - struct eeepc_wmi *eeepc; int err; if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || @@ -411,58 +462,30 @@ static int __init eeepc_wmi_init(void) return -ENODEV; } - eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); - if (!eeepc) - return -ENOMEM; - - platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); - if (!platform_device) { - pr_warning("Unable to allocate platform device\n"); - err = -ENOMEM; - goto fail_platform; + platform_device = eeepc_wmi_add(); + if (IS_ERR(platform_device)) { + err = PTR_ERR(platform_device); + goto fail_eeepc_wmi; } - err = platform_device_add(platform_device); - if (err) { - pr_warning("Unable to add platform device\n"); - goto put_dev; - } - - platform_set_drvdata(platform_device, eeepc); - err = platform_driver_register(&platform_driver); if (err) { pr_warning("Unable to register platform driver\n"); - goto del_dev; + goto fail_platform_driver; } - err = eeepc_wmi_sysfs_init(platform_device); - if (err) - goto del_sysfs; - return 0; -del_sysfs: - eeepc_wmi_sysfs_exit(platform_device); -del_dev: - platform_device_del(platform_device); -put_dev: - platform_device_put(platform_device); -fail_platform: - kfree(eeepc); - +fail_platform_driver: + eeepc_wmi_remove(platform_device); +fail_eeepc_wmi: return err; } static void __exit eeepc_wmi_exit(void) { - struct eeepc_wmi *eeepc; - - eeepc_wmi_sysfs_exit(platform_device); - eeepc = platform_get_drvdata(platform_device); + eeepc_wmi_remove(platform_device); platform_driver_unregister(&platform_driver); - platform_device_unregister(platform_device); - kfree(eeepc); } module_init(eeepc_wmi_init); -- cgit v1.2.3 From 084fca63128849c0961b3cfdb0cd0345e8f51ad8 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:06 +0100 Subject: eeepc-wmi: add touchpad led support Most of the code comes from eeepc-laptop. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 2 + drivers/platform/x86/eeepc-wmi.c | 113 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 65ba62086ca8..adcdbbd7d3fd 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -426,6 +426,8 @@ config EEEPC_WMI depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE select INPUT_SPARSEKMAP + select LEDS_CLASS + select NEW_LEDS ---help--- Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index dfbb295326be..f12a25da4055 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_METHODID_CFVS 0x53564643 #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 +#define EEEPC_WMI_DEVID_TPDLED 0x00100011 static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ @@ -87,6 +89,11 @@ struct eeepc_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; struct platform_device *platform_device; + + struct led_classdev tpd_led; + int tpd_led_wk; + struct workqueue_struct *led_workqueue; + struct work_struct tpd_led_work; }; /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ @@ -176,6 +183,105 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) return status; } +/* + * LEDs + */ +/* + * These functions actually update the LED's, and are called from a + * workqueue. By doing this as separate work rather than when the LED + * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a + * potentially bad time, such as a timer interrupt. + */ +static void tpd_led_update(struct work_struct *work) +{ + int ctrl_param; + struct eeepc_wmi *eeepc; + + eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); + + ctrl_param = eeepc->tpd_led_wk; + eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param); +} + +static void tpd_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct eeepc_wmi *eeepc; + + eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); + + eeepc->tpd_led_wk = !!value; + queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); +} + +static int read_tpd_state(struct eeepc_wmi *eeepc) +{ + static u32 ctrl_param; + acpi_status status; + + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &ctrl_param); + + if (ACPI_FAILURE(status)) + return -1; + else if (!ctrl_param || ctrl_param == 0x00060000) + /* + * if touchpad led is present, DSTS will set some bits, + * usually 0x00020000. + * 0x00060000 means that the device is not supported + */ + return -ENODEV; + else + /* Status is stored in the first bit */ + return ctrl_param & 0x1; +} + +static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) +{ + struct eeepc_wmi *eeepc; + + eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); + + return read_tpd_state(eeepc); +} + +static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) +{ + int rv; + + if (read_tpd_state(eeepc) < 0) + return 0; + + eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!eeepc->led_workqueue) + return -ENOMEM; + INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); + + eeepc->tpd_led.name = "eeepc::touchpad"; + eeepc->tpd_led.brightness_set = tpd_led_set; + eeepc->tpd_led.brightness_get = tpd_led_get; + eeepc->tpd_led.max_brightness = 1; + + rv = led_classdev_register(&eeepc->platform_device->dev, + &eeepc->tpd_led); + if (rv) { + destroy_workqueue(eeepc->led_workqueue); + return rv; + } + + return 0; +} + +static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->tpd_led.dev) + led_classdev_unregister(&eeepc->tpd_led); + if (eeepc->led_workqueue) + destroy_workqueue(eeepc->led_workqueue); +} + +/* + * Backlight + */ static int read_brightness(struct backlight_device *bd) { static u32 ctrl_param; @@ -402,6 +508,10 @@ static struct platform_device * __init eeepc_wmi_add(void) if (err) goto fail_input; + err = eeepc_wmi_led_init(eeepc); + if (err) + goto fail_leds; + if (!acpi_video_backlight_support()) { err = eeepc_wmi_backlight_init(eeepc); if (err) @@ -423,6 +533,8 @@ static struct platform_device * __init eeepc_wmi_add(void) fail_wmi_handler: eeepc_wmi_backlight_exit(eeepc); fail_backlight: + eeepc_wmi_led_exit(eeepc); +fail_leds: eeepc_wmi_input_exit(eeepc); fail_input: eeepc_wmi_platform_exit(eeepc); @@ -439,6 +551,7 @@ static int eeepc_wmi_remove(struct platform_device *device) wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); eeepc_wmi_backlight_exit(eeepc); eeepc_wmi_input_exit(eeepc); + eeepc_wmi_led_exit(eeepc); eeepc_wmi_platform_exit(eeepc); kfree(eeepc); -- cgit v1.2.3 From ba48fdb969d0404d54f6fa0266373afecbbd19d7 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:07 +0100 Subject: eeepc-wmi: add rfkill support for wlan, bluetooth and 3g wimax support is missing because I don't have any DSDT with WMI and wimax support. Most of the code comes from eeepc-laptop. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/eeepc-wmi.c | 138 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index adcdbbd7d3fd..4c7f8b926103 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -425,6 +425,7 @@ config EEEPC_WMI depends on INPUT depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE + depends on RFKILL || RFKILL = n select INPUT_SPARSEKMAP select LEDS_CLASS select NEW_LEDS diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index f12a25da4055..fb548f4b03e0 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,9 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 #define EEEPC_WMI_DEVID_TPDLED 0x00100011 +#define EEEPC_WMI_DEVID_WLAN 0x00010011 +#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 +#define EEEPC_WMI_DEVID_WWAN3G 0x00010019 static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ @@ -94,6 +98,10 @@ struct eeepc_wmi { int tpd_led_wk; struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; + + struct rfkill *wlan_rfkill; + struct rfkill *bluetooth_rfkill; + struct rfkill *wwan3g_rfkill; }; /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ @@ -279,6 +287,129 @@ static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) destroy_workqueue(eeepc->led_workqueue); } +/* + * Rfkill devices + */ +static int eeepc_rfkill_set(void *data, bool blocked) +{ + int dev_id = (unsigned long)data; + u32 ctrl_param = !blocked; + + return eeepc_wmi_set_devstate(dev_id, ctrl_param); +} + +static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) +{ + int dev_id = (unsigned long)data; + u32 ctrl_param; + acpi_status status; + + status = eeepc_wmi_get_devstate(dev_id, &ctrl_param); + + if (ACPI_FAILURE(status)) + return ; + + rfkill_set_sw_state(rfkill, !(ctrl_param & 0x1)); +} + +static const struct rfkill_ops eeepc_rfkill_ops = { + .set_block = eeepc_rfkill_set, + .query = eeepc_rfkill_query, +}; + +static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, + struct rfkill **rfkill, + const char *name, + enum rfkill_type type, int dev_id) +{ + int result; + u32 ctrl_param; + acpi_status status; + + status = eeepc_wmi_get_devstate(dev_id, &ctrl_param); + + if (ACPI_FAILURE(status)) + return -1; + + /* If the device is present, DSTS will always set some bits + * 0x00070000 - 1110000000000000000 - device supported + * 0x00060000 - 1100000000000000000 - not supported + * 0x00020000 - 0100000000000000000 - device supported + * 0x00010000 - 0010000000000000000 - not supported / special mode ? + */ + if (!ctrl_param || ctrl_param == 0x00060000) + return -ENODEV; + + *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, + &eeepc_rfkill_ops, (void *)(long)dev_id); + + if (!*rfkill) + return -EINVAL; + + rfkill_init_sw_state(*rfkill, !(ctrl_param & 0x1)); + result = rfkill_register(*rfkill); + if (result) { + rfkill_destroy(*rfkill); + *rfkill = NULL; + return result; + } + return 0; +} + +static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->wlan_rfkill) { + rfkill_unregister(eeepc->wlan_rfkill); + rfkill_destroy(eeepc->wlan_rfkill); + eeepc->wlan_rfkill = NULL; + } + if (eeepc->bluetooth_rfkill) { + rfkill_unregister(eeepc->bluetooth_rfkill); + rfkill_destroy(eeepc->bluetooth_rfkill); + eeepc->bluetooth_rfkill = NULL; + } + if (eeepc->wwan3g_rfkill) { + rfkill_unregister(eeepc->wwan3g_rfkill); + rfkill_destroy(eeepc->wwan3g_rfkill); + eeepc->wwan3g_rfkill = NULL; + } +} + +static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) +{ + int result = 0; + + result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, + "eeepc-wlan", RFKILL_TYPE_WLAN, + EEEPC_WMI_DEVID_WLAN); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, + "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, + EEEPC_WMI_DEVID_BLUETOOTH); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, + "eeepc-wwan3g", RFKILL_TYPE_WWAN, + EEEPC_WMI_DEVID_WWAN3G); + + if (result && result != -ENODEV) + goto exit; + +exit: + if (result && result != -ENODEV) + eeepc_wmi_rfkill_exit(eeepc); + + if (result == -ENODEV) + result = 0; + + return result; +} + /* * Backlight */ @@ -512,6 +643,10 @@ static struct platform_device * __init eeepc_wmi_add(void) if (err) goto fail_leds; + err = eeepc_wmi_rfkill_init(eeepc); + if (err) + goto fail_rfkill; + if (!acpi_video_backlight_support()) { err = eeepc_wmi_backlight_init(eeepc); if (err) @@ -533,6 +668,8 @@ static struct platform_device * __init eeepc_wmi_add(void) fail_wmi_handler: eeepc_wmi_backlight_exit(eeepc); fail_backlight: + eeepc_wmi_rfkill_exit(eeepc); +fail_rfkill: eeepc_wmi_led_exit(eeepc); fail_leds: eeepc_wmi_input_exit(eeepc); @@ -552,6 +689,7 @@ static int eeepc_wmi_remove(struct platform_device *device) eeepc_wmi_backlight_exit(eeepc); eeepc_wmi_input_exit(eeepc); eeepc_wmi_led_exit(eeepc); + eeepc_wmi_rfkill_exit(eeepc); eeepc_wmi_platform_exit(eeepc); kfree(eeepc); -- cgit v1.2.3 From 4e37b42d5ac0d3f505bcdc09028f3fde82031593 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:08 +0100 Subject: eeepc-wmi: use attribute group to manage attributes Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index fb548f4b03e0..a70d76a463a6 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -560,24 +560,23 @@ static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); +static struct attribute *platform_attributes[] = { + &dev_attr_cpufv.attr, + NULL +}; + +static struct attribute_group platform_attribute_group = { + .attrs = platform_attributes +}; + static void eeepc_wmi_sysfs_exit(struct platform_device *device) { - device_remove_file(&device->dev, &dev_attr_cpufv); + sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); } static int eeepc_wmi_sysfs_init(struct platform_device *device) { - int retval = -ENOMEM; - - retval = device_create_file(&device->dev, &dev_attr_cpufv); - if (retval) - goto error_sysfs; - - return 0; - -error_sysfs: - eeepc_wmi_sysfs_exit(device); - return retval; + return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); } /* -- cgit v1.2.3 From 8c1b2d83e82e11b9447d7fb3715d6c9764f6f28d Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:09 +0100 Subject: eeepc-wmi: add debugfs entries eeepc-wmi/ - debugfs root directory dev_id - current dev_id ctrl_param - current ctrl_param devs - call DEVS(dev_id, ctrl_param) and print result dsts - call DSTS(dev_id) and print result DEVS and DSTS are the main functions used in eeepc-wmi, this will allow to test new features without patching the drivers. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 170 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 164 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index a70d76a463a6..253070ab963c 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,6 +91,19 @@ struct bios_args { u32 ctrl_param; }; +/* + * eeepc-wmi/ - debugfs root directory + * dev_id - current dev_id + * ctrl_param - current ctrl_param + * devs - call DEVS(dev_id, ctrl_param) and print result + * dsts - call DSTS(dev_id) and print result + */ +struct eeepc_wmi_debug { + struct dentry *root; + u32 dev_id; + u32 ctrl_param; +}; + struct eeepc_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; @@ -102,6 +117,8 @@ struct eeepc_wmi { struct rfkill *wlan_rfkill; struct rfkill *bluetooth_rfkill; struct rfkill *wwan3g_rfkill; + + struct eeepc_wmi_debug debug; }; /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ @@ -176,7 +193,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param) } -static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) +static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, + u32 *retval) { struct bios_args args = { .dev_id = dev_id, @@ -185,8 +203,32 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; acpi_status status; - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, - 1, EEEPC_WMI_METHODID_DEVS, &input, NULL); + if (!retval) { + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, + EEEPC_WMI_METHODID_DEVS, + &input, NULL); + } else { + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + u32 tmp; + + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, + EEEPC_WMI_METHODID_DEVS, + &input, &output); + + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32)obj->integer.value; + else + tmp = 0; + + *retval = tmp; + + kfree(obj); + } return status; } @@ -208,7 +250,7 @@ static void tpd_led_update(struct work_struct *work) eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); ctrl_param = eeepc->tpd_led_wk; - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param); + eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL); } static void tpd_led_set(struct led_classdev *led_cdev, @@ -295,7 +337,7 @@ static int eeepc_rfkill_set(void *data, bool blocked) int dev_id = (unsigned long)data; u32 ctrl_param = !blocked; - return eeepc_wmi_set_devstate(dev_id, ctrl_param); + return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); } static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) @@ -434,7 +476,8 @@ static int update_bl_status(struct backlight_device *bd) ctrl_param = bd->props.brightness; - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param); + status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, + ctrl_param, NULL); if (ACPI_FAILURE(status)) return -1; @@ -613,6 +656,114 @@ static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) platform_device_unregister(eeepc->platform_device); } +/* + * debugfs + */ +struct eeepc_wmi_debugfs_node { + struct eeepc_wmi *eeepc; + char *name; + int (*show)(struct seq_file *m, void *data); +}; + +static int show_dsts(struct seq_file *m, void *data) +{ + struct eeepc_wmi *eeepc = m->private; + acpi_status status; + u32 retval = -1; + + status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); + + if (ACPI_FAILURE(status)) + return -EIO; + + seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); + + return 0; +} + +static int show_devs(struct seq_file *m, void *data) +{ + struct eeepc_wmi *eeepc = m->private; + acpi_status status; + u32 retval = -1; + + status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, + eeepc->debug.ctrl_param, &retval); + if (ACPI_FAILURE(status)) + return -EIO; + + seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, + eeepc->debug.ctrl_param, retval); + + return 0; +} + +static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { + { NULL, "devs", show_devs }, + { NULL, "dsts", show_dsts }, +}; + +static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) +{ + struct eeepc_wmi_debugfs_node *node = inode->i_private; + + return single_open(file, node->show, node->eeepc); +} + +static const struct file_operations eeepc_wmi_debugfs_io_ops = { + .owner = THIS_MODULE, + .open = eeepc_wmi_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) +{ + debugfs_remove_recursive(eeepc->debug.root); +} + +static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) +{ + struct dentry *dent; + int i; + + eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); + if (!eeepc->debug.root) { + pr_err("failed to create debugfs directory"); + goto error_debugfs; + } + + dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, + eeepc->debug.root, &eeepc->debug.dev_id); + if (!dent) + goto error_debugfs; + + dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, + eeepc->debug.root, &eeepc->debug.ctrl_param); + if (!dent) + goto error_debugfs; + + for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { + struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; + + node->eeepc = eeepc; + dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, + eeepc->debug.root, node, + &eeepc_wmi_debugfs_io_ops); + if (!dent) { + pr_err("failed to create debug file: %s\n", node->name); + goto error_debugfs; + } + } + + return 0; + +error_debugfs: + eeepc_wmi_debugfs_exit(eeepc); + return -ENOMEM; +} + /* * WMI Driver */ @@ -662,8 +813,14 @@ static struct platform_device * __init eeepc_wmi_add(void) goto fail_wmi_handler; } + err = eeepc_wmi_debugfs_init(eeepc); + if (err) + goto fail_debugfs; + return eeepc->platform_device; +fail_debugfs: + wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); fail_wmi_handler: eeepc_wmi_backlight_exit(eeepc); fail_backlight: @@ -689,6 +846,7 @@ static int eeepc_wmi_remove(struct platform_device *device) eeepc_wmi_input_exit(eeepc); eeepc_wmi_led_exit(eeepc); eeepc_wmi_rfkill_exit(eeepc); + eeepc_wmi_debugfs_exit(eeepc); eeepc_wmi_platform_exit(eeepc); kfree(eeepc); -- cgit v1.2.3 From 2a3f0064f2a06d5a31cddb0e452681d9f884bd8c Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:10 +0100 Subject: eeepc-wmi: fix confusion between ctrl_param and retval Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 253070ab963c..78306bea01f7 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -164,7 +164,7 @@ static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) eeepc->inputdev = NULL; } -static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param) +static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) { struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -184,8 +184,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param) else tmp = 0; - if (ctrl_param) - *ctrl_param = tmp; + if (retval) + *retval = tmp; kfree(obj); @@ -266,14 +266,14 @@ static void tpd_led_set(struct led_classdev *led_cdev, static int read_tpd_state(struct eeepc_wmi *eeepc) { - static u32 ctrl_param; + static u32 retval; acpi_status status; - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &ctrl_param); + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval); if (ACPI_FAILURE(status)) return -1; - else if (!ctrl_param || ctrl_param == 0x00060000) + else if (!retval || retval == 0x00060000) /* * if touchpad led is present, DSTS will set some bits, * usually 0x00020000. @@ -282,7 +282,7 @@ static int read_tpd_state(struct eeepc_wmi *eeepc) return -ENODEV; else /* Status is stored in the first bit */ - return ctrl_param & 0x1; + return retval & 0x1; } static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) @@ -343,15 +343,15 @@ static int eeepc_rfkill_set(void *data, bool blocked) static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) { int dev_id = (unsigned long)data; - u32 ctrl_param; + u32 retval; acpi_status status; - status = eeepc_wmi_get_devstate(dev_id, &ctrl_param); + status = eeepc_wmi_get_devstate(dev_id, &retval); if (ACPI_FAILURE(status)) return ; - rfkill_set_sw_state(rfkill, !(ctrl_param & 0x1)); + rfkill_set_sw_state(rfkill, !(retval & 0x1)); } static const struct rfkill_ops eeepc_rfkill_ops = { @@ -365,10 +365,10 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, enum rfkill_type type, int dev_id) { int result; - u32 ctrl_param; + u32 retval; acpi_status status; - status = eeepc_wmi_get_devstate(dev_id, &ctrl_param); + status = eeepc_wmi_get_devstate(dev_id, &retval); if (ACPI_FAILURE(status)) return -1; @@ -379,7 +379,7 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, * 0x00020000 - 0100000000000000000 - device supported * 0x00010000 - 0010000000000000000 - not supported / special mode ? */ - if (!ctrl_param || ctrl_param == 0x00060000) + if (!retval || retval == 0x00060000) return -ENODEV; *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, @@ -388,7 +388,7 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, if (!*rfkill) return -EINVAL; - rfkill_init_sw_state(*rfkill, !(ctrl_param & 0x1)); + rfkill_init_sw_state(*rfkill, !(retval & 0x1)); result = rfkill_register(*rfkill); if (result) { rfkill_destroy(*rfkill); @@ -457,15 +457,15 @@ exit: */ static int read_brightness(struct backlight_device *bd) { - static u32 ctrl_param; + static u32 retval; acpi_status status; - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param); + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval); if (ACPI_FAILURE(status)) return -1; else - return ctrl_param & 0xFF; + return retval & 0xFF; } static int update_bl_status(struct backlight_device *bd) -- cgit v1.2.3 From 4c4edfa3d375109c1360ce786b9df984ca65d727 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:11 +0100 Subject: eeepc-wmi: claim eeepc-wmi maintainership Since eeepc-wmi has currently no official maintainer, I claim maintainership of this driver, and add it to the acpi4asus project. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- MAINTAINERS | 8 ++++++++ drivers/platform/x86/eeepc-wmi.c | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index bcb78306b62f..9a7817591876 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2271,6 +2271,14 @@ W: http://acpi4asus.sf.net S: Maintained F: drivers/platform/x86/eeepc-laptop.c +EEEPC WMI EXTRAS DRIVER +M: Corentin Chary +L: acpi4asus-user@lists.sourceforge.net +L: platform-driver-x86@vger.kernel.org +W: http://acpi4asus.sf.net +S: Maintained +F: drivers/platform/x86/eeepc-wmi.c + EFIFB FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org M: Peter Jones diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 78306bea01f7..5f3f42c8a989 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -2,6 +2,7 @@ * Eee PC WMI hotkey driver * * Copyright(C) 2010 Intel Corporation. + * Copyright(C) 2010 Corentin Chary * * Portions based on wistron_btns.c: * Copyright (C) 2005 Miloslav Trmac -- cgit v1.2.3 From dfed65d56f9a94466bb4afd44ec8e900a6709cda Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:12 +0100 Subject: eeepc-wmi: remove unneeded static Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 5f3f42c8a989..52274e21ee89 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -267,7 +267,7 @@ static void tpd_led_set(struct led_classdev *led_cdev, static int read_tpd_state(struct eeepc_wmi *eeepc) { - static u32 retval; + u32 retval; acpi_status status; status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval); @@ -458,7 +458,7 @@ exit: */ static int read_brightness(struct backlight_device *bd) { - static u32 retval; + u32 retval; acpi_status status; status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval); @@ -472,7 +472,7 @@ static int read_brightness(struct backlight_device *bd) static int update_bl_status(struct backlight_device *bd) { - static u32 ctrl_param; + u32 ctrl_param; acpi_status status; ctrl_param = bd->props.brightness; -- cgit v1.2.3 From 62a75d83131c8887237d26a36ffeabd53c3640fd Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:13 +0100 Subject: eeepc-laptop: add a getter for touchpad led Allow te get the current led state in a more accurate way. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-laptop.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index b2edfdcdcb84..e9fc530e7dc2 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -529,6 +529,15 @@ static void tpd_led_set(struct led_classdev *led_cdev, queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); } +static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) +{ + struct eeepc_laptop *eeepc; + + eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led); + + return get_acpi(eeepc, CM_ASL_TPD); +} + static int eeepc_led_init(struct eeepc_laptop *eeepc) { int rv; @@ -543,6 +552,8 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc) eeepc->tpd_led.name = "eeepc::touchpad"; eeepc->tpd_led.brightness_set = tpd_led_set; + if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */ + eeepc->tpd_led.brightness_get = tpd_led_get; eeepc->tpd_led.max_brightness = 1; rv = led_classdev_register(&eeepc->platform_device->dev, -- cgit v1.2.3 From d358cb55a4cc83c37fbaebc0e4401a573777c6ac Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 29 Nov 2010 08:14:14 +0100 Subject: eeepc-wmi: never load if legacy device is enabled If legacy device (SB.ATKD - ASUS010) used by eeepc-laptop is enabled, don't allow eeepc-wmi to load because: - eeepc-laptop may be loaded, and can conflict with eeepc-wmi (they both try to register eeepc::touchpad led for example). - the WMI interface is inteded to be used when the OS is not detected as Win 7. And when this is the case, the ASUS010 device is disabled. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 52274e21ee89..4d38f98aa976 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -49,6 +49,8 @@ MODULE_AUTHOR("Yong Wang "); MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); MODULE_LICENSE("GPL"); +#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ + #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" #define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" @@ -861,6 +863,27 @@ static struct platform_driver platform_driver = { }, }; +static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, + void *context, void **retval) +{ + pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); + *(bool *)context = true; + return AE_CTRL_TERMINATE; +} + +static int __init eeepc_wmi_check_atkd(void) +{ + acpi_status status; + bool found = false; + + status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device, + &found, NULL); + + if (ACPI_FAILURE(status) || !found) + return 0; + return -1; +} + static int __init eeepc_wmi_init(void) { int err; @@ -871,6 +894,16 @@ static int __init eeepc_wmi_init(void) return -ENODEV; } + if (eeepc_wmi_check_atkd()) { + pr_warning("WMI device present, but legacy ATKD device is also " + "present and enabled."); + pr_warning("You probably booted with acpi_osi=\"Linux\" or " + "acpi_osi=\"!Windows 2009\""); + pr_warning("Can't load eeepc-wmi, use default acpi_osi " + "(preferred) or eeepc-laptop"); + return -ENODEV; + } + platform_device = eeepc_wmi_add(); if (IS_ERR(platform_device)) { err = PTR_ERR(platform_device); -- cgit v1.2.3 From e1e0dacba5af2b0cd8f9043d0b937296c90bc990 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Dec 2010 16:44:23 -0500 Subject: WMI: return error if wmi_create_device() fails The break resets the retval to 0 but we want to return an error code. This was introduced in c64eefd48c4 "WMI: embed struct device directly into wmi_block" Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett Acked-by: Dmitry Torokhov --- drivers/platform/x86/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index b8e5383eab0c..05cc79672a8b 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -820,7 +820,7 @@ static acpi_status parse_wdg(acpi_handle handle) retval = wmi_create_device(&gblock[i], wblock, handle); if (retval) { wmi_free_devices(); - break; + goto out_free_pointer; } } -- cgit v1.2.3 From 9c23225006b695ceba31c035b287f5a7a0b0304e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Dec 2010 00:04:14 +0900 Subject: fujitsu-laptop: fix compiler warning on pnp_ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Annotate pnp_ids as '__used' to fix following warning: CC drivers/platform/x86/fujitsu-laptop.o drivers/platform/x86/fujitsu-laptop.c:1243: warning: ‘pnp_ids’ defined but not used Signed-off-by: Namhyung Kim Signed-off-by: Matthew Garrett --- drivers/platform/x86/fujitsu-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f44cd2620ff9..ad88b2ec34a1 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1240,7 +1240,7 @@ MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); -static struct pnp_device_id pnp_ids[] = { +static struct pnp_device_id pnp_ids[] __used = { {.id = "FUJ02bf"}, {.id = "FUJ02B1"}, {.id = "FUJ02E3"}, -- cgit v1.2.3 From 98ee69191d3af68e2292528cbb16dcba3d8e2b81 Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Mon, 13 Dec 2010 18:00:15 +0800 Subject: ideapad: add platform driver for ideapad Create /sys/devices/platform/ideapad for nodes of ideapad landing. Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 54 ++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 5ff12205aa6b..5998ae14a220 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -27,6 +27,7 @@ #include #include #include +#include #define IDEAPAD_DEV_CAMERA 0 #define IDEAPAD_DEV_WLAN 1 @@ -37,6 +38,7 @@ struct ideapad_private { acpi_handle handle; struct rfkill *rfk[5]; + struct platform_device *platform_device; } *ideapad_priv; static struct { @@ -277,6 +279,35 @@ static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) rfkill_destroy(priv->rfk[dev]); } +/* + * Platform device + */ +static int __devinit ideapad_platform_init(void) +{ + int result; + + ideapad_priv->platform_device = platform_device_alloc("ideapad", -1); + if (!ideapad_priv->platform_device) + return -ENOMEM; + platform_set_drvdata(ideapad_priv->platform_device, ideapad_priv); + + result = platform_device_add(ideapad_priv->platform_device); + if (result) + goto fail_platform_device; + + return 0; + +fail_platform_device: + platform_device_put(ideapad_priv->platform_device); + return result; +} + +static void ideapad_platform_exit(void) +{ + platform_device_unregister(ideapad_priv->platform_device); +} +/* the above is platform device */ + static const struct acpi_device_id ideapad_device_ids[] = { { "VPC2004", 0}, { "", 0}, @@ -285,7 +316,7 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); static int ideapad_acpi_add(struct acpi_device *adevice) { - int i, cfg; + int ret, i, cfg; int devs_present[5]; struct ideapad_private *priv; @@ -305,18 +336,20 @@ static int ideapad_acpi_add(struct acpi_device *adevice) priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + ideapad_priv = priv; + + ret = ideapad_platform_init(); + if (ret) + goto platform_failed; if (devs_present[IDEAPAD_DEV_CAMERA]) { - int ret = device_create_file(&adevice->dev, &dev_attr_camera_power); - if (ret) { - kfree(priv); - return ret; - } + ret = device_create_file(&adevice->dev, &dev_attr_camera_power); + if (ret) + goto camera_failed; } priv->handle = adevice->handle; dev_set_drvdata(&adevice->dev, priv); - ideapad_priv = priv; for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) { if (!devs_present[i]) continue; @@ -325,6 +358,12 @@ static int ideapad_acpi_add(struct acpi_device *adevice) } ideapad_sync_rfk_state(adevice); return 0; + +camera_failed: + ideapad_platform_exit(); +platform_failed: + kfree(priv); + return ret; } static int ideapad_acpi_remove(struct acpi_device *adevice, int type) @@ -337,6 +376,7 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type) for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) ideapad_unregister_rfkill(adevice, i); + ideapad_platform_exit(); dev_set_drvdata(&adevice->dev, NULL); kfree(priv); return 0; -- cgit v1.2.3 From c9f718d0c6b4cf8033aa0f5ac892d68ddfb865aa Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Mon, 13 Dec 2010 18:00:27 +0800 Subject: ideapad: let camera power control entry under platform driver The entry was at /sys/devices/LNXSYSTM:00/../VPC2004:00/camera_power move to /sys/devices/platform/ideapad/camera_power Add document about usage of ideapad node in sysfs. Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- .../ABI/testing/sysfs-platform-ideapad-laptop | 6 +++ drivers/platform/x86/ideapad-laptop.c | 55 ++++++++++------------ 2 files changed, 31 insertions(+), 30 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-platform-ideapad-laptop (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-platform-ideapad-laptop b/Documentation/ABI/testing/sysfs-platform-ideapad-laptop new file mode 100644 index 000000000000..807fca2ae2a4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-ideapad-laptop @@ -0,0 +1,6 @@ +What: /sys/devices/platform/ideapad/camera_power +Date: Dec 2010 +KernelVersion: 2.6.37 +Contact: "Ike Panhc " +Description: + Control the power of camera module. 1 means on, 0 means off. diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 5998ae14a220..49f207fc61d2 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -282,6 +282,15 @@ static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) /* * Platform device */ +static struct attribute *ideapad_attributes[] = { + &dev_attr_camera_power.attr, + NULL +}; + +static struct attribute_group ideapad_attribute_group = { + .attrs = ideapad_attributes +}; + static int __devinit ideapad_platform_init(void) { int result; @@ -295,8 +304,14 @@ static int __devinit ideapad_platform_init(void) if (result) goto fail_platform_device; + result = sysfs_create_group(&ideapad_priv->platform_device->dev.kobj, + &ideapad_attribute_group); + if (result) + goto fail_sysfs; return 0; +fail_sysfs: + platform_device_del(ideapad_priv->platform_device); fail_platform_device: platform_device_put(ideapad_priv->platform_device); return result; @@ -304,6 +319,8 @@ fail_platform_device: static void ideapad_platform_exit(void) { + sysfs_remove_group(&ideapad_priv->platform_device->dev.kobj, + &ideapad_attribute_group); platform_device_unregister(ideapad_priv->platform_device); } /* the above is platform device */ @@ -317,50 +334,30 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); static int ideapad_acpi_add(struct acpi_device *adevice) { int ret, i, cfg; - int devs_present[5]; struct ideapad_private *priv; if (read_method_int(adevice->handle, "_CFG", &cfg)) return -ENODEV; - for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) { - if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) - devs_present[i] = 1; - else - devs_present[i] = 0; - } - - /* The hardware switch is always present */ - devs_present[IDEAPAD_DEV_KILLSW] = 1; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; ideapad_priv = priv; + priv->handle = adevice->handle; + dev_set_drvdata(&adevice->dev, priv); ret = ideapad_platform_init(); if (ret) goto platform_failed; - if (devs_present[IDEAPAD_DEV_CAMERA]) { - ret = device_create_file(&adevice->dev, &dev_attr_camera_power); - if (ret) - goto camera_failed; - } - - priv->handle = adevice->handle; - dev_set_drvdata(&adevice->dev, priv); - for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) { - if (!devs_present[i]) - continue; - - ideapad_register_rfkill(adevice, i); + for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) { + if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) + ideapad_register_rfkill(adevice, i); } ideapad_sync_rfk_state(adevice); + return 0; -camera_failed: - ideapad_platform_exit(); platform_failed: kfree(priv); return ret; @@ -371,14 +368,12 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type) struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); int i; - device_remove_file(&adevice->dev, &dev_attr_camera_power); - - for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) + for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) ideapad_unregister_rfkill(adevice, i); - ideapad_platform_exit(); dev_set_drvdata(&adevice->dev, NULL); kfree(priv); + return 0; } -- cgit v1.2.3 From f63409ae91ff94e2192dafbeb00c278ba299f80e Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Mon, 13 Dec 2010 18:00:38 +0800 Subject: ideapad: add hotkey support Hotkey enabled by this patch: Fn+F3: Video mode switch Fn+F5: software rfkill for wifi For some ideapad when push Fn+F3, hardware generates Super-P keys, those key will not be enabled by this patch. Thanks for Dave Hansen report the problem. If CONFIG_INPUT_SPARSEKMAP is not set, when building, you will have error message: ERROR: "sparse_keymap_setup" [drivers/platform/x86/ideapad-laptop.ko] undefined! ERROR: "sparse_keymap_free" [drivers/platform/x86/ideapad-laptop.ko] undefined! ERROR: "sparse_keymap_report_event" [drivers/platform/x86/ideapad-laptop.ko] undefined! To select INPUT_SPARSEKMAP solve this issue. Ref: http://lkml.org/lkml/2010/12/2/340 Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/ideapad-laptop.c | 72 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4c7f8b926103..254c4ef6be35 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -226,6 +226,7 @@ config IDEAPAD_LAPTOP tristate "Lenovo IdeaPad Laptop Extras" depends on ACPI depends on RFKILL + select INPUT_SPARSEKMAP help This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 49f207fc61d2..04b4f5b3114d 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #define IDEAPAD_DEV_CAMERA 0 #define IDEAPAD_DEV_WLAN 1 @@ -39,6 +41,7 @@ struct ideapad_private { acpi_handle handle; struct rfkill *rfk[5]; struct platform_device *platform_device; + struct input_dev *inputdev; } *ideapad_priv; static struct { @@ -325,6 +328,66 @@ static void ideapad_platform_exit(void) } /* the above is platform device */ +/* + * input device + */ +static const struct key_entry ideapad_keymap[] = { + { KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x0D, { KEY_WLAN } }, + { KE_END, 0 }, +}; + +static int __devinit ideapad_input_init(void) +{ + struct input_dev *inputdev; + int error; + + inputdev = input_allocate_device(); + if (!inputdev) { + pr_info("Unable to allocate input device\n"); + return -ENOMEM; + } + + inputdev->name = "Ideapad extra buttons"; + inputdev->phys = "ideapad/input0"; + inputdev->id.bustype = BUS_HOST; + inputdev->dev.parent = &ideapad_priv->platform_device->dev; + + error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL); + if (error) { + pr_err("Unable to setup input device keymap\n"); + goto err_free_dev; + } + + error = input_register_device(inputdev); + if (error) { + pr_err("Unable to register input device\n"); + goto err_free_keymap; + } + + ideapad_priv->inputdev = inputdev; + return 0; + +err_free_keymap: + sparse_keymap_free(inputdev); +err_free_dev: + input_free_device(inputdev); + return error; +} + +static void __devexit ideapad_input_exit(void) +{ + sparse_keymap_free(ideapad_priv->inputdev); + input_unregister_device(ideapad_priv->inputdev); + ideapad_priv->inputdev = NULL; +} + +static void ideapad_input_report(unsigned long scancode) +{ + sparse_keymap_report_event(ideapad_priv->inputdev, scancode, 1, true); +} +/* the above is input device */ + static const struct acpi_device_id ideapad_device_ids[] = { { "VPC2004", 0}, { "", 0}, @@ -350,6 +413,10 @@ static int ideapad_acpi_add(struct acpi_device *adevice) if (ret) goto platform_failed; + ret = ideapad_input_init(); + if (ret) + goto input_failed; + for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) { if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) ideapad_register_rfkill(adevice, i); @@ -358,6 +425,8 @@ static int ideapad_acpi_add(struct acpi_device *adevice) return 0; +input_failed: + ideapad_platform_exit(); platform_failed: kfree(priv); return ret; @@ -370,6 +439,7 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type) for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) ideapad_unregister_rfkill(adevice, i); + ideapad_input_exit(); ideapad_platform_exit(); dev_set_drvdata(&adevice->dev, NULL); kfree(priv); @@ -392,6 +462,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) if (test_bit(vpc_bit, &vpc1)) { if (vpc_bit == 9) ideapad_sync_rfk_state(adevice); + else + ideapad_input_report(vpc_bit); } } } -- cgit v1.2.3 From a4b5a2794a27da870c2e16db390778a4683f95f8 Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Mon, 13 Dec 2010 18:00:48 +0800 Subject: ideapad: add markups, unify comments and return result when init 1. Add markups on init and exit functions 2. Unify the comments in the same style 3. Return result when module initial Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 04b4f5b3114d..3c6c5b5e1d53 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1,5 +1,5 @@ /* - * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras + * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras * * Copyright © 2010 Intel Corporation * Copyright © 2010 David Woodhouse @@ -168,8 +168,10 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) pr_err("timeout in write_ec_cmd\n"); return -1; } -/* the above is ACPI helpers */ +/* + * camera power + */ static ssize_t show_ideapad_cam(struct device *dev, struct device_attribute *attr, char *buf) @@ -203,6 +205,9 @@ static ssize_t store_ideapad_cam(struct device *dev, static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); +/* + * Rfkill + */ static int ideapad_rfk_set(void *data, bool blocked) { int device = (unsigned long)data; @@ -235,7 +240,8 @@ static void ideapad_sync_rfk_state(struct acpi_device *adevice) rfkill_set_hw_state(priv->rfk[i], hw_blocked); } -static int ideapad_register_rfkill(struct acpi_device *adevice, int dev) +static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, + int dev) { struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); int ret; @@ -271,7 +277,8 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev) return 0; } -static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) +static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, + int dev) { struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); @@ -326,7 +333,6 @@ static void ideapad_platform_exit(void) &ideapad_attribute_group); platform_device_unregister(ideapad_priv->platform_device); } -/* the above is platform device */ /* * input device @@ -386,15 +392,17 @@ static void ideapad_input_report(unsigned long scancode) { sparse_keymap_report_event(ideapad_priv->inputdev, scancode, 1, true); } -/* the above is input device */ +/* + * module init/exit + */ static const struct acpi_device_id ideapad_device_ids[] = { { "VPC2004", 0}, { "", 0}, }; MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); -static int ideapad_acpi_add(struct acpi_device *adevice) +static int __devinit ideapad_acpi_add(struct acpi_device *adevice) { int ret, i, cfg; struct ideapad_private *priv; @@ -432,7 +440,7 @@ platform_failed: return ret; } -static int ideapad_acpi_remove(struct acpi_device *adevice, int type) +static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) { struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); int i; @@ -478,19 +486,14 @@ static struct acpi_driver ideapad_acpi_driver = { .owner = THIS_MODULE, }; - static int __init ideapad_acpi_module_init(void) { - acpi_bus_register_driver(&ideapad_acpi_driver); - - return 0; + return acpi_bus_register_driver(&ideapad_acpi_driver); } - static void __exit ideapad_acpi_module_exit(void) { acpi_bus_unregister_driver(&ideapad_acpi_driver); - } MODULE_AUTHOR("David Woodhouse "); -- cgit v1.2.3 From 8693ae846cad00e6c2c40e116ec1fc50c145b559 Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Mon, 13 Dec 2010 18:01:01 +0800 Subject: ideapad: pass ideapad_priv as argument (part 1) Passing ideapad_priv as argument and try not to using too much global variable. This is part 1 for platform driver and input device. Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 54 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 3c6c5b5e1d53..37fe0d0448c9 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -301,37 +301,37 @@ static struct attribute_group ideapad_attribute_group = { .attrs = ideapad_attributes }; -static int __devinit ideapad_platform_init(void) +static int __devinit ideapad_platform_init(struct ideapad_private *priv) { int result; - ideapad_priv->platform_device = platform_device_alloc("ideapad", -1); - if (!ideapad_priv->platform_device) + priv->platform_device = platform_device_alloc("ideapad", -1); + if (!priv->platform_device) return -ENOMEM; - platform_set_drvdata(ideapad_priv->platform_device, ideapad_priv); + platform_set_drvdata(priv->platform_device, priv); - result = platform_device_add(ideapad_priv->platform_device); + result = platform_device_add(priv->platform_device); if (result) goto fail_platform_device; - result = sysfs_create_group(&ideapad_priv->platform_device->dev.kobj, + result = sysfs_create_group(&priv->platform_device->dev.kobj, &ideapad_attribute_group); if (result) goto fail_sysfs; return 0; fail_sysfs: - platform_device_del(ideapad_priv->platform_device); + platform_device_del(priv->platform_device); fail_platform_device: - platform_device_put(ideapad_priv->platform_device); + platform_device_put(priv->platform_device); return result; } -static void ideapad_platform_exit(void) +static void ideapad_platform_exit(struct ideapad_private *priv) { - sysfs_remove_group(&ideapad_priv->platform_device->dev.kobj, + sysfs_remove_group(&priv->platform_device->dev.kobj, &ideapad_attribute_group); - platform_device_unregister(ideapad_priv->platform_device); + platform_device_unregister(priv->platform_device); } /* @@ -343,7 +343,7 @@ static const struct key_entry ideapad_keymap[] = { { KE_END, 0 }, }; -static int __devinit ideapad_input_init(void) +static int __devinit ideapad_input_init(struct ideapad_private *priv) { struct input_dev *inputdev; int error; @@ -357,7 +357,7 @@ static int __devinit ideapad_input_init(void) inputdev->name = "Ideapad extra buttons"; inputdev->phys = "ideapad/input0"; inputdev->id.bustype = BUS_HOST; - inputdev->dev.parent = &ideapad_priv->platform_device->dev; + inputdev->dev.parent = &priv->platform_device->dev; error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL); if (error) { @@ -371,7 +371,7 @@ static int __devinit ideapad_input_init(void) goto err_free_keymap; } - ideapad_priv->inputdev = inputdev; + priv->inputdev = inputdev; return 0; err_free_keymap: @@ -381,16 +381,17 @@ err_free_dev: return error; } -static void __devexit ideapad_input_exit(void) +static void __devexit ideapad_input_exit(struct ideapad_private *priv) { - sparse_keymap_free(ideapad_priv->inputdev); - input_unregister_device(ideapad_priv->inputdev); - ideapad_priv->inputdev = NULL; + sparse_keymap_free(priv->inputdev); + input_unregister_device(priv->inputdev); + priv->inputdev = NULL; } -static void ideapad_input_report(unsigned long scancode) +static void ideapad_input_report(struct ideapad_private *priv, + unsigned long scancode) { - sparse_keymap_report_event(ideapad_priv->inputdev, scancode, 1, true); + sparse_keymap_report_event(priv->inputdev, scancode, 1, true); } /* @@ -417,11 +418,11 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) priv->handle = adevice->handle; dev_set_drvdata(&adevice->dev, priv); - ret = ideapad_platform_init(); + ret = ideapad_platform_init(priv); if (ret) goto platform_failed; - ret = ideapad_input_init(); + ret = ideapad_input_init(priv); if (ret) goto input_failed; @@ -434,7 +435,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) return 0; input_failed: - ideapad_platform_exit(); + ideapad_platform_exit(priv); platform_failed: kfree(priv); return ret; @@ -447,8 +448,8 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) ideapad_unregister_rfkill(adevice, i); - ideapad_input_exit(); - ideapad_platform_exit(); + ideapad_input_exit(priv); + ideapad_platform_exit(priv); dev_set_drvdata(&adevice->dev, NULL); kfree(priv); @@ -457,6 +458,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) { + struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); acpi_handle handle = adevice->handle; unsigned long vpc1, vpc2, vpc_bit; @@ -471,7 +473,7 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) if (vpc_bit == 9) ideapad_sync_rfk_state(adevice); else - ideapad_input_report(vpc_bit); + ideapad_input_report(priv, vpc_bit); } } } -- cgit v1.2.3 From c1f73658edc8ac6f624968b47a276361ce032ca9 Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Mon, 13 Dec 2010 18:01:12 +0800 Subject: ideapad: pass ideapad_priv as argument (part 2) Passing ideapad_priv as argument and try not to using too much global variable. This is part 2 for rfkill. Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 71 ++++++++++++++--------------------- 1 file changed, 29 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 37fe0d0448c9..114d95247cdf 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -31,32 +31,15 @@ #include #include -#define IDEAPAD_DEV_CAMERA 0 -#define IDEAPAD_DEV_WLAN 1 -#define IDEAPAD_DEV_BLUETOOTH 2 -#define IDEAPAD_DEV_3G 3 -#define IDEAPAD_DEV_KILLSW 4 +#define IDEAPAD_RFKILL_DEV_NUM (3) struct ideapad_private { - acpi_handle handle; - struct rfkill *rfk[5]; + struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; struct platform_device *platform_device; struct input_dev *inputdev; -} *ideapad_priv; - -static struct { - char *name; - int cfgbit; - int opcode; - int type; -} ideapad_rfk_data[] = { - { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES }, - { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN }, - { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH }, - { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN }, - { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN } }; +static acpi_handle ideapad_handle; static bool no_bt_rfkill; module_param(no_bt_rfkill, bool, 0444); MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); @@ -176,11 +159,9 @@ static ssize_t show_ideapad_cam(struct device *dev, struct device_attribute *attr, char *buf) { - struct ideapad_private *priv = dev_get_drvdata(dev); - acpi_handle handle = priv->handle; unsigned long result; - if (read_ec_data(handle, 0x1D, &result)) + if (read_ec_data(ideapad_handle, 0x1D, &result)) return sprintf(buf, "-1\n"); return sprintf(buf, "%lu\n", result); } @@ -189,15 +170,13 @@ static ssize_t store_ideapad_cam(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct ideapad_private *priv = dev_get_drvdata(dev); - acpi_handle handle = priv->handle; int ret, state; if (!count) return 0; if (sscanf(buf, "%i", &state) != 1) return -EINVAL; - ret = write_ec_cmd(handle, 0x1E, state); + ret = write_ec_cmd(ideapad_handle, 0x1E, state); if (ret < 0) return ret; return count; @@ -208,16 +187,24 @@ static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); /* * Rfkill */ +struct ideapad_rfk_data { + char *name; + int cfgbit; + int opcode; + int type; +}; + +const struct ideapad_rfk_data ideapad_rfk_data[] = { + { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN }, + { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH }, + { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN }, +}; + static int ideapad_rfk_set(void *data, bool blocked) { - int device = (unsigned long)data; - - if (device == IDEAPAD_DEV_KILLSW) - return -EINVAL; + unsigned long opcode = (unsigned long)data; - return write_ec_cmd(ideapad_priv->handle, - ideapad_rfk_data[device].opcode, - !blocked); + return write_ec_cmd(ideapad_handle, opcode, !blocked); } static struct rfkill_ops ideapad_rfk_ops = { @@ -227,15 +214,14 @@ static struct rfkill_ops ideapad_rfk_ops = { static void ideapad_sync_rfk_state(struct acpi_device *adevice) { struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); - acpi_handle handle = priv->handle; unsigned long hw_blocked; int i; - if (read_ec_data(handle, 0x23, &hw_blocked)) + if (read_ec_data(ideapad_handle, 0x23, &hw_blocked)) return; hw_blocked = !hw_blocked; - for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) + for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) if (priv->rfk[i]) rfkill_set_hw_state(priv->rfk[i], hw_blocked); } @@ -250,7 +236,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, if (no_bt_rfkill && (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) { /* Force to enable bluetooth when no_bt_rfkill=1 */ - write_ec_cmd(ideapad_priv->handle, + write_ec_cmd(ideapad_handle, ideapad_rfk_data[dev].opcode, 1); return 0; } @@ -261,7 +247,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, if (!priv->rfk[dev]) return -ENOMEM; - if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1, + if (read_ec_data(ideapad_handle, ideapad_rfk_data[dev].opcode-1, &sw_blocked)) { rfkill_init_sw_state(priv->rfk[dev], 0); } else { @@ -414,9 +400,8 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - ideapad_priv = priv; - priv->handle = adevice->handle; dev_set_drvdata(&adevice->dev, priv); + ideapad_handle = adevice->handle; ret = ideapad_platform_init(priv); if (ret) @@ -426,9 +411,11 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) if (ret) goto input_failed; - for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) { + for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) ideapad_register_rfkill(adevice, i); + else + priv->rfk[i] = NULL; } ideapad_sync_rfk_state(adevice); @@ -446,7 +433,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); int i; - for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) + for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) ideapad_unregister_rfkill(adevice, i); ideapad_input_exit(priv); ideapad_platform_exit(priv); -- cgit v1.2.3 From e98062ed6dc46ed3270350e1040e19d44150d1d1 Mon Sep 17 00:00:00 2001 From: Sedat Dilek Date: Wed, 8 Dec 2010 11:20:26 +0100 Subject: platform/x86: Kconfig: Replace select by depends on ACPI_WMI With 'make oldnoconfig' I see these warnings in linux-next (next-20101208): drivers/platform/x86/Kconfig:422:error: recursive dependency detected! drivers/platform/x86/Kconfig:422: symbol EEEPC_WMI depends on ACPI_WMI drivers/platform/x86/Kconfig:438: symbol ACPI_WMI is selected by ACER_WMI drivers/platform/x86/Kconfig:18: symbol ACER_WMI depends on LEDS_CLASS drivers/leds/Kconfig:10: symbol LEDS_CLASS is selected by EEEPC_WMI This patch replaces all "select on ACPI_WMI" by "depends on ACPI_WMI". Quote from David Woodhouse: "A better policy is: "NEVER USE SELECT"." Reported-and-tested-by: Sedat Dilek Signed-off-by: Sedat Dilek Acked-by: Randy Dunlap Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 254c4ef6be35..fbee997d2c24 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -23,7 +23,7 @@ config ACER_WMI depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 depends on RFKILL || RFKILL = n - select ACPI_WMI + depends on ACPI_WMI ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds wireless radio and bluetooth control, and on some laptops, @@ -131,7 +131,7 @@ config TC1100_WMI depends on !X86_64 depends on EXPERIMENTAL depends on ACPI - select ACPI_WMI + depends on ACPI_WMI ---help--- This is a driver for the WMI extensions (wireless and bluetooth power control) of the HP Compaq TC1100 tablet. -- cgit v1.2.3 From 3fdca87d10f1d45b1c034da343e68beb082f9b84 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Tue, 7 Dec 2010 10:29:20 +0800 Subject: acer-wmi: Add acer wmi hotkey events support Add acer wmi hotkey event support. Install a wmi notify handler to transfer wmi event key to key code, then send out keycode through acer wmi input device to userland. Signed-off-by: Lee, Chun-Yi Acked-by: Dmitry Torokhov Acked-by: Thomas Renninger Acked-by: Jiri Benc Signed-off-by: Carlos Corbacho Cc: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 2 + drivers/platform/x86/acer-wmi.c | 139 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index fbee997d2c24..a122a0dac981 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -22,8 +22,10 @@ config ACER_WMI depends on NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 + depends on INPUT depends on RFKILL || RFKILL = n depends on ACPI_WMI + select INPUT_SPARSEKMAP ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds wireless radio and bluetooth control, and on some laptops, diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c8c65375bfe2..a1c6141f463b 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include @@ -48,6 +50,7 @@ MODULE_LICENSE("GPL"); #define ACER_ERR KERN_ERR ACER_LOGPREFIX #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX #define ACER_INFO KERN_INFO ACER_LOGPREFIX +#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX /* * Magic Number @@ -83,8 +86,39 @@ MODULE_LICENSE("GPL"); #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" +/* + * Acer ACPI event GUIDs + */ +#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" + MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); +MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); + +enum acer_wmi_event_ids { + WMID_HOTKEY_EVENT = 0x1, +}; + +static const struct key_entry acer_wmi_keymap[] = { + {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */ + {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */ + {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */ + {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ + {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ + {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ + {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ + {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ + {KE_END, 0} +}; + +static struct input_dev *acer_wmi_input_dev; + +struct event_return_value { + u8 function; + u8 key_num; + u16 device_state; + u32 reserved; +} __attribute__((packed)); /* * Interface capability flags @@ -1085,6 +1119,99 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL); +static void acer_wmi_notify(u32 value, void *context) +{ + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + struct event_return_value return_value; + acpi_status status; + + status = wmi_get_event_data(value, &response); + if (status != AE_OK) { + printk(ACER_WARNING "bad event status 0x%x\n", status); + return; + } + + obj = (union acpi_object *)response.pointer; + + if (!obj) + return; + if (obj->type != ACPI_TYPE_BUFFER) { + printk(ACER_WARNING "Unknown response received %d\n", + obj->type); + kfree(obj); + return; + } + if (obj->buffer.length != 8) { + printk(ACER_WARNING "Unknown buffer length %d\n", + obj->buffer.length); + kfree(obj); + return; + } + + return_value = *((struct event_return_value *)obj->buffer.pointer); + kfree(obj); + + switch (return_value.function) { + case WMID_HOTKEY_EVENT: + if (!sparse_keymap_report_event(acer_wmi_input_dev, + return_value.key_num, 1, true)) + printk(ACER_WARNING "Unknown key number - 0x%x\n", + return_value.key_num); + break; + default: + printk(ACER_WARNING "Unknown function number - %d - %d\n", + return_value.function, return_value.key_num); + break; + } +} + +static int __init acer_wmi_input_setup(void) +{ + acpi_status status; + int err; + + acer_wmi_input_dev = input_allocate_device(); + if (!acer_wmi_input_dev) + return -ENOMEM; + + acer_wmi_input_dev->name = "Acer WMI hotkeys"; + acer_wmi_input_dev->phys = "wmi/input0"; + acer_wmi_input_dev->id.bustype = BUS_HOST; + + err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL); + if (err) + goto err_free_dev; + + status = wmi_install_notify_handler(ACERWMID_EVENT_GUID, + acer_wmi_notify, NULL); + if (ACPI_FAILURE(status)) { + err = -EIO; + goto err_free_keymap; + } + + err = input_register_device(acer_wmi_input_dev); + if (err) + goto err_uninstall_notifier; + + return 0; + +err_uninstall_notifier: + wmi_remove_notify_handler(ACERWMID_EVENT_GUID); +err_free_keymap: + sparse_keymap_free(acer_wmi_input_dev); +err_free_dev: + input_free_device(acer_wmi_input_dev); + return err; +} + +static void acer_wmi_input_destroy(void) +{ + wmi_remove_notify_handler(ACERWMID_EVENT_GUID); + sparse_keymap_free(acer_wmi_input_dev); + input_unregister_device(acer_wmi_input_dev); +} + /* * debugfs functions */ @@ -1327,6 +1454,12 @@ static int __init acer_wmi_init(void) "generic video driver\n"); } + if (wmi_has_guid(ACERWMID_EVENT_GUID)) { + err = acer_wmi_input_setup(); + if (err) + return err; + } + err = platform_driver_register(&acer_platform_driver); if (err) { printk(ACER_ERR "Unable to register platform driver.\n"); @@ -1368,11 +1501,17 @@ error_device_add: error_device_alloc: platform_driver_unregister(&acer_platform_driver); error_platform_register: + if (wmi_has_guid(ACERWMID_EVENT_GUID)) + acer_wmi_input_destroy(); + return err; } static void __exit acer_wmi_exit(void) { + if (wmi_has_guid(ACERWMID_EVENT_GUID)) + acer_wmi_input_destroy(); + remove_sysfs(acer_platform_device); remove_debugfs(); platform_device_unregister(acer_platform_device); -- cgit v1.2.3 From b3c9092b2fed427d45117d23ceb577ad8dc46a9a Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Tue, 7 Dec 2010 10:29:22 +0800 Subject: acer-wmi: Add 3G rfkill sysfs file Add 3G rfkill sysfs file for provide userland to control 3G device on/off by using WMI method. Signed-off-by: Lee, Chun-Yi Acked-by: Thomas Renninger Acked-by: Jiri Benc Acked-by: Dmitry Torokhov Signed-off-by: Carlos Corbaho Cc: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 100 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index a1c6141f463b..85d263349aac 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -85,6 +85,7 @@ MODULE_LICENSE("GPL"); #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" +#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" /* * Acer ACPI event GUIDs @@ -120,6 +121,24 @@ struct event_return_value { u32 reserved; } __attribute__((packed)); +/* + * GUID3 Get Device Status device flags + */ +#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ + +struct wmid3_gds_input_param { /* Get Device Status input parameter */ + u8 function_num; /* Function Number */ + u8 hotkey_number; /* Hotkey Number */ + u16 devices; /* Get Device */ +} __attribute__((packed)); + +struct wmid3_gds_return_value { /* Get Device Status return value*/ + u8 error_code; /* Error Code */ + u8 ec_return_value; /* EC Return Value */ + u16 devices; /* Current Device Status */ + u32 reserved; +} __attribute__((packed)); + /* * Interface capability flags */ @@ -174,6 +193,7 @@ struct acer_debug { static struct rfkill *wireless_rfkill; static struct rfkill *bluetooth_rfkill; +static struct rfkill *threeg_rfkill; /* Each low-level interface must define at least some of the following */ struct wmi_interface { @@ -982,6 +1002,54 @@ static void acer_backlight_exit(void) backlight_device_unregister(acer_backlight_device); } +static acpi_status wmid3_get_device_status(u32 *value, u16 device) +{ + struct wmid3_gds_return_value return_value; + acpi_status status; + union acpi_object *obj; + struct wmid3_gds_input_param params = { + .function_num = 0x1, + .hotkey_number = 0x01, + .devices = device, + }; + struct acpi_buffer input = { + sizeof(struct wmid3_gds_input_param), + ¶ms + }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + + status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); + if (ACPI_FAILURE(status)) + return status; + + obj = output.pointer; + + if (!obj) + return AE_ERROR; + else if (obj->type != ACPI_TYPE_BUFFER) { + kfree(obj); + return AE_ERROR; + } + if (obj->buffer.length != 8) { + printk(ACER_WARNING "Unknown buffer length %d\n", + obj->buffer.length); + kfree(obj); + return AE_ERROR; + } + + return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); + kfree(obj); + + if (return_value.error_code || return_value.ec_return_value) + printk(ACER_WARNING "Get Device Status failed: " + "0x%x - 0x%x\n", return_value.error_code, + return_value.ec_return_value); + else + *value = !!(return_value.devices & device); + + return status; +} + /* * Rfkill devices */ @@ -1002,6 +1070,13 @@ static void acer_rfkill_update(struct work_struct *ignored) rfkill_set_sw_state(bluetooth_rfkill, !state); } + if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { + status = wmid3_get_device_status(&state, + ACER_WMID3_GDS_THREEG); + if (ACPI_SUCCESS(status)) + rfkill_set_sw_state(threeg_rfkill, !state); + } + schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); } @@ -1058,6 +1133,19 @@ static int acer_rfkill_init(struct device *dev) } } + if (has_cap(ACER_CAP_THREEG)) { + threeg_rfkill = acer_rfkill_register(dev, + RFKILL_TYPE_WWAN, "acer-threeg", + ACER_CAP_THREEG); + if (IS_ERR(threeg_rfkill)) { + rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); + rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); + return PTR_ERR(threeg_rfkill); + } + } + schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); return 0; @@ -1074,6 +1162,11 @@ static void acer_rfkill_exit(void) rfkill_unregister(bluetooth_rfkill); rfkill_destroy(bluetooth_rfkill); } + + if (has_cap(ACER_CAP_THREEG)) { + rfkill_unregister(threeg_rfkill); + rfkill_destroy(threeg_rfkill); + } return; } @@ -1084,7 +1177,12 @@ static ssize_t show_bool_threeg(struct device *dev, struct device_attribute *attr, char *buf) { u32 result; \ - acpi_status status = get_u32(&result, ACER_CAP_THREEG); + acpi_status status; + if (wmi_has_guid(WMID_GUID3)) + status = wmid3_get_device_status(&result, + ACER_WMID3_GDS_THREEG); + else + status = get_u32(&result, ACER_CAP_THREEG); if (ACPI_SUCCESS(status)) return sprintf(buf, "%u\n", result); return sprintf(buf, "Read error\n"); -- cgit v1.2.3 From 6c3df88f19375217f0dbfc6160e8c2a635f56c53 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Tue, 7 Dec 2010 10:29:23 +0800 Subject: acer-wmi: Detect the WiFi/Bluetooth/3G devices available Check the Acer OEM-specific Type AA to detect the WiFi/Bluetooth/3G devices available or not, and set the devices capability flag. Signed-off-by: Lee, Chun-Yi Reviewed-by: Jean Delvare Reviewed-by: Dmitry Torokhov Acked-by: Thomas Renninger Acked-by: Jiri Benc Cc: Carlos Corbacho Cc: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 49 +++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 85d263349aac..583565a8bbce 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -124,7 +125,9 @@ struct event_return_value { /* * GUID3 Get Device Status device flags */ +#define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */ #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ +#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ struct wmid3_gds_input_param { /* Get Device Status input parameter */ u8 function_num; /* Function Number */ @@ -139,6 +142,13 @@ struct wmid3_gds_return_value { /* Get Device Status return value*/ u32 reserved; } __attribute__((packed)); +struct hotkey_function_type_aa { + u8 type; + u8 length; + u16 handle; + u16 commun_func_bitmap; +} __attribute__((packed)); + /* * Interface capability flags */ @@ -169,6 +179,7 @@ static int mailled = -1; static int brightness = -1; static int threeg = -1; static int force_series; +static bool has_type_aa; module_param(mailled, int, 0444); module_param(brightness, int, 0444); @@ -807,6 +818,28 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) return WMI_execute_u32(method_id, (u32)value, NULL); } +static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy) +{ + struct hotkey_function_type_aa *type_aa; + + /* We are looking for OEM-specific Type AAh */ + if (header->type != 0xAA) + return; + + has_type_aa = true; + type_aa = (struct hotkey_function_type_aa *) header; + + printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", + type_aa->commun_func_bitmap); + + if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) + interface->capability |= ACER_CAP_WIRELESS; + if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG) + interface->capability |= ACER_CAP_THREEG; + if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH) + interface->capability |= ACER_CAP_BLUETOOTH; +} + static acpi_status WMID_set_capabilities(void) { struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -827,16 +860,17 @@ static acpi_status WMID_set_capabilities(void) return AE_ERROR; } - /* Not sure on the meaning of the relevant bits yet to detect these */ - interface->capability |= ACER_CAP_WIRELESS; - interface->capability |= ACER_CAP_THREEG; + dmi_walk(type_aa_dmi_decode, NULL); + if (!has_type_aa) { + interface->capability |= ACER_CAP_WIRELESS; + interface->capability |= ACER_CAP_THREEG; + if (devices & 0x10) + interface->capability |= ACER_CAP_BLUETOOTH; + } /* WMID always provides brightness methods */ interface->capability |= ACER_CAP_BRIGHTNESS; - if (devices & 0x10) - interface->capability |= ACER_CAP_BLUETOOTH; - if (!(devices & 0x20)) max_brightness = 0x9; @@ -915,7 +949,8 @@ static void __init acer_commandline_init(void) * capability isn't available on the given interface */ set_u32(mailled, ACER_CAP_MAILLED); - set_u32(threeg, ACER_CAP_THREEG); + if (!has_type_aa) + set_u32(threeg, ACER_CAP_THREEG); set_u32(brightness, ACER_CAP_BRIGHTNESS); } -- cgit v1.2.3 From 466449cfe797b8a5d82d25d0e0e08426d8dfba19 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Mon, 13 Dec 2010 10:02:41 +0800 Subject: acer-wmi: Initialize wlan/bluetooth/wwan rfkill software block state Initial wlan/bluetooth/wwan rfkill software block state when acer-wmi driver probe. Acer notebook can save the devices state and this patch can use it to initial the devices' rfkill state. Signed-off-by: Lee, Chun-Yi Acked-by: Thomas Renninger Cc: Carlos Corbacho Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 583565a8bbce..d80db0899382 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1085,6 +1085,31 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) return status; } +static acpi_status get_device_status(u32 *value, u32 cap) +{ + if (wmi_has_guid(WMID_GUID3)) { + u16 device; + + switch (cap) { + case ACER_CAP_WIRELESS: + device = ACER_WMID3_GDS_WIRELESS; + break; + case ACER_CAP_BLUETOOTH: + device = ACER_WMID3_GDS_BLUETOOTH; + break; + case ACER_CAP_THREEG: + device = ACER_WMID3_GDS_THREEG; + break; + default: + return AE_ERROR; + } + return wmid3_get_device_status(value, device); + + } else { + return get_u32(value, cap); + } +} + /* * Rfkill devices */ @@ -1135,6 +1160,8 @@ static struct rfkill *acer_rfkill_register(struct device *dev, { int err; struct rfkill *rfkill_dev; + u32 state; + acpi_status status; rfkill_dev = rfkill_alloc(name, dev, type, &acer_rfkill_ops, @@ -1142,6 +1169,10 @@ static struct rfkill *acer_rfkill_register(struct device *dev, if (!rfkill_dev) return ERR_PTR(-ENOMEM); + status = get_device_status(&state, cap); + if (ACPI_SUCCESS(status)) + rfkill_init_sw_state(rfkill_dev, !state); + err = rfkill_register(rfkill_dev); if (err) { rfkill_destroy(rfkill_dev); -- cgit v1.2.3 From 213658516fd5e125eb7a97995f6cae8996f8015b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Dec 2010 19:56:28 +0100 Subject: ACPI Thinkpad: We must always call va_end() after va_start() but do not do so in thinkpad_acpi.c::acpi_evalf() Hi, In drivers/platform/x86/thinkpad_acpi.c::acpi_evalf() we don't always call va_end() after va_start(). This patch corrects that. Signed-off-by: Jesper Juhl Acked-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f372dc7ae14e..a974ca383cb9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -589,6 +589,7 @@ static int acpi_evalf(acpi_handle handle, default: printk(TPACPI_ERR "acpi_evalf() called " "with invalid format character '%c'\n", c); + va_end(ap); return 0; } } -- cgit v1.2.3 From 456dc301cc3b547b2a674de3028f53fb1453e532 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Fri, 31 Dec 2010 09:48:20 +0800 Subject: [PATCH] intel_pmic_gpio: modify EOI handling following change of kernel irq subsystem Latest kernel has many changes in IRQ subsystem and its interfaces, like adding "irq_eoi" for struct irq_chip, this patch will make it support both the new and old interface. Cc: Alek Du Signed-off-by: Feng Tang Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_pmic_gpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index e61db9dfebef..930e62762365 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -244,7 +244,11 @@ static void pmic_irq_handler(unsigned irq, struct irq_desc *desc) generic_handle_irq(pg->irq_base + gpio); } } - desc->chip->eoi(irq); + + if (desc->chip->irq_eoi) + desc->chip->irq_eoi(irq_get_irq_data(irq)); + else + dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq); } static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) -- cgit v1.2.3 From 59ccf2f3d55c06fd34613f1f78de0279436a7b35 Mon Sep 17 00:00:00 2001 From: "From: Lee, Chun-Yi" Date: Fri, 7 Jan 2011 17:25:14 -0500 Subject: acer-wmi: Enabled Acer Launch Manager mode Enabled Acer Launch Manager mode to disable the EC raw behavior for communication devices when WMID3 method available. And, we also add a ec_raw_mode kernel module option for enable The EC raw behavior mode when anyone what reset it back. When Acer Launch Manager mode enabled, EC will stop to touch any communication devices' RF state or power state that causes conflict with rfkill_input or any userland daemon to charge the rfkill rules. Signed-off-by: Lee, Chun-Yi Acked-by: Thomas Renninger Acked-by: Jiri Benc Acked-by: Dmitry Torokhov Signed-off-by: Carlos Corbacho Cc: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 110 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index d80db0899382..ee40d681edd0 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -129,6 +129,20 @@ struct event_return_value { #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ +struct lm_input_params { + u8 function_num; /* Function Number */ + u16 commun_devices; /* Communication type devices default status */ + u16 devices; /* Other type devices default status */ + u8 lm_status; /* Launch Manager Status */ + u16 reserved; +} __attribute__((packed)); + +struct lm_return_value { + u8 error_code; /* Error Code */ + u8 ec_return_value; /* EC Return Value */ + u16 reserved; +} __attribute__((packed)); + struct wmid3_gds_input_param { /* Get Device Status input parameter */ u8 function_num; /* Function Number */ u8 hotkey_number; /* Hotkey Number */ @@ -179,16 +193,19 @@ static int mailled = -1; static int brightness = -1; static int threeg = -1; static int force_series; +static bool ec_raw_mode; static bool has_type_aa; module_param(mailled, int, 0444); module_param(brightness, int, 0444); module_param(threeg, int, 0444); module_param(force_series, int, 0444); +module_param(ec_raw_mode, bool, 0444); MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); MODULE_PARM_DESC(force_series, "Force a different laptop series"); +MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode"); struct acer_data { int mailled; @@ -1330,6 +1347,85 @@ static void acer_wmi_notify(u32 value, void *context) } } +static acpi_status +wmid3_set_lm_mode(struct lm_input_params *params, + struct lm_return_value *return_value) +{ + acpi_status status; + union acpi_object *obj; + + struct acpi_buffer input = { sizeof(struct lm_input_params), params }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + + status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output); + if (ACPI_FAILURE(status)) + return status; + + obj = output.pointer; + + if (!obj) + return AE_ERROR; + else if (obj->type != ACPI_TYPE_BUFFER) { + kfree(obj); + return AE_ERROR; + } + if (obj->buffer.length != 4) { + printk(ACER_WARNING "Unknown buffer length %d\n", + obj->buffer.length); + kfree(obj); + return AE_ERROR; + } + + *return_value = *((struct lm_return_value *)obj->buffer.pointer); + kfree(obj); + + return status; +} + +static int acer_wmi_enable_ec_raw(void) +{ + struct lm_return_value return_value; + acpi_status status; + struct lm_input_params params = { + .function_num = 0x1, + .commun_devices = 0xFFFF, + .devices = 0xFFFF, + .lm_status = 0x00, /* Launch Manager Deactive */ + }; + + status = wmid3_set_lm_mode(¶ms, &return_value); + + if (return_value.error_code || return_value.ec_return_value) + printk(ACER_WARNING "Enabling EC raw mode failed: " + "0x%x - 0x%x\n", return_value.error_code, + return_value.ec_return_value); + else + printk(ACER_INFO "Enabled EC raw mode"); + + return status; +} + +static int acer_wmi_enable_lm(void) +{ + struct lm_return_value return_value; + acpi_status status; + struct lm_input_params params = { + .function_num = 0x1, + .commun_devices = 0xFFFF, + .devices = 0xFFFF, + .lm_status = 0x01, /* Launch Manager Active */ + }; + + status = wmid3_set_lm_mode(¶ms, &return_value); + + if (return_value.error_code || return_value.ec_return_value) + printk(ACER_WARNING "Enabling Launch Manager failed: " + "0x%x - 0x%x\n", return_value.error_code, + return_value.ec_return_value); + + return status; +} + static int __init acer_wmi_input_setup(void) { acpi_status status; @@ -1618,6 +1714,20 @@ static int __init acer_wmi_init(void) "generic video driver\n"); } + if (wmi_has_guid(WMID_GUID3)) { + if (ec_raw_mode) { + if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { + printk(ACER_ERR "Cannot enable EC raw mode\n"); + return -ENODEV; + } + } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { + printk(ACER_ERR "Cannot enable Launch Manager mode\n"); + return -ENODEV; + } + } else if (ec_raw_mode) { + printk(ACER_INFO "No WMID EC raw mode enable method\n"); + } + if (wmi_has_guid(ACERWMID_EVENT_GUID)) { err = acer_wmi_input_setup(); if (err) -- cgit v1.2.3 From 4a198be7f072190a44033b7de6084b090b9885ee Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 7 Jan 2011 17:29:44 -0500 Subject: Support KHLB2 in the compal laptop driver Add the KHLB2 model identifier to the list of supported models Signed-off-by: Albert Astals Cid Signed-off-by: Matthew Garrett --- drivers/platform/x86/compal-laptop.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 097083cac413..034572b980c9 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -872,6 +872,14 @@ static struct dmi_system_id __initdata compal_dmi_table[] = { }, .callback = dmi_check_cb_extra }, + { + .ident = "KHLB2", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "KHLB2"), + DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"), + }, + .callback = dmi_check_cb_extra + }, { } }; -- cgit v1.2.3 From c97415a72521071c235e0879f9a600014afd87b1 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 26 Nov 2010 19:57:29 +0000 Subject: sysfs: Introducing binary attributes for struct class Added dev_bin_attrs to struct class similar to existing dev_attrs. Signed-off-by: Stefan Achatz Acked-by: Greg Kroah-Hartman Signed-off-by: Jiri Kosina --- drivers/base/core.c | 41 +++++++++++++++++++++++++++++++++++++++-- include/linux/device.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index 6ed645411c40..761359261589 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -338,6 +338,35 @@ static void device_remove_attributes(struct device *dev, device_remove_file(dev, &attrs[i]); } +static int device_add_bin_attributes(struct device *dev, + struct bin_attribute *attrs) +{ + int error = 0; + int i; + + if (attrs) { + for (i = 0; attr_name(attrs[i]); i++) { + error = device_create_bin_file(dev, &attrs[i]); + if (error) + break; + } + if (error) + while (--i >= 0) + device_remove_bin_file(dev, &attrs[i]); + } + return error; +} + +static void device_remove_bin_attributes(struct device *dev, + struct bin_attribute *attrs) +{ + int i; + + if (attrs) + for (i = 0; attr_name(attrs[i]); i++) + device_remove_bin_file(dev, &attrs[i]); +} + static int device_add_groups(struct device *dev, const struct attribute_group **groups) { @@ -378,12 +407,15 @@ static int device_add_attrs(struct device *dev) error = device_add_attributes(dev, class->dev_attrs); if (error) return error; + error = device_add_bin_attributes(dev, class->dev_bin_attrs); + if (error) + goto err_remove_class_attrs; } if (type) { error = device_add_groups(dev, type->groups); if (error) - goto err_remove_class_attrs; + goto err_remove_class_bin_attrs; } error = device_add_groups(dev, dev->groups); @@ -395,6 +427,9 @@ static int device_add_attrs(struct device *dev) err_remove_type_groups: if (type) device_remove_groups(dev, type->groups); + err_remove_class_bin_attrs: + if (class) + device_remove_bin_attributes(dev, class->dev_bin_attrs); err_remove_class_attrs: if (class) device_remove_attributes(dev, class->dev_attrs); @@ -412,8 +447,10 @@ static void device_remove_attrs(struct device *dev) if (type) device_remove_groups(dev, type->groups); - if (class) + if (class) { device_remove_attributes(dev, class->dev_attrs); + device_remove_bin_attributes(dev, class->dev_bin_attrs); + } } diff --git a/include/linux/device.h b/include/linux/device.h index dd4895313468..032bdb5406a2 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -197,6 +197,7 @@ struct class { struct class_attribute *class_attrs; struct device_attribute *dev_attrs; + struct bin_attribute *dev_bin_attrs; struct kobject *dev_kobj; int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); -- cgit v1.2.3 From 5012aada506cb8b570e46579077c0ec5b82ebd5d Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 26 Nov 2010 19:57:33 +0000 Subject: HID: roccat: use class for char device for sysfs attribute creation Adding sysfs attributes to an already created device raises no userland notification. Now the device drivers associate the devices attributes with a class and use this for roccat event char device creation. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 298 ++++++++++++++++++------------------------ drivers/hid/hid-roccat-pyra.c | 273 +++++++++++--------------------------- drivers/hid/hid-roccat.c | 17 +-- drivers/hid/hid-roccat.h | 5 +- 4 files changed, 209 insertions(+), 384 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 73199de2e37f..648d28e5f3f0 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -35,6 +35,9 @@ #include "hid-roccat.h" #include "hid-roccat-kone.h" +/* kone_class is used for creating sysfs attributes via roccat char device */ +static struct class *kone_class; + static void kone_set_settings_checksum(struct kone_settings *settings) { uint16_t checksum = 0; @@ -261,7 +264,8 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result) static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); if (off >= sizeof(struct kone_settings)) @@ -285,7 +289,8 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj, static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval = 0, difference; @@ -321,7 +326,8 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count, int number) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); if (off >= sizeof(struct kone_profile)) @@ -371,7 +377,8 @@ static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj, static ssize_t kone_sysfs_write_profilex(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count, int number) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct kone_profile *profile; @@ -432,14 +439,16 @@ static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj, static ssize_t kone_sysfs_show_actual_profile(struct device *dev, struct device_attribute *attr, char *buf) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); + struct kone_device *kone = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile); } static ssize_t kone_sysfs_show_actual_dpi(struct device *dev, struct device_attribute *attr, char *buf) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); + struct kone_device *kone = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi); } @@ -447,11 +456,15 @@ static ssize_t kone_sysfs_show_actual_dpi(struct device *dev, static ssize_t kone_sysfs_show_weight(struct device *dev, struct device_attribute *attr, char *buf) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); - struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + struct kone_device *kone; + struct usb_device *usb_dev; int weight = 0; int retval; + dev = dev->parent->parent; + kone = hid_get_drvdata(dev_get_drvdata(dev)); + usb_dev = interface_to_usbdev(to_usb_interface(dev)); + mutex_lock(&kone->kone_lock); retval = kone_get_weight(usb_dev, &weight); mutex_unlock(&kone->kone_lock); @@ -464,14 +477,16 @@ static ssize_t kone_sysfs_show_weight(struct device *dev, static ssize_t kone_sysfs_show_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); + struct kone_device *kone = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version); } static ssize_t kone_sysfs_show_tcu(struct device *dev, struct device_attribute *attr, char *buf) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); + struct kone_device *kone = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu); } @@ -503,11 +518,15 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number) static ssize_t kone_sysfs_set_tcu(struct device *dev, struct device_attribute *attr, char const *buf, size_t size) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); - struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + struct kone_device *kone; + struct usb_device *usb_dev; int retval; unsigned long state; + dev = dev->parent->parent; + kone = hid_get_drvdata(dev_get_drvdata(dev)); + usb_dev = interface_to_usbdev(to_usb_interface(dev)); + retval = strict_strtoul(buf, 10, &state); if (retval) return retval; @@ -578,18 +597,23 @@ exit_unlock: static ssize_t kone_sysfs_show_startup_profile(struct device *dev, struct device_attribute *attr, char *buf) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); + struct kone_device *kone = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile); } static ssize_t kone_sysfs_set_startup_profile(struct device *dev, struct device_attribute *attr, char const *buf, size_t size) { - struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); - struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + struct kone_device *kone; + struct usb_device *usb_dev; int retval; unsigned long new_startup_profile; + dev = dev->parent->parent; + kone = hid_get_drvdata(dev_get_drvdata(dev)); + usb_dev = interface_to_usbdev(to_usb_interface(dev)); + retval = strict_strtoul(buf, 10, &new_startup_profile); if (retval) return retval; @@ -616,160 +640,87 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, return size; } -/* - * Read actual dpi settings. - * Returns raw value for further processing. Refer to enum kone_polling_rates to - * get real value. - */ -static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL); - -static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL); - -/* - * The mouse can be equipped with one of four supplied weights from 5 to 20 - * grams which are recognized and its value can be read out. - * This returns the raw value reported by the mouse for easy evaluation by - * software. Refer to enum kone_weights to get corresponding real weight. - */ -static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL); - -/* - * Prints firmware version stored in mouse as integer. - * The raw value reported by the mouse is returned for easy evaluation, to get - * the real version number the decimal point has to be shifted 2 positions to - * the left. E.g. a value of 138 means 1.38. - */ -static DEVICE_ATTR(firmware_version, 0440, - kone_sysfs_show_firmware_version, NULL); - -/* - * Prints state of Tracking Control Unit as number where 0 = off and 1 = on - * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu - */ -static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu); - -/* Prints and takes the number of the profile the mouse starts with */ -static DEVICE_ATTR(startup_profile, 0660, - kone_sysfs_show_startup_profile, - kone_sysfs_set_startup_profile); - -static struct attribute *kone_attributes[] = { - &dev_attr_actual_dpi.attr, - &dev_attr_actual_profile.attr, - &dev_attr_weight.attr, - &dev_attr_firmware_version.attr, - &dev_attr_tcu.attr, - &dev_attr_startup_profile.attr, - NULL -}; - -static struct attribute_group kone_attribute_group = { - .attrs = kone_attributes -}; - -static struct bin_attribute kone_settings_attr = { - .attr = { .name = "settings", .mode = 0660 }, - .size = sizeof(struct kone_settings), - .read = kone_sysfs_read_settings, - .write = kone_sysfs_write_settings -}; +static struct device_attribute kone_attributes[] = { + /* + * Read actual dpi settings. + * Returns raw value for further processing. Refer to enum + * kone_polling_rates to get real value. + */ + __ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL), + __ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL), -static struct bin_attribute kone_profile1_attr = { - .attr = { .name = "profile1", .mode = 0660 }, - .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile1, - .write = kone_sysfs_write_profile1 -}; + /* + * The mouse can be equipped with one of four supplied weights from 5 + * to 20 grams which are recognized and its value can be read out. + * This returns the raw value reported by the mouse for easy evaluation + * by software. Refer to enum kone_weights to get corresponding real + * weight. + */ + __ATTR(weight, 0440, kone_sysfs_show_weight, NULL), -static struct bin_attribute kone_profile2_attr = { - .attr = { .name = "profile2", .mode = 0660 }, - .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile2, - .write = kone_sysfs_write_profile2 -}; + /* + * Prints firmware version stored in mouse as integer. + * The raw value reported by the mouse is returned for easy evaluation, + * to get the real version number the decimal point has to be shifted 2 + * positions to the left. E.g. a value of 138 means 1.38. + */ + __ATTR(firmware_version, 0440, + kone_sysfs_show_firmware_version, NULL), -static struct bin_attribute kone_profile3_attr = { - .attr = { .name = "profile3", .mode = 0660 }, - .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile3, - .write = kone_sysfs_write_profile3 -}; + /* + * Prints state of Tracking Control Unit as number where 0 = off and + * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and + * activates the tcu + */ + __ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu), -static struct bin_attribute kone_profile4_attr = { - .attr = { .name = "profile4", .mode = 0660 }, - .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile4, - .write = kone_sysfs_write_profile4 + /* Prints and takes the number of the profile the mouse starts with */ + __ATTR(startup_profile, 0660, + kone_sysfs_show_startup_profile, + kone_sysfs_set_startup_profile), + __ATTR_NULL }; -static struct bin_attribute kone_profile5_attr = { - .attr = { .name = "profile5", .mode = 0660 }, - .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile5, - .write = kone_sysfs_write_profile5 +static struct bin_attribute kone_bin_attributes[] = { + { + .attr = { .name = "settings", .mode = 0660 }, + .size = sizeof(struct kone_settings), + .read = kone_sysfs_read_settings, + .write = kone_sysfs_write_settings + }, + { + .attr = { .name = "profile1", .mode = 0660 }, + .size = sizeof(struct kone_profile), + .read = kone_sysfs_read_profile1, + .write = kone_sysfs_write_profile1 + }, + { + .attr = { .name = "profile2", .mode = 0660 }, + .size = sizeof(struct kone_profile), + .read = kone_sysfs_read_profile2, + .write = kone_sysfs_write_profile2 + }, + { + .attr = { .name = "profile3", .mode = 0660 }, + .size = sizeof(struct kone_profile), + .read = kone_sysfs_read_profile3, + .write = kone_sysfs_write_profile3 + }, + { + .attr = { .name = "profile4", .mode = 0660 }, + .size = sizeof(struct kone_profile), + .read = kone_sysfs_read_profile4, + .write = kone_sysfs_write_profile4 + }, + { + .attr = { .name = "profile5", .mode = 0660 }, + .size = sizeof(struct kone_profile), + .read = kone_sysfs_read_profile5, + .write = kone_sysfs_write_profile5 + }, + __ATTR_NULL }; -static int kone_create_sysfs_attributes(struct usb_interface *intf) -{ - int retval; - - retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group); - if (retval) - goto exit_1; - - retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr); - if (retval) - goto exit_2; - - retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr); - if (retval) - goto exit_3; - - retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr); - if (retval) - goto exit_4; - - retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr); - if (retval) - goto exit_5; - - retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr); - if (retval) - goto exit_6; - - retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr); - if (retval) - goto exit_7; - - return 0; - -exit_7: - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr); -exit_6: - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr); -exit_5: - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr); -exit_4: - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr); -exit_3: - sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr); -exit_2: - sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group); -exit_1: - return retval; -} - -static void kone_remove_sysfs_attributes(struct usb_interface *intf) -{ - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr); - sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group); -} - static int kone_init_kone_device_struct(struct usb_device *usb_dev, struct kone_device *kone) { @@ -828,7 +779,7 @@ static int kone_init_specials(struct hid_device *hdev) goto exit_free; } - retval = roccat_connect(hdev); + retval = roccat_connect(kone_class, hdev); if (retval < 0) { hid_err(hdev, "couldn't init char dev\n"); /* be tolerant about not getting chrdev */ @@ -836,12 +787,6 @@ static int kone_init_specials(struct hid_device *hdev) kone->roccat_claimed = 1; kone->chrdev_minor = retval; } - - retval = kone_create_sysfs_attributes(intf); - if (retval) { - hid_err(hdev, "cannot create sysfs files\n"); - goto exit_free; - } } else { hid_set_drvdata(hdev, NULL); } @@ -852,7 +797,6 @@ exit_free: return retval; } - static void kone_remove_specials(struct hid_device *hdev) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); @@ -860,7 +804,6 @@ static void kone_remove_specials(struct hid_device *hdev) if (intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { - kone_remove_sysfs_attributes(intf); kone = hid_get_drvdata(hdev); if (kone->roccat_claimed) roccat_disconnect(kone->chrdev_minor); @@ -1004,11 +947,24 @@ static struct hid_driver kone_driver = { static int __init kone_init(void) { - return hid_register_driver(&kone_driver); + int retval; + + /* class name has to be same as driver name */ + kone_class = class_create(THIS_MODULE, "kone"); + if (IS_ERR(kone_class)) + return PTR_ERR(kone_class); + kone_class->dev_attrs = kone_attributes; + kone_class->dev_bin_attrs = kone_bin_attributes; + + retval = hid_register_driver(&kone_driver); + if (retval) + class_destroy(kone_class); + return retval; } static void __exit kone_exit(void) { + class_destroy(kone_class); hid_unregister_driver(&kone_driver); } diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index e7b4affe2664..7273e1e9093d 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -27,6 +27,9 @@ #include "hid-roccat.h" #include "hid-roccat-pyra.h" +/* pyra_class is used for creating sysfs attributes via roccat char device */ +static struct class *pyra_class; + static void profile_activated(struct pyra_device *pyra, unsigned int new_profile) { @@ -222,7 +225,8 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count, int number) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); if (off >= sizeof(struct pyra_profile_settings)) @@ -283,7 +287,8 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count, int number) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); if (off >= sizeof(struct pyra_profile_buttons)) @@ -344,7 +349,8 @@ static ssize_t pyra_sysfs_write_profile_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval = 0; @@ -380,7 +386,8 @@ static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval = 0; @@ -416,7 +423,8 @@ static ssize_t pyra_sysfs_read_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); if (off >= sizeof(struct pyra_settings)) @@ -436,7 +444,8 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval = 0; @@ -468,255 +477,115 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev, struct device_attribute *attr, char *buf) { - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); + struct pyra_device *pyra = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi); } static ssize_t pyra_sysfs_show_actual_profile(struct device *dev, struct device_attribute *attr, char *buf) { - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); + struct pyra_device *pyra = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile); } static ssize_t pyra_sysfs_show_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) { - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); + struct pyra_device *pyra = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version); } static ssize_t pyra_sysfs_show_startup_profile(struct device *dev, struct device_attribute *attr, char *buf) { - struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); + struct pyra_device *pyra = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile); } -static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL); - -static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL); - -static DEVICE_ATTR(firmware_version, 0440, - pyra_sysfs_show_firmware_version, NULL); - -static DEVICE_ATTR(startup_profile, 0440, - pyra_sysfs_show_startup_profile, NULL); - -static struct attribute *pyra_attributes[] = { - &dev_attr_actual_cpi.attr, - &dev_attr_actual_profile.attr, - &dev_attr_firmware_version.attr, - &dev_attr_startup_profile.attr, - NULL -}; - -static struct attribute_group pyra_attribute_group = { - .attrs = pyra_attributes +static struct device_attribute pyra_attributes[] = { + __ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL), + __ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL), + __ATTR(firmware_version, 0440, + pyra_sysfs_show_firmware_version, NULL), + __ATTR(startup_profile, 0440, + pyra_sysfs_show_startup_profile, NULL), + __ATTR_NULL }; -static struct bin_attribute pyra_profile_settings_attr = { +static struct bin_attribute pyra_bin_attributes[] = { + { .attr = { .name = "profile_settings", .mode = 0220 }, .size = sizeof(struct pyra_profile_settings), .write = pyra_sysfs_write_profile_settings -}; - -static struct bin_attribute pyra_profile1_settings_attr = { + }, + { .attr = { .name = "profile1_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), .read = pyra_sysfs_read_profile1_settings -}; - -static struct bin_attribute pyra_profile2_settings_attr = { + }, + { .attr = { .name = "profile2_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), .read = pyra_sysfs_read_profile2_settings -}; - -static struct bin_attribute pyra_profile3_settings_attr = { + }, + { .attr = { .name = "profile3_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), .read = pyra_sysfs_read_profile3_settings -}; - -static struct bin_attribute pyra_profile4_settings_attr = { + }, + { .attr = { .name = "profile4_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), .read = pyra_sysfs_read_profile4_settings -}; - -static struct bin_attribute pyra_profile5_settings_attr = { + }, + { .attr = { .name = "profile5_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), .read = pyra_sysfs_read_profile5_settings -}; - -static struct bin_attribute pyra_profile_buttons_attr = { + }, + { .attr = { .name = "profile_buttons", .mode = 0220 }, .size = sizeof(struct pyra_profile_buttons), .write = pyra_sysfs_write_profile_buttons -}; - -static struct bin_attribute pyra_profile1_buttons_attr = { + }, + { .attr = { .name = "profile1_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), .read = pyra_sysfs_read_profile1_buttons -}; - -static struct bin_attribute pyra_profile2_buttons_attr = { + }, + { .attr = { .name = "profile2_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), .read = pyra_sysfs_read_profile2_buttons -}; - -static struct bin_attribute pyra_profile3_buttons_attr = { + }, + { .attr = { .name = "profile3_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), .read = pyra_sysfs_read_profile3_buttons -}; - -static struct bin_attribute pyra_profile4_buttons_attr = { + }, + { .attr = { .name = "profile4_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), .read = pyra_sysfs_read_profile4_buttons -}; - -static struct bin_attribute pyra_profile5_buttons_attr = { + }, + { .attr = { .name = "profile5_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), .read = pyra_sysfs_read_profile5_buttons -}; - -static struct bin_attribute pyra_settings_attr = { + }, + { .attr = { .name = "settings", .mode = 0660 }, .size = sizeof(struct pyra_settings), .read = pyra_sysfs_read_settings, .write = pyra_sysfs_write_settings + }, + __ATTR_NULL }; -static int pyra_create_sysfs_attributes(struct usb_interface *intf) -{ - int retval; - - retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group); - if (retval) - goto exit_1; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile_settings_attr); - if (retval) - goto exit_2; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile1_settings_attr); - if (retval) - goto exit_3; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile2_settings_attr); - if (retval) - goto exit_4; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile3_settings_attr); - if (retval) - goto exit_5; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile4_settings_attr); - if (retval) - goto exit_6; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile5_settings_attr); - if (retval) - goto exit_7; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile_buttons_attr); - if (retval) - goto exit_8; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile1_buttons_attr); - if (retval) - goto exit_9; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile2_buttons_attr); - if (retval) - goto exit_10; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile3_buttons_attr); - if (retval) - goto exit_11; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile4_buttons_attr); - if (retval) - goto exit_12; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_profile5_buttons_attr); - if (retval) - goto exit_13; - - retval = sysfs_create_bin_file(&intf->dev.kobj, - &pyra_settings_attr); - if (retval) - goto exit_14; - - return 0; - -exit_14: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr); -exit_13: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr); -exit_12: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr); -exit_11: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr); -exit_10: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr); -exit_9: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr); -exit_8: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr); -exit_7: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr); -exit_6: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr); -exit_5: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr); -exit_4: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr); -exit_3: - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr); -exit_2: - sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group); -exit_1: - return retval; -} - -static void pyra_remove_sysfs_attributes(struct usb_interface *intf) -{ - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr); - sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr); - sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group); -} - static int pyra_init_pyra_device_struct(struct usb_device *usb_dev, struct pyra_device *pyra) { @@ -780,19 +649,13 @@ static int pyra_init_specials(struct hid_device *hdev) goto exit_free; } - retval = roccat_connect(hdev); + retval = roccat_connect(pyra_class, hdev); if (retval < 0) { hid_err(hdev, "couldn't init char dev\n"); } else { pyra->chrdev_minor = retval; pyra->roccat_claimed = 1; } - - retval = pyra_create_sysfs_attributes(intf); - if (retval) { - hid_err(hdev, "cannot create sysfs files\n"); - goto exit_free; - } } else { hid_set_drvdata(hdev, NULL); } @@ -810,7 +673,6 @@ static void pyra_remove_specials(struct hid_device *hdev) if (intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { - pyra_remove_sysfs_attributes(intf); pyra = hid_get_drvdata(hdev); if (pyra->roccat_claimed) roccat_disconnect(pyra->chrdev_minor); @@ -950,11 +812,24 @@ static struct hid_driver pyra_driver = { static int __init pyra_init(void) { - return hid_register_driver(&pyra_driver); + int retval; + + /* class name has to be same as driver name */ + pyra_class = class_create(THIS_MODULE, "pyra"); + if (IS_ERR(pyra_class)) + return PTR_ERR(pyra_class); + pyra_class->dev_attrs = pyra_attributes; + pyra_class->dev_bin_attrs = pyra_bin_attributes; + + retval = hid_register_driver(&pyra_driver); + if (retval) + class_destroy(pyra_class); + return retval; } static void __exit pyra_exit(void) { + class_destroy(pyra_class); hid_unregister_driver(&pyra_driver); } diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index 4bc7a93dc1f5..a14c579ea781 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -67,7 +67,6 @@ struct roccat_reader { }; static int roccat_major; -static struct class *roccat_class; static struct cdev roccat_cdev; static struct roccat_device *devices[ROCCAT_MAX_DEVICES]; @@ -289,12 +288,14 @@ EXPORT_SYMBOL_GPL(roccat_report_event); /* * roccat_connect() - create a char device for special event output + * @class: the class thats used to create the device. Meant to hold device + * specific sysfs attributes. * @hid: the hid device the char device should be connected to. * * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on * success, a negative error code on failure. */ -int roccat_connect(struct hid_device *hid) +int roccat_connect(struct class *klass, struct hid_device *hid) { unsigned int minor; struct roccat_device *device; @@ -320,7 +321,7 @@ int roccat_connect(struct hid_device *hid) return -EINVAL; } - device->dev = device_create(roccat_class, &hid->dev, + device->dev = device_create(klass, &hid->dev, MKDEV(roccat_major, minor), NULL, "%s%s%d", "roccat", hid->driver->name, minor); @@ -361,7 +362,7 @@ void roccat_disconnect(int minor) device->exist = 0; /* TODO exist maybe not needed */ - device_destroy(roccat_class, MKDEV(roccat_major, minor)); + device_destroy(device->dev->class, MKDEV(roccat_major, minor)); if (device->open) { hid_hw_close(device->hid); @@ -396,13 +397,6 @@ static int __init roccat_init(void) return retval; } - roccat_class = class_create(THIS_MODULE, "roccat"); - if (IS_ERR(roccat_class)) { - retval = PTR_ERR(roccat_class); - unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES); - return retval; - } - cdev_init(&roccat_cdev, &roccat_ops); cdev_add(&roccat_cdev, dev_id, ROCCAT_MAX_DEVICES); @@ -414,7 +408,6 @@ static void __exit roccat_exit(void) dev_t dev_id = MKDEV(roccat_major, 0); cdev_del(&roccat_cdev); - class_destroy(roccat_class); unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES); } diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h index 09e864e9f79d..5784281d613f 100644 --- a/drivers/hid/hid-roccat.h +++ b/drivers/hid/hid-roccat.h @@ -16,11 +16,12 @@ #include #if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE) -int roccat_connect(struct hid_device *hid); +int roccat_connect(struct class *klass, struct hid_device *hid); void roccat_disconnect(int minor); int roccat_report_event(int minor, u8 const *data, int len); #else -static inline int roccat_connect(struct hid_device *hid) { return -1; } +static inline int roccat_connect(struct class *klass, + struct hid_device *hid) { return -1; } static inline void roccat_disconnect(int minor) {} static inline int roccat_report_event(int minor, u8 const *data, int len) { -- cgit v1.2.3 From bd3a2b96631dd86b06dca96aef00790084a11e15 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 26 Nov 2010 19:57:36 +0000 Subject: HID: roccat: declare meaning of pack pragma usage in driver headers Using pack pragma to prevent padding bytes in binary data structures used for hardware communication. Explanation of these pragmas was requested. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.h | 3 +++ drivers/hid/hid-roccat-pyra.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 130d6566ea82..11203a75b0f9 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -14,6 +14,9 @@ #include +/* + * Binary data structures used for hardware communication must have no padding. + */ #pragma pack(push) #pragma pack(1) diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h index 22f80a8f26f9..ac5996e8817c 100644 --- a/drivers/hid/hid-roccat-pyra.h +++ b/drivers/hid/hid-roccat-pyra.h @@ -14,6 +14,9 @@ #include +/* + * Binary data structures used for hardware communication must have no padding. + */ #pragma pack(push) #pragma pack(1) -- cgit v1.2.3 From 14a057f80f0c4d45a9e68009f8bcb6b246e87ca0 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 26 Nov 2010 19:57:38 +0000 Subject: HID: roccat: reduce number of functions in kone and pyra drivers The profile number is now passed via bin_attribute->private instead of function parameter to reduce number of functions. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 106 ++++++++++--------------------------- drivers/hid/hid-roccat-pyra.c | 120 +++++++++--------------------------------- 2 files changed, 53 insertions(+), 173 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 648d28e5f3f0..cbd8cc42e75a 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -35,6 +35,8 @@ #include "hid-roccat.h" #include "hid-roccat-kone.h" +static uint profile_numbers[5] = {0, 1, 2, 3, 4}; + /* kone_class is used for creating sysfs attributes via roccat char device */ static struct class *kone_class; @@ -323,9 +325,9 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, return sizeof(struct kone_settings); } -static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count, int number) { +static ssize_t kone_sysfs_read_profilex(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); @@ -337,46 +339,16 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, count = sizeof(struct kone_profile) - off; mutex_lock(&kone->kone_lock); - memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count); + memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count); mutex_unlock(&kone->kone_lock); return count; } -static ssize_t kone_sysfs_read_profile1(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1); -} - -static ssize_t kone_sysfs_read_profile2(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2); -} - -static ssize_t kone_sysfs_read_profile3(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3); -} - -static ssize_t kone_sysfs_read_profile4(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4); -} - -static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5); -} - /* Writes data only if different to stored data */ -static ssize_t kone_sysfs_write_profilex(struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count, int number) { +static ssize_t kone_sysfs_write_profilex(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); @@ -388,13 +360,14 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj, if (off != 0 || count != sizeof(struct kone_profile)) return -EINVAL; - profile = &kone->profiles[number - 1]; + profile = &kone->profiles[*(uint *)(attr->private)]; mutex_lock(&kone->kone_lock); difference = memcmp(buf, profile, sizeof(struct kone_profile)); if (difference) { retval = kone_set_profile(usb_dev, - (struct kone_profile const *)buf, number); + (struct kone_profile const *)buf, + *(uint *)(attr->private) + 1); if (!retval) memcpy(profile, buf, sizeof(struct kone_profile)); } @@ -406,36 +379,6 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj, return sizeof(struct kone_profile); } -static ssize_t kone_sysfs_write_profile1(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1); -} - -static ssize_t kone_sysfs_write_profile2(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2); -} - -static ssize_t kone_sysfs_write_profile3(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3); -} - -static ssize_t kone_sysfs_write_profile4(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4); -} - -static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) { - return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5); -} - static ssize_t kone_sysfs_show_actual_profile(struct device *dev, struct device_attribute *attr, char *buf) { @@ -691,32 +634,37 @@ static struct bin_attribute kone_bin_attributes[] = { { .attr = { .name = "profile1", .mode = 0660 }, .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile1, - .write = kone_sysfs_write_profile1 + .read = kone_sysfs_read_profilex, + .write = kone_sysfs_write_profilex, + .private = &profile_numbers[0] }, { .attr = { .name = "profile2", .mode = 0660 }, .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile2, - .write = kone_sysfs_write_profile2 + .read = kone_sysfs_read_profilex, + .write = kone_sysfs_write_profilex, + .private = &profile_numbers[1] }, { .attr = { .name = "profile3", .mode = 0660 }, .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile3, - .write = kone_sysfs_write_profile3 + .read = kone_sysfs_read_profilex, + .write = kone_sysfs_write_profilex, + .private = &profile_numbers[2] }, { .attr = { .name = "profile4", .mode = 0660 }, .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile4, - .write = kone_sysfs_write_profile4 + .read = kone_sysfs_read_profilex, + .write = kone_sysfs_write_profilex, + .private = &profile_numbers[3] }, { .attr = { .name = "profile5", .mode = 0660 }, .size = sizeof(struct kone_profile), - .read = kone_sysfs_read_profile5, - .write = kone_sysfs_write_profile5 + .read = kone_sysfs_read_profilex, + .write = kone_sysfs_write_profilex, + .private = &profile_numbers[4] }, __ATTR_NULL }; diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 7273e1e9093d..02c58e015bee 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -27,6 +27,8 @@ #include "hid-roccat.h" #include "hid-roccat-pyra.h" +static uint profile_numbers[5] = {0, 1, 2, 3, 4}; + /* pyra_class is used for creating sysfs attributes via roccat char device */ static struct class *pyra_class; @@ -223,7 +225,7 @@ static int pyra_set_settings(struct usb_device *usb_dev, static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count, int number) + loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj)->parent->parent; @@ -236,56 +238,16 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, count = sizeof(struct pyra_profile_settings) - off; mutex_lock(&pyra->pyra_lock); - memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off, + memcpy(buf, ((char const *)&pyra->profile_settings[*(uint *)(attr->private)]) + off, count); mutex_unlock(&pyra->pyra_lock); return count; } -static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 0); -} - -static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 1); -} - -static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 2); -} - -static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 3); -} - -static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_settings(fp, kobj, - attr, buf, off, count, 4); -} - static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count, int number) + loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj)->parent->parent; @@ -298,53 +260,13 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, count = sizeof(struct pyra_profile_buttons) - off; mutex_lock(&pyra->pyra_lock); - memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off, + memcpy(buf, ((char const *)&pyra->profile_buttons[*(uint *)(attr->private)]) + off, count); mutex_unlock(&pyra->pyra_lock); return count; } -static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 0); -} - -static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 1); -} - -static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 2); -} - -static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 3); -} - -static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp, - struct kobject *kobj, struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - return pyra_sysfs_read_profilex_buttons(fp, kobj, - attr, buf, off, count, 4); -} - static ssize_t pyra_sysfs_write_profile_settings(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) @@ -525,27 +447,32 @@ static struct bin_attribute pyra_bin_attributes[] = { { .attr = { .name = "profile1_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile1_settings + .read = pyra_sysfs_read_profilex_settings, + .private = &profile_numbers[0] }, { .attr = { .name = "profile2_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile2_settings + .read = pyra_sysfs_read_profilex_settings, + .private = &profile_numbers[1] }, { .attr = { .name = "profile3_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile3_settings + .read = pyra_sysfs_read_profilex_settings, + .private = &profile_numbers[2] }, { .attr = { .name = "profile4_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile4_settings + .read = pyra_sysfs_read_profilex_settings, + .private = &profile_numbers[3] }, { .attr = { .name = "profile5_settings", .mode = 0440 }, .size = sizeof(struct pyra_profile_settings), - .read = pyra_sysfs_read_profile5_settings + .read = pyra_sysfs_read_profilex_settings, + .private = &profile_numbers[4] }, { .attr = { .name = "profile_buttons", .mode = 0220 }, @@ -555,27 +482,32 @@ static struct bin_attribute pyra_bin_attributes[] = { { .attr = { .name = "profile1_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile1_buttons + .read = pyra_sysfs_read_profilex_buttons, + .private = &profile_numbers[0] }, { .attr = { .name = "profile2_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile2_buttons + .read = pyra_sysfs_read_profilex_buttons, + .private = &profile_numbers[1] }, { .attr = { .name = "profile3_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile3_buttons + .read = pyra_sysfs_read_profilex_buttons, + .private = &profile_numbers[2] }, { .attr = { .name = "profile4_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile4_buttons + .read = pyra_sysfs_read_profilex_buttons, + .private = &profile_numbers[3] }, { .attr = { .name = "profile5_buttons", .mode = 0440 }, .size = sizeof(struct pyra_profile_buttons), - .read = pyra_sysfs_read_profile5_buttons + .read = pyra_sysfs_read_profilex_buttons, + .private = &profile_numbers[4] }, { .attr = { .name = "settings", .mode = 0660 }, -- cgit v1.2.3 From 47dbdbffe15b9582a41727766d43f1d4208e977e Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 26 Nov 2010 19:57:42 +0000 Subject: HID: roccat: Add support for Roccat Kone[+] v2 This patch adds support for Roccat Kone[+] gaming mouse. Kone[+] is an enhanced version of the old Kone with more memory for macros, a better sensor and more functionality. This driver is conceptual similar to the existing Kone and Pyra drivers. Userland tools can soon be found at http://sourceforge.net/projects/roccat Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-roccat-koneplus | 108 +++ drivers/hid/Kconfig | 7 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-roccat-koneplus.c | 837 +++++++++++++++++++++ drivers/hid/hid-roccat-koneplus.h | 232 ++++++ 7 files changed, 1187 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus create mode 100644 drivers/hid/hid-roccat-koneplus.c create mode 100644 drivers/hid/hid-roccat-koneplus.h (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus new file mode 100644 index 000000000000..0ebb64008cf7 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus @@ -0,0 +1,108 @@ +What: /sys/bus/usb/devices/-:./actual_profile +Date: October 2010 +Contact: Stefan Achatz +Description: When read, this file returns the number of the actual profile in + range 0-4. + This file is readonly. + +What: /sys/bus/usb/devices/-:./firmware_version +Date: October 2010 +Contact: Stefan Achatz +Description: When read, this file returns the raw integer version number of the + firmware reported by the mouse. Using the integer value eases + further usage in other programs. To receive the real version + number the decimal point has to be shifted 2 positions to the + left. E.g. a returned value of 121 means 1.21 + This file is readonly. + +What: /sys/bus/usb/devices/-:./macro +Date: October 2010 +Contact: Stefan Achatz +Description: The mouse can store a macro with max 500 key/button strokes + internally. + When written, this file lets one set the sequence for a specific + button for a specific profile. Button and profile numbers are + included in written data. The data has to be 2082 bytes long. + This file is writeonly. + +What: /sys/bus/usb/devices/-:./profile_buttons +Date: August 2010 +Contact: Stefan Achatz +Description: The mouse can store 5 profiles which can be switched by the + press of a button. A profile is split in settings and buttons. + profile_buttons holds informations about button layout. + When written, this file lets one write the respective profile + buttons back to the mouse. The data has to be 77 bytes long. + The mouse will reject invalid data. + Which profile to write is determined by the profile number + contained in the data. + This file is writeonly. + +What: /sys/bus/usb/devices/-:./profile[1-5]_buttons +Date: August 2010 +Contact: Stefan Achatz +Description: The mouse can store 5 profiles which can be switched by the + press of a button. A profile is split in settings and buttons. + profile_buttons holds informations about button layout. + When read, these files return the respective profile buttons. + The returned data is 77 bytes in size. + This file is readonly. + +What: /sys/bus/usb/devices/-:./profile_settings +Date: October 2010 +Contact: Stefan Achatz +Description: The mouse can store 5 profiles which can be switched by the + press of a button. A profile is split in settings and buttons. + profile_settings holds informations like resolution, sensitivity + and light effects. + When written, this file lets one write the respective profile + settings back to the mouse. The data has to be 43 bytes long. + The mouse will reject invalid data. + Which profile to write is determined by the profile number + contained in the data. + This file is writeonly. + +What: /sys/bus/usb/devices/-:./profile[1-5]_settings +Date: August 2010 +Contact: Stefan Achatz +Description: The mouse can store 5 profiles which can be switched by the + press of a button. A profile is split in settings and buttons. + profile_settings holds informations like resolution, sensitivity + and light effects. + When read, these files return the respective profile settings. + The returned data is 43 bytes in size. + This file is readonly. + +What: /sys/bus/usb/devices/-:./sensor +Date: October 2010 +Contact: Stefan Achatz +Description: The mouse has a tracking- and a distance-control-unit. These + can be activated/deactivated and the lift-off distance can be + set. The data has to be 6 bytes long. + This file is writeonly. + +What: /sys/bus/usb/devices/-:./startup_profile +Date: October 2010 +Contact: Stefan Achatz +Description: The integer value of this attribute ranges from 0-4. + When read, this attribute returns the number of the profile + that's active when the mouse is powered on. + When written, this file sets the number of the startup profile + and the mouse activates this profile immediately. + +What: /sys/bus/usb/devices/-:./tcu +Date: October 2010 +Contact: Stefan Achatz +Description: When written a calibration process for the tracking control unit + can be initiated/cancelled. + The data has to be 3 bytes long. + This file is writeonly. + +What: /sys/bus/usb/devices/-:./tcu_image +Date: October 2010 +Contact: Stefan Achatz +Description: When read the mouse returns a 30x30 pixel image of the + sampled underground. This works only in the course of a + calibration process initiated with tcu. + The returned data is 1028 bytes in size. + This file is readonly. diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 3d9a95f28aea..d2a27519ed13 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -406,6 +406,13 @@ config HID_ROCCAT_KONE ---help--- Support for Roccat Kone mouse. +config HID_ROCCAT_KONEPLUS + tristate "Roccat Kone[+] mouse support" + depends on USB_HID + select HID_ROCCAT + ---help--- + Support for Roccat Kone[+] mouse. + config HID_ROCCAT_PYRA tristate "Roccat Pyra mouse support" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b406269d1bcb..6eae9a90b8dd 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o +obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c4d47e635f95..04b7eb046820 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1397,6 +1397,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5cd1a6a356a3..a945d795e4ed 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -485,6 +485,7 @@ #define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced +#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c new file mode 100644 index 000000000000..1608c8d1efd6 --- /dev/null +++ b/drivers/hid/hid-roccat-koneplus.c @@ -0,0 +1,837 @@ +/* + * Roccat Kone[+] driver for Linux + * + * Copyright (c) 2010 Stefan Achatz + */ + +/* + * 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. + */ + +/* + * Roccat Kone[+] is an updated/improved version of the Kone with more memory + * and functionality and without the non-standard behaviours the Kone had. + */ + +#include +#include +#include +#include +#include +#include +#include "hid-ids.h" +#include "hid-roccat.h" +#include "hid-roccat-koneplus.h" + +static uint profile_numbers[5] = {0, 1, 2, 3, 4}; + +static struct class *koneplus_class; + +static void koneplus_profile_activated(struct koneplus_device *koneplus, + uint new_profile) +{ + koneplus->actual_profile = new_profile; +} + +static int koneplus_send_control(struct usb_device *usb_dev, uint value, + enum koneplus_control_requests request) +{ + int len; + struct koneplus_control *control; + + if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || + request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && + value > 4) + return -EINVAL; + + control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL); + if (!control) + return -ENOMEM; + + control->command = KONEPLUS_COMMAND_CONTROL; + control->value = value; + control->request = request; + + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + USB_REQ_SET_CONFIGURATION, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + KONEPLUS_USB_COMMAND_CONTROL, 0, control, + sizeof(struct koneplus_control), + USB_CTRL_SET_TIMEOUT); + + kfree(control); + + if (len != sizeof(struct koneplus_control)) + return len; + + return 0; +} + +static int koneplus_receive(struct usb_device *usb_dev, uint usb_command, + void *buf, uint size) { + int len; + + len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), + USB_REQ_CLEAR_FEATURE, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); + + return (len != size) ? -EIO : 0; +} + +static int koneplus_receive_control_status(struct usb_device *usb_dev) +{ + int retval; + struct koneplus_control *control; + + control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL); + if (!control) + return -ENOMEM; + + do { + retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL, + control, sizeof(struct koneplus_control)); + + /* check if we get a completely wrong answer */ + if (retval) + goto out; + + if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OK) { + retval = 0; + goto out; + } + + /* indicates that hardware needs some more time to complete action */ + if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) { + msleep(500); /* windows driver uses 1000 */ + continue; + } + + /* seems to be critical - replug necessary */ + if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) { + retval = -EINVAL; + goto out; + } + + dev_err(&usb_dev->dev, "koneplus_receive_control_status: " + "unknown response value 0x%x\n", control->value); + retval = -EINVAL; + goto out; + + } while (1); +out: + kfree(control); + return retval; +} + +static int koneplus_send(struct usb_device *usb_dev, uint command, + void *buf, uint size) { + int len; + + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + USB_REQ_SET_CONFIGURATION, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + command, 0, buf, size, USB_CTRL_SET_TIMEOUT); + + if (len != size) + return -EIO; + + if (koneplus_receive_control_status(usb_dev)) + return -EIO; + + return 0; +} + +static int koneplus_select_profile(struct usb_device *usb_dev, uint number, + enum koneplus_control_requests request) +{ + int retval; + + retval = koneplus_send_control(usb_dev, number, request); + if (retval) + return retval; + + /* allow time to settle things - windows driver uses 500 */ + msleep(100); + + retval = koneplus_receive_control_status(usb_dev); + if (retval) + return retval; + + return 0; +} + +static int koneplus_get_info(struct usb_device *usb_dev, + struct koneplus_info *buf) +{ + return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO, + buf, sizeof(struct koneplus_info)); +} + +static int koneplus_get_profile_settings(struct usb_device *usb_dev, + struct koneplus_profile_settings *buf, uint number) +{ + int retval; + + retval = koneplus_select_profile(usb_dev, number, + KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS); + if (retval) + return retval; + + return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS, + buf, sizeof(struct koneplus_profile_settings)); +} + +static int koneplus_set_profile_settings(struct usb_device *usb_dev, + struct koneplus_profile_settings const *settings) +{ + return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS, + (void *)settings, sizeof(struct koneplus_profile_settings)); +} + +static int koneplus_get_profile_buttons(struct usb_device *usb_dev, + struct koneplus_profile_buttons *buf, int number) +{ + int retval; + + retval = koneplus_select_profile(usb_dev, number, + KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS); + if (retval) + return retval; + + return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS, + buf, sizeof(struct koneplus_profile_buttons)); +} + +static int koneplus_set_profile_buttons(struct usb_device *usb_dev, + struct koneplus_profile_buttons const *buttons) +{ + return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS, + (void *)buttons, sizeof(struct koneplus_profile_buttons)); +} + +/* retval is 0-4 on success, < 0 on error */ +static int koneplus_get_startup_profile(struct usb_device *usb_dev) +{ + struct koneplus_startup_profile *buf; + int retval; + + buf = kmalloc(sizeof(struct koneplus_startup_profile), GFP_KERNEL); + + retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE, + buf, sizeof(struct koneplus_startup_profile)); + + if (retval) + goto out; + + retval = buf->startup_profile; +out: + kfree(buf); + return retval; +} + +static int koneplus_set_startup_profile(struct usb_device *usb_dev, + int startup_profile) +{ + struct koneplus_startup_profile buf; + + buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE; + buf.size = sizeof(struct koneplus_startup_profile); + buf.startup_profile = startup_profile; + + return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE, + (char *)&buf, sizeof(struct koneplus_profile_buttons)); +} + +static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj, + char *buf, loff_t off, size_t count, + size_t real_size, uint command) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval; + + if (off != 0 || count != real_size) + return -EINVAL; + + mutex_lock(&koneplus->koneplus_lock); + retval = koneplus_receive(usb_dev, command, buf, real_size); + mutex_unlock(&koneplus->koneplus_lock); + + if (retval) + return retval; + + return real_size; +} + +static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj, + void const *buf, loff_t off, size_t count, + size_t real_size, uint command) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval; + + if (off != 0 || count != real_size) + return -EINVAL; + + mutex_lock(&koneplus->koneplus_lock); + retval = koneplus_send(usb_dev, command, (void *)buf, real_size); + mutex_unlock(&koneplus->koneplus_lock); + + if (retval) + return retval; + + return real_size; +} + +static ssize_t koneplus_sysfs_write_macro(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return koneplus_sysfs_write(fp, kobj, buf, off, count, + sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO); +} + +static ssize_t koneplus_sysfs_read_sensor(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return koneplus_sysfs_read(fp, kobj, buf, off, count, + sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR); +} + +static ssize_t koneplus_sysfs_write_sensor(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return koneplus_sysfs_write(fp, kobj, buf, off, count, + sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR); +} + +static ssize_t koneplus_sysfs_write_tcu(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return koneplus_sysfs_write(fp, kobj, buf, off, count, + sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU); +} + +static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return koneplus_sysfs_read(fp, kobj, buf, off, count, + sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU); +} + +static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + + if (off >= sizeof(struct koneplus_profile_settings)) + return 0; + + if (off + count > sizeof(struct koneplus_profile_settings)) + count = sizeof(struct koneplus_profile_settings) - off; + + mutex_lock(&koneplus->koneplus_lock); + memcpy(buf, ((void const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off, + count); + mutex_unlock(&koneplus->koneplus_lock); + + return count; +} + +static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval = 0; + int difference; + int profile_number; + struct koneplus_profile_settings *profile_settings; + + if (off != 0 || count != sizeof(struct koneplus_profile_settings)) + return -EINVAL; + + profile_number = ((struct koneplus_profile_settings const *)buf)->number; + profile_settings = &koneplus->profile_settings[profile_number]; + + mutex_lock(&koneplus->koneplus_lock); + difference = memcmp(buf, profile_settings, + sizeof(struct koneplus_profile_settings)); + if (difference) { + retval = koneplus_set_profile_settings(usb_dev, + (struct koneplus_profile_settings const *)buf); + if (!retval) + memcpy(profile_settings, buf, + sizeof(struct koneplus_profile_settings)); + } + mutex_unlock(&koneplus->koneplus_lock); + + if (retval) + return retval; + + return sizeof(struct koneplus_profile_settings); +} + +static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + + if (off >= sizeof(struct koneplus_profile_buttons)) + return 0; + + if (off + count > sizeof(struct koneplus_profile_buttons)) + count = sizeof(struct koneplus_profile_buttons) - off; + + mutex_lock(&koneplus->koneplus_lock); + memcpy(buf, ((void const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off, + count); + mutex_unlock(&koneplus->koneplus_lock); + + return count; +} + +static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval = 0; + int difference; + uint profile_number; + struct koneplus_profile_buttons *profile_buttons; + + if (off != 0 || count != sizeof(struct koneplus_profile_buttons)) + return -EINVAL; + + profile_number = ((struct koneplus_profile_buttons const *)buf)->number; + profile_buttons = &koneplus->profile_buttons[profile_number]; + + mutex_lock(&koneplus->koneplus_lock); + difference = memcmp(buf, profile_buttons, + sizeof(struct koneplus_profile_buttons)); + if (difference) { + retval = koneplus_set_profile_buttons(usb_dev, + (struct koneplus_profile_buttons const *)buf); + if (!retval) + memcpy(profile_buttons, buf, + sizeof(struct koneplus_profile_buttons)); + } + mutex_unlock(&koneplus->koneplus_lock); + + if (retval) + return retval; + + return sizeof(struct koneplus_profile_buttons); +} + +static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct koneplus_device *koneplus = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); + return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile); +} + +static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev, + struct device_attribute *attr, char const *buf, size_t size) +{ + struct koneplus_device *koneplus; + struct usb_device *usb_dev; + unsigned long profile; + int retval; + + dev = dev->parent->parent; + koneplus = hid_get_drvdata(dev_get_drvdata(dev)); + usb_dev = interface_to_usbdev(to_usb_interface(dev)); + + retval = strict_strtoul(buf, 10, &profile); + if (retval) + return retval; + + mutex_lock(&koneplus->koneplus_lock); + retval = koneplus_set_startup_profile(usb_dev, profile); + mutex_unlock(&koneplus->koneplus_lock); + if (retval) + return retval; + + return size; +} + +static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct koneplus_device *koneplus = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); + return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile); +} + +static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct koneplus_device *koneplus = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); + return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version); +} + +static struct device_attribute koneplus_attributes[] = { + __ATTR(startup_profile, 0660, + koneplus_sysfs_show_startup_profile, + koneplus_sysfs_set_startup_profile), + __ATTR(actual_profile, 0440, + koneplus_sysfs_show_actual_profile, NULL), + __ATTR(firmware_version, 0440, + koneplus_sysfs_show_firmware_version, NULL), + __ATTR_NULL +}; + +static struct bin_attribute koneplus_bin_attributes[] = { + { + .attr = { .name = "sensor", .mode = 0220 }, + .size = sizeof(struct koneplus_sensor), + .read = koneplus_sysfs_read_sensor, + .write = koneplus_sysfs_write_sensor + }, + { + .attr = { .name = "tcu", .mode = 0220 }, + .size = sizeof(struct koneplus_tcu), + .write = koneplus_sysfs_write_tcu + }, + { + .attr = { .name = "tcu_image", .mode = 0440 }, + .size = sizeof(struct koneplus_tcu_image), + .read = koneplus_sysfs_read_tcu_image + }, + { + .attr = { .name = "profile_settings", .mode = 0220 }, + .size = sizeof(struct koneplus_profile_settings), + .write = koneplus_sysfs_write_profile_settings + }, + { + .attr = { .name = "profile1_settings", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_settings), + .read = koneplus_sysfs_read_profilex_settings, + .private = &profile_numbers[0] + }, + { + .attr = { .name = "profile2_settings", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_settings), + .read = koneplus_sysfs_read_profilex_settings, + .private = &profile_numbers[1] + }, + { + .attr = { .name = "profile3_settings", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_settings), + .read = koneplus_sysfs_read_profilex_settings, + .private = &profile_numbers[2] + }, + { + .attr = { .name = "profile4_settings", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_settings), + .read = koneplus_sysfs_read_profilex_settings, + .private = &profile_numbers[3] + }, + { + .attr = { .name = "profile5_settings", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_settings), + .read = koneplus_sysfs_read_profilex_settings, + .private = &profile_numbers[4] + }, + { + .attr = { .name = "profile_buttons", .mode = 0220 }, + .size = sizeof(struct koneplus_profile_buttons), + .write = koneplus_sysfs_write_profile_buttons + }, + { + .attr = { .name = "profile1_buttons", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_buttons), + .read = koneplus_sysfs_read_profilex_buttons, + .private = &profile_numbers[0] + }, + { + .attr = { .name = "profile2_buttons", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_buttons), + .read = koneplus_sysfs_read_profilex_buttons, + .private = &profile_numbers[1] + }, + { + .attr = { .name = "profile3_buttons", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_buttons), + .read = koneplus_sysfs_read_profilex_buttons, + .private = &profile_numbers[2] + }, + { + .attr = { .name = "profile4_buttons", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_buttons), + .read = koneplus_sysfs_read_profilex_buttons, + .private = &profile_numbers[3] + }, + { + .attr = { .name = "profile5_buttons", .mode = 0440 }, + .size = sizeof(struct koneplus_profile_buttons), + .read = koneplus_sysfs_read_profilex_buttons, + .private = &profile_numbers[4] + }, + { + .attr = { .name = "macro", .mode = 0220 }, + .size = sizeof(struct koneplus_macro), + .write = koneplus_sysfs_write_macro + }, + __ATTR_NULL +}; + +static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev, + struct koneplus_device *koneplus) +{ + int retval, i; + static uint wait = 70; /* device will freeze with just 60 */ + + mutex_init(&koneplus->koneplus_lock); + + koneplus->startup_profile = koneplus_get_startup_profile(usb_dev); + + msleep(wait); + retval = koneplus_get_info(usb_dev, &koneplus->info); + if (retval) + return retval; + + for (i = 0; i < 5; ++i) { + msleep(wait); + retval = koneplus_get_profile_settings(usb_dev, + &koneplus->profile_settings[i], i); + if (retval) + return retval; + + msleep(wait); + retval = koneplus_get_profile_buttons(usb_dev, + &koneplus->profile_buttons[i], i); + if (retval) + return retval; + } + + koneplus_profile_activated(koneplus, koneplus->startup_profile); + + return 0; +} + +static int koneplus_init_specials(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct koneplus_device *koneplus; + int retval; + + if (intf->cur_altsetting->desc.bInterfaceProtocol + == USB_INTERFACE_PROTOCOL_MOUSE) { + + koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL); + if (!koneplus) { + dev_err(&hdev->dev, "can't alloc device descriptor\n"); + return -ENOMEM; + } + hid_set_drvdata(hdev, koneplus); + + retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus); + if (retval) { + dev_err(&hdev->dev, + "couldn't init struct koneplus_device\n"); + goto exit_free; + } + + retval = roccat_connect(koneplus_class, hdev); + if (retval < 0) { + dev_err(&hdev->dev, "couldn't init char dev\n"); + } else { + koneplus->chrdev_minor = retval; + koneplus->roccat_claimed = 1; + } + } else { + hid_set_drvdata(hdev, NULL); + } + + return 0; +exit_free: + kfree(koneplus); + return retval; +} + +static void koneplus_remove_specials(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct koneplus_device *koneplus; + + if (intf->cur_altsetting->desc.bInterfaceProtocol + == USB_INTERFACE_PROTOCOL_MOUSE) { + koneplus = hid_get_drvdata(hdev); + if (koneplus->roccat_claimed) + roccat_disconnect(koneplus->chrdev_minor); + kfree(koneplus); + } +} + +static int koneplus_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int retval; + + retval = hid_parse(hdev); + if (retval) { + dev_err(&hdev->dev, "parse failed\n"); + goto exit; + } + + retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (retval) { + dev_err(&hdev->dev, "hw start failed\n"); + goto exit; + } + + retval = koneplus_init_specials(hdev); + if (retval) { + dev_err(&hdev->dev, "couldn't install mouse\n"); + goto exit_stop; + } + + return 0; + +exit_stop: + hid_hw_stop(hdev); +exit: + return retval; +} + +static void koneplus_remove(struct hid_device *hdev) +{ + koneplus_remove_specials(hdev); + hid_hw_stop(hdev); +} + +static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus, + u8 const *data) +{ + struct koneplus_mouse_report_button const *button_report; + + switch (data[0]) { + case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON: + button_report = (struct koneplus_mouse_report_button const *)data; + switch (button_report->type) { + case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE: + koneplus_profile_activated(koneplus, button_report->data1 - 1); + break; + } + break; + } +} + +static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus, + u8 const *data) +{ + struct koneplus_roccat_report roccat_report; + struct koneplus_mouse_report_button const *button_report; + + if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON) + return; + + button_report = (struct koneplus_mouse_report_button const *)data; + + if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH || + button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) && + button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS) + return; + + roccat_report.type = button_report->type; + roccat_report.data1 = button_report->data1; + roccat_report.data2 = button_report->data2; + roccat_report.profile = koneplus->actual_profile + 1; + roccat_report_event(koneplus->chrdev_minor, + (uint8_t const *)&roccat_report, + sizeof(struct koneplus_roccat_report)); +} + +static int koneplus_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct koneplus_device *koneplus = hid_get_drvdata(hdev); + + if (intf->cur_altsetting->desc.bInterfaceProtocol + != USB_INTERFACE_PROTOCOL_MOUSE) + return 0; + + koneplus_keep_values_up_to_date(koneplus, data); + + if (koneplus->roccat_claimed) + koneplus_report_to_chrdev(koneplus, data); + + return 0; +} + +static const struct hid_device_id koneplus_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, + { } +}; + +MODULE_DEVICE_TABLE(hid, koneplus_devices); + +static struct hid_driver koneplus_driver = { + .name = "koneplus", + .id_table = koneplus_devices, + .probe = koneplus_probe, + .remove = koneplus_remove, + .raw_event = koneplus_raw_event +}; + +static int __init koneplus_init(void) +{ + int retval; + + /* class name has to be same as driver name */ + koneplus_class = class_create(THIS_MODULE, "koneplus"); + if (IS_ERR(koneplus_class)) + return PTR_ERR(koneplus_class); + koneplus_class->dev_attrs = koneplus_attributes; + koneplus_class->dev_bin_attrs = koneplus_bin_attributes; + + retval = hid_register_driver(&koneplus_driver); + if (retval) + class_destroy(koneplus_class); + return retval; +} + +static void __exit koneplus_exit(void) +{ + class_destroy(koneplus_class); + hid_unregister_driver(&koneplus_driver); +} + +module_init(koneplus_init); +module_exit(koneplus_exit); + +MODULE_AUTHOR("Stefan Achatz"); +MODULE_DESCRIPTION("USB Roccat Kone[+] driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h new file mode 100644 index 000000000000..905e33d45354 --- /dev/null +++ b/drivers/hid/hid-roccat-koneplus.h @@ -0,0 +1,232 @@ +#ifndef __HID_ROCCAT_KONEPLUS_H +#define __HID_ROCCAT_KONEPLUS_H + +/* + * Copyright (c) 2010 Stefan Achatz + */ + +/* + * 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. + */ + +#include + +/* + * Binary data structures used for hardware communication must have no padding. + */ +#pragma pack(push) +#pragma pack(1) + +/* + * case 1: writes request 80 and reads value 1 + * + */ +struct koneplus_control { + uint8_t command; /* KONEPLUS_COMMAND_CONTROL */ + /* + * value is profile number in range 0-4 for requesting settings and buttons + * 1 if status ok for requesting status + */ + uint8_t value; + uint8_t request; +}; + +enum koneplus_control_requests { + KONEPLUS_CONTROL_REQUEST_STATUS = 0x00, + KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80, + KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90, +}; + +enum koneplus_control_values { + KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0, + KONEPLUS_CONTROL_REQUEST_STATUS_OK = 1, + KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, +}; + +struct koneplus_startup_profile { + uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */ + uint8_t size; /* always 3 */ + uint8_t startup_profile; /* Range 0-4! */ +}; + +struct koneplus_profile_settings { + uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */ + uint8_t size; /* always 43 */ + uint8_t number; /* range 0-4 */ + uint8_t advanced_sensitivity; + uint8_t sensitivity_x; + uint8_t sensitivity_y; + uint8_t cpi_levels_enabled; + uint8_t cpi_levels_x[5]; + uint8_t cpi_startup_level; /* range 0-4 */ + uint8_t cpi_levels_y[5]; /* range 1-60 means 100-6000 cpi */ + uint8_t unknown1; + uint8_t polling_rate; + uint8_t lights_enabled; + uint8_t light_effect_mode; + uint8_t color_flow_effect; + uint8_t light_effect_type; + uint8_t light_effect_speed; + uint8_t lights[16]; + uint16_t checksum; +}; + +struct koneplus_profile_buttons { + uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */ + uint8_t size; /* always 77 */ + uint8_t number; /* range 0-4 */ + uint8_t data[72]; + uint16_t checksum; +}; + +struct koneplus_macro { + uint8_t command; /* KONEPLUS_COMMAND_MACRO */ + uint16_t size; /* always 0x822 little endian */ + uint8_t profile; /* range 0-4 */ + uint8_t button; /* range 0-23 */ + uint8_t data[2075]; + uint16_t checksum; +}; + +struct koneplus_info { + uint8_t command; /* KONEPLUS_COMMAND_INFO */ + uint8_t size; /* always 6 */ + uint8_t firmware_version; + uint8_t unknown[3]; +}; + +struct koneplus_e { + uint8_t command; /* KONEPLUS_COMMAND_E */ + uint8_t size; /* always 3 */ + uint8_t unknown; /* TODO 1; 0 before firmware update */ +}; + +struct koneplus_sensor { + uint8_t command; /* KONEPLUS_COMMAND_SENSOR */ + uint8_t size; /* always 6 */ + uint8_t data[4]; +}; + +struct koneplus_firmware_write { + uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */ + uint8_t unknown[1025]; +}; + +struct koneplus_firmware_write_control { + uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */ + /* + * value is 1 on success + * 3 means "not finished yet" + */ + uint8_t value; + uint8_t unknown; /* always 0x75 */ +}; + +struct koneplus_tcu { + uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */ + uint8_t data[2]; +}; + +struct koneplus_tcu_image { + uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */ + uint8_t data[1024]; + uint16_t checksum; +}; + +enum koneplus_commands { + KONEPLUS_COMMAND_CONTROL = 0x4, + KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5, + KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6, + KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, + KONEPLUS_COMMAND_MACRO = 0x8, + KONEPLUS_COMMAND_INFO = 0x9, + KONEPLUS_COMMAND_E = 0xe, + KONEPLUS_COMMAND_SENSOR = 0xf, + KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b, + KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c, +}; + +enum koneplus_usb_commands { + KONEPLUS_USB_COMMAND_CONTROL = 0x304, + KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305, + KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306, + KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307, + KONEPLUS_USB_COMMAND_MACRO = 0x308, + KONEPLUS_USB_COMMAND_INFO = 0x309, + KONEPLUS_USB_COMMAND_TCU = 0x30c, + KONEPLUS_USB_COMMAND_E = 0x30e, + KONEPLUS_USB_COMMAND_SENSOR = 0x30f, + KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b, + KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c, +}; + +enum koneplus_mouse_report_numbers { + KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1, + KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2, + KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3, +}; + +struct koneplus_mouse_report_button { + uint8_t report_number; /* always KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON */ + uint8_t zero1; + uint8_t type; + uint8_t data1; + uint8_t data2; + uint8_t zero2; + uint8_t unknown[2]; +}; + +enum koneplus_mouse_report_button_types { + /* data1 = new profile range 1-5 */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20, + + /* data1 = button number range 1-24; data2 = action */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60, + + /* data1 = button number range 1-24; data2 = action */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80, + + /* data1 = setting number range 1-5 */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0, + + /* data1 and data2 = range 0x1-0xb */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0, + + /* data1 = 22 = next track... + * data2 = action + */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0, +}; + +enum koneplus_mouse_report_button_action { + KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0, + KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1, +}; + +struct koneplus_roccat_report { + uint8_t type; + uint8_t data1; + uint8_t data2; + uint8_t profile; +}; + +#pragma pack(pop) + +struct koneplus_device { + int actual_profile; + + int roccat_claimed; + int chrdev_minor; + + struct mutex koneplus_lock; + + int startup_profile; + struct koneplus_info info; + struct koneplus_profile_settings profile_settings[5]; + struct koneplus_profile_buttons profile_buttons[5]; +}; + +#endif -- cgit v1.2.3 From 4d043101897768dfde30a6f2674fc7cec403d6b0 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 9 Dec 2010 14:29:34 +0100 Subject: HID: roccat: don't use #pragma pack Replace #pragma pack ocurences with __atribute__((__packed__)); Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.h | 22 +++++++--------------- drivers/hid/hid-roccat-koneplus.h | 36 ++++++++++++++---------------------- drivers/hid/hid-roccat-pyra.h | 26 +++++++++----------------- 3 files changed, 30 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 11203a75b0f9..64abb5b8a59a 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -14,17 +14,11 @@ #include -/* - * Binary data structures used for hardware communication must have no padding. - */ -#pragma pack(push) -#pragma pack(1) - struct kone_keystroke { uint8_t key; uint8_t action; uint16_t period; /* in milliseconds */ -}; +} __attribute__ ((__packed__)); enum kone_keystroke_buttons { kone_keystroke_button_1 = 0xf0, /* left mouse button */ @@ -47,7 +41,7 @@ struct kone_button_info { uint8_t macro_name[16]; /* can be max 15 chars long */ uint8_t count; struct kone_keystroke keystrokes[20]; -}; +} __attribute__ ((__packed__)); enum kone_button_info_types { /* valid button types until firmware 1.32 */ @@ -98,7 +92,7 @@ struct kone_light_info { uint8_t red; /* range 0x00-0xff */ uint8_t green; /* range 0x00-0xff */ uint8_t blue; /* range 0x00-0xff */ -}; +} __attribute__ ((__packed__)); struct kone_profile { uint16_t size; /* always 975 */ @@ -133,7 +127,7 @@ struct kone_profile { struct kone_button_info button_infos[8]; uint16_t checksum; /* \brief holds checksum of struct */ -}; +} __attribute__ ((__packed__)); enum kone_polling_rates { kone_polling_rate_125 = 1, @@ -150,7 +144,7 @@ struct kone_settings { uint8_t calibration_data[4]; uint8_t unknown3[2]; uint16_t checksum; -}; +} __attribute__ ((__packed__)); /* * 12 byte mouse event read by interrupt_read @@ -166,7 +160,7 @@ struct kone_mouse_event { uint8_t event; uint8_t value; /* press = 0, release = 1 */ uint8_t macro_key; /* 0 to 8 */ -}; +} __attribute__ ((__packed__)); enum kone_mouse_events { /* osd events are thought to be display on screen */ @@ -194,9 +188,7 @@ struct kone_roccat_report { uint8_t event; uint8_t value; /* holds dpi or profile value */ uint8_t key; /* macro key on overlong macro execution */ -}; - -#pragma pack(pop) +} __attribute__ ((__packed__)); struct kone_device { /* diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h index 905e33d45354..57a5c1ab7b05 100644 --- a/drivers/hid/hid-roccat-koneplus.h +++ b/drivers/hid/hid-roccat-koneplus.h @@ -14,12 +14,6 @@ #include -/* - * Binary data structures used for hardware communication must have no padding. - */ -#pragma pack(push) -#pragma pack(1) - /* * case 1: writes request 80 and reads value 1 * @@ -32,7 +26,7 @@ struct koneplus_control { */ uint8_t value; uint8_t request; -}; +} __attribute__ ((__packed__)); enum koneplus_control_requests { KONEPLUS_CONTROL_REQUEST_STATUS = 0x00, @@ -50,7 +44,7 @@ struct koneplus_startup_profile { uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */ uint8_t size; /* always 3 */ uint8_t startup_profile; /* Range 0-4! */ -}; +} __attribute__ ((__packed__)); struct koneplus_profile_settings { uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */ @@ -72,7 +66,7 @@ struct koneplus_profile_settings { uint8_t light_effect_speed; uint8_t lights[16]; uint16_t checksum; -}; +} __attribute__ ((__packed__)); struct koneplus_profile_buttons { uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */ @@ -80,7 +74,7 @@ struct koneplus_profile_buttons { uint8_t number; /* range 0-4 */ uint8_t data[72]; uint16_t checksum; -}; +} __attribute__ ((__packed__)); struct koneplus_macro { uint8_t command; /* KONEPLUS_COMMAND_MACRO */ @@ -89,31 +83,31 @@ struct koneplus_macro { uint8_t button; /* range 0-23 */ uint8_t data[2075]; uint16_t checksum; -}; +} __attribute__ ((__packed__)); struct koneplus_info { uint8_t command; /* KONEPLUS_COMMAND_INFO */ uint8_t size; /* always 6 */ uint8_t firmware_version; uint8_t unknown[3]; -}; +} __attribute__ ((__packed__)); struct koneplus_e { uint8_t command; /* KONEPLUS_COMMAND_E */ uint8_t size; /* always 3 */ uint8_t unknown; /* TODO 1; 0 before firmware update */ -}; +} __attribute__ ((__packed__)); struct koneplus_sensor { uint8_t command; /* KONEPLUS_COMMAND_SENSOR */ uint8_t size; /* always 6 */ uint8_t data[4]; -}; +} __attribute__ ((__packed__)); struct koneplus_firmware_write { uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */ uint8_t unknown[1025]; -}; +} __attribute__ ((__packed__)); struct koneplus_firmware_write_control { uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */ @@ -123,18 +117,18 @@ struct koneplus_firmware_write_control { */ uint8_t value; uint8_t unknown; /* always 0x75 */ -}; +} __attribute__ ((__packed__)); struct koneplus_tcu { uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */ uint8_t data[2]; -}; +} __attribute__ ((__packed__)); struct koneplus_tcu_image { uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */ uint8_t data[1024]; uint16_t checksum; -}; +} __attribute__ ((__packed__)); enum koneplus_commands { KONEPLUS_COMMAND_CONTROL = 0x4, @@ -177,7 +171,7 @@ struct koneplus_mouse_report_button { uint8_t data2; uint8_t zero2; uint8_t unknown[2]; -}; +} __attribute__ ((__packed__)); enum koneplus_mouse_report_button_types { /* data1 = new profile range 1-5 */ @@ -211,9 +205,7 @@ struct koneplus_roccat_report { uint8_t data1; uint8_t data2; uint8_t profile; -}; - -#pragma pack(pop) +} __attribute__ ((__packed__)); struct koneplus_device { int actual_profile; diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h index ac5996e8817c..14cbbe1621e0 100644 --- a/drivers/hid/hid-roccat-pyra.h +++ b/drivers/hid/hid-roccat-pyra.h @@ -14,17 +14,11 @@ #include -/* - * Binary data structures used for hardware communication must have no padding. - */ -#pragma pack(push) -#pragma pack(1) - struct pyra_b { uint8_t command; /* PYRA_COMMAND_B */ uint8_t size; /* always 3 */ uint8_t unknown; /* 1 */ -}; +} __attribute__ ((__packed__)); struct pyra_control { uint8_t command; /* PYRA_COMMAND_CONTROL */ @@ -34,7 +28,7 @@ struct pyra_control { */ uint8_t value; /* Range 0-4 */ uint8_t request; -}; +} __attribute__ ((__packed__)); enum pyra_control_requests { PYRA_CONTROL_REQUEST_STATUS = 0x00, @@ -46,7 +40,7 @@ struct pyra_settings { uint8_t command; /* PYRA_COMMAND_SETTINGS */ uint8_t size; /* always 3 */ uint8_t startup_profile; /* Range 0-4! */ -}; +} __attribute__ ((__packed__)); struct pyra_profile_settings { uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */ @@ -61,7 +55,7 @@ struct pyra_profile_settings { uint8_t light_effect; uint8_t handedness; uint16_t checksum; /* byte sum */ -}; +} __attribute__ ((__packed__)); struct pyra_profile_buttons { uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */ @@ -69,7 +63,7 @@ struct pyra_profile_buttons { uint8_t number; /* Range 0-4 */ uint8_t buttons[14]; uint16_t checksum; /* byte sum */ -}; +} __attribute__ ((__packed__)); struct pyra_info { uint8_t command; /* PYRA_COMMAND_INFO */ @@ -78,7 +72,7 @@ struct pyra_info { uint8_t unknown1; /* always 0 */ uint8_t unknown2; /* always 1 */ uint8_t unknown3; /* always 0 */ -}; +} __attribute__ ((__packed__)); enum pyra_commands { PYRA_COMMAND_CONTROL = 0x4, @@ -110,13 +104,13 @@ struct pyra_mouse_event_button { uint8_t type; uint8_t data1; uint8_t data2; -}; +} __attribute__ ((__packed__)); struct pyra_mouse_event_audio { uint8_t report_number; /* always 2 */ uint8_t type; uint8_t unused; /* always 0 */ -}; +} __attribute__ ((__packed__)); /* hid audio controls */ enum pyra_mouse_event_audio_types { @@ -170,9 +164,7 @@ struct pyra_roccat_report { uint8_t type; uint8_t value; uint8_t key; -}; - -#pragma pack(pop) +} __attribute__ ((__packed__)); struct pyra_device { int actual_profile; -- cgit v1.2.3 From 8e834c2e6d51e053c6bd23fec1d95529f618f760 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 25 Dec 2010 22:44:01 +0300 Subject: pata_hpt{37x|3x2n}: SATA mode filtering The Marvell bridge chips used on HighPoint SATA cards do not seem to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes; these cards are based on HPT372/372A/372N/374 chips (judging from the vendor drivers), so the Linux drivers need to have a mode_filter() method for these chips... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt37x.c | 54 ++++++++++++++++++++++++++++++++-------- drivers/ata/pata_hpt3x2n.c | 61 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 93 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 9ae4c0830577..9c62951c3e26 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -8,7 +8,7 @@ * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. + * Portions Copyright (C) 2005-2010 MontaVista Software, Inc. * * TODO * Look into engine reset on timeout errors. Should not be required. @@ -24,7 +24,7 @@ #include #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.15" +#define DRV_VERSION "0.6.16" struct hpt_clock { u8 xfer_speed; @@ -301,6 +301,22 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) return mask; } +/** + * hpt372_filter - mode selection filter + * @adev: ATA device + * @mask: mode mask + * + * The Marvell bridge chips used on the HighPoint SATA cards do not seem + * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... + */ +static unsigned long hpt372_filter(struct ata_device *adev, unsigned long mask) +{ + if (ata_id_is_sata(adev->id)) + mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA); + + return mask; +} + /** * hpt37x_cable_detect - Detect the cable type * @ap: ATA port to detect on @@ -586,11 +602,11 @@ static struct ata_port_operations hpt370a_port_ops = { }; /* - * Configuration for HPT372, HPT371, HPT302. Slightly different PIO - * and DMA mode setting functionality. + * Configuration for HPT371 and HPT302. Slightly different PIO and DMA + * mode setting functionality. */ -static struct ata_port_operations hpt372_port_ops = { +static struct ata_port_operations hpt302_port_ops = { .inherits = &ata_bmdma_port_ops, .bmdma_stop = hpt37x_bmdma_stop, @@ -602,7 +618,17 @@ static struct ata_port_operations hpt372_port_ops = { }; /* - * Configuration for HPT374. Mode setting works like 372 and friends + * Configuration for HPT372. Mode setting works like 371 and 302 + * but we have a mode filter. + */ + +static struct ata_port_operations hpt372_port_ops = { + .inherits = &hpt302_port_ops, + .mode_filter = hpt372_filter, +}; + +/* + * Configuration for HPT374. Mode setting and filtering works like 372 * but we have a different cable detection procedure for function 1. */ @@ -753,7 +779,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA5, .port_ops = &hpt370a_port_ops }; - /* HPT371, 372 and friends - UDMA133 */ + /* HPT372 - UDMA133 */ static const struct ata_port_info info_hpt372 = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, @@ -761,6 +787,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA6, .port_ops = &hpt372_port_ops }; + /* HPT371, 302 - UDMA133 */ + static const struct ata_port_info info_hpt302 = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + .port_ops = &hpt302_port_ops + }; /* HPT374 - UDMA100, function 1 uses different prereset method */ static const struct ata_port_info info_hpt374_fn0 = { .flags = ATA_FLAG_SLAVE_POSS, @@ -828,7 +862,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) } else { switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT372: - /* 372N if rev >= 2*/ + /* 372N if rev >= 2 */ if (rev >= 2) return -ENODEV; ppi[0] = &info_hpt372; @@ -838,14 +872,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* 302N if rev > 1 */ if (rev > 1) return -ENODEV; - ppi[0] = &info_hpt372; + ppi[0] = &info_hpt302; /* Check this */ chip_table = &hpt302; break; case PCI_DEVICE_ID_TTI_HPT371: if (rev > 1) return -ENODEV; - ppi[0] = &info_hpt372; + ppi[0] = &info_hpt302; chip_table = &hpt371; /* Single channel device, master is not present but the BIOS (or us for non x86) must mark it diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 32f3463216b8..97c6ded047b8 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -8,7 +8,7 @@ * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc - * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. + * Portions Copyright (C) 2005-2010 MontaVista Software, Inc. * * * TODO @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3.10" +#define DRV_VERSION "0.3.11" enum { HPT_PCI_FAST = (1 << 31), @@ -112,6 +112,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) return 0xffffffffU; /* silence compiler warning */ } +/** + * hpt372n_filter - mode selection filter + * @adev: ATA device + * @mask: mode mask + * + * The Marvell bridge chips used on the HighPoint SATA cards do not seem + * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... + */ +static unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask) +{ + if (ata_id_is_sata(adev->id)) + mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA); + + return mask; +} + /** * hpt3x2n_cable_detect - Detect the cable type * @ap: ATA port to detect on @@ -328,10 +344,10 @@ static struct scsi_host_template hpt3x2n_sht = { }; /* - * Configuration for HPT3x2n. + * Configuration for HPT302N/371N. */ -static struct ata_port_operations hpt3x2n_port_ops = { +static struct ata_port_operations hpt3xxn_port_ops = { .inherits = &ata_bmdma_port_ops, .bmdma_stop = hpt3x2n_bmdma_stop, @@ -345,6 +361,15 @@ static struct ata_port_operations hpt3x2n_port_ops = { .prereset = hpt3x2n_pre_reset, }; +/* + * Configuration for HPT372N. Same as 302N/371N but we have a mode filter. + */ + +static struct ata_port_operations hpt372n_port_ops = { + .inherits = &hpt3xxn_port_ops, + .mode_filter = &hpt372n_filter, +}; + /** * hpt3xn_calibrate_dpll - Calibrate the DPLL loop * @dev: PCI device @@ -437,15 +462,23 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - /* HPT372N and friends - UDMA133 */ - static const struct ata_port_info info = { + /* HPT372N - UDMA133 */ + static const struct ata_port_info info_hpt372n = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA6, - .port_ops = &hpt3x2n_port_ops + .port_ops = &hpt372n_port_ops }; - const struct ata_port_info *ppi[] = { &info, NULL }; + /* HPT302N and HPT371N - UDMA133 */ + static const struct ata_port_info info_hpt3xxn = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + .port_ops = &hpt3xxn_port_ops + }; + const struct ata_port_info *ppi[] = { &info_hpt3xxn, NULL }; u8 rev = dev->revision; u8 irqmask; unsigned int pci_mhz; @@ -461,24 +494,28 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT366: + /* 372N if rev >= 6 */ if (rev < 6) return -ENODEV; - break; + goto hpt372n; case PCI_DEVICE_ID_TTI_HPT371: + /* 371N if rev >= 2 */ if (rev < 2) return -ENODEV; - /* 371N if rev > 1 */ break; case PCI_DEVICE_ID_TTI_HPT372: - /* 372N if rev >= 2*/ + /* 372N if rev >= 2 */ if (rev < 2) return -ENODEV; - break; + goto hpt372n; case PCI_DEVICE_ID_TTI_HPT302: + /* 302N if rev >= 2 */ if (rev < 2) return -ENODEV; break; case PCI_DEVICE_ID_TTI_HPT372N: +hpt372n: + ppi[0] = &info_hpt372n; break; default: printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device); -- cgit v1.2.3 From 0ca646db68d1bd7184dfc41362d0dd9d56c0e57e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 28 Dec 2010 21:46:40 +0300 Subject: pata_hpt3x2n: clarify about HPT371N support Commit 28e21c8c0d44cd63bad4c62f94ef0c5a1cb8402c (pata_hpt3x2n: Add HPT371N support and other bits) forgot to update the driver's Kconfig entry, heading comment, and module description (that also wrongly claims support of HPT302) which may confuse users... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 4 ++-- drivers/ata/pata_hpt3x2n.c | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index e3e0e95c7aa5..e0c34d73770a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -408,11 +408,11 @@ config PATA_HPT37X If unsure, say N. config PATA_HPT3X2N - tristate "HPT 372N/302N PATA support" + tristate "HPT 371N/372N/302N PATA support" depends on PCI help This option enables support for the N variant HPT PATA - controllers via the new ATA layer + controllers via the new ATA layer. If unsure, say N. diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 97c6ded047b8..87b735a45935 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -1,5 +1,5 @@ /* - * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers. + * Libata driver for the HighPoint 371N, 372N, and 302N UDMA66 ATA controllers. * * This driver is heavily based upon: * @@ -456,8 +456,6 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) * HPT372N 9 (HPT372N) * UDMA133 * * (1) UDMA133 support depends on the bus clock - * - * To pin down HPT371N */ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) @@ -616,7 +614,7 @@ static void __exit hpt3x2n_exit(void) } MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x"); +MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3xxN"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, hpt3x2n); MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3 From dfc7e3e37d4a22ed5fd3f6e8c9842cb1246fee4f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 28 Dec 2010 22:54:54 +0300 Subject: pata_hpt3x2n: calculate average f_CNT Allow hpt3x2n_pci_clock() to calculate the average f_CNT register value iff HighPoint BIOS hasn't saved one, just like the 'pata_hpt37x' driver (reading the full 16-bit register, unlike what that driver does), so that this driver would work correctly on e.g. non-x86 machine with 66 MHz PCI. I'm not sure why Alan has only done this in one driver and not the other... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt3x2n.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 87b735a45935..809a4b4e88ab 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3.11" +#define DRV_VERSION "0.3.12" enum { HPT_PCI_FAST = (1 << 31), @@ -413,8 +413,19 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev) fcnt = inl(iobase + 0x90); /* Not PCI readable for some chips */ if ((fcnt >> 12) != 0xABCDE) { - printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n"); - return 33; /* Not BIOS set */ + int i; + u16 sr; + u32 total = 0; + + printk(KERN_WARNING "pata_hpt3x2n: BIOS clock data not set.\n"); + + /* This is the process the HPT371 BIOS is reported to use */ + for (i = 0; i < 128; i++) { + pci_read_config_word(pdev, 0x78, &sr); + total += sr & 0x1FF; + udelay(15); + } + fcnt = total / 128; } fcnt &= 0x1FF; -- cgit v1.2.3 From 28cd4b6b4850d7588f1033c3808314b6bc2150d5 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 28 Dec 2010 23:06:38 +0300 Subject: pata_hpt366: coding style cleanup Fix 2 errors and 11 warnings given by checkpatch.pl: - *switch* and *case* not on the same indentation level; - no space between *switch* and open parenthesis; - drive blacklist arrays not being *const*; - spaces before tabs; - lines over 80 characters. In addition to these changes, also add new line after variable definition in hpt36x_init_chipset()... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt366.c | 51 +++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 7688868557b9..d7e57db36bc8 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.6.8" +#define DRV_VERSION "0.6.9" struct hpt_clock { u8 xfer_mode; @@ -110,18 +110,23 @@ static const struct hpt_clock hpt366_25[] = { { 0, 0x01208585 } }; -static const char *bad_ata33[] = { - "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", - "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", - "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", +static const char * const bad_ata33[] = { + "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", + "Maxtor 90845U3", "Maxtor 90650U2", + "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", + "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", + "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", + "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", "Maxtor 90510D4", "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", - "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", - "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", + "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", + "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", + "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", + "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", NULL }; -static const char *bad_ata66_4[] = { +static const char * const bad_ata66_4[] = { "IBM-DTLA-307075", "IBM-DTLA-307060", "IBM-DTLA-307045", @@ -140,12 +145,13 @@ static const char *bad_ata66_4[] = { NULL }; -static const char *bad_ata66_3[] = { +static const char * const bad_ata66_3[] = { "WDC AC310200R", NULL }; -static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) +static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, + const char * const list[]) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; int i = 0; @@ -288,6 +294,7 @@ static struct ata_port_operations hpt366_port_ops = { static void hpt36x_init_chipset(struct pci_dev *dev) { u8 drive_fast; + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); @@ -349,16 +356,16 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* PCI clocking determines the ATA timing values to use */ /* info_hpt366 is safe against re-entry so we can scribble on it */ - switch((reg1 & 0x700) >> 8) { - case 9: - hpriv = &hpt366_40; - break; - case 5: - hpriv = &hpt366_25; - break; - default: - hpriv = &hpt366_33; - break; + switch ((reg1 & 0x700) >> 8) { + case 9: + hpriv = &hpt366_40; + break; + case 5: + hpriv = &hpt366_25; + break; + default: + hpriv = &hpt366_33; + break; } /* Now kick off ATA set up */ return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0); @@ -385,9 +392,9 @@ static const struct pci_device_id hpt36x[] = { }; static struct pci_driver hpt36x_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt36x, - .probe = hpt36x_init_one, + .probe = hpt36x_init_one, .remove = ata_pci_remove_one, #ifdef CONFIG_PM .suspend = ata_pci_device_suspend, -- cgit v1.2.3 From 49bfbd38bfc997e9081beabd758b2bd655d26a9c Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 28 Dec 2010 23:09:27 +0300 Subject: pata_hpt37x: coding style cleanup Fix 12 errors and 15 warnings given by checkpatch.pl: - *switch* and *case* not on the same indentation level; - no space between *for*/*switch*/*while* and open parenthesis; - space between an unary operator and its operand; - drive blacklist arrays not being *const*; - spaces before tabs; - lines over 80 characters. In addition to these changes, also do the following: - add new line after variable definitions; - fix the style of some multi-line comments. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt37x.c | 182 +++++++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 9c62951c3e26..9e2c98449055 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -24,7 +24,7 @@ #include #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.16" +#define DRV_VERSION "0.6.17" struct hpt_clock { u8 xfer_speed; @@ -210,7 +210,7 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed) { struct hpt_clock *clocks = ap->host->private_data; - while(clocks->xfer_speed) { + while (clocks->xfer_speed) { if (clocks->xfer_speed == speed) return clocks->timing; clocks++; @@ -219,7 +219,8 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed) return 0xffffffffU; /* silence compiler warning */ } -static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) +static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, + const char * const list[]) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; int i = 0; @@ -237,18 +238,23 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons return 0; } -static const char *bad_ata33[] = { - "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", - "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", - "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", +static const char * const bad_ata33[] = { + "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", + "Maxtor 90845U3", "Maxtor 90650U2", + "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", + "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", + "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", + "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", "Maxtor 90510D4", "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", - "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", - "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", + "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", + "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", + "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", + "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", NULL }; -static const char *bad_ata100_5[] = { +static const char * const bad_ata100_5[] = { "IBM-DTLA-307075", "IBM-DTLA-307060", "IBM-DTLA-307045", @@ -389,6 +395,7 @@ static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline) { 0x50, 1, 0x04, 0x04 }, { 0x54, 1, 0x04, 0x04 } }; + if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) return -ENOENT; @@ -673,12 +680,12 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev) u32 reg5c; int tries; - for(tries = 0; tries < 0x5000; tries++) { + for (tries = 0; tries < 0x5000; tries++) { udelay(50); pci_read_config_byte(dev, 0x5b, ®5b); if (reg5b & 0x80) { /* See if it stays set */ - for(tries = 0; tries < 0x1000; tries ++) { + for (tries = 0; tries < 0x1000; tries++) { pci_read_config_byte(dev, 0x5b, ®5b); /* Failed ? */ if ((reg5b & 0x80) == 0) @@ -686,7 +693,7 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev) } /* Turn off tuning, we have the DPLL set */ pci_read_config_dword(dev, 0x5c, ®5c); - pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100); + pci_write_config_dword(dev, 0x5c, reg5c & ~0x100); return 1; } } @@ -698,6 +705,7 @@ static u32 hpt374_read_freq(struct pci_dev *pdev) { u32 freq; unsigned long io_base = pci_resource_start(pdev, 4); + if (PCI_FUNC(pdev->devfn) & 1) { struct pci_dev *pdev_0; @@ -839,64 +847,68 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (rev == 6) return -ENODEV; - switch(rev) { - case 3: - ppi[0] = &info_hpt370; - chip_table = &hpt370; - prefer_dpll = 0; - break; - case 4: - ppi[0] = &info_hpt370a; - chip_table = &hpt370a; - prefer_dpll = 0; - break; - case 5: - ppi[0] = &info_hpt372; - chip_table = &hpt372; - break; - default: - printk(KERN_ERR "pata_hpt37x: Unknown HPT366 " - "subtype, please report (%d).\n", rev); - return -ENODEV; + switch (rev) { + case 3: + ppi[0] = &info_hpt370; + chip_table = &hpt370; + prefer_dpll = 0; + break; + case 4: + ppi[0] = &info_hpt370a; + chip_table = &hpt370a; + prefer_dpll = 0; + break; + case 5: + ppi[0] = &info_hpt372; + chip_table = &hpt372; + break; + default: + printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype, " + "please report (%d).\n", rev); + return -ENODEV; } } else { - switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT372: - /* 372N if rev >= 2 */ - if (rev >= 2) - return -ENODEV; - ppi[0] = &info_hpt372; - chip_table = &hpt372a; - break; - case PCI_DEVICE_ID_TTI_HPT302: - /* 302N if rev > 1 */ - if (rev > 1) - return -ENODEV; - ppi[0] = &info_hpt302; - /* Check this */ - chip_table = &hpt302; - break; - case PCI_DEVICE_ID_TTI_HPT371: - if (rev > 1) - return -ENODEV; - ppi[0] = &info_hpt302; - chip_table = &hpt371; - /* Single channel device, master is not present - but the BIOS (or us for non x86) must mark it - absent */ - pci_read_config_byte(dev, 0x50, &mcr1); - mcr1 &= ~0x04; - pci_write_config_byte(dev, 0x50, mcr1); - break; - case PCI_DEVICE_ID_TTI_HPT374: - chip_table = &hpt374; - if (!(PCI_FUNC(dev->devfn) & 1)) - *ppi = &info_hpt374_fn0; - else - *ppi = &info_hpt374_fn1; - break; - default: - printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device); + switch (dev->device) { + case PCI_DEVICE_ID_TTI_HPT372: + /* 372N if rev >= 2 */ + if (rev >= 2) + return -ENODEV; + ppi[0] = &info_hpt372; + chip_table = &hpt372a; + break; + case PCI_DEVICE_ID_TTI_HPT302: + /* 302N if rev > 1 */ + if (rev > 1) + return -ENODEV; + ppi[0] = &info_hpt302; + /* Check this */ + chip_table = &hpt302; + break; + case PCI_DEVICE_ID_TTI_HPT371: + if (rev > 1) + return -ENODEV; + ppi[0] = &info_hpt302; + chip_table = &hpt371; + /* + * Single channel device, master is not present + * but the BIOS (or us for non x86) must mark it + * absent + */ + pci_read_config_byte(dev, 0x50, &mcr1); + mcr1 &= ~0x04; + pci_write_config_byte(dev, 0x50, mcr1); + break; + case PCI_DEVICE_ID_TTI_HPT374: + chip_table = &hpt374; + if (!(PCI_FUNC(dev->devfn) & 1)) + *ppi = &info_hpt374_fn0; + else + *ppi = &info_hpt374_fn1; + break; + default: + printk(KERN_ERR + "pata_hpt37x: PCI table is bogus, please report (%d).\n", + dev->device); return -ENODEV; } } @@ -927,9 +939,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (chip_table == &hpt372a) outb(0x0e, iobase + 0x9c); - /* Some devices do not let this value be accessed via PCI space - according to the old driver. In addition we must use the value - from FN 0 on the HPT374 */ + /* + * Some devices do not let this value be accessed via PCI space + * according to the old driver. In addition we must use the value + * from FN 0 on the HPT374. + */ if (chip_table == &hpt374) { freq = hpt374_read_freq(dev); @@ -943,10 +957,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) u8 sr; u32 total = 0; - printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n"); + printk(KERN_WARNING + "pata_hpt37x: BIOS has not set timing clocks.\n"); /* This is the process the HPT371 BIOS is reported to use */ - for(i = 0; i < 128; i++) { + for (i = 0; i < 128; i++) { pci_read_config_byte(dev, 0x78, &sr); total += sr & 0x1FF; udelay(15); @@ -981,17 +996,22 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* Select the DPLL clock. */ pci_write_config_byte(dev, 0x5b, 0x21); - pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100); + pci_write_config_dword(dev, 0x5C, + (f_high << 16) | f_low | 0x100); - for(adjust = 0; adjust < 8; adjust++) { + for (adjust = 0; adjust < 8; adjust++) { if (hpt37x_calibrate_dpll(dev)) break; - /* See if it'll settle at a fractionally different clock */ + /* + * See if it'll settle at a fractionally + * different clock + */ if (adjust & 1) f_low -= adjust >> 1; else f_high += adjust >> 1; - pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100); + pci_write_config_dword(dev, 0x5C, + (f_high << 16) | f_low | 0x100); } if (adjust == 8) { printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n"); @@ -1010,7 +1030,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) * Perform a final fixup. Note that we will have used the * DPLL on the HPT372 which means we don't have to worry * about lack of UDMA133 support on lower clocks - */ + */ if (clock_slot < 2 && ppi[0] == &info_hpt370) ppi[0] = &info_hpt370_33; @@ -1035,9 +1055,9 @@ static const struct pci_device_id hpt37x[] = { }; static struct pci_driver hpt37x_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt37x, - .probe = hpt37x_init_one, + .probe = hpt37x_init_one, .remove = ata_pci_remove_one }; -- cgit v1.2.3 From b197f13b53681c606e59d7d9a8a1d2d54fd363fe Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 28 Dec 2010 23:11:36 +0300 Subject: pata_hpt3x2n: coding style cleanup Fix 8 errors and 3 warnings given by checkpatch.pl: - *switch* and *case* not on the same indentation level; - no space between *for*/*switch*/*while* and open parenthesis; - space between an unary operator and its operand; - spaces before tabs; - lines over 80 characters. In addition to these changes, also do the following: - add new line after variable definitions; - fix the style of some multi-line comments. Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt3x2n.c | 86 +++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 809a4b4e88ab..d2239bbdb798 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -25,7 +25,7 @@ #include #define DRV_NAME "pata_hpt3x2n" -#define DRV_VERSION "0.3.12" +#define DRV_VERSION "0.3.13" enum { HPT_PCI_FAST = (1 << 31), @@ -103,7 +103,7 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) { struct hpt_clock *clocks = hpt3x2n_clocks; - while(clocks->xfer_speed) { + while (clocks->xfer_speed) { if (clocks->xfer_speed == speed) return clocks->timing; clocks++; @@ -169,6 +169,7 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); + /* Reset the state machine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); @@ -384,12 +385,12 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev) u32 reg5c; int tries; - for(tries = 0; tries < 0x5000; tries++) { + for (tries = 0; tries < 0x5000; tries++) { udelay(50); pci_read_config_byte(dev, 0x5b, ®5b); if (reg5b & 0x80) { /* See if it stays set */ - for(tries = 0; tries < 0x1000; tries ++) { + for (tries = 0; tries < 0x1000; tries++) { pci_read_config_byte(dev, 0x5b, ®5b); /* Failed ? */ if ((reg5b & 0x80) == 0) @@ -397,7 +398,7 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev) } /* Turn off tuning, we have the DPLL set */ pci_read_config_dword(dev, 0x5c, ®5c); - pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100); + pci_write_config_dword(dev, 0x5c, reg5c & ~0x100); return 1; } } @@ -501,34 +502,36 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (rc) return rc; - switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT366: - /* 372N if rev >= 6 */ - if (rev < 6) - return -ENODEV; - goto hpt372n; - case PCI_DEVICE_ID_TTI_HPT371: - /* 371N if rev >= 2 */ - if (rev < 2) - return -ENODEV; - break; - case PCI_DEVICE_ID_TTI_HPT372: - /* 372N if rev >= 2 */ - if (rev < 2) - return -ENODEV; - goto hpt372n; - case PCI_DEVICE_ID_TTI_HPT302: - /* 302N if rev >= 2 */ - if (rev < 2) - return -ENODEV; - break; - case PCI_DEVICE_ID_TTI_HPT372N: -hpt372n: - ppi[0] = &info_hpt372n; - break; - default: - printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device); + switch (dev->device) { + case PCI_DEVICE_ID_TTI_HPT366: + /* 372N if rev >= 6 */ + if (rev < 6) + return -ENODEV; + goto hpt372n; + case PCI_DEVICE_ID_TTI_HPT371: + /* 371N if rev >= 2 */ + if (rev < 2) + return -ENODEV; + break; + case PCI_DEVICE_ID_TTI_HPT372: + /* 372N if rev >= 2 */ + if (rev < 2) + return -ENODEV; + goto hpt372n; + case PCI_DEVICE_ID_TTI_HPT302: + /* 302N if rev >= 2 */ + if (rev < 2) return -ENODEV; + break; + case PCI_DEVICE_ID_TTI_HPT372N: +hpt372n: + ppi[0] = &info_hpt372n; + break; + default: + printk(KERN_ERR + "pata_hpt3x2n: PCI table is bogus please report (%d).\n", + dev->device); + return -ENODEV; } /* Ok so this is a chip we support */ @@ -555,8 +558,10 @@ hpt372n: pci_write_config_byte(dev, 0x50, mcr1); } - /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or - 50 for UDMA100. Right now we always use 66 */ + /* + * Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or + * 50 for UDMA100. Right now we always use 66 + */ pci_mhz = hpt3x2n_pci_clock(dev); @@ -568,7 +573,7 @@ hpt372n: pci_write_config_byte(dev, 0x5B, 0x21); /* Unlike the 37x we don't try jiggling the frequency */ - for(adjust = 0; adjust < 8; adjust++) { + for (adjust = 0; adjust < 8; adjust++) { if (hpt3xn_calibrate_dpll(dev)) break; pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low); @@ -580,8 +585,11 @@ hpt372n: printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n", pci_mhz); - /* Set our private data up. We only need a few flags so we use - it directly */ + + /* + * Set our private data up. We only need a few flags + * so we use it directly. + */ if (pci_mhz > 60) hpriv = (void *)(PCI66 | USE_DPLL); @@ -608,9 +616,9 @@ static const struct pci_device_id hpt3x2n[] = { }; static struct pci_driver hpt3x2n_pci_driver = { - .name = DRV_NAME, + .name = DRV_NAME, .id_table = hpt3x2n, - .probe = hpt3x2n_init_one, + .probe = hpt3x2n_init_one, .remove = ata_pci_remove_one }; -- cgit v1.2.3 From fc2698d5ec7e96ba2c94a942329cfa4c5d6085f7 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 5 Jan 2011 21:59:49 +0300 Subject: pata_hpt37x: actually limit HPT370 to UltraDMA/66 The driver clearly tries to limit HPT370[A] to UltraDMA/66 if the PCI clock is less than 50 MHz but due to cut&paste type mistake this code has no effect... Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/ata/pata_hpt37x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 9e2c98449055..efdd18bc8663 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -24,7 +24,7 @@ #include #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.6.17" +#define DRV_VERSION "0.6.18" struct hpt_clock { u8 xfer_speed; @@ -771,20 +771,20 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) .udma_mask = ATA_UDMA5, .port_ops = &hpt370a_port_ops }; - /* HPT370 - UDMA100 */ + /* HPT370 - UDMA66 */ static const struct ata_port_info info_hpt370_33 = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, + .udma_mask = ATA_UDMA4, .port_ops = &hpt370_port_ops }; - /* HPT370A - UDMA100 */ + /* HPT370A - UDMA66 */ static const struct ata_port_info info_hpt370a_33 = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, + .udma_mask = ATA_UDMA4, .port_ops = &hpt370a_port_ops }; /* HPT372 - UDMA133 */ -- cgit v1.2.3 From 2ad2c320a107aceeba984f97ab2a60064101f5d5 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Fri, 7 Jan 2011 21:32:02 -0500 Subject: pata_platform: Remove CONFIG_HAVE_PATA_PLATFORM's dependencies. CONFIG_HAVE_PATA_PLATFORM, by virtue of where its defined, has a dependency on CONFG_ATA and CONFIG_ATA_SFF. This causes Kconfig warnings when it is selected by various architectures, such as warning: (ARCH_VEXPRESS && || ARCH_RPC && || MACH_VPAC270 && ARCH_PXA || MACH_REALVIEW_PB11MP && ARCH_REALVIEW || MACH_REALVIEW_PBA8 && ARCH_REALVIEW || MACH_REALVIEW_PBX && ARCH_REALVIEW || MACH_BAST_IDE && ARCH_S3C2410 || MACH_ANUBIS && ARCH_S3C2410) selects HAVE_PATA_PLATFORM which has unmet direct dependencies (ATA && ATA_SFF) Since this option is only used to control visibility of the CONFIG_PATA_PLATFORM option and isn't itself visible in the menu, it is straightforward to simply remove these dependencies rather than adjust all the architectures. Signed-off-by: Nick Bowler Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index e0c34d73770a..c6b298d4c136 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -2,6 +2,14 @@ # SATA/PATA driver configuration # +config HAVE_PATA_PLATFORM + bool + help + This is an internal configuration node for any machine that + uses pata-platform driver to enable the relevant driver in the + configuration structure without having to submit endless patches + to update the PATA_PLATFORM entry. + menuconfig ATA tristate "Serial ATA and Parallel ATA drivers" depends on HAS_IOMEM @@ -773,14 +781,6 @@ config PATA_PCMCIA If unsure, say N. -config HAVE_PATA_PLATFORM - bool - help - This is an internal configuration node for any machine that - uses pata-platform driver to enable the relevant driver in the - configuration structure without having to submit endless patches - to update the PATA_PLATFORM entry. - config PATA_PLATFORM tristate "Generic platform device PATA support" depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM -- cgit v1.2.3 From f8313ef1f448006207f12c107123522c8bc00f15 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Sat, 8 Jan 2011 01:37:26 -0800 Subject: Input: i8042 - introduce 'notimeout' blacklist for Dell Vostro V13 i8042 controller present in Dell Vostro V13 errorneously signals spurious timeouts. Introduce i8042.notimeout parameter for ignoring i8042-signalled timeouts and apply this quirk automatically for Dell Vostro V13, based on DMI match. In addition to that, this machine also needs to be added to nomux blacklist. Signed-off-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- Documentation/kernel-parameters.txt | 1 + drivers/input/serio/i8042-x86ia64io.h | 21 +++++++++++++++++++++ drivers/input/serio/i8042.c | 6 +++++- 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ed45e9802aa8..185b6bf0fb85 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -884,6 +884,7 @@ and is between 256 and 4096 characters. It is defined in the file controller i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX controllers + i8042.notimeout [HW] Ignore timeout condition signalled by conroller i8042.reset [HW] Reset the controller during init and cleanup i8042.unlock [HW] Unlock (ignore) the keylock diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5ae0fc4578fe..bb9f5d31f0d0 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -424,6 +424,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), }, }, + { + /* Dell Vostro V13 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), + }, + }, { } }; @@ -545,6 +552,17 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { }; #endif +static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { + { + /* Dell Vostro V13 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), + }, + }, + { } +}; + /* * Some Wistron based laptops need us to explicitly enable the 'Dritek * keyboard extension' to make their extra keys start generating scancodes. @@ -896,6 +914,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = true; + if (dmi_check_system(i8042_dmi_notimeout_table)) + i8042_notimeout = true; + if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = true; #endif /* CONFIG_X86 */ diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c04ff00a3663..ac4c93689ab9 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -63,6 +63,10 @@ static bool i8042_noloop; module_param_named(noloop, i8042_noloop, bool, 0); MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); +static bool i8042_notimeout; +module_param_named(notimeout, i8042_notimeout, bool, 0); +MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042"); + #ifdef CONFIG_X86 static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); @@ -504,7 +508,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) } else { dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); + ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0); port_no = (str & I8042_STR_AUXDATA) ? I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; -- cgit v1.2.3 From 048fc018c81d2acd86db2c3d1e226ea28f646729 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Sat, 8 Jan 2011 01:37:42 -0800 Subject: Input: remove aaed2000 keyboard driver The only platform using this driver (mach-aaec2000) is no longer in the kernel so remove the driver. Signed-off-by: Jamie Iles Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 12 --- drivers/input/keyboard/Makefile | 1 - drivers/input/keyboard/aaed2000_kbd.c | 186 ---------------------------------- 3 files changed, 199 deletions(-) delete mode 100644 drivers/input/keyboard/aaed2000_kbd.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a378e959368e..05ab6f41ee1e 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -12,18 +12,6 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD -config KEYBOARD_AAED2000 - tristate "AAED-2000 keyboard" - depends on MACH_AAED2000 - select INPUT_POLLDEV - default y - help - Say Y here to enable the keyboard on the Agilent AAED-2000 - development board. - - To compile this driver as a module, choose M here: the - module will be called aaed2000_kbd. - config KEYBOARD_ADP5520 tristate "Keypad Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 8449c730892c..ee14f85a716f 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -4,7 +4,6 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c deleted file mode 100644 index 18222a689a03..000000000000 --- a/drivers/input/keyboard/aaed2000_kbd.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Keyboard driver for the AAED-2000 dev board - * - * Copyright (c) 2006 Nicolas Bellido Y Ortega - * - * Based on corgikbd.c - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define KB_ROWS 12 -#define KB_COLS 8 -#define KB_ROWMASK(r) (1 << (r)) -#define SCANCODE(r,c) (((c) * KB_ROWS) + (r)) -#define NR_SCANCODES (KB_COLS * KB_ROWS) - -#define SCAN_INTERVAL (50) /* ms */ -#define KB_ACTIVATE_DELAY (20) /* us */ - -static unsigned char aaedkbd_keycode[NR_SCANCODES] = { - KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, 0, KEY_SPACE, KEY_KP6, 0, KEY_KPDOT, 0, 0, - KEY_K, KEY_M, KEY_O, KEY_DOT, KEY_SLASH, 0, KEY_F, 0, 0, 0, KEY_LEFTSHIFT, 0, - KEY_I, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 0, 0, 0, 0, KEY_RIGHTSHIFT, 0, - KEY_8, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0, - KEY_J, KEY_H, KEY_B, KEY_KP8, KEY_KP4, 0, KEY_C, KEY_D, KEY_S, KEY_A, 0, KEY_CAPSLOCK, - KEY_Y, KEY_U, KEY_N, KEY_T, 0, 0, KEY_R, KEY_E, KEY_W, KEY_Q, 0, KEY_TAB, - KEY_7, KEY_6, KEY_G, 0, KEY_5, 0, KEY_4, KEY_3, KEY_2, KEY_1, 0, KEY_GRAVE, - 0, 0, KEY_COMMA, 0, KEY_KP2, 0, KEY_V, KEY_LEFTALT, KEY_X, KEY_Z, 0, KEY_LEFTCTRL -}; - -struct aaedkbd { - unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)]; - struct input_polled_dev *poll_dev; - int kbdscan_state[KB_COLS]; - int kbdscan_count[KB_COLS]; -}; - -#define KBDSCAN_STABLE_COUNT 2 - -static void aaedkbd_report_col(struct aaedkbd *aaedkbd, - unsigned int col, unsigned int rowd) -{ - unsigned int scancode, pressed; - unsigned int row; - - for (row = 0; row < KB_ROWS; row++) { - scancode = SCANCODE(row, col); - pressed = rowd & KB_ROWMASK(row); - - input_report_key(aaedkbd->poll_dev->input, - aaedkbd->keycode[scancode], pressed); - } -} - -/* Scan the hardware keyboard and push any changes up through the input layer */ -static void aaedkbd_poll(struct input_polled_dev *dev) -{ - struct aaedkbd *aaedkbd = dev->private; - unsigned int col, rowd; - - col = 0; - do { - AAEC_GPIO_KSCAN = col + 8; - udelay(KB_ACTIVATE_DELAY); - rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN; - - if (rowd != aaedkbd->kbdscan_state[col]) { - aaedkbd->kbdscan_count[col] = 0; - aaedkbd->kbdscan_state[col] = rowd; - } else if (++aaedkbd->kbdscan_count[col] >= KBDSCAN_STABLE_COUNT) { - aaedkbd_report_col(aaedkbd, col, rowd); - col++; - } - } while (col < KB_COLS); - - AAEC_GPIO_KSCAN = 0x07; - input_sync(dev->input); -} - -static int __devinit aaedkbd_probe(struct platform_device *pdev) -{ - struct aaedkbd *aaedkbd; - struct input_polled_dev *poll_dev; - struct input_dev *input_dev; - int i; - int error; - - aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL); - poll_dev = input_allocate_polled_device(); - if (!aaedkbd || !poll_dev) { - error = -ENOMEM; - goto fail; - } - - platform_set_drvdata(pdev, aaedkbd); - - aaedkbd->poll_dev = poll_dev; - memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode)); - - poll_dev->private = aaedkbd; - poll_dev->poll = aaedkbd_poll; - poll_dev->poll_interval = SCAN_INTERVAL; - - input_dev = poll_dev->input; - input_dev->name = "AAED-2000 Keyboard"; - input_dev->phys = "aaedkbd/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x0001; - input_dev->id.product = 0x0001; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - input_dev->keycode = aaedkbd->keycode; - input_dev->keycodesize = sizeof(unsigned char); - input_dev->keycodemax = ARRAY_SIZE(aaedkbd_keycode); - - for (i = 0; i < ARRAY_SIZE(aaedkbd_keycode); i++) - set_bit(aaedkbd->keycode[i], input_dev->keybit); - clear_bit(0, input_dev->keybit); - - error = input_register_polled_device(aaedkbd->poll_dev); - if (error) - goto fail; - - return 0; - - fail: kfree(aaedkbd); - input_free_polled_device(poll_dev); - return error; -} - -static int __devexit aaedkbd_remove(struct platform_device *pdev) -{ - struct aaedkbd *aaedkbd = platform_get_drvdata(pdev); - - input_unregister_polled_device(aaedkbd->poll_dev); - input_free_polled_device(aaedkbd->poll_dev); - kfree(aaedkbd); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:aaed2000-keyboard"); - -static struct platform_driver aaedkbd_driver = { - .probe = aaedkbd_probe, - .remove = __devexit_p(aaedkbd_remove), - .driver = { - .name = "aaed2000-keyboard", - .owner = THIS_MODULE, - }, -}; - -static int __init aaedkbd_init(void) -{ - return platform_driver_register(&aaedkbd_driver); -} - -static void __exit aaedkbd_exit(void) -{ - platform_driver_unregister(&aaedkbd_driver); -} - -module_init(aaedkbd_init); -module_exit(aaedkbd_exit); - -MODULE_AUTHOR("Nicolas Bellido Y Ortega"); -MODULE_DESCRIPTION("AAED-2000 Keyboard Driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 28ebfa13f97265e415fbe19795500a6d922a6c86 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:25 +0000 Subject: hwmon: (abituguru) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Added a few static strings to standardize logging messages. Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/abituguru.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 03694cc17a32..8f07a9dda152 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -20,6 +20,9 @@ the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because of lack of specs the CPU/RAM voltage & frequency control is not supported! */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -220,6 +223,10 @@ struct abituguru_data { u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5]; }; +static const char *never_happen = "This should never happen."; +static const char *report_this = + "Please report this to the abituguru maintainer (see MAINTAINERS)"; + /* wait till the uguru is in the specified state */ static int abituguru_wait(struct abituguru_data *data, u8 state) { @@ -438,8 +445,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, /* Test val is sane / usable for sensor type detection. */ if ((val < 10u) || (val > 250u)) { - printk(KERN_WARNING ABIT_UGURU_NAME - ": bank1-sensor: %d reading (%d) too close to limits, " + pr_warn("bank1-sensor: %d reading (%d) too close to limits, " "unable to determine sensor type, skipping sensor\n", (int)sensor_addr, (int)val); /* assume no sensor is there for sensors for which we can't @@ -535,10 +541,8 @@ abituguru_detect_bank1_sensor_type_exit: 3) == 3) break; if (i == 3) { - printk(KERN_ERR ABIT_UGURU_NAME - ": Fatal error could not restore original settings. " - "This should never happen please report this to the " - "abituguru maintainer (see MAINTAINERS)\n"); + pr_err("Fatal error could not restore original settings. %s %s\n", + never_happen, report_this); return -ENODEV; } return ret; @@ -1268,14 +1272,12 @@ static int __devinit abituguru_probe(struct platform_device *pdev) } /* Fail safe check, this should never happen! */ if (sysfs_names_free < 0) { - printk(KERN_ERR ABIT_UGURU_NAME ": Fatal error ran out of " - "space for sysfs attr names. This should never " - "happen please report to the abituguru maintainer " - "(see MAINTAINERS)\n"); + pr_err("Fatal error ran out of space for sysfs attr names. %s %s", + never_happen, report_this); res = -ENAMETOOLONG; goto abituguru_probe_error; } - printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n"); + pr_info("found Abit uGuru\n"); /* Register sysfs hooks */ for (i = 0; i < sysfs_attr_i; i++) @@ -1432,8 +1434,7 @@ static int __init abituguru_detect(void) "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val); if (force) { - printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is " - "present because of \"force\" parameter\n"); + pr_info("Assuming Abit uGuru is present because of \"force\" parameter\n"); return ABIT_UGURU_BASE; } @@ -1467,8 +1468,7 @@ static int __init abituguru_init(void) abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address); if (!abituguru_pdev) { - printk(KERN_ERR ABIT_UGURU_NAME - ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); err = -ENOMEM; goto exit_driver_unregister; } @@ -1479,15 +1479,13 @@ static int __init abituguru_init(void) err = platform_device_add_resources(abituguru_pdev, &res, 1); if (err) { - printk(KERN_ERR ABIT_UGURU_NAME - ": Device resource addition failed (%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(abituguru_pdev); if (err) { - printk(KERN_ERR ABIT_UGURU_NAME - ": Device addition failed (%d)\n", err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From fe826749aec090c6f9ab48502bb9a7777572b85b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:26 +0000 Subject: hwmon: (abituguru3) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Added a few static strings to standardize logging messages. Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/abituguru3.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 3cf28af614b5..48d21e22e930 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -23,6 +23,9 @@ chip found on newer Abit uGuru motherboards. Note: because of lack of specs only reading the sensors and their settings is supported. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -608,6 +611,9 @@ static int verbose = 1; module_param(verbose, bool, 0644); MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting"); +static const char *never_happen = "This should never happen."; +static const char *report_this = + "Please report this to the abituguru3 maintainer (see MAINTAINERS)"; /* wait while the uguru is busy (usually after a write) */ static int abituguru3_wait_while_busy(struct abituguru3_data *data) @@ -940,15 +946,13 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) if (abituguru3_motherboards[i].id == id) break; if (!abituguru3_motherboards[i].id) { - printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard " - "ID: %04X. Please report this to the abituguru3 " - "maintainer (see MAINTAINERS)\n", (unsigned int)id); + pr_err("error unknown motherboard ID: %04X. %s\n", + (unsigned int)id, report_this); goto abituguru3_probe_error; } data->sensors = abituguru3_motherboards[i].sensors; - printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard " - "ID: %04X\n", (unsigned int)id); + pr_info("found Abit uGuru3, motherboard ID: %04X\n", (unsigned int)id); /* Fill the sysfs attr array */ sysfs_attr_i = 0; @@ -957,11 +961,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) for (i = 0; data->sensors[i].name; i++) { /* Fail safe check, this should never happen! */ if (i >= ABIT_UGURU3_MAX_NO_SENSORS) { - printk(KERN_ERR ABIT_UGURU3_NAME - ": Fatal error motherboard has more sensors " - "then ABIT_UGURU3_MAX_NO_SENSORS. This should " - "never happen please report to the abituguru3 " - "maintainer (see MAINTAINERS)\n"); + pr_err("Fatal error motherboard has more sensors then ABIT_UGURU3_MAX_NO_SENSORS. %s %s\n", + never_happen, report_this); res = -ENAMETOOLONG; goto abituguru3_probe_error; } @@ -983,10 +984,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) } /* Fail safe check, this should never happen! */ if (sysfs_names_free < 0) { - printk(KERN_ERR ABIT_UGURU3_NAME - ": Fatal error ran out of space for sysfs attr names. " - "This should never happen please report to the " - "abituguru3 maintainer (see MAINTAINERS)\n"); + pr_err("Fatal error ran out of space for sysfs attr names. %s %s\n", + never_happen, report_this); res = -ENAMETOOLONG; goto abituguru3_probe_error; } @@ -1189,8 +1188,7 @@ static int __init abituguru3_detect(void) "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val); if (force) { - printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is " - "present because of \"force\" parameter\n"); + pr_info("Assuming Abit uGuru3 is present because of \"force\" parameter\n"); return 0; } @@ -1219,10 +1217,8 @@ static int __init abituguru3_init(void) return err; #ifdef CONFIG_DMI - printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was " - "not detected using DMI. Please send the output of " - "\"dmidecode\" to the abituguru3 maintainer " - "(see MAINTAINERS)\n"); + pr_warn("this motherboard was not detected using DMI. " + "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n"); #endif } @@ -1233,8 +1229,7 @@ static int __init abituguru3_init(void) abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, ABIT_UGURU3_BASE); if (!abituguru3_pdev) { - printk(KERN_ERR ABIT_UGURU3_NAME - ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); err = -ENOMEM; goto exit_driver_unregister; } @@ -1245,15 +1240,13 @@ static int __init abituguru3_init(void) err = platform_device_add_resources(abituguru3_pdev, &res, 1); if (err) { - printk(KERN_ERR ABIT_UGURU3_NAME - ": Device resource addition failed (%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(abituguru3_pdev); if (err) { - printk(KERN_ERR ABIT_UGURU3_NAME - ": Device addition failed (%d)\n", err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From 2e991201e4ebffb1fb32873d72e2ee4b499269c3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:27 +0000 Subject: hwmon: (adt7470) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/adt7470.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 87d92a56a939..c6d1ce059aea 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -274,7 +276,7 @@ static int adt7470_read_temperatures(struct i2c_client *client, i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]); if (res) { - printk(KERN_ERR "ha ha, interrupted"); + pr_err("ha ha, interrupted\n"); return -EAGAIN; } -- cgit v1.2.3 From 4d630e2ba59a231c8e5031cc55e16737aa59af97 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:29 +0000 Subject: hwmon: (asb1000) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/asb100.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 7dada559b3a1..c02a052d3085 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -36,6 +36,8 @@ asb100 7 3 1 4 0x31 0x0694 yes no */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -701,8 +703,7 @@ static int asb100_detect(struct i2c_client *client, int val1, val2; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - pr_debug("asb100.o: detect failed, " - "smbus byte data not supported!\n"); + pr_debug("detect failed, smbus byte data not supported!\n"); return -ENODEV; } @@ -715,7 +716,7 @@ static int asb100_detect(struct i2c_client *client, (((!(val1 & 0x80)) && (val2 != 0x94)) || /* Check for ASB100 ID (high byte ) */ ((val1 & 0x80) && (val2 != 0x06)))) { - pr_debug("asb100: detect failed, bad chip id 0x%02x!\n", val2); + pr_debug("detect failed, bad chip id 0x%02x!\n", val2); return -ENODEV; } @@ -744,7 +745,7 @@ static int asb100_probe(struct i2c_client *client, data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL); if (!data) { - pr_debug("asb100.o: probe failed, kzalloc failed!\n"); + pr_debug("probe failed, kzalloc failed!\n"); err = -ENOMEM; goto ERROR0; } -- cgit v1.2.3 From ac561494d48b92a41424cc87e2a02b545424643c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:30 +0000 Subject: hwmon: (asus_atk0110) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/asus_atk0110.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 23b8555215d2..2d68cf3c223b 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -5,6 +5,8 @@ * See COPYING in the top level directory of the kernel tree. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1414,14 +1416,13 @@ static int __init atk0110_init(void) /* Make sure it's safe to access the device through ACPI */ if (!acpi_resources_are_enforced()) { - pr_err("atk: Resources not safely usable due to " - "acpi_enforce_resources kernel parameter\n"); + pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n"); return -EBUSY; } ret = acpi_bus_register_driver(&atk_driver); if (ret) - pr_info("atk: acpi_bus_register_driver failed: %d\n", ret); + pr_info("acpi_bus_register_driver failed: %d\n", ret); return ret; } -- cgit v1.2.3 From f8bb8925682f355dc20f721bda7021ef13e5869f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:31 +0000 Subject: hwmon: (coretemp) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 42de98d73ff5..194ca0aa8b0c 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -20,6 +20,8 @@ * 02110-1301 USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -445,8 +447,8 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) * without thermal sensors will be filtered out. */ if (!cpu_has(c, X86_FEATURE_DTS)) { - printk(KERN_INFO DRVNAME ": CPU (model=0x%x)" - " has no thermal sensor.\n", c->x86_model); + pr_info("CPU (model=0x%x) has no thermal sensor\n", + c->x86_model); return 0; } @@ -466,7 +468,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) pdev = platform_device_alloc(DRVNAME, cpu); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } @@ -478,8 +480,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_free; } -- cgit v1.2.3 From 9c6e13b411cf0f656b7d7a78ec35bf0069f631bb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:32 +0000 Subject: hwmon: (dme1737) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/dme1737.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 980c17d5eeae..e9a610bfd0cc 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -25,6 +25,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -2446,7 +2448,7 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) /* Get the base address of the runtime registers */ if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | dme1737_sio_inb(sio_cip, 0x61))) { - printk(KERN_ERR "dme1737: Base address not set.\n"); + pr_err("Base address not set\n"); err = -ENODEV; goto exit; } @@ -2475,20 +2477,18 @@ static int __init dme1737_isa_device_add(unsigned short addr) goto exit; if (!(pdev = platform_device_alloc("dme1737", addr))) { - printk(KERN_ERR "dme1737: Failed to allocate device.\n"); + pr_err("Failed to allocate device\n"); err = -ENOMEM; goto exit; } if ((err = platform_device_add_resources(pdev, &res, 1))) { - printk(KERN_ERR "dme1737: Failed to add device resource " - "(err = %d).\n", err); + pr_err("Failed to add device resource (err = %d)\n", err); goto exit_device_put; } if ((err = platform_device_add(pdev))) { - printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n", - err); + pr_err("Failed to add device (err = %d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From e54c5ad61f4e2c4fdfbdb8dff31fc604073d3550 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:33 +0000 Subject: hwmon: (f71805f) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/f71805f.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 525a00bd70b1..92f949767ece 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -28,6 +28,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1309,7 +1311,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev) if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Out of memory\n"); + pr_err("Out of memory\n"); goto exit; } @@ -1451,7 +1453,7 @@ static int __init f71805f_device_add(unsigned short address, pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } @@ -1462,22 +1464,20 @@ static int __init f71805f_device_add(unsigned short address, err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct f71805f_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } @@ -1516,30 +1516,27 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1); break; default: - printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " - "skipping\n"); + pr_info("Unsupported Fintek device, skipping\n"); goto exit; } superio_select(sioaddr, F71805F_LD_HWM); if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { - printk(KERN_WARNING DRVNAME ": Device not activated, " - "skipping\n"); + pr_warn("Device not activated, skipping\n"); goto exit; } *address = superio_inw(sioaddr, SIO_REG_ADDR); if (*address == 0) { - printk(KERN_WARNING DRVNAME ": Base address not set, " - "skipping\n"); + pr_warn("Base address not set, skipping\n"); goto exit; } *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ err = 0; - printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n", - names[sio_data->kind], *address, - superio_inb(sioaddr, SIO_REG_DEVREV)); + pr_info("Found %s chip at %#x, revision %u\n", + names[sio_data->kind], *address, + superio_inb(sioaddr, SIO_REG_DEVREV)); exit: superio_exit(sioaddr); -- cgit v1.2.3 From 22d3b41281b4c1a55086fa4dff7abb4f0c36403e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:34 +0000 Subject: hwmon: (f71882fg) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 75afb3b0e076..3f49dd376f02 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -18,6 +18,8 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -865,8 +867,7 @@ static inline int superio_enter(int base) { /* Don't step on other drivers' I/O space by accident */ if (!request_muxed_region(base, 2, DRVNAME)) { - printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n", - base); + pr_err("I/O address 0x%04x already in use\n", base); return -EBUSY; } @@ -2192,7 +2193,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = superio_inw(sioaddr, SIO_REG_MANID); if (devid != SIO_FINTEK_ID) { - pr_debug(DRVNAME ": Not a Fintek device\n"); + pr_debug("Not a Fintek device\n"); err = -ENODEV; goto exit; } @@ -2215,8 +2216,8 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, sio_data->type = f8000; break; default: - printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n", - (unsigned int)devid); + pr_info("Unsupported Fintek device: %04x\n", + (unsigned int)devid); err = -ENODEV; goto exit; } @@ -2227,21 +2228,21 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, superio_select(sioaddr, SIO_F71882FG_LD_HWM); if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { - printk(KERN_WARNING DRVNAME ": Device not activated\n"); + pr_warn("Device not activated\n"); err = -ENODEV; goto exit; } *address = superio_inw(sioaddr, SIO_REG_ADDR); if (*address == 0) { - printk(KERN_WARNING DRVNAME ": Base address not set\n"); + pr_warn("Base address not set\n"); err = -ENODEV; goto exit; } *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ err = 0; - printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n", + pr_info("Found %s chip at %#x, revision %d\n", f71882fg_names[sio_data->type], (unsigned int)*address, (int)superio_inb(sioaddr, SIO_REG_DEVREV)); exit: @@ -2270,20 +2271,20 @@ static int __init f71882fg_device_add(unsigned short address, err = platform_device_add_resources(f71882fg_pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed\n"); + pr_err("Device resource addition failed\n"); goto exit_device_put; } err = platform_device_add_data(f71882fg_pdev, sio_data, sizeof(struct f71882fg_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(f71882fg_pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed\n"); + pr_err("Device addition failed\n"); goto exit_device_put; } -- cgit v1.2.3 From 53ab0e6888925ae3ebe931c060120b0f11c1923c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:35 +0000 Subject: hwmon: (hp_accel) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/hp_accel.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index a56a78412fcb..3d21fa2b97cd 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -147,7 +149,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val) static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) { lis3_dev.ac = *((union axis_conversion *)dmi->driver_data); - printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); + pr_info("hardware type %s found\n", dmi->ident); return 1; } @@ -303,11 +305,10 @@ static int lis3lv02d_add(struct acpi_device *device) /* If possible use a "standard" axes order */ if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) { - printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n", - lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z); + pr_info("Using custom axes %d,%d,%d\n", + lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z); } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { - printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " - "using default axes configuration\n"); + pr_info("laptop model unknown, using default axes configuration\n"); lis3_dev.ac = lis3lv02d_axis_normal; } @@ -385,7 +386,7 @@ static int __init lis3lv02d_init_module(void) if (ret < 0) return ret; - printk(KERN_INFO DRIVER_NAME " driver loaded.\n"); + pr_info("driver loaded\n"); return 0; } -- cgit v1.2.3 From 1f923c7a6726b224b6b1b059da5a7f8e3dff1196 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:36 +0000 Subject: hwmon: (hwmon-vid) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon-vid.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 2b2ca1694f95..2582bfef6ccb 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -22,6 +22,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -146,8 +148,8 @@ int vid_from_reg(int val, u8 vrm) return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000); default: /* report 0 for unknown */ if (vrm) - printk(KERN_WARNING "hwmon-vid: Requested unsupported " - "VRM version (%u)\n", (unsigned int)vrm); + pr_warn("Requested unsupported VRM version (%u)\n", + (unsigned int)vrm); return 0; } } @@ -246,8 +248,7 @@ u8 vid_which_vrm(void) } vrm_ret = find_vrm(eff_family, eff_model, eff_stepping, c->x86_vendor); if (vrm_ret == 0) - printk(KERN_INFO "hwmon-vid: Unknown VRM version of your " - "x86 CPU\n"); + pr_info("Unknown VRM version of your x86 CPU\n"); return vrm_ret; } @@ -255,7 +256,7 @@ u8 vid_which_vrm(void) #else u8 vid_which_vrm(void) { - printk(KERN_INFO "hwmon-vid: Unknown VRM version of your CPU\n"); + pr_info("Unknown VRM version of your CPU\n"); return 0; } #endif -- cgit v1.2.3 From c95df1ae69b85d5f306d86164e245aae614b852a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:37 +0000 Subject: hwmon: (core) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 29ea6753f3bb..a61e7815a2a9 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -10,6 +10,8 @@ the Free Software Foundation; version 2 of the License. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -119,7 +121,7 @@ static int __init hwmon_init(void) hwmon_class = class_create(THIS_MODULE, "hwmon"); if (IS_ERR(hwmon_class)) { - printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); + pr_err("couldn't create sysfs class\n"); return PTR_ERR(hwmon_class); } return 0; -- cgit v1.2.3 From 55d705cce829c37999f26a8d4f1dd701013e7920 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:38 +0000 Subject: hwmon: (ibmaem) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/ibmaem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index eaee546af19a..bc6e2ab3a361 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1090,7 +1092,7 @@ static int __init aem_init(void) res = driver_register(&aem_driver.driver); if (res) { - printk(KERN_ERR "Can't register aem driver\n"); + pr_err("Can't register aem driver\n"); return res; } -- cgit v1.2.3 From 63366d37ad5dbb4f208b517c88ea4bd41738dbf7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:40 +0000 Subject: hwmon: (lis3lv02d) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/lis3lv02d.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 0cee73a6124e..1b674b7d4584 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -860,8 +862,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev, (p->irq_flags2 & IRQF_TRIGGER_MASK), DRIVER_NAME, &lis3_dev); if (err < 0) - printk(KERN_ERR DRIVER_NAME - "No second IRQ. Limited functionality\n"); + pr_err("No second IRQ. Limited functionality\n"); } } @@ -879,7 +880,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) switch (dev->whoami) { case WAI_12B: - printk(KERN_INFO DRIVER_NAME ": 12 bits sensor found\n"); + pr_info("12 bits sensor found\n"); dev->read_data = lis3lv02d_read_12; dev->mdps_max_val = 2048; dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B; @@ -890,7 +891,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) dev->regs_size = ARRAY_SIZE(lis3_wai12_regs); break; case WAI_8B: - printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n"); + pr_info("8 bits sensor found\n"); dev->read_data = lis3lv02d_read_8; dev->mdps_max_val = 128; dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; @@ -901,7 +902,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) dev->regs_size = ARRAY_SIZE(lis3_wai8_regs); break; case WAI_3DC: - printk(KERN_INFO DRIVER_NAME ": 8 bits 3DC sensor found\n"); + pr_info("8 bits 3DC sensor found\n"); dev->read_data = lis3lv02d_read_8; dev->mdps_max_val = 128; dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; @@ -910,8 +911,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) dev->scale = LIS3_SENSITIVITY_8B; break; default: - printk(KERN_ERR DRIVER_NAME - ": unknown sensor type 0x%X\n", dev->whoami); + pr_err("unknown sensor type 0x%X\n", dev->whoami); return -EINVAL; } @@ -935,7 +935,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) } if (lis3lv02d_joystick_enable()) - printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); + pr_err("joystick initialization failed\n"); /* passing in platform specific data is purely optional and only * used by the SPI transport layer at the moment */ @@ -957,8 +957,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) /* bail if we did not get an IRQ from the bus layer */ if (!dev->irq) { - printk(KERN_ERR DRIVER_NAME - ": No IRQ. Disabling /dev/freefall\n"); + pr_err("No IRQ. Disabling /dev/freefall\n"); goto out; } @@ -985,12 +984,12 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) DRIVER_NAME, &lis3_dev); if (err < 0) { - printk(KERN_ERR DRIVER_NAME "Cannot get IRQ\n"); + pr_err("Cannot get IRQ\n"); goto out; } if (misc_register(&lis3lv02d_misc_device)) - printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); + pr_err("misc_register failed\n"); out: return 0; } -- cgit v1.2.3 From 5713017ec5e1a437ae4d0d196bce46d572eb7e1a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:41 +0000 Subject: hwmon: (lm70) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/lm70.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index fd108cfc05c7..3b84fb503053 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -24,6 +24,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -67,8 +69,7 @@ static ssize_t lm70_sense_temp(struct device *dev, */ status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2); if (status < 0) { - printk(KERN_WARNING - "spi_write_then_read failed with status %d\n", status); + pr_warn("spi_write_then_read failed with status %d\n", status); goto out; } raw = (rxbuf[0] << 8) + rxbuf[1]; -- cgit v1.2.3 From 2caec1343e0cfe59bacf3d4f67d69ab6283cc75b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:45 +0000 Subject: hwmon: (pcf8591) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/pcf8591.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index dc7259d69812..731b09af76b9 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -18,6 +18,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -290,8 +292,7 @@ static struct i2c_driver pcf8591_driver = { static int __init pcf8591_init(void) { if (input_mode < 0 || input_mode > 3) { - printk(KERN_WARNING "pcf8591: invalid input_mode (%d)\n", - input_mode); + pr_warn("invalid input_mode (%d)\n", input_mode); input_mode = 0; } return i2c_add_driver(&pcf8591_driver); -- cgit v1.2.3 From 14a613cc23869d0ca69154bbc5816004fe201b17 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:46 +0000 Subject: hwmon: (pkgtemp) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/pkgtemp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c index 0798210590bc..21c817d98123 100644 --- a/drivers/hwmon/pkgtemp.c +++ b/drivers/hwmon/pkgtemp.c @@ -20,6 +20,8 @@ * 02110-1301 USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -303,7 +305,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu) pdev = platform_device_alloc(DRVNAME, cpu); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } @@ -315,8 +317,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu) err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_free; } -- cgit v1.2.3 From 4b2515dbb94341db01db3208f9f40658c5e2a251 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:47 +0000 Subject: hwmon: (sis5595) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/sis5595.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 79c2931e3008..47d7ce9af8fb 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -50,6 +50,8 @@ 735 0008 0735 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -735,21 +737,19 @@ static int __devinit sis5595_device_add(unsigned short address) pdev = platform_device_alloc("sis5595", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "sis5595: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "sis5595: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "sis5595: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From bf1a85eff87eeb0651b1c5b348d51206ec7c0ef5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:48 +0000 Subject: hwmon: (smsc47b397) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/smsc47b397.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index f46d936c12da..9fb7516e6f45 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -311,21 +313,19 @@ static int __init smsc47b397_device_add(unsigned short address) pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } @@ -367,8 +367,7 @@ static int __init smsc47b397_find(unsigned short *addr) *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) | superio_inb(SUPERIO_REG_BASE_LSB); - printk(KERN_INFO DRVNAME ": found SMSC %s " - "(base address 0x%04x, revision %u)\n", + pr_info("found SMSC %s (base address 0x%04x, revision %u)\n", name, *addr, rev); superio_exit(); -- cgit v1.2.3 From 512504e9f5489dbe85c80fd2c1b44ab5a8e0d5fa Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:49 +0000 Subject: hwmon: (smsc47m1) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/smsc47m1.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 8fa462f2b570..f44a89aac381 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -435,30 +437,29 @@ static int __init smsc47m1_find(unsigned short *addr, */ switch (val) { case 0x51: - pr_info(DRVNAME ": Found SMSC LPC47B27x\n"); + pr_info("Found SMSC LPC47B27x\n"); sio_data->type = smsc47m1; break; case 0x59: - pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n"); + pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n"); sio_data->type = smsc47m1; break; case 0x5F: - pr_info(DRVNAME ": Found SMSC LPC47M14x\n"); + pr_info("Found SMSC LPC47M14x\n"); sio_data->type = smsc47m1; break; case 0x60: - pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n"); + pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997\n"); sio_data->type = smsc47m1; break; case 0x6B: if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) { - pr_debug(DRVNAME ": " - "Found SMSC LPC47M233, unsupported\n"); + pr_debug("Found SMSC LPC47M233, unsupported\n"); superio_exit(); return -ENODEV; } - pr_info(DRVNAME ": Found SMSC LPC47M292\n"); + pr_info("Found SMSC LPC47M292\n"); sio_data->type = smsc47m2; break; default: @@ -470,7 +471,7 @@ static int __init smsc47m1_find(unsigned short *addr, *addr = (superio_inb(SUPERIO_REG_BASE) << 8) | superio_inb(SUPERIO_REG_BASE + 1); if (*addr == 0) { - pr_info(DRVNAME ": Device address not set, will not use\n"); + pr_info("Device address not set, will not use\n"); superio_exit(); return -ENODEV; } @@ -479,7 +480,7 @@ static int __init smsc47m1_find(unsigned short *addr, * Compaq Presario S4000NX) */ sio_data->activate = superio_inb(SUPERIO_REG_ACT); if ((sio_data->activate & 0x01) == 0) { - pr_info(DRVNAME ": Enabling device\n"); + pr_info("Enabling device\n"); superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01); } @@ -494,7 +495,7 @@ static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data) superio_enter(); superio_select(); - pr_info(DRVNAME ": Disabling device\n"); + pr_info("Disabling device\n"); superio_outb(SUPERIO_REG_ACT, sio_data->activate); superio_exit(); @@ -823,28 +824,26 @@ static int __init smsc47m1_device_add(unsigned short address, pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct smsc47m1_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From edb8d53c684da4062ac8c461727ddc1839336aa5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:50 +0000 Subject: hwmon: (via-cputemp) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/via-cputemp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index ec7fad747adc..45b08c78b531 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -21,6 +21,8 @@ * 02110-1301 USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -202,7 +204,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu) pdev = platform_device_alloc(DRVNAME, cpu); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } @@ -214,8 +216,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu) err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_free; } @@ -295,8 +296,7 @@ static int __init via_cputemp_init(void) continue; if (c->x86_model > 0x0f) { - printk(KERN_WARNING DRVNAME ": Unknown CPU " - "model 0x%x\n", c->x86_model); + pr_warn("Unknown CPU model 0x%x\n", c->x86_model); continue; } -- cgit v1.2.3 From 774f7827e13cfae720306ca44b83b93ab2a6b9be Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:51 +0000 Subject: hwmon: (via686a) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/via686a.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index f397ce7ad598..13e8d218e495 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -30,6 +30,8 @@ Warning - only supports a single device. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -791,21 +793,19 @@ static int __devinit via686a_device_add(unsigned short address) pdev = platform_device_alloc("via686a", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "via686a: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "via686a: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "via686a: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From 5ed9ba6b87545d21b48e50a028bfb79f9812f89f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:52 +0000 Subject: hwmon: (vt1211) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/vt1211.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index ae33bbb577c7..49163d48e966 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -21,6 +21,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1254,8 +1256,7 @@ static int __init vt1211_device_add(unsigned short address) pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n", - err); + pr_err("Device allocation failed (%d)\n", err); goto EXIT; } @@ -1266,15 +1267,13 @@ static int __init vt1211_device_add(unsigned short address) err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto EXIT_DEV_PUT; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto EXIT_DEV_PUT; } @@ -1301,23 +1300,20 @@ static int __init vt1211_find(int sio_cip, unsigned short *address) superio_select(sio_cip, SIO_VT1211_LDN_HWMON); if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) { - printk(KERN_WARNING DRVNAME ": HW monitor is disabled, " - "skipping\n"); + pr_warn("HW monitor is disabled, skipping\n"); goto EXIT; } *address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) | (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00; if (*address == 0) { - printk(KERN_WARNING DRVNAME ": Base address is not set, " - "skipping\n"); + pr_warn("Base address is not set, skipping\n"); goto EXIT; } err = 0; - printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, " - "revision %u\n", *address, - superio_inb(sio_cip, SIO_VT1211_DEVREV)); + pr_info("Found VT1211 chip at 0x%04x, revision %u\n", + *address, superio_inb(sio_cip, SIO_VT1211_DEVREV)); EXIT: superio_exit(sio_cip); @@ -1336,15 +1332,15 @@ static int __init vt1211_init(void) if ((uch_config < -1) || (uch_config > 31)) { err = -EINVAL; - printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. " - "Choose a value between 0 and 31.\n", uch_config); + pr_warn("Invalid UCH configuration %d. " + "Choose a value between 0 and 31.\n", uch_config); goto EXIT; } if ((int_mode < -1) || (int_mode > 0)) { err = -EINVAL; - printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. " - "Only mode 0 is supported.\n", int_mode); + pr_warn("Invalid interrupt mode %d. " + "Only mode 0 is supported.\n", int_mode); goto EXIT; } -- cgit v1.2.3 From 9d72be0da16da10e27f6a8c01f877db6c513413d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:53 +0000 Subject: hwmon: (vt8231) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/vt8231.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index e6078c9f0e27..db3b2e8d2a67 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -24,6 +24,8 @@ /* Supports VIA VT8231 South Bridge embedded sensors */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -902,21 +904,19 @@ static int __devinit vt8231_device_add(unsigned short address) pdev = platform_device_alloc("vt8231", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "vt8231: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "vt8231: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "vt8231: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From abdc6fd189405a83ebd20aa9facfbdf3c179d48a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:54 +0000 Subject: hwmon: (w83627ehf) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/w83627ehf.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 072c58008a63..073eabedc432 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -42,6 +42,8 @@ w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1668,8 +1670,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, break; default: if (val != 0xffff) - pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", - val); + pr_debug("unsupported chip ID: 0x%04x\n", val); superio_exit(sioaddr); return -ENODEV; } @@ -1680,8 +1681,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | superio_inb(sioaddr, SIO_REG_ADDR + 1); *addr = val & IOREGION_ALIGNMENT; if (*addr == 0) { - printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O " - "device with a base I/O port 0.\n"); + pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n"); superio_exit(sioaddr); return -ENODEV; } @@ -1689,13 +1689,12 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, /* Activate logical device if needed */ val = superio_inb(sioaddr, SIO_REG_ENABLE); if (!(val & 0x01)) { - printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. " - "Sensor is probably unusable.\n"); + pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n"); superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); } superio_exit(sioaddr); - pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr); + pr_info("Found %s chip at %#x\n", sio_name, *addr); sio_data->sioreg = sioaddr; return 0; @@ -1729,14 +1728,14 @@ static int __init sensors_w83627ehf_init(void) if (!(pdev = platform_device_alloc(DRVNAME, address))) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit_unregister; } err = platform_device_add_data(pdev, &sio_data, sizeof(struct w83627ehf_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } @@ -1752,16 +1751,14 @@ static int __init sensors_w83627ehf_init(void) err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } /* platform_device_add calls probe() */ err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From 18de030f1dbaef0c13cf393899a298d978aa200f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 20 Oct 2010 06:51:55 +0000 Subject: hwmon: (w83627hf) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Guenter Roeck --- drivers/hwmon/w83627hf.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 38e280523071..bde50e34d013 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -39,6 +39,8 @@ supported yet. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1166,14 +1168,13 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, superio_inb(sio_data, WINB_BASE_REG + 1); *addr = val & WINB_ALIGNMENT; if (*addr == 0) { - printk(KERN_WARNING DRVNAME ": Base address not set, " - "skipping\n"); + pr_warn("Base address not set, skipping\n"); goto exit; } val = superio_inb(sio_data, WINB_ACT_REG); if (!(val & 0x01)) { - printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n"); + pr_warn("Enabling HWM logical device\n"); superio_outb(sio_data, WINB_ACT_REG, val | 0x01); } @@ -1789,28 +1790,26 @@ static int __init w83627hf_device_add(unsigned short address, pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct w83627hf_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From 132af03233b493101a53010383b5abb5b9ff1e51 Mon Sep 17 00:00:00 2001 From: Edgar Hucek Date: Tue, 9 Nov 2010 15:15:01 +0000 Subject: hwmon: (applesmc) Add MacBookAir3,1(3,2) support This patch add support for the MacBookAir3,1 and MacBookAir3,2 to the applesmc driver. [rydberg@euromail.se: minor cleanup] Cc: stable@kernel.org Signed-off-by: Edgar Hucek Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index b6598aa557a0..d616174807a1 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -162,6 +162,10 @@ static const char *temperature_sensors_sets[][41] = { /* Set 22: MacBook Pro 7,1 */ { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S", "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL }, +/* Set 23: MacBook Air 3,1 */ + { "TB0T", "TB1T", "TB2T", "TC0D", "TC0E", "TC0P", "TC1E", "TCZ3", + "TCZ4", "TCZ5", "TG0E", "TG1E", "TG2E", "TGZ3", "TGZ4", "TGZ5", + "TH0F", "TH0O", "TM0P" }, }; /* List of keys used to read/write fan speeds */ @@ -1524,11 +1528,17 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = { { .accelerometer = 1, .light = 1, .temperature_set = 21 }, /* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */ { .accelerometer = 1, .light = 1, .temperature_set = 22 }, +/* MacBook Air 3,1: accelerometer, backlight and temperature set 23 */ + { .accelerometer = 0, .light = 0, .temperature_set = 23 }, }; /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ static __initdata struct dmi_system_id applesmc_whitelist[] = { + { applesmc_dmi_match, "Apple MacBook Air 3", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3") }, + &applesmc_dmi_data[23]}, { applesmc_dmi_match, "Apple MacBook Air 2", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") }, -- cgit v1.2.3 From 2344cd0c2e9ea8f3037be11fb997ddbeda0237ca Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 9 Nov 2010 15:15:02 +0000 Subject: hwmon: (applesmc) Relax the severity of device init failure The device init is used to reset the accelerometer. Failure to reset is not severe enough to stop loading the module or to resume from hibernation. This patch relaxes failure to a warning and drops output in case of success. Cc: stable@kernel.org Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index d616174807a1..87a5fd51dd5e 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -448,38 +448,22 @@ static int applesmc_read_motion_sensor(int index, s16* value) } /* - * applesmc_device_init - initialize the accelerometer. Returns zero on success - * and negative error code on failure. Can sleep. + * applesmc_device_init - initialize the accelerometer. Can sleep. */ -static int applesmc_device_init(void) +static void applesmc_device_init(void) { - int total, ret = -ENXIO; + int total; u8 buffer[2]; if (!applesmc_accelerometer) - return 0; + return; mutex_lock(&applesmc_lock); for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) { - if (debug) - printk(KERN_DEBUG "applesmc try %d\n", total); if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) && - (buffer[0] != 0x00 || buffer[1] != 0x00)) { - if (total == INIT_TIMEOUT_MSECS) { - printk(KERN_DEBUG "applesmc: device has" - " already been initialized" - " (0x%02x, 0x%02x).\n", - buffer[0], buffer[1]); - } else { - printk(KERN_DEBUG "applesmc: device" - " successfully initialized" - " (0x%02x, 0x%02x).\n", - buffer[0], buffer[1]); - } - ret = 0; + (buffer[0] != 0x00 || buffer[1] != 0x00)) goto out; - } buffer[0] = 0xe0; buffer[1] = 0x00; applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2); @@ -490,7 +474,6 @@ static int applesmc_device_init(void) out: mutex_unlock(&applesmc_lock); - return ret; } /* @@ -516,13 +499,8 @@ static int applesmc_get_fan_count(void) /* Device model stuff */ static int applesmc_probe(struct platform_device *dev) { - int ret; + applesmc_device_init(); - ret = applesmc_device_init(); - if (ret) - return ret; - - printk(KERN_INFO "applesmc: device successfully initialized.\n"); return 0; } @@ -539,9 +517,7 @@ static int applesmc_pm_resume(struct device *dev) /* Reinitialize device on resume from hibernation */ static int applesmc_pm_restore(struct device *dev) { - int ret = applesmc_device_init(); - if (ret) - return ret; + applesmc_device_init(); return applesmc_pm_resume(dev); } -- cgit v1.2.3 From 1ee7c71bd1aa9758f14e1be92310215a5bd0abe7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 9 Nov 2010 15:15:03 +0000 Subject: hwmon: (applesmc) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 58 ++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 87a5fd51dd5e..5f67e390e45c 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -26,6 +26,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -251,8 +253,7 @@ static int __wait_status(u8 val) } } - printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n", - val, inb(APPLESMC_CMD_PORT)); + pr_warn("wait status failed: %x != %x\n", val, inb(APPLESMC_CMD_PORT)); return -EIO; } @@ -271,8 +272,7 @@ static int send_command(u8 cmd) if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c) return 0; } - printk(KERN_WARNING "applesmc: command failed: %x -> %x\n", - cmd, inb(APPLESMC_CMD_PORT)); + pr_warn("command failed: %x -> %x\n", cmd, inb(APPLESMC_CMD_PORT)); return -EIO; } @@ -286,8 +286,8 @@ static int applesmc_read_key(const char* key, u8* buffer, u8 len) int i; if (len > APPLESMC_MAX_DATA_LENGTH) { - printk(KERN_ERR "applesmc_read_key: cannot read more than " - "%d bytes\n", APPLESMC_MAX_DATA_LENGTH); + pr_err("%s(): cannot read more than %d bytes\n", + __func__, APPLESMC_MAX_DATA_LENGTH); return -EINVAL; } @@ -329,8 +329,8 @@ static int applesmc_write_key(const char* key, u8* buffer, u8 len) int i; if (len > APPLESMC_MAX_DATA_LENGTH) { - printk(KERN_ERR "applesmc_write_key: cannot write more than " - "%d bytes\n", APPLESMC_MAX_DATA_LENGTH); + pr_err("%s(): cannot write more than %d bytes\n", + __func__, APPLESMC_MAX_DATA_LENGTH); return -EINVAL; } @@ -470,7 +470,7 @@ static void applesmc_device_init(void) msleep(INIT_WAIT_MSECS); } - printk(KERN_WARNING "applesmc: failed to init the device\n"); + pr_warn("failed to init the device\n"); out: mutex_unlock(&applesmc_lock); @@ -616,8 +616,7 @@ static ssize_t applesmc_light_show(struct device *dev, if (ret) goto out; data_length = clamp_val(query[0], 0, 10); - printk(KERN_INFO "applesmc: light sensor data length set to " - "%d\n", data_length); + pr_info("light sensor data length set to %d\n", data_length); } ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length); @@ -1383,18 +1382,18 @@ static int applesmc_dmi_match(const struct dmi_system_id *id) { int i = 0; struct dmi_match_data* dmi_data = id->driver_data; - printk(KERN_INFO "applesmc: %s detected:\n", id->ident); + pr_info("%s detected:\n", id->ident); applesmc_accelerometer = dmi_data->accelerometer; - printk(KERN_INFO "applesmc: - Model %s accelerometer\n", - applesmc_accelerometer ? "with" : "without"); + pr_info(" - Model %s accelerometer\n", + applesmc_accelerometer ? "with" : "without"); applesmc_light = dmi_data->light; - printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n", - applesmc_light ? "with" : "without"); + pr_info(" - Model %s light sensors and backlight\n", + applesmc_light ? "with" : "without"); applesmc_temperature_set = dmi_data->temperature_set; while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL) i++; - printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i); + pr_info(" - Model with %d temperature sensors\n", i); return 1; } @@ -1445,7 +1444,7 @@ out_sysfs: sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); out: - printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret); + pr_warn("driver init failed (ret=%d)!\n", ret); return ret; } @@ -1625,7 +1624,7 @@ static int __init applesmc_init(void) int i; if (!dmi_check_system(applesmc_whitelist)) { - printk(KERN_WARNING "applesmc: supported laptop not found!\n"); + pr_warn("supported laptop not found!\n"); ret = -ENODEV; goto out; } @@ -1659,15 +1658,13 @@ static int __init applesmc_init(void) /* create fan files */ count = applesmc_get_fan_count(); if (count < 0) - printk(KERN_ERR "applesmc: Cannot get the number of fans.\n"); + pr_err("Cannot get the number of fans\n"); else - printk(KERN_INFO "applesmc: %d fans found.\n", count); + pr_info("%d fans found\n", count); if (count > 4) { count = 4; - printk(KERN_WARNING "applesmc: More than 4 fans found," - " but at most 4 fans are supported" - " by the driver.\n"); + pr_warn("A maximum of 4 fans are supported by this driver\n"); } while (fans_handled < count) { @@ -1683,11 +1680,8 @@ static int __init applesmc_init(void) i++) { if (temperature_attributes[i] == NULL || label_attributes[i] == NULL) { - printk(KERN_ERR "applesmc: More temperature sensors " - "in temperature_sensors_sets (at least %i)" - "than available sysfs files in " - "temperature_attributes (%i), please report " - "this bug.\n", i, i-1); + pr_err("More temperature sensors in temperature_sensors_sets (at least %i) than available sysfs files in temperature_attributes (%i), please report this bug\n", + i, i-1); goto out_temperature; } ret = sysfs_create_file(&pdev->dev.kobj, @@ -1731,7 +1725,7 @@ static int __init applesmc_init(void) goto out_light_ledclass; } - printk(KERN_INFO "applesmc: driver successfully loaded.\n"); + pr_info("driver successfully loaded\n"); return 0; @@ -1764,7 +1758,7 @@ out_driver: out_region: release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); out: - printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret); + pr_warn("driver init failed (ret=%d)!\n", ret); return ret; } @@ -1789,7 +1783,7 @@ static void __exit applesmc_exit(void) platform_driver_unregister(&applesmc_driver); release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); - printk(KERN_INFO "applesmc: driver unloaded.\n"); + pr_info("driver unloaded\n"); } module_init(applesmc_init); -- cgit v1.2.3 From 5874583d5662de5550b0ed1c54a9dea70bcdcba4 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 10 Nov 2010 10:58:03 +0000 Subject: hwmon: (applesmc) Introduce a register lookup table One main problem with the current driver is the inability to quickly search for supported keys, resulting in detailed feature maps per machine model which are cumbersome to maintain. This patch adds a register lookup table, which enables binary search for supported keys. The lookup also reduces the io frequency, so the original mutex is replaced by locks around the actual io. Signed-off-by: Henrik Rydberg [guenter.roeck@ericsson.com: Added value range check to key_at_index_store()] Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 539 ++++++++++++++++++++++++++--------------------- 1 file changed, 297 insertions(+), 242 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 5f67e390e45c..f213997adaec 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #define APPLESMC_MAX_DATA_LENGTH 32 +/* wait up to 32 ms for a status change. */ #define APPLESMC_MIN_WAIT 0x0040 #define APPLESMC_MAX_WAIT 0x8000 @@ -200,6 +202,25 @@ struct dmi_match_data { int temperature_set; }; +/* AppleSMC entry - cached register information */ +struct applesmc_entry { + char key[5]; /* four-letter key code */ + u8 valid; /* set when entry is successfully read once */ + u8 len; /* bounded by APPLESMC_MAX_DATA_LENGTH */ + char type[5]; /* four-letter type code */ + u8 flags; /* 0x10: func; 0x40: write; 0x80: read */ +}; + +/* Register lookup and registers common to all SMCs */ +static struct applesmc_registers { + struct mutex mutex; /* register read/write mutex */ + unsigned int key_count; /* number of SMC registers */ + bool init_complete; /* true when fully initialized */ + struct applesmc_entry *cache; /* cached key entries */ +} smcreg = { + .mutex = __MUTEX_INITIALIZER(smcreg.mutex), +}; + static const int debug; static struct platform_device *pdev; static s16 rest_x; @@ -221,8 +242,6 @@ static unsigned int fans_handled; /* Indicates which temperature sensors set to use. */ static unsigned int applesmc_temperature_set; -static DEFINE_MUTEX(applesmc_lock); - /* * Last index written to key_at_index sysfs file, and value to use for all other * key_at_index_* sysfs files. @@ -245,16 +264,10 @@ static int __wait_status(u8 val) for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { udelay(us); if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) { - if (debug) - printk(KERN_DEBUG - "Waited %d us for status %x\n", - 2 * us - APPLESMC_MIN_WAIT, val); return 0; } } - pr_warn("wait status failed: %x != %x\n", val, inb(APPLESMC_CMD_PORT)); - return -EIO; } @@ -272,156 +285,228 @@ static int send_command(u8 cmd) if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c) return 0; } - pr_warn("command failed: %x -> %x\n", cmd, inb(APPLESMC_CMD_PORT)); return -EIO; } -/* - * applesmc_read_key - reads len bytes from a given key, and put them in buffer. - * Returns zero on success or a negative error on failure. Callers must - * hold applesmc_lock. - */ -static int applesmc_read_key(const char* key, u8* buffer, u8 len) +static int send_argument(const char *key) { int i; - if (len > APPLESMC_MAX_DATA_LENGTH) { - pr_err("%s(): cannot read more than %d bytes\n", - __func__, APPLESMC_MAX_DATA_LENGTH); - return -EINVAL; - } - - if (send_command(APPLESMC_READ_CMD)) - return -EIO; - for (i = 0; i < 4; i++) { outb(key[i], APPLESMC_DATA_PORT); if (__wait_status(0x04)) return -EIO; } - if (debug) - printk(KERN_DEBUG "<%s", key); + return 0; +} + +static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len) +{ + int i; + + if (send_command(cmd) || send_argument(key)) { + pr_warn("%s: read arg fail\n", key); + return -EIO; + } outb(len, APPLESMC_DATA_PORT); - if (debug) - printk(KERN_DEBUG ">%x", len); for (i = 0; i < len; i++) { - if (__wait_status(0x05)) + if (__wait_status(0x05)) { + pr_warn("%s: read data fail\n", key); return -EIO; + } buffer[i] = inb(APPLESMC_DATA_PORT); - if (debug) - printk(KERN_DEBUG "<%x", buffer[i]); } - if (debug) - printk(KERN_DEBUG "\n"); return 0; } -/* - * applesmc_write_key - writes len bytes from buffer to a given key. - * Returns zero on success or a negative error on failure. Callers must - * hold applesmc_lock. - */ -static int applesmc_write_key(const char* key, u8* buffer, u8 len) +static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len) { int i; - if (len > APPLESMC_MAX_DATA_LENGTH) { - pr_err("%s(): cannot write more than %d bytes\n", - __func__, APPLESMC_MAX_DATA_LENGTH); - return -EINVAL; - } - - if (send_command(APPLESMC_WRITE_CMD)) + if (send_command(cmd) || send_argument(key)) { + pr_warn("%s: write arg fail\n", key); return -EIO; - - for (i = 0; i < 4; i++) { - outb(key[i], APPLESMC_DATA_PORT); - if (__wait_status(0x04)) - return -EIO; } outb(len, APPLESMC_DATA_PORT); for (i = 0; i < len; i++) { - if (__wait_status(0x04)) + if (__wait_status(0x04)) { + pr_warn("%s: write data fail\n", key); return -EIO; + } outb(buffer[i], APPLESMC_DATA_PORT); } return 0; } +static int read_register_count(unsigned int *count) +{ + __be32 be; + int ret; + + ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4); + if (ret) + return ret; + + *count = be32_to_cpu(be); + return 0; +} + /* - * applesmc_get_key_at_index - get key at index, and put the result in key - * (char[6]). Returns zero on success or a negative error on failure. Callers - * must hold applesmc_lock. + * Serialized I/O + * + * Returns zero on success or a negative error on failure. + * All functions below are concurrency safe - callers should NOT hold lock. */ -static int applesmc_get_key_at_index(int index, char* key) + +static int applesmc_read_entry(const struct applesmc_entry *entry, + u8 *buf, u8 len) { - int i; - u8 readkey[4]; - readkey[0] = index >> 24; - readkey[1] = index >> 16; - readkey[2] = index >> 8; - readkey[3] = index; + int ret; - if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD)) - return -EIO; + if (entry->len != len) + return -EINVAL; + mutex_lock(&smcreg.mutex); + ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len); + mutex_unlock(&smcreg.mutex); - for (i = 0; i < 4; i++) { - outb(readkey[i], APPLESMC_DATA_PORT); - if (__wait_status(0x04)) - return -EIO; + return ret; +} + +static int applesmc_write_entry(const struct applesmc_entry *entry, + const u8 *buf, u8 len) +{ + int ret; + + if (entry->len != len) + return -EINVAL; + mutex_lock(&smcreg.mutex); + ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len); + mutex_unlock(&smcreg.mutex); + return ret; +} + +static const struct applesmc_entry *applesmc_get_entry_by_index(int index) +{ + struct applesmc_entry *cache = &smcreg.cache[index]; + u8 key[4], info[6]; + __be32 be; + int ret = 0; + + if (cache->valid) + return cache; + + mutex_lock(&smcreg.mutex); + + if (cache->valid) + goto out; + be = cpu_to_be32(index); + ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4); + if (ret) + goto out; + ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6); + if (ret) + goto out; + + memcpy(cache->key, key, 4); + cache->len = info[0]; + memcpy(cache->type, &info[1], 4); + cache->flags = info[5]; + cache->valid = 1; + +out: + mutex_unlock(&smcreg.mutex); + if (ret) + return ERR_PTR(ret); + return cache; +} + +static int applesmc_get_lower_bound(unsigned int *lo, const char *key) +{ + int begin = 0, end = smcreg.key_count; + const struct applesmc_entry *entry; + + while (begin != end) { + int middle = begin + (end - begin) / 2; + entry = applesmc_get_entry_by_index(middle); + if (IS_ERR(entry)) + return PTR_ERR(entry); + if (strcmp(entry->key, key) < 0) + begin = middle + 1; + else + end = middle; } - outb(4, APPLESMC_DATA_PORT); + *lo = begin; + return 0; +} - for (i = 0; i < 4; i++) { - if (__wait_status(0x05)) - return -EIO; - key[i] = inb(APPLESMC_DATA_PORT); +static int applesmc_get_upper_bound(unsigned int *hi, const char *key) +{ + int begin = 0, end = smcreg.key_count; + const struct applesmc_entry *entry; + + while (begin != end) { + int middle = begin + (end - begin) / 2; + entry = applesmc_get_entry_by_index(middle); + if (IS_ERR(entry)) + return PTR_ERR(entry); + if (strcmp(key, entry->key) < 0) + end = middle; + else + begin = middle + 1; } - key[4] = 0; + *hi = begin; return 0; } -/* - * applesmc_get_key_type - get key type, and put the result in type (char[6]). - * Returns zero on success or a negative error on failure. Callers must - * hold applesmc_lock. - */ -static int applesmc_get_key_type(char* key, char* type) +static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key) { - int i; + int begin, end; + int ret; - if (send_command(APPLESMC_GET_KEY_TYPE_CMD)) - return -EIO; + ret = applesmc_get_lower_bound(&begin, key); + if (ret) + return ERR_PTR(ret); + ret = applesmc_get_upper_bound(&end, key); + if (ret) + return ERR_PTR(ret); + if (end - begin != 1) + return ERR_PTR(-EINVAL); - for (i = 0; i < 4; i++) { - outb(key[i], APPLESMC_DATA_PORT); - if (__wait_status(0x04)) - return -EIO; - } + return applesmc_get_entry_by_index(begin); +} - outb(6, APPLESMC_DATA_PORT); +static int applesmc_read_key(const char *key, u8 *buffer, u8 len) +{ + const struct applesmc_entry *entry; - for (i = 0; i < 6; i++) { - if (__wait_status(0x05)) - return -EIO; - type[i] = inb(APPLESMC_DATA_PORT); - } - type[5] = 0; + entry = applesmc_get_entry_by_key(key); + if (IS_ERR(entry)) + return PTR_ERR(entry); - return 0; + return applesmc_read_entry(entry, buffer, len); +} + +static int applesmc_write_key(const char *key, const u8 *buffer, u8 len) +{ + const struct applesmc_entry *entry; + + entry = applesmc_get_entry_by_key(key); + if (IS_ERR(entry)) + return PTR_ERR(entry); + + return applesmc_write_entry(entry, buffer, len); } /* - * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must - * hold applesmc_lock. + * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). */ static int applesmc_read_motion_sensor(int index, s16* value) { @@ -458,12 +543,10 @@ static void applesmc_device_init(void) if (!applesmc_accelerometer) return; - mutex_lock(&applesmc_lock); - for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) { if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) && (buffer[0] != 0x00 || buffer[1] != 0x00)) - goto out; + return; buffer[0] = 0xe0; buffer[1] = 0x00; applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2); @@ -471,34 +554,93 @@ static void applesmc_device_init(void) } pr_warn("failed to init the device\n"); - -out: - mutex_unlock(&applesmc_lock); } /* - * applesmc_get_fan_count - get the number of fans. Callers must NOT hold - * applesmc_lock. + * applesmc_get_fan_count - get the number of fans. */ static int applesmc_get_fan_count(void) { int ret; u8 buffer[1]; - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(FANS_COUNT, buffer, 1); - mutex_unlock(&applesmc_lock); if (ret) return ret; else return buffer[0]; } +/* + * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent. + */ +static int applesmc_init_smcreg_try(void) +{ + struct applesmc_registers *s = &smcreg; + int ret; + + if (s->init_complete) + return 0; + + ret = read_register_count(&s->key_count); + if (ret) + return ret; + + if (!s->cache) + s->cache = kcalloc(s->key_count, sizeof(*s->cache), GFP_KERNEL); + if (!s->cache) + return -ENOMEM; + + s->init_complete = true; + + pr_info("key=%d\n", s->key_count); + + return 0; +} + +/* + * applesmc_init_smcreg - Initialize register cache. + * + * Retries until initialization is successful, or the operation times out. + * + */ +static int applesmc_init_smcreg(void) +{ + int ms, ret; + + for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) { + ret = applesmc_init_smcreg_try(); + if (!ret) { + if (ms) + pr_info("init_smcreg() took %d ms\n", ms); + return 0; + } + msleep(INIT_WAIT_MSECS); + } + + kfree(smcreg.cache); + smcreg.cache = NULL; + + return ret; +} + +static void applesmc_destroy_smcreg(void) +{ + kfree(smcreg.cache); + smcreg.cache = NULL; + smcreg.init_complete = false; +} + /* Device model stuff */ static int applesmc_probe(struct platform_device *dev) { + int ret; + + ret = applesmc_init_smcreg(); + if (ret) + return ret; + applesmc_device_init(); return 0; @@ -507,10 +649,8 @@ static int applesmc_probe(struct platform_device *dev) /* Synchronize device with memorized backlight state */ static int applesmc_pm_resume(struct device *dev) { - mutex_lock(&applesmc_lock); if (applesmc_light) applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2); - mutex_unlock(&applesmc_lock); return 0; } @@ -551,20 +691,15 @@ static void applesmc_idev_poll(struct input_polled_dev *dev) struct input_dev *idev = dev->input; s16 x, y; - mutex_lock(&applesmc_lock); - if (applesmc_read_motion_sensor(SENSOR_X, &x)) - goto out; + return; if (applesmc_read_motion_sensor(SENSOR_Y, &y)) - goto out; + return; x = -x; input_report_abs(idev, ABS_X, x - rest_x); input_report_abs(idev, ABS_Y, y - rest_y); input_sync(idev); - -out: - mutex_unlock(&applesmc_lock); } /* Sysfs Files */ @@ -581,8 +716,6 @@ static ssize_t applesmc_position_show(struct device *dev, int ret; s16 x, y, z; - mutex_lock(&applesmc_lock); - ret = applesmc_read_motion_sensor(SENSOR_X, &x); if (ret) goto out; @@ -594,7 +727,6 @@ static ssize_t applesmc_position_show(struct device *dev, goto out; out: - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -604,18 +736,19 @@ out: static ssize_t applesmc_light_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { + const struct applesmc_entry *entry; static int data_length; int ret; u8 left = 0, right = 0; - u8 buffer[10], query[6]; - - mutex_lock(&applesmc_lock); + u8 buffer[10]; if (!data_length) { - ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query); - if (ret) - goto out; - data_length = clamp_val(query[0], 0, 10); + entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY); + if (IS_ERR(entry)) + return PTR_ERR(entry); + if (entry->len > 10) + return -ENXIO; + data_length = entry->len; pr_info("light sensor data length set to %d\n", data_length); } @@ -632,7 +765,6 @@ static ssize_t applesmc_light_show(struct device *dev, right = buffer[2]; out: - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -661,14 +793,10 @@ static ssize_t applesmc_show_temperature(struct device *dev, const char* key = temperature_sensors_sets[applesmc_temperature_set][attr->index]; - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(key, buffer, 2); temp = buffer[0]*1000; temp += (buffer[1] >> 6) * 250; - mutex_unlock(&applesmc_lock); - if (ret) return ret; else @@ -691,12 +819,9 @@ static ssize_t applesmc_show_fan_speed(struct device *dev, newkey[3] = fan_speed_keys[sensor_attr->nr][3]; newkey[4] = 0; - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(newkey, buffer, 2); speed = ((buffer[0] << 8 | buffer[1]) >> 2); - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -725,13 +850,10 @@ static ssize_t applesmc_store_fan_speed(struct device *dev, newkey[3] = fan_speed_keys[sensor_attr->nr][3]; newkey[4] = 0; - mutex_lock(&applesmc_lock); - buffer[0] = (speed >> 6) & 0xff; buffer[1] = (speed << 2) & 0xff; ret = applesmc_write_key(newkey, buffer, 2); - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -746,12 +868,9 @@ static ssize_t applesmc_show_fan_manual(struct device *dev, u8 buffer[2]; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(FANS_MANUAL, buffer, 2); manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01; - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -770,8 +889,6 @@ static ssize_t applesmc_store_fan_manual(struct device *dev, input = simple_strtoul(sysfsbuf, NULL, 10); - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(FANS_MANUAL, buffer, 2); val = (buffer[0] << 8 | buffer[1]); if (ret) @@ -788,7 +905,6 @@ static ssize_t applesmc_store_fan_manual(struct device *dev, ret = applesmc_write_key(FANS_MANUAL, buffer, 2); out: - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -810,12 +926,9 @@ static ssize_t applesmc_show_fan_position(struct device *dev, newkey[3] = FAN_POSITION[3]; newkey[4] = 0; - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(newkey, buffer, 16); buffer[16] = 0; - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -831,18 +944,14 @@ static ssize_t applesmc_calibrate_show(struct device *dev, static ssize_t applesmc_calibrate_store(struct device *dev, struct device_attribute *attr, const char *sysfsbuf, size_t count) { - mutex_lock(&applesmc_lock); applesmc_calibrate(); - mutex_unlock(&applesmc_lock); return count; } static void applesmc_backlight_set(struct work_struct *work) { - mutex_lock(&applesmc_lock); applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2); - mutex_unlock(&applesmc_lock); } static DECLARE_WORK(backlight_work, &applesmc_backlight_set); @@ -865,13 +974,10 @@ static ssize_t applesmc_key_count_show(struct device *dev, u8 buffer[4]; u32 count; - mutex_lock(&applesmc_lock); - ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4); count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) + ((u32)buffer[2]<<8) + buffer[3]; - mutex_unlock(&applesmc_lock); if (ret) return ret; else @@ -881,113 +987,53 @@ static ssize_t applesmc_key_count_show(struct device *dev, static ssize_t applesmc_key_at_index_read_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { - char key[5]; - char info[6]; + const struct applesmc_entry *entry; int ret; - mutex_lock(&applesmc_lock); - - ret = applesmc_get_key_at_index(key_at_index, key); - - if (ret || !key[0]) { - mutex_unlock(&applesmc_lock); - - return -EINVAL; - } - - ret = applesmc_get_key_type(key, info); - - if (ret) { - mutex_unlock(&applesmc_lock); - + entry = applesmc_get_entry_by_index(key_at_index); + if (IS_ERR(entry)) + return PTR_ERR(entry); + ret = applesmc_read_entry(entry, sysfsbuf, entry->len); + if (ret) return ret; - } - /* - * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than - * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf. - */ - ret = applesmc_read_key(key, sysfsbuf, info[0]); - - mutex_unlock(&applesmc_lock); - - if (!ret) { - return info[0]; - } else { - return ret; - } + return entry->len; } static ssize_t applesmc_key_at_index_data_length_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { - char key[5]; - char info[6]; - int ret; - - mutex_lock(&applesmc_lock); + const struct applesmc_entry *entry; - ret = applesmc_get_key_at_index(key_at_index, key); + entry = applesmc_get_entry_by_index(key_at_index); + if (IS_ERR(entry)) + return PTR_ERR(entry); - if (ret || !key[0]) { - mutex_unlock(&applesmc_lock); - - return -EINVAL; - } - - ret = applesmc_get_key_type(key, info); - - mutex_unlock(&applesmc_lock); - - if (!ret) - return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]); - else - return ret; + return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len); } static ssize_t applesmc_key_at_index_type_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { - char key[5]; - char info[6]; - int ret; - - mutex_lock(&applesmc_lock); - - ret = applesmc_get_key_at_index(key_at_index, key); - - if (ret || !key[0]) { - mutex_unlock(&applesmc_lock); - - return -EINVAL; - } - - ret = applesmc_get_key_type(key, info); + const struct applesmc_entry *entry; - mutex_unlock(&applesmc_lock); + entry = applesmc_get_entry_by_index(key_at_index); + if (IS_ERR(entry)) + return PTR_ERR(entry); - if (!ret) - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1); - else - return ret; + return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type); } static ssize_t applesmc_key_at_index_name_show(struct device *dev, struct device_attribute *attr, char *sysfsbuf) { - char key[5]; - int ret; - - mutex_lock(&applesmc_lock); + const struct applesmc_entry *entry; - ret = applesmc_get_key_at_index(key_at_index, key); + entry = applesmc_get_entry_by_index(key_at_index); + if (IS_ERR(entry)) + return PTR_ERR(entry); - mutex_unlock(&applesmc_lock); - - if (!ret && key[0]) - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key); - else - return -EINVAL; + return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key); } static ssize_t applesmc_key_at_index_show(struct device *dev, @@ -999,12 +1045,13 @@ static ssize_t applesmc_key_at_index_show(struct device *dev, static ssize_t applesmc_key_at_index_store(struct device *dev, struct device_attribute *attr, const char *sysfsbuf, size_t count) { - mutex_lock(&applesmc_lock); + unsigned long newkey; - key_at_index = simple_strtoul(sysfsbuf, NULL, 10); - - mutex_unlock(&applesmc_lock); + if (strict_strtoul(sysfsbuf, 10, &newkey) < 0 + || newkey >= smcreg.key_count) + return -EINVAL; + key_at_index = newkey; return count; } @@ -1646,10 +1693,15 @@ static int __init applesmc_init(void) goto out_driver; } - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr); + /* create register cache */ + ret = applesmc_init_smcreg(); if (ret) goto out_device; + ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr); + if (ret) + goto out_smcreg; + /* Create key enumeration sysfs files */ ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group); if (ret) @@ -1751,6 +1803,8 @@ out_fans: sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); out_name: sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr); +out_smcreg: + applesmc_destroy_smcreg(); out_device: platform_device_unregister(pdev); out_driver: @@ -1779,6 +1833,7 @@ static void __exit applesmc_exit(void) &fan_attribute_groups[--fans_handled]); sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr); + applesmc_destroy_smcreg(); platform_device_unregister(pdev); platform_driver_unregister(&applesmc_driver); release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); -- cgit v1.2.3 From 9792dadfce22ae1518c88577ac743a3077a85084 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 10 Nov 2010 10:58:04 +0000 Subject: hwmon: (applesmc) Dynamic creation of temperature files The current driver creates temperature files based on a list of temperature keys given per device. Apart from slow adaption to new machine models, the number of sensors also depends on the number of processors. This patch looks up the temperature keys dynamically, thereby supporting all models. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 500 +++++++++++------------------------------------ 1 file changed, 111 insertions(+), 389 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index f213997adaec..03c24b7c9cbd 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -84,94 +84,6 @@ #define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */ #define FAN_POSITION "F0ID" /* r-o char[16] */ -/* - * Temperature sensors keys (sp78 - 2 bytes). - */ -static const char *temperature_sensors_sets[][41] = { -/* Set 0: Macbook Pro */ - { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H", - "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL }, -/* Set 1: Macbook2 set */ - { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H", - "Th0S", "Th1H", NULL }, -/* Set 2: Macbook set */ - { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S", - "Th1H", "Ts0P", NULL }, -/* Set 3: Macmini set */ - { "TC0D", "TC0P", NULL }, -/* Set 4: Mac Pro (2 x Quad-Core) */ - { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P", - "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P", - "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", - "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", - "TM9S", "TN0H", "TS0C", NULL }, -/* Set 5: iMac */ - { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P", - "Tp0C", NULL }, -/* Set 6: Macbook3 set */ - { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H", - "Th0S", "Th1H", NULL }, -/* Set 7: Macbook Air */ - { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP", - "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL }, -/* Set 8: Macbook Pro 4,1 (Penryn) */ - { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H", - "Th1H", "Th2H", "Tm0P", "Ts0P", NULL }, -/* Set 9: Macbook Pro 3,1 (Santa Rosa) */ - { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", - "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL }, -/* Set 10: iMac 5,1 */ - { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL }, -/* Set 11: Macbook 5,1 */ - { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P", - "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL }, -/* Set 12: Macbook Pro 5,1 */ - { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D", - "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0", - "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL }, -/* Set 13: iMac 8,1 */ - { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P", - "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL }, -/* Set 14: iMac 6,1 */ - { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P", - "TO0P", "Tp0P", NULL }, -/* Set 15: MacBook Air 2,1 */ - { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0", - "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P", - "Ts0S", NULL }, -/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */ - { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P", - "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P", - "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", - "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S", - "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S", - NULL }, -/* Set 17: iMac 9,1 */ - { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P", - "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL }, -/* Set 18: MacBook Pro 2,2 */ - { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0", - "Th0H", "Th1H", "Tm0P", "Ts0P", NULL }, -/* Set 19: Macbook Pro 5,3 */ - { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D", - "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H", - "Tm0P", "Ts0P", "Ts0S", NULL }, -/* Set 20: MacBook Pro 5,4 */ - { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D", - "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL }, -/* Set 21: MacBook Pro 6,2 */ - { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D", - "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P", - "Ts0P", "Ts0S", NULL }, -/* Set 22: MacBook Pro 7,1 */ - { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S", - "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL }, -/* Set 23: MacBook Air 3,1 */ - { "TB0T", "TB1T", "TB2T", "TC0D", "TC0E", "TC0P", "TC1E", "TCZ3", - "TCZ4", "TCZ5", "TG0E", "TG1E", "TG2E", "TGZ3", "TGZ4", "TGZ5", - "TH0F", "TH0O", "TM0P" }, -}; - /* List of keys used to read/write fan speeds */ static const char* fan_speed_keys[] = { FAN_ACTUAL_SPEED, @@ -192,6 +104,8 @@ static const char* fan_speed_keys[] = { #define SENSOR_Y 1 #define SENSOR_Z 2 +#define to_index(attr) (to_sensor_dev_attr(attr)->index) + /* Structure to be passed to DMI_MATCH function */ struct dmi_match_data { /* Indicates whether this computer has an accelerometer. */ @@ -202,6 +116,20 @@ struct dmi_match_data { int temperature_set; }; +/* Dynamic device node attributes */ +struct applesmc_dev_attr { + struct sensor_device_attribute sda; /* hwmon attributes */ + char name[32]; /* room for node file name */ +}; + +/* Dynamic device node group */ +struct applesmc_node_group { + char *format; /* format string */ + void *show; /* show function */ + void *store; /* store function */ + struct applesmc_dev_attr *nodes; /* dynamic node array */ +}; + /* AppleSMC entry - cached register information */ struct applesmc_entry { char key[5]; /* four-letter key code */ @@ -215,6 +143,9 @@ struct applesmc_entry { static struct applesmc_registers { struct mutex mutex; /* register read/write mutex */ unsigned int key_count; /* number of SMC registers */ + unsigned int temp_count; /* number of temperature registers */ + unsigned int temp_begin; /* temperature lower index bound */ + unsigned int temp_end; /* temperature upper index bound */ bool init_complete; /* true when fully initialized */ struct applesmc_entry *cache; /* cached key entries */ } smcreg = { @@ -239,9 +170,6 @@ static unsigned int applesmc_light; /* The number of fans handled by the driver */ static unsigned int fans_handled; -/* Indicates which temperature sensors set to use. */ -static unsigned int applesmc_temperature_set; - /* * Last index written to key_at_index sysfs file, and value to use for all other * key_at_index_* sysfs files. @@ -592,9 +520,17 @@ static int applesmc_init_smcreg_try(void) if (!s->cache) return -ENOMEM; + ret = applesmc_get_lower_bound(&s->temp_begin, "T"); + if (ret) + return ret; + ret = applesmc_get_lower_bound(&s->temp_end, "U"); + if (ret) + return ret; + s->temp_count = s->temp_end - s->temp_begin; + s->init_complete = true; - pr_info("key=%d\n", s->key_count); + pr_info("key=%d temp=%d\n", s->key_count, s->temp_count); return 0; } @@ -775,32 +711,38 @@ out: static ssize_t applesmc_show_sensor_label(struct device *dev, struct device_attribute *devattr, char *sysfsbuf) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - const char *key = - temperature_sensors_sets[applesmc_temperature_set][attr->index]; + int index = smcreg.temp_begin + to_index(devattr); + const struct applesmc_entry *entry; - return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key); + entry = applesmc_get_entry_by_index(index); + if (IS_ERR(entry)) + return PTR_ERR(entry); + + return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key); } /* Displays degree Celsius * 1000 */ static ssize_t applesmc_show_temperature(struct device *dev, struct device_attribute *devattr, char *sysfsbuf) { + int index = smcreg.temp_begin + to_index(devattr); + const struct applesmc_entry *entry; int ret; u8 buffer[2]; unsigned int temp; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - const char* key = - temperature_sensors_sets[applesmc_temperature_set][attr->index]; - ret = applesmc_read_key(key, buffer, 2); - temp = buffer[0]*1000; - temp += (buffer[1] >> 6) * 250; + entry = applesmc_get_entry_by_index(index); + if (IS_ERR(entry)) + return PTR_ERR(entry); + ret = applesmc_read_entry(entry, buffer, 2); if (ret) return ret; - else - return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp); + + temp = buffer[0]*1000; + temp += (buffer[1] >> 6) * 250; + + return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp); } static ssize_t applesmc_show_fan_speed(struct device *dev, @@ -1161,263 +1103,10 @@ static const struct attribute_group fan_attribute_groups[] = { { .attrs = fan4_attributes }, }; -/* - * Temperature sensors sysfs entries. - */ -static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 1); -static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 2); -static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 3); -static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 4); -static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 5); -static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 6); -static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 7); -static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 8); -static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 9); -static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 10); -static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 11); -static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 12); -static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 13); -static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 14); -static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 15); -static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 16); -static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 17); -static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 18); -static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 19); -static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 20); -static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 21); -static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 22); -static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 23); -static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 24); -static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 25); -static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 26); -static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 27); -static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 28); -static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 29); -static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 30); -static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 31); -static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 32); -static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 33); -static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 34); -static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 35); -static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 36); -static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 37); -static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 38); -static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO, - applesmc_show_sensor_label, NULL, 39); -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, - applesmc_show_temperature, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, - applesmc_show_temperature, NULL, 1); -static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, - applesmc_show_temperature, NULL, 2); -static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, - applesmc_show_temperature, NULL, 3); -static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, - applesmc_show_temperature, NULL, 4); -static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, - applesmc_show_temperature, NULL, 5); -static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, - applesmc_show_temperature, NULL, 6); -static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, - applesmc_show_temperature, NULL, 7); -static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, - applesmc_show_temperature, NULL, 8); -static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, - applesmc_show_temperature, NULL, 9); -static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, - applesmc_show_temperature, NULL, 10); -static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, - applesmc_show_temperature, NULL, 11); -static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, - applesmc_show_temperature, NULL, 12); -static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, - applesmc_show_temperature, NULL, 13); -static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, - applesmc_show_temperature, NULL, 14); -static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO, - applesmc_show_temperature, NULL, 15); -static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO, - applesmc_show_temperature, NULL, 16); -static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO, - applesmc_show_temperature, NULL, 17); -static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO, - applesmc_show_temperature, NULL, 18); -static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO, - applesmc_show_temperature, NULL, 19); -static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO, - applesmc_show_temperature, NULL, 20); -static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO, - applesmc_show_temperature, NULL, 21); -static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO, - applesmc_show_temperature, NULL, 22); -static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO, - applesmc_show_temperature, NULL, 23); -static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO, - applesmc_show_temperature, NULL, 24); -static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO, - applesmc_show_temperature, NULL, 25); -static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO, - applesmc_show_temperature, NULL, 26); -static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO, - applesmc_show_temperature, NULL, 27); -static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO, - applesmc_show_temperature, NULL, 28); -static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO, - applesmc_show_temperature, NULL, 29); -static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO, - applesmc_show_temperature, NULL, 30); -static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO, - applesmc_show_temperature, NULL, 31); -static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO, - applesmc_show_temperature, NULL, 32); -static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO, - applesmc_show_temperature, NULL, 33); -static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO, - applesmc_show_temperature, NULL, 34); -static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO, - applesmc_show_temperature, NULL, 35); -static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO, - applesmc_show_temperature, NULL, 36); -static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO, - applesmc_show_temperature, NULL, 37); -static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO, - applesmc_show_temperature, NULL, 38); -static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO, - applesmc_show_temperature, NULL, 39); - -static struct attribute *label_attributes[] = { - &sensor_dev_attr_temp1_label.dev_attr.attr, - &sensor_dev_attr_temp2_label.dev_attr.attr, - &sensor_dev_attr_temp3_label.dev_attr.attr, - &sensor_dev_attr_temp4_label.dev_attr.attr, - &sensor_dev_attr_temp5_label.dev_attr.attr, - &sensor_dev_attr_temp6_label.dev_attr.attr, - &sensor_dev_attr_temp7_label.dev_attr.attr, - &sensor_dev_attr_temp8_label.dev_attr.attr, - &sensor_dev_attr_temp9_label.dev_attr.attr, - &sensor_dev_attr_temp10_label.dev_attr.attr, - &sensor_dev_attr_temp11_label.dev_attr.attr, - &sensor_dev_attr_temp12_label.dev_attr.attr, - &sensor_dev_attr_temp13_label.dev_attr.attr, - &sensor_dev_attr_temp14_label.dev_attr.attr, - &sensor_dev_attr_temp15_label.dev_attr.attr, - &sensor_dev_attr_temp16_label.dev_attr.attr, - &sensor_dev_attr_temp17_label.dev_attr.attr, - &sensor_dev_attr_temp18_label.dev_attr.attr, - &sensor_dev_attr_temp19_label.dev_attr.attr, - &sensor_dev_attr_temp20_label.dev_attr.attr, - &sensor_dev_attr_temp21_label.dev_attr.attr, - &sensor_dev_attr_temp22_label.dev_attr.attr, - &sensor_dev_attr_temp23_label.dev_attr.attr, - &sensor_dev_attr_temp24_label.dev_attr.attr, - &sensor_dev_attr_temp25_label.dev_attr.attr, - &sensor_dev_attr_temp26_label.dev_attr.attr, - &sensor_dev_attr_temp27_label.dev_attr.attr, - &sensor_dev_attr_temp28_label.dev_attr.attr, - &sensor_dev_attr_temp29_label.dev_attr.attr, - &sensor_dev_attr_temp30_label.dev_attr.attr, - &sensor_dev_attr_temp31_label.dev_attr.attr, - &sensor_dev_attr_temp32_label.dev_attr.attr, - &sensor_dev_attr_temp33_label.dev_attr.attr, - &sensor_dev_attr_temp34_label.dev_attr.attr, - &sensor_dev_attr_temp35_label.dev_attr.attr, - &sensor_dev_attr_temp36_label.dev_attr.attr, - &sensor_dev_attr_temp37_label.dev_attr.attr, - &sensor_dev_attr_temp38_label.dev_attr.attr, - &sensor_dev_attr_temp39_label.dev_attr.attr, - &sensor_dev_attr_temp40_label.dev_attr.attr, - NULL -}; - -static struct attribute *temperature_attributes[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, - &sensor_dev_attr_temp5_input.dev_attr.attr, - &sensor_dev_attr_temp6_input.dev_attr.attr, - &sensor_dev_attr_temp7_input.dev_attr.attr, - &sensor_dev_attr_temp8_input.dev_attr.attr, - &sensor_dev_attr_temp9_input.dev_attr.attr, - &sensor_dev_attr_temp10_input.dev_attr.attr, - &sensor_dev_attr_temp11_input.dev_attr.attr, - &sensor_dev_attr_temp12_input.dev_attr.attr, - &sensor_dev_attr_temp13_input.dev_attr.attr, - &sensor_dev_attr_temp14_input.dev_attr.attr, - &sensor_dev_attr_temp15_input.dev_attr.attr, - &sensor_dev_attr_temp16_input.dev_attr.attr, - &sensor_dev_attr_temp17_input.dev_attr.attr, - &sensor_dev_attr_temp18_input.dev_attr.attr, - &sensor_dev_attr_temp19_input.dev_attr.attr, - &sensor_dev_attr_temp20_input.dev_attr.attr, - &sensor_dev_attr_temp21_input.dev_attr.attr, - &sensor_dev_attr_temp22_input.dev_attr.attr, - &sensor_dev_attr_temp23_input.dev_attr.attr, - &sensor_dev_attr_temp24_input.dev_attr.attr, - &sensor_dev_attr_temp25_input.dev_attr.attr, - &sensor_dev_attr_temp26_input.dev_attr.attr, - &sensor_dev_attr_temp27_input.dev_attr.attr, - &sensor_dev_attr_temp28_input.dev_attr.attr, - &sensor_dev_attr_temp29_input.dev_attr.attr, - &sensor_dev_attr_temp30_input.dev_attr.attr, - &sensor_dev_attr_temp31_input.dev_attr.attr, - &sensor_dev_attr_temp32_input.dev_attr.attr, - &sensor_dev_attr_temp33_input.dev_attr.attr, - &sensor_dev_attr_temp34_input.dev_attr.attr, - &sensor_dev_attr_temp35_input.dev_attr.attr, - &sensor_dev_attr_temp36_input.dev_attr.attr, - &sensor_dev_attr_temp37_input.dev_attr.attr, - &sensor_dev_attr_temp38_input.dev_attr.attr, - &sensor_dev_attr_temp39_input.dev_attr.attr, - &sensor_dev_attr_temp40_input.dev_attr.attr, - NULL -}; - -static const struct attribute_group temperature_attributes_group = - { .attrs = temperature_attributes }; - -static const struct attribute_group label_attributes_group = { - .attrs = label_attributes +static struct applesmc_node_group temp_group[] = { + { "temp%d_label", applesmc_show_sensor_label }, + { "temp%d_input", applesmc_show_temperature }, + { } }; /* Module stuff */ @@ -1427,7 +1116,6 @@ static const struct attribute_group label_attributes_group = { */ static int applesmc_dmi_match(const struct dmi_system_id *id) { - int i = 0; struct dmi_match_data* dmi_data = id->driver_data; pr_info("%s detected:\n", id->ident); applesmc_accelerometer = dmi_data->accelerometer; @@ -1437,13 +1125,65 @@ static int applesmc_dmi_match(const struct dmi_system_id *id) pr_info(" - Model %s light sensors and backlight\n", applesmc_light ? "with" : "without"); - applesmc_temperature_set = dmi_data->temperature_set; - while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL) - i++; - pr_info(" - Model with %d temperature sensors\n", i); return 1; } +/* + * applesmc_destroy_nodes - remove files and free associated memory + */ +static void applesmc_destroy_nodes(struct applesmc_node_group *groups) +{ + struct applesmc_node_group *grp; + struct applesmc_dev_attr *node; + + for (grp = groups; grp->nodes; grp++) { + for (node = grp->nodes; node->sda.dev_attr.attr.name; node++) + sysfs_remove_file(&pdev->dev.kobj, + &node->sda.dev_attr.attr); + kfree(grp->nodes); + grp->nodes = NULL; + } +} + +/* + * applesmc_create_nodes - create a two-dimensional group of sysfs files + */ +static int applesmc_create_nodes(struct applesmc_node_group *groups, int num) +{ + struct applesmc_node_group *grp; + struct applesmc_dev_attr *node; + struct attribute *attr; + int ret, i; + + for (grp = groups; grp->format; grp++) { + grp->nodes = kcalloc(num + 1, sizeof(*node), GFP_KERNEL); + if (!grp->nodes) { + ret = -ENOMEM; + goto out; + } + for (i = 0; i < num; i++) { + node = &grp->nodes[i]; + sprintf(node->name, grp->format, i + 1); + node->sda.index = i; + node->sda.dev_attr.show = grp->show; + node->sda.dev_attr.store = grp->store; + attr = &node->sda.dev_attr.attr; + attr->name = node->name; + attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0); + ret = sysfs_create_file(&pdev->dev.kobj, attr); + if (ret) { + attr->name = NULL; + goto out; + } + } + } + + return 0; +out: + applesmc_destroy_nodes(groups); + return ret; +} + /* Create accelerometer ressources */ static int applesmc_create_accelerometer(void) { @@ -1668,7 +1408,6 @@ static int __init applesmc_init(void) { int ret; int count; - int i; if (!dmi_check_system(applesmc_whitelist)) { pr_warn("supported laptop not found!\n"); @@ -1727,24 +1466,9 @@ static int __init applesmc_init(void) fans_handled++; } - for (i = 0; - temperature_sensors_sets[applesmc_temperature_set][i] != NULL; - i++) { - if (temperature_attributes[i] == NULL || - label_attributes[i] == NULL) { - pr_err("More temperature sensors in temperature_sensors_sets (at least %i) than available sysfs files in temperature_attributes (%i), please report this bug\n", - i, i-1); - goto out_temperature; - } - ret = sysfs_create_file(&pdev->dev.kobj, - temperature_attributes[i]); - if (ret) - goto out_temperature; - ret = sysfs_create_file(&pdev->dev.kobj, - label_attributes[i]); - if (ret) - goto out_temperature; - } + ret = applesmc_create_nodes(temp_group, smcreg.temp_count); + if (ret) + goto out_fans; if (applesmc_accelerometer) { ret = applesmc_create_accelerometer(); @@ -1794,8 +1518,7 @@ out_accelerometer: if (applesmc_accelerometer) applesmc_release_accelerometer(); out_temperature: - sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group); - sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group); + applesmc_destroy_nodes(temp_group); out_fans: while (fans_handled) sysfs_remove_group(&pdev->dev.kobj, @@ -1826,8 +1549,7 @@ static void __exit applesmc_exit(void) } if (applesmc_accelerometer) applesmc_release_accelerometer(); - sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group); - sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group); + applesmc_destroy_nodes(temp_group); while (fans_handled) sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[--fans_handled]); -- cgit v1.2.3 From dcdea2614ab9b7864a3ae620419d04e0cc4a65cc Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 9 Nov 2010 15:15:06 +0000 Subject: hwmon: (applesmc) Handle new temperature format The recent Macbooks have temperature registers of a new type. This patch adds the logic to handle them. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 03c24b7c9cbd..1d7f8aff9982 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -734,13 +734,19 @@ static ssize_t applesmc_show_temperature(struct device *dev, entry = applesmc_get_entry_by_index(index); if (IS_ERR(entry)) return PTR_ERR(entry); + if (entry->len > 2) + return -EINVAL; - ret = applesmc_read_entry(entry, buffer, 2); + ret = applesmc_read_entry(entry, buffer, entry->len); if (ret) return ret; - temp = buffer[0]*1000; - temp += (buffer[1] >> 6) * 250; + if (entry->len == 2) { + temp = buffer[0] * 1000; + temp += (buffer[1] >> 6) * 250; + } else { + temp = buffer[0] * 4000; + } return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp); } -- cgit v1.2.3 From 40ef06f1120bcc0a2ad483b5cd42f58c4df78a5b Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 10 Nov 2010 10:58:05 +0000 Subject: hwmon: (applesmc) Extract all features generically With temperature keys being determined automatically, the dmi match data is only used to assign features that can easily be detected from the smc. This patch removes the dmi match data altogether, and reduces the match table to the main machine models. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 241 ++++++++++++----------------------------------- 1 file changed, 59 insertions(+), 182 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 1d7f8aff9982..d4d647522331 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -106,16 +106,6 @@ static const char* fan_speed_keys[] = { #define to_index(attr) (to_sensor_dev_attr(attr)->index) -/* Structure to be passed to DMI_MATCH function */ -struct dmi_match_data { -/* Indicates whether this computer has an accelerometer. */ - int accelerometer; -/* Indicates whether this computer has light sensors and keyboard backlight. */ - int light; -/* Indicates which temperature sensors set to use. */ - int temperature_set; -}; - /* Dynamic device node attributes */ struct applesmc_dev_attr { struct sensor_device_attribute sda; /* hwmon attributes */ @@ -146,6 +136,9 @@ static struct applesmc_registers { unsigned int temp_count; /* number of temperature registers */ unsigned int temp_begin; /* temperature lower index bound */ unsigned int temp_end; /* temperature upper index bound */ + int num_light_sensors; /* number of light sensors */ + bool has_accelerometer; /* has motion sensor */ + bool has_key_backlight; /* has keyboard backlight */ bool init_complete; /* true when fully initialized */ struct applesmc_entry *cache; /* cached key entries */ } smcreg = { @@ -161,12 +154,6 @@ static u8 backlight_state[2]; static struct device *hwmon_dev; static struct input_polled_dev *applesmc_idev; -/* Indicates whether this computer has an accelerometer. */ -static unsigned int applesmc_accelerometer; - -/* Indicates whether this computer has light sensors and keyboard backlight. */ -static unsigned int applesmc_light; - /* The number of fans handled by the driver */ static unsigned int fans_handled; @@ -433,6 +420,18 @@ static int applesmc_write_key(const char *key, const u8 *buffer, u8 len) return applesmc_write_entry(entry, buffer, len); } +static int applesmc_has_key(const char *key, bool *value) +{ + const struct applesmc_entry *entry; + + entry = applesmc_get_entry_by_key(key); + if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL) + return PTR_ERR(entry); + + *value = !IS_ERR(entry); + return 0; +} + /* * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). */ @@ -468,7 +467,7 @@ static void applesmc_device_init(void) int total; u8 buffer[2]; - if (!applesmc_accelerometer) + if (!smcreg.has_accelerometer) return; for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) { @@ -506,6 +505,7 @@ static int applesmc_get_fan_count(void) static int applesmc_init_smcreg_try(void) { struct applesmc_registers *s = &smcreg; + bool left_light_sensor, right_light_sensor; int ret; if (s->init_complete) @@ -528,9 +528,27 @@ static int applesmc_init_smcreg_try(void) return ret; s->temp_count = s->temp_end - s->temp_begin; + ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor); + if (ret) + return ret; + ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor); + if (ret) + return ret; + ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer); + if (ret) + return ret; + ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight); + if (ret) + return ret; + + s->num_light_sensors = left_light_sensor + right_light_sensor; s->init_complete = true; - pr_info("key=%d temp=%d\n", s->key_count, s->temp_count); + pr_info("key=%d temp=%d acc=%d lux=%d kbd=%d\n", + s->key_count, s->temp_count, + s->has_accelerometer, + s->num_light_sensors, + s->has_key_backlight); return 0; } @@ -585,7 +603,7 @@ static int applesmc_probe(struct platform_device *dev) /* Synchronize device with memorized backlight state */ static int applesmc_pm_resume(struct device *dev) { - if (applesmc_light) + if (smcreg.has_key_backlight) applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2); return 0; } @@ -1117,23 +1135,6 @@ static struct applesmc_node_group temp_group[] = { /* Module stuff */ -/* - * applesmc_dmi_match - found a match. return one, short-circuiting the hunt. - */ -static int applesmc_dmi_match(const struct dmi_system_id *id) -{ - struct dmi_match_data* dmi_data = id->driver_data; - pr_info("%s detected:\n", id->ident); - applesmc_accelerometer = dmi_data->accelerometer; - pr_info(" - Model %s accelerometer\n", - applesmc_accelerometer ? "with" : "without"); - applesmc_light = dmi_data->light; - pr_info(" - Model %s light sensors and backlight\n", - applesmc_light ? "with" : "without"); - - return 1; -} - /* * applesmc_destroy_nodes - remove files and free associated memory */ @@ -1248,165 +1249,38 @@ static void applesmc_release_accelerometer(void) input_free_polled_device(applesmc_idev); sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); } - -static __initdata struct dmi_match_data applesmc_dmi_data[] = { -/* MacBook Pro: accelerometer, backlight and temperature set 0 */ - { .accelerometer = 1, .light = 1, .temperature_set = 0 }, -/* MacBook2: accelerometer and temperature set 1 */ - { .accelerometer = 1, .light = 0, .temperature_set = 1 }, -/* MacBook: accelerometer and temperature set 2 */ - { .accelerometer = 1, .light = 0, .temperature_set = 2 }, -/* MacMini: temperature set 3 */ - { .accelerometer = 0, .light = 0, .temperature_set = 3 }, -/* MacPro: temperature set 4 */ - { .accelerometer = 0, .light = 0, .temperature_set = 4 }, -/* iMac: temperature set 5 */ - { .accelerometer = 0, .light = 0, .temperature_set = 5 }, -/* MacBook3, MacBook4: accelerometer and temperature set 6 */ - { .accelerometer = 1, .light = 0, .temperature_set = 6 }, -/* MacBook Air: accelerometer, backlight and temperature set 7 */ - { .accelerometer = 1, .light = 1, .temperature_set = 7 }, -/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */ - { .accelerometer = 1, .light = 1, .temperature_set = 8 }, -/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */ - { .accelerometer = 1, .light = 1, .temperature_set = 9 }, -/* iMac 5: light sensor only, temperature set 10 */ - { .accelerometer = 0, .light = 0, .temperature_set = 10 }, -/* MacBook 5: accelerometer, backlight and temperature set 11 */ - { .accelerometer = 1, .light = 1, .temperature_set = 11 }, -/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */ - { .accelerometer = 1, .light = 1, .temperature_set = 12 }, -/* iMac 8: light sensor only, temperature set 13 */ - { .accelerometer = 0, .light = 0, .temperature_set = 13 }, -/* iMac 6: light sensor only, temperature set 14 */ - { .accelerometer = 0, .light = 0, .temperature_set = 14 }, -/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */ - { .accelerometer = 1, .light = 1, .temperature_set = 15 }, -/* MacPro3,1: temperature set 16 */ - { .accelerometer = 0, .light = 0, .temperature_set = 16 }, -/* iMac 9,1: light sensor only, temperature set 17 */ - { .accelerometer = 0, .light = 0, .temperature_set = 17 }, -/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */ - { .accelerometer = 1, .light = 1, .temperature_set = 18 }, -/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */ - { .accelerometer = 1, .light = 1, .temperature_set = 19 }, -/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */ - { .accelerometer = 1, .light = 1, .temperature_set = 20 }, -/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */ - { .accelerometer = 1, .light = 1, .temperature_set = 21 }, -/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */ - { .accelerometer = 1, .light = 1, .temperature_set = 22 }, -/* MacBook Air 3,1: accelerometer, backlight and temperature set 23 */ - { .accelerometer = 0, .light = 0, .temperature_set = 23 }, -}; +static int applesmc_dmi_match(const struct dmi_system_id *id) +{ + return 1; +} /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ static __initdata struct dmi_system_id applesmc_whitelist[] = { - { applesmc_dmi_match, "Apple MacBook Air 3", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3") }, - &applesmc_dmi_data[23]}, - { applesmc_dmi_match, "Apple MacBook Air 2", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") }, - &applesmc_dmi_data[15]}, { applesmc_dmi_match, "Apple MacBook Air", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") }, - &applesmc_dmi_data[7]}, - { applesmc_dmi_match, "Apple MacBook Pro 7", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") }, - &applesmc_dmi_data[22]}, - { applesmc_dmi_match, "Apple MacBook Pro 5,4", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") }, - &applesmc_dmi_data[20]}, - { applesmc_dmi_match, "Apple MacBook Pro 5,3", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") }, - &applesmc_dmi_data[19]}, - { applesmc_dmi_match, "Apple MacBook Pro 6", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") }, - &applesmc_dmi_data[21]}, - { applesmc_dmi_match, "Apple MacBook Pro 5", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") }, - &applesmc_dmi_data[12]}, - { applesmc_dmi_match, "Apple MacBook Pro 4", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") }, - &applesmc_dmi_data[8]}, - { applesmc_dmi_match, "Apple MacBook Pro 3", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") }, - &applesmc_dmi_data[9]}, - { applesmc_dmi_match, "Apple MacBook Pro 2,2", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") }, - &applesmc_dmi_data[18]}, + }, { applesmc_dmi_match, "Apple MacBook Pro", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") }, - &applesmc_dmi_data[0]}, - { applesmc_dmi_match, "Apple MacBook (v2)", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") }, - &applesmc_dmi_data[1]}, - { applesmc_dmi_match, "Apple MacBook (v3)", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") }, - &applesmc_dmi_data[6]}, - { applesmc_dmi_match, "Apple MacBook 4", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") }, - &applesmc_dmi_data[6]}, - { applesmc_dmi_match, "Apple MacBook 5", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") }, - &applesmc_dmi_data[11]}, + }, { applesmc_dmi_match, "Apple MacBook", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") }, - &applesmc_dmi_data[2]}, + }, { applesmc_dmi_match, "Apple Macmini", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") }, - &applesmc_dmi_data[3]}, - { applesmc_dmi_match, "Apple MacPro2", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") }, - &applesmc_dmi_data[4]}, - { applesmc_dmi_match, "Apple MacPro3", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") }, - &applesmc_dmi_data[16]}, + }, { applesmc_dmi_match, "Apple MacPro", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") }, - &applesmc_dmi_data[4]}, - { applesmc_dmi_match, "Apple iMac 9,1", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") }, - &applesmc_dmi_data[17]}, - { applesmc_dmi_match, "Apple iMac 8", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") }, - &applesmc_dmi_data[13]}, - { applesmc_dmi_match, "Apple iMac 6", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") }, - &applesmc_dmi_data[14]}, - { applesmc_dmi_match, "Apple iMac 5", { - DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), - DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") }, - &applesmc_dmi_data[10]}, + }, { applesmc_dmi_match, "Apple iMac", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"iMac") }, - &applesmc_dmi_data[5]}, + }, { .ident = NULL } }; @@ -1476,18 +1350,20 @@ static int __init applesmc_init(void) if (ret) goto out_fans; - if (applesmc_accelerometer) { + if (smcreg.has_accelerometer) { ret = applesmc_create_accelerometer(); if (ret) goto out_temperature; } - if (applesmc_light) { + if (smcreg.num_light_sensors) { /* Add light sensor file */ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr); if (ret) goto out_accelerometer; + } + if (smcreg.has_key_backlight) { /* Create the workqueue */ applesmc_led_wq = create_singlethread_workqueue("applesmc-led"); if (!applesmc_led_wq) { @@ -1512,16 +1388,16 @@ static int __init applesmc_init(void) return 0; out_light_ledclass: - if (applesmc_light) + if (smcreg.has_key_backlight) led_classdev_unregister(&applesmc_backlight); out_light_wq: - if (applesmc_light) + if (smcreg.has_key_backlight) destroy_workqueue(applesmc_led_wq); out_light_sysfs: - if (applesmc_light) + if (smcreg.num_light_sensors) sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); out_accelerometer: - if (applesmc_accelerometer) + if (smcreg.has_accelerometer) applesmc_release_accelerometer(); out_temperature: applesmc_destroy_nodes(temp_group); @@ -1548,12 +1424,13 @@ out: static void __exit applesmc_exit(void) { hwmon_device_unregister(hwmon_dev); - if (applesmc_light) { + if (smcreg.has_key_backlight) { led_classdev_unregister(&applesmc_backlight); destroy_workqueue(applesmc_led_wq); - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); } - if (applesmc_accelerometer) + if (smcreg.num_light_sensors) + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); + if (smcreg.has_accelerometer) applesmc_release_accelerometer(); applesmc_destroy_nodes(temp_group); while (fans_handled) -- cgit v1.2.3 From 3eba2bf7c5fb7863412554cd73646cb80ac293ff Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 9 Nov 2010 15:15:08 +0000 Subject: hwmon: (applesmc) Dynamic creation of fan files With the dynamic temperature group in place, the setup of fans can be simplified. This patch sets up the fans dynamically, removing a hundred lines of code. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 188 +++++++++++------------------------------------ 1 file changed, 43 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index d4d647522331..b0792361c52e 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -77,20 +77,15 @@ #define FANS_COUNT "FNum" /* r-o ui8 */ #define FANS_MANUAL "FS! " /* r-w ui16 */ -#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */ -#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */ -#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */ -#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */ -#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */ -#define FAN_POSITION "F0ID" /* r-o char[16] */ +#define FAN_ID_FMT "F%dID" /* r-o char[16] */ /* List of keys used to read/write fan speeds */ -static const char* fan_speed_keys[] = { - FAN_ACTUAL_SPEED, - FAN_MIN_SPEED, - FAN_MAX_SPEED, - FAN_SAFE_SPEED, - FAN_TARGET_SPEED +static const char *const fan_speed_fmt[] = { + "F%dAc", /* actual speed */ + "F%dMn", /* minimum speed (rw) */ + "F%dMx", /* maximum speed */ + "F%dSf", /* safe speed - not all models */ + "F%dTg", /* target speed (manual: rw) */ }; #define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */ @@ -104,7 +99,8 @@ static const char* fan_speed_keys[] = { #define SENSOR_Y 1 #define SENSOR_Z 2 -#define to_index(attr) (to_sensor_dev_attr(attr)->index) +#define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff) +#define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16) /* Dynamic device node attributes */ struct applesmc_dev_attr { @@ -117,6 +113,7 @@ struct applesmc_node_group { char *format; /* format string */ void *show; /* show function */ void *store; /* store function */ + int option; /* function argument */ struct applesmc_dev_attr *nodes; /* dynamic node array */ }; @@ -133,6 +130,7 @@ struct applesmc_entry { static struct applesmc_registers { struct mutex mutex; /* register read/write mutex */ unsigned int key_count; /* number of SMC registers */ + unsigned int fan_count; /* number of fans */ unsigned int temp_count; /* number of temperature registers */ unsigned int temp_begin; /* temperature lower index bound */ unsigned int temp_end; /* temperature upper index bound */ @@ -154,9 +152,6 @@ static u8 backlight_state[2]; static struct device *hwmon_dev; static struct input_polled_dev *applesmc_idev; -/* The number of fans handled by the driver */ -static unsigned int fans_handled; - /* * Last index written to key_at_index sysfs file, and value to use for all other * key_at_index_* sysfs files. @@ -483,22 +478,6 @@ static void applesmc_device_init(void) pr_warn("failed to init the device\n"); } -/* - * applesmc_get_fan_count - get the number of fans. - */ -static int applesmc_get_fan_count(void) -{ - int ret; - u8 buffer[1]; - - ret = applesmc_read_key(FANS_COUNT, buffer, 1); - - if (ret) - return ret; - else - return buffer[0]; -} - /* * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent. */ @@ -506,6 +485,7 @@ static int applesmc_init_smcreg_try(void) { struct applesmc_registers *s = &smcreg; bool left_light_sensor, right_light_sensor; + u8 tmp[1]; int ret; if (s->init_complete) @@ -520,6 +500,11 @@ static int applesmc_init_smcreg_try(void) if (!s->cache) return -ENOMEM; + ret = applesmc_read_key(FANS_COUNT, tmp, 1); + if (ret) + return ret; + s->fan_count = tmp[0]; + ret = applesmc_get_lower_bound(&s->temp_begin, "T"); if (ret) return ret; @@ -544,8 +529,8 @@ static int applesmc_init_smcreg_try(void) s->num_light_sensors = left_light_sensor + right_light_sensor; s->init_complete = true; - pr_info("key=%d temp=%d acc=%d lux=%d kbd=%d\n", - s->key_count, s->temp_count, + pr_info("key=%d fan=%d temp=%d acc=%d lux=%d kbd=%d\n", + s->key_count, s->fan_count, s->temp_count, s->has_accelerometer, s->num_light_sensors, s->has_key_backlight); @@ -776,14 +761,8 @@ static ssize_t applesmc_show_fan_speed(struct device *dev, unsigned int speed = 0; char newkey[5]; u8 buffer[2]; - struct sensor_device_attribute_2 *sensor_attr = - to_sensor_dev_attr_2(attr); - newkey[0] = fan_speed_keys[sensor_attr->nr][0]; - newkey[1] = '0' + sensor_attr->index; - newkey[2] = fan_speed_keys[sensor_attr->nr][2]; - newkey[3] = fan_speed_keys[sensor_attr->nr][3]; - newkey[4] = 0; + sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr)); ret = applesmc_read_key(newkey, buffer, 2); speed = ((buffer[0] << 8 | buffer[1]) >> 2); @@ -802,19 +781,13 @@ static ssize_t applesmc_store_fan_speed(struct device *dev, u32 speed; char newkey[5]; u8 buffer[2]; - struct sensor_device_attribute_2 *sensor_attr = - to_sensor_dev_attr_2(attr); speed = simple_strtoul(sysfsbuf, NULL, 10); if (speed > 0x4000) /* Bigger than a 14-bit value */ return -EINVAL; - newkey[0] = fan_speed_keys[sensor_attr->nr][0]; - newkey[1] = '0' + sensor_attr->index; - newkey[2] = fan_speed_keys[sensor_attr->nr][2]; - newkey[3] = fan_speed_keys[sensor_attr->nr][3]; - newkey[4] = 0; + sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr)); buffer[0] = (speed >> 6) & 0xff; buffer[1] = (speed << 2) & 0xff; @@ -827,15 +800,14 @@ static ssize_t applesmc_store_fan_speed(struct device *dev, } static ssize_t applesmc_show_fan_manual(struct device *dev, - struct device_attribute *devattr, char *sysfsbuf) + struct device_attribute *attr, char *sysfsbuf) { int ret; u16 manual = 0; u8 buffer[2]; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ret = applesmc_read_key(FANS_MANUAL, buffer, 2); - manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01; + manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01; if (ret) return ret; @@ -844,14 +816,13 @@ static ssize_t applesmc_show_fan_manual(struct device *dev, } static ssize_t applesmc_store_fan_manual(struct device *dev, - struct device_attribute *devattr, + struct device_attribute *attr, const char *sysfsbuf, size_t count) { int ret; u8 buffer[2]; u32 input; u16 val; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); input = simple_strtoul(sysfsbuf, NULL, 10); @@ -861,9 +832,9 @@ static ssize_t applesmc_store_fan_manual(struct device *dev, goto out; if (input) - val = val | (0x01 << attr->index); + val = val | (0x01 << to_index(attr)); else - val = val & ~(0x01 << attr->index); + val = val & ~(0x01 << to_index(attr)); buffer[0] = (val >> 8) & 0xFF; buffer[1] = val & 0xFF; @@ -883,14 +854,8 @@ static ssize_t applesmc_show_fan_position(struct device *dev, int ret; char newkey[5]; u8 buffer[17]; - struct sensor_device_attribute_2 *sensor_attr = - to_sensor_dev_attr_2(attr); - newkey[0] = FAN_POSITION[0]; - newkey[1] = '0' + sensor_attr->index; - newkey[2] = FAN_POSITION[2]; - newkey[3] = FAN_POSITION[3]; - newkey[4] = 0; + sprintf(newkey, FAN_ID_FMT, to_index(attr)); ret = applesmc_read_key(newkey, buffer, 16); buffer[16] = 0; @@ -1069,62 +1034,15 @@ static struct attribute *key_enumeration_attributes[] = { static const struct attribute_group key_enumeration_group = { .attrs = key_enumeration_attributes }; -/* - * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries. - * - show actual speed - * - show/store minimum speed - * - show maximum speed - * - show safe speed - * - show/store target speed - * - show/store manual mode - */ -#define sysfs_fan_speeds_offset(offset) \ -static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \ - applesmc_show_fan_speed, NULL, 0, offset-1); \ -\ -static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \ - applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \ -\ -static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \ - applesmc_show_fan_speed, NULL, 2, offset-1); \ -\ -static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \ - applesmc_show_fan_speed, NULL, 3, offset-1); \ -\ -static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \ - applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \ -\ -static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \ - applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \ -\ -static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \ - applesmc_show_fan_position, NULL, offset-1); \ -\ -static struct attribute *fan##offset##_attributes[] = { \ - &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \ - &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \ - &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \ - &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \ - &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \ - &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \ - &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \ - NULL \ -}; - -/* - * Create the needed functions for each fan using the macro defined above - * (4 fans are supported) - */ -sysfs_fan_speeds_offset(1); -sysfs_fan_speeds_offset(2); -sysfs_fan_speeds_offset(3); -sysfs_fan_speeds_offset(4); - -static const struct attribute_group fan_attribute_groups[] = { - { .attrs = fan1_attributes }, - { .attrs = fan2_attributes }, - { .attrs = fan3_attributes }, - { .attrs = fan4_attributes }, +static struct applesmc_node_group fan_group[] = { + { "fan%d_label", applesmc_show_fan_position }, + { "fan%d_input", applesmc_show_fan_speed, NULL, 0 }, + { "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 }, + { "fan%d_max", applesmc_show_fan_speed, NULL, 2 }, + { "fan%d_safe", applesmc_show_fan_speed, NULL, 3 }, + { "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 }, + { "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual }, + { } }; static struct applesmc_node_group temp_group[] = { @@ -1171,7 +1089,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num) for (i = 0; i < num; i++) { node = &grp->nodes[i]; sprintf(node->name, grp->format, i + 1); - node->sda.index = i; + node->sda.index = (grp->option << 16) | (i & 0xffff); node->sda.dev_attr.show = grp->show; node->sda.dev_attr.store = grp->store; attr = &node->sda.dev_attr.attr; @@ -1287,7 +1205,6 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = { static int __init applesmc_init(void) { int ret; - int count; if (!dmi_check_system(applesmc_whitelist)) { pr_warn("supported laptop not found!\n"); @@ -1326,25 +1243,9 @@ static int __init applesmc_init(void) if (ret) goto out_name; - /* create fan files */ - count = applesmc_get_fan_count(); - if (count < 0) - pr_err("Cannot get the number of fans\n"); - else - pr_info("%d fans found\n", count); - - if (count > 4) { - count = 4; - pr_warn("A maximum of 4 fans are supported by this driver\n"); - } - - while (fans_handled < count) { - ret = sysfs_create_group(&pdev->dev.kobj, - &fan_attribute_groups[fans_handled]); - if (ret) - goto out_fans; - fans_handled++; - } + ret = applesmc_create_nodes(fan_group, smcreg.fan_count); + if (ret) + goto out_info; ret = applesmc_create_nodes(temp_group, smcreg.temp_count); if (ret) @@ -1402,9 +1303,8 @@ out_accelerometer: out_temperature: applesmc_destroy_nodes(temp_group); out_fans: - while (fans_handled) - sysfs_remove_group(&pdev->dev.kobj, - &fan_attribute_groups[--fans_handled]); + applesmc_destroy_nodes(fan_group); +out_info: sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); out_name: sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr); @@ -1433,9 +1333,7 @@ static void __exit applesmc_exit(void) if (smcreg.has_accelerometer) applesmc_release_accelerometer(); applesmc_destroy_nodes(temp_group); - while (fans_handled) - sysfs_remove_group(&pdev->dev.kobj, - &fan_attribute_groups[--fans_handled]); + applesmc_destroy_nodes(fan_group); sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr); applesmc_destroy_smcreg(); -- cgit v1.2.3 From 0b0b5dff8967a4468f05174d0d74e1ed6e369776 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 9 Nov 2010 15:15:09 +0000 Subject: hwmon: (applesmc) Simplify feature sysfs handling Given the dynamic node construction method, the setup of the accelerometer, light sensor and keyboard backlight sysfs nodes can be simplified. This patch does not contain any logic changes. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 169 +++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index b0792361c52e..ec06b9989278 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -992,47 +992,27 @@ static struct led_classdev applesmc_backlight = { .brightness_set = applesmc_brightness_set, }; -static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL); - -static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL); -static DEVICE_ATTR(calibrate, 0644, - applesmc_calibrate_show, applesmc_calibrate_store); - -static struct attribute *accelerometer_attributes[] = { - &dev_attr_position.attr, - &dev_attr_calibrate.attr, - NULL +static struct applesmc_node_group info_group[] = { + { "name", applesmc_name_show }, + { "key_count", applesmc_key_count_show }, + { "key_at_index", applesmc_key_at_index_show, applesmc_key_at_index_store }, + { "key_at_index_name", applesmc_key_at_index_name_show }, + { "key_at_index_type", applesmc_key_at_index_type_show }, + { "key_at_index_data_length", applesmc_key_at_index_data_length_show }, + { "key_at_index_data", applesmc_key_at_index_read_show }, + { } }; -static const struct attribute_group accelerometer_attributes_group = - { .attrs = accelerometer_attributes }; - -static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL); - -static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL); -static DEVICE_ATTR(key_at_index, 0644, - applesmc_key_at_index_show, applesmc_key_at_index_store); -static DEVICE_ATTR(key_at_index_name, 0444, - applesmc_key_at_index_name_show, NULL); -static DEVICE_ATTR(key_at_index_type, 0444, - applesmc_key_at_index_type_show, NULL); -static DEVICE_ATTR(key_at_index_data_length, 0444, - applesmc_key_at_index_data_length_show, NULL); -static DEVICE_ATTR(key_at_index_data, 0444, - applesmc_key_at_index_read_show, NULL); - -static struct attribute *key_enumeration_attributes[] = { - &dev_attr_key_count.attr, - &dev_attr_key_at_index.attr, - &dev_attr_key_at_index_name.attr, - &dev_attr_key_at_index_type.attr, - &dev_attr_key_at_index_data_length.attr, - &dev_attr_key_at_index_data.attr, - NULL +static struct applesmc_node_group accelerometer_group[] = { + { "position", applesmc_position_show }, + { "calibrate", applesmc_calibrate_show, applesmc_calibrate_store }, + { } }; -static const struct attribute_group key_enumeration_group = - { .attrs = key_enumeration_attributes }; +static struct applesmc_node_group light_sensor_group[] = { + { "light", applesmc_light_show }, + { } +}; static struct applesmc_node_group fan_group[] = { { "fan%d_label", applesmc_show_fan_position }, @@ -1115,8 +1095,10 @@ static int applesmc_create_accelerometer(void) struct input_dev *idev; int ret; - ret = sysfs_create_group(&pdev->dev.kobj, - &accelerometer_attributes_group); + if (!smcreg.has_accelerometer) + return 0; + + ret = applesmc_create_nodes(accelerometer_group, 1); if (ret) goto out; @@ -1153,7 +1135,7 @@ out_idev: input_free_polled_device(applesmc_idev); out_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); + applesmc_destroy_nodes(accelerometer_group); out: pr_warn("driver init failed (ret=%d)!\n", ret); @@ -1163,10 +1145,45 @@ out: /* Release all ressources used by the accelerometer */ static void applesmc_release_accelerometer(void) { + if (!smcreg.has_accelerometer) + return; input_unregister_polled_device(applesmc_idev); input_free_polled_device(applesmc_idev); - sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); + applesmc_destroy_nodes(accelerometer_group); } + +static int applesmc_create_light_sensor(void) +{ + if (!smcreg.num_light_sensors) + return 0; + return applesmc_create_nodes(light_sensor_group, 1); +} + +static void applesmc_release_light_sensor(void) +{ + if (!smcreg.num_light_sensors) + return; + applesmc_destroy_nodes(light_sensor_group); +} + +static int applesmc_create_key_backlight(void) +{ + if (!smcreg.has_key_backlight) + return 0; + applesmc_led_wq = create_singlethread_workqueue("applesmc-led"); + if (!applesmc_led_wq) + return -ENOMEM; + return led_classdev_register(&pdev->dev, &applesmc_backlight); +} + +static void applesmc_release_key_backlight(void) +{ + if (!smcreg.has_key_backlight) + return; + led_classdev_unregister(&applesmc_backlight); + destroy_workqueue(applesmc_led_wq); +} + static int applesmc_dmi_match(const struct dmi_system_id *id) { return 1; @@ -1234,15 +1251,10 @@ static int __init applesmc_init(void) if (ret) goto out_device; - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr); + ret = applesmc_create_nodes(info_group, 1); if (ret) goto out_smcreg; - /* Create key enumeration sysfs files */ - ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group); - if (ret) - goto out_name; - ret = applesmc_create_nodes(fan_group, smcreg.fan_count); if (ret) goto out_info; @@ -1251,32 +1263,17 @@ static int __init applesmc_init(void) if (ret) goto out_fans; - if (smcreg.has_accelerometer) { - ret = applesmc_create_accelerometer(); - if (ret) - goto out_temperature; - } - - if (smcreg.num_light_sensors) { - /* Add light sensor file */ - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr); - if (ret) - goto out_accelerometer; - } + ret = applesmc_create_accelerometer(); + if (ret) + goto out_temperature; - if (smcreg.has_key_backlight) { - /* Create the workqueue */ - applesmc_led_wq = create_singlethread_workqueue("applesmc-led"); - if (!applesmc_led_wq) { - ret = -ENOMEM; - goto out_light_sysfs; - } + ret = applesmc_create_light_sensor(); + if (ret) + goto out_accelerometer; - /* register as a led device */ - ret = led_classdev_register(&pdev->dev, &applesmc_backlight); - if (ret < 0) - goto out_light_wq; - } + ret = applesmc_create_key_backlight(); + if (ret) + goto out_light_sysfs; hwmon_dev = hwmon_device_register(&pdev->dev); if (IS_ERR(hwmon_dev)) { @@ -1289,25 +1286,17 @@ static int __init applesmc_init(void) return 0; out_light_ledclass: - if (smcreg.has_key_backlight) - led_classdev_unregister(&applesmc_backlight); -out_light_wq: - if (smcreg.has_key_backlight) - destroy_workqueue(applesmc_led_wq); + applesmc_release_key_backlight(); out_light_sysfs: - if (smcreg.num_light_sensors) - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); + applesmc_release_light_sensor(); out_accelerometer: - if (smcreg.has_accelerometer) - applesmc_release_accelerometer(); + applesmc_release_accelerometer(); out_temperature: applesmc_destroy_nodes(temp_group); out_fans: applesmc_destroy_nodes(fan_group); out_info: - sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); -out_name: - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr); + applesmc_destroy_nodes(info_group); out_smcreg: applesmc_destroy_smcreg(); out_device: @@ -1324,18 +1313,12 @@ out: static void __exit applesmc_exit(void) { hwmon_device_unregister(hwmon_dev); - if (smcreg.has_key_backlight) { - led_classdev_unregister(&applesmc_backlight); - destroy_workqueue(applesmc_led_wq); - } - if (smcreg.num_light_sensors) - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr); - if (smcreg.has_accelerometer) - applesmc_release_accelerometer(); + applesmc_release_key_backlight(); + applesmc_release_light_sensor(); + applesmc_release_accelerometer(); applesmc_destroy_nodes(temp_group); applesmc_destroy_nodes(fan_group); - sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group); - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr); + applesmc_destroy_nodes(info_group); applesmc_destroy_smcreg(); platform_device_unregister(pdev); platform_driver_unregister(&applesmc_driver); -- cgit v1.2.3 From 0b8ad5a57b75322e4b671ef420b5fe90e5154912 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 9 Nov 2010 15:15:10 +0000 Subject: hwmon: (applesmc) Silence driver Make the driver report a single line on success. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index ec06b9989278..bcdf5bc2c40a 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1281,8 +1281,6 @@ static int __init applesmc_init(void) goto out_light_ledclass; } - pr_info("driver successfully loaded\n"); - return 0; out_light_ledclass: @@ -1323,8 +1321,6 @@ static void __exit applesmc_exit(void) platform_device_unregister(pdev); platform_driver_unregister(&applesmc_driver); release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); - - pr_info("driver unloaded\n"); } module_init(applesmc_init); -- cgit v1.2.3 From 41e71f97174ba08fcca7f31bf448de92abc8862e Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 9 Nov 2010 15:15:11 +0000 Subject: hwmon: (applesmc) Update copyright information With the preceding patches, git blame assigns about half of the file to the present author. Add a line to the copyright to reflect this. Signed-off-by: Henrik Rydberg Signed-off-by: Guenter Roeck --- drivers/hwmon/applesmc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index bcdf5bc2c40a..81792ca47175 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -4,6 +4,7 @@ * computers. * * Copyright (C) 2007 Nicolas Boichat + * Copyright (C) 2010 Henrik Rydberg * * Based on hdaps.c driver: * Copyright (C) 2005 Robert Love -- cgit v1.2.3 From 2bfe814826b7266a489895f731a777f8cbe37963 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 10 Nov 2010 10:42:21 -0800 Subject: hwmon: (applesmc) Fix checkpatch errors and fix value range checks This patch fixes all checkpatch errors and most of the checkpatch warnings. It also fixes the range check in applesmc_store_fan_speed(). Signed-off-by: Guenter Roeck Acked-by: Henrik Rydberg --- drivers/hwmon/applesmc.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 81792ca47175..ce0372f0615e 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -174,9 +174,8 @@ static int __wait_status(u8 val) for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) { udelay(us); - if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) { + if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) return 0; - } } return -EIO; @@ -431,7 +430,7 @@ static int applesmc_has_key(const char *key, bool *value) /* * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). */ -static int applesmc_read_motion_sensor(int index, s16* value) +static int applesmc_read_motion_sensor(int index, s16 *value) { u8 buffer[2]; int ret; @@ -779,14 +778,12 @@ static ssize_t applesmc_store_fan_speed(struct device *dev, const char *sysfsbuf, size_t count) { int ret; - u32 speed; + unsigned long speed; char newkey[5]; u8 buffer[2]; - speed = simple_strtoul(sysfsbuf, NULL, 10); - - if (speed > 0x4000) /* Bigger than a 14-bit value */ - return -EINVAL; + if (strict_strtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000) + return -EINVAL; /* Bigger than a 14-bit value */ sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr)); @@ -822,10 +819,11 @@ static ssize_t applesmc_store_fan_manual(struct device *dev, { int ret; u8 buffer[2]; - u32 input; + unsigned long input; u16 val; - input = simple_strtoul(sysfsbuf, NULL, 10); + if (strict_strtoul(sysfsbuf, 10, &input) < 0) + return -EINVAL; ret = applesmc_read_key(FANS_MANUAL, buffer, 2); val = (buffer[0] << 8 | buffer[1]); @@ -1198,24 +1196,24 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = { DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") }, }, { applesmc_dmi_match, "Apple MacBook Pro", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") }, + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro") }, }, { applesmc_dmi_match, "Apple MacBook", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") }, + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") }, }, { applesmc_dmi_match, "Apple Macmini", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") }, + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") }, }, { applesmc_dmi_match, "Apple MacPro", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") }, }, { applesmc_dmi_match, "Apple iMac", { - DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), - DMI_MATCH(DMI_PRODUCT_NAME,"iMac") }, + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "iMac") }, }, { .ident = NULL } }; -- cgit v1.2.3 From 0f1deb4b820cfacf22492abd7b17e891dafc51ae Mon Sep 17 00:00:00 2001 From: Davide Rizzo Date: Thu, 18 Nov 2010 07:23:00 -0800 Subject: hwmon: (lm95241) Rewrite to avoid using macros Signed-off-by: Davide Rizzo [guenter.roeck@ericsson.com: Formatting changes] Signed-off-by: Guenter Roeck --- drivers/hwmon/lm95241.c | 495 +++++++++++++++++++++++------------------------- 1 file changed, 233 insertions(+), 262 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 4546d82f024a..1a6dfb6df1e7 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -1,13 +1,9 @@ /* - * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2008 Davide Rizzo + * Copyright (C) 2008, 2010 Davide Rizzo * - * Based on the max1619 driver. The LM95241 is a sensor chip made by National - * Semiconductors. - * It reports up to three temperatures (its own plus up to - * two external ones). Complete datasheet can be - * obtained from National's website at: + * The LM95241 is a sensor chip made by National Semiconductors. + * It reports up to three temperatures (its own plus up to two external ones). + * Complete datasheet can be obtained from National's website at: * http://www.national.com/ds.cgi/LM/LM95241.pdf * * This program is free software; you can redistribute it and/or modify @@ -36,8 +32,10 @@ #include #include +#define DEVNAME "lm95241" + static const unsigned short normal_i2c[] = { - 0x19, 0x2a, 0x2b, I2C_CLIENT_END}; + 0x19, 0x2a, 0x2b, I2C_CLIENT_END }; /* LM95241 registers */ #define LM95241_REG_R_MAN_ID 0xFE @@ -46,7 +44,7 @@ static const unsigned short normal_i2c[] = { #define LM95241_REG_RW_CONFIG 0x03 #define LM95241_REG_RW_REM_FILTER 0x06 #define LM95241_REG_RW_TRUTHERM 0x07 -#define LM95241_REG_W_ONE_SHOT 0x0F +#define LM95241_REG_W_ONE_SHOT 0x0F #define LM95241_REG_R_LOCAL_TEMPH 0x10 #define LM95241_REG_R_REMOTE1_TEMPH 0x11 #define LM95241_REG_R_REMOTE2_TEMPH 0x12 @@ -79,235 +77,246 @@ static const unsigned short normal_i2c[] = { #define MANUFACTURER_ID 0x01 #define DEFAULT_REVISION 0xA4 -/* Conversions and various macros */ -#define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \ - (val_h)) * 1000 + (val_l) * 1000 / 256) - -/* Functions declaration */ -static void lm95241_init_client(struct i2c_client *client); -static struct lm95241_data *lm95241_update_device(struct device *dev); +static const u8 lm95241_reg_address[] = { + LM95241_REG_R_LOCAL_TEMPH, + LM95241_REG_R_LOCAL_TEMPL, + LM95241_REG_R_REMOTE1_TEMPH, + LM95241_REG_R_REMOTE1_TEMPL, + LM95241_REG_R_REMOTE2_TEMPH, + LM95241_REG_R_REMOTE2_TEMPL +}; /* Client data (each client gets its own) */ struct lm95241_data { struct device *hwmon_dev; struct mutex update_lock; - unsigned long last_updated, interval; /* in jiffies */ - char valid; /* zero until following fields are valid */ + unsigned long last_updated, interval; /* in jiffies */ + char valid; /* zero until following fields are valid */ /* registers values */ - u8 local_h, local_l; /* local */ - u8 remote1_h, remote1_l; /* remote1 */ - u8 remote2_h, remote2_l; /* remote2 */ + u8 temp[ARRAY_SIZE(lm95241_reg_address)]; u8 config, model, trutherm; }; +/* Conversions */ +static int TempFromReg(u8 val_h, u8 val_l) +{ + if (val_h & 0x80) + return val_h - 0x100; + return val_h * 1000 + val_l * 1000 / 256; +} + +static struct lm95241_data *lm95241_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + data->interval) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Updating lm95241 data.\n"); + for (i = 0; i < ARRAY_SIZE(lm95241_reg_address); i++) + data->temp[i] + = i2c_smbus_read_byte_data(client, + lm95241_reg_address[i]); + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + /* Sysfs stuff */ -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct lm95241_data *data = lm95241_update_device(dev); \ - snprintf(buf, PAGE_SIZE - 1, "%d\n", \ - TEMP_FROM_REG(data->value##_h, data->value##_l)); \ - return strlen(buf); \ +static ssize_t show_input(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm95241_data *data = lm95241_update_device(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", + TempFromReg(data->temp[to_sensor_dev_attr(attr)->index], + data->temp[to_sensor_dev_attr(attr)->index + 1])); } -show_temp(local); -show_temp(remote1); -show_temp(remote2); -static ssize_t show_interval(struct device *dev, struct device_attribute *attr, +static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct lm95241_data *data = lm95241_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); - snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval / HZ); - return strlen(buf); + return snprintf(buf, PAGE_SIZE - 1, + data->model & to_sensor_dev_attr(attr)->index ? "1\n" : "2\n"); } -static ssize_t set_interval(struct device *dev, struct device_attribute *attr, +static ssize_t set_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm95241_data *data = i2c_get_clientdata(client); unsigned long val; + int shift; + u8 mask = to_sensor_dev_attr(attr)->index; if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; + if (val != 1 && val != 2) + return -EINVAL; - data->interval = val * HZ / 1000; + shift = mask == R1MS_MASK ? TT1_SHIFT : TT2_SHIFT; + + mutex_lock(&data->update_lock); + + data->trutherm &= ~(TT_MASK << shift); + if (val == 1) { + data->model |= mask; + data->trutherm |= (TT_ON << shift); + } else { + data->model &= ~mask; + data->trutherm |= (TT_OFF << shift); + } + data->valid = 0; + + i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, + data->model); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, + data->trutherm); + + mutex_unlock(&data->update_lock); return count; } -#define show_type(flag) \ -static ssize_t show_type##flag(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm95241_data *data = i2c_get_clientdata(client); \ -\ - snprintf(buf, PAGE_SIZE - 1, \ - data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \ - return strlen(buf); \ +static ssize_t show_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + + return snprintf(buf, PAGE_SIZE - 1, + data->config & to_sensor_dev_attr(attr)->index ? + "-127000\n" : "0\n"); } -show_type(1); -show_type(2); - -#define show_min(flag) \ -static ssize_t show_min##flag(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm95241_data *data = i2c_get_clientdata(client); \ -\ - snprintf(buf, PAGE_SIZE - 1, \ - data->config & R##flag##DF_MASK ? \ - "-127000\n" : "0\n"); \ - return strlen(buf); \ + +static ssize_t set_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + long val; + + if (strict_strtol(buf, 10, &val) < 0) + return -EINVAL; + if (val < -128000) + return -EINVAL; + + mutex_lock(&data->update_lock); + + if (val < 0) + data->config |= to_sensor_dev_attr(attr)->index; + else + data->config &= ~to_sensor_dev_attr(attr)->index; + data->valid = 0; + + i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config); + + mutex_unlock(&data->update_lock); + + return count; } -show_min(1); -show_min(2); - -#define show_max(flag) \ -static ssize_t show_max##flag(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm95241_data *data = i2c_get_clientdata(client); \ -\ - snprintf(buf, PAGE_SIZE - 1, \ - data->config & R##flag##DF_MASK ? \ - "127000\n" : "255000\n"); \ - return strlen(buf); \ + +static ssize_t show_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + + return snprintf(buf, PAGE_SIZE - 1, + data->config & to_sensor_dev_attr(attr)->index ? + "127000\n" : "255000\n"); } -show_max(1); -show_max(2); - -#define set_type(flag) \ -static ssize_t set_type##flag(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm95241_data *data = i2c_get_clientdata(client); \ -\ - long val; \ -\ - if (strict_strtol(buf, 10, &val) < 0) \ - return -EINVAL; \ -\ - if ((val == 1) || (val == 2)) { \ -\ - mutex_lock(&data->update_lock); \ -\ - data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \ - if (val == 1) { \ - data->model |= R##flag##MS_MASK; \ - data->trutherm |= (TT_ON << TT##flag##_SHIFT); \ - } \ - else { \ - data->model &= ~R##flag##MS_MASK; \ - data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \ - } \ -\ - data->valid = 0; \ -\ - i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \ - data->model); \ - i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \ - data->trutherm); \ -\ - mutex_unlock(&data->update_lock); \ -\ - } \ - return count; \ + +static ssize_t set_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + long val; + + if (strict_strtol(buf, 10, &val) < 0) + return -EINVAL; + if (val >= 256000) + return -EINVAL; + + mutex_lock(&data->update_lock); + + if (val <= 127000) + data->config |= to_sensor_dev_attr(attr)->index; + else + data->config &= ~to_sensor_dev_attr(attr)->index; + data->valid = 0; + + i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config); + + mutex_unlock(&data->update_lock); + + return count; } -set_type(1); -set_type(2); - -#define set_min(flag) \ -static ssize_t set_min##flag(struct device *dev, \ - struct device_attribute *devattr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm95241_data *data = i2c_get_clientdata(client); \ -\ - long val; \ -\ - if (strict_strtol(buf, 10, &val) < 0) \ - return -EINVAL;\ -\ - mutex_lock(&data->update_lock); \ -\ - if (val < 0) \ - data->config |= R##flag##DF_MASK; \ - else \ - data->config &= ~R##flag##DF_MASK; \ -\ - data->valid = 0; \ -\ - i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ - data->config); \ -\ - mutex_unlock(&data->update_lock); \ -\ - return count; \ + +static ssize_t show_interval(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm95241_data *data = lm95241_update_device(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval + / HZ); } -set_min(1); -set_min(2); - -#define set_max(flag) \ -static ssize_t set_max##flag(struct device *dev, \ - struct device_attribute *devattr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm95241_data *data = i2c_get_clientdata(client); \ -\ - long val; \ -\ - if (strict_strtol(buf, 10, &val) < 0) \ - return -EINVAL; \ -\ - mutex_lock(&data->update_lock); \ -\ - if (val <= 127000) \ - data->config |= R##flag##DF_MASK; \ - else \ - data->config &= ~R##flag##DF_MASK; \ -\ - data->valid = 0; \ -\ - i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ - data->config); \ -\ - mutex_unlock(&data->update_lock); \ -\ - return count; \ + +static ssize_t set_interval(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + data->interval = val * HZ / 1000; + + return count; } -set_max(1); -set_max(2); - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL); -static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL); -static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1); -static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1); -static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1); -static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type, + R1MS_MASK); +static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type, + R2MS_MASK); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min, + R1DF_MASK); +static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min, + R2DF_MASK); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max, + R1DF_MASK); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max, + R2DF_MASK); static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, set_interval); static struct attribute *lm95241_attributes[] = { - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp3_input.attr, - &dev_attr_temp2_type.attr, - &dev_attr_temp3_type.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp3_min.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp3_max.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp2_type.dev_attr.attr, + &sensor_dev_attr_temp3_type.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, &dev_attr_update_interval.attr, NULL }; @@ -329,9 +338,9 @@ static int lm95241_detect(struct i2c_client *new_client, if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) == MANUFACTURER_ID) - && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) - >= DEFAULT_REVISION)) { - name = "lm95241"; + && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) + >= DEFAULT_REVISION)) { + name = DEVNAME; } else { dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n", address); @@ -343,6 +352,25 @@ static int lm95241_detect(struct i2c_client *new_client, return 0; } +static void lm95241_init_client(struct i2c_client *client) +{ + struct lm95241_data *data = i2c_get_clientdata(client); + + data->interval = HZ; /* 1 sec default */ + data->valid = 0; + data->config = CFG_CR0076; + data->model = 0; + data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); + + i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, data->config); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER, + R1FE_MASK | R2FE_MASK); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, + data->trutherm); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, + data->model); +} + static int lm95241_probe(struct i2c_client *new_client, const struct i2c_device_id *id) { @@ -382,26 +410,6 @@ exit: return err; } -static void lm95241_init_client(struct i2c_client *client) -{ - struct lm95241_data *data = i2c_get_clientdata(client); - - data->interval = HZ; /* 1 sec default */ - data->valid = 0; - data->config = CFG_CR0076; - data->model = 0; - data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); - - i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, - data->config); - i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER, - R1FE_MASK | R2FE_MASK); - i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, - data->trutherm); - i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, - data->model); -} - static int lm95241_remove(struct i2c_client *client) { struct lm95241_data *data = i2c_get_clientdata(client); @@ -413,46 +421,9 @@ static int lm95241_remove(struct i2c_client *client) return 0; } -static struct lm95241_data *lm95241_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm95241_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + data->interval) || - !data->valid) { - dev_dbg(&client->dev, "Updating lm95241 data.\n"); - data->local_h = - i2c_smbus_read_byte_data(client, - LM95241_REG_R_LOCAL_TEMPH); - data->local_l = - i2c_smbus_read_byte_data(client, - LM95241_REG_R_LOCAL_TEMPL); - data->remote1_h = - i2c_smbus_read_byte_data(client, - LM95241_REG_R_REMOTE1_TEMPH); - data->remote1_l = - i2c_smbus_read_byte_data(client, - LM95241_REG_R_REMOTE1_TEMPL); - data->remote2_h = - i2c_smbus_read_byte_data(client, - LM95241_REG_R_REMOTE2_TEMPH); - data->remote2_l = - i2c_smbus_read_byte_data(client, - LM95241_REG_R_REMOTE2_TEMPL); - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); - - return data; -} - /* Driver data (common to all clients) */ static const struct i2c_device_id lm95241_id[] = { - { "lm95241", 0 }, + { DEVNAME, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, lm95241_id); @@ -460,7 +431,7 @@ MODULE_DEVICE_TABLE(i2c, lm95241_id); static struct i2c_driver lm95241_driver = { .class = I2C_CLASS_HWMON, .driver = { - .name = "lm95241", + .name = DEVNAME, }, .probe = lm95241_probe, .remove = lm95241_remove, @@ -479,7 +450,7 @@ static void __exit sensors_lm95241_exit(void) i2c_del_driver(&lm95241_driver); } -MODULE_AUTHOR("Davide Rizzo "); +MODULE_AUTHOR("Davide Rizzo "); MODULE_DESCRIPTION("LM95241 sensor driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ae9e0ce73e9fc55a620e0b3bd4a154330a7e64cc Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 6 Dec 2010 11:48:35 -0500 Subject: hwmon: (via-cputemp) sync hotplug handling with coretemp/pkgtemp Signed-off-by: Jan Beulich Signed-off-by: Guenter Roeck --- drivers/hwmon/via-cputemp.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 45b08c78b531..0d18de424c66 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -238,13 +238,16 @@ exit: static void __cpuinit via_cputemp_device_remove(unsigned int cpu) { - struct pdev_entry *p, *n; + struct pdev_entry *p; + mutex_lock(&pdev_list_mutex); - list_for_each_entry_safe(p, n, &pdev_list, list) { + list_for_each_entry(p, &pdev_list, list) { if (p->cpu == cpu) { platform_device_unregister(p->pdev); list_del(&p->list); + mutex_unlock(&pdev_list_mutex); kfree(p); + return; } } mutex_unlock(&pdev_list_mutex); @@ -274,7 +277,6 @@ static struct notifier_block via_cputemp_cpu_notifier __refdata = { static int __init via_cputemp_init(void) { int i, err; - struct pdev_entry *p, *n; if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) { printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n"); @@ -300,28 +302,23 @@ static int __init via_cputemp_init(void) continue; } - err = via_cputemp_device_add(i); - if (err) - goto exit_devices_unreg; + via_cputemp_device_add(i); } + +#ifndef CONFIG_HOTPLUG_CPU if (list_empty(&pdev_list)) { err = -ENODEV; goto exit_driver_unreg; } +#endif register_hotcpu_notifier(&via_cputemp_cpu_notifier); return 0; -exit_devices_unreg: - mutex_lock(&pdev_list_mutex); - list_for_each_entry_safe(p, n, &pdev_list, list) { - platform_device_unregister(p->pdev); - list_del(&p->list); - kfree(p); - } - mutex_unlock(&pdev_list_mutex); +#ifndef CONFIG_HOTPLUG_CPU exit_driver_unreg: platform_driver_unregister(&via_cputemp_driver); +#endif exit: return err; } -- cgit v1.2.3 From 430400b86304ea729ba10f2966a8af67da60a37f Mon Sep 17 00:00:00 2001 From: Urs Fleisch Date: Fri, 7 Jan 2011 07:15:39 +0000 Subject: hwmon: driver for Sensirion SHT21 humidity and temperature sensor Signed-off-by: Urs Fleisch Acked-by: Jonathan Cameron Signed-off-by: Guenter Roeck --- Documentation/hwmon/sht21 | 49 ++++++++ drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/sht21.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+) create mode 100644 Documentation/hwmon/sht21 create mode 100644 drivers/hwmon/sht21.c (limited to 'drivers') diff --git a/Documentation/hwmon/sht21 b/Documentation/hwmon/sht21 new file mode 100644 index 000000000000..db17fda45c3e --- /dev/null +++ b/Documentation/hwmon/sht21 @@ -0,0 +1,49 @@ +Kernel driver sht21 +=================== + +Supported chips: + * Sensirion SHT21 + Prefix: 'sht21' + Addresses scanned: none + Datasheet: Publicly available at the Sensirion website + http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf + + * Sensirion SHT25 + Prefix: 'sht21' + Addresses scanned: none + Datasheet: Publicly available at the Sensirion website + http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT25.pdf + +Author: + Urs Fleisch + +Description +----------- + +The SHT21 and SHT25 are humidity and temperature sensors in a DFN package of +only 3 x 3 mm footprint and 1.1 mm height. The difference between the two +devices is the higher level of precision of the SHT25 (1.8% relative humidity, +0.2 degree Celsius) compared with the SHT21 (2.0% relative humidity, +0.3 degree Celsius). + +The devices communicate with the I2C protocol. All sensors are set to the same +I2C address 0x40, so an entry with I2C_BOARD_INFO("sht21", 0x40) can be used +in the board setup code. + +sysfs-Interface +--------------- + +temp1_input - temperature input +humidity1_input - humidity input + +Notes +----- + +The driver uses the default resolution settings of 12 bit for humidity and 14 +bit for temperature, which results in typical measurement times of 22 ms for +humidity and 66 ms for temperature. To keep self heating below 0.1 degree +Celsius, the device should not be active for more than 10% of the time, +e.g. maximum two measurements per second at the given resolution. + +Different resolutions, the on-chip heater, using the CRC checksum and reading +the serial number are not supported yet. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index a56f6adf3b76..0f09567257fd 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -734,6 +734,16 @@ config SENSORS_SHT15 This driver can also be built as a module. If so, the module will be called sht15. +config SENSORS_SHT21 + tristate "Sensiron humidity and temperature sensors. SHT21 and compat." + depends on I2C + help + If you say yes here you get support for the Sensiron SHT21, SHT25 + humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called sht21. + config SENSORS_S3C tristate "Samsung built-in ADC" depends on S3C_ADC diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2479b3da272c..20e74086e681 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o +obj-$(CONFIG_SENSORS_SHT21) += sht21.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c new file mode 100644 index 000000000000..1c8c9812f244 --- /dev/null +++ b/drivers/hwmon/sht21.c @@ -0,0 +1,307 @@ +/* Sensirion SHT21 humidity and temperature sensor driver + * + * Copyright (C) 2010 Urs Fleisch + * + * 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA + * + * Data sheet available (5/2010) at + * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* I2C command bytes */ +#define SHT21_TRIG_T_MEASUREMENT_HM 0xe3 +#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5 + +/** + * struct sht21 - SHT21 device specific data + * @hwmon_dev: device registered with hwmon + * @lock: mutex to protect measurement values + * @valid: only 0 before first measurement is taken + * @last_update: time of last update (jiffies) + * @temperature: cached temperature measurement value + * @humidity: cached humidity measurement value + */ +struct sht21 { + struct device *hwmon_dev; + struct mutex lock; + char valid; + unsigned long last_update; + int temperature; + int humidity; +}; + +/** + * sht21_temp_ticks_to_millicelsius() - convert raw temperature ticks to + * milli celsius + * @ticks: temperature ticks value received from sensor + */ +static inline int sht21_temp_ticks_to_millicelsius(int ticks) +{ + ticks &= ~0x0003; /* clear status bits */ + /* + * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2, + * optimized for integer fixed point (3 digits) arithmetic + */ + return ((21965 * ticks) >> 13) - 46850; +} + +/** + * sht21_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to + * one-thousandths of a percent relative humidity + * @ticks: humidity ticks value received from sensor + */ +static inline int sht21_rh_ticks_to_per_cent_mille(int ticks) +{ + ticks &= ~0x0003; /* clear status bits */ + /* + * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1, + * optimized for integer fixed point (3 digits) arithmetic + */ + return ((15625 * ticks) >> 13) - 6000; +} + +/** + * sht21_read_word_data() - read word from register + * @client: I2C client device + * @reg: I2C command byte + * + * Returns value, negative errno on error. + */ +static inline int sht21_read_word_data(struct i2c_client *client, u8 reg) +{ + int ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + /* + * SMBus specifies low byte first, but the SHT21 returns MSB + * first, so we have to swab16 the values + */ + return swab16(ret); +} + +/** + * sht21_update_measurements() - get updated measurements from device + * @client: I2C client device + * + * Returns 0 on success, else negative errno. + */ +static int sht21_update_measurements(struct i2c_client *client) +{ + int ret = 0; + struct sht21 *sht21 = i2c_get_clientdata(client); + + mutex_lock(&sht21->lock); + /* + * Data sheet 2.4: + * SHT2x should not be active for more than 10% of the time - e.g. + * maximum two measurements per second at 12bit accuracy shall be made. + */ + if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) { + ret = sht21_read_word_data(client, SHT21_TRIG_T_MEASUREMENT_HM); + if (ret < 0) + goto out; + sht21->temperature = sht21_temp_ticks_to_millicelsius(ret); + ret = sht21_read_word_data(client, + SHT21_TRIG_RH_MEASUREMENT_HM); + if (ret < 0) + goto out; + sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret); + sht21->last_update = jiffies; + sht21->valid = 1; + } +out: + mutex_unlock(&sht21->lock); + + return ret >= 0 ? 0 : ret; +} + +/** + * sht21_show_temperature() - show temperature measurement value in sysfs + * @dev: device + * @attr: device attribute + * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to + * + * Will be called on read access to temp1_input sysfs attribute. + * Returns number of bytes written into buffer, negative errno on error. + */ +static ssize_t sht21_show_temperature(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sht21 *sht21 = i2c_get_clientdata(client); + int ret = sht21_update_measurements(client); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", sht21->temperature); +} + +/** + * sht21_show_humidity() - show humidity measurement value in sysfs + * @dev: device + * @attr: device attribute + * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to + * + * Will be called on read access to humidity1_input sysfs attribute. + * Returns number of bytes written into buffer, negative errno on error. + */ +static ssize_t sht21_show_humidity(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sht21 *sht21 = i2c_get_clientdata(client); + int ret = sht21_update_measurements(client); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", sht21->humidity); +} + +/* sysfs attributes */ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature, + NULL, 0); +static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity, + NULL, 0); + +static struct attribute *sht21_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_humidity1_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group sht21_attr_group = { + .attrs = sht21_attributes, +}; + +/** + * sht21_probe() - probe device + * @client: I2C client device + * @id: device ID + * + * Called by the I2C core when an entry in the ID table matches a + * device's name. + * Returns 0 on success. + */ +static int __devinit sht21_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sht21 *sht21; + int err; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_err(&client->dev, + "adapter does not support SMBus word transactions\n"); + return -ENODEV; + } + + sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL); + if (!sht21) { + dev_dbg(&client->dev, "kzalloc failed\n"); + return -ENOMEM; + } + i2c_set_clientdata(client, sht21); + + mutex_init(&sht21->lock); + + err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group); + if (err) { + dev_dbg(&client->dev, "could not create sysfs files\n"); + goto fail_free; + } + sht21->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(sht21->hwmon_dev)) { + dev_dbg(&client->dev, "unable to register hwmon device\n"); + err = PTR_ERR(sht21->hwmon_dev); + goto fail_remove_sysfs; + } + + dev_info(&client->dev, "initialized\n"); + + return 0; + +fail_remove_sysfs: + sysfs_remove_group(&client->dev.kobj, &sht21_attr_group); +fail_free: + kfree(sht21); + + return err; +} + +/** + * sht21_remove() - remove device + * @client: I2C client device + */ +static int __devexit sht21_remove(struct i2c_client *client) +{ + struct sht21 *sht21 = i2c_get_clientdata(client); + + hwmon_device_unregister(sht21->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &sht21_attr_group); + kfree(sht21); + + return 0; +} + +/* Device ID table */ +static const struct i2c_device_id sht21_id[] = { + { "sht21", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sht21_id); + +static struct i2c_driver sht21_driver = { + .driver.name = "sht21", + .probe = sht21_probe, + .remove = __devexit_p(sht21_remove), + .id_table = sht21_id, +}; + +/** + * sht21_init() - initialize driver + * + * Called when kernel is booted or module is inserted. + * Returns 0 on success. + */ +static int __init sht21_init(void) +{ + return i2c_add_driver(&sht21_driver); +} +module_init(sht21_init); + +/** + * sht21_init() - clean up driver + * + * Called when module is removed. + */ +static void __exit sht21_exit(void) +{ + i2c_del_driver(&sht21_driver); +} +module_exit(sht21_exit); + +MODULE_AUTHOR("Urs Fleisch "); +MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 985b1aa05bc47794780ac92eebdaf006a5187afb Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 7 Nov 2010 16:57:12 -0500 Subject: mmc: Add support for the Marvell Dove SDHCI controller Implement an sdhci-pltfm driver for the controller found in the Marvell Dove SoC. Signed-off-by: Mike Rapoport CC: Saeed Bishara Acked-by: Wolfram Sang Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 11 +++++++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-dove.c | 70 ++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/host/sdhci-pltfm.c | 3 ++ drivers/mmc/host/sdhci-pltfm.h | 1 + 5 files changed, 86 insertions(+) create mode 100644 drivers/mmc/host/sdhci-dove.c (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d618e8673996..f8fa9efca8ee 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -140,6 +140,17 @@ config MMC_SDHCI_ESDHC_IMX If unsure, say N. +config MMC_SDHCI_DOVE + bool "SDHCI support on Marvell's Dove SoC" + depends on ARCH_DOVE + depends on MMC_SDHCI_PLTFM + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Secure Digital Host Controller Interface in + Marvell's Dove SoC. + + If unsure, say N. + config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" depends on MMC_SDHCI && PLAT_SAMSUNG diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 7b645ff43b30..d91364d4bf39 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o sdhci-platform-y := sdhci-pltfm.o sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o +sdhci-platform-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o sdhci-of-y := sdhci-of-core.o diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c new file mode 100644 index 000000000000..2aeef4ffed8c --- /dev/null +++ b/drivers/mmc/host/sdhci-dove.c @@ -0,0 +1,70 @@ +/* + * sdhci-dove.c Support for SDHCI on Marvell's Dove SoC + * + * Author: Saeed Bishara + * Mike Rapoport + * Based on sdhci-cns3xxx.c + * + * 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. + * + * 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. + */ + +#include +#include + +#include "sdhci.h" +#include "sdhci-pltfm.h" + +static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) +{ + u16 ret; + + switch (reg) { + case SDHCI_HOST_VERSION: + case SDHCI_SLOT_INT_STATUS: + /* those registers don't exist */ + return 0; + default: + ret = readw(host->ioaddr + reg); + } + return ret; +} + +static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) +{ + u32 ret; + + switch (reg) { + case SDHCI_CAPABILITIES: + ret = readl(host->ioaddr + reg); + /* Mask the support for 3.0V */ + ret &= ~SDHCI_CAN_VDD_300; + break; + default: + ret = readl(host->ioaddr + reg); + } + return ret; +} + +static struct sdhci_ops sdhci_dove_ops = { + .read_w = sdhci_dove_readw, + .read_l = sdhci_dove_readl, +}; + +struct sdhci_pltfm_data sdhci_dove_pdata = { + .ops = &sdhci_dove_ops, + .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | + SDHCI_QUIRK_NO_BUSY_IRQ | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_FORCE_DMA, +}; diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 0502f89f662b..91c6766c660c 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -169,6 +169,9 @@ static const struct platform_device_id sdhci_pltfm_ids[] = { #endif #ifdef CONFIG_MMC_SDHCI_ESDHC_IMX { "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata }, +#endif +#ifdef CONFIG_MMC_SDHCI_DOVE + { "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata }, #endif { }, }; diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index c1bfe48af56a..62118b9f9d0a 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -22,5 +22,6 @@ struct sdhci_pltfm_host { extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata; +extern struct sdhci_pltfm_data sdhci_dove_pdata; #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ -- cgit v1.2.3 From 74b66954ebfcef9bc26d9c377d32fbd46b4ddc32 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Tue, 2 Nov 2010 01:05:37 +0100 Subject: mmc: mxcmmc: Allow binding a regulator to manage the MMC card voltage This implementation is based on the pxamci.c driver and it will be used to support the mx31_3ds machine. Signed-off-by: Alberto Panizzo Acked-by: Sascha Hauer Signed-off-by: Chris Ball --- drivers/mmc/host/mxcmmc.c | 48 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index bdd2cbb87cba..1a7f48c3c554 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -141,10 +142,45 @@ struct mxcmci_host { struct work_struct datawork; spinlock_t lock; + + struct regulator *vcc; }; static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); +static inline void mxcmci_init_ocr(struct mxcmci_host *host) +{ +#ifdef CONFIG_REGULATOR + host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + + if (IS_ERR(host->vcc)) { + host->vcc = NULL; + } else { + host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); + if (host->pdata && host->pdata->ocr_avail) + dev_warn(mmc_dev(host->mmc), + "pdata->ocr_avail will not be used\n"); + } +#endif + if (host->vcc == NULL) { + /* fall-back to platform data */ + if (host->pdata && host->pdata->ocr_avail) + host->mmc->ocr_avail = host->pdata->ocr_avail; + else + host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + } +} + +static inline void mxcmci_set_power(struct mxcmci_host *host, unsigned int vdd) +{ +#ifdef CONFIG_REGULATOR + if (host->vcc) + mmc_regulator_set_ocr(host->vcc, vdd); +#endif + if (host->pdata && host->pdata->setpower) + host->pdata->setpower(mmc_dev(host->mmc), vdd); +} + static inline int mxcmci_use_dma(struct mxcmci_host *host) { return host->do_dma; @@ -680,9 +716,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; if (host->power_mode != ios->power_mode) { - if (host->pdata && host->pdata->setpower) - host->pdata->setpower(mmc_dev(mmc), ios->vdd); + mxcmci_set_power(host, ios->vdd); host->power_mode = ios->power_mode; + if (ios->power_mode == MMC_POWER_ON) host->cmdat |= CMD_DAT_CONT_INIT; } @@ -807,10 +843,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->pdata = pdev->dev.platform_data; spin_lock_init(&host->lock); - if (host->pdata && host->pdata->ocr_avail) - mmc->ocr_avail = host->pdata->ocr_avail; - else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mxcmci_init_ocr(host); if (host->pdata && host->pdata->dat3_card_detect) host->default_irq_mask = @@ -915,6 +948,9 @@ static int mxcmci_remove(struct platform_device *pdev) mmc_remove_host(mmc); + if (host->vcc) + regulator_put(host->vcc); + if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); -- cgit v1.2.3 From d078d24242ff6c36338991627f9c63b2d48a6eee Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Tue, 9 Nov 2010 11:35:37 +0100 Subject: mmc: mxcmmc: update the regulator support code to the latest API This also fixes the build problem introduced by my previous patch due to unhandled API changes introduced by commit: 99fc513101 (mmc: Move regulator handling closer to core) Signed-off-by: Alberto Panizzo Signed-off-by: Chris Ball --- drivers/mmc/host/mxcmmc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 1a7f48c3c554..2b9f7c856700 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -150,7 +150,6 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); static inline void mxcmci_init_ocr(struct mxcmci_host *host) { -#ifdef CONFIG_REGULATOR host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); if (IS_ERR(host->vcc)) { @@ -161,7 +160,7 @@ static inline void mxcmci_init_ocr(struct mxcmci_host *host) dev_warn(mmc_dev(host->mmc), "pdata->ocr_avail will not be used\n"); } -#endif + if (host->vcc == NULL) { /* fall-back to platform data */ if (host->pdata && host->pdata->ocr_avail) @@ -171,12 +170,17 @@ static inline void mxcmci_init_ocr(struct mxcmci_host *host) } } -static inline void mxcmci_set_power(struct mxcmci_host *host, unsigned int vdd) +static inline void mxcmci_set_power(struct mxcmci_host *host, + unsigned char power_mode, + unsigned int vdd) { -#ifdef CONFIG_REGULATOR - if (host->vcc) - mmc_regulator_set_ocr(host->vcc, vdd); -#endif + if (host->vcc) { + if (power_mode == MMC_POWER_UP) + mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); + else if (power_mode == MMC_POWER_OFF) + mmc_regulator_set_ocr(host->mmc, host->vcc, 0); + } + if (host->pdata && host->pdata->setpower) host->pdata->setpower(mmc_dev(host->mmc), vdd); } @@ -716,7 +720,7 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; if (host->power_mode != ios->power_mode) { - mxcmci_set_power(host, ios->vdd); + mxcmci_set_power(host, ios->power_mode, ios->vdd); host->power_mode = ios->power_mode; if (ios->power_mode == MMC_POWER_ON) -- cgit v1.2.3 From 17d8020d9a4ee7d5965996ea75636dc3d058963f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 22 Nov 2010 16:47:51 +0800 Subject: mmc: mxcmmc: remove a unnecessary release_resource() call Remove release_resource() after release_mem_region(). Signed-off-by: Axel Lin Acked-by: Sascha Hauer Signed-off-by: Chris Ball --- drivers/mmc/host/mxcmmc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2b9f7c856700..4428594261c5 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -967,7 +967,6 @@ static int mxcmci_remove(struct platform_device *pdev) clk_put(host->clk); release_mem_region(host->res->start, resource_size(host->res)); - release_resource(host->res); mmc_free_host(mmc); -- cgit v1.2.3 From 26daa1ed40c6b31b4220581431982814c47c608a Mon Sep 17 00:00:00 2001 From: Jennifer Li Date: Wed, 17 Nov 2010 23:01:59 -0500 Subject: mmc: sdhci: Disable ADMA on some O2Micro SD/MMC parts. This patch disables the broken ADMA on selected O2Micro devices. Signed-off-by: Jennifer Li Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 112 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 5 ++ 2 files changed, 117 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 3d9c2460d437..831cf91b644a 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -176,6 +176,74 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, }; +/* O2Micro extra registers */ +#define O2_SD_LOCK_WP 0xD3 +#define O2_SD_MULTI_VCC3V 0xEE +#define O2_SD_CLKREQ 0xEC +#define O2_SD_CAPS 0xE0 +#define O2_SD_ADMA1 0xE2 +#define O2_SD_ADMA2 0xE7 +#define O2_SD_INF_MOD 0xF1 + +static int o2_probe(struct sdhci_pci_chip *chip) +{ + int ret; + u8 scratch; + + switch (chip->pdev->device) { + case PCI_DEVICE_ID_O2_8220: + case PCI_DEVICE_ID_O2_8221: + case PCI_DEVICE_ID_O2_8320: + case PCI_DEVICE_ID_O2_8321: + /* This extra setup is required due to broken ADMA. */ + ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + + /* Set Multi 3 to VCC3V# */ + pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); + + /* Disable CLK_REQ# support after media DET */ + ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch); + if (ret) + return ret; + scratch |= 0x20; + pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); + + /* Choose capabilities, enable SDMA. We have to write 0x01 + * to the capabilities register first to unlock it. + */ + ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); + if (ret) + return ret; + scratch |= 0x01; + pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); + pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); + + /* Disable ADMA1/2 */ + pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); + pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); + + /* Disable the infinite transfer mode */ + ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch); + if (ret) + return ret; + scratch |= 0x08; + pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); + + /* Lock WP */ + ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); + if (ret) + return ret; + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + } + + return 0; +} + static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) { u8 scratch; @@ -339,6 +407,10 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) return 0; } +static const struct sdhci_pci_fixes sdhci_o2 = { + .probe = o2_probe, +}; + static const struct sdhci_pci_fixes sdhci_jmicron = { .probe = jmicron_probe, @@ -589,6 +661,46 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio, }, + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_8120, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_8220, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_8221, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_8320, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + + { + .vendor = PCI_VENDOR_ID_O2, + .device = PCI_DEVICE_ID_O2_8321, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_o2, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index cb845c16ad7d..7a58875cdad5 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1650,6 +1650,11 @@ #define PCI_DEVICE_ID_O2_6836 0x6836 #define PCI_DEVICE_ID_O2_6812 0x6872 #define PCI_DEVICE_ID_O2_6933 0x6933 +#define PCI_DEVICE_ID_O2_8120 0x8120 +#define PCI_DEVICE_ID_O2_8220 0x8220 +#define PCI_DEVICE_ID_O2_8221 0x8221 +#define PCI_DEVICE_ID_O2_8320 0x8320 +#define PCI_DEVICE_ID_O2_8321 0x8321 #define PCI_VENDOR_ID_3DFX 0x121a #define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 -- cgit v1.2.3 From 04566831a703ae3ef4b49a2deae261c9ed26e020 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 8 Nov 2010 21:36:50 -0500 Subject: mmc: Aggressive clock gating framework This patch modifies the MMC core code to optionally call the set_ios() operation on the driver with the clock frequency set to 0 (gate) after a grace period of at least 8 MCLK cycles, then restore it (ungate) before any new request. This gives the driver the option to shut down the MCI clock to the MMC/SD card when the clock frequency is 0, i.e. the core has stated that the MCI clock does not need to be generated. It is inspired by existing clock gating code found in the OMAP and Atmel drivers and brings this up to the host abstraction. Gating is performed before and after any MMC request. This patchset implements this for the MMCI/PL180 MMC/SD host controller, but it should be simple to switch OMAP/Atmel over to using this instead. mmc_set_{gated,ungated}() add variable protection to the state holders for the clock gating code. This is particularly important when ordinary .set_ios() calls would race with the .set_ios() call resulting from a delayed gate operation. Signed-off-by: Linus Walleij Reviewed-by: Chris Ball Tested-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/Kconfig | 11 +++ drivers/mmc/core/core.c | 62 +++++++++++++- drivers/mmc/core/core.h | 3 + drivers/mmc/core/debugfs.c | 5 ++ drivers/mmc/core/host.c | 205 ++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/host.h | 21 +++++ include/linux/mmc/host.h | 10 +++ 7 files changed, 315 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index bb22ffd76ef8..ef103871517f 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -16,3 +16,14 @@ config MMC_UNSAFE_RESUME This option sets a default which can be overridden by the module parameter "removable=0" or "removable=1". + +config MMC_CLKGATE + bool "MMC host clock gating (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + This will attempt to aggressively gate the clock to the MMC card. + This is done to save power due to gating off the logic and bus + noise when the MMC card is not in use. Your host driver has to + support handling this in order for it to be of any use. + + If unsure, say N. diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a3a780faf85a..722af2dce3bb 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -130,6 +130,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) if (mrq->done) mrq->done(mrq); + + mmc_host_clk_gate(host); } } @@ -190,6 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->stop->mrq = mrq; } } + mmc_host_clk_ungate(host); host->ops->request(host, mrq); } @@ -296,7 +299,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) timeout_us = data->timeout_ns / 1000; timeout_us += data->timeout_clks * 1000 / - (card->host->ios.clock / 1000); + (mmc_host_clk_rate(card->host) / 1000); if (data->flags & MMC_DATA_WRITE) /* @@ -614,6 +617,8 @@ static inline void mmc_set_ios(struct mmc_host *host) ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width, ios->timing); + if (ios->clock > 0) + mmc_set_ungated(host); host->ops->set_ios(host, ios); } @@ -641,6 +646,61 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz) mmc_set_ios(host); } +#ifdef CONFIG_MMC_CLKGATE +/* + * This gates the clock by setting it to 0 Hz. + */ +void mmc_gate_clock(struct mmc_host *host) +{ + unsigned long flags; + + spin_lock_irqsave(&host->clk_lock, flags); + host->clk_old = host->ios.clock; + host->ios.clock = 0; + host->clk_gated = true; + spin_unlock_irqrestore(&host->clk_lock, flags); + mmc_set_ios(host); +} + +/* + * This restores the clock from gating by using the cached + * clock value. + */ +void mmc_ungate_clock(struct mmc_host *host) +{ + /* + * We should previously have gated the clock, so the clock shall + * be 0 here! The clock may however be 0 during initialization, + * when some request operations are performed before setting + * the frequency. When ungate is requested in that situation + * we just ignore the call. + */ + if (host->clk_old) { + BUG_ON(host->ios.clock); + /* This call will also set host->clk_gated to false */ + mmc_set_clock(host, host->clk_old); + } +} + +void mmc_set_ungated(struct mmc_host *host) +{ + unsigned long flags; + + /* + * We've been given a new frequency while the clock is gated, + * so make sure we regard this as ungating it. + */ + spin_lock_irqsave(&host->clk_lock, flags); + host->clk_gated = false; + spin_unlock_irqrestore(&host->clk_lock, flags); +} + +#else +void mmc_set_ungated(struct mmc_host *host) +{ +} +#endif + /* * Change the bus mode (open drain/push-pull) of a host. */ diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 77240cd11bcf..026c975b99a9 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -33,6 +33,9 @@ void mmc_init_erase(struct mmc_card *card); void mmc_set_chip_select(struct mmc_host *host, int mode); void mmc_set_clock(struct mmc_host *host, unsigned int hz); +void mmc_gate_clock(struct mmc_host *host); +void mmc_ungate_clock(struct mmc_host *host); +void mmc_set_ungated(struct mmc_host *host); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_width(struct mmc_host *host, unsigned int width); void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index eed1405fd742..998797ed67a6 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -183,6 +183,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) &mmc_clock_fops)) goto err_node; +#ifdef CONFIG_MMC_CLKGATE + if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), + root, &host->clk_delay)) + goto err_node; +#endif return; err_node: diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 10b8af27e03a..92e33703e437 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -3,6 +3,7 @@ * * Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright (C) 2007-2008 Pierre Ossman + * Copyright (C) 2010 Linus Walleij * * 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 @@ -20,6 +21,7 @@ #include #include +#include #include "core.h" #include "host.h" @@ -50,6 +52,204 @@ void mmc_unregister_host_class(void) static DEFINE_IDR(mmc_host_idr); static DEFINE_SPINLOCK(mmc_host_lock); +#ifdef CONFIG_MMC_CLKGATE + +/* + * Enabling clock gating will make the core call out to the host + * once up and once down when it performs a request or card operation + * intermingled in any fashion. The driver will see this through + * set_ios() operations with ios.clock field set to 0 to gate (disable) + * the block clock, and to the old frequency to enable it again. + */ +static void mmc_host_clk_gate_delayed(struct mmc_host *host) +{ + unsigned long tick_ns; + unsigned long freq = host->ios.clock; + unsigned long flags; + + if (!freq) { + pr_debug("%s: frequency set to 0 in disable function, " + "this means the clock is already disabled.\n", + mmc_hostname(host)); + return; + } + /* + * New requests may have appeared while we were scheduling, + * then there is no reason to delay the check before + * clk_disable(). + */ + spin_lock_irqsave(&host->clk_lock, flags); + + /* + * Delay n bus cycles (at least 8 from MMC spec) before attempting + * to disable the MCI block clock. The reference count may have + * gone up again after this delay due to rescheduling! + */ + if (!host->clk_requests) { + spin_unlock_irqrestore(&host->clk_lock, flags); + tick_ns = DIV_ROUND_UP(1000000000, freq); + ndelay(host->clk_delay * tick_ns); + } else { + /* New users appeared while waiting for this work */ + spin_unlock_irqrestore(&host->clk_lock, flags); + return; + } + mutex_lock(&host->clk_gate_mutex); + spin_lock_irqsave(&host->clk_lock, flags); + if (!host->clk_requests) { + spin_unlock_irqrestore(&host->clk_lock, flags); + /* This will set host->ios.clock to 0 */ + mmc_gate_clock(host); + spin_lock_irqsave(&host->clk_lock, flags); + pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); + } + spin_unlock_irqrestore(&host->clk_lock, flags); + mutex_unlock(&host->clk_gate_mutex); +} + +/* + * Internal work. Work to disable the clock at some later point. + */ +static void mmc_host_clk_gate_work(struct work_struct *work) +{ + struct mmc_host *host = container_of(work, struct mmc_host, + clk_gate_work); + + mmc_host_clk_gate_delayed(host); +} + +/** + * mmc_host_clk_ungate - ungate hardware MCI clocks + * @host: host to ungate. + * + * Makes sure the host ios.clock is restored to a non-zero value + * past this call. Increase clock reference count and ungate clock + * if we're the first user. + */ +void mmc_host_clk_ungate(struct mmc_host *host) +{ + unsigned long flags; + + mutex_lock(&host->clk_gate_mutex); + spin_lock_irqsave(&host->clk_lock, flags); + if (host->clk_gated) { + spin_unlock_irqrestore(&host->clk_lock, flags); + mmc_ungate_clock(host); + spin_lock_irqsave(&host->clk_lock, flags); + pr_debug("%s: ungated MCI clock\n", mmc_hostname(host)); + } + host->clk_requests++; + spin_unlock_irqrestore(&host->clk_lock, flags); + mutex_unlock(&host->clk_gate_mutex); +} + +/** + * mmc_host_may_gate_card - check if this card may be gated + * @card: card to check. + */ +static bool mmc_host_may_gate_card(struct mmc_card *card) +{ + /* If there is no card we may gate it */ + if (!card) + return true; + /* + * Don't gate SDIO cards! These need to be clocked at all times + * since they may be independent systems generating interrupts + * and other events. The clock requests counter from the core will + * go down to zero since the core does not need it, but we will not + * gate the clock, because there is somebody out there that may still + * be using it. + */ + if (mmc_card_sdio(card)) + return false; + + return true; +} + +/** + * mmc_host_clk_gate - gate off hardware MCI clocks + * @host: host to gate. + * + * Calls the host driver with ios.clock set to zero as often as possible + * in order to gate off hardware MCI clocks. Decrease clock reference + * count and schedule disabling of clock. + */ +void mmc_host_clk_gate(struct mmc_host *host) +{ + unsigned long flags; + + spin_lock_irqsave(&host->clk_lock, flags); + host->clk_requests--; + if (mmc_host_may_gate_card(host->card) && + !host->clk_requests) + schedule_work(&host->clk_gate_work); + spin_unlock_irqrestore(&host->clk_lock, flags); +} + +/** + * mmc_host_clk_rate - get current clock frequency setting + * @host: host to get the clock frequency for. + * + * Returns current clock frequency regardless of gating. + */ +unsigned int mmc_host_clk_rate(struct mmc_host *host) +{ + unsigned long freq; + unsigned long flags; + + spin_lock_irqsave(&host->clk_lock, flags); + if (host->clk_gated) + freq = host->clk_old; + else + freq = host->ios.clock; + spin_unlock_irqrestore(&host->clk_lock, flags); + return freq; +} + +/** + * mmc_host_clk_init - set up clock gating code + * @host: host with potential clock to control + */ +static inline void mmc_host_clk_init(struct mmc_host *host) +{ + host->clk_requests = 0; + /* Hold MCI clock for 8 cycles by default */ + host->clk_delay = 8; + host->clk_gated = false; + INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); + spin_lock_init(&host->clk_lock); + mutex_init(&host->clk_gate_mutex); +} + +/** + * mmc_host_clk_exit - shut down clock gating code + * @host: host with potential clock to control + */ +static inline void mmc_host_clk_exit(struct mmc_host *host) +{ + /* + * Wait for any outstanding gate and then make sure we're + * ungated before exiting. + */ + if (cancel_work_sync(&host->clk_gate_work)) + mmc_host_clk_gate_delayed(host); + if (host->clk_gated) + mmc_host_clk_ungate(host); + BUG_ON(host->clk_requests > 0); +} + +#else + +static inline void mmc_host_clk_init(struct mmc_host *host) +{ +} + +static inline void mmc_host_clk_exit(struct mmc_host *host) +{ +} + +#endif + /** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure @@ -82,6 +282,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->class_dev.class = &mmc_host_class; device_initialize(&host->class_dev); + mmc_host_clk_init(host); + spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); @@ -163,6 +365,8 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); led_trigger_unregister_simple(host->led); + + mmc_host_clk_exit(host); } EXPORT_SYMBOL(mmc_remove_host); @@ -183,4 +387,3 @@ void mmc_free_host(struct mmc_host *host) } EXPORT_SYMBOL(mmc_free_host); - diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 8c87e1109a34..de199f911928 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -10,10 +10,31 @@ */ #ifndef _MMC_CORE_HOST_H #define _MMC_CORE_HOST_H +#include int mmc_register_host_class(void); void mmc_unregister_host_class(void); +#ifdef CONFIG_MMC_CLKGATE +void mmc_host_clk_ungate(struct mmc_host *host); +void mmc_host_clk_gate(struct mmc_host *host); +unsigned int mmc_host_clk_rate(struct mmc_host *host); + +#else +static inline void mmc_host_clk_ungate(struct mmc_host *host) +{ +} + +static inline void mmc_host_clk_gate(struct mmc_host *host) +{ +} + +static inline unsigned int mmc_host_clk_rate(struct mmc_host *host) +{ + return host->ios.clock; +} +#endif + void mmc_host_deeper_disable(struct work_struct *work); #endif diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 30f6fad99a58..381c77fd4dca 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -172,6 +172,16 @@ struct mmc_host { mmc_pm_flag_t pm_caps; /* supported pm features */ +#ifdef CONFIG_MMC_CLKGATE + int clk_requests; /* internal reference counter */ + unsigned int clk_delay; /* number of MCI clk hold cycles */ + bool clk_gated; /* clock gated */ + struct work_struct clk_gate_work; /* delayed clock gate */ + unsigned int clk_old; /* old clock value cache */ + spinlock_t clk_lock; /* lock for clk fields */ + struct mutex clk_gate_mutex; /* mutex for clock gating */ +#endif + /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned short max_segs; /* see blk_queue_max_segments */ -- cgit v1.2.3 From e8120ad129c160ff5b2e2b197d025a2cd661c2f2 Mon Sep 17 00:00:00 2001 From: Philip Rakity Date: Tue, 30 Nov 2010 00:55:23 -0500 Subject: mmc: sdhci: print SD Command and CAPABILITY_1 when dumping registers More information should be shown when sdhci_dumpregs is called. Knowing the command is useful for debugging, and Capability 1 is useful for SD v3. Signed-off-by: Philip Rakity Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 5 ++++- drivers/mmc/host/sdhci.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a25db426c910..8a74fcbfe13b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -77,8 +77,11 @@ static void sdhci_dumpregs(struct sdhci_host *host) printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", sdhci_readw(host, SDHCI_ACMD12_ERR), sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Max curr: 0x%08x\n", + printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES), + sdhci_readl(host, SDHCI_CAPABILITIES_1)); + printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", + sdhci_readw(host, SDHCI_COMMAND), sdhci_readl(host, SDHCI_MAX_CURRENT)); if (host->flags & SDHCI_USE_ADMA) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e42d7f00c060..1efe7dc5255b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -165,7 +165,7 @@ #define SDHCI_CAN_VDD_180 0x04000000 #define SDHCI_CAN_64BIT 0x10000000 -/* 44-47 reserved for more caps */ +#define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_MAX_CURRENT 0x48 -- cgit v1.2.3 From 150ee73d1b35936aafc5fd3b39a7291b1f66de07 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 19:04:30 -0800 Subject: mmc: davinci_mmc: Remove unnecessary semicolon Signed-off-by: Joe Perches Signed-off-by: Chris Ball --- drivers/mmc/host/davinci_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index e15547cf701f..b643ddef4f70 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -480,7 +480,7 @@ static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, struct scatterlist *sg; unsigned sg_len; unsigned bytes_left = host->bytes_left; - const unsigned shift = ffs(rw_threshold) - 1;; + const unsigned shift = ffs(rw_threshold) - 1; if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { template = &host->tx_template; -- cgit v1.2.3 From 8f230f454fe04ba326ffaead3a6b88dcf44eaf4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Dec 2010 10:04:30 +0100 Subject: mmc: Add support for JMicron 388 SD/MMC controller JMicron 388 SD/MMC combo controller supports the 1.8V low-voltage for SD, but MMC doesn't work with the low-voltage, resulting in an error at probing. This patch adds the support for multiple voltage mask per device type, so that SD works with 1.8V while MMC forces 3.3V. Here new ocr_avail_* fields for each device are introduced, so that the actual OCR mask is switched dynamically. Also, the restriction of low-voltage in core/sd.c is removed when the bit is allowed explicitly via ocr_avail_sd mask. This patch was rewritten from scratch based on Aries' original code. Signed-off-by: Aries Lee Signed-off-by: Takashi Iwai Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 2 ++ drivers/mmc/core/sd.c | 5 ++++- drivers/mmc/core/sdio.c | 2 ++ drivers/mmc/host/sdhci-pci.c | 47 ++++++++++++++++++++++++++++++++++++++------ drivers/mmc/host/sdhci.c | 23 +++++++++++++++++----- include/linux/mmc/host.h | 3 +++ include/linux/mmc/sdhci.h | 4 ++++ include/linux/pci_ids.h | 2 ++ 8 files changed, 76 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 77f93c3b8808..76bb621e9aa9 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -745,6 +745,8 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) WARN_ON(!host->claimed); mmc_attach_bus_ops(host); + if (host->ocr_avail_mmc) + host->ocr_avail = host->ocr_avail_mmc; /* * We need to get OCR a different way for SPI. diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 49da4dffd28e..de062ebd8b26 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -772,6 +772,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) WARN_ON(!host->claimed); mmc_sd_attach_bus_ops(host); + if (host->ocr_avail_sd) + host->ocr_avail = host->ocr_avail_sd; /* * We need to get OCR a different way for SPI. @@ -795,7 +797,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) ocr &= ~0x7F; } - if (ocr & MMC_VDD_165_195) { + if ((ocr & MMC_VDD_165_195) && + !(host->ocr_avail_sd & MMC_VDD_165_195)) { printk(KERN_WARNING "%s: SD card claims to support the " "incompletely defined 'low voltage range'. This " "will be ignored.\n", mmc_hostname(host)); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index efef5f94ac42..c18810ab6465 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -700,6 +700,8 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_sdio_ops); + if (host->ocr_avail_sdio) + host->ocr_avail = host->ocr_avail_sdio; /* * Sanity check the voltages that the card claims to diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 831cf91b644a..d2638ffc4ed2 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -272,6 +272,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) static int jmicron_probe(struct sdhci_pci_chip *chip) { int ret; + u16 mmcdev = 0; if (chip->pdev->revision == 0) { chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | @@ -293,12 +294,17 @@ static int jmicron_probe(struct sdhci_pci_chip *chip) * 2. The MMC interface has a lower subfunction number * than the SD interface. */ - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) { + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) + mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC; + else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD) + mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD; + + if (mmcdev) { struct pci_dev *sd_dev; sd_dev = NULL; while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON, - PCI_DEVICE_ID_JMICRON_JMB38X_MMC, sd_dev)) != NULL) { + mmcdev, sd_dev)) != NULL) { if ((PCI_SLOT(chip->pdev->devfn) == PCI_SLOT(sd_dev->devfn)) && (chip->pdev->bus == sd_dev->bus)) @@ -358,11 +364,21 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot) slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; } + /* JM388 MMC doesn't support 1.8V while SD supports it */ + if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { + slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 | + MMC_VDD_29_30 | MMC_VDD_30_31 | + MMC_VDD_165_195; /* allow 1.8V */ + slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 | + MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */ + } + /* * The secondary interface requires a bit set to get the * interrupts. */ - if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) + if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) jmicron_enable_mmc(slot->host, 1); return 0; @@ -373,7 +389,8 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) if (dead) return; - if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) + if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) jmicron_enable_mmc(slot->host, 0); } @@ -381,7 +398,8 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state) { int i; - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) { + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { for (i = 0;i < chip->num_slots;i++) jmicron_enable_mmc(chip->slots[i]->host, 0); } @@ -393,7 +411,8 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) { int ret, i; - if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) { + if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC || + chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) { for (i = 0;i < chip->num_slots;i++) jmicron_enable_mmc(chip->slots[i]->host, 1); } @@ -581,6 +600,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = (kernel_ulong_t)&sdhci_jmicron, }, + { + .vendor = PCI_VENDOR_ID_JMICRON, + .device = PCI_DEVICE_ID_JMICRON_JMB388_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_jmicron, + }, + + { + .vendor = PCI_VENDOR_ID_JMICRON, + .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_jmicron, + }, + { .vendor = PCI_VENDOR_ID_SYSKONNECT, .device = 0x8000, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8a74fcbfe13b..55698864c2cd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1739,7 +1739,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host); int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; - unsigned int caps; + unsigned int caps, ocr_avail; int ret; WARN_ON(host == NULL); @@ -1893,13 +1893,26 @@ int sdhci_add_host(struct sdhci_host *host) mmc_card_is_removable(mmc)) mmc->caps |= MMC_CAP_NEEDS_POLL; - mmc->ocr_avail = 0; + ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) - mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; + ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; if (caps & SDHCI_CAN_VDD_300) - mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; + ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; if (caps & SDHCI_CAN_VDD_180) - mmc->ocr_avail |= MMC_VDD_165_195; + ocr_avail |= MMC_VDD_165_195; + + mmc->ocr_avail = ocr_avail; + mmc->ocr_avail_sdio = ocr_avail; + if (host->ocr_avail_sdio) + mmc->ocr_avail_sdio &= host->ocr_avail_sdio; + mmc->ocr_avail_sd = ocr_avail; + if (host->ocr_avail_sd) + mmc->ocr_avail_sd &= host->ocr_avail_sd; + else /* normal SD controllers don't support 1.8V */ + mmc->ocr_avail_sd &= ~MMC_VDD_165_195; + mmc->ocr_avail_mmc = ocr_avail; + if (host->ocr_avail_mmc) + mmc->ocr_avail_mmc &= host->ocr_avail_mmc; if (mmc->ocr_avail == 0) { printk(KERN_ERR "%s: Hardware doesn't report any " diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 381c77fd4dca..4a9d9d2589c7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -131,6 +131,9 @@ struct mmc_host { unsigned int f_max; unsigned int f_init; u32 ocr_avail; + u32 ocr_avail_sdio; /* SDIO-specific OCR */ + u32 ocr_avail_sd; /* SD-specific OCR */ + u32 ocr_avail_mmc; /* MMC-specific OCR */ struct notifier_block pm_notify; #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 1fdc673f2396..0d953f513d81 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -139,6 +139,10 @@ struct sdhci_host { unsigned int caps; /* Alternative capabilities */ + unsigned int ocr_avail_sdio; /* OCR bit masks */ + unsigned int ocr_avail_sd; + unsigned int ocr_avail_mmc; + unsigned long private[0] ____cacheline_aligned; }; #endif /* __SDHCI_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 7a58875cdad5..2f17b4ccbb58 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2368,6 +2368,8 @@ #define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 #define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382 #define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 +#define PCI_DEVICE_ID_JMICRON_JMB388_SD 0x2391 +#define PCI_DEVICE_ID_JMICRON_JMB388_ESD 0x2392 #define PCI_VENDOR_ID_KORENIX 0x1982 #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 -- cgit v1.2.3 From 30201e7f3ac639fe98fcd25d40346b65dde9ecba Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 28 Nov 2010 07:21:28 +0200 Subject: mmc: skip detection of nonremovable cards on rescan mmc_rescan() checks whether registered cards are still present before skipping them, by calling the bus-specific ->detect() handler. With buses that support runtime PM, the card may be powered off at this point, so they need to be powered on and fully reinitialized before ->detect() executes. This whole process is redundant with nonremovable cards; in those cases, we can safely skip calling ->detect() and implicitly assume its success. Signed-off-by: Ohad Ben-Cohen Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 722af2dce3bb..9683d4d3fced 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1506,8 +1506,12 @@ void mmc_rescan(struct work_struct *work) mmc_bus_get(host); - /* if there is a card registered, check whether it is still present */ - if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead) + /* + * if there is a _removable_ card registered, check whether it is + * still present + */ + if (host->bus_ops && host->bus_ops->detect && !host->bus_dead + && mmc_card_is_removable(host)) host->bus_ops->detect(host); mmc_bus_put(host); -- cgit v1.2.3 From e594573d790bd7e269f05955d316b88f7be0c14a Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 28 Nov 2010 07:21:30 +0200 Subject: mmc: sdio: don't power up cards on system suspend Initial SDIO runtime PM implementation took a conservative approach of powering up cards (and fully reinitializing them) on system suspend, just before the suspend handlers of the relevant drivers were executed. To avoid redundant power and reinitialization cycles, this patch removes this behavior: if a card is already powered off when system suspend kicks in, it is left at that state. If a card is active when a system sleep starts, everything is straightforward and works exactly like before. But if the card was already suspended before the sleep began, then when the MMC core powers it back up on resume, its run-time PM status has to be updated to reflect the actual post-system sleep status. The technique to do that is borrowed from the I2C runtime PM implementation (for more info see Documentation/power/runtime_pm.txt). Signed-off-by: Ohad Ben-Cohen Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 13 +++++++++++++ drivers/mmc/core/sdio_bus.c | 32 -------------------------------- 2 files changed, 13 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9683d4d3fced..241ffb28351c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -1785,6 +1786,18 @@ int mmc_resume_host(struct mmc_host *host) if (!(host->pm_flags & MMC_PM_KEEP_POWER)) { mmc_power_up(host); mmc_select_voltage(host, host->ocr); + /* + * Tell runtime PM core we just powered up the card, + * since it still believes the card is powered off. + * Note that currently runtime PM is only enabled + * for SDIO cards that are MMC_CAP_POWER_OFF_CARD + */ + if (mmc_card_sdio(host->card) && + (host->caps & MMC_CAP_POWER_OFF_CARD)) { + pm_runtime_disable(&host->card->dev); + pm_runtime_set_active(&host->card->dev); + pm_runtime_enable(&host->card->dev); + } } BUG_ON(!host->bus_ops->resume); err = host->bus_ops->resume(host); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 203da443e339..d29b9c36919a 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -197,44 +197,12 @@ out: #ifdef CONFIG_PM_RUNTIME -static int sdio_bus_pm_prepare(struct device *dev) -{ - struct sdio_func *func = dev_to_sdio_func(dev); - - /* - * Resume an SDIO device which was suspended at run time at this - * point, in order to allow standard SDIO suspend/resume paths - * to keep working as usual. - * - * Ultimately, the SDIO driver itself will decide (in its - * suspend handler, or lack thereof) whether the card should be - * removed or kept, and if kept, at what power state. - * - * At this point, PM core have increased our use count, so it's - * safe to directly resume the device. After system is resumed - * again, PM core will drop back its runtime PM use count, and if - * needed device will be suspended again. - * - * The end result is guaranteed to be a power state that is - * coherent with the device's runtime PM use count. - * - * The return value of pm_runtime_resume is deliberately unchecked - * since there is little point in failing system suspend if a - * device can't be resumed. - */ - if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) - pm_runtime_resume(dev); - - return 0; -} - static const struct dev_pm_ops sdio_bus_pm_ops = { SET_RUNTIME_PM_OPS( pm_generic_runtime_suspend, pm_generic_runtime_resume, pm_generic_runtime_idle ) - .prepare = sdio_bus_pm_prepare, }; #define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) -- cgit v1.2.3 From 080bc9774b6f1e3866747b18631bad26f47c22ce Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Sun, 28 Nov 2010 07:21:29 +0200 Subject: mmc: sdio: don't reinitialize nonremovable powered-resumed cards Upon system resume, SDIO core must reinitialize cards that were powered off during suspend. If the card had its power kept during suspend (and thus it is 'powered-resumed'), SDIO core performs only a limited reinitializing, mainly needed to make sure that the card wasn't removed/replaced. If a __nonremovable__ card is powered-resumed, we can safely skip the reinitializing phase. Note: 9b966aa (mmc: sdio: fully reconfigure oldcard on resume) removed the bus width reconfiguration since mmc_sdio_init_card already does it. It is brought back now in case mmc_sdio_init_card is skipped. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Chris Ball --- drivers/mmc/core/sdio.c | 16 ++++++++++++++-- include/linux/mmc/host.h | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c18810ab6465..82f4b9008987 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -627,15 +627,27 @@ static int mmc_sdio_suspend(struct mmc_host *host) static int mmc_sdio_resume(struct mmc_host *host) { - int i, err; + int i, err = 0; BUG_ON(!host); BUG_ON(!host->card); /* Basic card reinitialization. */ mmc_claim_host(host); - err = mmc_sdio_init_card(host, host->ocr, host->card, + + /* No need to reinitialize powered-resumed nonremovable cards */ + if (mmc_card_is_removable(host) || !mmc_card_is_powered_resumed(host)) + err = mmc_sdio_init_card(host, host->ocr, host->card, (host->pm_flags & MMC_PM_KEEP_POWER)); + else if (mmc_card_is_powered_resumed(host)) { + /* We may have switched to 1-bit mode during suspend */ + err = sdio_enable_4bit_bus(host->card); + if (err > 0) { + mmc_set_bus_width(host, MMC_BUS_WIDTH_4); + err = 0; + } + } + if (!err && host->sdio_irqs) mmc_signal_sdio_irq(host); mmc_release_host(host); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 4a9d9d2589c7..3a85e73a38a9 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -320,5 +320,10 @@ static inline int mmc_card_is_removable(struct mmc_host *host) return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable; } +static inline int mmc_card_is_powered_resumed(struct mmc_host *host) +{ + return host->pm_flags & MMC_PM_KEEP_POWER; +} + #endif -- cgit v1.2.3 From e6f29a8dc1602e170daf955233891a9130573a55 Mon Sep 17 00:00:00 2001 From: Michal Miroslaw Date: Thu, 2 Dec 2010 23:38:12 +0100 Subject: mmc: fix detection of memory part of SD-combo card with broken SDIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of failure, mmc_attach_sdio() will power off the SD bus. Power it up and reinitialize before trying SD memory detection. Reported-by: Sahitya Tummala Signed-off-by: Michał Mirosław Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 241ffb28351c..97e0624eb9b6 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1569,6 +1569,11 @@ void mmc_rescan(struct work_struct *work) * Try SDMEM (but not MMC) even if SDIO * is broken. */ + mmc_power_up(host); + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->ocr_avail); + if (mmc_send_app_op_cond(host, 0, &ocr)) goto out_fail; -- cgit v1.2.3 From 22113efd00491310da802f3b1a9a66cfcf415fac Mon Sep 17 00:00:00 2001 From: Aries Lee Date: Wed, 15 Dec 2010 08:14:24 +0100 Subject: mmc: Test bus-width for old MMC devices Some old MMC devices fail with the 4/8 bits the driver tries to use exclusively. This patch adds a test for the given bus setup and falls back to the lower bit mode (until 1-bit mode) when the test fails. [Major rework and refactoring by tiwai] [Quirk addition and many fixes by prakity] Signed-off-by: Aries Lee Signed-off-by: Takashi Iwai Signed-off-by: Philip Rakity Tested-by: Philip Rakity Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 76 +++++++++++++++++++++------------- drivers/mmc/core/mmc_ops.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/mmc_ops.h | 1 + drivers/mmc/host/sdhci.c | 7 +++- drivers/mmc/host/sdhci.h | 1 + include/linux/mmc/host.h | 1 + include/linux/mmc/mmc.h | 2 + 7 files changed, 159 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 76bb621e9aa9..1d8409fcf155 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -534,39 +534,57 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { - unsigned ext_csd_bit, bus_width; - - if (host->caps & MMC_CAP_8_BIT_DATA) { - if (ddr) - ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8; - else - ext_csd_bit = EXT_CSD_BUS_WIDTH_8; - bus_width = MMC_BUS_WIDTH_8; - } else { - if (ddr) - ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4; - else - ext_csd_bit = EXT_CSD_BUS_WIDTH_4; - bus_width = MMC_BUS_WIDTH_4; + static unsigned ext_csd_bits[][2] = { + { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, + { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 }, + { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 }, + }; + static unsigned bus_widths[] = { + MMC_BUS_WIDTH_8, + MMC_BUS_WIDTH_4, + MMC_BUS_WIDTH_1 + }; + unsigned idx, bus_width = 0; + + if (host->caps & MMC_CAP_8_BIT_DATA) + idx = 0; + else + idx = 1; + for (; idx < ARRAY_SIZE(bus_widths); idx++) { + bus_width = bus_widths[idx]; + if (bus_width == MMC_BUS_WIDTH_1) + ddr = 0; /* no DDR for 1-bit width */ + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, + ext_csd_bits[idx][0]); + if (!err) { + /* + * If controller can't handle bus width test, + * use the highest bus width to maintain + * compatibility with previous MMC behavior. + */ + if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) + break; + mmc_set_bus_width_ddr(card->host, + bus_width, MMC_SDR_MODE); + err = mmc_bus_test(card, bus_width); + if (!err) + break; + } } - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, ext_csd_bit); - - if (err && err != -EBADMSG) - goto free_card; - + if (!err && ddr) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, + ext_csd_bits[idx][1]); + } if (err) { printk(KERN_WARNING "%s: switch to bus width %d ddr %d " - "failed\n", mmc_hostname(card->host), - 1 << bus_width, ddr); - err = 0; - } else { - if (ddr) - mmc_card_set_ddr_mode(card); - else - ddr = MMC_SDR_MODE; - + "failed\n", mmc_hostname(card->host), + 1 << bus_width, ddr); + goto free_card; + } else if (ddr) { + mmc_card_set_ddr_mode(card); mmc_set_bus_width_ddr(card->host, bus_width, ddr); } } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 326447c9ede8..60842f878ded 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -462,3 +462,104 @@ int mmc_send_status(struct mmc_card *card, u32 *status) return 0; } +static int +mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, + u8 len) +{ + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + u8 *data_buf; + u8 *test_buf; + int i, err; + static u8 testdata_8bit[8] = { 0x55, 0xaa, 0, 0, 0, 0, 0, 0 }; + static u8 testdata_4bit[4] = { 0x5a, 0, 0, 0 }; + + /* dma onto stack is unsafe/nonportable, but callers to this + * routine normally provide temporary on-stack buffers ... + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (!data_buf) + return -ENOMEM; + + if (len == 8) + test_buf = testdata_8bit; + else if (len == 4) + test_buf = testdata_4bit; + else { + printk(KERN_ERR "%s: Invalid bus_width %d\n", + mmc_hostname(host), len); + kfree(data_buf); + return -EINVAL; + } + + if (opcode == MMC_BUS_TEST_W) + memcpy(data_buf, test_buf, len); + + memset(&mrq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + mrq.cmd = &cmd; + mrq.data = &data; + cmd.opcode = opcode; + cmd.arg = 0; + + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = len; + data.blocks = 1; + if (opcode == MMC_BUS_TEST_R) + data.flags = MMC_DATA_READ; + else + data.flags = MMC_DATA_WRITE; + + data.sg = &sg; + data.sg_len = 1; + sg_init_one(&sg, data_buf, len); + mmc_wait_for_req(host, &mrq); + err = 0; + if (opcode == MMC_BUS_TEST_R) { + for (i = 0; i < len / 4; i++) + if ((test_buf[i] ^ data_buf[i]) != 0xff) { + err = -EIO; + break; + } + } + kfree(data_buf); + + if (cmd.error) + return cmd.error; + if (data.error) + return data.error; + + return err; +} + +int mmc_bus_test(struct mmc_card *card, u8 bus_width) +{ + int err, width; + + if (bus_width == MMC_BUS_WIDTH_8) + width = 8; + else if (bus_width == MMC_BUS_WIDTH_4) + width = 4; + else if (bus_width == MMC_BUS_WIDTH_1) + return 0; /* no need for test */ + else + return -EINVAL; + + /* + * Ignore errors from BUS_TEST_W. BUS_TEST_R will fail if there + * is a problem. This improves chances that the test will work. + */ + mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width); + err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); + return err; +} diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 653eb8e84178..e6d44b8a18db 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -26,6 +26,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_card_sleepawake(struct mmc_host *host, int sleep); +int mmc_bus_test(struct mmc_card *card, u8 bus_width); #endif diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 55698864c2cd..d5febe584b05 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -23,6 +23,7 @@ #include +#include #include #include "sdhci.h" @@ -1521,7 +1522,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) if (intmask & SDHCI_INT_DATA_TIMEOUT) host->data->error = -ETIMEDOUT; - else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) + else if (intmask & SDHCI_INT_DATA_END_BIT) + host->data->error = -EILSEQ; + else if ((intmask & SDHCI_INT_DATA_CRC) && + SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) + != MMC_BUS_TEST_R) host->data->error = -EILSEQ; else if (intmask & SDHCI_INT_ADMA_ERROR) { printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 1efe7dc5255b..6e0969e40650 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -52,6 +52,7 @@ #define SDHCI_CMD_RESP_SHORT_BUSY 0x03 #define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) +#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f) #define SDHCI_RESPONSE 0x10 diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 3a85e73a38a9..bcb793ec7374 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -172,6 +172,7 @@ struct mmc_host { #define MMC_CAP_1_2V_DDR (1 << 12) /* can support */ /* DDR mode at 1.2V */ #define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */ +#define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */ mmc_pm_flag_t pm_caps; /* supported pm features */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 956fbd877692..612301f85d14 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -40,7 +40,9 @@ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_BUS_TEST_R 14 /* adtc R1 */ #define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_BUS_TEST_W 19 /* adtc R1 */ #define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ #define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ -- cgit v1.2.3 From d75c1084db5e4a30603729852046d0a87d4f7688 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Dec 2010 17:54:14 +0100 Subject: mmc: sdhci: Enable bus-width test for JMicron controllers Signed-off-by: Takashi Iwai Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index d2638ffc4ed2..0dc905b20eee 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -381,6 +381,8 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot) slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) jmicron_enable_mmc(slot->host, 1); + slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST; + return 0; } -- cgit v1.2.3 From b3824f2c6f16ef19060a53ef9345a124de175098 Mon Sep 17 00:00:00 2001 From: Jeongbae Seo Date: Fri, 8 Oct 2010 17:46:20 +0900 Subject: mmc: sdhci-s3c: Support additional host capabilities This patch adds support for additional host capabilities like SD/MMC high speed, SDHCI bus width, etc. Signed-off-by: Jeongbae Seo Signed-off-by: Kukjin Kim Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index aacb862ecc8a..a7710f557849 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -427,6 +427,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; + /* It supports additional host capabilities if needed */ + if (pdata->host_caps) + host->mmc->caps |= pdata->host_caps; + ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); -- cgit v1.2.3 From 253e0a7c3dc4bbbc69fc6bfd7c01bc4c9397a5e5 Mon Sep 17 00:00:00 2001 From: Jeongbae Seo Date: Fri, 8 Oct 2010 17:46:21 +0900 Subject: mmc: sdhci-s3c: Support controllers with no internal clock divider This patch supports controllers with no internal clock divider in SDHCI, such as the s5pc210 board. The external clock divider can be used to make a proper clock because SDHCI doesn't support internal clock divider by itself. If external clock divider type is selected, some functions related to clock control will be overrided by other functions. The current clock control index is added to let you know which clock bus is used for SDHCI when overriding functions. Checking functions are added into sdhci_s3c_consider_clock, because the clock divider step is different from that of host controller. Signed-off-by: Jeongbae Seo Cc: Jaehoon Chung Cc: Ben Dooks Signed-off-by: Kukjin Kim Acked-by: Kyungmin Park Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index a7710f557849..17203586305c 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -130,6 +130,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, if (!clksrc) return UINT_MAX; + /* + * Clock divider's step is different as 1 from that of host controller + * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL. + */ + if (ourhost->pdata->clk_type) { + rate = clk_round_rate(clksrc, wanted); + return wanted - rate; + } + rate = clk_get_rate(clksrc); for (div = 1; div < 256; div *= 2) { @@ -232,6 +241,42 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) return min; } +/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/ +static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + + return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX); +} + +/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */ +static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + + /* + * initial clock can be in the frequency range of + * 100KHz-400KHz, so we set it as max value. + */ + return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000); +} + +/* sdhci_cmu_set_clock - callback on clock change.*/ +static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_s3c *ourhost = to_s3c(host); + + /* don't bother if the clock is going off */ + if (clock == 0) + return; + + sdhci_s3c_set_clock(host, clock); + + clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + + host->clock = clock; +} + static struct sdhci_ops sdhci_s3c_ops = { .get_max_clock = sdhci_s3c_get_max_clk, .set_clock = sdhci_s3c_set_clock, @@ -361,6 +406,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) clks++; sc->clk_bus[ptr] = clk; + + /* + * save current clock index to know which clock bus + * is used later in overriding functions. + */ + sc->cur_clk = ptr; + clk_enable(clk); dev_info(dev, "clock source %d: %s (%ld Hz)\n", @@ -427,6 +479,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; + /* + * If controller does not have internal clock divider, + * we can use overriding functions instead of default. + */ + if (pdata->clk_type) { + sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; + sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; + sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; + } + /* It supports additional host capabilities if needed */ if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; -- cgit v1.2.3 From c288b85554097a3d1271f935c48b442280b2db9e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 22 Dec 2010 09:50:12 +0100 Subject: mmc: check for > 1 clk_requests when disabling gating Since we make sure the clock is enabled in the mmc_host_clk_exit() function we should expect a reference counter of 1, not 0. Signed-off-by: Linus Walleij Tested-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 92e33703e437..b3ac6c5bc5c6 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -235,7 +235,8 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) mmc_host_clk_gate_delayed(host); if (host->clk_gated) mmc_host_clk_ungate(host); - BUG_ON(host->clk_requests > 0); + /* There should be only one user now */ + WARN_ON(host->clk_requests > 1); } #else -- cgit v1.2.3 From 30652aa36b58d57fcc1a0acce51e391bbb6edf5e Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 1 Jan 2011 18:37:32 -0600 Subject: mmc: sdhci: add quirk for max len ADMA descriptors Some controllers misparse segment length 0 as being 0, not 65536. Add a quirk to deal with it. Signed-off-by: Olof Johansson Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 10 +++++++--- include/linux/mmc/sdhci.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d5febe584b05..9e15f41f87be 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1949,10 +1949,14 @@ int sdhci_add_host(struct sdhci_host *host) * of bytes. When doing hardware scatter/gather, each entry cannot * be larger than 64 KiB though. */ - if (host->flags & SDHCI_USE_ADMA) - mmc->max_seg_size = 65536; - else + if (host->flags & SDHCI_USE_ADMA) { + if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) + mmc->max_seg_size = 65535; + else + mmc->max_seg_size = 65536; + } else { mmc->max_seg_size = mmc->max_req_size; + } /* * Maximum block size. This varies from controller to controller and diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 0d953f513d81..83bd9f76709a 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -83,6 +83,8 @@ struct sdhci_host { #define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) /* Controller doesn't have HISPD bit field in HI-SPEED SD card */ #define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) +/* Controller treats ADMA descriptors with length 0000h incorrectly */ +#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3 From 03d2bfc878e4dff9e596accc7b7eccf947804a3c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 1 Jan 2011 23:52:56 -0500 Subject: mmc: add sdhci-tegra driver for Tegra SoCs SDHCI driver for Tegra. This driver plugs in as a new variant of sdhci-pltfm, using the platform data structure passed in to specify the GPIOs to use for card detect, write protect and card power enablement. Original driver (of which only the header file is left): Signed-off-by: Yvonne Yip The rest, which has been rewritten by now: Signed-off-by: Olof Johansson Reviewed-by: Wolfram Sang Acked-by: Mike Rapoport Signed-off-by: Chris Ball --- arch/arm/mach-tegra/include/mach/sdhci.h | 29 ++++ drivers/mmc/host/Kconfig | 10 ++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-pltfm.c | 3 + drivers/mmc/host/sdhci-pltfm.h | 1 + drivers/mmc/host/sdhci-tegra.c | 257 +++++++++++++++++++++++++++++++ 6 files changed, 301 insertions(+) create mode 100644 arch/arm/mach-tegra/include/mach/sdhci.h create mode 100644 drivers/mmc/host/sdhci-tegra.c (limited to 'drivers') diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h new file mode 100644 index 000000000000..3ad086e859c3 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/sdhci.h @@ -0,0 +1,29 @@ +/* + * include/asm-arm/arch-tegra/include/mach/sdhci.h + * + * Copyright (C) 2009 Palm, Inc. + * Author: Yvonne Yip + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#ifndef __ASM_ARM_ARCH_TEGRA_SDHCI_H +#define __ASM_ARM_ARCH_TEGRA_SDHCI_H + +#include + +struct tegra_sdhci_platform_data { + int cd_gpio; + int wp_gpio; + int power_gpio; + int is_8bit; +}; + +#endif diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index f8fa9efca8ee..9f47d38dcc7f 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -151,6 +151,16 @@ config MMC_SDHCI_DOVE If unsure, say N. +config MMC_SDHCI_TEGRA + tristate "SDHCI platform support for the Tegra SD/MMC Controller" + depends on MMC_SDHCI_PLTFM && ARCH_TEGRA + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Tegra SD/MMC controller. If you have a Tegra + platform with SD or MMC devices, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" depends on MMC_SDHCI && PLAT_SAMSUNG diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index d91364d4bf39..6d1ff9e27368 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -40,6 +40,7 @@ sdhci-platform-y := sdhci-pltfm.o sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o sdhci-platform-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o +sdhci-platform-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o sdhci-of-y := sdhci-of-core.o diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 91c6766c660c..dbab0407f4b6 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -172,6 +172,9 @@ static const struct platform_device_id sdhci_pltfm_ids[] = { #endif #ifdef CONFIG_MMC_SDHCI_DOVE { "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata }, +#endif +#ifdef CONFIG_MMC_SDHCI_TEGRA + { "sdhci-tegra", (kernel_ulong_t)&sdhci_tegra_pdata }, #endif { }, }; diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 62118b9f9d0a..ea2e44d9be5e 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -23,5 +23,6 @@ struct sdhci_pltfm_host { extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata; extern struct sdhci_pltfm_data sdhci_dove_pdata; +extern struct sdhci_pltfm_data sdhci_tegra_pdata; #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c new file mode 100644 index 000000000000..4823ee94a63f --- /dev/null +++ b/drivers/mmc/host/sdhci-tegra.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "sdhci.h" +#include "sdhci-pltfm.h" + +static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) +{ + u32 val; + + if (unlikely(reg == SDHCI_PRESENT_STATE)) { + /* Use wp_gpio here instead? */ + val = readl(host->ioaddr + reg); + return val | SDHCI_WRITE_PROTECT; + } + + return readl(host->ioaddr + reg); +} + +static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) +{ + if (unlikely(reg == SDHCI_HOST_VERSION)) { + /* Erratum: Version register is invalid in HW. */ + return SDHCI_SPEC_200; + } + + return readw(host->ioaddr + reg); +} + +static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) +{ + /* Seems like we're getting spurious timeout and crc errors, so + * disable signalling of them. In case of real errors software + * timers should take care of eventually detecting them. + */ + if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) + val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); + + writel(val, host->ioaddr + reg); + + if (unlikely(reg == SDHCI_INT_ENABLE)) { + /* Erratum: Must enable block gap interrupt detection */ + u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); + if (val & SDHCI_INT_CARD_INT) + gap_ctrl |= 0x8; + else + gap_ctrl &= ~0x8; + writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); + } +} + +static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); + struct tegra_sdhci_platform_data *plat; + + plat = pdev->dev.platform_data; + + if (!gpio_is_valid(plat->wp_gpio)) + return -1; + + return gpio_get_value(plat->wp_gpio); +} + +static irqreturn_t carddetect_irq(int irq, void *data) +{ + struct sdhci_host *sdhost = (struct sdhci_host *)data; + + tasklet_schedule(&sdhost->card_tasklet); + return IRQ_HANDLED; +}; + +static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + u32 ctrl; + + plat = pdev->dev.platform_data; + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { + ctrl &= ~SDHCI_CTRL_4BITBUS; + ctrl |= SDHCI_CTRL_8BITBUS; + } else { + ctrl &= ~SDHCI_CTRL_8BITBUS; + if (bus_width == MMC_BUS_WIDTH_4) + ctrl |= SDHCI_CTRL_4BITBUS; + else + ctrl &= ~SDHCI_CTRL_4BITBUS; + } + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + return 0; +} + + +static int tegra_sdhci_pltfm_init(struct sdhci_host *host, + struct sdhci_pltfm_data *pdata) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + struct clk *clk; + int rc; + + plat = pdev->dev.platform_data; + if (plat == NULL) { + dev_err(mmc_dev(host->mmc), "missing platform data\n"); + return -ENXIO; + } + + if (gpio_is_valid(plat->power_gpio)) { + rc = gpio_request(plat->power_gpio, "sdhci_power"); + if (rc) { + dev_err(mmc_dev(host->mmc), + "failed to allocate power gpio\n"); + goto out; + } + tegra_gpio_enable(plat->power_gpio); + gpio_direction_output(plat->power_gpio, 1); + } + + if (gpio_is_valid(plat->cd_gpio)) { + rc = gpio_request(plat->cd_gpio, "sdhci_cd"); + if (rc) { + dev_err(mmc_dev(host->mmc), + "failed to allocate cd gpio\n"); + goto out_power; + } + tegra_gpio_enable(plat->cd_gpio); + gpio_direction_input(plat->cd_gpio); + + rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + mmc_hostname(host->mmc), host); + + if (rc) { + dev_err(mmc_dev(host->mmc), "request irq error\n"); + goto out_cd; + } + + } + + if (gpio_is_valid(plat->wp_gpio)) { + rc = gpio_request(plat->wp_gpio, "sdhci_wp"); + if (rc) { + dev_err(mmc_dev(host->mmc), + "failed to allocate wp gpio\n"); + goto out_cd; + } + tegra_gpio_enable(plat->wp_gpio); + gpio_direction_input(plat->wp_gpio); + } + + clk = clk_get(mmc_dev(host->mmc), NULL); + if (IS_ERR(clk)) { + dev_err(mmc_dev(host->mmc), "clk err\n"); + rc = PTR_ERR(clk); + goto out_wp; + } + clk_enable(clk); + pltfm_host->clk = clk; + + if (plat->is_8bit) + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + + return 0; + +out_wp: + if (gpio_is_valid(plat->wp_gpio)) { + tegra_gpio_disable(plat->wp_gpio); + gpio_free(plat->wp_gpio); + } + +out_cd: + if (gpio_is_valid(plat->cd_gpio)) { + tegra_gpio_disable(plat->cd_gpio); + gpio_free(plat->cd_gpio); + } + +out_power: + if (gpio_is_valid(plat->power_gpio)) { + tegra_gpio_disable(plat->power_gpio); + gpio_free(plat->power_gpio); + } + +out: + return rc; +} + +static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + + plat = pdev->dev.platform_data; + + if (gpio_is_valid(plat->wp_gpio)) { + tegra_gpio_disable(plat->wp_gpio); + gpio_free(plat->wp_gpio); + } + + if (gpio_is_valid(plat->cd_gpio)) { + tegra_gpio_disable(plat->cd_gpio); + gpio_free(plat->cd_gpio); + } + + if (gpio_is_valid(plat->power_gpio)) { + tegra_gpio_disable(plat->power_gpio); + gpio_free(plat->power_gpio); + } + + clk_disable(pltfm_host->clk); + clk_put(pltfm_host->clk); +} + +static struct sdhci_ops tegra_sdhci_ops = { + .get_ro = tegra_sdhci_get_ro, + .read_l = tegra_sdhci_readl, + .read_w = tegra_sdhci_readw, + .write_l = tegra_sdhci_writel, + .platform_8bit_width = tegra_sdhci_8bit, +}; + +struct sdhci_pltfm_data sdhci_tegra_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra_sdhci_ops, + .init = tegra_sdhci_pltfm_init, + .exit = tegra_sdhci_pltfm_exit, +}; -- cgit v1.2.3 From f95f3850f7a9e1d49ebc5b6e72e7cc3ec3685b0b Mon Sep 17 00:00:00 2001 From: Will Newton Date: Sun, 2 Jan 2011 01:11:59 -0500 Subject: mmc: dw_mmc: Add Synopsys DesignWare mmc host driver. This adds the mmc host driver for the Synopsys DesignWare mmc host controller, found in a number of embedded SoC designs. Signed-off-by: Will Newton Reviewed-by: Matt Fleming Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 16 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/dw_mmc.c | 1796 ++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/host/dw_mmc.h | 168 +++++ include/linux/mmc/dw_mmc.h | 217 ++++++ 5 files changed, 2198 insertions(+) create mode 100644 drivers/mmc/host/dw_mmc.c create mode 100644 drivers/mmc/host/dw_mmc.h create mode 100644 include/linux/mmc/dw_mmc.h (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9f47d38dcc7f..5ec02a536c5d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -479,6 +479,22 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND help If you say yes here SD-Cards may work on the EZkit. +config MMC_DW + tristate "Synopsys DesignWare Memory Card Interface" + depends on ARM + help + This selects support for the Synopsys DesignWare Mobile Storage IP + block, this provides host support for SD and MMC interfaces, in both + PIO and external DMA modes. + +config MMC_DW_IDMAC + bool "Internal DMAC interface" + depends on MMC_DW + help + This selects support for the internal DMAC block within the Synopsys + Designware Mobile Storage IP block. This disables the external DMA + interface. + config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE) diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6d1ff9e27368..e834fb223e9a 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o +obj-$(CONFIG_MMC_DW) += dw_mmc.o obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_USHC) += ushc.o diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c new file mode 100644 index 000000000000..2fcc82577c1b --- /dev/null +++ b/drivers/mmc/host/dw_mmc.c @@ -0,0 +1,1796 @@ +/* + * Synopsys DesignWare Multimedia Card Interface driver + * (Based on NXP driver for lpc 31xx) + * + * Copyright (C) 2009 NXP Semiconductors + * Copyright (C) 2009, 2010 Imagination Technologies Ltd. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dw_mmc.h" + +/* Common flag combinations */ +#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \ + SDMMC_INT_HTO | SDMMC_INT_SBE | \ + SDMMC_INT_EBE) +#define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ + SDMMC_INT_RESP_ERR) +#define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ + DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) +#define DW_MCI_SEND_STATUS 1 +#define DW_MCI_RECV_STATUS 2 +#define DW_MCI_DMA_THRESHOLD 16 + +#ifdef CONFIG_MMC_DW_IDMAC +struct idmac_desc { + u32 des0; /* Control Descriptor */ +#define IDMAC_DES0_DIC BIT(1) +#define IDMAC_DES0_LD BIT(2) +#define IDMAC_DES0_FD BIT(3) +#define IDMAC_DES0_CH BIT(4) +#define IDMAC_DES0_ER BIT(5) +#define IDMAC_DES0_CES BIT(30) +#define IDMAC_DES0_OWN BIT(31) + + u32 des1; /* Buffer sizes */ +#define IDMAC_SET_BUFFER1_SIZE(d, s) \ + ((d)->des1 = ((d)->des1 & 0x03ffc000) | ((s) & 0x3fff)) + + u32 des2; /* buffer 1 physical address */ + + u32 des3; /* buffer 2 physical address */ +}; +#endif /* CONFIG_MMC_DW_IDMAC */ + +/** + * struct dw_mci_slot - MMC slot state + * @mmc: The mmc_host representing this slot. + * @host: The MMC controller this slot is using. + * @ctype: Card type for this slot. + * @mrq: mmc_request currently being processed or waiting to be + * processed, or NULL when the slot is idle. + * @queue_node: List node for placing this node in the @queue list of + * &struct dw_mci. + * @clock: Clock rate configured by set_ios(). Protected by host->lock. + * @flags: Random state bits associated with the slot. + * @id: Number of this slot. + * @last_detect_state: Most recently observed card detect state. + */ +struct dw_mci_slot { + struct mmc_host *mmc; + struct dw_mci *host; + + u32 ctype; + + struct mmc_request *mrq; + struct list_head queue_node; + + unsigned int clock; + unsigned long flags; +#define DW_MMC_CARD_PRESENT 0 +#define DW_MMC_CARD_NEED_INIT 1 + int id; + int last_detect_state; +}; + +#if defined(CONFIG_DEBUG_FS) +static int dw_mci_req_show(struct seq_file *s, void *v) +{ + struct dw_mci_slot *slot = s->private; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_command *stop; + struct mmc_data *data; + + /* Make sure we get a consistent snapshot */ + spin_lock_bh(&slot->host->lock); + mrq = slot->mrq; + + if (mrq) { + cmd = mrq->cmd; + data = mrq->data; + stop = mrq->stop; + + if (cmd) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + cmd->opcode, cmd->arg, cmd->flags, + cmd->resp[0], cmd->resp[1], cmd->resp[2], + cmd->resp[2], cmd->error); + if (data) + seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", + data->bytes_xfered, data->blocks, + data->blksz, data->flags, data->error); + if (stop) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + stop->opcode, stop->arg, stop->flags, + stop->resp[0], stop->resp[1], stop->resp[2], + stop->resp[2], stop->error); + } + + spin_unlock_bh(&slot->host->lock); + + return 0; +} + +static int dw_mci_req_open(struct inode *inode, struct file *file) +{ + return single_open(file, dw_mci_req_show, inode->i_private); +} + +static const struct file_operations dw_mci_req_fops = { + .owner = THIS_MODULE, + .open = dw_mci_req_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dw_mci_regs_show(struct seq_file *s, void *v) +{ + seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); + seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); + seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); + seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); + seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); + seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); + + return 0; +} + +static int dw_mci_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, dw_mci_regs_show, inode->i_private); +} + +static const struct file_operations dw_mci_regs_fops = { + .owner = THIS_MODULE, + .open = dw_mci_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dw_mci_init_debugfs(struct dw_mci_slot *slot) +{ + struct mmc_host *mmc = slot->mmc; + struct dw_mci *host = slot->host; + struct dentry *root; + struct dentry *node; + + root = mmc->debugfs_root; + if (!root) + return; + + node = debugfs_create_file("regs", S_IRUSR, root, host, + &dw_mci_regs_fops); + if (!node) + goto err; + + node = debugfs_create_file("req", S_IRUSR, root, slot, + &dw_mci_req_fops); + if (!node) + goto err; + + node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); + if (!node) + goto err; + + node = debugfs_create_x32("pending_events", S_IRUSR, root, + (u32 *)&host->pending_events); + if (!node) + goto err; + + node = debugfs_create_x32("completed_events", S_IRUSR, root, + (u32 *)&host->completed_events); + if (!node) + goto err; + + return; + +err: + dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); +} +#endif /* defined(CONFIG_DEBUG_FS) */ + +static void dw_mci_set_timeout(struct dw_mci *host) +{ + /* timeout (maximum) */ + mci_writel(host, TMOUT, 0xffffffff); +} + +static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) +{ + struct mmc_data *data; + u32 cmdr; + cmd->error = -EINPROGRESS; + + cmdr = cmd->opcode; + + if (cmdr == MMC_STOP_TRANSMISSION) + cmdr |= SDMMC_CMD_STOP; + else + cmdr |= SDMMC_CMD_PRV_DAT_WAIT; + + if (cmd->flags & MMC_RSP_PRESENT) { + /* We expect a response, so set this bit */ + cmdr |= SDMMC_CMD_RESP_EXP; + if (cmd->flags & MMC_RSP_136) + cmdr |= SDMMC_CMD_RESP_LONG; + } + + if (cmd->flags & MMC_RSP_CRC) + cmdr |= SDMMC_CMD_RESP_CRC; + + data = cmd->data; + if (data) { + cmdr |= SDMMC_CMD_DAT_EXP; + if (data->flags & MMC_DATA_STREAM) + cmdr |= SDMMC_CMD_STRM_MODE; + if (data->flags & MMC_DATA_WRITE) + cmdr |= SDMMC_CMD_DAT_WR; + } + + return cmdr; +} + +static void dw_mci_start_command(struct dw_mci *host, + struct mmc_command *cmd, u32 cmd_flags) +{ + host->cmd = cmd; + dev_vdbg(&host->pdev->dev, + "start command: ARGR=0x%08x CMDR=0x%08x\n", + cmd->arg, cmd_flags); + + mci_writel(host, CMDARG, cmd->arg); + wmb(); + + mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); +} + +static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) +{ + dw_mci_start_command(host, data->stop, host->stop_cmdr); +} + +/* DMA interface functions */ +static void dw_mci_stop_dma(struct dw_mci *host) +{ + if (host->use_dma) { + host->dma_ops->stop(host); + host->dma_ops->cleanup(host); + } else { + /* Data transfer was stopped by the interrupt handler */ + set_bit(EVENT_XFER_COMPLETE, &host->pending_events); + } +} + +#ifdef CONFIG_MMC_DW_IDMAC +static void dw_mci_dma_cleanup(struct dw_mci *host) +{ + struct mmc_data *data = host->data; + + if (data) + dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); +} + +static void dw_mci_idmac_stop_dma(struct dw_mci *host) +{ + u32 temp; + + /* Disable and reset the IDMAC interface */ + temp = mci_readl(host, CTRL); + temp &= ~SDMMC_CTRL_USE_IDMAC; + temp |= SDMMC_CTRL_DMA_RESET; + mci_writel(host, CTRL, temp); + + /* Stop the IDMAC running */ + temp = mci_readl(host, BMOD); + temp &= ~SDMMC_IDMAC_ENABLE; + mci_writel(host, BMOD, temp); +} + +static void dw_mci_idmac_complete_dma(struct dw_mci *host) +{ + struct mmc_data *data = host->data; + + dev_vdbg(&host->pdev->dev, "DMA complete\n"); + + host->dma_ops->cleanup(host); + + /* + * If the card was removed, data will be NULL. No point in trying to + * send the stop command or waiting for NBUSY in this case. + */ + if (data) { + set_bit(EVENT_XFER_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); + } +} + +static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, + unsigned int sg_len) +{ + int i; + struct idmac_desc *desc = host->sg_cpu; + + for (i = 0; i < sg_len; i++, desc++) { + unsigned int length = sg_dma_len(&data->sg[i]); + u32 mem_addr = sg_dma_address(&data->sg[i]); + + /* Set the OWN bit and disable interrupts for this descriptor */ + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; + + /* Buffer length */ + IDMAC_SET_BUFFER1_SIZE(desc, length); + + /* Physical address to DMA to/from */ + desc->des2 = mem_addr; + } + + /* Set first descriptor */ + desc = host->sg_cpu; + desc->des0 |= IDMAC_DES0_FD; + + /* Set last descriptor */ + desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); + desc->des0 |= IDMAC_DES0_LD; + + wmb(); +} + +static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) +{ + u32 temp; + + dw_mci_translate_sglist(host, host->data, sg_len); + + /* Select IDMAC interface */ + temp = mci_readl(host, CTRL); + temp |= SDMMC_CTRL_USE_IDMAC; + mci_writel(host, CTRL, temp); + + wmb(); + + /* Enable the IDMAC */ + temp = mci_readl(host, BMOD); + temp |= SDMMC_IDMAC_ENABLE; + mci_writel(host, BMOD, temp); + + /* Start it running */ + mci_writel(host, PLDMND, 1); +} + +static int dw_mci_idmac_init(struct dw_mci *host) +{ + struct idmac_desc *p; + int i; + + /* Number of descriptors in the ring buffer */ + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); + + /* Forward link the descriptor list */ + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) + p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); + + /* Set the last descriptor as the end-of-ring descriptor */ + p->des3 = host->sg_dma; + p->des0 = IDMAC_DES0_ER; + + /* Mask out interrupts - get Tx & Rx complete only */ + mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | + SDMMC_IDMAC_INT_TI); + + /* Set the descriptor base address */ + mci_writel(host, DBADDR, host->sg_dma); + return 0; +} + +static struct dw_mci_dma_ops dw_mci_idmac_ops = { + .init = dw_mci_idmac_init, + .start = dw_mci_idmac_start_dma, + .stop = dw_mci_idmac_stop_dma, + .complete = dw_mci_idmac_complete_dma, + .cleanup = dw_mci_dma_cleanup, +}; +#endif /* CONFIG_MMC_DW_IDMAC */ + +static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) +{ + struct scatterlist *sg; + unsigned int i, direction, sg_len; + u32 temp; + + /* If we don't have a channel, we can't do DMA */ + if (!host->use_dma) + return -ENODEV; + + /* + * We don't do DMA on "complex" transfers, i.e. with + * non-word-aligned buffers or lengths. Also, we don't bother + * with all the DMA setup overhead for short transfers. + */ + if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) + return -EINVAL; + if (data->blksz & 3) + return -EINVAL; + + for_each_sg(data->sg, sg, data->sg_len, i) { + if (sg->offset & 3 || sg->length & 3) + return -EINVAL; + } + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + + sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, + direction); + + dev_vdbg(&host->pdev->dev, + "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", + (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, + sg_len); + + /* Enable the DMA interface */ + temp = mci_readl(host, CTRL); + temp |= SDMMC_CTRL_DMA_ENABLE; + mci_writel(host, CTRL, temp); + + /* Disable RX/TX IRQs, let DMA handle it */ + temp = mci_readl(host, INTMASK); + temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); + mci_writel(host, INTMASK, temp); + + host->dma_ops->start(host, sg_len); + + return 0; +} + +static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) +{ + u32 temp; + + data->error = -EINPROGRESS; + + WARN_ON(host->data); + host->sg = NULL; + host->data = data; + + if (dw_mci_submit_data_dma(host, data)) { + host->sg = data->sg; + host->pio_offset = 0; + if (data->flags & MMC_DATA_READ) + host->dir_status = DW_MCI_RECV_STATUS; + else + host->dir_status = DW_MCI_SEND_STATUS; + + temp = mci_readl(host, INTMASK); + temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; + mci_writel(host, INTMASK, temp); + + temp = mci_readl(host, CTRL); + temp &= ~SDMMC_CTRL_DMA_ENABLE; + mci_writel(host, CTRL, temp); + } +} + +static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) +{ + struct dw_mci *host = slot->host; + unsigned long timeout = jiffies + msecs_to_jiffies(500); + unsigned int cmd_status = 0; + + mci_writel(host, CMDARG, arg); + wmb(); + mci_writel(host, CMD, SDMMC_CMD_START | cmd); + + while (time_before(jiffies, timeout)) { + cmd_status = mci_readl(host, CMD); + if (!(cmd_status & SDMMC_CMD_START)) + return; + } + dev_err(&slot->mmc->class_dev, + "Timeout sending command (cmd %#x arg %#x status %#x)\n", + cmd, arg, cmd_status); +} + +static void dw_mci_setup_bus(struct dw_mci_slot *slot) +{ + struct dw_mci *host = slot->host; + u32 div; + + if (slot->clock != host->current_speed) { + if (host->bus_hz % slot->clock) + /* + * move the + 1 after the divide to prevent + * over-clocking the card. + */ + div = ((host->bus_hz / slot->clock) >> 1) + 1; + else + div = (host->bus_hz / slot->clock) >> 1; + + dev_info(&slot->mmc->class_dev, + "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ" + " div = %d)\n", slot->id, host->bus_hz, slot->clock, + div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div); + + /* disable clock */ + mci_writel(host, CLKENA, 0); + mci_writel(host, CLKSRC, 0); + + /* inform CIU */ + mci_send_cmd(slot, + SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + + /* set clock to desired speed */ + mci_writel(host, CLKDIV, div); + + /* inform CIU */ + mci_send_cmd(slot, + SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + + /* enable clock */ + mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE); + + /* inform CIU */ + mci_send_cmd(slot, + SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + + host->current_speed = slot->clock; + } + + /* Set the current slot bus width */ + mci_writel(host, CTYPE, slot->ctype); +} + +static void dw_mci_start_request(struct dw_mci *host, + struct dw_mci_slot *slot) +{ + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + u32 cmdflags; + + mrq = slot->mrq; + if (host->pdata->select_slot) + host->pdata->select_slot(slot->id); + + /* Slot specific timing and width adjustment */ + dw_mci_setup_bus(slot); + + host->cur_slot = slot; + host->mrq = mrq; + + host->pending_events = 0; + host->completed_events = 0; + host->data_status = 0; + + data = mrq->data; + if (data) { + dw_mci_set_timeout(host); + mci_writel(host, BYTCNT, data->blksz*data->blocks); + mci_writel(host, BLKSIZ, data->blksz); + } + + cmd = mrq->cmd; + cmdflags = dw_mci_prepare_command(slot->mmc, cmd); + + /* this is the first command, send the initialization clock */ + if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) + cmdflags |= SDMMC_CMD_INIT; + + if (data) { + dw_mci_submit_data(host, data); + wmb(); + } + + dw_mci_start_command(host, cmd, cmdflags); + + if (mrq->stop) + host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); +} + +static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, + struct mmc_request *mrq) +{ + dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", + host->state); + + spin_lock_bh(&host->lock); + slot->mrq = mrq; + + if (host->state == STATE_IDLE) { + host->state = STATE_SENDING_CMD; + dw_mci_start_request(host, slot); + } else { + list_add_tail(&slot->queue_node, &host->queue); + } + + spin_unlock_bh(&host->lock); +} + +static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + + WARN_ON(slot->mrq); + + if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { + mrq->cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); + return; + } + + /* We don't support multiple blocks of weird lengths. */ + dw_mci_queue_request(host, slot, mrq); +} + +static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + + /* set default 1 bit mode */ + slot->ctype = SDMMC_CTYPE_1BIT; + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + slot->ctype = SDMMC_CTYPE_1BIT; + break; + case MMC_BUS_WIDTH_4: + slot->ctype = SDMMC_CTYPE_4BIT; + break; + } + + if (ios->clock) { + /* + * Use mirror of ios->clock to prevent race with mmc + * core ios update when finding the minimum. + */ + slot->clock = ios->clock; + } + + switch (ios->power_mode) { + case MMC_POWER_UP: + set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); + break; + default: + break; + } +} + +static int dw_mci_get_ro(struct mmc_host *mmc) +{ + int read_only; + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci_board *brd = slot->host->pdata; + + /* Use platform get_ro function, else try on board write protect */ + if (brd->get_ro) + read_only = brd->get_ro(slot->id); + else + read_only = + mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; + + dev_dbg(&mmc->class_dev, "card is %s\n", + read_only ? "read-only" : "read-write"); + + return read_only; +} + +static int dw_mci_get_cd(struct mmc_host *mmc) +{ + int present; + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci_board *brd = slot->host->pdata; + + /* Use platform get_cd function, else try onboard card detect */ + if (brd->get_cd) + present = !brd->get_cd(slot->id); + else + present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) + == 0 ? 1 : 0; + + if (present) + dev_dbg(&mmc->class_dev, "card is present\n"); + else + dev_dbg(&mmc->class_dev, "card is not present\n"); + + return present; +} + +static const struct mmc_host_ops dw_mci_ops = { + .request = dw_mci_request, + .set_ios = dw_mci_set_ios, + .get_ro = dw_mci_get_ro, + .get_cd = dw_mci_get_cd, +}; + +static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) + __releases(&host->lock) + __acquires(&host->lock) +{ + struct dw_mci_slot *slot; + struct mmc_host *prev_mmc = host->cur_slot->mmc; + + WARN_ON(host->cmd || host->data); + + host->cur_slot->mrq = NULL; + host->mrq = NULL; + if (!list_empty(&host->queue)) { + slot = list_entry(host->queue.next, + struct dw_mci_slot, queue_node); + list_del(&slot->queue_node); + dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", + mmc_hostname(slot->mmc)); + host->state = STATE_SENDING_CMD; + dw_mci_start_request(host, slot); + } else { + dev_vdbg(&host->pdev->dev, "list empty\n"); + host->state = STATE_IDLE; + } + + spin_unlock(&host->lock); + mmc_request_done(prev_mmc, mrq); + spin_lock(&host->lock); +} + +static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) +{ + u32 status = host->cmd_status; + + host->cmd_status = 0; + + /* Read the response from the card (up to 16 bytes) */ + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { + cmd->resp[3] = mci_readl(host, RESP0); + cmd->resp[2] = mci_readl(host, RESP1); + cmd->resp[1] = mci_readl(host, RESP2); + cmd->resp[0] = mci_readl(host, RESP3); + } else { + cmd->resp[0] = mci_readl(host, RESP0); + cmd->resp[1] = 0; + cmd->resp[2] = 0; + cmd->resp[3] = 0; + } + } + + if (status & SDMMC_INT_RTO) + cmd->error = -ETIMEDOUT; + else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) + cmd->error = -EILSEQ; + else if (status & SDMMC_INT_RESP_ERR) + cmd->error = -EIO; + else + cmd->error = 0; + + if (cmd->error) { + /* newer ip versions need a delay between retries */ + if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) + mdelay(20); + + if (cmd->data) { + host->data = NULL; + dw_mci_stop_dma(host); + } + } +} + +static void dw_mci_tasklet_func(unsigned long priv) +{ + struct dw_mci *host = (struct dw_mci *)priv; + struct mmc_data *data; + struct mmc_command *cmd; + enum dw_mci_state state; + enum dw_mci_state prev_state; + u32 status; + + spin_lock(&host->lock); + + state = host->state; + data = host->data; + + do { + prev_state = state; + + switch (state) { + case STATE_IDLE: + break; + + case STATE_SENDING_CMD: + if (!test_and_clear_bit(EVENT_CMD_COMPLETE, + &host->pending_events)) + break; + + cmd = host->cmd; + host->cmd = NULL; + set_bit(EVENT_CMD_COMPLETE, &host->completed_events); + dw_mci_command_complete(host, host->mrq->cmd); + if (!host->mrq->data || cmd->error) { + dw_mci_request_end(host, host->mrq); + goto unlock; + } + + prev_state = state = STATE_SENDING_DATA; + /* fall through */ + + case STATE_SENDING_DATA: + if (test_and_clear_bit(EVENT_DATA_ERROR, + &host->pending_events)) { + dw_mci_stop_dma(host); + if (data->stop) + send_stop_cmd(host, data); + state = STATE_DATA_ERROR; + break; + } + + if (!test_and_clear_bit(EVENT_XFER_COMPLETE, + &host->pending_events)) + break; + + set_bit(EVENT_XFER_COMPLETE, &host->completed_events); + prev_state = state = STATE_DATA_BUSY; + /* fall through */ + + case STATE_DATA_BUSY: + if (!test_and_clear_bit(EVENT_DATA_COMPLETE, + &host->pending_events)) + break; + + host->data = NULL; + set_bit(EVENT_DATA_COMPLETE, &host->completed_events); + status = host->data_status; + + if (status & DW_MCI_DATA_ERROR_FLAGS) { + if (status & SDMMC_INT_DTO) { + dev_err(&host->pdev->dev, + "data timeout error\n"); + data->error = -ETIMEDOUT; + } else if (status & SDMMC_INT_DCRC) { + dev_err(&host->pdev->dev, + "data CRC error\n"); + data->error = -EILSEQ; + } else { + dev_err(&host->pdev->dev, + "data FIFO error " + "(status=%08x)\n", + status); + data->error = -EIO; + } + } else { + data->bytes_xfered = data->blocks * data->blksz; + data->error = 0; + } + + if (!data->stop) { + dw_mci_request_end(host, host->mrq); + goto unlock; + } + + prev_state = state = STATE_SENDING_STOP; + if (!data->error) + send_stop_cmd(host, data); + /* fall through */ + + case STATE_SENDING_STOP: + if (!test_and_clear_bit(EVENT_CMD_COMPLETE, + &host->pending_events)) + break; + + host->cmd = NULL; + dw_mci_command_complete(host, host->mrq->stop); + dw_mci_request_end(host, host->mrq); + goto unlock; + + case STATE_DATA_ERROR: + if (!test_and_clear_bit(EVENT_XFER_COMPLETE, + &host->pending_events)) + break; + + state = STATE_DATA_BUSY; + break; + } + } while (state != prev_state); + + host->state = state; +unlock: + spin_unlock(&host->lock); + +} + +static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) +{ + u16 *pdata = (u16 *)buf; + + WARN_ON(cnt % 2 != 0); + + cnt = cnt >> 1; + while (cnt > 0) { + mci_writew(host, DATA, *pdata++); + cnt--; + } +} + +static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) +{ + u16 *pdata = (u16 *)buf; + + WARN_ON(cnt % 2 != 0); + + cnt = cnt >> 1; + while (cnt > 0) { + *pdata++ = mci_readw(host, DATA); + cnt--; + } +} + +static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) +{ + u32 *pdata = (u32 *)buf; + + WARN_ON(cnt % 4 != 0); + WARN_ON((unsigned long)pdata & 0x3); + + cnt = cnt >> 2; + while (cnt > 0) { + mci_writel(host, DATA, *pdata++); + cnt--; + } +} + +static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) +{ + u32 *pdata = (u32 *)buf; + + WARN_ON(cnt % 4 != 0); + WARN_ON((unsigned long)pdata & 0x3); + + cnt = cnt >> 2; + while (cnt > 0) { + *pdata++ = mci_readl(host, DATA); + cnt--; + } +} + +static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) +{ + u64 *pdata = (u64 *)buf; + + WARN_ON(cnt % 8 != 0); + + cnt = cnt >> 3; + while (cnt > 0) { + mci_writeq(host, DATA, *pdata++); + cnt--; + } +} + +static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) +{ + u64 *pdata = (u64 *)buf; + + WARN_ON(cnt % 8 != 0); + + cnt = cnt >> 3; + while (cnt > 0) { + *pdata++ = mci_readq(host, DATA); + cnt--; + } +} + +static void dw_mci_read_data_pio(struct dw_mci *host) +{ + struct scatterlist *sg = host->sg; + void *buf = sg_virt(sg); + unsigned int offset = host->pio_offset; + struct mmc_data *data = host->data; + int shift = host->data_shift; + u32 status; + unsigned int nbytes = 0, len, old_len, count = 0; + + do { + len = SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift; + if (count == 0) + old_len = len; + + if (offset + len <= sg->length) { + host->pull_data(host, (void *)(buf + offset), len); + + offset += len; + nbytes += len; + + if (offset == sg->length) { + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = 0; + buf = sg_virt(sg); + } + } else { + unsigned int remaining = sg->length - offset; + host->pull_data(host, (void *)(buf + offset), + remaining); + nbytes += remaining; + + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = len - remaining; + buf = sg_virt(sg); + host->pull_data(host, buf, offset); + nbytes += 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; + smp_wmb(); + + set_bit(EVENT_DATA_ERROR, &host->pending_events); + + tasklet_schedule(&host->tasklet); + return; + } + count++; + } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ + len = SDMMC_GET_FCNT(mci_readl(host, STATUS)); + host->pio_offset = offset; + data->bytes_xfered += nbytes; + return; + +done: + data->bytes_xfered += nbytes; + smp_wmb(); + set_bit(EVENT_XFER_COMPLETE, &host->pending_events); +} + +static void dw_mci_write_data_pio(struct dw_mci *host) +{ + struct scatterlist *sg = host->sg; + void *buf = sg_virt(sg); + unsigned int offset = host->pio_offset; + struct mmc_data *data = host->data; + int shift = host->data_shift; + u32 status; + unsigned int nbytes = 0, len; + + do { + len = SDMMC_FIFO_SZ - + (SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift); + if (offset + len <= sg->length) { + host->push_data(host, (void *)(buf + offset), len); + + offset += len; + nbytes += len; + if (offset == sg->length) { + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = 0; + buf = sg_virt(sg); + } + } else { + unsigned int remaining = sg->length - offset; + + host->push_data(host, (void *)(buf + offset), + remaining); + nbytes += remaining; + + host->sg = sg = sg_next(sg); + if (!sg) + goto done; + + offset = len - remaining; + buf = sg_virt(sg); + host->push_data(host, (void *)buf, offset); + nbytes += 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; + + smp_wmb(); + + set_bit(EVENT_DATA_ERROR, &host->pending_events); + + tasklet_schedule(&host->tasklet); + return; + } + } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ + + host->pio_offset = offset; + data->bytes_xfered += nbytes; + + return; + +done: + data->bytes_xfered += nbytes; + smp_wmb(); + set_bit(EVENT_XFER_COMPLETE, &host->pending_events); +} + +static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) +{ + if (!host->cmd_status) + host->cmd_status = status; + + smp_wmb(); + + set_bit(EVENT_CMD_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); +} + +static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) +{ + struct dw_mci *host = dev_id; + u32 status, pending; + unsigned int pass_count = 0; + + do { + status = mci_readl(host, RINTSTS); + pending = mci_readl(host, MINTSTS); /* read-only mask reg */ + + /* + * DTO fix - version 2.10a and below, and only if internal DMA + * is configured. + */ + if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { + if (!pending && + ((mci_readl(host, STATUS) >> 17) & 0x1fff)) + pending |= SDMMC_INT_DATA_OVER; + } + + if (!pending) + break; + + if (pending & DW_MCI_CMD_ERROR_FLAGS) { + mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); + host->cmd_status = status; + smp_wmb(); + set_bit(EVENT_CMD_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); + } + + 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; + smp_wmb(); + set_bit(EVENT_DATA_ERROR, &host->pending_events); + tasklet_schedule(&host->tasklet); + } + + if (pending & SDMMC_INT_DATA_OVER) { + mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); + if (!host->data_status) + host->data_status = status; + smp_wmb(); + if (host->dir_status == DW_MCI_RECV_STATUS) { + if (host->sg != NULL) + dw_mci_read_data_pio(host); + } + set_bit(EVENT_DATA_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); + } + + if (pending & SDMMC_INT_RXDR) { + mci_writel(host, RINTSTS, SDMMC_INT_RXDR); + if (host->sg) + dw_mci_read_data_pio(host); + } + + if (pending & SDMMC_INT_TXDR) { + mci_writel(host, RINTSTS, SDMMC_INT_TXDR); + if (host->sg) + dw_mci_write_data_pio(host); + } + + if (pending & SDMMC_INT_CMD_DONE) { + mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); + dw_mci_cmd_interrupt(host, status); + } + + if (pending & SDMMC_INT_CD) { + mci_writel(host, RINTSTS, SDMMC_INT_CD); + tasklet_schedule(&host->card_tasklet); + } + + } while (pass_count++ < 5); + +#ifdef CONFIG_MMC_DW_IDMAC + /* Handle DMA interrupts */ + pending = mci_readl(host, IDSTS); + if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); + set_bit(EVENT_DATA_COMPLETE, &host->pending_events); + host->dma_ops->complete(host); + } +#endif + + return IRQ_HANDLED; +} + +static void dw_mci_tasklet_card(unsigned long data) +{ + struct dw_mci *host = (struct dw_mci *)data; + int i; + + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + struct mmc_host *mmc = slot->mmc; + struct mmc_request *mrq; + int present; + u32 ctrl; + + present = dw_mci_get_cd(mmc); + while (present != slot->last_detect_state) { + spin_lock(&host->lock); + + dev_dbg(&slot->mmc->class_dev, "card %s\n", + present ? "inserted" : "removed"); + + /* Card change detected */ + slot->last_detect_state = present; + + /* Power up slot */ + if (present != 0) { + if (host->pdata->setpower) + host->pdata->setpower(slot->id, + mmc->ocr_avail); + + set_bit(DW_MMC_CARD_PRESENT, &slot->flags); + } + + /* Clean up queue if present */ + mrq = slot->mrq; + if (mrq) { + if (mrq == host->mrq) { + host->data = NULL; + host->cmd = NULL; + + switch (host->state) { + case STATE_IDLE: + break; + case STATE_SENDING_CMD: + mrq->cmd->error = -ENOMEDIUM; + if (!mrq->data) + break; + /* fall through */ + case STATE_SENDING_DATA: + mrq->data->error = -ENOMEDIUM; + dw_mci_stop_dma(host); + break; + case STATE_DATA_BUSY: + case STATE_DATA_ERROR: + if (mrq->data->error == -EINPROGRESS) + mrq->data->error = -ENOMEDIUM; + if (!mrq->stop) + break; + /* fall through */ + case STATE_SENDING_STOP: + mrq->stop->error = -ENOMEDIUM; + break; + } + + dw_mci_request_end(host, mrq); + } else { + list_del(&slot->queue_node); + mrq->cmd->error = -ENOMEDIUM; + if (mrq->data) + mrq->data->error = -ENOMEDIUM; + if (mrq->stop) + mrq->stop->error = -ENOMEDIUM; + + spin_unlock(&host->lock); + mmc_request_done(slot->mmc, mrq); + spin_lock(&host->lock); + } + } + + /* Power down slot */ + if (present == 0) { + if (host->pdata->setpower) + host->pdata->setpower(slot->id, 0); + clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + + /* + * Clear down the FIFO - doing so generates a + * block interrupt, hence setting the + * scatter-gather pointer to NULL. + */ + host->sg = NULL; + + ctrl = mci_readl(host, CTRL); + ctrl |= SDMMC_CTRL_FIFO_RESET; + mci_writel(host, CTRL, ctrl); + +#ifdef CONFIG_MMC_DW_IDMAC + ctrl = mci_readl(host, BMOD); + ctrl |= 0x01; /* Software reset of DMA */ + mci_writel(host, BMOD, ctrl); +#endif + + } + + spin_unlock(&host->lock); + present = dw_mci_get_cd(mmc); + } + + mmc_detect_change(slot->mmc, + msecs_to_jiffies(host->pdata->detect_delay_ms)); + } +} + +static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) +{ + struct mmc_host *mmc; + struct dw_mci_slot *slot; + + mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev); + if (!mmc) + return -ENOMEM; + + slot = mmc_priv(mmc); + slot->id = id; + slot->mmc = mmc; + slot->host = host; + + mmc->ops = &dw_mci_ops; + mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510); + mmc->f_max = host->bus_hz; + + if (host->pdata->get_ocr) + mmc->ocr_avail = host->pdata->get_ocr(id); + else + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + /* + * Start with slot power disabled, it will be enabled when a card + * is detected. + */ + if (host->pdata->setpower) + host->pdata->setpower(id, 0); + + mmc->caps = 0; + if (host->pdata->get_bus_wd) + if (host->pdata->get_bus_wd(slot->id) >= 4) + mmc->caps |= MMC_CAP_4_BIT_DATA; + + if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED) + mmc->caps |= MMC_CAP_SD_HIGHSPEED; + +#ifdef CONFIG_MMC_DW_IDMAC + mmc->max_segs = host->ring_size; + mmc->max_blk_size = 65536; + mmc->max_blk_count = host->ring_size; + mmc->max_seg_size = 0x1000; + mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; +#else + if (host->pdata->blk_settings) { + mmc->max_segs = host->pdata->blk_settings->max_segs; + mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; + mmc->max_blk_count = host->pdata->blk_settings->max_blk_count; + mmc->max_req_size = host->pdata->blk_settings->max_req_size; + mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; + } else { + /* Useful defaults if platform data is unset. */ + mmc->max_segs = 64; + mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ + mmc->max_blk_count = 512; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + } +#endif /* CONFIG_MMC_DW_IDMAC */ + + if (dw_mci_get_cd(mmc)) + set_bit(DW_MMC_CARD_PRESENT, &slot->flags); + else + clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + + host->slot[id] = slot; + mmc_add_host(mmc); + +#if defined(CONFIG_DEBUG_FS) + dw_mci_init_debugfs(slot); +#endif + + /* Card initially undetected */ + slot->last_detect_state = 0; + + return 0; +} + +static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) +{ + /* Shutdown detect IRQ */ + if (slot->host->pdata->exit) + slot->host->pdata->exit(id); + + /* Debugfs stuff is cleaned up by mmc core */ + mmc_remove_host(slot->mmc); + slot->host->slot[id] = NULL; + mmc_free_host(slot->mmc); +} + +static void dw_mci_init_dma(struct dw_mci *host) +{ + /* Alloc memory for sg translation */ + host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE, + &host->sg_dma, GFP_KERNEL); + if (!host->sg_cpu) { + dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n", + __func__); + goto no_dma; + } + + /* Determine which DMA interface to use */ +#ifdef CONFIG_MMC_DW_IDMAC + host->dma_ops = &dw_mci_idmac_ops; + dev_info(&host->pdev->dev, "Using internal DMA controller.\n"); +#endif + + if (!host->dma_ops) + goto no_dma; + + if (host->dma_ops->init) { + if (host->dma_ops->init(host)) { + dev_err(&host->pdev->dev, "%s: Unable to initialize " + "DMA Controller.\n", __func__); + goto no_dma; + } + } else { + dev_err(&host->pdev->dev, "DMA initialization not found.\n"); + goto no_dma; + } + + host->use_dma = 1; + return; + +no_dma: + dev_info(&host->pdev->dev, "Using PIO mode.\n"); + host->use_dma = 0; + return; +} + +static bool mci_wait_reset(struct device *dev, struct dw_mci *host) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(500); + unsigned int ctrl; + + mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | + SDMMC_CTRL_DMA_RESET)); + + /* wait till resets clear */ + do { + ctrl = mci_readl(host, CTRL); + if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | + SDMMC_CTRL_DMA_RESET))) + return true; + } while (time_before(jiffies, timeout)); + + dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl); + + return false; +} + +static int dw_mci_probe(struct platform_device *pdev) +{ + struct dw_mci *host; + struct resource *regs; + struct dw_mci_board *pdata; + int irq, ret, i, width; + u32 fifo_size; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->pdev = pdev; + host->pdata = pdata = pdev->dev.platform_data; + if (!pdata || !pdata->init) { + dev_err(&pdev->dev, + "Platform data must supply init function\n"); + ret = -ENODEV; + goto err_freehost; + } + + if (!pdata->select_slot && pdata->num_slots > 1) { + dev_err(&pdev->dev, + "Platform data must supply select_slot function\n"); + ret = -ENODEV; + goto err_freehost; + } + + if (!pdata->bus_hz) { + dev_err(&pdev->dev, + "Platform data must supply bus speed\n"); + ret = -ENODEV; + goto err_freehost; + } + + host->bus_hz = pdata->bus_hz; + host->quirks = pdata->quirks; + + spin_lock_init(&host->lock); + INIT_LIST_HEAD(&host->queue); + + ret = -ENOMEM; + host->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!host->regs) + goto err_freehost; + + host->dma_ops = pdata->dma_ops; + dw_mci_init_dma(host); + + /* + * Get the host data width - this assumes that HCON has been set with + * the correct values. + */ + i = (mci_readl(host, HCON) >> 7) & 0x7; + if (!i) { + host->push_data = dw_mci_push_data16; + host->pull_data = dw_mci_pull_data16; + width = 16; + host->data_shift = 1; + } else if (i == 2) { + host->push_data = dw_mci_push_data64; + host->pull_data = dw_mci_pull_data64; + width = 64; + host->data_shift = 3; + } else { + /* Check for a reserved value, and warn if it is */ + WARN((i != 1), + "HCON reports a reserved host data width!\n" + "Defaulting to 32-bit access.\n"); + host->push_data = dw_mci_push_data32; + host->pull_data = dw_mci_pull_data32; + width = 32; + host->data_shift = 2; + } + + /* Reset all blocks */ + if (!mci_wait_reset(&pdev->dev, host)) { + ret = -ENODEV; + goto err_dmaunmap; + } + + /* Clear the interrupts for the host controller */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ + + /* Put in max timeout */ + mci_writel(host, TMOUT, 0xFFFFFFFF); + + /* + * FIFO threshold settings RxMark = fifo_size / 2 - 1, + * Tx Mark = fifo_size / 2 DMA Size = 8 + */ + fifo_size = mci_readl(host, FIFOTH); + fifo_size = (fifo_size >> 16) & 0x7ff; + mci_writel(host, FIFOTH, ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | + ((fifo_size/2) << 0))); + + /* disable clock to CIU */ + mci_writel(host, CLKENA, 0); + mci_writel(host, CLKSRC, 0); + + tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); + tasklet_init(&host->card_tasklet, + dw_mci_tasklet_card, (unsigned long)host); + + ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host); + if (ret) + goto err_dmaunmap; + + platform_set_drvdata(pdev, host); + + if (host->pdata->num_slots) + host->num_slots = host->pdata->num_slots; + else + host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; + + /* We need at least one slot to succeed */ + for (i = 0; i < host->num_slots; i++) { + ret = dw_mci_init_slot(host, i); + if (ret) { + ret = -ENODEV; + goto err_init_slot; + } + } + + /* + * Enable interrupts for command done, data over, data empty, card det, + * receive ready and error such as transmit, receive timeout, crc error + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | + SDMMC_INT_TXDR | SDMMC_INT_RXDR | + DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); + mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ + + dev_info(&pdev->dev, "DW MMC controller at irq %d, " + "%d bit host data width\n", irq, width); + if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) + dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n"); + + return 0; + +err_init_slot: + /* De-init any initialized slots */ + while (i > 0) { + if (host->slot[i]) + dw_mci_cleanup_slot(host->slot[i], i); + i--; + } + free_irq(irq, host); + +err_dmaunmap: + if (host->use_dma && host->dma_ops->exit) + host->dma_ops->exit(host); + dma_free_coherent(&host->pdev->dev, PAGE_SIZE, + host->sg_cpu, host->sg_dma); + iounmap(host->regs); + +err_freehost: + kfree(host); + return ret; +} + +static int __exit dw_mci_remove(struct platform_device *pdev) +{ + struct dw_mci *host = platform_get_drvdata(pdev); + int i; + + mci_writel(host, RINTSTS, 0xFFFFFFFF); + mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ + + platform_set_drvdata(pdev, NULL); + + for (i = 0; i < host->num_slots; i++) { + dev_dbg(&pdev->dev, "remove slot %d\n", i); + if (host->slot[i]) + dw_mci_cleanup_slot(host->slot[i], i); + } + + /* disable clock to CIU */ + mci_writel(host, CLKENA, 0); + mci_writel(host, CLKSRC, 0); + + free_irq(platform_get_irq(pdev, 0), host); + dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + + if (host->use_dma && host->dma_ops->exit) + host->dma_ops->exit(host); + + iounmap(host->regs); + + kfree(host); + return 0; +} + +#ifdef CONFIG_PM +/* + * TODO: we should probably disable the clock to the card in the suspend path. + */ +static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + int i, ret; + struct dw_mci *host = platform_get_drvdata(pdev); + + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + if (!slot) + continue; + ret = mmc_suspend_host(slot->mmc); + if (ret < 0) { + while (--i >= 0) { + slot = host->slot[i]; + if (slot) + mmc_resume_host(host->slot[i]->mmc); + } + return ret; + } + } + + return 0; +} + +static int dw_mci_resume(struct platform_device *pdev) +{ + int i, ret; + struct dw_mci *host = platform_get_drvdata(pdev); + + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + if (!slot) + continue; + ret = mmc_resume_host(host->slot[i]->mmc); + if (ret < 0) + return ret; + } + + return 0; +} +#else +#define dw_mci_suspend NULL +#define dw_mci_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver dw_mci_driver = { + .remove = __exit_p(dw_mci_remove), + .suspend = dw_mci_suspend, + .resume = dw_mci_resume, + .driver = { + .name = "dw_mmc", + }, +}; + +static int __init dw_mci_init(void) +{ + return platform_driver_probe(&dw_mci_driver, dw_mci_probe); +} + +static void __exit dw_mci_exit(void) +{ + platform_driver_unregister(&dw_mci_driver); +} + +module_init(dw_mci_init); +module_exit(dw_mci_exit); + +MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); +MODULE_AUTHOR("NXP Semiconductor VietNam"); +MODULE_AUTHOR("Imagination Technologies Ltd"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h new file mode 100644 index 000000000000..5dd55a75233d --- /dev/null +++ b/drivers/mmc/host/dw_mmc.h @@ -0,0 +1,168 @@ +/* + * Synopsys DesignWare Multimedia Card Interface driver + * (Based on NXP driver for lpc 31xx) + * + * Copyright (C) 2009 NXP Semiconductors + * Copyright (C) 2009, 2010 Imagination Technologies Ltd. + * + * 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 _DW_MMC_H_ +#define _DW_MMC_H_ + +#define SDMMC_CTRL 0x000 +#define SDMMC_PWREN 0x004 +#define SDMMC_CLKDIV 0x008 +#define SDMMC_CLKSRC 0x00c +#define SDMMC_CLKENA 0x010 +#define SDMMC_TMOUT 0x014 +#define SDMMC_CTYPE 0x018 +#define SDMMC_BLKSIZ 0x01c +#define SDMMC_BYTCNT 0x020 +#define SDMMC_INTMASK 0x024 +#define SDMMC_CMDARG 0x028 +#define SDMMC_CMD 0x02c +#define SDMMC_RESP0 0x030 +#define SDMMC_RESP1 0x034 +#define SDMMC_RESP2 0x038 +#define SDMMC_RESP3 0x03c +#define SDMMC_MINTSTS 0x040 +#define SDMMC_RINTSTS 0x044 +#define SDMMC_STATUS 0x048 +#define SDMMC_FIFOTH 0x04c +#define SDMMC_CDETECT 0x050 +#define SDMMC_WRTPRT 0x054 +#define SDMMC_GPIO 0x058 +#define SDMMC_TCBCNT 0x05c +#define SDMMC_TBBCNT 0x060 +#define SDMMC_DEBNCE 0x064 +#define SDMMC_USRID 0x068 +#define SDMMC_VERID 0x06c +#define SDMMC_HCON 0x070 +#define SDMMC_BMOD 0x080 +#define SDMMC_PLDMND 0x084 +#define SDMMC_DBADDR 0x088 +#define SDMMC_IDSTS 0x08c +#define SDMMC_IDINTEN 0x090 +#define SDMMC_DSCADDR 0x094 +#define SDMMC_BUFADDR 0x098 +#define SDMMC_DATA 0x100 +#define SDMMC_DATA_ADR 0x100 + +/* shift bit field */ +#define _SBF(f, v) ((v) << (f)) + +/* Control register defines */ +#define SDMMC_CTRL_USE_IDMAC BIT(25) +#define SDMMC_CTRL_CEATA_INT_EN BIT(11) +#define SDMMC_CTRL_SEND_AS_CCSD BIT(10) +#define SDMMC_CTRL_SEND_CCSD BIT(9) +#define SDMMC_CTRL_ABRT_READ_DATA BIT(8) +#define SDMMC_CTRL_SEND_IRQ_RESP BIT(7) +#define SDMMC_CTRL_READ_WAIT BIT(6) +#define SDMMC_CTRL_DMA_ENABLE BIT(5) +#define SDMMC_CTRL_INT_ENABLE BIT(4) +#define SDMMC_CTRL_DMA_RESET BIT(2) +#define SDMMC_CTRL_FIFO_RESET BIT(1) +#define SDMMC_CTRL_RESET BIT(0) +/* Clock Enable register defines */ +#define SDMMC_CLKEN_LOW_PWR BIT(16) +#define SDMMC_CLKEN_ENABLE BIT(0) +/* time-out register defines */ +#define SDMMC_TMOUT_DATA(n) _SBF(8, (n)) +#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00 +#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF) +#define SDMMC_TMOUT_RESP_MSK 0xFF +/* card-type register defines */ +#define SDMMC_CTYPE_8BIT BIT(16) +#define SDMMC_CTYPE_4BIT BIT(0) +#define SDMMC_CTYPE_1BIT 0 +/* Interrupt status & mask register defines */ +#define SDMMC_INT_SDIO BIT(16) +#define SDMMC_INT_EBE BIT(15) +#define SDMMC_INT_ACD BIT(14) +#define SDMMC_INT_SBE BIT(13) +#define SDMMC_INT_HLE BIT(12) +#define SDMMC_INT_FRUN BIT(11) +#define SDMMC_INT_HTO BIT(10) +#define SDMMC_INT_DTO BIT(9) +#define SDMMC_INT_RTO BIT(8) +#define SDMMC_INT_DCRC BIT(7) +#define SDMMC_INT_RCRC BIT(6) +#define SDMMC_INT_RXDR BIT(5) +#define SDMMC_INT_TXDR BIT(4) +#define SDMMC_INT_DATA_OVER BIT(3) +#define SDMMC_INT_CMD_DONE BIT(2) +#define SDMMC_INT_RESP_ERR BIT(1) +#define SDMMC_INT_CD BIT(0) +#define SDMMC_INT_ERROR 0xbfc2 +/* Command register defines */ +#define SDMMC_CMD_START BIT(31) +#define SDMMC_CMD_CCS_EXP BIT(23) +#define SDMMC_CMD_CEATA_RD BIT(22) +#define SDMMC_CMD_UPD_CLK BIT(21) +#define SDMMC_CMD_INIT BIT(15) +#define SDMMC_CMD_STOP BIT(14) +#define SDMMC_CMD_PRV_DAT_WAIT BIT(13) +#define SDMMC_CMD_SEND_STOP BIT(12) +#define SDMMC_CMD_STRM_MODE BIT(11) +#define SDMMC_CMD_DAT_WR BIT(10) +#define SDMMC_CMD_DAT_EXP BIT(9) +#define SDMMC_CMD_RESP_CRC BIT(8) +#define SDMMC_CMD_RESP_LONG BIT(7) +#define SDMMC_CMD_RESP_EXP BIT(6) +#define SDMMC_CMD_INDX(n) ((n) & 0x1F) +/* Status register defines */ +#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF) +#define SDMMC_FIFO_SZ 32 +/* Internal DMAC interrupt defines */ +#define SDMMC_IDMAC_INT_AI BIT(9) +#define SDMMC_IDMAC_INT_NI BIT(8) +#define SDMMC_IDMAC_INT_CES BIT(5) +#define SDMMC_IDMAC_INT_DU BIT(4) +#define SDMMC_IDMAC_INT_FBE BIT(2) +#define SDMMC_IDMAC_INT_RI BIT(1) +#define SDMMC_IDMAC_INT_TI BIT(0) +/* Internal DMAC bus mode bits */ +#define SDMMC_IDMAC_ENABLE BIT(7) +#define SDMMC_IDMAC_FB BIT(1) +#define SDMMC_IDMAC_SWRESET BIT(0) + +/* Register access macros */ +#define mci_readl(dev, reg) \ + __raw_readl(dev->regs + SDMMC_##reg) +#define mci_writel(dev, reg, value) \ + __raw_writel((value), dev->regs + SDMMC_##reg) + +/* 16-bit FIFO access macros */ +#define mci_readw(dev, reg) \ + __raw_readw(dev->regs + SDMMC_##reg) +#define mci_writew(dev, reg, value) \ + __raw_writew((value), dev->regs + SDMMC_##reg) + +/* 64-bit FIFO access macros */ +#ifdef readq +#define mci_readq(dev, reg) \ + __raw_readq(dev->regs + SDMMC_##reg) +#define mci_writeq(dev, reg, value) \ + __raw_writeq((value), dev->regs + SDMMC_##reg) +#else +/* + * Dummy readq implementation for architectures that don't define it. + * + * We would assume that none of these architectures would configure + * the IP block with a 64bit FIFO width, so this code will never be + * executed on those machines. Defining these macros here keeps the + * rest of the code free from ifdefs. + */ +#define mci_readq(dev, reg) \ + (*(volatile u64 __force *)(dev->regs + SDMMC_##reg)) +#define mci_writeq(dev, reg, value) \ + (*(volatile u64 __force *)(dev->regs + SDMMC_##reg) = value) +#endif + +#endif /* _DW_MMC_H_ */ diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h new file mode 100644 index 000000000000..16b0261763ed --- /dev/null +++ b/include/linux/mmc/dw_mmc.h @@ -0,0 +1,217 @@ +/* + * Synopsys DesignWare Multimedia Card Interface driver + * (Based on NXP driver for lpc 31xx) + * + * Copyright (C) 2009 NXP Semiconductors + * Copyright (C) 2009, 2010 Imagination Technologies Ltd. + * + * 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 _LINUX_MMC_DW_MMC_H_ +#define _LINUX_MMC_DW_MMC_H_ + +#define MAX_MCI_SLOTS 2 + +enum dw_mci_state { + STATE_IDLE = 0, + STATE_SENDING_CMD, + STATE_SENDING_DATA, + STATE_DATA_BUSY, + STATE_SENDING_STOP, + STATE_DATA_ERROR, +}; + +enum { + EVENT_CMD_COMPLETE = 0, + EVENT_XFER_COMPLETE, + EVENT_DATA_COMPLETE, + EVENT_DATA_ERROR, + EVENT_XFER_ERROR +}; + +struct mmc_data; + +/** + * struct dw_mci - MMC controller state shared between all slots + * @lock: Spinlock protecting the queue and associated data. + * @regs: Pointer to MMIO registers. + * @sg: Scatterlist entry currently being processed by PIO code, if any. + * @pio_offset: Offset into the current scatterlist entry. + * @cur_slot: The slot which is currently using the controller. + * @mrq: The request currently being processed on @cur_slot, + * or NULL if the controller is idle. + * @cmd: The command currently being sent to the card, or NULL. + * @data: The data currently being transferred, or NULL if no data + * transfer is in progress. + * @use_dma: Whether DMA channel is initialized or not. + * @sg_dma: Bus address of DMA buffer. + * @sg_cpu: Virtual address of DMA buffer. + * @dma_ops: Pointer to platform-specific DMA callbacks. + * @cmd_status: Snapshot of SR taken upon completion of the current + * command. Only valid when EVENT_CMD_COMPLETE is pending. + * @data_status: Snapshot of SR taken upon completion of the current + * data transfer. Only valid when EVENT_DATA_COMPLETE or + * EVENT_DATA_ERROR is pending. + * @stop_cmdr: Value to be loaded into CMDR when the stop command is + * to be sent. + * @dir_status: Direction of current transfer. + * @tasklet: Tasklet running the request state machine. + * @card_tasklet: Tasklet handling card detect. + * @pending_events: Bitmask of events flagged by the interrupt handler + * to be processed by the tasklet. + * @completed_events: Bitmask of events which the state machine has + * processed. + * @state: Tasklet state. + * @queue: List of slots waiting for access to the controller. + * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus + * rate and timeout calculations. + * @current_speed: Configured rate of the controller. + * @num_slots: Number of slots available. + * @pdev: Platform device associated with the MMC controller. + * @pdata: Platform data associated with the MMC controller. + * @slot: Slots sharing this MMC controller. + * @data_shift: log2 of FIFO item size. + * @push_data: Pointer to FIFO push function. + * @pull_data: Pointer to FIFO pull function. + * @quirks: Set of quirks that apply to specific versions of the IP. + * + * Locking + * ======= + * + * @lock is a softirq-safe spinlock protecting @queue as well as + * @cur_slot, @mrq and @state. These must always be updated + * at the same time while holding @lock. + * + * The @mrq field of struct dw_mci_slot is also protected by @lock, + * and must always be written at the same time as the slot is added to + * @queue. + * + * @pending_events and @completed_events are accessed using atomic bit + * operations, so they don't need any locking. + * + * None of the fields touched by the interrupt handler need any + * locking. However, ordering is important: Before EVENT_DATA_ERROR or + * EVENT_DATA_COMPLETE is set in @pending_events, all data-related + * interrupts must be disabled and @data_status updated with a + * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the + * CMDRDY interupt must be disabled and @cmd_status updated with a + * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the + * bytes_xfered field of @data must be written. This is ensured by + * using barriers. + */ +struct dw_mci { + spinlock_t lock; + void __iomem *regs; + + struct scatterlist *sg; + unsigned int pio_offset; + + struct dw_mci_slot *cur_slot; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + + /* DMA interface members*/ + int use_dma; + + dma_addr_t sg_dma; + void *sg_cpu; + struct dw_mci_dma_ops *dma_ops; +#ifdef CONFIG_MMC_DW_IDMAC + unsigned int ring_size; +#else + struct dw_mci_dma_data *dma_data; +#endif + u32 cmd_status; + u32 data_status; + u32 stop_cmdr; + u32 dir_status; + struct tasklet_struct tasklet; + struct tasklet_struct card_tasklet; + unsigned long pending_events; + unsigned long completed_events; + enum dw_mci_state state; + struct list_head queue; + + u32 bus_hz; + u32 current_speed; + u32 num_slots; + struct platform_device *pdev; + struct dw_mci_board *pdata; + struct dw_mci_slot *slot[MAX_MCI_SLOTS]; + + /* FIFO push and pull */ + int data_shift; + void (*push_data)(struct dw_mci *host, void *buf, int cnt); + void (*pull_data)(struct dw_mci *host, void *buf, int cnt); + + /* Workaround flags */ + u32 quirks; +}; + +/* DMA ops for Internal/External DMAC interface */ +struct dw_mci_dma_ops { + /* DMA Ops */ + int (*init)(struct dw_mci *host); + void (*start)(struct dw_mci *host, unsigned int sg_len); + void (*complete)(struct dw_mci *host); + void (*stop)(struct dw_mci *host); + void (*cleanup)(struct dw_mci *host); + void (*exit)(struct dw_mci *host); +}; + +/* IP Quirks/flags. */ +/* No special quirks or flags to cater for */ +#define DW_MCI_QUIRK_NONE 0 +/* DTO fix for command transmission with IDMAC configured */ +#define DW_MCI_QUIRK_IDMAC_DTO 1 +/* delay needed between retries on some 2.11a implementations */ +#define DW_MCI_QUIRK_RETRY_DELAY 2 +/* High Speed Capable - Supports HS cards (upto 50MHz) */ +#define DW_MCI_QUIRK_HIGHSPEED 4 + + +struct dma_pdata; + +struct block_settings { + unsigned short max_segs; /* see blk_queue_max_segments */ + unsigned int max_blk_size; /* maximum size of one mmc block */ + unsigned int max_blk_count; /* maximum number of blocks in one req*/ + unsigned int max_req_size; /* maximum number of bytes in one req*/ + unsigned int max_seg_size; /* see blk_queue_max_segment_size */ +}; + +/* Board platform data */ +struct dw_mci_board { + u32 num_slots; + + u32 quirks; /* Workaround / Quirk flags */ + unsigned int bus_hz; /* Bus speed */ + + /* delay in mS before detecting cards after interrupt */ + u32 detect_delay_ms; + + int (*init)(u32 slot_id, irq_handler_t , void *); + int (*get_ro)(u32 slot_id); + int (*get_cd)(u32 slot_id); + int (*get_ocr)(u32 slot_id); + int (*get_bus_wd)(u32 slot_id); + /* + * Enable power to selected slot and set voltage to desired level. + * Voltage levels are specified using MMC_VDD_xxx defines defined + * in linux/mmc/host.h file. + */ + void (*setpower)(u32 slot_id, u32 volt); + void (*exit)(u32 slot_id); + void (*select_slot)(u32 slot_id); + + struct dw_mci_dma_ops *dma_ops; + struct dma_pdata *data; + struct block_settings *blk_settings; +}; + +#endif /* _LINUX_MMC_DW_MMC_H_ */ -- cgit v1.2.3 From 08c82dfad2458f8f9b83126224a85e7ea9e2b046 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Dec 2010 09:59:44 +0100 Subject: mmc: fix mmc_set_bus_width_ddr() call without bus-width-test cap With the bus-width test patch, mmc_set_bus_width*() isn't called properly when the driver doesn't set MMC_CAP_BUS_WIDTH and no DDR mode. This patch fixes the regression by moving the call up before the cap test. Signed-off-by: Takashi Iwai Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 1d8409fcf155..c86dd7384d7d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -558,6 +558,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][0]); if (!err) { + mmc_set_bus_width_ddr(card->host, + bus_width, MMC_SDR_MODE); /* * If controller can't handle bus width test, * use the highest bus width to maintain @@ -565,8 +567,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) break; - mmc_set_bus_width_ddr(card->host, - bus_width, MMC_SDR_MODE); err = mmc_bus_test(card, bus_width); if (!err) break; -- cgit v1.2.3 From 807e8e40673d9628fa7dcdd14423424b4ee5f43b Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 3 Jan 2011 10:36:56 -0800 Subject: mmc: Fix sd/sdio/mmc initialization frequency retries Rewrite and clean up mmc_rescan() to properly retry frequencies lower than 400kHz. Failures can happen both in sd_send_* calls and mmc_attach_*. Break out "mmc_rescan_try_freq" from the frequency selection loop. Symmetrize claim/release logic in mmc_attach_* API, and move the sd_send_* calls there to make mmc_rescan easier to read. Signed-off-by: Andy Ross Reviewed-and-Tested-by: Hein Tibosch Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 119 +++++++++++++++--------------------------------- drivers/mmc/core/core.h | 6 +-- drivers/mmc/core/mmc.c | 13 ++++-- drivers/mmc/core/sd.c | 11 +++-- drivers/mmc/core/sdio.c | 18 +++++--- 5 files changed, 68 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 97e0624eb9b6..198f70bad908 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1485,25 +1485,41 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) } EXPORT_SYMBOL(mmc_set_blocklen); +static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) +{ + host->f_init = freq; + +#ifdef CONFIG_MMC_DEBUG + pr_info("%s: %s: trying to init card at %u Hz\n", + mmc_hostname(host), __func__, host->f_init); +#endif + mmc_power_up(host); + sdio_reset(host); + mmc_go_idle(host); + + mmc_send_if_cond(host, host->ocr_avail); + + /* Order's important: probe SDIO, then SD, then MMC */ + if (!mmc_attach_sdio(host)) + return 0; + if (!mmc_attach_sd(host)) + return 0; + if (!mmc_attach_mmc(host)) + return 0; + + mmc_power_off(host); + return -EIO; +} + void mmc_rescan(struct work_struct *work) { + static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; struct mmc_host *host = container_of(work, struct mmc_host, detect.work); - u32 ocr; - int err; - unsigned long flags; int i; - const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; - - spin_lock_irqsave(&host->lock, flags); - if (host->rescan_disable) { - spin_unlock_irqrestore(&host->lock, flags); + if (host->rescan_disable) return; - } - - spin_unlock_irqrestore(&host->lock, flags); - mmc_bus_get(host); @@ -1526,8 +1542,6 @@ void mmc_rescan(struct work_struct *work) goto out; } - /* detect a newly inserted card */ - /* * Only we can add a new handler, so it's safe to * release the lock here. @@ -1537,77 +1551,16 @@ void mmc_rescan(struct work_struct *work) if (host->ops->get_cd && host->ops->get_cd(host) == 0) goto out; + mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { - mmc_claim_host(host); - - if (freqs[i] >= host->f_min) - host->f_init = freqs[i]; - else if (!i || freqs[i-1] > host->f_min) - host->f_init = host->f_min; - else { - mmc_release_host(host); - goto out; - } -#ifdef CONFIG_MMC_DEBUG - pr_info("%s: %s: trying to init card at %u Hz\n", - mmc_hostname(host), __func__, host->f_init); -#endif - mmc_power_up(host); - sdio_reset(host); - mmc_go_idle(host); - - mmc_send_if_cond(host, host->ocr_avail); - - /* - * First we search for SDIO... - */ - err = mmc_send_io_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_sdio(host, ocr)) { - mmc_claim_host(host); - /* - * Try SDMEM (but not MMC) even if SDIO - * is broken. - */ - mmc_power_up(host); - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); - - if (mmc_send_app_op_cond(host, 0, &ocr)) - goto out_fail; - - if (mmc_attach_sd(host, ocr)) - mmc_power_off(host); - } - goto out; - } - - /* - * ...then normal SD... - */ - err = mmc_send_app_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_sd(host, ocr)) - mmc_power_off(host); - goto out; - } - - /* - * ...and finally MMC. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_mmc(host, ocr)) - mmc_power_off(host); - goto out; - } - -out_fail: - mmc_release_host(host); - mmc_power_off(host); + if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) + break; + if (freqs[i] < host->f_min) + break; } -out: + mmc_release_host(host); + + out: if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); } diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 026c975b99a9..ca1fdde29df6 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -57,9 +57,9 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); -int mmc_attach_mmc(struct mmc_host *host, u32 ocr); -int mmc_attach_sd(struct mmc_host *host, u32 ocr); -int mmc_attach_sdio(struct mmc_host *host, u32 ocr); +int mmc_attach_mmc(struct mmc_host *host); +int mmc_attach_sd(struct mmc_host *host); +int mmc_attach_sdio(struct mmc_host *host); /* Module parameters */ extern int use_spi_crc; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c86dd7384d7d..16006ef153fe 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -755,13 +755,18 @@ static void mmc_attach_bus_ops(struct mmc_host *host) /* * Starting point for MMC card init. */ -int mmc_attach_mmc(struct mmc_host *host, u32 ocr) +int mmc_attach_mmc(struct mmc_host *host) { int err; + u32 ocr; BUG_ON(!host); WARN_ON(!host->claimed); + err = mmc_send_op_cond(host, 0, &ocr); + if (err) + return err; + mmc_attach_bus_ops(host); if (host->ocr_avail_mmc) host->ocr_avail = host->ocr_avail_mmc; @@ -804,20 +809,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) goto err; mmc_release_host(host); - err = mmc_add_card(host->card); + mmc_claim_host(host); if (err) goto remove_card; return 0; remove_card: + mmc_release_host(host); mmc_remove_card(host->card); - host->card = NULL; mmc_claim_host(host); + host->card = NULL; err: mmc_detach_bus(host); - mmc_release_host(host); printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", mmc_hostname(host), err); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index de062ebd8b26..d18c32bca99b 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -764,13 +764,18 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host) /* * Starting point for SD card init. */ -int mmc_attach_sd(struct mmc_host *host, u32 ocr) +int mmc_attach_sd(struct mmc_host *host) { int err; + u32 ocr; BUG_ON(!host); WARN_ON(!host->claimed); + err = mmc_send_app_op_cond(host, 0, &ocr); + if (err) + return err; + mmc_sd_attach_bus_ops(host); if (host->ocr_avail_sd) host->ocr_avail = host->ocr_avail_sd; @@ -823,20 +828,20 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) goto err; mmc_release_host(host); - err = mmc_add_card(host->card); + mmc_claim_host(host); if (err) goto remove_card; return 0; remove_card: + mmc_release_host(host); mmc_remove_card(host->card); host->card = NULL; mmc_claim_host(host); err: mmc_detach_bus(host); - mmc_release_host(host); printk(KERN_ERR "%s: error %d whilst initialising SD card\n", mmc_hostname(host), err); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 82f4b9008987..5c4a54d9b6a4 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -702,15 +702,19 @@ static const struct mmc_bus_ops mmc_sdio_ops = { /* * Starting point for SDIO card init. */ -int mmc_attach_sdio(struct mmc_host *host, u32 ocr) +int mmc_attach_sdio(struct mmc_host *host) { - int err; - int i, funcs; + int err, i, funcs; + u32 ocr; struct mmc_card *card; BUG_ON(!host); WARN_ON(!host->claimed); + err = mmc_send_io_op_cond(host, 0, &ocr); + if (err) + return err; + mmc_attach_bus(host, &mmc_sdio_ops); if (host->ocr_avail_sdio) host->ocr_avail = host->ocr_avail_sdio; @@ -783,12 +787,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) pm_runtime_enable(&card->sdio_func[i]->dev); } - mmc_release_host(host); - /* * First add the card to the driver model... */ + mmc_release_host(host); err = mmc_add_card(host->card); + mmc_claim_host(host); if (err) goto remove_added; @@ -806,15 +810,17 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) remove_added: /* Remove without lock if the device has been added. */ + mmc_release_host(host); mmc_sdio_remove(host); mmc_claim_host(host); remove: /* And with lock if it hasn't been added. */ + mmc_release_host(host); if (host->card) mmc_sdio_remove(host); + mmc_claim_host(host); err: mmc_detach_bus(host); - mmc_release_host(host); printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", mmc_hostname(host), err); -- cgit v1.2.3 From c584179828b268152f5ff82dab529a2c095b09ac Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 4 Jan 2011 12:20:22 -0500 Subject: mmc: Explain why we make adjacent mmc_bus_{put,get} calls during rescan. Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 198f70bad908..4b1d8fb04e9b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1531,9 +1531,11 @@ void mmc_rescan(struct work_struct *work) && mmc_card_is_removable(host)) host->bus_ops->detect(host); + /* + * Let mmc_bus_put() free the bus/bus_ops if we've found that + * the card is no longer present. + */ mmc_bus_put(host); - - mmc_bus_get(host); /* if there still is a card present, stop here */ -- cgit v1.2.3 From b37427b0a4e01ab5aaec1c9af7cef616ac4ce6d6 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 4 Jan 2011 12:39:20 -0500 Subject: mmc: MMC_BLOCK_MINORS should depend on MMC_BLOCK. Signed-off-by: Chris Ball Tested-by: Chris Ball Acked-by: Olof Johansson --- drivers/mmc/card/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index 57e4416b9ef0..2a876c4099cd 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -16,6 +16,7 @@ config MMC_BLOCK config MMC_BLOCK_MINORS int "Number of minors per block device" + depends on MMC_BLOCK range 4 256 default 8 help -- cgit v1.2.3 From 1a2727e98786136fb968b18d96f8ecdd9ba38aa8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 4 Jan 2011 12:55:14 -0500 Subject: mmc: Register debugfs dir before calling card probe function. This way, the probe function may register debugfs files if it wants to. This fixes a bug with mmc_test where mmc_test_register_file_test() is called before the card's debugfs dir exists, and so it fails. Signed-off-by: Viresh Kumar Tested-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/bus.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index af8dc6a2a317..63667a8f140c 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -303,14 +303,14 @@ int mmc_add_card(struct mmc_card *card) type, card->rca); } - ret = device_add(&card->dev); - if (ret) - return ret; - #ifdef CONFIG_DEBUG_FS mmc_add_card_debugfs(card); #endif + ret = device_add(&card->dev); + if (ret) + return ret; + mmc_card_set_present(card); return 0; -- cgit v1.2.3 From 729b0c79c2c0f631bffe1be5abaf291febf7792f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Nov 2010 12:15:06 +0100 Subject: mmc: tmio_mmc: allow multi-element scatter-gather lists The driver is capable of handling multi-element sg lists in both PIO and DMA modes. In DMA mode this also allows to use the DMA sg capability more efficiently and almost doubles the throughput. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e7765a89593e..4e75799291ca 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -864,10 +864,15 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) goto host_free; mmc->ops = &tmio_mmc_ops; - mmc->caps = MMC_CAP_4_BIT_DATA; - mmc->caps |= pdata->capabilities; + mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; mmc->f_max = pdata->hclk; mmc->f_min = mmc->f_max / 512; + mmc->max_segs = 32; + mmc->max_blk_size = 512; + mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * + mmc->max_segs; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; if (pdata->ocr_mask) mmc->ocr_avail = pdata->ocr_mask; else -- cgit v1.2.3 From ef17fee1e559b3faeb6f89963e78ad47731d18a1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Nov 2010 12:19:47 +0100 Subject: mmc: tmio_mmc: fix PIO fallback on DMA descriptor allocation failure The easiest way to fall back to PIO, when a DMA descriptor allocation fails is to disable DMA on the controller but continue with the current request in PIO mode. This way tmio_mmc_start_dma() can become void, since it cannot be failing any more. The current version is also broken: it is testing a wrong pointer and thus failing to recognise, that a descriptor allocation wasn't successful. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 69 ++++++++++++++++----------------------------- drivers/mmc/host/tmio_mmc.h | 2 -- 2 files changed, 25 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 4e75799291ca..63115a6de935 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -427,11 +427,12 @@ static void tmio_dma_complete(void *arg) enable_mmc_irqs(host, TMIO_STAT_DATAEND); } -static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) +static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) { struct scatterlist *sg = host->sg_ptr; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; + dma_cookie_t cookie; int ret; ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_FROM_DEVICE); @@ -442,21 +443,20 @@ static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) } if (desc) { - host->desc = desc; desc->callback = tmio_dma_complete; desc->callback_param = host; - host->cookie = desc->tx_submit(desc); - if (host->cookie < 0) { - host->desc = NULL; - ret = host->cookie; + cookie = desc->tx_submit(desc); + if (cookie < 0) { + desc = NULL; + ret = cookie; } else { chan->device->device_issue_pending(chan); } } dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, host->cookie, host->mrq); + __func__, host->sg_len, ret, cookie, host->mrq); - if (!host->desc) { + if (!desc) { /* DMA failed, fall back to PIO */ if (ret >= 0) ret = -EIO; @@ -471,23 +471,18 @@ static int tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) dev_warn(&host->pdev->dev, "DMA failed: %d, falling back to PIO\n", ret); tmio_mmc_enable_dma(host, false); - reset(host); - /* Fail this request, let above layers recover */ - host->mrq->cmd->error = ret; - tmio_mmc_finish_request(host); } dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, host->cookie, host->sg_len); - - return ret > 0 ? 0 : ret; + desc, cookie, host->sg_len); } -static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) +static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) { struct scatterlist *sg = host->sg_ptr; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; + dma_cookie_t cookie; int ret; ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_TO_DEVICE); @@ -498,19 +493,18 @@ static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) } if (desc) { - host->desc = desc; desc->callback = tmio_dma_complete; desc->callback_param = host; - host->cookie = desc->tx_submit(desc); - if (host->cookie < 0) { - host->desc = NULL; - ret = host->cookie; + cookie = desc->tx_submit(desc); + if (cookie < 0) { + desc = NULL; + ret = cookie; } } dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, host->cookie, host->mrq); + __func__, host->sg_len, ret, cookie, host->mrq); - if (!host->desc) { + if (!desc) { /* DMA failed, fall back to PIO */ if (ret >= 0) ret = -EIO; @@ -525,30 +519,22 @@ static int tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) dev_warn(&host->pdev->dev, "DMA failed: %d, falling back to PIO\n", ret); tmio_mmc_enable_dma(host, false); - reset(host); - /* Fail this request, let above layers recover */ - host->mrq->cmd->error = ret; - tmio_mmc_finish_request(host); } dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, - desc, host->cookie); - - return ret > 0 ? 0 : ret; + desc, cookie); } -static int tmio_mmc_start_dma(struct tmio_mmc_host *host, +static void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data) { if (data->flags & MMC_DATA_READ) { if (host->chan_rx) - return tmio_mmc_start_dma_rx(host); + tmio_mmc_start_dma_rx(host); } else { if (host->chan_tx) - return tmio_mmc_start_dma_tx(host); + tmio_mmc_start_dma_tx(host); } - - return 0; } static void tmio_issue_tasklet_fn(unsigned long priv) @@ -584,9 +570,6 @@ static bool tmio_mmc_filter(struct dma_chan *chan, void *arg) static void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) { - host->cookie = -EINVAL; - host->desc = NULL; - /* We can only either use DMA for both Tx and Rx or not use it at all */ if (pdata->dma) { dma_cap_mask_t mask; @@ -632,15 +615,11 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host) host->chan_rx = NULL; dma_release_channel(chan); } - - host->cookie = -EINVAL; - host->desc = NULL; } #else -static int tmio_mmc_start_dma(struct tmio_mmc_host *host, +static void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data) { - return 0; } static void tmio_mmc_request_dma(struct tmio_mmc_host *host, @@ -682,7 +661,9 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); - return tmio_mmc_start_dma(host, data); + tmio_mmc_start_dma(host, data); + + return 0; } /* Process requests from the MMC layer */ diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 0fedc78e3ea5..0b7d9162c1b5 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -112,9 +112,7 @@ struct tmio_mmc_host { struct tasklet_struct dma_complete; struct tasklet_struct dma_issue; #ifdef CONFIG_TMIO_MMC_DMA - struct dma_async_tx_descriptor *desc; unsigned int dma_sglen; - dma_cookie_t cookie; #endif }; -- cgit v1.2.3 From e0bc6ff8b8d5c066d978d23e690d5599db4cb2b3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 23 Nov 2010 17:24:11 +0100 Subject: mmc: tmio_mmc: merge the private header into the driver drivers/mmc/host/tmio_mmc.h is only used by drivers/mmc/host/tmio_mmc.c, this needlessly complicates source-code handling. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 215 ++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/tmio_mmc.h | 226 -------------------------------------------- 2 files changed, 210 insertions(+), 231 deletions(-) delete mode 100644 drivers/mmc/host/tmio_mmc.h (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 63115a6de935..e04c032abb1c 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -25,16 +25,221 @@ * double buffer support * */ -#include -#include -#include + #include +#include #include -#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include + +#define CTL_SD_CMD 0x00 +#define CTL_ARG_REG 0x04 +#define CTL_STOP_INTERNAL_ACTION 0x08 +#define CTL_XFER_BLK_COUNT 0xa +#define CTL_RESPONSE 0x0c +#define CTL_STATUS 0x1c +#define CTL_IRQ_MASK 0x20 +#define CTL_SD_CARD_CLK_CTL 0x24 +#define CTL_SD_XFER_LEN 0x26 +#define CTL_SD_MEM_CARD_OPT 0x28 +#define CTL_SD_ERROR_DETAIL_STATUS 0x2c +#define CTL_SD_DATA_PORT 0x30 +#define CTL_TRANSACTION_CTL 0x34 +#define CTL_RESET_SD 0xe0 +#define CTL_SDIO_REGS 0x100 +#define CTL_CLK_AND_WAIT_CTL 0x138 +#define CTL_RESET_SDIO 0x1e0 + +/* Definitions for values the CTRL_STATUS register can take. */ +#define TMIO_STAT_CMDRESPEND 0x00000001 +#define TMIO_STAT_DATAEND 0x00000004 +#define TMIO_STAT_CARD_REMOVE 0x00000008 +#define TMIO_STAT_CARD_INSERT 0x00000010 +#define TMIO_STAT_SIGSTATE 0x00000020 +#define TMIO_STAT_WRPROTECT 0x00000080 +#define TMIO_STAT_CARD_REMOVE_A 0x00000100 +#define TMIO_STAT_CARD_INSERT_A 0x00000200 +#define TMIO_STAT_SIGSTATE_A 0x00000400 +#define TMIO_STAT_CMD_IDX_ERR 0x00010000 +#define TMIO_STAT_CRCFAIL 0x00020000 +#define TMIO_STAT_STOPBIT_ERR 0x00040000 +#define TMIO_STAT_DATATIMEOUT 0x00080000 +#define TMIO_STAT_RXOVERFLOW 0x00100000 +#define TMIO_STAT_TXUNDERRUN 0x00200000 +#define TMIO_STAT_CMDTIMEOUT 0x00400000 +#define TMIO_STAT_RXRDY 0x01000000 +#define TMIO_STAT_TXRQ 0x02000000 +#define TMIO_STAT_ILL_FUNC 0x20000000 +#define TMIO_STAT_CMD_BUSY 0x40000000 +#define TMIO_STAT_ILL_ACCESS 0x80000000 + +/* Define some IRQ masks */ +/* This is the mask used at reset by the chip */ +#define TMIO_MASK_ALL 0x837f031d +#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) +#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) +#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) + +#define enable_mmc_irqs(host, i) \ + do { \ + u32 mask;\ + mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ + mask &= ~((i) & TMIO_MASK_IRQ); \ + sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ + } while (0) + +#define disable_mmc_irqs(host, i) \ + do { \ + u32 mask;\ + mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ + mask |= ((i) & TMIO_MASK_IRQ); \ + sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ + } while (0) + +#define ack_mmc_irqs(host, i) \ + do { \ + sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ + } while (0) + + +struct tmio_mmc_host { + void __iomem *ctl; + unsigned long bus_shift; + struct mmc_command *cmd; + struct mmc_request *mrq; + struct mmc_data *data; + struct mmc_host *mmc; + int irq; + + /* Callbacks for clock / power control */ + void (*set_pwr)(struct platform_device *host, int state); + void (*set_clk_div)(struct platform_device *host, int state); + + /* pio related stuff */ + struct scatterlist *sg_ptr; + unsigned int sg_len; + unsigned int sg_off; + + struct platform_device *pdev; + + /* DMA support */ + struct dma_chan *chan_rx; + struct dma_chan *chan_tx; + struct tasklet_struct dma_complete; + struct tasklet_struct dma_issue; +#ifdef CONFIG_TMIO_MMC_DMA + unsigned int dma_sglen; +#endif +}; -#include "tmio_mmc.h" +static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) +{ + return readw(host->ctl + (addr << host->bus_shift)); +} + +static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, + u16 *buf, int count) +{ + readsw(host->ctl + (addr << host->bus_shift), buf, count); +} + +static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) +{ + return readw(host->ctl + (addr << host->bus_shift)) | + readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; +} + +static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) +{ + writew(val, host->ctl + (addr << host->bus_shift)); +} + +static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, + u16 *buf, int count) +{ + writesw(host->ctl + (addr << host->bus_shift), buf, count); +} + +static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) +{ + writew(val, host->ctl + (addr << host->bus_shift)); + writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); +} + +static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) +{ + host->sg_len = data->sg_len; + host->sg_ptr = data->sg; + host->sg_off = 0; +} + +static int tmio_mmc_next_sg(struct tmio_mmc_host *host) +{ + host->sg_ptr = sg_next(host->sg_ptr); + host->sg_off = 0; + return --host->sg_len; +} + +static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) +{ + local_irq_save(*flags); + return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; +} + +static void tmio_mmc_kunmap_atomic(void *virt, unsigned long *flags) +{ + kunmap_atomic(virt, KM_BIO_SRC_IRQ); + local_irq_restore(*flags); +} + +#ifdef CONFIG_MMC_DEBUG + +#define STATUS_TO_TEXT(a) \ + do { \ + if (status & TMIO_STAT_##a) \ + printk(#a); \ + } while (0) + +void pr_debug_status(u32 status) +{ + printk(KERN_DEBUG "status: %08x = ", status); + STATUS_TO_TEXT(CARD_REMOVE); + STATUS_TO_TEXT(CARD_INSERT); + STATUS_TO_TEXT(SIGSTATE); + STATUS_TO_TEXT(WRPROTECT); + STATUS_TO_TEXT(CARD_REMOVE_A); + STATUS_TO_TEXT(CARD_INSERT_A); + STATUS_TO_TEXT(SIGSTATE_A); + STATUS_TO_TEXT(CMD_IDX_ERR); + STATUS_TO_TEXT(STOPBIT_ERR); + STATUS_TO_TEXT(ILL_FUNC); + STATUS_TO_TEXT(CMD_BUSY); + STATUS_TO_TEXT(CMDRESPEND); + STATUS_TO_TEXT(DATAEND); + STATUS_TO_TEXT(CRCFAIL); + STATUS_TO_TEXT(DATATIMEOUT); + STATUS_TO_TEXT(CMDTIMEOUT); + STATUS_TO_TEXT(RXOVERFLOW); + STATUS_TO_TEXT(TXUNDERRUN); + STATUS_TO_TEXT(RXRDY); + STATUS_TO_TEXT(TXRQ); + STATUS_TO_TEXT(ILL_ACCESS); + printk("\n"); +} + +#else +#define pr_debug_status(s) do { } while (0) +#endif static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) { diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h deleted file mode 100644 index 0b7d9162c1b5..000000000000 --- a/drivers/mmc/host/tmio_mmc.h +++ /dev/null @@ -1,226 +0,0 @@ -/* Definitons for use with the tmio_mmc.c - * - * (c) 2004 Ian Molton - * (c) 2007 Ian Molton - * - * 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. - * - */ - -#include -#include -#include - -#define CTL_SD_CMD 0x00 -#define CTL_ARG_REG 0x04 -#define CTL_STOP_INTERNAL_ACTION 0x08 -#define CTL_XFER_BLK_COUNT 0xa -#define CTL_RESPONSE 0x0c -#define CTL_STATUS 0x1c -#define CTL_IRQ_MASK 0x20 -#define CTL_SD_CARD_CLK_CTL 0x24 -#define CTL_SD_XFER_LEN 0x26 -#define CTL_SD_MEM_CARD_OPT 0x28 -#define CTL_SD_ERROR_DETAIL_STATUS 0x2c -#define CTL_SD_DATA_PORT 0x30 -#define CTL_TRANSACTION_CTL 0x34 -#define CTL_RESET_SD 0xe0 -#define CTL_SDIO_REGS 0x100 -#define CTL_CLK_AND_WAIT_CTL 0x138 -#define CTL_RESET_SDIO 0x1e0 - -/* Definitions for values the CTRL_STATUS register can take. */ -#define TMIO_STAT_CMDRESPEND 0x00000001 -#define TMIO_STAT_DATAEND 0x00000004 -#define TMIO_STAT_CARD_REMOVE 0x00000008 -#define TMIO_STAT_CARD_INSERT 0x00000010 -#define TMIO_STAT_SIGSTATE 0x00000020 -#define TMIO_STAT_WRPROTECT 0x00000080 -#define TMIO_STAT_CARD_REMOVE_A 0x00000100 -#define TMIO_STAT_CARD_INSERT_A 0x00000200 -#define TMIO_STAT_SIGSTATE_A 0x00000400 -#define TMIO_STAT_CMD_IDX_ERR 0x00010000 -#define TMIO_STAT_CRCFAIL 0x00020000 -#define TMIO_STAT_STOPBIT_ERR 0x00040000 -#define TMIO_STAT_DATATIMEOUT 0x00080000 -#define TMIO_STAT_RXOVERFLOW 0x00100000 -#define TMIO_STAT_TXUNDERRUN 0x00200000 -#define TMIO_STAT_CMDTIMEOUT 0x00400000 -#define TMIO_STAT_RXRDY 0x01000000 -#define TMIO_STAT_TXRQ 0x02000000 -#define TMIO_STAT_ILL_FUNC 0x20000000 -#define TMIO_STAT_CMD_BUSY 0x40000000 -#define TMIO_STAT_ILL_ACCESS 0x80000000 - -/* Define some IRQ masks */ -/* This is the mask used at reset by the chip */ -#define TMIO_MASK_ALL 0x837f031d -#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) -#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) -#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) - - -#define enable_mmc_irqs(host, i) \ - do { \ - u32 mask;\ - mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ - mask &= ~((i) & TMIO_MASK_IRQ); \ - sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ - } while (0) - -#define disable_mmc_irqs(host, i) \ - do { \ - u32 mask;\ - mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ - mask |= ((i) & TMIO_MASK_IRQ); \ - sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ - } while (0) - -#define ack_mmc_irqs(host, i) \ - do { \ - sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ - } while (0) - - -struct tmio_mmc_host { - void __iomem *ctl; - unsigned long bus_shift; - struct mmc_command *cmd; - struct mmc_request *mrq; - struct mmc_data *data; - struct mmc_host *mmc; - int irq; - - /* Callbacks for clock / power control */ - void (*set_pwr)(struct platform_device *host, int state); - void (*set_clk_div)(struct platform_device *host, int state); - - /* pio related stuff */ - struct scatterlist *sg_ptr; - unsigned int sg_len; - unsigned int sg_off; - - struct platform_device *pdev; - - /* DMA support */ - struct dma_chan *chan_rx; - struct dma_chan *chan_tx; - struct tasklet_struct dma_complete; - struct tasklet_struct dma_issue; -#ifdef CONFIG_TMIO_MMC_DMA - unsigned int dma_sglen; -#endif -}; - -#include - -static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) -{ - return readw(host->ctl + (addr << host->bus_shift)); -} - -static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, - u16 *buf, int count) -{ - readsw(host->ctl + (addr << host->bus_shift), buf, count); -} - -static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) -{ - return readw(host->ctl + (addr << host->bus_shift)) | - readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; -} - -static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, - u16 val) -{ - writew(val, host->ctl + (addr << host->bus_shift)); -} - -static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, - u16 *buf, int count) -{ - writesw(host->ctl + (addr << host->bus_shift), buf, count); -} - -static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, - u32 val) -{ - writew(val, host->ctl + (addr << host->bus_shift)); - writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); -} - -#include -#include - -static inline void tmio_mmc_init_sg(struct tmio_mmc_host *host, - struct mmc_data *data) -{ - host->sg_len = data->sg_len; - host->sg_ptr = data->sg; - host->sg_off = 0; -} - -static inline int tmio_mmc_next_sg(struct tmio_mmc_host *host) -{ - host->sg_ptr = sg_next(host->sg_ptr); - host->sg_off = 0; - return --host->sg_len; -} - -static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, - unsigned long *flags) -{ - local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; -} - -static inline void tmio_mmc_kunmap_atomic(void *virt, - unsigned long *flags) -{ - kunmap_atomic(virt, KM_BIO_SRC_IRQ); - local_irq_restore(*flags); -} - -#ifdef CONFIG_MMC_DEBUG - -#define STATUS_TO_TEXT(a) \ - do { \ - if (status & TMIO_STAT_##a) \ - printk(#a); \ - } while (0) - -void pr_debug_status(u32 status) -{ - printk(KERN_DEBUG "status: %08x = ", status); - STATUS_TO_TEXT(CARD_REMOVE); - STATUS_TO_TEXT(CARD_INSERT); - STATUS_TO_TEXT(SIGSTATE); - STATUS_TO_TEXT(WRPROTECT); - STATUS_TO_TEXT(CARD_REMOVE_A); - STATUS_TO_TEXT(CARD_INSERT_A); - STATUS_TO_TEXT(SIGSTATE_A); - STATUS_TO_TEXT(CMD_IDX_ERR); - STATUS_TO_TEXT(STOPBIT_ERR); - STATUS_TO_TEXT(ILL_FUNC); - STATUS_TO_TEXT(CMD_BUSY); - STATUS_TO_TEXT(CMDRESPEND); - STATUS_TO_TEXT(DATAEND); - STATUS_TO_TEXT(CRCFAIL); - STATUS_TO_TEXT(DATATIMEOUT); - STATUS_TO_TEXT(CMDTIMEOUT); - STATUS_TO_TEXT(RXOVERFLOW); - STATUS_TO_TEXT(TXUNDERRUN); - STATUS_TO_TEXT(RXRDY); - STATUS_TO_TEXT(TXRQ); - STATUS_TO_TEXT(ILL_ACCESS); - printk("\n"); -} - -#else -#define pr_debug_status(s) do { } while (0) -#endif -- cgit v1.2.3 From 93173054f2979de41b1912b19f0b57edfb35fcdc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 22 Dec 2010 12:02:15 +0100 Subject: mmc: tmio_mmc: implement a bounce buffer for unaligned DMA For example, with SDIO WLAN cards, some transfers happen with buffers at odd addresses, whereas the SH-Mobile DMA engine requires even addresses for SDHI. This patch extends the tmio driver with a bounce buffer, that is used for single entry scatter-gather lists both for sending and receiving. If we ever encounter unaligned transfers with multi-element sg lists, this patch will have to be extended. For now it just falls back to PIO in this and other unsupported cases. Signed-off-by: Guennadi Liakhovetski Acked-by: Samuel Ortiz Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 89 ++++++++++++++++++++++++++++++++++++++++++--- include/linux/mfd/tmio.h | 1 + 2 files changed, 84 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e04c032abb1c..595b7b3f160d 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -111,6 +111,8 @@ sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ } while (0) +/* This is arbitrary, just noone needed any higher alignment yet */ +#define MAX_ALIGN 4 struct tmio_mmc_host { void __iomem *ctl; @@ -127,6 +129,7 @@ struct tmio_mmc_host { /* pio related stuff */ struct scatterlist *sg_ptr; + struct scatterlist *sg_orig; unsigned int sg_len; unsigned int sg_off; @@ -139,9 +142,13 @@ struct tmio_mmc_host { struct tasklet_struct dma_issue; #ifdef CONFIG_TMIO_MMC_DMA unsigned int dma_sglen; + u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN))); + struct scatterlist bounce_sg; #endif }; +static void tmio_check_bounce_buffer(struct tmio_mmc_host *host); + static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->bus_shift)); @@ -180,6 +187,7 @@ static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) { host->sg_len = data->sg_len; host->sg_ptr = data->sg; + host->sg_orig = data->sg; host->sg_off = 0; } @@ -438,6 +446,8 @@ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) if (data->flags & MMC_DATA_READ) { if (!host->chan_rx) disable_mmc_irqs(host, TMIO_MASK_READOP); + else + tmio_check_bounce_buffer(host); dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", host->mrq); } else { @@ -529,8 +539,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, if (!host->chan_rx) enable_mmc_irqs(host, TMIO_MASK_READOP); } else { - struct dma_chan *chan = host->chan_tx; - if (!chan) + if (!host->chan_tx) enable_mmc_irqs(host, TMIO_MASK_WRITEOP); else tasklet_schedule(&host->dma_issue); @@ -612,6 +621,16 @@ out: } #ifdef CONFIG_TMIO_MMC_DMA +static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) +{ + if (host->sg_ptr == &host->bounce_sg) { + unsigned long flags; + void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); + memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); + tmio_mmc_kunmap_atomic(sg_vaddr, &flags); + } +} + static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) { #if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE) @@ -634,11 +653,35 @@ static void tmio_dma_complete(void *arg) static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) { - struct scatterlist *sg = host->sg_ptr; + struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; dma_cookie_t cookie; - int ret; + int ret, i; + bool aligned = true, multiple = true; + unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + + for_each_sg(sg, sg_tmp, host->sg_len, i) { + if (sg_tmp->offset & align) + aligned = false; + if (sg_tmp->length & align) { + multiple = false; + break; + } + } + + if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || + align >= MAX_ALIGN)) || !multiple) + goto pio; + + /* The only sg element can be unaligned, use our bounce buffer then */ + if (!aligned) { + sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); + host->sg_ptr = &host->bounce_sg; + sg = host->sg_ptr; + } ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_FROM_DEVICE); if (ret > 0) { @@ -661,6 +704,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", __func__, host->sg_len, ret, cookie, host->mrq); +pio: if (!desc) { /* DMA failed, fall back to PIO */ if (ret >= 0) @@ -684,11 +728,39 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) { - struct scatterlist *sg = host->sg_ptr; + struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; dma_cookie_t cookie; - int ret; + int ret, i; + bool aligned = true, multiple = true; + unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + + for_each_sg(sg, sg_tmp, host->sg_len, i) { + if (sg_tmp->offset & align) + aligned = false; + if (sg_tmp->length & align) { + multiple = false; + break; + } + } + + if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || + align >= MAX_ALIGN)) || !multiple) + goto pio; + + /* The only sg element can be unaligned, use our bounce buffer then */ + if (!aligned) { + unsigned long flags; + void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); + sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); + memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); + tmio_mmc_kunmap_atomic(sg_vaddr, &flags); + host->sg_ptr = &host->bounce_sg; + sg = host->sg_ptr; + } ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_TO_DEVICE); if (ret > 0) { @@ -709,6 +781,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", __func__, host->sg_len, ret, cookie, host->mrq); +pio: if (!desc) { /* DMA failed, fall back to PIO */ if (ret >= 0) @@ -822,6 +895,10 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host) } } #else +static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) +{ +} + static void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data) { diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 085f041197dc..dbfc053b1f95 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -66,6 +66,7 @@ void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state); struct tmio_mmc_dma { void *chan_priv_tx; void *chan_priv_rx; + int alignment_shift; }; /* -- cgit v1.2.3 From eba46030e1727f2af377300b6a55df846fa830f1 Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Sun, 19 Dec 2010 21:16:07 +0000 Subject: mmc: tmio_mmc: silence compiler warnings with "mmc: tmio: implement a bounce buffer for unaligned DMA" gcc generates the following warnings: drivers/mmc/host/tmio_mmc.c:654:6: warning: 'ret' may be used uninitialized in this function drivers/mmc/host/tmio_mmc.c:730:6: warning: 'ret' may be used uninitialized in this function This patch fixes these by setting ret to -EINVAL in the affected code paths. Signed-off-by: Arnd Hannemann Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 595b7b3f160d..f442c8205b0a 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -673,8 +673,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) } if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || - align >= MAX_ALIGN)) || !multiple) + align >= MAX_ALIGN)) || !multiple) { + ret = -EINVAL; goto pio; + } /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { @@ -748,8 +750,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) } if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || - align >= MAX_ALIGN)) || !multiple) + align >= MAX_ALIGN)) || !multiple) { + ret = -EINVAL; goto pio; + } /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { -- cgit v1.2.3 From 39a65a0dbbf73403daa9f4cc0ab30957ba61e60f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 23 Nov 2010 17:24:19 +0100 Subject: mfd: sdhi: require the tmio-mmc driver to bounce unaligned buffers The SDHI controller on SH-Mobile SoCs requires even buffer addresses, when used with DMA. Signed-off-by: Guennadi Liakhovetski Acked-by: Samuel Ortiz Signed-off-by: Chris Ball --- drivers/mfd/sh_mobile_sdhi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index f1714f93af9d..3ca20ecaac7e 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c @@ -136,6 +136,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) priv->param_rx.slave_id = p->dma_slave_rx; priv->dma_priv.chan_priv_tx = &priv->param_tx; priv->dma_priv.chan_priv_rx = &priv->param_rx; + priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ mmc_data->dma = &priv->dma_priv; } -- cgit v1.2.3 From 845ecd20239c28e97e766ff54078a58be19f3a91 Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Tue, 28 Dec 2010 23:22:31 +0100 Subject: mmc: tmio_mmc: implement SDIO IRQ support This patch implements SDIO IRQ support for mfds which announce the TMIO_MMC_SDIO_IRQ flag for tmio_mmc. If MMC_CAP_SDIO_IRQ is also set SDIO IRQ signalling is activated. Tested with a b43-based wireless SDIO card and sh_mobile_sdhi. Signed-off-by: Arnd Hannemann Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/tmio.h | 4 +++ 2 files changed, 83 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index f442c8205b0a..81bed310ddcd 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -53,6 +53,8 @@ #define CTL_SD_ERROR_DETAIL_STATUS 0x2c #define CTL_SD_DATA_PORT 0x30 #define CTL_TRANSACTION_CTL 0x34 +#define CTL_SDIO_STATUS 0x36 +#define CTL_SDIO_IRQ_MASK 0x38 #define CTL_RESET_SD 0xe0 #define CTL_SDIO_REGS 0x100 #define CTL_CLK_AND_WAIT_CTL 0x138 @@ -81,6 +83,12 @@ #define TMIO_STAT_CMD_BUSY 0x40000000 #define TMIO_STAT_ILL_ACCESS 0x80000000 +/* Definitions for values the CTRL_SDIO_STATUS register can take. */ +#define TMIO_SDIO_STAT_IOIRQ 0x0001 +#define TMIO_SDIO_STAT_EXPUB52 0x4000 +#define TMIO_SDIO_STAT_EXWT 0x8000 +#define TMIO_SDIO_MASK_ALL 0xc007 + /* Define some IRQ masks */ /* This is the mask used at reset by the chip */ #define TMIO_MASK_ALL 0x837f031d @@ -122,6 +130,7 @@ struct tmio_mmc_host { struct mmc_data *data; struct mmc_host *mmc; int irq; + unsigned int sdio_irq_enabled; /* Callbacks for clock / power control */ void (*set_pwr)(struct platform_device *host, int state); @@ -249,6 +258,22 @@ void pr_debug_status(u32 status) #define pr_debug_status(s) do { } while (0) #endif +static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + + if (enable) { + host->sdio_irq_enabled = 1; + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, + (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); + } else { + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); + host->sdio_irq_enabled = 0; + } +} + static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) { u32 clk = 0, clock; @@ -268,8 +293,23 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; + + /* + * Testing on sh-mobile showed that SDIO IRQs are unmasked when + * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the + * device IRQ here and restore the SDIO IRQ mask before + * re-enabling the device IRQ. + */ + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + disable_irq(host->irq); sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); msleep(10); + if (pdata->flags & TMIO_MMC_SDIO_IRQ) { + tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); + enable_irq(host->irq); + } sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(10); @@ -277,11 +317,21 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(10); + /* see comment in tmio_mmc_clk_stop above */ + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + disable_irq(host->irq); sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); msleep(10); + if (pdata->flags & TMIO_MMC_SDIO_IRQ) { + tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); + enable_irq(host->irq); + } } static void reset(struct tmio_mmc_host *host) @@ -554,7 +604,10 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, static irqreturn_t tmio_mmc_irq(int irq, void *devid) { struct tmio_mmc_host *host = devid; + struct mfd_cell *cell = host->pdev->dev.platform_data; + struct tmio_mmc_data *pdata = cell->driver_data; unsigned int ireg, irq_mask, status; + unsigned int sdio_ireg, sdio_irq_mask, sdio_status; pr_debug("MMC IRQ begin\n"); @@ -562,6 +615,29 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); ireg = status & TMIO_MASK_IRQ & ~irq_mask; + sdio_ireg = 0; + if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { + sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); + sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); + sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; + + sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); + + if (sdio_ireg && !host->sdio_irq_enabled) { + pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", + sdio_status, sdio_irq_mask, sdio_ireg); + tmio_mmc_enable_sdio_irq(host->mmc, 0); + goto out; + } + + if (host->mmc->caps & MMC_CAP_SDIO_IRQ && + sdio_ireg & TMIO_SDIO_STAT_IOIRQ) + mmc_signal_sdio_irq(host->mmc); + + if (sdio_ireg) + goto out; + } + pr_debug_status(status); pr_debug_status(ireg); @@ -1047,6 +1123,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { .set_ios = tmio_mmc_set_ios, .get_ro = tmio_mmc_get_ro, .get_cd = tmio_mmc_get_cd, + .enable_sdio_irq = tmio_mmc_enable_sdio_irq, }; #ifdef CONFIG_PM @@ -1162,6 +1239,8 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) goto cell_disable; disable_mmc_irqs(host, TMIO_MASK_ALL); + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + tmio_mmc_enable_sdio_irq(mmc, 0); ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index dbfc053b1f95..8e70310ee945 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -57,6 +57,10 @@ * is configured in 4-bit mode. */ #define TMIO_MMC_BLKSZ_2BYTES (1 << 1) +/* + * Some controllers can support SDIO IRQ signalling. + */ +#define TMIO_MMC_SDIO_IRQ (1 << 2) int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); -- cgit v1.2.3 From 23b66071e8ce7f359a0e410a8a3514bd3179e92e Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Tue, 28 Dec 2010 23:22:32 +0100 Subject: mfd: sh_mobile_sdhi: activate SDIO IRQ for tmio_mmc The SDHI Controller on SH-Mobile SoCs supports SDIO IRQ signalling. This patch advertises this fact to the tmio_mmc driver. Signed-off-by: Arnd Hannemann Acked-by: Samuel Ortiz Signed-off-by: Chris Ball --- drivers/mfd/sh_mobile_sdhi.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index 3ca20ecaac7e..0a7df44a93c0 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c @@ -131,6 +131,11 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; + /* + * All SDHI blocks support SDIO IRQ signalling. + */ + mmc_data->flags |= TMIO_MMC_SDIO_IRQ; + if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { priv->param_tx.slave_id = p->dma_slave_tx; priv->param_rx.slave_id = p->dma_slave_rx; -- cgit v1.2.3 From 6ff56e0d8e02df023440ea65774cf1d15e669ece Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Wed, 5 Jan 2011 17:36:14 -0500 Subject: mmc: tmio_mmc: handle missing HW interrupts When doing excessive hotplug, e.g., repeated insert/eject operations, the hardware may get confused to a point where no CMDTIMEOUT/CMDRESPEND interrupts are generated any more. As a result requests get stuck, e.g.: [ 360.351562] INFO: task kworker/u:0:5 blocked for more than 120 seconds. [ 360.351562] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 360.359375] kworker/u:0 D c020c2b4 0 5 2 0x00000000 [ 360.367187] Backtrace: [ 360.367187] [] (schedule+0x0/0x340) from [] (schedule_timeout+0x20/0x190) [ 360.375000] r8:c702fd70 r7:00000002 r6:c702e000 r5:c702fdc4 r4:7fffffff [ 360.375000] r3:c701e040 [ 360.382812] [] (schedule_timeout+0x0/0x190) from [] (wait_for_common+0xc4/0x150) [ 360.390625] r6:c702e000 r5:c702fdc4 r4:7fffffff [ 360.390625] [] (wait_for_common+0x0/0x150) from [] (wait_for_completion+0x18/0x1c) [ 360.398437] [] (wait_for_completion+0x0/0x1c) from [] (mmc_wait_for_req+0x214/0x234) [ 360.406250] [] (mmc_wait_for_req+0x0/0x234) from [] (mmc_sd_switch+0xfc/0x114) [ 360.414062] r7:c702fe4c r6:c702fe20 r5:c7179800 r4:00fffff0 [ 360.421875] [] (mmc_sd_switch+0x0/0x114) from [] (mmc_sd_setup_card+0x260/0x384) [ 360.429687] [] (mmc_sd_setup_card+0x0/0x384) from [] (mmc_sd_init_card+0x13c/0x1e0) [ 360.437500] [] (mmc_sd_init_card+0x0/0x1e0) from [] (mmc_attach_sd+0x124/0x1a8) [ 360.445312] r8:c02db404 r7:ffffff92 r6:c702ff34 r5:c6007da8 r4:c6007c00 [ 360.453125] [] (mmc_attach_sd+0x0/0x1a8) from [] (mmc_rescan+0x248/0x2f0) [ 360.460937] r5:c6007da8 r4:c6007c00 [ 360.468750] [] (mmc_rescan+0x0/0x2f0) from [] (process_one_work+0x1ec/0x318) [ 360.476562] r7:c6007da8 r6:00000000 r5:c710ec00 r4:c701bde0 [ 360.484375] [] (process_one_work+0x0/0x318) from [] (worker_thread+0x1b0/0x2cc) [ 360.492187] [] (worker_thread+0x0/0x2cc) from [] (kthread+0x8c/0x94) [ 360.500000] [] (kthread+0x0/0x94) from [] (do_exit+0x0/0x590) [ 360.507812] r7:00000013 r6:c0037fc4 r5:c004b2ac r4:c7021f00 This patch addresses this problem by introducing timeouts for outstanding interrupts. If a hardware interrupt is missing, a soft reset will be performed to bring the hardware back to a working state. Tested with the SDHI hardware block in sh7372 / AP4EVB. Signed-off-by: Arnd Hannemann Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 90 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 81bed310ddcd..689a3692242e 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #define CTL_SD_CMD 0x00 #define CTL_ARG_REG 0x04 @@ -154,6 +156,11 @@ struct tmio_mmc_host { u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN))); struct scatterlist bounce_sg; #endif + + /* Track lost interrupts */ + struct delayed_work delayed_reset_work; + spinlock_t lock; + unsigned long last_req_ts; }; static void tmio_check_bounce_buffer(struct tmio_mmc_host *host); @@ -345,15 +352,60 @@ static void reset(struct tmio_mmc_host *host) msleep(10); } +static void tmio_mmc_reset_work(struct work_struct *work) +{ + struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, + delayed_reset_work.work); + struct mmc_request *mrq; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + mrq = host->mrq; + + /* request already finished */ + if (!mrq + || time_is_after_jiffies(host->last_req_ts + + msecs_to_jiffies(2000))) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + dev_warn(&host->pdev->dev, + "timeout waiting for hardware interrupt (CMD%u)\n", + mrq->cmd->opcode); + + if (host->data) + host->data->error = -ETIMEDOUT; + else if (host->cmd) + host->cmd->error = -ETIMEDOUT; + else + mrq->cmd->error = -ETIMEDOUT; + + host->cmd = NULL; + host->data = NULL; + host->mrq = NULL; + + spin_unlock_irqrestore(&host->lock, flags); + + reset(host); + + mmc_request_done(host->mmc, mrq); +} + static void tmio_mmc_finish_request(struct tmio_mmc_host *host) { struct mmc_request *mrq = host->mrq; + if (!mrq) + return; + host->mrq = NULL; host->cmd = NULL; host->data = NULL; + cancel_delayed_work(&host->delayed_reset_work); + mmc_request_done(host->mmc, mrq); } @@ -463,6 +515,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) return; } +/* needs to be called with host->lock held */ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) { struct mmc_data *data = host->data; @@ -519,10 +572,12 @@ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) static void tmio_mmc_data_irq(struct tmio_mmc_host *host) { - struct mmc_data *data = host->data; + struct mmc_data *data; + spin_lock(&host->lock); + data = host->data; if (!data) - return; + goto out; if (host->chan_tx && (data->flags & MMC_DATA_WRITE)) { /* @@ -543,6 +598,8 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host) } else { tmio_mmc_do_data_irq(host); } +out: + spin_unlock(&host->lock); } static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, @@ -551,9 +608,11 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, struct mmc_command *cmd = host->cmd; int i, addr; + spin_lock(&host->lock); + if (!host->cmd) { pr_debug("Spurious CMD irq\n"); - return; + goto out; } host->cmd = NULL; @@ -598,6 +657,9 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, tmio_mmc_finish_request(host); } +out: + spin_unlock(&host->lock); + return; } @@ -906,6 +968,12 @@ static void tmio_issue_tasklet_fn(unsigned long priv) static void tmio_tasklet_fn(unsigned long arg) { struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (!host->data) + goto out; if (host->data->flags & MMC_DATA_READ) dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen, @@ -915,6 +983,8 @@ static void tmio_tasklet_fn(unsigned long arg) DMA_TO_DEVICE); tmio_mmc_do_data_irq(host); +out: + spin_unlock_irqrestore(&host->lock, flags); } /* It might be necessary to make filter MFD specific */ @@ -1037,6 +1107,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) if (host->mrq) pr_debug("request not null\n"); + host->last_req_ts = jiffies; + wmb(); host->mrq = mrq; if (mrq->data) { @@ -1046,10 +1118,14 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } ret = tmio_mmc_start_command(host, mrq->cmd); - if (!ret) + if (!ret) { + schedule_delayed_work(&host->delayed_reset_work, + msecs_to_jiffies(2000)); return; + } fail: + host->mrq = NULL; mrq->cmd->error = ret; mmc_request_done(mmc, mrq); } @@ -1247,6 +1323,11 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) if (ret) goto cell_disable; + spin_lock_init(&host->lock); + + /* Init delayed work for request timeouts */ + INIT_DELAYED_WORK(&host->delayed_reset_work, tmio_mmc_reset_work); + /* See if we also get DMA */ tmio_mmc_request_dma(host, pdata); @@ -1285,6 +1366,7 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev) if (mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); mmc_remove_host(mmc); + cancel_delayed_work_sync(&host->delayed_reset_work); tmio_mmc_release_dma(host); free_irq(host->irq, host); if (cell->disable) -- cgit v1.2.3 From 2bd6a935555b06622fa7f47a9c411b8a7812e4dc Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Wed, 29 Dec 2010 14:21:14 +0100 Subject: mmc: tmio_mmc: fix CMD irq handling With current code card insert/eject interrupts will acknowledge outstanding commands. Normally this seems to be no problem, however if the hardware gets stuck and no interrupts for CMD_TIMEOUT or CMD_RESPEND are generated, then inserting and ejecting cards will falsely acknowledge outstanding commands from the core. This patch changes the behavior so that CMDs are only acked, if CMD_TIMEOUT or CMD_RESPEND is received. Signed-off-by: Arnd Hannemann Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 689a3692242e..e3c6ef208391 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -727,8 +727,10 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) */ /* Command completion */ - if (ireg & TMIO_MASK_CMD) { - ack_mmc_irqs(host, TMIO_MASK_CMD); + if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { + ack_mmc_irqs(host, + TMIO_STAT_CMDRESPEND | + TMIO_STAT_CMDTIMEOUT); tmio_mmc_cmd_irq(host, status); } -- cgit v1.2.3 From e9b86841b372de01ae865080118e29159d8b7c39 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 5 Jan 2011 00:44:32 +0100 Subject: mmc: fix division by zero in MMC core The card is not always clocked and the clock frequency zero is perfectly legal, thus this code in mmc_set_data_timeout() may cause a division by zero. It will be triggered more often if you're using software clock gating but can be triggered under other conditions too. Reported-by: Pierre Tardy Signed-off-by: Linus Walleij Reviewed-by: Chris Ball Cc: Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 4b1d8fb04e9b..6625c057be05 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -299,8 +299,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) unsigned int timeout_us, limit_us; timeout_us = data->timeout_ns / 1000; - timeout_us += data->timeout_clks * 1000 / - (mmc_host_clk_rate(card->host) / 1000); + if (mmc_host_clk_rate(card->host)) + timeout_us += data->timeout_clks * 1000 / + (mmc_host_clk_rate(card->host) / 1000); if (data->flags & MMC_DATA_WRITE) /* -- cgit v1.2.3 From 6099469805c24af14250e182bb9ca082b8a6b716 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sun, 9 Jan 2011 09:31:39 -0500 Subject: hwmon: Support for Dallas Semiconductor DS620 Driver for Dallas Semiconductor DS620 temperature sensor and thermostat Signed-off-by: Roland Stigge Signed-off-by: Guenter Roeck --- Documentation/hwmon/ds620 | 34 +++++ drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/ds620.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/i2c/ds620.h | 21 +++ 5 files changed, 403 insertions(+) create mode 100644 Documentation/hwmon/ds620 create mode 100644 drivers/hwmon/ds620.c create mode 100644 include/linux/i2c/ds620.h (limited to 'drivers') diff --git a/Documentation/hwmon/ds620 b/Documentation/hwmon/ds620 new file mode 100644 index 000000000000..1fbe3cd916cc --- /dev/null +++ b/Documentation/hwmon/ds620 @@ -0,0 +1,34 @@ +Kernel driver ds620 +=================== + +Supported chips: + * Dallas Semiconductor DS620 + Prefix: 'ds620' + Datasheet: Publicly available at the Dallas Semiconductor website + http://www.dalsemi.com/ + +Authors: + Roland Stigge + based on ds1621.c by + Christian W. Zuckschwerdt + +Description +----------- + +The DS620 is a (one instance) digital thermometer and thermostat. It has both +high and low temperature limits which can be user defined (i.e. programmed +into non-volatile on-chip registers). Temperature range is -55 degree Celsius +to +125. Between 0 and 70 degree Celsius, accuracy is 0.5 Kelvin. The value +returned via sysfs displays post decimal positions. + +The thermostat function works as follows: When configured via platform_data +(struct ds620_platform_data) .pomode == 0 (default), the thermostat output pin +PO is always low. If .pomode == 1, the thermostat is in PO_LOW mode. I.e., the +output pin PO becomes active when the temperature falls below temp1_min and +stays active until the temperature goes above temp1_max. + +Likewise, with .pomode == 2, the thermostat is in PO_HIGH mode. I.e., the PO +output pin becomes active when the temperature goes above temp1_max and stays +active until the temperature falls below temp1_min. + +The PO output pin of the DS620 operates active-low. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0f09567257fd..bdc13d28b1ea 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -274,6 +274,16 @@ config SENSORS_ATXP1 This driver can also be built as a module. If so, the module will be called atxp1. +config SENSORS_DS620 + tristate "Dallas Semiconductor DS620" + depends on I2C + help + If you say yes here you get support for Dallas Semiconductor + DS620 sensor chip. + + This driver can also be built as a module. If so, the module + will be called ds620. + config SENSORS_DS1621 tristate "Dallas Semiconductor DS1621 and DS1625" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 20e74086e681..dde02d99c238 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_PKGTEMP) += pkgtemp.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o +obj-$(CONFIG_SENSORS_DS620) += ds620.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c new file mode 100644 index 000000000000..257957c69d92 --- /dev/null +++ b/drivers/hwmon/ds620.c @@ -0,0 +1,337 @@ +/* + * ds620.c - Support for temperature sensor and thermostat DS620 + * + * Copyright (C) 2010, 2011 Roland Stigge + * + * based on ds1621.c by Christian W. Zuckschwerdt + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Many DS620 constants specified below + * 15 14 13 12 11 10 09 08 + * |Done|NVB |THF |TLF |R1 |R0 |AUTOC|1SHOT| + * + * 07 06 05 04 03 02 01 00 + * |PO2 |PO1 |A2 |A1 |A0 | | | | + */ +#define DS620_REG_CONFIG_DONE 0x8000 +#define DS620_REG_CONFIG_NVB 0x4000 +#define DS620_REG_CONFIG_THF 0x2000 +#define DS620_REG_CONFIG_TLF 0x1000 +#define DS620_REG_CONFIG_R1 0x0800 +#define DS620_REG_CONFIG_R0 0x0400 +#define DS620_REG_CONFIG_AUTOC 0x0200 +#define DS620_REG_CONFIG_1SHOT 0x0100 +#define DS620_REG_CONFIG_PO2 0x0080 +#define DS620_REG_CONFIG_PO1 0x0040 +#define DS620_REG_CONFIG_A2 0x0020 +#define DS620_REG_CONFIG_A1 0x0010 +#define DS620_REG_CONFIG_A0 0x0008 + +/* The DS620 registers */ +static const u8 DS620_REG_TEMP[3] = { + 0xAA, /* input, word, RO */ + 0xA2, /* min, word, RW */ + 0xA0, /* max, word, RW */ +}; + +#define DS620_REG_CONF 0xAC /* word, RW */ +#define DS620_COM_START 0x51 /* no data */ +#define DS620_COM_STOP 0x22 /* no data */ + +/* Each client has this additional data */ +struct ds620_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u16 temp[3]; /* Register values, word */ +}; + +/* + * Temperature registers are word-sized. + * DS620 uses a high-byte first convention, which is exactly opposite to + * the SMBus standard. + */ +static int ds620_read_temp(struct i2c_client *client, u8 reg) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + return swab16(ret); +} + +static int ds620_write_temp(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void ds620_init_client(struct i2c_client *client) +{ + struct ds620_platform_data *ds620_info = client->dev.platform_data; + u16 conf, new_conf; + + new_conf = conf = + swab16(i2c_smbus_read_word_data(client, DS620_REG_CONF)); + + /* switch to continuous conversion mode */ + new_conf &= ~DS620_REG_CONFIG_1SHOT; + /* already high at power-on, but don't trust the BIOS! */ + new_conf |= DS620_REG_CONFIG_PO2; + /* thermostat mode according to platform data */ + if (ds620_info && ds620_info->pomode == 1) + new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */ + else if (ds620_info && ds620_info->pomode == 2) + new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */ + else + new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */ + /* with highest precision */ + new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0; + + if (conf != new_conf) + i2c_smbus_write_word_data(client, DS620_REG_CONF, + swab16(new_conf)); + + /* start conversion */ + i2c_smbus_write_byte(client, DS620_COM_START); +} + +static struct ds620_data *ds620_update_client(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds620_data *data = i2c_get_clientdata(client); + struct ds620_data *ret = data; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i; + int res; + + dev_dbg(&client->dev, "Starting ds620 update\n"); + + for (i = 0; i < ARRAY_SIZE(data->temp); i++) { + res = ds620_read_temp(client, + DS620_REG_TEMP[i]); + if (res < 0) { + ret = ERR_PTR(res); + goto abort; + } + + data->temp[i] = res; + } + + data->last_updated = jiffies; + data->valid = 1; + } +abort: + mutex_unlock(&data->update_lock); + + return ret; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ds620_data *data = ds620_update_client(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10); +} + +static ssize_t set_temp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int res; + long val; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct ds620_data *data = i2c_get_clientdata(client); + + res = strict_strtol(buf, 10, &val); + + if (res) + return res; + + val = (val * 10 / 625) * 8; + + mutex_lock(&data->update_lock); + data->temp[attr->index] = val; + ds620_write_temp(client, DS620_REG_TEMP[attr->index], + data->temp[attr->index]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ds620_data *data = ds620_update_client(dev); + struct i2c_client *client = to_i2c_client(dev); + u16 conf, new_conf; + int res; + + if (IS_ERR(data)) + return PTR_ERR(data); + + /* reset alarms if necessary */ + res = i2c_smbus_read_word_data(client, DS620_REG_CONF); + if (res < 0) + return res; + + conf = swab16(res); + new_conf = conf; + new_conf &= ~attr->index; + if (conf != new_conf) { + res = i2c_smbus_write_word_data(client, DS620_REG_CONF, + swab16(new_conf)); + if (res < 0) + return res; + } + + return sprintf(buf, "%d\n", !!(conf & attr->index)); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, + DS620_REG_CONFIG_TLF); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, + DS620_REG_CONFIG_THF); + +static struct attribute *ds620_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group ds620_group = { + .attrs = ds620_attributes, +}; + +static int ds620_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ds620_data *data; + int err; + + data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* Initialize the DS620 chip */ + ds620_init_client(client); + + /* Register sysfs hooks */ + err = sysfs_create_group(&client->dev.kobj, &ds620_group); + if (err) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove_files; + } + + dev_info(&client->dev, "temperature sensor found\n"); + + return 0; + +exit_remove_files: + sysfs_remove_group(&client->dev.kobj, &ds620_group); +exit_free: + kfree(data); +exit: + return err; +} + +static int ds620_remove(struct i2c_client *client) +{ + struct ds620_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &ds620_group); + + kfree(data); + + return 0; +} + +static const struct i2c_device_id ds620_id[] = { + {"ds620", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ds620_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver ds620_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ds620", + }, + .probe = ds620_probe, + .remove = ds620_remove, + .id_table = ds620_id, +}; + +static int __init ds620_init(void) +{ + return i2c_add_driver(&ds620_driver); +} + +static void __exit ds620_exit(void) +{ + i2c_del_driver(&ds620_driver); +} + +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("DS620 driver"); +MODULE_LICENSE("GPL"); + +module_init(ds620_init); +module_exit(ds620_exit); diff --git a/include/linux/i2c/ds620.h b/include/linux/i2c/ds620.h new file mode 100644 index 000000000000..736bb87ac0fc --- /dev/null +++ b/include/linux/i2c/ds620.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_DS620_H +#define _LINUX_DS620_H + +#include +#include + +/* platform data for the DS620 temperature sensor and thermostat */ + +struct ds620_platform_data { + /* + * Thermostat output pin PO mode: + * 0 = always low (default) + * 1 = PO_LOW + * 2 = PO_HIGH + * + * (see Documentation/hwmon/ds620) + */ + int pomode; +}; + +#endif /* _LINUX_DS620_H */ -- cgit v1.2.3 From 0ba41e449fd0f45f5b29c1009020ab1b298bedda Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 8 Jan 2011 15:10:41 +0000 Subject: drm: Restore the old_fb upon modeset failure ... or else we may end up disabling the wrong framebuffer, leading to an OOPS, e.g: [ 6033.229012] kernel BUG at drivers/gpu/drm/i915/i915_gem.c:3271! [ 6033.229012] invalid opcode: 0000 [#1] SMP [ 6033.229012] last sysfs file: /sys/devices/virtual/backlight/acpi_video0/uevent [ 6033.229012] Modules linked in: sunrpc cpufreq_ondemand acpi_cpufreq mperf snd_hda_codec_analog snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer thinkpad_acpi ppdev snd r852 sm_common iTCO_wdt uvcvideo i2c_i801 iTCO_vendor_support microcode wmi nand videodev nand_ids nand_ecc snd_page_alloc parport_pc parport mtd soundcore joydev v4l1_compat pcspkr uinput ipv6 sdhci_pci sdhci mmc_core yenta_socket i915 drm_kms_helper drm i2c_algo_bit i2c_core video output [last unloaded: scsi_wait_scan] [ 6033.229012] [ 6033.229012] Pid: 4834, comm: Xorg Not tainted 2.6.37-rc8+ #25 7661BL5/7661BL5 [ 6033.229012] EIP: 0060:[] EFLAGS: 00013246 CPU: 0 [ 6033.229012] EIP is at i915_gem_object_unpin+0x23/0x76 [i915] [ 6033.229012] EAX: f68a4000 EBX: f6831f00 ECX: 000600fa EDX: f68a8000 [ 6033.229012] ESI: f68a4014 EDI: f68a42b8 EBP: f2169c44 ESP: f2169c3c [ 6033.229012] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 6033.229012] Process Xorg (pid: 4834, ti=f2168000 task=f21c8000 task.ti=f2168000) [ 6033.229012] Stack: [ 6033.229012] f3a84800 f68a4014 f2169c54 f87045d8 f3a84800 f872d9a8 f2169c68 f7fd8091 [ 6033.229012] f3b952a4 00000000 f68a414c f2169cf0 f7fd9377 00000000 00000000 f7fd98b0 [ 6033.229012] f7fd9f4e 0000000f f7f328a0 00000000 00000000 00000000 f2169ca4 f68a414c [ 6033.229012] Call Trace: [ 6033.229012] [] ? intel_crtc_disable+0x36/0x41 [i915] [ 6033.229012] [] ? drm_helper_disable_unused_functions+0xcd/0xf9 [drm_kms_helper] [ 6033.229012] [] ? drm_crtc_helper_set_config+0x62a/0x7f7 [drm_kms_helper] [ 6033.229012] [] ? __slab_free+0x1b/0xa4 [ 6033.229012] [] ? drm_fb_helper_initial_config+0x466/0x497 [drm_kms_helper] [ 6033.229012] [] ? drm_fb_helper_restore+0x10/0x2a [drm_kms_helper] [ 6033.229012] [] ? i915_driver_lastclose+0x2a/0x57 [i915] [ 6033.229012] [] ? drm_lastclose+0x45/0x23e [drm] [ 6033.229012] [] ? drm_release+0x462/0x4d7 [drm] Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 8de333aeeca3..952b3d4fb2a6 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -661,6 +661,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) old_fb)) { DRM_ERROR("failed to set mode on [CRTC:%d]\n", set->crtc->base.id); + set->crtc->fb = old_fb; ret = -EINVAL; goto fail; } @@ -675,8 +676,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->crtc->fb = set->fb; ret = crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb); - if (ret != 0) + if (ret != 0) { + set->crtc->fb = old_fb; goto fail; + } } DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); for (i = 0; i < set->num_connectors; i++) { -- cgit v1.2.3 From f9db92cb8084c756890ddf953e9329588c59e8e8 Mon Sep 17 00:00:00 2001 From: Alagu Sankar Date: Mon, 3 Jan 2011 12:43:27 +0530 Subject: mmc: davinci: add support for SDIO irq handling This patch adds support for handling SDIO interrupt on DaVinci MMC/SD controller. The patch has been tested on DM355 and DA850 EVMs with Marvell Libertas based SDIO wireless LAN card. Signed-off-by: Alagu Sankar Signed-off-by: Sekhar Nori Signed-off-by: Chris Ball --- drivers/mmc/host/davinci_mmc.c | 78 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index b643ddef4f70..0076c7448fe6 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -66,8 +66,8 @@ #define DAVINCI_MMCBLNC 0x60 #define DAVINCI_SDIOCTL 0x64 #define DAVINCI_SDIOST0 0x68 -#define DAVINCI_SDIOEN 0x6C -#define DAVINCI_SDIOST 0x70 +#define DAVINCI_SDIOIEN 0x6C +#define DAVINCI_SDIOIST 0x70 #define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */ /* DAVINCI_MMCCTL definitions */ @@ -131,6 +131,14 @@ #define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ #define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ +/* DAVINCI_SDIOST0 definitions */ +#define SDIOST0_DAT1_HI BIT(0) + +/* DAVINCI_SDIOIEN definitions */ +#define SDIOIEN_IOINTEN BIT(0) + +/* DAVINCI_SDIOIST definitions */ +#define SDIOIST_IOINT BIT(0) /* MMCSD Init clock in Hz in opendrain mode */ #define MMCSD_INIT_CLOCK 200000 @@ -164,7 +172,7 @@ struct mmc_davinci_host { unsigned int mmc_input_clk; void __iomem *base; struct resource *mem_res; - int irq; + int mmc_irq, sdio_irq; unsigned char bus_mode; #define DAVINCI_MMC_DATADIR_NONE 0 @@ -184,6 +192,7 @@ struct mmc_davinci_host { u32 rxdma, txdma; bool use_dma; bool do_dma; + bool sdio_int; /* Scatterlist DMA uses one or more parameter RAM entries: * the main one (associated with rxdma or txdma) plus zero or @@ -866,6 +875,19 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data) { host->data = NULL; + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { + /* + * SDIO Interrupt Detection work-around as suggested by + * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata + * 2.1.6): Signal SDIO interrupt only if it is enabled by core + */ + if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) & + SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + } + if (host->do_dma) { davinci_abort_dma(host); @@ -932,6 +954,21 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data) mmc_davinci_reset_ctrl(host, 0); } +static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) +{ + struct mmc_davinci_host *host = dev_id; + unsigned int status; + + status = readl(host->base + DAVINCI_SDIOIST); + if (status & SDIOIST_IOINT) { + dev_dbg(mmc_dev(host->mmc), + "SDIO interrupt status %x\n", status); + writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } + return IRQ_HANDLED; +} + static irqreturn_t mmc_davinci_irq(int irq, void *dev_id) { struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id; @@ -1076,11 +1113,32 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc) return config->get_ro(pdev->id); } +static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mmc_davinci_host *host = mmc_priv(mmc); + + if (enable) { + if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) { + writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST); + mmc_signal_sdio_irq(host->mmc); + } else { + host->sdio_int = true; + writel(readl(host->base + DAVINCI_SDIOIEN) | + SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN); + } + } else { + host->sdio_int = false; + writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN, + host->base + DAVINCI_SDIOIEN); + } +} + static struct mmc_host_ops mmc_davinci_ops = { .request = mmc_davinci_request, .set_ios = mmc_davinci_set_ios, .get_cd = mmc_davinci_get_cd, .get_ro = mmc_davinci_get_ro, + .enable_sdio_irq = mmc_davinci_enable_sdio_irq, }; /*----------------------------------------------------------------------*/ @@ -1209,7 +1267,8 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) host->nr_sg = MAX_NR_SG; host->use_dma = use_dma; - host->irq = irq; + host->mmc_irq = irq; + host->sdio_irq = platform_get_irq(pdev, 1); if (host->use_dma && davinci_acquire_dma_channels(host) != 0) host->use_dma = 0; @@ -1270,6 +1329,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) if (ret) goto out; + if (host->sdio_irq >= 0) { + ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, + mmc_hostname(mmc), host); + if (!ret) + mmc->caps |= MMC_CAP_SDIO_IRQ; + } + rename_region(mem, mmc_hostname(mmc)); dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n", @@ -1313,7 +1379,9 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) mmc_davinci_cpufreq_deregister(host); mmc_remove_host(host->mmc); - free_irq(host->irq, host); + free_irq(host->mmc_irq, host); + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) + free_irq(host->sdio_irq, host); davinci_release_dma_channels(host); -- cgit v1.2.3 From c268cd36cc8fd543f58aee0392c78bb92e54edcb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 17 Dec 2010 10:27:25 -0500 Subject: drm/radeon/kms: only enable hdmi features if the monitor supports audio This avoids some issues in the current hdmi audio code for monitors without audio. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index e7a948f60587..8fd184286c0b 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -641,7 +641,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (drm_detect_monitor_audio(radeon_connector->edid)) { /* fix me */ if (ASIC_IS_DCE4(rdev)) return ATOM_ENCODER_MODE_DVI; @@ -655,7 +655,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_HDMIA: default: - if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + if (drm_detect_monitor_audio(radeon_connector->edid)) { /* fix me */ if (ASIC_IS_DCE4(rdev)) return ATOM_ENCODER_MODE_DVI; @@ -673,7 +673,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return ATOM_ENCODER_MODE_DP; - else if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + else if (drm_detect_monitor_audio(radeon_connector->edid)) { /* fix me */ if (ASIC_IS_DCE4(rdev)) return ATOM_ENCODER_MODE_DVI; -- cgit v1.2.3 From 56bec7c009872ef33fe452ea75fecba481351b44 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 5 Jan 2011 11:57:52 -0500 Subject: drm/radeon/kms: disable underscan by default Lots of HDMI TVs overscan the incoming image by default. The underscan option was added as a way to compensate for that by underscanning the image so that the edges would not be cut off on an overscanning TV. However, the TV provides no way of knowing whether it is overscanning or not. If the user has disabled overscan on their TV or has a TV that does not overscan, you will get black bars around the edges of your screen. Prior to the patch we got complaints and bug reports from users with overscanning TVs, now with the patch, we get lots of complaints and bug reports from users with non-overscanning TVs. There's no good default, but on average there have been more users complaining about it being on by default than off, so change it to off. This will probably result in a new deluge of overscanning TV user complaints. There's no winning. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 5b00f92a50a2..22b7e3dc0eca 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1219,7 +1219,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (ASIC_IS_AVIVO(rdev)) { drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.underscan_property, - UNDERSCAN_AUTO); + UNDERSCAN_OFF); drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.underscan_hborder_property, 0); @@ -1259,7 +1259,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (ASIC_IS_AVIVO(rdev)) { drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.underscan_property, - UNDERSCAN_AUTO); + UNDERSCAN_OFF); drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.underscan_hborder_property, 0); @@ -1302,7 +1302,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (ASIC_IS_AVIVO(rdev)) { drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.underscan_property, - UNDERSCAN_AUTO); + UNDERSCAN_OFF); drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.underscan_hborder_property, 0); -- cgit v1.2.3 From 712247a6811530acdd604fa21574ccf1f2d80838 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 8 Nov 2010 12:56:21 +0100 Subject: OMAP: DSS2: Fix: Read correct bit in dispc_enable_alpha_blending() Read correct DISPC_CONFIG bit when the channel is DIGIT, remove extra line at the end of the function. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index fa40fa59a9ac..4e04a73a8ff3 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2003,13 +2003,12 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) if (ch == OMAP_DSS_CHANNEL_LCD) enabled = REG_GET(DISPC_CONFIG, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) - enabled = REG_GET(DISPC_CONFIG, 18, 18); + enabled = REG_GET(DISPC_CONFIG, 19, 19); else BUG(); enable_clocks(0); return enabled; - } -- cgit v1.2.3 From 8fbde10aff726c9b5a1a2fe878a072b937d32476 Mon Sep 17 00:00:00 2001 From: Samreen Date: Thu, 4 Nov 2010 12:28:41 +0100 Subject: OMAP3: DSS2: Split OMAP3 has feature for 3430 & 3630 Splitting the OMAP3 dss has feature separately for omap3430 & omap3630 Signed-off-by: Samreen Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss_features.c | 20 +++++++++++++++++--- drivers/video/omap2/dss/dss_features.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 867f68de125f..854deba4e0d8 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -134,7 +134,7 @@ static struct omap_dss_features omap2_dss_features = { }; /* OMAP3 DSS Features */ -static struct omap_dss_features omap3_dss_features = { +static struct omap_dss_features omap3430_dss_features = { .reg_fields = omap3_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), @@ -146,6 +146,18 @@ static struct omap_dss_features omap3_dss_features = { .supported_color_modes = omap3_dss_supported_color_modes, }; +static struct omap_dss_features omap3630_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA, + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + /* Functions returning values related to a DSS feature */ int dss_feat_get_num_mgrs(void) { @@ -186,6 +198,8 @@ void dss_features_init(void) { if (cpu_is_omap24xx()) omap_current_dss_features = &omap2_dss_features; - else - omap_current_dss_features = &omap3_dss_features; + else if (cpu_is_omap3630()) + omap_current_dss_features = &omap3630_dss_features; + else if (cpu_is_omap34xx()) + omap_current_dss_features = &omap3430_dss_features; } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index cb231eaa9b31..aeb2eea454fc 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -27,6 +27,7 @@ enum dss_feat_id { FEAT_GLOBAL_ALPHA = 1 << 0, FEAT_GLOBAL_ALPHA_VID1 = 1 << 1, + FEAT_PRE_MULT_ALPHA = 1 << 2, }; /* DSS register field id */ -- cgit v1.2.3 From fd28a39071cee34ec59021f620f6dfca5f89ac9b Mon Sep 17 00:00:00 2001 From: Rajkumar N Date: Thu, 4 Nov 2010 12:28:42 +0100 Subject: OMAP3630: DSS2: Enable Pre-Multiplied Alpha Support Enable dss to process color formats with pre-mulitplied alpha. With this we can have alpha values defined for each pixel and hence can have different blending values for each pixel. sysfs entry has been created for this and pre-multiplied alpha support is turned off by default. Signed-off-by: Sudeep Basavaraj Signed-off-by: Rajkumar N Signed-off-by: Samreen Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- arch/arm/plat-omap/include/plat/display.h | 1 + drivers/video/omap2/dss/dispc.c | 30 ++++++++++++++++------ drivers/video/omap2/dss/dss.h | 3 ++- drivers/video/omap2/dss/manager.c | 5 +++- drivers/video/omap2/dss/overlay.c | 41 +++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index c915a661f1f5..d433baf4e977 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -268,6 +268,7 @@ struct omap_overlay_info { u16 out_width; /* if 0, out_width == width */ u16 out_height; /* if 0, out_height == height */ u8 global_alpha; + u8 pre_mult_alpha; }; struct omap_overlay { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 4e04a73a8ff3..54ba8d3ad317 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -773,13 +773,26 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) dispc_write_reg(vsi_reg[plane-1], val); } +static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable) +{ + if (!dss_has_feature(FEAT_PRE_MULT_ALPHA)) + return; + + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) + return; + + REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28); +} + static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; - BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1); + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) + return; if (plane == OMAP_DSS_GFX) REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); @@ -1507,7 +1520,8 @@ static int _dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, int mirror, - u8 global_alpha) + u8 global_alpha, + u8 pre_mult_alpha) { const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; bool five_taps = 0; @@ -1693,8 +1707,8 @@ static int _dispc_setup_plane(enum omap_plane plane, _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode); - if (plane != OMAP_DSS_VIDEO1) - _dispc_setup_global_alpha(plane, global_alpha); + _dispc_set_pre_mult_alpha(plane, pre_mult_alpha); + _dispc_setup_global_alpha(plane, global_alpha); return 0; } @@ -3138,7 +3152,8 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_color_mode color_mode, bool ilace, enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, u8 global_alpha) + u8 rotation, bool mirror, u8 global_alpha, + u8 pre_mult_alpha) { int r = 0; @@ -3160,7 +3175,8 @@ int dispc_setup_plane(enum omap_plane plane, color_mode, ilace, rotation_type, rotation, mirror, - global_alpha); + global_alpha, + pre_mult_alpha); enable_clocks(0); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 5c7940d5f282..2bb515c61f4b 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -359,7 +359,8 @@ int dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, bool mirror, - u8 global_alpha); + u8 global_alpha, + u8 pre_mult_alpha); bool dispc_go_busy(enum omap_channel channel); void dispc_go(enum omap_channel channel); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 545e9b9a4d92..873b33469060 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -406,6 +406,7 @@ struct overlay_cache_data { u16 out_width; /* if 0, out_width == width */ u16 out_height; /* if 0, out_height == height */ u8 global_alpha; + u8 pre_mult_alpha; enum omap_channel channel; bool replication; @@ -842,7 +843,8 @@ static int configure_overlay(enum omap_plane plane) c->rotation_type, c->rotation, c->mirror, - c->global_alpha); + c->global_alpha, + c->pre_mult_alpha); if (r) { /* this shouldn't happen */ @@ -1265,6 +1267,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc->out_width = ovl->info.out_width; oc->out_height = ovl->info.out_height; oc->global_alpha = ovl->info.global_alpha; + oc->pre_mult_alpha = ovl->info.pre_mult_alpha; oc->replication = dss_use_replication(dssdev, ovl->info.color_mode); diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 75642c22cac7..41a29024a8d0 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -257,6 +257,43 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, return size; } +static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + ovl->info.pre_mult_alpha); +} + +static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + /* only GFX and Video2 plane support pre alpha multiplied + * set zero for Video1 plane + */ + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + ovl->id == OMAP_DSS_VIDEO1) + info.pre_mult_alpha = 0; + else + info.pre_mult_alpha = simple_strtoul(buf, NULL, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + struct overlay_attribute { struct attribute attr; ssize_t (*show)(struct omap_overlay *, char *); @@ -280,6 +317,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, overlay_enabled_show, overlay_enabled_store); static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, overlay_global_alpha_show, overlay_global_alpha_store); +static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, + overlay_pre_mult_alpha_show, + overlay_pre_mult_alpha_store); static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_name.attr, @@ -290,6 +330,7 @@ static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_output_size.attr, &overlay_attr_enabled.attr, &overlay_attr_global_alpha.attr, + &overlay_attr_pre_mult_alpha.attr, NULL }; -- cgit v1.2.3 From 2d2afa46e320b22d1ddcd430d62d6363b0a7e2b9 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Tue, 26 Oct 2010 05:12:36 +0200 Subject: OMAP: DSS2: Add NEC NL8048HL11-01B display panel NEC WVGA LCD NL8048HL11-01B panel support has been added. This panel is being used in zoom2/zoom3/3630 sdp boards. Signed-off-by: Mukund Mittal Signed-off-by: Rajkumar N Signed-off-by: Samreen CC: Subbu Venkatesh CC: Erik Gilling Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 7 + drivers/video/omap2/displays/Makefile | 1 + .../omap2/displays/panel-nec-nl8048hl11-01b.c | 325 +++++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c (limited to 'drivers') diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 12327bbfdbbb..f8152cfedb5f 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -20,6 +20,13 @@ config PANEL_SHARP_LQ043T1DG01 help LCD Panel used in TI's OMAP3517 EVM boards +config PANEL_NEC_NL8048HL11_01B + tristate "NEC NL8048HL11-01B Panel" + depends on OMAP2_DSS + help + This NEC NL8048HL11-01B panel is TFT LCD + used in the Zoom2/3/3630 sdp boards. + config PANEL_TAAL tristate "Taal DSI Panel" depends on OMAP2_DSS_DSI diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index aa386095d7c4..8ece91cfe177 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o +obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c new file mode 100644 index 000000000000..925e0fadff54 --- /dev/null +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -0,0 +1,325 @@ +/* + * Support for NEC-nl8048hl11-01b panel driver + * + * Copyright (C) 2010 Texas Instruments Inc. + * Author: Erik Gilling + * 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. + * + * 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, see . + */ + +#include +#include +#include +#include +#include + +#include + +#define LCD_XRES 800 +#define LCD_YRES 480 +/* + * NEC PIX Clock Ratings + * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz + */ +#define LCD_PIXEL_CLOCK 23800 + +struct nec_8048_data { + struct backlight_device *bl; +}; + +static const struct { + unsigned char addr; + unsigned char dat; +} nec_8048_init_seq[] = { + { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 }, + { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 }, + { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 }, + { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F }, + { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F }, + { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F }, + { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F }, + { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, + { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 }, + { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C }, + { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, + { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 }, + { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 }, + { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 }, + { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC }, + { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, + { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 }, + { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 }, +}; + +/* + * NEC NL8048HL11-01B Manual + * defines HFB, HSW, HBP, VFP, VSW, VBP as shown below + */ + +static struct omap_video_timings nec_8048_panel_timings = { + /* 800 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ + .x_res = LCD_XRES, + .y_res = LCD_YRES, + .pixel_clock = LCD_PIXEL_CLOCK, + .hfp = 6, + .hsw = 1, + .hbp = 4, + .vfp = 3, + .vsw = 1, + .vbp = 4, +}; + +static int nec_8048_bl_update_status(struct backlight_device *bl) +{ + struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); + int level; + + if (!dssdev->set_backlight) + return -EINVAL; + + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + level = bl->props.brightness; + else + level = 0; + + return dssdev->set_backlight(dssdev, level); +} + +static int nec_8048_bl_get_brightness(struct backlight_device *bl) +{ + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + return bl->props.brightness; + + return 0; +} + +static const struct backlight_ops nec_8048_bl_ops = { + .get_brightness = nec_8048_bl_get_brightness, + .update_status = nec_8048_bl_update_status, +}; + +static int nec_8048_panel_probe(struct omap_dss_device *dssdev) +{ + struct backlight_device *bl; + struct nec_8048_data *necd; + struct backlight_properties props; + int r; + + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF | + OMAP_DSS_LCD_ONOFF; + dssdev->panel.timings = nec_8048_panel_timings; + + necd = kzalloc(sizeof(*necd), GFP_KERNEL); + if (!necd) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, necd); + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 255; + + bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev, + &nec_8048_bl_ops, &props); + if (IS_ERR(bl)) { + r = PTR_ERR(bl); + kfree(necd); + return r; + } + necd->bl = bl; + + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.power = FB_BLANK_UNBLANK; + bl->props.max_brightness = dssdev->max_backlight_level; + bl->props.brightness = dssdev->max_backlight_level; + + r = nec_8048_bl_update_status(bl); + if (r < 0) + dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + + return 0; +} + +static void nec_8048_panel_remove(struct omap_dss_device *dssdev) +{ + struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = necd->bl; + + bl->props.power = FB_BLANK_POWERDOWN; + nec_8048_bl_update_status(bl); + backlight_device_unregister(bl); + + kfree(necd); +} + +static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = necd->bl; + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + return r; + } + + r = nec_8048_bl_update_status(bl); + if (r < 0) + dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + + r = omapdss_dpi_display_enable(dssdev); + + return r; +} + +static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +{ + struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = necd->bl; + + omapdss_dpi_display_disable(dssdev); + + bl->props.brightness = 0; + nec_8048_bl_update_status(bl); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +} + +static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) +{ + nec_8048_panel_disable(dssdev); + return 0; +} + +static int nec_8048_panel_resume(struct omap_dss_device *dssdev) +{ + return nec_8048_panel_enable(dssdev); +} + +static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) +{ + return 16; +} + +static struct omap_dss_driver nec_8048_driver = { + .probe = nec_8048_panel_probe, + .remove = nec_8048_panel_remove, + .enable = nec_8048_panel_enable, + .disable = nec_8048_panel_disable, + .suspend = nec_8048_panel_suspend, + .resume = nec_8048_panel_resume, + .get_recommended_bpp = nec_8048_recommended_bpp, + + .driver = { + .name = "NEC_8048_panel", + .owner = THIS_MODULE, + }, +}; + +static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr, + unsigned char reg_data) +{ + int ret = 0; + unsigned int cmd = 0, data = 0; + + cmd = 0x0000 | reg_addr; /* register address write */ + data = 0x0100 | reg_data ; /* register data write */ + data = (cmd << 16) | data; + + ret = spi_write(spi, (unsigned char *)&data, 4); + if (ret) + pr_err("error in spi_write %x\n", data); + + return ret; +} + +static int init_nec_8048_wvga_lcd(struct spi_device *spi) +{ + unsigned int i; + /* Initialization Sequence */ + /* nec_8048_spi_send(spi, REG, VAL) */ + for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++) + nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, + nec_8048_init_seq[i].dat); + udelay(20); + nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, + nec_8048_init_seq[i].dat); + return 0; +} + +static int nec_8048_spi_probe(struct spi_device *spi) +{ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 32; + spi_setup(spi); + + init_nec_8048_wvga_lcd(spi); + + return omap_dss_register_driver(&nec_8048_driver); +} + +static int nec_8048_spi_remove(struct spi_device *spi) +{ + omap_dss_unregister_driver(&nec_8048_driver); + + return 0; +} + +static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg) +{ + nec_8048_spi_send(spi, 2, 0x01); + mdelay(40); + + return 0; +} + +static int nec_8048_spi_resume(struct spi_device *spi) +{ + /* reinitialize the panel */ + spi_setup(spi); + nec_8048_spi_send(spi, 2, 0x00); + init_nec_8048_wvga_lcd(spi); + + return 0; +} + +static struct spi_driver nec_8048_spi_driver = { + .probe = nec_8048_spi_probe, + .remove = __devexit_p(nec_8048_spi_remove), + .suspend = nec_8048_spi_suspend, + .resume = nec_8048_spi_resume, + .driver = { + .name = "nec_8048_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, +}; + +static int __init nec_8048_lcd_init(void) +{ + return spi_register_driver(&nec_8048_spi_driver); +} + +static void __exit nec_8048_lcd_exit(void) +{ + return spi_unregister_driver(&nec_8048_spi_driver); +} + +module_init(nec_8048_lcd_init); +module_exit(nec_8048_lcd_exit); +MODULE_AUTHOR("Erik Gilling "); +MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 36e8c27f3bee5e58f96b0a79d65922fa9e53b030 Mon Sep 17 00:00:00 2001 From: Samreen Date: Tue, 16 Nov 2010 12:49:07 +0100 Subject: OMAP: DSS2: OMAPFB: Add null pointer check A null pointer check added. And using kstrdup() instead of kmalloc() & strcpy() Signed-off-by: Samreen Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 6a704f176c22..4fdab8e9c496 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2132,8 +2132,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) char *str, *options, *this_opt; int r = 0; - str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL); - strcpy(str, def_mode); + str = kstrdup(def_mode, GFP_KERNEL); + if (!str) + return -ENOMEM; options = str; while (!r && (this_opt = strsep(&options, ",")) != NULL) { -- cgit v1.2.3 From a9a62b6a886545960488cae3b97acb482361b802 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 17 Nov 2010 13:34:33 +0000 Subject: OMAP: DSS2: Add generic DPI panel display driver Generic DPI panel driver includes the driver and 4 similar panel configurations. It will match the panel name which is passed from platform data and setup the right configurations. With generic DPI panel driver, we can remove those 4 duplicated panel display drivers. In the future, it is simple for us just add new panel configuration date in panel-generic-dpi.c to support new display panel. Signed-off-by: Bryan Wu Acked-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- .../arm/plat-omap/include/plat/panel-generic-dpi.h | 37 +++ drivers/video/omap2/displays/Kconfig | 8 + drivers/video/omap2/displays/Makefile | 1 + drivers/video/omap2/displays/panel-generic-dpi.c | 355 +++++++++++++++++++++ 4 files changed, 401 insertions(+) create mode 100644 arch/arm/plat-omap/include/plat/panel-generic-dpi.h create mode 100644 drivers/video/omap2/displays/panel-generic-dpi.c (limited to 'drivers') diff --git a/arch/arm/plat-omap/include/plat/panel-generic-dpi.h b/arch/arm/plat-omap/include/plat/panel-generic-dpi.h new file mode 100644 index 000000000000..790619734bcd --- /dev/null +++ b/arch/arm/plat-omap/include/plat/panel-generic-dpi.h @@ -0,0 +1,37 @@ +/* + * Header for generic DPI panel driver + * + * Copyright (C) 2010 Canonical Ltd. + * Author: Bryan Wu + * + * 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. + * + * 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, see . + */ + +#ifndef __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H +#define __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H + +#include "display.h" + +/** + * struct panel_generic_dpi_data - panel driver configuration data + * @name: panel name + * @platform_enable: platform specific panel enable function + * @platform_disable: platform specific panel disable function + */ +struct panel_generic_dpi_data { + const char *name; + int (*platform_enable)(struct omap_dss_device *dssdev); + void (*platform_disable)(struct omap_dss_device *dssdev); +}; + +#endif /* __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H */ diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index f8152cfedb5f..6d921969e731 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -1,6 +1,14 @@ menu "OMAP2/3 Display Device Drivers" depends on OMAP2_DSS +config PANEL_GENERIC_DPI + tristate "Generic DPI Panel" + help + Generic DPI panel driver. + Supports DVI output for Beagle and OMAP3 SDP. + Supports LCD Panel used in TI SDP3430 and EVM boards, + OMAP3517 EVM boards and CM-T35. + config PANEL_GENERIC tristate "Generic Panel" help diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index 8ece91cfe177..48f9c88af0c7 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c new file mode 100644 index 000000000000..6702cf6d0a57 --- /dev/null +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -0,0 +1,355 @@ +/* + * Generic DPI Panels support + * + * Copyright (C) 2010 Canonical Ltd. + * Author: Bryan Wu + * + * Copyright (C) 2008 Nokia Corporation + * Author: Tomi Valkeinen + * + * 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. + * + * 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, see . + */ + +#include +#include +#include + +#include + +struct panel_config { + struct omap_video_timings timings; + + int acbi; /* ac-bias pin transitions per interrupt */ + /* Unit: line clocks */ + int acb; /* ac-bias pin frequency */ + + enum omap_panel_config config; + + int power_on_delay; + int power_off_delay; + + /* + * Used to match device to panel configuration + * when use generic panel driver + */ + const char *name; +}; + +/* Panel configurations */ +static struct panel_config generic_dpi_panels[] = { + /* Generic Panel */ + { + { + .x_res = 640, + .y_res = 480, + + .pixel_clock = 23500, + + .hfp = 48, + .hsw = 32, + .hbp = 80, + + .vfp = 3, + .vsw = 4, + .vbp = 7, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "generic", + }, + + /* Sharp LQ043T1DG01 */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 9000, + + .hsw = 42, + .hfp = 3, + .hbp = 2, + + .vsw = 11, + .vfp = 3, + .vbp = 2, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, + .power_on_delay = 50, + .power_off_delay = 100, + .name = "sharp_lq", + }, + + /* Sharp LS037V7DW01 */ + { + { + .x_res = 480, + .y_res = 640, + + .pixel_clock = 19200, + + .hsw = 2, + .hfp = 1, + .hbp = 28, + + .vsw = 1, + .vfp = 1, + .vbp = 1, + }, + .acbi = 0x0, + .acb = 0x28, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .power_on_delay = 50, + .power_off_delay = 100, + .name = "sharp_ls", + }, + + /* Toppoly TDO35S */ + { + { + .x_res = 480, + .y_res = 640, + + .pixel_clock = 26000, + + .hfp = 104, + .hsw = 8, + .hbp = 8, + + .vfp = 4, + .vsw = 2, + .vbp = 2, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC | + OMAP_DSS_LCD_ONOFF, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "toppoly_tdo35s", + }, +}; + +struct panel_drv_data { + + struct omap_dss_device *dssdev; + + struct panel_config *panel_config; +}; + +static inline struct panel_generic_dpi_data +*get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct panel_generic_dpi_data *) dssdev->data; +} + +static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) +{ + int r; + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + struct panel_config *panel_config = drv_data->panel_config; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + + /* wait couple of vsyncs until enabling the LCD */ + if (panel_config->power_on_delay) + msleep(panel_config->power_on_delay); + + if (panel_data->platform_enable) { + r = panel_data->platform_enable(dssdev); + if (r) + goto err1; + } + + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: + return r; +} + +static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) +{ + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + struct panel_config *panel_config = drv_data->panel_config; + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; + + if (panel_data->platform_disable) + panel_data->platform_disable(dssdev); + + /* wait couple of vsyncs after disabling the LCD */ + if (panel_config->power_off_delay) + msleep(panel_config->power_off_delay); + + omapdss_dpi_display_disable(dssdev); +} + +static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) +{ + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct panel_config *panel_config = NULL; + struct panel_drv_data *drv_data = NULL; + int i; + + dev_dbg(&dssdev->dev, "probe\n"); + + if (!panel_data || !panel_data->name) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) { + if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) { + panel_config = &generic_dpi_panels[i]; + break; + } + } + + if (!panel_config) + return -EINVAL; + + dssdev->panel.config = panel_config->config; + dssdev->panel.timings = panel_config->timings; + dssdev->panel.acb = panel_config->acb; + dssdev->panel.acbi = panel_config->acbi; + + drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + drv_data->dssdev = dssdev; + drv_data->panel_config = panel_config; + + dev_set_drvdata(&dssdev->dev, drv_data); + + return 0; +} + +static void generic_dpi_panel_remove(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + dev_dbg(&dssdev->dev, "remove\n"); + + kfree(drv_data); + + dev_set_drvdata(&dssdev->dev, NULL); +} + +static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + r = generic_dpi_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) +{ + generic_dpi_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +} + +static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) +{ + generic_dpi_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + + return 0; +} + +static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) +{ + int r = 0; + + r = generic_dpi_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dpi_set_timings(dssdev, timings); +} + +static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = dssdev->panel.timings; +} + +static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + return dpi_check_timings(dssdev, timings); +} + +static struct omap_dss_driver dpi_driver = { + .probe = generic_dpi_panel_probe, + .remove = generic_dpi_panel_remove, + + .enable = generic_dpi_panel_enable, + .disable = generic_dpi_panel_disable, + .suspend = generic_dpi_panel_suspend, + .resume = generic_dpi_panel_resume, + + .set_timings = generic_dpi_panel_set_timings, + .get_timings = generic_dpi_panel_get_timings, + .check_timings = generic_dpi_panel_check_timings, + + .driver = { + .name = "generic_dpi_panel", + .owner = THIS_MODULE, + }, +}; + +static int __init generic_dpi_panel_drv_init(void) +{ + return omap_dss_register_driver(&dpi_driver); +} + +static void __exit generic_dpi_panel_drv_exit(void) +{ + omap_dss_unregister_driver(&dpi_driver); +} + +module_init(generic_dpi_panel_drv_init); +module_exit(generic_dpi_panel_drv_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From da9d2f47aa74f20b07ebbe04676b67ead2672abf Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 17 Nov 2010 13:34:35 +0000 Subject: OMAP: DSS2: remove generic DPI panel driver duplicated panel drivers Still keep sharp_ls_panel driver, because it contains blacklight control driver. Signed-off-by: Bryan Wu Acked-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 18 --- drivers/video/omap2/displays/Makefile | 3 - drivers/video/omap2/displays/panel-generic.c | 174 --------------------- .../video/omap2/displays/panel-sharp-lq043t1dg01.c | 165 ------------------- .../video/omap2/displays/panel-toppoly-tdo35s.c | 164 ------------------- 5 files changed, 524 deletions(-) delete mode 100644 drivers/video/omap2/displays/panel-generic.c delete mode 100644 drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c delete mode 100644 drivers/video/omap2/displays/panel-toppoly-tdo35s.c (limited to 'drivers') diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 6d921969e731..940cab394c2e 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -9,12 +9,6 @@ config PANEL_GENERIC_DPI Supports LCD Panel used in TI SDP3430 and EVM boards, OMAP3517 EVM boards and CM-T35. -config PANEL_GENERIC - tristate "Generic Panel" - help - Generic panel driver. - Used for DVI output for Beagle and OMAP3 SDP. - config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on OMAP2_DSS @@ -22,12 +16,6 @@ config PANEL_SHARP_LS037V7DW01 help LCD Panel used in TI's SDP3430 and EVM boards -config PANEL_SHARP_LQ043T1DG01 - tristate "Sharp LQ043T1DG01 LCD Panel" - depends on OMAP2_DSS - help - LCD Panel used in TI's OMAP3517 EVM boards - config PANEL_NEC_NL8048HL11_01B tristate "NEC NL8048HL11-01B Panel" depends on OMAP2_DSS @@ -41,12 +29,6 @@ config PANEL_TAAL help Taal DSI command mode panel from TPO. -config PANEL_TOPPOLY_TDO35S - tristate "Toppoly TDO35S LCD Panel support" - depends on OMAP2_DSS - help - LCD Panel used in CM-T35 - config PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" depends on OMAP2_DSS && SPI diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index 48f9c88af0c7..861f0255ec6b 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -1,10 +1,7 @@ obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o -obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o -obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o -obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c deleted file mode 100644 index 395a68de3990..000000000000 --- a/drivers/video/omap2/displays/panel-generic.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Generic panel support - * - * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen - * - * 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. - * - * 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, see . - */ - -#include -#include - -#include - -static struct omap_video_timings generic_panel_timings = { - /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ - .x_res = 640, - .y_res = 480, - .pixel_clock = 23500, - .hfp = 48, - .hsw = 32, - .hbp = 80, - .vfp = 3, - .vsw = 4, - .vbp = 7, -}; - -static int generic_panel_power_on(struct omap_dss_device *dssdev) -{ - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - r = omapdss_dpi_display_enable(dssdev); - if (r) - goto err0; - - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } - - return 0; -err1: - omapdss_dpi_display_disable(dssdev); -err0: - return r; -} - -static void generic_panel_power_off(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return; - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - omapdss_dpi_display_disable(dssdev); -} - -static int generic_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.config = OMAP_DSS_LCD_TFT; - dssdev->panel.timings = generic_panel_timings; - - return 0; -} - -static void generic_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int generic_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = generic_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void generic_panel_disable(struct omap_dss_device *dssdev) -{ - generic_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} - -static int generic_panel_suspend(struct omap_dss_device *dssdev) -{ - generic_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int generic_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = generic_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void generic_panel_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - dpi_set_timings(dssdev, timings); -} - -static void generic_panel_get_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - *timings = dssdev->panel.timings; -} - -static int generic_panel_check_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - return dpi_check_timings(dssdev, timings); -} - -static struct omap_dss_driver generic_driver = { - .probe = generic_panel_probe, - .remove = generic_panel_remove, - - .enable = generic_panel_enable, - .disable = generic_panel_disable, - .suspend = generic_panel_suspend, - .resume = generic_panel_resume, - - .set_timings = generic_panel_set_timings, - .get_timings = generic_panel_get_timings, - .check_timings = generic_panel_check_timings, - - .driver = { - .name = "generic_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init generic_panel_drv_init(void) -{ - return omap_dss_register_driver(&generic_driver); -} - -static void __exit generic_panel_drv_exit(void) -{ - omap_dss_unregister_driver(&generic_driver); -} - -module_init(generic_panel_drv_init); -module_exit(generic_panel_drv_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c deleted file mode 100644 index 0c6896cea2d0..000000000000 --- a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * LCD panel driver for Sharp LQ043T1DG01 - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Vaibhav Hiremath - * - * 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. - * - * 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, see . - */ - -#include -#include -#include -#include - -#include - -static struct omap_video_timings sharp_lq_timings = { - .x_res = 480, - .y_res = 272, - - .pixel_clock = 9000, - - .hsw = 42, - .hfp = 3, - .hbp = 2, - - .vsw = 11, - .vfp = 3, - .vbp = 2, -}; - -static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev) -{ - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - r = omapdss_dpi_display_enable(dssdev); - if (r) - goto err0; - - /* wait couple of vsyncs until enabling the LCD */ - msleep(50); - - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } - - return 0; -err1: - omapdss_dpi_display_disable(dssdev); -err0: - return r; -} - -static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return; - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - /* wait at least 5 vsyncs after disabling the LCD */ - msleep(100); - - omapdss_dpi_display_disable(dssdev); -} - -static int sharp_lq_panel_probe(struct omap_dss_device *dssdev) -{ - - dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | - OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO; - dssdev->panel.acb = 0x0; - dssdev->panel.timings = sharp_lq_timings; - - return 0; -} - -static void sharp_lq_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int sharp_lq_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = sharp_lq_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void sharp_lq_panel_disable(struct omap_dss_device *dssdev) -{ - sharp_lq_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} - -static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev) -{ - sharp_lq_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int sharp_lq_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = sharp_lq_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static struct omap_dss_driver sharp_lq_driver = { - .probe = sharp_lq_panel_probe, - .remove = sharp_lq_panel_remove, - - .enable = sharp_lq_panel_enable, - .disable = sharp_lq_panel_disable, - .suspend = sharp_lq_panel_suspend, - .resume = sharp_lq_panel_resume, - - .driver = { - .name = "sharp_lq_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init sharp_lq_panel_drv_init(void) -{ - return omap_dss_register_driver(&sharp_lq_driver); -} - -static void __exit sharp_lq_panel_drv_exit(void) -{ - omap_dss_unregister_driver(&sharp_lq_driver); -} - -module_init(sharp_lq_panel_drv_init); -module_exit(sharp_lq_panel_drv_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c deleted file mode 100644 index 526e906c8a6c..000000000000 --- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * LCD panel driver for Toppoly TDO35S - * - * Copyright (C) 2009 CompuLab, Ltd. - * Author: Mike Rapoport - * - * Based on generic panel support - * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen - * - * 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. - * - * 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, see . - */ - -#include -#include - -#include - -static struct omap_video_timings toppoly_tdo_panel_timings = { - /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ - .x_res = 480, - .y_res = 640, - - .pixel_clock = 26000, - - .hfp = 104, - .hsw = 8, - .hbp = 8, - - .vfp = 4, - .vsw = 2, - .vbp = 2, -}; - -static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev) -{ - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - r = omapdss_dpi_display_enable(dssdev); - if (r) - goto err0; - - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } - - return 0; -err1: - omapdss_dpi_display_disable(dssdev); -err0: - return r; -} - -static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return; - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - omapdss_dpi_display_disable(dssdev); -} - -static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.config = OMAP_DSS_LCD_TFT | - OMAP_DSS_LCD_IVS | - OMAP_DSS_LCD_IHS | - OMAP_DSS_LCD_IPC | - OMAP_DSS_LCD_ONOFF; - - dssdev->panel.timings = toppoly_tdo_panel_timings; - - return 0; -} - -static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = toppoly_tdo_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev) -{ - toppoly_tdo_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} - -static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev) -{ - toppoly_tdo_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = toppoly_tdo_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static struct omap_dss_driver generic_driver = { - .probe = toppoly_tdo_panel_probe, - .remove = toppoly_tdo_panel_remove, - - .enable = toppoly_tdo_panel_enable, - .disable = toppoly_tdo_panel_disable, - .suspend = toppoly_tdo_panel_suspend, - .resume = toppoly_tdo_panel_resume, - - .driver = { - .name = "toppoly_tdo35s_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init toppoly_tdo_panel_drv_init(void) -{ - return omap_dss_register_driver(&generic_driver); -} - -static void __exit toppoly_tdo_panel_drv_exit(void) -{ - omap_dss_unregister_driver(&generic_driver); -} - -module_init(toppoly_tdo_panel_drv_init); -module_exit(toppoly_tdo_panel_drv_exit); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ac1427e13b114f0c394fbc9bb7616f47d03bdba2 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 18 Nov 2010 09:45:59 +0800 Subject: OMAP: DSS2: Add back authors of panel-generic.c based drivers Signed-off-by: Bryan Wu Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-generic-dpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 6702cf6d0a57..07eb30ee59c8 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -4,6 +4,16 @@ * Copyright (C) 2010 Canonical Ltd. * Author: Bryan Wu * + * LCD panel driver for Sharp LQ043T1DG01 + * + * Copyright (C) 2009 Texas Instruments Inc + * Author: Vaibhav Hiremath + * + * LCD panel driver for Toppoly TDO35S + * + * Copyright (C) 2009 CompuLab, Ltd. + * Author: Mike Rapoport + * * Copyright (C) 2008 Nokia Corporation * Author: Tomi Valkeinen * -- cgit v1.2.3 From 8dad2ab6727f4dd9fdef06b890d736d7c6d1a725 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 25 Nov 2010 17:58:10 +0530 Subject: OMAP: DSS2: Clean up DISPC color mode validation checks The supported set of color modes varies for different DISPC pipelines(plane) and omap version. This makes the checks for validation of a color mode more complicated as new omap versions are added. A dss_feature function is created which tells if a color_mode is supported for a plane on the current omap revision. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 53 ++++------------------------------ drivers/video/omap2/dss/dss_features.c | 7 +++++ drivers/video/omap2/dss/dss_features.h | 2 ++ 3 files changed, 14 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 54ba8d3ad317..4e9ebdecc436 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1550,29 +1550,12 @@ static int _dispc_setup_plane(enum omap_plane plane, height, pos_y, out_height); } + if (!dss_feat_color_mode_supported(plane, color_mode)) + return -EINVAL; + if (plane == OMAP_DSS_GFX) { if (width != out_width || height != out_height) return -EINVAL; - - switch (color_mode) { - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -EINVAL; - case OMAP_DSS_COLOR_RGBX32: - if (cpu_is_omap24xx()) - return -EINVAL; - /* fall through */ - case OMAP_DSS_COLOR_RGB12U: - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_RGB24P: - case OMAP_DSS_COLOR_RGB24U: - break; - - default: - return -EINVAL; - } } else { /* video plane */ @@ -1586,35 +1569,9 @@ static int _dispc_setup_plane(enum omap_plane plane, out_height > height * 8) return -EINVAL; - switch (color_mode) { - case OMAP_DSS_COLOR_RGBX32: - case OMAP_DSS_COLOR_RGB12U: - if (cpu_is_omap24xx()) - return -EINVAL; - /* fall through */ - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_RGB24P: - case OMAP_DSS_COLOR_RGB24U: - break; - - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -EINVAL; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1) - return -EINVAL; - break; - - case OMAP_DSS_COLOR_YUV2: - case OMAP_DSS_COLOR_UYVY: + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY) cconv = 1; - break; - - default: - return -EINVAL; - } /* Must use 5-tap filter? */ five_taps = height > out_height * 2; diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 854deba4e0d8..620221f678f9 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -179,6 +179,13 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) return omap_current_dss_features->supported_color_modes[plane]; } +bool dss_feat_color_mode_supported(enum omap_plane plane, + enum omap_color_mode color_mode) +{ + return omap_current_dss_features->supported_color_modes[plane] & + color_mode; +} + /* DSS has_feature check */ bool dss_has_feature(enum dss_feat_id id) { diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index aeb2eea454fc..806db43bab17 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -44,6 +44,8 @@ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); +bool dss_feat_color_mode_supported(enum omap_plane plane, + enum omap_color_mode color_mode); bool dss_has_feature(enum dss_feat_id id); void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); -- cgit v1.2.3 From d50cd0373ad380fcc7f6fb4e020be4239174756d Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 2 Dec 2010 11:27:08 +0000 Subject: OMAP: DSS2: Add dss_features for omap4 and overlay manager related features Initialize a dss_features struct for omap4. Add support for LCD2 manager by introducing a new member in dss_feat_id. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss_features.c | 43 ++++++++++++++++++++++++++++++++-- drivers/video/omap2/dss/dss_features.h | 7 +++++- 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 620221f678f9..cf3ef696e141 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -82,6 +82,18 @@ static const enum omap_display_type omap3_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_VENC, }; +static const enum omap_display_type omap4_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_VENC, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, +}; + static const enum omap_color_mode omap2_dss_supported_color_modes[] = { /* OMAP_DSS_GFX */ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | @@ -127,6 +139,10 @@ static struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), + .has_feature = + FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | + FEAT_PCKFREEENABLE | FEAT_FUNCGATED, + .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, @@ -138,7 +154,10 @@ static struct omap_dss_features omap3430_dss_features = { .reg_fields = omap3_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), - .has_feature = FEAT_GLOBAL_ALPHA, + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | + FEAT_FUNCGATED, .num_mgrs = 2, .num_ovls = 3, @@ -150,7 +169,10 @@ static struct omap_dss_features omap3630_dss_features = { .reg_fields = omap3_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), - .has_feature = FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA, + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | + FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED, .num_mgrs = 2, .num_ovls = 3, @@ -158,6 +180,21 @@ static struct omap_dss_features omap3630_dss_features = { .supported_color_modes = omap3_dss_supported_color_modes, }; +/* OMAP4 DSS Features */ +static struct omap_dss_features omap4_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | + FEAT_MGR_LCD2, + + .num_mgrs = 3, + .num_ovls = 3, + .supported_displays = omap4_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + /* Functions returning values related to a DSS feature */ int dss_feat_get_num_mgrs(void) { @@ -209,4 +246,6 @@ void dss_features_init(void) omap_current_dss_features = &omap3630_dss_features; else if (cpu_is_omap34xx()) omap_current_dss_features = &omap3430_dss_features; + else + omap_current_dss_features = &omap4_dss_features; } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 806db43bab17..b9c70be92588 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -20,7 +20,7 @@ #ifndef __OMAP2_DSS_FEATURES_H #define __OMAP2_DSS_FEATURES_H -#define MAX_DSS_MANAGERS 2 +#define MAX_DSS_MANAGERS 3 #define MAX_DSS_OVERLAYS 3 /* DSS has feature id */ @@ -28,6 +28,11 @@ enum dss_feat_id { FEAT_GLOBAL_ALPHA = 1 << 0, FEAT_GLOBAL_ALPHA_VID1 = 1 << 1, FEAT_PRE_MULT_ALPHA = 1 << 2, + FEAT_LCDENABLEPOL = 1 << 3, + FEAT_LCDENABLESIGNAL = 1 << 4, + FEAT_PCKFREEENABLE = 1 << 5, + FEAT_FUNCGATED = 1 << 6, + FEAT_MGR_LCD2 = 1 << 7, }; /* DSS register field id */ -- cgit v1.2.3 From 8613b0005d315582a988bbeb2249d69df343eb3a Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Thu, 2 Dec 2010 11:27:09 +0000 Subject: OMAP: DSS2: Represent DISPC register defines with channel as parameter On OMAP4, we have a new DISPC channel for Overlay Manager LCD2. There is a set of regsiters for LCD2 channel similar to the existing LCD channel, like DISPC_CONTROL2, DISPC_DIVISOR2, DISPC_CONFIG2 and so on. Introduce new enum members for LCD2 Channel and corresponding Overlay Manager in display.h. Represent the following DISPC register defines with channel as a parameter to differentiate between LCD and LCD2 registers (and also DIGIT in some cases): DISPC_DEFAULT_COLOR, DISPC_TRANS_COLOR, DISPC_TIMING_H, DISPC_TIMING_V, DISPC_POL_FREQ, DISPC_DIVISOR, DISPC_SIZE_LCD, DISPC_DATA_CYCLEk, DISPC_CPR_COEF_R, DISPC_CPR_COEF_G and DISPC_CPR_COEF_B This parametrization helps in reducing the number of register defines for DISPC. Replace the existing reads/writes to these registers in this new way. Also, Introduce defines for registers DISPC_CONTROL2 and DISPC_CONFIG2 which are used exclusively for LCD2 channel. Signed-off-by: Sumit Semwal Signed-off-by: Mukund Mittal Signed-off-by: Samreen Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- arch/arm/plat-omap/include/plat/display.h | 2 + drivers/video/omap2/dss/dispc.c | 170 ++++++++++++++---------------- 2 files changed, 84 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index d433baf4e977..586944d8e9e8 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -64,6 +64,7 @@ enum omap_plane { enum omap_channel { OMAP_DSS_CHANNEL_LCD = 0, OMAP_DSS_CHANNEL_DIGIT = 1, + OMAP_DSS_CHANNEL_LCD2 = 2, }; enum omap_color_mode { @@ -142,6 +143,7 @@ enum omap_dss_display_state { enum omap_dss_overlay_managers { OMAP_DSS_OVL_MGR_LCD, OMAP_DSS_OVL_MGR_TV, + OMAP_DSS_OVL_MGR_LCD2, }; enum omap_dss_rotation_type { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 4e9ebdecc436..36fadb8e49c3 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -44,34 +44,40 @@ /* DISPC */ #define DISPC_BASE 0x48050400 -#define DISPC_SZ_REGS SZ_1K +#define DISPC_SZ_REGS SZ_4K struct dispc_reg { u16 idx; }; #define DISPC_REG(idx) ((const struct dispc_reg) { idx }) -/* DISPC common */ +/* + * DISPC common registers and + * DISPC channel registers , ch = 0 for LCD, ch = 1 for + * DIGIT, and ch = 2 for LCD2 + */ #define DISPC_REVISION DISPC_REG(0x0000) #define DISPC_SYSCONFIG DISPC_REG(0x0010) #define DISPC_SYSSTATUS DISPC_REG(0x0014) #define DISPC_IRQSTATUS DISPC_REG(0x0018) #define DISPC_IRQENABLE DISPC_REG(0x001C) #define DISPC_CONTROL DISPC_REG(0x0040) +#define DISPC_CONTROL2 DISPC_REG(0x0238) #define DISPC_CONFIG DISPC_REG(0x0044) +#define DISPC_CONFIG2 DISPC_REG(0x0620) #define DISPC_CAPABLE DISPC_REG(0x0048) -#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C) -#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050) -#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054) -#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058) +#define DISPC_DEFAULT_COLOR(ch) DISPC_REG(ch == 0 ? 0x004C : \ + (ch == 1 ? 0x0050 : 0x03AC)) +#define DISPC_TRANS_COLOR(ch) DISPC_REG(ch == 0 ? 0x0054 : \ + (ch == 1 ? 0x0058 : 0x03B0)) #define DISPC_LINE_STATUS DISPC_REG(0x005C) #define DISPC_LINE_NUMBER DISPC_REG(0x0060) -#define DISPC_TIMING_H DISPC_REG(0x0064) -#define DISPC_TIMING_V DISPC_REG(0x0068) -#define DISPC_POL_FREQ DISPC_REG(0x006C) -#define DISPC_DIVISOR DISPC_REG(0x0070) +#define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400) +#define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404) +#define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408) +#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) #define DISPC_SIZE_DIG DISPC_REG(0x0078) -#define DISPC_SIZE_LCD DISPC_REG(0x007C) +#define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC) /* DISPC GFX plane */ #define DISPC_GFX_BA0 DISPC_REG(0x0080) @@ -86,13 +92,12 @@ struct dispc_reg { u16 idx; }; #define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4) #define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8) -#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4) -#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8) -#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC) - -#define DISPC_CPR_COEF_R DISPC_REG(0x0220) -#define DISPC_CPR_COEF_G DISPC_REG(0x0224) -#define DISPC_CPR_COEF_B DISPC_REG(0x0228) +#define DISPC_DATA_CYCLE1(ch) DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0) +#define DISPC_DATA_CYCLE2(ch) DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4) +#define DISPC_DATA_CYCLE3(ch) DISPC_REG(ch != 2 ? 0x01DC : 0x03C8) +#define DISPC_CPR_COEF_R(ch) DISPC_REG(ch != 2 ? 0x0220 : 0x03BC) +#define DISPC_CPR_COEF_G(ch) DISPC_REG(ch != 2 ? 0x0224 : 0x03B8) +#define DISPC_CPR_COEF_B(ch) DISPC_REG(ch != 2 ? 0x0228 : 0x03B4) #define DISPC_GFX_PRELOAD DISPC_REG(0x022C) @@ -217,18 +222,18 @@ void dispc_save_context(void) SR(IRQENABLE); SR(CONTROL); SR(CONFIG); - SR(DEFAULT_COLOR0); - SR(DEFAULT_COLOR1); - SR(TRANS_COLOR0); - SR(TRANS_COLOR1); + SR(DEFAULT_COLOR(0)); + SR(DEFAULT_COLOR(1)); + SR(TRANS_COLOR(0)); + SR(TRANS_COLOR(1)); SR(LINE_NUMBER); - SR(TIMING_H); - SR(TIMING_V); - SR(POL_FREQ); - SR(DIVISOR); + SR(TIMING_H(0)); + SR(TIMING_V(0)); + SR(POL_FREQ(0)); + SR(DIVISOR(0)); SR(GLOBAL_ALPHA); SR(SIZE_DIG); - SR(SIZE_LCD); + SR(SIZE_LCD(0)); SR(GFX_BA0); SR(GFX_BA1); @@ -241,13 +246,13 @@ void dispc_save_context(void) SR(GFX_WINDOW_SKIP); SR(GFX_TABLE_BA); - SR(DATA_CYCLE1); - SR(DATA_CYCLE2); - SR(DATA_CYCLE3); + SR(DATA_CYCLE1(0)); + SR(DATA_CYCLE2(0)); + SR(DATA_CYCLE3(0)); - SR(CPR_COEF_R); - SR(CPR_COEF_G); - SR(CPR_COEF_B); + SR(CPR_COEF_R(0)); + SR(CPR_COEF_G(0)); + SR(CPR_COEF_B(0)); SR(GFX_PRELOAD); @@ -356,18 +361,18 @@ void dispc_restore_context(void) /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); - RR(DEFAULT_COLOR0); - RR(DEFAULT_COLOR1); - RR(TRANS_COLOR0); - RR(TRANS_COLOR1); + RR(DEFAULT_COLOR(0)); + RR(DEFAULT_COLOR(1)); + RR(TRANS_COLOR(0)); + RR(TRANS_COLOR(1)); RR(LINE_NUMBER); - RR(TIMING_H); - RR(TIMING_V); - RR(POL_FREQ); - RR(DIVISOR); + RR(TIMING_H(0)); + RR(TIMING_V(0)); + RR(POL_FREQ(0)); + RR(DIVISOR(0)); RR(GLOBAL_ALPHA); RR(SIZE_DIG); - RR(SIZE_LCD); + RR(SIZE_LCD(0)); RR(GFX_BA0); RR(GFX_BA1); @@ -380,13 +385,13 @@ void dispc_restore_context(void) RR(GFX_WINDOW_SKIP); RR(GFX_TABLE_BA); - RR(DATA_CYCLE1); - RR(DATA_CYCLE2); - RR(DATA_CYCLE3); + RR(DATA_CYCLE1(0)); + RR(DATA_CYCLE2(0)); + RR(DATA_CYCLE3(0)); - RR(CPR_COEF_R); - RR(CPR_COEF_G); - RR(CPR_COEF_B); + RR(CPR_COEF_R(0)); + RR(CPR_COEF_G(0)); + RR(CPR_COEF_B(0)); RR(GFX_PRELOAD); @@ -942,7 +947,7 @@ void dispc_set_lcd_size(u16 width, u16 height) BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); enable_clocks(1); - dispc_write_reg(DISPC_SIZE_LCD, val); + dispc_write_reg(DISPC_SIZE_LCD(OMAP_DSS_CHANNEL_LCD), val); enable_clocks(0); } @@ -1879,25 +1884,20 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) void dispc_set_default_color(enum omap_channel channel, u32 color) { - const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, - DISPC_DEFAULT_COLOR1 }; - enable_clocks(1); - dispc_write_reg(def_reg[channel], color); + dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); enable_clocks(0); } u32 dispc_get_default_color(enum omap_channel channel) { - const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, - DISPC_DEFAULT_COLOR1 }; u32 l; BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && channel != OMAP_DSS_CHANNEL_LCD); enable_clocks(1); - l = dispc_read_reg(def_reg[channel]); + l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); enable_clocks(0); return l; @@ -1907,16 +1907,13 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { - const struct dispc_reg tr_reg[] = { - DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); else /* OMAP_DSS_CHANNEL_DIGIT */ REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); - dispc_write_reg(tr_reg[ch], trans_key); + dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); enable_clocks(0); } @@ -1924,9 +1921,6 @@ void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { - const struct dispc_reg tr_reg[] = { - DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; - enable_clocks(1); if (type) { if (ch == OMAP_DSS_CHANNEL_LCD) @@ -1938,7 +1932,7 @@ void dispc_get_trans_key(enum omap_channel ch, } if (trans_key) - *trans_key = dispc_read_reg(tr_reg[ch]); + *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); enable_clocks(0); } @@ -2119,8 +2113,8 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, } enable_clocks(1); - dispc_write_reg(DISPC_TIMING_H, timing_h); - dispc_write_reg(DISPC_TIMING_V, timing_v); + dispc_write_reg(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD), timing_h); + dispc_write_reg(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD), timing_v); enable_clocks(0); } @@ -2161,7 +2155,7 @@ static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div) BUG_ON(pck_div < 2); enable_clocks(1); - dispc_write_reg(DISPC_DIVISOR, + dispc_write_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); enable_clocks(0); } @@ -2169,7 +2163,7 @@ static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div) static void dispc_get_lcd_divisor(int *lck_div, int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } @@ -2195,7 +2189,7 @@ unsigned long dispc_lclk_rate(void) unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD)); lcd = FLD_GET(l, 23, 16); @@ -2210,7 +2204,7 @@ unsigned long dispc_pclk_rate(void) unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD)); lcd = FLD_GET(l, 23, 16); pcd = FLD_GET(l, 7, 0); @@ -2297,19 +2291,19 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_CONTROL); DUMPREG(DISPC_CONFIG); DUMPREG(DISPC_CAPABLE); - DUMPREG(DISPC_DEFAULT_COLOR0); - DUMPREG(DISPC_DEFAULT_COLOR1); - DUMPREG(DISPC_TRANS_COLOR0); - DUMPREG(DISPC_TRANS_COLOR1); + DUMPREG(DISPC_DEFAULT_COLOR(0)); + DUMPREG(DISPC_DEFAULT_COLOR(1)); + DUMPREG(DISPC_TRANS_COLOR(0)); + DUMPREG(DISPC_TRANS_COLOR(1)); DUMPREG(DISPC_LINE_STATUS); DUMPREG(DISPC_LINE_NUMBER); - DUMPREG(DISPC_TIMING_H); - DUMPREG(DISPC_TIMING_V); - DUMPREG(DISPC_POL_FREQ); - DUMPREG(DISPC_DIVISOR); + DUMPREG(DISPC_TIMING_H(0)); + DUMPREG(DISPC_TIMING_V(0)); + DUMPREG(DISPC_POL_FREQ(0)); + DUMPREG(DISPC_DIVISOR(0)); DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_DIG); - DUMPREG(DISPC_SIZE_LCD); + DUMPREG(DISPC_SIZE_LCD(0)); DUMPREG(DISPC_GFX_BA0); DUMPREG(DISPC_GFX_BA1); @@ -2323,13 +2317,13 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_GFX_WINDOW_SKIP); DUMPREG(DISPC_GFX_TABLE_BA); - DUMPREG(DISPC_DATA_CYCLE1); - DUMPREG(DISPC_DATA_CYCLE2); - DUMPREG(DISPC_DATA_CYCLE3); + DUMPREG(DISPC_DATA_CYCLE1(0)); + DUMPREG(DISPC_DATA_CYCLE2(0)); + DUMPREG(DISPC_DATA_CYCLE3(0)); - DUMPREG(DISPC_CPR_COEF_R); - DUMPREG(DISPC_CPR_COEF_G); - DUMPREG(DISPC_CPR_COEF_B); + DUMPREG(DISPC_CPR_COEF_R(0)); + DUMPREG(DISPC_CPR_COEF_G(0)); + DUMPREG(DISPC_CPR_COEF_B(0)); DUMPREG(DISPC_GFX_PRELOAD); @@ -2446,7 +2440,7 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, l |= FLD_VAL(acb, 7, 0); enable_clocks(1); - dispc_write_reg(DISPC_POL_FREQ, l); + dispc_write_reg(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD), l); enable_clocks(0); } @@ -2537,8 +2531,8 @@ int dispc_get_clock_div(struct dispc_clock_info *cinfo) fck = dispc_fclk_rate(); - cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0); + cinfo->lck_div = REG_GET(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD), 23, 16); + cinfo->pck_div = REG_GET(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; -- cgit v1.2.3 From 64ba4f748a005a44c03c98e082d8ee157f4ee66f Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Thu, 2 Dec 2010 11:27:10 +0000 Subject: OMAP: DSS2: Introduce omap_channel argument to DISPC functions used by interface drivers The interface drivers (dsi.c, sdi.c etc) need to call dispc functions with dssdev->manager->id as a parameter to specify the DISPC channel which they want to configure/use, this is required as the same functions are now used to configure dispc registers of different channels. The following dispc functions are changed to incorporate channel as an argument: -dispc_enable_fifohandcheck() -dispc_set_lcd_size() -dispc_set_parallel_interface_mode() -dispc_set_tft_data_lines() -dispc_set_lcd_display_type() -dispc_set_lcd_timings() Signed-off-by: Sumit Semwal Signed-off-by: Mukund Mittal Signed-off-by: Samreen Signed-off-by: Archit Taneja [tomi.valkeinen@nokia.com: fixed trivial compile error] Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 38 ++++++++++++++++++++++---------------- drivers/video/omap2/dss/dpi.c | 12 +++++++----- drivers/video/omap2/dss/dsi.c | 14 ++++++++------ drivers/video/omap2/dss/dss.h | 19 +++++++++++-------- drivers/video/omap2/dss/rfbi.c | 20 +++++++++++--------- drivers/video/omap2/dss/sdi.c | 16 ++++++++++------ 6 files changed, 69 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 36fadb8e49c3..7ca53c100419 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -941,13 +941,13 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) enable_clocks(0); } -void dispc_set_lcd_size(u16 width, u16 height) +void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) { u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); enable_clocks(1); - dispc_write_reg(DISPC_SIZE_LCD(OMAP_DSS_CHANNEL_LCD), val); + dispc_write_reg(DISPC_SIZE_LCD(channel), val); enable_clocks(0); } @@ -1843,7 +1843,7 @@ void dispc_pck_free_enable(bool enable) enable_clocks(0); } -void dispc_enable_fifohandcheck(bool enable) +void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { enable_clocks(1); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); @@ -1851,7 +1851,8 @@ void dispc_enable_fifohandcheck(bool enable) } -void dispc_set_lcd_display_type(enum omap_lcd_display_type type) +void dispc_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type) { int mode; @@ -1994,7 +1995,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) } -void dispc_set_tft_data_lines(u8 data_lines) +void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -2021,7 +2022,8 @@ void dispc_set_tft_data_lines(u8 data_lines) enable_clocks(0); } -void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) +void dispc_set_parallel_interface_mode(enum omap_channel channel, + enum omap_parallel_interface_mode mode) { u32 l; int stallmode; @@ -2054,9 +2056,11 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) l = dispc_read_reg(DISPC_CONTROL); l = FLD_MOD(l, stallmode, 11, 11); - l = FLD_MOD(l, gpout0, 15, 15); - l = FLD_MOD(l, gpout1, 16, 16); + if (channel == OMAP_DSS_CHANNEL_LCD) { + l = FLD_MOD(l, gpout0, 15, 15); + l = FLD_MOD(l, gpout1, 16, 16); + } dispc_write_reg(DISPC_CONTROL, l); enable_clocks(0); @@ -2093,8 +2097,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings) timings->vfp, timings->vbp); } -static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, - int vsw, int vfp, int vbp) +static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, + int hfp, int hbp, int vsw, int vfp, int vbp) { u32 timing_h, timing_v; @@ -2113,13 +2117,14 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, } enable_clocks(1); - dispc_write_reg(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD), timing_h); - dispc_write_reg(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD), timing_v); + dispc_write_reg(DISPC_TIMING_H(channel), timing_h); + dispc_write_reg(DISPC_TIMING_V(channel), timing_v); enable_clocks(0); } /* change name to mode? */ -void dispc_set_lcd_timings(struct omap_video_timings *timings) +void dispc_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings) { unsigned xtot, ytot; unsigned long ht, vt; @@ -2129,10 +2134,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) timings->vfp, timings->vbp)) BUG(); - _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp, - timings->vsw, timings->vfp, timings->vbp); + _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp, + timings->hbp, timings->vsw, timings->vfp, + timings->vbp); - dispc_set_lcd_size(timings->x_res, timings->y_res); + dispc_set_lcd_size(channel, timings->x_res, timings->y_res); xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp; ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 960e977a8bf0..08b497f924bb 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -132,7 +132,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dispc_set_lcd_timings(t); + dispc_set_lcd_timings(dssdev->manager->id, t); err0: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -145,10 +145,12 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); - dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT : - OMAP_DSS_LCD_DISPLAY_STN); - dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + dispc_set_lcd_display_type(dssdev->manager->id, is_tft ? + OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); + dispc_set_tft_data_lines(dssdev->manager->id, + dssdev->phy.dpi.data_lines); return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index aa4f7a5fae29..acd36cad8445 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2888,7 +2888,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dss_setup_partial_planes(dssdev, x, y, w, h, enlarge_update_area); - dispc_set_lcd_size(*w, *h); + dispc_set_lcd_size(dssdev->manager->id, *w, *h); } return 0; @@ -2947,12 +2947,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) return r; } - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI); - dispc_enable_fifohandcheck(1); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_DSI); + dispc_enable_fifohandcheck(dssdev->manager->id, 1); - dispc_set_tft_data_lines(dssdev->ctrl.pixel_size); + dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); { struct omap_video_timings timings = { @@ -2964,7 +2966,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) .vbp = 0, }; - dispc_set_lcd_timings(&timings); + dispc_set_lcd_timings(dssdev->manager->id, &timings); } return 0; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 2bb515c61f4b..275e29067372 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -333,9 +333,9 @@ void dispc_disable_sidle(void); void dispc_lcd_enable_signal_polarity(bool act_high); void dispc_lcd_enable_signal(bool enable); void dispc_pck_free_enable(bool enable); -void dispc_enable_fifohandcheck(bool enable); +void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable); -void dispc_set_lcd_size(u16 width, u16 height); +void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height); void dispc_set_digit_size(u16 width, u16 height); u32 dispc_get_plane_fifo_size(enum omap_plane plane); void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high); @@ -369,9 +369,11 @@ bool dispc_is_channel_enabled(enum omap_channel channel); int dispc_enable_plane(enum omap_plane plane, bool enable); void dispc_enable_replication(enum omap_plane plane, bool enable); -void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode); -void dispc_set_tft_data_lines(u8 data_lines); -void dispc_set_lcd_display_type(enum omap_lcd_display_type type); +void dispc_set_parallel_interface_mode(enum omap_channel channel, + enum omap_parallel_interface_mode mode); +void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines); +void dispc_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type); void dispc_set_loadmode(enum omap_dss_load_mode mode); void dispc_set_default_color(enum omap_channel channel, u32 color); @@ -388,7 +390,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch); bool dispc_alpha_blending_enabled(enum omap_channel ch); bool dispc_lcd_timings_ok(struct omap_video_timings *timings); -void dispc_set_lcd_timings(struct omap_video_timings *timings); +void dispc_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); unsigned long dispc_lclk_rate(void); unsigned long dispc_pclk_rate(void); @@ -425,8 +428,8 @@ void rfbi_dump_regs(struct seq_file *s); int rfbi_configure(int rfbi_module, int bpp, int lines); void rfbi_enable_rfbi(bool enable); -void rfbi_transfer_area(u16 width, u16 height, - void (callback)(void *data), void *data); +void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, + u16 height, void (callback)(void *data), void *data); void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index bbe62464e92d..10a2ffe02882 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -301,8 +301,8 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -void rfbi_transfer_area(u16 width, u16 height, - void (callback)(void *data), void *data) +void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, + u16 height, void (*callback)(void *data), void *data) { u32 l; @@ -311,9 +311,9 @@ void rfbi_transfer_area(u16 width, u16 height, DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dispc_set_lcd_size(width, height); + dispc_set_lcd_size(dssdev->manager->id, width, height); - dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true); + dispc_enable_channel(dssdev->manager->id, true); rfbi.framedone_callback = callback; rfbi.framedone_callback_data = data; @@ -887,7 +887,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dss_setup_partial_planes(dssdev, x, y, w, h, true); - dispc_set_lcd_size(*w, *h); + dispc_set_lcd_size(dssdev->manager->id, *w, *h); } return 0; @@ -899,7 +899,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), void *data) { if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - rfbi_transfer_area(w, h, callback, data); + rfbi_transfer_area(dssdev, w, h, callback, data); } else { struct omap_overlay *ovl; void __iomem *addr; @@ -1018,11 +1018,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) goto err1; } - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_RFBI); - dispc_set_tft_data_lines(dssdev->ctrl.pixel_size); + dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); rfbi_configure(dssdev->phy.rfbi.channel, dssdev->ctrl.pixel_size, diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index ee07a3cc22ef..19443b18f3da 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -35,12 +35,16 @@ static struct { struct regulator *vdds_sdi_reg; } sdi; -static void sdi_basic_init(void) +static void sdi_basic_init(struct omap_dss_device *dssdev) + { - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_tft_data_lines(24); + dispc_set_tft_data_lines(dssdev->manager->id, 24); dispc_lcd_enable_signal_polarity(1); } @@ -68,7 +72,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) if (!sdi.skip_init) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - sdi_basic_init(); + sdi_basic_init(dssdev); /* 15.5.9.1.2 */ dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; @@ -102,7 +106,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dispc_set_lcd_timings(t); + dispc_set_lcd_timings(dssdev->manager->id, t); r = dss_set_clock_div(&dss_cinfo); if (r) -- cgit v1.2.3 From ff1b2cde3f551c9b56887b41e0ebbf2907566a7d Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Thu, 2 Dec 2010 11:27:11 +0000 Subject: OMAP: DSS2: Change remaining DISPC functions for new omap_channel argument The following dispc functions are also changed to incorporate channel as an argument: -dispc_lclk_rate() -dispc_pclk_rate() -dispc_set_pol_freq() -dispc_set_clock_div() -dispc_get_clock_div() Signed-off-by: Sumit Semwal Signed-off-by: Mukund Mittal Signed-off-by: Samreen Signed-off-by: Archit Taneja [tomi.valkeinen@nokia.com: fixed trivial compile error] Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 62 +++++++++++++++++++++++------------------ drivers/video/omap2/dss/dpi.c | 26 +++++++++-------- drivers/video/omap2/dss/dsi.c | 13 +++++---- drivers/video/omap2/dss/dss.h | 13 +++++---- drivers/video/omap2/dss/sdi.c | 8 +++--- 5 files changed, 68 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 7ca53c100419..5dfdf0ba409d 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1444,12 +1444,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, } } -static unsigned long calc_fclk_five_taps(u16 width, u16 height, - u16 out_width, u16 out_height, enum omap_color_mode color_mode) +static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, + u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode) { u32 fclk = 0; /* FIXME venc pclk? */ - u64 tmp, pclk = dispc_pclk_rate(); + u64 tmp, pclk = dispc_pclk_rate(channel); if (height > out_height) { /* FIXME get real display PPL */ @@ -1481,8 +1482,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height, return fclk; } -static unsigned long calc_fclk(u16 width, u16 height, - u16 out_width, u16 out_height) +static unsigned long calc_fclk(enum omap_channel channel, u16 width, + u16 height, u16 out_width, u16 out_height) { unsigned int hf, vf; @@ -1506,7 +1507,7 @@ static unsigned long calc_fclk(u16 width, u16 height, vf = 1; /* FIXME venc pclk? */ - return dispc_pclk_rate() * vf * hf; + return dispc_pclk_rate(channel) * vf * hf; } void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) @@ -1582,7 +1583,7 @@ static int _dispc_setup_plane(enum omap_plane plane, five_taps = height > out_height * 2; if (!five_taps) { - fclk = calc_fclk(width, height, + fclk = calc_fclk(OMAP_DSS_CHANNEL_LCD, width, height, out_width, out_height); /* Try 5-tap filter if 3-tap fclk is too high */ @@ -1597,8 +1598,9 @@ static int _dispc_setup_plane(enum omap_plane plane, } if (five_taps) - fclk = calc_fclk_five_taps(width, height, - out_width, out_height, color_mode); + fclk = calc_fclk_five_taps(OMAP_DSS_CHANNEL_LCD, width, + height, out_width, out_height, + color_mode); DSSDBG("required fclk rate = %lu Hz\n", fclk); DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); @@ -2155,13 +2157,14 @@ void dispc_set_lcd_timings(enum omap_channel channel, DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); } -static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div) +static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, + u16 pck_div) { BUG_ON(lck_div < 1); BUG_ON(pck_div < 2); enable_clocks(1); - dispc_write_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD), + dispc_write_reg(DISPC_DIVISOR(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); enable_clocks(0); } @@ -2189,13 +2192,13 @@ unsigned long dispc_fclk_rate(void) return r; } -unsigned long dispc_lclk_rate(void) +unsigned long dispc_lclk_rate(enum omap_channel channel) { int lcd; unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD)); + l = dispc_read_reg(DISPC_DIVISOR(channel)); lcd = FLD_GET(l, 23, 16); @@ -2204,13 +2207,13 @@ unsigned long dispc_lclk_rate(void) return r / lcd; } -unsigned long dispc_pclk_rate(void) +unsigned long dispc_pclk_rate(enum omap_channel channel) { int lcd, pcd; unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD)); + l = dispc_read_reg(DISPC_DIVISOR(channel)); lcd = FLD_GET(l, 23, 16); pcd = FLD_GET(l, 7, 0); @@ -2235,8 +2238,10 @@ void dispc_dump_clocks(struct seq_file *s) "dss1_alwon_fclk" : "dsi1_pll_fclk"); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); - seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd); - seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd); + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); + seq_printf(s, "pck\t\t%-16lupck div\t%u\n", + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); enable_clocks(0); } @@ -2428,8 +2433,8 @@ void dispc_dump_regs(struct seq_file *s) #undef DUMPREG } -static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, - bool ihs, bool ivs, u8 acbi, u8 acb) +static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, + bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb) { u32 l = 0; @@ -2446,13 +2451,14 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, l |= FLD_VAL(acb, 7, 0); enable_clocks(1); - dispc_write_reg(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD), l); + dispc_write_reg(DISPC_POL_FREQ(channel), l); enable_clocks(0); } -void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb) +void dispc_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb) { - _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0, + _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, (config & OMAP_DSS_LCD_RF) != 0, (config & OMAP_DSS_LCD_IEO) != 0, (config & OMAP_DSS_LCD_IPC) != 0, @@ -2521,24 +2527,26 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } -int dispc_set_clock_div(struct dispc_clock_info *cinfo) +int dispc_set_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo) { DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); - dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div); + dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); return 0; } -int dispc_get_clock_div(struct dispc_clock_info *cinfo) +int dispc_get_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo) { unsigned long fck; fck = dispc_fclk_rate(); - cinfo->lck_div = REG_GET(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD), 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD), 7, 0); + cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16); + cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 08b497f924bb..8c61e87629b3 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -40,8 +40,9 @@ static struct { } dpi; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL -static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { struct dsi_clock_info dsi_cinfo; struct dispc_clock_info dispc_cinfo; @@ -58,7 +59,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -69,8 +70,9 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, return 0; } #else -static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; @@ -84,7 +86,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req, if (r) return r; - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -107,17 +109,17 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, - dssdev->panel.acb); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dssdev->panel.acbi, dssdev->panel.acb); is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000, - &fck, &lck_div, &pck_div); + r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, + &lck_div, &pck_div); #else - r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000, - &fck, &lck_div, &pck_div); + r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, + &lck_div, &pck_div); #endif if (r) goto err0; diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index acd36cad8445..ddf3a0560822 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -792,7 +792,8 @@ static int dsi_pll_power(enum dsi_pll_power_state state) } /* calculate clock rates using dividers in cinfo */ -static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo) +static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, + struct dsi_clock_info *cinfo) { if (cinfo->regn == 0 || cinfo->regn > REGN_MAX) return -EINVAL; @@ -812,7 +813,7 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo) * with DSS2_FCK source also */ cinfo->highfreq = 0; } else { - cinfo->clkin = dispc_pclk_rate(); + cinfo->clkin = dispc_pclk_rate(dssdev->manager->id); if (cinfo->clkin < 32000000) cinfo->highfreq = 0; @@ -1206,8 +1207,8 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "VP_CLK\t\t%lu\n" "VP_PCLK\t\t%lu\n", - dispc_lclk_rate(), - dispc_pclk_rate()); + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD)); enable_clocks(0); } @@ -2989,7 +2990,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) cinfo.regm = dssdev->phy.dsi.div.regm; cinfo.regm3 = dssdev->phy.dsi.div.regm3; cinfo.regm4 = dssdev->phy.dsi.div.regm4; - r = dsi_calc_clock_rates(&cinfo); + r = dsi_calc_clock_rates(dssdev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); return r; @@ -3021,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) return r; } - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) { DSSERR("Failed to set dispc clocks\n"); return r; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 275e29067372..3fcb8ab781af 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -393,15 +393,18 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings); void dispc_set_lcd_timings(enum omap_channel channel, struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); -unsigned long dispc_lclk_rate(void); -unsigned long dispc_pclk_rate(void); -void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb); +unsigned long dispc_lclk_rate(enum omap_channel channel); +unsigned long dispc_pclk_rate(enum omap_channel channel); +void dispc_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb); void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, struct dispc_clock_info *cinfo); int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo); -int dispc_set_clock_div(struct dispc_clock_info *cinfo); -int dispc_get_clock_div(struct dispc_clock_info *cinfo); +int dispc_set_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo); +int dispc_get_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo); /* VENC */ diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 19443b18f3da..b64adf7dfc88 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -77,15 +77,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) /* 15.5.9.1.2 */ dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; - dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, - dssdev->panel.acb); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dssdev->panel.acbi, dssdev->panel.acb); if (!sdi.skip_init) { r = dss_calc_clock_div(1, t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); } else { r = dss_get_clock_div(&dss_cinfo); - r = dispc_get_clock_div(&dispc_cinfo); + r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo); } if (r) @@ -112,7 +112,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) if (r) goto err2; - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) goto err2; -- cgit v1.2.3 From 2a205f34b8fb2b86887b177befa7b42efd7a60b9 Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Thu, 2 Dec 2010 11:27:12 +0000 Subject: OMAP: DSS2: LCD2 Channel Changes for DISPC DISPC functions are modified in order to work when the manager is LCD2. This includes: Adding new IRQs specific to LCD2 and their handling. Provide dumps of the new manager's registers. Provide dumps of the new manager's clocks. Checks for channel for registers DISPC_CONTROL2 and DISPC_CONFIG2 which can't be parametrized. Signed-off-by: Sumit Semwal Signed-off-by: Mukund Mittal Signed-off-by: Samreen Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- arch/arm/plat-omap/include/plat/display.h | 4 + drivers/video/omap2/dss/dispc.c | 281 +++++++++++++++++++++++++----- drivers/video/omap2/dss/dpi.c | 2 +- 3 files changed, 247 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 586944d8e9e8..0180f25d1c8b 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -42,6 +42,10 @@ #define DISPC_IRQ_SYNC_LOST (1 << 14) #define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15) #define DISPC_IRQ_WAKEUP (1 << 16) +#define DISPC_IRQ_SYNC_LOST2 (1 << 17) +#define DISPC_IRQ_VSYNC2 (1 << 18) +#define DISPC_IRQ_ACBIAS_COUNT_STAT2 (1 << 21) +#define DISPC_IRQ_FRAMEDONE2 (1 << 22) struct omap_dss_device; struct omap_overlay_manager; diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5dfdf0ba409d..fe41d891fd42 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -234,6 +234,17 @@ void dispc_save_context(void) SR(GLOBAL_ALPHA); SR(SIZE_DIG); SR(SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + SR(CONTROL2); + SR(DEFAULT_COLOR(2)); + SR(TRANS_COLOR(2)); + SR(SIZE_LCD(2)); + SR(TIMING_H(2)); + SR(TIMING_V(2)); + SR(POL_FREQ(2)); + SR(DIVISOR(2)); + SR(CONFIG2); + } SR(GFX_BA0); SR(GFX_BA1); @@ -253,6 +264,15 @@ void dispc_save_context(void) SR(CPR_COEF_R(0)); SR(CPR_COEF_G(0)); SR(CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + SR(CPR_COEF_B(2)); + SR(CPR_COEF_G(2)); + SR(CPR_COEF_R(2)); + + SR(DATA_CYCLE1(2)); + SR(DATA_CYCLE2(2)); + SR(DATA_CYCLE3(2)); + } SR(GFX_PRELOAD); @@ -373,6 +393,16 @@ void dispc_restore_context(void) RR(GLOBAL_ALPHA); RR(SIZE_DIG); RR(SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + RR(DEFAULT_COLOR(2)); + RR(TRANS_COLOR(2)); + RR(SIZE_LCD(2)); + RR(TIMING_H(2)); + RR(TIMING_V(2)); + RR(POL_FREQ(2)); + RR(DIVISOR(2)); + RR(CONFIG2); + } RR(GFX_BA0); RR(GFX_BA1); @@ -392,6 +422,15 @@ void dispc_restore_context(void) RR(CPR_COEF_R(0)); RR(CPR_COEF_G(0)); RR(CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + RR(DATA_CYCLE1(2)); + RR(DATA_CYCLE2(2)); + RR(DATA_CYCLE3(2)); + + RR(CPR_COEF_B(2)); + RR(CPR_COEF_G(2)); + RR(CPR_COEF_R(2)); + } RR(GFX_PRELOAD); @@ -495,7 +534,8 @@ void dispc_restore_context(void) /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); - + if (dss_has_feature(FEAT_MGR_LCD2)) + RR(CONTROL2); /* clear spurious SYNC_LOST_DIGIT interrupts */ dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); @@ -521,42 +561,63 @@ bool dispc_go_busy(enum omap_channel channel) { int bit; - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ - return REG_GET(DISPC_CONTROL, bit, bit) == 1; + if (channel == OMAP_DSS_CHANNEL_LCD2) + return REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + return REG_GET(DISPC_CONTROL, bit, bit) == 1; } void dispc_go(enum omap_channel channel) { int bit; + bool enable_bit, go_bit; enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 0; /* LCDENABLE */ else bit = 1; /* DIGITALENABLE */ /* if the channel is not enabled, we don't need GO */ - if (REG_GET(DISPC_CONTROL, bit, bit) == 0) + if (channel == OMAP_DSS_CHANNEL_LCD2) + enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; + + if (!enable_bit) goto end; - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ - if (REG_GET(DISPC_CONTROL, bit, bit) == 1) { + if (channel == OMAP_DSS_CHANNEL_LCD2) + go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; + + if (go_bit) { DSSERR("GO bit not down for channel %d\n", channel); goto end; } - DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT"); + DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : + (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT")); - REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); + else + REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); end: enable_clocks(0); } @@ -869,6 +930,7 @@ static void _dispc_set_channel_out(enum omap_plane plane, { int shift; u32 val; + int chan = 0, chan2 = 0; switch (plane) { case OMAP_DSS_GFX: @@ -884,7 +946,29 @@ static void _dispc_set_channel_out(enum omap_plane plane, } val = dispc_read_reg(dispc_reg_att[plane]); - val = FLD_MOD(val, channel, shift, shift); + if (dss_has_feature(FEAT_MGR_LCD2)) { + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + chan = 0; + chan2 = 0; + break; + case OMAP_DSS_CHANNEL_DIGIT: + chan = 1; + chan2 = 0; + break; + case OMAP_DSS_CHANNEL_LCD2: + chan = 0; + chan2 = 1; + break; + default: + BUG(); + } + + val = FLD_MOD(val, chan, shift, shift); + val = FLD_MOD(val, chan2, 31, 30); + } else { + val = FLD_MOD(val, channel, shift, shift); + } dispc_write_reg(dispc_reg_att[plane], val); } @@ -1688,36 +1772,44 @@ static void dispc_disable_isr(void *data, u32 mask) complete(compl); } -static void _enable_lcd_out(bool enable) +static void _enable_lcd_out(enum omap_channel channel, bool enable) { - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); + else + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } -static void dispc_enable_lcd_out(bool enable) +static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) { struct completion frame_done_completion; bool is_on; int r; + u32 irq; enable_clocks(1); /* When we disable LCD output, we need to wait until frame is done. * Otherwise the DSS is still working, and turning off the clocks * prevents DSS from going to OFF mode */ - is_on = REG_GET(DISPC_CONTROL, 0, 0); + is_on = channel == OMAP_DSS_CHANNEL_LCD2 ? + REG_GET(DISPC_CONTROL2, 0, 0) : + REG_GET(DISPC_CONTROL, 0, 0); + + irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : + DISPC_IRQ_FRAMEDONE; if (!enable && is_on) { init_completion(&frame_done_completion); r = omap_dispc_register_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_FRAMEDONE); + &frame_done_completion, irq); if (r) DSSERR("failed to register FRAMEDONE isr\n"); } - _enable_lcd_out(enable); + _enable_lcd_out(channel, enable); if (!enable && is_on) { if (!wait_for_completion_timeout(&frame_done_completion, @@ -1725,8 +1817,7 @@ static void dispc_enable_lcd_out(bool enable) DSSERR("timeout waiting for FRAME DONE\n"); r = omap_dispc_unregister_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_FRAMEDONE); + &frame_done_completion, irq); if (r) DSSERR("failed to unregister FRAMEDONE isr\n"); @@ -1796,6 +1887,8 @@ static void dispc_enable_digit_out(bool enable) unsigned long flags; spin_lock_irqsave(&dispc.irq_lock, flags); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); @@ -1810,14 +1903,17 @@ bool dispc_is_channel_enabled(enum omap_channel channel) return !!REG_GET(DISPC_CONTROL, 0, 0); else if (channel == OMAP_DSS_CHANNEL_DIGIT) return !!REG_GET(DISPC_CONTROL, 1, 1); + else if (channel == OMAP_DSS_CHANNEL_LCD2) + return !!REG_GET(DISPC_CONTROL2, 0, 0); else BUG(); } void dispc_enable_channel(enum omap_channel channel, bool enable) { - if (channel == OMAP_DSS_CHANNEL_LCD) - dispc_enable_lcd_out(enable); + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) + dispc_enable_lcd_out(channel, enable); else if (channel == OMAP_DSS_CHANNEL_DIGIT) dispc_enable_digit_out(enable); else @@ -1848,7 +1944,10 @@ void dispc_pck_free_enable(bool enable) void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { enable_clocks(1); - REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); + else + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); enable_clocks(0); } @@ -1873,7 +1972,10 @@ void dispc_set_lcd_display_type(enum omap_channel channel, } enable_clocks(1); - REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); + else + REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); enable_clocks(0); } @@ -1897,7 +1999,8 @@ u32 dispc_get_default_color(enum omap_channel channel) u32 l; BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && - channel != OMAP_DSS_CHANNEL_LCD); + channel != OMAP_DSS_CHANNEL_LCD && + channel != OMAP_DSS_CHANNEL_LCD2); enable_clocks(1); l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); @@ -1913,8 +2016,10 @@ void dispc_set_trans_key(enum omap_channel ch, enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); enable_clocks(0); @@ -1930,6 +2035,8 @@ void dispc_get_trans_key(enum omap_channel ch, *type = REG_GET(DISPC_CONFIG, 11, 11); else if (ch == OMAP_DSS_CHANNEL_DIGIT) *type = REG_GET(DISPC_CONFIG, 13, 13); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + *type = REG_GET(DISPC_CONFIG2, 11, 11); else BUG(); } @@ -1944,8 +2051,10 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable) enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); enable_clocks(0); } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) @@ -1956,8 +2065,10 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); enable_clocks(0); } bool dispc_alpha_blending_enabled(enum omap_channel ch) @@ -1972,6 +2083,8 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG, 18, 18); else if (ch == OMAP_DSS_CHANNEL_DIGIT) enabled = REG_GET(DISPC_CONFIG, 19, 19); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); enable_clocks(0); @@ -1989,6 +2102,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch) enabled = REG_GET(DISPC_CONFIG, 10, 10); else if (ch == OMAP_DSS_CHANNEL_DIGIT) enabled = REG_GET(DISPC_CONFIG, 12, 12); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + enabled = REG_GET(DISPC_CONFIG2, 10, 10); else BUG(); enable_clocks(0); @@ -2020,7 +2135,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) } enable_clocks(1); - REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); + else + REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); enable_clocks(0); } @@ -2055,15 +2173,17 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, enable_clocks(1); - l = dispc_read_reg(DISPC_CONTROL); - - l = FLD_MOD(l, stallmode, 11, 11); - - if (channel == OMAP_DSS_CHANNEL_LCD) { + if (channel == OMAP_DSS_CHANNEL_LCD2) { + l = dispc_read_reg(DISPC_CONTROL2); + l = FLD_MOD(l, stallmode, 11, 11); + dispc_write_reg(DISPC_CONTROL2, l); + } else { + l = dispc_read_reg(DISPC_CONTROL); + l = FLD_MOD(l, stallmode, 11, 11); l = FLD_MOD(l, gpout0, 15, 15); l = FLD_MOD(l, gpout1, 16, 16); + dispc_write_reg(DISPC_CONTROL, l); } - dispc_write_reg(DISPC_CONTROL, l); enable_clocks(0); } @@ -2148,7 +2268,8 @@ void dispc_set_lcd_timings(enum omap_channel channel, ht = (timings->pixel_clock * 1000) / xtot; vt = (timings->pixel_clock * 1000) / xtot / ytot; - DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res); + DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res, + timings->y_res); DSSDBG("pck %u\n", timings->pixel_clock); DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", timings->hsw, timings->hfp, timings->hbp, @@ -2169,10 +2290,11 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, enable_clocks(0); } -static void dispc_get_lcd_divisor(int *lck_div, int *pck_div) +static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, + int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISOR(OMAP_DSS_CHANNEL_LCD)); + l = dispc_read_reg(DISPC_DIVISOR(channel)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } @@ -2229,8 +2351,6 @@ void dispc_dump_clocks(struct seq_file *s) enable_clocks(1); - dispc_get_lcd_divisor(&lcd, &pcd); - seq_printf(s, "- DISPC -\n"); seq_printf(s, "dispc fclk source = %s\n", @@ -2238,11 +2358,25 @@ void dispc_dump_clocks(struct seq_file *s) "dss1_alwon_fclk" : "dsi1_pll_fclk"); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); + + seq_printf(s, "- LCD1 -\n"); + + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); + if (dss_has_feature(FEAT_MGR_LCD2)) { + seq_printf(s, "- LCD2 -\n"); + + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd); + seq_printf(s, "pck\t\t%-16lupck div\t%u\n", + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); + } enable_clocks(0); } @@ -2284,6 +2418,12 @@ void dispc_dump_irqs(struct seq_file *s) PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); PIS(WAKEUP); + if (dss_has_feature(FEAT_MGR_LCD2)) { + PIS(FRAMEDONE2); + PIS(VSYNC2); + PIS(ACBIAS_COUNT_STAT2); + PIS(SYNC_LOST2); + } #undef PIS } #endif @@ -2315,6 +2455,17 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_DIG); DUMPREG(DISPC_SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + DUMPREG(DISPC_CONTROL2); + DUMPREG(DISPC_CONFIG2); + DUMPREG(DISPC_DEFAULT_COLOR(2)); + DUMPREG(DISPC_TRANS_COLOR(2)); + DUMPREG(DISPC_TIMING_H(2)); + DUMPREG(DISPC_TIMING_V(2)); + DUMPREG(DISPC_POL_FREQ(2)); + DUMPREG(DISPC_DIVISOR(2)); + DUMPREG(DISPC_SIZE_LCD(2)); + } DUMPREG(DISPC_GFX_BA0); DUMPREG(DISPC_GFX_BA1); @@ -2335,6 +2486,15 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_CPR_COEF_R(0)); DUMPREG(DISPC_CPR_COEF_G(0)); DUMPREG(DISPC_CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + DUMPREG(DISPC_DATA_CYCLE1(2)); + DUMPREG(DISPC_DATA_CYCLE2(2)); + DUMPREG(DISPC_DATA_CYCLE3(2)); + + DUMPREG(DISPC_CPR_COEF_R(2)); + DUMPREG(DISPC_CPR_COEF_G(2)); + DUMPREG(DISPC_CPR_COEF_B(2)); + } DUMPREG(DISPC_GFX_PRELOAD); @@ -2686,6 +2846,8 @@ static void print_irq_status(u32 status) PIS(VID2_FIFO_UNDERFLOW); PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); + if (dss_has_feature(FEAT_MGR_LCD2)) + PIS(SYNC_LOST2); #undef PIS printk("\n"); @@ -2904,6 +3066,45 @@ static void dispc_error_worker(struct work_struct *work) } } + if (errors & DISPC_IRQ_SYNC_LOST2) { + struct omap_overlay_manager *manager = NULL; + bool enable = false; + + DSSERR("SYNC_LOST for LCD2, disabling LCD2\n"); + + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + struct omap_overlay_manager *mgr; + mgr = omap_dss_get_overlay_manager(i); + + if (mgr->id == OMAP_DSS_CHANNEL_LCD2) { + manager = mgr; + enable = mgr->device->state == + OMAP_DSS_DISPLAY_ACTIVE; + mgr->device->driver->disable(mgr->device); + break; + } + } + + if (manager) { + struct omap_dss_device *dssdev = manager->device; + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl; + ovl = omap_dss_get_overlay(i); + + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) + continue; + + if (ovl->id != 0 && ovl->manager == manager) + dispc_enable_plane(ovl->id, 0); + } + + dispc_go(manager->id); + mdelay(50); + if (enable) + dssdev->driver->enable(dssdev); + } + } + if (errors & DISPC_IRQ_OCP_ERR) { DSSERR("OCP_ERR\n"); for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { @@ -3011,6 +3212,8 @@ static void _omap_dispc_initialize_irq(void) memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, * so clear it */ diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 8c61e87629b3..75fb0a515430 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -238,7 +238,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev, dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { dpi_set_mode(dssdev); - dispc_go(OMAP_DSS_CHANNEL_LCD); + dispc_go(dssdev->manager->id); } } EXPORT_SYMBOL(dpi_set_timings); -- cgit v1.2.3 From 6ced40bfc01f016de89b65d9c733c1fb5eeb06d0 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 2 Dec 2010 11:27:13 +0000 Subject: OMAP: DSS2: Use dss_features to handle DISPC bits removed on OMAP4 DISPC_CONFIG bits LCDENABLEPOL, LCDENABLESIGNAL, PCKFREEENABLE and FUNCGATED have been removed from OMAP4, use dss_features to handle them correctly. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index fe41d891fd42..6171bcc589f8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1922,6 +1922,9 @@ void dispc_enable_channel(enum omap_channel channel, bool enable) void dispc_lcd_enable_signal_polarity(bool act_high) { + if (!dss_has_feature(FEAT_LCDENABLEPOL)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); enable_clocks(0); @@ -1929,6 +1932,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high) void dispc_lcd_enable_signal(bool enable) { + if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); enable_clocks(0); @@ -1936,6 +1942,9 @@ void dispc_lcd_enable_signal(bool enable) void dispc_pck_free_enable(bool enable) { + if (!dss_has_feature(FEAT_PCKFREEENABLE)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); enable_clocks(0); @@ -3246,7 +3255,8 @@ static void _omap_dispc_initial_config(void) dispc_write_reg(DISPC_SYSCONFIG, l); /* FUNCGATED */ - REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); + if (dss_has_feature(FEAT_FUNCGATED)) + REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); /* L3 firewall setting: enable access to OCM RAM */ /* XXX this should be somewhere in plat-omap */ -- cgit v1.2.3 From 18faa1b68a54ff976dd03bfd9ace2c4ef4f7315c Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Thu, 2 Dec 2010 11:27:14 +0000 Subject: OMAP: DSS2: Introduce omap_channel as an omap_dss_device parameter, add new overlay manager. A panel connects to one of the overlay managers of DSS through some interface block. On OMAP4, specifying the type of the display is not sufficient to conclude which manager the panel should be connected to. Hence, a new member 'channel' is introduced in omap_dss_device structure to determine which manager the panel uses. The dss_recheck_connections() called in dss_driver_probe() uses this channel parameter to set the correct manager to the corresponding omap_dss_device. The channel parameter is used only once to ensure the correct managers are set for each panel. The parameter dssdev->manager->id will take care of ensuring that the panel and then the interface driver configures the correct DISPC channel. Also, add a new Overlay Manager in manager.c, make other changes needed for LCD2 channel. Signed-off-by: Sumit Semwal Signed-off-by: Mukund Mittal Signed-off-by: Samreen Signed-off-by: Tomi Valkeinen --- arch/arm/plat-omap/include/plat/display.h | 2 + drivers/video/omap2/dss/dispc.c | 21 ++++----- drivers/video/omap2/dss/dss.h | 4 +- drivers/video/omap2/dss/manager.c | 77 +++++++++++++++++++------------ drivers/video/omap2/dss/overlay.c | 14 +++++- 5 files changed, 74 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 0180f25d1c8b..537f4e449f50 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h @@ -358,6 +358,8 @@ struct omap_dss_device { enum omap_display_type type; + enum omap_channel channel; + union { struct { u8 data_lines; diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 6171bcc589f8..9f8c69f16e61 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1610,8 +1610,8 @@ static int _dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, int mirror, - u8 global_alpha, - u8 pre_mult_alpha) + u8 global_alpha, u8 pre_mult_alpha, + enum omap_channel channel) { const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; bool five_taps = 0; @@ -1667,8 +1667,8 @@ static int _dispc_setup_plane(enum omap_plane plane, five_taps = height > out_height * 2; if (!five_taps) { - fclk = calc_fclk(OMAP_DSS_CHANNEL_LCD, width, height, - out_width, out_height); + fclk = calc_fclk(channel, width, height, out_width, + out_height); /* Try 5-tap filter if 3-tap fclk is too high */ if (cpu_is_omap34xx() && height > out_height && @@ -1682,9 +1682,8 @@ static int _dispc_setup_plane(enum omap_plane plane, } if (five_taps) - fclk = calc_fclk_five_taps(OMAP_DSS_CHANNEL_LCD, width, - height, out_width, out_height, - color_mode); + fclk = calc_fclk_five_taps(channel, width, height, + out_width, out_height, color_mode); DSSDBG("required fclk rate = %lu Hz\n", fclk); DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); @@ -3331,17 +3330,17 @@ int dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, bool mirror, u8 global_alpha, - u8 pre_mult_alpha) + u8 pre_mult_alpha, enum omap_channel channel) { int r = 0; DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n", + "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", plane, paddr, screen_width, pos_x, pos_y, width, height, out_width, out_height, ilace, color_mode, - rotation, mirror); + rotation, mirror, channel); enable_clocks(1); @@ -3354,7 +3353,7 @@ int dispc_setup_plane(enum omap_plane plane, rotation_type, rotation, mirror, global_alpha, - pre_mult_alpha); + pre_mult_alpha, channel); enable_clocks(0); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 3fcb8ab781af..b394951120ac 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -359,8 +359,8 @@ int dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, bool mirror, - u8 global_alpha, - u8 pre_mult_alpha); + u8 global_alpha, u8 pre_mult_alpha, + enum omap_channel channel); bool dispc_go_busy(enum omap_channel channel); void dispc_go(enum omap_channel channel); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 873b33469060..172d4e697309 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -513,11 +513,14 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) unsigned long timeout = msecs_to_jiffies(500); u32 irq; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD; - else - irq = DISPC_IRQ_VSYNC; - + } else { + if (mgr->id == OMAP_DSS_CHANNEL_LCD) + irq = DISPC_IRQ_VSYNC; + else + irq = DISPC_IRQ_VSYNC2; + } return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } @@ -525,7 +528,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); struct manager_cache_data *mc; - enum omap_channel channel; u32 irq; int r; int i; @@ -536,7 +538,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; @@ -544,11 +545,14 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (mode != OMAP_DSS_UPDATE_AUTO) return 0; - irq = DISPC_IRQ_FRAMEDONE; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; } else { - irq = DISPC_IRQ_VSYNC; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; } - channel = OMAP_DSS_CHANNEL_LCD; } mc = &dss_cache.manager_cache[mgr->id]; @@ -595,7 +599,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); - enum omap_channel channel; struct overlay_cache_data *oc; struct omap_dss_device *dssdev; u32 irq; @@ -612,7 +615,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; @@ -620,11 +622,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (mode != OMAP_DSS_UPDATE_AUTO) return 0; - irq = DISPC_IRQ_FRAMEDONE; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; } else { - irq = DISPC_IRQ_VSYNC; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; } - channel = OMAP_DSS_CHANNEL_LCD; } oc = &dss_cache.overlay_cache[ovl->id]; @@ -844,7 +849,8 @@ static int configure_overlay(enum omap_plane plane) c->rotation, c->mirror, c->global_alpha, - c->pre_mult_alpha); + c->pre_mult_alpha, + c->channel); if (r) { /* this shouldn't happen */ @@ -896,10 +902,10 @@ static int configure_dispc(void) r = 0; busy = false; - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); - mgr_go[0] = false; - mgr_go[1] = false; + for (i = 0; i < num_mgrs; i++) { + mgr_busy[i] = dispc_go_busy(i); + mgr_go[i] = false; + } /* Commit overlay settings */ for (i = 0; i < num_ovls; ++i) { @@ -1158,9 +1164,10 @@ static void dss_apply_irq_handler(void *data, u32 mask) const int num_mgrs = dss_feat_get_num_mgrs(); int i, r; bool mgr_busy[MAX_DSS_MANAGERS]; + u32 irq_mask; - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); + for (i = 0; i < num_mgrs; i++) + mgr_busy[i] = dispc_go_busy(i); spin_lock(&dss_cache.lock); @@ -1181,8 +1188,8 @@ static void dss_apply_irq_handler(void *data, u32 mask) goto end; /* re-read busy flags */ - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); + for (i = 0; i < num_mgrs; i++) + mgr_busy[i] = dispc_go_busy(i); /* keep running as long as there are busy managers, so that * we can collect overlay-applied information */ @@ -1191,9 +1198,12 @@ static void dss_apply_irq_handler(void *data, u32 mask) goto end; } - omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, - DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN); + irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | + DISPC_IRQ_EVSYNC_EVEN; + if (dss_has_feature(FEAT_MGR_LCD2)) + irq_mask |= DISPC_IRQ_VSYNC2; + + omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); dss_cache.irq_enabled = false; end: @@ -1386,9 +1396,14 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) r = 0; dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); if (!dss_cache.irq_enabled) { - r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, - DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN); + u32 mask; + + mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | + DISPC_IRQ_EVSYNC_EVEN; + if (dss_has_feature(FEAT_MGR_LCD2)) + mask |= DISPC_IRQ_VSYNC2; + + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); dss_cache.irq_enabled = true; } configure_dispc(); @@ -1480,6 +1495,10 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->name = "tv"; mgr->id = OMAP_DSS_CHANNEL_DIGIT; break; + case 2: + mgr->name = "lcd2"; + mgr->id = OMAP_DSS_CHANNEL_LCD2; + break; } mgr->set_device = &omap_dss_set_device; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 41a29024a8d0..456efef03c20 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -664,12 +664,22 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) int i; struct omap_overlay_manager *lcd_mgr; struct omap_overlay_manager *tv_mgr; + struct omap_overlay_manager *lcd2_mgr = NULL; struct omap_overlay_manager *mgr = NULL; lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD); tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); - - if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { + if (dss_has_feature(FEAT_MGR_LCD2)) + lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2); + + if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { + if (!lcd2_mgr->device || force) { + if (lcd2_mgr->device) + lcd2_mgr->unset_device(lcd2_mgr); + lcd2_mgr->set_device(lcd2_mgr, dssdev); + mgr = lcd2_mgr; + } + } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { if (!lcd_mgr->device || force) { if (lcd_mgr->device) lcd_mgr->unset_device(lcd_mgr); -- cgit v1.2.3 From 709465d6ea0466454ef547e7d1065db2b23033a9 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 28 Oct 2010 15:43:50 -0400 Subject: net/irda: bfin_sir: pull in serial headers for defines We're in the process of cleaning up the global Blackfin namespace, so the bfin_sir driver needs to pull in the serial header explicitly now. This does add a little transitional cruft to keep things compiling, but a follow up patch in this series will cull that. Signed-off-by: Mike Frysinger --- drivers/net/irda/bfin_sir.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h index b54a6f08db45..1d33564029a4 100644 --- a/drivers/net/irda/bfin_sir.h +++ b/drivers/net/irda/bfin_sir.h @@ -26,6 +26,11 @@ #include #include #include +/* Some transitional glue */ +#include +#include +#include +#undef DRIVER_NAME #ifdef CONFIG_SIR_BFIN_DMA struct dma_rx_buf { -- cgit v1.2.3 From 21aa8ec362b59458bea1144494ae53ca2d8b13ed Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 10 Jan 2011 02:45:57 -0500 Subject: net/irda: bfin_sir: back out transitional defines Now that the common header is sane, we can drop the transitional cruft. Signed-off-by: Mike Frysinger --- drivers/net/irda/bfin_sir.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h index 1d33564029a4..e3b285a67734 100644 --- a/drivers/net/irda/bfin_sir.h +++ b/drivers/net/irda/bfin_sir.h @@ -26,9 +26,6 @@ #include #include #include -/* Some transitional glue */ -#include -#include #include #undef DRIVER_NAME -- cgit v1.2.3 From 57afb399350b45c0067f4979ce9f0c754239b048 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 9 Sep 2009 10:46:19 +0000 Subject: serial: bfin_5xx: move resources into board files Rather than maintain Kconfig entries where people have to enter raw numbers and hardcode lists of addresses/pins in the driver itself, push it all to platform resources. This lets us simplify the driver, the Kconfig, and gives board porters greater flexibility. In the process, we need to also start supporting the early platform interface. Not a big deal, but it causes the patch to be bigger than a simple resource relocation. All the Blackfin boards already have their resources updated and in place for this change. Signed-off-by: Sonic Zhang Acked-by: Greg Kroah-Hartman Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/bfin_serial.h | 12 + drivers/serial/Kconfig | 70 +--- drivers/serial/bfin_5xx.c | 638 +++++++++++++++++++------------- 3 files changed, 400 insertions(+), 320 deletions(-) (limited to 'drivers') diff --git a/arch/blackfin/include/asm/bfin_serial.h b/arch/blackfin/include/asm/bfin_serial.h index e9510eab5e22..1ff9f1468c02 100644 --- a/arch/blackfin/include/asm/bfin_serial.h +++ b/arch/blackfin/include/asm/bfin_serial.h @@ -13,6 +13,17 @@ #include #include +#if defined(CONFIG_BFIN_UART0_CTSRTS) || \ + defined(CONFIG_BFIN_UART1_CTSRTS) || \ + defined(CONFIG_BFIN_UART2_CTSRTS) || \ + defined(CONFIG_BFIN_UART3_CTSRTS) +# ifdef BFIN_UART_BF54X_STYLE +# define CONFIG_SERIAL_BFIN_HARD_CTSRTS +# else +# define CONFIG_SERIAL_BFIN_CTSRTS +# endif +#endif + struct circ_buf; struct timer_list; struct work_struct; @@ -203,6 +214,7 @@ struct bfin_uart_regs { #define UART_PUT_LSR(p, v) bfin_write16(port_membase(p) + OFFSET_LSR, v) /* This handles hard CTS/RTS */ +#define BFIN_UART_CTSRTS_HARD #define UART_CLEAR_SCTS(p) bfin_write16((port_membase(p) + OFFSET_MSR), SCTS) #define UART_GET_CTS(x) (UART_GET_MSR(x) & CTS) #define UART_DISABLE_RTS(x) UART_PUT_MCR(x, UART_GET_MCR(x) & ~(ARTS | MRTS)) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ec3c214598d0..ce39357f708b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -776,24 +776,7 @@ config BFIN_UART0_CTSRTS bool "Enable UART0 hardware flow control" depends on SERIAL_BFIN_UART0 help - Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS - signal. - -config UART0_CTS_PIN - int "UART0 CTS pin" - depends on BFIN_UART0_CTSRTS && !BF548 - default 23 - help - The default pin is GPIO_GP7. - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. - -config UART0_RTS_PIN - int "UART0 RTS pin" - depends on BFIN_UART0_CTSRTS && !BF548 - default 22 - help - The default pin is GPIO_GP6. - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. + Enable hardware flow control in the driver. config SERIAL_BFIN_UART1 bool "Enable UART1" @@ -805,22 +788,7 @@ config BFIN_UART1_CTSRTS bool "Enable UART1 hardware flow control" depends on SERIAL_BFIN_UART1 help - Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS - signal. - -config UART1_CTS_PIN - int "UART1 CTS pin" - depends on BFIN_UART1_CTSRTS && !BF548 - default -1 - help - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. - -config UART1_RTS_PIN - int "UART1 RTS pin" - depends on BFIN_UART1_CTSRTS && !BF548 - default -1 - help - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. + Enable hardware flow control in the driver. config SERIAL_BFIN_UART2 bool "Enable UART2" @@ -832,22 +800,7 @@ config BFIN_UART2_CTSRTS bool "Enable UART2 hardware flow control" depends on SERIAL_BFIN_UART2 help - Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS - signal. - -config UART2_CTS_PIN - int "UART2 CTS pin" - depends on BFIN_UART2_CTSRTS && !BF548 - default -1 - help - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. - -config UART2_RTS_PIN - int "UART2 RTS pin" - depends on BFIN_UART2_CTSRTS && !BF548 - default -1 - help - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. + Enable hardware flow control in the driver. config SERIAL_BFIN_UART3 bool "Enable UART3" @@ -859,22 +812,7 @@ config BFIN_UART3_CTSRTS bool "Enable UART3 hardware flow control" depends on SERIAL_BFIN_UART3 help - Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS - signal. - -config UART3_CTS_PIN - int "UART3 CTS pin" - depends on BFIN_UART3_CTSRTS && !BF548 - default -1 - help - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. - -config UART3_RTS_PIN - int "UART3 RTS pin" - depends on BFIN_UART3_CTSRTS && !BF548 - default -1 - help - Refer to arch/blackfin/mach-*/include/mach/gpio.h to see the GPIO map. + Enable hardware flow control in the driver. config SERIAL_IMX bool "IMX serial port support" diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 19cac9f610fd..e381b895b04d 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2008 Analog Devices Inc. + * Copyright 2006-2010 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -12,6 +12,9 @@ #define SUPPORT_SYSRQ #endif +#define DRIVER_NAME "bfin-uart" +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + #include #include #include @@ -23,21 +26,20 @@ #include #include #include -#include - -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) +#include +#include #include -#include -#endif - -#include -#include +#include +#include -#include -#include -#include +#include #include +#include + +#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase) +#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr) +#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v)) +#include #ifdef CONFIG_SERIAL_BFIN_MODULE # undef CONFIG_EARLY_PRINTK @@ -48,12 +50,11 @@ #endif /* UART name and device definitions */ -#define BFIN_SERIAL_NAME "ttyBF" +#define BFIN_SERIAL_DEV_NAME "ttyBF" #define BFIN_SERIAL_MAJOR 204 #define BFIN_SERIAL_MINOR 64 -static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; -static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); +static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS]; #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) @@ -743,14 +744,14 @@ static int bfin_serial_startup(struct uart_port *port) } } if (uart->rts_pin >= 0) { - gpio_request(uart->rts_pin, DRIVER_NAME); gpio_direction_output(uart->rts_pin, 0); } #endif #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (request_irq(uart->status_irq, + if (uart->cts_pin >= 0 && request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + uart->cts_pin = -1; pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n"); } @@ -796,11 +797,9 @@ static void bfin_serial_shutdown(struct uart_port *port) #ifdef CONFIG_SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) free_irq(gpio_to_irq(uart->cts_pin), uart); - if (uart->rts_pin >= 0) - gpio_free(uart->rts_pin); #endif #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (UART_GET_IER(uart) & EDSSI) + if (uart->cts_pin >= 0) free_irq(uart->status_irq, uart); #endif } @@ -962,33 +961,33 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) */ static void bfin_serial_set_ldisc(struct uart_port *port, int ld) { - int line = port->line; + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned short val; switch (ld) { case N_IRDA: - val = UART_GET_GCTL(&bfin_serial_ports[line]); + val = UART_GET_GCTL(uart); val |= (IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); + UART_PUT_GCTL(uart, val); break; default: - val = UART_GET_GCTL(&bfin_serial_ports[line]); + val = UART_GET_GCTL(uart); val &= ~(IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); + UART_PUT_GCTL(uart, val); } } static void bfin_serial_reset_irda(struct uart_port *port) { - int line = port->line; + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned short val; - val = UART_GET_GCTL(&bfin_serial_ports[line]); + val = UART_GET_GCTL(uart); val &= ~(IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); + UART_PUT_GCTL(uart, val); SSYNC(); val |= (IREN | RPOLC); - UART_PUT_GCTL(&bfin_serial_ports[line], val); + UART_PUT_GCTL(uart, val); SSYNC(); } @@ -1070,85 +1069,6 @@ static struct uart_ops bfin_serial_pops = { #endif }; -static void __init bfin_serial_hw_init(void) -{ -#ifdef CONFIG_SERIAL_BFIN_UART0 - peripheral_request(P_UART0_TX, DRIVER_NAME); - peripheral_request(P_UART0_RX, DRIVER_NAME); -#endif - -#ifdef CONFIG_SERIAL_BFIN_UART1 - peripheral_request(P_UART1_TX, DRIVER_NAME); - peripheral_request(P_UART1_RX, DRIVER_NAME); - -# if defined(CONFIG_BFIN_UART1_CTSRTS) && defined(CONFIG_BF54x) - peripheral_request(P_UART1_RTS, DRIVER_NAME); - peripheral_request(P_UART1_CTS, DRIVER_NAME); -# endif -#endif - -#ifdef CONFIG_SERIAL_BFIN_UART2 - peripheral_request(P_UART2_TX, DRIVER_NAME); - peripheral_request(P_UART2_RX, DRIVER_NAME); -#endif - -#ifdef CONFIG_SERIAL_BFIN_UART3 - peripheral_request(P_UART3_TX, DRIVER_NAME); - peripheral_request(P_UART3_RX, DRIVER_NAME); - -# if defined(CONFIG_BFIN_UART3_CTSRTS) && defined(CONFIG_BF54x) - peripheral_request(P_UART3_RTS, DRIVER_NAME); - peripheral_request(P_UART3_CTS, DRIVER_NAME); -# endif -#endif -} - -static void __init bfin_serial_init_ports(void) -{ - static int first = 1; - int i; - - if (!first) - return; - first = 0; - - bfin_serial_hw_init(); - - for (i = 0; i < nr_active_ports; i++) { - spin_lock_init(&bfin_serial_ports[i].port.lock); - bfin_serial_ports[i].port.uartclk = get_sclk(); - bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; - bfin_serial_ports[i].port.ops = &bfin_serial_pops; - bfin_serial_ports[i].port.line = i; - bfin_serial_ports[i].port.iotype = UPIO_MEM; - bfin_serial_ports[i].port.membase = - (void __iomem *)bfin_serial_resource[i].uart_base_addr; - bfin_serial_ports[i].port.mapbase = - bfin_serial_resource[i].uart_base_addr; - bfin_serial_ports[i].port.irq = - bfin_serial_resource[i].uart_irq; - bfin_serial_ports[i].status_irq = - bfin_serial_resource[i].uart_status_irq; - bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF; -#ifdef CONFIG_SERIAL_BFIN_DMA - bfin_serial_ports[i].tx_done = 1; - bfin_serial_ports[i].tx_count = 0; - bfin_serial_ports[i].tx_dma_channel = - bfin_serial_resource[i].uart_tx_dma_channel; - bfin_serial_ports[i].rx_dma_channel = - bfin_serial_resource[i].uart_rx_dma_channel; - init_timer(&(bfin_serial_ports[i].rx_dma_timer)); -#endif -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) - bfin_serial_ports[i].cts_pin = - bfin_serial_resource[i].uart_cts_pin; - bfin_serial_ports[i].rts_pin = - bfin_serial_resource[i].uart_rts_pin; -#endif - } -} - #if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) /* * If the port was already initialised (eg, by a boot loader), @@ -1196,6 +1116,34 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, static struct uart_driver bfin_serial_reg; +static void bfin_serial_console_putchar(struct uart_port *port, int ch) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + while (!(UART_GET_LSR(uart) & THRE)) + barrier(); + UART_PUT_CHAR(uart, ch); +} + +#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || + defined (CONFIG_EARLY_PRINTK) */ + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE +#define CLASS_BFIN_CONSOLE "bfin-console" +/* + * Interrupts are disabled on entering + */ +static void +bfin_serial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct bfin_serial_port *uart = bfin_serial_ports[co->index]; + unsigned long flags; + + spin_lock_irqsave(&uart->port.lock, flags); + uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); + spin_unlock_irqrestore(&uart->port.lock, flags); + +} + static int __init bfin_serial_console_setup(struct console *co, char *options) { @@ -1215,9 +1163,12 @@ bfin_serial_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index == -1 || co->index >= nr_active_ports) - co->index = 0; - uart = &bfin_serial_ports[co->index]; + if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS) + return -ENODEV; + + uart = bfin_serial_ports[co->index]; + if (!uart) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1226,36 +1177,9 @@ bfin_serial_console_setup(struct console *co, char *options) return uart_set_options(&uart->port, co, baud, parity, bits, flow); } -#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || - defined (CONFIG_EARLY_PRINTK) */ - -#ifdef CONFIG_SERIAL_BFIN_CONSOLE -static void bfin_serial_console_putchar(struct uart_port *port, int ch) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - while (!(UART_GET_LSR(uart) & THRE)) - barrier(); - UART_PUT_CHAR(uart, ch); - SSYNC(); -} - -/* - * Interrupts are disabled on entering - */ -static void -bfin_serial_console_write(struct console *co, const char *s, unsigned int count) -{ - struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; - unsigned long flags; - - spin_lock_irqsave(&uart->port.lock, flags); - uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); - spin_unlock_irqrestore(&uart->port.lock, flags); - -} static struct console bfin_serial_console = { - .name = BFIN_SERIAL_NAME, + .name = BFIN_SERIAL_DEV_NAME, .write = bfin_serial_console_write, .device = uart_console_device, .setup = bfin_serial_console_setup, @@ -1263,44 +1187,30 @@ static struct console bfin_serial_console = { .index = -1, .data = &bfin_serial_reg, }; - -static int __init bfin_serial_rs_console_init(void) -{ - bfin_serial_init_ports(); - register_console(&bfin_serial_console); - - return 0; -} -console_initcall(bfin_serial_rs_console_init); - #define BFIN_SERIAL_CONSOLE &bfin_serial_console #else #define BFIN_SERIAL_CONSOLE NULL #endif /* CONFIG_SERIAL_BFIN_CONSOLE */ +#ifdef CONFIG_EARLY_PRINTK +static struct bfin_serial_port bfin_earlyprintk_port; +#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk" -#ifdef CONFIG_EARLY_PRINTK -static __init void early_serial_putc(struct uart_port *port, int ch) +/* + * Interrupts are disabled on entering + */ +static void +bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count) { - unsigned timeout = 0xffff; - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - - while ((!(UART_GET_LSR(uart) & THRE)) && --timeout) - cpu_relax(); - UART_PUT_CHAR(uart, ch); -} + unsigned long flags; -static __init void early_serial_write(struct console *con, const char *s, - unsigned int n) -{ - struct bfin_serial_port *uart = &bfin_serial_ports[con->index]; - unsigned int i; + if (bfin_earlyprintk_port.port.line != co->index) + return; - for (i = 0; i < n; i++, s++) { - if (*s == '\n') - early_serial_putc(&uart->port, '\r'); - early_serial_putc(&uart->port, *s); - } + spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags); + uart_console_write(&bfin_earlyprintk_port.port, s, count, + bfin_serial_console_putchar); + spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags); } /* @@ -1311,113 +1221,204 @@ static __init void early_serial_write(struct console *con, const char *s, */ static struct __initdata console bfin_early_serial_console = { .name = "early_BFuart", - .write = early_serial_write, + .write = bfin_earlyprintk_console_write, .device = uart_console_device, .flags = CON_PRINTBUFFER, .index = -1, .data = &bfin_serial_reg, }; - -struct console __init *bfin_earlyserial_init(unsigned int port, - unsigned int cflag) -{ - struct bfin_serial_port *uart; - struct ktermios t; - -#ifdef CONFIG_SERIAL_BFIN_CONSOLE - /* - * If we are using early serial, don't let the normal console rewind - * log buffer, since that causes things to be printed multiple times - */ - bfin_serial_console.flags &= ~CON_PRINTBUFFER; #endif - if (port == -1 || port >= nr_active_ports) - port = 0; - bfin_serial_init_ports(); - bfin_early_serial_console.index = port; - uart = &bfin_serial_ports[port]; - t.c_cflag = cflag; - t.c_iflag = 0; - t.c_oflag = 0; - t.c_lflag = ICANON; - t.c_line = port; - bfin_serial_set_termios(&uart->port, &t, &t); - return &bfin_early_serial_console; -} - -#endif /* CONFIG_EARLY_PRINTK */ - static struct uart_driver bfin_serial_reg = { .owner = THIS_MODULE, - .driver_name = "bfin-uart", - .dev_name = BFIN_SERIAL_NAME, + .driver_name = DRIVER_NAME, + .dev_name = BFIN_SERIAL_DEV_NAME, .major = BFIN_SERIAL_MAJOR, .minor = BFIN_SERIAL_MINOR, .nr = BFIN_UART_NR_PORTS, .cons = BFIN_SERIAL_CONSOLE, }; -static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) +static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(pdev); - for (i = 0; i < nr_active_ports; i++) { - if (bfin_serial_ports[i].port.dev != &dev->dev) - continue; - uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - } + return uart_suspend_port(&bfin_serial_reg, &uart->port); +} - return 0; +static int bfin_serial_resume(struct platform_device *pdev) +{ + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + + return uart_resume_port(&bfin_serial_reg, &uart->port); } -static int bfin_serial_resume(struct platform_device *dev) +static int bfin_serial_probe(struct platform_device *pdev) { - int i; + struct resource *res; + struct bfin_serial_port *uart = NULL; + int ret = 0; - for (i = 0; i < nr_active_ports; i++) { - if (bfin_serial_ports[i].port.dev != &dev->dev) - continue; - uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) { + dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n"); + return -ENOENT; } - return 0; -} + if (bfin_serial_ports[pdev->id] == NULL) { -static int bfin_serial_probe(struct platform_device *dev) -{ - struct resource *res = dev->resource; - int i; + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) { + dev_err(&pdev->dev, + "fail to malloc bfin_serial_port\n"); + return -ENOMEM; + } + bfin_serial_ports[pdev->id] = uart; - for (i = 0; i < dev->num_resources; i++, res++) - if (res->flags & IORESOURCE_MEM) - break; +#ifdef CONFIG_EARLY_PRINTK + if (!(bfin_earlyprintk_port.port.membase + && bfin_earlyprintk_port.port.line == pdev->id)) { + /* + * If the peripheral PINs of current port is allocated + * in earlyprintk probe stage, don't do it again. + */ +#endif + ret = peripheral_request_list( + (unsigned short *)pdev->dev.platform_data, DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, + "fail to request bfin serial peripherals\n"); + goto out_error_free_mem; + } +#ifdef CONFIG_EARLY_PRINTK + } +#endif + + spin_lock_init(&uart->port.lock); + uart->port.uartclk = get_sclk(); + uart->port.fifosize = BFIN_UART_TX_FIFO_SIZE; + uart->port.ops = &bfin_serial_pops; + uart->port.line = pdev->id; + uart->port.iotype = UPIO_MEM; + uart->port.flags = UPF_BOOT_AUTOCONF; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + ret = -ENOENT; + goto out_error_free_peripherals; + } + + uart->port.membase = ioremap(res->start, + res->end - res->start); + if (!uart->port.membase) { + dev_err(&pdev->dev, "Cannot map uart IO\n"); + ret = -ENXIO; + goto out_error_free_peripherals; + } + uart->port.mapbase = res->start; - if (i < dev->num_resources) { - for (i = 0; i < nr_active_ports; i++, res++) { - if (bfin_serial_ports[i].port.mapbase != res->start) - continue; - bfin_serial_ports[i].port.dev = &dev->dev; - uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + uart->port.irq = platform_get_irq(pdev, 0); + if (uart->port.irq < 0) { + dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; } + + uart->status_irq = platform_get_irq(pdev, 1); + if (uart->status_irq < 0) { + dev_err(&pdev->dev, "No uart status IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + +#ifdef CONFIG_SERIAL_BFIN_DMA + uart->tx_done = 1; + uart->tx_count = 0; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res == NULL) { + dev_err(&pdev->dev, "No uart TX DMA channel specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + uart->tx_dma_channel = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (res == NULL) { + dev_err(&pdev->dev, "No uart RX DMA channel specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + uart->rx_dma_channel = res->start; + + init_timer(&(uart->rx_dma_timer)); +#endif + +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) + uart->cts_pin = -1; + else + uart->cts_pin = res->start; + + res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (res == NULL) + uart->rts_pin = -1; + else + uart->rts_pin = res->start; +# if defined(CONFIG_SERIAL_BFIN_CTSRTS) + if (uart->rts_pin >= 0) + gpio_request(uart->rts_pin, DRIVER_NAME); +# endif +#endif } - return 0; +#ifdef CONFIG_SERIAL_BFIN_CONSOLE + if (!is_early_platform_device(pdev)) { +#endif + uart = bfin_serial_ports[pdev->id]; + uart->port.dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, uart); + ret = uart_add_one_port(&bfin_serial_reg, &uart->port); +#ifdef CONFIG_SERIAL_BFIN_CONSOLE + } +#endif + + if (!ret) + return 0; + + if (uart) { +out_error_unmap: + iounmap(uart->port.membase); +out_error_free_peripherals: + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); +out_error_free_mem: + kfree(uart); + bfin_serial_ports[pdev->id] = NULL; + } + + return ret; } -static int bfin_serial_remove(struct platform_device *dev) +static int __devexit bfin_serial_remove(struct platform_device *pdev) { - int i; - - for (i = 0; i < nr_active_ports; i++) { - if (bfin_serial_ports[i].port.dev != &dev->dev) - continue; - uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - bfin_serial_ports[i].port.dev = NULL; -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) - gpio_free(bfin_serial_ports[i].cts_pin); - gpio_free(bfin_serial_ports[i].rts_pin); + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + + dev_set_drvdata(&pdev->dev, NULL); + + if (uart) { + uart_remove_one_port(&bfin_serial_reg, &uart->port); +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->rts_pin >= 0) + gpio_free(uart->rts_pin); #endif + iounmap(uart->port.membase); + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); + kfree(uart); + bfin_serial_ports[pdev->id] = NULL; } return 0; @@ -1425,31 +1426,160 @@ static int bfin_serial_remove(struct platform_device *dev) static struct platform_driver bfin_serial_driver = { .probe = bfin_serial_probe, - .remove = bfin_serial_remove, + .remove = __devexit_p(bfin_serial_remove), .suspend = bfin_serial_suspend, .resume = bfin_serial_resume, .driver = { - .name = "bfin-uart", + .name = DRIVER_NAME, .owner = THIS_MODULE, }, }; -static int __init bfin_serial_init(void) +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) +static __initdata struct early_platform_driver early_bfin_serial_driver = { + .class_str = CLASS_BFIN_CONSOLE, + .pdrv = &bfin_serial_driver, + .requested_id = EARLY_PLATFORM_ID_UNSET, +}; + +static int __init bfin_serial_rs_console_init(void) +{ + early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME); + + early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0); + + register_console(&bfin_serial_console); + + return 0; +} +console_initcall(bfin_serial_rs_console_init); +#endif + +#ifdef CONFIG_EARLY_PRINTK +/* + * Memory can't be allocated dynamically during earlyprink init stage. + * So, do individual probe for earlyprink with a static uart port variable. + */ +static int bfin_earlyprintk_probe(struct platform_device *pdev) { + struct resource *res; int ret; - pr_info("Serial: Blackfin serial driver\n"); + if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) { + dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n"); + return -ENOENT; + } + + ret = peripheral_request_list( + (unsigned short *)pdev->dev.platform_data, DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, + "fail to request bfin serial peripherals\n"); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + ret = -ENOENT; + goto out_error_free_peripherals; + } + + bfin_earlyprintk_port.port.membase = ioremap(res->start, + res->end - res->start); + if (!bfin_earlyprintk_port.port.membase) { + dev_err(&pdev->dev, "Cannot map uart IO\n"); + ret = -ENXIO; + goto out_error_free_peripherals; + } + bfin_earlyprintk_port.port.mapbase = res->start; + bfin_earlyprintk_port.port.line = pdev->id; + bfin_earlyprintk_port.port.uartclk = get_sclk(); + bfin_earlyprintk_port.port.fifosize = BFIN_UART_TX_FIFO_SIZE; + spin_lock_init(&bfin_earlyprintk_port.port.lock); + + return 0; + +out_error_free_peripherals: + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); + + return ret; +} + +static struct platform_driver bfin_earlyprintk_driver = { + .probe = bfin_earlyprintk_probe, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = { + .class_str = CLASS_BFIN_EARLYPRINTK, + .pdrv = &bfin_earlyprintk_driver, + .requested_id = EARLY_PLATFORM_ID_UNSET, +}; + +struct console __init *bfin_earlyserial_init(unsigned int port, + unsigned int cflag) +{ + struct ktermios t; + char port_name[20]; - bfin_serial_init_ports(); + if (port < 0 || port >= BFIN_UART_NR_PORTS) + return NULL; + + /* + * Only probe resource of the given port in earlyprintk boot arg. + * The expected port id should be indicated in port name string. + */ + snprintf(port_name, 20, DRIVER_NAME ".%d", port); + early_platform_driver_register(&early_bfin_earlyprintk_driver, + port_name); + early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0); + + if (!bfin_earlyprintk_port.port.membase) + return NULL; + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE + /* + * If we are using early serial, don't let the normal console rewind + * log buffer, since that causes things to be printed multiple times + */ + bfin_serial_console.flags &= ~CON_PRINTBUFFER; +#endif + + bfin_early_serial_console.index = port; + t.c_cflag = cflag; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = port; + bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t); + + return &bfin_early_serial_console; +} +#endif /* CONFIG_EARLY_PRINTK */ + +static int __init bfin_serial_init(void) +{ + int ret; + + pr_info("Blackfin serial driver\n"); ret = uart_register_driver(&bfin_serial_reg); - if (ret == 0) { - ret = platform_driver_register(&bfin_serial_driver); - if (ret) { - pr_debug("uart register failed\n"); - uart_unregister_driver(&bfin_serial_reg); - } + if (ret) { + pr_err("failed to register %s:%d\n", + bfin_serial_reg.driver_name, ret); + } + + ret = platform_driver_register(&bfin_serial_driver); + if (ret) { + pr_err("fail to register bfin uart\n"); + uart_unregister_driver(&bfin_serial_reg); } + return ret; } @@ -1463,7 +1593,7 @@ static void __exit bfin_serial_exit(void) module_init(bfin_serial_init); module_exit(bfin_serial_exit); -MODULE_AUTHOR("Aubrey.Li "); +MODULE_AUTHOR("Sonic Zhang, Aubrey Li"); MODULE_DESCRIPTION("Blackfin generic serial port driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR); -- cgit v1.2.3 From 731f3ab66a23dab28a359e87364f53d221b3d366 Mon Sep 17 00:00:00 2001 From: Joe Jin Date: Fri, 7 Jan 2011 18:17:17 +0800 Subject: xen/fb: fix xenfb suspend/resume race. When migrating guests over a long period we hit this: <1>BUG: unable to handle kernel paging request at 0000000b819fdb98 <1>IP: [] notify_remote_via_irq+0x13/0x34 <4>PGD 94b10067 PUD 0 <0>Oops: 0000 [#1] SMP .. snip.. Call Trace: [] xenfb_send_event+0x5c/0x5e [] ? xen_restore_fl_direct_end+0x0/0x1 [] ? _spin_unlock_irqrestore+0x16/0x18 [] xenfb_refresh+0x1b1/0x1d7 [] ? sys_imageblit+0x1ac/0x458 [] xenfb_imageblit+0x2f/0x34 [] soft_cursor+0x1b5/0x1c8 [] bit_cursor+0x4b6/0x4d7 [] ? xen_restore_fl_direct_end+0x0/0x1 [] ? _spin_unlock_irqrestore+0x16/0x18 [] ? bit_cursor+0x0/0x4d7 [] fb_flashcursor+0xff/0x111 [] ? fb_flashcursor+0x0/0x111 [] worker_thread+0x14d/0x1ed [] ? autoremove_wake_function+0x0/0x3d [] ? _spin_unlock_irqrestore+0x16/0x18 [] ? worker_thread+0x0/0x1ed [] kthread+0x6e/0x76 [] child_rip+0xa/0x20 [] ? int_ret_from_sys_call+0x7/0x1b [] ? retint_restore_args+0x5/0x6 [] ? child_rip+0x0/0x20 Code: 6b ff 0c 8b 87 a4 db 9f 81 66 85 c0 74 08 0f b7 f8 e8 3b ff ff ff c9 c3 55 48 89 e5 48 83 ec 10 0f 1f 44 00 00 89 ff 48 6b ff 0c <8b> 87 a4 db 9f 81 66 85 c0 74 14 48 8d 75 f0 0f b7 c0 bf 04 00 RIP [] notify_remote_via_irq+0x13/0x34 RSP CR2: 0000000b819fdb98 ---[ end trace 098b4b74827595d0 ]--- The root cause of the panic is the race between the resume and reconnect to the backend. Clearing the 'update_wanted' flag of xenfb before disconnecting from the backend fixes this issue. Signed-off-by: Joe Jin Signed-off-by: Konrad Rzeszutek Wilk Tested-by: Gurudas Pai Acked-by: Ian Campbell Cc: Jeremy Fitzhardinge Cc: Andrew Morton --- drivers/video/xen-fbfront.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 428d273be727..f92313d33e27 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -617,6 +617,8 @@ static int xenfb_connect_backend(struct xenbus_device *dev, static void xenfb_disconnect_backend(struct xenfb_info *info) { + /* Prevent xenfb refresh */ + info->update_wanted = 0; if (info->irq >= 0) unbind_from_irqhandler(info->irq, info); info->irq = -1; -- cgit v1.2.3 From fc550e95921e109f3778a6b2dc560d63388810ab Mon Sep 17 00:00:00 2001 From: Joe Jin Date: Fri, 7 Jan 2011 18:20:54 +0800 Subject: xen/fb: fix potential memory leak This patch fixes a potential memory leak when xenfb connect to the backend fails. Thanks for Ian's review and comments. [v2: reworded the commit message a bit] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Joe Jin Tested-by: Gurudas Pai Acked-by: Ian Campbell Cc: Jeremy Fitzhardinge Cc: Andrew Morton --- drivers/video/xen-fbfront.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index f92313d33e27..95bbd0a1e5da 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -562,26 +562,24 @@ static void xenfb_init_shared_page(struct xenfb_info *info, static int xenfb_connect_backend(struct xenbus_device *dev, struct xenfb_info *info) { - int ret, evtchn; + int ret, evtchn, irq; struct xenbus_transaction xbt; ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) return ret; - ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, + irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, 0, dev->devicetype, info); - if (ret < 0) { + if (irq < 0) { xenbus_free_evtchn(dev, evtchn); xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); - return ret; + return irq; } - info->irq = ret; - again: ret = xenbus_transaction_start(&xbt); if (ret) { xenbus_dev_fatal(dev, ret, "starting transaction"); - return ret; + goto unbind_irq; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", virt_to_mfn(info->page)); @@ -603,15 +601,18 @@ static int xenfb_connect_backend(struct xenbus_device *dev, if (ret == -EAGAIN) goto again; xenbus_dev_fatal(dev, ret, "completing transaction"); - return ret; + goto unbind_irq; } xenbus_switch_state(dev, XenbusStateInitialised); + info->irq = irq; return 0; error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); + unbind_irq: + unbind_from_irqhandler(irq, info); return ret; } -- cgit v1.2.3 From 110e7c7e4f8a61a34e0ab88fc9bdf4d5c6d220b2 Mon Sep 17 00:00:00 2001 From: Joe Jin Date: Fri, 7 Jan 2011 14:50:12 +0800 Subject: xen/event: validate irq before get evtchn by irq When retrieving the event channel number from irq, the irq number may not be valid under some conditions. So far that can be when we suspend/resume and irq ends with -1. Validate and return sanitized irq and provide diagnostics information. [v3: added unlikely on the WARN path] [v2: reworded the commit message] Signed-off-by: Joe Jin Signed-off-by: Konrad Rzeszutek Wilk Tested-by: Gurudas Pai Cc: Ian Campbell Cc: Jeremy Fitzhardinge Cc: Andrew Morton --- drivers/xen/events.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 4d4a23d4c9f6..3df7e477694a 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -170,6 +170,9 @@ static struct irq_info *info_for_irq(unsigned irq) static unsigned int evtchn_from_irq(unsigned irq) { + if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq))) + return 0; + return info_for_irq(irq)->evtchn; } -- cgit v1.2.3 From 57cc7215b70856dc6bae8e55b00ecd7b1d7429b1 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 10 Jan 2011 08:18:25 +0200 Subject: headers: kobject.h redux Remove kobject.h from files which don't need it, notably, sched.h and fs.h. Signed-off-by: Alexey Dobriyan Signed-off-by: Linus Torvalds --- arch/arm/plat-s3c24xx/cpu-freq.c | 1 - arch/powerpc/platforms/pseries/eeh_sysfs.c | 1 - drivers/char/snsc.h | 1 - drivers/net/bonding/bonding.h | 1 - drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/rpaphp_slot.c | 1 - drivers/s390/char/tape_class.h | 1 - drivers/sh/clk/core.c | 1 - drivers/usb/musb/musb_debugfs.c | 1 - fs/gfs2/incore.h | 1 + fs/nilfs2/super.c | 1 - fs/sysfs/inode.c | 1 + fs/sysfs/sysfs.h | 1 + include/linux/firmware-map.h | 1 - include/linux/fs.h | 2 +- include/linux/sched.h | 1 - include/linux/sunrpc/cache.h | 1 + security/apparmor/include/match.h | 1 + 18 files changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-s3c24xx/cpu-freq.c b/arch/arm/plat-s3c24xx/cpu-freq.c index 1ecc15bfe9d4..25a8fc7f512e 100644 --- a/arch/arm/plat-s3c24xx/cpu-freq.c +++ b/arch/arm/plat-s3c24xx/cpu-freq.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index 15e13b568904..23982c7892d2 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -25,7 +25,6 @@ #include #include #include -#include /** * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h index 4be62eda9fbc..e8c52c882b21 100644 --- a/drivers/char/snsc.h +++ b/drivers/char/snsc.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 4da384cc7603..31fe980e4e28 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include "bond_3ad.h" diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index bab52047baa8..7722108e78df 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -36,7 +36,6 @@ #define _ACPIPHP_H #include -#include #include #include diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 2ea9cf1a8d02..b283bbea6d24 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -24,7 +24,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h index 707b7f48c232..9e32780c317f 100644 --- a/drivers/s390/char/tape_class.h +++ b/drivers/s390/char/tape_class.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 3f5e387ed564..5f63c3b83828 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 9e8639d4e862..b0176e4569e0 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8d3d2b4a0a7d..a79790c06275 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -11,6 +11,7 @@ #define __INCORE_DOT_H__ #include +#include #include #include #include diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 6ea32d9b1b9d..70dfdd532b83 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include "nilfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 30ac27345586..0a12eb89cd32 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include "sysfs.h" diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index ffaaa816bfba..3d28af31d863 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -9,6 +9,7 @@ */ #include +#include #include struct sysfs_open_dirent; diff --git a/include/linux/firmware-map.h b/include/linux/firmware-map.h index c6dcc1dfe781..43fe52fcef0f 100644 --- a/include/linux/firmware-map.h +++ b/include/linux/firmware-map.h @@ -17,7 +17,6 @@ #define _LINUX_FIRMWARE_MAP_H #include -#include /* * provide a dummy interface if CONFIG_FIRMWARE_MEMMAP is disabled diff --git a/include/linux/fs.h b/include/linux/fs.h index baf3e556ff0e..f84d9928bdb1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -382,7 +382,6 @@ struct inodes_stat_t { #include #include #include -#include #include #include #include @@ -402,6 +401,7 @@ struct hd_geometry; struct iovec; struct nameidata; struct kiocb; +struct kobject; struct pipe_inode_info; struct poll_table_struct; struct kstatfs; diff --git a/include/linux/sched.h b/include/linux/sched.h index c118a7f203aa..abc527aa8550 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -87,7 +87,6 @@ struct sched_param { #include #include #include -#include #include #include diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 6950c981882d..78aa104250b7 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -13,6 +13,7 @@ #ifndef _LINUX_SUNRPC_CACHE_H_ #define _LINUX_SUNRPC_CACHE_H_ +#include #include #include #include diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index 734a6d35112c..19ba16e8aacd 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -15,6 +15,7 @@ #ifndef __AA_MATCH_H #define __AA_MATCH_H +#include #include #define DFA_NOMATCH 0 -- cgit v1.2.3 From 7027d8b570244f0fa3aaebccf0bcd8e95e172631 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 8 Jan 2011 19:55:40 -0800 Subject: intel_ips: fix sparse non-ANSI function warning Fix sparse warning for non-ANSI function declaration: drivers/platform/x86/intel_ips.c:1477:25: warning: non-ANSI function declaration of function 'ips_link_to_i915_driver' Signed-off-by: Randy Dunlap Cc: Matthew Garrett Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_ips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index f0b3ad13c273..1294a39373ba 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1474,7 +1474,7 @@ ips_gpu_turbo_enabled(struct ips_driver *ips) } void -ips_link_to_i915_driver() +ips_link_to_i915_driver(void) { /* We can't cleanly get at the various ips_driver structs from * this caller (the i915 driver), so just set a flag saying -- cgit v1.2.3 From a46a780835f394869e1fbbef8b528a1e02193e78 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 8 Jan 2011 19:56:44 -0800 Subject: sony-laptop: fix sparse non-ANSI function warning Fix sparse warning for non-ANSI function declaration: drivers/platform/x86/sony-laptop.c:1134:35: warning: non-ANSI function declaration of function 'sony_nc_rfkill_update' Signed-off-by: Randy Dunlap Cc: Matthew Garrett Cc: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f200677851b8..68edc97f1926 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1131,7 +1131,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, return err; } -static void sony_nc_rfkill_update() +static void sony_nc_rfkill_update(void) { enum sony_nc_rfkill i; int result; -- cgit v1.2.3 From 0c51a4d8abd6ed5ba55f828840c6b78ab672644b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 10 Jan 2011 14:37:02 +0000 Subject: platform/x86: Consistently select LEDS Kconfig options Currently the x86 platform devices are not consistent about selecting or depending on the LEDs Kconfig variables, and this inconsistency leads to Kconfig getting upset and refusing to offer LEDs (even on non-x86 platforms): drivers/platform/x86/Kconfig:422:error: recursive dependency detected! drivers/platform/x86/Kconfig:422: symbol EEEPC_WMI depends on ACPI_WMI drivers/platform/x86/Kconfig:438: symbol ACPI_WMI is selected by ACER_WMI drivers/platform/x86/Kconfig:18: symbol ACER_WMI depends on LEDS_CLASS drivers/leds/Kconfig:10: symbol LEDS_CLASS is selected by EEEPC_WMI Fix this by always selecting rather than depending on the symbols as slightly more drivers use this approach already and it seems more user friendly. Signed-off-by: Mark Brown Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index a122a0dac981..d163bc2e2b9e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -18,8 +18,8 @@ if X86_PLATFORM_DEVICES config ACER_WMI tristate "Acer WMI Laptop Extras" depends on ACPI - depends on LEDS_CLASS - depends on NEW_LEDS + select LEDS_CLASS + select NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 depends on INPUT @@ -516,8 +516,8 @@ config TOPSTAR_LAPTOP config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI - depends on LEDS_CLASS - depends on NEW_LEDS + select LEDS_CLASS + select NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on INPUT depends on RFKILL || RFKILL = n -- cgit v1.2.3 From 1a7d946993aaf2a79e9c65abbe169a108e351bcb Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 8 Jan 2011 18:47:29 +0900 Subject: sony-laptop: support new hotkeys on the P, Z and EC series Add new mappings for assist, VAIO, zoom and eject buttons present on refurbished P, Z and EC models. Reported-by: Gyorgy Jeney Reported-by: Stephan Mueller Cc: Dmitry Torokhov Cc: Matthew Garrett Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 10 ++++++++++ include/linux/sonypi.h | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 68edc97f1926..b4a95bb2f232 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -235,6 +235,7 @@ static int sony_laptop_input_index[] = { 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */ + 59, /* 72 SONYPI_EVENT_VENDOR_PRESSED */ }; static int sony_laptop_input_keycode_map[] = { @@ -297,6 +298,7 @@ static int sony_laptop_input_keycode_map[] = { KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */ + KEY_VENDOR, /* 59 SONYPI_EVENT_VENDOR_PRESSED */ }; /* release buttons after a short delay if pressed */ @@ -894,10 +896,18 @@ static struct sony_nc_event sony_100_events[] = { { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, { 0x8C, SONYPI_EVENT_FNKEY_F12 }, { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, + { 0x9d, SONYPI_EVENT_ZOOM_PRESSED }, + { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED }, { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, { 0xa1, SONYPI_EVENT_MEDIA_PRESSED }, { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED }, + { 0xa4, SONYPI_EVENT_CD_EJECT_PRESSED }, + { 0x24, SONYPI_EVENT_ANYBUTTON_RELEASED }, + { 0xa5, SONYPI_EVENT_VENDOR_PRESSED }, + { 0x25, SONYPI_EVENT_ANYBUTTON_RELEASED }, + { 0xa6, SONYPI_EVENT_HELP_PRESSED }, + { 0x26, SONYPI_EVENT_ANYBUTTON_RELEASED }, { 0, 0 }, }; diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h index 4f95c1aac2fd..0e6dc3891942 100644 --- a/include/linux/sonypi.h +++ b/include/linux/sonypi.h @@ -112,6 +112,7 @@ #define SONYPI_EVENT_VOLUME_DEC_PRESSED 70 #define SONYPI_EVENT_BRIGHTNESS_PRESSED 71 #define SONYPI_EVENT_MEDIA_PRESSED 72 +#define SONYPI_EVENT_VENDOR_PRESSED 73 /* get/set brightness */ #define SONYPI_IOCGBRT _IOR('v', 0, __u8) -- cgit v1.2.3 From daef1f35ea1e2cca125eecd5f078f40b55eb9105 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Mon, 10 Jan 2011 16:35:44 +0800 Subject: ACPI: Check the returned value of set_cpus_allowed_ptr before T-state operation Now before it executes the T-state operation on one CPU, it will try to migrate to the target CPU. Especially this is required on the system that uses the MSR_IA32_THERMAL_CONTROL register to switch T-state. But unfortunately it doesn't check whether the migration is successful or not. In such case we will get/set the incorrect T-state on the offline CPU as it fails in the migration to the offline CPU. Signed-off-by: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/processor_throttling.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ff3632717c51..ffc859c61393 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -876,7 +876,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) */ cpumask_copy(saved_mask, ¤t->cpus_allowed); /* FIXME: use work_on_cpu() */ - set_cpus_allowed_ptr(current, cpumask_of(pr->id)); + if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { + /* Can't migrate to the target pr->id CPU. Exit */ + free_cpumask_var(saved_mask); + return -ENODEV; + } ret = pr->throttling.acpi_processor_get_throttling(pr); /* restore the previous state */ set_cpus_allowed_ptr(current, saved_mask); @@ -1051,6 +1055,14 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, return -ENOMEM; } + if (cpu_is_offline(pr->id)) { + /* + * the cpu pointed by pr->id is offline. Unnecessary to change + * the throttling state any more. + */ + return -ENODEV; + } + cpumask_copy(saved_mask, ¤t->cpus_allowed); t_state.target_state = state; p_throttling = &(pr->throttling); @@ -1074,7 +1086,11 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, */ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { /* FIXME: use work_on_cpu() */ - set_cpus_allowed_ptr(current, cpumask_of(pr->id)); + if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { + /* Can't migrate to the pr->id CPU. Exit */ + ret = -ENODEV; + goto exit; + } ret = p_throttling->acpi_processor_set_throttling(pr, t_state.target_state, force); } else { @@ -1106,7 +1122,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, } t_state.cpu = i; /* FIXME: use work_on_cpu() */ - set_cpus_allowed_ptr(current, cpumask_of(i)); + if (set_cpus_allowed_ptr(current, cpumask_of(i))) + continue; ret = match_pr->throttling. acpi_processor_set_throttling( match_pr, t_state.target_state, force); @@ -1126,6 +1143,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, /* restore the previous state */ /* FIXME: use work_on_cpu() */ set_cpus_allowed_ptr(current, saved_mask); +exit: free_cpumask_var(online_throttling_cpus); free_cpumask_var(saved_mask); return ret; -- cgit v1.2.3 From 5a344a505093dd65f82f338ffdb7208321b3630e Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Mon, 10 Jan 2011 16:35:45 +0800 Subject: ACPI: Reevaluate whether the T-state is supported or not after cpu is online/offline After one CPU is offlined, it is unnecessary to switch T-state for it. So it will be better that the throttling is disabled after the cpu is offline. At the same time after one cpu is online, we should check whether the T-state is supported and then set the corresponding T-state flag. Signed-off-by: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/processor_driver.c | 5 ++++ drivers/acpi/processor_throttling.c | 52 +++++++++++++++++++++++++++++++++++++ include/acpi/processor.h | 6 +++++ 3 files changed, 63 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 85e48047d7b0..c8a0ca2af839 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -478,8 +478,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, if (action == CPU_ONLINE && pr) { acpi_processor_ppc_has_changed(pr, 0); acpi_processor_cst_has_changed(pr); + acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } + if (action == CPU_DEAD && pr) { + /* invalidate the flag.throttling after one CPU is offline */ + acpi_processor_reevaluate_tstate(pr, action); + } return NOTIFY_OK; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index ffc859c61393..4305d560b065 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -369,6 +369,58 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr) return acpi_processor_set_throttling(pr, target_state, false); } +/* + * This function is used to reevaluate whether the T-state is valid + * after one CPU is onlined/offlined. + * It is noted that it won't reevaluate the following properties for + * the T-state. + * 1. Control method. + * 2. the number of supported T-state + * 3. TSD domain + */ +void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, + unsigned long action) +{ + int result = 0; + + if (action == CPU_DEAD) { + /* When one CPU is offline, the T-state throttling + * will be invalidated. + */ + pr->flags.throttling = 0; + return; + } + /* the following is to recheck whether the T-state is valid for + * the online CPU + */ + if (!pr->throttling.state_count) { + /* If the number of T-state is invalid, it is + * invalidated. + */ + pr->flags.throttling = 0; + return; + } + pr->flags.throttling = 1; + + /* Disable throttling (if enabled). We'll let subsequent + * policy (e.g.thermal) decide to lower performance if it + * so chooses, but for now we'll crank up the speed. + */ + + result = acpi_processor_get_throttling(pr); + if (result) + goto end; + + if (pr->throttling.state) { + result = acpi_processor_set_throttling(pr, 0, false); + if (result) + goto end; + } + +end: + if (result) + pr->flags.throttling = 0; +} /* * _PTC - Processor Throttling Control (and status) register location */ diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 1b62102fbb67..55192ac0cede 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -324,6 +324,12 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr); int acpi_processor_get_throttling_info(struct acpi_processor *pr); extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force); +/* + * Reevaluate whether the T-state is invalid after one cpu is + * onlined/offlined. In such case the flags.throttling will be updated. + */ +extern void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, + unsigned long action); extern const struct file_operations acpi_processor_throttling_fops; extern void acpi_processor_throttling_init(void); /* in processor_idle.c */ -- cgit v1.2.3 From 9d084a3d5dffd076a9a006164ea0dbd9c495f2b0 Mon Sep 17 00:00:00 2001 From: Fabien Marteau Date: Mon, 10 Jan 2011 11:01:13 -0800 Subject: Input: add Austria Microsystem AS5011 joystick driver This is driver for EasyPoint AS5011 2 axis joystick chip. This chip is plugged on an I2C bus. Tested on ARM processor (i.MX27). Signed-off-by: Fabien Marteau Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/Kconfig | 10 ++ drivers/input/joystick/Makefile | 1 + drivers/input/joystick/as5011.c | 367 ++++++++++++++++++++++++++++++++++++++++ include/linux/input/as5011.h | 20 +++ 4 files changed, 398 insertions(+) create mode 100644 drivers/input/joystick/as5011.c create mode 100644 include/linux/input/as5011.h (limited to 'drivers') diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 5b596165b571..56eb471b5576 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -255,6 +255,16 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. +config JOYSTICK_AS5011 + tristate "Austria Microsystem AS5011 joystick" + depends on I2C + help + Say Y here if you have an AS5011 digital joystick connected to your + system. + + To compile this driver as a module, choose M here: the + module will be called as5011. + config JOYSTICK_JOYDUMP tristate "Gameport data dumper" select GAMEPORT diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile index f3a8cbe2abb6..92dc0de9dfed 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o +obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o obj-$(CONFIG_JOYSTICK_DB9) += db9.o diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c new file mode 100644 index 000000000000..f6732b57ca07 --- /dev/null +++ b/drivers/input/joystick/as5011.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2010, 2011 Fabien Marteau + * Sponsored by ARMadeus Systems + * + * 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 + * + * Driver for Austria Microsystems joysticks AS5011 + * + * TODO: + * - Power on the chip when open() and power down when close() + * - Manage power mode + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick" +#define MODULE_DEVICE_ALIAS "as5011" + +MODULE_AUTHOR("Fabien Marteau "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* registers */ +#define AS5011_CTRL1 0x76 +#define AS5011_CTRL2 0x75 +#define AS5011_XP 0x43 +#define AS5011_XN 0x44 +#define AS5011_YP 0x53 +#define AS5011_YN 0x54 +#define AS5011_X_REG 0x41 +#define AS5011_Y_REG 0x42 +#define AS5011_X_RES_INT 0x51 +#define AS5011_Y_RES_INT 0x52 + +/* CTRL1 bits */ +#define AS5011_CTRL1_LP_PULSED 0x80 +#define AS5011_CTRL1_LP_ACTIVE 0x40 +#define AS5011_CTRL1_LP_CONTINUE 0x20 +#define AS5011_CTRL1_INT_WUP_EN 0x10 +#define AS5011_CTRL1_INT_ACT_EN 0x08 +#define AS5011_CTRL1_EXT_CLK_EN 0x04 +#define AS5011_CTRL1_SOFT_RST 0x02 +#define AS5011_CTRL1_DATA_VALID 0x01 + +/* CTRL2 bits */ +#define AS5011_CTRL2_EXT_SAMPLE_EN 0x08 +#define AS5011_CTRL2_RC_BIAS_ON 0x04 +#define AS5011_CTRL2_INV_SPINNING 0x02 + +#define AS5011_MAX_AXIS 80 +#define AS5011_MIN_AXIS (-80) +#define AS5011_FUZZ 8 +#define AS5011_FLAT 40 + +struct as5011_device { + struct input_dev *input_dev; + struct i2c_client *i2c_client; + unsigned int button_gpio; + unsigned int button_irq; + unsigned int axis_irq; +}; + +static int as5011_i2c_write(struct i2c_client *client, + uint8_t aregaddr, + uint8_t avalue) +{ + uint8_t data[2] = { aregaddr, avalue }; + struct i2c_msg msg = { + client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data + }; + int error; + + error = i2c_transfer(client->adapter, &msg, 1); + return error < 0 ? error : 0; +} + +static int as5011_i2c_read(struct i2c_client *client, + uint8_t aregaddr, signed char *value) +{ + uint8_t data[2] = { aregaddr }; + struct i2c_msg msg_set[2] = { + { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data }, + { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data } + }; + int error; + + error = i2c_transfer(client->adapter, msg_set, 2); + if (error < 0) + return error; + + *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0]; + return 0; +} + +static irqreturn_t as5011_button_interrupt(int irq, void *dev_id) +{ + struct as5011_device *as5011 = dev_id; + int val = gpio_get_value_cansleep(as5011->button_gpio); + + input_report_key(as5011->input_dev, BTN_JOYSTICK, !val); + input_sync(as5011->input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id) +{ + struct as5011_device *as5011 = dev_id; + int error; + signed char x, y; + + error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x); + if (error < 0) + goto out; + + error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y); + if (error < 0) + goto out; + + input_report_abs(as5011->input_dev, ABS_X, x); + input_report_abs(as5011->input_dev, ABS_Y, y); + input_sync(as5011->input_dev); + +out: + return IRQ_HANDLED; +} + +static int __devinit as5011_configure_chip(struct as5011_device *as5011, + const struct as5011_platform_data *plat_dat) +{ + struct i2c_client *client = as5011->i2c_client; + int error; + signed char value; + + /* chip soft reset */ + error = as5011_i2c_write(client, AS5011_CTRL1, + AS5011_CTRL1_SOFT_RST); + if (error < 0) { + dev_err(&client->dev, "Soft reset failed\n"); + return error; + } + + mdelay(10); + + error = as5011_i2c_write(client, AS5011_CTRL1, + AS5011_CTRL1_LP_PULSED | + AS5011_CTRL1_LP_ACTIVE | + AS5011_CTRL1_INT_ACT_EN); + if (error < 0) { + dev_err(&client->dev, "Power config failed\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_CTRL2, + AS5011_CTRL2_INV_SPINNING); + if (error < 0) { + dev_err(&client->dev, "Can't invert spinning\n"); + return error; + } + + /* write threshold */ + error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + /* to free irq gpio in chip */ + error = as5011_i2c_read(client, AS5011_X_RES_INT, &value); + if (error < 0) { + dev_err(&client->dev, "Can't read i2c X resolution value\n"); + return error; + } + + return 0; +} + +static int __devinit as5011_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct as5011_platform_data *plat_data; + struct as5011_device *as5011; + struct input_dev *input_dev; + int irq; + int error; + + plat_data = client->dev.platform_data; + if (!plat_data) + return -EINVAL; + + if (!plat_data->axis_irq) { + dev_err(&client->dev, "No axis IRQ?\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_PROTOCOL_MANGLING)) { + dev_err(&client->dev, + "need i2c bus that supports protocol mangling\n"); + return -ENODEV; + } + + as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!as5011 || !input_dev) { + dev_err(&client->dev, + "Can't allocate memory for device structure\n"); + error = -ENOMEM; + goto err_free_mem; + } + + as5011->i2c_client = client; + as5011->input_dev = input_dev; + as5011->button_gpio = plat_data->button_gpio; + as5011->axis_irq = plat_data->axis_irq; + + input_dev->name = "Austria Microsystem as5011 joystick"; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(BTN_JOYSTICK, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_X, + AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); + input_set_abs_params(as5011->input_dev, ABS_Y, + AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); + + error = gpio_request(as5011->button_gpio, "AS5011 button"); + if (error < 0) { + dev_err(&client->dev, "Failed to request button gpio\n"); + goto err_free_mem; + } + + irq = gpio_to_irq(as5011->button_gpio); + if (irq < 0) { + dev_err(&client->dev, + "Failed to get irq number for button gpio\n"); + goto err_free_button_gpio; + } + + as5011->button_irq = irq; + + error = request_threaded_irq(as5011->button_irq, + NULL, as5011_button_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "as5011_button", as5011); + if (error < 0) { + dev_err(&client->dev, + "Can't allocate button irq %d\n", as5011->button_irq); + goto err_free_button_gpio; + } + + error = as5011_configure_chip(as5011, plat_data); + if (error) + goto err_free_button_irq; + + error = request_threaded_irq(as5011->axis_irq, NULL, + as5011_axis_interrupt, + plat_data->axis_irqflags, + "as5011_joystick", as5011); + if (error) { + dev_err(&client->dev, + "Can't allocate axis irq %d\n", plat_data->axis_irq); + goto err_free_button_irq; + } + + error = input_register_device(as5011->input_dev); + if (error) { + dev_err(&client->dev, "Failed to register input device\n"); + goto err_free_axis_irq; + } + + i2c_set_clientdata(client, as5011); + + return 0; + +err_free_axis_irq: + free_irq(as5011->axis_irq, as5011); +err_free_button_irq: + free_irq(as5011->button_irq, as5011); +err_free_button_gpio: + gpio_free(as5011->button_gpio); +err_free_mem: + input_free_device(input_dev); + kfree(as5011); + + return error; +} + +static int __devexit as5011_remove(struct i2c_client *client) +{ + struct as5011_device *as5011 = i2c_get_clientdata(client); + + free_irq(as5011->axis_irq, as5011); + free_irq(as5011->button_irq, as5011); + gpio_free(as5011->button_gpio); + + input_unregister_device(as5011->input_dev); + kfree(as5011); + + return 0; +} + +static const struct i2c_device_id as5011_id[] = { + { MODULE_DEVICE_ALIAS, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as5011_id); + +static struct i2c_driver as5011_driver = { + .driver = { + .name = "as5011", + }, + .probe = as5011_probe, + .remove = __devexit_p(as5011_remove), + .id_table = as5011_id, +}; + +static int __init as5011_init(void) +{ + return i2c_add_driver(&as5011_driver); +} +module_init(as5011_init); + +static void __exit as5011_exit(void) +{ + i2c_del_driver(&as5011_driver); +} +module_exit(as5011_exit); diff --git a/include/linux/input/as5011.h b/include/linux/input/as5011.h new file mode 100644 index 000000000000..1affd0ddfa9d --- /dev/null +++ b/include/linux/input/as5011.h @@ -0,0 +1,20 @@ +#ifndef _AS5011_H +#define _AS5011_H + +/* + * Copyright (c) 2010, 2011 Fabien Marteau + * + * 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. + */ + +struct as5011_platform_data { + unsigned int button_gpio; + unsigned int axis_irq; /* irq number */ + unsigned long axis_irqflags; + char xp, xn; /* threshold for x axis */ + char yp, yn; /* threshold for y axis */ +}; + +#endif /* _AS5011_H */ -- cgit v1.2.3 From 7571f089d7522a95c103558faf313c7af8856ceb Mon Sep 17 00:00:00 2001 From: Márton Németh Date: Mon, 13 Dec 2010 21:59:09 +0100 Subject: staging: usbip: remove double giveback of URB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the vhci_urb_dequeue() function the TCP connection is checked twice. Each time when the TCP connection is closed the URB is unlinked and given back. Remove the second attempt of unlinking and giving back of the URB completely. This patch fixes the bug described at https://bugzilla.kernel.org/show_bug.cgi?id=24872 . Signed-off-by: Márton Németh Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/vhci_hcd.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 832608d3e579..08bd26a245d5 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -799,20 +799,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) spin_unlock_irqrestore(&vdev->priv_lock, flags2); } - - if (!vdev->ud.tcp_socket) { - /* tcp connection is closed */ - usbip_uinfo("vhci_hcd: vhci_urb_dequeue() gives back urb %p\n", - urb); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - - spin_unlock_irqrestore(&the_controller->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); - spin_lock_irqsave(&the_controller->lock, flags); - } - spin_unlock_irqrestore(&the_controller->lock, flags); usbip_dbg_vhci_hc("leave\n"); -- cgit v1.2.3 From 7959d55679e4360205c9ebc89d40a5503c53bae2 Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Thu, 16 Dec 2010 13:26:58 -0600 Subject: staging: speakup: fix failure handling fix the failure handling in kobjects and the main function so that we release the virtual keyboard if we exit due to another failure. Signed-off-by: William Hubbs Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/kobjects.c | 9 ++++++--- drivers/staging/speakup/main.c | 33 +++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c index cc79f9edfe9e..408bb9b3303e 100644 --- a/drivers/staging/speakup/kobjects.c +++ b/drivers/staging/speakup/kobjects.c @@ -984,8 +984,10 @@ int speakup_kobj_init(void) * not known ahead of time. */ accessibility_kobj = kobject_create_and_add("accessibility", NULL); - if (!accessibility_kobj) - return -ENOMEM; + if (!accessibility_kobj) { + retval = -ENOMEM; + goto out; + } speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj); if (!speakup_kobj) { @@ -1002,7 +1004,7 @@ int speakup_kobj_init(void) if (retval) goto err_group; - return 0; + goto out; err_group: sysfs_remove_group(speakup_kobj, &main_attr_group); @@ -1010,6 +1012,7 @@ err_speakup: kobject_put(speakup_kobj); err_acc: kobject_put(accessibility_kobj); +out: return retval; } diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index 4b7a9c2b965f..3cd00396a462 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -2253,17 +2253,17 @@ static int __init speakup_init(void) err = speakup_add_virtual_keyboard(); if (err) - return err; + goto out; initialize_msgs(); /* Initialize arrays for i18n. */ first_console = kzalloc(sizeof(*first_console), GFP_KERNEL); - if (!first_console) - return -ENOMEM; - err = speakup_kobj_init(); - if (err) { - kfree(first_console); - return err; + if (!first_console) { + err = -ENOMEM; + goto err_cons; } + err = speakup_kobj_init(); + if (err) + goto err_kobject; reset_default_chars(); reset_default_chartab(); @@ -2299,11 +2299,20 @@ static int __init speakup_init(void) speakup_task = kthread_create(speakup_thread, NULL, "speakup"); set_user_nice(speakup_task, 10); - if (!IS_ERR(speakup_task)) - wake_up_process(speakup_task); - else - return -ENOMEM; - return 0; + if (IS_ERR(speakup_task)) { + err = -ENOMEM; + goto err_kobject; + } + wake_up_process(speakup_task); + goto out; + +err_kobject: +speakup_kobj_exit(); + kfree(first_console); +err_cons: + speakup_remove_virtual_keyboard(); +out: + return err; } module_init(speakup_init); -- cgit v1.2.3 From 536ae14e7588e85203d4b4147c041309be5b3efb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 26 Nov 2010 13:58:27 -0500 Subject: IB/srp: don't move active requests to their own list We use req->scmnd != NULL to indicate an active request, so there's no need to keep a separate list for them. We can afford the array iteration during error handling, and dropping it gives us one less item that needs lock protection. Signed-off-by: Bart Van Assche [ broken out and small cleanups by David Dillow ] Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 23 +++++++++++++---------- drivers/infiniband/ulp/srp/ib_srp.h | 1 - 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index aa78d2615c8d..2aff8814f2c5 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -553,7 +553,7 @@ static void srp_remove_req(struct srp_target_port *target, struct srp_request *r { srp_unmap_data(req->scmnd, target, req); req->scmnd = NULL; - list_move_tail(&req->list, &target->free_reqs); + list_add_tail(&req->list, &target->free_reqs); } static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) @@ -566,7 +566,6 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re static int srp_reconnect_target(struct srp_target_port *target) { struct ib_qp_attr qp_attr; - struct srp_request *req, *tmp; struct ib_wc wc; int i, ret; @@ -597,13 +596,16 @@ static int srp_reconnect_target(struct srp_target_port *target) ; /* nothing */ spin_lock_irq(target->scsi_host->host_lock); - list_for_each_entry_safe(req, tmp, &target->req_queue, list) - srp_reset_req(target, req); + for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { + struct srp_request *req = &target->req_ring[i]; + if (req->scmnd) + srp_reset_req(target, req); + } spin_unlock_irq(target->scsi_host->host_lock); - list_del_init(&target->free_tx); + INIT_LIST_HEAD(&target->free_tx); for (i = 0; i < SRP_SQ_SIZE; ++i) - list_move(&target->tx_ring[i]->list, &target->free_tx); + list_add(&target->tx_ring[i]->list, &target->free_tx); target->qp_in_error = 0; ret = srp_connect_target(target); @@ -1165,7 +1167,7 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, goto err_unmap; } - list_move_tail(&req->list, &target->req_queue); + list_del(&req->list); return 0; @@ -1504,7 +1506,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) static int srp_reset_device(struct scsi_cmnd *scmnd) { struct srp_target_port *target = host_to_target(scmnd->device->host); - struct srp_request *req, *tmp; + int i; shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); @@ -1518,9 +1520,11 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) spin_lock_irq(target->scsi_host->host_lock); - list_for_each_entry_safe(req, tmp, &target->req_queue, list) + for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { + struct srp_request *req = &target->req_ring[i]; if (req->scmnd && req->scmnd->device == scmnd->device) srp_reset_req(target, req); + } spin_unlock_irq(target->scsi_host->host_lock); @@ -1954,7 +1958,6 @@ static ssize_t srp_create_target(struct device *dev, INIT_LIST_HEAD(&target->free_tx); INIT_LIST_HEAD(&target->free_reqs); - INIT_LIST_HEAD(&target->req_queue); for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { target->req_ring[i].index = i; list_add_tail(&target->req_ring[i].list, &target->free_reqs); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 41ecb46adf15..924d8e9c6672 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -148,7 +148,6 @@ struct srp_target_port { struct srp_iu *tx_ring[SRP_SQ_SIZE]; struct list_head free_reqs; - struct list_head req_queue; struct srp_request req_ring[SRP_CMD_SQ_SIZE]; struct work_struct work; -- cgit v1.2.3 From 76c75b258f1fe6abac6af2356989ad4d6518886e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 26 Nov 2010 14:37:47 -0500 Subject: IB/srp: reduce local coverage for command submission and EH We only need locks to protect our lists and number of credits available. By pre-consuming the credit for the request, we can reduce our lock coverage to just those areas. If we don't actually send the request, we'll need to put the credit back into the pool. Signed-off-by: Bart Van Assche [ broken out and small cleanups by David Dillow ] Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 124 +++++++++++++++++++----------------- drivers/infiniband/ulp/srp/ib_srp.h | 1 - 2 files changed, 67 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 2aff8814f2c5..e5bd181dbce5 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -817,10 +817,25 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, return len; } +/* + * Return an IU and possible credit to the free pool + */ +static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu, + enum srp_iu_type iu_type) +{ + unsigned long flags; + + spin_lock_irqsave(target->scsi_host->host_lock, flags); + list_add(&iu->list, &target->free_tx); + if (iu_type != SRP_IU_RSP) + ++target->req_lim; + spin_unlock_irqrestore(target->scsi_host->host_lock, flags); +} + /* * Must be called with target->scsi_host->host_lock held to protect - * req_lim and free_tx. Lock cannot be dropped between call here and - * call to __srp_post_send(). + * req_lim and free_tx. If IU is not sent, it must be returned using + * srp_put_tx_iu(). * * Note: * An upper limit for the number of allocated information units for each @@ -843,26 +858,25 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, return NULL; /* Initiator responses to target requests do not consume credits */ - if (target->req_lim <= rsv && iu_type != SRP_IU_RSP) { - ++target->zero_req_lim; - return NULL; + if (iu_type != SRP_IU_RSP) { + if (target->req_lim <= rsv) { + ++target->zero_req_lim; + return NULL; + } + + --target->req_lim; } iu = list_first_entry(&target->free_tx, struct srp_iu, list); - iu->type = iu_type; + list_del(&iu->list); return iu; } -/* - * Must be called with target->scsi_host->host_lock held to protect - * req_lim and free_tx. - */ -static int __srp_post_send(struct srp_target_port *target, - struct srp_iu *iu, int len) +static int srp_post_send(struct srp_target_port *target, + struct srp_iu *iu, int len) { struct ib_sge list; struct ib_send_wr wr, *bad_wr; - int ret = 0; list.addr = iu->dma; list.length = len; @@ -875,15 +889,7 @@ static int __srp_post_send(struct srp_target_port *target, wr.opcode = IB_WR_SEND; wr.send_flags = IB_SEND_SIGNALED; - ret = ib_post_send(target->qp, &wr, &bad_wr); - - if (!ret) { - list_del(&iu->list); - if (iu->type != SRP_IU_RSP) - --target->req_lim; - } - - return ret; + return ib_post_send(target->qp, &wr, &bad_wr); } static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) @@ -953,34 +959,33 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) static int srp_response_common(struct srp_target_port *target, s32 req_delta, void *rsp, int len) { - struct ib_device *dev; + struct ib_device *dev = target->srp_host->srp_dev->dev; unsigned long flags; struct srp_iu *iu; - int err = 1; - - dev = target->srp_host->srp_dev->dev; + int err; spin_lock_irqsave(target->scsi_host->host_lock, flags); target->req_lim += req_delta; - iu = __srp_get_tx_iu(target, SRP_IU_RSP); + spin_unlock_irqrestore(target->scsi_host->host_lock, flags); + if (!iu) { shost_printk(KERN_ERR, target->scsi_host, PFX "no IU available to send response\n"); - goto out; + return 1; } ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); memcpy(iu->buf, rsp, len); ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); - err = __srp_post_send(target, iu, len); - if (err) + err = srp_post_send(target, iu, len); + if (err) { shost_printk(KERN_ERR, target->scsi_host, PFX "unable to post response: %d\n", err); + srp_put_tx_iu(target, iu, SRP_IU_RSP); + } -out: - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); return err; } @@ -1107,14 +1112,14 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) } } -static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, - void (*done)(struct scsi_cmnd *)) +static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) { - struct srp_target_port *target = host_to_target(scmnd->device->host); + struct srp_target_port *target = host_to_target(shost); struct srp_request *req; struct srp_iu *iu; struct srp_cmd *cmd; struct ib_device *dev; + unsigned long flags; int len; if (target->state == SRP_TARGET_CONNECTING) @@ -1123,11 +1128,19 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) { scmnd->result = DID_BAD_TARGET << 16; - done(scmnd); + scmnd->scsi_done(scmnd); return 0; } + spin_lock_irqsave(shost->host_lock, flags); iu = __srp_get_tx_iu(target, SRP_IU_CMD); + if (iu) { + req = list_first_entry(&target->free_reqs, struct srp_request, + list); + list_del(&req->list); + } + spin_unlock_irqrestore(shost->host_lock, flags); + if (!iu) goto err; @@ -1135,9 +1148,6 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len, DMA_TO_DEVICE); - req = list_first_entry(&target->free_reqs, struct srp_request, list); - - scmnd->scsi_done = done; scmnd->result = 0; scmnd->host_scribble = (void *) req; @@ -1156,30 +1166,33 @@ static int srp_queuecommand_lck(struct scsi_cmnd *scmnd, if (len < 0) { shost_printk(KERN_ERR, target->scsi_host, PFX "Failed to map data\n"); - goto err; + goto err_iu; } ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len, DMA_TO_DEVICE); - if (__srp_post_send(target, iu, len)) { + if (srp_post_send(target, iu, len)) { shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); goto err_unmap; } - list_del(&req->list); - return 0; err_unmap: srp_unmap_data(scmnd, target, req); +err_iu: + srp_put_tx_iu(target, iu, SRP_IU_CMD); + + spin_lock_irqsave(shost->host_lock, flags); + list_add(&req->list, &target->free_reqs); + spin_unlock_irqrestore(shost->host_lock, flags); + err: return SCSI_MLQUEUE_HOST_BUSY; } -static DEF_SCSI_QCMD(srp_queuecommand) - static int srp_alloc_iu_bufs(struct srp_target_port *target) { int i; @@ -1433,17 +1446,18 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; - spin_lock_irq(target->scsi_host->host_lock); - if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) - goto out; + return -1; init_completion(&target->tsk_mgmt_done); + spin_lock_irq(target->scsi_host->host_lock); iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); + spin_unlock_irq(target->scsi_host->host_lock); + if (!iu) - goto out; + return -1; ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, DMA_TO_DEVICE); @@ -1458,20 +1472,16 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, DMA_TO_DEVICE); - if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) - goto out; - - spin_unlock_irq(target->scsi_host->host_lock); + if (srp_post_send(target, iu, sizeof *tsk_mgmt)) { + srp_put_tx_iu(target, iu, SRP_IU_TSK_MGMT); + return -1; + } if (!wait_for_completion_timeout(&target->tsk_mgmt_done, msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) return -1; return 0; - -out: - spin_unlock_irq(target->scsi_host->host_lock); - return -1; } static int srp_abort(struct scsi_cmnd *scmnd) diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 924d8e9c6672..81686eee7e62 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -168,7 +168,6 @@ struct srp_iu { void *buf; size_t size; enum dma_data_direction direction; - enum srp_iu_type type; }; #endif /* IB_SRP_H */ -- cgit v1.2.3 From 94a9174c630c8465ed9e97ecd242993429930c05 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 26 Nov 2010 14:50:09 -0500 Subject: IB/srp: reduce lock coverage of command completion We only need the lock to cover list and credit manipulations, so push those into srp_remove_req() and update the call chains. We reorder the request removal and command completion in srp_process_rsp() to avoid the SCSI mid-layer sending another command before we've released our request and added any credits returned by the target. This prevents us from returning HOST_BUSY unneccesarily. Signed-off-by: Bart Van Assche [ broken out, small cleanups, and modified to avoid potential extraneous HOST_BUSY returns by David Dillow ] Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index e5bd181dbce5..e76fe54faeea 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -549,18 +549,24 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, scsi_sg_count(scmnd), scmnd->sc_data_direction); } -static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) +static void srp_remove_req(struct srp_target_port *target, + struct srp_request *req, s32 req_lim_delta) { + unsigned long flags; + srp_unmap_data(req->scmnd, target, req); + spin_lock_irqsave(target->scsi_host->host_lock, flags); + target->req_lim += req_lim_delta; req->scmnd = NULL; list_add_tail(&req->list, &target->free_reqs); + spin_unlock_irqrestore(target->scsi_host->host_lock, flags); } static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) { req->scmnd->result = DID_RESET << 16; req->scmnd->scsi_done(req->scmnd); - srp_remove_req(target, req); + srp_remove_req(target, req, 0); } static int srp_reconnect_target(struct srp_target_port *target) @@ -595,13 +601,11 @@ static int srp_reconnect_target(struct srp_target_port *target) while (ib_poll_cq(target->send_cq, 1, &wc) > 0) ; /* nothing */ - spin_lock_irq(target->scsi_host->host_lock); for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { struct srp_request *req = &target->req_ring[i]; if (req->scmnd) srp_reset_req(target, req); } - spin_unlock_irq(target->scsi_host->host_lock); INIT_LIST_HEAD(&target->free_tx); for (i = 0; i < SRP_SQ_SIZE; ++i) @@ -914,15 +918,12 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) struct srp_request *req; struct scsi_cmnd *scmnd; unsigned long flags; - s32 delta; - - delta = (s32) be32_to_cpu(rsp->req_lim_delta); - - spin_lock_irqsave(target->scsi_host->host_lock, flags); - - target->req_lim += delta; if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { + spin_lock_irqsave(target->scsi_host->host_lock, flags); + target->req_lim += be32_to_cpu(rsp->req_lim_delta); + spin_unlock_irqrestore(target->scsi_host->host_lock, flags); + target->tsk_mgmt_status = -1; if (be32_to_cpu(rsp->resp_data_len) >= 4) target->tsk_mgmt_status = rsp->data[3]; @@ -948,12 +949,10 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); + srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta)); scmnd->host_scribble = NULL; scmnd->scsi_done(scmnd); - srp_remove_req(target, req); } - - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); } static int srp_response_common(struct srp_target_port *target, s32 req_delta, @@ -1498,18 +1497,14 @@ static int srp_abort(struct scsi_cmnd *scmnd) SRP_TSK_ABORT_TASK)) return FAILED; - spin_lock_irq(target->scsi_host->host_lock); - if (req->scmnd) { if (!target->tsk_mgmt_status) { - srp_remove_req(target, req); + srp_remove_req(target, req, 0); scmnd->result = DID_ABORT << 16; } else ret = FAILED; } - spin_unlock_irq(target->scsi_host->host_lock); - return ret; } @@ -1528,16 +1523,12 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) if (target->tsk_mgmt_status) return FAILED; - spin_lock_irq(target->scsi_host->host_lock); - for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { struct srp_request *req = &target->req_ring[i]; if (req->scmnd && req->scmnd->device == scmnd->device) srp_reset_req(target, req); } - spin_unlock_irq(target->scsi_host->host_lock); - return SUCCESS; } -- cgit v1.2.3 From e9684678221441f886b4d7c74f8770bb0981737a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 26 Nov 2010 15:08:38 -0500 Subject: IB/srp: stop sharing the host lock with SCSI We don't need protection against the SCSI stack, so use our own lock to allow parallel progress on separate CPUs. Signed-off-by: Bart Van Assche [ broken out and small cleanups by David Dillow ] Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 46 ++++++++++++++++++------------------- drivers/infiniband/ulp/srp/ib_srp.h | 2 ++ 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index e76fe54faeea..8691fc83f70b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -447,12 +447,12 @@ static bool srp_change_state(struct srp_target_port *target, { bool changed = false; - spin_lock_irq(target->scsi_host->host_lock); + spin_lock_irq(&target->lock); if (target->state == old) { target->state = new; changed = true; } - spin_unlock_irq(target->scsi_host->host_lock); + spin_unlock_irq(&target->lock); return changed; } @@ -555,11 +555,11 @@ static void srp_remove_req(struct srp_target_port *target, unsigned long flags; srp_unmap_data(req->scmnd, target, req); - spin_lock_irqsave(target->scsi_host->host_lock, flags); + spin_lock_irqsave(&target->lock, flags); target->req_lim += req_lim_delta; req->scmnd = NULL; list_add_tail(&req->list, &target->free_reqs); - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); + spin_unlock_irqrestore(&target->lock, flags); } static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) @@ -634,13 +634,13 @@ err: * Schedule our work inside the lock to avoid a race with * the flush_scheduled_work() in srp_remove_one(). */ - spin_lock_irq(target->scsi_host->host_lock); + spin_lock_irq(&target->lock); if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; INIT_WORK(&target->work, srp_remove_work); schedule_work(&target->work); } - spin_unlock_irq(target->scsi_host->host_lock); + spin_unlock_irq(&target->lock); return ret; } @@ -829,17 +829,16 @@ static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu, { unsigned long flags; - spin_lock_irqsave(target->scsi_host->host_lock, flags); + spin_lock_irqsave(&target->lock, flags); list_add(&iu->list, &target->free_tx); if (iu_type != SRP_IU_RSP) ++target->req_lim; - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); + spin_unlock_irqrestore(&target->lock, flags); } /* - * Must be called with target->scsi_host->host_lock held to protect - * req_lim and free_tx. If IU is not sent, it must be returned using - * srp_put_tx_iu(). + * Must be called with target->lock held to protect req_lim and free_tx. + * If IU is not sent, it must be returned using srp_put_tx_iu(). * * Note: * An upper limit for the number of allocated information units for each @@ -920,9 +919,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) unsigned long flags; if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { - spin_lock_irqsave(target->scsi_host->host_lock, flags); + spin_lock_irqsave(&target->lock, flags); target->req_lim += be32_to_cpu(rsp->req_lim_delta); - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); + spin_unlock_irqrestore(&target->lock, flags); target->tsk_mgmt_status = -1; if (be32_to_cpu(rsp->resp_data_len) >= 4) @@ -963,10 +962,10 @@ static int srp_response_common(struct srp_target_port *target, s32 req_delta, struct srp_iu *iu; int err; - spin_lock_irqsave(target->scsi_host->host_lock, flags); + spin_lock_irqsave(&target->lock, flags); target->req_lim += req_delta; iu = __srp_get_tx_iu(target, SRP_IU_RSP); - spin_unlock_irqrestore(target->scsi_host->host_lock, flags); + spin_unlock_irqrestore(&target->lock, flags); if (!iu) { shost_printk(KERN_ERR, target->scsi_host, PFX @@ -1131,14 +1130,14 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) return 0; } - spin_lock_irqsave(shost->host_lock, flags); + spin_lock_irqsave(&target->lock, flags); iu = __srp_get_tx_iu(target, SRP_IU_CMD); if (iu) { req = list_first_entry(&target->free_reqs, struct srp_request, list); list_del(&req->list); } - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(&target->lock, flags); if (!iu) goto err; @@ -1184,9 +1183,9 @@ err_unmap: err_iu: srp_put_tx_iu(target, iu, SRP_IU_CMD); - spin_lock_irqsave(shost->host_lock, flags); + spin_lock_irqsave(&target->lock, flags); list_add(&req->list, &target->free_reqs); - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(&target->lock, flags); err: return SCSI_MLQUEUE_HOST_BUSY; @@ -1451,9 +1450,9 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, init_completion(&target->tsk_mgmt_done); - spin_lock_irq(target->scsi_host->host_lock); + spin_lock_irq(&target->lock); iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); - spin_unlock_irq(target->scsi_host->host_lock); + spin_unlock_irq(&target->lock); if (!iu) return -1; @@ -1957,6 +1956,7 @@ static ssize_t srp_create_target(struct device *dev, target->scsi_host = target_host; target->srp_host = host; + spin_lock_init(&target->lock); INIT_LIST_HEAD(&target->free_tx); INIT_LIST_HEAD(&target->free_reqs); for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { @@ -2186,9 +2186,9 @@ static void srp_remove_one(struct ib_device *device) */ spin_lock(&host->target_lock); list_for_each_entry(target, &host->target_list, list) { - spin_lock_irq(target->scsi_host->host_lock); + spin_lock_irq(&target->lock); target->state = SRP_TARGET_REMOVED; - spin_unlock_irq(target->scsi_host->host_lock); + spin_unlock_irq(&target->lock); } spin_unlock(&host->target_lock); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 81686eee7e62..acb435d3c1e3 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -144,6 +144,8 @@ struct srp_target_port { struct srp_iu *rx_ring[SRP_RQ_SIZE]; + spinlock_t lock; + struct list_head free_tx; struct srp_iu *tx_ring[SRP_SQ_SIZE]; -- cgit v1.2.3 From 9af762719e8f8fa282de02997dced593030eb238 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Fri, 26 Nov 2010 15:34:46 -0500 Subject: IB/srp: consolidate hot-path variables into cache lines Put the variables accessed together in the hot-path into common cachelines, and separate them by RW vs RO to avoid false dirtying. We keep a local copy of the lkey and rkey in the target to avoid traversing pointers (and associated cache lines) to find them. Reviewed-by: Bart Van Assche Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 12 +++++++----- drivers/infiniband/ulp/srp/ib_srp.h | 31 +++++++++++++++++++------------ 2 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 8691fc83f70b..4b62105ed1e8 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -768,7 +768,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, struct srp_direct_buf *buf = (void *) cmd->add_data; buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); - buf->key = cpu_to_be32(dev->mr->rkey); + buf->key = cpu_to_be32(target->rkey); buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); } else if (srp_map_fmr(target, scat, count, req, (void *) cmd->add_data)) { @@ -793,7 +793,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, buf->desc_list[i].va = cpu_to_be64(ib_sg_dma_address(ibdev, sg)); buf->desc_list[i].key = - cpu_to_be32(dev->mr->rkey); + cpu_to_be32(target->rkey); buf->desc_list[i].len = cpu_to_be32(dma_len); datalen += dma_len; } @@ -806,7 +806,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, buf->table_desc.va = cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf); buf->table_desc.key = - cpu_to_be32(target->srp_host->srp_dev->mr->rkey); + cpu_to_be32(target->rkey); buf->table_desc.len = cpu_to_be32(count * sizeof (struct srp_direct_buf)); @@ -883,7 +883,7 @@ static int srp_post_send(struct srp_target_port *target, list.addr = iu->dma; list.length = len; - list.lkey = target->srp_host->srp_dev->mr->lkey; + list.lkey = target->lkey; wr.next = NULL; wr.wr_id = (uintptr_t) iu; @@ -902,7 +902,7 @@ static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) list.addr = iu->dma; list.length = iu->size; - list.lkey = target->srp_host->srp_dev->mr->lkey; + list.lkey = target->lkey; wr.next = NULL; wr.wr_id = (uintptr_t) iu; @@ -1955,6 +1955,8 @@ static ssize_t srp_create_target(struct device *dev, target->io_class = SRP_REV16A_IB_IO_CLASS; target->scsi_host = target_host; target->srp_host = host; + target->lkey = host->srp_dev->mr->lkey; + target->rkey = host->srp_dev->mr->rkey; spin_lock_init(&target->lock); INIT_LIST_HEAD(&target->free_tx); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index acb435d3c1e3..9dc6fc3fd894 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -117,6 +117,24 @@ struct srp_request { }; struct srp_target_port { + /* These are RW in the hot path, and commonly used together */ + struct list_head free_tx; + struct list_head free_reqs; + spinlock_t lock; + s32 req_lim; + + /* These are read-only in the hot path */ + struct ib_cq *send_cq ____cacheline_aligned_in_smp; + struct ib_cq *recv_cq; + struct ib_qp *qp; + u32 lkey; + u32 rkey; + enum srp_target_state state; + + /* Everything above this point is used in the hot path of + * command processing. Try to keep them packed into cachelines. + */ + __be64 id_ext; __be64 ioc_guid; __be64 service_id; @@ -133,23 +151,13 @@ struct srp_target_port { int path_query_id; struct ib_cm_id *cm_id; - struct ib_cq *recv_cq; - struct ib_cq *send_cq; - struct ib_qp *qp; int max_ti_iu_len; - s32 req_lim; int zero_req_lim; - struct srp_iu *rx_ring[SRP_RQ_SIZE]; - - spinlock_t lock; - - struct list_head free_tx; struct srp_iu *tx_ring[SRP_SQ_SIZE]; - - struct list_head free_reqs; + struct srp_iu *rx_ring[SRP_RQ_SIZE]; struct srp_request req_ring[SRP_CMD_SQ_SIZE]; struct work_struct work; @@ -157,7 +165,6 @@ struct srp_target_port { struct list_head list; struct completion done; int status; - enum srp_target_state state; int qp_in_error; struct completion tsk_mgmt_done; -- cgit v1.2.3 From e6e1ee936d61d697735d17517678a626b7701ce4 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 10 Jan 2011 21:50:33 +0100 Subject: cciss: reinstate proper FIFO order of command queue list Commit 8a3173de inadvertently changed the ordering when switching to hlists. Change to regular list heads so we can use tail list adds, this improves performance. Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 23 +++++++++++------------ drivers/block/cciss.h | 4 ++-- drivers/block/cciss_cmd.h | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5e4fadcdece9..a54f7f4b91f6 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -266,9 +266,9 @@ static void set_performant_mode(ctlr_info_t *h, CommandList_struct *c) /* * Enqueuing and dequeuing functions for cmdlists. */ -static inline void addQ(struct hlist_head *list, CommandList_struct *c) +static inline void addQ(struct list_head *list, CommandList_struct *c) { - hlist_add_head(&c->list, list); + list_add_tail(&c->list, list); } static inline void removeQ(CommandList_struct *c) @@ -281,12 +281,12 @@ static inline void removeQ(CommandList_struct *c) * them off as 'stale' to prevent the driver from * falling over. */ - if (WARN_ON(hlist_unhashed(&c->list))) { + if (WARN_ON(list_empty(&c->list))) { c->cmd_type = CMD_MSG_STALE; return; } - hlist_del_init(&c->list); + list_del_init(&c->list); } static void enqueue_cmd_and_start_io(ctlr_info_t *h, @@ -935,7 +935,7 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h) c->cmdindex = i; - INIT_HLIST_NODE(&c->list); + INIT_LIST_HEAD(&c->list); c->busaddr = (__u32) cmd_dma_handle; temp64.val = (__u64) err_dma_handle; c->ErrDesc.Addr.lower = temp64.val32.lower; @@ -974,7 +974,7 @@ static CommandList_struct *cmd_special_alloc(ctlr_info_t *h) } memset(c->err_info, 0, sizeof(ErrorInfo_struct)); - INIT_HLIST_NODE(&c->list); + INIT_LIST_HEAD(&c->list); c->busaddr = (__u32) cmd_dma_handle; temp64.val = (__u64) err_dma_handle; c->ErrDesc.Addr.lower = temp64.val32.lower; @@ -2933,8 +2933,8 @@ static void start_io(ctlr_info_t *h) { CommandList_struct *c; - while (!hlist_empty(&h->reqQ)) { - c = hlist_entry(h->reqQ.first, CommandList_struct, list); + while (!list_empty(&h->reqQ)) { + c = list_entry(h->reqQ.next, CommandList_struct, list); /* can't do anything if fifo is full */ if ((h->access.fifo_full(h))) { dev_warn(&h->pdev->dev, "fifo full\n"); @@ -3447,11 +3447,10 @@ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag) { u32 tag; CommandList_struct *c = NULL; - struct hlist_node *tmp; __u32 busaddr_masked, tag_masked; tag = cciss_tag_discard_error_bits(raw_tag); - hlist_for_each_entry(c, tmp, &h->cmpQ, list) { + list_for_each_entry(c, &h->cmpQ, list) { busaddr_masked = cciss_tag_discard_error_bits(c->busaddr); tag_masked = cciss_tag_discard_error_bits(tag); if (busaddr_masked == tag_masked) { @@ -4632,8 +4631,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, h = hba[i]; h->pdev = pdev; h->busy_initializing = 1; - INIT_HLIST_HEAD(&h->cmpQ); - INIT_HLIST_HEAD(&h->reqQ); + INIT_LIST_HEAD(&h->cmpQ); + INIT_LIST_HEAD(&h->reqQ); mutex_init(&h->busy_shutting_down); if (cciss_pci_init(h) != 0) diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index ae340ffc8f81..7915dd473148 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -103,8 +103,8 @@ struct ctlr_info struct access_method access; /* queue and queue Info */ - struct hlist_head reqQ; - struct hlist_head cmpQ; + struct list_head reqQ; + struct list_head cmpQ; unsigned int Qdepth; unsigned int maxQsinceinit; unsigned int maxSG; diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index eb060f1b00b6..35463d2f0ee7 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -195,7 +195,7 @@ typedef struct _CommandList_struct { int ctlr; int cmd_type; long cmdindex; - struct hlist_node list; + struct list_head list; struct request * rq; struct completion *waiting; int retry_count; -- cgit v1.2.3 From 665a96b70bfccec6eab2e8d3c770e357e14294ea Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 10 Jan 2011 22:11:22 +0100 Subject: i2c-i801: Include Commit 5a0e3ad6af8660be21ca98a971cd00f331318c05 added direct inclusion of to those source files that appeared to need it, but somehow missed this. On most architectures is still indirectly included, but there are exceptions such as alpha. Signed-off-by: Ben Hutchings Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 02835ce7ff4b..7979aef7ee7b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -72,6 +72,7 @@ #include #include #include +#include /* I801 SMBus address offsets */ #define SMBHSTSTS(p) (0 + (p)->smba) -- cgit v1.2.3 From b18a5c80eb2e7e9c72d23f1960b09d78ddf7e5b0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 10 Jan 2011 22:11:22 +0100 Subject: i2c-nforce2: Remove unnecessary cast of pci_get_drvdata Signed-off-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-nforce2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index a605a5029cfe..ff1e127dfea8 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -432,7 +432,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ static void __devexit nforce2_remove(struct pci_dev *dev) { - struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev); + struct nforce2_smbus *smbuses = pci_get_drvdata(dev); nforce2_set_reference(NULL); if (smbuses[0].base) { -- cgit v1.2.3 From 92ed1a76ca31774eb27de14b2215841367c68056 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 10 Jan 2011 22:11:23 +0100 Subject: i2c: Add generic I2C multiplexer using GPIO API Add an i2c mux driver providing access to i2c bus segments using a hardware MUX sitting on a master bus and controlled through gpio pins. E.G. something like: ---------- ---------- Bus segment 1 - - - - - | | SCL/SDA | |-------------- | | | |------------| | | | | | Bus segment 2 | | | Linux | GPIO 1..N | MUX |--------------- Devices | |------------| | | | | | | | Bus segment M | | | |---------------| | ---------- ---------- - - - - - SCL/SDA of the master I2C bus is multiplexed to bus segment 1..M according to the settings of the GPIO pins 1..N. Signed-off-by: Peter Korsgaard Signed-off-by: Jean Delvare --- Documentation/i2c/muxes/gpio-i2cmux | 65 +++++++++++++ MAINTAINERS | 8 ++ drivers/i2c/muxes/Kconfig | 12 +++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/gpio-i2cmux.c | 184 ++++++++++++++++++++++++++++++++++++ include/linux/gpio-i2cmux.h | 38 ++++++++ 6 files changed, 308 insertions(+) create mode 100644 Documentation/i2c/muxes/gpio-i2cmux create mode 100644 drivers/i2c/muxes/gpio-i2cmux.c create mode 100644 include/linux/gpio-i2cmux.h (limited to 'drivers') diff --git a/Documentation/i2c/muxes/gpio-i2cmux b/Documentation/i2c/muxes/gpio-i2cmux new file mode 100644 index 000000000000..811cd78d4cdc --- /dev/null +++ b/Documentation/i2c/muxes/gpio-i2cmux @@ -0,0 +1,65 @@ +Kernel driver gpio-i2cmux + +Author: Peter Korsgaard + +Description +----------- + +gpio-i2cmux is an i2c mux driver providing access to I2C bus segments +from a master I2C bus and a hardware MUX controlled through GPIO pins. + +E.G.: + + ---------- ---------- Bus segment 1 - - - - - + | | SCL/SDA | |-------------- | | + | |------------| | + | | | | Bus segment 2 | | + | Linux | GPIO 1..N | MUX |--------------- Devices + | |------------| | | | + | | | | Bus segment M + | | | |---------------| | + ---------- ---------- - - - - - + +SCL/SDA of the master I2C bus is multiplexed to bus segment 1..M +according to the settings of the GPIO pins 1..N. + +Usage +----- + +gpio-i2cmux uses the platform bus, so you need to provide a struct +platform_device with the platform_data pointing to a struct +gpio_i2cmux_platform_data with the I2C adapter number of the master +bus, the number of bus segments to create and the GPIO pins used +to control it. See include/linux/gpio-i2cmux.h for details. + +E.G. something like this for a MUX providing 4 bus segments +controlled through 3 GPIO pins: + +#include +#include + +static const unsigned myboard_gpiomux_gpios[] = { + AT91_PIN_PC26, AT91_PIN_PC25, AT91_PIN_PC24 +}; + +static const unsigned myboard_gpiomux_values[] = { + 0, 1, 2, 3 +}; + +static struct gpio_i2cmux_platform_data myboard_i2cmux_data = { + .parent = 1, + .base_nr = 2, /* optional */ + .values = myboard_gpiomux_values, + .n_values = ARRAY_SIZE(myboard_gpiomux_values), + .gpios = myboard_gpiomux_gpios, + .n_gpios = ARRAY_SIZE(myboard_gpiomux_gpios), + .idle = 4, /* optional */ +}; + +static struct platform_device myboard_i2cmux = { + .name = "gpio-i2cmux", + .id = 0, + .dev = { + .platform_data = &myboard_i2cmux_data, + }, +}; diff --git a/MAINTAINERS b/MAINTAINERS index 23d04363a195..23a4765ab8d2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2608,6 +2608,14 @@ S: Supported F: drivers/i2c/busses/i2c-gpio.c F: include/linux/i2c-gpio.h +GENERIC GPIO I2C MULTIPLEXER DRIVER +M: Peter Korsgaard +L: linux-i2c@vger.kernel.org +S: Supported +F: drivers/i2c/muxes/gpio-i2cmux.c +F: include/linux/gpio-i2cmux.h +F: Documentation/i2c/muxes/gpio-i2cmux + GENERIC HDLC (WAN) DRIVERS M: Krzysztof Halasa W: http://www.kernel.org/pub/linux/utils/net/hdlc/ diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 4d91d80bfd23..90b7a0163899 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -5,6 +5,18 @@ menu "Multiplexer I2C Chip support" depends on I2C_MUX +config I2C_MUX_GPIO + tristate "GPIO-based I2C multiplexer" + depends on GENERIC_GPIO + help + If you say yes to this option, support will be included for a + GPIO based I2C multiplexer. This driver provides access to + I2C busses connected through a MUX, which is controlled + through GPIO pins. + + This driver can also be built as a module. If so, the module + will be called gpio-i2cmux. + config I2C_MUX_PCA9541 tristate "NXP PCA9541 I2C Master Selector" depends on EXPERIMENTAL diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index d743806d9b42..4640436ea61f 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -1,6 +1,7 @@ # # Makefile for multiplexer I2C chip drivers. +obj-$(CONFIG_I2C_MUX_GPIO) += gpio-i2cmux.o obj-$(CONFIG_I2C_MUX_PCA9541) += pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o diff --git a/drivers/i2c/muxes/gpio-i2cmux.c b/drivers/i2c/muxes/gpio-i2cmux.c new file mode 100644 index 000000000000..7b6ce624cd6e --- /dev/null +++ b/drivers/i2c/muxes/gpio-i2cmux.c @@ -0,0 +1,184 @@ +/* + * I2C multiplexer using GPIO API + * + * Peter Korsgaard + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct gpiomux { + struct i2c_adapter *parent; + struct i2c_adapter **adap; /* child busses */ + struct gpio_i2cmux_platform_data data; +}; + +static void gpiomux_set(const struct gpiomux *mux, unsigned val) +{ + int i; + + for (i = 0; i < mux->data.n_gpios; i++) + gpio_set_value(mux->data.gpios[i], val & (1 << i)); +} + +static int gpiomux_select(struct i2c_adapter *adap, void *data, u32 chan) +{ + struct gpiomux *mux = data; + + gpiomux_set(mux, mux->data.values[chan]); + + return 0; +} + +static int gpiomux_deselect(struct i2c_adapter *adap, void *data, u32 chan) +{ + struct gpiomux *mux = data; + + gpiomux_set(mux, mux->data.idle); + + return 0; +} + +static int __devinit gpiomux_probe(struct platform_device *pdev) +{ + struct gpiomux *mux; + struct gpio_i2cmux_platform_data *pdata; + struct i2c_adapter *parent; + int (*deselect) (struct i2c_adapter *, void *, u32); + unsigned initial_state; + int i, ret; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENODEV; + } + + parent = i2c_get_adapter(pdata->parent); + if (!parent) { + dev_err(&pdev->dev, "Parent adapter (%d) not found\n", + pdata->parent); + return -ENODEV; + } + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) { + ret = -ENOMEM; + goto alloc_failed; + } + + mux->parent = parent; + mux->data = *pdata; + mux->adap = kzalloc(sizeof(struct i2c_adapter *) * pdata->n_values, + GFP_KERNEL); + if (!mux->adap) { + ret = -ENOMEM; + goto alloc_failed2; + } + + if (pdata->idle != GPIO_I2CMUX_NO_IDLE) { + initial_state = pdata->idle; + deselect = gpiomux_deselect; + } else { + initial_state = pdata->values[0]; + deselect = NULL; + } + + for (i = 0; i < pdata->n_gpios; i++) { + ret = gpio_request(pdata->gpios[i], "gpio-i2cmux"); + if (ret) + goto err_request_gpio; + gpio_direction_output(pdata->gpios[i], + initial_state & (1 << i)); + } + + for (i = 0; i < pdata->n_values; i++) { + u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; + + mux->adap[i] = i2c_add_mux_adapter(parent, mux, nr, i, + gpiomux_select, deselect); + if (!mux->adap[i]) { + ret = -ENODEV; + dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + goto add_adapter_failed; + } + } + + dev_info(&pdev->dev, "%d port mux on %s adapter\n", + pdata->n_values, parent->name); + + platform_set_drvdata(pdev, mux); + + return 0; + +add_adapter_failed: + for (; i > 0; i--) + i2c_del_mux_adapter(mux->adap[i - 1]); + i = pdata->n_gpios; +err_request_gpio: + for (; i > 0; i--) + gpio_free(pdata->gpios[i - 1]); + kfree(mux->adap); +alloc_failed2: + kfree(mux); +alloc_failed: + i2c_put_adapter(parent); + + return ret; +} + +static int __devexit gpiomux_remove(struct platform_device *pdev) +{ + struct gpiomux *mux = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < mux->data.n_values; i++) + i2c_del_mux_adapter(mux->adap[i]); + + for (i = 0; i < mux->data.n_gpios; i++) + gpio_free(mux->data.gpios[i]); + + platform_set_drvdata(pdev, NULL); + i2c_put_adapter(mux->parent); + kfree(mux->adap); + kfree(mux); + + return 0; +} + +static struct platform_driver gpiomux_driver = { + .probe = gpiomux_probe, + .remove = __devexit_p(gpiomux_remove), + .driver = { + .owner = THIS_MODULE, + .name = "gpio-i2cmux", + }, +}; + +static int __init gpiomux_init(void) +{ + return platform_driver_register(&gpiomux_driver); +} + +static void __exit gpiomux_exit(void) +{ + platform_driver_unregister(&gpiomux_driver); +} + +module_init(gpiomux_init); +module_exit(gpiomux_exit); + +MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver"); +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-i2cmux"); diff --git a/include/linux/gpio-i2cmux.h b/include/linux/gpio-i2cmux.h new file mode 100644 index 000000000000..4a333bb0bd0d --- /dev/null +++ b/include/linux/gpio-i2cmux.h @@ -0,0 +1,38 @@ +/* + * gpio-i2cmux interface to platform code + * + * Peter Korsgaard + * + * 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. + */ + +#ifndef _LINUX_GPIO_I2CMUX_H +#define _LINUX_GPIO_I2CMUX_H + +/* MUX has no specific idle mode */ +#define GPIO_I2CMUX_NO_IDLE ((unsigned)-1) + +/** + * struct gpio_i2cmux_platform_data - Platform-dependent data for gpio-i2cmux + * @parent: Parent I2C bus adapter number + * @base_nr: Base I2C bus number to number adapters from or zero for dynamic + * @values: Array of bitmasks of GPIO settings (low/high) for each + * position + * @n_values: Number of multiplexer positions (busses to instantiate) + * @gpios: Array of GPIO numbers used to control MUX + * @n_gpios: Number of GPIOs used to control MUX + * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used + */ +struct gpio_i2cmux_platform_data { + int parent; + int base_nr; + const unsigned *values; + int n_values; + const unsigned *gpios; + int n_gpios; + unsigned idle; +}; + +#endif /* _LINUX_GPIO_I2CMUX_H */ -- cgit v1.2.3 From f451171c5ac829e55581c81caf2cb01e1c0a5c5f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 10 Jan 2011 22:11:23 +0100 Subject: i2c-algo-bit: Refactor adapter registration Use a function pointer to decide whether to call i2c_add_adapter or i2c_add_numbered_adapter. This makes the code more compact than the current strategy of having the common code in a separate function. Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index a39e6cff86e7..938170b8998b 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -600,7 +600,8 @@ static const struct i2c_algorithm i2c_bit_algo = { /* * registering functions to load algorithms at runtime */ -static int i2c_bit_prepare_bus(struct i2c_adapter *adap) +static int __i2c_bit_add_bus(struct i2c_adapter *adap, + int (*add_adapter)(struct i2c_adapter *)) { struct i2c_algo_bit_data *bit_adap = adap->algo_data; @@ -614,30 +615,18 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap) adap->algo = &i2c_bit_algo; adap->retries = 3; - return 0; + return add_adapter(adap); } int i2c_bit_add_bus(struct i2c_adapter *adap) { - int err; - - err = i2c_bit_prepare_bus(adap); - if (err) - return err; - - return i2c_add_adapter(adap); + return __i2c_bit_add_bus(adap, i2c_add_adapter); } EXPORT_SYMBOL(i2c_bit_add_bus); int i2c_bit_add_numbered_bus(struct i2c_adapter *adap) { - int err; - - err = i2c_bit_prepare_bus(adap); - if (err) - return err; - - return i2c_add_numbered_adapter(adap); + return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter); } EXPORT_SYMBOL(i2c_bit_add_numbered_bus); -- cgit v1.2.3 From af5a60baaee66e2f891dbb9a8519ca28ab7da7cd Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 10 Jan 2011 22:11:23 +0100 Subject: i2c-algo-bit: Complain about masters which can't read SCL The I2C specification explicitly describes both SDA and SCL as bidirectional lines. An I2C master with a read-only SCL is thus not compliant. If a slow slave stretches the clock, errors will happen, so the bus can't be considered as reliable. Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 938170b8998b..38319a69bd0a 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -604,9 +604,10 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, int (*add_adapter)(struct i2c_adapter *)) { struct i2c_algo_bit_data *bit_adap = adap->algo_data; + int ret; if (bit_test) { - int ret = test_bus(bit_adap, adap->name); + ret = test_bus(bit_adap, adap->name); if (ret < 0) return -ENODEV; } @@ -615,7 +616,16 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, adap->algo = &i2c_bit_algo; adap->retries = 3; - return add_adapter(adap); + ret = add_adapter(adap); + if (ret < 0) + return ret; + + /* Complain if SCL can't be read */ + if (bit_adap->getscl == NULL) { + dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); + dev_warn(&adap->dev, "Bus may be unreliable\n"); + } + return 0; } int i2c_bit_add_bus(struct i2c_adapter *adap) -- cgit v1.2.3 From 0cc43a1806f078f7fd414850d8f1f1761696e4af Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 10 Jan 2011 22:11:23 +0100 Subject: i2c: Constify i2c_client where possible Helper functions for I2C and SMBus transactions don't modify the i2c_client that is passed to them, so it can be marked const. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 29 ++++++++++++++++------------- drivers/rtc/rtc-ds1307.c | 12 ++++++------ include/linux/i2c.h | 27 +++++++++++++++------------ 3 files changed, 37 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 6b4cc567645b..c7db6980e3a3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1362,7 +1362,7 @@ EXPORT_SYMBOL(i2c_transfer); * * Returns negative errno, or else the number of bytes written. */ -int i2c_master_send(struct i2c_client *client, const char *buf, int count) +int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap = client->adapter; @@ -1389,7 +1389,7 @@ EXPORT_SYMBOL(i2c_master_send); * * Returns negative errno, or else the number of bytes read. */ -int i2c_master_recv(struct i2c_client *client, char *buf, int count) +int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; @@ -1679,7 +1679,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) * This executes the SMBus "receive byte" protocol, returning negative errno * else the byte received from the device. */ -s32 i2c_smbus_read_byte(struct i2c_client *client) +s32 i2c_smbus_read_byte(const struct i2c_client *client) { union i2c_smbus_data data; int status; @@ -1699,7 +1699,7 @@ EXPORT_SYMBOL(i2c_smbus_read_byte); * This executes the SMBus "send byte" protocol, returning negative errno * else zero on success. */ -s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value) +s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); @@ -1714,7 +1714,7 @@ EXPORT_SYMBOL(i2c_smbus_write_byte); * This executes the SMBus "read byte" protocol, returning negative errno * else a data byte received from the device. */ -s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) +s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) { union i2c_smbus_data data; int status; @@ -1735,7 +1735,8 @@ EXPORT_SYMBOL(i2c_smbus_read_byte_data); * This executes the SMBus "write byte" protocol, returning negative errno * else zero on success. */ -s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) +s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, + u8 value) { union i2c_smbus_data data; data.byte = value; @@ -1753,7 +1754,7 @@ EXPORT_SYMBOL(i2c_smbus_write_byte_data); * This executes the SMBus "read word" protocol, returning negative errno * else a 16-bit unsigned "word" received from the device. */ -s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) +s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command) { union i2c_smbus_data data; int status; @@ -1774,7 +1775,8 @@ EXPORT_SYMBOL(i2c_smbus_read_word_data); * This executes the SMBus "write word" protocol, returning negative errno * else zero on success. */ -s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) +s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, + u16 value) { union i2c_smbus_data data; data.word = value; @@ -1793,7 +1795,8 @@ EXPORT_SYMBOL(i2c_smbus_write_word_data); * This executes the SMBus "process call" protocol, returning negative errno * else a 16-bit unsigned "word" received from the device. */ -s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value) +s32 i2c_smbus_process_call(const struct i2c_client *client, u8 command, + u16 value) { union i2c_smbus_data data; int status; @@ -1821,7 +1824,7 @@ EXPORT_SYMBOL(i2c_smbus_process_call); * support this; its emulation through I2C messaging relies on a specific * mechanism (I2C_M_RECV_LEN) which may not be implemented. */ -s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, +s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values) { union i2c_smbus_data data; @@ -1848,7 +1851,7 @@ EXPORT_SYMBOL(i2c_smbus_read_block_data); * This executes the SMBus "block write" protocol, returning negative errno * else zero on success. */ -s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, +s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values) { union i2c_smbus_data data; @@ -1864,7 +1867,7 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, EXPORT_SYMBOL(i2c_smbus_write_block_data); /* Returns the number of read bytes */ -s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, +s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values) { union i2c_smbus_data data; @@ -1884,7 +1887,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, } EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); -s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, +s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values) { union i2c_smbus_data data; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index d827ce570a8c..0d559b6416dd 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -106,9 +106,9 @@ struct ds1307 { struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; - s32 (*read_block_data)(struct i2c_client *client, u8 command, + s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); - s32 (*write_block_data)(struct i2c_client *client, u8 command, + s32 (*write_block_data)(const struct i2c_client *client, u8 command, u8 length, const u8 *values); }; @@ -158,8 +158,8 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); #define BLOCK_DATA_MAX_TRIES 10 -static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, - u8 length, u8 *values) +static s32 ds1307_read_block_data_once(const struct i2c_client *client, + u8 command, u8 length, u8 *values) { s32 i, data; @@ -172,7 +172,7 @@ static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, return i; } -static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, +static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values) { u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; @@ -198,7 +198,7 @@ static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, return length; } -static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, +static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values) { u8 currvalues[I2C_SMBUS_BLOCK_MAX]; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 56cfe23ffb39..903576df88dc 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -57,9 +57,10 @@ struct i2c_board_info; * transmit an arbitrary number of messages without interruption. * @count must be be less than 64k since msg.len is u16. */ -extern int i2c_master_send(struct i2c_client *client, const char *buf, +extern int i2c_master_send(const struct i2c_client *client, const char *buf, + int count); +extern int i2c_master_recv(const struct i2c_client *client, char *buf, int count); -extern int i2c_master_recv(struct i2c_client *client, char *buf, int count); /* Transfer num messages. */ @@ -78,23 +79,25 @@ extern s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, /* Now follow the 'nice' access routines. These also document the calling conventions of i2c_smbus_xfer. */ -extern s32 i2c_smbus_read_byte(struct i2c_client *client); -extern s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value); -extern s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command); -extern s32 i2c_smbus_write_byte_data(struct i2c_client *client, +extern s32 i2c_smbus_read_byte(const struct i2c_client *client); +extern s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value); +extern s32 i2c_smbus_read_byte_data(const struct i2c_client *client, + u8 command); +extern s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value); -extern s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command); -extern s32 i2c_smbus_write_word_data(struct i2c_client *client, +extern s32 i2c_smbus_read_word_data(const struct i2c_client *client, + u8 command); +extern s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, u16 value); /* Returns the number of read bytes */ -extern s32 i2c_smbus_read_block_data(struct i2c_client *client, +extern s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values); -extern s32 i2c_smbus_write_block_data(struct i2c_client *client, +extern s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values); /* Returns the number of read bytes */ -extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, +extern s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values); -extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, +extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values); #endif /* I2C */ -- cgit v1.2.3 From 76d9cc454a8d0bb7484616a4b8136280068c8a8b Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Mon, 10 Jan 2011 11:05:06 +0000 Subject: spi: tegra: don't treat NULL clk as an error Some platforms have been known to return NULL from clk_get() if they support only a single struct clk. Whilst tegra doesn't do this, make the drivers consistent with others. Signed-off-by: Jamie Iles Acked-by: Russell King Signed-off-by: Grant Likely --- drivers/spi/spi_tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c index bb7df02a5472..891e5909038c 100644 --- a/drivers/spi/spi_tegra.c +++ b/drivers/spi/spi_tegra.c @@ -513,7 +513,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev) } tspi->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR_OR_NULL(tspi->clk)) { + if (IS_ERR(tspi->clk)) { dev_err(&pdev->dev, "can not get clock\n"); ret = PTR_ERR(tspi->clk); goto err2; -- cgit v1.2.3 From c94310916390ac162e70c8c134bf70680c944a02 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 10 Jan 2011 17:41:43 -0800 Subject: RDMA/cxgb3,cxgb4: Remove dead code This removes unused code found by running 'make namespacecheck'; compile tested only. Signed-off-by: Stephen Hemminger Acked-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.c | 2 ++ drivers/infiniband/hw/cxgb3/iwch_provider.h | 2 -- drivers/infiniband/hw/cxgb3/iwch_qp.c | 56 ----------------------------- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 - drivers/infiniband/hw/cxgb4/qp.c | 30 ---------------- 5 files changed, 2 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 09dda0b8740e..c3f5aca4ef00 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -189,6 +189,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel) return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); } +#ifdef notyet int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) { struct rdma_cq_setup setup; @@ -200,6 +201,7 @@ int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) setup.ovfl_mode = 1; return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); } +#endif static u32 get_qpid(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx) { diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index a237d49bdcc9..c5406da3f4cd 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -335,8 +335,6 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); int iwch_post_zb_read(struct iwch_qp *qhp); int iwch_register_device(struct iwch_dev *dev); void iwch_unregister_device(struct iwch_dev *dev); -int iwch_quiesce_qps(struct iwch_cq *chp); -int iwch_resume_qps(struct iwch_cq *chp); void stop_read_rep_timer(struct iwch_qp *qhp); int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php, struct iwch_mr *mhp, int shift); diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 0993137181d7..1b4cd09f74dc 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -1149,59 +1149,3 @@ out: PDBG("%s exit state %d\n", __func__, qhp->attr.state); return ret; } - -static int quiesce_qp(struct iwch_qp *qhp) -{ - spin_lock_irq(&qhp->lock); - iwch_quiesce_tid(qhp->ep); - qhp->flags |= QP_QUIESCED; - spin_unlock_irq(&qhp->lock); - return 0; -} - -static int resume_qp(struct iwch_qp *qhp) -{ - spin_lock_irq(&qhp->lock); - iwch_resume_tid(qhp->ep); - qhp->flags &= ~QP_QUIESCED; - spin_unlock_irq(&qhp->lock); - return 0; -} - -int iwch_quiesce_qps(struct iwch_cq *chp) -{ - int i; - struct iwch_qp *qhp; - - for (i=0; i < T3_MAX_NUM_QP; i++) { - qhp = get_qhp(chp->rhp, i); - if (!qhp) - continue; - if ((qhp->attr.rcq == chp->cq.cqid) && !qp_quiesced(qhp)) { - quiesce_qp(qhp); - continue; - } - if ((qhp->attr.scq == chp->cq.cqid) && !qp_quiesced(qhp)) - quiesce_qp(qhp); - } - return 0; -} - -int iwch_resume_qps(struct iwch_cq *chp) -{ - int i; - struct iwch_qp *qhp; - - for (i=0; i < T3_MAX_NUM_QP; i++) { - qhp = get_qhp(chp->rhp, i); - if (!qhp) - continue; - if ((qhp->attr.rcq == chp->cq.cqid) && qp_quiesced(qhp)) { - resume_qp(qhp); - continue; - } - if ((qhp->attr.scq == chp->cq.cqid) && qp_quiesced(qhp)) - resume_qp(qhp); - } - return 0; -} diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 16032cdb4337..cc600c2dd0b3 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -760,7 +760,6 @@ int c4iw_flush_rq(struct t4_wq *wq, struct t4_cq *cq, int count); int c4iw_flush_sq(struct t4_wq *wq, struct t4_cq *cq, int count); int c4iw_ev_handler(struct c4iw_dev *rnicp, u32 qid); u16 c4iw_rqes_posted(struct c4iw_qp *qhp); -int c4iw_post_zb_read(struct c4iw_qp *qhp); int c4iw_post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe); u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx); void c4iw_put_cqid(struct c4iw_rdev *rdev, u32 qid, diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 057cb2505ea1..565a0612a125 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -892,36 +892,6 @@ static inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type, } } -int c4iw_post_zb_read(struct c4iw_qp *qhp) -{ - union t4_wr *wqe; - struct sk_buff *skb; - u8 len16; - - PDBG("%s enter\n", __func__); - skb = alloc_skb(40, GFP_KERNEL); - if (!skb) { - printk(KERN_ERR "%s cannot send zb_read!!\n", __func__); - return -ENOMEM; - } - set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); - - wqe = (union t4_wr *)skb_put(skb, sizeof wqe->read); - memset(wqe, 0, sizeof wqe->read); - wqe->read.r2 = cpu_to_be64(0); - wqe->read.stag_sink = cpu_to_be32(1); - wqe->read.to_sink_hi = cpu_to_be32(0); - wqe->read.to_sink_lo = cpu_to_be32(1); - wqe->read.stag_src = cpu_to_be32(1); - wqe->read.plen = cpu_to_be32(0); - wqe->read.to_src_hi = cpu_to_be32(0); - wqe->read.to_src_lo = cpu_to_be32(1); - len16 = DIV_ROUND_UP(sizeof wqe->read, 16); - init_wr_hdr(wqe, 0, FW_RI_RDMA_READ_WR, FW_RI_COMPLETION_FLAG, len16); - - return c4iw_ofld_send(&qhp->rhp->rdev, skb); -} - static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe, gfp_t gfp) { -- cgit v1.2.3 From db8b10167126d72829653690f57b9c7ca53c4d54 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 10 Jan 2011 17:41:43 -0800 Subject: RDMA/cxgb4: Don't re-init wait object in init/fini paths Re-initializing the wait object in rdma_init()/rdma_fini() causes a timing window which can lead to a deadlock during close. Once this deadlock hits, all RDMA activity over the T4 device will be stuck. There's no need to re-init the wait object, so remove it. Signed-off-by: Steve Wise Cc: Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/qp.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 565a0612a125..20800900ef3f 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -999,7 +999,6 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, wqe->cookie = (unsigned long) &ep->com.wr_wait; wqe->u.fini.type = FW_RI_TYPE_FINI; - c4iw_init_wr_wait(&ep->com.wr_wait); ret = c4iw_ofld_send(&rhp->rdev, skb); if (ret) goto out; @@ -1095,7 +1094,6 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) if (qhp->attr.mpa_attr.initiator) build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init); - c4iw_init_wr_wait(&qhp->ep->com.wr_wait); ret = c4iw_ofld_send(&rhp->rdev, skb); if (ret) goto out; -- cgit v1.2.3 From 1eba27e87a85f6ed68905055bc9a7dbfb024c255 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 10 Jan 2011 17:41:50 -0800 Subject: IB/ipath: Use printf extension %pR for struct resource Using %pR standardizes the struct resource output. Signed-off-by: Joe Perches Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 765f0fc1da76..b33f0457a1ff 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -530,9 +530,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, for (j = 0; j < 6; j++) { if (!pdev->resource[j].start) continue; - ipath_cdbg(VERBOSE, "BAR %d start %llx, end %llx, len %llx\n", - j, (unsigned long long)pdev->resource[j].start, - (unsigned long long)pdev->resource[j].end, + ipath_cdbg(VERBOSE, "BAR %d %pR, len %llx\n", + j, &pdev->resource[j], (unsigned long long)pci_resource_len(pdev, j)); } -- cgit v1.2.3 From 19e364f6801e38972673278adedaab1abf6f854c Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 10 Jan 2011 17:41:54 -0800 Subject: IPoIB: Remove LRO support As a first step in moving from LRO to GRO, revert commit af40da894e9 ("IPoIB: add LRO support"). Also eliminate the ethtool set_flags callback which isn't needed anymore. Finally, we need to include directly to get the declaration of restart_syscall() (which used to be included implicitly through ). Cc: Ben Hutchings Cc: Eric W. Biederman Cc: Vladimir Sokolovsky Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/Kconfig | 1 - drivers/infiniband/ulp/ipoib/ipoib.h | 12 +----- drivers/infiniband/ulp/ipoib/ipoib_ethtool.c | 51 ----------------------- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 8 +--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 62 ---------------------------- 5 files changed, 2 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index 9d9a9dc51f18..55855eeabae7 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig @@ -1,7 +1,6 @@ config INFINIBAND_IPOIB tristate "IP-over-InfiniBand" depends on NETDEVICES && INET && (IPV6 || IPV6=n) - select INET_LRO ---help--- Support for the IP-over-InfiniBand protocol (IPoIB). This transports IP packets over InfiniBand so you can use your IB diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 753a983a5fdc..ab97f92fc257 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -50,7 +50,7 @@ #include #include #include -#include +#include /* constants */ @@ -100,9 +100,6 @@ enum { IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, - IPOIB_MAX_LRO_DESCRIPTORS = 8, - IPOIB_LRO_MAX_AGGR = 64, - MAX_SEND_CQE = 16, IPOIB_CM_COPYBREAK = 256, }; @@ -262,11 +259,6 @@ struct ipoib_ethtool_st { u16 max_coalesced_frames; }; -struct ipoib_lro { - struct net_lro_mgr lro_mgr; - struct net_lro_desc lro_desc[IPOIB_MAX_LRO_DESCRIPTORS]; -}; - /* * Device private locking: network stack tx_lock protects members used * in TX fast path, lock protects everything else. lock nests inside @@ -352,8 +344,6 @@ struct ipoib_dev_priv { int hca_caps; struct ipoib_ethtool_st ethtool; struct timer_list poll_timer; - - struct ipoib_lro lro; }; struct ipoib_ah { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 1a1657c82edd..19f7f5206f78 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -106,63 +106,12 @@ static int ipoib_set_coalesce(struct net_device *dev, return 0; } -static const char ipoib_stats_keys[][ETH_GSTRING_LEN] = { - "LRO aggregated", "LRO flushed", - "LRO avg aggr", "LRO no desc" -}; - -static void ipoib_get_strings(struct net_device *netdev, u32 stringset, u8 *data) -{ - switch (stringset) { - case ETH_SS_STATS: - memcpy(data, *ipoib_stats_keys, sizeof(ipoib_stats_keys)); - break; - } -} - -static int ipoib_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(ipoib_stats_keys); - default: - return -EOPNOTSUPP; - } -} - -static void ipoib_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, uint64_t *data) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - int index = 0; - - /* Get LRO statistics */ - data[index++] = priv->lro.lro_mgr.stats.aggregated; - data[index++] = priv->lro.lro_mgr.stats.flushed; - if (priv->lro.lro_mgr.stats.flushed) - data[index++] = priv->lro.lro_mgr.stats.aggregated / - priv->lro.lro_mgr.stats.flushed; - else - data[index++] = 0; - data[index++] = priv->lro.lro_mgr.stats.no_desc; -} - -static int ipoib_set_flags(struct net_device *dev, u32 flags) -{ - return ethtool_op_set_flags(dev, flags, ETH_FLAG_LRO); -} - static const struct ethtool_ops ipoib_ethtool_ops = { .get_drvinfo = ipoib_get_drvinfo, .get_rx_csum = ipoib_get_rx_csum, .set_tso = ipoib_set_tso, .get_coalesce = ipoib_get_coalesce, .set_coalesce = ipoib_set_coalesce, - .get_flags = ethtool_op_get_flags, - .set_flags = ipoib_set_flags, - .get_strings = ipoib_get_strings, - .get_sset_count = ipoib_get_sset_count, - .get_ethtool_stats = ipoib_get_ethtool_stats, }; void ipoib_set_ethtool_ops(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index dfa71903d6e4..44c33bd97952 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -295,10 +295,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok)) skb->ip_summed = CHECKSUM_UNNECESSARY; - if (dev->features & NETIF_F_LRO) - lro_receive_skb(&priv->lro.lro_mgr, skb, NULL); - else - netif_receive_skb(skb); + netif_receive_skb(skb); repost: if (unlikely(ipoib_ib_post_receive(dev, wr_id))) @@ -450,9 +447,6 @@ poll_more: } if (done < budget) { - if (dev->features & NETIF_F_LRO) - lro_flush_all(&priv->lro.lro_mgr); - napi_complete(napi); if (unlikely(ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP | diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 9ff7bc73ed95..c434a856a787 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -60,15 +60,6 @@ MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); -static int lro; -module_param(lro, bool, 0444); -MODULE_PARM_DESC(lro, "Enable LRO (Large Receive Offload)"); - -static int lro_max_aggr = IPOIB_LRO_MAX_AGGR; -module_param(lro_max_aggr, int, 0644); -MODULE_PARM_DESC(lro_max_aggr, "LRO: Max packets to be aggregated " - "(default = 64)"); - #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG int ipoib_debug_level; @@ -976,54 +967,6 @@ static const struct header_ops ipoib_header_ops = { .create = ipoib_hard_header, }; -static int get_skb_hdr(struct sk_buff *skb, void **iphdr, - void **tcph, u64 *hdr_flags, void *priv) -{ - unsigned int ip_len; - struct iphdr *iph; - - if (unlikely(skb->protocol != htons(ETH_P_IP))) - return -1; - - /* - * In the future we may add an else clause that verifies the - * checksum and allows devices which do not calculate checksum - * to use LRO. - */ - if (unlikely(skb->ip_summed != CHECKSUM_UNNECESSARY)) - return -1; - - /* Check for non-TCP packet */ - skb_reset_network_header(skb); - iph = ip_hdr(skb); - if (iph->protocol != IPPROTO_TCP) - return -1; - - ip_len = ip_hdrlen(skb); - skb_set_transport_header(skb, ip_len); - *tcph = tcp_hdr(skb); - - /* check if IP header and TCP header are complete */ - if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb)) - return -1; - - *hdr_flags = LRO_IPV4 | LRO_TCP; - *iphdr = iph; - - return 0; -} - -static void ipoib_lro_setup(struct ipoib_dev_priv *priv) -{ - priv->lro.lro_mgr.max_aggr = lro_max_aggr; - priv->lro.lro_mgr.max_desc = IPOIB_MAX_LRO_DESCRIPTORS; - priv->lro.lro_mgr.lro_arr = priv->lro.lro_desc; - priv->lro.lro_mgr.get_skb_header = get_skb_hdr; - priv->lro.lro_mgr.features = LRO_F_NAPI; - priv->lro.lro_mgr.dev = priv->dev; - priv->lro.lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; -} - static const struct net_device_ops ipoib_netdev_ops = { .ndo_open = ipoib_open, .ndo_stop = ipoib_stop, @@ -1067,8 +1010,6 @@ static void ipoib_setup(struct net_device *dev) priv->dev = dev; - ipoib_lro_setup(priv); - spin_lock_init(&priv->lock); mutex_init(&priv->vlan_mutex); @@ -1218,9 +1159,6 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca) priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; } - if (lro) - priv->dev->features |= NETIF_F_LRO; - if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) priv->dev->features |= NETIF_F_TSO; -- cgit v1.2.3 From 8ae31e5b1fc73751d800d551fb30340caa53c7dd Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 10 Jan 2011 17:41:55 -0800 Subject: IPoIB: Add GRO support Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 1 + drivers/infiniband/ulp/ipoib/ipoib_ib.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index bb1004114dec..c1c49f2d35b5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1480,6 +1480,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + priv->dev->features |= NETIF_F_GRO; if (priv->hca_caps & IB_DEVICE_UD_TSO) dev->features |= NETIF_F_TSO; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 44c33bd97952..806d0292dc39 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -295,7 +295,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok)) skb->ip_summed = CHECKSUM_UNNECESSARY; - netif_receive_skb(skb); + napi_gro_receive(&priv->napi, skb); repost: if (unlikely(ipoib_ib_post_receive(dev, wr_id))) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index c434a856a787..7a07a728fe0d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1159,6 +1159,8 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca) priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; } + priv->dev->features |= NETIF_F_GRO; + if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) priv->dev->features |= NETIF_F_TSO; -- cgit v1.2.3 From f5a49539a64ae5e3833fddec54a3c2524c7fe333 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 10 Jan 2011 17:42:05 -0800 Subject: mlx4_core: Remove warning message about firmware bug The kernel warning message added in commit 58d74bb1d9f7 ("mlx4_core: Workaround firmware bug in query dev cap") about mlx4 reporting the wrong number of "blue flame registers" doesn't really help anyone, since the firmware bug is known and fixed and the bug is pretty much harmless to users. So just get rid of the warning. Signed-off-by: Roland Dreier --- drivers/net/mlx4/fw.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 7a7e18ba278a..5de1db897835 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -289,10 +289,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); dev_cap->bf_reg_size = 1 << (field & 0x1f); MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); - if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) { - mlx4_warn(dev, "firmware bug: log2 # of blue flame regs is invalid (%d), forcing 3\n", field & 0x1f); + if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) field = 3; - } dev_cap->bf_regs_per_page = 1 << (field & 0x3f); mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); -- cgit v1.2.3 From 3afa9f19e5bd16abed998b7bf1b178206403286f Mon Sep 17 00:00:00 2001 From: Vladimir Sokolovsky Date: Mon, 10 Jan 2011 17:42:06 -0800 Subject: IB/mlx4: Don't call dma_free_coherent() with irqs disabled mlx4_ib_free_cq_buf() should not be called under spin_lock_irq() since it calls dma_free_coherent(), which needs irqs enabled. Fix this by deferring the free to outside the locked region. This was found due to the WARN_ON(irqs_disabled()); in swiotlb_free_coherent(). Signed-off-by: Vladimir Sokolovsky Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/cq.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 5a219a2fdf16..e8df155bc3b0 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -397,10 +397,14 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) cq->resize_buf = NULL; cq->resize_umem = NULL; } else { + struct mlx4_ib_cq_buf tmp_buf; + int tmp_cqe = 0; + spin_lock_irq(&cq->lock); if (cq->resize_buf) { mlx4_ib_cq_resize_copy_cqes(cq); - mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + tmp_buf = cq->buf; + tmp_cqe = cq->ibcq.cqe; cq->buf = cq->resize_buf->buf; cq->ibcq.cqe = cq->resize_buf->cqe; @@ -408,6 +412,9 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) cq->resize_buf = NULL; } spin_unlock_irq(&cq->lock); + + if (tmp_cqe) + mlx4_ib_free_cq_buf(dev, &tmp_buf, tmp_cqe); } goto out; -- cgit v1.2.3 From 030b4b3309e29c6c857d8521c3076743663c259e Mon Sep 17 00:00:00 2001 From: Ali Ayoub Date: Mon, 10 Jan 2011 17:42:06 -0800 Subject: mlx4_core: Avoid vunmap() of invalid pointer if allocation fails Signed-off-by: Ali Ayoub Signed-off-by: Roland Dreier --- drivers/net/mlx4/alloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 8f4bf1f07c11..3a4277f6fac4 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c @@ -178,6 +178,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, } else { int i; + buf->direct.buf = NULL; buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; buf->npages = buf->nbufs; buf->page_shift = PAGE_SHIFT; @@ -229,7 +230,7 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, buf->direct.map); else { - if (BITS_PER_LONG == 64) + if (BITS_PER_LONG == 64 && buf->direct.buf) vunmap(buf->direct.buf); for (i = 0; i < buf->nbufs; ++i) -- cgit v1.2.3 From 1397490938aa0aca39001c3fd5a9fc9387110d86 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Jan 2011 17:42:06 -0800 Subject: IB/mlx4: Handle -ENOMEM in forward_trap() ib_create_send_mad() can return ERR_PTR(-ENOMEM) here. Signed-off-by: Dan Carpenter Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/mad.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index c9a8dd63b9e2..57ffa50f509e 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -211,6 +211,8 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma if (agent) { send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, GFP_ATOMIC); + if (IS_ERR(send_buf)) + return; /* * We rely here on the fact that MLX QPs don't use the * address handle after the send is posted (this is -- cgit v1.2.3 From d0444f1527f22d193c209d4fdad0dbabbf2be2ee Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Jan 2011 17:42:10 -0800 Subject: IB/mthca: Handle -ENOMEM in forward_trap() ib_create_send_mad() can return ERR_PTR(-ENOMEM) here. Signed-off-by: Dan Carpenter Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_mad.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index 5648659ff0b0..03a59534f59e 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c @@ -171,6 +171,8 @@ static void forward_trap(struct mthca_dev *dev, if (agent) { send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, GFP_ATOMIC); + if (IS_ERR(send_buf)) + return; /* * We rely here on the fact that MLX QPs don't use the * address handle after the send is posted (this is -- cgit v1.2.3 From 601d87b0795c5affe5b73318c1088edbf10ce72f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 10 Jan 2011 17:42:14 -0800 Subject: RDMA/nes: Fix string continuation line Signed-off-by: Joe Perches Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_nic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 3892e2c0e95a..5a4c36484722 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -908,8 +908,8 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) nesvnic->nic_index && mc_index < max_pft_entries_avaiable) { nes_debug(NES_DBG_NIC_RX, - "mc_index=%d skipping nic_index=%d,\ - used for=%d \n", mc_index, + "mc_index=%d skipping nic_index=%d, " + "used for=%d \n", mc_index, nesvnic->nic_index, nesadapter->pft_mcast_map[mc_index]); mc_index++; -- cgit v1.2.3 From 9d5b243f24212966d6d06058f96b2b1a22482f59 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:19 -0800 Subject: IB/qib: Remove IB latency turnoff This is required for hardware testing. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7322.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 584d443b5335..9031cd82e879 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -7271,8 +7271,6 @@ static int serdes_7322_init(struct qib_pportdata *ppd) ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */ data = qib_read_kreg_port(ppd, krp_serdesctrl); - /* Turn off IB latency mode */ - data &= ~SYM_MASK(IBSerdesCtrl_0, IB_LAT_MODE); qib_write_kreg_port(ppd, krp_serdesctrl, data | SYM_MASK(IBSerdesCtrl_0, RXLOSEN)); -- cgit v1.2.3 From 0a43e117221702b08a023d6aa1a31ac30e40866b Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:19 -0800 Subject: IB/qib: Add receive header queue size module parameters The receive header queue sizes need to modified for performance tuning. Three module parameters are added to support this. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7322.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 9031cd82e879..b35676f44373 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -111,6 +111,21 @@ static ushort qib_singleport; module_param_named(singleport, qib_singleport, ushort, S_IRUGO); MODULE_PARM_DESC(singleport, "Use only IB port 1; more per-port buffer space"); +/* + * Receive header queue sizes + */ +static unsigned qib_rcvhdrcnt; +module_param_named(rcvhdrcnt, qib_rcvhdrcnt, uint, S_IRUGO); +MODULE_PARM_DESC(rcvhdrcnt, "receive header count"); + +static unsigned qib_rcvhdrsize; +module_param_named(rcvhdrsize, qib_rcvhdrsize, uint, S_IRUGO); +MODULE_PARM_DESC(rcvhdrsize, "receive header size in 32-bit words"); + +static unsigned qib_rcvhdrentsize; +module_param_named(rcvhdrentsize, qib_rcvhdrentsize, uint, S_IRUGO); +MODULE_PARM_DESC(rcvhdrentsize, "receive header entry size in 32-bit words"); + #define MAX_ATTEN_LEN 64 /* plenty for any real system */ /* for read back, default index is ~5m copper cable */ static char txselect_list[MAX_ATTEN_LEN] = "10"; @@ -3530,8 +3545,11 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd) /* kr_rcvegrcnt changes based on the number of contexts enabled */ dd->cspec->rcvegrcnt = qib_read_kreg32(dd, kr_rcvegrcnt); - dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt, - dd->num_pports > 1 ? 1024U : 2048U); + if (qib_rcvhdrcnt) + dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt, qib_rcvhdrcnt); + else + dd->rcvhdrcnt = max(dd->cspec->rcvegrcnt, + dd->num_pports > 1 ? 1024U : 2048U); } static int qib_7322_get_ib_cfg(struct qib_pportdata *ppd, int which) @@ -6097,8 +6115,10 @@ static int qib_init_7322_variables(struct qib_devdata *dd) ppd++; } - dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE; - dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE; + dd->rcvhdrentsize = qib_rcvhdrentsize ? + qib_rcvhdrentsize : QIB_RCVHDR_ENTSIZE; + dd->rcvhdrsize = qib_rcvhdrsize ? + qib_rcvhdrsize : QIB_DFLT_RCVHDRSIZE; dd->rhf_offset = dd->rcvhdrentsize - sizeof(u64) / sizeof(u32); /* we always allocate at least 2048 bytes for eager buffers */ -- cgit v1.2.3 From f509f9c14d3f70834f964189293bed3e0e1fc839 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:19 -0800 Subject: IB/qib: Add support for the new QME7362 card Add support to recognize another board variation named QME7362. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7322.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index b35676f44373..40f4a2353320 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3172,6 +3172,10 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd) case BOARD_QME7342: n = "InfiniPath_QME7342"; break; + case 8: + n = "InfiniPath_QME7362"; + dd->flags |= QIB_HAS_QSFP; + break; case 15: n = "InfiniPath_QLE7342_TEST"; dd->flags |= QIB_HAS_QSFP; -- cgit v1.2.3 From a377acd15188cf11e47a67af5feea098cd8b25d2 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:19 -0800 Subject: IB/qib: Generate completion callback on errors According to IBTA vol. 1, C11-30.1.1, a notification callback is invoked if the CQ is armed for the next solicited completion event or an error completion. The error case wasn't being generated correctly. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_cq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_cq.c b/drivers/infiniband/hw/qib/qib_cq.c index a86cbf880f98..5246aa486bbe 100644 --- a/drivers/infiniband/hw/qib/qib_cq.c +++ b/drivers/infiniband/hw/qib/qib_cq.c @@ -100,7 +100,8 @@ void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int solicited) wc->head = next; if (cq->notify == IB_CQ_NEXT_COMP || - (cq->notify == IB_CQ_SOLICITED && solicited)) { + (cq->notify == IB_CQ_SOLICITED && + (solicited || entry->status != IB_WC_SUCCESS))) { cq->notify = IB_CQ_NONE; cq->triggered++; /* -- cgit v1.2.3 From 3c9e5f4d657170c2fbc3d382d2daae3820713a6c Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:19 -0800 Subject: IB/qib: Set port physical state even if other fields are invalid The IBTA vol. 1 release 1.2.1 spec. says: C14-24.2.1: If PortInfo:Portstate=Down, then a SubnSet(PortInfo) shall make any changes it specifies to PortInfo:PortPhysicalState; any other result is vendor-dependent. The patch changes the error handling so that the reply says there are invalid fields but still attempts to set fields that are in range including PortInfo:PortPhysicalState. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_mad.c | 45 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c index 94b0d1f3a8f0..5ad224e4a38b 100644 --- a/drivers/infiniband/hw/qib/qib_mad.c +++ b/drivers/infiniband/hw/qib/qib_mad.c @@ -668,8 +668,8 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, lid = be16_to_cpu(pip->lid); /* Must be a valid unicast LID address. */ if (lid == 0 || lid >= QIB_MULTICAST_LID_BASE) - goto err; - if (ppd->lid != lid || ppd->lmc != (pip->mkeyprot_resv_lmc & 7)) { + smp->status |= IB_SMP_INVALID_FIELD; + else if (ppd->lid != lid || ppd->lmc != (pip->mkeyprot_resv_lmc & 7)) { if (ppd->lid != lid) qib_set_uevent_bits(ppd, _QIB_EVENT_LID_CHANGE_BIT); if (ppd->lmc != (pip->mkeyprot_resv_lmc & 7)) @@ -683,8 +683,8 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, msl = pip->neighbormtu_mastersmsl & 0xF; /* Must be a valid unicast LID address. */ if (smlid == 0 || smlid >= QIB_MULTICAST_LID_BASE) - goto err; - if (smlid != ibp->sm_lid || msl != ibp->sm_sl) { + smp->status |= IB_SMP_INVALID_FIELD; + else if (smlid != ibp->sm_lid || msl != ibp->sm_sl) { spin_lock_irqsave(&ibp->lock, flags); if (ibp->sm_ah) { if (smlid != ibp->sm_lid) @@ -707,8 +707,9 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, if (lwe == 0xFF) lwe = ppd->link_width_supported; else if (lwe >= 16 || (lwe & ~ppd->link_width_supported)) - goto err; - set_link_width_enabled(ppd, lwe); + smp->status |= IB_SMP_INVALID_FIELD; + else if (lwe != ppd->link_width_enabled) + set_link_width_enabled(ppd, lwe); } lse = pip->linkspeedactive_enabled & 0xF; @@ -721,8 +722,9 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, if (lse == 15) lse = ppd->link_speed_supported; else if (lse >= 8 || (lse & ~ppd->link_speed_supported)) - goto err; - set_link_speed_enabled(ppd, lse); + smp->status |= IB_SMP_INVALID_FIELD; + else if (lse != ppd->link_speed_enabled) + set_link_speed_enabled(ppd, lse); } /* Set link down default state. */ @@ -738,7 +740,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, IB_LINKINITCMD_POLL); break; default: - goto err; + smp->status |= IB_SMP_INVALID_FIELD; } ibp->mkeyprot = pip->mkeyprot_resv_lmc >> 6; @@ -748,15 +750,17 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, mtu = ib_mtu_enum_to_int((pip->neighbormtu_mastersmsl >> 4) & 0xF); if (mtu == -1) - goto err; - qib_set_mtu(ppd, mtu); + smp->status |= IB_SMP_INVALID_FIELD; + else + qib_set_mtu(ppd, mtu); /* Set operational VLs */ vls = (pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF; if (vls) { if (vls > ppd->vls_supported) - goto err; - (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_OP_VLS, vls); + smp->status |= IB_SMP_INVALID_FIELD; + else + (void) dd->f_set_ib_cfg(ppd, QIB_IB_CFG_OP_VLS, vls); } if (pip->mkey_violations == 0) @@ -770,10 +774,10 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, ore = pip->localphyerrors_overrunerrors; if (set_phyerrthreshold(ppd, (ore >> 4) & 0xF)) - goto err; + smp->status |= IB_SMP_INVALID_FIELD; if (set_overrunthreshold(ppd, (ore & 0xF))) - goto err; + smp->status |= IB_SMP_INVALID_FIELD; ibp->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F; @@ -792,7 +796,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, state = pip->linkspeed_portstate & 0xF; lstate = (pip->portphysstate_linkdown >> 4) & 0xF; if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) - goto err; + smp->status |= IB_SMP_INVALID_FIELD; /* * Only state changes of DOWN, ARM, and ACTIVE are valid @@ -812,8 +816,10 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, lstate = QIB_IB_LINKDOWN; else if (lstate == 3) lstate = QIB_IB_LINKDOWN_DISABLE; - else - goto err; + else { + smp->status |= IB_SMP_INVALID_FIELD; + break; + } spin_lock_irqsave(&ppd->lflags_lock, flags); ppd->lflags &= ~QIBL_LINKV; spin_unlock_irqrestore(&ppd->lflags_lock, flags); @@ -835,8 +841,7 @@ static int subn_set_portinfo(struct ib_smp *smp, struct ib_device *ibdev, qib_set_linkstate(ppd, QIB_IB_LINKACTIVE); break; default: - /* XXX We have already partially updated our state! */ - goto err; + smp->status |= IB_SMP_INVALID_FIELD; } ret = subn_get_portinfo(smp, ibdev, port); -- cgit v1.2.3 From c7665e5a6988450a6cc19c2dc1dff4d290077614 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:20 -0800 Subject: IB/qib: UD send with immediate receive completion has wrong size The code to generate receive completion entries for UD send with immediate contains the wrong payload length. This is because when the code to compute the payload size was moved, the value of hdrsize didn't get moved too. The fix is to update tlen directly. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_ud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c index e1b3da2a1f85..a4b945d9a303 100644 --- a/drivers/infiniband/hw/qib/qib_ud.c +++ b/drivers/infiniband/hw/qib/qib_ud.c @@ -519,7 +519,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) { wc.ex.imm_data = ohdr->u.ud.imm_data; wc.wc_flags = IB_WC_WITH_IMM; - hdrsize += sizeof(u32); + tlen -= sizeof(u32); } else if (opcode == IB_OPCODE_UD_SEND_ONLY) { wc.ex.imm_data = 0; wc.wc_flags = 0; -- cgit v1.2.3 From b3d5cb2f2067b30da53aa67e42fdd733030fb411 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:20 -0800 Subject: IB/qib: Handle transitions from ACTIVE_DEFERRED to ACTIVE better When the link transitions from ACTIVE_DEFERRED to ACTIVE, the driver only sees the ACTIVE state. With this change, it will check whether the state was already ACTIVE and if so, it will not generated IB events and will not clear symbol error counts. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_intr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c index 54a40828a106..a693c56ec8a6 100644 --- a/drivers/infiniband/hw/qib/qib_intr.c +++ b/drivers/infiniband/hw/qib/qib_intr.c @@ -131,7 +131,8 @@ void qib_handle_e_ibstatuschanged(struct qib_pportdata *ppd, u64 ibcs) /* start a 75msec timer to clear symbol errors */ mod_timer(&ppd->symerr_clear_timer, msecs_to_jiffies(75)); - } else if (ltstate == IB_PHYSPORTSTATE_LINKUP) { + } else if (ltstate == IB_PHYSPORTSTATE_LINKUP && + !(ppd->lflags & QIBL_LINKACTIVE)) { /* active, but not active defered */ qib_hol_up(ppd); /* useful only for 6120 now */ *ppd->statusp |= -- cgit v1.2.3 From 5dbbcb97cc55dd6e0c34cf06f9e1ee181247d054 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:20 -0800 Subject: IB/qib: Fix multi-Florida HCA host panic on reboot Add check when setting configured contexts that the value does not exceed the number of contexts allocated for the card. If the value exceeds the already allocated count, set it to what is already allocated. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index f3b503936043..7896afbb9ce8 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -92,9 +92,11 @@ unsigned long *qib_cpulist; /* set number of contexts we'll actually use */ void qib_set_ctxtcnt(struct qib_devdata *dd) { - if (!qib_cfgctxts) + if (!qib_cfgctxts) { dd->cfgctxts = dd->first_user_ctxt + num_online_cpus(); - else if (qib_cfgctxts < dd->num_pports) + if (dd->cfgctxts > dd->ctxtcnt) + dd->cfgctxts = dd->ctxtcnt; + } else if (qib_cfgctxts < dd->num_pports) dd->cfgctxts = dd->ctxtcnt; else if (qib_cfgctxts <= dd->ctxtcnt) dd->cfgctxts = qib_cfgctxts; -- cgit v1.2.3 From 6676b3f746ff164a4a367c9aa5ae4b5b1145083c Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:20 -0800 Subject: IB/qib: Fix context allocation with multiple HCAs The driver was incorrectly choosing HCAs on which to allocate new user contexts based on overall count of usable ports regardless whether the usable port was on the currently selected HCA. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_file_ops.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 79d9971aff1f..75bfad16c114 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1379,17 +1379,17 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo, /* find device (with ACTIVE ports) with fewest ctxts in use */ for (ndev = 0; ndev < devmax; ndev++) { struct qib_devdata *dd = qib_lookup(ndev); - unsigned cused = 0, cfree = 0; + unsigned cused = 0, cfree = 0, pusable = 0; if (!dd) continue; if (port && port <= dd->num_pports && usable(dd->pport + port - 1)) - dusable = 1; + pusable = 1; else for (i = 0; i < dd->num_pports; i++) if (usable(dd->pport + i)) - dusable++; - if (!dusable) + pusable++; + if (!pusable) continue; for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts; ctxt++) @@ -1397,7 +1397,7 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo, cused++; else cfree++; - if (cfree && cused < inuse) { + if (pusable && cfree && cused < inuse) { udd = dd; inuse = cused; } -- cgit v1.2.3 From 16028f27778cb6439516c36c0a72446d29805691 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:20 -0800 Subject: IB/qib: Clear WAIT_SEND flags when setting QP to error state If these flags are set when the QP is transitioned to the error state, it will wait until the flags are cleared, which may never happen if the error transition is due to a link going down. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_qp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index 6c39851d2ded..32dacd444158 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -468,6 +468,10 @@ int qib_error_qp(struct qib_qp *qp, enum ib_wc_status err) qp->s_flags &= ~(QIB_S_TIMER | QIB_S_WAIT_RNR); del_timer(&qp->s_timer); } + + if (qp->s_flags & QIB_S_ANY_WAIT_SEND) + qp->s_flags &= ~QIB_S_ANY_WAIT_SEND; + spin_lock(&dev->pending_lock); if (!list_empty(&qp->iowait) && !(qp->s_flags & QIB_S_BUSY)) { qp->s_flags &= ~QIB_S_ANY_WAIT_IO; -- cgit v1.2.3 From a0a234d47dcacfdb0a8dfcb861e0bd8300702674 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:20 -0800 Subject: IB/qib: New SERDES init routine and improvements to SI quality Implement new SERDES initialization routine and improvements to signal integrity -- disable LE1 adaptation, disable LOS after link-up, set better SERDES parameters. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7322.c | 270 ++++++++++++++++++++++++++++++-- 1 file changed, 255 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 40f4a2353320..d23297a307aa 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -71,6 +71,9 @@ static void qib_7322_mini_pcs_reset(struct qib_pportdata *); static u32 ahb_mod(struct qib_devdata *, int, int, int, u32, u32); static void ibsd_wr_allchans(struct qib_pportdata *, int, unsigned, unsigned); +static void serdes_7322_los_enable(struct qib_pportdata *, int); +static int serdes_7322_init_old(struct qib_pportdata *); +static int serdes_7322_init_new(struct qib_pportdata *); #define BMASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb)) @@ -1692,6 +1695,8 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst) (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR))) { force_h1(ppd); ppd->cpspec->qdr_reforce = 1; + if (!ppd->dd->cspec->r1) + serdes_7322_los_enable(ppd, 0); } else if (ppd->cpspec->qdr_reforce && (ibcst & SYM_MASK(IBCStatusA_0, LinkSpeedQDR)) && (ibclt == IB_7322_LT_STATE_CFGENH || @@ -1707,15 +1712,32 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst) ibclt <= IB_7322_LT_STATE_SLEEPQUIET))) adj_tx_serdes(ppd); - if (!ppd->cpspec->qdr_dfe_on && ibclt != IB_7322_LT_STATE_LINKUP && - ibclt <= IB_7322_LT_STATE_SLEEPQUIET) { - ppd->cpspec->qdr_dfe_on = 1; - ppd->cpspec->qdr_dfe_time = 0; - /* On link down, reenable QDR adaptation */ - qib_write_kreg_port(ppd, krp_static_adapt_dis(2), - ppd->dd->cspec->r1 ? - QDR_STATIC_ADAPT_DOWN_R1 : - QDR_STATIC_ADAPT_DOWN); + if (ibclt != IB_7322_LT_STATE_LINKUP) { + u8 ltstate = qib_7322_phys_portstate(ibcst); + u8 pibclt = (u8)SYM_FIELD(ppd->lastibcstat, IBCStatusA_0, + LinkTrainingState); + if (!ppd->dd->cspec->r1 && + pibclt == IB_7322_LT_STATE_LINKUP && + ltstate != IB_PHYSPORTSTATE_LINK_ERR_RECOVER && + ltstate != IB_PHYSPORTSTATE_RECOVERY_RETRAIN && + ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT && + ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE) + /* If the link went down (but no into recovery, + * turn LOS back on */ + serdes_7322_los_enable(ppd, 1); + if (!ppd->cpspec->qdr_dfe_on && + ibclt <= IB_7322_LT_STATE_SLEEPQUIET) { + ppd->cpspec->qdr_dfe_on = 1; + ppd->cpspec->qdr_dfe_time = 0; + /* On link down, reenable QDR adaptation */ + qib_write_kreg_port(ppd, krp_static_adapt_dis(2), + ppd->dd->cspec->r1 ? + QDR_STATIC_ADAPT_DOWN_R1 : + QDR_STATIC_ADAPT_DOWN); + printk(KERN_INFO QIB_DRV_NAME + " IB%u:%u re-enabled QDR adaptation " + "ibclt %x\n", ppd->dd->unit, ppd->port, ibclt); + } } } @@ -5544,7 +5566,7 @@ static void qsfp_7322_event(struct work_struct *work) u64 now = get_jiffies_64(); if (time_after64(now, pwrup)) break; - msleep(1); + msleep(20); } ret = qib_refresh_qsfp_cache(ppd, &qd->cache); /* @@ -6519,7 +6541,7 @@ static void qib_7322_txchk_change(struct qib_devdata *dd, u32 start, /* make sure we see an updated copy next time around */ sendctrl_7322_mod(dd->pport, QIB_SENDCTRL_AVAIL_BLIP); sleeps++; - msleep(1); + msleep(20); } switch (which) { @@ -7234,9 +7256,30 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data, } } +static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable) +{ + u64 data = qib_read_kreg_port(ppd, krp_serdesctrl); + printk(KERN_INFO QIB_DRV_NAME " Turning LOS %s for port %d\n", + (enable ? "on" : "off"), ppd->port); + if (enable) + data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN); + else + data &= ~SYM_MASK(IBSerdesCtrl_0, RXLOSEN); + qib_write_kreg_port(ppd, krp_serdesctrl, data); +} + static int serdes_7322_init(struct qib_pportdata *ppd) { - u64 data; + int ret = 0; + if (ppd->dd->cspec->r1) + ret = serdes_7322_init_old(ppd); + else + ret = serdes_7322_init_new(ppd); + return ret; +} + +static int serdes_7322_init_old(struct qib_pportdata *ppd) +{ u32 le_val; /* @@ -7294,9 +7337,7 @@ static int serdes_7322_init(struct qib_pportdata *ppd) ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */ ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */ - data = qib_read_kreg_port(ppd, krp_serdesctrl); - qib_write_kreg_port(ppd, krp_serdesctrl, data | - SYM_MASK(IBSerdesCtrl_0, RXLOSEN)); + serdes_7322_los_enable(ppd, 1); /* rxbistena; set 0 to avoid effects of it switch later */ ibsd_wr_allchans(ppd, 9, 0 << 15, 1 << 15); @@ -7336,6 +7377,205 @@ static int serdes_7322_init(struct qib_pportdata *ppd) return 0; } +static int serdes_7322_init_new(struct qib_pportdata *ppd) +{ + u64 tstart; + u32 le_val, rxcaldone; + int chan, chan_done = (1 << SERDES_CHANS) - 1; + + /* + * Initialize the Tx DDS tables. Also done every QSFP event, + * for adapters with QSFP + */ + init_txdds_table(ppd, 0); + + /* Clear cmode-override, may be set from older driver */ + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 0 << 14, 1 << 14); + + /* ensure no tx overrides from earlier driver loads */ + qib_write_kreg_port(ppd, krp_tx_deemph_override, + SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, + reset_tx_deemphasis_override)); + + /* START OF LSI SUGGESTED SERDES BRINGUP */ + /* Reset - Calibration Setup */ + /* Stop DFE adaptaion */ + ibsd_wr_allchans(ppd, 1, 0, BMASK(9, 1)); + /* Disable LE1 */ + ibsd_wr_allchans(ppd, 13, 0, BMASK(5, 5)); + /* Disable autoadapt for LE1 */ + ibsd_wr_allchans(ppd, 1, 0, BMASK(15, 15)); + /* Disable LE2 */ + ibsd_wr_allchans(ppd, 13, 0, BMASK(6, 6)); + /* Disable VGA */ + ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0)); + /* Disable AFE Offset Cancel */ + ibsd_wr_allchans(ppd, 12, 0, BMASK(12, 12)); + /* Disable Timing Loop */ + ibsd_wr_allchans(ppd, 2, 0, BMASK(3, 3)); + /* Disable Frequency Loop */ + ibsd_wr_allchans(ppd, 2, 0, BMASK(4, 4)); + /* Disable Baseline Wander Correction */ + ibsd_wr_allchans(ppd, 13, 0, BMASK(13, 13)); + /* Disable RX Calibration */ + ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10)); + /* Disable RX Offset Calibration */ + ibsd_wr_allchans(ppd, 12, 0, BMASK(4, 4)); + /* Select BB CDR */ + ibsd_wr_allchans(ppd, 2, (1 << 15), BMASK(15, 15)); + /* CDR Step Size */ + ibsd_wr_allchans(ppd, 5, 0, BMASK(9, 8)); + /* Enable phase Calibration */ + ibsd_wr_allchans(ppd, 12, (1 << 5), BMASK(5, 5)); + /* DFE Bandwidth [2:14-12] */ + ibsd_wr_allchans(ppd, 2, (4 << 12), BMASK(14, 12)); + /* DFE Config (4 taps only) */ + ibsd_wr_allchans(ppd, 16, 0, BMASK(1, 0)); + /* Gain Loop Bandwidth */ + if (!ppd->dd->cspec->r1) { + ibsd_wr_allchans(ppd, 12, 1 << 12, BMASK(12, 12)); + ibsd_wr_allchans(ppd, 12, 2 << 8, BMASK(11, 8)); + } else { + ibsd_wr_allchans(ppd, 19, (3 << 11), BMASK(13, 11)); + } + /* Baseline Wander Correction Gain [13:4-0] (leave as default) */ + /* Baseline Wander Correction Gain [3:7-5] (leave as default) */ + /* Data Rate Select [5:7-6] (leave as default) */ + /* RX Parralel Word Width [3:10-8] (leave as default) */ + + /* RX REST */ + /* Single- or Multi-channel reset */ + /* RX Analog reset */ + /* RX Digital reset */ + ibsd_wr_allchans(ppd, 0, 0, BMASK(15, 13)); + msleep(20); + /* RX Analog reset */ + ibsd_wr_allchans(ppd, 0, (1 << 14), BMASK(14, 14)); + msleep(20); + /* RX Digital reset */ + ibsd_wr_allchans(ppd, 0, (1 << 13), BMASK(13, 13)); + msleep(20); + + /* setup LoS params; these are subsystem, so chan == 5 */ + /* LoS filter threshold_count on, ch 0-3, set to 8 */ + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 5, 8 << 11, BMASK(14, 11)); + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 8 << 4, BMASK(7, 4)); + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 8, 8 << 11, BMASK(14, 11)); + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 8 << 4, BMASK(7, 4)); + + /* LoS filter threshold_count off, ch 0-3, set to 4 */ + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 6, 4 << 0, BMASK(3, 0)); + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 7, 4 << 8, BMASK(11, 8)); + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 4 << 0, BMASK(3, 0)); + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 10, 4 << 8, BMASK(11, 8)); + + /* LoS filter select enabled */ + ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), 5, 9, 1 << 15, 1 << 15); + + /* LoS target data: SDR=4, DDR=2, QDR=1 */ + ibsd_wr_allchans(ppd, 14, (1 << 3), BMASK(5, 3)); /* QDR */ + ibsd_wr_allchans(ppd, 20, (2 << 10), BMASK(12, 10)); /* DDR */ + ibsd_wr_allchans(ppd, 20, (4 << 13), BMASK(15, 13)); /* SDR */ + + /* Turn on LOS on initial SERDES init */ + serdes_7322_los_enable(ppd, 1); + /* FLoop LOS gate: PPM filter enabled */ + ibsd_wr_allchans(ppd, 38, 0 << 10, 1 << 10); + + /* RX LATCH CALIBRATION */ + /* Enable Eyefinder Phase Calibration latch */ + ibsd_wr_allchans(ppd, 15, 1, BMASK(0, 0)); + /* Enable RX Offset Calibration latch */ + ibsd_wr_allchans(ppd, 12, (1 << 4), BMASK(4, 4)); + msleep(20); + /* Start Calibration */ + ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10)); + tstart = get_jiffies_64(); + while (chan_done && + !time_after64(tstart, tstart + msecs_to_jiffies(500))) { + msleep(20); + for (chan = 0; chan < SERDES_CHANS; ++chan) { + rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), + (chan + (chan >> 1)), + 25, 0, 0); + if ((~rxcaldone & (u32)BMASK(9, 9)) == 0 && + (~chan_done & (1 << chan)) == 0) + chan_done &= ~(1 << chan); + } + } + if (chan_done) { + printk(KERN_INFO QIB_DRV_NAME + " Serdes %d calibration not done after .5 sec: 0x%x\n", + IBSD(ppd->hw_pidx), chan_done); + } else { + for (chan = 0; chan < SERDES_CHANS; ++chan) { + rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), + (chan + (chan >> 1)), + 25, 0, 0); + if ((~rxcaldone & (u32)BMASK(10, 10)) == 0) + printk(KERN_INFO QIB_DRV_NAME + " Serdes %d chan %d calibration " + "failed\n", IBSD(ppd->hw_pidx), chan); + } + } + + /* Turn off Calibration */ + ibsd_wr_allchans(ppd, 4, 0, BMASK(10, 10)); + msleep(20); + + /* BRING RX UP */ + /* Set LE2 value (May be overridden in qsfp_7322_event) */ + le_val = IS_QME(ppd->dd) ? LE2_QME : LE2_DEFAULT; + ibsd_wr_allchans(ppd, 13, (le_val << 7), BMASK(9, 7)); + /* Set LE2 Loop bandwidth */ + ibsd_wr_allchans(ppd, 3, (7 << 5), BMASK(7, 5)); + /* Enable LE2 */ + ibsd_wr_allchans(ppd, 13, (1 << 6), BMASK(6, 6)); + msleep(20); + /* Enable H0 only */ + ibsd_wr_allchans(ppd, 1, 1, BMASK(9, 1)); + /* gain hi stop 32 (22) (6:1) lo stop 7 (10:7) target 22 (13) (15:11) */ + le_val = (ppd->dd->cspec->r1 || IS_QME(ppd->dd)) ? 0xb6c0 : 0x6bac; + ibsd_wr_allchans(ppd, 21, le_val, 0xfffe); + /* Enable VGA */ + ibsd_wr_allchans(ppd, 5, 0, BMASK(0, 0)); + msleep(20); + /* Set Frequency Loop Bandwidth */ + ibsd_wr_allchans(ppd, 2, (7 << 5), BMASK(8, 5)); + /* Enable Frequency Loop */ + ibsd_wr_allchans(ppd, 2, (1 << 4), BMASK(4, 4)); + /* Set Timing Loop Bandwidth */ + ibsd_wr_allchans(ppd, 2, 0, BMASK(11, 9)); + /* Enable Timing Loop */ + ibsd_wr_allchans(ppd, 2, (1 << 3), BMASK(3, 3)); + msleep(50); + /* Enable DFE + * Set receive adaptation mode. SDR and DDR adaptation are + * always on, and QDR is initially enabled; later disabled. + */ + qib_write_kreg_port(ppd, krp_static_adapt_dis(0), 0ULL); + qib_write_kreg_port(ppd, krp_static_adapt_dis(1), 0ULL); + qib_write_kreg_port(ppd, krp_static_adapt_dis(2), + ppd->dd->cspec->r1 ? + QDR_STATIC_ADAPT_DOWN_R1 : QDR_STATIC_ADAPT_DOWN); + ppd->cpspec->qdr_dfe_on = 1; + /* Disable LE1 */ + ibsd_wr_allchans(ppd, 13, (0 << 5), (1 << 5)); + /* Disable auto adapt for LE1 */ + ibsd_wr_allchans(ppd, 1, (0 << 15), BMASK(15, 15)); + msleep(20); + /* Enable AFE Offset Cancel */ + ibsd_wr_allchans(ppd, 12, (1 << 12), BMASK(12, 12)); + /* Enable Baseline Wander Correction */ + ibsd_wr_allchans(ppd, 12, (1 << 13), BMASK(13, 13)); + /* Termination: rxtermctrl_r2d addr 11 bits [12:11] = 1 */ + ibsd_wr_allchans(ppd, 11, (1 << 11), BMASK(12, 11)); + /* VGA output common mode */ + ibsd_wr_allchans(ppd, 12, (3 << 2), BMASK(3, 2)); + + return 0; +} + /* start adjust QMH serdes parameters */ static void set_man_code(struct qib_pportdata *ppd, int chan, int code) -- cgit v1.2.3 From f73df408b299e4bc5ed66cc50058585af64a8f9e Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:21 -0800 Subject: IB/qib: Reset packet list after freeing Reset the list pointers after freeing the SDMA packet list. This is done to any potential double-free cases. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_user_sdma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c index 4c19e06b5e85..66208bcd7c13 100644 --- a/drivers/infiniband/hw/qib/qib_user_sdma.c +++ b/drivers/infiniband/hw/qib/qib_user_sdma.c @@ -382,6 +382,7 @@ static void qib_user_sdma_free_pkt_list(struct device *dev, kmem_cache_free(pq->pkt_slab, pkt); } + INIT_LIST_HEAD(list); } /* -- cgit v1.2.3 From e706203c7c1cff8c27f9ce6d58911014a6bd826c Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:21 -0800 Subject: IB/qib: Add a few new SERDES tunings Add new SERDES tuning to aid manufacturing. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7322.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index d23297a307aa..a9c8c7235fcd 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -562,6 +562,7 @@ static void write_tx_serdes_param(struct qib_pportdata *, struct txdds_ent *); #define TXDDS_TABLE_SZ 16 /* number of entries per speed in onchip table */ #define TXDDS_EXTRA_SZ 13 /* number of extra tx settings entries */ +#define TXDDS_MFG_SZ 2 /* number of mfg tx settings entries */ #define SERDES_CHANS 4 /* yes, it's obvious, but one less magic number */ #define H1_FORCE_VAL 8 @@ -5623,6 +5624,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) u32 pidx, unit, port, deflt, h1; unsigned long val; int any = 0, seth1; + int txdds_size; str = txselect_list; @@ -5631,6 +5633,10 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) for (pidx = 0; pidx < dd->num_pports; ++pidx) dd->pport[pidx].cpspec->no_eep = deflt; + txdds_size = TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ; + if (IS_QME(dd) || IS_QMH(dd)) + txdds_size += TXDDS_MFG_SZ; + while (*nxt && nxt[1]) { str = ++nxt; unit = simple_strtoul(str, &nxt, 0); @@ -5653,7 +5659,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) ; continue; } - if (val >= TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ) + if (val >= txdds_size) continue; seth1 = 0; h1 = 0; /* gcc thinks it might be used uninitted */ @@ -5705,10 +5711,11 @@ static int setup_txselect(const char *str, struct kernel_param *kp) return -ENOSPC; } val = simple_strtoul(str, &n, 0); - if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ)) { + if (n == str || val >= (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ + + TXDDS_MFG_SZ)) { printk(KERN_INFO QIB_DRV_NAME "txselect_values must start with a number < %d\n", - TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ); + TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ + TXDDS_MFG_SZ); return -EINVAL; } strcpy(txselect_list, str); @@ -7039,6 +7046,12 @@ static const struct txdds_ent txdds_extra_qdr[TXDDS_EXTRA_SZ] = { { 0, 1, 0, 12 }, /* QMH7342 backplane settings */ }; +static const struct txdds_ent txdds_extra_mfg[TXDDS_MFG_SZ] = { + /* amp, pre, main, post */ + { 0, 0, 0, 0 }, /* QME7342 mfg settings */ + { 0, 0, 0, 6 }, /* QME7342 P2 mfg settings */ +}; + static const struct txdds_ent *get_atten_table(const struct txdds_ent *txdds, unsigned atten) { @@ -7112,6 +7125,16 @@ static void find_best_ent(struct qib_pportdata *ppd, *sdr_dds = &txdds_extra_sdr[idx]; *ddr_dds = &txdds_extra_ddr[idx]; *qdr_dds = &txdds_extra_qdr[idx]; + } else if ((IS_QME(ppd->dd) || IS_QMH(ppd->dd)) && + ppd->cpspec->no_eep < (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ + + TXDDS_MFG_SZ)) { + idx = ppd->cpspec->no_eep - (TXDDS_TABLE_SZ + TXDDS_EXTRA_SZ); + printk(KERN_INFO QIB_DRV_NAME + " IB%u:%u use idx %u into txdds_mfg\n", + ppd->dd->unit, ppd->port, idx); + *sdr_dds = &txdds_extra_mfg[idx]; + *ddr_dds = &txdds_extra_mfg[idx]; + *qdr_dds = &txdds_extra_mfg[idx]; } else { /* this shouldn't happen, it's range checked */ *sdr_dds = txdds_sdr + qib_long_atten; -- cgit v1.2.3 From aa7374ac19ca08715693b0a2d9f88f479af3ea7c Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:21 -0800 Subject: IB/qib: Avoid duplicate writes to the rcv head register Avoid duplicate writes to the head register as this can lead to lost interrupts if the context goes full before the second write is done. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_driver.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 9cd193603fb1..3ed0d5a9a566 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -71,6 +71,11 @@ MODULE_DESCRIPTION("QLogic IB driver"); */ #define QIB_PIO_MAXIBHDR 128 +/* + * QIB_MAX_PKT_RCV is the max # if packets processed per receive interrupt. + */ +#define QIB_MAX_PKT_RECV 64 + struct qlogic_ib_stats qib_stats; const char *qib_get_unit_name(int unit) @@ -335,7 +340,7 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts) smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ } - for (last = 0, i = 1; !last && i <= 64; i += !last) { + for (last = 0, i = 1; !last; i += !last) { hdr = dd->f_get_msgheader(dd, rhf_addr); eflags = qib_hdrget_err_flags(rhf_addr); etype = qib_hdrget_rcv_type(rhf_addr); @@ -384,6 +389,9 @@ move_along: l += rsize; if (l >= maxcnt) l = 0; + if (i == QIB_MAX_PKT_RECV) + last = 1; + rhf_addr = (__le32 *) rcd->rcvhdrq + l + dd->rhf_offset; if (dd->flags & QIB_NODMA_RTAIL) { u32 seq = qib_hdrget_seq(rhf_addr); -- cgit v1.2.3 From 19ede2e422496b2a064b9b22823c6afb66ff927b Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:21 -0800 Subject: IB/qib: Fix interrupt mitigation For SusieQ we need to write to the interrupt timer register before updating the header queue head with interrupt count. This is to ensure that the timer is enabled properly and a receive available interrupt is delivered. Otherwise this interrupt can be lost if the receiver header/eager queues are full before the timer is enabled. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib.h | 2 +- drivers/infiniband/hw/qib/qib_driver.c | 4 ++-- drivers/infiniband/hw/qib/qib_iba6120.c | 2 +- drivers/infiniband/hw/qib/qib_iba7220.c | 2 +- drivers/infiniband/hw/qib/qib_iba7322.c | 10 +++++++--- 5 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 64c9e7d02d4a..73225eee3cc6 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -766,7 +766,7 @@ struct qib_devdata { void (*f_sdma_hw_start_up)(struct qib_pportdata *); void (*f_sdma_init_early)(struct qib_pportdata *); void (*f_set_cntr_sample)(struct qib_pportdata *, u32, u32); - void (*f_update_usrhead)(struct qib_ctxtdata *, u64, u32, u32); + void (*f_update_usrhead)(struct qib_ctxtdata *, u64, u32, u32, u32); u32 (*f_hdrqempty)(struct qib_ctxtdata *); u64 (*f_portcntr)(struct qib_pportdata *, u32); u32 (*f_read_cntrs)(struct qib_devdata *, loff_t, char **, diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 3ed0d5a9a566..816a6bdc0b1c 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -410,7 +410,7 @@ move_along: */ lval = l; if (!last && !(i & 0xf)) { - dd->f_update_usrhead(rcd, lval, updegr, etail); + dd->f_update_usrhead(rcd, lval, updegr, etail, i); updegr = 0; } } @@ -452,7 +452,7 @@ bail: * if no packets were processed. */ lval = (u64)rcd->head | dd->rhdrhead_intr_off; - dd->f_update_usrhead(rcd, lval, updegr, etail); + dd->f_update_usrhead(rcd, lval, updegr, etail, i); return crcs; } diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index a5e29dbb9537..774dea897e9c 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -2074,7 +2074,7 @@ static void qib_6120_config_ctxts(struct qib_devdata *dd) } static void qib_update_6120_usrhead(struct qib_ctxtdata *rcd, u64 hd, - u32 updegr, u32 egrhd) + u32 updegr, u32 egrhd, u32 npkts) { qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); if (updegr) diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 6fd8d74e7392..df49e8e7cc2a 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2703,7 +2703,7 @@ static int qib_7220_set_loopback(struct qib_pportdata *ppd, const char *what) } static void qib_update_7220_usrhead(struct qib_ctxtdata *rcd, u64 hd, - u32 updegr, u32 egrhd) + u32 updegr, u32 egrhd, u32 npkts) { qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); if (updegr) diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index a9c8c7235fcd..9bc6d0835e30 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -2823,7 +2823,6 @@ static irqreturn_t qib_7322intr(int irq, void *data) ctxtrbits &= ~rmask; if (dd->rcd[i]) { qib_kreceive(dd->rcd[i], NULL, &npkts); - adjust_rcv_timeout(dd->rcd[i], npkts); } } rmask <<= 1; @@ -2873,7 +2872,6 @@ static irqreturn_t qib_7322pintr(int irq, void *data) (1ULL << QIB_I_RCVURG_LSB)) << rcd->ctxt); qib_kreceive(rcd, NULL, &npkts); - adjust_rcv_timeout(rcd, npkts); return IRQ_HANDLED; } @@ -4047,8 +4045,14 @@ static int qib_7322_set_ib_table(struct qib_pportdata *ppd, int which, void *t) } static void qib_update_7322_usrhead(struct qib_ctxtdata *rcd, u64 hd, - u32 updegr, u32 egrhd) + u32 updegr, u32 egrhd, u32 npkts) { + /* + * Need to write timeout register before updating rcvhdrhead to ensure + * that the timer is enabled on reception of a packet. + */ + if (hd >> IBA7322_HDRHEAD_PKTINT_SHIFT) + adjust_rcv_timeout(rcd, npkts); qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); if (updegr) -- cgit v1.2.3 From 2528ea60f94ef9e1e1cd82066d55f62a1d19fde1 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:21 -0800 Subject: IB/qib: Change receive queue/QPN selection The basic idea is that on SusieQ, the difficult part of mapping QPN to context is handled by the mapping registers so the generic QPN allocation doesn't need to worry about chip specifics. For Monty and Linda, there is no mapping table so the qpt->mask (same as dd->qpn_mask), is used to see if the QPN to context falls within [zero..dd->n_krcv_queues). Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7220.c | 2 +- drivers/infiniband/hw/qib/qib_iba7322.c | 8 ++------ drivers/infiniband/hw/qib/qib_qp.c | 26 ++++++++++---------------- drivers/infiniband/hw/qib/qib_verbs.h | 10 ++-------- 4 files changed, 15 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index df49e8e7cc2a..127a0d5069f0 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2297,7 +2297,7 @@ static void qib_7220_config_ctxts(struct qib_devdata *dd) nchipctxts = qib_read_kreg32(dd, kr_portcnt); dd->cspec->numctxts = nchipctxts; if (qib_n_krcv_queues > 1) { - dd->qpn_mask = 0x3f; + dd->qpn_mask = 0x3e; dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports; if (dd->first_user_ctxt > nchipctxts) dd->first_user_ctxt = nchipctxts; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 9bc6d0835e30..d3b493824cdc 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3515,11 +3515,6 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd) nchipctxts = qib_read_kreg32(dd, kr_contextcnt); dd->cspec->numctxts = nchipctxts; if (qib_n_krcv_queues > 1 && dd->num_pports) { - /* - * Set the mask for which bits from the QPN are used - * to select a context number. - */ - dd->qpn_mask = 0x3f; dd->first_user_ctxt = NUM_IB_PORTS + (qib_n_krcv_queues - 1) * dd->num_pports; if (dd->first_user_ctxt > nchipctxts) @@ -5865,7 +5860,8 @@ static void write_7322_initregs(struct qib_devdata *dd) unsigned n, regno; unsigned long flags; - if (!dd->qpn_mask || !dd->pport[pidx].link_speed_supported) + if (dd->n_krcv_queues < 2 || + !dd->pport[pidx].link_speed_supported) continue; ppd = &dd->pport[pidx]; diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index 32dacd444158..eaab008466ca 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -48,13 +48,12 @@ static inline unsigned mk_qpn(struct qib_qpn_table *qpt, static inline unsigned find_next_offset(struct qib_qpn_table *qpt, struct qpn_map *map, unsigned off, - unsigned r) + unsigned n) { if (qpt->mask) { off++; - if ((off & qpt->mask) >> 1 != r) - off = ((off & qpt->mask) ? - (off | qpt->mask) + 1 : off) | (r << 1); + if (((off & qpt->mask) >> 1) >= n) + off = (off | qpt->mask) + 2; } else off = find_next_zero_bit(map->page, BITS_PER_PAGE, off); return off; @@ -123,7 +122,6 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, u32 i, offset, max_scan, qpn; struct qpn_map *map; u32 ret; - int r; if (type == IB_QPT_SMI || type == IB_QPT_GSI) { unsigned n; @@ -139,15 +137,11 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, goto bail; } - r = smp_processor_id(); - if (r >= dd->n_krcv_queues) - r %= dd->n_krcv_queues; qpn = qpt->last + 1; if (qpn >= QPN_MAX) qpn = 2; - if (qpt->mask && ((qpn & qpt->mask) >> 1) != r) - qpn = ((qpn & qpt->mask) ? (qpn | qpt->mask) + 1 : qpn) | - (r << 1); + if (qpt->mask && ((qpn & qpt->mask) >> 1) >= dd->n_krcv_queues) + qpn = (qpn | qpt->mask) + 2; offset = qpn & BITS_PER_PAGE_MASK; map = &qpt->map[qpn / BITS_PER_PAGE]; max_scan = qpt->nmaps - !offset; @@ -163,7 +157,8 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, ret = qpn; goto bail; } - offset = find_next_offset(qpt, map, offset, r); + offset = find_next_offset(qpt, map, offset, + dd->n_krcv_queues); qpn = mk_qpn(qpt, map, offset); /* * This test differs from alloc_pidmap(). @@ -183,13 +178,13 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, if (qpt->nmaps == QPNMAP_ENTRIES) break; map = &qpt->map[qpt->nmaps++]; - offset = qpt->mask ? (r << 1) : 0; + offset = 0; } else if (map < &qpt->map[qpt->nmaps]) { ++map; - offset = qpt->mask ? (r << 1) : 0; + offset = 0; } else { map = &qpt->map[0]; - offset = qpt->mask ? (r << 1) : 2; + offset = 2; } qpn = mk_qpn(qpt, map, offset); } @@ -1065,7 +1060,6 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, } qp->ibqp.qp_num = err; qp->port_num = init_attr->port_num; - qp->processor_id = smp_processor_id(); qib_reset_qp(qp, init_attr->qp_type); break; diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index bd57c1273225..a08ceab510e1 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -435,7 +435,6 @@ struct qib_qp { spinlock_t r_lock; /* used for APM */ spinlock_t s_lock; atomic_t s_dma_busy; - unsigned processor_id; /* Processor ID QP is bound to */ u32 s_flags; u32 s_cur_size; /* size of send packet in bytes */ u32 s_len; /* total length of s_sge */ @@ -813,13 +812,8 @@ extern struct workqueue_struct *qib_cq_wq; */ static inline void qib_schedule_send(struct qib_qp *qp) { - if (qib_send_ok(qp)) { - if (qp->processor_id == smp_processor_id()) - queue_work(qib_wq, &qp->s_work); - else - queue_work_on(qp->processor_id, - qib_wq, &qp->s_work); - } + if (qib_send_ok(qp)) + queue_work(qib_wq, &qp->s_work); } static inline int qib_pkey_ok(u16 pkey1, u16 pkey2) -- cgit v1.2.3 From 057ae62faceccb50b0c2387af60dbbbcd40aab84 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:21 -0800 Subject: IB/qib: Add fix missing from earlier patch The upstream code was missing part of a receive/error race fix from the internal tree. Add the missing part, which makes future merges possible. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_ud.c | 55 +++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c index a4b945d9a303..4a51fd1e9cb7 100644 --- a/drivers/infiniband/hw/qib/qib_ud.c +++ b/drivers/infiniband/hw/qib/qib_ud.c @@ -445,13 +445,14 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, qkey = be32_to_cpu(ohdr->u.ud.deth[0]); src_qp = be32_to_cpu(ohdr->u.ud.deth[1]) & QIB_QPN_MASK; - /* Get the number of bytes the message was padded by. */ + /* + * Get the number of bytes the message was padded by + * and drop incomplete packets. + */ pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; - if (unlikely(tlen < (hdrsize + pad + 4))) { - /* Drop incomplete packets. */ - ibp->n_pkt_drops++; - goto bail; - } + if (unlikely(tlen < (hdrsize + pad + 4))) + goto drop; + tlen -= hdrsize + pad + 4; /* @@ -460,10 +461,8 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, */ if (qp->ibqp.qp_num) { if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE || - hdr->lrh[3] == IB_LID_PERMISSIVE)) { - ibp->n_pkt_drops++; - goto bail; - } + hdr->lrh[3] == IB_LID_PERMISSIVE)) + goto drop; if (qp->ibqp.qp_num > 1) { u16 pkey1, pkey2; @@ -476,7 +475,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, 0xF, src_qp, qp->ibqp.qp_num, hdr->lrh[3], hdr->lrh[1]); - goto bail; + return; } } if (unlikely(qkey != qp->qkey)) { @@ -484,30 +483,24 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF, src_qp, qp->ibqp.qp_num, hdr->lrh[3], hdr->lrh[1]); - goto bail; + return; } /* Drop invalid MAD packets (see 13.5.3.1). */ if (unlikely(qp->ibqp.qp_num == 1 && (tlen != 256 || - (be16_to_cpu(hdr->lrh[0]) >> 12) == 15))) { - ibp->n_pkt_drops++; - goto bail; - } + (be16_to_cpu(hdr->lrh[0]) >> 12) == 15))) + goto drop; } else { struct ib_smp *smp; /* Drop invalid MAD packets (see 13.5.3.1). */ - if (tlen != 256 || (be16_to_cpu(hdr->lrh[0]) >> 12) != 15) { - ibp->n_pkt_drops++; - goto bail; - } + if (tlen != 256 || (be16_to_cpu(hdr->lrh[0]) >> 12) != 15) + goto drop; smp = (struct ib_smp *) data; if ((hdr->lrh[1] == IB_LID_PERMISSIVE || hdr->lrh[3] == IB_LID_PERMISSIVE) && - smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { - ibp->n_pkt_drops++; - goto bail; - } + smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + goto drop; } /* @@ -523,10 +516,8 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, } else if (opcode == IB_OPCODE_UD_SEND_ONLY) { wc.ex.imm_data = 0; wc.wc_flags = 0; - } else { - ibp->n_pkt_drops++; - goto bail; - } + } else + goto drop; /* * A GRH is expected to preceed the data even if not @@ -556,8 +547,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, /* Silently drop packets which are too big. */ if (unlikely(wc.byte_len > qp->r_len)) { qp->r_flags |= QIB_R_REUSE_SGE; - ibp->n_pkt_drops++; - return; + goto drop; } if (has_grh) { qib_copy_sge(&qp->r_sge, &hdr->u.l.grh, @@ -594,5 +584,8 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, (ohdr->bth[0] & cpu_to_be32(IB_BTH_SOLICITED)) != 0); -bail:; + return; + +drop: + ibp->n_pkt_drops++; } -- cgit v1.2.3 From 7c3edd3ff3098093e594dbcbc9dbeeae09b1b4a0 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:22 -0800 Subject: IB/qib: Change QPN increment Changing from +1 to +2 allows for better QP distribution across receive contexts. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index eaab008466ca..e16751f8639e 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -137,7 +137,7 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, goto bail; } - qpn = qpt->last + 1; + qpn = qpt->last + 2; if (qpn >= QPN_MAX) qpn = 2; if (qpt->mask && ((qpn & qpt->mask) >> 1) >= dd->n_krcv_queues) -- cgit v1.2.3 From 2a600f14d25fda341b5633c75cc50a7574fc1007 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:22 -0800 Subject: IB/qib: RDMA lkey/rkey validation is inefficient for large MRs The current code loops during rkey/lkey validiation to isolate the MR for the RDMA, which is expensive when the current operation is inside a very large memory region. This fix optimizes rkey/lkey validation routines for user memory regions and fast memory regions. The MR entry can be isolated by shifts/mods instead of looping. The existing loop is preserved for phys memory regions for now. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_keys.c | 74 +++++++++++++++++++++++++---------- drivers/infiniband/hw/qib/qib_mr.c | 8 ++-- drivers/infiniband/hw/qib/qib_verbs.h | 1 + 3 files changed, 60 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c index 4b80eb153d57..756d16098e73 100644 --- a/drivers/infiniband/hw/qib/qib_keys.c +++ b/drivers/infiniband/hw/qib/qib_keys.c @@ -158,31 +158,47 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd, isge->sge_length = sge->length; isge->m = 0; isge->n = 0; + spin_unlock_irqrestore(&rkt->lock, flags); goto ok; } mr = rkt->table[(sge->lkey >> (32 - ib_qib_lkey_table_size))]; if (unlikely(mr == NULL || mr->lkey != sge->lkey || mr->pd != &pd->ibpd)) goto bail; + atomic_inc(&mr->refcount); + spin_unlock_irqrestore(&rkt->lock, flags); off = sge->addr - mr->user_base; if (unlikely(sge->addr < mr->user_base || off + sge->length > mr->length || (mr->access_flags & acc) != acc)) - goto bail; + return ret; off += mr->offset; - m = 0; - n = 0; - while (off >= mr->map[m]->segs[n].length) { - off -= mr->map[m]->segs[n].length; - n++; - if (n >= QIB_SEGSZ) { - m++; - n = 0; + if (mr->page_shift) { + /* + page sizes are uniform power of 2 so no loop is necessary + entries_spanned_by_off is the number of times the loop below + would have executed. + */ + size_t entries_spanned_by_off; + + entries_spanned_by_off = off >> mr->page_shift; + off -= (entries_spanned_by_off << mr->page_shift); + m = entries_spanned_by_off/QIB_SEGSZ; + n = entries_spanned_by_off%QIB_SEGSZ; + } else { + m = 0; + n = 0; + while (off >= mr->map[m]->segs[n].length) { + off -= mr->map[m]->segs[n].length; + n++; + if (n >= QIB_SEGSZ) { + m++; + n = 0; + } } } - atomic_inc(&mr->refcount); isge->mr = mr; isge->vaddr = mr->map[m]->segs[n].vaddr + off; isge->length = mr->map[m]->segs[n].length - off; @@ -191,6 +207,7 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd, isge->n = n; ok: ret = 1; + return ret; bail: spin_unlock_irqrestore(&rkt->lock, flags); return ret; @@ -237,30 +254,46 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge, sge->sge_length = len; sge->m = 0; sge->n = 0; + spin_unlock_irqrestore(&rkt->lock, flags); goto ok; } mr = rkt->table[(rkey >> (32 - ib_qib_lkey_table_size))]; if (unlikely(mr == NULL || mr->lkey != rkey || qp->ibqp.pd != mr->pd)) goto bail; + atomic_inc(&mr->refcount); + spin_unlock_irqrestore(&rkt->lock, flags); off = vaddr - mr->iova; if (unlikely(vaddr < mr->iova || off + len > mr->length || (mr->access_flags & acc) == 0)) - goto bail; + return ret; off += mr->offset; - m = 0; - n = 0; - while (off >= mr->map[m]->segs[n].length) { - off -= mr->map[m]->segs[n].length; - n++; - if (n >= QIB_SEGSZ) { - m++; - n = 0; + if (mr->page_shift) { + /* + page sizes are uniform power of 2 so no loop is necessary + entries_spanned_by_off is the number of times the loop below + would have executed. + */ + size_t entries_spanned_by_off; + + entries_spanned_by_off = off >> mr->page_shift; + off -= (entries_spanned_by_off << mr->page_shift); + m = entries_spanned_by_off/QIB_SEGSZ; + n = entries_spanned_by_off%QIB_SEGSZ; + } else { + m = 0; + n = 0; + while (off >= mr->map[m]->segs[n].length) { + off -= mr->map[m]->segs[n].length; + n++; + if (n >= QIB_SEGSZ) { + m++; + n = 0; + } } } - atomic_inc(&mr->refcount); sge->mr = mr; sge->vaddr = mr->map[m]->segs[n].vaddr + off; sge->length = mr->map[m]->segs[n].length - off; @@ -269,6 +302,7 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge, sge->n = n; ok: ret = 1; + return ret; bail: spin_unlock_irqrestore(&rkt->lock, flags); return ret; diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c index 5f95f0f6385d..08944e2ee334 100644 --- a/drivers/infiniband/hw/qib/qib_mr.c +++ b/drivers/infiniband/hw/qib/qib_mr.c @@ -39,7 +39,6 @@ /* Fast memory region */ struct qib_fmr { struct ib_fmr ibfmr; - u8 page_shift; struct qib_mregion mr; /* must be last */ }; @@ -107,6 +106,7 @@ static struct qib_mr *alloc_mr(int count, struct qib_lkey_table *lk_table) goto bail; } mr->mr.mapsz = m; + mr->mr.page_shift = 0; mr->mr.max_segs = count; /* @@ -231,6 +231,8 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mr->mr.access_flags = mr_access_flags; mr->umem = umem; + if (is_power_of_2(umem->page_size)) + mr->mr.page_shift = ilog2(umem->page_size); m = 0; n = 0; list_for_each_entry(chunk, &umem->chunk_list, list) { @@ -390,7 +392,7 @@ struct ib_fmr *qib_alloc_fmr(struct ib_pd *pd, int mr_access_flags, fmr->mr.offset = 0; fmr->mr.access_flags = mr_access_flags; fmr->mr.max_segs = fmr_attr->max_pages; - fmr->page_shift = fmr_attr->page_shift; + fmr->mr.page_shift = fmr_attr->page_shift; atomic_set(&fmr->mr.refcount, 0); ret = &fmr->ibfmr; @@ -437,7 +439,7 @@ int qib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, spin_lock_irqsave(&rkt->lock, flags); fmr->mr.user_base = iova; fmr->mr.iova = iova; - ps = 1 << fmr->page_shift; + ps = 1 << fmr->mr.page_shift; fmr->mr.length = list_len * ps; m = 0; n = 0; diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index a08ceab510e1..63b22a9a7feb 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -301,6 +301,7 @@ struct qib_mregion { int access_flags; u32 max_segs; /* number of qib_segs in all the arrays */ u32 mapsz; /* size of the map array */ + u8 page_shift; /* 0 - non unform/non powerof2 sizes */ atomic_t refcount; struct qib_segarray *map[0]; /* the segments */ }; -- cgit v1.2.3 From 994bcd28a36af1413381dfe0aac065e2cbc2af40 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:22 -0800 Subject: IB/qib: Issue pre-emptive NAKs on eager buffer overflow Under congestion resulting in eager buffer overflow attempt to send pre-emptive NAKs if header queue entries with TID errors are generated and a valid header is present. This prevents long timeouts and flow restarts if a trailing set of packets are dropped due to eager overflows. Pre-emptive NAKs are currently only supported for RDMA writes. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_driver.c | 141 ++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 816a6bdc0b1c..23e584f4c36c 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -289,14 +289,147 @@ static inline void *qib_get_egrbuf(const struct qib_ctxtdata *rcd, u32 etail) * Returns 1 if error was a CRC, else 0. * Needed for some chip's synthesized error counters. */ -static u32 qib_rcv_hdrerr(struct qib_pportdata *ppd, u32 ctxt, - u32 eflags, u32 l, u32 etail, __le32 *rhf_addr, - struct qib_message_header *hdr) +static u32 qib_rcv_hdrerr(struct qib_ctxtdata *rcd, struct qib_pportdata *ppd, + u32 ctxt, u32 eflags, u32 l, u32 etail, + __le32 *rhf_addr, struct qib_message_header *rhdr) { u32 ret = 0; if (eflags & (QLOGIC_IB_RHF_H_ICRCERR | QLOGIC_IB_RHF_H_VCRCERR)) ret = 1; + else if (eflags == QLOGIC_IB_RHF_H_TIDERR) { + /* For TIDERR and RC QPs premptively schedule a NAK */ + struct qib_ib_header *hdr = (struct qib_ib_header *) rhdr; + struct qib_other_headers *ohdr = NULL; + struct qib_ibport *ibp = &ppd->ibport_data; + struct qib_qp *qp = NULL; + u32 tlen = qib_hdrget_length_in_bytes(rhf_addr); + u16 lid = be16_to_cpu(hdr->lrh[1]); + int lnh = be16_to_cpu(hdr->lrh[0]) & 3; + u32 qp_num; + u32 opcode; + u32 psn; + int diff; + unsigned long flags; + + /* Sanity check packet */ + if (tlen < 24) + goto drop; + + if (lid < QIB_MULTICAST_LID_BASE) { + lid &= ~((1 << ppd->lmc) - 1); + if (unlikely(lid != ppd->lid)) + goto drop; + } + + /* Check for GRH */ + if (lnh == QIB_LRH_BTH) + ohdr = &hdr->u.oth; + else if (lnh == QIB_LRH_GRH) { + u32 vtf; + + ohdr = &hdr->u.l.oth; + if (hdr->u.l.grh.next_hdr != IB_GRH_NEXT_HDR) + goto drop; + vtf = be32_to_cpu(hdr->u.l.grh.version_tclass_flow); + if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) + goto drop; + } else + goto drop; + + /* Get opcode and PSN from packet */ + opcode = be32_to_cpu(ohdr->bth[0]); + opcode >>= 24; + psn = be32_to_cpu(ohdr->bth[2]); + + /* Get the destination QP number. */ + qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK; + if (qp_num != QIB_MULTICAST_QPN) { + int ruc_res; + qp = qib_lookup_qpn(ibp, qp_num); + if (!qp) + goto drop; + + /* + * Handle only RC QPs - for other QP types drop error + * packet. + */ + spin_lock(&qp->r_lock); + + /* Check for valid receive state. */ + if (!(ib_qib_state_ops[qp->state] & + QIB_PROCESS_RECV_OK)) { + ibp->n_pkt_drops++; + goto unlock; + } + + switch (qp->ibqp.qp_type) { + case IB_QPT_RC: + spin_lock_irqsave(&qp->s_lock, flags); + ruc_res = + qib_ruc_check_hdr( + ibp, hdr, + lnh == QIB_LRH_GRH, + qp, + be32_to_cpu(ohdr->bth[0])); + if (ruc_res) { + spin_unlock_irqrestore(&qp->s_lock, + flags); + goto unlock; + } + spin_unlock_irqrestore(&qp->s_lock, flags); + + /* Only deal with RDMA Writes for now */ + if (opcode < + IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) { + diff = qib_cmp24(psn, qp->r_psn); + if (!qp->r_nak_state && diff >= 0) { + ibp->n_rc_seqnak++; + qp->r_nak_state = + IB_NAK_PSN_ERROR; + /* Use the expected PSN. */ + qp->r_ack_psn = qp->r_psn; + /* + * Wait to send the sequence + * NAK until all packets + * in the receive queue have + * been processed. + * Otherwise, we end up + * propagating congestion. + */ + if (list_empty(&qp->rspwait)) { + qp->r_flags |= + QIB_R_RSP_NAK; + atomic_inc( + &qp->refcount); + list_add_tail( + &qp->rspwait, + &rcd->qp_wait_list); + } + } /* Out of sequence NAK */ + } /* QP Request NAKs */ + break; + case IB_QPT_SMI: + case IB_QPT_GSI: + case IB_QPT_UD: + case IB_QPT_UC: + default: + /* For now don't handle any other QP types */ + break; + } + +unlock: + spin_unlock(&qp->r_lock); + /* + * Notify qib_destroy_qp() if it is waiting + * for us to finish. + */ + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } /* Unicast QP */ + } /* Valid packet with TIDErr */ + +drop: return ret; } @@ -376,7 +509,7 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts) * packets; only qibhdrerr should be set. */ if (unlikely(eflags)) - crcs += qib_rcv_hdrerr(ppd, rcd->ctxt, eflags, l, + crcs += qib_rcv_hdrerr(rcd, ppd, rcd->ctxt, eflags, l, etail, rhf_addr, hdr); else if (etype == RCVHQ_RCV_TYPE_NON_KD) { qib_ib_rcv(rcd, hdr, ebuf, tlen); -- cgit v1.2.3 From dd04e43d46ad7a4e625a9ff3b270dc0db9abe81d Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:22 -0800 Subject: IB/qib: Unnecessary delayed completions on RC connection Currently on receipt of a response message (ACKs, RDMA Response, Atomic Responses etc.) if the SDMA completion counter is not advanced the driver delays the completion of the WQE. In most cases this is overly pessimistic as the response (ACK) to a previously transmitted send implies that the send is complete. Ensure that SDMA queue is progressed appropriately before determining if a send has delayed completions. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_rc.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index 955fb7157793..8245237b67ce 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -1407,6 +1407,7 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp, struct qib_ctxtdata *rcd) { struct qib_swqe *wqe; + struct qib_pportdata *ppd = ppd_from_ibp(ibp); enum ib_wc_status status; unsigned long flags; int diff; @@ -1414,6 +1415,29 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp, u32 aeth; u64 val; + if (opcode != OP(RDMA_READ_RESPONSE_MIDDLE)) { + /* + * If ACK'd PSN on SDMA busy list try to make progress to + * reclaim SDMA credits. + */ + if ((qib_cmp24(psn, qp->s_sending_psn) >= 0) && + (qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) <= 0)) { + + /* + * If send tasklet not running attempt to progress + * SDMA queue. + */ + if (!(qp->s_flags & QIB_S_BUSY)) { + /* Acquire SDMA Lock */ + spin_lock_irqsave(&ppd->sdma_lock, flags); + /* Invoke sdma make progress */ + qib_sdma_make_progress(ppd); + /* Release SDMA Lock */ + spin_unlock_irqrestore(&ppd->sdma_lock, flags); + } + } + } + spin_lock_irqsave(&qp->s_lock, flags); /* Ignore invalid responses. */ -- cgit v1.2.3 From f2d255a0787119f7f4dc0e6093a0bd2700a49402 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:22 -0800 Subject: IB/qib: Improve SERDES tunning on QMH boards Improve the QMH SERDES tunning on initial driver load by having the driver go through a link state change. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_iba7322.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index d3b493824cdc..dbbb0e85afe4 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -623,6 +623,7 @@ struct qib_chippport_specific { u8 ibmalfusesnap; struct qib_qsfp_data qsfp_data; char epmsgbuf[192]; /* for port error interrupt msg buffer */ + u8 bounced; }; static struct { @@ -1742,6 +1743,8 @@ static void handle_serdes_issues(struct qib_pportdata *ppd, u64 ibcst) } } +static int qib_7322_set_ib_cfg(struct qib_pportdata *, int, u32); + /* * This is per-pport error handling. * will likely get it's own MSIx interrupt (one for each port, @@ -1878,7 +1881,23 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd) IB_PHYSPORTSTATE_DISABLED) qib_set_ib_7322_lstate(ppd, 0, QLOGIC_IB_IBCC_LINKINITCMD_DISABLE); - else + else { + u32 lstate; + /* + * We need the current logical link state before + * lflags are set in handle_e_ibstatuschanged. + */ + lstate = qib_7322_iblink_state(ibcs); + + if (IS_QMH(dd) && !ppd->cpspec->bounced && + ltstate == IB_PHYSPORTSTATE_LINKUP && + (lstate >= IB_PORT_INIT && + lstate <= IB_PORT_ACTIVE)) { + ppd->cpspec->bounced = 1; + qib_7322_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE, + IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL); + } + /* * Since going into a recovery state causes the link * state to go down and since recovery is transitory, @@ -1892,6 +1911,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd) ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT && ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE) qib_handle_e_ibstatuschanged(ppd, ibcs); + } } if (*msg && iserr) qib_dev_porterr(dd, ppd->port, "%s error\n", msg); @@ -7282,8 +7302,8 @@ static void ibsd_wr_allchans(struct qib_pportdata *ppd, int addr, unsigned data, static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable) { u64 data = qib_read_kreg_port(ppd, krp_serdesctrl); - printk(KERN_INFO QIB_DRV_NAME " Turning LOS %s for port %d\n", - (enable ? "on" : "off"), ppd->port); + printk(KERN_INFO QIB_DRV_NAME " IB%u:%u Turning LOS %s\n", + ppd->dd->unit, ppd->port, (enable ? "on" : "off")); if (enable) data |= SYM_MASK(IBSerdesCtrl_0, RXLOSEN); else -- cgit v1.2.3 From 4db62d4786e946e6fc8c2bb1f9201508f7f46c41 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Jan 2011 17:42:23 -0800 Subject: IB/qib: Fix refcount leak in lkey/rkey validation The mr optimization introduced a reference count leak on an exception test. The lock/refcount manipulation is moved down and the problematic exception test now calls bail to insure that the lock is released. Additional fixes as suggested by Ralph Campbell : - reduce lock scope of dma regions - use explicit values on returns vs. automatic ret value Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_keys.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c index 756d16098e73..8fd19a47df0c 100644 --- a/drivers/infiniband/hw/qib/qib_keys.c +++ b/drivers/infiniband/hw/qib/qib_keys.c @@ -136,7 +136,6 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd, struct qib_mregion *mr; unsigned n, m; size_t off; - int ret = 0; unsigned long flags; /* @@ -152,27 +151,28 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd, if (!dev->dma_mr) goto bail; atomic_inc(&dev->dma_mr->refcount); + spin_unlock_irqrestore(&rkt->lock, flags); + isge->mr = dev->dma_mr; isge->vaddr = (void *) sge->addr; isge->length = sge->length; isge->sge_length = sge->length; isge->m = 0; isge->n = 0; - spin_unlock_irqrestore(&rkt->lock, flags); goto ok; } mr = rkt->table[(sge->lkey >> (32 - ib_qib_lkey_table_size))]; if (unlikely(mr == NULL || mr->lkey != sge->lkey || mr->pd != &pd->ibpd)) goto bail; - atomic_inc(&mr->refcount); - spin_unlock_irqrestore(&rkt->lock, flags); off = sge->addr - mr->user_base; if (unlikely(sge->addr < mr->user_base || off + sge->length > mr->length || (mr->access_flags & acc) != acc)) - return ret; + goto bail; + atomic_inc(&mr->refcount); + spin_unlock_irqrestore(&rkt->lock, flags); off += mr->offset; if (mr->page_shift) { @@ -206,11 +206,10 @@ int qib_lkey_ok(struct qib_lkey_table *rkt, struct qib_pd *pd, isge->m = m; isge->n = n; ok: - ret = 1; - return ret; + return 1; bail: spin_unlock_irqrestore(&rkt->lock, flags); - return ret; + return 0; } /** @@ -231,7 +230,6 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge, struct qib_mregion *mr; unsigned n, m; size_t off; - int ret = 0; unsigned long flags; /* @@ -248,26 +246,27 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge, if (!dev->dma_mr) goto bail; atomic_inc(&dev->dma_mr->refcount); + spin_unlock_irqrestore(&rkt->lock, flags); + sge->mr = dev->dma_mr; sge->vaddr = (void *) vaddr; sge->length = len; sge->sge_length = len; sge->m = 0; sge->n = 0; - spin_unlock_irqrestore(&rkt->lock, flags); goto ok; } mr = rkt->table[(rkey >> (32 - ib_qib_lkey_table_size))]; if (unlikely(mr == NULL || mr->lkey != rkey || qp->ibqp.pd != mr->pd)) goto bail; - atomic_inc(&mr->refcount); - spin_unlock_irqrestore(&rkt->lock, flags); off = vaddr - mr->iova; if (unlikely(vaddr < mr->iova || off + len > mr->length || (mr->access_flags & acc) == 0)) - return ret; + goto bail; + atomic_inc(&mr->refcount); + spin_unlock_irqrestore(&rkt->lock, flags); off += mr->offset; if (mr->page_shift) { @@ -301,11 +300,10 @@ int qib_rkey_ok(struct qib_qp *qp, struct qib_sge *sge, sge->m = m; sge->n = n; ok: - ret = 1; - return ret; + return 1; bail: spin_unlock_irqrestore(&rkt->lock, flags); - return ret; + return 0; } /* -- cgit v1.2.3 From c7321d6f88e1f962d605923a93f9c255e4d0b8c9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 7 Jan 2011 11:57:55 +0000 Subject: fbdev: sh_mobile_hdmi: add command line option to use the preferred EDID mode Currently, if no command-line option is specified, the sh_mobile_hdmi will use the default 720p video mode. If a command line option of the form "video=sh_mobile_lcdc:x@" is provided, the driver will look for that mode among those, available in the monitor EDID. This patch adds the ability to request the driver to use monitor's preferred mode by specifying 0 as width and hight in the above string. If that mode is not supported by the system, the driver will continue scanning through EDID modes, until it finds a suitable one. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 60 +++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 8c59cc8c5a9c..571bd9f74513 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -737,7 +737,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, struct fb_modelist *modelist = NULL; unsigned int f_width = 0, f_height = 0, f_refresh = 0; unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ - bool exact_match = false; + bool scanning = false, preferred_bad = false; u8 edid[128]; char *forced; int i; @@ -800,6 +800,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, if (i < 2) { f_width = 0; f_height = 0; + } else { + /* The user wants us to use the EDID data */ + scanning = true; } dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", f_width, f_height, f_refresh); @@ -807,37 +810,56 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, /* Walk monitor modes to find the best or the exact match */ for (i = 0, mode = hdmi->monspec.modedb; - f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; + i < hdmi->monspec.modedb_len && scanning; i++, mode++) { unsigned long rate_error; - /* No interest in unmatching modes */ - if (f_width != mode->xres || f_height != mode->yres) + if (!f_width && !f_height) { + /* + * A parameter string "video=sh_mobile_lcdc:0x0" means + * use the preferred EDID mode. If it is rejected by + * .fb_check_var(), keep looking, until an acceptable + * one is found. + */ + if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad) + scanning = false; + else + continue; + } else if (f_width != mode->xres || f_height != mode->yres) { + /* No interest in unmatching modes */ continue; + } rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); - if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) - /* - * Exact match if either the refresh rate matches or it - * hasn't been specified and we've found a mode, for - * which we can configure the clock precisely - */ - exact_match = true; - else if (found && found_rate_error <= rate_error) - /* - * We otherwise search for the closest matching clock - * rate - either if no refresh rate has been specified - * or we cannot find an exactly matching one - */ - continue; + if (scanning) { + if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) + /* + * Exact match if either the refresh rate + * matches or it hasn't been specified and we've + * found a mode, for which we can configure the + * clock precisely + */ + scanning = false; + else if (found && found_rate_error <= rate_error) + /* + * We otherwise search for the closest matching + * clock rate - either if no refresh rate has + * been specified or we cannot find an exactly + * matching one + */ + continue; + } /* Check if supported: sufficient fb memory, supported clock-rate */ fb_videomode_to_var(var, mode); + var->bits_per_pixel = info->var.bits_per_pixel; + if (info && info->fbops->fb_check_var && info->fbops->fb_check_var(var, info)) { - exact_match = false; + scanning = true; + preferred_bad = true; continue; } -- cgit v1.2.3 From eb0778bd3c1d4d29ffb7e13739463855d92965df Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 7 Jan 2011 11:57:59 +0000 Subject: fbdev: sh_mobile_hdmi: framebuffer notifiers have to be registered A previous patch added a framebuffer notifier to sh_mobile_hdmi.c, but did not register it with the framebuffer core. This patch adds such a registration and moves the notifier block into dynamically allocated per-device private data. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 571bd9f74513..46ab355e0a6a 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -221,6 +221,7 @@ struct sh_hdmi { struct delayed_work edid_work; struct fb_var_screeninfo var; struct fb_monspecs monspec; + struct notifier_block notifier; }; static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) @@ -1196,13 +1197,6 @@ out: dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); } -static int sh_hdmi_notify(struct notifier_block *nb, - unsigned long action, void *data); - -static struct notifier_block sh_hdmi_notifier = { - .notifier_call = sh_hdmi_notify, -}; - static int sh_hdmi_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -1212,7 +1206,7 @@ static int sh_hdmi_notify(struct notifier_block *nb, struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; struct sh_hdmi *hdmi = board_cfg->board_data; - if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) + if (!hdmi || nb != &hdmi->notifier || hdmi->info != info) return NOTIFY_DONE; switch(action) { @@ -1231,11 +1225,11 @@ static int sh_hdmi_notify(struct notifier_block *nb, * temporarily, synchronise with the work queue and re-acquire * the info->lock. */ - unlock_fb_info(hdmi->info); + unlock_fb_info(info); mutex_lock(&hdmi->mutex); hdmi->info = NULL; mutex_unlock(&hdmi->mutex); - lock_fb_info(hdmi->info); + lock_fb_info(info); return NOTIFY_OK; } return NOTIFY_DONE; @@ -1333,6 +1327,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto ecodec; } + hdmi->notifier.notifier_call = sh_hdmi_notify; + fb_register_client(&hdmi->notifier); + return 0; ecodec: @@ -1363,6 +1360,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) snd_soc_unregister_codec(&pdev->dev); + fb_unregister_client(&hdmi->notifier); + board_cfg->display_on = NULL; board_cfg->display_off = NULL; board_cfg->board_data = NULL; -- cgit v1.2.3 From 0d7fa180a8f314eaa4f766a852bf73abce4dbcc2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 7 Jan 2011 11:58:03 +0000 Subject: fbdev: sh_mobile_hdmi: simplify pointer handling Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 46ab355e0a6a..e3eb77dfbf22 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -878,9 +878,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, * driver, and passing ->info with HDMI platform data. */ if (info && !found) { - modelist = hdmi->info->modelist.next && - !list_empty(&hdmi->info->modelist) ? - list_entry(hdmi->info->modelist.next, + modelist = info->modelist.next && + !list_empty(&info->modelist) ? + list_entry(info->modelist.next, struct fb_modelist, list) : NULL; @@ -1123,6 +1123,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { + struct fb_info *info = hdmi->info; unsigned long parent_rate = 0, hdmi_rate; /* A device has been plugged in */ @@ -1144,22 +1145,21 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) /* Switched to another (d) power-save mode */ msleep(10); - if (!hdmi->info) + if (!info) goto out; - ch = hdmi->info->par; + ch = info->par; acquire_console_sem(); /* HDMI plug in */ if (!sh_hdmi_must_reconfigure(hdmi) && - hdmi->info->state == FBINFO_STATE_RUNNING) { + info->state == FBINFO_STATE_RUNNING) { /* * First activation with the default monitor - just turn * on, if we run a resume here, the logo disappears */ - if (lock_fb_info(hdmi->info)) { - struct fb_info *info = hdmi->info; + if (lock_fb_info(info)) { info->var.width = hdmi->var.width; info->var.height = hdmi->var.height; sh_hdmi_display_on(hdmi, info); @@ -1167,7 +1167,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) } } else { /* New monitor or have to wake up */ - fb_set_suspend(hdmi->info, 0); + fb_set_suspend(info, 0); } release_console_sem(); -- cgit v1.2.3 From 90a48151599b5f5137aeb0c8849557231e9c1640 Mon Sep 17 00:00:00 2001 From: Vicente Jiménez Date: Sat, 8 Jan 2011 00:54:26 +0000 Subject: video: matroxfb: Correct video option in comments and kernel config help. Configuring the kernel I found that the Matrox frame buffer help has a different option than the one in the docs (Documentation/fb/matroxfb.txt). I decided to check the source code to see what is the correct option. drivers/video/matrox/matroxfb_base.c has a lot of comments that sugests that the video option is "matrox". However in line 2452 of this same file you have: fb_get_options("matroxfb", &option) video=matroxfb:XXX is the correct video option not video=matrox:XXX. Signed-off-by: Vicente Jimenez Aguilar Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 2 +- drivers/video/matrox/matroxfb_base.c | 70 ++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 55dc6fb6e909..c183faace63a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1273,7 +1273,7 @@ config FB_MATROX module will be called matroxfb. You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=matrox:XXX", and + module load time. The parameters look like "video=matroxfb:XXX", and are described in . config FB_MATROX_MILLENIUM diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 052dd9f0b760..a082debe824b 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1247,46 +1247,46 @@ static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; }; /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ -static unsigned int mem; /* "matrox:mem:xxxxxM" */ +static unsigned int mem; /* "matroxfb:mem:xxxxxM" */ static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ -static int inv24; /* "matrox:inv24" */ -static int cross4MB = -1; /* "matrox:cross4MB" */ -static int disabled; /* "matrox:disabled" */ -static int noaccel; /* "matrox:noaccel" */ -static int nopan; /* "matrox:nopan" */ -static int no_pci_retry; /* "matrox:nopciretry" */ -static int novga; /* "matrox:novga" */ -static int nobios; /* "matrox:nobios" */ -static int noinit = 1; /* "matrox:init" */ -static int inverse; /* "matrox:inverse" */ -static int sgram; /* "matrox:sgram" */ +static int inv24; /* "matroxfb:inv24" */ +static int cross4MB = -1; /* "matroxfb:cross4MB" */ +static int disabled; /* "matroxfb:disabled" */ +static int noaccel; /* "matroxfb:noaccel" */ +static int nopan; /* "matroxfb:nopan" */ +static int no_pci_retry; /* "matroxfb:nopciretry" */ +static int novga; /* "matroxfb:novga" */ +static int nobios; /* "matroxfb:nobios" */ +static int noinit = 1; /* "matroxfb:init" */ +static int inverse; /* "matroxfb:inverse" */ +static int sgram; /* "matroxfb:sgram" */ #ifdef CONFIG_MTRR -static int mtrr = 1; /* "matrox:nomtrr" */ +static int mtrr = 1; /* "matroxfb:nomtrr" */ #endif -static int grayscale; /* "matrox:grayscale" */ -static int dev = -1; /* "matrox:dev:xxxxx" */ -static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ -static int depth = -1; /* "matrox:depth:xxxxx" */ -static unsigned int xres; /* "matrox:xres:xxxxx" */ -static unsigned int yres; /* "matrox:yres:xxxxx" */ -static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */ -static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */ -static unsigned int vslen; /* "matrox:vslen:xxxxx" */ -static unsigned int left = ~0; /* "matrox:left:xxxxx" */ -static unsigned int right = ~0; /* "matrox:right:xxxxx" */ -static unsigned int hslen; /* "matrox:hslen:xxxxx" */ -static unsigned int pixclock; /* "matrox:pixclock:xxxxx" */ -static int sync = -1; /* "matrox:sync:xxxxx" */ -static unsigned int fv; /* "matrox:fv:xxxxx" */ -static unsigned int fh; /* "matrox:fh:xxxxxk" */ -static unsigned int maxclk; /* "matrox:maxclk:xxxxM" */ -static int dfp; /* "matrox:dfp */ -static int dfp_type = -1; /* "matrox:dfp:xxx */ -static int memtype = -1; /* "matrox:memtype:xxx" */ -static char outputs[8]; /* "matrox:outputs:xxx" */ +static int grayscale; /* "matroxfb:grayscale" */ +static int dev = -1; /* "matroxfb:dev:xxxxx" */ +static unsigned int vesa = ~0; /* "matroxfb:vesa:xxxxx" */ +static int depth = -1; /* "matroxfb:depth:xxxxx" */ +static unsigned int xres; /* "matroxfb:xres:xxxxx" */ +static unsigned int yres; /* "matroxfb:yres:xxxxx" */ +static unsigned int upper = ~0; /* "matroxfb:upper:xxxxx" */ +static unsigned int lower = ~0; /* "matroxfb:lower:xxxxx" */ +static unsigned int vslen; /* "matroxfb:vslen:xxxxx" */ +static unsigned int left = ~0; /* "matroxfb:left:xxxxx" */ +static unsigned int right = ~0; /* "matroxfb:right:xxxxx" */ +static unsigned int hslen; /* "matroxfb:hslen:xxxxx" */ +static unsigned int pixclock; /* "matroxfb:pixclock:xxxxx" */ +static int sync = -1; /* "matroxfb:sync:xxxxx" */ +static unsigned int fv; /* "matroxfb:fv:xxxxx" */ +static unsigned int fh; /* "matroxfb:fh:xxxxxk" */ +static unsigned int maxclk; /* "matroxfb:maxclk:xxxxM" */ +static int dfp; /* "matroxfb:dfp */ +static int dfp_type = -1; /* "matroxfb:dfp:xxx */ +static int memtype = -1; /* "matroxfb:memtype:xxx" */ +static char outputs[8]; /* "matroxfb:outputs:xxx" */ #ifndef MODULE -static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ +static char videomode[64]; /* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */ #endif static int matroxfb_getmemory(struct matrox_fb_info *minfo, -- cgit v1.2.3 From 5fca6cac9feed75efc0b2c454305a5f538d887f5 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 11 Jan 2011 01:06:58 -0800 Subject: Input: wacom_w8001 - add single-touch support Emulate single-touch compatible events for the 2-finger panels so that they can be used with single-touch legacy clients. Assign device ids as Wacom USB vendor ID and product ID. Name the device to reflect its specific features. Scale touch coordinates to pen maximum if pen supported. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wacom_w8001.c | 182 ++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 8ed53aded2d3..5cb8449c909d 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -3,6 +3,7 @@ * * Copyright (c) 2008 Jaya Kumar * Copyright (c) 2010 Red Hat, Inc. + * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -64,11 +65,11 @@ struct w8001_coord { /* touch query reply packet */ struct w8001_touch_query { + u16 x; + u16 y; u8 panel_res; u8 capacity_res; u8 sensor_id; - u16 x; - u16 y; }; /* @@ -87,9 +88,14 @@ struct w8001 { char phys[32]; int type; unsigned int pktlen; + u16 max_touch_x; + u16 max_touch_y; + u16 max_pen_x; + u16 max_pen_y; + char name[64]; }; -static void parse_data(u8 *data, struct w8001_coord *coord) +static void parse_pen_data(u8 *data, struct w8001_coord *coord) { memset(coord, 0, sizeof(*coord)); @@ -113,11 +119,30 @@ static void parse_data(u8 *data, struct w8001_coord *coord) coord->tilt_y = data[8] & 0x7F; } -static void parse_touch(struct w8001 *w8001) +static void parse_single_touch(u8 *data, struct w8001_coord *coord) +{ + coord->x = (data[1] << 7) | data[2]; + coord->y = (data[3] << 7) | data[4]; + coord->tsw = data[0] & 0x01; +} + +static void scale_touch_coordinates(struct w8001 *w8001, + unsigned int *x, unsigned int *y) +{ + if (w8001->max_pen_x && w8001->max_touch_x) + *x = *x * w8001->max_pen_x / w8001->max_touch_x; + + if (w8001->max_pen_y && w8001->max_touch_y) + *y = *y * w8001->max_pen_y / w8001->max_touch_y; +} + +static void parse_multi_touch(struct w8001 *w8001) { struct input_dev *dev = w8001->dev; unsigned char *data = w8001->data; + unsigned int x, y; int i; + int count = 0; for (i = 0; i < 2; i++) { bool touch = data[0] & (1 << i); @@ -125,15 +150,29 @@ static void parse_touch(struct w8001 *w8001) input_mt_slot(dev, i); input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch); if (touch) { - int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]); - int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]); + x = (data[6 * i + 1] << 7) | data[6 * i + 2]; + y = (data[6 * i + 3] << 7) | data[6 * i + 4]; /* data[5,6] and [11,12] is finger capacity */ + /* scale to pen maximum */ + scale_touch_coordinates(w8001, &x, &y); + input_report_abs(dev, ABS_MT_POSITION_X, x); input_report_abs(dev, ABS_MT_POSITION_Y, y); + count++; } } + /* emulate single touch events when stylus is out of proximity. + * This is to make single touch backward support consistent + * across all Wacom single touch devices. + */ + if (w8001->type != BTN_TOOL_PEN && + w8001->type != BTN_TOOL_RUBBER) { + w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED; + input_mt_report_pointer_emulation(dev, true); + } + input_sync(dev); } @@ -152,6 +191,15 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query) query->y = data[5] << 9; query->y |= data[6] << 2; query->y |= (data[2] >> 3) & 0x3; + + /* Early days' single-finger touch models need the following defaults */ + if (!query->x && !query->y) { + query->x = 1024; + query->y = 1024; + if (query->panel_res) + query->x = query->y = (1 << query->panel_res); + query->panel_res = 10; + } } static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) @@ -161,16 +209,15 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) /* * We have 1 bit for proximity (rdy) and 3 bits for tip, side, * side2/eraser. If rdy && f2 are set, this can be either pen + side2, - * or eraser. assume + * or eraser. Assume: * - if dev is already in proximity and f2 is toggled → pen + side2 * - if dev comes into proximity with f2 set → eraser * If f2 disappears after assuming eraser, fake proximity out for * eraser and in for pen. */ - if (!w8001->type) { - w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - } else if (w8001->type == BTN_TOOL_RUBBER) { + switch (w8001->type) { + case BTN_TOOL_RUBBER: if (!coord->f2) { input_report_abs(dev, ABS_PRESSURE, 0); input_report_key(dev, BTN_TOUCH, 0); @@ -180,8 +227,21 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) input_sync(dev); w8001->type = BTN_TOOL_PEN; } - } else { + break; + + case BTN_TOOL_FINGER: + input_report_key(dev, BTN_TOUCH, 0); + input_report_key(dev, BTN_TOOL_FINGER, 0); + input_sync(dev); + /* fall through */ + + case KEY_RESERVED: + w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + break; + + default: input_report_key(dev, BTN_STYLUS2, coord->f2); + break; } input_report_abs(dev, ABS_X, coord->x); @@ -193,7 +253,26 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) input_sync(dev); if (!coord->rdy) - w8001->type = 0; + w8001->type = KEY_RESERVED; +} + +static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) +{ + struct input_dev *dev = w8001->dev; + unsigned int x = coord->x; + unsigned int y = coord->y; + + /* scale to pen maximum */ + scale_touch_coordinates(w8001, &x, &y); + + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_key(dev, BTN_TOUCH, coord->tsw); + input_report_key(dev, BTN_TOOL_FINGER, coord->tsw); + + input_sync(dev); + + w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED; } static irqreturn_t w8001_interrupt(struct serio *serio, @@ -214,9 +293,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio, case W8001_PKTLEN_TOUCH93 - 1: case W8001_PKTLEN_TOUCH9A - 1: - /* ignore one-finger touch packet. */ - if (w8001->pktlen == w8001->idx) + tmp = w8001->data[0] & W8001_TOUCH_BYTE; + if (tmp != W8001_TOUCH_BYTE) + break; + + if (w8001->pktlen == w8001->idx) { w8001->idx = 0; + if (w8001->type != BTN_TOOL_PEN && + w8001->type != BTN_TOOL_RUBBER) { + parse_single_touch(w8001->data, &coord); + report_single_touch(w8001, &coord); + } + } break; /* Pen coordinates packet */ @@ -225,18 +313,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio, if (unlikely(tmp == W8001_TAB_BYTE)) break; - tmp = (w8001->data[0] & W8001_TOUCH_BYTE); + tmp = w8001->data[0] & W8001_TOUCH_BYTE; if (tmp == W8001_TOUCH_BYTE) break; w8001->idx = 0; - parse_data(w8001->data, &coord); + parse_pen_data(w8001->data, &coord); report_pen_events(w8001, &coord); break; /* control packet */ case W8001_PKTLEN_TPCCTL - 1: - tmp = (w8001->data[0] & W8001_TOUCH_MASK); + tmp = w8001->data[0] & W8001_TOUCH_MASK; if (tmp == W8001_TOUCH_BYTE) break; @@ -249,7 +337,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio, /* 2 finger touch packet */ case W8001_PKTLEN_TOUCH2FG - 1: w8001->idx = 0; - parse_touch(w8001); + parse_multi_touch(w8001); break; } @@ -279,6 +367,7 @@ static int w8001_setup(struct w8001 *w8001) { struct input_dev *dev = w8001->dev; struct w8001_coord coord; + struct w8001_touch_query touch; int error; error = w8001_command(w8001, W8001_CMD_STOP, false); @@ -287,14 +376,21 @@ static int w8001_setup(struct w8001 *w8001) msleep(250); /* wait 250ms before querying the device */ + dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name)); + /* penabled? */ error = w8001_command(w8001, W8001_CMD_QUERY, true); if (!error) { + __set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOOL_PEN, dev->keybit); __set_bit(BTN_TOOL_RUBBER, dev->keybit); __set_bit(BTN_STYLUS, dev->keybit); __set_bit(BTN_STYLUS2, dev->keybit); - parse_data(w8001->response, &coord); + + parse_pen_data(w8001->response, &coord); + w8001->max_pen_x = coord.x; + w8001->max_pen_y = coord.y; input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); @@ -303,6 +399,8 @@ static int w8001_setup(struct w8001 *w8001) input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); } + w8001->id = 0x90; + strlcat(w8001->name, " Penabled", sizeof(w8001->name)); } /* Touch enabled? */ @@ -313,24 +411,38 @@ static int w8001_setup(struct w8001 *w8001) * second byte is empty, which indicates touch is not supported. */ if (!error && w8001->response[1]) { - struct w8001_touch_query touch; + __set_bit(BTN_TOUCH, dev->keybit); + __set_bit(BTN_TOOL_FINGER, dev->keybit); parse_touchquery(w8001->response, &touch); + w8001->max_touch_x = touch.x; + w8001->max_touch_y = touch.y; + + /* scale to pen maximum */ + if (w8001->max_pen_x && w8001->max_pen_y) { + touch.x = w8001->max_pen_x; + touch.y = w8001->max_pen_y; + } input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0); - __set_bit(BTN_TOOL_FINGER, dev->keybit); switch (touch.sensor_id) { case 0: case 2: w8001->pktlen = W8001_PKTLEN_TOUCH93; + w8001->id = 0x93; + strlcat(w8001->name, " 1FG", sizeof(w8001->name)); break; + case 1: case 3: case 4: w8001->pktlen = W8001_PKTLEN_TOUCH9A; + strlcat(w8001->name, " 1FG", sizeof(w8001->name)); + w8001->id = 0x9a; break; + case 5: w8001->pktlen = W8001_PKTLEN_TOUCH2FG; @@ -341,10 +453,18 @@ static int w8001_setup(struct w8001 *w8001) 0, touch.y, 0, 0); input_set_abs_params(dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); + + strlcat(w8001->name, " 2FG", sizeof(w8001->name)); + if (w8001->max_pen_x && w8001->max_pen_y) + w8001->id = 0xE3; + else + w8001->id = 0xE2; break; } } + strlcat(w8001->name, " Touchscreen", sizeof(w8001->name)); + return w8001_command(w8001, W8001_CMD_START, false); } @@ -384,22 +504,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) } w8001->serio = serio; - w8001->id = serio->id.id; w8001->dev = input_dev; init_completion(&w8001->cmd_done); snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); - input_dev->name = "Wacom W8001 Penabled Serial TouchScreen"; - input_dev->phys = w8001->phys; - input_dev->id.bustype = BUS_RS232; - input_dev->id.vendor = SERIO_W8001; - input_dev->id.product = w8001->id; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(BTN_TOUCH, input_dev->keybit); - serio_set_drvdata(serio, w8001); err = serio_open(serio, drv); if (err) @@ -409,6 +517,14 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) if (err) goto fail3; + input_dev->name = w8001->name; + input_dev->phys = w8001->phys; + input_dev->id.product = w8001->id; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = 0x056a; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &serio->dev; + err = input_register_device(w8001->dev); if (err) goto fail3; -- cgit v1.2.3 From c0fdcfa8e9a994176ff1070dced50eeff5f6f851 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Mon, 10 Jan 2011 20:49:27 +0100 Subject: ARM: 6616/1: Fix ep93xx-fb init/exit annotations Fix section mismatch errors in the ep93xx-fb driver resulting from incorrect init/exit annotations. Reported-by: H Hartley Sweeten Signed-off-by: Ryan Mallon Tested-by: H Hartley Sweeten Signed-off-by: Russell King --- drivers/video/ep93xx-fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index 0c99de0562ca..b358d045f130 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -483,7 +483,7 @@ static void ep93xxfb_dealloc_videomem(struct fb_info *info) info->screen_base, info->fix.smem_start); } -static int __init ep93xxfb_probe(struct platform_device *pdev) +static int __devinit ep93xxfb_probe(struct platform_device *pdev) { struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data; struct fb_info *info; @@ -598,7 +598,7 @@ failed: return err; } -static int ep93xxfb_remove(struct platform_device *pdev) +static int __devexit ep93xxfb_remove(struct platform_device *pdev) { struct fb_info *info = platform_get_drvdata(pdev); struct ep93xx_fbi *fbi = info->par; @@ -622,7 +622,7 @@ static int ep93xxfb_remove(struct platform_device *pdev) static struct platform_driver ep93xxfb_driver = { .probe = ep93xxfb_probe, - .remove = ep93xxfb_remove, + .remove = __devexit_p(ep93xxfb_remove), .driver = { .name = "ep93xx-fb", .owner = THIS_MODULE, -- cgit v1.2.3 From 50c01fc355c6a97c511d58411f9bc0e4b8fc4659 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 11 Jan 2011 12:43:52 +0000 Subject: spi/dw_spi: don't treat NULL clk as an error clk_get() returns a struct clk cookie to the driver and some platforms may return NULL if they only support a single clock. clk_get() has only failed if it returns a ERR_PTR() encoded pointer. Signed-off-by: Jamie Iles Signed-off-by: Grant Likely --- drivers/spi/dw_spi_mmio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c index db35bd9c1b24..2fa012c109bc 100644 --- a/drivers/spi/dw_spi_mmio.c +++ b/drivers/spi/dw_spi_mmio.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -68,8 +69,8 @@ static int __devinit dw_spi_mmio_probe(struct platform_device *pdev) } dwsmmio->clk = clk_get(&pdev->dev, NULL); - if (!dwsmmio->clk) { - ret = -ENODEV; + if (IS_ERR(dwsmmio->clk)) { + ret = PTR_ERR(dwsmmio->clk); goto err_irq; } clk_enable(dwsmmio->clk); -- cgit v1.2.3 From ab31523c2fcac557226bac72cbdf5fafe01f9a26 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 14 Dec 2010 18:40:46 +0000 Subject: xen/gntdev: allow usermode to map granted pages The gntdev driver allows usermode to map granted pages from other domains. This is typically used to implement a Xen backend driver in user mode. Signed-off-by: Gerd Hoffmann Signed-off-by: Stefano Stabellini Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 7 + drivers/xen/Makefile | 2 + drivers/xen/gntdev.c | 635 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/xen/gntdev.h | 119 ++++++++++ 4 files changed, 763 insertions(+) create mode 100644 drivers/xen/gntdev.c create mode 100644 include/xen/gntdev.h (limited to 'drivers') diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 6e6180ccd726..bd3095f0dff2 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -62,6 +62,13 @@ config XEN_SYS_HYPERVISOR virtual environment, /sys/hypervisor will still be present, but will have no xen contents. +config XEN_GNTDEV + tristate "userspace grant access device driver" + depends on XEN + select MMU_NOTIFIER + help + Allows userspace processes to use grants. + config XEN_PLATFORM_PCI tristate "xen platform pci device driver" depends on XEN_PVHVM diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 533a199e7a3f..674fdb5fee49 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o +obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o obj-$(CONFIG_XENFS) += xenfs/ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o @@ -16,4 +17,5 @@ obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_DOM0) += pci.o xen-evtchn-y := evtchn.o +xen-gntdev-y := gntdev.o diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c new file mode 100644 index 000000000000..cfe063372aa4 --- /dev/null +++ b/drivers/xen/gntdev.c @@ -0,0 +1,635 @@ +/****************************************************************************** + * gntdev.c + * + * Device for accessing (in user-space) pages that have been granted by other + * domains. + * + * Copyright (c) 2006-2007, D G Murray. + * (c) 2009 Gerd Hoffmann + * + * 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 + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Derek G. Murray , " + "Gerd Hoffmann "); +MODULE_DESCRIPTION("User-space granted page access driver"); + +static int limit = 1024; +module_param(limit, int, 0644); +MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped at " + "once by a gntdev instance"); + +struct gntdev_priv { + struct list_head maps; + uint32_t used; + uint32_t limit; + /* lock protects maps from concurrent changes */ + spinlock_t lock; + struct mm_struct *mm; + struct mmu_notifier mn; +}; + +struct grant_map { + struct list_head next; + struct gntdev_priv *priv; + struct vm_area_struct *vma; + int index; + int count; + int flags; + int is_mapped; + struct ioctl_gntdev_grant_ref *grants; + struct gnttab_map_grant_ref *map_ops; + struct gnttab_unmap_grant_ref *unmap_ops; +}; + +/* ------------------------------------------------------------------ */ + +static void gntdev_print_maps(struct gntdev_priv *priv, + char *text, int text_index) +{ +#ifdef DEBUG + struct grant_map *map; + + pr_debug("maps list (priv %p, usage %d/%d)\n", + priv, priv->used, priv->limit); + + list_for_each_entry(map, &priv->maps, next) + pr_debug(" index %2d, count %2d %s\n", + map->index, map->count, + map->index == text_index && text ? text : ""); +#endif +} + +static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) +{ + struct grant_map *add; + + add = kzalloc(sizeof(struct grant_map), GFP_KERNEL); + if (NULL == add) + return NULL; + + add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); + add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); + add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); + if (NULL == add->grants || + NULL == add->map_ops || + NULL == add->unmap_ops) + goto err; + + add->index = 0; + add->count = count; + add->priv = priv; + + if (add->count + priv->used > priv->limit) + goto err; + + return add; + +err: + kfree(add->grants); + kfree(add->map_ops); + kfree(add->unmap_ops); + kfree(add); + return NULL; +} + +static void gntdev_add_map(struct gntdev_priv *priv, struct grant_map *add) +{ + struct grant_map *map; + + list_for_each_entry(map, &priv->maps, next) { + if (add->index + add->count < map->index) { + list_add_tail(&add->next, &map->next); + goto done; + } + add->index = map->index + map->count; + } + list_add_tail(&add->next, &priv->maps); + +done: + priv->used += add->count; + gntdev_print_maps(priv, "[new]", add->index); +} + +static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv, + int index, int count) +{ + struct grant_map *map; + + list_for_each_entry(map, &priv->maps, next) { + if (map->index != index) + continue; + if (map->count != count) + continue; + return map; + } + return NULL; +} + +static struct grant_map *gntdev_find_map_vaddr(struct gntdev_priv *priv, + unsigned long vaddr) +{ + struct grant_map *map; + + list_for_each_entry(map, &priv->maps, next) { + if (!map->vma) + continue; + if (vaddr < map->vma->vm_start) + continue; + if (vaddr >= map->vma->vm_end) + continue; + return map; + } + return NULL; +} + +static int gntdev_del_map(struct grant_map *map) +{ + int i; + + if (map->vma) + return -EBUSY; + for (i = 0; i < map->count; i++) + if (map->unmap_ops[i].handle) + return -EBUSY; + + map->priv->used -= map->count; + list_del(&map->next); + return 0; +} + +static void gntdev_free_map(struct grant_map *map) +{ + if (!map) + return; + kfree(map->grants); + kfree(map->map_ops); + kfree(map->unmap_ops); + kfree(map); +} + +/* ------------------------------------------------------------------ */ + +static int find_grant_ptes(pte_t *pte, pgtable_t token, + unsigned long addr, void *data) +{ + struct grant_map *map = data; + unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT; + u64 pte_maddr; + + BUG_ON(pgnr >= map->count); + pte_maddr = (u64)pfn_to_mfn(page_to_pfn(token)) << PAGE_SHIFT; + pte_maddr += (unsigned long)pte & ~PAGE_MASK; + gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, map->flags, + map->grants[pgnr].ref, + map->grants[pgnr].domid); + gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, map->flags, + 0 /* handle */); + return 0; +} + +static int map_grant_pages(struct grant_map *map) +{ + int i, err = 0; + + pr_debug("map %d+%d\n", map->index, map->count); + err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, + map->map_ops, map->count); + if (err) + return err; + + for (i = 0; i < map->count; i++) { + if (map->map_ops[i].status) + err = -EINVAL; + map->unmap_ops[i].handle = map->map_ops[i].handle; + } + return err; +} + +static int unmap_grant_pages(struct grant_map *map, int offset, int pages) +{ + int i, err = 0; + + pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages); + err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + map->unmap_ops + offset, pages); + if (err) + return err; + + for (i = 0; i < pages; i++) { + if (map->unmap_ops[offset+i].status) + err = -EINVAL; + map->unmap_ops[offset+i].handle = 0; + } + return err; +} + +/* ------------------------------------------------------------------ */ + +static void gntdev_vma_close(struct vm_area_struct *vma) +{ + struct grant_map *map = vma->vm_private_data; + + pr_debug("close %p\n", vma); + map->is_mapped = 0; + map->vma = NULL; + vma->vm_private_data = NULL; +} + +static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + pr_debug("vaddr %p, pgoff %ld (shouldn't happen)\n", + vmf->virtual_address, vmf->pgoff); + vmf->flags = VM_FAULT_ERROR; + return 0; +} + +static struct vm_operations_struct gntdev_vmops = { + .close = gntdev_vma_close, + .fault = gntdev_vma_fault, +}; + +/* ------------------------------------------------------------------ */ + +static void mn_invl_range_start(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); + struct grant_map *map; + unsigned long mstart, mend; + int err; + + spin_lock(&priv->lock); + list_for_each_entry(map, &priv->maps, next) { + if (!map->vma) + continue; + if (!map->is_mapped) + continue; + if (map->vma->vm_start >= end) + continue; + if (map->vma->vm_end <= start) + continue; + mstart = max(start, map->vma->vm_start); + mend = min(end, map->vma->vm_end); + pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n", + map->index, map->count, + map->vma->vm_start, map->vma->vm_end, + start, end, mstart, mend); + err = unmap_grant_pages(map, + (mstart - map->vma->vm_start) >> PAGE_SHIFT, + (mend - mstart) >> PAGE_SHIFT); + WARN_ON(err); + } + spin_unlock(&priv->lock); +} + +static void mn_invl_page(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long address) +{ + mn_invl_range_start(mn, mm, address, address + PAGE_SIZE); +} + +static void mn_release(struct mmu_notifier *mn, + struct mm_struct *mm) +{ + struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); + struct grant_map *map; + int err; + + spin_lock(&priv->lock); + list_for_each_entry(map, &priv->maps, next) { + if (!map->vma) + continue; + pr_debug("map %d+%d (%lx %lx)\n", + map->index, map->count, + map->vma->vm_start, map->vma->vm_end); + err = unmap_grant_pages(map, /* offset */ 0, map->count); + WARN_ON(err); + } + spin_unlock(&priv->lock); +} + +struct mmu_notifier_ops gntdev_mmu_ops = { + .release = mn_release, + .invalidate_page = mn_invl_page, + .invalidate_range_start = mn_invl_range_start, +}; + +/* ------------------------------------------------------------------ */ + +static int gntdev_open(struct inode *inode, struct file *flip) +{ + struct gntdev_priv *priv; + int ret = 0; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + INIT_LIST_HEAD(&priv->maps); + spin_lock_init(&priv->lock); + priv->limit = limit; + + priv->mm = get_task_mm(current); + if (!priv->mm) { + kfree(priv); + return -ENOMEM; + } + priv->mn.ops = &gntdev_mmu_ops; + ret = mmu_notifier_register(&priv->mn, priv->mm); + mmput(priv->mm); + + if (ret) { + kfree(priv); + return ret; + } + + flip->private_data = priv; + pr_debug("priv %p\n", priv); + + return 0; +} + +static int gntdev_release(struct inode *inode, struct file *flip) +{ + struct gntdev_priv *priv = flip->private_data; + struct grant_map *map; + int err; + + pr_debug("priv %p\n", priv); + + spin_lock(&priv->lock); + while (!list_empty(&priv->maps)) { + map = list_entry(priv->maps.next, struct grant_map, next); + err = gntdev_del_map(map); + if (WARN_ON(err)) + gntdev_free_map(map); + + } + spin_unlock(&priv->lock); + + mmu_notifier_unregister(&priv->mn, priv->mm); + kfree(priv); + return 0; +} + +static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, + struct ioctl_gntdev_map_grant_ref __user *u) +{ + struct ioctl_gntdev_map_grant_ref op; + struct grant_map *map; + int err; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + pr_debug("priv %p, add %d\n", priv, op.count); + if (unlikely(op.count <= 0)) + return -EINVAL; + if (unlikely(op.count > priv->limit)) + return -EINVAL; + + err = -ENOMEM; + map = gntdev_alloc_map(priv, op.count); + if (!map) + return err; + if (copy_from_user(map->grants, &u->refs, + sizeof(map->grants[0]) * op.count) != 0) { + gntdev_free_map(map); + return err; + } + + spin_lock(&priv->lock); + gntdev_add_map(priv, map); + op.index = map->index << PAGE_SHIFT; + spin_unlock(&priv->lock); + + if (copy_to_user(u, &op, sizeof(op)) != 0) { + spin_lock(&priv->lock); + gntdev_del_map(map); + spin_unlock(&priv->lock); + gntdev_free_map(map); + return err; + } + return 0; +} + +static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv, + struct ioctl_gntdev_unmap_grant_ref __user *u) +{ + struct ioctl_gntdev_unmap_grant_ref op; + struct grant_map *map; + int err = -ENOENT; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + pr_debug("priv %p, del %d+%d\n", priv, (int)op.index, (int)op.count); + + spin_lock(&priv->lock); + map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); + if (map) + err = gntdev_del_map(map); + spin_unlock(&priv->lock); + if (!err) + gntdev_free_map(map); + return err; +} + +static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv, + struct ioctl_gntdev_get_offset_for_vaddr __user *u) +{ + struct ioctl_gntdev_get_offset_for_vaddr op; + struct grant_map *map; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr); + + spin_lock(&priv->lock); + map = gntdev_find_map_vaddr(priv, op.vaddr); + if (map == NULL || + map->vma->vm_start != op.vaddr) { + spin_unlock(&priv->lock); + return -EINVAL; + } + op.offset = map->index << PAGE_SHIFT; + op.count = map->count; + spin_unlock(&priv->lock); + + if (copy_to_user(u, &op, sizeof(op)) != 0) + return -EFAULT; + return 0; +} + +static long gntdev_ioctl_set_max_grants(struct gntdev_priv *priv, + struct ioctl_gntdev_set_max_grants __user *u) +{ + struct ioctl_gntdev_set_max_grants op; + + if (copy_from_user(&op, u, sizeof(op)) != 0) + return -EFAULT; + pr_debug("priv %p, limit %d\n", priv, op.count); + if (op.count > limit) + return -E2BIG; + + spin_lock(&priv->lock); + priv->limit = op.count; + spin_unlock(&priv->lock); + return 0; +} + +static long gntdev_ioctl(struct file *flip, + unsigned int cmd, unsigned long arg) +{ + struct gntdev_priv *priv = flip->private_data; + void __user *ptr = (void __user *)arg; + + switch (cmd) { + case IOCTL_GNTDEV_MAP_GRANT_REF: + return gntdev_ioctl_map_grant_ref(priv, ptr); + + case IOCTL_GNTDEV_UNMAP_GRANT_REF: + return gntdev_ioctl_unmap_grant_ref(priv, ptr); + + case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR: + return gntdev_ioctl_get_offset_for_vaddr(priv, ptr); + + case IOCTL_GNTDEV_SET_MAX_GRANTS: + return gntdev_ioctl_set_max_grants(priv, ptr); + + default: + pr_debug("priv %p, unknown cmd %x\n", priv, cmd); + return -ENOIOCTLCMD; + } + + return 0; +} + +static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) +{ + struct gntdev_priv *priv = flip->private_data; + int index = vma->vm_pgoff; + int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + struct grant_map *map; + int err = -EINVAL; + + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + pr_debug("map %d+%d at %lx (pgoff %lx)\n", + index, count, vma->vm_start, vma->vm_pgoff); + + spin_lock(&priv->lock); + map = gntdev_find_map_index(priv, index, count); + if (!map) + goto unlock_out; + if (map->vma) + goto unlock_out; + if (priv->mm != vma->vm_mm) { + printk(KERN_WARNING "Huh? Other mm?\n"); + goto unlock_out; + } + + vma->vm_ops = &gntdev_vmops; + + vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND; + + vma->vm_private_data = map; + map->vma = vma; + + map->flags = GNTMAP_host_map | GNTMAP_application_map | GNTMAP_contains_pte; + if (!(vma->vm_flags & VM_WRITE)) + map->flags |= GNTMAP_readonly; + + err = apply_to_page_range(vma->vm_mm, vma->vm_start, + vma->vm_end - vma->vm_start, + find_grant_ptes, map); + if (err) { + printk(KERN_WARNING "find_grant_ptes() failure.\n"); + goto unlock_out; + } + + err = map_grant_pages(map); + if (err) { + printk(KERN_WARNING "map_grant_pages() failure.\n"); + goto unlock_out; + } + map->is_mapped = 1; + +unlock_out: + spin_unlock(&priv->lock); + return err; +} + +static const struct file_operations gntdev_fops = { + .owner = THIS_MODULE, + .open = gntdev_open, + .release = gntdev_release, + .mmap = gntdev_mmap, + .unlocked_ioctl = gntdev_ioctl +}; + +static struct miscdevice gntdev_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "xen/gntdev", + .fops = &gntdev_fops, +}; + +/* ------------------------------------------------------------------ */ + +static int __init gntdev_init(void) +{ + int err; + + if (!xen_domain()) + return -ENODEV; + + err = misc_register(&gntdev_miscdev); + if (err != 0) { + printk(KERN_ERR "Could not register gntdev device\n"); + return err; + } + return 0; +} + +static void __exit gntdev_exit(void) +{ + misc_deregister(&gntdev_miscdev); +} + +module_init(gntdev_init); +module_exit(gntdev_exit); + +/* ------------------------------------------------------------------ */ diff --git a/include/xen/gntdev.h b/include/xen/gntdev.h new file mode 100644 index 000000000000..eb23f4188f5a --- /dev/null +++ b/include/xen/gntdev.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * gntdev.h + * + * Interface to /dev/xen/gntdev. + * + * Copyright (c) 2007, D G Murray + * + * 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; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __LINUX_PUBLIC_GNTDEV_H__ +#define __LINUX_PUBLIC_GNTDEV_H__ + +struct ioctl_gntdev_grant_ref { + /* The domain ID of the grant to be mapped. */ + uint32_t domid; + /* The grant reference of the grant to be mapped. */ + uint32_t ref; +}; + +/* + * Inserts the grant references into the mapping table of an instance + * of gntdev. N.B. This does not perform the mapping, which is deferred + * until mmap() is called with @index as the offset. + */ +#define IOCTL_GNTDEV_MAP_GRANT_REF \ +_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref)) +struct ioctl_gntdev_map_grant_ref { + /* IN parameters */ + /* The number of grants to be mapped. */ + uint32_t count; + uint32_t pad; + /* OUT parameters */ + /* The offset to be used on a subsequent call to mmap(). */ + uint64_t index; + /* Variable IN parameter. */ + /* Array of grant references, of size @count. */ + struct ioctl_gntdev_grant_ref refs[1]; +}; + +/* + * Removes the grant references from the mapping table of an instance of + * of gntdev. N.B. munmap() must be called on the relevant virtual address(es) + * before this ioctl is called, or an error will result. + */ +#define IOCTL_GNTDEV_UNMAP_GRANT_REF \ +_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref)) +struct ioctl_gntdev_unmap_grant_ref { + /* IN parameters */ + /* The offset was returned by the corresponding map operation. */ + uint64_t index; + /* The number of pages to be unmapped. */ + uint32_t count; + uint32_t pad; +}; + +/* + * Returns the offset in the driver's address space that corresponds + * to @vaddr. This can be used to perform a munmap(), followed by an + * UNMAP_GRANT_REF ioctl, where no state about the offset is retained by + * the caller. The number of pages that were allocated at the same time as + * @vaddr is returned in @count. + * + * N.B. Where more than one page has been mapped into a contiguous range, the + * supplied @vaddr must correspond to the start of the range; otherwise + * an error will result. It is only possible to munmap() the entire + * contiguously-allocated range at once, and not any subrange thereof. + */ +#define IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR \ +_IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr)) +struct ioctl_gntdev_get_offset_for_vaddr { + /* IN parameters */ + /* The virtual address of the first mapped page in a range. */ + uint64_t vaddr; + /* OUT parameters */ + /* The offset that was used in the initial mmap() operation. */ + uint64_t offset; + /* The number of pages mapped in the VM area that begins at @vaddr. */ + uint32_t count; + uint32_t pad; +}; + +/* + * Sets the maximum number of grants that may mapped at once by this gntdev + * instance. + * + * N.B. This must be called before any other ioctl is performed on the device. + */ +#define IOCTL_GNTDEV_SET_MAX_GRANTS \ +_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants)) +struct ioctl_gntdev_set_max_grants { + /* IN parameter */ + /* The maximum number of grants that may be mapped at once. */ + uint32_t count; +}; + +#endif /* __LINUX_PUBLIC_GNTDEV_H__ */ -- cgit v1.2.3 From 8d3eaea24609c7cd6fb0e6471f46a52f9e5d0202 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 11 Nov 2010 14:39:12 -0800 Subject: xen/gntdev: add VM_PFNMAP to vma These pages are from other domains, so don't have any local PFN. VM_PFNMAP is the closest concept Linux has to this. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index cfe063372aa4..fa6355a97081 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -564,7 +564,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) vma->vm_ops = &gntdev_vmops; - vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND; + vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP; vma->vm_private_data = map; map->vma = vma; -- cgit v1.2.3 From 9329e7604fe915fd0201633d3c38adae307d56a5 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 8 Dec 2010 11:57:40 +0000 Subject: xen: gntdev: move use of GNTMAP_contains_pte next to the map_op This flag controls the meaning of gnttab_map_grant_ref.host_addr and specifies that the field contains a reference to the pte entry to be used to perform the mapping. Therefore move the use of this flag to the point at which we actually use a reference to the pte instead of something else, splitting up the usage of the flag in this way is confusing and potentially error prone. The other flags are all properties of the mapping itself as opposed to properties of the hypercall arguments and therefore it make sense to continue to pass them round in map->flags. Signed-off-by: Ian Campbell Cc: Stefano Stabellini Cc: Derek G. Murray Cc: Gerd Hoffmann Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index fa6355a97081..888d76307d59 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -211,10 +211,12 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token, BUG_ON(pgnr >= map->count); pte_maddr = (u64)pfn_to_mfn(page_to_pfn(token)) << PAGE_SHIFT; pte_maddr += (unsigned long)pte & ~PAGE_MASK; - gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, map->flags, + gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, + GNTMAP_contains_pte | map->flags, map->grants[pgnr].ref, map->grants[pgnr].domid); - gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, map->flags, + gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, + GNTMAP_contains_pte | map->flags, 0 /* handle */); return 0; } @@ -569,7 +571,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) vma->vm_private_data = map; map->vma = vma; - map->flags = GNTMAP_host_map | GNTMAP_application_map | GNTMAP_contains_pte; + map->flags = GNTMAP_host_map | GNTMAP_application_map; if (!(vma->vm_flags & VM_WRITE)) map->flags |= GNTMAP_readonly; -- cgit v1.2.3 From ba5d1012292403c8037adf4a54c4ec50dfe846c4 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 8 Dec 2010 10:54:32 -0800 Subject: xen/gntdev: stop using "token" argument It's the struct page of the L1 pte page. But we can get its mfn by simply doing an arbitrary_virt_to_machine() on it anyway (which is the safe conservative choice; since we no longer allow HIGHPTE pages, we would never expect to be operating on a mapped pte page). Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 888d76307d59..a2ea5335e152 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -209,8 +209,8 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token, u64 pte_maddr; BUG_ON(pgnr >= map->count); - pte_maddr = (u64)pfn_to_mfn(page_to_pfn(token)) << PAGE_SHIFT; - pte_maddr += (unsigned long)pte & ~PAGE_MASK; + pte_maddr = arbitrary_virt_to_machine(pte).maddr; + gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, GNTMAP_contains_pte | map->flags, map->grants[pgnr].ref, -- cgit v1.2.3 From f0a70c882ea546bbd802643990ceded32c39facc Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Fri, 7 Jan 2011 11:51:47 +0000 Subject: xen/gntdev: Fix circular locking dependency apply_to_page_range will acquire PTE lock while priv->lock is held, and mn_invl_range_start tries to acquire priv->lock with PTE already held. Fix by not holding priv->lock during the entire map operation. This is safe because map->vma is set nonzero while the lock is held, which will cause subsequent maps to fail and will cause the unmap ioctl (and other users of gntdev_del_map) to return -EBUSY until the area is unmapped. It is similarly impossible for gntdev_vma_close to be called while the vma is still being created. Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index a2ea5335e152..aba76d437ea8 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -575,21 +575,26 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) if (!(vma->vm_flags & VM_WRITE)) map->flags |= GNTMAP_readonly; + spin_unlock(&priv->lock); + err = apply_to_page_range(vma->vm_mm, vma->vm_start, vma->vm_end - vma->vm_start, find_grant_ptes, map); if (err) { printk(KERN_WARNING "find_grant_ptes() failure.\n"); - goto unlock_out; + return err; } err = map_grant_pages(map); if (err) { printk(KERN_WARNING "map_grant_pages() failure.\n"); - goto unlock_out; + return err; } + map->is_mapped = 1; + return 0; + unlock_out: spin_unlock(&priv->lock); return err; -- cgit v1.2.3 From 289b777eac19c811b474593b4d2fd14e46340c23 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 10 Dec 2010 14:54:44 +0000 Subject: xen: introduce gnttab_map_refs and gnttab_unmap_refs gnttab_map_refs maps some grant refs and uses the new m2p override to set a proper m2p mapping for the granted pages. gnttab_unmap_refs unmaps the granted refs and removes th mappings from the m2p override. Signed-off-by: Stefano Stabellini Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/grant-table.c | 36 ++++++++++++++++++++++++++++++++++++ include/xen/grant_table.h | 5 +++++ 2 files changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 6c4531816496..1afd5690858c 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -447,6 +447,42 @@ unsigned int gnttab_max_grant_frames(void) } EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); +int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, + struct page **pages, unsigned int count) +{ + int i, ret; + pte_t *pte; + unsigned long mfn; + + ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count); + + for (i = 0; i < count; i++) { + /* m2p override only supported for GNTMAP_contains_pte mappings */ + if (!(map_ops[i].flags & GNTMAP_contains_pte)) + continue; + pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + + (map_ops[i].host_addr & ~PAGE_MASK)); + mfn = pte_mfn(*pte); + m2p_add_override(mfn, pages[i]); + } + + return ret; +} +EXPORT_SYMBOL_GPL(gnttab_map_refs); + +int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, + struct page **pages, unsigned int count) +{ + int i, ret; + + ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count); + for (i = 0; i < count; i++) + m2p_remove_override(pages[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(gnttab_unmap_refs); + static int gnttab_map(unsigned int start_idx, unsigned int end_idx) { struct gnttab_setup_table setup; diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 1821aa103d82..b1fab6b5b3ef 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -155,4 +155,9 @@ unsigned int gnttab_max_grant_frames(void); #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) +int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, + struct page **pages, unsigned int count); +int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, + struct page **pages, unsigned int count); + #endif /* __ASM_GNTTAB_H__ */ -- cgit v1.2.3 From a12b4eb34bb1ea16046c5b61e7a887e252cc1cce Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 10 Dec 2010 14:56:42 +0000 Subject: xen gntdev: use gnttab_map_refs and gnttab_unmap_refs Use gnttab_map_refs and gnttab_unmap_refs to map and unmap the grant ref, so that we can have a corresponding struct page. Signed-off-by: Stefano Stabellini Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index aba76d437ea8..1e31cdcdae1e 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -71,6 +71,7 @@ struct grant_map { struct ioctl_gntdev_grant_ref *grants; struct gnttab_map_grant_ref *map_ops; struct gnttab_unmap_grant_ref *unmap_ops; + struct page **pages; }; /* ------------------------------------------------------------------ */ @@ -94,6 +95,7 @@ static void gntdev_print_maps(struct gntdev_priv *priv, static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) { struct grant_map *add; + int i; add = kzalloc(sizeof(struct grant_map), GFP_KERNEL); if (NULL == add) @@ -102,11 +104,19 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); - if (NULL == add->grants || - NULL == add->map_ops || - NULL == add->unmap_ops) + add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); + if (NULL == add->grants || + NULL == add->map_ops || + NULL == add->unmap_ops || + NULL == add->pages) goto err; + for (i = 0; i < count; i++) { + add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); + if (add->pages[i] == NULL) + goto err; + } + add->index = 0; add->count = count; add->priv = priv; @@ -117,6 +127,12 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) return add; err: + if (add->pages) + for (i = 0; i < count; i++) { + if (add->pages[i]) + __free_page(add->pages[i]); + } + kfree(add->pages); kfree(add->grants); kfree(add->map_ops); kfree(add->unmap_ops); @@ -191,8 +207,17 @@ static int gntdev_del_map(struct grant_map *map) static void gntdev_free_map(struct grant_map *map) { + int i; + if (!map) return; + + if (map->pages) + for (i = 0; i < map->count; i++) { + if (map->pages[i]) + __free_page(map->pages[i]); + } + kfree(map->pages); kfree(map->grants); kfree(map->map_ops); kfree(map->unmap_ops); @@ -226,8 +251,7 @@ static int map_grant_pages(struct grant_map *map) int i, err = 0; pr_debug("map %d+%d\n", map->index, map->count); - err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, - map->map_ops, map->count); + err = gnttab_map_refs(map->map_ops, map->pages, map->count); if (err) return err; @@ -244,8 +268,7 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages) int i, err = 0; pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages); - err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, - map->unmap_ops + offset, pages); + err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages); if (err) return err; -- cgit v1.2.3 From 87f1d40a706bdebdc8f959b9ac291d0d8fdfcc7e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 13 Dec 2010 14:42:30 +0000 Subject: xen p2m: clear the old pte when adding a page to m2p_override When adding a page to m2p_override we change the p2m of the page so we need to also clear the old pte of the kernel linear mapping because it doesn't correspond anymore. When we remove the page from m2p_override we restore the original p2m of the page and we also restore the old pte of the kernel linear mapping. Before changing the p2m mappings in m2p_add_override and m2p_remove_override, check that the page passed as argument is valid and return an error if it is not. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/xen/page.h | 4 ++-- arch/x86/xen/p2m.c | 49 +++++++++++++++++++++++++++++++++++++---- drivers/xen/grant-table.c | 16 +++++++++++--- 3 files changed, 60 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 50f0a0f6bd6a..f25bdf238a33 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -42,8 +42,8 @@ extern unsigned int machine_to_phys_order; extern unsigned long get_phys_to_machine(unsigned long pfn); extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); -extern void m2p_add_override(unsigned long mfn, struct page *page); -extern void m2p_remove_override(struct page *page); +extern int m2p_add_override(unsigned long mfn, struct page *page); +extern int m2p_remove_override(struct page *page); extern struct page *m2p_find_override(unsigned long mfn); extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index b3b19d43b951..40d51225ff08 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -404,34 +405,74 @@ static unsigned long mfn_hash(unsigned long mfn) } /* Add an MFN override for a particular page */ -void m2p_add_override(unsigned long mfn, struct page *page) +int m2p_add_override(unsigned long mfn, struct page *page) { unsigned long flags; - unsigned long pfn = page_to_pfn(page); + unsigned long pfn; + unsigned long address; + unsigned level; + pte_t *ptep = NULL; + + pfn = page_to_pfn(page); + if (!PageHighMem(page)) { + address = (unsigned long)__va(pfn << PAGE_SHIFT); + ptep = lookup_address(address, &level); + + if (WARN(ptep == NULL || level != PG_LEVEL_4K, + "m2p_add_override: pfn %lx not mapped", pfn)) + return -EINVAL; + } + page->private = mfn; page->index = pfn_to_mfn(pfn); __set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); + if (!PageHighMem(page)) + /* Just zap old mapping for now */ + pte_clear(&init_mm, address, ptep); + spin_lock_irqsave(&m2p_override_lock, flags); list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); spin_unlock_irqrestore(&m2p_override_lock, flags); + + return 0; } -void m2p_remove_override(struct page *page) +int m2p_remove_override(struct page *page) { unsigned long flags; unsigned long mfn; unsigned long pfn; + unsigned long address; + unsigned level; + pte_t *ptep = NULL; pfn = page_to_pfn(page); mfn = get_phys_to_machine(pfn); if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) - return; + return -EINVAL; + + if (!PageHighMem(page)) { + address = (unsigned long)__va(pfn << PAGE_SHIFT); + ptep = lookup_address(address, &level); + + if (WARN(ptep == NULL || level != PG_LEVEL_4K, + "m2p_remove_override: pfn %lx not mapped", pfn)) + return -EINVAL; + } spin_lock_irqsave(&m2p_override_lock, flags); list_del(&page->lru); spin_unlock_irqrestore(&m2p_override_lock, flags); __set_phys_to_machine(pfn, page->index); + + if (!PageHighMem(page)) + set_pte_at(&init_mm, address, ptep, + pfn_pte(pfn, PAGE_KERNEL)); + /* No tlb flush necessary because the caller already + * left the pte unmapped. */ + + return 0; } struct page *m2p_find_override(unsigned long mfn) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 1afd5690858c..9ef54ebc1194 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -455,6 +455,8 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, unsigned long mfn; ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count); + if (ret) + return ret; for (i = 0; i < count; i++) { /* m2p override only supported for GNTMAP_contains_pte mappings */ @@ -463,7 +465,9 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + (map_ops[i].host_addr & ~PAGE_MASK)); mfn = pte_mfn(*pte); - m2p_add_override(mfn, pages[i]); + ret = m2p_add_override(mfn, pages[i]); + if (ret) + return ret; } return ret; @@ -476,8 +480,14 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, int i, ret; ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count); - for (i = 0; i < count; i++) - m2p_remove_override(pages[i]); + if (ret) + return ret; + + for (i = 0; i < count; i++) { + ret = m2p_remove_override(pages[i]); + if (ret) + return ret; + } return ret; } -- cgit v1.2.3 From cc8e7a355c1ec64b06a5b8126c47c5cb47f44fce Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 10 Jan 2011 21:23:16 +0100 Subject: PNP / ACPI: Use DEVICE_ACPI_HANDLE() for device ACPI handle access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PNP ACPI driver squirrels the ACPI handles of PNP devices' ACPI companions, but this isn't correct, because those handles should be accessed using the DEVICE_ACPI_HANDLE() macro operating on struct device objects. Using DEVICE_ACPI_HANDLE() in the PNP ACPI driver instead of the driver's own copies of the ACPI handles allows us to avoid a problem with docking stations where a machine docked before suspend to RAM and undocked while suspended crashes during the subsequent resume (in that case the ACPI companion of the PNP device in question doesn't exist any more while the device is being resumed). It also allows us to avoid the problem where suspend to RAM fails when the machine was undocked while suspended before (again, the ACPI companion of the PNP device is not present any more while it is being suspended). This change doesn't fix all of the the PNP ACPI driver's problems with PNP devices in docking stations (generally speaking, the driver has no idea that devices can come and go and doesn't even attempt to handle such events), but at least it makes suspend work for the users of docking stations who don't use the PNP devices located in there. References: https://bugzilla.kernel.org/show_bug.cgi?id=15100 Reported-and-tested-by: Toralf Förster Signed-off-by: Rafael J. Wysocki Acked-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/pnp/driver.c | 7 +++- drivers/pnp/pnpacpi/core.c | 93 +++++++++++++++++++++++++++++++++------------- 2 files changed, 72 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index d1dbb9df53fa..00e94032531a 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -189,8 +189,11 @@ static int pnp_bus_resume(struct device *dev) if (!pnp_drv) return 0; - if (pnp_dev->protocol->resume) - pnp_dev->protocol->resume(pnp_dev); + if (pnp_dev->protocol->resume) { + error = pnp_dev->protocol->resume(pnp_dev); + if (error) + return error; + } if (pnp_can_write(pnp_dev)) { error = pnp_start_dev(pnp_dev); diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 57313f4658bc..ca84d5099ce7 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -81,12 +81,19 @@ static int pnpacpi_get_resources(struct pnp_dev *dev) static int pnpacpi_set_resources(struct pnp_dev *dev) { - struct acpi_device *acpi_dev = dev->data; - acpi_handle handle = acpi_dev->handle; + struct acpi_device *acpi_dev; + acpi_handle handle; struct acpi_buffer buffer; int ret; pnp_dbg(&dev->dev, "set resources\n"); + + handle = DEVICE_ACPI_HANDLE(&dev->dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return -ENODEV; + } + ret = pnpacpi_build_resource_template(dev, &buffer); if (ret) return ret; @@ -105,12 +112,18 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) static int pnpacpi_disable_resources(struct pnp_dev *dev) { - struct acpi_device *acpi_dev = dev->data; - acpi_handle handle = acpi_dev->handle; + struct acpi_device *acpi_dev; + acpi_handle handle; int ret; dev_dbg(&dev->dev, "disable resources\n"); + handle = DEVICE_ACPI_HANDLE(&dev->dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return 0; + } + /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ ret = 0; if (acpi_bus_power_manageable(handle)) @@ -124,46 +137,74 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) #ifdef CONFIG_ACPI_SLEEP static bool pnpacpi_can_wakeup(struct pnp_dev *dev) { - struct acpi_device *acpi_dev = dev->data; - acpi_handle handle = acpi_dev->handle; + struct acpi_device *acpi_dev; + acpi_handle handle; + + handle = DEVICE_ACPI_HANDLE(&dev->dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return false; + } return acpi_bus_can_wakeup(handle); } static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) { - struct acpi_device *acpi_dev = dev->data; - acpi_handle handle = acpi_dev->handle; - int power_state; + struct acpi_device *acpi_dev; + acpi_handle handle; + int error = 0; + + handle = DEVICE_ACPI_HANDLE(&dev->dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return 0; + } if (device_can_wakeup(&dev->dev)) { - int rc = acpi_pm_device_sleep_wake(&dev->dev, + error = acpi_pm_device_sleep_wake(&dev->dev, device_may_wakeup(&dev->dev)); + if (error) + return error; + } + + if (acpi_bus_power_manageable(handle)) { + int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); + + if (power_state < 0) + power_state = (state.event == PM_EVENT_ON) ? + ACPI_STATE_D0 : ACPI_STATE_D3; - if (rc) - return rc; + /* + * acpi_bus_set_power() often fails (keyboard port can't be + * powered-down?), and in any case, our return value is ignored + * by pnp_bus_suspend(). Hence we don't revert the wakeup + * setting if the set_power fails. + */ + error = acpi_bus_set_power(handle, power_state); } - power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); - if (power_state < 0) - power_state = (state.event == PM_EVENT_ON) ? - ACPI_STATE_D0 : ACPI_STATE_D3; - - /* acpi_bus_set_power() often fails (keyboard port can't be - * powered-down?), and in any case, our return value is ignored - * by pnp_bus_suspend(). Hence we don't revert the wakeup - * setting if the set_power fails. - */ - return acpi_bus_set_power(handle, power_state); + + return error; } static int pnpacpi_resume(struct pnp_dev *dev) { - struct acpi_device *acpi_dev = dev->data; - acpi_handle handle = acpi_dev->handle; + struct acpi_device *acpi_dev; + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); + int error = 0; + + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return -ENODEV; + } if (device_may_wakeup(&dev->dev)) acpi_pm_device_sleep_wake(&dev->dev, false); - return acpi_bus_set_power(handle, ACPI_STATE_D0); + + if (acpi_bus_power_manageable(handle)) + error = acpi_bus_set_power(handle, ACPI_STATE_D0); + + return error; } #endif -- cgit v1.2.3 From 858bc21f0637c407601a05626854ae58b242f75d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 4 Jan 2011 10:46:49 -0800 Subject: drm/i915: check eDP encoder correctly when setting modes We were using a stale pointer in the check which caused us to use CPU attached DP params when we should have been using PCH attached params. Signed-off-by: Jesse Barnes Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=31988 Tested-by: Jan-Hendrik Zab Tested-by: Christoph Lukas Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0abe79fb6385..f4d1797350f6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3951,7 +3951,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int lane = 0, link_bw, bpp; /* CPU eDP doesn't require FDI link, so just set DP M/N according to current link config */ - if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) { + if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { target_clock = mode->clock; intel_edp_link_config(has_edp_encoder, &lane, &link_bw); -- cgit v1.2.3 From 37f809755845cc3e18e8216c04525bdb885fa13b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 5 Jan 2011 14:45:24 -0800 Subject: drm/i915: make DP training try a little harder When trying to do channel equalization, we need to make sure we still have clock recovery on all lanes while training. We also need to try clock recovery again if we lose the clock or if channel eq fails 5 times. We'll try clock recovery up to 5 more times before giving up entirely. Gets suspend/resume working on my Vaio again and brings us back into compliance with the DP training sequence spec. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_dp.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1dc60408d5b8..c768e30e5e85 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1334,17 +1334,24 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool channel_eq = false; - int tries; + int tries, cr_tries; u32 reg; uint32_t DP = intel_dp->DP; /* channel equalization */ tries = 0; + cr_tries = 0; channel_eq = false; for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; + if (cr_tries > 5) { + DRM_ERROR("failed to train DP, aborting\n"); + intel_dp_link_down(intel_dp); + break; + } + if (IS_GEN6(dev) && is_edp(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; @@ -1367,14 +1374,26 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) if (!intel_dp_get_link_status(intel_dp)) break; + /* Make sure clock is still ok */ + if (!intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { + intel_dp_start_link_train(intel_dp); + cr_tries++; + continue; + } + if (intel_channel_eq_ok(intel_dp)) { channel_eq = true; break; } - /* Try 5 times */ - if (tries > 5) - break; + /* Try 5 times, then try clock recovery if that fails */ + if (tries > 5) { + intel_dp_link_down(intel_dp); + intel_dp_start_link_train(intel_dp); + tries = 0; + cr_tries++; + continue; + } /* Compute new intel_dp->train_set as requested by target */ intel_get_adjust_train(intel_dp); -- cgit v1.2.3 From f5afcd3dd0dca7fe869311c51da54d5a889191ba Mon Sep 17 00:00:00 2001 From: David Müller Date: Thu, 6 Jan 2011 12:29:32 +0000 Subject: drm/i915/crt: Check for a analog monitor in case of DVI-I MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since Linux 2.6.36 the digital output on my system (855GME + DVI-I) is not working any longer. The analog output is always activated regardless of the type of monitor attached. The culprit seems to be intel_crt_detect_ddc(), which returns true as soon as an ACK from the EDID device is received. Obviously this approach does not work with DVI-I where the analog and digital outputs share a common DDC bus. In a similar manner to the shared DDC wire, ala the "Mac Mini Hack", we need an additional check to make sure that there really is an analog device attached to the DDC. Signed-off-by: David Müller Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_crt.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 8df574316063..17035b87ee46 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -30,6 +30,7 @@ #include "drm.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_edid.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -287,8 +288,9 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus) return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1; } -static bool intel_crt_detect_ddc(struct intel_crt *crt) +static bool intel_crt_detect_ddc(struct drm_connector *connector) { + struct intel_crt *crt = intel_attached_crt(connector); struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private; /* CRT should always be at 0, but check anyway */ @@ -301,8 +303,26 @@ static bool intel_crt_detect_ddc(struct intel_crt *crt) } if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { - DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); - return true; + struct edid *edid; + bool is_digital = false; + + edid = drm_get_edid(connector, + &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter); + /* + * This may be a DVI-I connector with a shared DDC + * link between analog and digital outputs, so we + * have to check the EDID input spec of the attached device. + */ + if (edid != NULL) { + is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; + connector->display_info.raw_edid = NULL; + kfree(edid); + } + + if (!is_digital) { + DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); + return true; + } } return false; @@ -458,7 +478,7 @@ intel_crt_detect(struct drm_connector *connector, bool force) } } - if (intel_crt_detect_ddc(crt)) + if (intel_crt_detect_ddc(connector)) return connector_status_connected; if (!force) @@ -472,7 +492,7 @@ intel_crt_detect(struct drm_connector *connector, bool force) crtc = intel_get_load_detect_pipe(&crt->base, connector, NULL, &dpms_mode); if (crtc) { - if (intel_crt_detect_ddc(crt)) + if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else status = intel_crt_load_detect(crtc, crt); -- cgit v1.2.3 From 0d2689c0f054f6a8bf3115d6386bd9c2d65dc44b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 7 Jan 2011 23:44:32 +0100 Subject: HID: add feature_mapping callback Currently hid doesn't export the features it knows to the specific modules. Some information can be really important in such features: MosArt and Cypress devices are by default not in a multitouch mode. We have to send the value 2 on the right feature. This patch exports to the module the features report so they can find the right feature to set up the correct mode. Signed-off-by: Benjamin Tissoires Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 17 +++++++++++++---- include/linux/hid.h | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d8d372bae3cc..8703b2cd27ca 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -290,6 +290,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel goto ignore; } + if (field->report_type == HID_FEATURE_REPORT) { + if (device->driver->feature_mapping) { + device->driver->feature_mapping(device, hidinput, field, + usage); + } + goto ignore; + } + if (device->driver->input_mapping) { int ret = device->driver->input_mapping(device, hidinput, field, usage, &bit, &max); @@ -839,7 +847,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) struct hid_input *hidinput = NULL; struct input_dev *input_dev; int i, j, k; - int max_report_type = HID_OUTPUT_REPORT; INIT_LIST_HEAD(&hid->inputs); @@ -856,10 +863,11 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) return -1; } - if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) - max_report_type = HID_INPUT_REPORT; + for (k = HID_INPUT_REPORT; k <= HID_FEATURE_REPORT; k++) { + if (k == HID_OUTPUT_REPORT && + hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) + continue; - for (k = HID_INPUT_REPORT; k <= max_report_type; k++) list_for_each_entry(report, &hid->report_enum[k].report_list, list) { if (!report->maxfield) @@ -912,6 +920,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) hidinput = NULL; } } + } if (hidinput && input_register_device(hidinput->input)) goto out_cleanup; diff --git a/include/linux/hid.h b/include/linux/hid.h index bb0f56f5c01e..96bd7920a01a 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -593,6 +593,7 @@ struct hid_usage_id { * @report_fixup: called before report descriptor parsing (NULL means nop) * @input_mapping: invoked on input registering before mapping an usage * @input_mapped: invoked on input registering after mapping an usage + * @feature_mapping: invoked on feature registering * @suspend: invoked on suspend (NULL means nop) * @resume: invoked on resume if device was not reset (NULL means nop) * @reset_resume: invoked on resume if device was reset (NULL means nop) @@ -636,6 +637,9 @@ struct hid_driver { int (*input_mapped)(struct hid_device *hdev, struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max); + void (*feature_mapping)(struct hid_device *hdev, + struct hid_input *hidinput, struct hid_field *field, + struct hid_usage *usage); #ifdef CONFIG_PM int (*suspend)(struct hid_device *hdev, pm_message_t message); int (*resume)(struct hid_device *hdev); -- cgit v1.2.3 From 5519cab477b61326963c8d523520db0342862b63 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 7 Jan 2011 23:45:50 +0100 Subject: HID: hid-multitouch: support for PixCir-based panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created a driver for PixCir based dual-touch panels, including the one in the Hanvon tablet. This is done in a code structure aimed at unifying support for several existing HID multitouch panels. Signed-off-by: Benjamin Tissoires Signed-off-by: Stéphane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 9 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 2 + drivers/hid/hid-ids.h | 4 + drivers/hid/hid-multitouch.c | 468 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 484 insertions(+) create mode 100644 drivers/hid/hid-multitouch.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 401acecc7f32..511554de526e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -285,6 +285,15 @@ config HID_MONTEREY ---help--- Support for Monterey Genius KB29E. +config HID_MULTITOUCH + tristate "HID Multitouch panels" + depends on USB_HID + ---help--- + Generic support for HID multitouch panels. + + Say Y here if you have one of the following devices: + - PixCir touchscreen + config HID_NTRIG tristate "N-Trig touch screen" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index c335605b9200..ec991d475809 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MOSART) += hid-mosart.o +obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3f9673d94da9..9292eb148ce4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1286,6 +1286,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, @@ -1312,6 +1313,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 8e11af86b014..bd3cd551b4ee 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -134,6 +134,7 @@ #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 #define USB_VENDOR_ID_CANDO 0x2087 +#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01 @@ -308,6 +309,9 @@ #define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000 #define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff +#define USB_VENDOR_ID_HANVON 0x20b3 +#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18 + #define USB_VENDOR_ID_HAPP 0x078b #define USB_DEVICE_ID_UGCI_DRIVING 0x0010 #define USB_DEVICE_ID_UGCI_FLYING 0x0020 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c new file mode 100644 index 000000000000..3b05dfe910bc --- /dev/null +++ b/drivers/hid/hid-multitouch.c @@ -0,0 +1,468 @@ +/* + * HID driver for multitouch panels + * + * Copyright (c) 2010-2011 Stephane Chatty + * Copyright (c) 2010-2011 Benjamin Tissoires + * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France + * + */ + +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include "usbhid/usbhid.h" + + +MODULE_AUTHOR("Stephane Chatty "); +MODULE_DESCRIPTION("HID multitouch panels"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +/* quirks to control the device */ +#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) +#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) + +struct mt_slot { + __s32 x, y, p, w, h; + __s32 contactid; /* the device ContactID assigned to this slot */ + bool touch_state; /* is the touch valid? */ + bool seen_in_this_frame;/* has this slot been updated */ +}; + +struct mt_device { + struct mt_slot curdata; /* placeholder of incoming data */ + struct mt_class *mtclass; /* our mt device class */ + unsigned last_field_index; /* last field index of the report */ + unsigned last_slot_field; /* the last field of a slot */ + __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ + __u8 num_received; /* how many contacts we received */ + __u8 num_expected; /* expected last contact index */ + bool curvalid; /* is the current contact valid? */ + struct mt_slot slots[0]; /* first slot */ +}; + +struct mt_class { + __s32 quirks; + __s32 sn_move; /* Signal/noise ratio for move events */ + __s32 sn_pressure; /* Signal/noise ratio for pressure events */ + __u8 maxcontacts; +}; + +/* classes of device behavior */ +#define MT_CLS_DEFAULT 0 +#define MT_CLS_DUAL1 1 + +/* + * these device-dependent functions determine what slot corresponds + * to a valid contact that was just read. + */ + +static int slot_is_contactid(struct mt_device *td) +{ + return td->curdata.contactid; +} + +static int find_slot_from_contactid(struct mt_device *td) +{ + int i; + for (i = 0; i < td->mtclass->maxcontacts; ++i) { + if (td->slots[i].contactid == td->curdata.contactid && + td->slots[i].touch_state) + return i; + } + for (i = 0; i < td->mtclass->maxcontacts; ++i) { + if (!td->slots[i].seen_in_this_frame && + !td->slots[i].touch_state) + return i; + } + return -1; + /* should not occurs. If this happens that means + * that the device sent more touches that it says + * in the report descriptor. It is ignored then. */ +} + +struct mt_class mt_classes[] = { + { 0, 0, 0, 10 }, /* MT_CLS_DEFAULT */ + { MT_QUIRK_SLOT_IS_CONTACTID, 0, 0, 2 }, /* MT_CLS_DUAL1 */ +}; + +static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage) +{ + if (usage->hid == HID_DG_INPUTMODE) { + struct mt_device *td = hid_get_drvdata(hdev); + td->inputmode = field->report->id; + } +} + +static void set_abs(struct input_dev *input, unsigned int code, + struct hid_field *field, int snratio) +{ + int fmin = field->logical_minimum; + int fmax = field->logical_maximum; + int fuzz = snratio ? (fmax - fmin) / snratio : 0; + input_set_abs_params(input, code, fmin, fmax, fuzz, 0); +} + +static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_class *cls = td->mtclass; + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + set_abs(hi->input, ABS_MT_POSITION_X, field, + cls->sn_move); + /* touchscreen emulation */ + set_abs(hi->input, ABS_X, field, cls->sn_move); + td->last_slot_field = usage->hid; + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + set_abs(hi->input, ABS_MT_POSITION_Y, field, + cls->sn_move); + /* touchscreen emulation */ + set_abs(hi->input, ABS_Y, field, cls->sn_move); + td->last_slot_field = usage->hid; + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_INRANGE: + td->last_slot_field = usage->hid; + return 1; + case HID_DG_CONFIDENCE: + td->last_slot_field = usage->hid; + return 1; + case HID_DG_TIPSWITCH: + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + input_set_capability(hi->input, EV_KEY, BTN_TOUCH); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_CONTACTID: + input_mt_init_slots(hi->input, + td->mtclass->maxcontacts); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_WIDTH: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MAJOR); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_HEIGHT: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MINOR); + field->logical_maximum = 1; + field->logical_minimum = 1; + set_abs(hi->input, ABS_MT_ORIENTATION, field, 0); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_TIPPRESSURE: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_PRESSURE); + set_abs(hi->input, ABS_MT_PRESSURE, field, + cls->sn_pressure); + /* touchscreen emulation */ + set_abs(hi->input, ABS_PRESSURE, field, + cls->sn_pressure); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_CONTACTCOUNT: + td->last_field_index = field->report->maxfield - 1; + return 1; + case HID_DG_CONTACTMAX: + /* we don't set td->last_slot_field as contactcount and + * contact max are global to the report */ + return -1; + } + /* let hid-input decide for the others */ + return 0; + + case 0xff000000: + /* we do not want to map these: no input-oriented meaning */ + return -1; + } + + return 0; +} + +static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + set_bit(usage->type, hi->input->evbit); + + return -1; +} + +static int mt_compute_slot(struct mt_device *td) +{ + struct mt_class *cls = td->mtclass; + + if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTID) + return slot_is_contactid(td); + + return find_slot_from_contactid(td); +} + +/* + * this function is called when a whole contact has been processed, + * so that it can assign it to a slot and store the data there + */ +static void mt_complete_slot(struct mt_device *td) +{ + if (td->curvalid) { + struct mt_slot *slot; + int slotnum = mt_compute_slot(td); + + if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) { + slot = td->slots + slotnum; + + memcpy(slot, &(td->curdata), sizeof(struct mt_slot)); + slot->seen_in_this_frame = true; + } + } + td->num_received++; +} + + +/* + * this function is called when a whole packet has been received and processed, + * so that it can decide what to send to the input layer. + */ +static void mt_emit_event(struct mt_device *td, struct input_dev *input) +{ + int i; + + for (i = 0; i < td->mtclass->maxcontacts; ++i) { + struct mt_slot *s = &(td->slots[i]); + if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && + !s->seen_in_this_frame) { + /* + * this slot does not contain useful data, + * notify its closure + */ + s->touch_state = false; + } + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, + s->touch_state); + input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); + input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h); + s->seen_in_this_frame = false; + + } + + input_mt_report_pointer_emulation(input, true); + input_sync(input); + td->num_received = 0; +} + + + +static int mt_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct mt_device *td = hid_get_drvdata(hid); + + if (hid->claimed & HID_CLAIMED_INPUT) { + switch (usage->hid) { + case HID_DG_INRANGE: + break; + case HID_DG_TIPSWITCH: + td->curvalid = value; + td->curdata.touch_state = value; + break; + case HID_DG_CONFIDENCE: + break; + case HID_DG_CONTACTID: + td->curdata.contactid = value; + break; + case HID_DG_TIPPRESSURE: + td->curdata.p = value; + break; + case HID_GD_X: + td->curdata.x = value; + break; + case HID_GD_Y: + td->curdata.y = value; + break; + case HID_DG_WIDTH: + td->curdata.w = value; + break; + case HID_DG_HEIGHT: + td->curdata.h = value; + break; + case HID_DG_CONTACTCOUNT: + /* + * We must not overwrite the previous value (some + * devices send one sequence splitted over several + * messages) + */ + if (value) + td->num_expected = value - 1; + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + } + + if (usage->hid == td->last_slot_field) + mt_complete_slot(td); + + if (field->index == td->last_field_index + && td->num_received > td->num_expected) + mt_emit_event(td, field->hidinput->input); + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static void mt_set_input_mode(struct hid_device *hdev) +{ + struct mt_device *td = hid_get_drvdata(hdev); + struct hid_report *r; + struct hid_report_enum *re; + + if (td->inputmode < 0) + return; + + re = &(hdev->report_enum[HID_FEATURE_REPORT]); + r = re->report_id_hash[td->inputmode]; + if (r) { + r->field[0]->value[0] = 0x02; + usbhid_submit_report(hdev, r, USB_DIR_OUT); + } +} + +static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct mt_device *td; + struct mt_class *mtclass = mt_classes + id->driver_data; + + /* This allows the driver to correctly support devices + * that emit events over several HID messages. + */ + hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; + + td = kzalloc(sizeof(struct mt_device) + + mtclass->maxcontacts * sizeof(struct mt_slot), + GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate multitouch data\n"); + return -ENOMEM; + } + td->mtclass = mtclass; + td->inputmode = -1; + hid_set_drvdata(hdev, td); + + ret = hid_parse(hdev); + if (ret != 0) + goto fail; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret != 0) + goto fail; + + mt_set_input_mode(hdev); + + return 0; + +fail: + kfree(td); + return ret; +} + +#ifdef CONFIG_PM +static int mt_reset_resume(struct hid_device *hdev) +{ + mt_set_input_mode(hdev); + return 0; +} +#endif + +static void mt_remove(struct hid_device *hdev) +{ + struct mt_device *td = hid_get_drvdata(hdev); + hid_hw_stop(hdev); + kfree(td); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id mt_devices[] = { + + /* PixCir-based panels */ + { .driver_data = MT_CLS_DUAL1, + HID_USB_DEVICE(USB_VENDOR_ID_HANVON, + USB_DEVICE_ID_HANVON_MULTITOUCH) }, + { .driver_data = MT_CLS_DUAL1, + HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, + + { } +}; +MODULE_DEVICE_TABLE(hid, mt_devices); + +static const struct hid_usage_id mt_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver mt_driver = { + .name = "hid-multitouch", + .id_table = mt_devices, + .probe = mt_probe, + .remove = mt_remove, + .input_mapping = mt_input_mapping, + .input_mapped = mt_input_mapped, + .feature_mapping = mt_feature_mapping, + .usage_table = mt_grabbed_usages, + .event = mt_event, +#ifdef CONFIG_PM + .reset_resume = mt_reset_resume, +#endif +}; + +static int __init mt_init(void) +{ + return hid_register_driver(&mt_driver); +} + +static void __exit mt_exit(void) +{ + hid_unregister_driver(&mt_driver); +} + +module_init(mt_init); +module_exit(mt_exit); -- cgit v1.2.3 From a3b5e577d96bfccbc41ebf4df784e3a153072273 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 7 Jan 2011 23:46:30 +0100 Subject: HID: hid-multitouch: add support for Cypress TrueTouch panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added support for Cypress TrueTouch panels, which detect up to 10 fingers Signed-off-by: Benjamin Tissoires Signed-off-by: Stéphane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 19 +++++++++++++++++++ 4 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 511554de526e..de31d75e276f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -293,6 +293,7 @@ config HID_MULTITOUCH Say Y here if you have one of the following devices: - PixCir touchscreen + - Cypress TrueTouch config HID_NTRIG tristate "N-Trig touch screen" diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9292eb148ce4..12d4afafc73b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1298,6 +1298,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index bd3cd551b4ee..f5657a8c757d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -180,6 +180,7 @@ #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 #define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1 +#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 #define USB_VENDOR_ID_DEALEXTREAME 0x10c5 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3b05dfe910bc..7af9f7136bd5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -32,6 +32,7 @@ MODULE_LICENSE("GPL"); /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) #define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) +#define MT_QUIRK_CYPRESS (1 << 2) struct mt_slot { __s32 x, y, p, w, h; @@ -62,6 +63,7 @@ struct mt_class { /* classes of device behavior */ #define MT_CLS_DEFAULT 0 #define MT_CLS_DUAL1 1 +#define MT_CLS_CYPRESS 2 /* * these device-dependent functions determine what slot corresponds @@ -73,6 +75,14 @@ static int slot_is_contactid(struct mt_device *td) return td->curdata.contactid; } +static int cypress_compute_slot(struct mt_device *td) +{ + if (td->curdata.contactid != 0 || td->num_received == 0) + return td->curdata.contactid; + else + return -1; +} + static int find_slot_from_contactid(struct mt_device *td) { int i; @@ -95,6 +105,7 @@ static int find_slot_from_contactid(struct mt_device *td) struct mt_class mt_classes[] = { { 0, 0, 0, 10 }, /* MT_CLS_DEFAULT */ { MT_QUIRK_SLOT_IS_CONTACTID, 0, 0, 2 }, /* MT_CLS_DUAL1 */ + { MT_QUIRK_CYPRESS | MT_QUIRK_NOT_SEEN_MEANS_UP, 0, 0, 10 }, /* MT_CLS_CYPRESS */ }; static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -223,6 +234,9 @@ static int mt_compute_slot(struct mt_device *td) if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTID) return slot_is_contactid(td); + if (cls->quirks & MT_QUIRK_CYPRESS) + return cypress_compute_slot(td); + return find_slot_from_contactid(td); } @@ -422,6 +436,11 @@ static void mt_remove(struct hid_device *hdev) static const struct hid_device_id mt_devices[] = { + /* Cypress panel */ + { .driver_data = MT_CLS_CYPRESS, + HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, + USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, + /* PixCir-based panels */ { .driver_data = MT_CLS_DUAL1, HID_USB_DEVICE(USB_VENDOR_ID_HANVON, -- cgit v1.2.3 From 3c5a62b5226ca5db993660281e9c2a7275d9fb02 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Thu, 6 Jan 2011 18:26:08 +0800 Subject: drm/i915: fix calculation of eDP signal levels on Sandybridge Some voltage swing/pre-emphasis level use the same value on eDP Sandybridge, like 400mv_0db and 600mv_0db are with the same value of (0x0 << 22). So, fix them, and point out the value if it isn't a supported voltage swing/pre-emphasis level. Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_reg.h | 9 +++++---- drivers/gpu/drm/i915/intel_dp.c | 23 ++++++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8f948a6fbc1c..677eca65a4bc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3174,10 +3174,11 @@ #define EDP_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22) #define EDP_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22) /* SNB B-stepping */ -#define EDP_LINK_TRAIN_400MV_0DB_SNB_B (0x0<<22) -#define EDP_LINK_TRAIN_400MV_6DB_SNB_B (0x3a<<22) -#define EDP_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22) -#define EDP_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22) +#define EDP_LINK_TRAIN_400_600MV_0DB_SNB_B (0x0<<22) +#define EDP_LINK_TRAIN_400MV_3_5DB_SNB_B (0x1<<22) +#define EDP_LINK_TRAIN_400_600MV_6DB_SNB_B (0x3a<<22) +#define EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B (0x39<<22) +#define EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B (0x38<<22) #define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22) #define FORCEWAKE 0xA18C diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c768e30e5e85..1f4242b682c8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1153,18 +1153,27 @@ intel_dp_signal_levels(uint8_t train_set, int lane_count) static uint32_t intel_gen6_edp_signal_levels(uint8_t train_set) { - switch (train_set & (DP_TRAIN_VOLTAGE_SWING_MASK|DP_TRAIN_PRE_EMPHASIS_MASK)) { + int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | + DP_TRAIN_PRE_EMPHASIS_MASK); + switch (signal_levels) { case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0: - return EDP_LINK_TRAIN_400MV_0DB_SNB_B; + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0: + return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B; + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5: + return EDP_LINK_TRAIN_400MV_3_5DB_SNB_B; case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6: - return EDP_LINK_TRAIN_400MV_6DB_SNB_B; + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_6: + return EDP_LINK_TRAIN_400_600MV_6DB_SNB_B; case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5: - return EDP_LINK_TRAIN_600MV_3_5DB_SNB_B; + case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5: + return EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B; case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0: - return EDP_LINK_TRAIN_800MV_0DB_SNB_B; + case DP_TRAIN_VOLTAGE_SWING_1200 | DP_TRAIN_PRE_EMPHASIS_0: + return EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B; default: - DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level\n"); - return EDP_LINK_TRAIN_400MV_0DB_SNB_B; + DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:" + "0x%x\n", signal_levels); + return EDP_LINK_TRAIN_400_600MV_0DB_SNB_B; } } -- cgit v1.2.3 From 5572da08a784621f2ab4fdc8dc65471261871795 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 7 Jan 2011 23:47:27 +0100 Subject: HID: hid-mulitouch: add support for the 'Sensing Win7-TwoFinger' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added support for the 'Sensing Win7-TwoFinger' panel by GeneralTouch found on some tablets. Because of conflicting VID/PID, this conflicts with previous support for some single-touch panels by GeneralTouch Signed-off-by: Benjamin Tissoires Signed-off-by: Stéphane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 2 +- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 18 +++++++++++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index de31d75e276f..9bd21482e618 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -294,6 +294,7 @@ config HID_MULTITOUCH Say Y here if you have one of the following devices: - PixCir touchscreen - Cypress TrueTouch + - 'Sensing Win7-TwoFinger' panel by GeneralTouch config HID_NTRIG tristate "N-Trig touch screen" diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 12d4afafc73b..42cfc9464c0a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1309,6 +1309,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, @@ -1614,7 +1615,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f5657a8c757d..265c747ba9b8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -228,6 +228,7 @@ #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc +#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001 #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 7af9f7136bd5..3442ed56e964 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -33,6 +33,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) #define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) #define MT_QUIRK_CYPRESS (1 << 2) +#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) struct mt_slot { __s32 x, y, p, w, h; @@ -63,7 +64,8 @@ struct mt_class { /* classes of device behavior */ #define MT_CLS_DEFAULT 0 #define MT_CLS_DUAL1 1 -#define MT_CLS_CYPRESS 2 +#define MT_CLS_DUAL2 2 +#define MT_CLS_CYPRESS 3 /* * these device-dependent functions determine what slot corresponds @@ -75,6 +77,11 @@ static int slot_is_contactid(struct mt_device *td) return td->curdata.contactid; } +static int slot_is_contactnumber(struct mt_device *td) +{ + return td->num_received; +} + static int cypress_compute_slot(struct mt_device *td) { if (td->curdata.contactid != 0 || td->num_received == 0) @@ -105,6 +112,7 @@ static int find_slot_from_contactid(struct mt_device *td) struct mt_class mt_classes[] = { { 0, 0, 0, 10 }, /* MT_CLS_DEFAULT */ { MT_QUIRK_SLOT_IS_CONTACTID, 0, 0, 2 }, /* MT_CLS_DUAL1 */ + { MT_QUIRK_SLOT_IS_CONTACTNUMBER, 0, 0, 10 }, /* MT_CLS_DUAL2 */ { MT_QUIRK_CYPRESS | MT_QUIRK_NOT_SEEN_MEANS_UP, 0, 0, 10 }, /* MT_CLS_CYPRESS */ }; @@ -237,6 +245,9 @@ static int mt_compute_slot(struct mt_device *td) if (cls->quirks & MT_QUIRK_CYPRESS) return cypress_compute_slot(td); + if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) + return slot_is_contactnumber(td); + return find_slot_from_contactid(td); } @@ -441,6 +452,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, + /* GeneralTouch panel */ + { .driver_data = MT_CLS_DUAL2, + HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, + USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, + /* PixCir-based panels */ { .driver_data = MT_CLS_DUAL1, HID_USB_DEVICE(USB_VENDOR_ID_HANVON, -- cgit v1.2.3 From bc5ab083a68bfec212780281f8e57d871d8882a0 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jan 2011 12:15:41 +0100 Subject: HID: add Add Cando touch screen 10.1-inch product id This device has been reported to be an hid-cando one. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-cando.c | 2 ++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c index 5925bdcd417d..343c41bac80e 100644 --- a/drivers/hid/hid-cando.c +++ b/drivers/hid/hid-cando.c @@ -235,6 +235,8 @@ static void cando_remove(struct hid_device *hdev) static const struct hid_device_id cando_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 42cfc9464c0a..76ee7111d16c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1288,6 +1288,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 265c747ba9b8..372b5cf2a92f 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -136,6 +136,7 @@ #define USB_VENDOR_ID_CANDO 0x2087 #define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 +#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 0x0a02 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01 -- cgit v1.2.3 From c64f6f934c7490faff76faf96217066a1b3570a0 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Jan 2011 12:15:42 +0100 Subject: HID: Switch turbox/mosart touchscreen to hid-mosart This device used the MULTI_INPUT quirk whereas it could be used with hid-mosart instead to support the multitouch part. Reference: https://bugs.launchpad.net/ubuntu/+bug/620609/ Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-mosart.c | 1 + drivers/hid/usbhid/hid-quirks.c | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 76ee7111d16c..809060ede6d7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1398,6 +1398,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index ac5421d568f1..251eaa4eedb3 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -240,6 +240,7 @@ static void mosart_remove(struct hid_device *hdev) static const struct hid_device_id mosart_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, { } }; MODULE_DEVICE_TABLE(hid, mosart_devices); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 2c185477eeb3..af343760529c 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -35,7 +35,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.3 From 97aaf910731b03b27b1c4c8a58006a1dc99dcd9a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jan 2011 20:10:52 +0000 Subject: drm/i915/sdvo: Defer detection of output capabilities until probing Alex Fiestas reported an issue with his HDMI connector being misdetected as DVI unless he had something connected upon boot. By moving the decision as to whether to use HDMI or DVI encoding for the HDMI capable output until we probe the monitor means that we should avoid sending a HDMI signal to a DVI monitor and also correctly detect hardware like Alex's. However, to really determine what connector is soldered onto the wire we need to inspect the VBT sdvo child devices - but can we trust it? Reported-by: Alex Fiestas Tested-by: Alex Fiestas Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32828 Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_sdvo.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9d0af36a13ec..45cd37652a37 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1024,9 +1024,13 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (!intel_sdvo_set_target_input(intel_sdvo)) return; - if (intel_sdvo->has_hdmi_monitor && - !intel_sdvo_set_avi_infoframe(intel_sdvo)) - return; + if (intel_sdvo->has_hdmi_monitor) { + intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); + intel_sdvo_set_colorimetry(intel_sdvo, + SDVO_COLORIMETRY_RGB256); + intel_sdvo_set_avi_infoframe(intel_sdvo); + } else + intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); if (intel_sdvo->is_tv && !intel_sdvo_set_tv_format(intel_sdvo)) @@ -1398,6 +1402,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) intel_sdvo->attached_output = response; + intel_sdvo->has_hdmi_monitor = false; + intel_sdvo->has_hdmi_audio = false; + if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; else if (response & SDVO_TMDS_MASK) @@ -1922,20 +1929,7 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, static bool intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device) { - int is_hdmi; - - if (!intel_sdvo_check_supp_encode(intel_sdvo)) - return false; - - if (!intel_sdvo_set_target_output(intel_sdvo, - device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1)) - return false; - - is_hdmi = 0; - if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, &is_hdmi, 1)) - return false; - - return !!is_hdmi; + return intel_sdvo_check_supp_encode(intel_sdvo); } static u8 @@ -2037,12 +2031,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) connector->connector_type = DRM_MODE_CONNECTOR_DVID; if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { - /* enable hdmi encoding mode if supported */ - intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); - intel_sdvo_set_colorimetry(intel_sdvo, - SDVO_COLORIMETRY_RGB256); connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; - intel_sdvo->is_hdmi = true; } intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | -- cgit v1.2.3 From 2d93666e70662cfcf1927e1a858685f5b38d5d65 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 11 Jan 2011 16:45:54 +0100 Subject: HID: hid-multitouch: minor fixes based on additional review * amended Kconfig (PixCir and Hanvon are the same panel but with different name) * insert field name in mt_class and retrieving it in mt_probe * add 2 quirks: MT_QUIRK_VALID_IS_INRANGE, MT_QUIRK_VALID_IS_CONFIDENCE, in order to find the field "valid" * inlined slot_is_contactid and slot_is_contact_number * cosmetics changes (tabs and comments) * do not send unnecessary properties once the touch is up Signed-off-by: Benjamin Tissoires Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 10 +++- drivers/hid/hid-multitouch.c | 127 ++++++++++++++++++++++++------------------- 2 files changed, 78 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 9bd21482e618..97c200b0f4b8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -292,10 +292,16 @@ config HID_MULTITOUCH Generic support for HID multitouch panels. Say Y here if you have one of the following devices: - - PixCir touchscreen - - Cypress TrueTouch + - Cypress TrueTouch panels + - Hanvon dual touch panels + - Pixcir dual touch panels - 'Sensing Win7-TwoFinger' panel by GeneralTouch + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called hid-multitouch. + config HID_NTRIG tristate "N-Trig touch screen" depends on USB_HID diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3442ed56e964..07d3183fdde5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -32,8 +32,10 @@ MODULE_LICENSE("GPL"); /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) #define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) -#define MT_QUIRK_CYPRESS (1 << 2) +#define MT_QUIRK_CYPRESS (1 << 2) #define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) +#define MT_QUIRK_VALID_IS_INRANGE (1 << 4) +#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) struct mt_slot { __s32 x, y, p, w, h; @@ -55,6 +57,7 @@ struct mt_device { }; struct mt_class { + __s32 name; /* MT_CLS */ __s32 quirks; __s32 sn_move; /* Signal/noise ratio for move events */ __s32 sn_pressure; /* Signal/noise ratio for pressure events */ @@ -62,26 +65,16 @@ struct mt_class { }; /* classes of device behavior */ -#define MT_CLS_DEFAULT 0 -#define MT_CLS_DUAL1 1 -#define MT_CLS_DUAL2 2 -#define MT_CLS_CYPRESS 3 +#define MT_CLS_DEFAULT 1 +#define MT_CLS_DUAL1 2 +#define MT_CLS_DUAL2 3 +#define MT_CLS_CYPRESS 4 /* * these device-dependent functions determine what slot corresponds * to a valid contact that was just read. */ -static int slot_is_contactid(struct mt_device *td) -{ - return td->curdata.contactid; -} - -static int slot_is_contactnumber(struct mt_device *td) -{ - return td->num_received; -} - static int cypress_compute_slot(struct mt_device *td) { if (td->curdata.contactid != 0 || td->num_received == 0) @@ -103,17 +96,30 @@ static int find_slot_from_contactid(struct mt_device *td) !td->slots[i].touch_state) return i; } - return -1; /* should not occurs. If this happens that means * that the device sent more touches that it says * in the report descriptor. It is ignored then. */ + return -1; } struct mt_class mt_classes[] = { - { 0, 0, 0, 10 }, /* MT_CLS_DEFAULT */ - { MT_QUIRK_SLOT_IS_CONTACTID, 0, 0, 2 }, /* MT_CLS_DUAL1 */ - { MT_QUIRK_SLOT_IS_CONTACTNUMBER, 0, 0, 10 }, /* MT_CLS_DUAL2 */ - { MT_QUIRK_CYPRESS | MT_QUIRK_NOT_SEEN_MEANS_UP, 0, 0, 10 }, /* MT_CLS_CYPRESS */ + { .name = MT_CLS_DEFAULT, + .quirks = MT_QUIRK_VALID_IS_INRANGE, + .maxcontacts = 10 }, + { .name = MT_CLS_DUAL1, + .quirks = MT_QUIRK_VALID_IS_INRANGE | + MT_QUIRK_SLOT_IS_CONTACTID, + .maxcontacts = 2 }, + { .name = MT_CLS_DUAL2, + .quirks = MT_QUIRK_VALID_IS_INRANGE | + MT_QUIRK_SLOT_IS_CONTACTNUMBER, + .maxcontacts = 2 }, + { .name = MT_CLS_CYPRESS, + .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | + MT_QUIRK_CYPRESS, + .maxcontacts = 10 }, + + { } }; static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -192,7 +198,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); field->logical_maximum = 1; - field->logical_minimum = 1; + field->logical_minimum = 0; set_abs(hi->input, ABS_MT_ORIENTATION, field, 0); td->last_slot_field = usage->hid; return 1; @@ -237,16 +243,16 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, static int mt_compute_slot(struct mt_device *td) { - struct mt_class *cls = td->mtclass; + __s32 quirks = td->mtclass->quirks; - if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTID) - return slot_is_contactid(td); + if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) + return td->curdata.contactid; - if (cls->quirks & MT_QUIRK_CYPRESS) + if (quirks & MT_QUIRK_CYPRESS) return cypress_compute_slot(td); - if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) - return slot_is_contactnumber(td); + if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) + return td->num_received; return find_slot_from_contactid(td); } @@ -257,16 +263,12 @@ static int mt_compute_slot(struct mt_device *td) */ static void mt_complete_slot(struct mt_device *td) { + td->curdata.seen_in_this_frame = true; if (td->curvalid) { - struct mt_slot *slot; int slotnum = mt_compute_slot(td); - if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) { - slot = td->slots + slotnum; - - memcpy(slot, &(td->curdata), sizeof(struct mt_slot)); - slot->seen_in_this_frame = true; - } + if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) + td->slots[slotnum] = td->curdata; } td->num_received++; } @@ -284,21 +286,19 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) struct mt_slot *s = &(td->slots[i]); if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && !s->seen_in_this_frame) { - /* - * this slot does not contain useful data, - * notify its closure - */ s->touch_state = false; } input_mt_slot(input, i); input_mt_report_slot_state(input, MT_TOOL_FINGER, s->touch_state); - input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); - input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); - input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w); - input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h); + if (s->touch_state) { + input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); + input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h); + } s->seen_in_this_frame = false; } @@ -314,16 +314,22 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct mt_device *td = hid_get_drvdata(hid); + __s32 quirks = td->mtclass->quirks; if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { case HID_DG_INRANGE: + if (quirks & MT_QUIRK_VALID_IS_INRANGE) + td->curvalid = value; break; case HID_DG_TIPSWITCH: - td->curvalid = value; + if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) + td->curvalid = value; td->curdata.touch_state = value; break; case HID_DG_CONFIDENCE: + if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) + td->curvalid = value; break; case HID_DG_CONTACTID: td->curdata.contactid = value; @@ -345,26 +351,26 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, break; case HID_DG_CONTACTCOUNT: /* - * We must not overwrite the previous value (some - * devices send one sequence splitted over several - * messages) + * Includes multi-packet support where subsequent + * packets are sent with zero contactcount. */ if (value) - td->num_expected = value - 1; + td->num_expected = value; break; default: /* fallback to the generic hidinput handling */ return 0; } - } - if (usage->hid == td->last_slot_field) - mt_complete_slot(td); + if (usage->hid == td->last_slot_field) + mt_complete_slot(td); + + if (field->index == td->last_field_index + && td->num_received >= td->num_expected) + mt_emit_event(td, field->hidinput->input); - if (field->index == td->last_field_index - && td->num_received > td->num_expected) - mt_emit_event(td, field->hidinput->input); + } /* we have handled the hidinput part, now remains hiddev */ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) @@ -392,9 +398,16 @@ static void mt_set_input_mode(struct hid_device *hdev) static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { - int ret; + int ret, i; struct mt_device *td; - struct mt_class *mtclass = mt_classes + id->driver_data; + struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ + + for (i = 0; mt_classes[i].name ; i++) { + if (id->driver_data == mt_classes[i].name) { + mtclass = &(mt_classes[i]); + break; + } + } /* This allows the driver to correctly support devices * that emit events over several HID messages. @@ -417,7 +430,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - if (ret != 0) + if (ret) goto fail; mt_set_input_mode(hdev); -- cgit v1.2.3 From 47356eb67285014527a5ab87543ba1fae3d1e10a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Jan 2011 17:06:04 +0000 Subject: drm/i915/panel: Only record the backlight level when it is enabled By tracking the current status of the backlight we can prevent recording the value of the current backlight when we have disabled it. And so prevent restoring it to 'off' after an unbalanced sequence of intel_lvds_disable/enable. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=22672 Tested-by: Alex Riesen Tested-by: Larry Finger Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 2 ++ drivers/gpu/drm/i915/intel_drv.h | 3 +++ drivers/gpu/drm/i915/intel_lvds.c | 10 ++-------- drivers/gpu/drm/i915/intel_panel.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index aac1bf332f75..972e08e4e054 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -332,6 +332,7 @@ typedef struct drm_i915_private { /* LVDS info */ int backlight_level; /* restore backlight to this value */ + bool backlight_enabled; struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f4d1797350f6..bc829bbc14c8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5802,6 +5802,8 @@ static void intel_setup_outputs(struct drm_device *dev) encoder->base.possible_clones = intel_encoder_clones(dev, encoder->clone_mask); } + + intel_panel_setup_backlight(dev); } static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d782ad9fd6db..74db2557d644 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -257,6 +257,9 @@ extern void intel_pch_panel_fitting(struct drm_device *dev, extern u32 intel_panel_get_max_backlight(struct drm_device *dev); extern u32 intel_panel_get_backlight(struct drm_device *dev); extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); +extern void intel_panel_setup_backlight(struct drm_device *dev); +extern void intel_panel_enable_backlight(struct drm_device *dev); +extern void intel_panel_disable_backlight(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index aa2307080be2..4e7dcb330dad 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -106,7 +106,7 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds) I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); POSTING_READ(lvds_reg); - intel_panel_set_backlight(dev, dev_priv->backlight_level); + intel_panel_enable_backlight(dev); } static void intel_lvds_disable(struct intel_lvds *intel_lvds) @@ -123,8 +123,7 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds) lvds_reg = LVDS; } - dev_priv->backlight_level = intel_panel_get_backlight(dev); - intel_panel_set_backlight(dev, 0); + intel_panel_disable_backlight(dev); I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); @@ -398,8 +397,6 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_lvds *intel_lvds = to_intel_lvds(encoder); - dev_priv->backlight_level = intel_panel_get_backlight(dev); - /* We try to do the minimum that is necessary in order to unlock * the registers for mode setting. * @@ -430,9 +427,6 @@ static void intel_lvds_commit(struct drm_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_lvds *intel_lvds = to_intel_lvds(encoder); - if (dev_priv->backlight_level == 0) - dev_priv->backlight_level = intel_panel_get_max_backlight(dev); - /* Undo any unlocking done in prepare to prevent accidental * adjustment of the registers. */ diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7350ec2515c6..e00d200df3db 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -250,3 +250,34 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level) tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; I915_WRITE(BLC_PWM_CTL, tmp | level); } + +void intel_panel_disable_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->backlight_enabled) { + dev_priv->backlight_level = intel_panel_get_backlight(dev); + dev_priv->backlight_enabled = false; + } + + intel_panel_set_backlight(dev, 0); +} + +void intel_panel_enable_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->backlight_level == 0) + dev_priv->backlight_level = intel_panel_get_max_backlight(dev); + + intel_panel_set_backlight(dev, dev_priv->backlight_level); + dev_priv->backlight_enabled = true; +} + +void intel_panel_setup_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->backlight_level = intel_panel_get_max_backlight(dev); + dev_priv->backlight_enabled = dev_priv->backlight_level != 0; +} -- cgit v1.2.3 From bee17e5ae6b68d21b9d193f34ccefeef9d4fffe0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Jan 2011 18:09:58 +0000 Subject: drm/i915/lvds: Always use 0 to disable the pfit controller ... and just any combination of bits & ~PFIT_ENABLE. This way we do not attempt disable to the panel fitter controller uselessly upon intel_lvds_disable(). Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_lvds.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4e7dcb330dad..8f4f6bd33ee9 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -374,6 +374,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: + if ((pfit_control & PFIT_ENABLE) == 0) { + pfit_control = 0; + pfit_pgm_ratios = 0; + } if (pfit_control != intel_lvds->pfit_control || pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) { intel_lvds->pfit_control = pfit_control; -- cgit v1.2.3 From a6044e23b784544fe567db75dbf9c4f684bd6d5b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 20 Dec 2010 11:34:20 -0800 Subject: drm/i915: support overclocking on Sandy Bridge In some configuration, the PCU may allow us to overclock the GPU. Check for this case and adjust the max frequency as appropriate. Also initialize the min/max frequencies to default values as indicated by hardware. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 677eca65a4bc..1bc816f3934b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3240,6 +3240,7 @@ #define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_READY (1<<31) +#define GEN6_READ_OC_PARAMS 0xc #define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x9 #define GEN6_PCODE_DATA 0x138128 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bc829bbc14c8..efa88551cbe4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6147,6 +6147,10 @@ void intel_init_emon(struct drm_device *dev) void gen6_enable_rps(struct drm_i915_private *dev_priv) { + u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); + u32 pcu_mbox; + int cur_freq, min_freq, max_freq; int i; /* Here begins a magic sequence of register writes to enable @@ -6218,6 +6222,29 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) 500)) DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + min_freq = (rp_state_cap & 0xff0000) >> 16; + max_freq = rp_state_cap & 0xff; + cur_freq = (gt_perf_status & 0xff00) >> 8; + + /* Check for overclock support */ + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); + pcu_mbox = I915_READ(GEN6_PCODE_DATA); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + if (pcu_mbox & (1<<31)) { /* OC supported */ + max_freq = pcu_mbox & 0xff; + DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 100); + } + + /* In units of 100MHz */ + dev_priv->max_delay = max_freq; + dev_priv->min_delay = min_freq; + dev_priv->cur_delay = cur_freq; + /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, GEN6_PM_MBOX_EVENT | -- cgit v1.2.3 From 35c3047ad15849335242b847c94f180ef45db490 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Dec 2010 14:07:12 +0000 Subject: drm/i915: Use the mappable sizes determined by GTT for consistency. There should be no difference, but we can eliminate redundant code. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 7 +------ drivers/gpu/drm/i915/intel_fb.c | 20 +++++++++----------- 2 files changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index efa88551cbe4..9d97fd4e5558 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6694,12 +6694,7 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; } - - /* set memory base */ - if (IS_GEN2(dev)) - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); - else - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); + dev->mode_config.fb_base = dev->agp->base; if (IS_MOBILE(dev) || !IS_GEN2(dev)) dev_priv->num_pipe = 2; diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 701e830d0012..ee145a257287 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -62,6 +62,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, struct drm_fb_helper_surface_size *sizes) { struct drm_device *dev = ifbdev->helper.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; struct drm_mode_fb_cmd mode_cmd; @@ -77,7 +78,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mode_cmd.height = sizes->surface_height; mode_cmd.bpp = sizes->surface_bpp; - mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); + mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64); mode_cmd.depth = sizes->surface_depth; size = mode_cmd.pitch * mode_cmd.height; @@ -120,6 +121,11 @@ static int intelfb_create(struct intel_fbdev *ifbdev, info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &intelfb_ops; + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + ret = -ENOMEM; + goto out_unpin; + } /* setup aperture base/size for vesafb takeover */ info->apertures = alloc_apertures(1); if (!info->apertures) { @@ -127,10 +133,8 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - if (!IS_GEN2(dev)) - info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2); - else - info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); + info->apertures->ranges[0].size = + dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; info->fix.smem_len = size; @@ -140,12 +144,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev, ret = -ENOSPC; goto out_unpin; } - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unpin; - } info->screen_size = size; // memset(info->screen_base, 0, size); -- cgit v1.2.3 From 55249baaa5cd188ebd9acdb047eeaed8092e4a93 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Dec 2010 14:04:47 +0000 Subject: drm/i915: Workaround erratum on i830 for TAIL pointer within last 2 cachelines On i830 if the tail pointer is set to within 2 cachelines of the end of the buffer, the chip may hang. So instead if the tail were to land in that location, we pad the end of the buffer with NOPs, and start again at the beginning. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 13 ++++++++++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 56bc95c056dd..2de0e45464c5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -785,6 +785,14 @@ int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto err_unmap; + /* Workaround an erratum on the i830 which causes a hang if + * the TAIL pointer points to within the last 2 cachelines + * of the buffer. + */ + ring->effective_size = ring->size; + if (IS_I830(ring->dev)) + ring->effective_size -= 128; + return 0; err_unmap: @@ -827,8 +835,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) { unsigned int *virt; - int rem; - rem = ring->size - ring->tail; + int rem = ring->size - ring->tail; if (ring->space < rem) { int ret = intel_wait_ring_buffer(ring, rem); @@ -895,7 +902,7 @@ int intel_ring_begin(struct intel_ring_buffer *ring, int n = 4*num_dwords; int ret; - if (unlikely(ring->tail + n > ring->size)) { + if (unlikely(ring->tail + n > ring->effective_size)) { ret = intel_wrap_ring_buffer(ring); if (unlikely(ret)) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8e2e357ad6ee..bbbf505c8b56 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -49,6 +49,7 @@ struct intel_ring_buffer { u32 tail; int space; int size; + int effective_size; struct intel_hw_status_page status_page; u32 irq_seqno; /* last seq seem at irq time */ -- cgit v1.2.3 From c97689d8860f086125e7ff9cd730027a0057ca4f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Dec 2010 10:40:38 +0000 Subject: agp/intel: Flush the chipset write buffers when changing GTT base Flush the chipset write buffers before and after adjusting the GTT base register, just in case. We only modify this value upon initialisation (boot and resume) so there should be no outstanding writes, however there are always those persistent PGTBL_ER that keep getting reported upon resume. Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.h | 2 ++ drivers/char/agp/intel-gtt.c | 9 +++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 010e3defd6c3..c195bfeade11 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -94,6 +94,8 @@ #define G4x_GMCH_SIZE_VT_1_5M (0xa << 8) #define G4x_GMCH_SIZE_VT_2M (0xc << 8) +#define GFX_FLSH_CNTL 0x2170 /* 915+ */ + #define I810_DRAM_CTL 0x3000 #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 356f73e0d17e..da8161806f39 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -814,6 +814,12 @@ static bool intel_enable_gtt(void) } } + /* On the resume path we may be adjusting the PGTBL value, so + * be paranoid and flush all chipset write buffers... + */ + if (INTEL_GTT_GEN >= 3) + writel(0, intel_private.registers+GFX_FLSH_CNTL); + reg = intel_private.registers+I810_PGETBL_CTL; writel(intel_private.PGETBL_save, reg); if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) { @@ -823,6 +829,9 @@ static bool intel_enable_gtt(void) return false; } + if (INTEL_GTT_GEN >= 3) + writel(0, intel_private.registers+GFX_FLSH_CNTL); + return true; } -- cgit v1.2.3 From b79d4990226defc3789f9ba492b27e9e56790857 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 21 Dec 2010 13:10:23 -0800 Subject: drm/i915: support low power watermarks on Ironlake This patch actually makes the watermark code even uglier (if that's possible), but has the advantage of sharing code between SNB and ILK at least. Longer term we should refactor the watermark stuff into its own file and clean it up now that we know how it's supposed to work. Supporting WM2 on my Vaio reduced power consumption by around 0.5W, so this patch is definitely worthwhile (though it also needs lots of test coverage). Signed-off-by: Jesse Barnes [ickle: pass the watermark structs arounds] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 5 + drivers/gpu/drm/i915/intel_display.c | 258 +++++++++++++++++------------------ 2 files changed, 133 insertions(+), 130 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1bc816f3934b..ecfb0023f60d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2345,8 +2345,13 @@ /* Memory latency timer register */ #define MLTR_ILK 0x11222 +#define MLTR_WM1_SHIFT 0 +#define MLTR_WM2_SHIFT 8 /* the unit of memory self-refresh latency time is 0.5us */ #define ILK_SRLT_MASK 0x3f +#define ILK_LATENCY(shift) (I915_READ(MLTR_ILK) >> (shift) & ILK_SRLT_MASK) +#define ILK_READ_WM1_LATENCY() ILK_LATENCY(MLTR_WM1_SHIFT) +#define ILK_READ_WM2_LATENCY() ILK_LATENCY(MLTR_WM2_SHIFT) /* define the fifo size on Ironlake */ #define ILK_DISPLAY_FIFO 128 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9d97fd4e5558..79753b8ac797 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3456,113 +3456,17 @@ static bool ironlake_compute_wm0(struct drm_device *dev, return true; } -static void ironlake_update_wm(struct drm_device *dev, - int planea_clock, int planeb_clock, - int sr_hdisplay, int sr_htotal, - int pixel_size) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int plane_wm, cursor_wm, enabled; - int tmp; - - enabled = 0; - if (ironlake_compute_wm0(dev, 0, - &ironlake_display_wm_info, - ILK_LP0_PLANE_LATENCY, - &ironlake_cursor_wm_info, - ILK_LP0_CURSOR_LATENCY, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEA_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled++; - } - - if (ironlake_compute_wm0(dev, 1, - &ironlake_display_wm_info, - ILK_LP0_PLANE_LATENCY, - &ironlake_cursor_wm_info, - ILK_LP0_CURSOR_LATENCY, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEB_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled++; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - */ - tmp = 0; - if (enabled == 1) { - unsigned long line_time_us; - int small, large, plane_fbc; - int sr_clock, entries; - int line_count, line_size; - /* Read the self-refresh latency. The unit is 0.5us */ - int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK; - - sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = (sr_htotal * 1000) / sr_clock; - - /* Use ns/us then divide to preserve precision */ - line_count = ((ilk_sr_latency * 500) / line_time_us + 1000) - / 1000; - line_size = sr_hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), - ironlake_display_srwm_info.cacheline_size); - - plane_fbc = entries * 64; - plane_fbc = DIV_ROUND_UP(plane_fbc, line_size); - - plane_wm = entries + ironlake_display_srwm_info.guard_size; - if (plane_wm > (int)ironlake_display_srwm_info.max_wm) - plane_wm = ironlake_display_srwm_info.max_wm; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = DIV_ROUND_UP(entries, - ironlake_cursor_srwm_info.cacheline_size); - - cursor_wm = entries + ironlake_cursor_srwm_info.guard_size; - if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm) - cursor_wm = ironlake_cursor_srwm_info.max_wm; - - /* configure watermark and enable self-refresh */ - tmp = (WM1_LP_SR_EN | - (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | - (plane_fbc << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d," - " cursor %d\n", plane_wm, plane_fbc, cursor_wm); - } - I915_WRITE(WM1_LP_ILK, tmp); - /* XXX setup WM2 and WM3 */ -} - /* * Check the wm result. * * If any calculated watermark values is larger than the maximum value that * can be programmed into the associated watermark register, that watermark * must be disabled. - * - * Also return true if all of those watermark values is 0, which is set by - * sandybridge_compute_srwm, to indicate the latency is ZERO. */ -static bool sandybridge_check_srwm(struct drm_device *dev, int level, - int fbc_wm, int display_wm, int cursor_wm) +static bool ironlake_check_srwm(struct drm_device *dev, int level, + int fbc_wm, int display_wm, int cursor_wm, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3571,7 +3475,7 @@ static bool sandybridge_check_srwm(struct drm_device *dev, int level, if (fbc_wm > SNB_FBC_MAX_SRWM) { DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", - fbc_wm, SNB_FBC_MAX_SRWM, level); + fbc_wm, SNB_FBC_MAX_SRWM, level); /* fbc has it's own way to disable FBC WM */ I915_WRITE(DISP_ARB_CTL, @@ -3579,15 +3483,15 @@ static bool sandybridge_check_srwm(struct drm_device *dev, int level, return false; } - if (display_wm > SNB_DISPLAY_MAX_SRWM) { + if (display_wm > display->max_wm) { DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", - display_wm, SNB_DISPLAY_MAX_SRWM, level); + display_wm, SNB_DISPLAY_MAX_SRWM, level); return false; } - if (cursor_wm > SNB_CURSOR_MAX_SRWM) { + if (cursor_wm > cursor->max_wm) { DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", - cursor_wm, SNB_CURSOR_MAX_SRWM, level); + cursor_wm, SNB_CURSOR_MAX_SRWM, level); return false; } @@ -3602,16 +3506,18 @@ static bool sandybridge_check_srwm(struct drm_device *dev, int level, /* * Compute watermark values of WM[1-3], */ -static bool sandybridge_compute_srwm(struct drm_device *dev, int level, - int hdisplay, int htotal, int pixel_size, - int clock, int latency_ns, int *fbc_wm, - int *display_wm, int *cursor_wm) +static bool ironlake_compute_srwm(struct drm_device *dev, int level, + int hdisplay, int htotal, + int pixel_size, int clock, int latency_ns, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor, + int *fbc_wm, int *display_wm, int *cursor_wm) { unsigned long line_time_us; + int line_count, line_size; int small, large; int entries; - int line_count, line_size; if (!latency_ns) { *fbc_wm = *display_wm = *cursor_wm = 0; @@ -3626,24 +3532,110 @@ static bool sandybridge_compute_srwm(struct drm_device *dev, int level, small = ((clock * pixel_size / 1000) * latency_ns) / 1000; large = line_count * line_size; - entries = DIV_ROUND_UP(min(small, large), - sandybridge_display_srwm_info.cacheline_size); - *display_wm = entries + sandybridge_display_srwm_info.guard_size; + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *display_wm = entries + display->guard_size; /* - * Spec said: + * Spec says: * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 */ *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; /* calculate the self-refresh watermark for display cursor */ entries = line_count * pixel_size * 64; - entries = DIV_ROUND_UP(entries, - sandybridge_cursor_srwm_info.cacheline_size); - *cursor_wm = entries + sandybridge_cursor_srwm_info.guard_size; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; - return sandybridge_check_srwm(dev, level, - *fbc_wm, *display_wm, *cursor_wm); + return ironlake_check_srwm(dev, level, + *fbc_wm, *display_wm, *cursor_wm, + display, cursor); +} + +static void ironlake_update_wm(struct drm_device *dev, + int planea_clock, int planeb_clock, + int hdisplay, int htotal, + int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int fbc_wm, plane_wm, cursor_wm, enabled; + int clock; + + enabled = 0; + if (ironlake_compute_wm0(dev, 0, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEA_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled++; + } + + if (ironlake_compute_wm0(dev, 1, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEB_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled++; + } + + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (enabled != 1) + return; + + clock = planea_clock ? planea_clock : planeb_clock; + + /* WM1 */ + if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, + clock, ILK_READ_WM1_LATENCY() * 500, + &ironlake_display_srwm_info, + &ironlake_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!ironlake_compute_srwm(dev, 2, hdisplay, htotal, pixel_size, + clock, ILK_READ_WM2_LATENCY() * 500, + &ironlake_display_srwm_info, + &ironlake_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* + * WM3 is unsupported on ILK, probably because we don't have latency + * data for that power state + */ } static void sandybridge_update_wm(struct drm_device *dev, @@ -3701,9 +3693,11 @@ static void sandybridge_update_wm(struct drm_device *dev, clock = planea_clock ? planea_clock : planeb_clock; /* WM1 */ - if (!sandybridge_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, - clock, SNB_READ_WM1_LATENCY() * 500, - &fbc_wm, &plane_wm, &cursor_wm)) + if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, + clock, SNB_READ_WM1_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) return; I915_WRITE(WM1_LP_ILK, @@ -3714,10 +3708,12 @@ static void sandybridge_update_wm(struct drm_device *dev, cursor_wm); /* WM2 */ - if (!sandybridge_compute_srwm(dev, 2, - hdisplay, htotal, pixel_size, - clock, SNB_READ_WM2_LATENCY() * 500, - &fbc_wm, &plane_wm, &cursor_wm)) + if (!ironlake_compute_srwm(dev, 2, + hdisplay, htotal, pixel_size, + clock, SNB_READ_WM2_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) return; I915_WRITE(WM2_LP_ILK, @@ -3728,10 +3724,12 @@ static void sandybridge_update_wm(struct drm_device *dev, cursor_wm); /* WM3 */ - if (!sandybridge_compute_srwm(dev, 3, - hdisplay, htotal, pixel_size, - clock, SNB_READ_WM3_LATENCY() * 500, - &fbc_wm, &plane_wm, &cursor_wm)) + if (!ironlake_compute_srwm(dev, 3, + hdisplay, htotal, pixel_size, + clock, SNB_READ_WM3_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) return; I915_WRITE(WM3_LP_ILK, -- cgit v1.2.3 From a0fa62d3b6afaa260cad8ccd6944e81ad01c7cf3 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Thu, 23 Dec 2010 16:35:40 +0800 Subject: drm/i915: fix the wrong latency value while computing wm0 On Ironlake, the LP0 latency is hardcoded and in ns unit, while on Sandybridge, it comes from a register and with unit 0.1 us. So, fix the wrong latency value while computing wm0 on Ironlake and Sandybridge. Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 79753b8ac797..75c433e6f457 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3418,9 +3418,9 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, static bool ironlake_compute_wm0(struct drm_device *dev, int pipe, const struct intel_watermark_params *display, - int display_latency, + int display_latency_ns, const struct intel_watermark_params *cursor, - int cursor_latency, + int cursor_latency_ns, int *plane_wm, int *cursor_wm) { @@ -3438,7 +3438,7 @@ static bool ironlake_compute_wm0(struct drm_device *dev, pixel_size = crtc->fb->bits_per_pixel / 8; /* Use the small buffer method to calculate plane watermark */ - entries = ((clock * pixel_size / 1000) * display_latency * 100) / 1000; + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; entries = DIV_ROUND_UP(entries, display->cacheline_size); *plane_wm = entries + display->guard_size; if (*plane_wm > (int)display->max_wm) @@ -3446,7 +3446,7 @@ static bool ironlake_compute_wm0(struct drm_device *dev, /* Use the large buffer method to calculate cursor watermark */ line_time_us = ((htotal * 1000) / clock); - line_count = (cursor_latency * 100 / line_time_us + 1000) / 1000; + line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; entries = line_count * 64 * pixel_size; entries = DIV_ROUND_UP(entries, cursor->cacheline_size); *cursor_wm = entries + cursor->guard_size; @@ -3644,7 +3644,7 @@ static void sandybridge_update_wm(struct drm_device *dev, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; - int latency = SNB_READ_WM0_LATENCY(); + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ int fbc_wm, plane_wm, cursor_wm, enabled; int clock; -- cgit v1.2.3 From d78cb50baa9177353d6719612b83558a9bf2d59b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Dec 2010 13:33:15 +0000 Subject: drm/i915: add 'reset' parameter When bringing up new hardware, or otherwise experimenting, GPU hangs are a way of life. However, the automatic GPU reset can do more harm than good under these circumstances, as we may wish to capture a full trace for debugging. Based on a patch by Zhenyu Wang. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 872493331988..2913496e8716 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,6 +49,9 @@ module_param_named(powersave, i915_powersave, int, 0600); unsigned int i915_lvds_downclock = 0; module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); +bool i915_try_reset = true; +module_param_named(reset, i915_try_reset, bool, 0600); + static struct drm_driver driver; extern int intel_agp_enabled; @@ -475,6 +478,9 @@ int i915_reset(struct drm_device *dev, u8 flags) bool need_display = true; int ret; + if (!i915_try_reset) + return 0; + if (!mutex_trylock(&dev->struct_mutex)) return -EBUSY; -- cgit v1.2.3 From dbdc647927a0f4b34e7cf486889d8f671f73d2e5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 30 Dec 2010 09:36:39 -0800 Subject: drm/i915: avoid reading non-existent PLL reg on Ironlake+ These functions need to be reworked for Ironlake and above, but until then at least avoid reading non-existent registers. Signed-off-by: Jesse Barnes [ickle: combine with a gratuitous tidy] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 75c433e6f457..043825c9ddcf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5036,8 +5036,8 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; - int dpll = I915_READ(dpll_reg); + int dpll_reg = DPLL(pipe); + int dpll; if (HAS_PCH_SPLIT(dev)) return; @@ -5045,17 +5045,19 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) if (!dev_priv->lvds_downclock_avail) return; + dpll = I915_READ(dpll_reg); if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) { DRM_DEBUG_DRIVER("upclocking LVDS\n"); /* Unlock panel regs */ - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | - PANEL_UNLOCK_REGS); + I915_WRITE(PP_CONTROL, + I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); dpll &= ~DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); - dpll = I915_READ(dpll_reg); + POSTING_READ(dpll_reg); intel_wait_for_vblank(dev, pipe); + dpll = I915_READ(dpll_reg); if (dpll & DISPLAY_RATE_SELECT_FPA1) DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); -- cgit v1.2.3 From 759010728b1323aec03c5baae13fde8f76e44a99 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Jan 2011 16:39:21 +0000 Subject: drm/i915: Remove impossible test As has_gem is unconditionally set to true, the conditional immediately following that assignment is superfluous. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0568dbdc10ef..844f3c972b04 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1962,13 +1962,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* enable GEM by default */ dev_priv->has_gem = 1; - if (dev_priv->has_gem == 0 && - drm_core_check_feature(dev, DRIVER_MODESET)) { - DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n"); - ret = -ENODEV; - goto out_workqueue_free; - } - dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { @@ -2055,7 +2048,6 @@ out_gem_unload: intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); -out_workqueue_free: destroy_workqueue(dev_priv->wq); out_iomapfree: io_mapping_free(dev_priv->mm.gtt_mapping); -- cgit v1.2.3 From 63256ec5347fb2344a42adbae732b90603c92f35 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jan 2011 18:42:07 +0000 Subject: drm/i915: Enforce write ordering through the GTT We need to ensure that writes through the GTT land before any modification to the MMIO registers and so must impose a mandatory write barrier when flushing the GTT domain. This was revealed by relaxing the write ordering by experimentally mapping the registers and the GATT as write-combining. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 14 +++++++++++++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c79c0b62ef60..f9c093c08d58 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2393,6 +2393,12 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, obj->last_fenced_ring = NULL; } + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) + mb(); + return 0; } @@ -2833,10 +2839,16 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) if (obj->base.write_domain != I915_GEM_DOMAIN_GTT) return; - /* No actual flushing is required for the GTT write domain. Writes + /* No actual flushing is required for the GTT write domain. Writes * to it immediately go to main memory as far as we know, so there's * no chipset flush. It also doesn't land in render cache. + * + * However, we do have to enforce the order so that all writes through + * the GTT land before any writes to the device, such as updates to + * the GATT itself. */ + wmb(); + i915_gem_release_mmap(obj); old_write_domain = obj->base.write_domain; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 61129e6759eb..0d42de42868c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -725,6 +725,9 @@ i915_gem_execbuffer_flush(struct drm_device *dev, if (flush_domains & I915_GEM_DOMAIN_CPU) intel_gtt_chipset_flush(); + if (flush_domains & I915_GEM_DOMAIN_GTT) + wmb(); + if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { for (i = 0; i < I915_NUM_RINGS; i++) if (flush_rings & (1 << i)) -- cgit v1.2.3 From b72f3acb71646de073abdc070fe1108866c96634 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jan 2011 17:34:02 +0000 Subject: drm/i915: Handle ringbuffer stalls when flushing Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 4 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 +++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 86 ++++++++++++++++++------------ drivers/gpu/drm/i915/intel_ringbuffer.h | 6 +-- 4 files changed, 65 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f9c093c08d58..07b62449b9e1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2148,8 +2148,8 @@ i915_gem_flush_ring(struct drm_device *dev, uint32_t invalidate_domains, uint32_t flush_domains) { - ring->flush(ring, invalidate_domains, flush_domains); - i915_gem_process_flushing_list(dev, flush_domains, ring); + if (ring->flush(ring, invalidate_domains, flush_domains) == 0) + i915_gem_process_flushing_list(dev, flush_domains, ring); } static int i915_ring_idle(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 0d42de42868c..1b78b66dd77e 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -924,7 +924,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) { struct drm_i915_gem_request *request; - u32 flush_domains; + u32 invalidate; /* * Ensure that the commands in the batch buffer are @@ -932,11 +932,13 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, * * The sampler always gets flushed on i965 (sigh). */ - flush_domains = 0; + invalidate = I915_GEM_DOMAIN_COMMAND; if (INTEL_INFO(dev)->gen >= 4) - flush_domains |= I915_GEM_DOMAIN_SAMPLER; - - ring->flush(ring, I915_GEM_DOMAIN_COMMAND, flush_domains); + invalidate |= I915_GEM_DOMAIN_SAMPLER; + if (ring->flush(ring, invalidate, 0)) { + i915_gem_next_request_seqno(dev, ring); + return; + } /* Add a breadcrumb for the completion of the batch buffer */ request = kzalloc(sizeof(*request), GFP_KERNEL); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2de0e45464c5..aa8f6abf16f2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -48,7 +48,7 @@ static u32 i915_gem_get_seqno(struct drm_device *dev) return seqno; } -static void +static int render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) @@ -56,6 +56,7 @@ render_ring_flush(struct intel_ring_buffer *ring, struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 cmd; + int ret; #if WATCH_EXEC DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, @@ -116,12 +117,16 @@ render_ring_flush(struct intel_ring_buffer *ring, #if WATCH_EXEC DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); #endif - if (intel_ring_begin(ring, 2) == 0) { - intel_ring_emit(ring, cmd); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); } + + return 0; } static void ring_write_tail(struct intel_ring_buffer *ring, @@ -534,19 +539,24 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) POSTING_READ(mmio); } -static void +static int bsd_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + int ret; + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) - return; + return 0; - if (intel_ring_begin(ring, 2) == 0) { - intel_ring_emit(ring, MI_FLUSH); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, MI_FLUSH); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + return 0; } static int @@ -980,20 +990,25 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE); } -static void gen6_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) +static int gen6_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { + int ret; + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) - return; + return 0; - if (intel_ring_begin(ring, 4) == 0) { - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); - } + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; + + intel_ring_emit(ring, MI_FLUSH_DW); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + return 0; } static int @@ -1122,20 +1137,25 @@ static int blt_ring_begin(struct intel_ring_buffer *ring, return intel_ring_begin(ring, 4); } -static void blt_ring_flush(struct intel_ring_buffer *ring, +static int blt_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + int ret; + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) - return; + return 0; - if (blt_ring_begin(ring, 4) == 0) { - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_emit(ring, 0); - intel_ring_advance(ring); - } + ret = blt_ring_begin(ring, 4); + if (ret) + return ret; + + intel_ring_emit(ring, MI_FLUSH_DW); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); + return 0; } static void blt_ring_cleanup(struct intel_ring_buffer *ring) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index bbbf505c8b56..5969c2ed1028 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -63,9 +63,9 @@ struct intel_ring_buffer { void (*write_tail)(struct intel_ring_buffer *ring, u32 value); - void (*flush)(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains); + int __must_check (*flush)(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains); int (*add_request)(struct intel_ring_buffer *ring, u32 *seqno); u32 (*get_seqno)(struct intel_ring_buffer *ring); -- cgit v1.2.3 From 0f46832fab779a9a3314ce5e833155fe4cf18f6c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jan 2011 17:35:21 +0000 Subject: drm/i915: Mask USER interrupts on gen6 (until required) Otherwise we may consume 20% of the CPU just handling IRQs whilst rendering. Ouch. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 6 -- drivers/gpu/drm/i915/i915_irq.c | 45 ------------ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 120 +++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 + 5 files changed, 113 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 972e08e4e054..1f77d8c6c6a2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1007,12 +1007,6 @@ extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); -extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask); -extern void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, - u32 mask); -extern void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, - u32 mask); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0dadc025b77b..826873a23db0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -64,26 +64,6 @@ #define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ DRM_I915_VBLANK_PIPE_B) -void -ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - if ((dev_priv->gt_irq_mask & mask) != 0) { - dev_priv->gt_irq_mask &= ~mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - POSTING_READ(GTIMR); - } -} - -void -ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - if ((dev_priv->gt_irq_mask & mask) != mask) { - dev_priv->gt_irq_mask |= mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - POSTING_READ(GTIMR); - } -} - /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) @@ -105,26 +85,6 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) } } -void -i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - if ((dev_priv->irq_mask & mask) != 0) { - dev_priv->irq_mask &= ~mask; - I915_WRITE(IMR, dev_priv->irq_mask); - POSTING_READ(IMR); - } -} - -void -i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - if ((dev_priv->irq_mask & mask) != mask) { - dev_priv->irq_mask |= mask; - I915_WRITE(IMR, dev_priv->irq_mask); - POSTING_READ(IMR); - } -} - static inline u32 i915_pipestat(int pipe) { @@ -1673,11 +1633,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - if (IS_GEN6(dev)) { - I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_USER_INTERRUPT); - I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_USER_INTERRUPT); - I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT); - } if (IS_GEN6(dev)) render_irqs = diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ecfb0023f60d..b0ab4247ce48 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -288,6 +288,7 @@ #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) #define RING_ACTHD(base) ((base)+0x74) #define RING_NOPID(base) ((base)+0x94) +#define RING_IMR(base) ((base)+0xa8) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index aa8f6abf16f2..3bff7fb72341 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -485,6 +485,38 @@ pc_render_get_seqno(struct intel_ring_buffer *ring) return pc->cpu_page[0]; } +static void +ironlake_enable_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + dev_priv->gt_irq_mask &= ~mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); +} + +static void +ironlake_disable_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + dev_priv->gt_irq_mask |= mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); +} + +static void +i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + dev_priv->irq_mask &= ~mask; + I915_WRITE(IMR, dev_priv->irq_mask); + POSTING_READ(IMR); +} + +static void +i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + dev_priv->irq_mask |= mask; + I915_WRITE(IMR, dev_priv->irq_mask); + POSTING_READ(IMR); +} + static bool render_ring_get_irq(struct intel_ring_buffer *ring) { @@ -499,8 +531,8 @@ render_ring_get_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) - ironlake_enable_graphics_irq(dev_priv, - GT_PIPE_NOTIFY | GT_USER_INTERRUPT); + ironlake_enable_irq(dev_priv, + GT_PIPE_NOTIFY | GT_USER_INTERRUPT); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -520,9 +552,9 @@ render_ring_put_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (HAS_PCH_SPLIT(dev)) - ironlake_disable_graphics_irq(dev_priv, - GT_USER_INTERRUPT | - GT_PIPE_NOTIFY); + ironlake_disable_irq(dev_priv, + GT_USER_INTERRUPT | + GT_PIPE_NOTIFY); else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -596,7 +628,7 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag) unsigned long irqflags; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - ironlake_enable_graphics_irq(dev_priv, flag); + ironlake_enable_irq(dev_priv, flag); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } @@ -613,7 +645,46 @@ ring_put_irq(struct intel_ring_buffer *ring, u32 flag) unsigned long irqflags; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - ironlake_disable_graphics_irq(dev_priv, flag); + ironlake_disable_irq(dev_priv, flag); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } +} + +static bool +gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) +{ + struct drm_device *dev = ring->dev; + + if (!dev->irq_enabled) + return false; + + if (atomic_inc_return(&ring->irq_refcount) == 1) { + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ring->irq_mask &= ~rflag; + I915_WRITE_IMR(ring, ring->irq_mask); + ironlake_enable_irq(dev_priv, gflag); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } + + return true; +} + +static void +gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) +{ + struct drm_device *dev = ring->dev; + + if (atomic_dec_and_test(&ring->irq_refcount)) { + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + ring->irq_mask |= rflag; + I915_WRITE_IMR(ring, ring->irq_mask); + ironlake_disable_irq(dev_priv, gflag); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } } @@ -757,6 +828,7 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); + ring->irq_mask = ~0; if (I915_NEED_GFX_HWS(dev)) { ret = init_status_page(ring); @@ -1029,16 +1101,36 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, return 0; } +static bool +gen6_render_ring_get_irq(struct intel_ring_buffer *ring) +{ + return gen6_ring_get_irq(ring, + GT_USER_INTERRUPT, + GEN6_RENDER_USER_INTERRUPT); +} + +static void +gen6_render_ring_put_irq(struct intel_ring_buffer *ring) +{ + return gen6_ring_put_irq(ring, + GT_USER_INTERRUPT, + GEN6_RENDER_USER_INTERRUPT); +} + static bool gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring) { - return ring_get_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); + return gen6_ring_get_irq(ring, + GT_GEN6_BSD_USER_INTERRUPT, + GEN6_BSD_USER_INTERRUPT); } static void gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) { - ring_put_irq(ring, GT_GEN6_BSD_USER_INTERRUPT); + return gen6_ring_put_irq(ring, + GT_GEN6_BSD_USER_INTERRUPT, + GEN6_BSD_USER_INTERRUPT); } /* ring buffer for Video Codec for Gen6+ */ @@ -1062,13 +1154,17 @@ static const struct intel_ring_buffer gen6_bsd_ring = { static bool blt_ring_get_irq(struct intel_ring_buffer *ring) { - return ring_get_irq(ring, GT_BLT_USER_INTERRUPT); + return gen6_ring_get_irq(ring, + GT_BLT_USER_INTERRUPT, + GEN6_BLITTER_USER_INTERRUPT); } static void blt_ring_put_irq(struct intel_ring_buffer *ring) { - ring_put_irq(ring, GT_BLT_USER_INTERRUPT); + gen6_ring_put_irq(ring, + GT_BLT_USER_INTERRUPT, + GEN6_BLITTER_USER_INTERRUPT); } @@ -1192,6 +1288,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev) *ring = render_ring; if (INTEL_INFO(dev)->gen >= 6) { ring->add_request = gen6_add_request; + ring->irq_get = gen6_render_ring_get_irq; + ring->irq_put = gen6_render_ring_put_irq; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; ring->get_seqno = pc_render_get_seqno; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 5969c2ed1028..634f6f84cb57 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -28,6 +28,8 @@ struct intel_hw_status_page { #define I915_READ_CTL(ring) I915_RING_READ(RING_CTL(ring->mmio_base)) #define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val) +#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR(ring->mmio_base), val) + #define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID(ring->mmio_base)) #define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0(ring->mmio_base)) #define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1(ring->mmio_base)) @@ -52,6 +54,7 @@ struct intel_ring_buffer { int effective_size; struct intel_hw_status_page status_page; + u32 irq_mask; u32 irq_seqno; /* last seq seem at irq time */ u32 waiting_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; -- cgit v1.2.3 From 9862e600cef87de0e301bad7d1435b87e03ea84d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jan 2011 22:22:17 +0000 Subject: drm/i915/debugfs: Show the per-ring IMR Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 8 +++++++- drivers/gpu/drm/i915/i915_irq.c | 5 ++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 25 +++++++++++++------------ 3 files changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 92f75782c332..7243d6418651 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -456,8 +456,14 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } seq_printf(m, "Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - for (i = 0; i < I915_NUM_RINGS; i++) + for (i = 0; i < I915_NUM_RINGS; i++) { + if (IS_GEN6(dev)) { + seq_printf(m, "Graphics Interrupt mask (%s): %08x\n", + dev_priv->ring[i].name, + I915_READ_IMR(&dev_priv->ring[i])); + } i915_ring_seqno_info(m, &dev_priv->ring[i]); + } mutex_unlock(&dev->struct_mutex); return 0; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 826873a23db0..c9adcdd6ad6a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -349,9 +349,12 @@ static void notify_ring(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; u32 seqno = ring->get_seqno(ring); - ring->irq_seqno = seqno; + trace_i915_gem_request_complete(dev, seqno); + + ring->irq_seqno = seqno; wake_up_all(&ring->irq_queue); + dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 634f6f84cb57..9b134b8643cb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -16,23 +16,24 @@ struct intel_hw_status_page { #define I915_RING_READ(reg) i915_safe_read(dev_priv, reg) -#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL(ring->mmio_base)) -#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val) +#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base)) +#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val) -#define I915_READ_START(ring) I915_RING_READ(RING_START(ring->mmio_base)) -#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val) +#define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base)) +#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val) -#define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD(ring->mmio_base)) -#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val) +#define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD((ring)->mmio_base)) +#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val) -#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL(ring->mmio_base)) -#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val) +#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base)) +#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val) -#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR(ring->mmio_base), val) +#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val) +#define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base)) -#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID(ring->mmio_base)) -#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0(ring->mmio_base)) -#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1(ring->mmio_base)) +#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base)) +#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base)) +#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1((ring)->mmio_base)) struct intel_ring_buffer { const char *name; -- cgit v1.2.3 From 01a03331e5fe91861937f8b8e72c259f5e9eae67 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jan 2011 22:22:56 +0000 Subject: drm/i915/ringbuffer: Simplify the ring irq refcounting ... and move it under the spinlock to gain the appropriate memory barriers. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32752 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 62 +++++++++++++-------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 2 files changed, 25 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3bff7fb72341..13cad981713b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -521,22 +521,20 @@ static bool render_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; if (!dev->irq_enabled) return false; - if (atomic_inc_return(&ring->irq_refcount) == 1) { - drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); + if (ring->irq_refcount++ == 0) { if (HAS_PCH_SPLIT(dev)) ironlake_enable_irq(dev_priv, GT_PIPE_NOTIFY | GT_USER_INTERRUPT); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } + spin_unlock(&dev_priv->irq_lock); return true; } @@ -545,20 +543,18 @@ static void render_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; - if (atomic_dec_and_test(&ring->irq_refcount)) { - drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); + if (--ring->irq_refcount == 0) { if (HAS_PCH_SPLIT(dev)) ironlake_disable_irq(dev_priv, GT_USER_INTERRUPT | GT_PIPE_NOTIFY); else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } + spin_unlock(&dev_priv->irq_lock); } void intel_ring_setup_status_page(struct intel_ring_buffer *ring) @@ -619,18 +615,15 @@ static bool ring_get_irq(struct intel_ring_buffer *ring, u32 flag) { struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; if (!dev->irq_enabled) return false; - if (atomic_inc_return(&ring->irq_refcount) == 1) { - drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); + if (ring->irq_refcount++ == 0) ironlake_enable_irq(dev_priv, flag); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } + spin_unlock(&dev_priv->irq_lock); return true; } @@ -639,35 +632,30 @@ static void ring_put_irq(struct intel_ring_buffer *ring, u32 flag) { struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; - if (atomic_dec_and_test(&ring->irq_refcount)) { - drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); + if (--ring->irq_refcount == 0) ironlake_disable_irq(dev_priv, flag); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } + spin_unlock(&dev_priv->irq_lock); } static bool gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) { struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; if (!dev->irq_enabled) return false; - if (atomic_inc_return(&ring->irq_refcount) == 1) { - drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); + if (ring->irq_refcount++ == 0) { ring->irq_mask &= ~rflag; I915_WRITE_IMR(ring, ring->irq_mask); ironlake_enable_irq(dev_priv, gflag); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } + spin_unlock(&dev_priv->irq_lock); return true; } @@ -676,17 +664,15 @@ static void gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) { struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; - if (atomic_dec_and_test(&ring->irq_refcount)) { - drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + spin_lock(&dev_priv->irq_lock); + if (--ring->irq_refcount == 0) { ring->irq_mask |= rflag; I915_WRITE_IMR(ring, ring->irq_mask); ironlake_disable_irq(dev_priv, gflag); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } + spin_unlock(&dev_priv->irq_lock); } static bool diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9b134b8643cb..6b1d9a5a7d07 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -55,11 +55,11 @@ struct intel_ring_buffer { int effective_size; struct intel_hw_status_page status_page; + u32 irq_refcount; u32 irq_mask; u32 irq_seqno; /* last seq seem at irq time */ u32 waiting_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; - atomic_t irq_refcount; bool __must_check (*irq_get)(struct intel_ring_buffer *ring); void (*irq_put)(struct intel_ring_buffer *ring); -- cgit v1.2.3 From 0dc79fb2a36efcadbb39bd8b28933d8aa40408b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Jan 2011 10:32:24 +0000 Subject: drm/i915: Make the ring IMR handling private As the IMR for the USER interrupts are not modified elsewhere, we can separate the spinlock used for these from that of hpd and pipestats. Those two IMR are manipulated under an IRQ and so need heavier locking. Reported-and-tested-by: Alexey Fisher Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_ringbuffer.c | 26 ++++++++++++++------------ drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 13cad981713b..03e337072517 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -526,7 +526,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring) if (!dev->irq_enabled) return false; - spin_lock(&dev_priv->irq_lock); + spin_lock(&ring->irq_lock); if (ring->irq_refcount++ == 0) { if (HAS_PCH_SPLIT(dev)) ironlake_enable_irq(dev_priv, @@ -534,7 +534,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring) else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); } - spin_unlock(&dev_priv->irq_lock); + spin_unlock(&ring->irq_lock); return true; } @@ -545,7 +545,7 @@ render_ring_put_irq(struct intel_ring_buffer *ring) struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - spin_lock(&dev_priv->irq_lock); + spin_lock(&ring->irq_lock); if (--ring->irq_refcount == 0) { if (HAS_PCH_SPLIT(dev)) ironlake_disable_irq(dev_priv, @@ -554,7 +554,7 @@ render_ring_put_irq(struct intel_ring_buffer *ring) else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); } - spin_unlock(&dev_priv->irq_lock); + spin_unlock(&ring->irq_lock); } void intel_ring_setup_status_page(struct intel_ring_buffer *ring) @@ -620,10 +620,10 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag) if (!dev->irq_enabled) return false; - spin_lock(&dev_priv->irq_lock); + spin_lock(&ring->irq_lock); if (ring->irq_refcount++ == 0) ironlake_enable_irq(dev_priv, flag); - spin_unlock(&dev_priv->irq_lock); + spin_unlock(&ring->irq_lock); return true; } @@ -634,10 +634,10 @@ ring_put_irq(struct intel_ring_buffer *ring, u32 flag) struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - spin_lock(&dev_priv->irq_lock); + spin_lock(&ring->irq_lock); if (--ring->irq_refcount == 0) ironlake_disable_irq(dev_priv, flag); - spin_unlock(&dev_priv->irq_lock); + spin_unlock(&ring->irq_lock); } static bool @@ -649,13 +649,13 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) if (!dev->irq_enabled) return false; - spin_lock(&dev_priv->irq_lock); + spin_lock(&ring->irq_lock); if (ring->irq_refcount++ == 0) { ring->irq_mask &= ~rflag; I915_WRITE_IMR(ring, ring->irq_mask); ironlake_enable_irq(dev_priv, gflag); } - spin_unlock(&dev_priv->irq_lock); + spin_unlock(&ring->irq_lock); return true; } @@ -666,13 +666,13 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - spin_lock(&dev_priv->irq_lock); + spin_lock(&ring->irq_lock); if (--ring->irq_refcount == 0) { ring->irq_mask |= rflag; I915_WRITE_IMR(ring, ring->irq_mask); ironlake_disable_irq(dev_priv, gflag); } - spin_unlock(&dev_priv->irq_lock); + spin_unlock(&ring->irq_lock); } static bool @@ -814,6 +814,8 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); + + spin_lock_init(&ring->irq_lock); ring->irq_mask = ~0; if (I915_NEED_GFX_HWS(dev)) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 6b1d9a5a7d07..be9087e4c9be 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -55,6 +55,7 @@ struct intel_ring_buffer { int effective_size; struct intel_hw_status_page status_page; + spinlock_t irq_lock; u32 irq_refcount; u32 irq_mask; u32 irq_seqno; /* last seq seem at irq time */ -- cgit v1.2.3 From 88271da3f3da75d6eaef5e768c82a1627edf7088 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 5 Jan 2011 12:01:24 -0800 Subject: drm/i915: re-enable rc6 support for Ironlake+ Re-enable rc6 support on Ironlake for power savings. Adds a debugfs file to check current RC state, adds a missing workaround for Ironlake MI_SET_CONTEXT instructions, and renames MCHBAR_RENDER_STANDBY to RSTDBYCTL to match the docs. Keep RC6 and the power context disabled on pre-ILK. It only seems to hang and doesn't save any power. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 26 ++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 50 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/i915_suspend.c | 4 +-- drivers/gpu/drm/i915/intel_display.c | 32 ++++++++++++----------- 4 files changed, 91 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7243d6418651..9c4cdc143be9 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -896,7 +896,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 rgvmodectl = I915_READ(MEMMODECTL); - u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY); + u32 rstdbyctl = I915_READ(RSTDBYCTL); u16 crstandvid = I915_READ16(CRSTANDVID); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? @@ -919,6 +919,30 @@ static int i915_drpc_info(struct seq_file *m, void *unused) seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); seq_printf(m, "Render standby enabled: %s\n", (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes"); + seq_printf(m, "Current RS state: "); + switch (rstdbyctl & RSX_STATUS_MASK) { + case RSX_STATUS_ON: + seq_printf(m, "on\n"); + break; + case RSX_STATUS_RC1: + seq_printf(m, "RC1\n"); + break; + case RSX_STATUS_RC1E: + seq_printf(m, "RC1E\n"); + break; + case RSX_STATUS_RS1: + seq_printf(m, "RS1\n"); + break; + case RSX_STATUS_RS2: + seq_printf(m, "RS2 (RC6)\n"); + break; + case RSX_STATUS_RS3: + seq_printf(m, "RC3 (RC6+)\n"); + break; + default: + seq_printf(m, "unknown\n"); + break; + } return 0; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b0ab4247ce48..33ddf3120f2f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -145,6 +145,8 @@ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ #define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) +#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) +#define MI_SUSPEND_FLUSH_EN (1<<0) #define MI_REPORT_HEAD MI_INSTR(0x07, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11,0) #define MI_OVERLAY_CONTINUE (0x0<<21) @@ -159,6 +161,7 @@ #define MI_MM_SPACE_PHYSICAL (0<<8) #define MI_SAVE_EXT_STATE_EN (1<<3) #define MI_RESTORE_EXT_STATE_EN (1<<2) +#define MI_FORCE_RESTORE (1<<1) #define MI_RESTORE_INHIBIT (1<<0) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ @@ -1131,9 +1134,50 @@ #define RCBMINAVG 0x111a0 #define RCUPEI 0x111b0 #define RCDNEI 0x111b4 -#define MCHBAR_RENDER_STANDBY 0x111b8 -#define RCX_SW_EXIT (1<<23) -#define RSX_STATUS_MASK 0x00700000 +#define RSTDBYCTL 0x111b8 +#define RS1EN (1<<31) +#define RS2EN (1<<30) +#define RS3EN (1<<29) +#define D3RS3EN (1<<28) /* Display D3 imlies RS3 */ +#define SWPROMORSX (1<<27) /* RSx promotion timers ignored */ +#define RCWAKERW (1<<26) /* Resetwarn from PCH causes wakeup */ +#define DPRSLPVREN (1<<25) /* Fast voltage ramp enable */ +#define GFXTGHYST (1<<24) /* Hysteresis to allow trunk gating */ +#define RCX_SW_EXIT (1<<23) /* Leave RSx and prevent re-entry */ +#define RSX_STATUS_MASK (7<<20) +#define RSX_STATUS_ON (0<<20) +#define RSX_STATUS_RC1 (1<<20) +#define RSX_STATUS_RC1E (2<<20) +#define RSX_STATUS_RS1 (3<<20) +#define RSX_STATUS_RS2 (4<<20) /* aka rc6 */ +#define RSX_STATUS_RSVD (5<<20) /* deep rc6 unsupported on ilk */ +#define RSX_STATUS_RS3 (6<<20) /* rs3 unsupported on ilk */ +#define RSX_STATUS_RSVD2 (7<<20) +#define UWRCRSXE (1<<19) /* wake counter limit prevents rsx */ +#define RSCRP (1<<18) /* rs requests control on rs1/2 reqs */ +#define JRSC (1<<17) /* rsx coupled to cpu c-state */ +#define RS2INC0 (1<<16) /* allow rs2 in cpu c0 */ +#define RS1CONTSAV_MASK (3<<14) +#define RS1CONTSAV_NO_RS1 (0<<14) /* rs1 doesn't save/restore context */ +#define RS1CONTSAV_RSVD (1<<14) +#define RS1CONTSAV_SAVE_RS1 (2<<14) /* rs1 saves context */ +#define RS1CONTSAV_FULL_RS1 (3<<14) /* rs1 saves and restores context */ +#define NORMSLEXLAT_MASK (3<<12) +#define SLOW_RS123 (0<<12) +#define SLOW_RS23 (1<<12) +#define SLOW_RS3 (2<<12) +#define NORMAL_RS123 (3<<12) +#define RCMODE_TIMEOUT (1<<11) /* 0 is eval interval method */ +#define IMPROMOEN (1<<10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */ +#define RCENTSYNC (1<<9) /* rs coupled to cpu c-state (3/6/7) */ +#define STATELOCK (1<<7) /* locked to rs_cstate if 0 */ +#define RS_CSTATE_MASK (3<<4) +#define RS_CSTATE_C367_RS1 (0<<4) +#define RS_CSTATE_C36_RS1_C7_RS2 (1<<4) +#define RS_CSTATE_RSVD (2<<4) +#define RS_CSTATE_C367_RS2 (3<<4) +#define REDSAVES (1<<3) /* no context save if was idle during rs0 */ +#define REDRESTORES (1<<2) /* no restore if was idle during rs0 */ #define VIDCTL 0x111c0 #define VIDSTS 0x111c8 #define VIDSTART 0x111cc /* 8 bits */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 410772466fa7..af530637777a 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -740,7 +740,7 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL); - I915_WRITE(MCHBAR_RENDER_STANDBY, + I915_WRITE(RSTDBYCTL, dev_priv->saveMCHBAR_RENDER_STANDBY); } else { I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); @@ -811,7 +811,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR); dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR); dev_priv->saveMCHBAR_RENDER_STANDBY = - I915_READ(MCHBAR_RENDER_STANDBY); + I915_READ(RSTDBYCTL); } else { dev_priv->saveIER = I915_READ(IER); dev_priv->saveIMR = I915_READ(IMR); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 043825c9ddcf..f3c0525d5328 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6420,35 +6420,37 @@ void intel_enable_clock_gating(struct drm_device *dev) * GPU can automatically power down the render unit if given a page * to save state. */ - if (IS_IRONLAKE_M(dev) && 0) { /* XXX causes a failure during suspend */ + if (IS_IRONLAKE_M(dev)) { if (dev_priv->renderctx == NULL) dev_priv->renderctx = intel_alloc_context_page(dev); if (dev_priv->renderctx) { struct drm_i915_gem_object *obj = dev_priv->renderctx; - if (BEGIN_LP_RING(4) == 0) { - OUT_RING(MI_SET_CONTEXT); - OUT_RING(obj->gtt_offset | - MI_MM_SPACE_GTT | - MI_SAVE_EXT_STATE_EN | - MI_RESTORE_EXT_STATE_EN | - MI_RESTORE_INHIBIT); - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); - ADVANCE_LP_RING(); + if (BEGIN_LP_RING(6) != 0) { + i915_gem_object_unpin(obj); + drm_gem_object_unreference(&obj->base); + dev_priv->renderctx = NULL; + return; } + OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); + OUT_RING(MI_SET_CONTEXT); + OUT_RING(obj->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_SUSPEND_FLUSH); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); } else DRM_DEBUG_KMS("Failed to allocate render context." "Disable RC6\n"); - } - if (IS_GEN4(dev) && IS_MOBILE(dev)) { if (dev_priv->pwrctx == NULL) dev_priv->pwrctx = intel_alloc_context_page(dev); if (dev_priv->pwrctx) { struct drm_i915_gem_object *obj = dev_priv->pwrctx; I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN); - I915_WRITE(MCHBAR_RENDER_STANDBY, - I915_READ(MCHBAR_RENDER_STANDBY) & ~RCX_SW_EXIT); } } } -- cgit v1.2.3 From 1daed3fb8324d517a1f9da43f1a1d3619d1b0ddc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 5 Jan 2011 12:01:25 -0800 Subject: drm/i915: fix rc6 enabling around suspend/resume Enabling RC6 implies setting a graphics context. Make sure we do that only after the ring has been enabled, otherwise our ring commands will hang. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 3 +++ drivers/gpu/drm/i915/i915_suspend.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2913496e8716..02fce7fbcd8a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -357,6 +357,9 @@ static int i915_drm_thaw(struct drm_device *dev) drm_helper_resume_force_mode(dev); } + /* Clock gating state */ + intel_enable_clock_gating(dev); + intel_opregion_init(dev); dev_priv->modeset_on_lid = 0; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index af530637777a..147cd9666700 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -868,9 +868,6 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE (IMR, dev_priv->saveIMR); } - /* Clock gating state */ - intel_enable_clock_gating(dev); - if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); intel_init_emon(dev); -- cgit v1.2.3 From d5bb081b027b520f9e59b4fb8faea83a136ec15e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 5 Jan 2011 12:01:26 -0800 Subject: drm/i915: cleanup rc6 code Cleanup several aspects of the rc6 code: - misnamed intel_disable_clock_gating function (was only about rc6) - remove commented call to intel_disable_clock_gating - rc6 enabling code belongs in its own function (allows us to move the actual clock gating enable call back into restore_state) - allocate power & render contexts up front, only free on unload (avoids ugly lazy init at rc6 enable time) Signed-off-by: Jesse Barnes [ickle: checkpatch cleanup] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 6 +- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_suspend.c | 7 +-- drivers/gpu/drm/i915/intel_display.c | 107 ++++++++++++++++++++++------------- 4 files changed, 75 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 02fce7fbcd8a..0de75a23f8e7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -355,10 +355,10 @@ static int i915_drm_thaw(struct drm_device *dev) /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); - } - /* Clock gating state */ - intel_enable_clock_gating(dev); + if (dev_priv->renderctx && dev_priv->pwrctx) + ironlake_enable_rc6(dev); + } intel_opregion_init(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1f77d8c6c6a2..455260067ff7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1260,6 +1260,7 @@ extern void intel_disable_fbc(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern bool intel_fbc_enabled(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); +extern void ironlake_enable_rc6(struct drm_device *dev); extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 147cd9666700..0521ecf26017 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -822,10 +822,6 @@ int i915_save_state(struct drm_device *dev) if (IS_GEN6(dev)) gen6_disable_rps(dev); - /* XXX disabling the clock gating breaks suspend on gm45 - intel_disable_clock_gating(dev); - */ - /* Cache mode state */ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); @@ -868,6 +864,9 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE (IMR, dev_priv->saveIMR); } + /* Clock gating state */ + intel_enable_clock_gating(dev); + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); intel_init_emon(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f3c0525d5328..1190efa390bd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6415,44 +6415,6 @@ void intel_enable_clock_gating(struct drm_device *dev) } else if (IS_I830(dev)) { I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); } - - /* - * GPU can automatically power down the render unit if given a page - * to save state. - */ - if (IS_IRONLAKE_M(dev)) { - if (dev_priv->renderctx == NULL) - dev_priv->renderctx = intel_alloc_context_page(dev); - if (dev_priv->renderctx) { - struct drm_i915_gem_object *obj = dev_priv->renderctx; - if (BEGIN_LP_RING(6) != 0) { - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - dev_priv->renderctx = NULL; - return; - } - OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); - OUT_RING(MI_SET_CONTEXT); - OUT_RING(obj->gtt_offset | - MI_MM_SPACE_GTT | - MI_SAVE_EXT_STATE_EN | - MI_RESTORE_EXT_STATE_EN | - MI_RESTORE_INHIBIT); - OUT_RING(MI_SUSPEND_FLUSH); - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); - ADVANCE_LP_RING(); - } else - DRM_DEBUG_KMS("Failed to allocate render context." - "Disable RC6\n"); - - if (dev_priv->pwrctx == NULL) - dev_priv->pwrctx = intel_alloc_context_page(dev); - if (dev_priv->pwrctx) { - struct drm_i915_gem_object *obj = dev_priv->pwrctx; - I915_WRITE(PWRCTXA, obj->gtt_offset | PWRCTX_EN); - } - } } void intel_disable_clock_gating(struct drm_device *dev) @@ -6482,6 +6444,57 @@ void intel_disable_clock_gating(struct drm_device *dev) } } +static void ironlake_disable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); + wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), + 10); + POSTING_READ(CCID); + I915_WRITE(PWRCTXA, 0); + POSTING_READ(PWRCTXA); + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + POSTING_READ(RSTDBYCTL); + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(&dev_priv->renderctx->base); + dev_priv->renderctx = NULL; + i915_gem_object_unpin(dev_priv->pwrctx); + drm_gem_object_unreference(&dev_priv->pwrctx->base); + dev_priv->pwrctx = NULL; +} + +void ironlake_enable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + /* + * GPU can automatically power down the render unit if given a page + * to save state. + */ + ret = BEGIN_LP_RING(6); + if (ret) { + ironlake_disable_rc6(dev); + return; + } + OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); + OUT_RING(MI_SET_CONTEXT); + OUT_RING(dev_priv->renderctx->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_SUSPEND_FLUSH); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); + + I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); +} + /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) { @@ -6724,6 +6737,21 @@ void intel_modeset_init(struct drm_device *dev) if (IS_GEN6(dev)) gen6_enable_rps(dev_priv); + if (IS_IRONLAKE_M(dev)) { + dev_priv->renderctx = intel_alloc_context_page(dev); + if (!dev_priv->renderctx) + goto skip_rc6; + dev_priv->pwrctx = intel_alloc_context_page(dev); + if (!dev_priv->pwrctx) { + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(&dev_priv->renderctx->base); + dev_priv->renderctx = NULL; + goto skip_rc6; + } + ironlake_enable_rc6(dev); + } + +skip_rc6: INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); @@ -6760,7 +6788,8 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_GEN6(dev)) gen6_disable_rps(dev); - intel_disable_clock_gating(dev); + if (IS_IRONLAKE_M(dev)) + ironlake_disable_rc6(dev); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 776ad8062bb77697b8728a9794e3a394b28cf885 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 4 Jan 2011 15:09:39 -0800 Subject: drm/i915: detect & report PCH display error interrupts FDI and the transcoders can fail for various reasons, so detect those conditions and report on them. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 54 +++++++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_reg.h | 29 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c9adcdd6ad6a..d431fc4fb84b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -398,6 +398,50 @@ static void gen6_pm_irq_handler(struct drm_device *dev) I915_WRITE(GEN6_PMIIR, pm_iir); } +static void pch_irq_handler(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 pch_iir; + + pch_iir = I915_READ(SDEIIR); + + if (pch_iir & SDE_AUDIO_POWER_MASK) + DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", + (pch_iir & SDE_AUDIO_POWER_MASK) >> + SDE_AUDIO_POWER_SHIFT); + + if (pch_iir & SDE_GMBUS) + DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); + + if (pch_iir & SDE_AUDIO_HDCP_MASK) + DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); + + if (pch_iir & SDE_AUDIO_TRANS_MASK) + DRM_DEBUG_DRIVER("PCH transcoder audio interrupt\n"); + + if (pch_iir & SDE_POISON) + DRM_ERROR("PCH poison interrupt\n"); + + if (pch_iir & SDE_FDI_MASK) { + u32 fdia, fdib; + + fdia = I915_READ(FDI_RXA_IIR); + fdib = I915_READ(FDI_RXB_IIR); + DRM_DEBUG_DRIVER("PCH FDI RX interrupt; FDI RXA IIR: 0x%08x, FDI RXB IIR: 0x%08x\n", fdia, fdib); + } + + if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) + DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n"); + + if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) + DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n"); + + if (pch_iir & SDE_TRANSB_FIFO_UNDER) + DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n"); + if (pch_iir & SDE_TRANSA_FIFO_UNDER) + DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); +} + static irqreturn_t ironlake_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -465,8 +509,11 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) drm_handle_vblank(dev, 1); /* check event from PCH */ - if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask)) - queue_work(dev_priv->wq, &dev_priv->hotplug_work); + if (de_iir & DE_PCH_EVENT) { + if (pch_iir & hotplug_mask) + queue_work(dev_priv->wq, &dev_priv->hotplug_work); + pch_irq_handler(dev); + } if (de_iir & DE_PCU_EVENT) { I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); @@ -1656,6 +1703,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev) } else { hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; + hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK; + I915_WRITE(FDI_RXA_IMR, 0); + I915_WRITE(FDI_RXB_IMR, 0); } dev_priv->pch_irq_mask = ~hotplug_mask; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 33ddf3120f2f..40a407f41f61 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2778,12 +2778,41 @@ /* PCH */ /* south display engine interrupt */ +#define SDE_AUDIO_POWER_D (1 << 27) +#define SDE_AUDIO_POWER_C (1 << 26) +#define SDE_AUDIO_POWER_B (1 << 25) +#define SDE_AUDIO_POWER_SHIFT (25) +#define SDE_AUDIO_POWER_MASK (7 << SDE_AUDIO_POWER_SHIFT) +#define SDE_GMBUS (1 << 24) +#define SDE_AUDIO_HDCP_TRANSB (1 << 23) +#define SDE_AUDIO_HDCP_TRANSA (1 << 22) +#define SDE_AUDIO_HDCP_MASK (3 << 22) +#define SDE_AUDIO_TRANSB (1 << 21) +#define SDE_AUDIO_TRANSA (1 << 20) +#define SDE_AUDIO_TRANS_MASK (3 << 20) +#define SDE_POISON (1 << 19) +/* 18 reserved */ +#define SDE_FDI_RXB (1 << 17) +#define SDE_FDI_RXA (1 << 16) +#define SDE_FDI_MASK (3 << 16) +#define SDE_AUXD (1 << 15) +#define SDE_AUXC (1 << 14) +#define SDE_AUXB (1 << 13) +#define SDE_AUX_MASK (7 << 13) +/* 12 reserved */ #define SDE_CRT_HOTPLUG (1 << 11) #define SDE_PORTD_HOTPLUG (1 << 10) #define SDE_PORTC_HOTPLUG (1 << 9) #define SDE_PORTB_HOTPLUG (1 << 8) #define SDE_SDVOB_HOTPLUG (1 << 6) #define SDE_HOTPLUG_MASK (0xf << 8) +#define SDE_TRANSB_CRC_DONE (1 << 5) +#define SDE_TRANSB_CRC_ERR (1 << 4) +#define SDE_TRANSB_FIFO_UNDER (1 << 3) +#define SDE_TRANSA_CRC_DONE (1 << 2) +#define SDE_TRANSA_CRC_ERR (1 << 1) +#define SDE_TRANSA_FIFO_UNDER (1 << 0) +#define SDE_TRANS_MASK (0x3f) /* CPT */ #define SDE_CRT_HOTPLUG_CPT (1 << 19) #define SDE_PORTD_HOTPLUG_CPT (1 << 23) -- cgit v1.2.3 From 882417851a0f2e09e110038a13e88e9b5a100800 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Jan 2011 17:09:48 +0000 Subject: drm/i915: Propagate error from flushing the ring ... in order to avoid a BUG() and potential unbounded waits. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 8 +-- drivers/gpu/drm/i915/i915_gem.c | 102 +++++++++++++++++++---------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 28 +++++--- 3 files changed, 90 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 455260067ff7..3e78314514a2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1086,10 +1086,10 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); int i915_gem_init_object(struct drm_gem_object *obj); -void i915_gem_flush_ring(struct drm_device *dev, - struct intel_ring_buffer *ring, - uint32_t invalidate_domains, - uint32_t flush_domains); +int __must_check i915_gem_flush_ring(struct drm_device *dev, + struct intel_ring_buffer *ring, + uint32_t invalidate_domains, + uint32_t flush_domains); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 07b62449b9e1..2873d068eb1f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,18 +35,18 @@ #include #include -static void i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj); +static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj); -static int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, - bool write); -static int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, - uint64_t offset, - uint64_t size); +static __must_check int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, + bool write); +static __must_check int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, + uint64_t offset, + uint64_t size); static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj); -static int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, - unsigned alignment, - bool map_and_fenceable); +static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, + unsigned alignment, + bool map_and_fenceable); static void i915_gem_clear_fence_reg(struct drm_device *dev, struct drm_i915_fence_reg *reg); static int i915_gem_phys_pwrite(struct drm_device *dev, @@ -2142,25 +2142,37 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) return ret; } -void +int i915_gem_flush_ring(struct drm_device *dev, struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains) { - if (ring->flush(ring, invalidate_domains, flush_domains) == 0) - i915_gem_process_flushing_list(dev, flush_domains, ring); + int ret; + + ret = ring->flush(ring, invalidate_domains, flush_domains); + if (ret) + return ret; + + i915_gem_process_flushing_list(dev, flush_domains, ring); + return 0; } static int i915_ring_idle(struct drm_device *dev, struct intel_ring_buffer *ring) { + int ret; + if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list)) return 0; - if (!list_empty(&ring->gpu_write_list)) - i915_gem_flush_ring(dev, ring, + if (!list_empty(&ring->gpu_write_list)) { + ret = i915_gem_flush_ring(dev, ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + if (ret) + return ret; + } + return i915_wait_request(dev, i915_gem_next_request_seqno(dev, ring), ring); @@ -2370,10 +2382,13 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, int ret; if (obj->fenced_gpu_access) { - if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) - i915_gem_flush_ring(obj->base.dev, - obj->last_fenced_ring, - 0, obj->base.write_domain); + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { + ret = i915_gem_flush_ring(obj->base.dev, + obj->last_fenced_ring, + 0, obj->base.write_domain); + if (ret) + return ret; + } obj->fenced_gpu_access = false; } @@ -2529,9 +2544,12 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, return ret; } else if (obj->tiling_changed) { if (obj->fenced_gpu_access) { - if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) - i915_gem_flush_ring(obj->base.dev, obj->ring, - 0, obj->base.write_domain); + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { + ret = i915_gem_flush_ring(obj->base.dev, obj->ring, + 0, obj->base.write_domain); + if (ret) + return ret; + } obj->fenced_gpu_access = false; } @@ -2817,17 +2835,16 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) } /** Flushes any GPU write domain for the object if it's dirty. */ -static void +static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) - return; + return 0; /* Queue the GPU write cache flushing we need. */ - i915_gem_flush_ring(dev, obj->ring, 0, obj->base.write_domain); - BUG_ON(obj->base.write_domain); + return i915_gem_flush_ring(dev, obj->ring, 0, obj->base.write_domain); } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2894,7 +2911,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) if (obj->gtt_space == NULL) return -EINVAL; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; + if (obj->pending_gpu_write || write) { ret = i915_gem_object_wait_rendering(obj, true); if (ret) @@ -2939,7 +2959,10 @@ i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, if (obj->gtt_space == NULL) return -EINVAL; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; + /* Currently, we are always called from an non-interruptible context. */ if (pipelined != obj->ring) { @@ -2964,12 +2987,17 @@ int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, bool interruptible) { + int ret; + if (!obj->active) return 0; - if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) - i915_gem_flush_ring(obj->base.dev, obj->ring, - 0, obj->base.write_domain); + if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { + ret = i915_gem_flush_ring(obj->base.dev, obj->ring, + 0, obj->base.write_domain); + if (ret) + return ret; + } return i915_gem_object_wait_rendering(obj, interruptible); } @@ -2986,7 +3014,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) uint32_t old_write_domain, old_read_domains; int ret; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; + ret = i915_gem_object_wait_rendering(obj, true); if (ret) return ret; @@ -3081,7 +3112,10 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, if (offset == 0 && size == obj->base.size) return i915_gem_object_set_to_cpu_domain(obj, 0); - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; + ret = i915_gem_object_wait_rendering(obj, true); if (ret) return ret; @@ -3374,8 +3408,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * flush earlier is beneficial. */ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - i915_gem_flush_ring(dev, obj->ring, - 0, obj->base.write_domain); + ret = i915_gem_flush_ring(dev, obj->ring, + 0, obj->base.write_domain); } else if (obj->ring->outstanding_lazy_request == obj->last_rendering_seqno) { struct drm_i915_gem_request *request; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1b78b66dd77e..97d5fbd8ea13 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -713,14 +713,14 @@ err: return ret; } -static void +static int i915_gem_execbuffer_flush(struct drm_device *dev, uint32_t invalidate_domains, uint32_t flush_domains, uint32_t flush_rings) { drm_i915_private_t *dev_priv = dev->dev_private; - int i; + int i, ret; if (flush_domains & I915_GEM_DOMAIN_CPU) intel_gtt_chipset_flush(); @@ -730,11 +730,17 @@ i915_gem_execbuffer_flush(struct drm_device *dev, if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { for (i = 0; i < I915_NUM_RINGS; i++) - if (flush_rings & (1 << i)) - i915_gem_flush_ring(dev, &dev_priv->ring[i], - invalidate_domains, - flush_domains); + if (flush_rings & (1 << i)) { + ret = i915_gem_flush_ring(dev, + &dev_priv->ring[i], + invalidate_domains, + flush_domains); + if (ret) + return ret; + } } + + return 0; } static int @@ -798,10 +804,12 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, cd.invalidate_domains, cd.flush_domains); #endif - i915_gem_execbuffer_flush(ring->dev, - cd.invalidate_domains, - cd.flush_domains, - cd.flush_rings); + ret = i915_gem_execbuffer_flush(ring->dev, + cd.invalidate_domains, + cd.flush_domains, + cd.flush_rings); + if (ret) + return ret; } list_for_each_entry(obj, objects, exec_list) { -- cgit v1.2.3 From db66e37d239b45f36a3f6495cf4ec49391b2c089 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 8 Jan 2011 09:02:21 +0000 Subject: drm/i915: Include TLB miss overhead for computing WM The docs recommend that if 8 display lines fit inside the FIFO buffer, then the number of watermark entries should be increased to hide the latency of filling the rest of the FIFO buffer. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1190efa390bd..25d96889d7d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3425,8 +3425,9 @@ static bool ironlake_compute_wm0(struct drm_device *dev, int *cursor_wm) { struct drm_crtc *crtc; - int htotal, hdisplay, clock, pixel_size = 0; - int line_time_us, line_count, entries; + int htotal, hdisplay, clock, pixel_size; + int line_time_us, line_count; + int entries, tlb_miss; crtc = intel_get_crtc_for_pipe(dev, pipe); if (crtc->fb == NULL || !crtc->enabled) @@ -3439,6 +3440,9 @@ static bool ironlake_compute_wm0(struct drm_device *dev, /* Use the small buffer method to calculate plane watermark */ entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; entries = DIV_ROUND_UP(entries, display->cacheline_size); *plane_wm = entries + display->guard_size; if (*plane_wm > (int)display->max_wm) @@ -3448,6 +3452,9 @@ static bool ironlake_compute_wm0(struct drm_device *dev, line_time_us = ((htotal * 1000) / clock); line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; entries = line_count * 64 * pixel_size; + tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; entries = DIV_ROUND_UP(entries, cursor->cacheline_size); *cursor_wm = entries + cursor->guard_size; if (*cursor_wm > (int)cursor->max_wm) -- cgit v1.2.3 From bcfb2e285827bf0cfea8bbfad18a4fca57fbabae Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Jan 2011 21:06:07 +0000 Subject: drm/i915: Record the error batchbuffer on each ring Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 164 ++++++++++-------------------------- 3 files changed, 50 insertions(+), 120 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9c4cdc143be9..a7c194a837a3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -750,7 +750,9 @@ static int i915_error_state(struct seq_file *m, void *unused) if (error->batchbuffer[i]) { struct drm_i915_error_object *obj = error->batchbuffer[i]; - seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset); + seq_printf(m, "%s --- gtt_offset = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); offset = 0; for (page = 0; page < obj->page_count; page++) { for (elt = 0; elt < PAGE_SIZE/4; elt++) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3e78314514a2..6c9a042737d6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -172,7 +172,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer[2]; + } *ringbuffer, *batchbuffer[I915_NUM_RINGS]; struct drm_i915_error_buffer { size_t size; u32 name; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d431fc4fb84b..cf61235b858f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -566,10 +566,9 @@ static void i915_error_work_func(struct work_struct *work) #ifdef CONFIG_DEBUG_FS static struct drm_i915_error_object * -i915_error_object_create(struct drm_device *dev, +i915_error_object_create(struct drm_i915_private *dev_priv, struct drm_i915_gem_object *src) { - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_object *dst; int page, page_count; u32 reloc_offset; @@ -642,52 +641,6 @@ i915_error_state_free(struct drm_device *dev, kfree(error); } -static u32 -i915_get_bbaddr(struct drm_device *dev, u32 *ring) -{ - u32 cmd; - - if (IS_I830(dev) || IS_845G(dev)) - cmd = MI_BATCH_BUFFER; - else if (INTEL_INFO(dev)->gen >= 4) - cmd = (MI_BATCH_BUFFER_START | (2 << 6) | - MI_BATCH_NON_SECURE_I965); - else - cmd = (MI_BATCH_BUFFER_START | (2 << 6)); - - return ring[0] == cmd ? ring[1] : 0; -} - -static u32 -i915_ringbuffer_last_batch(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 head, bbaddr; - u32 *val; - - /* Locate the current position in the ringbuffer and walk back - * to find the most recently dispatched batch buffer. - */ - head = I915_READ_HEAD(ring) & HEAD_ADDR; - - val = (u32 *)(ring->virtual_start + head); - while (--val >= (u32 *)ring->virtual_start) { - bbaddr = i915_get_bbaddr(dev, val); - if (bbaddr) - return bbaddr; - } - - val = (u32 *)(ring->virtual_start + ring->size); - while (--val >= (u32 *)ring->virtual_start) { - bbaddr = i915_get_bbaddr(dev, val); - if (bbaddr) - return bbaddr; - } - - return 0; -} - static u32 capture_bo_list(struct drm_i915_error_buffer *err, int count, struct list_head *head) @@ -751,6 +704,36 @@ static void i915_gem_record_fences(struct drm_device *dev, } } +static struct drm_i915_error_object * +i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) +{ + struct drm_i915_gem_object *obj; + u32 seqno; + + if (!ring->get_seqno) + return NULL; + + seqno = ring->get_seqno(ring); + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { + if (obj->ring != ring) + continue; + + if (!i915_seqno_passed(obj->last_rendering_seqno, seqno)) + continue; + + if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) + continue; + + /* We need to copy these to an anonymous buffer as the simplest + * method to avoid being overwritten by userspace. + */ + return i915_error_object_create(dev_priv, obj); + } + + return NULL; +} + /** * i915_capture_error_state - capture an error record for later analysis * @dev: drm device @@ -765,10 +748,8 @@ static void i915_capture_error_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct drm_i915_error_state *error; - struct drm_i915_gem_object *batchbuffer[2]; unsigned long flags; - u32 bbaddr; - int count; + int i; spin_lock_irqsave(&dev_priv->error_lock, flags); error = dev_priv->first_error; @@ -827,83 +808,30 @@ static void i915_capture_error_state(struct drm_device *dev) } i915_gem_record_fences(dev, error); - bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->ring[RCS]); - - /* Grab the current batchbuffer, most likely to have crashed. */ - batchbuffer[0] = NULL; - batchbuffer[1] = NULL; - count = 0; - list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { - if (batchbuffer[0] == NULL && - bbaddr >= obj->gtt_offset && - bbaddr < obj->gtt_offset + obj->base.size) - batchbuffer[0] = obj; - - if (batchbuffer[1] == NULL && - error->acthd >= obj->gtt_offset && - error->acthd < obj->gtt_offset + obj->base.size) - batchbuffer[1] = obj; - - count++; - } - /* Scan the other lists for completeness for those bizarre errors. */ - if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { - list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) { - if (batchbuffer[0] == NULL && - bbaddr >= obj->gtt_offset && - bbaddr < obj->gtt_offset + obj->base.size) - batchbuffer[0] = obj; - - if (batchbuffer[1] == NULL && - error->acthd >= obj->gtt_offset && - error->acthd < obj->gtt_offset + obj->base.size) - batchbuffer[1] = obj; - - if (batchbuffer[0] && batchbuffer[1]) - break; - } - } - if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { - list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { - if (batchbuffer[0] == NULL && - bbaddr >= obj->gtt_offset && - bbaddr < obj->gtt_offset + obj->base.size) - batchbuffer[0] = obj; - - if (batchbuffer[1] == NULL && - error->acthd >= obj->gtt_offset && - error->acthd < obj->gtt_offset + obj->base.size) - batchbuffer[1] = obj; - - if (batchbuffer[0] && batchbuffer[1]) - break; - } - } - - /* We need to copy these to an anonymous buffer as the simplest - * method to avoid being overwritten by userspace. - */ - error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]); - if (batchbuffer[1] != batchbuffer[0]) - error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); - else - error->batchbuffer[1] = NULL; + /* Record the active batchbuffers */ + for (i = 0; i < I915_NUM_RINGS; i++) + error->batchbuffer[i] = + i915_error_first_batchbuffer(dev_priv, + &dev_priv->ring[i]); /* Record the ringbuffer */ - error->ringbuffer = i915_error_object_create(dev, + error->ringbuffer = i915_error_object_create(dev_priv, dev_priv->ring[RCS].obj); /* Record buffers on the active and pinned lists. */ error->active_bo = NULL; error->pinned_bo = NULL; - error->active_bo_count = count; + i = 0; + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) + i++; + error->active_bo_count = i; list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list) - count++; - error->pinned_bo_count = count - error->active_bo_count; + i++; + error->pinned_bo_count = i - error->active_bo_count; - if (count) { - error->active_bo = kmalloc(sizeof(*error->active_bo)*count, + if (i) { + error->active_bo = kmalloc(sizeof(*error->active_bo)*i, GFP_ATOMIC); if (error->active_bo) error->pinned_bo = -- cgit v1.2.3 From d9126400580e2caada85fa68799952956a6062fd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 11 Jan 2011 11:07:54 +0000 Subject: drm/i915/gtt: Unmap the PCI pages after unbinding them from the GTT Dave Airlie spotted that his ILK laptop with DMAR enabled was generating the occasional DMAR warning. "The ordering in the previous code was to rewrite the GTT table before unmapping the pages and that makes sense to me." This is his stable patch ported to d-i-n. Reported-by: Dave Airlie Original-patch-by: Dave Airlie Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_gtt.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 86673e77d7cb..70433ae50ac8 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -85,15 +85,11 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); - if (dev_priv->mm.gtt->needs_dmar) { + if (obj->sg_list) { intel_gtt_unmap_memory(obj->sg_list, obj->num_sg); obj->sg_list = NULL; - obj->num_sg = 0; } - - intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); } -- cgit v1.2.3 From bf572541ab44240163eaa2d486b06f306a31d45a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 12 Jan 2011 09:03:35 +1100 Subject: md: fix regression with re-adding devices to arrays with no metadata Commit 1a855a0606 (2.6.37-rc4) fixed a problem where devices were re-added when they shouldn't be but caused a regression in a less common case that means sometimes devices cannot be re-added when they should be. In particular, when re-adding a device to an array without metadata we should always access the device, but after the above commit we didn't. This patch sets the In_sync flag in that case so that the re-add succeeds. This patch is suitable for any -stable kernel to which 1a855a0606 was applied. Cc: stable@kernel.org Signed-off-by: NeilBrown --- drivers/md/md.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 175c424f201f..0da25daea9be 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5159,9 +5159,10 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) /* set saved_raid_disk if appropriate */ if (!mddev->persistent) { if (info->state & (1<raid_disk < mddev->raid_disks) + info->raid_disk < mddev->raid_disks) { rdev->raid_disk = info->raid_disk; - else + set_bit(In_sync, &rdev->flags); + } else rdev->raid_disk = -1; } else super_types[mddev->major_version]. -- cgit v1.2.3 From 0a58705b2fc3fa29525cf2fdae3d4276a5771280 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 9 Jan 2011 21:05:44 +0000 Subject: drm/i915: Periodically flush the active lists and requests In order to retire active buffers whilst no client is active, we need to insert our own flush requests onto the ring. This is useful for servers that queue up some rendering and then go to sleep as it allows us to the complete processing of those requests, potentially making that memory available again much earlier. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2873d068eb1f..87c2df714f66 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1935,6 +1935,8 @@ i915_gem_retire_work_handler(struct work_struct *work) { drm_i915_private_t *dev_priv; struct drm_device *dev; + bool idle; + int i; dev_priv = container_of(work, drm_i915_private_t, mm.retire_work.work); @@ -1948,11 +1950,31 @@ i915_gem_retire_work_handler(struct work_struct *work) i915_gem_retire_requests(dev); - if (!dev_priv->mm.suspended && - (!list_empty(&dev_priv->ring[RCS].request_list) || - !list_empty(&dev_priv->ring[VCS].request_list) || - !list_empty(&dev_priv->ring[BCS].request_list))) + /* Send a periodic flush down the ring so we don't hold onto GEM + * objects indefinitely. + */ + idle = true; + for (i = 0; i < I915_NUM_RINGS; i++) { + struct intel_ring_buffer *ring = &dev_priv->ring[i]; + + if (!list_empty(&ring->gpu_write_list)) { + struct drm_i915_gem_request *request; + int ret; + + ret = i915_gem_flush_ring(dev, ring, 0, + I915_GEM_GPU_DOMAINS); + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (ret || request == NULL || + i915_add_request(dev, NULL, request, ring)) + kfree(request); + } + + idle &= list_empty(&ring->request_list); + } + + if (!dev_priv->mm.suspended && !idle) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + mutex_unlock(&dev->struct_mutex); } -- cgit v1.2.3 From a779e5abda0367aa9d53c0931d9687743afe503d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 9 Jan 2011 21:07:49 +0000 Subject: drm/i915: Record AGP memory type upon error Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 14 ++++++++++++-- drivers/gpu/drm/i915/i915_drv.h | 5 +++-- drivers/gpu/drm/i915/i915_irq.c | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a7c194a837a3..73914d841856 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -624,6 +624,15 @@ static const char *ring_str(int ring) } } +static const char *agp_type_str(int type) +{ + switch (type) { + case 0: return " uncached"; + case 1: return " snooped"; + default: return ""; + } +} + static const char *pin_flag(int pinned) { if (pinned > 0) @@ -662,7 +671,7 @@ static void print_error_buffers(struct seq_file *m, seq_printf(m, "%s [%d]:\n", name, count); while (count--) { - seq_printf(m, " %08x %8zd %04x %04x %08x%s%s%s%s%s", + seq_printf(m, " %08x %8zd %04x %04x %08x%s%s%s%s%s%s", err->gtt_offset, err->size, err->read_domains, @@ -672,7 +681,8 @@ static void print_error_buffers(struct seq_file *m, tiling_flag(err->tiling), dirty_flag(err->dirty), purgeable_flag(err->purgeable), - ring_str(err->ring)); + ring_str(err->ring), + agp_type_str(err->agp_type)); if (err->name) seq_printf(m, " (name: %d)", err->name); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6c9a042737d6..6130f77c26bf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -174,18 +174,19 @@ struct drm_i915_error_state { u32 *pages[0]; } *ringbuffer, *batchbuffer[I915_NUM_RINGS]; struct drm_i915_error_buffer { - size_t size; + u32 size; u32 name; u32 seqno; u32 gtt_offset; u32 read_domains; u32 write_domain; - u32 fence_reg; + s32 fence_reg:5; s32 pinned:2; u32 tiling:2; u32 dirty:1; u32 purgeable:1; u32 ring:4; + u32 agp_type:1; } *active_bo, *pinned_bo; u32 active_bo_count, pinned_bo_count; struct intel_overlay_error_state *overlay; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cf61235b858f..e418e8bb61e6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -665,6 +665,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err, err->dirty = obj->dirty; err->purgeable = obj->madv != I915_MADV_WILLNEED; err->ring = obj->ring ? obj->ring->id : 0; + err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY; if (++i == count) break; -- cgit v1.2.3 From 08c18323547ce6d70eab3b37eca894baf114ad85 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jan 2011 00:00:24 +0000 Subject: drm/i915/debugfs: Show all objects in the gtt Useful for determining the layout. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 53 ++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 73914d841856..19a3d58044dd 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -106,10 +106,19 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj) } } +static const char *agp_type_str(int type) +{ + switch (type) { + case 0: return " uncached"; + case 1: return " snooped"; + default: return ""; + } +} + static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { - seq_printf(m, "%p: %s%s %8zd %04x %04x %d %d%s%s", + seq_printf(m, "%p: %s%s %8zd %04x %04x %d %d%s%s%s", &obj->base, get_pin_flag(obj), get_tiling_flag(obj), @@ -118,6 +127,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) obj->base.write_domain, obj->last_rendering_seqno, obj->last_fenced_seqno, + agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY), obj->dirty ? " dirty" : "", obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); if (obj->base.name) @@ -276,6 +286,37 @@ static int i915_gem_object_info(struct seq_file *m, void* data) return 0; } +static int i915_gem_gtt_info(struct seq_file *m, void* data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + size_t total_obj_size, total_gtt_size; + int count, ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + total_obj_size = total_gtt_size = count = 0; + list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + seq_printf(m, " "); + describe_obj(m, obj); + seq_printf(m, "\n"); + total_obj_size += obj->base.size; + total_gtt_size += obj->gtt_space->size; + count++; + } + + mutex_unlock(&dev->struct_mutex); + + seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + count, total_obj_size, total_gtt_size); + + return 0; +} + static int i915_gem_pageflip_info(struct seq_file *m, void *data) { @@ -624,15 +665,6 @@ static const char *ring_str(int ring) } } -static const char *agp_type_str(int type) -{ - switch (type) { - case 0: return " uncached"; - case 1: return " snooped"; - default: return ""; - } -} - static const char *pin_flag(int pinned) { if (pinned > 0) @@ -1229,6 +1261,7 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, + {"i915_gem_gtt", i915_gem_gtt_info, 0}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, -- cgit v1.2.3 From 36cf17423095882ec0f8f2c04d1bd0ee812149df Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jan 2011 12:09:12 +0000 Subject: drm/i915/execbuffer: Correctly clear the current object list upon EFAULT Before releasing the lock in order to copy the relocation list from user pages, we need to drop all the object references as another thread may usurp and execute another batchbuffer before we reacquire the lock. However, the code was buggy and failed to clear the list... Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 97d5fbd8ea13..0445770cc23c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -622,7 +622,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, int i, total, ret; /* We may process another execbuffer during the unlock... */ - while (list_empty(objects)) { + while (!list_empty(objects)) { obj = list_first_entry(objects, struct drm_i915_gem_object, exec_list); @@ -665,7 +665,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, } /* reacquire the objects */ - INIT_LIST_HEAD(objects); eb_reset(eb); for (i = 0; i < count; i++) { struct drm_i915_gem_object *obj; @@ -1353,4 +1352,3 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, drm_free_large(exec2_list); return ret; } - -- cgit v1.2.3 From 092de6f225638ec300936bfcbdc67805733cc78c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jan 2011 14:21:05 +0000 Subject: drm/i915/evict: Ensure we completely cleanup on failure ... and not leave the objects in a inconsistent state. Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem_evict.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 78b8cf90c922..3d39005540aa 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -127,9 +127,15 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, } /* Nothing found, clean up and bail out! */ - list_for_each_entry(obj, &unwind_list, exec_list) { + while (!list_empty(&unwind_list)) { + obj = list_first_entry(&unwind_list, + struct drm_i915_gem_object, + exec_list); + ret = drm_mm_scan_remove_block(obj->gtt_space); BUG_ON(ret); + + list_del_init(&obj->exec_list); drm_gem_object_unreference(&obj->base); } @@ -162,6 +168,7 @@ found: exec_list); if (ret == 0) ret = i915_gem_object_unbind(obj); + list_del_init(&obj->exec_list); drm_gem_object_unreference(&obj->base); } -- cgit v1.2.3 From 809b63349ce6eb6603e7dab482c642f28135a2db Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jan 2011 17:33:15 +0000 Subject: drm/i915: If we hit OOM when allocating GTT pages, clear the aperture Rather than evicting an object at random, which is unlikely to alleviate the memory pressure sufficient to allow us to continue, zap the entire aperture. That should give the system long enough to recover and reap some pages from the evicted objects, forestalling the allocation error for the new object. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 87c2df714f66..3dfc848ff755 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2782,10 +2782,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, obj->gtt_space = NULL; if (ret == -ENOMEM) { - /* first try to clear up some space from the GTT */ - ret = i915_gem_evict_something(dev, size, - alignment, - map_and_fenceable); + /* first try to reclaim some memory by clearing the GTT */ + ret = i915_gem_evict_everything(dev, false); if (ret) { /* now try to shrink everyone else */ if (gfpmask) { @@ -2793,7 +2791,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, goto search_free; } - return ret; + return -ENOMEM; } goto search_free; @@ -2808,9 +2806,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, drm_mm_put_block(obj->gtt_space); obj->gtt_space = NULL; - ret = i915_gem_evict_something(dev, size, - alignment, map_and_fenceable); - if (ret) + if (i915_gem_evict_everything(dev, false)) return ret; goto search_free; -- cgit v1.2.3 From 6fe4f14044f181e146cdc15485428f95fa541ce8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jan 2011 17:35:37 +0000 Subject: drm/i915/execbuffer: Reorder binding of objects to favour restrictions As the mappable portion of the aperture is always a small subset at the start of the GTT, it is allocated preferentially by drm_mm. This is useful in case we ever need to map an object later. However, if you have a large object that can consume the entire mappable region of the GTT this prevents the batchbuffer from fitting and so causing an error. Instead allocate all those that require a mapping up front in order to improve the likelihood of finding sufficient space to bind them. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 72 +++++++++++++++++++----------- 2 files changed, 47 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6130f77c26bf..385fc7ec39d3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -796,6 +796,7 @@ struct drm_i915_gem_object { */ struct hlist_node exec_node; unsigned long exec_handle; + struct drm_i915_gem_exec_object2 *exec_entry; /** * Current offset of the object in GTT space. diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 0445770cc23c..e69834341ef0 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -268,7 +268,6 @@ eb_destroy(struct eb_objects *eb) static int i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, struct eb_objects *eb, - struct drm_i915_gem_exec_object2 *entry, struct drm_i915_gem_relocation_entry *reloc) { struct drm_device *dev = obj->base.dev; @@ -411,10 +410,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, - struct eb_objects *eb, - struct drm_i915_gem_exec_object2 *entry) + struct eb_objects *eb) { struct drm_i915_gem_relocation_entry __user *user_relocs; + struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; int i, ret; user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; @@ -426,7 +425,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, sizeof(reloc))) return -EFAULT; - ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &reloc); + ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc); if (ret) return ret; @@ -442,13 +441,13 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, struct eb_objects *eb, - struct drm_i915_gem_exec_object2 *entry, struct drm_i915_gem_relocation_entry *relocs) { + const struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; int i, ret; for (i = 0; i < entry->relocation_count; i++) { - ret = i915_gem_execbuffer_relocate_entry(obj, eb, entry, &relocs[i]); + ret = i915_gem_execbuffer_relocate_entry(obj, eb, &relocs[i]); if (ret) return ret; } @@ -459,8 +458,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, struct eb_objects *eb, - struct list_head *objects, - struct drm_i915_gem_exec_object2 *exec) + struct list_head *objects) { struct drm_i915_gem_object *obj; int ret; @@ -468,7 +466,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, list_for_each_entry(obj, objects, exec_list) { obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; - ret = i915_gem_execbuffer_relocate_object(obj, eb, exec++); + ret = i915_gem_execbuffer_relocate_object(obj, eb); if (ret) return ret; } @@ -479,13 +477,36 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, static int i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_file *file, - struct list_head *objects, - struct drm_i915_gem_exec_object2 *exec) + struct list_head *objects) { struct drm_i915_gem_object *obj; - struct drm_i915_gem_exec_object2 *entry; int ret, retry; bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; + struct list_head ordered_objects; + + INIT_LIST_HEAD(&ordered_objects); + while (!list_empty(objects)) { + struct drm_i915_gem_exec_object2 *entry; + bool need_fence, need_mappable; + + obj = list_first_entry(objects, + struct drm_i915_gem_object, + exec_list); + entry = obj->exec_entry; + + need_fence = + has_fenced_gpu_access && + entry->flags & EXEC_OBJECT_NEEDS_FENCE && + obj->tiling_mode != I915_TILING_NONE; + need_mappable = + entry->relocation_count ? true : need_fence; + + if (need_mappable) + list_move(&obj->exec_list, &ordered_objects); + else + list_move_tail(&obj->exec_list, &ordered_objects); + } + list_splice(&ordered_objects, objects); /* Attempt to pin all of the buffers into the GTT. * This is done in 3 phases: @@ -504,14 +525,11 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, ret = 0; /* Unbind any ill-fitting objects or pin. */ - entry = exec; list_for_each_entry(obj, objects, exec_list) { + struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; bool need_fence, need_mappable; - - if (!obj->gtt_space) { - entry++; + if (!obj->gtt_space) continue; - } need_fence = has_fenced_gpu_access && @@ -534,8 +552,8 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, } /* Bind fresh objects */ - entry = exec; list_for_each_entry(obj, objects, exec_list) { + struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; bool need_fence; need_fence = @@ -570,7 +588,6 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, } entry->offset = obj->gtt_offset; - entry++; } /* Decrement pin count for bound objects */ @@ -680,10 +697,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, list_add_tail(&obj->exec_list, objects); obj->exec_handle = exec[i].handle; + obj->exec_entry = &exec[i]; eb_add_object(eb, obj); } - ret = i915_gem_execbuffer_reserve(ring, file, objects, exec); + ret = i915_gem_execbuffer_reserve(ring, file, objects); if (ret) goto err; @@ -692,7 +710,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, - exec, reloc + total); if (ret) goto err; @@ -1110,16 +1127,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, list_add_tail(&obj->exec_list, &objects); obj->exec_handle = exec[i].handle; + obj->exec_entry = &exec[i]; eb_add_object(eb, obj); } + /* take note of the batch buffer before we might reorder the lists */ + batch_obj = list_entry(objects.prev, + struct drm_i915_gem_object, + exec_list); + /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(ring, file, &objects, exec); + ret = i915_gem_execbuffer_reserve(ring, file, &objects); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, eb, &objects, exec); + ret = i915_gem_execbuffer_relocate(dev, eb, &objects); if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, @@ -1133,9 +1156,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } /* Set the pending read domains for the batch buffer to COMMAND */ - batch_obj = list_entry(objects.prev, - struct drm_i915_gem_object, - exec_list); if (batch_obj->base.pending_write_domain) { DRM_ERROR("Attempting to use self-modifying batch buffer\n"); ret = -EINVAL; -- cgit v1.2.3 From a46f3108b1cd8bf11d46ac8a5f30df6f6dbdf738 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 12 Jan 2011 11:38:37 +1000 Subject: i915/gtt: fix ordering issues with status setup and DMAR This code was setting up the status page before setting the DMAR-is-on-bit, so we were getting DMAR errors on the status page. Reverse the two bits of init code to the correct result. Signed-off-by: Dave Airlie --- drivers/char/agp/intel-gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index da8161806f39..b7c0c7ee67c8 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -688,14 +688,14 @@ static int intel_gtt_init(void) intel_private.base.stolen_size = intel_gtt_stolen_size(); + intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; + ret = intel_gtt_setup_scratch_page(); if (ret != 0) { intel_gtt_cleanup(); return ret; } - intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; - return 0; } -- cgit v1.2.3 From d15eda5c6edff4987af6f4423af0bab0c3251e74 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 12 Jan 2011 11:39:48 +1000 Subject: i915/gtt: fix ordering causing DMAR errors on object teardown. Previous to the last GTT rework we always rewrote the GTT then unmapped the object, somehow this got reversed in the rework in 2.6.37-rc5 timeframe. This fix needs to go to stable in an alternate form since the code changed. This fixes DMAR reports on my Ironlake HP2540p. Signed-off-by: Dave Airlie --- drivers/char/agp/intel-gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index b7c0c7ee67c8..e921b693412b 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1000,14 +1000,14 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, if (mem->page_count == 0) return 0; + intel_gtt_clear_range(pg_start, mem->page_count); + if (intel_private.base.needs_dmar) { intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); mem->sg_list = NULL; mem->num_sg = 0; } - intel_gtt_clear_range(pg_start, mem->page_count); - return 0; } -- cgit v1.2.3 From 5b026c4e3af52fda22c9313a3388344f82f3ba15 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 11 Jan 2011 23:25:30 -0500 Subject: SFI: use ioremap_cache() instead of ioremap() We copied ACPI's oversight of using ioremap() and creating non-cached table mappings when we should have been using ioremap_cache(). Signed-off-by: Len Brown --- drivers/sfi/sfi_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index ceba593dc84f..04113e5304a0 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -101,7 +101,7 @@ static void __iomem * __ref sfi_map_memory(u64 phys, u32 size) return NULL; if (sfi_use_ioremap) - return ioremap(phys, size); + return ioremap_cache(phys, size); else return early_ioremap(phys, size); } -- cgit v1.2.3 From eb4a7cbf27082bea34764bab3bc85595683f967b Mon Sep 17 00:00:00 2001 From: "John L. Burr" Date: Tue, 11 Jan 2011 20:39:46 -0800 Subject: IB/mthca: Fix driver when sizeof (phys_addr_t) > sizeof (long) Some systems have PCI addresses that don't fit in unsigned long (eg some 32-bit PowerPC 440 systems have 36-bit bus addresses). Fix up the driver by using phys_addr_t where appropriate, so we don't truncate any PCI resource addresses before ioremapping them. Signed-off-by: John L. Burr [ Update to apply to current driver source. - Roland ] Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_catas.c | 5 +++-- drivers/infiniband/hw/mthca/mthca_cmd.c | 2 +- drivers/infiniband/hw/mthca/mthca_eq.c | 2 +- drivers/infiniband/hw/mthca/mthca_main.c | 2 +- drivers/infiniband/hw/mthca/mthca_mr.c | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index 0aa0110e4b6c..e4a08c2819e4 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -146,7 +146,7 @@ static void poll_catas(unsigned long dev_ptr) void mthca_start_catas_poll(struct mthca_dev *dev) { - unsigned long addr; + phys_addr_t addr; init_timer(&dev->catas_err.timer); dev->catas_err.map = NULL; @@ -158,7 +158,8 @@ void mthca_start_catas_poll(struct mthca_dev *dev) dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4); if (!dev->catas_err.map) { mthca_warn(dev, "couldn't map catastrophic error region " - "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); + "at 0x%llx/0x%x\n", (unsigned long long) addr, + dev->catas_err.size * 4); return; } diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index f4ceecd9684b..7bfa2a164955 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -713,7 +713,7 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status) static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base) { - unsigned long addr; + phys_addr_t addr; u16 max_off = 0; int i; diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 8e8c728aff88..76785c653c13 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -653,7 +653,7 @@ static int mthca_map_reg(struct mthca_dev *dev, unsigned long offset, unsigned long size, void __iomem **map) { - unsigned long base = pci_resource_start(dev->pdev, 0); + phys_addr_t base = pci_resource_start(dev->pdev, 0); *map = ioremap(base + offset, size); if (!*map) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 5eee6665919a..8a40cd539ab1 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -790,7 +790,7 @@ static int mthca_setup_hca(struct mthca_dev *dev) goto err_uar_table_free; } - dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + dev->kar = ioremap((phys_addr_t) dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); if (!dev->kar) { mthca_err(dev, "Couldn't map kernel access region, " "aborting.\n"); diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 065b20899876..44045c8846db 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -853,7 +853,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) int mthca_init_mr_table(struct mthca_dev *dev) { - unsigned long addr; + phys_addr_t addr; int mpts, mtts, err, i; err = mthca_alloc_init(&dev->mr_table.mpt_alloc, -- cgit v1.2.3 From 4cb18728709683c91a5f6f8d5f337bfb498b089a Mon Sep 17 00:00:00 2001 From: "R.Durgadoss" Date: Wed, 27 Oct 2010 03:33:29 +0530 Subject: thermal: Add event notification to thermal framework This patch adds event notification support to the generic thermal sysfs framework in the kernel. The notification is in the form of a netlink event. Signed-off-by: R.Durgadoss Signed-off-by: Len Brown --- Documentation/ABI/stable/thermal-notification | 4 + Documentation/thermal/sysfs-api.txt | 12 +++ drivers/thermal/Kconfig | 1 + drivers/thermal/thermal_sys.c | 103 +++++++++++++++++++++++++- include/linux/thermal.h | 32 ++++++++ 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/stable/thermal-notification (limited to 'drivers') diff --git a/Documentation/ABI/stable/thermal-notification b/Documentation/ABI/stable/thermal-notification new file mode 100644 index 000000000000..9723e8b7aeb3 --- /dev/null +++ b/Documentation/ABI/stable/thermal-notification @@ -0,0 +1,4 @@ +What: A notification mechanism for thermal related events +Description: + This interface enables notification for thermal related events. + The notification is in the form of a netlink event. diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index cb3d15bc1aeb..b61e46f449aa 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt @@ -278,3 +278,15 @@ method, the sys I/F structure will be built like this: |---name: acpitz |---temp1_input: 37000 |---temp1_crit: 100000 + +4. Event Notification + +The framework includes a simple notification mechanism, in the form of a +netlink event. Netlink socket initialization is done during the _init_ +of the framework. Drivers which intend to use the notification mechanism +just need to call generate_netlink_event() with two arguments viz +(originator, event). Typically the originator will be an integer assigned +to a thermal_zone_device when it registers itself with the framework. The +event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL, +THERMAL_DEV_FAULT}. Notification can be sent when the current temperature +crosses any of the configured thresholds. diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index bf7c687519ef..f7a5dba3ca23 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -4,6 +4,7 @@ menuconfig THERMAL tristate "Generic Thermal sysfs driver" + depends on NET help Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 13c72c629329..760e045c93c8 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); @@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list); static LIST_HEAD(thermal_cdev_list); static DEFINE_MUTEX(thermal_list_lock); +static unsigned int thermal_event_seqnum; + +static struct genl_family thermal_event_genl_family = { + .id = GENL_ID_GENERATE, + .name = THERMAL_GENL_FAMILY_NAME, + .version = THERMAL_GENL_VERSION, + .maxattr = THERMAL_GENL_ATTR_MAX, +}; + +static struct genl_multicast_group thermal_event_mcgrp = { + .name = THERMAL_GENL_MCAST_GROUP_NAME, +}; + +static int genetlink_init(void); +static void genetlink_exit(void); + static int get_idr(struct idr *idr, struct mutex *lock, int *id) { int err; @@ -1214,6 +1232,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) EXPORT_SYMBOL(thermal_zone_device_unregister); +int generate_netlink_event(u32 orig, enum events event) +{ + struct sk_buff *skb; + struct nlattr *attr; + struct thermal_genl_event *thermal_event; + void *msg_header; + int size; + int result; + + /* allocate memory */ + size = nla_total_size(sizeof(struct thermal_genl_event)) + \ + nla_total_size(0); + + skb = genlmsg_new(size, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + /* add the genetlink message header */ + msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++, + &thermal_event_genl_family, 0, + THERMAL_GENL_CMD_EVENT); + if (!msg_header) { + nlmsg_free(skb); + return -ENOMEM; + } + + /* fill the data */ + attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \ + sizeof(struct thermal_genl_event)); + + if (!attr) { + nlmsg_free(skb); + return -EINVAL; + } + + thermal_event = nla_data(attr); + if (!thermal_event) { + nlmsg_free(skb); + return -EINVAL; + } + + memset(thermal_event, 0, sizeof(struct thermal_genl_event)); + + thermal_event->orig = orig; + thermal_event->event = event; + + /* send multicast genetlink message */ + result = genlmsg_end(skb, msg_header); + if (result < 0) { + nlmsg_free(skb); + return result; + } + + result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC); + if (result) + printk(KERN_INFO "failed to send netlink event:%d", result); + + return result; +} +EXPORT_SYMBOL(generate_netlink_event); + +static int genetlink_init(void) +{ + int result; + + result = genl_register_family(&thermal_event_genl_family); + if (result) + return result; + + result = genl_register_mc_group(&thermal_event_genl_family, + &thermal_event_mcgrp); + if (result) + genl_unregister_family(&thermal_event_genl_family); + return result; +} + static int __init thermal_init(void) { int result = 0; @@ -1225,9 +1319,15 @@ static int __init thermal_init(void) mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); } + result = genetlink_init(); return result; } +static void genetlink_exit(void) +{ + genl_unregister_family(&thermal_event_genl_family); +} + static void __exit thermal_exit(void) { class_unregister(&thermal_class); @@ -1235,7 +1335,8 @@ static void __exit thermal_exit(void) idr_destroy(&thermal_cdev_idr); mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); + genetlink_exit(); } -subsys_initcall(thermal_init); +fs_initcall(thermal_init); module_exit(thermal_exit); diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 1de8b9eb841b..784644961279 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -127,6 +127,37 @@ struct thermal_zone_device { struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ #endif }; +/* Adding event notification support elements */ +#define THERMAL_GENL_FAMILY_NAME "thermal_event" +#define THERMAL_GENL_VERSION 0x01 +#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group" + +enum events { + THERMAL_AUX0, + THERMAL_AUX1, + THERMAL_CRITICAL, + THERMAL_DEV_FAULT, +}; + +struct thermal_genl_event { + u32 orig; + enum events event; +}; +/* attributes of thermal_genl_family */ +enum { + THERMAL_GENL_ATTR_UNSPEC, + THERMAL_GENL_ATTR_EVENT, + __THERMAL_GENL_ATTR_MAX, +}; +#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) + +/* commands supported by the thermal_genl_family */ +enum { + THERMAL_GENL_CMD_UNSPEC, + THERMAL_GENL_CMD_EVENT, + __THERMAL_GENL_CMD_MAX, +}; +#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) struct thermal_zone_device *thermal_zone_device_register(char *, int, void *, struct @@ -146,5 +177,6 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, thermal_cooling_device_ops *); void thermal_cooling_device_unregister(struct thermal_cooling_device *); +extern int generate_netlink_event(u32 orig, enum events event); #endif /* __THERMAL_H__ */ -- cgit v1.2.3 From 4464ed3b05de7a41ae55c74109cec8aeb138ce14 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 10 Jan 2011 11:16:26 +0800 Subject: ACPI: update CONFIG_ACPI_PROCFS description Update CONFIG_ACPI_PROCFS description because the processor, video and thermal zone procfs I/F have been removed. Some ACPI drivers, e.g. button, have their procfs I/F always built in, because we don't have sysfs I/F replacement at the moment. But once we finish developing the sysfs I/F for these driver, we need CONFIG_ACPI_PROCFS to enabled/disable the corresponding procfs I/F. So just updating the description rather than removing this option, although there is no procfs I/F depends on it for now. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index a0c03658b2ea..ad370a1fe2e4 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -51,12 +51,7 @@ config ACPI_PROCFS For backwards compatibility, this option allows deprecated /proc/acpi/ files to exist, even when they have been replaced by functions in /sys. - The deprecated files (and their replacements) include: - /proc/acpi/processor/*/throttling (/sys/class/thermal/ - cooling_device*/*) - /proc/acpi/video/*/brightness (/sys/class/backlight/) - /proc/acpi/thermal_zone/*/* (/sys/class/thermal/) This option has no effect on /proc/acpi/ files and functions which do not yet exist in /sys. -- cgit v1.2.3 From 6d855fcdd24d2491455527c4999b4d04363f1980 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 10 Jan 2011 11:16:30 +0800 Subject: ACPI: delete CONFIG_ACPI_PROCFS_POWER and power procfs I/F in 2.6.39 sysfs I/F for ACPI power devices, including AC and Battery, has been working in upstream kenrel since 2.6.24, Sep 2007. In 2.6.37, we made the sysfs I/F always built in and this option disabled by default. Now, we plan to remove this option and the ACPI power procfs interface in 2.6.39. First, update the feature-removal-schedule to announce this change. Second, add runtime warnings in ACPI AC/Battery/SBS driver, so that users will notice this change even if "make oldconfig" is used. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- Documentation/feature-removal-schedule.txt | 11 +++++++++++ drivers/acpi/Kconfig | 2 ++ drivers/acpi/ac.c | 3 ++- drivers/acpi/battery.c | 2 ++ drivers/acpi/sbs.c | 2 ++ 5 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 6c2f55e05f13..f281532a15ce 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -232,6 +232,17 @@ Who: Zhang Rui --------------------------- +What: CONFIG_ACPI_PROCFS_POWER +When: 2.6.39 +Why: sysfs I/F for ACPI power devices, including AC and Battery, + has been working in upstream kenrel since 2.6.24, Sep 2007. + In 2.6.37, we make the sysfs I/F always built in and this option + disabled by default. + Remove this option and the ACPI power procfs interface in 2.6.39. +Who: Zhang Rui + +--------------------------- + What: /proc/acpi/button When: August 2007 Why: /proc/acpi/button has been replaced by events to the input layer diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5959077be0a4..788e88eb18ec 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -70,6 +70,8 @@ config ACPI_PROCFS_POWER /proc/acpi/ac_adapter/* (sys/class/power_supply/*) This option has no effect on /proc/acpi/ directories and functions, which do not yet exist in /sys + This option, together with the proc directories, will be + deleted in 2.6.39. Say N to delete power /proc/acpi/ directories that have moved to /sys/ diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index ba9afeaa23ac..f441e92481f6 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -185,7 +185,8 @@ static int acpi_ac_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; - + printk(KERN_WARNING PREFIX "Deprecated procfs I/F for AC is loaded," + " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_ac_dir); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 95649d373071..2a31421e0d75 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -868,6 +868,8 @@ static int acpi_battery_add_fs(struct acpi_device *device) struct proc_dir_entry *entry = NULL; int i; + printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded," + " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_battery_dir); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index e5dbedb16bbf..51ae3794ec7f 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -484,6 +484,8 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, const struct file_operations *state_fops, const struct file_operations *alarm_fops, void *data) { + printk(KERN_WARNING PREFIX "Deprecated procfs I/F for SBS is loaded," + " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { -- cgit v1.2.3 From 2cf0c58ed970b91e620e551d4c8da8b1d0baab49 Mon Sep 17 00:00:00 2001 From: Darius Augulis Date: Wed, 12 Jan 2011 14:50:51 +0900 Subject: serial: samsung: fix device name Swap device and driver names in serial/samsung.c Signed-off-by: Darius Augulis Cc: Ben Dooks Signed-off-by: Kukjin Kim --- drivers/serial/samsung.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index 7ac2bf5167cd..2335edafe903 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -883,10 +883,10 @@ static struct uart_ops s3c24xx_serial_ops = { static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, - .dev_name = "s3c2410_serial", + .driver_name = "s3c2410_serial", .nr = CONFIG_SERIAL_SAMSUNG_UARTS, .cons = S3C24XX_SERIAL_CONSOLE, - .driver_name = S3C24XX_SERIAL_NAME, + .dev_name = S3C24XX_SERIAL_NAME, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, }; -- cgit v1.2.3 From ccd8c79c5608fc4835dcb0244623ceae2489f72d Mon Sep 17 00:00:00 2001 From: Mayuresh Janorkar Date: Tue, 11 Jan 2011 19:54:03 +0530 Subject: video: tidy up modedb formatting. A part of file: drivers/video/modedb.c was not as per the coding guidelines. The cleanup includes: 1) Converting spcaes to tabs 2) Adding spaces on either sides of "|" operator Signed-off-by: Mayuresh Janorkar Signed-off-by: Paul Mundt --- drivers/video/modedb.c | 420 ++++++++++++++++++++++++++----------------------- 1 file changed, 220 insertions(+), 200 deletions(-) (limited to 'drivers') diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index d2bb365f09b3..48c3ea8652b6 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -32,300 +32,320 @@ const char *fb_mode_option; EXPORT_SYMBOL_GPL(fb_mode_option); - /* - * Standard video mode definitions (taken from XFree86) - */ +/* + * Standard video mode definitions (taken from XFree86) + */ static const struct fb_videomode modedb[] = { - { + /* 640x400 @ 70 Hz, 31.5 kHz hsync */ - NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ - NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, + FB_VMODE_NONINTERLACED }, + /* 800x600 @ 56 Hz, 35.15 kHz hsync */ - NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ - NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0, + FB_VMODE_INTERLACED }, + /* 640x400 @ 85 Hz, 37.86 kHz hsync */ - NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + /* 640x480 @ 72 Hz, 36.5 kHz hsync */ - NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 75 Hz, 37.50 kHz hsync */ - NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 800x600 @ 60 Hz, 37.8 kHz hsync */ - NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 85 Hz, 43.27 kHz hsync */ - NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ - NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0, + FB_VMODE_INTERLACED }, /* 800x600 @ 72 Hz, 48.0 kHz hsync */ - NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ - NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 100 Hz, 53.01 kHz hsync */ - NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ - NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0, + FB_VMODE_NONINTERLACED }, + /* 800x600 @ 85 Hz, 55.84 kHz hsync */ - NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ - NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ - NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0, + FB_VMODE_INTERLACED }, + /* 800x600 @ 100 Hz, 64.02 kHz hsync */ - NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ - NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ - NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ - NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ - NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ - NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ - NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ - NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ - NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ - NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ - NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ - NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ - NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 100Hz, 80.21 kHz hsync */ - NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ - NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ - NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ - NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ - NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ - NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */ - NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ - NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ - NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0, + FB_VMODE_NONINTERLACED }, + /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ - NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ - NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 512x384 @ 78 Hz, 31.50 kHz hsync */ - NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 512x384 @ 85 Hz, 34.38 kHz hsync */ - NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ - NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0, + FB_VMODE_DOUBLE }, + /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ - NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0, + FB_VMODE_DOUBLE }, + /* 320x240 @ 72 Hz, 36.5 kHz hsync */ - NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0, + FB_VMODE_DOUBLE }, + /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ - NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0, + FB_VMODE_DOUBLE }, + /* 400x300 @ 60 Hz, 37.8 kHz hsync */ - NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0, + FB_VMODE_DOUBLE }, + /* 400x300 @ 72 Hz, 48.0 kHz hsync */ - NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ - NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 60 Hz, 37.8 kHz hsync */ - NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 63 Hz, 39.6 kHz hsync */ - NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 72 Hz, 48.0 kHz hsync */ - NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0, + FB_VMODE_DOUBLE }, + /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */ - NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ - NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ - NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ - NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, - 0, FB_VMODE_NONINTERLACED - }, { - /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ - NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, - 0, FB_VMODE_INTERLACED - }, { - /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ - NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0, + FB_VMODE_NONINTERLACED }, + + /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + { NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0, + FB_VMODE_INTERLACED }, + + /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + { NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0, + FB_VMODE_INTERLACED }, + /* 864x480 @ 60 Hz, 35.15 kHz hsync */ - NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0, - 0, FB_VMODE_NONINTERLACED - }, + { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0, + 0, FB_VMODE_NONINTERLACED }, }; #ifdef CONFIG_FB_MODE_HELPERS const struct fb_videomode cea_modes[64] = { /* #1: 640x480p@59.94/60Hz */ [1] = { - NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #3: 720x480p@59.94/60Hz */ [3] = { - NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #5: 1920x1080i@59.94/60Hz */ [5] = { NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, 0, }, /* #7: 720(1440)x480iH@59.94/60Hz */ [7] = { - NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, FB_VMODE_INTERLACED, 0, + NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, + FB_VMODE_INTERLACED, 0, }, /* #9: 720(1440)x240pH@59.94/60Hz */ [9] = { - NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #18: 720x576pH@50Hz */ [18] = { - NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #19: 1280x720p@50Hz */ [19] = { NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0, }, /* #20: 1920x1080i@50Hz */ [20] = { NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, 0, }, /* #32: 1920x1080p@23.98/24Hz */ [32] = { NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0, }, /* #35: (2880)x480p4x@59.94/60Hz */ [35] = { - NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0, + FB_VMODE_NONINTERLACED, 0, }, }; @@ -340,10 +360,10 @@ const struct fb_videomode vesa_modes[] = { { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 3 640x480-60 VESA */ - { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 4 640x480-72 VESA */ - { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, + { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 5 640x480-75 VESA */ { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, @@ -426,7 +446,7 @@ const struct fb_videomode vesa_modes[] = { FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 26 1600x1200-75 VESA */ - { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 27 1600x1200-85 VESA */ -- cgit v1.2.3 From 0b2e9cb42cd0b5b0c95a776e30c9ecdff16587ea Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 11 Jan 2011 12:43:42 +0000 Subject: s3c2410fb: don't treat NULL clk as an error clk_get() returns a struct clk cookie to the driver and some platforms may return NULL if they only support a single clock. clk_get() has only failed if it returns a ERR_PTR() encoded pointer. Cc: Vincent Sanders Cc: linux-fbdev@vger.kernel.org Signed-off-by: Jamie Iles Signed-off-by: Paul Mundt --- drivers/video/s3c2410fb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 46b430978bcc..61c819e35f7f 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -918,9 +919,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, } info->clk = clk_get(NULL, "lcd"); - if (!info->clk || IS_ERR(info->clk)) { + if (IS_ERR(info->clk)) { printk(KERN_ERR "failed to get lcd clock source\n"); - ret = -ENOENT; + ret = PTR_ERR(info->clk); goto release_irq; } -- cgit v1.2.3 From ec03031707a348578c6ded277e5d92eb21de4fce Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 11 Jan 2011 12:43:43 +0000 Subject: nuc900fb: don't treat NULL clk as an error clk_get() returns a struct clk cookie to the driver and some platforms may return NULL if they only support a single clock. clk_get() has only failed if it returns a ERR_PTR() encoded pointer. Cc: linux-fbdev@vger.kernel.org Signed-off-by: Jamie Iles Acked-by: Wan ZongShun Signed-off-by: Paul Mundt --- drivers/video/nuc900fb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 81687ed26ba9..62498bd662fc 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -15,6 +15,7 @@ */ #include #include +#include #include #include #include @@ -597,9 +598,9 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev) } fbi->clk = clk_get(&pdev->dev, NULL); - if (!fbi->clk || IS_ERR(fbi->clk)) { + if (IS_ERR(fbi->clk)) { printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n"); - ret = -ENOENT; + ret = PTR_ERR(fbi->clk); goto release_irq; } -- cgit v1.2.3 From e3d5fb71e228c22ee1f78f19f19ef4e07f48f076 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 10 Jan 2011 09:47:41 -0200 Subject: video: imx: Update the manufacturer's name i.MX processors are currently manufactured by Freescale, not Motorola. Make the manufacturer's name consistent. Signed-off-by: Fabio Estevam Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 2 +- drivers/video/imxfb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c183faace63a..0a96a60bbe49 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -414,7 +414,7 @@ config FB_SA1100 Y here. config FB_IMX - tristate "Motorola i.MX LCD support" + tristate "Freescale i.MX LCD support" depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2) select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 1ab2c2588675..69bd4a581d4a 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -974,6 +974,6 @@ static void __exit imxfb_cleanup(void) module_init(imxfb_init); module_exit(imxfb_cleanup); -MODULE_DESCRIPTION("Motorola i.MX framebuffer driver"); +MODULE_DESCRIPTION("Freescale i.MX framebuffer driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 81e88fdc432a1552401d6e91a984dcccce72b8dc Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 12 Jan 2011 14:44:55 +0800 Subject: ACPI, APEI, Generic Hardware Error Source POLL/IRQ/NMI notification type support Generic Hardware Error Source provides a way to report platform hardware errors (such as that from chipset). It works in so called "Firmware First" mode, that is, hardware errors are reported to firmware firstly, then reported to Linux by firmware. This way, some non-standard hardware error registers or non-standard hardware link can be checked by firmware to produce more valuable hardware error information for Linux. This patch adds POLL/IRQ/NMI notification types support. Because the memory area used to transfer hardware error information from BIOS to Linux can be determined only in NMI, IRQ or timer handler, but general ioremap can not be used in atomic context, so a special version of atomic ioremap is implemented for that. Known issue: - Error information can not be printed for recoverable errors notified via NMI, because printk is not NMI-safe. Will fix this via delay printing to IRQ context via irq_work or make printk NMI-safe. v2: - adjust printk format per comments. Signed-off-by: Huang Ying Reviewed-by: Andi Kleen Signed-off-by: Len Brown --- arch/x86/kernel/acpi/boot.c | 1 + arch/x86/kernel/dumpstack.c | 1 + drivers/acpi/apei/ghes.c | 406 +++++++++++++++++++++++++++++++++++--------- kernel/panic.c | 1 + lib/ioremap.c | 2 + mm/vmalloc.c | 1 + 6 files changed, 328 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 71232b941b6c..c2d0baa48d8c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -504,6 +504,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) return 0; } +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi) { diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 6e8752c1bd52..d34cf80ec402 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -240,6 +240,7 @@ unsigned __kprobes long oops_begin(void) bust_spinlocks(1); return flags; } +EXPORT_SYMBOL_GPL(oops_begin); void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) { diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 51905d07a4d9..d1d484d4a06a 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -12,10 +12,6 @@ * For more information about Generic Hardware Error Source, please * refer to ACPI Specification version 4.0, section 17.3.2.6 * - * Now, only SCI notification type and memory errors are - * supported. More notification type and hardware error type will be - * added later. - * * Copyright 2010 Intel Corp. * Author: Huang Ying * @@ -39,15 +35,18 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include +#include #include "apei-internal.h" @@ -56,42 +55,131 @@ #define GHES_ESTATUS_MAX_SIZE 65536 /* - * One struct ghes is created for each generic hardware error - * source. - * + * One struct ghes is created for each generic hardware error source. * It provides the context for APEI hardware error timer/IRQ/SCI/NMI - * handler. Handler for one generic hardware error source is only - * triggered after the previous one is done. So handler can uses - * struct ghes without locking. + * handler. * * estatus: memory buffer for error status block, allocated during * HEST parsing. */ #define GHES_TO_CLEAR 0x0001 +#define GHES_EXITING 0x0002 struct ghes { struct acpi_hest_generic *generic; struct acpi_hest_generic_status *estatus; - struct list_head list; u64 buffer_paddr; unsigned long flags; + union { + struct list_head list; + struct timer_list timer; + unsigned int irq; + }; }; +static int ghes_panic_timeout __read_mostly = 30; + /* - * Error source lists, one list for each notification method. The - * members in lists are struct ghes. + * All error sources notified with SCI shares one notifier function, + * so they need to be linked and checked one by one. This is applied + * to NMI too. * - * The list members are only added in HEST parsing and deleted during - * module_exit, that is, single-threaded. So no lock is needed for - * that. - * - * But the mutual exclusion is needed between members adding/deleting - * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is - * used for that. + * RCU is used for these lists, so ghes_list_mutex is only used for + * list changing, not for traversing. */ static LIST_HEAD(ghes_sci); +static LIST_HEAD(ghes_nmi); static DEFINE_MUTEX(ghes_list_mutex); +/* + * NMI may be triggered on any CPU, so ghes_nmi_lock is used for + * mutual exclusion. + */ +static DEFINE_RAW_SPINLOCK(ghes_nmi_lock); + +/* + * Because the memory area used to transfer hardware error information + * from BIOS to Linux can be determined only in NMI, IRQ or timer + * handler, but general ioremap can not be used in atomic context, so + * a special version of atomic ioremap is implemented for that. + */ + +/* + * Two virtual pages are used, one for NMI context, the other for + * IRQ/PROCESS context + */ +#define GHES_IOREMAP_PAGES 2 +#define GHES_IOREMAP_NMI_PAGE(base) (base) +#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE) + +/* virtual memory area for atomic ioremap */ +static struct vm_struct *ghes_ioremap_area; +/* + * These 2 spinlock is used to prevent atomic ioremap virtual memory + * area from being mapped simultaneously. + */ +static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi); +static DEFINE_SPINLOCK(ghes_ioremap_lock_irq); + +static int ghes_ioremap_init(void) +{ + ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES, + VM_IOREMAP, VMALLOC_START, VMALLOC_END); + if (!ghes_ioremap_area) { + pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n"); + return -ENOMEM; + } + + return 0; +} + +static void ghes_ioremap_exit(void) +{ + free_vm_area(ghes_ioremap_area); +} + +static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) +{ + unsigned long vaddr; + + vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr); + ioremap_page_range(vaddr, vaddr + PAGE_SIZE, + pfn << PAGE_SHIFT, PAGE_KERNEL); + + return (void __iomem *)vaddr; +} + +static void __iomem *ghes_ioremap_pfn_irq(u64 pfn) +{ + unsigned long vaddr; + + vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr); + ioremap_page_range(vaddr, vaddr + PAGE_SIZE, + pfn << PAGE_SHIFT, PAGE_KERNEL); + + return (void __iomem *)vaddr; +} + +static void ghes_iounmap_nmi(void __iomem *vaddr_ptr) +{ + unsigned long vaddr = (unsigned long __force)vaddr_ptr; + void *base = ghes_ioremap_area->addr; + + BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base)); + unmap_kernel_range_noflush(vaddr, PAGE_SIZE); + __flush_tlb_one(vaddr); +} + +static void ghes_iounmap_irq(void __iomem *vaddr_ptr) +{ + unsigned long vaddr = (unsigned long __force)vaddr_ptr; + void *base = ghes_ioremap_area->addr; + + BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base)); + unmap_kernel_range_noflush(vaddr, PAGE_SIZE); + __flush_tlb_one(vaddr); +} + static struct ghes *ghes_new(struct acpi_hest_generic *generic) { struct ghes *ghes; @@ -102,7 +190,6 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) if (!ghes) return ERR_PTR(-ENOMEM); ghes->generic = generic; - INIT_LIST_HEAD(&ghes->list); rc = acpi_pre_map_gar(&generic->error_status_address); if (rc) goto err_free; @@ -159,22 +246,41 @@ static inline int ghes_severity(int severity) } } -/* SCI handler run in work queue, so ioremap can be used here */ -static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len, - int from_phys) +static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len, + int from_phys) { - void *vaddr; - - vaddr = ioremap_cache(paddr, len); - if (!vaddr) - return -ENOMEM; - if (from_phys) - memcpy(buffer, vaddr, len); - else - memcpy(vaddr, buffer, len); - iounmap(vaddr); - - return 0; + void __iomem *vaddr; + unsigned long flags = 0; + int in_nmi = in_nmi(); + u64 offset; + u32 trunk; + + while (len > 0) { + offset = paddr - (paddr & PAGE_MASK); + if (in_nmi) { + raw_spin_lock(&ghes_ioremap_lock_nmi); + vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT); + } else { + spin_lock_irqsave(&ghes_ioremap_lock_irq, flags); + vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT); + } + trunk = PAGE_SIZE - offset; + trunk = min(trunk, len); + if (from_phys) + memcpy_fromio(buffer, vaddr + offset, trunk); + else + memcpy_toio(vaddr + offset, buffer, trunk); + len -= trunk; + paddr += trunk; + buffer += trunk; + if (in_nmi) { + ghes_iounmap_nmi(vaddr); + raw_spin_unlock(&ghes_ioremap_lock_nmi); + } else { + ghes_iounmap_irq(vaddr); + spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags); + } + } } static int ghes_read_estatus(struct ghes *ghes, int silent) @@ -195,10 +301,8 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) if (!buf_paddr) return -ENOENT; - rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr, - sizeof(*ghes->estatus), 1); - if (rc) - return rc; + ghes_copy_tofrom_phys(ghes->estatus, buf_paddr, + sizeof(*ghes->estatus), 1); if (!ghes->estatus->block_status) return -ENOENT; @@ -213,17 +317,15 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) goto err_read_block; if (apei_estatus_check_header(ghes->estatus)) goto err_read_block; - rc = ghes_copy_tofrom_phys(ghes->estatus + 1, - buf_paddr + sizeof(*ghes->estatus), - len - sizeof(*ghes->estatus), 1); - if (rc) - return rc; + ghes_copy_tofrom_phys(ghes->estatus + 1, + buf_paddr + sizeof(*ghes->estatus), + len - sizeof(*ghes->estatus), 1); if (apei_estatus_check(ghes->estatus)) goto err_read_block; rc = 0; err_read_block: - if (rc && !silent) + if (rc && !silent && printk_ratelimit()) pr_warning(FW_WARN GHES_PFX "Failed to read error status block!\n"); return rc; @@ -293,6 +395,42 @@ out: return 0; } +static void ghes_add_timer(struct ghes *ghes) +{ + struct acpi_hest_generic *g = ghes->generic; + unsigned long expire; + + if (!g->notify.poll_interval) { + pr_warning(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n", + g->header.source_id); + return; + } + expire = jiffies + msecs_to_jiffies(g->notify.poll_interval); + ghes->timer.expires = round_jiffies_relative(expire); + add_timer(&ghes->timer); +} + +static void ghes_poll_func(unsigned long data) +{ + struct ghes *ghes = (void *)data; + + ghes_proc(ghes); + if (!(ghes->flags & GHES_EXITING)) + ghes_add_timer(ghes); +} + +static irqreturn_t ghes_irq_func(int irq, void *data) +{ + struct ghes *ghes = data; + int rc; + + rc = ghes_proc(ghes); + if (rc) + return IRQ_NONE; + + return IRQ_HANDLED; +} + static int ghes_notify_sci(struct notifier_block *this, unsigned long event, void *data) { @@ -309,10 +447,63 @@ static int ghes_notify_sci(struct notifier_block *this, return ret; } +static int ghes_notify_nmi(struct notifier_block *this, + unsigned long cmd, void *data) +{ + struct ghes *ghes, *ghes_global = NULL; + int sev, sev_global = -1; + int ret = NOTIFY_DONE; + + if (cmd != DIE_NMI) + return ret; + + raw_spin_lock(&ghes_nmi_lock); + list_for_each_entry_rcu(ghes, &ghes_nmi, list) { + if (ghes_read_estatus(ghes, 1)) { + ghes_clear_estatus(ghes); + continue; + } + sev = ghes_severity(ghes->estatus->error_severity); + if (sev > sev_global) { + sev_global = sev; + ghes_global = ghes; + } + ret = NOTIFY_STOP; + } + + if (ret == NOTIFY_DONE) + goto out; + + if (sev_global >= GHES_SEV_PANIC) { + oops_begin(); + ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global); + /* reboot to log the error! */ + if (panic_timeout == 0) + panic_timeout = ghes_panic_timeout; + panic("Fatal hardware error!"); + } + + list_for_each_entry_rcu(ghes, &ghes_nmi, list) { + if (!(ghes->flags & GHES_TO_CLEAR)) + continue; + /* Do not print estatus because printk is not NMI safe */ + ghes_do_proc(ghes); + ghes_clear_estatus(ghes); + } + +out: + raw_spin_unlock(&ghes_nmi_lock); + return ret; +} + static struct notifier_block ghes_notifier_sci = { .notifier_call = ghes_notify_sci, }; +static struct notifier_block ghes_notifier_nmi = { + .notifier_call = ghes_notify_nmi, +}; + static int __devinit ghes_probe(struct platform_device *ghes_dev) { struct acpi_hest_generic *generic; @@ -323,18 +514,27 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev) if (!generic->enabled) return -ENODEV; - if (generic->error_block_length < - sizeof(struct acpi_hest_generic_status)) { - pr_warning(FW_BUG GHES_PFX -"Invalid error block length: %u for generic hardware error source: %d\n", - generic->error_block_length, + switch (generic->notify.type) { + case ACPI_HEST_NOTIFY_POLLED: + case ACPI_HEST_NOTIFY_EXTERNAL: + case ACPI_HEST_NOTIFY_SCI: + case ACPI_HEST_NOTIFY_NMI: + break; + case ACPI_HEST_NOTIFY_LOCAL: + pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n", generic->header.source_id); goto err; + default: + pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n", + generic->notify.type, generic->header.source_id); + goto err; } - if (generic->records_to_preallocate == 0) { - pr_warning(FW_BUG GHES_PFX -"Invalid records to preallocate: %u for generic hardware error source: %d\n", - generic->records_to_preallocate, + + rc = -EIO; + if (generic->error_block_length < + sizeof(struct acpi_hest_generic_status)) { + pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n", + generic->error_block_length, generic->header.source_id); goto err; } @@ -344,38 +544,43 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev) ghes = NULL; goto err; } - if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) { + switch (generic->notify.type) { + case ACPI_HEST_NOTIFY_POLLED: + ghes->timer.function = ghes_poll_func; + ghes->timer.data = (unsigned long)ghes; + init_timer_deferrable(&ghes->timer); + ghes_add_timer(ghes); + break; + case ACPI_HEST_NOTIFY_EXTERNAL: + /* External interrupt vector is GSI */ + if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) { + pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n", + generic->header.source_id); + goto err; + } + if (request_irq(ghes->irq, ghes_irq_func, + 0, "GHES IRQ", ghes)) { + pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", + generic->header.source_id); + goto err; + } + break; + case ACPI_HEST_NOTIFY_SCI: mutex_lock(&ghes_list_mutex); if (list_empty(&ghes_sci)) register_acpi_hed_notifier(&ghes_notifier_sci); list_add_rcu(&ghes->list, &ghes_sci); mutex_unlock(&ghes_list_mutex); - } else { - unsigned char *notify = NULL; - - switch (generic->notify.type) { - case ACPI_HEST_NOTIFY_POLLED: - notify = "POLL"; - break; - case ACPI_HEST_NOTIFY_EXTERNAL: - case ACPI_HEST_NOTIFY_LOCAL: - notify = "IRQ"; - break; - case ACPI_HEST_NOTIFY_NMI: - notify = "NMI"; - break; - } - if (notify) { - pr_warning(GHES_PFX -"Generic hardware error source: %d notified via %s is not supported!\n", - generic->header.source_id, notify); - } else { - pr_warning(FW_WARN GHES_PFX -"Unknown notification type: %u for generic hardware error source: %d\n", - generic->notify.type, generic->header.source_id); - } - rc = -ENODEV; - goto err; + break; + case ACPI_HEST_NOTIFY_NMI: + mutex_lock(&ghes_list_mutex); + if (list_empty(&ghes_nmi)) + register_die_notifier(&ghes_notifier_nmi); + list_add_rcu(&ghes->list, &ghes_nmi); + mutex_unlock(&ghes_list_mutex); + break; + default: + BUG(); } platform_set_drvdata(ghes_dev, ghes); @@ -396,7 +601,14 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev) ghes = platform_get_drvdata(ghes_dev); generic = ghes->generic; + ghes->flags |= GHES_EXITING; switch (generic->notify.type) { + case ACPI_HEST_NOTIFY_POLLED: + del_timer_sync(&ghes->timer); + break; + case ACPI_HEST_NOTIFY_EXTERNAL: + free_irq(ghes->irq, ghes); + break; case ACPI_HEST_NOTIFY_SCI: mutex_lock(&ghes_list_mutex); list_del_rcu(&ghes->list); @@ -404,12 +616,23 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev) unregister_acpi_hed_notifier(&ghes_notifier_sci); mutex_unlock(&ghes_list_mutex); break; + case ACPI_HEST_NOTIFY_NMI: + mutex_lock(&ghes_list_mutex); + list_del_rcu(&ghes->list); + if (list_empty(&ghes_nmi)) + unregister_die_notifier(&ghes_notifier_nmi); + mutex_unlock(&ghes_list_mutex); + /* + * To synchronize with NMI handler, ghes can only be + * freed after NMI handler finishes. + */ + synchronize_rcu(); + break; default: BUG(); break; } - synchronize_rcu(); ghes_fini(ghes); kfree(ghes); @@ -429,6 +652,8 @@ static struct platform_driver ghes_platform_driver = { static int __init ghes_init(void) { + int rc; + if (acpi_disabled) return -ENODEV; @@ -437,12 +662,25 @@ static int __init ghes_init(void) return -EINVAL; } - return platform_driver_register(&ghes_platform_driver); + rc = ghes_ioremap_init(); + if (rc) + goto err; + + rc = platform_driver_register(&ghes_platform_driver); + if (rc) + goto err_ioremap_exit; + + return 0; +err_ioremap_exit: + ghes_ioremap_exit(); +err: + return rc; } static void __exit ghes_exit(void) { platform_driver_unregister(&ghes_platform_driver); + ghes_ioremap_exit(); } module_init(ghes_init); diff --git a/kernel/panic.c b/kernel/panic.c index 4c13b1a88ebb..991bb87a1704 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -34,6 +34,7 @@ static int pause_on_oops_flag; static DEFINE_SPINLOCK(pause_on_oops_lock); int panic_timeout; +EXPORT_SYMBOL_GPL(panic_timeout); ATOMIC_NOTIFIER_HEAD(panic_notifier_list); diff --git a/lib/ioremap.c b/lib/ioremap.c index 5730ecd3eb66..da4e2ad74b68 100644 --- a/lib/ioremap.c +++ b/lib/ioremap.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -90,3 +91,4 @@ int ioremap_page_range(unsigned long addr, return err; } +EXPORT_SYMBOL_GPL(ioremap_page_range); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index eb5cc7d00c5a..816f074fb4e1 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1175,6 +1175,7 @@ void unmap_kernel_range_noflush(unsigned long addr, unsigned long size) { vunmap_page_range(addr, addr + size); } +EXPORT_SYMBOL_GPL(unmap_kernel_range_noflush); /** * unmap_kernel_range - unmap kernel VM area and flush cache and TLB -- cgit v1.2.3 From b17295e646562a2122ce84c1e55c9ae66fb6ae50 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 12 Jan 2011 09:55:10 +0100 Subject: [S390] cio: path_event overindication after resume While resuming report any found paths as new to the device drivers. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e8391b89eff4..b7eaff9ca19e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1835,6 +1835,7 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev) * available again. Kick re-detection. */ cdev->private->flags.resuming = 1; + cdev->private->path_new_mask = LPM_ANYPATH; css_schedule_eval(sch->schid); spin_unlock_irq(sch->lock); css_complete_work(); -- cgit v1.2.3 From 3cfd53d53f700a225716294842b1a843326dea21 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:36:02 +0800 Subject: ACPICA: Move GPE functions to new file evxfgpe.c Create a new file evxfgpe.c and move GPE specific functions to it. Acked-by: Rafael J. Wysocki Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/Makefile | 2 +- drivers/acpi/acpica/acevents.h | 4 + drivers/acpi/acpica/evgpeutil.c | 39 +++ drivers/acpi/acpica/evxfevnt.c | 600 --------------------------------------- drivers/acpi/acpica/evxfgpe.c | 610 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 654 insertions(+), 601 deletions(-) create mode 100644 drivers/acpi/acpica/evxfgpe.c (limited to 'drivers') diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index a7e1d1aa4107..eec2eadd2431 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -14,7 +14,7 @@ acpi-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ acpi-y += evevent.o evregion.o evsci.o evxfevnt.o \ evmisc.o evrgnini.o evxface.o evxfregn.o \ - evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o + evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o evxfgpe.o acpi-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index a6f99cc37a19..43f15c8cd2b2 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -138,6 +138,10 @@ acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context); u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info); +acpi_status +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); + struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number); acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt); diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 19a0e513ea48..10e477494dcf 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -152,6 +152,45 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) return (FALSE); } +/******************************************************************************* + * + * FUNCTION: acpi_ev_get_gpe_device + * + * PARAMETERS: GPE_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE + * block device. NULL if the GPE is one of the FADT-defined GPEs. + * + ******************************************************************************/ + +acpi_status +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) +{ + struct acpi_gpe_device_info *info = context; + + /* Increment Index by the number of GPEs in this block */ + + info->next_block_base_index += gpe_block->gpe_count; + + if (info->index < info->next_block_base_index) { + /* + * The GPE index is within this block, get the node. Leave the node + * NULL for the FADT-defined GPEs + */ + if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) { + info->gpe_device = gpe_block->node; + } + + info->status = AE_OK; + return (AE_CTRL_END); + } + + return (AE_OK); +} + /******************************************************************************* * * FUNCTION: acpi_ev_get_gpe_xrupt_block diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index a1dabe3fd8ae..90488c1e0f3d 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -43,18 +43,11 @@ #include #include "accommon.h" -#include "acevents.h" -#include "acnamesp.h" #include "actables.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfevnt") -/* Local prototypes */ -static acpi_status -acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context); - /******************************************************************************* * * FUNCTION: acpi_enable @@ -211,185 +204,6 @@ acpi_status acpi_enable_event(u32 event, u32 flags) ACPI_EXPORT_SYMBOL(acpi_enable_event) -/******************************************************************************* - * - * FUNCTION: acpi_gpe_wakeup - * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block - * Action - Enable or Disable - * - * RETURN: Status - * - * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. - * - ******************************************************************************/ -acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action) -{ - acpi_status status = AE_OK; - struct acpi_gpe_event_info *gpe_event_info; - struct acpi_gpe_register_info *gpe_register_info; - acpi_cpu_flags flags; - u32 register_bit; - - ACPI_FUNCTION_TRACE(acpi_gpe_wakeup); - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - status = AE_NOT_EXIST; - goto unlock_and_exit; - } - - register_bit = - acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); - - /* Perform the action */ - - switch (action) { - case ACPI_GPE_ENABLE: - ACPI_SET_BIT(gpe_register_info->enable_for_wake, - (u8)register_bit); - break; - - case ACPI_GPE_DISABLE: - ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, - (u8)register_bit); - break; - - default: - ACPI_ERROR((AE_INFO, "%u, Invalid action", action)); - status = AE_BAD_PARAMETER; - break; - } - -unlock_and_exit: - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup) - -/******************************************************************************* - * - * FUNCTION: acpi_enable_gpe - * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block - * - * RETURN: Status - * - * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is - * hardware-enabled. - * - ******************************************************************************/ -acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) -{ - acpi_status status = AE_BAD_PARAMETER; - struct acpi_gpe_event_info *gpe_event_info; - acpi_cpu_flags flags; - - ACPI_FUNCTION_TRACE(acpi_enable_gpe); - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (gpe_event_info) { - status = acpi_raw_enable_gpe(gpe_event_info); - } - - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - return_ACPI_STATUS(status); -} -ACPI_EXPORT_SYMBOL(acpi_enable_gpe) - -/******************************************************************************* - * - * FUNCTION: acpi_disable_gpe - * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block - * - * RETURN: Status - * - * DESCRIPTION: Remove a reference to a GPE. When the last reference is - * removed, only then is the GPE disabled (for runtime GPEs), or - * the GPE mask bit disabled (for wake GPEs) - * - ******************************************************************************/ -acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) -{ - acpi_status status = AE_BAD_PARAMETER; - struct acpi_gpe_event_info *gpe_event_info; - acpi_cpu_flags flags; - - ACPI_FUNCTION_TRACE(acpi_disable_gpe); - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (gpe_event_info) { - status = acpi_raw_disable_gpe(gpe_event_info) ; - } - - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - return_ACPI_STATUS(status); -} -ACPI_EXPORT_SYMBOL(acpi_disable_gpe) - -/******************************************************************************* - * - * FUNCTION: acpi_gpe_can_wake - * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block - * - * RETURN: Status - * - * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE - * has a corresponding method and is currently enabled, disable it - * (GPEs with corresponding methods are enabled unconditionally - * during initialization, but GPEs that can wake up are expected - * to be initially disabled). - * - ******************************************************************************/ -acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) -{ - acpi_status status = AE_OK; - struct acpi_gpe_event_info *gpe_event_info; - acpi_cpu_flags flags; - - ACPI_FUNCTION_TRACE(acpi_gpe_can_wake); - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (gpe_event_info) { - gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; - } else { - status = AE_BAD_PARAMETER; - } - - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - return_ACPI_STATUS(status); -} -ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake) - /******************************************************************************* * * FUNCTION: acpi_disable_event @@ -481,44 +295,6 @@ acpi_status acpi_clear_event(u32 event) ACPI_EXPORT_SYMBOL(acpi_clear_event) -/******************************************************************************* - * - * FUNCTION: acpi_clear_gpe - * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block - * - * RETURN: Status - * - * DESCRIPTION: Clear an ACPI event (general purpose) - * - ******************************************************************************/ -acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number) -{ - acpi_status status = AE_OK; - struct acpi_gpe_event_info *gpe_event_info; - acpi_cpu_flags flags; - - ACPI_FUNCTION_TRACE(acpi_clear_gpe); - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (!gpe_event_info) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - status = acpi_hw_clear_gpe(gpe_event_info); - - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_clear_gpe) /******************************************************************************* * * FUNCTION: acpi_get_event_status @@ -575,379 +351,3 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) } ACPI_EXPORT_SYMBOL(acpi_get_event_status) - -/******************************************************************************* - * - * FUNCTION: acpi_get_gpe_status - * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block - * event_status - Where the current status of the event will - * be returned - * - * RETURN: Status - * - * DESCRIPTION: Get status of an event (general purpose) - * - ******************************************************************************/ -acpi_status -acpi_get_gpe_status(acpi_handle gpe_device, - u32 gpe_number, acpi_event_status *event_status) -{ - acpi_status status = AE_OK; - struct acpi_gpe_event_info *gpe_event_info; - acpi_cpu_flags flags; - - ACPI_FUNCTION_TRACE(acpi_get_gpe_status); - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (!gpe_event_info) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - /* Obtain status on the requested GPE number */ - - status = acpi_hw_get_gpe_status(gpe_event_info, event_status); - - if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) - *event_status |= ACPI_EVENT_FLAG_HANDLE; - - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) -/******************************************************************************* - * - * FUNCTION: acpi_install_gpe_block - * - * PARAMETERS: gpe_device - Handle to the parent GPE Block Device - * gpe_block_address - Address and space_iD - * register_count - Number of GPE register pairs in the block - * interrupt_number - H/W interrupt for the block - * - * RETURN: Status - * - * DESCRIPTION: Create and Install a block of GPE registers - * - ******************************************************************************/ -acpi_status -acpi_install_gpe_block(acpi_handle gpe_device, - struct acpi_generic_address *gpe_block_address, - u32 register_count, u32 interrupt_number) -{ - acpi_status status = AE_OK; - union acpi_operand_object *obj_desc; - struct acpi_namespace_node *node; - struct acpi_gpe_block_info *gpe_block; - - ACPI_FUNCTION_TRACE(acpi_install_gpe_block); - - if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - - node = acpi_ns_validate_handle(gpe_device); - if (!node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - /* - * For user-installed GPE Block Devices, the gpe_block_base_number - * is always zero - */ - status = - acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, - interrupt_number, &gpe_block); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - - /* Install block in the device_object attached to the node */ - - obj_desc = acpi_ns_get_attached_object(node); - if (!obj_desc) { - - /* - * No object, create a new one (Device nodes do not always have - * an attached object) - */ - obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } - - status = - acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE); - - /* Remove local reference to the object */ - - acpi_ut_remove_reference(obj_desc); - - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - } - - /* Now install the GPE block in the device_object */ - - obj_desc->device.gpe_block = gpe_block; - - unlock_and_exit: - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_install_gpe_block) - -/******************************************************************************* - * - * FUNCTION: acpi_remove_gpe_block - * - * PARAMETERS: gpe_device - Handle to the parent GPE Block Device - * - * RETURN: Status - * - * DESCRIPTION: Remove a previously installed block of GPE registers - * - ******************************************************************************/ -acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) -{ - union acpi_operand_object *obj_desc; - acpi_status status; - struct acpi_namespace_node *node; - - ACPI_FUNCTION_TRACE(acpi_remove_gpe_block); - - if (!gpe_device) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - - node = acpi_ns_validate_handle(gpe_device); - if (!node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - /* Get the device_object attached to the node */ - - obj_desc = acpi_ns_get_attached_object(node); - if (!obj_desc || !obj_desc->device.gpe_block) { - return_ACPI_STATUS(AE_NULL_OBJECT); - } - - /* Delete the GPE block (but not the device_object) */ - - status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block); - if (ACPI_SUCCESS(status)) { - obj_desc->device.gpe_block = NULL; - } - - unlock_and_exit: - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) - -/******************************************************************************* - * - * FUNCTION: acpi_get_gpe_device - * - * PARAMETERS: Index - System GPE index (0-current_gpe_count) - * gpe_device - Where the parent GPE Device is returned - * - * RETURN: Status - * - * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL - * gpe device indicates that the gpe number is contained in one of - * the FADT-defined gpe blocks. Otherwise, the GPE block device. - * - ******************************************************************************/ -acpi_status -acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) -{ - struct acpi_gpe_device_info info; - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_get_gpe_device); - - if (!gpe_device) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (index >= acpi_current_gpe_count) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* Setup and walk the GPE list */ - - info.index = index; - info.status = AE_NOT_EXIST; - info.gpe_device = NULL; - info.next_block_base_index = 0; - - status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - *gpe_device = info.gpe_device; - return_ACPI_STATUS(info.status); -} - -ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) - -/******************************************************************************* - * - * FUNCTION: acpi_ev_get_gpe_device - * - * PARAMETERS: GPE_WALK_CALLBACK - * - * RETURN: Status - * - * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE - * block device. NULL if the GPE is one of the FADT-defined GPEs. - * - ******************************************************************************/ -static acpi_status -acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context) -{ - struct acpi_gpe_device_info *info = context; - - /* Increment Index by the number of GPEs in this block */ - - info->next_block_base_index += gpe_block->gpe_count; - - if (info->index < info->next_block_base_index) { - /* - * The GPE index is within this block, get the node. Leave the node - * NULL for the FADT-defined GPEs - */ - if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) { - info->gpe_device = gpe_block->node; - } - - info->status = AE_OK; - return (AE_CTRL_END); - } - - return (AE_OK); -} - -/****************************************************************************** - * - * FUNCTION: acpi_disable_all_gpes - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Disable and clear all GPEs in all GPE blocks - * - ******************************************************************************/ - -acpi_status acpi_disable_all_gpes(void) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_disable_all_gpes); - - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - status = acpi_hw_disable_all_gpes(); - (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); - - return_ACPI_STATUS(status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_enable_all_runtime_gpes - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks - * - ******************************************************************************/ - -acpi_status acpi_enable_all_runtime_gpes(void) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes); - - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - status = acpi_hw_enable_all_runtime_gpes(); - (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); - - return_ACPI_STATUS(status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_update_gpes - * - * PARAMETERS: None - * - * RETURN: None - * - * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and - * are not pointed to by any device _PRW methods indicating that - * these GPEs are generally intended for system or device wakeup - * (such GPEs have to be enabled directly when the devices whose - * _PRW methods point to them are set up for wakeup signaling). - * - ******************************************************************************/ - -acpi_status acpi_update_gpes(void) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_update_gpes); - - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } else if (acpi_all_gpes_initialized) { - goto unlock; - } - - status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL); - if (ACPI_SUCCESS(status)) { - acpi_all_gpes_initialized = TRUE; - } - -unlock: - (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); - - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c new file mode 100644 index 000000000000..8068065d90eb --- /dev/null +++ b/drivers/acpi/acpica/evxfgpe.c @@ -0,0 +1,610 @@ +/****************************************************************************** + * + * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2010, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_EVENTS +ACPI_MODULE_NAME("evxfgpe") + +/****************************************************************************** + * + * FUNCTION: acpi_update_gpes + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and + * are not pointed to by any device _PRW methods indicating that + * these GPEs are generally intended for system or device wakeup + * (such GPEs have to be enabled directly when the devices whose + * _PRW methods point to them are set up for wakeup signaling). + * + ******************************************************************************/ + +acpi_status acpi_update_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_update_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } else if (acpi_all_gpes_initialized) { + goto unlock; + } + + status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL); + if (ACPI_SUCCESS(status)) { + acpi_all_gpes_initialized = TRUE; + } + +unlock: + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_enable_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is + * hardware-enabled. + * + ******************************************************************************/ + +acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + acpi_status status = AE_BAD_PARAMETER; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_enable_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (gpe_event_info) { + status = acpi_raw_enable_gpe(gpe_event_info); + } + + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} +ACPI_EXPORT_SYMBOL(acpi_enable_gpe) + +/******************************************************************************* + * + * FUNCTION: acpi_disable_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Remove a reference to a GPE. When the last reference is + * removed, only then is the GPE disabled (for runtime GPEs), or + * the GPE mask bit disabled (for wake GPEs) + * + ******************************************************************************/ + +acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + acpi_status status = AE_BAD_PARAMETER; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_disable_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (gpe_event_info) { + status = acpi_raw_disable_gpe(gpe_event_info) ; + } + + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} +ACPI_EXPORT_SYMBOL(acpi_disable_gpe) + +/******************************************************************************* + * + * FUNCTION: acpi_gpe_can_wake + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE + * has a corresponding method and is currently enabled, disable it + * (GPEs with corresponding methods are enabled unconditionally + * during initialization, but GPEs that can wake up are expected + * to be initially disabled). + * + ******************************************************************************/ +acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_gpe_can_wake); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (gpe_event_info) { + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; + } else { + status = AE_BAD_PARAMETER; + } + + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} +ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake) + +/******************************************************************************* + * + * FUNCTION: acpi_gpe_wakeup + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * Action - Enable or Disable + * + * RETURN: Status + * + * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. + * + ******************************************************************************/ + +acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; + struct acpi_gpe_register_info *gpe_register_info; + acpi_cpu_flags flags; + u32 register_bit; + + ACPI_FUNCTION_TRACE(acpi_gpe_wakeup); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + gpe_register_info = gpe_event_info->register_info; + if (!gpe_register_info) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + register_bit = + acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); + + /* Perform the action */ + + switch (action) { + case ACPI_GPE_ENABLE: + ACPI_SET_BIT(gpe_register_info->enable_for_wake, + (u8)register_bit); + break; + + case ACPI_GPE_DISABLE: + ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, + (u8)register_bit); + break; + + default: + ACPI_ERROR((AE_INFO, "%u, Invalid action", action)); + status = AE_BAD_PARAMETER; + break; + } + +unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup) + +/******************************************************************************* + * + * FUNCTION: acpi_clear_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Clear an ACPI event (general purpose) + * + ******************************************************************************/ +acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_clear_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_hw_clear_gpe(gpe_event_info); + + unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_clear_gpe) + +/******************************************************************************* + * + * FUNCTION: acpi_get_gpe_status + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * event_status - Where the current status of the event will + * be returned + * + * RETURN: Status + * + * DESCRIPTION: Get status of an event (general purpose) + * + ******************************************************************************/ +acpi_status +acpi_get_gpe_status(acpi_handle gpe_device, + u32 gpe_number, acpi_event_status *event_status) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_get_gpe_status); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Obtain status on the requested GPE number */ + + status = acpi_hw_get_gpe_status(gpe_event_info, event_status); + + if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) + *event_status |= ACPI_EVENT_FLAG_HANDLE; + + unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) + +/****************************************************************************** + * + * FUNCTION: acpi_disable_all_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks + * + ******************************************************************************/ + +acpi_status acpi_disable_all_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_disable_all_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_hw_disable_all_gpes(); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_enable_all_runtime_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks + * + ******************************************************************************/ + +acpi_status acpi_enable_all_runtime_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_hw_enable_all_runtime_gpes(); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_install_gpe_block + * + * PARAMETERS: gpe_device - Handle to the parent GPE Block Device + * gpe_block_address - Address and space_iD + * register_count - Number of GPE register pairs in the block + * interrupt_number - H/W interrupt for the block + * + * RETURN: Status + * + * DESCRIPTION: Create and Install a block of GPE registers + * + ******************************************************************************/ +acpi_status +acpi_install_gpe_block(acpi_handle gpe_device, + struct acpi_generic_address *gpe_block_address, + u32 register_count, u32 interrupt_number) +{ + acpi_status status = AE_OK; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node; + struct acpi_gpe_block_info *gpe_block; + + ACPI_FUNCTION_TRACE(acpi_install_gpe_block); + + if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return (status); + } + + node = acpi_ns_validate_handle(gpe_device); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* + * For user-installed GPE Block Devices, the gpe_block_base_number + * is always zero + */ + status = + acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, + interrupt_number, &gpe_block); + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + + /* Install block in the device_object attached to the node */ + + obj_desc = acpi_ns_get_attached_object(node); + if (!obj_desc) { + + /* + * No object, create a new one (Device nodes do not always have + * an attached object) + */ + obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + status = + acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference(obj_desc); + + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + } + + /* Now install the GPE block in the device_object */ + + obj_desc->device.gpe_block = gpe_block; + + unlock_and_exit: + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_install_gpe_block) + +/******************************************************************************* + * + * FUNCTION: acpi_remove_gpe_block + * + * PARAMETERS: gpe_device - Handle to the parent GPE Block Device + * + * RETURN: Status + * + * DESCRIPTION: Remove a previously installed block of GPE registers + * + ******************************************************************************/ +acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + struct acpi_namespace_node *node; + + ACPI_FUNCTION_TRACE(acpi_remove_gpe_block); + + if (!gpe_device) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return (status); + } + + node = acpi_ns_validate_handle(gpe_device); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Get the device_object attached to the node */ + + obj_desc = acpi_ns_get_attached_object(node); + if (!obj_desc || !obj_desc->device.gpe_block) { + return_ACPI_STATUS(AE_NULL_OBJECT); + } + + /* Delete the GPE block (but not the device_object) */ + + status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block); + if (ACPI_SUCCESS(status)) { + obj_desc->device.gpe_block = NULL; + } + + unlock_and_exit: + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) + +/******************************************************************************* + * + * FUNCTION: acpi_get_gpe_device + * + * PARAMETERS: Index - System GPE index (0-current_gpe_count) + * gpe_device - Where the parent GPE Device is returned + * + * RETURN: Status + * + * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL + * gpe device indicates that the gpe number is contained in one of + * the FADT-defined gpe blocks. Otherwise, the GPE block device. + * + ******************************************************************************/ +acpi_status +acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) +{ + struct acpi_gpe_device_info info; + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_get_gpe_device); + + if (!gpe_device) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (index >= acpi_current_gpe_count) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + + /* Setup and walk the GPE list */ + + info.index = index; + info.status = AE_NOT_EXIST; + info.gpe_device = NULL; + info.next_block_base_index = 0; + + status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + *gpe_device = info.gpe_device; + return_ACPI_STATUS(info.status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) -- cgit v1.2.3 From 3a37898d507794cfc68a092303e02651d3f01308 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:36:15 +0800 Subject: ACPICA: Rename some function and variable names Some function and variable names are renamed to be consistent with ACPICA code base. acpi_raw_enable_gpe -> acpi_ev_add_gpe_reference acpi_raw_disable_gpe -> acpi_ev_remove_gpe_reference acpi_gpe_can_wake -> acpi_setup_gpe_for_wake acpi_gpe_wakeup -> acpi_set_gpe_wake_mask acpi_update_gpes -> acpi_update_all_gpes acpi_all_gpes_initialized -> acpi_gbl_all_gpes_initialized acpi_handler_info -> acpi_gpe_handler_info ... Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acevents.h | 6 ++--- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/aclocal.h | 8 +++---- drivers/acpi/acpica/evgpe.c | 14 +++++++---- drivers/acpi/acpica/evgpeblk.c | 4 ++-- drivers/acpi/acpica/evxface.c | 16 ++++++------- drivers/acpi/acpica/evxfgpe.c | 53 ++++++++++++++++++++++++++---------------- drivers/acpi/acpica/hwgpe.c | 2 +- drivers/acpi/acpica/utglobal.c | 2 +- drivers/acpi/dock.c | 2 +- drivers/acpi/scan.c | 6 ++--- drivers/acpi/wakeup.c | 4 ++-- include/acpi/acpixf.h | 6 ++--- include/acpi/actypes.h | 4 ++-- 14 files changed, 73 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 43f15c8cd2b2..ce2af07f62b3 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -82,9 +82,9 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); +acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_raw_disable_gpe(struct acpi_gpe_event_info *gpe_event_info); +acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, u32 gpe_number); @@ -107,7 +107,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, acpi_status acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, - void *ignored); + void *context); acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index ad88fcae4eb9..fc694647699f 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -370,7 +370,7 @@ ACPI_EXTERN struct acpi_fixed_event_handler ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head; ACPI_EXTERN struct acpi_gpe_block_info *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; -ACPI_EXTERN u8 acpi_all_gpes_initialized; +ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized; /***************************************************************************** * diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2ceb0c05b2d7..2f841d019a3a 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -412,13 +412,13 @@ struct acpi_handler_info { acpi_event_handler address; /* Address of handler, if any */ void *context; /* Context to be passed to handler */ struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ - u8 orig_flags; /* Original misc info about this GPE */ - u8 orig_enabled; /* Set if the GPE was originally enabled */ + u8 original_flags; /* Original (pre-handler) GPE info */ + u8 originally_enabled; /* True if GPE was originally enabled */ }; union acpi_gpe_dispatch_info { struct acpi_namespace_node *method_node; /* Method node for this GPE level */ - struct acpi_handler_info *handler; + struct acpi_handler_info *handler; /* Installed GPE handler */ }; /* @@ -458,7 +458,7 @@ struct acpi_gpe_block_info { u32 register_count; /* Number of register pairs in block */ u16 gpe_count; /* Number of individual GPEs in block */ u8 block_base_number; /* Base GPE number for this block */ - u8 initialized; /* If set, the GPE block has been initialized */ + u8 initialized; /* TRUE if this block is initialized */ }; /* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index f226eac314db..005c170d2448 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -137,7 +137,7 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) /******************************************************************************* * - * FUNCTION: acpi_raw_enable_gpe + * FUNCTION: acpi_ev_add_gpe_reference * * PARAMETERS: gpe_event_info - GPE to enable * @@ -148,10 +148,12 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) +acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status = AE_OK; + ACPI_FUNCTION_TRACE(ev_add_gpe_reference); + if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) { return_ACPI_STATUS(AE_LIMIT); } @@ -173,7 +175,7 @@ acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) /******************************************************************************* * - * FUNCTION: acpi_raw_disable_gpe + * FUNCTION: acpi_ev_remove_gpe_reference * * PARAMETERS: gpe_event_info - GPE to disable * @@ -184,10 +186,12 @@ acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_raw_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) +acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status = AE_OK; + ACPI_FUNCTION_TRACE(ev_remove_gpe_reference); + if (!gpe_event_info->runtime_count) { return_ACPI_STATUS(AE_LIMIT); } @@ -529,7 +533,7 @@ static void acpi_ev_asynch_enable_gpe(void *context) * Enable this GPE, conditionally. This means that the GPE will only be * physically enabled if the enable_for_run bit is set in the event_info */ - (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_COND_ENABLE); + (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); return_VOID; } diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 020add3eee1c..2a445dfcfdb4 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -386,7 +386,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, return_ACPI_STATUS(status); } - acpi_all_gpes_initialized = FALSE; + acpi_gbl_all_gpes_initialized = FALSE; /* Find all GPE methods (_Lxx or_Exx) for this block */ @@ -479,7 +479,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, continue; } - status = acpi_raw_enable_gpe(gpe_event_info); + status = acpi_ev_add_gpe_reference(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not enable GPE 0x%02X", diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 36af222cac65..042a6d69f38e 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -722,7 +722,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, handler->address = address; handler->context = context; handler->method_node = gpe_event_info->dispatch.method_node; - handler->orig_flags = gpe_event_info->flags & + handler->original_flags = gpe_event_info->flags & (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* @@ -731,10 +731,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, * disabled now to avoid spurious execution of the handler. */ - if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD) + if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) && gpe_event_info->runtime_count) { - handler->orig_enabled = 1; - (void)acpi_raw_disable_gpe(gpe_event_info); + handler->originally_enabled = 1; + (void)acpi_ev_remove_gpe_reference(gpe_event_info); } /* Install the handler */ @@ -835,7 +835,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, gpe_event_info->dispatch.method_node = handler->method_node; gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - gpe_event_info->flags |= handler->orig_flags; + gpe_event_info->flags |= handler->original_flags; /* * If the GPE was previously associated with a method and it was @@ -843,9 +843,9 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, * post-initialization configuration. */ - if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD) - && handler->orig_enabled) - (void)acpi_raw_enable_gpe(gpe_event_info); + if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) + && handler->originally_enabled) + (void)acpi_ev_add_gpe_reference(gpe_event_info); /* Now we can free the handler object */ diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 8068065d90eb..99f77ab29729 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -51,7 +51,7 @@ ACPI_MODULE_NAME("evxfgpe") /****************************************************************************** * - * FUNCTION: acpi_update_gpes + * FUNCTION: acpi_update_all_gpes * * PARAMETERS: None * @@ -65,30 +65,34 @@ ACPI_MODULE_NAME("evxfgpe") * ******************************************************************************/ -acpi_status acpi_update_gpes(void) +acpi_status acpi_update_all_gpes(void) { acpi_status status; - ACPI_FUNCTION_TRACE(acpi_update_gpes); + ACPI_FUNCTION_TRACE(acpi_update_all_gpes); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); - } else if (acpi_all_gpes_initialized) { - goto unlock; + } + + if (acpi_gbl_all_gpes_initialized) { + goto unlock_and_exit; } status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL); if (ACPI_SUCCESS(status)) { - acpi_all_gpes_initialized = TRUE; + acpi_gbl_all_gpes_initialized = TRUE; } -unlock: +unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_update_all_gpes) + /******************************************************************************* * * FUNCTION: acpi_enable_gpe @@ -117,7 +121,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { - status = acpi_raw_enable_gpe(gpe_event_info); + status = acpi_ev_add_gpe_reference(gpe_event_info); } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); @@ -154,7 +158,7 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { - status = acpi_raw_disable_gpe(gpe_event_info) ; + status = acpi_ev_remove_gpe_reference(gpe_event_info) ; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); @@ -164,7 +168,7 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe) /******************************************************************************* * - * FUNCTION: acpi_gpe_can_wake + * FUNCTION: acpi_setup_gpe_for_wake * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block @@ -178,13 +182,13 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe) * to be initially disabled). * ******************************************************************************/ -acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) +acpi_status acpi_setup_gpe_for_wake(acpi_handle gpe_device, u32 gpe_number) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE(acpi_gpe_can_wake); + ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); @@ -200,11 +204,11 @@ acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number) acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake) +ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) /******************************************************************************* * - * FUNCTION: acpi_gpe_wakeup + * FUNCTION: acpi_set_gpe_wake_mask * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block @@ -216,7 +220,7 @@ ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake) * ******************************************************************************/ -acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action) +acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; @@ -224,18 +228,23 @@ acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action) acpi_cpu_flags flags; u32 register_bit; - ACPI_FUNCTION_TRACE(acpi_gpe_wakeup); + ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); - if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { + if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } + if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { + status = AE_TYPE; + goto unlock_and_exit; + } + gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { status = AE_NOT_EXIST; @@ -269,7 +278,7 @@ unlock_and_exit: return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup) +ACPI_EXPORT_SYMBOL(acpi_set_gpe_wake_mask) /******************************************************************************* * @@ -387,6 +396,8 @@ acpi_status acpi_disable_all_gpes(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_disable_all_gpes) + /****************************************************************************** * * FUNCTION: acpi_enable_all_runtime_gpes @@ -416,6 +427,8 @@ acpi_status acpi_enable_all_runtime_gpes(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes) + /******************************************************************************* * * FUNCTION: acpi_install_gpe_block @@ -435,7 +448,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_generic_address *gpe_block_address, u32 register_count, u32 interrupt_number) { - acpi_status status = AE_OK; + acpi_status status; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; struct acpi_gpe_block_info *gpe_block; @@ -603,7 +616,7 @@ acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) return_ACPI_STATUS(status); } - *gpe_device = info.gpe_device; + *gpe_device = ACPI_CAST_PTR(acpi_handle, info.gpe_device); return_ACPI_STATUS(info.status); } diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 14750db2a1b8..7c6d4858bb49 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -118,7 +118,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action) register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); switch (action) { - case ACPI_GPE_COND_ENABLE: + case ACPI_GPE_CONDITIONAL_ENABLE: if (!(register_bit & gpe_register_info->enable_for_run)) return (AE_BAD_PARAMETER); diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index e87bc6760be6..a99c32aa48a4 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -768,7 +768,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL; acpi_current_gpe_count = 0; - acpi_all_gpes_initialized = FALSE; + acpi_gbl_all_gpes_initialized = FALSE; /* Global handlers */ diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 81514a4918cc..1864ad3cf895 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -725,7 +725,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) complete_dock(ds); dock_event(ds, event, DOCK_EVENT); dock_lock(ds, 1); - acpi_update_gpes(); + acpi_update_all_gpes(); break; } if (dock_present(ds) || dock_in_progress(ds)) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 29ef505c487b..70249b3d2934 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -778,7 +778,7 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, wakeup->resources.handles[i] = element->reference.handle; } - acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number); + acpi_setup_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number); out: kfree(buffer.pointer); @@ -1467,7 +1467,7 @@ int acpi_bus_start(struct acpi_device *device) result = acpi_bus_scan(device->handle, &ops, NULL); - acpi_update_gpes(); + acpi_update_all_gpes(); return result; } @@ -1584,7 +1584,7 @@ int __init acpi_scan_init(void) if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); else - acpi_update_gpes(); + acpi_update_all_gpes(); return result; } diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index f62a50c3ed34..c6cb68e0a80c 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -45,7 +45,7 @@ void acpi_enable_wakeup_devices(u8 sleep_state) acpi_enable_wakeup_device_power(dev, sleep_state); /* The wake-up power should have been enabled already. */ - acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number, + acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_GPE_ENABLE); } } @@ -67,7 +67,7 @@ void acpi_disable_wakeup_devices(u8 sleep_state) || (sleep_state > (u32) dev->wakeup.sleep_state)) continue; - acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number, + acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_GPE_DISABLE); if (dev->wakeup.state.enabled) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 53b7cfd924a3..5f8ccf1b5ae9 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -292,11 +292,11 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number); acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number); -acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number); +acpi_status acpi_setup_gpe_for_wake(acpi_handle gpe_device, u32 gpe_number); acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number); -acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action); +acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action); acpi_status acpi_get_gpe_status(acpi_handle gpe_device, @@ -315,7 +315,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, acpi_status acpi_remove_gpe_block(acpi_handle gpe_device); -acpi_status acpi_update_gpes(void); +acpi_status acpi_update_all_gpes(void); /* * Resource interfaces diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 2b134b691e34..e73893994b5d 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -656,11 +656,11 @@ typedef u32 acpi_event_status; #define ACPI_GPE_MAX 0xFF #define ACPI_NUM_GPE 256 -/* Actions for acpi_gpe_wakeup, acpi_hw_low_set_gpe */ +/* Actions for acpi_set_gpe_wake_mask, acpi_hw_low_set_gpe */ #define ACPI_GPE_ENABLE 0 #define ACPI_GPE_DISABLE 1 -#define ACPI_GPE_COND_ENABLE 2 +#define ACPI_GPE_CONDITIONAL_ENABLE 2 /* * GPE info flags - Per GPE -- cgit v1.2.3 From 8b6cd8ad18def34bfc5045b2a0234329bf94cf78 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:38:46 +0800 Subject: ACPICA: New GPE handler callback definition The new GPE handler callback has 2 additional parameters, gpe_device and gpe_number. typedef u32 (*acpi_gpe_handler) (acpi_handle gpe_device, u32 gpe_number, void *context); Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acevents.h | 3 ++- drivers/acpi/acpica/aclocal.h | 6 +++--- drivers/acpi/acpica/evgpe.c | 14 ++++++++++---- drivers/acpi/acpica/evxface.c | 10 +++++----- drivers/acpi/ec.c | 3 ++- drivers/char/ipmi/ipmi_si_intf.c | 3 ++- include/acpi/acpixf.h | 4 ++-- include/acpi/actypes.h | 3 +++ 8 files changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index ce2af07f62b3..ebb467fe3678 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -112,7 +112,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block); u32 -acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, +acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, + struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number); /* diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2f841d019a3a..6a71f8e673e9 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -408,8 +408,8 @@ struct acpi_predefined_data { /* Dispatch info for each GPE -- either a method or handler, cannot be both */ -struct acpi_handler_info { - acpi_event_handler address; /* Address of handler, if any */ +struct acpi_gpe_handler_info { + acpi_gpe_handler address; /* Address of handler, if any */ void *context; /* Context to be passed to handler */ struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ u8 original_flags; /* Original (pre-handler) GPE info */ @@ -418,7 +418,7 @@ struct acpi_handler_info { union acpi_gpe_dispatch_info { struct acpi_namespace_node *method_node; /* Method node for this GPE level */ - struct acpi_handler_info *handler; /* Installed GPE handler */ + struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ }; /* diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 005c170d2448..3fb621eec2fa 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -409,7 +409,9 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) * or method. */ int_status |= - acpi_ev_gpe_dispatch(&gpe_block-> + acpi_ev_gpe_dispatch(gpe_block-> + node, + &gpe_block-> event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number); } } @@ -542,7 +544,8 @@ static void acpi_ev_asynch_enable_gpe(void *context) * * FUNCTION: acpi_ev_gpe_dispatch * - * PARAMETERS: gpe_event_info - Info for this GPE + * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 + * gpe_event_info - Info for this GPE * gpe_number - Number relative to the parent GPE block * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED @@ -555,7 +558,8 @@ static void acpi_ev_asynch_enable_gpe(void *context) ******************************************************************************/ u32 -acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) +acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, + struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) { acpi_status status; @@ -593,7 +597,9 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) * Ignore return status for now. * TBD: leave GPE disabled on error? */ - (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> + (void)gpe_event_info->dispatch.handler->address(gpe_device, + gpe_number, + gpe_event_info-> dispatch. handler-> context); diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 042a6d69f38e..d193b905dfa2 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -671,10 +671,10 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler) acpi_status acpi_install_gpe_handler(acpi_handle gpe_device, u32 gpe_number, - u32 type, acpi_event_handler address, void *context) + u32 type, acpi_gpe_handler address, void *context) { struct acpi_gpe_event_info *gpe_event_info; - struct acpi_handler_info *handler; + struct acpi_gpe_handler_info *handler; acpi_status status; acpi_cpu_flags flags; @@ -693,7 +693,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, /* Allocate memory for the handler object */ - handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info)); + handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info)); if (!handler) { status = AE_NO_MEMORY; goto unlock_and_exit; @@ -777,10 +777,10 @@ ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler) ******************************************************************************/ acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, acpi_event_handler address) + u32 gpe_number, acpi_gpe_handler address) { struct acpi_gpe_event_info *gpe_event_info; - struct acpi_handler_info *handler; + struct acpi_gpe_handler_info *handler; acpi_status status; acpi_cpu_flags flags; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 302b31ed31f1..81887724de80 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -606,7 +606,8 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state) return 0; } -static u32 acpi_ec_gpe_handler(void *data) +static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, void *data) { struct acpi_ec *ec = data; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 035da9e64a17..c4bacc6ec450 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1928,7 +1928,8 @@ static void __devinit hardcode_find_bmc(void) static int acpi_failure; /* For GPE-type interrupts. */ -static u32 ipmi_acpi_gpe(void *context) +static u32 ipmi_acpi_gpe(acpi_handle gpe_device, + u32 gpe_number, void *context) { struct smi_info *smi_info = context; unsigned long flags; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 5f8ccf1b5ae9..b806e5611c90 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -258,11 +258,11 @@ acpi_remove_address_space_handler(acpi_handle device, acpi_status acpi_install_gpe_handler(acpi_handle gpe_device, u32 gpe_number, - u32 type, acpi_event_handler address, void *context); + u32 type, acpi_gpe_handler address, void *context); acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, acpi_event_handler address); + u32 gpe_number, acpi_gpe_handler address); #ifdef ACPI_FUTURE_USAGE acpi_status acpi_install_exception_handler(acpi_exception_handler handler); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index e73893994b5d..b9575ad9b748 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -896,6 +896,9 @@ typedef void */ typedef u32(*acpi_event_handler) (void *context); +typedef +u32 (*acpi_gpe_handler) (acpi_handle gpe_device, u32 gpe_number, void *context); + typedef void (*acpi_notify_handler) (acpi_handle device, u32 value, void *context); -- cgit v1.2.3 From 84f6b2a681cd2cc55ecc3fa94bfbe672d7ef4126 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:38:55 +0800 Subject: ACPICA: Remove unused function declarations Acked-by: Rafael J. Wysocki Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acevents.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index ebb467fe3678..04a83fe47d6f 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -51,8 +51,6 @@ acpi_status acpi_ev_initialize_events(void); acpi_status acpi_ev_install_xrupt_handlers(void); -acpi_status acpi_ev_install_fadt_gpes(void); - u32 acpi_ev_fixed_event_detect(void); /* @@ -127,10 +125,6 @@ acpi_status acpi_ev_match_gpe_method(acpi_handle obj_handle, u32 level, void *context, void **return_value); -acpi_status -acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, - u32 level, void *context, void **return_value); - /* * evgpeutil - GPE utilities */ -- cgit v1.2.3 From 5a284cd75d635e3c5db0210dc9a9a44c6839f460 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:39:07 +0800 Subject: ACPICA: Fix local variable mess in acpi_ev_asynch_execute_gpe_method Change the local variable in acpi_ev_asynch_execute_gpe_method() back into a pointer as ACPICA code base does. Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/evgpe.c | 57 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 3fb621eec2fa..c25999546c8c 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -52,6 +52,8 @@ ACPI_MODULE_NAME("evgpe") /* Local prototypes */ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context); +static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context); + /******************************************************************************* * * FUNCTION: acpi_ev_update_gpe_enable_mask @@ -441,17 +443,25 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) * an interrupt handler. * ******************************************************************************/ -static void acpi_ev_asynch_enable_gpe(void *context); static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { - struct acpi_gpe_event_info *gpe_event_info = (void *)context; + struct acpi_gpe_event_info *gpe_event_info = context; acpi_status status; - struct acpi_gpe_event_info local_gpe_event_info; + struct acpi_gpe_event_info *local_gpe_event_info; struct acpi_evaluate_info *info; ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); + /* Allocate a local GPE block */ + + local_gpe_event_info = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info)); + if (!local_gpe_event_info) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); + return_VOID; + } + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_VOID; @@ -468,7 +478,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * Take a snapshot of the GPE info for this level - we copy the info to * prevent a race condition with remove_handler/remove_block. */ - ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info, + ACPI_MEMCPY(local_gpe_event_info, gpe_event_info, sizeof(struct acpi_gpe_event_info)); status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); @@ -480,7 +490,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * Must check for control method type dispatch one more time to avoid a * race with ev_gpe_install_handler */ - if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == + if ((local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { /* Allocate the evaluation information block */ @@ -494,7 +504,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * control method that corresponds to this GPE */ info->prefix_node = - local_gpe_event_info.dispatch.method_node; + local_gpe_event_info->dispatch.method_node; info->flags = ACPI_IGNORE_RETURN_VALUE; status = acpi_ns_evaluate(info); @@ -505,20 +515,41 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) ACPI_EXCEPTION((AE_INFO, status, "while evaluating GPE method [%4.4s]", acpi_ut_get_node_name - (local_gpe_event_info.dispatch. + (local_gpe_event_info->dispatch. method_node))); } } + /* Defer enabling of GPE until all notify handlers are done */ - acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe, - gpe_event_info); + + status = acpi_os_execute(OSL_NOTIFY_HANDLER, + acpi_ev_asynch_enable_gpe, + local_gpe_event_info); + if (ACPI_FAILURE(status)) { + ACPI_FREE(local_gpe_event_info); + } return_VOID; } -static void acpi_ev_asynch_enable_gpe(void *context) +/******************************************************************************* + * + * FUNCTION: acpi_ev_asynch_enable_gpe + * + * PARAMETERS: Context (gpe_event_info) - Info for this GPE + * Callback from acpi_os_execute + * + * RETURN: None + * + * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to + * complete. + * + ******************************************************************************/ + +static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; acpi_status status; + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* @@ -527,7 +558,7 @@ static void acpi_ev_asynch_enable_gpe(void *context) */ status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { - return_VOID; + goto exit; } } @@ -537,7 +568,9 @@ static void acpi_ev_asynch_enable_gpe(void *context) */ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); - return_VOID; +exit: + ACPI_FREE(gpe_event_info); + return; } /******************************************************************************* -- cgit v1.2.3 From bba63a296ffab20e08d9e8252d2f0d99050ac859 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:39:17 +0800 Subject: ACPICA: Implicit notify support This feature provides an automatic device notification for wake devices when a wakeup GPE occurs and there is no corresponding GPE method or handler. Rather than ignoring such a GPE, an implicit AML Notify operation is performed on the parent device object. This feature is not part of the ACPI specification and is provided for Windows compatibility only. Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acevents.h | 2 + drivers/acpi/acpica/aclocal.h | 1 + drivers/acpi/acpica/evgpe.c | 172 +++++++++++++++++++++++----------------- drivers/acpi/acpica/evgpeblk.c | 11 ++- drivers/acpi/acpica/evgpeinit.c | 1 + drivers/acpi/acpica/evxfgpe.c | 58 +++++++++++--- drivers/acpi/ec.c | 2 +- drivers/acpi/scan.c | 2 +- include/acpi/acpixf.h | 6 +- include/acpi/actypes.h | 37 +++++---- 10 files changed, 186 insertions(+), 106 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 04a83fe47d6f..70e0b28801aa 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -91,6 +91,8 @@ struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number, struct acpi_gpe_block_info *gpe_block); +acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info); + /* * evgpeblk - Upper-level GPE block support */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 6a71f8e673e9..74000f5b7dab 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -419,6 +419,7 @@ struct acpi_gpe_handler_info { union acpi_gpe_dispatch_info { struct acpi_namespace_node *method_node; /* Method node for this GPE level */ struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ + struct acpi_namespace_node *device_node; /* Parent _PRW device for implicit notify */ }; /* diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index c25999546c8c..2dbca95979ce 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -115,12 +115,13 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) ACPI_FUNCTION_TRACE(ev_enable_gpe); /* - * We will only allow a GPE to be enabled if it has either an - * associated method (_Lxx/_Exx) or a handler. Otherwise, the - * GPE will be immediately disabled by acpi_ev_gpe_dispatch the - * first time it fires. + * We will only allow a GPE to be enabled if it has either an associated + * method (_Lxx/_Exx) or a handler, or is using the implicit notify + * feature. Otherwise, the GPE will be immediately disabled by + * acpi_ev_gpe_dispatch the first time it fires. */ - if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_NONE) { return_ACPI_STATUS(AE_NO_HANDLER); } @@ -486,12 +487,26 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) return_VOID; } - /* - * Must check for control method type dispatch one more time to avoid a - * race with ev_gpe_install_handler - */ - if ((local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_METHOD) { + /* Do the correct dispatch - normal method or implicit notify */ + + switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + case ACPI_GPE_DISPATCH_NOTIFY: + + /* + * Implicit notify. + * Dispatch a DEVICE_WAKE notify to the appropriate handler. + * NOTE: the request is queued for execution after this method + * completes. The notify handlers are NOT invoked synchronously + * from this thread -- because handlers may in turn run other + * control methods. + */ + status = + acpi_ev_queue_notify_request(local_gpe_event_info->dispatch. + device_node, + ACPI_NOTIFY_DEVICE_WAKE); + break; + + case ACPI_GPE_DISPATCH_METHOD: /* Allocate the evaluation information block */ @@ -518,6 +533,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) (local_gpe_event_info->dispatch. method_node))); } + + break; + + default: + return_VOID; /* Should never happen */ } /* Defer enabling of GPE until all notify handlers are done */ @@ -531,6 +551,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) return_VOID; } + /******************************************************************************* * * FUNCTION: acpi_ev_asynch_enable_gpe @@ -541,38 +562,60 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * RETURN: None * * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to - * complete. + * complete (i.e., finish execution of Notify) * ******************************************************************************/ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; + + (void)acpi_ev_finish_gpe(gpe_event_info); + + ACPI_FREE(gpe_event_info); + return; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_finish_gpe + * + * PARAMETERS: gpe_event_info - Info for this GPE + * + * RETURN: Status + * + * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution + * of a GPE method or a synchronous or asynchronous GPE handler. + * + ******************************************************************************/ + +acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) +{ acpi_status status; if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* - * GPE is level-triggered, we clear the GPE status bit after handling - * the event. + * GPE is level-triggered, we clear the GPE status bit after + * handling the event. */ status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { - goto exit; + return (status); } } /* - * Enable this GPE, conditionally. This means that the GPE will only be - * physically enabled if the enable_for_run bit is set in the event_info + * Enable this GPE, conditionally. This means that the GPE will + * only be physically enabled if the enable_for_run bit is set + * in the event_info. */ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); - -exit: - ACPI_FREE(gpe_event_info); - return; + return (AE_OK); } + /******************************************************************************* * * FUNCTION: acpi_ev_gpe_dispatch @@ -595,6 +638,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) { acpi_status status; + u32 return_value; ACPI_FUNCTION_TRACE(ev_gpe_dispatch); @@ -616,54 +660,49 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, } /* - * Dispatch the GPE to either an installed handler, or the control method - * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke - * it and do not attempt to run the method. If there is neither a handler - * nor a method, we disable this GPE to prevent further such pointless - * events from firing. + * Always disable the GPE so that it does not keep firing before + * any asynchronous activity completes (either from the execution + * of a GPE method or an asynchronous GPE handler.) + * + * If there is no handler or method to run, just disable the + * GPE and leave it disabled permanently to prevent further such + * pointless events from firing. + */ + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Unable to disable GPE%02X", gpe_number)); + return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); + } + + /* + * Dispatch the GPE to either an installed handler or the control + * method associated with this GPE (_Lxx or _Exx). If a handler + * exists, we invoke it and do not attempt to run the method. + * If there is neither a handler nor a method, leave the GPE + * disabled. */ switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_HANDLER: - /* - * Invoke the installed handler (at interrupt level) - * Ignore return status for now. - * TBD: leave GPE disabled on error? - */ - (void)gpe_event_info->dispatch.handler->address(gpe_device, - gpe_number, - gpe_event_info-> - dispatch. - handler-> - context); - - /* It is now safe to clear level-triggered events. */ - - if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == - ACPI_GPE_LEVEL_TRIGGERED) { - status = acpi_hw_clear_gpe(gpe_event_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to clear GPE[0x%2X]", - gpe_number)); - return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); - } + /* Invoke the installed handler (at interrupt level) */ + + return_value = + gpe_event_info->dispatch.handler->address(gpe_device, + gpe_number, + gpe_event_info-> + dispatch.handler-> + context); + + /* If requested, clear (if level-triggered) and reenable the GPE */ + + if (return_value & ACPI_REENABLE_GPE) { + (void)acpi_ev_finish_gpe(gpe_event_info); } break; case ACPI_GPE_DISPATCH_METHOD: - - /* - * Disable the GPE, so it doesn't keep firing before the method has a - * chance to run (it runs asynchronously with interrupts enabled). - */ - status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to disable GPE[0x%2X]", - gpe_number)); - return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); - } + case ACPI_GPE_DISPATCH_NOTIFY: /* * Execute the method associated with the GPE @@ -690,17 +729,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, "No handler or method for GPE[0x%2X], disabling event", gpe_number)); - /* - * Disable the GPE. The GPE will remain disabled a handler - * is installed or ACPICA is restarted. - */ - status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to disable GPE[0x%2X]", - gpe_number)); - return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); - } break; } diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 2a445dfcfdb4..e2e8164bb811 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -472,9 +472,14 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j; gpe_event_info = &gpe_block->event_info[gpe_index]; - /* Ignore GPEs that have no corresponding _Lxx/_Exx method */ - - if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) + /* + * Ignore GPEs that have no corresponding _Lxx/_Exx method + * and GPEs that are used to wake the system + */ + if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_NONE) + || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) + == ACPI_GPE_DISPATCH_HANDLER) || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { continue; } diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 4c8dea513b66..734a494bd705 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -415,6 +415,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, * Add the GPE information from above to the gpe_event_info block for * use during dispatch of this GPE. */ + gpe_event_info->flags &= ~(ACPI_GPE_DISPATCH_MASK); gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD); gpe_event_info->dispatch.method_node = method_node; diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 99f77ab29729..fcf4a5cdc9a4 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -166,39 +166,75 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) } ACPI_EXPORT_SYMBOL(acpi_disable_gpe) + /******************************************************************************* * * FUNCTION: acpi_setup_gpe_for_wake * - * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 - * gpe_number - GPE level within the GPE block + * PARAMETERS: wake_device - Device associated with the GPE (via _PRW) + * gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block * * RETURN: Status * - * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE - * has a corresponding method and is currently enabled, disable it - * (GPEs with corresponding methods are enabled unconditionally - * during initialization, but GPEs that can wake up are expected - * to be initially disabled). + * DESCRIPTION: Mark a GPE as having the ability to wake the system. This + * interface is intended to be used as the host executes the + * _PRW methods (Power Resources for Wake) in the system tables. + * Each _PRW appears under a Device Object (The wake_device), and + * contains the info for the wake GPE associated with the + * wake_device. * ******************************************************************************/ -acpi_status acpi_setup_gpe_for_wake(acpi_handle gpe_device, u32 gpe_number) +acpi_status +acpi_setup_gpe_for_wake(acpi_handle wake_device, + acpi_handle gpe_device, u32 gpe_number) { - acpi_status status = AE_OK; + acpi_status status = AE_BAD_PARAMETER; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_namespace_node *device_node; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); + /* Parameter Validation */ + + if (!wake_device) { + /* + * By forcing wake_device to be valid, we automatically enable the + * implicit notify feature on all hosts. + */ + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + /* Validate wake_device is of type Device */ + + device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); + if (device_node->type != ACPI_TYPE_DEVICE) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { + /* + * If there is no method or handler for this GPE, then the + * wake_device will be notified whenever this GPE fires (aka + * "implicit notify") Note: The GPE is assumed to be + * level-triggered (for windows compatibility). + */ + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_NONE) { + gpe_event_info->flags = + (ACPI_GPE_DISPATCH_NOTIFY | + ACPI_GPE_LEVEL_TRIGGERED); + gpe_event_info->dispatch.device_node = device_node; + } + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; - } else { - status = AE_BAD_PARAMETER; + status = AE_OK; } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 81887724de80..fa848c4116a8 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -619,7 +619,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, wake_up(&ec->wait); ec_check_sci(ec, acpi_ec_read_status(ec)); } - return ACPI_INTERRUPT_HANDLED; + return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; } /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 70249b3d2934..ce6741ee1965 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -778,7 +778,7 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, wakeup->resources.handles[i] = element->reference.handle; } - acpi_setup_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number); + acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); out: kfree(buffer.pointer); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index b806e5611c90..9de6a17cbd4c 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -292,10 +292,12 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number); acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number); -acpi_status acpi_setup_gpe_for_wake(acpi_handle gpe_device, u32 gpe_number); - acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number); +acpi_status +acpi_setup_gpe_for_wake(acpi_handle parent_device, + acpi_handle gpe_device, u32 gpe_number); + acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action); acpi_status diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index b9575ad9b748..d7274ee4474f 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -664,25 +664,26 @@ typedef u32 acpi_event_status; /* * GPE info flags - Per GPE - * +-------+---+-+-+ - * | 7:4 |3:2|1|0| - * +-------+---+-+-+ - * | | | | - * | | | +--- Interrupt type: edge or level triggered - * | | +----- GPE can wake the system - * | +-------- Type of dispatch:to method, handler, or none - * +-------------- + * +-------+-+-+---+ + * | 7:4 |3|2|1:0| + * +-------+-+-+---+ + * | | | | + * | | | +-- Type of dispatch:to method, handler, notify, or none + * | | +----- Interrupt type: edge or level triggered + * | +------- Is a Wake GPE + * +------------ */ -#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01 -#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01 -#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 +#define ACPI_GPE_DISPATCH_NONE (u8) 0x00 +#define ACPI_GPE_DISPATCH_METHOD (u8) 0x01 +#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x02 +#define ACPI_GPE_DISPATCH_NOTIFY (u8) 0x03 +#define ACPI_GPE_DISPATCH_MASK (u8) 0x03 -#define ACPI_GPE_CAN_WAKE (u8) 0x02 +#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x04 +#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 +#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x04 -#define ACPI_GPE_DISPATCH_MASK (u8) 0x0C -#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x04 -#define ACPI_GPE_DISPATCH_METHOD (u8) 0x08 -#define ACPI_GPE_DISPATCH_NOT_USED (u8) 0x00 +#define ACPI_GPE_CAN_WAKE (u8) 0x08 /* * Flags for GPE and Lock interfaces @@ -954,6 +955,10 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); #define ACPI_INTERRUPT_NOT_HANDLED 0x00 #define ACPI_INTERRUPT_HANDLED 0x01 +/* GPE handler return values */ + +#define ACPI_REENABLE_GPE 0x80 + /* Length of 32-bit EISAID values when converted back to a string */ #define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */ -- cgit v1.2.3 From a0fcdb237fcd4eaa7e5009b28ef5be07415f287d Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:39:26 +0800 Subject: ACPICA: Global event handler The global event handler is called whenever a general purpose or fixed ACPI event occurs. Also update Linux OSL to collect events counter with global event handler. Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acglobal.h | 5 +++++ drivers/acpi/acpica/evevent.c | 12 ++++++++-- drivers/acpi/acpica/evgpe.c | 9 +++++++- drivers/acpi/acpica/evxface.c | 51 ++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/utglobal.c | 1 + drivers/acpi/sysfs.c | 19 ++++++++++++++-- include/acpi/acpixf.h | 4 ++++ include/acpi/actypes.h | 8 +++++++ 8 files changed, 104 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index fc694647699f..9bb69c59bb12 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -146,6 +146,9 @@ u8 acpi_gbl_system_awake_and_running; extern u32 acpi_gbl_nesting_level; +ACPI_EXTERN u32 acpi_gpe_count; +ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]; + /* Support for dynamic control method tracing mechanism */ ACPI_EXTERN u32 acpi_gbl_original_dbg_level; @@ -371,6 +374,8 @@ ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head; ACPI_EXTERN struct acpi_gpe_block_info *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized; +ACPI_EXTERN ACPI_GBL_EVENT_HANDLER acpi_gbl_global_event_handler; +ACPI_EXTERN void *acpi_gbl_global_event_handler_context; /***************************************************************************** * diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index c61c3039c31a..e5e313c663a5 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -217,9 +217,17 @@ u32 acpi_ev_fixed_event_detect(void) status_bit_mask) && (fixed_enable & acpi_gbl_fixed_event_info[i]. enable_bit_mask)) { + /* + * Found an active (signalled) event. Invoke global event + * handler if present. + */ + acpi_fixed_event_count[i]++; + if (acpi_gbl_global_event_handler) { + acpi_gbl_global_event_handler + (ACPI_EVENT_TYPE_FIXED, NULL, i, + acpi_gbl_global_event_handler_context); + } - /* Found an active (signalled) event */ - acpi_os_fixed_event_count(i); int_status |= acpi_ev_fixed_event_dispatch(i); } } diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 2dbca95979ce..3bcf5ef74c62 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -642,7 +642,14 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, ACPI_FUNCTION_TRACE(ev_gpe_dispatch); - acpi_os_gpe_count(gpe_number); + /* Invoke global event handler if present */ + + acpi_gpe_count++; + if (acpi_gbl_global_event_handler) { + acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device, + gpe_number, + acpi_gbl_global_event_handler_context); + } /* * If edge-triggered, clear the GPE status bit now. Note that diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index d193b905dfa2..1226689bdb1b 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -92,6 +92,57 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler) ACPI_EXPORT_SYMBOL(acpi_install_exception_handler) #endif /* ACPI_FUTURE_USAGE */ + +/******************************************************************************* + * + * FUNCTION: acpi_install_global_event_handler + * + * PARAMETERS: Handler - Pointer to the global event handler function + * Context - Value passed to the handler on each event + * + * RETURN: Status + * + * DESCRIPTION: Saves the pointer to the handler function. The global handler + * is invoked upon each incoming GPE and Fixed Event. It is + * invoked at interrupt level at the time of the event dispatch. + * Can be used to update event counters, etc. + * + ******************************************************************************/ +acpi_status +acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_install_global_event_handler); + + /* Parameter validation */ + + if (!handler) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Don't allow two handlers. */ + + if (acpi_gbl_global_event_handler) { + status = AE_ALREADY_EXISTS; + goto cleanup; + } + + acpi_gbl_global_event_handler = handler; + acpi_gbl_global_event_handler_context = context; + + cleanup: + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler) + /******************************************************************************* * * FUNCTION: acpi_install_fixed_event_handler diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index a99c32aa48a4..508537f884ac 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -778,6 +778,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_init_handler = NULL; acpi_gbl_table_handler = NULL; acpi_gbl_interface_handler = NULL; + acpi_gbl_global_event_handler = NULL; /* Global Lock support */ diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index f8588f81048a..61891e75583d 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -438,7 +438,7 @@ static void delete_gpe_attr_array(void) return; } -void acpi_os_gpe_count(u32 gpe_number) +static void gpe_count(u32 gpe_number) { acpi_gpe_count++; @@ -454,7 +454,7 @@ void acpi_os_gpe_count(u32 gpe_number) return; } -void acpi_os_fixed_event_count(u32 event_number) +static void fixed_event_count(u32 event_number) { if (!all_counters) return; @@ -468,6 +468,16 @@ void acpi_os_fixed_event_count(u32 event_number) return; } +static void acpi_gbl_event_handler(u32 event_type, acpi_handle device, + u32 event_number, void *context) +{ + if (event_type == ACPI_EVENT_TYPE_GPE) + gpe_count(event_number); + + if (event_type == ACPI_EVENT_TYPE_FIXED) + fixed_event_count(event_number); +} + static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle) { @@ -601,6 +611,7 @@ end: void acpi_irq_stats_init(void) { + acpi_status status; int i; if (all_counters) @@ -619,6 +630,10 @@ void acpi_irq_stats_init(void) if (all_counters == NULL) goto fail; + status = acpi_install_global_event_handler(acpi_gbl_event_handler, NULL); + if (ACPI_FAILURE(status)) + goto fail; + counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), GFP_KERNEL); if (counter_attrs == NULL) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9de6a17cbd4c..e8142d5ebab9 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -228,6 +228,10 @@ acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle); acpi_status acpi_install_initialization_handler(acpi_init_handler handler, u32 function); +acpi_status +acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, + void *context); + acpi_status acpi_install_fixed_event_handler(u32 acpi_event, acpi_event_handler handler, void *context); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index d7274ee4474f..939a431a6ab6 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -895,6 +895,14 @@ typedef void /* * Various handlers and callback procedures */ +typedef +void (*ACPI_GBL_EVENT_HANDLER) (u32 event_type, + acpi_handle device, + u32 event_number, void *context); + +#define ACPI_EVENT_TYPE_GPE 0 +#define ACPI_EVENT_TYPE_FIXED 1 + typedef u32(*acpi_event_handler) (void *context); typedef -- cgit v1.2.3 From da50337373c90c15c6db6ed4239e87c5a3806f9a Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 13 Dec 2010 13:39:37 +0800 Subject: ACPICA: Misc comments to minimize code divergence Modify/add some comments to minimize ACPICA/linux GPE code divergence. Acked-by: Rafael J. Wysocki Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/achware.h | 2 +- drivers/acpi/acpica/evgpe.c | 21 +++++++++++++-------- drivers/acpi/acpica/evgpeblk.c | 18 ++++++++---------- drivers/acpi/acpica/evgpeinit.c | 24 ++++++++++++++++++++---- drivers/acpi/acpica/evxfgpe.c | 32 +++++++++++++++++++++----------- drivers/acpi/acpica/hwgpe.c | 30 ++++++++++++++++++------------ 6 files changed, 81 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 167470ad2d21..258d628793ea 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -94,7 +94,7 @@ u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info, struct acpi_gpe_register_info *gpe_register_info); acpi_status -acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action); +acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action); acpi_status acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 3bcf5ef74c62..7c339d34ab42 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -104,7 +104,7 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) * * RETURN: Status * - * DESCRIPTION: Clear the given GPE from stale events and enable it. + * DESCRIPTION: Clear a GPE of stale events and enable it. * ******************************************************************************/ acpi_status @@ -142,7 +142,7 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) * * FUNCTION: acpi_ev_add_gpe_reference * - * PARAMETERS: gpe_event_info - GPE to enable + * PARAMETERS: gpe_event_info - Add a reference to this GPE * * RETURN: Status * @@ -163,6 +163,9 @@ acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info gpe_event_info->runtime_count++; if (gpe_event_info->runtime_count == 1) { + + /* Enable on first reference */ + status = acpi_ev_update_gpe_enable_mask(gpe_event_info); if (ACPI_SUCCESS(status)) { status = acpi_ev_enable_gpe(gpe_event_info); @@ -180,7 +183,7 @@ acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info * * FUNCTION: acpi_ev_remove_gpe_reference * - * PARAMETERS: gpe_event_info - GPE to disable + * PARAMETERS: gpe_event_info - Remove a reference to this GPE * * RETURN: Status * @@ -201,6 +204,9 @@ acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_i gpe_event_info->runtime_count--; if (!gpe_event_info->runtime_count) { + + /* Disable on last reference */ + status = acpi_ev_update_gpe_enable_mask(gpe_event_info); if (ACPI_SUCCESS(status)) { status = acpi_hw_low_set_gpe(gpe_event_info, @@ -386,7 +392,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) } ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, - "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n", + "Read GPE Register at GPE%02X: Status=%02X, Enable=%02X\n", gpe_register_info->base_gpe_number, status_reg, enable_reg)); @@ -660,8 +666,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to clear GPE[0x%2X]", - gpe_number)); + "Unable to clear GPE%02X", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } @@ -720,7 +725,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to queue handler for GPE[0x%2X] - event disabled", + "Unable to queue handler for GPE%2X - event disabled", gpe_number)); } break; @@ -733,7 +738,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, * a GPE to be enabled if it has no handler or method. */ ACPI_ERROR((AE_INFO, - "No handler or method for GPE[0x%2X], disabling event", + "No handler or method for GPE%02X, disabling event", gpe_number)); break; diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index e2e8164bb811..9acb86958c09 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -361,9 +361,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, gpe_block->node = gpe_device; gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); + gpe_block->initialized = FALSE; gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; - gpe_block->initialized = FALSE; ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address, sizeof(struct acpi_generic_address)); @@ -423,14 +423,12 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, * * FUNCTION: acpi_ev_initialize_gpe_block * - * PARAMETERS: gpe_device - Handle to the parent GPE block - * gpe_block - Gpe Block info + * PARAMETERS: acpi_gpe_callback * * RETURN: Status * - * DESCRIPTION: Initialize and enable a GPE block. First find and run any - * _PRT methods associated with the block, then enable the - * appropriate GPEs. + * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have + * associated methods. * Note: Assumes namespace is locked. * ******************************************************************************/ @@ -450,8 +448,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ACPI_FUNCTION_TRACE(ev_initialize_gpe_block); /* - * Ignore a null GPE block (e.g., if no GPE block 1 exists) and - * GPE blocks that have been initialized already. + * Ignore a null GPE block (e.g., if no GPE block 1 exists), and + * any GPE blocks that have been initialized already. */ if (!gpe_block || gpe_block->initialized) { return_ACPI_STATUS(AE_OK); @@ -459,8 +457,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* * Enable all GPEs that have a corresponding method and have the - * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block must - * be enabled via the acpi_enable_gpe() interface. + * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block + * must be enabled via the acpi_enable_gpe() interface. */ gpe_enabled_count = 0; diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 734a494bd705..c59dc2340593 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -45,11 +45,27 @@ #include "accommon.h" #include "acevents.h" #include "acnamesp.h" -#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evgpeinit") +/* + * Note: History of _PRW support in ACPICA + * + * Originally (2000 - 2010), the GPE initialization code performed a walk of + * the entire namespace to execute the _PRW methods and detect all GPEs + * capable of waking the system. + * + * As of 10/2010, the _PRW method execution has been removed since it is + * actually unnecessary. The host OS must in fact execute all _PRW methods + * in order to identify the device/power-resource dependencies. We now put + * the onus on the host OS to identify the wake GPEs as part of this process + * and to inform ACPICA of these GPEs via the acpi_setup_gpe_for_wake interface. This + * not only reduces the complexity of the ACPICA initialization code, but in + * some cases (on systems with very large namespaces) it should reduce the + * kernel boot time as well. + */ + /******************************************************************************* * * FUNCTION: acpi_ev_gpe_initialize @@ -222,7 +238,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id) acpi_status status = AE_OK; /* - * 2) Find any _Lxx/_Exx GPE methods that have just been loaded. + * Find any _Lxx/_Exx GPE methods that have just been loaded. * * Any GPEs that correspond to new _Lxx/_Exx methods are immediately * enabled. @@ -235,9 +251,9 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id) return; } + walk_info.count = 0; walk_info.owner_id = table_owner_id; walk_info.execute_by_owner_id = TRUE; - walk_info.count = 0; /* Walk the interrupt level descriptor list */ @@ -298,7 +314,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id) * xx - is the GPE number [in HEX] * * If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods - * with that owner. + * with that owner. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index fcf4a5cdc9a4..416845bc9c1f 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -55,13 +55,19 @@ ACPI_MODULE_NAME("evxfgpe") * * PARAMETERS: None * - * RETURN: None + * RETURN: Status + * + * DESCRIPTION: Complete GPE initialization and enable all GPEs that have + * associated _Lxx or _Exx methods and are not pointed to by any + * device _PRW methods (this indicates that these GPEs are + * generally intended for system or device wakeup. Such GPEs + * have to be enabled directly when the devices whose _PRW + * methods point to them are set up for wakeup signaling.) * - * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and - * are not pointed to by any device _PRW methods indicating that - * these GPEs are generally intended for system or device wakeup - * (such GPEs have to be enabled directly when the devices whose - * _PRW methods point to them are set up for wakeup signaling). + * NOTE: Should be called after any GPEs are added to the system. Primarily, + * after the system _PRW methods have been run, but also after a GPE Block + * Device has been added or if any new GPE methods have been added via a + * dynamic table load. * ******************************************************************************/ @@ -252,7 +258,8 @@ ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) * * RETURN: Status * - * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. + * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must + * already be marked as a WAKE GPE. * ******************************************************************************/ @@ -268,8 +275,10 @@ acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 ac flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - /* Ensure that we have a valid GPE number */ - + /* + * Ensure that we have a valid GPE number and that this GPE is in + * fact a wake GPE + */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; @@ -366,7 +375,7 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe) * * RETURN: Status * - * DESCRIPTION: Get status of an event (general purpose) + * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled) * ******************************************************************************/ acpi_status @@ -476,7 +485,8 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes) * * RETURN: Status * - * DESCRIPTION: Create and Install a block of GPE registers + * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not + * enabled here. * ******************************************************************************/ acpi_status diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 7c6d4858bb49..85c3cbd4304d 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -62,10 +62,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * PARAMETERS: gpe_event_info - Info block for the GPE * gpe_register_info - Info block for the GPE register * - * RETURN: Status + * RETURN: Register mask with a one in the GPE bit position * - * DESCRIPTION: Compute GPE enable mask with one bit corresponding to the given - * GPE set. + * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the + * correct position for the input GPE. * ******************************************************************************/ @@ -85,12 +85,12 @@ u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info, * * RETURN: Status * - * DESCRIPTION: Enable or disable a single GPE in its enable register. + * DESCRIPTION: Enable or disable a single GPE in the parent enable register. * ******************************************************************************/ acpi_status -acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action) +acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) { struct acpi_gpe_register_info *gpe_register_info; acpi_status status; @@ -113,14 +113,20 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action) return (status); } - /* Set ot clear just the bit that corresponds to this GPE */ + /* Set or clear just the bit that corresponds to this GPE */ register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); switch (action) { case ACPI_GPE_CONDITIONAL_ENABLE: - if (!(register_bit & gpe_register_info->enable_for_run)) + + /* Only enable if the enable_for_run bit is set */ + + if (!(register_bit & gpe_register_info->enable_for_run)) { return (AE_BAD_PARAMETER); + } + + /*lint -fallthrough */ case ACPI_GPE_ENABLE: ACPI_SET_BIT(enable_mask, register_bit); @@ -131,7 +137,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action) break; default: - ACPI_ERROR((AE_INFO, "Invalid action\n")); + ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u\n", action)); return (AE_BAD_PARAMETER); } @@ -168,13 +174,13 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) return (AE_NOT_EXIST); } - register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info, - gpe_register_info); - /* * Write a one to the appropriate bit in the status register to * clear this GPE. */ + register_bit = + acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info); + status = acpi_hw_write(register_bit, &gpe_register_info->status_address); @@ -201,8 +207,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, u32 in_byte; u32 register_bit; struct acpi_gpe_register_info *gpe_register_info; - acpi_status status; acpi_event_status local_event_status = 0; + acpi_status status; ACPI_FUNCTION_ENTRY(); -- cgit v1.2.3 From 32a00d274e877eab3ea7ab196b75c9be5170d25e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:05:17 +0100 Subject: ACPI / PM: Prevent acpi_power_get_inferred_state() from making changes acpi_power_get_inferred_state() should not update device->power.state behind the back of its caller, so make it return the state via a pointer instead. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 3 ++- drivers/acpi/internal.h | 2 +- drivers/acpi/power.c | 12 ++++-------- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d68bd61072bb..a9fe8e6bc40e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -222,7 +222,8 @@ int acpi_bus_get_power(acpi_handle handle, int *state) * indirectly (via power resources). */ if (device->power.flags.power_resources) { - result = acpi_power_get_inferred_state(device); + result = acpi_power_get_inferred_state(device, + &device->power.state); if (result) return result; } else if (device->power.flags.explicit_get) { diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a212bfeddf8c..2cc01489dccf 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -41,7 +41,7 @@ static inline int acpi_debugfs_init(void) { return 0; } int acpi_power_init(void); int acpi_device_sleep_wake(struct acpi_device *dev, int enable, int sleep_state, int dev_state); -int acpi_power_get_inferred_state(struct acpi_device *device); +int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_transition(struct acpi_device *device, int state); extern int acpi_power_nocheck; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 4c9c2fb5d98f..9bd1b6044b55 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -423,19 +423,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) Device Power Management -------------------------------------------------------------------------- */ -int acpi_power_get_inferred_state(struct acpi_device *device) +int acpi_power_get_inferred_state(struct acpi_device *device, int *state) { int result = 0; struct acpi_handle_list *list = NULL; int list_state = 0; int i = 0; - - if (!device) + if (!device || !state) return -EINVAL; - device->power.state = ACPI_STATE_UNKNOWN; - /* * We know a device's inferred power state when all the resources * required for a given D-state are 'on'. @@ -450,13 +447,12 @@ int acpi_power_get_inferred_state(struct acpi_device *device) return result; if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { - device->power.state = i; + *state = i; return 0; } } - device->power.state = ACPI_STATE_D3; - + *state = ACPI_STATE_D3; return 0; } -- cgit v1.2.3 From d2ef555b57292cd818934636ac8e3414cc2a6762 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:06:09 +0100 Subject: ACPI / PM: Add functions for manipulating lists of power resources ACPI device power resources should be reference counted during device initialization, so that their reference counters are always up to date. It is convenient to do that with the help of a function that will reference count and possibly turn on power resources in a given list, so introduce that function, acpi_power_on_list(). For symmetry, introduce acpi_power_off_list() for performing the reverse operation and use the both of them to simplify acpi_power_transition(). Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/power.c | 67 +++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 9bd1b6044b55..95fedbdf4fb8 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -266,6 +266,35 @@ static int acpi_power_off_device(acpi_handle handle) return result; } +static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) +{ + int i; + + for (i = num_res - 1; i >= 0 ; i--) + acpi_power_off_device(list->handles[i]); +} + +static void acpi_power_off_list(struct acpi_handle_list *list) +{ + __acpi_power_off_list(list, list->count); +} + +static int acpi_power_on_list(struct acpi_handle_list *list) +{ + int result = 0; + int i; + + for (i = 0; i < list->count; i++) { + result = acpi_power_on(list->handles[i]); + if (result) { + __acpi_power_off_list(list, i); + break; + } + } + + return result; +} + /** * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in * ACPI 3.0) _PSW (Power State Wake) @@ -458,10 +487,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state) int acpi_power_transition(struct acpi_device *device, int state) { - int result = 0; - struct acpi_handle_list *cl = NULL; /* Current Resources */ - struct acpi_handle_list *tl = NULL; /* Target Resources */ - int i = 0; + int result; if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) return -EINVAL; @@ -473,37 +499,20 @@ int acpi_power_transition(struct acpi_device *device, int state) || (device->power.state > ACPI_STATE_D3)) return -ENODEV; - cl = &device->power.states[device->power.state].resources; - tl = &device->power.states[state].resources; - /* TBD: Resources must be ordered. */ /* * First we reference all power resources required in the target list - * (e.g. so the device doesn't lose power while transitioning). + * (e.g. so the device doesn't lose power while transitioning). Then, + * we dereference all power resources used in the current list. */ - for (i = 0; i < tl->count; i++) { - result = acpi_power_on(tl->handles[i]); - if (result) - goto end; - } + result = acpi_power_on_list(&device->power.states[state].resources); + if (!result) + acpi_power_off_list( + &device->power.states[device->power.state].resources); - /* - * Then we dereference all power resources used in the current list. - */ - for (i = 0; i < cl->count; i++) { - result = acpi_power_off_device(cl->handles[i]); - if (result) - goto end; - } - - end: - if (result) - device->power.state = ACPI_STATE_UNKNOWN; - else { - /* We shouldn't change the state till all above operations succeed */ - device->power.state = state; - } + /* We shouldn't change the state unless the above operations succeed. */ + device->power.state = result ? ACPI_STATE_UNKNOWN : state; return result; } -- cgit v1.2.3 From 30d3df41b32b1ea63d3ebc52ef5644cbe41520f4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:06:55 +0100 Subject: ACPI / PM: Introduce function for refcounting device power resources Introduce function acpi_power_on_resources() that reference counts and possibly turns on ACPI power resources for a given device and a given power state of it. This function will be used for reference counting device power resources during initialization. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/internal.h | 1 + drivers/acpi/power.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 2cc01489dccf..433a8ee8ac2c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -42,6 +42,7 @@ int acpi_power_init(void); int acpi_device_sleep_wake(struct acpi_device *dev, int enable, int sleep_state, int dev_state); int acpi_power_get_inferred_state(struct acpi_device *device, int *state); +int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); extern int acpi_power_nocheck; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 95fedbdf4fb8..0cb4eab50d73 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -485,6 +485,14 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state) return 0; } +int acpi_power_on_resources(struct acpi_device *device, int state) +{ + if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) + return -EINVAL; + + return acpi_power_on_list(&device->power.states[state].resources); +} + int acpi_power_transition(struct acpi_device *device, int state) { int result; -- cgit v1.2.3 From 5e6d4fe4296782f1f095575b8213a97c3e925a16 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:07:56 +0100 Subject: ACPI / PM: Introduce __acpi_bus_get_power() It sometimes is necessary to get the power state of an ACPI device without updating its device->power.state field, for example to avoid inconsistencies between device->power.state and the reference counters of the device's power resources. For this purpose introduce __acpi_bus_get_power() that will return the given device's power state via a pointer (instead of modifying device->power.state) and make acpi_bus_get_power() use it. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a9fe8e6bc40e..9657abc4a7fb 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -196,34 +196,24 @@ EXPORT_SYMBOL(acpi_bus_get_private_data); Power Management -------------------------------------------------------------------------- */ -int acpi_bus_get_power(acpi_handle handle, int *state) +static int __acpi_bus_get_power(struct acpi_device *device, int *state) { int result = 0; acpi_status status = 0; - struct acpi_device *device = NULL; unsigned long long psc = 0; - - result = acpi_bus_get_device(handle, &device); - if (result) - return result; + if (!device || !state) + return -EINVAL; *state = ACPI_STATE_UNKNOWN; - if (!device->flags.power_manageable) { - /* TBD: Non-recursive algorithm for walking up hierarchy */ - if (device->parent) - *state = device->parent->power.state; - else - *state = ACPI_STATE_D0; - } else { + if (device->flags.power_manageable) { /* * Get the device's power state either directly (via _PSC) or * indirectly (via power resources). */ if (device->power.flags.power_resources) { - result = acpi_power_get_inferred_state(device, - &device->power.state); + result = acpi_power_get_inferred_state(device, state); if (result) return result; } else if (device->power.flags.explicit_get) { @@ -231,20 +221,40 @@ int acpi_bus_get_power(acpi_handle handle, int *state) NULL, &psc); if (ACPI_FAILURE(status)) return -ENODEV; - device->power.state = (int)psc; + *state = (int)psc; } - - *state = device->power.state; + } else { + /* TBD: Non-recursive algorithm for walking up hierarchy. */ + *state = device->parent ? + device->parent->power.state : ACPI_STATE_D0; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", - device->pnp.bus_id, device->power.state)); + device->pnp.bus_id, *state)); return 0; } + +int acpi_bus_get_power(acpi_handle handle, int *state) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + if (result) + return result; + + result = __acpi_bus_get_power(device, state); + if (result) + return result; + + device->power.state = *state; + return 0; +} EXPORT_SYMBOL(acpi_bus_get_power); + int acpi_bus_set_power(acpi_handle handle, int state) { int result = 0; -- cgit v1.2.3 From ade3e7fef794781c0798d0cf0f046123842ba550 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:08:36 +0100 Subject: ACPI / PM: Add function for device power state initialization Add function acpi_bus_init_power() for getting the initial power state of an ACPI device and reference counting its power resources as appropriate. Make acpi_bus_get_power_flags() use the new function instead of acpi_bus_get_power() that updates device->power.state without reference counting the device's power resources. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 25 +++++++++++++++++++++++++ drivers/acpi/internal.h | 1 + drivers/acpi/scan.c | 5 +---- 3 files changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9657abc4a7fb..453451090502 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -364,6 +364,31 @@ int acpi_bus_set_power(acpi_handle handle, int state) EXPORT_SYMBOL(acpi_bus_set_power); + +int acpi_bus_init_power(struct acpi_device *device) +{ + int state; + int result; + + if (!device) + return -EINVAL; + + device->power.state = ACPI_STATE_UNKNOWN; + + result = __acpi_bus_get_power(device, &state); + if (result) + return result; + + if (device->power.flags.power_resources) + result = acpi_power_on_resources(device, state); + + if (!result) + device->power.state = state; + + return result; +} + + bool acpi_bus_power_manageable(acpi_handle handle) { struct acpi_device *device; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 433a8ee8ac2c..7493e6c7a003 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -44,6 +44,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev, int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +int acpi_bus_init_power(struct acpi_device *device); extern int acpi_power_nocheck; int acpi_wakeup_device_init(void); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 29ef505c487b..ef8e659771e1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -901,10 +901,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) device->power.states[ACPI_STATE_D3].flags.valid = 1; device->power.states[ACPI_STATE_D3].power = 0; - /* TBD: System wake support and resource requirements. */ - - device->power.state = ACPI_STATE_UNKNOWN; - acpi_bus_get_power(device->handle, &(device->power.state)); + acpi_bus_init_power(device); return 0; } -- cgit v1.2.3 From 25eed40720fc9005c63a1f436e5f8a78836c26ff Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:09:15 +0100 Subject: ACPI / PM: Add function for updating device power state consistently Add function acpi_bus_update_power() for reading the actual power state of an ACPI device and updating its device->power.state field in such a way that its power resources' reference counters will remain consistent with that field. For this purpose introduce __acpi_bus_set_power() setting the power state of an ACPI device without updating its device->power.state field and make acpi_bus_set_power() and acpi_bus_update_power() use it (acpi_bus_set_power() retains the current behavior for now). Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 90 +++++++++++++++++++++++++++++++++---------------- include/acpi/acpi_bus.h | 1 + 2 files changed, 62 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 453451090502..19decee72e92 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -255,44 +255,17 @@ int acpi_bus_get_power(acpi_handle handle, int *state) EXPORT_SYMBOL(acpi_bus_get_power); -int acpi_bus_set_power(acpi_handle handle, int state) +static int __acpi_bus_set_power(struct acpi_device *device, int state) { int result = 0; acpi_status status = AE_OK; - struct acpi_device *device = NULL; char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; - - result = acpi_bus_get_device(handle, &device); - if (result) - return result; - - if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) + if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) return -EINVAL; /* Make sure this is a valid target state */ - if (!device->flags.power_manageable) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - kobject_name(&device->dev.kobj))); - return -ENODEV; - } - /* - * Get device's current power state - */ - if (!acpi_power_nocheck) { - /* - * Maybe the incorrect power state is returned on the bogus - * bios, which is different with the real power state. - * For example: the bios returns D0 state and the real power - * state is D3. OS expects to set the device to D0 state. In - * such case if OS uses the power state returned by the BIOS, - * the device can't be transisted to the correct power state. - * So if the acpi_power_nocheck is set, it is unnecessary to - * get the power state by calling acpi_bus_get_power. - */ - acpi_bus_get_power(device->handle, &device->power.state); - } if ((state == device->power.state) && !device->flags.force_power_state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); @@ -362,6 +335,42 @@ int acpi_bus_set_power(acpi_handle handle, int state) return result; } + +int acpi_bus_set_power(acpi_handle handle, int state) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + if (result) + return result; + + if (!device->flags.power_manageable) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device [%s] is not power manageable\n", + dev_name(&device->dev))); + return -ENODEV; + } + + /* + * Get device's current power state + */ + if (!acpi_power_nocheck) { + /* + * Maybe the incorrect power state is returned on the bogus + * bios, which is different with the real power state. + * For example: the bios returns D0 state and the real power + * state is D3. OS expects to set the device to D0 state. In + * such case if OS uses the power state returned by the BIOS, + * the device can't be transisted to the correct power state. + * So if the acpi_power_nocheck is set, it is unnecessary to + * get the power state by calling acpi_bus_get_power. + */ + __acpi_bus_get_power(device, &device->power.state); + } + + return __acpi_bus_set_power(device, state); +} EXPORT_SYMBOL(acpi_bus_set_power); @@ -389,6 +398,29 @@ int acpi_bus_init_power(struct acpi_device *device) } +int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + struct acpi_device *device; + int state; + int result; + + result = acpi_bus_get_device(handle, &device); + if (result) + return result; + + result = __acpi_bus_get_power(device, &state); + if (result) + return result; + + result = __acpi_bus_set_power(device, state); + if (!result && state_p) + *state_p = state; + + return result; +} +EXPORT_SYMBOL_GPL(acpi_bus_update_power); + + bool acpi_bus_power_manageable(acpi_handle handle) { struct acpi_device *device; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 359ef11725a6..5d2c4c540063 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -330,6 +330,7 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle, int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_get_power(acpi_handle handle, int *state); int acpi_bus_set_power(acpi_handle handle, int state); +int acpi_bus_update_power(acpi_handle handle, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); bool acpi_bus_can_wakeup(acpi_handle handle); #ifdef CONFIG_ACPI_PROC_EVENT -- cgit v1.2.3 From 97d9a9e9f5ee68f20005ca5aa77c6b684e7cace8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:10:02 +0100 Subject: ACPI / PM: Register acpi_power_driver early The ACPI device driver used for handling power resources, acpi_power_driver, creates a struct acpi_power_resource object for each ACPI device representing a power resource. These objects are then used when setting and reading the power states of devices using the corresponding power resources. Unfortunately, acpi_power_driver is registered after acpi_scan_init() that may add devices using the power resources before acpi_power_driver has a chance to create struct acpi_power_resource objects for them (specifically, the power resources may be referred to during the scanning process through acpi_bus_get_power() before they have been initialized). As the first step towards fixing this issue, move the registration of acpi_power_driver into acpi_scan_init() so that power resource devices can be initialized by it as soon as they have been found in the namespace. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 1 - drivers/acpi/scan.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 19decee72e92..47864013c0df 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1099,7 +1099,6 @@ static int __init acpi_init(void) acpi_scan_init(); acpi_ec_init(); - acpi_power_init(); acpi_debugfs_init(); acpi_sleep_proc_init(); acpi_wakeup_device_init(); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ef8e659771e1..2951a27303cb 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1570,6 +1570,8 @@ int __init acpi_scan_init(void) printk(KERN_ERR PREFIX "Could not register bus type\n"); } + acpi_power_init(); + /* * Enumerate devices in the ACPI namespace. */ -- cgit v1.2.3 From bf325f9538d8c89312be305b9779edbcb436af00 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:10:44 +0100 Subject: ACPI / PM: Register power resource devices as soon as they are needed Depending on the organization of the ACPI namespace, power resource device objects may generally be scanned after the "regular" device objects that they are referred from through _PRn. This, in turn, may cause acpi_bus_get_power_flags() to attempt to access them through acpi_bus_init_power() before they are registered (and initialized by acpi_power_driver). [This is not a theoretical issue, it actually happens for one PnP device on my testbed HP nx6325.] To fix this problem, make acpi_bus_get_power_flags() attempt to register power resource devices as soon as they have been found in the _PRn output for any other devices. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/scan.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2951a27303cb..cb7956c23ca4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -847,6 +847,8 @@ end: return 0; } +static void acpi_bus_add_power_resource(acpi_handle handle); + static int acpi_bus_get_power_flags(struct acpi_device *device) { acpi_status status = 0; @@ -875,8 +877,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) acpi_evaluate_reference(device->handle, object_name, NULL, &ps->resources); if (ps->resources.count) { + int j; + device->power.flags.power_resources = 1; ps->flags.valid = 1; + for (j = 0; j < ps->resources.count; j++) + acpi_bus_add_power_resource(ps->resources.handles[j]); } /* Evaluate "_PSx" to see if we can do explicit sets */ @@ -1323,6 +1329,20 @@ end: #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) +static void acpi_bus_add_power_resource(acpi_handle handle) +{ + struct acpi_bus_ops ops = { + .acpi_op_add = 1, + .acpi_op_start = 1, + }; + struct acpi_device *device = NULL; + + acpi_bus_get_device(handle, &device); + if (!device) + acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, + ACPI_STA_DEFAULT, &ops); +} + static int acpi_bus_type_and_status(acpi_handle handle, int *type, unsigned long long *sta) { -- cgit v1.2.3 From 488a76c52606199100adf09c8eb7cbedbd94e9d9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 25 Nov 2010 00:11:24 +0100 Subject: ACPI / Fan: Rework the handling of power resources Use the new function acpi_bus_update_power() for manipulating power resources used by ACPI fan devices, which allows them to be put into the right state during initialization and resume. Consequently, remove the flags.force_power_state field from struct acpi_device, which is not necessary any more. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 2 +- drivers/acpi/fan.c | 27 +++++++-------------------- drivers/acpi/thermal.c | 5 +++-- include/acpi/acpi_bus.h | 3 +-- 4 files changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 47864013c0df..2ee83b5fff97 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -266,7 +266,7 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) /* Make sure this is a valid target state */ - if ((state == device->power.state) && !device->flags.force_power_state) { + if (state == device->power.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); return 0; diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 60049080c869..467479f07c1f 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -86,7 +86,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long if (!device) return -EINVAL; - result = acpi_bus_get_power(device->handle, &acpi_state); + result = acpi_bus_update_power(device->handle, &acpi_state); if (result) return result; @@ -123,7 +123,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = { static int acpi_fan_add(struct acpi_device *device) { int result = 0; - int state = 0; struct thermal_cooling_device *cdev; if (!device) @@ -132,16 +131,12 @@ static int acpi_fan_add(struct acpi_device *device) strcpy(acpi_device_name(device), "Fan"); strcpy(acpi_device_class(device), ACPI_FAN_CLASS); - result = acpi_bus_get_power(device->handle, &state); + result = acpi_bus_update_power(device->handle, NULL); if (result) { - printk(KERN_ERR PREFIX "Reading power state\n"); + printk(KERN_ERR PREFIX "Setting initial power state\n"); goto end; } - device->flags.force_power_state = 1; - acpi_bus_set_power(device->handle, state); - device->flags.force_power_state = 0; - cdev = thermal_cooling_device_register("Fan", device, &fan_cooling_ops); if (IS_ERR(cdev)) { @@ -200,22 +195,14 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) static int acpi_fan_resume(struct acpi_device *device) { - int result = 0; - int power_state = 0; + int result; if (!device) return -EINVAL; - result = acpi_bus_get_power(device->handle, &power_state); - if (result) { - printk(KERN_ERR PREFIX - "Error reading fan power state\n"); - return result; - } - - device->flags.force_power_state = 1; - acpi_bus_set_power(device->handle, power_state); - device->flags.force_power_state = 0; + result = acpi_bus_update_power(device->handle, NULL); + if (result) + printk(KERN_ERR PREFIX "Error updating fan power state\n"); return result; } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 5a27b0a31315..2607e17b520f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1059,8 +1059,9 @@ static int acpi_thermal_resume(struct acpi_device *device) break; tz->trips.active[i].flags.enabled = 1; for (j = 0; j < tz->trips.active[i].devices.count; j++) { - result = acpi_bus_get_power(tz->trips.active[i].devices. - handles[j], &power_state); + result = acpi_bus_update_power( + tz->trips.active[i].devices.handles[j], + &power_state); if (result || (power_state != ACPI_STATE_D0)) { tz->trips.active[i].flags.enabled = 0; break; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 5d2c4c540063..89125808fbd5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -149,8 +149,7 @@ struct acpi_device_flags { u32 power_manageable:1; u32 performance_manageable:1; u32 wake_capable:1; /* Wakeup(_PRW) supported? */ - u32 force_power_state:1; - u32 reserved:22; + u32 reserved:23; }; /* File System */ -- cgit v1.2.3 From 40b7397579e006c0f9cf4de58e9ccc350e06308f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 11 Dec 2010 23:43:26 +0100 Subject: Platform / x86: Make fujitsu_laptop use acpi_bus_update_power() Use the new function acpi_bus_update_power(), which is safer than acpi_bus_get_power(), for getting device power state in acpi_fujitsu_add() and acpi_fujitsu_hotkey_add(). Signed-off-by: Rafael J. Wysocki Reported-and-Tested-by: Sedat Dilek Signed-off-by: Len Brown --- drivers/platform/x86/fujitsu-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f44cd2620ff9..cf6c47250c56 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -689,7 +689,7 @@ static int acpi_fujitsu_add(struct acpi_device *device) if (error) goto err_free_input_dev; - result = acpi_bus_get_power(fujitsu->acpi_handle, &state); + result = acpi_bus_update_power(fujitsu->acpi_handle, &state); if (result) { printk(KERN_ERR "Error reading power state\n"); goto err_unregister_input_dev; @@ -857,7 +857,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) if (error) goto err_free_input_dev; - result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state); + result = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state); if (result) { printk(KERN_ERR "Error reading power state\n"); goto err_unregister_input_dev; -- cgit v1.2.3 From f6767dcf2a4f6e62960912d0affec1e15a246191 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 11 Dec 2010 23:44:39 +0100 Subject: ACPI / PM: Drop acpi_bus_get_power() There are no more users of acpi_bus_get_power(), so it can be dropped. Moreover, it should be dropped, because it modifies the device->power.state field of an ACPI device without updating the reference counters of the device's power resources, which is wrong. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 19 ------------------- include/acpi/acpi_bus.h | 1 - 2 files changed, 20 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2ee83b5fff97..0baa5f97734a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -236,25 +236,6 @@ static int __acpi_bus_get_power(struct acpi_device *device, int *state) } -int acpi_bus_get_power(acpi_handle handle, int *state) -{ - struct acpi_device *device; - int result; - - result = acpi_bus_get_device(handle, &device); - if (result) - return result; - - result = __acpi_bus_get_power(device, state); - if (result) - return result; - - device->power.state = *state; - return 0; -} -EXPORT_SYMBOL(acpi_bus_get_power); - - static int __acpi_bus_set_power(struct acpi_device *device, int state) { int result = 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 89125808fbd5..673a3f4d1f07 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -327,7 +327,6 @@ void acpi_bus_data_handler(acpi_handle handle, void *context); acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); -int acpi_bus_get_power(acpi_handle handle, int *state); int acpi_bus_set_power(acpi_handle handle, int state); int acpi_bus_update_power(acpi_handle handle, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); -- cgit v1.2.3 From 53eac700b0df1fef8c957b9eedfd7f48120425e3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 11 Dec 2010 23:45:30 +0100 Subject: ACPI / PM: Drop acpi_power_nocheck Since acpi_bus_set_power() should not use __acpi_bus_get_power() to update the device's device->power.state field before changing its power state (this may cause device->power.state to be inconsistent with the device power resources' reference counters), remove this call from it. In consequence, the acpi_power_nocheck variable is not necessary any more, so it can be dropped along with the DMI table used for setting that variable for HP Pavilion 05. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/bus.c | 39 --------------------------------------- drivers/acpi/internal.h | 1 - drivers/acpi/power.c | 3 --- 3 files changed, 43 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 0baa5f97734a..7ced61f39492 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -52,22 +52,6 @@ EXPORT_SYMBOL(acpi_root_dir); #define STRUCT_TO_INT(s) (*((int*)&s)) -static int set_power_nocheck(const struct dmi_system_id *id) -{ - printk(KERN_NOTICE PREFIX "%s detected - " - "disable power check in power transition\n", id->ident); - acpi_power_nocheck = 1; - return 0; -} -static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = { - { - set_power_nocheck, "HP Pavilion 05", { - DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), - DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"), - DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL}, - {}, -}; - #ifdef CONFIG_X86 static int set_copy_dsdt(const struct dmi_system_id *id) @@ -333,23 +317,6 @@ int acpi_bus_set_power(acpi_handle handle, int state) return -ENODEV; } - /* - * Get device's current power state - */ - if (!acpi_power_nocheck) { - /* - * Maybe the incorrect power state is returned on the bogus - * bios, which is different with the real power state. - * For example: the bios returns D0 state and the real power - * state is D3. OS expects to set the device to D0 state. In - * such case if OS uses the power state returned by the BIOS, - * the device can't be transisted to the correct power state. - * So if the acpi_power_nocheck is set, it is unnecessary to - * get the power state by calling acpi_bus_get_power. - */ - __acpi_bus_get_power(device, &device->power.state); - } - return __acpi_bus_set_power(device, state); } EXPORT_SYMBOL(acpi_bus_set_power); @@ -1072,12 +1039,6 @@ static int __init acpi_init(void) if (acpi_disabled) return result; - /* - * If the laptop falls into the DMI check table, the power state check - * will be disabled in the course of device power transition. - */ - dmi_check_system(power_nocheck_dmi_table); - acpi_scan_init(); acpi_ec_init(); acpi_debugfs_init(); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 7493e6c7a003..8df5d7061a45 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -45,7 +45,6 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); int acpi_bus_init_power(struct acpi_device *device); -extern int acpi_power_nocheck; int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0cb4eab50d73..0003f1009885 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power"); #define ACPI_POWER_RESOURCE_STATE_ON 0x01 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF -int acpi_power_nocheck; -module_param_named(power_nocheck, acpi_power_nocheck, bool, 000); - static int acpi_power_add(struct acpi_device *device); static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_resume(struct acpi_device *device); -- cgit v1.2.3 From 36237fa0a711c309a38d7a7a9aed727e0eb76449 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:38:04 +0100 Subject: ACPI / PM: Rename acpi_power_off_device() Rename acpi_power_off_device() to acpi_power_off() in analogy with acpi_power_on(). Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/power.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0003f1009885..ac02af419b32 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -219,7 +219,7 @@ static int acpi_power_on(acpi_handle handle) return result; } -static int acpi_power_off_device(acpi_handle handle) +static int acpi_power_off(acpi_handle handle) { int result = 0; acpi_status status = AE_OK; @@ -268,7 +268,7 @@ static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) int i; for (i = num_res - 1; i >= 0 ; i--) - acpi_power_off_device(list->handles[i]); + acpi_power_off(list->handles[i]); } static void acpi_power_off_list(struct acpi_handle_list *list) @@ -430,8 +430,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) /* Close power resource */ for (i = 0; i < dev->wakeup.resources.count; i++) { - int ret = acpi_power_off_device( - dev->wakeup.resources.handles[i]); + int ret = acpi_power_off(dev->wakeup.resources.handles[i]); if (ret) { printk(KERN_ERR PREFIX "Transition power state\n"); dev->wakeup.flags.valid = 0; -- cgit v1.2.3 From d0515d9fec68bace144fda57a69f4268fb875209 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:38:57 +0100 Subject: ACPI / PM: Check status of power resources under mutexes It certainly is not a good idea to execute _ON or _OFF and _STA for the same power resource at the same time which may happen in some circumstances in theory. To prevent that from happening, read the power state of each power resource under its mutex, as that will prevent the state from being changed at the same time. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/power.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index ac02af419b32..9ac2a9fa90ff 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -145,9 +145,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state) static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) { - int result = 0, state1; - u32 i = 0; - + int cur_state; + int i = 0; if (!list || !state) return -EINVAL; @@ -155,25 +154,33 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) /* The state of the list is 'on' IFF all resources are 'on'. */ for (i = 0; i < list->count; i++) { - /* - * The state of the power resource can be obtained by - * using the ACPI handle. In such case it is unnecessary to - * get the Power resource first and then get its state again. - */ - result = acpi_power_get_state(list->handles[i], &state1); + struct acpi_power_resource *resource; + acpi_handle handle = list->handles[i]; + int result; + + result = acpi_power_get_context(handle, &resource); if (result) return result; - *state = state1; + mutex_lock(&resource->resource_lock); - if (*state != ACPI_POWER_RESOURCE_STATE_ON) + result = acpi_power_get_state(handle, &cur_state); + + mutex_unlock(&resource->resource_lock); + + if (result) + return result; + + if (cur_state != ACPI_POWER_RESOURCE_STATE_ON) break; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", - *state ? "on" : "off")); + cur_state ? "on" : "off")); - return result; + *state = cur_state; + + return 0; } static int __acpi_power_on(struct acpi_power_resource *resource) -- cgit v1.2.3 From 86e4e20e8a5301ff7104a4f40f35fd5bee408186 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:40:00 +0100 Subject: ACPI: Always check if _PRW is present before trying to evaluate it Before evaluating _PRW for devices that are reported as inactive or not present by their _STA control methods we should check if those methods are actually present (otherwise the evaulation of _PRW will obviously fail and a scary message will be printed unnecessarily). Reported-by: Andreas Mohr Reported-by: Maciej Rutecki Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/scan.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64d4da0d6d52..b5e4dedb497d 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1388,7 +1388,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, struct acpi_bus_ops *ops = context; int type; unsigned long long sta; - struct acpi_device_wakeup wakeup; struct acpi_device *device; acpi_status status; int result; @@ -1399,7 +1398,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, if (!(sta & ACPI_STA_DEVICE_PRESENT) && !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { - acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); + struct acpi_device_wakeup wakeup; + acpi_handle temp; + + status = acpi_get_handle(handle, "_PRW", &temp); + if (ACPI_SUCCESS(status)) + acpi_bus_extract_wakeup_device_power_package(handle, + &wakeup); return AE_CTRL_DEPTH; } -- cgit v1.2.3 From d57d09a480e1db38eeee7629c81289b00f338a15 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:41:27 +0100 Subject: ACPI: Drop device flag wake_capable The wake_capable ACPI device flag is not necessary, because it is only used in scan.c for recording the information that _PRW is present for the given device. That information is only used by acpi_add_single_object() to decide whether or not to call acpi_bus_get_wakeup_device_flags(), so the flag may be dropped if the _PRW check is moved to acpi_bus_get_wakeup_device_flags(). Moreover, acpi_bus_get_wakeup_device_flags() always returns 0, so it really should be void. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/scan.c | 26 +++++++++----------------- include/acpi/acpi_bus.h | 3 +-- 2 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b5e4dedb497d..b99e62494607 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -815,16 +815,22 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) !!(event_status & ACPI_EVENT_FLAG_HANDLE); } -static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) +static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) { + acpi_handle temp; acpi_status status = 0; int psw_error; + /* Presence of _PRW indicates wake capable */ + status = acpi_get_handle(device->handle, "_PRW", &temp); + if (ACPI_FAILURE(status)) + return; + status = acpi_bus_extract_wakeup_device_power_package(device->handle, &device->wakeup); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); - goto end; + return; } device->wakeup.flags.valid = 1; @@ -840,11 +846,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) if (psw_error) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in _DSW or _PSW evaluation\n")); - -end: - if (ACPI_FAILURE(status)) - device->flags.wake_capable = 0; - return 0; } static void acpi_bus_add_power_resource(acpi_handle handle); @@ -950,11 +951,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) if (ACPI_SUCCESS(status)) device->flags.power_manageable = 1; - /* Presence of _PRW indicates wake capable */ - status = acpi_get_handle(device->handle, "_PRW", &temp); - if (ACPI_SUCCESS(status)) - device->flags.wake_capable = 1; - /* TBD: Performance management */ return 0; @@ -1281,11 +1277,7 @@ static int acpi_add_single_object(struct acpi_device **child, * Wakeup device management *----------------------- */ - if (device->flags.wake_capable) { - result = acpi_bus_get_wakeup_device_flags(device); - if (result) - goto end; - } + acpi_bus_get_wakeup_device_flags(device); /* * Performance Management diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 20b05cd68663..78ca429929f7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -148,8 +148,7 @@ struct acpi_device_flags { u32 suprise_removal_ok:1; u32 power_manageable:1; u32 performance_manageable:1; - u32 wake_capable:1; /* Wakeup(_PRW) supported? */ - u32 reserved:23; + u32 reserved:24; }; /* File System */ -- cgit v1.2.3 From da8aeb92d4853f37e281f11fddf61f9c7d84c3cd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 6 Jan 2011 23:42:27 +0100 Subject: ACPI / Battery: Update information on info notification and resume A notification event 0x81 from an ACPI battery device requires us to re-read the battery information structure. Follow this requirement and remove and re-create the battery's attibutes in sysfs so that they reflect the reporting units used by the battery at the moment (those units may actually change sometimes at run time, which happens on some Thinkpads). The approach used in this patch was suggested by Matthew Garrett. Signed-off-by: Rafael J. Wysocki Reported-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/battery.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2a31421e0d75..68bc227e7c4c 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -631,6 +631,17 @@ static int acpi_battery_update(struct acpi_battery *battery) return result; } +static void acpi_battery_refresh(struct acpi_battery *battery) +{ + if (!battery->bat.dev) + return; + + acpi_battery_get_info(battery); + /* The battery may have changed its reporting units. */ + sysfs_remove_battery(battery); + sysfs_add_battery(battery); +} + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -916,6 +927,8 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) if (!battery) return; old = battery->bat.dev; + if (event == ACPI_BATTERY_NOTIFY_INFO) + acpi_battery_refresh(battery); acpi_battery_update(battery); acpi_bus_generate_proc_event(device, event, acpi_battery_present(battery)); @@ -985,6 +998,7 @@ static int acpi_battery_resume(struct acpi_device *device) if (!device) return -EINVAL; battery = acpi_driver_data(device); + acpi_battery_refresh(battery); battery->update_time = 0; acpi_battery_update(battery); return 0; -- cgit v1.2.3 From f9a9f096d25bbc54dc3147613ee1d86b35cce691 Mon Sep 17 00:00:00 2001 From: Lutz Ballaschke Date: Sun, 26 Sep 2010 16:38:20 +0200 Subject: watchdog: clean-up f71808e_wdt.c Cleaned up and replaced some magic numbers by constants. Signed-off-by: Lutz Ballaschke Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/f71808e_wdt.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 65e579635dba..3c9142474d18 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -42,18 +42,19 @@ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ #define SIO_REG_DEVREV 0x22 /* Device revision */ #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ +#define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */ +#define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */ +#define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */ #define SIO_REG_ENABLE 0x30 /* Logical device enable */ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ -#define SIO_F71808_ID 0x0901 /* Chipset ID */ -#define SIO_F71858_ID 0x0507 /* Chipset ID */ +#define SIO_F71808_ID 0x0901 /* Chipset ID */ +#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71889_ID 0x0723 /* Chipset ID */ -#define F71882FG_REG_START 0x01 - #define F71808FG_REG_WDO_CONF 0xf0 #define F71808FG_REG_WDT_CONF 0xf5 #define F71808FG_REG_WD_TIME 0xf6 @@ -76,7 +77,7 @@ module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); static const int max_timeout = WATCHDOG_MAX_TIMEOUT; -static int timeout = 60; /* default timeout in seconds */ +static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=" @@ -299,19 +300,19 @@ static int watchdog_start(void) switch (watchdog.type) { case f71808fg: /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */ - superio_clear_bit(watchdog.sioaddr, 0x2a, 3); - superio_clear_bit(watchdog.sioaddr, 0x2b, 3); + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT2, 3); + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3); break; case f71882fg: /* Set pin 56 to WDTRST# */ - superio_set_bit(watchdog.sioaddr, 0x29, 1); + superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1); break; case f71889fg: /* set pin 40 to WDTRST# */ - superio_outb(watchdog.sioaddr, 0x2b, - superio_inb(watchdog.sioaddr, 0x2b) & 0xcf); + superio_outb(watchdog.sioaddr, SIO_REG_MFUNCT3, + superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf); break; default: -- cgit v1.2.3 From 7977ff6e3deb042b29370e52607df20d1ee33b9d Mon Sep 17 00:00:00 2001 From: Lutz Ballaschke Date: Sun, 26 Sep 2010 16:25:35 +0200 Subject: watchdog: add f71862fg support Watchdog support for Fintek F71862fg Super-I/O added. Two different hardware reset pins of the F71862fg chip can be configured by an additional module parameter. Signed-off-by: Lutz Ballaschke Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/f71808e_wdt.c | 45 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 3c9142474d18..f573948998b0 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -42,6 +42,7 @@ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ #define SIO_REG_DEVREV 0x22 /* Device revision */ #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ +#define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */ #define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */ #define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */ #define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */ @@ -71,6 +72,8 @@ #define WATCHDOG_MAX_TIMEOUT (60 * 255) #define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for watchdog signal */ +#define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output + pin number 63 */ static unsigned short force_id; module_param(force_id, ushort, 0); @@ -90,6 +93,12 @@ MODULE_PARM_DESC(pulse_width, "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms" " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); +static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN; +module_param(f71862fg_pin, uint, 0); +MODULE_PARM_DESC(f71862fg_pin, + "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63" + " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")"); + static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0444); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); @@ -283,6 +292,28 @@ exit_unlock: return err; } +static int f71862fg_pin_configure(unsigned short ioaddr) +{ + /* When ioaddr is non-zero the calling function has to take care of + mutex handling and superio preparation! */ + + if (f71862fg_pin == 63) { + if (ioaddr) { + /* SPI must be disabled first to use this pin! */ + superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6); + superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4); + } + } else if (f71862fg_pin == 56) { + if (ioaddr) + superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1); + } else { + printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n", + f71862fg_pin); + return -EINVAL; + } + return 0; +} + static int watchdog_start(void) { /* Make sure we don't die as soon as the watchdog is enabled below */ @@ -304,6 +335,12 @@ static int watchdog_start(void) superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3); break; + case f71862fg: + err = f71862fg_pin_configure(watchdog.sioaddr); + if (err) + goto exit_superio; + break; + case f71882fg: /* Set pin 56 to WDTRST# */ superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1); @@ -712,16 +749,16 @@ static int __init f71808e_find(int sioaddr) case SIO_F71808_ID: watchdog.type = f71808fg; break; + case SIO_F71862_ID: + watchdog.type = f71862fg; + err = f71862fg_pin_configure(0); /* validate module parameter */ + break; case SIO_F71882_ID: watchdog.type = f71882fg; break; case SIO_F71889_ID: watchdog.type = f71889fg; break; - case SIO_F71862_ID: - /* These have a watchdog, though it isn't implemented (yet). */ - err = -ENOSYS; - goto exit; case SIO_F71858_ID: /* Confirmed (by datasheet) not to have a watchdog. */ err = -ENODEV; -- cgit v1.2.3 From df278dac2070e677cf22c30e1c78c5a753191375 Mon Sep 17 00:00:00 2001 From: Michel Arboi Date: Mon, 6 Dec 2010 20:53:45 +0100 Subject: watchdog: f71808e_wdt: Add Fintek F71869 watchdog Add Fintek f71869 as a supported watchdog device. Signed-off-by: Michel Arboi Acked-by: Giel van Schijndel Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/f71808e_wdt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index f573948998b0..d4d8d1fdccc4 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -53,6 +53,7 @@ #define SIO_F71808_ID 0x0901 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ +#define SIO_F71869_ID 0x0814 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71889_ID 0x0723 /* Chipset ID */ @@ -108,12 +109,13 @@ module_param(start_withtimeout, uint, 0); MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" " given initial timeout. Zero (default) disables this feature."); -enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg }; +enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg }; static const char *f71808e_names[] = { "f71808fg", "f71858fg", "f71862fg", + "f71869", "f71882fg", "f71889fg", }; @@ -341,6 +343,11 @@ static int watchdog_start(void) goto exit_superio; break; + case f71869: + /* GPIO14 --> WDTRST# */ + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4); + break; + case f71882fg: /* Set pin 56 to WDTRST# */ superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1); @@ -753,6 +760,9 @@ static int __init f71808e_find(int sioaddr) watchdog.type = f71862fg; err = f71862fg_pin_configure(0); /* validate module parameter */ break; + case SIO_F71869_ID: + watchdog.type = f71869; + break; case SIO_F71882_ID: watchdog.type = f71882fg; break; -- cgit v1.2.3 From 9c67bea419c384561eeb84bdf251d521a3234e45 Mon Sep 17 00:00:00 2001 From: Benny Loenstrup Ammitzboell Date: Thu, 11 Nov 2010 16:08:41 +0100 Subject: watchdog: Add watchdog support for W83627DHG chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following adds watchdog support for the Winbond W83627DHG chip. I have tested it on a PQ7-M102XL (Intel Atom) board. Signed-off-by: Benny Lønstrup Ammitzbøll Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 9 +++++---- drivers/watchdog/w83627hf_wdt.c | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index a5ad77ef4266..8a3aa2f050c8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -722,14 +722,15 @@ config SMSC37B787_WDT Most people will say N. config W83627HF_WDT - tristate "W83627HF Watchdog Timer" + tristate "W83627HF/W83627DHG Watchdog Timer" depends on X86 ---help--- This is the driver for the hardware watchdog on the W83627HF chipset as used in Advantech PC-9578 and Tyan S2721-533 motherboards - (and likely others). This watchdog simply watches your kernel to - make sure it doesn't freeze, and if it does, it reboots your computer - after a certain amount of time. + (and likely others). The driver also supports the W83627DHG chip. + This watchdog simply watches your kernel to make sure it doesn't + freeze, and if it does, it reboots your computer after a certain + amount of time. To compile this driver as a module, choose M here: the module will be called w83627hf_wdt. diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 0f5288df0091..48f2e0148bb4 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -42,7 +42,7 @@ #include -#define WATCHDOG_NAME "w83627hf/thf/hg WDT" +#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" #define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ @@ -89,7 +89,7 @@ static void w83627hf_select_wd_register(void) c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ outb_p(0x2b, WDT_EFER); outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */ - } else if (c == 0x88) { /* W83627EHF */ + } else if (c == 0x88 || c == 0xa0) { /* W83627EHF / W83627DHG */ outb_p(0x2d, WDT_EFER); /* select GPIO5 */ c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */ outb_p(0x2d, WDT_EFER); @@ -321,7 +321,7 @@ static int __init wdt_init(void) { int ret; - printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n"); + printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n"); if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); -- cgit v1.2.3 From 6d106e0cac842bc17c87aadd5fa01730694c987a Mon Sep 17 00:00:00 2001 From: Herman Morsink Vollenbroek Date: Mon, 6 Dec 2010 21:24:56 +0100 Subject: watchdog: Fix reboot on W83627ehf chipset. The watchdog driver for the SUPERIO chip winbond w83627ehf does not work. If you open /dev/watchdog and write a character to /dev/watchdog then the watchdog will be triggered. However the watchdog will not trigger the hardware RESET after the timeout, because the watchdog has never been enabled. Signed-off-by: Herman Morsink Vollenbroek Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/w83627hf_wdt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 48f2e0148bb4..e5c91d4404ed 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -129,6 +129,8 @@ static void w83627hf_init(void) t = inb_p(WDT_EFDR); /* read CRF5 */ t &= ~0x0C; /* set second mode & disable keyboard turning off watchdog */ + t |= 0x02; /* enable the WDTO# output low pulse + to the KBRST# pin (PIN60) */ outb_p(t, WDT_EFDR); /* Write back to CRF5 */ outb_p(0xF7, WDT_EFER); /* Select CRF7 */ -- cgit v1.2.3 From 202af5b307b0ccdad5e960a1f87fac322d8cdb02 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Dec 2010 01:27:35 +0900 Subject: watchdog: alim1535_wdt: fix compiler warning on ali_pci_tbl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Annotate ali_pci_tbl as '__used' to fix following warning: CC drivers/watchdog/alim1535_wdt.o drivers/watchdog/alim1535_wdt.c:304: warning: ‘ali_pci_tbl’ defined but not used Signed-off-by: Namhyung Kim Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/alim1535_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index 1e9caea8ff8a..fa4d36033552 100644 --- a/drivers/watchdog/alim1535_wdt.c +++ b/drivers/watchdog/alim1535_wdt.c @@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this, * want to register another driver on the same PCI id. */ -static struct pci_device_id ali_pci_tbl[] = { +static struct pci_device_id ali_pci_tbl[] __used = { { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, { 0, }, -- cgit v1.2.3 From a787e71068d7c2e438d8a5a38a7e1385389819f0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Dec 2010 01:27:36 +0900 Subject: watchdog: alim7101_wdt: fix compiler warning on alim7101_pci_tbl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Annotate alim7101_pci_tbl as '__used' to fix following warning: CC drivers/watchdog/alim7101_wdt.o drivers/watchdog/alim7101_wdt.c:433: warning: ‘alim7101_pci_tbl’ defined but not used Signed-off-by: Namhyung Kim Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/alim7101_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index d8d4da9a483d..4b7a2b4138ed 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c @@ -430,7 +430,7 @@ err_out: module_init(alim7101_wdt_init); module_exit(alim7101_wdt_unload); -static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { +static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { } -- cgit v1.2.3 From 5d63c13415db2819590bba975dd023eaa593ddc3 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 3 Dec 2010 10:51:43 -0600 Subject: watchdog: add CONFIG_WATCHDOG_NOWAYOUT support to PowerPC Book-E watchdog driver Normally, the watchdog is disabled when dev/watchdog is closed, but if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the watchdog should remain enabled. So we should disable it only if CONFIG_WATCHDOG_NOWAYOUT is not defined. Also ensure that /dev/watchdog is only opened by one process at a time. That way, a second process can't accidentally disable the watchdog while the first process has it open. There shouldn't be any need for more than one process to open /dev/watchdog anyway. Signed-off-by: Timur Tabi Acked-by: Josh Boyer Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/booke_wdt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index d11ffb091b0d..636e013e221e 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -193,8 +193,15 @@ static long booke_wdt_ioctl(struct file *file, return 0; } +/* wdt_is_active stores wether or not the /dev/watchdog device is opened */ +static unsigned long wdt_is_active; + static int booke_wdt_open(struct inode *inode, struct file *file) { + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &wdt_is_active)) + return -EBUSY; + spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 0) { booke_wdt_enabled = 1; @@ -210,8 +217,17 @@ static int booke_wdt_open(struct inode *inode, struct file *file) static int booke_wdt_release(struct inode *inode, struct file *file) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + /* Normally, the watchdog is disabled when /dev/watchdog is closed, but + * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the + * watchdog should remain enabled. So we disable it only if + * CONFIG_WATCHDOG_NOWAYOUT is not defined. + */ on_each_cpu(__booke_wdt_disable, NULL, 0); booke_wdt_enabled = 0; +#endif + + clear_bit(0, &wdt_is_active); return 0; } -- cgit v1.2.3 From 6ae98ed186cbe6909105c536c24419e52af8fc66 Mon Sep 17 00:00:00 2001 From: Randy Vinson Date: Mon, 6 Dec 2010 14:02:23 -0700 Subject: watchdog: Propagate Book E WDT period changes to all cores When the watchdog period is changed, it needs to be propagated to all cores in addition to the core that performed the change. Signed-off-by: Randy Vinson Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/booke_wdt.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 636e013e221e..7e7ec9c35b6a 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -85,6 +85,22 @@ static unsigned int sec_to_period(unsigned int secs) return 0; } +static void __booke_wdt_set(void *data) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val &= ~WDTP_MASK; + val |= WDTP(booke_wdt_period); + + mtspr(SPRN_TCR, val); +} + +static void booke_wdt_set(void) +{ + on_each_cpu(__booke_wdt_set, NULL, 0); +} + static void __booke_wdt_ping(void *data) { mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); @@ -181,8 +197,7 @@ static long booke_wdt_ioctl(struct file *file, #else booke_wdt_period = tmp; #endif - mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) | - WDTP(booke_wdt_period)); + booke_wdt_set(); return 0; case WDIOC_GETTIMEOUT: return put_user(booke_wdt_period, p); -- cgit v1.2.3 From 568dba66ac307532b6703331df71c17373c17a4a Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 14 Dec 2010 16:29:31 +0100 Subject: watchdog: ks8695_wdt: include mach/hardware.h instead of mach/timex.h. ks8695_wdt needs KS8695_CLOCK_RATE, which is defined in mach/hardware.h, which is pulled in by the include of mach/timex.h, but the latter is going away, so just include mach/hardware.h directly. Signed-off-by: Yegor Yefremov Signed-off-by: Lennert Buytenhek Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/ks8695_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index 2852bb2e3fd9..811471903e8a 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #define WDT_DEFAULT_TIME 5 /* seconds */ -- cgit v1.2.3 From d38bd479a10d1981816061da0a8ba27384dc3c35 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Fri, 31 Dec 2010 14:10:45 +0000 Subject: watchdog: iTCO_wdt: TCO Watchdog patch for Intel NM10 DeviceIDs This patch adds the Intel NM10 DeviceIDs for iTCO Watchdog. Reported-by: Dan Weinlader Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/iTCO_wdt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index b8838d2c67a6..db164153239e 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -1,7 +1,7 @@ /* * intel TCO Watchdog Driver * - * (c) Copyright 2006-2009 Wim Van Sebroeck . + * (c) Copyright 2006-2010 Wim Van Sebroeck . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,6 +26,7 @@ * document number 301473-002, 301474-026: 82801F (ICH6) * document number 313082-001, 313075-006: 631xESB, 632xESB * document number 307013-003, 307014-024: 82801G (ICH7) + * document number 322896-001, 322897-001: NM10 * document number 313056-003, 313057-017: 82801H (ICH8) * document number 316972-004, 316973-012: 82801I (ICH9) * document number 319973-002, 319974-002: 82801J (ICH10) @@ -85,6 +86,7 @@ enum iTCO_chipsets { TCO_ICH7DH, /* ICH7DH */ TCO_ICH7M, /* ICH7-M & ICH7-U */ TCO_ICH7MDH, /* ICH7-M DH */ + TCO_NM10, /* NM10 */ TCO_ICH8, /* ICH8 & ICH8R */ TCO_ICH8DH, /* ICH8DH */ TCO_ICH8DO, /* ICH8DO */ @@ -174,6 +176,7 @@ static struct { {"ICH7DH", 2}, {"ICH7-M or ICH7-U", 2}, {"ICH7-M DH", 2}, + {"NM10", 2}, {"ICH8 or ICH8R", 2}, {"ICH8DH", 2}, {"ICH8DO", 2}, @@ -291,6 +294,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, + { ITCO_PCI_DEVICE(0x27bc, TCO_NM10)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, -- cgit v1.2.3 From 203f8d893ed772ec8589cfd3c7d1af312643b703 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Fri, 7 Jan 2011 17:11:08 -0800 Subject: watchdog: iTCO_wdt: TCO Watchdog patch for Intel DH89xxCC PCH This patch adds the DeviceIDs for TCO Watchdog on the Intel DH89xxCC PCH. Signed-off-by: Seth Heasley Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/iTCO_wdt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index db164153239e..2c6c2b4ad8bf 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -32,8 +32,9 @@ * document number 319973-002, 319974-002: 82801J (ICH10) * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) * document number 320066-003, 320257-008: EP80597 (IICH) - * document number TBD : Cougar Point (CPT) + * document number 324645-001, 324646-001: Cougar Point (CPT) * document number TBD : Patsburg (PBG) + * document number TBD : DH89xxCC */ /* @@ -151,6 +152,7 @@ enum iTCO_chipsets { TCO_CPT31, /* Cougar Point */ TCO_PBG1, /* Patsburg */ TCO_PBG2, /* Patsburg */ + TCO_DH89XXCC, /* DH89xxCC */ }; static struct { @@ -241,6 +243,7 @@ static struct { {"Cougar Point", 2}, {"Patsburg", 2}, {"Patsburg", 2}, + {"DH89xxCC", 2}, {NULL, 0} }; @@ -359,6 +362,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, + { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); -- cgit v1.2.3 From 9378b63ccb32b9c071dab155c96357ad1e52a709 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 12 Jan 2011 00:50:37 -0800 Subject: x86, ia64, acpi: Clean up x86-ism in drivers/acpi/numa.c As pointed out by Linus CONFIG_X86 in drivers/acpi/numa.c is ugly. Builds and boots on ia64 (both normally and with maxcpus=8 to limit the number of cpus). Signed-off-by: Tony Luck Acked-by: Yinghai Lu Cc: Linus Torvalds Cc: Wu Fengguang Cc: Bjorn Helgaas Cc: Len Brown LKML-Reference: <4D2D6B5D.4080208@kernel.org> Signed-off-by: Ingo Molnar --- drivers/acpi/numa.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index d9926afec110..5eb25eb3ea48 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -275,23 +275,19 @@ acpi_table_parse_srat(enum acpi_srat_type id, int __init acpi_numa_init(void) { int ret = 0; - int nr_cpu_entries = nr_cpu_ids; -#ifdef CONFIG_X86 /* * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= * SRAT cpu entries could have different order with that in MADT. * So go over all cpu entries in SRAT to get apicid to node mapping. */ - nr_cpu_entries = MAX_LOCAL_APIC; -#endif /* SRAT: Static Resource Affinity Table */ if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY, - acpi_parse_x2apic_affinity, nr_cpu_entries); + acpi_parse_x2apic_affinity, 0); acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, - acpi_parse_processor_affinity, nr_cpu_entries); + acpi_parse_processor_affinity, 0); ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); -- cgit v1.2.3 From e13752a1de02044bfda352cbc834e3c9541f148b Mon Sep 17 00:00:00 2001 From: Lutz Ballaschke Date: Wed, 12 Jan 2011 01:09:02 +0100 Subject: watchdog: f71808e_wdt: add F71862FG, F71869 to Kconfig Update Kconfig with the additional Fintek hardware that we support. Signed-off-by: Lutz Ballaschke Acked-by: Giel van Schijndel Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 8a3aa2f050c8..3c6607ddcd20 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -409,11 +409,11 @@ config ALIM7101_WDT Most people will say N. config F71808E_WDT - tristate "Fintek F71808E, F71882FG and F71889FG Watchdog" + tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" depends on X86 && EXPERIMENTAL help This is the driver for the hardware watchdog on the Fintek - F71808E, F71882FG and F71889FG Super I/O controllers. + F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. You can compile this driver directly into the kernel, or use it as a module. The module will be called f71808e_wdt. -- cgit v1.2.3 From 15e28bf130081a574192fb934b832ac7d07739f7 Mon Sep 17 00:00:00 2001 From: Priyanka Gupta Date: Mon, 25 Oct 2010 17:58:04 -0700 Subject: watchdog: Add support for sp5100 chipset TCO This driver adds /dev/watchdog support for the AMD sp5100 aka SB7x0 chipsets. It follows the same conventions found in other /dev/watchdog drivers. Signed-off-by: Priyanka Gupta Signed-off-by: Mike Waychison Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 11 + drivers/watchdog/Makefile | 1 + drivers/watchdog/sp5100_tco.c | 480 ++++++++++++++++++++++++++++++++++++++++++ drivers/watchdog/sp5100_tco.h | 41 ++++ 4 files changed, 533 insertions(+) create mode 100644 drivers/watchdog/sp5100_tco.c create mode 100644 drivers/watchdog/sp5100_tco.h (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3c6607ddcd20..c48faa5ade73 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -418,6 +418,17 @@ config F71808E_WDT You can compile this driver directly into the kernel, or use it as a module. The module will be called f71808e_wdt. +config SP5100_TCO + tristate "AMD/ATI SP5100 TCO Timer/Watchdog" + depends on X86 && PCI + ---help--- + Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO + (Total Cost of Ownership) timer is a watchdog timer that will reboot + the machine after its expiration. The expiration time can be + configured with the "heartbeat" parameter. + + To compile this driver as a module, choose M here: the + module will be called sp5100_tco. config GEODE_WDT tristate "AMD Geode CS5535/CS5536 Watchdog" diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 4b0ef386229d..12e6c1e32671 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o +obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o obj-$(CONFIG_GEODE_WDT) += geodewdt.o obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c new file mode 100644 index 000000000000..808372883e88 --- /dev/null +++ b/drivers/watchdog/sp5100_tco.c @@ -0,0 +1,480 @@ +/* + * sp5100_tco : TCO timer driver for sp5100 chipsets + * + * (c) Copyright 2009 Google Inc., All Rights Reserved. + * + * Based on i8xx_tco.c: + * (c) Copyright 2000 kernel concepts , All Rights + * Reserved. + * http://www.kernelconcepts.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. + * + * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide" + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sp5100_tco.h" + +/* Module and version information */ +#define TCO_VERSION "0.01" +#define TCO_MODULE_NAME "SP5100 TCO timer" +#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION +#define PFX TCO_MODULE_NAME ": " + +/* internal variables */ +static void __iomem *tcobase; +static unsigned int pm_iobase; +static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ +static unsigned long timer_alive; +static char tco_expect_close; +static struct pci_dev *sp5100_tco_pci; + +/* the watchdog platform device */ +static struct platform_device *sp5100_tco_platform_device; + +/* module parameters */ + +#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat. */ +static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default=" + __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" + " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +/* + * Some TCO specific functions + */ +static void tco_timer_start(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = readl(SP5100_WDT_CONTROL(tcobase)); + val |= SP5100_WDT_START_STOP_BIT; + writel(val, SP5100_WDT_CONTROL(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static void tco_timer_stop(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = readl(SP5100_WDT_CONTROL(tcobase)); + val &= ~SP5100_WDT_START_STOP_BIT; + writel(val, SP5100_WDT_CONTROL(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static void tco_timer_keepalive(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = readl(SP5100_WDT_CONTROL(tcobase)); + val |= SP5100_WDT_TRIGGER_BIT; + writel(val, SP5100_WDT_CONTROL(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static int tco_timer_set_heartbeat(int t) +{ + unsigned long flags; + + if (t < 0 || t > 0xffff) + return -EINVAL; + + /* Write new heartbeat to watchdog */ + spin_lock_irqsave(&tco_lock, flags); + writel(t, SP5100_WDT_COUNT(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); + + heartbeat = t; + return 0; +} + +/* + * /dev/watchdog handling + */ + +static int sp5100_tco_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* Reload and activate timer */ + tco_timer_start(); + tco_timer_keepalive(); + return nonseekable_open(inode, file); +} + +static int sp5100_tco_release(struct inode *inode, struct file *file) +{ + /* Shut off the timer. */ + if (tco_expect_close == 42) { + tco_timer_stop(); + } else { + printk(KERN_CRIT PFX + "Unexpected close, not stopping watchdog!\n"); + tco_timer_keepalive(); + } + clear_bit(0, &timer_alive); + tco_expect_close = 0; + return 0; +} + +static ssize_t sp5100_tco_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* note: just in case someone wrote the magic character + * five months ago... */ + tco_expect_close = 0; + + /* scan to see whether or not we got the magic character + */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + tco_expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + tco_timer_keepalive(); + } + return len; +} + +static long sp5100_tco_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_options, retval = -EINVAL; + int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; + static const struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = TCO_MODULE_NAME, + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, + sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_SETOPTIONS: + if (get_user(new_options, p)) + return -EFAULT; + if (new_options & WDIOS_DISABLECARD) { + tco_timer_stop(); + retval = 0; + } + if (new_options & WDIOS_ENABLECARD) { + tco_timer_start(); + tco_timer_keepalive(); + retval = 0; + } + return retval; + case WDIOC_KEEPALIVE: + tco_timer_keepalive(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_heartbeat, p)) + return -EFAULT; + if (tco_timer_set_heartbeat(new_heartbeat)) + return -EINVAL; + tco_timer_keepalive(); + /* Fall through */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + default: + return -ENOTTY; + } +} + +/* + * Kernel Interfaces + */ + +static const struct file_operations sp5100_tco_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = sp5100_tco_write, + .unlocked_ioctl = sp5100_tco_ioctl, + .open = sp5100_tco_open, + .release = sp5100_tco_release, +}; + +static struct miscdevice sp5100_tco_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &sp5100_tco_fops, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might + * want to register another driver on the same PCI id. + */ +static struct pci_device_id sp5100_tco_pci_tbl[] = { + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID, + PCI_ANY_ID, }, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl); + +/* + * Init & exit routines + */ + +static unsigned char __devinit sp5100_tco_setupdevice(void) +{ + struct pci_dev *dev = NULL; + u32 val; + + /* Match the PCI device */ + for_each_pci_dev(dev) { + if (pci_match_id(sp5100_tco_pci_tbl, dev) != NULL) { + sp5100_tco_pci = dev; + break; + } + } + + if (!sp5100_tco_pci) + return 0; + + /* Request the IO ports used by this driver */ + pm_iobase = SP5100_IO_PM_INDEX_REG; + if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + pm_iobase); + goto exit; + } + + /* Find the watchdog base address. */ + outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG); + val = inb(SP5100_IO_PM_DATA_REG); + outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG); + val = val << 8 | inb(SP5100_IO_PM_DATA_REG); + outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG); + val = val << 8 | inb(SP5100_IO_PM_DATA_REG); + outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG); + /* Low three bits of BASE0 are reserved. */ + val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); + + tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); + if (tcobase == 0) { + printk(KERN_ERR PFX "failed to get tcobase address\n"); + goto unreg_region; + } + + /* Enable watchdog decode bit */ + pci_read_config_dword(sp5100_tco_pci, + SP5100_PCI_WATCHDOG_MISC_REG, + &val); + + val |= SP5100_PCI_WATCHDOG_DECODE_EN; + + pci_write_config_dword(sp5100_tco_pci, + SP5100_PCI_WATCHDOG_MISC_REG, + val); + + /* Enable Watchdog timer and set the resolution to 1 sec. */ + outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); + val = inb(SP5100_IO_PM_DATA_REG); + val |= SP5100_PM_WATCHDOG_SECOND_RES; + val &= ~SP5100_PM_WATCHDOG_DISABLE; + outb(val, SP5100_IO_PM_DATA_REG); + + /* Check that the watchdog action is set to reset the system. */ + val = readl(SP5100_WDT_CONTROL(tcobase)); + val &= ~SP5100_PM_WATCHDOG_ACTION_RESET; + writel(val, SP5100_WDT_CONTROL(tcobase)); + + /* Set a reasonable heartbeat before we stop the timer */ + tco_timer_set_heartbeat(heartbeat); + + /* + * Stop the TCO before we change anything so we don't race with + * a zeroed timer. + */ + tco_timer_stop(); + + /* Done */ + return 1; + + iounmap(tcobase); +unreg_region: + release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); +exit: + return 0; +} + +static int __devinit sp5100_tco_init(struct platform_device *dev) +{ + int ret; + u32 val; + + /* Check whether or not the hardware watchdog is there. If found, then + * set it up. + */ + if (!sp5100_tco_setupdevice()) + return -ENODEV; + + /* Check to see if last reboot was due to watchdog timeout */ + printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n", + readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ? + "" : "not "); + + /* Clear out the old status */ + val = readl(SP5100_WDT_CONTROL(tcobase)); + val &= ~SP5100_PM_WATCHDOG_FIRED; + writel(val, SP5100_WDT_CONTROL(tcobase)); + + /* + * Check that the heartbeat value is within it's range. + * If not, reset to the default. + */ + if (tco_timer_set_heartbeat(heartbeat)) { + heartbeat = WATCHDOG_HEARTBEAT; + tco_timer_set_heartbeat(heartbeat); + } + + ret = misc_register(&sp5100_tco_miscdev); + if (ret != 0) { + printk(KERN_ERR PFX "cannot register miscdev on minor=" + "%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto exit; + } + + clear_bit(0, &timer_alive); + + printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec" + " (nowayout=%d)\n", + tcobase, heartbeat, nowayout); + + return 0; + +exit: + iounmap(tcobase); + release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); + return ret; +} + +static void __devexit sp5100_tco_cleanup(void) +{ + /* Stop the timer before we leave */ + if (!nowayout) + tco_timer_stop(); + + /* Deregister */ + misc_deregister(&sp5100_tco_miscdev); + iounmap(tcobase); + release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); +} + +static int __devexit sp5100_tco_remove(struct platform_device *dev) +{ + if (tcobase) + sp5100_tco_cleanup(); + return 0; +} + +static void sp5100_tco_shutdown(struct platform_device *dev) +{ + tco_timer_stop(); +} + +static struct platform_driver sp5100_tco_driver = { + .probe = sp5100_tco_init, + .remove = __devexit_p(sp5100_tco_remove), + .shutdown = sp5100_tco_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = TCO_MODULE_NAME, + }, +}; + +static int __init sp5100_tco_init_module(void) +{ + int err; + + printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n", + TCO_VERSION); + + err = platform_driver_register(&sp5100_tco_driver); + if (err) + return err; + + sp5100_tco_platform_device = platform_device_register_simple( + TCO_MODULE_NAME, -1, NULL, 0); + if (IS_ERR(sp5100_tco_platform_device)) { + err = PTR_ERR(sp5100_tco_platform_device); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&sp5100_tco_driver); + return err; +} + +static void __exit sp5100_tco_cleanup_module(void) +{ + platform_device_unregister(sp5100_tco_platform_device); + platform_driver_unregister(&sp5100_tco_driver); + printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n"); +} + +module_init(sp5100_tco_init_module); +module_exit(sp5100_tco_cleanup_module); + +MODULE_AUTHOR("Priyanka Gupta"); +MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h new file mode 100644 index 000000000000..a5a16cc90a34 --- /dev/null +++ b/drivers/watchdog/sp5100_tco.h @@ -0,0 +1,41 @@ +/* + * sp5100_tco: TCO timer driver for sp5100 chipsets. + * + * (c) Copyright 2009 Google Inc., All Rights Reserved. + * + * TCO timer driver for sp5100 chipsets + */ + +/* + * Some address definitions for the Watchdog + */ + +#define SP5100_WDT_MEM_MAP_SIZE 0x08 +#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */ +#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */ + +#define SP5100_WDT_START_STOP_BIT 1 +#define SP5100_WDT_TRIGGER_BIT (1 << 7) + +#define SP5100_PCI_WATCHDOG_MISC_REG 0x41 +#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3) + +#define SP5100_PM_IOPORTS_SIZE 0x02 + +/* These two IO registers are hardcoded and there doesn't seem to be a way to + * read them from a register. + */ +#define SP5100_IO_PM_INDEX_REG 0xCD6 +#define SP5100_IO_PM_DATA_REG 0xCD7 + +#define SP5100_PM_WATCHDOG_CONTROL 0x69 +#define SP5100_PM_WATCHDOG_BASE0 0x6C +#define SP5100_PM_WATCHDOG_BASE1 0x6D +#define SP5100_PM_WATCHDOG_BASE2 0x6E +#define SP5100_PM_WATCHDOG_BASE3 0x6F + +#define SP5100_PM_WATCHDOG_FIRED (1 << 1) +#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2) + +#define SP5100_PM_WATCHDOG_DISABLE 1 +#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1) -- cgit v1.2.3 From 456c730153fe33134fe93742510a96e46a9217c4 Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Mon, 25 Oct 2010 17:58:05 -0700 Subject: watchdog: Add TCO support for nVidia chipsets This driver adds support for /dev/watchdog for boards using either the MCP51 or MCP55 chipsets. These are also known as the nForce 430 and nForce 550. This driver is likely to work on other chipsets as well, though those are the only two that have been tested. Signed-off-by: Mike Waychison Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 18 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/nv_tco.c | 512 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/watchdog/nv_tco.h | 64 ++++++ 4 files changed, 595 insertions(+) create mode 100644 drivers/watchdog/nv_tco.c create mode 100644 drivers/watchdog/nv_tco.h (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index c48faa5ade73..db00fa9f6979 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -642,6 +642,24 @@ config PC87413_WDT Most people will say N. +config NV_TCO + tristate "nVidia TCO Timer/Watchdog" + depends on X86 && PCI + ---help--- + Hardware driver for the TCO timer built into the nVidia Hub family + (such as the MCP51). The TCO (Total Cost of Ownership) timer is a + watchdog timer that will reboot the machine after its second + expiration. The expiration time can be configured with the + "heartbeat" parameter. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the + machine. If this is the case you will get a kernel message like + "failed to reset NO_REBOOT flag, reboot disabled by hardware". + + To compile this driver as a module, choose M here: the + module will be called nv_tco. + config RDC321X_WDT tristate "RDC R-321x SoC watchdog" depends on X86_RDC321X diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 12e6c1e32671..cd77f5492f95 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -87,6 +87,7 @@ obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o +obj-$(CONFIG_NV_TCO) += nv_tco.o obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_SBC8360_WDT) += sbc8360.o diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c new file mode 100644 index 000000000000..1a50aa7079bf --- /dev/null +++ b/drivers/watchdog/nv_tco.c @@ -0,0 +1,512 @@ +/* + * nv_tco 0.01: TCO timer driver for NV chipsets + * + * (c) Copyright 2005 Google Inc., All Rights Reserved. + * + * Based off i8xx_tco.c: + * (c) Copyright 2000 kernel concepts , All Rights + * Reserved. + * http://www.kernelconcepts.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. + * + * TCO timer driver for NV chipsets + * based on softdog.c by Alan Cox + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nv_tco.h" + +/* Module and version information */ +#define TCO_VERSION "0.01" +#define TCO_MODULE_NAME "NV_TCO" +#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION +#define PFX TCO_MODULE_NAME ": " + +/* internal variables */ +static unsigned int tcobase; +static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ +static unsigned long timer_alive; +static char tco_expect_close; +static struct pci_dev *tco_pci; + +/* the watchdog platform device */ +static struct platform_device *nv_tco_platform_device; + +/* module parameters */ +#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2 t, so if t > 0x3f, so is + * tmrval=seconds_to_ticks(t). Check that the count in seconds isn't + * out of range on it's own (to avoid overflow in tmrval). + */ + if (t < 0 || t > 0x3f) + return -EINVAL; + tmrval = seconds_to_ticks(t); + + /* "Values of 0h-3h are ignored and should not be attempted" */ + if (tmrval > 0x3f || tmrval < 0x04) + return -EINVAL; + + /* Write new heartbeat to watchdog */ + spin_lock_irqsave(&tco_lock, flags); + val = inb(TCO_TMR(tcobase)); + val &= 0xc0; + val |= tmrval; + outb(val, TCO_TMR(tcobase)); + val = inb(TCO_TMR(tcobase)); + + if ((val & 0x3f) != tmrval) + ret = -EINVAL; + spin_unlock_irqrestore(&tco_lock, flags); + + if (ret) + return ret; + + heartbeat = t; + return 0; +} + +/* + * /dev/watchdog handling + */ + +static int nv_tco_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* Reload and activate timer */ + tco_timer_keepalive(); + tco_timer_start(); + return nonseekable_open(inode, file); +} + +static int nv_tco_release(struct inode *inode, struct file *file) +{ + /* Shut off the timer */ + if (tco_expect_close == 42) { + tco_timer_stop(); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping " + "watchdog!\n"); + tco_timer_keepalive(); + } + clear_bit(0, &timer_alive); + tco_expect_close = 0; + return 0; +} + +static ssize_t nv_tco_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* + * note: just in case someone wrote the magic character + * five months ago... + */ + tco_expect_close = 0; + + /* + * scan to see whether or not we got the magic + * character + */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + tco_expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + tco_timer_keepalive(); + } + return len; +} + +static long nv_tco_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_options, retval = -EINVAL; + int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; + static const struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = TCO_MODULE_NAME, + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_SETOPTIONS: + if (get_user(new_options, p)) + return -EFAULT; + if (new_options & WDIOS_DISABLECARD) { + tco_timer_stop(); + retval = 0; + } + if (new_options & WDIOS_ENABLECARD) { + tco_timer_keepalive(); + tco_timer_start(); + retval = 0; + } + return retval; + case WDIOC_KEEPALIVE: + tco_timer_keepalive(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_heartbeat, p)) + return -EFAULT; + if (tco_timer_set_heartbeat(new_heartbeat)) + return -EINVAL; + tco_timer_keepalive(); + /* Fall through */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + default: + return -ENOTTY; + } +} + +/* + * Kernel Interfaces + */ + +static const struct file_operations nv_tco_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = nv_tco_write, + .unlocked_ioctl = nv_tco_ioctl, + .open = nv_tco_open, + .release = nv_tco_release, +}; + +static struct miscdevice nv_tco_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &nv_tco_fops, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id tco_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE(pci, tco_pci_tbl); + +/* + * Init & exit routines + */ + +static unsigned char __init nv_tco_getdevice(void) +{ + struct pci_dev *dev = NULL; + u32 val; + + /* Find the PCI device */ + for_each_pci_dev(dev) { + if (pci_match_id(tco_pci_tbl, dev) != NULL) { + tco_pci = dev; + break; + } + } + + if (!tco_pci) + return 0; + + /* Find the base io port */ + pci_read_config_dword(tco_pci, 0x64, &val); + val &= 0xffff; + if (val == 0x0001 || val == 0x0000) { + /* Something is wrong here, bar isn't setup */ + printk(KERN_ERR PFX "failed to get tcobase address\n"); + return 0; + } + val &= 0xff00; + tcobase = val + 0x40; + + if (!request_region(tcobase, 0x10, "NV TCO")) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + tcobase); + return 0; + } + + /* Set a reasonable heartbeat before we stop the timer */ + tco_timer_set_heartbeat(30); + + /* + * Stop the TCO before we change anything so we don't race with + * a zeroed timer. + */ + tco_timer_keepalive(); + tco_timer_stop(); + + /* Disable SMI caused by TCO */ + if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + MCP51_SMI_EN(tcobase)); + goto out; + } + val = inl(MCP51_SMI_EN(tcobase)); + val &= ~MCP51_SMI_EN_TCO; + outl(val, MCP51_SMI_EN(tcobase)); + val = inl(MCP51_SMI_EN(tcobase)); + release_region(MCP51_SMI_EN(tcobase), 4); + if (val & MCP51_SMI_EN_TCO) { + printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n"); + goto out; + } + + /* Check chipset's NO_REBOOT bit */ + pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); + val |= MCP51_SMBUS_SETUP_B_TCO_REBOOT; + pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val); + pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); + if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) { + printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot " + "disabled by hardware\n"); + goto out; + } + + return 1; +out: + release_region(tcobase, 0x10); + return 0; +} + +static int __devinit nv_tco_init(struct platform_device *dev) +{ + int ret; + + /* Check whether or not the hardware watchdog is there */ + if (!nv_tco_getdevice()) + return -ENODEV; + + /* Check to see if last reboot was due to watchdog timeout */ + printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n", + inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not "); + + /* Clear out the old status */ + outl(TCO_STS_RESET, TCO_STS(tcobase)); + + /* + * Check that the heartbeat value is within it's range. + * If not, reset to the default. + */ + if (tco_timer_set_heartbeat(heartbeat)) { + heartbeat = WATCHDOG_HEARTBEAT; + tco_timer_set_heartbeat(heartbeat); + printk(KERN_INFO PFX "heartbeat value must be 2, All Rights + * Reserved. + * http://www.kernelconcepts.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. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for NV chipsets + * based on softdog.c by Alan Cox + */ + +/* + * Some address definitions for the TCO + */ + +#define TCO_RLD(base) ((base) + 0x00) /* TCO Timer Reload and Current Value */ +#define TCO_TMR(base) ((base) + 0x01) /* TCO Timer Initial Value */ + +#define TCO_STS(base) ((base) + 0x04) /* TCO Status Register */ +/* + * TCO Boot Status bit: set on TCO reset, reset by software or standby + * power-good (survives reboots), unfortunately this bit is never + * set. + */ +# define TCO_STS_BOOT_STS (1 << 9) +/* + * first and 2nd timeout status bits, these also survive a warm boot, + * and they work, so we use them. + */ +# define TCO_STS_TCO_INT_STS (1 << 1) +# define TCO_STS_TCO2TO_STS (1 << 10) +# define TCO_STS_RESET (TCO_STS_BOOT_STS | TCO_STS_TCO2TO_STS | \ + TCO_STS_TCO_INT_STS) + +#define TCO_CNT(base) ((base) + 0x08) /* TCO Control Register */ +# define TCO_CNT_TCOHALT (1 << 12) + +#define MCP51_SMBUS_SETUP_B 0xe8 +# define MCP51_SMBUS_SETUP_B_TCO_REBOOT (1 << 25) + +/* + * The SMI_EN register is at the base io address + 0x04, + * while TCOBASE is + 0x40. + */ +#define MCP51_SMI_EN(base) ((base) - 0x40 + 0x04) +# define MCP51_SMI_EN_TCO ((1 << 4) | (1 << 5)) -- cgit v1.2.3 From f8394f61c66f48b1fe9d6964ddce492d7f9a4cd9 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 4 Jan 2011 21:28:19 +0100 Subject: watchdog: add driver for the Atheros AR71XX/AR724X/AR913X SoCs This patch adds a driver for the built-in hardware watchdog device of the Atheros AR71XX/AR724X/AR913X SoCs. Signed-off-by: Gabor Juhos Signed-off-by: Imre Kaloz Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 7 + drivers/watchdog/Makefile | 1 + drivers/watchdog/ath79_wdt.c | 305 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 313 insertions(+) create mode 100644 drivers/watchdog/ath79_wdt.c (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index db00fa9f6979..68a9527f92d0 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -866,6 +866,13 @@ config SBC_EPX_C3_WATCHDOG # MIPS Architecture +config ATH79_WDT + tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog" + depends on ATH79 + help + Hardware driver for the built-in watchdog timer on the Atheros + AR71XX/AR724X/AR913X SoCs. + config BCM47XX_WDT tristate "Broadcom BCM47xx Watchdog Timer" depends on BCM47XX diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index cd77f5492f95..9b6b33a02072 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o # M68KNOMMU Architecture # MIPS Architecture +obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c new file mode 100644 index 000000000000..725c84bfdd76 --- /dev/null +++ b/drivers/watchdog/ath79_wdt.c @@ -0,0 +1,305 @@ +/* + * Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer. + * + * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008 Imre Kaloz + * + * This driver was based on: drivers/watchdog/ixp4xx_wdt.c + * Author: Deepak Saxena + * Copyright 2004 (c) MontaVista, Software, Inc. + * + * which again was based on sa1100 driver, + * Copyright (C) 2000 Oleg Drokin + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "ath79-wdt" + +#define WDT_TIMEOUT 15 /* seconds */ + +#define WDOG_CTRL_LAST_RESET BIT(31) +#define WDOG_CTRL_ACTION_MASK 3 +#define WDOG_CTRL_ACTION_NONE 0 /* no action */ +#define WDOG_CTRL_ACTION_GPI 1 /* general purpose interrupt */ +#define WDOG_CTRL_ACTION_NMI 2 /* NMI */ +#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */ + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " + "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static int timeout = WDT_TIMEOUT; +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds " + "(default=" __MODULE_STRING(WDT_TIMEOUT) "s)"); + +static unsigned long wdt_flags; + +#define WDT_FLAGS_BUSY 0 +#define WDT_FLAGS_EXPECT_CLOSE 1 + +static struct clk *wdt_clk; +static unsigned long wdt_freq; +static int boot_status; +static int max_timeout; + +static inline void ath79_wdt_keepalive(void) +{ + ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout); +} + +static inline void ath79_wdt_enable(void) +{ + ath79_wdt_keepalive(); + ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR); +} + +static inline void ath79_wdt_disable(void) +{ + ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE); +} + +static int ath79_wdt_set_timeout(int val) +{ + if (val < 1 || val > max_timeout) + return -EINVAL; + + timeout = val; + ath79_wdt_keepalive(); + + return 0; +} + +static int ath79_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags)) + return -EBUSY; + + clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + ath79_wdt_enable(); + + return nonseekable_open(inode, file); +} + +static int ath79_wdt_release(struct inode *inode, struct file *file) +{ + if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags)) + ath79_wdt_disable(); + else { + pr_crit(DRIVER_NAME ": device closed unexpectedly, " + "watchdog timer will not stop!\n"); + ath79_wdt_keepalive(); + } + + clear_bit(WDT_FLAGS_BUSY, &wdt_flags); + clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + + return 0; +} + +static ssize_t ath79_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + + if (c == 'V') + set_bit(WDT_FLAGS_EXPECT_CLOSE, + &wdt_flags); + } + } + + ath79_wdt_keepalive(); + } + + return len; +} + +static const struct watchdog_info ath79_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE | WDIOF_CARDRESET, + .firmware_version = 0, + .identity = "ATH79 watchdog", +}; + +static long ath79_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int err; + int t; + + switch (cmd) { + case WDIOC_GETSUPPORT: + err = copy_to_user(argp, &ath79_wdt_info, + sizeof(ath79_wdt_info)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + err = put_user(0, p); + break; + + case WDIOC_GETBOOTSTATUS: + err = put_user(boot_status, p); + break; + + case WDIOC_KEEPALIVE: + ath79_wdt_keepalive(); + err = 0; + break; + + case WDIOC_SETTIMEOUT: + err = get_user(t, p); + if (err) + break; + + err = ath79_wdt_set_timeout(t); + if (err) + break; + + /* fallthrough */ + case WDIOC_GETTIMEOUT: + err = put_user(timeout, p); + break; + + default: + err = -ENOTTY; + break; + } + + return err; +} + +static const struct file_operations ath79_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = ath79_wdt_write, + .unlocked_ioctl = ath79_wdt_ioctl, + .open = ath79_wdt_open, + .release = ath79_wdt_release, +}; + +static struct miscdevice ath79_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ath79_wdt_fops, +}; + +static int __devinit ath79_wdt_probe(struct platform_device *pdev) +{ + u32 ctrl; + int err; + + wdt_clk = clk_get(&pdev->dev, "wdt"); + if (IS_ERR(wdt_clk)) + return PTR_ERR(wdt_clk); + + err = clk_enable(wdt_clk); + if (err) + goto err_clk_put; + + wdt_freq = clk_get_rate(wdt_clk); + if (!wdt_freq) { + err = -EINVAL; + goto err_clk_disable; + } + + max_timeout = (0xfffffffful / wdt_freq); + if (timeout < 1 || timeout > max_timeout) { + timeout = max_timeout; + dev_info(&pdev->dev, + "timeout value must be 0 < timeout < %d, using %d\n", + max_timeout, timeout); + } + + ctrl = ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL); + boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0; + + err = misc_register(&ath79_wdt_miscdev); + if (err) { + dev_err(&pdev->dev, + "unable to register misc device, err=%d\n", err); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable(wdt_clk); +err_clk_put: + clk_put(wdt_clk); + return err; +} + +static int __devexit ath79_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(&ath79_wdt_miscdev); + clk_disable(wdt_clk); + clk_put(wdt_clk); + return 0; +} + +static void ath97_wdt_shutdown(struct platform_device *pdev) +{ + ath79_wdt_disable(); +} + +static struct platform_driver ath79_wdt_driver = { + .remove = __devexit_p(ath79_wdt_remove), + .shutdown = ath97_wdt_shutdown, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ath79_wdt_init(void) +{ + return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe); +} +module_init(ath79_wdt_init); + +static void __exit ath79_wdt_exit(void) +{ + platform_driver_unregister(&ath79_wdt_driver); +} +module_exit(ath79_wdt_exit); + +MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver"); +MODULE_AUTHOR("Gabor Juhos Date: Wed, 3 Nov 2010 15:07:28 +0100 Subject: watchdog: Add MCF548x watchdog driver. Add watchdog driver for MCF548x. Signed-off-by: Philippe De Muyter Signed-off-by: Wim Van Sebroeck --- arch/m68k/include/asm/m548xgpt.h | 2 + drivers/watchdog/Kconfig | 7 +- drivers/watchdog/Makefile | 3 +- drivers/watchdog/m548x_wdt.c | 227 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/m548x_wdt.c (limited to 'drivers') diff --git a/arch/m68k/include/asm/m548xgpt.h b/arch/m68k/include/asm/m548xgpt.h index c8ef158a1c4e..33b2eef90f0a 100644 --- a/arch/m68k/include/asm/m548xgpt.h +++ b/arch/m68k/include/asm/m548xgpt.h @@ -59,11 +59,13 @@ #define MCF_GPT_GMS_GPIO_INPUT (0x00000000) #define MCF_GPT_GMS_GPIO_OUTLO (0x00000020) #define MCF_GPT_GMS_GPIO_OUTHI (0x00000030) +#define MCF_GPT_GMS_GPIO_MASK (0x00000030) #define MCF_GPT_GMS_TMS_DISABLE (0x00000000) #define MCF_GPT_GMS_TMS_INCAPT (0x00000001) #define MCF_GPT_GMS_TMS_OUTCAPT (0x00000002) #define MCF_GPT_GMS_TMS_PWM (0x00000003) #define MCF_GPT_GMS_TMS_GPIO (0x00000004) +#define MCF_GPT_GMS_TMS_MASK (0x00000007) /* Bit definitions and macros for MCF_GPT_GCIR */ #define MCF_GPT_GCIR_CNT(x) (((x)&0x0000FFFF)<<0) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 68a9527f92d0..2e2400e7322e 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -862,7 +862,12 @@ config SBC_EPX_C3_WATCHDOG # M68K Architecture -# M68KNOMMU Architecture +config M548x_WATCHDOG + tristate "MCF548x watchdog support" + depends on M548x + help + To compile this driver as a module, choose M here: the + module will be called m548x_wdt. # MIPS Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 9b6b33a02072..dd776651917c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -106,8 +106,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o # M32R Architecture # M68K Architecture - -# M68KNOMMU Architecture +obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o # MIPS Architecture obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m548x_wdt.c new file mode 100644 index 000000000000..cabbcfe1c847 --- /dev/null +++ b/drivers/watchdog/m548x_wdt.c @@ -0,0 +1,227 @@ +/* + * drivers/watchdog/m548x_wdt.c + * + * Watchdog driver for ColdFire MCF548x processors + * Copyright 2010 (c) Philippe De Muyter + * + * Adapted from the IXP4xx watchdog driver, which carries these notices: + * + * Author: Deepak Saxena + * + * Copyright 2004 (c) MontaVista, Software, Inc. + * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int nowayout = WATCHDOG_NOWAYOUT; +static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */ +static unsigned long wdt_status; + +#define WDT_IN_USE 0 +#define WDT_OK_TO_CLOSE 1 + +static void wdt_enable(void) +{ + unsigned int gms0; + + /* preserve GPIO usage, if any */ + gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0); + if (gms0 & MCF_GPT_GMS_TMS_GPIO) + gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK + | MCF_GPT_GMS_OD); + else + gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD; + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); + __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) | + MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0); + gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE; + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); +} + +static void wdt_disable(void) +{ + unsigned int gms0; + + /* disable watchdog */ + gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0); + gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE); + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); +} + +static void wdt_keepalive(void) +{ + unsigned int gms0; + + gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0); + gms0 |= MCF_GPT_GMS_OCPW(0xA5); + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); +} + +static int m548x_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) + return -EBUSY; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + wdt_enable(); + return nonseekable_open(inode, file); +} + +static ssize_t m548x_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + set_bit(WDT_OK_TO_CLOSE, &wdt_status); + } + } + wdt_keepalive(); + } + return len; +} + +static const struct watchdog_info ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING, + .identity = "Coldfire M548x Watchdog", +}; + +static long m548x_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -ENOTTY; + int time; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_KEEPALIVE: + wdt_keepalive(); + ret = 0; + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(time, (int *)arg); + if (ret) + break; + + if (time <= 0 || time > 30) { + ret = -EINVAL; + break; + } + + heartbeat = time; + wdt_enable(); + /* Fall through */ + + case WDIOC_GETTIMEOUT: + ret = put_user(heartbeat, (int *)arg); + break; + } + return ret; +} + +static int m548x_wdt_release(struct inode *inode, struct file *file) +{ + if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) + wdt_disable(); + else { + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " + "timer will not stop\n"); + wdt_keepalive(); + } + clear_bit(WDT_IN_USE, &wdt_status); + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + return 0; +} + + +static const struct file_operations m548x_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = m548x_wdt_write, + .unlocked_ioctl = m548x_wdt_ioctl, + .open = m548x_wdt_open, + .release = m548x_wdt_release, +}; + +static struct miscdevice m548x_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &m548x_wdt_fops, +}; + +static int __init m548x_wdt_init(void) +{ + if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4, + "Coldfire M548x Watchdog")) { + printk(KERN_WARNING + "Coldfire M548x Watchdog : I/O region busy\n"); + return -EBUSY; + } + printk(KERN_INFO "ColdFire watchdog driver is loaded.\n"); + + return misc_register(&m548x_wdt_miscdev); +} + +static void __exit m548x_wdt_exit(void) +{ + misc_deregister(&m548x_wdt_miscdev); + release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4); +} + +module_init(m548x_wdt_init); +module_exit(m548x_wdt_exit); + +MODULE_AUTHOR("Philippe De Muyter "); +MODULE_DESCRIPTION("Coldfire M548x Watchdog"); + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.2.3 From 63cee946148821bca42be10130b061c2d0f5af7e Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Thu, 4 Nov 2010 11:01:31 +0100 Subject: regulator: lock supply in regulator enable This patch add locks around regulator supply enable. Signed-off-by: Mattias Wallin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ba521f0f0fac..81336e23848a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1267,17 +1267,15 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; - if (rdev->use_count == 0) { - /* do we need to enable the supply regulator first */ - if (rdev->supply) { - mutex_lock(&rdev->supply->mutex); - ret = _regulator_enable(rdev->supply); - mutex_unlock(&rdev->supply->mutex); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); - return ret; - } + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev_get_name(rdev), ret); + return ret; } } -- cgit v1.2.3 From 3a93f2a9f4d8f73d74c0e552feb68a10f778a219 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Nov 2010 14:38:29 +0000 Subject: regulator: Report actual configured voltage to set_voltage() Change the interface used by set_voltage() to report the selected value to the regulator core in terms of a selector used by list_voltage(). This allows the regulator core to know the voltage that was chosen without having to do an explict get_voltage(), which would be much more expensive as it will generally access hardware. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/88pm8607.c | 3 ++- drivers/regulator/ab3100.c | 5 ++++- drivers/regulator/ab8500.c | 5 ++++- drivers/regulator/core.c | 14 ++++++++++-- drivers/regulator/da903x.c | 17 +++++++++----- drivers/regulator/isl6271a-regulator.c | 6 ++++- drivers/regulator/lp3971.c | 10 +++++++-- drivers/regulator/lp3972.c | 10 +++++++-- drivers/regulator/max1586.c | 30 ++++++++++++------------- drivers/regulator/max8649.c | 3 ++- drivers/regulator/max8660.c | 14 +++++++++--- drivers/regulator/max8925-regulator.c | 3 ++- drivers/regulator/max8952.c | 3 ++- drivers/regulator/max8998.c | 8 +++++-- drivers/regulator/mc13783-regulator.c | 10 +++++++-- drivers/regulator/pcap-regulator.c | 7 ++++-- drivers/regulator/pcf50633-regulator.c | 5 ++++- drivers/regulator/tps65023-regulator.c | 9 ++++++-- drivers/regulator/tps6507x-regulator.c | 10 +++++++-- drivers/regulator/tps6586x-regulator.c | 15 ++++++++----- drivers/regulator/twl-regulator.c | 11 ++++++--- drivers/regulator/wm831x-dcdc.c | 17 +++++++++----- drivers/regulator/wm831x-ldo.c | 41 ++++++++++++++++++++++++---------- drivers/regulator/wm8350-regulator.c | 8 +++++-- drivers/regulator/wm8400-regulator.c | 8 +++++-- drivers/regulator/wm8994-regulator.c | 6 +++-- include/linux/regulator/driver.h | 3 ++- 27 files changed, 202 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 2ce2eb71d0f5..dd6308499bd4 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -249,7 +249,7 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) } static int pm8607_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); uint8_t val, mask; @@ -263,6 +263,7 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, ret = choose_voltage(rdev, min_uV, max_uV); if (ret < 0) return -EINVAL; + *selector = ret; val = (uint8_t)(ret << info->vol_shift); mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index b349266a43de..ed6feaf9398d 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -362,7 +362,8 @@ static int ab3100_get_best_voltage_index(struct regulator_dev *reg, } static int ab3100_set_voltage_regulator(struct regulator_dev *reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct ab3100_regulator *abreg = reg->reg_data; u8 regval; @@ -373,6 +374,8 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg, if (bestindex < 0) return bestindex; + *selector = bestindex; + err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg, ®val); if (err) { diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index db6b70f20511..2f4ec0facef1 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -215,7 +215,8 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, } static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { int regulator_id, ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); @@ -232,6 +233,8 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, return ret; } + *selector = ret; + /* set the registers for the request */ ret = abx500_mask_and_set_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 81336e23848a..67d3a61f3785 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -723,13 +723,16 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, struct regulator_ops *ops = rdev->desc->ops; const char *name = rdev_get_name(rdev); int ret; + unsigned selector; /* do we need to apply the constraint voltage */ if (rdev->constraints->apply_uV && rdev->constraints->min_uV == rdev->constraints->max_uV && ops->set_voltage) { ret = ops->set_voltage(rdev, - rdev->constraints->min_uV, rdev->constraints->max_uV); + rdev->constraints->min_uV, + rdev->constraints->max_uV, + &selector); if (ret < 0) { printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n", __func__, @@ -1625,6 +1628,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret; + unsigned selector; mutex_lock(&rdev->mutex); @@ -1640,7 +1644,13 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) goto out; regulator->min_uV = min_uV; regulator->max_uV = max_uV; - ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV); + + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); + + if (rdev->desc->ops->list_voltage) + selector = rdev->desc->ops->list_voltage(rdev, selector); + else + selector = -1; out: _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index f8c4661a7a81..362e08221085 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -107,7 +107,7 @@ static inline int check_range(struct da903x_regulator_info *info, /* DA9030/DA9034 common operations */ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -119,6 +119,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -187,7 +188,8 @@ static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector) /* DA9030 specific operations */ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); @@ -200,6 +202,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */ @@ -214,7 +217,8 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, } static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); @@ -234,6 +238,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, val = (min_uV - thresh + info->step_uV - 1) / info->step_uV; } + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -263,7 +268,7 @@ static int da9030_get_ldo14_voltage(struct regulator_dev *rdev) /* DA9034 specific operations */ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -276,6 +281,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -289,7 +295,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, } static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -302,6 +308,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val); + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index b8cc6389a541..b5639e82fcc7 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -58,7 +58,9 @@ out: return data; } -static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) +static int isl6271a_set_voltage(struct regulator_dev *dev, + int minuV, int maxuV, + unsigned *selector) { struct isl_pmic *pmic = rdev_get_drvdata(dev); int vsel, err, data; @@ -78,6 +80,8 @@ static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) /* Convert the microvolts to data for the chip */ data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP; + *selector = data; + mutex_lock(&pmic->mtx); err = i2c_smbus_write_byte(pmic->client, data); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 3bb82b624e19..0f22ef12601c 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -168,7 +168,8 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) } static int lp3971_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3971_LDO1; @@ -187,6 +188,8 @@ static int lp3971_ldo_set_voltage(struct regulator_dev *dev, if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val << LDO_VOL_CONTR_SHIFT(ldo)); @@ -256,7 +259,8 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) } static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3971_DCDC1; @@ -277,6 +281,8 @@ static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), BUCK_TARGET_VOL_MASK, val); if (ret) diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index e07062fd0b42..6aa1b506fb5d 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -292,7 +292,8 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) } static int lp3972_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3972_LDO1; @@ -313,6 +314,8 @@ static int lp3972_ldo_set_voltage(struct regulator_dev *dev, if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), LP3972_LDO_VOL_MASK(ldo) << shift, val << shift); @@ -416,7 +419,8 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) } static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3972_DCDC1; @@ -438,6 +442,8 @@ static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, vol_map[val] > max_vol) return -EINVAL; + *selector = val; + ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), LP3972_BUCK_VOL_MASK, val); if (ret) diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 559cfa271a44..3f49512c5134 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -63,12 +63,12 @@ static int max1586_v3_calc_voltage(struct max1586_data *max1586, return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL); } -static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct max1586_data *max1586 = rdev_get_drvdata(rdev); struct i2c_client *client = max1586->client; unsigned range_uV = max1586->max_uV - max1586->min_uV; - unsigned selector; u8 v3_prog; if (min_uV > max1586->max_uV || max_uV < max1586->min_uV) @@ -76,15 +76,15 @@ static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (min_uV < max1586->min_uV) min_uV = max1586->min_uV; - selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + + *selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + range_uV - 1) / range_uV; - if (max1586_v3_calc_voltage(max1586, selector) > max_uV) + if (max1586_v3_calc_voltage(max1586, *selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", - max1586_v3_calc_voltage(max1586, selector) / 1000); + max1586_v3_calc_voltage(max1586, *selector) / 1000); - v3_prog = I2C_V3_SELECT | (u8) selector; + v3_prog = I2C_V3_SELECT | (u8) *selector; return i2c_smbus_write_byte(client, v3_prog); } @@ -110,10 +110,10 @@ static int max1586_v6_calc_voltage(unsigned selector) return voltages_uv[selector]; } -static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *selector) { struct i2c_client *client = rdev_get_drvdata(rdev); - unsigned selector; u8 v6_prog; if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) @@ -122,21 +122,21 @@ static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) return -EINVAL; if (min_uV < 1800000) - selector = 0; + *selector = 0; else if (min_uV < 2500000) - selector = 1; + *selector = 1; else if (min_uV < 3000000) - selector = 2; + *selector = 2; else if (min_uV >= 3000000) - selector = 3; + *selector = 3; - if (max1586_v6_calc_voltage(selector) > max_uV) + if (max1586_v6_calc_voltage(*selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", - max1586_v6_calc_voltage(selector) / 1000); + max1586_v6_calc_voltage(*selector) / 1000); - v6_prog = I2C_V6_SELECT | (u8) selector; + v6_prog = I2C_V6_SELECT | (u8) *selector; return i2c_smbus_write_byte(client, v6_prog); } diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 6b60a9c0366b..30eb9e54f7ec 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -155,7 +155,7 @@ static int max8649_get_voltage(struct regulator_dev *rdev) } static int max8649_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -168,6 +168,7 @@ static int max8649_set_voltage(struct regulator_dev *rdev, data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1) / MAX8649_DCDC_STEP; mask = MAX8649_VOL_MASK; + *selector = data & mask; return max8649_set_bits(info->i2c, info->vol_reg, mask, data); } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index c570e6eb0db2..33f5d9a492ef 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -141,7 +141,8 @@ static int max8660_dcdc_get(struct regulator_dev *rdev) return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP; } -static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 reg, selector, bits; @@ -154,6 +155,7 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV) selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1)) / MAX8660_DCDC_STEP; + *s = selector; ret = max8660_dcdc_list(rdev, selector); if (ret < 0 || ret > max_uV) @@ -196,7 +198,8 @@ static int max8660_ldo5_get(struct regulator_dev *rdev) return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP; } -static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 selector; @@ -213,6 +216,8 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector); if (ret) return ret; @@ -270,7 +275,8 @@ static int max8660_ldo67_get(struct regulator_dev *rdev) return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP; } -static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 selector; @@ -288,6 +294,8 @@ static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + if (rdev_get_id(rdev) == MAX8660_V6) return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector); else diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 552cad85ae5a..8ae147549c6a 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -55,7 +55,7 @@ static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) } static int max8925_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned int *selector) { struct max8925_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -66,6 +66,7 @@ static int max8925_set_voltage(struct regulator_dev *rdev, return -EINVAL; } data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = data; data <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 0d5dda4fd911..a8f4ecfb0843 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -133,7 +133,7 @@ static int max8952_get_voltage(struct regulator_dev *rdev) } static int max8952_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8952_data *max8952 = rdev_get_drvdata(rdev); s8 vid = -1, i; @@ -156,6 +156,7 @@ static int max8952_set_voltage(struct regulator_dev *rdev, if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) { max8952->vid0 = (vid % 2 == 1); max8952->vid1 = (((vid >> 1) % 2) == 1); + *selector = vid; gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); } else diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 5c20756db607..cb28cf8b9397 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -304,7 +304,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev) } static int max8998_set_voltage_ldo(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8998->iodev->i2c; @@ -331,6 +331,8 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev, if (desc->min + desc->step*i > max_vol) return -EINVAL; + *selector = i; + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; @@ -352,7 +354,7 @@ static inline void buck2_gpio_set(int gpio, int v) } static int max8998_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, int *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct max8998_platform_data *pdata = @@ -384,6 +386,8 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, if (desc->min + desc->step*i > max_vol) return -EINVAL; + *selector = i; + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index ecd99f59dba8..47ea99949798 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -373,7 +373,8 @@ static int mc13783_get_best_voltage_index(struct regulator_dev *rdev, } static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); int value, id = rdev_get_id(rdev); @@ -388,6 +389,8 @@ static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, if (value < 0) return value; + *selector = value; + mc13783_lock(priv->mc13783); ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg, mc13783_regulators[id].vsel_mask, @@ -433,13 +436,16 @@ static struct regulator_ops mc13783_regulator_ops = { }; static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { int id = rdev_get_id(rdev); dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", __func__, id, min_uV, max_uV); + *selector = 0; + if (min_uV >= mc13783_regulators[id].voltages[0] && max_uV <= mc13783_regulators[id].voltages[0]) return 0; diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 29d0566379ae..8dca11694f75 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -151,7 +151,8 @@ static struct pcap_regulator vreg_table[] = { }; static int pcap_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsiged *selector) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); @@ -170,10 +171,12 @@ static int pcap_regulator_set_voltage(struct regulator_dev *rdev, i = 0; uV = vreg->voltage_table[i] * 1000; - if (min_uV <= uV && uV <= max_uV) + if (min_uV <= uV && uV <= max_uV) { + *selector = i; return ezx_pcap_set_bits(pcap, vreg->reg, (vreg->n_voltages - 1) << vreg->index, i << vreg->index); + } if (i == 0 && rdev_get_id(rdev) == V1) i = vreg->n_voltages - 1; diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index c8f41dc05b76..69a11d9dd87f 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -108,7 +108,8 @@ static unsigned int ldo_voltage_value(u8 bits) } static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct pcf50633 *pcf; int regulator_id, millivolts; @@ -147,6 +148,8 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, return -EINVAL; } + *selector = volt_bits; + return pcf50633_reg_write(pcf, regnr, volt_bits); } diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index cd6d4fc9d74f..60a7ca5409e9 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -321,7 +321,8 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) } static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int dcdc = rdev_get_id(dev); @@ -346,6 +347,8 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, break; } + *selector = vsel; + /* write to the register in case we found a match */ if (vsel == tps->info[dcdc]->table_len) return -EINVAL; @@ -371,7 +374,7 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev) } static int tps65023_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); @@ -396,6 +399,8 @@ static int tps65023_ldo_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[ldo]->table_len) return -EINVAL; + *selector = vsel; + data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); if (data < 0) return data; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 020f5878d7ff..064755290599 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -369,7 +369,8 @@ static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev) } static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, vsel, dcdc = rdev_get_id(dev); @@ -415,6 +416,8 @@ static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[dcdc]->table_len) return -EINVAL; + *selector = vsel; + data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; @@ -450,7 +453,8 @@ static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev) } static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); @@ -483,6 +487,8 @@ static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[ldo]->table_len) return -EINVAL; + *selector = vsel; + data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 6d20b0454a1d..bb04a75a4c98 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -85,7 +85,8 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev, static int __tps6586x_ldo_set_voltage(struct device *parent, struct tps6586x_regulator *ri, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { int val, uV; uint8_t mask; @@ -100,6 +101,8 @@ static int __tps6586x_ldo_set_voltage(struct device *parent, /* use the first in-range value */ if (min_uV <= uV && uV <= max_uV) { + *selector = val; + val <<= ri->volt_shift; mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; @@ -111,12 +114,13 @@ static int __tps6586x_ldo_set_voltage(struct device *parent, } static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); - return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV); + return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, + selector); } static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) @@ -140,13 +144,14 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) } static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); int ret; - ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV); + ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, + selector); if (ret) return ret; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index a57262a4fa6c..bd332cf1cc3f 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -329,7 +329,8 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) } static int -twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel; @@ -345,9 +346,11 @@ twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) /* REVISIT for VAUX2, first match may not be best/lowest */ /* use the first in-range value */ - if (min_uV <= uV && uV <= max_uV) + if (min_uV <= uV && uV <= max_uV) { + *selector = vsel; return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); + } } return -EDOM; @@ -389,7 +392,8 @@ static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) } static int -twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel; @@ -402,6 +406,7 @@ twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) * mV = 1000mv + 100mv * (vsel - 1) */ vsel = (min_uV/1000 - 1000)/100 + 1; + *selector = vsel; return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); } diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index dbfaf5945e48..71da6b2ad863 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -302,7 +302,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) } static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -314,6 +314,8 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, if (vsel < 0) return vsel; + *selector = vsel; + /* If this value is already set then do a GPIO update if we can */ if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 0); @@ -636,7 +638,7 @@ static int wm831x_buckp_list_voltage(struct regulator_dev *rdev, } static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, int *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -650,16 +652,20 @@ static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel); } static int wm831x_buckp_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; - return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, @@ -667,8 +673,9 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; + unsigned selector; - return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV); + return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9edf8f692341..9594e7161b4d 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -113,7 +113,8 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, } static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -133,16 +134,20 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel); } static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -150,8 +155,9 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + unsigned int selector; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) @@ -413,7 +419,8 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, } static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -433,16 +440,19 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel); } static int wm831x_aldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; - return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -450,8 +460,9 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + unsigned int selector; - return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) @@ -666,7 +677,8 @@ static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev, static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -680,16 +692,20 @@ static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel); } static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -697,8 +713,9 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL; + unsigned selector; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index fe4b8a8a9dfd..7e45b0ddd710 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -360,7 +360,7 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode, EXPORT_SYMBOL_GPL(wm8350_isink_set_flash); static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) + int max_uV, unsigned *selector) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, dcdc = rdev_get_id(rdev), mV, @@ -397,6 +397,8 @@ static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, return -EINVAL; } + *selector = mV; + /* all DCDCs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; wm8350_reg_write(wm8350, volt_reg, val | mV); @@ -754,7 +756,7 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev) } static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) + int max_uV, unsigned *selector) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000, @@ -797,6 +799,8 @@ static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, return -EINVAL; } + *selector = mV; + /* all LDOs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; wm8350_reg_write(wm8350, volt_reg, val | mV); diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 924c7eb29ee9..b42d01cef35a 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -67,7 +67,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev) } static int wm8400_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; @@ -93,6 +93,8 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev, val += 0xf; } + *selector = val; + return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev), WM8400_LDO1_VSEL_MASK, val); } @@ -156,7 +158,7 @@ static int wm8400_dcdc_get_voltage(struct regulator_dev *dev) } static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; @@ -171,6 +173,8 @@ static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, return -EINVAL; BUG_ON(850000 + (25000 * val) < min_uV); + *selector = val; + return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, WM8400_DC1_VSEL_MASK, val); } diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 03713bc66e4a..1b162e699368 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -101,7 +101,7 @@ static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) } static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *s) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; @@ -111,6 +111,7 @@ static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, if (v < 0 || v > max_uV) return -EINVAL; + *s = selector; selector <<= WM8994_LDO1_VSEL_SHIFT; return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1, @@ -152,7 +153,7 @@ static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) } static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *s) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; @@ -162,6 +163,7 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, if (v < 0 || v > max_uV) return -EINVAL; + *s = selector; selector <<= WM8994_LDO2_VSEL_SHIFT; return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2, diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 592cd7c642c2..4275cd475eac 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -79,7 +79,8 @@ struct regulator_ops { int (*list_voltage) (struct regulator_dev *, unsigned selector); /* get/set regulator voltage */ - int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV); + int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, + unsigned *selector); int (*get_voltage) (struct regulator_dev *); /* get/set regulator current */ -- cgit v1.2.3 From 02fa3ec01a0df7a8ccc356d8e245a9a1423b3596 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Nov 2010 14:38:30 +0000 Subject: regulator: Add basic trace facilities Provide some basic trace facilities to the regulator API. We generate events on regulator enable, disable and voltage setting over the actual hardware operations (which are assumed to be the expensive ones which require interaction with the actual device). This is intended to facilitate debug of the performance and behaviour with consumers allowing unified traces to be generated including the regulator operations within the context of the other components of the system. For enable we log the explicit delay for the voltage ramp separately to the interaction with the hardware to highlight the time consumed in I/O. We should add a similar delay for voltage changes, though there the relatively small magnitude of the changes in the context of the I/O costs makes it much less critical for most regulators. Only hardware interactions are currently traced as the primary focus is on the performance and synchronisation of actual hardware interactions. Additional tracepoints for debugging of the logical operations can be added later if required. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 17 +++++ include/trace/events/regulator.h | 141 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 include/trace/events/regulator.h (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 67d3a61f3785..8a5d0ae191b3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -25,6 +25,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "dummy.h" #define REGULATOR_VERSION "0.5" @@ -1310,6 +1313,8 @@ static int _regulator_enable(struct regulator_dev *rdev) delay = 0; } + trace_regulator_enable(rdev_get_name(rdev)); + /* Allow the regulator to ramp; it would be useful * to extend this for bulk operations so that the * regulators can ramp together. */ @@ -1317,6 +1322,8 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret < 0) return ret; + trace_regulator_enable_delay(rdev_get_name(rdev)); + if (delay >= 1000) { mdelay(delay / 1000); udelay(delay % 1000); @@ -1324,6 +1331,8 @@ static int _regulator_enable(struct regulator_dev *rdev) udelay(delay); } + trace_regulator_enable_complete(rdev_get_name(rdev)); + } else if (ret < 0) { printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", __func__, rdev_get_name(rdev), ret); @@ -1379,6 +1388,8 @@ static int _regulator_disable(struct regulator_dev *rdev, /* we are last user */ if (_regulator_can_change_status(rdev) && rdev->desc->ops->disable) { + trace_regulator_disable(rdev_get_name(rdev)); + ret = rdev->desc->ops->disable(rdev); if (ret < 0) { printk(KERN_ERR "%s: failed to disable %s\n", @@ -1386,6 +1397,8 @@ static int _regulator_disable(struct regulator_dev *rdev, return ret; } + trace_regulator_disable_complete(rdev_get_name(rdev)); + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, NULL); } @@ -1645,6 +1658,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) regulator->min_uV = min_uV; regulator->max_uV = max_uV; + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); if (rdev->desc->ops->list_voltage) @@ -1652,6 +1667,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) else selector = -1; + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + out: _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); mutex_unlock(&rdev->mutex); diff --git a/include/trace/events/regulator.h b/include/trace/events/regulator.h new file mode 100644 index 000000000000..37502a7404b7 --- /dev/null +++ b/include/trace/events/regulator.h @@ -0,0 +1,141 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM regulator + +#if !defined(_TRACE_REGULATOR_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_REGULATOR_H + +#include +#include + +/* + * Events which just log themselves and the regulator name for enable/disable + * type tracking. + */ +DECLARE_EVENT_CLASS(regulator_basic, + + TP_PROTO(const char *name), + + TP_ARGS(name), + + TP_STRUCT__entry( + __string( name, name ) + ), + + TP_fast_assign( + __assign_str(name, name); + ), + + TP_printk("name=%s", __get_str(name)) + +); + +DEFINE_EVENT(regulator_basic, regulator_enable, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_enable_delay, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_enable_complete, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_disable, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_disable_complete, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +/* + * Events that take a range of numerical values, mostly for voltages + * and so on. + */ +DECLARE_EVENT_CLASS(regulator_range, + + TP_PROTO(const char *name, int min, int max), + + TP_ARGS(name, min, max), + + TP_STRUCT__entry( + __string( name, name ) + __field( int, min ) + __field( int, max ) + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->min = min; + __entry->max = max; + ), + + TP_printk("name=%s (%d-%d)", __get_str(name), + (int)__entry->min, (int)__entry->max) +); + +DEFINE_EVENT(regulator_range, regulator_set_voltage, + + TP_PROTO(const char *name, int min, int max), + + TP_ARGS(name, min, max) + +); + + +/* + * Events that take a single value, mostly for readback and refcounts. + */ +DECLARE_EVENT_CLASS(regulator_value, + + TP_PROTO(const char *name, unsigned int val), + + TP_ARGS(name, val), + + TP_STRUCT__entry( + __string( name, name ) + __field( unsigned int, val ) + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->val = val; + ), + + TP_printk("name=%s, val=%u", __get_str(name), + (int)__entry->val) +); + +DEFINE_EVENT(regulator_value, regulator_set_voltage_complete, + + TP_PROTO(const char *name, unsigned int value), + + TP_ARGS(name, value) + +); + +#endif /* _TRACE_POWER_H */ + +/* This part must be outside protection */ +#include -- cgit v1.2.3 From acaf6ffefdf65188071f88664435b86651d70e7c Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Wed, 10 Nov 2010 11:06:22 +0100 Subject: regulator: enable supply regulator only when use count is zero Supply regulators are disabled only when the last reference count is removed on the child regulator (the use count goes from 1 to 0). This patch changes the behaviour of enable so the supply regulator is enabled only when the use count of the child regulator goes from 0 to 1. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8a5d0ae191b3..a48cf582dcd0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1273,15 +1273,17 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; - /* do we need to enable the supply regulator first */ - if (rdev->supply) { - mutex_lock(&rdev->supply->mutex); - ret = _regulator_enable(rdev->supply); - mutex_unlock(&rdev->supply->mutex); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); - return ret; + if (rdev->use_count == 0) { + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev_get_name(rdev), ret); + return ret; + } } } -- cgit v1.2.3 From 7bed08c56540825ab9c7909a12e9b5bcdafa62ba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Nov 2010 11:57:17 +0000 Subject: regulator: Fix typo in PCAP regulator_set_voltage() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/pcap-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 8dca11694f75..31f6e11a7f16 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -152,7 +152,7 @@ static struct pcap_regulator vreg_table[] = { static int pcap_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, - unsiged *selector) + unsigned *selector) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); -- cgit v1.2.3 From c5e28ed78274468b92522e7f1e9a5e6080559100 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 17 Nov 2010 15:30:27 -0800 Subject: drivers: regulator: core: use pr_fmt This adds a pr_fmt line which uses the __func__ macro. I also convert the current pr_ lines to remove their __func__ usage. Cc: bleong@codeaurora.org Signed-off-by: Daniel Walker Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a48cf582dcd0..7c0906367239 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) "%s:" fmt, __func__ + #include #include #include @@ -771,8 +773,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("%s: %s '%s' voltage constraints\n", - __func__, "invalid", name); + pr_err("%s '%s' voltage constraints\n", "invalid", + name); return -EINVAL; } @@ -793,22 +795,22 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("%s: %s '%s' voltage constraints\n", - __func__, "unsupportable", name); + pr_err("%s '%s' voltage constraints\n", "unsupportable", + name); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("%s: override '%s' %s, %d -> %d\n", - __func__, name, "min_uV", - constraints->min_uV, min_uV); + pr_debug("override '%s' %s, %d -> %d\n", + name, "min_uV", + constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("%s: override '%s' %s, %d -> %d\n", - __func__, name, "max_uV", - constraints->max_uV, max_uV); + pr_debug("override '%s' %s, %d -> %d\n", + name, "max_uV", + constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } -- cgit v1.2.3 From 1d7372e15ebd7f56a336fabe6ee31f8e692cd9cb Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 17 Nov 2010 15:30:28 -0800 Subject: drivers: regulator: core: convert to using pr_ macros The regulator framework uses a lot of printks with a specific formatting using __func__. This converts them to use pr_ calls with a central format string. Cc: bleong@codeaurora.org Signed-off-by: Daniel Walker Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 137 ++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7c0906367239..8d492f40cebf 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -13,7 +13,7 @@ * */ -#define pr_fmt(fmt) "%s:" fmt, __func__ +#define pr_fmt(fmt) "%s: " fmt, __func__ #include #include @@ -116,13 +116,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev, BUG_ON(*min_uV > *max_uV); if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } @@ -144,13 +142,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, BUG_ON(*min_uA > *max_uA); if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } @@ -179,18 +175,15 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) } if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } if (!(rdev->constraints->valid_modes_mask & mode)) { - printk(KERN_ERR "%s: invalid mode %x for %s\n", - __func__, mode, rdev_get_name(rdev)); + pr_err("invalid mode %x for %s\n", mode, rdev_get_name(rdev)); return -EINVAL; } return 0; @@ -200,13 +193,11 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) static int regulator_check_drms(struct regulator_dev *rdev) { if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } return 0; @@ -603,20 +594,18 @@ static int suspend_set_state(struct regulator_dev *rdev, */ if (!rstate->enabled && !rstate->disabled) { if (can_set_state) - printk(KERN_WARNING "%s: No configuration for %s\n", - __func__, rdev_get_name(rdev)); + pr_warning("No configuration for %s\n", + rdev_get_name(rdev)); return 0; } if (rstate->enabled && rstate->disabled) { - printk(KERN_ERR "%s: invalid configuration for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("invalid configuration for %s\n", rdev_get_name(rdev)); return -EINVAL; } if (!can_set_state) { - printk(KERN_ERR "%s: no way to set suspend state\n", - __func__); + pr_err("no way to set suspend state\n"); return -EINVAL; } @@ -625,15 +614,14 @@ static int suspend_set_state(struct regulator_dev *rdev, else ret = rdev->desc->ops->set_suspend_disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to enabled/disable\n", __func__); + pr_err("failed to enabled/disable\n"); return ret; } if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); if (ret < 0) { - printk(KERN_ERR "%s: failed to set voltage\n", - __func__); + pr_err("failed to set voltage\n"); return ret; } } @@ -641,7 +629,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to set mode\n", __func__); + pr_err("failed to set mode\n"); return ret; } } @@ -739,9 +727,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->max_uV, &selector); if (ret < 0) { - printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n", - __func__, - rdev->constraints->min_uV, name); + pr_err("failed to apply %duV constraint to %s\n", + rdev->constraints->min_uV, name); rdev->constraints = NULL; return ret; } @@ -848,8 +835,8 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_state) { ret = suspend_prepare(rdev, constraints->initial_state); if (ret < 0) { - printk(KERN_ERR "%s: failed to set suspend state for %s\n", - __func__, name); + pr_err("failed to set suspend state for %s\n", + name); rdev->constraints = NULL; goto out; } @@ -857,17 +844,16 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_mode) { if (!ops->set_mode) { - printk(KERN_ERR "%s: no set_mode operation for %s\n", - __func__, name); + pr_err("no set_mode operation for %s\n", + name); ret = -EINVAL; goto out; } ret = ops->set_mode(rdev, constraints->initial_mode); if (ret < 0) { - printk(KERN_ERR - "%s: failed to set initial mode for %s: %d\n", - __func__, name, ret); + pr_err("failed to set initial mode for %s: %d\n", + name, ret); goto out; } } @@ -878,8 +864,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, if ((constraints->always_on || constraints->boot_on) && ops->enable) { ret = ops->enable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s\n", - __func__, name); + pr_err("failed to enable %s\n", name); rdev->constraints = NULL; goto out; } @@ -907,9 +892,8 @@ static int set_supply(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, "supply"); if (err) { - printk(KERN_ERR - "%s: could not add device link %s err %d\n", - __func__, supply_rdev->dev.kobj.name, err); + pr_err("could not add device link %s err %d\n", + supply_rdev->dev.kobj.name, err); goto out; } rdev->supply = supply_rdev; @@ -1039,8 +1023,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, regulator->dev_attr.show = device_requested_uA_show; err = device_create_file(dev, ®ulator->dev_attr); if (err < 0) { - printk(KERN_WARNING "%s: could not add regulator_dev" - " load sysfs\n", __func__); + pr_warning("could not add regulator_dev" + " requested microamps sysfs entry\n"); goto attr_name_err; } @@ -1057,9 +1041,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { - printk(KERN_WARNING - "%s: could not add device link %s err %d\n", - __func__, dev->kobj.name, err); + pr_warning("could not add device link %s err %d\n", + dev->kobj.name, err); goto link_name_err; } } @@ -1096,7 +1079,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, int ret; if (id == NULL) { - printk(KERN_ERR "regulator: get() with no identifier\n"); + pr_err("regulator: get() with no identifier\n"); return regulator; } @@ -1282,8 +1265,8 @@ static int _regulator_enable(struct regulator_dev *rdev) ret = _regulator_enable(rdev->supply); mutex_unlock(&rdev->supply->mutex); if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); + pr_err("failed to enable %s: %d\n", + rdev_get_name(rdev), ret); return ret; } } @@ -1310,10 +1293,9 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret >= 0) { delay = ret; } else { - printk(KERN_WARNING - "%s: enable_time() failed for %s: %d\n", - __func__, rdev_get_name(rdev), - ret); + pr_warning("enable_time() failed for %s: %d\n", + rdev_get_name(rdev), + ret); delay = 0; } @@ -1338,8 +1320,8 @@ static int _regulator_enable(struct regulator_dev *rdev) trace_regulator_enable_complete(rdev_get_name(rdev)); } else if (ret < 0) { - printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", - __func__, rdev_get_name(rdev), ret); + pr_err("is_enabled() failed for %s: %d\n", + rdev_get_name(rdev), ret); return ret; } /* Fallthrough on positive return values - already enabled */ @@ -1396,8 +1378,8 @@ static int _regulator_disable(struct regulator_dev *rdev, ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to disable %s\n", - __func__, rdev_get_name(rdev)); + pr_err("failed to disable %s\n", + rdev_get_name(rdev)); return ret; } @@ -1469,8 +1451,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev, /* ah well, who wants to live forever... */ ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to force disable %s\n", - __func__, rdev_get_name(rdev)); + pr_err("failed to force disable %s\n", + rdev_get_name(rdev)); return ret; } /* notify other consumers that power has been forced off */ @@ -1911,8 +1893,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) /* get output voltage */ output_uV = rdev->desc->ops->get_voltage(rdev); if (output_uV <= 0) { - printk(KERN_ERR "%s: invalid output voltage found for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("invalid output voltage found for %s\n", + rdev_get_name(rdev)); goto out; } @@ -1922,8 +1904,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) else input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { - printk(KERN_ERR "%s: invalid input voltage found for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("invalid input voltage found for %s\n", + rdev_get_name(rdev)); goto out; } @@ -1936,16 +1918,16 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) total_uA_load); ret = regulator_check_mode(rdev, mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to get optimum mode for %s @" - " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev), + pr_err("failed to get optimum mode for %s @" + " %d uA %d -> %d uV\n", rdev_get_name(rdev), total_uA_load, input_uV, output_uV); goto out; } ret = rdev->desc->ops->set_mode(rdev, mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n", - __func__, mode, rdev_get_name(rdev)); + pr_err("failed to set optimum mode %x for %s\n", + mode, rdev_get_name(rdev)); goto out; } ret = mode; @@ -2494,8 +2476,7 @@ int regulator_suspend_prepare(suspend_state_t state) mutex_unlock(&rdev->mutex); if (ret < 0) { - printk(KERN_ERR "%s: failed to prepare %s\n", - __func__, rdev_get_name(rdev)); + pr_err("failed to prepare %s\n", rdev_get_name(rdev)); goto out; } } @@ -2653,13 +2634,10 @@ static int __init regulator_init_complete(void) if (has_full_constraints) { /* We log since this may kill the system if it * goes wrong. */ - printk(KERN_INFO "%s: disabling %s\n", - __func__, name); + pr_info("disabling %s\n", name); ret = ops->disable(rdev); if (ret != 0) { - printk(KERN_ERR - "%s: couldn't disable %s: %d\n", - __func__, name, ret); + pr_err("couldn't disable %s: %d\n", name, ret); } } else { /* The intention is that in future we will @@ -2667,9 +2645,8 @@ static int __init regulator_init_complete(void) * so warn even if we aren't going to do * anything here. */ - printk(KERN_WARNING - "%s: incomplete constraints, leaving %s on\n", - __func__, name); + pr_warning("incomplete constraints, leaving %s on\n", + name); } unlock: -- cgit v1.2.3 From 4c35508fc0b7883820923b3b8eb9fea25d35cf72 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 Nov 2010 13:51:18 +0000 Subject: regulator: Fix obfuscated log messages Don't use %s to format fixed static strings into log messages, it just makes searching for and reading the message in the kernel source needlessly hard. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8d492f40cebf..fe47860c6633 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -760,7 +760,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("%s '%s' voltage constraints\n", "invalid", + pr_err("invalid '%s' voltage constraints\n", name); return -EINVAL; } @@ -782,22 +782,20 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("%s '%s' voltage constraints\n", "unsupportable", + pr_err("unsupportable '%s' voltage constraints\n", name); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("override '%s' %s, %d -> %d\n", - name, "min_uV", - constraints->min_uV, min_uV); + pr_debug("override '%s' min_uV, %d -> %d\n", + name, constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("override '%s' %s, %d -> %d\n", - name, "max_uV", - constraints->max_uV, max_uV); + pr_debug("override '%s' max_uV, %d -> %d\n", + name, constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } -- cgit v1.2.3 From 50ba5ca4be30674517ca33425648ec43d93f9a69 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 Nov 2010 13:51:19 +0000 Subject: regulator: Remove regulator core version announcement The version hasn't been updated since the regulator API was merged in 2.6.27 so just remove it - now we're in mainline the kernel version is much more useful. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe47860c6633..64a56a7a1f9d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -32,8 +32,6 @@ #include "dummy.h" -#define REGULATOR_VERSION "0.5" - static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); @@ -2580,8 +2578,6 @@ static int __init regulator_init(void) { int ret; - printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); - ret = class_register(®ulator_class); regulator_dummy_init(); -- cgit v1.2.3 From f4d6adf11b0a596ac4fee2fb2591f286de35c088 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 19 Nov 2010 12:07:44 +0000 Subject: regulator: Fix prototype for MAX8998 buck set_voltage() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max8998.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index cb28cf8b9397..7568df6122ab 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -354,7 +354,7 @@ static inline void buck2_gpio_set(int gpio, int v) } static int max8998_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV, int *selector) + int min_uV, int max_uV, unsigned *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct max8998_platform_data *pdata = -- cgit v1.2.3 From f8c12fe329c8da9f50d8b2b1183eeaa4d587e747 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Nov 2010 15:55:17 +0000 Subject: regulator: Copy constraints from regulators when initialising them Currently the regulator API uses the constraints structure passed in to the core throughout the lifetime of the object. This means that it is not possible to mark the constraints as __initdata so if the kernel supports many boards the constraints for all of them are kept around throughout the lifetime of the system, consuming memory needlessly. By copying constraints that are actually used we allow the use of __initdata, saving memory when multiple boards are supported. This also means the constraints can be const. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 19 ++++++++++++------- include/linux/regulator/driver.h | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 64a56a7a1f9d..40cf7b9ea943 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -813,23 +813,26 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, * set_mode. */ static int set_machine_constraints(struct regulator_dev *rdev, - struct regulation_constraints *constraints) + const struct regulation_constraints *constraints) { int ret = 0; const char *name; struct regulator_ops *ops = rdev->desc->ops; - rdev->constraints = constraints; + rdev->constraints = kmemdup(constraints, sizeof(*constraints), + GFP_KERNEL); + if (!rdev->constraints) + return -ENOMEM; name = rdev_get_name(rdev); - ret = machine_constraints_voltage(rdev, constraints); + ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) goto out; /* do we need to setup our suspend state */ if (constraints->initial_state) { - ret = suspend_prepare(rdev, constraints->initial_state); + ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { pr_err("failed to set suspend state for %s\n", name); @@ -846,7 +849,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, goto out; } - ret = ops->set_mode(rdev, constraints->initial_mode); + ret = ops->set_mode(rdev, rdev->constraints->initial_mode); if (ret < 0) { pr_err("failed to set initial mode for %s: %d\n", name, ret); @@ -857,7 +860,8 @@ static int set_machine_constraints(struct regulator_dev *rdev, /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ - if ((constraints->always_on || constraints->boot_on) && ops->enable) { + if ((rdev->constraints->always_on || rdev->constraints->boot_on) && + ops->enable) { ret = ops->enable(rdev); if (ret < 0) { pr_err("failed to enable %s\n", name); @@ -2289,7 +2293,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) * Returns 0 on success. */ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, + struct device *dev, const struct regulator_init_data *init_data, void *driver_data) { static atomic_t regulator_no = ATOMIC_INIT(0); @@ -2444,6 +2448,7 @@ void regulator_unregister(struct regulator_dev *rdev) if (rdev->supply) sysfs_remove_link(&rdev->dev.kobj, "supply"); device_unregister(&rdev->dev); + kfree(rdev->constraints); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4275cd475eac..cce575359712 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -192,7 +192,7 @@ struct regulator_dev { }; struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, + struct device *dev, const struct regulator_init_data *init_data, void *driver_data); void regulator_unregister(struct regulator_dev *rdev); -- cgit v1.2.3 From 6220b87bfd60d77bf9b19e18aa093110b0f34d41 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Nov 2010 15:57:48 +0000 Subject: regulator: Remove duplicate consts from mc13873 driver voltage tables They're not needed and sparse is verbosely upset about them. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/mc13783-regulator.c | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 47ea99949798..e99917a63ed4 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -100,78 +100,78 @@ struct mc13783_regulator { }; /* Voltage Values */ -static const int const mc13783_sw3_val[] = { +static const int mc13783_sw3_val[] = { 5000000, 5000000, 5000000, 5500000, }; -static const int const mc13783_vaudio_val[] = { +static const int mc13783_vaudio_val[] = { 2775000, }; -static const int const mc13783_viohi_val[] = { +static const int mc13783_viohi_val[] = { 2775000, }; -static const int const mc13783_violo_val[] = { +static const int mc13783_violo_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int const mc13783_vdig_val[] = { +static const int mc13783_vdig_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int const mc13783_vgen_val[] = { +static const int mc13783_vgen_val[] = { 1200000, 1300000, 1500000, 1800000, 1100000, 2000000, 2775000, 2400000, }; -static const int const mc13783_vrfdig_val[] = { +static const int mc13783_vrfdig_val[] = { 1200000, 1500000, 1800000, 1875000, }; -static const int const mc13783_vrfref_val[] = { +static const int mc13783_vrfref_val[] = { 2475000, 2600000, 2700000, 2775000, }; -static const int const mc13783_vrfcp_val[] = { +static const int mc13783_vrfcp_val[] = { 2700000, 2775000, }; -static const int const mc13783_vsim_val[] = { +static const int mc13783_vsim_val[] = { 1800000, 2900000, 3000000, }; -static const int const mc13783_vesim_val[] = { +static const int mc13783_vesim_val[] = { 1800000, 2900000, }; -static const int const mc13783_vcam_val[] = { +static const int mc13783_vcam_val[] = { 1500000, 1800000, 2500000, 2550000, 2600000, 2750000, 2800000, 3000000, }; -static const int const mc13783_vrfbg_val[] = { +static const int mc13783_vrfbg_val[] = { 1250000, }; -static const int const mc13783_vvib_val[] = { +static const int mc13783_vvib_val[] = { 1300000, 1800000, 2000000, 3000000, }; -static const int const mc13783_vmmc_val[] = { +static const int mc13783_vmmc_val[] = { 1600000, 1800000, 2000000, 2600000, 2700000, 2800000, 2900000, 3000000, }; -static const int const mc13783_vrf_val[] = { +static const int mc13783_vrf_val[] = { 1500000, 1875000, 2700000, 2775000, }; -static const int const mc13783_gpo_val[] = { +static const int mc13783_gpo_val[] = { 3100000, }; -static const int const mc13783_pwgtdrv_val[] = { +static const int mc13783_pwgtdrv_val[] = { 5500000, }; -- cgit v1.2.3 From 5da84fd99bb1ab1c7cd39d0cf7c08bb63931a59a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 30 Nov 2010 05:53:48 -0800 Subject: regulator: Add and use rdev_ macros On Tue, 2010-11-30 at 10:52 +0000, Mark Brown wrote: > On Mon, Nov 29, 2010 at 05:12:56PM -0800, Joe Perches wrote: > > Just to please broonie... > > Signed-off-by: Joe Perches > As usual when fixing review issues please revise your original patch > rather than posting a fresh patch. Here's an earlier comment: On Thu, 2010-11-18 at 13:30 +0000, Mark Brown wrote: > This looks reasonable, please rebase on top of Daniel's patches and > submit it properly (with changelog and so on). Sometimes it's simpler for an upstream maintainer to do something like: git am -s patch -p1 < patch2.mbox git commit --amend file instead of back and forthing. Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 146 +++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 40cf7b9ea943..e63366f826f9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -32,6 +32,15 @@ #include "dummy.h" +#define rdev_err(rdev, fmt, ...) \ + pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_warn(rdev, fmt, ...) \ + pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_info(rdev, fmt, ...) \ + pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_dbg(rdev, fmt, ...) \ + pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) + static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); @@ -114,11 +123,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev, BUG_ON(*min_uV > *max_uV); if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } @@ -140,11 +149,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, BUG_ON(*min_uA > *max_uA); if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } @@ -173,15 +182,15 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) } if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } if (!(rdev->constraints->valid_modes_mask & mode)) { - pr_err("invalid mode %x for %s\n", mode, rdev_get_name(rdev)); + rdev_err(rdev, "invalid mode %x\n", mode); return -EINVAL; } return 0; @@ -191,11 +200,11 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) static int regulator_check_drms(struct regulator_dev *rdev) { if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } return 0; @@ -592,18 +601,17 @@ static int suspend_set_state(struct regulator_dev *rdev, */ if (!rstate->enabled && !rstate->disabled) { if (can_set_state) - pr_warning("No configuration for %s\n", - rdev_get_name(rdev)); + rdev_warn(rdev, "No configuration\n"); return 0; } if (rstate->enabled && rstate->disabled) { - pr_err("invalid configuration for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "invalid configuration\n"); return -EINVAL; } if (!can_set_state) { - pr_err("no way to set suspend state\n"); + rdev_err(rdev, "no way to set suspend state\n"); return -EINVAL; } @@ -612,14 +620,14 @@ static int suspend_set_state(struct regulator_dev *rdev, else ret = rdev->desc->ops->set_suspend_disable(rdev); if (ret < 0) { - pr_err("failed to enabled/disable\n"); + rdev_err(rdev, "failed to enabled/disable\n"); return ret; } if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); if (ret < 0) { - pr_err("failed to set voltage\n"); + rdev_err(rdev, "failed to set voltage\n"); return ret; } } @@ -627,7 +635,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); if (ret < 0) { - pr_err("failed to set mode\n"); + rdev_err(rdev, "failed to set mode\n"); return ret; } } @@ -705,14 +713,13 @@ static void print_constraints(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += sprintf(buf + count, "standby"); - printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf); + rdev_info(rdev, "regulator: %s\n", buf); } static int machine_constraints_voltage(struct regulator_dev *rdev, struct regulation_constraints *constraints) { struct regulator_ops *ops = rdev->desc->ops; - const char *name = rdev_get_name(rdev); int ret; unsigned selector; @@ -725,8 +732,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->max_uV, &selector); if (ret < 0) { - pr_err("failed to apply %duV constraint to %s\n", - rdev->constraints->min_uV, name); + rdev_err(rdev, "failed to apply %duV constraint\n", + rdev->constraints->min_uV); rdev->constraints = NULL; return ret; } @@ -758,8 +765,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("invalid '%s' voltage constraints\n", - name); + rdev_err(rdev, "invalid voltage constraints\n"); return -EINVAL; } @@ -780,20 +786,19 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("unsupportable '%s' voltage constraints\n", - name); + rdev_err(rdev, "unsupportable voltage constraints\n"); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("override '%s' min_uV, %d -> %d\n", - name, constraints->min_uV, min_uV); + rdev_dbg(rdev, "override min_uV, %d -> %d\n", + constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("override '%s' max_uV, %d -> %d\n", - name, constraints->max_uV, max_uV); + rdev_dbg(rdev, "override max_uV, %d -> %d\n", + constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } @@ -816,7 +821,6 @@ static int set_machine_constraints(struct regulator_dev *rdev, const struct regulation_constraints *constraints) { int ret = 0; - const char *name; struct regulator_ops *ops = rdev->desc->ops; rdev->constraints = kmemdup(constraints, sizeof(*constraints), @@ -824,8 +828,6 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (!rdev->constraints) return -ENOMEM; - name = rdev_get_name(rdev); - ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) goto out; @@ -834,8 +836,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_state) { ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { - pr_err("failed to set suspend state for %s\n", - name); + rdev_err(rdev, "failed to set suspend state\n"); rdev->constraints = NULL; goto out; } @@ -843,16 +844,14 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_mode) { if (!ops->set_mode) { - pr_err("no set_mode operation for %s\n", - name); + rdev_err(rdev, "no set_mode operation\n"); ret = -EINVAL; goto out; } ret = ops->set_mode(rdev, rdev->constraints->initial_mode); if (ret < 0) { - pr_err("failed to set initial mode for %s: %d\n", - name, ret); + rdev_err(rdev, "failed to set initial mode: %d\n", ret); goto out; } } @@ -864,7 +863,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, ops->enable) { ret = ops->enable(rdev); if (ret < 0) { - pr_err("failed to enable %s\n", name); + rdev_err(rdev, "failed to enable\n"); rdev->constraints = NULL; goto out; } @@ -892,8 +891,8 @@ static int set_supply(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, "supply"); if (err) { - pr_err("could not add device link %s err %d\n", - supply_rdev->dev.kobj.name, err); + rdev_err(rdev, "could not add device link %s err %d\n", + supply_rdev->dev.kobj.name, err); goto out; } rdev->supply = supply_rdev; @@ -949,10 +948,10 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, continue; dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n", - dev_name(&node->regulator->dev), - node->regulator->desc->name, - supply, - dev_name(&rdev->dev), rdev_get_name(rdev)); + dev_name(&node->regulator->dev), + node->regulator->desc->name, + supply, + dev_name(&rdev->dev), rdev_get_name(rdev)); return -EBUSY; } @@ -1023,8 +1022,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, regulator->dev_attr.show = device_requested_uA_show; err = device_create_file(dev, ®ulator->dev_attr); if (err < 0) { - pr_warning("could not add regulator_dev" - " requested microamps sysfs entry\n"); + rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n"); goto attr_name_err; } @@ -1041,8 +1039,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { - pr_warning("could not add device link %s err %d\n", - dev->kobj.name, err); + rdev_warn(rdev, "could not add device link %s err %d\n", + dev->kobj.name, err); goto link_name_err; } } @@ -1079,7 +1077,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, int ret; if (id == NULL) { - pr_err("regulator: get() with no identifier\n"); + pr_err("get() with no identifier\n"); return regulator; } @@ -1113,8 +1111,8 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * substitute in a dummy regulator so consumers can continue. */ if (!has_full_constraints) { - pr_warning("%s supply %s not found, using dummy regulator\n", - devname, id); + pr_warn("%s supply %s not found, using dummy regulator\n", + devname, id); rdev = dummy_regulator_rdev; goto found; } @@ -1265,8 +1263,7 @@ static int _regulator_enable(struct regulator_dev *rdev) ret = _regulator_enable(rdev->supply); mutex_unlock(&rdev->supply->mutex); if (ret < 0) { - pr_err("failed to enable %s: %d\n", - rdev_get_name(rdev), ret); + rdev_err(rdev, "failed to enable: %d\n", ret); return ret; } } @@ -1293,8 +1290,7 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret >= 0) { delay = ret; } else { - pr_warning("enable_time() failed for %s: %d\n", - rdev_get_name(rdev), + rdev_warn(rdev, "enable_time() failed: %d\n", ret); delay = 0; } @@ -1320,8 +1316,7 @@ static int _regulator_enable(struct regulator_dev *rdev) trace_regulator_enable_complete(rdev_get_name(rdev)); } else if (ret < 0) { - pr_err("is_enabled() failed for %s: %d\n", - rdev_get_name(rdev), ret); + rdev_err(rdev, "is_enabled() failed: %d\n", ret); return ret; } /* Fallthrough on positive return values - already enabled */ @@ -1378,8 +1373,7 @@ static int _regulator_disable(struct regulator_dev *rdev, ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - pr_err("failed to disable %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "failed to disable\n"); return ret; } @@ -1451,8 +1445,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev, /* ah well, who wants to live forever... */ ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - pr_err("failed to force disable %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "failed to force disable\n"); return ret; } /* notify other consumers that power has been forced off */ @@ -1893,8 +1886,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) /* get output voltage */ output_uV = rdev->desc->ops->get_voltage(rdev); if (output_uV <= 0) { - pr_err("invalid output voltage found for %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "invalid output voltage found\n"); goto out; } @@ -1904,8 +1896,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) else input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { - pr_err("invalid input voltage found for %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "invalid input voltage found\n"); goto out; } @@ -1918,16 +1909,14 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) total_uA_load); ret = regulator_check_mode(rdev, mode); if (ret < 0) { - pr_err("failed to get optimum mode for %s @" - " %d uA %d -> %d uV\n", rdev_get_name(rdev), - total_uA_load, input_uV, output_uV); + rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", + total_uA_load, input_uV, output_uV); goto out; } ret = rdev->desc->ops->set_mode(rdev, mode); if (ret < 0) { - pr_err("failed to set optimum mode %x for %s\n", - mode, rdev_get_name(rdev)); + rdev_err(rdev, "failed to set optimum mode %x\n", mode); goto out; } ret = mode; @@ -2058,7 +2047,7 @@ int regulator_bulk_enable(int num_consumers, return 0; err: - printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret); + pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); for (--i; i >= 0; --i) regulator_disable(consumers[i].consumer); @@ -2093,8 +2082,7 @@ int regulator_bulk_disable(int num_consumers, return 0; err: - printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply, - ret); + pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret); for (--i; i >= 0; --i) regulator_enable(consumers[i].consumer); @@ -2477,7 +2465,7 @@ int regulator_suspend_prepare(suspend_state_t state) mutex_unlock(&rdev->mutex); if (ret < 0) { - pr_err("failed to prepare %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "failed to prepare\n"); goto out; } } @@ -2599,7 +2587,6 @@ static int __init regulator_init_complete(void) struct regulator_ops *ops; struct regulation_constraints *c; int enabled, ret; - const char *name; mutex_lock(®ulator_list_mutex); @@ -2611,8 +2598,6 @@ static int __init regulator_init_complete(void) ops = rdev->desc->ops; c = rdev->constraints; - name = rdev_get_name(rdev); - if (!ops->disable || (c && c->always_on)) continue; @@ -2633,10 +2618,10 @@ static int __init regulator_init_complete(void) if (has_full_constraints) { /* We log since this may kill the system if it * goes wrong. */ - pr_info("disabling %s\n", name); + rdev_info(rdev, "disabling\n"); ret = ops->disable(rdev); if (ret != 0) { - pr_err("couldn't disable %s: %d\n", name, ret); + rdev_err(rdev, "couldn't disable: %d\n", ret); } } else { /* The intention is that in future we will @@ -2644,8 +2629,7 @@ static int __init regulator_init_complete(void) * so warn even if we aren't going to do * anything here. */ - pr_warning("incomplete constraints, leaving %s on\n", - name); + rdev_warn(rdev, "incomplete constraints, leaving on\n"); } unlock: -- cgit v1.2.3 From 05fda3b1abc23d832144e9497fb218870927d645 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Dec 2010 11:31:07 +0100 Subject: regulator: Take into account the requirements of all consumers Extend the regulator_set_voltage() function to take into account the voltage requirements of all consumers of the regulator being changed, in order to set the voltage to the minimum voltage acceptable to all consumers. The existing behaviour was that the latest regulator_set_voltage() call would win over previous regulator_set_voltage() calls even if setting the voltage to a non-acceptable level from other consumers. Signed-off-by: Thomas Petazzoni Cc: Liam Girdwood Cc: Mark Brown Cc: Kevin Hilman Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e63366f826f9..a1b12379b09f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -142,6 +142,27 @@ static int regulator_check_voltage(struct regulator_dev *rdev, return 0; } +/* Make sure we select a voltage that suits the needs of all + * regulator consumers + */ +static int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + struct regulator *regulator; + + list_for_each_entry(regulator, &rdev->consumer_list, list) { + if (*max_uV > regulator->max_uV) + *max_uV = regulator->max_uV; + if (*min_uV < regulator->min_uV) + *min_uV = regulator->min_uV; + } + + if (*min_uV > *max_uV) + return -EINVAL; + + return 0; +} + /* current constraint check */ static int regulator_check_current_limit(struct regulator_dev *rdev, int *min_uA, int *max_uA) @@ -1637,6 +1658,10 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) regulator->min_uV = min_uV; regulator->max_uV = max_uV; + ret = regulator_check_consumers(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); -- cgit v1.2.3 From 43e7ee33f2a8d20238267b789791386739247478 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 6 Dec 2010 14:05:19 -0800 Subject: drivers/regulator: Update WARN uses Align arguments. Signed-off-by: Joe Perches Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a1b12379b09f..5d07e5dd417f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1379,8 +1379,7 @@ static int _regulator_disable(struct regulator_dev *rdev, *supply_rdev_ptr = NULL; if (WARN(rdev->use_count <= 0, - "unbalanced disables for %s\n", - rdev_get_name(rdev))) + "unbalanced disables for %s\n", rdev_get_name(rdev))) return -EIO; /* are we the last user and permitted to disable ? */ -- cgit v1.2.3 From 1bf5a1f86a328122714680cd59951074b4f31e07 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Dec 2010 17:28:06 +0000 Subject: regulator: Use _regulator_get_voltage() consistently Rather than referencing the get_voltage() operation directly in the ops struct use the internal _regulator_get_voltage() API call to do so, facilitating refactoring. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5d07e5dd417f..671eb53b5cdc 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -581,14 +581,15 @@ static void drms_uA_update(struct regulator_dev *rdev) return; /* get output voltage */ - output_uV = rdev->desc->ops->get_voltage(rdev); + output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) return; /* get input voltage */ - if (rdev->supply && rdev->supply->desc->ops->get_voltage) - input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); - else + input_uV = 0; + if (rdev->supply) + input_uV = _regulator_get_voltage(rdev); + if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) return; @@ -1908,16 +1909,17 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) goto out; /* get output voltage */ - output_uV = rdev->desc->ops->get_voltage(rdev); + output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) { rdev_err(rdev, "invalid output voltage found\n"); goto out; } /* get input voltage */ - if (rdev->supply && rdev->supply->desc->ops->get_voltage) - input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); - else + input_uV = 0; + if (rdev->supply) + input_uV = _regulator_get_voltage(rdev->supply); + if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { rdev_err(rdev, "invalid input voltage found\n"); -- cgit v1.2.3 From 476c2d83c7ffb2429b2a504fbdb4326fc8a9d0e8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Dec 2010 17:28:07 +0000 Subject: regulator: Allow drivers to report voltages as selectors Since drivers already have to provide an API for translating selectors into voltages they may as well just report the selector values directly to the core API rather than implement the lookup themselves. The old interface is left in place for now, but may be removed in future. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 25 ++++++++++++++++++++++--- include/linux/regulator/driver.h | 3 +++ 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 671eb53b5cdc..b362dbde80f7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -577,7 +577,9 @@ static void drms_uA_update(struct regulator_dev *rdev) err = regulator_check_drms(rdev); if (err < 0 || !rdev->desc->ops->get_optimum_mode || - !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode) + (!rdev->desc->ops->get_voltage && + !rdev->desc->ops->get_voltage_sel) || + !rdev->desc->ops->set_mode) return; /* get output voltage */ @@ -1682,7 +1684,14 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage); static int _regulator_get_voltage(struct regulator_dev *rdev) { - /* sanity check */ + int sel; + + if (rdev->desc->ops->get_voltage_sel) { + sel = rdev->desc->ops->get_voltage_sel(rdev); + if (sel < 0) + return sel; + return rdev->desc->ops->list_voltage(rdev, sel); + } if (rdev->desc->ops->get_voltage) return rdev->desc->ops->get_voltage(rdev); else @@ -2191,7 +2200,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) int status = 0; /* some attributes need specific methods to be displayed */ - if (ops->get_voltage) { + if (ops->get_voltage || ops->get_voltage_sel) { status = device_create_file(dev, &dev_attr_microvolts); if (status < 0) return status; @@ -2327,6 +2336,16 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (!init_data) return ERR_PTR(-EINVAL); + /* Only one of each should be implemented */ + WARN_ON(regulator_desc->ops->get_voltage && + regulator_desc->ops->get_voltage_sel); + + /* If we're using selectors we must implement list_voltage. */ + if (regulator_desc->ops->get_voltage_sel && + !regulator_desc->ops->list_voltage) { + return ERR_PTR(-EINVAL); + } + rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) return ERR_PTR(-ENOMEM); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index cce575359712..bf3e653591b9 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -43,6 +43,8 @@ enum regulator_status { * @set_voltage: Set the voltage for the regulator within the range specified. * The driver should select the voltage closest to min_uV. * @get_voltage: Return the currently configured voltage for the regulator. + * @get_voltage_sel: Return the currently configured voltage selector for the + * regulator. * @list_voltage: Return one of the supported voltages, in microvolts; zero * if the selector indicates a voltage that is unusable on this system; * or negative errno. Selectors range from zero to one less than @@ -82,6 +84,7 @@ struct regulator_ops { int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector); int (*get_voltage) (struct regulator_dev *); + int (*get_voltage_sel) (struct regulator_dev *); /* get/set regulator current */ int (*set_current_limit) (struct regulator_dev *, -- cgit v1.2.3 From afb8bb805bb9336ec1f7b74e7b5c0e9baceb42c1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Dec 2010 17:28:08 +0000 Subject: regulator: Convert WM831x drivers to use get_voltage_sel() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm831x-dcdc.c | 14 +++++++------- drivers/regulator/wm831x-ldo.c | 18 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 71da6b2ad863..8b0d2c4bde91 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -377,14 +377,14 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel); } -static int wm831x_buckv_get_voltage(struct regulator_dev *rdev) +static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); if (dcdc->dvs_gpio && dcdc->dvs_gpio_state) - return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel); + return dcdc->dvs_vsel; else - return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel); + return dcdc->on_vsel; } /* Current limit options */ @@ -426,7 +426,7 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) static struct regulator_ops wm831x_buckv_ops = { .set_voltage = wm831x_buckv_set_voltage, - .get_voltage = wm831x_buckv_get_voltage, + .get_voltage_sel = wm831x_buckv_get_voltage_sel, .list_voltage = wm831x_buckv_list_voltage, .set_suspend_voltage = wm831x_buckv_set_suspend_voltage, .set_current_limit = wm831x_buckv_set_current_limit, @@ -678,7 +678,7 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) +static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -689,12 +689,12 @@ static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - return wm831x_buckp_list_voltage(rdev, val & WM831X_DC3_ON_VSEL_MASK); + return val & WM831X_DC3_ON_VSEL_MASK; } static struct regulator_ops wm831x_buckp_ops = { .set_voltage = wm831x_buckp_set_voltage, - .get_voltage = wm831x_buckp_get_voltage, + .get_voltage_sel = wm831x_buckp_get_voltage_sel, .list_voltage = wm831x_buckp_list_voltage, .set_suspend_voltage = wm831x_buckp_set_suspend_voltage, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9594e7161b4d..c94fc5b7cd5b 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -160,7 +160,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -173,7 +173,7 @@ static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO1_ON_VSEL_MASK; - return wm831x_gp_ldo_list_voltage(rdev, ret); + return ret; } static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev) @@ -293,7 +293,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { .list_voltage = wm831x_gp_ldo_list_voltage, - .get_voltage = wm831x_gp_ldo_get_voltage, + .get_voltage_sel = wm831x_gp_ldo_get_voltage_sel, .set_voltage = wm831x_gp_ldo_set_voltage, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, .get_mode = wm831x_gp_ldo_get_mode, @@ -465,7 +465,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -478,7 +478,7 @@ static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO7_ON_VSEL_MASK; - return wm831x_aldo_list_voltage(rdev, ret); + return ret; } static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev) @@ -559,7 +559,7 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_aldo_ops = { .list_voltage = wm831x_aldo_list_voltage, - .get_voltage = wm831x_aldo_get_voltage, + .get_voltage_sel = wm831x_aldo_get_voltage_sel, .set_voltage = wm831x_aldo_set_voltage, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, .get_mode = wm831x_aldo_get_mode, @@ -718,7 +718,7 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -731,7 +731,7 @@ static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO11_ON_VSEL_MASK; - return wm831x_alive_ldo_list_voltage(rdev, ret); + return ret; } static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) @@ -753,7 +753,7 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_alive_ldo_ops = { .list_voltage = wm831x_alive_ldo_list_voltage, - .get_voltage = wm831x_alive_ldo_get_voltage, + .get_voltage_sel = wm831x_alive_ldo_get_voltage_sel, .set_voltage = wm831x_alive_ldo_set_voltage, .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage, .get_status = wm831x_alive_ldo_get_status, -- cgit v1.2.3 From 1394fd2826afb2adf7f6c4833d36a0feba22e665 Mon Sep 17 00:00:00 2001 From: Cyril Chemparathy Date: Tue, 7 Dec 2010 12:04:11 -0500 Subject: regulator: add driver for tps6524x regulator TPS6524X provides three step-down converters and two general-purpose LDO voltage regulators. This device is interfaced using SPI. Signed-off-by: Cyril Chemparathy Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + drivers/regulator/tps6524x-regulator.c | 693 +++++++++++++++++++++++++++++++++ 3 files changed, 704 insertions(+) create mode 100644 drivers/regulator/tps6524x-regulator.c (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dd30e883d4a7..da34981b1675 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -250,5 +250,15 @@ config REGULATOR_TPS6586X help This driver supports TPS6586X voltage regulator chips. +config REGULATOR_TPS6524X + tristate "TI TPS6524X Power regulators" + depends on SPI + help + This driver supports TPS6524X voltage regulator chips. TPS6524X + provides three step-down converters and two general-purpose LDO + voltage regulators. This device is interfaced using a customized + serial interface currently supported on the sequencer serial + port controller. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bff815736780..cf71df72ea5a 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o +obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c new file mode 100644 index 000000000000..176a6be5a8ce --- /dev/null +++ b/drivers/regulator/tps6524x-regulator.c @@ -0,0 +1,693 @@ +/* + * Regulator driver for TPS6524x PMIC + * + * Copyright (C) 2010 Texas Instruments + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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 + +#define REG_LDO_SET 0x0 +#define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */ +#define LDO_VSEL_MASK 0x0f +#define LDO2_ILIM_SHIFT 12 +#define LDO2_VSEL_SHIFT 4 +#define LDO1_ILIM_SHIFT 8 +#define LDO1_VSEL_SHIFT 0 + +#define REG_BLOCK_EN 0x1 +#define BLOCK_MASK 1 +#define BLOCK_LDO1_SHIFT 0 +#define BLOCK_LDO2_SHIFT 1 +#define BLOCK_LCD_SHIFT 2 +#define BLOCK_USB_SHIFT 3 + +#define REG_DCDC_SET 0x2 +#define DCDC_VDCDC_MASK 0x1f +#define DCDC_VDCDC1_SHIFT 0 +#define DCDC_VDCDC2_SHIFT 5 +#define DCDC_VDCDC3_SHIFT 10 + +#define REG_DCDC_EN 0x3 +#define DCDCDCDC_EN_MASK 0x1 +#define DCDCDCDC1_EN_SHIFT 0 +#define DCDCDCDC1_PG_MSK BIT(1) +#define DCDCDCDC2_EN_SHIFT 2 +#define DCDCDCDC2_PG_MSK BIT(3) +#define DCDCDCDC3_EN_SHIFT 4 +#define DCDCDCDC3_PG_MSK BIT(5) + +#define REG_USB 0x4 +#define USB_ILIM_SHIFT 0 +#define USB_ILIM_MASK 0x3 +#define USB_TSD_SHIFT 2 +#define USB_TSD_MASK 0x3 +#define USB_TWARN_SHIFT 4 +#define USB_TWARN_MASK 0x3 +#define USB_IWARN_SD BIT(6) +#define USB_FAST_LOOP BIT(7) + +#define REG_ALARM 0x5 +#define ALARM_LDO1 BIT(0) +#define ALARM_DCDC1 BIT(1) +#define ALARM_DCDC2 BIT(2) +#define ALARM_DCDC3 BIT(3) +#define ALARM_LDO2 BIT(4) +#define ALARM_USB_WARN BIT(5) +#define ALARM_USB_ALARM BIT(6) +#define ALARM_LCD BIT(9) +#define ALARM_TEMP_WARM BIT(10) +#define ALARM_TEMP_HOT BIT(11) +#define ALARM_NRST BIT(14) +#define ALARM_POWERUP BIT(15) + +#define REG_INT_ENABLE 0x6 +#define INT_LDO1 BIT(0) +#define INT_DCDC1 BIT(1) +#define INT_DCDC2 BIT(2) +#define INT_DCDC3 BIT(3) +#define INT_LDO2 BIT(4) +#define INT_USB_WARN BIT(5) +#define INT_USB_ALARM BIT(6) +#define INT_LCD BIT(9) +#define INT_TEMP_WARM BIT(10) +#define INT_TEMP_HOT BIT(11) +#define INT_GLOBAL_EN BIT(15) + +#define REG_INT_STATUS 0x7 +#define STATUS_LDO1 BIT(0) +#define STATUS_DCDC1 BIT(1) +#define STATUS_DCDC2 BIT(2) +#define STATUS_DCDC3 BIT(3) +#define STATUS_LDO2 BIT(4) +#define STATUS_USB_WARN BIT(5) +#define STATUS_USB_ALARM BIT(6) +#define STATUS_LCD BIT(9) +#define STATUS_TEMP_WARM BIT(10) +#define STATUS_TEMP_HOT BIT(11) + +#define REG_SOFTWARE_RESET 0xb +#define REG_WRITE_ENABLE 0xd +#define REG_REV_ID 0xf + +#define N_DCDC 3 +#define N_LDO 2 +#define N_SWITCH 2 +#define N_REGULATORS (3 /* DCDC */ + \ + 2 /* LDO */ + \ + 2 /* switch */) + +#define FIXED_ILIMSEL BIT(0) +#define FIXED_VOLTAGE BIT(1) + +#define CMD_READ(reg) ((reg) << 6) +#define CMD_WRITE(reg) (BIT(5) | (reg) << 6) +#define STAT_CLK BIT(3) +#define STAT_WRITE BIT(2) +#define STAT_INVALID BIT(1) +#define STAT_WP BIT(0) + +struct field { + int reg; + int shift; + int mask; +}; + +struct supply_info { + const char *name; + int n_voltages; + const int *voltages; + int fixed_voltage; + int n_ilimsels; + const int *ilimsels; + int fixed_ilimsel; + int flags; + struct field enable, voltage, ilimsel; +}; + +struct tps6524x { + struct device *dev; + struct spi_device *spi; + struct mutex lock; + struct regulator_desc desc[N_REGULATORS]; + struct regulator_dev *rdev[N_REGULATORS]; +}; + +static int __read_reg(struct tps6524x *hw, int reg) +{ + int error = 0; + u16 cmd = CMD_READ(reg), in; + u8 status; + struct spi_message m; + struct spi_transfer t[3]; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 2; + t[0].bits_per_word = 12; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = ∈ + t[1].len = 2; + t[1].bits_per_word = 16; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = &status; + t[2].len = 1; + t[2].bits_per_word = 4; + spi_message_add_tail(&t[2], &m); + + error = spi_sync(hw->spi, &m); + if (error < 0) + return error; + + dev_dbg(hw->dev, "read reg %d, data %x, status %x\n", + reg, in, status); + + if (!(status & STAT_CLK) || (status & STAT_WRITE)) + return -EIO; + + if (status & STAT_INVALID) + return -EINVAL; + + return in; +} + +static int read_reg(struct tps6524x *hw, int reg) +{ + int ret; + + mutex_lock(&hw->lock); + ret = __read_reg(hw, reg); + mutex_unlock(&hw->lock); + + return ret; +} + +static int __write_reg(struct tps6524x *hw, int reg, int val) +{ + int error = 0; + u16 cmd = CMD_WRITE(reg), out = val; + u8 status; + struct spi_message m; + struct spi_transfer t[3]; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 2; + t[0].bits_per_word = 12; + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = &out; + t[1].len = 2; + t[1].bits_per_word = 16; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = &status; + t[2].len = 1; + t[2].bits_per_word = 4; + spi_message_add_tail(&t[2], &m); + + error = spi_sync(hw->spi, &m); + if (error < 0) + return error; + + dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n", + reg, out, status); + + if (!(status & STAT_CLK) || !(status & STAT_WRITE)) + return -EIO; + + if (status & (STAT_INVALID | STAT_WP)) + return -EINVAL; + + return error; +} + +static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val) +{ + int ret; + + ret = __read_reg(hw, reg); + if (ret < 0) + return ret; + + ret &= ~mask; + ret |= val; + + ret = __write_reg(hw, reg, ret); + + return (ret < 0) ? ret : 0; +} + +static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val) +{ + int ret; + + mutex_lock(&hw->lock); + + ret = __write_reg(hw, REG_WRITE_ENABLE, 1); + if (ret) { + dev_err(hw->dev, "failed to set write enable\n"); + goto error; + } + + ret = __rmw_reg(hw, reg, mask, val); + if (ret) + dev_err(hw->dev, "failed to rmw register %d\n", reg); + + ret = __write_reg(hw, REG_WRITE_ENABLE, 0); + if (ret) { + dev_err(hw->dev, "failed to clear write enable\n"); + goto error; + } + +error: + mutex_unlock(&hw->lock); + + return ret; +} + +static int read_field(struct tps6524x *hw, const struct field *field) +{ + int tmp; + + tmp = read_reg(hw, field->reg); + if (tmp < 0) + return tmp; + + return (tmp >> field->shift) & field->mask; +} + +static int write_field(struct tps6524x *hw, const struct field *field, + int val) +{ + if (val & ~field->mask) + return -EOVERFLOW; + + return rmw_protect(hw, field->reg, + field->mask << field->shift, + val << field->shift); +} + +static const int dcdc1_voltages[] = { + 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, + 1000000, 1025000, 1050000, 1075000, + 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, + 1300000, 1325000, 1350000, 1375000, + 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1575000, +}; + +static const int dcdc2_voltages[] = { + 1400000, 1450000, 1500000, 1550000, + 1600000, 1650000, 1700000, 1750000, + 1800000, 1850000, 1900000, 1950000, + 2000000, 2050000, 2100000, 2150000, + 2200000, 2250000, 2300000, 2350000, + 2400000, 2450000, 2500000, 2550000, + 2600000, 2650000, 2700000, 2750000, + 2800000, 2850000, 2900000, 2950000, +}; + +static const int dcdc3_voltages[] = { + 2400000, 2450000, 2500000, 2550000, 2600000, + 2650000, 2700000, 2750000, 2800000, 2850000, + 2900000, 2950000, 3000000, 3050000, 3100000, + 3150000, 3200000, 3250000, 3300000, 3350000, + 3400000, 3450000, 3500000, 3550000, 3600000, +}; + +static const int ldo1_voltages[] = { + 4300000, 4350000, 4400000, 4450000, + 4500000, 4550000, 4600000, 4650000, + 4700000, 4750000, 4800000, 4850000, + 4900000, 4950000, 5000000, 5050000, +}; + +static const int ldo2_voltages[] = { + 1100000, 1150000, 1200000, 1250000, + 1300000, 1700000, 1750000, 1800000, + 1850000, 1900000, 3150000, 3200000, + 3250000, 3300000, 3350000, 3400000, +}; + +static const int ldo_ilimsel[] = { + 400000, 1500000 +}; + +static const int usb_ilimsel[] = { + 200000, 400000, 800000, 1000000 +}; + +#define __MK_FIELD(_reg, _mask, _shift) \ + { .reg = (_reg), .mask = (_mask), .shift = (_shift), } + +static const struct supply_info supply_info[N_REGULATORS] = { + { + .name = "DCDC1", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc1_voltages), + .voltages = dcdc1_voltages, + .fixed_ilimsel = 2400000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC1_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC1_SHIFT), + }, + { + .name = "DCDC2", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc2_voltages), + .voltages = dcdc2_voltages, + .fixed_ilimsel = 1200000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC2_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC2_SHIFT), + }, + { + .name = "DCDC3", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc3_voltages), + .voltages = dcdc3_voltages, + .fixed_ilimsel = 1200000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC3_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC3_SHIFT), + }, + { + .name = "LDO1", + .n_voltages = ARRAY_SIZE(ldo1_voltages), + .voltages = ldo1_voltages, + .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), + .ilimsels = ldo_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LDO1_SHIFT), + .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, + LDO1_VSEL_SHIFT), + .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, + LDO1_ILIM_SHIFT), + }, + { + .name = "LDO2", + .n_voltages = ARRAY_SIZE(ldo2_voltages), + .voltages = ldo2_voltages, + .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), + .ilimsels = ldo_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LDO2_SHIFT), + .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, + LDO2_VSEL_SHIFT), + .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, + LDO2_ILIM_SHIFT), + }, + { + .name = "USB", + .flags = FIXED_VOLTAGE, + .fixed_voltage = 5000000, + .n_ilimsels = ARRAY_SIZE(usb_ilimsel), + .ilimsels = usb_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_USB_SHIFT), + .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK, + USB_ILIM_SHIFT), + }, + { + .name = "LCD", + .flags = FIXED_VOLTAGE | FIXED_ILIMSEL, + .fixed_voltage = 5000000, + .fixed_ilimsel = 400000, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LCD_SHIFT), + }, +}; + +static int list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return selector ? -EINVAL : info->fixed_voltage; + + return ((selector < info->n_voltages) ? + info->voltages[selector] : -EINVAL); +} + +static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) +{ + const struct supply_info *info; + struct tps6524x *hw; + unsigned i; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return -EINVAL; + + for (i = 0; i < info->n_voltages; i++) + if (min_uV <= info->voltages[i] && + max_uV >= info->voltages[i]) + break; + + if (i >= info->n_voltages) + i = info->n_voltages - 1; + + *selector = info->voltages[i]; + + return write_field(hw, &info->voltage, i); +} + +static int get_voltage(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + int ret; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return info->fixed_voltage; + + ret = read_field(hw, &info->voltage); + if (ret < 0) + return ret; + if (WARN_ON(ret >= info->n_voltages)) + return -EIO; + + return info->voltages[ret]; +} + +static int set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + const struct supply_info *info; + struct tps6524x *hw; + int i; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_ILIMSEL) + return -EINVAL; + + for (i = 0; i < info->n_ilimsels; i++) + if (min_uA <= info->ilimsels[i] && + max_uA >= info->ilimsels[i]) + break; + + if (i >= info->n_ilimsels) + return -EINVAL; + + return write_field(hw, &info->ilimsel, i); +} + +static int get_current_limit(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + int ret; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_ILIMSEL) + return info->fixed_ilimsel; + + ret = read_field(hw, &info->ilimsel); + if (ret < 0) + return ret; + if (WARN_ON(ret >= info->n_ilimsels)) + return -EIO; + + return info->ilimsels[ret]; +} + +static int enable_supply(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return write_field(hw, &info->enable, 1); +} + +static int disable_supply(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return write_field(hw, &info->enable, 0); +} + +static int is_supply_enabled(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return read_field(hw, &info->enable); +} + +static struct regulator_ops regulator_ops = { + .is_enabled = is_supply_enabled, + .enable = enable_supply, + .disable = disable_supply, + .get_voltage = get_voltage, + .set_voltage = set_voltage, + .list_voltage = list_voltage, + .set_current_limit = set_current_limit, + .get_current_limit = get_current_limit, +}; + +static int __devexit pmic_remove(struct spi_device *spi) +{ + struct tps6524x *hw = spi_get_drvdata(spi); + int i; + + if (!hw) + return 0; + for (i = 0; i < N_REGULATORS; i++) { + if (hw->rdev[i]) + regulator_unregister(hw->rdev[i]); + hw->rdev[i] = NULL; + } + spi_set_drvdata(spi, NULL); + kfree(hw); + return 0; +} + +static int __devinit pmic_probe(struct spi_device *spi) +{ + struct tps6524x *hw; + struct device *dev = &spi->dev; + const struct supply_info *info = supply_info; + struct regulator_init_data *init_data; + int ret = 0, i; + + init_data = dev->platform_data; + if (!init_data) { + dev_err(dev, "could not find regulator platform data\n"); + return -EINVAL; + } + + hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL); + if (!hw) { + dev_err(dev, "cannot allocate regulator private data\n"); + return -ENOMEM; + } + spi_set_drvdata(spi, hw); + + memset(hw, 0, sizeof(struct tps6524x)); + hw->dev = dev; + hw->spi = spi_dev_get(spi); + mutex_init(&hw->lock); + + for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { + hw->desc[i].name = info->name; + hw->desc[i].id = i; + hw->desc[i].n_voltages = info->n_voltages; + hw->desc[i].ops = ®ulator_ops; + hw->desc[i].type = REGULATOR_VOLTAGE; + hw->desc[i].owner = THIS_MODULE; + + if (info->flags & FIXED_VOLTAGE) + hw->desc[i].n_voltages = 1; + + hw->rdev[i] = regulator_register(&hw->desc[i], dev, + init_data, hw); + if (IS_ERR(hw->rdev[i])) { + ret = PTR_ERR(hw->rdev[i]); + hw->rdev[i] = NULL; + goto fail; + } + } + + return 0; + +fail: + pmic_remove(spi); + return ret; +} + +static struct spi_driver pmic_driver = { + .probe = pmic_probe, + .remove = __devexit_p(pmic_remove), + .driver = { + .name = "tps6524x", + .owner = THIS_MODULE, + }, +}; + +static int __init pmic_driver_init(void) +{ + return spi_register_driver(&pmic_driver); +} +module_init(pmic_driver_init); + +static void __exit pmic_driver_exit(void) +{ + spi_unregister_driver(&pmic_driver); +} +module_exit(pmic_driver_exit); + +MODULE_DESCRIPTION("TPS6524X PMIC Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:tps6524x"); -- cgit v1.2.3 From cb189b07d57b574cc14382e2130960b0a0193c23 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:40 +0100 Subject: regulators: Moved define for number of regulators in ab8500 The define for number of regulators is moved from ab8500-core to ab8500-regulator so that the regulator driver can be updated independently of ab8500-core. This also changes the platform configuration structure of ab8500-core so that it contains a pointer to the regulator_init_data array plus number of regulators instead of an fixed size array of pointers to regulator_init_data. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 8 +++++++- include/linux/mfd/ab8500.h | 5 ++--- include/linux/regulator/ab8500.h | 24 +++++++++++++----------- 3 files changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 2f4ec0facef1..5670775f6c9b 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -370,6 +370,12 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) } pdata = dev_get_platdata(ab8500->dev); + /* make sure the platform data has the correct size */ + if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { + dev_err(&pdev->dev, "platform configuration error\n"); + return -EINVAL; + } + /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; @@ -380,7 +386,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) info->ab8500 = ab8500; info->regulator = regulator_register(&info->desc, &pdev->dev, - pdata->regulator[i], info); + &pdata->regulator[i], info); if (IS_ERR(info->regulator)) { err = PTR_ERR(info->regulator); dev_err(&pdev->dev, "failed to register regulator %s\n", diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index d63b6050b183..85cf2c28fac6 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h @@ -99,8 +99,6 @@ #define AB8500_NR_IRQS 104 #define AB8500_NUM_IRQ_REGS 13 -#define AB8500_NUM_REGULATORS 15 - /** * struct ab8500 - ab8500 internal structure * @dev: parent device @@ -145,7 +143,8 @@ struct regulator_init_data; struct ab8500_platform_data { int irq_base; void (*init) (struct ab8500 *); - struct regulator_init_data *regulator[AB8500_NUM_REGULATORS]; + int num_regulator; + struct regulator_init_data *regulator; }; extern int __devinit ab8500_init(struct ab8500 *ab8500); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index f509877c2ed4..6a210f1511fc 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -11,15 +11,17 @@ #define __LINUX_MFD_AB8500_REGULATOR_H /* AB8500 regulators */ -#define AB8500_LDO_AUX1 0 -#define AB8500_LDO_AUX2 1 -#define AB8500_LDO_AUX3 2 -#define AB8500_LDO_INTCORE 3 -#define AB8500_LDO_TVOUT 4 -#define AB8500_LDO_AUDIO 5 -#define AB8500_LDO_ANAMIC1 6 -#define AB8500_LDO_ANAMIC2 7 -#define AB8500_LDO_DMIC 8 -#define AB8500_LDO_ANA 9 - +enum ab8500_regulator_id { + AB8500_LDO_AUX1, + AB8500_LDO_AUX2, + AB8500_LDO_AUX3, + AB8500_LDO_INTCORE, + AB8500_LDO_TVOUT, + AB8500_LDO_AUDIO, + AB8500_LDO_ANAMIC1, + AB8500_LDO_ANAMIC2, + AB8500_LDO_DMIC, + AB8500_LDO_ANA, + AB8500_NUM_REGULATORS, +}; #endif -- cgit v1.2.3 From 65e03ed2d0cd49259c527e488b94e93fcf23f62e Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:41 +0100 Subject: regulators: Fixed errors in ab8500 register mapping For INTCORE and TVOUT regulators, the low power register bit is included in the mask so that enable will set the regulator in normal (high power) mode. ANAMIC1, ANAMIC2, DMIC regulator settings are swapped with each other so that the correct regulator gets enabled/disabled. ANA regulator register address is corrected. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 5670775f6c9b..4efe3cf25083 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -330,19 +330,19 @@ static struct ab8500_regulator_info ab8500_regulator_info[] = { ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38, + AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x44, 0x4, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), /* * Fixed Voltage LDOs * name, o/p uV, ctrl bank, ctrl reg, enable, disable */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x2, 0x2), + AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x2), AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x4, 0x4), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x8, 0x8), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(ANA, 1200, 0x03, 0x83, 0xc, 0x4), + AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), + AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), + AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), + AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0xc, 0x4), }; static inline struct ab8500_regulator_info *find_regulator_info(int id) -- cgit v1.2.3 From deaca1ee8250e204cab6ca9390e43ac63b46959c Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:42 +0100 Subject: regulators: Clean out unused code in ab8500 regulators The find_regulator function was unused so it has been removed. The ab8500 pointer in the regulator info structure was unused and so it has also been removed. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 4efe3cf25083..51ff569384df 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -29,7 +29,6 @@ /** * struct ab8500_regulator_info - ab8500 regulator information * @desc: regulator description - * @ab8500: ab8500 parent * @regulator_dev: regulator device * @max_uV: maximum voltage (for variable voltage supplies) * @min_uV: minimum voltage (for variable voltage supplies) @@ -47,7 +46,6 @@ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; - struct ab8500 *ab8500; struct regulator_dev *regulator; int max_uV; int min_uV; @@ -345,19 +343,6 @@ static struct ab8500_regulator_info ab8500_regulator_info[] = { AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0xc, 0x4), }; -static inline struct ab8500_regulator_info *find_regulator_info(int id) -{ - struct ab8500_regulator_info *info; - int i; - - for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { - info = &ab8500_regulator_info[i]; - if (info->desc.id == id) - return info; - } - return NULL; -} - static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); @@ -383,7 +368,6 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) /* assign per-regulator data */ info = &ab8500_regulator_info[i]; info->dev = &pdev->dev; - info->ab8500 = ab8500; info->regulator = regulator_register(&info->desc, &pdev->dev, &pdata->regulator[i], info); -- cgit v1.2.3 From 2b75151a1041f200ee3f36475ba389da43664bb4 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:43 +0100 Subject: regulators: Added ab8500 v2 support The AUX3 regulator voltage setting is changed in ab8500 v2 compared to ab8500 v1. This patch adds v2 support while keeping support for v1. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 51ff569384df..9a3dc7973ae1 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -81,6 +81,17 @@ static const int ldo_vauxn_voltages[] = { 3300000, }; +static const int ldo_vaux3_voltages[] = { + 1200000, + 1500000, + 1800000, + 2100000, + 2500000, + 2750000, + 2790000, + 2910000, +}; + static const int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -326,8 +337,8 @@ static struct ab8500_regulator_info ab8500_regulator_info[] = { ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), + AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0x7, + ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x44, 0x4, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), @@ -369,6 +380,19 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) info = &ab8500_regulator_info[i]; info->dev = &pdev->dev; + /* fix for hardware before ab8500v2.0 */ + if (abx500_get_chip_id(info->dev) < 0x20) { + if (info->desc.id == AB8500_LDO_AUX3) { + info->desc.n_voltages = + ARRAY_SIZE(ldo_vauxn_voltages); + info->supported_voltages = ldo_vauxn_voltages; + info->voltages_len = + ARRAY_SIZE(ldo_vauxn_voltages); + info->voltage_mask = 0xf; + } + } + + /* register regulator with framework */ info->regulator = regulator_register(&info->desc, &pdev->dev, &pdata->regulator[i], info); if (IS_ERR(info->regulator)) { -- cgit v1.2.3 From e1159e6d9ac5faf42abedd2fc02234e3d946585a Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:44 +0100 Subject: regulators: Updated ab8500 variable names, macro names and comments The regulator enumeration is used for putting the regulator data in correct place in the info array. This should be matched in the board configuration. Variable names are updated to be more consistent, comments are corrected and macros have been edited to be consistent. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 161 +++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 9a3dc7973ae1..ccb0bfd71f23 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -3,18 +3,13 @@ * * License Terms: GNU General Public License v2 * - * Author: Sundar Iyer for ST-Ericsson + * Authors: Sundar Iyer for ST-Ericsson + * Bengt Jonsson for ST-Ericsson * * AB8500 peripheral regulators * - * AB8500 supports the following regulators, - * LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT, - * VAUX1/2/3, VANA - * - * for DB8500 cut 1.0 and previous versions of the silicon, all accesses - * to registers are through the DB8500 SPI. In cut 1.1 onwards, these - * accesses are through the DB8500 PRCMU I2C - * + * AB8500 supports the following regulators: + * VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include #include @@ -28,6 +23,7 @@ /** * struct ab8500_regulator_info - ab8500 regulator information + * @dev: device pointer * @desc: regulator description * @regulator_dev: regulator device * @max_uV: maximum voltage (for variable voltage supplies) @@ -35,12 +31,12 @@ * @fixed_uV: typical voltage (for fixed voltage supplies) * @update_bank: bank to control on/off * @update_reg: register to control on/off - * @mask: mask to enable/disable regulator - * @enable: bits to enable the regulator in normal(high power) mode + * @update_mask: mask to enable/disable regulator + * @update_val_enable: bits to enable the regulator in normal (high power) mode * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage - * @supported_voltages: supported voltage table + * @voltages: supported voltage table * @voltages_len: number of supported voltages for the regulator */ struct ab8500_regulator_info { @@ -52,12 +48,12 @@ struct ab8500_regulator_info { int fixed_uV; u8 update_bank; u8 update_reg; - u8 mask; - u8 enable; + u8 update_mask; + u8 update_val_enable; u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; - int const *supported_voltages; + int const *voltages; int voltages_len; }; @@ -112,7 +108,8 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) return -EINVAL; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, info->mask, info->enable); + info->update_bank, info->update_reg, + info->update_mask, info->update_val_enable); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); @@ -129,7 +126,8 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) return -EINVAL; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, info->mask, 0x0); + info->update_bank, info->update_reg, + info->update_mask, 0x0); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); @@ -154,7 +152,7 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) return ret; } - if (value & info->mask) + if (value & info->update_mask) return true; else return false; @@ -176,7 +174,7 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) if (selector >= info->voltages_len) return -EINVAL; - return info->supported_voltages[selector]; + return info->voltages[selector]; } static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) @@ -200,9 +198,9 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) /* vintcore has a different layout */ value &= info->voltage_mask; if (regulator_id == AB8500_LDO_INTCORE) - ret = info->supported_voltages[value >> 0x3]; + ret = info->voltages[value >> 0x3]; else - ret = info->supported_voltages[value]; + ret = info->voltages[value]; return ret; } @@ -215,8 +213,8 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, /* check the supported voltage */ for (i = 0; i < info->voltages_len; i++) { - if ((info->supported_voltages[i] >= min_uV) && - (info->supported_voltages[i] <= max_uV)) + if ((info->voltages[i] >= min_uV) && + (info->voltages[i] <= max_uV)) return i; } @@ -284,74 +282,79 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, min, max, bank, reg, reg_mask, \ - reg_enable, volt_bank, volt_reg, volt_mask, \ - voltages, len_volts) \ -{ \ +#define AB8500_LDO(_id, _min_mV, _max_mV, \ + _u_bank, _u_reg, _u_mask, _u_val_enable, \ + _v_bank, _v_reg, _v_mask, _v_table, _v_table_len) \ +[AB8500_LDO_##_id] = { \ .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ + .name = "LDO-" #_id, \ + .ops = &ab8500_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = AB8500_LDO_##_id, \ + .owner = THIS_MODULE, \ }, \ - .min_uV = (min) * 1000, \ - .max_uV = (max) * 1000, \ - .update_bank = bank, \ - .update_reg = reg, \ - .mask = reg_mask, \ - .enable = reg_enable, \ - .voltage_bank = volt_bank, \ - .voltage_reg = volt_reg, \ - .voltage_mask = volt_mask, \ - .supported_voltages = voltages, \ - .voltages_len = len_volts, \ - .fixed_uV = 0, \ + .min_uV = (_min_mV) * 1000, \ + .max_uV = (_max_mV) * 1000, \ + .update_bank = _u_bank, \ + .update_reg = _u_reg, \ + .update_mask = _u_mask, \ + .update_val_enable = _u_val_enable, \ + .voltage_bank = _v_bank, \ + .voltage_reg = _v_reg, \ + .voltage_mask = _v_mask, \ + .voltages = _v_table, \ + .voltages_len = _v_table_len, \ + .fixed_uV = 0, \ } -#define AB8500_FIXED_LDO(_id, fixed, bank, reg, \ - reg_mask, reg_enable) \ -{ \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_ldo_fixed_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .fixed_uV = fixed * 1000, \ - .update_bank = bank, \ - .update_reg = reg, \ - .mask = reg_mask, \ - .enable = reg_enable, \ +#define AB8500_FIXED_LDO(_id, _fixed_mV, \ + _u_bank, _u_reg, _u_mask, _u_val_enable) \ +[AB8500_LDO_##_id] = { \ + .desc = { \ + .name = "LDO-" #_id, \ + .ops = &ab8500_ldo_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = AB8500_LDO_##_id, \ + .owner = THIS_MODULE, \ + }, \ + .fixed_uV = (_fixed_mV) * 1000, \ + .update_bank = _u_bank, \ + .update_reg = _u_reg, \ + .update_mask = _u_mask, \ + .update_val_enable = _u_val_enable, \ } static struct ab8500_regulator_info ab8500_regulator_info[] = { /* - * Variable Voltage LDOs - * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask, - * volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table, - * num supported volts + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask, table, table length */ - AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0x7, - ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x44, 0x4, 0x03, 0x80, 0x38, + AB8500_LDO(AUX1, 1100, 3300, + 0x04, 0x09, 0x03, 0x01, 0x04, 0x1f, 0x0f, + ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), + AB8500_LDO(AUX2, 1100, 3300, + 0x04, 0x09, 0x0c, 0x04, 0x04, 0x20, 0x0f, + ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), + AB8500_LDO(AUX3, 1100, 3300, + 0x04, 0x0a, 0x03, 0x01, 0x04, 0x21, 0x07, + ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), + AB8500_LDO(INTCORE, 1100, 3300, + 0x03, 0x80, 0x44, 0x04, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), /* - * Fixed Voltage LDOs - * name, o/p uV, ctrl bank, ctrl reg, enable, disable + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x2), - AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), - AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0xc, 0x4), + AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x02), + AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x02, 0x02), + AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), + AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), + AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), + AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0x0c, 0x04), }; static __devinit int ab8500_regulator_probe(struct platform_device *pdev) @@ -385,7 +388,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) if (info->desc.id == AB8500_LDO_AUX3) { info->desc.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages); - info->supported_voltages = ldo_vauxn_voltages; + info->voltages = ldo_vauxn_voltages; info->voltages_len = ARRAY_SIZE(ldo_vauxn_voltages); info->voltage_mask = 0xf; -- cgit v1.2.3 From fc24b426fff45ddaf5663a11daa31ba74f6b6b4f Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:45 +0100 Subject: regulators: Modified ab8500 error handling Error handling is updated to catch NULL pointer errors. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 53 +++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index ccb0bfd71f23..2a15b6300e18 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -100,12 +100,13 @@ static const int ldo_vintcore_voltages[] = { static int ab8500_regulator_enable(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, @@ -118,12 +119,13 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) static int ab8500_regulator_disable(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, @@ -136,13 +138,14 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); u8 value; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_get_register_interruptible(info->dev, info->update_bank, info->update_reg, &value); @@ -160,12 +163,12 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) { - int regulator_id; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } /* return the uV for the fixed regulators */ if (info->fixed_uV) @@ -179,13 +182,14 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); u8 value; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, &value); @@ -197,7 +201,7 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) /* vintcore has a different layout */ value &= info->voltage_mask; - if (regulator_id == AB8500_LDO_INTCORE) + if (info->desc.id == AB8500_LDO_INTCORE) ret = info->voltages[value >> 0x3]; else ret = info->voltages[value]; @@ -225,12 +229,13 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } /* get the appropriate voltages within the range */ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV); @@ -264,12 +269,12 @@ static struct regulator_ops ab8500_regulator_ops = { static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) { - int regulator_id; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } return info->fixed_uV; } @@ -368,6 +373,10 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) return -EINVAL; } pdata = dev_get_platdata(ab8500->dev); + if (!pdata) { + dev_err(&pdev->dev, "null pdata\n"); + return -EINVAL; + } /* make sure the platform data has the correct size */ if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { -- cgit v1.2.3 From 09aefa12ac3c023e2db2315b0e229be98ef6bf23 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:46 +0100 Subject: regulators: Added verbose debug messages to ab8500 regulators The verbose debug outputs register writes and reads that can be used to debug the driver. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 63 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 2a15b6300e18..7d372b87b5dd 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -114,6 +114,12 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); + + dev_vdbg(rdev_get_dev(rdev), + "%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, info->update_val_enable); + return ret; } @@ -133,6 +139,12 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); + + dev_vdbg(rdev_get_dev(rdev), + "%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, 0x0); + return ret; } @@ -140,7 +152,7 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 value; + u8 regval; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); @@ -148,14 +160,20 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) } ret = abx500_get_register_interruptible(info->dev, - info->update_bank, info->update_reg, &value); + info->update_bank, info->update_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read 0x%x register\n", info->update_reg); return ret; } - if (value & info->update_mask) + dev_vdbg(rdev_get_dev(rdev), + "%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," + " 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + if (regval & info->update_mask) return true; else return false; @@ -182,29 +200,35 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int ret; + int ret, val; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 value; + u8 regval; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; } - ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, - info->voltage_reg, &value); + ret = abx500_get_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read voltage reg for regulator\n"); return ret; } + dev_vdbg(rdev_get_dev(rdev), + "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," + " 0x%x\n", + info->desc.name, info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + /* vintcore has a different layout */ - value &= info->voltage_mask; + val = regval & info->voltage_mask; if (info->desc.id == AB8500_LDO_INTCORE) - ret = info->voltages[value >> 0x3]; + ret = info->voltages[val >> 0x3]; else - ret = info->voltages[value]; + ret = info->voltages[val]; return ret; } @@ -231,6 +255,7 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); @@ -248,13 +273,20 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, *selector = ret; /* set the registers for the request */ + regval = (u8)ret; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->voltage_bank, info->voltage_reg, - info->voltage_mask, (u8)ret); + info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set voltage reg for regulator\n"); + dev_vdbg(rdev_get_dev(rdev), + "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," + " 0x%x\n", + info->desc.name, info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + return ret; } @@ -418,6 +450,9 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) } return err; } + + dev_vdbg(rdev_get_dev(info->regulator), + "%s-probed\n", info->desc.name); } return 0; @@ -430,6 +465,10 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; info = &ab8500_regulator_info[i]; + + dev_vdbg(rdev_get_dev(info->regulator), + "%s-remove\n", info->desc.name); + regulator_unregister(info->regulator); } -- cgit v1.2.3 From 6909b4522e0fc459d344fd42db444ca8b3106b8c Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:47 +0100 Subject: regulators: Removed macros for initialization of ab8500 regulators This patch removes the macros for initializing the regulators. The purpose is to remove one layer of abstraction and make the code easier to read. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 241 +++++++++++++++++++++++++++++++++------------ 1 file changed, 179 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 7d372b87b5dd..d9a052c53aec 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -311,7 +311,7 @@ static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) return info->fixed_uV; } -static struct regulator_ops ab8500_ldo_fixed_ops = { +static struct regulator_ops ab8500_regulator_fixed_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, @@ -319,79 +319,196 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, _min_mV, _max_mV, \ - _u_bank, _u_reg, _u_mask, _u_val_enable, \ - _v_bank, _v_reg, _v_mask, _v_table, _v_table_len) \ -[AB8500_LDO_##_id] = { \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .min_uV = (_min_mV) * 1000, \ - .max_uV = (_max_mV) * 1000, \ - .update_bank = _u_bank, \ - .update_reg = _u_reg, \ - .update_mask = _u_mask, \ - .update_val_enable = _u_val_enable, \ - .voltage_bank = _v_bank, \ - .voltage_reg = _v_reg, \ - .voltage_mask = _v_mask, \ - .voltages = _v_table, \ - .voltages_len = _v_table_len, \ - .fixed_uV = 0, \ -} - -#define AB8500_FIXED_LDO(_id, _fixed_mV, \ - _u_bank, _u_reg, _u_mask, _u_val_enable) \ -[AB8500_LDO_##_id] = { \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_ldo_fixed_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .fixed_uV = (_fixed_mV) * 1000, \ - .update_bank = _u_bank, \ - .update_reg = _u_reg, \ - .update_mask = _u_mask, \ - .update_val_enable = _u_val_enable, \ -} - -static struct ab8500_regulator_info ab8500_regulator_info[] = { +static struct ab8500_regulator_info + ab8500_regulator_info[AB8500_NUM_REGULATORS] = { /* * Variable Voltage Regulators * name, min mV, max mV, * update bank, reg, mask, enable val * volt bank, reg, mask, table, table length */ - AB8500_LDO(AUX1, 1100, 3300, - 0x04, 0x09, 0x03, 0x01, 0x04, 0x1f, 0x0f, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, - 0x04, 0x09, 0x0c, 0x04, 0x04, 0x20, 0x0f, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, - 0x04, 0x0a, 0x03, 0x01, 0x04, 0x21, 0x07, - ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, - 0x03, 0x80, 0x44, 0x04, 0x03, 0x80, 0x38, - ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), + [AB8500_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val_enable = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8500_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val_enable = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8500_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val_enable = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + .voltages = ldo_vaux3_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages), + }, + [AB8500_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val_enable = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + .voltages = ldo_vintcore_voltages, + .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages), + }, /* * Fixed Voltage Regulators * name, fixed mV, * update bank, reg, mask, enable val */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x02), - AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x02, 0x02), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), - AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0x0c, 0x04), + [AB8500_LDO_TVOUT] = { + .desc = { + .name = "LDO-TVOUT", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_TVOUT, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val_enable = 0x02, + }, + [AB8500_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val_enable = 0x02, + }, + [AB8500_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val_enable = 0x08, + }, + [AB8500_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val_enable = 0x10, + }, + [AB8500_LDO_DMIC] = { + .desc = { + .name = "LDO-DMIC", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_DMIC, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1800000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val_enable = 0x04, + }, + [AB8500_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1200000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val_enable = 0x04, + }, + + }; static __devinit int ab8500_regulator_probe(struct platform_device *pdev) -- cgit v1.2.3 From 57c78e359a35c69eca4c88f107500f74ef7f0acf Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 14 Dec 2010 14:00:53 +0800 Subject: Change the register name definitions for mc13783 To make mc13783 and mc13892 share code, the register names should be changed to fit the new macro definitions in the comming patch. Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Samuel Ortiz Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- arch/arm/mach-imx/mach-pcm038.c | 4 +-- arch/arm/mach-mx3/mach-mx31_3ds.c | 4 +-- arch/arm/mach-mx3/mach-mx31moboard.c | 4 +-- drivers/regulator/mc13783-regulator.c | 30 ++++++++-------- include/linux/mfd/mc13783.h | 67 ++++++++++++++++++----------------- 5 files changed, 55 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c index f667a262dfc1..505614803bc6 100644 --- a/arch/arm/mach-imx/mach-pcm038.c +++ b/arch/arm/mach-imx/mach-pcm038.c @@ -254,10 +254,10 @@ static struct regulator_init_data cam_data = { static struct mc13783_regulator_init_data pcm038_regulators[] = { { - .id = MC13783_REGU_VCAM, + .id = MC13783_REG_VCAM, .init_data = &cam_data, }, { - .id = MC13783_REGU_VMMC1, + .id = MC13783_REG_VMMC1, .init_data = &sdhc1_data, }, }; diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-mx3/mach-mx31_3ds.c index 4e516b49a901..899a969e92fa 100644 --- a/arch/arm/mach-mx3/mach-mx31_3ds.c +++ b/arch/arm/mach-mx3/mach-mx31_3ds.c @@ -140,10 +140,10 @@ static struct regulator_init_data gpo_init = { static struct mc13783_regulator_init_data mx31_3ds_regulators[] = { { - .id = MC13783_REGU_PWGT1SPI, /* Power Gate for ARM core. */ + .id = MC13783_REG_PWGT1SPI, /* Power Gate for ARM core. */ .init_data = &pwgtx_init, }, { - .id = MC13783_REGU_PWGT2SPI, /* Power Gate for L2 Cache. */ + .id = MC13783_REG_PWGT2SPI, /* Power Gate for L2 Cache. */ .init_data = &pwgtx_init, }, { diff --git a/arch/arm/mach-mx3/mach-mx31moboard.c b/arch/arm/mach-mx3/mach-mx31moboard.c index 203d21a510aa..1aa8d65fccbb 100644 --- a/arch/arm/mach-mx3/mach-mx31moboard.c +++ b/arch/arm/mach-mx3/mach-mx31moboard.c @@ -216,11 +216,11 @@ static struct regulator_init_data cam_vreg_data = { static struct mc13783_regulator_init_data moboard_regulators[] = { { - .id = MC13783_REGU_VMMC1, + .id = MC13783_REG_VMMC1, .init_data = &sdhc_vreg_data, }, { - .id = MC13783_REGU_VCAM, + .id = MC13783_REG_VCAM, .init_data = &cam_vreg_data, }, }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index e99917a63ed4..6a6e1d63d86f 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -228,15 +228,15 @@ static struct regulator_ops mc13783_gpo_regulator_ops; } #define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages) + MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) #define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages) + MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) static struct mc13783_regulator mc13783_regulators[] = { MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), - MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), - MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val), + MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), + MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val), MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \ mc13783_violo_val), MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ @@ -255,7 +255,7 @@ static struct mc13783_regulator mc13783_regulators[] = { mc13783_vesim_val), MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ mc13783_vcam_val), - MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), + MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \ mc13783_vvib_val), MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \ @@ -266,12 +266,12 @@ static struct mc13783_regulator mc13783_regulators[] = { mc13783_vmmc_val), MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \ mc13783_vmmc_val), - MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), - MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO3, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO4, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), }; struct mc13783_regulator_priv { @@ -508,8 +508,8 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); /* Power Gate enable value is 0 */ - if (id == MC13783_REGU_PWGT1SPI || - id == MC13783_REGU_PWGT2SPI) + if (id == MC13783_REG_PWGT1SPI || + id == MC13783_REG_PWGT2SPI) en_val = 0; mc13783_lock(priv->mc13783); @@ -530,8 +530,8 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); /* Power Gate disable value is 1 */ - if (id == MC13783_REGU_PWGT1SPI || - id == MC13783_REGU_PWGT2SPI) + if (id == MC13783_REG_PWGT1SPI || + id == MC13783_REG_PWGT2SPI) dis_val = mc13783_regulators[id].enable_bit; mc13783_lock(priv->mc13783); diff --git a/include/linux/mfd/mc13783.h b/include/linux/mfd/mc13783.h index b4c741e352c2..7d0f3d6a0002 100644 --- a/include/linux/mfd/mc13783.h +++ b/include/linux/mfd/mc13783.h @@ -1,4 +1,5 @@ /* + * Copyright 2010 Yong Shen * Copyright 2009-2010 Pengutronix * Uwe Kleine-Koenig * @@ -122,39 +123,39 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, unsigned int channel, unsigned int *sample); -#define MC13783_SW_SW1A 0 -#define MC13783_SW_SW1B 1 -#define MC13783_SW_SW2A 2 -#define MC13783_SW_SW2B 3 -#define MC13783_SW_SW3 4 -#define MC13783_SW_PLL 5 -#define MC13783_REGU_VAUDIO 6 -#define MC13783_REGU_VIOHI 7 -#define MC13783_REGU_VIOLO 8 -#define MC13783_REGU_VDIG 9 -#define MC13783_REGU_VGEN 10 -#define MC13783_REGU_VRFDIG 11 -#define MC13783_REGU_VRFREF 12 -#define MC13783_REGU_VRFCP 13 -#define MC13783_REGU_VSIM 14 -#define MC13783_REGU_VESIM 15 -#define MC13783_REGU_VCAM 16 -#define MC13783_REGU_VRFBG 17 -#define MC13783_REGU_VVIB 18 -#define MC13783_REGU_VRF1 19 -#define MC13783_REGU_VRF2 20 -#define MC13783_REGU_VMMC1 21 -#define MC13783_REGU_VMMC2 22 -#define MC13783_REGU_GPO1 23 -#define MC13783_REGU_GPO2 24 -#define MC13783_REGU_GPO3 25 -#define MC13783_REGU_GPO4 26 -#define MC13783_REGU_V1 27 -#define MC13783_REGU_V2 28 -#define MC13783_REGU_V3 29 -#define MC13783_REGU_V4 30 -#define MC13783_REGU_PWGT1SPI 31 -#define MC13783_REGU_PWGT2SPI 32 +#define MC13783_REG_SW1A 0 +#define MC13783_REG_SW1B 1 +#define MC13783_REG_SW2A 2 +#define MC13783_REG_SW2B 3 +#define MC13783_REG_SW3 4 +#define MC13783_REG_PLL 5 +#define MC13783_REG_VAUDIO 6 +#define MC13783_REG_VIOHI 7 +#define MC13783_REG_VIOLO 8 +#define MC13783_REG_VDIG 9 +#define MC13783_REG_VGEN 10 +#define MC13783_REG_VRFDIG 11 +#define MC13783_REG_VRFREF 12 +#define MC13783_REG_VRFCP 13 +#define MC13783_REG_VSIM 14 +#define MC13783_REG_VESIM 15 +#define MC13783_REG_VCAM 16 +#define MC13783_REG_VRFBG 17 +#define MC13783_REG_VVIB 18 +#define MC13783_REG_VRF1 19 +#define MC13783_REG_VRF2 20 +#define MC13783_REG_VMMC1 21 +#define MC13783_REG_VMMC2 22 +#define MC13783_REG_GPO1 23 +#define MC13783_REG_GPO2 24 +#define MC13783_REG_GPO3 25 +#define MC13783_REG_GPO4 26 +#define MC13783_REG_V1 27 +#define MC13783_REG_V2 28 +#define MC13783_REG_V3 29 +#define MC13783_REG_V4 30 +#define MC13783_REG_PWGT1SPI 31 +#define MC13783_REG_PWGT2SPI 32 #define MC13783_IRQ_ADCDONE MC13XXX_IRQ_ADCDONE #define MC13783_IRQ_ADCBISDONE MC13XXX_IRQ_ADCBISDONE -- cgit v1.2.3 From 167e3d8af98a111994c4d6b3c5cbc589aedbbc2a Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 14 Dec 2010 14:00:54 +0800 Subject: make mc13783 regulator code generic move some common functions and micros of mc13783 regulaor driver to a seperate file, which makes it possible for mc13892 to share code. Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 4 + drivers/regulator/Makefile | 1 + drivers/regulator/mc13783-regulator.c | 325 ++++------------------------- drivers/regulator/mc13xxx-regulator-core.c | 234 +++++++++++++++++++++ drivers/regulator/mc13xxx.h | 101 +++++++++ 5 files changed, 383 insertions(+), 282 deletions(-) create mode 100644 drivers/regulator/mc13xxx-regulator-core.c create mode 100644 drivers/regulator/mc13xxx.h (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index da34981b1675..ce17a038b0b8 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -186,9 +186,13 @@ config REGULATOR_PCAP This driver provides support for the voltage regulators of the PCAP2 PMIC. +config REGULATOR_MC13XXX_CORE + bool + config REGULATOR_MC13783 tristate "Support regulators on Freescale MC13783 PMIC" depends on MFD_MC13783 + select REGULATOR_MC13XXX_CORE help Say y here to support the regulators found on the Freescale MC13783 PMIC. diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index cf71df72ea5a..0b33bac4f2ab 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o +obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 6a6e1d63d86f..3e5d0c3b4e53 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -1,6 +1,7 @@ /* * Regulator Driver for Freescale MC13783 PMIC * + * Copyright 2010 Yong Shen * Copyright (C) 2008 Sascha Hauer, Pengutronix * Copyright 2009 Alberto Panizzo * @@ -17,6 +18,7 @@ #include #include #include +#include "mc13xxx.h" #define MC13783_REG_SWITCHERS5 29 #define MC13783_REG_SWITCHERS5_SW3EN (1 << 20) @@ -89,16 +91,6 @@ #define MC13783_REG_POWERMISC_PWGTSPI_M (3 << 15) -struct mc13783_regulator { - struct regulator_desc desc; - int reg; - int enable_bit; - int vsel_reg; - int vsel_shift; - int vsel_mask; - int const *voltages; -}; - /* Voltage Values */ static const int mc13783_sw3_val[] = { 5000000, 5000000, 5000000, 5500000, @@ -175,64 +167,26 @@ static const int mc13783_pwgtdrv_val[] = { 5500000, }; -static struct regulator_ops mc13783_regulator_ops; -static struct regulator_ops mc13783_fixed_regulator_ops; static struct regulator_ops mc13783_gpo_regulator_ops; -#define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .vsel_reg = MC13783_REG_ ## _vsel_reg, \ - .vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\ - .vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\ - .voltages = _voltages, \ - } +#define MC13783_DEFINE(prefix, name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13783_REG_, name, reg, vsel_reg, voltages, \ + mc13xxx_regulator_ops) -#define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_fixed_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ - } +#define MC13783_FIXED_DEFINE(prefix, name, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13783_REG_, name, reg, voltages, \ + mc13xxx_fixed_regulator_ops) -#define MC13783_GPO_DEFINE(prefix, _name, _reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_gpo_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ - } +#define MC13783_GPO_DEFINE(prefix, name, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13783_REG_, name, reg, voltages, \ + mc13783_gpo_regulator_ops) #define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \ MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) #define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \ MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) -static struct mc13783_regulator mc13783_regulators[] = { +static struct mc13xxx_regulator mc13783_regulators[] = { MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), @@ -274,213 +228,16 @@ static struct mc13783_regulator mc13783_regulators[] = { MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), }; -struct mc13783_regulator_priv { - struct mc13783 *mc13783; - u32 powermisc_pwgt_state; - struct regulator_dev *regulators[]; -}; - -static int mc13783_regulator_enable(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg, - mc13783_regulators[id].enable_bit, - mc13783_regulators[id].enable_bit); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_disable(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg, - mc13783_regulators[id].enable_bit, 0); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - unsigned int val; - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - return (val & mc13783_regulators[id].enable_bit) != 0; -} - -static int mc13783_regulator_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - int id = rdev_get_id(rdev); - - if (selector >= mc13783_regulators[id].desc.n_voltages) - return -EINVAL; - - return mc13783_regulators[id].voltages[selector]; -} - -static int mc13783_get_best_voltage_index(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int reg_id = rdev_get_id(rdev); - int i; - int bestmatch; - int bestindex; - - /* - * Locate the minimum voltage fitting the criteria on - * this regulator. The switchable voltages are not - * in strict falling order so we need to check them - * all for the best match. - */ - bestmatch = INT_MAX; - bestindex = -1; - for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) { - if (mc13783_regulators[reg_id].voltages[i] >= min_uV && - mc13783_regulators[reg_id].voltages[i] < bestmatch) { - bestmatch = mc13783_regulators[reg_id].voltages[i]; - bestindex = i; - } - } - - if (bestindex < 0 || bestmatch > max_uV) { - dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", - min_uV, max_uV); - return -EINVAL; - } - return bestindex; -} - -static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int value, id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - /* Find the best index */ - value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV); - dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value); - if (value < 0) - return value; - - *selector = value; - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg, - mc13783_regulators[id].vsel_mask, - value << mc13783_regulators[id].vsel_shift); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_get_voltage(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - unsigned int val; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, - mc13783_regulators[id].vsel_reg, &val); - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - val = (val & mc13783_regulators[id].vsel_mask) - >> mc13783_regulators[id].vsel_shift; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); - - BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages); - - return mc13783_regulators[id].voltages[val]; -} - -static struct regulator_ops mc13783_regulator_ops = { - .enable = mc13783_regulator_enable, - .disable = mc13783_regulator_disable, - .is_enabled = mc13783_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_regulator_set_voltage, - .get_voltage = mc13783_regulator_get_voltage, -}; - -static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned int *selector) -{ - int id = rdev_get_id(rdev); - - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - *selector = 0; - - if (min_uV >= mc13783_regulators[id].voltages[0] && - max_uV <= mc13783_regulators[id].voltages[0]) - return 0; - else - return -EINVAL; -} - -static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev) -{ - int id = rdev_get_id(rdev); - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - return mc13783_regulators[id].voltages[0]; -} - -static struct regulator_ops mc13783_fixed_regulator_ops = { - .enable = mc13783_regulator_enable, - .disable = mc13783_regulator_disable, - .is_enabled = mc13783_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_fixed_regulator_set_voltage, - .get_voltage = mc13783_fixed_regulator_get_voltage, -}; - -static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, - u32 val) +static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) { - struct mc13783 *mc13783 = priv->mc13783; + struct mc13xxx *mc13783 = priv->mc13xxx; int ret; u32 valread; BUG_ON(val & ~mask); - ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); + ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); if (ret) return ret; @@ -495,15 +252,16 @@ static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) | priv->powermisc_pwgt_state; - return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread); + return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread); } static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); int ret; - u32 en_val = mc13783_regulators[id].enable_bit; + u32 en_val = mc13xxx_regulators[id].enable_bit; dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); @@ -512,17 +270,18 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) id == MC13783_REG_PWGT2SPI) en_val = 0; - mc13783_lock(priv->mc13783); - ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, + mc13xxx_lock(priv->mc13xxx); + ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, en_val); - mc13783_unlock(priv->mc13783); + mc13xxx_unlock(priv->mc13xxx); return ret; } static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); int ret; u32 dis_val = 0; @@ -532,25 +291,26 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) /* Power Gate disable value is 1 */ if (id == MC13783_REG_PWGT1SPI || id == MC13783_REG_PWGT2SPI) - dis_val = mc13783_regulators[id].enable_bit; + dis_val = mc13xxx_regulators[id].enable_bit; - mc13783_lock(priv->mc13783); - ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, + mc13xxx_lock(priv->mc13xxx); + ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, dis_val); - mc13783_unlock(priv->mc13783); + mc13xxx_unlock(priv->mc13xxx); return ret; } static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int ret, id = rdev_get_id(rdev); unsigned int val; - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); - mc13783_unlock(priv->mc13783); + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); if (ret) return ret; @@ -560,22 +320,22 @@ static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) | (priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M); - return (val & mc13783_regulators[id].enable_bit) != 0; + return (val & mc13xxx_regulators[id].enable_bit) != 0; } static struct regulator_ops mc13783_gpo_regulator_ops = { .enable = mc13783_gpo_regulator_enable, .disable = mc13783_gpo_regulator_disable, .is_enabled = mc13783_gpo_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_fixed_regulator_set_voltage, - .get_voltage = mc13783_fixed_regulator_get_voltage, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; static int __devinit mc13783_regulator_probe(struct platform_device *pdev) { - struct mc13783_regulator_priv *priv; - struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_regulator_priv *priv; + struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); struct mc13783_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783_regulator_init_data *init_data; @@ -589,7 +349,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->mc13783 = mc13783; + priv->mc13xxx_regulators = mc13783_regulators; + priv->mc13xxx = mc13783; for (i = 0; i < pdata->num_regulators; i++) { init_data = &pdata->regulators[i]; @@ -619,7 +380,7 @@ err: static int __devexit mc13783_regulator_remove(struct platform_device *pdev) { - struct mc13783_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13783_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); int i; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c new file mode 100644 index 000000000000..448e8f4cf41b --- /dev/null +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -0,0 +1,234 @@ +/* + * Regulator Driver for Freescale MC13xxx PMIC + * + * Copyright 2010 Yong Shen + * + * Based on mc13783 regulator driver : + * Copyright (C) 2008 Sascha Hauer, Pengutronix + * Copyright 2009 Alberto Panizzo + * + * 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. + * + * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file + * from freescale + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mc13xxx.h" + +static int mc13xxx_regulator_enable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, + mc13xxx_regulators[id].enable_bit); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_disable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, 0); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + return (val & mc13xxx_regulators[id].enable_bit) != 0; +} + +int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + int id = rdev_get_id(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + + if (selector >= mc13xxx_regulators[id].desc.n_voltages) + return -EINVAL; + + return mc13xxx_regulators[id].voltages[selector]; +} + +int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int reg_id = rdev_get_id(rdev); + int i; + int bestmatch; + int bestindex; + + /* + * Locate the minimum voltage fitting the criteria on + * this regulator. The switchable voltages are not + * in strict falling order so we need to check them + * all for the best match. + */ + bestmatch = INT_MAX; + bestindex = -1; + for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) { + if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV && + mc13xxx_regulators[reg_id].voltages[i] < bestmatch) { + bestmatch = mc13xxx_regulators[reg_id].voltages[i]; + bestindex = i; + } + } + + if (bestindex < 0 || bestmatch > max_uV) { + dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", + min_uV, max_uV); + return -EINVAL; + } + return bestindex; +} + +static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int value, id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + /* Find the best index */ + value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); + dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); + if (value < 0) + return value; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, + mc13xxx_regulators[id].vsel_mask, + value << mc13xxx_regulators[id].vsel_shift); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int ret, id = rdev_get_id(rdev); + unsigned int val; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13xxx_regulators[id].vsel_reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + val = (val & mc13xxx_regulators[id].vsel_mask) + >> mc13xxx_regulators[id].vsel_shift; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + + BUG_ON(val < 0 || val > mc13xxx_regulators[id].desc.n_voltages); + + return mc13xxx_regulators[id].voltages[val]; +} + +struct regulator_ops mc13xxx_regulator_ops = { + .enable = mc13xxx_regulator_enable, + .disable = mc13xxx_regulator_disable, + .is_enabled = mc13xxx_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_regulator_set_voltage, + .get_voltage = mc13xxx_regulator_get_voltage, +}; + +int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + if (min_uV >= mc13xxx_regulators[id].voltages[0] && + max_uV <= mc13xxx_regulators[id].voltages[0]) + return 0; + else + return -EINVAL; +} + +int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + return mc13xxx_regulators[id].voltages[0]; +} + +struct regulator_ops mc13xxx_fixed_regulator_ops = { + .enable = mc13xxx_regulator_enable, + .disable = mc13xxx_regulator_disable, + .is_enabled = mc13xxx_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, +}; + +int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) +{ + return 1; +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen "); +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC"); +MODULE_ALIAS("mc13xxx-regulator-core"); diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h new file mode 100644 index 000000000000..27758267e122 --- /dev/null +++ b/drivers/regulator/mc13xxx.h @@ -0,0 +1,101 @@ +/* + * mc13xxx.h - regulators for the Freescale mc13xxx PMIC + * + * Copyright (C) 2010 Yong Shen + * + * 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 __LINUX_REGULATOR_MC13XXX_H +#define __LINUX_REGULATOR_MC13XXX_H + +#include + +struct mc13xxx_regulator { + struct regulator_desc desc; + int reg; + int enable_bit; + int vsel_reg; + int vsel_shift; + int vsel_mask; + int hi_bit; + int const *voltages; +}; + +struct mc13xxx_regulator_priv { + struct mc13xxx *mc13xxx; + u32 powermisc_pwgt_state; + struct mc13xxx_regulator *mc13xxx_regulators; + struct regulator_dev *regulators[]; +}; + +extern int mc13xxx_sw_regulator(struct regulator_dev *rdev); +extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev); +extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, + int min_uV, int max_uV); +extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector); +extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector); +extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev); + +extern struct regulator_ops mc13xxx_regulator_ops; +extern struct regulator_ops mc13xxx_fixed_regulator_ops; + +#define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .vsel_reg = prefix ## _vsel_reg, \ + .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\ + .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\ + .voltages = _voltages, \ + } + +#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .voltages = _voltages, \ + } + +#define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .voltages = _voltages, \ + } + +#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(SW, _name, _reg, _vsel_reg, _voltages, ops) +#define MC13xxx_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages, ops) + +#endif -- cgit v1.2.3 From 5e428d5cecc3f109b52e993a1bd91f82137867b3 Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 14 Dec 2010 14:00:55 +0800 Subject: regulator: support PMIC mc13892 add support for mc13892, tested on mx51 babbage board Signed-off-by: Arnaud Patard Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Samuel Ortiz Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 8 + drivers/regulator/Makefile | 1 + drivers/regulator/mc13892-regulator.c | 635 ++++++++++++++++++++++++++++++++++ include/linux/mfd/mc13892.h | 39 +++ 4 files changed, 683 insertions(+) create mode 100644 drivers/regulator/mc13892-regulator.c create mode 100644 include/linux/mfd/mc13892.h (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index ce17a038b0b8..485a9bc88ca9 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -197,6 +197,14 @@ config REGULATOR_MC13783 Say y here to support the regulators found on the Freescale MC13783 PMIC. +config REGULATOR_MC13892 + tristate "Support regulators on Freescale MC13892 PMIC" + depends on MFD_MC13XXX + select REGULATOR_MC13XXX_CORE + help + Say y here to support the regulators found on the Freescale MC13892 + PMIC. + config REGULATOR_AB3100 tristate "ST-Ericsson AB3100 Regulator functions" depends on AB3100_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 0b33bac4f2ab..0b5e88c2b8d7 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o +obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c new file mode 100644 index 000000000000..ca1d30adad99 --- /dev/null +++ b/drivers/regulator/mc13892-regulator.c @@ -0,0 +1,635 @@ +/* + * Regulator Driver for Freescale MC13892 PMIC + * + * Copyright 2010 Yong Shen + * + * Based on draft driver from Arnaud Patard + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mc13xxx.h" + +#define MC13892_REVISION 7 + +#define MC13892_POWERCTL0 13 +#define MC13892_POWERCTL0_USEROFFSPI 3 +#define MC13892_POWERCTL0_VCOINCELLVSEL 20 +#define MC13892_POWERCTL0_VCOINCELLVSEL_M (7<<20) +#define MC13892_POWERCTL0_VCOINCELLEN (1<<23) + +#define MC13892_SWITCHERS0_SWxHI (1<<23) + +#define MC13892_SWITCHERS0 24 +#define MC13892_SWITCHERS0_SW1VSEL 0 +#define MC13892_SWITCHERS0_SW1VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS0_SW1HI (1<<23) +#define MC13892_SWITCHERS0_SW1EN 0 + +#define MC13892_SWITCHERS1 25 +#define MC13892_SWITCHERS1_SW2VSEL 0 +#define MC13892_SWITCHERS1_SW2VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS1_SW2HI (1<<23) +#define MC13892_SWITCHERS1_SW2EN 0 + +#define MC13892_SWITCHERS2 26 +#define MC13892_SWITCHERS2_SW3VSEL 0 +#define MC13892_SWITCHERS2_SW3VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS2_SW3HI (1<<23) +#define MC13892_SWITCHERS2_SW3EN 0 + +#define MC13892_SWITCHERS3 27 +#define MC13892_SWITCHERS3_SW4VSEL 0 +#define MC13892_SWITCHERS3_SW4VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS3_SW4HI (1<<23) +#define MC13892_SWITCHERS3_SW4EN 0 + +#define MC13892_SWITCHERS4 28 +#define MC13892_SWITCHERS4_SW1MODE 0 +#define MC13892_SWITCHERS4_SW1MODE_AUTO (8<<0) +#define MC13892_SWITCHERS4_SW1MODE_M (0xf<<0) +#define MC13892_SWITCHERS4_SW2MODE 10 +#define MC13892_SWITCHERS4_SW2MODE_AUTO (8<<10) +#define MC13892_SWITCHERS4_SW2MODE_M (0xf<<10) + +#define MC13892_SWITCHERS5 29 +#define MC13892_SWITCHERS5_SW3MODE 0 +#define MC13892_SWITCHERS5_SW3MODE_AUTO (8<<0) +#define MC13892_SWITCHERS5_SW3MODE_M (0xf<<0) +#define MC13892_SWITCHERS5_SW4MODE 8 +#define MC13892_SWITCHERS5_SW4MODE_AUTO (8<<8) +#define MC13892_SWITCHERS5_SW4MODE_M (0xf<<8) +#define MC13892_SWITCHERS5_SWBSTEN (1<<20) + +#define MC13892_REGULATORSETTING0 30 +#define MC13892_REGULATORSETTING0_VGEN1VSEL 0 +#define MC13892_REGULATORSETTING0_VDIGVSEL 4 +#define MC13892_REGULATORSETTING0_VGEN2VSEL 6 +#define MC13892_REGULATORSETTING0_VPLLVSEL 9 +#define MC13892_REGULATORSETTING0_VUSB2VSEL 11 +#define MC13892_REGULATORSETTING0_VGEN3VSEL 14 +#define MC13892_REGULATORSETTING0_VCAMVSEL 16 + +#define MC13892_REGULATORSETTING0_VGEN1VSEL_M (3<<0) +#define MC13892_REGULATORSETTING0_VDIGVSEL_M (3<<4) +#define MC13892_REGULATORSETTING0_VGEN2VSEL_M (7<<6) +#define MC13892_REGULATORSETTING0_VPLLVSEL_M (3<<9) +#define MC13892_REGULATORSETTING0_VUSB2VSEL_M (3<<11) +#define MC13892_REGULATORSETTING0_VGEN3VSEL_M (1<<14) +#define MC13892_REGULATORSETTING0_VCAMVSEL_M (3<<16) + +#define MC13892_REGULATORSETTING1 31 +#define MC13892_REGULATORSETTING1_VVIDEOVSEL 2 +#define MC13892_REGULATORSETTING1_VAUDIOVSEL 4 +#define MC13892_REGULATORSETTING1_VSDVSEL 6 + +#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M (3<<2) +#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M (3<<4) +#define MC13892_REGULATORSETTING1_VSDVSEL_M (7<<6) + +#define MC13892_REGULATORMODE0 32 +#define MC13892_REGULATORMODE0_VGEN1EN (1<<0) +#define MC13892_REGULATORMODE0_VGEN1STDBY (1<<1) +#define MC13892_REGULATORMODE0_VGEN1MODE (1<<2) +#define MC13892_REGULATORMODE0_VIOHIEN (1<<3) +#define MC13892_REGULATORMODE0_VIOHISTDBY (1<<4) +#define MC13892_REGULATORMODE0_VIOHIMODE (1<<5) +#define MC13892_REGULATORMODE0_VDIGEN (1<<9) +#define MC13892_REGULATORMODE0_VDIGSTDBY (1<<10) +#define MC13892_REGULATORMODE0_VDIGMODE (1<<11) +#define MC13892_REGULATORMODE0_VGEN2EN (1<<12) +#define MC13892_REGULATORMODE0_VGEN2STDBY (1<<13) +#define MC13892_REGULATORMODE0_VGEN2MODE (1<<14) +#define MC13892_REGULATORMODE0_VPLLEN (1<<15) +#define MC13892_REGULATORMODE0_VPLLSTDBY (1<<16) +#define MC13892_REGULATORMODE0_VPLLMODE (1<<17) +#define MC13892_REGULATORMODE0_VUSB2EN (1<<18) +#define MC13892_REGULATORMODE0_VUSB2STDBY (1<<19) +#define MC13892_REGULATORMODE0_VUSB2MODE (1<<20) + +#define MC13892_REGULATORMODE1 33 +#define MC13892_REGULATORMODE1_VGEN3EN (1<<0) +#define MC13892_REGULATORMODE1_VGEN3STDBY (1<<1) +#define MC13892_REGULATORMODE1_VGEN3MODE (1<<2) +#define MC13892_REGULATORMODE1_VCAMEN (1<<6) +#define MC13892_REGULATORMODE1_VCAMSTDBY (1<<7) +#define MC13892_REGULATORMODE1_VCAMMODE (1<<8) +#define MC13892_REGULATORMODE1_VCAMCONFIGEN (1<<9) +#define MC13892_REGULATORMODE1_VVIDEOEN (1<<12) +#define MC13892_REGULATORMODE1_VVIDEOSTDBY (1<<13) +#define MC13892_REGULATORMODE1_VVIDEOMODE (1<<14) +#define MC13892_REGULATORMODE1_VAUDIOEN (1<<15) +#define MC13892_REGULATORMODE1_VAUDIOSTDBY (1<<16) +#define MC13892_REGULATORMODE1_VAUDIOMODE (1<<17) +#define MC13892_REGULATORMODE1_VSDEN (1<<18) +#define MC13892_REGULATORMODE1_VSDSTDBY (1<<19) +#define MC13892_REGULATORMODE1_VSDMODE (1<<20) + +#define MC13892_POWERMISC 34 +#define MC13892_POWERMISC_GPO1EN (1<<6) +#define MC13892_POWERMISC_GPO2EN (1<<8) +#define MC13892_POWERMISC_GPO3EN (1<<10) +#define MC13892_POWERMISC_GPO4EN (1<<12) +#define MC13892_POWERMISC_PWGT1SPIEN (1<<15) +#define MC13892_POWERMISC_PWGT2SPIEN (1<<16) +#define MC13892_POWERMISC_GPO4ADINEN (1<<21) + +#define MC13892_POWERMISC_PWGTSPI_M (3 << 15) + +#define MC13892_USB1 50 +#define MC13892_USB1_VUSBEN (1<<3) + +static const int mc13892_vcoincell[] = { + 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, + 3200000, 3300000, +}; + +static const int mc13892_sw1[] = { + 600000, 625000, 650000, 675000, 700000, 725000, + 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, + 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, + 1350000, 1375000 +}; + +static const int mc13892_sw[] = { + 600000, 625000, 650000, 675000, 700000, 725000, + 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, + 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, + 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1575000, 1600000, 1625000, + 1650000, 1675000, 1700000, 1725000, 1750000, 1775000, + 1800000, 1825000, 1850000, 1875000 +}; + +static const int mc13892_swbst[] = { + 5000000, +}; + +static const int mc13892_viohi[] = { + 2775000, +}; + +static const int mc13892_vpll[] = { + 1050000, 1250000, 1650000, 1800000, +}; + +static const int mc13892_vdig[] = { + 1050000, 1250000, 1650000, 1800000, +}; + +static const int mc13892_vsd[] = { + 1800000, 2000000, 2600000, 2700000, + 2800000, 2900000, 3000000, 3150000, +}; + +static const int mc13892_vusb2[] = { + 2400000, 2600000, 2700000, 2775000, +}; + +static const int mc13892_vvideo[] = { + 2700000, 2775000, 2500000, 2600000, +}; + +static const int mc13892_vaudio[] = { + 2300000, 2500000, 2775000, 3000000, +}; + +static const int mc13892_vcam[] = { + 2500000, 2600000, 2750000, 3000000, +}; + +static const int mc13892_vgen1[] = { + 1200000, 1500000, 2775000, 3150000, +}; + +static const int mc13892_vgen2[] = { + 1200000, 1500000, 1600000, 1800000, + 2700000, 2800000, 3000000, 3150000, +}; + +static const int mc13892_vgen3[] = { + 1800000, 2900000, +}; + +static const int mc13892_vusb[] = { + 3300000, +}; + +static const int mc13892_gpo[] = { + 2750000, +}; + +static const int mc13892_pwgtdrv[] = { + 5000000, +}; + +static struct regulator_ops mc13892_gpo_regulator_ops; +/* sw regulators need special care due to the "hi bit" */ +static struct regulator_ops mc13892_sw_regulator_ops; + + +#define MC13892_FIXED_DEFINE(name, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \ + mc13xxx_fixed_regulator_ops) + +#define MC13892_GPO_DEFINE(name, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \ + mc13892_gpo_regulator_ops) + +#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ + mc13892_sw_regulator_ops) + +#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ + mc13xxx_regulator_ops) + +static struct mc13xxx_regulator mc13892_regulators[] = { + MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell), + MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1), + MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw), + MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw), + MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw), + MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst), + MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi), + MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vpll), + MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vdig), + MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vsd), + MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vusb2), + MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vvideo), + MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vaudio), + MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ + mc13892_vcam), + MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vgen1), + MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vgen2), + MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, \ + mc13892_vgen3), + MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb), + MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv), + MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), +}; + +int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) +{ + struct mc13xxx *mc13892 = priv->mc13xxx; + int ret; + u32 valread; + + BUG_ON(val & ~mask); + + ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread); + if (ret) + return ret; + + /* Update the stored state for Power Gates. */ + priv->powermisc_pwgt_state = + (priv->powermisc_pwgt_state & ~mask) | val; + priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M; + + /* Construct the new register value */ + valread = (valread & ~mask) | val; + /* Overwrite the PWGTxEN with the stored version */ + valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) | + priv->powermisc_pwgt_state; + + return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread); +} + +static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + u32 en_val = mc13892_regulators[id].enable_bit; + u32 mask = mc13892_regulators[id].enable_bit; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + /* Power Gate enable value is 0 */ + if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) + en_val = 0; + + if (id == MC13892_GPO4) + mask |= MC13892_POWERMISC_GPO4ADINEN; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13892_powermisc_rmw(priv, mask, en_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + u32 dis_val = 0; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + /* Power Gate disable value is 1 */ + if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) + dis_val = mc13892_regulators[id].enable_bit; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit, + dis_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + /* Power Gates state is stored in powermisc_pwgt_state + * where the meaning of bits is negated */ + val = (val & ~MC13892_POWERMISC_PWGTSPI_M) | + (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M); + + return (val & mc13892_regulators[id].enable_bit) != 0; +} + + +static struct regulator_ops mc13892_gpo_regulator_ops = { + .enable = mc13892_gpo_regulator_enable, + .disable = mc13892_gpo_regulator_disable, + .is_enabled = mc13892_gpo_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, +}; + +static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val, hi; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13892_regulators[id].vsel_reg, &val); + mc13xxx_unlock(priv->mc13xxx); + if (ret) + return ret; + + hi = val & MC13892_SWITCHERS0_SWxHI; + val = (val & mc13892_regulators[id].vsel_mask) + >> mc13892_regulators[id].vsel_shift; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + + if (hi) + val = (25000 * val) + 1100000; + else + val = (25000 * val) + 600000; + + return val; +} + +static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int hi, value, val, mask, id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + /* Find the best index */ + value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); + dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); + if (value < 0) + return value; + + value = mc13892_regulators[id].voltages[value]; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13892_regulators[id].vsel_reg, &val); + if (ret) + goto err; + + hi = val & MC13892_SWITCHERS0_SWxHI; + if (value > 1375) + hi = 1; + if (value < 1100) + hi = 0; + + if (hi) { + value = (value - 1100000) / 25000; + value |= MC13892_SWITCHERS0_SWxHI; + } else + value = (value - 600000) / 25000; + + mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI; + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, + mask, value << mc13892_regulators[id].vsel_shift); +err: + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static struct regulator_ops mc13892_sw_regulator_ops = { + .is_enabled = mc13xxx_sw_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13892_sw_regulator_set_voltage, + .get_voltage = mc13892_sw_regulator_get_voltage, +}; + +static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + unsigned int en_val = 0; + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + + if (mode == REGULATOR_MODE_FAST) + en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, + MC13892_REGULATORMODE1_VCAMCONFIGEN, en_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + + +static int __devinit mc13892_regulator_probe(struct platform_device *pdev) +{ + struct mc13xxx_regulator_priv *priv; + struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); + struct mc13xxx_regulator_init_data *init_data; + int i, ret; + u32 val; + + priv = kzalloc(sizeof(*priv) + + pdata->num_regulators * sizeof(priv->regulators[0]), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->mc13xxx_regulators = mc13892_regulators; + priv->mc13xxx = mc13892; + + mc13xxx_lock(mc13892); + ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val); + if (ret) + goto err_free; + + /* enable switch auto mode */ + if ((val & 0x0000FFFF) == 0x45d0) { + ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4, + MC13892_SWITCHERS4_SW1MODE_M | + MC13892_SWITCHERS4_SW2MODE_M, + MC13892_SWITCHERS4_SW1MODE_AUTO | + MC13892_SWITCHERS4_SW2MODE_AUTO); + if (ret) + goto err_free; + + mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, + MC13892_SWITCHERS5_SW3MODE_M | + MC13892_SWITCHERS5_SW4MODE_M, + MC13892_SWITCHERS5_SW3MODE_AUTO | + MC13892_SWITCHERS5_SW4MODE_AUTO); + if (ret) + goto err_free; + } + mc13xxx_unlock(mc13892); + + mc13892_regulators[MC13892_VCAM].desc.ops->set_mode + = mc13892_vcam_set_mode; + mc13892_regulators[MC13892_VCAM].desc.ops->get_mode + = mc13892_vcam_get_mode; + for (i = 0; i < pdata->num_regulators; i++) { + init_data = &pdata->regulators[i]; + priv->regulators[i] = regulator_register( + &mc13892_regulators[init_data->id].desc, + &pdev->dev, init_data->init_data, priv); + + if (IS_ERR(priv->regulators[i])) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + mc13892_regulators[i].desc.name); + ret = PTR_ERR(priv->regulators[i]); + goto err; + } + } + + platform_set_drvdata(pdev, priv); + + return 0; +err: + while (--i >= 0) + regulator_unregister(priv->regulators[i]); + +err_free: + mc13xxx_unlock(mc13892); + kfree(priv); + + return ret; +} + +static int __devexit mc13892_regulator_remove(struct platform_device *pdev) +{ + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); + int i; + + platform_set_drvdata(pdev, NULL); + + for (i = 0; i < pdata->num_regulators; i++) + regulator_unregister(priv->regulators[i]); + + kfree(priv); + return 0; +} + +static struct platform_driver mc13892_regulator_driver = { + .driver = { + .name = "mc13892-regulator", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(mc13892_regulator_remove), + .probe = mc13892_regulator_probe, +}; + +static int __init mc13892_regulator_init(void) +{ + return platform_driver_register(&mc13892_regulator_driver); +} +subsys_initcall(mc13892_regulator_init); + +static void __exit mc13892_regulator_exit(void) +{ + platform_driver_unregister(&mc13892_regulator_driver); +} +module_exit(mc13892_regulator_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen "); +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC"); +MODULE_ALIAS("platform:mc13892-regulator"); diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h new file mode 100644 index 000000000000..a00f2bec178c --- /dev/null +++ b/include/linux/mfd/mc13892.h @@ -0,0 +1,39 @@ +/* + * Copyright 2010 Yong Shen + * + * 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. + */ + +#ifndef __LINUX_MFD_MC13892_H +#define __LINUX_MFD_MC13892_H + +#include + +#define MC13892_SW1 0 +#define MC13892_SW2 1 +#define MC13892_SW3 2 +#define MC13892_SW4 3 +#define MC13892_SWBST 4 +#define MC13892_VIOHI 5 +#define MC13892_VPLL 6 +#define MC13892_VDIG 7 +#define MC13892_VSD 8 +#define MC13892_VUSB2 9 +#define MC13892_VVIDEO 10 +#define MC13892_VAUDIO 11 +#define MC13892_VCAM 12 +#define MC13892_VGEN1 13 +#define MC13892_VGEN2 14 +#define MC13892_VGEN3 15 +#define MC13892_VUSB 16 +#define MC13892_GPO1 17 +#define MC13892_GPO2 18 +#define MC13892_GPO3 19 +#define MC13892_GPO4 20 +#define MC13892_PWGT1SPI 21 +#define MC13892_PWGT2SPI 22 +#define MC13892_VCOINCELL 23 + +#endif -- cgit v1.2.3 From 4d7071f1fdc9c27e15e8aaede27bef9f4feccafe Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Dec 2010 14:10:25 +0000 Subject: regulator: Allow modular build of mc13xxx-core Since the MFD core for this device and the regulator drivers for these devices can be built modular we should also support modular build of the shared code for the regulator drivers, otherwise we try to link built in code against modular code with unfortunate results. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 2 +- drivers/regulator/mc13xxx-regulator-core.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 485a9bc88ca9..e1d943619ab8 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -187,7 +187,7 @@ config REGULATOR_PCAP PCAP2 PMIC. config REGULATOR_MC13XXX_CORE - bool + tristate config REGULATOR_MC13783 tristate "Support regulators on Freescale MC13783 PMIC" diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 448e8f4cf41b..f53d31b950d4 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -89,6 +89,7 @@ int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, return mc13xxx_regulators[id].voltages[selector]; } +EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage); int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, int min_uV, int max_uV) @@ -123,6 +124,7 @@ int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, } return bestindex; } +EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index); static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) @@ -185,6 +187,7 @@ struct regulator_ops mc13xxx_regulator_ops = { .set_voltage = mc13xxx_regulator_set_voltage, .get_voltage = mc13xxx_regulator_get_voltage, }; +EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops); int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) @@ -202,6 +205,7 @@ int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, else return -EINVAL; } +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) { @@ -213,6 +217,7 @@ int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) return mc13xxx_regulators[id].voltages[0]; } +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage); struct regulator_ops mc13xxx_fixed_regulator_ops = { .enable = mc13xxx_regulator_enable, @@ -222,11 +227,13 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = { .set_voltage = mc13xxx_fixed_regulator_set_voltage, .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) { return 1; } +EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yong Shen "); -- cgit v1.2.3 From c24516a1d674b1d9d847fd736feca444bc249b12 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:06:51 +0000 Subject: regulator: Convert WM835x to use get_voltage_sel() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm8350-regulator.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7e45b0ddd710..1bcb22c44095 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -405,11 +405,10 @@ static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, return 0; } -static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev) +static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, dcdc = rdev_get_id(rdev); - u16 val; switch (dcdc) { case WM8350_DCDC_1: @@ -431,8 +430,7 @@ static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev) } /* all DCDCs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; - return wm8350_dcdc_val_to_mvolts(val) * 1000; + return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; } static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev, @@ -807,11 +805,10 @@ static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, return 0; } -static int wm8350_ldo_get_voltage(struct regulator_dev *rdev) +static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, ldo = rdev_get_id(rdev); - u16 val; switch (ldo) { case WM8350_LDO_1: @@ -831,8 +828,7 @@ static int wm8350_ldo_get_voltage(struct regulator_dev *rdev) } /* all LDOs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; - return wm8350_ldo_val_to_mvolts(val) * 1000; + return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; } static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, @@ -1229,7 +1225,7 @@ static int wm8350_ldo_is_enabled(struct regulator_dev *rdev) static struct regulator_ops wm8350_dcdc_ops = { .set_voltage = wm8350_dcdc_set_voltage, - .get_voltage = wm8350_dcdc_get_voltage, + .get_voltage_sel = wm8350_dcdc_get_voltage_sel, .list_voltage = wm8350_dcdc_list_voltage, .enable = wm8350_dcdc_enable, .disable = wm8350_dcdc_disable, @@ -1253,7 +1249,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = { static struct regulator_ops wm8350_ldo_ops = { .set_voltage = wm8350_ldo_set_voltage, - .get_voltage = wm8350_ldo_get_voltage, + .get_voltage_sel = wm8350_ldo_get_voltage_sel, .list_voltage = wm8350_ldo_list_voltage, .enable = wm8350_ldo_enable, .disable = wm8350_ldo_disable, -- cgit v1.2.3 From d9f0f287179f76ec71a50a96d553dfd1dbb41711 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:07:06 +0000 Subject: regulator: Convert WM8994 to use get_voltage_sel() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm8994-regulator.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 1b162e699368..594f88eb60c3 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -86,7 +86,7 @@ static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 2400000; } -static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) +static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int val; @@ -95,9 +95,7 @@ static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; - - return wm8994_ldo1_list_voltage(rdev, val); + return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; } static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, @@ -125,7 +123,7 @@ static struct regulator_ops wm8994_ldo1_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo1_list_voltage, - .get_voltage = wm8994_ldo1_get_voltage, + .get_voltage_sel = wm8994_ldo1_get_voltage_sel, .set_voltage = wm8994_ldo1_set_voltage, }; @@ -138,7 +136,7 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 900000; } -static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) +static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int val; @@ -147,9 +145,7 @@ static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; - - return wm8994_ldo2_list_voltage(rdev, val); + return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; } static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, @@ -177,7 +173,7 @@ static struct regulator_ops wm8994_ldo2_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo2_list_voltage, - .get_voltage = wm8994_ldo2_get_voltage, + .get_voltage_sel = wm8994_ldo2_get_voltage_sel, .set_voltage = wm8994_ldo2_set_voltage, }; -- cgit v1.2.3 From 757902513019e6ee469791ff76f954b19ca8d036 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:25:50 +0000 Subject: regulator: Factor out voltage set operation into a separate function Push all the callers of the chip set_voltage() operation out into a single function to facilitiate future refactoring. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 63 ++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b362dbde80f7..23c5f7c80bff 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -83,6 +83,8 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); +static int _regulator_do_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV); static const char *rdev_get_name(struct regulator_dev *rdev) { @@ -745,22 +747,19 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, { struct regulator_ops *ops = rdev->desc->ops; int ret; - unsigned selector; /* do we need to apply the constraint voltage */ if (rdev->constraints->apply_uV && - rdev->constraints->min_uV == rdev->constraints->max_uV && - ops->set_voltage) { - ret = ops->set_voltage(rdev, - rdev->constraints->min_uV, - rdev->constraints->max_uV, - &selector); - if (ret < 0) { - rdev_err(rdev, "failed to apply %duV constraint\n", - rdev->constraints->min_uV); - rdev->constraints = NULL; - return ret; - } + rdev->constraints->min_uV == rdev->constraints->max_uV) { + ret = _regulator_do_set_voltage(rdev, + rdev->constraints->min_uV, + rdev->constraints->max_uV); + if (ret < 0) { + rdev_err(rdev, "failed to apply %duV constraint\n", + rdev->constraints->min_uV); + rdev->constraints = NULL; + return ret; + } } /* constrain machine-level voltage specs to fit @@ -1621,6 +1620,32 @@ int regulator_is_supported_voltage(struct regulator *regulator, return 0; } +static int _regulator_do_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + unsigned int selector; + + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); + + if (rdev->desc->ops->set_voltage) { + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, + &selector); + + if (rdev->desc->ops->list_voltage) + selector = rdev->desc->ops->list_voltage(rdev, + selector); + else + selector = -1; + } else { + ret = -EINVAL; + } + + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + + return ret; +} + /** * regulator_set_voltage - set regulator output voltage * @regulator: regulator source @@ -1643,7 +1668,6 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret; - unsigned selector; mutex_lock(&rdev->mutex); @@ -1664,16 +1688,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) if (ret < 0) goto out; - trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); - - ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); - - if (rdev->desc->ops->list_voltage) - selector = rdev->desc->ops->list_voltage(rdev, selector); - else - selector = -1; - - trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); -- cgit v1.2.3 From e8eef82b2c652d031bee9dff9762325672f5a1e0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:36:17 +0000 Subject: regulator: Provide a selector based set_voltage_sel() operation Many regulator drivers implement voltage setting by looping through a table of possible values, normally because the set of available voltages can't be mapped onto selectors with simple calcuation. Factor out these loops by providing a variant of set_voltage() which takes a selector rather than a voltage range as an argument and implementing a loop through the available selectors in the core. This is not going to be suitable for use with all devices as when the regulator voltage can be mapped onto selector values with a simple calculation the linear scan through the available values will be more expensive than just doing the calculation, especially for regulators that provide fine grained voltage control. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 37 +++++++++++++++++++++++++++++++++++-- include/linux/regulator/driver.h | 3 +++ 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 23c5f7c80bff..a0579f069002 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1637,6 +1637,32 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, selector); else selector = -1; + } else if (rdev->desc->ops->set_voltage_sel) { + int best_val = INT_MAX; + int i; + + selector = 0; + + /* Find the smallest voltage that falls within the specified + * range. + */ + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret < best_val && ret >= min_uV && ret <= max_uV) { + best_val = ret; + selector = i; + } + } + + if (best_val != INT_MAX) { + ret = rdev->desc->ops->set_voltage_sel(rdev, selector); + selector = best_val; + } else { + ret = -EINVAL; + } } else { ret = -EINVAL; } @@ -1672,7 +1698,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) mutex_lock(&rdev->mutex); /* sanity check */ - if (!rdev->desc->ops->set_voltage) { + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { ret = -EINVAL; goto out; } @@ -2256,7 +2283,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; /* constraints need specific supporting methods */ - if (ops->set_voltage) { + if (ops->set_voltage || ops->set_voltage_sel) { status = device_create_file(dev, &dev_attr_min_microvolts); if (status < 0) return status; @@ -2354,12 +2381,18 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* Only one of each should be implemented */ WARN_ON(regulator_desc->ops->get_voltage && regulator_desc->ops->get_voltage_sel); + WARN_ON(regulator_desc->ops->set_voltage && + regulator_desc->ops->set_voltage_sel); /* If we're using selectors we must implement list_voltage. */ if (regulator_desc->ops->get_voltage_sel && !regulator_desc->ops->list_voltage) { return ERR_PTR(-EINVAL); } + if (regulator_desc->ops->set_voltage_sel && + !regulator_desc->ops->list_voltage) { + return ERR_PTR(-EINVAL); + } rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bf3e653591b9..975ae06cb634 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -42,6 +42,8 @@ enum regulator_status { * * @set_voltage: Set the voltage for the regulator within the range specified. * The driver should select the voltage closest to min_uV. + * @set_voltage_sel: Set the voltage for the regulator using the specified + * selector. * @get_voltage: Return the currently configured voltage for the regulator. * @get_voltage_sel: Return the currently configured voltage selector for the * regulator. @@ -83,6 +85,7 @@ struct regulator_ops { /* get/set regulator voltage */ int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector); + int (*set_voltage_sel) (struct regulator_dev *, unsigned selector); int (*get_voltage) (struct regulator_dev *); int (*get_voltage_sel) (struct regulator_dev *); -- cgit v1.2.3 From ded06a5270ddd6c3c3e25d9ddcaaaa4cb8385c2f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 13:59:10 +0000 Subject: regulator: Only notify voltage changes when they succeed Currently we notify a voltage change whenever we exit set_voltage(), even if the change failed for some reason (eg, a constraints issue). This shouldn't cause any substantial ill effects but is wasteful as listeners get notified on noops. Fix this by moving the notification into _do_set_voltage() and only notifying if we don't return an error. Reported-by: Saravana Kannan Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a0579f069002..3d72cc8e2f3e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1667,6 +1667,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, ret = -EINVAL; } + if (ret == 0) + _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, + NULL); + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); return ret; @@ -1718,7 +1722,6 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: - _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); mutex_unlock(&rdev->mutex); return ret; } -- cgit v1.2.3 From 27315cf61fb813b3916cecfbfa6932dc9447f3f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 15:29:56 +0000 Subject: regulator: Staticise non-exported functions in mc13892 No point exposing functions that aren't used elsewhere to the global namespace and sparse warns about doing so. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/mc13892-regulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index ca1d30adad99..16a053243f92 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -295,8 +295,8 @@ static struct mc13xxx_regulator mc13892_regulators[] = { MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), }; -int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, - u32 val) +static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) { struct mc13xxx *mc13892 = priv->mc13xxx; int ret; @@ -496,7 +496,7 @@ static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) return ret; } -unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) +static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) { struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); int ret, id = rdev_get_id(rdev); -- cgit v1.2.3 From 606a25628187ce863b48d43ca42bc0cbe8342de9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 15:49:36 +0000 Subject: regulator: Add API to re-apply voltage to hardware When cooperating with an external control source the regulator setup may be changed underneath the API. Currently consumers can just redo the regulator_set_voltage() to restore a previously set configuration but provide an explicit API for doing this as optimsations in the regulator_set_voltage() implementation will shortly prevent that. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 47 ++++++++++++++++++++++++++++++++++++++ include/linux/regulator/consumer.h | 1 + 2 files changed, 48 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 3d72cc8e2f3e..a12cba32460e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1727,6 +1727,53 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_voltage); +/** + * regulator_sync_voltage - re-apply last regulator output voltage + * @regulator: regulator source + * + * Re-apply the last configured voltage. This is intended to be used + * where some external control source the consumer is cooperating with + * has caused the configured voltage to change. + */ +int regulator_sync_voltage(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret, min_uV, max_uV; + + mutex_lock(&rdev->mutex); + + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { + ret = -EINVAL; + goto out; + } + + /* This is only going to work if we've had a voltage configured. */ + if (!regulator->min_uV && !regulator->max_uV) { + ret = -EINVAL; + goto out; + } + + min_uV = regulator->min_uV; + max_uV = regulator->max_uV; + + /* This should be a paranoia check... */ + ret = regulator_check_voltage(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = regulator_check_consumers(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); + +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_sync_voltage); + static int _regulator_get_voltage(struct regulator_dev *rdev) { int sel; diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index ebd747265294..7954f6bd7edb 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -154,6 +154,7 @@ int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV); int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); int regulator_get_voltage(struct regulator *regulator); +int regulator_sync_voltage(struct regulator *regulator); int regulator_set_current_limit(struct regulator *regulator, int min_uA, int max_uA); int regulator_get_current_limit(struct regulator *regulator); -- cgit v1.2.3 From 95a3c23ae620c1b4c499746e70f4034bdc067737 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 15:49:37 +0000 Subject: regulator: Optimise out noop voltage changes If a consumer sets the same voltage range as is currently configured for that consumer there's no need to run through setting the voltage again. This pattern may occur with some CPUfreq implementations where the same voltage range is used for multiple frequencies. Reported-by: Saravana Kannan Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a12cba32460e..ab419f8b2a84 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1697,10 +1697,17 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; - int ret; + int ret = 0; mutex_lock(&rdev->mutex); + /* If we're setting the same range as last time the change + * should be a noop (some cpufreq implementations use the same + * voltage for multiple frequencies, for example). + */ + if (regulator->min_uV == min_uV && regulator->max_uV == max_uV) + goto out; + /* sanity check */ if (!rdev->desc->ops->set_voltage && !rdev->desc->ops->set_voltage_sel) { -- cgit v1.2.3 From 13ce29f80fe3f61d3865b90244b1d1430f553e9f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 17 Dec 2010 16:04:12 +0000 Subject: regulator: Clean up logging a bit The recent introduction of standard regulator API logging macros means that all our log messages have at least the function name in them and logging that the constraints are for the regulator API is probably a bit much. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ab419f8b2a84..911b774c745c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -739,7 +739,7 @@ static void print_constraints(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += sprintf(buf + count, "standby"); - rdev_info(rdev, "regulator: %s\n", buf); + rdev_info(rdev, "%s\n", buf); } static int machine_constraints_voltage(struct regulator_dev *rdev, -- cgit v1.2.3 From 21cf891a47ff5e7bd77fdc524a25072c447d56bb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Dec 2010 23:30:07 +0000 Subject: regulator: Make regulator_has_full_constraints a bool It's a boolean value so use the type. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 911b774c745c..6066a8f2d5bb 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -44,7 +44,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); -static int has_full_constraints; +static bool has_full_constraints; static bool board_wants_dummy_regulator; /* -- cgit v1.2.3 From 1130e5b3ff4a7f3f54a48d46e9d0d81b47765bd8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Dec 2010 23:49:31 +0000 Subject: regulator: Add initial per-regulator debugfs support We only expose the use and open counts to userspace, providing a tiny bit of insight into what the API is up to. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 8 ++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6066a8f2d5bb..9fa20957847d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,10 @@ static LIST_HEAD(regulator_map_list); static bool has_full_constraints; static bool board_wants_dummy_regulator; +#ifdef CONFIG_DEBUG_FS +static struct dentry *debugfs_root; +#endif + /* * struct regulator_map * @@ -2404,6 +2409,23 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; } +static void rdev_init_debugfs(struct regulator_dev *rdev) +{ +#ifdef CONFIG_DEBUG_FS + rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); + if (IS_ERR(rdev->debugfs) || !rdev->debugfs) { + rdev_warn(rdev, "Failed to create debugfs directory\n"); + rdev->debugfs = NULL; + return; + } + + debugfs_create_u32("use_count", 0444, rdev->debugfs, + &rdev->use_count); + debugfs_create_u32("open_count", 0444, rdev->debugfs, + &rdev->open_count); +#endif +} + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -2548,6 +2570,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, } list_add(&rdev->list, ®ulator_list); + + rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); return rdev; @@ -2580,6 +2604,9 @@ void regulator_unregister(struct regulator_dev *rdev) return; mutex_lock(®ulator_list_mutex); +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(rdev->debugfs); +#endif WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); @@ -2723,6 +2750,14 @@ static int __init regulator_init(void) ret = class_register(®ulator_class); +#ifdef CONFIG_DEBUG_FS + debugfs_root = debugfs_create_dir("regulator", NULL); + if (IS_ERR(debugfs_root) || !debugfs_root) { + pr_warn("regulator: Failed to create debugfs directory\n"); + debugfs_root = NULL; + } +#endif + regulator_dummy_init(); return ret; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 975ae06cb634..b8ed16a33c47 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -175,9 +175,9 @@ struct regulator_desc { */ struct regulator_dev { struct regulator_desc *desc; - int use_count; - int open_count; int exclusive; + u32 use_count; + u32 open_count; /* lists we belong to */ struct list_head list; /* list of all regulators */ @@ -195,6 +195,10 @@ struct regulator_dev { struct regulator_dev *supply; /* for tree */ void *reg_data; /* regulator_dev data */ + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; +#endif }; struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, -- cgit v1.2.3 From 923430cfee112c5f8223a313f5ec148a27dfed7f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 3 Jan 2011 23:57:38 +0800 Subject: regulator: Assign return value of mc13xxx_reg_rmw to ret Otherwise, we will not return error if write to MC13892_SWITCHERS5 failed. Signed-off-by: Axel Lin Acked-by: Yong Shen Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/mc13892-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 16a053243f92..1b8f7398a4a8 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -550,7 +550,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) if (ret) goto err_free; - mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, + ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, MC13892_SWITCHERS5_SW3MODE_M | MC13892_SWITCHERS5_SW4MODE_M, MC13892_SWITCHERS5_SW3MODE_AUTO | -- cgit v1.2.3 From fa63bd4aa53aecc38956cbdd50f8ff9ed0d6d5ba Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 31 Dec 2010 16:26:47 +0100 Subject: regulator: missing index in PTR_ERR() in isl6271a_probe() The index is missing so the return is wrong. Signed-off-by: Roel Kluin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/isl6271a-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index b5639e82fcc7..e4b3592e8176 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -173,7 +173,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, init_data, pmic); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); - err = PTR_ERR(pmic->rdev); + err = PTR_ERR(pmic->rdev[i]); goto error; } } -- cgit v1.2.3 From 00f28e4037c8d5782fa7a1b2666b0dca21522d69 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 11 Jan 2011 11:50:28 +0000 Subject: xen-platform: use PCI interfaces to request IO and MEM resources. This is the correct interface to use and something has broken the use of the previous incorrect interface (which fails because the request conflicts with the resources assigned for the PCI device itself instead of nesting like the PCI interfaces do). Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk Cc: stable@kernel.org # 2.6.37 only --- drivers/xen/platform-pci.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index c01b5ddce529..afbe041f42c5 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -105,7 +105,7 @@ static int __devinit platform_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) { int i, ret; - long ioaddr, iolen; + long ioaddr; long mmio_addr, mmio_len; unsigned int max_nr_gframes; @@ -114,7 +114,6 @@ static int __devinit platform_pci_init(struct pci_dev *pdev, return i; ioaddr = pci_resource_start(pdev, 0); - iolen = pci_resource_len(pdev, 0); mmio_addr = pci_resource_start(pdev, 1); mmio_len = pci_resource_len(pdev, 1); @@ -125,19 +124,13 @@ static int __devinit platform_pci_init(struct pci_dev *pdev, goto pci_out; } - if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) { - dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n", - mmio_addr, mmio_len); - ret = -EBUSY; + ret = pci_request_region(pdev, 1, DRV_NAME); + if (ret < 0) goto pci_out; - } - if (request_region(ioaddr, iolen, DRV_NAME) == NULL) { - dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n", - iolen, ioaddr); - ret = -EBUSY; + ret = pci_request_region(pdev, 0, DRV_NAME); + if (ret < 0) goto mem_out; - } platform_mmio = mmio_addr; platform_mmiolen = mmio_len; @@ -169,9 +162,9 @@ static int __devinit platform_pci_init(struct pci_dev *pdev, return 0; out: - release_region(ioaddr, iolen); + pci_release_region(pdev, 0); mem_out: - release_mem_region(mmio_addr, mmio_len); + pci_release_region(pdev, 1); pci_out: pci_disable_device(pdev); return ret; -- cgit v1.2.3 From 7c8c06c5bb2dcc9fd0d2eeac4e9c10bf77ffed1a Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 11 Jan 2011 11:51:14 +0000 Subject: xen: rename platform-pci module to xen-platform-pci. platform-pci is rather generic for a modular distro style kernel. Signed-off-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 533a199e7a3f..f81819b0f916 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -11,9 +11,10 @@ obj-$(CONFIG_XEN_BALLOON) += balloon.o obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o obj-$(CONFIG_XENFS) += xenfs/ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o -obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o +obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_DOM0) += pci.o xen-evtchn-y := evtchn.o +xen-platform-pci-y := platform-pci.o -- cgit v1.2.3 From 106d1a0ab2a354b97df3e232be7dedbfaf8e901d Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 20 Dec 2010 12:11:45 +0100 Subject: ACPI: fix resource check message printk("%pR",...) is for formatting struct resource only. But the list built up in drivers/acpi/osl.c uses it's own struct: struct acpi_res_list {} Without this patch you can see wrongly formatted resources (SMRG is of IO type): ACPI: resource 0000:00:1f.3 [io 0x0400-0x041f] conflicts with AC PI region SMRG [mem 0x00000400-0x0000040f 64bit pref disabled] https://bugzilla.kernel.org/show_bug.cgi?id=26342 Signed-off-by: Thomas Renninger CC: Matthew Wilcox Signed-off-by: Len Brown --- drivers/acpi/osl.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 966feddf6b1b..6eaa13cdf767 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1192,8 +1192,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); int acpi_check_resource_conflict(const struct resource *res) { struct acpi_res_list *res_list_elem; - int ioport; - int clash = 0; + int ioport = 0, clash = 0; if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) return 0; @@ -1223,9 +1222,13 @@ int acpi_check_resource_conflict(const struct resource *res) if (clash) { if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { printk(KERN_WARNING "ACPI: resource %s %pR" - " conflicts with ACPI region %s %pR\n", + " conflicts with ACPI region %s " + "[%s 0x%zx-0x%zx]\n", res->name, res, res_list_elem->name, - res_list_elem); + (res_list_elem->resource_type == + ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", + (size_t) res_list_elem->start, + (size_t) res_list_elem->end); if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) printk(KERN_NOTICE "ACPI: This conflict may" " cause random problems and system" -- cgit v1.2.3 From c566d299f91bdb622046126dbcb040f9e52572ba Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 29 Dec 2010 19:12:01 +0000 Subject: olpc_battery: Ambient temperature is not available on XO-1.5 The XO-1.5 does not support the ambient temperature property. Create a separate list of properties for that configuration where ambient temperature is not included, and apply the correct property list at runtime. Signed-off-by: Daniel Drake Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 5bc1dcf7785e..0cd4f15e3013 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -331,7 +331,7 @@ static int olpc_bat_get_property(struct power_supply *psy, return ret; } -static enum power_supply_property olpc_bat_props[] = { +static enum power_supply_property olpc_xo1_bat_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_PRESENT, @@ -348,6 +348,23 @@ static enum power_supply_property olpc_bat_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, }; +/* XO-1.5 does not have ambient temperature property */ +static enum power_supply_property olpc_xo15_bat_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_SERIAL_NUMBER, + POWER_SUPPLY_PROP_CHARGE_COUNTER, +}; + /* EEPROM reading goes completely around the power_supply API, sadly */ #define EEPROM_START 0x20 @@ -419,8 +436,6 @@ static struct device_attribute olpc_bat_error = { static struct platform_device *bat_pdev; static struct power_supply olpc_bat = { - .properties = olpc_bat_props, - .num_properties = ARRAY_SIZE(olpc_bat_props), .get_property = olpc_bat_get_property, .use_for_apm = 1, }; @@ -466,6 +481,13 @@ static int __init olpc_bat_init(void) goto ac_failed; olpc_bat.name = bat_pdev->name; + if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */ + olpc_bat.properties = olpc_xo15_bat_props; + olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props); + } else { /* XO-1 */ + olpc_bat.properties = olpc_xo1_bat_props; + olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props); + } ret = power_supply_register(&bat_pdev->dev, &olpc_bat); if (ret) -- cgit v1.2.3 From b202a5e6c94d8c43ade5adb97e87734cc4f4f228 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Fri, 10 Dec 2010 23:05:19 +0100 Subject: olpc_battery: Add support for CHARGE_FULL_DESIGN Some user space software (read: UPower) uses CHARGE_FULL_DESIGN for internal calculations. The design capacity of the OLPC batteries is effectively fixed and only needs to be exported. Signed-off-by: Sascha Silbe Signed-off-by: Paul Fox Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 0cd4f15e3013..663b73023eaf 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -201,6 +201,54 @@ static int olpc_bat_get_tech(union power_supply_propval *val) return ret; } +static int olpc_bat_get_charge_full_design(union power_supply_propval *val) +{ + uint8_t ec_byte; + union power_supply_propval tech; + int ret, mfr; + + ret = olpc_bat_get_tech(&tech); + if (ret) + return ret; + + ec_byte = BAT_ADDR_MFR_TYPE; + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); + if (ret) + return ret; + + mfr = ec_byte >> 4; + + switch (tech.intval) { + case POWER_SUPPLY_TECHNOLOGY_NiMH: + switch (mfr) { + case 1: /* Gold Peak */ + val->intval = 3000000*.8; + break; + default: + return -EIO; + } + break; + + case POWER_SUPPLY_TECHNOLOGY_LiFe: + switch (mfr) { + case 1: /* Gold Peak */ + val->intval = 2800000; + break; + case 2: /* BYD */ + val->intval = 3100000; + break; + default: + return -EIO; + } + break; + + default: + return -EIO; + } + + return ret; +} + /********************************************************************* * Battery properties *********************************************************************/ @@ -294,6 +342,11 @@ static int olpc_bat_get_property(struct power_supply *psy, else val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret = olpc_bat_get_charge_full_design(val); + if (ret) + return ret; + break; case POWER_SUPPLY_PROP_TEMP: ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); if (ret) @@ -341,6 +394,7 @@ static enum power_supply_property olpc_xo1_bat_props[] = { POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TEMP_AMBIENT, POWER_SUPPLY_PROP_MANUFACTURER, -- cgit v1.2.3 From 20fd9830ccc685adce65ba89ffc3ca5426a2b064 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Fri, 10 Dec 2010 23:05:20 +0100 Subject: olpc_battery: Add support for CHARGE_NOW CHARGE_NOW is needed by some user space software (read: UPower) for internal calculations. This patch violates the power supply class definition (as we already do for CAPACITY though it isn't as obvious there), but this is the best we can do without adding rather sophisticated algorithms to either the EC or UPower. Signed-off-by: Sascha Silbe Signed-off-by: Paul Fox Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 663b73023eaf..0f7a7b11bda3 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -249,6 +249,24 @@ static int olpc_bat_get_charge_full_design(union power_supply_propval *val) return ret; } +static int olpc_bat_get_charge_now(union power_supply_propval *val) +{ + uint8_t soc; + union power_supply_propval full; + int ret; + + ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1); + if (ret) + return ret; + + ret = olpc_bat_get_charge_full_design(&full); + if (ret) + return ret; + + val->intval = soc * (full.intval / 100); + return 0; +} + /********************************************************************* * Battery properties *********************************************************************/ @@ -347,6 +365,11 @@ static int olpc_bat_get_property(struct power_supply *psy, if (ret) return ret; break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret = olpc_bat_get_charge_now(val); + if (ret) + return ret; + break; case POWER_SUPPLY_PROP_TEMP: ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); if (ret) @@ -395,6 +418,7 @@ static enum power_supply_property olpc_xo1_bat_props[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TEMP_AMBIENT, POWER_SUPPLY_PROP_MANUFACTURER, -- cgit v1.2.3 From 22fadd766b2a222b273df9f2264b72e4b3bbe921 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Fri, 10 Dec 2010 23:05:21 +0100 Subject: olpc_battery: Add support for CURRENT_NOW and VOLTAGE_NOW {CURRENT,VOLTAGE}_AVG are actually {CURRENT,VOLTAGE}_NOW (the EC code directly passes through the value from the gas gauge instead of the internally used average). We retain {CURRENT,VOLTAGE}_AVG as an alias for compatibility reasons, it will be removed later. Signed-off-by: Sascha Silbe [ pgf@laptop.org: added VOLTAGE_NOW, aliased to VOLTAGE_AVG ] Signed-off-by: Paul Fox Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 0f7a7b11bda3..64e40ff5c44a 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -333,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy, return ret; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: + case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); if (ret) return ret; @@ -340,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy, val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32; break; case POWER_SUPPLY_PROP_CURRENT_AVG: + case POWER_SUPPLY_PROP_CURRENT_NOW: ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); if (ret) return ret; @@ -414,7 +416,9 @@ static enum power_supply_property olpc_xo1_bat_props[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -- cgit v1.2.3 From ddbd550d503c9cdefcd6674a0ef168d57d3f0917 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 13 Dec 2010 18:28:22 -0500 Subject: intel_idle: update Sandy Bridge core C-state residency targets Signed-off-by: Len Brown --- drivers/idle/intel_idle.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index c131d58bcb50..94a652625ae2 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -122,7 +122,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, - .target_residency = 4, + .target_residency = 1, .enter = &intel_idle }, { /* MWAIT C2 */ .name = "SNB-C3", @@ -130,7 +130,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, - .target_residency = 160, + .target_residency = 211, .enter = &intel_idle }, { /* MWAIT C3 */ .name = "SNB-C6", @@ -138,7 +138,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 104, - .target_residency = 208, + .target_residency = 345, .enter = &intel_idle }, { /* MWAIT C4 */ .name = "SNB-C7", @@ -146,7 +146,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 109, - .target_residency = 300, + .target_residency = 345, .enter = &intel_idle }, }; -- cgit v1.2.3 From d8c216cfa57e8a579f41729cbb88c97835d9ac8d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 8 Jan 2011 00:29:20 +0100 Subject: cpuidle: Make cpuidle_enable_device() call poll_idle_init() The following scenario is possible with the current cpuidle code and the ACPI cpuidle driver: (1) acpi_processor_cst_has_changed() is called, (2) cpuidle_disable_device() is called, (3) cpuidle_remove_state_sysfs() is called to remove the (presumably outdated) states info from sysfs, (3) acpi_processor_get_power_info() is called, the first entry in the pr->power.states[] table is filled with zeros, (4) acpi_processor_setup_cpuidle() is called and it doesn't fill the first entry in pr->power.states[], (5) cpuidle_enable_device() is called, (6) __cpuidle_register_device() is _not_ called, since the device has already been registered, (7) Consequently, poll_idle_init() is _not_ called either, (8) cpuidle_add_state_sysfs() is called to create the sysfs attributes for the new states and it uses the bogus first table entry from acpi_processor_get_power_info() for creating state0. This problem is avoided if cpuidle_enable_device() unconditionally calls poll_idle_init(). Reported-by: Len Brown Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown cc: stable@kernel.org --- drivers/cpuidle/cpuidle.c | 82 +++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index a50710843378..97df791c74cb 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -154,6 +154,45 @@ void cpuidle_resume_and_unlock(void) EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); +#ifdef CONFIG_ARCH_HAS_CPU_RELAX +static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) +{ + ktime_t t1, t2; + s64 diff; + int ret; + + t1 = ktime_get(); + local_irq_enable(); + while (!need_resched()) + cpu_relax(); + + t2 = ktime_get(); + diff = ktime_to_us(ktime_sub(t2, t1)); + if (diff > INT_MAX) + diff = INT_MAX; + + ret = (int) diff; + return ret; +} + +static void poll_idle_init(struct cpuidle_device *dev) +{ + struct cpuidle_state *state = &dev->states[0]; + + cpuidle_set_statedata(state, NULL); + + snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); + snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); + state->exit_latency = 0; + state->target_residency = 0; + state->power_usage = -1; + state->flags = CPUIDLE_FLAG_POLL; + state->enter = poll_idle; +} +#else +static void poll_idle_init(struct cpuidle_device *dev) {} +#endif /* CONFIG_ARCH_HAS_CPU_RELAX */ + /** * cpuidle_enable_device - enables idle PM for a CPU * @dev: the CPU @@ -178,6 +217,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; } + poll_idle_init(dev); + if ((ret = cpuidle_add_state_sysfs(dev))) return ret; @@ -232,45 +273,6 @@ void cpuidle_disable_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_disable_device); -#ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) -{ - ktime_t t1, t2; - s64 diff; - int ret; - - t1 = ktime_get(); - local_irq_enable(); - while (!need_resched()) - cpu_relax(); - - t2 = ktime_get(); - diff = ktime_to_us(ktime_sub(t2, t1)); - if (diff > INT_MAX) - diff = INT_MAX; - - ret = (int) diff; - return ret; -} - -static void poll_idle_init(struct cpuidle_device *dev) -{ - struct cpuidle_state *state = &dev->states[0]; - - cpuidle_set_statedata(state, NULL); - - snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); - snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); - state->exit_latency = 0; - state->target_residency = 0; - state->power_usage = -1; - state->flags = CPUIDLE_FLAG_POLL; - state->enter = poll_idle; -} -#else -static void poll_idle_init(struct cpuidle_device *dev) {} -#endif /* CONFIG_ARCH_HAS_CPU_RELAX */ - /** * __cpuidle_register_device - internal register function called before register * and enable routines @@ -291,8 +293,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) init_completion(&dev->kobj_unregister); - poll_idle_init(dev); - /* * cpuidle driver should set the dev->power_specified bit * before registering the device if the driver provides -- cgit v1.2.3 From d18960494f65ca4fa0d67c865aaca99452070d15 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 3 Nov 2010 17:06:14 +0100 Subject: ACPI, intel_idle: Cleanup idle= internal variables Having four variables for the same thing: idle_halt, idle_nomwait, force_mwait and boot_option_idle_overrides is rather confusing and unnecessary complex. if idle= boot param is passed, only set up one variable: boot_option_idle_overrides Introduces following functional changes/fixes: - intel_idle driver does not register if any idle=xy boot param is passed. - processor_idle.c will also not register a cpuidle driver and get active if idle=halt is passed. Before a cpuidle driver with one (C1, halt) state got registered Now the default_idle function will be used which finally uses the same idle call to enter sleep state (safe_halt()), but without registering a whole cpuidle driver. That means idle= param will always avoid cpuidle drivers to register with one exception (same behavior as before): idle=nomwait may still register acpi_idle cpuidle driver, but C1 will not use mwait, but hlt. This can be a workaround for IO based deeper sleep states where C1 mwait causes problems. Signed-off-by: Thomas Renninger cc: x86@kernel.org Signed-off-by: Len Brown --- arch/ia64/include/asm/processor.h | 5 +++-- arch/ia64/kernel/process.c | 6 +----- arch/x86/include/asm/processor.h | 5 +++-- arch/x86/kernel/process.c | 24 ++++++++---------------- drivers/acpi/processor_core.c | 4 ++-- drivers/acpi/processor_idle.c | 24 +++++++++++------------- drivers/idle/intel_idle.c | 4 ++++ 7 files changed, 32 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index 348e44d08ce3..03afe7970748 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h @@ -717,8 +717,9 @@ prefetchw (const void *x) #define spin_lock_prefetch(x) prefetchw(x) extern unsigned long boot_option_idle_override; -extern unsigned long idle_halt; -extern unsigned long idle_nomwait; + +enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT, + IDLE_NOMWAIT, IDLE_POLL}; #endif /* !__ASSEMBLY__ */ diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 16f1c7b04c69..6d33c5cc94f0 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -53,12 +53,8 @@ void (*ia64_mark_idle)(int); -unsigned long boot_option_idle_override = 0; +unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; EXPORT_SYMBOL(boot_option_idle_override); -unsigned long idle_halt; -EXPORT_SYMBOL(idle_halt); -unsigned long idle_nomwait; -EXPORT_SYMBOL(idle_nomwait); void (*pm_idle) (void); EXPORT_SYMBOL(pm_idle); void (*pm_power_off) (void); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index cae9c3cb95cf..b79bd980461c 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -762,10 +762,11 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c); extern void init_c1e_mask(void); extern unsigned long boot_option_idle_override; -extern unsigned long idle_halt; -extern unsigned long idle_nomwait; extern bool c1e_detected; +enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT, + IDLE_POLL, IDLE_FORCE_MWAIT}; + extern void enable_sep_cpu(void); extern int sysenter_setup(void); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 57d1868a86aa..b6472153e45b 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -22,11 +22,6 @@ #include #include -unsigned long idle_halt; -EXPORT_SYMBOL(idle_halt); -unsigned long idle_nomwait; -EXPORT_SYMBOL(idle_nomwait); - struct kmem_cache *task_xstate_cachep; EXPORT_SYMBOL_GPL(task_xstate_cachep); @@ -328,7 +323,7 @@ long sys_execve(const char __user *name, /* * Idle related variables and functions */ -unsigned long boot_option_idle_override = 0; +unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; EXPORT_SYMBOL(boot_option_idle_override); /* @@ -499,7 +494,6 @@ static void poll_idle(void) * * idle=mwait overrides this decision and forces the usage of mwait. */ -static int __cpuinitdata force_mwait; #define MWAIT_INFO 0x05 #define MWAIT_ECX_EXTENDED_INFO 0x01 @@ -509,7 +503,7 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) { u32 eax, ebx, ecx, edx; - if (force_mwait) + if (boot_option_idle_override == IDLE_FORCE_MWAIT) return 1; if (c->cpuid_level < MWAIT_INFO) @@ -629,9 +623,10 @@ static int __init idle_setup(char *str) if (!strcmp(str, "poll")) { printk("using polling idle threads.\n"); pm_idle = poll_idle; - } else if (!strcmp(str, "mwait")) - force_mwait = 1; - else if (!strcmp(str, "halt")) { + boot_option_idle_override = IDLE_POLL; + } else if (!strcmp(str, "mwait")) { + boot_option_idle_override = IDLE_FORCE_MWAIT; + } else if (!strcmp(str, "halt")) { /* * When the boot option of idle=halt is added, halt is * forced to be used for CPU idle. In such case CPU C2/C3 @@ -640,8 +635,7 @@ static int __init idle_setup(char *str) * the boot_option_idle_override. */ pm_idle = default_idle; - idle_halt = 1; - return 0; + boot_option_idle_override = IDLE_HALT; } else if (!strcmp(str, "nomwait")) { /* * If the boot option of "idle=nomwait" is added, @@ -649,12 +643,10 @@ static int __init idle_setup(char *str) * states. In such case it won't touch the variable * of boot_option_idle_override. */ - idle_nomwait = 1; - return 0; + boot_option_idle_override = IDLE_NOMWAIT; } else return -1; - boot_option_idle_override = 1; return 0; } early_param("idle", idle_setup); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index bec561c14beb..3c1a2fec8cda 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -23,7 +23,7 @@ static int set_no_mwait(const struct dmi_system_id *id) { printk(KERN_NOTICE PREFIX "%s detected - " "disabling mwait for CPU C-states\n", id->ident); - idle_nomwait = 1; + boot_option_idle_override = IDLE_NOMWAIT; return 0; } @@ -283,7 +283,7 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) { acpi_status status = AE_OK; - if (idle_nomwait) { + if (boot_option_idle_override == IDLE_NOMWAIT) { /* * If mwait is disabled for CPU C-states, the C2C3_FFH access * mode will be disabled in the parameter of _PDC object. diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index dcb38f8ddfda..eefd4aa0e71d 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -79,6 +79,13 @@ module_param(bm_check_disable, uint, 0000); static unsigned int latency_factor __read_mostly = 2; module_param(latency_factor, uint, 0644); +static int disabled_by_idle_boot_param(void) +{ + return boot_option_idle_override == IDLE_POLL || + boot_option_idle_override == IDLE_FORCE_MWAIT || + boot_option_idle_override == IDLE_HALT; +} + /* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * For now disable this. Probably a bug somewhere else. @@ -455,7 +462,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) continue; } if (cx.type == ACPI_STATE_C1 && - (idle_halt || idle_nomwait)) { + (boot_option_idle_override == IDLE_NOMWAIT)) { /* * In most cases the C1 space_id obtained from * _CST object is FIXED_HARDWARE access mode. @@ -1058,7 +1065,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) { int ret = 0; - if (boot_option_idle_override) + if (disabled_by_idle_boot_param()) return 0; if (!pr) @@ -1089,19 +1096,10 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, acpi_status status = 0; static int first_run; - if (boot_option_idle_override) + if (disabled_by_idle_boot_param()) return 0; if (!first_run) { - if (idle_halt) { - /* - * When the boot option of "idle=halt" is added, halt - * is used for CPU IDLE. - * In such case C2/C3 is meaningless. So the max_cstate - * is set to one. - */ - max_cstate = 1; - } dmi_check_system(processor_power_dmi_table); max_cstate = acpi_processor_cstate_check(max_cstate); if (max_cstate < ACPI_C_STATES_MAX) @@ -1142,7 +1140,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device) { - if (boot_option_idle_override) + if (disabled_by_idle_boot_param()) return 0; cpuidle_unregister_device(&pr->power.dev); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 94a652625ae2..21d387132dbc 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -404,6 +404,10 @@ static int __init intel_idle_init(void) { int retval; + /* Do not load intel_idle at all for now if idle= is passed */ + if (boot_option_idle_override != IDLE_NO_OVERRIDE) + return -ENODEV; + retval = intel_idle_probe(); if (retval) return retval; -- cgit v1.2.3 From 720f1c3010db6a411358b962a2007969117840bc Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 7 Jan 2011 11:29:43 +0100 Subject: cpuidle: Rename X86 specific idle poll state[0] from C0 to POLL C0 means and is well know as "not idle". All documentation out there uses this term as "running"/"not idle" state. Also Linux userspace tools (e.g. cpufreq-aperf and turbostat) show C0 residency which there is correct, but means something totally else than cpuidle "POLL" state. Signed-off-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 97df791c74cb..37e446041306 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -181,7 +181,7 @@ static void poll_idle_init(struct cpuidle_device *dev) cpuidle_set_statedata(state, NULL); - snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); + snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); state->exit_latency = 0; state->target_residency = 0; -- cgit v1.2.3 From 0aae9f923bcc476a8e4725dd3ac37547b9816ee5 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 12 Jan 2011 02:22:56 -0500 Subject: ACPI: processor_idle: delete use of NOP CPUIDLE_FLAGs CPUIDLE_FLAG_SHALLOW CPUIDLE_FLAG_BALANCED CPUIDLE_FLAG_DEEP CPUIDLE_FLAG_CHECK_BM were set by acpi_processor_setup_cpuidle(), but never used by cpuidle or by acpi_idle. So stop setting them. Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index eefd4aa0e71d..70599d2ada61 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1023,7 +1023,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) state->flags = 0; switch (cx->type) { case ACPI_STATE_C1: - state->flags |= CPUIDLE_FLAG_SHALLOW; if (cx->entry_method == ACPI_CSTATE_FFH) state->flags |= CPUIDLE_FLAG_TIME_VALID; @@ -1032,16 +1031,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) break; case ACPI_STATE_C2: - state->flags |= CPUIDLE_FLAG_BALANCED; state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_simple; dev->safe_state = state; break; case ACPI_STATE_C3: - state->flags |= CPUIDLE_FLAG_DEEP; state->flags |= CPUIDLE_FLAG_TIME_VALID; - state->flags |= CPUIDLE_FLAG_CHECK_BM; state->enter = pr->flags.bm_check ? acpi_idle_enter_bm : acpi_idle_enter_simple; -- cgit v1.2.3 From d247632c08c674864d438733280422ddb7130ff8 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 12 Jan 2011 02:34:59 -0500 Subject: cpuidle: delete NOP CPUIDLE_FLAG_POLL it serves no purpose Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 2 +- include/linux/cpuidle.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 37e446041306..dd5f1eafd6f2 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -186,7 +186,7 @@ static void poll_idle_init(struct cpuidle_device *dev) state->exit_latency = 0; state->target_residency = 0; state->power_usage = -1; - state->flags = CPUIDLE_FLAG_POLL; + state->flags = 0; state->enter = poll_idle; } #else diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 1be416bbbb82..dee32853b0da 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -48,7 +48,6 @@ struct cpuidle_state { /* Idle State Flags */ #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ #define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */ -#define CPUIDLE_FLAG_POLL (0x10) /* no latency, no savings */ #define CPUIDLE_FLAG_SHALLOW (0x20) /* low latency, minimal savings */ #define CPUIDLE_FLAG_BALANCED (0x40) /* medium latency, moderate savings */ #define CPUIDLE_FLAG_DEEP (0x80) /* high latency, large savings */ -- cgit v1.2.3 From 956d033fb2eb3f8818260cdf01644bf4dc1a9e33 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 12 Jan 2011 02:51:20 -0500 Subject: cpuidle: CPUIDLE_FLAG_TLB_FLUSHED is specific to intel_idle Signed-off-by: Len Brown --- drivers/idle/intel_idle.c | 8 ++++++++ include/linux/cpuidle.h | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 21d387132dbc..8256309deaad 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -81,6 +81,14 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); static struct cpuidle_state *cpuidle_state_table; +/* + * Set this flag for states where the HW flushes the TLB for us + * and so we don't need cross-calls to keep it consistent. + * If this flag is set, SW flushes the TLB, so even if the + * HW doesn't do the flushing, this flag is safe to use. + */ +#define CPUIDLE_FLAG_TLB_FLUSHED 0x10000 + /* * States are indexed by the cstate number, * which is also the index into the MWAIT hint array. diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index c25295337382..6be722c725d5 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -49,7 +49,6 @@ struct cpuidle_state { #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ #define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */ #define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */ -#define CPUIDLE_FLAG_TLB_FLUSHED (0x200) /* tlb will be flushed */ #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) -- cgit v1.2.3 From 2a2d31c8dc6f1ebcf5eab1d93a0cb0fb4ed57c7c Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 10 Jan 2011 09:38:12 +0800 Subject: intel_idle: open broadcast clock event Intel_idle driver uses CLOCK_EVT_NOTIFY_BROADCAST_ENTER CLOCK_EVT_NOTIFY_BROADCAST_EXIT for broadcast clock events. The _ENTER/_EXIT doesn't really open broadcast clock events, please see processor_idle.c for an example. In some situation, this will cause boot hang, because some CPUs enters idle but local APIC timer stalls. Reported-and-tested-by: Yan Zheng Signed-off-by: Shaohua Li cc: stable@kernel.org Signed-off-by: Len Brown --- drivers/idle/intel_idle.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 8256309deaad..fc393586cc70 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -59,6 +59,8 @@ #include /* ktime_get_real() */ #include #include +#include +#include #include #define INTEL_IDLE_VERSION "0.4" @@ -73,6 +75,7 @@ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1; static unsigned int mwait_substates; +#define LAPIC_TIMER_ALWAYS_RELIABLE 0xFFFFFFFF /* Reliable LAPIC Timer States, bit 1 for C1 etc. */ static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ @@ -252,6 +255,39 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) return usec_delta; } +static void __setup_broadcast_timer(void *arg) +{ + unsigned long reason = (unsigned long)arg; + int cpu = smp_processor_id(); + + reason = reason ? + CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; + + clockevents_notify(reason, &cpu); +} + +static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n, + unsigned long action, void *hcpu) +{ + int hotcpu = (unsigned long)hcpu; + + switch (action & 0xf) { + case CPU_ONLINE: + smp_call_function_single(hotcpu, __setup_broadcast_timer, + (void *)true, 1); + break; + case CPU_DOWN_PREPARE: + smp_call_function_single(hotcpu, __setup_broadcast_timer, + (void *)false, 1); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata setup_broadcast_notifier = { + .notifier_call = setup_broadcast_cpuhp_notify, +}; + /* * intel_idle_probe() */ @@ -314,7 +350,11 @@ static int intel_idle_probe(void) } if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ - lapic_timer_reliable_states = 0xFFFFFFFF; + lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; + else { + smp_call_function(__setup_broadcast_timer, (void *)true, 1); + register_cpu_notifier(&setup_broadcast_notifier); + } pr_debug(PREFIX "v" INTEL_IDLE_VERSION " model 0x%X\n", boot_cpu_data.x86_model); @@ -441,6 +481,11 @@ static void __exit intel_idle_exit(void) intel_idle_cpuidle_devices_uninit(); cpuidle_unregister_driver(&intel_idle_driver); + if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) { + smp_call_function(__setup_broadcast_timer, (void *)false, 1); + unregister_cpu_notifier(&setup_broadcast_notifier); + } + return; } -- cgit v1.2.3 From 4979d18fe105297f8f065743f31f8f735da8df2d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 12 Jan 2011 09:50:36 -0800 Subject: mlx4_{core, ib, en}: Fix driver when sizeof (phys_addr_t) > sizeof (long) Some systems have PCI addresses that don't fit in unsigned long (eg some 32-bit PowerPC 440 systems have 36-bit bus addresses). Fix up mlx4 drivers by using phys_addr_t where appropriate, so we don't truncate any PCI resource addresses before ioremapping them. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 3 ++- drivers/net/mlx4/catas.c | 6 +++--- drivers/net/mlx4/en_main.c | 3 ++- drivers/net/mlx4/main.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 4c85224aeaa7..d68d849ab866 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1005,7 +1005,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) if (mlx4_uar_alloc(dev, &ibdev->priv_uar)) goto err_pd; - ibdev->uar_map = ioremap(ibdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT, + PAGE_SIZE); if (!ibdev->uar_map) goto err_uar; MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock); diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c index 68aaa42d0ced..32f947154c33 100644 --- a/drivers/net/mlx4/catas.c +++ b/drivers/net/mlx4/catas.c @@ -113,7 +113,7 @@ static void catas_reset(struct work_struct *work) void mlx4_start_catas_poll(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - unsigned long addr; + phys_addr_t addr; INIT_LIST_HEAD(&priv->catas_err.list); init_timer(&priv->catas_err.timer); @@ -124,8 +124,8 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev) priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); if (!priv->catas_err.map) { - mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n", - addr); + mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", + (unsigned long long) addr); return; } diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index f6e0d40cd876..1ff6ca6466ed 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -202,7 +202,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev) if (mlx4_uar_alloc(dev, &mdev->priv_uar)) goto err_pd; - mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT, + PAGE_SIZE); if (!mdev->uar_map) goto err_uar; spin_lock_init(&mdev->uar_lock); diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 782f11d8fa71..4ffdc18fcb8a 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -829,7 +829,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) goto err_uar_table_free; } - priv->kar = ioremap(priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + priv->kar = ioremap((phys_addr_t) priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); if (!priv->kar) { mlx4_err(dev, "Couldn't map kernel access region, " "aborting.\n"); -- cgit v1.2.3 From e528db5b392ab2a624258a667fed0e65af6e411b Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 12 Jan 2011 12:58:06 -0500 Subject: xen-platform: Fix compile errors if CONFIG_PCI is not enabled. drivers/xen/platform-pci.c:127: error: implicit declaration of function 'pci_request_region' drivers/xen/platform-pci.c:165: error: implicit declaration of function 'pci_release_region' Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 6e6180ccd726..6f52b3189803 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -64,7 +64,7 @@ config XEN_SYS_HYPERVISOR config XEN_PLATFORM_PCI tristate "xen platform pci device driver" - depends on XEN_PVHVM + depends on XEN_PVHVM && PCI default m help Driver for the Xen PCI Platform device: it is responsible for -- cgit v1.2.3 From 948579cd8c6ea7c8c98c52b79f4470952e182ebd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 5 Nov 2010 03:07:36 +0000 Subject: RDMA: Use vzalloc() to replace vmalloc()+memset(0) Signed-off-by: Joe Perches Signed-off-by: Roland Dreier --- drivers/infiniband/hw/amso1100/c2_rnic.c | 5 ++--- drivers/infiniband/hw/ehca/ipz_pt_fn.c | 5 ++--- drivers/infiniband/hw/ipath/ipath_driver.c | 3 +-- drivers/infiniband/hw/ipath/ipath_file_ops.c | 11 +++-------- drivers/infiniband/hw/ipath/ipath_init_chip.c | 5 +---- drivers/infiniband/hw/qib/qib_init.c | 7 ++----- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 10 +++------- drivers/infiniband/ulp/ipoib/ipoib_main.c | 3 +-- 8 files changed, 15 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c index 85cfae4cad71..8c81992fa6db 100644 --- a/drivers/infiniband/hw/amso1100/c2_rnic.c +++ b/drivers/infiniband/hw/amso1100/c2_rnic.c @@ -459,13 +459,12 @@ int __devinit c2_rnic_init(struct c2_dev *c2dev) IB_DEVICE_MEM_WINDOW); /* Allocate the qptr_array */ - c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *)); + c2dev->qptr_array = vzalloc(C2_MAX_CQS * sizeof(void *)); if (!c2dev->qptr_array) { return -ENOMEM; } - /* Inialize the qptr_array */ - memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *)); + /* Initialize the qptr_array */ c2dev->qptr_array[0] = (void *) &c2dev->req_vq; c2dev->qptr_array[1] = (void *) &c2dev->rep_vq; c2dev->qptr_array[2] = (void *) &c2dev->aeq; diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index 1596e3085344..1898d6e7cce5 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c @@ -222,15 +222,14 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue, queue->small_page = NULL; /* allocate queue page pointers */ - queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL); + queue->queue_pages = kzalloc(nr_of_pages * sizeof(void *), GFP_KERNEL); if (!queue->queue_pages) { - queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); + queue->queue_pages = vzalloc(nr_of_pages * sizeof(void *)); if (!queue->queue_pages) { ehca_gen_err("Couldn't allocate queue page list"); return 0; } } - memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); /* allocate actual queue pages */ if (is_small) { diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index b33f0457a1ff..ae92da2d3f56 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -199,12 +199,11 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev) goto bail; } - dd = vmalloc(sizeof(*dd)); + dd = vzalloc(sizeof(*dd)); if (!dd) { dd = ERR_PTR(-ENOMEM); goto bail; } - memset(dd, 0, sizeof(*dd)); dd->ipath_unit = -1; spin_lock_irqsave(&ipath_devs_lock, flags); diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 9292a15ad7c4..6d4b29c4cd89 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1530,7 +1530,7 @@ static int init_subports(struct ipath_devdata *dd, } num_subports = uinfo->spu_subport_cnt; - pd->subport_uregbase = vmalloc(PAGE_SIZE * num_subports); + pd->subport_uregbase = vzalloc(PAGE_SIZE * num_subports); if (!pd->subport_uregbase) { ret = -ENOMEM; goto bail; @@ -1538,13 +1538,13 @@ static int init_subports(struct ipath_devdata *dd, /* Note: pd->port_rcvhdrq_size isn't initialized yet. */ size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize * sizeof(u32), PAGE_SIZE) * num_subports; - pd->subport_rcvhdr_base = vmalloc(size); + pd->subport_rcvhdr_base = vzalloc(size); if (!pd->subport_rcvhdr_base) { ret = -ENOMEM; goto bail_ureg; } - pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks * + pd->subport_rcvegrbuf = vzalloc(pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size * num_subports); if (!pd->subport_rcvegrbuf) { @@ -1556,11 +1556,6 @@ static int init_subports(struct ipath_devdata *dd, pd->port_subport_id = uinfo->spu_subport_id; pd->active_slaves = 1; set_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag); - memset(pd->subport_uregbase, 0, PAGE_SIZE * num_subports); - memset(pd->subport_rcvhdr_base, 0, size); - memset(pd->subport_rcvegrbuf, 0, pd->port_rcvegrbuf_chunks * - pd->port_rcvegrbuf_size * - num_subports); goto bail; bail_rhdr: diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 776938299e4c..fef0f4201257 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -442,7 +442,7 @@ static void init_shadow_tids(struct ipath_devdata *dd) struct page **pages; dma_addr_t *addrs; - pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt * + pages = vzalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt * sizeof(struct page *)); if (!pages) { ipath_dev_err(dd, "failed to allocate shadow page * " @@ -461,9 +461,6 @@ static void init_shadow_tids(struct ipath_devdata *dd) return; } - memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt * - sizeof(struct page *)); - dd->ipath_pageshadow = pages; dd->ipath_physshadow = addrs; } diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 7896afbb9ce8..304bd8038541 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -270,23 +270,20 @@ static void init_shadow_tids(struct qib_devdata *dd) struct page **pages; dma_addr_t *addrs; - pages = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); + pages = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); if (!pages) { qib_dev_err(dd, "failed to allocate shadow page * " "array, no expected sends!\n"); goto bail; } - addrs = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); + addrs = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); if (!addrs) { qib_dev_err(dd, "failed to allocate shadow dma handle " "array, no expected sends!\n"); goto bail_free; } - memset(pages, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); - memset(addrs, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); - dd->pageshadow = pages; dd->physshadow = addrs; return; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index c1c49f2d35b5..93d55806b967 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -352,15 +352,13 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i int ret; int i; - rx->rx_ring = vmalloc(ipoib_recvq_size * sizeof *rx->rx_ring); + rx->rx_ring = vzalloc(ipoib_recvq_size * sizeof *rx->rx_ring); if (!rx->rx_ring) { printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n", priv->ca->name, ipoib_recvq_size); return -ENOMEM; } - memset(rx->rx_ring, 0, ipoib_recvq_size * sizeof *rx->rx_ring); - t = kmalloc(sizeof *t, GFP_KERNEL); if (!t) { ret = -ENOMEM; @@ -1097,13 +1095,12 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, struct ipoib_dev_priv *priv = netdev_priv(p->dev); int ret; - p->tx_ring = vmalloc(ipoib_sendq_size * sizeof *p->tx_ring); + p->tx_ring = vzalloc(ipoib_sendq_size * sizeof *p->tx_ring); if (!p->tx_ring) { ipoib_warn(priv, "failed to allocate tx ring\n"); ret = -ENOMEM; goto err_tx; } - memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring); p->qp = ipoib_cm_create_tx_qp(p->dev, p); if (IS_ERR(p->qp)) { @@ -1521,7 +1518,7 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) return; } - priv->cm.srq_ring = vmalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); + priv->cm.srq_ring = vzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); if (!priv->cm.srq_ring) { printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", priv->ca->name, ipoib_recvq_size); @@ -1530,7 +1527,6 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) return; } - memset(priv->cm.srq_ring, 0, ipoib_recvq_size * sizeof *priv->cm.srq_ring); } int ipoib_cm_dev_init(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 7a07a728fe0d..aca3b44f7aed 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -916,13 +916,12 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out; } - priv->tx_ring = vmalloc(ipoib_sendq_size * sizeof *priv->tx_ring); + priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring); if (!priv->tx_ring) { printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", ca->name, ipoib_sendq_size); goto out_rx_ring_cleanup; } - memset(priv->tx_ring, 0, ipoib_sendq_size * sizeof *priv->tx_ring); /* priv->tx_head, tx_tail & tx_outstanding are already 0 */ -- cgit v1.2.3 From 833bcb00c478c674fda0aaea089c1a92abd2da01 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Jan 2011 12:14:13 +0000 Subject: drm/i915/debugfs: Correct format after changing type of err object 'size' Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 19a3d58044dd..3601466c5502 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -703,7 +703,7 @@ static void print_error_buffers(struct seq_file *m, seq_printf(m, "%s [%d]:\n", name, count); while (count--) { - seq_printf(m, " %08x %8zd %04x %04x %08x%s%s%s%s%s%s", + seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s", err->gtt_offset, err->size, err->read_domains, -- cgit v1.2.3 From c8303e7f3f3093c16ef0fa5f73280637c89d4368 Mon Sep 17 00:00:00 2001 From: Indan Zupancic Date: Wed, 12 Jan 2011 11:59:19 +0000 Subject: drm/i915/panel: The backlight is enabled if the current value is non-zero ... and not if the maximum is non-zero. This fixes the typo introduced in 47356eb6728501452 and preserves the backlight value from boot. [ickle: My thanks also to Indan Zupancic for diagnosing the original regression and suggesting the appropriate fix.] Signed-off-by: Chris Wilson Cc: stable@kernel.org # after 47356eb6728501452 --- drivers/gpu/drm/i915/intel_panel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e00d200df3db..c65992df458d 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -278,6 +278,6 @@ void intel_panel_setup_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->backlight_level = intel_panel_get_max_backlight(dev); + dev_priv->backlight_level = intel_panel_get_backlight(dev); dev_priv->backlight_enabled = dev_priv->backlight_level != 0; } -- cgit v1.2.3 From 5d84291da3a594ac391c85296e28f41ff92da0cf Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Wed, 12 Jan 2011 21:55:08 +0100 Subject: hwmon: (ads7828) Update email contact details Trivial patch updating my email contact details due to change of employer, and because I no longer have access to the previously used domain. Unfortunately I also no longer have access to any ads7828 hardware, but am happy to support/maintain the driver if others are able to test changes. Signed-off-by: Steve Hardy Signed-off-by: Jean Delvare --- Documentation/hwmon/ads7828 | 2 +- drivers/hwmon/ads7828.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/ads7828 b/Documentation/hwmon/ads7828 index 75bc4beaf447..2bbebe6f771f 100644 --- a/Documentation/hwmon/ads7828 +++ b/Documentation/hwmon/ads7828 @@ -9,7 +9,7 @@ Supported chips: http://focus.ti.com/lit/ds/symlink/ads7828.pdf Authors: - Steve Hardy + Steve Hardy Module Parameters ----------------- diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index aac85f3aed50..c42c5a69a664 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -4,7 +4,7 @@ This driver is based on the lm75 and other lm_sensors/hwmon drivers - Written by Steve Hardy + Written by Steve Hardy Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf @@ -271,7 +271,7 @@ static void __exit sensors_ads7828_exit(void) i2c_del_driver(&ads7828_driver); } -MODULE_AUTHOR("Steve Hardy "); +MODULE_AUTHOR("Steve Hardy "); MODULE_DESCRIPTION("ADS7828 driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 014bcd28a04ec085940ea3125f5ea91b16a1945d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:09 +0100 Subject: hwmon: (w83795) Silent false warning from gcc The code triggers a false warning with older versions of gcc: w83795.c: In function 'w83795_update_device': w83795.c:475: warning: 'lsb' may be used uninitialized in this function I admit that the code is a little tricky, but I see no way to write it differently without hurting performance. So let's just silent the warning with a needless initialization. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83795.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index cdbc7448491e..845232d7f611 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -458,6 +458,7 @@ static void w83795_update_limits(struct i2c_client *client) { struct w83795_data *data = i2c_get_clientdata(client); int i, limit; + u8 lsb; /* Read the voltage limits */ for (i = 0; i < ARRAY_SIZE(data->in); i++) { @@ -479,9 +480,8 @@ static void w83795_update_limits(struct i2c_client *client) } /* Read the fan limits */ + lsb = 0; /* Silent false gcc warning */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { - u8 lsb; - /* Each register contains LSB for 2 fans, but we want to * read it only once to save time */ if ((i & 1) == 0 && (data->has_fan & (3 << i))) -- cgit v1.2.3 From f790674d3f87df6390828ac21a7d1530f71b59c8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:09 +0100 Subject: hwmon: (via686a) Initialize fan_div values Functions set_fan_min() and set_fan_div() assume that the fan_div values have already been read from the register. The driver currently doesn't initialize them at load time, they are only set when function via686a_update_device() is called. This means that set_fan_min() and set_fan_div() misbehave if, for example, "sensors -s" is called before any monitoring application (e.g. "sensors") is has been run. Fix the problem by always initializing the fan_div values at device bind time. Signed-off-by: Jean Delvare Cc: stable@kernel.org Acked-by: Guenter Roeck --- drivers/hwmon/via686a.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 13e8d218e495..25e91665a0a2 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -689,6 +689,13 @@ static int __devexit via686a_remove(struct platform_device *pdev) return 0; } +static void via686a_update_fan_div(struct via686a_data *data) +{ + int reg = via686a_read_value(data, VIA686A_REG_FANDIV); + data->fan_div[0] = (reg >> 4) & 0x03; + data->fan_div[1] = reg >> 6; +} + static void __devinit via686a_init_device(struct via686a_data *data) { u8 reg; @@ -702,6 +709,9 @@ static void __devinit via686a_init_device(struct via686a_data *data) via686a_write_value(data, VIA686A_REG_TEMP_MODE, (reg & ~VIA686A_TEMP_MODE_MASK) | VIA686A_TEMP_MODE_CONTINUOUS); + + /* Pre-read fan clock divisor values */ + via686a_update_fan_div(data); } static struct via686a_data *via686a_update_device(struct device *dev) @@ -753,9 +763,7 @@ static struct via686a_data *via686a_update_device(struct device *dev) (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & 0xc0) >> 6; - i = via686a_read_value(data, VIA686A_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; + via686a_update_fan_div(data); data->alarms = via686a_read_value(data, VIA686A_REG_ALARM1) | -- cgit v1.2.3 From 0de2b244800b2c0d88d0a85bbe4a0b95fee13332 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:09 +0100 Subject: hwmon: (adm9240) Implement the standard intrusion detection interface We have a standard intrusion detection interface now, drivers should implement it. I've left the old interface in place for the time being, with a deprecation warning, it will be removed later. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- Documentation/hwmon/adm9240 | 2 +- drivers/hwmon/adm9240.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/adm9240 b/Documentation/hwmon/adm9240 index 2c6f1fed4618..36e8ec6aa868 100644 --- a/Documentation/hwmon/adm9240 +++ b/Documentation/hwmon/adm9240 @@ -155,7 +155,7 @@ connected to a normally open switch. The ADM9240 provides an internal open drain on this line, and may output a 20 ms active low pulse to reset an external Chassis Intrusion latch. -Clear the CI latch by writing value 1 to the sysfs chassis_clear file. +Clear the CI latch by writing value 0 to the sysfs intrusion0_alarm file. Alarm flags reported as 16-bit word diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 0727ad250793..9e234b981b83 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -20,7 +20,7 @@ * Alarms 16-bit map of active alarms * Analog Out 0..1250 mV output * - * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' + * Chassis Intrusion: clear CI latch with 'echo 0 > intrusion0_alarm' * * Test hardware: Intel SE440BX-2 desktop motherboard --Grant * @@ -476,13 +476,16 @@ static ssize_t set_aout(struct device *dev, static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); /* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, +static ssize_t chassis_clear_legacy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); unsigned long val = simple_strtol(buf, NULL, 10); + dev_warn(dev, "Attribute chassis_clear is deprecated, " + "use intrusion0_alarm instead\n"); + if (val == 1) { i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); @@ -490,7 +493,29 @@ static ssize_t chassis_clear(struct device *dev, } return count; } -static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); +static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear_legacy); + +static ssize_t chassis_clear(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + data->valid = 0; /* Force cache refresh */ + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + + return count; +} +static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, show_alarm, + chassis_clear, 12); static struct attribute *adm9240_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, @@ -532,6 +557,7 @@ static struct attribute *adm9240_attributes[] = { &dev_attr_alarms.attr, &dev_attr_aout_output.attr, &dev_attr_chassis_clear.attr, + &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, &dev_attr_cpu0_vid.attr, NULL }; -- cgit v1.2.3 From c32301b5957bb77579eb80ff5a84324d34b97346 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:09 +0100 Subject: hwmon: (w83792d) Implement the standard intrusion detection interface We have a standard intrusion detection interface now, drivers should implement it. I've left the old interface in place for the time being, with a deprecation warning, it will be removed later. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/w83792d.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 679718e6b017..63841f8cec07 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -691,13 +691,23 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, } static ssize_t -show_regs_chassis(struct device *dev, struct device_attribute *attr, +show_chassis(struct device *dev, struct device_attribute *attr, char *buf) { struct w83792d_data *data = w83792d_update_device(dev); return sprintf(buf, "%d\n", data->chassis); } +static ssize_t +show_regs_chassis(struct device *dev, struct device_attribute *attr, + char *buf) +{ + dev_warn(dev, + "Attribute %s is deprecated, use intrusion0_alarm instead\n", + "chassis"); + return show_chassis(dev, attr, buf); +} + static ssize_t show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf) { @@ -706,7 +716,7 @@ show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -store_chassis_clear(struct device *dev, struct device_attribute *attr, +store_chassis_clear_legacy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -714,6 +724,10 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr, u32 val; u8 temp1 = 0, temp2 = 0; + dev_warn(dev, + "Attribute %s is deprecated, use intrusion0_alarm instead\n", + "chassis_clear"); + val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->chassis_clear = SENSORS_LIMIT(val, 0 ,1); @@ -726,6 +740,27 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t +store_chassis_clear(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83792d_data *data = i2c_get_clientdata(client); + unsigned long val; + u8 reg; + + if (strict_strtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + reg = w83792d_read_value(client, W83792D_REG_CHASSIS_CLR); + w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, reg | 0x80); + data->valid = 0; /* Force cache refresh */ + mutex_unlock(&data->update_lock); + + return count; +} + /* For Smart Fan I / Thermal Cruise */ static ssize_t show_thermal_cruise(struct device *dev, struct device_attribute *attr, @@ -1012,7 +1047,9 @@ static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22); static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23); static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, - show_chassis_clear, store_chassis_clear); + show_chassis_clear, store_chassis_clear_legacy); +static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, + show_chassis, store_chassis_clear); static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0); static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2); @@ -1214,6 +1251,7 @@ static struct attribute *w83792d_attributes[] = { &dev_attr_alarms.attr, &dev_attr_chassis.attr, &dev_attr_chassis_clear.attr, + &dev_attr_intrusion0_alarm.attr, &sensor_dev_attr_tolerance1.dev_attr.attr, &sensor_dev_attr_thermal_cruise1.dev_attr.attr, &sensor_dev_attr_tolerance2.dev_attr.attr, -- cgit v1.2.3 From a516dc3e9b19adbcaa9aeda0100ee8ee2938748a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:10 +0100 Subject: hwmon: (w83793) Implement the standard intrusion detection interface We have a standard intrusion detection interface now, drivers should implement it. I've left the old interface in place for the time being, with a deprecation warning, it will be removed later. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- Documentation/hwmon/w83793 | 2 +- drivers/hwmon/w83793.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/w83793 b/Documentation/hwmon/w83793 index 51171a83165b..6cc5f639b721 100644 --- a/Documentation/hwmon/w83793 +++ b/Documentation/hwmon/w83793 @@ -92,7 +92,7 @@ This driver implements support for Winbond W83793G/W83793R chips. * Chassis If the case open alarm triggers, it will stay in this state unless cleared - by any write to the sysfs file "chassis". + by writing 0 to the sysfs file "intrusion0_alarm". * VID and VRM The VRM version is detected automatically, don't modify the it unless you diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 8e540ada47d2..d0c30124c13b 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -421,14 +421,17 @@ store_beep_enable(struct device *dev, struct device_attribute *attr, /* Write any value to clear chassis alarm */ static ssize_t -store_chassis_clear(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +store_chassis_clear_legacy(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); u8 val; + dev_warn(dev, "Attribute chassis is deprecated, " + "use intrusion0_alarm instead\n"); + mutex_lock(&data->update_lock); val = w83793_read_value(client, W83793_REG_CLR_CHASSIS); val |= 0x80; @@ -437,6 +440,28 @@ store_chassis_clear(struct device *dev, return count; } +/* Write 0 to clear chassis alarm */ +static ssize_t +store_chassis_clear(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83793_data *data = i2c_get_clientdata(client); + unsigned long val; + u8 reg; + + if (strict_strtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + reg = w83793_read_value(client, W83793_REG_CLR_CHASSIS); + w83793_write_value(client, W83793_REG_CLR_CHASSIS, reg | 0x80); + data->valid = 0; /* Force cache refresh */ + mutex_unlock(&data->update_lock); + return count; +} + #define FAN_INPUT 0 #define FAN_MIN 1 static ssize_t @@ -1102,6 +1127,8 @@ static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm); static struct sensor_device_attribute_2 sda_single_files[] = { SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, + store_chassis_clear_legacy, ALARM_STATUS, 30), + SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, store_chassis_clear, ALARM_STATUS, 30), SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, store_beep_enable, NOT_USED, NOT_USED), -- cgit v1.2.3 From a8ca103793350bd66280d56ee58870c682b54e75 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 21:55:10 +0100 Subject: hwmon: (it87) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/hwmon/it87.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index a428a9264195..316b64823f7b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -38,6 +38,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1570,26 +1572,25 @@ static int __init it87_find(unsigned short *address, case 0xffff: /* No device at all */ goto exit; default: - pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n", - chip_type); + pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type); goto exit; } superio_select(PME); if (!(superio_inb(IT87_ACT_REG) & 0x01)) { - pr_info("it87: Device not activated, skipping\n"); + pr_info("Device not activated, skipping\n"); goto exit; } *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); if (*address == 0) { - pr_info("it87: Base address not set, skipping\n"); + pr_info("Base address not set, skipping\n"); goto exit; } err = 0; sio_data->revision = superio_inb(DEVREV) & 0x0f; - pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", + pr_info("Found IT%04xF chip at 0x%x, revision %d\n", chip_type, *address, sio_data->revision); /* in8 (Vbat) is always internal */ @@ -1615,7 +1616,7 @@ static int __init it87_find(unsigned short *address, } else { /* We need at least 4 VID pins */ if (reg & 0x0f) { - pr_info("it87: VID is disabled (pins used for GPIO)\n"); + pr_info("VID is disabled (pins used for GPIO)\n"); sio_data->skip_vid = 1; } } @@ -1651,7 +1652,7 @@ static int __init it87_find(unsigned short *address, if (sio_data->type == it8720 && !(reg & (1 << 1))) { reg |= (1 << 1); superio_outb(IT87_SIO_PINX2_REG, reg); - pr_notice("it87: Routing internal VCCH to in7\n"); + pr_notice("Routing internal VCCH to in7\n"); } if (reg & (1 << 0)) sio_data->internal |= (1 << 0); @@ -1661,7 +1662,7 @@ static int __init it87_find(unsigned short *address, sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; } if (sio_data->beep_pin) - pr_info("it87: Beeping is supported\n"); + pr_info("Beeping is supported\n"); /* Disable specific features based on DMI strings */ board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); @@ -1675,8 +1676,7 @@ static int __init it87_find(unsigned short *address, the PWM2 duty cycle, so we disable it. I use the board name string as the trigger in case the same board is ever used in other systems. */ - pr_info("it87: Disabling pwm2 due to " - "hardware constraints\n"); + pr_info("Disabling pwm2 due to hardware constraints\n"); sio_data->skip_pwm = (1 << 1); } } @@ -2189,28 +2189,26 @@ static int __init it87_device_add(unsigned short address, pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct it87_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From ce47da742ddd950197c29df6f9f89cf8adb5a0a1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 21:55:10 +0100 Subject: hwmon: (lm78) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/hwmon/lm78.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 72ff2c4e757d..4cb24eafe318 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -19,6 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -858,7 +860,7 @@ static int __init lm78_isa_found(unsigned short address) * individually for the probing phase. */ for (port = address; port < address + LM78_EXTENT; port++) { if (!request_region(port, 1, "lm78")) { - pr_debug("lm78: Failed to request port 0x%x\n", port); + pr_debug("Failed to request port 0x%x\n", port); goto release; } } @@ -920,7 +922,7 @@ static int __init lm78_isa_found(unsigned short address) found = 1; if (found) - pr_info("lm78: Found an %s chip at %#x\n", + pr_info("Found an %s chip at %#x\n", val & 0x80 ? "LM79" : "LM78", (int)address); release: @@ -942,21 +944,19 @@ static int __init lm78_isa_device_add(unsigned short address) pdev = platform_device_alloc("lm78", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "lm78: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "lm78: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "lm78: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From 9e991c6fad4618a9158437f1f650225f9ec485c3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 21:55:11 +0100 Subject: hwmon: (pc87360) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats [JD: Also convert debug messages] Signed-off-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/hwmon/pc87360.c | 53 +++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 68e69a49633c..3d99b8854d7c 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -33,6 +33,8 @@ * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1031,16 +1033,15 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses val = superio_inb(sioaddr, ACT); if (!(val & 0x01)) { - printk(KERN_INFO "pc87360: Device 0x%02x not " - "activated\n", logdev[i]); + pr_info("Device 0x%02x not activated\n", logdev[i]); continue; } val = (superio_inb(sioaddr, BASE) << 8) | superio_inb(sioaddr, BASE + 1); if (!val) { - printk(KERN_INFO "pc87360: Base address not set for " - "device 0x%02x\n", logdev[i]); + pr_info("Base address not set for device 0x%02x\n", + logdev[i]); continue; } @@ -1050,17 +1051,15 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses confreg[0] = superio_inb(sioaddr, 0xF0); confreg[1] = superio_inb(sioaddr, 0xF1); -#ifdef DEBUG - printk(KERN_DEBUG "pc87360: Fan 1: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, - (confreg[0]>>3)&1, (confreg[0]>>4)&1); - printk(KERN_DEBUG "pc87360: Fan 2: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, - (confreg[0]>>6)&1, (confreg[0]>>7)&1); - printk(KERN_DEBUG "pc87360: Fan 3: mon=%d " - "ctrl=%d inv=%d\n", confreg[1]&1, - (confreg[1]>>1)&1, (confreg[1]>>2)&1); -#endif + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1, + (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1, + (confreg[0] >> 4) & 1); + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2, + (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1, + (confreg[0] >> 7) & 1); + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3, + confreg[1] & 1, (confreg[1] >> 1) & 1, + (confreg[1] >> 2) & 1); } else if (i==1) { /* Voltages */ /* Are we using thermistors? */ if (*devid == 0xE9) { /* PC87366 */ @@ -1071,14 +1070,12 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses confreg[3] = superio_inb(sioaddr, 0x25); if (confreg[2] & 0x40) { - printk(KERN_INFO "pc87360: Using " - "thermistors for temperature " - "monitoring\n"); + pr_info("Using thermistors for " + "temperature monitoring\n"); } if (confreg[3] & 0xE0) { - printk(KERN_INFO "pc87360: VID " - "inputs routed (mode %u)\n", - confreg[3] >> 5); + pr_info("VID inputs routed (mode %u)\n", + confreg[3] >> 5); } } } @@ -1616,7 +1613,7 @@ static int __init pc87360_device_add(unsigned short address) pdev = platform_device_alloc("pc87360", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "pc87360: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } @@ -1639,15 +1636,13 @@ static int __init pc87360_device_add(unsigned short address) err = platform_device_add_resources(pdev, res, res_count); if (err) { - printk(KERN_ERR "pc87360: Device resources addition failed " - "(%d)\n", err); + pr_err("Device resources addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "pc87360: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } @@ -1666,8 +1661,7 @@ static int __init pc87360_init(void) if (pc87360_find(0x2e, &devid, extra_isa) && pc87360_find(0x4e, &devid, extra_isa)) { - printk(KERN_WARNING "pc87360: PC8736x not detected, " - "module not inserted.\n"); + pr_warn("PC8736x not detected, module not inserted\n"); return -ENODEV; } @@ -1680,8 +1674,7 @@ static int __init pc87360_init(void) } if (address == 0x0000) { - printk(KERN_WARNING "pc87360: No active logical device, " - "module not inserted.\n"); + pr_warn("No active logical device, module not inserted\n"); return -ENODEV; } -- cgit v1.2.3 From 5e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 21:55:11 +0100 Subject: hwmon: (pc87427) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats Signed-off-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/hwmon/pc87427.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 9ec4daaf6ca6..8da2181630b1 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -22,6 +22,8 @@ * mode, and voltages aren't supported at all. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1077,7 +1079,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev) data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL); if (!data) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Out of memory\n"); + pr_err("Out of memory\n"); goto exit; } @@ -1196,28 +1198,26 @@ static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) pdev = platform_device_alloc(DRVNAME, res[0].start); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, res, res_count); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct pc87427_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } @@ -1249,23 +1249,23 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data) val = superio_inb(sioaddr, SIOREG_ACT); if (!(val & 0x01)) { - printk(KERN_INFO DRVNAME ": Logical device 0x%02x " - "not activated\n", logdev[i]); + pr_info("Logical device 0x%02x not activated\n", + logdev[i]); continue; } val = superio_inb(sioaddr, SIOREG_MAP); if (val & 0x01) { - printk(KERN_WARNING DRVNAME ": Logical device 0x%02x " - "is memory-mapped, can't use\n", logdev[i]); + pr_warn("Logical device 0x%02x is memory-mapped, " + "can't use\n", logdev[i]); continue; } val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8) | superio_inb(sioaddr, SIOREG_IOBASE + 1); if (!val) { - printk(KERN_INFO DRVNAME ": I/O base address not set " - "for logical device 0x%02x\n", logdev[i]); + pr_info("I/O base address not set for logical device " + "0x%02x\n", logdev[i]); continue; } sio_data->address[i] = val; -- cgit v1.2.3 From 1ca28218eb57143d9ae6298f10c8a193696458a8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 21:55:11 +0100 Subject: hwmon: (w83781d) Use pr_fmt and pr_ Added #define pr_fmt KBUILD_MODNAME ": " fmt Converted printks to pr_ Coalesced any long formats Removed prefixes from formats [JD: Optimize repeated debug messages] Signed-off-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/hwmon/w83781d.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index c84b9b4e6960..eed43a008be1 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -33,6 +33,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1798,8 +1800,7 @@ w83781d_isa_found(unsigned short address) * individually for the probing phase. */ for (port = address; port < address + W83781D_EXTENT; port++) { if (!request_region(port, 1, "w83781d")) { - pr_debug("w83781d: Failed to request port 0x%x\n", - port); + pr_debug("Failed to request port 0x%x\n", port); goto release; } } @@ -1811,7 +1812,7 @@ w83781d_isa_found(unsigned short address) if (inb_p(address + 2) != val || inb_p(address + 3) != val || inb_p(address + 7) != val) { - pr_debug("w83781d: Detection failed at step 1\n"); + pr_debug("Detection failed at step %d\n", 1); goto release; } #undef REALLY_SLOW_IO @@ -1820,14 +1821,14 @@ w83781d_isa_found(unsigned short address) MSB (busy flag) should be clear initially, set after the write. */ save = inb_p(address + W83781D_ADDR_REG_OFFSET); if (save & 0x80) { - pr_debug("w83781d: Detection failed at step 2\n"); + pr_debug("Detection failed at step %d\n", 2); goto release; } val = ~save & 0x7f; outb_p(val, address + W83781D_ADDR_REG_OFFSET); if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) { outb_p(save, address + W83781D_ADDR_REG_OFFSET); - pr_debug("w83781d: Detection failed at step 3\n"); + pr_debug("Detection failed at step %d\n", 3); goto release; } @@ -1835,7 +1836,7 @@ w83781d_isa_found(unsigned short address) outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET); val = inb_p(address + W83781D_DATA_REG_OFFSET); if (val & 0x80) { - pr_debug("w83781d: Detection failed at step 4\n"); + pr_debug("Detection failed at step %d\n", 4); goto release; } outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET); @@ -1844,19 +1845,19 @@ w83781d_isa_found(unsigned short address) val = inb_p(address + W83781D_DATA_REG_OFFSET); if ((!(save & 0x80) && (val != 0xa3)) || ((save & 0x80) && (val != 0x5c))) { - pr_debug("w83781d: Detection failed at step 5\n"); + pr_debug("Detection failed at step %d\n", 5); goto release; } outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET); val = inb_p(address + W83781D_DATA_REG_OFFSET); if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */ - pr_debug("w83781d: Detection failed at step 6\n"); + pr_debug("Detection failed at step %d\n", 6); goto release; } /* The busy flag should be clear again */ if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) { - pr_debug("w83781d: Detection failed at step 7\n"); + pr_debug("Detection failed at step %d\n", 7); goto release; } @@ -1871,7 +1872,7 @@ w83781d_isa_found(unsigned short address) found = 1; if (found) - pr_info("w83781d: Found a %s chip at %#x\n", + pr_info("Found a %s chip at %#x\n", val == 0x30 ? "W83782D" : "W83781D", (int)address); release: @@ -1894,21 +1895,19 @@ w83781d_isa_device_add(unsigned short address) pdev = platform_device_alloc("w83781d", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "w83781d: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "w83781d: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "w83781d: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } -- cgit v1.2.3 From 1b7243e8f51157103dcca33236163a191c8afd01 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:11 +0100 Subject: hwmon: (fschmd) Drop useless mutex As discussed one year ago, the WDIOC_GETSUPPORT ioctl only needs a mutex because it operates on a static variable. There is no good reason to keep this variable static, so let's just make it non-static and drop the now useless mutex altogether. See the discussion at: http://marc.info/?l=lm-sensors&m=125563869402323&w=2 Signed-off-by: Jean Delvare Cc: Hans de Goede Acked-by: Guenter Roeck Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner --- drivers/hwmon/fschmd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index d4d4ca65d371..aa6d8b686f82 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -49,7 +49,6 @@ #include /* Addresses to scan */ -static DEFINE_MUTEX(watchdog_mutex); static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; /* Insmod parameters */ @@ -850,7 +849,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf, static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - static struct watchdog_info ident = { + struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_CARDRESET, .identity = "FSC watchdog" @@ -858,7 +857,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar int i, ret = 0; struct fschmd_data *data = filp->private_data; - mutex_lock(&watchdog_mutex); switch (cmd) { case WDIOC_GETSUPPORT: ident.firmware_version = data->revision; @@ -915,7 +913,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar default: ret = -ENOTTY; } - mutex_unlock(&watchdog_mutex); return ret; } -- cgit v1.2.3 From 36c7fe133e29a0b2558edaef18b2401e99765417 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 12 Jan 2011 21:55:11 +0100 Subject: hwmon: (w83793) Drop useless mutex This is the same case as fschmd, from which the code was copied as far as I can see. So the same clean-up applies: The WDIOC_GETSUPPORT ioctl only needs a mutex because it operates on a static variable. There is no good reason to keep this variable static, so let's just make it non-static and drop the now useless mutex altogether. See the discussion at: http://marc.info/?l=lm-sensors&m=125563869402323&w=2 Signed-off-by: Jean Delvare Cc: Hans de Goede Acked-by: Guenter Roeck Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner --- drivers/hwmon/w83793.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index d0c30124c13b..e3bdedfb5347 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -51,7 +51,6 @@ #define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */ /* Addresses to scan */ -static DEFINE_MUTEX(watchdog_mutex); static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; @@ -1350,7 +1349,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf, static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - static struct watchdog_info ident = { + struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_CARDRESET, @@ -1360,7 +1359,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, int val, ret = 0; struct w83793_data *data = filp->private_data; - mutex_lock(&watchdog_mutex); switch (cmd) { case WDIOC_GETSUPPORT: if (!nowayout) @@ -1414,7 +1412,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, default: ret = -ENOTTY; } - mutex_unlock(&watchdog_mutex); return ret; } -- cgit v1.2.3 From 7a1b76f2a46016809c7bcacf81e89948cc306703 Mon Sep 17 00:00:00 2001 From: Jekyll Lai Date: Wed, 12 Jan 2011 21:55:12 +0100 Subject: hwmon: (emc1403) Add EMC1423 support EMC1423 uses the similar register and adds a hardware shutdown pin to protect exceed temperature. This function is set by resistor; it's not necessary to do anything in the driver except add the emc1423 pid of 0x23. Signed-off-by: Jekyll Lai [Updated Kconfig/comments and minor further changes asked for by the hwmon maintainers] Signed-off-by: Alan Cox [Fixed checkpatch warning] Signed-of--by: Jean Delvare --- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/emc1403.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index bdc13d28b1ea..35f00dae3676 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -809,10 +809,10 @@ config SENSORS_DME1737 will be called dme1737. config SENSORS_EMC1403 - tristate "SMSC EMC1403 thermal sensor" + tristate "SMSC EMC1403/23 thermal sensor" depends on I2C help - If you say yes here you get support for the SMSC EMC1403 + If you say yes here you get support for the SMSC EMC1403/23 temperature monitoring chip. Threshold values can be configured using sysfs. diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 8dee3f38fdfb..5dea9faa1656 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -269,23 +269,30 @@ static int emc1403_detect(struct i2c_client *client, struct i2c_board_info *info) { int id; - /* Check if thermal chip is SMSC and EMC1403 */ + /* Check if thermal chip is SMSC and EMC1403 or EMC1423 */ id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG); if (id != 0x5d) return -ENODEV; + id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); + switch (id) { + case 0x21: + strlcpy(info->type, "emc1403", I2C_NAME_SIZE); + break; + case 0x23: + strlcpy(info->type, "emc1423", I2C_NAME_SIZE); + break; /* Note: 0x25 is the 1404 which is very similar and this driver could be extended */ - id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); - if (id != 0x21) + default: return -ENODEV; + } id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG); if (id != 0x01) return -ENODEV; - strlcpy(info->type, "emc1403", I2C_NAME_SIZE); return 0; } @@ -342,6 +349,7 @@ static const unsigned short emc1403_address_list[] = { static const struct i2c_device_id emc1403_idtable[] = { { "emc1403", 0 }, + { "emc1423", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, emc1403_idtable); -- cgit v1.2.3 From d4b94e1fa6c69fd74abca5b7db1ab350d65ce89b Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Wed, 12 Jan 2011 21:55:13 +0100 Subject: hwmon: (dme1737) Add support for in7 for SCH5127 Add support for the 1.5V voltage monitoring input (in7) of the SMSC SCH5127 chip. Signed-off-by: Juerg Haefliger Signed-off-by: Jean Delvare --- Documentation/hwmon/dme1737 | 12 ++++---- drivers/hwmon/dme1737.c | 68 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/dme1737 b/Documentation/hwmon/dme1737 index fc5df7654d63..4d2935145a1c 100644 --- a/Documentation/hwmon/dme1737 +++ b/Documentation/hwmon/dme1737 @@ -42,7 +42,7 @@ Description This driver implements support for the hardware monitoring capabilities of the SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, SCH311x, and SCH5127 Super-I/O chips. These chips feature monitoring of 3 temp sensors -temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and +temp[1-3] (2 remote diodes and 1 internal), 8 voltages in[0-7] (7 external and 1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and automatically. @@ -105,6 +105,7 @@ SCH5127: in4: V1_IN 0V - 1.5V in5: VTR (+3.3V standby) 0V - 4.38V in6: Vbat (+3.0V) 0V - 4.38V + in7: Vtrip (+1.5V) 0V - 1.99V Each voltage input has associated min and max limits which trigger an alarm when crossed. @@ -217,10 +218,10 @@ cpu0_vid RO CPU core reference voltage in vrm RW Voltage regulator module version number. -in[0-6]_input RO Measured voltage in millivolts. -in[0-6]_min RW Low limit for voltage input. -in[0-6]_max RW High limit for voltage input. -in[0-6]_alarm RO Voltage input alarm. Returns 1 if +in[0-7]_input RO Measured voltage in millivolts. +in[0-7]_min RW Low limit for voltage input. +in[0-7]_max RW High limit for voltage input. +in[0-7]_alarm RO Voltage input alarm. Returns 1 if voltage input is or went outside the associated min-max range, 0 otherwise. @@ -324,3 +325,4 @@ fan5 opt opt pwm5 opt opt fan6 opt opt pwm6 opt opt +in7 yes diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index e9a610bfd0cc..ec683eabd7ac 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -77,12 +77,14 @@ enum chips { dme1737, sch5027, sch311x, sch5127 }; * in4 +12V * in5 VTR (+3.3V stby) * in6 Vbat + * in7 Vtrip (sch5127 only) * * --------------------------------------------------------------------- */ -/* Voltages (in) numbered 0-6 (ix) */ -#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) \ - : 0x94 + (ix)) +/* Voltages (in) numbered 0-7 (ix) */ +#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) : \ + (ix) < 7 ? 0x94 + (ix) : \ + 0x1f) #define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \ : 0x91 + (ix) * 2) #define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \ @@ -101,10 +103,11 @@ enum chips { dme1737, sch5027, sch311x, sch5127 }; * IN_TEMP_LSB(1) = [temp3, temp1] * IN_TEMP_LSB(2) = [in4, temp2] * IN_TEMP_LSB(3) = [in3, in0] - * IN_TEMP_LSB(4) = [in2, in1] */ + * IN_TEMP_LSB(4) = [in2, in1] + * IN_TEMP_LSB(5) = [res, in7] */ #define DME1737_REG_IN_TEMP_LSB(ix) (0x84 + (ix)) -static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0}; -static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4}; +static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5}; +static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4}; static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1}; static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0}; @@ -145,7 +148,7 @@ static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0}; #define DME1737_REG_ALARM1 0x41 #define DME1737_REG_ALARM2 0x42 #define DME1737_REG_ALARM3 0x83 -static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17}; +static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17, 18}; static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6}; static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; @@ -190,6 +193,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; #define HAS_PWM_MIN (1 << 4) /* bit 4 */ #define HAS_FAN(ix) (1 << ((ix) + 5)) /* bits 5-10 */ #define HAS_PWM(ix) (1 << ((ix) + 11)) /* bits 11-16 */ +#define HAS_IN7 (1 << 17) /* bit 17 */ /* --------------------------------------------------------------------- * Data structures and manipulation thereof @@ -213,9 +217,9 @@ struct dme1737_data { u32 has_features; /* Register values */ - u16 in[7]; - u8 in_min[7]; - u8 in_max[7]; + u16 in[8]; + u8 in_min[8]; + u8 in_max[8]; s16 temp[3]; s8 temp_min[3]; s8 temp_max[3]; @@ -247,7 +251,7 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300, 3300}; static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300, - 3300}; + 3300, 1500}; #define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \ (type) == sch5027 ? IN_NOMINAL_SCH5027 : \ (type) == sch5127 ? IN_NOMINAL_SCH5127 : \ @@ -580,7 +584,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) { struct dme1737_data *data = dev_get_drvdata(dev); int ix; - u8 lsb[5]; + u8 lsb[6]; mutex_lock(&data->update_lock); @@ -603,6 +607,9 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* Voltage inputs are stored as 16 bit values even * though they have only 12 bits resolution. This is * to make it consistent with the temp inputs. */ + if (ix == 7 && !(data->has_features & HAS_IN7)) { + continue; + } data->in[ix] = dme1737_read(data, DME1737_REG_IN(ix)) << 8; data->in_min[ix] = dme1737_read(data, @@ -635,10 +642,16 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) * which the registers are read (MSB first, then LSB) is * important! */ for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) { + if (ix == 5 && !(data->has_features & HAS_IN7)) { + continue; + } lsb[ix] = dme1737_read(data, DME1737_REG_IN_TEMP_LSB(ix)); } for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { + if (ix == 7 && !(data->has_features & HAS_IN7)) { + continue; + } data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] << DME1737_REG_IN_LSB_SHL[ix]) & 0xf0; } @@ -762,7 +775,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* --------------------------------------------------------------------- * Voltage sysfs attributes - * ix = [0-5] + * ix = [0-7] * --------------------------------------------------------------------- */ #define SYS_IN_INPUT 0 @@ -1439,7 +1452,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, * Sysfs device attribute defines and structs * --------------------------------------------------------------------- */ -/* Voltages 0-6 */ +/* Voltages 0-7 */ #define SENSOR_DEVICE_ATTR_IN(ix) \ static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \ @@ -1458,6 +1471,7 @@ SENSOR_DEVICE_ATTR_IN(3); SENSOR_DEVICE_ATTR_IN(4); SENSOR_DEVICE_ATTR_IN(5); SENSOR_DEVICE_ATTR_IN(6); +SENSOR_DEVICE_ATTR_IN(7); /* Temperatures 1-3 */ @@ -1695,6 +1709,21 @@ static const struct attribute_group dme1737_zone_hyst_group = { .attrs = dme1737_zone_hyst_attr, }; +/* The following struct holds voltage in7 related attributes, which + * are not available in all chips. The following chips support them: + * SCH5127 */ +static struct attribute *dme1737_in7_attr[] = { + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group dme1737_in7_group = { + .attrs = dme1737_in7_attr, +}; + /* The following structs hold the PWM attributes, some of which are optional. * Their creation depends on the chip configuration which is determined during * module load. */ @@ -1986,6 +2015,9 @@ static void dme1737_remove_files(struct device *dev) if (data->has_features & HAS_ZONE_HYST) { sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group); } + if (data->has_features & HAS_IN7) { + sysfs_remove_group(&dev->kobj, &dme1737_in7_group); + } sysfs_remove_group(&dev->kobj, &dme1737_group); if (!data->client) { @@ -2030,6 +2062,12 @@ static int dme1737_create_files(struct device *dev) &dme1737_zone_hyst_group))) { goto exit_remove; } + if (data->has_features & HAS_IN7) { + err = sysfs_create_group(&dev->kobj, &dme1737_in7_group); + if (err) { + goto exit_remove; + } + } /* Create fan sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { @@ -2188,7 +2226,7 @@ static int dme1737_init_device(struct device *dev) data->has_features |= HAS_ZONE3; break; case sch5127: - data->has_features |= HAS_FAN(2) | HAS_PWM(2); + data->has_features |= HAS_FAN(2) | HAS_PWM(2) | HAS_IN7; break; default: break; -- cgit v1.2.3 From 06f3d9fb4a7d3528121446e94ee37b95bba4d106 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Wed, 12 Jan 2011 21:55:13 +0100 Subject: hwmon: (dme1737) Minor cleanups Minor cleanups. Mostly removing assignments in if statements to get rid of checkpatch errors. Signed-off-by: Juerg Haefliger Signed-off-by: Jean Delvare --- drivers/hwmon/dme1737.c | 121 +++++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index ec683eabd7ac..d9c592713919 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -1590,7 +1590,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ * created unconditionally. The attributes that need modification of their * permissions are created read-only and write permissions are added or removed * on the fly when required */ -static struct attribute *dme1737_attr[] ={ +static struct attribute *dme1737_attr[] = { /* Voltages */ &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, @@ -1695,7 +1695,7 @@ static const struct attribute_group dme1737_zone3_group = { }; -/* The following struct holds temp zone hysteresis related attributes, which +/* The following struct holds temp zone hysteresis related attributes, which * are not available in all chips. The following chips support them: * DME1737, SCH311x */ static struct attribute *dme1737_zone_hyst_attr[] = { @@ -2031,36 +2031,44 @@ static int dme1737_create_files(struct device *dev) int err, ix; /* Create a name attribute for ISA devices */ - if (!data->client && - (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) { - goto exit; + if (!data->client) { + err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr); + if (err) { + goto exit; + } } /* Create standard sysfs attributes */ - if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) { + err = sysfs_create_group(&dev->kobj, &dme1737_group); + if (err) { goto exit_remove; } /* Create chip-dependent sysfs attributes */ - if ((data->has_features & HAS_TEMP_OFFSET) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_temp_offset_group))) { - goto exit_remove; + if (data->has_features & HAS_TEMP_OFFSET) { + err = sysfs_create_group(&dev->kobj, + &dme1737_temp_offset_group); + if (err) { + goto exit_remove; + } } - if ((data->has_features & HAS_VID) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_vid_group))) { - goto exit_remove; + if (data->has_features & HAS_VID) { + err = sysfs_create_group(&dev->kobj, &dme1737_vid_group); + if (err) { + goto exit_remove; + } } - if ((data->has_features & HAS_ZONE3) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_zone3_group))) { - goto exit_remove; + if (data->has_features & HAS_ZONE3) { + err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group); + if (err) { + goto exit_remove; + } } - if ((data->has_features & HAS_ZONE_HYST) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_zone_hyst_group))) { - goto exit_remove; + if (data->has_features & HAS_ZONE_HYST) { + err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group); + if (err) { + goto exit_remove; + } } if (data->has_features & HAS_IN7) { err = sysfs_create_group(&dev->kobj, &dme1737_in7_group); @@ -2072,8 +2080,9 @@ static int dme1737_create_files(struct device *dev) /* Create fan sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { if (data->has_features & HAS_FAN(ix)) { - if ((err = sysfs_create_group(&dev->kobj, - &dme1737_fan_group[ix]))) { + err = sysfs_create_group(&dev->kobj, + &dme1737_fan_group[ix]); + if (err) { goto exit_remove; } } @@ -2082,14 +2091,17 @@ static int dme1737_create_files(struct device *dev) /* Create PWM sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { if (data->has_features & HAS_PWM(ix)) { - if ((err = sysfs_create_group(&dev->kobj, - &dme1737_pwm_group[ix]))) { + err = sysfs_create_group(&dev->kobj, + &dme1737_pwm_group[ix]); + if (err) { goto exit_remove; } - if ((data->has_features & HAS_PWM_MIN) && ix < 3 && - (err = sysfs_create_file(&dev->kobj, - dme1737_auto_pwm_min_attr[ix]))) { - goto exit_remove; + if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) { + err = sysfs_create_file(&dev->kobj, + dme1737_auto_pwm_min_attr[ix]); + if (err) { + goto exit_remove; + } } } } @@ -2319,8 +2331,9 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) dme1737_sio_outb(sio_cip, 0x07, 0x0a); /* Get the base address of the runtime registers */ - if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | - dme1737_sio_inb(sio_cip, 0x61))) { + addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61); + if (!addr) { err = -ENODEV; goto exit; } @@ -2401,13 +2414,15 @@ static int dme1737_i2c_probe(struct i2c_client *client, mutex_init(&data->update_lock); /* Initialize the DME1737 chip */ - if ((err = dme1737_init_device(dev))) { + err = dme1737_init_device(dev); + if (err) { dev_err(dev, "Failed to initialize device.\n"); goto exit_kfree; } /* Create sysfs files */ - if ((err = dme1737_create_files(dev))) { + err = dme1737_create_files(dev); + if (err) { dev_err(dev, "Failed to create sysfs files.\n"); goto exit_kfree; } @@ -2484,8 +2499,9 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) dme1737_sio_outb(sio_cip, 0x07, 0x0a); /* Get the base address of the runtime registers */ - if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | - dme1737_sio_inb(sio_cip, 0x61))) { + base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61); + if (!base_addr) { pr_err("Base address not set\n"); err = -ENODEV; goto exit; @@ -2514,18 +2530,21 @@ static int __init dme1737_isa_device_add(unsigned short addr) if (err) goto exit; - if (!(pdev = platform_device_alloc("dme1737", addr))) { + pdev = platform_device_alloc("dme1737", addr); + if (!pdev) { pr_err("Failed to allocate device\n"); err = -ENOMEM; goto exit; } - if ((err = platform_device_add_resources(pdev, &res, 1))) { + err = platform_device_add_resources(pdev, &res, 1); + if (err) { pr_err("Failed to add device resource (err = %d)\n", err); goto exit_device_put; } - if ((err = platform_device_add(pdev))) { + err = platform_device_add(pdev); + if (err) { pr_err("Failed to add device (err = %d)\n", err); goto exit_device_put; } @@ -2552,11 +2571,12 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n", (unsigned short)res->start, (unsigned short)res->start + DME1737_EXTENT - 1); - err = -EBUSY; - goto exit; - } + err = -EBUSY; + goto exit; + } - if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit_release_region; } @@ -2603,13 +2623,15 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr); /* Initialize the chip */ - if ((err = dme1737_init_device(dev))) { + err = dme1737_init_device(dev); + if (err) { dev_err(dev, "Failed to initialize device.\n"); goto exit_kfree; } /* Create sysfs files */ - if ((err = dme1737_create_files(dev))) { + err = dme1737_create_files(dev); + if (err) { dev_err(dev, "Failed to create sysfs files.\n"); goto exit_kfree; } @@ -2666,7 +2688,8 @@ static int __init dme1737_init(void) int err; unsigned short addr; - if ((err = i2c_add_driver(&dme1737_i2c_driver))) { + err = i2c_add_driver(&dme1737_i2c_driver); + if (err) { goto exit; } @@ -2679,12 +2702,14 @@ static int __init dme1737_init(void) return 0; } - if ((err = platform_driver_register(&dme1737_isa_driver))) { + err = platform_driver_register(&dme1737_isa_driver); + if (err) { goto exit_del_i2c_driver; } /* Sets global pdev as a side effect */ - if ((err = dme1737_isa_device_add(addr))) { + err = dme1737_isa_device_add(addr); + if (err) { goto exit_del_isa_driver; } -- cgit v1.2.3 From 6fed05c9c9812b5882bc708f4da4fa8d5df2875c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 12 Jan 2011 22:03:20 +0100 Subject: ACPI / PM: Fix build problems for !CONFIG_ACPI related to NVS rework The recent rework of the NVS saving/restoring code introduced two build issues for !CONFIG_ACPI, a warning in drivers/acpi/internal.h and an error in arch/x86/kernel/e820.c. Fix them by providing suitable static inline definitions of the relevant functions. Signed-off-by: Rafael J. Wysocki Acked-by: Randy Dunlap Signed-off-by: Len Brown --- drivers/acpi/internal.h | 2 +- include/linux/acpi.h | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 7c23b76e8eca..6d69bbedf97a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -90,7 +90,7 @@ void suspend_nvs_restore(void); static inline int acpi_sleep_proc_init(void) { return 0; } static inline int suspend_nvs_alloc(void) { return 0; } static inline void suspend_nvs_free(void) {} -static inline int suspend_nvs_save(void) {} +static inline int suspend_nvs_save(void) { return 0; } static inline void suspend_nvs_restore(void) {} #endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index fa7ed6a983d0..eb176bb1b15b 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -254,15 +254,6 @@ void __init acpi_old_suspend_ordering(void); void __init acpi_nvs_nosave(void); #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_ACPI_SLEEP -int suspend_nvs_register(unsigned long start, unsigned long size); -#else -static inline int suspend_nvs_register(unsigned long a, unsigned long b) -{ - return 0; -} -#endif - struct acpi_osc_context { char *uuid_str; /* uuid string */ int rev; @@ -361,4 +352,14 @@ static inline int acpi_table_parse(char *id, return -1; } #endif /* !CONFIG_ACPI */ + +#ifdef CONFIG_ACPI_SLEEP +int suspend_nvs_register(unsigned long start, unsigned long size); +#else +static inline int suspend_nvs_register(unsigned long a, unsigned long b) +{ + return 0; +} +#endif + #endif /*_LINUX_ACPI_H*/ -- cgit v1.2.3 From 540ac5553e8169413a90a8e68b3a10f801640eb7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2011 00:25:08 -0500 Subject: i2c-bfin-twi: handle faulty slave devices better Faulty slave devices might drive SDA low after a transfer finishes. So, when this scenario is detected, have the master generate up to 9 extra clocks until the SDA is properly released. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fb26e5c67515..1ee9d5a31928 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -159,6 +160,27 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, if (mast_stat & BUFWRERR) dev_dbg(&iface->adap.dev, "Buffer Write Error\n"); + /* Faulty slave devices, may drive SDA low after a transfer + * finishes. To release the bus this code generates up to 9 + * extra clocks until SDA is released. + */ + + if (read_MASTER_STAT(iface) & SDASEN) { + int cnt = 9; + do { + write_MASTER_CTL(iface, SCLOVR); + udelay(6); + write_MASTER_CTL(iface, 0); + udelay(6); + } while ((read_MASTER_STAT(iface) & SDASEN) && cnt--); + + write_MASTER_CTL(iface, SDAOVR | SCLOVR); + udelay(6); + write_MASTER_CTL(iface, SDAOVR); + udelay(6); + write_MASTER_CTL(iface, 0); + } + /* If it is a quick transfer, only address without data, * not an err, return 1. */ -- cgit v1.2.3 From 74f56c4ad4e4627862bddb0b8c3ab394e3c004f7 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 11 Jan 2011 00:25:09 -0500 Subject: i2c-bfin-twi: move setup to the earlier subsys initcall Some systems using this bus sometimes have very basic devices such as regulators on the bus, so the I2C bus master needs to be loaded early. This also matches the behavior of many other I2C bus master drivers. Therefore initialize via subsys_initcall(). Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 1ee9d5a31928..52b545a795f2 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -782,7 +782,7 @@ static void __exit i2c_bfin_twi_exit(void) platform_driver_unregister(&i2c_bfin_twi_driver); } -module_init(i2c_bfin_twi_init); +subsys_initcall(i2c_bfin_twi_init); module_exit(i2c_bfin_twi_exit); MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); -- cgit v1.2.3 From bf542a4e7b634c2adcba4241a29082f69b0f45dc Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Wed, 12 Jan 2011 23:23:23 +0100 Subject: olpc_battery: Fix up XO-1.5 properties list The patches adding support for CURRENT_NOW, VOLTAGE_NOW, CHARGE_NOW and CHARGE_FULL_DESIGN were based on a tree not including c566d299 ("olpc_battery: Ambient temperature is not available on XO-1.5") and therefore only modified the then-common, now-XO-1 properties list. This patch adds the new properties to XO-1.5 as well. Signed-off-by: Sascha Silbe Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 64e40ff5c44a..0b0ff3a936a6 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -438,9 +438,13 @@ static enum power_supply_property olpc_xo15_bat_props[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, -- cgit v1.2.3 From da995a8aee044bc5d0847e19e351cd48a2cb8bcc Mon Sep 17 00:00:00 2001 From: Aleksey Senin Date: Thu, 2 Dec 2010 11:44:49 +0000 Subject: IB/mlx4: Handle protocol field in multicast table The newest device firmware stores IB vs. Ethernet protocol in two bits in members_count field of multicast group table (0: Infiniband, 1: Ethernet). When changing the QP members count for a multicast group, it important not to reset this information. When calling multicast attach first time, the protocol type should be specified. In this patch we always set it IB, but in the future we will handle Ethernet too. When looking for a QP, the protocol type shoud be checked too. Signed-off-by: Aleksey Senin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 9 +++++---- drivers/net/mlx4/mcg.c | 23 +++++++++++++---------- include/linux/mlx4/device.h | 10 ++++++++-- include/linux/mlx4/driver.h | 6 +----- 4 files changed, 27 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index d68d849ab866..c7a6213c6996 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -623,8 +623,9 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); struct mlx4_ib_qp *mqp = to_mqp(ibqp); - err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags & - MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK)); + err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, + !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), + MLX4_PROTOCOL_IB); if (err) return err; @@ -635,7 +636,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return 0; err_add: - mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw); + mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); return err; } @@ -665,7 +666,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx4_ib_gid_entry *ge; err = mlx4_multicast_detach(mdev->dev, - &mqp->mqp, gid->raw); + &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); if (err) return err; diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index c4f88b7ef7b6..79cf42db2ea9 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -95,7 +95,8 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox * entry in hash chain and *mgm holds end of hash chain. */ static int find_mgm(struct mlx4_dev *dev, - u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox, + u8 *gid, enum mlx4_protocol protocol, + struct mlx4_cmd_mailbox *mgm_mailbox, u16 *hash, int *prev, int *index) { struct mlx4_cmd_mailbox *mailbox; @@ -134,7 +135,8 @@ static int find_mgm(struct mlx4_dev *dev, return err; } - if (!memcmp(mgm->gid, gid, 16)) + if (!memcmp(mgm->gid, gid, 16) && + be32_to_cpu(mgm->members_count) >> 30 == protocol) return err; *prev = *index; @@ -146,7 +148,7 @@ static int find_mgm(struct mlx4_dev *dev, } int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback) + int block_mcast_loopback, enum mlx4_protocol protocol) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -165,7 +167,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mutex_lock(&priv->mcg_table.mutex); - err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); + err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); if (err) goto out; @@ -187,7 +189,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], memcpy(mgm->gid, gid, 16); } - members_count = be32_to_cpu(mgm->members_count); + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; if (members_count == MLX4_QP_PER_MGM) { mlx4_err(dev, "MGM at index %x is full.\n", index); err = -ENOMEM; @@ -207,7 +209,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], else mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count); + mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30); err = mlx4_WRITE_MCG(dev, index, mailbox); if (err) @@ -242,7 +244,8 @@ out: } EXPORT_SYMBOL_GPL(mlx4_multicast_attach); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol protocol) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -260,7 +263,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) mutex_lock(&priv->mcg_table.mutex); - err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); + err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); if (err) goto out; @@ -270,7 +273,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) goto out; } - members_count = be32_to_cpu(mgm->members_count); + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; for (loc = -1, i = 0; i < members_count; ++i) if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) loc = i; @@ -282,7 +285,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) } - mgm->members_count = cpu_to_be32(--members_count); + mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30); mgm->qp[loc] = mgm->qp[i - 1]; mgm->qp[i - 1] = 0; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index a7b15bc7648e..049214642036 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -144,6 +144,11 @@ enum { MLX4_STAT_RATE_OFFSET = 5 }; +enum mlx4_protocol { + MLX4_PROTOCOL_IB, + MLX4_PROTOCOL_EN, +}; + enum { MLX4_MTT_FLAG_PRESENT = 1 }; @@ -500,8 +505,9 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port); int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); + int block_mcast_loopback, enum mlx4_protocol protocol); +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol protocol); int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index); void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index); diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h index f407cd4bfb34..e1eebf78caba 100644 --- a/include/linux/mlx4/driver.h +++ b/include/linux/mlx4/driver.h @@ -34,6 +34,7 @@ #define MLX4_DRIVER_H #include +#include struct mlx4_dev; @@ -44,11 +45,6 @@ enum mlx4_dev_event { MLX4_DEV_EVENT_PORT_REINIT, }; -enum mlx4_protocol { - MLX4_PROTOCOL_IB, - MLX4_PROTOCOL_EN, -}; - struct mlx4_interface { void * (*add) (struct mlx4_dev *dev); void (*remove)(struct mlx4_dev *dev, void *context); -- cgit v1.2.3 From f77cfe4ea21760268c0277fa3e4b02dfd2a2c2f4 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 7 Jan 2011 11:29:44 +0100 Subject: cpuidle/x86/perf: fix power:cpu_idle double end events and throw cpu_idle events from the cpuidle layer Currently intel_idle and acpi_idle driver show double cpu_idle "exit idle" events -> this patch fixes it and makes cpu_idle events throwing less complex. It also introduces cpu_idle events for all architectures which use the cpuidle subsystem, namely: - arch/arm/mach-at91/cpuidle.c - arch/arm/mach-davinci/cpuidle.c - arch/arm/mach-kirkwood/cpuidle.c - arch/arm/mach-omap2/cpuidle34xx.c - arch/drivers/acpi/processor_idle.c (for all cases, not only mwait) - arch/x86/kernel/process.c (did throw events before, but was a mess) - drivers/idle/intel_idle.c (did throw events before) Convention should be: Fire cpu_idle events inside the current pm_idle function (not somewhere down the the callee tree) to keep things easy. Current possible pm_idle functions in X86: c1e_idle, poll_idle, cpuidle_idle_call, mwait_idle, default_idle -> this is really easy is now. This affects userspace: The type field of the cpu_idle power event can now direclty get mapped to: /sys/devices/system/cpu/cpuX/cpuidle/stateX/{name,desc,usage,time,...} instead of throwing very CPU/mwait specific values. This change is not visible for the intel_idle driver. For the acpi_idle driver it should only be visible if the vendor misses out C-states in his BIOS. Another (perf timechart) patch reads out cpuidle info of cpu_idle events from: /sys/.../cpuidle/stateX/*, then the cpuidle events are mapped to the correct C-/cpuidle state again, even if e.g. vendors miss out C-states in their BIOS and for example only export C1 and C3. -> everything is fine. Signed-off-by: Thomas Renninger CC: Robert Schoene CC: Jean Pihet CC: Arjan van de Ven CC: Ingo Molnar CC: Frederic Weisbecker CC: linux-pm@lists.linux-foundation.org CC: linux-acpi@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: linux-perf-users@vger.kernel.org CC: linux-omap@vger.kernel.org Signed-off-by: Len Brown --- arch/x86/kernel/process.c | 6 ++++-- arch/x86/kernel/process_32.c | 4 ---- arch/x86/kernel/process_64.c | 6 ------ drivers/cpuidle/cpuidle.c | 10 ++++++++-- drivers/idle/intel_idle.c | 2 -- 5 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 09c08a1c706f..67e96e67157b 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -386,6 +386,8 @@ void default_idle(void) else local_irq_enable(); current_thread_info()->status |= TS_POLLING; + trace_power_end(smp_processor_id()); + trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); } else { local_irq_enable(); /* loop is done by the caller */ @@ -443,8 +445,6 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); */ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) { - trace_power_start(POWER_CSTATE, (ax>>4)+1, smp_processor_id()); - trace_cpu_idle((ax>>4)+1, smp_processor_id()); if (!need_resched()) { if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); @@ -471,6 +471,8 @@ static void mwait_idle(void) __sti_mwait(0, 0); else local_irq_enable(); + trace_power_end(smp_processor_id()); + trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); } else local_irq_enable(); } diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 4b9befa0e347..8d128783af47 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -57,8 +57,6 @@ #include #include -#include - asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); /* @@ -113,8 +111,6 @@ void cpu_idle(void) stop_critical_timings(); pm_idle(); start_critical_timings(); - trace_power_end(smp_processor_id()); - trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); } tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 4c818a738396..bd387e8f73b4 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -51,8 +51,6 @@ #include #include -#include - asmlinkage extern void ret_from_fork(void); DEFINE_PER_CPU(unsigned long, old_rsp); @@ -141,10 +139,6 @@ void cpu_idle(void) pm_idle(); start_critical_timings(); - trace_power_end(smp_processor_id()); - trace_cpu_idle(PWR_EVENT_EXIT, - smp_processor_id()); - /* In many cases the interrupt that ended idle has already called exit_idle. But some idle loops can be woken up without interrupt. */ diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 386888f10df0..e4855c33f897 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -96,7 +96,15 @@ static void cpuidle_idle_call(void) /* enter the state and update stats */ dev->last_state = target_state; + + trace_power_start(POWER_CSTATE, next_state, dev->cpu); + trace_cpu_idle(next_state, dev->cpu); + dev->last_residency = target_state->enter(dev, target_state); + + trace_power_end(dev->cpu); + trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); + if (dev->last_state) target_state = dev->last_state; @@ -106,8 +114,6 @@ static void cpuidle_idle_call(void) /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) cpuidle_curr_governor->reflect(dev); - trace_power_end(smp_processor_id()); - trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); } /** diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 56ac09d6c930..60fa6ecdb41f 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -220,8 +220,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) kt_before = ktime_get_real(); stop_critical_timings(); - trace_power_start(POWER_CSTATE, (eax >> 4) + 1, cpu); - trace_cpu_idle((eax >> 4) + 1, cpu); if (!need_resched()) { __monitor((void *)¤t_thread_info()->flags, 0, 0); -- cgit v1.2.3 From 766fc43973b16f9becb6b7402b3e052dbb84adee Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 7 Jan 2011 14:58:42 -0800 Subject: rbd: fix cleanup when trying to mount inexistent image Previously we didn't clean up the sysfs entry that was just created. Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil --- drivers/block/rbd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 008d4a00b50d..e1e38b11f48a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1790,18 +1790,29 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) rc = rbd_bus_add_dev(rbd_dev); if (rc) - goto err_out_disk; + goto err_out_blkdev; + /* set up and announce blkdev mapping */ rc = rbd_init_disk(rbd_dev); if (rc) - goto err_out_blkdev; + goto err_out_bus; return count; +err_out_bus: + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + list_del_init(&rbd_dev->node); + mutex_unlock(&ctl_mutex); + + /* this will also clean up rest of rbd_dev stuff */ + + rbd_bus_del_dev(rbd_dev); + kfree(options); + kfree(mon_dev_name); + return rc; + err_out_blkdev: unregister_blkdev(rbd_dev->major, rbd_dev->name); -err_out_disk: - rbd_free_disk(rbd_dev); err_out_client: rbd_put_client(rbd_dev); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); -- cgit v1.2.3 From d93e34faf924bd98f158712d63085662e648e389 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Dec 2010 07:41:48 -0500 Subject: pohmelfs: double-free and leak wrong dentry dropped... Signed-off-by: Al Viro --- drivers/staging/pohmelfs/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c index 9279897ff161..b2e918622088 100644 --- a/drivers/staging/pohmelfs/net.c +++ b/drivers/staging/pohmelfs/net.c @@ -413,7 +413,7 @@ static int pohmelfs_readdir_response(struct netfs_state *st) if (dentry) { alias = d_materialise_unique(dentry, &npi->vfs_inode); if (alias) - dput(dentry); + dput(alias); } dput(dentry); -- cgit v1.2.3 From b5c7d208ca48e7769aa38731665283790de49840 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:19:20 -0500 Subject: convert smbfs Signed-off-by: Al Viro --- drivers/staging/smbfs/dir.c | 13 ------------- drivers/staging/smbfs/inode.c | 4 ++++ drivers/staging/smbfs/proto.h | 2 ++ 3 files changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c index dd612f50749f..87a3a9bd5842 100644 --- a/drivers/staging/smbfs/dir.c +++ b/drivers/staging/smbfs/dir.c @@ -403,12 +403,6 @@ smb_delete_dentry(const struct dentry *dentry) void smb_new_dentry(struct dentry *dentry) { - struct smb_sb_info *server = server_from_dentry(dentry); - - if (server->mnt->flags & SMB_MOUNT_CASE) - d_set_d_op(dentry, &smbfs_dentry_operations_case); - else - d_set_d_op(dentry, &smbfs_dentry_operations); dentry->d_time = jiffies; } @@ -440,7 +434,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct smb_fattr finfo; struct inode *inode; int error; - struct smb_sb_info *server; error = -ENAMETOOLONG; if (dentry->d_name.len > SMB_MAXNAMELEN) @@ -468,12 +461,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) inode = smb_iget(dir->i_sb, &finfo); if (inode) { add_entry: - server = server_from_dentry(dentry); - if (server->mnt->flags & SMB_MOUNT_CASE) - d_set_d_op(dentry, &smbfs_dentry_operations_case); - else - d_set_d_op(dentry, &smbfs_dentry_operations); - d_add(dentry, inode); smb_renew_times(dentry); error = 0; diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c index 244319dc9702..0778589d9e9e 100644 --- a/drivers/staging/smbfs/inode.c +++ b/drivers/staging/smbfs/inode.c @@ -614,6 +614,10 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) printk(KERN_ERR "smbfs: failed to start smbiod\n"); goto out_no_smbiod; } + if (server->mnt->flags & SMB_MOUNT_CASE) + sb->s_d_op = &smbfs_dentry_operations_case; + else + sb->s_d_op = &smbfs_dentry_operations; /* * Keep the super block locked while we get the root inode. diff --git a/drivers/staging/smbfs/proto.h b/drivers/staging/smbfs/proto.h index 05939a6f43e6..3883cb16a3f6 100644 --- a/drivers/staging/smbfs/proto.h +++ b/drivers/staging/smbfs/proto.h @@ -38,6 +38,8 @@ extern void smb_install_null_ops(struct smb_ops *ops); extern const struct file_operations smb_dir_operations; extern const struct inode_operations smb_dir_inode_operations; extern const struct inode_operations smb_dir_inode_operations_unix; +extern const struct dentry_operations smbfs_dentry_operations_case; +extern const struct dentry_operations smbfs_dentry_operations; extern void smb_new_dentry(struct dentry *dentry); extern void smb_renew_times(struct dentry *dentry); /* cache.c */ -- cgit v1.2.3 From c74a1cbb3cac348f276fabc381758f5b0b4713b2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:59:34 -0500 Subject: pass default dentry_operations to mount_pseudo() Signed-off-by: Al Viro --- arch/ia64/kernel/perfmon.c | 6 ++++-- drivers/mtd/mtdchar.c | 2 +- fs/anon_inodes.c | 21 +++++++++++---------- fs/block_dev.c | 2 +- fs/libfs.c | 4 +++- fs/pipe.c | 4 ++-- include/linux/fs.h | 4 +++- net/socket.c | 30 +++++++++++++++--------------- 8 files changed, 40 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index d92d5b5161fc..ac76da099a6d 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -617,11 +617,14 @@ pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, return get_unmapped_area(file, addr, len, pgoff, flags); } +/* forward declaration */ +static static const struct dentry_operations pfmfs_dentry_operations; static struct dentry * pfmfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); + return mount_pseudo(fs_type, "pfm:", NULL, &pfmfs_dentry_operations, + PFMFS_MAGIC); } static struct file_system_type pfm_fs_type = { @@ -2232,7 +2235,6 @@ pfm_alloc_file(pfm_context_t *ctx) } path.mnt = mntget(pfmfs_mnt); - d_set_d_op(path.dentry, &pfmfs_dentry_operations); d_add(path.dentry, inode); file = alloc_file(&path, FMODE_READ, &pfm_file_ops); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index f511dd15fd31..ee4bb3330bdf 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1134,7 +1134,7 @@ static const struct file_operations mtd_fops = { static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); + return mount_pseudo(fs_type, "mtd_inode:", NULL, NULL, MTD_INODE_FS_MAGIC); } static struct file_system_type mtd_inodefs_type = { diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 5fd38112a6ca..549a53cc0283 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -26,12 +26,6 @@ static struct vfsmount *anon_inode_mnt __read_mostly; static struct inode *anon_inode_inode; static const struct file_operations anon_inode_fops; -static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC); -} - /* * anon_inodefs_dname() is called from d_path(). */ @@ -41,14 +35,22 @@ static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen) dentry->d_name.name); } +static const struct dentry_operations anon_inodefs_dentry_operations = { + .d_dname = anon_inodefs_dname, +}; + +static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "anon_inode:", NULL, + &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); +} + static struct file_system_type anon_inode_fs_type = { .name = "anon_inodefs", .mount = anon_inodefs_mount, .kill_sb = kill_anon_super, }; -static const struct dentry_operations anon_inodefs_dentry_operations = { - .d_dname = anon_inodefs_dname, -}; /* * nop .set_page_dirty method so that people can use .page_mkwrite on @@ -113,7 +115,6 @@ struct file *anon_inode_getfile(const char *name, */ ihold(anon_inode_inode); - d_set_d_op(path.dentry, &anon_inodefs_dentry_operations); d_instantiate(path.dentry, anon_inode_inode); error = -ENFILE; diff --git a/fs/block_dev.c b/fs/block_dev.c index 771f23527010..88da70355aa3 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -473,7 +473,7 @@ static const struct super_operations bdev_sops = { static struct dentry *bd_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); + return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, 0x62646576); } static struct file_system_type bd_type = { diff --git a/fs/libfs.c b/fs/libfs.c index 889311e3d06b..c88eab55aec9 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -217,7 +217,8 @@ static const struct super_operations simple_super_operations = { * will never be mountable) */ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, unsigned long magic) + const struct super_operations *ops, + const struct dentry_operations *dops, unsigned long magic) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); struct dentry *dentry; @@ -254,6 +255,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, dentry->d_parent = dentry; d_instantiate(dentry, root); s->s_root = dentry; + s->s_d_op = dops; s->s_flags |= MS_ACTIVE; return dget(s->s_root); diff --git a/fs/pipe.c b/fs/pipe.c index 68f1f8e4e23b..6b0255a74f36 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1004,7 +1004,6 @@ struct file *create_write_pipe(int flags) goto err_inode; path.mnt = mntget(pipe_mnt); - d_set_d_op(path.dentry, &pipefs_dentry_operations); d_instantiate(path.dentry, inode); err = -ENFILE; @@ -1266,7 +1265,8 @@ static const struct super_operations pipefs_ops = { static struct dentry *pipefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "pipe:", &pipefs_ops, PIPEFS_MAGIC); + return mount_pseudo(fs_type, "pipe:", &pipefs_ops, + &pipefs_dentry_operations, PIPEFS_MAGIC); } static struct file_system_type pipe_fs_type = { diff --git a/include/linux/fs.h b/include/linux/fs.h index 3e4c27486e74..c0701288d204 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1835,7 +1835,9 @@ struct super_block *sget(struct file_system_type *type, int (*set)(struct super_block *,void *), void *data); extern struct dentry *mount_pseudo(struct file_system_type *, char *, - const struct super_operations *ops, unsigned long); + const struct super_operations *ops, + const struct dentry_operations *dops, + unsigned long); extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); static inline void sb_mark_dirty(struct super_block *sb) diff --git a/net/socket.c b/net/socket.c index ccc576a6a508..ac2219f90d5d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -306,20 +306,6 @@ static const struct super_operations sockfs_ops = { .statfs = simple_statfs, }; -static struct dentry *sockfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); -} - -static struct vfsmount *sock_mnt __read_mostly; - -static struct file_system_type sock_fs_type = { - .name = "sockfs", - .mount = sockfs_mount, - .kill_sb = kill_anon_super, -}; - /* * sockfs_dname() is called from d_path(). */ @@ -333,6 +319,21 @@ static const struct dentry_operations sockfs_dentry_operations = { .d_dname = sockfs_dname, }; +static struct dentry *sockfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "socket:", &sockfs_ops, + &sockfs_dentry_operations, SOCKFS_MAGIC); +} + +static struct vfsmount *sock_mnt __read_mostly; + +static struct file_system_type sock_fs_type = { + .name = "sockfs", + .mount = sockfs_mount, + .kill_sb = kill_anon_super, +}; + /* * Obtains the first available file descriptor and sets it up for use. * @@ -368,7 +369,6 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags) } path.mnt = mntget(sock_mnt); - d_set_d_op(path.dentry, &sockfs_dentry_operations); d_instantiate(path.dentry, SOCK_INODE(sock)); SOCK_INODE(sock)->i_fop = &socket_file_ops; -- cgit v1.2.3 From e41f1a98940824ad0c95271e69939acdc6092e5f Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Wed, 12 Jan 2011 22:14:44 +0000 Subject: fbdev: Implement simple blanking in pseudocolor modes for vt8500lcdfb Implement simple blanking in pseudocolor modes for vt8500lcdfb This follows the style of some other in-tree drivers by just setting the hardware palette colors to all black. True Color modes are not affected, but this at least allows to run xf86-video-fbdev without errors due to blanking being unimplemented. Signed-off-by: Alexey Charkov Signed-off-by: Paul Mundt --- drivers/video/vt8500lcdfb.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 7617f12e4fd7..0e120d67eb65 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -215,6 +215,33 @@ static int vt8500lcd_pan_display(struct fb_var_screeninfo *var, return 0; } +/* + * vt8500lcd_blank(): + * Blank the display by setting all palette values to zero. Note, + * True Color modes do not really use the palette, so this will not + * blank the display in all modes. + */ +static int vt8500lcd_blank(int blank, struct fb_info *info) +{ + int i; + + switch (blank) { + case FB_BLANK_POWERDOWN: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR || + info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + for (i = 0; i < 256; i++) + vt8500lcd_setcolreg(i, 0, 0, 0, 0, info); + case FB_BLANK_UNBLANK: + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR || + info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + fb_set_cmap(&info->cmap, info); + } + return 0; +} + static struct fb_ops vt8500lcd_ops = { .owner = THIS_MODULE, .fb_set_par = vt8500lcd_set_par, @@ -225,6 +252,7 @@ static struct fb_ops vt8500lcd_ops = { .fb_sync = wmt_ge_sync, .fb_ioctl = vt8500lcd_ioctl, .fb_pan_display = vt8500lcd_pan_display, + .fb_blank = vt8500lcd_blank, }; static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id) -- cgit v1.2.3 From f00117a78341e330eecebdfe74cce345ed068802 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 12 Jan 2011 15:19:35 +0000 Subject: video: move SH_MIPI_DSI/SH_LCD_MIPI_DSI to the top of menu Kconfig entries SH_MIPI_DSI and SH_LCD_MIPI_DSI while being invisible to the user, broke the FrameBuffer menu (at least in menuconfig), as they aren't depending on respective menuconfig item (FB). In result several items got moved to the main "Graphics support" menu. Move these two problematic items to the top of drivers/video/Kbuild to restore nice display of FB menu. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0a96a60bbe49..d916ac04abab 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -11,6 +11,13 @@ config HAVE_FB_ATMEL config HAVE_FB_IMX bool +config SH_MIPI_DSI + tristate + depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK + +config SH_LCD_MIPI_DSI + bool + source "drivers/char/agp/Kconfig" source "drivers/gpu/vga/Kconfig" @@ -1990,13 +1997,6 @@ config FB_W100 If unsure, say N. -config SH_MIPI_DSI - tristate - depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK - -config SH_LCD_MIPI_DSI - bool - config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK -- cgit v1.2.3 From 77e7bc6194655c36d43707ea53b4f86d1f1c8cf5 Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 11 Jan 2011 17:21:53 +0800 Subject: spi/imx: Add i.MX53 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Change the Kconfig to include i.MX53 2. add devtype entry for i.MX53 Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Uwe Kleine-König Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 4 ++-- drivers/spi/spi_imx.c | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1906840c1113..879b2a974d64 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -156,10 +156,10 @@ config SPI_IMX_VER_0_4 def_bool y if ARCH_MX31 config SPI_IMX_VER_0_7 - def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 + def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 || ARCH_MX53 config SPI_IMX_VER_2_3 - def_bool y if ARCH_MX51 + def_bool y if ARCH_MX51 || ARCH_MX53 config SPI_IMX tristate "Freescale i.MX SPI controllers" diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 9469564e6888..1cf9d5faabf4 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -742,6 +742,12 @@ static struct platform_device_id spi_imx_devtype[] = { }, { .name = "imx51-ecspi", .driver_data = SPI_IMX_VER_2_3, + }, { + .name = "imx53-cspi", + .driver_data = SPI_IMX_VER_0_7, + }, { + .name = "imx53-ecspi", + .driver_data = SPI_IMX_VER_2_3, }, { /* sentinel */ } -- cgit v1.2.3 From 4ae26f46c98f58ef19ad34f475617b40740d2faa Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 13 Jan 2011 15:46:35 +0900 Subject: serial: sh-sci: build fixes. This fixes up the port_rx_irq_mask() REIE flag definition as well as a debug printk blowing up on the SCSCR_INIT having gone away. Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 251c08c55ae0..92c91c83edde 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -794,7 +794,7 @@ static inline unsigned long port_rx_irq_mask(struct uart_port *port) * it's unset, it's logically inferred that there's no point in * testing for it. */ - return SCSCR_RIE | (to_sci_port(port)->scscr & SCSR_REIE); + return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE); } static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) @@ -1540,7 +1540,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_out(port, SCSMR, smr_val); dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, - SCSCR_INIT(port)); + s->scscr); if (t > 0) { if (t >= 256) { -- cgit v1.2.3 From 1427130425c1239d977e8891c3a8923f53a6e352 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 13 Jan 2011 10:12:17 +0100 Subject: firewire: ohci: fix compilation on arches without PAGE_KERNEL_RO PAGE_KERNEL_RO is not available on all architectures, so its use in the new AR code broke compilation on sparc64. Because the read-only mapping was just a debugging aid, just use PAGE_KERNEL instead. Signed-off-by: Clemens Ladisch James Bottomley wrote: > On Thu, 2011-01-13 at 08:27 +0100, Clemens Ladisch wrote: >> firewire: ohci: fix compilation on arches without PAGE_KERNEL_RO, e.g. sparc >> >> PAGE_KERNEL_RO is not available on all architectures, so its use in the >> new AR code broke compilation on sparc64. >> >> Because the R/O mapping is only used to catch drivers that try to write >> to the reception buffer and not actually required for correct operation, >> we can just use a normal PAGE_KERNEL mapping where _RO is not available. [...] >> +/* >> + * For archs where PAGE_KERNEL_RO is not supported; >> + * mapping the AR buffers readonly for the CPU is just a debugging aid. >> + */ >> +#ifndef PAGE_KERNEL_RO >> +#define PAGE_KERNEL_RO PAGE_KERNEL >> +#endif > > This might cause interesting issues on sparc64 if it ever acquired a > PAGE_KERNEL_RO. Sparc64 has extern pgprot_t for it's PAGE_KERNEL types > rather than #defines, so the #ifdef check wouldn't see this. > > I think either PAGE_PROT_RO becomes part of our arch API (so all > architectures are forced to add it), or, if it's not part of the API, > ohci isn't entitled to use it. The latter seems simplest since you have > no real use for write protection anyway. Reported-by: Andrew Morton Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index d77d120ddc25..bd3c61b6dd8d 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -961,7 +961,7 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, for (i = 0; i < AR_WRAPAROUND_PAGES; i++) pages[AR_BUFFERS + i] = ctx->pages[i]; ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES, - -1, PAGE_KERNEL_RO); + -1, PAGE_KERNEL); if (!ctx->buffer) goto out_of_memory; -- cgit v1.2.3 From 2260209c4973e3eeb1e48abaa9e639373a0d4fb7 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Wed, 12 Jan 2011 16:59:14 -0800 Subject: drivers/leds/leds-lp5521.c: fix potential buffer overflow The code doesn't check first sscanf() return value. If first sscanf() failed then c contains some garbage. It might lead to reading uninitialised stack data in the second sscanf() call. Signed-off-by: Vasiliy Kulikov Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5521.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 33facd0c45d1..e881a75dc39d 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -373,6 +373,8 @@ static int lp5521_do_store_load(struct lp5521_engine *engine, while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { /* separate sscanfs because length is working only for %s */ ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); + if (ret != 2) + goto fail; ret = sscanf(c, "%2x", &cmd); if (ret != 1) goto fail; -- cgit v1.2.3 From 125c7135251de3aea1429968aea9bdfcb6535fc7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Jan 2011 16:59:15 -0800 Subject: leds: leds-pca9532 cleanups - Remove unneeded input_free_device() after input_unregister_device(). - Add pca9532_destroy_devices() function for destroy devices. Signed-off-by: Axel Lin Acked-by: Dmitry Torokhov Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-pca9532.c | 66 +++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 43d08756d823..afac338d5025 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -200,6 +200,32 @@ static void pca9532_led_work(struct work_struct *work) pca9532_setled(led); } +static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs) +{ + int i = n_devs; + + if (!data) + return; + + while (--i >= 0) { + switch (data->leds[i].type) { + case PCA9532_TYPE_NONE: + break; + case PCA9532_TYPE_LED: + led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); + break; + case PCA9532_TYPE_N2100_BEEP: + if (data->idev != NULL) { + input_unregister_device(data->idev); + cancel_work_sync(&data->work); + data->idev = NULL; + } + break; + } + } +} + static int pca9532_configure(struct i2c_client *client, struct pca9532_data *data, struct pca9532_platform_data *pdata) { @@ -274,25 +300,7 @@ static int pca9532_configure(struct i2c_client *client, return 0; exit: - if (i > 0) - for (i = i - 1; i >= 0; i--) - switch (data->leds[i].type) { - case PCA9532_TYPE_NONE: - break; - case PCA9532_TYPE_LED: - led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); - break; - case PCA9532_TYPE_N2100_BEEP: - if (data->idev != NULL) { - input_unregister_device(data->idev); - input_free_device(data->idev); - cancel_work_sync(&data->work); - data->idev = NULL; - } - break; - } - + pca9532_destroy_devices(data, i); return err; } @@ -329,25 +337,7 @@ static int pca9532_probe(struct i2c_client *client, static int pca9532_remove(struct i2c_client *client) { struct pca9532_data *data = i2c_get_clientdata(client); - int i; - for (i = 0; i < 16; i++) - switch (data->leds[i].type) { - case PCA9532_TYPE_NONE: - break; - case PCA9532_TYPE_LED: - led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); - break; - case PCA9532_TYPE_N2100_BEEP: - if (data->idev != NULL) { - input_unregister_device(data->idev); - input_free_device(data->idev); - cancel_work_sync(&data->work); - data->idev = NULL; - } - break; - } - + pca9532_destroy_devices(data, 16); kfree(data); return 0; } -- cgit v1.2.3 From 278ad4fd0e7517f1d74b8fc1c8347cad34a09b02 Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Wed, 12 Jan 2011 16:59:17 -0800 Subject: leds: leds-lp5523: modify the way of setting led device name Currently all leds channels begins with string lp5523. Patch adds a possibility to provide name via platform data. This makes it possible to have several chips without overlapping sysfs names. Signed-off-by: Samu Onkalo Cc: Arun Murthy Cc: Ilkka Koskinen Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5523.c | 3 ++- include/linux/leds-lp5523.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 0cc4ead2fd8b..6cb41607519d 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -870,7 +870,8 @@ static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, return -EINVAL; } - snprintf(name, 32, "lp5523:channel%d", chan); + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: "lp5523", chan); led->cdev.name = name; led->cdev.brightness_set = lp5523_set_brightness; diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h index 796747637b80..2694289babd0 100644 --- a/include/linux/leds-lp5523.h +++ b/include/linux/leds-lp5523.h @@ -42,6 +42,7 @@ struct lp5523_platform_data { int (*setup_resources)(void); void (*release_resources)(void); void (*enable)(bool state); + const char *label; }; #endif /* __LINUX_LP5523_H */ -- cgit v1.2.3 From fbac0812de0455c6af3e1f29fccffc207073b7eb Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Wed, 12 Jan 2011 16:59:18 -0800 Subject: leds: lp5523: fix circular locking Driver contained possibility for circular locking. One lock is held by sysfs-core and another one by the driver itself. This happened when the driver created or removed sysfs entries dynamically. There is no real need to do those operations. Now all the sysfs entries are created at probe and removed at removal. Engine load and mux configuration sysfs entries are now visible all the time. However, access to the entries fails if the engine is disabled or running. Signed-off-by: Samu Onkalo Cc: Arun Murthy Reviewed-by: Ilkka Koskinen Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5523.c | 56 +++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 6cb41607519d..d0c4068ecddd 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -105,7 +105,6 @@ #define SHIFT_MASK(id) (((id) - 1) * 2) struct lp5523_engine { - const struct attribute_group *attributes; int id; u8 mode; u8 prog_page; @@ -403,14 +402,23 @@ static ssize_t store_engine_leds(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct lp5523_chip *chip = i2c_get_clientdata(client); u16 mux = 0; + ssize_t ret; if (lp5523_mux_parse(buf, &mux, len)) return -EINVAL; + mutex_lock(&chip->lock); + ret = -EINVAL; + if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD) + goto leave; + if (lp5523_load_mux(&chip->engines[nr - 1], mux)) - return -EINVAL; + goto leave; - return len; + ret = len; +leave: + mutex_unlock(&chip->lock); + return ret; } #define store_leds(nr) \ @@ -556,7 +564,11 @@ static int lp5523_do_store_load(struct lp5523_engine *engine, mutex_lock(&chip->lock); - ret = lp5523_load_program(engine, pattern); + if (engine->mode == LP5523_CMD_LOAD) + ret = lp5523_load_program(engine, pattern); + else + ret = -EINVAL; + mutex_unlock(&chip->lock); if (ret) { @@ -737,37 +749,18 @@ static struct attribute *lp5523_attributes[] = { &dev_attr_engine2_mode.attr, &dev_attr_engine3_mode.attr, &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5523_engine1_attributes[] = { &dev_attr_engine1_load.attr, &dev_attr_engine1_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine2_attributes[] = { &dev_attr_engine2_load.attr, &dev_attr_engine2_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine3_attributes[] = { &dev_attr_engine3_load.attr, &dev_attr_engine3_leds.attr, - NULL }; static const struct attribute_group lp5523_group = { .attrs = lp5523_attributes, }; -static const struct attribute_group lp5523_engine_group[] = { - {.attrs = lp5523_engine1_attributes }, - {.attrs = lp5523_engine2_attributes }, - {.attrs = lp5523_engine3_attributes }, -}; - static int lp5523_register_sysfs(struct i2c_client *client) { struct device *dev = &client->dev; @@ -788,10 +781,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) sysfs_remove_group(&dev->kobj, &lp5523_group); - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) - if (chip->engines[i].mode == LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]); - for (i = 0; i < chip->num_leds; i++) sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, &lp5523_led_attribute_group); @@ -802,10 +791,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) /*--------------------------------------------------------------*/ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) { - /* engine to chip */ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; int ret = 0; /* if in that mode already do nothing, except for run */ @@ -817,18 +802,10 @@ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) } else if (mode == LP5523_CMD_LOAD) { lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; } else if (mode == LP5523_CMD_DISABLED) { lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); } - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - engine->mode = mode; return ret; @@ -845,7 +822,6 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); engine->prog_page = id - 1; engine->mux_page = id + 2; - engine->attributes = &lp5523_engine_group[id - 1]; return 0; } -- cgit v1.2.3 From d4e7ad03e84b2301be4f9a39ef2778126699ff0c Mon Sep 17 00:00:00 2001 From: Samu Onkalo Date: Wed, 12 Jan 2011 16:59:19 -0800 Subject: leds: lp5521: fix circular locking Driver contained possibility for circular locking. One lock is held by sysfs-core and another one by the driver itself. This happened when the driver created or removed sysfs entries dynamically. There is no real need to do those operations. Now all the sysfs entries are created at probe and removed at removal. Engine load sysfs entries are now visible all the time. However, access to the entries fails if the engine is disabled or running. Signed-off-by: Samu Onkalo Cc: Arun Murthy Reviewed-by: Ilkka Koskinen Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5521.c | 52 +++++++--------------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index e881a75dc39d..4d91c08656c5 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -98,7 +98,6 @@ #define LP5521_EXT_CLK_USED 0x08 struct lp5521_engine { - const struct attribute_group *attributes; int id; u8 mode; u8 prog_page; @@ -225,25 +224,22 @@ static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) curr); } -static void lp5521_init_engine(struct lp5521_chip *chip, - const struct attribute_group *attr_group) +static void lp5521_init_engine(struct lp5521_chip *chip) { int i; for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { chip->engines[i].id = i + 1; chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2); chip->engines[i].prog_page = i; - chip->engines[i].attributes = &attr_group[i]; } } -static int lp5521_configure(struct i2c_client *client, - const struct attribute_group *attr_group) +static int lp5521_configure(struct i2c_client *client) { struct lp5521_chip *chip = i2c_get_clientdata(client); int ret; - lp5521_init_engine(chip, attr_group); + lp5521_init_engine(chip); /* Set all PWMs to direct control mode */ ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); @@ -329,9 +325,6 @@ static int lp5521_detect(struct i2c_client *client) /* Set engine mode and create appropriate sysfs attributes, if required. */ static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) { - struct lp5521_chip *chip = engine_to_lp5521(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; int ret = 0; /* if in that mode already do nothing, except for run */ @@ -343,18 +336,10 @@ static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) } else if (mode == LP5521_CMD_LOAD) { lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); lp5521_set_engine_mode(engine, LP5521_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; } else if (mode == LP5521_CMD_DISABLED) { lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); } - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - engine->mode = mode; return ret; @@ -389,7 +374,10 @@ static int lp5521_do_store_load(struct lp5521_engine *engine, goto fail; mutex_lock(&chip->lock); - ret = lp5521_load_program(engine, pattern); + if (engine->mode == LP5521_CMD_LOAD) + ret = lp5521_load_program(engine, pattern); + else + ret = -EINVAL; mutex_unlock(&chip->lock); if (ret) { @@ -576,20 +564,8 @@ static struct attribute *lp5521_attributes[] = { &dev_attr_engine2_mode.attr, &dev_attr_engine3_mode.attr, &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5521_engine1_attributes[] = { &dev_attr_engine1_load.attr, - NULL -}; - -static struct attribute *lp5521_engine2_attributes[] = { &dev_attr_engine2_load.attr, - NULL -}; - -static struct attribute *lp5521_engine3_attributes[] = { &dev_attr_engine3_load.attr, NULL }; @@ -598,12 +574,6 @@ static const struct attribute_group lp5521_group = { .attrs = lp5521_attributes, }; -static const struct attribute_group lp5521_engine_group[] = { - {.attrs = lp5521_engine1_attributes }, - {.attrs = lp5521_engine2_attributes }, - {.attrs = lp5521_engine3_attributes }, -}; - static int lp5521_register_sysfs(struct i2c_client *client) { struct device *dev = &client->dev; @@ -618,12 +588,6 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) sysfs_remove_group(&dev->kobj, &lp5521_group); - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { - if (chip->engines[i].mode == LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, - chip->engines[i].attributes); - } - for (i = 0; i < chip->num_leds; i++) sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, &lp5521_led_attribute_group); @@ -725,7 +689,7 @@ static int lp5521_probe(struct i2c_client *client, dev_info(&client->dev, "%s programmable led chip found\n", id->name); - ret = lp5521_configure(client, lp5521_engine_group); + ret = lp5521_configure(client); if (ret < 0) { dev_err(&client->dev, "error configuring chip\n"); goto fail2; -- cgit v1.2.3 From 61a83932b8b3f1624d753e06aab2fdf0a119e100 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Wed, 12 Jan 2011 16:59:20 -0800 Subject: leds-lp5521: modify the way of setting led device name Currently the led device name is fetched from the device_type in I2C_BOARD_INFO which comes from the platform data. This name is in turn used to create an entry in sysfs. If there exists two or more lp5521 on a particular platform, the device_type in I2C_BOARD_INFO has to be the same, else lp5521 driver probe wont be called and if used so, results in run time warning "cannot create sysfs with same name" and hence a failure. The name that is used to create sysfs entry is to be passed by the struct led_platform_data. Hence adding an element of type const char * and change in lp5521 driver to use this name in creating the led device if present else use the name obtained by I2C_BOARD_INFO. Signed-off-by: Arun Murthy Acked-by: Samu Onkalo Cc: Ilkka Koskinen Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5521.c | 3 ++- include/linux/leds-lp5521.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 4d91c08656c5..80a3ae3c00b9 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -617,7 +617,8 @@ static int __init lp5521_init_led(struct lp5521_led *led, return -EINVAL; } - snprintf(name, sizeof(name), "%s:channel%d", client->name, chan); + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: client->name, chan); led->cdev.brightness_set = lp5521_set_brightness; led->cdev.name = name; res = led_classdev_register(dev, &led->cdev); diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h index 38368d785f08..fd548d2a8775 100644 --- a/include/linux/leds-lp5521.h +++ b/include/linux/leds-lp5521.h @@ -42,6 +42,7 @@ struct lp5521_platform_data { int (*setup_resources)(void); void (*release_resources)(void); void (*enable)(bool state); + const char *label; }; #endif /* __LINUX_LP5521_H */ -- cgit v1.2.3 From 9f9455ae710786bd11625d501567f4f783fedea5 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 12 Jan 2011 16:59:20 -0800 Subject: leds: add output inversion option to backlight trigger Extend the LED backlight tirgger driver with an option that allows for inverting the trigger output polarity. With the invertion option provided, I (ab)use the backlight trigger for driving a LED that indicates LCD display blank condtition on my Amstrad Delta videophone. Since the machine has no dedicated power LED, it was not possible to distinguish if the display was blanked, or the machine was turned off, without touching it. The invert sysfs control is patterned after a similiar function of the GPIO trigger driver. [akpm@linux-foundation.org: make output match input, tighten input checking] [akpm@linux-foundation.org: make output match input, tighten input checking] Signed-off-by: Janusz Krzysztofik Cc: Paul Mundt Acked-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-class-led | 9 +++++ drivers/leds/ledtrig-backlight.c | 61 +++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led index 9e4541d71cb6..edff6630c805 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -26,3 +26,12 @@ Description: scheduler is chosen. Trigger specific parameters can appear in /sys/class/leds/ once a given trigger is selected. +What: /sys/class/leds//inverted +Date: January 2011 +KernelVersion: 2.6.38 +Contact: Richard Purdie +Description: + Invert the LED on/off state. This parameter is specific to + gpio and backlight triggers. In case of the backlight trigger, + it is usefull when driving a LED which is intended to indicate + a device in a standby like state. diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c index f948e57bd9b8..2b513a2ad7de 100644 --- a/drivers/leds/ledtrig-backlight.c +++ b/drivers/leds/ledtrig-backlight.c @@ -26,6 +26,7 @@ struct bl_trig_notifier { int brightness; int old_status; struct notifier_block notifier; + unsigned invert; }; static int fb_notifier_callback(struct notifier_block *p, @@ -36,23 +37,64 @@ static int fb_notifier_callback(struct notifier_block *p, struct led_classdev *led = n->led; struct fb_event *fb_event = data; int *blank = fb_event->data; + int new_status = *blank ? BLANK : UNBLANK; switch (event) { case FB_EVENT_BLANK : - if (*blank && n->old_status == UNBLANK) { + if (new_status == n->old_status) + break; + + if ((n->old_status == UNBLANK) ^ n->invert) { n->brightness = led->brightness; led_set_brightness(led, LED_OFF); - n->old_status = BLANK; - } else if (!*blank && n->old_status == BLANK) { + } else { led_set_brightness(led, n->brightness); - n->old_status = UNBLANK; } + + n->old_status = new_status; + break; } return 0; } +static ssize_t bl_trig_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led = dev_get_drvdata(dev); + struct bl_trig_notifier *n = led->trigger_data; + + return sprintf(buf, "%u\n", n->invert); +} + +static ssize_t bl_trig_invert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t num) +{ + struct led_classdev *led = dev_get_drvdata(dev); + struct bl_trig_notifier *n = led->trigger_data; + unsigned long invert; + int ret; + + ret = strict_strtoul(buf, 10, &invert); + if (ret < 0) + return ret; + + if (invert > 1) + return -EINVAL; + + n->invert = invert; + + /* After inverting, we need to update the LED. */ + if ((n->old_status == BLANK) ^ n->invert) + led_set_brightness(led, LED_OFF); + else + led_set_brightness(led, n->brightness); + + return num; +} +static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store); + static void bl_trig_activate(struct led_classdev *led) { int ret; @@ -66,6 +108,10 @@ static void bl_trig_activate(struct led_classdev *led) return; } + ret = device_create_file(led->dev, &dev_attr_inverted); + if (ret) + goto err_invert; + n->led = led; n->brightness = led->brightness; n->old_status = UNBLANK; @@ -74,6 +120,12 @@ static void bl_trig_activate(struct led_classdev *led) ret = fb_register_client(&n->notifier); if (ret) dev_err(led->dev, "unable to register backlight trigger\n"); + + return; + +err_invert: + led->trigger_data = NULL; + kfree(n); } static void bl_trig_deactivate(struct led_classdev *led) @@ -82,6 +134,7 @@ static void bl_trig_deactivate(struct led_classdev *led) (struct bl_trig_notifier *) led->trigger_data; if (n) { + device_remove_file(led->dev, &dev_attr_inverted); fb_unregister_client(&n->notifier); kfree(n); } -- cgit v1.2.3 From 5c2202f9c8202b89ae9ba4233a0d281f300474b9 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 12 Jan 2011 16:59:21 -0800 Subject: drivers/video/backlight/l4f00242t03.c: make 1-bit signed field unsigned Fixes sparse warning: drivers/video/backlight/l4f00242t03.c:28:21: error: dubious one-bit signed bitfield Signed-off-by: Mariusz Kozlowski Acked-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/l4f00242t03.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index c67801e57aaf..6d9ba0e2b0c5 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -25,7 +25,7 @@ struct l4f00242t03_priv { struct spi_device *spi; struct lcd_device *ld; - int lcd_on:1; + unsigned int lcd_on:1; struct regulator *io_reg; struct regulator *core_reg; }; -- cgit v1.2.3 From 95558ad15b2b679fb8b312d3fd637acea854ba2f Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Wed, 12 Jan 2011 16:59:22 -0800 Subject: drivers/video/backlight/l4f00242t03.c: full implement fb power states for this lcd Complete the support of fb power states managing correctly the regulators bound to this driver. Signed-off-by: Alberto Panizzo Cc: Richard Purdie Cc: Marek Vasut Cc: Tejun Heo Cc: Axel Lin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/l4f00242t03.c | 97 +++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 6d9ba0e2b0c5..5d25743bf8e2 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -25,7 +25,7 @@ struct l4f00242t03_priv { struct spi_device *spi; struct lcd_device *ld; - unsigned int lcd_on:1; + int lcd_state; struct regulator *io_reg; struct regulator *core_reg; }; @@ -67,6 +67,29 @@ static void l4f00242t03_lcd_init(struct spi_device *spi) spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16)); } +static void l4f00242t03_lcd_powerdown(struct spi_device *spi) +{ + struct l4f00242t03_pdata *pdata = spi->dev.platform_data; + struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "Powering down LCD\n"); + + gpio_set_value(pdata->data_enable_gpio, 0); + + if (priv->io_reg) + regulator_disable(priv->io_reg); + + if (priv->core_reg) + regulator_disable(priv->core_reg); +} + +static int l4f00242t03_lcd_power_get(struct lcd_device *ld) +{ + struct l4f00242t03_priv *priv = lcd_get_data(ld); + + return priv->lcd_state; +} + static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) { struct l4f00242t03_priv *priv = lcd_get_data(ld); @@ -79,35 +102,52 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) const u16 disoff = 0x28; if (power <= FB_BLANK_NORMAL) { - if (priv->lcd_on) - return 0; - - dev_dbg(&spi->dev, "turning on LCD\n"); - - spi_write(spi, (const u8 *)&slpout, sizeof(u16)); - msleep(60); - spi_write(spi, (const u8 *)&dison, sizeof(u16)); - - priv->lcd_on = 1; + if (priv->lcd_state <= FB_BLANK_NORMAL) { + /* Do nothing, the LCD is running */ + } else if (priv->lcd_state < FB_BLANK_POWERDOWN) { + dev_dbg(&spi->dev, "Resuming LCD\n"); + + spi_write(spi, (const u8 *)&slpout, sizeof(u16)); + msleep(60); + spi_write(spi, (const u8 *)&dison, sizeof(u16)); + } else { + /* priv->lcd_state == FB_BLANK_POWERDOWN */ + l4f00242t03_lcd_init(spi); + priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; + l4f00242t03_lcd_power_set(priv->ld, power); + } + } else if (power < FB_BLANK_POWERDOWN) { + if (priv->lcd_state <= FB_BLANK_NORMAL) { + /* Send the display in standby */ + dev_dbg(&spi->dev, "Standby the LCD\n"); + + spi_write(spi, (const u8 *)&disoff, sizeof(u16)); + msleep(60); + spi_write(spi, (const u8 *)&slpin, sizeof(u16)); + } else if (priv->lcd_state < FB_BLANK_POWERDOWN) { + /* Do nothing, the LCD is already in standby */ + } else { + /* priv->lcd_state == FB_BLANK_POWERDOWN */ + l4f00242t03_lcd_init(spi); + priv->lcd_state = FB_BLANK_UNBLANK; + l4f00242t03_lcd_power_set(ld, power); + } } else { - if (!priv->lcd_on) - return 0; - - dev_dbg(&spi->dev, "turning off LCD\n"); - + /* power == FB_BLANK_POWERDOWN */ + /* Clear the screen before shutting down */ spi_write(spi, (const u8 *)&disoff, sizeof(u16)); msleep(60); - spi_write(spi, (const u8 *)&slpin, sizeof(u16)); - - priv->lcd_on = 0; + l4f00242t03_lcd_powerdown(spi); } + priv->lcd_state = power; + return 0; } static struct lcd_ops l4f_ops = { .set_power = l4f00242t03_lcd_power_set, - .get_power = NULL, + .get_power = l4f00242t03_lcd_power_get, }; static int __devinit l4f00242t03_probe(struct spi_device *spi) @@ -187,7 +227,8 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) /* Init the LCD */ l4f00242t03_reset(pdata->reset_gpio); l4f00242t03_lcd_init(spi); - l4f00242t03_lcd_power_set(priv->ld, 1); + priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; + l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_UNBLANK); dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n"); @@ -214,9 +255,11 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data; - l4f00242t03_lcd_power_set(priv->ld, 0); + l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); lcd_device_unregister(priv->ld); + dev_set_drvdata(&spi->dev, NULL); + gpio_free(pdata->data_enable_gpio); gpio_free(pdata->reset_gpio); @@ -230,6 +273,15 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) return 0; } +static void l4f00242t03_shutdown(struct spi_device *spi) +{ + struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + + if (priv) + l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); + +} + static struct spi_driver l4f00242t03_driver = { .driver = { .name = "l4f00242t03", @@ -237,6 +289,7 @@ static struct spi_driver l4f00242t03_driver = { }, .probe = l4f00242t03_probe, .remove = __devexit_p(l4f00242t03_remove), + .shutdown = l4f00242t03_shutdown, }; static __init int l4f00242t03_init(void) -- cgit v1.2.3 From 26bbabc8e80b4b9e42aca13376a2c1609a880e21 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Wed, 12 Jan 2011 16:59:23 -0800 Subject: drivers/video/backlight/l4f00242t03.c: prevent unbalanced calls to regulator enable/disable Otherwise a double call to: $ echo 4 > /sys/class/lcd/l4f00242t03/lcd_power Will, the first power down the lcd and regulators correctly and the second produce an unbalanced call to regulator disable. Signed-off-by: Alberto Panizzo Cc: Richard Purdie Cc: Marek Vasut Cc: Tejun Heo Cc: Axel Lin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/l4f00242t03.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 5d25743bf8e2..1fcaaf3d78e1 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -134,10 +134,12 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) } } else { /* power == FB_BLANK_POWERDOWN */ - /* Clear the screen before shutting down */ - spi_write(spi, (const u8 *)&disoff, sizeof(u16)); - msleep(60); - l4f00242t03_lcd_powerdown(spi); + if (priv->lcd_state != FB_BLANK_POWERDOWN) { + /* Clear the screen before shutting down */ + spi_write(spi, (const u8 *)&disoff, sizeof(u16)); + msleep(60); + l4f00242t03_lcd_powerdown(spi); + } } priv->lcd_state = power; -- cgit v1.2.3 From aff5ce6ca8d25c7dbcd886e2e51dd081981af95e Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Wed, 12 Jan 2011 16:59:24 -0800 Subject: drivers/video/backlight/l4f00242t03.c: fix reset sequence The reset command is part of the init sequence and it take effect only if the lcd is powered. The effect of the bug was that the sequence: set lcd power_state to FB_BLANK_POWERDOWN set lcd power_state to FB_BLANK_UNBLANK Did not produced a complete reboot of the LCD which was showing fuzzy colours. This was not experienced before implementing correctly all the LCD power states with the patch [1]. Since before the patch [1] the regulators were not touched and the LCD shutdown was reached with a register write. After the patch [1] a complete boot sequence with an initial reset is needed for the display every time the LCD is powered up. drivers-video-backlight-l4f00242t03c-full-implement-fb-power-states-for-this-lcd.patch Signed-off-by: Alberto Panizzo Cc: Richard Purdie Cc: Marek Vasut Cc: Tejun Heo Cc: Axel Lin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/l4f00242t03.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 1fcaaf3d78e1..98ad3e5f7c85 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -62,6 +62,8 @@ static void l4f00242t03_lcd_init(struct spi_device *spi) regulator_enable(priv->core_reg); } + l4f00242t03_reset(pdata->reset_gpio); + gpio_set_value(pdata->data_enable_gpio, 1); msleep(60); spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16)); @@ -227,7 +229,6 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) } /* Init the LCD */ - l4f00242t03_reset(pdata->reset_gpio); l4f00242t03_lcd_init(spi); priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_UNBLANK); -- cgit v1.2.3 From fc2d557c74dc58294b9acc7231a2113ae59af97c Mon Sep 17 00:00:00 2001 From: Seiji Aguchi Date: Wed, 12 Jan 2011 16:59:29 -0800 Subject: kmsg_dump: constrain mtdoops and ramoops to perform their actions only for KMSG_DUMP_PANIC This series aims to develop logging facility for enterprise use. It is important to save kernel messages reliably on enterprise system because they are helpful for diagnosing system. This series add kmsg_dump() to the paths loosing kernel messages. The use case is the following. [Use case of reboot/poweroff/halt/emergency_restart] My company has often experienced the followings in our support service. - Customer's system suddenly reboots. - Customers ask us to investigate the reason of the reboot. We recognize the fact itself because boot messages remain in /var/log/messages. However, we can't investigate the reason why the system rebooted, because the last messages don't remain. And off course we can't explain the reason. We can solve above problem with this patch as follows. Case1: reboot with command - We can see "Restarting system with command:" or ""Restarting system.". Case2: halt with command - We can see "System halted.". Case3: poweroff with command - We can see " Power down.". Case4: emergency_restart with sysrq. - We can see "Sysrq:" outputted in __handle_sysrq(). Case5: emergency_restart with softdog. - We can see "Initiating system reboot" in watchdog_fire(). So, we can distinguish the reason of reboot, poweroff, halt and emergency_restart. If customer executed reboot command, you may think the customer should know the fact. However, they often claim they don't execute the command when they rebooted system by mistake. No message remains on the current Linux kernel, so we can't show the proof to the customer. This patch improves this situation. This patch: Alters mtdoops and ramoops to perform their actions only for KMSG_DUMP_PANIC, KMSG_DUMP_OOPS and KMSG_DUMP_KEXEC because they would like to log crashes only. Signed-off-by: Seiji Aguchi Cc: David Woodhouse Cc: Marco Stornelli Reviewed-by: Artem Bityutskiy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ramoops.c | 5 +++++ drivers/mtd/mtdoops.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index d3d63be2cd37..eeec5758f9c4 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -68,6 +68,11 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, char *buf, *buf_orig; struct timeval timestamp; + if (reason != KMSG_DUMP_OOPS && + reason != KMSG_DUMP_PANIC && + reason != KMSG_DUMP_KEXEC) + return; + /* Only dump oopses if dump_oops is set */ if (reason == KMSG_DUMP_OOPS && !dump_oops) return; diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 1ee72f3f0512..c948150079be 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -307,6 +307,11 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper, unsigned long l1_cpy, l2_cpy; char *dst; + if (reason != KMSG_DUMP_OOPS && + reason != KMSG_DUMP_PANIC && + reason != KMSG_DUMP_KEXEC) + return; + /* Only dump oopses if dump_oops is set */ if (reason == KMSG_DUMP_OOPS && !dump_oops) return; -- cgit v1.2.3 From f0f2c2b5b40b5e621a47a6a274117cce77841f1e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Jan 2011 16:59:42 -0800 Subject: dca: remove unneeded NULL check The return here doesn't release the locks or re-enable IRQs. But as Andrew Morton points out, domain is never NULL. list_first_entry() essentially never returns NULL and also we already verified that the list is not empty. Signed-off-by: Dan Carpenter Acked-by: Maciej Sosnowski Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/dca/dca-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index b98c67664ae7..c461eda62411 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -110,8 +110,6 @@ static void unregister_dca_providers(void) /* at this point only one domain in the list is expected */ domain = list_first_entry(&dca_domains, struct dca_domain, node); - if (!domain) - return; list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) { list_del(&dca->node); -- cgit v1.2.3 From 554ec37aca8f5fbe4d70df462d7032aaa5d95ae9 Mon Sep 17 00:00:00 2001 From: Yannick Heneault Date: Wed, 12 Jan 2011 17:00:04 -0800 Subject: vgacon: check for efi machine It seems there is a small problem of VGA palette corruption on EFI machine. When the kernel initializes the architecture, it checks if the machine is a EFI machine and assumes that a VGA console can exist. When it initializes the console in vgacon_startup it checks if it can really use the VGA console. I think this is where a check is missing. Currently, the function can fail if a VESA boot mode is detected but not if a EFI boot mode was used. Thus vgacon_startup() doesn't fail and initialize the video card for a real VGA mode. This function changes the first 16entries of the VGA palette. When the efifb driver kicks in, the palette is not restored to default ramp value, thus the 16 first entry remain in a modified state. The following patch prevent this corruption. Signed-off-by: Yannick Heneault Cc: Dave Airlie Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/vgacon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 915448ec75bf..c97491b8b39b 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -375,7 +375,8 @@ static const char *vgacon_startup(void) u16 saved1, saved2; volatile u16 *p; - if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) { + if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB || + screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) { no_vga: #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; -- cgit v1.2.3 From 19412ce9fcc9ca2d0f5b62af15c63381f0ac9657 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Jan 2011 17:00:05 -0800 Subject: drivers/rtc/rtc-omap.c: fix a memory leak request_mem_region() will call kzalloc to allocate memory for struct resource. release_resource() unregisters the resource but does not free the allocated memory, thus use release_mem_region() instead to fix the memory leak. Also add a missing iounmap() in omap_rtc_remove(). Signed-off-by: Axel Lin Cc: Alessandro Zummo Cc: Sekhar Nori Cc: Kevin Hilman Cc: Tony Lindgren Acked-by: Mark A. Greer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-omap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 73377b0d65da..e72b523c79a5 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -429,13 +429,14 @@ fail1: fail0: iounmap(rtc_base); fail: - release_resource(mem); + release_mem_region(mem->start, resource_size(mem)); return -EIO; } static int __exit omap_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); + struct resource *mem = dev_get_drvdata(&rtc->dev); device_init_wakeup(&pdev->dev, 0); @@ -447,8 +448,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) if (omap_rtc_timer != omap_rtc_alarm) free_irq(omap_rtc_alarm, rtc); - release_resource(dev_get_drvdata(&rtc->dev)); rtc_device_unregister(rtc); + iounmap(rtc_base); + release_mem_region(mem->start, resource_size(mem)); return 0; } -- cgit v1.2.3 From 2fb08e6ca9f00d1aedb3964983e9c8f84b36b807 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Wed, 12 Jan 2011 17:00:07 -0800 Subject: rtc-cmos: fix suspend/resume rtc-cmos was setting suspend/resume hooks at the device_driver level. However, the platform bus code (drivers/base/platform.c) only looks for resume hooks at the dev_pm_ops level, or within the platform_driver. Switch rtc_cmos to use dev_pm_ops so that suspend/resume code is executed again. Paul said: : The user visible symptom in our (XO laptop) case was that rtcwake would : fail to wake the laptop. The RTC alarm would expire, but the wakeup : wasn't unmasked. : : As for severity, the impact may have been reduced because if I recall : correctly, the bug only affected platforms with CONFIG_PNP disabled. Signed-off-by: Paul Fox Signed-off-by: Daniel Drake Acked-by: Rafael J. Wysocki Cc: [2.6.37.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-cmos.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 7e6ce626b7f1..c7ff8df347e7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -36,6 +36,7 @@ #include #include #include +#include /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include @@ -851,7 +852,7 @@ static void __exit cmos_do_remove(struct device *dev) #ifdef CONFIG_PM -static int cmos_suspend(struct device *dev, pm_message_t mesg) +static int cmos_suspend(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp; @@ -899,7 +900,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) */ static inline int cmos_poweroff(struct device *dev) { - return cmos_suspend(dev, PMSG_HIBERNATE); + return cmos_suspend(dev); } static int cmos_resume(struct device *dev) @@ -946,9 +947,9 @@ static int cmos_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); + #else -#define cmos_suspend NULL -#define cmos_resume NULL static inline int cmos_poweroff(struct device *dev) { @@ -1078,7 +1079,7 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp) static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg) { - return cmos_suspend(&pnp->dev, mesg); + return cmos_suspend(&pnp->dev); } static int cmos_pnp_resume(struct pnp_dev *pnp) @@ -1158,8 +1159,9 @@ static struct platform_driver cmos_platform_driver = { .shutdown = cmos_platform_shutdown, .driver = { .name = (char *) driver_name, - .suspend = cmos_suspend, - .resume = cmos_resume, +#ifdef CONFIG_PM + .pm = &cmos_pm_ops, +#endif } }; -- cgit v1.2.3 From 5f003feba2a8761d2ee7b367df5a0fe6b729dc8f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Jan 2011 17:00:09 -0800 Subject: rtc: rtc-max6902 - set driver data in max6902_probe() Current implementation does not set driver data in max6902_probe(), thus calling platform_get_drvdata(spi) in max6902_remove() returns NULL. Signed-off-by: Axel Lin Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-max6902.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 657403ebd54a..0ec3f588a255 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -139,12 +139,13 @@ static int __devinit max6902_probe(struct spi_device *spi) if (IS_ERR(rtc)) return PTR_ERR(rtc); + dev_set_drvdata(&spi->dev, rtc); return 0; } static int __devexit max6902_remove(struct spi_device *spi) { - struct rtc_device *rtc = platform_get_drvdata(spi); + struct rtc_device *rtc = dev_get_drvdata(&spi->dev); rtc_device_unregister(rtc); return 0; -- cgit v1.2.3 From 1b912c1bca5c162e611384fe7d39c916e081701a Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 12 Jan 2011 17:00:10 -0800 Subject: drivers/gpio/cs5535-gpio.c: add some additional cs5535-specific GPIO functionality This adds (well, re-adds actually) handling for events/IRQs through cs5535 GPIOs. In the wild and wooly world of CS5535, setup_event() is for assigning an IRQ to a GPIO filter/event pair, and set_irq() sets up the pair to trigger IRQs. These should really only be used in highly platform-specific drivers (such as OLPC's DCON driver). Sadly, because set_irq() uses MSRs, this causes the driver to become X86-specific. Signed-off-by: Andres Salomon Signed-off-by: Daniel Drake Cc: Grant Likely Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/Kconfig | 2 +- drivers/gpio/cs5535-gpio.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/cs5535.h | 2 ++ 3 files changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 082495bb08a7..bfa276a95411 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -295,7 +295,7 @@ comment "PCI GPIO expanders:" config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" - depends on PCI && !CS5535_GPIO + depends on PCI && X86 && !CS5535_GPIO help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that can be used for quite a number of things. The CS5535/6 is found on diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index d3e55a0ae92b..815d98b2c1ba 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -15,6 +15,7 @@ #include #include #include +#include #define DRV_NAME "cs5535-gpio" #define GPIO_BAR 1 @@ -144,6 +145,57 @@ int cs5535_gpio_isset(unsigned offset, unsigned int reg) } EXPORT_SYMBOL_GPL(cs5535_gpio_isset); +int cs5535_gpio_set_irq(unsigned group, unsigned irq) +{ + uint32_t lo, hi; + + if (group > 7 || irq > 15) + return -EINVAL; + + rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi); + + lo &= ~(0xF << (group * 4)); + lo |= (irq & 0xF) << (group * 4); + + wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi); + return 0; +} +EXPORT_SYMBOL_GPL(cs5535_gpio_set_irq); + +void cs5535_gpio_setup_event(unsigned offset, int pair, int pme) +{ + struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; + uint32_t shift = (offset % 8) * 4; + unsigned long flags; + uint32_t val; + + if (offset >= 24) + offset = GPIO_MAP_W; + else if (offset >= 16) + offset = GPIO_MAP_Z; + else if (offset >= 8) + offset = GPIO_MAP_Y; + else + offset = GPIO_MAP_X; + + spin_lock_irqsave(&chip->lock, flags); + val = inl(chip->base + offset); + + /* Clear whatever was there before */ + val &= ~(0xF << shift); + + /* Set the new value */ + val |= ((pair & 7) << shift); + + /* Set the PME bit if this is a PME event */ + if (pme) + val |= (1 << (shift + 3)); + + outl(val, chip->base + offset); + spin_unlock_irqrestore(&chip->lock, flags); +} +EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event); + /* * Generic gpio_chip API support. */ diff --git a/include/linux/cs5535.h b/include/linux/cs5535.h index d5a1d4810b80..213cc50b5809 100644 --- a/include/linux/cs5535.h +++ b/include/linux/cs5535.h @@ -111,6 +111,8 @@ static inline int cs5535_has_vsa2(void) void cs5535_gpio_set(unsigned offset, unsigned int reg); void cs5535_gpio_clear(unsigned offset, unsigned int reg); int cs5535_gpio_isset(unsigned offset, unsigned int reg); +int cs5535_gpio_set_irq(unsigned group, unsigned irq); +void cs5535_gpio_setup_event(unsigned offset, int pair, int pme); /* MFGPTs */ -- cgit v1.2.3 From 7637c9259f7b6dd841471ccf1120d484b7364f99 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 12 Jan 2011 17:00:11 -0800 Subject: drivers/staging/olpc_dcon: convert to new cs5535 gpio API Drop the old geode_gpio crud, as well as the raw outl() calls; instead, use the Linux GPIO API where possible, and the cs5535_gpio API in other places. Note that we don't actually clean up the driver properly yet (once loaded, it always remains loaded). That'll come later.. This patch is necessary for building the driver. Signed-off-by: Andres Salomon Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/include/asm/olpc.h | 10 +- drivers/staging/olpc_dcon/TODO | 1 - drivers/staging/olpc_dcon/olpc_dcon.c | 3 +- drivers/staging/olpc_dcon/olpc_dcon.h | 20 ---- drivers/staging/olpc_dcon/olpc_dcon_xo_1.c | 168 ++++++++++++++++----------- drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c | 4 +- include/linux/cs5535.h | 4 + 7 files changed, 114 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h index 42a978c0c1b3..f482010350fb 100644 --- a/arch/x86/include/asm/olpc.h +++ b/arch/x86/include/asm/olpc.h @@ -107,10 +107,14 @@ extern int olpc_ec_mask_unset(uint8_t bits); /* GPIO assignments */ #define OLPC_GPIO_MIC_AC 1 -#define OLPC_GPIO_DCON_IRQ geode_gpio(7) +#define OLPC_GPIO_DCON_STAT0 5 +#define OLPC_GPIO_DCON_STAT1 6 +#define OLPC_GPIO_DCON_IRQ 7 #define OLPC_GPIO_THRM_ALRM geode_gpio(10) -#define OLPC_GPIO_SMB_CLK geode_gpio(14) -#define OLPC_GPIO_SMB_DATA geode_gpio(15) +#define OLPC_GPIO_DCON_LOAD 11 +#define OLPC_GPIO_DCON_BLANK 12 +#define OLPC_GPIO_SMB_CLK 14 +#define OLPC_GPIO_SMB_DATA 15 #define OLPC_GPIO_WORKAUX geode_gpio(24) #define OLPC_GPIO_LID geode_gpio(26) #define OLPC_GPIO_ECSCI geode_gpio(27) diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO index ac2d3d023715..35f9cda7be11 100644 --- a/drivers/staging/olpc_dcon/TODO +++ b/drivers/staging/olpc_dcon/TODO @@ -1,6 +1,5 @@ TODO: - checkpatch.pl cleanups - - port geode gpio calls to newer cs5535 API - see if vx855 gpio API can be made similar enough to cs5535 so we can share more code - allow simultaneous XO-1 and XO-1.5 support diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 4ca45ec7fd84..da040c12fbf9 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -49,7 +48,7 @@ struct dcon_platform_data { int (*init)(void); void (*bus_stabilize_wiggle)(void); void (*set_dconload)(int); - int (*read_status)(void); + u8 (*read_status)(void); }; static struct dcon_platform_data *pdata; diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h index 6453ca4ba0ee..e566d213da2a 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.h +++ b/drivers/staging/olpc_dcon/olpc_dcon.h @@ -29,26 +29,6 @@ #define DCON_REG_SCAN_INT 9 #define DCON_REG_BRIGHT 10 -/* GPIO registers (CS5536) */ - -#define MSR_LBAR_GPIO 0x5140000C - -#define GPIOx_OUT_VAL 0x00 -#define GPIOx_OUT_EN 0x04 -#define GPIOx_IN_EN 0x20 -#define GPIOx_INV_EN 0x24 -#define GPIOx_IN_FLTR_EN 0x28 -#define GPIOx_EVNTCNT_EN 0x2C -#define GPIOx_READ_BACK 0x30 -#define GPIOx_EVNT_EN 0x38 -#define GPIOx_NEGEDGE_EN 0x44 -#define GPIOx_NEGEDGE_STS 0x4C -#define GPIO_FLT7_AMNT 0xD8 -#define GPIO_MAP_X 0xE0 -#define GPIO_MAP_Y 0xE4 -#define GPIO_FE7_SEL 0xF7 - - /* Status values */ #define DCONSTAT_SCANINT 0 diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index 779fb7d7b30c..043198dc6ff7 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -10,54 +10,70 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ - +#include +#include #include #include "olpc_dcon.h" -/* Base address of the GPIO registers */ -static unsigned long gpio_base; - -/* - * List of GPIOs that we care about: - * (in) GPIO12 -- DCONBLANK - * (in) GPIO[56] -- DCONSTAT[01] - * (out) GPIO11 -- DCONLOAD - */ - -#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12)) -#define OUT_GPIOS (1<<11) - static int dcon_init_xo_1(void) { - unsigned long lo, hi; unsigned char lob; - rdmsr(MSR_LBAR_GPIO, lo, hi); - - /* Check the mask and whether GPIO is enabled (sanity check) */ - if (hi != 0x0000f001) { - printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n"); - return -ENODEV; + if (gpio_request(OLPC_GPIO_DCON_STAT0, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request STAT0 GPIO\n"); + return -EIO; + } + if (gpio_request(OLPC_GPIO_DCON_STAT1, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request STAT1 GPIO\n"); + goto err_gp_stat1; + } + if (gpio_request(OLPC_GPIO_DCON_IRQ, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request IRQ GPIO\n"); + goto err_gp_irq; + } + if (gpio_request(OLPC_GPIO_DCON_LOAD, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request LOAD GPIO\n"); + goto err_gp_load; + } + if (gpio_request(OLPC_GPIO_DCON_BLANK, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request BLANK GPIO\n"); + goto err_gp_blank; } - - /* Mask off the IO base address */ - gpio_base = lo & 0x0000ff00; /* Turn off the event enable for GPIO7 just to be safe */ - outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); + + /* + * Determine the current state by reading the GPIO bit; earlier + * stages of the boot process have established the state. + * + * Note that we read GPIO_OUPUT_VAL rather than GPIO_READ_BACK here; + * this is because OFW will disable input for the pin and set a value.. + * READ_BACK will only contain a valid value if input is enabled and + * then a value is set. So, future readings of the pin can use + * READ_BACK, but the first one cannot. Awesome, huh? + */ + dcon_source = cs5535_gpio_isset(OLPC_GPIO_DCON_LOAD, GPIO_OUTPUT_VAL) + ? DCON_SOURCE_CPU + : DCON_SOURCE_DCON; + dcon_pending = dcon_source; /* Set the directions for the GPIO pins */ - outl(OUT_GPIOS | (IN_GPIOS << 16), gpio_base + GPIOx_OUT_EN); - outl(IN_GPIOS | (OUT_GPIOS << 16), gpio_base + GPIOx_IN_EN); + gpio_direction_input(OLPC_GPIO_DCON_STAT0); + gpio_direction_input(OLPC_GPIO_DCON_STAT1); + gpio_direction_input(OLPC_GPIO_DCON_IRQ); + gpio_direction_input(OLPC_GPIO_DCON_BLANK); + gpio_direction_output(OLPC_GPIO_DCON_LOAD, + dcon_source == DCON_SOURCE_CPU); /* Set up the interrupt mappings */ /* Set the IRQ to pair 2 */ - geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2); + cs5535_gpio_setup_event(OLPC_GPIO_DCON_IRQ, 2, 0); /* Enable group 2 to trigger the DCON interrupt */ - geode_gpio_set_irq(2, DCON_IRQ); + cs5535_gpio_set_irq(2, DCON_IRQ); /* Select edge level for interrupt (in PIC) */ lob = inb(0x4d0); @@ -65,52 +81,61 @@ static int dcon_init_xo_1(void) outb(lob, 0x4d0); /* Register the interupt handler */ - if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver)) - return -EIO; + if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver)) { + printk(KERN_ERR "olpc-dcon: failed to request DCON's irq\n"); + goto err_req_irq; + } /* Clear INV_EN for GPIO7 (DCONIRQ) */ - outl((1<<(16+7)), gpio_base + GPIOx_INV_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_INVERT); /* Enable filter for GPIO12 (DCONBLANK) */ - outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_FILTER); /* Disable filter for GPIO7 */ - outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_FILTER); /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ - - outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN); - outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_EVENT_COUNT); + cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_EVENT_COUNT); /* Add GPIO12 to the Filter Event Pair #7 */ - outb(12, gpio_base + GPIO_FE7_SEL); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_FE7_SEL); /* Turn off negative Edge Enable for GPIO12 */ - outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_EN); /* Enable negative Edge Enable for GPIO7 */ - outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_EN); /* Zero the filter amount for Filter Event Pair #7 */ - outw(0, gpio_base + GPIO_FLT7_AMNT); + cs5535_gpio_set(0, GPIO_FLTR7_AMOUNT); /* Clear the negative edge status for GPIO7 and GPIO12 */ - outl((1<<7) | (1<<12), gpio_base+0x4c); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS); /* FIXME: Clear the posiitive status as well, just to be sure */ - outl((1<<7) | (1<<12), gpio_base+0x48); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS); /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ - outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN); - - /* Determine the current state by reading the GPIO bit */ - /* Earlier stages of the boot process have established the state */ - dcon_source = inl(gpio_base + GPIOx_OUT_VAL) & (1<<11) - ? DCON_SOURCE_CPU - : DCON_SOURCE_DCON; - dcon_pending = dcon_source; + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_EVENTS_ENABLE); return 0; + +err_req_irq: + gpio_free(OLPC_GPIO_DCON_BLANK); +err_gp_blank: + gpio_free(OLPC_GPIO_DCON_LOAD); +err_gp_load: + gpio_free(OLPC_GPIO_DCON_IRQ); +err_gp_irq: + gpio_free(OLPC_GPIO_DCON_STAT1); +err_gp_stat1: + gpio_free(OLPC_GPIO_DCON_STAT0); + return -EIO; } static void dcon_wiggle_xo_1(void) @@ -128,37 +153,44 @@ static void dcon_wiggle_xo_1(void) * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and * GPIO15. */ - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL); - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE); - geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); - geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2); - geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_ENABLE); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX2); + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); for (x = 0; x < 16; x++) { udelay(5); - geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); udelay(5); - geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); } udelay(5); - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); } static void dcon_set_dconload_1(int val) { - if (val) - outl(1<<11, gpio_base + GPIOx_OUT_VAL); - else - outl(1<<(11 + 16), gpio_base + GPIOx_OUT_VAL); + gpio_set_value(OLPC_GPIO_DCON_LOAD, val); } -static int dcon_read_status_xo_1(void) +static u8 dcon_read_status_xo_1(void) { - int status = inl(gpio_base + GPIOx_READ_BACK) >> 5; - + u8 status; + + status = gpio_get_value(OLPC_GPIO_DCON_STAT0); + status |= gpio_get_value(OLPC_GPIO_DCON_STAT1) << 1; + /* Clear the negative edge status for GPIO7 */ - outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); return status; } diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c index cca6a235ef96..4f56098bb366 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c @@ -195,9 +195,9 @@ static void dcon_set_dconload_xo_1_5(int val) } } -static int dcon_read_status_xo_1_5(void) +static u8 dcon_read_status_xo_1_5(void) { - int status; + u8 status; if (!dcon_was_irq()) return -1; diff --git a/include/linux/cs5535.h b/include/linux/cs5535.h index 213cc50b5809..6fe2114f8ad2 100644 --- a/include/linux/cs5535.h +++ b/include/linux/cs5535.h @@ -103,11 +103,15 @@ static inline int cs5535_has_vsa2(void) #define GPIO_POSITIVE_EDGE_STS 0x48 #define GPIO_NEGATIVE_EDGE_STS 0x4C +#define GPIO_FLTR7_AMOUNT 0xD8 + #define GPIO_MAP_X 0xE0 #define GPIO_MAP_Y 0xE4 #define GPIO_MAP_Z 0xE8 #define GPIO_MAP_W 0xEC +#define GPIO_FE7_SEL 0xF7 + void cs5535_gpio_set(unsigned offset, unsigned int reg); void cs5535_gpio_clear(unsigned offset, unsigned int reg); int cs5535_gpio_isset(unsigned offset, unsigned int reg); -- cgit v1.2.3 From cf8e9086de5daf14dbf0be9efef7d2793f256693 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 12 Jan 2011 17:00:12 -0800 Subject: cs5535: deprecate older cs5535_gpio driver The newer drivers/gpio/cs5535-gpio.c replaces drivers/misc/cs5535_gpio.c. The new driver has been in the tree for a little while, and has received some testing; it's time to mark the old one as deprecated. I'm thinking removal around 2.6.40 would be good, provided we're not missing critical functionality in the newer driver. Signed-off-by: Andres Salomon Cc: Daniel Drake Acked-by: Ben Gardner Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 14 ++ drivers/char/Kconfig | 9 - drivers/char/Makefile | 1 - drivers/char/cs5535_gpio.c | 259 ----------------------------- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/cs5535_gpio/Kconfig | 11 ++ drivers/staging/cs5535_gpio/Makefile | 1 + drivers/staging/cs5535_gpio/TODO | 6 + drivers/staging/cs5535_gpio/cs5535_gpio.c | 259 +++++++++++++++++++++++++++++ 10 files changed, 294 insertions(+), 269 deletions(-) delete mode 100644 drivers/char/cs5535_gpio.c create mode 100644 drivers/staging/cs5535_gpio/Kconfig create mode 100644 drivers/staging/cs5535_gpio/Makefile create mode 100644 drivers/staging/cs5535_gpio/TODO create mode 100644 drivers/staging/cs5535_gpio/cs5535_gpio.c (limited to 'drivers') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 22f10818c2b3..07eb3f624998 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -193,6 +193,20 @@ Why: /proc//oom_adj allows userspace to influence the oom killer's --------------------------- +What: CS5535/CS5536 obsolete GPIO driver +When: June 2011 +Files: drivers/staging/cs5535_gpio/* +Check: drivers/staging/cs5535_gpio/cs5535_gpio.c +Why: A newer driver replaces this; it is drivers/gpio/cs5535-gpio.c, and + integrates with the Linux GPIO subsystem. The old driver has been + moved to staging, and will be removed altogether around 2.6.40. + Please test the new driver, and ensure that the functionality you + need and any bugfixes from the old driver are available in the new + one. +Who: Andres Salomon + +-------------------------- + What: remove EXPORT_SYMBOL(kernel_thread) When: August 2006 Files: arch/*/kernel/*_ksyms.c diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d4a7776f4b77..0f175a866ef0 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1047,15 +1047,6 @@ config NSC_GPIO pc8736x_gpio drivers. If those drivers are built as modules, this one will be too, named nsc_gpio -config CS5535_GPIO - tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" - depends on X86_32 - help - Give userspace access to the GPIO pins on the AMD CS5535 and - CS5536 Geode companion devices. - - If compiled as a module, it will be called cs5535_gpio. - config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN)" depends on BLOCK diff --git a/drivers/char/Makefile b/drivers/char/Makefile index fa0b824b7a65..1e9dffb33778 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -82,7 +82,6 @@ obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o -obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c deleted file mode 100644 index 0cf1e5fad9ab..000000000000 --- a/drivers/char/cs5535_gpio.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * AMD CS5535/CS5536 GPIO driver. - * Allows a user space process to play with the GPIO pins. - * - * Copyright (c) 2005 Ben Gardner - * - * This program is free software; you can redistribute it and/or modify - * it under the smems of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -#define NAME "cs5535_gpio" - -MODULE_AUTHOR("Ben Gardner "); -MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO Pin Driver"); -MODULE_LICENSE("GPL"); - -static int major; -module_param(major, int, 0); -MODULE_PARM_DESC(major, "Major device number"); - -static ulong mask; -module_param(mask, ulong, 0); -MODULE_PARM_DESC(mask, "GPIO channel mask"); - -#define MSR_LBAR_GPIO 0x5140000C - -static u32 gpio_base; - -static struct pci_device_id divil_pci[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, - { } /* NULL entry */ -}; -MODULE_DEVICE_TABLE(pci, divil_pci); - -static struct cdev cs5535_gpio_cdev; - -/* reserve 32 entries even though some aren't usable */ -#define CS5535_GPIO_COUNT 32 - -/* IO block size */ -#define CS5535_GPIO_SIZE 256 - -struct gpio_regmap { - u32 rd_offset; - u32 wr_offset; - char on; - char off; -}; -static struct gpio_regmap rm[] = -{ - { 0x30, 0x00, '1', '0' }, /* GPIOx_READ_BACK / GPIOx_OUT_VAL */ - { 0x20, 0x20, 'I', 'i' }, /* GPIOx_IN_EN */ - { 0x04, 0x04, 'O', 'o' }, /* GPIOx_OUT_EN */ - { 0x08, 0x08, 't', 'T' }, /* GPIOx_OUT_OD_EN */ - { 0x18, 0x18, 'P', 'p' }, /* GPIOx_OUT_PU_EN */ - { 0x1c, 0x1c, 'D', 'd' }, /* GPIOx_OUT_PD_EN */ -}; - - -/** - * Gets the register offset for the GPIO bank. - * Low (0-15) starts at 0x00, high (16-31) starts at 0x80 - */ -static inline u32 cs5535_lowhigh_base(int reg) -{ - return (reg & 0x10) << 3; -} - -static ssize_t cs5535_gpio_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - u32 m = iminor(file->f_path.dentry->d_inode); - int i, j; - u32 base = gpio_base + cs5535_lowhigh_base(m); - u32 m0, m1; - char c; - - /** - * Creates the mask for atomic bit programming. - * The high 16 bits and the low 16 bits are used to set the mask. - * For example, GPIO 15 maps to 31,15: 0,1 => On; 1,0=> Off - */ - m1 = 1 << (m & 0x0F); - m0 = m1 << 16; - - for (i = 0; i < len; ++i) { - if (get_user(c, data+i)) - return -EFAULT; - - for (j = 0; j < ARRAY_SIZE(rm); j++) { - if (c == rm[j].on) { - outl(m1, base + rm[j].wr_offset); - /* If enabling output, turn off AUX 1 and AUX 2 */ - if (c == 'O') { - outl(m0, base + 0x10); - outl(m0, base + 0x14); - } - break; - } else if (c == rm[j].off) { - outl(m0, base + rm[j].wr_offset); - break; - } - } - } - *ppos = 0; - return len; -} - -static ssize_t cs5535_gpio_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos) -{ - u32 m = iminor(file->f_path.dentry->d_inode); - u32 base = gpio_base + cs5535_lowhigh_base(m); - int rd_bit = 1 << (m & 0x0f); - int i; - char ch; - ssize_t count = 0; - - if (*ppos >= ARRAY_SIZE(rm)) - return 0; - - for (i = *ppos; (i < (*ppos + len)) && (i < ARRAY_SIZE(rm)); i++) { - ch = (inl(base + rm[i].rd_offset) & rd_bit) ? - rm[i].on : rm[i].off; - - if (put_user(ch, buf+count)) - return -EFAULT; - - count++; - } - - /* add a line-feed if there is room */ - if ((i == ARRAY_SIZE(rm)) && (count < len)) { - put_user('\n', buf + count); - count++; - } - - *ppos += count; - return count; -} - -static int cs5535_gpio_open(struct inode *inode, struct file *file) -{ - u32 m = iminor(inode); - - /* the mask says which pins are usable by this driver */ - if ((mask & (1 << m)) == 0) - return -EINVAL; - - return nonseekable_open(inode, file); -} - -static const struct file_operations cs5535_gpio_fops = { - .owner = THIS_MODULE, - .write = cs5535_gpio_write, - .read = cs5535_gpio_read, - .open = cs5535_gpio_open, - .llseek = no_llseek, -}; - -static int __init cs5535_gpio_init(void) -{ - dev_t dev_id; - u32 low, hi; - int retval; - - if (pci_dev_present(divil_pci) == 0) { - printk(KERN_WARNING NAME ": DIVIL not found\n"); - return -ENODEV; - } - - /* Grab the GPIO I/O range */ - rdmsr(MSR_LBAR_GPIO, low, hi); - - /* Check the mask and whether GPIO is enabled (sanity check) */ - if (hi != 0x0000f001) { - printk(KERN_WARNING NAME ": GPIO not enabled\n"); - return -ENODEV; - } - - /* Mask off the IO base address */ - gpio_base = low & 0x0000ff00; - - /** - * Some GPIO pins - * 31-29,23 : reserved (always mask out) - * 28 : Power Button - * 26 : PME# - * 22-16 : LPC - * 14,15 : SMBus - * 9,8 : UART1 - * 7 : PCI INTB - * 3,4 : UART2/DDC - * 2 : IDE_IRQ0 - * 0 : PCI INTA - * - * If a mask was not specified, be conservative and only allow: - * 1,2,5,6,10-13,24,25,27 - */ - if (mask != 0) - mask &= 0x1f7fffff; - else - mask = 0x0b003c66; - - if (!request_region(gpio_base, CS5535_GPIO_SIZE, NAME)) { - printk(KERN_ERR NAME ": can't allocate I/O for GPIO\n"); - return -ENODEV; - } - - if (major) { - dev_id = MKDEV(major, 0); - retval = register_chrdev_region(dev_id, CS5535_GPIO_COUNT, - NAME); - } else { - retval = alloc_chrdev_region(&dev_id, 0, CS5535_GPIO_COUNT, - NAME); - major = MAJOR(dev_id); - } - - if (retval) { - release_region(gpio_base, CS5535_GPIO_SIZE); - return -1; - } - - printk(KERN_DEBUG NAME ": base=%#x mask=%#lx major=%d\n", - gpio_base, mask, major); - - cdev_init(&cs5535_gpio_cdev, &cs5535_gpio_fops); - cdev_add(&cs5535_gpio_cdev, dev_id, CS5535_GPIO_COUNT); - - return 0; -} - -static void __exit cs5535_gpio_cleanup(void) -{ - dev_t dev_id = MKDEV(major, 0); - - cdev_del(&cs5535_gpio_cdev); - unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT); - release_region(gpio_base, CS5535_GPIO_SIZE); -} - -module_init(cs5535_gpio_init); -module_exit(cs5535_gpio_cleanup); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e2d586903432..5c8fcfc42c3e 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -123,6 +123,8 @@ source "drivers/staging/sep/Kconfig" source "drivers/staging/iio/Kconfig" +source "drivers/staging/cs5535_gpio/Kconfig" + source "drivers/staging/zram/Kconfig" source "drivers/staging/wlags49_h2/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index c7d222413c07..d53886317826 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ +obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ diff --git a/drivers/staging/cs5535_gpio/Kconfig b/drivers/staging/cs5535_gpio/Kconfig new file mode 100644 index 000000000000..a1b3a8d2b866 --- /dev/null +++ b/drivers/staging/cs5535_gpio/Kconfig @@ -0,0 +1,11 @@ +config CS5535_GPIO + tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" + depends on X86_32 + help + Note: this driver is DEPRECATED. Please use the cs5535-gpio module + in the GPIO section instead (CONFIG_GPIO_CS5535). + + Give userspace access to the GPIO pins on the AMD CS5535 and + CS5536 Geode companion devices. + + If compiled as a module, it will be called cs5535_gpio. diff --git a/drivers/staging/cs5535_gpio/Makefile b/drivers/staging/cs5535_gpio/Makefile new file mode 100644 index 000000000000..d67c4b85f191 --- /dev/null +++ b/drivers/staging/cs5535_gpio/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o diff --git a/drivers/staging/cs5535_gpio/TODO b/drivers/staging/cs5535_gpio/TODO new file mode 100644 index 000000000000..98d1cd1e2363 --- /dev/null +++ b/drivers/staging/cs5535_gpio/TODO @@ -0,0 +1,6 @@ +This is an obsolete driver for some the CS5535 and CS5536 southbridge GPIOs. +It has been replaced by a driver that makes use of the Linux GPIO subsystem. +Please switch to that driver, and let dilinger@queued.net know if there's +anything missing from the new driver. + +This driver is scheduled for removal in 2.6.40. diff --git a/drivers/staging/cs5535_gpio/cs5535_gpio.c b/drivers/staging/cs5535_gpio/cs5535_gpio.c new file mode 100644 index 000000000000..0cf1e5fad9ab --- /dev/null +++ b/drivers/staging/cs5535_gpio/cs5535_gpio.c @@ -0,0 +1,259 @@ +/* + * AMD CS5535/CS5536 GPIO driver. + * Allows a user space process to play with the GPIO pins. + * + * Copyright (c) 2005 Ben Gardner + * + * This program is free software; you can redistribute it and/or modify + * it under the smems of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define NAME "cs5535_gpio" + +MODULE_AUTHOR("Ben Gardner "); +MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO Pin Driver"); +MODULE_LICENSE("GPL"); + +static int major; +module_param(major, int, 0); +MODULE_PARM_DESC(major, "Major device number"); + +static ulong mask; +module_param(mask, ulong, 0); +MODULE_PARM_DESC(mask, "GPIO channel mask"); + +#define MSR_LBAR_GPIO 0x5140000C + +static u32 gpio_base; + +static struct pci_device_id divil_pci[] = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, + { } /* NULL entry */ +}; +MODULE_DEVICE_TABLE(pci, divil_pci); + +static struct cdev cs5535_gpio_cdev; + +/* reserve 32 entries even though some aren't usable */ +#define CS5535_GPIO_COUNT 32 + +/* IO block size */ +#define CS5535_GPIO_SIZE 256 + +struct gpio_regmap { + u32 rd_offset; + u32 wr_offset; + char on; + char off; +}; +static struct gpio_regmap rm[] = +{ + { 0x30, 0x00, '1', '0' }, /* GPIOx_READ_BACK / GPIOx_OUT_VAL */ + { 0x20, 0x20, 'I', 'i' }, /* GPIOx_IN_EN */ + { 0x04, 0x04, 'O', 'o' }, /* GPIOx_OUT_EN */ + { 0x08, 0x08, 't', 'T' }, /* GPIOx_OUT_OD_EN */ + { 0x18, 0x18, 'P', 'p' }, /* GPIOx_OUT_PU_EN */ + { 0x1c, 0x1c, 'D', 'd' }, /* GPIOx_OUT_PD_EN */ +}; + + +/** + * Gets the register offset for the GPIO bank. + * Low (0-15) starts at 0x00, high (16-31) starts at 0x80 + */ +static inline u32 cs5535_lowhigh_base(int reg) +{ + return (reg & 0x10) << 3; +} + +static ssize_t cs5535_gpio_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + u32 m = iminor(file->f_path.dentry->d_inode); + int i, j; + u32 base = gpio_base + cs5535_lowhigh_base(m); + u32 m0, m1; + char c; + + /** + * Creates the mask for atomic bit programming. + * The high 16 bits and the low 16 bits are used to set the mask. + * For example, GPIO 15 maps to 31,15: 0,1 => On; 1,0=> Off + */ + m1 = 1 << (m & 0x0F); + m0 = m1 << 16; + + for (i = 0; i < len; ++i) { + if (get_user(c, data+i)) + return -EFAULT; + + for (j = 0; j < ARRAY_SIZE(rm); j++) { + if (c == rm[j].on) { + outl(m1, base + rm[j].wr_offset); + /* If enabling output, turn off AUX 1 and AUX 2 */ + if (c == 'O') { + outl(m0, base + 0x10); + outl(m0, base + 0x14); + } + break; + } else if (c == rm[j].off) { + outl(m0, base + rm[j].wr_offset); + break; + } + } + } + *ppos = 0; + return len; +} + +static ssize_t cs5535_gpio_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + u32 m = iminor(file->f_path.dentry->d_inode); + u32 base = gpio_base + cs5535_lowhigh_base(m); + int rd_bit = 1 << (m & 0x0f); + int i; + char ch; + ssize_t count = 0; + + if (*ppos >= ARRAY_SIZE(rm)) + return 0; + + for (i = *ppos; (i < (*ppos + len)) && (i < ARRAY_SIZE(rm)); i++) { + ch = (inl(base + rm[i].rd_offset) & rd_bit) ? + rm[i].on : rm[i].off; + + if (put_user(ch, buf+count)) + return -EFAULT; + + count++; + } + + /* add a line-feed if there is room */ + if ((i == ARRAY_SIZE(rm)) && (count < len)) { + put_user('\n', buf + count); + count++; + } + + *ppos += count; + return count; +} + +static int cs5535_gpio_open(struct inode *inode, struct file *file) +{ + u32 m = iminor(inode); + + /* the mask says which pins are usable by this driver */ + if ((mask & (1 << m)) == 0) + return -EINVAL; + + return nonseekable_open(inode, file); +} + +static const struct file_operations cs5535_gpio_fops = { + .owner = THIS_MODULE, + .write = cs5535_gpio_write, + .read = cs5535_gpio_read, + .open = cs5535_gpio_open, + .llseek = no_llseek, +}; + +static int __init cs5535_gpio_init(void) +{ + dev_t dev_id; + u32 low, hi; + int retval; + + if (pci_dev_present(divil_pci) == 0) { + printk(KERN_WARNING NAME ": DIVIL not found\n"); + return -ENODEV; + } + + /* Grab the GPIO I/O range */ + rdmsr(MSR_LBAR_GPIO, low, hi); + + /* Check the mask and whether GPIO is enabled (sanity check) */ + if (hi != 0x0000f001) { + printk(KERN_WARNING NAME ": GPIO not enabled\n"); + return -ENODEV; + } + + /* Mask off the IO base address */ + gpio_base = low & 0x0000ff00; + + /** + * Some GPIO pins + * 31-29,23 : reserved (always mask out) + * 28 : Power Button + * 26 : PME# + * 22-16 : LPC + * 14,15 : SMBus + * 9,8 : UART1 + * 7 : PCI INTB + * 3,4 : UART2/DDC + * 2 : IDE_IRQ0 + * 0 : PCI INTA + * + * If a mask was not specified, be conservative and only allow: + * 1,2,5,6,10-13,24,25,27 + */ + if (mask != 0) + mask &= 0x1f7fffff; + else + mask = 0x0b003c66; + + if (!request_region(gpio_base, CS5535_GPIO_SIZE, NAME)) { + printk(KERN_ERR NAME ": can't allocate I/O for GPIO\n"); + return -ENODEV; + } + + if (major) { + dev_id = MKDEV(major, 0); + retval = register_chrdev_region(dev_id, CS5535_GPIO_COUNT, + NAME); + } else { + retval = alloc_chrdev_region(&dev_id, 0, CS5535_GPIO_COUNT, + NAME); + major = MAJOR(dev_id); + } + + if (retval) { + release_region(gpio_base, CS5535_GPIO_SIZE); + return -1; + } + + printk(KERN_DEBUG NAME ": base=%#x mask=%#lx major=%d\n", + gpio_base, mask, major); + + cdev_init(&cs5535_gpio_cdev, &cs5535_gpio_fops); + cdev_add(&cs5535_gpio_cdev, dev_id, CS5535_GPIO_COUNT); + + return 0; +} + +static void __exit cs5535_gpio_cleanup(void) +{ + dev_t dev_id = MKDEV(major, 0); + + cdev_del(&cs5535_gpio_cdev); + unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT); + release_region(gpio_base, CS5535_GPIO_SIZE); +} + +module_init(cs5535_gpio_init); +module_exit(cs5535_gpio_cleanup); -- cgit v1.2.3 From 12401eeddd21a59357c9a34c39761a7d32ddd4cd Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:12 -0800 Subject: gpio: adp5588-gpio: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Acked-by: "Hennerich, Michael" Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/adp5588-gpio.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c index 0871f78af593..33fc685cb385 100644 --- a/drivers/gpio/adp5588-gpio.c +++ b/drivers/gpio/adp5588-gpio.c @@ -146,9 +146,10 @@ static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off) return dev->irq_base + off; } -static void adp5588_irq_bus_lock(unsigned int irq) +static void adp5588_irq_bus_lock(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + mutex_lock(&dev->irq_lock); } @@ -160,9 +161,9 @@ static void adp5588_irq_bus_lock(unsigned int irq) * and unlocks the bus. */ -static void adp5588_irq_bus_sync_unlock(unsigned int irq) +static void adp5588_irq_bus_sync_unlock(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); int i; for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) @@ -175,31 +176,31 @@ static void adp5588_irq_bus_sync_unlock(unsigned int irq) mutex_unlock(&dev->irq_lock); } -static void adp5588_irq_mask(unsigned int irq) +static void adp5588_irq_mask(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); - unsigned gpio = irq - dev->irq_base; + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + unsigned gpio = d->irq - dev->irq_base; dev->irq_mask[ADP5588_BANK(gpio)] &= ~ADP5588_BIT(gpio); } -static void adp5588_irq_unmask(unsigned int irq) +static void adp5588_irq_unmask(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); - unsigned gpio = irq - dev->irq_base; + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + unsigned gpio = d->irq - dev->irq_base; dev->irq_mask[ADP5588_BANK(gpio)] |= ADP5588_BIT(gpio); } -static int adp5588_irq_set_type(unsigned int irq, unsigned int type) +static int adp5588_irq_set_type(struct irq_data *d, unsigned int type) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); - uint16_t gpio = irq - dev->irq_base; + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + uint16_t gpio = d->irq - dev->irq_base; unsigned bank, bit; if ((type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&dev->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -222,11 +223,11 @@ static int adp5588_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip adp5588_irq_chip = { .name = "adp5588", - .mask = adp5588_irq_mask, - .unmask = adp5588_irq_unmask, - .bus_lock = adp5588_irq_bus_lock, - .bus_sync_unlock = adp5588_irq_bus_sync_unlock, - .set_type = adp5588_irq_set_type, + .irq_mask = adp5588_irq_mask, + .irq_unmask = adp5588_irq_unmask, + .irq_bus_lock = adp5588_irq_bus_lock, + .irq_bus_sync_unlock = adp5588_irq_bus_sync_unlock, + .irq_set_type = adp5588_irq_set_type, }; static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf) -- cgit v1.2.3 From 5ffd72c674a8332b37cfd62c364bc5492e8ea4c5 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:13 -0800 Subject: gpio: langwell_gpio: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Cc: Alan Cox Cc: Yin Kangkai Cc: Alek Du Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/langwell_gpio.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 64db9dc3a275..d81cc748e77f 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -134,10 +134,10 @@ static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return lnw->irq_base + offset; } -static int lnw_irq_type(unsigned irq, unsigned type) +static int lnw_irq_type(struct irq_data *d, unsigned type) { - struct lnw_gpio *lnw = get_irq_chip_data(irq); - u32 gpio = irq - lnw->irq_base; + struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); + u32 gpio = d->irq - lnw->irq_base; unsigned long flags; u32 value; void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); @@ -162,19 +162,19 @@ static int lnw_irq_type(unsigned irq, unsigned type) return 0; } -static void lnw_irq_unmask(unsigned irq) +static void lnw_irq_unmask(struct irq_data *d) { } -static void lnw_irq_mask(unsigned irq) +static void lnw_irq_mask(struct irq_data *d) { } static struct irq_chip lnw_irqchip = { .name = "LNW-GPIO", - .mask = lnw_irq_mask, - .unmask = lnw_irq_unmask, - .set_type = lnw_irq_type, + .irq_mask = lnw_irq_mask, + .irq_unmask = lnw_irq_unmask, + .irq_set_type = lnw_irq_type, }; static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ -- cgit v1.2.3 From fbc4667ab08a1c43c6141ce844005c76883e1930 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:14 -0800 Subject: gpio: max732x: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Acked-by: Marc Zyngier Cc: Eric Miao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/max732x.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c index 9cad60f9e962..9e1d01f0071a 100644 --- a/drivers/gpio/max732x.c +++ b/drivers/gpio/max732x.c @@ -327,40 +327,40 @@ static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) return chip->irq_base + off; } -static void max732x_irq_mask(unsigned int irq) +static void max732x_irq_mask(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur &= ~(1 << (irq - chip->irq_base)); + chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base)); } -static void max732x_irq_unmask(unsigned int irq) +static void max732x_irq_unmask(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur |= 1 << (irq - chip->irq_base); + chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base); } -static void max732x_irq_bus_lock(unsigned int irq) +static void max732x_irq_bus_lock(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); mutex_lock(&chip->irq_lock); chip->irq_mask_cur = chip->irq_mask; } -static void max732x_irq_bus_sync_unlock(unsigned int irq) +static void max732x_irq_bus_sync_unlock(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); max732x_irq_update_mask(chip); mutex_unlock(&chip->irq_lock); } -static int max732x_irq_set_type(unsigned int irq, unsigned int type) +static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { - struct max732x_chip *chip = get_irq_chip_data(irq); - uint16_t off = irq - chip->irq_base; + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t off = d->irq - chip->irq_base; uint16_t mask = 1 << off; if (!(mask & chip->dir_input)) { @@ -371,7 +371,7 @@ static int max732x_irq_set_type(unsigned int irq, unsigned int type) if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -390,11 +390,11 @@ static int max732x_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip max732x_irq_chip = { .name = "max732x", - .mask = max732x_irq_mask, - .unmask = max732x_irq_unmask, - .bus_lock = max732x_irq_bus_lock, - .bus_sync_unlock = max732x_irq_bus_sync_unlock, - .set_type = max732x_irq_set_type, + .irq_mask = max732x_irq_mask, + .irq_unmask = max732x_irq_unmask, + .irq_bus_lock = max732x_irq_bus_lock, + .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock, + .irq_set_type = max732x_irq_set_type, }; static uint8_t max732x_irq_pending(struct max732x_chip *chip) -- cgit v1.2.3 From 6f5cfc0e2d5feac9094a8b26b9ad1739c1e7d9df Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:15 -0800 Subject: gpio: pca953x: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Cc: Alek Du Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/pca953x.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 501866662e05..a261972f603d 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -228,30 +228,30 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) return chip->irq_base + off; } -static void pca953x_irq_mask(unsigned int irq) +static void pca953x_irq_mask(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (irq - chip->irq_base)); + chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); } -static void pca953x_irq_unmask(unsigned int irq) +static void pca953x_irq_unmask(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (irq - chip->irq_base); + chip->irq_mask |= 1 << (d->irq - chip->irq_base); } -static void pca953x_irq_bus_lock(unsigned int irq) +static void pca953x_irq_bus_lock(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); mutex_lock(&chip->irq_lock); } -static void pca953x_irq_bus_sync_unlock(unsigned int irq) +static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); uint16_t new_irqs; uint16_t level; @@ -268,15 +268,15 @@ static void pca953x_irq_bus_sync_unlock(unsigned int irq) mutex_unlock(&chip->irq_lock); } -static int pca953x_irq_set_type(unsigned int irq, unsigned int type) +static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { - struct pca953x_chip *chip = get_irq_chip_data(irq); - uint16_t level = irq - chip->irq_base; + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t level = d->irq - chip->irq_base; uint16_t mask = 1 << level; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -295,11 +295,11 @@ static int pca953x_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip pca953x_irq_chip = { .name = "pca953x", - .mask = pca953x_irq_mask, - .unmask = pca953x_irq_unmask, - .bus_lock = pca953x_irq_bus_lock, - .bus_sync_unlock = pca953x_irq_bus_sync_unlock, - .set_type = pca953x_irq_set_type, + .irq_mask = pca953x_irq_mask, + .irq_unmask = pca953x_irq_unmask, + .irq_bus_lock = pca953x_irq_bus_lock, + .irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock, + .irq_set_type = pca953x_irq_set_type, }; static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) -- cgit v1.2.3 From b2221869dbd84994f07c91be73103d9f9cb7309f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:16 -0800 Subject: gpio: pl061: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Acked-by: Baruch Siach Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/pl061.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 5005990f751f..2975d22daffe 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -129,10 +129,10 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) /* * PL061 GPIO IRQ */ -static void pl061_irq_disable(unsigned irq) +static void pl061_irq_disable(struct irq_data *d) { - struct pl061_gpio *chip = get_irq_chip_data(irq); - int offset = irq - chip->irq_base; + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpioie; @@ -143,10 +143,10 @@ static void pl061_irq_disable(unsigned irq) spin_unlock_irqrestore(&chip->irq_lock, flags); } -static void pl061_irq_enable(unsigned irq) +static void pl061_irq_enable(struct irq_data *d) { - struct pl061_gpio *chip = get_irq_chip_data(irq); - int offset = irq - chip->irq_base; + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpioie; @@ -157,10 +157,10 @@ static void pl061_irq_enable(unsigned irq) spin_unlock_irqrestore(&chip->irq_lock, flags); } -static int pl061_irq_type(unsigned irq, unsigned trigger) +static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = get_irq_chip_data(irq); - int offset = irq - chip->irq_base; + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -203,9 +203,9 @@ static int pl061_irq_type(unsigned irq, unsigned trigger) static struct irq_chip pl061_irqchip = { .name = "GPIO", - .enable = pl061_irq_enable, - .disable = pl061_irq_disable, - .set_type = pl061_irq_type, + .irq_enable = pl061_irq_enable, + .irq_disable = pl061_irq_disable, + .irq_set_type = pl061_irq_type, }; static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) @@ -214,7 +214,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) struct list_head *ptr; struct pl061_gpio *chip; - desc->chip->ack(irq); + desc->irq_data.chip->irq_ack(&desc->irq_data); list_for_each(ptr, chip_list) { unsigned long pending; int offset; @@ -229,7 +229,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(pl061_to_irq(&chip->gc, offset)); } - desc->chip->unmask(irq); + desc->irq_data.chip->irq_unmask(&desc->irq_data); } static int pl061_probe(struct amba_device *dev, struct amba_id *id) -- cgit v1.2.3 From 2a866f39146a5613d5c2db9031c13c218a4c7402 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:17 -0800 Subject: gpio: stmpe-gpio: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Acked-by: Rabin Vincent Cc: Luotao Fu Cc: Linus Walleij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/stmpe-gpio.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c index 7c9e6a052c45..eb2901f8ab5e 100644 --- a/drivers/gpio/stmpe-gpio.c +++ b/drivers/gpio/stmpe-gpio.c @@ -122,10 +122,10 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type) +static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); - int offset = irq - stmpe_gpio->irq_base; + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - stmpe_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -145,16 +145,16 @@ static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type) return 0; } -static void stmpe_gpio_irq_lock(unsigned int irq) +static void stmpe_gpio_irq_lock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); mutex_lock(&stmpe_gpio->irq_lock); } -static void stmpe_gpio_irq_sync_unlock(unsigned int irq) +static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); struct stmpe *stmpe = stmpe_gpio->stmpe; int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); static const u8 regmap[] = { @@ -180,20 +180,20 @@ static void stmpe_gpio_irq_sync_unlock(unsigned int irq) mutex_unlock(&stmpe_gpio->irq_lock); } -static void stmpe_gpio_irq_mask(unsigned int irq) +static void stmpe_gpio_irq_mask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); - int offset = irq - stmpe_gpio->irq_base; + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - stmpe_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); stmpe_gpio->regs[REG_IE][regoffset] &= ~mask; } -static void stmpe_gpio_irq_unmask(unsigned int irq) +static void stmpe_gpio_irq_unmask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); - int offset = irq - stmpe_gpio->irq_base; + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - stmpe_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -202,11 +202,11 @@ static void stmpe_gpio_irq_unmask(unsigned int irq) static struct irq_chip stmpe_gpio_irq_chip = { .name = "stmpe-gpio", - .bus_lock = stmpe_gpio_irq_lock, - .bus_sync_unlock = stmpe_gpio_irq_sync_unlock, - .mask = stmpe_gpio_irq_mask, - .unmask = stmpe_gpio_irq_unmask, - .set_type = stmpe_gpio_irq_set_type, + .irq_bus_lock = stmpe_gpio_irq_lock, + .irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock, + .irq_mask = stmpe_gpio_irq_mask, + .irq_unmask = stmpe_gpio_irq_unmask, + .irq_set_type = stmpe_gpio_irq_set_type, }; static irqreturn_t stmpe_gpio_irq(int irq, void *dev) -- cgit v1.2.3 From 673860c107d3adc3fb0c85d7b4c86f551e75dc01 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:18 -0800 Subject: gpio: sx150x: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Cc: Gregory Bean Tested-by: Rohit Vaswani Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/sx150x.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index 823559ab0e24..e60be0015c9b 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c @@ -304,36 +304,36 @@ static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return chip->irq_base + offset; } -static void sx150x_irq_mask(unsigned int irq) +static void sx150x_irq_mask(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n; chip = container_of(ic, struct sx150x_chip, irq_chip); - n = irq - chip->irq_base; + n = d->irq - chip->irq_base; sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); } -static void sx150x_irq_unmask(unsigned int irq) +static void sx150x_irq_unmask(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n; chip = container_of(ic, struct sx150x_chip, irq_chip); - n = irq - chip->irq_base; + n = d->irq - chip->irq_base; sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, chip->irq_sense >> (n * 2)); } -static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type) +static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n, val = 0; @@ -341,7 +341,7 @@ static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type) return -EINVAL; chip = container_of(ic, struct sx150x_chip, irq_chip); - n = irq - chip->irq_base; + n = d->irq - chip->irq_base; if (flow_type & IRQ_TYPE_EDGE_RISING) val |= 0x1; @@ -386,9 +386,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); } -static void sx150x_irq_bus_lock(unsigned int irq) +static void sx150x_irq_bus_lock(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; chip = container_of(ic, struct sx150x_chip, irq_chip); @@ -396,9 +396,9 @@ static void sx150x_irq_bus_lock(unsigned int irq) mutex_lock(&chip->lock); } -static void sx150x_irq_bus_sync_unlock(unsigned int irq) +static void sx150x_irq_bus_sync_unlock(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n; @@ -437,16 +437,16 @@ static void sx150x_init_chip(struct sx150x_chip *chip, if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; - chip->irq_chip.name = client->name; - chip->irq_chip.mask = sx150x_irq_mask; - chip->irq_chip.unmask = sx150x_irq_unmask; - chip->irq_chip.set_type = sx150x_irq_set_type; - chip->irq_chip.bus_lock = sx150x_irq_bus_lock; - chip->irq_chip.bus_sync_unlock = sx150x_irq_bus_sync_unlock; - chip->irq_summary = -1; - chip->irq_base = -1; - chip->irq_sense = 0; - chip->irq_set_type_pending = 0; + chip->irq_chip.name = client->name; + chip->irq_chip.irq_mask = sx150x_irq_mask; + chip->irq_chip.irq_unmask = sx150x_irq_unmask; + chip->irq_chip.irq_set_type = sx150x_irq_set_type; + chip->irq_chip.irq_bus_lock = sx150x_irq_bus_lock; + chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; + chip->irq_summary = -1; + chip->irq_base = -1; + chip->irq_sense = 0; + chip->irq_set_type_pending = 0; } static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) -- cgit v1.2.3 From 33fcc1b80259a9c09074a3859c26772f3d595c20 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:19 -0800 Subject: gpio: tc35892-gpio: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Acked-by: Rabin Vincent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/tc3589x-gpio.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c index 180d584454fb..27200af1a595 100644 --- a/drivers/gpio/tc3589x-gpio.c +++ b/drivers/gpio/tc3589x-gpio.c @@ -110,10 +110,10 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type) +static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); - int offset = irq - tc3589x_gpio->irq_base; + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tc3589x_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -137,16 +137,16 @@ static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type) return 0; } -static void tc3589x_gpio_irq_lock(unsigned int irq) +static void tc3589x_gpio_irq_lock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); mutex_lock(&tc3589x_gpio->irq_lock); } -static void tc3589x_gpio_irq_sync_unlock(unsigned int irq) +static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -172,20 +172,20 @@ static void tc3589x_gpio_irq_sync_unlock(unsigned int irq) mutex_unlock(&tc3589x_gpio->irq_lock); } -static void tc3589x_gpio_irq_mask(unsigned int irq) +static void tc3589x_gpio_irq_mask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); - int offset = irq - tc3589x_gpio->irq_base; + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tc3589x_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; } -static void tc3589x_gpio_irq_unmask(unsigned int irq) +static void tc3589x_gpio_irq_unmask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); - int offset = irq - tc3589x_gpio->irq_base; + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tc3589x_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -194,11 +194,11 @@ static void tc3589x_gpio_irq_unmask(unsigned int irq) static struct irq_chip tc3589x_gpio_irq_chip = { .name = "tc3589x-gpio", - .bus_lock = tc3589x_gpio_irq_lock, - .bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, - .mask = tc3589x_gpio_irq_mask, - .unmask = tc3589x_gpio_irq_unmask, - .set_type = tc3589x_gpio_irq_set_type, + .irq_bus_lock = tc3589x_gpio_irq_lock, + .irq_bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, + .irq_mask = tc3589x_gpio_irq_mask, + .irq_unmask = tc3589x_gpio_irq_unmask, + .irq_set_type = tc3589x_gpio_irq_set_type, }; static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) -- cgit v1.2.3 From a1f5f22adc3206c47e70652c12671666c65b579f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:19 -0800 Subject: gpio: timbgpio: irq_data conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Cc: Richard Röjfors Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/timbgpio.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index 45293662e950..349131eb1ce0 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -109,10 +109,10 @@ static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset) /* * GPIO IRQ */ -static void timbgpio_irq_disable(unsigned irq) +static void timbgpio_irq_disable(struct irq_data *d) { - struct timbgpio *tgpio = get_irq_chip_data(irq); - int offset = irq - tgpio->irq_base; + struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tgpio->irq_base; unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); @@ -121,10 +121,10 @@ static void timbgpio_irq_disable(unsigned irq) spin_unlock_irqrestore(&tgpio->lock, flags); } -static void timbgpio_irq_enable(unsigned irq) +static void timbgpio_irq_enable(struct irq_data *d) { - struct timbgpio *tgpio = get_irq_chip_data(irq); - int offset = irq - tgpio->irq_base; + struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tgpio->irq_base; unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); @@ -133,10 +133,10 @@ static void timbgpio_irq_enable(unsigned irq) spin_unlock_irqrestore(&tgpio->lock, flags); } -static int timbgpio_irq_type(unsigned irq, unsigned trigger) +static int timbgpio_irq_type(struct irq_data *d, unsigned trigger) { - struct timbgpio *tgpio = get_irq_chip_data(irq); - int offset = irq - tgpio->irq_base; + struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tgpio->irq_base; unsigned long flags; u32 lvr, flr, bflr = 0; u32 ver; @@ -193,13 +193,13 @@ out: return ret; } -static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) +static void timbgpio_irq(struct irq_data *d, struct irq_desc *desc) { - struct timbgpio *tgpio = get_irq_data(irq); + struct timbgpio *tgpio = irq_data_get_irq_data(d); unsigned long ipr; int offset; - desc->chip->ack(irq); + desc->irq_data.chip->ack(irq_get_irq_data(d)); ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); @@ -217,9 +217,9 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) static struct irq_chip timbgpio_irqchip = { .name = "GPIO", - .enable = timbgpio_irq_enable, - .disable = timbgpio_irq_disable, - .set_type = timbgpio_irq_type, + .irq_enable = timbgpio_irq_enable, + .irq_disable = timbgpio_irq_disable, + .irq_set_type = timbgpio_irq_type, }; static int __devinit timbgpio_probe(struct platform_device *pdev) -- cgit v1.2.3 From 67d15ed7dfba8df6c723623a50a96ed1a08ba834 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 12 Jan 2011 17:00:20 -0800 Subject: gpio: vr41xx_giu: irq_data conversion Converts irq_chips and flow handlers over to the new struct irq_data based irq_chip functions. Signed-off-by: Lennert Buytenhek Cc: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/vr41xx_giu.c | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c index b16c9a8c03f5..cffa3bd7ad3b 100644 --- a/drivers/gpio/vr41xx_giu.c +++ b/drivers/gpio/vr41xx_giu.c @@ -111,69 +111,69 @@ static inline u16 giu_clear(u16 offset, u16 clear) return data; } -static void ack_giuint_low(unsigned int irq) +static void ack_giuint_low(struct irq_data *d) { - giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } -static void mask_giuint_low(unsigned int irq) +static void mask_giuint_low(struct irq_data *d) { - giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } -static void mask_ack_giuint_low(unsigned int irq) +static void mask_ack_giuint_low(struct irq_data *d) { unsigned int pin; - pin = GPIO_PIN_OF_IRQ(irq); + pin = GPIO_PIN_OF_IRQ(d->irq); giu_clear(GIUINTENL, 1 << pin); giu_write(GIUINTSTATL, 1 << pin); } -static void unmask_giuint_low(unsigned int irq) +static void unmask_giuint_low(struct irq_data *d) { - giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } static struct irq_chip giuint_low_irq_chip = { .name = "GIUINTL", - .ack = ack_giuint_low, - .mask = mask_giuint_low, - .mask_ack = mask_ack_giuint_low, - .unmask = unmask_giuint_low, + .irq_ack = ack_giuint_low, + .irq_mask = mask_giuint_low, + .irq_mask_ack = mask_ack_giuint_low, + .irq_unmask = unmask_giuint_low, }; -static void ack_giuint_high(unsigned int irq) +static void ack_giuint_high(struct irq_data *d) { giu_write(GIUINTSTATH, - 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); } -static void mask_giuint_high(unsigned int irq) +static void mask_giuint_high(struct irq_data *d) { - giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); } -static void mask_ack_giuint_high(unsigned int irq) +static void mask_ack_giuint_high(struct irq_data *d) { unsigned int pin; - pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET; giu_clear(GIUINTENH, 1 << pin); giu_write(GIUINTSTATH, 1 << pin); } -static void unmask_giuint_high(unsigned int irq) +static void unmask_giuint_high(struct irq_data *d) { - giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); } static struct irq_chip giuint_high_irq_chip = { .name = "GIUINTH", - .ack = ack_giuint_high, - .mask = mask_giuint_high, - .mask_ack = mask_ack_giuint_high, - .unmask = unmask_giuint_high, + .irq_ack = ack_giuint_high, + .irq_mask = mask_giuint_high, + .irq_mask_ack = mask_ack_giuint_high, + .irq_unmask = unmask_giuint_high, }; static int giu_get_irq(unsigned int irq) -- cgit v1.2.3 From 6f7ab5246d63358033497f8cb4e0867bb7b0df1e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 12 Jan 2011 17:00:21 -0800 Subject: GPIO_RDC321X: select MFD_SUPPORT to squelch kconfig warning Fix kconfig dependency warning to satisfy dependencies: warning: (GPIO_RDC321X && PCI && GPIOLIB) selects MFD_RDC321X which has unmet direct dependencies (MFD_SUPPORT && PCI) Signed-off-by: Randy Dunlap Cc: Florian Fainelli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index bfa276a95411..d832423ba12d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -342,6 +342,7 @@ config GPIO_TIMBERDALE config GPIO_RDC321X tristate "RDC R-321x GPIO support" depends on PCI && GPIOLIB + select MFD_SUPPORT select MFD_CORE select MFD_RDC321X help -- cgit v1.2.3 From 32518863b483d521edc813616a35601cad213d31 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 12 Jan 2011 17:00:22 -0800 Subject: GPIO_VX855: eliminate kconfig dependency warning Fix kconfig dependency warning to satisfy dependencies: warning: (GPIO_VX855 && GPIOLIB) selects MFD_VX855 which has unmet direct dependencies (MFD_SUPPORT && PCI) Signed-off-by: Randy Dunlap Cc: Daniel Drake Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d832423ba12d..454e2bc373a8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -118,7 +118,7 @@ config GPIO_SCH config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" - depends on GPIOLIB + depends on GPIOLIB && MFD_SUPPORT && PCI select MFD_CORE select MFD_VX855 help -- cgit v1.2.3 From 49a367937fe4250144e24440e5a11ae4344202b1 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Wed, 12 Jan 2011 17:00:22 -0800 Subject: gpio/ml_ioh_gpio: ML7213 GPIO driver ML7213 is a companion chip for Intel Atom E6xx series. This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output Hub) which is for IVI(In-Vehicle Infotainment) use. This driver can access the IOH's GPIO device. Signed-off-by: Tomoya MORINAGA Cc: Samuel Ortiz Cc: Rabin Vincent Cc: Marc Zyngier Cc: Linus Walleij Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/ml_ioh_gpio.c | 352 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 362 insertions(+) create mode 100644 drivers/gpio/ml_ioh_gpio.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 454e2bc373a8..664660e56335 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -333,6 +333,15 @@ config GPIO_PCH which is an IOH(Input/Output Hub) for x86 embedded processor. This driver can access PCH GPIO device. +config GPIO_ML_IOH + tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" + depends on PCI + help + ML7213 is companion chip for Intel Atom E6xx series. + This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output + Hub) which is for IVI(In-Vehicle Infotainment) use. + This driver can access the IOH's GPIO device. + config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 39bfd7a37650..3351cf87b0ed 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o +obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c new file mode 100644 index 000000000000..cead8e6ff345 --- /dev/null +++ b/drivers/gpio/ml_ioh_gpio.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * 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; version 2 of the License. + * + * 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 + +#define PCI_VENDOR_ID_ROHM 0x10DB + +struct ioh_reg_comn { + u32 ien; + u32 istatus; + u32 idisp; + u32 iclr; + u32 imask; + u32 imaskclr; + u32 po; + u32 pi; + u32 pm; + u32 im_0; + u32 im_1; + u32 reserved; +}; + +struct ioh_regs { + struct ioh_reg_comn regs[8]; + u32 reserve1[16]; + u32 ioh_sel_reg[4]; + u32 reserve2[11]; + u32 srst; +}; + +/** + * struct ioh_gpio_reg_data - The register store data. + * @po_reg: To store contents of PO register. + * @pm_reg: To store contents of PM register. + */ +struct ioh_gpio_reg_data { + u32 po_reg; + u32 pm_reg; +}; + +/** + * struct ioh_gpio - GPIO private data structure. + * @base: PCI base address of Memory mapped I/O register. + * @reg: Memory mapped IOH GPIO register list. + * @dev: Pointer to device structure. + * @gpio: Data for GPIO infrastructure. + * @ioh_gpio_reg: Memory mapped Register data is saved here + * when suspend. + * @ch: Indicate GPIO channel + */ +struct ioh_gpio { + void __iomem *base; + struct ioh_regs __iomem *reg; + struct device *dev; + struct gpio_chip gpio; + struct ioh_gpio_reg_data ioh_gpio_reg; + struct mutex lock; + int ch; +}; + +static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12}; + +static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) +{ + u32 reg_val; + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + + mutex_lock(&chip->lock); + reg_val = ioread32(&chip->reg->regs[chip->ch].po); + if (val) + reg_val |= (1 << nr); + else + reg_val &= ~(1 << nr); + + iowrite32(reg_val, &chip->reg->regs[chip->ch].po); + mutex_unlock(&chip->lock); +} + +static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + + return ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr); +} + +static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, + int val) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + u32 pm; + u32 reg_val; + + mutex_lock(&chip->lock); + pm = ioread32(&chip->reg->regs[chip->ch].pm) & + ((1 << num_ports[chip->ch]) - 1); + pm |= (1 << nr); + iowrite32(pm, &chip->reg->regs[chip->ch].pm); + + reg_val = ioread32(&chip->reg->regs[chip->ch].po); + if (val) + reg_val |= (1 << nr); + else + reg_val &= ~(1 << nr); + + mutex_unlock(&chip->lock); + + return 0; +} + +static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + u32 pm; + + mutex_lock(&chip->lock); + pm = ioread32(&chip->reg->regs[chip->ch].pm) & + ((1 << num_ports[chip->ch]) - 1); + pm &= ~(1 << nr); + iowrite32(pm, &chip->reg->regs[chip->ch].pm); + mutex_unlock(&chip->lock); + + return 0; +} + +/* + * Save register configuration and disable interrupts. + */ +static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) +{ + chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po); + chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm); +} + +/* + * This function restores the register configuration of the GPIO device. + */ +static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) +{ + /* to store contents of PO register */ + iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po); + /* to store contents of PM register */ + iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm); +} + +static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) +{ + struct gpio_chip *gpio = &chip->gpio; + + gpio->label = dev_name(chip->dev); + gpio->owner = THIS_MODULE; + gpio->direction_input = ioh_gpio_direction_input; + gpio->get = ioh_gpio_get; + gpio->direction_output = ioh_gpio_direction_output; + gpio->set = ioh_gpio_set; + gpio->dbg_show = NULL; + gpio->base = -1; + gpio->ngpio = num_port; + gpio->can_sleep = 0; +} + +static int __devinit ioh_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + int i; + struct ioh_gpio *chip; + void __iomem *base; + void __iomem *chip_save; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "%s : pci_enable_device failed", __func__); + goto err_pci_enable; + } + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + dev_err(&pdev->dev, "pci_request_regions failed-%d", ret); + goto err_request_regions; + } + + base = pci_iomap(pdev, 1, 0); + if (base == 0) { + dev_err(&pdev->dev, "%s : pci_iomap failed", __func__); + ret = -ENOMEM; + goto err_iomap; + } + + chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL); + if (chip_save == NULL) { + dev_err(&pdev->dev, "%s : kzalloc failed", __func__); + ret = -ENOMEM; + goto err_kzalloc; + } + + chip = chip_save; + for (i = 0; i < 8; i++, chip++) { + chip->dev = &pdev->dev; + chip->base = base; + chip->reg = chip->base; + chip->ch = i; + mutex_init(&chip->lock); + ioh_gpio_setup(chip, num_ports[i]); + ret = gpiochip_add(&chip->gpio); + if (ret) { + dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n"); + goto err_gpiochip_add; + } + } + + chip = chip_save; + pci_set_drvdata(pdev, chip); + + return 0; + +err_gpiochip_add: + for (; i != 0; i--) { + chip--; + ret = gpiochip_remove(&chip->gpio); + if (ret) + dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i); + } + kfree(chip_save); + +err_kzalloc: + pci_iounmap(pdev, base); + +err_iomap: + pci_release_regions(pdev); + +err_request_regions: + pci_disable_device(pdev); + +err_pci_enable: + + dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret); + return ret; +} + +static void __devexit ioh_gpio_remove(struct pci_dev *pdev) +{ + int err; + int i; + struct ioh_gpio *chip = pci_get_drvdata(pdev); + void __iomem *chip_save; + + chip_save = chip; + for (i = 0; i < 8; i++, chip++) { + err = gpiochip_remove(&chip->gpio); + if (err) + dev_err(&pdev->dev, "Failed gpiochip_remove\n"); + } + + chip = chip_save; + pci_iounmap(pdev, chip->base); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(chip); +} + +#ifdef CONFIG_PM +static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state) +{ + s32 ret; + struct ioh_gpio *chip = pci_get_drvdata(pdev); + + ioh_gpio_save_reg_conf(chip); + ioh_gpio_restore_reg_conf(chip); + + ret = pci_save_state(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret); + return ret; + } + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_wake(pdev, PCI_D0, 1); + if (ret) + dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret); + + return 0; +} + +static int ioh_gpio_resume(struct pci_dev *pdev) +{ + s32 ret; + struct ioh_gpio *chip = pci_get_drvdata(pdev); + + ret = pci_enable_wake(pdev, PCI_D0, 0); + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret); + return ret; + } + pci_restore_state(pdev); + + iowrite32(0x01, &chip->reg->srst); + iowrite32(0x00, &chip->reg->srst); + ioh_gpio_restore_reg_conf(chip); + + return 0; +} +#else +#define ioh_gpio_suspend NULL +#define ioh_gpio_resume NULL +#endif + +static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = { + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, + { 0, } +}; + +static struct pci_driver ioh_gpio_driver = { + .name = "ml_ioh_gpio", + .id_table = ioh_gpio_pcidev_id, + .probe = ioh_gpio_probe, + .remove = __devexit_p(ioh_gpio_remove), + .suspend = ioh_gpio_suspend, + .resume = ioh_gpio_resume +}; + +static int __init ioh_gpio_pci_init(void) +{ + return pci_register_driver(&ioh_gpio_driver); +} +module_init(ioh_gpio_pci_init); + +static void __exit ioh_gpio_pci_exit(void) +{ + pci_unregister_driver(&ioh_gpio_driver); +} +module_exit(ioh_gpio_pci_exit); + +MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 25f959d63d39c83fda09d93a052835ed35669b1a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 12 Jan 2011 17:00:26 -0800 Subject: drivers/telephony/ixj.c: fix warning CC drivers/telephony/ixj.o drivers/telephony/ixj.c:287: warning: \u2018ixj_pci_tbl\u2019 defined but not used Reported-by: Namhyung Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/telephony/ixj.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 0d236f4bb8c2..c4bc8d5a9d18 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -284,12 +284,11 @@ static int samplerate = 100; module_param(ixjdebug, int, 0); -static struct pci_device_id ixj_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ixj_pci_tbl) = { { PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { } }; - MODULE_DEVICE_TABLE(pci, ixj_pci_tbl); /************************************************************************ -- cgit v1.2.3 From a93192a5d245a262dc52fa426de5b20467308a77 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 12 Jan 2011 17:00:38 -0800 Subject: rapidio: use common destid storage for endpoints and switches Change code to use one storage location common for switches and endpoints. This eliminates unnecessary device type checks during basic access operations. Logic that assigns destid to RIO devices stays unchanged - as before, switches use an associated destid because they do not have their own. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 84 +++++++++++++++++---------------- drivers/rapidio/rio.c | 74 +++++++++-------------------- drivers/rapidio/switches/idt_gen2.c | 93 +++++++++++++------------------------ drivers/rapidio/switches/idtcps.c | 6 +-- drivers/rapidio/switches/tsi568.c | 13 ++---- drivers/rapidio/switches/tsi57x.c | 56 ++++++++++------------ include/linux/rio.h | 8 ++-- include/linux/rio_drv.h | 72 +++++----------------------- 8 files changed, 141 insertions(+), 265 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 1eb82c4c712e..51f0af241eb7 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -437,9 +437,15 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, next_destid++; } else rdev->destid = rio_get_device_id(port, destid, hopcount); - } else - /* Switch device has an associated destID */ - rdev->destid = RIO_INVALID_DESTID; + + rdev->hopcount = 0xff; + } else { + /* Switch device has an associated destID which + * will be adjusted later + */ + rdev->destid = destid; + rdev->hopcount = hopcount; + } /* If a PE has both switch and other functions, show it as a switch */ if (rio_is_switch(rdev)) { @@ -450,8 +456,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, if (!rswitch) goto cleanup; rswitch->switchid = next_switchid; - rswitch->hopcount = hopcount; - rswitch->destid = destid; rswitch->port_ok = 0; rswitch->route_table = kzalloc(sizeof(u8)* RIO_MAX_ROUTE_ENTRIES(port->sys_size), @@ -632,8 +636,7 @@ rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) /** * rio_route_add_entry- Add a route entry to a switch routing table - * @mport: Master port to send transaction - * @rswitch: Switch device + * @rdev: RIO device * @table: Routing table ID * @route_destid: Destination ID to be routed * @route_port: Port number to be routed @@ -647,31 +650,31 @@ rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) * on failure. */ static int -rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, +rio_route_add_entry(struct rio_dev *rdev, u16 table, u16 route_destid, u8 route_port, int lock) { int rc; if (lock) { - rc = rio_lock_device(mport, rswitch->destid, - rswitch->hopcount, 1000); + rc = rio_lock_device(rdev->net->hport, rdev->destid, + rdev->hopcount, 1000); if (rc) return rc; } - rc = rswitch->add_entry(mport, rswitch->destid, - rswitch->hopcount, table, - route_destid, route_port); + rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid, + rdev->hopcount, table, + route_destid, route_port); if (lock) - rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); + rio_unlock_device(rdev->net->hport, rdev->destid, + rdev->hopcount); return rc; } /** * rio_route_get_entry- Read a route entry in a switch routing table - * @mport: Master port to send transaction - * @rswitch: Switch device + * @rdev: RIO device * @table: Routing table ID * @route_destid: Destination ID to be routed * @route_port: Pointer to read port number into @@ -685,23 +688,24 @@ rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, * on failure. */ static int -rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, +rio_route_get_entry(struct rio_dev *rdev, u16 table, u16 route_destid, u8 *route_port, int lock) { int rc; if (lock) { - rc = rio_lock_device(mport, rswitch->destid, - rswitch->hopcount, 1000); + rc = rio_lock_device(rdev->net->hport, rdev->destid, + rdev->hopcount, 1000); if (rc) return rc; } - rc = rswitch->get_entry(mport, rswitch->destid, - rswitch->hopcount, table, - route_destid, route_port); + rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid, + rdev->hopcount, table, + route_destid, route_port); if (lock) - rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); + rio_unlock_device(rdev->net->hport, rdev->destid, + rdev->hopcount); return rc; } @@ -811,14 +815,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, if (rio_is_switch(rdev)) { next_switchid++; sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); - rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport, 0); rdev->rswitch->route_table[port->host_deviceid] = sw_inport; for (destid = 0; destid < next_destid; destid++) { if (destid == port->host_deviceid) continue; - rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, destid, sw_inport, 0); rdev->rswitch->route_table[destid] = sw_inport; } @@ -850,8 +854,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, "RIO: scanning device on port %d\n", port_num); rdev->rswitch->port_ok |= (1 << port_num); - rio_route_add_entry(port, rdev->rswitch, - RIO_GLOBAL_TABLE, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, RIO_ANY_DESTID(port->sys_size), port_num, 0); @@ -865,7 +868,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, destid < next_destid; destid++) { if (destid == port->host_deviceid) continue; - rio_route_add_entry(port, rdev->rswitch, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, destid, port_num, @@ -904,7 +907,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, next_destid++; } - rdev->rswitch->destid = sw_destid; + rdev->destid = sw_destid; } else pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", rio_name(rdev), rdev->vid, rdev->did); @@ -958,7 +961,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, next_switchid++; /* Associated destid is how we accessed this switch */ - rdev->rswitch->destid = destid; + rdev->destid = destid; pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", @@ -981,7 +984,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, for (ndestid = 0; ndestid < RIO_ANY_DESTID(port->sys_size); ndestid++) { - rio_route_get_entry(port, rdev->rswitch, + rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, ndestid, &route_port, 0); @@ -1076,7 +1079,7 @@ static void rio_update_route_tables(struct rio_mport *port) list_for_each_entry(rdev, &rio_devices, global_list) { - destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid; + destid = rdev->destid; list_for_each_entry(rswitch, &rio_switches, node) { @@ -1085,13 +1088,13 @@ static void rio_update_route_tables(struct rio_mport *port) if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { /* Skip if destid ends in empty switch*/ - if (rswitch->destid == destid) + if (rswitch->rdev->destid == destid) continue; sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo); if (rswitch->add_entry) { - rio_route_add_entry(port, rswitch, + rio_route_add_entry(rswitch->rdev, RIO_GLOBAL_TABLE, destid, sport, 0); rswitch->route_table[destid] = sport; @@ -1203,21 +1206,20 @@ static void rio_build_route_tables(void) list_for_each_entry(rdev, &rio_devices, global_list) if (rio_is_switch(rdev)) { - rio_lock_device(rdev->net->hport, rdev->rswitch->destid, - rdev->rswitch->hopcount, 1000); + rio_lock_device(rdev->net->hport, rdev->destid, + rdev->hopcount, 1000); for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); i++) { - if (rio_route_get_entry - (rdev->net->hport, rdev->rswitch, - RIO_GLOBAL_TABLE, i, &sport, 0) < 0) + if (rio_route_get_entry(rdev, + RIO_GLOBAL_TABLE, i, &sport, 0) < 0) continue; rdev->rswitch->route_table[i] = sport; } rio_unlock_device(rdev->net->hport, - rdev->rswitch->destid, - rdev->rswitch->hopcount); + rdev->destid, + rdev->hopcount); } } diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 7b5080c45569..c13289e10bb1 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -471,16 +471,9 @@ exit: */ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; u32 regval; - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - rio_mport_read_config_32(rdev->net->hport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), ®val); if (lock) @@ -488,7 +481,7 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) else regval &= ~RIO_PORT_N_CTL_LOCKOUT; - rio_mport_write_config_32(rdev->net->hport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), regval); return 0; @@ -507,7 +500,7 @@ static int rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) { u32 result; - int p_port, dstid, rc = -EIO; + int p_port, rc = -EIO; struct rio_dev *prev = NULL; /* Find switch with failed RIO link */ @@ -522,9 +515,7 @@ rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) if (prev == NULL) goto err_out; - dstid = (rdev->pef & RIO_PEF_SWITCH) ? - rdev->rswitch->destid : rdev->destid; - p_port = prev->rswitch->route_table[dstid]; + p_port = prev->rswitch->route_table[rdev->destid]; if (p_port != RIO_INVALID_ROUTE) { pr_debug("RIO: link failed on [%s]-P%d\n", @@ -567,15 +558,8 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) */ static int rio_chk_dev_access(struct rio_dev *rdev) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_chk_dev_access(rdev->net->hport, destid, hopcount); + return rio_mport_chk_dev_access(rdev->net->hport, + rdev->destid, rdev->hopcount); } /** @@ -588,23 +572,20 @@ static int rio_chk_dev_access(struct rio_dev *rdev) static int rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int checkcount; if (lnkresp) { /* Read from link maintenance response register * to clear valid bit */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), ®val); udelay(50); } /* Issue Input-status command */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), RIO_MNT_REQ_CMD_IS); @@ -615,7 +596,7 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) checkcount = 3; while (checkcount--) { udelay(50); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), ®val); if (regval & RIO_PORT_N_MNT_RSP_RVAL) { @@ -635,15 +616,12 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) */ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; u32 regval; u32 far_ackid, far_linkstat, near_ackid; if (err_status == 0) - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), &err_status); @@ -661,7 +639,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) pnum, regval); far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), ®val); pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); @@ -679,9 +657,8 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) /* Align near outstanding/outbound ackIDs with * far inbound. */ - rio_mport_write_config_32(mport, destid, - hopcount, rdev->phys_efptr + - RIO_PORT_N_ACK_STS_CSR(pnum), + rio_write_config_32(rdev, + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), (near_ackid << 24) | (far_ackid << 8) | far_ackid); /* Align far outstanding/outbound ackIDs with @@ -698,7 +675,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); } rd_err: - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), &err_status); pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); @@ -710,7 +687,7 @@ rd_err: RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); udelay(50); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), &err_status); pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); @@ -730,9 +707,6 @@ rd_err: int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) { struct rio_dev *rdev; - struct rio_mport *mport; - u8 hopcount; - u16 destid; u32 err_status, em_perrdet, em_ltlerrdet; int rc, portnum; @@ -800,17 +774,13 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) return 0; } - mport = rdev->net->hport; - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - /* * Process the port-write notification from switch */ if (rdev->rswitch->em_handle) rdev->rswitch->em_handle(rdev, portnum); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), &err_status); pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); @@ -840,7 +810,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) rdev->rswitch->port_ok &= ~(1 << portnum); rio_set_port_lockout(rdev, portnum, 1); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(portnum), RIO_PORT_N_ACK_CLEAR); @@ -851,28 +821,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) } } - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); if (em_perrdet) { pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", portnum, em_perrdet); /* Clear EM Port N Error Detect CSR */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); } - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); if (em_ltlerrdet) { pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", em_ltlerrdet); /* Clear EM L/T Layer Error Detect CSR */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); } /* Clear remaining error bits and Port-Write Pending bit */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), err_status); diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index 0bb871cb5c40..dd4b2b7112c0 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -209,9 +209,6 @@ idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int idtg2_em_init(struct rio_dev *rdev) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int i, tmp; @@ -220,29 +217,25 @@ idtg2_em_init(struct rio_dev *rdev) * All standard EM configuration should be performed at upper level. */ - pr_debug("RIO: %s [%d:%d]\n", __func__, destid, hopcount); + pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); /* Set Port-Write info CSR: PRIO=3 and CRF=1 */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_PW_INFO_CSR, 0x0000e000); + rio_write_config_32(rdev, IDT_PW_INFO_CSR, 0x0000e000); /* * Configure LT LAYER error reporting. */ /* Enable standard (RIO.p8) error reporting */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_LT_ERR_REPORT_EN, + rio_write_config_32(rdev, IDT_LT_ERR_REPORT_EN, REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR | REM_LTL_ERR_UNSUPTR); /* Use Port-Writes for LT layer error reporting. * Enable per-port reset */ - rio_mport_read_config_32(mport, destid, hopcount, - IDT_DEV_CTRL_1, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_DEV_CTRL_1, + rio_read_config_32(rdev, IDT_DEV_CTRL_1, ®val); + rio_write_config_32(rdev, IDT_DEV_CTRL_1, regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH); /* @@ -250,45 +243,40 @@ idtg2_em_init(struct rio_dev *rdev) */ /* Report all RIO.p8 errors supported by device */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037); + rio_write_config_32(rdev, IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037); /* Configure reporting of implementation specific errors/events */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_PORT_ISERR_REPORT_EN_BC, IDT_PORT_INIT_TX_ACQUIRED); + rio_write_config_32(rdev, IDT_PORT_ISERR_REPORT_EN_BC, + IDT_PORT_INIT_TX_ACQUIRED); /* Use Port-Writes for port error reporting and enable error logging */ tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); for (i = 0; i < tmp; i++) { - rio_mport_read_config_32(mport, destid, hopcount, - IDT_PORT_OPS(i), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, IDT_PORT_OPS(i), ®val); + rio_write_config_32(rdev, IDT_PORT_OPS(i), regval | IDT_PORT_OPS_GENPW | IDT_PORT_OPS_PL_ELOG | IDT_PORT_OPS_LL_ELOG | IDT_PORT_OPS_LT_ELOG); } /* Overwrite error log if full */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); + rio_write_config_32(rdev, IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); /* * Configure LANE error reporting. */ /* Disable line error reporting */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_LANE_ERR_REPORT_EN_BC, 0); + rio_write_config_32(rdev, IDT_LANE_ERR_REPORT_EN_BC, 0); /* Use Port-Writes for lane error reporting (when enabled) * (do per-lane update because lanes may have different configuration) */ tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16; for (i = 0; i < tmp; i++) { - rio_mport_read_config_32(mport, destid, hopcount, - IDT_LANE_CTRL(i), ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_LANE_CTRL(i), regval | IDT_LANE_CTRL_GENPW); + rio_read_config_32(rdev, IDT_LANE_CTRL(i), ®val); + rio_write_config_32(rdev, IDT_LANE_CTRL(i), + regval | IDT_LANE_CTRL_GENPW); } /* @@ -296,41 +284,32 @@ idtg2_em_init(struct rio_dev *rdev) */ /* Disable JTAG and I2C Error capture */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_AUX_PORT_ERR_CAP_EN, 0); + rio_write_config_32(rdev, IDT_AUX_PORT_ERR_CAP_EN, 0); /* Disable JTAG and I2C Error reporting/logging */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_AUX_ERR_REPORT_EN, 0); + rio_write_config_32(rdev, IDT_AUX_ERR_REPORT_EN, 0); /* Disable Port-Write notification from JTAG */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_JTAG_CTRL, 0); + rio_write_config_32(rdev, IDT_JTAG_CTRL, 0); /* Disable Port-Write notification from I2C */ - rio_mport_read_config_32(mport, destid, hopcount, - IDT_I2C_MCTRL, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_I2C_MCTRL, - regval & ~IDT_I2C_MCTRL_GENPW); + rio_read_config_32(rdev, IDT_I2C_MCTRL, ®val); + rio_write_config_32(rdev, IDT_I2C_MCTRL, regval & ~IDT_I2C_MCTRL_GENPW); /* * Configure CFG_BLK error reporting. */ /* Disable Configuration Block error capture */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_CFGBLK_ERR_CAPTURE_EN, 0); + rio_write_config_32(rdev, IDT_CFGBLK_ERR_CAPTURE_EN, 0); /* Disable Port-Writes for Configuration Block error reporting */ - rio_mport_read_config_32(mport, destid, hopcount, - IDT_CFGBLK_ERR_REPORT, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_CFGBLK_ERR_REPORT, - regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); + rio_read_config_32(rdev, IDT_CFGBLK_ERR_REPORT, ®val); + rio_write_config_32(rdev, IDT_CFGBLK_ERR_REPORT, + regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); /* set TVAL = ~50us */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); return 0; @@ -339,18 +318,15 @@ idtg2_em_init(struct rio_dev *rdev) static int idtg2_em_handler(struct rio_dev *rdev, u8 portnum) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval, em_perrdet, em_ltlerrdet; - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); if (em_ltlerrdet) { /* Service Logical/Transport Layer Error(s) */ if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) { /* Implementation specific error reported */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, ®val); pr_debug("RIO: %s Implementation Specific LTL errors" \ @@ -358,13 +334,12 @@ idtg2_em_handler(struct rio_dev *rdev, u8 portnum) rio_name(rdev), em_ltlerrdet, regval); /* Clear implementation specific address capture CSR */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_ISLTL_ADDRESS_CAP, 0); + rio_write_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, 0); } } - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); if (em_perrdet) { /* Service Port-Level Error(s) */ @@ -372,14 +347,14 @@ idtg2_em_handler(struct rio_dev *rdev, u8 portnum) /* Implementation Specific port error reported */ /* Get IS errors reported */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, IDT_PORT_ISERR_DET(portnum), ®val); pr_debug("RIO: %s Implementation Specific Port" \ " errors 0x%x\n", rio_name(rdev), regval); /* Clear all implementation specific events */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, IDT_PORT_ISERR_DET(portnum), 0); } } @@ -391,14 +366,10 @@ static ssize_t idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf) { struct rio_dev *rdev = to_rio_dev(dev); - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; ssize_t len = 0; u32 regval; - while (!rio_mport_read_config_32(mport, destid, hopcount, - IDT_ERR_RD, ®val)) { + while (!rio_read_config_32(rdev, IDT_ERR_RD, ®val)) { if (!regval) /* 0 = end of log */ break; len += snprintf(buf + len, PAGE_SIZE - len, diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c index fc9f6374f759..3a971077e7bf 100644 --- a/drivers/rapidio/switches/idtcps.c +++ b/drivers/rapidio/switches/idtcps.c @@ -117,10 +117,6 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; - pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); rdev->rswitch->add_entry = idtcps_route_add_entry; rdev->rswitch->get_entry = idtcps_route_get_entry; @@ -132,7 +128,7 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) if (do_enum) { /* set TVAL = ~50us */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); } diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c index b9a389b9f812..3994c00aa01f 100644 --- a/drivers/rapidio/switches/tsi568.c +++ b/drivers/rapidio/switches/tsi568.c @@ -113,22 +113,17 @@ tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, static int tsi568_em_init(struct rio_dev *rdev) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int portnum; - pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount); + pr_debug("TSI568 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); /* Make sure that Port-Writes are disabled (for all ports) */ for (portnum = 0; portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { - rio_mport_read_config_32(mport, destid, hopcount, - TSI568_SP_MODE(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, - TSI568_SP_MODE(portnum), - regval | TSI568_SP_MODE_PW_DIS); + rio_read_config_32(rdev, TSI568_SP_MODE(portnum), ®val); + rio_write_config_32(rdev, TSI568_SP_MODE(portnum), + regval | TSI568_SP_MODE_PW_DIS); } return 0; diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c index 2003fb63c404..1a62934bfebc 100644 --- a/drivers/rapidio/switches/tsi57x.c +++ b/drivers/rapidio/switches/tsi57x.c @@ -158,48 +158,45 @@ tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int tsi57x_em_init(struct rio_dev *rdev) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int portnum; - pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount); + pr_debug("TSI578 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); for (portnum = 0; portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { /* Make sure that Port-Writes are enabled (for all ports) */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_MODE(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_MODE(portnum), regval & ~TSI578_SP_MODE_PW_DIS); /* Clear all pending interrupts */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), regval & 0x07120214); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum), regval & 0x000700bd); /* Enable all interrupts to allow ports to send a port-write */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_CTL_INDEP(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_CTL_INDEP(portnum), regval | 0x000b0000); /* Skip next (odd) port if the current port is in x4 mode */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), ®val); if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4) @@ -207,7 +204,7 @@ tsi57x_em_init(struct rio_dev *rdev) } /* set TVAL = ~50us */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8); return 0; @@ -217,14 +214,12 @@ static int tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) { struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 intstat, err_status; int sendcount, checkcount; u8 route_port; u32 regval; - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), &err_status); @@ -232,15 +227,15 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | RIO_PORT_N_ERR_STS_PW_INP_ES))) { /* Remove any queued packets by locking/unlocking port */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), ®val); if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) { - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), regval | RIO_PORT_N_CTL_LOCKOUT); udelay(50); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), regval); } @@ -248,7 +243,7 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) /* Read from link maintenance response register to clear * valid bit */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum), ®val); @@ -257,13 +252,12 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) */ sendcount = 3; while (sendcount) { - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_CS_TX(portnum), 0x40fc8000); checkcount = 3; while (checkcount--) { udelay(50); - rio_mport_read_config_32( - mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum), ®val); @@ -277,25 +271,23 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) exit_es: /* Clear implementation specific error status bits */ - rio_mport_read_config_32(mport, destid, hopcount, - TSI578_SP_INT_STATUS(portnum), &intstat); + rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), &intstat); pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n", - destid, hopcount, portnum, intstat); + rdev->destid, rdev->hopcount, portnum, intstat); if (intstat & 0x10000) { - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_LUT_PEINF(portnum), ®val); regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24); route_port = rdev->rswitch->route_table[regval]; pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n", rio_name(rdev), portnum, regval); - tsi57x_route_add_entry(mport, destid, hopcount, + tsi57x_route_add_entry(mport, rdev->destid, rdev->hopcount, RIO_GLOBAL_TABLE, regval, route_port); } - rio_mport_write_config_32(mport, destid, hopcount, - TSI578_SP_INT_STATUS(portnum), - intstat & 0x000700bd); + rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum), + intstat & 0x000700bd); return 0; } diff --git a/include/linux/rio.h b/include/linux/rio.h index 0bed941f9b13..f6e25b3a6967 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -98,7 +98,8 @@ union rio_pw_msg; * @dev: Device model device * @riores: RIO resources this device owns * @pwcback: port-write callback function for this device - * @destid: Network destination ID + * @destid: Network destination ID (or associated destid for switch) + * @hopcount: Hopcount to this device * @prev: Previous RIO device connected to the current one */ struct rio_dev { @@ -126,6 +127,7 @@ struct rio_dev { struct resource riores[RIO_MAX_DEV_RESOURCES]; int (*pwcback) (struct rio_dev *rdev, union rio_pw_msg *msg, int step); u16 destid; + u8 hopcount; struct rio_dev *prev; }; @@ -229,8 +231,6 @@ struct rio_net { * @node: Node in global list of switches * @rdev: Associated RIO device structure * @switchid: Switch ID that is unique across a network - * @hopcount: Hopcount to this switch - * @destid: Associated destid in the path * @route_table: Copy of switch routing table * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0 * @add_entry: Callback for switch-specific route add function @@ -247,8 +247,6 @@ struct rio_switch { struct list_head node; struct rio_dev *rdev; u16 switchid; - u16 hopcount; - u16 destid; u8 *route_table; u32 port_ok; int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h index edc55da717b3..e09e565c4bce 100644 --- a/include/linux/rio_drv.h +++ b/include/linux/rio_drv.h @@ -150,16 +150,8 @@ static inline int rio_local_write_config_8(struct rio_mport *port, u32 offset, static inline int rio_read_config_32(struct rio_dev *rdev, u32 offset, u32 * data) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_read_config_32(rdev->net->hport, destid, hopcount, - offset, data); + return rio_mport_read_config_32(rdev->net->hport, rdev->destid, + rdev->hopcount, offset, data); }; /** @@ -174,16 +166,8 @@ static inline int rio_read_config_32(struct rio_dev *rdev, u32 offset, static inline int rio_write_config_32(struct rio_dev *rdev, u32 offset, u32 data) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_write_config_32(rdev->net->hport, destid, hopcount, - offset, data); + return rio_mport_write_config_32(rdev->net->hport, rdev->destid, + rdev->hopcount, offset, data); }; /** @@ -198,16 +182,8 @@ static inline int rio_write_config_32(struct rio_dev *rdev, u32 offset, static inline int rio_read_config_16(struct rio_dev *rdev, u32 offset, u16 * data) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_read_config_16(rdev->net->hport, destid, hopcount, - offset, data); + return rio_mport_read_config_16(rdev->net->hport, rdev->destid, + rdev->hopcount, offset, data); }; /** @@ -222,16 +198,8 @@ static inline int rio_read_config_16(struct rio_dev *rdev, u32 offset, static inline int rio_write_config_16(struct rio_dev *rdev, u32 offset, u16 data) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_write_config_16(rdev->net->hport, destid, hopcount, - offset, data); + return rio_mport_write_config_16(rdev->net->hport, rdev->destid, + rdev->hopcount, offset, data); }; /** @@ -245,16 +213,8 @@ static inline int rio_write_config_16(struct rio_dev *rdev, u32 offset, */ static inline int rio_read_config_8(struct rio_dev *rdev, u32 offset, u8 * data) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_read_config_8(rdev->net->hport, destid, hopcount, - offset, data); + return rio_mport_read_config_8(rdev->net->hport, rdev->destid, + rdev->hopcount, offset, data); }; /** @@ -268,16 +228,8 @@ static inline int rio_read_config_8(struct rio_dev *rdev, u32 offset, u8 * data) */ static inline int rio_write_config_8(struct rio_dev *rdev, u32 offset, u8 data) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_write_config_8(rdev->net->hport, destid, hopcount, - offset, data); + return rio_mport_write_config_8(rdev->net->hport, rdev->destid, + rdev->hopcount, offset, data); }; extern int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, -- cgit v1.2.3 From ded05782719d0f7e79af98be7cf88c7e23a90435 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 12 Jan 2011 17:00:39 -0800 Subject: rapidio: integrate rio_switch into rio_dev Convert RIO switches device structures (rio_dev + rio_switch) into a single allocation unit. This change is based on the fact that RIO switches are using common RIO device objects anyway. Allocating RIO switch objects as RIO devices with added space for switch information simplifies handling of RIO switch devices. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 59 +++++++++++++++++--------------- drivers/rapidio/rio-sysfs.c | 4 +-- include/linux/rio.h | 82 ++++++++++++++++++++++----------------------- 3 files changed, 75 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 51f0af241eb7..45d14cd6b356 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -378,12 +378,30 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, struct rio_dev *rdev; struct rio_switch *rswitch = NULL; int result, rdid; + size_t size; + u32 swpinfo = 0; - rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); + size = sizeof(struct rio_dev); + if (rio_mport_read_config_32(port, destid, hopcount, + RIO_PEF_CAR, &result)) + return NULL; + + if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { + rio_mport_read_config_32(port, destid, hopcount, + RIO_SWP_INFO_CAR, &swpinfo); + if (result & RIO_PEF_SWITCH) { + size += (RIO_GET_TOTAL_PORTS(swpinfo) * + sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); + } + } + + rdev = kzalloc(size, GFP_KERNEL); if (!rdev) return NULL; rdev->net = net; + rdev->pef = result; + rdev->swpinfo = swpinfo; rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, &result); rdev->did = result >> 16; @@ -397,8 +415,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, &result); rdev->asm_rev = result >> 16; - rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, - &rdev->pef); if (rdev->pef & RIO_PEF_EXT_FEATURES) { rdev->efptr = result & 0xffff; rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, @@ -408,11 +424,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, hopcount, RIO_EFB_ERR_MGMNT); } - if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { - rio_mport_read_config_32(port, destid, hopcount, - RIO_SWP_INFO_CAR, &rdev->swpinfo); - } - rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, &rdev->src_ops); rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, @@ -449,12 +460,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, /* If a PE has both switch and other functions, show it as a switch */ if (rio_is_switch(rdev)) { - rswitch = kzalloc(sizeof(*rswitch) + - RIO_GET_TOTAL_PORTS(rdev->swpinfo) * - sizeof(rswitch->nextdev[0]), - GFP_KERNEL); - if (!rswitch) - goto cleanup; + rswitch = rdev->rswitch; rswitch->switchid = next_switchid; rswitch->port_ok = 0; rswitch->route_table = kzalloc(sizeof(u8)* @@ -466,15 +472,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; - rdev->rswitch = rswitch; - rswitch->rdev = rdev; dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, - rdev->rswitch->switchid); + rswitch->switchid); rio_switch_init(rdev, do_enum); - if (do_enum && rdev->rswitch->clr_table) - rdev->rswitch->clr_table(port, destid, hopcount, - RIO_GLOBAL_TABLE); + if (do_enum && rswitch->clr_table) + rswitch->clr_table(port, destid, hopcount, + RIO_GLOBAL_TABLE); list_add_tail(&rswitch->node, &rio_switches); @@ -510,10 +514,9 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, return rdev; cleanup: - if (rswitch) { + if (rswitch->route_table) kfree(rswitch->route_table); - kfree(rswitch); - } + kfree(rdev); return NULL; } @@ -1072,7 +1075,7 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) */ static void rio_update_route_tables(struct rio_mport *port) { - struct rio_dev *rdev; + struct rio_dev *rdev, *swrdev; struct rio_switch *rswitch; u8 sport; u16 destid; @@ -1087,14 +1090,16 @@ static void rio_update_route_tables(struct rio_mport *port) continue; if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { + swrdev = sw_to_rio_dev(rswitch); + /* Skip if destid ends in empty switch*/ - if (rswitch->rdev->destid == destid) + if (swrdev->destid == destid) continue; - sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo); + sport = RIO_GET_PORT_NUM(swrdev->swpinfo); if (rswitch->add_entry) { - rio_route_add_entry(rswitch->rdev, + rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE, destid, sport, 0); rswitch->route_table[destid] = sport; diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 137ed93ee33f..76b41853a877 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -217,7 +217,7 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) err = device_create_bin_file(&rdev->dev, &rio_config_attr); - if (!err && rdev->rswitch) { + if (!err && (rdev->pef & RIO_PEF_SWITCH)) { err = device_create_file(&rdev->dev, &dev_attr_routes); if (!err && rdev->rswitch->sw_sysfs) err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE); @@ -239,7 +239,7 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) void rio_remove_sysfs_dev_files(struct rio_dev *rdev) { device_remove_bin_file(&rdev->dev, &rio_config_attr); - if (rdev->rswitch) { + if (rdev->pef & RIO_PEF_SWITCH) { device_remove_file(&rdev->dev, &dev_attr_routes); if (rdev->rswitch->sw_sysfs) rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); diff --git a/include/linux/rio.h b/include/linux/rio.h index f6e25b3a6967..9b558856a8b6 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -71,8 +71,46 @@ extern struct device rio_bus; extern struct list_head rio_devices; /* list of all devices */ struct rio_mport; +struct rio_dev; union rio_pw_msg; +/** + * struct rio_switch - RIO switch info + * @node: Node in global list of switches + * @switchid: Switch ID that is unique across a network + * @route_table: Copy of switch routing table + * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0 + * @add_entry: Callback for switch-specific route add function + * @get_entry: Callback for switch-specific route get function + * @clr_table: Callback for switch-specific clear route table function + * @set_domain: Callback for switch-specific domain setting function + * @get_domain: Callback for switch-specific domain get function + * @em_init: Callback for switch-specific error management init function + * @em_handle: Callback for switch-specific error management handler function + * @sw_sysfs: Callback that initializes switch-specific sysfs attributes + * @nextdev: Array of per-port pointers to the next attached device + */ +struct rio_switch { + struct list_head node; + u16 switchid; + u8 *route_table; + u32 port_ok; + int (*add_entry) (struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port); + int (*get_entry) (struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 *route_port); + int (*clr_table) (struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table); + int (*set_domain) (struct rio_mport *mport, u16 destid, u8 hopcount, + u8 sw_domain); + int (*get_domain) (struct rio_mport *mport, u16 destid, u8 hopcount, + u8 *sw_domain); + int (*em_init) (struct rio_dev *dev); + int (*em_handle) (struct rio_dev *dev, u8 swport); + int (*sw_sysfs) (struct rio_dev *dev, int create); + struct rio_dev *nextdev[0]; +}; + /** * struct rio_dev - RIO device info * @global_list: Node in list of all RIO devices @@ -93,7 +131,6 @@ union rio_pw_msg; * @phys_efptr: RIO device extended features pointer * @em_efptr: RIO Error Management features pointer * @dma_mask: Mask of bits of RIO address this device implements - * @rswitch: Pointer to &struct rio_switch if valid for this device * @driver: Driver claiming this device * @dev: Device model device * @riores: RIO resources this device owns @@ -101,6 +138,7 @@ union rio_pw_msg; * @destid: Network destination ID (or associated destid for switch) * @hopcount: Hopcount to this device * @prev: Previous RIO device connected to the current one + * @rswitch: struct rio_switch (if valid for this device) */ struct rio_dev { struct list_head global_list; /* node in list of all RIO devices */ @@ -121,7 +159,6 @@ struct rio_dev { u32 phys_efptr; u32 em_efptr; u64 dma_mask; - struct rio_switch *rswitch; /* RIO switch info */ struct rio_driver *driver; /* RIO driver claiming this device */ struct device dev; /* LDM device structure */ struct resource riores[RIO_MAX_DEV_RESOURCES]; @@ -129,11 +166,13 @@ struct rio_dev { u16 destid; u8 hopcount; struct rio_dev *prev; + struct rio_switch rswitch[0]; /* RIO switch info */ }; #define rio_dev_g(n) list_entry(n, struct rio_dev, global_list) #define rio_dev_f(n) list_entry(n, struct rio_dev, net_list) #define to_rio_dev(n) container_of(n, struct rio_dev, dev) +#define sw_to_rio_dev(n) container_of(n, struct rio_dev, rswitch[0]) /** * struct rio_msg - RIO message event @@ -226,45 +265,6 @@ struct rio_net { #define RIO_SW_SYSFS_CREATE 1 /* Create switch attributes */ #define RIO_SW_SYSFS_REMOVE 0 /* Remove switch attributes */ -/** - * struct rio_switch - RIO switch info - * @node: Node in global list of switches - * @rdev: Associated RIO device structure - * @switchid: Switch ID that is unique across a network - * @route_table: Copy of switch routing table - * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0 - * @add_entry: Callback for switch-specific route add function - * @get_entry: Callback for switch-specific route get function - * @clr_table: Callback for switch-specific clear route table function - * @set_domain: Callback for switch-specific domain setting function - * @get_domain: Callback for switch-specific domain get function - * @em_init: Callback for switch-specific error management initialization function - * @em_handle: Callback for switch-specific error management handler function - * @sw_sysfs: Callback that initializes switch-specific sysfs attributes - * @nextdev: Array of per-port pointers to the next attached device - */ -struct rio_switch { - struct list_head node; - struct rio_dev *rdev; - u16 switchid; - u8 *route_table; - u32 port_ok; - int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, - u16 table, u16 route_destid, u8 route_port); - int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, - u16 table, u16 route_destid, u8 * route_port); - int (*clr_table) (struct rio_mport *mport, u16 destid, u8 hopcount, - u16 table); - int (*set_domain) (struct rio_mport *mport, u16 destid, u8 hopcount, - u8 sw_domain); - int (*get_domain) (struct rio_mport *mport, u16 destid, u8 hopcount, - u8 *sw_domain); - int (*em_init) (struct rio_dev *dev); - int (*em_handle) (struct rio_dev *dev, u8 swport); - int (*sw_sysfs) (struct rio_dev *dev, int create); - struct rio_dev *nextdev[0]; -}; - /* Low-level architecture-dependent routines */ /** -- cgit v1.2.3 From e6536927e64a2511864f2141d3e5b198b3f25ba6 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 12 Jan 2011 17:00:40 -0800 Subject: rapidio: add definitions of Component Tag fields Add definition of the unique device identifier field in the component tag. RIO_CTAG_UDEVID does not take all 32 bits of the component tag value to allow future extensions to the component tag use. Selected size of the RIO_CTAG_UDEVID field (17 bits) is sufficient to accommodate maximum number of endpoints in large RIO network (16-bit id) plus switches. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio.c | 2 +- include/linux/rio.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index c13289e10bb1..cc2a3b74d0f0 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -710,7 +710,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) u32 err_status, em_perrdet, em_ltlerrdet; int rc, portnum; - rdev = rio_get_comptag(pw_msg->em.comptag, NULL); + rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); if (rdev == NULL) { /* Device removed or enumeration error */ pr_debug("RIO: %s No matching device for CTag 0x%08x\n", diff --git a/include/linux/rio.h b/include/linux/rio.h index 9b558856a8b6..ff681ebba585 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -66,6 +66,16 @@ #define RIO_PW_MSG_SIZE 64 +/* + * A component tag value (stored in the component tag CSR) is used as device's + * unique identifier assigned during enumeration. Besides being used for + * identifying switches (which do not have device ID register), it also is used + * by error management notification and therefore has to be assigned + * to endpoints as well. + */ +#define RIO_CTAG_RESRVD 0xfffe0000 /* Reserved */ +#define RIO_CTAG_UDEVID 0x0001ffff /* Unique device identifier */ + extern struct bus_type rio_bus_type; extern struct device rio_bus; extern struct list_head rio_devices; /* list of all devices */ -- cgit v1.2.3 From 17e9620563e25e759e677508068305e5d6ce44ff Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 12 Jan 2011 17:00:41 -0800 Subject: rapidio: add device object linking into discovery Add setting links between rio_dev objects into the discovery process. This needed to report device connections on agent (non-host) processors that perform RIO discovery. Originally, these links have been introduced for enumerating host only to support error management. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 45d14cd6b356..e655756e1185 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -947,7 +947,7 @@ static int rio_enum_complete(struct rio_mport *port) */ static int __devinit rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, - u8 hopcount) + u8 hopcount, struct rio_dev *prev, int prev_port) { u8 port_num, route_port; struct rio_dev *rdev; @@ -957,6 +957,9 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { /* Add device to the global and bus/net specific list. */ list_add_tail(&rdev->net_list, &net->devices); + rdev->prev = prev; + if (prev && rio_is_switch(prev)) + prev->rswitch->nextdev[prev_port] = rdev; } else return -1; @@ -998,8 +1001,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, if (ndestid == RIO_ANY_DESTID(port->sys_size)) continue; rio_unlock_device(port, destid, hopcount); - if (rio_disc_peer - (net, port, ndestid, hopcount + 1) < 0) + if (rio_disc_peer(net, port, ndestid, + hopcount + 1, rdev, port_num) < 0) return -1; } } @@ -1291,7 +1294,7 @@ int __devinit rio_disc_mport(struct rio_mport *mport) mport->host_deviceid); if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), - 0) < 0) { + 0, NULL, 0) < 0) { printk(KERN_INFO "RIO: master port %d device has failed discovery\n", mport->id); -- cgit v1.2.3 From 558bda65775d740a97efae2b67f1d53da7a7b9a2 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 12 Jan 2011 17:00:42 -0800 Subject: rapidio: use Component Tag for unified switch identification Change the way how switchid value is set. Local counter variable does not provide unified way to identify switch devices in a system with multiple processors. Using local counter leads to the situation when the same RIO switch has different switch ID for each processor. Replacing local counter with unique portion of the Component Tag provides unified reference to the switch by every processor in the system. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index e655756e1185..467e82bd0929 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -46,7 +46,6 @@ static void rio_init_em(struct rio_dev *rdev); DEFINE_SPINLOCK(rio_global_list_lock); static int next_destid = 0; -static int next_switchid = 0; static int next_net = 0; static int next_comptag = 1; @@ -438,6 +437,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, rio_mport_write_config_32(port, destid, hopcount, RIO_COMPONENT_TAG_CSR, next_comptag); rdev->comp_tag = next_comptag++; + } else { + rio_mport_read_config_32(port, destid, hopcount, + RIO_COMPONENT_TAG_CSR, + &rdev->comp_tag); } if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { @@ -461,7 +464,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, /* If a PE has both switch and other functions, show it as a switch */ if (rio_is_switch(rdev)) { rswitch = rdev->rswitch; - rswitch->switchid = next_switchid; + rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID; rswitch->port_ok = 0; rswitch->route_table = kzalloc(sizeof(u8)* RIO_MAX_ROUTE_ENTRIES(port->sys_size), @@ -816,7 +819,6 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, return -1; if (rio_is_switch(rdev)) { - next_switchid++; sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport, 0); @@ -964,8 +966,6 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, return -1; if (rio_is_switch(rdev)) { - next_switchid++; - /* Associated destid is how we accessed this switch */ rdev->destid = destid; -- cgit v1.2.3 From 2e9d4d84847b5b05c8a049b681f15906a91e0f78 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 12 Jan 2011 17:00:43 -0800 Subject: rapidio: add new idt sRIO switches Add new sRIO switch device IDs and enable a basic support for them. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/switches/idt_gen2.c | 2 ++ include/linux/rio_ids.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index dd4b2b7112c0..095016a9dec1 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -416,3 +416,5 @@ static int idtg2_switch_init(struct rio_dev *rdev, int do_enum) DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init); DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init); +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init); +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init); diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h index ee7b6ada188f..7410d3365e2a 100644 --- a/include/linux/rio_ids.h +++ b/include/linux/rio_ids.h @@ -36,5 +36,7 @@ #define RIO_DID_IDTCPS10Q 0x035e #define RIO_DID_IDTCPS1848 0x0374 #define RIO_DID_IDTCPS1616 0x0379 +#define RIO_DID_IDTVPS1616 0x0377 +#define RIO_DID_IDTSPS1616 0x0378 #endif /* LINUX_RIO_IDS_H */ -- cgit v1.2.3 From 0329326e85aaa30fb8d427828c718d565c287385 Mon Sep 17 00:00:00 2001 From: "Matti J. Aaltonen" Date: Wed, 12 Jan 2011 17:00:47 -0800 Subject: NFC: Driver for NXP Semiconductors PN544 NFC chip. Creates a new "Near Field Communication" subsystem in drivers/nfc. http://en.wikipedia.org/wiki/Near_Field_Communication is useful ;) This is a driver for the pn544 NFC device. The driver transfers ETSI messages between the device and the user space. Signed-off-by: Matti J. Aaltonen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/nfc/nfc-pn544.txt | 114 +++++ drivers/Kconfig | 2 + drivers/Makefile | 2 +- drivers/nfc/Kconfig | 30 ++ drivers/nfc/Makefile | 5 + drivers/nfc/pn544.c | 891 ++++++++++++++++++++++++++++++++++++++++ include/linux/nfc/pn544.h | 97 +++++ 7 files changed, 1140 insertions(+), 1 deletion(-) create mode 100644 Documentation/nfc/nfc-pn544.txt create mode 100644 drivers/nfc/Kconfig create mode 100644 drivers/nfc/Makefile create mode 100644 drivers/nfc/pn544.c create mode 100644 include/linux/nfc/pn544.h (limited to 'drivers') diff --git a/Documentation/nfc/nfc-pn544.txt b/Documentation/nfc/nfc-pn544.txt new file mode 100644 index 000000000000..2fcac9f5996e --- /dev/null +++ b/Documentation/nfc/nfc-pn544.txt @@ -0,0 +1,114 @@ +Kernel driver for the NXP Semiconductors PN544 Near Field +Communication chip + +Author: Jari Vanhala +Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com) + +General +------- + +The PN544 is an integrated transmission module for contactless +communication. The driver goes under drives/nfc/ and is compiled as a +module named "pn544". It registers a misc device and creates a device +file named "/dev/pn544". + +Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C. + +The Interface +------------- + +The driver offers a sysfs interface for a hardware test and an IOCTL +interface for selecting between two operating modes. There are read, +write and poll functions for transferring messages. The two operating +modes are the normal (HCI) mode and the firmware update mode. + +PN544 is controlled by sending messages from the userspace to the +chip. The main function of the driver is just to pass those messages +without caring about the message content. + + +Protocols +--------- + +In the normal (HCI) mode and in the firmware update mode read and +write functions behave a bit differently because the message formats +or the protocols are different. + +In the normal (HCI) mode the protocol used is derived from the ETSI +HCI specification. The firmware is updated using a specific protocol, +which is different from HCI. + +HCI messages consist of an eight bit header and the message body. The +header contains the message length. Maximum size for an HCI message is +33. In HCI mode sent messages are tested for a correct +checksum. Firmware update messages have the length in the second (MSB) +and third (LSB) bytes of the message. The maximum FW message length is +1024 bytes. + +For the ETSI HCI specification see +http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx + +The Hardware Test +----------------- + +The idea of the test is that it can performed by reading from the +corresponding sysfs file. The test is implemented in the board file +and it should test that PN544 can be put into the firmware update +mode. If the test is not implemented the sysfs file does not get +created. + +Example: +> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test +1 + +Normal Operation +---------------- + +PN544 is powered up when the device file is opened, otherwise it's +turned off. Only one instance can use the device at a time. + +Userspace applications control PN544 with HCI messages. The hardware +sends an interrupt when data is available for reading. Data is +physically read when the read function is called by a userspace +application. Poll() checks the read interrupt state. Configuration and +self testing are also done from the userspace using read and write. + +Example platform data: + +static int rx71_pn544_nfc_request_resources(struct i2c_client *client) +{ + /* Get and setup the HW resources for the device */ +} + +static void rx71_pn544_nfc_free_resources(void) +{ + /* Release the HW resources */ +} + +static void rx71_pn544_nfc_enable(int fw) +{ + /* Turn the device on */ +} + +static int rx71_pn544_nfc_test(void) +{ + /* + * Put the device into the FW update mode + * and then back to the normal mode. + * Check the behavior and return one on success, + * zero on failure. + */ +} + +static void rx71_pn544_nfc_disable(void) +{ + /* turn the power off */ +} + +static struct pn544_nfc_platform_data rx71_nfc_data = { + .request_resources = rx71_pn544_nfc_request_resources, + .free_resources = rx71_pn544_nfc_free_resources, + .enable = rx71_pn544_nfc_enable, + .test = rx71_pn544_nfc_test, + .disable = rx71_pn544_nfc_disable, +}; diff --git a/drivers/Kconfig b/drivers/Kconfig index 3d93b3a3d630..dd0a5b5e9bf3 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -88,6 +88,8 @@ source "drivers/memstick/Kconfig" source "drivers/leds/Kconfig" +source "drivers/nfc/Kconfig" + source "drivers/accessibility/Kconfig" source "drivers/infiniband/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index bf15ce7493d2..ef5132469f58 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_FB_INTEL) += video/intelfb/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ -obj-y += base/ block/ misc/ mfd/ +obj-y += base/ block/ misc/ mfd/ nfc/ obj-$(CONFIG_NUBUS) += nubus/ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig new file mode 100644 index 000000000000..ffedfd492754 --- /dev/null +++ b/drivers/nfc/Kconfig @@ -0,0 +1,30 @@ +# +# Near Field Communication (NFC) devices +# + +menuconfig NFC_DEVICES + bool "NFC devices" + default n + ---help--- + You'll have to say Y if your computer contains an NFC device that + you want to use under Linux. + + You can say N here if you don't have any Near Field Communication + devices connected to your computer. + +if NFC_DEVICES + +config PN544_NFC + tristate "PN544 NFC driver" + depends on I2C + select CRC_CCITT + default n + ---help--- + Say yes if you want PN544 Near Field Communication driver. + This is for i2c connected version. If unsure, say N here. + + To compile this driver as a module, choose m here. The module will + be called pn544. + + +endif # NFC_DEVICES diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile new file mode 100644 index 000000000000..a4efb164ec49 --- /dev/null +++ b/drivers/nfc/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for nfc devices +# + +obj-$(CONFIG_PN544_NFC) += pn544.o diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c new file mode 100644 index 000000000000..401c44b6eadb --- /dev/null +++ b/drivers/nfc/pn544.c @@ -0,0 +1,891 @@ +/* + * Driver for the PN544 NFC chip. + * + * Copyright (C) Nokia Corporation + * + * Author: Jari Vanhala + * Contact: Matti Aaltonen + * + * 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. + * + * 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 +#include /* for TCGETS */ +#include + +#define DRIVER_CARD "PN544 NFC" +#define DRIVER_DESC "NFC driver for PN544" + +static struct i2c_device_id pn544_id_table[] = { + { PN544_DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pn544_id_table); + +#define HCI_MODE 0 +#define FW_MODE 1 + +enum pn544_state { + PN544_ST_COLD, + PN544_ST_FW_READY, + PN544_ST_READY, +}; + +enum pn544_irq { + PN544_NONE, + PN544_INT, +}; + +struct pn544_info { + struct miscdevice miscdev; + struct i2c_client *i2c_dev; + struct regulator_bulk_data regs[2]; + + enum pn544_state state; + wait_queue_head_t read_wait; + loff_t read_offset; + enum pn544_irq read_irq; + struct mutex read_mutex; /* Serialize read_irq access */ + struct mutex mutex; /* Serialize info struct access */ + u8 *buf; + unsigned int buflen; +}; + +static const char reg_vdd_io[] = "Vdd_IO"; +static const char reg_vbat[] = "VBat"; + +/* sysfs interface */ +static ssize_t pn544_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pn544_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->i2c_dev; + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test()); +} + +static int pn544_enable(struct pn544_info *info, int mode) +{ + struct pn544_nfc_platform_data *pdata; + struct i2c_client *client = info->i2c_dev; + + int r; + + r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs); + if (r < 0) + return r; + + pdata = client->dev.platform_data; + info->read_irq = PN544_NONE; + if (pdata->enable) + pdata->enable(mode); + + if (mode) { + info->state = PN544_ST_FW_READY; + dev_dbg(&client->dev, "now in FW-mode\n"); + } else { + info->state = PN544_ST_READY; + dev_dbg(&client->dev, "now in HCI-mode\n"); + } + + usleep_range(10000, 15000); + + return 0; +} + +static void pn544_disable(struct pn544_info *info) +{ + struct pn544_nfc_platform_data *pdata; + struct i2c_client *client = info->i2c_dev; + + pdata = client->dev.platform_data; + if (pdata->disable) + pdata->disable(); + + info->state = PN544_ST_COLD; + + dev_dbg(&client->dev, "Now in OFF-mode\n"); + + msleep(PN544_RESETVEN_TIME); + + info->read_irq = PN544_NONE; + regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs); +} + +static int check_crc(u8 *buf, int buflen) +{ + u8 len; + u16 crc; + + len = buf[0] + 1; + if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) { + pr_err(PN544_DRIVER_NAME + ": CRC; corrupt packet len %u (%d)\n", len, buflen); + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + crc = crc_ccitt(0xffff, buf, len - 2); + crc = ~crc; + + if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) { + pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", + crc, buf[len-1], buf[len-2]); + + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + return 0; +} + +static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + if (len < 4 || len != (buf[0] + 1)) { + dev_err(&client->dev, "%s: Illegal message length: %d\n", + __func__, len); + return -EINVAL; + } + + if (check_crc(buf, len)) + return -EINVAL; + + usleep_range(3000, 6000); + + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "send: %d\n", r); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "send2: %d\n", r); + } + + if (r != len) + return -EREMOTEIO; + + return r; +} + +static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen) +{ + int r; + u8 len; + + /* + * You could read a packet in one go, but then you'd need to read + * max size and rest would be 0xff fill, so we do split reads. + */ + r = i2c_master_recv(client, &len, 1); + dev_dbg(&client->dev, "recv1: %d\n", r); + + if (r != 1) + return -EREMOTEIO; + + if (len < PN544_LLC_HCI_OVERHEAD) + len = PN544_LLC_HCI_OVERHEAD; + else if (len > (PN544_MSG_MAX_SIZE - 1)) + len = PN544_MSG_MAX_SIZE - 1; + + if (1 + len > buflen) /* len+(data+crc16) */ + return -EMSGSIZE; + + buf[0] = len; + + r = i2c_master_recv(client, buf + 1, len); + dev_dbg(&client->dev, "recv2: %d\n", r); + + if (r != len) + return -EREMOTEIO; + + usleep_range(3000, 6000); + + return r + 1; +} + +static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + dev_dbg(&client->dev, "%s\n", __func__); + + if (len < PN544_FW_HEADER_SIZE || + (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len) + return -EINVAL; + + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "fw send: %d\n", r); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "fw send2: %d\n", r); + } + + if (r != len) + return -EREMOTEIO; + + return r; +} + +static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen) +{ + int r, len; + + if (buflen < PN544_FW_HEADER_SIZE) + return -EINVAL; + + r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE); + dev_dbg(&client->dev, "FW recv1: %d\n", r); + + if (r < 0) + return r; + + if (r < PN544_FW_HEADER_SIZE) + return -EINVAL; + + len = (buf[1] << 8) + buf[2]; + if (len == 0) /* just header, no additional data */ + return r; + + if (len > buflen - PN544_FW_HEADER_SIZE) + return -EMSGSIZE; + + r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len); + dev_dbg(&client->dev, "fw recv2: %d\n", r); + + if (r != len) + return -EINVAL; + + return r + PN544_FW_HEADER_SIZE; +} + +static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id) +{ + struct pn544_info *info = dev_id; + struct i2c_client *client = info->i2c_dev; + + BUG_ON(!info); + BUG_ON(irq != info->i2c_dev->irq); + + dev_dbg(&client->dev, "IRQ\n"); + + mutex_lock(&info->read_mutex); + info->read_irq = PN544_INT; + mutex_unlock(&info->read_mutex); + + wake_up_interruptible(&info->read_wait); + + return IRQ_HANDLED; +} + +static enum pn544_irq pn544_irq_state(struct pn544_info *info) +{ + enum pn544_irq irq; + + mutex_lock(&info->read_mutex); + irq = info->read_irq; + mutex_unlock(&info->read_mutex); + /* + * XXX: should we check GPIO-line status directly? + * return pdata->irq_status() ? PN544_INT : PN544_NONE; + */ + + return irq; +} + +static ssize_t pn544_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + enum pn544_irq irq; + size_t len; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__, + info, count); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + irq = pn544_irq_state(info); + if (irq == PN544_NONE) { + if (file->f_flags & O_NONBLOCK) { + r = -EAGAIN; + goto out; + } + + if (wait_event_interruptible(info->read_wait, + (info->read_irq == PN544_INT))) { + r = -ERESTARTSYS; + goto out; + } + } + + if (info->state == PN544_ST_FW_READY) { + len = min(count, info->buflen); + + mutex_lock(&info->read_mutex); + r = pn544_fw_read(info->i2c_dev, info->buf, len); + info->read_irq = PN544_NONE; + mutex_unlock(&info->read_mutex); + + if (r < 0) { + dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r); + goto out; + } + + print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, r, false); + + *offset += r; + if (copy_to_user(buf, info->buf, r)) { + r = -EFAULT; + goto out; + } + } else { + len = min(count, info->buflen); + + mutex_lock(&info->read_mutex); + r = pn544_i2c_read(info->i2c_dev, info->buf, len); + info->read_irq = PN544_NONE; + mutex_unlock(&info->read_mutex); + + if (r < 0) { + dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r); + goto out; + } + print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, r, false); + + *offset += r; + if (copy_to_user(buf, info->buf, r)) { + r = -EFAULT; + goto out; + } + } + +out: + mutex_unlock(&info->mutex); + + return r; +} + +static unsigned int pn544_poll(struct file *file, poll_table *wait) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p\n", __func__, info); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + poll_wait(file, &info->read_wait, wait); + + if (pn544_irq_state(info) == PN544_INT) { + r = POLLIN | POLLRDNORM; + goto out; + } +out: + mutex_unlock(&info->mutex); + + return r; +} + +static ssize_t pn544_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + ssize_t len; + int r; + + dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__, + info, count); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + /* + * XXX: should we detect rset-writes and clean possible + * read_irq state + */ + if (info->state == PN544_ST_FW_READY) { + size_t fw_len; + + if (count < PN544_FW_HEADER_SIZE) { + r = -EINVAL; + goto out; + } + + len = min(count, info->buflen); + if (copy_from_user(info->buf, buf, len)) { + r = -EFAULT; + goto out; + } + + print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, len, false); + + fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) + + info->buf[2]; + + if (len > fw_len) /* 1 msg at a time */ + len = fw_len; + + r = pn544_fw_write(info->i2c_dev, info->buf, len); + } else { + if (count < PN544_LLC_MIN_SIZE) { + r = -EINVAL; + goto out; + } + + len = min(count, info->buflen); + if (copy_from_user(info->buf, buf, len)) { + r = -EFAULT; + goto out; + } + + print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, len, false); + + if (len > (info->buf[0] + 1)) /* 1 msg at a time */ + len = info->buf[0] + 1; + + r = pn544_i2c_write(info->i2c_dev, info->buf, len); + } +out: + mutex_unlock(&info->mutex); + + return r; + +} + +static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + struct pn544_nfc_platform_data *pdata; + unsigned int val; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + pdata = info->i2c_dev->dev.platform_data; + switch (cmd) { + case PN544_GET_FW_MODE: + dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__); + + val = (info->state == PN544_ST_FW_READY); + if (copy_to_user((void __user *)arg, &val, sizeof(val))) { + r = -EFAULT; + goto out; + } + + break; + + case PN544_SET_FW_MODE: + dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__); + + if (copy_from_user(&val, (void __user *)arg, sizeof(val))) { + r = -EFAULT; + goto out; + } + + if (val) { + if (info->state == PN544_ST_FW_READY) + break; + + pn544_disable(info); + r = pn544_enable(info, FW_MODE); + if (r < 0) + goto out; + } else { + if (info->state == PN544_ST_READY) + break; + pn544_disable(info); + r = pn544_enable(info, HCI_MODE); + if (r < 0) + goto out; + } + file->f_pos = info->read_offset; + break; + + case TCGETS: + dev_dbg(&client->dev, "%s: TCGETS\n", __func__); + + r = -ENOIOCTLCMD; + break; + + default: + dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd); + r = -ENOIOCTLCMD; + break; + } + +out: + mutex_unlock(&info->mutex); + + return r; +} + +static int pn544_open(struct inode *inode, struct file *file) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, + info, info->i2c_dev); + + mutex_lock(&info->mutex); + + /* + * Only 1 at a time. + * XXX: maybe user (counter) would work better + */ + if (info->state != PN544_ST_COLD) { + r = -EBUSY; + goto out; + } + + file->f_pos = info->read_offset; + r = pn544_enable(info, HCI_MODE); + +out: + mutex_unlock(&info->mutex); + return r; +} + +static int pn544_close(struct inode *inode, struct file *file) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + + dev_dbg(&client->dev, "%s: info: %p, client %p\n", + __func__, info, info->i2c_dev); + + mutex_lock(&info->mutex); + pn544_disable(info); + mutex_unlock(&info->mutex); + + return 0; +} + +static const struct file_operations pn544_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_read, + .write = pn544_write, + .poll = pn544_poll, + .open = pn544_open, + .release = pn544_close, + .unlocked_ioctl = pn544_ioctl, +}; + +#ifdef CONFIG_PM +static int pn544_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pn544_info *info; + int r = 0; + + dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client); + + info = i2c_get_clientdata(client); + dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, + info, client); + + mutex_lock(&info->mutex); + + switch (info->state) { + case PN544_ST_FW_READY: + /* Do not suspend while upgrading FW, please! */ + r = -EPERM; + break; + + case PN544_ST_READY: + /* + * CHECK: Device should be in standby-mode. No way to check? + * Allowing low power mode for the regulator is potentially + * dangerous if pn544 does not go to suspension. + */ + break; + + case PN544_ST_COLD: + break; + }; + + mutex_unlock(&info->mutex); + return r; +} + +static int pn544_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pn544_info *info = i2c_get_clientdata(client); + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, + info, client); + + mutex_lock(&info->mutex); + + switch (info->state) { + case PN544_ST_READY: + /* + * CHECK: If regulator low power mode is allowed in + * pn544_suspend, we should go back to normal mode + * here. + */ + break; + + case PN544_ST_COLD: + break; + + case PN544_ST_FW_READY: + break; + }; + + mutex_unlock(&info->mutex); + + return r; +} + +static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); +#endif + +static struct device_attribute pn544_attr = + __ATTR(nfc_test, S_IRUGO, pn544_test, NULL); + +static int __devinit pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn544_info *info; + struct pn544_nfc_platform_data *pdata; + int r = 0; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + /* private data allocation */ + info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_info.\n"); + r = -ENOMEM; + goto err_info_alloc; + } + + info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER); + info->buf = kzalloc(info->buflen, GFP_KERNEL); + if (!info->buf) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_info->buf.\n"); + r = -ENOMEM; + goto err_buf_alloc; + } + + info->regs[0].supply = reg_vdd_io; + info->regs[1].supply = reg_vbat; + r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs), + info->regs); + if (r < 0) + goto err_kmalloc; + + info->i2c_dev = client; + info->state = PN544_ST_COLD; + info->read_irq = PN544_NONE; + mutex_init(&info->read_mutex); + mutex_init(&info->mutex); + init_waitqueue_head(&info->read_wait); + i2c_set_clientdata(client, info); + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto err_reg; + } + + if (!pdata->request_resources) { + dev_err(&client->dev, "request_resources() missing\n"); + r = -EINVAL; + goto err_reg; + } + + r = pdata->request_resources(client); + if (r) { + dev_err(&client->dev, "Cannot get platform resources\n"); + goto err_reg; + } + + r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn, + IRQF_TRIGGER_RISING, PN544_DRIVER_NAME, + info); + if (r < 0) { + dev_err(&client->dev, "Unable to register IRQ handler\n"); + goto err_res; + } + + /* If we don't have the test we don't need the sysfs file */ + if (pdata->test) { + r = device_create_file(&client->dev, &pn544_attr); + if (r) { + dev_err(&client->dev, + "sysfs registration failed, error %d\n", r); + goto err_irq; + } + } + + info->miscdev.minor = MISC_DYNAMIC_MINOR; + info->miscdev.name = PN544_DRIVER_NAME; + info->miscdev.fops = &pn544_fops; + info->miscdev.parent = &client->dev; + r = misc_register(&info->miscdev); + if (r < 0) { + dev_err(&client->dev, "Device registration failed\n"); + goto err_sysfs; + } + + dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n", + __func__, info, pdata, client); + + return 0; + +err_sysfs: + if (pdata->test) + device_remove_file(&client->dev, &pn544_attr); +err_irq: + free_irq(client->irq, info); +err_res: + if (pdata->free_resources) + pdata->free_resources(); +err_reg: + regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); +err_kmalloc: + kfree(info->buf); +err_buf_alloc: + kfree(info); +err_info_alloc: + return r; +} + +static __devexit int pn544_remove(struct i2c_client *client) +{ + struct pn544_info *info = i2c_get_clientdata(client); + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + dev_dbg(&client->dev, "%s\n", __func__); + + misc_deregister(&info->miscdev); + if (pdata->test) + device_remove_file(&client->dev, &pn544_attr); + + if (info->state != PN544_ST_COLD) { + if (pdata->disable) + pdata->disable(); + + info->read_irq = PN544_NONE; + } + + free_irq(client->irq, info); + if (pdata->free_resources) + pdata->free_resources(); + + regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); + kfree(info->buf); + kfree(info); + + return 0; +} + +static struct i2c_driver pn544_driver = { + .driver = { + .name = PN544_DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &pn544_pm_ops, +#endif + }, + .probe = pn544_probe, + .id_table = pn544_id_table, + .remove = __devexit_p(pn544_remove), +}; + +static int __init pn544_init(void) +{ + int r; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + + r = i2c_add_driver(&pn544_driver); + if (r) { + pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; +} + +static void __exit pn544_exit(void) +{ + i2c_del_driver(&pn544_driver); + pr_info(DRIVER_DESC ", Exiting.\n"); +} + +module_init(pn544_init); +module_exit(pn544_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h new file mode 100644 index 000000000000..7ab8521f2347 --- /dev/null +++ b/include/linux/nfc/pn544.h @@ -0,0 +1,97 @@ +/* + * Driver include for the PN544 NFC chip. + * + * Copyright (C) Nokia Corporation + * + * Author: Jari Vanhala + * Contact: Matti Aaltoenn + * + * 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. + * + * 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 + */ + +#ifndef _PN544_H_ +#define _PN544_H_ + +#include + +#define PN544_DRIVER_NAME "pn544" +#define PN544_MAXWINDOW_SIZE 7 +#define PN544_WINDOW_SIZE 4 +#define PN544_RETRIES 10 +#define PN544_MAX_I2C_TRANSFER 0x0400 +#define PN544_MSG_MAX_SIZE 0x21 /* at normal HCI mode */ + +/* ioctl */ +#define PN544_CHAR_BASE 'P' +#define PN544_IOR(num, dtype) _IOR(PN544_CHAR_BASE, num, dtype) +#define PN544_IOW(num, dtype) _IOW(PN544_CHAR_BASE, num, dtype) +#define PN544_GET_FW_MODE PN544_IOW(1, unsigned int) +#define PN544_SET_FW_MODE PN544_IOW(2, unsigned int) +#define PN544_GET_DEBUG PN544_IOW(3, unsigned int) +#define PN544_SET_DEBUG PN544_IOW(4, unsigned int) + +/* Timing restrictions (ms) */ +#define PN544_RESETVEN_TIME 30 /* 7 */ +#define PN544_PVDDVEN_TIME 0 +#define PN544_VBATVEN_TIME 0 +#define PN544_GPIO4VEN_TIME 0 +#define PN544_WAKEUP_ACK 5 +#define PN544_WAKEUP_GUARD (PN544_WAKEUP_ACK + 1) +#define PN544_INACTIVITY_TIME 1000 +#define PN544_INTERFRAME_DELAY 200 /* us */ +#define PN544_BAUDRATE_CHANGE 150 /* us */ + +/* Debug bits */ +#define PN544_DEBUG_BUF 0x01 +#define PN544_DEBUG_READ 0x02 +#define PN544_DEBUG_WRITE 0x04 +#define PN544_DEBUG_IRQ 0x08 +#define PN544_DEBUG_CALLS 0x10 +#define PN544_DEBUG_MODE 0x20 + +/* Normal (HCI) mode */ +#define PN544_LLC_HCI_OVERHEAD 3 /* header + crc (to length) */ +#define PN544_LLC_MIN_SIZE (1 + PN544_LLC_HCI_OVERHEAD) /* length + */ +#define PN544_LLC_MAX_DATA (PN544_MSG_MAX_SIZE - 2) +#define PN544_LLC_MAX_HCI_SIZE (PN544_LLC_MAX_DATA - 2) + +struct pn544_llc_packet { + unsigned char length; /* of rest of packet */ + unsigned char header; + unsigned char data[PN544_LLC_MAX_DATA]; /* includes crc-ccitt */ +}; + +/* Firmware upgrade mode */ +#define PN544_FW_HEADER_SIZE 3 +/* max fw transfer is 1024bytes, but I2C limits it to 0xC0 */ +#define PN544_MAX_FW_DATA (PN544_MAX_I2C_TRANSFER - PN544_FW_HEADER_SIZE) + +struct pn544_fw_packet { + unsigned char command; /* status in answer */ + unsigned char length[2]; /* big-endian order (msf) */ + unsigned char data[PN544_MAX_FW_DATA]; +}; + +#ifdef __KERNEL__ +/* board config */ +struct pn544_nfc_platform_data { + int (*request_resources) (struct i2c_client *client); + void (*free_resources) (void); + void (*enable) (int fw); + int (*test) (void); + void (*disable) (void); +}; +#endif /* __KERNEL__ */ + +#endif /* _PN544_H_ */ -- cgit v1.2.3 From 7a21a3cc0be92e70474cc2ab06cb074f6a7c3f09 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:49 -0800 Subject: pps: trivial fixes Here are some very trivial fixes combined: - add macro definitions to protect header file from including several times - remove declaration for an unexistent array - fix typos Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/kapi.c | 2 +- include/linux/pps_kernel.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 1aa02db3ff4e..55f39618261b 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -324,7 +324,7 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data) captured = ~0; } - /* Wake up iif captured somthing */ + /* Wake up if captured something */ if (captured) { pps->go = ~0; wake_up_interruptible(&pps->queue); diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index e0a193f830ef..23f63c3263bb 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -18,6 +18,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef LINUX_PPS_KERNEL_H +#define LINUX_PPS_KERNEL_H + #include #include @@ -71,7 +74,6 @@ struct pps_device { extern spinlock_t pps_idr_lock; extern struct idr pps_idr; -extern struct timespec pps_irq_ts[]; extern struct device_attribute pps_attrs[]; @@ -87,3 +89,5 @@ extern void pps_unregister_source(int source); extern int pps_register_cdev(struct pps_device *pps); extern void pps_unregister_cdev(struct pps_device *pps); extern void pps_event(int source, struct pps_ktime *ts, int event, void *data); + +#endif /* LINUX_PPS_KERNEL_H */ -- cgit v1.2.3 From 86d921f9ec06bc3fd357a77877d37a604d5674c3 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:49 -0800 Subject: pps: declare variables where they are used in switch Move variable declarations where they are used in pps_cdev_ioctl. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/pps.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index ca5183bdad85..c76afb980a98 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -61,8 +61,6 @@ static long pps_cdev_ioctl(struct file *file, { struct pps_device *pps = file->private_data; struct pps_kparams params; - struct pps_fdata fdata; - unsigned long ticks; void __user *uarg = (void __user *) arg; int __user *iuarg = (int __user *) arg; int err; @@ -136,7 +134,9 @@ static long pps_cdev_ioctl(struct file *file, break; - case PPS_FETCH: + case PPS_FETCH: { + struct pps_fdata fdata; + pr_debug("PPS_FETCH: source %d\n", pps->id); err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata)); @@ -149,6 +149,8 @@ static long pps_cdev_ioctl(struct file *file, if (fdata.timeout.flags & PPS_TIME_INVALID) err = wait_event_interruptible(pps->queue, pps->go); else { + unsigned long ticks; + pr_debug("timeout %lld.%09d\n", (long long) fdata.timeout.sec, fdata.timeout.nsec); @@ -185,7 +187,7 @@ static long pps_cdev_ioctl(struct file *file, return -EFAULT; break; - + } default: return -ENOTTY; break; -- cgit v1.2.3 From 3003d55b59aa98aeaff2773df69732b27c0cbf6a Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:50 -0800 Subject: pps: fix race in PPS_FETCH handler There was a race in PPS_FETCH ioctl handler when several processes want to obtain PPS data simultaneously using sleeping PPS_FETCH. They all sleep most of the time in the system call. With the old approach when the first process waiting on the pps queue is waken up it makes new system call right away and zeroes pps->go. So other processes continue to sleep. This is a clear race condition because of the global 'go' variable. With the new approach pps->last_ev holds some value increasing at each PPS event. PPS_FETCH ioctl handler saves current value to the local variable at the very beginning so it can safely check that there is a new event by just comparing both variables. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/kapi.c | 4 ++-- drivers/pps/pps.c | 10 +++++++--- include/linux/pps_kernel.h | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 55f39618261b..3f89f5eba81c 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -326,8 +326,8 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data) /* Wake up if captured something */ if (captured) { - pps->go = ~0; - wake_up_interruptible(&pps->queue); + pps->last_ev++; + wake_up_interruptible_all(&pps->queue); kill_fasync(&pps->async_queue, SIGIO, POLL_IN); } diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index c76afb980a98..dc7e66cb2762 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -136,6 +136,7 @@ static long pps_cdev_ioctl(struct file *file, case PPS_FETCH: { struct pps_fdata fdata; + unsigned int ev; pr_debug("PPS_FETCH: source %d\n", pps->id); @@ -143,11 +144,12 @@ static long pps_cdev_ioctl(struct file *file, if (err) return -EFAULT; - pps->go = 0; + ev = pps->last_ev; /* Manage the timeout */ if (fdata.timeout.flags & PPS_TIME_INVALID) - err = wait_event_interruptible(pps->queue, pps->go); + err = wait_event_interruptible(pps->queue, + ev != pps->last_ev); else { unsigned long ticks; @@ -159,7 +161,9 @@ static long pps_cdev_ioctl(struct file *file, if (ticks != 0) { err = wait_event_interruptible_timeout( - pps->queue, pps->go, ticks); + pps->queue, + ev != pps->last_ev, + ticks); if (err == 0) return -ETIMEDOUT; } diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index 23f63c3263bb..65194fe498bb 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -55,7 +55,7 @@ struct pps_device { struct pps_ktime clear_tu; int current_mode; /* PPS mode at event time */ - int go; /* PPS event is arrived? */ + unsigned int last_ev; /* last PPS event id */ wait_queue_head_t queue; /* PPS event queue */ unsigned int id; /* PPS source unique ID */ -- cgit v1.2.3 From 6f4229b51106cbc859e9d8209b22c8a2ec749e64 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:50 -0800 Subject: pps: unify timestamp gathering Add a helper function to gather timestamps. This way clients don't have to duplicate it. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/clients/pps-ktimer.c | 9 ++------- drivers/pps/clients/pps-ldisc.c | 18 ++++++------------ drivers/pps/kapi.c | 19 ++++++++++++------- include/linux/pps_kernel.h | 20 +++++++++++++++++++- include/linux/serial_core.h | 5 +++-- include/linux/tty_ldisc.h | 5 +++-- 6 files changed, 45 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c index e7ef5b8186d0..e1bdd8bc8c9c 100644 --- a/drivers/pps/clients/pps-ktimer.c +++ b/drivers/pps/clients/pps-ktimer.c @@ -40,18 +40,13 @@ static struct timer_list ktimer; static void pps_ktimer_event(unsigned long ptr) { - struct timespec __ts; - struct pps_ktime ts; + struct pps_event_time ts; /* First of all we get the time stamp... */ - getnstimeofday(&__ts); + pps_get_ts(&ts); pr_info("PPS event at %lu\n", jiffies); - /* ... and translate it to PPS time data struct */ - ts.sec = __ts.tv_sec; - ts.nsec = __ts.tv_nsec; - pps_event(source, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 8e1932d29fd4..20fc9f7645c8 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -27,26 +27,20 @@ #define PPS_TTY_MAGIC 0x0001 static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, - struct timespec *ts) + struct pps_event_time *ts) { int id = (long)tty->disc_data; - struct timespec __ts; - struct pps_ktime pps_ts; + struct pps_event_time __ts; /* First of all we get the time stamp... */ - getnstimeofday(&__ts); + pps_get_ts(&__ts); /* Does caller give us a timestamp? */ - if (ts) { /* Yes. Let's use it! */ - pps_ts.sec = ts->tv_sec; - pps_ts.nsec = ts->tv_nsec; - } else { /* No. Do it ourself! */ - pps_ts.sec = __ts.tv_sec; - pps_ts.nsec = __ts.tv_nsec; - } + if (!ts) /* No. Do it ourself! */ + ts = &__ts; /* Now do the PPS event report */ - pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR, + pps_event(id, ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR, NULL); pr_debug("PPS %s at %lu on source #%d\n", diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 3f89f5eba81c..b431d83b824a 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -268,11 +268,12 @@ EXPORT_SYMBOL(pps_unregister_source); * pps->info.echo(source, event, data); */ -void pps_event(int source, struct pps_ktime *ts, int event, void *data) +void pps_event(int source, struct pps_event_time *ts, int event, void *data) { struct pps_device *pps; unsigned long flags; int captured = 0; + struct pps_ktime ts_real; if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { printk(KERN_ERR "pps: unknown event (%x) for source %d\n", @@ -284,8 +285,10 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data) if (!pps) return; - pr_debug("PPS event on source %d at %llu.%06u\n", - pps->id, (unsigned long long) ts->sec, ts->nsec); + pr_debug("PPS event on source %d at %ld.%09ld\n", + pps->id, ts->ts_real.tv_sec, ts->ts_real.tv_nsec); + + timespec_to_pps_ktime(&ts_real, ts->ts_real); spin_lock_irqsave(&pps->lock, flags); @@ -299,10 +302,11 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data) (pps->params.mode & PPS_CAPTUREASSERT)) { /* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETASSERT) - pps_add_offset(ts, &pps->params.assert_off_tu); + pps_add_offset(&ts_real, + &pps->params.assert_off_tu); /* Save the time stamp */ - pps->assert_tu = *ts; + pps->assert_tu = ts_real; pps->assert_sequence++; pr_debug("capture assert seq #%u for source %d\n", pps->assert_sequence, source); @@ -313,10 +317,11 @@ void pps_event(int source, struct pps_ktime *ts, int event, void *data) (pps->params.mode & PPS_CAPTURECLEAR)) { /* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETCLEAR) - pps_add_offset(ts, &pps->params.clear_off_tu); + pps_add_offset(&ts_real, + &pps->params.clear_off_tu); /* Save the time stamp */ - pps->clear_tu = *ts; + pps->clear_tu = ts_real; pps->clear_sequence++; pr_debug("capture clear seq #%u for source %d\n", pps->clear_sequence, source); diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index 65194fe498bb..32aa6763ca1b 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -43,6 +43,10 @@ struct pps_source_info { struct device *dev; }; +struct pps_event_time { + struct timespec ts_real; +}; + /* The main struct */ struct pps_device { struct pps_source_info info; /* PSS source info */ @@ -88,6 +92,20 @@ extern int pps_register_source(struct pps_source_info *info, extern void pps_unregister_source(int source); extern int pps_register_cdev(struct pps_device *pps); extern void pps_unregister_cdev(struct pps_device *pps); -extern void pps_event(int source, struct pps_ktime *ts, int event, void *data); +extern void pps_event(int source, struct pps_event_time *ts, int event, + void *data); + +static inline void timespec_to_pps_ktime(struct pps_ktime *kt, + struct timespec ts) +{ + kt->sec = ts.tv_sec; + kt->nsec = ts.tv_nsec; +} + +static inline void pps_get_ts(struct pps_event_time *ts) +{ + getnstimeofday(&ts->ts_real); +} #endif /* LINUX_PPS_KERNEL_H */ + diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index a23fa29d4eb0..758c5b0c6fd3 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -212,6 +212,7 @@ #include #include #include +#include struct uart_port; struct serial_struct; @@ -528,10 +529,10 @@ uart_handle_dcd_change(struct uart_port *uport, unsigned int status) struct uart_state *state = uport->state; struct tty_port *port = &state->port; struct tty_ldisc *ld = tty_ldisc_ref(port->tty); - struct timespec ts; + struct pps_event_time ts; if (ld && ld->ops->dcd_change) - getnstimeofday(&ts); + pps_get_ts(&ts); uport->icount.dcd++; #ifdef CONFIG_HARD_PPS diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 526d66f066a3..763e061e19f1 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -101,7 +101,7 @@ * any pending driver I/O is completed. * * void (*dcd_change)(struct tty_struct *tty, unsigned int status, - * struct timespec *ts) + * struct pps_event_time *ts) * * Tells the discipline that the DCD pin has changed its status and * the relative timestamp. Pointer ts can be NULL. @@ -109,6 +109,7 @@ #include #include +#include struct tty_ldisc_ops { int magic; @@ -143,7 +144,7 @@ struct tty_ldisc_ops { char *fp, int count); void (*write_wakeup)(struct tty_struct *); void (*dcd_change)(struct tty_struct *, unsigned int, - struct timespec *); + struct pps_event_time *); struct module *owner; -- cgit v1.2.3 From 5e196d34a776420278e4117b4742cd9d3f2350ed Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:51 -0800 Subject: pps: access pps device by direct pointer Using device index as a pointer needs some unnecessary work to be done every time the pointer is needed (in irq handler for example). Using a direct pointer is much more easy (and safe as well). Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/clients/pps-ktimer.c | 30 ++++------ drivers/pps/clients/pps-ldisc.c | 41 ++++++++----- drivers/pps/kapi.c | 124 +++++++++------------------------------ drivers/pps/pps.c | 22 ++----- include/linux/pps_kernel.h | 23 +++----- 5 files changed, 82 insertions(+), 158 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c index e1bdd8bc8c9c..966ead188ee2 100644 --- a/drivers/pps/clients/pps-ktimer.c +++ b/drivers/pps/clients/pps-ktimer.c @@ -31,7 +31,7 @@ * Global variables */ -static int source; +static struct pps_device *pps; static struct timer_list ktimer; /* @@ -47,7 +47,7 @@ static void pps_ktimer_event(unsigned long ptr) pr_info("PPS event at %lu\n", jiffies); - pps_event(source, &ts, PPS_CAPTUREASSERT, NULL); + pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); } @@ -56,12 +56,11 @@ static void pps_ktimer_event(unsigned long ptr) * The echo function */ -static void pps_ktimer_echo(int source, int event, void *data) +static void pps_ktimer_echo(struct pps_device *pps, int event, void *data) { - pr_info("echo %s %s for source %d\n", + dev_info(pps->dev, "echo %s %s\n", event & PPS_CAPTUREASSERT ? "assert" : "", - event & PPS_CAPTURECLEAR ? "clear" : "", - source); + event & PPS_CAPTURECLEAR ? "clear" : ""); } /* @@ -84,30 +83,27 @@ static struct pps_source_info pps_ktimer_info = { static void __exit pps_ktimer_exit(void) { - del_timer_sync(&ktimer); - pps_unregister_source(source); + dev_info(pps->dev, "ktimer PPS source unregistered\n"); - pr_info("ktimer PPS source unregistered\n"); + del_timer_sync(&ktimer); + pps_unregister_source(pps); } static int __init pps_ktimer_init(void) { - int ret; - - ret = pps_register_source(&pps_ktimer_info, + pps = pps_register_source(&pps_ktimer_info, PPS_CAPTUREASSERT | PPS_OFFSETASSERT); - if (ret < 0) { + if (pps == NULL) { printk(KERN_ERR "cannot register ktimer source\n"); - return ret; + return -ENOMEM; } - source = ret; setup_timer(&ktimer, pps_ktimer_event, 0); mod_timer(&ktimer, jiffies + HZ); - pr_info("ktimer PPS source registered at %d\n", source); + dev_info(pps->dev, "ktimer PPS source registered\n"); - return 0; + return 0; } module_init(pps_ktimer_init); diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 20fc9f7645c8..1517f5498ec0 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -29,7 +29,7 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, struct pps_event_time *ts) { - int id = (long)tty->disc_data; + struct pps_device *pps = (struct pps_device *)tty->disc_data; struct pps_event_time __ts; /* First of all we get the time stamp... */ @@ -39,12 +39,14 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, if (!ts) /* No. Do it ourself! */ ts = &__ts; + BUG_ON(pps == NULL); + /* Now do the PPS event report */ - pps_event(id, ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR, - NULL); + pps_event(pps, ts, status ? PPS_CAPTUREASSERT : + PPS_CAPTURECLEAR, NULL); - pr_debug("PPS %s at %lu on source #%d\n", - status ? "assert" : "clear", jiffies, id); + dev_dbg(pps->dev, "PPS %s at %lu\n", + status ? "assert" : "clear", jiffies); } static int (*alias_n_tty_open)(struct tty_struct *tty); @@ -54,6 +56,7 @@ static int pps_tty_open(struct tty_struct *tty) struct pps_source_info info; struct tty_driver *drv = tty->driver; int index = tty->index + drv->name_base; + struct pps_device *pps; int ret; info.owner = THIS_MODULE; @@ -64,34 +67,42 @@ static int pps_tty_open(struct tty_struct *tty) PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ PPS_CANWAIT | PPS_TSFMT_TSPEC; - ret = pps_register_source(&info, PPS_CAPTUREBOTH | \ + pps = pps_register_source(&info, PPS_CAPTUREBOTH | \ PPS_OFFSETASSERT | PPS_OFFSETCLEAR); - if (ret < 0) { + if (pps == NULL) { pr_err("cannot register PPS source \"%s\"\n", info.path); - return ret; + return -ENOMEM; } - tty->disc_data = (void *)(long)ret; + tty->disc_data = pps; /* Should open N_TTY ldisc too */ ret = alias_n_tty_open(tty); - if (ret < 0) - pps_unregister_source((long)tty->disc_data); + if (ret < 0) { + pr_err("cannot open tty ldisc \"%s\"\n", info.path); + goto err_unregister; + } - pr_info("PPS source #%d \"%s\" added\n", ret, info.path); + dev_info(pps->dev, "source \"%s\" added\n", info.path); return 0; + +err_unregister: + tty->disc_data = NULL; + pps_unregister_source(pps); + return ret; } static void (*alias_n_tty_close)(struct tty_struct *tty); static void pps_tty_close(struct tty_struct *tty) { - int id = (long)tty->disc_data; + struct pps_device *pps = (struct pps_device *)tty->disc_data; - pps_unregister_source(id); alias_n_tty_close(tty); - pr_info("PPS source #%d removed\n", id); + tty->disc_data = NULL; + dev_info(pps->dev, "removed\n"); + pps_unregister_source(pps); } static struct tty_ldisc_ops pps_ldisc_ops; diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index b431d83b824a..98d4012ca595 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -32,11 +32,11 @@ #include /* - * Global variables + * Local variables */ -DEFINE_SPINLOCK(pps_idr_lock); -DEFINE_IDR(pps_idr); +static DEFINE_SPINLOCK(pps_idr_lock); +static DEFINE_IDR(pps_idr); /* * Local functions @@ -60,60 +60,6 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset) * Exported functions */ -/* pps_get_source - find a PPS source - * @source: the PPS source ID. - * - * This function is used to find an already registered PPS source into the - * system. - * - * The function returns NULL if found nothing, otherwise it returns a pointer - * to the PPS source data struct (the refcounter is incremented by 1). - */ - -struct pps_device *pps_get_source(int source) -{ - struct pps_device *pps; - unsigned long flags; - - spin_lock_irqsave(&pps_idr_lock, flags); - - pps = idr_find(&pps_idr, source); - if (pps != NULL) - atomic_inc(&pps->usage); - - spin_unlock_irqrestore(&pps_idr_lock, flags); - - return pps; -} - -/* pps_put_source - free the PPS source data - * @pps: a pointer to the PPS source. - * - * This function is used to free a PPS data struct if its refcount is 0. - */ - -void pps_put_source(struct pps_device *pps) -{ - unsigned long flags; - - spin_lock_irqsave(&pps_idr_lock, flags); - BUG_ON(atomic_read(&pps->usage) == 0); - - if (!atomic_dec_and_test(&pps->usage)) { - pps = NULL; - goto exit; - } - - /* No more reference to the PPS source. We can safely remove the - * PPS data struct. - */ - idr_remove(&pps_idr, pps->id); - -exit: - spin_unlock_irqrestore(&pps_idr_lock, flags); - kfree(pps); -} - /* pps_register_source - add a PPS source in the system * @info: the PPS info struct * @default_params: the default PPS parameters of the new source @@ -122,10 +68,11 @@ exit: * source is described by info's fields and it will have, as default PPS * parameters, the ones specified into default_params. * - * The function returns, in case of success, the PPS source ID. + * The function returns, in case of success, the PPS device. Otherwise NULL. */ -int pps_register_source(struct pps_source_info *info, int default_params) +struct pps_device *pps_register_source(struct pps_source_info *info, + int default_params) { struct pps_device *pps; int id; @@ -168,7 +115,6 @@ int pps_register_source(struct pps_source_info *info, int default_params) init_waitqueue_head(&pps->queue); spin_lock_init(&pps->lock); - atomic_set(&pps->usage, 1); /* Get new ID for the new PPS source */ if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { @@ -211,7 +157,7 @@ int pps_register_source(struct pps_source_info *info, int default_params) pr_info("new PPS source %s at ID %d\n", info->name, id); - return id; + return pps; free_idr: spin_lock_irq(&pps_idr_lock); @@ -224,38 +170,33 @@ kfree_pps: pps_register_source_exit: printk(KERN_ERR "pps: %s: unable to register source\n", info->name); - return err; + return NULL; } EXPORT_SYMBOL(pps_register_source); /* pps_unregister_source - remove a PPS source from the system - * @source: the PPS source ID + * @pps: the PPS source * * This function is used to remove a previously registered PPS source from * the system. */ -void pps_unregister_source(int source) +void pps_unregister_source(struct pps_device *pps) { - struct pps_device *pps; + unsigned int id = pps->id; - spin_lock_irq(&pps_idr_lock); - pps = idr_find(&pps_idr, source); + pps_unregister_cdev(pps); - if (!pps) { - BUG(); - spin_unlock_irq(&pps_idr_lock); - return; - } + spin_lock_irq(&pps_idr_lock); + idr_remove(&pps_idr, pps->id); spin_unlock_irq(&pps_idr_lock); - pps_unregister_cdev(pps); - pps_put_source(pps); + kfree(pps); } EXPORT_SYMBOL(pps_unregister_source); /* pps_event - register a PPS event into the system - * @source: the PPS source ID + * @pps: the PPS device * @ts: the event timestamp * @event: the event type * @data: userdef pointer @@ -263,30 +204,24 @@ EXPORT_SYMBOL(pps_unregister_source); * This function is used by each PPS client in order to register a new * PPS event into the system (it's usually called inside an IRQ handler). * - * If an echo function is associated with the PPS source it will be called + * If an echo function is associated with the PPS device it will be called * as: - * pps->info.echo(source, event, data); + * pps->info.echo(pps, event, data); */ - -void pps_event(int source, struct pps_event_time *ts, int event, void *data) +void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, + void *data) { - struct pps_device *pps; unsigned long flags; int captured = 0; struct pps_ktime ts_real; if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { - printk(KERN_ERR "pps: unknown event (%x) for source %d\n", - event, source); + dev_err(pps->dev, "unknown event (%x)\n", event); return; } - pps = pps_get_source(source); - if (!pps) - return; - - pr_debug("PPS event on source %d at %ld.%09ld\n", - pps->id, ts->ts_real.tv_sec, ts->ts_real.tv_nsec); + dev_dbg(pps->dev, "PPS event at %ld.%09ld\n", + ts->ts_real.tv_sec, ts->ts_real.tv_nsec); timespec_to_pps_ktime(&ts_real, ts->ts_real); @@ -294,7 +229,7 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) /* Must call the echo function? */ if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) - pps->info.echo(source, event, data); + pps->info.echo(pps, event, data); /* Check the event */ pps->current_mode = pps->params.mode; @@ -308,8 +243,8 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) /* Save the time stamp */ pps->assert_tu = ts_real; pps->assert_sequence++; - pr_debug("capture assert seq #%u for source %d\n", - pps->assert_sequence, source); + dev_dbg(pps->dev, "capture assert seq #%u\n", + pps->assert_sequence); captured = ~0; } @@ -323,8 +258,8 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) /* Save the time stamp */ pps->clear_tu = ts_real; pps->clear_sequence++; - pr_debug("capture clear seq #%u for source %d\n", - pps->clear_sequence, source); + dev_dbg(pps->dev, "capture clear seq #%u\n", + pps->clear_sequence); captured = ~0; } @@ -338,8 +273,5 @@ void pps_event(int source, struct pps_event_time *ts, int event, void *data) } spin_unlock_irqrestore(&pps->lock, flags); - - /* Now we can release the PPS source for (possible) deregistration */ - pps_put_source(pps); } EXPORT_SYMBOL(pps_event); diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index dc7e66cb2762..1922f27a52ac 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -204,12 +204,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file) { struct pps_device *pps = container_of(inode->i_cdev, struct pps_device, cdev); - int found; - - found = pps_get_source(pps->id) != 0; - if (!found) - return -ENODEV; - file->private_data = pps; return 0; @@ -217,11 +211,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file) static int pps_cdev_release(struct inode *inode, struct file *file) { - struct pps_device *pps = file->private_data; - - /* Free the PPS source and wake up (possible) deregistration */ - pps_put_source(pps); - return 0; } @@ -242,22 +231,23 @@ static const struct file_operations pps_cdev_fops = { int pps_register_cdev(struct pps_device *pps) { int err; + dev_t devt; + + devt = MKDEV(MAJOR(pps_devt), pps->id); - pps->devno = MKDEV(MAJOR(pps_devt), pps->id); cdev_init(&pps->cdev, &pps_cdev_fops); pps->cdev.owner = pps->info.owner; - err = cdev_add(&pps->cdev, pps->devno, 1); + err = cdev_add(&pps->cdev, devt, 1); if (err) { printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n", pps->info.name, MAJOR(pps_devt), pps->id); return err; } - pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL, + pps->dev = device_create(pps_class, pps->info.dev, devt, pps, "pps%d", pps->id); if (IS_ERR(pps->dev)) goto del_cdev; - dev_set_drvdata(pps->dev, pps); pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, MAJOR(pps_devt), pps->id); @@ -272,7 +262,7 @@ del_cdev: void pps_unregister_cdev(struct pps_device *pps) { - device_destroy(pps_class, pps->devno); + device_destroy(pps_class, pps->dev->devt); cdev_del(&pps->cdev); } diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index 32aa6763ca1b..1aedf50088cf 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -31,13 +31,16 @@ * Global defines */ +struct pps_device; + /* The specific PPS source info */ struct pps_source_info { char name[PPS_MAX_NAME_LEN]; /* simbolic name */ char path[PPS_MAX_NAME_LEN]; /* path of connected device */ int mode; /* PPS's allowed mode */ - void (*echo)(int source, int event, void *data); /* PPS echo function */ + void (*echo)(struct pps_device *pps, + int event, void *data); /* PPS echo function */ struct module *owner; struct device *dev; @@ -65,35 +68,27 @@ struct pps_device { unsigned int id; /* PPS source unique ID */ struct cdev cdev; struct device *dev; - int devno; struct fasync_struct *async_queue; /* fasync method */ spinlock_t lock; - - atomic_t usage; /* usage count */ }; /* * Global variables */ -extern spinlock_t pps_idr_lock; -extern struct idr pps_idr; - extern struct device_attribute pps_attrs[]; /* * Exported functions */ -struct pps_device *pps_get_source(int source); -extern void pps_put_source(struct pps_device *pps); -extern int pps_register_source(struct pps_source_info *info, - int default_params); -extern void pps_unregister_source(int source); +extern struct pps_device *pps_register_source( + struct pps_source_info *info, int default_params); +extern void pps_unregister_source(struct pps_device *pps); extern int pps_register_cdev(struct pps_device *pps); extern void pps_unregister_cdev(struct pps_device *pps); -extern void pps_event(int source, struct pps_event_time *ts, int event, - void *data); +extern void pps_event(struct pps_device *pps, + struct pps_event_time *ts, int event, void *data); static inline void timespec_to_pps_ktime(struct pps_ktime *kt, struct timespec ts) -- cgit v1.2.3 From 7f7cce74105adf714bdc9357da3b6f06e019958c Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:52 -0800 Subject: pps: convert printk/pr_* to dev_* Since we now have direct pointers to struct pps_device everywhere it's easy to use dev_* functions to print messages instead of plain printks. Where dev_* cannot be used printks are converted to pr_*. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/clients/pps-ktimer.c | 5 +++-- drivers/pps/clients/pps-ldisc.c | 2 ++ drivers/pps/kapi.c | 15 ++++++++------- drivers/pps/pps.c | 25 +++++++++++++------------ 4 files changed, 26 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c index 966ead188ee2..2728469d3884 100644 --- a/drivers/pps/clients/pps-ktimer.c +++ b/drivers/pps/clients/pps-ktimer.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -45,7 +46,7 @@ static void pps_ktimer_event(unsigned long ptr) /* First of all we get the time stamp... */ pps_get_ts(&ts); - pr_info("PPS event at %lu\n", jiffies); + dev_info(pps->dev, "PPS event at %lu\n", jiffies); pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL); @@ -94,7 +95,7 @@ static int __init pps_ktimer_init(void) pps = pps_register_source(&pps_ktimer_info, PPS_CAPTUREASSERT | PPS_OFFSETASSERT); if (pps == NULL) { - printk(KERN_ERR "cannot register ktimer source\n"); + pr_err("cannot register PPS source\n"); return -ENOMEM; } diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 1517f5498ec0..1b3c6eda12ba 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 98d4012ca595..e8847c118ea3 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -80,20 +81,20 @@ struct pps_device *pps_register_source(struct pps_source_info *info, /* Sanity checks */ if ((info->mode & default_params) != default_params) { - printk(KERN_ERR "pps: %s: unsupported default parameters\n", + pr_err("%s: unsupported default parameters\n", info->name); err = -EINVAL; goto pps_register_source_exit; } if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 && info->echo == NULL) { - printk(KERN_ERR "pps: %s: echo function is not defined\n", + pr_err("%s: echo function is not defined\n", info->name); err = -EINVAL; goto pps_register_source_exit; } if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { - printk(KERN_ERR "pps: %s: unspecified time format\n", + pr_err("%s: unspecified time format\n", info->name); err = -EINVAL; goto pps_register_source_exit; @@ -138,7 +139,7 @@ struct pps_device *pps_register_source(struct pps_source_info *info, if (id >= PPS_MAX_SOURCES) { spin_unlock_irq(&pps_idr_lock); - printk(KERN_ERR "pps: %s: too many PPS sources in the system\n", + pr_err("%s: too many PPS sources in the system\n", info->name); err = -EBUSY; goto free_idr; @@ -150,12 +151,12 @@ struct pps_device *pps_register_source(struct pps_source_info *info, /* Create the char device */ err = pps_register_cdev(pps); if (err < 0) { - printk(KERN_ERR "pps: %s: unable to create char device\n", + pr_err("%s: unable to create char device\n", info->name); goto free_idr; } - pr_info("new PPS source %s at ID %d\n", info->name, id); + dev_info(pps->dev, "new PPS source %s\n", info->name); return pps; @@ -168,7 +169,7 @@ kfree_pps: kfree(pps); pps_register_source_exit: - printk(KERN_ERR "pps: %s: unable to register source\n", info->name); + pr_err("%s: unable to register source\n", info->name); return NULL; } diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 1922f27a52ac..9f7c2e858dd0 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -67,7 +68,7 @@ static long pps_cdev_ioctl(struct file *file, switch (cmd) { case PPS_GETPARAMS: - pr_debug("PPS_GETPARAMS: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_GETPARAMS\n"); spin_lock_irq(&pps->lock); @@ -83,7 +84,7 @@ static long pps_cdev_ioctl(struct file *file, break; case PPS_SETPARAMS: - pr_debug("PPS_SETPARAMS: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_SETPARAMS\n"); /* Check the capabilities */ if (!capable(CAP_SYS_TIME)) @@ -93,14 +94,14 @@ static long pps_cdev_ioctl(struct file *file, if (err) return -EFAULT; if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { - pr_debug("capture mode unspecified (%x)\n", + dev_dbg(pps->dev, "capture mode unspecified (%x)\n", params.mode); return -EINVAL; } /* Check for supported capabilities */ if ((params.mode & ~pps->info.mode) != 0) { - pr_debug("unsupported capabilities (%x)\n", + dev_dbg(pps->dev, "unsupported capabilities (%x)\n", params.mode); return -EINVAL; } @@ -113,7 +114,7 @@ static long pps_cdev_ioctl(struct file *file, /* Restore the read only parameters */ if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { /* section 3.3 of RFC 2783 interpreted */ - pr_debug("time format unspecified (%x)\n", + dev_dbg(pps->dev, "time format unspecified (%x)\n", params.mode); pps->params.mode |= PPS_TSFMT_TSPEC; } @@ -126,7 +127,7 @@ static long pps_cdev_ioctl(struct file *file, break; case PPS_GETCAP: - pr_debug("PPS_GETCAP: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_GETCAP\n"); err = put_user(pps->info.mode, iuarg); if (err) @@ -138,7 +139,7 @@ static long pps_cdev_ioctl(struct file *file, struct pps_fdata fdata; unsigned int ev; - pr_debug("PPS_FETCH: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_FETCH\n"); err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata)); if (err) @@ -153,7 +154,7 @@ static long pps_cdev_ioctl(struct file *file, else { unsigned long ticks; - pr_debug("timeout %lld.%09d\n", + dev_dbg(pps->dev, "timeout %lld.%09d\n", (long long) fdata.timeout.sec, fdata.timeout.nsec); ticks = fdata.timeout.sec * HZ; @@ -171,7 +172,7 @@ static long pps_cdev_ioctl(struct file *file, /* Check for pending signals */ if (err == -ERESTARTSYS) { - pr_debug("pending signal caught\n"); + dev_dbg(pps->dev, "pending signal caught\n"); return -EINTR; } @@ -240,7 +241,7 @@ int pps_register_cdev(struct pps_device *pps) err = cdev_add(&pps->cdev, devt, 1); if (err) { - printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n", + pr_err("%s: failed to add char device %d:%d\n", pps->info.name, MAJOR(pps_devt), pps->id); return err; } @@ -282,14 +283,14 @@ static int __init pps_init(void) pps_class = class_create(THIS_MODULE, "pps"); if (!pps_class) { - printk(KERN_ERR "pps: failed to allocate class\n"); + pr_err("failed to allocate class\n"); return -ENOMEM; } pps_class->dev_attrs = pps_attrs; err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps"); if (err < 0) { - printk(KERN_ERR "pps: failed to allocate char device region\n"); + pr_err("failed to allocate char device region\n"); goto remove_class; } -- cgit v1.2.3 From 083e58666ff5b3c5750d9a5c0560018b03cfb4b2 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:53 -0800 Subject: pps: move idr stuff to pps.c Since now idr is only used to manage char device id's and not used in kernel API anymore it should be moved to pps.c. This also makes it possible to release id only at actual device freeing so nobody can register a pps device with the same id while our device is not freed yet. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/kapi.c | 56 +++--------------------------------------------------- drivers/pps/pps.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index e8847c118ea3..c42d3cb8baa1 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -27,18 +27,10 @@ #include #include #include -#include #include #include #include -/* - * Local variables - */ - -static DEFINE_SPINLOCK(pps_idr_lock); -static DEFINE_IDR(pps_idr); - /* * Local functions */ @@ -76,7 +68,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info, int default_params) { struct pps_device *pps; - int id; int err; /* Sanity checks */ @@ -117,54 +108,18 @@ struct pps_device *pps_register_source(struct pps_source_info *info, init_waitqueue_head(&pps->queue); spin_lock_init(&pps->lock); - /* Get new ID for the new PPS source */ - if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { - err = -ENOMEM; - goto kfree_pps; - } - - spin_lock_irq(&pps_idr_lock); - - /* Now really allocate the PPS source. - * After idr_get_new() calling the new source will be freely available - * into the kernel. - */ - err = idr_get_new(&pps_idr, pps, &id); - if (err < 0) { - spin_unlock_irq(&pps_idr_lock); - goto kfree_pps; - } - - id = id & MAX_ID_MASK; - if (id >= PPS_MAX_SOURCES) { - spin_unlock_irq(&pps_idr_lock); - - pr_err("%s: too many PPS sources in the system\n", - info->name); - err = -EBUSY; - goto free_idr; - } - pps->id = id; - - spin_unlock_irq(&pps_idr_lock); - /* Create the char device */ err = pps_register_cdev(pps); if (err < 0) { pr_err("%s: unable to create char device\n", info->name); - goto free_idr; + goto kfree_pps; } dev_info(pps->dev, "new PPS source %s\n", info->name); return pps; -free_idr: - spin_lock_irq(&pps_idr_lock); - idr_remove(&pps_idr, id); - spin_unlock_irq(&pps_idr_lock); - kfree_pps: kfree(pps); @@ -184,15 +139,10 @@ EXPORT_SYMBOL(pps_register_source); void pps_unregister_source(struct pps_device *pps) { - unsigned int id = pps->id; - pps_unregister_cdev(pps); - spin_lock_irq(&pps_idr_lock); - idr_remove(&pps_idr, pps->id); - spin_unlock_irq(&pps_idr_lock); - - kfree(pps); + /* don't have to kfree(pps) here because it will be done on + * device destruction */ } EXPORT_SYMBOL(pps_unregister_source); diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 9f7c2e858dd0..79b445578132 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * Local variables @@ -38,6 +39,9 @@ static dev_t pps_devt; static struct class *pps_class; +static DEFINE_SPINLOCK(pps_idr_lock); +static DEFINE_IDR(pps_idr); + /* * Char device methods */ @@ -229,11 +233,48 @@ static const struct file_operations pps_cdev_fops = { .release = pps_cdev_release, }; +static void pps_device_destruct(struct device *dev) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + /* release id here to protect others from using it while it's + * still in use */ + spin_lock_irq(&pps_idr_lock); + idr_remove(&pps_idr, pps->id); + spin_unlock_irq(&pps_idr_lock); + + kfree(dev); + kfree(pps); +} + int pps_register_cdev(struct pps_device *pps) { int err; dev_t devt; + /* Get new ID for the new PPS source */ + if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) + return -ENOMEM; + + /* Now really allocate the PPS source. + * After idr_get_new() calling the new source will be freely available + * into the kernel. + */ + spin_lock_irq(&pps_idr_lock); + err = idr_get_new(&pps_idr, pps, &pps->id); + spin_unlock_irq(&pps_idr_lock); + + if (err < 0) + return err; + + pps->id &= MAX_ID_MASK; + if (pps->id >= PPS_MAX_SOURCES) { + pr_err("%s: too many PPS sources in the system\n", + pps->info.name); + err = -EBUSY; + goto free_idr; + } + devt = MKDEV(MAJOR(pps_devt), pps->id); cdev_init(&pps->cdev, &pps_cdev_fops); @@ -243,13 +284,15 @@ int pps_register_cdev(struct pps_device *pps) if (err) { pr_err("%s: failed to add char device %d:%d\n", pps->info.name, MAJOR(pps_devt), pps->id); - return err; + goto free_idr; } pps->dev = device_create(pps_class, pps->info.dev, devt, pps, "pps%d", pps->id); if (IS_ERR(pps->dev)) goto del_cdev; + pps->dev->release = pps_device_destruct; + pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, MAJOR(pps_devt), pps->id); @@ -258,6 +301,11 @@ int pps_register_cdev(struct pps_device *pps) del_cdev: cdev_del(&pps->cdev); +free_idr: + spin_lock_irq(&pps_idr_lock); + idr_remove(&pps_idr, pps->id); + spin_unlock_irq(&pps_idr_lock); + return err; } -- cgit v1.2.3 From 2a5cd6e2fb1984cc83f08b3645bf394830ac7825 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:53 -0800 Subject: pps: make idr lock a mutex and protect idr_pre_get Now pps_idr_lock is never used in interrupt context so we can replace spin_lock_irq/spin_unlock_irq with plain spin_lock/spin_unlock. But there is also a potential race condition when someone can steal an id which was allocated by idr_pre_get before it is used. So convert spin lock to mutex and protect the whole id generation process. Signed-off-by: Alexander Gordeev Cc: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/pps.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 79b445578132..9e15cf1da946 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,7 @@ static dev_t pps_devt; static struct class *pps_class; -static DEFINE_SPINLOCK(pps_idr_lock); +static DEFINE_MUTEX(pps_idr_lock); static DEFINE_IDR(pps_idr); /* @@ -239,9 +240,9 @@ static void pps_device_destruct(struct device *dev) /* release id here to protect others from using it while it's * still in use */ - spin_lock_irq(&pps_idr_lock); + mutex_lock(&pps_idr_lock); idr_remove(&pps_idr, pps->id); - spin_unlock_irq(&pps_idr_lock); + mutex_unlock(&pps_idr_lock); kfree(dev); kfree(pps); @@ -252,17 +253,19 @@ int pps_register_cdev(struct pps_device *pps) int err; dev_t devt; + mutex_lock(&pps_idr_lock); /* Get new ID for the new PPS source */ - if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) + if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { + mutex_unlock(&pps_idr_lock); return -ENOMEM; + } /* Now really allocate the PPS source. * After idr_get_new() calling the new source will be freely available * into the kernel. */ - spin_lock_irq(&pps_idr_lock); err = idr_get_new(&pps_idr, pps, &pps->id); - spin_unlock_irq(&pps_idr_lock); + mutex_unlock(&pps_idr_lock); if (err < 0) return err; @@ -302,9 +305,9 @@ del_cdev: cdev_del(&pps->cdev); free_idr: - spin_lock_irq(&pps_idr_lock); + mutex_lock(&pps_idr_lock); idr_remove(&pps_idr, pps->id); - spin_unlock_irq(&pps_idr_lock); + mutex_unlock(&pps_idr_lock); return err; } -- cgit v1.2.3 From 29f347c9faf53cfb953e4d529e6e632482214e62 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:54 -0800 Subject: pps: use BUG_ON for kernel API safety checks This way less overhead is involved when running production kernel. If you want to debug a pps client module please define DEBUG to enable the checks. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/kapi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index c42d3cb8baa1..3e8eb3fb7570 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -166,10 +166,8 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, int captured = 0; struct pps_ktime ts_real; - if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { - dev_err(pps->dev, "unknown event (%x)\n", event); - return; - } + /* check event type */ + BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0); dev_dbg(pps->dev, "PPS event at %ld.%09ld\n", ts->ts_real.tv_sec, ts->ts_real.tv_nsec); -- cgit v1.2.3 From 818b9eefe742cc29c6456e163e2c035cfb431e51 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:54 -0800 Subject: pps: simplify conditions a bit Bitwise conjunction is distributive so we can simplify some conditions. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/kapi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 3e8eb3fb7570..ebf33746c37c 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -182,8 +182,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, /* Check the event */ pps->current_mode = pps->params.mode; - if ((event & PPS_CAPTUREASSERT) & - (pps->params.mode & PPS_CAPTUREASSERT)) { + if (event & pps->params.mode & PPS_CAPTUREASSERT) { /* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETASSERT) pps_add_offset(&ts_real, @@ -197,8 +196,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, captured = ~0; } - if ((event & PPS_CAPTURECLEAR) & - (pps->params.mode & PPS_CAPTURECLEAR)) { + if (event & pps->params.mode & PPS_CAPTURECLEAR) { /* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETCLEAR) pps_add_offset(&ts_real, -- cgit v1.2.3 From 12f9b1f9c11700893a7b453705d95b260d78f268 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:55 -0800 Subject: pps: timestamp is always passed to dcd_change() Remove the code that gatheres timestamp in pps_tty_dcd_change() in case passed ts parameter is NULL because it never happens in the current code. Fix comments as well. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/serial/tty.txt | 2 +- drivers/pps/clients/pps-ldisc.c | 8 -------- include/linux/tty_ldisc.h | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt index 7c900507279f..540db41dfd5d 100644 --- a/Documentation/serial/tty.txt +++ b/Documentation/serial/tty.txt @@ -107,7 +107,7 @@ write_wakeup() - May be called at any point between open and close. dcd_change() - Report to the tty line the current DCD pin status changes and the relative timestamp. The timestamp - can be NULL. + cannot be NULL. Driver Access diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 1b3c6eda12ba..79451f2dea6a 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -32,14 +32,6 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, struct pps_event_time *ts) { struct pps_device *pps = (struct pps_device *)tty->disc_data; - struct pps_event_time __ts; - - /* First of all we get the time stamp... */ - pps_get_ts(&__ts); - - /* Does caller give us a timestamp? */ - if (!ts) /* No. Do it ourself! */ - ts = &__ts; BUG_ON(pps == NULL); diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 763e061e19f1..ff7dc08696a8 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -104,7 +104,7 @@ * struct pps_event_time *ts) * * Tells the discipline that the DCD pin has changed its status and - * the relative timestamp. Pointer ts can be NULL. + * the relative timestamp. Pointer ts cannot be NULL. */ #include -- cgit v1.2.3 From 025b40abe715d638e60516a657d354e8560c1a85 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:56 -0800 Subject: ntp: add hardpps implementation This commit adds hardpps() implementation based upon the original one from the NTPv4 reference kernel code from David Mills. However, it is highly optimized towards very fast syncronization and maximum stickness to PPS signal. The typical error is less then a microsecond. To make it sync faster I had to throw away exponential phase filter so that the full phase offset is corrected immediately. Then I also had to throw away median phase filter because it gives a bigger error itself if used without exponential filter. Maybe we will find an appropriate filtering scheme in the future but it's not necessary if the signal quality is ok. Signed-off-by: Alexander Gordeev Acked-by: John Stultz Cc: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/Kconfig | 9 ++ include/linux/timex.h | 1 + kernel/time/ntp.c | 425 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 420 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig index 1afe4e03440f..0ad5ff38bfec 100644 --- a/drivers/pps/Kconfig +++ b/drivers/pps/Kconfig @@ -30,6 +30,15 @@ config PPS_DEBUG messages to the system log. Select this if you are having a problem with PPS support and want to see more of what is going on. +config NTP_PPS + bool "PPS kernel consumer support" + depends on PPS && !NO_HZ + help + This option adds support for direct in-kernel time + syncronization using an external PPS signal. + + It doesn't work on tickless systems at the moment. + source drivers/pps/clients/Kconfig endmenu diff --git a/include/linux/timex.h b/include/linux/timex.h index 32d852f8cbe4..d23999f9499d 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -268,6 +268,7 @@ extern u64 tick_length; extern void second_overflow(void); extern void update_ntp_one_tick(void); extern int do_adjtimex(struct timex *); +extern void hardpps(const struct timespec *, const struct timespec *); int read_current_timer(unsigned long *timer_val); diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index d2321891538f..5c00242fa921 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -14,6 +14,7 @@ #include #include #include +#include /* * NTP timekeeping variables: @@ -74,6 +75,162 @@ static long time_adjust; /* constant (boot-param configurable) NTP tick adjustment (upscaled) */ static s64 ntp_tick_adj; +#ifdef CONFIG_NTP_PPS + +/* + * The following variables are used when a pulse-per-second (PPS) signal + * is available. They establish the engineering parameters of the clock + * discipline loop when controlled by the PPS signal. + */ +#define PPS_VALID 10 /* PPS signal watchdog max (s) */ +#define PPS_POPCORN 4 /* popcorn spike threshold (shift) */ +#define PPS_INTMIN 2 /* min freq interval (s) (shift) */ +#define PPS_INTMAX 8 /* max freq interval (s) (shift) */ +#define PPS_INTCOUNT 4 /* number of consecutive good intervals to + increase pps_shift or consecutive bad + intervals to decrease it */ +#define PPS_MAXWANDER 100000 /* max PPS freq wander (ns/s) */ + +static int pps_valid; /* signal watchdog counter */ +static long pps_tf[3]; /* phase median filter */ +static long pps_jitter; /* current jitter (ns) */ +static struct timespec pps_fbase; /* beginning of the last freq interval */ +static int pps_shift; /* current interval duration (s) (shift) */ +static int pps_intcnt; /* interval counter */ +static s64 pps_freq; /* frequency offset (scaled ns/s) */ +static long pps_stabil; /* current stability (scaled ns/s) */ + +/* + * PPS signal quality monitors + */ +static long pps_calcnt; /* calibration intervals */ +static long pps_jitcnt; /* jitter limit exceeded */ +static long pps_stbcnt; /* stability limit exceeded */ +static long pps_errcnt; /* calibration errors */ + + +/* PPS kernel consumer compensates the whole phase error immediately. + * Otherwise, reduce the offset by a fixed factor times the time constant. + */ +static inline s64 ntp_offset_chunk(s64 offset) +{ + if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) + return offset; + else + return shift_right(offset, SHIFT_PLL + time_constant); +} + +static inline void pps_reset_freq_interval(void) +{ + /* the PPS calibration interval may end + surprisingly early */ + pps_shift = PPS_INTMIN; + pps_intcnt = 0; +} + +/** + * pps_clear - Clears the PPS state variables + * + * Must be called while holding a write on the xtime_lock + */ +static inline void pps_clear(void) +{ + pps_reset_freq_interval(); + pps_tf[0] = 0; + pps_tf[1] = 0; + pps_tf[2] = 0; + pps_fbase.tv_sec = pps_fbase.tv_nsec = 0; + pps_freq = 0; +} + +/* Decrease pps_valid to indicate that another second has passed since + * the last PPS signal. When it reaches 0, indicate that PPS signal is + * missing. + * + * Must be called while holding a write on the xtime_lock + */ +static inline void pps_dec_valid(void) +{ + if (pps_valid > 0) + pps_valid--; + else { + time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | + STA_PPSWANDER | STA_PPSERROR); + pps_clear(); + } +} + +static inline void pps_set_freq(s64 freq) +{ + pps_freq = freq; +} + +static inline int is_error_status(int status) +{ + return (time_status & (STA_UNSYNC|STA_CLOCKERR)) + /* PPS signal lost when either PPS time or + * PPS frequency synchronization requested + */ + || ((time_status & (STA_PPSFREQ|STA_PPSTIME)) + && !(time_status & STA_PPSSIGNAL)) + /* PPS jitter exceeded when + * PPS time synchronization requested */ + || ((time_status & (STA_PPSTIME|STA_PPSJITTER)) + == (STA_PPSTIME|STA_PPSJITTER)) + /* PPS wander exceeded or calibration error when + * PPS frequency synchronization requested + */ + || ((time_status & STA_PPSFREQ) + && (time_status & (STA_PPSWANDER|STA_PPSERROR))); +} + +static inline void pps_fill_timex(struct timex *txc) +{ + txc->ppsfreq = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) * + PPM_SCALE_INV, NTP_SCALE_SHIFT); + txc->jitter = pps_jitter; + if (!(time_status & STA_NANO)) + txc->jitter /= NSEC_PER_USEC; + txc->shift = pps_shift; + txc->stabil = pps_stabil; + txc->jitcnt = pps_jitcnt; + txc->calcnt = pps_calcnt; + txc->errcnt = pps_errcnt; + txc->stbcnt = pps_stbcnt; +} + +#else /* !CONFIG_NTP_PPS */ + +static inline s64 ntp_offset_chunk(s64 offset) +{ + return shift_right(offset, SHIFT_PLL + time_constant); +} + +static inline void pps_reset_freq_interval(void) {} +static inline void pps_clear(void) {} +static inline void pps_dec_valid(void) {} +static inline void pps_set_freq(s64 freq) {} + +static inline int is_error_status(int status) +{ + return status & (STA_UNSYNC|STA_CLOCKERR); +} + +static inline void pps_fill_timex(struct timex *txc) +{ + /* PPS is not implemented, so these are zero */ + txc->ppsfreq = 0; + txc->jitter = 0; + txc->shift = 0; + txc->stabil = 0; + txc->jitcnt = 0; + txc->calcnt = 0; + txc->errcnt = 0; + txc->stbcnt = 0; +} + +#endif /* CONFIG_NTP_PPS */ + /* * NTP methods: */ @@ -185,6 +342,9 @@ void ntp_clear(void) tick_length = tick_length_base; time_offset = 0; + + /* Clear PPS state variables */ + pps_clear(); } /* @@ -250,16 +410,16 @@ void second_overflow(void) time_status |= STA_UNSYNC; } - /* - * Compute the phase adjustment for the next second. The offset is - * reduced by a fixed factor times the time constant. - */ + /* Compute the phase adjustment for the next second */ tick_length = tick_length_base; - delta = shift_right(time_offset, SHIFT_PLL + time_constant); + delta = ntp_offset_chunk(time_offset); time_offset -= delta; tick_length += delta; + /* Check PPS signal */ + pps_dec_valid(); + if (!time_adjust) return; @@ -369,6 +529,8 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts) if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) { time_state = TIME_OK; time_status = STA_UNSYNC; + /* restart PPS frequency calibration */ + pps_reset_freq_interval(); } /* @@ -418,6 +580,8 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts time_freq = txc->freq * PPM_SCALE; time_freq = min(time_freq, MAXFREQ_SCALED); time_freq = max(time_freq, -MAXFREQ_SCALED); + /* update pps_freq */ + pps_set_freq(time_freq); } if (txc->modes & ADJ_MAXERROR) @@ -508,7 +672,8 @@ int do_adjtimex(struct timex *txc) } result = time_state; /* mostly `TIME_OK' */ - if (time_status & (STA_UNSYNC|STA_CLOCKERR)) + /* check for errors */ + if (is_error_status(time_status)) result = TIME_ERROR; txc->freq = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) * @@ -522,15 +687,8 @@ int do_adjtimex(struct timex *txc) txc->tick = tick_usec; txc->tai = time_tai; - /* PPS is not implemented, so these are zero */ - txc->ppsfreq = 0; - txc->jitter = 0; - txc->shift = 0; - txc->stabil = 0; - txc->jitcnt = 0; - txc->calcnt = 0; - txc->errcnt = 0; - txc->stbcnt = 0; + /* fill PPS status fields */ + pps_fill_timex(txc); write_sequnlock_irq(&xtime_lock); @@ -544,6 +702,243 @@ int do_adjtimex(struct timex *txc) return result; } +#ifdef CONFIG_NTP_PPS + +/* actually struct pps_normtime is good old struct timespec, but it is + * semantically different (and it is the reason why it was invented): + * pps_normtime.nsec has a range of ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] + * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) */ +struct pps_normtime { + __kernel_time_t sec; /* seconds */ + long nsec; /* nanoseconds */ +}; + +/* normalize the timestamp so that nsec is in the + ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval */ +static inline struct pps_normtime pps_normalize_ts(struct timespec ts) +{ + struct pps_normtime norm = { + .sec = ts.tv_sec, + .nsec = ts.tv_nsec + }; + + if (norm.nsec > (NSEC_PER_SEC >> 1)) { + norm.nsec -= NSEC_PER_SEC; + norm.sec++; + } + + return norm; +} + +/* get current phase correction and jitter */ +static inline long pps_phase_filter_get(long *jitter) +{ + *jitter = pps_tf[0] - pps_tf[1]; + if (*jitter < 0) + *jitter = -*jitter; + + /* TODO: test various filters */ + return pps_tf[0]; +} + +/* add the sample to the phase filter */ +static inline void pps_phase_filter_add(long err) +{ + pps_tf[2] = pps_tf[1]; + pps_tf[1] = pps_tf[0]; + pps_tf[0] = err; +} + +/* decrease frequency calibration interval length. + * It is halved after four consecutive unstable intervals. + */ +static inline void pps_dec_freq_interval(void) +{ + if (--pps_intcnt <= -PPS_INTCOUNT) { + pps_intcnt = -PPS_INTCOUNT; + if (pps_shift > PPS_INTMIN) { + pps_shift--; + pps_intcnt = 0; + } + } +} + +/* increase frequency calibration interval length. + * It is doubled after four consecutive stable intervals. + */ +static inline void pps_inc_freq_interval(void) +{ + if (++pps_intcnt >= PPS_INTCOUNT) { + pps_intcnt = PPS_INTCOUNT; + if (pps_shift < PPS_INTMAX) { + pps_shift++; + pps_intcnt = 0; + } + } +} + +/* update clock frequency based on MONOTONIC_RAW clock PPS signal + * timestamps + * + * At the end of the calibration interval the difference between the + * first and last MONOTONIC_RAW clock timestamps divided by the length + * of the interval becomes the frequency update. If the interval was + * too long, the data are discarded. + * Returns the difference between old and new frequency values. + */ +static long hardpps_update_freq(struct pps_normtime freq_norm) +{ + long delta, delta_mod; + s64 ftemp; + + /* check if the frequency interval was too long */ + if (freq_norm.sec > (2 << pps_shift)) { + time_status |= STA_PPSERROR; + pps_errcnt++; + pps_dec_freq_interval(); + pr_err("hardpps: PPSERROR: interval too long - %ld s\n", + freq_norm.sec); + return 0; + } + + /* here the raw frequency offset and wander (stability) is + * calculated. If the wander is less than the wander threshold + * the interval is increased; otherwise it is decreased. + */ + ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT, + freq_norm.sec); + delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT); + pps_freq = ftemp; + if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) { + pr_warning("hardpps: PPSWANDER: change=%ld\n", delta); + time_status |= STA_PPSWANDER; + pps_stbcnt++; + pps_dec_freq_interval(); + } else { /* good sample */ + pps_inc_freq_interval(); + } + + /* the stability metric is calculated as the average of recent + * frequency changes, but is used only for performance + * monitoring + */ + delta_mod = delta; + if (delta_mod < 0) + delta_mod = -delta_mod; + pps_stabil += (div_s64(((s64)delta_mod) << + (NTP_SCALE_SHIFT - SHIFT_USEC), + NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; + + /* if enabled, the system clock frequency is updated */ + if ((time_status & STA_PPSFREQ) != 0 && + (time_status & STA_FREQHOLD) == 0) { + time_freq = pps_freq; + ntp_update_frequency(); + } + + return delta; +} + +/* correct REALTIME clock phase error against PPS signal */ +static void hardpps_update_phase(long error) +{ + long correction = -error; + long jitter; + + /* add the sample to the median filter */ + pps_phase_filter_add(correction); + correction = pps_phase_filter_get(&jitter); + + /* Nominal jitter is due to PPS signal noise. If it exceeds the + * threshold, the sample is discarded; otherwise, if so enabled, + * the time offset is updated. + */ + if (jitter > (pps_jitter << PPS_POPCORN)) { + pr_warning("hardpps: PPSJITTER: jitter=%ld, limit=%ld\n", + jitter, (pps_jitter << PPS_POPCORN)); + time_status |= STA_PPSJITTER; + pps_jitcnt++; + } else if (time_status & STA_PPSTIME) { + /* correct the time using the phase offset */ + time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, + NTP_INTERVAL_FREQ); + /* cancel running adjtime() */ + time_adjust = 0; + } + /* update jitter */ + pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN; +} + +/* + * hardpps() - discipline CPU clock oscillator to external PPS signal + * + * This routine is called at each PPS signal arrival in order to + * discipline the CPU clock oscillator to the PPS signal. It takes two + * parameters: REALTIME and MONOTONIC_RAW clock timestamps. The former + * is used to correct clock phase error and the latter is used to + * correct the frequency. + * + * This code is based on David Mills's reference nanokernel + * implementation. It was mostly rewritten but keeps the same idea. + */ +void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts) +{ + struct pps_normtime pts_norm, freq_norm; + unsigned long flags; + + pts_norm = pps_normalize_ts(*phase_ts); + + write_seqlock_irqsave(&xtime_lock, flags); + + /* clear the error bits, they will be set again if needed */ + time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); + + /* indicate signal presence */ + time_status |= STA_PPSSIGNAL; + pps_valid = PPS_VALID; + + /* when called for the first time, + * just start the frequency interval */ + if (unlikely(pps_fbase.tv_sec == 0)) { + pps_fbase = *raw_ts; + write_sequnlock_irqrestore(&xtime_lock, flags); + return; + } + + /* ok, now we have a base for frequency calculation */ + freq_norm = pps_normalize_ts(timespec_sub(*raw_ts, pps_fbase)); + + /* check that the signal is in the range + * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */ + if ((freq_norm.sec == 0) || + (freq_norm.nsec > MAXFREQ * freq_norm.sec) || + (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { + time_status |= STA_PPSJITTER; + /* restart the frequency calibration interval */ + pps_fbase = *raw_ts; + write_sequnlock_irqrestore(&xtime_lock, flags); + pr_err("hardpps: PPSJITTER: bad pulse\n"); + return; + } + + /* signal is ok */ + + /* check if the current frequency interval is finished */ + if (freq_norm.sec >= (1 << pps_shift)) { + pps_calcnt++; + /* restart the frequency calibration interval */ + pps_fbase = *raw_ts; + hardpps_update_freq(freq_norm); + } + + hardpps_update_phase(pts_norm.nsec); + + write_sequnlock_irqrestore(&xtime_lock, flags); +} +EXPORT_SYMBOL(hardpps); + +#endif /* CONFIG_NTP_PPS */ + static int __init ntp_tick_adj_setup(char *str) { ntp_tick_adj = simple_strtol(str, NULL, 0); -- cgit v1.2.3 From 717c033669ed3ceaee8df57d4562fafcc1a6267a Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:58 -0800 Subject: pps: add kernel consumer support Add an optional feature of PPSAPI, kernel consumer support, which uses the added hardpps() function. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ioctl/ioctl-number.txt | 2 +- drivers/pps/Makefile | 1 + drivers/pps/kapi.c | 6 ++ drivers/pps/kc.c | 122 +++++++++++++++++++++++++++++++++++ drivers/pps/kc.h | 46 +++++++++++++ drivers/pps/pps.c | 38 ++++++++++- include/linux/pps.h | 7 ++ 7 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 drivers/pps/kc.c create mode 100644 drivers/pps/kc.h (limited to 'drivers') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index d6a63c7b4478..ac293e955308 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -247,7 +247,7 @@ Code Seq#(hex) Include File Comments 'p' 40-7F linux/nvram.h 'p' 80-9F linux/ppdev.h user-space parport -'p' A1-A4 linux/pps.h LinuxPPS +'p' A1-A5 linux/pps.h LinuxPPS 'q' 00-1F linux/serio.h 'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile index 98960ddd3188..77c23457b739 100644 --- a/drivers/pps/Makefile +++ b/drivers/pps/Makefile @@ -3,6 +3,7 @@ # pps_core-y := pps.o kapi.o sysfs.o +pps_core-$(CONFIG_NTP_PPS) += kc.o obj-$(CONFIG_PPS) := pps_core.o obj-y += clients/ diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index ebf33746c37c..cba1b43f7519 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -26,11 +26,14 @@ #include #include #include +#include #include #include #include #include +#include "kc.h" + /* * Local functions */ @@ -139,6 +142,7 @@ EXPORT_SYMBOL(pps_register_source); void pps_unregister_source(struct pps_device *pps) { + pps_kc_remove(pps); pps_unregister_cdev(pps); /* don't have to kfree(pps) here because it will be done on @@ -211,6 +215,8 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, captured = ~0; } + pps_kc_event(pps, ts, event); + /* Wake up if captured something */ if (captured) { pps->last_ev++; diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c new file mode 100644 index 000000000000..079e930b1938 --- /dev/null +++ b/drivers/pps/kc.c @@ -0,0 +1,122 @@ +/* + * PPS kernel consumer API + * + * Copyright (C) 2009-2010 Alexander Gordeev + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "kc.h" + +/* + * Global variables + */ + +/* state variables to bind kernel consumer */ +DEFINE_SPINLOCK(pps_kc_hardpps_lock); +/* PPS API (RFC 2783): current source and mode for kernel consumer */ +struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */ +int pps_kc_hardpps_mode; /* mode bits for kernel consumer */ + +/* pps_kc_bind - control PPS kernel consumer binding + * @pps: the PPS source + * @bind_args: kernel consumer bind parameters + * + * This function is used to bind or unbind PPS kernel consumer according to + * supplied parameters. Should not be called in interrupt context. + */ +int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args) +{ + /* Check if another consumer is already bound */ + spin_lock_irq(&pps_kc_hardpps_lock); + + if (bind_args->edge == 0) + if (pps_kc_hardpps_dev == pps) { + pps_kc_hardpps_mode = 0; + pps_kc_hardpps_dev = NULL; + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_info(pps->dev, "unbound kernel" + " consumer\n"); + } else { + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_err(pps->dev, "selected kernel consumer" + " is not bound\n"); + return -EINVAL; + } + else + if (pps_kc_hardpps_dev == NULL || + pps_kc_hardpps_dev == pps) { + pps_kc_hardpps_mode = bind_args->edge; + pps_kc_hardpps_dev = pps; + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_info(pps->dev, "bound kernel consumer: " + "edge=0x%x\n", bind_args->edge); + } else { + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_err(pps->dev, "another kernel consumer" + " is already bound\n"); + return -EINVAL; + } + + return 0; +} + +/* pps_kc_remove - unbind kernel consumer on PPS source removal + * @pps: the PPS source + * + * This function is used to disable kernel consumer on PPS source removal + * if this source was bound to PPS kernel consumer. Can be called on any + * source safely. Should not be called in interrupt context. + */ +void pps_kc_remove(struct pps_device *pps) +{ + spin_lock_irq(&pps_kc_hardpps_lock); + if (pps == pps_kc_hardpps_dev) { + pps_kc_hardpps_mode = 0; + pps_kc_hardpps_dev = NULL; + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_info(pps->dev, "unbound kernel consumer" + " on device removal\n"); + } else + spin_unlock_irq(&pps_kc_hardpps_lock); +} + +/* pps_kc_event - call hardpps() on PPS event + * @pps: the PPS source + * @ts: PPS event timestamp + * @event: PPS event edge + * + * This function calls hardpps() when an event from bound PPS source occurs. + */ +void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts, + int event) +{ + unsigned long flags; + + /* Pass some events to kernel consumer if activated */ + spin_lock_irqsave(&pps_kc_hardpps_lock, flags); + if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode) + hardpps(&ts->ts_real, &ts->ts_raw); + spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags); +} diff --git a/drivers/pps/kc.h b/drivers/pps/kc.h new file mode 100644 index 000000000000..d296fcd0a175 --- /dev/null +++ b/drivers/pps/kc.h @@ -0,0 +1,46 @@ +/* + * PPS kernel consumer API header + * + * Copyright (C) 2009-2010 Alexander Gordeev + * + * 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 LINUX_PPS_KC_H +#define LINUX_PPS_KC_H + +#include +#include + +#ifdef CONFIG_NTP_PPS + +extern int pps_kc_bind(struct pps_device *pps, + struct pps_bind_args *bind_args); +extern void pps_kc_remove(struct pps_device *pps); +extern void pps_kc_event(struct pps_device *pps, + struct pps_event_time *ts, int event); + + +#else /* CONFIG_NTP_PPS */ + +static inline int pps_kc_bind(struct pps_device *pps, + struct pps_bind_args *bind_args) { return -EOPNOTSUPP; } +static inline void pps_kc_remove(struct pps_device *pps) {} +static inline void pps_kc_event(struct pps_device *pps, + struct pps_event_time *ts, int event) {} + +#endif /* CONFIG_NTP_PPS */ + +#endif /* LINUX_PPS_KC_H */ diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 9e15cf1da946..2baadd21b7a6 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -33,6 +33,8 @@ #include #include +#include "kc.h" + /* * Local variables */ @@ -198,9 +200,43 @@ static long pps_cdev_ioctl(struct file *file, break; } + case PPS_KC_BIND: { + struct pps_bind_args bind_args; + + dev_dbg(pps->dev, "PPS_KC_BIND\n"); + + /* Check the capabilities */ + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (copy_from_user(&bind_args, uarg, + sizeof(struct pps_bind_args))) + return -EFAULT; + + /* Check for supported capabilities */ + if ((bind_args.edge & ~pps->info.mode) != 0) { + dev_err(pps->dev, "unsupported capabilities (%x)\n", + bind_args.edge); + return -EINVAL; + } + + /* Validate parameters roughly */ + if (bind_args.tsformat != PPS_TSFMT_TSPEC || + (bind_args.edge & ~PPS_CAPTUREBOTH) != 0 || + bind_args.consumer != PPS_KC_HARDPPS) { + dev_err(pps->dev, "invalid kernel consumer bind" + " parameters (%x)\n", bind_args.edge); + return -EINVAL; + } + + err = pps_kc_bind(pps, &bind_args); + if (err < 0) + return err; + + break; + } default: return -ENOTTY; - break; } return 0; diff --git a/include/linux/pps.h b/include/linux/pps.h index 0194ab06177b..a9bb1d93451a 100644 --- a/include/linux/pps.h +++ b/include/linux/pps.h @@ -114,11 +114,18 @@ struct pps_fdata { struct pps_ktime timeout; }; +struct pps_bind_args { + int tsformat; /* format of time stamps */ + int edge; /* selected event type */ + int consumer; /* selected kernel consumer */ +}; + #include #define PPS_GETPARAMS _IOR('p', 0xa1, struct pps_kparams *) #define PPS_SETPARAMS _IOW('p', 0xa2, struct pps_kparams *) #define PPS_GETCAP _IOR('p', 0xa3, int *) #define PPS_FETCH _IOWR('p', 0xa4, struct pps_fdata *) +#define PPS_KC_BIND _IOW('p', 0xa5, struct pps_bind_args *) #endif /* _PPS_H_ */ -- cgit v1.2.3 From a10203c691eac287664f531b149ddc23056c2f61 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:58 -0800 Subject: pps: add parallel port PPS client Add parallel port PPS client. It uses a standard method for capturing timestamps for assert edge transitions: getting a timestamp soon after an interrupt has happened. This is not a very precise source of time information due to interrupt handling delays. However, timestamps for clear edge transitions are much more precise because the interrupt handler continuously polls hardware port until the transition is done. Hardware port operations require only about 1us so the maximum error should not exceed this value. This was my primary goal when developing this client. Clear edge capture could be disabled using clear_wait parameter. Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/clients/Kconfig | 7 ++ drivers/pps/clients/Makefile | 1 + drivers/pps/clients/pps_parport.c | 258 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 drivers/pps/clients/pps_parport.c (limited to 'drivers') diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig index 4e801bd7254f..8520a7f4dd62 100644 --- a/drivers/pps/clients/Kconfig +++ b/drivers/pps/clients/Kconfig @@ -22,4 +22,11 @@ config PPS_CLIENT_LDISC If you say yes here you get support for a PPS source connected with the CD (Carrier Detect) pin of your serial port. +config PPS_CLIENT_PARPORT + tristate "Parallel port PPS client" + depends on PPS && PARPORT + help + If you say yes here you get support for a PPS source connected + with the interrupt pin of your parallel port. + endif diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile index 812c9b19b430..42517da07049 100644 --- a/drivers/pps/clients/Makefile +++ b/drivers/pps/clients/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o +obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o ifeq ($(CONFIG_PPS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c new file mode 100644 index 000000000000..32221efd9ca9 --- /dev/null +++ b/drivers/pps/clients/pps_parport.c @@ -0,0 +1,258 @@ +/* + * pps_parport.c -- kernel parallel port PPS client + * + * + * Copyright (C) 2009 Alexander Gordeev + * + * 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. + */ + + +/* + * TODO: + * implement echo over SEL pin + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define DRVDESC "parallel port PPS client" + +/* module parameters */ + +#define CLEAR_WAIT_MAX 100 +#define CLEAR_WAIT_MAX_ERRORS 5 + +static unsigned int clear_wait = 100; +MODULE_PARM_DESC(clear_wait, + "Maximum number of port reads when polling for signal clear," + " zero turns clear edge capture off entirely"); +module_param(clear_wait, uint, 0); + + +/* internal per port structure */ +struct pps_client_pp { + struct pardevice *pardev; /* parport device */ + struct pps_device *pps; /* PPS device */ + unsigned int cw; /* port clear timeout */ + unsigned int cw_err; /* number of timeouts */ +}; + +static inline int signal_is_set(struct parport *port) +{ + return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0; +} + +/* parport interrupt handler */ +static void parport_irq(void *handle) +{ + struct pps_event_time ts_assert, ts_clear; + struct pps_client_pp *dev = handle; + struct parport *port = dev->pardev->port; + unsigned int i; + unsigned long flags; + + /* first of all we get the time stamp... */ + pps_get_ts(&ts_assert); + + if (dev->cw == 0) + /* clear edge capture disabled */ + goto out_assert; + + /* try capture the clear edge */ + + /* We have to disable interrupts here. The idea is to prevent + * other interrupts on the same processor to introduce random + * lags while polling the port. Reading from IO port is known + * to take approximately 1us while other interrupt handlers can + * take much more potentially. + * + * Interrupts won't be disabled for a long time because the + * number of polls is limited by clear_wait parameter which is + * kept rather low. So it should never be an issue. + */ + local_irq_save(flags); + /* check the signal (no signal means the pulse is lost this time) */ + if (!signal_is_set(port)) { + local_irq_restore(flags); + dev_err(dev->pps->dev, "lost the signal\n"); + goto out_assert; + } + + /* poll the port until the signal is unset */ + for (i = dev->cw; i; i--) + if (!signal_is_set(port)) { + pps_get_ts(&ts_clear); + local_irq_restore(flags); + dev->cw_err = 0; + goto out_both; + } + local_irq_restore(flags); + + /* timeout */ + dev->cw_err++; + if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) { + dev_err(dev->pps->dev, "disabled clear edge capture after %d" + " timeouts\n", dev->cw_err); + dev->cw = 0; + dev->cw_err = 0; + } + +out_assert: + /* fire assert event */ + pps_event(dev->pps, &ts_assert, + PPS_CAPTUREASSERT, NULL); + return; + +out_both: + /* fire assert event */ + pps_event(dev->pps, &ts_assert, + PPS_CAPTUREASSERT, NULL); + /* fire clear event */ + pps_event(dev->pps, &ts_clear, + PPS_CAPTURECLEAR, NULL); + return; +} + +/* the PPS echo function */ +static void pps_echo(struct pps_device *pps, int event, void *data) +{ + dev_info(pps->dev, "echo %s %s\n", + event & PPS_CAPTUREASSERT ? "assert" : "", + event & PPS_CAPTURECLEAR ? "clear" : ""); +} + +static void parport_attach(struct parport *port) +{ + struct pps_client_pp *device; + struct pps_source_info info = { + .name = KBUILD_MODNAME, + .path = "", + .mode = PPS_CAPTUREBOTH | \ + PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ + PPS_ECHOASSERT | PPS_ECHOCLEAR | \ + PPS_CANWAIT | PPS_TSFMT_TSPEC, + .echo = pps_echo, + .owner = THIS_MODULE, + .dev = NULL + }; + + device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL); + if (!device) { + pr_err("memory allocation failed, not attaching\n"); + return; + } + + device->pardev = parport_register_device(port, KBUILD_MODNAME, + NULL, NULL, parport_irq, 0, device); + if (!device->pardev) { + pr_err("couldn't register with %s\n", port->name); + goto err_free; + } + + if (parport_claim_or_block(device->pardev) < 0) { + pr_err("couldn't claim %s\n", port->name); + goto err_unregister_dev; + } + + device->pps = pps_register_source(&info, + PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR); + if (device->pps == NULL) { + pr_err("couldn't register PPS source\n"); + goto err_release_dev; + } + + device->cw = clear_wait; + + port->ops->enable_irq(port); + + pr_info("attached to %s\n", port->name); + + return; + +err_release_dev: + parport_release(device->pardev); +err_unregister_dev: + parport_unregister_device(device->pardev); +err_free: + kfree(device); +} + +static void parport_detach(struct parport *port) +{ + struct pardevice *pardev = port->cad; + struct pps_client_pp *device; + + /* FIXME: oooh, this is ugly! */ + if (strcmp(pardev->name, KBUILD_MODNAME)) + /* not our port */ + return; + + device = pardev->private; + + port->ops->disable_irq(port); + pps_unregister_source(device->pps); + parport_release(pardev); + parport_unregister_device(pardev); + kfree(device); +} + +static struct parport_driver pps_parport_driver = { + .name = KBUILD_MODNAME, + .attach = parport_attach, + .detach = parport_detach, +}; + +/* module staff */ + +static int __init pps_parport_init(void) +{ + int ret; + + pr_info(DRVDESC "\n"); + + if (clear_wait > CLEAR_WAIT_MAX) { + pr_err("clear_wait value should be not greater" + " then %d\n", CLEAR_WAIT_MAX); + return -EINVAL; + } + + ret = parport_register_driver(&pps_parport_driver); + if (ret) { + pr_err("unable to register with parport\n"); + return ret; + } + + return 0; +} + +static void __exit pps_parport_exit(void) +{ + parport_unregister_driver(&pps_parport_driver); +} + +module_init(pps_parport_init); +module_exit(pps_parport_exit); + +MODULE_AUTHOR("Alexander Gordeev "); +MODULE_DESCRIPTION(DRVDESC); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 46b402a0e5e4b4d81b11c32dfb2312bf5828ecb5 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:59 -0800 Subject: pps: add parallel port PPS signal generator Add PPS signal generator which utilizes STROBE pin of a parallel port to send PPS signals. It uses parport abstraction layer and hrtimers to precisely control the signal. [akpm@linux-foundation.org: fix build] Signed-off-by: Alexander Gordeev Acked-by: Rodolfo Giometti Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/pps/pps.txt | 46 ++++++ drivers/pps/Kconfig | 2 + drivers/pps/Makefile | 2 +- drivers/pps/generators/Kconfig | 17 ++ drivers/pps/generators/Makefile | 9 + drivers/pps/generators/pps_gen_parport.c | 275 +++++++++++++++++++++++++++++++ 6 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 drivers/pps/generators/Kconfig create mode 100644 drivers/pps/generators/Makefile create mode 100644 drivers/pps/generators/pps_gen_parport.c (limited to 'drivers') diff --git a/Documentation/pps/pps.txt b/Documentation/pps/pps.txt index 125f4ab48998..d35dcdd82ff6 100644 --- a/Documentation/pps/pps.txt +++ b/Documentation/pps/pps.txt @@ -170,3 +170,49 @@ and the run ppstest as follow: Please, note that to compile userland programs you need the file timepps.h (see Documentation/pps/). + + +Generators +---------- + +Sometimes one needs to be able not only to catch PPS signals but to produce +them also. For example, running a distributed simulation, which requires +computers' clock to be synchronized very tightly. One way to do this is to +invent some complicated hardware solutions but it may be neither necessary +nor affordable. The cheap way is to load a PPS generator on one of the +computers (master) and PPS clients on others (slaves), and use very simple +cables to deliver signals using parallel ports, for example. + +Parallel port cable pinout: +pin name master slave +1 STROBE *------ * +2 D0 * | * +3 D1 * | * +4 D2 * | * +5 D3 * | * +6 D4 * | * +7 D5 * | * +8 D6 * | * +9 D7 * | * +10 ACK * ------* +11 BUSY * * +12 PE * * +13 SEL * * +14 AUTOFD * * +15 ERROR * * +16 INIT * * +17 SELIN * * +18-25 GND *-----------* + +Please note that parallel port interrupt occurs only on high->low transition, +so it is used for PPS assert edge. PPS clear edge can be determined only +using polling in the interrupt handler which actually can be done way more +precisely because interrupt handling delays can be quite big and random. So +current parport PPS generator implementation (pps_gen_parport module) is +geared towards using the clear edge for time synchronization. + +Clear edge polling is done with disabled interrupts so it's better to select +delay between assert and clear edge as small as possible to reduce system +latencies. But if it is too small slave won't be able to capture clear edge +transition. The default of 30us should be good enough in most situations. +The delay can be selected using 'delay' pps_gen_parport module parameter. diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig index 0ad5ff38bfec..f0d3376b58ba 100644 --- a/drivers/pps/Kconfig +++ b/drivers/pps/Kconfig @@ -41,4 +41,6 @@ config NTP_PPS source drivers/pps/clients/Kconfig +source drivers/pps/generators/Kconfig + endmenu diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile index 77c23457b739..4483eaadaddd 100644 --- a/drivers/pps/Makefile +++ b/drivers/pps/Makefile @@ -5,6 +5,6 @@ pps_core-y := pps.o kapi.o sysfs.o pps_core-$(CONFIG_NTP_PPS) += kc.o obj-$(CONFIG_PPS) := pps_core.o -obj-y += clients/ +obj-y += clients/ generators/ ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig new file mode 100644 index 000000000000..5fbd6148c804 --- /dev/null +++ b/drivers/pps/generators/Kconfig @@ -0,0 +1,17 @@ +# +# PPS generators configuration +# + +if PPS + +comment "PPS generators support" + +config PPS_GENERATOR_PARPORT + tristate "Parallel port PPS signal generator" + depends on PARPORT != n && GENERIC_TIME + help + If you say yes here you get support for a PPS signal generator which + utilizes STROBE pin of a parallel port to send PPS signals. It uses + parport abstraction layer and hrtimers to precisely control the signal. + +endif diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile new file mode 100644 index 000000000000..303304a6b8ec --- /dev/null +++ b/drivers/pps/generators/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for PPS generators. +# + +obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o + +ifeq ($(CONFIG_PPS_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c new file mode 100644 index 000000000000..a15fe25efd55 --- /dev/null +++ b/drivers/pps/generators/pps_gen_parport.c @@ -0,0 +1,275 @@ +/* + * pps_gen_parport.c -- kernel parallel port PPS signal generator + * + * + * Copyright (C) 2009 Alexander Gordeev + * + * 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. + */ + + +/* + * TODO: + * fix issues when realtime clock is adjusted in a leap + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define DRVDESC "parallel port PPS signal generator" + +#define SIGNAL 0 +#define NO_SIGNAL PARPORT_CONTROL_STROBE + +/* module parameters */ + +#define SEND_DELAY_MAX 100000 + +static unsigned int send_delay = 30000; +MODULE_PARM_DESC(delay, + "Delay between setting and dropping the signal (ns)"); +module_param_named(delay, send_delay, uint, 0); + + +#define SAFETY_INTERVAL 3000 /* set the hrtimer earlier for safety (ns) */ + +/* internal per port structure */ +struct pps_generator_pp { + struct pardevice *pardev; /* parport device */ + struct hrtimer timer; + long port_write_time; /* calibrated port write time (ns) */ +}; + +static struct pps_generator_pp device = { + .pardev = NULL, +}; + +static int attached; + +/* calibrated time between a hrtimer event and the reaction */ +static long hrtimer_error = SAFETY_INTERVAL; + +/* the kernel hrtimer event */ +static enum hrtimer_restart hrtimer_event(struct hrtimer *timer) +{ + struct timespec expire_time, ts1, ts2, ts3, dts; + struct pps_generator_pp *dev; + struct parport *port; + long lim, delta; + unsigned long flags; + + /* NB: approx time with blocked interrupts = + send_delay + 3 * SAFETY_INTERVAL */ + local_irq_save(flags); + + /* first of all we get the time stamp... */ + getnstimeofday(&ts1); + expire_time = ktime_to_timespec(hrtimer_get_softexpires(timer)); + dev = container_of(timer, struct pps_generator_pp, timer); + lim = NSEC_PER_SEC - send_delay - dev->port_write_time; + + /* check if we are late */ + if (expire_time.tv_sec != ts1.tv_sec || ts1.tv_nsec > lim) { + local_irq_restore(flags); + pr_err("we are late this time %ld.%09ld\n", + ts1.tv_sec, ts1.tv_nsec); + goto done; + } + + /* busy loop until the time is right for an assert edge */ + do { + getnstimeofday(&ts2); + } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim); + + /* set the signal */ + port = dev->pardev->port; + port->ops->write_control(port, SIGNAL); + + /* busy loop until the time is right for a clear edge */ + lim = NSEC_PER_SEC - dev->port_write_time; + do { + getnstimeofday(&ts2); + } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim); + + /* unset the signal */ + port->ops->write_control(port, NO_SIGNAL); + + getnstimeofday(&ts3); + + local_irq_restore(flags); + + /* update calibrated port write time */ + dts = timespec_sub(ts3, ts2); + dev->port_write_time = + (dev->port_write_time + timespec_to_ns(&dts)) >> 1; + +done: + /* update calibrated hrtimer error */ + dts = timespec_sub(ts1, expire_time); + delta = timespec_to_ns(&dts); + /* If the new error value is bigger then the old, use the new + * value, if not then slowly move towards the new value. This + * way it should be safe in bad conditions and efficient in + * good conditions. + */ + if (delta >= hrtimer_error) + hrtimer_error = delta; + else + hrtimer_error = (3 * hrtimer_error + delta) >> 2; + + /* update the hrtimer expire time */ + hrtimer_set_expires(timer, + ktime_set(expire_time.tv_sec + 1, + NSEC_PER_SEC - (send_delay + + dev->port_write_time + SAFETY_INTERVAL + + 2 * hrtimer_error))); + + return HRTIMER_RESTART; +} + +/* calibrate port write time */ +#define PORT_NTESTS_SHIFT 5 +static void calibrate_port(struct pps_generator_pp *dev) +{ + struct parport *port = dev->pardev->port; + int i; + long acc = 0; + + for (i = 0; i < (1 << PORT_NTESTS_SHIFT); i++) { + struct timespec a, b; + unsigned long irq_flags; + + local_irq_save(irq_flags); + getnstimeofday(&a); + port->ops->write_control(port, NO_SIGNAL); + getnstimeofday(&b); + local_irq_restore(irq_flags); + + b = timespec_sub(b, a); + acc += timespec_to_ns(&b); + } + + dev->port_write_time = acc >> PORT_NTESTS_SHIFT; + pr_info("port write takes %ldns\n", dev->port_write_time); +} + +static inline ktime_t next_intr_time(struct pps_generator_pp *dev) +{ + struct timespec ts; + + getnstimeofday(&ts); + + return ktime_set(ts.tv_sec + + ((ts.tv_nsec > 990 * NSEC_PER_MSEC) ? 1 : 0), + NSEC_PER_SEC - (send_delay + + dev->port_write_time + 3 * SAFETY_INTERVAL)); +} + +static void parport_attach(struct parport *port) +{ + if (attached) { + /* we already have a port */ + return; + } + + device.pardev = parport_register_device(port, KBUILD_MODNAME, + NULL, NULL, NULL, 0, &device); + if (!device.pardev) { + pr_err("couldn't register with %s\n", port->name); + return; + } + + if (parport_claim_or_block(device.pardev) < 0) { + pr_err("couldn't claim %s\n", port->name); + goto err_unregister_dev; + } + + pr_info("attached to %s\n", port->name); + attached = 1; + + calibrate_port(&device); + + hrtimer_init(&device.timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); + device.timer.function = hrtimer_event; +#ifdef CONFIG_PREEMPT_RT + /* hrtimer interrupt will run in the interrupt context with this */ + device.timer.irqsafe = 1; +#endif + + hrtimer_start(&device.timer, next_intr_time(&device), HRTIMER_MODE_ABS); + + return; + +err_unregister_dev: + parport_unregister_device(device.pardev); +} + +static void parport_detach(struct parport *port) +{ + if (port->cad != device.pardev) + return; /* not our port */ + + hrtimer_cancel(&device.timer); + parport_release(device.pardev); + parport_unregister_device(device.pardev); +} + +static struct parport_driver pps_gen_parport_driver = { + .name = KBUILD_MODNAME, + .attach = parport_attach, + .detach = parport_detach, +}; + +/* module staff */ + +static int __init pps_gen_parport_init(void) +{ + int ret; + + pr_info(DRVDESC "\n"); + + if (send_delay > SEND_DELAY_MAX) { + pr_err("delay value should be not greater" + " then %d\n", SEND_DELAY_MAX); + return -EINVAL; + } + + ret = parport_register_driver(&pps_gen_parport_driver); + if (ret) { + pr_err("unable to register with parport\n"); + return ret; + } + + return 0; +} + +static void __exit pps_gen_parport_exit(void) +{ + parport_unregister_driver(&pps_gen_parport_driver); + pr_info("hrtimer avg error is %ldns\n", hrtimer_error); +} + +module_init(pps_gen_parport_init); +module_exit(pps_gen_parport_exit); + +MODULE_AUTHOR("Alexander Gordeev "); +MODULE_DESCRIPTION(DRVDESC); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 563558b2c7350371551bf08348ac61be62200505 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:01:00 -0800 Subject: pps: add parallel port PPS signal generator Add PPS signal generator which utilizes STROBE pin of a parallel port to send PPS signals. It uses parport abstraction layer and hrtimers to precisely control the signal. Signed-off-by: Alexander Gordeev Cc: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/generators/Kconfig | 6 +----- drivers/pps/generators/pps_gen_parport.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig index 5fbd6148c804..f3a73dd77660 100644 --- a/drivers/pps/generators/Kconfig +++ b/drivers/pps/generators/Kconfig @@ -2,16 +2,12 @@ # PPS generators configuration # -if PPS - comment "PPS generators support" config PPS_GENERATOR_PARPORT tristate "Parallel port PPS signal generator" - depends on PARPORT != n && GENERIC_TIME + depends on PARPORT help If you say yes here you get support for a PPS signal generator which utilizes STROBE pin of a parallel port to send PPS signals. It uses parport abstraction layer and hrtimers to precisely control the signal. - -endif diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c index a15fe25efd55..5c32f8dacf56 100644 --- a/drivers/pps/generators/pps_gen_parport.c +++ b/drivers/pps/generators/pps_gen_parport.c @@ -76,8 +76,15 @@ static enum hrtimer_restart hrtimer_event(struct hrtimer *timer) long lim, delta; unsigned long flags; - /* NB: approx time with blocked interrupts = - send_delay + 3 * SAFETY_INTERVAL */ + /* We have to disable interrupts here. The idea is to prevent + * other interrupts on the same processor to introduce random + * lags while polling the clock. getnstimeofday() takes <1us on + * most machines while other interrupt handlers can take much + * more potentially. + * + * NB: approx time with blocked interrupts = + * send_delay + 3 * SAFETY_INTERVAL + */ local_irq_save(flags); /* first of all we get the time stamp... */ -- cgit v1.2.3 From 0193383a5833c1f082c738eaca868e4093a8df39 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Wed, 12 Jan 2011 17:01:00 -0800 Subject: memstick: core: fix device_register() error handling If device_register() fails then call put_device(). See comment to device_register. Signed-off-by: Vasiliy Kulikov Cc: Maxim Levitsky Cc: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/core/memstick.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index c00fe8253c51..4303b7ef73e2 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work) if (!host->card) { host->card = card; if (device_register(&card->dev)) { + put_device(&card->dev); kfree(host->card); host->card = NULL; } -- cgit v1.2.3 From 23c5947ac3f7a610bb4cb9e433802b36edc80fdf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 12 Jan 2011 17:01:01 -0800 Subject: memstick: fix setup for JMicron 38x controllers This patch corrects the definition of clock values for JMicron 38x controllers and sets the value properly per interface type. Also, it adds a check for TPC errors in the interrupt handler. Signed-off-by: Aries Lee Signed-off-by: Takashi Iwai Cc: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/host/jmb38x_ms.c | 66 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index f2b894cd8b02..c90ba5082252 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -61,6 +61,7 @@ struct jmb38x_ms_host { struct memstick_request *req; unsigned char cmd_flags; unsigned char io_pos; + unsigned char ifmode; unsigned int io_word[2]; }; @@ -136,15 +137,14 @@ struct jmb38x_ms { #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 +#define CLOCK_CONTROL_BY_MMIO 0x00000008 #define CLOCK_CONTROL_40MHZ 0x00000001 -#define CLOCK_CONTROL_50MHZ 0x0000000a -#define CLOCK_CONTROL_60MHZ 0x00000008 -#define CLOCK_CONTROL_62_5MHZ 0x0000000c +#define CLOCK_CONTROL_50MHZ 0x00000002 +#define CLOCK_CONTROL_60MHZ 0x00000010 +#define CLOCK_CONTROL_62_5MHZ 0x00000004 #define CLOCK_CONTROL_OFF 0x00000000 #define PCI_CTL_CLOCK_DLY_ADDR 0x000000b0 -#define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00 -#define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000 enum { CMD_READY = 0x01, @@ -390,8 +390,13 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) if (host->req->data_dir == READ) cmd |= TPC_DIR; - if (host->req->need_card_int) - cmd |= TPC_WAIT_INT; + + if (host->req->need_card_int) { + if (host->ifmode == MEMSTICK_SERIAL) + cmd |= TPC_GET_INT; + else + cmd |= TPC_WAIT_INT; + } data = host->req->data; @@ -529,7 +534,10 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) if (irq_status & INT_STATUS_ANY_ERR) { if (irq_status & INT_STATUS_CRC_ERR) host->req->error = -EILSEQ; - else + else if (irq_status & INT_STATUS_TPC_ERR) { + dev_dbg(&host->chip->pdev->dev, "TPC_ERR\n"); + jmb38x_ms_complete_cmd(msh, 0); + } else host->req->error = -ETIME; } else { if (host->cmd_flags & DMA_DATA) { @@ -644,7 +652,6 @@ static int jmb38x_ms_reset(struct jmb38x_ms_host *host) ndelay(20); } dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); - /* return -EIO; */ reset_next: writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN @@ -675,7 +682,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, { struct jmb38x_ms_host *host = memstick_priv(msh); unsigned int host_ctl = readl(host->addr + HOST_CONTROL); - unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; + unsigned int clock_ctl = CLOCK_CONTROL_BY_MMIO, clock_delay = 0; int rc = 0; switch (param) { @@ -687,9 +694,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, host_ctl = 7; host_ctl |= HOST_CONTROL_POWER_EN - | HOST_CONTROL_CLOCK_EN - | HOST_CONTROL_HW_OC_P - | HOST_CONTROL_TDELAY_EN; + | HOST_CONTROL_CLOCK_EN; writel(host_ctl, host->addr + HOST_CONTROL); writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 @@ -712,41 +717,42 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, return -EINVAL; break; case MEMSTICK_INTERFACE: + dev_dbg(&host->chip->pdev->dev, + "Set Host Interface Mode to %d\n", value); + host_ctl &= ~(HOST_CONTROL_FAST_CLK | HOST_CONTROL_REI | + HOST_CONTROL_REO); + host_ctl |= HOST_CONTROL_TDELAY_EN | HOST_CONTROL_HW_OC_P; host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); - pci_read_config_dword(host->chip->pdev, - PCI_CTL_CLOCK_DLY_ADDR, - &clock_delay); - clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B - : ~PCI_CTL_CLOCK_DLY_MASK_A; if (value == MEMSTICK_SERIAL) { - host_ctl &= ~HOST_CONTROL_FAST_CLK; - host_ctl &= ~HOST_CONTROL_REO; host_ctl |= HOST_CONTROL_IF_SERIAL << HOST_CONTROL_IF_SHIFT; host_ctl |= HOST_CONTROL_REI; - clock_ctl = CLOCK_CONTROL_40MHZ; + clock_ctl |= CLOCK_CONTROL_40MHZ; + clock_delay = 0; } else if (value == MEMSTICK_PAR4) { - host_ctl |= HOST_CONTROL_FAST_CLK | HOST_CONTROL_REO; + host_ctl |= HOST_CONTROL_FAST_CLK; host_ctl |= HOST_CONTROL_IF_PAR4 << HOST_CONTROL_IF_SHIFT; - host_ctl &= ~HOST_CONTROL_REI; - clock_ctl = CLOCK_CONTROL_40MHZ; - clock_delay |= host->id ? (4 << 12) : (4 << 8); + host_ctl |= HOST_CONTROL_REO; + clock_ctl |= CLOCK_CONTROL_40MHZ; + clock_delay = 4; } else if (value == MEMSTICK_PAR8) { host_ctl |= HOST_CONTROL_FAST_CLK; host_ctl |= HOST_CONTROL_IF_PAR8 << HOST_CONTROL_IF_SHIFT; - host_ctl &= ~(HOST_CONTROL_REI | HOST_CONTROL_REO); - clock_ctl = CLOCK_CONTROL_50MHZ; + clock_ctl |= CLOCK_CONTROL_50MHZ; + clock_delay = 0; } else return -EINVAL; writel(host_ctl, host->addr + HOST_CONTROL); + writel(CLOCK_CONTROL_OFF, host->addr + CLOCK_CONTROL); writel(clock_ctl, host->addr + CLOCK_CONTROL); - pci_write_config_dword(host->chip->pdev, - PCI_CTL_CLOCK_DLY_ADDR, - clock_delay); + pci_write_config_byte(host->chip->pdev, + PCI_CTL_CLOCK_DLY_ADDR + 1, + clock_delay); + host->ifmode = value; break; }; return 0; -- cgit v1.2.3 From 68860b96ebac0d56961cf80b94f65dab55e39069 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 12 Jan 2011 17:01:02 -0800 Subject: memstick: set PMOS values propery for JMicron 38x controllers Add a function jmb38x_ms_pmos() to enable / disable PMOS setups for JMicron 38x controllers. Signed-off-by: Aries Lee Signed-off-by: Takashi Iwai Cc: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/host/jmb38x_ms.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index c90ba5082252..4ce8773fa3b8 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -758,6 +758,35 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, return 0; } +#define PCI_PMOS0_CONTROL 0xae +#define PMOS0_ENABLE 0x01 +#define PMOS0_OVERCURRENT_LEVEL_2_4V 0x06 +#define PMOS0_EN_OVERCURRENT_DEBOUNCE 0x40 +#define PMOS0_SW_LED_POLARITY_ENABLE 0x80 +#define PMOS0_ACTIVE_BITS (PMOS0_ENABLE | PMOS0_EN_OVERCURRENT_DEBOUNCE | \ + PMOS0_OVERCURRENT_LEVEL_2_4V) +#define PCI_CLOCK_CTL 0xb9 + +static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag) +{ + unsigned char val; + + pci_read_config_byte(pdev, PCI_PMOS0_CONTROL, &val); + if (flag) + val |= PMOS0_ACTIVE_BITS; + else + val &= ~PMOS0_ACTIVE_BITS; + pci_write_config_byte(pdev, PCI_PMOS0_CONTROL, val); + dev_dbg(&pdev->dev, "JMB38x: set PMOS0 val 0x%x\n", val); + + pci_read_config_byte(pdev, PCI_CLOCK_CTL, &val); + pci_write_config_byte(pdev, PCI_CLOCK_CTL, val & ~0x0f); + pci_write_config_byte(pdev, PCI_CLOCK_CTL, val | 0x01); + dev_dbg(&pdev->dev, "Clock Control by PCI config is disabled!\n"); + + return 0; +} + #ifdef CONFIG_PM static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) @@ -790,8 +819,7 @@ static int jmb38x_ms_resume(struct pci_dev *dev) return rc; pci_set_master(dev); - pci_read_config_dword(dev, 0xac, &rc); - pci_write_config_dword(dev, 0xac, rc | 0x00470000); + jmb38x_ms_pmos(dev, 1); for (rc = 0; rc < jm->host_cnt; ++rc) { if (!jm->hosts[rc]) @@ -900,8 +928,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev, goto err_out; } - pci_read_config_dword(pdev, 0xac, &rc); - pci_write_config_dword(pdev, 0xac, rc | 0x00470000); + jmb38x_ms_pmos(pdev, 1); cnt = jmb38x_ms_count_slots(pdev); if (!cnt) { @@ -982,6 +1009,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev) jmb38x_ms_free_host(jm->hosts[cnt]); } + jmb38x_ms_pmos(dev, 0); + pci_set_drvdata(dev, NULL); pci_release_regions(dev); pci_disable_device(dev); -- cgit v1.2.3 From 8930c8aa740b12ad69f44a35137bcc39bfa3dc41 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 12 Jan 2011 17:01:03 -0800 Subject: memstick: add support for JMicron JMB 385 and 390 controllers Signed-off-by: Aries Lee Signed-off-by: Takashi Iwai Cc: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/host/jmb38x_ms.c | 17 +++++++++++++++-- include/linux/pci_ids.h | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 4ce8773fa3b8..d89d925caecf 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -765,6 +765,8 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, #define PMOS0_SW_LED_POLARITY_ENABLE 0x80 #define PMOS0_ACTIVE_BITS (PMOS0_ENABLE | PMOS0_EN_OVERCURRENT_DEBOUNCE | \ PMOS0_OVERCURRENT_LEVEL_2_4V) +#define PCI_PMOS1_CONTROL 0xbd +#define PMOS1_ACTIVE_BITS 0x4a #define PCI_CLOCK_CTL 0xb9 static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag) @@ -779,6 +781,16 @@ static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag) pci_write_config_byte(pdev, PCI_PMOS0_CONTROL, val); dev_dbg(&pdev->dev, "JMB38x: set PMOS0 val 0x%x\n", val); + if (pci_resource_flags(pdev, 1)) { + pci_read_config_byte(pdev, PCI_PMOS1_CONTROL, &val); + if (flag) + val |= PMOS1_ACTIVE_BITS; + else + val &= ~PMOS1_ACTIVE_BITS; + pci_write_config_byte(pdev, PCI_PMOS1_CONTROL, val); + dev_dbg(&pdev->dev, "JMB38x: set PMOS1 val 0x%x\n", val); + } + pci_read_config_byte(pdev, PCI_CLOCK_CTL, &val); pci_write_config_byte(pdev, PCI_CLOCK_CTL, val & ~0x0f); pci_write_config_byte(pdev, PCI_CLOCK_CTL, val | 0x01); @@ -1018,8 +1030,9 @@ static void jmb38x_ms_remove(struct pci_dev *dev) } static struct pci_device_id jmb38x_ms_id_tbl [] = { - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0 }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB385_MS) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB390_MS) }, { } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ab47732d81e0..ae0dc453e3e2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2369,8 +2369,10 @@ #define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 #define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382 #define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 +#define PCI_DEVICE_ID_JMICRON_JMB385_MS 0x2388 #define PCI_DEVICE_ID_JMICRON_JMB388_SD 0x2391 #define PCI_DEVICE_ID_JMICRON_JMB388_ESD 0x2392 +#define PCI_DEVICE_ID_JMICRON_JMB390_MS 0x2393 #define PCI_VENDOR_ID_KORENIX 0x1982 #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 -- cgit v1.2.3 From d8256d487840f9c2c372f8fc615a5d378bc133f1 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 12 Jan 2011 17:01:04 -0800 Subject: memstick: avert possible race condition between idr_pre_get and idr_get_new Implement the usual pattern around idr_pre_get() and idr_get_new() to handlethe situation where another thread concurrently steals this thread's idr_pre_get() preallocation. Signed-off-by: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/core/memstick.c | 18 +++++++++++------- drivers/memstick/core/mspro_block.c | 6 ++++-- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 4303b7ef73e2..e9a3eab7b0cf 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -511,14 +511,18 @@ int memstick_add_host(struct memstick_host *host) { int rc; - if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL)) - return -ENOMEM; + while (1) { + if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL)) + return -ENOMEM; - spin_lock(&memstick_host_lock); - rc = idr_get_new(&memstick_host_idr, host, &host->id); - spin_unlock(&memstick_host_lock); - if (rc) - return rc; + spin_lock(&memstick_host_lock); + rc = idr_get_new(&memstick_host_idr, host, &host->id); + spin_unlock(&memstick_host_lock); + if (!rc) + break; + else if (rc != -EAGAIN) + return rc; + } dev_set_name(&host->dev, "memstick%u", host->id); diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 02362eccc588..a167938d4517 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1206,10 +1206,12 @@ static int mspro_block_init_disk(struct memstick_dev *card) msb->page_size = be16_to_cpu(sys_info->unit_size); - if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) + mutex_lock(&mspro_block_disk_lock); + if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) { + mutex_unlock(&mspro_block_disk_lock); return -ENOMEM; + } - mutex_lock(&mspro_block_disk_lock); rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); mutex_unlock(&mspro_block_disk_lock); -- cgit v1.2.3 From edb50b3b1d9bf6d51dc68f7f885e78285f8d6f18 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 12 Jan 2011 17:01:04 -0800 Subject: memstick: remove mspro_block_mutex mspro_block_mutex is identical in scope to mspro_block_disk_lock and therefore unnecessary. Signed-off-by: Alex Dubov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/core/mspro_block.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index a167938d4517..b11b2b89ae22 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -23,7 +23,6 @@ #define DRIVER_NAME "mspro_block" -static DEFINE_MUTEX(mspro_block_mutex); static int major; module_param(major, int, 0644); @@ -181,7 +180,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) struct mspro_block_data *msb = disk->private_data; int rc = -ENXIO; - mutex_lock(&mspro_block_mutex); mutex_lock(&mspro_block_disk_lock); if (msb && msb->card) { @@ -193,7 +191,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) } mutex_unlock(&mspro_block_disk_lock); - mutex_unlock(&mspro_block_mutex); return rc; } @@ -225,11 +222,7 @@ static int mspro_block_disk_release(struct gendisk *disk) static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode) { - int ret; - mutex_lock(&mspro_block_mutex); - ret = mspro_block_disk_release(disk); - mutex_unlock(&mspro_block_mutex); - return ret; + return mspro_block_disk_release(disk); } static int mspro_block_bd_getgeo(struct block_device *bdev, -- cgit v1.2.3 From 496fc1a68a45ae159d26331775411f6fea36d4d3 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 12 Jan 2011 17:01:05 -0800 Subject: memstick: factor out transfer initiating functionality in mspro_block.c Apart from currently used standard memstick data transfer method, Sony introduced several newer ones, to uncover full bandwidth/capacity of its Pro, HG and XC media formats. This patch lays a foundation to enable those methods as made possible by host/media capabilities. As a side effect of this patch, mspro_block_read_attributes became more streamlined and readable. [akpm@linux-foundation.org: fix printk warning] Signed-off-by: Alex Dubov Reported-by: Maxim Levitsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/core/mspro_block.c | 136 ++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index b11b2b89ae22..57b42bfc7d23 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -159,6 +159,13 @@ struct mspro_block_data { int (*mrq_handler)(struct memstick_dev *card, struct memstick_request **mrq); + + /* Default request setup function for data access method preferred by + * this host instance. + */ + void (*setup_transfer)(struct memstick_dev *card, + u64 offset, size_t length); + struct attribute_group attr_group; struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; @@ -656,14 +663,43 @@ has_int_reg: } } +/*** Transfer setup functions for different access methods. ***/ + +/** Setup data transfer request for SET_CMD TPC with arguments in card + * registers. + * + * @card Current media instance + * @offset Target data offset in bytes + * @length Required transfer length in bytes. + */ +static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset, + size_t length) +{ + struct mspro_block_data *msb = memstick_get_drvdata(card); + struct mspro_param_register param = { + .system = msb->system, + .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)), + /* ISO C90 warning precludes direct initialization for now. */ + .data_address = 0, + .tpc_param = 0 + }; + + do_div(offset, msb->page_size); + param.data_address = cpu_to_be32((uint32_t)offset); + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_transfer_data; + memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, + ¶m, sizeof(param)); +} + /*** Data transfer ***/ static int mspro_block_issue_req(struct memstick_dev *card, int chunk) { struct mspro_block_data *msb = memstick_get_drvdata(card); - sector_t t_sec; + u64 t_off; unsigned int count; - struct mspro_param_register param; try_again: while (chunk) { @@ -678,30 +714,17 @@ try_again: continue; } - t_sec = blk_rq_pos(msb->block_req) << 9; - sector_div(t_sec, msb->page_size); - + t_off = blk_rq_pos(msb->block_req); + t_off <<= 9; count = blk_rq_bytes(msb->block_req); - count /= msb->page_size; - param.system = msb->system; - param.data_count = cpu_to_be16(count); - param.data_address = cpu_to_be32((uint32_t)t_sec); - param.tpc_param = 0; + msb->setup_transfer(card, t_off, count); msb->data_dir = rq_data_dir(msb->block_req); msb->transfer_cmd = msb->data_dir == READ ? MSPRO_CMD_READ_DATA : MSPRO_CMD_WRITE_DATA; - dev_dbg(&card->dev, "data transfer: cmd %x, " - "lba %x, count %x\n", msb->transfer_cmd, - be32_to_cpu(param.data_address), count); - - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - ¶m, sizeof(param)); memstick_new_req(card->host); return 0; } @@ -956,18 +979,16 @@ try_again: static int mspro_block_read_attributes(struct memstick_dev *card) { struct mspro_block_data *msb = memstick_get_drvdata(card); - struct mspro_param_register param = { - .system = msb->system, - .data_count = cpu_to_be16(1), - .data_address = 0, - .tpc_param = 0 - }; struct mspro_attribute *attr = NULL; struct mspro_sys_attr *s_attr = NULL; unsigned char *buffer = NULL; int cnt, rc, attr_count; - unsigned int addr; - unsigned short page_count; + /* While normally physical device offsets, represented here by + * attr_offset and attr_len will be of large numeric types, we can be + * sure, that attributes are close enough to the beginning of the + * device, to save ourselves some trouble. + */ + unsigned int addr, attr_offset = 0, attr_len = msb->page_size; attr = kmalloc(msb->page_size, GFP_KERNEL); if (!attr) @@ -980,10 +1001,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, - sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); + memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1014,13 +1033,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card) } msb->attr_group.name = "media_attributes"; - buffer = kmalloc(msb->page_size, GFP_KERNEL); + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } - memcpy(buffer, (char *)attr, msb->page_size); - page_count = 1; + memcpy(buffer, (char *)attr, attr_len); for (cnt = 0; cnt < attr_count; ++cnt) { s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); @@ -1031,9 +1049,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; addr = be32_to_cpu(attr->entries[cnt].address); - rc = be32_to_cpu(attr->entries[cnt].size); + s_attr->size = be32_to_cpu(attr->entries[cnt].size); dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " - "size %x\n", cnt, attr->entries[cnt].id, addr, rc); + "size %zx\n", cnt, attr->entries[cnt].id, addr, + s_attr->size); s_attr->id = attr->entries[cnt].id; if (mspro_block_attr_name(s_attr->id)) snprintf(s_attr->name, sizeof(s_attr->name), "%s", @@ -1047,57 +1066,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card) s_attr->dev_attr.attr.mode = S_IRUGO; s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); - if (!rc) + if (!s_attr->size) continue; - s_attr->size = rc; - s_attr->data = kmalloc(rc, GFP_KERNEL); + s_attr->data = kmalloc(s_attr->size, GFP_KERNEL); if (!s_attr->data) { rc = -ENOMEM; goto out_free_buffer; } - if (((addr / msb->page_size) - == be32_to_cpu(param.data_address)) - && (((addr + rc - 1) / msb->page_size) - == be32_to_cpu(param.data_address))) { + if (((addr / msb->page_size) == (attr_offset / msb->page_size)) + && (((addr + s_attr->size - 1) / msb->page_size) + == (attr_offset / msb->page_size))) { memcpy(s_attr->data, buffer + addr % msb->page_size, - rc); + s_attr->size); continue; } - if (page_count <= (rc / msb->page_size)) { + attr_offset = (addr / msb->page_size) * msb->page_size; + + if ((attr_offset + attr_len) < (addr + s_attr->size)) { kfree(buffer); - page_count = (rc / msb->page_size) + 1; - buffer = kmalloc(page_count * msb->page_size, - GFP_KERNEL); + attr_len = (((addr + s_attr->size) / msb->page_size) + + 1 ) * msb->page_size - attr_offset; + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } } - param.system = msb->system; - param.data_count = cpu_to_be16((rc / msb->page_size) + 1); - param.data_address = cpu_to_be32(addr / msb->page_size); - param.tpc_param = 0; - - sg_init_one(&msb->req_sg[0], buffer, - be16_to_cpu(param.data_count) * msb->page_size); + sg_init_one(&msb->req_sg[0], buffer, attr_len); msb->seg_count = 1; msb->current_seg = 0; msb->current_page = 0; msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - dev_dbg(&card->dev, "reading attribute pages %x, %x\n", - be32_to_cpu(param.data_address), - be16_to_cpu(param.data_count)); + dev_dbg(&card->dev, "reading attribute range %x, %x\n", + attr_offset, attr_len); - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - (char *)¶m, sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1105,7 +1114,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) goto out_free_buffer; } - memcpy(s_attr->data, buffer + addr % msb->page_size, rc); + memcpy(s_attr->data, buffer + addr % msb->page_size, + s_attr->size); } rc = 0; @@ -1123,6 +1133,8 @@ static int mspro_block_init_card(struct memstick_dev *card) int rc = 0; msb->system = MEMSTICK_SYS_SERIAL; + msb->setup_transfer = h_mspro_block_setup_cmd; + card->reg_addr.r_offset = offsetof(struct mspro_register, status); card->reg_addr.r_length = sizeof(struct ms_status_register); card->reg_addr.w_offset = offsetof(struct mspro_register, param); -- cgit v1.2.3 From 17fecb5582962c2ca5627a51ec9ab0979fb673ef Mon Sep 17 00:00:00 2001 From: Mika Laitio Date: Wed, 12 Jan 2011 17:01:06 -0800 Subject: w1: DS2423 counter driver and documentation This is a 1-wire/w1 DS2423 slave driver for reading the values from all 4 counters available DS2423 devices by using standard w1_slave file. In ds2423 the counters are tied to ram pages 12-15 in and each of those ram-pages. Each of these counter values (and asoociated ram page values) are represented as a own line in w1_slave file. Driver has been tested on mips and x86. usage example: cat /sys/bus/w1/devices/1d-00000009b964/w1_slave 00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 00 02 00 00 00 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 00 5a 0e 5f 18 00 00 00 00 0b 28 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=408882778 00 05 00 00 00 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=YES c=5 Patch includes also the documentation. [randy.dunlap@oracle.com: fix ds2423 build, needs to select CRC16] Signed-off-by: Mika Laitio Signed-off-by: Randy Dunlap Cc: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/w1/slaves/00-INDEX | 2 + Documentation/w1/slaves/w1_ds2423 | 47 +++++++++++ drivers/w1/slaves/Kconfig | 11 +++ drivers/w1/slaves/Makefile | 1 + drivers/w1/slaves/w1_ds2423.c | 166 ++++++++++++++++++++++++++++++++++++++ drivers/w1/w1_family.h | 1 + 6 files changed, 228 insertions(+) create mode 100644 Documentation/w1/slaves/w1_ds2423 create mode 100644 drivers/w1/slaves/w1_ds2423.c (limited to 'drivers') diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX index f8101d6b07b7..75613c9ac4db 100644 --- a/Documentation/w1/slaves/00-INDEX +++ b/Documentation/w1/slaves/00-INDEX @@ -2,3 +2,5 @@ - This file w1_therm - The Maxim/Dallas Semiconductor ds18*20 temperature sensor. +w1_ds2423 + - The Maxim/Dallas Semiconductor ds2423 counter device. diff --git a/Documentation/w1/slaves/w1_ds2423 b/Documentation/w1/slaves/w1_ds2423 new file mode 100644 index 000000000000..90a65d23cf59 --- /dev/null +++ b/Documentation/w1/slaves/w1_ds2423 @@ -0,0 +1,47 @@ +Kernel driver w1_ds2423 +======================= + +Supported chips: + * Maxim DS2423 based counter devices. + +supported family codes: + W1_THERM_DS2423 0x1D + +Author: Mika Laitio + +Description +----------- + +Support is provided through the sysfs w1_slave file. Each opening and +read sequence of w1_slave file initiates the read of counters and ram +available in DS2423 pages 12 - 15. + +Result of each page is provided as an ASCII output where each counter +value and associated ram buffer is outpputed to own line. + +Each lines will contain the values of 42 bytes read from the counter and +memory page along the crc=YES or NO for indicating whether the read operation +was successfull and CRC matched. +If the operation was successfull, there is also in the end of each line +a counter value expressed as an integer after c= + +Meaning of 42 bytes represented is following: + - 1 byte from ram page + - 4 bytes for the counter value + - 4 zero bytes + - 2 bytes for crc16 which was calculated from the data read since the previous crc bytes + - 31 remaining bytes from the ram page + - crc=YES/NO indicating whether read was ok and crc matched + - c= current counter value + +example from the successfull read: +00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 +00 02 00 00 00 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 +00 29 c6 5d 18 00 00 00 00 04 37 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=408798761 +00 05 00 00 00 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=YES c=5 + +example from the read with crc errors: +00 02 00 00 00 00 00 00 00 6d 38 00 ff ff 00 00 fe ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=YES c=2 +00 02 00 00 22 00 00 00 00 e0 1f 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=NO +00 e1 61 5d 19 00 00 00 00 df 0b 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff 00 00 ff ff crc=NO +00 05 00 00 20 00 00 00 00 8d 39 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff crc=NO diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 1f51366417b9..f0c909625bd1 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -16,6 +16,17 @@ config W1_SLAVE_SMEM Say Y here if you want to connect 1-wire simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire. +config W1_SLAVE_DS2423 + tristate "Counter 1-wire device (DS2423)" + select CRC16 + help + If you enable this you can read the counter values available + in the DS2423 chipset from the w1_slave file under the + sys file system. + + Say Y here if you want to use a 1-wire + counter family device (DS2423). + config W1_SLAVE_DS2431 tristate "1kb EEPROM family support (DS2431)" help diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index f1f51f19b129..3c76350a24f7 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o +obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c new file mode 100644 index 000000000000..7a7dbe5026f1 --- /dev/null +++ b/drivers/w1/slaves/w1_ds2423.c @@ -0,0 +1,166 @@ +/* + * w1_ds2423.c + * + * Copyright (c) 2010 Mika Laitio + * + * This driver will read and write the value of 4 counters to w1_slave file in + * sys filesystem. + * Inspired by the w1_therm and w1_ds2431 drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the therms 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 "../w1.h" +#include "../w1_int.h" +#include "../w1_family.h" + +#define CRC16_VALID 0xb001 +#define CRC16_INIT 0 + +#define COUNTER_COUNT 4 +#define READ_BYTE_COUNT 42 + +static ssize_t w1_counter_read(struct device *device, + struct device_attribute *attr, char *buf); + +static struct device_attribute w1_counter_attr = + __ATTR(w1_slave, S_IRUGO, w1_counter_read, NULL); + +static ssize_t w1_counter_read(struct device *device, + struct device_attribute *attr, char *out_buf) +{ + struct w1_slave *sl = dev_to_w1_slave(device); + struct w1_master *dev = sl->master; + u8 rbuf[COUNTER_COUNT * READ_BYTE_COUNT]; + u8 wrbuf[3]; + int rom_addr; + int read_byte_count; + int result; + ssize_t c; + int ii; + int p; + int crc; + + c = PAGE_SIZE; + rom_addr = (12 << 5) + 31; + wrbuf[0] = 0xA5; + wrbuf[1] = rom_addr & 0xFF; + wrbuf[2] = rom_addr >> 8; + mutex_lock(&dev->mutex); + if (!w1_reset_select_slave(sl)) { + w1_write_block(dev, wrbuf, 3); + read_byte_count = 0; + for (p = 0; p < 4; p++) { + /* + * 1 byte for first bytes in ram page read + * 4 bytes for counter + * 4 bytes for zero bits + * 2 bytes for crc + * 31 remaining bytes from the ram page + */ + read_byte_count += w1_read_block(dev, + rbuf + (p * READ_BYTE_COUNT), READ_BYTE_COUNT); + for (ii = 0; ii < READ_BYTE_COUNT; ++ii) + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "%02x ", + rbuf[(p * READ_BYTE_COUNT) + ii]); + if (read_byte_count != (p + 1) * READ_BYTE_COUNT) { + dev_warn(device, + "w1_counter_read() returned %u bytes " + "instead of %d bytes wanted.\n", + read_byte_count, + READ_BYTE_COUNT); + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "crc=NO\n"); + } else { + if (p == 0) { + crc = crc16(CRC16_INIT, wrbuf, 3); + crc = crc16(crc, rbuf, 11); + } else { + /* + * DS2423 calculates crc from all bytes + * read after the previous crc bytes. + */ + crc = crc16(CRC16_INIT, + (rbuf + 11) + + ((p - 1) * READ_BYTE_COUNT), + READ_BYTE_COUNT); + } + if (crc == CRC16_VALID) { + result = 0; + for (ii = 4; ii > 0; ii--) { + result <<= 8; + result |= rbuf[(p * + READ_BYTE_COUNT) + ii]; + } + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "crc=YES c=%d\n", result); + } else { + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "crc=NO\n"); + } + } + } + } else { + c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error"); + } + mutex_unlock(&dev->mutex); + return PAGE_SIZE - c; +} + +static int w1_f1d_add_slave(struct w1_slave *sl) +{ + return device_create_file(&sl->dev, &w1_counter_attr); +} + +static void w1_f1d_remove_slave(struct w1_slave *sl) +{ + device_remove_file(&sl->dev, &w1_counter_attr); +} + +static struct w1_family_ops w1_f1d_fops = { + .add_slave = w1_f1d_add_slave, + .remove_slave = w1_f1d_remove_slave, +}; + +static struct w1_family w1_family_1d = { + .fid = W1_COUNTER_DS2423, + .fops = &w1_f1d_fops, +}; + +static int __init w1_f1d_init(void) +{ + return w1_register_family(&w1_family_1d); +} + +static void __exit w1_f1d_exit(void) +{ + w1_unregister_family(&w1_family_1d); +} + +module_init(w1_f1d_init); +module_exit(w1_f1d_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mika Laitio "); +MODULE_DESCRIPTION("w1 family 1d driver for DS2423, 4 counters and 4kb ram"); diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 3ca1b9298f21..f3b636d7cafe 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -30,6 +30,7 @@ #define W1_FAMILY_SMEM_01 0x01 #define W1_FAMILY_SMEM_81 0x81 #define W1_THERM_DS18S20 0x10 +#define W1_COUNTER_DS2423 0x1D #define W1_THERM_DS1822 0x22 #define W1_EEPROM_DS2433 0x23 #define W1_THERM_DS18B20 0x28 -- cgit v1.2.3 From d27a0c06ec31aadc3582f50cd7b88855922e95ae Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 12 Jan 2011 17:01:07 -0800 Subject: VMware balloon: stop locking pages when hypervisor tells us enough When hypervisor decides to decrease target balloon size while the balloon driver tries to lock pages hypervisor may respond with VMW_BALLOON_PPN_NOTNEEDED. Use this data and immediately stop reserving pages and wait for the next update cycle to fetch new target instead of continuing trying to lock pages until size of refused list grows above VMW_BALLOON_MAX_REFUSED (16) pages. As a result the driver stops bothering the hypervisor with its attempts to lock more pages that are not needed anymore. Most likely next order from hypervisor will be to reduce ballon size anyway. It is a small optimization. Signed-off-by: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/vmw_balloon.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2a1e804a71aa..4d2ea8e80140 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -45,7 +45,7 @@ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.1.1-k"); +MODULE_VERSION("1.2.1.2-k"); MODULE_ALIAS("dmi:*:svnVMware*:*"); MODULE_ALIAS("vmware_vmmemctl"); MODULE_LICENSE("GPL"); @@ -315,7 +315,8 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) * fear that guest will need it. Host may reject some pages, we need to * check the return value and maybe submit a different page. */ -static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) +static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, + unsigned int *hv_status) { unsigned long status, dummy; u32 pfn32; @@ -326,7 +327,7 @@ static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) STATS_INC(b->stats.lock); - status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); + *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); if (vmballoon_check_status(b, status)) return true; @@ -410,6 +411,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) { struct page *page; gfp_t flags; + unsigned int hv_status; bool locked = false; do { @@ -429,11 +431,12 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) } /* inform monitor */ - locked = vmballoon_send_lock_page(b, page_to_pfn(page)); + locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); if (!locked) { STATS_INC(b->stats.refused_alloc); - if (b->reset_required) { + if (hv_status == VMW_BALLOON_ERROR_RESET || + hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) { __free_page(page); return -EIO; } -- cgit v1.2.3 From 264b795fbd055f57b445eb3d58cfc51d6b10b22e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 12 Jan 2011 17:01:11 -0800 Subject: ramoops: fix types, remove typecasts Cc: Ahmed S. Darwish Cc: Kyungmin Park Cc: Marco Stornelli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ramoops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index eeec5758f9c4..1a9f5f6d6ac5 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -30,7 +30,7 @@ #define RAMOOPS_KERNMSG_HDR "====" -#define RECORD_SIZE 4096 +#define RECORD_SIZE 4096UL static ulong mem_address; module_param(mem_address, ulong, 0400); @@ -77,7 +77,7 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, if (reason == KMSG_DUMP_OOPS && !dump_oops) return; - buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE)); + buf = cxt->virt_addr + (cxt->count * RECORD_SIZE); buf_orig = buf; memset(buf, '\0', RECORD_SIZE); @@ -88,8 +88,8 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, buf += res; hdr_size = buf - buf_orig; - l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - hdr_size)); - l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - hdr_size) - l2_cpy); + l2_cpy = min(l2, RECORD_SIZE - hdr_size); + l1_cpy = min(l1, RECORD_SIZE - hdr_size - l2_cpy); s2_start = l2 - l2_cpy; s1_start = l1 - l1_cpy; -- cgit v1.2.3 From a76150302d6e7ebc43e1a1ddaee7fd51db8da3b3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Jan 2011 17:04:08 +0000 Subject: drm/i915: Add a module option to override the use of SSC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to workaround the issue with LVDS not working on the Lenovo U160 apparently due to using the wrong SSC frequency, add an option to disable SSC. Suggested-by: Lukács, Árpád Bugzillla: https://bugs.freedesktop.org/show_bug.cgi?id=32748 Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_drv.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_bios.c | 17 ++++++----------- drivers/gpu/drm/i915/intel_display.c | 17 +++++++++++------ 4 files changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0de75a23f8e7..72fea2bcfc4f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,6 +49,9 @@ module_param_named(powersave, i915_powersave, int, 0600); unsigned int i915_lvds_downclock = 0; module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); +unsigned int i915_panel_use_ssc = 1; +module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); + bool i915_try_reset = true; module_param_named(reset, i915_try_reset, bool, 0600); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 385fc7ec39d3..5969f46ac2d6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -954,6 +954,7 @@ extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; extern unsigned int i915_powersave; extern unsigned int i915_lvds_downclock; +extern unsigned int i915_panel_use_ssc; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index b0b1200ed650..0b44956c336b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -264,17 +264,12 @@ parse_general_features(struct drm_i915_private *dev_priv, dev_priv->int_crt_support = general->int_crt_support; dev_priv->lvds_use_ssc = general->enable_ssc; - if (dev_priv->lvds_use_ssc) { - if (IS_I85X(dev)) - dev_priv->lvds_ssc_freq = - general->ssc_freq ? 66 : 48; - else if (IS_GEN5(dev) || IS_GEN6(dev)) - dev_priv->lvds_ssc_freq = - general->ssc_freq ? 100 : 120; - else - dev_priv->lvds_ssc_freq = - general->ssc_freq ? 100 : 96; - } + if (IS_I85X(dev)) + dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48; + else if (IS_GEN5(dev) || IS_GEN6(dev)) + dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 120; + else + dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96; } } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 25d96889d7d2..98967f3b7724 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3822,6 +3822,11 @@ static void intel_update_watermarks(struct drm_device *dev) sr_hdisplay, sr_htotal, pixel_size); } +static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) +{ + return dev_priv->lvds_use_ssc && i915_panel_use_ssc; +} + static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -3884,7 +3889,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) { + if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { refclk = dev_priv->lvds_ssc_freq * 1000; DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", refclk / 1000); @@ -4059,7 +4064,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, udelay(200); if (has_edp_encoder) { - if (dev_priv->lvds_use_ssc) { + if (intel_panel_use_ssc(dev_priv)) { temp |= DREF_SSC1_ENABLE; I915_WRITE(PCH_DREF_CONTROL, temp); @@ -4070,13 +4075,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Enable CPU source on CPU attached eDP */ if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { - if (dev_priv->lvds_use_ssc) + if (intel_panel_use_ssc(dev_priv)) temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; else temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; } else { /* Enable SSC on PCH eDP if needed */ - if (dev_priv->lvds_use_ssc) { + if (intel_panel_use_ssc(dev_priv)) { DRM_ERROR("enabling SSC on PCH\n"); temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; } @@ -4104,7 +4109,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int factor = 21; if (is_lvds) { - if ((dev_priv->lvds_use_ssc && + if ((intel_panel_use_ssc(dev_priv) && dev_priv->lvds_ssc_freq == 100) || (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) factor = 25; @@ -4183,7 +4188,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* XXX: just matching BIOS for now */ /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ dpll |= 3; - else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) + else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else dpll |= PLL_REF_INPUT_DREFCLK; -- cgit v1.2.3 From c37d9a5de94a6fe60a756af350cd21aa9bbbc8a1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Jan 2011 20:33:01 +0000 Subject: drm/i915: Fix error handler to capture the first batch after the seqno Whilst we had no older batches on the active list, everything was fine. However, if the GPU is free running and the requests are only being reaped by the periodic retirer, than the current seqno may not be at the start of the list. In this case we need to select the first batch after the last seqno written by the gpu and not inclusive of the seqno. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e418e8bb61e6..b8e509ae065e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -720,7 +720,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, if (obj->ring != ring) continue; - if (!i915_seqno_passed(obj->last_rendering_seqno, seqno)) + if (i915_seqno_passed(seqno, obj->last_rendering_seqno)) continue; if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) -- cgit v1.2.3 From dd6864a4edb9b2d0055a7f30e17cbc521098b1be Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Jan 2011 23:49:13 +0000 Subject: drm/i915/execbuffer: Reorder relocations to match new object order On the fault path, commit 6fe4f140 introduction a regression whereby it changed the sequence of the objects but continued to use the original ordering of relocation entries. The result was that incorrect GTT offsets were being fed into the execbuffer causing lots of misrendering and potential hangs. Reported-by: Linus Torvalds Tested-by: Linus Torvalds Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index e69834341ef0..6b34e98a1270 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -636,6 +636,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, { struct drm_i915_gem_relocation_entry *reloc; struct drm_i915_gem_object *obj; + int *reloc_offset; int i, total, ret; /* We may process another execbuffer during the unlock... */ @@ -653,8 +654,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, for (i = 0; i < count; i++) total += exec[i].relocation_count; + reloc_offset = drm_malloc_ab(count, sizeof(*reloc_offset)); reloc = drm_malloc_ab(total, sizeof(*reloc)); - if (reloc == NULL) { + if (reloc == NULL || reloc_offset == NULL) { + drm_free_large(reloc); + drm_free_large(reloc_offset); mutex_lock(&dev->struct_mutex); return -ENOMEM; } @@ -672,6 +676,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; } + reloc_offset[i] = total; total += exec[i].relocation_count; } @@ -705,17 +710,14 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, if (ret) goto err; - total = 0; list_for_each_entry(obj, objects, exec_list) { + int offset = obj->exec_entry - exec; obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, - reloc + total); + reloc + reloc_offset[offset]); if (ret) goto err; - - total += exec->relocation_count; - exec++; } /* Leave the user relocations as are, this is the painfully slow path, @@ -726,6 +728,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, err: drm_free_large(reloc); + drm_free_large(reloc_offset); return ret; } -- cgit v1.2.3 From 595dad76a0d213adc3dbe4f463f7887e905082b9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 13 Jan 2011 11:03:48 +0000 Subject: drm/i915/execbuffer: Clear domains before beginning reloc processing After reordering the sequence of relocating objects, commit 6fe4f1404, we can no longer rely on seeing all reloc targets prior to performing the relocation. As a result we were ignoring the need to flush objects from the render cache and invalidate the sampler caches, resulting in rendering glitches. So we need to clear the relocation domains earlier. Reported-by: Linus Torvalds Tested-by: Linus Torvalds Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6b34e98a1270..8db88e34ef7b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -464,8 +464,6 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, int ret; list_for_each_entry(obj, objects, exec_list) { - obj->base.pending_read_domains = 0; - obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object(obj, eb); if (ret) return ret; @@ -505,6 +503,9 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, list_move(&obj->exec_list, &ordered_objects); else list_move_tail(&obj->exec_list, &ordered_objects); + + obj->base.pending_read_domains = 0; + obj->base.pending_write_domain = 0; } list_splice(&ordered_objects, objects); @@ -712,8 +713,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, list_for_each_entry(obj, objects, exec_list) { int offset = obj->exec_entry - exec; - obj->base.pending_read_domains = 0; - obj->base.pending_write_domain = 0; ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, reloc + reloc_offset[offset]); if (ret) -- cgit v1.2.3 From c217649bf2d60ac119afd71d938278cffd55962b Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 13 Jan 2011 19:53:46 +0000 Subject: dm: dont take i_mutex to change device size No longer needlessly hold md->bdev->bd_inode->i_mutex when changing the size of a DM device. This additional locking is unnecessary because i_size_write() is already protected by the existing critical section in dm_swap_table(). DM already has a reference on md->bdev so the associated bd_inode may be changed without lifetime concerns. A negative side-effect of having held md->bdev->bd_inode->i_mutex was that a concurrent DM device resize and flush (via fsync) would deadlock. Dropping md->bdev->bd_inode->i_mutex eliminates this potential for deadlock. The following reproducer no longer deadlocks: https://www.redhat.com/archives/dm-devel/2009-July/msg00284.html Signed-off-by: Mike Snitzer Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon Cc: stable@kernel.org --- drivers/md/dm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f48a2f359ac4..4ef066a3090f 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1992,13 +1992,14 @@ static void event_callback(void *context) wake_up(&md->eventq); } +/* + * Protected by md->suspend_lock obtained by dm_swap_table(). + */ static void __set_size(struct mapped_device *md, sector_t size) { set_capacity(md->disk, size); - mutex_lock(&md->bdev->bd_inode->i_mutex); i_size_write(md->bdev->bd_inode, (loff_t)size << SECTOR_SHIFT); - mutex_unlock(&md->bdev->bd_inode->i_mutex); } /* -- cgit v1.2.3 From 09c9d4c9b6a2b5909ae3c6265e4cd3820b636863 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 13 Jan 2011 19:59:46 +0000 Subject: dm mpath: disable blk_abort_queue Revert commit 224cb3e981f1b2f9f93dbd49eaef505d17d894c2 dm: Call blk_abort_queue on failed paths Multipath began to use blk_abort_queue() to allow for lower latency path deactivation. This was found to cause list corruption: the cmd gets blk_abort_queued/timedout run on it and the scsi eh somehow is able to complete and run scsi_queue_insert while scsi_request_fn is still trying to process the request. https://www.redhat.com/archives/dm-devel/2010-November/msg00085.html Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon Cc: Mike Anderson Cc: Mike Christie Cc: stable@kernel.org --- drivers/md/dm-mpath.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 487ecda90ad4..406091f9692b 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -33,7 +33,6 @@ struct pgpath { unsigned fail_count; /* Cumulative failure count */ struct dm_path path; - struct work_struct deactivate_path; struct work_struct activate_path; }; @@ -116,7 +115,6 @@ static struct workqueue_struct *kmultipathd, *kmpath_handlerd; static void process_queued_ios(struct work_struct *work); static void trigger_event(struct work_struct *work); static void activate_path(struct work_struct *work); -static void deactivate_path(struct work_struct *work); /*----------------------------------------------- @@ -129,7 +127,6 @@ static struct pgpath *alloc_pgpath(void) if (pgpath) { pgpath->is_active = 1; - INIT_WORK(&pgpath->deactivate_path, deactivate_path); INIT_WORK(&pgpath->activate_path, activate_path); } @@ -141,14 +138,6 @@ static void free_pgpath(struct pgpath *pgpath) kfree(pgpath); } -static void deactivate_path(struct work_struct *work) -{ - struct pgpath *pgpath = - container_of(work, struct pgpath, deactivate_path); - - blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue); -} - static struct priority_group *alloc_priority_group(void) { struct priority_group *pg; @@ -995,7 +984,6 @@ static int fail_path(struct pgpath *pgpath) pgpath->path.dev->name, m->nr_valid_paths); schedule_work(&m->trigger_event); - queue_work(kmultipathd, &pgpath->deactivate_path); out: spin_unlock_irqrestore(&m->lock, flags); -- cgit v1.2.3 From d9bf0b508ddfe19883b982b29a03c02ccbf53806 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 13 Jan 2011 19:59:47 +0000 Subject: dm io: remove BIO_RW_SYNCIO flag from kcopyd Remove the REQ_SYNC flag to improve write throughput when writing to the origin with a snapshot on the same device (using the CFQ I/O scheduler). Sequential write throughput (chunksize of 4k, 32k, 512k) unpatched: 8.5, 8.6, 9.3 MB/s patched: 15.2, 18.5, 17.5 MB/s Snapshot exception reallocations are triggered by writes that are usually async, so mark the associated dm_io_request as async as well. This helps when using the CFQ I/O scheduler because it has separate queues for sync and async I/O. Async is optimized for throughput; sync for latency. With this change we're consciously favoring throughput over latency. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-kcopyd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index d8587bac5682..5ad9231c8700 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -345,7 +345,7 @@ static int run_io_job(struct kcopyd_job *job) { int r; struct dm_io_request io_req = { - .bi_rw = job->rw | REQ_SYNC | REQ_UNPLUG, + .bi_rw = job->rw | REQ_UNPLUG, .mem.type = DM_IO_PAGE_LIST, .mem.ptr.pl = job->pages, .mem.offset = job->offset, -- cgit v1.2.3 From 84c89557a302e18414a011cc52b1abd034860743 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 13 Jan 2011 19:59:47 +0000 Subject: dm ioctl: allow rename to fill empty uuid Allow the uuid of a mapped device to be set after device creation. Previously the uuid (which is optional) could only be set by DM_DEV_CREATE. If no uuid was supplied it could not be set later. Sometimes it's necessary to create the device before the uuid is known, and in such cases the uuid must be filled in after the creation. This patch extends DM_DEV_RENAME to accept a uuid accompanied by a new flag DM_UUID_FLAG. This can only be done once and if no uuid was previously supplied. It cannot be used to change an existing uuid. DM_VERSION_MINOR is also bumped to 19 to indicate this interface extension is available. Signed-off-by: Peter Jones Signed-off-by: Jonathan Brassow Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 103 +++++++++++++++++++++++++++++++++++------------ include/linux/dm-ioctl.h | 12 ++++-- 2 files changed, 87 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 4b54618b4159..f3481d922206 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -295,19 +295,55 @@ retry: DMWARN("remove_all left %d open device(s)", dev_skipped); } +/* + * Set the uuid of a hash_cell that isn't already set. + */ +static void __set_cell_uuid(struct hash_cell *hc, char *new_uuid) +{ + mutex_lock(&dm_hash_cells_mutex); + hc->uuid = new_uuid; + mutex_unlock(&dm_hash_cells_mutex); + + list_add(&hc->uuid_list, _uuid_buckets + hash_str(new_uuid)); +} + +/* + * Changes the name of a hash_cell and returns the old name for + * the caller to free. + */ +static char *__change_cell_name(struct hash_cell *hc, char *new_name) +{ + char *old_name; + + /* + * Rename and move the name cell. + */ + list_del(&hc->name_list); + old_name = hc->name; + + mutex_lock(&dm_hash_cells_mutex); + hc->name = new_name; + mutex_unlock(&dm_hash_cells_mutex); + + list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + + return old_name; +} + static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, const char *new) { - char *new_name, *old_name; + char *new_data, *old_name = NULL; struct hash_cell *hc; struct dm_table *table; struct mapped_device *md; + unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0; /* * duplicate new. */ - new_name = kstrdup(new, GFP_KERNEL); - if (!new_name) + new_data = kstrdup(new, GFP_KERNEL); + if (!new_data) return ERR_PTR(-ENOMEM); down_write(&_hash_lock); @@ -315,13 +351,19 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, /* * Is new free ? */ - hc = __get_name_cell(new); + if (change_uuid) + hc = __get_uuid_cell(new); + else + hc = __get_name_cell(new); + if (hc) { - DMWARN("asked to rename to an already-existing name %s -> %s", + DMWARN("Unable to change %s on mapped device %s to one that " + "already exists: %s", + change_uuid ? "uuid" : "name", param->name, new); dm_put(hc->md); up_write(&_hash_lock); - kfree(new_name); + kfree(new_data); return ERR_PTR(-EBUSY); } @@ -330,22 +372,30 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, */ hc = __get_name_cell(param->name); if (!hc) { - DMWARN("asked to rename a non-existent device %s -> %s", - param->name, new); + DMWARN("Unable to rename non-existent device, %s to %s%s", + param->name, change_uuid ? "uuid " : "", new); up_write(&_hash_lock); - kfree(new_name); + kfree(new_data); return ERR_PTR(-ENXIO); } /* - * rename and move the name cell. + * Does this device already have a uuid? */ - list_del(&hc->name_list); - old_name = hc->name; - mutex_lock(&dm_hash_cells_mutex); - hc->name = new_name; - mutex_unlock(&dm_hash_cells_mutex); - list_add(&hc->name_list, _name_buckets + hash_str(new_name)); + if (change_uuid && hc->uuid) { + DMWARN("Unable to change uuid of mapped device %s to %s " + "because uuid is already set to %s", + param->name, new, hc->uuid); + dm_put(hc->md); + up_write(&_hash_lock); + kfree(new_data); + return ERR_PTR(-EINVAL); + } + + if (change_uuid) + __set_cell_uuid(hc, new_data); + else + old_name = __change_cell_name(hc, new_data); /* * Wake up any dm event waiters. @@ -774,21 +824,24 @@ static int invalid_str(char *str, void *end) static int dev_rename(struct dm_ioctl *param, size_t param_size) { int r; - char *new_name = (char *) param + param->data_start; + char *new_data = (char *) param + param->data_start; struct mapped_device *md; + unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0; - if (new_name < param->data || - invalid_str(new_name, (void *) param + param_size) || - strlen(new_name) > DM_NAME_LEN - 1) { - DMWARN("Invalid new logical volume name supplied."); + if (new_data < param->data || + invalid_str(new_data, (void *) param + param_size) || + strlen(new_data) > (change_uuid ? DM_UUID_LEN - 1 : DM_NAME_LEN - 1)) { + DMWARN("Invalid new mapped device name or uuid string supplied."); return -EINVAL; } - r = check_name(new_name); - if (r) - return r; + if (!change_uuid) { + r = check_name(new_data); + if (r) + return r; + } - md = dm_hash_rename(param, new_name); + md = dm_hash_rename(param, new_data); if (IS_ERR(md)) return PTR_ERR(md); diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 49eab360d5d4..e453e1174ae1 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -44,7 +44,7 @@ * Remove a device, destroy any tables. * * DM_DEV_RENAME: - * Rename a device. + * Rename a device or set its uuid if none was previously supplied. * * DM_SUSPEND: * This performs both suspend and resume, depending which flag is @@ -267,9 +267,9 @@ enum { #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 18 +#define DM_VERSION_MINOR 19 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2010-06-29)" +#define DM_VERSION_EXTRA "-ioctl (2010-10-14)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ @@ -322,4 +322,10 @@ enum { */ #define DM_UEVENT_GENERATED_FLAG (1 << 13) /* Out */ +/* + * If set, rename changes the uuid not the name. Only permitted + * if no uuid was previously supplied: an existing uuid cannot be changed. + */ +#define DM_UUID_FLAG (1 << 14) /* In */ + #endif /* _LINUX_DM_IOCTL_H */ -- cgit v1.2.3 From 5fc2ffeabb9ee0fc0e71ff16b49f34f0ed3d05b4 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 13 Jan 2011 19:59:48 +0000 Subject: dm raid1: support discard Enable discard support in the DM mirror target. Also change an existing use of 'bvec' to 'addr' in the union. Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-raid1.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 19a59b041c27..c87756eb7a21 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -261,7 +261,7 @@ static int mirror_flush(struct dm_target *ti) struct dm_io_request io_req = { .bi_rw = WRITE_FLUSH, .mem.type = DM_IO_KMEM, - .mem.ptr.bvec = NULL, + .mem.ptr.addr = NULL, .client = ms->io_client, }; @@ -637,6 +637,12 @@ static void do_write(struct mirror_set *ms, struct bio *bio) .client = ms->io_client, }; + if (bio->bi_rw & REQ_DISCARD) { + io_req.bi_rw |= REQ_DISCARD; + io_req.mem.type = DM_IO_KMEM; + io_req.mem.ptr.addr = NULL; + } + for (i = 0, m = ms->mirror; i < ms->nr_mirrors; i++, m++) map_region(dest++, m, bio); @@ -670,7 +676,8 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) bio_list_init(&requeue); while ((bio = bio_list_pop(writes))) { - if (bio->bi_rw & REQ_FLUSH) { + if ((bio->bi_rw & REQ_FLUSH) || + (bio->bi_rw & REQ_DISCARD)) { bio_list_add(&sync, bio); continue; } @@ -1076,6 +1083,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->private = ms; ti->split_io = dm_rh_get_region_size(ms->rh); ti->num_flush_requests = 1; + ti->num_discard_requests = 1; ms->kmirrord_wq = create_singlethread_workqueue("kmirrord"); if (!ms->kmirrord_wq) { -- cgit v1.2.3 From 4a1aeb98297e17f4e0a8cdda919e63bf528b2e5d Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:48 +0000 Subject: dm: remove dm_mutex after bkl conversion This patch replaces dm_mutex with _minor_lock in dm_blk_close() and then removes it. During the BKL conversion, commit 6e9624b8caec290d28b4c6d9ec75749df6372b87 (block: push down BKL into .open and .release) pushed lock_kernel() down into dm_blk_open/close calls. Commit 2a48fc0ab24241755dc93bfd4f01d68efab47f5a (block: autoconvert trivial BKL users to private mutex) converted it to a local mutex, but _minor_lock is sufficient. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4ef066a3090f..0de692176ad4 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -32,7 +32,6 @@ #define DM_COOKIE_ENV_VAR_NAME "DM_COOKIE" #define DM_COOKIE_LENGTH 24 -static DEFINE_MUTEX(dm_mutex); static const char *_name = DM_NAME; static unsigned int major = 0; @@ -328,7 +327,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode) { struct mapped_device *md; - mutex_lock(&dm_mutex); spin_lock(&_minor_lock); md = bdev->bd_disk->private_data; @@ -346,7 +344,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode) out: spin_unlock(&_minor_lock); - mutex_unlock(&dm_mutex); return md ? 0 : -ENXIO; } @@ -355,10 +352,12 @@ static int dm_blk_close(struct gendisk *disk, fmode_t mode) { struct mapped_device *md = disk->private_data; - mutex_lock(&dm_mutex); + spin_lock(&_minor_lock); + atomic_dec(&md->open_count); dm_put(md); - mutex_unlock(&dm_mutex); + + spin_unlock(&_minor_lock); return 0; } -- cgit v1.2.3 From 69a8cfcda21017364df1c21b720daf304b5598a6 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:49 +0000 Subject: dm crypt: set key size early Simplify key size verification (hexadecimal string) and set key size early in constructor. (Patch required by later changes.) Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-crypt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index d5b0e4c0e702..4c4408a2602f 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -973,15 +973,15 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size) static int crypt_set_key(struct crypt_config *cc, char *key) { - unsigned key_size = strlen(key) >> 1; - - if (cc->key_size && cc->key_size != key_size) + /* The key size may not be changed. */ + if (cc->key_size != (strlen(key) >> 1)) return -EINVAL; - cc->key_size = key_size; /* initial settings */ + /* Hyphen (which gives a key_size of zero) means there is no key. */ + if (!cc->key_size && strcmp(key, "-")) + return -EINVAL; - if ((!key_size && strcmp(key, "-")) || - (key_size && crypt_decode_key(cc->key, key, key_size) < 0)) + if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) return -EINVAL; set_bit(DM_CRYPT_KEY_VALID, &cc->flags); @@ -1194,6 +1194,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->error = "Cannot allocate encryption context"; return -ENOMEM; } + cc->key_size = key_size; ti->private = cc; ret = crypt_ctr_cipher(ti, argv[0], argv[1]); -- cgit v1.2.3 From 4a038677df4da84e42fd68b5ab2dfa4d82baa444 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 13 Jan 2011 19:59:49 +0000 Subject: dm log userspace: trap all failed log construction errors When constructing a mirror log, it is possible for the initial request to fail for other reasons besides -ESRCH. These must be handled too. Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log-userspace-base.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 1ed0094f064b..1c25ad3d02a2 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -181,8 +181,11 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, ctr_str, str_size, NULL, NULL); - if (r == -ESRCH) { - DMERR("Userspace log server not found"); + if (r < 0) { + if (r == -ESRCH) + DMERR("Userspace log server not found"); + else + DMERR("Userspace log server failed to create log"); goto out; } @@ -214,10 +217,9 @@ out: static void userspace_dtr(struct dm_dirty_log *log) { - int r; struct log_c *lc = log->context; - r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, + (void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, NULL, 0, NULL, NULL); -- cgit v1.2.3 From 8d35d3e37eed884ba15229a146df846f399909b4 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 13 Jan 2011 19:59:50 +0000 Subject: dm kcopyd: delay unplugging Make kcopyd merge more I/O requests by using device unplugging. Without this patch, each I/O request is dispatched separately to the device. If the device supports tagged queuing, there are many small requests sent to the device. To improve performance, this patch will batch as many requests as possible, allowing the queue to merge consecutive requests, and send them to the device at once. In my tests (15k SCSI disk), this patch improves sequential write throughput: Sequential write throughput (chunksize of 4k, 32k, 512k) unpatched: 15.2, 18.5, 17.5 MB/s patched: 14.4, 22.6, 23.0 MB/s In most common uses (snapshot or two-way mirror), kcopyd is only used for two devices, one for reading and the other for writing, thus this optimization is implemented only for two devices. The optimization may be extended to n-way mirrors with some code complexity increase. We keep track of two block devices to unplug (one for read and the other for write) and unplug them when exiting "do_work" thread. If there are more devices used (in theory it could happen, in practice it is rare), we unplug immediately. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-kcopyd.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 5ad9231c8700..dad32f8bce7d 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -37,6 +37,13 @@ struct dm_kcopyd_client { unsigned int nr_pages; unsigned int nr_free_pages; + /* + * Block devices to unplug. + * Non-NULL pointer means that a block device has some pending requests + * and needs to be unplugged. + */ + struct block_device *unplug[2]; + struct dm_io_client *io_client; wait_queue_head_t destroyq; @@ -308,6 +315,31 @@ static int run_complete_job(struct kcopyd_job *job) return 0; } +/* + * Unplug the block device at the specified index. + */ +static void unplug(struct dm_kcopyd_client *kc, int rw) +{ + if (kc->unplug[rw] != NULL) { + blk_unplug(bdev_get_queue(kc->unplug[rw])); + kc->unplug[rw] = NULL; + } +} + +/* + * Prepare block device unplug. If there's another device + * to be unplugged at the same array index, we unplug that + * device first. + */ +static void prepare_unplug(struct dm_kcopyd_client *kc, int rw, + struct block_device *bdev) +{ + if (likely(kc->unplug[rw] == bdev)) + return; + unplug(kc, rw); + kc->unplug[rw] = bdev; +} + static void complete_io(unsigned long error, void *context) { struct kcopyd_job *job = (struct kcopyd_job *) context; @@ -345,7 +377,7 @@ static int run_io_job(struct kcopyd_job *job) { int r; struct dm_io_request io_req = { - .bi_rw = job->rw | REQ_UNPLUG, + .bi_rw = job->rw, .mem.type = DM_IO_PAGE_LIST, .mem.ptr.pl = job->pages, .mem.offset = job->offset, @@ -354,10 +386,16 @@ static int run_io_job(struct kcopyd_job *job) .client = job->kc->io_client, }; - if (job->rw == READ) + if (job->rw == READ) { r = dm_io(&io_req, 1, &job->source, NULL); - else + prepare_unplug(job->kc, READ, job->source.bdev); + } else { + if (job->num_dests > 1) + io_req.bi_rw |= REQ_UNPLUG; r = dm_io(&io_req, job->num_dests, job->dests, NULL); + if (!(io_req.bi_rw & REQ_UNPLUG)) + prepare_unplug(job->kc, WRITE, job->dests[0].bdev); + } return r; } @@ -435,10 +473,18 @@ static void do_work(struct work_struct *work) * Pages jobs when successful will jump onto the io jobs * list. io jobs call wake when they complete and it all * starts again. + * + * Note that io_jobs add block devices to the unplug array, + * this array is cleared with "unplug" calls. It is thus + * forbidden to run complete_jobs after io_jobs and before + * unplug because the block device could be destroyed in + * job completion callback. */ process_jobs(&kc->complete_jobs, kc, run_complete_job); process_jobs(&kc->pages_jobs, kc, run_pages_job); process_jobs(&kc->io_jobs, kc, run_io_job); + unplug(kc, READ); + unplug(kc, WRITE); } /* @@ -619,6 +665,8 @@ int dm_kcopyd_client_create(unsigned int nr_pages, INIT_LIST_HEAD(&kc->io_jobs); INIT_LIST_HEAD(&kc->pages_jobs); + memset(kc->unplug, 0, sizeof(kc->unplug)); + kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache); if (!kc->job_pool) goto bad_slab; -- cgit v1.2.3 From 909cc4fb48dd9870f6ebe4bd32cfbe37c102df62 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 13 Jan 2011 19:59:50 +0000 Subject: dm log userspace: split flush queue Split the 'flush_list', which contained a mix of both 'mark' and 'clear' requests, into two distinct lists ('mark_list' and 'clear_list'). The device mapper log implementations (used by various DM targets) are allowed to cache 'mark' and 'clear' requests until a 'flush' is received. Until now, these cached requests were kept in the same list. They will now be put into distinct lists to facilitate group processing of these requests (in the next patch). Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log-userspace-base.c | 41 +++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 1c25ad3d02a2..767adf300fa5 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -37,8 +37,15 @@ struct log_c { */ uint64_t in_sync_hint; + /* + * Mark and clear requests are held until a flush is issued + * so that we can group, and thereby limit, the amount of + * network traffic between kernel and userspace. The 'flush_lock' + * is used to protect these lists. + */ spinlock_t flush_lock; - struct list_head flush_list; /* only for clear and mark requests */ + struct list_head mark_list; + struct list_head clear_list; }; static mempool_t *flush_entry_pool; @@ -169,7 +176,8 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, strncpy(lc->uuid, argv[0], DM_UUID_LEN); spin_lock_init(&lc->flush_lock); - INIT_LIST_HEAD(&lc->flush_list); + INIT_LIST_HEAD(&lc->mark_list); + INIT_LIST_HEAD(&lc->clear_list); str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str); if (str_size < 0) { @@ -362,14 +370,16 @@ static int userspace_flush(struct dm_dirty_log *log) int r = 0; unsigned long flags; struct log_c *lc = log->context; - LIST_HEAD(flush_list); + LIST_HEAD(mark_list); + LIST_HEAD(clear_list); struct flush_entry *fe, *tmp_fe; spin_lock_irqsave(&lc->flush_lock, flags); - list_splice_init(&lc->flush_list, &flush_list); + list_splice_init(&lc->mark_list, &mark_list); + list_splice_init(&lc->clear_list, &clear_list); spin_unlock_irqrestore(&lc->flush_lock, flags); - if (list_empty(&flush_list)) + if (list_empty(&mark_list) && list_empty(&clear_list)) return 0; /* @@ -379,7 +389,16 @@ static int userspace_flush(struct dm_dirty_log *log) * do it one by one. */ - list_for_each_entry(fe, &flush_list, list) { + list_for_each_entry(fe, &mark_list, list) { + r = userspace_do_request(lc, lc->uuid, fe->type, + (char *)&fe->region, + sizeof(fe->region), + NULL, NULL); + if (r) + goto fail; + } + + list_for_each_entry(fe, &clear_list, list) { r = userspace_do_request(lc, lc->uuid, fe->type, (char *)&fe->region, sizeof(fe->region), @@ -397,7 +416,11 @@ fail: * Calling code will receive an error and will know that * the log facility has failed. */ - list_for_each_entry_safe(fe, tmp_fe, &flush_list, list) { + list_for_each_entry_safe(fe, tmp_fe, &mark_list, list) { + list_del(&fe->list); + mempool_free(fe, flush_entry_pool); + } + list_for_each_entry_safe(fe, tmp_fe, &clear_list, list) { list_del(&fe->list); mempool_free(fe, flush_entry_pool); } @@ -427,7 +450,7 @@ static void userspace_mark_region(struct dm_dirty_log *log, region_t region) spin_lock_irqsave(&lc->flush_lock, flags); fe->type = DM_ULOG_MARK_REGION; fe->region = region; - list_add(&fe->list, &lc->flush_list); + list_add(&fe->list, &lc->mark_list); spin_unlock_irqrestore(&lc->flush_lock, flags); return; @@ -464,7 +487,7 @@ static void userspace_clear_region(struct dm_dirty_log *log, region_t region) spin_lock_irqsave(&lc->flush_lock, flags); fe->type = DM_ULOG_CLEAR_REGION; fe->region = region; - list_add(&fe->list, &lc->flush_list); + list_add(&fe->list, &lc->clear_list); spin_unlock_irqrestore(&lc->flush_lock, flags); return; -- cgit v1.2.3 From 085ae0651b2791f3a430ddb76da92925b9952e13 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 13 Jan 2011 19:59:51 +0000 Subject: dm log userspace: group clear and mark requests Allow the device-mapper log's 'mark' and 'clear' requests to be grouped and processed in a batch. This can significantly reduce the amount of traffic going between the kernel and userspace (where the processing daemon resides). Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log-userspace-base.c | 102 ++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 767adf300fa5..31e1687e7bf6 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -18,6 +18,14 @@ struct flush_entry { struct list_head list; }; +/* + * This limit on the number of mark and clear request is, to a degree, + * arbitrary. However, there is some basis for the choice in the limits + * imposed on the size of data payload by dm-log-userspace-transfer.c: + * dm_consult_userspace(). + */ +#define MAX_FLUSH_GROUP_COUNT 32 + struct log_c { struct dm_target *ti; uint32_t region_size; @@ -348,6 +356,71 @@ static int userspace_in_sync(struct dm_dirty_log *log, region_t region, return (r) ? 0 : (int)in_sync; } +static int flush_one_by_one(struct log_c *lc, struct list_head *flush_list) +{ + int r = 0; + struct flush_entry *fe; + + list_for_each_entry(fe, flush_list, list) { + r = userspace_do_request(lc, lc->uuid, fe->type, + (char *)&fe->region, + sizeof(fe->region), + NULL, NULL); + if (r) + break; + } + + return r; +} + +static int flush_by_group(struct log_c *lc, struct list_head *flush_list) +{ + int r = 0; + int count; + uint32_t type = 0; + struct flush_entry *fe, *tmp_fe; + LIST_HEAD(tmp_list); + uint64_t group[MAX_FLUSH_GROUP_COUNT]; + + /* + * Group process the requests + */ + while (!list_empty(flush_list)) { + count = 0; + + list_for_each_entry_safe(fe, tmp_fe, flush_list, list) { + group[count] = fe->region; + count++; + + list_del(&fe->list); + list_add(&fe->list, &tmp_list); + + type = fe->type; + if (count >= MAX_FLUSH_GROUP_COUNT) + break; + } + + r = userspace_do_request(lc, lc->uuid, type, + (char *)(group), + count * sizeof(uint64_t), + NULL, NULL); + if (r) { + /* Group send failed. Attempt one-by-one. */ + list_splice_init(&tmp_list, flush_list); + r = flush_one_by_one(lc, flush_list); + break; + } + } + + /* + * Must collect flush_entrys that were successfully processed + * as a group so that they will be free'd by the caller. + */ + list_splice_init(&tmp_list, flush_list); + + return r; +} + /* * userspace_flush * @@ -382,30 +455,13 @@ static int userspace_flush(struct dm_dirty_log *log) if (list_empty(&mark_list) && list_empty(&clear_list)) return 0; - /* - * FIXME: Count up requests, group request types, - * allocate memory to stick all requests in and - * send to server in one go. Failing the allocation, - * do it one by one. - */ - - list_for_each_entry(fe, &mark_list, list) { - r = userspace_do_request(lc, lc->uuid, fe->type, - (char *)&fe->region, - sizeof(fe->region), - NULL, NULL); - if (r) - goto fail; - } + r = flush_by_group(lc, &mark_list); + if (r) + goto fail; - list_for_each_entry(fe, &clear_list, list) { - r = userspace_do_request(lc, lc->uuid, fe->type, - (char *)&fe->region, - sizeof(fe->region), - NULL, NULL); - if (r) - goto fail; - } + r = flush_by_group(lc, &clear_list); + if (r) + goto fail; r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH, NULL, 0, NULL, NULL); -- cgit v1.2.3 From 86a54a4802df10d23ccd655e2083e812fe990243 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 13 Jan 2011 19:59:52 +0000 Subject: dm log userspace: add version number to comms This patch adds a 'version' field to the 'dm_ulog_request' structure. The 'version' field is taken from a portion of the unused 'padding' field in the 'dm_ulog_request' structure. This was done to avoid changing the size of the structure and possibly disrupting backwards compatibility. The version number will help notify user-space daemons when a change has been made to the kernel/userspace log API. Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log-userspace-base.c | 6 ++++-- drivers/md/dm-log-userspace-transfer.c | 1 + include/linux/dm-log-userspace.h | 13 ++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 31e1687e7bf6..aa2e0c374ab3 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -12,6 +12,8 @@ #include "dm-log-userspace-transfer.h" +#define DM_LOG_USERSPACE_VSN "1.1.0" + struct flush_entry { int type; region_t region; @@ -765,7 +767,7 @@ static int __init userspace_dirty_log_init(void) return r; } - DMINFO("version 1.0.0 loaded"); + DMINFO("version " DM_LOG_USERSPACE_VSN " loaded"); return 0; } @@ -775,7 +777,7 @@ static void __exit userspace_dirty_log_exit(void) dm_ulog_tfr_exit(); mempool_destroy(flush_entry_pool); - DMINFO("version 1.0.0 unloaded"); + DMINFO("version " DM_LOG_USERSPACE_VSN " unloaded"); return; } diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index 075cbcf8a9f5..049eaf12aaab 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c @@ -198,6 +198,7 @@ resend: memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - sizeof(struct cn_msg)); memcpy(tfr->uuid, uuid, DM_UUID_LEN); + tfr->version = DM_ULOG_REQUEST_VERSION; tfr->luid = luid; tfr->seq = dm_ulog_seq++; diff --git a/include/linux/dm-log-userspace.h b/include/linux/dm-log-userspace.h index 0c3c3a2110c4..eeace7d3ff15 100644 --- a/include/linux/dm-log-userspace.h +++ b/include/linux/dm-log-userspace.h @@ -370,6 +370,16 @@ #define DM_ULOG_REQUEST_TYPE(request_type) \ (DM_ULOG_REQUEST_MASK & (request_type)) +/* + * DM_ULOG_REQUEST_VERSION is incremented when there is a + * change to the way information is passed between kernel + * and userspace. This could be a structure change of + * dm_ulog_request or a change in the way requests are + * issued/handled. Changes are outlined here: + * version 1: Initial implementation + */ +#define DM_ULOG_REQUEST_VERSION 1 + struct dm_ulog_request { /* * The local unique identifier (luid) and the universally unique @@ -383,8 +393,9 @@ struct dm_ulog_request { */ uint64_t luid; char uuid[DM_UUID_LEN]; - char padding[7]; /* Padding because DM_UUID_LEN = 129 */ + char padding[3]; /* Padding because DM_UUID_LEN = 129 */ + uint32_t version; /* See DM_ULOG_REQUEST_VERSION */ int32_t error; /* Used to report back processing errors */ uint32_t seq; /* Sequence number for request */ -- cgit v1.2.3 From 7dbcd137414f3877737802438926d6dba7906a9a Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:52 +0000 Subject: dm crypt: simplify compatible table output Rename cc->cipher_mode to cc->cipher_string and store the whole of the cipher information so it can easily be printed when processing the DM_DEV_STATUS ioctl. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-crypt.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 4c4408a2602f..9a896e1cb2ea 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -108,7 +108,7 @@ struct crypt_config { struct workqueue_struct *crypt_queue; char *cipher; - char *cipher_mode; + char *cipher_string; struct crypt_iv_operations *iv_gen_ops; union { @@ -1030,7 +1030,7 @@ static void crypt_dtr(struct dm_target *ti) dm_put_device(ti, cc->dev); kzfree(cc->cipher); - kzfree(cc->cipher_mode); + kzfree(cc->cipher_string); /* Must zero key material before freeing */ kzfree(cc); @@ -1050,6 +1050,10 @@ static int crypt_ctr_cipher(struct dm_target *ti, return -EINVAL; } + cc->cipher_string = kstrdup(cipher_in, GFP_KERNEL); + if (!cc->cipher_string) + goto bad_mem; + /* * Legacy dm-crypt cipher specification * cipher-mode-iv:ivopts @@ -1061,12 +1065,6 @@ static int crypt_ctr_cipher(struct dm_target *ti, if (!cc->cipher) goto bad_mem; - if (tmp) { - cc->cipher_mode = kstrdup(tmp, GFP_KERNEL); - if (!cc->cipher_mode) - goto bad_mem; - } - chainmode = strsep(&tmp, "-"); ivopts = strsep(&tmp, "-"); ivmode = strsep(&ivopts, ":"); @@ -1074,10 +1072,11 @@ static int crypt_ctr_cipher(struct dm_target *ti, if (tmp) DMWARN("Ignoring unexpected additional cipher options"); - /* Compatibility mode for old dm-crypt mappings */ + /* + * For compatibility with the original dm-crypt mapping format, if + * only the cipher name is supplied, use cbc-plain. + */ if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) { - kfree(cc->cipher_mode); - cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL); chainmode = "cbc"; ivmode = "plain"; } @@ -1307,10 +1306,7 @@ static int crypt_status(struct dm_target *ti, status_type_t type, break; case STATUSTYPE_TABLE: - if (cc->cipher_mode) - DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode); - else - DMEMIT("%s ", cc->cipher); + DMEMIT("%s ", cc->cipher_string); if (cc->key_size > 0) { if ((maxlen - sz) < ((cc->key_size << 1) + 1)) @@ -1422,7 +1418,7 @@ static int crypt_iterate_devices(struct dm_target *ti, static struct target_type crypt_target = { .name = "crypt", - .version = {1, 7, 0}, + .version = {1, 8, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, -- cgit v1.2.3 From c029772125594e31eb1a5ad9e0913724ed9891f2 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 13 Jan 2011 19:59:53 +0000 Subject: dm crypt: scale to multiple cpus Currently dm-crypt does all the encryption work for a single dm-crypt mapping in a single workqueue. This does not scale well when multiple CPUs are submitting IO at a high rate. The single CPU running the single thread cannot keep up with the encryption and encrypted IO performance tanks. This patch changes the crypto workqueue to be per CPU. This means that as long as the IO submitter (or the interrupt target CPUs for reads) runs on different CPUs the encryption work will be also parallel. To avoid a bottleneck on the IO worker I also changed those to be per-CPU threads. There is still some shared data, so I suspect some bouncing cache lines. But I haven't done a detailed study on that yet. Signed-off-by: Andi Kleen Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-crypt.c | 254 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 196 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 9a896e1cb2ea..50ae6ef83738 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,6 @@ struct crypt_iv_operations { }; struct iv_essiv_private { - struct crypto_cipher *tfm; struct crypto_hash *hash_tfm; u8 *salt; }; @@ -91,6 +91,22 @@ struct iv_benbi_private { * and encrypts / decrypts at the same time. */ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID }; + +/* + * Duplicated per-CPU state for cipher. + */ +struct crypt_cpu { + struct ablkcipher_request *req; + struct crypto_ablkcipher *tfm; + + /* ESSIV: struct crypto_cipher *essiv_tfm */ + void *iv_private; +}; + +/* + * The fields in here must be read only after initialization, + * changing state should be in crypt_cpu. + */ struct crypt_config { struct dm_dev *dev; sector_t start; @@ -118,6 +134,12 @@ struct crypt_config { sector_t iv_offset; unsigned int iv_size; + /* + * Duplicated per cpu state. Access through + * per_cpu_ptr() only. + */ + struct crypt_cpu __percpu *cpu; + /* * Layout of each crypto request: * @@ -132,9 +154,7 @@ struct crypt_config { * correctly aligned. */ unsigned int dmreq_start; - struct ablkcipher_request *req; - struct crypto_ablkcipher *tfm; unsigned long flags; unsigned int key_size; u8 key[0]; @@ -149,6 +169,19 @@ static struct kmem_cache *_crypt_io_pool; static void clone_init(struct dm_crypt_io *, struct bio *); static void kcryptd_queue_crypt(struct dm_crypt_io *io); +static struct crypt_cpu *this_crypt_config(struct crypt_config *cc) +{ + return this_cpu_ptr(cc->cpu); +} + +/* + * Use this to access cipher attributes that are the same for each CPU. + */ +static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc) +{ + return __this_cpu_ptr(cc->cpu)->tfm; +} + /* * Different IV generation algorithms: * @@ -195,7 +228,8 @@ static int crypt_iv_essiv_init(struct crypt_config *cc) struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; struct hash_desc desc; struct scatterlist sg; - int err; + struct crypto_cipher *essiv_tfm; + int err, cpu; sg_init_one(&sg, cc->key, cc->key_size); desc.tfm = essiv->hash_tfm; @@ -205,8 +239,16 @@ static int crypt_iv_essiv_init(struct crypt_config *cc) if (err) return err; - return crypto_cipher_setkey(essiv->tfm, essiv->salt, + for_each_possible_cpu(cpu) { + essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private, + + err = crypto_cipher_setkey(essiv_tfm, essiv->salt, crypto_hash_digestsize(essiv->hash_tfm)); + if (err) + return err; + } + + return 0; } /* Wipe salt and reset key derived from volume key */ @@ -214,24 +256,76 @@ static int crypt_iv_essiv_wipe(struct crypt_config *cc) { struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm); + struct crypto_cipher *essiv_tfm; + int cpu, r, err = 0; memset(essiv->salt, 0, salt_size); - return crypto_cipher_setkey(essiv->tfm, essiv->salt, salt_size); + for_each_possible_cpu(cpu) { + essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private; + r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size); + if (r) + err = r; + } + + return err; +} + +/* Set up per cpu cipher state */ +static struct crypto_cipher *setup_essiv_cpu(struct crypt_config *cc, + struct dm_target *ti, + u8 *salt, unsigned saltsize) +{ + struct crypto_cipher *essiv_tfm; + int err; + + /* Setup the essiv_tfm with the given salt */ + essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(essiv_tfm)) { + ti->error = "Error allocating crypto tfm for ESSIV"; + return essiv_tfm; + } + + if (crypto_cipher_blocksize(essiv_tfm) != + crypto_ablkcipher_ivsize(any_tfm(cc))) { + ti->error = "Block size of ESSIV cipher does " + "not match IV size of block cipher"; + crypto_free_cipher(essiv_tfm); + return ERR_PTR(-EINVAL); + } + + err = crypto_cipher_setkey(essiv_tfm, salt, saltsize); + if (err) { + ti->error = "Failed to set key for ESSIV cipher"; + crypto_free_cipher(essiv_tfm); + return ERR_PTR(err); + } + + return essiv_tfm; } static void crypt_iv_essiv_dtr(struct crypt_config *cc) { + int cpu; + struct crypt_cpu *cpu_cc; + struct crypto_cipher *essiv_tfm; struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; - crypto_free_cipher(essiv->tfm); - essiv->tfm = NULL; - crypto_free_hash(essiv->hash_tfm); essiv->hash_tfm = NULL; kzfree(essiv->salt); essiv->salt = NULL; + + for_each_possible_cpu(cpu) { + cpu_cc = per_cpu_ptr(cc->cpu, cpu); + essiv_tfm = cpu_cc->iv_private; + + if (essiv_tfm) + crypto_free_cipher(essiv_tfm); + + cpu_cc->iv_private = NULL; + } } static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, @@ -240,7 +334,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, struct crypto_cipher *essiv_tfm = NULL; struct crypto_hash *hash_tfm = NULL; u8 *salt = NULL; - int err; + int err, cpu; if (!opts) { ti->error = "Digest algorithm missing for ESSIV mode"; @@ -262,30 +356,22 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, goto bad; } - /* Allocate essiv_tfm */ - essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(essiv_tfm)) { - ti->error = "Error allocating crypto tfm for ESSIV"; - err = PTR_ERR(essiv_tfm); - goto bad; - } - if (crypto_cipher_blocksize(essiv_tfm) != - crypto_ablkcipher_ivsize(cc->tfm)) { - ti->error = "Block size of ESSIV cipher does " - "not match IV size of block cipher"; - err = -EINVAL; - goto bad; - } - cc->iv_gen_private.essiv.salt = salt; - cc->iv_gen_private.essiv.tfm = essiv_tfm; cc->iv_gen_private.essiv.hash_tfm = hash_tfm; + for_each_possible_cpu(cpu) { + essiv_tfm = setup_essiv_cpu(cc, ti, salt, + crypto_hash_digestsize(hash_tfm)); + if (IS_ERR(essiv_tfm)) { + crypt_iv_essiv_dtr(cc); + return PTR_ERR(essiv_tfm); + } + per_cpu_ptr(cc->cpu, cpu)->iv_private = essiv_tfm; + } + return 0; bad: - if (essiv_tfm && !IS_ERR(essiv_tfm)) - crypto_free_cipher(essiv_tfm); if (hash_tfm && !IS_ERR(hash_tfm)) crypto_free_hash(hash_tfm); kfree(salt); @@ -294,16 +380,19 @@ bad: static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector) { + struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private; + memset(iv, 0, cc->iv_size); *(u64 *)iv = cpu_to_le64(sector); - crypto_cipher_encrypt_one(cc->iv_gen_private.essiv.tfm, iv, iv); + crypto_cipher_encrypt_one(essiv_tfm, iv, iv); + return 0; } static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti, const char *opts) { - unsigned bs = crypto_ablkcipher_blocksize(cc->tfm); + unsigned bs = crypto_ablkcipher_blocksize(any_tfm(cc)); int log = ilog2(bs); /* we need to calculate how far we must shift the sector count @@ -412,7 +501,7 @@ static int crypt_convert_block(struct crypt_config *cc, dmreq = dmreq_of_req(cc, req); iv = (u8 *)ALIGN((unsigned long)(dmreq + 1), - crypto_ablkcipher_alignmask(cc->tfm) + 1); + crypto_ablkcipher_alignmask(any_tfm(cc)) + 1); dmreq->ctx = ctx; sg_init_table(&dmreq->sg_in, 1); @@ -454,16 +543,19 @@ static int crypt_convert_block(struct crypt_config *cc, static void kcryptd_async_done(struct crypto_async_request *async_req, int error); + static void crypt_alloc_req(struct crypt_config *cc, struct convert_context *ctx) { - if (!cc->req) - cc->req = mempool_alloc(cc->req_pool, GFP_NOIO); - ablkcipher_request_set_tfm(cc->req, cc->tfm); - ablkcipher_request_set_callback(cc->req, CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP, - kcryptd_async_done, - dmreq_of_req(cc, cc->req)); + struct crypt_cpu *this_cc = this_crypt_config(cc); + + if (!this_cc->req) + this_cc->req = mempool_alloc(cc->req_pool, GFP_NOIO); + + ablkcipher_request_set_tfm(this_cc->req, this_cc->tfm); + ablkcipher_request_set_callback(this_cc->req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + kcryptd_async_done, dmreq_of_req(cc, this_cc->req)); } /* @@ -472,6 +564,7 @@ static void crypt_alloc_req(struct crypt_config *cc, static int crypt_convert(struct crypt_config *cc, struct convert_context *ctx) { + struct crypt_cpu *this_cc = this_crypt_config(cc); int r; atomic_set(&ctx->pending, 1); @@ -483,7 +576,7 @@ static int crypt_convert(struct crypt_config *cc, atomic_inc(&ctx->pending); - r = crypt_convert_block(cc, ctx, cc->req); + r = crypt_convert_block(cc, ctx, this_cc->req); switch (r) { /* async */ @@ -492,7 +585,7 @@ static int crypt_convert(struct crypt_config *cc, INIT_COMPLETION(ctx->restart); /* fall through*/ case -EINPROGRESS: - cc->req = NULL; + this_cc->req = NULL; ctx->sector++; continue; @@ -651,6 +744,9 @@ static void crypt_dec_pending(struct dm_crypt_io *io) * They must be separated as otherwise the final stages could be * starved by new requests which can block in the first stages due * to memory allocation. + * + * The work is done per CPU global for all dm-crypt instances. + * They should not depend on each other and do not block. */ static void crypt_endio(struct bio *clone, int error) { @@ -971,6 +1067,20 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size) } } +static int crypt_setkey_allcpus(struct crypt_config *cc) +{ + int cpu, err = 0, r; + + for_each_possible_cpu(cpu) { + r = crypto_ablkcipher_setkey(per_cpu_ptr(cc->cpu, cpu)->tfm, + cc->key, cc->key_size); + if (r) + err = r; + } + + return err; +} + static int crypt_set_key(struct crypt_config *cc, char *key) { /* The key size may not be changed. */ @@ -986,19 +1096,22 @@ static int crypt_set_key(struct crypt_config *cc, char *key) set_bit(DM_CRYPT_KEY_VALID, &cc->flags); - return crypto_ablkcipher_setkey(cc->tfm, cc->key, cc->key_size); + return crypt_setkey_allcpus(cc); } static int crypt_wipe_key(struct crypt_config *cc) { clear_bit(DM_CRYPT_KEY_VALID, &cc->flags); memset(&cc->key, 0, cc->key_size * sizeof(u8)); - return crypto_ablkcipher_setkey(cc->tfm, cc->key, cc->key_size); + + return crypt_setkey_allcpus(cc); } static void crypt_dtr(struct dm_target *ti) { struct crypt_config *cc = ti->private; + struct crypt_cpu *cpu_cc; + int cpu; ti->private = NULL; @@ -1010,6 +1123,15 @@ static void crypt_dtr(struct dm_target *ti) if (cc->crypt_queue) destroy_workqueue(cc->crypt_queue); + if (cc->cpu) + for_each_possible_cpu(cpu) { + cpu_cc = per_cpu_ptr(cc->cpu, cpu); + if (cpu_cc->req) + mempool_free(cpu_cc->req, cc->req_pool); + if (cpu_cc->tfm) + crypto_free_ablkcipher(cpu_cc->tfm); + } + if (cc->bs) bioset_free(cc->bs); @@ -1023,12 +1145,12 @@ static void crypt_dtr(struct dm_target *ti) if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) cc->iv_gen_ops->dtr(cc); - if (cc->tfm && !IS_ERR(cc->tfm)) - crypto_free_ablkcipher(cc->tfm); - if (cc->dev) dm_put_device(ti, cc->dev); + if (cc->cpu) + free_percpu(cc->cpu); + kzfree(cc->cipher); kzfree(cc->cipher_string); @@ -1040,9 +1162,10 @@ static int crypt_ctr_cipher(struct dm_target *ti, char *cipher_in, char *key) { struct crypt_config *cc = ti->private; + struct crypto_ablkcipher *tfm; char *tmp, *cipher, *chainmode, *ivmode, *ivopts; char *cipher_api = NULL; - int ret = -EINVAL; + int cpu, ret = -EINVAL; /* Convert to crypto api definition? */ if (strchr(cipher_in, '(')) { @@ -1072,6 +1195,12 @@ static int crypt_ctr_cipher(struct dm_target *ti, if (tmp) DMWARN("Ignoring unexpected additional cipher options"); + cc->cpu = alloc_percpu(struct crypt_cpu); + if (!cc->cpu) { + ti->error = "Cannot allocate per cpu state"; + goto bad_mem; + } + /* * For compatibility with the original dm-crypt mapping format, if * only the cipher name is supplied, use cbc-plain. @@ -1098,11 +1227,14 @@ static int crypt_ctr_cipher(struct dm_target *ti, } /* Allocate cipher */ - cc->tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0); - if (IS_ERR(cc->tfm)) { - ret = PTR_ERR(cc->tfm); - ti->error = "Error allocating crypto tfm"; - goto bad; + for_each_possible_cpu(cpu) { + tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + ti->error = "Error allocating crypto tfm"; + goto bad; + } + per_cpu_ptr(cc->cpu, cpu)->tfm = tfm; } /* Initialize and set key */ @@ -1113,7 +1245,7 @@ static int crypt_ctr_cipher(struct dm_target *ti, } /* Initialize IV */ - cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm); + cc->iv_size = crypto_ablkcipher_ivsize(any_tfm(cc)); if (cc->iv_size) /* at least a 64 bit sector number should fit in our buffer */ cc->iv_size = max(cc->iv_size, @@ -1208,9 +1340,9 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } cc->dmreq_start = sizeof(struct ablkcipher_request); - cc->dmreq_start += crypto_ablkcipher_reqsize(cc->tfm); + cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc)); cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment()); - cc->dmreq_start += crypto_ablkcipher_alignmask(cc->tfm) & + cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) & ~(crypto_tfm_ctx_alignment() - 1); cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start + @@ -1219,7 +1351,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->error = "Cannot allocate crypt request mempool"; goto bad; } - cc->req = NULL; cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); if (!cc->page_pool) { @@ -1252,13 +1383,20 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) cc->start = tmpll; ret = -ENOMEM; - cc->io_queue = create_singlethread_workqueue("kcryptd_io"); + cc->io_queue = alloc_workqueue("kcryptd_io", + WQ_NON_REENTRANT| + WQ_MEM_RECLAIM, + 1); if (!cc->io_queue) { ti->error = "Couldn't create kcryptd io queue"; goto bad; } - cc->crypt_queue = create_singlethread_workqueue("kcryptd"); + cc->crypt_queue = alloc_workqueue("kcryptd", + WQ_NON_REENTRANT| + WQ_CPU_INTENSIVE| + WQ_MEM_RECLAIM, + 1); if (!cc->crypt_queue) { ti->error = "Couldn't create kcryptd queue"; goto bad; @@ -1418,7 +1556,7 @@ static int crypt_iterate_devices(struct dm_target *ti, static struct target_type crypt_target = { .name = "crypt", - .version = {1, 8, 0}, + .version = {1, 9, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, -- cgit v1.2.3 From 20c82538e4f5ede51bc2b4795bc6e5cae772796d Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:53 +0000 Subject: dm crypt: use io thread for reads only if mempool exhausted If there is enough memory, code can directly submit bio instead queing this operation in separate thread. Try to alloc bio clone with GFP_NOWAIT and only if it fails use separate queue (map function cannot block here). Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-crypt.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 50ae6ef83738..dc4403bcc6a0 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -787,26 +787,30 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone) clone->bi_destructor = dm_crypt_bio_destructor; } -static void kcryptd_io_read(struct dm_crypt_io *io) +static void kcryptd_unplug(struct crypt_config *cc) +{ + blk_unplug(bdev_get_queue(cc->dev->bdev)); +} + +static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) { struct crypt_config *cc = io->target->private; struct bio *base_bio = io->base_bio; struct bio *clone; - crypt_inc_pending(io); - /* * The block layer might modify the bvec array, so always * copy the required bvecs because we need the original * one in order to decrypt the whole bio data *afterwards*. */ - clone = bio_alloc_bioset(GFP_NOIO, bio_segments(base_bio), cc->bs); - if (unlikely(!clone)) { - io->error = -ENOMEM; - crypt_dec_pending(io); - return; + clone = bio_alloc_bioset(gfp, bio_segments(base_bio), cc->bs); + if (!clone) { + kcryptd_unplug(cc); + return 1; } + crypt_inc_pending(io); + clone_init(io, clone); clone->bi_idx = 0; clone->bi_vcnt = bio_segments(base_bio); @@ -816,6 +820,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io) sizeof(struct bio_vec) * clone->bi_vcnt); generic_make_request(clone); + return 0; } static void kcryptd_io_write(struct dm_crypt_io *io) @@ -828,9 +833,12 @@ static void kcryptd_io(struct work_struct *work) { struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work); - if (bio_data_dir(io->base_bio) == READ) - kcryptd_io_read(io); - else + if (bio_data_dir(io->base_bio) == READ) { + crypt_inc_pending(io); + if (kcryptd_io_read(io, GFP_NOIO)) + io->error = -ENOMEM; + crypt_dec_pending(io); + } else kcryptd_io_write(io); } @@ -1424,9 +1432,10 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, io = crypt_io_alloc(ti, bio, dm_target_offset(ti, bio->bi_sector)); - if (bio_data_dir(io->base_bio) == READ) - kcryptd_queue_io(io); - else + if (bio_data_dir(io->base_bio) == READ) { + if (kcryptd_io_read(io, GFP_NOWAIT)) + kcryptd_queue_io(io); + } else kcryptd_queue_crypt(io); return DM_MAPIO_SUBMITTED; -- cgit v1.2.3 From 2dc5327d3acb3340ab6fa3981401b076b78a51f4 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:54 +0000 Subject: dm crypt: add post iv call to iv generator IV (initialisation vector) can in principle depend not only on sector but also on plaintext data (or other attributes). Change IV generator interface to work directly with dmreq structure to allow such dependence in generator. Also add post() function which is called after the crypto operation. This allows tricky modification of decrypted data or IV internals. In asynchronous mode the post() can be called after ctx->sector count was increased so it is needed to add iv_sector copy directly to dmreq structure. (N.B. dmreq always include only one sector in scatterlists) Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-crypt.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index dc4403bcc6a0..e0ebe685be6a 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -64,6 +64,7 @@ struct dm_crypt_request { struct convert_context *ctx; struct scatterlist sg_in; struct scatterlist sg_out; + sector_t iv_sector; }; struct crypt_config; @@ -74,7 +75,10 @@ struct crypt_iv_operations { void (*dtr)(struct crypt_config *cc); int (*init)(struct crypt_config *cc); int (*wipe)(struct crypt_config *cc); - int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector); + int (*generator)(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq); + int (*post)(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq); }; struct iv_essiv_private { @@ -168,6 +172,7 @@ static struct kmem_cache *_crypt_io_pool; static void clone_init(struct dm_crypt_io *, struct bio *); static void kcryptd_queue_crypt(struct dm_crypt_io *io); +static u8 *iv_of_dmreq(struct crypt_config *cc, struct dm_crypt_request *dmreq); static struct crypt_cpu *this_crypt_config(struct crypt_config *cc) { @@ -205,19 +210,20 @@ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc) * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454 */ -static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector) +static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) { memset(iv, 0, cc->iv_size); - *(u32 *)iv = cpu_to_le32(sector & 0xffffffff); + *(u32 *)iv = cpu_to_le32(dmreq->iv_sector & 0xffffffff); return 0; } static int crypt_iv_plain64_gen(struct crypt_config *cc, u8 *iv, - sector_t sector) + struct dm_crypt_request *dmreq) { memset(iv, 0, cc->iv_size); - *(u64 *)iv = cpu_to_le64(sector); + *(u64 *)iv = cpu_to_le64(dmreq->iv_sector); return 0; } @@ -378,12 +384,13 @@ bad: return err; } -static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector) +static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) { struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private; memset(iv, 0, cc->iv_size); - *(u64 *)iv = cpu_to_le64(sector); + *(u64 *)iv = cpu_to_le64(dmreq->iv_sector); crypto_cipher_encrypt_one(essiv_tfm, iv, iv); return 0; @@ -417,19 +424,21 @@ static void crypt_iv_benbi_dtr(struct crypt_config *cc) { } -static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, sector_t sector) +static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) { __be64 val; memset(iv, 0, cc->iv_size - sizeof(u64)); /* rest is cleared below */ - val = cpu_to_be64(((u64)sector << cc->iv_gen_private.benbi.shift) + 1); + val = cpu_to_be64(((u64)dmreq->iv_sector << cc->iv_gen_private.benbi.shift) + 1); put_unaligned(val, (__be64 *)(iv + cc->iv_size - sizeof(u64))); return 0; } -static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, sector_t sector) +static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) { memset(iv, 0, cc->iv_size); @@ -489,6 +498,13 @@ static struct ablkcipher_request *req_of_dmreq(struct crypt_config *cc, return (struct ablkcipher_request *)((char *)dmreq - cc->dmreq_start); } +static u8 *iv_of_dmreq(struct crypt_config *cc, + struct dm_crypt_request *dmreq) +{ + return (u8 *)ALIGN((unsigned long)(dmreq + 1), + crypto_ablkcipher_alignmask(any_tfm(cc)) + 1); +} + static int crypt_convert_block(struct crypt_config *cc, struct convert_context *ctx, struct ablkcipher_request *req) @@ -500,9 +516,9 @@ static int crypt_convert_block(struct crypt_config *cc, int r = 0; dmreq = dmreq_of_req(cc, req); - iv = (u8 *)ALIGN((unsigned long)(dmreq + 1), - crypto_ablkcipher_alignmask(any_tfm(cc)) + 1); + iv = iv_of_dmreq(cc, dmreq); + dmreq->iv_sector = ctx->sector; dmreq->ctx = ctx; sg_init_table(&dmreq->sg_in, 1); sg_set_page(&dmreq->sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT, @@ -525,7 +541,7 @@ static int crypt_convert_block(struct crypt_config *cc, } if (cc->iv_gen_ops) { - r = cc->iv_gen_ops->generator(cc, iv, ctx->sector); + r = cc->iv_gen_ops->generator(cc, iv, dmreq); if (r < 0) return r; } @@ -538,6 +554,9 @@ static int crypt_convert_block(struct crypt_config *cc, else r = crypto_ablkcipher_decrypt(req); + if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post) + r = cc->iv_gen_ops->post(cc, iv, dmreq); + return r; } @@ -1005,6 +1024,9 @@ static void kcryptd_async_done(struct crypto_async_request *async_req, return; } + if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post) + error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq); + mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool); if (!atomic_dec_and_test(&ctx->pending)) -- cgit v1.2.3 From d1f9642381847e2b94caa34c3533211cf36ffcf4 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:54 +0000 Subject: dm crypt: add multi key capability This patch adds generic multikey handling to be used in following patch for Loop-AES mode compatibility. This patch extends mapping table to optional keycount and implements generic multi-key capability. With more keys defined the string is divided into several sections and these are used for tfms. The tfm is used according to sector offset (sector 0->tfm[0], sector 1->tfm[1], sector N->tfm[N modulo keycount]) (only power of two values supported for keycount here). Because of tfms per-cpu allocation, this mode can be take a lot of memory on large smp systems. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon Cc: Max Vozeler --- Documentation/device-mapper/dm-crypt.txt | 7 ++- drivers/md/dm-crypt.c | 85 ++++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt index 524de926290d..59293ac4a5d0 100644 --- a/Documentation/device-mapper/dm-crypt.txt +++ b/Documentation/device-mapper/dm-crypt.txt @@ -8,7 +8,7 @@ Parameters: Encryption cipher and an optional IV generation mode. - (In format cipher-chainmode-ivopts:ivmode). + (In format cipher[:keycount]-chainmode-ivopts:ivmode). Examples: des aes-cbc-essiv:sha256 @@ -20,6 +20,11 @@ Parameters: Key used for encryption. It is encoded as a hexadecimal number. You can only use key sizes that are valid for the selected cipher. + + Multi-key compatibility mode. You can define keys and + then sectors are encrypted according to their offsets (sector 0 uses key0; + sector 1 uses key1 etc.). must be a power of two. + The IV offset is a sector count that is added to the sector number before creating the IV. diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index e0ebe685be6a..b8b9267c4dbb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -101,10 +101,9 @@ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID }; */ struct crypt_cpu { struct ablkcipher_request *req; - struct crypto_ablkcipher *tfm; - /* ESSIV: struct crypto_cipher *essiv_tfm */ void *iv_private; + struct crypto_ablkcipher *tfms[0]; }; /* @@ -143,6 +142,7 @@ struct crypt_config { * per_cpu_ptr() only. */ struct crypt_cpu __percpu *cpu; + unsigned tfms_count; /* * Layout of each crypto request: @@ -161,6 +161,7 @@ struct crypt_config { unsigned long flags; unsigned int key_size; + unsigned int key_parts; u8 key[0]; }; @@ -184,7 +185,7 @@ static struct crypt_cpu *this_crypt_config(struct crypt_config *cc) */ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc) { - return __this_cpu_ptr(cc->cpu)->tfm; + return __this_cpu_ptr(cc->cpu)->tfms[0]; } /* @@ -567,11 +568,12 @@ static void crypt_alloc_req(struct crypt_config *cc, struct convert_context *ctx) { struct crypt_cpu *this_cc = this_crypt_config(cc); + unsigned key_index = ctx->sector & (cc->tfms_count - 1); if (!this_cc->req) this_cc->req = mempool_alloc(cc->req_pool, GFP_NOIO); - ablkcipher_request_set_tfm(this_cc->req, this_cc->tfm); + ablkcipher_request_set_tfm(this_cc->req, this_cc->tfms[key_index]); ablkcipher_request_set_callback(this_cc->req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, kcryptd_async_done, dmreq_of_req(cc, this_cc->req)); @@ -1097,15 +1099,48 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size) } } +static void crypt_free_tfms(struct crypt_config *cc, int cpu) +{ + struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu); + unsigned i; + + for (i = 0; i < cc->tfms_count; i++) + if (cpu_cc->tfms[i] && !IS_ERR(cpu_cc->tfms[i])) { + crypto_free_ablkcipher(cpu_cc->tfms[i]); + cpu_cc->tfms[i] = NULL; + } +} + +static int crypt_alloc_tfms(struct crypt_config *cc, int cpu, char *ciphermode) +{ + struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu); + unsigned i; + int err; + + for (i = 0; i < cc->tfms_count; i++) { + cpu_cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0); + if (IS_ERR(cpu_cc->tfms[i])) { + err = PTR_ERR(cpu_cc->tfms[i]); + crypt_free_tfms(cc, cpu); + return err; + } + } + + return 0; +} + static int crypt_setkey_allcpus(struct crypt_config *cc) { - int cpu, err = 0, r; + unsigned subkey_size = cc->key_size >> ilog2(cc->tfms_count); + int cpu, err = 0, i, r; for_each_possible_cpu(cpu) { - r = crypto_ablkcipher_setkey(per_cpu_ptr(cc->cpu, cpu)->tfm, - cc->key, cc->key_size); - if (r) - err = r; + for (i = 0; i < cc->tfms_count; i++) { + r = crypto_ablkcipher_setkey(per_cpu_ptr(cc->cpu, cpu)->tfms[i], + cc->key + (i * subkey_size), subkey_size); + if (r) + err = r; + } } return err; @@ -1158,8 +1193,7 @@ static void crypt_dtr(struct dm_target *ti) cpu_cc = per_cpu_ptr(cc->cpu, cpu); if (cpu_cc->req) mempool_free(cpu_cc->req, cc->req_pool); - if (cpu_cc->tfm) - crypto_free_ablkcipher(cpu_cc->tfm); + crypt_free_tfms(cc, cpu); } if (cc->bs) @@ -1192,8 +1226,7 @@ static int crypt_ctr_cipher(struct dm_target *ti, char *cipher_in, char *key) { struct crypt_config *cc = ti->private; - struct crypto_ablkcipher *tfm; - char *tmp, *cipher, *chainmode, *ivmode, *ivopts; + char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount; char *cipher_api = NULL; int cpu, ret = -EINVAL; @@ -1209,10 +1242,20 @@ static int crypt_ctr_cipher(struct dm_target *ti, /* * Legacy dm-crypt cipher specification - * cipher-mode-iv:ivopts + * cipher[:keycount]-mode-iv:ivopts */ tmp = cipher_in; - cipher = strsep(&tmp, "-"); + keycount = strsep(&tmp, "-"); + cipher = strsep(&keycount, ":"); + + if (!keycount) + cc->tfms_count = 1; + else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 || + !is_power_of_2(cc->tfms_count)) { + ti->error = "Bad cipher key count specification"; + return -EINVAL; + } + cc->key_parts = cc->tfms_count; cc->cipher = kstrdup(cipher, GFP_KERNEL); if (!cc->cipher) @@ -1225,7 +1268,9 @@ static int crypt_ctr_cipher(struct dm_target *ti, if (tmp) DMWARN("Ignoring unexpected additional cipher options"); - cc->cpu = alloc_percpu(struct crypt_cpu); + cc->cpu = __alloc_percpu(sizeof(*(cc->cpu)) + + cc->tfms_count * sizeof(*(cc->cpu->tfms)), + __alignof__(struct crypt_cpu)); if (!cc->cpu) { ti->error = "Cannot allocate per cpu state"; goto bad_mem; @@ -1258,13 +1303,11 @@ static int crypt_ctr_cipher(struct dm_target *ti, /* Allocate cipher */ for_each_possible_cpu(cpu) { - tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0); - if (IS_ERR(tfm)) { - ret = PTR_ERR(tfm); + ret = crypt_alloc_tfms(cc, cpu, cipher_api); + if (ret < 0) { ti->error = "Error allocating crypto tfm"; goto bad; } - per_cpu_ptr(cc->cpu, cpu)->tfm = tfm; } /* Initialize and set key */ @@ -1587,7 +1630,7 @@ static int crypt_iterate_devices(struct dm_target *ti, static struct target_type crypt_target = { .name = "crypt", - .version = {1, 9, 0}, + .version = {1, 10, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, -- cgit v1.2.3 From 34745785937a2003c144c0d4802fa637470d87af Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:55 +0000 Subject: dm crypt: add loop aes iv generator This patch adds a compatible implementation of the block chaining mode used by the Loop-AES block device encryption system (http://loop-aes.sourceforge.net/) designed by Jari Ruusu. It operates on full 512 byte sectors and uses CBC with an IV derived from the sector number, the data and optionally extra IV seed. This means that after CBC decryption the first block of sector must be tweaked according to decrypted data. Loop-AES can use three encryption schemes: version 1: is plain aes-cbc mode (already compatible) version 2: uses 64 multikey scheme with own IV generator version 3: the same as version 2 with additional IV seed (it uses 65 keys, last key is used as IV seed) The IV generator is here named lmk (Loop-AES multikey) and for the cipher specification looks like: aes:64-cbc-lmk Version 2 and 3 is recognised according to length of provided multi-key string (which is just hexa encoded "raw key" used in original Loop-AES ioctl). Configuration of the device and decoding key string will be done in userspace (cryptsetup). (Loop-AES stores keys in gpg encrypted file, raw keys are output of simple hashing of lines in this file). Based on an implementation by Max Vozeler: http://article.gmane.org/gmane.linux.kernel.cryptoapi/3752/ Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon CC: Max Vozeler --- drivers/md/dm-crypt.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index b8b9267c4dbb..4e054bd91664 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include @@ -90,6 +93,12 @@ struct iv_benbi_private { int shift; }; +#define LMK_SEED_SIZE 64 /* hash + 0 */ +struct iv_lmk_private { + struct crypto_shash *hash_tfm; + u8 *seed; +}; + /* * Crypt: maps a linear range of a block device * and encrypts / decrypts at the same time. @@ -133,6 +142,7 @@ struct crypt_config { union { struct iv_essiv_private essiv; struct iv_benbi_private benbi; + struct iv_lmk_private lmk; } iv_gen_private; sector_t iv_offset; unsigned int iv_size; @@ -207,6 +217,20 @@ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc) * null: the initial vector is always zero. Provides compatibility with * obsolete loop_fish2 devices. Do not use for new devices. * + * lmk: Compatible implementation of the block chaining mode used + * by the Loop-AES block device encryption system + * designed by Jari Ruusu. See http://loop-aes.sourceforge.net/ + * It operates on full 512 byte sectors and uses CBC + * with an IV derived from the sector number, the data and + * optionally extra IV seed. + * This means that after decryption the first block + * of sector must be tweaked according to decrypted data. + * Loop-AES can use three encryption schemes: + * version 1: is plain aes-cbc mode + * version 2: uses 64 multikey scheme with lmk IV generator + * version 3: the same as version 2 with additional IV seed + * (it uses 65 keys, last key is used as IV seed) + * * plumb: unimplemented, see: * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454 */ @@ -446,6 +470,156 @@ static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, return 0; } +static void crypt_iv_lmk_dtr(struct crypt_config *cc) +{ + struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; + + if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm)) + crypto_free_shash(lmk->hash_tfm); + lmk->hash_tfm = NULL; + + kzfree(lmk->seed); + lmk->seed = NULL; +} + +static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti, + const char *opts) +{ + struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; + + lmk->hash_tfm = crypto_alloc_shash("md5", 0, 0); + if (IS_ERR(lmk->hash_tfm)) { + ti->error = "Error initializing LMK hash"; + return PTR_ERR(lmk->hash_tfm); + } + + /* No seed in LMK version 2 */ + if (cc->key_parts == cc->tfms_count) { + lmk->seed = NULL; + return 0; + } + + lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL); + if (!lmk->seed) { + crypt_iv_lmk_dtr(cc); + ti->error = "Error kmallocing seed storage in LMK"; + return -ENOMEM; + } + + return 0; +} + +static int crypt_iv_lmk_init(struct crypt_config *cc) +{ + struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; + int subkey_size = cc->key_size / cc->key_parts; + + /* LMK seed is on the position of LMK_KEYS + 1 key */ + if (lmk->seed) + memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size), + crypto_shash_digestsize(lmk->hash_tfm)); + + return 0; +} + +static int crypt_iv_lmk_wipe(struct crypt_config *cc) +{ + struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; + + if (lmk->seed) + memset(lmk->seed, 0, LMK_SEED_SIZE); + + return 0; +} + +static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq, + u8 *data) +{ + struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk; + struct { + struct shash_desc desc; + char ctx[crypto_shash_descsize(lmk->hash_tfm)]; + } sdesc; + struct md5_state md5state; + u32 buf[4]; + int i, r; + + sdesc.desc.tfm = lmk->hash_tfm; + sdesc.desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + r = crypto_shash_init(&sdesc.desc); + if (r) + return r; + + if (lmk->seed) { + r = crypto_shash_update(&sdesc.desc, lmk->seed, LMK_SEED_SIZE); + if (r) + return r; + } + + /* Sector is always 512B, block size 16, add data of blocks 1-31 */ + r = crypto_shash_update(&sdesc.desc, data + 16, 16 * 31); + if (r) + return r; + + /* Sector is cropped to 56 bits here */ + buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF); + buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000); + buf[2] = cpu_to_le32(4024); + buf[3] = 0; + r = crypto_shash_update(&sdesc.desc, (u8 *)buf, sizeof(buf)); + if (r) + return r; + + /* No MD5 padding here */ + r = crypto_shash_export(&sdesc.desc, &md5state); + if (r) + return r; + + for (i = 0; i < MD5_HASH_WORDS; i++) + __cpu_to_le32s(&md5state.hash[i]); + memcpy(iv, &md5state.hash, cc->iv_size); + + return 0; +} + +static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) +{ + u8 *src; + int r = 0; + + if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) { + src = kmap_atomic(sg_page(&dmreq->sg_in), KM_USER0); + r = crypt_iv_lmk_one(cc, iv, dmreq, src + dmreq->sg_in.offset); + kunmap_atomic(src, KM_USER0); + } else + memset(iv, 0, cc->iv_size); + + return r; +} + +static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, + struct dm_crypt_request *dmreq) +{ + u8 *dst; + int r; + + if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) + return 0; + + dst = kmap_atomic(sg_page(&dmreq->sg_out), KM_USER0); + r = crypt_iv_lmk_one(cc, iv, dmreq, dst + dmreq->sg_out.offset); + + /* Tweak the first block of plaintext sector */ + if (!r) + crypto_xor(dst + dmreq->sg_out.offset, iv, cc->iv_size); + + kunmap_atomic(dst, KM_USER0); + return r; +} + static struct crypt_iv_operations crypt_iv_plain_ops = { .generator = crypt_iv_plain_gen }; @@ -472,6 +646,15 @@ static struct crypt_iv_operations crypt_iv_null_ops = { .generator = crypt_iv_null_gen }; +static struct crypt_iv_operations crypt_iv_lmk_ops = { + .ctr = crypt_iv_lmk_ctr, + .dtr = crypt_iv_lmk_dtr, + .init = crypt_iv_lmk_init, + .wipe = crypt_iv_lmk_wipe, + .generator = crypt_iv_lmk_gen, + .post = crypt_iv_lmk_post +}; + static void crypt_convert_init(struct crypt_config *cc, struct convert_context *ctx, struct bio *bio_out, struct bio *bio_in, @@ -1341,7 +1524,15 @@ static int crypt_ctr_cipher(struct dm_target *ti, cc->iv_gen_ops = &crypt_iv_benbi_ops; else if (strcmp(ivmode, "null") == 0) cc->iv_gen_ops = &crypt_iv_null_ops; - else { + else if (strcmp(ivmode, "lmk") == 0) { + cc->iv_gen_ops = &crypt_iv_lmk_ops; + /* Version 2 and 3 is recognised according + * to length of provided multi-key string. + * If present (version 3), last key is used as IV seed. + */ + if (cc->key_size % cc->key_parts) + cc->key_parts++; + } else { ret = -EINVAL; ti->error = "Invalid IV mode"; goto bad; -- cgit v1.2.3 From 810b492375f4aed5ce222982054adc0394a4bd33 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 13 Jan 2011 19:59:55 +0000 Subject: dm ioctl: suppress needless warning messages The device-mapper should not send warning messages to syslog if a device is not found. This can be done by userspace according to the returned dm-ioctl error code. So move these messages to debug level and use rate limiting to not flood syslog. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index f3481d922206..6d12775a1061 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -779,7 +779,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) hc = __find_device_hash_cell(param); if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); + DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table."); up_write(&_hash_lock); return -ENXIO; } @@ -791,7 +791,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) */ r = dm_lock_for_deletion(md); if (r) { - DMWARN("unable to remove open device %s", hc->name); + DMDEBUG_LIMIT("unable to remove open device %s", hc->name); up_write(&_hash_lock); dm_put(md); return r; @@ -938,7 +938,7 @@ static int do_resume(struct dm_ioctl *param) hc = __find_device_hash_cell(param); if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); + DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table."); up_write(&_hash_lock); return -ENXIO; } @@ -1265,7 +1265,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size) hc = __find_device_hash_cell(param); if (!hc) { - DMWARN("device doesn't appear to be in the dev hash table."); + DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table."); up_write(&_hash_lock); return -ENXIO; } -- cgit v1.2.3 From fecec20e55ec117a09857ac1a455e2e6e2f17df4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 13 Jan 2011 19:59:56 +0000 Subject: dm snapshot: remove unused dm_snapshot queued_bios_work dm_snapshot->queued_bios_work isn't used. Remove ->queued_bios[_work] from dm_snapshot structure, the flush_queued_bios work function and ksnapd workqueue. The DM snapshot changes that were going to use the ksnapd workqueue were either superseded (fix for origin write races) or never completed (deallocation of invalid snapshot's memory via workqueue). Signed-off-by: Tejun Heo Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 53cf79d8bcbc..0f47698beafa 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "dm-exception-store.h" @@ -106,10 +105,6 @@ struct dm_snapshot { struct dm_kcopyd_client *kcopyd_client; - /* Queue of snapshot writes for ksnapd to flush */ - struct bio_list queued_bios; - struct work_struct queued_bios_work; - /* Wait for events based on state_bits */ unsigned long state_bits; @@ -160,9 +155,6 @@ struct dm_dev *dm_snap_cow(struct dm_snapshot *s) } EXPORT_SYMBOL(dm_snap_cow); -static struct workqueue_struct *ksnapd; -static void flush_queued_bios(struct work_struct *work); - static sector_t chunk_to_sector(struct dm_exception_store *store, chunk_t chunk) { @@ -1153,9 +1145,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) spin_lock_init(&s->tracked_chunk_lock); - bio_list_init(&s->queued_bios); - INIT_WORK(&s->queued_bios_work, flush_queued_bios); - ti->private = s; ti->num_flush_requests = num_flush_requests; @@ -1279,8 +1268,6 @@ static void snapshot_dtr(struct dm_target *ti) struct dm_snapshot *s = ti->private; struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; - flush_workqueue(ksnapd); - down_read(&_origins_lock); /* Check whether exception handover must be cancelled */ (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); @@ -1342,20 +1329,6 @@ static void flush_bios(struct bio *bio) } } -static void flush_queued_bios(struct work_struct *work) -{ - struct dm_snapshot *s = - container_of(work, struct dm_snapshot, queued_bios_work); - struct bio *queued_bios; - unsigned long flags; - - spin_lock_irqsave(&s->pe_lock, flags); - queued_bios = bio_list_get(&s->queued_bios); - spin_unlock_irqrestore(&s->pe_lock, flags); - - flush_bios(queued_bios); -} - static int do_origin(struct dm_dev *origin, struct bio *bio); /* @@ -2291,17 +2264,8 @@ static int __init dm_snapshot_init(void) goto bad_tracked_chunk_cache; } - ksnapd = create_singlethread_workqueue("ksnapd"); - if (!ksnapd) { - DMERR("Failed to create ksnapd workqueue."); - r = -ENOMEM; - goto bad_pending_pool; - } - return 0; -bad_pending_pool: - kmem_cache_destroy(tracked_chunk_cache); bad_tracked_chunk_cache: kmem_cache_destroy(pending_cache); bad_pending_cache: @@ -2322,8 +2286,6 @@ bad_register_snapshot_target: static void __exit dm_snapshot_exit(void) { - destroy_workqueue(ksnapd); - dm_unregister_target(&snapshot_target); dm_unregister_target(&origin_target); dm_unregister_target(&merge_target); -- cgit v1.2.3 From d5ffa387e24646cb1cb55d80fd0f182a00e0edb7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 13 Jan 2011 19:59:56 +0000 Subject: dm: dont use flush_scheduled_work flush_scheduled_work() is being deprecated. Flush the used work directly instead. In all dm targets, the only work which uses system_wq is ->trigger_event. Signed-off-by: Tejun Heo Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-mpath.c | 2 +- drivers/md/dm-raid1.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 406091f9692b..fcc59c3f756e 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -920,7 +920,7 @@ static void flush_multipath_work(struct multipath *m) flush_workqueue(kmpath_handlerd); multipath_wait_for_pg_init_completion(m); flush_workqueue(kmultipathd); - flush_scheduled_work(); + flush_work_sync(&m->trigger_event); } static void multipath_dtr(struct dm_target *ti) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index c87756eb7a21..0d58b6f875cc 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1138,7 +1138,7 @@ static void mirror_dtr(struct dm_target *ti) del_timer_sync(&ms->timer); flush_workqueue(ms->kmirrord_wq); - flush_scheduled_work(); + flush_work_sync(&ms->trigger_event); dm_kcopyd_client_destroy(ms->kcopyd_client); destroy_workqueue(ms->kmirrord_wq); free_context(ms, ti, ms->nr_mirrors); -- cgit v1.2.3 From f521f074abe7b3990f5df65482cdc3d851b80665 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 13 Jan 2011 19:59:57 +0000 Subject: dm stripe: switch from local workqueue to system_wq kstriped only serves sc->kstriped_ws which runs dm_table_event(). This doesn't need to be executed from an ordered workqueue w/ rescuer. Drop kstriped and use the system_wq instead. While at it, rename kstriped_ws to trigger_event so that it's consistent with other dm modules. Signed-off-by: Tejun Heo Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-stripe.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index f0371b4c4fbf..dddfa14f2982 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -39,23 +39,20 @@ struct stripe_c { struct dm_target *ti; /* Work struct used for triggering events*/ - struct work_struct kstriped_ws; + struct work_struct trigger_event; struct stripe stripe[0]; }; -static struct workqueue_struct *kstriped; - /* * An event is triggered whenever a drive * drops out of a stripe volume. */ static void trigger_event(struct work_struct *work) { - struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws); - + struct stripe_c *sc = container_of(work, struct stripe_c, + trigger_event); dm_table_event(sc->ti->table); - } static inline struct stripe_c *alloc_context(unsigned int stripes) @@ -160,7 +157,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) return -ENOMEM; } - INIT_WORK(&sc->kstriped_ws, trigger_event); + INIT_WORK(&sc->trigger_event, trigger_event); /* Set pointer to dm target; used in trigger_event */ sc->ti = ti; @@ -211,7 +208,7 @@ static void stripe_dtr(struct dm_target *ti) for (i = 0; i < sc->stripes; i++) dm_put_device(ti, sc->stripe[i].dev); - flush_workqueue(kstriped); + flush_work_sync(&sc->trigger_event); kfree(sc); } @@ -367,7 +364,7 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio, atomic_inc(&(sc->stripe[i].error_count)); if (atomic_read(&(sc->stripe[i].error_count)) < DM_IO_ERROR_THRESHOLD) - queue_work(kstriped, &sc->kstriped_ws); + schedule_work(&sc->trigger_event); } return error; @@ -401,7 +398,7 @@ static void stripe_io_hints(struct dm_target *ti, static struct target_type stripe_target = { .name = "striped", - .version = {1, 3, 0}, + .version = {1, 3, 1}, .module = THIS_MODULE, .ctr = stripe_ctr, .dtr = stripe_dtr, @@ -422,20 +419,10 @@ int __init dm_stripe_init(void) return r; } - kstriped = create_singlethread_workqueue("kstriped"); - if (!kstriped) { - DMERR("failed to create workqueue kstriped"); - dm_unregister_target(&stripe_target); - return -ENOMEM; - } - return r; } void dm_stripe_exit(void) { dm_unregister_target(&stripe_target); - destroy_workqueue(kstriped); - - return; } -- cgit v1.2.3 From 4d4d66ab5322fa9b0f51842a76139387a40e1ce9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 13 Jan 2011 19:59:57 +0000 Subject: dm: convert workqueues to alloc_ordered Convert all create[_singlethread]_work() users to the new alloc[_ordered]_workqueue(). This conversion is mechanical and doesn't introduce any behavior change. Signed-off-by: Tejun Heo Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-delay.c | 2 +- drivers/md/dm-kcopyd.c | 2 +- drivers/md/dm-mpath.c | 5 +++-- drivers/md/dm-raid1.c | 2 +- drivers/md/dm-snap-persistent.c | 2 +- drivers/md/dm.c | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index baa11912cc94..f18375dcedd9 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -352,7 +352,7 @@ static int __init dm_delay_init(void) { int r = -ENOMEM; - kdelayd_wq = create_workqueue("kdelayd"); + kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); if (!kdelayd_wq) { DMERR("Couldn't start kdelayd"); goto bad_queue; diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index dad32f8bce7d..63d67169c7f4 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -672,7 +672,7 @@ int dm_kcopyd_client_create(unsigned int nr_pages, goto bad_slab; INIT_WORK(&kc->kcopyd_work, do_work); - kc->kcopyd_wq = create_singlethread_workqueue("kcopyd"); + kc->kcopyd_wq = alloc_ordered_workqueue("kcopyd", WQ_MEM_RECLAIM); if (!kc->kcopyd_wq) goto bad_workqueue; diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index fcc59c3f756e..35ab5781f88f 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1675,7 +1675,7 @@ static int __init dm_multipath_init(void) return -EINVAL; } - kmultipathd = create_workqueue("kmpathd"); + kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); if (!kmultipathd) { DMERR("failed to create workqueue kmpathd"); dm_unregister_target(&multipath_target); @@ -1689,7 +1689,8 @@ static int __init dm_multipath_init(void) * old workqueue would also create a bottleneck in the * path of the storage hardware device activation. */ - kmpath_handlerd = create_singlethread_workqueue("kmpath_handlerd"); + kmpath_handlerd = alloc_ordered_workqueue("kmpath_handlerd", + WQ_MEM_RECLAIM); if (!kmpath_handlerd) { DMERR("failed to create workqueue kmpath_handlerd"); destroy_workqueue(kmultipathd); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 0d58b6f875cc..39917430f9f8 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1085,7 +1085,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->num_flush_requests = 1; ti->num_discard_requests = 1; - ms->kmirrord_wq = create_singlethread_workqueue("kmirrord"); + ms->kmirrord_wq = alloc_ordered_workqueue("kmirrord", WQ_MEM_RECLAIM); if (!ms->kmirrord_wq) { DMERR("couldn't start kmirrord"); r = -ENOMEM; diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 2129cdb115dc..d3021a69c857 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -818,7 +818,7 @@ static int persistent_ctr(struct dm_exception_store *store, atomic_set(&ps->pending_count, 0); ps->callbacks = NULL; - ps->metadata_wq = create_singlethread_workqueue("ksnaphd"); + ps->metadata_wq = alloc_ordered_workqueue("ksnaphd", WQ_MEM_RECLAIM); if (!ps->metadata_wq) { kfree(ps); DMERR("couldn't start header metadata update thread"); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0de692176ad4..39aaa9290128 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1883,7 +1883,7 @@ static struct mapped_device *alloc_dev(int minor) add_disk(md->disk); format_dev_t(md->name, MKDEV(_major, minor)); - md->wq = create_singlethread_workqueue("kdmflush"); + md->wq = alloc_ordered_workqueue("kdmflush", WQ_MEM_RECLAIM); if (!md->wq) goto bad_thread; -- cgit v1.2.3 From 9c4376de98719d2768dd919553843de34bb094a6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 13 Jan 2011 19:59:58 +0000 Subject: dm: use non reentrant workqueues if equivalent kmirrord_wq, kcopyd_work and md->wq are created per dm instance and serve only a single work item from the dm instance, so non-reentrant workqueues would provide the same ordering guarantees as ordered ones while allowing CPU affinity and use of the workqueues for other purposes. Switch them to non-reentrant workqueues. Signed-off-by: Tejun Heo Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-kcopyd.c | 3 ++- drivers/md/dm-raid1.c | 5 +++-- drivers/md/dm.c | 3 ++- include/linux/dm-ioctl.h | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 63d67169c7f4..924f5f0084c2 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -672,7 +672,8 @@ int dm_kcopyd_client_create(unsigned int nr_pages, goto bad_slab; INIT_WORK(&kc->kcopyd_work, do_work); - kc->kcopyd_wq = alloc_ordered_workqueue("kcopyd", WQ_MEM_RECLAIM); + kc->kcopyd_wq = alloc_workqueue("kcopyd", + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); if (!kc->kcopyd_wq) goto bad_workqueue; diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 39917430f9f8..dee326775c60 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1085,7 +1085,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->num_flush_requests = 1; ti->num_discard_requests = 1; - ms->kmirrord_wq = alloc_ordered_workqueue("kmirrord", WQ_MEM_RECLAIM); + ms->kmirrord_wq = alloc_workqueue("kmirrord", + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); if (!ms->kmirrord_wq) { DMERR("couldn't start kmirrord"); r = -ENOMEM; @@ -1414,7 +1415,7 @@ static int mirror_iterate_devices(struct dm_target *ti, static struct target_type mirror_target = { .name = "mirror", - .version = {1, 12, 0}, + .version = {1, 12, 1}, .module = THIS_MODULE, .ctr = mirror_ctr, .dtr = mirror_dtr, diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 39aaa9290128..e504bb40d60e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1883,7 +1883,8 @@ static struct mapped_device *alloc_dev(int minor) add_disk(md->disk); format_dev_t(md->name, MKDEV(_major, minor)); - md->wq = alloc_ordered_workqueue("kdmflush", WQ_MEM_RECLAIM); + md->wq = alloc_workqueue("kdmflush", + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); if (!md->wq) goto bad_thread; diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index e453e1174ae1..78bbf47bbb96 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -268,8 +268,8 @@ enum { #define DM_VERSION_MAJOR 4 #define DM_VERSION_MINOR 19 -#define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2010-10-14)" +#define DM_VERSION_PATCHLEVEL 1 +#define DM_VERSION_EXTRA "-ioctl (2011-01-07)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ -- cgit v1.2.3 From 239c8dd533e74de4a7f3c85c4f9f430eb08867c1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 13 Jan 2011 19:59:59 +0000 Subject: dm snapshot: persistent make metadata_wq multithreaded metadata_wq serves on-stack work items from chunk_io(). Even if multiple chunk_io() are simultaneously in progress, each is independent and queued only once, so multithreaded workqueue can be safely used. Switch metadata_wq to multithread and flush the work item instead of the workqueue in chunk_io(). Signed-off-by: Tejun Heo Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap-persistent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index d3021a69c857..95891dfcbca0 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -256,7 +256,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw, */ INIT_WORK_ONSTACK(&req.work, do_metadata); queue_work(ps->metadata_wq, &req.work); - flush_workqueue(ps->metadata_wq); + flush_work(&req.work); return req.result; } @@ -818,7 +818,7 @@ static int persistent_ctr(struct dm_exception_store *store, atomic_set(&ps->pending_count, 0); ps->callbacks = NULL; - ps->metadata_wq = alloc_ordered_workqueue("ksnaphd", WQ_MEM_RECLAIM); + ps->metadata_wq = alloc_workqueue("ksnaphd", WQ_MEM_RECLAIM, 0); if (!ps->metadata_wq) { kfree(ps); DMERR("couldn't start header metadata update thread"); -- cgit v1.2.3 From b83b2f295aec418c7501c05df4dfd168a79d165a Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 13 Jan 2011 19:59:59 +0000 Subject: dm snapshot: avoid storing private suspended state Use dm_suspended() rather than having each snapshot target maintain a private 'suspended' flag in struct dm_snapshot. Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 0f47698beafa..fdde53cd12b7 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -79,9 +79,6 @@ struct dm_snapshot { /* Origin writes don't trigger exceptions until this is set */ int active; - /* Whether or not owning mapped_device is suspended */ - int suspended; - atomic_t pending_exceptions_count; mempool_t *pending_pool; @@ -1102,7 +1099,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) s->ti = ti; s->valid = 1; s->active = 0; - s->suspended = 0; atomic_set(&s->pending_exceptions_count, 0); init_rwsem(&s->lock); INIT_LIST_HEAD(&s->list); @@ -1733,15 +1729,6 @@ static void snapshot_merge_presuspend(struct dm_target *ti) stop_merge(s); } -static void snapshot_postsuspend(struct dm_target *ti) -{ - struct dm_snapshot *s = ti->private; - - down_write(&s->lock); - s->suspended = 1; - up_write(&s->lock); -} - static int snapshot_preresume(struct dm_target *ti) { int r = 0; @@ -1756,7 +1743,7 @@ static int snapshot_preresume(struct dm_target *ti) DMERR("Unable to resume snapshot source until " "handover completes."); r = -EINVAL; - } else if (!snap_src->suspended) { + } else if (!dm_suspended(snap_src->ti)) { DMERR("Unable to perform snapshot handover until " "source is suspended."); r = -EINVAL; @@ -1789,7 +1776,6 @@ static void snapshot_resume(struct dm_target *ti) down_write(&s->lock); s->active = 1; - s->suspended = 0; up_write(&s->lock); } @@ -2167,7 +2153,7 @@ static int origin_iterate_devices(struct dm_target *ti, static struct target_type origin_target = { .name = "snapshot-origin", - .version = {1, 7, 0}, + .version = {1, 7, 1}, .module = THIS_MODULE, .ctr = origin_ctr, .dtr = origin_dtr, @@ -2180,13 +2166,12 @@ static struct target_type origin_target = { static struct target_type snapshot_target = { .name = "snapshot", - .version = {1, 9, 0}, + .version = {1, 10, 0}, .module = THIS_MODULE, .ctr = snapshot_ctr, .dtr = snapshot_dtr, .map = snapshot_map, .end_io = snapshot_end_io, - .postsuspend = snapshot_postsuspend, .preresume = snapshot_preresume, .resume = snapshot_resume, .status = snapshot_status, @@ -2195,14 +2180,13 @@ static struct target_type snapshot_target = { static struct target_type merge_target = { .name = dm_snapshot_merge_target_name, - .version = {1, 0, 0}, + .version = {1, 1, 0}, .module = THIS_MODULE, .ctr = snapshot_ctr, .dtr = snapshot_dtr, .map = snapshot_merge_map, .end_io = snapshot_end_io, .presuspend = snapshot_merge_presuspend, - .postsuspend = snapshot_postsuspend, .preresume = snapshot_preresume, .resume = snapshot_merge_resume, .status = snapshot_status, -- cgit v1.2.3 From dbc883f1570d992ba926a8c9e22140ba473c6cc1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Jan 2011 20:00:00 +0000 Subject: dm log: use PTR_ERR value instead of ENOMEM It's nicer to return the PTR_ERR() value instead of just returning -ENOMEM. In the current code the PTR_ERR() value is always equal to -ENOMEM so this doesn't actually affect anything, but still... In addition, dm_dirty_log_create() doesn't check for a specific -ENOMEM return. So this change is safe relative to potential for a non -ENOMEM return in the future. Signed-off-by: Dan Carpenter Acked-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 33420e68d153..6951536ea29c 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -455,7 +455,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, r = PTR_ERR(lc->io_req.client); DMWARN("couldn't allocate disk io client"); kfree(lc); - return -ENOMEM; + return r; } lc->disk_header = vmalloc(buf_size); -- cgit v1.2.3 From 052189a2ec956810feefb6a681416c5e6a207646 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Thu, 13 Jan 2011 20:00:00 +0000 Subject: dm: remove superfluous irq disablement in dm_request_fn This patch changes spin_lock_irq() to spin_lock() in dm_request_fn(). This patch is just a clean-up and no functional change. The spin_lock_irq() was leftover from the early request-based dm code, where map_request() used to enable interrupts. Since current map_request() never enables interrupts, we can change it to spin_lock() to match the prior spin_unlock(). Auditing through the dm and block-layer code called from map_request(), I confirmed all functions save/restore interrupt status, so no function returning with interrupts enabled. Also I haven't observed any problem on my test environment which uses scsi and lpfc driver after heavy I/O testing with occasional path down/up. Added BUG_ON() to detect breakage in future. Signed-off-by: Kiyoshi Ueda Signed-off-by: Jun'ichi Nomura Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index e504bb40d60e..eaa3af0e0632 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1637,13 +1637,15 @@ static void dm_request_fn(struct request_queue *q) if (map_request(ti, clone, md)) goto requeued; - spin_lock_irq(q->queue_lock); + BUG_ON(!irqs_disabled()); + spin_lock(q->queue_lock); } goto out; requeued: - spin_lock_irq(q->queue_lock); + BUG_ON(!irqs_disabled()); + spin_lock(q->queue_lock); plug_and_out: if (!elv_queue_empty(q)) -- cgit v1.2.3 From 4e2d19e46b507018c6ed15f6c081d8f887ae229c Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Thu, 13 Jan 2011 20:00:01 +0000 Subject: dm mpath: delay activate_path retry on SCSI_DH_RETRY This patch adds a user-configurable 'pg_init_delay_msecs' feature. Use this feature to specify the number of milliseconds to delay before retrying scsi_dh_activate, when SCSI_DH_RETRY is returned. SCSI Device Handlers return SCSI_DH_IMM_RETRY if we could retry activation immediately and SCSI_DH_RETRY in cases where it is better to retry after some delay. Currently we immediately retry scsi_dh_activate irrespective of SCSI_DH_IMM_RETRY and SCSI_DH_RETRY. The 'pg_init_delay_msecs' feature may be provided during table create or load, e.g.: dmsetup create --table "0 20971520 multipath 3 queue_if_no_path \ pg_init_delay_msecs 2500 ..." mpatha The default for 'pg_init_delay_msecs' is 2000 milliseconds. Maximum configurable delay is 60000 milliseconds. Specifying a 'pg_init_delay_msecs' of 0 will cause immediate retry. Signed-off-by: Nikanth Karthikesan Signed-off-by: Chandra Seetharaman Acked-by: Mike Christie Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-mpath.c | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 35ab5781f88f..b82d28819e2a 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -23,6 +23,8 @@ #define DM_MSG_PREFIX "multipath" #define MESG_STR(x) x, sizeof(x) +#define DM_PG_INIT_DELAY_MSECS 2000 +#define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1) /* Path properties */ struct pgpath { @@ -33,7 +35,7 @@ struct pgpath { unsigned fail_count; /* Cumulative failure count */ struct dm_path path; - struct work_struct activate_path; + struct delayed_work activate_path; }; #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path) @@ -64,11 +66,15 @@ struct multipath { const char *hw_handler_name; char *hw_handler_params; + unsigned nr_priority_groups; struct list_head priority_groups; + + wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */ + unsigned pg_init_required; /* pg_init needs calling? */ unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ - wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */ + unsigned pg_init_delay_retry; /* Delay pg_init retry? */ unsigned nr_valid_paths; /* Total number of usable paths */ struct pgpath *current_pgpath; @@ -81,6 +87,7 @@ struct multipath { unsigned saved_queue_if_no_path;/* Saved state during suspension */ unsigned pg_init_retries; /* Number of times to retry pg_init */ unsigned pg_init_count; /* Number of times pg_init called */ + unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */ struct work_struct process_queued_ios; struct list_head queued_ios; @@ -127,7 +134,7 @@ static struct pgpath *alloc_pgpath(void) if (pgpath) { pgpath->is_active = 1; - INIT_WORK(&pgpath->activate_path, activate_path); + INIT_DELAYED_WORK(&pgpath->activate_path, activate_path); } return pgpath; @@ -188,6 +195,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti) INIT_LIST_HEAD(&m->queued_ios); spin_lock_init(&m->lock); m->queue_io = 1; + m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT; INIT_WORK(&m->process_queued_ios, process_queued_ios); INIT_WORK(&m->trigger_event, trigger_event); init_waitqueue_head(&m->pg_init_wait); @@ -227,14 +235,19 @@ static void free_multipath(struct multipath *m) static void __pg_init_all_paths(struct multipath *m) { struct pgpath *pgpath; + unsigned long pg_init_delay = 0; m->pg_init_count++; m->pg_init_required = 0; + if (m->pg_init_delay_retry) + pg_init_delay = msecs_to_jiffies(m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT ? + m->pg_init_delay_msecs : DM_PG_INIT_DELAY_MSECS); list_for_each_entry(pgpath, &m->current_pg->pgpaths, list) { /* Skip failed paths */ if (!pgpath->is_active) continue; - if (queue_work(kmpath_handlerd, &pgpath->activate_path)) + if (queue_delayed_work(kmpath_handlerd, &pgpath->activate_path, + pg_init_delay)) m->pg_init_in_progress++; } } @@ -782,8 +795,9 @@ static int parse_features(struct arg_set *as, struct multipath *m) const char *param_name; static struct param _params[] = { - {0, 3, "invalid number of feature args"}, + {0, 5, "invalid number of feature args"}, {1, 50, "pg_init_retries must be between 1 and 50"}, + {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, }; r = read_param(_params, shift(as), &argc, &ti->error); @@ -810,6 +824,14 @@ static int parse_features(struct arg_set *as, struct multipath *m) continue; } + if (!strnicmp(param_name, MESG_STR("pg_init_delay_msecs")) && + (argc >= 1)) { + r = read_param(_params + 2, shift(as), + &m->pg_init_delay_msecs, &ti->error); + argc--; + continue; + } + ti->error = "Unrecognised multipath feature request"; r = -EINVAL; } while (argc && !r); @@ -1022,7 +1044,7 @@ static int reinstate_path(struct pgpath *pgpath) m->current_pgpath = NULL; queue_work(kmultipathd, &m->process_queued_ios); } else if (m->hw_handler_name && (m->current_pg == pgpath->pg)) { - if (queue_work(kmpath_handlerd, &pgpath->activate_path)) + if (queue_work(kmpath_handlerd, &pgpath->activate_path.work)) m->pg_init_in_progress++; } @@ -1157,6 +1179,7 @@ static void pg_init_done(void *data, int errors) struct priority_group *pg = pgpath->pg; struct multipath *m = pg->m; unsigned long flags; + unsigned delay_retry = 0; /* device or driver problems */ switch (errors) { @@ -1181,8 +1204,9 @@ static void pg_init_done(void *data, int errors) */ bypass_pg(m, pg, 1); break; - /* TODO: For SCSI_DH_RETRY we should wait a couple seconds */ case SCSI_DH_RETRY: + /* Wait before retrying. */ + delay_retry = 1; case SCSI_DH_IMM_RETRY: case SCSI_DH_RES_TEMP_UNAVAIL: if (pg_init_limit_reached(m, pgpath)) @@ -1215,6 +1239,7 @@ static void pg_init_done(void *data, int errors) if (!m->pg_init_required) m->queue_io = 0; + m->pg_init_delay_retry = delay_retry; queue_work(kmultipathd, &m->process_queued_ios); /* @@ -1229,7 +1254,7 @@ out: static void activate_path(struct work_struct *work) { struct pgpath *pgpath = - container_of(work, struct pgpath, activate_path); + container_of(work, struct pgpath, activate_path.work); scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev), pg_init_done, pgpath); @@ -1370,11 +1395,14 @@ static int multipath_status(struct dm_target *ti, status_type_t type, DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count); else { DMEMIT("%u ", m->queue_if_no_path + - (m->pg_init_retries > 0) * 2); + (m->pg_init_retries > 0) * 2 + + (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2); if (m->queue_if_no_path) DMEMIT("queue_if_no_path "); if (m->pg_init_retries) DMEMIT("pg_init_retries %u ", m->pg_init_retries); + if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) + DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); } if (!m->hw_handler_name || type == STATUSTYPE_INFO) @@ -1643,7 +1671,7 @@ out: *---------------------------------------------------------------*/ static struct target_type multipath_target = { .name = "multipath", - .version = {1, 1, 1}, + .version = {1, 2, 0}, .module = THIS_MODULE, .ctr = multipath_ctr, .dtr = multipath_dtr, -- cgit v1.2.3 From 9d357b0787bb3c91835d5e658c3bda178f9ca419 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 13 Jan 2011 20:00:01 +0000 Subject: dm: introduce target callbacks and congestion callback DM currently implements congestion checking by checking on congestion in each component device. For raid456 we need to also check if the stripe cache is congested. Add per-target congestion checker callback support. Extending the target_callbacks structure with additional callback functions allows for establishing multiple callbacks per-target (a callback is also needed for unplug). Cc: linux-raid@vger.kernel.org Signed-off-by: NeilBrown Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-table.c | 14 ++++++++++++++ include/linux/device-mapper.h | 11 +++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 985c20a4f30e..7e2ec3c05550 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -71,6 +71,8 @@ struct dm_table { void *event_context; struct dm_md_mempools *mempools; + + struct list_head target_callbacks; }; /* @@ -204,6 +206,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode, return -ENOMEM; INIT_LIST_HEAD(&t->devices); + INIT_LIST_HEAD(&t->target_callbacks); atomic_set(&t->holders, 0); t->discards_supported = 1; @@ -1225,10 +1228,17 @@ int dm_table_resume_targets(struct dm_table *t) return 0; } +void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb) +{ + list_add(&cb->list, &t->target_callbacks); +} +EXPORT_SYMBOL_GPL(dm_table_add_target_callbacks); + int dm_table_any_congested(struct dm_table *t, int bdi_bits) { struct dm_dev_internal *dd; struct list_head *devices = dm_table_get_devices(t); + struct dm_target_callbacks *cb; int r = 0; list_for_each_entry(dd, devices, list) { @@ -1243,6 +1253,10 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits) bdevname(dd->dm_dev.bdev, b)); } + list_for_each_entry(cb, &t->target_callbacks, list) + if (cb->congested_fn) + r |= cb->congested_fn(cb, bdi_bits); + return r; } diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 2970022faa63..4b1c63d478ab 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -193,6 +193,12 @@ struct dm_target { char *error; }; +/* Each target can link one of these into the table */ +struct dm_target_callbacks { + struct list_head list; + int (*congested_fn) (struct dm_target_callbacks *, int); +}; + int dm_register_target(struct target_type *t); void dm_unregister_target(struct target_type *t); @@ -268,6 +274,11 @@ int dm_table_create(struct dm_table **result, fmode_t mode, int dm_table_add_target(struct dm_table *t, const char *type, sector_t start, sector_t len, char *params); +/* + * Target_ctr should call this if it needs to add any callbacks. + */ +void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb); + /* * Finally call this to make the table ready for use. */ -- cgit v1.2.3 From 99d03c141b40914b67d63c9d23b8da4386422ed7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 13 Jan 2011 20:00:02 +0000 Subject: dm: per target unplug callback support Add per-target unplug callback support. Cc: linux-raid@vger.kernel.org Signed-off-by: NeilBrown Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-table.c | 5 +++++ include/linux/device-mapper.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 7e2ec3c05550..dffa0ac7c4f0 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1278,6 +1278,7 @@ void dm_table_unplug_all(struct dm_table *t) { struct dm_dev_internal *dd; struct list_head *devices = dm_table_get_devices(t); + struct dm_target_callbacks *cb; list_for_each_entry(dd, devices, list) { struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev); @@ -1290,6 +1291,10 @@ void dm_table_unplug_all(struct dm_table *t) dm_device_name(t->md), bdevname(dd->dm_dev.bdev, b)); } + + list_for_each_entry(cb, &t->target_callbacks, list) + if (cb->unplug_fn) + cb->unplug_fn(cb); } struct mapped_device *dm_table_get_md(struct dm_table *t) diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 4b1c63d478ab..272496d1fae4 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -197,6 +197,7 @@ struct dm_target { struct dm_target_callbacks { struct list_head list; int (*congested_fn) (struct dm_target_callbacks *, int); + void (*unplug_fn)(struct dm_target_callbacks *); }; int dm_register_target(struct target_type *t); -- cgit v1.2.3 From 9d09e663d5502c46f2d9481c04c1087e1c2da698 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 13 Jan 2011 20:00:02 +0000 Subject: dm: raid456 basic support This patch is the skeleton for the DM target that will be the bridge from DM to MD (initially RAID456 and later RAID1). It provides a way to use device-mapper interfaces to the MD RAID456 drivers. As with all device-mapper targets, the nominal public interfaces are the constructor (CTR) tables and the status outputs (both STATUSTYPE_INFO and STATUSTYPE_TABLE). The CTR table looks like the following: 1: raid \ 2: <#raid_params> \ 3: <#raid_devs> .. Line 1 contains the standard first three arguments to any device-mapper target - the start, length, and target type fields. The target type in this case is "raid". Line 2 contains the arguments that define the particular raid type/personality/level, the required arguments for that raid type, and any optional arguments. Possible raid types include: raid4, raid5_la, raid5_ls, raid5_rs, raid6_zr, raid6_nr, and raid6_nc. (again, raid1 is planned for the future.) The list of required and optional parameters is the same for all the current raid types. The required parameters are positional, while the optional parameters are given as key/value pairs. The possible parameters are as follows: Chunk size in sectors. [[no]sync] Force/Prevent RAID initialization [rebuild ] Rebuild the drive indicated by the index [daemon_sleep ] Time between bitmap daemon work to clear bits [min_recovery_rate ] Throttle RAID initialization [max_recovery_rate ] Throttle RAID initialization [max_write_behind ] See '-write-behind=' (man mdadm) [stripe_cache ] Stripe cache size for higher RAIDs Line 3 contains the list of devices that compose the array in metadata/data device pairs. If the metadata is stored separately, a '-' is given for the metadata device position. If a drive has failed or is missing at creation time, a '-' can be given for both the metadata and data drives for a given position. Examples: # RAID4 - 4 data drives, 1 parity # No metadata devices specified to hold superblock/bitmap info # Chunk size of 1MiB # (Lines separated for easy reading) 0 1960893648 raid \ raid4 1 2048 \ 5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81 # RAID4 - 4 data drives, 1 parity (no metadata devices) # Chunk size of 1MiB, force RAID initialization, # min recovery rate at 20 kiB/sec/disk 0 1960893648 raid \ raid4 4 2048 min_recovery_rate 20 sync\ 5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81 Performing a 'dmsetup table' should display the CTR table used to construct the mapping (with possible reordering of optional parameters). Performing a 'dmsetup status' will yield information on the state and health of the array. The output is as follows: 1: raid \ 2: <#devices> <1 health char for each dev> Line 1 is standard DM output. Line 2 is best shown by example: 0 1960893648 raid raid4 5 AAAAA 2/490221568 Here we can see the RAID type is raid4, there are 5 devices - all of which are 'A'live, and the array is 2/490221568 complete with recovery. Cc: linux-raid@vger.kernel.org Signed-off-by: NeilBrown Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- Documentation/device-mapper/dm-raid.txt | 70 ++++ drivers/md/Kconfig | 24 ++ drivers/md/Makefile | 1 + drivers/md/dm-raid.c | 697 ++++++++++++++++++++++++++++++++ 4 files changed, 792 insertions(+) create mode 100644 Documentation/device-mapper/dm-raid.txt create mode 100644 drivers/md/dm-raid.c (limited to 'drivers') diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt new file mode 100644 index 000000000000..33b6b7071ac8 --- /dev/null +++ b/Documentation/device-mapper/dm-raid.txt @@ -0,0 +1,70 @@ +Device-mapper RAID (dm-raid) is a bridge from DM to MD. It +provides a way to use device-mapper interfaces to access the MD RAID +drivers. + +As with all device-mapper targets, the nominal public interfaces are the +constructor (CTR) tables and the status outputs (both STATUSTYPE_INFO +and STATUSTYPE_TABLE). The CTR table looks like the following: + +1: raid \ +2: <#raid_params> \ +3: <#raid_devs> .. + +Line 1 contains the standard first three arguments to any device-mapper +target - the start, length, and target type fields. The target type in +this case is "raid". + +Line 2 contains the arguments that define the particular raid +type/personality/level, the required arguments for that raid type, and +any optional arguments. Possible raid types include: raid4, raid5_la, +raid5_ls, raid5_rs, raid6_zr, raid6_nr, and raid6_nc. (raid1 is +planned for the future.) The list of required and optional parameters +is the same for all the current raid types. The required parameters are +positional, while the optional parameters are given as key/value pairs. +The possible parameters are as follows: + Chunk size in sectors. + [[no]sync] Force/Prevent RAID initialization + [rebuild ] Rebuild the drive indicated by the index + [daemon_sleep ] Time between bitmap daemon work to clear bits + [min_recovery_rate ] Throttle RAID initialization + [max_recovery_rate ] Throttle RAID initialization + [max_write_behind ] See '-write-behind=' (man mdadm) + [stripe_cache ] Stripe cache size for higher RAIDs + +Line 3 contains the list of devices that compose the array in +metadata/data device pairs. If the metadata is stored separately, a '-' +is given for the metadata device position. If a drive has failed or is +missing at creation time, a '-' can be given for both the metadata and +data drives for a given position. + +NB. Currently all metadata devices must be specified as '-'. + +Examples: +# RAID4 - 4 data drives, 1 parity +# No metadata devices specified to hold superblock/bitmap info +# Chunk size of 1MiB +# (Lines separated for easy reading) +0 1960893648 raid \ + raid4 1 2048 \ + 5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81 + +# RAID4 - 4 data drives, 1 parity (no metadata devices) +# Chunk size of 1MiB, force RAID initialization, +# min recovery rate at 20 kiB/sec/disk +0 1960893648 raid \ + raid4 4 2048 min_recovery_rate 20 sync\ + 5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81 + +Performing a 'dmsetup table' should display the CTR table used to +construct the mapping (with possible reordering of optional +parameters). + +Performing a 'dmsetup status' will yield information on the state and +health of the array. The output is as follows: +1: raid \ +2: <#devices> <1 health char for each dev> + +Line 1 is standard DM output. Line 2 is best shown by example: + 0 1960893648 raid raid4 5 AAAAA 2/490221568 +Here we can see the RAID type is raid4, there are 5 devices - all of +which are 'A'live, and the array is 2/490221568 complete with recovery. diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index bf1a95e31559..98d9ec85e0eb 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -240,6 +240,30 @@ config DM_MIRROR Allow volume managers to mirror logical volumes, also needed for live data migration tools such as 'pvmove'. +config DM_RAID + tristate "RAID 4/5/6 target (EXPERIMENTAL)" + depends on BLK_DEV_DM && EXPERIMENTAL + select MD_RAID456 + select BLK_DEV_MD + ---help--- + A dm target that supports RAID4, RAID5 and RAID6 mappings + + A RAID-5 set of N drives with a capacity of C MB per drive provides + the capacity of C * (N - 1) MB, and protects against a failure + of a single drive. For a given sector (row) number, (N - 1) drives + contain data sectors, and one drive contains the parity protection. + For a RAID-4 set, the parity blocks are present on a single drive, + while a RAID-5 set distributes the parity across the drives in one + of the available parity distribution methods. + + A RAID-6 set of N drives with a capacity of C MB per drive + provides the capacity of C * (N - 2) MB, and protects + against a failure of any two drives. For a given sector + (row) number, (N - 2) drives contain data sectors, and two + drives contains two independent redundancy syndromes. Like + RAID-5, RAID-6 distributes the syndromes across the drives + in one of the available parity distribution methods. + config DM_LOG_USERSPACE tristate "Mirror userspace logging (EXPERIMENTAL)" depends on DM_MIRROR && EXPERIMENTAL && NET diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 5e3aac41919d..d0138606c2e8 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o obj-$(CONFIG_DM_ZERO) += dm-zero.o +obj-$(CONFIG_DM_RAID) += dm-raid.o ifeq ($(CONFIG_DM_UEVENT),y) dm-mod-objs += dm-uevent.o diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c new file mode 100644 index 000000000000..b9e1e15ef11c --- /dev/null +++ b/drivers/md/dm-raid.c @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2010-2011 Neil Brown + * Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved. + * + * This file is released under the GPL. + */ + +#include + +#include "md.h" +#include "raid5.h" +#include "dm.h" +#include "bitmap.h" + +#define DM_MSG_PREFIX "raid" + +/* + * If the MD doesn't support MD_SYNC_STATE_FORCED yet, then + * make it so the flag doesn't set anything. + */ +#ifndef MD_SYNC_STATE_FORCED +#define MD_SYNC_STATE_FORCED 0 +#endif + +struct raid_dev { + /* + * Two DM devices, one to hold metadata and one to hold the + * actual data/parity. The reason for this is to not confuse + * ti->len and give more flexibility in altering size and + * characteristics. + * + * While it is possible for this device to be associated + * with a different physical device than the data_dev, it + * is intended for it to be the same. + * |--------- Physical Device ---------| + * |- meta_dev -|------ data_dev ------| + */ + struct dm_dev *meta_dev; + struct dm_dev *data_dev; + struct mdk_rdev_s rdev; +}; + +/* + * Flags for rs->print_flags field. + */ +#define DMPF_DAEMON_SLEEP 0x1 +#define DMPF_MAX_WRITE_BEHIND 0x2 +#define DMPF_SYNC 0x4 +#define DMPF_NOSYNC 0x8 +#define DMPF_STRIPE_CACHE 0x10 +#define DMPF_MIN_RECOVERY_RATE 0x20 +#define DMPF_MAX_RECOVERY_RATE 0x40 + +struct raid_set { + struct dm_target *ti; + + uint64_t print_flags; + + struct mddev_s md; + struct raid_type *raid_type; + struct dm_target_callbacks callbacks; + + struct raid_dev dev[0]; +}; + +/* Supported raid types and properties. */ +static struct raid_type { + const char *name; /* RAID algorithm. */ + const char *descr; /* Descriptor text for logging. */ + const unsigned parity_devs; /* # of parity devices. */ + const unsigned minimal_devs; /* minimal # of devices in set. */ + const unsigned level; /* RAID level. */ + const unsigned algorithm; /* RAID algorithm. */ +} raid_types[] = { + {"raid4", "RAID4 (dedicated parity disk)", 1, 2, 5, ALGORITHM_PARITY_0}, + {"raid5_la", "RAID5 (left asymmetric)", 1, 2, 5, ALGORITHM_LEFT_ASYMMETRIC}, + {"raid5_ra", "RAID5 (right asymmetric)", 1, 2, 5, ALGORITHM_RIGHT_ASYMMETRIC}, + {"raid5_ls", "RAID5 (left symmetric)", 1, 2, 5, ALGORITHM_LEFT_SYMMETRIC}, + {"raid5_rs", "RAID5 (right symmetric)", 1, 2, 5, ALGORITHM_RIGHT_SYMMETRIC}, + {"raid6_zr", "RAID6 (zero restart)", 2, 4, 6, ALGORITHM_ROTATING_ZERO_RESTART}, + {"raid6_nr", "RAID6 (N restart)", 2, 4, 6, ALGORITHM_ROTATING_N_RESTART}, + {"raid6_nc", "RAID6 (N continue)", 2, 4, 6, ALGORITHM_ROTATING_N_CONTINUE} +}; + +static struct raid_type *get_raid_type(char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(raid_types); i++) + if (!strcmp(raid_types[i].name, name)) + return &raid_types[i]; + + return NULL; +} + +static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *raid_type, unsigned raid_devs) +{ + unsigned i; + struct raid_set *rs; + sector_t sectors_per_dev; + + if (raid_devs <= raid_type->parity_devs) { + ti->error = "Insufficient number of devices"; + return ERR_PTR(-EINVAL); + } + + sectors_per_dev = ti->len; + if (sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) { + ti->error = "Target length not divisible by number of data devices"; + return ERR_PTR(-EINVAL); + } + + rs = kzalloc(sizeof(*rs) + raid_devs * sizeof(rs->dev[0]), GFP_KERNEL); + if (!rs) { + ti->error = "Cannot allocate raid context"; + return ERR_PTR(-ENOMEM); + } + + mddev_init(&rs->md); + + rs->ti = ti; + rs->raid_type = raid_type; + rs->md.raid_disks = raid_devs; + rs->md.level = raid_type->level; + rs->md.new_level = rs->md.level; + rs->md.dev_sectors = sectors_per_dev; + rs->md.layout = raid_type->algorithm; + rs->md.new_layout = rs->md.layout; + rs->md.delta_disks = 0; + rs->md.recovery_cp = 0; + + for (i = 0; i < raid_devs; i++) + md_rdev_init(&rs->dev[i].rdev); + + /* + * Remaining items to be initialized by further RAID params: + * rs->md.persistent + * rs->md.external + * rs->md.chunk_sectors + * rs->md.new_chunk_sectors + */ + + return rs; +} + +static void context_free(struct raid_set *rs) +{ + int i; + + for (i = 0; i < rs->md.raid_disks; i++) + if (rs->dev[i].data_dev) + dm_put_device(rs->ti, rs->dev[i].data_dev); + + kfree(rs); +} + +/* + * For every device we have two words + * : meta device name or '-' if missing + * : data device name or '-' if missing + * + * This code parses those words. + */ +static int dev_parms(struct raid_set *rs, char **argv) +{ + int i; + int rebuild = 0; + int metadata_available = 0; + int ret = 0; + + for (i = 0; i < rs->md.raid_disks; i++, argv += 2) { + rs->dev[i].rdev.raid_disk = i; + + rs->dev[i].meta_dev = NULL; + rs->dev[i].data_dev = NULL; + + /* + * There are no offsets, since there is a separate device + * for data and metadata. + */ + rs->dev[i].rdev.data_offset = 0; + rs->dev[i].rdev.mddev = &rs->md; + + if (strcmp(argv[0], "-")) { + rs->ti->error = "Metadata devices not supported"; + return -EINVAL; + } + + if (!strcmp(argv[1], "-")) { + if (!test_bit(In_sync, &rs->dev[i].rdev.flags) && + (!rs->dev[i].rdev.recovery_offset)) { + rs->ti->error = "Drive designated for rebuild not specified"; + return -EINVAL; + } + + continue; + } + + ret = dm_get_device(rs->ti, argv[1], + dm_table_get_mode(rs->ti->table), + &rs->dev[i].data_dev); + if (ret) { + rs->ti->error = "RAID device lookup failure"; + return ret; + } + + rs->dev[i].rdev.bdev = rs->dev[i].data_dev->bdev; + list_add(&rs->dev[i].rdev.same_set, &rs->md.disks); + if (!test_bit(In_sync, &rs->dev[i].rdev.flags)) + rebuild++; + } + + if (metadata_available) { + rs->md.external = 0; + rs->md.persistent = 1; + rs->md.major_version = 2; + } else if (rebuild && !rs->md.recovery_cp) { + /* + * Without metadata, we will not be able to tell if the array + * is in-sync or not - we must assume it is not. Therefore, + * it is impossible to rebuild a drive. + * + * Even if there is metadata, the on-disk information may + * indicate that the array is not in-sync and it will then + * fail at that time. + * + * User could specify 'nosync' option if desperate. + */ + DMERR("Unable to rebuild drive while array is not in-sync"); + rs->ti->error = "RAID device lookup failure"; + return -EINVAL; + } + + return 0; +} + +/* + * Possible arguments are... + * RAID456: + * [optional_args] + * + * Optional args: + * [[no]sync] Force or prevent recovery of the entire array + * [rebuild ] Rebuild the drive indicated by the index + * [daemon_sleep ] Time between bitmap daemon work to clear bits + * [min_recovery_rate ] Throttle RAID initialization + * [max_recovery_rate ] Throttle RAID initialization + * [max_write_behind ] See '-write-behind=' (man mdadm) + * [stripe_cache ] Stripe cache size for higher RAIDs + */ +static int parse_raid_params(struct raid_set *rs, char **argv, + unsigned num_raid_params) +{ + unsigned i, rebuild_cnt = 0; + unsigned long value; + char *key; + + /* + * First, parse the in-order required arguments + */ + if ((strict_strtoul(argv[0], 10, &value) < 0) || + !is_power_of_2(value) || (value < 8)) { + rs->ti->error = "Bad chunk size"; + return -EINVAL; + } + + rs->md.new_chunk_sectors = rs->md.chunk_sectors = value; + argv++; + num_raid_params--; + + /* + * Second, parse the unordered optional arguments + */ + for (i = 0; i < rs->md.raid_disks; i++) + set_bit(In_sync, &rs->dev[i].rdev.flags); + + for (i = 0; i < num_raid_params; i++) { + if (!strcmp(argv[i], "nosync")) { + rs->md.recovery_cp = MaxSector; + rs->print_flags |= DMPF_NOSYNC; + rs->md.flags |= MD_SYNC_STATE_FORCED; + continue; + } + if (!strcmp(argv[i], "sync")) { + rs->md.recovery_cp = 0; + rs->print_flags |= DMPF_SYNC; + rs->md.flags |= MD_SYNC_STATE_FORCED; + continue; + } + + /* The rest of the optional arguments come in key/value pairs */ + if ((i + 1) >= num_raid_params) { + rs->ti->error = "Wrong number of raid parameters given"; + return -EINVAL; + } + + key = argv[i++]; + if (strict_strtoul(argv[i], 10, &value) < 0) { + rs->ti->error = "Bad numerical argument given in raid params"; + return -EINVAL; + } + + if (!strcmp(key, "rebuild")) { + if (++rebuild_cnt > rs->raid_type->parity_devs) { + rs->ti->error = "Too many rebuild drives given"; + return -EINVAL; + } + if (value > rs->md.raid_disks) { + rs->ti->error = "Invalid rebuild index given"; + return -EINVAL; + } + clear_bit(In_sync, &rs->dev[value].rdev.flags); + rs->dev[value].rdev.recovery_offset = 0; + } else if (!strcmp(key, "max_write_behind")) { + rs->print_flags |= DMPF_MAX_WRITE_BEHIND; + + /* + * In device-mapper, we specify things in sectors, but + * MD records this value in kB + */ + value /= 2; + if (value > COUNTER_MAX) { + rs->ti->error = "Max write-behind limit out of range"; + return -EINVAL; + } + rs->md.bitmap_info.max_write_behind = value; + } else if (!strcmp(key, "daemon_sleep")) { + rs->print_flags |= DMPF_DAEMON_SLEEP; + if (!value || (value > MAX_SCHEDULE_TIMEOUT)) { + rs->ti->error = "daemon sleep period out of range"; + return -EINVAL; + } + rs->md.bitmap_info.daemon_sleep = value; + } else if (!strcmp(key, "stripe_cache")) { + rs->print_flags |= DMPF_STRIPE_CACHE; + + /* + * In device-mapper, we specify things in sectors, but + * MD records this value in kB + */ + value /= 2; + + if (rs->raid_type->level < 5) { + rs->ti->error = "Inappropriate argument: stripe_cache"; + return -EINVAL; + } + if (raid5_set_cache_size(&rs->md, (int)value)) { + rs->ti->error = "Bad stripe_cache size"; + return -EINVAL; + } + } else if (!strcmp(key, "min_recovery_rate")) { + rs->print_flags |= DMPF_MIN_RECOVERY_RATE; + if (value > INT_MAX) { + rs->ti->error = "min_recovery_rate out of range"; + return -EINVAL; + } + rs->md.sync_speed_min = (int)value; + } else if (!strcmp(key, "max_recovery_rate")) { + rs->print_flags |= DMPF_MAX_RECOVERY_RATE; + if (value > INT_MAX) { + rs->ti->error = "max_recovery_rate out of range"; + return -EINVAL; + } + rs->md.sync_speed_max = (int)value; + } else { + DMERR("Unable to parse RAID parameter: %s", key); + rs->ti->error = "Unable to parse RAID parameters"; + return -EINVAL; + } + } + + /* Assume there are no metadata devices until the drives are parsed */ + rs->md.persistent = 0; + rs->md.external = 1; + + return 0; +} + +static void do_table_event(struct work_struct *ws) +{ + struct raid_set *rs = container_of(ws, struct raid_set, md.event_work); + + dm_table_event(rs->ti->table); +} + +static int raid_is_congested(struct dm_target_callbacks *cb, int bits) +{ + struct raid_set *rs = container_of(cb, struct raid_set, callbacks); + + return md_raid5_congested(&rs->md, bits); +} + +static void raid_unplug(struct dm_target_callbacks *cb) +{ + struct raid_set *rs = container_of(cb, struct raid_set, callbacks); + + md_raid5_unplug_device(rs->md.private); +} + +/* + * Construct a RAID4/5/6 mapping: + * Args: + * <#raid_params> \ + * <#raid_devs> { .. } + * + * ** metadata devices are not supported yet, use '-' instead ** + * + * varies by . See 'parse_raid_params' for + * details on possible . + */ +static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) +{ + int ret; + struct raid_type *rt; + unsigned long num_raid_params, num_raid_devs; + struct raid_set *rs = NULL; + + /* Must have at least <#raid_params> */ + if (argc < 2) { + ti->error = "Too few arguments"; + return -EINVAL; + } + + /* raid type */ + rt = get_raid_type(argv[0]); + if (!rt) { + ti->error = "Unrecognised raid_type"; + return -EINVAL; + } + argc--; + argv++; + + /* number of RAID parameters */ + if (strict_strtoul(argv[0], 10, &num_raid_params) < 0) { + ti->error = "Cannot understand number of RAID parameters"; + return -EINVAL; + } + argc--; + argv++; + + /* Skip over RAID params for now and find out # of devices */ + if (num_raid_params + 1 > argc) { + ti->error = "Arguments do not agree with counts given"; + return -EINVAL; + } + + if ((strict_strtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) || + (num_raid_devs >= INT_MAX)) { + ti->error = "Cannot understand number of raid devices"; + return -EINVAL; + } + + rs = context_alloc(ti, rt, (unsigned)num_raid_devs); + if (IS_ERR(rs)) + return PTR_ERR(rs); + + ret = parse_raid_params(rs, argv, (unsigned)num_raid_params); + if (ret) + goto bad; + + ret = -EINVAL; + + argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */ + argv += num_raid_params + 1; + + if (argc != (num_raid_devs * 2)) { + ti->error = "Supplied RAID devices does not match the count given"; + goto bad; + } + + ret = dev_parms(rs, argv); + if (ret) + goto bad; + + INIT_WORK(&rs->md.event_work, do_table_event); + ti->split_io = rs->md.chunk_sectors; + ti->private = rs; + + mutex_lock(&rs->md.reconfig_mutex); + ret = md_run(&rs->md); + rs->md.in_sync = 0; /* Assume already marked dirty */ + mutex_unlock(&rs->md.reconfig_mutex); + + if (ret) { + ti->error = "Fail to run raid array"; + goto bad; + } + + rs->callbacks.congested_fn = raid_is_congested; + rs->callbacks.unplug_fn = raid_unplug; + dm_table_add_target_callbacks(ti->table, &rs->callbacks); + + return 0; + +bad: + context_free(rs); + + return ret; +} + +static void raid_dtr(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + + list_del_init(&rs->callbacks.list); + md_stop(&rs->md); + context_free(rs); +} + +static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_context) +{ + struct raid_set *rs = ti->private; + mddev_t *mddev = &rs->md; + + mddev->pers->make_request(mddev, bio); + + return DM_MAPIO_SUBMITTED; +} + +static int raid_status(struct dm_target *ti, status_type_t type, + char *result, unsigned maxlen) +{ + struct raid_set *rs = ti->private; + unsigned raid_param_cnt = 1; /* at least 1 for chunksize */ + unsigned sz = 0; + int i; + sector_t sync; + + switch (type) { + case STATUSTYPE_INFO: + DMEMIT("%s %d ", rs->raid_type->name, rs->md.raid_disks); + + for (i = 0; i < rs->md.raid_disks; i++) { + if (test_bit(Faulty, &rs->dev[i].rdev.flags)) + DMEMIT("D"); + else if (test_bit(In_sync, &rs->dev[i].rdev.flags)) + DMEMIT("A"); + else + DMEMIT("a"); + } + + if (test_bit(MD_RECOVERY_RUNNING, &rs->md.recovery)) + sync = rs->md.curr_resync_completed; + else + sync = rs->md.recovery_cp; + + if (sync > rs->md.resync_max_sectors) + sync = rs->md.resync_max_sectors; + + DMEMIT(" %llu/%llu", + (unsigned long long) sync, + (unsigned long long) rs->md.resync_max_sectors); + + break; + case STATUSTYPE_TABLE: + /* The string you would use to construct this array */ + for (i = 0; i < rs->md.raid_disks; i++) + if (rs->dev[i].data_dev && + !test_bit(In_sync, &rs->dev[i].rdev.flags)) + raid_param_cnt++; /* for rebuilds */ + + raid_param_cnt += (hweight64(rs->print_flags) * 2); + if (rs->print_flags & (DMPF_SYNC | DMPF_NOSYNC)) + raid_param_cnt--; + + DMEMIT("%s %u %u", rs->raid_type->name, + raid_param_cnt, rs->md.chunk_sectors); + + if ((rs->print_flags & DMPF_SYNC) && + (rs->md.recovery_cp == MaxSector)) + DMEMIT(" sync"); + if (rs->print_flags & DMPF_NOSYNC) + DMEMIT(" nosync"); + + for (i = 0; i < rs->md.raid_disks; i++) + if (rs->dev[i].data_dev && + !test_bit(In_sync, &rs->dev[i].rdev.flags)) + DMEMIT(" rebuild %u", i); + + if (rs->print_flags & DMPF_DAEMON_SLEEP) + DMEMIT(" daemon_sleep %lu", + rs->md.bitmap_info.daemon_sleep); + + if (rs->print_flags & DMPF_MIN_RECOVERY_RATE) + DMEMIT(" min_recovery_rate %d", rs->md.sync_speed_min); + + if (rs->print_flags & DMPF_MAX_RECOVERY_RATE) + DMEMIT(" max_recovery_rate %d", rs->md.sync_speed_max); + + if (rs->print_flags & DMPF_MAX_WRITE_BEHIND) + DMEMIT(" max_write_behind %lu", + rs->md.bitmap_info.max_write_behind); + + if (rs->print_flags & DMPF_STRIPE_CACHE) { + raid5_conf_t *conf = rs->md.private; + + /* convert from kiB to sectors */ + DMEMIT(" stripe_cache %d", + conf ? conf->max_nr_stripes * 2 : 0); + } + + DMEMIT(" %d", rs->md.raid_disks); + for (i = 0; i < rs->md.raid_disks; i++) { + DMEMIT(" -"); /* metadata device */ + + if (rs->dev[i].data_dev) + DMEMIT(" %s", rs->dev[i].data_dev->name); + else + DMEMIT(" -"); + } + } + + return 0; +} + +static int raid_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) +{ + struct raid_set *rs = ti->private; + unsigned i; + int ret = 0; + + for (i = 0; !ret && i < rs->md.raid_disks; i++) + if (rs->dev[i].data_dev) + ret = fn(ti, + rs->dev[i].data_dev, + 0, /* No offset on data devs */ + rs->md.dev_sectors, + data); + + return ret; +} + +static void raid_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + struct raid_set *rs = ti->private; + unsigned chunk_size = rs->md.chunk_sectors << 9; + raid5_conf_t *conf = rs->md.private; + + blk_limits_io_min(limits, chunk_size); + blk_limits_io_opt(limits, chunk_size * (conf->raid_disks - conf->max_degraded)); +} + +static void raid_presuspend(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + + md_stop_writes(&rs->md); +} + +static void raid_postsuspend(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + + mddev_suspend(&rs->md); +} + +static void raid_resume(struct dm_target *ti) +{ + struct raid_set *rs = ti->private; + + mddev_resume(&rs->md); +} + +static struct target_type raid_target = { + .name = "raid", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = raid_ctr, + .dtr = raid_dtr, + .map = raid_map, + .status = raid_status, + .iterate_devices = raid_iterate_devices, + .io_hints = raid_io_hints, + .presuspend = raid_presuspend, + .postsuspend = raid_postsuspend, + .resume = raid_resume, +}; + +static int __init dm_raid_init(void) +{ + return dm_register_target(&raid_target); +} + +static void __exit dm_raid_exit(void) +{ + dm_unregister_target(&raid_target); +} + +module_init(dm_raid_init); +module_exit(dm_raid_exit); + +MODULE_DESCRIPTION(DM_NAME " raid4/5/6 target"); +MODULE_ALIAS("dm-raid4"); +MODULE_ALIAS("dm-raid5"); +MODULE_ALIAS("dm-raid6"); +MODULE_AUTHOR("Neil Brown "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 728674a7e466628df2aeec6d11a2ae1ef968fb67 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Jan 2011 12:03:00 -0800 Subject: tty: move hvc drivers to drivers/tty/hvc/ As requested by Arnd Bergmann, the hvc drivers are now moved to the drivers/tty/hvc/ directory. The virtio_console.c driver was also moved, as it required the hvc_console.h file to be able to be built, and it really is a hvc driver. Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/char/Makefile | 13 - drivers/char/hvc_beat.c | 134 --- drivers/char/hvc_console.c | 914 ------------------- drivers/char/hvc_console.h | 119 --- drivers/char/hvc_dcc.c | 133 --- drivers/char/hvc_irq.c | 49 - drivers/char/hvc_iseries.c | 598 ------------- drivers/char/hvc_iucv.c | 1337 --------------------------- drivers/char/hvc_rtas.c | 133 --- drivers/char/hvc_tile.c | 68 -- drivers/char/hvc_udbg.c | 96 -- drivers/char/hvc_vio.c | 173 ---- drivers/char/hvc_xen.c | 271 ------ drivers/char/hvcs.c | 1604 --------------------------------- drivers/char/hvsi.c | 1314 --------------------------- drivers/char/virtio_console.c | 1838 -------------------------------------- drivers/tty/Makefile | 1 + drivers/tty/hvc/Makefile | 13 + drivers/tty/hvc/hvc_beat.c | 134 +++ drivers/tty/hvc/hvc_console.c | 914 +++++++++++++++++++ drivers/tty/hvc/hvc_console.h | 119 +++ drivers/tty/hvc/hvc_dcc.c | 133 +++ drivers/tty/hvc/hvc_irq.c | 49 + drivers/tty/hvc/hvc_iseries.c | 598 +++++++++++++ drivers/tty/hvc/hvc_iucv.c | 1337 +++++++++++++++++++++++++++ drivers/tty/hvc/hvc_rtas.c | 133 +++ drivers/tty/hvc/hvc_tile.c | 68 ++ drivers/tty/hvc/hvc_udbg.c | 96 ++ drivers/tty/hvc/hvc_vio.c | 173 ++++ drivers/tty/hvc/hvc_xen.c | 271 ++++++ drivers/tty/hvc/hvcs.c | 1604 +++++++++++++++++++++++++++++++++ drivers/tty/hvc/hvsi.c | 1314 +++++++++++++++++++++++++++ drivers/tty/hvc/virtio_console.c | 1838 ++++++++++++++++++++++++++++++++++++++ 33 files changed, 8795 insertions(+), 8794 deletions(-) delete mode 100644 drivers/char/hvc_beat.c delete mode 100644 drivers/char/hvc_console.c delete mode 100644 drivers/char/hvc_console.h delete mode 100644 drivers/char/hvc_dcc.c delete mode 100644 drivers/char/hvc_irq.c delete mode 100644 drivers/char/hvc_iseries.c delete mode 100644 drivers/char/hvc_iucv.c delete mode 100644 drivers/char/hvc_rtas.c delete mode 100644 drivers/char/hvc_tile.c delete mode 100644 drivers/char/hvc_udbg.c delete mode 100644 drivers/char/hvc_vio.c delete mode 100644 drivers/char/hvc_xen.c delete mode 100644 drivers/char/hvcs.c delete mode 100644 drivers/char/hvsi.c delete mode 100644 drivers/char/virtio_console.c create mode 100644 drivers/tty/hvc/Makefile create mode 100644 drivers/tty/hvc/hvc_beat.c create mode 100644 drivers/tty/hvc/hvc_console.c create mode 100644 drivers/tty/hvc/hvc_console.h create mode 100644 drivers/tty/hvc/hvc_dcc.c create mode 100644 drivers/tty/hvc/hvc_irq.c create mode 100644 drivers/tty/hvc/hvc_iseries.c create mode 100644 drivers/tty/hvc/hvc_iucv.c create mode 100644 drivers/tty/hvc/hvc_rtas.c create mode 100644 drivers/tty/hvc/hvc_tile.c create mode 100644 drivers/tty/hvc/hvc_udbg.c create mode 100644 drivers/tty/hvc/hvc_vio.c create mode 100644 drivers/tty/hvc/hvc_xen.c create mode 100644 drivers/tty/hvc/hvcs.c create mode 100644 drivers/tty/hvc/hvsi.c create mode 100644 drivers/tty/hvc/virtio_console.c (limited to 'drivers') diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 1e9dffb33778..5bc765d4c3ca 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -30,25 +30,12 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o -obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o -obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o -obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o -obj-$(CONFIG_HVC_TILE) += hvc_tile.o -obj-$(CONFIG_HVC_DCC) += hvc_dcc.o -obj-$(CONFIG_HVC_BEAT) += hvc_beat.o -obj-$(CONFIG_HVC_DRIVER) += hvc_console.o -obj-$(CONFIG_HVC_IRQ) += hvc_irq.o -obj-$(CONFIG_HVC_XEN) += hvc_xen.o -obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o -obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o -obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_VIOTAPE) += viotape.o -obj-$(CONFIG_HVCS) += hvcs.o obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c deleted file mode 100644 index 5fe4631e2a61..000000000000 --- a/drivers/char/hvc_beat.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Beat hypervisor console driver - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on drivers/char/hvc_rtas.c: - * (C) Copyright IBM Corporation 2001-2005 - * (C) Copyright Red Hat, Inc. 2005 - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hvc_console.h" - -extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); -extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); - -struct hvc_struct *hvc_beat_dev = NULL; - -/* bug: only one queue is available regardless of vtermno */ -static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) -{ - static unsigned char q[sizeof(unsigned long) * 2] - __attribute__((aligned(sizeof(unsigned long)))); - static int qlen = 0; - u64 got; - -again: - if (qlen) { - if (qlen > cnt) { - memcpy(buf, q, cnt); - qlen -= cnt; - memmove(q + cnt, q, qlen); - return cnt; - } else { /* qlen <= cnt */ - int r; - - memcpy(buf, q, qlen); - r = qlen; - qlen = 0; - return r; - } - } - if (beat_get_term_char(vtermno, &got, - ((u64 *)q), ((u64 *)q) + 1) == 0) { - qlen = got; - goto again; - } - return 0; -} - -static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) -{ - unsigned long kb[2]; - int rest, nlen; - - for (rest = cnt; rest > 0; rest -= nlen) { - nlen = (rest > 16) ? 16 : rest; - memcpy(kb, buf, nlen); - beat_put_term_char(vtermno, nlen, kb[0], kb[1]); - buf += nlen; - } - return cnt; -} - -static const struct hv_ops hvc_beat_get_put_ops = { - .get_chars = hvc_beat_get_chars, - .put_chars = hvc_beat_put_chars, -}; - -static int hvc_beat_useit = 1; - -static int hvc_beat_config(char *p) -{ - hvc_beat_useit = simple_strtoul(p, NULL, 0); - return 0; -} - -static int __init hvc_beat_console_init(void) -{ - if (hvc_beat_useit && of_machine_is_compatible("Beat")) { - hvc_instantiate(0, 0, &hvc_beat_get_put_ops); - } - return 0; -} - -/* temp */ -static int __init hvc_beat_init(void) -{ - struct hvc_struct *hp; - - if (!firmware_has_feature(FW_FEATURE_BEAT)) - return -ENODEV; - - hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); - if (IS_ERR(hp)) - return PTR_ERR(hp); - hvc_beat_dev = hp; - return 0; -} - -static void __exit hvc_beat_exit(void) -{ - if (hvc_beat_dev) - hvc_remove(hvc_beat_dev); -} - -module_init(hvc_beat_init); -module_exit(hvc_beat_exit); - -__setup("hvc_beat=", hvc_beat_config); - -console_initcall(hvc_beat_console_init); diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c deleted file mode 100644 index e9cba13ee800..000000000000 --- a/drivers/char/hvc_console.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - * Copyright (C) 2001 Anton Blanchard , IBM - * Copyright (C) 2001 Paul Mackerras , IBM - * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. - * Copyright (C) 2004 IBM Corporation - * - * Additional Author(s): - * Ryan S. Arnold - * - * 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 -#include -#include -#include -#include -#include -#include - -#include - -#include "hvc_console.h" - -#define HVC_MAJOR 229 -#define HVC_MINOR 0 - -/* - * Wait this long per iteration while trying to push buffered data to the - * hypervisor before allowing the tty to complete a close operation. - */ -#define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ - -/* - * These sizes are most efficient for vio, because they are the - * native transfer size. We could make them selectable in the - * future to better deal with backends that want other buffer sizes. - */ -#define N_OUTBUF 16 -#define N_INBUF 16 - -#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) - -static struct tty_driver *hvc_driver; -static struct task_struct *hvc_task; - -/* Picks up late kicks after list walk but before schedule() */ -static int hvc_kicked; - -static int hvc_init(void); - -#ifdef CONFIG_MAGIC_SYSRQ -static int sysrq_pressed; -#endif - -/* dynamic list of hvc_struct instances */ -static LIST_HEAD(hvc_structs); - -/* - * Protect the list of hvc_struct instances from inserts and removals during - * list traversal. - */ -static DEFINE_SPINLOCK(hvc_structs_lock); - -/* - * This value is used to assign a tty->index value to a hvc_struct based - * upon order of exposure via hvc_probe(), when we can not match it to - * a console candidate registered with hvc_instantiate(). - */ -static int last_hvc = -1; - -/* - * Do not call this function with either the hvc_structs_lock or the hvc_struct - * lock held. If successful, this function increments the kref reference - * count against the target hvc_struct so it should be released when finished. - */ -static struct hvc_struct *hvc_get_by_index(int index) -{ - struct hvc_struct *hp; - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - list_for_each_entry(hp, &hvc_structs, next) { - spin_lock_irqsave(&hp->lock, flags); - if (hp->index == index) { - kref_get(&hp->kref); - spin_unlock_irqrestore(&hp->lock, flags); - spin_unlock(&hvc_structs_lock); - return hp; - } - spin_unlock_irqrestore(&hp->lock, flags); - } - hp = NULL; - - spin_unlock(&hvc_structs_lock); - return hp; -} - - -/* - * Initial console vtermnos for console API usage prior to full console - * initialization. Any vty adapter outside this range will not have usable - * console interfaces but can still be used as a tty device. This has to be - * static because kmalloc will not work during early console init. - */ -static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; -static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = - {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; - -/* - * Console APIs, NOT TTY. These APIs are available immediately when - * hvc_console_setup() finds adapters. - */ - -static void hvc_console_print(struct console *co, const char *b, - unsigned count) -{ - char c[N_OUTBUF] __ALIGNED__; - unsigned i = 0, n = 0; - int r, donecr = 0, index = co->index; - - /* Console access attempt outside of acceptable console range. */ - if (index >= MAX_NR_HVC_CONSOLES) - return; - - /* This console adapter was removed so it is not usable. */ - if (vtermnos[index] == -1) - return; - - while (count > 0 || i > 0) { - if (count > 0 && i < sizeof(c)) { - if (b[n] == '\n' && !donecr) { - c[i++] = '\r'; - donecr = 1; - } else { - c[i++] = b[n++]; - donecr = 0; - --count; - } - } else { - r = cons_ops[index]->put_chars(vtermnos[index], c, i); - if (r <= 0) { - /* throw away chars on error */ - i = 0; - } else if (r > 0) { - i -= r; - if (i > 0) - memmove(c, c+r, i); - } - } - } -} - -static struct tty_driver *hvc_console_device(struct console *c, int *index) -{ - if (vtermnos[c->index] == -1) - return NULL; - - *index = c->index; - return hvc_driver; -} - -static int __init hvc_console_setup(struct console *co, char *options) -{ - if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) - return -ENODEV; - - if (vtermnos[co->index] == -1) - return -ENODEV; - - return 0; -} - -static struct console hvc_console = { - .name = "hvc", - .write = hvc_console_print, - .device = hvc_console_device, - .setup = hvc_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* - * Early console initialization. Precedes driver initialization. - * - * (1) we are first, and the user specified another driver - * -- index will remain -1 - * (2) we are first and the user specified no driver - * -- index will be set to 0, then we will fail setup. - * (3) we are first and the user specified our driver - * -- index will be set to user specified driver, and we will fail - * (4) we are after driver, and this initcall will register us - * -- if the user didn't specify a driver then the console will match - * - * Note that for cases 2 and 3, we will match later when the io driver - * calls hvc_instantiate() and call register again. - */ -static int __init hvc_console_init(void) -{ - register_console(&hvc_console); - return 0; -} -console_initcall(hvc_console_init); - -/* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kref *kref) -{ - struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - spin_lock_irqsave(&hp->lock, flags); - list_del(&(hp->next)); - spin_unlock_irqrestore(&hp->lock, flags); - - spin_unlock(&hvc_structs_lock); - - kfree(hp); -} - -/* - * hvc_instantiate() is an early console discovery method which locates - * consoles * prior to the vio subsystem discovering them. Hotplugged - * vty adapters do NOT get an hvc_instantiate() callback since they - * appear after early console init. - */ -int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) -{ - struct hvc_struct *hp; - - if (index < 0 || index >= MAX_NR_HVC_CONSOLES) - return -1; - - if (vtermnos[index] != -1) - return -1; - - /* make sure no no tty has been registered in this index */ - hp = hvc_get_by_index(index); - if (hp) { - kref_put(&hp->kref, destroy_hvc_struct); - return -1; - } - - vtermnos[index] = vtermno; - cons_ops[index] = ops; - - /* reserve all indices up to and including this index */ - if (last_hvc < index) - last_hvc = index; - - /* if this index is what the user requested, then register - * now (setup won't fail at this point). It's ok to just - * call register again if previously .setup failed. - */ - if (index == hvc_console.index) - register_console(&hvc_console); - - return 0; -} -EXPORT_SYMBOL_GPL(hvc_instantiate); - -/* Wake the sleeping khvcd */ -void hvc_kick(void) -{ - hvc_kicked = 1; - wake_up_process(hvc_task); -} -EXPORT_SYMBOL_GPL(hvc_kick); - -static void hvc_unthrottle(struct tty_struct *tty) -{ - hvc_kick(); -} - -/* - * 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; - 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->lock, flags); - /* Check and then increment for fast path open. */ - if (hp->count++ > 0) { - tty_kref_get(tty); - spin_unlock_irqrestore(&hp->lock, flags); - hvc_kick(); - return 0; - } /* else count == 0 */ - - tty->driver_data = hp; - - hp->tty = tty_kref_get(tty); - - spin_unlock_irqrestore(&hp->lock, flags); - - if (hp->ops->notifier_add) - rc = hp->ops->notifier_add(hp, hp->data); - - /* - * If the notifier fails we return an error. The tty layer - * will call hvc_close() after a failed open but we don't want to clean - * up there so we'll clean up here and clear out the previously set - * tty fields and return the kref reference. - */ - if (rc) { - spin_lock_irqsave(&hp->lock, flags); - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); - tty_kref_put(tty); - tty->driver_data = NULL; - kref_put(&hp->kref, destroy_hvc_struct); - printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); - } - /* Force wakeup of the polling thread */ - hvc_kick(); - - return rc; -} - -static void hvc_close(struct tty_struct *tty, struct file * filp) -{ - struct hvc_struct *hp; - unsigned long flags; - - if (tty_hung_up_p(filp)) - return; - - /* - * No driver_data means that this close was issued after a failed - * hvc_open by the tty layer's release_dev() function and we can just - * exit cleanly because the kref reference wasn't made. - */ - if (!tty->driver_data) - return; - - hp = tty->driver_data; - - spin_lock_irqsave(&hp->lock, flags); - - if (--hp->count == 0) { - /* We are done with the tty pointer now. */ - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); - - if (hp->ops->notifier_del) - hp->ops->notifier_del(hp, hp->data); - - /* cancel pending tty resize work */ - cancel_work_sync(&hp->tty_resize); - - /* - * Chain calls chars_in_buffer() and returns immediately if - * there is no buffered data otherwise sleeps on a wait queue - * waking periodically to check chars_in_buffer(). - */ - tty_wait_until_sent(tty, HVC_CLOSE_WAIT); - } else { - if (hp->count < 0) - printk(KERN_ERR "hvc_close %X: oops, count is %d\n", - hp->vtermno, hp->count); - spin_unlock_irqrestore(&hp->lock, flags); - } - - tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); -} - -static void hvc_hangup(struct tty_struct *tty) -{ - struct hvc_struct *hp = tty->driver_data; - unsigned long flags; - int temp_open_count; - - if (!hp) - return; - - /* cancel pending tty resize work */ - cancel_work_sync(&hp->tty_resize); - - spin_lock_irqsave(&hp->lock, flags); - - /* - * The N_TTY line discipline has problems such that in a close vs - * open->hangup case this can be called after the final close so prevent - * that from happening for now. - */ - if (hp->count <= 0) { - spin_unlock_irqrestore(&hp->lock, flags); - return; - } - - temp_open_count = hp->count; - hp->count = 0; - hp->n_outbuf = 0; - hp->tty = NULL; - - spin_unlock_irqrestore(&hp->lock, flags); - - if (hp->ops->notifier_hangup) - hp->ops->notifier_hangup(hp, hp->data); - - while(temp_open_count) { - --temp_open_count; - tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); - } -} - -/* - * Push buffered characters whether they were just recently buffered or waiting - * on a blocked hypervisor. Call this function with hp->lock held. - */ -static int hvc_push(struct hvc_struct *hp) -{ - int n; - - n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); - if (n <= 0) { - if (n == 0) { - hp->do_wakeup = 1; - return 0; - } - /* throw away output on error; this happens when - there is no session connected to the vterm. */ - hp->n_outbuf = 0; - } else - hp->n_outbuf -= n; - if (hp->n_outbuf > 0) - memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf); - else - hp->do_wakeup = 1; - - return n; -} - -static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct hvc_struct *hp = tty->driver_data; - unsigned long flags; - int rsize, written = 0; - - /* This write was probably executed during a tty close. */ - if (!hp) - return -EPIPE; - - if (hp->count <= 0) - return -EIO; - - spin_lock_irqsave(&hp->lock, flags); - - /* Push pending writes */ - if (hp->n_outbuf > 0) - hvc_push(hp); - - while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) { - if (rsize > count) - rsize = count; - memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); - count -= rsize; - buf += rsize; - hp->n_outbuf += rsize; - written += rsize; - hvc_push(hp); - } - spin_unlock_irqrestore(&hp->lock, flags); - - /* - * Racy, but harmless, kick thread if there is still pending data. - */ - if (hp->n_outbuf) - hvc_kick(); - - return written; -} - -/** - * hvc_set_winsz() - Resize the hvc tty terminal window. - * @work: work structure. - * - * The routine shall not be called within an atomic context because it - * might sleep. - * - * Locking: hp->lock - */ -static void hvc_set_winsz(struct work_struct *work) -{ - struct hvc_struct *hp; - unsigned long hvc_flags; - struct tty_struct *tty; - struct winsize ws; - - hp = container_of(work, struct hvc_struct, tty_resize); - - spin_lock_irqsave(&hp->lock, hvc_flags); - if (!hp->tty) { - spin_unlock_irqrestore(&hp->lock, hvc_flags); - return; - } - ws = hp->ws; - tty = tty_kref_get(hp->tty); - spin_unlock_irqrestore(&hp->lock, hvc_flags); - - tty_do_resize(tty, &ws); - tty_kref_put(tty); -} - -/* - * This is actually a contract between the driver and the tty layer outlining - * how much write room the driver can guarantee will be sent OR BUFFERED. This - * driver MUST honor the return value. - */ -static int hvc_write_room(struct tty_struct *tty) -{ - struct hvc_struct *hp = tty->driver_data; - - if (!hp) - return -1; - - return hp->outbuf_size - hp->n_outbuf; -} - -static int hvc_chars_in_buffer(struct tty_struct *tty) -{ - struct hvc_struct *hp = tty->driver_data; - - if (!hp) - return 0; - return hp->n_outbuf; -} - -/* - * timeout will vary between the MIN and MAX values defined here. By default - * and during console activity we will use a default MIN_TIMEOUT of 10. When - * the console is idle, we increase the timeout value on each pass through - * msleep until we reach the max. This may be noticeable as a brief (average - * one second) delay on the console before the console responds to input when - * there has been no input for some time. - */ -#define MIN_TIMEOUT (10) -#define MAX_TIMEOUT (2000) -static u32 timeout = MIN_TIMEOUT; - -#define HVC_POLL_READ 0x00000001 -#define HVC_POLL_WRITE 0x00000002 - -int hvc_poll(struct hvc_struct *hp) -{ - struct tty_struct *tty; - int i, n, poll_mask = 0; - char buf[N_INBUF] __ALIGNED__; - unsigned long flags; - int read_total = 0; - int written_total = 0; - - spin_lock_irqsave(&hp->lock, flags); - - /* Push pending writes */ - if (hp->n_outbuf > 0) - written_total = hvc_push(hp); - - /* Reschedule us if still some write pending */ - if (hp->n_outbuf > 0) { - poll_mask |= HVC_POLL_WRITE; - /* If hvc_push() was not able to write, sleep a few msecs */ - timeout = (written_total) ? 0 : MIN_TIMEOUT; - } - - /* No tty attached, just skip */ - tty = tty_kref_get(hp->tty); - if (tty == NULL) - goto bail; - - /* Now check if we can get data (are we throttled ?) */ - if (test_bit(TTY_THROTTLED, &tty->flags)) - goto throttled; - - /* If we aren't notifier driven and aren't throttled, we always - * request a reschedule - */ - if (!hp->irq_requested) - poll_mask |= HVC_POLL_READ; - - /* Read data if any */ - for (;;) { - int count = tty_buffer_request_room(tty, N_INBUF); - - /* If flip is full, just reschedule a later read */ - if (count == 0) { - poll_mask |= HVC_POLL_READ; - break; - } - - n = hp->ops->get_chars(hp->vtermno, buf, count); - if (n <= 0) { - /* Hangup the tty when disconnected from host */ - if (n == -EPIPE) { - spin_unlock_irqrestore(&hp->lock, flags); - tty_hangup(tty); - spin_lock_irqsave(&hp->lock, flags); - } else if ( n == -EAGAIN ) { - /* - * Some back-ends can only ensure a certain min - * num of bytes read, which may be > 'count'. - * Let the tty clear the flip buff to make room. - */ - poll_mask |= HVC_POLL_READ; - } - break; - } - for (i = 0; i < n; ++i) { -#ifdef CONFIG_MAGIC_SYSRQ - if (hp->index == hvc_console.index) { - /* Handle the SysRq Hack */ - /* XXX should support a sequence */ - if (buf[i] == '\x0f') { /* ^O */ - /* if ^O is pressed again, reset - * sysrq_pressed and flip ^O char */ - sysrq_pressed = !sysrq_pressed; - if (sysrq_pressed) - continue; - } else if (sysrq_pressed) { - handle_sysrq(buf[i]); - sysrq_pressed = 0; - continue; - } - } -#endif /* CONFIG_MAGIC_SYSRQ */ - tty_insert_flip_char(tty, buf[i], 0); - } - - read_total += n; - } - throttled: - /* Wakeup write queue if necessary */ - if (hp->do_wakeup) { - hp->do_wakeup = 0; - tty_wakeup(tty); - } - bail: - spin_unlock_irqrestore(&hp->lock, flags); - - if (read_total) { - /* Activity is occurring, so reset the polling backoff value to - a minimum for performance. */ - timeout = MIN_TIMEOUT; - - tty_flip_buffer_push(tty); - } - if (tty) - tty_kref_put(tty); - - return poll_mask; -} -EXPORT_SYMBOL_GPL(hvc_poll); - -/** - * __hvc_resize() - Update terminal window size information. - * @hp: HVC console pointer - * @ws: Terminal window size structure - * - * Stores the specified window size information in the hvc structure of @hp. - * The function schedule the tty resize update. - * - * Locking: Locking free; the function MUST be called holding hp->lock - */ -void __hvc_resize(struct hvc_struct *hp, struct winsize ws) -{ - hp->ws = ws; - schedule_work(&hp->tty_resize); -} -EXPORT_SYMBOL_GPL(__hvc_resize); - -/* - * This kthread is either polling or interrupt driven. This is determined by - * calling hvc_poll() who determines whether a console adapter support - * interrupts. - */ -static int khvcd(void *unused) -{ - int poll_mask; - struct hvc_struct *hp; - - set_freezable(); - do { - poll_mask = 0; - hvc_kicked = 0; - try_to_freeze(); - wmb(); - if (!cpus_are_in_xmon()) { - spin_lock(&hvc_structs_lock); - list_for_each_entry(hp, &hvc_structs, next) { - poll_mask |= hvc_poll(hp); - } - spin_unlock(&hvc_structs_lock); - } else - poll_mask |= HVC_POLL_READ; - if (hvc_kicked) - continue; - set_current_state(TASK_INTERRUPTIBLE); - if (!hvc_kicked) { - if (poll_mask == 0) - schedule(); - else { - if (timeout < MAX_TIMEOUT) - timeout += (timeout >> 6) + 1; - - msleep_interruptible(timeout); - } - } - __set_current_state(TASK_RUNNING); - } while (!kthread_should_stop()); - - return 0; -} - -static const struct tty_operations hvc_ops = { - .open = hvc_open, - .close = hvc_close, - .write = hvc_write, - .hangup = hvc_hangup, - .unthrottle = hvc_unthrottle, - .write_room = hvc_write_room, - .chars_in_buffer = hvc_chars_in_buffer, -}; - -struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, - const struct hv_ops *ops, - int outbuf_size) -{ - struct hvc_struct *hp; - int i; - - /* We wait until a driver actually comes along */ - if (!hvc_driver) { - int err = hvc_init(); - if (err) - return ERR_PTR(err); - } - - hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, - GFP_KERNEL); - if (!hp) - return ERR_PTR(-ENOMEM); - - hp->vtermno = vtermno; - hp->data = data; - hp->ops = ops; - hp->outbuf_size = outbuf_size; - hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - - kref_init(&hp->kref); - - INIT_WORK(&hp->tty_resize, hvc_set_winsz); - spin_lock_init(&hp->lock); - spin_lock(&hvc_structs_lock); - - /* - * find index to use: - * see if this vterm id matches one registered for console. - */ - for (i=0; i < MAX_NR_HVC_CONSOLES; i++) - if (vtermnos[i] == hp->vtermno && - cons_ops[i] == hp->ops) - break; - - /* no matching slot, just use a counter */ - if (i >= MAX_NR_HVC_CONSOLES) - i = ++last_hvc; - - hp->index = i; - - list_add_tail(&(hp->next), &hvc_structs); - spin_unlock(&hvc_structs_lock); - - return hp; -} -EXPORT_SYMBOL_GPL(hvc_alloc); - -int hvc_remove(struct hvc_struct *hp) -{ - unsigned long flags; - struct tty_struct *tty; - - spin_lock_irqsave(&hp->lock, flags); - tty = tty_kref_get(hp->tty); - - if (hp->index < MAX_NR_HVC_CONSOLES) - vtermnos[hp->index] = -1; - - /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ - - spin_unlock_irqrestore(&hp->lock, flags); - - /* - * We 'put' the instance that was grabbed when the kref instance - * was initialized using kref_init(). Let the last holder of this - * kref cause it to be removed, which will probably be the tty_vhangup - * below. - */ - kref_put(&hp->kref, destroy_hvc_struct); - - /* - * This function call will auto chain call hvc_hangup. - */ - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } - return 0; -} -EXPORT_SYMBOL_GPL(hvc_remove); - -/* Driver initialization: called as soon as someone uses hvc_alloc(). */ -static int hvc_init(void) -{ - struct tty_driver *drv; - int err; - - /* We need more than hvc_count adapters due to hotplug additions. */ - drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); - if (!drv) { - err = -ENOMEM; - goto out; - } - - drv->owner = THIS_MODULE; - drv->driver_name = "hvc"; - drv->name = "hvc"; - drv->major = HVC_MAJOR; - drv->minor_start = HVC_MINOR; - drv->type = TTY_DRIVER_TYPE_SYSTEM; - drv->init_termios = tty_std_termios; - drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - tty_set_operations(drv, &hvc_ops); - - /* Always start the kthread because there can be hotplug vty adapters - * added later. */ - hvc_task = kthread_run(khvcd, NULL, "khvcd"); - if (IS_ERR(hvc_task)) { - printk(KERN_ERR "Couldn't create kthread for console.\n"); - err = PTR_ERR(hvc_task); - goto put_tty; - } - - err = tty_register_driver(drv); - if (err) { - printk(KERN_ERR "Couldn't register hvc console driver\n"); - goto stop_thread; - } - - /* - * Make sure tty is fully registered before allowing it to be - * found by hvc_console_device. - */ - smp_mb(); - hvc_driver = drv; - return 0; - -stop_thread: - kthread_stop(hvc_task); - hvc_task = NULL; -put_tty: - put_tty_driver(drv); -out: - return err; -} - -/* This isn't particularly necessary due to this being a console driver - * but it is nice to be thorough. - */ -static void __exit hvc_exit(void) -{ - if (hvc_driver) { - kthread_stop(hvc_task); - - tty_unregister_driver(hvc_driver); - /* return tty_struct instances allocated in hvc_init(). */ - put_tty_driver(hvc_driver); - unregister_console(&hvc_console); - } -} -module_exit(hvc_exit); diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h deleted file mode 100644 index 54381eba4e4a..000000000000 --- a/drivers/char/hvc_console.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * hvc_console.h - * Copyright (C) 2005 IBM Corporation - * - * Author(s): - * Ryan S. Arnold - * - * hvc_console header information: - * moved here from arch/powerpc/include/asm/hvconsole.h - * and drivers/char/hvc_console.c - * - * 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 - */ - -#ifndef HVC_CONSOLE_H -#define HVC_CONSOLE_H -#include -#include -#include - -/* - * This is the max number of console adapters that can/will be found as - * console devices on first stage console init. Any number beyond this range - * can't be used as a console device but is still a valid tty device. - */ -#define MAX_NR_HVC_CONSOLES 16 - -/* - * The Linux TTY code does not support dynamic addition of tty derived devices - * so we need to know how many tty devices we might need when space is allocated - * for the tty device. Since this driver supports hotplug of vty adapters we - * need to make sure we have enough allocated. - */ -#define HVC_ALLOC_TTY_ADAPTERS 8 - -struct hvc_struct { - spinlock_t lock; - int index; - struct tty_struct *tty; - int count; - int do_wakeup; - char *outbuf; - int outbuf_size; - int n_outbuf; - uint32_t vtermno; - const struct hv_ops *ops; - int irq_requested; - int data; - struct winsize ws; - struct work_struct tty_resize; - struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ -}; - -/* implemented by a low level driver */ -struct hv_ops { - int (*get_chars)(uint32_t vtermno, char *buf, int count); - int (*put_chars)(uint32_t vtermno, const char *buf, int count); - - /* Callbacks for notification. Called in open, close and hangup */ - int (*notifier_add)(struct hvc_struct *hp, int irq); - void (*notifier_del)(struct hvc_struct *hp, int irq); - void (*notifier_hangup)(struct hvc_struct *hp, int irq); -}; - -/* Register a vterm and a slot index for use as a console (console_init) */ -extern int hvc_instantiate(uint32_t vtermno, int index, - const struct hv_ops *ops); - -/* register a vterm for hvc tty operation (module_init or hotplug add) */ -extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data, - const struct hv_ops *ops, int outbuf_size); -/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ -extern int hvc_remove(struct hvc_struct *hp); - -/* data available */ -int hvc_poll(struct hvc_struct *hp); -void hvc_kick(void); - -/* Resize hvc tty terminal window */ -extern void __hvc_resize(struct hvc_struct *hp, struct winsize ws); - -static inline void hvc_resize(struct hvc_struct *hp, struct winsize ws) -{ - unsigned long flags; - - spin_lock_irqsave(&hp->lock, flags); - __hvc_resize(hp, ws); - spin_unlock_irqrestore(&hp->lock, flags); -} - -/* default notifier for irq based notification */ -extern int notifier_add_irq(struct hvc_struct *hp, int data); -extern void notifier_del_irq(struct hvc_struct *hp, int data); -extern void notifier_hangup_irq(struct hvc_struct *hp, int data); - - -#if defined(CONFIG_XMON) && defined(CONFIG_SMP) -#include -#else -static inline int cpus_are_in_xmon(void) -{ - return 0; -} -#endif - -#endif // HVC_CONSOLE_H diff --git a/drivers/char/hvc_dcc.c b/drivers/char/hvc_dcc.c deleted file mode 100644 index 6470f63deb4b..000000000000 --- a/drivers/char/hvc_dcc.c +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "hvc_console.h" - -/* DCC Status Bits */ -#define DCC_STATUS_RX (1 << 30) -#define DCC_STATUS_TX (1 << 29) - -static inline u32 __dcc_getstatus(void) -{ - u32 __ret; - - asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg" - : "=r" (__ret) : : "cc"); - - return __ret; -} - - -#if defined(CONFIG_CPU_V7) -static inline char __dcc_getchar(void) -{ - char __c; - - asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\ - bne get_wait \n\ - mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" - : "=r" (__c) : : "cc"); - - return __c; -} -#else -static inline char __dcc_getchar(void) -{ - char __c; - - asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" - : "=r" (__c)); - - return __c; -} -#endif - -#if defined(CONFIG_CPU_V7) -static inline void __dcc_putchar(char c) -{ - asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\ - bcs put_wait \n\ - mcr p14, 0, %0, c0, c5, 0 " - : : "r" (c) : "cc"); -} -#else -static inline void __dcc_putchar(char c) -{ - asm("mcr p14, 0, %0, c0, c5, 0 @ write a char" - : /* no output register */ - : "r" (c)); -} -#endif - -static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) -{ - int i; - - for (i = 0; i < count; i++) { - while (__dcc_getstatus() & DCC_STATUS_TX) - cpu_relax(); - - __dcc_putchar((char)(buf[i] & 0xFF)); - } - - return count; -} - -static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count) -{ - int i; - - for (i = 0; i < count; ++i) { - int c = -1; - - if (__dcc_getstatus() & DCC_STATUS_RX) - c = __dcc_getchar(); - if (c < 0) - break; - buf[i] = c; - } - - return i; -} - -static const struct hv_ops hvc_dcc_get_put_ops = { - .get_chars = hvc_dcc_get_chars, - .put_chars = hvc_dcc_put_chars, -}; - -static int __init hvc_dcc_console_init(void) -{ - hvc_instantiate(0, 0, &hvc_dcc_get_put_ops); - return 0; -} -console_initcall(hvc_dcc_console_init); - -static int __init hvc_dcc_init(void) -{ - hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128); - return 0; -} -device_initcall(hvc_dcc_init); diff --git a/drivers/char/hvc_irq.c b/drivers/char/hvc_irq.c deleted file mode 100644 index 2623e177e8d6..000000000000 --- a/drivers/char/hvc_irq.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright IBM Corp. 2001,2008 - * - * This file contains the IRQ specific code for hvc_console - * - */ - -#include - -#include "hvc_console.h" - -static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) -{ - /* if hvc_poll request a repoll, then kick the hvcd thread */ - if (hvc_poll(dev_instance)) - hvc_kick(); - return IRQ_HANDLED; -} - -/* - * For IRQ based systems these callbacks can be used - */ -int notifier_add_irq(struct hvc_struct *hp, int irq) -{ - int rc; - - if (!irq) { - hp->irq_requested = 0; - return 0; - } - rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, - "hvc_console", hp); - if (!rc) - hp->irq_requested = 1; - return rc; -} - -void notifier_del_irq(struct hvc_struct *hp, int irq) -{ - if (!hp->irq_requested) - return; - free_irq(irq, hp); - hp->irq_requested = 0; -} - -void notifier_hangup_irq(struct hvc_struct *hp, int irq) -{ - notifier_del_irq(hp, irq); -} diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c deleted file mode 100644 index 21c54955084e..000000000000 --- a/drivers/char/hvc_iseries.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * iSeries vio driver interface to hvc_console.c - * - * This code is based heavily on hvc_vio.c and viocons.c - * - * Copyright (C) 2006 Stephen Rothwell, IBM Corporation - * - * 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 -#include -#include -#include - -#include "hvc_console.h" - -#define VTTY_PORTS 10 - -static DEFINE_SPINLOCK(consolelock); -static DEFINE_SPINLOCK(consoleloglock); - -static const char hvc_driver_name[] = "hvc_console"; - -#define IN_BUF_SIZE 200 - -/* - * Our port information. - */ -static struct port_info { - HvLpIndex lp; - u64 seq; /* sequence number of last HV send */ - u64 ack; /* last ack from HV */ - struct hvc_struct *hp; - int in_start; - int in_end; - unsigned char in_buf[IN_BUF_SIZE]; -} port_info[VTTY_PORTS] = { - [ 0 ... VTTY_PORTS - 1 ] = { - .lp = HvLpIndexInvalid - } -}; - -#define viochar_is_console(pi) ((pi) == &port_info[0]) - -static struct vio_device_id hvc_driver_table[] __devinitdata = { - {"serial", "IBM,iSeries-vty"}, - { "", "" } -}; -MODULE_DEVICE_TABLE(vio, hvc_driver_table); - -static void hvlog(char *fmt, ...) -{ - int i; - unsigned long flags; - va_list args; - static char buf[256]; - - spin_lock_irqsave(&consoleloglock, flags); - va_start(args, fmt); - i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); - va_end(args); - buf[i++] = '\r'; - HvCall_writeLogBuffer(buf, i); - spin_unlock_irqrestore(&consoleloglock, flags); -} - -/* - * Initialize the common fields in a charLpEvent - */ -static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp) -{ - struct HvLpEvent *hev = &viochar->event; - - memset(viochar, 0, sizeof(struct viocharlpevent)); - - hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | - HV_LP_EVENT_INT; - hev->xType = HvLpEvent_Type_VirtualIo; - hev->xSubtype = viomajorsubtype_chario | viochardata; - hev->xSourceLp = HvLpConfig_getLpIndex(); - hev->xTargetLp = lp; - hev->xSizeMinus1 = sizeof(struct viocharlpevent); - hev->xSourceInstanceId = viopath_sourceinst(lp); - hev->xTargetInstanceId = viopath_targetinst(lp); -} - -static int get_chars(uint32_t vtermno, char *buf, int count) -{ - struct port_info *pi; - int n = 0; - unsigned long flags; - - if (vtermno >= VTTY_PORTS) - return -EINVAL; - if (count == 0) - return 0; - - pi = &port_info[vtermno]; - spin_lock_irqsave(&consolelock, flags); - - if (pi->in_end == 0) - goto done; - - n = pi->in_end - pi->in_start; - if (n > count) - n = count; - memcpy(buf, &pi->in_buf[pi->in_start], n); - pi->in_start += n; - if (pi->in_start == pi->in_end) { - pi->in_start = 0; - pi->in_end = 0; - } -done: - spin_unlock_irqrestore(&consolelock, flags); - return n; -} - -static int put_chars(uint32_t vtermno, const char *buf, int count) -{ - struct viocharlpevent *viochar; - struct port_info *pi; - HvLpEvent_Rc hvrc; - unsigned long flags; - int sent = 0; - - if (vtermno >= VTTY_PORTS) - return -EINVAL; - - pi = &port_info[vtermno]; - - spin_lock_irqsave(&consolelock, flags); - - if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) { - HvCall_writeLogBuffer(buf, count); - sent = count; - goto done; - } - - viochar = vio_get_event_buffer(viomajorsubtype_chario); - if (viochar == NULL) { - hvlog("\n\rviocons: Can't get viochar buffer."); - goto done; - } - - while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { - int len; - - len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count; - - if (viochar_is_console(pi)) - HvCall_writeLogBuffer(buf, len); - - init_data_event(viochar, pi->lp); - - viochar->len = len; - viochar->event.xCorrelationToken = pi->seq++; - viochar->event.xSizeMinus1 = - offsetof(struct viocharlpevent, data) + len; - - memcpy(viochar->data, buf, len); - - hvrc = HvCallEvent_signalLpEvent(&viochar->event); - if (hvrc) - hvlog("\n\rerror sending event! return code %d\n\r", - (int)hvrc); - sent += len; - count -= len; - buf += len; - } - - vio_free_event_buffer(viomajorsubtype_chario, viochar); -done: - spin_unlock_irqrestore(&consolelock, flags); - return sent; -} - -static const struct hv_ops hvc_get_put_ops = { - .get_chars = get_chars, - .put_chars = put_chars, - .notifier_add = notifier_add_irq, - .notifier_del = notifier_del_irq, - .notifier_hangup = notifier_hangup_irq, -}; - -static int __devinit hvc_vio_probe(struct vio_dev *vdev, - const struct vio_device_id *id) -{ - struct hvc_struct *hp; - struct port_info *pi; - - /* probed with invalid parameters. */ - if (!vdev || !id) - return -EPERM; - - if (vdev->unit_address >= VTTY_PORTS) - return -ENODEV; - - pi = &port_info[vdev->unit_address]; - - hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, - VIOCHAR_MAX_DATA); - if (IS_ERR(hp)) - return PTR_ERR(hp); - pi->hp = hp; - dev_set_drvdata(&vdev->dev, pi); - - return 0; -} - -static int __devexit hvc_vio_remove(struct vio_dev *vdev) -{ - struct port_info *pi = dev_get_drvdata(&vdev->dev); - struct hvc_struct *hp = pi->hp; - - return hvc_remove(hp); -} - -static struct vio_driver hvc_vio_driver = { - .id_table = hvc_driver_table, - .probe = hvc_vio_probe, - .remove = __devexit_p(hvc_vio_remove), - .driver = { - .name = hvc_driver_name, - .owner = THIS_MODULE, - } -}; - -static void hvc_open_event(struct HvLpEvent *event) -{ - unsigned long flags; - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - u8 port = cevent->virtual_device; - struct port_info *pi; - int reject = 0; - - if (hvlpevent_is_ack(event)) { - if (port >= VTTY_PORTS) - return; - - spin_lock_irqsave(&consolelock, flags); - - pi = &port_info[port]; - if (event->xRc == HvLpEvent_Rc_Good) { - pi->seq = pi->ack = 0; - /* - * This line allows connections from the primary - * partition but once one is connected from the - * primary partition nothing short of a reboot - * of linux will allow access from the hosting - * partition again without a required iSeries fix. - */ - pi->lp = event->xTargetLp; - } - - spin_unlock_irqrestore(&consolelock, flags); - if (event->xRc != HvLpEvent_Rc_Good) - printk(KERN_WARNING - "hvc: handle_open_event: event->xRc == (%d).\n", - event->xRc); - - if (event->xCorrelationToken != 0) { - atomic_t *aptr= (atomic_t *)event->xCorrelationToken; - atomic_set(aptr, 1); - } else - printk(KERN_WARNING - "hvc: weird...got open ack without atomic\n"); - return; - } - - /* This had better require an ack, otherwise complain */ - if (!hvlpevent_need_ack(event)) { - printk(KERN_WARNING "hvc: viocharopen without ack bit!\n"); - return; - } - - spin_lock_irqsave(&consolelock, flags); - - /* Make sure this is a good virtual tty */ - if (port >= VTTY_PORTS) { - event->xRc = HvLpEvent_Rc_SubtypeError; - cevent->subtype_result_code = viorc_openRejected; - /* - * Flag state here since we can't printk while holding - * the consolelock spinlock. - */ - reject = 1; - } else { - pi = &port_info[port]; - if ((pi->lp != HvLpIndexInvalid) && - (pi->lp != event->xSourceLp)) { - /* - * If this is tty is already connected to a different - * partition, fail. - */ - event->xRc = HvLpEvent_Rc_SubtypeError; - cevent->subtype_result_code = viorc_openRejected; - reject = 2; - } else { - pi->lp = event->xSourceLp; - event->xRc = HvLpEvent_Rc_Good; - cevent->subtype_result_code = viorc_good; - pi->seq = pi->ack = 0; - } - } - - spin_unlock_irqrestore(&consolelock, flags); - - if (reject == 1) - printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n"); - else if (reject == 2) - printk(KERN_WARNING "hvc: open rejected: console in exclusive " - "use by another partition.\n"); - - /* Return the acknowledgement */ - HvCallEvent_ackLpEvent(event); -} - -/* - * Handle a close charLpEvent. This should ONLY be an Interrupt because the - * virtual console should never actually issue a close event to the hypervisor - * because the virtual console never goes away. A close event coming from the - * hypervisor simply means that there are no client consoles connected to the - * virtual console. - */ -static void hvc_close_event(struct HvLpEvent *event) -{ - unsigned long flags; - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - u8 port = cevent->virtual_device; - - if (!hvlpevent_is_int(event)) { - printk(KERN_WARNING - "hvc: got unexpected close acknowledgement\n"); - return; - } - - if (port >= VTTY_PORTS) { - printk(KERN_WARNING - "hvc: close message from invalid virtual device.\n"); - return; - } - - /* For closes, just mark the console partition invalid */ - spin_lock_irqsave(&consolelock, flags); - - if (port_info[port].lp == event->xSourceLp) - port_info[port].lp = HvLpIndexInvalid; - - spin_unlock_irqrestore(&consolelock, flags); -} - -static void hvc_data_event(struct HvLpEvent *event) -{ - unsigned long flags; - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - struct port_info *pi; - int n; - u8 port = cevent->virtual_device; - - if (port >= VTTY_PORTS) { - printk(KERN_WARNING "hvc: data on invalid virtual device %d\n", - port); - return; - } - if (cevent->len == 0) - return; - - /* - * Change 05/01/2003 - Ryan Arnold: If a partition other than - * the current exclusive partition tries to send us data - * events then just drop them on the floor because we don't - * want his stinking data. He isn't authorized to receive - * data because he wasn't the first one to get the console, - * therefore he shouldn't be allowed to send data either. - * This will work without an iSeries fix. - */ - pi = &port_info[port]; - if (pi->lp != event->xSourceLp) - return; - - spin_lock_irqsave(&consolelock, flags); - - n = IN_BUF_SIZE - pi->in_end; - if (n > cevent->len) - n = cevent->len; - if (n > 0) { - memcpy(&pi->in_buf[pi->in_end], cevent->data, n); - pi->in_end += n; - } - spin_unlock_irqrestore(&consolelock, flags); - if (n == 0) - printk(KERN_WARNING "hvc: input buffer overflow\n"); -} - -static void hvc_ack_event(struct HvLpEvent *event) -{ - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - unsigned long flags; - u8 port = cevent->virtual_device; - - if (port >= VTTY_PORTS) { - printk(KERN_WARNING "hvc: data on invalid virtual device\n"); - return; - } - - spin_lock_irqsave(&consolelock, flags); - port_info[port].ack = event->xCorrelationToken; - spin_unlock_irqrestore(&consolelock, flags); -} - -static void hvc_config_event(struct HvLpEvent *event) -{ - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - - if (cevent->data[0] == 0x01) - printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n", - cevent->data[1], cevent->data[2], - cevent->data[3], cevent->data[4]); - else - printk(KERN_WARNING "hvc: unknown config event\n"); -} - -static void hvc_handle_event(struct HvLpEvent *event) -{ - int charminor; - - if (event == NULL) - return; - - charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; - switch (charminor) { - case viocharopen: - hvc_open_event(event); - break; - case viocharclose: - hvc_close_event(event); - break; - case viochardata: - hvc_data_event(event); - break; - case viocharack: - hvc_ack_event(event); - break; - case viocharconfig: - hvc_config_event(event); - break; - default: - if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - } -} - -static int __init send_open(HvLpIndex remoteLp, void *sem) -{ - return HvCallEvent_signalLpEventFast(remoteLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_chario | viocharopen, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(remoteLp), - viopath_targetinst(remoteLp), - (u64)(unsigned long)sem, VIOVERSION << 16, - 0, 0, 0, 0); -} - -static int __init hvc_vio_init(void) -{ - atomic_t wait_flag; - int rc; - - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return -EIO; - - /* +2 for fudge */ - rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), - viomajorsubtype_chario, VIOCHAR_WINDOW + 2); - if (rc) - printk(KERN_WARNING "hvc: error opening to primary %d\n", rc); - - if (viopath_hostLp == HvLpIndexInvalid) - vio_set_hostlp(); - - /* - * And if the primary is not the same as the hosting LP, open to the - * hosting lp - */ - if ((viopath_hostLp != HvLpIndexInvalid) && - (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { - printk(KERN_INFO "hvc: open path to hosting (%d)\n", - viopath_hostLp); - rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, - VIOCHAR_WINDOW + 2); /* +2 for fudge */ - if (rc) - printk(KERN_WARNING - "error opening to partition %d: %d\n", - viopath_hostLp, rc); - } - - if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0) - printk(KERN_WARNING - "hvc: error seting handler for console events!\n"); - - /* - * First, try to open the console to the hosting lp. - * Wait on a semaphore for the response. - */ - atomic_set(&wait_flag, 0); - if ((viopath_isactive(viopath_hostLp)) && - (send_open(viopath_hostLp, &wait_flag) == 0)) { - printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp); - while (atomic_read(&wait_flag) == 0) - mb(); - atomic_set(&wait_flag, 0); - } - - /* - * If we don't have an active console, try the primary - */ - if ((!viopath_isactive(port_info[0].lp)) && - (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && - (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) { - printk(KERN_INFO "hvc: opening console to primary partition\n"); - while (atomic_read(&wait_flag) == 0) - mb(); - } - - /* Register as a vio device to receive callbacks */ - rc = vio_register_driver(&hvc_vio_driver); - - return rc; -} -module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ - -static void __exit hvc_vio_exit(void) -{ - vio_unregister_driver(&hvc_vio_driver); -} -module_exit(hvc_vio_exit); - -/* the device tree order defines our numbering */ -static int __init hvc_find_vtys(void) -{ - struct device_node *vty; - int num_found = 0; - - for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; - vty = of_find_node_by_name(vty, "vty")) { - const uint32_t *vtermno; - - /* We have statically defined space for only a certain number - * of console adapters. - */ - if ((num_found >= MAX_NR_HVC_CONSOLES) || - (num_found >= VTTY_PORTS)) { - of_node_put(vty); - break; - } - - vtermno = of_get_property(vty, "reg", NULL); - if (!vtermno) - continue; - - if (!of_device_is_compatible(vty, "IBM,iSeries-vty")) - continue; - - if (num_found == 0) - add_preferred_console("hvc", 0, NULL); - hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); - ++num_found; - } - - return num_found; -} -console_initcall(hvc_find_vtys); diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c deleted file mode 100644 index c3425bb3a1f6..000000000000 --- a/drivers/char/hvc_iucv.c +++ /dev/null @@ -1,1337 +0,0 @@ -/* - * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver - * - * This HVC device driver provides terminal access using - * z/VM IUCV communication paths. - * - * Copyright IBM Corp. 2008, 2009 - * - * Author(s): Hendrik Brueckner - */ -#define KMSG_COMPONENT "hvc_iucv" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hvc_console.h" - - -/* General device driver settings */ -#define HVC_IUCV_MAGIC 0xc9e4c3e5 -#define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS -#define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) - -/* IUCV TTY message */ -#define MSG_VERSION 0x02 /* Message version */ -#define MSG_TYPE_ERROR 0x01 /* Error message */ -#define MSG_TYPE_TERMENV 0x02 /* Terminal environment variable */ -#define MSG_TYPE_TERMIOS 0x04 /* Terminal IO struct update */ -#define MSG_TYPE_WINSIZE 0x08 /* Terminal window size update */ -#define MSG_TYPE_DATA 0x10 /* Terminal data */ - -struct iucv_tty_msg { - u8 version; /* Message version */ - u8 type; /* Message type */ -#define MSG_MAX_DATALEN ((u16)(~0)) - u16 datalen; /* Payload length */ - u8 data[]; /* Payload buffer */ -} __attribute__((packed)); -#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data)) - -enum iucv_state_t { - IUCV_DISCONN = 0, - IUCV_CONNECTED = 1, - IUCV_SEVERED = 2, -}; - -enum tty_state_t { - TTY_CLOSED = 0, - TTY_OPENED = 1, -}; - -struct hvc_iucv_private { - struct hvc_struct *hvc; /* HVC struct reference */ - u8 srv_name[8]; /* IUCV service name (ebcdic) */ - unsigned char is_console; /* Linux console usage flag */ - enum iucv_state_t iucv_state; /* IUCV connection status */ - enum tty_state_t tty_state; /* TTY status */ - struct iucv_path *path; /* IUCV path pointer */ - spinlock_t lock; /* hvc_iucv_private lock */ -#define SNDBUF_SIZE (PAGE_SIZE) /* must be < MSG_MAX_DATALEN */ - void *sndbuf; /* send buffer */ - size_t sndbuf_len; /* length of send buffer */ -#define QUEUE_SNDBUF_DELAY (HZ / 25) - struct delayed_work sndbuf_work; /* work: send iucv msg(s) */ - wait_queue_head_t sndbuf_waitq; /* wait for send completion */ - struct list_head tty_outqueue; /* outgoing IUCV messages */ - struct list_head tty_inqueue; /* incoming IUCV messages */ - struct device *dev; /* device structure */ -}; - -struct iucv_tty_buffer { - struct list_head list; /* list pointer */ - struct iucv_message msg; /* store an IUCV message */ - size_t offset; /* data buffer offset */ - struct iucv_tty_msg *mbuf; /* buffer to store input/output data */ -}; - -/* IUCV callback handler */ -static int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]); -static void hvc_iucv_path_severed(struct iucv_path *, u8[16]); -static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *); -static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *); - - -/* Kernel module parameter: use one terminal device as default */ -static unsigned long hvc_iucv_devices = 1; - -/* Array of allocated hvc iucv tty lines... */ -static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; -#define IUCV_HVC_CON_IDX (0) -/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */ -#define MAX_VMID_FILTER (500) -static size_t hvc_iucv_filter_size; -static void *hvc_iucv_filter; -static const char *hvc_iucv_filter_string; -static DEFINE_RWLOCK(hvc_iucv_filter_lock); - -/* Kmem cache and mempool for iucv_tty_buffer elements */ -static struct kmem_cache *hvc_iucv_buffer_cache; -static mempool_t *hvc_iucv_mempool; - -/* IUCV handler callback functions */ -static struct iucv_handler hvc_iucv_handler = { - .path_pending = hvc_iucv_path_pending, - .path_severed = hvc_iucv_path_severed, - .message_complete = hvc_iucv_msg_complete, - .message_pending = hvc_iucv_msg_pending, -}; - - -/** - * hvc_iucv_get_private() - Return a struct hvc_iucv_private instance. - * @num: The HVC virtual terminal number (vtermno) - * - * This function returns the struct hvc_iucv_private instance that corresponds - * to the HVC virtual terminal number specified as parameter @num. - */ -struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) -{ - if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) - return NULL; - return hvc_iucv_table[num - HVC_IUCV_MAGIC]; -} - -/** - * alloc_tty_buffer() - Return a new struct iucv_tty_buffer element. - * @size: Size of the internal buffer used to store data. - * @flags: Memory allocation flags passed to mempool. - * - * This function allocates a new struct iucv_tty_buffer element and, optionally, - * allocates an internal data buffer with the specified size @size. - * The internal data buffer is always allocated with GFP_DMA which is - * required for receiving and sending data with IUCV. - * Note: The total message size arises from the internal buffer size and the - * members of the iucv_tty_msg structure. - * The function returns NULL if memory allocation has failed. - */ -static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) -{ - struct iucv_tty_buffer *bufp; - - bufp = mempool_alloc(hvc_iucv_mempool, flags); - if (!bufp) - return NULL; - memset(bufp, 0, sizeof(*bufp)); - - if (size > 0) { - bufp->msg.length = MSG_SIZE(size); - bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA); - if (!bufp->mbuf) { - mempool_free(bufp, hvc_iucv_mempool); - return NULL; - } - bufp->mbuf->version = MSG_VERSION; - bufp->mbuf->type = MSG_TYPE_DATA; - bufp->mbuf->datalen = (u16) size; - } - return bufp; -} - -/** - * destroy_tty_buffer() - destroy struct iucv_tty_buffer element. - * @bufp: Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL. - */ -static void destroy_tty_buffer(struct iucv_tty_buffer *bufp) -{ - kfree(bufp->mbuf); - mempool_free(bufp, hvc_iucv_mempool); -} - -/** - * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element. - * @list: List containing struct iucv_tty_buffer elements. - */ -static void destroy_tty_buffer_list(struct list_head *list) -{ - struct iucv_tty_buffer *ent, *next; - - list_for_each_entry_safe(ent, next, list, list) { - list_del(&ent->list); - destroy_tty_buffer(ent); - } -} - -/** - * hvc_iucv_write() - Receive IUCV message & write data to HVC buffer. - * @priv: Pointer to struct hvc_iucv_private - * @buf: HVC buffer for writing received terminal data. - * @count: HVC buffer size. - * @has_more_data: Pointer to an int variable. - * - * The function picks up pending messages from the input queue and receives - * the message data that is then written to the specified buffer @buf. - * If the buffer size @count is less than the data message size, the - * message is kept on the input queue and @has_more_data is set to 1. - * If all message data has been written, the message is removed from - * the input queue. - * - * The function returns the number of bytes written to the terminal, zero if - * there are no pending data messages available or if there is no established - * IUCV path. - * If the IUCV path has been severed, then -EPIPE is returned to cause a - * hang up (that is issued by the HVC layer). - */ -static int hvc_iucv_write(struct hvc_iucv_private *priv, - char *buf, int count, int *has_more_data) -{ - struct iucv_tty_buffer *rb; - int written; - int rc; - - /* immediately return if there is no IUCV connection */ - if (priv->iucv_state == IUCV_DISCONN) - return 0; - - /* if the IUCV path has been severed, return -EPIPE to inform the - * HVC layer to hang up the tty device. */ - if (priv->iucv_state == IUCV_SEVERED) - return -EPIPE; - - /* check if there are pending messages */ - if (list_empty(&priv->tty_inqueue)) - return 0; - - /* receive an iucv message and flip data to the tty (ldisc) */ - rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list); - - written = 0; - if (!rb->mbuf) { /* message not yet received ... */ - /* allocate mem to store msg data; if no memory is available - * then leave the buffer on the list and re-try later */ - rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA); - if (!rb->mbuf) - return -ENOMEM; - - rc = __iucv_message_receive(priv->path, &rb->msg, 0, - rb->mbuf, rb->msg.length, NULL); - switch (rc) { - case 0: /* Successful */ - break; - case 2: /* No message found */ - case 9: /* Message purged */ - break; - default: - written = -EIO; - } - /* remove buffer if an error has occured or received data - * is not correct */ - if (rc || (rb->mbuf->version != MSG_VERSION) || - (rb->msg.length != MSG_SIZE(rb->mbuf->datalen))) - goto out_remove_buffer; - } - - switch (rb->mbuf->type) { - case MSG_TYPE_DATA: - written = min_t(int, rb->mbuf->datalen - rb->offset, count); - memcpy(buf, rb->mbuf->data + rb->offset, written); - if (written < (rb->mbuf->datalen - rb->offset)) { - rb->offset += written; - *has_more_data = 1; - goto out_written; - } - break; - - case MSG_TYPE_WINSIZE: - if (rb->mbuf->datalen != sizeof(struct winsize)) - break; - /* The caller must ensure that the hvc is locked, which - * is the case when called from hvc_iucv_get_chars() */ - __hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data)); - break; - - case MSG_TYPE_ERROR: /* ignored ... */ - case MSG_TYPE_TERMENV: /* ignored ... */ - case MSG_TYPE_TERMIOS: /* ignored ... */ - break; - } - -out_remove_buffer: - list_del(&rb->list); - destroy_tty_buffer(rb); - *has_more_data = !list_empty(&priv->tty_inqueue); - -out_written: - return written; -} - -/** - * hvc_iucv_get_chars() - HVC get_chars operation. - * @vtermno: HVC virtual terminal number. - * @buf: Pointer to a buffer to store data - * @count: Size of buffer available for writing - * - * The HVC thread calls this method to read characters from the back-end. - * If an IUCV communication path has been established, pending IUCV messages - * are received and data is copied into buffer @buf up to @count bytes. - * - * Locking: The routine gets called under an irqsave() spinlock; and - * the routine locks the struct hvc_iucv_private->lock to call - * helper functions. - */ -static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count) -{ - struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); - int written; - int has_more_data; - - if (count <= 0) - return 0; - - if (!priv) - return -ENODEV; - - spin_lock(&priv->lock); - has_more_data = 0; - written = hvc_iucv_write(priv, buf, count, &has_more_data); - spin_unlock(&priv->lock); - - /* if there are still messages on the queue... schedule another run */ - if (has_more_data) - hvc_kick(); - - return written; -} - -/** - * hvc_iucv_queue() - Buffer terminal data for sending. - * @priv: Pointer to struct hvc_iucv_private instance. - * @buf: Buffer containing data to send. - * @count: Size of buffer and amount of data to send. - * - * The function queues data for sending. To actually send the buffered data, - * a work queue function is scheduled (with QUEUE_SNDBUF_DELAY). - * The function returns the number of data bytes that has been buffered. - * - * If the device is not connected, data is ignored and the function returns - * @count. - * If the buffer is full, the function returns 0. - * If an existing IUCV communicaton path has been severed, -EPIPE is returned - * (that can be passed to HVC layer to cause a tty hangup). - */ -static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf, - int count) -{ - size_t len; - - if (priv->iucv_state == IUCV_DISCONN) - return count; /* ignore data */ - - if (priv->iucv_state == IUCV_SEVERED) - return -EPIPE; - - len = min_t(size_t, count, SNDBUF_SIZE - priv->sndbuf_len); - if (!len) - return 0; - - memcpy(priv->sndbuf + priv->sndbuf_len, buf, len); - priv->sndbuf_len += len; - - if (priv->iucv_state == IUCV_CONNECTED) - schedule_delayed_work(&priv->sndbuf_work, QUEUE_SNDBUF_DELAY); - - return len; -} - -/** - * hvc_iucv_send() - Send an IUCV message containing terminal data. - * @priv: Pointer to struct hvc_iucv_private instance. - * - * If an IUCV communication path has been established, the buffered output data - * is sent via an IUCV message and the number of bytes sent is returned. - * Returns 0 if there is no established IUCV communication path or - * -EPIPE if an existing IUCV communicaton path has been severed. - */ -static int hvc_iucv_send(struct hvc_iucv_private *priv) -{ - struct iucv_tty_buffer *sb; - int rc, len; - - if (priv->iucv_state == IUCV_SEVERED) - return -EPIPE; - - if (priv->iucv_state == IUCV_DISCONN) - return -EIO; - - if (!priv->sndbuf_len) - return 0; - - /* allocate internal buffer to store msg data and also compute total - * message length */ - sb = alloc_tty_buffer(priv->sndbuf_len, GFP_ATOMIC); - if (!sb) - return -ENOMEM; - - memcpy(sb->mbuf->data, priv->sndbuf, priv->sndbuf_len); - sb->mbuf->datalen = (u16) priv->sndbuf_len; - sb->msg.length = MSG_SIZE(sb->mbuf->datalen); - - list_add_tail(&sb->list, &priv->tty_outqueue); - - rc = __iucv_message_send(priv->path, &sb->msg, 0, 0, - (void *) sb->mbuf, sb->msg.length); - if (rc) { - /* drop the message here; however we might want to handle - * 0x03 (msg limit reached) by trying again... */ - list_del(&sb->list); - destroy_tty_buffer(sb); - } - len = priv->sndbuf_len; - priv->sndbuf_len = 0; - - return len; -} - -/** - * hvc_iucv_sndbuf_work() - Send buffered data over IUCV - * @work: Work structure. - * - * This work queue function sends buffered output data over IUCV and, - * if not all buffered data could be sent, reschedules itself. - */ -static void hvc_iucv_sndbuf_work(struct work_struct *work) -{ - struct hvc_iucv_private *priv; - - priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work); - if (!priv) - return; - - spin_lock_bh(&priv->lock); - hvc_iucv_send(priv); - spin_unlock_bh(&priv->lock); -} - -/** - * hvc_iucv_put_chars() - HVC put_chars operation. - * @vtermno: HVC virtual terminal number. - * @buf: Pointer to an buffer to read data from - * @count: Size of buffer available for reading - * - * The HVC thread calls this method to write characters to the back-end. - * The function calls hvc_iucv_queue() to queue terminal data for sending. - * - * Locking: The method gets called under an irqsave() spinlock; and - * locks struct hvc_iucv_private->lock. - */ -static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) -{ - struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); - int queued; - - if (count <= 0) - return 0; - - if (!priv) - return -ENODEV; - - spin_lock(&priv->lock); - queued = hvc_iucv_queue(priv, buf, count); - spin_unlock(&priv->lock); - - return queued; -} - -/** - * hvc_iucv_notifier_add() - HVC notifier for opening a TTY for the first time. - * @hp: Pointer to the HVC device (struct hvc_struct) - * @id: Additional data (originally passed to hvc_alloc): the index of an struct - * hvc_iucv_private instance. - * - * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private - * instance that is derived from @id. Always returns 0. - * - * Locking: struct hvc_iucv_private->lock, spin_lock_bh - */ -static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id) -{ - struct hvc_iucv_private *priv; - - priv = hvc_iucv_get_private(id); - if (!priv) - return 0; - - spin_lock_bh(&priv->lock); - priv->tty_state = TTY_OPENED; - spin_unlock_bh(&priv->lock); - - return 0; -} - -/** - * hvc_iucv_cleanup() - Clean up and reset a z/VM IUCV HVC instance. - * @priv: Pointer to the struct hvc_iucv_private instance. - */ -static void hvc_iucv_cleanup(struct hvc_iucv_private *priv) -{ - destroy_tty_buffer_list(&priv->tty_outqueue); - destroy_tty_buffer_list(&priv->tty_inqueue); - - priv->tty_state = TTY_CLOSED; - priv->iucv_state = IUCV_DISCONN; - - priv->sndbuf_len = 0; -} - -/** - * tty_outqueue_empty() - Test if the tty outq is empty - * @priv: Pointer to struct hvc_iucv_private instance. - */ -static inline int tty_outqueue_empty(struct hvc_iucv_private *priv) -{ - int rc; - - spin_lock_bh(&priv->lock); - rc = list_empty(&priv->tty_outqueue); - spin_unlock_bh(&priv->lock); - - return rc; -} - -/** - * flush_sndbuf_sync() - Flush send buffer and wait for completion - * @priv: Pointer to struct hvc_iucv_private instance. - * - * The routine cancels a pending sndbuf work, calls hvc_iucv_send() - * to flush any buffered terminal output data and waits for completion. - */ -static void flush_sndbuf_sync(struct hvc_iucv_private *priv) -{ - int sync_wait; - - cancel_delayed_work_sync(&priv->sndbuf_work); - - spin_lock_bh(&priv->lock); - hvc_iucv_send(priv); /* force sending buffered data */ - sync_wait = !list_empty(&priv->tty_outqueue); /* anything queued ? */ - spin_unlock_bh(&priv->lock); - - if (sync_wait) - wait_event_timeout(priv->sndbuf_waitq, - tty_outqueue_empty(priv), HZ/10); -} - -/** - * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up - * @priv: Pointer to hvc_iucv_private structure - * - * This routine severs an existing IUCV communication path and hangs - * up the underlying HVC terminal device. - * The hang-up occurs only if an IUCV communication path is established; - * otherwise there is no need to hang up the terminal device. - * - * The IUCV HVC hang-up is separated into two steps: - * 1. After the IUCV path has been severed, the iucv_state is set to - * IUCV_SEVERED. - * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the - * IUCV_SEVERED state causes the tty hang-up in the HVC layer. - * - * If the tty has not yet been opened, clean up the hvc_iucv_private - * structure to allow re-connects. - * If the tty has been opened, let get_chars() return -EPIPE to signal - * the HVC layer to hang up the tty and, if so, wake up the HVC thread - * to call get_chars()... - * - * Special notes on hanging up a HVC terminal instantiated as console: - * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops) - * 2. do_tty_hangup() calls tty->ops->close() for console_filp - * => no hangup notifier is called by HVC (default) - * 2. hvc_close() returns because of tty_hung_up_p(filp) - * => no delete notifier is called! - * Finally, the back-end is not being notified, thus, the tty session is - * kept active (TTY_OPEN) to be ready for re-connects. - * - * Locking: spin_lock(&priv->lock) w/o disabling bh - */ -static void hvc_iucv_hangup(struct hvc_iucv_private *priv) -{ - struct iucv_path *path; - - path = NULL; - spin_lock(&priv->lock); - if (priv->iucv_state == IUCV_CONNECTED) { - path = priv->path; - priv->path = NULL; - priv->iucv_state = IUCV_SEVERED; - if (priv->tty_state == TTY_CLOSED) - hvc_iucv_cleanup(priv); - else - /* console is special (see above) */ - if (priv->is_console) { - hvc_iucv_cleanup(priv); - priv->tty_state = TTY_OPENED; - } else - hvc_kick(); - } - spin_unlock(&priv->lock); - - /* finally sever path (outside of priv->lock due to lock ordering) */ - if (path) { - iucv_path_sever(path, NULL); - iucv_path_free(path); - } -} - -/** - * hvc_iucv_notifier_hangup() - HVC notifier for TTY hangups. - * @hp: Pointer to the HVC device (struct hvc_struct) - * @id: Additional data (originally passed to hvc_alloc): - * the index of an struct hvc_iucv_private instance. - * - * This routine notifies the HVC back-end that a tty hangup (carrier loss, - * virtual or otherwise) has occured. - * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup()) - * to keep an existing IUCV communication path established. - * (Background: vhangup() is called from user space (by getty or login) to - * disable writing to the tty by other applications). - * If the tty has been opened and an established IUCV path has been severed - * (we caused the tty hangup), the function calls hvc_iucv_cleanup(). - * - * Locking: struct hvc_iucv_private->lock - */ -static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) -{ - struct hvc_iucv_private *priv; - - priv = hvc_iucv_get_private(id); - if (!priv) - return; - - flush_sndbuf_sync(priv); - - spin_lock_bh(&priv->lock); - /* NOTE: If the hangup was scheduled by ourself (from the iucv - * path_servered callback [IUCV_SEVERED]), we have to clean up - * our structure and to set state to TTY_CLOSED. - * If the tty was hung up otherwise (e.g. vhangup()), then we - * ignore this hangup and keep an established IUCV path open... - * (...the reason is that we are not able to connect back to the - * client if we disconnect on hang up) */ - priv->tty_state = TTY_CLOSED; - - if (priv->iucv_state == IUCV_SEVERED) - hvc_iucv_cleanup(priv); - spin_unlock_bh(&priv->lock); -} - -/** - * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time. - * @hp: Pointer to the HVC device (struct hvc_struct) - * @id: Additional data (originally passed to hvc_alloc): - * the index of an struct hvc_iucv_private instance. - * - * This routine notifies the HVC back-end that the last tty device fd has been - * closed. The function calls hvc_iucv_cleanup() to clean up the struct - * hvc_iucv_private instance. - * - * Locking: struct hvc_iucv_private->lock - */ -static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) -{ - struct hvc_iucv_private *priv; - struct iucv_path *path; - - priv = hvc_iucv_get_private(id); - if (!priv) - return; - - flush_sndbuf_sync(priv); - - spin_lock_bh(&priv->lock); - path = priv->path; /* save reference to IUCV path */ - priv->path = NULL; - hvc_iucv_cleanup(priv); - spin_unlock_bh(&priv->lock); - - /* sever IUCV path outside of priv->lock due to lock ordering of: - * priv->lock <--> iucv_table_lock */ - if (path) { - iucv_path_sever(path, NULL); - iucv_path_free(path); - } -} - -/** - * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID - * @ipvmid: Originating z/VM user ID (right padded with blanks) - * - * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise - * non-zero. - */ -static int hvc_iucv_filter_connreq(u8 ipvmid[8]) -{ - size_t i; - - /* Note: default policy is ACCEPT if no filter is set */ - if (!hvc_iucv_filter_size) - return 0; - - for (i = 0; i < hvc_iucv_filter_size; i++) - if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8)) - return 0; - return 1; -} - -/** - * hvc_iucv_path_pending() - IUCV handler to process a connection request. - * @path: Pending path (struct iucv_path) - * @ipvmid: z/VM system identifier of originator - * @ipuser: User specified data for this path - * (AF_IUCV: port/service name and originator port) - * - * The function uses the @ipuser data to determine if the pending path belongs - * to a terminal managed by this device driver. - * If the path belongs to this driver, ensure that the terminal is not accessed - * multiple times (only one connection to a terminal is allowed). - * If the terminal is not yet connected, the pending path is accepted and is - * associated to the appropriate struct hvc_iucv_private instance. - * - * Returns 0 if @path belongs to a terminal managed by the this device driver; - * otherwise returns -ENODEV in order to dispatch this path to other handlers. - * - * Locking: struct hvc_iucv_private->lock - */ -static int hvc_iucv_path_pending(struct iucv_path *path, - u8 ipvmid[8], u8 ipuser[16]) -{ - struct hvc_iucv_private *priv; - u8 nuser_data[16]; - u8 vm_user_id[9]; - int i, rc; - - priv = NULL; - for (i = 0; i < hvc_iucv_devices; i++) - if (hvc_iucv_table[i] && - (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { - priv = hvc_iucv_table[i]; - break; - } - if (!priv) - return -ENODEV; - - /* Enforce that ipvmid is allowed to connect to us */ - read_lock(&hvc_iucv_filter_lock); - rc = hvc_iucv_filter_connreq(ipvmid); - read_unlock(&hvc_iucv_filter_lock); - if (rc) { - iucv_path_sever(path, ipuser); - iucv_path_free(path); - memcpy(vm_user_id, ipvmid, 8); - vm_user_id[8] = 0; - pr_info("A connection request from z/VM user ID %s " - "was refused\n", vm_user_id); - return 0; - } - - spin_lock(&priv->lock); - - /* If the terminal is already connected or being severed, then sever - * this path to enforce that there is only ONE established communication - * path per terminal. */ - if (priv->iucv_state != IUCV_DISCONN) { - iucv_path_sever(path, ipuser); - iucv_path_free(path); - goto out_path_handled; - } - - /* accept path */ - memcpy(nuser_data, ipuser + 8, 8); /* remote service (for af_iucv) */ - memcpy(nuser_data + 8, ipuser, 8); /* local service (for af_iucv) */ - path->msglim = 0xffff; /* IUCV MSGLIMIT */ - path->flags &= ~IUCV_IPRMDATA; /* TODO: use IUCV_IPRMDATA */ - rc = iucv_path_accept(path, &hvc_iucv_handler, nuser_data, priv); - if (rc) { - iucv_path_sever(path, ipuser); - iucv_path_free(path); - goto out_path_handled; - } - priv->path = path; - priv->iucv_state = IUCV_CONNECTED; - - /* flush buffered output data... */ - schedule_delayed_work(&priv->sndbuf_work, 5); - -out_path_handled: - spin_unlock(&priv->lock); - return 0; -} - -/** - * hvc_iucv_path_severed() - IUCV handler to process a path sever. - * @path: Pending path (struct iucv_path) - * @ipuser: User specified data for this path - * (AF_IUCV: port/service name and originator port) - * - * This function calls the hvc_iucv_hangup() function for the - * respective IUCV HVC terminal. - * - * Locking: struct hvc_iucv_private->lock - */ -static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) -{ - struct hvc_iucv_private *priv = path->private; - - hvc_iucv_hangup(priv); -} - -/** - * hvc_iucv_msg_pending() - IUCV handler to process an incoming IUCV message. - * @path: Pending path (struct iucv_path) - * @msg: Pointer to the IUCV message - * - * The function puts an incoming message on the input queue for later - * processing (by hvc_iucv_get_chars() / hvc_iucv_write()). - * If the tty has not yet been opened, the message is rejected. - * - * Locking: struct hvc_iucv_private->lock - */ -static void hvc_iucv_msg_pending(struct iucv_path *path, - struct iucv_message *msg) -{ - struct hvc_iucv_private *priv = path->private; - struct iucv_tty_buffer *rb; - - /* reject messages that exceed max size of iucv_tty_msg->datalen */ - if (msg->length > MSG_SIZE(MSG_MAX_DATALEN)) { - iucv_message_reject(path, msg); - return; - } - - spin_lock(&priv->lock); - - /* reject messages if tty has not yet been opened */ - if (priv->tty_state == TTY_CLOSED) { - iucv_message_reject(path, msg); - goto unlock_return; - } - - /* allocate tty buffer to save iucv msg only */ - rb = alloc_tty_buffer(0, GFP_ATOMIC); - if (!rb) { - iucv_message_reject(path, msg); - goto unlock_return; /* -ENOMEM */ - } - rb->msg = *msg; - - list_add_tail(&rb->list, &priv->tty_inqueue); - - hvc_kick(); /* wake up hvc thread */ - -unlock_return: - spin_unlock(&priv->lock); -} - -/** - * hvc_iucv_msg_complete() - IUCV handler to process message completion - * @path: Pending path (struct iucv_path) - * @msg: Pointer to the IUCV message - * - * The function is called upon completion of message delivery to remove the - * message from the outqueue. Additional delivery information can be found - * msg->audit: rejected messages (0x040000 (IPADRJCT)), and - * purged messages (0x010000 (IPADPGNR)). - * - * Locking: struct hvc_iucv_private->lock - */ -static void hvc_iucv_msg_complete(struct iucv_path *path, - struct iucv_message *msg) -{ - struct hvc_iucv_private *priv = path->private; - struct iucv_tty_buffer *ent, *next; - LIST_HEAD(list_remove); - - spin_lock(&priv->lock); - list_for_each_entry_safe(ent, next, &priv->tty_outqueue, list) - if (ent->msg.id == msg->id) { - list_move(&ent->list, &list_remove); - break; - } - wake_up(&priv->sndbuf_waitq); - spin_unlock(&priv->lock); - destroy_tty_buffer_list(&list_remove); -} - -/** - * hvc_iucv_pm_freeze() - Freeze PM callback - * @dev: IUVC HVC terminal device - * - * Sever an established IUCV communication path and - * trigger a hang-up of the underlying HVC terminal. - */ -static int hvc_iucv_pm_freeze(struct device *dev) -{ - struct hvc_iucv_private *priv = dev_get_drvdata(dev); - - local_bh_disable(); - hvc_iucv_hangup(priv); - local_bh_enable(); - - return 0; -} - -/** - * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback - * @dev: IUVC HVC terminal device - * - * Wake up the HVC thread to trigger hang-up and respective - * HVC back-end notifier invocations. - */ -static int hvc_iucv_pm_restore_thaw(struct device *dev) -{ - hvc_kick(); - return 0; -} - - -/* HVC operations */ -static const struct hv_ops hvc_iucv_ops = { - .get_chars = hvc_iucv_get_chars, - .put_chars = hvc_iucv_put_chars, - .notifier_add = hvc_iucv_notifier_add, - .notifier_del = hvc_iucv_notifier_del, - .notifier_hangup = hvc_iucv_notifier_hangup, -}; - -/* Suspend / resume device operations */ -static const struct dev_pm_ops hvc_iucv_pm_ops = { - .freeze = hvc_iucv_pm_freeze, - .thaw = hvc_iucv_pm_restore_thaw, - .restore = hvc_iucv_pm_restore_thaw, -}; - -/* IUCV HVC device driver */ -static struct device_driver hvc_iucv_driver = { - .name = KMSG_COMPONENT, - .bus = &iucv_bus, - .pm = &hvc_iucv_pm_ops, -}; - -/** - * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance - * @id: hvc_iucv_table index - * @is_console: Flag if the instance is used as Linux console - * - * This function allocates a new hvc_iucv_private structure and stores - * the instance in hvc_iucv_table at index @id. - * Returns 0 on success; otherwise non-zero. - */ -static int __init hvc_iucv_alloc(int id, unsigned int is_console) -{ - struct hvc_iucv_private *priv; - char name[9]; - int rc; - - priv = kzalloc(sizeof(struct hvc_iucv_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - spin_lock_init(&priv->lock); - INIT_LIST_HEAD(&priv->tty_outqueue); - INIT_LIST_HEAD(&priv->tty_inqueue); - INIT_DELAYED_WORK(&priv->sndbuf_work, hvc_iucv_sndbuf_work); - init_waitqueue_head(&priv->sndbuf_waitq); - - priv->sndbuf = (void *) get_zeroed_page(GFP_KERNEL); - if (!priv->sndbuf) { - kfree(priv); - return -ENOMEM; - } - - /* set console flag */ - priv->is_console = is_console; - - /* allocate hvc device */ - priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ - HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); - if (IS_ERR(priv->hvc)) { - rc = PTR_ERR(priv->hvc); - goto out_error_hvc; - } - - /* notify HVC thread instead of using polling */ - priv->hvc->irq_requested = 1; - - /* setup iucv related information */ - snprintf(name, 9, "lnxhvc%-2d", id); - memcpy(priv->srv_name, name, 8); - ASCEBC(priv->srv_name, 8); - - /* create and setup device */ - priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL); - if (!priv->dev) { - rc = -ENOMEM; - goto out_error_dev; - } - dev_set_name(priv->dev, "hvc_iucv%d", id); - dev_set_drvdata(priv->dev, priv); - priv->dev->bus = &iucv_bus; - priv->dev->parent = iucv_root; - priv->dev->driver = &hvc_iucv_driver; - priv->dev->release = (void (*)(struct device *)) kfree; - rc = device_register(priv->dev); - if (rc) { - put_device(priv->dev); - goto out_error_dev; - } - - hvc_iucv_table[id] = priv; - return 0; - -out_error_dev: - hvc_remove(priv->hvc); -out_error_hvc: - free_page((unsigned long) priv->sndbuf); - kfree(priv); - - return rc; -} - -/** - * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances - */ -static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) -{ - hvc_remove(priv->hvc); - device_unregister(priv->dev); - free_page((unsigned long) priv->sndbuf); - kfree(priv); -} - -/** - * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID - * @filter: String containing a comma-separated list of z/VM user IDs - */ -static const char *hvc_iucv_parse_filter(const char *filter, char *dest) -{ - const char *nextdelim, *residual; - size_t len; - - nextdelim = strchr(filter, ','); - if (nextdelim) { - len = nextdelim - filter; - residual = nextdelim + 1; - } else { - len = strlen(filter); - residual = filter + len; - } - - if (len == 0) - return ERR_PTR(-EINVAL); - - /* check for '\n' (if called from sysfs) */ - if (filter[len - 1] == '\n') - len--; - - if (len > 8) - return ERR_PTR(-EINVAL); - - /* pad with blanks and save upper case version of user ID */ - memset(dest, ' ', 8); - while (len--) - dest[len] = toupper(filter[len]); - return residual; -} - -/** - * hvc_iucv_setup_filter() - Set up z/VM user ID filter - * @filter: String consisting of a comma-separated list of z/VM user IDs - * - * The function parses the @filter string and creates an array containing - * the list of z/VM user ID filter entries. - * Return code 0 means success, -EINVAL if the filter is syntactically - * incorrect, -ENOMEM if there was not enough memory to allocate the - * filter list array, or -ENOSPC if too many z/VM user IDs have been specified. - */ -static int hvc_iucv_setup_filter(const char *val) -{ - const char *residual; - int err; - size_t size, count; - void *array, *old_filter; - - count = strlen(val); - if (count == 0 || (count == 1 && val[0] == '\n')) { - size = 0; - array = NULL; - goto out_replace_filter; /* clear filter */ - } - - /* count user IDs in order to allocate sufficient memory */ - size = 1; - residual = val; - while ((residual = strchr(residual, ',')) != NULL) { - residual++; - size++; - } - - /* check if the specified list exceeds the filter limit */ - if (size > MAX_VMID_FILTER) - return -ENOSPC; - - array = kzalloc(size * 8, GFP_KERNEL); - if (!array) - return -ENOMEM; - - count = size; - residual = val; - while (*residual && count) { - residual = hvc_iucv_parse_filter(residual, - array + ((size - count) * 8)); - if (IS_ERR(residual)) { - err = PTR_ERR(residual); - kfree(array); - goto out_err; - } - count--; - } - -out_replace_filter: - write_lock_bh(&hvc_iucv_filter_lock); - old_filter = hvc_iucv_filter; - hvc_iucv_filter_size = size; - hvc_iucv_filter = array; - write_unlock_bh(&hvc_iucv_filter_lock); - kfree(old_filter); - - err = 0; -out_err: - return err; -} - -/** - * param_set_vmidfilter() - Set z/VM user ID filter parameter - * @val: String consisting of a comma-separated list of z/VM user IDs - * @kp: Kernel parameter pointing to hvc_iucv_filter array - * - * The function sets up the z/VM user ID filter specified as comma-separated - * list of user IDs in @val. - * Note: If it is called early in the boot process, @val is stored and - * parsed later in hvc_iucv_init(). - */ -static int param_set_vmidfilter(const char *val, const struct kernel_param *kp) -{ - int rc; - - if (!MACHINE_IS_VM || !hvc_iucv_devices) - return -ENODEV; - - if (!val) - return -EINVAL; - - rc = 0; - if (slab_is_available()) - rc = hvc_iucv_setup_filter(val); - else - hvc_iucv_filter_string = val; /* defer... */ - return rc; -} - -/** - * param_get_vmidfilter() - Get z/VM user ID filter - * @buffer: Buffer to store z/VM user ID filter, - * (buffer size assumption PAGE_SIZE) - * @kp: Kernel parameter pointing to the hvc_iucv_filter array - * - * The function stores the filter as a comma-separated list of z/VM user IDs - * in @buffer. Typically, sysfs routines call this function for attr show. - */ -static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp) -{ - int rc; - size_t index, len; - void *start, *end; - - if (!MACHINE_IS_VM || !hvc_iucv_devices) - return -ENODEV; - - rc = 0; - read_lock_bh(&hvc_iucv_filter_lock); - for (index = 0; index < hvc_iucv_filter_size; index++) { - start = hvc_iucv_filter + (8 * index); - end = memchr(start, ' ', 8); - len = (end) ? end - start : 8; - memcpy(buffer + rc, start, len); - rc += len; - buffer[rc++] = ','; - } - read_unlock_bh(&hvc_iucv_filter_lock); - if (rc) - buffer[--rc] = '\0'; /* replace last comma and update rc */ - return rc; -} - -#define param_check_vmidfilter(name, p) __param_check(name, p, void) - -static struct kernel_param_ops param_ops_vmidfilter = { - .set = param_set_vmidfilter, - .get = param_get_vmidfilter, -}; - -/** - * hvc_iucv_init() - z/VM IUCV HVC device driver initialization - */ -static int __init hvc_iucv_init(void) -{ - int rc; - unsigned int i; - - if (!hvc_iucv_devices) - return -ENODEV; - - if (!MACHINE_IS_VM) { - pr_notice("The z/VM IUCV HVC device driver cannot " - "be used without z/VM\n"); - rc = -ENODEV; - goto out_error; - } - - if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) { - pr_err("%lu is not a valid value for the hvc_iucv= " - "kernel parameter\n", hvc_iucv_devices); - rc = -EINVAL; - goto out_error; - } - - /* register IUCV HVC device driver */ - rc = driver_register(&hvc_iucv_driver); - if (rc) - goto out_error; - - /* parse hvc_iucv_allow string and create z/VM user ID filter list */ - if (hvc_iucv_filter_string) { - rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); - switch (rc) { - case 0: - break; - case -ENOMEM: - pr_err("Allocating memory failed with " - "reason code=%d\n", 3); - goto out_error; - case -EINVAL: - pr_err("hvc_iucv_allow= does not specify a valid " - "z/VM user ID list\n"); - goto out_error; - case -ENOSPC: - pr_err("hvc_iucv_allow= specifies too many " - "z/VM user IDs\n"); - goto out_error; - default: - goto out_error; - } - } - - hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT, - sizeof(struct iucv_tty_buffer), - 0, 0, NULL); - if (!hvc_iucv_buffer_cache) { - pr_err("Allocating memory failed with reason code=%d\n", 1); - rc = -ENOMEM; - goto out_error; - } - - hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR, - hvc_iucv_buffer_cache); - if (!hvc_iucv_mempool) { - pr_err("Allocating memory failed with reason code=%d\n", 2); - kmem_cache_destroy(hvc_iucv_buffer_cache); - rc = -ENOMEM; - goto out_error; - } - - /* register the first terminal device as console - * (must be done before allocating hvc terminal devices) */ - rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); - if (rc) { - pr_err("Registering HVC terminal device as " - "Linux console failed\n"); - goto out_error_memory; - } - - /* allocate hvc_iucv_private structs */ - for (i = 0; i < hvc_iucv_devices; i++) { - rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0); - if (rc) { - pr_err("Creating a new HVC terminal device " - "failed with error code=%d\n", rc); - goto out_error_hvc; - } - } - - /* register IUCV callback handler */ - rc = iucv_register(&hvc_iucv_handler, 0); - if (rc) { - pr_err("Registering IUCV handlers failed with error code=%d\n", - rc); - goto out_error_hvc; - } - - return 0; - -out_error_hvc: - for (i = 0; i < hvc_iucv_devices; i++) - if (hvc_iucv_table[i]) - hvc_iucv_destroy(hvc_iucv_table[i]); -out_error_memory: - mempool_destroy(hvc_iucv_mempool); - kmem_cache_destroy(hvc_iucv_buffer_cache); -out_error: - if (hvc_iucv_filter) - kfree(hvc_iucv_filter); - hvc_iucv_devices = 0; /* ensure that we do not provide any device */ - return rc; -} - -/** - * hvc_iucv_config() - Parsing of hvc_iucv= kernel command line parameter - * @val: Parameter value (numeric) - */ -static int __init hvc_iucv_config(char *val) -{ - return strict_strtoul(val, 10, &hvc_iucv_devices); -} - - -device_initcall(hvc_iucv_init); -__setup("hvc_iucv=", hvc_iucv_config); -core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640); diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c deleted file mode 100644 index 61c4a61558d9..000000000000 --- a/drivers/char/hvc_rtas.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * IBM RTAS driver interface to hvc_console.c - * - * (C) Copyright IBM Corporation 2001-2005 - * (C) Copyright Red Hat, Inc. 2005 - * - * Author(s): Maximino Augilar - * : Ryan S. Arnold - * : Utz Bacher - * : David Woodhouse - * - * inspired by drivers/char/hvc_console.c - * written by Anton Blanchard and Paul Mackerras - * - * 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 "hvc_console.h" - -#define hvc_rtas_cookie 0x67781e15 -struct hvc_struct *hvc_rtas_dev; - -static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; -static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; - -static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, - int count) -{ - int i; - - for (i = 0; i < count; i++) { - if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i])) - break; - } - - return i; -} - -static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) -{ - int i, c; - - for (i = 0; i < count; i++) { - if (rtas_call(rtascons_get_char_token, 0, 2, &c)) - break; - - buf[i] = c; - } - - return i; -} - -static const struct hv_ops hvc_rtas_get_put_ops = { - .get_chars = hvc_rtas_read_console, - .put_chars = hvc_rtas_write_console, -}; - -static int __init hvc_rtas_init(void) -{ - struct hvc_struct *hp; - - if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) - rtascons_put_char_token = rtas_token("put-term-char"); - if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) - return -EIO; - - if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) - rtascons_get_char_token = rtas_token("get-term-char"); - if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) - return -EIO; - - BUG_ON(hvc_rtas_dev); - - /* Allocate an hvc_struct for the console device we instantiated - * earlier. Save off hp so that we can return it on exit */ - hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); - if (IS_ERR(hp)) - return PTR_ERR(hp); - - hvc_rtas_dev = hp; - - return 0; -} -module_init(hvc_rtas_init); - -/* This will tear down the tty portion of the driver */ -static void __exit hvc_rtas_exit(void) -{ - /* Really the fun isn't over until the worker thread breaks down and - * the tty cleans up */ - if (hvc_rtas_dev) - hvc_remove(hvc_rtas_dev); -} -module_exit(hvc_rtas_exit); - -/* This will happen prior to module init. There is no tty at this time? */ -static int __init hvc_rtas_console_init(void) -{ - rtascons_put_char_token = rtas_token("put-term-char"); - if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) - return -EIO; - - rtascons_get_char_token = rtas_token("get-term-char"); - if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) - return -EIO; - - hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops); - add_preferred_console("hvc", 0, NULL); - - return 0; -} -console_initcall(hvc_rtas_console_init); diff --git a/drivers/char/hvc_tile.c b/drivers/char/hvc_tile.c deleted file mode 100644 index 7a84a0595477..000000000000 --- a/drivers/char/hvc_tile.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * 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, version 2. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Tilera TILE Processor hypervisor console - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "hvc_console.h" - -static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) -{ - return hv_console_write((HV_VirtAddr)buf, count); -} - -static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) -{ - int i, c; - - for (i = 0; i < count; ++i) { - c = hv_console_read_if_ready(); - if (c < 0) - break; - buf[i] = c; - } - - return i; -} - -static const struct hv_ops hvc_tile_get_put_ops = { - .get_chars = hvc_tile_get_chars, - .put_chars = hvc_tile_put_chars, -}; - -static int __init hvc_tile_console_init(void) -{ - extern void disable_early_printk(void); - hvc_instantiate(0, 0, &hvc_tile_get_put_ops); - add_preferred_console("hvc", 0, NULL); - disable_early_printk(); - return 0; -} -console_initcall(hvc_tile_console_init); - -static int __init hvc_tile_init(void) -{ - struct hvc_struct *s; - s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); - return IS_ERR(s) ? PTR_ERR(s) : 0; -} -device_initcall(hvc_tile_init); diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c deleted file mode 100644 index b0957e61a7be..000000000000 --- a/drivers/char/hvc_udbg.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * udbg interface to hvc_console.c - * - * (C) Copyright David Gibson, IBM Corporation 2008. - * - * 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 "hvc_console.h" - -struct hvc_struct *hvc_udbg_dev; - -static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) -{ - int i; - - for (i = 0; i < count; i++) - udbg_putc(buf[i]); - - return i; -} - -static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) -{ - int i, c; - - if (!udbg_getc_poll) - return 0; - - for (i = 0; i < count; i++) { - if ((c = udbg_getc_poll()) == -1) - break; - buf[i] = c; - } - - return i; -} - -static const struct hv_ops hvc_udbg_ops = { - .get_chars = hvc_udbg_get, - .put_chars = hvc_udbg_put, -}; - -static int __init hvc_udbg_init(void) -{ - struct hvc_struct *hp; - - BUG_ON(hvc_udbg_dev); - - hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); - if (IS_ERR(hp)) - return PTR_ERR(hp); - - hvc_udbg_dev = hp; - - return 0; -} -module_init(hvc_udbg_init); - -static void __exit hvc_udbg_exit(void) -{ - if (hvc_udbg_dev) - hvc_remove(hvc_udbg_dev); -} -module_exit(hvc_udbg_exit); - -static int __init hvc_udbg_console_init(void) -{ - hvc_instantiate(0, 0, &hvc_udbg_ops); - add_preferred_console("hvc", 0, NULL); - - return 0; -} -console_initcall(hvc_udbg_console_init); diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c deleted file mode 100644 index 5e2f52b33327..000000000000 --- a/drivers/char/hvc_vio.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * vio driver interface to hvc_console.c - * - * This code was moved here to allow the remaing code to be reused as a - * generic polling mode with semi-reliable transport driver core to the - * console and tty subsystems. - * - * - * Copyright (C) 2001 Anton Blanchard , IBM - * Copyright (C) 2001 Paul Mackerras , IBM - * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. - * Copyright (C) 2004 IBM Corporation - * - * Additional Author(s): - * Ryan S. Arnold - * - * 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 "hvc_console.h" - -static const char hvc_driver_name[] = "hvc_console"; - -static struct vio_device_id hvc_driver_table[] __devinitdata = { - {"serial", "hvterm1"}, - { "", "" } -}; -MODULE_DEVICE_TABLE(vio, hvc_driver_table); - -static int filtered_get_chars(uint32_t vtermno, char *buf, int count) -{ - unsigned long got; - int i; - - /* - * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion - * so we play safe and avoid the situation where got > count which could - * overload the flip buffer. - */ - if (count < SIZE_VIO_GET_CHARS) - return -EAGAIN; - - got = hvc_get_chars(vtermno, buf, count); - - /* - * Work around a HV bug where it gives us a null - * after every \r. -- paulus - */ - for (i = 1; i < got; ++i) { - if (buf[i] == 0 && buf[i-1] == '\r') { - --got; - if (i < got) - memmove(&buf[i], &buf[i+1], - got - i); - } - } - return got; -} - -static const struct hv_ops hvc_get_put_ops = { - .get_chars = filtered_get_chars, - .put_chars = hvc_put_chars, - .notifier_add = notifier_add_irq, - .notifier_del = notifier_del_irq, - .notifier_hangup = notifier_hangup_irq, -}; - -static int __devinit hvc_vio_probe(struct vio_dev *vdev, - const struct vio_device_id *id) -{ - struct hvc_struct *hp; - - /* probed with invalid parameters. */ - if (!vdev || !id) - return -EPERM; - - hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, - MAX_VIO_PUT_CHARS); - if (IS_ERR(hp)) - return PTR_ERR(hp); - dev_set_drvdata(&vdev->dev, hp); - - return 0; -} - -static int __devexit hvc_vio_remove(struct vio_dev *vdev) -{ - struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); - - return hvc_remove(hp); -} - -static struct vio_driver hvc_vio_driver = { - .id_table = hvc_driver_table, - .probe = hvc_vio_probe, - .remove = __devexit_p(hvc_vio_remove), - .driver = { - .name = hvc_driver_name, - .owner = THIS_MODULE, - } -}; - -static int __init hvc_vio_init(void) -{ - int rc; - - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return -EIO; - - /* Register as a vio device to receive callbacks */ - rc = vio_register_driver(&hvc_vio_driver); - - return rc; -} -module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ - -static void __exit hvc_vio_exit(void) -{ - vio_unregister_driver(&hvc_vio_driver); -} -module_exit(hvc_vio_exit); - -/* the device tree order defines our numbering */ -static int hvc_find_vtys(void) -{ - struct device_node *vty; - int num_found = 0; - - for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; - vty = of_find_node_by_name(vty, "vty")) { - const uint32_t *vtermno; - - /* We have statically defined space for only a certain number - * of console adapters. - */ - if (num_found >= MAX_NR_HVC_CONSOLES) { - of_node_put(vty); - break; - } - - vtermno = of_get_property(vty, "reg", NULL); - if (!vtermno) - continue; - - if (of_device_is_compatible(vty, "hvterm1")) { - hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); - ++num_found; - } - } - - return num_found; -} -console_initcall(hvc_find_vtys); diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c deleted file mode 100644 index 3740e327f180..000000000000 --- a/drivers/char/hvc_xen.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * xen console driver interface to hvc_console.c - * - * (c) 2007 Gerd Hoffmann - * - * 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 - -#include "hvc_console.h" - -#define HVC_COOKIE 0x58656e /* "Xen" in hex */ - -static struct hvc_struct *hvc; -static int xencons_irq; - -/* ------------------------------------------------------------------ */ - -static unsigned long console_pfn = ~0ul; - -static inline struct xencons_interface *xencons_interface(void) -{ - if (console_pfn == ~0ul) - return mfn_to_virt(xen_start_info->console.domU.mfn); - else - return __va(console_pfn << PAGE_SHIFT); -} - -static inline void notify_daemon(void) -{ - /* Use evtchn: this is called early, before irq is set up. */ - notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); -} - -static int __write_console(const char *data, int len) -{ - struct xencons_interface *intf = xencons_interface(); - XENCONS_RING_IDX cons, prod; - int sent = 0; - - cons = intf->out_cons; - prod = intf->out_prod; - mb(); /* update queue values before going on */ - BUG_ON((prod - cons) > sizeof(intf->out)); - - while ((sent < len) && ((prod - cons) < sizeof(intf->out))) - intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; - - wmb(); /* write ring before updating pointer */ - intf->out_prod = prod; - - if (sent) - notify_daemon(); - return sent; -} - -static int domU_write_console(uint32_t vtermno, const char *data, int len) -{ - int ret = len; - - /* - * Make sure the whole buffer is emitted, polling if - * necessary. We don't ever want to rely on the hvc daemon - * because the most interesting console output is when the - * kernel is crippled. - */ - while (len) { - int sent = __write_console(data, len); - - data += sent; - len -= sent; - - if (unlikely(len)) - HYPERVISOR_sched_op(SCHEDOP_yield, NULL); - } - - return ret; -} - -static int domU_read_console(uint32_t vtermno, char *buf, int len) -{ - struct xencons_interface *intf = xencons_interface(); - XENCONS_RING_IDX cons, prod; - int recv = 0; - - cons = intf->in_cons; - prod = intf->in_prod; - mb(); /* get pointers before reading ring */ - BUG_ON((prod - cons) > sizeof(intf->in)); - - while (cons != prod && recv < len) - buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; - - mb(); /* read ring before consuming */ - intf->in_cons = cons; - - notify_daemon(); - return recv; -} - -static struct hv_ops domU_hvc_ops = { - .get_chars = domU_read_console, - .put_chars = domU_write_console, - .notifier_add = notifier_add_irq, - .notifier_del = notifier_del_irq, - .notifier_hangup = notifier_hangup_irq, -}; - -static int dom0_read_console(uint32_t vtermno, char *buf, int len) -{ - return HYPERVISOR_console_io(CONSOLEIO_read, len, buf); -} - -/* - * Either for a dom0 to write to the system console, or a domU with a - * debug version of Xen - */ -static int dom0_write_console(uint32_t vtermno, const char *str, int len) -{ - int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); - if (rc < 0) - return 0; - - return len; -} - -static struct hv_ops dom0_hvc_ops = { - .get_chars = dom0_read_console, - .put_chars = dom0_write_console, - .notifier_add = notifier_add_irq, - .notifier_del = notifier_del_irq, - .notifier_hangup = notifier_hangup_irq, -}; - -static int __init xen_hvc_init(void) -{ - struct hvc_struct *hp; - struct hv_ops *ops; - - if (!xen_pv_domain()) - return -ENODEV; - - if (xen_initial_domain()) { - ops = &dom0_hvc_ops; - xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); - } else { - if (!xen_start_info->console.domU.evtchn) - return -ENODEV; - - ops = &domU_hvc_ops; - xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); - } - if (xencons_irq < 0) - xencons_irq = 0; /* NO_IRQ */ - - hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); - if (IS_ERR(hp)) - return PTR_ERR(hp); - - hvc = hp; - - console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn); - - return 0; -} - -void xen_console_resume(void) -{ - if (xencons_irq) - rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); -} - -static void __exit xen_hvc_fini(void) -{ - if (hvc) - hvc_remove(hvc); -} - -static int xen_cons_init(void) -{ - struct hv_ops *ops; - - if (!xen_pv_domain()) - return 0; - - if (xen_initial_domain()) - ops = &dom0_hvc_ops; - else - ops = &domU_hvc_ops; - - hvc_instantiate(HVC_COOKIE, 0, ops); - return 0; -} - -module_init(xen_hvc_init); -module_exit(xen_hvc_fini); -console_initcall(xen_cons_init); - -#ifdef CONFIG_EARLY_PRINTK -static void xenboot_write_console(struct console *console, const char *string, - unsigned len) -{ - unsigned int linelen, off = 0; - const char *pos; - - dom0_write_console(0, string, len); - - if (xen_initial_domain()) - return; - - domU_write_console(0, "(early) ", 8); - while (off < len && NULL != (pos = strchr(string+off, '\n'))) { - linelen = pos-string+off; - if (off + linelen > len) - break; - domU_write_console(0, string+off, linelen); - domU_write_console(0, "\r\n", 2); - off += linelen + 1; - } - if (off < len) - domU_write_console(0, string+off, len-off); -} - -struct console xenboot_console = { - .name = "xenboot", - .write = xenboot_write_console, - .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, -}; -#endif /* CONFIG_EARLY_PRINTK */ - -void xen_raw_console_write(const char *str) -{ - dom0_write_console(0, str, strlen(str)); -} - -void xen_raw_printk(const char *fmt, ...) -{ - static char buf[512]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - xen_raw_console_write(buf); -} diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c deleted file mode 100644 index bedc6c1b6fa5..000000000000 --- a/drivers/char/hvcs.c +++ /dev/null @@ -1,1604 +0,0 @@ -/* - * IBM eServer Hypervisor Virtual Console Server Device Driver - * Copyright (C) 2003, 2004 IBM Corp. - * Ryan S. Arnold (rsa@us.ibm.com) - * - * 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 - * - * Author(s) : Ryan S. Arnold - * - * This is the device driver for the IBM Hypervisor Virtual Console Server, - * "hvcs". The IBM hvcs provides a tty driver interface to allow Linux - * user space applications access to the system consoles of logically - * partitioned operating systems, e.g. Linux, running on the same partitioned - * Power5 ppc64 system. Physical hardware consoles per partition are not - * practical on this hardware so system consoles are accessed by this driver - * using inter-partition firmware interfaces to virtual terminal devices. - * - * A vty is known to the HMC as a "virtual serial server adapter". It is a - * virtual terminal device that is created by firmware upon partition creation - * to act as a partitioned OS's console device. - * - * Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64 - * Linux system upon their creation by the HMC or their exposure during boot. - * The non-user interactive backend of this driver is implemented as a vio - * device driver so that it can receive notification of vty-server lifetimes - * after it registers with the vio bus to handle vty-server probe and remove - * callbacks. - * - * Many vty-servers can be configured to connect to one vty, but a vty can - * only be actively connected to by a single vty-server, in any manner, at one - * time. If the HMC is currently hosting the console for a target Linux - * partition; attempts to open the tty device to the partition's console using - * the hvcs on any partition will return -EBUSY with every open attempt until - * the HMC frees the connection between its vty-server and the desired - * partition's vty device. Conversely, a vty-server may only be connected to - * a single vty at one time even though it may have several configured vty - * partner possibilities. - * - * Firmware does not provide notification of vty partner changes to this - * driver. This means that an HMC Super Admin may add or remove partner vtys - * from a vty-server's partner list but the changes will not be signaled to - * the vty-server. Firmware only notifies the driver when a vty-server is - * added or removed from the system. To compensate for this deficiency, this - * driver implements a sysfs update attribute which provides a method for - * rescanning partner information upon a user's request. - * - * Each vty-server, prior to being exposed to this driver is reference counted - * using the 2.6 Linux kernel kref construct. - * - * For direction on installation and usage of this driver please reference - * Documentation/powerpc/hvcs.txt. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00). - * Removed braces around single statements following conditionals. Removed '= - * 0' after static int declarations since these default to zero. Removed - * list_for_each_safe() and replaced with list_for_each_entry() in - * hvcs_get_by_index(). The 'safe' version is un-needed now that the driver is - * using spinlocks. Changed spin_lock_irqsave() to spin_lock() when locking - * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int - * handler. Initialized hvcs_structs_lock and hvcs_pi_lock to - * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init(). - * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the - * list traversals from a deletion. Removed '= NULL' from pointer declaration - * statements since they are initialized NULL by default. Removed wmb() - * instances from hvcs_try_write(). They probably aren't needed with locking in - * place. Added check and cleanup for hvcs_pi_buff = kmalloc() in - * hvcs_module_init(). Exposed hvcs_struct.index via a sysfs attribute so that - * the coupling between /dev/hvcs* and a vty-server can be automatically - * determined. Moved kobject_put() in hvcs_open outside of the - * spin_unlock_irqrestore(). - * - * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it - * align with how the tty layer always assigns the lowest index available. This - * change resulted in a list of ints that denotes which indexes are available. - * Device additions and removals use the new hvcs_get_index() and - * hvcs_return_index() helper functions. The list is created with - * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list(). - * Without these fixes hotplug vty-server adapter support goes crazy with this - * driver if the user removes a vty-server adapter. Moved free_irq() outside of - * the hvcs_final_close() function in order to get it out of the spinlock. - * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping - * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from - * arch/powerepc/include/asm/hvcserver.h - * - * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to - * prevent possible lockup with realtime scheduling as similarily pointed out by - * akpm in hvc_console. Changed resulted in the removal of hvcs_final_close() - * to reorder cleanup operations and prevent discarding of pending data during - * an hvcs_close(). Removed spinlock protection of hvcs_struct data members in - * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed. - */ - -#define HVCS_DRIVER_VERSION "1.3.3" - -MODULE_AUTHOR("Ryan S. Arnold "); -MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(HVCS_DRIVER_VERSION); - -/* - * Wait this long per iteration while trying to push buffered data to the - * hypervisor before allowing the tty to complete a close operation. - */ -#define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ - -/* - * Since the Linux TTY code does not currently (2-04-2004) support dynamic - * addition of tty derived devices and we shouldn't allocate thousands of - * tty_device pointers when the number of vty-server & vty partner connections - * will most often be much lower than this, we'll arbitrarily allocate - * HVCS_DEFAULT_SERVER_ADAPTERS tty_structs and cdev's by default when we - * register the tty_driver. This can be overridden using an insmod parameter. - */ -#define HVCS_DEFAULT_SERVER_ADAPTERS 64 - -/* - * The user can't insmod with more than HVCS_MAX_SERVER_ADAPTERS hvcs device - * nodes as a sanity check. Theoretically there can be over 1 Billion - * vty-server & vty partner connections. - */ -#define HVCS_MAX_SERVER_ADAPTERS 1024 - -/* - * We let Linux assign us a major number and we start the minors at zero. There - * is no intuitive mapping between minor number and the target vty-server - * adapter except that each new vty-server adapter is always assigned to the - * smallest minor number available. - */ -#define HVCS_MINOR_START 0 - -/* - * The hcall interface involves putting 8 chars into each of two registers. - * We load up those 2 registers (in arch/powerpc/platforms/pseries/hvconsole.c) - * by casting char[16] to long[2]. It would work without __ALIGNED__, but a - * little (tiny) bit slower because an unaligned load is slower than aligned - * load. - */ -#define __ALIGNED__ __attribute__((__aligned__(8))) - -/* - * How much data can firmware send with each hvc_put_chars()? Maybe this - * should be moved into an architecture specific area. - */ -#define HVCS_BUFF_LEN 16 - -/* - * This is the maximum amount of data we'll let the user send us (hvcs_write) at - * once in a chunk as a sanity check. - */ -#define HVCS_MAX_FROM_USER 4096 - -/* - * Be careful when adding flags to this line discipline. Don't add anything - * that will cause echoing or we'll go into recursive loop echoing chars back - * and forth with the console drivers. - */ -static struct ktermios hvcs_tty_termios = { - .c_iflag = IGNBRK | IGNPAR, - .c_oflag = OPOST, - .c_cflag = B38400 | CS8 | CREAD | HUPCL, - .c_cc = INIT_C_CC, - .c_ispeed = 38400, - .c_ospeed = 38400 -}; - -/* - * This value is used to take the place of a command line parameter when the - * module is inserted. It starts as -1 and stays as such if the user doesn't - * specify a module insmod parameter. If they DO specify one then it is set to - * the value of the integer passed in. - */ -static int hvcs_parm_num_devs = -1; -module_param(hvcs_parm_num_devs, int, 0); - -static const char hvcs_driver_name[] = "hvcs"; -static const char hvcs_device_node[] = "hvcs"; -static const char hvcs_driver_string[] - = "IBM hvcs (Hypervisor Virtual Console Server) Driver"; - -/* Status of partner info rescan triggered via sysfs. */ -static int hvcs_rescan_status; - -static struct tty_driver *hvcs_tty_driver; - -/* - * In order to be somewhat sane this driver always associates the hvcs_struct - * index element with the numerically equal tty->index. This means that a - * hotplugged vty-server adapter will always map to the lowest index valued - * device node. If vty-servers were hotplug removed from the system and then - * new ones added the new vty-server may have the largest slot number of all - * the vty-server adapters in the partition but it may have the lowest dev node - * index of all the adapters due to the hole left by the hotplug removed - * adapter. There are a set of functions provided to get the lowest index for - * a new device as well as return the index to the list. This list is allocated - * with a number of elements equal to the number of device nodes requested when - * the module was inserted. - */ -static int *hvcs_index_list; - -/* - * How large is the list? This is kept for traversal since the list is - * dynamically created. - */ -static int hvcs_index_count; - -/* - * Used by the khvcsd to pick up I/O operations when the kernel_thread is - * already awake but potentially shifted to TASK_INTERRUPTIBLE state. - */ -static int hvcs_kicked; - -/* - * Use by the kthread construct for task operations like waking the sleeping - * thread and stopping the kthread. - */ -static struct task_struct *hvcs_task; - -/* - * We allocate this for the use of all of the hvcs_structs when they fetch - * partner info. - */ -static unsigned long *hvcs_pi_buff; - -/* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */ -static DEFINE_SPINLOCK(hvcs_pi_lock); - -/* One vty-server per hvcs_struct */ -struct hvcs_struct { - spinlock_t lock; - - /* - * This index identifies this hvcs device as the complement to a - * specific tty index. - */ - unsigned int index; - - struct tty_struct *tty; - int open_count; - - /* - * Used to tell the driver kernel_thread what operations need to take - * place upon this hvcs_struct instance. - */ - int todo_mask; - - /* - * This buffer is required so that when hvcs_write_room() reports that - * it can send HVCS_BUFF_LEN characters that it will buffer the full - * HVCS_BUFF_LEN characters if need be. This is essential for opost - * writes since they do not do high level buffering and expect to be - * able to send what the driver commits to sending buffering - * [e.g. tab to space conversions in n_tty.c opost()]. - */ - char buffer[HVCS_BUFF_LEN]; - int chars_in_buffer; - - /* - * Any variable below the kref is valid before a tty is connected and - * stays valid after the tty is disconnected. These shouldn't be - * whacked until the koject refcount reaches zero though some entries - * may be changed via sysfs initiatives. - */ - struct kref kref; /* ref count & hvcs_struct lifetime */ - int connected; /* is the vty-server currently connected to a vty? */ - uint32_t p_unit_address; /* partner unit address */ - uint32_t p_partition_ID; /* partner partition ID */ - char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */ - struct list_head next; /* list management */ - struct vio_dev *vdev; -}; - -/* Required to back map a kref to its containing object */ -#define from_kref(k) container_of(k, struct hvcs_struct, kref) - -static LIST_HEAD(hvcs_structs); -static DEFINE_SPINLOCK(hvcs_structs_lock); - -static void hvcs_unthrottle(struct tty_struct *tty); -static void hvcs_throttle(struct tty_struct *tty); -static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance); - -static int hvcs_write(struct tty_struct *tty, - const unsigned char *buf, int count); -static int hvcs_write_room(struct tty_struct *tty); -static int hvcs_chars_in_buffer(struct tty_struct *tty); - -static int hvcs_has_pi(struct hvcs_struct *hvcsd); -static void hvcs_set_pi(struct hvcs_partner_info *pi, - struct hvcs_struct *hvcsd); -static int hvcs_get_pi(struct hvcs_struct *hvcsd); -static int hvcs_rescan_devices_list(void); - -static int hvcs_partner_connect(struct hvcs_struct *hvcsd); -static void hvcs_partner_free(struct hvcs_struct *hvcsd); - -static int hvcs_enable_device(struct hvcs_struct *hvcsd, - uint32_t unit_address, unsigned int irq, struct vio_dev *dev); - -static int hvcs_open(struct tty_struct *tty, struct file *filp); -static void hvcs_close(struct tty_struct *tty, struct file *filp); -static void hvcs_hangup(struct tty_struct * tty); - -static int __devinit hvcs_probe(struct vio_dev *dev, - const struct vio_device_id *id); -static int __devexit hvcs_remove(struct vio_dev *dev); -static int __init hvcs_module_init(void); -static void __exit hvcs_module_exit(void); - -#define HVCS_SCHED_READ 0x00000001 -#define HVCS_QUICK_READ 0x00000002 -#define HVCS_TRY_WRITE 0x00000004 -#define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) - -static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) -{ - return dev_get_drvdata(&viod->dev); -} -/* The sysfs interface for the driver and devices */ - -static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} -static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); - -static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} -static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); - -static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, - size_t count) -{ - /* - * Don't need this feature at the present time because firmware doesn't - * yet support multiple partners. - */ - printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); - return -EPERM; -} - -static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} - -static DEVICE_ATTR(current_vty, - S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); - -static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - - /* writing a '0' to this sysfs entry will result in the disconnect. */ - if (simple_strtol(buf, NULL, 0) != 0) - return -EINVAL; - - spin_lock_irqsave(&hvcsd->lock, flags); - - if (hvcsd->open_count > 0) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_INFO "HVCS: vterm state unchanged. " - "The hvcs device node is still in use.\n"); - return -EPERM; - } - - if (hvcsd->connected == 0) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_INFO "HVCS: vterm state unchanged. The" - " vty-server is not connected to a vty.\n"); - return -EPERM; - } - - hvcs_partner_free(hvcsd); - printk(KERN_INFO "HVCS: Closed vty-server@%X and" - " partner vty@%X:%d connection.\n", - hvcsd->vdev->unit_address, - hvcsd->p_unit_address, - (uint32_t)hvcsd->p_partition_ID); - - spin_unlock_irqrestore(&hvcsd->lock, flags); - return count; -} - -static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%d\n", hvcsd->connected); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} -static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, - hvcs_vterm_state_show, hvcs_vterm_state_store); - -static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct vio_dev *viod = to_vio_dev(dev); - struct hvcs_struct *hvcsd = from_vio_dev(viod); - unsigned long flags; - int retval; - - spin_lock_irqsave(&hvcsd->lock, flags); - retval = sprintf(buf, "%d\n", hvcsd->index); - spin_unlock_irqrestore(&hvcsd->lock, flags); - return retval; -} - -static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); - -static struct attribute *hvcs_attrs[] = { - &dev_attr_partner_vtys.attr, - &dev_attr_partner_clcs.attr, - &dev_attr_current_vty.attr, - &dev_attr_vterm_state.attr, - &dev_attr_index.attr, - NULL, -}; - -static struct attribute_group hvcs_attr_group = { - .attrs = hvcs_attrs, -}; - -static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) -{ - /* A 1 means it is updating, a 0 means it is done updating */ - return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); -} - -static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, - size_t count) -{ - if ((simple_strtol(buf, NULL, 0) != 1) - && (hvcs_rescan_status != 0)) - return -EINVAL; - - hvcs_rescan_status = 1; - printk(KERN_INFO "HVCS: rescanning partner info for all" - " vty-servers.\n"); - hvcs_rescan_devices_list(); - hvcs_rescan_status = 0; - return count; -} - -static DRIVER_ATTR(rescan, - S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); - -static void hvcs_kick(void) -{ - hvcs_kicked = 1; - wmb(); - wake_up_process(hvcs_task); -} - -static void hvcs_unthrottle(struct tty_struct *tty) -{ - struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - - spin_lock_irqsave(&hvcsd->lock, flags); - hvcsd->todo_mask |= HVCS_SCHED_READ; - spin_unlock_irqrestore(&hvcsd->lock, flags); - hvcs_kick(); -} - -static void hvcs_throttle(struct tty_struct *tty) -{ - struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - - spin_lock_irqsave(&hvcsd->lock, flags); - vio_disable_interrupts(hvcsd->vdev); - spin_unlock_irqrestore(&hvcsd->lock, flags); -} - -/* - * If the device is being removed we don't have to worry about this interrupt - * handler taking any further interrupts because they are disabled which means - * the hvcs_struct will always be valid in this handler. - */ -static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) -{ - struct hvcs_struct *hvcsd = dev_instance; - - spin_lock(&hvcsd->lock); - vio_disable_interrupts(hvcsd->vdev); - hvcsd->todo_mask |= HVCS_SCHED_READ; - spin_unlock(&hvcsd->lock); - hvcs_kick(); - - return IRQ_HANDLED; -} - -/* This function must be called with the hvcsd->lock held */ -static void hvcs_try_write(struct hvcs_struct *hvcsd) -{ - uint32_t unit_address = hvcsd->vdev->unit_address; - struct tty_struct *tty = hvcsd->tty; - int sent; - - if (hvcsd->todo_mask & HVCS_TRY_WRITE) { - /* won't send partial writes */ - sent = hvc_put_chars(unit_address, - &hvcsd->buffer[0], - hvcsd->chars_in_buffer ); - if (sent > 0) { - hvcsd->chars_in_buffer = 0; - /* wmb(); */ - hvcsd->todo_mask &= ~(HVCS_TRY_WRITE); - /* wmb(); */ - - /* - * We are still obligated to deliver the data to the - * hypervisor even if the tty has been closed because - * we commited to delivering it. But don't try to wake - * a non-existent tty. - */ - if (tty) { - tty_wakeup(tty); - } - } - } -} - -static int hvcs_io(struct hvcs_struct *hvcsd) -{ - uint32_t unit_address; - struct tty_struct *tty; - char buf[HVCS_BUFF_LEN] __ALIGNED__; - unsigned long flags; - int got = 0; - - spin_lock_irqsave(&hvcsd->lock, flags); - - unit_address = hvcsd->vdev->unit_address; - tty = hvcsd->tty; - - hvcs_try_write(hvcsd); - - if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) { - hvcsd->todo_mask &= ~(HVCS_READ_MASK); - goto bail; - } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK))) - goto bail; - - /* remove the read masks */ - hvcsd->todo_mask &= ~(HVCS_READ_MASK); - - if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) { - got = hvc_get_chars(unit_address, - &buf[0], - HVCS_BUFF_LEN); - tty_insert_flip_string(tty, buf, got); - } - - /* Give the TTY time to process the data we just sent. */ - if (got) - hvcsd->todo_mask |= HVCS_QUICK_READ; - - spin_unlock_irqrestore(&hvcsd->lock, flags); - /* This is synch because tty->low_latency == 1 */ - if(got) - tty_flip_buffer_push(tty); - - if (!got) { - /* Do this _after_ the flip_buffer_push */ - spin_lock_irqsave(&hvcsd->lock, flags); - vio_enable_interrupts(hvcsd->vdev); - spin_unlock_irqrestore(&hvcsd->lock, flags); - } - - return hvcsd->todo_mask; - - bail: - spin_unlock_irqrestore(&hvcsd->lock, flags); - return hvcsd->todo_mask; -} - -static int khvcsd(void *unused) -{ - struct hvcs_struct *hvcsd; - int hvcs_todo_mask; - - __set_current_state(TASK_RUNNING); - - do { - hvcs_todo_mask = 0; - hvcs_kicked = 0; - wmb(); - - spin_lock(&hvcs_structs_lock); - list_for_each_entry(hvcsd, &hvcs_structs, next) { - hvcs_todo_mask |= hvcs_io(hvcsd); - } - spin_unlock(&hvcs_structs_lock); - - /* - * If any of the hvcs adapters want to try a write or quick read - * don't schedule(), yield a smidgen then execute the hvcs_io - * thread again for those that want the write. - */ - if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) { - yield(); - continue; - } - - set_current_state(TASK_INTERRUPTIBLE); - if (!hvcs_kicked) - schedule(); - __set_current_state(TASK_RUNNING); - } while (!kthread_should_stop()); - - return 0; -} - -static struct vio_device_id hvcs_driver_table[] __devinitdata= { - {"serial-server", "hvterm2"}, - { "", "" } -}; -MODULE_DEVICE_TABLE(vio, hvcs_driver_table); - -static void hvcs_return_index(int index) -{ - /* Paranoia check */ - if (!hvcs_index_list) - return; - if (index < 0 || index >= hvcs_index_count) - return; - if (hvcs_index_list[index] == -1) - return; - else - hvcs_index_list[index] = -1; -} - -/* callback when the kref ref count reaches zero */ -static void destroy_hvcs_struct(struct kref *kref) -{ - struct hvcs_struct *hvcsd = from_kref(kref); - struct vio_dev *vdev; - unsigned long flags; - - spin_lock(&hvcs_structs_lock); - spin_lock_irqsave(&hvcsd->lock, flags); - - /* the list_del poisons the pointers */ - list_del(&(hvcsd->next)); - - if (hvcsd->connected == 1) { - hvcs_partner_free(hvcsd); - printk(KERN_INFO "HVCS: Closed vty-server@%X and" - " partner vty@%X:%d connection.\n", - hvcsd->vdev->unit_address, - hvcsd->p_unit_address, - (uint32_t)hvcsd->p_partition_ID); - } - printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n", - hvcsd->vdev->unit_address); - - vdev = hvcsd->vdev; - hvcsd->vdev = NULL; - - hvcsd->p_unit_address = 0; - hvcsd->p_partition_ID = 0; - hvcs_return_index(hvcsd->index); - memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1); - - spin_unlock_irqrestore(&hvcsd->lock, flags); - spin_unlock(&hvcs_structs_lock); - - sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); - - kfree(hvcsd); -} - -static int hvcs_get_index(void) -{ - int i; - /* Paranoia check */ - if (!hvcs_index_list) { - printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n"); - return -EFAULT; - } - /* Find the numerically lowest first free index. */ - for(i = 0; i < hvcs_index_count; i++) { - if (hvcs_index_list[i] == -1) { - hvcs_index_list[i] = 0; - return i; - } - } - return -1; -} - -static int __devinit hvcs_probe( - struct vio_dev *dev, - const struct vio_device_id *id) -{ - struct hvcs_struct *hvcsd; - int index; - int retval; - - if (!dev || !id) { - printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); - return -EPERM; - } - - /* early to avoid cleanup on failure */ - index = hvcs_get_index(); - if (index < 0) { - return -EFAULT; - } - - hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL); - if (!hvcsd) - return -ENODEV; - - - spin_lock_init(&hvcsd->lock); - /* Automatically incs the refcount the first time */ - kref_init(&hvcsd->kref); - - hvcsd->vdev = dev; - dev_set_drvdata(&dev->dev, hvcsd); - - hvcsd->index = index; - - /* hvcsd->index = ++hvcs_struct_count; */ - hvcsd->chars_in_buffer = 0; - hvcsd->todo_mask = 0; - hvcsd->connected = 0; - - /* - * This will populate the hvcs_struct's partner info fields for the - * first time. - */ - if (hvcs_get_pi(hvcsd)) { - printk(KERN_ERR "HVCS: Failed to fetch partner" - " info for vty-server@%X on device probe.\n", - hvcsd->vdev->unit_address); - } - - /* - * If a user app opens a tty that corresponds to this vty-server before - * the hvcs_struct has been added to the devices list then the user app - * will get -ENODEV. - */ - spin_lock(&hvcs_structs_lock); - list_add_tail(&(hvcsd->next), &hvcs_structs); - spin_unlock(&hvcs_structs_lock); - - retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group); - if (retval) { - printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n", - hvcsd->vdev->unit_address); - return retval; - } - - printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); - - /* - * DON'T enable interrupts here because there is no user to receive the - * data. - */ - return 0; -} - -static int __devexit hvcs_remove(struct vio_dev *dev) -{ - struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); - unsigned long flags; - struct tty_struct *tty; - - if (!hvcsd) - return -ENODEV; - - /* By this time the vty-server won't be getting any more interrupts */ - - spin_lock_irqsave(&hvcsd->lock, flags); - - tty = hvcsd->tty; - - spin_unlock_irqrestore(&hvcsd->lock, flags); - - /* - * Let the last holder of this object cause it to be removed, which - * would probably be tty_hangup below. - */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); - - /* - * The hangup is a scheduled function which will auto chain call - * hvcs_hangup. The tty should always be valid at this time unless a - * simultaneous tty close already cleaned up the hvcs_struct. - */ - if (tty) - tty_hangup(tty); - - printk(KERN_INFO "HVCS: vty-server@%X removed from the" - " vio bus.\n", dev->unit_address); - return 0; -}; - -static struct vio_driver hvcs_vio_driver = { - .id_table = hvcs_driver_table, - .probe = hvcs_probe, - .remove = __devexit_p(hvcs_remove), - .driver = { - .name = hvcs_driver_name, - .owner = THIS_MODULE, - } -}; - -/* Only called from hvcs_get_pi please */ -static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) -{ - int clclength; - - hvcsd->p_unit_address = pi->unit_address; - hvcsd->p_partition_ID = pi->partition_ID; - clclength = strlen(&pi->location_code[0]); - if (clclength > HVCS_CLC_LENGTH) - clclength = HVCS_CLC_LENGTH; - - /* copy the null-term char too */ - strncpy(&hvcsd->p_location_code[0], - &pi->location_code[0], clclength + 1); -} - -/* - * Traverse the list and add the partner info that is found to the hvcs_struct - * struct entry. NOTE: At this time I know that partner info will return a - * single entry but in the future there may be multiple partner info entries per - * vty-server and you'll want to zero out that list and reset it. If for some - * reason you have an old version of this driver but there IS more than one - * partner info then hvcsd->p_* will hold the last partner info data from the - * firmware query. A good way to update this code would be to replace the three - * partner info fields in hvcs_struct with a list of hvcs_partner_info - * instances. - * - * This function must be called with the hvcsd->lock held. - */ -static int hvcs_get_pi(struct hvcs_struct *hvcsd) -{ - struct hvcs_partner_info *pi; - uint32_t unit_address = hvcsd->vdev->unit_address; - struct list_head head; - int retval; - - spin_lock(&hvcs_pi_lock); - if (!hvcs_pi_buff) { - spin_unlock(&hvcs_pi_lock); - return -EFAULT; - } - retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff); - spin_unlock(&hvcs_pi_lock); - if (retval) { - printk(KERN_ERR "HVCS: Failed to fetch partner" - " info for vty-server@%x.\n", unit_address); - return retval; - } - - /* nixes the values if the partner vty went away */ - hvcsd->p_unit_address = 0; - hvcsd->p_partition_ID = 0; - - list_for_each_entry(pi, &head, node) - hvcs_set_pi(pi, hvcsd); - - hvcs_free_partner_info(&head); - return 0; -} - -/* - * This function is executed by the driver "rescan" sysfs entry. It shouldn't - * be executed elsewhere, in order to prevent deadlock issues. - */ -static int hvcs_rescan_devices_list(void) -{ - struct hvcs_struct *hvcsd; - unsigned long flags; - - spin_lock(&hvcs_structs_lock); - - list_for_each_entry(hvcsd, &hvcs_structs, next) { - spin_lock_irqsave(&hvcsd->lock, flags); - hvcs_get_pi(hvcsd); - spin_unlock_irqrestore(&hvcsd->lock, flags); - } - - spin_unlock(&hvcs_structs_lock); - - return 0; -} - -/* - * Farm this off into its own function because it could be more complex once - * multiple partners support is added. This function should be called with - * the hvcsd->lock held. - */ -static int hvcs_has_pi(struct hvcs_struct *hvcsd) -{ - if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID)) - return 0; - return 1; -} - -/* - * NOTE: It is possible that the super admin removed a partner vty and then - * added a different vty as the new partner. - * - * This function must be called with the hvcsd->lock held. - */ -static int hvcs_partner_connect(struct hvcs_struct *hvcsd) -{ - int retval; - unsigned int unit_address = hvcsd->vdev->unit_address; - - /* - * If there wasn't any pi when the device was added it doesn't meant - * there isn't any now. This driver isn't notified when a new partner - * vty is added to a vty-server so we discover changes on our own. - * Please see comments in hvcs_register_connection() for justification - * of this bizarre code. - */ - retval = hvcs_register_connection(unit_address, - hvcsd->p_partition_ID, - hvcsd->p_unit_address); - if (!retval) { - hvcsd->connected = 1; - return 0; - } else if (retval != -EINVAL) - return retval; - - /* - * As per the spec re-get the pi and try again if -EINVAL after the - * first connection attempt. - */ - if (hvcs_get_pi(hvcsd)) - return -ENOMEM; - - if (!hvcs_has_pi(hvcsd)) - return -ENODEV; - - retval = hvcs_register_connection(unit_address, - hvcsd->p_partition_ID, - hvcsd->p_unit_address); - if (retval != -EINVAL) { - hvcsd->connected = 1; - return retval; - } - - /* - * EBUSY is the most likely scenario though the vty could have been - * removed or there really could be an hcall error due to the parameter - * data but thanks to ambiguous firmware return codes we can't really - * tell. - */ - printk(KERN_INFO "HVCS: vty-server or partner" - " vty is busy. Try again later.\n"); - return -EBUSY; -} - -/* This function must be called with the hvcsd->lock held */ -static void hvcs_partner_free(struct hvcs_struct *hvcsd) -{ - int retval; - do { - retval = hvcs_free_connection(hvcsd->vdev->unit_address); - } while (retval == -EBUSY); - hvcsd->connected = 0; -} - -/* This helper function must be called WITHOUT the hvcsd->lock held */ -static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, - unsigned int irq, struct vio_dev *vdev) -{ - unsigned long flags; - int rc; - - /* - * It is possible that the vty-server was removed between the time that - * the conn was registered and now. - */ - if (!(rc = request_irq(irq, &hvcs_handle_interrupt, - IRQF_DISABLED, "ibmhvcs", hvcsd))) { - /* - * It is possible the vty-server was removed after the irq was - * requested but before we have time to enable interrupts. - */ - if (vio_enable_interrupts(vdev) == H_SUCCESS) - return 0; - else { - printk(KERN_ERR "HVCS: int enable failed for" - " vty-server@%X.\n", unit_address); - free_irq(irq, hvcsd); - } - } else - printk(KERN_ERR "HVCS: irq req failed for" - " vty-server@%X.\n", unit_address); - - spin_lock_irqsave(&hvcsd->lock, flags); - hvcs_partner_free(hvcsd); - spin_unlock_irqrestore(&hvcsd->lock, flags); - - return rc; - -} - -/* - * This always increments the kref ref count if the call is successful. - * Please remember to dec when you are done with the instance. - * - * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when - * calling this function or you will get deadlock. - */ -static struct hvcs_struct *hvcs_get_by_index(int index) -{ - struct hvcs_struct *hvcsd = NULL; - unsigned long flags; - - spin_lock(&hvcs_structs_lock); - /* We can immediately discard OOB requests */ - if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { - list_for_each_entry(hvcsd, &hvcs_structs, next) { - spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->index == index) { - kref_get(&hvcsd->kref); - spin_unlock_irqrestore(&hvcsd->lock, flags); - spin_unlock(&hvcs_structs_lock); - return hvcsd; - } - spin_unlock_irqrestore(&hvcsd->lock, flags); - } - hvcsd = NULL; - } - - spin_unlock(&hvcs_structs_lock); - return hvcsd; -} - -/* - * 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; - int rc, retval = 0; - unsigned long flags; - unsigned int irq; - struct vio_dev *vdev; - unsigned long unit_address; - - if (tty->driver_data) - goto fast_open; - - /* - * Is there a vty-server that shares the same index? - * This function increments the kref index. - */ - if (!(hvcsd = hvcs_get_by_index(tty->index))) { - printk(KERN_WARNING "HVCS: open failed, no device associated" - " with tty->index %d.\n", tty->index); - return -ENODEV; - } - - spin_lock_irqsave(&hvcsd->lock, flags); - - if (hvcsd->connected == 0) - if ((retval = hvcs_partner_connect(hvcsd))) - goto error_release; - - hvcsd->open_count = 1; - hvcsd->tty = tty; - tty->driver_data = hvcsd; - - memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); - - /* - * Save these in the spinlock for the enable operations that need them - * outside of the spinlock. - */ - irq = hvcsd->vdev->irq; - vdev = hvcsd->vdev; - unit_address = hvcsd->vdev->unit_address; - - hvcsd->todo_mask |= HVCS_SCHED_READ; - spin_unlock_irqrestore(&hvcsd->lock, flags); - - /* - * 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)))) { - kref_put(&hvcsd->kref, destroy_hvcs_struct); - printk(KERN_WARNING "HVCS: enable device failed.\n"); - return rc; - } - - goto open_success; - -fast_open: - hvcsd = tty->driver_data; - - spin_lock_irqsave(&hvcsd->lock, flags); - kref_get(&hvcsd->kref); - hvcsd->open_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; - -error_release: - spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); - - printk(KERN_WARNING "HVCS: partner connect failed.\n"); - return retval; -} - -static void hvcs_close(struct tty_struct *tty, struct file *filp) -{ - struct hvcs_struct *hvcsd; - unsigned long flags; - int irq = NO_IRQ; - - /* - * Is someone trying to close the file associated with this device after - * we have hung up? If so tty->driver_data wouldn't be valid. - */ - if (tty_hung_up_p(filp)) - return; - - /* - * No driver_data means that this close was probably issued after a - * failed hvcs_open by the tty layer's release_dev() api and we can just - * exit cleanly. - */ - if (!tty->driver_data) - return; - - hvcsd = tty->driver_data; - - spin_lock_irqsave(&hvcsd->lock, flags); - if (--hvcsd->open_count == 0) { - - vio_disable_interrupts(hvcsd->vdev); - - /* - * NULL this early so that the kernel_thread doesn't try to - * execute any operations on the TTY even though it is obligated - * to deliver any pending I/O to the hypervisor. - */ - hvcsd->tty = NULL; - - irq = hvcsd->vdev->irq; - spin_unlock_irqrestore(&hvcsd->lock, flags); - - tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); - - /* - * This line is important because it tells hvcs_open that this - * device needs to be re-configured the next time hvcs_open is - * called. - */ - tty->driver_data = NULL; - - free_irq(irq, hvcsd); - kref_put(&hvcsd->kref, destroy_hvcs_struct); - return; - } else if (hvcsd->open_count < 0) { - printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" - " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->open_count); - } - - spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); -} - -static void hvcs_hangup(struct tty_struct * tty) -{ - struct hvcs_struct *hvcsd = tty->driver_data; - unsigned long flags; - int temp_open_count; - int irq = NO_IRQ; - - spin_lock_irqsave(&hvcsd->lock, flags); - /* Preserve this so that we know how many kref refs to put */ - temp_open_count = hvcsd->open_count; - - /* - * Don't kref put inside the spinlock because the destruction - * callback may use the spinlock and it may get called before the - * spinlock has been released. - */ - vio_disable_interrupts(hvcsd->vdev); - - hvcsd->todo_mask = 0; - - /* I don't think the tty needs the hvcs_struct pointer after a hangup */ - hvcsd->tty->driver_data = NULL; - hvcsd->tty = NULL; - - hvcsd->open_count = 0; - - /* This will drop any buffered data on the floor which is OK in a hangup - * scenario. */ - memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); - hvcsd->chars_in_buffer = 0; - - irq = hvcsd->vdev->irq; - - spin_unlock_irqrestore(&hvcsd->lock, flags); - - free_irq(irq, hvcsd); - - /* - * We need to kref_put() for every open_count we have since the - * tty_hangup() function doesn't invoke a close per open connection on a - * non-console device. - */ - while(temp_open_count) { - --temp_open_count; - /* - * The final put will trigger destruction of the hvcs_struct. - * NOTE: If this hangup was signaled from user space then the - * final put will never happen. - */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); - } -} - -/* - * NOTE: This is almost always from_user since user level apps interact with the - * /dev nodes. I'm trusting that if hvcs_write gets called and interrupted by - * hvcs_remove (which removes the target device and executes tty_hangup()) that - * tty_hangup will allow hvcs_write time to complete execution before it - * terminates our device. - */ -static int hvcs_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct hvcs_struct *hvcsd = tty->driver_data; - unsigned int unit_address; - const unsigned char *charbuf; - unsigned long flags; - int total_sent = 0; - int tosend = 0; - int result = 0; - - /* - * If they don't check the return code off of their open they may - * attempt this even if there is no connected device. - */ - if (!hvcsd) - return -ENODEV; - - /* Reasonable size to prevent user level flooding */ - if (count > HVCS_MAX_FROM_USER) { - printk(KERN_WARNING "HVCS write: count being truncated to" - " HVCS_MAX_FROM_USER.\n"); - count = HVCS_MAX_FROM_USER; - } - - charbuf = buf; - - spin_lock_irqsave(&hvcsd->lock, flags); - - /* - * Somehow an open succedded but the device was removed or the - * connection terminated between the vty-server and partner vty during - * the middle of a write operation? This is a crummy place to do this - * but we want to keep it all in the spinlock. - */ - if (hvcsd->open_count <= 0) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - return -ENODEV; - } - - unit_address = hvcsd->vdev->unit_address; - - while (count > 0) { - tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer)); - /* - * No more space, this probably means that the last call to - * hvcs_write() didn't succeed and the buffer was filled up. - */ - if (!tosend) - break; - - memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer], - &charbuf[total_sent], - tosend); - - hvcsd->chars_in_buffer += tosend; - - result = 0; - - /* - * If this is true then we don't want to try writing to the - * hypervisor because that is the kernel_threads job now. We'll - * just add to the buffer. - */ - if (!(hvcsd->todo_mask & HVCS_TRY_WRITE)) - /* won't send partial writes */ - result = hvc_put_chars(unit_address, - &hvcsd->buffer[0], - hvcsd->chars_in_buffer); - - /* - * Since we know we have enough room in hvcsd->buffer for - * tosend we record that it was sent regardless of whether the - * hypervisor actually took it because we have it buffered. - */ - total_sent+=tosend; - count-=tosend; - if (result == 0) { - hvcsd->todo_mask |= HVCS_TRY_WRITE; - hvcs_kick(); - break; - } - - hvcsd->chars_in_buffer = 0; - /* - * Test after the chars_in_buffer reset otherwise this could - * deadlock our writes if hvc_put_chars fails. - */ - if (result < 0) - break; - } - - spin_unlock_irqrestore(&hvcsd->lock, flags); - - if (result == -1) - return -EIO; - else - return total_sent; -} - -/* - * This is really asking how much can we guarentee that we can send or that we - * absolutely WILL BUFFER if we can't send it. This driver MUST honor the - * return value, hence the reason for hvcs_struct buffering. - */ -static int hvcs_write_room(struct tty_struct *tty) -{ - struct hvcs_struct *hvcsd = tty->driver_data; - - if (!hvcsd || hvcsd->open_count <= 0) - return 0; - - return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; -} - -static int hvcs_chars_in_buffer(struct tty_struct *tty) -{ - struct hvcs_struct *hvcsd = tty->driver_data; - - return hvcsd->chars_in_buffer; -} - -static const struct tty_operations hvcs_ops = { - .open = hvcs_open, - .close = hvcs_close, - .hangup = hvcs_hangup, - .write = hvcs_write, - .write_room = hvcs_write_room, - .chars_in_buffer = hvcs_chars_in_buffer, - .unthrottle = hvcs_unthrottle, - .throttle = hvcs_throttle, -}; - -static int hvcs_alloc_index_list(int n) -{ - int i; - - hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); - if (!hvcs_index_list) - return -ENOMEM; - hvcs_index_count = n; - for (i = 0; i < hvcs_index_count; i++) - hvcs_index_list[i] = -1; - return 0; -} - -static void hvcs_free_index_list(void) -{ - /* Paranoia check to be thorough. */ - kfree(hvcs_index_list); - hvcs_index_list = NULL; - hvcs_index_count = 0; -} - -static int __init hvcs_module_init(void) -{ - int rc; - int num_ttys_to_alloc; - - printk(KERN_INFO "Initializing %s\n", hvcs_driver_string); - - /* Has the user specified an overload with an insmod param? */ - if (hvcs_parm_num_devs <= 0 || - (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) { - num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS; - } else - num_ttys_to_alloc = hvcs_parm_num_devs; - - hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc); - if (!hvcs_tty_driver) - return -ENOMEM; - - if (hvcs_alloc_index_list(num_ttys_to_alloc)) { - rc = -ENOMEM; - goto index_fail; - } - - hvcs_tty_driver->owner = THIS_MODULE; - - hvcs_tty_driver->driver_name = hvcs_driver_name; - hvcs_tty_driver->name = hvcs_device_node; - - /* - * We'll let the system assign us a major number, indicated by leaving - * it blank. - */ - - hvcs_tty_driver->minor_start = HVCS_MINOR_START; - hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; - - /* - * We role our own so that we DONT ECHO. We can't echo because the - * device we are connecting to already echoes by default and this would - * throw us into a horrible recursive echo-echo-echo loop. - */ - hvcs_tty_driver->init_termios = hvcs_tty_termios; - hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW; - - tty_set_operations(hvcs_tty_driver, &hvcs_ops); - - /* - * The following call will result in sysfs entries that denote the - * dynamically assigned major and minor numbers for our devices. - */ - if (tty_register_driver(hvcs_tty_driver)) { - printk(KERN_ERR "HVCS: registration as a tty driver failed.\n"); - rc = -EIO; - goto register_fail; - } - - hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!hvcs_pi_buff) { - rc = -ENOMEM; - goto buff_alloc_fail; - } - - hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); - if (IS_ERR(hvcs_task)) { - printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); - rc = -EIO; - goto kthread_fail; - } - - rc = vio_register_driver(&hvcs_vio_driver); - if (rc) { - printk(KERN_ERR "HVCS: can't register vio driver\n"); - goto vio_fail; - } - - /* - * This needs to be done AFTER the vio_register_driver() call or else - * the kobjects won't be initialized properly. - */ - rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); - if (rc) { - printk(KERN_ERR "HVCS: sysfs attr create failed\n"); - goto attr_fail; - } - - printk(KERN_INFO "HVCS: driver module inserted.\n"); - - return 0; - -attr_fail: - vio_unregister_driver(&hvcs_vio_driver); -vio_fail: - kthread_stop(hvcs_task); -kthread_fail: - kfree(hvcs_pi_buff); -buff_alloc_fail: - tty_unregister_driver(hvcs_tty_driver); -register_fail: - hvcs_free_index_list(); -index_fail: - put_tty_driver(hvcs_tty_driver); - hvcs_tty_driver = NULL; - return rc; -} - -static void __exit hvcs_module_exit(void) -{ - /* - * This driver receives hvcs_remove callbacks for each device upon - * module removal. - */ - - /* - * This synchronous operation will wake the khvcsd kthread if it is - * asleep and will return when khvcsd has terminated. - */ - kthread_stop(hvcs_task); - - spin_lock(&hvcs_pi_lock); - kfree(hvcs_pi_buff); - hvcs_pi_buff = NULL; - spin_unlock(&hvcs_pi_lock); - - driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); - - vio_unregister_driver(&hvcs_vio_driver); - - tty_unregister_driver(hvcs_tty_driver); - - hvcs_free_index_list(); - - put_tty_driver(hvcs_tty_driver); - - printk(KERN_INFO "HVCS: driver module removed.\n"); -} - -module_init(hvcs_module_init); -module_exit(hvcs_module_exit); diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c deleted file mode 100644 index 67a75a502c01..000000000000 --- a/drivers/char/hvsi.c +++ /dev/null @@ -1,1314 +0,0 @@ -/* - * Copyright (C) 2004 Hollis Blanchard , IBM - * - * 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 - */ - -/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS - * and the service processor on IBM pSeries servers. On these servers, there - * are no serial ports under the OS's control, and sometimes there is no other - * console available either. However, the service processor has two standard - * serial ports, so this over-complicated protocol allows the OS to control - * those ports by proxy. - * - * Besides data, the procotol supports the reading/writing of the serial - * port's DTR line, and the reading of the CD line. This is to allow the OS to - * control a modem attached to the service processor's serial port. Note that - * the OS cannot change the speed of the port through this protocol. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HVSI_MAJOR 229 -#define HVSI_MINOR 128 -#define MAX_NR_HVSI_CONSOLES 4 - -#define HVSI_TIMEOUT (5*HZ) -#define HVSI_VERSION 1 -#define HVSI_MAX_PACKET 256 -#define HVSI_MAX_READ 16 -#define HVSI_MAX_OUTGOING_DATA 12 -#define N_OUTBUF 12 - -/* - * we pass data via two 8-byte registers, so we would like our char arrays - * properly aligned for those loads. - */ -#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) - -struct hvsi_struct { - struct delayed_work writer; - struct work_struct handshaker; - wait_queue_head_t emptyq; /* woken when outbuf is emptied */ - wait_queue_head_t stateq; /* woken when HVSI state changes */ - spinlock_t lock; - int index; - struct tty_struct *tty; - int count; - uint8_t throttle_buf[128]; - uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ - /* inbuf is for packet reassembly. leave a little room for leftovers. */ - uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ]; - uint8_t *inbuf_end; - int n_throttle; - int n_outbuf; - uint32_t vtermno; - uint32_t virq; - atomic_t seqno; /* HVSI packet sequence number */ - uint16_t mctrl; - uint8_t state; /* HVSI protocol state */ - uint8_t flags; -#ifdef CONFIG_MAGIC_SYSRQ - uint8_t sysrq; -#endif /* CONFIG_MAGIC_SYSRQ */ -}; -static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES]; - -static struct tty_driver *hvsi_driver; -static int hvsi_count; -static int (*hvsi_wait)(struct hvsi_struct *hp, int state); - -enum HVSI_PROTOCOL_STATE { - HVSI_CLOSED, - HVSI_WAIT_FOR_VER_RESPONSE, - HVSI_WAIT_FOR_VER_QUERY, - HVSI_OPEN, - HVSI_WAIT_FOR_MCTRL_RESPONSE, - HVSI_FSP_DIED, -}; -#define HVSI_CONSOLE 0x1 - -#define VS_DATA_PACKET_HEADER 0xff -#define VS_CONTROL_PACKET_HEADER 0xfe -#define VS_QUERY_PACKET_HEADER 0xfd -#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc - -/* control verbs */ -#define VSV_SET_MODEM_CTL 1 /* to service processor only */ -#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */ -#define VSV_CLOSE_PROTOCOL 3 - -/* query verbs */ -#define VSV_SEND_VERSION_NUMBER 1 -#define VSV_SEND_MODEM_CTL_STATUS 2 - -/* yes, these masks are not consecutive. */ -#define HVSI_TSDTR 0x01 -#define HVSI_TSCD 0x20 - -struct hvsi_header { - uint8_t type; - uint8_t len; - uint16_t seqno; -} __attribute__((packed)); - -struct hvsi_data { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint8_t data[HVSI_MAX_OUTGOING_DATA]; -} __attribute__((packed)); - -struct hvsi_control { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint16_t verb; - /* optional depending on verb: */ - uint32_t word; - uint32_t mask; -} __attribute__((packed)); - -struct hvsi_query { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint16_t verb; -} __attribute__((packed)); - -struct hvsi_query_response { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint16_t verb; - uint16_t query_seqno; - union { - uint8_t version; - uint32_t mctrl_word; - } u; -} __attribute__((packed)); - - - -static inline int is_console(struct hvsi_struct *hp) -{ - return hp->flags & HVSI_CONSOLE; -} - -static inline int is_open(struct hvsi_struct *hp) -{ - /* if we're waiting for an mctrl then we're already open */ - return (hp->state == HVSI_OPEN) - || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE); -} - -static inline void print_state(struct hvsi_struct *hp) -{ -#ifdef DEBUG - static const char *state_names[] = { - "HVSI_CLOSED", - "HVSI_WAIT_FOR_VER_RESPONSE", - "HVSI_WAIT_FOR_VER_QUERY", - "HVSI_OPEN", - "HVSI_WAIT_FOR_MCTRL_RESPONSE", - "HVSI_FSP_DIED", - }; - const char *name = (hp->state < ARRAY_SIZE(state_names)) - ? state_names[hp->state] : "UNKNOWN"; - - pr_debug("hvsi%i: state = %s\n", hp->index, name); -#endif /* DEBUG */ -} - -static inline void __set_state(struct hvsi_struct *hp, int state) -{ - hp->state = state; - print_state(hp); - wake_up_all(&hp->stateq); -} - -static inline void set_state(struct hvsi_struct *hp, int state) -{ - unsigned long flags; - - spin_lock_irqsave(&hp->lock, flags); - __set_state(hp, state); - spin_unlock_irqrestore(&hp->lock, flags); -} - -static inline int len_packet(const uint8_t *packet) -{ - return (int)((struct hvsi_header *)packet)->len; -} - -static inline int is_header(const uint8_t *packet) -{ - struct hvsi_header *header = (struct hvsi_header *)packet; - return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER; -} - -static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet) -{ - if (hp->inbuf_end < packet + sizeof(struct hvsi_header)) - return 0; /* don't even have the packet header */ - - if (hp->inbuf_end < (packet + len_packet(packet))) - return 0; /* don't have the rest of the packet */ - - return 1; -} - -/* shift remaining bytes in packetbuf down */ -static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to) -{ - int remaining = (int)(hp->inbuf_end - read_to); - - pr_debug("%s: %i chars remain\n", __func__, remaining); - - if (read_to != hp->inbuf) - memmove(hp->inbuf, read_to, remaining); - - hp->inbuf_end = hp->inbuf + remaining; -} - -#ifdef DEBUG -#define dbg_dump_packet(packet) dump_packet(packet) -#define dbg_dump_hex(data, len) dump_hex(data, len) -#else -#define dbg_dump_packet(packet) do { } while (0) -#define dbg_dump_hex(data, len) do { } while (0) -#endif - -static void dump_hex(const uint8_t *data, int len) -{ - int i; - - printk(" "); - for (i=0; i < len; i++) - printk("%.2x", data[i]); - - printk("\n "); - for (i=0; i < len; i++) { - if (isprint(data[i])) - printk("%c", data[i]); - else - printk("."); - } - printk("\n"); -} - -static void dump_packet(uint8_t *packet) -{ - struct hvsi_header *header = (struct hvsi_header *)packet; - - printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len, - header->seqno); - - dump_hex(packet, header->len); -} - -static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) -{ - unsigned long got; - - got = hvc_get_chars(hp->vtermno, buf, count); - - return got; -} - -static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, - struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) -{ - struct hvsi_control *header = (struct hvsi_control *)packet; - - switch (header->verb) { - case VSV_MODEM_CTL_UPDATE: - if ((header->word & HVSI_TSCD) == 0) { - /* CD went away; no more connection */ - pr_debug("hvsi%i: CD dropped\n", hp->index); - hp->mctrl &= TIOCM_CD; - /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ - if (hp->tty && !(hp->tty->flags & CLOCAL)) - *to_hangup = hp->tty; - } - break; - case VSV_CLOSE_PROTOCOL: - pr_debug("hvsi%i: service processor came back\n", hp->index); - if (hp->state != HVSI_CLOSED) { - *to_handshake = hp; - } - break; - default: - printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ", - hp->index); - dump_packet(packet); - break; - } -} - -static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet) -{ - struct hvsi_query_response *resp = (struct hvsi_query_response *)packet; - - switch (hp->state) { - case HVSI_WAIT_FOR_VER_RESPONSE: - __set_state(hp, HVSI_WAIT_FOR_VER_QUERY); - break; - case HVSI_WAIT_FOR_MCTRL_RESPONSE: - hp->mctrl = 0; - if (resp->u.mctrl_word & HVSI_TSDTR) - hp->mctrl |= TIOCM_DTR; - if (resp->u.mctrl_word & HVSI_TSCD) - hp->mctrl |= TIOCM_CD; - __set_state(hp, HVSI_OPEN); - break; - default: - printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index); - dump_packet(packet); - break; - } -} - -/* respond to service processor's version query */ -static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) -{ - struct hvsi_query_response packet __ALIGNED__; - int wrote; - - packet.type = VS_QUERY_RESPONSE_PACKET_HEADER; - packet.len = sizeof(struct hvsi_query_response); - packet.seqno = atomic_inc_return(&hp->seqno); - packet.verb = VSV_SEND_VERSION_NUMBER; - packet.u.version = HVSI_VERSION; - packet.query_seqno = query_seqno+1; - - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); - - wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (wrote != packet.len) { - printk(KERN_ERR "hvsi%i: couldn't send query response!\n", - hp->index); - return -EIO; - } - - return 0; -} - -static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) -{ - struct hvsi_query *query = (struct hvsi_query *)packet; - - switch (hp->state) { - case HVSI_WAIT_FOR_VER_QUERY: - hvsi_version_respond(hp, query->seqno); - __set_state(hp, HVSI_OPEN); - break; - default: - printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index); - dump_packet(packet); - break; - } -} - -static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) -{ - int i; - - for (i=0; i < len; i++) { - char c = buf[i]; -#ifdef CONFIG_MAGIC_SYSRQ - if (c == '\0') { - hp->sysrq = 1; - continue; - } else if (hp->sysrq) { - handle_sysrq(c); - hp->sysrq = 0; - continue; - } -#endif /* CONFIG_MAGIC_SYSRQ */ - tty_insert_flip_char(hp->tty, c, 0); - } -} - -/* - * We could get 252 bytes of data at once here. But the tty layer only - * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow - * it. Accordingly we won't send more than 128 bytes at a time to the flip - * buffer, which will give the tty buffer a chance to throttle us. Should the - * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be - * revisited. - */ -#define TTY_THRESHOLD_THROTTLE 128 -static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, - const uint8_t *packet) -{ - const struct hvsi_header *header = (const struct hvsi_header *)packet; - const uint8_t *data = packet + sizeof(struct hvsi_header); - int datalen = header->len - sizeof(struct hvsi_header); - int overflow = datalen - TTY_THRESHOLD_THROTTLE; - - pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); - - if (datalen == 0) - return NULL; - - if (overflow > 0) { - pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); - datalen = TTY_THRESHOLD_THROTTLE; - } - - hvsi_insert_chars(hp, data, datalen); - - if (overflow > 0) { - /* - * we still have more data to deliver, so we need to save off the - * overflow and send it later - */ - pr_debug("%s: deferring overflow\n", __func__); - memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow); - hp->n_throttle = overflow; - } - - return hp->tty; -} - -/* - * Returns true/false indicating data successfully read from hypervisor. - * Used both to get packets for tty connections and to advance the state - * machine during console handshaking (in which case tty = NULL and we ignore - * incoming data). - */ -static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, - struct tty_struct **hangup, struct hvsi_struct **handshake) -{ - uint8_t *packet = hp->inbuf; - int chunklen; - - *flip = NULL; - *hangup = NULL; - *handshake = NULL; - - chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); - if (chunklen == 0) { - pr_debug("%s: 0-length read\n", __func__); - return 0; - } - - pr_debug("%s: got %i bytes\n", __func__, chunklen); - dbg_dump_hex(hp->inbuf_end, chunklen); - - hp->inbuf_end += chunklen; - - /* handle all completed packets */ - while ((packet < hp->inbuf_end) && got_packet(hp, packet)) { - struct hvsi_header *header = (struct hvsi_header *)packet; - - if (!is_header(packet)) { - printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index); - /* skip bytes until we find a header or run out of data */ - while ((packet < hp->inbuf_end) && (!is_header(packet))) - packet++; - continue; - } - - pr_debug("%s: handling %i-byte packet\n", __func__, - len_packet(packet)); - dbg_dump_packet(packet); - - switch (header->type) { - case VS_DATA_PACKET_HEADER: - if (!is_open(hp)) - break; - if (hp->tty == NULL) - break; /* no tty buffer to put data in */ - *flip = hvsi_recv_data(hp, packet); - break; - case VS_CONTROL_PACKET_HEADER: - hvsi_recv_control(hp, packet, hangup, handshake); - break; - case VS_QUERY_RESPONSE_PACKET_HEADER: - hvsi_recv_response(hp, packet); - break; - case VS_QUERY_PACKET_HEADER: - hvsi_recv_query(hp, packet); - break; - default: - printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n", - hp->index, header->type); - dump_packet(packet); - break; - } - - packet += len_packet(packet); - - if (*hangup || *handshake) { - pr_debug("%s: hangup or handshake\n", __func__); - /* - * we need to send the hangup now before receiving any more data. - * If we get "data, hangup, data", we can't deliver the second - * data before the hangup. - */ - break; - } - } - - compact_inbuf(hp, packet); - - return 1; -} - -static void hvsi_send_overflow(struct hvsi_struct *hp) -{ - pr_debug("%s: delivering %i bytes overflow\n", __func__, - hp->n_throttle); - - hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); - hp->n_throttle = 0; -} - -/* - * must get all pending data because we only get an irq on empty->non-empty - * transition - */ -static irqreturn_t hvsi_interrupt(int irq, void *arg) -{ - struct hvsi_struct *hp = (struct hvsi_struct *)arg; - struct tty_struct *flip; - struct tty_struct *hangup; - struct hvsi_struct *handshake; - unsigned long flags; - int again = 1; - - pr_debug("%s\n", __func__); - - while (again) { - spin_lock_irqsave(&hp->lock, flags); - again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); - spin_unlock_irqrestore(&hp->lock, flags); - - /* - * we have to call tty_flip_buffer_push() and tty_hangup() outside our - * spinlock. But we also have to keep going until we've read all the - * available data. - */ - - if (flip) { - /* there was data put in the tty flip buffer */ - tty_flip_buffer_push(flip); - flip = NULL; - } - - if (hangup) { - tty_hangup(hangup); - } - - if (handshake) { - pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); - schedule_work(&handshake->handshaker); - } - } - - spin_lock_irqsave(&hp->lock, flags); - if (hp->tty && hp->n_throttle - && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { - /* we weren't hung up and we weren't throttled, so we can deliver the - * rest now */ - flip = hp->tty; - hvsi_send_overflow(hp); - } - spin_unlock_irqrestore(&hp->lock, flags); - - if (flip) { - tty_flip_buffer_push(flip); - } - - return IRQ_HANDLED; -} - -/* for boot console, before the irq handler is running */ -static int __init poll_for_state(struct hvsi_struct *hp, int state) -{ - unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; - - for (;;) { - hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */ - - if (hp->state == state) - return 0; - - mdelay(5); - if (time_after(jiffies, end_jiffies)) - return -EIO; - } -} - -/* wait for irq handler to change our state */ -static int wait_for_state(struct hvsi_struct *hp, int state) -{ - int ret = 0; - - if (!wait_event_timeout(hp->stateq, (hp->state == state), HVSI_TIMEOUT)) - ret = -EIO; - - return ret; -} - -static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) -{ - struct hvsi_query packet __ALIGNED__; - int wrote; - - packet.type = VS_QUERY_PACKET_HEADER; - packet.len = sizeof(struct hvsi_query); - packet.seqno = atomic_inc_return(&hp->seqno); - packet.verb = verb; - - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); - - wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (wrote != packet.len) { - printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index, - wrote); - return -EIO; - } - - return 0; -} - -static int hvsi_get_mctrl(struct hvsi_struct *hp) -{ - int ret; - - set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE); - hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS); - - ret = hvsi_wait(hp, HVSI_OPEN); - if (ret < 0) { - printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index); - set_state(hp, HVSI_OPEN); - return ret; - } - - pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl); - - return 0; -} - -/* note that we can only set DTR */ -static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) -{ - struct hvsi_control packet __ALIGNED__; - int wrote; - - packet.type = VS_CONTROL_PACKET_HEADER, - packet.seqno = atomic_inc_return(&hp->seqno); - packet.len = sizeof(struct hvsi_control); - packet.verb = VSV_SET_MODEM_CTL; - packet.mask = HVSI_TSDTR; - - if (mctrl & TIOCM_DTR) - packet.word = HVSI_TSDTR; - - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); - - wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (wrote != packet.len) { - printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index); - return -EIO; - } - - return 0; -} - -static void hvsi_drain_input(struct hvsi_struct *hp) -{ - uint8_t buf[HVSI_MAX_READ] __ALIGNED__; - unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; - - while (time_before(end_jiffies, jiffies)) - if (0 == hvsi_read(hp, buf, HVSI_MAX_READ)) - break; -} - -static int hvsi_handshake(struct hvsi_struct *hp) -{ - int ret; - - /* - * We could have a CLOSE or other data waiting for us before we even try - * to open; try to throw it all away so we don't get confused. (CLOSE - * is the first message sent up the pipe when the FSP comes online. We - * need to distinguish between "it came up a while ago and we're the first - * user" and "it was just reset before it saw our handshake packet".) - */ - hvsi_drain_input(hp); - - set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE); - ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER); - if (ret < 0) { - printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index); - return ret; - } - - ret = hvsi_wait(hp, HVSI_OPEN); - if (ret < 0) - return ret; - - return 0; -} - -static void hvsi_handshaker(struct work_struct *work) -{ - struct hvsi_struct *hp = - container_of(work, struct hvsi_struct, handshaker); - - if (hvsi_handshake(hp) >= 0) - return; - - printk(KERN_ERR "hvsi%i: re-handshaking failed\n", hp->index); - if (is_console(hp)) { - /* - * ttys will re-attempt the handshake via hvsi_open, but - * the console will not. - */ - printk(KERN_ERR "hvsi%i: lost console!\n", hp->index); - } -} - -static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) -{ - struct hvsi_data packet __ALIGNED__; - int ret; - - BUG_ON(count > HVSI_MAX_OUTGOING_DATA); - - packet.type = VS_DATA_PACKET_HEADER; - packet.seqno = atomic_inc_return(&hp->seqno); - packet.len = count + sizeof(struct hvsi_header); - memcpy(&packet.data, buf, count); - - ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (ret == packet.len) { - /* return the number of chars written, not the packet length */ - return count; - } - return ret; /* return any errors */ -} - -static void hvsi_close_protocol(struct hvsi_struct *hp) -{ - struct hvsi_control packet __ALIGNED__; - - packet.type = VS_CONTROL_PACKET_HEADER; - packet.seqno = atomic_inc_return(&hp->seqno); - packet.len = 6; - packet.verb = VSV_CLOSE_PROTOCOL; - - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); - - hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); -} - -static int hvsi_open(struct tty_struct *tty, struct file *filp) -{ - struct hvsi_struct *hp; - unsigned long flags; - int line = tty->index; - int ret; - - pr_debug("%s\n", __func__); - - if (line < 0 || line >= hvsi_count) - return -ENODEV; - hp = &hvsi_ports[line]; - - tty->driver_data = hp; - - mb(); - if (hp->state == HVSI_FSP_DIED) - return -EIO; - - spin_lock_irqsave(&hp->lock, flags); - hp->tty = tty; - hp->count++; - atomic_set(&hp->seqno, 0); - h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); - spin_unlock_irqrestore(&hp->lock, flags); - - if (is_console(hp)) - return 0; /* this has already been handshaked as the console */ - - ret = hvsi_handshake(hp); - if (ret < 0) { - printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name); - return ret; - } - - ret = hvsi_get_mctrl(hp); - if (ret < 0) { - printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name); - return ret; - } - - ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); - if (ret < 0) { - printk(KERN_ERR "%s: couldn't set DTR\n", tty->name); - return ret; - } - - return 0; -} - -/* wait for hvsi_write_worker to empty hp->outbuf */ -static void hvsi_flush_output(struct hvsi_struct *hp) -{ - wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT); - - /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ - cancel_delayed_work_sync(&hp->writer); - flush_work_sync(&hp->handshaker); - - /* - * it's also possible that our timeout expired and hvsi_write_worker - * didn't manage to push outbuf. poof. - */ - hp->n_outbuf = 0; -} - -static void hvsi_close(struct tty_struct *tty, struct file *filp) -{ - struct hvsi_struct *hp = tty->driver_data; - unsigned long flags; - - pr_debug("%s\n", __func__); - - if (tty_hung_up_p(filp)) - return; - - spin_lock_irqsave(&hp->lock, flags); - - if (--hp->count == 0) { - hp->tty = NULL; - hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ - - /* only close down connection if it is not the console */ - if (!is_console(hp)) { - h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */ - __set_state(hp, HVSI_CLOSED); - /* - * any data delivered to the tty layer after this will be - * discarded (except for XON/XOFF) - */ - tty->closing = 1; - - spin_unlock_irqrestore(&hp->lock, flags); - - /* let any existing irq handlers finish. no more will start. */ - synchronize_irq(hp->virq); - - /* hvsi_write_worker will re-schedule until outbuf is empty. */ - hvsi_flush_output(hp); - - /* tell FSP to stop sending data */ - hvsi_close_protocol(hp); - - /* - * drain anything FSP is still in the middle of sending, and let - * hvsi_handshake drain the rest on the next open. - */ - hvsi_drain_input(hp); - - spin_lock_irqsave(&hp->lock, flags); - } - } else if (hp->count < 0) - printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", - hp - hvsi_ports, hp->count); - - spin_unlock_irqrestore(&hp->lock, flags); -} - -static void hvsi_hangup(struct tty_struct *tty) -{ - struct hvsi_struct *hp = tty->driver_data; - unsigned long flags; - - pr_debug("%s\n", __func__); - - spin_lock_irqsave(&hp->lock, flags); - - hp->count = 0; - hp->n_outbuf = 0; - hp->tty = NULL; - - spin_unlock_irqrestore(&hp->lock, flags); -} - -/* called with hp->lock held */ -static void hvsi_push(struct hvsi_struct *hp) -{ - int n; - - if (hp->n_outbuf <= 0) - return; - - n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf); - if (n > 0) { - /* success */ - pr_debug("%s: wrote %i chars\n", __func__, n); - hp->n_outbuf = 0; - } else if (n == -EIO) { - __set_state(hp, HVSI_FSP_DIED); - printk(KERN_ERR "hvsi%i: service processor died\n", hp->index); - } -} - -/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ -static void hvsi_write_worker(struct work_struct *work) -{ - struct hvsi_struct *hp = - container_of(work, struct hvsi_struct, writer.work); - unsigned long flags; -#ifdef DEBUG - static long start_j = 0; - - if (start_j == 0) - start_j = jiffies; -#endif /* DEBUG */ - - spin_lock_irqsave(&hp->lock, flags); - - pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf); - - if (!is_open(hp)) { - /* - * We could have a non-open connection if the service processor died - * while we were busily scheduling ourselves. In that case, it could - * be minutes before the service processor comes back, so only try - * again once a second. - */ - schedule_delayed_work(&hp->writer, HZ); - goto out; - } - - hvsi_push(hp); - if (hp->n_outbuf > 0) - schedule_delayed_work(&hp->writer, 10); - else { -#ifdef DEBUG - pr_debug("%s: outbuf emptied after %li jiffies\n", __func__, - jiffies - start_j); - start_j = 0; -#endif /* DEBUG */ - wake_up_all(&hp->emptyq); - tty_wakeup(hp->tty); - } - -out: - spin_unlock_irqrestore(&hp->lock, flags); -} - -static int hvsi_write_room(struct tty_struct *tty) -{ - struct hvsi_struct *hp = tty->driver_data; - - return N_OUTBUF - hp->n_outbuf; -} - -static int hvsi_chars_in_buffer(struct tty_struct *tty) -{ - struct hvsi_struct *hp = tty->driver_data; - - return hp->n_outbuf; -} - -static int hvsi_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct hvsi_struct *hp = tty->driver_data; - const char *source = buf; - unsigned long flags; - int total = 0; - int origcount = count; - - spin_lock_irqsave(&hp->lock, flags); - - pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf); - - if (!is_open(hp)) { - /* we're either closing or not yet open; don't accept data */ - pr_debug("%s: not open\n", __func__); - goto out; - } - - /* - * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf - * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls - * will see there is no room in outbuf and return. - */ - while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { - int chunksize = min(count, hvsi_write_room(hp->tty)); - - BUG_ON(hp->n_outbuf < 0); - memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); - hp->n_outbuf += chunksize; - - total += chunksize; - source += chunksize; - count -= chunksize; - hvsi_push(hp); - } - - if (hp->n_outbuf > 0) { - /* - * we weren't able to write it all to the hypervisor. - * schedule another push attempt. - */ - schedule_delayed_work(&hp->writer, 10); - } - -out: - spin_unlock_irqrestore(&hp->lock, flags); - - if (total != origcount) - pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount, - total); - - return total; -} - -/* - * I have never seen throttle or unthrottle called, so this little throttle - * buffering scheme may or may not work. - */ -static void hvsi_throttle(struct tty_struct *tty) -{ - struct hvsi_struct *hp = tty->driver_data; - - pr_debug("%s\n", __func__); - - h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); -} - -static void hvsi_unthrottle(struct tty_struct *tty) -{ - struct hvsi_struct *hp = tty->driver_data; - unsigned long flags; - int shouldflip = 0; - - pr_debug("%s\n", __func__); - - spin_lock_irqsave(&hp->lock, flags); - if (hp->n_throttle) { - hvsi_send_overflow(hp); - shouldflip = 1; - } - spin_unlock_irqrestore(&hp->lock, flags); - - if (shouldflip) - tty_flip_buffer_push(hp->tty); - - h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); -} - -static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct hvsi_struct *hp = tty->driver_data; - - hvsi_get_mctrl(hp); - return hp->mctrl; -} - -static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct hvsi_struct *hp = tty->driver_data; - unsigned long flags; - uint16_t new_mctrl; - - /* we can only alter DTR */ - clear &= TIOCM_DTR; - set &= TIOCM_DTR; - - spin_lock_irqsave(&hp->lock, flags); - - new_mctrl = (hp->mctrl & ~clear) | set; - - if (hp->mctrl != new_mctrl) { - hvsi_set_mctrl(hp, new_mctrl); - hp->mctrl = new_mctrl; - } - spin_unlock_irqrestore(&hp->lock, flags); - - return 0; -} - - -static const struct tty_operations hvsi_ops = { - .open = hvsi_open, - .close = hvsi_close, - .write = hvsi_write, - .hangup = hvsi_hangup, - .write_room = hvsi_write_room, - .chars_in_buffer = hvsi_chars_in_buffer, - .throttle = hvsi_throttle, - .unthrottle = hvsi_unthrottle, - .tiocmget = hvsi_tiocmget, - .tiocmset = hvsi_tiocmset, -}; - -static int __init hvsi_init(void) -{ - int i; - - hvsi_driver = alloc_tty_driver(hvsi_count); - if (!hvsi_driver) - return -ENOMEM; - - hvsi_driver->owner = THIS_MODULE; - hvsi_driver->driver_name = "hvsi"; - hvsi_driver->name = "hvsi"; - hvsi_driver->major = HVSI_MAJOR; - hvsi_driver->minor_start = HVSI_MINOR; - hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM; - hvsi_driver->init_termios = tty_std_termios; - hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; - hvsi_driver->init_termios.c_ispeed = 9600; - hvsi_driver->init_termios.c_ospeed = 9600; - hvsi_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(hvsi_driver, &hvsi_ops); - - for (i=0; i < hvsi_count; i++) { - struct hvsi_struct *hp = &hvsi_ports[i]; - int ret = 1; - - ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp); - if (ret) - printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", - hp->virq, ret); - } - hvsi_wait = wait_for_state; /* irqs active now */ - - if (tty_register_driver(hvsi_driver)) - panic("Couldn't register hvsi console driver\n"); - - printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count); - - return 0; -} -device_initcall(hvsi_init); - -/***** console (not tty) code: *****/ - -static void hvsi_console_print(struct console *console, const char *buf, - unsigned int count) -{ - struct hvsi_struct *hp = &hvsi_ports[console->index]; - char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__; - unsigned int i = 0, n = 0; - int ret, donecr = 0; - - mb(); - if (!is_open(hp)) - return; - - /* - * ugh, we have to translate LF -> CRLF ourselves, in place. - * copied from hvc_console.c: - */ - while (count > 0 || i > 0) { - if (count > 0 && i < sizeof(c)) { - if (buf[n] == '\n' && !donecr) { - c[i++] = '\r'; - donecr = 1; - } else { - c[i++] = buf[n++]; - donecr = 0; - --count; - } - } else { - ret = hvsi_put_chars(hp, c, i); - if (ret < 0) - i = 0; - i -= ret; - } - } -} - -static struct tty_driver *hvsi_console_device(struct console *console, - int *index) -{ - *index = console->index; - return hvsi_driver; -} - -static int __init hvsi_console_setup(struct console *console, char *options) -{ - struct hvsi_struct *hp; - int ret; - - if (console->index < 0 || console->index >= hvsi_count) - return -1; - hp = &hvsi_ports[console->index]; - - /* give the FSP a chance to change the baud rate when we re-open */ - hvsi_close_protocol(hp); - - ret = hvsi_handshake(hp); - if (ret < 0) - return ret; - - ret = hvsi_get_mctrl(hp); - if (ret < 0) - return ret; - - ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); - if (ret < 0) - return ret; - - hp->flags |= HVSI_CONSOLE; - - return 0; -} - -static struct console hvsi_console = { - .name = "hvsi", - .write = hvsi_console_print, - .device = hvsi_console_device, - .setup = hvsi_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init hvsi_console_init(void) -{ - struct device_node *vty; - - hvsi_wait = poll_for_state; /* no irqs yet; must poll */ - - /* search device tree for vty nodes */ - for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol"); - vty != NULL; - vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) { - struct hvsi_struct *hp; - const uint32_t *vtermno, *irq; - - vtermno = of_get_property(vty, "reg", NULL); - irq = of_get_property(vty, "interrupts", NULL); - if (!vtermno || !irq) - continue; - - if (hvsi_count >= MAX_NR_HVSI_CONSOLES) { - of_node_put(vty); - break; - } - - hp = &hvsi_ports[hvsi_count]; - INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker); - INIT_WORK(&hp->handshaker, hvsi_handshaker); - init_waitqueue_head(&hp->emptyq); - init_waitqueue_head(&hp->stateq); - spin_lock_init(&hp->lock); - hp->index = hvsi_count; - hp->inbuf_end = hp->inbuf; - hp->state = HVSI_CLOSED; - hp->vtermno = *vtermno; - hp->virq = irq_create_mapping(NULL, irq[0]); - if (hp->virq == NO_IRQ) { - printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", - __func__, irq[0]); - continue; - } - - hvsi_count++; - } - - if (hvsi_count) - register_console(&hvsi_console); - return 0; -} -console_initcall(hvsi_console_init); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c deleted file mode 100644 index 896a2ced1d27..000000000000 --- a/drivers/char/virtio_console.c +++ /dev/null @@ -1,1838 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation - * Copyright (C) 2009, 2010 Red Hat, Inc. - * - * 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 -#include -#include -#include -#include -#include "hvc_console.h" - -/* - * This is a global struct for storing common data for all the devices - * this driver handles. - * - * Mainly, it has a linked list for all the consoles in one place so - * that callbacks from hvc for get_chars(), put_chars() work properly - * across multiple devices and multiple ports per device. - */ -struct ports_driver_data { - /* Used for registering chardevs */ - struct class *class; - - /* Used for exporting per-port information to debugfs */ - struct dentry *debugfs_dir; - - /* List of all the devices we're handling */ - struct list_head portdevs; - - /* Number of devices this driver is handling */ - unsigned int index; - - /* - * This is used to keep track of the number of hvc consoles - * spawned by this driver. This number is given as the first - * argument to hvc_alloc(). To correctly map an initial - * console spawned via hvc_instantiate to the console being - * hooked up via hvc_alloc, we need to pass the same vtermno. - * - * We also just assume the first console being initialised was - * the first one that got used as the initial console. - */ - unsigned int next_vtermno; - - /* All the console devices handled by this driver */ - struct list_head consoles; -}; -static struct ports_driver_data pdrvdata; - -DEFINE_SPINLOCK(pdrvdata_lock); - -/* This struct holds information that's relevant only for console ports */ -struct console { - /* We'll place all consoles in a list in the pdrvdata struct */ - struct list_head list; - - /* The hvc device associated with this console port */ - struct hvc_struct *hvc; - - /* The size of the console */ - struct winsize ws; - - /* - * This number identifies the number that we used to register - * with hvc in hvc_instantiate() and hvc_alloc(); this is the - * number passed on by the hvc callbacks to us to - * differentiate between the other console ports handled by - * this driver - */ - u32 vtermno; -}; - -struct port_buffer { - char *buf; - - /* size of the buffer in *buf above */ - size_t size; - - /* used length of the buffer */ - size_t len; - /* offset in the buf from which to consume data */ - size_t offset; -}; - -/* - * This is a per-device struct that stores data common to all the - * ports for that device (vdev->priv). - */ -struct ports_device { - /* Next portdev in the list, head is in the pdrvdata struct */ - struct list_head list; - - /* - * Workqueue handlers where we process deferred work after - * notification - */ - struct work_struct control_work; - - struct list_head ports; - - /* To protect the list of ports */ - spinlock_t ports_lock; - - /* To protect the vq operations for the control channel */ - spinlock_t cvq_lock; - - /* The current config space is stored here */ - struct virtio_console_config config; - - /* The virtio device we're associated with */ - struct virtio_device *vdev; - - /* - * A couple of virtqueues for the control channel: one for - * guest->host transfers, one for host->guest transfers - */ - struct virtqueue *c_ivq, *c_ovq; - - /* Array of per-port IO virtqueues */ - struct virtqueue **in_vqs, **out_vqs; - - /* Used for numbering devices for sysfs and debugfs */ - unsigned int drv_index; - - /* Major number for this device. Ports will be created as minors. */ - int chr_major; -}; - -/* This struct holds the per-port data */ -struct port { - /* Next port in the list, head is in the ports_device */ - struct list_head list; - - /* Pointer to the parent virtio_console device */ - struct ports_device *portdev; - - /* The current buffer from which data has to be fed to readers */ - struct port_buffer *inbuf; - - /* - * To protect the operations on the in_vq associated with this - * port. Has to be a spinlock because it can be called from - * interrupt context (get_char()). - */ - spinlock_t inbuf_lock; - - /* Protect the operations on the out_vq. */ - spinlock_t outvq_lock; - - /* The IO vqs for this port */ - struct virtqueue *in_vq, *out_vq; - - /* File in the debugfs directory that exposes this port's information */ - struct dentry *debugfs_file; - - /* - * The entries in this struct will be valid if this port is - * hooked up to an hvc console - */ - struct console cons; - - /* Each port associates with a separate char device */ - struct cdev *cdev; - struct device *dev; - - /* Reference-counting to handle port hot-unplugs and file operations */ - struct kref kref; - - /* A waitqueue for poll() or blocking read operations */ - wait_queue_head_t waitqueue; - - /* The 'name' of the port that we expose via sysfs properties */ - char *name; - - /* We can notify apps of host connect / disconnect events via SIGIO */ - struct fasync_struct *async_queue; - - /* The 'id' to identify the port with the Host */ - u32 id; - - bool outvq_full; - - /* Is the host device open */ - bool host_connected; - - /* We should allow only one process to open a port */ - bool guest_connected; -}; - -/* This is the very early arch-specified put chars function. */ -static int (*early_put_chars)(u32, const char *, int); - -static struct port *find_port_by_vtermno(u32 vtermno) -{ - struct port *port; - struct console *cons; - unsigned long flags; - - spin_lock_irqsave(&pdrvdata_lock, flags); - list_for_each_entry(cons, &pdrvdata.consoles, list) { - if (cons->vtermno == vtermno) { - port = container_of(cons, struct port, cons); - goto out; - } - } - port = NULL; -out: - spin_unlock_irqrestore(&pdrvdata_lock, flags); - return port; -} - -static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, - dev_t dev) -{ - struct port *port; - unsigned long flags; - - spin_lock_irqsave(&portdev->ports_lock, flags); - list_for_each_entry(port, &portdev->ports, list) - if (port->cdev->dev == dev) - goto out; - port = NULL; -out: - spin_unlock_irqrestore(&portdev->ports_lock, flags); - - return port; -} - -static struct port *find_port_by_devt(dev_t dev) -{ - struct ports_device *portdev; - struct port *port; - unsigned long flags; - - spin_lock_irqsave(&pdrvdata_lock, flags); - list_for_each_entry(portdev, &pdrvdata.portdevs, list) { - port = find_port_by_devt_in_portdev(portdev, dev); - if (port) - goto out; - } - port = NULL; -out: - spin_unlock_irqrestore(&pdrvdata_lock, flags); - return port; -} - -static struct port *find_port_by_id(struct ports_device *portdev, u32 id) -{ - struct port *port; - unsigned long flags; - - spin_lock_irqsave(&portdev->ports_lock, flags); - list_for_each_entry(port, &portdev->ports, list) - if (port->id == id) - goto out; - port = NULL; -out: - spin_unlock_irqrestore(&portdev->ports_lock, flags); - - return port; -} - -static struct port *find_port_by_vq(struct ports_device *portdev, - struct virtqueue *vq) -{ - struct port *port; - unsigned long flags; - - spin_lock_irqsave(&portdev->ports_lock, flags); - list_for_each_entry(port, &portdev->ports, list) - if (port->in_vq == vq || port->out_vq == vq) - goto out; - port = NULL; -out: - spin_unlock_irqrestore(&portdev->ports_lock, flags); - return port; -} - -static bool is_console_port(struct port *port) -{ - if (port->cons.hvc) - return true; - return false; -} - -static inline bool use_multiport(struct ports_device *portdev) -{ - /* - * This condition can be true when put_chars is called from - * early_init - */ - if (!portdev->vdev) - return 0; - return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); -} - -static void free_buf(struct port_buffer *buf) -{ - kfree(buf->buf); - kfree(buf); -} - -static struct port_buffer *alloc_buf(size_t buf_size) -{ - struct port_buffer *buf; - - buf = kmalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - goto fail; - buf->buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf->buf) - goto free_buf; - buf->len = 0; - buf->offset = 0; - buf->size = buf_size; - return buf; - -free_buf: - kfree(buf); -fail: - return NULL; -} - -/* Callers should take appropriate locks */ -static void *get_inbuf(struct port *port) -{ - struct port_buffer *buf; - struct virtqueue *vq; - unsigned int len; - - vq = port->in_vq; - buf = virtqueue_get_buf(vq, &len); - if (buf) { - buf->len = len; - buf->offset = 0; - } - return buf; -} - -/* - * Create a scatter-gather list representing our input buffer and put - * it in the queue. - * - * Callers should take appropriate locks. - */ -static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) -{ - struct scatterlist sg[1]; - int ret; - - sg_init_one(sg, buf->buf, buf->size); - - ret = virtqueue_add_buf(vq, sg, 0, 1, buf); - virtqueue_kick(vq); - return ret; -} - -/* Discard any unread data this port has. Callers lockers. */ -static void discard_port_data(struct port *port) -{ - struct port_buffer *buf; - struct virtqueue *vq; - unsigned int len; - int ret; - - vq = port->in_vq; - if (port->inbuf) - buf = port->inbuf; - else - buf = virtqueue_get_buf(vq, &len); - - ret = 0; - while (buf) { - if (add_inbuf(vq, buf) < 0) { - ret++; - free_buf(buf); - } - buf = virtqueue_get_buf(vq, &len); - } - port->inbuf = NULL; - if (ret) - dev_warn(port->dev, "Errors adding %d buffers back to vq\n", - ret); -} - -static bool port_has_data(struct port *port) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&port->inbuf_lock, flags); - if (port->inbuf) { - ret = true; - goto out; - } - port->inbuf = get_inbuf(port); - if (port->inbuf) { - ret = true; - goto out; - } - ret = false; -out: - spin_unlock_irqrestore(&port->inbuf_lock, flags); - return ret; -} - -static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, - unsigned int event, unsigned int value) -{ - struct scatterlist sg[1]; - struct virtio_console_control cpkt; - struct virtqueue *vq; - unsigned int len; - - if (!use_multiport(portdev)) - return 0; - - cpkt.id = port_id; - cpkt.event = event; - cpkt.value = value; - - vq = portdev->c_ovq; - - sg_init_one(sg, &cpkt, sizeof(cpkt)); - if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) { - virtqueue_kick(vq); - while (!virtqueue_get_buf(vq, &len)) - cpu_relax(); - } - return 0; -} - -static ssize_t send_control_msg(struct port *port, unsigned int event, - unsigned int value) -{ - /* Did the port get unplugged before userspace closed it? */ - if (port->portdev) - return __send_control_msg(port->portdev, port->id, event, value); - return 0; -} - -/* Callers must take the port->outvq_lock */ -static void reclaim_consumed_buffers(struct port *port) -{ - void *buf; - unsigned int len; - - while ((buf = virtqueue_get_buf(port->out_vq, &len))) { - kfree(buf); - port->outvq_full = false; - } -} - -static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, - bool nonblock) -{ - struct scatterlist sg[1]; - struct virtqueue *out_vq; - ssize_t ret; - unsigned long flags; - unsigned int len; - - out_vq = port->out_vq; - - spin_lock_irqsave(&port->outvq_lock, flags); - - reclaim_consumed_buffers(port); - - sg_init_one(sg, in_buf, in_count); - ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf); - - /* Tell Host to go! */ - virtqueue_kick(out_vq); - - if (ret < 0) { - in_count = 0; - goto done; - } - - if (ret == 0) - port->outvq_full = true; - - if (nonblock) - goto done; - - /* - * Wait till the host acknowledges it pushed out the data we - * sent. This is done for data from the hvc_console; the tty - * operations are performed with spinlocks held so we can't - * sleep here. An alternative would be to copy the data to a - * buffer and relax the spinning requirement. The downside is - * we need to kmalloc a GFP_ATOMIC buffer each time the - * console driver writes something out. - */ - while (!virtqueue_get_buf(out_vq, &len)) - cpu_relax(); -done: - spin_unlock_irqrestore(&port->outvq_lock, flags); - /* - * We're expected to return the amount of data we wrote -- all - * of it - */ - return in_count; -} - -/* - * Give out the data that's requested from the buffer that we have - * queued up. - */ -static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, - bool to_user) -{ - struct port_buffer *buf; - unsigned long flags; - - if (!out_count || !port_has_data(port)) - return 0; - - buf = port->inbuf; - out_count = min(out_count, buf->len - buf->offset); - - if (to_user) { - ssize_t ret; - - ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count); - if (ret) - return -EFAULT; - } else { - memcpy(out_buf, buf->buf + buf->offset, out_count); - } - - buf->offset += out_count; - - if (buf->offset == buf->len) { - /* - * We're done using all the data in this buffer. - * Re-queue so that the Host can send us more data. - */ - spin_lock_irqsave(&port->inbuf_lock, flags); - port->inbuf = NULL; - - if (add_inbuf(port->in_vq, buf) < 0) - dev_warn(port->dev, "failed add_buf\n"); - - spin_unlock_irqrestore(&port->inbuf_lock, flags); - } - /* Return the number of bytes actually copied */ - return out_count; -} - -/* The condition that must be true for polling to end */ -static bool will_read_block(struct port *port) -{ - if (!port->guest_connected) { - /* Port got hot-unplugged. Let's exit. */ - return false; - } - return !port_has_data(port) && port->host_connected; -} - -static bool will_write_block(struct port *port) -{ - bool ret; - - if (!port->guest_connected) { - /* Port got hot-unplugged. Let's exit. */ - return false; - } - if (!port->host_connected) - return true; - - spin_lock_irq(&port->outvq_lock); - /* - * Check if the Host has consumed any buffers since we last - * sent data (this is only applicable for nonblocking ports). - */ - reclaim_consumed_buffers(port); - ret = port->outvq_full; - spin_unlock_irq(&port->outvq_lock); - - return ret; -} - -static ssize_t port_fops_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) -{ - struct port *port; - ssize_t ret; - - port = filp->private_data; - - if (!port_has_data(port)) { - /* - * If nothing's connected on the host just return 0 in - * case of list_empty; this tells the userspace app - * that there's no connection - */ - if (!port->host_connected) - return 0; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - - ret = wait_event_interruptible(port->waitqueue, - !will_read_block(port)); - if (ret < 0) - return ret; - } - /* Port got hot-unplugged. */ - if (!port->guest_connected) - return -ENODEV; - /* - * We could've received a disconnection message while we were - * waiting for more data. - * - * This check is not clubbed in the if() statement above as we - * might receive some data as well as the host could get - * disconnected after we got woken up from our wait. So we - * really want to give off whatever data we have and only then - * check for host_connected. - */ - if (!port_has_data(port) && !port->host_connected) - return 0; - - return fill_readbuf(port, ubuf, count, true); -} - -static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, - size_t count, loff_t *offp) -{ - struct port *port; - char *buf; - ssize_t ret; - bool nonblock; - - /* Userspace could be out to fool us */ - if (!count) - return 0; - - port = filp->private_data; - - nonblock = filp->f_flags & O_NONBLOCK; - - if (will_write_block(port)) { - if (nonblock) - return -EAGAIN; - - ret = wait_event_interruptible(port->waitqueue, - !will_write_block(port)); - if (ret < 0) - return ret; - } - /* Port got hot-unplugged. */ - if (!port->guest_connected) - return -ENODEV; - - count = min((size_t)(32 * 1024), count); - - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = copy_from_user(buf, ubuf, count); - if (ret) { - ret = -EFAULT; - goto free_buf; - } - - /* - * We now ask send_buf() to not spin for generic ports -- we - * can re-use the same code path that non-blocking file - * descriptors take for blocking file descriptors since the - * wait is already done and we're certain the write will go - * through to the host. - */ - nonblock = true; - ret = send_buf(port, buf, count, nonblock); - - if (nonblock && ret > 0) - goto out; - -free_buf: - kfree(buf); -out: - return ret; -} - -static unsigned int port_fops_poll(struct file *filp, poll_table *wait) -{ - struct port *port; - unsigned int ret; - - port = filp->private_data; - poll_wait(filp, &port->waitqueue, wait); - - if (!port->guest_connected) { - /* Port got unplugged */ - return POLLHUP; - } - ret = 0; - if (!will_read_block(port)) - ret |= POLLIN | POLLRDNORM; - if (!will_write_block(port)) - ret |= POLLOUT; - if (!port->host_connected) - ret |= POLLHUP; - - return ret; -} - -static void remove_port(struct kref *kref); - -static int port_fops_release(struct inode *inode, struct file *filp) -{ - struct port *port; - - port = filp->private_data; - - /* Notify host of port being closed */ - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); - - spin_lock_irq(&port->inbuf_lock); - port->guest_connected = false; - - discard_port_data(port); - - spin_unlock_irq(&port->inbuf_lock); - - spin_lock_irq(&port->outvq_lock); - reclaim_consumed_buffers(port); - spin_unlock_irq(&port->outvq_lock); - - /* - * Locks aren't necessary here as a port can't be opened after - * unplug, and if a port isn't unplugged, a kref would already - * exist for the port. Plus, taking ports_lock here would - * create a dependency on other locks taken by functions - * inside remove_port if we're the last holder of the port, - * creating many problems. - */ - kref_put(&port->kref, remove_port); - - return 0; -} - -static int port_fops_open(struct inode *inode, struct file *filp) -{ - struct cdev *cdev = inode->i_cdev; - struct port *port; - int ret; - - port = find_port_by_devt(cdev->dev); - filp->private_data = port; - - /* Prevent against a port getting hot-unplugged at the same time */ - spin_lock_irq(&port->portdev->ports_lock); - kref_get(&port->kref); - spin_unlock_irq(&port->portdev->ports_lock); - - /* - * Don't allow opening of console port devices -- that's done - * via /dev/hvc - */ - if (is_console_port(port)) { - ret = -ENXIO; - goto out; - } - - /* Allow only one process to open a particular port at a time */ - spin_lock_irq(&port->inbuf_lock); - if (port->guest_connected) { - spin_unlock_irq(&port->inbuf_lock); - ret = -EMFILE; - goto out; - } - - port->guest_connected = true; - spin_unlock_irq(&port->inbuf_lock); - - spin_lock_irq(&port->outvq_lock); - /* - * There might be a chance that we missed reclaiming a few - * buffers in the window of the port getting previously closed - * and opening now. - */ - reclaim_consumed_buffers(port); - spin_unlock_irq(&port->outvq_lock); - - nonseekable_open(inode, filp); - - /* Notify host of port being opened */ - send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); - - return 0; -out: - kref_put(&port->kref, remove_port); - return ret; -} - -static int port_fops_fasync(int fd, struct file *filp, int mode) -{ - struct port *port; - - port = filp->private_data; - return fasync_helper(fd, filp, mode, &port->async_queue); -} - -/* - * The file operations that we support: programs in the guest can open - * a console device, read from it, write to it, poll for data and - * close it. The devices are at - * /dev/vportp - */ -static const struct file_operations port_fops = { - .owner = THIS_MODULE, - .open = port_fops_open, - .read = port_fops_read, - .write = port_fops_write, - .poll = port_fops_poll, - .release = port_fops_release, - .fasync = port_fops_fasync, - .llseek = no_llseek, -}; - -/* - * The put_chars() callback is pretty straightforward. - * - * We turn the characters into a scatter-gather list, add it to the - * output queue and then kick the Host. Then we sit here waiting for - * it to finish: inefficient in theory, but in practice - * implementations will do it immediately (lguest's Launcher does). - */ -static int put_chars(u32 vtermno, const char *buf, int count) -{ - struct port *port; - - if (unlikely(early_put_chars)) - return early_put_chars(vtermno, buf, count); - - port = find_port_by_vtermno(vtermno); - if (!port) - return -EPIPE; - - return send_buf(port, (void *)buf, count, false); -} - -/* - * get_chars() is the callback from the hvc_console infrastructure - * when an interrupt is received. - * - * We call out to fill_readbuf that gets us the required data from the - * buffers that are queued up. - */ -static int get_chars(u32 vtermno, char *buf, int count) -{ - struct port *port; - - /* If we've not set up the port yet, we have no input to give. */ - if (unlikely(early_put_chars)) - return 0; - - port = find_port_by_vtermno(vtermno); - if (!port) - return -EPIPE; - - /* If we don't have an input queue yet, we can't get input. */ - BUG_ON(!port->in_vq); - - return fill_readbuf(port, buf, count, false); -} - -static void resize_console(struct port *port) -{ - struct virtio_device *vdev; - - /* The port could have been hot-unplugged */ - if (!port || !is_console_port(port)) - return; - - vdev = port->portdev->vdev; - if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) - hvc_resize(port->cons.hvc, port->cons.ws); -} - -/* We set the configuration at this point, since we now have a tty */ -static int notifier_add_vio(struct hvc_struct *hp, int data) -{ - struct port *port; - - port = find_port_by_vtermno(hp->vtermno); - if (!port) - return -EINVAL; - - hp->irq_requested = 1; - resize_console(port); - - return 0; -} - -static void notifier_del_vio(struct hvc_struct *hp, int data) -{ - hp->irq_requested = 0; -} - -/* The operations for console ports. */ -static const struct hv_ops hv_ops = { - .get_chars = get_chars, - .put_chars = put_chars, - .notifier_add = notifier_add_vio, - .notifier_del = notifier_del_vio, - .notifier_hangup = notifier_del_vio, -}; - -/* - * Console drivers are initialized very early so boot messages can go - * out, so we do things slightly differently from the generic virtio - * initialization of the net and block drivers. - * - * At this stage, the console is output-only. It's too early to set - * up a virtqueue, so we let the drivers do some boutique early-output - * thing. - */ -int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) -{ - early_put_chars = put_chars; - return hvc_instantiate(0, 0, &hv_ops); -} - -int init_port_console(struct port *port) -{ - int ret; - - /* - * The Host's telling us this port is a console port. Hook it - * up with an hvc console. - * - * To set up and manage our virtual console, we call - * hvc_alloc(). - * - * The first argument of hvc_alloc() is the virtual console - * number. The second argument is the parameter for the - * notification mechanism (like irq number). We currently - * leave this as zero, virtqueues have implicit notifications. - * - * The third argument is a "struct hv_ops" containing the - * put_chars() get_chars(), notifier_add() and notifier_del() - * pointers. The final argument is the output buffer size: we - * can do any size, so we put PAGE_SIZE here. - */ - port->cons.vtermno = pdrvdata.next_vtermno; - - port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); - if (IS_ERR(port->cons.hvc)) { - ret = PTR_ERR(port->cons.hvc); - dev_err(port->dev, - "error %d allocating hvc for port\n", ret); - port->cons.hvc = NULL; - return ret; - } - spin_lock_irq(&pdrvdata_lock); - pdrvdata.next_vtermno++; - list_add_tail(&port->cons.list, &pdrvdata.consoles); - spin_unlock_irq(&pdrvdata_lock); - port->guest_connected = true; - - /* - * Start using the new console output if this is the first - * console to come up. - */ - if (early_put_chars) - early_put_chars = NULL; - - /* Notify host of port being opened */ - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); - - return 0; -} - -static ssize_t show_port_name(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - struct port *port; - - port = dev_get_drvdata(dev); - - return sprintf(buffer, "%s\n", port->name); -} - -static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL); - -static struct attribute *port_sysfs_entries[] = { - &dev_attr_name.attr, - NULL -}; - -static struct attribute_group port_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = port_sysfs_entries, -}; - -static int debugfs_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - -static ssize_t debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) -{ - struct port *port; - char *buf; - ssize_t ret, out_offset, out_count; - - out_count = 1024; - buf = kmalloc(out_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - port = filp->private_data; - out_offset = 0; - out_offset += snprintf(buf + out_offset, out_count, - "name: %s\n", port->name ? port->name : ""); - out_offset += snprintf(buf + out_offset, out_count - out_offset, - "guest_connected: %d\n", port->guest_connected); - out_offset += snprintf(buf + out_offset, out_count - out_offset, - "host_connected: %d\n", port->host_connected); - out_offset += snprintf(buf + out_offset, out_count - out_offset, - "outvq_full: %d\n", port->outvq_full); - out_offset += snprintf(buf + out_offset, out_count - out_offset, - "is_console: %s\n", - is_console_port(port) ? "yes" : "no"); - out_offset += snprintf(buf + out_offset, out_count - out_offset, - "console_vtermno: %u\n", port->cons.vtermno); - - ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); - kfree(buf); - return ret; -} - -static const struct file_operations port_debugfs_ops = { - .owner = THIS_MODULE, - .open = debugfs_open, - .read = debugfs_read, -}; - -static void set_console_size(struct port *port, u16 rows, u16 cols) -{ - if (!port || !is_console_port(port)) - return; - - port->cons.ws.ws_row = rows; - port->cons.ws.ws_col = cols; -} - -static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) -{ - struct port_buffer *buf; - unsigned int nr_added_bufs; - int ret; - - nr_added_bufs = 0; - do { - buf = alloc_buf(PAGE_SIZE); - if (!buf) - break; - - spin_lock_irq(lock); - ret = add_inbuf(vq, buf); - if (ret < 0) { - spin_unlock_irq(lock); - free_buf(buf); - break; - } - nr_added_bufs++; - spin_unlock_irq(lock); - } while (ret > 0); - - return nr_added_bufs; -} - -static void send_sigio_to_port(struct port *port) -{ - if (port->async_queue && port->guest_connected) - kill_fasync(&port->async_queue, SIGIO, POLL_OUT); -} - -static int add_port(struct ports_device *portdev, u32 id) -{ - char debugfs_name[16]; - struct port *port; - struct port_buffer *buf; - dev_t devt; - unsigned int nr_added_bufs; - int err; - - port = kmalloc(sizeof(*port), GFP_KERNEL); - if (!port) { - err = -ENOMEM; - goto fail; - } - kref_init(&port->kref); - - port->portdev = portdev; - port->id = id; - - port->name = NULL; - port->inbuf = NULL; - port->cons.hvc = NULL; - port->async_queue = NULL; - - port->cons.ws.ws_row = port->cons.ws.ws_col = 0; - - port->host_connected = port->guest_connected = false; - - port->outvq_full = false; - - port->in_vq = portdev->in_vqs[port->id]; - port->out_vq = portdev->out_vqs[port->id]; - - port->cdev = cdev_alloc(); - if (!port->cdev) { - dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n"); - err = -ENOMEM; - goto free_port; - } - port->cdev->ops = &port_fops; - - devt = MKDEV(portdev->chr_major, id); - err = cdev_add(port->cdev, devt, 1); - if (err < 0) { - dev_err(&port->portdev->vdev->dev, - "Error %d adding cdev for port %u\n", err, id); - goto free_cdev; - } - port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, - devt, port, "vport%up%u", - port->portdev->drv_index, id); - if (IS_ERR(port->dev)) { - err = PTR_ERR(port->dev); - dev_err(&port->portdev->vdev->dev, - "Error %d creating device for port %u\n", - err, id); - goto free_cdev; - } - - spin_lock_init(&port->inbuf_lock); - spin_lock_init(&port->outvq_lock); - init_waitqueue_head(&port->waitqueue); - - /* Fill the in_vq with buffers so the host can send us data. */ - nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); - if (!nr_added_bufs) { - dev_err(port->dev, "Error allocating inbufs\n"); - err = -ENOMEM; - goto free_device; - } - - /* - * If we're not using multiport support, this has to be a console port - */ - if (!use_multiport(port->portdev)) { - err = init_port_console(port); - if (err) - goto free_inbufs; - } - - spin_lock_irq(&portdev->ports_lock); - list_add_tail(&port->list, &port->portdev->ports); - spin_unlock_irq(&portdev->ports_lock); - - /* - * Tell the Host we're set so that it can send us various - * configuration parameters for this port (eg, port name, - * caching, whether this is a console port, etc.) - */ - send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); - - if (pdrvdata.debugfs_dir) { - /* - * Finally, create the debugfs file that we can use to - * inspect a port's state at any time - */ - sprintf(debugfs_name, "vport%up%u", - port->portdev->drv_index, id); - port->debugfs_file = debugfs_create_file(debugfs_name, 0444, - pdrvdata.debugfs_dir, - port, - &port_debugfs_ops); - } - return 0; - -free_inbufs: - while ((buf = virtqueue_detach_unused_buf(port->in_vq))) - free_buf(buf); -free_device: - device_destroy(pdrvdata.class, port->dev->devt); -free_cdev: - cdev_del(port->cdev); -free_port: - kfree(port); -fail: - /* The host might want to notify management sw about port add failure */ - __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0); - return err; -} - -/* No users remain, remove all port-specific data. */ -static void remove_port(struct kref *kref) -{ - struct port *port; - - port = container_of(kref, struct port, kref); - - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); - device_destroy(pdrvdata.class, port->dev->devt); - cdev_del(port->cdev); - - kfree(port->name); - - debugfs_remove(port->debugfs_file); - - kfree(port); -} - -/* - * Port got unplugged. Remove port from portdev's list and drop the - * kref reference. If no userspace has this port opened, it will - * result in immediate removal the port. - */ -static void unplug_port(struct port *port) -{ - struct port_buffer *buf; - - spin_lock_irq(&port->portdev->ports_lock); - list_del(&port->list); - spin_unlock_irq(&port->portdev->ports_lock); - - if (port->guest_connected) { - port->guest_connected = false; - port->host_connected = false; - wake_up_interruptible(&port->waitqueue); - - /* Let the app know the port is going down. */ - send_sigio_to_port(port); - } - - if (is_console_port(port)) { - spin_lock_irq(&pdrvdata_lock); - list_del(&port->cons.list); - spin_unlock_irq(&pdrvdata_lock); -#if 0 - /* - * hvc_remove() not called as removing one hvc port - * results in other hvc ports getting frozen. - * - * Once this is resolved in hvc, this functionality - * will be enabled. Till that is done, the -EPIPE - * return from get_chars() above will help - * hvc_console.c to clean up on ports we remove here. - */ - hvc_remove(port->cons.hvc); -#endif - } - - /* Remove unused data this port might have received. */ - discard_port_data(port); - - reclaim_consumed_buffers(port); - - /* Remove buffers we queued up for the Host to send us data in. */ - while ((buf = virtqueue_detach_unused_buf(port->in_vq))) - free_buf(buf); - - /* - * We should just assume the device itself has gone off -- - * else a close on an open port later will try to send out a - * control message. - */ - port->portdev = NULL; - - /* - * Locks around here are not necessary - a port can't be - * opened after we removed the port struct from ports_list - * above. - */ - kref_put(&port->kref, remove_port); -} - -/* Any private messages that the Host and Guest want to share */ -static void handle_control_message(struct ports_device *portdev, - struct port_buffer *buf) -{ - struct virtio_console_control *cpkt; - struct port *port; - size_t name_size; - int err; - - cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); - - port = find_port_by_id(portdev, cpkt->id); - if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) { - /* No valid header at start of buffer. Drop it. */ - dev_dbg(&portdev->vdev->dev, - "Invalid index %u in control packet\n", cpkt->id); - return; - } - - switch (cpkt->event) { - case VIRTIO_CONSOLE_PORT_ADD: - if (port) { - dev_dbg(&portdev->vdev->dev, - "Port %u already added\n", port->id); - send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); - break; - } - if (cpkt->id >= portdev->config.max_nr_ports) { - dev_warn(&portdev->vdev->dev, - "Request for adding port with out-of-bound id %u, max. supported id: %u\n", - cpkt->id, portdev->config.max_nr_ports - 1); - break; - } - add_port(portdev, cpkt->id); - break; - case VIRTIO_CONSOLE_PORT_REMOVE: - unplug_port(port); - break; - case VIRTIO_CONSOLE_CONSOLE_PORT: - if (!cpkt->value) - break; - if (is_console_port(port)) - break; - - init_port_console(port); - /* - * Could remove the port here in case init fails - but - * have to notify the host first. - */ - break; - case VIRTIO_CONSOLE_RESIZE: { - struct { - __u16 rows; - __u16 cols; - } size; - - if (!is_console_port(port)) - break; - - memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), - sizeof(size)); - set_console_size(port, size.rows, size.cols); - - port->cons.hvc->irq_requested = 1; - resize_console(port); - break; - } - case VIRTIO_CONSOLE_PORT_OPEN: - port->host_connected = cpkt->value; - wake_up_interruptible(&port->waitqueue); - /* - * If the host port got closed and the host had any - * unconsumed buffers, we'll be able to reclaim them - * now. - */ - spin_lock_irq(&port->outvq_lock); - reclaim_consumed_buffers(port); - spin_unlock_irq(&port->outvq_lock); - - /* - * If the guest is connected, it'll be interested in - * knowing the host connection state changed. - */ - send_sigio_to_port(port); - break; - case VIRTIO_CONSOLE_PORT_NAME: - /* - * Skip the size of the header and the cpkt to get the size - * of the name that was sent - */ - name_size = buf->len - buf->offset - sizeof(*cpkt) + 1; - - port->name = kmalloc(name_size, GFP_KERNEL); - if (!port->name) { - dev_err(port->dev, - "Not enough space to store port name\n"); - break; - } - strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), - name_size - 1); - port->name[name_size - 1] = 0; - - /* - * Since we only have one sysfs attribute, 'name', - * create it only if we have a name for the port. - */ - err = sysfs_create_group(&port->dev->kobj, - &port_attribute_group); - if (err) { - dev_err(port->dev, - "Error %d creating sysfs device attributes\n", - err); - } else { - /* - * Generate a udev event so that appropriate - * symlinks can be created based on udev - * rules. - */ - kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); - } - break; - } -} - -static void control_work_handler(struct work_struct *work) -{ - struct ports_device *portdev; - struct virtqueue *vq; - struct port_buffer *buf; - unsigned int len; - - portdev = container_of(work, struct ports_device, control_work); - vq = portdev->c_ivq; - - spin_lock(&portdev->cvq_lock); - while ((buf = virtqueue_get_buf(vq, &len))) { - spin_unlock(&portdev->cvq_lock); - - buf->len = len; - buf->offset = 0; - - handle_control_message(portdev, buf); - - spin_lock(&portdev->cvq_lock); - if (add_inbuf(portdev->c_ivq, buf) < 0) { - dev_warn(&portdev->vdev->dev, - "Error adding buffer to queue\n"); - free_buf(buf); - } - } - spin_unlock(&portdev->cvq_lock); -} - -static void in_intr(struct virtqueue *vq) -{ - struct port *port; - unsigned long flags; - - port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) - return; - - spin_lock_irqsave(&port->inbuf_lock, flags); - if (!port->inbuf) - port->inbuf = get_inbuf(port); - - /* - * Don't queue up data when port is closed. This condition - * can be reached when a console port is not yet connected (no - * tty is spawned) and the host sends out data to console - * ports. For generic serial ports, the host won't - * (shouldn't) send data till the guest is connected. - */ - if (!port->guest_connected) - discard_port_data(port); - - spin_unlock_irqrestore(&port->inbuf_lock, flags); - - wake_up_interruptible(&port->waitqueue); - - /* Send a SIGIO indicating new data in case the process asked for it */ - send_sigio_to_port(port); - - if (is_console_port(port) && hvc_poll(port->cons.hvc)) - hvc_kick(); -} - -static void control_intr(struct virtqueue *vq) -{ - struct ports_device *portdev; - - portdev = vq->vdev->priv; - schedule_work(&portdev->control_work); -} - -static void config_intr(struct virtio_device *vdev) -{ - struct ports_device *portdev; - - portdev = vdev->priv; - - if (!use_multiport(portdev)) { - struct port *port; - u16 rows, cols; - - vdev->config->get(vdev, - offsetof(struct virtio_console_config, cols), - &cols, sizeof(u16)); - vdev->config->get(vdev, - offsetof(struct virtio_console_config, rows), - &rows, sizeof(u16)); - - port = find_port_by_id(portdev, 0); - set_console_size(port, rows, cols); - - /* - * We'll use this way of resizing only for legacy - * support. For newer userspace - * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages - * to indicate console size changes so that it can be - * done per-port. - */ - resize_console(port); - } -} - -static int init_vqs(struct ports_device *portdev) -{ - vq_callback_t **io_callbacks; - char **io_names; - struct virtqueue **vqs; - u32 i, j, nr_ports, nr_queues; - int err; - - nr_ports = portdev->config.max_nr_ports; - nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; - - vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); - io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); - io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); - portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), - GFP_KERNEL); - portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), - GFP_KERNEL); - if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || - !portdev->out_vqs) { - err = -ENOMEM; - goto free; - } - - /* - * For backward compat (newer host but older guest), the host - * spawns a console port first and also inits the vqs for port - * 0 before others. - */ - j = 0; - io_callbacks[j] = in_intr; - io_callbacks[j + 1] = NULL; - io_names[j] = "input"; - io_names[j + 1] = "output"; - j += 2; - - if (use_multiport(portdev)) { - io_callbacks[j] = control_intr; - io_callbacks[j + 1] = NULL; - io_names[j] = "control-i"; - io_names[j + 1] = "control-o"; - - for (i = 1; i < nr_ports; i++) { - j += 2; - io_callbacks[j] = in_intr; - io_callbacks[j + 1] = NULL; - io_names[j] = "input"; - io_names[j + 1] = "output"; - } - } - /* Find the queues. */ - err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, - io_callbacks, - (const char **)io_names); - if (err) - goto free; - - j = 0; - portdev->in_vqs[0] = vqs[0]; - portdev->out_vqs[0] = vqs[1]; - j += 2; - if (use_multiport(portdev)) { - portdev->c_ivq = vqs[j]; - portdev->c_ovq = vqs[j + 1]; - - for (i = 1; i < nr_ports; i++) { - j += 2; - portdev->in_vqs[i] = vqs[j]; - portdev->out_vqs[i] = vqs[j + 1]; - } - } - kfree(io_names); - kfree(io_callbacks); - kfree(vqs); - - return 0; - -free: - kfree(portdev->out_vqs); - kfree(portdev->in_vqs); - kfree(io_names); - kfree(io_callbacks); - kfree(vqs); - - return err; -} - -static const struct file_operations portdev_fops = { - .owner = THIS_MODULE, -}; - -/* - * Once we're further in boot, we get probed like any other virtio - * device. - * - * If the host also supports multiple console ports, we check the - * config space to see how many ports the host has spawned. We - * initialize each port found. - */ -static int __devinit virtcons_probe(struct virtio_device *vdev) -{ - struct ports_device *portdev; - int err; - bool multiport; - - portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); - if (!portdev) { - err = -ENOMEM; - goto fail; - } - - /* Attach this portdev to this virtio_device, and vice-versa. */ - portdev->vdev = vdev; - vdev->priv = portdev; - - spin_lock_irq(&pdrvdata_lock); - portdev->drv_index = pdrvdata.index++; - spin_unlock_irq(&pdrvdata_lock); - - portdev->chr_major = register_chrdev(0, "virtio-portsdev", - &portdev_fops); - if (portdev->chr_major < 0) { - dev_err(&vdev->dev, - "Error %d registering chrdev for device %u\n", - portdev->chr_major, portdev->drv_index); - err = portdev->chr_major; - goto free; - } - - multiport = false; - portdev->config.max_nr_ports = 1; - if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { - multiport = true; - vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT; - - vdev->config->get(vdev, offsetof(struct virtio_console_config, - max_nr_ports), - &portdev->config.max_nr_ports, - sizeof(portdev->config.max_nr_ports)); - } - - /* Let the Host know we support multiple ports.*/ - vdev->config->finalize_features(vdev); - - err = init_vqs(portdev); - if (err < 0) { - dev_err(&vdev->dev, "Error %d initializing vqs\n", err); - goto free_chrdev; - } - - spin_lock_init(&portdev->ports_lock); - INIT_LIST_HEAD(&portdev->ports); - - if (multiport) { - unsigned int nr_added_bufs; - - spin_lock_init(&portdev->cvq_lock); - INIT_WORK(&portdev->control_work, &control_work_handler); - - nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); - if (!nr_added_bufs) { - dev_err(&vdev->dev, - "Error allocating buffers for control queue\n"); - err = -ENOMEM; - goto free_vqs; - } - } else { - /* - * For backward compatibility: Create a console port - * if we're running on older host. - */ - add_port(portdev, 0); - } - - spin_lock_irq(&pdrvdata_lock); - list_add_tail(&portdev->list, &pdrvdata.portdevs); - spin_unlock_irq(&pdrvdata_lock); - - __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, - VIRTIO_CONSOLE_DEVICE_READY, 1); - return 0; - -free_vqs: - /* The host might want to notify mgmt sw about device add failure */ - __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, - VIRTIO_CONSOLE_DEVICE_READY, 0); - vdev->config->del_vqs(vdev); - kfree(portdev->in_vqs); - kfree(portdev->out_vqs); -free_chrdev: - unregister_chrdev(portdev->chr_major, "virtio-portsdev"); -free: - kfree(portdev); -fail: - return err; -} - -static void virtcons_remove(struct virtio_device *vdev) -{ - struct ports_device *portdev; - struct port *port, *port2; - - portdev = vdev->priv; - - spin_lock_irq(&pdrvdata_lock); - list_del(&portdev->list); - spin_unlock_irq(&pdrvdata_lock); - - /* Disable interrupts for vqs */ - vdev->config->reset(vdev); - /* Finish up work that's lined up */ - cancel_work_sync(&portdev->control_work); - - list_for_each_entry_safe(port, port2, &portdev->ports, list) - unplug_port(port); - - unregister_chrdev(portdev->chr_major, "virtio-portsdev"); - - /* - * When yanking out a device, we immediately lose the - * (device-side) queues. So there's no point in keeping the - * guest side around till we drop our final reference. This - * also means that any ports which are in an open state will - * have to just stop using the port, as the vqs are going - * away. - */ - if (use_multiport(portdev)) { - struct port_buffer *buf; - unsigned int len; - - while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) - free_buf(buf); - - while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) - free_buf(buf); - } - - vdev->config->del_vqs(vdev); - kfree(portdev->in_vqs); - kfree(portdev->out_vqs); - - kfree(portdev); -} - -static struct virtio_device_id id_table[] = { - { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, - { 0 }, -}; - -static unsigned int features[] = { - VIRTIO_CONSOLE_F_SIZE, - VIRTIO_CONSOLE_F_MULTIPORT, -}; - -static struct virtio_driver virtio_console = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), - .driver.name = KBUILD_MODNAME, - .driver.owner = THIS_MODULE, - .id_table = id_table, - .probe = virtcons_probe, - .remove = virtcons_remove, - .config_changed = config_intr, -}; - -static int __init init(void) -{ - int err; - - pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); - if (IS_ERR(pdrvdata.class)) { - err = PTR_ERR(pdrvdata.class); - pr_err("Error %d creating virtio-ports class\n", err); - return err; - } - - pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); - if (!pdrvdata.debugfs_dir) { - pr_warning("Error %ld creating debugfs dir for virtio-ports\n", - PTR_ERR(pdrvdata.debugfs_dir)); - } - INIT_LIST_HEAD(&pdrvdata.consoles); - INIT_LIST_HEAD(&pdrvdata.portdevs); - - return register_virtio_driver(&virtio_console); -} - -static void __exit fini(void) -{ - unregister_virtio_driver(&virtio_console); - - class_destroy(pdrvdata.class); - if (pdrvdata.debugfs_dir) - debugfs_remove_recursive(pdrvdata.debugfs_dir); -} -module_init(init); -module_exit(fini); - -MODULE_DEVICE_TABLE(virtio, id_table); -MODULE_DESCRIPTION("Virtio console driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index c43ef48b1a0f..d3685f071b8d 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_N_GSM) += n_gsm.o obj-$(CONFIG_R3964) += n_r3964.o obj-y += vt/ +obj-$(CONFIG_HVC_DRIVER) += hvc/ diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile new file mode 100644 index 000000000000..e6bed5f177ff --- /dev/null +++ b/drivers/tty/hvc/Makefile @@ -0,0 +1,13 @@ +obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o +obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o +obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o +obj-$(CONFIG_HVC_TILE) += hvc_tile.o +obj-$(CONFIG_HVC_DCC) += hvc_dcc.o +obj-$(CONFIG_HVC_BEAT) += hvc_beat.o +obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_IRQ) += hvc_irq.o +obj-$(CONFIG_HVC_XEN) += hvc_xen.o +obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o +obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o +obj-$(CONFIG_HVCS) += hvcs.o +obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c new file mode 100644 index 000000000000..5fe4631e2a61 --- /dev/null +++ b/drivers/tty/hvc/hvc_beat.c @@ -0,0 +1,134 @@ +/* + * Beat hypervisor console driver + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on drivers/char/hvc_rtas.c: + * (C) Copyright IBM Corporation 2001-2005 + * (C) Copyright Red Hat, Inc. 2005 + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hvc_console.h" + +extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); +extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); + +struct hvc_struct *hvc_beat_dev = NULL; + +/* bug: only one queue is available regardless of vtermno */ +static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) +{ + static unsigned char q[sizeof(unsigned long) * 2] + __attribute__((aligned(sizeof(unsigned long)))); + static int qlen = 0; + u64 got; + +again: + if (qlen) { + if (qlen > cnt) { + memcpy(buf, q, cnt); + qlen -= cnt; + memmove(q + cnt, q, qlen); + return cnt; + } else { /* qlen <= cnt */ + int r; + + memcpy(buf, q, qlen); + r = qlen; + qlen = 0; + return r; + } + } + if (beat_get_term_char(vtermno, &got, + ((u64 *)q), ((u64 *)q) + 1) == 0) { + qlen = got; + goto again; + } + return 0; +} + +static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) +{ + unsigned long kb[2]; + int rest, nlen; + + for (rest = cnt; rest > 0; rest -= nlen) { + nlen = (rest > 16) ? 16 : rest; + memcpy(kb, buf, nlen); + beat_put_term_char(vtermno, nlen, kb[0], kb[1]); + buf += nlen; + } + return cnt; +} + +static const struct hv_ops hvc_beat_get_put_ops = { + .get_chars = hvc_beat_get_chars, + .put_chars = hvc_beat_put_chars, +}; + +static int hvc_beat_useit = 1; + +static int hvc_beat_config(char *p) +{ + hvc_beat_useit = simple_strtoul(p, NULL, 0); + return 0; +} + +static int __init hvc_beat_console_init(void) +{ + if (hvc_beat_useit && of_machine_is_compatible("Beat")) { + hvc_instantiate(0, 0, &hvc_beat_get_put_ops); + } + return 0; +} + +/* temp */ +static int __init hvc_beat_init(void) +{ + struct hvc_struct *hp; + + if (!firmware_has_feature(FW_FEATURE_BEAT)) + return -ENODEV; + + hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + hvc_beat_dev = hp; + return 0; +} + +static void __exit hvc_beat_exit(void) +{ + if (hvc_beat_dev) + hvc_remove(hvc_beat_dev); +} + +module_init(hvc_beat_init); +module_exit(hvc_beat_exit); + +__setup("hvc_beat=", hvc_beat_config); + +console_initcall(hvc_beat_console_init); diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c new file mode 100644 index 000000000000..e9cba13ee800 --- /dev/null +++ b/drivers/tty/hvc/hvc_console.c @@ -0,0 +1,914 @@ +/* + * Copyright (C) 2001 Anton Blanchard , IBM + * Copyright (C) 2001 Paul Mackerras , IBM + * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "hvc_console.h" + +#define HVC_MAJOR 229 +#define HVC_MINOR 0 + +/* + * Wait this long per iteration while trying to push buffered data to the + * hypervisor before allowing the tty to complete a close operation. + */ +#define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ + +/* + * These sizes are most efficient for vio, because they are the + * native transfer size. We could make them selectable in the + * future to better deal with backends that want other buffer sizes. + */ +#define N_OUTBUF 16 +#define N_INBUF 16 + +#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) + +static struct tty_driver *hvc_driver; +static struct task_struct *hvc_task; + +/* Picks up late kicks after list walk but before schedule() */ +static int hvc_kicked; + +static int hvc_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; +#endif + +/* dynamic list of hvc_struct instances */ +static LIST_HEAD(hvc_structs); + +/* + * Protect the list of hvc_struct instances from inserts and removals during + * list traversal. + */ +static DEFINE_SPINLOCK(hvc_structs_lock); + +/* + * This value is used to assign a tty->index value to a hvc_struct based + * upon order of exposure via hvc_probe(), when we can not match it to + * a console candidate registered with hvc_instantiate(). + */ +static int last_hvc = -1; + +/* + * Do not call this function with either the hvc_structs_lock or the hvc_struct + * lock held. If successful, this function increments the kref reference + * count against the target hvc_struct so it should be released when finished. + */ +static struct hvc_struct *hvc_get_by_index(int index) +{ + struct hvc_struct *hp; + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + list_for_each_entry(hp, &hvc_structs, next) { + spin_lock_irqsave(&hp->lock, flags); + if (hp->index == index) { + kref_get(&hp->kref); + spin_unlock_irqrestore(&hp->lock, flags); + spin_unlock(&hvc_structs_lock); + return hp; + } + spin_unlock_irqrestore(&hp->lock, flags); + } + hp = NULL; + + spin_unlock(&hvc_structs_lock); + return hp; +} + + +/* + * Initial console vtermnos for console API usage prior to full console + * initialization. Any vty adapter outside this range will not have usable + * console interfaces but can still be used as a tty device. This has to be + * static because kmalloc will not work during early console init. + */ +static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; +static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = + {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; + +/* + * Console APIs, NOT TTY. These APIs are available immediately when + * hvc_console_setup() finds adapters. + */ + +static void hvc_console_print(struct console *co, const char *b, + unsigned count) +{ + char c[N_OUTBUF] __ALIGNED__; + unsigned i = 0, n = 0; + int r, donecr = 0, index = co->index; + + /* Console access attempt outside of acceptable console range. */ + if (index >= MAX_NR_HVC_CONSOLES) + return; + + /* This console adapter was removed so it is not usable. */ + if (vtermnos[index] == -1) + return; + + while (count > 0 || i > 0) { + if (count > 0 && i < sizeof(c)) { + if (b[n] == '\n' && !donecr) { + c[i++] = '\r'; + donecr = 1; + } else { + c[i++] = b[n++]; + donecr = 0; + --count; + } + } else { + r = cons_ops[index]->put_chars(vtermnos[index], c, i); + if (r <= 0) { + /* throw away chars on error */ + i = 0; + } else if (r > 0) { + i -= r; + if (i > 0) + memmove(c, c+r, i); + } + } + } +} + +static struct tty_driver *hvc_console_device(struct console *c, int *index) +{ + if (vtermnos[c->index] == -1) + return NULL; + + *index = c->index; + return hvc_driver; +} + +static int __init hvc_console_setup(struct console *co, char *options) +{ + if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) + return -ENODEV; + + if (vtermnos[co->index] == -1) + return -ENODEV; + + return 0; +} + +static struct console hvc_console = { + .name = "hvc", + .write = hvc_console_print, + .device = hvc_console_device, + .setup = hvc_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* + * Early console initialization. Precedes driver initialization. + * + * (1) we are first, and the user specified another driver + * -- index will remain -1 + * (2) we are first and the user specified no driver + * -- index will be set to 0, then we will fail setup. + * (3) we are first and the user specified our driver + * -- index will be set to user specified driver, and we will fail + * (4) we are after driver, and this initcall will register us + * -- if the user didn't specify a driver then the console will match + * + * Note that for cases 2 and 3, we will match later when the io driver + * calls hvc_instantiate() and call register again. + */ +static int __init hvc_console_init(void) +{ + register_console(&hvc_console); + return 0; +} +console_initcall(hvc_console_init); + +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kref *kref) +{ + struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + +/* + * hvc_instantiate() is an early console discovery method which locates + * consoles * prior to the vio subsystem discovering them. Hotplugged + * vty adapters do NOT get an hvc_instantiate() callback since they + * appear after early console init. + */ +int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) +{ + struct hvc_struct *hp; + + if (index < 0 || index >= MAX_NR_HVC_CONSOLES) + return -1; + + if (vtermnos[index] != -1) + return -1; + + /* make sure no no tty has been registered in this index */ + hp = hvc_get_by_index(index); + if (hp) { + kref_put(&hp->kref, destroy_hvc_struct); + return -1; + } + + vtermnos[index] = vtermno; + cons_ops[index] = ops; + + /* reserve all indices up to and including this index */ + if (last_hvc < index) + last_hvc = index; + + /* if this index is what the user requested, then register + * now (setup won't fail at this point). It's ok to just + * call register again if previously .setup failed. + */ + if (index == hvc_console.index) + register_console(&hvc_console); + + return 0; +} +EXPORT_SYMBOL_GPL(hvc_instantiate); + +/* Wake the sleeping khvcd */ +void hvc_kick(void) +{ + hvc_kicked = 1; + wake_up_process(hvc_task); +} +EXPORT_SYMBOL_GPL(hvc_kick); + +static void hvc_unthrottle(struct tty_struct *tty) +{ + hvc_kick(); +} + +/* + * 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; + 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->lock, flags); + /* Check and then increment for fast path open. */ + if (hp->count++ > 0) { + tty_kref_get(tty); + spin_unlock_irqrestore(&hp->lock, flags); + hvc_kick(); + return 0; + } /* else count == 0 */ + + tty->driver_data = hp; + + hp->tty = tty_kref_get(tty); + + spin_unlock_irqrestore(&hp->lock, flags); + + if (hp->ops->notifier_add) + rc = hp->ops->notifier_add(hp, hp->data); + + /* + * If the notifier fails we return an error. The tty layer + * will call hvc_close() after a failed open but we don't want to clean + * up there so we'll clean up here and clear out the previously set + * tty fields and return the kref reference. + */ + if (rc) { + spin_lock_irqsave(&hp->lock, flags); + hp->tty = NULL; + spin_unlock_irqrestore(&hp->lock, flags); + tty_kref_put(tty); + tty->driver_data = NULL; + kref_put(&hp->kref, destroy_hvc_struct); + printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); + } + /* Force wakeup of the polling thread */ + hvc_kick(); + + return rc; +} + +static void hvc_close(struct tty_struct *tty, struct file * filp) +{ + struct hvc_struct *hp; + unsigned long flags; + + if (tty_hung_up_p(filp)) + return; + + /* + * No driver_data means that this close was issued after a failed + * hvc_open by the tty layer's release_dev() function and we can just + * exit cleanly because the kref reference wasn't made. + */ + if (!tty->driver_data) + return; + + hp = tty->driver_data; + + spin_lock_irqsave(&hp->lock, flags); + + if (--hp->count == 0) { + /* We are done with the tty pointer now. */ + hp->tty = NULL; + spin_unlock_irqrestore(&hp->lock, flags); + + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); + + /* cancel pending tty resize work */ + cancel_work_sync(&hp->tty_resize); + + /* + * Chain calls chars_in_buffer() and returns immediately if + * there is no buffered data otherwise sleeps on a wait queue + * waking periodically to check chars_in_buffer(). + */ + tty_wait_until_sent(tty, HVC_CLOSE_WAIT); + } else { + if (hp->count < 0) + printk(KERN_ERR "hvc_close %X: oops, count is %d\n", + hp->vtermno, hp->count); + spin_unlock_irqrestore(&hp->lock, flags); + } + + tty_kref_put(tty); + kref_put(&hp->kref, destroy_hvc_struct); +} + +static void hvc_hangup(struct tty_struct *tty) +{ + struct hvc_struct *hp = tty->driver_data; + unsigned long flags; + int temp_open_count; + + if (!hp) + return; + + /* cancel pending tty resize work */ + cancel_work_sync(&hp->tty_resize); + + spin_lock_irqsave(&hp->lock, flags); + + /* + * The N_TTY line discipline has problems such that in a close vs + * open->hangup case this can be called after the final close so prevent + * that from happening for now. + */ + if (hp->count <= 0) { + spin_unlock_irqrestore(&hp->lock, flags); + return; + } + + temp_open_count = hp->count; + hp->count = 0; + hp->n_outbuf = 0; + hp->tty = NULL; + + spin_unlock_irqrestore(&hp->lock, flags); + + if (hp->ops->notifier_hangup) + hp->ops->notifier_hangup(hp, hp->data); + + while(temp_open_count) { + --temp_open_count; + tty_kref_put(tty); + kref_put(&hp->kref, destroy_hvc_struct); + } +} + +/* + * Push buffered characters whether they were just recently buffered or waiting + * on a blocked hypervisor. Call this function with hp->lock held. + */ +static int hvc_push(struct hvc_struct *hp) +{ + int n; + + n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); + if (n <= 0) { + if (n == 0) { + hp->do_wakeup = 1; + return 0; + } + /* throw away output on error; this happens when + there is no session connected to the vterm. */ + hp->n_outbuf = 0; + } else + hp->n_outbuf -= n; + if (hp->n_outbuf > 0) + memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf); + else + hp->do_wakeup = 1; + + return n; +} + +static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + struct hvc_struct *hp = tty->driver_data; + unsigned long flags; + int rsize, written = 0; + + /* This write was probably executed during a tty close. */ + if (!hp) + return -EPIPE; + + if (hp->count <= 0) + return -EIO; + + spin_lock_irqsave(&hp->lock, flags); + + /* Push pending writes */ + if (hp->n_outbuf > 0) + hvc_push(hp); + + while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) { + if (rsize > count) + rsize = count; + memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); + count -= rsize; + buf += rsize; + hp->n_outbuf += rsize; + written += rsize; + hvc_push(hp); + } + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * Racy, but harmless, kick thread if there is still pending data. + */ + if (hp->n_outbuf) + hvc_kick(); + + return written; +} + +/** + * hvc_set_winsz() - Resize the hvc tty terminal window. + * @work: work structure. + * + * The routine shall not be called within an atomic context because it + * might sleep. + * + * Locking: hp->lock + */ +static void hvc_set_winsz(struct work_struct *work) +{ + struct hvc_struct *hp; + unsigned long hvc_flags; + struct tty_struct *tty; + struct winsize ws; + + hp = container_of(work, struct hvc_struct, tty_resize); + + spin_lock_irqsave(&hp->lock, hvc_flags); + if (!hp->tty) { + spin_unlock_irqrestore(&hp->lock, hvc_flags); + return; + } + ws = hp->ws; + tty = tty_kref_get(hp->tty); + spin_unlock_irqrestore(&hp->lock, hvc_flags); + + tty_do_resize(tty, &ws); + tty_kref_put(tty); +} + +/* + * This is actually a contract between the driver and the tty layer outlining + * how much write room the driver can guarantee will be sent OR BUFFERED. This + * driver MUST honor the return value. + */ +static int hvc_write_room(struct tty_struct *tty) +{ + struct hvc_struct *hp = tty->driver_data; + + if (!hp) + return -1; + + return hp->outbuf_size - hp->n_outbuf; +} + +static int hvc_chars_in_buffer(struct tty_struct *tty) +{ + struct hvc_struct *hp = tty->driver_data; + + if (!hp) + return 0; + return hp->n_outbuf; +} + +/* + * timeout will vary between the MIN and MAX values defined here. By default + * and during console activity we will use a default MIN_TIMEOUT of 10. When + * the console is idle, we increase the timeout value on each pass through + * msleep until we reach the max. This may be noticeable as a brief (average + * one second) delay on the console before the console responds to input when + * there has been no input for some time. + */ +#define MIN_TIMEOUT (10) +#define MAX_TIMEOUT (2000) +static u32 timeout = MIN_TIMEOUT; + +#define HVC_POLL_READ 0x00000001 +#define HVC_POLL_WRITE 0x00000002 + +int hvc_poll(struct hvc_struct *hp) +{ + struct tty_struct *tty; + int i, n, poll_mask = 0; + char buf[N_INBUF] __ALIGNED__; + unsigned long flags; + int read_total = 0; + int written_total = 0; + + spin_lock_irqsave(&hp->lock, flags); + + /* Push pending writes */ + if (hp->n_outbuf > 0) + written_total = hvc_push(hp); + + /* Reschedule us if still some write pending */ + if (hp->n_outbuf > 0) { + poll_mask |= HVC_POLL_WRITE; + /* If hvc_push() was not able to write, sleep a few msecs */ + timeout = (written_total) ? 0 : MIN_TIMEOUT; + } + + /* No tty attached, just skip */ + tty = tty_kref_get(hp->tty); + if (tty == NULL) + goto bail; + + /* Now check if we can get data (are we throttled ?) */ + if (test_bit(TTY_THROTTLED, &tty->flags)) + goto throttled; + + /* If we aren't notifier driven and aren't throttled, we always + * request a reschedule + */ + if (!hp->irq_requested) + poll_mask |= HVC_POLL_READ; + + /* Read data if any */ + for (;;) { + int count = tty_buffer_request_room(tty, N_INBUF); + + /* If flip is full, just reschedule a later read */ + if (count == 0) { + poll_mask |= HVC_POLL_READ; + break; + } + + n = hp->ops->get_chars(hp->vtermno, buf, count); + if (n <= 0) { + /* Hangup the tty when disconnected from host */ + if (n == -EPIPE) { + spin_unlock_irqrestore(&hp->lock, flags); + tty_hangup(tty); + spin_lock_irqsave(&hp->lock, flags); + } else if ( n == -EAGAIN ) { + /* + * Some back-ends can only ensure a certain min + * num of bytes read, which may be > 'count'. + * Let the tty clear the flip buff to make room. + */ + poll_mask |= HVC_POLL_READ; + } + break; + } + for (i = 0; i < n; ++i) { +#ifdef CONFIG_MAGIC_SYSRQ + if (hp->index == hvc_console.index) { + /* Handle the SysRq Hack */ + /* XXX should support a sequence */ + if (buf[i] == '\x0f') { /* ^O */ + /* if ^O is pressed again, reset + * sysrq_pressed and flip ^O char */ + sysrq_pressed = !sysrq_pressed; + if (sysrq_pressed) + continue; + } else if (sysrq_pressed) { + handle_sysrq(buf[i]); + sysrq_pressed = 0; + continue; + } + } +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(tty, buf[i], 0); + } + + read_total += n; + } + throttled: + /* Wakeup write queue if necessary */ + if (hp->do_wakeup) { + hp->do_wakeup = 0; + tty_wakeup(tty); + } + bail: + spin_unlock_irqrestore(&hp->lock, flags); + + if (read_total) { + /* Activity is occurring, so reset the polling backoff value to + a minimum for performance. */ + timeout = MIN_TIMEOUT; + + tty_flip_buffer_push(tty); + } + if (tty) + tty_kref_put(tty); + + return poll_mask; +} +EXPORT_SYMBOL_GPL(hvc_poll); + +/** + * __hvc_resize() - Update terminal window size information. + * @hp: HVC console pointer + * @ws: Terminal window size structure + * + * Stores the specified window size information in the hvc structure of @hp. + * The function schedule the tty resize update. + * + * Locking: Locking free; the function MUST be called holding hp->lock + */ +void __hvc_resize(struct hvc_struct *hp, struct winsize ws) +{ + hp->ws = ws; + schedule_work(&hp->tty_resize); +} +EXPORT_SYMBOL_GPL(__hvc_resize); + +/* + * This kthread is either polling or interrupt driven. This is determined by + * calling hvc_poll() who determines whether a console adapter support + * interrupts. + */ +static int khvcd(void *unused) +{ + int poll_mask; + struct hvc_struct *hp; + + set_freezable(); + do { + poll_mask = 0; + hvc_kicked = 0; + try_to_freeze(); + wmb(); + if (!cpus_are_in_xmon()) { + spin_lock(&hvc_structs_lock); + list_for_each_entry(hp, &hvc_structs, next) { + poll_mask |= hvc_poll(hp); + } + spin_unlock(&hvc_structs_lock); + } else + poll_mask |= HVC_POLL_READ; + if (hvc_kicked) + continue; + set_current_state(TASK_INTERRUPTIBLE); + if (!hvc_kicked) { + if (poll_mask == 0) + schedule(); + else { + if (timeout < MAX_TIMEOUT) + timeout += (timeout >> 6) + 1; + + msleep_interruptible(timeout); + } + } + __set_current_state(TASK_RUNNING); + } while (!kthread_should_stop()); + + return 0; +} + +static const struct tty_operations hvc_ops = { + .open = hvc_open, + .close = hvc_close, + .write = hvc_write, + .hangup = hvc_hangup, + .unthrottle = hvc_unthrottle, + .write_room = hvc_write_room, + .chars_in_buffer = hvc_chars_in_buffer, +}; + +struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, + const struct hv_ops *ops, + int outbuf_size) +{ + struct hvc_struct *hp; + int i; + + /* We wait until a driver actually comes along */ + if (!hvc_driver) { + int err = hvc_init(); + if (err) + return ERR_PTR(err); + } + + hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, + GFP_KERNEL); + if (!hp) + return ERR_PTR(-ENOMEM); + + hp->vtermno = vtermno; + hp->data = data; + hp->ops = ops; + hp->outbuf_size = outbuf_size; + hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; + + kref_init(&hp->kref); + + INIT_WORK(&hp->tty_resize, hvc_set_winsz); + spin_lock_init(&hp->lock); + spin_lock(&hvc_structs_lock); + + /* + * find index to use: + * see if this vterm id matches one registered for console. + */ + for (i=0; i < MAX_NR_HVC_CONSOLES; i++) + if (vtermnos[i] == hp->vtermno && + cons_ops[i] == hp->ops) + break; + + /* no matching slot, just use a counter */ + if (i >= MAX_NR_HVC_CONSOLES) + i = ++last_hvc; + + hp->index = i; + + list_add_tail(&(hp->next), &hvc_structs); + spin_unlock(&hvc_structs_lock); + + return hp; +} +EXPORT_SYMBOL_GPL(hvc_alloc); + +int hvc_remove(struct hvc_struct *hp) +{ + unsigned long flags; + struct tty_struct *tty; + + spin_lock_irqsave(&hp->lock, flags); + tty = tty_kref_get(hp->tty); + + if (hp->index < MAX_NR_HVC_CONSOLES) + vtermnos[hp->index] = -1; + + /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ + + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * We 'put' the instance that was grabbed when the kref instance + * was initialized using kref_init(). Let the last holder of this + * kref cause it to be removed, which will probably be the tty_vhangup + * below. + */ + kref_put(&hp->kref, destroy_hvc_struct); + + /* + * This function call will auto chain call hvc_hangup. + */ + if (tty) { + tty_vhangup(tty); + tty_kref_put(tty); + } + return 0; +} +EXPORT_SYMBOL_GPL(hvc_remove); + +/* Driver initialization: called as soon as someone uses hvc_alloc(). */ +static int hvc_init(void) +{ + struct tty_driver *drv; + int err; + + /* We need more than hvc_count adapters due to hotplug additions. */ + drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); + if (!drv) { + err = -ENOMEM; + goto out; + } + + drv->owner = THIS_MODULE; + drv->driver_name = "hvc"; + drv->name = "hvc"; + drv->major = HVC_MAJOR; + drv->minor_start = HVC_MINOR; + drv->type = TTY_DRIVER_TYPE_SYSTEM; + drv->init_termios = tty_std_termios; + drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + tty_set_operations(drv, &hvc_ops); + + /* Always start the kthread because there can be hotplug vty adapters + * added later. */ + hvc_task = kthread_run(khvcd, NULL, "khvcd"); + if (IS_ERR(hvc_task)) { + printk(KERN_ERR "Couldn't create kthread for console.\n"); + err = PTR_ERR(hvc_task); + goto put_tty; + } + + err = tty_register_driver(drv); + if (err) { + printk(KERN_ERR "Couldn't register hvc console driver\n"); + goto stop_thread; + } + + /* + * Make sure tty is fully registered before allowing it to be + * found by hvc_console_device. + */ + smp_mb(); + hvc_driver = drv; + return 0; + +stop_thread: + kthread_stop(hvc_task); + hvc_task = NULL; +put_tty: + put_tty_driver(drv); +out: + return err; +} + +/* This isn't particularly necessary due to this being a console driver + * but it is nice to be thorough. + */ +static void __exit hvc_exit(void) +{ + if (hvc_driver) { + kthread_stop(hvc_task); + + tty_unregister_driver(hvc_driver); + /* return tty_struct instances allocated in hvc_init(). */ + put_tty_driver(hvc_driver); + unregister_console(&hvc_console); + } +} +module_exit(hvc_exit); diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h new file mode 100644 index 000000000000..54381eba4e4a --- /dev/null +++ b/drivers/tty/hvc/hvc_console.h @@ -0,0 +1,119 @@ +/* + * hvc_console.h + * Copyright (C) 2005 IBM Corporation + * + * Author(s): + * Ryan S. Arnold + * + * hvc_console header information: + * moved here from arch/powerpc/include/asm/hvconsole.h + * and drivers/char/hvc_console.c + * + * 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 + */ + +#ifndef HVC_CONSOLE_H +#define HVC_CONSOLE_H +#include +#include +#include + +/* + * This is the max number of console adapters that can/will be found as + * console devices on first stage console init. Any number beyond this range + * can't be used as a console device but is still a valid tty device. + */ +#define MAX_NR_HVC_CONSOLES 16 + +/* + * The Linux TTY code does not support dynamic addition of tty derived devices + * so we need to know how many tty devices we might need when space is allocated + * for the tty device. Since this driver supports hotplug of vty adapters we + * need to make sure we have enough allocated. + */ +#define HVC_ALLOC_TTY_ADAPTERS 8 + +struct hvc_struct { + spinlock_t lock; + int index; + struct tty_struct *tty; + int count; + int do_wakeup; + char *outbuf; + int outbuf_size; + int n_outbuf; + uint32_t vtermno; + const struct hv_ops *ops; + int irq_requested; + int data; + struct winsize ws; + struct work_struct tty_resize; + struct list_head next; + struct kref kref; /* ref count & hvc_struct lifetime */ +}; + +/* implemented by a low level driver */ +struct hv_ops { + int (*get_chars)(uint32_t vtermno, char *buf, int count); + int (*put_chars)(uint32_t vtermno, const char *buf, int count); + + /* Callbacks for notification. Called in open, close and hangup */ + int (*notifier_add)(struct hvc_struct *hp, int irq); + void (*notifier_del)(struct hvc_struct *hp, int irq); + void (*notifier_hangup)(struct hvc_struct *hp, int irq); +}; + +/* Register a vterm and a slot index for use as a console (console_init) */ +extern int hvc_instantiate(uint32_t vtermno, int index, + const struct hv_ops *ops); + +/* register a vterm for hvc tty operation (module_init or hotplug add) */ +extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data, + const struct hv_ops *ops, int outbuf_size); +/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ +extern int hvc_remove(struct hvc_struct *hp); + +/* data available */ +int hvc_poll(struct hvc_struct *hp); +void hvc_kick(void); + +/* Resize hvc tty terminal window */ +extern void __hvc_resize(struct hvc_struct *hp, struct winsize ws); + +static inline void hvc_resize(struct hvc_struct *hp, struct winsize ws) +{ + unsigned long flags; + + spin_lock_irqsave(&hp->lock, flags); + __hvc_resize(hp, ws); + spin_unlock_irqrestore(&hp->lock, flags); +} + +/* default notifier for irq based notification */ +extern int notifier_add_irq(struct hvc_struct *hp, int data); +extern void notifier_del_irq(struct hvc_struct *hp, int data); +extern void notifier_hangup_irq(struct hvc_struct *hp, int data); + + +#if defined(CONFIG_XMON) && defined(CONFIG_SMP) +#include +#else +static inline int cpus_are_in_xmon(void) +{ + return 0; +} +#endif + +#endif // HVC_CONSOLE_H diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c new file mode 100644 index 000000000000..6470f63deb4b --- /dev/null +++ b/drivers/tty/hvc/hvc_dcc.c @@ -0,0 +1,133 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "hvc_console.h" + +/* DCC Status Bits */ +#define DCC_STATUS_RX (1 << 30) +#define DCC_STATUS_TX (1 << 29) + +static inline u32 __dcc_getstatus(void) +{ + u32 __ret; + + asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg" + : "=r" (__ret) : : "cc"); + + return __ret; +} + + +#if defined(CONFIG_CPU_V7) +static inline char __dcc_getchar(void) +{ + char __c; + + asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\ + bne get_wait \n\ + mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" + : "=r" (__c) : : "cc"); + + return __c; +} +#else +static inline char __dcc_getchar(void) +{ + char __c; + + asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" + : "=r" (__c)); + + return __c; +} +#endif + +#if defined(CONFIG_CPU_V7) +static inline void __dcc_putchar(char c) +{ + asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\ + bcs put_wait \n\ + mcr p14, 0, %0, c0, c5, 0 " + : : "r" (c) : "cc"); +} +#else +static inline void __dcc_putchar(char c) +{ + asm("mcr p14, 0, %0, c0, c5, 0 @ write a char" + : /* no output register */ + : "r" (c)); +} +#endif + +static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) +{ + int i; + + for (i = 0; i < count; i++) { + while (__dcc_getstatus() & DCC_STATUS_TX) + cpu_relax(); + + __dcc_putchar((char)(buf[i] & 0xFF)); + } + + return count; +} + +static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count) +{ + int i; + + for (i = 0; i < count; ++i) { + int c = -1; + + if (__dcc_getstatus() & DCC_STATUS_RX) + c = __dcc_getchar(); + if (c < 0) + break; + buf[i] = c; + } + + return i; +} + +static const struct hv_ops hvc_dcc_get_put_ops = { + .get_chars = hvc_dcc_get_chars, + .put_chars = hvc_dcc_put_chars, +}; + +static int __init hvc_dcc_console_init(void) +{ + hvc_instantiate(0, 0, &hvc_dcc_get_put_ops); + return 0; +} +console_initcall(hvc_dcc_console_init); + +static int __init hvc_dcc_init(void) +{ + hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128); + return 0; +} +device_initcall(hvc_dcc_init); diff --git a/drivers/tty/hvc/hvc_irq.c b/drivers/tty/hvc/hvc_irq.c new file mode 100644 index 000000000000..2623e177e8d6 --- /dev/null +++ b/drivers/tty/hvc/hvc_irq.c @@ -0,0 +1,49 @@ +/* + * Copyright IBM Corp. 2001,2008 + * + * This file contains the IRQ specific code for hvc_console + * + */ + +#include + +#include "hvc_console.h" + +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) +{ + /* if hvc_poll request a repoll, then kick the hvcd thread */ + if (hvc_poll(dev_instance)) + hvc_kick(); + return IRQ_HANDLED; +} + +/* + * For IRQ based systems these callbacks can be used + */ +int notifier_add_irq(struct hvc_struct *hp, int irq) +{ + int rc; + + if (!irq) { + hp->irq_requested = 0; + return 0; + } + rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, + "hvc_console", hp); + if (!rc) + hp->irq_requested = 1; + return rc; +} + +void notifier_del_irq(struct hvc_struct *hp, int irq) +{ + if (!hp->irq_requested) + return; + free_irq(irq, hp); + hp->irq_requested = 0; +} + +void notifier_hangup_irq(struct hvc_struct *hp, int irq) +{ + notifier_del_irq(hp, irq); +} diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c new file mode 100644 index 000000000000..21c54955084e --- /dev/null +++ b/drivers/tty/hvc/hvc_iseries.c @@ -0,0 +1,598 @@ +/* + * iSeries vio driver interface to hvc_console.c + * + * This code is based heavily on hvc_vio.c and viocons.c + * + * Copyright (C) 2006 Stephen Rothwell, IBM Corporation + * + * 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 +#include +#include +#include + +#include "hvc_console.h" + +#define VTTY_PORTS 10 + +static DEFINE_SPINLOCK(consolelock); +static DEFINE_SPINLOCK(consoleloglock); + +static const char hvc_driver_name[] = "hvc_console"; + +#define IN_BUF_SIZE 200 + +/* + * Our port information. + */ +static struct port_info { + HvLpIndex lp; + u64 seq; /* sequence number of last HV send */ + u64 ack; /* last ack from HV */ + struct hvc_struct *hp; + int in_start; + int in_end; + unsigned char in_buf[IN_BUF_SIZE]; +} port_info[VTTY_PORTS] = { + [ 0 ... VTTY_PORTS - 1 ] = { + .lp = HvLpIndexInvalid + } +}; + +#define viochar_is_console(pi) ((pi) == &port_info[0]) + +static struct vio_device_id hvc_driver_table[] __devinitdata = { + {"serial", "IBM,iSeries-vty"}, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + +static void hvlog(char *fmt, ...) +{ + int i; + unsigned long flags; + va_list args; + static char buf[256]; + + spin_lock_irqsave(&consoleloglock, flags); + va_start(args, fmt); + i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); + va_end(args); + buf[i++] = '\r'; + HvCall_writeLogBuffer(buf, i); + spin_unlock_irqrestore(&consoleloglock, flags); +} + +/* + * Initialize the common fields in a charLpEvent + */ +static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp) +{ + struct HvLpEvent *hev = &viochar->event; + + memset(viochar, 0, sizeof(struct viocharlpevent)); + + hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | + HV_LP_EVENT_INT; + hev->xType = HvLpEvent_Type_VirtualIo; + hev->xSubtype = viomajorsubtype_chario | viochardata; + hev->xSourceLp = HvLpConfig_getLpIndex(); + hev->xTargetLp = lp; + hev->xSizeMinus1 = sizeof(struct viocharlpevent); + hev->xSourceInstanceId = viopath_sourceinst(lp); + hev->xTargetInstanceId = viopath_targetinst(lp); +} + +static int get_chars(uint32_t vtermno, char *buf, int count) +{ + struct port_info *pi; + int n = 0; + unsigned long flags; + + if (vtermno >= VTTY_PORTS) + return -EINVAL; + if (count == 0) + return 0; + + pi = &port_info[vtermno]; + spin_lock_irqsave(&consolelock, flags); + + if (pi->in_end == 0) + goto done; + + n = pi->in_end - pi->in_start; + if (n > count) + n = count; + memcpy(buf, &pi->in_buf[pi->in_start], n); + pi->in_start += n; + if (pi->in_start == pi->in_end) { + pi->in_start = 0; + pi->in_end = 0; + } +done: + spin_unlock_irqrestore(&consolelock, flags); + return n; +} + +static int put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct viocharlpevent *viochar; + struct port_info *pi; + HvLpEvent_Rc hvrc; + unsigned long flags; + int sent = 0; + + if (vtermno >= VTTY_PORTS) + return -EINVAL; + + pi = &port_info[vtermno]; + + spin_lock_irqsave(&consolelock, flags); + + if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) { + HvCall_writeLogBuffer(buf, count); + sent = count; + goto done; + } + + viochar = vio_get_event_buffer(viomajorsubtype_chario); + if (viochar == NULL) { + hvlog("\n\rviocons: Can't get viochar buffer."); + goto done; + } + + while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { + int len; + + len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count; + + if (viochar_is_console(pi)) + HvCall_writeLogBuffer(buf, len); + + init_data_event(viochar, pi->lp); + + viochar->len = len; + viochar->event.xCorrelationToken = pi->seq++; + viochar->event.xSizeMinus1 = + offsetof(struct viocharlpevent, data) + len; + + memcpy(viochar->data, buf, len); + + hvrc = HvCallEvent_signalLpEvent(&viochar->event); + if (hvrc) + hvlog("\n\rerror sending event! return code %d\n\r", + (int)hvrc); + sent += len; + count -= len; + buf += len; + } + + vio_free_event_buffer(viomajorsubtype_chario, viochar); +done: + spin_unlock_irqrestore(&consolelock, flags); + return sent; +} + +static const struct hv_ops hvc_get_put_ops = { + .get_chars = get_chars, + .put_chars = put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int __devinit hvc_vio_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct hvc_struct *hp; + struct port_info *pi; + + /* probed with invalid parameters. */ + if (!vdev || !id) + return -EPERM; + + if (vdev->unit_address >= VTTY_PORTS) + return -ENODEV; + + pi = &port_info[vdev->unit_address]; + + hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, + VIOCHAR_MAX_DATA); + if (IS_ERR(hp)) + return PTR_ERR(hp); + pi->hp = hp; + dev_set_drvdata(&vdev->dev, pi); + + return 0; +} + +static int __devexit hvc_vio_remove(struct vio_dev *vdev) +{ + struct port_info *pi = dev_get_drvdata(&vdev->dev); + struct hvc_struct *hp = pi->hp; + + return hvc_remove(hp); +} + +static struct vio_driver hvc_vio_driver = { + .id_table = hvc_driver_table, + .probe = hvc_vio_probe, + .remove = __devexit_p(hvc_vio_remove), + .driver = { + .name = hvc_driver_name, + .owner = THIS_MODULE, + } +}; + +static void hvc_open_event(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + u8 port = cevent->virtual_device; + struct port_info *pi; + int reject = 0; + + if (hvlpevent_is_ack(event)) { + if (port >= VTTY_PORTS) + return; + + spin_lock_irqsave(&consolelock, flags); + + pi = &port_info[port]; + if (event->xRc == HvLpEvent_Rc_Good) { + pi->seq = pi->ack = 0; + /* + * This line allows connections from the primary + * partition but once one is connected from the + * primary partition nothing short of a reboot + * of linux will allow access from the hosting + * partition again without a required iSeries fix. + */ + pi->lp = event->xTargetLp; + } + + spin_unlock_irqrestore(&consolelock, flags); + if (event->xRc != HvLpEvent_Rc_Good) + printk(KERN_WARNING + "hvc: handle_open_event: event->xRc == (%d).\n", + event->xRc); + + if (event->xCorrelationToken != 0) { + atomic_t *aptr= (atomic_t *)event->xCorrelationToken; + atomic_set(aptr, 1); + } else + printk(KERN_WARNING + "hvc: weird...got open ack without atomic\n"); + return; + } + + /* This had better require an ack, otherwise complain */ + if (!hvlpevent_need_ack(event)) { + printk(KERN_WARNING "hvc: viocharopen without ack bit!\n"); + return; + } + + spin_lock_irqsave(&consolelock, flags); + + /* Make sure this is a good virtual tty */ + if (port >= VTTY_PORTS) { + event->xRc = HvLpEvent_Rc_SubtypeError; + cevent->subtype_result_code = viorc_openRejected; + /* + * Flag state here since we can't printk while holding + * the consolelock spinlock. + */ + reject = 1; + } else { + pi = &port_info[port]; + if ((pi->lp != HvLpIndexInvalid) && + (pi->lp != event->xSourceLp)) { + /* + * If this is tty is already connected to a different + * partition, fail. + */ + event->xRc = HvLpEvent_Rc_SubtypeError; + cevent->subtype_result_code = viorc_openRejected; + reject = 2; + } else { + pi->lp = event->xSourceLp; + event->xRc = HvLpEvent_Rc_Good; + cevent->subtype_result_code = viorc_good; + pi->seq = pi->ack = 0; + } + } + + spin_unlock_irqrestore(&consolelock, flags); + + if (reject == 1) + printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n"); + else if (reject == 2) + printk(KERN_WARNING "hvc: open rejected: console in exclusive " + "use by another partition.\n"); + + /* Return the acknowledgement */ + HvCallEvent_ackLpEvent(event); +} + +/* + * Handle a close charLpEvent. This should ONLY be an Interrupt because the + * virtual console should never actually issue a close event to the hypervisor + * because the virtual console never goes away. A close event coming from the + * hypervisor simply means that there are no client consoles connected to the + * virtual console. + */ +static void hvc_close_event(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + u8 port = cevent->virtual_device; + + if (!hvlpevent_is_int(event)) { + printk(KERN_WARNING + "hvc: got unexpected close acknowledgement\n"); + return; + } + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING + "hvc: close message from invalid virtual device.\n"); + return; + } + + /* For closes, just mark the console partition invalid */ + spin_lock_irqsave(&consolelock, flags); + + if (port_info[port].lp == event->xSourceLp) + port_info[port].lp = HvLpIndexInvalid; + + spin_unlock_irqrestore(&consolelock, flags); +} + +static void hvc_data_event(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + struct port_info *pi; + int n; + u8 port = cevent->virtual_device; + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING "hvc: data on invalid virtual device %d\n", + port); + return; + } + if (cevent->len == 0) + return; + + /* + * Change 05/01/2003 - Ryan Arnold: If a partition other than + * the current exclusive partition tries to send us data + * events then just drop them on the floor because we don't + * want his stinking data. He isn't authorized to receive + * data because he wasn't the first one to get the console, + * therefore he shouldn't be allowed to send data either. + * This will work without an iSeries fix. + */ + pi = &port_info[port]; + if (pi->lp != event->xSourceLp) + return; + + spin_lock_irqsave(&consolelock, flags); + + n = IN_BUF_SIZE - pi->in_end; + if (n > cevent->len) + n = cevent->len; + if (n > 0) { + memcpy(&pi->in_buf[pi->in_end], cevent->data, n); + pi->in_end += n; + } + spin_unlock_irqrestore(&consolelock, flags); + if (n == 0) + printk(KERN_WARNING "hvc: input buffer overflow\n"); +} + +static void hvc_ack_event(struct HvLpEvent *event) +{ + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + unsigned long flags; + u8 port = cevent->virtual_device; + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING "hvc: data on invalid virtual device\n"); + return; + } + + spin_lock_irqsave(&consolelock, flags); + port_info[port].ack = event->xCorrelationToken; + spin_unlock_irqrestore(&consolelock, flags); +} + +static void hvc_config_event(struct HvLpEvent *event) +{ + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + + if (cevent->data[0] == 0x01) + printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n", + cevent->data[1], cevent->data[2], + cevent->data[3], cevent->data[4]); + else + printk(KERN_WARNING "hvc: unknown config event\n"); +} + +static void hvc_handle_event(struct HvLpEvent *event) +{ + int charminor; + + if (event == NULL) + return; + + charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; + switch (charminor) { + case viocharopen: + hvc_open_event(event); + break; + case viocharclose: + hvc_close_event(event); + break; + case viochardata: + hvc_data_event(event); + break; + case viocharack: + hvc_ack_event(event); + break; + case viocharconfig: + hvc_config_event(event); + break; + default: + if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static int __init send_open(HvLpIndex remoteLp, void *sem) +{ + return HvCallEvent_signalLpEventFast(remoteLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_chario | viocharopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(remoteLp), + viopath_targetinst(remoteLp), + (u64)(unsigned long)sem, VIOVERSION << 16, + 0, 0, 0, 0); +} + +static int __init hvc_vio_init(void) +{ + atomic_t wait_flag; + int rc; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -EIO; + + /* +2 for fudge */ + rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), + viomajorsubtype_chario, VIOCHAR_WINDOW + 2); + if (rc) + printk(KERN_WARNING "hvc: error opening to primary %d\n", rc); + + if (viopath_hostLp == HvLpIndexInvalid) + vio_set_hostlp(); + + /* + * And if the primary is not the same as the hosting LP, open to the + * hosting lp + */ + if ((viopath_hostLp != HvLpIndexInvalid) && + (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { + printk(KERN_INFO "hvc: open path to hosting (%d)\n", + viopath_hostLp); + rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, + VIOCHAR_WINDOW + 2); /* +2 for fudge */ + if (rc) + printk(KERN_WARNING + "error opening to partition %d: %d\n", + viopath_hostLp, rc); + } + + if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0) + printk(KERN_WARNING + "hvc: error seting handler for console events!\n"); + + /* + * First, try to open the console to the hosting lp. + * Wait on a semaphore for the response. + */ + atomic_set(&wait_flag, 0); + if ((viopath_isactive(viopath_hostLp)) && + (send_open(viopath_hostLp, &wait_flag) == 0)) { + printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp); + while (atomic_read(&wait_flag) == 0) + mb(); + atomic_set(&wait_flag, 0); + } + + /* + * If we don't have an active console, try the primary + */ + if ((!viopath_isactive(port_info[0].lp)) && + (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && + (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) { + printk(KERN_INFO "hvc: opening console to primary partition\n"); + while (atomic_read(&wait_flag) == 0) + mb(); + } + + /* Register as a vio device to receive callbacks */ + rc = vio_register_driver(&hvc_vio_driver); + + return rc; +} +module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ + +static void __exit hvc_vio_exit(void) +{ + vio_unregister_driver(&hvc_vio_driver); +} +module_exit(hvc_vio_exit); + +/* the device tree order defines our numbering */ +static int __init hvc_find_vtys(void) +{ + struct device_node *vty; + int num_found = 0; + + for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; + vty = of_find_node_by_name(vty, "vty")) { + const uint32_t *vtermno; + + /* We have statically defined space for only a certain number + * of console adapters. + */ + if ((num_found >= MAX_NR_HVC_CONSOLES) || + (num_found >= VTTY_PORTS)) { + of_node_put(vty); + break; + } + + vtermno = of_get_property(vty, "reg", NULL); + if (!vtermno) + continue; + + if (!of_device_is_compatible(vty, "IBM,iSeries-vty")) + continue; + + if (num_found == 0) + add_preferred_console("hvc", 0, NULL); + hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); + ++num_found; + } + + return num_found; +} +console_initcall(hvc_find_vtys); diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c new file mode 100644 index 000000000000..c3425bb3a1f6 --- /dev/null +++ b/drivers/tty/hvc/hvc_iucv.c @@ -0,0 +1,1337 @@ +/* + * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver + * + * This HVC device driver provides terminal access using + * z/VM IUCV communication paths. + * + * Copyright IBM Corp. 2008, 2009 + * + * Author(s): Hendrik Brueckner + */ +#define KMSG_COMPONENT "hvc_iucv" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hvc_console.h" + + +/* General device driver settings */ +#define HVC_IUCV_MAGIC 0xc9e4c3e5 +#define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS +#define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) + +/* IUCV TTY message */ +#define MSG_VERSION 0x02 /* Message version */ +#define MSG_TYPE_ERROR 0x01 /* Error message */ +#define MSG_TYPE_TERMENV 0x02 /* Terminal environment variable */ +#define MSG_TYPE_TERMIOS 0x04 /* Terminal IO struct update */ +#define MSG_TYPE_WINSIZE 0x08 /* Terminal window size update */ +#define MSG_TYPE_DATA 0x10 /* Terminal data */ + +struct iucv_tty_msg { + u8 version; /* Message version */ + u8 type; /* Message type */ +#define MSG_MAX_DATALEN ((u16)(~0)) + u16 datalen; /* Payload length */ + u8 data[]; /* Payload buffer */ +} __attribute__((packed)); +#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data)) + +enum iucv_state_t { + IUCV_DISCONN = 0, + IUCV_CONNECTED = 1, + IUCV_SEVERED = 2, +}; + +enum tty_state_t { + TTY_CLOSED = 0, + TTY_OPENED = 1, +}; + +struct hvc_iucv_private { + struct hvc_struct *hvc; /* HVC struct reference */ + u8 srv_name[8]; /* IUCV service name (ebcdic) */ + unsigned char is_console; /* Linux console usage flag */ + enum iucv_state_t iucv_state; /* IUCV connection status */ + enum tty_state_t tty_state; /* TTY status */ + struct iucv_path *path; /* IUCV path pointer */ + spinlock_t lock; /* hvc_iucv_private lock */ +#define SNDBUF_SIZE (PAGE_SIZE) /* must be < MSG_MAX_DATALEN */ + void *sndbuf; /* send buffer */ + size_t sndbuf_len; /* length of send buffer */ +#define QUEUE_SNDBUF_DELAY (HZ / 25) + struct delayed_work sndbuf_work; /* work: send iucv msg(s) */ + wait_queue_head_t sndbuf_waitq; /* wait for send completion */ + struct list_head tty_outqueue; /* outgoing IUCV messages */ + struct list_head tty_inqueue; /* incoming IUCV messages */ + struct device *dev; /* device structure */ +}; + +struct iucv_tty_buffer { + struct list_head list; /* list pointer */ + struct iucv_message msg; /* store an IUCV message */ + size_t offset; /* data buffer offset */ + struct iucv_tty_msg *mbuf; /* buffer to store input/output data */ +}; + +/* IUCV callback handler */ +static int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]); +static void hvc_iucv_path_severed(struct iucv_path *, u8[16]); +static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *); +static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *); + + +/* Kernel module parameter: use one terminal device as default */ +static unsigned long hvc_iucv_devices = 1; + +/* Array of allocated hvc iucv tty lines... */ +static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; +#define IUCV_HVC_CON_IDX (0) +/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */ +#define MAX_VMID_FILTER (500) +static size_t hvc_iucv_filter_size; +static void *hvc_iucv_filter; +static const char *hvc_iucv_filter_string; +static DEFINE_RWLOCK(hvc_iucv_filter_lock); + +/* Kmem cache and mempool for iucv_tty_buffer elements */ +static struct kmem_cache *hvc_iucv_buffer_cache; +static mempool_t *hvc_iucv_mempool; + +/* IUCV handler callback functions */ +static struct iucv_handler hvc_iucv_handler = { + .path_pending = hvc_iucv_path_pending, + .path_severed = hvc_iucv_path_severed, + .message_complete = hvc_iucv_msg_complete, + .message_pending = hvc_iucv_msg_pending, +}; + + +/** + * hvc_iucv_get_private() - Return a struct hvc_iucv_private instance. + * @num: The HVC virtual terminal number (vtermno) + * + * This function returns the struct hvc_iucv_private instance that corresponds + * to the HVC virtual terminal number specified as parameter @num. + */ +struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) +{ + if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) + return NULL; + return hvc_iucv_table[num - HVC_IUCV_MAGIC]; +} + +/** + * alloc_tty_buffer() - Return a new struct iucv_tty_buffer element. + * @size: Size of the internal buffer used to store data. + * @flags: Memory allocation flags passed to mempool. + * + * This function allocates a new struct iucv_tty_buffer element and, optionally, + * allocates an internal data buffer with the specified size @size. + * The internal data buffer is always allocated with GFP_DMA which is + * required for receiving and sending data with IUCV. + * Note: The total message size arises from the internal buffer size and the + * members of the iucv_tty_msg structure. + * The function returns NULL if memory allocation has failed. + */ +static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) +{ + struct iucv_tty_buffer *bufp; + + bufp = mempool_alloc(hvc_iucv_mempool, flags); + if (!bufp) + return NULL; + memset(bufp, 0, sizeof(*bufp)); + + if (size > 0) { + bufp->msg.length = MSG_SIZE(size); + bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA); + if (!bufp->mbuf) { + mempool_free(bufp, hvc_iucv_mempool); + return NULL; + } + bufp->mbuf->version = MSG_VERSION; + bufp->mbuf->type = MSG_TYPE_DATA; + bufp->mbuf->datalen = (u16) size; + } + return bufp; +} + +/** + * destroy_tty_buffer() - destroy struct iucv_tty_buffer element. + * @bufp: Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL. + */ +static void destroy_tty_buffer(struct iucv_tty_buffer *bufp) +{ + kfree(bufp->mbuf); + mempool_free(bufp, hvc_iucv_mempool); +} + +/** + * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element. + * @list: List containing struct iucv_tty_buffer elements. + */ +static void destroy_tty_buffer_list(struct list_head *list) +{ + struct iucv_tty_buffer *ent, *next; + + list_for_each_entry_safe(ent, next, list, list) { + list_del(&ent->list); + destroy_tty_buffer(ent); + } +} + +/** + * hvc_iucv_write() - Receive IUCV message & write data to HVC buffer. + * @priv: Pointer to struct hvc_iucv_private + * @buf: HVC buffer for writing received terminal data. + * @count: HVC buffer size. + * @has_more_data: Pointer to an int variable. + * + * The function picks up pending messages from the input queue and receives + * the message data that is then written to the specified buffer @buf. + * If the buffer size @count is less than the data message size, the + * message is kept on the input queue and @has_more_data is set to 1. + * If all message data has been written, the message is removed from + * the input queue. + * + * The function returns the number of bytes written to the terminal, zero if + * there are no pending data messages available or if there is no established + * IUCV path. + * If the IUCV path has been severed, then -EPIPE is returned to cause a + * hang up (that is issued by the HVC layer). + */ +static int hvc_iucv_write(struct hvc_iucv_private *priv, + char *buf, int count, int *has_more_data) +{ + struct iucv_tty_buffer *rb; + int written; + int rc; + + /* immediately return if there is no IUCV connection */ + if (priv->iucv_state == IUCV_DISCONN) + return 0; + + /* if the IUCV path has been severed, return -EPIPE to inform the + * HVC layer to hang up the tty device. */ + if (priv->iucv_state == IUCV_SEVERED) + return -EPIPE; + + /* check if there are pending messages */ + if (list_empty(&priv->tty_inqueue)) + return 0; + + /* receive an iucv message and flip data to the tty (ldisc) */ + rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list); + + written = 0; + if (!rb->mbuf) { /* message not yet received ... */ + /* allocate mem to store msg data; if no memory is available + * then leave the buffer on the list and re-try later */ + rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA); + if (!rb->mbuf) + return -ENOMEM; + + rc = __iucv_message_receive(priv->path, &rb->msg, 0, + rb->mbuf, rb->msg.length, NULL); + switch (rc) { + case 0: /* Successful */ + break; + case 2: /* No message found */ + case 9: /* Message purged */ + break; + default: + written = -EIO; + } + /* remove buffer if an error has occured or received data + * is not correct */ + if (rc || (rb->mbuf->version != MSG_VERSION) || + (rb->msg.length != MSG_SIZE(rb->mbuf->datalen))) + goto out_remove_buffer; + } + + switch (rb->mbuf->type) { + case MSG_TYPE_DATA: + written = min_t(int, rb->mbuf->datalen - rb->offset, count); + memcpy(buf, rb->mbuf->data + rb->offset, written); + if (written < (rb->mbuf->datalen - rb->offset)) { + rb->offset += written; + *has_more_data = 1; + goto out_written; + } + break; + + case MSG_TYPE_WINSIZE: + if (rb->mbuf->datalen != sizeof(struct winsize)) + break; + /* The caller must ensure that the hvc is locked, which + * is the case when called from hvc_iucv_get_chars() */ + __hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data)); + break; + + case MSG_TYPE_ERROR: /* ignored ... */ + case MSG_TYPE_TERMENV: /* ignored ... */ + case MSG_TYPE_TERMIOS: /* ignored ... */ + break; + } + +out_remove_buffer: + list_del(&rb->list); + destroy_tty_buffer(rb); + *has_more_data = !list_empty(&priv->tty_inqueue); + +out_written: + return written; +} + +/** + * hvc_iucv_get_chars() - HVC get_chars operation. + * @vtermno: HVC virtual terminal number. + * @buf: Pointer to a buffer to store data + * @count: Size of buffer available for writing + * + * The HVC thread calls this method to read characters from the back-end. + * If an IUCV communication path has been established, pending IUCV messages + * are received and data is copied into buffer @buf up to @count bytes. + * + * Locking: The routine gets called under an irqsave() spinlock; and + * the routine locks the struct hvc_iucv_private->lock to call + * helper functions. + */ +static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count) +{ + struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); + int written; + int has_more_data; + + if (count <= 0) + return 0; + + if (!priv) + return -ENODEV; + + spin_lock(&priv->lock); + has_more_data = 0; + written = hvc_iucv_write(priv, buf, count, &has_more_data); + spin_unlock(&priv->lock); + + /* if there are still messages on the queue... schedule another run */ + if (has_more_data) + hvc_kick(); + + return written; +} + +/** + * hvc_iucv_queue() - Buffer terminal data for sending. + * @priv: Pointer to struct hvc_iucv_private instance. + * @buf: Buffer containing data to send. + * @count: Size of buffer and amount of data to send. + * + * The function queues data for sending. To actually send the buffered data, + * a work queue function is scheduled (with QUEUE_SNDBUF_DELAY). + * The function returns the number of data bytes that has been buffered. + * + * If the device is not connected, data is ignored and the function returns + * @count. + * If the buffer is full, the function returns 0. + * If an existing IUCV communicaton path has been severed, -EPIPE is returned + * (that can be passed to HVC layer to cause a tty hangup). + */ +static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf, + int count) +{ + size_t len; + + if (priv->iucv_state == IUCV_DISCONN) + return count; /* ignore data */ + + if (priv->iucv_state == IUCV_SEVERED) + return -EPIPE; + + len = min_t(size_t, count, SNDBUF_SIZE - priv->sndbuf_len); + if (!len) + return 0; + + memcpy(priv->sndbuf + priv->sndbuf_len, buf, len); + priv->sndbuf_len += len; + + if (priv->iucv_state == IUCV_CONNECTED) + schedule_delayed_work(&priv->sndbuf_work, QUEUE_SNDBUF_DELAY); + + return len; +} + +/** + * hvc_iucv_send() - Send an IUCV message containing terminal data. + * @priv: Pointer to struct hvc_iucv_private instance. + * + * If an IUCV communication path has been established, the buffered output data + * is sent via an IUCV message and the number of bytes sent is returned. + * Returns 0 if there is no established IUCV communication path or + * -EPIPE if an existing IUCV communicaton path has been severed. + */ +static int hvc_iucv_send(struct hvc_iucv_private *priv) +{ + struct iucv_tty_buffer *sb; + int rc, len; + + if (priv->iucv_state == IUCV_SEVERED) + return -EPIPE; + + if (priv->iucv_state == IUCV_DISCONN) + return -EIO; + + if (!priv->sndbuf_len) + return 0; + + /* allocate internal buffer to store msg data and also compute total + * message length */ + sb = alloc_tty_buffer(priv->sndbuf_len, GFP_ATOMIC); + if (!sb) + return -ENOMEM; + + memcpy(sb->mbuf->data, priv->sndbuf, priv->sndbuf_len); + sb->mbuf->datalen = (u16) priv->sndbuf_len; + sb->msg.length = MSG_SIZE(sb->mbuf->datalen); + + list_add_tail(&sb->list, &priv->tty_outqueue); + + rc = __iucv_message_send(priv->path, &sb->msg, 0, 0, + (void *) sb->mbuf, sb->msg.length); + if (rc) { + /* drop the message here; however we might want to handle + * 0x03 (msg limit reached) by trying again... */ + list_del(&sb->list); + destroy_tty_buffer(sb); + } + len = priv->sndbuf_len; + priv->sndbuf_len = 0; + + return len; +} + +/** + * hvc_iucv_sndbuf_work() - Send buffered data over IUCV + * @work: Work structure. + * + * This work queue function sends buffered output data over IUCV and, + * if not all buffered data could be sent, reschedules itself. + */ +static void hvc_iucv_sndbuf_work(struct work_struct *work) +{ + struct hvc_iucv_private *priv; + + priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work); + if (!priv) + return; + + spin_lock_bh(&priv->lock); + hvc_iucv_send(priv); + spin_unlock_bh(&priv->lock); +} + +/** + * hvc_iucv_put_chars() - HVC put_chars operation. + * @vtermno: HVC virtual terminal number. + * @buf: Pointer to an buffer to read data from + * @count: Size of buffer available for reading + * + * The HVC thread calls this method to write characters to the back-end. + * The function calls hvc_iucv_queue() to queue terminal data for sending. + * + * Locking: The method gets called under an irqsave() spinlock; and + * locks struct hvc_iucv_private->lock. + */ +static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); + int queued; + + if (count <= 0) + return 0; + + if (!priv) + return -ENODEV; + + spin_lock(&priv->lock); + queued = hvc_iucv_queue(priv, buf, count); + spin_unlock(&priv->lock); + + return queued; +} + +/** + * hvc_iucv_notifier_add() - HVC notifier for opening a TTY for the first time. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): the index of an struct + * hvc_iucv_private instance. + * + * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private + * instance that is derived from @id. Always returns 0. + * + * Locking: struct hvc_iucv_private->lock, spin_lock_bh + */ +static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id) +{ + struct hvc_iucv_private *priv; + + priv = hvc_iucv_get_private(id); + if (!priv) + return 0; + + spin_lock_bh(&priv->lock); + priv->tty_state = TTY_OPENED; + spin_unlock_bh(&priv->lock); + + return 0; +} + +/** + * hvc_iucv_cleanup() - Clean up and reset a z/VM IUCV HVC instance. + * @priv: Pointer to the struct hvc_iucv_private instance. + */ +static void hvc_iucv_cleanup(struct hvc_iucv_private *priv) +{ + destroy_tty_buffer_list(&priv->tty_outqueue); + destroy_tty_buffer_list(&priv->tty_inqueue); + + priv->tty_state = TTY_CLOSED; + priv->iucv_state = IUCV_DISCONN; + + priv->sndbuf_len = 0; +} + +/** + * tty_outqueue_empty() - Test if the tty outq is empty + * @priv: Pointer to struct hvc_iucv_private instance. + */ +static inline int tty_outqueue_empty(struct hvc_iucv_private *priv) +{ + int rc; + + spin_lock_bh(&priv->lock); + rc = list_empty(&priv->tty_outqueue); + spin_unlock_bh(&priv->lock); + + return rc; +} + +/** + * flush_sndbuf_sync() - Flush send buffer and wait for completion + * @priv: Pointer to struct hvc_iucv_private instance. + * + * The routine cancels a pending sndbuf work, calls hvc_iucv_send() + * to flush any buffered terminal output data and waits for completion. + */ +static void flush_sndbuf_sync(struct hvc_iucv_private *priv) +{ + int sync_wait; + + cancel_delayed_work_sync(&priv->sndbuf_work); + + spin_lock_bh(&priv->lock); + hvc_iucv_send(priv); /* force sending buffered data */ + sync_wait = !list_empty(&priv->tty_outqueue); /* anything queued ? */ + spin_unlock_bh(&priv->lock); + + if (sync_wait) + wait_event_timeout(priv->sndbuf_waitq, + tty_outqueue_empty(priv), HZ/10); +} + +/** + * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up + * @priv: Pointer to hvc_iucv_private structure + * + * This routine severs an existing IUCV communication path and hangs + * up the underlying HVC terminal device. + * The hang-up occurs only if an IUCV communication path is established; + * otherwise there is no need to hang up the terminal device. + * + * The IUCV HVC hang-up is separated into two steps: + * 1. After the IUCV path has been severed, the iucv_state is set to + * IUCV_SEVERED. + * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the + * IUCV_SEVERED state causes the tty hang-up in the HVC layer. + * + * If the tty has not yet been opened, clean up the hvc_iucv_private + * structure to allow re-connects. + * If the tty has been opened, let get_chars() return -EPIPE to signal + * the HVC layer to hang up the tty and, if so, wake up the HVC thread + * to call get_chars()... + * + * Special notes on hanging up a HVC terminal instantiated as console: + * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops) + * 2. do_tty_hangup() calls tty->ops->close() for console_filp + * => no hangup notifier is called by HVC (default) + * 2. hvc_close() returns because of tty_hung_up_p(filp) + * => no delete notifier is called! + * Finally, the back-end is not being notified, thus, the tty session is + * kept active (TTY_OPEN) to be ready for re-connects. + * + * Locking: spin_lock(&priv->lock) w/o disabling bh + */ +static void hvc_iucv_hangup(struct hvc_iucv_private *priv) +{ + struct iucv_path *path; + + path = NULL; + spin_lock(&priv->lock); + if (priv->iucv_state == IUCV_CONNECTED) { + path = priv->path; + priv->path = NULL; + priv->iucv_state = IUCV_SEVERED; + if (priv->tty_state == TTY_CLOSED) + hvc_iucv_cleanup(priv); + else + /* console is special (see above) */ + if (priv->is_console) { + hvc_iucv_cleanup(priv); + priv->tty_state = TTY_OPENED; + } else + hvc_kick(); + } + spin_unlock(&priv->lock); + + /* finally sever path (outside of priv->lock due to lock ordering) */ + if (path) { + iucv_path_sever(path, NULL); + iucv_path_free(path); + } +} + +/** + * hvc_iucv_notifier_hangup() - HVC notifier for TTY hangups. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): + * the index of an struct hvc_iucv_private instance. + * + * This routine notifies the HVC back-end that a tty hangup (carrier loss, + * virtual or otherwise) has occured. + * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup()) + * to keep an existing IUCV communication path established. + * (Background: vhangup() is called from user space (by getty or login) to + * disable writing to the tty by other applications). + * If the tty has been opened and an established IUCV path has been severed + * (we caused the tty hangup), the function calls hvc_iucv_cleanup(). + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) +{ + struct hvc_iucv_private *priv; + + priv = hvc_iucv_get_private(id); + if (!priv) + return; + + flush_sndbuf_sync(priv); + + spin_lock_bh(&priv->lock); + /* NOTE: If the hangup was scheduled by ourself (from the iucv + * path_servered callback [IUCV_SEVERED]), we have to clean up + * our structure and to set state to TTY_CLOSED. + * If the tty was hung up otherwise (e.g. vhangup()), then we + * ignore this hangup and keep an established IUCV path open... + * (...the reason is that we are not able to connect back to the + * client if we disconnect on hang up) */ + priv->tty_state = TTY_CLOSED; + + if (priv->iucv_state == IUCV_SEVERED) + hvc_iucv_cleanup(priv); + spin_unlock_bh(&priv->lock); +} + +/** + * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): + * the index of an struct hvc_iucv_private instance. + * + * This routine notifies the HVC back-end that the last tty device fd has been + * closed. The function calls hvc_iucv_cleanup() to clean up the struct + * hvc_iucv_private instance. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) +{ + struct hvc_iucv_private *priv; + struct iucv_path *path; + + priv = hvc_iucv_get_private(id); + if (!priv) + return; + + flush_sndbuf_sync(priv); + + spin_lock_bh(&priv->lock); + path = priv->path; /* save reference to IUCV path */ + priv->path = NULL; + hvc_iucv_cleanup(priv); + spin_unlock_bh(&priv->lock); + + /* sever IUCV path outside of priv->lock due to lock ordering of: + * priv->lock <--> iucv_table_lock */ + if (path) { + iucv_path_sever(path, NULL); + iucv_path_free(path); + } +} + +/** + * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID + * @ipvmid: Originating z/VM user ID (right padded with blanks) + * + * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise + * non-zero. + */ +static int hvc_iucv_filter_connreq(u8 ipvmid[8]) +{ + size_t i; + + /* Note: default policy is ACCEPT if no filter is set */ + if (!hvc_iucv_filter_size) + return 0; + + for (i = 0; i < hvc_iucv_filter_size; i++) + if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8)) + return 0; + return 1; +} + +/** + * hvc_iucv_path_pending() - IUCV handler to process a connection request. + * @path: Pending path (struct iucv_path) + * @ipvmid: z/VM system identifier of originator + * @ipuser: User specified data for this path + * (AF_IUCV: port/service name and originator port) + * + * The function uses the @ipuser data to determine if the pending path belongs + * to a terminal managed by this device driver. + * If the path belongs to this driver, ensure that the terminal is not accessed + * multiple times (only one connection to a terminal is allowed). + * If the terminal is not yet connected, the pending path is accepted and is + * associated to the appropriate struct hvc_iucv_private instance. + * + * Returns 0 if @path belongs to a terminal managed by the this device driver; + * otherwise returns -ENODEV in order to dispatch this path to other handlers. + * + * Locking: struct hvc_iucv_private->lock + */ +static int hvc_iucv_path_pending(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) +{ + struct hvc_iucv_private *priv; + u8 nuser_data[16]; + u8 vm_user_id[9]; + int i, rc; + + priv = NULL; + for (i = 0; i < hvc_iucv_devices; i++) + if (hvc_iucv_table[i] && + (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { + priv = hvc_iucv_table[i]; + break; + } + if (!priv) + return -ENODEV; + + /* Enforce that ipvmid is allowed to connect to us */ + read_lock(&hvc_iucv_filter_lock); + rc = hvc_iucv_filter_connreq(ipvmid); + read_unlock(&hvc_iucv_filter_lock); + if (rc) { + iucv_path_sever(path, ipuser); + iucv_path_free(path); + memcpy(vm_user_id, ipvmid, 8); + vm_user_id[8] = 0; + pr_info("A connection request from z/VM user ID %s " + "was refused\n", vm_user_id); + return 0; + } + + spin_lock(&priv->lock); + + /* If the terminal is already connected or being severed, then sever + * this path to enforce that there is only ONE established communication + * path per terminal. */ + if (priv->iucv_state != IUCV_DISCONN) { + iucv_path_sever(path, ipuser); + iucv_path_free(path); + goto out_path_handled; + } + + /* accept path */ + memcpy(nuser_data, ipuser + 8, 8); /* remote service (for af_iucv) */ + memcpy(nuser_data + 8, ipuser, 8); /* local service (for af_iucv) */ + path->msglim = 0xffff; /* IUCV MSGLIMIT */ + path->flags &= ~IUCV_IPRMDATA; /* TODO: use IUCV_IPRMDATA */ + rc = iucv_path_accept(path, &hvc_iucv_handler, nuser_data, priv); + if (rc) { + iucv_path_sever(path, ipuser); + iucv_path_free(path); + goto out_path_handled; + } + priv->path = path; + priv->iucv_state = IUCV_CONNECTED; + + /* flush buffered output data... */ + schedule_delayed_work(&priv->sndbuf_work, 5); + +out_path_handled: + spin_unlock(&priv->lock); + return 0; +} + +/** + * hvc_iucv_path_severed() - IUCV handler to process a path sever. + * @path: Pending path (struct iucv_path) + * @ipuser: User specified data for this path + * (AF_IUCV: port/service name and originator port) + * + * This function calls the hvc_iucv_hangup() function for the + * respective IUCV HVC terminal. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) +{ + struct hvc_iucv_private *priv = path->private; + + hvc_iucv_hangup(priv); +} + +/** + * hvc_iucv_msg_pending() - IUCV handler to process an incoming IUCV message. + * @path: Pending path (struct iucv_path) + * @msg: Pointer to the IUCV message + * + * The function puts an incoming message on the input queue for later + * processing (by hvc_iucv_get_chars() / hvc_iucv_write()). + * If the tty has not yet been opened, the message is rejected. + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_msg_pending(struct iucv_path *path, + struct iucv_message *msg) +{ + struct hvc_iucv_private *priv = path->private; + struct iucv_tty_buffer *rb; + + /* reject messages that exceed max size of iucv_tty_msg->datalen */ + if (msg->length > MSG_SIZE(MSG_MAX_DATALEN)) { + iucv_message_reject(path, msg); + return; + } + + spin_lock(&priv->lock); + + /* reject messages if tty has not yet been opened */ + if (priv->tty_state == TTY_CLOSED) { + iucv_message_reject(path, msg); + goto unlock_return; + } + + /* allocate tty buffer to save iucv msg only */ + rb = alloc_tty_buffer(0, GFP_ATOMIC); + if (!rb) { + iucv_message_reject(path, msg); + goto unlock_return; /* -ENOMEM */ + } + rb->msg = *msg; + + list_add_tail(&rb->list, &priv->tty_inqueue); + + hvc_kick(); /* wake up hvc thread */ + +unlock_return: + spin_unlock(&priv->lock); +} + +/** + * hvc_iucv_msg_complete() - IUCV handler to process message completion + * @path: Pending path (struct iucv_path) + * @msg: Pointer to the IUCV message + * + * The function is called upon completion of message delivery to remove the + * message from the outqueue. Additional delivery information can be found + * msg->audit: rejected messages (0x040000 (IPADRJCT)), and + * purged messages (0x010000 (IPADPGNR)). + * + * Locking: struct hvc_iucv_private->lock + */ +static void hvc_iucv_msg_complete(struct iucv_path *path, + struct iucv_message *msg) +{ + struct hvc_iucv_private *priv = path->private; + struct iucv_tty_buffer *ent, *next; + LIST_HEAD(list_remove); + + spin_lock(&priv->lock); + list_for_each_entry_safe(ent, next, &priv->tty_outqueue, list) + if (ent->msg.id == msg->id) { + list_move(&ent->list, &list_remove); + break; + } + wake_up(&priv->sndbuf_waitq); + spin_unlock(&priv->lock); + destroy_tty_buffer_list(&list_remove); +} + +/** + * hvc_iucv_pm_freeze() - Freeze PM callback + * @dev: IUVC HVC terminal device + * + * Sever an established IUCV communication path and + * trigger a hang-up of the underlying HVC terminal. + */ +static int hvc_iucv_pm_freeze(struct device *dev) +{ + struct hvc_iucv_private *priv = dev_get_drvdata(dev); + + local_bh_disable(); + hvc_iucv_hangup(priv); + local_bh_enable(); + + return 0; +} + +/** + * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback + * @dev: IUVC HVC terminal device + * + * Wake up the HVC thread to trigger hang-up and respective + * HVC back-end notifier invocations. + */ +static int hvc_iucv_pm_restore_thaw(struct device *dev) +{ + hvc_kick(); + return 0; +} + + +/* HVC operations */ +static const struct hv_ops hvc_iucv_ops = { + .get_chars = hvc_iucv_get_chars, + .put_chars = hvc_iucv_put_chars, + .notifier_add = hvc_iucv_notifier_add, + .notifier_del = hvc_iucv_notifier_del, + .notifier_hangup = hvc_iucv_notifier_hangup, +}; + +/* Suspend / resume device operations */ +static const struct dev_pm_ops hvc_iucv_pm_ops = { + .freeze = hvc_iucv_pm_freeze, + .thaw = hvc_iucv_pm_restore_thaw, + .restore = hvc_iucv_pm_restore_thaw, +}; + +/* IUCV HVC device driver */ +static struct device_driver hvc_iucv_driver = { + .name = KMSG_COMPONENT, + .bus = &iucv_bus, + .pm = &hvc_iucv_pm_ops, +}; + +/** + * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance + * @id: hvc_iucv_table index + * @is_console: Flag if the instance is used as Linux console + * + * This function allocates a new hvc_iucv_private structure and stores + * the instance in hvc_iucv_table at index @id. + * Returns 0 on success; otherwise non-zero. + */ +static int __init hvc_iucv_alloc(int id, unsigned int is_console) +{ + struct hvc_iucv_private *priv; + char name[9]; + int rc; + + priv = kzalloc(sizeof(struct hvc_iucv_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + INIT_LIST_HEAD(&priv->tty_outqueue); + INIT_LIST_HEAD(&priv->tty_inqueue); + INIT_DELAYED_WORK(&priv->sndbuf_work, hvc_iucv_sndbuf_work); + init_waitqueue_head(&priv->sndbuf_waitq); + + priv->sndbuf = (void *) get_zeroed_page(GFP_KERNEL); + if (!priv->sndbuf) { + kfree(priv); + return -ENOMEM; + } + + /* set console flag */ + priv->is_console = is_console; + + /* allocate hvc device */ + priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ + HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); + if (IS_ERR(priv->hvc)) { + rc = PTR_ERR(priv->hvc); + goto out_error_hvc; + } + + /* notify HVC thread instead of using polling */ + priv->hvc->irq_requested = 1; + + /* setup iucv related information */ + snprintf(name, 9, "lnxhvc%-2d", id); + memcpy(priv->srv_name, name, 8); + ASCEBC(priv->srv_name, 8); + + /* create and setup device */ + priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL); + if (!priv->dev) { + rc = -ENOMEM; + goto out_error_dev; + } + dev_set_name(priv->dev, "hvc_iucv%d", id); + dev_set_drvdata(priv->dev, priv); + priv->dev->bus = &iucv_bus; + priv->dev->parent = iucv_root; + priv->dev->driver = &hvc_iucv_driver; + priv->dev->release = (void (*)(struct device *)) kfree; + rc = device_register(priv->dev); + if (rc) { + put_device(priv->dev); + goto out_error_dev; + } + + hvc_iucv_table[id] = priv; + return 0; + +out_error_dev: + hvc_remove(priv->hvc); +out_error_hvc: + free_page((unsigned long) priv->sndbuf); + kfree(priv); + + return rc; +} + +/** + * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances + */ +static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) +{ + hvc_remove(priv->hvc); + device_unregister(priv->dev); + free_page((unsigned long) priv->sndbuf); + kfree(priv); +} + +/** + * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID + * @filter: String containing a comma-separated list of z/VM user IDs + */ +static const char *hvc_iucv_parse_filter(const char *filter, char *dest) +{ + const char *nextdelim, *residual; + size_t len; + + nextdelim = strchr(filter, ','); + if (nextdelim) { + len = nextdelim - filter; + residual = nextdelim + 1; + } else { + len = strlen(filter); + residual = filter + len; + } + + if (len == 0) + return ERR_PTR(-EINVAL); + + /* check for '\n' (if called from sysfs) */ + if (filter[len - 1] == '\n') + len--; + + if (len > 8) + return ERR_PTR(-EINVAL); + + /* pad with blanks and save upper case version of user ID */ + memset(dest, ' ', 8); + while (len--) + dest[len] = toupper(filter[len]); + return residual; +} + +/** + * hvc_iucv_setup_filter() - Set up z/VM user ID filter + * @filter: String consisting of a comma-separated list of z/VM user IDs + * + * The function parses the @filter string and creates an array containing + * the list of z/VM user ID filter entries. + * Return code 0 means success, -EINVAL if the filter is syntactically + * incorrect, -ENOMEM if there was not enough memory to allocate the + * filter list array, or -ENOSPC if too many z/VM user IDs have been specified. + */ +static int hvc_iucv_setup_filter(const char *val) +{ + const char *residual; + int err; + size_t size, count; + void *array, *old_filter; + + count = strlen(val); + if (count == 0 || (count == 1 && val[0] == '\n')) { + size = 0; + array = NULL; + goto out_replace_filter; /* clear filter */ + } + + /* count user IDs in order to allocate sufficient memory */ + size = 1; + residual = val; + while ((residual = strchr(residual, ',')) != NULL) { + residual++; + size++; + } + + /* check if the specified list exceeds the filter limit */ + if (size > MAX_VMID_FILTER) + return -ENOSPC; + + array = kzalloc(size * 8, GFP_KERNEL); + if (!array) + return -ENOMEM; + + count = size; + residual = val; + while (*residual && count) { + residual = hvc_iucv_parse_filter(residual, + array + ((size - count) * 8)); + if (IS_ERR(residual)) { + err = PTR_ERR(residual); + kfree(array); + goto out_err; + } + count--; + } + +out_replace_filter: + write_lock_bh(&hvc_iucv_filter_lock); + old_filter = hvc_iucv_filter; + hvc_iucv_filter_size = size; + hvc_iucv_filter = array; + write_unlock_bh(&hvc_iucv_filter_lock); + kfree(old_filter); + + err = 0; +out_err: + return err; +} + +/** + * param_set_vmidfilter() - Set z/VM user ID filter parameter + * @val: String consisting of a comma-separated list of z/VM user IDs + * @kp: Kernel parameter pointing to hvc_iucv_filter array + * + * The function sets up the z/VM user ID filter specified as comma-separated + * list of user IDs in @val. + * Note: If it is called early in the boot process, @val is stored and + * parsed later in hvc_iucv_init(). + */ +static int param_set_vmidfilter(const char *val, const struct kernel_param *kp) +{ + int rc; + + if (!MACHINE_IS_VM || !hvc_iucv_devices) + return -ENODEV; + + if (!val) + return -EINVAL; + + rc = 0; + if (slab_is_available()) + rc = hvc_iucv_setup_filter(val); + else + hvc_iucv_filter_string = val; /* defer... */ + return rc; +} + +/** + * param_get_vmidfilter() - Get z/VM user ID filter + * @buffer: Buffer to store z/VM user ID filter, + * (buffer size assumption PAGE_SIZE) + * @kp: Kernel parameter pointing to the hvc_iucv_filter array + * + * The function stores the filter as a comma-separated list of z/VM user IDs + * in @buffer. Typically, sysfs routines call this function for attr show. + */ +static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp) +{ + int rc; + size_t index, len; + void *start, *end; + + if (!MACHINE_IS_VM || !hvc_iucv_devices) + return -ENODEV; + + rc = 0; + read_lock_bh(&hvc_iucv_filter_lock); + for (index = 0; index < hvc_iucv_filter_size; index++) { + start = hvc_iucv_filter + (8 * index); + end = memchr(start, ' ', 8); + len = (end) ? end - start : 8; + memcpy(buffer + rc, start, len); + rc += len; + buffer[rc++] = ','; + } + read_unlock_bh(&hvc_iucv_filter_lock); + if (rc) + buffer[--rc] = '\0'; /* replace last comma and update rc */ + return rc; +} + +#define param_check_vmidfilter(name, p) __param_check(name, p, void) + +static struct kernel_param_ops param_ops_vmidfilter = { + .set = param_set_vmidfilter, + .get = param_get_vmidfilter, +}; + +/** + * hvc_iucv_init() - z/VM IUCV HVC device driver initialization + */ +static int __init hvc_iucv_init(void) +{ + int rc; + unsigned int i; + + if (!hvc_iucv_devices) + return -ENODEV; + + if (!MACHINE_IS_VM) { + pr_notice("The z/VM IUCV HVC device driver cannot " + "be used without z/VM\n"); + rc = -ENODEV; + goto out_error; + } + + if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) { + pr_err("%lu is not a valid value for the hvc_iucv= " + "kernel parameter\n", hvc_iucv_devices); + rc = -EINVAL; + goto out_error; + } + + /* register IUCV HVC device driver */ + rc = driver_register(&hvc_iucv_driver); + if (rc) + goto out_error; + + /* parse hvc_iucv_allow string and create z/VM user ID filter list */ + if (hvc_iucv_filter_string) { + rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); + switch (rc) { + case 0: + break; + case -ENOMEM: + pr_err("Allocating memory failed with " + "reason code=%d\n", 3); + goto out_error; + case -EINVAL: + pr_err("hvc_iucv_allow= does not specify a valid " + "z/VM user ID list\n"); + goto out_error; + case -ENOSPC: + pr_err("hvc_iucv_allow= specifies too many " + "z/VM user IDs\n"); + goto out_error; + default: + goto out_error; + } + } + + hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT, + sizeof(struct iucv_tty_buffer), + 0, 0, NULL); + if (!hvc_iucv_buffer_cache) { + pr_err("Allocating memory failed with reason code=%d\n", 1); + rc = -ENOMEM; + goto out_error; + } + + hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR, + hvc_iucv_buffer_cache); + if (!hvc_iucv_mempool) { + pr_err("Allocating memory failed with reason code=%d\n", 2); + kmem_cache_destroy(hvc_iucv_buffer_cache); + rc = -ENOMEM; + goto out_error; + } + + /* register the first terminal device as console + * (must be done before allocating hvc terminal devices) */ + rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); + if (rc) { + pr_err("Registering HVC terminal device as " + "Linux console failed\n"); + goto out_error_memory; + } + + /* allocate hvc_iucv_private structs */ + for (i = 0; i < hvc_iucv_devices; i++) { + rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0); + if (rc) { + pr_err("Creating a new HVC terminal device " + "failed with error code=%d\n", rc); + goto out_error_hvc; + } + } + + /* register IUCV callback handler */ + rc = iucv_register(&hvc_iucv_handler, 0); + if (rc) { + pr_err("Registering IUCV handlers failed with error code=%d\n", + rc); + goto out_error_hvc; + } + + return 0; + +out_error_hvc: + for (i = 0; i < hvc_iucv_devices; i++) + if (hvc_iucv_table[i]) + hvc_iucv_destroy(hvc_iucv_table[i]); +out_error_memory: + mempool_destroy(hvc_iucv_mempool); + kmem_cache_destroy(hvc_iucv_buffer_cache); +out_error: + if (hvc_iucv_filter) + kfree(hvc_iucv_filter); + hvc_iucv_devices = 0; /* ensure that we do not provide any device */ + return rc; +} + +/** + * hvc_iucv_config() - Parsing of hvc_iucv= kernel command line parameter + * @val: Parameter value (numeric) + */ +static int __init hvc_iucv_config(char *val) +{ + return strict_strtoul(val, 10, &hvc_iucv_devices); +} + + +device_initcall(hvc_iucv_init); +__setup("hvc_iucv=", hvc_iucv_config); +core_param(hvc_iucv_allow, hvc_iucv_filter, vmidfilter, 0640); diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c new file mode 100644 index 000000000000..61c4a61558d9 --- /dev/null +++ b/drivers/tty/hvc/hvc_rtas.c @@ -0,0 +1,133 @@ +/* + * IBM RTAS driver interface to hvc_console.c + * + * (C) Copyright IBM Corporation 2001-2005 + * (C) Copyright Red Hat, Inc. 2005 + * + * Author(s): Maximino Augilar + * : Ryan S. Arnold + * : Utz Bacher + * : David Woodhouse + * + * inspired by drivers/char/hvc_console.c + * written by Anton Blanchard and Paul Mackerras + * + * 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 "hvc_console.h" + +#define hvc_rtas_cookie 0x67781e15 +struct hvc_struct *hvc_rtas_dev; + +static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; +static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; + +static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, + int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i])) + break; + } + + return i; +} + +static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) +{ + int i, c; + + for (i = 0; i < count; i++) { + if (rtas_call(rtascons_get_char_token, 0, 2, &c)) + break; + + buf[i] = c; + } + + return i; +} + +static const struct hv_ops hvc_rtas_get_put_ops = { + .get_chars = hvc_rtas_read_console, + .put_chars = hvc_rtas_write_console, +}; + +static int __init hvc_rtas_init(void) +{ + struct hvc_struct *hp; + + if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) + rtascons_put_char_token = rtas_token("put-term-char"); + if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) + rtascons_get_char_token = rtas_token("get-term-char"); + if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + BUG_ON(hvc_rtas_dev); + + /* Allocate an hvc_struct for the console device we instantiated + * earlier. Save off hp so that we can return it on exit */ + hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc_rtas_dev = hp; + + return 0; +} +module_init(hvc_rtas_init); + +/* This will tear down the tty portion of the driver */ +static void __exit hvc_rtas_exit(void) +{ + /* Really the fun isn't over until the worker thread breaks down and + * the tty cleans up */ + if (hvc_rtas_dev) + hvc_remove(hvc_rtas_dev); +} +module_exit(hvc_rtas_exit); + +/* This will happen prior to module init. There is no tty at this time? */ +static int __init hvc_rtas_console_init(void) +{ + rtascons_put_char_token = rtas_token("put-term-char"); + if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + rtascons_get_char_token = rtas_token("get-term-char"); + if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops); + add_preferred_console("hvc", 0, NULL); + + return 0; +} +console_initcall(hvc_rtas_console_init); diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c new file mode 100644 index 000000000000..7a84a0595477 --- /dev/null +++ b/drivers/tty/hvc/hvc_tile.c @@ -0,0 +1,68 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * 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, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * Tilera TILE Processor hypervisor console + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "hvc_console.h" + +static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) +{ + return hv_console_write((HV_VirtAddr)buf, count); +} + +static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) +{ + int i, c; + + for (i = 0; i < count; ++i) { + c = hv_console_read_if_ready(); + if (c < 0) + break; + buf[i] = c; + } + + return i; +} + +static const struct hv_ops hvc_tile_get_put_ops = { + .get_chars = hvc_tile_get_chars, + .put_chars = hvc_tile_put_chars, +}; + +static int __init hvc_tile_console_init(void) +{ + extern void disable_early_printk(void); + hvc_instantiate(0, 0, &hvc_tile_get_put_ops); + add_preferred_console("hvc", 0, NULL); + disable_early_printk(); + return 0; +} +console_initcall(hvc_tile_console_init); + +static int __init hvc_tile_init(void) +{ + struct hvc_struct *s; + s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); + return IS_ERR(s) ? PTR_ERR(s) : 0; +} +device_initcall(hvc_tile_init); diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c new file mode 100644 index 000000000000..b0957e61a7be --- /dev/null +++ b/drivers/tty/hvc/hvc_udbg.c @@ -0,0 +1,96 @@ +/* + * udbg interface to hvc_console.c + * + * (C) Copyright David Gibson, IBM Corporation 2008. + * + * 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 "hvc_console.h" + +struct hvc_struct *hvc_udbg_dev; + +static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) +{ + int i; + + for (i = 0; i < count; i++) + udbg_putc(buf[i]); + + return i; +} + +static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) +{ + int i, c; + + if (!udbg_getc_poll) + return 0; + + for (i = 0; i < count; i++) { + if ((c = udbg_getc_poll()) == -1) + break; + buf[i] = c; + } + + return i; +} + +static const struct hv_ops hvc_udbg_ops = { + .get_chars = hvc_udbg_get, + .put_chars = hvc_udbg_put, +}; + +static int __init hvc_udbg_init(void) +{ + struct hvc_struct *hp; + + BUG_ON(hvc_udbg_dev); + + hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc_udbg_dev = hp; + + return 0; +} +module_init(hvc_udbg_init); + +static void __exit hvc_udbg_exit(void) +{ + if (hvc_udbg_dev) + hvc_remove(hvc_udbg_dev); +} +module_exit(hvc_udbg_exit); + +static int __init hvc_udbg_console_init(void) +{ + hvc_instantiate(0, 0, &hvc_udbg_ops); + add_preferred_console("hvc", 0, NULL); + + return 0; +} +console_initcall(hvc_udbg_console_init); diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c new file mode 100644 index 000000000000..5e2f52b33327 --- /dev/null +++ b/drivers/tty/hvc/hvc_vio.c @@ -0,0 +1,173 @@ +/* + * vio driver interface to hvc_console.c + * + * This code was moved here to allow the remaing code to be reused as a + * generic polling mode with semi-reliable transport driver core to the + * console and tty subsystems. + * + * + * Copyright (C) 2001 Anton Blanchard , IBM + * Copyright (C) 2001 Paul Mackerras , IBM + * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold + * + * 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 "hvc_console.h" + +static const char hvc_driver_name[] = "hvc_console"; + +static struct vio_device_id hvc_driver_table[] __devinitdata = { + {"serial", "hvterm1"}, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + +static int filtered_get_chars(uint32_t vtermno, char *buf, int count) +{ + unsigned long got; + int i; + + /* + * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion + * so we play safe and avoid the situation where got > count which could + * overload the flip buffer. + */ + if (count < SIZE_VIO_GET_CHARS) + return -EAGAIN; + + got = hvc_get_chars(vtermno, buf, count); + + /* + * Work around a HV bug where it gives us a null + * after every \r. -- paulus + */ + for (i = 1; i < got; ++i) { + if (buf[i] == 0 && buf[i-1] == '\r') { + --got; + if (i < got) + memmove(&buf[i], &buf[i+1], + got - i); + } + } + return got; +} + +static const struct hv_ops hvc_get_put_ops = { + .get_chars = filtered_get_chars, + .put_chars = hvc_put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int __devinit hvc_vio_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct hvc_struct *hp; + + /* probed with invalid parameters. */ + if (!vdev || !id) + return -EPERM; + + hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, + MAX_VIO_PUT_CHARS); + if (IS_ERR(hp)) + return PTR_ERR(hp); + dev_set_drvdata(&vdev->dev, hp); + + return 0; +} + +static int __devexit hvc_vio_remove(struct vio_dev *vdev) +{ + struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); + + return hvc_remove(hp); +} + +static struct vio_driver hvc_vio_driver = { + .id_table = hvc_driver_table, + .probe = hvc_vio_probe, + .remove = __devexit_p(hvc_vio_remove), + .driver = { + .name = hvc_driver_name, + .owner = THIS_MODULE, + } +}; + +static int __init hvc_vio_init(void) +{ + int rc; + + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return -EIO; + + /* Register as a vio device to receive callbacks */ + rc = vio_register_driver(&hvc_vio_driver); + + return rc; +} +module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ + +static void __exit hvc_vio_exit(void) +{ + vio_unregister_driver(&hvc_vio_driver); +} +module_exit(hvc_vio_exit); + +/* the device tree order defines our numbering */ +static int hvc_find_vtys(void) +{ + struct device_node *vty; + int num_found = 0; + + for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; + vty = of_find_node_by_name(vty, "vty")) { + const uint32_t *vtermno; + + /* We have statically defined space for only a certain number + * of console adapters. + */ + if (num_found >= MAX_NR_HVC_CONSOLES) { + of_node_put(vty); + break; + } + + vtermno = of_get_property(vty, "reg", NULL); + if (!vtermno) + continue; + + if (of_device_is_compatible(vty, "hvterm1")) { + hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); + ++num_found; + } + } + + return num_found; +} +console_initcall(hvc_find_vtys); diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c new file mode 100644 index 000000000000..3740e327f180 --- /dev/null +++ b/drivers/tty/hvc/hvc_xen.c @@ -0,0 +1,271 @@ +/* + * xen console driver interface to hvc_console.c + * + * (c) 2007 Gerd Hoffmann + * + * 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 + +#include "hvc_console.h" + +#define HVC_COOKIE 0x58656e /* "Xen" in hex */ + +static struct hvc_struct *hvc; +static int xencons_irq; + +/* ------------------------------------------------------------------ */ + +static unsigned long console_pfn = ~0ul; + +static inline struct xencons_interface *xencons_interface(void) +{ + if (console_pfn == ~0ul) + return mfn_to_virt(xen_start_info->console.domU.mfn); + else + return __va(console_pfn << PAGE_SHIFT); +} + +static inline void notify_daemon(void) +{ + /* Use evtchn: this is called early, before irq is set up. */ + notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); +} + +static int __write_console(const char *data, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int sent = 0; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); /* update queue values before going on */ + BUG_ON((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + wmb(); /* write ring before updating pointer */ + intf->out_prod = prod; + + if (sent) + notify_daemon(); + return sent; +} + +static int domU_write_console(uint32_t vtermno, const char *data, int len) +{ + int ret = len; + + /* + * Make sure the whole buffer is emitted, polling if + * necessary. We don't ever want to rely on the hvc daemon + * because the most interesting console output is when the + * kernel is crippled. + */ + while (len) { + int sent = __write_console(data, len); + + data += sent; + len -= sent; + + if (unlikely(len)) + HYPERVISOR_sched_op(SCHEDOP_yield, NULL); + } + + return ret; +} + +static int domU_read_console(uint32_t vtermno, char *buf, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int recv = 0; + + cons = intf->in_cons; + prod = intf->in_prod; + mb(); /* get pointers before reading ring */ + BUG_ON((prod - cons) > sizeof(intf->in)); + + while (cons != prod && recv < len) + buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; + + mb(); /* read ring before consuming */ + intf->in_cons = cons; + + notify_daemon(); + return recv; +} + +static struct hv_ops domU_hvc_ops = { + .get_chars = domU_read_console, + .put_chars = domU_write_console, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int dom0_read_console(uint32_t vtermno, char *buf, int len) +{ + return HYPERVISOR_console_io(CONSOLEIO_read, len, buf); +} + +/* + * Either for a dom0 to write to the system console, or a domU with a + * debug version of Xen + */ +static int dom0_write_console(uint32_t vtermno, const char *str, int len) +{ + int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); + if (rc < 0) + return 0; + + return len; +} + +static struct hv_ops dom0_hvc_ops = { + .get_chars = dom0_read_console, + .put_chars = dom0_write_console, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int __init xen_hvc_init(void) +{ + struct hvc_struct *hp; + struct hv_ops *ops; + + if (!xen_pv_domain()) + return -ENODEV; + + if (xen_initial_domain()) { + ops = &dom0_hvc_ops; + xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); + } else { + if (!xen_start_info->console.domU.evtchn) + return -ENODEV; + + ops = &domU_hvc_ops; + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + } + if (xencons_irq < 0) + xencons_irq = 0; /* NO_IRQ */ + + hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc = hp; + + console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn); + + return 0; +} + +void xen_console_resume(void) +{ + if (xencons_irq) + rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); +} + +static void __exit xen_hvc_fini(void) +{ + if (hvc) + hvc_remove(hvc); +} + +static int xen_cons_init(void) +{ + struct hv_ops *ops; + + if (!xen_pv_domain()) + return 0; + + if (xen_initial_domain()) + ops = &dom0_hvc_ops; + else + ops = &domU_hvc_ops; + + hvc_instantiate(HVC_COOKIE, 0, ops); + return 0; +} + +module_init(xen_hvc_init); +module_exit(xen_hvc_fini); +console_initcall(xen_cons_init); + +#ifdef CONFIG_EARLY_PRINTK +static void xenboot_write_console(struct console *console, const char *string, + unsigned len) +{ + unsigned int linelen, off = 0; + const char *pos; + + dom0_write_console(0, string, len); + + if (xen_initial_domain()) + return; + + domU_write_console(0, "(early) ", 8); + while (off < len && NULL != (pos = strchr(string+off, '\n'))) { + linelen = pos-string+off; + if (off + linelen > len) + break; + domU_write_console(0, string+off, linelen); + domU_write_console(0, "\r\n", 2); + off += linelen + 1; + } + if (off < len) + domU_write_console(0, string+off, len-off); +} + +struct console xenboot_console = { + .name = "xenboot", + .write = xenboot_write_console, + .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, +}; +#endif /* CONFIG_EARLY_PRINTK */ + +void xen_raw_console_write(const char *str) +{ + dom0_write_console(0, str, strlen(str)); +} + +void xen_raw_printk(const char *fmt, ...) +{ + static char buf[512]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + xen_raw_console_write(buf); +} diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c new file mode 100644 index 000000000000..bedc6c1b6fa5 --- /dev/null +++ b/drivers/tty/hvc/hvcs.c @@ -0,0 +1,1604 @@ +/* + * IBM eServer Hypervisor Virtual Console Server Device Driver + * Copyright (C) 2003, 2004 IBM Corp. + * Ryan S. Arnold (rsa@us.ibm.com) + * + * 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 + * + * Author(s) : Ryan S. Arnold + * + * This is the device driver for the IBM Hypervisor Virtual Console Server, + * "hvcs". The IBM hvcs provides a tty driver interface to allow Linux + * user space applications access to the system consoles of logically + * partitioned operating systems, e.g. Linux, running on the same partitioned + * Power5 ppc64 system. Physical hardware consoles per partition are not + * practical on this hardware so system consoles are accessed by this driver + * using inter-partition firmware interfaces to virtual terminal devices. + * + * A vty is known to the HMC as a "virtual serial server adapter". It is a + * virtual terminal device that is created by firmware upon partition creation + * to act as a partitioned OS's console device. + * + * Firmware dynamically (via hotplug) exposes vty-servers to a running ppc64 + * Linux system upon their creation by the HMC or their exposure during boot. + * The non-user interactive backend of this driver is implemented as a vio + * device driver so that it can receive notification of vty-server lifetimes + * after it registers with the vio bus to handle vty-server probe and remove + * callbacks. + * + * Many vty-servers can be configured to connect to one vty, but a vty can + * only be actively connected to by a single vty-server, in any manner, at one + * time. If the HMC is currently hosting the console for a target Linux + * partition; attempts to open the tty device to the partition's console using + * the hvcs on any partition will return -EBUSY with every open attempt until + * the HMC frees the connection between its vty-server and the desired + * partition's vty device. Conversely, a vty-server may only be connected to + * a single vty at one time even though it may have several configured vty + * partner possibilities. + * + * Firmware does not provide notification of vty partner changes to this + * driver. This means that an HMC Super Admin may add or remove partner vtys + * from a vty-server's partner list but the changes will not be signaled to + * the vty-server. Firmware only notifies the driver when a vty-server is + * added or removed from the system. To compensate for this deficiency, this + * driver implements a sysfs update attribute which provides a method for + * rescanning partner information upon a user's request. + * + * Each vty-server, prior to being exposed to this driver is reference counted + * using the 2.6 Linux kernel kref construct. + * + * For direction on installation and usage of this driver please reference + * Documentation/powerpc/hvcs.txt. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 1.3.0 -> 1.3.1 In hvcs_open memset(..,0x00,..) instead of memset(..,0x3F,00). + * Removed braces around single statements following conditionals. Removed '= + * 0' after static int declarations since these default to zero. Removed + * list_for_each_safe() and replaced with list_for_each_entry() in + * hvcs_get_by_index(). The 'safe' version is un-needed now that the driver is + * using spinlocks. Changed spin_lock_irqsave() to spin_lock() when locking + * hvcs_structs_lock and hvcs_pi_lock since these are not touched in an int + * handler. Initialized hvcs_structs_lock and hvcs_pi_lock to + * SPIN_LOCK_UNLOCKED at declaration time rather than in hvcs_module_init(). + * Added spin_lock around list_del() in destroy_hvcs_struct() to protect the + * list traversals from a deletion. Removed '= NULL' from pointer declaration + * statements since they are initialized NULL by default. Removed wmb() + * instances from hvcs_try_write(). They probably aren't needed with locking in + * place. Added check and cleanup for hvcs_pi_buff = kmalloc() in + * hvcs_module_init(). Exposed hvcs_struct.index via a sysfs attribute so that + * the coupling between /dev/hvcs* and a vty-server can be automatically + * determined. Moved kobject_put() in hvcs_open outside of the + * spin_unlock_irqrestore(). + * + * 1.3.1 -> 1.3.2 Changed method for determining hvcs_struct->index and had it + * align with how the tty layer always assigns the lowest index available. This + * change resulted in a list of ints that denotes which indexes are available. + * Device additions and removals use the new hvcs_get_index() and + * hvcs_return_index() helper functions. The list is created with + * hvsc_alloc_index_list() and it is destroyed with hvcs_free_index_list(). + * Without these fixes hotplug vty-server adapter support goes crazy with this + * driver if the user removes a vty-server adapter. Moved free_irq() outside of + * the hvcs_final_close() function in order to get it out of the spinlock. + * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping + * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from + * arch/powerepc/include/asm/hvcserver.h + * + * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to + * prevent possible lockup with realtime scheduling as similarily pointed out by + * akpm in hvc_console. Changed resulted in the removal of hvcs_final_close() + * to reorder cleanup operations and prevent discarding of pending data during + * an hvcs_close(). Removed spinlock protection of hvcs_struct data members in + * hvcs_write_room() and hvcs_chars_in_buffer() because they aren't needed. + */ + +#define HVCS_DRIVER_VERSION "1.3.3" + +MODULE_AUTHOR("Ryan S. Arnold "); +MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(HVCS_DRIVER_VERSION); + +/* + * Wait this long per iteration while trying to push buffered data to the + * hypervisor before allowing the tty to complete a close operation. + */ +#define HVCS_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ + +/* + * Since the Linux TTY code does not currently (2-04-2004) support dynamic + * addition of tty derived devices and we shouldn't allocate thousands of + * tty_device pointers when the number of vty-server & vty partner connections + * will most often be much lower than this, we'll arbitrarily allocate + * HVCS_DEFAULT_SERVER_ADAPTERS tty_structs and cdev's by default when we + * register the tty_driver. This can be overridden using an insmod parameter. + */ +#define HVCS_DEFAULT_SERVER_ADAPTERS 64 + +/* + * The user can't insmod with more than HVCS_MAX_SERVER_ADAPTERS hvcs device + * nodes as a sanity check. Theoretically there can be over 1 Billion + * vty-server & vty partner connections. + */ +#define HVCS_MAX_SERVER_ADAPTERS 1024 + +/* + * We let Linux assign us a major number and we start the minors at zero. There + * is no intuitive mapping between minor number and the target vty-server + * adapter except that each new vty-server adapter is always assigned to the + * smallest minor number available. + */ +#define HVCS_MINOR_START 0 + +/* + * The hcall interface involves putting 8 chars into each of two registers. + * We load up those 2 registers (in arch/powerpc/platforms/pseries/hvconsole.c) + * by casting char[16] to long[2]. It would work without __ALIGNED__, but a + * little (tiny) bit slower because an unaligned load is slower than aligned + * load. + */ +#define __ALIGNED__ __attribute__((__aligned__(8))) + +/* + * How much data can firmware send with each hvc_put_chars()? Maybe this + * should be moved into an architecture specific area. + */ +#define HVCS_BUFF_LEN 16 + +/* + * This is the maximum amount of data we'll let the user send us (hvcs_write) at + * once in a chunk as a sanity check. + */ +#define HVCS_MAX_FROM_USER 4096 + +/* + * Be careful when adding flags to this line discipline. Don't add anything + * that will cause echoing or we'll go into recursive loop echoing chars back + * and forth with the console drivers. + */ +static struct ktermios hvcs_tty_termios = { + .c_iflag = IGNBRK | IGNPAR, + .c_oflag = OPOST, + .c_cflag = B38400 | CS8 | CREAD | HUPCL, + .c_cc = INIT_C_CC, + .c_ispeed = 38400, + .c_ospeed = 38400 +}; + +/* + * This value is used to take the place of a command line parameter when the + * module is inserted. It starts as -1 and stays as such if the user doesn't + * specify a module insmod parameter. If they DO specify one then it is set to + * the value of the integer passed in. + */ +static int hvcs_parm_num_devs = -1; +module_param(hvcs_parm_num_devs, int, 0); + +static const char hvcs_driver_name[] = "hvcs"; +static const char hvcs_device_node[] = "hvcs"; +static const char hvcs_driver_string[] + = "IBM hvcs (Hypervisor Virtual Console Server) Driver"; + +/* Status of partner info rescan triggered via sysfs. */ +static int hvcs_rescan_status; + +static struct tty_driver *hvcs_tty_driver; + +/* + * In order to be somewhat sane this driver always associates the hvcs_struct + * index element with the numerically equal tty->index. This means that a + * hotplugged vty-server adapter will always map to the lowest index valued + * device node. If vty-servers were hotplug removed from the system and then + * new ones added the new vty-server may have the largest slot number of all + * the vty-server adapters in the partition but it may have the lowest dev node + * index of all the adapters due to the hole left by the hotplug removed + * adapter. There are a set of functions provided to get the lowest index for + * a new device as well as return the index to the list. This list is allocated + * with a number of elements equal to the number of device nodes requested when + * the module was inserted. + */ +static int *hvcs_index_list; + +/* + * How large is the list? This is kept for traversal since the list is + * dynamically created. + */ +static int hvcs_index_count; + +/* + * Used by the khvcsd to pick up I/O operations when the kernel_thread is + * already awake but potentially shifted to TASK_INTERRUPTIBLE state. + */ +static int hvcs_kicked; + +/* + * Use by the kthread construct for task operations like waking the sleeping + * thread and stopping the kthread. + */ +static struct task_struct *hvcs_task; + +/* + * We allocate this for the use of all of the hvcs_structs when they fetch + * partner info. + */ +static unsigned long *hvcs_pi_buff; + +/* Only allow one hvcs_struct to use the hvcs_pi_buff at a time. */ +static DEFINE_SPINLOCK(hvcs_pi_lock); + +/* One vty-server per hvcs_struct */ +struct hvcs_struct { + spinlock_t lock; + + /* + * This index identifies this hvcs device as the complement to a + * specific tty index. + */ + unsigned int index; + + struct tty_struct *tty; + int open_count; + + /* + * Used to tell the driver kernel_thread what operations need to take + * place upon this hvcs_struct instance. + */ + int todo_mask; + + /* + * This buffer is required so that when hvcs_write_room() reports that + * it can send HVCS_BUFF_LEN characters that it will buffer the full + * HVCS_BUFF_LEN characters if need be. This is essential for opost + * writes since they do not do high level buffering and expect to be + * able to send what the driver commits to sending buffering + * [e.g. tab to space conversions in n_tty.c opost()]. + */ + char buffer[HVCS_BUFF_LEN]; + int chars_in_buffer; + + /* + * Any variable below the kref is valid before a tty is connected and + * stays valid after the tty is disconnected. These shouldn't be + * whacked until the koject refcount reaches zero though some entries + * may be changed via sysfs initiatives. + */ + struct kref kref; /* ref count & hvcs_struct lifetime */ + int connected; /* is the vty-server currently connected to a vty? */ + uint32_t p_unit_address; /* partner unit address */ + uint32_t p_partition_ID; /* partner partition ID */ + char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */ + struct list_head next; /* list management */ + struct vio_dev *vdev; +}; + +/* Required to back map a kref to its containing object */ +#define from_kref(k) container_of(k, struct hvcs_struct, kref) + +static LIST_HEAD(hvcs_structs); +static DEFINE_SPINLOCK(hvcs_structs_lock); + +static void hvcs_unthrottle(struct tty_struct *tty); +static void hvcs_throttle(struct tty_struct *tty); +static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance); + +static int hvcs_write(struct tty_struct *tty, + const unsigned char *buf, int count); +static int hvcs_write_room(struct tty_struct *tty); +static int hvcs_chars_in_buffer(struct tty_struct *tty); + +static int hvcs_has_pi(struct hvcs_struct *hvcsd); +static void hvcs_set_pi(struct hvcs_partner_info *pi, + struct hvcs_struct *hvcsd); +static int hvcs_get_pi(struct hvcs_struct *hvcsd); +static int hvcs_rescan_devices_list(void); + +static int hvcs_partner_connect(struct hvcs_struct *hvcsd); +static void hvcs_partner_free(struct hvcs_struct *hvcsd); + +static int hvcs_enable_device(struct hvcs_struct *hvcsd, + uint32_t unit_address, unsigned int irq, struct vio_dev *dev); + +static int hvcs_open(struct tty_struct *tty, struct file *filp); +static void hvcs_close(struct tty_struct *tty, struct file *filp); +static void hvcs_hangup(struct tty_struct * tty); + +static int __devinit hvcs_probe(struct vio_dev *dev, + const struct vio_device_id *id); +static int __devexit hvcs_remove(struct vio_dev *dev); +static int __init hvcs_module_init(void); +static void __exit hvcs_module_exit(void); + +#define HVCS_SCHED_READ 0x00000001 +#define HVCS_QUICK_READ 0x00000002 +#define HVCS_TRY_WRITE 0x00000004 +#define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) + +static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) +{ + return dev_get_drvdata(&viod->dev); +} +/* The sysfs interface for the driver and devices */ + +static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} +static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); + +static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} +static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); + +static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, + size_t count) +{ + /* + * Don't need this feature at the present time because firmware doesn't + * yet support multiple partners. + */ + printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); + return -EPERM; +} + +static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} + +static DEVICE_ATTR(current_vty, + S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); + +static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + + /* writing a '0' to this sysfs entry will result in the disconnect. */ + if (simple_strtol(buf, NULL, 0) != 0) + return -EINVAL; + + spin_lock_irqsave(&hvcsd->lock, flags); + + if (hvcsd->open_count > 0) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + printk(KERN_INFO "HVCS: vterm state unchanged. " + "The hvcs device node is still in use.\n"); + return -EPERM; + } + + if (hvcsd->connected == 0) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + printk(KERN_INFO "HVCS: vterm state unchanged. The" + " vty-server is not connected to a vty.\n"); + return -EPERM; + } + + hvcs_partner_free(hvcsd); + printk(KERN_INFO "HVCS: Closed vty-server@%X and" + " partner vty@%X:%d connection.\n", + hvcsd->vdev->unit_address, + hvcsd->p_unit_address, + (uint32_t)hvcsd->p_partition_ID); + + spin_unlock_irqrestore(&hvcsd->lock, flags); + return count; +} + +static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%d\n", hvcsd->connected); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} +static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, + hvcs_vterm_state_show, hvcs_vterm_state_store); + +static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct vio_dev *viod = to_vio_dev(dev); + struct hvcs_struct *hvcsd = from_vio_dev(viod); + unsigned long flags; + int retval; + + spin_lock_irqsave(&hvcsd->lock, flags); + retval = sprintf(buf, "%d\n", hvcsd->index); + spin_unlock_irqrestore(&hvcsd->lock, flags); + return retval; +} + +static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); + +static struct attribute *hvcs_attrs[] = { + &dev_attr_partner_vtys.attr, + &dev_attr_partner_clcs.attr, + &dev_attr_current_vty.attr, + &dev_attr_vterm_state.attr, + &dev_attr_index.attr, + NULL, +}; + +static struct attribute_group hvcs_attr_group = { + .attrs = hvcs_attrs, +}; + +static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) +{ + /* A 1 means it is updating, a 0 means it is done updating */ + return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); +} + +static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, + size_t count) +{ + if ((simple_strtol(buf, NULL, 0) != 1) + && (hvcs_rescan_status != 0)) + return -EINVAL; + + hvcs_rescan_status = 1; + printk(KERN_INFO "HVCS: rescanning partner info for all" + " vty-servers.\n"); + hvcs_rescan_devices_list(); + hvcs_rescan_status = 0; + return count; +} + +static DRIVER_ATTR(rescan, + S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); + +static void hvcs_kick(void) +{ + hvcs_kicked = 1; + wmb(); + wake_up_process(hvcs_task); +} + +static void hvcs_unthrottle(struct tty_struct *tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned long flags; + + spin_lock_irqsave(&hvcsd->lock, flags); + hvcsd->todo_mask |= HVCS_SCHED_READ; + spin_unlock_irqrestore(&hvcsd->lock, flags); + hvcs_kick(); +} + +static void hvcs_throttle(struct tty_struct *tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned long flags; + + spin_lock_irqsave(&hvcsd->lock, flags); + vio_disable_interrupts(hvcsd->vdev); + spin_unlock_irqrestore(&hvcsd->lock, flags); +} + +/* + * If the device is being removed we don't have to worry about this interrupt + * handler taking any further interrupts because they are disabled which means + * the hvcs_struct will always be valid in this handler. + */ +static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) +{ + struct hvcs_struct *hvcsd = dev_instance; + + spin_lock(&hvcsd->lock); + vio_disable_interrupts(hvcsd->vdev); + hvcsd->todo_mask |= HVCS_SCHED_READ; + spin_unlock(&hvcsd->lock); + hvcs_kick(); + + return IRQ_HANDLED; +} + +/* This function must be called with the hvcsd->lock held */ +static void hvcs_try_write(struct hvcs_struct *hvcsd) +{ + uint32_t unit_address = hvcsd->vdev->unit_address; + struct tty_struct *tty = hvcsd->tty; + int sent; + + if (hvcsd->todo_mask & HVCS_TRY_WRITE) { + /* won't send partial writes */ + sent = hvc_put_chars(unit_address, + &hvcsd->buffer[0], + hvcsd->chars_in_buffer ); + if (sent > 0) { + hvcsd->chars_in_buffer = 0; + /* wmb(); */ + hvcsd->todo_mask &= ~(HVCS_TRY_WRITE); + /* wmb(); */ + + /* + * We are still obligated to deliver the data to the + * hypervisor even if the tty has been closed because + * we commited to delivering it. But don't try to wake + * a non-existent tty. + */ + if (tty) { + tty_wakeup(tty); + } + } + } +} + +static int hvcs_io(struct hvcs_struct *hvcsd) +{ + uint32_t unit_address; + struct tty_struct *tty; + char buf[HVCS_BUFF_LEN] __ALIGNED__; + unsigned long flags; + int got = 0; + + spin_lock_irqsave(&hvcsd->lock, flags); + + unit_address = hvcsd->vdev->unit_address; + tty = hvcsd->tty; + + hvcs_try_write(hvcsd); + + if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) { + hvcsd->todo_mask &= ~(HVCS_READ_MASK); + goto bail; + } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK))) + goto bail; + + /* remove the read masks */ + hvcsd->todo_mask &= ~(HVCS_READ_MASK); + + if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) { + got = hvc_get_chars(unit_address, + &buf[0], + HVCS_BUFF_LEN); + tty_insert_flip_string(tty, buf, got); + } + + /* Give the TTY time to process the data we just sent. */ + if (got) + hvcsd->todo_mask |= HVCS_QUICK_READ; + + spin_unlock_irqrestore(&hvcsd->lock, flags); + /* This is synch because tty->low_latency == 1 */ + if(got) + tty_flip_buffer_push(tty); + + if (!got) { + /* Do this _after_ the flip_buffer_push */ + spin_lock_irqsave(&hvcsd->lock, flags); + vio_enable_interrupts(hvcsd->vdev); + spin_unlock_irqrestore(&hvcsd->lock, flags); + } + + return hvcsd->todo_mask; + + bail: + spin_unlock_irqrestore(&hvcsd->lock, flags); + return hvcsd->todo_mask; +} + +static int khvcsd(void *unused) +{ + struct hvcs_struct *hvcsd; + int hvcs_todo_mask; + + __set_current_state(TASK_RUNNING); + + do { + hvcs_todo_mask = 0; + hvcs_kicked = 0; + wmb(); + + spin_lock(&hvcs_structs_lock); + list_for_each_entry(hvcsd, &hvcs_structs, next) { + hvcs_todo_mask |= hvcs_io(hvcsd); + } + spin_unlock(&hvcs_structs_lock); + + /* + * If any of the hvcs adapters want to try a write or quick read + * don't schedule(), yield a smidgen then execute the hvcs_io + * thread again for those that want the write. + */ + if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) { + yield(); + continue; + } + + set_current_state(TASK_INTERRUPTIBLE); + if (!hvcs_kicked) + schedule(); + __set_current_state(TASK_RUNNING); + } while (!kthread_should_stop()); + + return 0; +} + +static struct vio_device_id hvcs_driver_table[] __devinitdata= { + {"serial-server", "hvterm2"}, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, hvcs_driver_table); + +static void hvcs_return_index(int index) +{ + /* Paranoia check */ + if (!hvcs_index_list) + return; + if (index < 0 || index >= hvcs_index_count) + return; + if (hvcs_index_list[index] == -1) + return; + else + hvcs_index_list[index] = -1; +} + +/* callback when the kref ref count reaches zero */ +static void destroy_hvcs_struct(struct kref *kref) +{ + struct hvcs_struct *hvcsd = from_kref(kref); + struct vio_dev *vdev; + unsigned long flags; + + spin_lock(&hvcs_structs_lock); + spin_lock_irqsave(&hvcsd->lock, flags); + + /* the list_del poisons the pointers */ + list_del(&(hvcsd->next)); + + if (hvcsd->connected == 1) { + hvcs_partner_free(hvcsd); + printk(KERN_INFO "HVCS: Closed vty-server@%X and" + " partner vty@%X:%d connection.\n", + hvcsd->vdev->unit_address, + hvcsd->p_unit_address, + (uint32_t)hvcsd->p_partition_ID); + } + printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n", + hvcsd->vdev->unit_address); + + vdev = hvcsd->vdev; + hvcsd->vdev = NULL; + + hvcsd->p_unit_address = 0; + hvcsd->p_partition_ID = 0; + hvcs_return_index(hvcsd->index); + memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1); + + spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcs_structs_lock); + + sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); + + kfree(hvcsd); +} + +static int hvcs_get_index(void) +{ + int i; + /* Paranoia check */ + if (!hvcs_index_list) { + printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n"); + return -EFAULT; + } + /* Find the numerically lowest first free index. */ + for(i = 0; i < hvcs_index_count; i++) { + if (hvcs_index_list[i] == -1) { + hvcs_index_list[i] = 0; + return i; + } + } + return -1; +} + +static int __devinit hvcs_probe( + struct vio_dev *dev, + const struct vio_device_id *id) +{ + struct hvcs_struct *hvcsd; + int index; + int retval; + + if (!dev || !id) { + printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); + return -EPERM; + } + + /* early to avoid cleanup on failure */ + index = hvcs_get_index(); + if (index < 0) { + return -EFAULT; + } + + hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL); + if (!hvcsd) + return -ENODEV; + + + spin_lock_init(&hvcsd->lock); + /* Automatically incs the refcount the first time */ + kref_init(&hvcsd->kref); + + hvcsd->vdev = dev; + dev_set_drvdata(&dev->dev, hvcsd); + + hvcsd->index = index; + + /* hvcsd->index = ++hvcs_struct_count; */ + hvcsd->chars_in_buffer = 0; + hvcsd->todo_mask = 0; + hvcsd->connected = 0; + + /* + * This will populate the hvcs_struct's partner info fields for the + * first time. + */ + if (hvcs_get_pi(hvcsd)) { + printk(KERN_ERR "HVCS: Failed to fetch partner" + " info for vty-server@%X on device probe.\n", + hvcsd->vdev->unit_address); + } + + /* + * If a user app opens a tty that corresponds to this vty-server before + * the hvcs_struct has been added to the devices list then the user app + * will get -ENODEV. + */ + spin_lock(&hvcs_structs_lock); + list_add_tail(&(hvcsd->next), &hvcs_structs); + spin_unlock(&hvcs_structs_lock); + + retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group); + if (retval) { + printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n", + hvcsd->vdev->unit_address); + return retval; + } + + printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); + + /* + * DON'T enable interrupts here because there is no user to receive the + * data. + */ + return 0; +} + +static int __devexit hvcs_remove(struct vio_dev *dev) +{ + struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); + unsigned long flags; + struct tty_struct *tty; + + if (!hvcsd) + return -ENODEV; + + /* By this time the vty-server won't be getting any more interrupts */ + + spin_lock_irqsave(&hvcsd->lock, flags); + + tty = hvcsd->tty; + + spin_unlock_irqrestore(&hvcsd->lock, flags); + + /* + * Let the last holder of this object cause it to be removed, which + * would probably be tty_hangup below. + */ + kref_put(&hvcsd->kref, destroy_hvcs_struct); + + /* + * The hangup is a scheduled function which will auto chain call + * hvcs_hangup. The tty should always be valid at this time unless a + * simultaneous tty close already cleaned up the hvcs_struct. + */ + if (tty) + tty_hangup(tty); + + printk(KERN_INFO "HVCS: vty-server@%X removed from the" + " vio bus.\n", dev->unit_address); + return 0; +}; + +static struct vio_driver hvcs_vio_driver = { + .id_table = hvcs_driver_table, + .probe = hvcs_probe, + .remove = __devexit_p(hvcs_remove), + .driver = { + .name = hvcs_driver_name, + .owner = THIS_MODULE, + } +}; + +/* Only called from hvcs_get_pi please */ +static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) +{ + int clclength; + + hvcsd->p_unit_address = pi->unit_address; + hvcsd->p_partition_ID = pi->partition_ID; + clclength = strlen(&pi->location_code[0]); + if (clclength > HVCS_CLC_LENGTH) + clclength = HVCS_CLC_LENGTH; + + /* copy the null-term char too */ + strncpy(&hvcsd->p_location_code[0], + &pi->location_code[0], clclength + 1); +} + +/* + * Traverse the list and add the partner info that is found to the hvcs_struct + * struct entry. NOTE: At this time I know that partner info will return a + * single entry but in the future there may be multiple partner info entries per + * vty-server and you'll want to zero out that list and reset it. If for some + * reason you have an old version of this driver but there IS more than one + * partner info then hvcsd->p_* will hold the last partner info data from the + * firmware query. A good way to update this code would be to replace the three + * partner info fields in hvcs_struct with a list of hvcs_partner_info + * instances. + * + * This function must be called with the hvcsd->lock held. + */ +static int hvcs_get_pi(struct hvcs_struct *hvcsd) +{ + struct hvcs_partner_info *pi; + uint32_t unit_address = hvcsd->vdev->unit_address; + struct list_head head; + int retval; + + spin_lock(&hvcs_pi_lock); + if (!hvcs_pi_buff) { + spin_unlock(&hvcs_pi_lock); + return -EFAULT; + } + retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff); + spin_unlock(&hvcs_pi_lock); + if (retval) { + printk(KERN_ERR "HVCS: Failed to fetch partner" + " info for vty-server@%x.\n", unit_address); + return retval; + } + + /* nixes the values if the partner vty went away */ + hvcsd->p_unit_address = 0; + hvcsd->p_partition_ID = 0; + + list_for_each_entry(pi, &head, node) + hvcs_set_pi(pi, hvcsd); + + hvcs_free_partner_info(&head); + return 0; +} + +/* + * This function is executed by the driver "rescan" sysfs entry. It shouldn't + * be executed elsewhere, in order to prevent deadlock issues. + */ +static int hvcs_rescan_devices_list(void) +{ + struct hvcs_struct *hvcsd; + unsigned long flags; + + spin_lock(&hvcs_structs_lock); + + list_for_each_entry(hvcsd, &hvcs_structs, next) { + spin_lock_irqsave(&hvcsd->lock, flags); + hvcs_get_pi(hvcsd); + spin_unlock_irqrestore(&hvcsd->lock, flags); + } + + spin_unlock(&hvcs_structs_lock); + + return 0; +} + +/* + * Farm this off into its own function because it could be more complex once + * multiple partners support is added. This function should be called with + * the hvcsd->lock held. + */ +static int hvcs_has_pi(struct hvcs_struct *hvcsd) +{ + if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID)) + return 0; + return 1; +} + +/* + * NOTE: It is possible that the super admin removed a partner vty and then + * added a different vty as the new partner. + * + * This function must be called with the hvcsd->lock held. + */ +static int hvcs_partner_connect(struct hvcs_struct *hvcsd) +{ + int retval; + unsigned int unit_address = hvcsd->vdev->unit_address; + + /* + * If there wasn't any pi when the device was added it doesn't meant + * there isn't any now. This driver isn't notified when a new partner + * vty is added to a vty-server so we discover changes on our own. + * Please see comments in hvcs_register_connection() for justification + * of this bizarre code. + */ + retval = hvcs_register_connection(unit_address, + hvcsd->p_partition_ID, + hvcsd->p_unit_address); + if (!retval) { + hvcsd->connected = 1; + return 0; + } else if (retval != -EINVAL) + return retval; + + /* + * As per the spec re-get the pi and try again if -EINVAL after the + * first connection attempt. + */ + if (hvcs_get_pi(hvcsd)) + return -ENOMEM; + + if (!hvcs_has_pi(hvcsd)) + return -ENODEV; + + retval = hvcs_register_connection(unit_address, + hvcsd->p_partition_ID, + hvcsd->p_unit_address); + if (retval != -EINVAL) { + hvcsd->connected = 1; + return retval; + } + + /* + * EBUSY is the most likely scenario though the vty could have been + * removed or there really could be an hcall error due to the parameter + * data but thanks to ambiguous firmware return codes we can't really + * tell. + */ + printk(KERN_INFO "HVCS: vty-server or partner" + " vty is busy. Try again later.\n"); + return -EBUSY; +} + +/* This function must be called with the hvcsd->lock held */ +static void hvcs_partner_free(struct hvcs_struct *hvcsd) +{ + int retval; + do { + retval = hvcs_free_connection(hvcsd->vdev->unit_address); + } while (retval == -EBUSY); + hvcsd->connected = 0; +} + +/* This helper function must be called WITHOUT the hvcsd->lock held */ +static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, + unsigned int irq, struct vio_dev *vdev) +{ + unsigned long flags; + int rc; + + /* + * It is possible that the vty-server was removed between the time that + * the conn was registered and now. + */ + if (!(rc = request_irq(irq, &hvcs_handle_interrupt, + IRQF_DISABLED, "ibmhvcs", hvcsd))) { + /* + * It is possible the vty-server was removed after the irq was + * requested but before we have time to enable interrupts. + */ + if (vio_enable_interrupts(vdev) == H_SUCCESS) + return 0; + else { + printk(KERN_ERR "HVCS: int enable failed for" + " vty-server@%X.\n", unit_address); + free_irq(irq, hvcsd); + } + } else + printk(KERN_ERR "HVCS: irq req failed for" + " vty-server@%X.\n", unit_address); + + spin_lock_irqsave(&hvcsd->lock, flags); + hvcs_partner_free(hvcsd); + spin_unlock_irqrestore(&hvcsd->lock, flags); + + return rc; + +} + +/* + * This always increments the kref ref count if the call is successful. + * Please remember to dec when you are done with the instance. + * + * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when + * calling this function or you will get deadlock. + */ +static struct hvcs_struct *hvcs_get_by_index(int index) +{ + struct hvcs_struct *hvcsd = NULL; + unsigned long flags; + + spin_lock(&hvcs_structs_lock); + /* We can immediately discard OOB requests */ + if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { + list_for_each_entry(hvcsd, &hvcs_structs, next) { + spin_lock_irqsave(&hvcsd->lock, flags); + if (hvcsd->index == index) { + kref_get(&hvcsd->kref); + spin_unlock_irqrestore(&hvcsd->lock, flags); + spin_unlock(&hvcs_structs_lock); + return hvcsd; + } + spin_unlock_irqrestore(&hvcsd->lock, flags); + } + hvcsd = NULL; + } + + spin_unlock(&hvcs_structs_lock); + return hvcsd; +} + +/* + * 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; + int rc, retval = 0; + unsigned long flags; + unsigned int irq; + struct vio_dev *vdev; + unsigned long unit_address; + + if (tty->driver_data) + goto fast_open; + + /* + * Is there a vty-server that shares the same index? + * This function increments the kref index. + */ + if (!(hvcsd = hvcs_get_by_index(tty->index))) { + printk(KERN_WARNING "HVCS: open failed, no device associated" + " with tty->index %d.\n", tty->index); + return -ENODEV; + } + + spin_lock_irqsave(&hvcsd->lock, flags); + + if (hvcsd->connected == 0) + if ((retval = hvcs_partner_connect(hvcsd))) + goto error_release; + + hvcsd->open_count = 1; + hvcsd->tty = tty; + tty->driver_data = hvcsd; + + memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); + + /* + * Save these in the spinlock for the enable operations that need them + * outside of the spinlock. + */ + irq = hvcsd->vdev->irq; + vdev = hvcsd->vdev; + unit_address = hvcsd->vdev->unit_address; + + hvcsd->todo_mask |= HVCS_SCHED_READ; + spin_unlock_irqrestore(&hvcsd->lock, flags); + + /* + * 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)))) { + kref_put(&hvcsd->kref, destroy_hvcs_struct); + printk(KERN_WARNING "HVCS: enable device failed.\n"); + return rc; + } + + goto open_success; + +fast_open: + hvcsd = tty->driver_data; + + spin_lock_irqsave(&hvcsd->lock, flags); + kref_get(&hvcsd->kref); + hvcsd->open_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; + +error_release: + spin_unlock_irqrestore(&hvcsd->lock, flags); + kref_put(&hvcsd->kref, destroy_hvcs_struct); + + printk(KERN_WARNING "HVCS: partner connect failed.\n"); + return retval; +} + +static void hvcs_close(struct tty_struct *tty, struct file *filp) +{ + struct hvcs_struct *hvcsd; + unsigned long flags; + int irq = NO_IRQ; + + /* + * Is someone trying to close the file associated with this device after + * we have hung up? If so tty->driver_data wouldn't be valid. + */ + if (tty_hung_up_p(filp)) + return; + + /* + * No driver_data means that this close was probably issued after a + * failed hvcs_open by the tty layer's release_dev() api and we can just + * exit cleanly. + */ + if (!tty->driver_data) + return; + + hvcsd = tty->driver_data; + + spin_lock_irqsave(&hvcsd->lock, flags); + if (--hvcsd->open_count == 0) { + + vio_disable_interrupts(hvcsd->vdev); + + /* + * NULL this early so that the kernel_thread doesn't try to + * execute any operations on the TTY even though it is obligated + * to deliver any pending I/O to the hypervisor. + */ + hvcsd->tty = NULL; + + irq = hvcsd->vdev->irq; + spin_unlock_irqrestore(&hvcsd->lock, flags); + + tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); + + /* + * This line is important because it tells hvcs_open that this + * device needs to be re-configured the next time hvcs_open is + * called. + */ + tty->driver_data = NULL; + + free_irq(irq, hvcsd); + kref_put(&hvcsd->kref, destroy_hvcs_struct); + return; + } else if (hvcsd->open_count < 0) { + printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" + " is missmanaged.\n", + hvcsd->vdev->unit_address, hvcsd->open_count); + } + + spin_unlock_irqrestore(&hvcsd->lock, flags); + kref_put(&hvcsd->kref, destroy_hvcs_struct); +} + +static void hvcs_hangup(struct tty_struct * tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned long flags; + int temp_open_count; + int irq = NO_IRQ; + + spin_lock_irqsave(&hvcsd->lock, flags); + /* Preserve this so that we know how many kref refs to put */ + temp_open_count = hvcsd->open_count; + + /* + * Don't kref put inside the spinlock because the destruction + * callback may use the spinlock and it may get called before the + * spinlock has been released. + */ + vio_disable_interrupts(hvcsd->vdev); + + hvcsd->todo_mask = 0; + + /* I don't think the tty needs the hvcs_struct pointer after a hangup */ + hvcsd->tty->driver_data = NULL; + hvcsd->tty = NULL; + + hvcsd->open_count = 0; + + /* This will drop any buffered data on the floor which is OK in a hangup + * scenario. */ + memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); + hvcsd->chars_in_buffer = 0; + + irq = hvcsd->vdev->irq; + + spin_unlock_irqrestore(&hvcsd->lock, flags); + + free_irq(irq, hvcsd); + + /* + * We need to kref_put() for every open_count we have since the + * tty_hangup() function doesn't invoke a close per open connection on a + * non-console device. + */ + while(temp_open_count) { + --temp_open_count; + /* + * The final put will trigger destruction of the hvcs_struct. + * NOTE: If this hangup was signaled from user space then the + * final put will never happen. + */ + kref_put(&hvcsd->kref, destroy_hvcs_struct); + } +} + +/* + * NOTE: This is almost always from_user since user level apps interact with the + * /dev nodes. I'm trusting that if hvcs_write gets called and interrupted by + * hvcs_remove (which removes the target device and executes tty_hangup()) that + * tty_hangup will allow hvcs_write time to complete execution before it + * terminates our device. + */ +static int hvcs_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned int unit_address; + const unsigned char *charbuf; + unsigned long flags; + int total_sent = 0; + int tosend = 0; + int result = 0; + + /* + * If they don't check the return code off of their open they may + * attempt this even if there is no connected device. + */ + if (!hvcsd) + return -ENODEV; + + /* Reasonable size to prevent user level flooding */ + if (count > HVCS_MAX_FROM_USER) { + printk(KERN_WARNING "HVCS write: count being truncated to" + " HVCS_MAX_FROM_USER.\n"); + count = HVCS_MAX_FROM_USER; + } + + charbuf = buf; + + spin_lock_irqsave(&hvcsd->lock, flags); + + /* + * Somehow an open succedded but the device was removed or the + * connection terminated between the vty-server and partner vty during + * the middle of a write operation? This is a crummy place to do this + * but we want to keep it all in the spinlock. + */ + if (hvcsd->open_count <= 0) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + return -ENODEV; + } + + unit_address = hvcsd->vdev->unit_address; + + while (count > 0) { + tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer)); + /* + * No more space, this probably means that the last call to + * hvcs_write() didn't succeed and the buffer was filled up. + */ + if (!tosend) + break; + + memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer], + &charbuf[total_sent], + tosend); + + hvcsd->chars_in_buffer += tosend; + + result = 0; + + /* + * If this is true then we don't want to try writing to the + * hypervisor because that is the kernel_threads job now. We'll + * just add to the buffer. + */ + if (!(hvcsd->todo_mask & HVCS_TRY_WRITE)) + /* won't send partial writes */ + result = hvc_put_chars(unit_address, + &hvcsd->buffer[0], + hvcsd->chars_in_buffer); + + /* + * Since we know we have enough room in hvcsd->buffer for + * tosend we record that it was sent regardless of whether the + * hypervisor actually took it because we have it buffered. + */ + total_sent+=tosend; + count-=tosend; + if (result == 0) { + hvcsd->todo_mask |= HVCS_TRY_WRITE; + hvcs_kick(); + break; + } + + hvcsd->chars_in_buffer = 0; + /* + * Test after the chars_in_buffer reset otherwise this could + * deadlock our writes if hvc_put_chars fails. + */ + if (result < 0) + break; + } + + spin_unlock_irqrestore(&hvcsd->lock, flags); + + if (result == -1) + return -EIO; + else + return total_sent; +} + +/* + * This is really asking how much can we guarentee that we can send or that we + * absolutely WILL BUFFER if we can't send it. This driver MUST honor the + * return value, hence the reason for hvcs_struct buffering. + */ +static int hvcs_write_room(struct tty_struct *tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + + if (!hvcsd || hvcsd->open_count <= 0) + return 0; + + return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; +} + +static int hvcs_chars_in_buffer(struct tty_struct *tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + + return hvcsd->chars_in_buffer; +} + +static const struct tty_operations hvcs_ops = { + .open = hvcs_open, + .close = hvcs_close, + .hangup = hvcs_hangup, + .write = hvcs_write, + .write_room = hvcs_write_room, + .chars_in_buffer = hvcs_chars_in_buffer, + .unthrottle = hvcs_unthrottle, + .throttle = hvcs_throttle, +}; + +static int hvcs_alloc_index_list(int n) +{ + int i; + + hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); + if (!hvcs_index_list) + return -ENOMEM; + hvcs_index_count = n; + for (i = 0; i < hvcs_index_count; i++) + hvcs_index_list[i] = -1; + return 0; +} + +static void hvcs_free_index_list(void) +{ + /* Paranoia check to be thorough. */ + kfree(hvcs_index_list); + hvcs_index_list = NULL; + hvcs_index_count = 0; +} + +static int __init hvcs_module_init(void) +{ + int rc; + int num_ttys_to_alloc; + + printk(KERN_INFO "Initializing %s\n", hvcs_driver_string); + + /* Has the user specified an overload with an insmod param? */ + if (hvcs_parm_num_devs <= 0 || + (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) { + num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS; + } else + num_ttys_to_alloc = hvcs_parm_num_devs; + + hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc); + if (!hvcs_tty_driver) + return -ENOMEM; + + if (hvcs_alloc_index_list(num_ttys_to_alloc)) { + rc = -ENOMEM; + goto index_fail; + } + + hvcs_tty_driver->owner = THIS_MODULE; + + hvcs_tty_driver->driver_name = hvcs_driver_name; + hvcs_tty_driver->name = hvcs_device_node; + + /* + * We'll let the system assign us a major number, indicated by leaving + * it blank. + */ + + hvcs_tty_driver->minor_start = HVCS_MINOR_START; + hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; + + /* + * We role our own so that we DONT ECHO. We can't echo because the + * device we are connecting to already echoes by default and this would + * throw us into a horrible recursive echo-echo-echo loop. + */ + hvcs_tty_driver->init_termios = hvcs_tty_termios; + hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW; + + tty_set_operations(hvcs_tty_driver, &hvcs_ops); + + /* + * The following call will result in sysfs entries that denote the + * dynamically assigned major and minor numbers for our devices. + */ + if (tty_register_driver(hvcs_tty_driver)) { + printk(KERN_ERR "HVCS: registration as a tty driver failed.\n"); + rc = -EIO; + goto register_fail; + } + + hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!hvcs_pi_buff) { + rc = -ENOMEM; + goto buff_alloc_fail; + } + + hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); + if (IS_ERR(hvcs_task)) { + printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); + rc = -EIO; + goto kthread_fail; + } + + rc = vio_register_driver(&hvcs_vio_driver); + if (rc) { + printk(KERN_ERR "HVCS: can't register vio driver\n"); + goto vio_fail; + } + + /* + * This needs to be done AFTER the vio_register_driver() call or else + * the kobjects won't be initialized properly. + */ + rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); + if (rc) { + printk(KERN_ERR "HVCS: sysfs attr create failed\n"); + goto attr_fail; + } + + printk(KERN_INFO "HVCS: driver module inserted.\n"); + + return 0; + +attr_fail: + vio_unregister_driver(&hvcs_vio_driver); +vio_fail: + kthread_stop(hvcs_task); +kthread_fail: + kfree(hvcs_pi_buff); +buff_alloc_fail: + tty_unregister_driver(hvcs_tty_driver); +register_fail: + hvcs_free_index_list(); +index_fail: + put_tty_driver(hvcs_tty_driver); + hvcs_tty_driver = NULL; + return rc; +} + +static void __exit hvcs_module_exit(void) +{ + /* + * This driver receives hvcs_remove callbacks for each device upon + * module removal. + */ + + /* + * This synchronous operation will wake the khvcsd kthread if it is + * asleep and will return when khvcsd has terminated. + */ + kthread_stop(hvcs_task); + + spin_lock(&hvcs_pi_lock); + kfree(hvcs_pi_buff); + hvcs_pi_buff = NULL; + spin_unlock(&hvcs_pi_lock); + + driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); + + vio_unregister_driver(&hvcs_vio_driver); + + tty_unregister_driver(hvcs_tty_driver); + + hvcs_free_index_list(); + + put_tty_driver(hvcs_tty_driver); + + printk(KERN_INFO "HVCS: driver module removed.\n"); +} + +module_init(hvcs_module_init); +module_exit(hvcs_module_exit); diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c new file mode 100644 index 000000000000..67a75a502c01 --- /dev/null +++ b/drivers/tty/hvc/hvsi.c @@ -0,0 +1,1314 @@ +/* + * Copyright (C) 2004 Hollis Blanchard , IBM + * + * 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 + */ + +/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS + * and the service processor on IBM pSeries servers. On these servers, there + * are no serial ports under the OS's control, and sometimes there is no other + * console available either. However, the service processor has two standard + * serial ports, so this over-complicated protocol allows the OS to control + * those ports by proxy. + * + * Besides data, the procotol supports the reading/writing of the serial + * port's DTR line, and the reading of the CD line. This is to allow the OS to + * control a modem attached to the service processor's serial port. Note that + * the OS cannot change the speed of the port through this protocol. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HVSI_MAJOR 229 +#define HVSI_MINOR 128 +#define MAX_NR_HVSI_CONSOLES 4 + +#define HVSI_TIMEOUT (5*HZ) +#define HVSI_VERSION 1 +#define HVSI_MAX_PACKET 256 +#define HVSI_MAX_READ 16 +#define HVSI_MAX_OUTGOING_DATA 12 +#define N_OUTBUF 12 + +/* + * we pass data via two 8-byte registers, so we would like our char arrays + * properly aligned for those loads. + */ +#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) + +struct hvsi_struct { + struct delayed_work writer; + struct work_struct handshaker; + wait_queue_head_t emptyq; /* woken when outbuf is emptied */ + wait_queue_head_t stateq; /* woken when HVSI state changes */ + spinlock_t lock; + int index; + struct tty_struct *tty; + int count; + uint8_t throttle_buf[128]; + uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ + /* inbuf is for packet reassembly. leave a little room for leftovers. */ + uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ]; + uint8_t *inbuf_end; + int n_throttle; + int n_outbuf; + uint32_t vtermno; + uint32_t virq; + atomic_t seqno; /* HVSI packet sequence number */ + uint16_t mctrl; + uint8_t state; /* HVSI protocol state */ + uint8_t flags; +#ifdef CONFIG_MAGIC_SYSRQ + uint8_t sysrq; +#endif /* CONFIG_MAGIC_SYSRQ */ +}; +static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES]; + +static struct tty_driver *hvsi_driver; +static int hvsi_count; +static int (*hvsi_wait)(struct hvsi_struct *hp, int state); + +enum HVSI_PROTOCOL_STATE { + HVSI_CLOSED, + HVSI_WAIT_FOR_VER_RESPONSE, + HVSI_WAIT_FOR_VER_QUERY, + HVSI_OPEN, + HVSI_WAIT_FOR_MCTRL_RESPONSE, + HVSI_FSP_DIED, +}; +#define HVSI_CONSOLE 0x1 + +#define VS_DATA_PACKET_HEADER 0xff +#define VS_CONTROL_PACKET_HEADER 0xfe +#define VS_QUERY_PACKET_HEADER 0xfd +#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc + +/* control verbs */ +#define VSV_SET_MODEM_CTL 1 /* to service processor only */ +#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */ +#define VSV_CLOSE_PROTOCOL 3 + +/* query verbs */ +#define VSV_SEND_VERSION_NUMBER 1 +#define VSV_SEND_MODEM_CTL_STATUS 2 + +/* yes, these masks are not consecutive. */ +#define HVSI_TSDTR 0x01 +#define HVSI_TSCD 0x20 + +struct hvsi_header { + uint8_t type; + uint8_t len; + uint16_t seqno; +} __attribute__((packed)); + +struct hvsi_data { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint8_t data[HVSI_MAX_OUTGOING_DATA]; +} __attribute__((packed)); + +struct hvsi_control { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; + /* optional depending on verb: */ + uint32_t word; + uint32_t mask; +} __attribute__((packed)); + +struct hvsi_query { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; +} __attribute__((packed)); + +struct hvsi_query_response { + uint8_t type; + uint8_t len; + uint16_t seqno; + uint16_t verb; + uint16_t query_seqno; + union { + uint8_t version; + uint32_t mctrl_word; + } u; +} __attribute__((packed)); + + + +static inline int is_console(struct hvsi_struct *hp) +{ + return hp->flags & HVSI_CONSOLE; +} + +static inline int is_open(struct hvsi_struct *hp) +{ + /* if we're waiting for an mctrl then we're already open */ + return (hp->state == HVSI_OPEN) + || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE); +} + +static inline void print_state(struct hvsi_struct *hp) +{ +#ifdef DEBUG + static const char *state_names[] = { + "HVSI_CLOSED", + "HVSI_WAIT_FOR_VER_RESPONSE", + "HVSI_WAIT_FOR_VER_QUERY", + "HVSI_OPEN", + "HVSI_WAIT_FOR_MCTRL_RESPONSE", + "HVSI_FSP_DIED", + }; + const char *name = (hp->state < ARRAY_SIZE(state_names)) + ? state_names[hp->state] : "UNKNOWN"; + + pr_debug("hvsi%i: state = %s\n", hp->index, name); +#endif /* DEBUG */ +} + +static inline void __set_state(struct hvsi_struct *hp, int state) +{ + hp->state = state; + print_state(hp); + wake_up_all(&hp->stateq); +} + +static inline void set_state(struct hvsi_struct *hp, int state) +{ + unsigned long flags; + + spin_lock_irqsave(&hp->lock, flags); + __set_state(hp, state); + spin_unlock_irqrestore(&hp->lock, flags); +} + +static inline int len_packet(const uint8_t *packet) +{ + return (int)((struct hvsi_header *)packet)->len; +} + +static inline int is_header(const uint8_t *packet) +{ + struct hvsi_header *header = (struct hvsi_header *)packet; + return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER; +} + +static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet) +{ + if (hp->inbuf_end < packet + sizeof(struct hvsi_header)) + return 0; /* don't even have the packet header */ + + if (hp->inbuf_end < (packet + len_packet(packet))) + return 0; /* don't have the rest of the packet */ + + return 1; +} + +/* shift remaining bytes in packetbuf down */ +static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to) +{ + int remaining = (int)(hp->inbuf_end - read_to); + + pr_debug("%s: %i chars remain\n", __func__, remaining); + + if (read_to != hp->inbuf) + memmove(hp->inbuf, read_to, remaining); + + hp->inbuf_end = hp->inbuf + remaining; +} + +#ifdef DEBUG +#define dbg_dump_packet(packet) dump_packet(packet) +#define dbg_dump_hex(data, len) dump_hex(data, len) +#else +#define dbg_dump_packet(packet) do { } while (0) +#define dbg_dump_hex(data, len) do { } while (0) +#endif + +static void dump_hex(const uint8_t *data, int len) +{ + int i; + + printk(" "); + for (i=0; i < len; i++) + printk("%.2x", data[i]); + + printk("\n "); + for (i=0; i < len; i++) { + if (isprint(data[i])) + printk("%c", data[i]); + else + printk("."); + } + printk("\n"); +} + +static void dump_packet(uint8_t *packet) +{ + struct hvsi_header *header = (struct hvsi_header *)packet; + + printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len, + header->seqno); + + dump_hex(packet, header->len); +} + +static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) +{ + unsigned long got; + + got = hvc_get_chars(hp->vtermno, buf, count); + + return got; +} + +static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, + struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) +{ + struct hvsi_control *header = (struct hvsi_control *)packet; + + switch (header->verb) { + case VSV_MODEM_CTL_UPDATE: + if ((header->word & HVSI_TSCD) == 0) { + /* CD went away; no more connection */ + pr_debug("hvsi%i: CD dropped\n", hp->index); + hp->mctrl &= TIOCM_CD; + /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ + if (hp->tty && !(hp->tty->flags & CLOCAL)) + *to_hangup = hp->tty; + } + break; + case VSV_CLOSE_PROTOCOL: + pr_debug("hvsi%i: service processor came back\n", hp->index); + if (hp->state != HVSI_CLOSED) { + *to_handshake = hp; + } + break; + default: + printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ", + hp->index); + dump_packet(packet); + break; + } +} + +static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet) +{ + struct hvsi_query_response *resp = (struct hvsi_query_response *)packet; + + switch (hp->state) { + case HVSI_WAIT_FOR_VER_RESPONSE: + __set_state(hp, HVSI_WAIT_FOR_VER_QUERY); + break; + case HVSI_WAIT_FOR_MCTRL_RESPONSE: + hp->mctrl = 0; + if (resp->u.mctrl_word & HVSI_TSDTR) + hp->mctrl |= TIOCM_DTR; + if (resp->u.mctrl_word & HVSI_TSCD) + hp->mctrl |= TIOCM_CD; + __set_state(hp, HVSI_OPEN); + break; + default: + printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index); + dump_packet(packet); + break; + } +} + +/* respond to service processor's version query */ +static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) +{ + struct hvsi_query_response packet __ALIGNED__; + int wrote; + + packet.type = VS_QUERY_RESPONSE_PACKET_HEADER; + packet.len = sizeof(struct hvsi_query_response); + packet.seqno = atomic_inc_return(&hp->seqno); + packet.verb = VSV_SEND_VERSION_NUMBER; + packet.u.version = HVSI_VERSION; + packet.query_seqno = query_seqno+1; + + pr_debug("%s: sending %i bytes\n", __func__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't send query response!\n", + hp->index); + return -EIO; + } + + return 0; +} + +static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) +{ + struct hvsi_query *query = (struct hvsi_query *)packet; + + switch (hp->state) { + case HVSI_WAIT_FOR_VER_QUERY: + hvsi_version_respond(hp, query->seqno); + __set_state(hp, HVSI_OPEN); + break; + default: + printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index); + dump_packet(packet); + break; + } +} + +static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +{ + int i; + + for (i=0; i < len; i++) { + char c = buf[i]; +#ifdef CONFIG_MAGIC_SYSRQ + if (c == '\0') { + hp->sysrq = 1; + continue; + } else if (hp->sysrq) { + handle_sysrq(c); + hp->sysrq = 0; + continue; + } +#endif /* CONFIG_MAGIC_SYSRQ */ + tty_insert_flip_char(hp->tty, c, 0); + } +} + +/* + * We could get 252 bytes of data at once here. But the tty layer only + * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow + * it. Accordingly we won't send more than 128 bytes at a time to the flip + * buffer, which will give the tty buffer a chance to throttle us. Should the + * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be + * revisited. + */ +#define TTY_THRESHOLD_THROTTLE 128 +static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, + const uint8_t *packet) +{ + const struct hvsi_header *header = (const struct hvsi_header *)packet; + const uint8_t *data = packet + sizeof(struct hvsi_header); + int datalen = header->len - sizeof(struct hvsi_header); + int overflow = datalen - TTY_THRESHOLD_THROTTLE; + + pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); + + if (datalen == 0) + return NULL; + + if (overflow > 0) { + pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); + datalen = TTY_THRESHOLD_THROTTLE; + } + + hvsi_insert_chars(hp, data, datalen); + + if (overflow > 0) { + /* + * we still have more data to deliver, so we need to save off the + * overflow and send it later + */ + pr_debug("%s: deferring overflow\n", __func__); + memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow); + hp->n_throttle = overflow; + } + + return hp->tty; +} + +/* + * Returns true/false indicating data successfully read from hypervisor. + * Used both to get packets for tty connections and to advance the state + * machine during console handshaking (in which case tty = NULL and we ignore + * incoming data). + */ +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, + struct tty_struct **hangup, struct hvsi_struct **handshake) +{ + uint8_t *packet = hp->inbuf; + int chunklen; + + *flip = NULL; + *hangup = NULL; + *handshake = NULL; + + chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); + if (chunklen == 0) { + pr_debug("%s: 0-length read\n", __func__); + return 0; + } + + pr_debug("%s: got %i bytes\n", __func__, chunklen); + dbg_dump_hex(hp->inbuf_end, chunklen); + + hp->inbuf_end += chunklen; + + /* handle all completed packets */ + while ((packet < hp->inbuf_end) && got_packet(hp, packet)) { + struct hvsi_header *header = (struct hvsi_header *)packet; + + if (!is_header(packet)) { + printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index); + /* skip bytes until we find a header or run out of data */ + while ((packet < hp->inbuf_end) && (!is_header(packet))) + packet++; + continue; + } + + pr_debug("%s: handling %i-byte packet\n", __func__, + len_packet(packet)); + dbg_dump_packet(packet); + + switch (header->type) { + case VS_DATA_PACKET_HEADER: + if (!is_open(hp)) + break; + if (hp->tty == NULL) + break; /* no tty buffer to put data in */ + *flip = hvsi_recv_data(hp, packet); + break; + case VS_CONTROL_PACKET_HEADER: + hvsi_recv_control(hp, packet, hangup, handshake); + break; + case VS_QUERY_RESPONSE_PACKET_HEADER: + hvsi_recv_response(hp, packet); + break; + case VS_QUERY_PACKET_HEADER: + hvsi_recv_query(hp, packet); + break; + default: + printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n", + hp->index, header->type); + dump_packet(packet); + break; + } + + packet += len_packet(packet); + + if (*hangup || *handshake) { + pr_debug("%s: hangup or handshake\n", __func__); + /* + * we need to send the hangup now before receiving any more data. + * If we get "data, hangup, data", we can't deliver the second + * data before the hangup. + */ + break; + } + } + + compact_inbuf(hp, packet); + + return 1; +} + +static void hvsi_send_overflow(struct hvsi_struct *hp) +{ + pr_debug("%s: delivering %i bytes overflow\n", __func__, + hp->n_throttle); + + hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); + hp->n_throttle = 0; +} + +/* + * must get all pending data because we only get an irq on empty->non-empty + * transition + */ +static irqreturn_t hvsi_interrupt(int irq, void *arg) +{ + struct hvsi_struct *hp = (struct hvsi_struct *)arg; + struct tty_struct *flip; + struct tty_struct *hangup; + struct hvsi_struct *handshake; + unsigned long flags; + int again = 1; + + pr_debug("%s\n", __func__); + + while (again) { + spin_lock_irqsave(&hp->lock, flags); + again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); + spin_unlock_irqrestore(&hp->lock, flags); + + /* + * we have to call tty_flip_buffer_push() and tty_hangup() outside our + * spinlock. But we also have to keep going until we've read all the + * available data. + */ + + if (flip) { + /* there was data put in the tty flip buffer */ + tty_flip_buffer_push(flip); + flip = NULL; + } + + if (hangup) { + tty_hangup(hangup); + } + + if (handshake) { + pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); + schedule_work(&handshake->handshaker); + } + } + + spin_lock_irqsave(&hp->lock, flags); + if (hp->tty && hp->n_throttle + && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { + /* we weren't hung up and we weren't throttled, so we can deliver the + * rest now */ + flip = hp->tty; + hvsi_send_overflow(hp); + } + spin_unlock_irqrestore(&hp->lock, flags); + + if (flip) { + tty_flip_buffer_push(flip); + } + + return IRQ_HANDLED; +} + +/* for boot console, before the irq handler is running */ +static int __init poll_for_state(struct hvsi_struct *hp, int state) +{ + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + + for (;;) { + hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */ + + if (hp->state == state) + return 0; + + mdelay(5); + if (time_after(jiffies, end_jiffies)) + return -EIO; + } +} + +/* wait for irq handler to change our state */ +static int wait_for_state(struct hvsi_struct *hp, int state) +{ + int ret = 0; + + if (!wait_event_timeout(hp->stateq, (hp->state == state), HVSI_TIMEOUT)) + ret = -EIO; + + return ret; +} + +static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) +{ + struct hvsi_query packet __ALIGNED__; + int wrote; + + packet.type = VS_QUERY_PACKET_HEADER; + packet.len = sizeof(struct hvsi_query); + packet.seqno = atomic_inc_return(&hp->seqno); + packet.verb = verb; + + pr_debug("%s: sending %i bytes\n", __func__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index, + wrote); + return -EIO; + } + + return 0; +} + +static int hvsi_get_mctrl(struct hvsi_struct *hp) +{ + int ret; + + set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE); + hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS); + + ret = hvsi_wait(hp, HVSI_OPEN); + if (ret < 0) { + printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index); + set_state(hp, HVSI_OPEN); + return ret; + } + + pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl); + + return 0; +} + +/* note that we can only set DTR */ +static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) +{ + struct hvsi_control packet __ALIGNED__; + int wrote; + + packet.type = VS_CONTROL_PACKET_HEADER, + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = sizeof(struct hvsi_control); + packet.verb = VSV_SET_MODEM_CTL; + packet.mask = HVSI_TSDTR; + + if (mctrl & TIOCM_DTR) + packet.word = HVSI_TSDTR; + + pr_debug("%s: sending %i bytes\n", __func__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (wrote != packet.len) { + printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index); + return -EIO; + } + + return 0; +} + +static void hvsi_drain_input(struct hvsi_struct *hp) +{ + uint8_t buf[HVSI_MAX_READ] __ALIGNED__; + unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; + + while (time_before(end_jiffies, jiffies)) + if (0 == hvsi_read(hp, buf, HVSI_MAX_READ)) + break; +} + +static int hvsi_handshake(struct hvsi_struct *hp) +{ + int ret; + + /* + * We could have a CLOSE or other data waiting for us before we even try + * to open; try to throw it all away so we don't get confused. (CLOSE + * is the first message sent up the pipe when the FSP comes online. We + * need to distinguish between "it came up a while ago and we're the first + * user" and "it was just reset before it saw our handshake packet".) + */ + hvsi_drain_input(hp); + + set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE); + ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER); + if (ret < 0) { + printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index); + return ret; + } + + ret = hvsi_wait(hp, HVSI_OPEN); + if (ret < 0) + return ret; + + return 0; +} + +static void hvsi_handshaker(struct work_struct *work) +{ + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, handshaker); + + if (hvsi_handshake(hp) >= 0) + return; + + printk(KERN_ERR "hvsi%i: re-handshaking failed\n", hp->index); + if (is_console(hp)) { + /* + * ttys will re-attempt the handshake via hvsi_open, but + * the console will not. + */ + printk(KERN_ERR "hvsi%i: lost console!\n", hp->index); + } +} + +static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) +{ + struct hvsi_data packet __ALIGNED__; + int ret; + + BUG_ON(count > HVSI_MAX_OUTGOING_DATA); + + packet.type = VS_DATA_PACKET_HEADER; + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = count + sizeof(struct hvsi_header); + memcpy(&packet.data, buf, count); + + ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + if (ret == packet.len) { + /* return the number of chars written, not the packet length */ + return count; + } + return ret; /* return any errors */ +} + +static void hvsi_close_protocol(struct hvsi_struct *hp) +{ + struct hvsi_control packet __ALIGNED__; + + packet.type = VS_CONTROL_PACKET_HEADER; + packet.seqno = atomic_inc_return(&hp->seqno); + packet.len = 6; + packet.verb = VSV_CLOSE_PROTOCOL; + + pr_debug("%s: sending %i bytes\n", __func__, packet.len); + dbg_dump_hex((uint8_t*)&packet, packet.len); + + hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); +} + +static int hvsi_open(struct tty_struct *tty, struct file *filp) +{ + struct hvsi_struct *hp; + unsigned long flags; + int line = tty->index; + int ret; + + pr_debug("%s\n", __func__); + + if (line < 0 || line >= hvsi_count) + return -ENODEV; + hp = &hvsi_ports[line]; + + tty->driver_data = hp; + + mb(); + if (hp->state == HVSI_FSP_DIED) + return -EIO; + + spin_lock_irqsave(&hp->lock, flags); + hp->tty = tty; + hp->count++; + atomic_set(&hp->seqno, 0); + h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); + spin_unlock_irqrestore(&hp->lock, flags); + + if (is_console(hp)) + return 0; /* this has already been handshaked as the console */ + + ret = hvsi_handshake(hp); + if (ret < 0) { + printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name); + return ret; + } + + ret = hvsi_get_mctrl(hp); + if (ret < 0) { + printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name); + return ret; + } + + ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); + if (ret < 0) { + printk(KERN_ERR "%s: couldn't set DTR\n", tty->name); + return ret; + } + + return 0; +} + +/* wait for hvsi_write_worker to empty hp->outbuf */ +static void hvsi_flush_output(struct hvsi_struct *hp) +{ + wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT); + + /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ + cancel_delayed_work_sync(&hp->writer); + flush_work_sync(&hp->handshaker); + + /* + * it's also possible that our timeout expired and hvsi_write_worker + * didn't manage to push outbuf. poof. + */ + hp->n_outbuf = 0; +} + +static void hvsi_close(struct tty_struct *tty, struct file *filp) +{ + struct hvsi_struct *hp = tty->driver_data; + unsigned long flags; + + pr_debug("%s\n", __func__); + + if (tty_hung_up_p(filp)) + return; + + spin_lock_irqsave(&hp->lock, flags); + + if (--hp->count == 0) { + hp->tty = NULL; + hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ + + /* only close down connection if it is not the console */ + if (!is_console(hp)) { + h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */ + __set_state(hp, HVSI_CLOSED); + /* + * any data delivered to the tty layer after this will be + * discarded (except for XON/XOFF) + */ + tty->closing = 1; + + spin_unlock_irqrestore(&hp->lock, flags); + + /* let any existing irq handlers finish. no more will start. */ + synchronize_irq(hp->virq); + + /* hvsi_write_worker will re-schedule until outbuf is empty. */ + hvsi_flush_output(hp); + + /* tell FSP to stop sending data */ + hvsi_close_protocol(hp); + + /* + * drain anything FSP is still in the middle of sending, and let + * hvsi_handshake drain the rest on the next open. + */ + hvsi_drain_input(hp); + + spin_lock_irqsave(&hp->lock, flags); + } + } else if (hp->count < 0) + printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", + hp - hvsi_ports, hp->count); + + spin_unlock_irqrestore(&hp->lock, flags); +} + +static void hvsi_hangup(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + unsigned long flags; + + pr_debug("%s\n", __func__); + + spin_lock_irqsave(&hp->lock, flags); + + hp->count = 0; + hp->n_outbuf = 0; + hp->tty = NULL; + + spin_unlock_irqrestore(&hp->lock, flags); +} + +/* called with hp->lock held */ +static void hvsi_push(struct hvsi_struct *hp) +{ + int n; + + if (hp->n_outbuf <= 0) + return; + + n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf); + if (n > 0) { + /* success */ + pr_debug("%s: wrote %i chars\n", __func__, n); + hp->n_outbuf = 0; + } else if (n == -EIO) { + __set_state(hp, HVSI_FSP_DIED); + printk(KERN_ERR "hvsi%i: service processor died\n", hp->index); + } +} + +/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */ +static void hvsi_write_worker(struct work_struct *work) +{ + struct hvsi_struct *hp = + container_of(work, struct hvsi_struct, writer.work); + unsigned long flags; +#ifdef DEBUG + static long start_j = 0; + + if (start_j == 0) + start_j = jiffies; +#endif /* DEBUG */ + + spin_lock_irqsave(&hp->lock, flags); + + pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf); + + if (!is_open(hp)) { + /* + * We could have a non-open connection if the service processor died + * while we were busily scheduling ourselves. In that case, it could + * be minutes before the service processor comes back, so only try + * again once a second. + */ + schedule_delayed_work(&hp->writer, HZ); + goto out; + } + + hvsi_push(hp); + if (hp->n_outbuf > 0) + schedule_delayed_work(&hp->writer, 10); + else { +#ifdef DEBUG + pr_debug("%s: outbuf emptied after %li jiffies\n", __func__, + jiffies - start_j); + start_j = 0; +#endif /* DEBUG */ + wake_up_all(&hp->emptyq); + tty_wakeup(hp->tty); + } + +out: + spin_unlock_irqrestore(&hp->lock, flags); +} + +static int hvsi_write_room(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + + return N_OUTBUF - hp->n_outbuf; +} + +static int hvsi_chars_in_buffer(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + + return hp->n_outbuf; +} + +static int hvsi_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + struct hvsi_struct *hp = tty->driver_data; + const char *source = buf; + unsigned long flags; + int total = 0; + int origcount = count; + + spin_lock_irqsave(&hp->lock, flags); + + pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf); + + if (!is_open(hp)) { + /* we're either closing or not yet open; don't accept data */ + pr_debug("%s: not open\n", __func__); + goto out; + } + + /* + * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf + * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls + * will see there is no room in outbuf and return. + */ + while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { + int chunksize = min(count, hvsi_write_room(hp->tty)); + + BUG_ON(hp->n_outbuf < 0); + memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); + hp->n_outbuf += chunksize; + + total += chunksize; + source += chunksize; + count -= chunksize; + hvsi_push(hp); + } + + if (hp->n_outbuf > 0) { + /* + * we weren't able to write it all to the hypervisor. + * schedule another push attempt. + */ + schedule_delayed_work(&hp->writer, 10); + } + +out: + spin_unlock_irqrestore(&hp->lock, flags); + + if (total != origcount) + pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount, + total); + + return total; +} + +/* + * I have never seen throttle or unthrottle called, so this little throttle + * buffering scheme may or may not work. + */ +static void hvsi_throttle(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + + pr_debug("%s\n", __func__); + + h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); +} + +static void hvsi_unthrottle(struct tty_struct *tty) +{ + struct hvsi_struct *hp = tty->driver_data; + unsigned long flags; + int shouldflip = 0; + + pr_debug("%s\n", __func__); + + spin_lock_irqsave(&hp->lock, flags); + if (hp->n_throttle) { + hvsi_send_overflow(hp); + shouldflip = 1; + } + spin_unlock_irqrestore(&hp->lock, flags); + + if (shouldflip) + tty_flip_buffer_push(hp->tty); + + h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); +} + +static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct hvsi_struct *hp = tty->driver_data; + + hvsi_get_mctrl(hp); + return hp->mctrl; +} + +static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct hvsi_struct *hp = tty->driver_data; + unsigned long flags; + uint16_t new_mctrl; + + /* we can only alter DTR */ + clear &= TIOCM_DTR; + set &= TIOCM_DTR; + + spin_lock_irqsave(&hp->lock, flags); + + new_mctrl = (hp->mctrl & ~clear) | set; + + if (hp->mctrl != new_mctrl) { + hvsi_set_mctrl(hp, new_mctrl); + hp->mctrl = new_mctrl; + } + spin_unlock_irqrestore(&hp->lock, flags); + + return 0; +} + + +static const struct tty_operations hvsi_ops = { + .open = hvsi_open, + .close = hvsi_close, + .write = hvsi_write, + .hangup = hvsi_hangup, + .write_room = hvsi_write_room, + .chars_in_buffer = hvsi_chars_in_buffer, + .throttle = hvsi_throttle, + .unthrottle = hvsi_unthrottle, + .tiocmget = hvsi_tiocmget, + .tiocmset = hvsi_tiocmset, +}; + +static int __init hvsi_init(void) +{ + int i; + + hvsi_driver = alloc_tty_driver(hvsi_count); + if (!hvsi_driver) + return -ENOMEM; + + hvsi_driver->owner = THIS_MODULE; + hvsi_driver->driver_name = "hvsi"; + hvsi_driver->name = "hvsi"; + hvsi_driver->major = HVSI_MAJOR; + hvsi_driver->minor_start = HVSI_MINOR; + hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM; + hvsi_driver->init_termios = tty_std_termios; + hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + hvsi_driver->init_termios.c_ispeed = 9600; + hvsi_driver->init_termios.c_ospeed = 9600; + hvsi_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(hvsi_driver, &hvsi_ops); + + for (i=0; i < hvsi_count; i++) { + struct hvsi_struct *hp = &hvsi_ports[i]; + int ret = 1; + + ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp); + if (ret) + printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", + hp->virq, ret); + } + hvsi_wait = wait_for_state; /* irqs active now */ + + if (tty_register_driver(hvsi_driver)) + panic("Couldn't register hvsi console driver\n"); + + printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count); + + return 0; +} +device_initcall(hvsi_init); + +/***** console (not tty) code: *****/ + +static void hvsi_console_print(struct console *console, const char *buf, + unsigned int count) +{ + struct hvsi_struct *hp = &hvsi_ports[console->index]; + char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__; + unsigned int i = 0, n = 0; + int ret, donecr = 0; + + mb(); + if (!is_open(hp)) + return; + + /* + * ugh, we have to translate LF -> CRLF ourselves, in place. + * copied from hvc_console.c: + */ + while (count > 0 || i > 0) { + if (count > 0 && i < sizeof(c)) { + if (buf[n] == '\n' && !donecr) { + c[i++] = '\r'; + donecr = 1; + } else { + c[i++] = buf[n++]; + donecr = 0; + --count; + } + } else { + ret = hvsi_put_chars(hp, c, i); + if (ret < 0) + i = 0; + i -= ret; + } + } +} + +static struct tty_driver *hvsi_console_device(struct console *console, + int *index) +{ + *index = console->index; + return hvsi_driver; +} + +static int __init hvsi_console_setup(struct console *console, char *options) +{ + struct hvsi_struct *hp; + int ret; + + if (console->index < 0 || console->index >= hvsi_count) + return -1; + hp = &hvsi_ports[console->index]; + + /* give the FSP a chance to change the baud rate when we re-open */ + hvsi_close_protocol(hp); + + ret = hvsi_handshake(hp); + if (ret < 0) + return ret; + + ret = hvsi_get_mctrl(hp); + if (ret < 0) + return ret; + + ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); + if (ret < 0) + return ret; + + hp->flags |= HVSI_CONSOLE; + + return 0; +} + +static struct console hvsi_console = { + .name = "hvsi", + .write = hvsi_console_print, + .device = hvsi_console_device, + .setup = hvsi_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int __init hvsi_console_init(void) +{ + struct device_node *vty; + + hvsi_wait = poll_for_state; /* no irqs yet; must poll */ + + /* search device tree for vty nodes */ + for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol"); + vty != NULL; + vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) { + struct hvsi_struct *hp; + const uint32_t *vtermno, *irq; + + vtermno = of_get_property(vty, "reg", NULL); + irq = of_get_property(vty, "interrupts", NULL); + if (!vtermno || !irq) + continue; + + if (hvsi_count >= MAX_NR_HVSI_CONSOLES) { + of_node_put(vty); + break; + } + + hp = &hvsi_ports[hvsi_count]; + INIT_DELAYED_WORK(&hp->writer, hvsi_write_worker); + INIT_WORK(&hp->handshaker, hvsi_handshaker); + init_waitqueue_head(&hp->emptyq); + init_waitqueue_head(&hp->stateq); + spin_lock_init(&hp->lock); + hp->index = hvsi_count; + hp->inbuf_end = hp->inbuf; + hp->state = HVSI_CLOSED; + hp->vtermno = *vtermno; + hp->virq = irq_create_mapping(NULL, irq[0]); + if (hp->virq == NO_IRQ) { + printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", + __func__, irq[0]); + continue; + } + + hvsi_count++; + } + + if (hvsi_count) + register_console(&hvsi_console); + return 0; +} +console_initcall(hvsi_console_init); diff --git a/drivers/tty/hvc/virtio_console.c b/drivers/tty/hvc/virtio_console.c new file mode 100644 index 000000000000..896a2ced1d27 --- /dev/null +++ b/drivers/tty/hvc/virtio_console.c @@ -0,0 +1,1838 @@ +/* + * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation + * Copyright (C) 2009, 2010 Red Hat, Inc. + * + * 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 +#include +#include +#include +#include +#include "hvc_console.h" + +/* + * This is a global struct for storing common data for all the devices + * this driver handles. + * + * Mainly, it has a linked list for all the consoles in one place so + * that callbacks from hvc for get_chars(), put_chars() work properly + * across multiple devices and multiple ports per device. + */ +struct ports_driver_data { + /* Used for registering chardevs */ + struct class *class; + + /* Used for exporting per-port information to debugfs */ + struct dentry *debugfs_dir; + + /* List of all the devices we're handling */ + struct list_head portdevs; + + /* Number of devices this driver is handling */ + unsigned int index; + + /* + * This is used to keep track of the number of hvc consoles + * spawned by this driver. This number is given as the first + * argument to hvc_alloc(). To correctly map an initial + * console spawned via hvc_instantiate to the console being + * hooked up via hvc_alloc, we need to pass the same vtermno. + * + * We also just assume the first console being initialised was + * the first one that got used as the initial console. + */ + unsigned int next_vtermno; + + /* All the console devices handled by this driver */ + struct list_head consoles; +}; +static struct ports_driver_data pdrvdata; + +DEFINE_SPINLOCK(pdrvdata_lock); + +/* This struct holds information that's relevant only for console ports */ +struct console { + /* We'll place all consoles in a list in the pdrvdata struct */ + struct list_head list; + + /* The hvc device associated with this console port */ + struct hvc_struct *hvc; + + /* The size of the console */ + struct winsize ws; + + /* + * This number identifies the number that we used to register + * with hvc in hvc_instantiate() and hvc_alloc(); this is the + * number passed on by the hvc callbacks to us to + * differentiate between the other console ports handled by + * this driver + */ + u32 vtermno; +}; + +struct port_buffer { + char *buf; + + /* size of the buffer in *buf above */ + size_t size; + + /* used length of the buffer */ + size_t len; + /* offset in the buf from which to consume data */ + size_t offset; +}; + +/* + * This is a per-device struct that stores data common to all the + * ports for that device (vdev->priv). + */ +struct ports_device { + /* Next portdev in the list, head is in the pdrvdata struct */ + struct list_head list; + + /* + * Workqueue handlers where we process deferred work after + * notification + */ + struct work_struct control_work; + + struct list_head ports; + + /* To protect the list of ports */ + spinlock_t ports_lock; + + /* To protect the vq operations for the control channel */ + spinlock_t cvq_lock; + + /* The current config space is stored here */ + struct virtio_console_config config; + + /* The virtio device we're associated with */ + struct virtio_device *vdev; + + /* + * A couple of virtqueues for the control channel: one for + * guest->host transfers, one for host->guest transfers + */ + struct virtqueue *c_ivq, *c_ovq; + + /* Array of per-port IO virtqueues */ + struct virtqueue **in_vqs, **out_vqs; + + /* Used for numbering devices for sysfs and debugfs */ + unsigned int drv_index; + + /* Major number for this device. Ports will be created as minors. */ + int chr_major; +}; + +/* This struct holds the per-port data */ +struct port { + /* Next port in the list, head is in the ports_device */ + struct list_head list; + + /* Pointer to the parent virtio_console device */ + struct ports_device *portdev; + + /* The current buffer from which data has to be fed to readers */ + struct port_buffer *inbuf; + + /* + * To protect the operations on the in_vq associated with this + * port. Has to be a spinlock because it can be called from + * interrupt context (get_char()). + */ + spinlock_t inbuf_lock; + + /* Protect the operations on the out_vq. */ + spinlock_t outvq_lock; + + /* The IO vqs for this port */ + struct virtqueue *in_vq, *out_vq; + + /* File in the debugfs directory that exposes this port's information */ + struct dentry *debugfs_file; + + /* + * The entries in this struct will be valid if this port is + * hooked up to an hvc console + */ + struct console cons; + + /* Each port associates with a separate char device */ + struct cdev *cdev; + struct device *dev; + + /* Reference-counting to handle port hot-unplugs and file operations */ + struct kref kref; + + /* A waitqueue for poll() or blocking read operations */ + wait_queue_head_t waitqueue; + + /* The 'name' of the port that we expose via sysfs properties */ + char *name; + + /* We can notify apps of host connect / disconnect events via SIGIO */ + struct fasync_struct *async_queue; + + /* The 'id' to identify the port with the Host */ + u32 id; + + bool outvq_full; + + /* Is the host device open */ + bool host_connected; + + /* We should allow only one process to open a port */ + bool guest_connected; +}; + +/* This is the very early arch-specified put chars function. */ +static int (*early_put_chars)(u32, const char *, int); + +static struct port *find_port_by_vtermno(u32 vtermno) +{ + struct port *port; + struct console *cons; + unsigned long flags; + + spin_lock_irqsave(&pdrvdata_lock, flags); + list_for_each_entry(cons, &pdrvdata.consoles, list) { + if (cons->vtermno == vtermno) { + port = container_of(cons, struct port, cons); + goto out; + } + } + port = NULL; +out: + spin_unlock_irqrestore(&pdrvdata_lock, flags); + return port; +} + +static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, + dev_t dev) +{ + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&portdev->ports_lock, flags); + list_for_each_entry(port, &portdev->ports, list) + if (port->cdev->dev == dev) + goto out; + port = NULL; +out: + spin_unlock_irqrestore(&portdev->ports_lock, flags); + + return port; +} + +static struct port *find_port_by_devt(dev_t dev) +{ + struct ports_device *portdev; + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&pdrvdata_lock, flags); + list_for_each_entry(portdev, &pdrvdata.portdevs, list) { + port = find_port_by_devt_in_portdev(portdev, dev); + if (port) + goto out; + } + port = NULL; +out: + spin_unlock_irqrestore(&pdrvdata_lock, flags); + return port; +} + +static struct port *find_port_by_id(struct ports_device *portdev, u32 id) +{ + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&portdev->ports_lock, flags); + list_for_each_entry(port, &portdev->ports, list) + if (port->id == id) + goto out; + port = NULL; +out: + spin_unlock_irqrestore(&portdev->ports_lock, flags); + + return port; +} + +static struct port *find_port_by_vq(struct ports_device *portdev, + struct virtqueue *vq) +{ + struct port *port; + unsigned long flags; + + spin_lock_irqsave(&portdev->ports_lock, flags); + list_for_each_entry(port, &portdev->ports, list) + if (port->in_vq == vq || port->out_vq == vq) + goto out; + port = NULL; +out: + spin_unlock_irqrestore(&portdev->ports_lock, flags); + return port; +} + +static bool is_console_port(struct port *port) +{ + if (port->cons.hvc) + return true; + return false; +} + +static inline bool use_multiport(struct ports_device *portdev) +{ + /* + * This condition can be true when put_chars is called from + * early_init + */ + if (!portdev->vdev) + return 0; + return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT); +} + +static void free_buf(struct port_buffer *buf) +{ + kfree(buf->buf); + kfree(buf); +} + +static struct port_buffer *alloc_buf(size_t buf_size) +{ + struct port_buffer *buf; + + buf = kmalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + goto fail; + buf->buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf->buf) + goto free_buf; + buf->len = 0; + buf->offset = 0; + buf->size = buf_size; + return buf; + +free_buf: + kfree(buf); +fail: + return NULL; +} + +/* Callers should take appropriate locks */ +static void *get_inbuf(struct port *port) +{ + struct port_buffer *buf; + struct virtqueue *vq; + unsigned int len; + + vq = port->in_vq; + buf = virtqueue_get_buf(vq, &len); + if (buf) { + buf->len = len; + buf->offset = 0; + } + return buf; +} + +/* + * Create a scatter-gather list representing our input buffer and put + * it in the queue. + * + * Callers should take appropriate locks. + */ +static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) +{ + struct scatterlist sg[1]; + int ret; + + sg_init_one(sg, buf->buf, buf->size); + + ret = virtqueue_add_buf(vq, sg, 0, 1, buf); + virtqueue_kick(vq); + return ret; +} + +/* Discard any unread data this port has. Callers lockers. */ +static void discard_port_data(struct port *port) +{ + struct port_buffer *buf; + struct virtqueue *vq; + unsigned int len; + int ret; + + vq = port->in_vq; + if (port->inbuf) + buf = port->inbuf; + else + buf = virtqueue_get_buf(vq, &len); + + ret = 0; + while (buf) { + if (add_inbuf(vq, buf) < 0) { + ret++; + free_buf(buf); + } + buf = virtqueue_get_buf(vq, &len); + } + port->inbuf = NULL; + if (ret) + dev_warn(port->dev, "Errors adding %d buffers back to vq\n", + ret); +} + +static bool port_has_data(struct port *port) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&port->inbuf_lock, flags); + if (port->inbuf) { + ret = true; + goto out; + } + port->inbuf = get_inbuf(port); + if (port->inbuf) { + ret = true; + goto out; + } + ret = false; +out: + spin_unlock_irqrestore(&port->inbuf_lock, flags); + return ret; +} + +static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, + unsigned int event, unsigned int value) +{ + struct scatterlist sg[1]; + struct virtio_console_control cpkt; + struct virtqueue *vq; + unsigned int len; + + if (!use_multiport(portdev)) + return 0; + + cpkt.id = port_id; + cpkt.event = event; + cpkt.value = value; + + vq = portdev->c_ovq; + + sg_init_one(sg, &cpkt, sizeof(cpkt)); + if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) { + virtqueue_kick(vq); + while (!virtqueue_get_buf(vq, &len)) + cpu_relax(); + } + return 0; +} + +static ssize_t send_control_msg(struct port *port, unsigned int event, + unsigned int value) +{ + /* Did the port get unplugged before userspace closed it? */ + if (port->portdev) + return __send_control_msg(port->portdev, port->id, event, value); + return 0; +} + +/* Callers must take the port->outvq_lock */ +static void reclaim_consumed_buffers(struct port *port) +{ + void *buf; + unsigned int len; + + while ((buf = virtqueue_get_buf(port->out_vq, &len))) { + kfree(buf); + port->outvq_full = false; + } +} + +static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, + bool nonblock) +{ + struct scatterlist sg[1]; + struct virtqueue *out_vq; + ssize_t ret; + unsigned long flags; + unsigned int len; + + out_vq = port->out_vq; + + spin_lock_irqsave(&port->outvq_lock, flags); + + reclaim_consumed_buffers(port); + + sg_init_one(sg, in_buf, in_count); + ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf); + + /* Tell Host to go! */ + virtqueue_kick(out_vq); + + if (ret < 0) { + in_count = 0; + goto done; + } + + if (ret == 0) + port->outvq_full = true; + + if (nonblock) + goto done; + + /* + * Wait till the host acknowledges it pushed out the data we + * sent. This is done for data from the hvc_console; the tty + * operations are performed with spinlocks held so we can't + * sleep here. An alternative would be to copy the data to a + * buffer and relax the spinning requirement. The downside is + * we need to kmalloc a GFP_ATOMIC buffer each time the + * console driver writes something out. + */ + while (!virtqueue_get_buf(out_vq, &len)) + cpu_relax(); +done: + spin_unlock_irqrestore(&port->outvq_lock, flags); + /* + * We're expected to return the amount of data we wrote -- all + * of it + */ + return in_count; +} + +/* + * Give out the data that's requested from the buffer that we have + * queued up. + */ +static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, + bool to_user) +{ + struct port_buffer *buf; + unsigned long flags; + + if (!out_count || !port_has_data(port)) + return 0; + + buf = port->inbuf; + out_count = min(out_count, buf->len - buf->offset); + + if (to_user) { + ssize_t ret; + + ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count); + if (ret) + return -EFAULT; + } else { + memcpy(out_buf, buf->buf + buf->offset, out_count); + } + + buf->offset += out_count; + + if (buf->offset == buf->len) { + /* + * We're done using all the data in this buffer. + * Re-queue so that the Host can send us more data. + */ + spin_lock_irqsave(&port->inbuf_lock, flags); + port->inbuf = NULL; + + if (add_inbuf(port->in_vq, buf) < 0) + dev_warn(port->dev, "failed add_buf\n"); + + spin_unlock_irqrestore(&port->inbuf_lock, flags); + } + /* Return the number of bytes actually copied */ + return out_count; +} + +/* The condition that must be true for polling to end */ +static bool will_read_block(struct port *port) +{ + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } + return !port_has_data(port) && port->host_connected; +} + +static bool will_write_block(struct port *port) +{ + bool ret; + + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } + if (!port->host_connected) + return true; + + spin_lock_irq(&port->outvq_lock); + /* + * Check if the Host has consumed any buffers since we last + * sent data (this is only applicable for nonblocking ports). + */ + reclaim_consumed_buffers(port); + ret = port->outvq_full; + spin_unlock_irq(&port->outvq_lock); + + return ret; +} + +static ssize_t port_fops_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct port *port; + ssize_t ret; + + port = filp->private_data; + + if (!port_has_data(port)) { + /* + * If nothing's connected on the host just return 0 in + * case of list_empty; this tells the userspace app + * that there's no connection + */ + if (!port->host_connected) + return 0; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(port->waitqueue, + !will_read_block(port)); + if (ret < 0) + return ret; + } + /* Port got hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; + /* + * We could've received a disconnection message while we were + * waiting for more data. + * + * This check is not clubbed in the if() statement above as we + * might receive some data as well as the host could get + * disconnected after we got woken up from our wait. So we + * really want to give off whatever data we have and only then + * check for host_connected. + */ + if (!port_has_data(port) && !port->host_connected) + return 0; + + return fill_readbuf(port, ubuf, count, true); +} + +static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, + size_t count, loff_t *offp) +{ + struct port *port; + char *buf; + ssize_t ret; + bool nonblock; + + /* Userspace could be out to fool us */ + if (!count) + return 0; + + port = filp->private_data; + + nonblock = filp->f_flags & O_NONBLOCK; + + if (will_write_block(port)) { + if (nonblock) + return -EAGAIN; + + ret = wait_event_interruptible(port->waitqueue, + !will_write_block(port)); + if (ret < 0) + return ret; + } + /* Port got hot-unplugged. */ + if (!port->guest_connected) + return -ENODEV; + + count = min((size_t)(32 * 1024), count); + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = copy_from_user(buf, ubuf, count); + if (ret) { + ret = -EFAULT; + goto free_buf; + } + + /* + * We now ask send_buf() to not spin for generic ports -- we + * can re-use the same code path that non-blocking file + * descriptors take for blocking file descriptors since the + * wait is already done and we're certain the write will go + * through to the host. + */ + nonblock = true; + ret = send_buf(port, buf, count, nonblock); + + if (nonblock && ret > 0) + goto out; + +free_buf: + kfree(buf); +out: + return ret; +} + +static unsigned int port_fops_poll(struct file *filp, poll_table *wait) +{ + struct port *port; + unsigned int ret; + + port = filp->private_data; + poll_wait(filp, &port->waitqueue, wait); + + if (!port->guest_connected) { + /* Port got unplugged */ + return POLLHUP; + } + ret = 0; + if (!will_read_block(port)) + ret |= POLLIN | POLLRDNORM; + if (!will_write_block(port)) + ret |= POLLOUT; + if (!port->host_connected) + ret |= POLLHUP; + + return ret; +} + +static void remove_port(struct kref *kref); + +static int port_fops_release(struct inode *inode, struct file *filp) +{ + struct port *port; + + port = filp->private_data; + + /* Notify host of port being closed */ + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); + + spin_lock_irq(&port->inbuf_lock); + port->guest_connected = false; + + discard_port_data(port); + + spin_unlock_irq(&port->inbuf_lock); + + spin_lock_irq(&port->outvq_lock); + reclaim_consumed_buffers(port); + spin_unlock_irq(&port->outvq_lock); + + /* + * Locks aren't necessary here as a port can't be opened after + * unplug, and if a port isn't unplugged, a kref would already + * exist for the port. Plus, taking ports_lock here would + * create a dependency on other locks taken by functions + * inside remove_port if we're the last holder of the port, + * creating many problems. + */ + kref_put(&port->kref, remove_port); + + return 0; +} + +static int port_fops_open(struct inode *inode, struct file *filp) +{ + struct cdev *cdev = inode->i_cdev; + struct port *port; + int ret; + + port = find_port_by_devt(cdev->dev); + filp->private_data = port; + + /* Prevent against a port getting hot-unplugged at the same time */ + spin_lock_irq(&port->portdev->ports_lock); + kref_get(&port->kref); + spin_unlock_irq(&port->portdev->ports_lock); + + /* + * Don't allow opening of console port devices -- that's done + * via /dev/hvc + */ + if (is_console_port(port)) { + ret = -ENXIO; + goto out; + } + + /* Allow only one process to open a particular port at a time */ + spin_lock_irq(&port->inbuf_lock); + if (port->guest_connected) { + spin_unlock_irq(&port->inbuf_lock); + ret = -EMFILE; + goto out; + } + + port->guest_connected = true; + spin_unlock_irq(&port->inbuf_lock); + + spin_lock_irq(&port->outvq_lock); + /* + * There might be a chance that we missed reclaiming a few + * buffers in the window of the port getting previously closed + * and opening now. + */ + reclaim_consumed_buffers(port); + spin_unlock_irq(&port->outvq_lock); + + nonseekable_open(inode, filp); + + /* Notify host of port being opened */ + send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); + + return 0; +out: + kref_put(&port->kref, remove_port); + return ret; +} + +static int port_fops_fasync(int fd, struct file *filp, int mode) +{ + struct port *port; + + port = filp->private_data; + return fasync_helper(fd, filp, mode, &port->async_queue); +} + +/* + * The file operations that we support: programs in the guest can open + * a console device, read from it, write to it, poll for data and + * close it. The devices are at + * /dev/vportp + */ +static const struct file_operations port_fops = { + .owner = THIS_MODULE, + .open = port_fops_open, + .read = port_fops_read, + .write = port_fops_write, + .poll = port_fops_poll, + .release = port_fops_release, + .fasync = port_fops_fasync, + .llseek = no_llseek, +}; + +/* + * The put_chars() callback is pretty straightforward. + * + * We turn the characters into a scatter-gather list, add it to the + * output queue and then kick the Host. Then we sit here waiting for + * it to finish: inefficient in theory, but in practice + * implementations will do it immediately (lguest's Launcher does). + */ +static int put_chars(u32 vtermno, const char *buf, int count) +{ + struct port *port; + + if (unlikely(early_put_chars)) + return early_put_chars(vtermno, buf, count); + + port = find_port_by_vtermno(vtermno); + if (!port) + return -EPIPE; + + return send_buf(port, (void *)buf, count, false); +} + +/* + * get_chars() is the callback from the hvc_console infrastructure + * when an interrupt is received. + * + * We call out to fill_readbuf that gets us the required data from the + * buffers that are queued up. + */ +static int get_chars(u32 vtermno, char *buf, int count) +{ + struct port *port; + + /* If we've not set up the port yet, we have no input to give. */ + if (unlikely(early_put_chars)) + return 0; + + port = find_port_by_vtermno(vtermno); + if (!port) + return -EPIPE; + + /* If we don't have an input queue yet, we can't get input. */ + BUG_ON(!port->in_vq); + + return fill_readbuf(port, buf, count, false); +} + +static void resize_console(struct port *port) +{ + struct virtio_device *vdev; + + /* The port could have been hot-unplugged */ + if (!port || !is_console_port(port)) + return; + + vdev = port->portdev->vdev; + if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) + hvc_resize(port->cons.hvc, port->cons.ws); +} + +/* We set the configuration at this point, since we now have a tty */ +static int notifier_add_vio(struct hvc_struct *hp, int data) +{ + struct port *port; + + port = find_port_by_vtermno(hp->vtermno); + if (!port) + return -EINVAL; + + hp->irq_requested = 1; + resize_console(port); + + return 0; +} + +static void notifier_del_vio(struct hvc_struct *hp, int data) +{ + hp->irq_requested = 0; +} + +/* The operations for console ports. */ +static const struct hv_ops hv_ops = { + .get_chars = get_chars, + .put_chars = put_chars, + .notifier_add = notifier_add_vio, + .notifier_del = notifier_del_vio, + .notifier_hangup = notifier_del_vio, +}; + +/* + * Console drivers are initialized very early so boot messages can go + * out, so we do things slightly differently from the generic virtio + * initialization of the net and block drivers. + * + * At this stage, the console is output-only. It's too early to set + * up a virtqueue, so we let the drivers do some boutique early-output + * thing. + */ +int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) +{ + early_put_chars = put_chars; + return hvc_instantiate(0, 0, &hv_ops); +} + +int init_port_console(struct port *port) +{ + int ret; + + /* + * The Host's telling us this port is a console port. Hook it + * up with an hvc console. + * + * To set up and manage our virtual console, we call + * hvc_alloc(). + * + * The first argument of hvc_alloc() is the virtual console + * number. The second argument is the parameter for the + * notification mechanism (like irq number). We currently + * leave this as zero, virtqueues have implicit notifications. + * + * The third argument is a "struct hv_ops" containing the + * put_chars() get_chars(), notifier_add() and notifier_del() + * pointers. The final argument is the output buffer size: we + * can do any size, so we put PAGE_SIZE here. + */ + port->cons.vtermno = pdrvdata.next_vtermno; + + port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); + if (IS_ERR(port->cons.hvc)) { + ret = PTR_ERR(port->cons.hvc); + dev_err(port->dev, + "error %d allocating hvc for port\n", ret); + port->cons.hvc = NULL; + return ret; + } + spin_lock_irq(&pdrvdata_lock); + pdrvdata.next_vtermno++; + list_add_tail(&port->cons.list, &pdrvdata.consoles); + spin_unlock_irq(&pdrvdata_lock); + port->guest_connected = true; + + /* + * Start using the new console output if this is the first + * console to come up. + */ + if (early_put_chars) + early_put_chars = NULL; + + /* Notify host of port being opened */ + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); + + return 0; +} + +static ssize_t show_port_name(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct port *port; + + port = dev_get_drvdata(dev); + + return sprintf(buffer, "%s\n", port->name); +} + +static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL); + +static struct attribute *port_sysfs_entries[] = { + &dev_attr_name.attr, + NULL +}; + +static struct attribute_group port_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = port_sysfs_entries, +}; + +static int debugfs_open(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct port *port; + char *buf; + ssize_t ret, out_offset, out_count; + + out_count = 1024; + buf = kmalloc(out_count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + port = filp->private_data; + out_offset = 0; + out_offset += snprintf(buf + out_offset, out_count, + "name: %s\n", port->name ? port->name : ""); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "guest_connected: %d\n", port->guest_connected); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "host_connected: %d\n", port->host_connected); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "outvq_full: %d\n", port->outvq_full); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "is_console: %s\n", + is_console_port(port) ? "yes" : "no"); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "console_vtermno: %u\n", port->cons.vtermno); + + ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); + kfree(buf); + return ret; +} + +static const struct file_operations port_debugfs_ops = { + .owner = THIS_MODULE, + .open = debugfs_open, + .read = debugfs_read, +}; + +static void set_console_size(struct port *port, u16 rows, u16 cols) +{ + if (!port || !is_console_port(port)) + return; + + port->cons.ws.ws_row = rows; + port->cons.ws.ws_col = cols; +} + +static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) +{ + struct port_buffer *buf; + unsigned int nr_added_bufs; + int ret; + + nr_added_bufs = 0; + do { + buf = alloc_buf(PAGE_SIZE); + if (!buf) + break; + + spin_lock_irq(lock); + ret = add_inbuf(vq, buf); + if (ret < 0) { + spin_unlock_irq(lock); + free_buf(buf); + break; + } + nr_added_bufs++; + spin_unlock_irq(lock); + } while (ret > 0); + + return nr_added_bufs; +} + +static void send_sigio_to_port(struct port *port) +{ + if (port->async_queue && port->guest_connected) + kill_fasync(&port->async_queue, SIGIO, POLL_OUT); +} + +static int add_port(struct ports_device *portdev, u32 id) +{ + char debugfs_name[16]; + struct port *port; + struct port_buffer *buf; + dev_t devt; + unsigned int nr_added_bufs; + int err; + + port = kmalloc(sizeof(*port), GFP_KERNEL); + if (!port) { + err = -ENOMEM; + goto fail; + } + kref_init(&port->kref); + + port->portdev = portdev; + port->id = id; + + port->name = NULL; + port->inbuf = NULL; + port->cons.hvc = NULL; + port->async_queue = NULL; + + port->cons.ws.ws_row = port->cons.ws.ws_col = 0; + + port->host_connected = port->guest_connected = false; + + port->outvq_full = false; + + port->in_vq = portdev->in_vqs[port->id]; + port->out_vq = portdev->out_vqs[port->id]; + + port->cdev = cdev_alloc(); + if (!port->cdev) { + dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n"); + err = -ENOMEM; + goto free_port; + } + port->cdev->ops = &port_fops; + + devt = MKDEV(portdev->chr_major, id); + err = cdev_add(port->cdev, devt, 1); + if (err < 0) { + dev_err(&port->portdev->vdev->dev, + "Error %d adding cdev for port %u\n", err, id); + goto free_cdev; + } + port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, + devt, port, "vport%up%u", + port->portdev->drv_index, id); + if (IS_ERR(port->dev)) { + err = PTR_ERR(port->dev); + dev_err(&port->portdev->vdev->dev, + "Error %d creating device for port %u\n", + err, id); + goto free_cdev; + } + + spin_lock_init(&port->inbuf_lock); + spin_lock_init(&port->outvq_lock); + init_waitqueue_head(&port->waitqueue); + + /* Fill the in_vq with buffers so the host can send us data. */ + nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); + if (!nr_added_bufs) { + dev_err(port->dev, "Error allocating inbufs\n"); + err = -ENOMEM; + goto free_device; + } + + /* + * If we're not using multiport support, this has to be a console port + */ + if (!use_multiport(port->portdev)) { + err = init_port_console(port); + if (err) + goto free_inbufs; + } + + spin_lock_irq(&portdev->ports_lock); + list_add_tail(&port->list, &port->portdev->ports); + spin_unlock_irq(&portdev->ports_lock); + + /* + * Tell the Host we're set so that it can send us various + * configuration parameters for this port (eg, port name, + * caching, whether this is a console port, etc.) + */ + send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); + + if (pdrvdata.debugfs_dir) { + /* + * Finally, create the debugfs file that we can use to + * inspect a port's state at any time + */ + sprintf(debugfs_name, "vport%up%u", + port->portdev->drv_index, id); + port->debugfs_file = debugfs_create_file(debugfs_name, 0444, + pdrvdata.debugfs_dir, + port, + &port_debugfs_ops); + } + return 0; + +free_inbufs: + while ((buf = virtqueue_detach_unused_buf(port->in_vq))) + free_buf(buf); +free_device: + device_destroy(pdrvdata.class, port->dev->devt); +free_cdev: + cdev_del(port->cdev); +free_port: + kfree(port); +fail: + /* The host might want to notify management sw about port add failure */ + __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0); + return err; +} + +/* No users remain, remove all port-specific data. */ +static void remove_port(struct kref *kref) +{ + struct port *port; + + port = container_of(kref, struct port, kref); + + sysfs_remove_group(&port->dev->kobj, &port_attribute_group); + device_destroy(pdrvdata.class, port->dev->devt); + cdev_del(port->cdev); + + kfree(port->name); + + debugfs_remove(port->debugfs_file); + + kfree(port); +} + +/* + * Port got unplugged. Remove port from portdev's list and drop the + * kref reference. If no userspace has this port opened, it will + * result in immediate removal the port. + */ +static void unplug_port(struct port *port) +{ + struct port_buffer *buf; + + spin_lock_irq(&port->portdev->ports_lock); + list_del(&port->list); + spin_unlock_irq(&port->portdev->ports_lock); + + if (port->guest_connected) { + port->guest_connected = false; + port->host_connected = false; + wake_up_interruptible(&port->waitqueue); + + /* Let the app know the port is going down. */ + send_sigio_to_port(port); + } + + if (is_console_port(port)) { + spin_lock_irq(&pdrvdata_lock); + list_del(&port->cons.list); + spin_unlock_irq(&pdrvdata_lock); +#if 0 + /* + * hvc_remove() not called as removing one hvc port + * results in other hvc ports getting frozen. + * + * Once this is resolved in hvc, this functionality + * will be enabled. Till that is done, the -EPIPE + * return from get_chars() above will help + * hvc_console.c to clean up on ports we remove here. + */ + hvc_remove(port->cons.hvc); +#endif + } + + /* Remove unused data this port might have received. */ + discard_port_data(port); + + reclaim_consumed_buffers(port); + + /* Remove buffers we queued up for the Host to send us data in. */ + while ((buf = virtqueue_detach_unused_buf(port->in_vq))) + free_buf(buf); + + /* + * We should just assume the device itself has gone off -- + * else a close on an open port later will try to send out a + * control message. + */ + port->portdev = NULL; + + /* + * Locks around here are not necessary - a port can't be + * opened after we removed the port struct from ports_list + * above. + */ + kref_put(&port->kref, remove_port); +} + +/* Any private messages that the Host and Guest want to share */ +static void handle_control_message(struct ports_device *portdev, + struct port_buffer *buf) +{ + struct virtio_console_control *cpkt; + struct port *port; + size_t name_size; + int err; + + cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); + + port = find_port_by_id(portdev, cpkt->id); + if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) { + /* No valid header at start of buffer. Drop it. */ + dev_dbg(&portdev->vdev->dev, + "Invalid index %u in control packet\n", cpkt->id); + return; + } + + switch (cpkt->event) { + case VIRTIO_CONSOLE_PORT_ADD: + if (port) { + dev_dbg(&portdev->vdev->dev, + "Port %u already added\n", port->id); + send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); + break; + } + if (cpkt->id >= portdev->config.max_nr_ports) { + dev_warn(&portdev->vdev->dev, + "Request for adding port with out-of-bound id %u, max. supported id: %u\n", + cpkt->id, portdev->config.max_nr_ports - 1); + break; + } + add_port(portdev, cpkt->id); + break; + case VIRTIO_CONSOLE_PORT_REMOVE: + unplug_port(port); + break; + case VIRTIO_CONSOLE_CONSOLE_PORT: + if (!cpkt->value) + break; + if (is_console_port(port)) + break; + + init_port_console(port); + /* + * Could remove the port here in case init fails - but + * have to notify the host first. + */ + break; + case VIRTIO_CONSOLE_RESIZE: { + struct { + __u16 rows; + __u16 cols; + } size; + + if (!is_console_port(port)) + break; + + memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), + sizeof(size)); + set_console_size(port, size.rows, size.cols); + + port->cons.hvc->irq_requested = 1; + resize_console(port); + break; + } + case VIRTIO_CONSOLE_PORT_OPEN: + port->host_connected = cpkt->value; + wake_up_interruptible(&port->waitqueue); + /* + * If the host port got closed and the host had any + * unconsumed buffers, we'll be able to reclaim them + * now. + */ + spin_lock_irq(&port->outvq_lock); + reclaim_consumed_buffers(port); + spin_unlock_irq(&port->outvq_lock); + + /* + * If the guest is connected, it'll be interested in + * knowing the host connection state changed. + */ + send_sigio_to_port(port); + break; + case VIRTIO_CONSOLE_PORT_NAME: + /* + * Skip the size of the header and the cpkt to get the size + * of the name that was sent + */ + name_size = buf->len - buf->offset - sizeof(*cpkt) + 1; + + port->name = kmalloc(name_size, GFP_KERNEL); + if (!port->name) { + dev_err(port->dev, + "Not enough space to store port name\n"); + break; + } + strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), + name_size - 1); + port->name[name_size - 1] = 0; + + /* + * Since we only have one sysfs attribute, 'name', + * create it only if we have a name for the port. + */ + err = sysfs_create_group(&port->dev->kobj, + &port_attribute_group); + if (err) { + dev_err(port->dev, + "Error %d creating sysfs device attributes\n", + err); + } else { + /* + * Generate a udev event so that appropriate + * symlinks can be created based on udev + * rules. + */ + kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); + } + break; + } +} + +static void control_work_handler(struct work_struct *work) +{ + struct ports_device *portdev; + struct virtqueue *vq; + struct port_buffer *buf; + unsigned int len; + + portdev = container_of(work, struct ports_device, control_work); + vq = portdev->c_ivq; + + spin_lock(&portdev->cvq_lock); + while ((buf = virtqueue_get_buf(vq, &len))) { + spin_unlock(&portdev->cvq_lock); + + buf->len = len; + buf->offset = 0; + + handle_control_message(portdev, buf); + + spin_lock(&portdev->cvq_lock); + if (add_inbuf(portdev->c_ivq, buf) < 0) { + dev_warn(&portdev->vdev->dev, + "Error adding buffer to queue\n"); + free_buf(buf); + } + } + spin_unlock(&portdev->cvq_lock); +} + +static void in_intr(struct virtqueue *vq) +{ + struct port *port; + unsigned long flags; + + port = find_port_by_vq(vq->vdev->priv, vq); + if (!port) + return; + + spin_lock_irqsave(&port->inbuf_lock, flags); + if (!port->inbuf) + port->inbuf = get_inbuf(port); + + /* + * Don't queue up data when port is closed. This condition + * can be reached when a console port is not yet connected (no + * tty is spawned) and the host sends out data to console + * ports. For generic serial ports, the host won't + * (shouldn't) send data till the guest is connected. + */ + if (!port->guest_connected) + discard_port_data(port); + + spin_unlock_irqrestore(&port->inbuf_lock, flags); + + wake_up_interruptible(&port->waitqueue); + + /* Send a SIGIO indicating new data in case the process asked for it */ + send_sigio_to_port(port); + + if (is_console_port(port) && hvc_poll(port->cons.hvc)) + hvc_kick(); +} + +static void control_intr(struct virtqueue *vq) +{ + struct ports_device *portdev; + + portdev = vq->vdev->priv; + schedule_work(&portdev->control_work); +} + +static void config_intr(struct virtio_device *vdev) +{ + struct ports_device *portdev; + + portdev = vdev->priv; + + if (!use_multiport(portdev)) { + struct port *port; + u16 rows, cols; + + vdev->config->get(vdev, + offsetof(struct virtio_console_config, cols), + &cols, sizeof(u16)); + vdev->config->get(vdev, + offsetof(struct virtio_console_config, rows), + &rows, sizeof(u16)); + + port = find_port_by_id(portdev, 0); + set_console_size(port, rows, cols); + + /* + * We'll use this way of resizing only for legacy + * support. For newer userspace + * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages + * to indicate console size changes so that it can be + * done per-port. + */ + resize_console(port); + } +} + +static int init_vqs(struct ports_device *portdev) +{ + vq_callback_t **io_callbacks; + char **io_names; + struct virtqueue **vqs; + u32 i, j, nr_ports, nr_queues; + int err; + + nr_ports = portdev->config.max_nr_ports; + nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; + + vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); + io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); + io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); + portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), + GFP_KERNEL); + portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), + GFP_KERNEL); + if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || + !portdev->out_vqs) { + err = -ENOMEM; + goto free; + } + + /* + * For backward compat (newer host but older guest), the host + * spawns a console port first and also inits the vqs for port + * 0 before others. + */ + j = 0; + io_callbacks[j] = in_intr; + io_callbacks[j + 1] = NULL; + io_names[j] = "input"; + io_names[j + 1] = "output"; + j += 2; + + if (use_multiport(portdev)) { + io_callbacks[j] = control_intr; + io_callbacks[j + 1] = NULL; + io_names[j] = "control-i"; + io_names[j + 1] = "control-o"; + + for (i = 1; i < nr_ports; i++) { + j += 2; + io_callbacks[j] = in_intr; + io_callbacks[j + 1] = NULL; + io_names[j] = "input"; + io_names[j + 1] = "output"; + } + } + /* Find the queues. */ + err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, + io_callbacks, + (const char **)io_names); + if (err) + goto free; + + j = 0; + portdev->in_vqs[0] = vqs[0]; + portdev->out_vqs[0] = vqs[1]; + j += 2; + if (use_multiport(portdev)) { + portdev->c_ivq = vqs[j]; + portdev->c_ovq = vqs[j + 1]; + + for (i = 1; i < nr_ports; i++) { + j += 2; + portdev->in_vqs[i] = vqs[j]; + portdev->out_vqs[i] = vqs[j + 1]; + } + } + kfree(io_names); + kfree(io_callbacks); + kfree(vqs); + + return 0; + +free: + kfree(portdev->out_vqs); + kfree(portdev->in_vqs); + kfree(io_names); + kfree(io_callbacks); + kfree(vqs); + + return err; +} + +static const struct file_operations portdev_fops = { + .owner = THIS_MODULE, +}; + +/* + * Once we're further in boot, we get probed like any other virtio + * device. + * + * If the host also supports multiple console ports, we check the + * config space to see how many ports the host has spawned. We + * initialize each port found. + */ +static int __devinit virtcons_probe(struct virtio_device *vdev) +{ + struct ports_device *portdev; + int err; + bool multiport; + + portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); + if (!portdev) { + err = -ENOMEM; + goto fail; + } + + /* Attach this portdev to this virtio_device, and vice-versa. */ + portdev->vdev = vdev; + vdev->priv = portdev; + + spin_lock_irq(&pdrvdata_lock); + portdev->drv_index = pdrvdata.index++; + spin_unlock_irq(&pdrvdata_lock); + + portdev->chr_major = register_chrdev(0, "virtio-portsdev", + &portdev_fops); + if (portdev->chr_major < 0) { + dev_err(&vdev->dev, + "Error %d registering chrdev for device %u\n", + portdev->chr_major, portdev->drv_index); + err = portdev->chr_major; + goto free; + } + + multiport = false; + portdev->config.max_nr_ports = 1; + if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { + multiport = true; + vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT; + + vdev->config->get(vdev, offsetof(struct virtio_console_config, + max_nr_ports), + &portdev->config.max_nr_ports, + sizeof(portdev->config.max_nr_ports)); + } + + /* Let the Host know we support multiple ports.*/ + vdev->config->finalize_features(vdev); + + err = init_vqs(portdev); + if (err < 0) { + dev_err(&vdev->dev, "Error %d initializing vqs\n", err); + goto free_chrdev; + } + + spin_lock_init(&portdev->ports_lock); + INIT_LIST_HEAD(&portdev->ports); + + if (multiport) { + unsigned int nr_added_bufs; + + spin_lock_init(&portdev->cvq_lock); + INIT_WORK(&portdev->control_work, &control_work_handler); + + nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); + if (!nr_added_bufs) { + dev_err(&vdev->dev, + "Error allocating buffers for control queue\n"); + err = -ENOMEM; + goto free_vqs; + } + } else { + /* + * For backward compatibility: Create a console port + * if we're running on older host. + */ + add_port(portdev, 0); + } + + spin_lock_irq(&pdrvdata_lock); + list_add_tail(&portdev->list, &pdrvdata.portdevs); + spin_unlock_irq(&pdrvdata_lock); + + __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, + VIRTIO_CONSOLE_DEVICE_READY, 1); + return 0; + +free_vqs: + /* The host might want to notify mgmt sw about device add failure */ + __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, + VIRTIO_CONSOLE_DEVICE_READY, 0); + vdev->config->del_vqs(vdev); + kfree(portdev->in_vqs); + kfree(portdev->out_vqs); +free_chrdev: + unregister_chrdev(portdev->chr_major, "virtio-portsdev"); +free: + kfree(portdev); +fail: + return err; +} + +static void virtcons_remove(struct virtio_device *vdev) +{ + struct ports_device *portdev; + struct port *port, *port2; + + portdev = vdev->priv; + + spin_lock_irq(&pdrvdata_lock); + list_del(&portdev->list); + spin_unlock_irq(&pdrvdata_lock); + + /* Disable interrupts for vqs */ + vdev->config->reset(vdev); + /* Finish up work that's lined up */ + cancel_work_sync(&portdev->control_work); + + list_for_each_entry_safe(port, port2, &portdev->ports, list) + unplug_port(port); + + unregister_chrdev(portdev->chr_major, "virtio-portsdev"); + + /* + * When yanking out a device, we immediately lose the + * (device-side) queues. So there's no point in keeping the + * guest side around till we drop our final reference. This + * also means that any ports which are in an open state will + * have to just stop using the port, as the vqs are going + * away. + */ + if (use_multiport(portdev)) { + struct port_buffer *buf; + unsigned int len; + + while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) + free_buf(buf); + + while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) + free_buf(buf); + } + + vdev->config->del_vqs(vdev); + kfree(portdev->in_vqs); + kfree(portdev->out_vqs); + + kfree(portdev); +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { + VIRTIO_CONSOLE_F_SIZE, + VIRTIO_CONSOLE_F_MULTIPORT, +}; + +static struct virtio_driver virtio_console = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtcons_probe, + .remove = virtcons_remove, + .config_changed = config_intr, +}; + +static int __init init(void) +{ + int err; + + pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); + if (IS_ERR(pdrvdata.class)) { + err = PTR_ERR(pdrvdata.class); + pr_err("Error %d creating virtio-ports class\n", err); + return err; + } + + pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); + if (!pdrvdata.debugfs_dir) { + pr_warning("Error %ld creating debugfs dir for virtio-ports\n", + PTR_ERR(pdrvdata.debugfs_dir)); + } + INIT_LIST_HEAD(&pdrvdata.consoles); + INIT_LIST_HEAD(&pdrvdata.portdevs); + + return register_virtio_driver(&virtio_console); +} + +static void __exit fini(void) +{ + unregister_virtio_driver(&virtio_console); + + class_destroy(pdrvdata.class); + if (pdrvdata.debugfs_dir) + debugfs_remove_recursive(pdrvdata.debugfs_dir); +} +module_init(init); +module_exit(fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio console driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ab4382d27412e7e3e7c936e8d50d8888dfac3df8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Jan 2011 12:10:18 -0800 Subject: tty: move drivers/serial/ to drivers/tty/serial/ The serial drivers are really just tty drivers, so move them to drivers/tty/ to make things a bit neater overall. This is part of the tty/serial driver movement proceedure as proposed by Arnd Bergmann and approved by everyone involved a number of months ago. Cc: Arnd Bergmann Cc: Alan Cox Cc: Geert Uytterhoeven Cc: Rogier Wolff Cc: Michael H. Warfield Signed-off-by: Greg Kroah-Hartman --- drivers/Makefile | 3 +- drivers/char/Kconfig | 2 +- drivers/serial/21285.c | 513 --- drivers/serial/68328serial.c | 1472 --------- drivers/serial/68328serial.h | 188 -- drivers/serial/68360serial.c | 2978 ----------------- drivers/serial/8250.c | 3377 -------------------- drivers/serial/8250.h | 80 - drivers/serial/8250_accent.c | 47 - drivers/serial/8250_acorn.c | 141 - drivers/serial/8250_boca.c | 61 - drivers/serial/8250_early.c | 287 -- drivers/serial/8250_exar_st16c554.c | 52 - drivers/serial/8250_fourport.c | 53 - drivers/serial/8250_gsc.c | 122 - drivers/serial/8250_hp300.c | 327 -- drivers/serial/8250_hub6.c | 58 - drivers/serial/8250_mca.c | 63 - drivers/serial/8250_pci.c | 3850 ---------------------- drivers/serial/8250_pnp.c | 523 --- drivers/serial/Kconfig | 1598 ---------- drivers/serial/Makefile | 94 - drivers/serial/altera_jtaguart.c | 504 --- drivers/serial/altera_uart.c | 608 ---- drivers/serial/amba-pl010.c | 825 ----- drivers/serial/amba-pl011.c | 1519 --------- drivers/serial/apbuart.c | 709 ----- drivers/serial/apbuart.h | 64 - drivers/serial/atmel_serial.c | 1808 ----------- drivers/serial/bcm63xx_uart.c | 891 ------ drivers/serial/bfin_5xx.c | 1600 ---------- drivers/serial/bfin_sport_uart.c | 935 ------ drivers/serial/bfin_sport_uart.h | 86 - drivers/serial/clps711x.c | 579 ---- drivers/serial/cpm_uart/Makefile | 11 - drivers/serial/cpm_uart/cpm_uart.h | 147 - drivers/serial/cpm_uart/cpm_uart_core.c | 1443 --------- drivers/serial/cpm_uart/cpm_uart_cpm1.c | 138 - drivers/serial/cpm_uart/cpm_uart_cpm1.h | 34 - drivers/serial/cpm_uart/cpm_uart_cpm2.c | 174 - drivers/serial/cpm_uart/cpm_uart_cpm2.h | 34 - drivers/serial/crisv10.c | 4573 --------------------------- drivers/serial/crisv10.h | 147 - drivers/serial/dz.c | 955 ------ drivers/serial/dz.h | 129 - drivers/serial/icom.c | 1658 ---------- drivers/serial/icom.h | 287 -- drivers/serial/ifx6x60.c | 1406 -------- drivers/serial/ifx6x60.h | 129 - drivers/serial/imx.c | 1380 -------- drivers/serial/ioc3_serial.c | 2199 ------------- drivers/serial/ioc4_serial.c | 2953 ----------------- drivers/serial/ip22zilog.c | 1221 ------- drivers/serial/ip22zilog.h | 281 -- drivers/serial/jsm/Makefile | 8 - drivers/serial/jsm/jsm.h | 388 --- drivers/serial/jsm/jsm_driver.c | 297 -- drivers/serial/jsm/jsm_neo.c | 1412 --------- drivers/serial/jsm/jsm_tty.c | 910 ------ drivers/serial/kgdboc.c | 328 -- drivers/serial/m32r_sio.c | 1192 ------- drivers/serial/m32r_sio.h | 48 - drivers/serial/m32r_sio_reg.h | 152 - drivers/serial/max3100.c | 926 ------ drivers/serial/max3107-aava.c | 344 -- drivers/serial/max3107.c | 1213 ------- drivers/serial/max3107.h | 441 --- drivers/serial/mcf.c | 662 ---- drivers/serial/mfd.c | 1513 --------- drivers/serial/mpc52xx_uart.c | 1527 --------- drivers/serial/mpsc.c | 2159 ------------- drivers/serial/mrst_max3110.c | 919 ------ drivers/serial/mrst_max3110.h | 60 - drivers/serial/msm_serial.c | 758 ----- drivers/serial/msm_serial.h | 173 - drivers/serial/mux.c | 633 ---- drivers/serial/netx-serial.c | 750 ----- drivers/serial/nwpserial.c | 477 --- drivers/serial/of_serial.c | 201 -- drivers/serial/omap-serial.c | 1359 -------- drivers/serial/pch_uart.c | 1451 --------- drivers/serial/pmac_zilog.c | 2208 ------------- drivers/serial/pmac_zilog.h | 396 --- drivers/serial/pnx8xxx_uart.c | 854 ----- drivers/serial/pxa.c | 879 ----- drivers/serial/s3c2400.c | 106 - drivers/serial/s3c2410.c | 118 - drivers/serial/s3c2412.c | 152 - drivers/serial/s3c2440.c | 181 -- drivers/serial/s3c24a0.c | 118 - drivers/serial/s3c6400.c | 152 - drivers/serial/s5pv210.c | 162 - drivers/serial/sa1100.c | 918 ------ drivers/serial/samsung.c | 1487 --------- drivers/serial/samsung.h | 120 - drivers/serial/sb1250-duart.c | 976 ------ drivers/serial/sc26xx.c | 757 ----- drivers/serial/serial_core.c | 2578 --------------- drivers/serial/serial_cs.c | 869 ----- drivers/serial/serial_ks8695.c | 705 ----- drivers/serial/serial_lh7a40x.c | 682 ---- drivers/serial/serial_txx9.c | 1344 -------- drivers/serial/sh-sci.c | 2027 ------------ drivers/serial/sh-sci.h | 660 ---- drivers/serial/sn_console.c | 1085 ------- drivers/serial/suncore.c | 247 -- drivers/serial/suncore.h | 33 - drivers/serial/sunhv.c | 661 ---- drivers/serial/sunsab.c | 1152 ------- drivers/serial/sunsab.h | 322 -- drivers/serial/sunsu.c | 1608 ---------- drivers/serial/sunzilog.c | 1655 ---------- drivers/serial/sunzilog.h | 289 -- drivers/serial/timbuart.c | 531 ---- drivers/serial/timbuart.h | 58 - drivers/serial/uartlite.c | 709 ----- drivers/serial/ucc_uart.c | 1537 --------- drivers/serial/vr41xx_siu.c | 978 ------ drivers/serial/vt8500_serial.c | 648 ---- drivers/serial/zs.c | 1304 -------- drivers/serial/zs.h | 284 -- drivers/tty/Makefile | 1 + drivers/tty/serial/21285.c | 513 +++ drivers/tty/serial/68328serial.c | 1472 +++++++++ drivers/tty/serial/68328serial.h | 188 ++ drivers/tty/serial/68360serial.c | 2978 +++++++++++++++++ drivers/tty/serial/8250.c | 3377 ++++++++++++++++++++ drivers/tty/serial/8250.h | 80 + drivers/tty/serial/8250_accent.c | 47 + drivers/tty/serial/8250_acorn.c | 141 + drivers/tty/serial/8250_boca.c | 61 + drivers/tty/serial/8250_early.c | 287 ++ drivers/tty/serial/8250_exar_st16c554.c | 52 + drivers/tty/serial/8250_fourport.c | 53 + drivers/tty/serial/8250_gsc.c | 122 + drivers/tty/serial/8250_hp300.c | 327 ++ drivers/tty/serial/8250_hub6.c | 58 + drivers/tty/serial/8250_mca.c | 63 + drivers/tty/serial/8250_pci.c | 3850 ++++++++++++++++++++++ drivers/tty/serial/8250_pnp.c | 523 +++ drivers/tty/serial/Kconfig | 1598 ++++++++++ drivers/tty/serial/Makefile | 94 + drivers/tty/serial/altera_jtaguart.c | 504 +++ drivers/tty/serial/altera_uart.c | 608 ++++ drivers/tty/serial/amba-pl010.c | 825 +++++ drivers/tty/serial/amba-pl011.c | 1519 +++++++++ drivers/tty/serial/apbuart.c | 709 +++++ drivers/tty/serial/apbuart.h | 64 + drivers/tty/serial/atmel_serial.c | 1808 +++++++++++ drivers/tty/serial/bcm63xx_uart.c | 891 ++++++ drivers/tty/serial/bfin_5xx.c | 1600 ++++++++++ drivers/tty/serial/bfin_sport_uart.c | 935 ++++++ drivers/tty/serial/bfin_sport_uart.h | 86 + drivers/tty/serial/clps711x.c | 579 ++++ drivers/tty/serial/cpm_uart/Makefile | 11 + drivers/tty/serial/cpm_uart/cpm_uart.h | 147 + drivers/tty/serial/cpm_uart/cpm_uart_core.c | 1443 +++++++++ drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c | 138 + drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h | 34 + drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c | 174 + drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h | 34 + drivers/tty/serial/crisv10.c | 4573 +++++++++++++++++++++++++++ drivers/tty/serial/crisv10.h | 147 + drivers/tty/serial/dz.c | 955 ++++++ drivers/tty/serial/dz.h | 129 + drivers/tty/serial/icom.c | 1658 ++++++++++ drivers/tty/serial/icom.h | 287 ++ drivers/tty/serial/ifx6x60.c | 1406 ++++++++ drivers/tty/serial/ifx6x60.h | 129 + drivers/tty/serial/imx.c | 1380 ++++++++ drivers/tty/serial/ioc3_serial.c | 2199 +++++++++++++ drivers/tty/serial/ioc4_serial.c | 2953 +++++++++++++++++ drivers/tty/serial/ip22zilog.c | 1221 +++++++ drivers/tty/serial/ip22zilog.h | 281 ++ drivers/tty/serial/jsm/Makefile | 8 + drivers/tty/serial/jsm/jsm.h | 388 +++ drivers/tty/serial/jsm/jsm_driver.c | 297 ++ drivers/tty/serial/jsm/jsm_neo.c | 1412 +++++++++ drivers/tty/serial/jsm/jsm_tty.c | 910 ++++++ drivers/tty/serial/kgdboc.c | 328 ++ drivers/tty/serial/m32r_sio.c | 1192 +++++++ drivers/tty/serial/m32r_sio.h | 48 + drivers/tty/serial/m32r_sio_reg.h | 152 + drivers/tty/serial/max3100.c | 926 ++++++ drivers/tty/serial/max3107-aava.c | 344 ++ drivers/tty/serial/max3107.c | 1213 +++++++ drivers/tty/serial/max3107.h | 441 +++ drivers/tty/serial/mcf.c | 662 ++++ drivers/tty/serial/mfd.c | 1513 +++++++++ drivers/tty/serial/mpc52xx_uart.c | 1527 +++++++++ drivers/tty/serial/mpsc.c | 2159 +++++++++++++ drivers/tty/serial/mrst_max3110.c | 919 ++++++ drivers/tty/serial/mrst_max3110.h | 60 + drivers/tty/serial/msm_serial.c | 758 +++++ drivers/tty/serial/msm_serial.h | 173 + drivers/tty/serial/mux.c | 633 ++++ drivers/tty/serial/netx-serial.c | 750 +++++ drivers/tty/serial/nwpserial.c | 477 +++ drivers/tty/serial/of_serial.c | 201 ++ drivers/tty/serial/omap-serial.c | 1359 ++++++++ drivers/tty/serial/pch_uart.c | 1451 +++++++++ drivers/tty/serial/pmac_zilog.c | 2208 +++++++++++++ drivers/tty/serial/pmac_zilog.h | 396 +++ drivers/tty/serial/pnx8xxx_uart.c | 854 +++++ drivers/tty/serial/pxa.c | 879 +++++ drivers/tty/serial/s3c2400.c | 106 + drivers/tty/serial/s3c2410.c | 118 + drivers/tty/serial/s3c2412.c | 152 + drivers/tty/serial/s3c2440.c | 181 ++ drivers/tty/serial/s3c24a0.c | 118 + drivers/tty/serial/s3c6400.c | 152 + drivers/tty/serial/s5pv210.c | 162 + drivers/tty/serial/sa1100.c | 918 ++++++ drivers/tty/serial/samsung.c | 1487 +++++++++ drivers/tty/serial/samsung.h | 120 + drivers/tty/serial/sb1250-duart.c | 976 ++++++ drivers/tty/serial/sc26xx.c | 757 +++++ drivers/tty/serial/serial_core.c | 2578 +++++++++++++++ drivers/tty/serial/serial_cs.c | 869 +++++ drivers/tty/serial/serial_ks8695.c | 705 +++++ drivers/tty/serial/serial_lh7a40x.c | 682 ++++ drivers/tty/serial/serial_txx9.c | 1344 ++++++++ drivers/tty/serial/sh-sci.c | 2027 ++++++++++++ drivers/tty/serial/sh-sci.h | 660 ++++ drivers/tty/serial/sn_console.c | 1085 +++++++ drivers/tty/serial/suncore.c | 247 ++ drivers/tty/serial/suncore.h | 33 + drivers/tty/serial/sunhv.c | 661 ++++ drivers/tty/serial/sunsab.c | 1152 +++++++ drivers/tty/serial/sunsab.h | 322 ++ drivers/tty/serial/sunsu.c | 1608 ++++++++++ drivers/tty/serial/sunzilog.c | 1655 ++++++++++ drivers/tty/serial/sunzilog.h | 289 ++ drivers/tty/serial/timbuart.c | 531 ++++ drivers/tty/serial/timbuart.h | 58 + drivers/tty/serial/uartlite.c | 709 +++++ drivers/tty/serial/ucc_uart.c | 1537 +++++++++ drivers/tty/serial/vr41xx_siu.c | 978 ++++++ drivers/tty/serial/vt8500_serial.c | 648 ++++ drivers/tty/serial/zs.c | 1304 ++++++++ drivers/tty/serial/zs.h | 284 ++ 241 files changed, 97165 insertions(+), 97165 deletions(-) delete mode 100644 drivers/serial/21285.c delete mode 100644 drivers/serial/68328serial.c delete mode 100644 drivers/serial/68328serial.h delete mode 100644 drivers/serial/68360serial.c delete mode 100644 drivers/serial/8250.c delete mode 100644 drivers/serial/8250.h delete mode 100644 drivers/serial/8250_accent.c delete mode 100644 drivers/serial/8250_acorn.c delete mode 100644 drivers/serial/8250_boca.c delete mode 100644 drivers/serial/8250_early.c delete mode 100644 drivers/serial/8250_exar_st16c554.c delete mode 100644 drivers/serial/8250_fourport.c delete mode 100644 drivers/serial/8250_gsc.c delete mode 100644 drivers/serial/8250_hp300.c delete mode 100644 drivers/serial/8250_hub6.c delete mode 100644 drivers/serial/8250_mca.c delete mode 100644 drivers/serial/8250_pci.c delete mode 100644 drivers/serial/8250_pnp.c delete mode 100644 drivers/serial/Kconfig delete mode 100644 drivers/serial/Makefile delete mode 100644 drivers/serial/altera_jtaguart.c delete mode 100644 drivers/serial/altera_uart.c delete mode 100644 drivers/serial/amba-pl010.c delete mode 100644 drivers/serial/amba-pl011.c delete mode 100644 drivers/serial/apbuart.c delete mode 100644 drivers/serial/apbuart.h delete mode 100644 drivers/serial/atmel_serial.c delete mode 100644 drivers/serial/bcm63xx_uart.c delete mode 100644 drivers/serial/bfin_5xx.c delete mode 100644 drivers/serial/bfin_sport_uart.c delete mode 100644 drivers/serial/bfin_sport_uart.h delete mode 100644 drivers/serial/clps711x.c delete mode 100644 drivers/serial/cpm_uart/Makefile delete mode 100644 drivers/serial/cpm_uart/cpm_uart.h delete mode 100644 drivers/serial/cpm_uart/cpm_uart_core.c delete mode 100644 drivers/serial/cpm_uart/cpm_uart_cpm1.c delete mode 100644 drivers/serial/cpm_uart/cpm_uart_cpm1.h delete mode 100644 drivers/serial/cpm_uart/cpm_uart_cpm2.c delete mode 100644 drivers/serial/cpm_uart/cpm_uart_cpm2.h delete mode 100644 drivers/serial/crisv10.c delete mode 100644 drivers/serial/crisv10.h delete mode 100644 drivers/serial/dz.c delete mode 100644 drivers/serial/dz.h delete mode 100644 drivers/serial/icom.c delete mode 100644 drivers/serial/icom.h delete mode 100644 drivers/serial/ifx6x60.c delete mode 100644 drivers/serial/ifx6x60.h delete mode 100644 drivers/serial/imx.c delete mode 100644 drivers/serial/ioc3_serial.c delete mode 100644 drivers/serial/ioc4_serial.c delete mode 100644 drivers/serial/ip22zilog.c delete mode 100644 drivers/serial/ip22zilog.h delete mode 100644 drivers/serial/jsm/Makefile delete mode 100644 drivers/serial/jsm/jsm.h delete mode 100644 drivers/serial/jsm/jsm_driver.c delete mode 100644 drivers/serial/jsm/jsm_neo.c delete mode 100644 drivers/serial/jsm/jsm_tty.c delete mode 100644 drivers/serial/kgdboc.c delete mode 100644 drivers/serial/m32r_sio.c delete mode 100644 drivers/serial/m32r_sio.h delete mode 100644 drivers/serial/m32r_sio_reg.h delete mode 100644 drivers/serial/max3100.c delete mode 100644 drivers/serial/max3107-aava.c delete mode 100644 drivers/serial/max3107.c delete mode 100644 drivers/serial/max3107.h delete mode 100644 drivers/serial/mcf.c delete mode 100644 drivers/serial/mfd.c delete mode 100644 drivers/serial/mpc52xx_uart.c delete mode 100644 drivers/serial/mpsc.c delete mode 100644 drivers/serial/mrst_max3110.c delete mode 100644 drivers/serial/mrst_max3110.h delete mode 100644 drivers/serial/msm_serial.c delete mode 100644 drivers/serial/msm_serial.h delete mode 100644 drivers/serial/mux.c delete mode 100644 drivers/serial/netx-serial.c delete mode 100644 drivers/serial/nwpserial.c delete mode 100644 drivers/serial/of_serial.c delete mode 100644 drivers/serial/omap-serial.c delete mode 100644 drivers/serial/pch_uart.c delete mode 100644 drivers/serial/pmac_zilog.c delete mode 100644 drivers/serial/pmac_zilog.h delete mode 100644 drivers/serial/pnx8xxx_uart.c delete mode 100644 drivers/serial/pxa.c delete mode 100644 drivers/serial/s3c2400.c delete mode 100644 drivers/serial/s3c2410.c delete mode 100644 drivers/serial/s3c2412.c delete mode 100644 drivers/serial/s3c2440.c delete mode 100644 drivers/serial/s3c24a0.c delete mode 100644 drivers/serial/s3c6400.c delete mode 100644 drivers/serial/s5pv210.c delete mode 100644 drivers/serial/sa1100.c delete mode 100644 drivers/serial/samsung.c delete mode 100644 drivers/serial/samsung.h delete mode 100644 drivers/serial/sb1250-duart.c delete mode 100644 drivers/serial/sc26xx.c delete mode 100644 drivers/serial/serial_core.c delete mode 100644 drivers/serial/serial_cs.c delete mode 100644 drivers/serial/serial_ks8695.c delete mode 100644 drivers/serial/serial_lh7a40x.c delete mode 100644 drivers/serial/serial_txx9.c delete mode 100644 drivers/serial/sh-sci.c delete mode 100644 drivers/serial/sh-sci.h delete mode 100644 drivers/serial/sn_console.c delete mode 100644 drivers/serial/suncore.c delete mode 100644 drivers/serial/suncore.h delete mode 100644 drivers/serial/sunhv.c delete mode 100644 drivers/serial/sunsab.c delete mode 100644 drivers/serial/sunsab.h delete mode 100644 drivers/serial/sunsu.c delete mode 100644 drivers/serial/sunzilog.c delete mode 100644 drivers/serial/sunzilog.h delete mode 100644 drivers/serial/timbuart.c delete mode 100644 drivers/serial/timbuart.h delete mode 100644 drivers/serial/uartlite.c delete mode 100644 drivers/serial/ucc_uart.c delete mode 100644 drivers/serial/vr41xx_siu.c delete mode 100644 drivers/serial/vt8500_serial.c delete mode 100644 drivers/serial/zs.c delete mode 100644 drivers/serial/zs.h create mode 100644 drivers/tty/serial/21285.c create mode 100644 drivers/tty/serial/68328serial.c create mode 100644 drivers/tty/serial/68328serial.h create mode 100644 drivers/tty/serial/68360serial.c create mode 100644 drivers/tty/serial/8250.c create mode 100644 drivers/tty/serial/8250.h create mode 100644 drivers/tty/serial/8250_accent.c create mode 100644 drivers/tty/serial/8250_acorn.c create mode 100644 drivers/tty/serial/8250_boca.c create mode 100644 drivers/tty/serial/8250_early.c create mode 100644 drivers/tty/serial/8250_exar_st16c554.c create mode 100644 drivers/tty/serial/8250_fourport.c create mode 100644 drivers/tty/serial/8250_gsc.c create mode 100644 drivers/tty/serial/8250_hp300.c create mode 100644 drivers/tty/serial/8250_hub6.c create mode 100644 drivers/tty/serial/8250_mca.c create mode 100644 drivers/tty/serial/8250_pci.c create mode 100644 drivers/tty/serial/8250_pnp.c create mode 100644 drivers/tty/serial/Kconfig create mode 100644 drivers/tty/serial/Makefile create mode 100644 drivers/tty/serial/altera_jtaguart.c create mode 100644 drivers/tty/serial/altera_uart.c create mode 100644 drivers/tty/serial/amba-pl010.c create mode 100644 drivers/tty/serial/amba-pl011.c create mode 100644 drivers/tty/serial/apbuart.c create mode 100644 drivers/tty/serial/apbuart.h create mode 100644 drivers/tty/serial/atmel_serial.c create mode 100644 drivers/tty/serial/bcm63xx_uart.c create mode 100644 drivers/tty/serial/bfin_5xx.c create mode 100644 drivers/tty/serial/bfin_sport_uart.c create mode 100644 drivers/tty/serial/bfin_sport_uart.h create mode 100644 drivers/tty/serial/clps711x.c create mode 100644 drivers/tty/serial/cpm_uart/Makefile create mode 100644 drivers/tty/serial/cpm_uart/cpm_uart.h create mode 100644 drivers/tty/serial/cpm_uart/cpm_uart_core.c create mode 100644 drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c create mode 100644 drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h create mode 100644 drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c create mode 100644 drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h create mode 100644 drivers/tty/serial/crisv10.c create mode 100644 drivers/tty/serial/crisv10.h create mode 100644 drivers/tty/serial/dz.c create mode 100644 drivers/tty/serial/dz.h create mode 100644 drivers/tty/serial/icom.c create mode 100644 drivers/tty/serial/icom.h create mode 100644 drivers/tty/serial/ifx6x60.c create mode 100644 drivers/tty/serial/ifx6x60.h create mode 100644 drivers/tty/serial/imx.c create mode 100644 drivers/tty/serial/ioc3_serial.c create mode 100644 drivers/tty/serial/ioc4_serial.c create mode 100644 drivers/tty/serial/ip22zilog.c create mode 100644 drivers/tty/serial/ip22zilog.h create mode 100644 drivers/tty/serial/jsm/Makefile create mode 100644 drivers/tty/serial/jsm/jsm.h create mode 100644 drivers/tty/serial/jsm/jsm_driver.c create mode 100644 drivers/tty/serial/jsm/jsm_neo.c create mode 100644 drivers/tty/serial/jsm/jsm_tty.c create mode 100644 drivers/tty/serial/kgdboc.c create mode 100644 drivers/tty/serial/m32r_sio.c create mode 100644 drivers/tty/serial/m32r_sio.h create mode 100644 drivers/tty/serial/m32r_sio_reg.h create mode 100644 drivers/tty/serial/max3100.c create mode 100644 drivers/tty/serial/max3107-aava.c create mode 100644 drivers/tty/serial/max3107.c create mode 100644 drivers/tty/serial/max3107.h create mode 100644 drivers/tty/serial/mcf.c create mode 100644 drivers/tty/serial/mfd.c create mode 100644 drivers/tty/serial/mpc52xx_uart.c create mode 100644 drivers/tty/serial/mpsc.c create mode 100644 drivers/tty/serial/mrst_max3110.c create mode 100644 drivers/tty/serial/mrst_max3110.h create mode 100644 drivers/tty/serial/msm_serial.c create mode 100644 drivers/tty/serial/msm_serial.h create mode 100644 drivers/tty/serial/mux.c create mode 100644 drivers/tty/serial/netx-serial.c create mode 100644 drivers/tty/serial/nwpserial.c create mode 100644 drivers/tty/serial/of_serial.c create mode 100644 drivers/tty/serial/omap-serial.c create mode 100644 drivers/tty/serial/pch_uart.c create mode 100644 drivers/tty/serial/pmac_zilog.c create mode 100644 drivers/tty/serial/pmac_zilog.h create mode 100644 drivers/tty/serial/pnx8xxx_uart.c create mode 100644 drivers/tty/serial/pxa.c create mode 100644 drivers/tty/serial/s3c2400.c create mode 100644 drivers/tty/serial/s3c2410.c create mode 100644 drivers/tty/serial/s3c2412.c create mode 100644 drivers/tty/serial/s3c2440.c create mode 100644 drivers/tty/serial/s3c24a0.c create mode 100644 drivers/tty/serial/s3c6400.c create mode 100644 drivers/tty/serial/s5pv210.c create mode 100644 drivers/tty/serial/sa1100.c create mode 100644 drivers/tty/serial/samsung.c create mode 100644 drivers/tty/serial/samsung.h create mode 100644 drivers/tty/serial/sb1250-duart.c create mode 100644 drivers/tty/serial/sc26xx.c create mode 100644 drivers/tty/serial/serial_core.c create mode 100644 drivers/tty/serial/serial_cs.c create mode 100644 drivers/tty/serial/serial_ks8695.c create mode 100644 drivers/tty/serial/serial_lh7a40x.c create mode 100644 drivers/tty/serial/serial_txx9.c create mode 100644 drivers/tty/serial/sh-sci.c create mode 100644 drivers/tty/serial/sh-sci.h create mode 100644 drivers/tty/serial/sn_console.c create mode 100644 drivers/tty/serial/suncore.c create mode 100644 drivers/tty/serial/suncore.h create mode 100644 drivers/tty/serial/sunhv.c create mode 100644 drivers/tty/serial/sunsab.c create mode 100644 drivers/tty/serial/sunsab.h create mode 100644 drivers/tty/serial/sunsu.c create mode 100644 drivers/tty/serial/sunzilog.c create mode 100644 drivers/tty/serial/sunzilog.h create mode 100644 drivers/tty/serial/timbuart.c create mode 100644 drivers/tty/serial/timbuart.h create mode 100644 drivers/tty/serial/uartlite.c create mode 100644 drivers/tty/serial/ucc_uart.c create mode 100644 drivers/tty/serial/vr41xx_siu.c create mode 100644 drivers/tty/serial/vt8500_serial.c create mode 100644 drivers/tty/serial/zs.c create mode 100644 drivers/tty/serial/zs.h (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index ef5132469f58..1e2cda18c718 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_XEN) += xen/ # regulators early, since some subsystems rely on them to initialize obj-$(CONFIG_REGULATOR) += regulator/ -# char/ comes before serial/ etc so that the VT console is the boot-time +# tty/ comes before char/ so that the VT console is the boot-time # default. obj-y += tty/ obj-y += char/ @@ -38,7 +38,6 @@ obj-$(CONFIG_CONNECTOR) += connector/ obj-$(CONFIG_FB_I810) += video/i810/ obj-$(CONFIG_FB_INTEL) += video/intelfb/ -obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ nfc/ obj-$(CONFIG_NUBUS) += nubus/ diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 0f175a866ef0..ccac7d090727 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -426,7 +426,7 @@ config SGI_MBCS If you have an SGI Altix with an attached SABrick say Y or M here, otherwise say N. -source "drivers/serial/Kconfig" +source "drivers/tty/serial/Kconfig" config UNIX98_PTYS bool "Unix98 PTY support" if EMBEDDED diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c deleted file mode 100644 index d89aa38c5cf0..000000000000 --- a/drivers/serial/21285.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * linux/drivers/serial/21285.c - * - * Driver for the serial port on the 21285 StrongArm-110 core logic chip. - * - * Based on drivers/char/serial.c - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define BAUD_BASE (mem_fclk_21285/64) - -#define SERIAL_21285_NAME "ttyFB" -#define SERIAL_21285_MAJOR 204 -#define SERIAL_21285_MINOR 4 - -#define RXSTAT_DUMMY_READ 0x80000000 -#define RXSTAT_FRAME (1 << 0) -#define RXSTAT_PARITY (1 << 1) -#define RXSTAT_OVERRUN (1 << 2) -#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN) - -#define H_UBRLCR_BREAK (1 << 0) -#define H_UBRLCR_PARENB (1 << 1) -#define H_UBRLCR_PAREVN (1 << 2) -#define H_UBRLCR_STOPB (1 << 3) -#define H_UBRLCR_FIFO (1 << 4) - -static const char serial21285_name[] = "Footbridge UART"; - -#define tx_enabled(port) ((port)->unused[0]) -#define rx_enabled(port) ((port)->unused[1]) - -/* - * The documented expression for selecting the divisor is: - * BAUD_BASE / baud - 1 - * However, typically BAUD_BASE is not divisible by baud, so - * we want to select the divisor that gives us the minimum - * error. Therefore, we want: - * int(BAUD_BASE / baud - 0.5) -> - * int(BAUD_BASE / baud - (baud >> 1) / baud) -> - * int((BAUD_BASE - (baud >> 1)) / baud) - */ - -static void serial21285_stop_tx(struct uart_port *port) -{ - if (tx_enabled(port)) { - disable_irq_nosync(IRQ_CONTX); - tx_enabled(port) = 0; - } -} - -static void serial21285_start_tx(struct uart_port *port) -{ - if (!tx_enabled(port)) { - enable_irq(IRQ_CONTX); - tx_enabled(port) = 1; - } -} - -static void serial21285_stop_rx(struct uart_port *port) -{ - if (rx_enabled(port)) { - disable_irq_nosync(IRQ_CONRX); - rx_enabled(port) = 0; - } -} - -static void serial21285_enable_ms(struct uart_port *port) -{ -} - -static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; - unsigned int status, ch, flag, rxs, max_count = 256; - - status = *CSR_UARTFLG; - while (!(status & 0x10) && max_count--) { - ch = *CSR_UARTDR; - flag = TTY_NORMAL; - port->icount.rx++; - - rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ; - if (unlikely(rxs & RXSTAT_ANYERR)) { - if (rxs & RXSTAT_PARITY) - port->icount.parity++; - else if (rxs & RXSTAT_FRAME) - port->icount.frame++; - if (rxs & RXSTAT_OVERRUN) - port->icount.overrun++; - - rxs &= port->read_status_mask; - - if (rxs & RXSTAT_PARITY) - flag = TTY_PARITY; - else if (rxs & RXSTAT_FRAME) - flag = TTY_FRAME; - } - - uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag); - - status = *CSR_UARTFLG; - } - tty_flip_buffer_push(tty); - - return IRQ_HANDLED; -} - -static irqreturn_t serial21285_tx_chars(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; - int count = 256; - - if (port->x_char) { - *CSR_UARTDR = port->x_char; - port->icount.tx++; - port->x_char = 0; - goto out; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - serial21285_stop_tx(port); - goto out; - } - - do { - *CSR_UARTDR = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - serial21285_stop_tx(port); - - out: - return IRQ_HANDLED; -} - -static unsigned int serial21285_tx_empty(struct uart_port *port) -{ - return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT; -} - -/* no modem control lines */ -static unsigned int serial21285_get_mctrl(struct uart_port *port) -{ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; -} - -static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -static void serial21285_break_ctl(struct uart_port *port, int break_state) -{ - unsigned long flags; - unsigned int h_lcr; - - spin_lock_irqsave(&port->lock, flags); - h_lcr = *CSR_H_UBRLCR; - if (break_state) - h_lcr |= H_UBRLCR_BREAK; - else - h_lcr &= ~H_UBRLCR_BREAK; - *CSR_H_UBRLCR = h_lcr; - spin_unlock_irqrestore(&port->lock, flags); -} - -static int serial21285_startup(struct uart_port *port) -{ - int ret; - - tx_enabled(port) = 1; - rx_enabled(port) = 1; - - ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0, - serial21285_name, port); - if (ret == 0) { - ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0, - serial21285_name, port); - if (ret) - free_irq(IRQ_CONRX, port); - } - - return ret; -} - -static void serial21285_shutdown(struct uart_port *port) -{ - free_irq(IRQ_CONTX, port); - free_irq(IRQ_CONRX, port); -} - -static void -serial21285_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int baud, quot, h_lcr, b; - - /* - * We don't support modem control lines. - */ - termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); - termios->c_cflag |= CLOCAL; - - /* - * We don't support BREAK character recognition. - */ - termios->c_iflag &= ~(IGNBRK | BRKINT); - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - b = port->uartclk / (16 * quot); - tty_termios_encode_baud_rate(termios, b, b); - - switch (termios->c_cflag & CSIZE) { - case CS5: - h_lcr = 0x00; - break; - case CS6: - h_lcr = 0x20; - break; - case CS7: - h_lcr = 0x40; - break; - default: /* CS8 */ - h_lcr = 0x60; - break; - } - - if (termios->c_cflag & CSTOPB) - h_lcr |= H_UBRLCR_STOPB; - if (termios->c_cflag & PARENB) { - h_lcr |= H_UBRLCR_PARENB; - if (!(termios->c_cflag & PARODD)) - h_lcr |= H_UBRLCR_PAREVN; - } - - if (port->fifosize) - h_lcr |= H_UBRLCR_FIFO; - - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * Which character status flags are we interested in? - */ - port->read_status_mask = RXSTAT_OVERRUN; - if (termios->c_iflag & INPCK) - port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; - - /* - * Which character status flags should we ignore? - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; - if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) - port->ignore_status_mask |= RXSTAT_OVERRUN; - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= RXSTAT_DUMMY_READ; - - quot -= 1; - - *CSR_UARTCON = 0; - *CSR_L_UBRLCR = quot & 0xff; - *CSR_M_UBRLCR = (quot >> 8) & 0x0f; - *CSR_H_UBRLCR = h_lcr; - *CSR_UARTCON = 1; - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *serial21285_type(struct uart_port *port) -{ - return port->type == PORT_21285 ? "DC21285" : NULL; -} - -static void serial21285_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, 32); -} - -static int serial21285_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, 32, serial21285_name) - != NULL ? 0 : -EBUSY; -} - -static void serial21285_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0) - port->type = PORT_21285; -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) - ret = -EINVAL; - if (ser->irq != NO_IRQ) - ret = -EINVAL; - if (ser->baud_base != port->uartclk / 16) - ret = -EINVAL; - return ret; -} - -static struct uart_ops serial21285_ops = { - .tx_empty = serial21285_tx_empty, - .get_mctrl = serial21285_get_mctrl, - .set_mctrl = serial21285_set_mctrl, - .stop_tx = serial21285_stop_tx, - .start_tx = serial21285_start_tx, - .stop_rx = serial21285_stop_rx, - .enable_ms = serial21285_enable_ms, - .break_ctl = serial21285_break_ctl, - .startup = serial21285_startup, - .shutdown = serial21285_shutdown, - .set_termios = serial21285_set_termios, - .type = serial21285_type, - .release_port = serial21285_release_port, - .request_port = serial21285_request_port, - .config_port = serial21285_config_port, - .verify_port = serial21285_verify_port, -}; - -static struct uart_port serial21285_port = { - .mapbase = 0x42000160, - .iotype = UPIO_MEM, - .irq = NO_IRQ, - .fifosize = 16, - .ops = &serial21285_ops, - .flags = UPF_BOOT_AUTOCONF, -}; - -static void serial21285_setup_ports(void) -{ - serial21285_port.uartclk = mem_fclk_21285 / 4; -} - -#ifdef CONFIG_SERIAL_21285_CONSOLE -static void serial21285_console_putchar(struct uart_port *port, int ch) -{ - while (*CSR_UARTFLG & 0x20) - barrier(); - *CSR_UARTDR = ch; -} - -static void -serial21285_console_write(struct console *co, const char *s, - unsigned int count) -{ - uart_console_write(&serial21285_port, s, count, serial21285_console_putchar); -} - -static void __init -serial21285_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - if (*CSR_UARTCON == 1) { - unsigned int tmp; - - tmp = *CSR_H_UBRLCR; - switch (tmp & 0x60) { - case 0x00: - *bits = 5; - break; - case 0x20: - *bits = 6; - break; - case 0x40: - *bits = 7; - break; - default: - case 0x60: - *bits = 8; - break; - } - - if (tmp & H_UBRLCR_PARENB) { - *parity = 'o'; - if (tmp & H_UBRLCR_PAREVN) - *parity = 'e'; - } - - tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8); - - *baud = port->uartclk / (16 * (tmp + 1)); - } -} - -static int __init serial21285_console_setup(struct console *co, char *options) -{ - struct uart_port *port = &serial21285_port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (machine_is_personal_server()) - baud = 57600; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - serial21285_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver serial21285_reg; - -static struct console serial21285_console = -{ - .name = SERIAL_21285_NAME, - .write = serial21285_console_write, - .device = uart_console_device, - .setup = serial21285_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial21285_reg, -}; - -static int __init rs285_console_init(void) -{ - serial21285_setup_ports(); - register_console(&serial21285_console); - return 0; -} -console_initcall(rs285_console_init); - -#define SERIAL_21285_CONSOLE &serial21285_console -#else -#define SERIAL_21285_CONSOLE NULL -#endif - -static struct uart_driver serial21285_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyFB", - .dev_name = "ttyFB", - .major = SERIAL_21285_MAJOR, - .minor = SERIAL_21285_MINOR, - .nr = 1, - .cons = SERIAL_21285_CONSOLE, -}; - -static int __init serial21285_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: 21285 driver\n"); - - serial21285_setup_ports(); - - ret = uart_register_driver(&serial21285_reg); - if (ret == 0) - uart_add_one_port(&serial21285_reg, &serial21285_port); - - return ret; -} - -static void __exit serial21285_exit(void) -{ - uart_remove_one_port(&serial21285_reg, &serial21285_port); - uart_unregister_driver(&serial21285_reg); -} - -module_init(serial21285_init); -module_exit(serial21285_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver"); -MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c deleted file mode 100644 index be0ebce36e54..000000000000 --- a/drivers/serial/68328serial.c +++ /dev/null @@ -1,1472 +0,0 @@ -/* 68328serial.c: Serial port driver for 68328 microcontroller - * - * Copyright (C) 1995 David S. Miller - * Copyright (C) 1998 Kenneth Albanowski - * Copyright (C) 1998, 1999 D. Jeff Dionne - * Copyright (C) 1999 Vladimir Gurevich - * Copyright (C) 2002-2003 David McCullough - * Copyright (C) 2002 Greg Ungerer - * - * VZ Support/Fixes Evan Stawnyczy - * Multiple UART support Daniel Potts - * Power management support Daniel Potts - * VZ Second Serial Port enable Phil Wilshire - * 2.4/2.5 port David McCullough - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* (es) */ -/* note: perhaps we can murge these files, so that you can just - * define 1 of them, and they can sort that out for themselves - */ -#if defined(CONFIG_M68EZ328) -#include -#else -#if defined(CONFIG_M68VZ328) -#include -#else -#include -#endif /* CONFIG_M68VZ328 */ -#endif /* CONFIG_M68EZ328 */ - -#include "68328serial.h" - -/* Turn off usage of real serial interrupt code, to "support" Copilot */ -#ifdef CONFIG_XCOPILOT_BUGS -#undef USE_INTS -#else -#define USE_INTS -#endif - -static struct m68k_serial m68k_soft[NR_PORTS]; - -static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; - -/* multiple ports are contiguous in memory */ -m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; - -struct tty_struct m68k_ttys; -struct m68k_serial *m68k_consinfo = 0; - -#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */ - -struct tty_driver *serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( - */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW - -#define RS_ISR_PASS_LIMIT 256 - -static void change_speed(struct m68k_serial *info); - -/* - * Setup for console. Argument comes from the boot command line. - */ - -/* note: this is messy, but it works, again, perhaps defined somewhere else?*/ -#ifdef CONFIG_M68VZ328 -#define CONSOLE_BAUD_RATE 19200 -#define DEFAULT_CBAUD B19200 -#endif - - -#ifndef CONSOLE_BAUD_RATE -#define CONSOLE_BAUD_RATE 9600 -#define DEFAULT_CBAUD B9600 -#endif - - -static int m68328_console_initted = 0; -static int m68328_console_baud = CONSOLE_BAUD_RATE; -static int m68328_console_cbaud = DEFAULT_CBAUD; - - -static inline int serial_paranoia_check(struct m68k_serial *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct %s in %s\n"; - static const char *badinfo = - "Warning: null m68k_serial for %s in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0 }; - -/* Sets or clears DTR/RTS on the requested line */ -static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) -{ - if (set) { - /* set the RTS/CTS line */ - } else { - /* clear it */ - } - return; -} - -/* Utility routines */ -static inline int get_baud(struct m68k_serial *ss) -{ - unsigned long result = 115200; - unsigned short int baud = uart_addr[ss->line].ubaud; - if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400; - result >>= GET_FIELD(baud, UBAUD_DIVIDE); - - return result; -} - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_stop(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - uart->ustcnt &= ~USTCNT_TXEN; - local_irq_restore(flags); -} - -static int rs_put_char(char ch) -{ - int flags, loops = 0; - - local_irq_save(flags); - - while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) { - loops++; - udelay(5); - } - - UTX_TXDATA = ch; - udelay(5); - local_irq_restore(flags); - return 1; -} - -static void rs_start(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_start")) - return; - - local_irq_save(flags); - if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) { -#ifdef USE_INTS - uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; -#else - uart->ustcnt |= USTCNT_TXEN; -#endif - } - local_irq_restore(flags); -} - -/* Drop into either the boot monitor or kadb upon receiving a break - * from keyboard/console input. - */ -static void batten_down_hatches(void) -{ - /* Drop into the debugger */ -} - -static void status_handle(struct m68k_serial *info, unsigned short status) -{ -#if 0 - if(status & DCD) { - if((info->port.tty->termios->c_cflag & CRTSCTS) && - ((info->curregs[3] & AUTO_ENAB)==0)) { - info->curregs[3] |= AUTO_ENAB; - info->pendregs[3] |= AUTO_ENAB; - write_zsreg(info->m68k_channel, 3, info->curregs[3]); - } - } else { - if((info->curregs[3] & AUTO_ENAB)) { - info->curregs[3] &= ~AUTO_ENAB; - info->pendregs[3] &= ~AUTO_ENAB; - write_zsreg(info->m68k_channel, 3, info->curregs[3]); - } - } -#endif - /* If this is console input and this is a - * 'break asserted' status change interrupt - * see if we can drop into the debugger - */ - if((status & URX_BREAK) && info->break_abort) - batten_down_hatches(); - return; -} - -static void receive_chars(struct m68k_serial *info, unsigned short rx) -{ - struct tty_struct *tty = info->port.tty; - m68328_uart *uart = &uart_addr[info->line]; - unsigned char ch, flag; - - /* - * This do { } while() loop will get ALL chars out of Rx FIFO - */ -#ifndef CONFIG_XCOPILOT_BUGS - do { -#endif - ch = GET_FIELD(rx, URX_RXDATA); - - if(info->is_cons) { - if(URX_BREAK & rx) { /* whee, break received */ - status_handle(info, rx); - return; -#ifdef CONFIG_MAGIC_SYSRQ - } else if (ch == 0x10) { /* ^P */ - show_state(); - show_free_areas(); - show_buffers(); -/* show_net_buffers(); */ - return; - } else if (ch == 0x12) { /* ^R */ - emergency_restart(); - return; -#endif /* CONFIG_MAGIC_SYSRQ */ - } - } - - if(!tty) - goto clear_and_exit; - - flag = TTY_NORMAL; - - if(rx & URX_PARITY_ERROR) { - flag = TTY_PARITY; - status_handle(info, rx); - } else if(rx & URX_OVRUN) { - flag = TTY_OVERRUN; - status_handle(info, rx); - } else if(rx & URX_FRAME_ERROR) { - flag = TTY_FRAME; - status_handle(info, rx); - } - tty_insert_flip_char(tty, ch, flag); -#ifndef CONFIG_XCOPILOT_BUGS - } while((rx = uart->urx.w) & URX_DATA_READY); -#endif - - tty_schedule_flip(tty); - -clear_and_exit: - return; -} - -static void transmit_chars(struct m68k_serial *info) -{ - m68328_uart *uart = &uart_addr[info->line]; - - if (info->x_char) { - /* Send next char */ - uart->utx.b.txdata = info->x_char; - info->x_char = 0; - goto clear_and_return; - } - - if((info->xmit_cnt <= 0) || info->port.tty->stopped) { - /* That's peculiar... TX ints off */ - uart->ustcnt &= ~USTCNT_TX_INTR_MASK; - goto clear_and_return; - } - - /* Send char */ - uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - - if (info->xmit_cnt < WAKEUP_CHARS) - schedule_work(&info->tqueue); - - if(info->xmit_cnt <= 0) { - /* All done for now... TX ints off */ - uart->ustcnt &= ~USTCNT_TX_INTR_MASK; - goto clear_and_return; - } - -clear_and_return: - /* Clear interrupt (should be auto)*/ - return; -} - -/* - * This is the serial driver's generic interrupt routine - */ -irqreturn_t rs_interrupt(int irq, void *dev_id) -{ - struct m68k_serial *info = dev_id; - m68328_uart *uart; - unsigned short rx; - unsigned short tx; - - uart = &uart_addr[info->line]; - rx = uart->urx.w; - -#ifdef USE_INTS - tx = uart->utx.w; - - if (rx & URX_DATA_READY) receive_chars(info, rx); - if (tx & UTX_TX_AVAIL) transmit_chars(info); -#else - receive_chars(info, rx); -#endif - return IRQ_HANDLED; -} - -static void do_softint(struct work_struct *work) -{ - struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; -#if 0 - if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - tty_wakeup(tty); - } -#endif -} - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void do_serial_hangup(struct work_struct *work) -{ - struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup); - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - tty_hangup(tty); -} - - -static int startup(struct m68k_serial * info) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (info->flags & S_INITIALIZED) - return 0; - - if (!info->xmit_buf) { - info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); - if (!info->xmit_buf) - return -ENOMEM; - } - - local_irq_save(flags); - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - - uart->ustcnt = USTCNT_UEN; - info->xmit_fifo_size = 1; - uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; - (void)uart->urx.w; - - /* - * Finally, enable sequencing and interrupts - */ -#ifdef USE_INTS - uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | - USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK; -#else - uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; -#endif - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* - * and set the speed of the serial port - */ - - change_speed(info); - - info->flags |= S_INITIALIZED; - local_irq_restore(flags); - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct m68k_serial * info) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - uart->ustcnt = 0; /* All off! */ - if (!(info->flags & S_INITIALIZED)) - return; - - local_irq_save(flags); - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~S_INITIALIZED; - local_irq_restore(flags); -} - -struct { - int divisor, prescale; -} -#ifndef CONFIG_M68VZ328 - hw_baud_table[18] = { - {0,0}, /* 0 */ - {0,0}, /* 50 */ - {0,0}, /* 75 */ - {0,0}, /* 110 */ - {0,0}, /* 134 */ - {0,0}, /* 150 */ - {0,0}, /* 200 */ - {7,0x26}, /* 300 */ - {6,0x26}, /* 600 */ - {5,0x26}, /* 1200 */ - {0,0}, /* 1800 */ - {4,0x26}, /* 2400 */ - {3,0x26}, /* 4800 */ - {2,0x26}, /* 9600 */ - {1,0x26}, /* 19200 */ - {0,0x26}, /* 38400 */ - {1,0x38}, /* 57600 */ - {0,0x38}, /* 115200 */ -}; -#else - hw_baud_table[18] = { - {0,0}, /* 0 */ - {0,0}, /* 50 */ - {0,0}, /* 75 */ - {0,0}, /* 110 */ - {0,0}, /* 134 */ - {0,0}, /* 150 */ - {0,0}, /* 200 */ - {0,0}, /* 300 */ - {7,0x26}, /* 600 */ - {6,0x26}, /* 1200 */ - {0,0}, /* 1800 */ - {5,0x26}, /* 2400 */ - {4,0x26}, /* 4800 */ - {3,0x26}, /* 9600 */ - {2,0x26}, /* 19200 */ - {1,0x26}, /* 38400 */ - {0,0x26}, /* 57600 */ - {1,0x38}, /* 115200 */ -}; -#endif -/* rate = 1036800 / ((65 - prescale) * (1<line]; - unsigned short port; - unsigned short ustcnt; - unsigned cflag; - int i; - - if (!info->port.tty || !info->port.tty->termios) - return; - cflag = info->port.tty->termios->c_cflag; - if (!(port = info->port)) - return; - - ustcnt = uart->ustcnt; - uart->ustcnt = ustcnt & ~USTCNT_TXEN; - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i = (i & ~CBAUDEX) + B38400; - } - - info->baud = baud_table[i]; - uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | - PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); - - ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); - - if ((cflag & CSIZE) == CS8) - ustcnt |= USTCNT_8_7; - - if (cflag & CSTOPB) - ustcnt |= USTCNT_STOP; - - if (cflag & PARENB) - ustcnt |= USTCNT_PARITYEN; - if (cflag & PARODD) - ustcnt |= USTCNT_ODD_EVEN; - -#ifdef CONFIG_SERIAL_68328_RTS_CTS - if (cflag & CRTSCTS) { - uart->utx.w &= ~ UTX_NOCTS; - } else { - uart->utx.w |= UTX_NOCTS; - } -#endif - - ustcnt |= USTCNT_TXEN; - - uart->ustcnt = ustcnt; - return; -} - -/* - * Fair output driver allows a process to speak. - */ -static void rs_fair_output(void) -{ - int left; /* Output no more than that */ - unsigned long flags; - struct m68k_serial *info = &m68k_soft[0]; - char c; - - if (info == 0) return; - if (info->xmit_buf == 0) return; - - local_irq_save(flags); - left = info->xmit_cnt; - while (left != 0) { - c = info->xmit_buf[info->xmit_tail]; - info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - local_irq_restore(flags); - - rs_put_char(c); - - local_irq_save(flags); - left = min(info->xmit_cnt, left-1); - } - - /* Last character is being transmitted now (hopefully). */ - udelay(5); - - local_irq_restore(flags); - return; -} - -/* - * m68k_console_print is registered for printk. - */ -void console_print_68328(const char *p) -{ - char c; - - while((c=*(p++)) != 0) { - if(c == '\n') - rs_put_char('\r'); - rs_put_char(c); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - rs_fair_output(); - - return; -} - -static void rs_set_ldisc(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) - return; - - info->is_cons = (tty->termios->c_line == N_TTY); - - printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off"); -} - -static void rs_flush_chars(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) - return; -#ifndef USE_INTS - for(;;) { -#endif - - /* Enable transmitter */ - local_irq_save(flags); - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) { - local_irq_restore(flags); - return; - } - -#ifdef USE_INTS - uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; -#else - uart->ustcnt |= USTCNT_TXEN; -#endif - -#ifdef USE_INTS - if (uart->utx.w & UTX_TX_AVAIL) { -#else - if (1) { -#endif - /* Send char */ - uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - } - -#ifndef USE_INTS - while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); - } -#endif - local_irq_restore(flags); -} - -extern void console_printn(const char * b, int count); - -static int rs_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, total = 0; - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_write")) - return 0; - - if (!tty || !info->xmit_buf) - return 0; - - local_save_flags(flags); - while (1) { - local_irq_disable(); - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - local_irq_restore(flags); - - if (c <= 0) - break; - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - - local_irq_disable(); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - local_irq_restore(flags); - buf += c; - count -= c; - total += c; - } - - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { - /* Enable transmitter */ - local_irq_disable(); -#ifndef USE_INTS - while(info->xmit_cnt) { -#endif - - uart->ustcnt |= USTCNT_TXEN; -#ifdef USE_INTS - uart->ustcnt |= USTCNT_TX_INTR_MASK; -#else - while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); -#endif - if (uart->utx.w & UTX_TX_AVAIL) { - uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - } - -#ifndef USE_INTS - } -#endif - local_irq_restore(flags); - } - - return total; -} - -static int rs_write_room(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "rs_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int rs_chars_in_buffer(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) - return 0; - return info->xmit_cnt; -} - -static void rs_flush_buffer(struct tty_struct *tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) - return; - local_irq_save(flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); - tty_wakeup(tty); -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_throttle(struct tty_struct * tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - - /* Turn off RTS line (do this atomic) */ -} - -static void rs_unthrottle(struct tty_struct * tty) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } - - /* Assert RTS line (do this atomic) */ -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int get_serial_info(struct m68k_serial * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = info->port; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - -static int set_serial_info(struct m68k_serial * info, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct m68k_serial old_info; - int retval = 0; - - if (!new_info) - return -EFAULT; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~S_USR_MASK) != - (info->flags & ~S_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~S_USR_MASK) | - (new_serial.flags & S_USR_MASK)); - info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (info->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~S_FLAGS) | - (new_serial.flags & S_FLAGS)); - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - -check_and_exit: - retval = startup(info); - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct m68k_serial * info, unsigned int *value) -{ -#ifdef CONFIG_SERIAL_68328_RTS_CTS - m68328_uart *uart = &uart_addr[info->line]; -#endif - unsigned char status; - unsigned long flags; - - local_irq_save(flags); -#ifdef CONFIG_SERIAL_68328_RTS_CTS - status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0; -#else - status = 0; -#endif - local_irq_restore(flags); - return put_user(status, value); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break(struct m68k_serial * info, unsigned int duration) -{ - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - if (!info->port) - return; - local_irq_save(flags); -#ifdef USE_INTS - uart->utx.w |= UTX_SEND_BREAK; - msleep_interruptible(duration); - uart->utx.w &= ~UTX_SEND_BREAK; -#endif - local_irq_restore(flags); -} - -static int rs_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int error; - struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; - int retval; - - if (serial_paranoia_check(info, tty->name, "rs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - send_break(info, 250); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(100) : 250); - return 0; - case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); - case TIOCSERGSTRUCT: - if (copy_to_user((struct m68k_serial *) arg, - info, sizeof(struct m68k_serial))) - return -EFAULT; - return 0; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - - change_speed(info); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_start(tty); - } - -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * S structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_close(struct tty_struct *tty, struct file * filp) -{ - struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; - m68328_uart *uart = &uart_addr[info->line]; - unsigned long flags; - - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) - return; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - local_irq_restore(flags); - return; - } - - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->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. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk("rs_close: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; - } - if (info->count) { - local_irq_restore(flags); - return; - } - info->flags |= S_CLOSING; - /* - * 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 (info->closing_wait != S_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - - uart->ustcnt &= ~USTCNT_RXEN; - uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); - - shutdown(info); - rs_flush_buffer(tty); - - tty_ldisc_flush(tty); - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; -#warning "This is not and has never been valid so fix it" -#if 0 - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } -#endif - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -void rs_hangup(struct tty_struct *tty) -{ - struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_hangup")) - return; - - rs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~S_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct m68k_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & S_CLOSING) { - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= S_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); - - info->count--; - info->blocked_open++; - while (1) { - local_irq_disable(); - m68k_rtsdtr(info, 1); - local_irq_enable(); - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(info->flags & S_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & S_CLOSING) && do_clocal) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; - - if (retval) - return retval; - info->flags |= S_NORMAL_ACTIVE; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its S structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -int rs_open(struct tty_struct *tty, struct file * filp) -{ - struct m68k_serial *info; - int retval, line; - - line = tty->index; - - if (line >= NR_PORTS || line < 0) /* we have exactly one */ - return -ENODEV; - - info = &m68k_soft[line]; - - if (serial_paranoia_check(info, tty->name, "rs_open")) - return -ENODEV; - - info->count++; - tty->driver_data = info; - info->port.tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - return block_til_ready(tty, filp, info); -} - -/* Finally, routines used to initialize the serial driver. */ - -static void show_serial_version(void) -{ - printk("MC68328 serial driver version 1.00\n"); -} - -static const struct tty_operations rs_ops = { - .open = rs_open, - .close = rs_close, - .write = rs_write, - .flush_chars = rs_flush_chars, - .write_room = rs_write_room, - .chars_in_buffer = rs_chars_in_buffer, - .flush_buffer = rs_flush_buffer, - .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, - .set_termios = rs_set_termios, - .stop = rs_stop, - .start = rs_start, - .hangup = rs_hangup, - .set_ldisc = rs_set_ldisc, -}; - -/* rs_init inits the driver */ -static int __init -rs68328_init(void) -{ - int flags, i; - struct m68k_serial *info; - - serial_driver = alloc_tty_driver(NR_PORTS); - if (!serial_driver) - return -ENOMEM; - - show_serial_version(); - - /* Initialize the tty_driver structure */ - /* SPARC: Not all of this is exactly right for us. */ - - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - 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 = - m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; - 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;imagic = SERIAL_MAGIC; - info->port = (int) &uart_addr[i]; - info->port.tty = NULL; - info->irq = uart_irqs[i]; - info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - INIT_WORK(&info->tqueue, do_softint); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->line = i; - info->is_cons = 1; /* Means shortcuts work */ - - printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, - info->port, info->irq); - printk(" is a builtin MC68328 UART\n"); - -#ifdef CONFIG_M68VZ328 - if (i > 0 ) - PJSEL &= 0xCF; /* PSW enable second port output */ -#endif - - if (request_irq(uart_irqs[i], - rs_interrupt, - IRQF_DISABLED, - "M68328_UART", info)) - panic("Unable to attach 68328 serial interrupt\n"); - } - local_irq_restore(flags); - return 0; -} - -module_init(rs68328_init); - - - -static void m68328_set_baud(void) -{ - unsigned short ustcnt; - int i; - - ustcnt = USTCNT; - USTCNT = ustcnt & ~USTCNT_TXEN; - -again: - for (i = 0; i < ARRAY_SIZE(baud_table); i++) - if (baud_table[i] == m68328_console_baud) - break; - if (i >= ARRAY_SIZE(baud_table)) { - m68328_console_baud = 9600; - goto again; - } - - UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | - PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); - ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); - ustcnt |= USTCNT_8_7; - ustcnt |= USTCNT_TXEN; - USTCNT = ustcnt; - m68328_console_initted = 1; - return; -} - - -int m68328_console_setup(struct console *cp, char *arg) -{ - int i, n = CONSOLE_BAUD_RATE; - - if (!cp) - return(-1); - - if (arg) - n = simple_strtoul(arg,NULL,0); - - for (i = 0; i < ARRAY_SIZE(baud_table); i++) - if (baud_table[i] == n) - break; - if (i < ARRAY_SIZE(baud_table)) { - m68328_console_baud = n; - m68328_console_cbaud = 0; - if (i > 15) { - m68328_console_cbaud |= CBAUDEX; - i -= 15; - } - m68328_console_cbaud |= i; - } - - m68328_set_baud(); /* make sure baud rate changes */ - return(0); -} - - -static struct tty_driver *m68328_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - - -void m68328_console_write (struct console *co, const char *str, - unsigned int count) -{ - if (!m68328_console_initted) - m68328_set_baud(); - while (count--) { - if (*str == '\n') - rs_put_char('\r'); - rs_put_char( *str++ ); - } -} - - -static struct console m68328_driver = { - .name = "ttyS", - .write = m68328_console_write, - .device = m68328_console_device, - .setup = m68328_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - - -static int __init m68328_console_init(void) -{ - register_console(&m68328_driver); - return 0; -} - -console_initcall(m68328_console_init); diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h deleted file mode 100644 index 664ceb0a158c..000000000000 --- a/drivers/serial/68328serial.h +++ /dev/null @@ -1,188 +0,0 @@ -/* 68328serial.h: Definitions for the mc68328 serial driver. - * - * Copyright (C) 1995 David S. Miller - * Copyright (C) 1998 Kenneth Albanowski - * Copyright (C) 1998, 1999 D. Jeff Dionne - * Copyright (C) 1999 Vladimir Gurevich - * - * VZ Support/Fixes Evan Stawnyczy - */ - -#ifndef _MC683XX_SERIAL_H -#define _MC683XX_SERIAL_H - - -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; /* FIXME: We don't have AT&T Hub6 boards! */ - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define S_CLOSING_WAIT_INF 0 -#define S_CLOSING_WAIT_NONE 65535 - -/* - * Definitions for S_struct (and serial_struct) flags field - */ -#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define S_SPD_MASK 0x0030 -#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define S_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define S_FLAGS 0x0FFF /* Possible legal S flags */ -#define S_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define S_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define S_CLOSING 0x08000000 /* Serial port is closing */ -#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ - -/* - * I believe this is the optimal setting that reduces the number of interrupts. - * At high speeds the output might become a little "bursted" (use USTCNT_TXHE - * if that bothers you), but in most cases it will not, since we try to - * transmit characters every time rs_interrupt is called. Thus, quite often - * you'll see that a receive interrupt occures before the transmit one. - * -- Vladimir Gurevich - */ -#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) - -/* - * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special - * "Old data interrupt" which occures whenever the data stay in the FIFO - * longer than 30 bits time. This allows us to use FIFO without compromising - * latency. '328 does not have this feature and without the real 328-based - * board I would assume that RXRE is the safest setting. - * - * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of - * interrupts. RXFE (receive queue full) causes the system to lose data - * at least at 115200 baud - * - * If your board is busy doing other stuff, you might consider to use - * RXRE (data ready intrrupt) instead. - * - * The other option is to make these INTR masks run-time configurable, so - * that people can dynamically adapt them according to the current usage. - * -- Vladimir Gurevich - */ - -/* (es) */ -#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) -#elif defined(CONFIG_M68328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) -#else -#error Please, define the Rx interrupt events for your CPU -#endif -/* (/es) */ - -/* - * 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 m68k_serial { - char soft_carrier; /* Use soft carrier on this channel */ - char break_abort; /* Is serial console in, so process brk/abrt */ - char is_cons; /* Is this our console. */ - - /* We need to know the current clock divisor - * to read the bps rate the chip has currently - * loaded. - */ - unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ - int baud; - int magic; - int baud_base; - int port; - int irq; - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; - int custom_divisor; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - struct work_struct tqueue; - struct work_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -}; - - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -/* - * Define the number of ports supported and their irqs. - */ -#define NR_PORTS 1 -#define UART_IRQ_DEFNS {UART_IRQ_NUM} - -#endif /* __KERNEL__ */ -#endif /* !(_MC683XX_SERIAL_H) */ diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c deleted file mode 100644 index 88b13356ec10..000000000000 --- a/drivers/serial/68360serial.c +++ /dev/null @@ -1,2978 +0,0 @@ -/* - * UART driver for 68360 CPM SCC or SMC - * Copyright (c) 2000 D. Jeff Dionne , - * Copyright (c) 2000 Michael Leslie - * Copyright (c) 1997 Dan Malek - * - * I used the serial.c driver as the framework for this driver. - * Give credit to those guys. - * The original code was written for the MBX860 board. I tried to make - * it generic, but there may be some assumptions in the structures that - * have to be fixed later. - * To save porting time, I did not bother to change any object names - * that are not accessed outside of this file. - * It still needs lots of work........When it was easy, I included code - * to support the SCCs, but this has never been tested, nor is it complete. - * Only the SCCs support modem control, so that is not complete either. - * - * This module exports the following rs232 io functions: - * - * int rs_360_init(void); - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef CONFIG_KGDB -extern void breakpoint(void); -extern void set_debug_traps(void); -extern int kgdb_output_string (const char* s, unsigned int count); -#endif - - -/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */ -#include -#include - -/* this defines the index into rs_table for the port to use - */ -#ifndef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 1 /* ie SMC2 - note USE_SMC2 must be defined */ -#endif -/* #endif */ - -#if 0 -/* SCC2 for console - */ -#undef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 2 -#endif - - -#define TX_WAKEUP ASYNC_SHARE_IRQ - -static char *serial_name = "CPM UART driver"; -static char *serial_version = "0.03"; - -static struct tty_driver *serial_driver; -int serial_console_setup(struct console *co, char *options); - -/* - * Serial driver configuration section. Here are the various options: - */ -#define SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO -#define SERIAL_DO_RESTART - -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - -#define _INLINE_ inline - -#define DBG_CNT(s) - -/* We overload some of the items in the data structure to meet our - * needs. For example, the port address is the CPM parameter ram - * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and - * 2 SMCs. The "hub6" field is used to indicate the channel number, with - * a flag indicating SCC or SMC, and the number is used as an index into - * the CPM parameter area for this device. - * The "type" field is currently set to 0, for PORT_UNKNOWN. It is - * not currently used. I should probably use it to indicate the port - * type of SMC or SCC. - * The SMCs do not support any modem control signals. - */ -#define smc_scc_num hub6 -#define NUM_IS_SCC ((int)0x00010000) -#define PORT_NUM(P) ((P) & 0x0000ffff) - - -#if defined (CONFIG_UCQUICC) - -volatile extern void *_periph_base; -/* sipex transceiver - * mode bits for are on pins - * - * SCC2 d16..19 - * SCC3 d20..23 - * SCC4 d24..27 - */ -#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1))) - -static uint sipex_mode_bits = 0x00000000; - -#endif - -/* There is no `serial_state' defined back here in 2.0. - * Try to get by with serial_struct - */ -/* #define serial_state serial_struct */ - -/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few - * extras: */ - -#if 0 -struct async_icount_24 { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; -} icount; -#endif - -#if 0 - -struct serial_state { - int magic; - int baud_base; - unsigned long port; - int irq; - int flags; - int hub6; - int type; - int line; - int revision; /* Chip revision (950) */ - int xmit_fifo_size; - int custom_divisor; - int count; - u8 *iomem_base; - u16 iomem_reg_shift; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - struct async_icount_24 icount; - int io_type; - struct async_struct *info; -}; -#endif - -#define SSTATE_MAGIC 0x5302 - - - -/* SMC2 is sometimes used for low performance TDM interfaces. Define - * this as 1 if you want SMC2 as a serial port UART managed by this driver. - * Define this as 0 if you wish to use SMC2 for something else. - */ -#define USE_SMC2 1 - -#if 0 -/* Define SCC to ttySx mapping. */ -#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ - -/* Define which SCC is the first one to use for a serial port. These - * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used - * for Ethernet, and the first available SCC for serial UART is SCC2. - * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and - * interrupt vectors in the table below to match. - */ -#define SCC_IDX_BASE 1 /* table index */ -#endif - - -/* Processors other than the 860 only get SMCs configured by default. - * Either they don't have SCCs or they are allocated somewhere else. - * Of course, there are now 860s without some SCCs, so we will need to - * address that someday. - * The Embedded Planet Multimedia I/O cards use TDM interfaces to the - * stereo codec parts, and we use SMC2 to help support that. - */ -static struct serial_state rs_table[] = { -/* type line PORT IRQ FLAGS smc_scc_num (F.K.A. hub6) */ - { 0, 0, PRSLOT_SMC1, CPMVEC_SMC1, 0, 0 } /* SMC1 ttyS0 */ -#if USE_SMC2 - ,{ 0, 0, PRSLOT_SMC2, CPMVEC_SMC2, 0, 1 } /* SMC2 ttyS1 */ -#endif - -#if defined(CONFIG_SERIAL_68360_SCC) - ,{ 0, 0, PRSLOT_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) } /* SCC2 ttyS2 */ - ,{ 0, 0, PRSLOT_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) } /* SCC3 ttyS3 */ - ,{ 0, 0, PRSLOT_SCC4, CPMVEC_SCC4, 0, (NUM_IS_SCC | 3) } /* SCC4 ttyS4 */ -#endif -}; - -#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) - -/* The number of buffer descriptors and their sizes. - */ -#define RX_NUM_FIFO 4 -#define RX_BUF_SIZE 32 -#define TX_NUM_FIFO 4 -#define TX_BUF_SIZE 32 - -#define CONSOLE_NUM_FIFO 2 -#define CONSOLE_BUF_SIZE 4 - -char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE]; - -/* The async_struct in serial.h does not really give us what we - * need, so define our own here. - */ -typedef struct serial_info { - int magic; - int flags; - - struct serial_state *state; - /* struct serial_struct *state; */ - /* struct async_struct *state; */ - - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int line; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int blocked_open; /* # of blocked opens */ - struct work_struct tqueue; - struct work_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - -/* CPM Buffer Descriptor pointers. - */ - QUICC_BD *rx_bd_base; - QUICC_BD *rx_cur; - QUICC_BD *tx_bd_base; - QUICC_BD *tx_cur; -} ser_info_t; - - -/* since kmalloc_init() does not get called until much after this initialization: */ -static ser_info_t quicc_ser_info[NR_PORTS]; -static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE]; -static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE]; - -static void change_speed(ser_info_t *info); -static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout); - -static inline int serial_paranoia_check(ser_info_t *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null async_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts, - * indexed by the termio value. The generic CPM functions are responsible - * for setting and assigning baud rate generators for us. - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; - -/* This sucks. There is a better way: */ -#if defined(CONFIG_CONSOLE_9600) - #define CONSOLE_BAUDRATE 9600 -#elif defined(CONFIG_CONSOLE_19200) - #define CONSOLE_BAUDRATE 19200 -#elif defined(CONFIG_CONSOLE_115200) - #define CONSOLE_BAUDRATE 115200 -#else - #warning "console baud rate undefined" - #define CONSOLE_BAUDRATE 9600 -#endif - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_360_stop(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile struct scc_regs *sccp; - volatile struct smc_regs *smcp; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm &= ~UART_SCCM_TX; - } else { - /* smcp = &cpmp->cp_smc[idx]; */ - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm &= ~SMCM_TX; - } - local_irq_restore(flags); -} - - -static void rs_360_start(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile struct scc_regs *sccp; - volatile struct smc_regs *smcp; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm |= UART_SCCM_TX; - } else { - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm |= SMCM_TX; - } - local_irq_restore(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -static _INLINE_ void receive_chars(ser_info_t *info) -{ - struct tty_struct *tty = info->port.tty; - unsigned char ch, flag, *cp; - /*int ignored = 0;*/ - int i; - ushort status; - struct async_icount *icount; - /* struct async_icount_24 *icount; */ - volatile QUICC_BD *bdp; - - icount = &info->state->icount; - - /* Just loop through the closed BDs and copy the characters into - * the buffer. - */ - bdp = info->rx_cur; - for (;;) { - if (bdp->status & BD_SC_EMPTY) /* If this one is empty */ - break; /* we are all done */ - - /* The read status mask tell us what we should do with - * incoming characters, especially if errors occur. - * One special case is the use of BD_SC_EMPTY. If - * this is not set, we are supposed to be ignoring - * inputs. In this case, just mark the buffer empty and - * continue. - */ - if (!(info->read_status_mask & BD_SC_EMPTY)) { - bdp->status |= BD_SC_EMPTY; - bdp->status &= - ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->status & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - continue; - } - - /* Get the number of characters and the buffer pointer. - */ - i = bdp->length; - /* cp = (unsigned char *)__va(bdp->buf); */ - cp = (char *)bdp->buf; - status = bdp->status; - - while (i-- > 0) { - ch = *cp++; - icount->rx++; - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, status); -#endif - flag = TTY_NORMAL; - - if (status & (BD_SC_BR | BD_SC_FR | - BD_SC_PR | BD_SC_OV)) { - /* - * For statistics only - */ - if (status & BD_SC_BR) - icount->brk++; - else if (status & BD_SC_PR) - icount->parity++; - else if (status & BD_SC_FR) - icount->frame++; - if (status & BD_SC_OV) - icount->overrun++; - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - if (status & info->ignore_status_mask) { - if (++ignored > 100) - break; - continue; - } - */ - status &= info->read_status_mask; - - if (status & (BD_SC_BR)) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); -#endif - *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (status & BD_SC_PR) - flag = TTY_PARITY; - else if (status & BD_SC_FR) - flag = TTY_FRAME; - } - tty_insert_flip_char(tty, ch, flag); - if (status & BD_SC_OV) - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - /* This BD is ready to be used again. Clear status. - * Get next BD. - */ - bdp->status |= BD_SC_EMPTY; - bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->status & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - } - - info->rx_cur = (QUICC_BD *)bdp; - - tty_schedule_flip(tty); -} - -static _INLINE_ void receive_break(ser_info_t *info) -{ - struct tty_struct *tty = info->port.tty; - - info->state->icount.brk++; - /* Check to see if there is room in the tty buffer for - * the break. If not, we exit now, losing the break. FIXME - */ - tty_insert_flip_char(tty, 0, TTY_BREAK); - tty_schedule_flip(tty); -} - -static _INLINE_ void transmit_chars(ser_info_t *info) -{ - - if ((info->flags & TX_WAKEUP) || - (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) { - schedule_work(&info->tqueue); - } - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif -} - -#ifdef notdef - /* I need to do this for the SCCs, so it is left as a reminder. - */ -static _INLINE_ void check_modem_status(struct async_struct *info) -{ - int status; - /* struct async_icount *icount; */ - struct async_icount_24 *icount; - - status = serial_in(info, UART_MSR); - - if (status & UART_MSR_ANY_DELTA) { - icount = &info->state->icount; - /* update input line counters */ - if (status & UART_MSR_TERI) - icount->rng++; - if (status & UART_MSR_DDSR) - icount->dsr++; - if (status & UART_MSR_DDCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif - } - if (status & UART_MSR_DCTS) - icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); - } - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { -#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttys%d CD now %s...", info->line, - (status & UART_MSR_DCD) ? "on" : "off"); -#endif - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - else { -#ifdef SERIAL_DEBUG_OPEN - printk("scheduling hangup..."); -#endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); - } - } - if (info->flags & ASYNC_CTS_FLOW) { - if (info->port.tty->hw_stopped) { - if (status & UART_MSR_CTS) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx start..."); -#endif - info->port.tty->hw_stopped = 0; - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - return; - } - } else { - if (!(status & UART_MSR_CTS)) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx stop..."); -#endif - info->port.tty->hw_stopped = 1; - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - } - } -} -#endif - -/* - * This is the serial driver's interrupt routine for a single port - */ -/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */ -static void rs_360_interrupt(int vec, void *dev_id) -{ - u_char events; - int idx; - ser_info_t *info; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - info = dev_id; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - events = sccp->scc_scce; - if (events & SCCM_RX) - receive_chars(info); - if (events & SCCM_TX) - transmit_chars(info); - sccp->scc_scce = events; - } else { - smcp = &pquicc->smc_regs[idx]; - events = smcp->smc_smce; - if (events & SMCM_BRKE) - receive_break(info); - if (events & SMCM_RX) - receive_chars(info); - if (events & SMCM_TX) - transmit_chars(info); - smcp->smc_smce = events; - } - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_single(%d, %x)...", - info->state->smc_scc_num, events); -#endif -#ifdef modem_control - check_modem_status(info); -#endif - info->last_active = jiffies; -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - - -static void do_softint(void *private_) -{ - ser_info_t *info = (ser_info_t *) private_; - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) - tty_wakeup(tty); -} - - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void do_serial_hangup(void *private_) -{ - struct async_struct *info = (struct async_struct *) private_; - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - tty_hangup(tty); -} - - -static int startup(ser_info_t *info) -{ - unsigned long flags; - int retval=0; - int idx; - /*struct serial_state *state = info->state;*/ - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - volatile struct smc_uart_pram *up; - volatile struct uart_pram *scup; - - - local_irq_save(flags); - - if (info->flags & ASYNC_INITIALIZED) { - goto errout; - } - -#ifdef maybe - if (!state->port || !state->type) { - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - goto errout; - } -#endif - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, state->irq); -#endif - - -#ifdef modem_control - info->MCR = 0; - if (info->port.tty->termios->c_cflag & CBAUD) - info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#endif - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - /* - * and set the speed of the serial port - */ - change_speed(info); - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - scup = &pquicc->pram[info->state->port].scc.pscc.u; - - scup->mrblr = RX_BUF_SIZE; - scup->max_idl = RX_BUF_SIZE; - - sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); - sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Enable interrupts and I/O. - */ - smcp->smc_smcm |= (SMCM_RX | SMCM_TX); - smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); - - /* We can tune the buffer length and idle characters - * to take advantage of the entire incoming buffer size. - * If mrblr is something other than 1, maxidl has to be - * non-zero or we never get an interrupt. The maxidl - * is the number of character times we wait after reception - * of the last character before we decide no more characters - * are coming. - */ - /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */ - /* holy unionized structures, Batman: */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - - up->mrblr = RX_BUF_SIZE; - up->max_idl = RX_BUF_SIZE; - - up->brkcr = 1; /* number of break chars */ - } - - info->flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; - -errout: - local_irq_restore(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(ser_info_t *info) -{ - unsigned long flags; - struct serial_state *state; - int idx; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - state = info->state; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....", info->line, - state->irq); -#endif - - local_irq_save(flags); - - idx = PORT_NUM(state->smc_scc_num); - if (state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) -#endif - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Disable interrupts and I/O. - */ - smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) -#endif - smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(ser_info_t *info) -{ - int baud_rate; - unsigned cflag, cval, scval, prev_mode; - int i, bits, sbits, idx; - unsigned long flags; - struct serial_state *state; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!info->port.tty || !info->port.tty->termios) - return; - cflag = info->port.tty->termios->c_cflag; - - state = info->state; - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ - cval = 0; - scval = 0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: bits = 5; break; - case CS6: bits = 6; break; - case CS7: bits = 7; break; - case CS8: bits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: bits = 8; break; - } - sbits = bits - 5; - - if (cflag & CSTOPB) { - cval |= SMCMR_SL; /* Two stops */ - scval |= SCU_PMSR_SL; - bits++; - } - if (cflag & PARENB) { - cval |= SMCMR_PEN; - scval |= SCU_PMSR_PEN; - bits++; - } - if (!(cflag & PARODD)) { - cval |= SMCMR_PM_EVEN; - scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); - } - - /* Determine divisor based on baud rate */ - i = cflag & CBAUD; - if (i >= (sizeof(baud_table)/sizeof(int))) - baud_rate = 9600; - else - baud_rate = baud_table[i]; - - info->timeout = (TX_BUF_SIZE*HZ*bits); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - -#ifdef modem_control - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) - info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - } else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - serial_out(info, UART_IER, info->IER); -#endif - - /* - * Set up parity check flag - */ - info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); - if (I_INPCK(info->port.tty)) - info->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask |= BD_SC_BR; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (I_IGNBRK(info->port.tty)) { - info->ignore_status_mask |= BD_SC_BR; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= BD_SC_OV; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - info->read_status_mask &= ~BD_SC_EMPTY; - local_irq_save(flags); - - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; - idx = PORT_NUM(state->smc_scc_num); - if (state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_psmr = (sbits << 12) | scval; - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Set the mode register. We want to keep a copy of the - * enables, because we want to put them back if they were - * present. - */ - prev_mode = smcp->smc_smcmr; - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); - } - - m360_cpm_setbrg((state - rs_table), baud_rate); - - local_irq_restore(flags); -} - -static void rs_360_put_char(struct tty_struct *tty, unsigned char ch) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile QUICC_BD *bdp; - - if (serial_paranoia_check(info, tty->name, "rs_put_char")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - while (bdp->status & BD_SC_READY); - - /* *((char *)__va(bdp->buf)) = ch; */ - *((char *)bdp->buf) = ch; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (QUICC_BD *)bdp; - return 1; - -} - -static int rs_360_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile QUICC_BD *bdp; - -#ifdef CONFIG_KGDB - /* Try to let stub handle output. Returns true if it did. */ - if (kgdb_output_string(buf, count)) - return ret; -#endif - - if (serial_paranoia_check(info, tty->name, "rs_write")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - - while (1) { - c = min(count, TX_BUF_SIZE); - - if (c <= 0) - break; - - if (bdp->status & BD_SC_READY) { - info->flags |= TX_WAKEUP; - break; - } - - /* memcpy(__va(bdp->buf), buf, c); */ - memcpy((void *)bdp->buf, buf, c); - - bdp->length = c; - bdp->status |= BD_SC_READY; - - buf += c; - count -= c; - ret += c; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - info->tx_cur = (QUICC_BD *)bdp; - } - return ret; -} - -static int rs_360_write_room(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "rs_write_room")) - return 0; - - if ((info->tx_cur->status & BD_SC_READY) == 0) { - info->flags &= ~TX_WAKEUP; - ret = TX_BUF_SIZE; - } - else { - info->flags |= TX_WAKEUP; - ret = 0; - } - return ret; -} - -/* I could track this with transmit counters....maybe later. -*/ -static int rs_360_chars_in_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) - return 0; - return 0; -} - -static void rs_360_flush_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) - return; - - /* There is nothing to "flush", whatever we gave the CPM - * is on its way out. - */ - tty_wakeup(tty); - info->flags &= ~TX_WAKEUP; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void rs_360_send_xchar(struct tty_struct *tty, char ch) -{ - volatile QUICC_BD *bdp; - - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_send_char")) - return; - - bdp = info->tx_cur; - while (bdp->status & BD_SC_READY); - - /* *((char *)__va(bdp->buf)) = ch; */ - *((char *)bdp->buf) = ch; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (QUICC_BD *)bdp; -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_360_throttle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - rs_360_send_xchar(tty, STOP_CHAR(tty)); - -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR &= ~UART_MCR_RTS; - - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif -} - -static void rs_360_unthrottle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_360_send_xchar(tty, START_CHAR(tty)); - } -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR |= UART_MCR_RTS; - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -#ifdef maybe -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct async_struct * info, unsigned int *value) -{ - unsigned char status; - unsigned int result; - - local_irq_disable(); - status = serial_in(info, UART_LSR); - local_irq_enable(); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); -} -#endif - -static int rs_360_tiocmget(struct tty_struct *tty, struct file *file) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned int result = 0; -#ifdef modem_control - unsigned char control, status; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - control = info->MCR; - local_irq_disable(); - status = serial_in(info, UART_MSR); - local_irq_enable(); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) -#ifdef TIOCM_OUT1 - | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) - | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) -#endif - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -#endif - return result; -} - -static int rs_360_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ -#ifdef modem_control - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned int arg; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - /* FIXME: locking on info->mcr */ - if (set & TIOCM_RTS) - info->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - info->mcr |= UART_MCR_DTR; - if (clear & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; - -#ifdef TIOCM_OUT1 - if (set & TIOCM_OUT1) - info->MCR |= UART_MCR_OUT1; - if (set & TIOCM_OUT2) - info->MCR |= UART_MCR_OUT2; - if (clear & TIOCM_OUT1) - info->MCR &= ~UART_MCR_OUT1; - if (clear & TIOCM_OUT2) - info->MCR &= ~UART_MCR_OUT2; -#endif - - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif - return 0; -} - -/* Sending a break is a two step process on the SMC/SCC. It is accomplished - * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT - * command. We take advantage of the begin/end functions to make this - * happen. - */ -static ushort smc_chan_map[] = { - CPM_CR_CH_SMC1, - CPM_CR_CH_SMC2 -}; - -static ushort scc_chan_map[] = { - CPM_CR_CH_SCC1, - CPM_CR_CH_SCC2, - CPM_CR_CH_SCC3, - CPM_CR_CH_SCC4 -}; - -static void begin_break(ser_info_t *info) -{ - volatile QUICC *cp; - ushort chan; - int idx; - - cp = pquicc; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) - chan = scc_chan_map[idx]; - else - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); -} - -static void end_break(ser_info_t *info) -{ - volatile QUICC *cp; - ushort chan; - int idx; - - cp = pquicc; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) - chan = scc_chan_map[idx]; - else - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break(ser_info_t *info, unsigned int duration) -{ -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); -#endif - begin_break(info); - msleep_interruptible(duration); - end_break(info); -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("done jiffies=%lu\n", jiffies); -#endif -} - - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int rs_360_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct async_icount cnow; - - local_irq_disable(); - cnow = info->state->icount; - local_irq_enable(); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - - return 0; -} - -static int rs_360_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int error; - ser_info_t *info = (ser_info_t *)tty->driver_data; - int retval; - struct async_icount cnow; - /* struct async_icount_24 cnow;*/ /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ - - if (serial_paranoia_check(info, tty->name, "rs_ioctl")) - return -ENODEV; - - if (cmd != TIOCMIWAIT) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, 250); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*100 : 250); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCSBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - begin_break(info); - return 0; - case TIOCCBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - end_break(info); - return 0; -#ifdef maybe - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); -#endif - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: -#ifdef modem_control - local_irq_disable(); - /* note the counters on entry */ - cprev = info->state->icount; - local_irq_enable(); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - local_irq_disable(); - cnow = info->state->icount; /* atomic copy */ - local_irq_enable(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ -#else - return 0; -#endif - - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -/* FIX UP modem control here someday...... -*/ -static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - change_speed(info); - -#ifdef modem_control - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - info->MCR |= UART_MCR_DTR; - if (!tty->hw_stopped || - !(tty->termios->c_cflag & CRTSCTS)) { - info->MCR |= UART_MCR_RTS; - } - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_360_start(tty); - } -#endif - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_360_close(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - /* struct async_state *state; */ - struct serial_state *state; - unsigned long flags; - int idx; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) - return; - - state = info->state; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - local_irq_restore(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, state->count); -#endif - if ((tty->count == 1) && (state->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. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - if (--state->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); - state->count = 0; - } - if (state->count) { - DBG_CNT("before DEC-2"); - local_irq_restore(flags); - return; - } - info->flags |= ASYNC_CLOSING; - /* - * 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 (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->read_status_mask &= ~BD_SC_EMPTY; - if (info->flags & ASYNC_INITIALIZED) { - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm &= ~UART_SCCM_RX; - sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR; - } else { - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm &= ~SMCM_RX; - smcp->smc_smcmr &= ~SMCMR_REN; - } - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - rs_360_wait_until_sent(tty, info->timeout); - } - shutdown(info); - rs_360_flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned long orig_jiffies, char_time; - /*int lsr;*/ - volatile QUICC_BD *bdp; - - if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) - return; - -#ifdef maybe - if (info->state->type == PORT_UNKNOWN) - return; -#endif - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = 1; - if (timeout) - char_time = min(char_time, (unsigned long)timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - - /* We go through the loop at least once because we can't tell - * exactly when the last character exits the shifter. There can - * be at least two characters waiting to be sent after the buffers - * are empty. - */ - do { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif -/* current->counter = 0; make us low-priority */ - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && (time_after(jiffies, orig_jiffies + timeout))) - break; - /* The 'tx_cur' is really the next buffer to send. We - * have to back up to the previous BD and wait for it - * to go. This isn't perfect, because all this indicates - * is the buffer is available. There are still characters - * in the CPM FIFO. - */ - bdp = info->tx_cur; - if (bdp == info->tx_bd_base) - bdp += (TX_NUM_FIFO-1); - else - bdp--; - } while (bdp->status & BD_SC_READY); - current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rs_360_hangup(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct serial_state *state = info->state; - - if (serial_paranoia_check(info, tty->name, "rs_hangup")) - return; - - state = info->state; - - rs_360_flush_buffer(tty); - shutdown(info); - info->event = 0; - state->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - ser_info_t *info) -{ -#ifdef DO_THIS_LATER - DECLARE_WAITQUEUE(wait, current); -#endif - struct serial_state *state = info->state; - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - * If this is an SMC port, we don't have modem control to wait - * for, so just get out here. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR)) || - !(info->state->smc_scc_num & NUM_IS_SCC)) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; -#ifdef DO_THIS_LATER - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - state->line, state->count); -#endif - local_irq_disable(); - if (!tty_hung_up_p(filp)) - state->count--; - local_irq_enable(); - info->blocked_open++; - while (1) { - local_irq_disable(); - if (tty->termios->c_cflag & CBAUD) - serial_out(info, UART_MCR, - serial_inp(info, UART_MCR) | - (UART_MCR_DTR | UART_MCR_RTS)); - local_irq_enable(); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CLOSING) && - (do_clocal || (serial_in(info, UART_MSR) & - UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - state->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif -#endif /* DO_THIS_LATER */ - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int get_async_struct(int line, ser_info_t **ret_info) -{ - struct serial_state *sstate; - - sstate = rs_table + line; - if (sstate->info) { - sstate->count++; - *ret_info = (ser_info_t *)sstate->info; - return 0; - } - else { - return -ENOMEM; - } -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int rs_360_open(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info; - int retval, line; - - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - retval = get_async_struct(line, &info); - if (retval) - return retval; - if (serial_paranoia_check(info, tty->name, "rs_open")) - return -ENODEV; - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s, count = %d\n", tty->name, info->state->count); -#endif - tty->driver_data = info; - info->port.tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s successful...", tty->name); -#endif - return 0; -} - -/* - * /proc fs routines.... - */ - -static inline int line_info(char *buf, struct serial_state *state) -{ -#ifdef notdef - struct async_struct *info = state->info, scr_info; - char stat_buf[30], control, status; -#endif - int ret; - - ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", - state->line, - (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC", - (unsigned int)(state->port), state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } - -#ifdef notdef - /* - * Figure out the current RS-232 lines - */ - if (!info) { - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->port = state->port; - info->flags = state->flags; - info->quot = 0; - info->port.tty = NULL; - } - local_irq_disable(); - status = serial_in(info, UART_MSR); - control = info ? info->MCR : serial_in(info, UART_MCR); - local_irq_enable(); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (control & UART_MCR_RTS) - strcat(stat_buf, "|RTS"); - if (status & UART_MSR_CTS) - strcat(stat_buf, "|CTS"); - if (control & UART_MCR_DTR) - strcat(stat_buf, "|DTR"); - if (status & UART_MSR_DSR) - strcat(stat_buf, "|DSR"); - if (status & UART_MSR_DCD) - strcat(stat_buf, "|CD"); - if (status & UART_MSR_RI) - strcat(stat_buf, "|RI"); - - if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - state->baud_base / info->quot); - } - - ret += sprintf(buf+ret, " tx:%d rx:%d", - state->icount.tx, state->icount.rx); - - if (state->icount.frame) - ret += sprintf(buf+ret, " fe:%d", state->icount.frame); - - if (state->icount.parity) - ret += sprintf(buf+ret, " pe:%d", state->icount.parity); - - if (state->icount.brk) - ret += sprintf(buf+ret, " brk:%d", state->icount.brk); - - if (state->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); -#endif - return ret; -} - -int rs_360_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i, len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - len += line_info(page + len, &rs_table[i]); - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (begin-off); - return ((count < begin+len-off) ? count : begin+len-off); -} - -/* - * --------------------------------------------------------------------- - * rs_init() and friends - * - * rs_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static _INLINE_ void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); -} - - -/* - * The serial console driver used during boot. Note that these names - * clash with those found in "serial.c", so we currently can't support - * the 16xxx uarts and these at the same time. I will fix this to become - * an indirect function call from tty_io.c (or something). - */ - -#ifdef CONFIG_SERIAL_CONSOLE - -/* - * Print a string to the serial port trying not to disturb any possible - * real use of the port... - */ -static void my_console_write(int idx, const char *s, - unsigned count) -{ - struct serial_state *ser; - ser_info_t *info; - unsigned i; - QUICC_BD *bdp, *bdbase; - volatile struct smc_uart_pram *up; - volatile u_char *cp; - - ser = rs_table + idx; - - - /* If the port has been initialized for general use, we have - * to use the buffer descriptors allocated there. Otherwise, - * we simply use the single buffer allocated. - */ - if ((info = (ser_info_t *)ser->info) != NULL) { - bdp = info->tx_cur; - bdbase = info->tx_bd_base; - } - else { - /* Pointer to UART in parameter ram. - */ - /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ - up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; - - /* Get the address of the host memory buffer. - */ - bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); - } - - /* - * We need to gracefully shut down the transmitter, disable - * interrupts, then send our bytes out. - */ - - /* - * Now, do each character. This is not as bad as it looks - * since this is a holding FIFO and not a transmitting FIFO. - * We could add the complexity of filling the entire transmit - * buffer, but we would just wait longer between accesses...... - */ - for (i = 0; i < count; i++, s++) { - /* Wait for transmitter fifo to empty. - * Ready indicates output is ready, and xmt is doing - * that, not that it is ready for us to send. - */ - while (bdp->status & BD_SC_READY); - - /* Send the character out. - */ - cp = bdp->buf; - *cp = *s; - - bdp->length = 1; - bdp->status |= BD_SC_READY; - - if (bdp->status & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - - /* if a LF, also do CR... */ - if (*s == 10) { - while (bdp->status & BD_SC_READY); - /* cp = __va(bdp->buf); */ - cp = bdp->buf; - *cp = 13; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - if (bdp->status & BD_SC_WRAP) { - bdp = bdbase; - } - else { - bdp++; - } - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - while (bdp->status & BD_SC_READY); - - if (info) - info->tx_cur = (QUICC_BD *)bdp; -} - -static void serial_console_write(struct console *c, const char *s, - unsigned count) -{ -#ifdef CONFIG_KGDB - /* Try to let stub handle output. Returns true if it did. */ - if (kgdb_output_string(s, count)) - return; -#endif - my_console_write(c->index, s, count); -} - - - -/*void console_print_68360(const char *p) -{ - const char *cp = p; - int i; - - for (i=0;cp[i]!=0;i++); - - serial_console_write (p, i); - - //Comment this if you want to have a strict interrupt-driven output - //rs_fair_output(); - - return; -}*/ - - - - - - -#ifdef CONFIG_XMON -int -xmon_360_write(const char *s, unsigned count) -{ - my_console_write(0, s, count); - return(count); -} -#endif - -#ifdef CONFIG_KGDB -void -putDebugChar(char ch) -{ - my_console_write(0, &ch, 1); -} -#endif - -/* - * Receive character from the serial port. This only works well - * before the port is initialized for real use. - */ -static int my_console_wait_key(int idx, int xmon, char *obuf) -{ - struct serial_state *ser; - u_char c, *cp; - ser_info_t *info; - QUICC_BD *bdp; - volatile struct smc_uart_pram *up; - int i; - - ser = rs_table + idx; - - /* Get the address of the host memory buffer. - * If the port has been initialized for general use, we must - * use information from the port structure. - */ - if ((info = (ser_info_t *)ser->info)) - bdp = info->rx_cur; - else - /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */ - bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); - - /* Pointer to UART in parameter ram. - */ - /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - - /* - * We need to gracefully shut down the receiver, disable - * interrupts, then read the input. - * XMON just wants a poll. If no character, return -1, else - * return the character. - */ - if (!xmon) { - while (bdp->status & BD_SC_EMPTY); - } - else { - if (bdp->status & BD_SC_EMPTY) - return -1; - } - - cp = (char *)bdp->buf; - - if (obuf) { - i = c = bdp->length; - while (i-- > 0) - *obuf++ = *cp++; - } - else { - c = *cp; - } - bdp->status |= BD_SC_EMPTY; - - if (info) { - if (bdp->status & BD_SC_WRAP) { - bdp = info->rx_bd_base; - } - else { - bdp++; - } - info->rx_cur = (QUICC_BD *)bdp; - } - - return((int)c); -} - -static int serial_console_wait_key(struct console *co) -{ - return(my_console_wait_key(co->index, 0, NULL)); -} - -#ifdef CONFIG_XMON -int -xmon_360_read_poll(void) -{ - return(my_console_wait_key(0, 1, NULL)); -} - -int -xmon_360_read_char(void) -{ - return(my_console_wait_key(0, 0, NULL)); -} -#endif - -#ifdef CONFIG_KGDB -static char kgdb_buf[RX_BUF_SIZE], *kgdp; -static int kgdb_chars; - -unsigned char -getDebugChar(void) -{ - if (kgdb_chars <= 0) { - kgdb_chars = my_console_wait_key(0, 0, kgdb_buf); - kgdp = kgdb_buf; - } - kgdb_chars--; - - return(*kgdp++); -} - -void kgdb_interruptible(int state) -{ -} -void kgdb_map_scc(void) -{ - struct serial_state *ser; - uint mem_addr; - volatile QUICC_BD *bdp; - volatile smc_uart_t *up; - - cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - - /* To avoid data cache CPM DMA coherency problems, allocate a - * buffer in the CPM DPRAM. This will work until the CPM and - * serial ports are initialized. At that time a memory buffer - * will be allocated. - * The port is already initialized from the boot procedure, all - * we do here is give it a different buffer and make it a FIFO. - */ - - ser = rs_table; - - /* Right now, assume we are using SMCs. - */ - up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; - - /* Allocate space for an input FIFO, plus a few bytes for output. - * Allocate bytes to maintain word alignment. - */ - mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]); - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; - bdp->buf = mem_addr; - - bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase]; - bdp->buf = mem_addr+RX_BUF_SIZE; - - up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */ - up->smc_maxidl = RX_BUF_SIZE; -} -#endif - -static struct tty_struct *serial_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - - -struct console sercons = { - .name = "ttyS", - .write = serial_console_write, - .device = serial_console_device, - .wait_key = serial_console_wait_key, - .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = CONFIG_SERIAL_CONSOLE_PORT, -}; - - - -/* - * Register console. - */ -long console_360_init(long kmem_start, long kmem_end) -{ - register_console(&sercons); - /*register_console (console_print_68360); - 2.0.38 only required a write - function pointer. */ - return kmem_start; -} - -#endif - -/* Index in baud rate table of the default console baud rate. -*/ -static int baud_idx; - -static const struct tty_operations rs_360_ops = { - .owner = THIS_MODULE, - .open = rs_360_open, - .close = rs_360_close, - .write = rs_360_write, - .put_char = rs_360_put_char, - .write_room = rs_360_write_room, - .chars_in_buffer = rs_360_chars_in_buffer, - .flush_buffer = rs_360_flush_buffer, - .ioctl = rs_360_ioctl, - .throttle = rs_360_throttle, - .unthrottle = rs_360_unthrottle, - /* .send_xchar = rs_360_send_xchar, */ - .set_termios = rs_360_set_termios, - .stop = rs_360_stop, - .start = rs_360_start, - .hangup = rs_360_hangup, - /* .wait_until_sent = rs_360_wait_until_sent, */ - /* .read_proc = rs_360_read_proc, */ - .tiocmget = rs_360_tiocmget, - .tiocmset = rs_360_tiocmset, -}; - -static int __init rs_360_init(void) -{ - struct serial_state * state; - ser_info_t *info; - void *mem_addr; - uint dp_addr, iobits; - int i, j, idx; - ushort chan; - QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct smc_regs *sp; - volatile struct smc_uart_pram *up; - volatile struct scc_regs *scp; - volatile struct uart_pram *sup; - /* volatile immap_t *immap; */ - - serial_driver = alloc_tty_driver(NR_PORTS); - if (!serial_driver) - return -1; - - show_serial_version(); - - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - 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 = - baud_idx | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &rs_360_ops); - - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); - - cp = pquicc; /* Get pointer to Communication Processor */ - /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ - - - /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. - */ - /* The "standard" configuration through the 860. - */ -/* immap->im_ioport.iop_papar |= 0x00fc; */ -/* immap->im_ioport.iop_padir &= ~0x00fc; */ -/* immap->im_ioport.iop_paodr &= ~0x00fc; */ - cp->pio_papar |= 0x00fc; - cp->pio_padir &= ~0x00fc; - /* cp->pio_paodr &= ~0x00fc; */ - - - /* Since we don't yet do modem control, connect the port C pins - * as general purpose I/O. This will assert CTS and CD for the - * SCC ports. - */ - /* FIXME: see 360um p.7-365 and 860um p.34-12 - * I can't make sense of these bits - mleslie*/ -/* immap->im_ioport.iop_pcdir |= 0x03c6; */ -/* immap->im_ioport.iop_pcpar &= ~0x03c6; */ - -/* cp->pio_pcdir |= 0x03c6; */ -/* cp->pio_pcpar &= ~0x03c6; */ - - - - /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and - * BRG4 to SCC3. - */ - cp->si_sicr &= ~0x00ffff00; - cp->si_sicr |= 0x001b1200; - -#ifdef CONFIG_PP04 - /* Frequentis PP04 forced to RS-232 until we know better. - * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4. - */ - immap->im_ioport.iop_pcdir |= 0x000c; - immap->im_ioport.iop_pcpar &= ~0x000c; - immap->im_ioport.iop_pcdat &= ~0x000c; - - /* This enables the TX driver. - */ - cp->cp_pbpar &= ~0x6000; - cp->cp_pbdat &= ~0x6000; -#endif - - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - state->magic = SSTATE_MAGIC; - state->line = i; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n", - i, (unsigned int)(state->irq), - (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC"); - -#ifdef CONFIG_SERIAL_CONSOLE - /* If we just printed the message on the console port, and - * we are about to initialize it for general use, we have - * to wait a couple of character times for the CR/NL to - * make it out of the transmit buffer. - */ - if (i == CONFIG_SERIAL_CONSOLE_PORT) - mdelay(8); - - -/* idx = PORT_NUM(info->state->smc_scc_num); */ -/* if (info->state->smc_scc_num & NUM_IS_SCC) */ -/* chan = scc_chan_map[idx]; */ -/* else */ -/* chan = smc_chan_map[idx]; */ - -/* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */ -/* while (cp->cp_cr & CPM_CR_FLG); */ - -#endif - /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */ - info = &quicc_ser_info[i]; - if (info) { - memset (info, 0, sizeof(ser_info_t)); - info->magic = SERIAL_MAGIC; - info->line = i; - info->flags = state->flags; - INIT_WORK(&info->tqueue, do_softint, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->state = state; - state->info = (struct async_struct *)info; - - /* We need to allocate a transmit and receive buffer - * descriptors from dual port ram, and a character - * buffer area from host mem. - */ - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO); - - /* Allocate space for FIFOs in the host memory. - * (for now this is from a static array of buffers :( - */ - /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */ - /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */ - mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE]; - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - info->rx_cur = info->rx_bd_base = bdp; - - /* initialize rx buffer descriptors */ - for (j=0; j<(RX_NUM_FIFO-1); j++) { - bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; - bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; - mem_addr += RX_BUF_SIZE; - bdp++; - } - bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; - bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - -#if defined (CONFIG_UCQUICC) && 1 - /* set the transceiver mode to RS232 */ - sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */ - sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02); - *(uint *)_periph_base = sipex_mode_bits; - /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */ -#endif - } - - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO); - - /* Allocate space for FIFOs in the host memory. - */ - /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */ - /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */ - mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE]; - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp; - - /* initialize tx buffer descriptors */ - for (j=0; j<(TX_NUM_FIFO-1); j++) { - bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; - bdp->status = BD_SC_INTRPT; - mem_addr += TX_BUF_SIZE; - bdp++; - } - bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; - bdp->status = (BD_SC_WRAP | BD_SC_INTRPT); - - if (info->state->smc_scc_num & NUM_IS_SCC) { - scp = &pquicc->scc_regs[idx]; - sup = &pquicc->pram[info->state->port].scc.pscc.u; - sup->rbase = dp_addr; - sup->tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->rfcr = SMC_EB; - sup->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - sup->mrblr = 1; - sup->max_idl = 0; - sup->brkcr = 1; - sup->parec = 0; - sup->frmer = 0; - sup->nosec = 0; - sup->brkec = 0; - sup->uaddr1 = 0; - sup->uaddr2 = 0; - sup->toseq = 0; - { - int i; - for (i=0;i<8;i++) - sup->cc[i] = 0x8000; - } - sup->rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - chan = scc_chan_map[idx]; - - /* execute the INIT RX & TX PARAMS command for this channel. */ - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmr.w.high = 0; - scp->scc_gsmr.w.low = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - } - else { - /* Configure SMCs Tx/Rx instead of port B - * parallel I/O. - */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - up->rbase = dp_addr; - - iobits = 0xc0 << (idx * 4); - cp->pip_pbpar |= iobits; - cp->pip_pbdir &= ~iobits; - cp->pip_pbodr &= ~iobits; - - - /* Connect the baud rate generator to the - * SMC based upon index in rs_table. Also - * make sure it is connected to NMSI. - */ - cp->si_simode &= ~(0xffff << (idx * 16)); - cp->si_simode |= (i << ((idx * 16) + 12)); - - up->tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - up->rfcr = SMC_EB; - up->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - up->mrblr = 1; - up->max_idl = 0; - up->brkcr = 1; - - /* Send the CPM an initialize command. - */ - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, - CPM_CR_INIT_TRX) | CPM_CR_FLG; -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - printk(""); -#endif - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp = &cp->smc_regs[idx]; - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Disable all interrupts and clear all pending - * events. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -#endif - } - - /* Install interrupt handler. - */ - /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */ - /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */ - request_irq(state->irq, rs_360_interrupt, - IRQ_FLG_LOCK, "ttyS", (void *)info); - - /* Set up the baud rate generator. - */ - m360_cpm_setbrg(i, baud_table[baud_idx]); - - } - } - - return 0; -} -module_init(rs_360_init); - -/* This must always be called before the rs_360_init() function, otherwise - * it blows away the port control information. - */ -//static int __init serial_console_setup( struct console *co, char *options) -int serial_console_setup( struct console *co, char *options) -{ - struct serial_state *ser; - uint mem_addr, dp_addr, bidx, idx, iobits; - ushort chan; - QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct smc_regs *sp; - volatile struct scc_regs *scp; - volatile struct smc_uart_pram *up; - volatile struct uart_pram *sup; - -/* mleslie TODO: - * add something to the 68k bootloader to store a desired initial console baud rate */ - -/* bd_t *bd; */ /* a board info struct used by EPPC-bug */ -/* bd = (bd_t *)__res; */ - - for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) - /* if (bd->bi_baudrate == baud_table[bidx]) */ - if (CONSOLE_BAUDRATE == baud_table[bidx]) - break; - - /* co->cflag = CREAD|CLOCAL|bidx|CS8; */ - baud_idx = bidx; - - ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; - - cp = pquicc; /* Get pointer to Communication Processor */ - - idx = PORT_NUM(ser->smc_scc_num); - if (ser->smc_scc_num & NUM_IS_SCC) { - - /* TODO: need to set up SCC pin assignment etc. here */ - - } - else { - iobits = 0xc0 << (idx * 4); - cp->pip_pbpar |= iobits; - cp->pip_pbdir &= ~iobits; - cp->pip_pbodr &= ~iobits; - - /* Connect the baud rate generator to the - * SMC based upon index in rs_table. Also - * make sure it is connected to NMSI. - */ - cp->si_simode &= ~(0xffff << (idx * 16)); - cp->si_simode |= (idx << ((idx * 16) + 12)); - } - - /* When we get here, the CPM has been reset, so we need - * to configure the port. - * We need to allocate a transmit and receive buffer descriptor - * from dual port ram, and a character buffer area from host mem. - */ - - /* Allocate space for two buffer descriptors in the DP ram. - */ - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO); - - /* Allocate space for two 2 byte FIFOs in the host memory. - */ - /* mem_addr = m360_cpm_hostalloc(8); */ - mem_addr = (uint)console_fifos; - - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - bdp->buf = (char *)mem_addr; - (bdp+1)->buf = (char *)(mem_addr+4); - - /* For the receive, set empty and wrap. - * For transmit, set wrap. - */ - bdp->status = BD_SC_EMPTY | BD_SC_WRAP; - (bdp+1)->status = BD_SC_WRAP; - - /* Set up the uart parameters in the parameter ram. - */ - if (ser->smc_scc_num & NUM_IS_SCC) { - scp = &cp->scc_regs[idx]; - /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */ - sup = &pquicc->pram[ser->port].scc.pscc.u; - - sup->rbase = dp_addr; - sup->tbase = dp_addr + sizeof(QUICC_BD); - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->rfcr = SMC_EB; - sup->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - sup->mrblr = 1; - sup->max_idl = 0; - sup->brkcr = 1; - sup->parec = 0; - sup->frmer = 0; - sup->nosec = 0; - sup->brkec = 0; - sup->uaddr1 = 0; - sup->uaddr2 = 0; - sup->toseq = 0; - { - int i; - for (i=0;i<8;i++) - sup->cc[i] = 0x8000; - } - sup->rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - chan = scc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmr.w.high = 0; - scp->scc_gsmr.w.low = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; - - scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - } - else { - /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */ - up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; - - up->rbase = dp_addr; /* Base of receive buffer desc. */ - up->tbase = dp_addr+sizeof(QUICC_BD); /* Base of xmt buffer desc. */ - up->rfcr = SMC_EB; - up->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single character interrupts. - */ - up->mrblr = 1; /* receive buffer length */ - up->max_idl = 0; /* wait forever for next char */ - - /* Send the CPM an initialize command. - */ - chan = smc_chan_map[idx]; - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp = &cp->smc_regs[idx]; - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* And finally, enable Rx and Tx. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; - } - - /* Set up the baud rate generator. - */ - /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */ - m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE); - - return 0; -} - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c deleted file mode 100644 index b25e6e490530..000000000000 --- a/drivers/serial/8250.c +++ /dev/null @@ -1,3377 +0,0 @@ -/* - * linux/drivers/char/8250.c - * - * Driver for 8250/16550-type serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright (C) 2001 Russell King. - * - * 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. - * - * A note about mapbase / membase - * - * mapbase is the physical address of the IO port. - * membase is an 'ioremapped' cookie. - */ - -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "8250.h" - -#ifdef CONFIG_SPARC -#include "suncore.h" -#endif - -/* - * Configuration: - * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option - * is unsafe when used on edge-triggered interrupts. - */ -static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; - -static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; - -static struct uart_driver serial8250_reg; - -static int serial_index(struct uart_port *port) -{ - return (serial8250_reg.minor - 64) + port->line; -} - -static unsigned int skip_txen_test; /* force skip of txen test at init time */ - -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - -#define PASS_LIMIT 256 - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - - -/* - * We default to IRQ0 for the "no irq" hack. Some - * machine types want others as well - they're free - * to redefine this in their header file. - */ -#define is_real_interrupt(irq) ((irq) != 0) - -#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define CONFIG_SERIAL_DETECT_IRQ 1 -#endif -#ifdef CONFIG_SERIAL_8250_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS 1 -#endif - -/* - * HUB6 is always on. This will be removed once the header - * files have been cleaned. - */ -#define CONFIG_HUB6 1 - -#include -/* - * SERIAL_PORT_DFNS tells us about built-in ports that have no - * standard enumeration mechanism. Platforms that can find all - * serial ports via mechanisms like ACPI or PCI need not supply it. - */ -#ifndef SERIAL_PORT_DFNS -#define SERIAL_PORT_DFNS -#endif - -static const struct old_serial_port old_serial_port[] = { - SERIAL_PORT_DFNS /* defined in asm/serial.h */ -}; - -#define UART_NR CONFIG_SERIAL_8250_NR_UARTS - -#ifdef CONFIG_SERIAL_8250_RSA - -#define PORT_RSA_MAX 4 -static unsigned long probe_rsa[PORT_RSA_MAX]; -static unsigned int probe_rsa_count; -#endif /* CONFIG_SERIAL_8250_RSA */ - -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; -}; - -struct irq_info { - struct hlist_node node; - int irq; - spinlock_t lock; /* Protects list not the hash */ - struct list_head *head; -}; - -#define NR_IRQ_HASH 32 /* Can be adjusted later */ -static struct hlist_head irq_lists[NR_IRQ_HASH]; -static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ - -/* - * Here we define the default xmit fifo size used for each type of UART. - */ -static const struct serial8250_config uart_config[] = { - [PORT_UNKNOWN] = { - .name = "unknown", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_8250] = { - .name = "8250", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16450] = { - .name = "16450", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550] = { - .name = "16550", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550A] = { - .name = "16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_CIRRUS] = { - .name = "Cirrus", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16650] = { - .name = "ST16650", - .fifo_size = 1, - .tx_loadsz = 1, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16650V2] = { - .name = "ST16650V2", - .fifo_size = 32, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16750] = { - .name = "TI16750", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR7_64BYTE, - .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, - }, - [PORT_STARTECH] = { - .name = "Startech", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16C950] = { - .name = "16C950/954", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16654] = { - .name = "ST16654", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16850] = { - .name = "XR16850", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_RSA] = { - .name = "RSA", - .fifo_size = 2048, - .tx_loadsz = 2048, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, - .flags = UART_CAP_FIFO, - }, - [PORT_NS16550A] = { - .name = "NS16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_NATSEMI, - }, - [PORT_XSCALE] = { - .name = "XScale", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_UUE, - }, - [PORT_RM9000] = { - .name = "RM9000", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_OCTEON] = { - .name = "OCTEON", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_AR7] = { - .name = "AR7", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_U6_16550A] = { - .name = "U6_16550A", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, -}; - -#if defined(CONFIG_MIPS_ALCHEMY) - -/* Au1x00 UART hardware has a weird register layout */ -static const u8 au_io_in_map[] = { - [UART_RX] = 0, - [UART_IER] = 2, - [UART_IIR] = 3, - [UART_LCR] = 5, - [UART_MCR] = 6, - [UART_LSR] = 7, - [UART_MSR] = 8, -}; - -static const u8 au_io_out_map[] = { - [UART_TX] = 1, - [UART_IER] = 2, - [UART_FCR] = 4, - [UART_LCR] = 5, - [UART_MCR] = 6, -}; - -/* sane hardware needs no mapping */ -static inline int map_8250_in_reg(struct uart_port *p, int offset) -{ - if (p->iotype != UPIO_AU) - return offset; - return au_io_in_map[offset]; -} - -static inline int map_8250_out_reg(struct uart_port *p, int offset) -{ - if (p->iotype != UPIO_AU) - return offset; - return au_io_out_map[offset]; -} - -#elif defined(CONFIG_SERIAL_8250_RM9K) - -static const u8 - regmap_in[8] = { - [UART_RX] = 0x00, - [UART_IER] = 0x0c, - [UART_IIR] = 0x14, - [UART_LCR] = 0x1c, - [UART_MCR] = 0x20, - [UART_LSR] = 0x24, - [UART_MSR] = 0x28, - [UART_SCR] = 0x2c - }, - regmap_out[8] = { - [UART_TX] = 0x04, - [UART_IER] = 0x0c, - [UART_FCR] = 0x18, - [UART_LCR] = 0x1c, - [UART_MCR] = 0x20, - [UART_LSR] = 0x24, - [UART_MSR] = 0x28, - [UART_SCR] = 0x2c - }; - -static inline int map_8250_in_reg(struct uart_port *p, int offset) -{ - if (p->iotype != UPIO_RM9000) - return offset; - return regmap_in[offset]; -} - -static inline int map_8250_out_reg(struct uart_port *p, int offset) -{ - if (p->iotype != UPIO_RM9000) - return offset; - return regmap_out[offset]; -} - -#else - -/* sane hardware needs no mapping */ -#define map_8250_in_reg(up, offset) (offset) -#define map_8250_out_reg(up, offset) (offset) - -#endif - -static unsigned int hub6_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - return inb(p->iobase + 1); -} - -static void hub6_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - outb(value, p->iobase + 1); -} - -static unsigned int mem_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return readb(p->membase + offset); -} - -static void mem_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - writeb(value, p->membase + offset); -} - -static void mem32_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - writel(value, p->membase + offset); -} - -static unsigned int mem32_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return readl(p->membase + offset); -} - -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return __raw_readl(p->membase + offset); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - __raw_writel(value, p->membase + offset); -} - -static unsigned int tsi_serial_in(struct uart_port *p, int offset) -{ - unsigned int tmp; - offset = map_8250_in_reg(p, offset) << p->regshift; - if (offset == UART_IIR) { - tmp = readl(p->membase + (UART_IIR & ~3)); - return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ - } else - return readb(p->membase + offset); -} - -static void tsi_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - if (!((offset == UART_IER) && (value & UART_IER_UUE))) - writeb(value, p->membase + offset); -} - -/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ -static inline void dwapb_save_out_value(struct uart_port *p, int offset, - int value) -{ - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); - - if (offset == UART_LCR) - up->lcr = value; -} - -/* Read the IER to ensure any interrupt is cleared before returning from ISR. */ -static inline void dwapb_check_clear_ier(struct uart_port *p, int offset) -{ - if (offset == UART_TX || offset == UART_IER) - p->serial_in(p, UART_IER); -} - -static void dwapb_serial_out(struct uart_port *p, int offset, int value) -{ - int save_offset = offset; - offset = map_8250_out_reg(p, offset) << p->regshift; - dwapb_save_out_value(p, save_offset, value); - writeb(value, p->membase + offset); - dwapb_check_clear_ier(p, save_offset); -} - -static void dwapb32_serial_out(struct uart_port *p, int offset, int value) -{ - int save_offset = offset; - offset = map_8250_out_reg(p, offset) << p->regshift; - dwapb_save_out_value(p, save_offset, value); - writel(value, p->membase + offset); - dwapb_check_clear_ier(p, save_offset); -} - -static unsigned int io_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return inb(p->iobase + offset); -} - -static void io_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - outb(value, p->iobase + offset); -} - -static void set_io_from_upio(struct uart_port *p) -{ - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); - switch (p->iotype) { - case UPIO_HUB6: - p->serial_in = hub6_serial_in; - p->serial_out = hub6_serial_out; - break; - - case UPIO_MEM: - p->serial_in = mem_serial_in; - p->serial_out = mem_serial_out; - break; - - case UPIO_RM9000: - case UPIO_MEM32: - p->serial_in = mem32_serial_in; - p->serial_out = mem32_serial_out; - break; - - case UPIO_AU: - p->serial_in = au_serial_in; - p->serial_out = au_serial_out; - break; - - case UPIO_TSI: - p->serial_in = tsi_serial_in; - p->serial_out = tsi_serial_out; - break; - - case UPIO_DWAPB: - p->serial_in = mem_serial_in; - p->serial_out = dwapb_serial_out; - break; - - case UPIO_DWAPB32: - p->serial_in = mem32_serial_in; - p->serial_out = dwapb32_serial_out; - break; - - default: - p->serial_in = io_serial_in; - p->serial_out = io_serial_out; - break; - } - /* Remember loaded iotype */ - up->cur_iotype = p->iotype; -} - -static void -serial_out_sync(struct uart_8250_port *up, int offset, int value) -{ - struct uart_port *p = &up->port; - switch (p->iotype) { - case UPIO_MEM: - case UPIO_MEM32: - case UPIO_AU: - case UPIO_DWAPB: - case UPIO_DWAPB32: - p->serial_out(p, offset, value); - p->serial_in(p, UART_LCR); /* safe, no side-effects */ - break; - default: - p->serial_out(p, offset, value); - } -} - -#define serial_in(up, offset) \ - (up->port.serial_in(&(up)->port, (offset))) -#define serial_out(up, offset, value) \ - (up->port.serial_out(&(up)->port, (offset), (value))) -/* - * We used to support using pause I/O for certain machines. We - * haven't supported this for a while, but just in case it's badly - * needed for certain old 386 machines, I've left these #define's - * in.... - */ -#define serial_inp(up, offset) serial_in(up, offset) -#define serial_outp(up, offset, value) serial_out(up, offset, value) - -/* Uart divisor latch read */ -static inline int _serial_dl_read(struct uart_8250_port *up) -{ - return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; -} - -/* Uart divisor latch write */ -static inline void _serial_dl_write(struct uart_8250_port *up, int value) -{ - serial_outp(up, UART_DLL, value & 0xff); - serial_outp(up, UART_DLM, value >> 8 & 0xff); -} - -#if defined(CONFIG_MIPS_ALCHEMY) -/* Au1x00 haven't got a standard divisor latch */ -static int serial_dl_read(struct uart_8250_port *up) -{ - if (up->port.iotype == UPIO_AU) - return __raw_readl(up->port.membase + 0x28); - else - return _serial_dl_read(up); -} - -static void serial_dl_write(struct uart_8250_port *up, int value) -{ - if (up->port.iotype == UPIO_AU) - __raw_writel(value, up->port.membase + 0x28); - else - _serial_dl_write(up, value); -} -#elif defined(CONFIG_SERIAL_8250_RM9K) -static int serial_dl_read(struct uart_8250_port *up) -{ - return (up->port.iotype == UPIO_RM9000) ? - (((__raw_readl(up->port.membase + 0x10) << 8) | - (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : - _serial_dl_read(up); -} - -static void serial_dl_write(struct uart_8250_port *up, int value) -{ - if (up->port.iotype == UPIO_RM9000) { - __raw_writel(value, up->port.membase + 0x08); - __raw_writel(value >> 8, up->port.membase + 0x10); - } else { - _serial_dl_write(up, value); - } -} -#else -#define serial_dl_read(up) _serial_dl_read(up) -#define serial_dl_write(up, value) _serial_dl_write(up, value) -#endif - -/* - * For the 16C950 - */ -static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); -} - -static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) -{ - unsigned int value; - - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); - - return value; -} - -/* - * FIFO support. - */ -static void serial8250_clear_fifos(struct uart_8250_port *p) -{ - if (p->capabilities & UART_CAP_FIFO) { - serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(p, UART_FCR, 0); - } -} - -/* - * IER sleep support. UARTs which have EFRs need the "extended - * capability" bit enabled. Note that on XR16C850s, we need to - * reset LCR to write to IER. - */ -static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) -{ - if (p->capabilities & UART_CAP_SLEEP) { - if (p->capabilities & UART_CAP_EFR) { - serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(p, UART_EFR, UART_EFR_ECB); - serial_outp(p, UART_LCR, 0); - } - serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); - if (p->capabilities & UART_CAP_EFR) { - serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(p, UART_EFR, 0); - serial_outp(p, UART_LCR, 0); - } - } -} - -#ifdef CONFIG_SERIAL_8250_RSA -/* - * Attempts to turn on the RSA FIFO. Returns zero on failure. - * We set the port uart clock rate if we succeed. - */ -static int __enable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - mode = serial_inp(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; - - return result; -} - -static void enable_rsa(struct uart_8250_port *up) -{ - if (up->port.type == PORT_RSA) { - if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - __enable_rsa(up); - spin_unlock_irq(&up->port.lock); - } - if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_outp(up, UART_RSA_FRR, 0); - } -} - -/* - * Attempts to turn off the RSA FIFO. Returns zero on failure. - * It is unknown why interrupts were disabled in here. However, - * the caller is expected to preserve this behaviour by grabbing - * the spinlock before calling this function. - */ -static void disable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - if (up->port.type == PORT_RSA && - up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - - mode = serial_inp(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); - } -} -#endif /* CONFIG_SERIAL_8250_RSA */ - -/* - * This is a quickie test to see how big the FIFO is. - * It doesn't work at all the time, more's the pity. - */ -static int size_fifo(struct uart_8250_port *up) -{ - unsigned char old_fcr, old_mcr, old_lcr; - unsigned short old_dl; - int count; - - old_lcr = serial_inp(up, UART_LCR); - serial_outp(up, UART_LCR, 0); - old_fcr = serial_inp(up, UART_FCR); - old_mcr = serial_inp(up, UART_MCR); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_MCR, UART_MCR_LOOP); - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); - old_dl = serial_dl_read(up); - serial_dl_write(up, 0x0001); - serial_outp(up, UART_LCR, 0x03); - for (count = 0; count < 256; count++) - serial_outp(up, UART_TX, count); - mdelay(20);/* FIXME - schedule_timeout */ - for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) && - (count < 256); count++) - serial_inp(up, UART_RX); - serial_outp(up, UART_FCR, old_fcr); - serial_outp(up, UART_MCR, old_mcr); - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_dl_write(up, old_dl); - serial_outp(up, UART_LCR, old_lcr); - - return count; -} - -/* - * Read UART ID using the divisor method - set DLL and DLM to zero - * and the revision will be in DLL and device type in DLM. We - * preserve the device state across this. - */ -static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) -{ - unsigned char old_dll, old_dlm, old_lcr; - unsigned int id; - - old_lcr = serial_inp(p, UART_LCR); - serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A); - - old_dll = serial_inp(p, UART_DLL); - old_dlm = serial_inp(p, UART_DLM); - - serial_outp(p, UART_DLL, 0); - serial_outp(p, UART_DLM, 0); - - id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8; - - serial_outp(p, UART_DLL, old_dll); - serial_outp(p, UART_DLM, old_dlm); - serial_outp(p, UART_LCR, old_lcr); - - return id; -} - -/* - * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. - * When this function is called we know it is at least a StarTech - * 16650 V2, but it might be one of several StarTech UARTs, or one of - * its clones. (We treat the broken original StarTech 16650 V1 as a - * 16550, and why not? Startech doesn't seem to even acknowledge its - * existence.) - * - * What evil have men's minds wrought... - */ -static void autoconfig_has_efr(struct uart_8250_port *up) -{ - unsigned int id1, id2, id3, rev; - - /* - * Everything with an EFR has SLEEP - */ - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - - /* - * First we check to see if it's an Oxford Semiconductor UART. - * - * If we have to do this here because some non-National - * Semiconductor clone chips lock up if you try writing to the - * LSR register (which serial_icr_read does) - */ - - /* - * Check for Oxford Semiconductor 16C950. - * - * EFR [4] must be set else this test fails. - * - * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) - * claims that it's needed for 952 dual UART's (which are not - * recommended for new designs). - */ - up->acr = 0; - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_LCR, 0x00); - id1 = serial_icr_read(up, UART_ID1); - id2 = serial_icr_read(up, UART_ID2); - id3 = serial_icr_read(up, UART_ID3); - rev = serial_icr_read(up, UART_REV); - - DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); - - if (id1 == 0x16 && id2 == 0xC9 && - (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { - up->port.type = PORT_16C950; - - /* - * Enable work around for the Oxford Semiconductor 952 rev B - * chip which causes it to seriously miscalculate baud rates - * when DLL is 0. - */ - if (id3 == 0x52 && rev == 0x01) - up->bugs |= UART_BUG_QUOT; - return; - } - - /* - * We check for a XR16C850 by setting DLL and DLM to 0, and then - * reading back DLL and DLM. The chip type depends on the DLM - * value read back: - * 0x10 - XR16C850 and the DLL contains the chip revision. - * 0x12 - XR16C2850. - * 0x14 - XR16C854. - */ - id1 = autoconfig_read_divisor_id(up); - DEBUG_AUTOCONF("850id=%04x ", id1); - - id2 = id1 >> 8; - if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { - up->port.type = PORT_16850; - return; - } - - /* - * It wasn't an XR16C850. - * - * We distinguish between the '654 and the '650 by counting - * how many bytes are in the FIFO. I'm using this for now, - * since that's the technique that was sent to me in the - * serial driver update, but I'm not convinced this works. - * I've had problems doing this in the past. -TYT - */ - if (size_fifo(up) == 64) - up->port.type = PORT_16654; - else - up->port.type = PORT_16650V2; -} - -/* - * We detected a chip without a FIFO. Only two fall into - * this category - the original 8250 and the 16450. The - * 16450 has a scratch register (accessible with LCR=0) - */ -static void autoconfig_8250(struct uart_8250_port *up) -{ - unsigned char scratch, status1, status2; - - up->port.type = PORT_8250; - - scratch = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0xa5); - status1 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0x5a); - status2 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, scratch); - - if (status1 == 0xa5 && status2 == 0x5a) - up->port.type = PORT_16450; -} - -static int broken_efr(struct uart_8250_port *up) -{ - /* - * Exar ST16C2550 "A2" devices incorrectly detect as - * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html - */ - if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) - return 1; - - return 0; -} - -/* - * We know that the chip has FIFOs. Does it have an EFR? The - * EFR is located in the same register position as the IIR and - * we know the top two bits of the IIR are currently set. The - * EFR should contain zero. Try to read the EFR. - */ -static void autoconfig_16550a(struct uart_8250_port *up) -{ - unsigned char status1, status2; - unsigned int iersave; - - up->port.type = PORT_16550A; - up->capabilities |= UART_CAP_FIFO; - - /* - * Check for presence of the EFR when DLAB is set. - * Only ST16C650V1 UARTs pass this test. - */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); - if (serial_in(up, UART_EFR) == 0) { - serial_outp(up, UART_EFR, 0xA8); - if (serial_in(up, UART_EFR) != 0) { - DEBUG_AUTOCONF("EFRv1 "); - up->port.type = PORT_16650; - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - } else { - DEBUG_AUTOCONF("Motorola 8xxx DUART "); - } - serial_outp(up, UART_EFR, 0); - return; - } - - /* - * Maybe it requires 0xbf to be written to the LCR. - * (other ST16C650V2 UARTs, TI16C752A, etc) - */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { - DEBUG_AUTOCONF("EFRv2 "); - autoconfig_has_efr(up); - return; - } - - /* - * Check for a National Semiconductor SuperIO chip. - * Attempt to switch to bank 2, read the value of the LOOP bit - * from EXCR1. Switch back to bank 0, change it in MCR. Then - * switch back to bank 2, read it from EXCR1 again and check - * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 - */ - serial_outp(up, UART_LCR, 0); - status1 = serial_in(up, UART_MCR); - serial_outp(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - - if (!((status2 ^ status1) & UART_MCR_LOOP)) { - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP); - serial_outp(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_MCR, status1); - - if ((status2 ^ status1) & UART_MCR_LOOP) { - unsigned short quot; - - serial_outp(up, UART_LCR, 0xE0); - - quot = serial_dl_read(up); - quot <<= 3; - - status1 = serial_in(up, 0x04); /* EXCR2 */ - status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ - status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ - serial_outp(up, 0x04, status1); - - serial_dl_write(up, quot); - - serial_outp(up, UART_LCR, 0); - - up->port.uartclk = 921600*16; - up->port.type = PORT_NS16550A; - up->capabilities |= UART_NATSEMI; - return; - } - } - - /* - * No EFR. Try to detect a TI16750, which only sets bit 5 of - * the IIR when 64 byte FIFO mode is enabled when DLAB is set. - * Try setting it with and without DLAB set. Cheap clones - * set bit 5 without DLAB set. - */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status2 = serial_in(up, UART_IIR) >> 5; - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, 0); - - DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); - - if (status1 == 6 && status2 == 7) { - up->port.type = PORT_16750; - up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; - return; - } - - /* - * Try writing and reading the UART_IER_UUE bit (b6). - * If it works, this is probably one of the Xscale platform's - * internal UARTs. - * We're going to explicitly set the UUE bit to 0 before - * trying to write and read a 1 just to make sure it's not - * already a 1 and maybe locked there before we even start start. - */ - iersave = serial_in(up, UART_IER); - serial_outp(up, UART_IER, iersave & ~UART_IER_UUE); - if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { - /* - * OK it's in a known zero state, try writing and reading - * without disturbing the current state of the other bits. - */ - serial_outp(up, UART_IER, iersave | UART_IER_UUE); - if (serial_in(up, UART_IER) & UART_IER_UUE) { - /* - * It's an Xscale. - * We'll leave the UART_IER_UUE bit set to 1 (enabled). - */ - DEBUG_AUTOCONF("Xscale "); - up->port.type = PORT_XSCALE; - up->capabilities |= UART_CAP_UUE; - return; - } - } else { - /* - * If we got here we couldn't force the IER_UUE bit to 0. - * Log it and continue. - */ - DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); - } - serial_outp(up, UART_IER, iersave); - - /* - * We distinguish between 16550A and U6 16550A by counting - * how many bytes are in the FIFO. - */ - if (up->port.type == PORT_16550A && size_fifo(up) == 64) { - up->port.type = PORT_U6_16550A; - up->capabilities |= UART_CAP_AFE; - } -} - -/* - * This routine is called by rs_init() to initialize a specific serial - * port. It determines what type of UART chip this serial port is - * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A or not, since this will - * determine whether or not we can use its FIFO features or not. - */ -static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) -{ - unsigned char status1, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - unsigned long flags; - - if (!up->port.iobase && !up->port.mapbase && !up->port.membase) - return; - - DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", - serial_index(&up->port), up->port.iobase, up->port.membase); - - /* - * We really do need global IRQs disabled here - we're going to - * be frobbing the chips IRQ enable register to see if it exists. - */ - spin_lock_irqsave(&up->port.lock, flags); - - up->capabilities = 0; - up->bugs = 0; - - if (!(up->port.flags & UPF_BUGGY_UART)) { - /* - * Do a simple existence test first; if we fail this, - * there's no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against - * false positives due to ISA bus float. The - * assumption is that 0x80 is a non-existent port; - * which should be safe since include/asm/io.h also - * makes this assumption. - * - * Note: this is safe as long as MCR bit 4 is clear - * and the device is in "PC" mode. - */ - scratch = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - /* - * Mask out IER[7:4] bits for test as some UARTs (e.g. TL - * 16C754B) allow only to modify them if an EFR bit is set. - */ - scratch2 = serial_inp(up, UART_IER) & 0x0f; - serial_outp(up, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_inp(up, UART_IER) & 0x0f; - serial_outp(up, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) { - /* - * We failed; there's nothing here - */ - DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", - scratch2, scratch3); - goto out; - } - } - - save_mcr = serial_in(up, UART_MCR); - save_lcr = serial_in(up, UART_LCR); - - /* - * Check to see if a UART is really there. Certain broken - * internal modems based on the Rockwell chipset fail this - * test, because they apparently don't implement the loopback - * test mode. So this test is skipped on the COM 1 through - * COM 4 ports. This *should* be safe, since no board - * manufacturer would be stupid enough to design a board - * that conflicts with COM 1-4 --- we hope! - */ - if (!(up->port.flags & UPF_SKIP_TEST)) { - serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(up, UART_MSR) & 0xF0; - serial_outp(up, UART_MCR, save_mcr); - if (status1 != 0x90) { - DEBUG_AUTOCONF("LOOP test failed (%02x) ", - status1); - goto out; - } - } - - /* - * We're pretty sure there's a port here. Lets find out what - * type of port it is. The IIR top two bits allows us to find - * out if it's 8250 or 16450, 16550, 16550A or later. This - * determines what we test for next. - * - * We also initialise the EFR (if any) to zero for later. The - * EFR occupies the same register location as the FCR and IIR. - */ - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, 0); - serial_outp(up, UART_LCR, 0); - - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(up, UART_IIR) >> 6; - - DEBUG_AUTOCONF("iir=%d ", scratch); - - switch (scratch) { - case 0: - autoconfig_8250(up); - break; - case 1: - up->port.type = PORT_UNKNOWN; - break; - case 2: - up->port.type = PORT_16550; - break; - case 3: - autoconfig_16550a(up); - break; - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Only probe for RSA ports if we got the region. - */ - if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) { - int i; - - for (i = 0 ; i < probe_rsa_count; ++i) { - if (probe_rsa[i] == up->port.iobase && - __enable_rsa(up)) { - up->port.type = PORT_RSA; - break; - } - } - } -#endif - - serial_outp(up, UART_LCR, save_lcr); - - if (up->capabilities != uart_config[up->port.type].flags) { - printk(KERN_WARNING - "ttyS%d: detected caps %08x should be %08x\n", - serial_index(&up->port), up->capabilities, - uart_config[up->port.type].flags); - } - - up->port.fifosize = uart_config[up->port.type].fifo_size; - up->capabilities = uart_config[up->port.type].flags; - up->tx_loadsz = uart_config[up->port.type].tx_loadsz; - - if (up->port.type == PORT_UNKNOWN) - goto out; - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_8250_RSA - if (up->port.type == PORT_RSA) - serial_outp(up, UART_RSA_FRR, 0); -#endif - serial_outp(up, UART_MCR, save_mcr); - serial8250_clear_fifos(up); - serial_in(up, UART_RX); - if (up->capabilities & UART_CAP_UUE) - serial_outp(up, UART_IER, UART_IER_UUE); - else - serial_outp(up, UART_IER, 0); - - out: - spin_unlock_irqrestore(&up->port.lock, flags); - DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); -} - -static void autoconfig_irq(struct uart_8250_port *up) -{ - unsigned char save_mcr, save_ier; - unsigned char save_ICP = 0; - unsigned int ICP = 0; - unsigned long irqs; - int irq; - - if (up->port.flags & UPF_FOURPORT) { - ICP = (up->port.iobase & 0xfe0) | 0x1f; - save_ICP = inb_p(ICP); - outb_p(0x80, ICP); - (void) inb_p(ICP); - } - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_inp(up, UART_MCR); - save_ier = serial_inp(up, UART_IER); - serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_outp(up, UART_MCR, 0); - udelay(10); - if (up->port.flags & UPF_FOURPORT) { - serial_outp(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); - } else { - serial_outp(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - } - serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ - (void)serial_inp(up, UART_LSR); - (void)serial_inp(up, UART_RX); - (void)serial_inp(up, UART_IIR); - (void)serial_inp(up, UART_MSR); - serial_outp(up, UART_TX, 0xFF); - udelay(20); - irq = probe_irq_off(irqs); - - serial_outp(up, UART_MCR, save_mcr); - serial_outp(up, UART_IER, save_ier); - - if (up->port.flags & UPF_FOURPORT) - outb_p(save_ICP, ICP); - - up->port.irq = (irq > 0) ? irq : 0; -} - -static inline void __stop_tx(struct uart_8250_port *p) -{ - if (p->ier & UART_IER_THRI) { - p->ier &= ~UART_IER_THRI; - serial_out(p, UART_IER, p->ier); - } -} - -static void serial8250_stop_tx(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - __stop_tx(up); - - /* - * We really want to stop the transmitter from sending. - */ - if (up->port.type == PORT_16C950) { - up->acr |= UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void transmit_chars(struct uart_8250_port *up); - -static void serial8250_start_tx(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - - if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((up->port.type == PORT_RM9000) ? - (lsr & UART_LSR_THRE) : - (lsr & UART_LSR_TEMT)) - transmit_chars(up); - } - } - - /* - * Re-enable the transmitter if we disabled it. - */ - if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { - up->acr &= ~UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void serial8250_stop_rx(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); -} - -static void serial8250_enable_ms(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - /* no MSR capabilities */ - if (up->bugs & UART_BUG_NOMSR) - return; - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void -receive_chars(struct uart_8250_port *up, unsigned int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned char ch, lsr = *status; - int max_count = 256; - char flag; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_inp(up, UART_RX); - else - /* - * Intel 82571 has a Serial Over Lan device that will - * set UART_LSR_BI without setting UART_LSR_DR when - * it receives a break. To avoid reading from the - * receive buffer without UART_LSR_DR bit set, we - * just force the read character to be 0 - */ - ch = 0; - - flag = TTY_NORMAL; - up->port.icount.rx++; - - lsr |= up->lsr_saved_flags; - up->lsr_saved_flags = 0; - - 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; - - if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - 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_inp(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); - *status = lsr; -} - -static void transmit_chars(struct uart_8250_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_outp(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_tx_stopped(&up->port)) { - serial8250_stop_tx(&up->port); - return; - } - if (uart_circ_empty(xmit)) { - __stop_tx(up); - return; - } - - count = up->tx_loadsz; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - DEBUG_INTR("THRE..."); - - if (uart_circ_empty(xmit)) - __stop_tx(up); -} - -static unsigned int check_modem_status(struct uart_8250_port *up) -{ - unsigned int status = serial_in(up, UART_MSR); - - status |= up->msr_saved_flags; - up->msr_saved_flags = 0; - if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - up->port.state != NULL) { - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); - } - - return status; -} - -/* - * This handles the interrupt from one port. - */ -static void serial8250_handle_port(struct uart_8250_port *up) -{ - unsigned int status; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - status = serial_inp(up, UART_LSR); - - DEBUG_INTR("status = %x...", status); - - if (status & (UART_LSR_DR | UART_LSR_BI)) - receive_chars(up, &status); - check_modem_status(up); - if (status & UART_LSR_THRE) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* - * This is the serial driver's interrupt routine. - * - * Arjan thinks the old way was overly complex, so it got simplified. - * Alan disagrees, saying that need the complexity to handle the weird - * nature of ISA shared interrupts. (This is a special exception.) - * - * In order to handle ISA shared interrupts properly, we need to check - * that all ports have been serviced, and therefore the ISA interrupt - * line has been de-asserted. - * - * This means we need to loop through all ports. checking that they - * don't have an interrupt pending. - */ -static irqreturn_t serial8250_interrupt(int irq, void *dev_id) -{ - struct irq_info *i = dev_id; - struct list_head *l, *end = NULL; - int pass_counter = 0, handled = 0; - - DEBUG_INTR("serial8250_interrupt(%d)...", irq); - - spin_lock(&i->lock); - - l = i->head; - do { - struct uart_8250_port *up; - unsigned int iir; - - up = list_entry(l, struct uart_8250_port, list); - - iir = serial_in(up, UART_IIR); - if (!(iir & UART_IIR_NO_INT)) { - serial8250_handle_port(up); - - handled = 1; - - end = NULL; - } else if ((up->port.iotype == UPIO_DWAPB || - up->port.iotype == UPIO_DWAPB32) && - (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { - /* The DesignWare APB UART has an Busy Detect (0x07) - * interrupt meaning an LCR write attempt occured while the - * UART was busy. The interrupt must be cleared by reading - * the UART status register (USR) and the LCR re-written. */ - unsigned int status; - status = *(volatile u32 *)up->port.private_data; - serial_out(up, UART_LCR, up->lcr); - - handled = 1; - - end = NULL; - } else if (end == NULL) - end = l; - - l = l->next; - - if (l == i->head && pass_counter++ > PASS_LIMIT) { - /* If we hit this, we're dead. */ - printk_ratelimited(KERN_ERR - "serial8250: too much work for irq%d\n", irq); - break; - } - } while (l != end); - - spin_unlock(&i->lock); - - DEBUG_INTR("end.\n"); - - return IRQ_RETVAL(handled); -} - -/* - * To support ISA shared interrupts, we need to have one interrupt - * handler that ensures that the IRQ line has been deasserted - * before returning. Failing to do this will result in the IRQ - * line being stuck active, and, since ISA irqs are edge triggered, - * no more IRQs will be seen. - */ -static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) -{ - spin_lock_irq(&i->lock); - - if (!list_empty(i->head)) { - if (i->head == &up->list) - i->head = i->head->next; - list_del(&up->list); - } else { - BUG_ON(i->head != &up->list); - i->head = NULL; - } - spin_unlock_irq(&i->lock); - /* List empty so throw away the hash node */ - if (i->head == NULL) { - hlist_del(&i->node); - kfree(i); - } -} - -static int serial_link_irq_chain(struct uart_8250_port *up) -{ - struct hlist_head *h; - struct hlist_node *n; - struct irq_info *i; - int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; - - mutex_lock(&hash_mutex); - - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } - - if (n == NULL) { - i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); - if (i == NULL) { - mutex_unlock(&hash_mutex); - return -ENOMEM; - } - spin_lock_init(&i->lock); - i->irq = up->port.irq; - hlist_add_head(&i->node, h); - } - mutex_unlock(&hash_mutex); - - spin_lock_irq(&i->lock); - - if (i->head) { - list_add(&up->list, i->head); - spin_unlock_irq(&i->lock); - - ret = 0; - } else { - INIT_LIST_HEAD(&up->list); - i->head = &up->list; - spin_unlock_irq(&i->lock); - irq_flags |= up->port.irqflags; - ret = request_irq(up->port.irq, serial8250_interrupt, - irq_flags, "serial", i); - if (ret < 0) - serial_do_unlink(i, up); - } - - return ret; -} - -static void serial_unlink_irq_chain(struct uart_8250_port *up) -{ - struct irq_info *i; - struct hlist_node *n; - struct hlist_head *h; - - mutex_lock(&hash_mutex); - - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } - - BUG_ON(n == NULL); - BUG_ON(i->head == NULL); - - if (list_empty(i->head)) - free_irq(up->port.irq, i); - - serial_do_unlink(i, up); - mutex_unlock(&hash_mutex); -} - -/* - * This function is used to handle ports that do not have an - * interrupt. This doesn't work very well for 16450's, but gives - * barely passable results for a 16550A. (Although at the expense - * of much CPU overhead). - */ -static void serial8250_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - unsigned int iir; - - iir = serial_in(up, UART_IIR); - if (!(iir & UART_IIR_NO_INT)) - serial8250_handle_port(up); - mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); -} - -static void serial8250_backup_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - unsigned int iir, ier = 0, lsr; - unsigned long flags; - - /* - * Must disable interrupts or else we risk racing with the interrupt - * based handler. - */ - if (is_real_interrupt(up->port.irq)) { - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - } - - iir = serial_in(up, UART_IIR); - - /* - * This should be a safe test for anyone who doesn't trust the - * IIR bits on their UART, but it's specifically designed for - * the "Diva" UART used on the management processor on many HP - * ia64 and parisc boxes. - */ - spin_lock_irqsave(&up->port.lock, flags); - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&up->port.lock, flags); - if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && - (lsr & UART_LSR_THRE)) { - iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); - iir |= UART_IIR_THRI; - } - - if (!(iir & UART_IIR_NO_INT)) - serial8250_handle_port(up); - - if (is_real_interrupt(up->port.irq)) - serial_out(up, UART_IER, ier); - - /* Standard timer interval plus 0.2s to keep the port running */ - mod_timer(&up->timer, - jiffies + uart_poll_timeout(&up->port) + HZ / 5); -} - -static unsigned int serial8250_tx_empty(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - unsigned int lsr; - - spin_lock_irqsave(&up->port.lock, flags); - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&up->port.lock, flags); - - return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; -} - -static unsigned int serial8250_get_mctrl(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned int status; - unsigned int ret; - - status = check_modem_status(up); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - - serial_out(up, UART_MCR, mcr); -} - -static void serial8250_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - for (;;) { - status = serial_in(up, UART_LSR); - - up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; - - if ((status & bits) == bits) - break; - if (--tmout == 0) - break; - udelay(1); - } - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - unsigned int tmout; - for (tmout = 1000000; tmout; tmout--) { - unsigned int msr = serial_in(up, UART_MSR); - up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; - if (msr & UART_MSR_CTS) - break; - udelay(1); - touch_nmi_watchdog(); - } - } -} - -#ifdef CONFIG_CONSOLE_POLL -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int serial8250_get_poll_char(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned char lsr = serial_inp(up, UART_LSR); - - if (!(lsr & UART_LSR_DR)) - return NO_POLL_CHAR; - - return serial_inp(up, UART_RX); -} - - -static void serial8250_put_poll_char(struct uart_port *port, - unsigned char c) -{ - unsigned int ier; - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - /* - * First save the IER then disable the interrupts - */ - ier = serial_in(up, UART_IER); - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); - - wait_for_xmitr(up, BOTH_EMPTY); - /* - * Send the character out. - * If a LF, also do CR... - */ - serial_out(up, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up, BOTH_EMPTY); - serial_out(up, UART_TX, 13); - } - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_out(up, UART_IER, ier); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -static int serial8250_startup(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - unsigned char lsr, iir; - int retval; - - up->port.fifosize = uart_config[up->port.type].fifo_size; - up->tx_loadsz = uart_config[up->port.type].tx_loadsz; - up->capabilities = uart_config[up->port.type].flags; - up->mcr = 0; - - if (up->port.iotype != up->cur_iotype) - set_io_from_upio(port); - - if (up->port.type == PORT_16C950) { - /* Wake up and initialize UART */ - up->acr = 0; - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_IER, 0); - serial_outp(up, UART_LCR, 0); - serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_LCR, 0); - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - enable_rsa(up); -#endif - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial8250_clear_fifos(up); - - /* - * Clear the interrupt registers. - */ - (void) serial_inp(up, UART_LSR); - (void) serial_inp(up, UART_RX); - (void) serial_inp(up, UART_IIR); - (void) serial_inp(up, UART_MSR); - - /* - * At this point, there's no way the LSR could still be 0xff; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(up->port.flags & UPF_BUGGY_UART) && - (serial_inp(up, UART_LSR) == 0xff)) { - printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(&up->port)); - return -ENODEV; - } - - /* - * For a XR16C850, we need to set the trigger levels - */ - if (up->port.type == PORT_16850) { - unsigned char fctr; - - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - - fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); - serial_outp(up, UART_TRG, UART_TRG_96); - serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); - serial_outp(up, UART_TRG, UART_TRG_96); - - serial_outp(up, UART_LCR, 0); - } - - if (is_real_interrupt(up->port.irq)) { - unsigned char iir1; - /* - * Test for UARTs that do not reassert THRE when the - * transmitter is idle and the interrupt has already - * been cleared. Real 16550s should always reassert - * this interrupt whenever the transmitter is idle and - * the interrupt is enabled. Delays are necessary to - * allow register changes to become visible. - */ - spin_lock_irqsave(&up->port.lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(up->port.irq); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_out_sync(up, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ - iir1 = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); - serial_out_sync(up, UART_IER, UART_IER_THRI); - udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_in(up, UART_IIR); - serial_out(up, UART_IER, 0); - - if (up->port.irqflags & IRQF_SHARED) - enable_irq(up->port.irq); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * If the interrupt is not reasserted, setup a timer to - * kick the UART on a regular basis. - */ - if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { - up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); - } - } - - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - uart_poll_timeout(port) + HZ / 5); - } - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!is_real_interrupt(up->port.irq)) { - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else { - retval = serial_link_irq_chain(up); - if (retval) - return retval; - } - - /* - * Now, initialize the UART - */ - serial_outp(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - if (up->port.flags & UPF_FOURPORT) { - if (!is_real_interrupt(up->port.irq)) - up->port.mctrl |= TIOCM_OUT1; - } else - /* - * Most PC uarts need OUT2 raised to enable interrupts. - */ - if (is_real_interrupt(up->port.irq)) - up->port.mctrl |= TIOCM_OUT2; - - serial8250_set_mctrl(&up->port, up->port.mctrl); - - /* Serial over Lan (SoL) hack: - Intel 8257x Gigabit ethernet chips have a - 16550 emulation, to be used for Serial Over Lan. - Those chips take a longer time than a normal - serial device to signalize that a transmission - data was queued. Due to that, the above test generally - fails. One solution would be to delay the reading of - iir. However, this is not reliable, since the timeout - is variable. So, let's just don't test if we receive - TX irq. This way, we'll never enable UART_BUG_TXEN. - */ - if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) - goto dont_test_tx_en; - - /* - * Do a quick test to see if we receive an - * interrupt when we enable the TX irq. - */ - serial_outp(up, UART_IER, UART_IER_THRI); - lsr = serial_in(up, UART_LSR); - iir = serial_in(up, UART_IIR); - serial_outp(up, UART_IER, 0); - - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { - if (!(up->bugs & UART_BUG_TXEN)) { - up->bugs |= UART_BUG_TXEN; - pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); - } - } else { - up->bugs &= ~UART_BUG_TXEN; - } - -dont_test_tx_en: - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Clear the interrupt registers again for luck, and clear the - * saved flags to avoid getting false values from polling - * routines or the previous session. - */ - serial_inp(up, UART_LSR); - serial_inp(up, UART_RX); - serial_inp(up, UART_IIR); - serial_inp(up, UART_MSR); - up->lsr_saved_flags = 0; - up->msr_saved_flags = 0; - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_outp(up, UART_IER, up->ier); - - if (up->port.flags & UPF_FOURPORT) { - unsigned int icp; - /* - * Enable interrupts on the AST Fourport board - */ - icp = (up->port.iobase & 0xfe0) | 0x01f; - outb_p(0x80, icp); - (void) inb_p(icp); - } - - return 0; -} - -static void serial8250_shutdown(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned long flags; - - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_outp(up, UART_IER, 0); - - spin_lock_irqsave(&up->port.lock, flags); - if (up->port.flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((up->port.iobase & 0xfe0) | 0x1f); - up->port.mctrl |= TIOCM_OUT1; - } else - up->port.mctrl &= ~TIOCM_OUT2; - - serial8250_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); - serial8250_clear_fifos(up); - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - disable_rsa(up); -#endif - - /* - * Read data port to reset things, and then unlink from - * the IRQ chain. - */ - (void) serial_in(up, UART_RX); - - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; - if (is_real_interrupt(up->port.irq)) - serial_unlink_irq_chain(up); -} - -static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud) -{ - unsigned int quot; - - /* - * Handle magic divisors for baud rates above baud_base on - * SMSC SuperIO chips. - */ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) - quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) - quot = 0x8002; - else - quot = uart_get_divisor(port, baud); - - return quot; -} - -void -serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (termios->c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); - quot = serial8250_get_divisor(port, baud); - - /* - * Oxford Semi 952 rev B workaround - */ - if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) - quot++; - - if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { - if (baud < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - else - fcr = uart_config[up->port.type].fcr; - } - - /* - * MCR-based auto flow control. When AFE is enabled, RTS will be - * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. - */ - if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) { - up->mcr &= ~UART_MCR_AFE; - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; - } - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (!(up->bugs & UART_BUG_NOMSR) && - UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - if (up->capabilities & UART_CAP_UUE) - up->ier |= UART_IER_UUE | UART_IER_RTOIE; - - serial_out(up, UART_IER, up->ier); - - if (up->capabilities & UART_CAP_EFR) { - unsigned char efr = 0; - /* - * TI16C752/Startech hardware flow control. FIXME: - * - TI16C752 requires control thresholds to be set. - * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. - */ - if (termios->c_cflag & CRTSCTS) - efr |= UART_EFR_CTS; - - serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, efr); - } - -#ifdef CONFIG_ARCH_OMAP - /* Workaround to enable 115200 baud on OMAP1510 internal ports */ - if (cpu_is_omap1510() && is_omap_port(up)) { - if (baud == 115200) { - quot = 1; - serial_out(up, UART_OMAP_OSC_12M_SEL, 1); - } else - serial_out(up, UART_OMAP_OSC_12M_SEL, 0); - } -#endif - - if (up->capabilities & UART_NATSEMI) { - /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ - serial_outp(up, UART_LCR, 0xe0); - } else { - serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - } - - serial_dl_write(up, quot); - - /* - * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR - * is written without DLAB set, this mode will be disabled. - */ - if (up->port.type == PORT_16750) - serial_outp(up, UART_FCR, fcr); - - serial_outp(up, UART_LCR, cval); /* reset DLAB */ - up->lcr = cval; /* Save LCR */ - if (up->port.type != PORT_16750) { - if (fcr & UART_FCR_ENABLE_FIFO) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - } - serial_outp(up, UART_FCR, fcr); /* set fcr */ - } - serial8250_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - /* Don't rewrite B0 */ - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); -} -EXPORT_SYMBOL(serial8250_do_set_termios); - -static void -serial8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - if (port->set_termios) - port->set_termios(port, termios, old); - else - serial8250_do_set_termios(port, termios, old); -} - -static void -serial8250_set_ldisc(struct uart_port *port, int new) -{ - if (new == N_PPS) { - port->flags |= UPF_HARDPPS_CD; - serial8250_enable_ms(port); - } else - port->flags &= ~UPF_HARDPPS_CD; -} - - -void serial8250_do_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_8250_port *p = - container_of(port, struct uart_8250_port, port); - - serial8250_set_sleep(p, state != 0); -} -EXPORT_SYMBOL(serial8250_do_pm); - -static void -serial8250_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - if (port->pm) - port->pm(port, state, oldstate); - else - serial8250_do_pm(port, state, oldstate); -} - -static unsigned int serial8250_port_size(struct uart_8250_port *pt) -{ - if (pt->port.iotype == UPIO_AU) - return 0x1000; -#ifdef CONFIG_ARCH_OMAP - if (is_omap_port(pt)) - return 0x16 << pt->port.regshift; -#endif - return 8 << pt->port.regshift; -} - -/* - * Resource handling. - */ -static int serial8250_request_std_resource(struct uart_8250_port *up) -{ - unsigned int size = serial8250_port_size(up); - int ret = 0; - - switch (up->port.iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM: - case UPIO_DWAPB: - case UPIO_DWAPB32: - if (!up->port.mapbase) - break; - - if (!request_mem_region(up->port.mapbase, size, "serial")) { - ret = -EBUSY; - break; - } - - if (up->port.flags & UPF_IOREMAP) { - up->port.membase = ioremap_nocache(up->port.mapbase, - size); - if (!up->port.membase) { - release_mem_region(up->port.mapbase, size); - ret = -ENOMEM; - } - } - break; - - case UPIO_HUB6: - case UPIO_PORT: - if (!request_region(up->port.iobase, size, "serial")) - ret = -EBUSY; - break; - } - return ret; -} - -static void serial8250_release_std_resource(struct uart_8250_port *up) -{ - unsigned int size = serial8250_port_size(up); - - switch (up->port.iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM: - case UPIO_DWAPB: - case UPIO_DWAPB32: - if (!up->port.mapbase) - break; - - if (up->port.flags & UPF_IOREMAP) { - iounmap(up->port.membase); - up->port.membase = NULL; - } - - release_mem_region(up->port.mapbase, size); - break; - - case UPIO_HUB6: - case UPIO_PORT: - release_region(up->port.iobase, size); - break; - } -} - -static int serial8250_request_rsa_resource(struct uart_8250_port *up) -{ - unsigned long start = UART_RSA_BASE << up->port.regshift; - unsigned int size = 8 << up->port.regshift; - int ret = -EINVAL; - - switch (up->port.iotype) { - case UPIO_HUB6: - case UPIO_PORT: - start += up->port.iobase; - if (request_region(start, size, "serial-rsa")) - ret = 0; - else - ret = -EBUSY; - break; - } - - return ret; -} - -static void serial8250_release_rsa_resource(struct uart_8250_port *up) -{ - unsigned long offset = UART_RSA_BASE << up->port.regshift; - unsigned int size = 8 << up->port.regshift; - - switch (up->port.iotype) { - case UPIO_HUB6: - case UPIO_PORT: - release_region(up->port.iobase + offset, size); - break; - } -} - -static void serial8250_release_port(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - serial8250_release_std_resource(up); - if (up->port.type == PORT_RSA) - serial8250_release_rsa_resource(up); -} - -static int serial8250_request_port(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int ret = 0; - - ret = serial8250_request_std_resource(up); - if (ret == 0 && up->port.type == PORT_RSA) { - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - serial8250_release_std_resource(up); - } - - return ret; -} - -static void serial8250_config_port(struct uart_port *port, int flags) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - int probeflags = PROBE_ANY; - int ret; - - /* - * Find the region that we can probe for. This in turn - * tells us whether we can probe for the type of port. - */ - ret = serial8250_request_std_resource(up); - if (ret < 0) - return; - - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - probeflags &= ~PROBE_RSA; - - if (up->port.iotype != up->cur_iotype) - set_io_from_upio(port); - - if (flags & UART_CONFIG_TYPE) - autoconfig(up, probeflags); - - /* if access method is AU, it is a 16550 with a quirk */ - if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) - up->bugs |= UART_BUG_NOMSR; - - if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) - autoconfig_irq(up); - - if (up->port.type != PORT_RSA && probeflags & PROBE_RSA) - serial8250_release_rsa_resource(up); - if (up->port.type == PORT_UNKNOWN) - serial8250_release_std_resource(up); -} - -static int -serial8250_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) || ser->type == PORT_CIRRUS || - ser->type == PORT_STARTECH) - return -EINVAL; - return 0; -} - -static const char * -serial8250_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 serial8250_pops = { - .tx_empty = serial8250_tx_empty, - .set_mctrl = serial8250_set_mctrl, - .get_mctrl = serial8250_get_mctrl, - .stop_tx = serial8250_stop_tx, - .start_tx = serial8250_start_tx, - .stop_rx = serial8250_stop_rx, - .enable_ms = serial8250_enable_ms, - .break_ctl = serial8250_break_ctl, - .startup = serial8250_startup, - .shutdown = serial8250_shutdown, - .set_termios = serial8250_set_termios, - .set_ldisc = serial8250_set_ldisc, - .pm = serial8250_pm, - .type = serial8250_type, - .release_port = serial8250_release_port, - .request_port = serial8250_request_port, - .config_port = serial8250_config_port, - .verify_port = serial8250_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = serial8250_get_poll_char, - .poll_put_char = serial8250_put_poll_char, -#endif -}; - -static struct uart_8250_port serial8250_ports[UART_NR]; - -static void (*serial8250_isa_config)(int port, struct uart_port *up, - unsigned short *capabilities); - -void serial8250_set_isa_configurator( - void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) -{ - serial8250_isa_config = v; -} -EXPORT_SYMBOL(serial8250_set_isa_configurator); - -static void __init serial8250_isa_init_ports(void) -{ - struct uart_8250_port *up; - static int first = 1; - int i, irqflag = 0; - - if (!first) - return; - first = 0; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - up->port.line = i; - spin_lock_init(&up->port.lock); - - init_timer(&up->timer); - up->timer.function = serial8250_timeout; - - /* - * ALPHA_KLUDGE_MCR needs to be killed. - */ - up->mcr_mask = ~ALPHA_KLUDGE_MCR; - up->mcr_force = ALPHA_KLUDGE_MCR; - - up->port.ops = &serial8250_pops; - } - - if (share_irqs) - irqflag = IRQF_SHARED; - - for (i = 0, up = serial8250_ports; - i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; - i++, up++) { - up->port.iobase = old_serial_port[i].port; - up->port.irq = irq_canonicalize(old_serial_port[i].irq); - up->port.irqflags = old_serial_port[i].irqflags; - up->port.uartclk = old_serial_port[i].baud_base * 16; - up->port.flags = old_serial_port[i].flags; - up->port.hub6 = old_serial_port[i].hub6; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; - set_io_from_upio(&up->port); - up->port.irqflags |= irqflag; - if (serial8250_isa_config != NULL) - serial8250_isa_config(i, &up->port, &up->capabilities); - - } -} - -static void -serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) -{ - up->port.type = type; - up->port.fifosize = uart_config[type].fifo_size; - up->capabilities = uart_config[type].flags; - up->tx_loadsz = uart_config[type].tx_loadsz; -} - -static void __init -serial8250_register_ports(struct uart_driver *drv, struct device *dev) -{ - int i; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - up->cur_iotype = 0xFF; - } - - serial8250_isa_init_ports(); - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - up->port.dev = dev; - - if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(up, up->port.type); - - uart_add_one_port(drv, &up->port); - } -} - -#ifdef CONFIG_SERIAL_8250_CONSOLE - -static void serial8250_console_putchar(struct uart_port *port, int ch) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial8250_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_8250_port *up = &serial8250_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - local_irq_save(flags); - if (up->port.sysrq) { - /* serial8250_handle_port() already took the lock */ - 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 - */ - ier = serial_in(up, UART_IER); - - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, serial8250_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_out(up, UART_IER, ier); - - /* - * The receive handling will happen properly because the - * receive ready bit will still be set; it is not cleared - * on read. However, modem control will not, we must - * call it if we have saved something in the saved flags - * while processing with interrupts off. - */ - if (up->msr_saved_flags) - check_modem_status(up); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static int __init serial8250_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= nr_uarts) - co->index = 0; - port = &serial8250_ports[co->index].port; - if (!port->iobase && !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 int serial8250_console_early_setup(void) -{ - return serial8250_find_port_for_earlycon(); -} - -static struct console serial8250_console = { - .name = "ttyS", - .write = serial8250_console_write, - .device = uart_console_device, - .setup = serial8250_console_setup, - .early_setup = serial8250_console_early_setup, - .flags = CON_PRINTBUFFER | CON_ANYTIME, - .index = -1, - .data = &serial8250_reg, -}; - -static int __init serial8250_console_init(void) -{ - if (nr_uarts > UART_NR) - nr_uarts = UART_NR; - - serial8250_isa_init_ports(); - register_console(&serial8250_console); - return 0; -} -console_initcall(serial8250_console_init); - -int serial8250_find_port(struct uart_port *p) -{ - int line; - struct uart_port *port; - - for (line = 0; line < nr_uarts; line++) { - port = &serial8250_ports[line].port; - if (uart_match_port(p, port)) - return line; - } - return -ENODEV; -} - -#define SERIAL8250_CONSOLE &serial8250_console -#else -#define SERIAL8250_CONSOLE NULL -#endif - -static struct uart_driver serial8250_reg = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .cons = SERIAL8250_CONSOLE, -}; - -/* - * early_serial_setup - early registration for 8250 ports - * - * Setup an 8250 port structure prior to console initialisation. Use - * after console initialisation will cause undefined behaviour. - */ -int __init early_serial_setup(struct uart_port *port) -{ - struct uart_port *p; - - if (port->line >= ARRAY_SIZE(serial8250_ports)) - return -ENODEV; - - serial8250_isa_init_ports(); - p = &serial8250_ports[port->line].port; - p->iobase = port->iobase; - p->membase = port->membase; - p->irq = port->irq; - p->irqflags = port->irqflags; - p->uartclk = port->uartclk; - p->fifosize = port->fifosize; - p->regshift = port->regshift; - p->iotype = port->iotype; - p->flags = port->flags; - p->mapbase = port->mapbase; - p->private_data = port->private_data; - p->type = port->type; - p->line = port->line; - - set_io_from_upio(p); - if (port->serial_in) - p->serial_in = port->serial_in; - if (port->serial_out) - p->serial_out = port->serial_out; - - return 0; -} - -/** - * serial8250_suspend_port - suspend one serial port - * @line: serial line number - * - * Suspend one serial port. - */ -void serial8250_suspend_port(int line) -{ - uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port); -} - -/** - * serial8250_resume_port - resume one serial port - * @line: serial line number - * - * Resume one serial port. - */ -void serial8250_resume_port(int line) -{ - struct uart_8250_port *up = &serial8250_ports[line]; - - if (up->capabilities & UART_NATSEMI) { - unsigned char tmp; - - /* Ensure it's still in high speed mode */ - serial_outp(up, UART_LCR, 0xE0); - - tmp = serial_in(up, 0x04); /* EXCR2 */ - tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ - tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ - serial_outp(up, 0x04, tmp); - - serial_outp(up, UART_LCR, 0); - } - uart_resume_port(&serial8250_reg, &up->port); -} - -/* - * Register a set of serial devices attached to a platform device. The - * list is terminated with a zero flags entry, which means we expect - * all entries to have at least UPF_BOOT_AUTOCONF set. - */ -static int __devinit serial8250_probe(struct platform_device *dev) -{ - struct plat_serial8250_port *p = dev->dev.platform_data; - struct uart_port port; - int ret, i, irqflag = 0; - - memset(&port, 0, sizeof(struct uart_port)); - - 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.set_termios = p->set_termios; - port.pm = p->pm; - port.dev = &dev->dev; - port.irqflags |= irqflag; - ret = serial8250_register_port(&port); - if (ret < 0) { - dev_err(&dev->dev, "unable to register port at index %d " - "(IO%lx MEM%llx IRQ%d): %d\n", i, - p->iobase, (unsigned long long)p->mapbase, - p->irq, ret); - } - } - return 0; -} - -/* - * Remove serial ports registered against a platform device. - */ -static int __devexit serial8250_remove(struct platform_device *dev) -{ - int i; - - for (i = 0; i < nr_uarts; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.dev == &dev->dev) - serial8250_unregister_port(i); - } - return 0; -} - -static int serial8250_suspend(struct platform_device *dev, pm_message_t state) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_suspend_port(&serial8250_reg, &up->port); - } - - return 0; -} - -static int serial8250_resume(struct platform_device *dev) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - serial8250_resume_port(i); - } - - return 0; -} - -static struct platform_driver serial8250_isa_driver = { - .probe = serial8250_probe, - .remove = __devexit_p(serial8250_remove), - .suspend = serial8250_suspend, - .resume = serial8250_resume, - .driver = { - .name = "serial8250", - .owner = THIS_MODULE, - }, -}; - -/* - * This "device" covers _all_ ISA 8250-compatible serial devices listed - * in the table in include/asm/serial.h - */ -static struct platform_device *serial8250_isa_devs; - -/* - * serial8250_register_port and serial8250_unregister_port allows for - * 16x50 serial ports to be configured at run-time, to support PCMCIA - * modems and PCI multiport cards. - */ -static DEFINE_MUTEX(serial_mutex); - -static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) -{ - int i; - - /* - * First, find a port entry which matches. - */ - for (i = 0; i < nr_uarts; i++) - if (uart_match_port(&serial8250_ports[i].port, port)) - return &serial8250_ports[i]; - - /* - * We didn't find a matching entry, so look for the first - * free entry. We look for one which hasn't been previously - * used (indicated by zero iobase). - */ - for (i = 0; i < nr_uarts; i++) - if (serial8250_ports[i].port.type == PORT_UNKNOWN && - serial8250_ports[i].port.iobase == 0) - return &serial8250_ports[i]; - - /* - * That also failed. Last resort is to find any entry which - * doesn't have a real port associated with it. - */ - for (i = 0; i < nr_uarts; i++) - if (serial8250_ports[i].port.type == PORT_UNKNOWN) - return &serial8250_ports[i]; - - return NULL; -} - -/** - * 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 *uart; - int ret = -ENOSPC; - - if (port->uartclk == 0) - return -EINVAL; - - mutex_lock(&serial_mutex); - - uart = serial8250_find_match_or_unused(port); - if (uart) { - uart_remove_one_port(&serial8250_reg, &uart->port); - - uart->port.iobase = port->iobase; - uart->port.membase = port->membase; - uart->port.irq = port->irq; - uart->port.irqflags = port->irqflags; - uart->port.uartclk = port->uartclk; - uart->port.fifosize = port->fifosize; - uart->port.regshift = port->regshift; - uart->port.iotype = port->iotype; - uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; - uart->port.mapbase = port->mapbase; - uart->port.private_data = port->private_data; - if (port->dev) - uart->port.dev = port->dev; - - if (port->flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(uart, port->type); - - set_io_from_upio(&uart->port); - /* Possibly override default I/O functions. */ - if (port->serial_in) - uart->port.serial_in = port->serial_in; - if (port->serial_out) - uart->port.serial_out = port->serial_out; - /* Possibly override set_termios call */ - if (port->set_termios) - uart->port.set_termios = port->set_termios; - if (port->pm) - uart->port.pm = port->pm; - - if (serial8250_isa_config != NULL) - serial8250_isa_config(0, &uart->port, - &uart->capabilities); - - ret = uart_add_one_port(&serial8250_reg, &uart->port); - if (ret == 0) - ret = uart->port.line; - } - mutex_unlock(&serial_mutex); - - return ret; -} -EXPORT_SYMBOL(serial8250_register_port); - -/** - * serial8250_unregister_port - remove a 16x50 serial port at runtime - * @line: serial line number - * - * Remove one serial port. This may not be called from interrupt - * context. We hand the port back to the our control. - */ -void serial8250_unregister_port(int line) -{ - struct uart_8250_port *uart = &serial8250_ports[line]; - - mutex_lock(&serial_mutex); - uart_remove_one_port(&serial8250_reg, &uart->port); - if (serial8250_isa_devs) { - uart->port.flags &= ~UPF_BOOT_AUTOCONF; - uart->port.type = PORT_UNKNOWN; - uart->port.dev = &serial8250_isa_devs->dev; - uart_add_one_port(&serial8250_reg, &uart->port); - } else { - uart->port.dev = NULL; - } - mutex_unlock(&serial_mutex); -} -EXPORT_SYMBOL(serial8250_unregister_port); - -static int __init serial8250_init(void) -{ - int ret; - - if (nr_uarts > UART_NR) - nr_uarts = UART_NR; - - printk(KERN_INFO "Serial: 8250/16550 driver, " - "%d ports, IRQ sharing %sabled\n", nr_uarts, - share_irqs ? "en" : "dis"); - -#ifdef CONFIG_SPARC - ret = sunserial_register_minors(&serial8250_reg, UART_NR); -#else - serial8250_reg.nr = UART_NR; - ret = uart_register_driver(&serial8250_reg); -#endif - if (ret) - goto out; - - serial8250_isa_devs = platform_device_alloc("serial8250", - PLAT8250_DEV_LEGACY); - if (!serial8250_isa_devs) { - ret = -ENOMEM; - goto unreg_uart_drv; - } - - ret = platform_device_add(serial8250_isa_devs); - if (ret) - goto put_dev; - - serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); - - ret = platform_driver_register(&serial8250_isa_driver); - if (ret == 0) - goto out; - - platform_device_del(serial8250_isa_devs); -put_dev: - platform_device_put(serial8250_isa_devs); -unreg_uart_drv: -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else - uart_unregister_driver(&serial8250_reg); -#endif -out: - return ret; -} - -static void __exit serial8250_exit(void) -{ - struct platform_device *isa_dev = serial8250_isa_devs; - - /* - * This tells serial8250_unregister_port() not to re-register - * the ports (thereby making serial8250_isa_driver permanently - * in use.) - */ - serial8250_isa_devs = NULL; - - platform_driver_unregister(&serial8250_isa_driver); - platform_device_unregister(isa_dev); - -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else - uart_unregister_driver(&serial8250_reg); -#endif -} - -module_init(serial8250_init); -module_exit(serial8250_exit); - -EXPORT_SYMBOL(serial8250_suspend_port); -EXPORT_SYMBOL(serial8250_resume_port); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); - -module_param(share_irqs, uint, 0644); -MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" - " (unsafe)"); - -module_param(nr_uarts, uint, 0644); -MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); - -module_param(skip_txen_test, uint, 0644); -MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); - -#ifdef CONFIG_SERIAL_8250_RSA -module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); -MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); -#endif -MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h deleted file mode 100644 index 6e19ea3e48d5..000000000000 --- a/drivers/serial/8250.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * linux/drivers/char/8250.h - * - * Driver for 8250/16550-type serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright (C) 2001 Russell King. - * - * 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. - */ - -#include - -struct old_serial_port { - unsigned int uart; - unsigned int baud_base; - unsigned int port; - unsigned int irq; - unsigned int flags; - unsigned char hub6; - unsigned char io_type; - unsigned char *iomem_base; - unsigned short iomem_reg_shift; - unsigned long irqflags; -}; - -/* - * This replaces serial_uart_config in include/linux/serial.h - */ -struct serial8250_config { - const char *name; - unsigned short fifo_size; - unsigned short tx_loadsz; - unsigned char fcr; - unsigned int flags; -}; - -#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */ -#define UART_CAP_EFR (1 << 9) /* UART has EFR */ -#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */ -#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */ -#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ - -#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ -#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 PROBE_RSA (1 << 0) -#define PROBE_ANY (~0) - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) - -#ifdef CONFIG_SERIAL_8250_SHARE_IRQ -#define SERIAL8250_SHARE_IRQS 1 -#else -#define SERIAL8250_SHARE_IRQS 0 -#endif - -#if defined(__alpha__) && !defined(CONFIG_PCI) -/* - * Digital did something really horribly wrong with the OUT1 and OUT2 - * lines on at least some ALPHA's. The failure mode is that if either - * is cleared, the machine locks up with endless interrupts. - */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) -#elif defined(CONFIG_SBC8560) -/* - * WindRiver did something similarly broken on their SBC8560 board. The - * UART tristates its IRQ output while OUT2 is clear, but they pulled - * the interrupt line _up_ instead of down, so if we register the IRQ - * while the UART is in that state, we die in an IRQ storm. */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2) -#else -#define ALPHA_KLUDGE_MCR 0 -#endif diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c deleted file mode 100644 index 9c10262f2469..000000000000 --- a/drivers/serial/8250_accent.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * linux/drivers/serial/8250_accent.c - * - * Copyright (C) 2005 Russell King. - * Data taken from include/asm-i386/serial.h - * - * 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. - */ -#include -#include -#include - -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF, \ - } - -static struct plat_serial8250_port accent_data[] = { - PORT(0x330, 4), - PORT(0x338, 4), - { }, -}; - -static struct platform_device accent_device = { - .name = "serial8250", - .id = PLAT8250_DEV_ACCENT, - .dev = { - .platform_data = accent_data, - }, -}; - -static int __init accent_init(void) -{ - return platform_device_register(&accent_device); -} - -module_init(accent_init); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c deleted file mode 100644 index b0ce8c56f1a4..000000000000 --- a/drivers/serial/8250_acorn.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * linux/drivers/serial/acorn.c - * - * Copyright (C) 1996-2003 Russell King. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "8250.h" - -#define MAX_PORTS 3 - -struct serial_card_type { - unsigned int num_ports; - unsigned int uartclk; - unsigned int type; - unsigned int offset[MAX_PORTS]; -}; - -struct serial_card_info { - unsigned int num_ports; - int ports[MAX_PORTS]; - void __iomem *vaddr; -}; - -static int __devinit -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; - unsigned long bus_addr; - unsigned int i; - - info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->num_ports = type->num_ports; - - bus_addr = ecard_resource_start(ec, type->type); - info->vaddr = ecardm_iomap(ec, type->type, 0, 0); - if (!info->vaddr) { - kfree(info); - return -ENOMEM; - } - - 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; - - for (i = 0; i < info->num_ports; i ++) { - port.membase = info->vaddr + type->offset[i]; - port.mapbase = bus_addr + type->offset[i]; - - info->ports[i] = serial8250_register_port(&port); - } - - return 0; -} - -static void __devexit serial_card_remove(struct expansion_card *ec) -{ - struct serial_card_info *info = ecard_get_drvdata(ec); - int i; - - ecard_set_drvdata(ec, NULL); - - for (i = 0; i < info->num_ports; i++) - if (info->ports[i] > 0) - serial8250_unregister_port(info->ports[i]); - - kfree(info); -} - -static struct serial_card_type atomwide_type = { - .num_ports = 3, - .uartclk = 7372800, - .type = ECARD_RES_IOCSLOW, - .offset = { 0x2800, 0x2400, 0x2000 }, -}; - -static struct serial_card_type serport_type = { - .num_ports = 2, - .uartclk = 3686400, - .type = ECARD_RES_IOCSLOW, - .offset = { 0x2000, 0x2020 }, -}; - -static const struct ecard_id serial_cids[] = { - { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, &atomwide_type }, - { MANU_SERPORT, PROD_SERPORT_DSPORT, &serport_type }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver serial_card_driver = { - .probe = serial_card_probe, - .remove = __devexit_p(serial_card_remove), - .id_table = serial_cids, - .drv = { - .name = "8250_acorn", - }, -}; - -static int __init serial_card_init(void) -{ - return ecard_register_driver(&serial_card_driver); -} - -static void __exit serial_card_exit(void) -{ - ecard_remove_driver(&serial_card_driver); -} - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver"); -MODULE_LICENSE("GPL"); - -module_init(serial_card_init); -module_exit(serial_card_exit); diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c deleted file mode 100644 index 3bfe0f7b26fb..000000000000 --- a/drivers/serial/8250_boca.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * linux/drivers/serial/8250_boca.c - * - * Copyright (C) 2005 Russell King. - * Data taken from include/asm-i386/serial.h - * - * 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. - */ -#include -#include -#include - -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF, \ - } - -static struct plat_serial8250_port boca_data[] = { - PORT(0x100, 12), - PORT(0x108, 12), - PORT(0x110, 12), - PORT(0x118, 12), - PORT(0x120, 12), - PORT(0x128, 12), - PORT(0x130, 12), - PORT(0x138, 12), - PORT(0x140, 12), - PORT(0x148, 12), - PORT(0x150, 12), - PORT(0x158, 12), - PORT(0x160, 12), - PORT(0x168, 12), - PORT(0x170, 12), - PORT(0x178, 12), - { }, -}; - -static struct platform_device boca_device = { - .name = "serial8250", - .id = PLAT8250_DEV_BOCA, - .dev = { - .platform_data = boca_data, - }, -}; - -static int __init boca_init(void) -{ - return platform_device_register(&boca_device); -} - -module_init(boca_init); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("8250 serial probe module for Boca cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c deleted file mode 100644 index eaafb98debed..000000000000 --- a/drivers/serial/8250_early.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Early serial console for 8250/16550 devices - * - * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. - * Bjorn Helgaas - * - * 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. - * - * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King, - * and on early_printk.c by Andi Kleen. - * - * This is for use before the serial driver has initialized, in - * particular, before the UARTs have been discovered and named. - * Instead of specifying the console device as, e.g., "ttyS0", - * we locate the device directly by its MMIO or I/O port address. - * - * The user can specify the device directly, e.g., - * earlycon=uart8250,io,0x3f8,9600n8 - * earlycon=uart8250,mmio,0xff5e0000,115200n8 - * earlycon=uart8250,mmio32,0xff5e0000,115200n8 - * or - * console=uart8250,io,0x3f8,9600n8 - * console=uart8250,mmio,0xff5e0000,115200n8 - * console=uart8250,mmio32,0xff5e0000,115200n8 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_FIX_EARLYCON_MEM -#include -#include -#endif - -struct early_serial8250_device { - struct uart_port port; - char options[16]; /* e.g., 115200n8 */ - unsigned int baud; -}; - -static struct early_serial8250_device early_device; - -static unsigned int __init serial_in(struct uart_port *port, int offset) -{ - switch (port->iotype) { - case UPIO_MEM: - return readb(port->membase + offset); - case UPIO_MEM32: - return readl(port->membase + (offset << 2)); - case UPIO_PORT: - return inb(port->iobase + offset); - default: - return 0; - } -} - -static void __init serial_out(struct uart_port *port, int offset, int value) -{ - switch (port->iotype) { - case UPIO_MEM: - writeb(value, port->membase + offset); - break; - case UPIO_MEM32: - writel(value, port->membase + (offset << 2)); - break; - case UPIO_PORT: - outb(value, port->iobase + offset); - break; - } -} - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static void __init wait_for_xmitr(struct uart_port *port) -{ - unsigned int status; - - for (;;) { - status = serial_in(port, UART_LSR); - if ((status & BOTH_EMPTY) == BOTH_EMPTY) - return; - cpu_relax(); - } -} - -static void __init serial_putc(struct uart_port *port, int c) -{ - wait_for_xmitr(port); - serial_out(port, UART_TX, c); -} - -static void __init early_serial8250_write(struct console *console, - const char *s, unsigned int count) -{ - struct uart_port *port = &early_device.port; - unsigned int ier; - - /* Save the IER and disable interrupts */ - ier = serial_in(port, UART_IER); - serial_out(port, UART_IER, 0); - - uart_console_write(port, s, count, serial_putc); - - /* Wait for transmitter to become empty and restore the IER */ - wait_for_xmitr(port); - serial_out(port, UART_IER, ier); -} - -static unsigned int __init probe_baud(struct uart_port *port) -{ - unsigned char lcr, dll, dlm; - unsigned int quot; - - lcr = serial_in(port, UART_LCR); - serial_out(port, UART_LCR, lcr | UART_LCR_DLAB); - dll = serial_in(port, UART_DLL); - dlm = serial_in(port, UART_DLM); - serial_out(port, UART_LCR, lcr); - - quot = (dlm << 8) | dll; - return (port->uartclk / 16) / quot; -} - -static void __init init_port(struct early_serial8250_device *device) -{ - struct uart_port *port = &device->port; - unsigned int divisor; - unsigned char c; - - serial_out(port, UART_LCR, 0x3); /* 8n1 */ - serial_out(port, UART_IER, 0); /* no interrupt */ - serial_out(port, UART_FCR, 0); /* no fifo */ - serial_out(port, UART_MCR, 0x3); /* DTR + RTS */ - - divisor = port->uartclk / (16 * device->baud); - c = serial_in(port, UART_LCR); - serial_out(port, UART_LCR, c | UART_LCR_DLAB); - serial_out(port, UART_DLL, divisor & 0xff); - serial_out(port, UART_DLM, (divisor >> 8) & 0xff); - serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); -} - -static int __init parse_options(struct early_serial8250_device *device, - char *options) -{ - struct uart_port *port = &device->port; - int mmio, mmio32, length; - - if (!options) - return -ENODEV; - - port->uartclk = BASE_BAUD * 16; - - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - port->mapbase = simple_strtoul(options + (mmio ? 5 : 7), - &options, 0); - if (mmio32) - port->regshift = 2; -#ifdef CONFIG_FIX_EARLYCON_MEM - set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, - port->mapbase & PAGE_MASK); - port->membase = - (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); - port->membase += port->mapbase & ~PAGE_MASK; -#else - port->membase = ioremap_nocache(port->mapbase, 64); - if (!port->membase) { - printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", - __func__, - (unsigned long long) port->mapbase); - return -ENOMEM; - } -#endif - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - port->iobase = simple_strtoul(options + 3, &options, 0); - mmio = 0; - } else - return -EINVAL; - - options = strchr(options, ','); - if (options) { - options++; - device->baud = simple_strtoul(options, NULL, 0); - length = min(strcspn(options, " "), sizeof(device->options)); - strncpy(device->options, options, length); - } else { - device->baud = probe_baud(port); - snprintf(device->options, sizeof(device->options), "%u", - device->baud); - } - - if (mmio || mmio32) - printk(KERN_INFO - "Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", - (unsigned long long)port->mapbase, - device->options); - else - printk(KERN_INFO - "Early serial console at I/O port 0x%lx (options '%s')\n", - port->iobase, - device->options); - - return 0; -} - -static struct console early_serial8250_console __initdata = { - .name = "uart", - .write = early_serial8250_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -static int __init early_serial8250_setup(char *options) -{ - struct early_serial8250_device *device = &early_device; - int err; - - if (device->port.membase || device->port.iobase) - return 0; - - err = parse_options(device, options); - if (err < 0) - return err; - - init_port(device); - return 0; -} - -int __init setup_early_serial8250_console(char *cmdline) -{ - char *options; - int err; - - options = strstr(cmdline, "uart8250,"); - if (!options) { - options = strstr(cmdline, "uart,"); - if (!options) - return 0; - } - - options = strchr(cmdline, ',') + 1; - err = early_serial8250_setup(options); - if (err < 0) - return err; - - register_console(&early_serial8250_console); - - return 0; -} - -int serial8250_find_port_for_earlycon(void) -{ - struct early_serial8250_device *device = &early_device; - struct uart_port *port = &device->port; - int line; - int ret; - - if (!device->port.membase && !device->port.iobase) - return -ENODEV; - - line = serial8250_find_port(port); - if (line < 0) - return -ENODEV; - - ret = update_console_cmdline("uart", 8250, - "ttyS", line, device->options); - if (ret < 0) - ret = update_console_cmdline("uart", 0, - "ttyS", line, device->options); - - return ret; -} - -early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/serial/8250_exar_st16c554.c b/drivers/serial/8250_exar_st16c554.c deleted file mode 100644 index 567143ace159..000000000000 --- a/drivers/serial/8250_exar_st16c554.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * linux/drivers/serial/8250_exar.c - * - * Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com > - * Based on 8250_boca. - * - * Copyright (C) 2005 Russell King. - * Data taken from include/asm-i386/serial.h - * - * 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. - */ -#include -#include -#include - -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF, \ - } - -static struct plat_serial8250_port exar_data[] = { - PORT(0x100, 5), - PORT(0x108, 5), - PORT(0x110, 5), - PORT(0x118, 5), - { }, -}; - -static struct platform_device exar_device = { - .name = "serial8250", - .id = PLAT8250_DEV_EXAR_ST16C554, - .dev = { - .platform_data = exar_data, - }, -}; - -static int __init exar_init(void) -{ - return platform_device_register(&exar_device); -} - -module_init(exar_init); - -MODULE_AUTHOR("Paul B Schroeder"); -MODULE_DESCRIPTION("8250 serial probe module for Exar cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c deleted file mode 100644 index 6375d68b7913..000000000000 --- a/drivers/serial/8250_fourport.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/drivers/serial/8250_fourport.c - * - * Copyright (C) 2005 Russell King. - * Data taken from include/asm-i386/serial.h - * - * 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. - */ -#include -#include -#include - -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \ - } - -static struct plat_serial8250_port fourport_data[] = { - PORT(0x1a0, 9), - PORT(0x1a8, 9), - PORT(0x1b0, 9), - PORT(0x1b8, 9), - PORT(0x2a0, 5), - PORT(0x2a8, 5), - PORT(0x2b0, 5), - PORT(0x2b8, 5), - { }, -}; - -static struct platform_device fourport_device = { - .name = "serial8250", - .id = PLAT8250_DEV_FOURPORT, - .dev = { - .platform_data = fourport_data, - }, -}; - -static int __init fourport_init(void) -{ - return platform_device_register(&fourport_device); -} - -module_init(fourport_init); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c deleted file mode 100644 index d8c0ffbfa6e3..000000000000 --- a/drivers/serial/8250_gsc.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Serial Device Initialisation for Lasi/Asp/Wax/Dino - * - * (c) Copyright Matthew Wilcox 2001-2002 - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "8250.h" - -static int __init serial_init_chip(struct parisc_device *dev) -{ - struct uart_port port; - unsigned long address; - int err; - - if (!dev->irq) { - /* We find some unattached serial ports by walking native - * busses. These should be silently ignored. Otherwise, - * what we have here is a missing parent device, so tell - * the user what they're missing. - */ - if (parisc_parent(dev)->id.hw_type != HPHW_IOA) - printk(KERN_INFO - "Serial: device 0x%llx not configured.\n" - "Enable support for Wax, Lasi, Asp or Dino.\n", - (unsigned long long)dev->hpa.start); - return -ENODEV; - } - - address = dev->hpa.start; - if (dev->id.sversion != 0x8d) - address += 0x800; - - memset(&port, 0, sizeof(port)); - 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); - if (err < 0) { - printk(KERN_WARNING - "serial8250_register_port returned error %d\n", err); - iounmap(port.membase); - return err; - } - - return 0; -} - -static struct parisc_device_id serial_tbl[] = { - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 }, - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c }, - { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d }, - { 0 } -}; - -/* Hack. Some machines have SERIAL_0 attached to Lasi and SERIAL_1 - * attached to Dino. Unfortunately, Dino appears before Lasi in the device - * tree. To ensure that ttyS0 == SERIAL_0, we register two drivers; one - * which only knows about Lasi and then a second which will find all the - * other serial ports. HPUX ignores this problem. - */ -static struct parisc_device_id lasi_tbl[] = { - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */ - { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */ - { 0 } -}; - - -MODULE_DEVICE_TABLE(parisc, serial_tbl); - -static struct parisc_driver lasi_driver = { - .name = "serial_1", - .id_table = lasi_tbl, - .probe = serial_init_chip, -}; - -static struct parisc_driver serial_driver = { - .name = "serial", - .id_table = serial_tbl, - .probe = serial_init_chip, -}; - -static int __init probe_serial_gsc(void) -{ - register_parisc_driver(&lasi_driver); - register_parisc_driver(&serial_driver); - return 0; -} - -module_init(probe_serial_gsc); - -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c deleted file mode 100644 index c13438c93012..000000000000 --- a/drivers/serial/8250_hp300.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Driver for the 98626/98644/internal serial interface on hp300/hp400 - * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs) - * - * Ported from 2.2 and modified to use the normal 8250 driver - * by Kars de Jong , May 2004. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "8250.h" - -#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI) -#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? -#endif - -#ifdef CONFIG_HPAPCI -struct hp300_port -{ - struct hp300_port *next; /* next port */ - int line; /* line (tty) number */ -}; - -static struct hp300_port *hp300_ports; -#endif - -#ifdef CONFIG_HPDCA - -static int __devinit hpdca_init_one(struct dio_dev *d, - const struct dio_device_id *ent); -static void __devexit hpdca_remove_one(struct dio_dev *d); - -static struct dio_device_id hpdca_dio_tbl[] = { - { DIO_ID_DCA0 }, - { DIO_ID_DCA0REM }, - { DIO_ID_DCA1 }, - { DIO_ID_DCA1REM }, - { 0 } -}; - -static struct dio_driver hpdca_driver = { - .name = "hpdca", - .id_table = hpdca_dio_tbl, - .probe = hpdca_init_one, - .remove = __devexit_p(hpdca_remove_one), -}; - -#endif - -static unsigned int num_ports; - -extern int hp300_uart_scode; - -/* Offset to UART registers from base of DCA */ -#define UART_OFFSET 17 - -#define DCA_ID 0x01 /* ID (read), reset (write) */ -#define DCA_IC 0x03 /* Interrupt control */ - -/* Interrupt control */ -#define DCA_IC_IE 0x80 /* Master interrupt enable */ - -#define HPDCA_BAUD_BASE 153600 - -/* Base address of the Frodo part */ -#define FRODO_BASE (0x41c000) - -/* - * Where we find the 8250-like APCI ports, and how far apart they are. - */ -#define FRODO_APCIBASE 0x0 -#define FRODO_APCISPACE 0x20 -#define FRODO_APCI_OFFSET(x) (FRODO_APCIBASE + ((x) * FRODO_APCISPACE)) - -#define HPAPCI_BAUD_BASE 500400 - -#ifdef CONFIG_SERIAL_8250_CONSOLE -/* - * Parse the bootinfo to find descriptions for headless console and - * debug serial ports and register them with the 8250 driver. - * This function should be called before serial_console_init() is called - * to make sure the serial console will be available for use. IA-64 kernel - * calls this function from setup_arch() after the EFI and ACPI tables have - * been parsed. - */ -int __init hp300_setup_serial_console(void) -{ - int scode; - struct uart_port port; - - memset(&port, 0, sizeof(port)); - - if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX) - return 0; - - if (DIO_SCINHOLE(hp300_uart_scode)) - return 0; - - scode = hp300_uart_scode; - - /* Memory mapped I/O */ - port.iotype = UPIO_MEM; - port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; - port.type = PORT_UNKNOWN; - - /* Check for APCI console */ - if (scode == 256) { -#ifdef CONFIG_HPAPCI - printk(KERN_INFO "Serial console is HP APCI 1\n"); - - port.uartclk = HPAPCI_BAUD_BASE * 16; - port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1)); - port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); - port.regshift = 2; - add_preferred_console("ttyS", port.line, "9600n8"); -#else - printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); - return 0; -#endif - } else { -#ifdef CONFIG_HPDCA - unsigned long pa = dio_scodetophysaddr(scode); - if (!pa) - return 0; - - printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); - - port.uartclk = HPDCA_BAUD_BASE * 16; - port.mapbase = (pa + UART_OFFSET); - port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); - port.regshift = 1; - port.irq = DIO_IPL(pa + DIO_VIRADDRBASE); - - /* Enable board-interrupts */ - out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); - - if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) - add_preferred_console("ttyS", port.line, "9600n8"); -#else - printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); - return 0; -#endif - } - - if (early_serial_setup(&port) < 0) - printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); - return 0; -} -#endif /* CONFIG_SERIAL_8250_CONSOLE */ - -#ifdef CONFIG_HPDCA -static int __devinit hpdca_init_one(struct dio_dev *d, - const struct dio_device_id *ent) -{ - struct uart_port port; - int line; - -#ifdef CONFIG_SERIAL_8250_CONSOLE - if (hp300_uart_scode == d->scode) { - /* Already got it. */ - return 0; - } -#endif - memset(&port, 0, sizeof(struct uart_port)); - - /* Memory mapped I/O */ - port.iotype = UPIO_MEM; - port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; - port.irq = d->ipl; - port.uartclk = HPDCA_BAUD_BASE * 16; - port.mapbase = (d->resource.start + UART_OFFSET); - port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); - port.regshift = 1; - port.dev = &d->dev; - line = serial8250_register_port(&port); - - if (line < 0) { - printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" - " irq %d failed\n", d->scode, port.irq); - return -ENOMEM; - } - - /* Enable board-interrupts */ - out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); - dio_set_drvdata(d, (void *)line); - - /* Reset the DCA */ - out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff); - udelay(100); - - num_ports++; - - return 0; -} -#endif - -static int __init hp300_8250_init(void) -{ - static int called; -#ifdef CONFIG_HPAPCI - int line; - unsigned long base; - struct uart_port uport; - struct hp300_port *port; - int i; -#endif - if (called) - return -ENODEV; - called = 1; - - if (!MACH_IS_HP300) - return -ENODEV; - -#ifdef CONFIG_HPDCA - dio_register_driver(&hpdca_driver); -#endif -#ifdef CONFIG_HPAPCI - if (hp300_model < HP_400) { - if (!num_ports) - return -ENODEV; - return 0; - } - /* These models have the Frodo chip. - * Port 0 is reserved for the Apollo Domain keyboard. - * Port 1 is either the console or the DCA. - */ - for (i = 1; i < 4; i++) { - /* Port 1 is the console on a 425e, on other machines it's - * mapped to DCA. - */ -#ifdef CONFIG_SERIAL_8250_CONSOLE - if (i == 1) - continue; -#endif - - /* Create new serial device */ - port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL); - if (!port) - return -ENOMEM; - - memset(&uport, 0, sizeof(struct uart_port)); - - base = (FRODO_BASE + FRODO_APCI_OFFSET(i)); - - /* Memory mapped I/O */ - uport.iotype = UPIO_MEM; - uport.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; - - line = serial8250_register_port(&uport); - - if (line < 0) { - printk(KERN_NOTICE "8250_hp300: register_serial() APCI" - " %d irq %d failed\n", i, uport.irq); - kfree(port); - continue; - } - - port->line = line; - port->next = hp300_ports; - hp300_ports = port; - - num_ports++; - } -#endif - - /* Any boards found? */ - if (!num_ports) - return -ENODEV; - - return 0; -} - -#ifdef CONFIG_HPDCA -static void __devexit hpdca_remove_one(struct dio_dev *d) -{ - int line; - - line = (int) dio_get_drvdata(d); - if (d->resource.start) { - /* Disable board-interrupts */ - out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0); - } - serial8250_unregister_port(line); -} -#endif - -static void __exit hp300_8250_exit(void) -{ -#ifdef CONFIG_HPAPCI - struct hp300_port *port, *to_free; - - for (port = hp300_ports; port; ) { - serial8250_unregister_port(port->line); - to_free = port; - port = port->next; - kfree(to_free); - } - - hp300_ports = NULL; -#endif -#ifdef CONFIG_HPDCA - dio_unregister_driver(&hpdca_driver); -#endif -} - -module_init(hp300_8250_init); -module_exit(hp300_8250_exit); -MODULE_DESCRIPTION("HP DCA/APCI serial driver"); -MODULE_AUTHOR("Kars de Jong "); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c deleted file mode 100644 index 7609150e7d5e..000000000000 --- a/drivers/serial/8250_hub6.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * linux/drivers/serial/8250_hub6.c - * - * Copyright (C) 2005 Russell King. - * Data taken from include/asm-i386/serial.h - * - * 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. - */ -#include -#include -#include - -#define HUB6(card,port) \ - { \ - .iobase = 0x302, \ - .irq = 3, \ - .uartclk = 1843200, \ - .iotype = UPIO_HUB6, \ - .flags = UPF_BOOT_AUTOCONF, \ - .hub6 = (card) << 6 | (port) << 3 | 1, \ - } - -static struct plat_serial8250_port hub6_data[] = { - HUB6(0, 0), - HUB6(0, 1), - HUB6(0, 2), - HUB6(0, 3), - HUB6(0, 4), - HUB6(0, 5), - HUB6(1, 0), - HUB6(1, 1), - HUB6(1, 2), - HUB6(1, 3), - HUB6(1, 4), - HUB6(1, 5), - { }, -}; - -static struct platform_device hub6_device = { - .name = "serial8250", - .id = PLAT8250_DEV_HUB6, - .dev = { - .platform_data = hub6_data, - }, -}; - -static int __init hub6_init(void) -{ - return platform_device_register(&hub6_device); -} - -module_init(hub6_init); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c deleted file mode 100644 index d10be944ad44..000000000000 --- a/drivers/serial/8250_mca.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/drivers/serial/8250_mca.c - * - * Copyright (C) 2005 Russell King. - * Data taken from include/asm-i386/serial.h - * - * 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. - */ -#include -#include -#include -#include - -/* - * FIXME: Should we be doing AUTO_IRQ here? - */ -#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ -#else -#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST -#endif - -#define PORT(_base,_irq) \ - { \ - .iobase = _base, \ - .irq = _irq, \ - .uartclk = 1843200, \ - .iotype = UPIO_PORT, \ - .flags = MCA_FLAGS, \ - } - -static struct plat_serial8250_port mca_data[] = { - PORT(0x3220, 3), - PORT(0x3228, 3), - PORT(0x4220, 3), - PORT(0x4228, 3), - PORT(0x5220, 3), - PORT(0x5228, 3), - { }, -}; - -static struct platform_device mca_device = { - .name = "serial8250", - .id = PLAT8250_DEV_MCA, - .dev = { - .platform_data = mca_data, - }, -}; - -static int __init mca_init(void) -{ - if (!MCA_bus) - return -ENODEV; - return platform_device_register(&mca_device); -} - -module_init(mca_init); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("8250 serial probe module for MCA ports"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c deleted file mode 100644 index 8b8930f700b5..000000000000 --- a/drivers/serial/8250_pci.c +++ /dev/null @@ -1,3850 +0,0 @@ -/* - * linux/drivers/char/8250_pci.c - * - * Probe module for 8250/16550-type PCI serial ports. - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright (C) 2001 Russell King, All Rights Reserved. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "8250.h" - -#undef SERIAL_DEBUG_PCI - -/* - * init function returns: - * > 0 - number of ports - * = 0 - use board->num_ports - * < 0 - error - */ -struct pci_serial_quirk { - u32 vendor; - u32 device; - u32 subvendor; - u32 subdevice; - int (*init)(struct pci_dev *dev); - int (*setup)(struct serial_private *, - const struct pciserial_board *, - struct uart_port *, int); - void (*exit)(struct pci_dev *dev); -}; - -#define PCI_NUM_BAR_RESOURCES 6 - -struct serial_private { - struct pci_dev *dev; - unsigned int nr; - void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES]; - struct pci_serial_quirk *quirk; - int line[0]; -}; - -static void moan_device(const char *str, struct pci_dev *dev) -{ - printk(KERN_WARNING - "%s: %s\n" - "Please send the output of lspci -vv, this\n" - "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" - "manufacturer and name of serial board or\n" - "modem board to rmk+serial@arm.linux.org.uk.\n", - pci_name(dev), str, dev->vendor, dev->device, - dev->subsystem_vendor, dev->subsystem_device); -} - -static int -setup_port(struct serial_private *priv, struct uart_port *port, - int bar, int offset, int regshift) -{ - struct pci_dev *dev = priv->dev; - unsigned long base, len; - - if (bar >= PCI_NUM_BAR_RESOURCES) - return -EINVAL; - - base = pci_resource_start(dev, bar); - - if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { - len = pci_resource_len(dev, bar); - - if (!priv->remapped_bar[bar]) - priv->remapped_bar[bar] = ioremap_nocache(base, len); - 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; - } else { - port->iotype = UPIO_PORT; - port->iobase = base + offset; - port->mapbase = 0; - port->membase = NULL; - port->regshift = 0; - } - return 0; -} - -/* - * ADDI-DATA GmbH communication cards - */ -static int addidata_apci7800_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int bar = 0, offset = board->first_offset; - bar = FL_GET_BASE(board->flags); - - if (idx < 2) { - offset += idx * board->uart_offset; - } else if ((idx >= 2) && (idx < 4)) { - bar += 1; - offset += ((idx - 2) * board->uart_offset); - } else if ((idx >= 4) && (idx < 6)) { - bar += 2; - offset += ((idx - 4) * board->uart_offset); - } else if (idx >= 6) { - bar += 3; - offset += ((idx - 6) * board->uart_offset); - } - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -/* - * AFAVLAB uses a different mixture of BARs and offsets - * Not that ugly ;) -- HW - */ -static int -afavlab_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset; - - bar = FL_GET_BASE(board->flags); - if (idx < 4) - bar += idx; - else { - bar = 4; - offset += (idx - 4) * board->uart_offset; - } - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -/* - * HP's Remote Management Console. The Diva chip came in several - * different versions. N-class, L2000 and A500 have two Diva chips, each - * with 3 UARTs (the third UART on the second chip is unused). Superdome - * and Keystone have one Diva chip with 3 UARTs. Some later machines have - * one Diva chip, but it has been expanded to 5 UARTs. - */ -static int pci_hp_diva_init(struct pci_dev *dev) -{ - int rc = 0; - - switch (dev->subsystem_device) { - case PCI_DEVICE_ID_HP_DIVA_TOSCA1: - case PCI_DEVICE_ID_HP_DIVA_HALFDOME: - case PCI_DEVICE_ID_HP_DIVA_KEYSTONE: - case PCI_DEVICE_ID_HP_DIVA_EVEREST: - rc = 3; - break; - case PCI_DEVICE_ID_HP_DIVA_TOSCA2: - rc = 2; - break; - case PCI_DEVICE_ID_HP_DIVA_MAESTRO: - rc = 4; - break; - case PCI_DEVICE_ID_HP_DIVA_POWERBAR: - case PCI_DEVICE_ID_HP_DIVA_HURRICANE: - rc = 1; - break; - } - - return rc; -} - -/* - * HP's Diva chip puts the 4th/5th serial port further out, and - * some serial ports are supposed to be hidden on certain models. - */ -static int -pci_hp_diva_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int offset = board->first_offset; - unsigned int bar = FL_GET_BASE(board->flags); - - switch (priv->dev->subsystem_device) { - case PCI_DEVICE_ID_HP_DIVA_MAESTRO: - if (idx == 3) - idx++; - break; - case PCI_DEVICE_ID_HP_DIVA_EVEREST: - if (idx > 0) - idx++; - if (idx > 2) - idx++; - break; - } - if (idx > 2) - offset = 0x18; - - offset += idx * board->uart_offset; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -/* - * Added for EKF Intel i960 serial boards - */ -static int pci_inteli960ni_init(struct pci_dev *dev) -{ - unsigned long oldval; - - if (!(dev->subsystem_device & 0x1000)) - return -ENODEV; - - /* is firmware started? */ - pci_read_config_dword(dev, 0x44, (void *)&oldval); - if (oldval == 0x00001000L) { /* RESET value */ - printk(KERN_DEBUG "Local i960 firmware missing"); - return -ENODEV; - } - return 0; -} - -/* - * Some PCI serial cards using the PLX 9050 PCI interface chip require - * that the card interrupt be explicitly enabled or disabled. This - * seems to be mainly needed on card using the PLX which also use I/O - * mapped memory. - */ -static int pci_plx9050_init(struct pci_dev *dev) -{ - u8 irq_config; - void __iomem *p; - - if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) { - moan_device("no memory in bar 0", dev); - return 0; - } - - irq_config = 0x41; - if (dev->vendor == PCI_VENDOR_ID_PANACOM || - dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) - irq_config = 0x43; - - if ((dev->vendor == PCI_VENDOR_ID_PLX) && - (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) - /* - * As the megawolf cards have the int pins active - * high, and have 2 UART chips, both ints must be - * enabled on the 9050. Also, the UARTS are set in - * 16450 mode by default, so we have to enable the - * 16C950 'enhanced' mode so that we can use the - * deep FIFOs - */ - irq_config = 0x5b; - /* - * enable/disable interrupts - */ - p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); - if (p == NULL) - return -ENOMEM; - writel(irq_config, p + 0x4c); - - /* - * Read the register back to ensure that it took effect. - */ - readl(p + 0x4c); - iounmap(p); - - return 0; -} - -static void __devexit pci_plx9050_exit(struct pci_dev *dev) -{ - u8 __iomem *p; - - if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) - return; - - /* - * disable interrupts - */ - p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); - if (p != NULL) { - writel(0, p + 0x4c); - - /* - * Read the register back to ensure that it took effect. - */ - readl(p + 0x4c); - iounmap(p); - } -} - -#define NI8420_INT_ENABLE_REG 0x38 -#define NI8420_INT_ENABLE_BIT 0x2000 - -static void __devexit pci_ni8420_exit(struct pci_dev *dev) -{ - void __iomem *p; - unsigned long base, len; - unsigned int bar = 0; - - if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { - moan_device("no memory in bar", dev); - return; - } - - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); - if (p == NULL) - return; - - /* Disable the CPU Interrupt */ - writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT), - p + NI8420_INT_ENABLE_REG); - iounmap(p); -} - - -/* MITE registers */ -#define MITE_IOWBSR1 0xc4 -#define MITE_IOWCR1 0xf4 -#define MITE_LCIMR1 0x08 -#define MITE_LCIMR2 0x10 - -#define MITE_LCIMR2_CLR_CPU_IE (1 << 30) - -static void __devexit pci_ni8430_exit(struct pci_dev *dev) -{ - void __iomem *p; - unsigned long base, len; - unsigned int bar = 0; - - if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { - moan_device("no memory in bar", dev); - return; - } - - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); - if (p == NULL) - return; - - /* Disable the CPU Interrupt */ - writel(MITE_LCIMR2_CLR_CPU_IE, p + MITE_LCIMR2); - iounmap(p); -} - -/* 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) -{ - unsigned int bar, offset = board->first_offset; - - bar = 0; - - if (idx < 4) { - /* first four channels map to 0, 0x100, 0x200, 0x300 */ - offset += idx * board->uart_offset; - } else if (idx < 8) { - /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */ - offset += idx * board->uart_offset + 0xC00; - } else /* we have only 8 ports on PMC-OCTALPRO */ - return 1; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -/* -* This does initialization for PMC OCTALPRO cards: -* maps the device memory, resets the UARTs (needed, bc -* if the module is removed and inserted again, the card -* is in the sleep mode) and enables global interrupt. -*/ - -/* global control register offset for SBS PMC-OctalPro */ -#define OCT_REG_CR_OFF 0x500 - -static int sbs_init(struct pci_dev *dev) -{ - u8 __iomem *p; - - p = pci_ioremap_bar(dev, 0); - - if (p == NULL) - return -ENOMEM; - /* Set bit-4 Control Register (UART RESET) in to reset the uarts */ - writeb(0x10, p + OCT_REG_CR_OFF); - udelay(50); - writeb(0x0, p + OCT_REG_CR_OFF); - - /* Set bit-2 (INTENABLE) of Control Register */ - writeb(0x4, p + OCT_REG_CR_OFF); - iounmap(p); - - return 0; -} - -/* - * Disables the global interrupt of PMC-OctalPro - */ - -static void __devexit sbs_exit(struct pci_dev *dev) -{ - u8 __iomem *p; - - p = pci_ioremap_bar(dev, 0); - /* FIXME: What if resource_len < OCT_REG_CR_OFF */ - if (p != NULL) - writeb(0, p + OCT_REG_CR_OFF); - iounmap(p); -} - -/* - * SIIG serial cards have an PCI interface chip which also controls - * the UART clocking frequency. Each UART can be clocked independently - * (except cards equiped with 4 UARTs) and initial clocking settings - * are stored in the EEPROM chip. It can cause problems because this - * version of serial driver doesn't support differently clocked UART's - * on single PCI card. To prevent this, initialization functions set - * high frequency clocking for all UART's on given card. It is safe (I - * hope) because it doesn't touch EEPROM settings to prevent conflicts - * with other OSes (like M$ DOS). - * - * SIIG support added by Andrey Panin , 10/1999 - * - * There is two family of SIIG serial cards with different PCI - * interface chip and different configuration methods: - * - 10x cards have control registers in IO and/or memory space; - * - 20x cards have control registers in standard PCI configuration space. - * - * Note: all 10x cards have PCI device ids 0x10.. - * all 20x cards have PCI device ids 0x20.. - * - * There are also Quartet Serial cards which use Oxford Semiconductor - * 16954 quad UART PCI chip clocked by 18.432 MHz quartz. - * - * Note: some SIIG cards are probed by the parport_serial object. - */ - -#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) -#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) - -static int pci_siig10x_init(struct pci_dev *dev) -{ - u16 data; - void __iomem *p; - - switch (dev->device & 0xfff8) { - case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ - data = 0xffdf; - break; - case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ - data = 0xf7ff; - break; - default: /* 1S1P, 4S */ - data = 0xfffb; - break; - } - - p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); - if (p == NULL) - return -ENOMEM; - - writew(readw(p + 0x28) & data, p + 0x28); - readw(p + 0x28); - iounmap(p); - return 0; -} - -#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) -#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) - -static int pci_siig20x_init(struct pci_dev *dev) -{ - u8 data; - - /* Change clock frequency for the first UART. */ - pci_read_config_byte(dev, 0x6f, &data); - pci_write_config_byte(dev, 0x6f, data & 0xef); - - /* If this card has 2 UART, we have to do the same with second UART. */ - if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || - ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { - pci_read_config_byte(dev, 0x73, &data); - pci_write_config_byte(dev, 0x73, data & 0xef); - } - return 0; -} - -static int pci_siig_init(struct pci_dev *dev) -{ - unsigned int type = dev->device & 0xff00; - - if (type == 0x1000) - return pci_siig10x_init(dev); - else if (type == 0x2000) - return pci_siig20x_init(dev); - - moan_device("Unknown SIIG card", dev); - return -ENODEV; -} - -static int pci_siig_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0; - - if (idx > 3) { - bar = 4; - offset = (idx - 4) * 8; - } - - return setup_port(priv, port, bar, offset, 0); -} - -/* - * Timedia has an explosion of boards, and to avoid the PCI table from - * growing *huge*, we use this function to collapse some 70 entries - * in the PCI table into one, for sanity's and compactness's sake. - */ -static const unsigned short timedia_single_port[] = { - 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 -}; - -static const unsigned short timedia_dual_port[] = { - 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, - 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, - 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, - 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, - 0xD079, 0 -}; - -static const unsigned short timedia_quad_port[] = { - 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, - 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, - 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, - 0xB157, 0 -}; - -static const unsigned short timedia_eight_port[] = { - 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, - 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 -}; - -static const struct timedia_struct { - int num; - const unsigned short *ids; -} timedia_data[] = { - { 1, timedia_single_port }, - { 2, timedia_dual_port }, - { 4, timedia_quad_port }, - { 8, timedia_eight_port } -}; - -static int pci_timedia_init(struct pci_dev *dev) -{ - const unsigned short *ids; - int i, j; - - for (i = 0; i < ARRAY_SIZE(timedia_data); i++) { - ids = timedia_data[i].ids; - for (j = 0; ids[j]; j++) - if (dev->subsystem_device == ids[j]) - return timedia_data[i].num; - } - return 0; -} - -/* - * Timedia/SUNIX uses a mixture of BARs and offsets - * Ugh, this is ugly as all hell --- TYT - */ -static int -pci_timedia_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int bar = 0, offset = board->first_offset; - - switch (idx) { - case 0: - bar = 0; - break; - case 1: - offset = board->uart_offset; - bar = 0; - break; - case 2: - bar = 1; - break; - case 3: - offset = board->uart_offset; - /* FALLTHROUGH */ - case 4: /* BAR 2 */ - case 5: /* BAR 3 */ - case 6: /* BAR 4 */ - case 7: /* BAR 5 */ - bar = idx - 2; - } - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -/* - * Some Titan cards are also a little weird - */ -static int -titan_400l_800l_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset; - - switch (idx) { - case 0: - bar = 1; - break; - case 1: - bar = 2; - break; - default: - bar = 4; - offset = (idx - 2) * board->uart_offset; - } - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -static int pci_xircom_init(struct pci_dev *dev) -{ - msleep(100); - return 0; -} - -static int pci_ni8420_init(struct pci_dev *dev) -{ - void __iomem *p; - unsigned long base, len; - unsigned int bar = 0; - - if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { - moan_device("no memory in bar", dev); - return 0; - } - - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); - if (p == NULL) - return -ENOMEM; - - /* Enable CPU Interrupt */ - writel(readl(p + NI8420_INT_ENABLE_REG) | NI8420_INT_ENABLE_BIT, - p + NI8420_INT_ENABLE_REG); - - iounmap(p); - return 0; -} - -#define MITE_IOWBSR1_WSIZE 0xa -#define MITE_IOWBSR1_WIN_OFFSET 0x800 -#define MITE_IOWBSR1_WENAB (1 << 7) -#define MITE_LCIMR1_IO_IE_0 (1 << 24) -#define MITE_LCIMR2_SET_CPU_IE (1 << 31) -#define MITE_IOWCR1_RAMSEL_MASK 0xfffffffe - -static int pci_ni8430_init(struct pci_dev *dev) -{ - void __iomem *p; - unsigned long base, len; - u32 device_window; - unsigned int bar = 0; - - if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { - moan_device("no memory in bar", dev); - return 0; - } - - base = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - p = ioremap_nocache(base, len); - if (p == NULL) - return -ENOMEM; - - /* Set device window address and size in BAR0 */ - device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) - | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE; - writel(device_window, p + MITE_IOWBSR1); - - /* Set window access to go to RAMSEL IO address space */ - writel((readl(p + MITE_IOWCR1) & MITE_IOWCR1_RAMSEL_MASK), - p + MITE_IOWCR1); - - /* Enable IO Bus Interrupt 0 */ - writel(MITE_LCIMR1_IO_IE_0, p + MITE_LCIMR1); - - /* Enable CPU Interrupt */ - writel(MITE_LCIMR2_SET_CPU_IE, p + MITE_LCIMR2); - - iounmap(p); - return 0; -} - -/* UART Port Control Register */ -#define NI8430_PORTCON 0x0f -#define NI8430_PORTCON_TXVR_ENABLE (1 << 3) - -static int -pci_ni8430_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - void __iomem *p; - unsigned long base, len; - unsigned int bar, offset = board->first_offset; - - if (idx >= board->num_ports) - return 1; - - bar = FL_GET_BASE(board->flags); - offset += idx * board->uart_offset; - - base = pci_resource_start(priv->dev, bar); - len = pci_resource_len(priv->dev, bar); - p = ioremap_nocache(base, len); - - /* enable the transciever */ - writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE, - p + offset + NI8430_PORTCON); - - iounmap(p); - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - - -static int pci_netmos_init(struct pci_dev *dev) -{ - /* subdevice 0x00PS means

parallel, serial */ - unsigned int num_serial = dev->subsystem_device & 0xf; - - if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) || - (dev->device == PCI_DEVICE_ID_NETMOS_9865)) - return 0; - if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && - dev->subsystem_device == 0x0299) - return 0; - - if (num_serial == 0) - return -ENODEV; - return num_serial; -} - -/* - * These chips are available with optionally one parallel port and up to - * two serial ports. Unfortunately they all have the same product id. - * - * Basic configuration is done over a region of 32 I/O ports. The base - * ioport is called INTA or INTC, depending on docs/other drivers. - * - * The region of the 32 I/O ports is configured in POSIO0R... - */ - -/* registers */ -#define ITE_887x_MISCR 0x9c -#define ITE_887x_INTCBAR 0x78 -#define ITE_887x_UARTBAR 0x7c -#define ITE_887x_PS0BAR 0x10 -#define ITE_887x_POSIO0 0x60 - -/* I/O space size */ -#define ITE_887x_IOSIZE 32 -/* I/O space size (bits 26-24; 8 bytes = 011b) */ -#define ITE_887x_POSIO_IOSIZE_8 (3 << 24) -/* I/O space size (bits 26-24; 32 bytes = 101b) */ -#define ITE_887x_POSIO_IOSIZE_32 (5 << 24) -/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */ -#define ITE_887x_POSIO_SPEED (3 << 29) -/* enable IO_Space bit */ -#define ITE_887x_POSIO_ENABLE (1 << 31) - -static int pci_ite887x_init(struct pci_dev *dev) -{ - /* inta_addr are the configuration addresses of the ITE */ - static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, - 0x200, 0x280, 0 }; - int ret, i, type; - struct resource *iobase = NULL; - u32 miscr, uartbar, ioport; - - /* search for the base-ioport */ - i = 0; - while (inta_addr[i] && iobase == NULL) { - iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, - "ite887x"); - if (iobase != NULL) { - /* write POSIO0R - speed | size | ioport */ - pci_write_config_dword(dev, ITE_887x_POSIO0, - ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | - ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]); - /* write INTCBAR - ioport */ - pci_write_config_dword(dev, ITE_887x_INTCBAR, - inta_addr[i]); - ret = inb(inta_addr[i]); - if (ret != 0xff) { - /* ioport connected */ - break; - } - release_region(iobase->start, ITE_887x_IOSIZE); - iobase = NULL; - } - i++; - } - - if (!inta_addr[i]) { - printk(KERN_ERR "ite887x: could not find iobase\n"); - return -ENODEV; - } - - /* start of undocumented type checking (see parport_pc.c) */ - type = inb(iobase->start + 0x18) & 0x0f; - - switch (type) { - case 0x2: /* ITE8871 (1P) */ - case 0xa: /* ITE8875 (1P) */ - ret = 0; - break; - case 0xe: /* ITE8872 (2S1P) */ - ret = 2; - break; - case 0x6: /* ITE8873 (1S) */ - ret = 1; - break; - case 0x8: /* ITE8874 (2S) */ - ret = 2; - break; - default: - moan_device("Unknown ITE887x", dev); - ret = -ENODEV; - } - - /* configure all serial ports */ - for (i = 0; i < ret; i++) { - /* read the I/O port from the device */ - pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)), - &ioport); - ioport &= 0x0000FF00; /* the actual base address */ - pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)), - ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | - ITE_887x_POSIO_IOSIZE_8 | ioport); - - /* write the ioport to the UARTBAR */ - pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar); - uartbar &= ~(0xffff << (16 * i)); /* clear half the reg */ - uartbar |= (ioport << (16 * i)); /* set the ioport */ - pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar); - - /* get current config */ - pci_read_config_dword(dev, ITE_887x_MISCR, &miscr); - /* disable interrupts (UARTx_Routing[3:0]) */ - miscr &= ~(0xf << (12 - 4 * i)); - /* activate the UART (UARTx_En) */ - miscr |= 1 << (23 - i); - /* write new config with activated UART */ - pci_write_config_dword(dev, ITE_887x_MISCR, miscr); - } - - if (ret <= 0) { - /* the device has no UARTs if we get here */ - release_region(iobase->start, ITE_887x_IOSIZE); - } - - return ret; -} - -static void __devexit pci_ite887x_exit(struct pci_dev *dev) -{ - u32 ioport; - /* the ioport is bit 0-15 in POSIO0R */ - pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport); - ioport &= 0xffff; - release_region(ioport, ITE_887x_IOSIZE); -} - -/* - * Oxford Semiconductor Inc. - * Check that device is part of the Tornado range of devices, then determine - * the number of ports available on the device. - */ -static int pci_oxsemi_tornado_init(struct pci_dev *dev) -{ - u8 __iomem *p; - unsigned long deviceID; - unsigned int number_uarts = 0; - - /* OxSemi Tornado devices are all 0xCxxx */ - if (dev->vendor == PCI_VENDOR_ID_OXSEMI && - (dev->device & 0xF000) != 0xC000) - return 0; - - p = pci_iomap(dev, 0, 5); - if (p == NULL) - return -ENOMEM; - - deviceID = ioread32(p); - /* Tornado device */ - if (deviceID == 0x07000200) { - number_uarts = ioread8(p + 4); - printk(KERN_DEBUG - "%d ports detected on Oxford PCI Express device\n", - number_uarts); - } - pci_iounmap(dev, p); - return number_uarts; -} - -static int -pci_default_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset, maxnr; - - bar = FL_GET_BASE(board->flags); - if (board->flags & FL_BASE_BARS) - bar += idx; - else - offset += idx * board->uart_offset; - - maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> - (board->reg_shift + 3); - - if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) - return 1; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -static int -ce4100_serial_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_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; - - return ret; -} - -static int skip_tx_en_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - port->flags |= UPF_NO_TXEN_TEST; - printk(KERN_DEBUG "serial8250: skipping TxEn test for device " - "[%04x:%04x] subsystem [%04x:%04x]\n", - priv->dev->vendor, - priv->dev->device, - priv->dev->subsystem_vendor, - priv->dev->subsystem_device); - - return pci_default_setup(priv, board, port, idx); -} - -/* This should be in linux/pci_ids.h */ -#define PCI_VENDOR_ID_SBSMODULARIO 0x124B -#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B -#define PCI_DEVICE_ID_OCTPRO 0x0001 -#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108 -#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208 -#define PCI_SUBDEVICE_ID_POCTAL232 0x0308 -#define PCI_SUBDEVICE_ID_POCTAL422 0x0408 -#define PCI_VENDOR_ID_ADVANTECH 0x13fe -#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 -#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 -#define PCI_DEVICE_ID_TITAN_200I 0x8028 -#define PCI_DEVICE_ID_TITAN_400I 0x8048 -#define PCI_DEVICE_ID_TITAN_800I 0x8088 -#define PCI_DEVICE_ID_TITAN_800EH 0xA007 -#define PCI_DEVICE_ID_TITAN_800EHB 0xA008 -#define PCI_DEVICE_ID_TITAN_400EH 0xA009 -#define PCI_DEVICE_ID_TITAN_100E 0xA010 -#define PCI_DEVICE_ID_TITAN_200E 0xA012 -#define PCI_DEVICE_ID_TITAN_400E 0xA013 -#define PCI_DEVICE_ID_TITAN_800E 0xA014 -#define PCI_DEVICE_ID_TITAN_200EI 0xA016 -#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 -#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 - -/* Unknown vendors/cards - this should not be in linux/pci_ids.h */ -#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 - -/* - * Master list of serial port init/setup/exit quirks. - * This does not describe the general nature of the port. - * (ie, baud base, number and location of ports, etc) - * - * This list is ordered alphabetically by vendor then device. - * Specific entries must come before more generic entries. - */ -static struct pci_serial_quirk pci_serial_quirks[] __refdata = { - /* - * ADDI-DATA GmbH communication cards - */ - { - .vendor = PCI_VENDOR_ID_ADDIDATA_OLD, - .device = PCI_DEVICE_ID_ADDIDATA_APCI7800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = addidata_apci7800_setup, - }, - /* - * AFAVLAB cards - these may be called via parport_serial - * It is not clear whether this applies to all products. - */ - { - .vendor = PCI_VENDOR_ID_AFAVLAB, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = afavlab_setup, - }, - /* - * HP Diva - */ - { - .vendor = PCI_VENDOR_ID_HP, - .device = PCI_DEVICE_ID_HP_DIVA, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_hp_diva_init, - .setup = pci_hp_diva_setup, - }, - /* - * Intel - */ - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_80960_RP, - .subvendor = 0xe4bf, - .subdevice = PCI_ANY_ID, - .init = pci_inteli960ni_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_8257X_SOL, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = skip_tx_en_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82573L_SOL, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = skip_tx_en_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82573E_SOL, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = skip_tx_en_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_CE4100_UART, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = ce4100_serial_setup, - }, - /* - * ITE - */ - { - .vendor = PCI_VENDOR_ID_ITE, - .device = PCI_DEVICE_ID_ITE_8872, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ite887x_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ite887x_exit), - }, - /* - * National Instruments - */ - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PCI23216, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PCI2328, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PCI2324, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PCI2322, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PCI2324I, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PCI2322I, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PXI8420_23216, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PXI8420_2328, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PXI8420_2324, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PXI8420_2322, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PXI8422_2324, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_DEVICE_ID_NI_PXI8422_2322, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8420_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_ni8420_exit), - }, - { - .vendor = PCI_VENDOR_ID_NI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_ni8430_init, - .setup = pci_ni8430_setup, - .exit = __devexit_p(pci_ni8430_exit), - }, - /* - * Panacom - */ - { - .vendor = PCI_VENDOR_ID_PANACOM, - .device = PCI_DEVICE_ID_PANACOM_QUADMODEM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - { - .vendor = PCI_VENDOR_ID_PANACOM, - .device = PCI_DEVICE_ID_PANACOM_DUALMODEM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - /* - * PLX - */ - { - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_PLX_9030, - .subvendor = PCI_SUBVENDOR_ID_PERLE, - .subdevice = PCI_ANY_ID, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_PLX_9050, - .subvendor = PCI_SUBVENDOR_ID_EXSYS, - .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - { - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_PLX_9050, - .subvendor = PCI_SUBVENDOR_ID_KEYSPAN, - .subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - { - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_PLX_9050, - .subvendor = PCI_VENDOR_ID_PLX, - .subdevice = PCI_SUBDEVICE_ID_UNKNOWN_0x1584, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - { - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_PLX_ROMULUS, - .subvendor = PCI_VENDOR_ID_PLX, - .subdevice = PCI_DEVICE_ID_PLX_ROMULUS, - .init = pci_plx9050_init, - .setup = pci_default_setup, - .exit = __devexit_p(pci_plx9050_exit), - }, - /* - * SBS Technologies, Inc., PMC-OCTALPRO 232 - */ - { - .vendor = PCI_VENDOR_ID_SBSMODULARIO, - .device = PCI_DEVICE_ID_OCTPRO, - .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, - .subdevice = PCI_SUBDEVICE_ID_OCTPRO232, - .init = sbs_init, - .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), - }, - /* - * SBS Technologies, Inc., PMC-OCTALPRO 422 - */ - { - .vendor = PCI_VENDOR_ID_SBSMODULARIO, - .device = PCI_DEVICE_ID_OCTPRO, - .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, - .subdevice = PCI_SUBDEVICE_ID_OCTPRO422, - .init = sbs_init, - .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), - }, - /* - * SBS Technologies, Inc., P-Octal 232 - */ - { - .vendor = PCI_VENDOR_ID_SBSMODULARIO, - .device = PCI_DEVICE_ID_OCTPRO, - .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, - .subdevice = PCI_SUBDEVICE_ID_POCTAL232, - .init = sbs_init, - .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), - }, - /* - * SBS Technologies, Inc., P-Octal 422 - */ - { - .vendor = PCI_VENDOR_ID_SBSMODULARIO, - .device = PCI_DEVICE_ID_OCTPRO, - .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, - .subdevice = PCI_SUBDEVICE_ID_POCTAL422, - .init = sbs_init, - .setup = sbs_setup, - .exit = __devexit_p(sbs_exit), - }, - /* - * SIIG cards - these may be called via parport_serial - */ - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig_init, - .setup = pci_siig_setup, - }, - /* - * Titan cards - */ - { - .vendor = PCI_VENDOR_ID_TITAN, - .device = PCI_DEVICE_ID_TITAN_400L, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = titan_400l_800l_setup, - }, - { - .vendor = PCI_VENDOR_ID_TITAN, - .device = PCI_DEVICE_ID_TITAN_800L, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = titan_400l_800l_setup, - }, - /* - * Timedia cards - */ - { - .vendor = PCI_VENDOR_ID_TIMEDIA, - .device = PCI_DEVICE_ID_TIMEDIA_1889, - .subvendor = PCI_VENDOR_ID_TIMEDIA, - .subdevice = PCI_ANY_ID, - .init = pci_timedia_init, - .setup = pci_timedia_setup, - }, - { - .vendor = PCI_VENDOR_ID_TIMEDIA, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_timedia_setup, - }, - /* - * Xircom cards - */ - { - .vendor = PCI_VENDOR_ID_XIRCOM, - .device = PCI_DEVICE_ID_XIRCOM_X3201_MDM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_xircom_init, - .setup = pci_default_setup, - }, - /* - * Netmos cards - these may be called via parport_serial - */ - { - .vendor = PCI_VENDOR_ID_NETMOS, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_netmos_init, - .setup = pci_default_setup, - }, - /* - * For Oxford Semiconductor and Mainpine - */ - { - .vendor = PCI_VENDOR_ID_OXSEMI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_MAINPINE, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, - }, - /* - * Default "match everything" terminator entry - */ - { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_default_setup, - } -}; - -static inline int quirk_id_matches(u32 quirk_id, u32 dev_id) -{ - return quirk_id == PCI_ANY_ID || quirk_id == dev_id; -} - -static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) -{ - struct pci_serial_quirk *quirk; - - for (quirk = pci_serial_quirks; ; quirk++) - if (quirk_id_matches(quirk->vendor, dev->vendor) && - quirk_id_matches(quirk->device, dev->device) && - quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) && - quirk_id_matches(quirk->subdevice, dev->subsystem_device)) - break; - return quirk; -} - -static inline int get_pci_irq(struct pci_dev *dev, - const struct pciserial_board *board) -{ - if (board->flags & FL_NOIRQ) - return 0; - else - return dev->irq; -} - -/* - * This is the configuration table for all of the PCI serial boards - * which we support. It is directly indexed by the pci_board_num_t enum - * value, which is encoded in the pci_device_id PCI probe table's - * driver_data member. - * - * The makeup of these names are: - * pbn_bn{_bt}_n_baud{_offsetinhex} - * - * bn = PCI BAR number - * bt = Index using PCI BARs - * n = number of serial ports - * baud = baud rate - * offsetinhex = offset for each sequential port (in hex) - * - * This table is sorted by (in order): bn, bt, baud, offsetindex, n. - * - * Please note: in theory if n = 1, _bt infix should make no difference. - * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200 - */ -enum pci_board_num_t { - pbn_default = 0, - - pbn_b0_1_115200, - pbn_b0_2_115200, - pbn_b0_4_115200, - pbn_b0_5_115200, - pbn_b0_8_115200, - - pbn_b0_1_921600, - pbn_b0_2_921600, - pbn_b0_4_921600, - - pbn_b0_2_1130000, - - pbn_b0_4_1152000, - - pbn_b0_2_1843200, - pbn_b0_4_1843200, - - pbn_b0_2_1843200_200, - pbn_b0_4_1843200_200, - pbn_b0_8_1843200_200, - - pbn_b0_1_4000000, - - pbn_b0_bt_1_115200, - pbn_b0_bt_2_115200, - pbn_b0_bt_4_115200, - pbn_b0_bt_8_115200, - - pbn_b0_bt_1_460800, - pbn_b0_bt_2_460800, - pbn_b0_bt_4_460800, - - pbn_b0_bt_1_921600, - pbn_b0_bt_2_921600, - pbn_b0_bt_4_921600, - pbn_b0_bt_8_921600, - - pbn_b1_1_115200, - pbn_b1_2_115200, - pbn_b1_4_115200, - pbn_b1_8_115200, - pbn_b1_16_115200, - - pbn_b1_1_921600, - pbn_b1_2_921600, - pbn_b1_4_921600, - pbn_b1_8_921600, - - pbn_b1_2_1250000, - - pbn_b1_bt_1_115200, - pbn_b1_bt_2_115200, - pbn_b1_bt_4_115200, - - pbn_b1_bt_2_921600, - - pbn_b1_1_1382400, - pbn_b1_2_1382400, - pbn_b1_4_1382400, - pbn_b1_8_1382400, - - pbn_b2_1_115200, - pbn_b2_2_115200, - pbn_b2_4_115200, - pbn_b2_8_115200, - - pbn_b2_1_460800, - pbn_b2_4_460800, - pbn_b2_8_460800, - pbn_b2_16_460800, - - pbn_b2_1_921600, - pbn_b2_4_921600, - pbn_b2_8_921600, - - pbn_b2_8_1152000, - - pbn_b2_bt_1_115200, - pbn_b2_bt_2_115200, - pbn_b2_bt_4_115200, - - pbn_b2_bt_2_921600, - pbn_b2_bt_4_921600, - - pbn_b3_2_115200, - pbn_b3_4_115200, - pbn_b3_8_115200, - - pbn_b4_bt_2_921600, - pbn_b4_bt_4_921600, - pbn_b4_bt_8_921600, - - /* - * Board-specific versions. - */ - pbn_panacom, - pbn_panacom2, - pbn_panacom4, - pbn_exsys_4055, - pbn_plx_romulus, - pbn_oxsemi, - pbn_oxsemi_1_4000000, - pbn_oxsemi_2_4000000, - pbn_oxsemi_4_4000000, - pbn_oxsemi_8_4000000, - pbn_intel_i960, - pbn_sgi_ioc3, - pbn_computone_4, - pbn_computone_6, - pbn_computone_8, - pbn_sbsxrsio, - pbn_exar_XR17C152, - pbn_exar_XR17C154, - pbn_exar_XR17C158, - pbn_exar_ibm_saturn, - pbn_pasemi_1682M, - pbn_ni8430_2, - pbn_ni8430_4, - pbn_ni8430_8, - pbn_ni8430_16, - pbn_ADDIDATA_PCIe_1_3906250, - pbn_ADDIDATA_PCIe_2_3906250, - pbn_ADDIDATA_PCIe_4_3906250, - pbn_ADDIDATA_PCIe_8_3906250, - pbn_ce4100_1_115200, -}; - -/* - * uart_offset - the space between channels - * reg_shift - describes how the UART registers are mapped - * to PCI memory by the card. - * For example IER register on SBS, Inc. PMC-OctPro is located at - * offset 0x10 from the UART base, while UART_IER is defined as 1 - * in include/linux/serial_reg.h, - * see first lines of serial_in() and serial_out() in 8250.c -*/ - -static struct pciserial_board pci_boards[] __devinitdata = { - [pbn_default] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_1_115200] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_2_115200] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_4_115200] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_5_115200] = { - .flags = FL_BASE0, - .num_ports = 5, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_8_115200] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_1_921600] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b0_2_921600] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b0_4_921600] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8, - }, - - [pbn_b0_2_1130000] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 1130000, - .uart_offset = 8, - }, - - [pbn_b0_4_1152000] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 1152000, - .uart_offset = 8, - }, - - [pbn_b0_2_1843200] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 1843200, - .uart_offset = 8, - }, - [pbn_b0_4_1843200] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 1843200, - .uart_offset = 8, - }, - - [pbn_b0_2_1843200_200] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 1843200, - .uart_offset = 0x200, - }, - [pbn_b0_4_1843200_200] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 1843200, - .uart_offset = 0x200, - }, - [pbn_b0_8_1843200_200] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 1843200, - .uart_offset = 0x200, - }, - [pbn_b0_1_4000000] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 4000000, - .uart_offset = 8, - }, - - [pbn_b0_bt_1_115200] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_bt_2_115200] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_bt_4_115200] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b0_bt_8_115200] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 8, - .base_baud = 115200, - .uart_offset = 8, - }, - - [pbn_b0_bt_1_460800] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 1, - .base_baud = 460800, - .uart_offset = 8, - }, - [pbn_b0_bt_2_460800] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 460800, - .uart_offset = 8, - }, - [pbn_b0_bt_4_460800] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 460800, - .uart_offset = 8, - }, - - [pbn_b0_bt_1_921600] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b0_bt_2_921600] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b0_bt_4_921600] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b0_bt_8_921600] = { - .flags = FL_BASE0|FL_BASE_BARS, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 8, - }, - - [pbn_b1_1_115200] = { - .flags = FL_BASE1, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b1_2_115200] = { - .flags = FL_BASE1, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b1_4_115200] = { - .flags = FL_BASE1, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b1_8_115200] = { - .flags = FL_BASE1, - .num_ports = 8, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b1_16_115200] = { - .flags = FL_BASE1, - .num_ports = 16, - .base_baud = 115200, - .uart_offset = 8, - }, - - [pbn_b1_1_921600] = { - .flags = FL_BASE1, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b1_2_921600] = { - .flags = FL_BASE1, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b1_4_921600] = { - .flags = FL_BASE1, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b1_8_921600] = { - .flags = FL_BASE1, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b1_2_1250000] = { - .flags = FL_BASE1, - .num_ports = 2, - .base_baud = 1250000, - .uart_offset = 8, - }, - - [pbn_b1_bt_1_115200] = { - .flags = FL_BASE1|FL_BASE_BARS, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b1_bt_2_115200] = { - .flags = FL_BASE1|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b1_bt_4_115200] = { - .flags = FL_BASE1|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - - [pbn_b1_bt_2_921600] = { - .flags = FL_BASE1|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, - }, - - [pbn_b1_1_1382400] = { - .flags = FL_BASE1, - .num_ports = 1, - .base_baud = 1382400, - .uart_offset = 8, - }, - [pbn_b1_2_1382400] = { - .flags = FL_BASE1, - .num_ports = 2, - .base_baud = 1382400, - .uart_offset = 8, - }, - [pbn_b1_4_1382400] = { - .flags = FL_BASE1, - .num_ports = 4, - .base_baud = 1382400, - .uart_offset = 8, - }, - [pbn_b1_8_1382400] = { - .flags = FL_BASE1, - .num_ports = 8, - .base_baud = 1382400, - .uart_offset = 8, - }, - - [pbn_b2_1_115200] = { - .flags = FL_BASE2, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b2_2_115200] = { - .flags = FL_BASE2, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b2_4_115200] = { - .flags = FL_BASE2, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b2_8_115200] = { - .flags = FL_BASE2, - .num_ports = 8, - .base_baud = 115200, - .uart_offset = 8, - }, - - [pbn_b2_1_460800] = { - .flags = FL_BASE2, - .num_ports = 1, - .base_baud = 460800, - .uart_offset = 8, - }, - [pbn_b2_4_460800] = { - .flags = FL_BASE2, - .num_ports = 4, - .base_baud = 460800, - .uart_offset = 8, - }, - [pbn_b2_8_460800] = { - .flags = FL_BASE2, - .num_ports = 8, - .base_baud = 460800, - .uart_offset = 8, - }, - [pbn_b2_16_460800] = { - .flags = FL_BASE2, - .num_ports = 16, - .base_baud = 460800, - .uart_offset = 8, - }, - - [pbn_b2_1_921600] = { - .flags = FL_BASE2, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b2_4_921600] = { - .flags = FL_BASE2, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b2_8_921600] = { - .flags = FL_BASE2, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 8, - }, - - [pbn_b2_8_1152000] = { - .flags = FL_BASE2, - .num_ports = 8, - .base_baud = 1152000, - .uart_offset = 8, - }, - - [pbn_b2_bt_1_115200] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 1, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b2_bt_2_115200] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b2_bt_4_115200] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - - [pbn_b2_bt_2_921600] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b2_bt_4_921600] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8, - }, - - [pbn_b3_2_115200] = { - .flags = FL_BASE3, - .num_ports = 2, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b3_4_115200] = { - .flags = FL_BASE3, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_b3_8_115200] = { - .flags = FL_BASE3, - .num_ports = 8, - .base_baud = 115200, - .uart_offset = 8, - }, - - [pbn_b4_bt_2_921600] = { - .flags = FL_BASE4, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b4_bt_4_921600] = { - .flags = FL_BASE4, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8, - }, - [pbn_b4_bt_8_921600] = { - .flags = FL_BASE4, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 8, - }, - - /* - * Entries following this are board-specific. - */ - - /* - * Panacom - IOMEM - */ - [pbn_panacom] = { - .flags = FL_BASE2, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 0x400, - .reg_shift = 7, - }, - [pbn_panacom2] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 0x400, - .reg_shift = 7, - }, - [pbn_panacom4] = { - .flags = FL_BASE2|FL_BASE_BARS, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 0x400, - .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, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 8 << 2, - .reg_shift = 2, - .first_offset = 0x03, - }, - - /* - * This board uses the size of PCI Base region 0 to - * signal now many ports are available - */ - [pbn_oxsemi] = { - .flags = FL_BASE0|FL_REGION_SZ_CAP, - .num_ports = 32, - .base_baud = 115200, - .uart_offset = 8, - }, - [pbn_oxsemi_1_4000000] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 4000000, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_oxsemi_2_4000000] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 4000000, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_oxsemi_4_4000000] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 4000000, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_oxsemi_8_4000000] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 4000000, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - - - /* - * EKF addition for i960 Boards form EKF with serial port. - * Max 256 ports. - */ - [pbn_intel_i960] = { - .flags = FL_BASE0, - .num_ports = 32, - .base_baud = 921600, - .uart_offset = 8 << 2, - .reg_shift = 2, - .first_offset = 0x10000, - }, - [pbn_sgi_ioc3] = { - .flags = FL_BASE0|FL_NOIRQ, - .num_ports = 1, - .base_baud = 458333, - .uart_offset = 8, - .reg_shift = 0, - .first_offset = 0x20178, - }, - - /* - * Computone - uses IOMEM. - */ - [pbn_computone_4] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 0x40, - .reg_shift = 2, - .first_offset = 0x200, - }, - [pbn_computone_6] = { - .flags = FL_BASE0, - .num_ports = 6, - .base_baud = 921600, - .uart_offset = 0x40, - .reg_shift = 2, - .first_offset = 0x200, - }, - [pbn_computone_8] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 0x40, - .reg_shift = 2, - .first_offset = 0x200, - }, - [pbn_sbsxrsio] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 460800, - .uart_offset = 256, - .reg_shift = 4, - }, - /* - * Exar Corp. XR17C15[248] Dual/Quad/Octal UART - * Only basic 16550A support. - * XR17C15[24] are not tested, but they should work. - */ - [pbn_exar_XR17C152] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 0x200, - }, - [pbn_exar_XR17C154] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 0x200, - }, - [pbn_exar_XR17C158] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 0x200, - }, - [pbn_exar_ibm_saturn] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 0x200, - }, - - /* - * PA Semi PWRficient PA6T-1682M on-chip UART - */ - [pbn_pasemi_1682M] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 8333333, - }, - /* - * National Instruments 843x - */ - [pbn_ni8430_16] = { - .flags = FL_BASE0, - .num_ports = 16, - .base_baud = 3686400, - .uart_offset = 0x10, - .first_offset = 0x800, - }, - [pbn_ni8430_8] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 3686400, - .uart_offset = 0x10, - .first_offset = 0x800, - }, - [pbn_ni8430_4] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 3686400, - .uart_offset = 0x10, - .first_offset = 0x800, - }, - [pbn_ni8430_2] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 3686400, - .uart_offset = 0x10, - .first_offset = 0x800, - }, - /* - * ADDI-DATA GmbH PCI-Express communication cards - */ - [pbn_ADDIDATA_PCIe_1_3906250] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 3906250, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_ADDIDATA_PCIe_2_3906250] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 3906250, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_ADDIDATA_PCIe_4_3906250] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 3906250, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_ADDIDATA_PCIe_8_3906250] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 3906250, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - [pbn_ce4100_1_115200] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 921600, - .reg_shift = 2, - }, -}; - -static const struct pci_device_id softmodem_blacklist[] = { - { 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 */ -}; - -/* - * Given a complete unknown PCI device, try to use some heuristics to - * guess what the configuration might be, based on the pitiful PCI - * serial specs. Returns 0 on success, 1 on failure. - */ -static int __devinit -serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) -{ - const struct pci_device_id *blacklist; - int num_iomem, num_port, first_port = -1, i; - - /* - * If it is not a communications device or the programming - * interface is greater than 6, give up. - * - * (Should we try to make guesses for multiport serial devices - * later?) - */ - if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && - ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || - (dev->class & 0xff) > 6) - return -ENODEV; - - /* - * Do not access blacklisted devices that are known not to - * feature serial ports. - */ - for (blacklist = softmodem_blacklist; - blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist); - blacklist++) { - if (dev->vendor == blacklist->vendor && - dev->device == blacklist->device) - return -ENODEV; - } - - num_iomem = num_port = 0; - for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { - if (pci_resource_flags(dev, i) & IORESOURCE_IO) { - num_port++; - if (first_port == -1) - first_port = i; - } - if (pci_resource_flags(dev, i) & IORESOURCE_MEM) - num_iomem++; - } - - /* - * If there is 1 or 0 iomem regions, and exactly one port, - * use it. We guess the number of ports based on the IO - * region size. - */ - if (num_iomem <= 1 && num_port == 1) { - board->flags = first_port; - board->num_ports = pci_resource_len(dev, first_port) / 8; - return 0; - } - - /* - * Now guess if we've got a board which indexes by BARs. - * Each IO BAR should be 8 bytes, and they should follow - * consecutively. - */ - first_port = -1; - num_port = 0; - for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { - if (pci_resource_flags(dev, i) & IORESOURCE_IO && - pci_resource_len(dev, i) == 8 && - (first_port == -1 || (first_port + num_port) == i)) { - num_port++; - if (first_port == -1) - first_port = i; - } - } - - if (num_port > 1) { - board->flags = first_port | FL_BASE_BARS; - board->num_ports = num_port; - return 0; - } - - return -ENODEV; -} - -static inline int -serial_pci_matches(const struct pciserial_board *board, - const struct pciserial_board *guessed) -{ - return - board->num_ports == guessed->num_ports && - board->base_baud == guessed->base_baud && - board->uart_offset == guessed->uart_offset && - board->reg_shift == guessed->reg_shift && - board->first_offset == guessed->first_offset; -} - -struct serial_private * -pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) -{ - struct uart_port serial_port; - struct serial_private *priv; - struct pci_serial_quirk *quirk; - int rc, nr_ports, i; - - nr_ports = board->num_ports; - - /* - * Find an init and setup quirks. - */ - quirk = find_quirk(dev); - - /* - * Run the new-style initialization function. - * The initialization function returns: - * <0 - error - * 0 - use board->num_ports - * >0 - number of ports - */ - if (quirk->init) { - rc = quirk->init(dev); - if (rc < 0) { - priv = ERR_PTR(rc); - goto err_out; - } - if (rc) - nr_ports = rc; - } - - priv = kzalloc(sizeof(struct serial_private) + - sizeof(unsigned int) * nr_ports, - GFP_KERNEL); - if (!priv) { - priv = ERR_PTR(-ENOMEM); - goto err_deinit; - } - - 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; - - for (i = 0; i < nr_ports; i++) { - if (quirk->setup(priv, board, &serial_port, 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); -#endif - - priv->line[i] = serial8250_register_port(&serial_port); - if (priv->line[i] < 0) { - printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); - break; - } - } - priv->nr = i; - return priv; - -err_deinit: - if (quirk->exit) - quirk->exit(dev); -err_out: - return priv; -} -EXPORT_SYMBOL_GPL(pciserial_init_ports); - -void pciserial_remove_ports(struct serial_private *priv) -{ - struct pci_serial_quirk *quirk; - int i; - - for (i = 0; i < priv->nr; i++) - serial8250_unregister_port(priv->line[i]); - - for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { - if (priv->remapped_bar[i]) - iounmap(priv->remapped_bar[i]); - priv->remapped_bar[i] = NULL; - } - - /* - * Find the exit quirks. - */ - quirk = find_quirk(priv->dev); - if (quirk->exit) - quirk->exit(priv->dev); - - kfree(priv); -} -EXPORT_SYMBOL_GPL(pciserial_remove_ports); - -void pciserial_suspend_ports(struct serial_private *priv) -{ - int i; - - for (i = 0; i < priv->nr; i++) - if (priv->line[i] >= 0) - serial8250_suspend_port(priv->line[i]); -} -EXPORT_SYMBOL_GPL(pciserial_suspend_ports); - -void pciserial_resume_ports(struct serial_private *priv) -{ - int i; - - /* - * Ensure that the board is correctly configured. - */ - if (priv->quirk->init) - priv->quirk->init(priv->dev); - - for (i = 0; i < priv->nr; i++) - if (priv->line[i] >= 0) - serial8250_resume_port(priv->line[i]); -} -EXPORT_SYMBOL_GPL(pciserial_resume_ports); - -/* - * Probe one serial board. Unfortunately, there is no rhyme nor reason - * to the arrangement of serial ports on a PCI card. - */ -static int __devinit -pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) -{ - struct serial_private *priv; - const struct pciserial_board *board; - struct pciserial_board tmp; - int rc; - - if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", - ent->driver_data); - return -EINVAL; - } - - board = &pci_boards[ent->driver_data]; - - rc = pci_enable_device(dev); - if (rc) - return rc; - - if (ent->driver_data == pbn_default) { - /* - * Use a copy of the pci_board entry for this; - * avoid changing entries in the table. - */ - memcpy(&tmp, board, sizeof(struct pciserial_board)); - board = &tmp; - - /* - * We matched one of our class entries. Try to - * determine the parameters of this board. - */ - rc = serial_pci_guess_board(dev, &tmp); - if (rc) - goto disable; - } else { - /* - * We matched an explicit entry. If we are able to - * detect this boards settings with our heuristic, - * then we no longer need this entry. - */ - memcpy(&tmp, &pci_boards[pbn_default], - sizeof(struct pciserial_board)); - rc = serial_pci_guess_board(dev, &tmp); - if (rc == 0 && serial_pci_matches(board, &tmp)) - moan_device("Redundant entry in serial pci_table.", - dev); - } - - priv = pciserial_init_ports(dev, board); - if (!IS_ERR(priv)) { - pci_set_drvdata(dev, priv); - return 0; - } - - rc = PTR_ERR(priv); - - disable: - pci_disable_device(dev); - return rc; -} - -static void __devexit pciserial_remove_one(struct pci_dev *dev) -{ - struct serial_private *priv = pci_get_drvdata(dev); - - pci_set_drvdata(dev, NULL); - - pciserial_remove_ports(priv); - - pci_disable_device(dev); -} - -#ifdef CONFIG_PM -static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) -{ - struct serial_private *priv = pci_get_drvdata(dev); - - if (priv) - pciserial_suspend_ports(priv); - - pci_save_state(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); - return 0; -} - -static int pciserial_resume_one(struct pci_dev *dev) -{ - int err; - struct serial_private *priv = pci_get_drvdata(dev); - - pci_set_power_state(dev, PCI_D0); - pci_restore_state(dev); - - if (priv) { - /* - * The device may have been disabled. Re-enable it. - */ - err = pci_enable_device(dev); - /* FIXME: We cannot simply error out here */ - if (err) - printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); - pciserial_resume_ports(priv); - } - return 0; -} -#endif - -static struct pci_device_id serial_pci_tbl[] = { - /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ - { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, - PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, - pbn_b2_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, - pbn_b1_8_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, - pbn_b1_4_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, - pbn_b1_2_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, - pbn_b1_8_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, - pbn_b1_4_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, - pbn_b1_2_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0, - pbn_b1_4_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0, - pbn_b1_4_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0, - pbn_b1_2_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, - pbn_b1_4_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0, - pbn_b1_2_1250000 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0, - pbn_b0_2_1843200 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0, - pbn_b0_4_1843200 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_VENDOR_ID_AFAVLAB, - PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0, - pbn_b0_4_1152000 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0, - pbn_b0_2_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0, - pbn_b0_4_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0, - pbn_b0_8_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0, - pbn_b0_2_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0, - pbn_b0_4_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0, - pbn_b0_8_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0, - pbn_b0_2_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0, - pbn_b0_4_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0, - pbn_b0_8_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0, - pbn_b0_2_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0, - pbn_b0_4_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0, - pbn_b0_8_1843200_200 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, - PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT, - 0, 0, pbn_exar_ibm_saturn }, - - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_1_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_460800 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_115200 }, - - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_921600 }, - /* - * VScom SPCOM800, from sl@s.pl - */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_921600 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_4_921600 }, - /* Unknown card - subdevice 0x1584 */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_VENDOR_ID_PLX, - PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0, - pbn_b0_4_115200 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_KEYSPAN, - PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, - pbn_panacom }, - { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_panacom4 }, - { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_panacom2 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, - PCI_VENDOR_ID_ESDGMBH, - PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0, - pbn_b2_4_115200 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, - pbn_b2_4_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, - pbn_b2_8_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, - pbn_b2_16_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, - pbn_b2_16_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, - pbn_b2_4_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, - pbn_b2_8_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_EXSYS, - PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0, - pbn_exsys_4055 }, - /* - * Megawolf Romulus PCI Serial Card, from Mike Hudson - * (Exoray@isys.ca) - */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, - 0x10b5, 0x106a, 0, 0, - pbn_plx_romulus }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_4_115200 }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_2_115200 }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_8_115200 }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_8_115200 }, - { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, - 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL, - 0, 0, - pbn_b0_4_1152000 }, - { PCI_VENDOR_ID_OXSEMI, 0x9505, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_921600 }, - - /* - * The below card is a little controversial since it is the - * subject of a PCI vendor/device ID clash. (See - * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html). - * For now just used the hex ID 0x950a. - */ - { PCI_VENDOR_ID_OXSEMI, 0x950a, - PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0, - pbn_b0_2_115200 }, - { PCI_VENDOR_ID_OXSEMI, 0x950a, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_2_1130000 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, - PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0, - pbn_b0_1_921600 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_115200 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_921600 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958, - PCI_ANY_ID , PCI_ANY_ID, 0, 0, - pbn_b2_8_1152000 }, - - /* - * Oxford Semiconductor Inc. Tornado PCI express device range. - */ - { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - /* - * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado - */ - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0, - pbn_oxsemi_2_4000000 }, - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0, - pbn_oxsemi_4_4000000 }, - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0, - pbn_oxsemi_8_4000000 }, - /* - * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards, - * from skokodyn@yahoo.com - */ - { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, - PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0, - pbn_sbsxrsio }, - { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, - PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0, - pbn_sbsxrsio }, - { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, - PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0, - pbn_sbsxrsio }, - { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, - PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0, - pbn_sbsxrsio }, - - /* - * Digitan DS560-558, from jimd@esoft.com - */ - { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_1_115200 }, - - /* - * Titan Electronic cards - * The 400L and 800L have a custom setup quirk. - */ - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_2_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_1_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_2_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_8_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b4_bt_2_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b4_bt_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b4_bt_8_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, - - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_460800 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_460800 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_460800 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_4_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_4_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_4_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_8_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_8_921600 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_8_921600 }, - - /* - * Computone devices submitted by Doug McNash dmcnash@computone.com - */ - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, - 0, 0, pbn_computone_4 }, - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, - 0, 0, pbn_computone_8 }, - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, - 0, 0, pbn_computone_6 }, - - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, - PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_921600 }, - - /* - * AFAVLAB serial card, from Harald Welte - */ - { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_8_115200 }, - { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_8_115200 }, - - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_4_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_4_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_460800 }, - - /* - * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408). - * Cards are identified by their subsystem vendor IDs, which - * (in hex) match the model number. - * - * Note that JC140x are RS422/485 cards which require ox950 - * ACR = 0x10, and as such are not currently fully supported. - */ - { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, - 0x1204, 0x0004, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, - 0x1208, 0x0004, 0, 0, - pbn_b0_4_921600 }, -/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, - 0x1402, 0x0002, 0, 0, - pbn_b0_2_921600 }, */ -/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, - 0x1404, 0x0004, 0, 0, - pbn_b0_4_921600 }, */ - { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1, - 0x1208, 0x0004, 0, 0, - pbn_b0_4_921600 }, - - { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, - 0x1204, 0x0004, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, - 0x1208, 0x0004, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3, - 0x1208, 0x0004, 0, 0, - pbn_b0_4_921600 }, - /* - * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com - */ - { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_1_1382400 }, - - /* - * Dell Remote Access Card III - Tim_T_Murphy@Dell.com - */ - { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_1_1382400 }, - - /* - * RAStel 2 port modem, gerg@moreton.com.au - */ - { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - - /* - * EKF addition for i960 Boards form EKF with serial port - */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP, - 0xE4BF, PCI_ANY_ID, 0, 0, - pbn_intel_i960 }, - - /* - * Xircom Cardbus/Ethernet combos - */ - { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_115200 }, - /* - * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry) - */ - { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_115200 }, - - /* - * Untested PCI modems, sent in from various folks... - */ - - /* - * Elsa Model 56K PCI Modem, from Andreas Rath - */ - { PCI_VENDOR_ID_ROCKWELL, 0x1004, - 0x1048, 0x1500, 0, 0, - pbn_b1_1_115200 }, - - { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - 0xFF00, 0, 0, 0, - pbn_sgi_ioc3 }, - - /* - * HP Diva card - */ - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA, - PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0, - pbn_b1_1_115200 }, - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_5_115200 }, - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_115200 }, - - { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b3_2_115200 }, - { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b3_4_115200 }, - { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b3_8_115200 }, - - /* - * Exar Corp. XR17C15[248] Dual/Quad/Octal UART - */ - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_exar_XR17C152 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_exar_XR17C154 }, - { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_exar_XR17C158 }, - - /* - * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) - */ - { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_115200 }, - /* - * ITE - */ - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b1_bt_1_115200 }, - - /* - * IntaShield IS-200 - */ - { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */ - pbn_b2_2_115200 }, - /* - * IntaShield IS-400 - */ - { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ - pbn_b2_4_115200 }, - /* - * Perle PCI-RAS cards - */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, - PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4, - 0, 0, pbn_b2_4_921600 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, - PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8, - 0, 0, pbn_b2_8_921600 }, - - /* - * Mainpine series cards: Fairly standard layout but fools - * parts of the autodetect in some cases and uses otherwise - * unmatched communications subclasses in the PCI Express case - */ - - { /* RockForceDUO */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0200, - 0, 0, pbn_b0_2_115200 }, - { /* RockForceQUATRO */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0300, - 0, 0, pbn_b0_4_115200 }, - { /* RockForceDUO+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0400, - 0, 0, pbn_b0_2_115200 }, - { /* RockForceQUATRO+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0500, - 0, 0, pbn_b0_4_115200 }, - { /* RockForce+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0600, - 0, 0, pbn_b0_2_115200 }, - { /* RockForce+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0700, - 0, 0, pbn_b0_4_115200 }, - { /* RockForceOCTO+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0800, - 0, 0, pbn_b0_8_115200 }, - { /* RockForceDUO+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0C00, - 0, 0, pbn_b0_2_115200 }, - { /* RockForceQUARTRO+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x0D00, - 0, 0, pbn_b0_4_115200 }, - { /* RockForceOCTO+ */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x1D00, - 0, 0, pbn_b0_8_115200 }, - { /* RockForceD1 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2000, - 0, 0, pbn_b0_1_115200 }, - { /* RockForceF1 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2100, - 0, 0, pbn_b0_1_115200 }, - { /* RockForceD2 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2200, - 0, 0, pbn_b0_2_115200 }, - { /* RockForceF2 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2300, - 0, 0, pbn_b0_2_115200 }, - { /* RockForceD4 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2400, - 0, 0, pbn_b0_4_115200 }, - { /* RockForceF4 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2500, - 0, 0, pbn_b0_4_115200 }, - { /* RockForceD8 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2600, - 0, 0, pbn_b0_8_115200 }, - { /* RockForceF8 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x2700, - 0, 0, pbn_b0_8_115200 }, - { /* IQ Express D1 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3000, - 0, 0, pbn_b0_1_115200 }, - { /* IQ Express F1 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3100, - 0, 0, pbn_b0_1_115200 }, - { /* IQ Express D2 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3200, - 0, 0, pbn_b0_2_115200 }, - { /* IQ Express F2 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3300, - 0, 0, pbn_b0_2_115200 }, - { /* IQ Express D4 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3400, - 0, 0, pbn_b0_4_115200 }, - { /* IQ Express F4 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3500, - 0, 0, pbn_b0_4_115200 }, - { /* IQ Express D8 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3C00, - 0, 0, pbn_b0_8_115200 }, - { /* IQ Express F8 */ - PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, - PCI_VENDOR_ID_MAINPINE, 0x3D00, - 0, 0, pbn_b0_8_115200 }, - - - /* - * PA Semi PA6T-1682M on-chip UART - */ - { PCI_VENDOR_ID_PASEMI, 0xa004, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pasemi_1682M }, - - /* - * National Instruments - */ - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_16_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_8_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_4_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_2_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_4_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_2_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_16_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_8_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_4_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_2_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_4_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_bt_2_115200 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_2 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_2 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_4 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_4 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_8 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_8 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_16 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_16 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_2 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_2 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_4 }, - { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ni8430_4 }, - - /* - * ADDI-DATA GmbH communication cards - */ - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7500, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_4_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7420, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_2_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7300, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_1_115200 }, - - { PCI_VENDOR_ID_ADDIDATA_OLD, - PCI_DEVICE_ID_ADDIDATA_APCI7800, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b1_8_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7500_2, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_4_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7420_2, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_2_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7300_2, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_1_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7500_3, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_4_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7420_3, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_2_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7300_3, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_1_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCI7800_3, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_8_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCIe7500, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_ADDIDATA_PCIe_4_3906250 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCIe7420, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_ADDIDATA_PCIe_2_3906250 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCIe7300, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_ADDIDATA_PCIe_1_3906250 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_APCIe7800, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_ADDIDATA_PCIe_8_3906250 }, - - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, - PCI_VENDOR_ID_IBM, 0x0299, - 0, 0, pbn_b0_bt_2_115200 }, - - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, - 0xA000, 0x1000, - 0, 0, pbn_b0_1_115200 }, - - /* - * Best Connectivity PCI Multi I/O cards - */ - - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, - 0xA000, 0x1000, - 0, 0, pbn_b0_1_115200 }, - - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, - 0xA000, 0x3004, - 0, 0, pbn_b0_bt_4_115200 }, - /* Intel CE4100 */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_ce4100_1_115200 }, - - - /* - * These entries match devices with class COMMUNICATION_SERIAL, - * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL - */ - { PCI_ANY_ID, PCI_ANY_ID, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, - 0xffff00, pbn_default }, - { PCI_ANY_ID, PCI_ANY_ID, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_MODEM << 8, - 0xffff00, pbn_default }, - { PCI_ANY_ID, PCI_ANY_ID, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, - 0xffff00, pbn_default }, - { 0, } -}; - -static struct pci_driver serial_pci_driver = { - .name = "serial", - .probe = pciserial_init_one, - .remove = __devexit_p(pciserial_remove_one), -#ifdef CONFIG_PM - .suspend = pciserial_suspend_one, - .resume = pciserial_resume_one, -#endif - .id_table = serial_pci_tbl, -}; - -static int __init serial8250_pci_init(void) -{ - return pci_register_driver(&serial_pci_driver); -} - -static void __exit serial8250_pci_exit(void) -{ - pci_unregister_driver(&serial_pci_driver); -} - -module_init(serial8250_pci_init); -module_exit(serial8250_pci_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); -MODULE_DEVICE_TABLE(pci, serial_pci_tbl); diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c deleted file mode 100644 index 4822cb50cd0f..000000000000 --- a/drivers/serial/8250_pnp.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * linux/drivers/char/8250_pnp.c - * - * Probe module for 8250/16550-type ISAPNP serial ports. - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright (C) 2001 Russell King, All Rights Reserved. - * - * Ported to the Linux PnP Layer - (C) Adam Belay. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "8250.h" - -#define UNKNOWN_DEV 0x3000 - - -static const struct pnp_device_id pnp_dev_table[] = { - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { "AAC000F", 0 }, - /* Anchor Datacomm BV */ - /* SXPro 144 External Data Fax Modem Plug & Play */ - { "ADC0001", 0 }, - /* SXPro 288 External Data Fax Modem Plug & Play */ - { "ADC0002", 0 }, - /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */ - { "AEI0250", 0 }, - /* Actiontec ISA PNP 56K X2 Fax Modem */ - { "AEI1240", 0 }, - /* Rockwell 56K ACF II Fax+Data+Voice Modem */ - { "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ }, - /* AZT3005 PnP SOUND DEVICE */ - { "AZT4001", 0 }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { "BDP3336", 0 }, - /* Boca Research */ - /* Boca Complete Ofc Communicator 14.4 Data-FAX */ - { "BRI0A49", 0 }, - /* Boca Research 33,600 ACF Modem */ - { "BRI1400", 0 }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { "BRI3400", 0 }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { "BRI0A49", 0 }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { "BDP3336", 0 }, - /* Computer Peripherals Inc */ - /* EuroViVa CommCenter-33.6 SP PnP */ - { "CPI4050", 0 }, - /* Creative Labs */ - /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ - { "CTL3001", 0 }, - /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ - { "CTL3011", 0 }, - /* Davicom ISA 33.6K Modem */ - { "DAV0336", 0 }, - /* Creative */ - /* Creative Modem Blaster Flash56 DI5601-1 */ - { "DMB1032", 0 }, - /* Creative Modem Blaster V.90 DI5660 */ - { "DMB2001", 0 }, - /* E-Tech */ - /* E-Tech CyberBULLET PC56RVP */ - { "ETT0002", 0 }, - /* FUJITSU */ - /* Fujitsu 33600 PnP-I2 R Plug & Play */ - { "FUJ0202", 0 }, - /* Fujitsu FMV-FX431 Plug & Play */ - { "FUJ0205", 0 }, - /* Fujitsu 33600 PnP-I4 R Plug & Play */ - { "FUJ0206", 0 }, - /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ - { "FUJ0209", 0 }, - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { "GVC000F", 0 }, - /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */ - { "GVC0303", 0 }, - /* Hayes */ - /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ - { "HAY0001", 0 }, - /* Hayes Optima 336 V.34 + FAX + Voice PnP */ - { "HAY000C", 0 }, - /* Hayes Optima 336B V.34 + FAX + Voice PnP */ - { "HAY000D", 0 }, - /* Hayes Accura 56K Ext Fax Modem PnP */ - { "HAY5670", 0 }, - /* Hayes Accura 56K Ext Fax Modem PnP */ - { "HAY5674", 0 }, - /* Hayes Accura 56K Fax Modem PnP */ - { "HAY5675", 0 }, - /* Hayes 288, V.34 + FAX */ - { "HAYF000", 0 }, - /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ - { "HAYF001", 0 }, - /* IBM */ - /* IBM Thinkpad 701 Internal Modem Voice */ - { "IBM0033", 0 }, - /* Intertex */ - /* Intertex 28k8 33k6 Voice EXT PnP */ - { "IXDC801", 0 }, - /* Intertex 33k6 56k Voice EXT PnP */ - { "IXDC901", 0 }, - /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { "IXDD801", 0 }, - /* Intertex 33k6 56k Voice SP EXT PnP */ - { "IXDD901", 0 }, - /* Intertex 28k8 33k6 Voice SP INT PnP */ - { "IXDF401", 0 }, - /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { "IXDF801", 0 }, - /* Intertex 33k6 56k Voice SP EXT PnP */ - { "IXDF901", 0 }, - /* Kortex International */ - /* KORTEX 28800 Externe PnP */ - { "KOR4522", 0 }, - /* KXPro 33.6 Vocal ASVD PnP */ - { "KORF661", 0 }, - /* Lasat */ - /* LASAT Internet 33600 PnP */ - { "LAS4040", 0 }, - /* Lasat Safire 560 PnP */ - { "LAS4540", 0 }, - /* Lasat Safire 336 PnP */ - { "LAS5440", 0 }, - /* Microcom, Inc. */ - /* Microcom TravelPorte FAST V.34 Plug & Play */ - { "MNP0281", 0 }, - /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ - { "MNP0336", 0 }, - /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ - { "MNP0339", 0 }, - /* Microcom DeskPorte 28.8P Plug & Play */ - { "MNP0342", 0 }, - /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { "MNP0500", 0 }, - /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { "MNP0501", 0 }, - /* Microcom DeskPorte 28.8S Internal Plug & Play */ - { "MNP0502", 0 }, - /* Motorola */ - /* Motorola BitSURFR Plug & Play */ - { "MOT1105", 0 }, - /* Motorola TA210 Plug & Play */ - { "MOT1111", 0 }, - /* Motorola HMTA 200 (ISDN) Plug & Play */ - { "MOT1114", 0 }, - /* Motorola BitSURFR Plug & Play */ - { "MOT1115", 0 }, - /* Motorola Lifestyle 28.8 Internal */ - { "MOT1190", 0 }, - /* Motorola V.3400 Plug & Play */ - { "MOT1501", 0 }, - /* Motorola Lifestyle 28.8 V.34 Plug & Play */ - { "MOT1502", 0 }, - /* Motorola Power 28.8 V.34 Plug & Play */ - { "MOT1505", 0 }, - /* Motorola ModemSURFR External 28.8 Plug & Play */ - { "MOT1509", 0 }, - /* Motorola Premier 33.6 Desktop Plug & Play */ - { "MOT150A", 0 }, - /* Motorola VoiceSURFR 56K External PnP */ - { "MOT150F", 0 }, - /* Motorola ModemSURFR 56K External PnP */ - { "MOT1510", 0 }, - /* Motorola ModemSURFR 56K Internal PnP */ - { "MOT1550", 0 }, - /* Motorola ModemSURFR Internal 28.8 Plug & Play */ - { "MOT1560", 0 }, - /* Motorola Premier 33.6 Internal Plug & Play */ - { "MOT1580", 0 }, - /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ - { "MOT15B0", 0 }, - /* Motorola VoiceSURFR 56K Internal PnP */ - { "MOT15F0", 0 }, - /* Com 1 */ - /* Deskline K56 Phone System PnP */ - { "MVX00A1", 0 }, - /* PC Rider K56 Phone System PnP */ - { "MVX00F2", 0 }, - /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */ - { "nEC8241", 0 }, - /* Pace 56 Voice Internal Plug & Play Modem */ - { "PMC2430", 0 }, - /* Generic */ - /* Generic standard PC COM port */ - { "PNP0500", 0 }, - /* Generic 16550A-compatible COM port */ - { "PNP0501", 0 }, - /* Compaq 14400 Modem */ - { "PNPC000", 0 }, - /* Compaq 2400/9600 Modem */ - { "PNPC001", 0 }, - /* Dial-Up Networking Serial Cable between 2 PCs */ - { "PNPC031", 0 }, - /* Dial-Up Networking Parallel Cable between 2 PCs */ - { "PNPC032", 0 }, - /* Standard 9600 bps Modem */ - { "PNPC100", 0 }, - /* Standard 14400 bps Modem */ - { "PNPC101", 0 }, - /* Standard 28800 bps Modem*/ - { "PNPC102", 0 }, - /* Standard Modem*/ - { "PNPC103", 0 }, - /* Standard 9600 bps Modem*/ - { "PNPC104", 0 }, - /* Standard 14400 bps Modem*/ - { "PNPC105", 0 }, - /* Standard 28800 bps Modem*/ - { "PNPC106", 0 }, - /* Standard Modem */ - { "PNPC107", 0 }, - /* Standard 9600 bps Modem */ - { "PNPC108", 0 }, - /* Standard 14400 bps Modem */ - { "PNPC109", 0 }, - /* Standard 28800 bps Modem */ - { "PNPC10A", 0 }, - /* Standard Modem */ - { "PNPC10B", 0 }, - /* Standard 9600 bps Modem */ - { "PNPC10C", 0 }, - /* Standard 14400 bps Modem */ - { "PNPC10D", 0 }, - /* Standard 28800 bps Modem */ - { "PNPC10E", 0 }, - /* Standard Modem */ - { "PNPC10F", 0 }, - /* Standard PCMCIA Card Modem */ - { "PNP2000", 0 }, - /* Rockwell */ - /* Modular Technology */ - /* Rockwell 33.6 DPF Internal PnP */ - /* Modular Technology 33.6 Internal PnP */ - { "ROK0030", 0 }, - /* Kortex International */ - /* KORTEX 14400 Externe PnP */ - { "ROK0100", 0 }, - /* Rockwell 28.8 */ - { "ROK4120", 0 }, - /* Viking Components, Inc */ - /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ - { "ROK4920", 0 }, - /* Rockwell */ - /* British Telecom */ - /* Modular Technology */ - /* Rockwell 33.6 DPF External PnP */ - /* BT Prologue 33.6 External PnP */ - /* Modular Technology 33.6 External PnP */ - { "RSS00A0", 0 }, - /* Viking 56K FAX INT */ - { "RSS0262", 0 }, - /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */ - { "RSS0250", 0 }, - /* SupraExpress 28.8 Data/Fax PnP modem */ - { "SUP1310", 0 }, - /* SupraExpress 336i PnP Voice Modem */ - { "SUP1381", 0 }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { "SUP1421", 0 }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { "SUP1590", 0 }, - /* SupraExpress 336i Sp ASVD */ - { "SUP1620", 0 }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { "SUP1760", 0 }, - /* SupraExpress 56i Sp Intl */ - { "SUP2171", 0 }, - /* Phoebe Micro */ - /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ - { "TEX0011", 0 }, - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { "UAC000F", 0 }, - /* 3Com Corp. */ - /* Gateway Telepath IIvi 33.6 */ - { "USR0000", 0 }, - /* U.S. Robotics Sporster 33.6K Fax INT PnP */ - { "USR0002", 0 }, - /* Sportster Vi 14.4 PnP FAX Voicemail */ - { "USR0004", 0 }, - /* U.S. Robotics 33.6K Voice INT PnP */ - { "USR0006", 0 }, - /* U.S. Robotics 33.6K Voice EXT PnP */ - { "USR0007", 0 }, - /* U.S. Robotics Courier V.Everything INT PnP */ - { "USR0009", 0 }, - /* U.S. Robotics 33.6K Voice INT PnP */ - { "USR2002", 0 }, - /* U.S. Robotics 56K Voice INT PnP */ - { "USR2070", 0 }, - /* U.S. Robotics 56K Voice EXT PnP */ - { "USR2080", 0 }, - /* U.S. Robotics 56K FAX INT */ - { "USR3031", 0 }, - /* U.S. Robotics 56K FAX INT */ - { "USR3050", 0 }, - /* U.S. Robotics 56K Voice INT PnP */ - { "USR3070", 0 }, - /* U.S. Robotics 56K Voice EXT PnP */ - { "USR3080", 0 }, - /* U.S. Robotics 56K Voice INT PnP */ - { "USR3090", 0 }, - /* U.S. Robotics 56K Message */ - { "USR9100", 0 }, - /* U.S. Robotics 56K FAX EXT PnP*/ - { "USR9160", 0 }, - /* U.S. Robotics 56K FAX INT PnP*/ - { "USR9170", 0 }, - /* U.S. Robotics 56K Voice EXT PnP*/ - { "USR9180", 0 }, - /* U.S. Robotics 56K Voice INT PnP*/ - { "USR9190", 0 }, - /* Wacom tablets */ - { "WACFXXX", 0 }, - /* Compaq touchscreen */ - { "FPI2002", 0 }, - /* Fujitsu Stylistic touchscreens */ - { "FUJ02B2", 0 }, - { "FUJ02B3", 0 }, - /* Fujitsu Stylistic LT touchscreens */ - { "FUJ02B4", 0 }, - /* Passive Fujitsu Stylistic touchscreens */ - { "FUJ02B6", 0 }, - { "FUJ02B7", 0 }, - { "FUJ02B8", 0 }, - { "FUJ02B9", 0 }, - { "FUJ02BC", 0 }, - /* Fujitsu Wacom Tablet PC device */ - { "FUJ02E5", 0 }, - /* Fujitsu P-series tablet PC device */ - { "FUJ02E6", 0 }, - /* Fujitsu Wacom 2FGT Tablet PC device */ - { "FUJ02E7", 0 }, - /* Fujitsu Wacom 1FGT Tablet PC device */ - { "FUJ02E9", 0 }, - /* - * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in - * disguise) - */ - { "LTS0001", 0 }, - /* Rockwell's (PORALiNK) 33600 INT PNP */ - { "WCI0003", 0 }, - /* Unknown PnP modems */ - { "PNPCXXX", UNKNOWN_DEV }, - /* More unknown PnP modems */ - { "PNPDXXX", UNKNOWN_DEV }, - { "", 0 } -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); - -static char *modem_names[] __devinitdata = { - "MODEM", "Modem", "modem", "FAX", "Fax", "fax", - "56K", "56k", "K56", "33.6", "28.8", "14.4", - "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", - "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL -}; - -static int __devinit check_name(char *name) -{ - char **tmp; - - for (tmp = modem_names; *tmp; tmp++) - if (strstr(name, *tmp)) - return 1; - - return 0; -} - -static int __devinit check_resources(struct pnp_dev *dev) -{ - resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8}; - int i; - - for (i = 0; i < ARRAY_SIZE(base); i++) { - if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8)) - return 1; - } - - return 0; -} - -/* - * Given a complete unknown PnP device, try to use some heuristics to - * detect modems. Currently use such heuristic set: - * - dev->name or dev->bus->name must contain "modem" substring; - * - device must have only one IO region (8 byte long) with base address - * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. - * - * Such detection looks very ugly, but can detect at least some of numerous - * PnP modems, alternatively we must hardcode all modems in pnp_devices[] - * table. - */ -static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) -{ - if (!(check_name(pnp_dev_name(dev)) || - (dev->card && check_name(dev->card->name)))) - return -ENODEV; - - if (check_resources(dev)) - return 0; - - return -ENODEV; -} - -static int __devinit -serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) -{ - struct uart_port port; - int ret, line, flags = dev_id->driver_data; - - if (flags & UNKNOWN_DEV) { - ret = serial_pnp_guess_board(dev, &flags); - if (ret < 0) - return ret; - } - - memset(&port, 0, sizeof(struct uart_port)); - if (pnp_irq_valid(dev, 0)) - port.irq = pnp_irq(dev, 0); - if (pnp_port_valid(dev, 0)) { - port.iobase = pnp_port_start(dev, 0); - 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; - } 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); -#endif - - 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; - - line = serial8250_register_port(&port); - if (line < 0) - return -ENODEV; - - pnp_set_drvdata(dev, (void *)((long)line + 1)); - return 0; -} - -static void __devexit serial_pnp_remove(struct pnp_dev *dev) -{ - long line = (long)pnp_get_drvdata(dev); - if (line) - serial8250_unregister_port(line - 1); -} - -#ifdef CONFIG_PM -static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -{ - long line = (long)pnp_get_drvdata(dev); - - if (!line) - return -ENODEV; - serial8250_suspend_port(line - 1); - return 0; -} - -static int serial_pnp_resume(struct pnp_dev *dev) -{ - long line = (long)pnp_get_drvdata(dev); - - if (!line) - return -ENODEV; - serial8250_resume_port(line - 1); - return 0; -} -#else -#define serial_pnp_suspend NULL -#define serial_pnp_resume NULL -#endif /* CONFIG_PM */ - -static struct pnp_driver serial_pnp_driver = { - .name = "serial", - .probe = serial_pnp_probe, - .remove = __devexit_p(serial_pnp_remove), - .suspend = serial_pnp_suspend, - .resume = serial_pnp_resume, - .id_table = pnp_dev_table, -}; - -static int __init serial8250_pnp_init(void) -{ - return pnp_register_driver(&serial_pnp_driver); -} - -static void __exit serial8250_pnp_exit(void) -{ - pnp_unregister_driver(&serial_pnp_driver); -} - -module_init(serial8250_pnp_init); -module_exit(serial8250_pnp_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig deleted file mode 100644 index c1df7676a73d..000000000000 --- a/drivers/serial/Kconfig +++ /dev/null @@ -1,1598 +0,0 @@ -# -# Serial device configuration -# - -menu "Serial drivers" - depends on HAS_IOMEM - -# -# The new 8250/16550 serial drivers -config SERIAL_8250 - tristate "8250/16550 and compatible serial support" - select SERIAL_CORE - ---help--- - This selects whether you want to include the driver for the standard - serial ports. The standard answer is Y. People who might say N - here are those that are setting up dedicated Ethernet WWW/FTP - servers, or users that have one of the various bus mice instead of a - serial mouse and don't intend to use their machine's standard serial - port for anything. (Note that the Cyclades and Stallion multi - serial port drivers do not need this driver built in for them to - work.) - - To compile this driver as a module, choose M here: the - module will be called 8250. - [WARNING: Do not compile this driver as a module if you are using - non-standard serial ports, since the configuration information will - be lost when the driver is unloaded. This limitation may be lifted - in the future.] - - BTW1: If you have a mouseman serial mouse which is not recognized by - the X window system, try running gpm first. - - BTW2: If you intend to use a software modem (also called Winmodem) - under Linux, forget it. These modems are crippled and require - proprietary drivers which are only available under Windows. - - Most people will say Y or M here, so that they can use serial mice, - modems and similar devices connecting to the standard serial ports. - -config SERIAL_8250_CONSOLE - bool "Console on 8250/16550 and compatible serial port" - depends on SERIAL_8250=y - select SERIAL_CORE_CONSOLE - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). This could be useful if some terminal or printer is connected - to that serial port. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyS1". (Try "man bootparam" or see the documentation of - your boot loader (grub or lilo or loadlin) about how to pass options - to the kernel at boot time.) - - If you don't have a VGA card installed and you say Y here, the - kernel will automatically use the first serial line, /dev/ttyS0, as - system console. - - You can set that using a kernel command line option such as - "console=uart8250,io,0x3f8,9600n8" - "console=uart8250,mmio,0xff5e0000,115200n8". - and it will switch to normal serial console when the corresponding - port is ready. - "earlycon=uart8250,io,0x3f8,9600n8" - "earlycon=uart8250,mmio,0xff5e0000,115200n8". - it will not only setup early console. - - If unsure, say N. - -config FIX_EARLYCON_MEM - bool - depends on X86 - default y - -config SERIAL_8250_GSC - tristate - depends on SERIAL_8250 && GSC - default SERIAL_8250 - -config SERIAL_8250_PCI - tristate "8250/16550 PCI device support" if EMBEDDED - depends on SERIAL_8250 && PCI - default SERIAL_8250 - help - This builds standard PCI serial support. You may be able to - disable this feature if you only need legacy serial support. - Saves about 9K. - -config SERIAL_8250_PNP - tristate "8250/16550 PNP device support" if EMBEDDED - depends on SERIAL_8250 && PNP - default SERIAL_8250 - help - This builds standard PNP serial support. You may be able to - disable this feature if you only need legacy serial support. - -config SERIAL_8250_HP300 - tristate - depends on SERIAL_8250 && HP300 - default SERIAL_8250 - -config SERIAL_8250_CS - tristate "8250/16550 PCMCIA device support" - depends on PCMCIA && SERIAL_8250 - ---help--- - Say Y here to enable support for 16-bit PCMCIA serial devices, - including serial port cards, modems, and the modem functions of - multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are - credit-card size devices often used with laptops.) - - To compile this driver as a module, choose M here: the - module will be called serial_cs. - - If unsure, say N. - -config SERIAL_8250_NR_UARTS - int "Maximum number of 8250/16550 serial ports" - depends on SERIAL_8250 - default "4" - help - Set this to the number of serial ports you want the driver - to support. This includes any ports discovered via ACPI or - PCI enumeration and any ports that may be added at run-time - via hot-plug, or any ISA multi-port serial cards. - -config SERIAL_8250_RUNTIME_UARTS - int "Number of 8250/16550 serial ports to register at runtime" - depends on SERIAL_8250 - range 0 SERIAL_8250_NR_UARTS - default "4" - help - Set this to the maximum number of serial ports you want - the kernel to register at boot time. This can be overridden - with the module parameter "nr_uarts", or boot-time parameter - 8250.nr_uarts - -config SERIAL_8250_EXTENDED - bool "Extended 8250/16550 serial driver options" - depends on SERIAL_8250 - help - If you wish to use any non-standard features of the standard "dumb" - driver, say Y here. This includes HUB6 support, shared serial - interrupts, special multiport support, support for more than the - four COM 1/2/3/4 boards, etc. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about serial driver options. If unsure, say N. - -config SERIAL_8250_MANY_PORTS - bool "Support more than 4 legacy serial ports" - depends on SERIAL_8250_EXTENDED && !IA64 - help - Say Y here if you have dumb serial boards other than the four - standard COM 1/2/3/4 ports. This may happen if you have an AST - FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available - from ), or other custom - serial port hardware which acts similar to standard serial port - hardware. If you only use the standard COM 1/2/3/4 ports, you can - say N here to save some memory. You can also say Y if you have an - "intelligent" multiport card such as Cyclades, Digiboards, etc. - -# -# Multi-port serial cards -# - -config SERIAL_8250_FOURPORT - tristate "Support Fourport cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have an AST FourPort serial board. - - To compile this driver as a module, choose M here: the module - will be called 8250_fourport. - -config SERIAL_8250_ACCENT - tristate "Support Accent cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have an Accent Async serial board. - - To compile this driver as a module, choose M here: the module - will be called 8250_accent. - -config SERIAL_8250_BOCA - tristate "Support Boca cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have a Boca serial board. Please read the Boca - mini-HOWTO, available from - - To compile this driver as a module, choose M here: the module - will be called 8250_boca. - -config SERIAL_8250_EXAR_ST16C554 - tristate "Support Exar ST16C554/554D Quad UART" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - The Uplogix Envoy TU301 uses this Exar Quad UART. If you are - tinkering with your Envoy TU301, or have a machine with this UART, - say Y here. - - To compile this driver as a module, choose M here: the module - will be called 8250_exar_st16c554. - -config SERIAL_8250_HUB6 - tristate "Support Hub6 cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have a HUB6 serial board. - - To compile this driver as a module, choose M here: the module - will be called 8250_hub6. - -config SERIAL_8250_SHARE_IRQ - bool "Support for sharing serial interrupts" - depends on SERIAL_8250_EXTENDED - help - Some serial boards have hardware support which allows multiple dumb - serial ports on the same board to share a single IRQ. To enable - support for this in the serial driver, say Y here. - -config SERIAL_8250_DETECT_IRQ - bool "Autodetect IRQ on standard ports (unsafe)" - depends on SERIAL_8250_EXTENDED - help - Say Y here if you want the kernel to try to guess which IRQ - to use for your serial port. - - This is considered unsafe; it is far better to configure the IRQ in - a boot script using the setserial command. - - If unsure, say N. - -config SERIAL_8250_RSA - bool "Support RSA serial ports" - depends on SERIAL_8250_EXTENDED - help - ::: To be written ::: - -config SERIAL_8250_MCA - tristate "Support 8250-type ports on MCA buses" - depends on SERIAL_8250 != n && MCA - help - Say Y here if you have a MCA serial ports. - - To compile this driver as a module, choose M here: the module - will be called 8250_mca. - -config SERIAL_8250_ACORN - tristate "Acorn expansion card serial port support" - depends on ARCH_ACORN && SERIAL_8250 - help - If you have an Atomwide Serial card or Serial Port card for an Acorn - system, say Y to this option. The driver can handle 1, 2, or 3 port - cards. If unsure, say N. - -config SERIAL_8250_RM9K - bool "Support for MIPS RM9xxx integrated serial port" - depends on SERIAL_8250 != n && SERIAL_RM9000 - select SERIAL_8250_SHARE_IRQ - help - Selecting this option will add support for the integrated serial - port hardware found on MIPS RM9122 and similar processors. - If unsure, say N. - -comment "Non-8250 serial port support" - -config SERIAL_AMBA_PL010 - tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) - select SERIAL_CORE - help - This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have - an Integrator/AP or Integrator/PP2 platform, or if you have a - Cirrus Logic EP93xx CPU, say Y or M here. - - If unsure, say N. - -config SERIAL_AMBA_PL010_CONSOLE - bool "Support for console on AMBA serial port" - depends on SERIAL_AMBA_PL010=y - select SERIAL_CORE_CONSOLE - ---help--- - Say Y here if you wish to use an AMBA PrimeCell UART as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyAM0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_AMBA_PL011 - tristate "ARM AMBA PL011 serial port support" - depends on ARM_AMBA - select SERIAL_CORE - help - This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have - an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M - here. - - If unsure, say N. - -config SERIAL_AMBA_PL011_CONSOLE - bool "Support for console on AMBA serial port" - depends on SERIAL_AMBA_PL011=y - select SERIAL_CORE_CONSOLE - ---help--- - Say Y here if you wish to use an AMBA PrimeCell UART as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyAMA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_SB1250_DUART - tristate "BCM1xxx on-chip DUART serial support" - depends on SIBYTE_SB1xxx_SOC=y - select SERIAL_CORE - default y - ---help--- - Support for the asynchronous serial interface (DUART) included in - the BCM1250 and derived System-On-a-Chip (SOC) devices. Note that - the letter D in DUART stands for "dual", which is how the device - is implemented. Depending on the SOC configuration there may be - one or more DUARTs available of which all are handled. - - If unsure, say Y. To compile this driver as a module, choose M here: - the module will be called sb1250-duart. - -config SERIAL_SB1250_DUART_CONSOLE - bool "Support for console on a BCM1xxx DUART serial port" - depends on SERIAL_SB1250_DUART=y - select SERIAL_CORE_CONSOLE - default y - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). - - If unsure, say Y. - -config SERIAL_ATMEL - bool "AT91 / AT32 on-chip serial port support" - depends on (ARM && ARCH_AT91) || AVR32 - select SERIAL_CORE - help - This enables the driver for the on-chip UARTs of the Atmel - AT91 and AT32 processors. - -config SERIAL_ATMEL_CONSOLE - bool "Support for console on AT91 / AT32 serial port" - depends on SERIAL_ATMEL=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use an on-chip UART on a Atmel - AT91 or AT32 processor as the system console (the system - console is the device which receives all kernel messages and - warnings and which allows logins in single user mode). - -config SERIAL_ATMEL_PDC - bool "Support DMA transfers on AT91 / AT32 serial port" - depends on SERIAL_ATMEL - default y - help - Say Y here if you wish to use the PDC to do DMA transfers to - and from the Atmel AT91 / AT32 serial port. In order to - actually use DMA transfers, make sure that the use_dma_tx - and use_dma_rx members in the atmel_uart_data struct is set - appropriately for each port. - - Note that break and error handling currently doesn't work - properly when DMA is enabled. Make sure that ports where - this matters don't use DMA. - -config SERIAL_ATMEL_TTYAT - bool "Install as device ttyATn instead of ttySn" - depends on SERIAL_ATMEL=y - help - Say Y here if you wish to have the internal AT91 / AT32 UARTs - appear as /dev/ttyATn (major 204, minor starting at 154) - instead of the normal /dev/ttySn (major 4, minor starting at - 64). This is necessary if you also want other UARTs, such as - external 8250/16C550 compatible UARTs. - The ttySn nodes are legally reserved for the 8250 serial driver - but are often misused by other serial drivers. - - To use this, you should create suitable ttyATn device nodes in - /dev/, and pass "console=ttyATn" to the kernel. - - Say Y if you have an external 8250/16C550 UART. If unsure, say N. - -config SERIAL_KS8695 - bool "Micrel KS8695 (Centaur) serial port support" - depends on ARCH_KS8695 - select SERIAL_CORE - help - This selects the Micrel Centaur KS8695 UART. Say Y here. - -config SERIAL_KS8695_CONSOLE - bool "Support for console on KS8695 (Centaur) serial port" - depends on SERIAL_KS8695=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use a KS8695 (Centaur) UART as the - system console (the system console is the device which - receives all kernel messages and warnings and which allows - logins in single user mode). - -config SERIAL_CLPS711X - tristate "CLPS711X serial port support" - depends on ARM && ARCH_CLPS711X - select SERIAL_CORE - help - ::: To be written ::: - -config SERIAL_CLPS711X_CONSOLE - bool "Support for console on CLPS711X serial port" - depends on SERIAL_CLPS711X=y - select SERIAL_CORE_CONSOLE - help - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyCL1". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_SAMSUNG - tristate "Samsung SoC serial support" - depends on ARM && PLAT_SAMSUNG - select SERIAL_CORE - help - Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, - providing /dev/ttySAC0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured. - -config SERIAL_SAMSUNG_UARTS_4 - bool - depends on ARM && PLAT_SAMSUNG - default y if CPU_S3C2443 - help - Internal node for the common case of 4 Samsung compatible UARTs - -config SERIAL_SAMSUNG_UARTS - int - depends on ARM && PLAT_SAMSUNG - default 2 if ARCH_S3C2400 - default 6 if ARCH_S5P6450 - default 4 if SERIAL_SAMSUNG_UARTS_4 - default 3 - help - Select the number of available UART ports for the Samsung S3C - serial driver - -config SERIAL_SAMSUNG_DEBUG - bool "Samsung SoC serial debug" - depends on SERIAL_SAMSUNG && DEBUG_LL - help - Add support for debugging the serial driver. Since this is - generally being used as a console, we use our own output - routines that go via the low-level debug printascii() - function. - -config SERIAL_SAMSUNG_CONSOLE - bool "Support for console on Samsung SoC serial port" - depends on SERIAL_SAMSUNG=y - select SERIAL_CORE_CONSOLE - help - Allow selection of the S3C24XX on-board serial ports for use as - an virtual console. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySACx". (Try "man bootparam" or see the documentation of - your boot loader about how to pass options to the kernel at - boot time.) - -config SERIAL_S3C2400 - tristate "Samsung S3C2410 Serial port support" - depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400 - default y if CPU_S3C2400 - help - Serial port support for the Samsung S3C2400 SoC - -config SERIAL_S3C2410 - tristate "Samsung S3C2410 Serial port support" - depends on SERIAL_SAMSUNG && CPU_S3C2410 - default y if CPU_S3C2410 - help - Serial port support for the Samsung S3C2410 SoC - -config SERIAL_S3C2412 - tristate "Samsung S3C2412/S3C2413 Serial port support" - depends on SERIAL_SAMSUNG && CPU_S3C2412 - default y if CPU_S3C2412 - help - Serial port support for the Samsung S3C2412 and S3C2413 SoC - -config SERIAL_S3C2440 - tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support" - depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416) - default y if CPU_S3C2440 - default y if CPU_S3C2442 - select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416 - help - Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC - -config SERIAL_S3C24A0 - tristate "Samsung S3C24A0 Serial port support" - depends on SERIAL_SAMSUNG && CPU_S3C24A0 - default y if CPU_S3C24A0 - help - Serial port support for the Samsung S3C24A0 SoC - -config SERIAL_S3C6400 - tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support" - depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100) - select SERIAL_SAMSUNG_UARTS_4 - default y - help - Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450 - and S5PC100 SoCs - -config SERIAL_S5PV210 - tristate "Samsung S5PV210 Serial port support" - depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310) - select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310) - default y - help - Serial port support for Samsung's S5P Family of SoC's - - -config SERIAL_MAX3100 - tristate "MAX3100 support" - depends on SPI - select SERIAL_CORE - help - MAX3100 chip support - -config SERIAL_MAX3107 - tristate "MAX3107 support" - depends on SPI - select SERIAL_CORE - help - MAX3107 chip support - -config SERIAL_MAX3107_AAVA - tristate "MAX3107 AAVA platform support" - depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB - select SERIAL_CORE - help - Support for the MAX3107 chip configuration found on the AAVA - platform. Includes the extra initialisation and GPIO support - neded for this device. - -config SERIAL_DZ - bool "DECstation DZ serial driver" - depends on MACH_DECSTATION && 32BIT - select SERIAL_CORE - default y - ---help--- - DZ11-family serial controllers for DECstations and VAXstations, - including the DC7085, M7814, and M7819. - -config SERIAL_DZ_CONSOLE - bool "Support console on DECstation DZ serial driver" - depends on SERIAL_DZ=y - select SERIAL_CORE_CONSOLE - default y - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). - - Note that the firmware uses ttyS3 as the serial console on - DECstations that use this driver. - - If unsure, say Y. - -config SERIAL_ZS - tristate "DECstation Z85C30 serial support" - depends on MACH_DECSTATION - select SERIAL_CORE - default y - ---help--- - Support for the Zilog 85C350 serial communications controller used - for serial ports in newer DECstation systems. These include the - DECsystem 5900 and all models of the DECstation and DECsystem 5000 - systems except from model 200. - - If unsure, say Y. To compile this driver as a module, choose M here: - the module will be called zs. - -config SERIAL_ZS_CONSOLE - bool "Support for console on a DECstation Z85C30 serial port" - depends on SERIAL_ZS=y - select SERIAL_CORE_CONSOLE - default y - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). - - Note that the firmware uses ttyS1 as the serial console on the - Maxine and ttyS3 on the others using this driver. - - If unsure, say Y. - -config SERIAL_21285 - tristate "DC21285 serial port support" - depends on ARM && FOOTBRIDGE - select SERIAL_CORE - help - If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ - PCI bridge you can enable its onboard serial port by enabling this - option. - -config SERIAL_21285_CONSOLE - bool "Console on DC21285 serial port" - depends on SERIAL_21285=y - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the 21285 footbridge you can - make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyFB". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_MPSC - bool "Marvell MPSC serial port support" - depends on PPC32 && MV64X60 - select SERIAL_CORE - help - Say Y here if you want to use the Marvell MPSC serial controller. - -config SERIAL_MPSC_CONSOLE - bool "Support for console on Marvell MPSC serial port" - depends on SERIAL_MPSC - select SERIAL_CORE_CONSOLE - help - Say Y here if you want to support a serial console on a Marvell MPSC. - -config SERIAL_PXA - bool "PXA serial port support" - depends on ARCH_PXA || ARCH_MMP - select SERIAL_CORE - help - If you have a machine based on an Intel XScale PXA2xx CPU you - can enable its onboard serial ports by enabling this option. - -config SERIAL_PXA_CONSOLE - bool "Console on PXA serial port" - depends on SERIAL_PXA - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the Intel XScale PXA - CPU you can make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_SA1100 - bool "SA1100 serial port support" - depends on ARM && ARCH_SA1100 - select SERIAL_CORE - help - If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you - can enable its onboard serial port by enabling this option. - Please read for further - info. - -config SERIAL_SA1100_CONSOLE - bool "Console on SA1100 serial port" - depends on SERIAL_SA1100 - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the SA1100/SA1110 StrongARM - CPU you can make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_MRST_MAX3110 - tristate "SPI UART driver for Max3110" - depends on SPI_DW_PCI - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - help - This is the UART protocol driver for the MAX3110 device on - the Intel Moorestown platform. On other systems use the max3100 - driver. - -config SERIAL_MFD_HSU - tristate "Medfield High Speed UART support" - depends on PCI - select SERIAL_CORE - -config SERIAL_MFD_HSU_CONSOLE - boolean "Medfile HSU serial console support" - depends on SERIAL_MFD_HSU=y - select SERIAL_CORE_CONSOLE - -config SERIAL_BFIN - tristate "Blackfin serial port support" - depends on BLACKFIN - select SERIAL_CORE - select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561) - help - Add support for the built-in UARTs on the Blackfin. - - To compile this driver as a module, choose M here: the - module will be called bfin_5xx. - -config SERIAL_BFIN_CONSOLE - bool "Console on Blackfin serial port" - depends on SERIAL_BFIN=y - select SERIAL_CORE_CONSOLE - -choice - prompt "UART Mode" - depends on SERIAL_BFIN - default SERIAL_BFIN_DMA - help - This driver supports the built-in serial ports of the Blackfin family - of CPUs - -config SERIAL_BFIN_DMA - bool "DMA mode" - depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n - help - This driver works under DMA mode. If this option is selected, the - blackfin simple dma driver is also enabled. - -config SERIAL_BFIN_PIO - bool "PIO mode" - help - This driver works under PIO mode. - -endchoice - -config SERIAL_BFIN_UART0 - bool "Enable UART0" - depends on SERIAL_BFIN - help - Enable UART0 - -config BFIN_UART0_CTSRTS - bool "Enable UART0 hardware flow control" - depends on SERIAL_BFIN_UART0 - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_UART1 - bool "Enable UART1" - depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561) - help - Enable UART1 - -config BFIN_UART1_CTSRTS - bool "Enable UART1 hardware flow control" - depends on SERIAL_BFIN_UART1 - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_UART2 - bool "Enable UART2" - depends on SERIAL_BFIN && (BF54x || BF538 || BF539) - help - Enable UART2 - -config BFIN_UART2_CTSRTS - bool "Enable UART2 hardware flow control" - depends on SERIAL_BFIN_UART2 - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_UART3 - bool "Enable UART3" - depends on SERIAL_BFIN && (BF54x) - help - Enable UART3 - -config BFIN_UART3_CTSRTS - bool "Enable UART3 hardware flow control" - depends on SERIAL_BFIN_UART3 - help - Enable hardware flow control in the driver. - -config SERIAL_IMX - bool "IMX serial port support" - depends on ARM && (ARCH_IMX || ARCH_MXC) - select SERIAL_CORE - select RATIONAL - help - If you have a machine based on a Motorola IMX CPU you - can enable its onboard serial port by enabling this option. - -config SERIAL_IMX_CONSOLE - bool "Console on IMX serial port" - depends on SERIAL_IMX - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the Motorola IMX - CPU you can make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_UARTLITE - tristate "Xilinx uartlite serial port support" - depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE - select SERIAL_CORE - help - Say Y here if you want to use the Xilinx uartlite serial controller. - - To compile this driver as a module, choose M here: the - module will be called uartlite. - -config SERIAL_UARTLITE_CONSOLE - bool "Support for console on Xilinx uartlite serial port" - depends on SERIAL_UARTLITE=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use a Xilinx uartlite as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - -config SERIAL_SUNCORE - bool - depends on SPARC - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - default y - -config SERIAL_SUNZILOG - tristate "Sun Zilog8530 serial support" - depends on SPARC - help - This driver supports the Zilog8530 serial ports found on many Sparc - systems. Say Y or M if you want to be able to these serial ports. - -config SERIAL_SUNZILOG_CONSOLE - bool "Console on Sun Zilog8530 serial port" - depends on SERIAL_SUNZILOG=y - help - If you would like to be able to use the Zilog8530 serial port - on your Sparc system as the console, you can do so by answering - Y to this option. - -config SERIAL_SUNSU - tristate "Sun SU serial support" - depends on SPARC && PCI - help - This driver supports the 8250 serial ports that run the keyboard and - mouse on (PCI) UltraSPARC systems. Say Y or M if you want to be able - to these serial ports. - -config SERIAL_SUNSU_CONSOLE - bool "Console on Sun SU serial port" - depends on SERIAL_SUNSU=y - help - If you would like to be able to use the SU serial port - on your Sparc system as the console, you can do so by answering - Y to this option. - -config SERIAL_MUX - tristate "Serial MUX support" - depends on GSC - select SERIAL_CORE - default y - ---help--- - Saying Y here will enable the hardware MUX serial driver for - the Nova, K class systems and D class with a 'remote control card'. - The hardware MUX is not 8250/16550 compatible therefore the - /dev/ttyB0 device is shared between the Serial MUX and the PDC - software console. The following steps need to be completed to use - the Serial MUX: - - 1. create the device entry (mknod /dev/ttyB0 c 11 0) - 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 - 3. Add device ttyB0 to /etc/securetty (if you want to log on as - root on this console.) - 4. Change the kernel command console parameter to: console=ttyB0 - -config SERIAL_MUX_CONSOLE - bool "Support for console on serial MUX" - depends on SERIAL_MUX=y - select SERIAL_CORE_CONSOLE - default y - -config PDC_CONSOLE - bool "PDC software console support" - depends on PARISC && !SERIAL_MUX && VT - default n - help - Saying Y here will enable the software based PDC console to be - used as the system console. This is useful for machines in - which the hardware based console has not been written yet. The - following steps must be competed to use the PDC console: - - 1. create the device entry (mknod /dev/ttyB0 c 11 0) - 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 - 3. Add device ttyB0 to /etc/securetty (if you want to log on as - root on this console.) - 4. Change the kernel command console parameter to: console=ttyB0 - -config SERIAL_SUNSAB - tristate "Sun Siemens SAB82532 serial support" - depends on SPARC && PCI - help - This driver supports the Siemens SAB82532 DUSCC serial ports on newer - (PCI) UltraSPARC systems. Say Y or M if you want to be able to these - serial ports. - -config SERIAL_SUNSAB_CONSOLE - bool "Console on Sun Siemens SAB82532 serial port" - depends on SERIAL_SUNSAB=y - help - If you would like to be able to use the SAB82532 serial port - on your Sparc system as the console, you can do so by answering - Y to this option. - -config SERIAL_SUNHV - bool "Sun4v Hypervisor Console support" - depends on SPARC64 - help - This driver supports the console device found on SUN4V Sparc - systems. Say Y if you want to be able to use this device. - -config SERIAL_IP22_ZILOG - tristate "SGI Zilog8530 serial support" - depends on SGI_HAS_ZILOG - select SERIAL_CORE - help - This driver supports the Zilog8530 serial ports found on SGI - systems. Say Y or M if you want to be able to these serial ports. - -config SERIAL_IP22_ZILOG_CONSOLE - bool "Console on SGI Zilog8530 serial port" - depends on SERIAL_IP22_ZILOG=y - select SERIAL_CORE_CONSOLE - -config SERIAL_SH_SCI - tristate "SuperH SCI(F) serial port support" - depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE) - select SERIAL_CORE - -config SERIAL_SH_SCI_NR_UARTS - int "Maximum number of SCI(F) serial ports" - depends on SERIAL_SH_SCI - default "2" - -config SERIAL_SH_SCI_CONSOLE - bool "Support for console on SuperH SCI(F)" - depends on SERIAL_SH_SCI=y - select SERIAL_CORE_CONSOLE - -config SERIAL_SH_SCI_DMA - bool "DMA support" - depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL - -config SERIAL_PNX8XXX - bool "Enable PNX8XXX SoCs' UART Support" - depends on MIPS && (SOC_PNX8550 || SOC_PNX833X) - select SERIAL_CORE - help - If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 - and you want to use serial ports, say Y. Otherwise, say N. - -config SERIAL_PNX8XXX_CONSOLE - bool "Enable PNX8XX0 serial console" - depends on SERIAL_PNX8XXX - select SERIAL_CORE_CONSOLE - help - 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_CORE - tristate - -config SERIAL_CORE_CONSOLE - bool - -config CONSOLE_POLL - bool - -config SERIAL_68328 - bool "68328 serial support" - depends on M68328 || M68EZ328 || M68VZ328 - help - This driver supports the built-in serial port of the Motorola 68328 - (standard, EZ and VZ varieties). - -config SERIAL_68328_RTS_CTS - bool "Support RTS/CTS on 68328 serial port" - depends on SERIAL_68328 - -config SERIAL_MCF - bool "Coldfire serial support" - depends on COLDFIRE - select SERIAL_CORE - help - This serial driver supports the Freescale Coldfire serial ports. - -config SERIAL_MCF_BAUDRATE - int "Default baudrate for Coldfire serial ports" - depends on SERIAL_MCF - default 19200 - help - This setting lets you define what the default baudrate is for the - ColdFire serial ports. The usual default varies from board to board, - and this setting is a way of catering for that. - -config SERIAL_MCF_CONSOLE - bool "Coldfire serial console support" - depends on SERIAL_MCF - select SERIAL_CORE_CONSOLE - help - Enable a ColdFire internal serial port to be the system console. - -config SERIAL_68360_SMC - bool "68360 SMC uart support" - depends on M68360 - help - This driver supports the SMC serial ports of the Motorola 68360 CPU. - -config SERIAL_68360_SCC - bool "68360 SCC uart support" - depends on M68360 - help - This driver supports the SCC serial ports of the Motorola 68360 CPU. - -config SERIAL_68360 - bool - depends on SERIAL_68360_SMC || SERIAL_68360_SCC - default y - -config SERIAL_PMACZILOG - tristate "Mac or PowerMac z85c30 ESCC support" - depends on (M68K && MAC) || (PPC_OF && PPC_PMAC) - select SERIAL_CORE - help - This driver supports the Zilog z85C30 serial ports found on - (Power)Mac machines. - Say Y or M if you want to be able to these serial ports. - -config SERIAL_PMACZILOG_TTYS - bool "Use ttySn device nodes for Zilog z85c30" - depends on SERIAL_PMACZILOG - help - The pmac_zilog driver for the z85C30 chip on many powermacs - historically used the device numbers for /dev/ttySn. The - 8250 serial port driver also uses these numbers, which means - the two drivers being unable to coexist; you could not use - both z85C30 and 8250 type ports at the same time. - - If this option is not selected, the pmac_zilog driver will - use the device numbers allocated for /dev/ttyPZn. This allows - the pmac_zilog and 8250 drivers to co-exist, but may cause - existing userspace setups to break. Programs that need to - access the built-in serial ports on powermacs will need to - be reconfigured to use /dev/ttyPZn instead of /dev/ttySn. - - If you enable this option, any z85c30 ports in the system will - be registered as ttyS0 onwards as in the past, and you will be - unable to use the 8250 module for PCMCIA or other 16C550-style - UARTs. - - Say N unless you need the z85c30 ports on your (Power)Mac - to appear as /dev/ttySn. - -config SERIAL_PMACZILOG_CONSOLE - bool "Console on Mac or PowerMac z85c30 serial port" - depends on SERIAL_PMACZILOG=y - select SERIAL_CORE_CONSOLE - help - If you would like to be able to use the z85c30 serial port - on your (Power)Mac as the console, you can do so by answering - Y to this option. - -config SERIAL_LH7A40X - tristate "Sharp LH7A40X embedded UART support" - depends on ARM && ARCH_LH7A40X - select SERIAL_CORE - help - This enables support for the three on-board UARTs of the - Sharp LH7A40X series CPUs. Choose Y or M. - -config SERIAL_LH7A40X_CONSOLE - bool "Support for console on Sharp LH7A40X serial port" - depends on SERIAL_LH7A40X=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use one of the serial ports as the - system console--the system console is the device which - receives all kernel messages and warnings and which allows - logins in single user mode. - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the default system console, but - you can alter that using a kernel command line, for example - "console=ttyAM1". - -config SERIAL_CPM - tristate "CPM SCC/SMC serial port support" - depends on CPM2 || 8xx - select SERIAL_CORE - help - This driver supports the SCC and SMC serial ports on Motorola - embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx) - -config SERIAL_CPM_CONSOLE - bool "Support for console on CPM SCC/SMC serial port" - depends on SERIAL_CPM=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use a SCC or SMC CPM UART as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyCPM0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_SGI_L1_CONSOLE - bool "SGI Altix L1 serial console support" - depends on IA64_GENERIC || IA64_SGI_SN2 - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - help - If you have an SGI Altix and you would like to use the system - controller serial port as your console (you want this!), - say Y. Otherwise, say N. - -config SERIAL_MPC52xx - tristate "Freescale MPC52xx/MPC512x family PSC serial support" - depends on PPC_MPC52xx || PPC_MPC512x - select SERIAL_CORE - help - This driver supports MPC52xx and MPC512x PSC serial ports. If you would - like to use them, you must answer Y or M to this option. Note that - for use as console, it must be included in kernel and not as a - module. - -config SERIAL_MPC52xx_CONSOLE - bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port" - depends on SERIAL_MPC52xx=y - select SERIAL_CORE_CONSOLE - help - Select this options if you'd like to use one of the PSC serial port - of the Freescale MPC52xx family as a console. - -config SERIAL_MPC52xx_CONSOLE_BAUD - int "Freescale MPC52xx/MPC512x family PSC serial port baud" - depends on SERIAL_MPC52xx_CONSOLE=y - default "9600" - help - Select the MPC52xx console baud rate. - This value is only used if the bootloader doesn't pass in the - console baudrate - -config SERIAL_ICOM - tristate "IBM Multiport Serial Adapter" - depends on PCI && (PPC_ISERIES || PPC_PSERIES) - select SERIAL_CORE - select FW_LOADER - help - This driver is for a family of multiport serial adapters - including 2 port RVX, 2 port internal modem, 4 port internal - modem and a split 1 port RVX and 1 port internal modem. - - This driver can also be built as a module. If so, the module - will be called icom. - -config SERIAL_M32R_SIO - bool "M32R SIO I/F" - depends on M32R - default y - select SERIAL_CORE - help - Say Y here if you want to use the M32R serial controller. - -config SERIAL_M32R_SIO_CONSOLE - bool "use SIO console" - depends on SERIAL_M32R_SIO=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you want to support a serial console. - - If you use an M3T-M32700UT or an OPSPUT platform, - please say also y for SERIAL_M32R_PLDSIO. - -config SERIAL_M32R_PLDSIO - bool "M32R SIO I/F on a PLD" - depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT) - default n - help - Say Y here if you want to use the M32R serial controller - on a PLD (Programmable Logic Device). - - If you use an M3T-M32700UT or an OPSPUT platform, - please say Y. - -config SERIAL_TXX9 - bool "TMPTX39XX/49XX SIO support" - depends on HAS_TXX9_SERIAL - select SERIAL_CORE - default y - -config HAS_TXX9_SERIAL - bool - -config SERIAL_TXX9_NR_UARTS - int "Maximum number of TMPTX39XX/49XX SIO ports" - depends on SERIAL_TXX9 - default "6" - -config SERIAL_TXX9_CONSOLE - bool "TMPTX39XX/49XX SIO Console support" - depends on SERIAL_TXX9=y - select SERIAL_CORE_CONSOLE - -config SERIAL_TXX9_STDSERIAL - bool "TX39XX/49XX SIO act as standard serial" - depends on !SERIAL_8250 && SERIAL_TXX9 - -config SERIAL_VR41XX - tristate "NEC VR4100 series Serial Interface Unit support" - depends on CPU_VR41XX - select SERIAL_CORE - help - If you have a NEC VR4100 series processor and you want to use - Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU) - (not include VR4111/VR4121 DSIU), say Y. Otherwise, say N. - -config SERIAL_VR41XX_CONSOLE - bool "Enable NEC VR4100 series Serial Interface Unit console" - depends on SERIAL_VR41XX=y - select SERIAL_CORE_CONSOLE - help - If you have a NEC VR4100 series processor and you want to use - a console on a serial port, say Y. Otherwise, say N. - -config SERIAL_JSM - tristate "Digi International NEO PCI Support" - depends on PCI - select SERIAL_CORE - help - This is a driver for Digi International's Neo series - of cards which provide multiple serial ports. You would need - something like this to connect more than two modems to your Linux - box, for instance in order to become a dial-in server. This driver - supports PCI boards only. - - If you have a card like this, say Y here, otherwise say N. - - To compile this driver as a module, choose M here: the - module will be called jsm. - -config SERIAL_SGI_IOC4 - tristate "SGI IOC4 controller serial support" - depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4 - select SERIAL_CORE - help - If you have an SGI Altix with an IOC4 based Base IO card - and wish to use the serial ports on this card, say Y. - Otherwise, say N. - -config SERIAL_SGI_IOC3 - tristate "SGI Altix IOC3 serial support" - depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3 - select SERIAL_CORE - help - If you have an SGI Altix with an IOC3 serial card, - say Y or M. Otherwise, say N. - -config SERIAL_MSM - bool "MSM on-chip serial port support" - depends on ARM && ARCH_MSM - select SERIAL_CORE - -config SERIAL_MSM_CONSOLE - bool "MSM serial console support" - depends on SERIAL_MSM=y - select SERIAL_CORE_CONSOLE - -config SERIAL_VT8500 - bool "VIA VT8500 on-chip serial port support" - depends on ARM && ARCH_VT8500 - select SERIAL_CORE - -config SERIAL_VT8500_CONSOLE - bool "VIA VT8500 serial console support" - depends on SERIAL_VT8500=y - select SERIAL_CORE_CONSOLE - -config SERIAL_NETX - tristate "NetX serial port support" - depends on ARM && ARCH_NETX - select SERIAL_CORE - help - If you have a machine based on a Hilscher NetX SoC you - can enable its onboard serial port by enabling this option. - - To compile this driver as a module, choose M here: the - module will be called netx-serial. - -config SERIAL_NETX_CONSOLE - bool "Console on NetX serial port" - depends on SERIAL_NETX=y - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the Hilscher NetX SoC - you can make it the console by answering Y to this option. - -config SERIAL_OF_PLATFORM - tristate "Serial port on Open Firmware platform bus" - depends on OF - depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL - help - If you have a PowerPC based system that has serial ports - on a platform specific bus, you should enable this option. - Currently, only 8250 compatible ports are supported, but - others can easily be added. - -config SERIAL_OMAP - tristate "OMAP serial port support" - depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 - select SERIAL_CORE - help - If you have a machine based on an Texas Instruments OMAP CPU you - can enable its onboard serial ports by enabling this option. - - By enabling this option you take advantage of dma feature available - with the omap-serial driver. DMA support can be enabled from platform - data. - -config SERIAL_OMAP_CONSOLE - bool "Console on OMAP serial port" - depends on SERIAL_OMAP - select SERIAL_CORE_CONSOLE - help - Select this option if you would like to use omap serial port as - console. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyOx". (Try "man bootparam" or see the documentation of - your boot loader about how to pass options to the kernel at - boot time.) - -config SERIAL_OF_PLATFORM_NWPSERIAL - tristate "NWP serial port driver" - depends on PPC_OF && PPC_DCR - select SERIAL_OF_PLATFORM - select SERIAL_CORE_CONSOLE - select SERIAL_CORE - help - This driver supports the cell network processor nwp serial - device. - -config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE - bool "Console on NWP serial port" - depends on SERIAL_OF_PLATFORM_NWPSERIAL=y - select SERIAL_CORE_CONSOLE - help - Support for Console on the NWP serial ports. - -config SERIAL_QE - tristate "Freescale QUICC Engine serial port support" - depends on QUICC_ENGINE - select SERIAL_CORE - select FW_LOADER - default n - help - This driver supports the QE serial ports on Freescale embedded - PowerPC that contain a QUICC Engine. - -config SERIAL_SC26XX - tristate "SC2681/SC2692 serial port support" - depends on SNI_RM - select SERIAL_CORE - help - This is a driver for the onboard serial ports of - older RM400 machines. - -config SERIAL_SC26XX_CONSOLE - bool "Console on SC2681/SC2692 serial port" - depends on SERIAL_SC26XX - select SERIAL_CORE_CONSOLE - help - Support for Console on SC2681/SC2692 serial ports. - -config SERIAL_BFIN_SPORT - tristate "Blackfin SPORT emulate UART" - depends on BLACKFIN - select SERIAL_CORE - help - Enable SPORT emulate UART on Blackfin series. - - To compile this driver as a module, choose M here: the - module will be called bfin_sport_uart. - -config SERIAL_BFIN_SPORT_CONSOLE - bool "Console on Blackfin sport emulated uart" - depends on SERIAL_BFIN_SPORT=y - select SERIAL_CORE_CONSOLE - -config SERIAL_BFIN_SPORT0_UART - bool "Enable UART over SPORT0" - depends on SERIAL_BFIN_SPORT && !(BF542 || BF544) - help - Enable UART over SPORT0 - -config SERIAL_BFIN_SPORT0_UART_CTSRTS - bool "Enable UART over SPORT0 hardware flow control" - depends on SERIAL_BFIN_SPORT0_UART - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_SPORT1_UART - bool "Enable UART over SPORT1" - depends on SERIAL_BFIN_SPORT - help - Enable UART over SPORT1 - -config SERIAL_BFIN_SPORT1_UART_CTSRTS - bool "Enable UART over SPORT1 hardware flow control" - depends on SERIAL_BFIN_SPORT1_UART - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_SPORT2_UART - bool "Enable UART over SPORT2" - depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) - help - Enable UART over SPORT2 - -config SERIAL_BFIN_SPORT2_UART_CTSRTS - bool "Enable UART over SPORT2 hardware flow control" - depends on SERIAL_BFIN_SPORT2_UART - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_SPORT3_UART - bool "Enable UART over SPORT3" - depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) - help - Enable UART over SPORT3 - -config SERIAL_BFIN_SPORT3_UART_CTSRTS - bool "Enable UART over SPORT3 hardware flow control" - depends on SERIAL_BFIN_SPORT3_UART - help - Enable hardware flow control in the driver. - -config SERIAL_TIMBERDALE - tristate "Support for timberdale UART" - select SERIAL_CORE - ---help--- - Add support for UART controller on timberdale. - -config SERIAL_BCM63XX - tristate "bcm63xx serial port support" - select SERIAL_CORE - depends on BCM63XX - help - If you have a bcm63xx CPU, you can enable its onboard - serial port by enabling this options. - - To compile this driver as a module, choose M here: the - module will be called bcm963xx_uart. - -config SERIAL_BCM63XX_CONSOLE - bool "Console on bcm63xx serial port" - depends on SERIAL_BCM63XX=y - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the bcm63xx CPU - you can make it the console by answering Y to this option. - -config SERIAL_GRLIB_GAISLER_APBUART - tristate "GRLIB APBUART serial support" - depends on OF - ---help--- - Add support for the GRLIB APBUART serial port. - -config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE - bool "Console on GRLIB APBUART serial port" - depends on SERIAL_GRLIB_GAISLER_APBUART=y - select SERIAL_CORE_CONSOLE - help - Support for running a console on the GRLIB APBUART - -config SERIAL_ALTERA_JTAGUART - tristate "Altera JTAG UART support" - select SERIAL_CORE - help - This driver supports the Altera JTAG UART port. - -config SERIAL_ALTERA_JTAGUART_CONSOLE - bool "Altera JTAG UART console support" - depends on SERIAL_ALTERA_JTAGUART=y - select SERIAL_CORE_CONSOLE - help - Enable a Altera JTAG UART port to be the system console. - -config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS - bool "Bypass output when no connection" - depends on SERIAL_ALTERA_JTAGUART_CONSOLE - select SERIAL_CORE_CONSOLE - help - Bypass console output and keep going even if there is no - JTAG terminal connection with the host. - -config SERIAL_ALTERA_UART - tristate "Altera UART support" - select SERIAL_CORE - help - This driver supports the Altera softcore UART port. - -config SERIAL_ALTERA_UART_MAXPORTS - int "Maximum number of Altera UART ports" - depends on SERIAL_ALTERA_UART - default 4 - help - This setting lets you define the maximum number of the Altera - UART ports. The usual default varies from board to board, and - this setting is a way of catering for that. - -config SERIAL_ALTERA_UART_BAUDRATE - int "Default baudrate for Altera UART ports" - depends on SERIAL_ALTERA_UART - default 115200 - help - This setting lets you define what the default baudrate is for the - Altera UART ports. The usual default varies from board to board, - and this setting is a way of catering for that. - -config SERIAL_ALTERA_UART_CONSOLE - bool "Altera UART console support" - depends on SERIAL_ALTERA_UART=y - select SERIAL_CORE_CONSOLE - help - Enable a Altera UART port to be the system console. - -config SERIAL_IFX6X60 - tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB && SPI && EXPERIMENTAL - help - Support for the IFX6x60 modem devices on Intel MID platforms. - -config SERIAL_PCH_UART - tristate "Intel EG20T PCH UART" - depends on PCI && DMADEVICES - select SERIAL_CORE - select PCH_DMA - help - This driver is for PCH(Platform controller Hub) UART of Intel EG20T - which is an IOH(Input/Output Hub) for x86 embedded processor. - Enabling PCH_DMA, this PCH UART works as DMA mode. -endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile deleted file mode 100644 index 8ea92e9c73b0..000000000000 --- a/drivers/serial/Makefile +++ /dev/null @@ -1,94 +0,0 @@ -# -# Makefile for the kernel serial device drivers. -# - -obj-$(CONFIG_SERIAL_CORE) += serial_core.o -obj-$(CONFIG_SERIAL_21285) += 21285.o - -# These Sparc drivers have to appear before others such as 8250 -# which share ttySx minor node space. Otherwise console device -# names change and other unplesantries. -obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o -obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o -obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o -obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o -obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o - -obj-$(CONFIG_SERIAL_8250) += 8250.o -obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o -obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o -obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o -obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o -obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o -obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o -obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o -obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o -obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o -obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o -obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o -obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o -obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o -obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o -obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o -obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o -obj-$(CONFIG_SERIAL_PXA) += pxa.o -obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o -obj-$(CONFIG_SERIAL_SA1100) += sa1100.o -obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o -obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o -obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o -obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o -obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o -obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o -obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o -obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o -obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o -obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o -obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o -obj-$(CONFIG_SERIAL_MAX3100) += max3100.o -obj-$(CONFIG_SERIAL_MAX3107) += max3107.o -obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o -obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o -obj-$(CONFIG_SERIAL_MUX) += mux.o -obj-$(CONFIG_SERIAL_68328) += 68328serial.o -obj-$(CONFIG_SERIAL_68360) += 68360serial.o -obj-$(CONFIG_SERIAL_MCF) += mcf.o -obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o -obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o -obj-$(CONFIG_SERIAL_DZ) += dz.o -obj-$(CONFIG_SERIAL_ZS) += zs.o -obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o -obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o -obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ -obj-$(CONFIG_SERIAL_IMX) += imx.o -obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o -obj-$(CONFIG_SERIAL_ICOM) += icom.o -obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o -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_JSM) += jsm/ -obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o -obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o -obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o -obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o -obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o -obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o -obj-$(CONFIG_SERIAL_MSM) += msm_serial.o -obj-$(CONFIG_SERIAL_NETX) += netx-serial.o -obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o -obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o -obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o -obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o -obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o -obj-$(CONFIG_SERIAL_QE) += ucc_uart.o -obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o -obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o -obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o -obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o -obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o -obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o -obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o -obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o diff --git a/drivers/serial/altera_jtaguart.c b/drivers/serial/altera_jtaguart.c deleted file mode 100644 index f9b49b5ff5e1..000000000000 --- a/drivers/serial/altera_jtaguart.c +++ /dev/null @@ -1,504 +0,0 @@ -/* - * altera_jtaguart.c -- Altera JTAG UART driver - * - * Based on mcf.c -- Freescale ColdFire UART driver - * - * (C) Copyright 2003-2007, Greg Ungerer - * (C) Copyright 2008, Thomas Chou - * (C) Copyright 2010, Tobias Klauser - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "altera_jtaguart" - -/* - * Altera JTAG UART register definitions according to the Altera JTAG UART - * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf - */ - -#define ALTERA_JTAGUART_SIZE 8 - -#define ALTERA_JTAGUART_DATA_REG 0 - -#define ALTERA_JTAGUART_DATA_DATA_MSK 0x000000FF -#define ALTERA_JTAGUART_DATA_RVALID_MSK 0x00008000 -#define ALTERA_JTAGUART_DATA_RAVAIL_MSK 0xFFFF0000 -#define ALTERA_JTAGUART_DATA_RAVAIL_OFF 16 - -#define ALTERA_JTAGUART_CONTROL_REG 4 - -#define ALTERA_JTAGUART_CONTROL_RE_MSK 0x00000001 -#define ALTERA_JTAGUART_CONTROL_WE_MSK 0x00000002 -#define ALTERA_JTAGUART_CONTROL_RI_MSK 0x00000100 -#define ALTERA_JTAGUART_CONTROL_RI_OFF 8 -#define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200 -#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400 -#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000 -#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16 - -/* - * Local per-uart structure. - */ -struct altera_jtaguart { - struct uart_port port; - unsigned int sigs; /* Local copy of line sigs */ - unsigned long imr; /* Local IMR mirror */ -}; - -static unsigned int altera_jtaguart_tx_empty(struct uart_port *port) -{ - return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0; -} - -static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port) -{ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; -} - -static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs) -{ -} - -static void altera_jtaguart_start_tx(struct uart_port *port) -{ - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - - pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); -} - -static void altera_jtaguart_stop_tx(struct uart_port *port) -{ - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - - pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); -} - -static void altera_jtaguart_stop_rx(struct uart_port *port) -{ - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - - pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); -} - -static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state) -{ -} - -static void altera_jtaguart_enable_ms(struct uart_port *port) -{ -} - -static void altera_jtaguart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - /* Just copy the old termios settings back */ - if (old) - tty_termios_copy_hw(termios, old); -} - -static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) -{ - struct uart_port *port = &pp->port; - unsigned char ch, flag; - unsigned long status; - - while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) & - ALTERA_JTAGUART_DATA_RVALID_MSK) { - ch = status & ALTERA_JTAGUART_DATA_DATA_MSK; - flag = TTY_NORMAL; - port->icount.rx++; - - if (uart_handle_sysrq_char(port, ch)) - continue; - uart_insert_char(port, 0, 0, ch, flag); - } - - tty_flip_buffer_push(port->state->port.tty); -} - -static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) -{ - struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned int pending, count; - - if (port->x_char) { - /* Send special char - probably flow control */ - writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG); - port->x_char = 0; - port->icount.tx++; - return; - } - - pending = uart_circ_chars_pending(xmit); - if (pending > 0) { - count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >> - ALTERA_JTAGUART_CONTROL_WSPACE_OFF; - if (count > pending) - count = pending; - if (count > 0) { - pending -= count; - while (count--) { - writel(xmit->buf[xmit->tail], - port->membase + ALTERA_JTAGUART_DATA_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if (pending < WAKEUP_CHARS) - uart_write_wakeup(port); - } - } - - if (pending == 0) { - pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); - } -} - -static irqreturn_t altera_jtaguart_interrupt(int irq, void *data) -{ - struct uart_port *port = data; - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - unsigned int isr; - - isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >> - ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr; - - spin_lock(&port->lock); - - if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK) - altera_jtaguart_rx_chars(pp); - if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK) - altera_jtaguart_tx_chars(pp); - - spin_unlock(&port->lock); - - return IRQ_RETVAL(isr); -} - -static void altera_jtaguart_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_ALTERA_JTAGUART; - - /* Clear mask, so no surprise interrupts. */ - writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG); -} - -static int altera_jtaguart_startup(struct uart_port *port) -{ - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - unsigned long flags; - int ret; - - ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED, - DRV_NAME, port); - if (ret) { - pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d " - "interrupt vector=%d\n", port->line, port->irq); - return ret; - } - - spin_lock_irqsave(&port->lock, flags); - - /* Enable RX interrupts now */ - pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); - - spin_unlock_irqrestore(&port->lock, flags); - - return 0; -} - -static void altera_jtaguart_shutdown(struct uart_port *port) -{ - struct altera_jtaguart *pp = - container_of(port, struct altera_jtaguart, port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - /* Disable all interrupts now */ - pp->imr = 0; - writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); - - spin_unlock_irqrestore(&port->lock, flags); - - free_irq(port->irq, port); -} - -static const char *altera_jtaguart_type(struct uart_port *port) -{ - return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL; -} - -static int altera_jtaguart_request_port(struct uart_port *port) -{ - /* UARTs always present */ - return 0; -} - -static void altera_jtaguart_release_port(struct uart_port *port) -{ - /* Nothing to release... */ -} - -static int altera_jtaguart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART) - return -EINVAL; - return 0; -} - -/* - * Define the basic serial functions we support. - */ -static struct uart_ops altera_jtaguart_ops = { - .tx_empty = altera_jtaguart_tx_empty, - .get_mctrl = altera_jtaguart_get_mctrl, - .set_mctrl = altera_jtaguart_set_mctrl, - .start_tx = altera_jtaguart_start_tx, - .stop_tx = altera_jtaguart_stop_tx, - .stop_rx = altera_jtaguart_stop_rx, - .enable_ms = altera_jtaguart_enable_ms, - .break_ctl = altera_jtaguart_break_ctl, - .startup = altera_jtaguart_startup, - .shutdown = altera_jtaguart_shutdown, - .set_termios = altera_jtaguart_set_termios, - .type = altera_jtaguart_type, - .request_port = altera_jtaguart_request_port, - .release_port = altera_jtaguart_release_port, - .config_port = altera_jtaguart_config_port, - .verify_port = altera_jtaguart_verify_port, -}; - -#define ALTERA_JTAGUART_MAXPORTS 1 -static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; - -#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) - -int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart - *platp) -{ - struct uart_port *port; - int i; - - for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) { - port = &altera_jtaguart_ports[i].port; - - port->line = i; - port->type = PORT_ALTERA_JTAGUART; - port->mapbase = platp[i].mapbase; - port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->flags = ASYNC_BOOT_AUTOCONF; - port->ops = &altera_jtaguart_ops; - } - - return 0; -} - -#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) -static void altera_jtaguart_console_putc(struct console *co, const char c) -{ - struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; - unsigned long status; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { - if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) { - spin_unlock_irqrestore(&port->lock, flags); - return; /* no connection activity */ - } - spin_unlock_irqrestore(&port->lock, flags); - cpu_relax(); - spin_lock_irqsave(&port->lock, flags); - } - writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); - spin_unlock_irqrestore(&port->lock, flags); -} -#else -static void altera_jtaguart_console_putc(struct console *co, const char c) -{ - struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & - ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { - spin_unlock_irqrestore(&port->lock, flags); - cpu_relax(); - spin_lock_irqsave(&port->lock, flags); - } - writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); - spin_unlock_irqrestore(&port->lock, flags); -} -#endif - -static void altera_jtaguart_console_write(struct console *co, const char *s, - unsigned int count) -{ - for (; count; count--, s++) { - altera_jtaguart_console_putc(co, *s); - if (*s == '\n') - altera_jtaguart_console_putc(co, '\r'); - } -} - -static int __init altera_jtaguart_console_setup(struct console *co, - char *options) -{ - struct uart_port *port; - - if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS) - return -EINVAL; - port = &altera_jtaguart_ports[co->index].port; - if (port->membase == 0) - return -ENODEV; - return 0; -} - -static struct uart_driver altera_jtaguart_driver; - -static struct console altera_jtaguart_console = { - .name = "ttyJ", - .write = altera_jtaguart_console_write, - .device = uart_console_device, - .setup = altera_jtaguart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &altera_jtaguart_driver, -}; - -static int __init altera_jtaguart_console_init(void) -{ - register_console(&altera_jtaguart_console); - return 0; -} - -console_initcall(altera_jtaguart_console_init); - -#define ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console) - -#else - -#define ALTERA_JTAGUART_CONSOLE NULL - -#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */ - -static struct uart_driver altera_jtaguart_driver = { - .owner = THIS_MODULE, - .driver_name = "altera_jtaguart", - .dev_name = "ttyJ", - .major = ALTERA_JTAGUART_MAJOR, - .minor = ALTERA_JTAGUART_MINOR, - .nr = ALTERA_JTAGUART_MAXPORTS, - .cons = ALTERA_JTAGUART_CONSOLE, -}; - -static int __devinit altera_jtaguart_probe(struct platform_device *pdev) -{ - struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data; - struct uart_port *port; - int i; - - for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) { - port = &altera_jtaguart_ports[i].port; - - port->line = i; - port->type = PORT_ALTERA_JTAGUART; - port->mapbase = platp[i].mapbase; - port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->ops = &altera_jtaguart_ops; - port->flags = ASYNC_BOOT_AUTOCONF; - - uart_add_one_port(&altera_jtaguart_driver, port); - } - - return 0; -} - -static int __devexit altera_jtaguart_remove(struct platform_device *pdev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) { - port = &altera_jtaguart_ports[i].port; - if (port) - uart_remove_one_port(&altera_jtaguart_driver, port); - } - - return 0; -} - -static struct platform_driver altera_jtaguart_platform_driver = { - .probe = altera_jtaguart_probe, - .remove = __devexit_p(altera_jtaguart_remove), - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init altera_jtaguart_init(void) -{ - int rc; - - rc = uart_register_driver(&altera_jtaguart_driver); - if (rc) - return rc; - rc = platform_driver_register(&altera_jtaguart_platform_driver); - if (rc) { - uart_unregister_driver(&altera_jtaguart_driver); - return rc; - } - return 0; -} - -static void __exit altera_jtaguart_exit(void) -{ - platform_driver_unregister(&altera_jtaguart_platform_driver); - uart_unregister_driver(&altera_jtaguart_driver); -} - -module_init(altera_jtaguart_init); -module_exit(altera_jtaguart_exit); - -MODULE_DESCRIPTION("Altera JTAG UART driver"); -MODULE_AUTHOR("Thomas Chou "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c deleted file mode 100644 index 721216292a50..000000000000 --- a/drivers/serial/altera_uart.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * altera_uart.c -- Altera UART driver - * - * Based on mcf.c -- Freescale ColdFire UART driver - * - * (C) Copyright 2003-2007, Greg Ungerer - * (C) Copyright 2008, Thomas Chou - * (C) Copyright 2010, Tobias Klauser - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "altera_uart" -#define SERIAL_ALTERA_MAJOR 204 -#define SERIAL_ALTERA_MINOR 213 - -/* - * Altera UART register definitions according to the Nios UART datasheet: - * http://www.altera.com/literature/ds/ds_nios_uart.pdf - */ - -#define ALTERA_UART_SIZE 32 - -#define ALTERA_UART_RXDATA_REG 0 -#define ALTERA_UART_TXDATA_REG 4 -#define ALTERA_UART_STATUS_REG 8 -#define ALTERA_UART_CONTROL_REG 12 -#define ALTERA_UART_DIVISOR_REG 16 -#define ALTERA_UART_EOP_REG 20 - -#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */ -#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */ -#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */ -#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */ -#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */ -#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */ -#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */ -#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */ -#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */ -#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */ -#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */ -#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */ - - /* Enable interrupt on... */ -#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */ -#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */ -#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */ -#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */ -#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */ -#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */ -#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */ -#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */ -#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/ - -#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */ -#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */ -#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */ -#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */ - -/* - * Local per-uart structure. - */ -struct altera_uart { - struct uart_port port; - struct timer_list tmr; - unsigned int sigs; /* Local copy of line sigs */ - unsigned short imr; /* Local IMR mirror */ -}; - -static u32 altera_uart_readl(struct uart_port *port, int reg) -{ - struct altera_uart_platform_uart *platp = port->private_data; - - return readl(port->membase + (reg << platp->bus_shift)); -} - -static void altera_uart_writel(struct uart_port *port, u32 dat, int reg) -{ - struct altera_uart_platform_uart *platp = port->private_data; - - writel(dat, port->membase + (reg << platp->bus_shift)); -} - -static unsigned int altera_uart_tx_empty(struct uart_port *port) -{ - return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0; -} - -static unsigned int altera_uart_get_mctrl(struct uart_port *port) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned int sigs; - - sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; - sigs |= (pp->sigs & TIOCM_RTS); - - return sigs; -} - -static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - - pp->sigs = sigs; - if (sigs & TIOCM_RTS) - pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; - else - pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); -} - -static void altera_uart_start_tx(struct uart_port *port) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - - pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); -} - -static void altera_uart_stop_tx(struct uart_port *port) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - - pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); -} - -static void altera_uart_stop_rx(struct uart_port *port) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - - pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); -} - -static void altera_uart_break_ctl(struct uart_port *port, int break_state) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; - else - pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void altera_uart_enable_ms(struct uart_port *port) -{ -} - -static void altera_uart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int baud, baudclk; - - baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - baudclk = port->uartclk / baud; - - if (old) - tty_termios_copy_hw(termios, old); - tty_termios_encode_baud_rate(termios, baud, baud); - - spin_lock_irqsave(&port->lock, flags); - uart_update_timeout(port, termios->c_cflag, baud); - altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void altera_uart_rx_chars(struct altera_uart *pp) -{ - struct uart_port *port = &pp->port; - unsigned char ch, flag; - unsigned short status; - - while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) & - ALTERA_UART_STATUS_RRDY_MSK) { - ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG); - flag = TTY_NORMAL; - port->icount.rx++; - - if (status & ALTERA_UART_STATUS_E_MSK) { - altera_uart_writel(port, status, - ALTERA_UART_STATUS_REG); - - if (status & ALTERA_UART_STATUS_BRK_MSK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (status & ALTERA_UART_STATUS_PE_MSK) { - port->icount.parity++; - } else if (status & ALTERA_UART_STATUS_ROE_MSK) { - port->icount.overrun++; - } else if (status & ALTERA_UART_STATUS_FE_MSK) { - port->icount.frame++; - } - - status &= port->read_status_mask; - - if (status & ALTERA_UART_STATUS_BRK_MSK) - flag = TTY_BREAK; - else if (status & ALTERA_UART_STATUS_PE_MSK) - flag = TTY_PARITY; - else if (status & ALTERA_UART_STATUS_FE_MSK) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - continue; - uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch, - flag); - } - - tty_flip_buffer_push(port->state->port.tty); -} - -static void altera_uart_tx_chars(struct altera_uart *pp) -{ - struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - /* Send special char - probably flow control */ - altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG); - port->x_char = 0; - port->icount.tx++; - return; - } - - while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK) { - if (xmit->head == xmit->tail) - break; - altera_uart_writel(port, xmit->buf[xmit->tail], - ALTERA_UART_TXDATA_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (xmit->head == xmit->tail) { - pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); - } -} - -static irqreturn_t altera_uart_interrupt(int irq, void *data) -{ - struct uart_port *port = data; - struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned int isr; - - isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr; - - spin_lock(&port->lock); - if (isr & ALTERA_UART_STATUS_RRDY_MSK) - altera_uart_rx_chars(pp); - if (isr & ALTERA_UART_STATUS_TRDY_MSK) - altera_uart_tx_chars(pp); - spin_unlock(&port->lock); - - return IRQ_RETVAL(isr); -} - -static void altera_uart_timer(unsigned long data) -{ - struct uart_port *port = (void *)data; - struct altera_uart *pp = container_of(port, struct altera_uart, port); - - altera_uart_interrupt(0, port); - mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); -} - -static void altera_uart_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_ALTERA_UART; - - /* Clear mask, so no surprise interrupts. */ - altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG); - /* Clear status register */ - altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG); -} - -static int altera_uart_startup(struct uart_port *port) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - int ret; - - if (!port->irq) { - setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port); - mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); - return 0; - } - - ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED, - DRV_NAME, port); - if (ret) { - pr_err(DRV_NAME ": unable to attach Altera UART %d " - "interrupt vector=%d\n", port->line, port->irq); - return ret; - } - - spin_lock_irqsave(&port->lock, flags); - - /* Enable RX interrupts now */ - pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - - spin_unlock_irqrestore(&port->lock, flags); - - return 0; -} - -static void altera_uart_shutdown(struct uart_port *port) -{ - struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - /* Disable all interrupts now */ - pp->imr = 0; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - - spin_unlock_irqrestore(&port->lock, flags); - - if (port->irq) - free_irq(port->irq, port); - else - del_timer_sync(&pp->tmr); -} - -static const char *altera_uart_type(struct uart_port *port) -{ - return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL; -} - -static int altera_uart_request_port(struct uart_port *port) -{ - /* UARTs always present */ - return 0; -} - -static void altera_uart_release_port(struct uart_port *port) -{ - /* Nothing to release... */ -} - -static int altera_uart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART)) - return -EINVAL; - return 0; -} - -/* - * Define the basic serial functions we support. - */ -static struct uart_ops altera_uart_ops = { - .tx_empty = altera_uart_tx_empty, - .get_mctrl = altera_uart_get_mctrl, - .set_mctrl = altera_uart_set_mctrl, - .start_tx = altera_uart_start_tx, - .stop_tx = altera_uart_stop_tx, - .stop_rx = altera_uart_stop_rx, - .enable_ms = altera_uart_enable_ms, - .break_ctl = altera_uart_break_ctl, - .startup = altera_uart_startup, - .shutdown = altera_uart_shutdown, - .set_termios = altera_uart_set_termios, - .type = altera_uart_type, - .request_port = altera_uart_request_port, - .release_port = altera_uart_release_port, - .config_port = altera_uart_config_port, - .verify_port = altera_uart_verify_port, -}; - -static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; - -#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) - -int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) -{ - struct uart_port *port; - int i; - - for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) { - port = &altera_uart_ports[i].port; - - port->line = i; - port->type = PORT_ALTERA_UART; - port->mapbase = platp[i].mapbase; - port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = platp[i].uartclk; - port->flags = UPF_BOOT_AUTOCONF; - port->ops = &altera_uart_ops; - port->private_data = platp; - } - - return 0; -} - -static void altera_uart_console_putc(struct uart_port *port, const char c) -{ - while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK)) - cpu_relax(); - - writel(c, port->membase + ALTERA_UART_TXDATA_REG); -} - -static void altera_uart_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_port *port = &(altera_uart_ports + co->index)->port; - - for (; count; count--, s++) { - altera_uart_console_putc(port, *s); - if (*s == '\n') - altera_uart_console_putc(port, '\r'); - } -} - -static int __init altera_uart_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS) - return -EINVAL; - port = &altera_uart_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 altera_uart_driver; - -static struct console altera_uart_console = { - .name = "ttyAL", - .write = altera_uart_console_write, - .device = uart_console_device, - .setup = altera_uart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &altera_uart_driver, -}; - -static int __init altera_uart_console_init(void) -{ - register_console(&altera_uart_console); - return 0; -} - -console_initcall(altera_uart_console_init); - -#define ALTERA_UART_CONSOLE (&altera_uart_console) - -#else - -#define ALTERA_UART_CONSOLE NULL - -#endif /* CONFIG_ALTERA_UART_CONSOLE */ - -/* - * Define the altera_uart UART driver structure. - */ -static struct uart_driver altera_uart_driver = { - .owner = THIS_MODULE, - .driver_name = DRV_NAME, - .dev_name = "ttyAL", - .major = SERIAL_ALTERA_MAJOR, - .minor = SERIAL_ALTERA_MINOR, - .nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS, - .cons = ALTERA_UART_CONSOLE, -}; - -static int __devinit altera_uart_probe(struct platform_device *pdev) -{ - struct altera_uart_platform_uart *platp = pdev->dev.platform_data; - struct uart_port *port; - struct resource *res_mem; - struct resource *res_irq; - int i = pdev->id; - - /* -1 emphasizes that the platform must have one port, no .N suffix */ - if (i == -1) - i = 0; - - if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS) - return -EINVAL; - - port = &altera_uart_ports[i].port; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem) - port->mapbase = res_mem->start; - else if (platp->mapbase) - port->mapbase = platp->mapbase; - else - return -EINVAL; - - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res_irq) - port->irq = res_irq->start; - else if (platp->irq) - port->irq = platp->irq; - - port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); - if (!port->membase) - return -ENOMEM; - - port->line = i; - port->type = PORT_ALTERA_UART; - port->iotype = SERIAL_IO_MEM; - port->uartclk = platp->uartclk; - port->ops = &altera_uart_ops; - port->flags = UPF_BOOT_AUTOCONF; - port->private_data = platp; - - uart_add_one_port(&altera_uart_driver, port); - - return 0; -} - -static int __devexit altera_uart_remove(struct platform_device *pdev) -{ - struct uart_port *port = &altera_uart_ports[pdev->id].port; - - uart_remove_one_port(&altera_uart_driver, port); - return 0; -} - -static struct platform_driver altera_uart_platform_driver = { - .probe = altera_uart_probe, - .remove = __devexit_p(altera_uart_remove), - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .pm = NULL, - }, -}; - -static int __init altera_uart_init(void) -{ - int rc; - - rc = uart_register_driver(&altera_uart_driver); - if (rc) - return rc; - rc = platform_driver_register(&altera_uart_platform_driver); - if (rc) { - uart_unregister_driver(&altera_uart_driver); - return rc; - } - return 0; -} - -static void __exit altera_uart_exit(void) -{ - platform_driver_unregister(&altera_uart_platform_driver); - uart_unregister_driver(&altera_uart_driver); -} - -module_init(altera_uart_init); -module_exit(altera_uart_exit); - -MODULE_DESCRIPTION("Altera UART driver"); -MODULE_AUTHOR("Thomas Chou "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR); diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c deleted file mode 100644 index 2904aa044126..000000000000 --- a/drivers/serial/amba-pl010.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - * linux/drivers/char/amba.c - * - * Driver for AMBA serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * 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 - * - * This is a generic driver for ARM AMBA-type serial ports. They - * have a lot of 16550-like features, but are not register compatible. - * Note that although they do have CTS, DCD and DSR inputs, they do - * not have an RI input, nor do they have DTR or RTS outputs. If - * required, these have to be supplied via some other means (eg, GPIO) - * and hooked into this driver. - */ - -#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define UART_NR 8 - -#define SERIAL_AMBA_MAJOR 204 -#define SERIAL_AMBA_MINOR 16 -#define SERIAL_AMBA_NR UART_NR - -#define AMBA_ISR_PASS_LIMIT 256 - -#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) -#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) - -#define UART_DUMMY_RSR_RX 256 -#define UART_PORT_SIZE 64 - -/* - * We wrap our port structure around the generic uart_port. - */ -struct uart_amba_port { - struct uart_port port; - struct clk *clk; - struct amba_device *dev; - struct amba_pl010_data *data; - unsigned int old_status; -}; - -static void pl010_stop_tx(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; - - cr = readb(uap->port.membase + UART010_CR); - cr &= ~UART010_CR_TIE; - writel(cr, uap->port.membase + UART010_CR); -} - -static void pl010_start_tx(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; - - cr = readb(uap->port.membase + UART010_CR); - cr |= UART010_CR_TIE; - writel(cr, uap->port.membase + UART010_CR); -} - -static void pl010_stop_rx(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; - - cr = readb(uap->port.membase + UART010_CR); - cr &= ~(UART010_CR_RIE | UART010_CR_RTIE); - writel(cr, uap->port.membase + UART010_CR); -} - -static void pl010_enable_ms(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; - - cr = readb(uap->port.membase + UART010_CR); - cr |= UART010_CR_MSIE; - writel(cr, uap->port.membase + UART010_CR); -} - -static void pl010_rx_chars(struct uart_amba_port *uap) -{ - struct tty_struct *tty = uap->port.state->port.tty; - unsigned int status, ch, flag, rsr, max_count = 256; - - status = readb(uap->port.membase + UART01x_FR); - while (UART_RX_DATA(status) && max_count--) { - ch = readb(uap->port.membase + UART01x_DR); - flag = TTY_NORMAL; - - uap->port.icount.rx++; - - /* - * Note that the error handling code is - * out of the main execution path - */ - rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; - if (unlikely(rsr & UART01x_RSR_ANY)) { - writel(0, uap->port.membase + UART01x_ECR); - - if (rsr & UART01x_RSR_BE) { - rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); - uap->port.icount.brk++; - if (uart_handle_break(&uap->port)) - goto ignore_char; - } else if (rsr & UART01x_RSR_PE) - uap->port.icount.parity++; - else if (rsr & UART01x_RSR_FE) - uap->port.icount.frame++; - if (rsr & UART01x_RSR_OE) - uap->port.icount.overrun++; - - rsr &= uap->port.read_status_mask; - - if (rsr & UART01x_RSR_BE) - flag = TTY_BREAK; - else if (rsr & UART01x_RSR_PE) - flag = TTY_PARITY; - else if (rsr & UART01x_RSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&uap->port, ch)) - goto ignore_char; - - uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); - - ignore_char: - status = readb(uap->port.membase + UART01x_FR); - } - spin_unlock(&uap->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&uap->port.lock); -} - -static void pl010_tx_chars(struct uart_amba_port *uap) -{ - struct circ_buf *xmit = &uap->port.state->xmit; - int count; - - if (uap->port.x_char) { - writel(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { - pl010_stop_tx(&uap->port); - return; - } - - count = uap->port.fifosize >> 1; - do { - writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); - - if (uart_circ_empty(xmit)) - pl010_stop_tx(&uap->port); -} - -static void pl010_modem_status(struct uart_amba_port *uap) -{ - unsigned int status, delta; - - writel(0, uap->port.membase + UART010_ICR); - - status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; - - delta = status ^ uap->old_status; - uap->old_status = status; - - if (!delta) - return; - - if (delta & UART01x_FR_DCD) - uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); - - if (delta & UART01x_FR_DSR) - uap->port.icount.dsr++; - - if (delta & UART01x_FR_CTS) - uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); - - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); -} - -static irqreturn_t pl010_int(int irq, void *dev_id) -{ - struct uart_amba_port *uap = dev_id; - unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; - int handled = 0; - - spin_lock(&uap->port.lock); - - status = readb(uap->port.membase + UART010_IIR); - if (status) { - do { - if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) - pl010_rx_chars(uap); - if (status & UART010_IIR_MIS) - pl010_modem_status(uap); - if (status & UART010_IIR_TIS) - pl010_tx_chars(uap); - - if (pass_counter-- == 0) - break; - - status = readb(uap->port.membase + UART010_IIR); - } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS | - UART010_IIR_TIS)); - handled = 1; - } - - spin_unlock(&uap->port.lock); - - return IRQ_RETVAL(handled); -} - -static unsigned int pl010_tx_empty(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int status = readb(uap->port.membase + UART01x_FR); - return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; -} - -static unsigned int pl010_get_mctrl(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int result = 0; - unsigned int status; - - status = readb(uap->port.membase + UART01x_FR); - if (status & UART01x_FR_DCD) - result |= TIOCM_CAR; - if (status & UART01x_FR_DSR) - result |= TIOCM_DSR; - if (status & UART01x_FR_CTS) - result |= TIOCM_CTS; - - return result; -} - -static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - if (uap->data) - uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl); -} - -static void pl010_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned long flags; - unsigned int lcr_h; - - spin_lock_irqsave(&uap->port.lock, flags); - lcr_h = readb(uap->port.membase + UART010_LCRH); - if (break_state == -1) - lcr_h |= UART01x_LCRH_BRK; - else - lcr_h &= ~UART01x_LCRH_BRK; - writel(lcr_h, uap->port.membase + UART010_LCRH); - spin_unlock_irqrestore(&uap->port.lock, flags); -} - -static int pl010_startup(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - int retval; - - /* - * Try to enable the clock producer. - */ - retval = clk_enable(uap->clk); - if (retval) - goto out; - - uap->port.uartclk = clk_get_rate(uap->clk); - - /* - * Allocate the IRQ - */ - retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap); - if (retval) - goto clk_dis; - - /* - * initialise the old status of the modem signals - */ - uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; - - /* - * Finally, enable interrupts - */ - writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE, - uap->port.membase + UART010_CR); - - return 0; - - clk_dis: - clk_disable(uap->clk); - out: - return retval; -} - -static void pl010_shutdown(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - /* - * Free the interrupt - */ - free_irq(uap->port.irq, uap); - - /* - * disable all interrupts, disable the port - */ - writel(0, uap->port.membase + UART010_CR); - - /* disable break condition and fifos */ - writel(readb(uap->port.membase + UART010_LCRH) & - ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), - uap->port.membase + UART010_LCRH); - - /* - * Shut down the clock producer - */ - clk_disable(uap->clk); -} - -static void -pl010_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int lcr_h, old_cr; - unsigned long flags; - unsigned int baud, quot; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); - quot = uart_get_divisor(port, baud); - - switch (termios->c_cflag & CSIZE) { - case CS5: - lcr_h = UART01x_LCRH_WLEN_5; - break; - case CS6: - lcr_h = UART01x_LCRH_WLEN_6; - break; - case CS7: - lcr_h = UART01x_LCRH_WLEN_7; - break; - default: // CS8 - lcr_h = UART01x_LCRH_WLEN_8; - break; - } - if (termios->c_cflag & CSTOPB) - lcr_h |= UART01x_LCRH_STP2; - if (termios->c_cflag & PARENB) { - lcr_h |= UART01x_LCRH_PEN; - if (!(termios->c_cflag & PARODD)) - lcr_h |= UART01x_LCRH_EPS; - } - if (uap->port.fifosize > 1) - lcr_h |= UART01x_LCRH_FEN; - - spin_lock_irqsave(&uap->port.lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - uap->port.read_status_mask = UART01x_RSR_OE; - if (termios->c_iflag & INPCK) - uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - uap->port.read_status_mask |= UART01x_RSR_BE; - - /* - * Characters to ignore - */ - uap->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; - if (termios->c_iflag & IGNBRK) { - uap->port.ignore_status_mask |= UART01x_RSR_BE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - uap->port.ignore_status_mask |= UART01x_RSR_OE; - } - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX; - - /* first, disable everything */ - old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE; - - if (UART_ENABLE_MS(port, termios->c_cflag)) - old_cr |= UART010_CR_MSIE; - - writel(0, uap->port.membase + UART010_CR); - - /* Set baud rate */ - quot -= 1; - writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM); - writel(quot & 0xff, uap->port.membase + UART010_LCRL); - - /* - * ----------v----------v----------v----------v----- - * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L - * ----------^----------^----------^----------^----- - */ - writel(lcr_h, uap->port.membase + UART010_LCRH); - writel(old_cr, uap->port.membase + UART010_CR); - - spin_unlock_irqrestore(&uap->port.lock, flags); -} - -static void pl010_set_ldisc(struct uart_port *port, int new) -{ - if (new == N_PPS) { - port->flags |= UPF_HARDPPS_CD; - pl010_enable_ms(port); - } else - port->flags &= ~UPF_HARDPPS_CD; -} - -static const char *pl010_type(struct uart_port *port) -{ - return port->type == PORT_AMBA ? "AMBA" : NULL; -} - -/* - * Release the memory region(s) being used by 'port' - */ -static void pl010_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int pl010_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010") - != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void pl010_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_AMBA; - pl010_request_port(port); - } -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops amba_pl010_pops = { - .tx_empty = pl010_tx_empty, - .set_mctrl = pl010_set_mctrl, - .get_mctrl = pl010_get_mctrl, - .stop_tx = pl010_stop_tx, - .start_tx = pl010_start_tx, - .stop_rx = pl010_stop_rx, - .enable_ms = pl010_enable_ms, - .break_ctl = pl010_break_ctl, - .startup = pl010_startup, - .shutdown = pl010_shutdown, - .set_termios = pl010_set_termios, - .set_ldisc = pl010_set_ldisc, - .type = pl010_type, - .release_port = pl010_release_port, - .request_port = pl010_request_port, - .config_port = pl010_config_port, - .verify_port = pl010_verify_port, -}; - -static struct uart_amba_port *amba_ports[UART_NR]; - -#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE - -static void pl010_console_putchar(struct uart_port *port, int ch) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int status; - - do { - status = readb(uap->port.membase + UART01x_FR); - barrier(); - } while (!UART_TX_READY(status)); - writel(ch, uap->port.membase + UART01x_DR); -} - -static void -pl010_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_amba_port *uap = amba_ports[co->index]; - unsigned int status, old_cr; - - clk_enable(uap->clk); - - /* - * First save the CR then disable the interrupts - */ - old_cr = readb(uap->port.membase + UART010_CR); - writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR); - - uart_console_write(&uap->port, s, count, pl010_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the TCR - */ - do { - status = readb(uap->port.membase + UART01x_FR); - barrier(); - } while (status & UART01x_FR_BUSY); - writel(old_cr, uap->port.membase + UART010_CR); - - clk_disable(uap->clk); -} - -static void __init -pl010_console_get_options(struct uart_amba_port *uap, int *baud, - int *parity, int *bits) -{ - if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) { - unsigned int lcr_h, quot; - lcr_h = readb(uap->port.membase + UART010_LCRH); - - *parity = 'n'; - if (lcr_h & UART01x_LCRH_PEN) { - if (lcr_h & UART01x_LCRH_EPS) - *parity = 'e'; - else - *parity = 'o'; - } - - if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) - *bits = 7; - else - *bits = 8; - - quot = readb(uap->port.membase + UART010_LCRL) | - readb(uap->port.membase + UART010_LCRM) << 8; - *baud = uap->port.uartclk / (16 * (quot + 1)); - } -} - -static int __init pl010_console_setup(struct console *co, char *options) -{ - struct uart_amba_port *uap; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= UART_NR) - co->index = 0; - uap = amba_ports[co->index]; - if (!uap) - return -ENODEV; - - uap->port.uartclk = clk_get_rate(uap->clk); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - pl010_console_get_options(uap, &baud, &parity, &bits); - - return uart_set_options(&uap->port, co, baud, parity, bits, flow); -} - -static struct uart_driver amba_reg; -static struct console amba_console = { - .name = "ttyAM", - .write = pl010_console_write, - .device = uart_console_device, - .setup = pl010_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &amba_reg, -}; - -#define AMBA_CONSOLE &amba_console -#else -#define AMBA_CONSOLE NULL -#endif - -static struct uart_driver amba_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyAM", - .dev_name = "ttyAM", - .major = SERIAL_AMBA_MAJOR, - .minor = SERIAL_AMBA_MINOR, - .nr = UART_NR, - .cons = AMBA_CONSOLE, -}; - -static int pl010_probe(struct amba_device *dev, struct amba_id *id) -{ - struct uart_amba_port *uap; - void __iomem *base; - int i, ret; - - for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == NULL) - break; - - if (i == ARRAY_SIZE(amba_ports)) { - ret = -EBUSY; - goto out; - } - - uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); - if (!uap) { - ret = -ENOMEM; - goto out; - } - - base = ioremap(dev->res.start, resource_size(&dev->res)); - if (!base) { - ret = -ENOMEM; - goto free; - } - - uap->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(uap->clk)) { - ret = PTR_ERR(uap->clk); - goto unmap; - } - - uap->port.dev = &dev->dev; - uap->port.mapbase = dev->res.start; - uap->port.membase = base; - uap->port.iotype = UPIO_MEM; - uap->port.irq = dev->irq[0]; - uap->port.fifosize = 16; - uap->port.ops = &amba_pl010_pops; - uap->port.flags = UPF_BOOT_AUTOCONF; - uap->port.line = i; - uap->dev = dev; - uap->data = dev->dev.platform_data; - - amba_ports[i] = uap; - - amba_set_drvdata(dev, uap); - ret = uart_add_one_port(&amba_reg, &uap->port); - if (ret) { - amba_set_drvdata(dev, NULL); - amba_ports[i] = NULL; - clk_put(uap->clk); - unmap: - iounmap(base); - free: - kfree(uap); - } - out: - return ret; -} - -static int pl010_remove(struct amba_device *dev) -{ - struct uart_amba_port *uap = amba_get_drvdata(dev); - int i; - - amba_set_drvdata(dev, NULL); - - uart_remove_one_port(&amba_reg, &uap->port); - - for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == uap) - amba_ports[i] = NULL; - - iounmap(uap->port.membase); - clk_put(uap->clk); - kfree(uap); - return 0; -} - -static int pl010_suspend(struct amba_device *dev, pm_message_t state) -{ - struct uart_amba_port *uap = amba_get_drvdata(dev); - - if (uap) - uart_suspend_port(&amba_reg, &uap->port); - - return 0; -} - -static int pl010_resume(struct amba_device *dev) -{ - struct uart_amba_port *uap = amba_get_drvdata(dev); - - if (uap) - uart_resume_port(&amba_reg, &uap->port); - - return 0; -} - -static struct amba_id pl010_ids[] = { - { - .id = 0x00041010, - .mask = 0x000fffff, - }, - { 0, 0 }, -}; - -static struct amba_driver pl010_driver = { - .drv = { - .name = "uart-pl010", - }, - .id_table = pl010_ids, - .probe = pl010_probe, - .remove = pl010_remove, - .suspend = pl010_suspend, - .resume = pl010_resume, -}; - -static int __init pl010_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: AMBA driver\n"); - - ret = uart_register_driver(&amba_reg); - if (ret == 0) { - ret = amba_driver_register(&pl010_driver); - if (ret) - uart_unregister_driver(&amba_reg); - } - return ret; -} - -static void __exit pl010_exit(void) -{ - amba_driver_unregister(&pl010_driver); - uart_unregister_driver(&amba_reg); -} - -module_init(pl010_init); -module_exit(pl010_exit); - -MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("ARM AMBA serial port driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c deleted file mode 100644 index e76d7d000128..000000000000 --- a/drivers/serial/amba-pl011.c +++ /dev/null @@ -1,1519 +0,0 @@ -/* - * linux/drivers/char/amba.c - * - * Driver for AMBA serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * Copyright (C) 2010 ST-Ericsson SA - * - * 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 - * - * This is a generic driver for ARM AMBA-type serial ports. They - * have a lot of 16550-like features, but are not register compatible. - * Note that although they do have CTS, DCD and DSR inputs, they do - * not have an RI input, nor do they have DTR or RTS outputs. If - * required, these have to be supplied via some other means (eg, GPIO) - * and hooked into this driver. - */ - -#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define UART_NR 14 - -#define SERIAL_AMBA_MAJOR 204 -#define SERIAL_AMBA_MINOR 64 -#define SERIAL_AMBA_NR UART_NR - -#define AMBA_ISR_PASS_LIMIT 256 - -#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) -#define UART_DUMMY_DR_RX (1 << 16) - -/* There is by now at least one vendor with differing details, so handle it */ -struct vendor_data { - unsigned int ifls; - unsigned int fifosize; - unsigned int lcrh_tx; - unsigned int lcrh_rx; - bool oversampling; - bool dma_threshold; -}; - -static struct vendor_data vendor_arm = { - .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .fifosize = 16, - .lcrh_tx = UART011_LCRH, - .lcrh_rx = UART011_LCRH, - .oversampling = false, - .dma_threshold = false, -}; - -static struct vendor_data vendor_st = { - .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, - .fifosize = 64, - .lcrh_tx = ST_UART011_LCRH_TX, - .lcrh_rx = ST_UART011_LCRH_RX, - .oversampling = true, - .dma_threshold = true, -}; - -/* Deals with DMA transactions */ -struct pl011_dmatx_data { - struct dma_chan *chan; - struct scatterlist sg; - char *buf; - bool queued; -}; - -/* - * We wrap our port structure around the generic uart_port. - */ -struct uart_amba_port { - struct uart_port port; - struct clk *clk; - const struct vendor_data *vendor; - unsigned int dmacr; /* dma control reg */ - unsigned int im; /* interrupt mask */ - unsigned int old_status; - unsigned int fifosize; /* vendor-specific */ - unsigned int lcrh_tx; /* vendor-specific */ - unsigned int lcrh_rx; /* vendor-specific */ - bool autorts; - char type[12]; -#ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ - bool using_dma; - struct pl011_dmatx_data dmatx; -#endif -}; - -/* - * All the DMA operation mode stuff goes inside this ifdef. - * This assumes that you have a generic DMA device interface, - * no custom DMA interfaces are supported. - */ -#ifdef CONFIG_DMA_ENGINE - -#define PL011_DMA_BUFFER_SIZE PAGE_SIZE - -static void pl011_dma_probe_initcall(struct uart_amba_port *uap) -{ - /* DMA is the sole user of the platform data right now */ - struct amba_pl011_data *plat = uap->port.dev->platform_data; - struct dma_slave_config tx_conf = { - .dst_addr = uap->port.mapbase + UART01x_DR, - .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .direction = DMA_TO_DEVICE, - .dst_maxburst = uap->fifosize >> 1, - }; - struct dma_chan *chan; - dma_cap_mask_t mask; - - /* We need platform data */ - if (!plat || !plat->dma_filter) { - dev_info(uap->port.dev, "no DMA platform data\n"); - return; - } - - /* Try to acquire a generic DMA engine slave channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); - if (!chan) { - dev_err(uap->port.dev, "no TX DMA channel!\n"); - return; - } - - dmaengine_slave_config(chan, &tx_conf); - uap->dmatx.chan = chan; - - dev_info(uap->port.dev, "DMA channel TX %s\n", - dma_chan_name(uap->dmatx.chan)); -} - -#ifndef MODULE -/* - * Stack up the UARTs and let the above initcall be done at device - * initcall time, because the serial driver is called as an arch - * initcall, and at this time the DMA subsystem is not yet registered. - * At this point the driver will switch over to using DMA where desired. - */ -struct dma_uap { - struct list_head node; - struct uart_amba_port *uap; -}; - -static LIST_HEAD(pl011_dma_uarts); - -static int __init pl011_dma_initcall(void) -{ - struct list_head *node, *tmp; - - list_for_each_safe(node, tmp, &pl011_dma_uarts) { - struct dma_uap *dmau = list_entry(node, struct dma_uap, node); - pl011_dma_probe_initcall(dmau->uap); - list_del(node); - kfree(dmau); - } - return 0; -} - -device_initcall(pl011_dma_initcall); - -static void pl011_dma_probe(struct uart_amba_port *uap) -{ - struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); - if (dmau) { - dmau->uap = uap; - list_add_tail(&dmau->node, &pl011_dma_uarts); - } -} -#else -static void pl011_dma_probe(struct uart_amba_port *uap) -{ - pl011_dma_probe_initcall(uap); -} -#endif - -static void pl011_dma_remove(struct uart_amba_port *uap) -{ - /* TODO: remove the initcall if it has not yet executed */ - if (uap->dmatx.chan) - dma_release_channel(uap->dmatx.chan); -} - - -/* Forward declare this for the refill routine */ -static int pl011_dma_tx_refill(struct uart_amba_port *uap); - -/* - * The current DMA TX buffer has been sent. - * Try to queue up another DMA buffer. - */ -static void pl011_dma_tx_callback(void *data) -{ - struct uart_amba_port *uap = data; - struct pl011_dmatx_data *dmatx = &uap->dmatx; - unsigned long flags; - u16 dmacr; - - spin_lock_irqsave(&uap->port.lock, flags); - if (uap->dmatx.queued) - dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, - DMA_TO_DEVICE); - - dmacr = uap->dmacr; - uap->dmacr = dmacr & ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - - /* - * If TX DMA was disabled, it means that we've stopped the DMA for - * some reason (eg, XOFF received, or we want to send an X-char.) - * - * Note: we need to be careful here of a potential race between DMA - * and the rest of the driver - if the driver disables TX DMA while - * a TX buffer completing, we must update the tx queued status to - * get further refills (hence we check dmacr). - */ - if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || - uart_circ_empty(&uap->port.state->xmit)) { - uap->dmatx.queued = false; - spin_unlock_irqrestore(&uap->port.lock, flags); - return; - } - - if (pl011_dma_tx_refill(uap) <= 0) { - /* - * We didn't queue a DMA buffer for some reason, but we - * have data pending to be sent. Re-enable the TX IRQ. - */ - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - } - spin_unlock_irqrestore(&uap->port.lock, flags); -} - -/* - * Try to refill the TX DMA buffer. - * Locking: called with port lock held and IRQs disabled. - * Returns: - * 1 if we queued up a TX DMA buffer. - * 0 if we didn't want to handle this by DMA - * <0 on error - */ -static int pl011_dma_tx_refill(struct uart_amba_port *uap) -{ - struct pl011_dmatx_data *dmatx = &uap->dmatx; - struct dma_chan *chan = dmatx->chan; - struct dma_device *dma_dev = chan->device; - struct dma_async_tx_descriptor *desc; - struct circ_buf *xmit = &uap->port.state->xmit; - unsigned int count; - - /* - * Try to avoid the overhead involved in using DMA if the - * transaction fits in the first half of the FIFO, by using - * the standard interrupt handling. This ensures that we - * issue a uart_write_wakeup() at the appropriate time. - */ - count = uart_circ_chars_pending(xmit); - if (count < (uap->fifosize >> 1)) { - uap->dmatx.queued = false; - return 0; - } - - /* - * Bodge: don't send the last character by DMA, as this - * will prevent XON from notifying us to restart DMA. - */ - count -= 1; - - /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */ - if (count > PL011_DMA_BUFFER_SIZE) - count = PL011_DMA_BUFFER_SIZE; - - if (xmit->tail < xmit->head) - memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); - else { - size_t first = UART_XMIT_SIZE - xmit->tail; - size_t second = xmit->head; - - memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); - if (second) - memcpy(&dmatx->buf[first], &xmit->buf[0], second); - } - - dmatx->sg.length = count; - - if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { - uap->dmatx.queued = false; - dev_dbg(uap->port.dev, "unable to map TX DMA\n"); - return -EBUSY; - } - - desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); - uap->dmatx.queued = false; - /* - * If DMA cannot be used right now, we complete this - * transaction via IRQ and let the TTY layer retry. - */ - dev_dbg(uap->port.dev, "TX DMA busy\n"); - return -EBUSY; - } - - /* Some data to go along to the callback */ - desc->callback = pl011_dma_tx_callback; - desc->callback_param = uap; - - /* All errors should happen at prepare time */ - dmaengine_submit(desc); - - /* Fire the DMA transaction */ - dma_dev->device_issue_pending(chan); - - uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - uap->dmatx.queued = true; - - /* - * Now we know that DMA will fire, so advance the ring buffer - * with the stuff we just dispatched. - */ - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx += count; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); - - return 1; -} - -/* - * We received a transmit interrupt without a pending X-char but with - * pending characters. - * Locking: called with port lock held and IRQs disabled. - * Returns: - * false if we want to use PIO to transmit - * true if we queued a DMA buffer - */ -static bool pl011_dma_tx_irq(struct uart_amba_port *uap) -{ - if (!uap->using_dma) - return false; - - /* - * If we already have a TX buffer queued, but received a - * TX interrupt, it will be because we've just sent an X-char. - * Ensure the TX DMA is enabled and the TX IRQ is disabled. - */ - if (uap->dmatx.queued) { - uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - return true; - } - - /* - * We don't have a TX buffer queued, so try to queue one. - * If we succesfully queued a buffer, mask the TX IRQ. - */ - if (pl011_dma_tx_refill(uap) > 0) { - uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - return true; - } - return false; -} - -/* - * Stop the DMA transmit (eg, due to received XOFF). - * Locking: called with port lock held and IRQs disabled. - */ -static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) -{ - if (uap->dmatx.queued) { - uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - } -} - -/* - * Try to start a DMA transmit, or in the case of an XON/OFF - * character queued for send, try to get that character out ASAP. - * Locking: called with port lock held and IRQs disabled. - * Returns: - * false if we want the TX IRQ to be enabled - * true if we have a buffer queued - */ -static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) -{ - u16 dmacr; - - if (!uap->using_dma) - return false; - - if (!uap->port.x_char) { - /* no X-char, try to push chars out in DMA mode */ - bool ret = true; - - if (!uap->dmatx.queued) { - if (pl011_dma_tx_refill(uap) > 0) { - uap->im &= ~UART011_TXIM; - ret = true; - } else { - uap->im |= UART011_TXIM; - ret = false; - } - writew(uap->im, uap->port.membase + UART011_IMSC); - } else if (!(uap->dmacr & UART011_TXDMAE)) { - uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, - uap->port.membase + UART011_DMACR); - } - return ret; - } - - /* - * We have an X-char to send. Disable DMA to prevent it loading - * the TX fifo, and then see if we can stuff it into the FIFO. - */ - dmacr = uap->dmacr; - uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - - if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { - /* - * No space in the FIFO, so enable the transmit interrupt - * so we know when there is space. Note that once we've - * loaded the character, we should just re-enable DMA. - */ - return false; - } - - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; - - /* Success - restore the DMA state */ - uap->dmacr = dmacr; - writew(dmacr, uap->port.membase + UART011_DMACR); - - return true; -} - -/* - * Flush the transmit buffer. - * Locking: called with port lock held and IRQs disabled. - */ -static void pl011_dma_flush_buffer(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - if (!uap->using_dma) - return; - - /* Avoid deadlock with the DMA engine callback */ - spin_unlock(&uap->port.lock); - dmaengine_terminate_all(uap->dmatx.chan); - spin_lock(&uap->port.lock); - if (uap->dmatx.queued) { - dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, - DMA_TO_DEVICE); - uap->dmatx.queued = false; - uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - } -} - - -static void pl011_dma_startup(struct uart_amba_port *uap) -{ - if (!uap->dmatx.chan) - return; - - uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); - if (!uap->dmatx.buf) { - dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); - uap->port.fifosize = uap->fifosize; - return; - } - - sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); - - /* The DMA buffer is now the FIFO the TTY subsystem can use */ - uap->port.fifosize = PL011_DMA_BUFFER_SIZE; - uap->using_dma = true; - - /* Turn on DMA error (RX/TX will be enabled on demand) */ - uap->dmacr |= UART011_DMAONERR; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - - /* - * ST Micro variants has some specific dma burst threshold - * compensation. Set this to 16 bytes, so burst will only - * be issued above/below 16 bytes. - */ - if (uap->vendor->dma_threshold) - writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, - uap->port.membase + ST_UART011_DMAWM); -} - -static void pl011_dma_shutdown(struct uart_amba_port *uap) -{ - if (!uap->using_dma) - return; - - /* Disable RX and TX DMA */ - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) - barrier(); - - spin_lock_irq(&uap->port.lock); - uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - spin_unlock_irq(&uap->port.lock); - - /* In theory, this should already be done by pl011_dma_flush_buffer */ - dmaengine_terminate_all(uap->dmatx.chan); - if (uap->dmatx.queued) { - dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, - DMA_TO_DEVICE); - uap->dmatx.queued = false; - } - - kfree(uap->dmatx.buf); - - uap->using_dma = false; -} - -#else -/* Blank functions if the DMA engine is not available */ -static inline void pl011_dma_probe(struct uart_amba_port *uap) -{ -} - -static inline void pl011_dma_remove(struct uart_amba_port *uap) -{ -} - -static inline void pl011_dma_startup(struct uart_amba_port *uap) -{ -} - -static inline void pl011_dma_shutdown(struct uart_amba_port *uap) -{ -} - -static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap) -{ - return false; -} - -static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) -{ -} - -static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) -{ - return false; -} - -#define pl011_dma_flush_buffer NULL -#endif - - -static void pl011_stop_tx(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - pl011_dma_tx_stop(uap); -} - -static void pl011_start_tx(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - if (!pl011_dma_tx_start(uap)) { - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - } -} - -static void pl011_stop_rx(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| - UART011_PEIM|UART011_BEIM|UART011_OEIM); - writew(uap->im, uap->port.membase + UART011_IMSC); -} - -static void pl011_enable_ms(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; - writew(uap->im, uap->port.membase + UART011_IMSC); -} - -static void pl011_rx_chars(struct uart_amba_port *uap) -{ - struct tty_struct *tty = uap->port.state->port.tty; - unsigned int status, ch, flag, max_count = 256; - - status = readw(uap->port.membase + UART01x_FR); - while ((status & UART01x_FR_RXFE) == 0 && max_count--) { - ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX; - flag = TTY_NORMAL; - uap->port.icount.rx++; - - /* - * Note that the error handling code is - * out of the main execution path - */ - if (unlikely(ch & UART_DR_ERROR)) { - if (ch & UART011_DR_BE) { - ch &= ~(UART011_DR_FE | UART011_DR_PE); - uap->port.icount.brk++; - if (uart_handle_break(&uap->port)) - goto ignore_char; - } else if (ch & UART011_DR_PE) - uap->port.icount.parity++; - else if (ch & UART011_DR_FE) - uap->port.icount.frame++; - if (ch & UART011_DR_OE) - uap->port.icount.overrun++; - - ch &= uap->port.read_status_mask; - - if (ch & UART011_DR_BE) - flag = TTY_BREAK; - else if (ch & UART011_DR_PE) - flag = TTY_PARITY; - else if (ch & UART011_DR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&uap->port, ch & 255)) - goto ignore_char; - - uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); - - ignore_char: - status = readw(uap->port.membase + UART01x_FR); - } - spin_unlock(&uap->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&uap->port.lock); -} - -static void pl011_tx_chars(struct uart_amba_port *uap) -{ - struct circ_buf *xmit = &uap->port.state->xmit; - int count; - - if (uap->port.x_char) { - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { - pl011_stop_tx(&uap->port); - return; - } - - /* If we are using DMA mode, try to send some characters. */ - if (pl011_dma_tx_irq(uap)) - return; - - count = uap->fifosize >> 1; - do { - writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); - - if (uart_circ_empty(xmit)) - pl011_stop_tx(&uap->port); -} - -static void pl011_modem_status(struct uart_amba_port *uap) -{ - unsigned int status, delta; - - status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; - - delta = status ^ uap->old_status; - uap->old_status = status; - - if (!delta) - return; - - if (delta & UART01x_FR_DCD) - uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); - - if (delta & UART01x_FR_DSR) - uap->port.icount.dsr++; - - if (delta & UART01x_FR_CTS) - uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); - - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); -} - -static irqreturn_t pl011_int(int irq, void *dev_id) -{ - struct uart_amba_port *uap = dev_id; - unsigned long flags; - unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; - int handled = 0; - - spin_lock_irqsave(&uap->port.lock, flags); - - status = readw(uap->port.membase + UART011_MIS); - if (status) { - do { - writew(status & ~(UART011_TXIS|UART011_RTIS| - UART011_RXIS), - uap->port.membase + UART011_ICR); - - if (status & (UART011_RTIS|UART011_RXIS)) - pl011_rx_chars(uap); - if (status & (UART011_DSRMIS|UART011_DCDMIS| - UART011_CTSMIS|UART011_RIMIS)) - pl011_modem_status(uap); - if (status & UART011_TXIS) - pl011_tx_chars(uap); - - if (pass_counter-- == 0) - break; - - status = readw(uap->port.membase + UART011_MIS); - } while (status != 0); - handled = 1; - } - - spin_unlock_irqrestore(&uap->port.lock, flags); - - return IRQ_RETVAL(handled); -} - -static unsigned int pl01x_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) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int result = 0; - unsigned int status = readw(uap->port.membase + UART01x_FR); - -#define TIOCMBIT(uartbit, tiocmbit) \ - if (status & uartbit) \ - result |= tiocmbit - - TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); - TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); - TIOCMBIT(UART011_FR_RI, TIOCM_RNG); -#undef TIOCMBIT - return result; -} - -static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; - - cr = readw(uap->port.membase + UART011_CR); - -#define TIOCMBIT(tiocmbit, uartbit) \ - if (mctrl & tiocmbit) \ - cr |= uartbit; \ - else \ - cr &= ~uartbit - - TIOCMBIT(TIOCM_RTS, UART011_CR_RTS); - TIOCMBIT(TIOCM_DTR, UART011_CR_DTR); - TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1); - TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2); - TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE); - - if (uap->autorts) { - /* We need to disable auto-RTS if we want to turn RTS off */ - TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN); - } -#undef TIOCMBIT - - writew(cr, uap->port.membase + UART011_CR); -} - -static void pl011_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned long flags; - unsigned int lcr_h; - - spin_lock_irqsave(&uap->port.lock, flags); - lcr_h = readw(uap->port.membase + uap->lcrh_tx); - if (break_state == -1) - lcr_h |= UART01x_LCRH_BRK; - else - lcr_h &= ~UART01x_LCRH_BRK; - writew(lcr_h, uap->port.membase + uap->lcrh_tx); - spin_unlock_irqrestore(&uap->port.lock, flags); -} - -#ifdef CONFIG_CONSOLE_POLL -static int pl010_get_poll_char(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int status; - - status = readw(uap->port.membase + UART01x_FR); - if (status & UART01x_FR_RXFE) - return NO_POLL_CHAR; - - return readw(uap->port.membase + UART01x_DR); -} - -static void pl010_put_poll_char(struct uart_port *port, - unsigned char ch) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) - barrier(); - - writew(ch, uap->port.membase + UART01x_DR); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -static int pl011_startup(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; - int retval; - - /* - * Try to enable the clock producer. - */ - retval = clk_enable(uap->clk); - if (retval) - goto out; - - uap->port.uartclk = clk_get_rate(uap->clk); - - /* - * Allocate the IRQ - */ - retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); - if (retval) - goto clk_dis; - - writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); - - /* - * Provoke TX FIFO interrupt into asserting. - */ - cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; - writew(cr, uap->port.membase + UART011_CR); - writew(0, uap->port.membase + UART011_FBRD); - writew(1, uap->port.membase + UART011_IBRD); - writew(0, uap->port.membase + uap->lcrh_rx); - if (uap->lcrh_tx != uap->lcrh_rx) { - int i; - /* - * Wait 10 PCLKs before writing LCRH_TX register, - * to get this delay write read only register 10 times - */ - for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + UART011_MIS); - writew(0, uap->port.membase + uap->lcrh_tx); - } - writew(0, uap->port.membase + UART01x_DR); - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) - barrier(); - - cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - writew(cr, uap->port.membase + UART011_CR); - - /* Clear pending error interrupts */ - writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, - uap->port.membase + UART011_ICR); - - /* - * initialise the old status of the modem signals - */ - uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; - - /* Startup DMA */ - pl011_dma_startup(uap); - - /* - * Finally, enable interrupts - */ - spin_lock_irq(&uap->port.lock); - uap->im = UART011_RXIM | UART011_RTIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - spin_unlock_irq(&uap->port.lock); - - return 0; - - clk_dis: - clk_disable(uap->clk); - out: - return retval; -} - -static void pl011_shutdown_channel(struct uart_amba_port *uap, - unsigned int lcrh) -{ - unsigned long val; - - val = readw(uap->port.membase + lcrh); - val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); - writew(val, uap->port.membase + lcrh); -} - -static void pl011_shutdown(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - /* - * disable all interrupts - */ - spin_lock_irq(&uap->port.lock); - uap->im = 0; - writew(uap->im, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); - spin_unlock_irq(&uap->port.lock); - - pl011_dma_shutdown(uap); - - /* - * Free the interrupt - */ - free_irq(uap->port.irq, uap); - - /* - * disable the port - */ - uap->autorts = false; - writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR); - - /* - * disable break condition and fifos - */ - pl011_shutdown_channel(uap, uap->lcrh_rx); - if (uap->lcrh_rx != uap->lcrh_tx) - pl011_shutdown_channel(uap, uap->lcrh_tx); - - /* - * Shut down the clock producer - */ - clk_disable(uap->clk); -} - -static void -pl011_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int lcr_h, old_cr; - unsigned long flags; - unsigned int baud, quot, clkdiv; - - if (uap->vendor->oversampling) - clkdiv = 8; - else - clkdiv = 16; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, - port->uartclk / clkdiv); - - if (baud > port->uartclk/16) - quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); - else - quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); - - switch (termios->c_cflag & CSIZE) { - case CS5: - lcr_h = UART01x_LCRH_WLEN_5; - break; - case CS6: - lcr_h = UART01x_LCRH_WLEN_6; - break; - case CS7: - lcr_h = UART01x_LCRH_WLEN_7; - break; - default: // CS8 - lcr_h = UART01x_LCRH_WLEN_8; - break; - } - if (termios->c_cflag & CSTOPB) - lcr_h |= UART01x_LCRH_STP2; - if (termios->c_cflag & PARENB) { - lcr_h |= UART01x_LCRH_PEN; - if (!(termios->c_cflag & PARODD)) - lcr_h |= UART01x_LCRH_EPS; - } - if (uap->fifosize > 1) - lcr_h |= UART01x_LCRH_FEN; - - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART011_DR_OE | 255; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART011_DR_BE; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART011_DR_BE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART011_DR_OE; - } - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_DR_RX; - - if (UART_ENABLE_MS(port, termios->c_cflag)) - pl011_enable_ms(port); - - /* first, disable everything */ - old_cr = readw(port->membase + UART011_CR); - writew(0, port->membase + UART011_CR); - - if (termios->c_cflag & CRTSCTS) { - if (old_cr & UART011_CR_RTS) - old_cr |= UART011_CR_RTSEN; - - old_cr |= UART011_CR_CTSEN; - uap->autorts = true; - } else { - old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN); - uap->autorts = false; - } - - if (uap->vendor->oversampling) { - if (baud > port->uartclk / 16) - old_cr |= ST_UART011_CR_OVSFACT; - else - old_cr &= ~ST_UART011_CR_OVSFACT; - } - - /* Set baud rate */ - writew(quot & 0x3f, port->membase + UART011_FBRD); - writew(quot >> 6, port->membase + UART011_IBRD); - - /* - * ----------v----------v----------v----------v----- - * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L - * ----------^----------^----------^----------^----- - */ - writew(lcr_h, port->membase + uap->lcrh_rx); - if (uap->lcrh_rx != uap->lcrh_tx) { - int i; - /* - * Wait 10 PCLKs before writing LCRH_TX register, - * to get this delay write read only register 10 times - */ - for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + UART011_MIS); - writew(lcr_h, port->membase + uap->lcrh_tx); - } - writew(old_cr, port->membase + UART011_CR); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *pl011_type(struct uart_port *port) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - return uap->port.type == PORT_AMBA ? uap->type : NULL; -} - -/* - * Release the memory region(s) being used by 'port' - */ -static void pl010_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, SZ_4K); -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int pl010_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") - != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void pl010_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_AMBA; - pl010_request_port(port); - } -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops amba_pl011_pops = { - .tx_empty = pl01x_tx_empty, - .set_mctrl = pl011_set_mctrl, - .get_mctrl = pl01x_get_mctrl, - .stop_tx = pl011_stop_tx, - .start_tx = pl011_start_tx, - .stop_rx = pl011_stop_rx, - .enable_ms = pl011_enable_ms, - .break_ctl = pl011_break_ctl, - .startup = pl011_startup, - .shutdown = pl011_shutdown, - .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, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = pl010_get_poll_char, - .poll_put_char = pl010_put_poll_char, -#endif -}; - -static struct uart_amba_port *amba_ports[UART_NR]; - -#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE - -static void pl011_console_putchar(struct uart_port *port, int ch) -{ - struct uart_amba_port *uap = (struct uart_amba_port *)port; - - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) - barrier(); - writew(ch, uap->port.membase + UART01x_DR); -} - -static void -pl011_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_amba_port *uap = amba_ports[co->index]; - unsigned int status, old_cr, new_cr; - - clk_enable(uap->clk); - - /* - * First save the CR then disable the interrupts - */ - old_cr = readw(uap->port.membase + UART011_CR); - new_cr = old_cr & ~UART011_CR_CTSEN; - new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(new_cr, uap->port.membase + UART011_CR); - - uart_console_write(&uap->port, s, count, pl011_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the TCR - */ - do { - status = readw(uap->port.membase + UART01x_FR); - } while (status & UART01x_FR_BUSY); - writew(old_cr, uap->port.membase + UART011_CR); - - clk_disable(uap->clk); -} - -static void __init -pl011_console_get_options(struct uart_amba_port *uap, int *baud, - int *parity, int *bits) -{ - if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { - unsigned int lcr_h, ibrd, fbrd; - - lcr_h = readw(uap->port.membase + uap->lcrh_tx); - - *parity = 'n'; - if (lcr_h & UART01x_LCRH_PEN) { - if (lcr_h & UART01x_LCRH_EPS) - *parity = 'e'; - else - *parity = 'o'; - } - - if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) - *bits = 7; - else - *bits = 8; - - ibrd = readw(uap->port.membase + UART011_IBRD); - fbrd = readw(uap->port.membase + UART011_FBRD); - - *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); - - if (uap->vendor->oversampling) { - if (readw(uap->port.membase + UART011_CR) - & ST_UART011_CR_OVSFACT) - *baud *= 2; - } - } -} - -static int __init pl011_console_setup(struct console *co, char *options) -{ - struct uart_amba_port *uap; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= UART_NR) - co->index = 0; - uap = amba_ports[co->index]; - if (!uap) - return -ENODEV; - - uap->port.uartclk = clk_get_rate(uap->clk); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - pl011_console_get_options(uap, &baud, &parity, &bits); - - return uart_set_options(&uap->port, co, baud, parity, bits, flow); -} - -static struct uart_driver amba_reg; -static struct console amba_console = { - .name = "ttyAMA", - .write = pl011_console_write, - .device = uart_console_device, - .setup = pl011_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &amba_reg, -}; - -#define AMBA_CONSOLE (&amba_console) -#else -#define AMBA_CONSOLE NULL -#endif - -static struct uart_driver amba_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyAMA", - .dev_name = "ttyAMA", - .major = SERIAL_AMBA_MAJOR, - .minor = SERIAL_AMBA_MINOR, - .nr = UART_NR, - .cons = AMBA_CONSOLE, -}; - -static int pl011_probe(struct amba_device *dev, struct amba_id *id) -{ - struct uart_amba_port *uap; - struct vendor_data *vendor = id->data; - void __iomem *base; - int i, ret; - - for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == NULL) - break; - - if (i == ARRAY_SIZE(amba_ports)) { - ret = -EBUSY; - goto out; - } - - uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); - if (uap == NULL) { - ret = -ENOMEM; - goto out; - } - - base = ioremap(dev->res.start, resource_size(&dev->res)); - if (!base) { - ret = -ENOMEM; - goto free; - } - - uap->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(uap->clk)) { - ret = PTR_ERR(uap->clk); - goto unmap; - } - - uap->vendor = vendor; - uap->lcrh_rx = vendor->lcrh_rx; - uap->lcrh_tx = vendor->lcrh_tx; - uap->fifosize = vendor->fifosize; - uap->port.dev = &dev->dev; - uap->port.mapbase = dev->res.start; - uap->port.membase = base; - uap->port.iotype = UPIO_MEM; - uap->port.irq = dev->irq[0]; - uap->port.fifosize = uap->fifosize; - uap->port.ops = &amba_pl011_pops; - uap->port.flags = UPF_BOOT_AUTOCONF; - uap->port.line = i; - pl011_dma_probe(uap); - - snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); - - amba_ports[i] = uap; - - amba_set_drvdata(dev, uap); - ret = uart_add_one_port(&amba_reg, &uap->port); - if (ret) { - amba_set_drvdata(dev, NULL); - amba_ports[i] = NULL; - pl011_dma_remove(uap); - clk_put(uap->clk); - unmap: - iounmap(base); - free: - kfree(uap); - } - out: - return ret; -} - -static int pl011_remove(struct amba_device *dev) -{ - struct uart_amba_port *uap = amba_get_drvdata(dev); - int i; - - amba_set_drvdata(dev, NULL); - - uart_remove_one_port(&amba_reg, &uap->port); - - for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == uap) - amba_ports[i] = NULL; - - pl011_dma_remove(uap); - iounmap(uap->port.membase); - clk_put(uap->clk); - kfree(uap); - return 0; -} - -#ifdef CONFIG_PM -static int pl011_suspend(struct amba_device *dev, pm_message_t state) -{ - struct uart_amba_port *uap = amba_get_drvdata(dev); - - if (!uap) - return -EINVAL; - - return uart_suspend_port(&amba_reg, &uap->port); -} - -static int pl011_resume(struct amba_device *dev) -{ - struct uart_amba_port *uap = amba_get_drvdata(dev); - - if (!uap) - return -EINVAL; - - return uart_resume_port(&amba_reg, &uap->port); -} -#endif - -static struct amba_id pl011_ids[] = { - { - .id = 0x00041011, - .mask = 0x000fffff, - .data = &vendor_arm, - }, - { - .id = 0x00380802, - .mask = 0x00ffffff, - .data = &vendor_st, - }, - { 0, 0 }, -}; - -static struct amba_driver pl011_driver = { - .drv = { - .name = "uart-pl011", - }, - .id_table = pl011_ids, - .probe = pl011_probe, - .remove = pl011_remove, -#ifdef CONFIG_PM - .suspend = pl011_suspend, - .resume = pl011_resume, -#endif -}; - -static int __init pl011_init(void) -{ - int ret; - printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); - - ret = uart_register_driver(&amba_reg); - if (ret == 0) { - ret = amba_driver_register(&pl011_driver); - if (ret) - uart_unregister_driver(&amba_reg); - } - return ret; -} - -static void __exit pl011_exit(void) -{ - amba_driver_unregister(&pl011_driver); - uart_unregister_driver(&amba_reg); -} - -/* - * While this can be a module, if builtin it's most likely the console - * So let's leave module_exit but move module_init to an earlier place - */ -arch_initcall(pl011_init); -module_exit(pl011_exit); - -MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("ARM AMBA serial port driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c deleted file mode 100644 index 095a5d562618..000000000000 --- a/drivers/serial/apbuart.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Driver for GRLIB serial ports (APBUART) - * - * Based on linux/drivers/serial/amba.c - * - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * Copyright (C) 2003 Konrad Eisele - * Copyright (C) 2006 Daniel Hellstrom , Aeroflex Gaisler AB - * Copyright (C) 2008 Gilead Kutnick - * Copyright (C) 2009 Kristoffer Glembo , Aeroflex Gaisler AB - */ - -#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "apbuart.h" - -#define SERIAL_APBUART_MAJOR TTY_MAJOR -#define SERIAL_APBUART_MINOR 64 -#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */ - -static void apbuart_tx_chars(struct uart_port *port); - -static void apbuart_stop_tx(struct uart_port *port) -{ - unsigned int cr; - - cr = UART_GET_CTRL(port); - cr &= ~UART_CTRL_TI; - UART_PUT_CTRL(port, cr); -} - -static void apbuart_start_tx(struct uart_port *port) -{ - unsigned int cr; - - cr = UART_GET_CTRL(port); - cr |= UART_CTRL_TI; - UART_PUT_CTRL(port, cr); - - if (UART_GET_STATUS(port) & UART_STATUS_THE) - apbuart_tx_chars(port); -} - -static void apbuart_stop_rx(struct uart_port *port) -{ - unsigned int cr; - - cr = UART_GET_CTRL(port); - cr &= ~(UART_CTRL_RI); - UART_PUT_CTRL(port, cr); -} - -static void apbuart_enable_ms(struct uart_port *port) -{ - /* No modem status change interrupts for APBUART */ -} - -static void apbuart_rx_chars(struct uart_port *port) -{ - struct tty_struct *tty = port->state->port.tty; - unsigned int status, ch, rsr, flag; - unsigned int max_chars = port->fifosize; - - status = UART_GET_STATUS(port); - - while (UART_RX_DATA(status) && (max_chars--)) { - - ch = UART_GET_CHAR(port); - flag = TTY_NORMAL; - - port->icount.rx++; - - rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX; - UART_PUT_STATUS(port, 0); - if (rsr & UART_STATUS_ERR) { - - if (rsr & UART_STATUS_BR) { - rsr &= ~(UART_STATUS_FE | UART_STATUS_PE); - port->icount.brk++; - if (uart_handle_break(port)) - goto ignore_char; - } else if (rsr & UART_STATUS_PE) { - port->icount.parity++; - } else if (rsr & UART_STATUS_FE) { - port->icount.frame++; - } - if (rsr & UART_STATUS_OE) - port->icount.overrun++; - - rsr &= port->read_status_mask; - - if (rsr & UART_STATUS_PE) - flag = TTY_PARITY; - else if (rsr & UART_STATUS_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag); - - - ignore_char: - status = UART_GET_STATUS(port); - } - - tty_flip_buffer_push(tty); -} - -static void apbuart_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - apbuart_stop_tx(port); - return; - } - - /* amba: fill FIFO */ - count = port->fifosize >> 1; - do { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - apbuart_stop_tx(port); -} - -static irqreturn_t apbuart_int(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned int status; - - spin_lock(&port->lock); - - status = UART_GET_STATUS(port); - if (status & UART_STATUS_DR) - apbuart_rx_chars(port); - if (status & UART_STATUS_THE) - apbuart_tx_chars(port); - - spin_unlock(&port->lock); - - return IRQ_HANDLED; -} - -static unsigned int apbuart_tx_empty(struct uart_port *port) -{ - unsigned int status = UART_GET_STATUS(port); - return status & UART_STATUS_THE ? TIOCSER_TEMT : 0; -} - -static unsigned int apbuart_get_mctrl(struct uart_port *port) -{ - /* The GRLIB APBUART handles flow control in hardware */ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; -} - -static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* The GRLIB APBUART handles flow control in hardware */ -} - -static void apbuart_break_ctl(struct uart_port *port, int break_state) -{ - /* We don't support sending break */ -} - -static int apbuart_startup(struct uart_port *port) -{ - int retval; - unsigned int cr; - - /* Allocate the IRQ */ - retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port); - if (retval) - return retval; - - /* Finally, enable interrupts */ - cr = UART_GET_CTRL(port); - UART_PUT_CTRL(port, - cr | UART_CTRL_RE | UART_CTRL_TE | - UART_CTRL_RI | UART_CTRL_TI); - - return 0; -} - -static void apbuart_shutdown(struct uart_port *port) -{ - unsigned int cr; - - /* disable all interrupts, disable the port */ - cr = UART_GET_CTRL(port); - UART_PUT_CTRL(port, - cr & ~(UART_CTRL_RE | UART_CTRL_TE | - UART_CTRL_RI | UART_CTRL_TI)); - - /* Free the interrupt */ - free_irq(port->irq, port); -} - -static void apbuart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - unsigned int cr; - unsigned long flags; - unsigned int baud, quot; - - /* Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - if (baud == 0) - panic("invalid baudrate %i\n", port->uartclk / 16); - - /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */ - quot = (uart_get_divisor(port, baud)) * 2; - cr = UART_GET_CTRL(port); - cr &= ~(UART_CTRL_PE | UART_CTRL_PS); - - if (termios->c_cflag & PARENB) { - cr |= UART_CTRL_PE; - if ((termios->c_cflag & PARODD)) - cr |= UART_CTRL_PS; - } - - /* Enable flow control. */ - if (termios->c_cflag & CRTSCTS) - cr |= UART_CTRL_FL; - - spin_lock_irqsave(&port->lock, flags); - - /* Update the per-port timeout. */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART_STATUS_OE; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE; - - /* Characters to ignore */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE; - - /* Ignore all characters if CREAD is not set. */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_RSR_RX; - - /* Set baud rate */ - quot -= 1; - UART_PUT_SCAL(port, quot); - UART_PUT_CTRL(port, cr); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *apbuart_type(struct uart_port *port) -{ - return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL; -} - -static void apbuart_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, 0x100); -} - -static int apbuart_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, 0x100, "grlib-apbuart") - != NULL ? 0 : -EBUSY; - return 0; -} - -/* Configure/autoconfigure the port */ -static void apbuart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_APBUART; - apbuart_request_port(port); - } -} - -/* Verify the new serial_struct (for TIOCSSERIAL) */ -static int apbuart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= NR_IRQS) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops grlib_apbuart_ops = { - .tx_empty = apbuart_tx_empty, - .set_mctrl = apbuart_set_mctrl, - .get_mctrl = apbuart_get_mctrl, - .stop_tx = apbuart_stop_tx, - .start_tx = apbuart_start_tx, - .stop_rx = apbuart_stop_rx, - .enable_ms = apbuart_enable_ms, - .break_ctl = apbuart_break_ctl, - .startup = apbuart_startup, - .shutdown = apbuart_shutdown, - .set_termios = apbuart_set_termios, - .type = apbuart_type, - .release_port = apbuart_release_port, - .request_port = apbuart_request_port, - .config_port = apbuart_config_port, - .verify_port = apbuart_verify_port, -}; - -static struct uart_port grlib_apbuart_ports[UART_NR]; -static struct device_node *grlib_apbuart_nodes[UART_NR]; - -static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber) -{ - int ctrl, loop = 0; - int status; - int fifosize; - unsigned long flags; - - ctrl = UART_GET_CTRL(port); - - /* - * Enable the transceiver and wait for it to be ready to send data. - * Clear interrupts so that this process will not be externally - * interrupted in the middle (which can cause the transceiver to - * drain prematurely). - */ - - local_irq_save(flags); - - UART_PUT_CTRL(port, ctrl | UART_CTRL_TE); - - while (!UART_TX_READY(UART_GET_STATUS(port))) - loop++; - - /* - * Disable the transceiver so data isn't actually sent during the - * actual test. - */ - - UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE)); - - fifosize = 1; - UART_PUT_CHAR(port, 0); - - /* - * So long as transmitting a character increments the tranceivier FIFO - * length the FIFO must be at least that big. These bytes will - * automatically drain off of the FIFO. - */ - - status = UART_GET_STATUS(port); - while (((status >> 20) & 0x3F) == fifosize) { - fifosize++; - UART_PUT_CHAR(port, 0); - status = UART_GET_STATUS(port); - } - - fifosize--; - - UART_PUT_CTRL(port, ctrl); - local_irq_restore(flags); - - if (fifosize == 0) - fifosize = 1; - - return fifosize; -} - -static void apbuart_flush_fifo(struct uart_port *port) -{ - int i; - - for (i = 0; i < port->fifosize; i++) - UART_GET_CHAR(port); -} - - -/* ======================================================================== */ -/* Console driver, if enabled */ -/* ======================================================================== */ - -#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE - -static void apbuart_console_putchar(struct uart_port *port, int ch) -{ - unsigned int status; - do { - status = UART_GET_STATUS(port); - } while (!UART_TX_READY(status)); - UART_PUT_CHAR(port, ch); -} - -static void -apbuart_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_port *port = &grlib_apbuart_ports[co->index]; - unsigned int status, old_cr, new_cr; - - /* First save the CR then disable the interrupts */ - old_cr = UART_GET_CTRL(port); - new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI); - UART_PUT_CTRL(port, new_cr); - - uart_console_write(port, s, count, apbuart_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the TCR - */ - do { - status = UART_GET_STATUS(port); - } while (!UART_TX_READY(status)); - UART_PUT_CTRL(port, old_cr); -} - -static void __init -apbuart_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) { - - unsigned int quot, status; - status = UART_GET_STATUS(port); - - *parity = 'n'; - if (status & UART_CTRL_PE) { - if ((status & UART_CTRL_PS) == 0) - *parity = 'e'; - else - *parity = 'o'; - } - - *bits = 8; - quot = UART_GET_SCAL(port) / 8; - *baud = port->uartclk / (16 * (quot + 1)); - } -} - -static int __init apbuart_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n", - co, co->index, options); - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= grlib_apbuart_port_nr) - co->index = 0; - - port = &grlib_apbuart_ports[co->index]; - - spin_lock_init(&port->lock); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - apbuart_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver grlib_apbuart_driver; - -static struct console grlib_apbuart_console = { - .name = "ttyS", - .write = apbuart_console_write, - .device = uart_console_device, - .setup = apbuart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &grlib_apbuart_driver, -}; - - -static int grlib_apbuart_configure(void); - -static int __init apbuart_console_init(void) -{ - if (grlib_apbuart_configure()) - return -ENODEV; - register_console(&grlib_apbuart_console); - return 0; -} - -console_initcall(apbuart_console_init); - -#define APBUART_CONSOLE (&grlib_apbuart_console) -#else -#define APBUART_CONSOLE NULL -#endif - -static struct uart_driver grlib_apbuart_driver = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = SERIAL_APBUART_MAJOR, - .minor = SERIAL_APBUART_MINOR, - .nr = UART_NR, - .cons = APBUART_CONSOLE, -}; - - -/* ======================================================================== */ -/* OF Platform Driver */ -/* ======================================================================== */ - -static int __devinit apbuart_probe(struct platform_device *op, - const struct of_device_id *match) -{ - int i = -1; - struct uart_port *port = NULL; - - i = 0; - for (i = 0; i < grlib_apbuart_port_nr; i++) { - if (op->dev.of_node == grlib_apbuart_nodes[i]) - break; - } - - port = &grlib_apbuart_ports[i]; - port->dev = &op->dev; - - uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port); - - apbuart_flush_fifo((struct uart_port *) port); - - printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n", - (unsigned long long) port->mapbase, port->irq); - return 0; -} - -static struct of_device_id __initdata apbuart_match[] = { - { - .name = "GAISLER_APBUART", - }, - { - .name = "01_00c", - }, - {}, -}; - -static struct of_platform_driver grlib_apbuart_of_driver = { - .probe = apbuart_probe, - .driver = { - .owner = THIS_MODULE, - .name = "grlib-apbuart", - .of_match_table = apbuart_match, - }, -}; - - -static int grlib_apbuart_configure(void) -{ - struct device_node *np, *rp; - const u32 *prop; - int freq_khz, line = 0; - - /* Get bus frequency */ - rp = of_find_node_by_path("/"); - if (!rp) - return -ENODEV; - rp = of_get_next_child(rp, NULL); - if (!rp) - return -ENODEV; - prop = of_get_property(rp, "clock-frequency", NULL); - if (!prop) - return -ENODEV; - freq_khz = *prop; - - for_each_matching_node(np, apbuart_match) { - const int *irqs, *ampopts; - const struct amba_prom_registers *regs; - struct uart_port *port; - unsigned long addr; - - ampopts = of_get_property(np, "ampopts", NULL); - if (ampopts && (*ampopts == 0)) - continue; /* Ignore if used by another OS instance */ - - irqs = of_get_property(np, "interrupts", NULL); - regs = of_get_property(np, "reg", NULL); - - if (!irqs || !regs) - continue; - - grlib_apbuart_nodes[line] = np; - - addr = regs->phys_addr; - - port = &grlib_apbuart_ports[line]; - - port->mapbase = addr; - port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map)); - port->irq = *irqs; - port->iotype = UPIO_MEM; - port->ops = &grlib_apbuart_ops; - port->flags = UPF_BOOT_AUTOCONF; - port->line = line; - port->uartclk = freq_khz * 1000; - port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line); - line++; - - /* We support maximum UART_NR uarts ... */ - if (line == UART_NR) - break; - } - - grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line; - return line ? 0 : -ENODEV; -} - -static int __init grlib_apbuart_init(void) -{ - int ret; - - /* Find all APBUARTS in device the tree and initialize their ports */ - ret = grlib_apbuart_configure(); - if (ret) - return ret; - - printk(KERN_INFO "Serial: GRLIB APBUART driver\n"); - - ret = uart_register_driver(&grlib_apbuart_driver); - - if (ret) { - printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", - __FILE__, ret); - return ret; - } - - ret = of_register_platform_driver(&grlib_apbuart_of_driver); - if (ret) { - printk(KERN_ERR - "%s: of_register_platform_driver failed (%i)\n", - __FILE__, ret); - uart_unregister_driver(&grlib_apbuart_driver); - return ret; - } - - return ret; -} - -static void __exit grlib_apbuart_exit(void) -{ - int i; - - for (i = 0; i < grlib_apbuart_port_nr; i++) - uart_remove_one_port(&grlib_apbuart_driver, - &grlib_apbuart_ports[i]); - - uart_unregister_driver(&grlib_apbuart_driver); - of_unregister_platform_driver(&grlib_apbuart_of_driver); -} - -module_init(grlib_apbuart_init); -module_exit(grlib_apbuart_exit); - -MODULE_AUTHOR("Aeroflex Gaisler AB"); -MODULE_DESCRIPTION("GRLIB APBUART serial driver"); -MODULE_VERSION("2.1"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/apbuart.h b/drivers/serial/apbuart.h deleted file mode 100644 index 5faf87c8d2bc..000000000000 --- a/drivers/serial/apbuart.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __GRLIB_APBUART_H__ -#define __GRLIB_APBUART_H__ - -#include - -#define UART_NR 8 -static int grlib_apbuart_port_nr; - -struct grlib_apbuart_regs_map { - u32 data; - u32 status; - u32 ctrl; - u32 scaler; -}; - -struct amba_prom_registers { - unsigned int phys_addr; - unsigned int reg_size; -}; - -/* - * The following defines the bits in the APBUART Status Registers. - */ -#define UART_STATUS_DR 0x00000001 /* Data Ready */ -#define UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */ -#define UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */ -#define UART_STATUS_BR 0x00000008 /* Break Error */ -#define UART_STATUS_OE 0x00000010 /* RX Overrun Error */ -#define UART_STATUS_PE 0x00000020 /* RX Parity Error */ -#define UART_STATUS_FE 0x00000040 /* RX Framing Error */ -#define UART_STATUS_ERR 0x00000078 /* Error Mask */ - -/* - * The following defines the bits in the APBUART Ctrl Registers. - */ -#define UART_CTRL_RE 0x00000001 /* Receiver enable */ -#define UART_CTRL_TE 0x00000002 /* Transmitter enable */ -#define UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */ -#define UART_CTRL_TI 0x00000008 /* Transmitter irq */ -#define UART_CTRL_PS 0x00000010 /* Parity select */ -#define UART_CTRL_PE 0x00000020 /* Parity enable */ -#define UART_CTRL_FL 0x00000040 /* Flow control enable */ -#define UART_CTRL_LB 0x00000080 /* Loopback enable */ - -#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase)) - -#define APBBASE_DATA_P(port) (&(APBBASE(port)->data)) -#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status)) -#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl)) -#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler)) - -#define UART_GET_CHAR(port) (__raw_readl(APBBASE_DATA_P(port))) -#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port))) -#define UART_GET_STATUS(port) (__raw_readl(APBBASE_STATUS_P(port))) -#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port))) -#define UART_GET_CTRL(port) (__raw_readl(APBBASE_CTRL_P(port))) -#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port))) -#define UART_GET_SCAL(port) (__raw_readl(APBBASE_SCALAR_P(port))) -#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port))) - -#define UART_RX_DATA(s) (((s) & UART_STATUS_DR) != 0) -#define UART_TX_READY(s) (((s) & UART_STATUS_THE) != 0) - -#endif /* __GRLIB_APBUART_H__ */ diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c deleted file mode 100644 index 3892666b5fbd..000000000000 --- a/drivers/serial/atmel_serial.c +++ /dev/null @@ -1,1808 +0,0 @@ -/* - * linux/drivers/char/atmel_serial.c - * - * Driver for Atmel AT91 / AT32 Serial ports - * Copyright (C) 2003 Rick Bronson - * - * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * DMA support added by Chip Coldwell. - * - * 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 -#include -#include -#include -#include - -#include -#include - -#include -#include - -#ifdef CONFIG_ARM -#include -#include -#endif - -#define PDC_BUFFER_SIZE 512 -/* Revisit: We should calculate this based on the actual port settings */ -#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ - -#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -static void atmel_start_rx(struct uart_port *port); -static void atmel_stop_rx(struct uart_port *port); - -#ifdef CONFIG_SERIAL_ATMEL_TTYAT - -/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we - * should coexist with the 8250 driver, such as if we have an external 16C550 - * UART. */ -#define SERIAL_ATMEL_MAJOR 204 -#define MINOR_START 154 -#define ATMEL_DEVICENAME "ttyAT" - -#else - -/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port - * name, but it is legally reserved for the 8250 driver. */ -#define SERIAL_ATMEL_MAJOR TTY_MAJOR -#define MINOR_START 64 -#define ATMEL_DEVICENAME "ttyS" - -#endif - -#define ATMEL_ISR_PASS_LIMIT 256 - -/* UART registers. CR is write-only, hence no GET macro */ -#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) -#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) -#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) -#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER) -#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR) -#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR) -#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR) -#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR) -#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR) -#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR) -#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) -#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) -#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) - - /* PDC registers */ -#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) - -#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) -#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR) -#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR) -#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR) -#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR) - -#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) -#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) -#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) - -static int (*atmel_open_hook)(struct uart_port *); -static void (*atmel_close_hook)(struct uart_port *); - -struct atmel_dma_buffer { - unsigned char *buf; - dma_addr_t dma_addr; - unsigned int dma_size; - unsigned int ofs; -}; - -struct atmel_uart_char { - u16 status; - u16 ch; -}; - -#define ATMEL_SERIAL_RINGSIZE 1024 - -/* - * We wrap our port structure around the generic uart_port. - */ -struct atmel_uart_port { - struct uart_port uart; /* uart */ - struct clk *clk; /* uart clock */ - int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ - u32 backup_imr; /* IMR saved during suspend */ - int break_active; /* break being received */ - - short use_dma_rx; /* enable PDC receiver */ - short pdc_rx_idx; /* current PDC RX buffer */ - struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ - - short use_dma_tx; /* enable PDC transmitter */ - struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ - - struct tasklet_struct tasklet; - unsigned int irq_status; - unsigned int irq_status_prev; - - struct circ_buf rx_ring; - - struct serial_rs485 rs485; /* rs485 settings */ - unsigned int tx_done_mask; -}; - -static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; - -#ifdef SUPPORT_SYSRQ -static struct console atmel_console; -#endif - -static inline struct atmel_uart_port * -to_atmel_uart_port(struct uart_port *uart) -{ - return container_of(uart, struct atmel_uart_port, uart); -} - -#ifdef CONFIG_SERIAL_ATMEL_PDC -static bool atmel_use_dma_rx(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - return atmel_port->use_dma_rx; -} - -static bool atmel_use_dma_tx(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - return atmel_port->use_dma_tx; -} -#else -static bool atmel_use_dma_rx(struct uart_port *port) -{ - return false; -} - -static bool atmel_use_dma_tx(struct uart_port *port) -{ - return false; -} -#endif - -/* Enable or disable the rs485 support */ -void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int mode; - - spin_lock(&port->lock); - - /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); - - mode = UART_GET_MR(port); - - /* Resetting serial mode to RS232 (0x0) */ - mode &= ~ATMEL_US_USMODE; - - atmel_port->rs485 = *rs485conf; - - if (rs485conf->flags & SER_RS485_ENABLED) { - dev_dbg(port->dev, "Setting UART to RS485\n"); - atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) - UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); - mode |= ATMEL_US_USMODE_RS485; - } else { - dev_dbg(port->dev, "Setting UART to RS232\n"); - if (atmel_use_dma_tx(port)) - atmel_port->tx_done_mask = ATMEL_US_ENDTX | - ATMEL_US_TXBUFE; - else - atmel_port->tx_done_mask = ATMEL_US_TXRDY; - } - UART_PUT_MR(port, mode); - - /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); - - spin_unlock(&port->lock); - -} - -/* - * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. - */ -static u_int atmel_tx_empty(struct uart_port *port) -{ - return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0; -} - -/* - * Set state of the modem control output lines - */ -static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) -{ - unsigned int control = 0; - unsigned int mode; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - -#ifdef CONFIG_ARCH_AT91RM9200 - if (cpu_is_at91rm9200()) { - /* - * AT91RM9200 Errata #39: RTS0 is not internally connected - * to PA21. We need to drive the pin manually. - */ - if (port->mapbase == AT91RM9200_BASE_US0) { - if (mctrl & TIOCM_RTS) - at91_set_gpio_value(AT91_PIN_PA21, 0); - else - at91_set_gpio_value(AT91_PIN_PA21, 1); - } - } -#endif - - if (mctrl & TIOCM_RTS) - control |= ATMEL_US_RTSEN; - else - control |= ATMEL_US_RTSDIS; - - if (mctrl & TIOCM_DTR) - control |= ATMEL_US_DTREN; - else - control |= ATMEL_US_DTRDIS; - - UART_PUT_CR(port, control); - - /* Local loopback mode? */ - mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE; - if (mctrl & TIOCM_LOOP) - mode |= ATMEL_US_CHMODE_LOC_LOOP; - else - mode |= ATMEL_US_CHMODE_NORMAL; - - /* Resetting serial mode to RS232 (0x0) */ - mode &= ~ATMEL_US_USMODE; - - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { - dev_dbg(port->dev, "Setting UART to RS485\n"); - if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - UART_PUT_TTGR(port, - atmel_port->rs485.delay_rts_after_send); - mode |= ATMEL_US_USMODE_RS485; - } else { - dev_dbg(port->dev, "Setting UART to RS232\n"); - } - UART_PUT_MR(port, mode); -} - -/* - * Get state of the modem control input lines - */ -static u_int atmel_get_mctrl(struct uart_port *port) -{ - unsigned int status, ret = 0; - - status = UART_GET_CSR(port); - - /* - * The control signals are active low. - */ - if (!(status & ATMEL_US_DCD)) - ret |= TIOCM_CD; - if (!(status & ATMEL_US_CTS)) - ret |= TIOCM_CTS; - if (!(status & ATMEL_US_DSR)) - ret |= TIOCM_DSR; - if (!(status & ATMEL_US_RI)) - ret |= TIOCM_RI; - - return ret; -} - -/* - * Stop transmitting. - */ -static void atmel_stop_tx(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (atmel_use_dma_tx(port)) { - /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); - } - /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); - - if (atmel_port->rs485.flags & SER_RS485_ENABLED) - atmel_start_rx(port); -} - -/* - * Start transmitting. - */ -static void atmel_start_tx(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (atmel_use_dma_tx(port)) { - if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) - /* The transmitter is already running. Yes, we - really need this.*/ - return; - - if (atmel_port->rs485.flags & SER_RS485_ENABLED) - atmel_stop_rx(port); - - /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); - } - /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); -} - -/* - * start receiving - port is in process of being opened. - */ -static void atmel_start_rx(struct uart_port *port) -{ - UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ - - if (atmel_use_dma_rx(port)) { - /* enable PDC controller */ - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); - } else { - UART_PUT_IER(port, ATMEL_US_RXRDY); - } -} - -/* - * Stop receiving - port is in process of being closed. - */ -static void atmel_stop_rx(struct uart_port *port) -{ - if (atmel_use_dma_rx(port)) { - /* disable PDC receive */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); - UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); - } else { - UART_PUT_IDR(port, ATMEL_US_RXRDY); - } -} - -/* - * Enable modem status interrupts - */ -static void atmel_enable_ms(struct uart_port *port) -{ - UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC - | ATMEL_US_DCDIC | ATMEL_US_CTSIC); -} - -/* - * Control the transmission of a break signal - */ -static void atmel_break_ctl(struct uart_port *port, int break_state) -{ - if (break_state != 0) - UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ - else - UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ -} - -/* - * Stores the incoming character in the ring buffer - */ -static void -atmel_buffer_rx_char(struct uart_port *port, unsigned int status, - unsigned int ch) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *ring = &atmel_port->rx_ring; - struct atmel_uart_char *c; - - if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE)) - /* Buffer overflow, ignore char */ - return; - - c = &((struct atmel_uart_char *)ring->buf)[ring->head]; - c->status = status; - c->ch = ch; - - /* Make sure the character is stored before we update head. */ - smp_wmb(); - - ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1); -} - -/* - * Deal with parity, framing and overrun errors. - */ -static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) -{ - /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - - if (status & ATMEL_US_RXBRK) { - /* ignore side-effect */ - status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); - port->icount.brk++; - } - if (status & ATMEL_US_PARE) - port->icount.parity++; - if (status & ATMEL_US_FRAME) - port->icount.frame++; - if (status & ATMEL_US_OVRE) - port->icount.overrun++; -} - -/* - * Characters received (called from interrupt handler) - */ -static void atmel_rx_chars(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status, ch; - - status = UART_GET_CSR(port); - while (status & ATMEL_US_RXRDY) { - ch = UART_GET_CHAR(port); - - /* - * note that the error handling code is - * out of the main execution path - */ - if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME - | ATMEL_US_OVRE | ATMEL_US_RXBRK) - || atmel_port->break_active)) { - - /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - - if (status & ATMEL_US_RXBRK - && !atmel_port->break_active) { - atmel_port->break_active = 1; - UART_PUT_IER(port, ATMEL_US_RXBRK); - } else { - /* - * This is either the end-of-break - * condition or we've received at - * least one character without RXBRK - * being set. In both cases, the next - * RXBRK will indicate start-of-break. - */ - UART_PUT_IDR(port, ATMEL_US_RXBRK); - status &= ~ATMEL_US_RXBRK; - atmel_port->break_active = 0; - } - } - - atmel_buffer_rx_char(port, status, ch); - status = UART_GET_CSR(port); - } - - tasklet_schedule(&atmel_port->tasklet); -} - -/* - * Transmit characters (called from tasklet with TXRDY interrupt - * disabled) - */ -static void atmel_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - while (UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - 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); - - if (!uart_circ_empty(xmit)) - /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); -} - -/* - * receive interrupt handler. - */ -static void -atmel_handle_receive(struct uart_port *port, unsigned int pending) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (atmel_use_dma_rx(port)) { - /* - * PDC receive. Just schedule the tasklet and let it - * figure out the details. - * - * TODO: We're not handling error flags correctly at - * the moment. - */ - if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { - UART_PUT_IDR(port, (ATMEL_US_ENDRX - | ATMEL_US_TIMEOUT)); - tasklet_schedule(&atmel_port->tasklet); - } - - if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | - ATMEL_US_FRAME | ATMEL_US_PARE)) - atmel_pdc_rxerr(port, pending); - } - - /* Interrupt receive */ - if (pending & ATMEL_US_RXRDY) - atmel_rx_chars(port); - else if (pending & ATMEL_US_RXBRK) { - /* - * End of break detected. If it came along with a - * character, atmel_rx_chars will handle it. - */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, ATMEL_US_RXBRK); - atmel_port->break_active = 0; - } -} - -/* - * transmit interrupt handler. (Transmit is IRQF_NODELAY safe) - */ -static void -atmel_handle_transmit(struct uart_port *port, unsigned int pending) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (pending & atmel_port->tx_done_mask) { - /* Either PDC or interrupt transmission */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); - tasklet_schedule(&atmel_port->tasklet); - } -} - -/* - * status flags interrupt handler. - */ -static void -atmel_handle_status(struct uart_port *port, unsigned int pending, - unsigned int status) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC - | ATMEL_US_CTSIC)) { - atmel_port->irq_status = status; - tasklet_schedule(&atmel_port->tasklet); - } -} - -/* - * Interrupt handler - */ -static irqreturn_t atmel_interrupt(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned int status, pending, pass_counter = 0; - - do { - status = UART_GET_CSR(port); - pending = status & UART_GET_IMR(port); - if (!pending) - break; - - atmel_handle_receive(port, pending); - atmel_handle_status(port, pending, status); - atmel_handle_transmit(port, pending); - } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); - - return pass_counter ? IRQ_HANDLED : IRQ_NONE; -} - -/* - * Called from tasklet with ENDTX and TXBUFE interrupts disabled. - */ -static void atmel_tx_dma(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; - struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - int count; - - /* nothing left to transmit? */ - if (UART_GET_TCR(port)) - return; - - xmit->tail += pdc->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += pdc->ofs; - pdc->ofs = 0; - - /* more to transmit - setup next transfer */ - - /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); - - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { - dma_sync_single_for_device(port->dev, - pdc->dma_addr, - pdc->dma_size, - DMA_TO_DEVICE); - - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - pdc->ofs = count; - - UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); - UART_PUT_TCR(port, count); - /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); - /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); - } else { - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { - /* DMA done, stop TX, start RX for RS485 */ - atmel_start_rx(port); - } - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static void atmel_rx_from_ring(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *ring = &atmel_port->rx_ring; - unsigned int flg; - unsigned int status; - - while (ring->head != ring->tail) { - struct atmel_uart_char c; - - /* Make sure c is loaded after head. */ - smp_rmb(); - - c = ((struct atmel_uart_char *)ring->buf)[ring->tail]; - - ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1); - - port->icount.rx++; - status = c.status; - flg = TTY_NORMAL; - - /* - * note that the error handling code is - * out of the main execution path - */ - if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME - | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { - if (status & ATMEL_US_RXBRK) { - /* ignore side-effect */ - status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); - - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } - if (status & ATMEL_US_PARE) - port->icount.parity++; - if (status & ATMEL_US_FRAME) - port->icount.frame++; - if (status & ATMEL_US_OVRE) - port->icount.overrun++; - - status &= port->read_status_mask; - - if (status & ATMEL_US_RXBRK) - flg = TTY_BREAK; - else if (status & ATMEL_US_PARE) - flg = TTY_PARITY; - else if (status & ATMEL_US_FRAME) - flg = TTY_FRAME; - } - - - if (uart_handle_sysrq_char(port, c.ch)) - continue; - - uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); - } - - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); - tty_flip_buffer_push(port->state->port.tty); - spin_lock(&port->lock); -} - -static void atmel_rx_from_dma(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; - struct atmel_dma_buffer *pdc; - int rx_idx = atmel_port->pdc_rx_idx; - unsigned int head; - unsigned int tail; - unsigned int count; - - do { - /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); - - pdc = &atmel_port->pdc_rx[rx_idx]; - head = UART_GET_RPR(port) - pdc->dma_addr; - tail = pdc->ofs; - - /* If the PDC has switched buffers, RPR won't contain - * any address within the current buffer. Since head - * is unsigned, we just need a one-way comparison to - * find out. - * - * In this case, we just need to consume the entire - * buffer and resubmit it for DMA. This will clear the - * ENDRX bit as well, so that we can safely re-enable - * all interrupts below. - */ - head = min(head, pdc->dma_size); - - if (likely(head != tail)) { - dma_sync_single_for_cpu(port->dev, pdc->dma_addr, - pdc->dma_size, DMA_FROM_DEVICE); - - /* - * head will only wrap around when we recycle - * the DMA buffer, and when that happens, we - * explicitly set tail to 0. So head will - * always be greater than tail. - */ - count = head - tail; - - tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); - - dma_sync_single_for_device(port->dev, pdc->dma_addr, - pdc->dma_size, DMA_FROM_DEVICE); - - port->icount.rx += count; - pdc->ofs = head; - } - - /* - * If the current buffer is full, we need to check if - * the next one contains any additional data. - */ - if (head >= pdc->dma_size) { - pdc->ofs = 0; - UART_PUT_RNPR(port, pdc->dma_addr); - UART_PUT_RNCR(port, pdc->dma_size); - - rx_idx = !rx_idx; - atmel_port->pdc_rx_idx = rx_idx; - } - } while (head >= pdc->dma_size); - - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); - tty_flip_buffer_push(tty); - spin_lock(&port->lock); - - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); -} - -/* - * tasklet handling tty stuff outside the interrupt handler. - */ -static void atmel_tasklet_func(unsigned long data) -{ - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status; - unsigned int status_change; - - /* The interrupt handler does not take the lock */ - spin_lock(&port->lock); - - if (atmel_use_dma_tx(port)) - atmel_tx_dma(port); - else - atmel_tx_chars(port); - - status = atmel_port->irq_status; - status_change = status ^ atmel_port->irq_status_prev; - - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR - | ATMEL_US_DCD | ATMEL_US_CTS)) { - /* TODO: All reads to CSR will clear these interrupts! */ - if (status_change & ATMEL_US_RI) - port->icount.rng++; - if (status_change & ATMEL_US_DSR) - port->icount.dsr++; - if (status_change & ATMEL_US_DCD) - uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); - if (status_change & ATMEL_US_CTS) - uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - - wake_up_interruptible(&port->state->port.delta_msr_wait); - - atmel_port->irq_status_prev = status; - } - - if (atmel_use_dma_rx(port)) - atmel_rx_from_dma(port); - else - atmel_rx_from_ring(port); - - spin_unlock(&port->lock); -} - -/* - * Perform initialization and enable port for reception - */ -static int atmel_startup(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; - int retval; - - /* - * Ensure that no interrupts are enabled otherwise when - * request_irq() is called we could get stuck trying to - * handle an unexpected interrupt - */ - UART_PUT_IDR(port, -1); - - /* - * Allocate the IRQ - */ - retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, - tty ? tty->name : "atmel_serial", port); - if (retval) { - printk("atmel_serial: atmel_startup - Can't get irq\n"); - return retval; - } - - /* - * Initialize DMA (if necessary) - */ - if (atmel_use_dma_rx(port)) { - int i; - - for (i = 0; i < 2; i++) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; - - pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); - if (pdc->buf == NULL) { - if (i != 0) { - dma_unmap_single(port->dev, - atmel_port->pdc_rx[0].dma_addr, - PDC_BUFFER_SIZE, - DMA_FROM_DEVICE); - kfree(atmel_port->pdc_rx[0].buf); - } - free_irq(port->irq, port); - return -ENOMEM; - } - pdc->dma_addr = dma_map_single(port->dev, - pdc->buf, - PDC_BUFFER_SIZE, - DMA_FROM_DEVICE); - pdc->dma_size = PDC_BUFFER_SIZE; - pdc->ofs = 0; - } - - atmel_port->pdc_rx_idx = 0; - - UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); - UART_PUT_RCR(port, PDC_BUFFER_SIZE); - - UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); - UART_PUT_RNCR(port, PDC_BUFFER_SIZE); - } - if (atmel_use_dma_tx(port)) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - struct circ_buf *xmit = &port->state->xmit; - - pdc->buf = xmit->buf; - pdc->dma_addr = dma_map_single(port->dev, - pdc->buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - pdc->dma_size = UART_XMIT_SIZE; - pdc->ofs = 0; - } - - /* - * If there is a specific "open" function (to register - * control line interrupts) - */ - if (atmel_open_hook) { - retval = atmel_open_hook(port); - if (retval) { - free_irq(port->irq, port); - return retval; - } - } - - /* Save current CSR for comparison in atmel_tasklet_func() */ - atmel_port->irq_status_prev = UART_GET_CSR(port); - atmel_port->irq_status = atmel_port->irq_status_prev; - - /* - * Finally, enable the serial port - */ - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - /* enable xmit & rcvr */ - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - - if (atmel_use_dma_rx(port)) { - /* set UART timeout */ - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); - - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); - /* enable PDC controller */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); - } else { - /* enable receive only */ - UART_PUT_IER(port, ATMEL_US_RXRDY); - } - - return 0; -} - -/* - * Disable the port - */ -static void atmel_shutdown(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - /* - * Ensure everything is stopped. - */ - atmel_stop_rx(port); - atmel_stop_tx(port); - - /* - * Shut-down the DMA. - */ - if (atmel_use_dma_rx(port)) { - int i; - - for (i = 0; i < 2; i++) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; - - dma_unmap_single(port->dev, - pdc->dma_addr, - pdc->dma_size, - DMA_FROM_DEVICE); - kfree(pdc->buf); - } - } - if (atmel_use_dma_tx(port)) { - struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - - dma_unmap_single(port->dev, - pdc->dma_addr, - pdc->dma_size, - DMA_TO_DEVICE); - } - - /* - * Disable all interrupts, port and break condition. - */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); - - /* - * Free the interrupt - */ - free_irq(port->irq, port); - - /* - * If there is a specific "close" function (to unregister - * control line interrupts) - */ - if (atmel_close_hook) - atmel_close_hook(port); -} - -/* - * Flush any TX data submitted for DMA. Called when the TX circular - * buffer is reset. - */ -static void atmel_flush_buffer(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (atmel_use_dma_tx(port)) { - UART_PUT_TCR(port, 0); - atmel_port->pdc_tx.ofs = 0; - } -} - -/* - * Power / Clock management. - */ -static void atmel_serial_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - switch (state) { - case 0: - /* - * Enable the peripheral clock for this serial port. - * This is called on uart_open() or a resume event. - */ - clk_enable(atmel_port->clk); - - /* re-enable interrupts if we disabled some on suspend */ - UART_PUT_IER(port, atmel_port->backup_imr); - break; - case 3: - /* Back up the interrupt mask and disable all interrupts */ - atmel_port->backup_imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); - - /* - * Disable the peripheral clock for this serial port. - * This is called on uart_close() or a suspend event. - */ - clk_disable(atmel_port->clk); - break; - default: - printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); - } -} - -/* - * Change the port parameters - */ -static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int mode, imr, quot, baud; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - /* Get current mode register */ - mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL - | ATMEL_US_NBSTOP | ATMEL_US_PAR - | ATMEL_US_USMODE); - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - quot = uart_get_divisor(port, baud); - - if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ - quot /= 8; - mode |= ATMEL_US_USCLKS_MCK_DIV8; - } - - /* byte size */ - switch (termios->c_cflag & CSIZE) { - case CS5: - mode |= ATMEL_US_CHRL_5; - break; - case CS6: - mode |= ATMEL_US_CHRL_6; - break; - case CS7: - mode |= ATMEL_US_CHRL_7; - break; - default: - mode |= ATMEL_US_CHRL_8; - break; - } - - /* stop bits */ - if (termios->c_cflag & CSTOPB) - mode |= ATMEL_US_NBSTOP_2; - - /* parity */ - if (termios->c_cflag & PARENB) { - /* Mark or Space parity */ - if (termios->c_cflag & CMSPAR) { - if (termios->c_cflag & PARODD) - mode |= ATMEL_US_PAR_MARK; - else - mode |= ATMEL_US_PAR_SPACE; - } else if (termios->c_cflag & PARODD) - mode |= ATMEL_US_PAR_ODD; - else - mode |= ATMEL_US_PAR_EVEN; - } else - mode |= ATMEL_US_PAR_NONE; - - /* hardware handshake (RTS/CTS) */ - if (termios->c_cflag & CRTSCTS) - mode |= ATMEL_US_USMODE_HWHS; - else - mode |= ATMEL_US_USMODE_NORMAL; - - spin_lock_irqsave(&port->lock, flags); - - port->read_status_mask = ATMEL_US_OVRE; - if (termios->c_iflag & INPCK) - port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= ATMEL_US_RXBRK; - - if (atmel_use_dma_rx(port)) - /* need to enable error interrupts */ - UART_PUT_IER(port, port->read_status_mask); - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= ATMEL_US_RXBRK; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= ATMEL_US_OVRE; - } - /* TODO: Ignore all characters if CREAD is set.*/ - - /* update the per-port timeout */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * save/disable interrupts. The tty layer will ensure that the - * transmitter is empty if requested by the caller, so there's - * no need to wait for it here. - */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); - - /* disable receiver and transmitter */ - UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); - - /* Resetting serial mode to RS232 (0x0) */ - mode &= ~ATMEL_US_USMODE; - - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { - dev_dbg(port->dev, "Setting UART to RS485\n"); - if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - UART_PUT_TTGR(port, - atmel_port->rs485.delay_rts_after_send); - mode |= ATMEL_US_USMODE_RS485; - } else { - dev_dbg(port->dev, "Setting UART to RS232\n"); - } - - /* set the parity, stop bits and data size */ - UART_PUT_MR(port, mode); - - /* set the baud rate */ - UART_PUT_BRGR(port, quot); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - - /* restore interrupts */ - UART_PUT_IER(port, imr); - - /* CTS flow-control and modem-status interrupts */ - if (UART_ENABLE_MS(port, termios->c_cflag)) - port->ops->enable_ms(port); - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* - * Return string describing the specified port - */ -static const char *atmel_type(struct uart_port *port) -{ - return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void atmel_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - int size = pdev->resource[0].end - pdev->resource[0].start + 1; - - release_mem_region(port->mapbase, size); - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int atmel_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - int size = pdev->resource[0].end - pdev->resource[0].start + 1; - - if (!request_mem_region(port->mapbase, size, "atmel_serial")) - return -EBUSY; - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_mem_region(port->mapbase, size); - return -ENOMEM; - } - } - - return 0; -} - -/* - * Configure/autoconfigure the port. - */ -static void atmel_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_ATMEL; - atmel_request_port(port); - } -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - */ -static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL) - ret = -EINVAL; - if (port->irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (port->uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)port->mapbase != ser->iomem_base) - ret = -EINVAL; - if (port->iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -#ifdef CONFIG_CONSOLE_POLL -static int atmel_poll_get_char(struct uart_port *port) -{ - while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY)) - cpu_relax(); - - return UART_GET_CHAR(port); -} - -static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) -{ - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) - cpu_relax(); - - UART_PUT_CHAR(port, ch); -} -#endif - -static int -atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) -{ - struct serial_rs485 rs485conf; - - switch (cmd) { - case TIOCSRS485: - if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg, - sizeof(rs485conf))) - return -EFAULT; - - atmel_config_rs485(port, &rs485conf); - break; - - case TIOCGRS485: - if (copy_to_user((struct serial_rs485 *) arg, - &(to_atmel_uart_port(port)->rs485), - sizeof(rs485conf))) - return -EFAULT; - break; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - - - -static struct uart_ops atmel_pops = { - .tx_empty = atmel_tx_empty, - .set_mctrl = atmel_set_mctrl, - .get_mctrl = atmel_get_mctrl, - .stop_tx = atmel_stop_tx, - .start_tx = atmel_start_tx, - .stop_rx = atmel_stop_rx, - .enable_ms = atmel_enable_ms, - .break_ctl = atmel_break_ctl, - .startup = atmel_startup, - .shutdown = atmel_shutdown, - .flush_buffer = atmel_flush_buffer, - .set_termios = atmel_set_termios, - .type = atmel_type, - .release_port = atmel_release_port, - .request_port = atmel_request_port, - .config_port = atmel_config_port, - .verify_port = atmel_verify_port, - .pm = atmel_serial_pm, - .ioctl = atmel_ioctl, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = atmel_poll_get_char, - .poll_put_char = atmel_poll_put_char, -#endif -}; - -/* - * Configure the port from the platform device resource info. - */ -static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, - struct platform_device *pdev) -{ - struct uart_port *port = &atmel_port->uart; - struct atmel_uart_data *data = pdev->dev.platform_data; - - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - port->ops = &atmel_pops; - port->fifosize = 1; - port->line = pdev->id; - port->dev = &pdev->dev; - port->mapbase = pdev->resource[0].start; - port->irq = pdev->resource[1].start; - - tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, - (unsigned long)port); - - memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); - - if (data->regs) - /* Already mapped by setup code */ - port->membase = data->regs; - else { - port->flags |= UPF_IOREMAP; - port->membase = NULL; - } - - /* for console, the clock could already be configured */ - if (!atmel_port->clk) { - atmel_port->clk = clk_get(&pdev->dev, "usart"); - clk_enable(atmel_port->clk); - port->uartclk = clk_get_rate(atmel_port->clk); - clk_disable(atmel_port->clk); - /* only enable clock when USART is in use */ - } - - atmel_port->use_dma_rx = data->use_dma_rx; - atmel_port->use_dma_tx = data->use_dma_tx; - atmel_port->rs485 = data->rs485; - /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */ - if (atmel_port->rs485.flags & SER_RS485_ENABLED) - atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - else if (atmel_use_dma_tx(port)) { - port->fifosize = PDC_BUFFER_SIZE; - atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE; - } else { - atmel_port->tx_done_mask = ATMEL_US_TXRDY; - } -} - -/* - * Register board-specific modem-control line handlers. - */ -void __init atmel_register_uart_fns(struct atmel_port_fns *fns) -{ - if (fns->enable_ms) - atmel_pops.enable_ms = fns->enable_ms; - if (fns->get_mctrl) - atmel_pops.get_mctrl = fns->get_mctrl; - if (fns->set_mctrl) - atmel_pops.set_mctrl = fns->set_mctrl; - atmel_open_hook = fns->open; - atmel_close_hook = fns->close; - atmel_pops.pm = fns->pm; - atmel_pops.set_wake = fns->set_wake; -} - -#ifdef CONFIG_SERIAL_ATMEL_CONSOLE -static void atmel_console_putchar(struct uart_port *port, int ch) -{ - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) - cpu_relax(); - UART_PUT_CHAR(port, ch); -} - -/* - * Interrupts are disabled on entering - */ -static void atmel_console_write(struct console *co, const char *s, u_int count) -{ - struct uart_port *port = &atmel_ports[co->index].uart; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status, imr; - unsigned int pdc_tx; - - /* - * First, save IMR and then disable interrupts - */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask); - - /* Store PDC transmit status and disable it */ - pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN; - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); - - uart_console_write(port, s, count, atmel_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore IMR - */ - do { - status = UART_GET_CSR(port); - } while (!(status & ATMEL_US_TXRDY)); - - /* Restore PDC transmit status */ - if (pdc_tx) - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); - - /* set interrupts back the way they were */ - UART_PUT_IER(port, imr); -} - -/* - * If the port was already initialised (eg, by a boot loader), - * try to determine the current setup. - */ -static void __init atmel_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - unsigned int mr, quot; - - /* - * If the baud rate generator isn't running, the port wasn't - * initialized by the boot loader. - */ - quot = UART_GET_BRGR(port) & ATMEL_US_CD; - if (!quot) - return; - - mr = UART_GET_MR(port) & ATMEL_US_CHRL; - if (mr == ATMEL_US_CHRL_8) - *bits = 8; - else - *bits = 7; - - mr = UART_GET_MR(port) & ATMEL_US_PAR; - if (mr == ATMEL_US_PAR_EVEN) - *parity = 'e'; - else if (mr == ATMEL_US_PAR_ODD) - *parity = 'o'; - - /* - * The serial core only rounds down when matching this to a - * supported baud rate. Make sure we don't end up slightly - * lower than one of those, as it would make us fall through - * to a much lower baud rate than we really want. - */ - *baud = port->uartclk / (16 * (quot - 1)); -} - -static int __init atmel_console_setup(struct console *co, char *options) -{ - struct uart_port *port = &atmel_ports[co->index].uart; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (port->membase == NULL) { - /* Port not initialized yet - delay setup */ - return -ENODEV; - } - - clk_enable(atmel_ports[co->index].clk); - - UART_PUT_IDR(port, -1); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - atmel_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver atmel_uart; - -static struct console atmel_console = { - .name = ATMEL_DEVICENAME, - .write = atmel_console_write, - .device = uart_console_device, - .setup = atmel_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &atmel_uart, -}; - -#define ATMEL_CONSOLE_DEVICE (&atmel_console) - -/* - * Early console initialization (before VM subsystem initialized). - */ -static int __init atmel_console_init(void) -{ - if (atmel_default_console_device) { - add_preferred_console(ATMEL_DEVICENAME, - atmel_default_console_device->id, NULL); - atmel_init_port(&atmel_ports[atmel_default_console_device->id], - atmel_default_console_device); - register_console(&atmel_console); - } - - return 0; -} - -console_initcall(atmel_console_init); - -/* - * Late console initialization. - */ -static int __init atmel_late_console_init(void) -{ - if (atmel_default_console_device - && !(atmel_console.flags & CON_ENABLED)) - register_console(&atmel_console); - - return 0; -} - -core_initcall(atmel_late_console_init); - -static inline bool atmel_is_console_port(struct uart_port *port) -{ - return port->cons && port->cons->index == port->line; -} - -#else -#define ATMEL_CONSOLE_DEVICE NULL - -static inline bool atmel_is_console_port(struct uart_port *port) -{ - return false; -} -#endif - -static struct uart_driver atmel_uart = { - .owner = THIS_MODULE, - .driver_name = "atmel_serial", - .dev_name = ATMEL_DEVICENAME, - .major = SERIAL_ATMEL_MAJOR, - .minor = MINOR_START, - .nr = ATMEL_MAX_UART, - .cons = ATMEL_CONSOLE_DEVICE, -}; - -#ifdef CONFIG_PM -static bool atmel_serial_clk_will_stop(void) -{ -#ifdef CONFIG_ARCH_AT91 - return at91_suspend_entering_slow_clock(); -#else - return false; -#endif -} - -static int atmel_serial_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - if (atmel_is_console_port(port) && console_suspend_enabled) { - /* Drain the TX shifter */ - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) - cpu_relax(); - } - - /* we can not wake up if we're running on slow clock */ - atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); - if (atmel_serial_clk_will_stop()) - device_set_wakeup_enable(&pdev->dev, 0); - - uart_suspend_port(&atmel_uart, port); - - return 0; -} - -static int atmel_serial_resume(struct platform_device *pdev) -{ - struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - - uart_resume_port(&atmel_uart, port); - device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); - - return 0; -} -#else -#define atmel_serial_suspend NULL -#define atmel_serial_resume NULL -#endif - -static int __devinit atmel_serial_probe(struct platform_device *pdev) -{ - struct atmel_uart_port *port; - void *data; - int ret; - - BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); - - port = &atmel_ports[pdev->id]; - port->backup_imr = 0; - - atmel_init_port(port, pdev); - - if (!atmel_use_dma_rx(&port->uart)) { - ret = -ENOMEM; - data = kmalloc(sizeof(struct atmel_uart_char) - * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); - if (!data) - goto err_alloc_ring; - port->rx_ring.buf = data; - } - - ret = uart_add_one_port(&atmel_uart, &port->uart); - if (ret) - goto err_add_port; - -#ifdef CONFIG_SERIAL_ATMEL_CONSOLE - if (atmel_is_console_port(&port->uart) - && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { - /* - * The serial core enabled the clock for us, so undo - * the clk_enable() in atmel_console_setup() - */ - clk_disable(port->clk); - } -#endif - - device_init_wakeup(&pdev->dev, 1); - platform_set_drvdata(pdev, port); - - return 0; - -err_add_port: - kfree(port->rx_ring.buf); - port->rx_ring.buf = NULL; -err_alloc_ring: - if (!atmel_is_console_port(&port->uart)) { - clk_put(port->clk); - port->clk = NULL; - } - - return ret; -} - -static int __devexit atmel_serial_remove(struct platform_device *pdev) -{ - struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int ret = 0; - - device_init_wakeup(&pdev->dev, 0); - platform_set_drvdata(pdev, NULL); - - ret = uart_remove_one_port(&atmel_uart, port); - - tasklet_kill(&atmel_port->tasklet); - kfree(atmel_port->rx_ring.buf); - - /* "port" is allocated statically, so we shouldn't free it */ - - clk_put(atmel_port->clk); - - return ret; -} - -static struct platform_driver atmel_serial_driver = { - .probe = atmel_serial_probe, - .remove = __devexit_p(atmel_serial_remove), - .suspend = atmel_serial_suspend, - .resume = atmel_serial_resume, - .driver = { - .name = "atmel_usart", - .owner = THIS_MODULE, - }, -}; - -static int __init atmel_serial_init(void) -{ - int ret; - - ret = uart_register_driver(&atmel_uart); - if (ret) - return ret; - - ret = platform_driver_register(&atmel_serial_driver); - if (ret) - uart_unregister_driver(&atmel_uart); - - return ret; -} - -static void __exit atmel_serial_exit(void) -{ - platform_driver_unregister(&atmel_serial_driver); - uart_unregister_driver(&atmel_uart); -} - -module_init(atmel_serial_init); -module_exit(atmel_serial_exit); - -MODULE_AUTHOR("Rick Bronson"); -MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:atmel_usart"); diff --git a/drivers/serial/bcm63xx_uart.c b/drivers/serial/bcm63xx_uart.c deleted file mode 100644 index a1a0e55d0807..000000000000 --- a/drivers/serial/bcm63xx_uart.c +++ /dev/null @@ -1,891 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Derived from many drivers using generic_serial interface. - * - * Copyright (C) 2008 Maxime Bizon - * - * Serial driver for BCM63xx integrated UART. - * - * Hardware flow control was _not_ tested since I only have RX/TX on - * my board. - */ - -#if defined(CONFIG_SERIAL_BCM63XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define BCM63XX_NR_UARTS 2 - -static struct uart_port ports[BCM63XX_NR_UARTS]; - -/* - * rx interrupt mask / stat - * - * mask: - * - rx fifo full - * - rx fifo above threshold - * - rx fifo not empty for too long - */ -#define UART_RX_INT_MASK (UART_IR_MASK(UART_IR_RXOVER) | \ - UART_IR_MASK(UART_IR_RXTHRESH) | \ - UART_IR_MASK(UART_IR_RXTIMEOUT)) - -#define UART_RX_INT_STAT (UART_IR_STAT(UART_IR_RXOVER) | \ - UART_IR_STAT(UART_IR_RXTHRESH) | \ - UART_IR_STAT(UART_IR_RXTIMEOUT)) - -/* - * tx interrupt mask / stat - * - * mask: - * - tx fifo empty - * - tx fifo below threshold - */ -#define UART_TX_INT_MASK (UART_IR_MASK(UART_IR_TXEMPTY) | \ - UART_IR_MASK(UART_IR_TXTRESH)) - -#define UART_TX_INT_STAT (UART_IR_STAT(UART_IR_TXEMPTY) | \ - UART_IR_STAT(UART_IR_TXTRESH)) - -/* - * external input interrupt - * - * mask: any edge on CTS, DCD - */ -#define UART_EXTINP_INT_MASK (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \ - UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD)) - -/* - * handy uart register accessor - */ -static inline unsigned int bcm_uart_readl(struct uart_port *port, - unsigned int offset) -{ - return bcm_readl(port->membase + offset); -} - -static inline void bcm_uart_writel(struct uart_port *port, - unsigned int value, unsigned int offset) -{ - bcm_writel(value, port->membase + offset); -} - -/* - * serial core request to check if uart tx fifo is empty - */ -static unsigned int bcm_uart_tx_empty(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_IR_REG); - return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0; -} - -/* - * serial core request to set RTS and DTR pin state and loopback mode - */ -static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_MCTL_REG); - val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK); - /* invert of written value is reflected on the pin */ - if (!(mctrl & TIOCM_DTR)) - val |= UART_MCTL_DTR_MASK; - if (!(mctrl & TIOCM_RTS)) - val |= UART_MCTL_RTS_MASK; - bcm_uart_writel(port, val, UART_MCTL_REG); - - val = bcm_uart_readl(port, UART_CTL_REG); - if (mctrl & TIOCM_LOOP) - val |= UART_CTL_LOOPBACK_MASK; - else - val &= ~UART_CTL_LOOPBACK_MASK; - bcm_uart_writel(port, val, UART_CTL_REG); -} - -/* - * serial core request to return RI, CTS, DCD and DSR pin state - */ -static unsigned int bcm_uart_get_mctrl(struct uart_port *port) -{ - unsigned int val, mctrl; - - mctrl = 0; - val = bcm_uart_readl(port, UART_EXTINP_REG); - if (val & UART_EXTINP_RI_MASK) - mctrl |= TIOCM_RI; - if (val & UART_EXTINP_CTS_MASK) - mctrl |= TIOCM_CTS; - if (val & UART_EXTINP_DCD_MASK) - mctrl |= TIOCM_CD; - if (val & UART_EXTINP_DSR_MASK) - mctrl |= TIOCM_DSR; - return mctrl; -} - -/* - * serial core request to disable tx ASAP (used for flow control) - */ -static void bcm_uart_stop_tx(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_CTL_REG); - val &= ~(UART_CTL_TXEN_MASK); - bcm_uart_writel(port, val, UART_CTL_REG); - - val = bcm_uart_readl(port, UART_IR_REG); - val &= ~UART_TX_INT_MASK; - bcm_uart_writel(port, val, UART_IR_REG); -} - -/* - * serial core request to (re)enable tx - */ -static void bcm_uart_start_tx(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_IR_REG); - val |= UART_TX_INT_MASK; - bcm_uart_writel(port, val, UART_IR_REG); - - val = bcm_uart_readl(port, UART_CTL_REG); - val |= UART_CTL_TXEN_MASK; - bcm_uart_writel(port, val, UART_CTL_REG); -} - -/* - * serial core request to stop rx, called before port shutdown - */ -static void bcm_uart_stop_rx(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_IR_REG); - val &= ~UART_RX_INT_MASK; - bcm_uart_writel(port, val, UART_IR_REG); -} - -/* - * serial core request to enable modem status interrupt reporting - */ -static void bcm_uart_enable_ms(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_IR_REG); - val |= UART_IR_MASK(UART_IR_EXTIP); - bcm_uart_writel(port, val, UART_IR_REG); -} - -/* - * serial core request to start/stop emitting break char - */ -static void bcm_uart_break_ctl(struct uart_port *port, int ctl) -{ - unsigned long flags; - unsigned int val; - - spin_lock_irqsave(&port->lock, flags); - - val = bcm_uart_readl(port, UART_CTL_REG); - if (ctl) - val |= UART_CTL_XMITBRK_MASK; - else - val &= ~UART_CTL_XMITBRK_MASK; - bcm_uart_writel(port, val, UART_CTL_REG); - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* - * return port type in string format - */ -static const char *bcm_uart_type(struct uart_port *port) -{ - return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL; -} - -/* - * read all chars in rx fifo and send them to core - */ -static void bcm_uart_do_rx(struct uart_port *port) -{ - struct tty_struct *tty; - unsigned int max_count; - - /* limit number of char read in interrupt, should not be - * higher than fifo size anyway since we're much faster than - * serial port */ - max_count = 32; - tty = port->state->port.tty; - do { - unsigned int iestat, c, cstat; - char flag; - - /* get overrun/fifo empty information from ier - * register */ - iestat = bcm_uart_readl(port, UART_IR_REG); - if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) - break; - - cstat = c = bcm_uart_readl(port, UART_FIFO_REG); - port->icount.rx++; - flag = TTY_NORMAL; - c &= 0xff; - - if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) { - /* do stats first */ - if (cstat & UART_FIFO_BRKDET_MASK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } - - if (cstat & UART_FIFO_PARERR_MASK) - port->icount.parity++; - if (cstat & UART_FIFO_FRAMEERR_MASK) - port->icount.frame++; - - /* update flag wrt read_status_mask */ - cstat &= port->read_status_mask; - if (cstat & UART_FIFO_BRKDET_MASK) - flag = TTY_BREAK; - if (cstat & UART_FIFO_FRAMEERR_MASK) - flag = TTY_FRAME; - if (cstat & UART_FIFO_PARERR_MASK) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(port, c)) - continue; - - if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { - port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - if ((cstat & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, c, flag); - - } while (--max_count); - - tty_flip_buffer_push(tty); -} - -/* - * fill tx fifo with chars to send, stop when fifo is about to be full - * or when all chars have been sent. - */ -static void bcm_uart_do_tx(struct uart_port *port) -{ - struct circ_buf *xmit; - unsigned int val, max_count; - - if (port->x_char) { - bcm_uart_writel(port, port->x_char, UART_FIFO_REG); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_tx_stopped(port)) { - bcm_uart_stop_tx(port); - return; - } - - xmit = &port->state->xmit; - if (uart_circ_empty(xmit)) - goto txq_empty; - - val = bcm_uart_readl(port, UART_MCTL_REG); - val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; - max_count = port->fifosize - val; - - while (max_count--) { - unsigned int c; - - c = xmit->buf[xmit->tail]; - bcm_uart_writel(port, c, UART_FIFO_REG); - 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); - - if (uart_circ_empty(xmit)) - goto txq_empty; - return; - -txq_empty: - /* nothing to send, disable transmit interrupt */ - val = bcm_uart_readl(port, UART_IR_REG); - val &= ~UART_TX_INT_MASK; - bcm_uart_writel(port, val, UART_IR_REG); - return; -} - -/* - * process uart interrupt - */ -static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) -{ - struct uart_port *port; - unsigned int irqstat; - - port = dev_id; - spin_lock(&port->lock); - - irqstat = bcm_uart_readl(port, UART_IR_REG); - if (irqstat & UART_RX_INT_STAT) - bcm_uart_do_rx(port); - - if (irqstat & UART_TX_INT_STAT) - bcm_uart_do_tx(port); - - if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) { - unsigned int estat; - - estat = bcm_uart_readl(port, UART_EXTINP_REG); - if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS)) - uart_handle_cts_change(port, - estat & UART_EXTINP_CTS_MASK); - if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD)) - uart_handle_dcd_change(port, - estat & UART_EXTINP_DCD_MASK); - } - - spin_unlock(&port->lock); - return IRQ_HANDLED; -} - -/* - * enable rx & tx operation on uart - */ -static void bcm_uart_enable(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_CTL_REG); - val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); - bcm_uart_writel(port, val, UART_CTL_REG); -} - -/* - * disable rx & tx operation on uart - */ -static void bcm_uart_disable(struct uart_port *port) -{ - unsigned int val; - - val = bcm_uart_readl(port, UART_CTL_REG); - val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | - UART_CTL_RXEN_MASK); - bcm_uart_writel(port, val, UART_CTL_REG); -} - -/* - * clear all unread data in rx fifo and unsent data in tx fifo - */ -static void bcm_uart_flush(struct uart_port *port) -{ - unsigned int val; - - /* empty rx and tx fifo */ - val = bcm_uart_readl(port, UART_CTL_REG); - val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK; - bcm_uart_writel(port, val, UART_CTL_REG); - - /* read any pending char to make sure all irq status are - * cleared */ - (void)bcm_uart_readl(port, UART_FIFO_REG); -} - -/* - * serial core request to initialize uart and start rx operation - */ -static int bcm_uart_startup(struct uart_port *port) -{ - unsigned int val; - int ret; - - /* mask all irq and flush port */ - bcm_uart_disable(port); - bcm_uart_writel(port, 0, UART_IR_REG); - bcm_uart_flush(port); - - /* clear any pending external input interrupt */ - (void)bcm_uart_readl(port, UART_EXTINP_REG); - - /* set rx/tx fifo thresh to fifo half size */ - val = bcm_uart_readl(port, UART_MCTL_REG); - val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK); - val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT; - val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT; - bcm_uart_writel(port, val, UART_MCTL_REG); - - /* set rx fifo timeout to 1 char time */ - val = bcm_uart_readl(port, UART_CTL_REG); - val &= ~UART_CTL_RXTMOUTCNT_MASK; - val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT; - bcm_uart_writel(port, val, UART_CTL_REG); - - /* report any edge on dcd and cts */ - val = UART_EXTINP_INT_MASK; - val |= UART_EXTINP_DCD_NOSENSE_MASK; - val |= UART_EXTINP_CTS_NOSENSE_MASK; - bcm_uart_writel(port, val, UART_EXTINP_REG); - - /* register irq and enable rx interrupts */ - ret = request_irq(port->irq, bcm_uart_interrupt, 0, - bcm_uart_type(port), port); - if (ret) - return ret; - bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG); - bcm_uart_enable(port); - return 0; -} - -/* - * serial core request to flush & disable uart - */ -static void bcm_uart_shutdown(struct uart_port *port) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - bcm_uart_writel(port, 0, UART_IR_REG); - spin_unlock_irqrestore(&port->lock, flags); - - bcm_uart_disable(port); - bcm_uart_flush(port); - free_irq(port->irq, port); -} - -/* - * serial core request to change current uart setting - */ -static void bcm_uart_set_termios(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) -{ - unsigned int ctl, baud, quot, ier; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - /* disable uart while changing speed */ - bcm_uart_disable(port); - bcm_uart_flush(port); - - /* update Control register */ - ctl = bcm_uart_readl(port, UART_CTL_REG); - ctl &= ~UART_CTL_BITSPERSYM_MASK; - - switch (new->c_cflag & CSIZE) { - case CS5: - ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT); - break; - case CS6: - ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT); - break; - case CS7: - ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT); - break; - default: - ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT); - break; - } - - ctl &= ~UART_CTL_STOPBITS_MASK; - if (new->c_cflag & CSTOPB) - ctl |= UART_CTL_STOPBITS_2; - else - ctl |= UART_CTL_STOPBITS_1; - - ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK); - if (new->c_cflag & PARENB) - ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK); - ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK); - if (new->c_cflag & PARODD) - ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK); - bcm_uart_writel(port, ctl, UART_CTL_REG); - - /* update Baudword register */ - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); - quot = uart_get_divisor(port, baud) - 1; - bcm_uart_writel(port, quot, UART_BAUD_REG); - - /* update Interrupt register */ - ier = bcm_uart_readl(port, UART_IR_REG); - - ier &= ~UART_IR_MASK(UART_IR_EXTIP); - if (UART_ENABLE_MS(port, new->c_cflag)) - ier |= UART_IR_MASK(UART_IR_EXTIP); - - bcm_uart_writel(port, ier, UART_IR_REG); - - /* update read/ignore mask */ - port->read_status_mask = UART_FIFO_VALID_MASK; - if (new->c_iflag & INPCK) { - port->read_status_mask |= UART_FIFO_FRAMEERR_MASK; - port->read_status_mask |= UART_FIFO_PARERR_MASK; - } - if (new->c_iflag & (BRKINT)) - port->read_status_mask |= UART_FIFO_BRKDET_MASK; - - port->ignore_status_mask = 0; - if (new->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_FIFO_PARERR_MASK; - if (new->c_iflag & IGNBRK) - port->ignore_status_mask |= UART_FIFO_BRKDET_MASK; - if (!(new->c_cflag & CREAD)) - port->ignore_status_mask |= UART_FIFO_VALID_MASK; - - uart_update_timeout(port, new->c_cflag, baud); - bcm_uart_enable(port); - spin_unlock_irqrestore(&port->lock, flags); -} - -/* - * serial core request to claim uart iomem - */ -static int bcm_uart_request_port(struct uart_port *port) -{ - unsigned int size; - - size = RSET_UART_SIZE; - if (!request_mem_region(port->mapbase, size, "bcm63xx")) { - dev_err(port->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, size); - return -EBUSY; - } - return 0; -} - -/* - * serial core request to release uart iomem - */ -static void bcm_uart_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, RSET_UART_SIZE); - iounmap(port->membase); -} - -/* - * serial core request to do any port required autoconfiguration - */ -static void bcm_uart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - if (bcm_uart_request_port(port)) - return; - port->type = PORT_BCM63XX; - } -} - -/* - * serial core request to check that port information in serinfo are - * suitable - */ -static int bcm_uart_verify_port(struct uart_port *port, - struct serial_struct *serinfo) -{ - if (port->type != PORT_BCM63XX) - return -EINVAL; - if (port->irq != serinfo->irq) - return -EINVAL; - if (port->iotype != serinfo->io_type) - return -EINVAL; - if (port->mapbase != (unsigned long)serinfo->iomem_base) - return -EINVAL; - return 0; -} - -/* serial core callbacks */ -static struct uart_ops bcm_uart_ops = { - .tx_empty = bcm_uart_tx_empty, - .get_mctrl = bcm_uart_get_mctrl, - .set_mctrl = bcm_uart_set_mctrl, - .start_tx = bcm_uart_start_tx, - .stop_tx = bcm_uart_stop_tx, - .stop_rx = bcm_uart_stop_rx, - .enable_ms = bcm_uart_enable_ms, - .break_ctl = bcm_uart_break_ctl, - .startup = bcm_uart_startup, - .shutdown = bcm_uart_shutdown, - .set_termios = bcm_uart_set_termios, - .type = bcm_uart_type, - .release_port = bcm_uart_release_port, - .request_port = bcm_uart_request_port, - .config_port = bcm_uart_config_port, - .verify_port = bcm_uart_verify_port, -}; - - - -#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE -static inline void wait_for_xmitr(struct uart_port *port) -{ - unsigned int tmout; - - /* Wait up to 10ms for the character(s) to be sent. */ - tmout = 10000; - while (--tmout) { - unsigned int val; - - val = bcm_uart_readl(port, UART_IR_REG); - if (val & UART_IR_STAT(UART_IR_TXEMPTY)) - break; - udelay(1); - } - - /* Wait up to 1s for flow control if necessary */ - if (port->flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout) { - unsigned int val; - - val = bcm_uart_readl(port, UART_EXTINP_REG); - if (val & UART_EXTINP_CTS_MASK) - break; - udelay(1); - } - } -} - -/* - * output given char - */ -static void bcm_console_putchar(struct uart_port *port, int ch) -{ - wait_for_xmitr(port); - bcm_uart_writel(port, ch, UART_FIFO_REG); -} - -/* - * console core request to output given string - */ -static void bcm_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_port *port; - unsigned long flags; - int locked; - - port = &ports[co->index]; - - local_irq_save(flags); - if (port->sysrq) { - /* bcm_uart_interrupt() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else { - spin_lock(&port->lock); - locked = 1; - } - - /* call helper to deal with \r\n */ - uart_console_write(port, s, count, bcm_console_putchar); - - /* and wait for char to be transmitted */ - wait_for_xmitr(port); - - if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); -} - -/* - * console core request to setup given console, find matching uart - * port and setup it. - */ -static int bcm_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index < 0 || co->index >= BCM63XX_NR_UARTS) - return -EINVAL; - port = &ports[co->index]; - 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 bcm_uart_driver; - -static struct console bcm63xx_console = { - .name = "ttyS", - .write = bcm_console_write, - .device = uart_console_device, - .setup = bcm_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &bcm_uart_driver, -}; - -static int __init bcm63xx_console_init(void) -{ - register_console(&bcm63xx_console); - return 0; -} - -console_initcall(bcm63xx_console_init); - -#define BCM63XX_CONSOLE (&bcm63xx_console) -#else -#define BCM63XX_CONSOLE NULL -#endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */ - -static struct uart_driver bcm_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "bcm63xx_uart", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = BCM63XX_NR_UARTS, - .cons = BCM63XX_CONSOLE, -}; - -/* - * platform driver probe/remove callback - */ -static int __devinit bcm_uart_probe(struct platform_device *pdev) -{ - struct resource *res_mem, *res_irq; - struct uart_port *port; - struct clk *clk; - int ret; - - if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) - return -EINVAL; - - if (ports[pdev->id].membase) - return -EBUSY; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_mem) - return -ENODEV; - - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) - return -ENODEV; - - clk = clk_get(&pdev->dev, "periph"); - if (IS_ERR(clk)) - return -ENODEV; - - port = &ports[pdev->id]; - memset(port, 0, sizeof(*port)); - port->iotype = UPIO_MEM; - port->mapbase = res_mem->start; - port->irq = res_irq->start; - port->ops = &bcm_uart_ops; - port->flags = UPF_BOOT_AUTOCONF; - port->dev = &pdev->dev; - port->fifosize = 16; - port->uartclk = clk_get_rate(clk) / 2; - port->line = pdev->id; - clk_put(clk); - - ret = uart_add_one_port(&bcm_uart_driver, port); - if (ret) { - ports[pdev->id].membase = 0; - return ret; - } - platform_set_drvdata(pdev, port); - return 0; -} - -static int __devexit bcm_uart_remove(struct platform_device *pdev) -{ - struct uart_port *port; - - port = platform_get_drvdata(pdev); - uart_remove_one_port(&bcm_uart_driver, port); - platform_set_drvdata(pdev, NULL); - /* mark port as free */ - ports[pdev->id].membase = 0; - return 0; -} - -/* - * platform driver stuff - */ -static struct platform_driver bcm_uart_platform_driver = { - .probe = bcm_uart_probe, - .remove = __devexit_p(bcm_uart_remove), - .driver = { - .owner = THIS_MODULE, - .name = "bcm63xx_uart", - }, -}; - -static int __init bcm_uart_init(void) -{ - int ret; - - ret = uart_register_driver(&bcm_uart_driver); - if (ret) - return ret; - - ret = platform_driver_register(&bcm_uart_platform_driver); - if (ret) - uart_unregister_driver(&bcm_uart_driver); - - return ret; -} - -static void __exit bcm_uart_exit(void) -{ - platform_driver_unregister(&bcm_uart_platform_driver); - uart_unregister_driver(&bcm_uart_driver); -} - -module_init(bcm_uart_init); -module_exit(bcm_uart_exit); - -MODULE_AUTHOR("Maxime Bizon "); -MODULE_DESCRIPTION("Broadcom 63 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase) -#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr) -#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v)) -#include - -#ifdef CONFIG_SERIAL_BFIN_MODULE -# undef CONFIG_EARLY_PRINTK -#endif - -#ifdef CONFIG_SERIAL_BFIN_MODULE -# undef CONFIG_EARLY_PRINTK -#endif - -/* UART name and device definitions */ -#define BFIN_SERIAL_DEV_NAME "ttyBF" -#define BFIN_SERIAL_MAJOR 204 -#define BFIN_SERIAL_MINOR 64 - -static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS]; - -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - -# ifndef CONFIG_SERIAL_BFIN_PIO -# error KGDB only support UART in PIO mode. -# endif - -static int kgdboc_port_line; -static int kgdboc_break_enabled; -#endif -/* - * Setup for console. Argument comes from the menuconfig - */ -#define DMA_RX_XCOUNT 512 -#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT) - -#define DMA_RX_FLUSH_JIFFIES (HZ / 50) - -#ifdef CONFIG_SERIAL_BFIN_DMA -static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); -#else -static void bfin_serial_tx_chars(struct bfin_serial_port *uart); -#endif - -static void bfin_serial_reset_irda(struct uart_port *port); - -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) -static unsigned int bfin_serial_get_mctrl(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - if (uart->cts_pin < 0) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - - /* CTS PIN is negative assertive. */ - if (UART_GET_CTS(uart)) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - else - return TIOCM_DSR | TIOCM_CAR; -} - -static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - if (uart->rts_pin < 0) - return; - - /* RTS PIN is negative assertive. */ - if (mctrl & TIOCM_RTS) - UART_ENABLE_RTS(uart); - else - UART_DISABLE_RTS(uart); -} - -/* - * Handle any change of modem status signal. - */ -static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) -{ - struct bfin_serial_port *uart = dev_id; - unsigned int status; - - status = bfin_serial_get_mctrl(&uart->port); - uart_handle_cts_change(&uart->port, status & TIOCM_CTS); -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - uart->scts = 1; - UART_CLEAR_SCTS(uart); - UART_CLEAR_IER(uart, EDSSI); -#endif - - return IRQ_HANDLED; -} -#else -static unsigned int bfin_serial_get_mctrl(struct uart_port *port) -{ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -} - -static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} -#endif - -/* - * interrupts are disabled on entry - */ -static void bfin_serial_stop_tx(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -#ifdef CONFIG_SERIAL_BFIN_DMA - struct circ_buf *xmit = &uart->port.state->xmit; -#endif - - while (!(UART_GET_LSR(uart) & TEMT)) - cpu_relax(); - -#ifdef CONFIG_SERIAL_BFIN_DMA - disable_dma(uart->tx_dma_channel); - xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); - uart->port.icount.tx += uart->tx_count; - uart->tx_count = 0; - uart->tx_done = 1; -#else -#ifdef CONFIG_BF54x - /* Clear TFI bit */ - UART_PUT_LSR(uart, TFI); -#endif - UART_CLEAR_IER(uart, ETBEI); -#endif -} - -/* - * port is locked and interrupts are disabled - */ -static void bfin_serial_start_tx(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - struct tty_struct *tty = uart->port.state->port.tty; - -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { - uart->scts = 0; - uart_handle_cts_change(&uart->port, uart->scts); - } -#endif - - /* - * To avoid losting RX interrupt, we reset IR function - * before sending data. - */ - if (tty->termios->c_line == N_IRDA) - bfin_serial_reset_irda(port); - -#ifdef CONFIG_SERIAL_BFIN_DMA - if (uart->tx_done) - bfin_serial_dma_tx_chars(uart); -#else - UART_SET_IER(uart, ETBEI); - bfin_serial_tx_chars(uart); -#endif -} - -/* - * Interrupts are enabled - */ -static void bfin_serial_stop_rx(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - - UART_CLEAR_IER(uart, ERBFI); -} - -/* - * Set the modem control timer to fire immediately. - */ -static void bfin_serial_enable_ms(struct uart_port *port) -{ -} - - -#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO) -# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold) -# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v)) -#else -# define UART_GET_ANOMALY_THRESHOLD(uart) 0 -# define UART_SET_ANOMALY_THRESHOLD(uart, v) -#endif - -#ifdef CONFIG_SERIAL_BFIN_PIO -static void bfin_serial_rx_chars(struct bfin_serial_port *uart) -{ - struct tty_struct *tty = NULL; - unsigned int status, ch, flg; - static struct timeval anomaly_start = { .tv_sec = 0 }; - - status = UART_GET_LSR(uart); - UART_CLEAR_LSR(uart); - - ch = UART_GET_CHAR(uart); - uart->port.icount.rx++; - -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - if (kgdb_connected && kgdboc_port_line == uart->port.line - && kgdboc_break_enabled) - if (ch == 0x3) {/* Ctrl + C */ - kgdb_breakpoint(); - return; - } - - if (!uart->port.state || !uart->port.state->port.tty) - return; -#endif - tty = uart->port.state->port.tty; - - if (ANOMALY_05000363) { - /* The BF533 (and BF561) family of processors have a nice anomaly - * where they continuously generate characters for a "single" break. - * We have to basically ignore this flood until the "next" valid - * character comes across. Due to the nature of the flood, it is - * not possible to reliably catch bytes that are sent too quickly - * after this break. So application code talking to the Blackfin - * which sends a break signal must allow at least 1.5 character - * times after the end of the break for things to stabilize. This - * timeout was picked as it must absolutely be larger than 1 - * character time +/- some percent. So 1.5 sounds good. All other - * Blackfin families operate properly. Woo. - */ - if (anomaly_start.tv_sec) { - struct timeval curr; - suseconds_t usecs; - - if ((~ch & (~ch + 1)) & 0xff) - goto known_good_char; - - do_gettimeofday(&curr); - if (curr.tv_sec - anomaly_start.tv_sec > 1) - goto known_good_char; - - usecs = 0; - if (curr.tv_sec != anomaly_start.tv_sec) - usecs += USEC_PER_SEC; - usecs += curr.tv_usec - anomaly_start.tv_usec; - - if (usecs > UART_GET_ANOMALY_THRESHOLD(uart)) - goto known_good_char; - - if (ch) - anomaly_start.tv_sec = 0; - else - anomaly_start = curr; - - return; - - known_good_char: - status &= ~BI; - anomaly_start.tv_sec = 0; - } - } - - if (status & BI) { - if (ANOMALY_05000363) - if (bfin_revid() < 5) - do_gettimeofday(&anomaly_start); - uart->port.icount.brk++; - if (uart_handle_break(&uart->port)) - goto ignore_char; - status &= ~(PE | FE); - } - if (status & PE) - uart->port.icount.parity++; - if (status & OE) - uart->port.icount.overrun++; - if (status & FE) - uart->port.icount.frame++; - - status &= uart->port.read_status_mask; - - if (status & BI) - flg = TTY_BREAK; - else if (status & PE) - flg = TTY_PARITY; - else if (status & FE) - flg = TTY_FRAME; - else - flg = TTY_NORMAL; - - if (uart_handle_sysrq_char(&uart->port, ch)) - goto ignore_char; - - uart_insert_char(&uart->port, status, OE, ch, flg); - - ignore_char: - tty_flip_buffer_push(tty); -} - -static void bfin_serial_tx_chars(struct bfin_serial_port *uart) -{ - struct circ_buf *xmit = &uart->port.state->xmit; - - if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { -#ifdef CONFIG_BF54x - /* Clear TFI bit */ - UART_PUT_LSR(uart, TFI); -#endif - /* Anomaly notes: - * 05000215 - we always clear ETBEI within last UART TX - * interrupt to end a string. It is always set - * when start a new tx. - */ - UART_CLEAR_IER(uart, ETBEI); - return; - } - - if (uart->port.x_char) { - UART_PUT_CHAR(uart, uart->port.x_char); - uart->port.icount.tx++; - uart->port.x_char = 0; - } - - while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { - UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uart->port.icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uart->port); -} - -static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) -{ - struct bfin_serial_port *uart = dev_id; - - spin_lock(&uart->port.lock); - while (UART_GET_LSR(uart) & DR) - bfin_serial_rx_chars(uart); - spin_unlock(&uart->port.lock); - - return IRQ_HANDLED; -} - -static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) -{ - struct bfin_serial_port *uart = dev_id; - -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { - uart->scts = 0; - uart_handle_cts_change(&uart->port, uart->scts); - } -#endif - spin_lock(&uart->port.lock); - if (UART_GET_LSR(uart) & THRE) - bfin_serial_tx_chars(uart); - spin_unlock(&uart->port.lock); - - return IRQ_HANDLED; -} -#endif - -#ifdef CONFIG_SERIAL_BFIN_DMA -static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) -{ - struct circ_buf *xmit = &uart->port.state->xmit; - - uart->tx_done = 0; - - if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { - uart->tx_count = 0; - uart->tx_done = 1; - return; - } - - if (uart->port.x_char) { - UART_PUT_CHAR(uart, uart->port.x_char); - uart->port.icount.tx++; - uart->port.x_char = 0; - } - - uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); - if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail)) - uart->tx_count = UART_XMIT_SIZE - xmit->tail; - blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail), - (unsigned long)(xmit->buf+xmit->tail+uart->tx_count)); - set_dma_config(uart->tx_dma_channel, - set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, - INTR_ON_BUF, - DIMENSION_LINEAR, - DATA_SIZE_8, - DMA_SYNC_RESTART)); - set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); - set_dma_x_count(uart->tx_dma_channel, uart->tx_count); - set_dma_x_modify(uart->tx_dma_channel, 1); - SSYNC(); - enable_dma(uart->tx_dma_channel); - - UART_SET_IER(uart, ETBEI); -} - -static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) -{ - struct tty_struct *tty = uart->port.state->port.tty; - int i, flg, status; - - status = UART_GET_LSR(uart); - UART_CLEAR_LSR(uart); - - uart->port.icount.rx += - CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, - UART_XMIT_SIZE); - - if (status & BI) { - uart->port.icount.brk++; - if (uart_handle_break(&uart->port)) - goto dma_ignore_char; - status &= ~(PE | FE); - } - if (status & PE) - uart->port.icount.parity++; - if (status & OE) - uart->port.icount.overrun++; - if (status & FE) - uart->port.icount.frame++; - - status &= uart->port.read_status_mask; - - if (status & BI) - flg = TTY_BREAK; - else if (status & PE) - flg = TTY_PARITY; - else if (status & FE) - flg = TTY_FRAME; - else - flg = TTY_NORMAL; - - for (i = uart->rx_dma_buf.tail; ; i++) { - if (i >= UART_XMIT_SIZE) - i = 0; - if (i == uart->rx_dma_buf.head) - break; - if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) - uart_insert_char(&uart->port, status, OE, - uart->rx_dma_buf.buf[i], flg); - } - - dma_ignore_char: - tty_flip_buffer_push(tty); -} - -void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) -{ - int x_pos, pos; - - dma_disable_irq(uart->tx_dma_channel); - dma_disable_irq(uart->rx_dma_channel); - spin_lock_bh(&uart->port.lock); - - /* 2D DMA RX buffer ring is used. Because curr_y_count and - * curr_x_count can't be read as an atomic operation, - * curr_y_count should be read before curr_x_count. When - * curr_x_count is read, curr_y_count may already indicate - * next buffer line. But, the position calculated here is - * still indicate the old line. The wrong position data may - * be smaller than current buffer tail, which cause garbages - * are received if it is not prohibit. - */ - uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); - x_pos = get_dma_curr_xcount(uart->rx_dma_channel); - uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; - if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) - uart->rx_dma_nrows = 0; - x_pos = DMA_RX_XCOUNT - x_pos; - if (x_pos == DMA_RX_XCOUNT) - x_pos = 0; - - pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; - /* Ignore receiving data if new position is in the same line of - * current buffer tail and small. - */ - if (pos > uart->rx_dma_buf.tail || - uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { - uart->rx_dma_buf.head = pos; - bfin_serial_dma_rx_chars(uart); - uart->rx_dma_buf.tail = uart->rx_dma_buf.head; - } - - spin_unlock_bh(&uart->port.lock); - dma_enable_irq(uart->tx_dma_channel); - dma_enable_irq(uart->rx_dma_channel); - - mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); -} - -static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) -{ - struct bfin_serial_port *uart = dev_id; - struct circ_buf *xmit = &uart->port.state->xmit; - -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) { - uart->scts = 0; - uart_handle_cts_change(&uart->port, uart->scts); - } -#endif - - spin_lock(&uart->port.lock); - if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { - disable_dma(uart->tx_dma_channel); - clear_dma_irqstat(uart->tx_dma_channel); - /* Anomaly notes: - * 05000215 - we always clear ETBEI within last UART TX - * interrupt to end a string. It is always set - * when start a new tx. - */ - UART_CLEAR_IER(uart, ETBEI); - xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); - uart->port.icount.tx += uart->tx_count; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uart->port); - - bfin_serial_dma_tx_chars(uart); - } - - spin_unlock(&uart->port.lock); - return IRQ_HANDLED; -} - -static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) -{ - struct bfin_serial_port *uart = dev_id; - unsigned short irqstat; - int x_pos, pos; - - spin_lock(&uart->port.lock); - irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); - clear_dma_irqstat(uart->rx_dma_channel); - - uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); - x_pos = get_dma_curr_xcount(uart->rx_dma_channel); - uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; - if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) - uart->rx_dma_nrows = 0; - - pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; - if (pos > uart->rx_dma_buf.tail || - uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { - uart->rx_dma_buf.head = pos; - bfin_serial_dma_rx_chars(uart); - uart->rx_dma_buf.tail = uart->rx_dma_buf.head; - } - - spin_unlock(&uart->port.lock); - - return IRQ_HANDLED; -} -#endif - -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int bfin_serial_tx_empty(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned short lsr; - - lsr = UART_GET_LSR(uart); - if (lsr & TEMT) - return TIOCSER_TEMT; - else - return 0; -} - -static void bfin_serial_break_ctl(struct uart_port *port, int break_state) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - u16 lcr = UART_GET_LCR(uart); - if (break_state) - lcr |= SB; - else - lcr &= ~SB; - UART_PUT_LCR(uart, lcr); - SSYNC(); -} - -static int bfin_serial_startup(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - -#ifdef CONFIG_SERIAL_BFIN_DMA - dma_addr_t dma_handle; - - if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) { - printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n"); - return -EBUSY; - } - - if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) { - printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n"); - free_dma(uart->rx_dma_channel); - return -EBUSY; - } - - set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart); - set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart); - - uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); - uart->rx_dma_buf.head = 0; - uart->rx_dma_buf.tail = 0; - uart->rx_dma_nrows = 0; - - set_dma_config(uart->rx_dma_channel, - set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, - INTR_ON_ROW, DIMENSION_2D, - DATA_SIZE_8, - DMA_SYNC_RESTART)); - set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT); - set_dma_x_modify(uart->rx_dma_channel, 1); - set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT); - set_dma_y_modify(uart->rx_dma_channel, 1); - set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf); - enable_dma(uart->rx_dma_channel); - - uart->rx_dma_timer.data = (unsigned long)(uart); - uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout; - uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; - add_timer(&(uart->rx_dma_timer)); -#else -# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled) - kgdboc_break_enabled = 0; - else { -# endif - if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, - "BFIN_UART_RX", uart)) { - printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); - return -EBUSY; - } - - if (request_irq - (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, - "BFIN_UART_TX", uart)) { - printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); - free_irq(uart->port.irq, uart); - return -EBUSY; - } - -# ifdef CONFIG_BF54x - { - /* - * UART2 and UART3 on BF548 share interrupt PINs and DMA - * controllers with SPORT2 and SPORT3. UART rx and tx - * interrupts are generated in PIO mode only when configure - * their peripheral mapping registers properly, which means - * request corresponding DMA channels in PIO mode as well. - */ - unsigned uart_dma_ch_rx, uart_dma_ch_tx; - - switch (uart->port.irq) { - case IRQ_UART3_RX: - uart_dma_ch_rx = CH_UART3_RX; - uart_dma_ch_tx = CH_UART3_TX; - break; - case IRQ_UART2_RX: - uart_dma_ch_rx = CH_UART2_RX; - uart_dma_ch_tx = CH_UART2_TX; - break; - default: - uart_dma_ch_rx = uart_dma_ch_tx = 0; - break; - }; - - if (uart_dma_ch_rx && - request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { - printk(KERN_NOTICE"Fail to attach UART interrupt\n"); - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq + 1, uart); - return -EBUSY; - } - if (uart_dma_ch_tx && - request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { - printk(KERN_NOTICE "Fail to attach UART interrupt\n"); - free_dma(uart_dma_ch_rx); - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq + 1, uart); - return -EBUSY; - } - } -# endif -# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - } -# endif -#endif - -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - if (uart->cts_pin >= 0) { - if (request_irq(gpio_to_irq(uart->cts_pin), - bfin_serial_mctrl_cts_int, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_DISABLED, "BFIN_UART_CTS", uart)) { - uart->cts_pin = -1; - pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n"); - } - } - if (uart->rts_pin >= 0) { - gpio_direction_output(uart->rts_pin, 0); - } -#endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (uart->cts_pin >= 0 && request_irq(uart->status_irq, - bfin_serial_mctrl_cts_int, - IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { - uart->cts_pin = -1; - pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n"); - } - - /* CTS RTS PINs are negative assertive. */ - UART_PUT_MCR(uart, ACTS); - UART_SET_IER(uart, EDSSI); -#endif - - UART_SET_IER(uart, ERBFI); - return 0; -} - -static void bfin_serial_shutdown(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - -#ifdef CONFIG_SERIAL_BFIN_DMA - disable_dma(uart->tx_dma_channel); - free_dma(uart->tx_dma_channel); - disable_dma(uart->rx_dma_channel); - free_dma(uart->rx_dma_channel); - del_timer(&(uart->rx_dma_timer)); - dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); -#else -#ifdef CONFIG_BF54x - switch (uart->port.irq) { - case IRQ_UART3_RX: - free_dma(CH_UART3_RX); - free_dma(CH_UART3_TX); - break; - case IRQ_UART2_RX: - free_dma(CH_UART2_RX); - free_dma(CH_UART2_TX); - break; - default: - break; - }; -#endif - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq+1, uart); -#endif - -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - if (uart->cts_pin >= 0) - free_irq(gpio_to_irq(uart->cts_pin), uart); -#endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (uart->cts_pin >= 0) - free_irq(uart->status_irq, uart); -#endif -} - -static void -bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned long flags; - unsigned int baud, quot; - unsigned short val, ier, lcr = 0; - - switch (termios->c_cflag & CSIZE) { - case CS8: - lcr = WLS(8); - break; - case CS7: - lcr = WLS(7); - break; - case CS6: - lcr = WLS(6); - break; - case CS5: - lcr = WLS(5); - break; - default: - printk(KERN_ERR "%s: word lengh not supported\n", - __func__); - } - - /* Anomaly notes: - * 05000231 - STOP bit is always set to 1 whatever the user is set. - */ - if (termios->c_cflag & CSTOPB) { - if (ANOMALY_05000231) - printk(KERN_WARNING "STOP bits other than 1 is not " - "supported in case of anomaly 05000231.\n"); - else - lcr |= STB; - } - if (termios->c_cflag & PARENB) - lcr |= PEN; - if (!(termios->c_cflag & PARODD)) - lcr |= EPS; - if (termios->c_cflag & CMSPAR) - lcr |= STP; - - spin_lock_irqsave(&uart->port.lock, flags); - - port->read_status_mask = OE; - if (termios->c_iflag & INPCK) - port->read_status_mask |= (FE | PE); - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= BI; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= FE | PE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= OE; - } - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - /* If discipline is not IRDA, apply ANOMALY_05000230 */ - if (termios->c_line != N_IRDA) - quot -= ANOMALY_05000230; - - UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); - - /* Disable UART */ - ier = UART_GET_IER(uart); - UART_DISABLE_INTS(uart); - - /* Set DLAB in LCR to Access DLL and DLH */ - UART_SET_DLAB(uart); - - UART_PUT_DLL(uart, quot & 0xFF); - UART_PUT_DLH(uart, (quot >> 8) & 0xFF); - SSYNC(); - - /* Clear DLAB in LCR to Access THR RBR IER */ - UART_CLEAR_DLAB(uart); - - UART_PUT_LCR(uart, lcr); - - /* Enable UART */ - UART_ENABLE_INTS(uart, ier); - - val = UART_GET_GCTL(uart); - val |= UCEN; - UART_PUT_GCTL(uart, val); - - /* Port speed changed, update the per-port timeout. */ - uart_update_timeout(port, termios->c_cflag, baud); - - spin_unlock_irqrestore(&uart->port.lock, flags); -} - -static const char *bfin_serial_type(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - - return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void bfin_serial_release_port(struct uart_port *port) -{ -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int bfin_serial_request_port(struct uart_port *port) -{ - return 0; -} - -/* - * Configure/autoconfigure the port. - */ -static void bfin_serial_config_port(struct uart_port *port, int flags) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - - if (flags & UART_CONFIG_TYPE && - bfin_serial_request_port(&uart->port) == 0) - uart->port.type = PORT_BFIN; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_BFIN and PORT_UNKNOWN - */ -static int -bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return 0; -} - -/* - * Enable the IrDA function if tty->ldisc.num is N_IRDA. - * In other cases, disable IrDA function. - */ -static void bfin_serial_set_ldisc(struct uart_port *port, int ld) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned short val; - - switch (ld) { - case N_IRDA: - val = UART_GET_GCTL(uart); - val |= (IREN | RPOLC); - UART_PUT_GCTL(uart, val); - break; - default: - val = UART_GET_GCTL(uart); - val &= ~(IREN | RPOLC); - UART_PUT_GCTL(uart, val); - } -} - -static void bfin_serial_reset_irda(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned short val; - - val = UART_GET_GCTL(uart); - val &= ~(IREN | RPOLC); - UART_PUT_GCTL(uart, val); - SSYNC(); - val |= (IREN | RPOLC); - UART_PUT_GCTL(uart, val); - SSYNC(); -} - -#ifdef CONFIG_CONSOLE_POLL -/* Anomaly notes: - * 05000099 - Because we only use THRE in poll_put and DR in poll_get, - * losing other bits of UART_LSR is not a problem here. - */ -static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - - while (!(UART_GET_LSR(uart) & THRE)) - cpu_relax(); - - UART_CLEAR_DLAB(uart); - UART_PUT_CHAR(uart, (unsigned char)chr); -} - -static int bfin_serial_poll_get_char(struct uart_port *port) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned char chr; - - while (!(UART_GET_LSR(uart) & DR)) - cpu_relax(); - - UART_CLEAR_DLAB(uart); - chr = UART_GET_CHAR(uart); - - return chr; -} -#endif - -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) -static void bfin_kgdboc_port_shutdown(struct uart_port *port) -{ - if (kgdboc_break_enabled) { - kgdboc_break_enabled = 0; - bfin_serial_shutdown(port); - } -} - -static int bfin_kgdboc_port_startup(struct uart_port *port) -{ - kgdboc_port_line = port->line; - kgdboc_break_enabled = !bfin_serial_startup(port); - return 0; -} -#endif - -static struct uart_ops bfin_serial_pops = { - .tx_empty = bfin_serial_tx_empty, - .set_mctrl = bfin_serial_set_mctrl, - .get_mctrl = bfin_serial_get_mctrl, - .stop_tx = bfin_serial_stop_tx, - .start_tx = bfin_serial_start_tx, - .stop_rx = bfin_serial_stop_rx, - .enable_ms = bfin_serial_enable_ms, - .break_ctl = bfin_serial_break_ctl, - .startup = bfin_serial_startup, - .shutdown = bfin_serial_shutdown, - .set_termios = bfin_serial_set_termios, - .set_ldisc = bfin_serial_set_ldisc, - .type = bfin_serial_type, - .release_port = bfin_serial_release_port, - .request_port = bfin_serial_request_port, - .config_port = bfin_serial_config_port, - .verify_port = bfin_serial_verify_port, -#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ - defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) - .kgdboc_port_startup = bfin_kgdboc_port_startup, - .kgdboc_port_shutdown = bfin_kgdboc_port_shutdown, -#endif -#ifdef CONFIG_CONSOLE_POLL - .poll_put_char = bfin_serial_poll_put_char, - .poll_get_char = bfin_serial_poll_get_char, -#endif -}; - -#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) -/* - * If the port was already initialised (eg, by a boot loader), - * try to determine the current setup. - */ -static void __init -bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, - int *parity, int *bits) -{ - unsigned short status; - - status = UART_GET_IER(uart) & (ERBFI | ETBEI); - if (status == (ERBFI | ETBEI)) { - /* ok, the port was enabled */ - u16 lcr, dlh, dll; - - lcr = UART_GET_LCR(uart); - - *parity = 'n'; - if (lcr & PEN) { - if (lcr & EPS) - *parity = 'e'; - else - *parity = 'o'; - } - switch (lcr & 0x03) { - case 0: *bits = 5; break; - case 1: *bits = 6; break; - case 2: *bits = 7; break; - case 3: *bits = 8; break; - } - /* Set DLAB in LCR to Access DLL and DLH */ - UART_SET_DLAB(uart); - - dll = UART_GET_DLL(uart); - dlh = UART_GET_DLH(uart); - - /* Clear DLAB in LCR to Access THR RBR IER */ - UART_CLEAR_DLAB(uart); - - *baud = get_sclk() / (16*(dll | dlh << 8)); - } - pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); -} - -static struct uart_driver bfin_serial_reg; - -static void bfin_serial_console_putchar(struct uart_port *port, int ch) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - while (!(UART_GET_LSR(uart) & THRE)) - barrier(); - UART_PUT_CHAR(uart, ch); -} - -#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || - defined (CONFIG_EARLY_PRINTK) */ - -#ifdef CONFIG_SERIAL_BFIN_CONSOLE -#define CLASS_BFIN_CONSOLE "bfin-console" -/* - * Interrupts are disabled on entering - */ -static void -bfin_serial_console_write(struct console *co, const char *s, unsigned int count) -{ - struct bfin_serial_port *uart = bfin_serial_ports[co->index]; - unsigned long flags; - - spin_lock_irqsave(&uart->port.lock, flags); - uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); - spin_unlock_irqrestore(&uart->port.lock, flags); - -} - -static int __init -bfin_serial_console_setup(struct console *co, char *options) -{ - struct bfin_serial_port *uart; - int baud = 57600; - int bits = 8; - int parity = 'n'; -# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) - int flow = 'r'; -# else - int flow = 'n'; -# endif - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS) - return -ENODEV; - - uart = bfin_serial_ports[co->index]; - if (!uart) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - bfin_serial_console_get_options(uart, &baud, &parity, &bits); - - return uart_set_options(&uart->port, co, baud, parity, bits, flow); -} - -static struct console bfin_serial_console = { - .name = BFIN_SERIAL_DEV_NAME, - .write = bfin_serial_console_write, - .device = uart_console_device, - .setup = bfin_serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &bfin_serial_reg, -}; -#define BFIN_SERIAL_CONSOLE &bfin_serial_console -#else -#define BFIN_SERIAL_CONSOLE NULL -#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ - -#ifdef CONFIG_EARLY_PRINTK -static struct bfin_serial_port bfin_earlyprintk_port; -#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk" - -/* - * Interrupts are disabled on entering - */ -static void -bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count) -{ - unsigned long flags; - - if (bfin_earlyprintk_port.port.line != co->index) - return; - - spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags); - uart_console_write(&bfin_earlyprintk_port.port, s, count, - bfin_serial_console_putchar); - spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags); -} - -/* - * This should have a .setup or .early_setup in it, but then things get called - * without the command line options, and the baud rate gets messed up - so - * don't let the common infrastructure play with things. (see calls to setup - * & earlysetup in ./kernel/printk.c:register_console() - */ -static struct __initdata console bfin_early_serial_console = { - .name = "early_BFuart", - .write = bfin_earlyprintk_console_write, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &bfin_serial_reg, -}; -#endif - -static struct uart_driver bfin_serial_reg = { - .owner = THIS_MODULE, - .driver_name = DRIVER_NAME, - .dev_name = BFIN_SERIAL_DEV_NAME, - .major = BFIN_SERIAL_MAJOR, - .minor = BFIN_SERIAL_MINOR, - .nr = BFIN_UART_NR_PORTS, - .cons = BFIN_SERIAL_CONSOLE, -}; - -static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct bfin_serial_port *uart = platform_get_drvdata(pdev); - - return uart_suspend_port(&bfin_serial_reg, &uart->port); -} - -static int bfin_serial_resume(struct platform_device *pdev) -{ - struct bfin_serial_port *uart = platform_get_drvdata(pdev); - - return uart_resume_port(&bfin_serial_reg, &uart->port); -} - -static int bfin_serial_probe(struct platform_device *pdev) -{ - struct resource *res; - struct bfin_serial_port *uart = NULL; - int ret = 0; - - if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) { - dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n"); - return -ENOENT; - } - - if (bfin_serial_ports[pdev->id] == NULL) { - - uart = kzalloc(sizeof(*uart), GFP_KERNEL); - if (!uart) { - dev_err(&pdev->dev, - "fail to malloc bfin_serial_port\n"); - return -ENOMEM; - } - bfin_serial_ports[pdev->id] = uart; - -#ifdef CONFIG_EARLY_PRINTK - if (!(bfin_earlyprintk_port.port.membase - && bfin_earlyprintk_port.port.line == pdev->id)) { - /* - * If the peripheral PINs of current port is allocated - * in earlyprintk probe stage, don't do it again. - */ -#endif - ret = peripheral_request_list( - (unsigned short *)pdev->dev.platform_data, DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, - "fail to request bfin serial peripherals\n"); - goto out_error_free_mem; - } -#ifdef CONFIG_EARLY_PRINTK - } -#endif - - spin_lock_init(&uart->port.lock); - uart->port.uartclk = get_sclk(); - uart->port.fifosize = BFIN_UART_TX_FIFO_SIZE; - uart->port.ops = &bfin_serial_pops; - uart->port.line = pdev->id; - uart->port.iotype = UPIO_MEM; - uart->port.flags = UPF_BOOT_AUTOCONF; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - ret = -ENOENT; - goto out_error_free_peripherals; - } - - uart->port.membase = ioremap(res->start, - res->end - res->start); - if (!uart->port.membase) { - dev_err(&pdev->dev, "Cannot map uart IO\n"); - ret = -ENXIO; - goto out_error_free_peripherals; - } - uart->port.mapbase = res->start; - - uart->port.irq = platform_get_irq(pdev, 0); - if (uart->port.irq < 0) { - dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n"); - ret = -ENOENT; - goto out_error_unmap; - } - - uart->status_irq = platform_get_irq(pdev, 1); - if (uart->status_irq < 0) { - dev_err(&pdev->dev, "No uart status IRQ specified\n"); - ret = -ENOENT; - goto out_error_unmap; - } - -#ifdef CONFIG_SERIAL_BFIN_DMA - uart->tx_done = 1; - uart->tx_count = 0; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No uart TX DMA channel specified\n"); - ret = -ENOENT; - goto out_error_unmap; - } - uart->tx_dma_channel = res->start; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (res == NULL) { - dev_err(&pdev->dev, "No uart RX DMA channel specified\n"); - ret = -ENOENT; - goto out_error_unmap; - } - uart->rx_dma_channel = res->start; - - init_timer(&(uart->rx_dma_timer)); -#endif - -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) - uart->cts_pin = -1; - else - uart->cts_pin = res->start; - - res = platform_get_resource(pdev, IORESOURCE_IO, 1); - if (res == NULL) - uart->rts_pin = -1; - else - uart->rts_pin = res->start; -# if defined(CONFIG_SERIAL_BFIN_CTSRTS) - if (uart->rts_pin >= 0) - gpio_request(uart->rts_pin, DRIVER_NAME); -# endif -#endif - } - -#ifdef CONFIG_SERIAL_BFIN_CONSOLE - if (!is_early_platform_device(pdev)) { -#endif - uart = bfin_serial_ports[pdev->id]; - uart->port.dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, uart); - ret = uart_add_one_port(&bfin_serial_reg, &uart->port); -#ifdef CONFIG_SERIAL_BFIN_CONSOLE - } -#endif - - if (!ret) - return 0; - - if (uart) { -out_error_unmap: - iounmap(uart->port.membase); -out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)pdev->dev.platform_data); -out_error_free_mem: - kfree(uart); - bfin_serial_ports[pdev->id] = NULL; - } - - return ret; -} - -static int __devexit bfin_serial_remove(struct platform_device *pdev) -{ - struct bfin_serial_port *uart = platform_get_drvdata(pdev); - - dev_set_drvdata(&pdev->dev, NULL); - - if (uart) { - uart_remove_one_port(&bfin_serial_reg, &uart->port); -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - if (uart->rts_pin >= 0) - gpio_free(uart->rts_pin); -#endif - iounmap(uart->port.membase); - peripheral_free_list( - (unsigned short *)pdev->dev.platform_data); - kfree(uart); - bfin_serial_ports[pdev->id] = NULL; - } - - return 0; -} - -static struct platform_driver bfin_serial_driver = { - .probe = bfin_serial_probe, - .remove = __devexit_p(bfin_serial_remove), - .suspend = bfin_serial_suspend, - .resume = bfin_serial_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -#if defined(CONFIG_SERIAL_BFIN_CONSOLE) -static __initdata struct early_platform_driver early_bfin_serial_driver = { - .class_str = CLASS_BFIN_CONSOLE, - .pdrv = &bfin_serial_driver, - .requested_id = EARLY_PLATFORM_ID_UNSET, -}; - -static int __init bfin_serial_rs_console_init(void) -{ - early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME); - - early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0); - - register_console(&bfin_serial_console); - - return 0; -} -console_initcall(bfin_serial_rs_console_init); -#endif - -#ifdef CONFIG_EARLY_PRINTK -/* - * Memory can't be allocated dynamically during earlyprink init stage. - * So, do individual probe for earlyprink with a static uart port variable. - */ -static int bfin_earlyprintk_probe(struct platform_device *pdev) -{ - struct resource *res; - int ret; - - if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) { - dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n"); - return -ENOENT; - } - - ret = peripheral_request_list( - (unsigned short *)pdev->dev.platform_data, DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, - "fail to request bfin serial peripherals\n"); - return ret; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - ret = -ENOENT; - goto out_error_free_peripherals; - } - - bfin_earlyprintk_port.port.membase = ioremap(res->start, - res->end - res->start); - if (!bfin_earlyprintk_port.port.membase) { - dev_err(&pdev->dev, "Cannot map uart IO\n"); - ret = -ENXIO; - goto out_error_free_peripherals; - } - bfin_earlyprintk_port.port.mapbase = res->start; - bfin_earlyprintk_port.port.line = pdev->id; - bfin_earlyprintk_port.port.uartclk = get_sclk(); - bfin_earlyprintk_port.port.fifosize = BFIN_UART_TX_FIFO_SIZE; - spin_lock_init(&bfin_earlyprintk_port.port.lock); - - return 0; - -out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)pdev->dev.platform_data); - - return ret; -} - -static struct platform_driver bfin_earlyprintk_driver = { - .probe = bfin_earlyprintk_probe, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = { - .class_str = CLASS_BFIN_EARLYPRINTK, - .pdrv = &bfin_earlyprintk_driver, - .requested_id = EARLY_PLATFORM_ID_UNSET, -}; - -struct console __init *bfin_earlyserial_init(unsigned int port, - unsigned int cflag) -{ - struct ktermios t; - char port_name[20]; - - if (port < 0 || port >= BFIN_UART_NR_PORTS) - return NULL; - - /* - * Only probe resource of the given port in earlyprintk boot arg. - * The expected port id should be indicated in port name string. - */ - snprintf(port_name, 20, DRIVER_NAME ".%d", port); - early_platform_driver_register(&early_bfin_earlyprintk_driver, - port_name); - early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0); - - if (!bfin_earlyprintk_port.port.membase) - return NULL; - -#ifdef CONFIG_SERIAL_BFIN_CONSOLE - /* - * If we are using early serial, don't let the normal console rewind - * log buffer, since that causes things to be printed multiple times - */ - bfin_serial_console.flags &= ~CON_PRINTBUFFER; -#endif - - bfin_early_serial_console.index = port; - t.c_cflag = cflag; - t.c_iflag = 0; - t.c_oflag = 0; - t.c_lflag = ICANON; - t.c_line = port; - bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t); - - return &bfin_early_serial_console; -} -#endif /* CONFIG_EARLY_PRINTK */ - -static int __init bfin_serial_init(void) -{ - int ret; - - pr_info("Blackfin serial driver\n"); - - ret = uart_register_driver(&bfin_serial_reg); - if (ret) { - pr_err("failed to register %s:%d\n", - bfin_serial_reg.driver_name, ret); - } - - ret = platform_driver_register(&bfin_serial_driver); - if (ret) { - pr_err("fail to register bfin uart\n"); - uart_unregister_driver(&bfin_serial_reg); - } - - return ret; -} - -static void __exit bfin_serial_exit(void) -{ - platform_driver_unregister(&bfin_serial_driver); - uart_unregister_driver(&bfin_serial_reg); -} - - -module_init(bfin_serial_init); -module_exit(bfin_serial_exit); - -MODULE_AUTHOR("Sonic Zhang, Aubrey Li"); -MODULE_DESCRIPTION("Blackfin generic serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR); -MODULE_ALIAS("platform:bfin-uart"); diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c deleted file mode 100644 index e95c524d9d18..000000000000 --- a/drivers/serial/bfin_sport_uart.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * Blackfin On-Chip Sport Emulated UART Driver - * - * Copyright 2006-2009 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -/* - * This driver and the hardware supported are in term of EE-191 of ADI. - * http://www.analog.com/static/imported-files/application_notes/EE191.pdf - * This application note describe how to implement a UART on a Sharc DSP, - * but this driver is implemented on Blackfin Processor. - * Transmit Frame Sync is not used by this driver to transfer data out. - */ - -/* #define DEBUG */ - -#define DRV_NAME "bfin-sport-uart" -#define DEVICE_NAME "ttySS" -#define pr_fmt(fmt) DRV_NAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bfin_sport_uart.h" - -struct sport_uart_port { - struct uart_port port; - int err_irq; - unsigned short csize; - unsigned short rxmask; - unsigned short txmask1; - unsigned short txmask2; - unsigned char stopb; -/* unsigned char parib; */ -#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS - int cts_pin; - int rts_pin; -#endif -}; - -static int sport_uart_tx_chars(struct sport_uart_port *up); -static void sport_stop_tx(struct uart_port *port); - -static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) -{ - pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value, - up->txmask1, up->txmask2); - - /* Place Start and Stop bits */ - __asm__ __volatile__ ( - "%[val] <<= 1;" - "%[val] = %[val] & %[mask1];" - "%[val] = %[val] | %[mask2];" - : [val]"+d"(value) - : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2) - : "ASTAT" - ); - pr_debug("%s value:%x\n", __func__, value); - - SPORT_PUT_TX(up, value); -} - -static inline unsigned char rx_one_byte(struct sport_uart_port *up) -{ - unsigned int value; - unsigned char extract; - u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; - - if ((up->csize + up->stopb) > 7) - value = SPORT_GET_RX32(up); - else - value = SPORT_GET_RX(up); - - pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value, - up->csize, up->rxmask); - - /* Extract data */ - __asm__ __volatile__ ( - "%[extr] = 0;" - "%[mask1] = %[rxmask];" - "%[mask2] = 0x0200(Z);" - "%[shift] = 0;" - "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" - ".Lloop_s:" - "%[tmp] = extract(%[val], %[mask1].L)(Z);" - "%[tmp] <<= %[shift];" - "%[extr] = %[extr] | %[tmp];" - "%[mask1] = %[mask1] - %[mask2];" - ".Lloop_e:" - "%[shift] += 1;" - : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp), - [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2) - : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize) - : "ASTAT", "LB0", "LC0", "LT0" - ); - - pr_debug(" extract:%x\n", extract); - return extract; -} - -static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate) -{ - int tclkdiv, rclkdiv; - unsigned int sclk = get_sclk(); - - /* Set TCR1 and TCR2, TFSR is not enabled for uart */ - SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); - SPORT_PUT_TCR2(up, size + 1); - pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); - - /* Set RCR1 and RCR2 */ - SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK)); - SPORT_PUT_RCR2(up, (size + 1) * 2 - 1); - pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); - - tclkdiv = sclk / (2 * baud_rate) - 1; - /* The actual uart baud rate of devices vary between +/-2%. The sport - * RX sample rate should be faster than the double of the worst case, - * otherwise, wrong data are received. So, set sport RX clock to be - * 3% faster. - */ - rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1; - SPORT_PUT_TCLKDIV(up, tclkdiv); - SPORT_PUT_RCLKDIV(up, rclkdiv); - SSYNC(); - pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n", - __func__, sclk, baud_rate, tclkdiv, rclkdiv); - - return 0; -} - -static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) -{ - struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; - unsigned int ch; - - spin_lock(&up->port.lock); - - while (SPORT_GET_STAT(up) & RXNE) { - ch = rx_one_byte(up); - up->port.icount.rx++; - - if (!uart_handle_sysrq_char(&up->port, ch)) - tty_insert_flip_char(tty, ch, TTY_NORMAL); - } - tty_flip_buffer_push(tty); - - spin_unlock(&up->port.lock); - - return IRQ_HANDLED; -} - -static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) -{ - struct sport_uart_port *up = dev_id; - - spin_lock(&up->port.lock); - sport_uart_tx_chars(up); - spin_unlock(&up->port.lock); - - return IRQ_HANDLED; -} - -static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) -{ - struct sport_uart_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; - unsigned int stat = SPORT_GET_STAT(up); - - spin_lock(&up->port.lock); - - /* Overflow in RX FIFO */ - if (stat & ROVF) { - up->port.icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */ - } - /* These should not happen */ - if (stat & (TOVF | TUVF | RUVF)) { - pr_err("SPORT Error:%s %s %s\n", - (stat & TOVF) ? "TX overflow" : "", - (stat & TUVF) ? "TX underflow" : "", - (stat & RUVF) ? "RX underflow" : ""); - SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); - SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); - } - SSYNC(); - - spin_unlock(&up->port.lock); - return IRQ_HANDLED; -} - -#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS -static unsigned int sport_get_mctrl(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - if (up->cts_pin < 0) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - - /* CTS PIN is negative assertive. */ - if (SPORT_UART_GET_CTS(up)) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - else - return TIOCM_DSR | TIOCM_CAR; -} - -static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - if (up->rts_pin < 0) - return; - - /* RTS PIN is negative assertive. */ - if (mctrl & TIOCM_RTS) - SPORT_UART_ENABLE_RTS(up); - else - SPORT_UART_DISABLE_RTS(up); -} - -/* - * Handle any change of modem status signal. - */ -static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id) -{ - struct sport_uart_port *up = (struct sport_uart_port *)dev_id; - unsigned int status; - - status = sport_get_mctrl(&up->port); - uart_handle_cts_change(&up->port, status & TIOCM_CTS); - - return IRQ_HANDLED; -} -#else -static unsigned int sport_get_mctrl(struct uart_port *port) -{ - pr_debug("%s enter\n", __func__); - return TIOCM_CTS | TIOCM_CD | TIOCM_DSR; -} - -static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - pr_debug("%s enter\n", __func__); -} -#endif - -/* Reqeust IRQ, Setup clock */ -static int sport_startup(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - int ret; - - pr_debug("%s enter\n", __func__); - ret = request_irq(up->port.irq, sport_uart_rx_irq, 0, - "SPORT_UART_RX", up); - if (ret) { - dev_err(port->dev, "unable to request SPORT RX interrupt\n"); - return ret; - } - - ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0, - "SPORT_UART_TX", up); - if (ret) { - dev_err(port->dev, "unable to request SPORT TX interrupt\n"); - goto fail1; - } - - ret = request_irq(up->err_irq, sport_uart_err_irq, 0, - "SPORT_UART_STATUS", up); - if (ret) { - dev_err(port->dev, "unable to request SPORT status interrupt\n"); - goto fail2; - } - -#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS - if (up->cts_pin >= 0) { - if (request_irq(gpio_to_irq(up->cts_pin), - sport_mctrl_cts_int, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) { - up->cts_pin = -1; - dev_info(port->dev, "Unable to attach BlackFin UART \ - over SPORT CTS interrupt. So, disable it.\n"); - } - } - if (up->rts_pin >= 0) - gpio_direction_output(up->rts_pin, 0); -#endif - - return 0; - fail2: - free_irq(up->port.irq+1, up); - fail1: - free_irq(up->port.irq, up); - - return ret; -} - -/* - * sport_uart_tx_chars - * - * ret 1 means need to enable sport. - * ret 0 means do nothing. - */ -static int sport_uart_tx_chars(struct sport_uart_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - - if (SPORT_GET_STAT(up) & TXF) - return 0; - - if (up->port.x_char) { - tx_one_byte(up, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return 1; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - /* The waiting loop to stop SPORT TX from TX interrupt is - * too long. This may block SPORT RX interrupts and cause - * RX FIFO overflow. So, do stop sport TX only after the last - * char in TX FIFO is moved into the shift register. - */ - if (SPORT_GET_STAT(up) & TXHRE) - sport_stop_tx(&up->port); - return 0; - } - - while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) { - tx_one_byte(up, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); - up->port.icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - return 1; -} - -static unsigned int sport_tx_empty(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - unsigned int stat; - - stat = SPORT_GET_STAT(up); - pr_debug("%s stat:%04x\n", __func__, stat); - if (stat & TXHRE) { - return TIOCSER_TEMT; - } else - return 0; -} - -static void sport_stop_tx(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - pr_debug("%s enter\n", __func__); - - if (!(SPORT_GET_TCR1(up) & TSPEN)) - return; - - /* Although the hold register is empty, last byte is still in shift - * register and not sent out yet. So, put a dummy data into TX FIFO. - * Then, sport tx stops when last byte is shift out and the dummy - * data is moved into the shift register. - */ - SPORT_PUT_TX(up, 0xffff); - while (!(SPORT_GET_STAT(up) & TXHRE)) - cpu_relax(); - - SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); - SSYNC(); - - return; -} - -static void sport_start_tx(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - pr_debug("%s enter\n", __func__); - - /* Write data into SPORT FIFO before enable SPROT to transmit */ - if (sport_uart_tx_chars(up)) { - /* Enable transmit, then an interrupt will generated */ - SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); - SSYNC(); - } - - pr_debug("%s exit\n", __func__); -} - -static void sport_stop_rx(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - pr_debug("%s enter\n", __func__); - /* Disable sport to stop rx */ - SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); - SSYNC(); -} - -static void sport_enable_ms(struct uart_port *port) -{ - pr_debug("%s enter\n", __func__); -} - -static void sport_break_ctl(struct uart_port *port, int break_state) -{ - pr_debug("%s enter\n", __func__); -} - -static void sport_shutdown(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - dev_dbg(port->dev, "%s enter\n", __func__); - - /* Disable sport */ - SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); - SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); - SSYNC(); - - free_irq(up->port.irq, up); - free_irq(up->port.irq+1, up); - free_irq(up->err_irq, up); -#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS - if (up->cts_pin >= 0) - free_irq(gpio_to_irq(up->cts_pin), up); -#endif -} - -static const char *sport_type(struct uart_port *port) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - pr_debug("%s enter\n", __func__); - return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL; -} - -static void sport_release_port(struct uart_port *port) -{ - pr_debug("%s enter\n", __func__); -} - -static int sport_request_port(struct uart_port *port) -{ - pr_debug("%s enter\n", __func__); - return 0; -} - -static void sport_config_port(struct uart_port *port, int flags) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - pr_debug("%s enter\n", __func__); - up->port.type = PORT_BFIN_SPORT; -} - -static int sport_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - pr_debug("%s enter\n", __func__); - return 0; -} - -static void sport_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - unsigned long flags; - int i; - - pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); - - switch (termios->c_cflag & CSIZE) { - case CS8: - up->csize = 8; - break; - case CS7: - up->csize = 7; - break; - case CS6: - up->csize = 6; - break; - case CS5: - up->csize = 5; - break; - default: - pr_warning("requested word length not supported\n"); - } - - if (termios->c_cflag & CSTOPB) { - up->stopb = 1; - } - if (termios->c_cflag & PARENB) { - pr_warning("PAREN bits is not supported yet\n"); - /* up->parib = 1; */ - } - - spin_lock_irqsave(&up->port.lock, flags); - - port->read_status_mask = 0; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - - /* RX extract mask */ - up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8); - /* TX masks, 8 bit data and 1 bit stop for example: - * mask1 = b#0111111110 - * mask2 = b#1000000000 - */ - for (i = 0, up->txmask1 = 0; i < up->csize; i++) - up->txmask1 |= (1<txmask2 = (1<stopb) { - ++i; - up->txmask2 |= (1<txmask1 <<= 1; - up->txmask2 <<= 1; - /* uart baud rate */ - port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16); - - /* Disable UART */ - SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); - SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); - - sport_uart_setup(up, up->csize + up->stopb, port->uartclk); - - /* driver TX line high after config, one dummy data is - * necessary to stop sport after shift one byte - */ - SPORT_PUT_TX(up, 0xffff); - SPORT_PUT_TX(up, 0xffff); - SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); - SSYNC(); - while (!(SPORT_GET_STAT(up) & TXHRE)) - cpu_relax(); - SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); - SSYNC(); - - /* Port speed changed, update the per-port timeout. */ - uart_update_timeout(port, termios->c_cflag, port->uartclk); - - /* Enable sport rx */ - SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN); - SSYNC(); - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -struct uart_ops sport_uart_ops = { - .tx_empty = sport_tx_empty, - .set_mctrl = sport_set_mctrl, - .get_mctrl = sport_get_mctrl, - .stop_tx = sport_stop_tx, - .start_tx = sport_start_tx, - .stop_rx = sport_stop_rx, - .enable_ms = sport_enable_ms, - .break_ctl = sport_break_ctl, - .startup = sport_startup, - .shutdown = sport_shutdown, - .set_termios = sport_set_termios, - .type = sport_type, - .release_port = sport_release_port, - .request_port = sport_request_port, - .config_port = sport_config_port, - .verify_port = sport_verify_port, -}; - -#define BFIN_SPORT_UART_MAX_PORTS 4 - -static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS]; - -#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE -#define CLASS_BFIN_SPORT_CONSOLE "bfin-sport-console" - -static int __init -sport_uart_console_setup(struct console *co, char *options) -{ - struct sport_uart_port *up; - int baud = 57600; - int bits = 8; - int parity = 'n'; -# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS - int flow = 'r'; -# else - int flow = 'n'; -# endif - - /* Check whether an invalid uart number has been specified */ - if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS) - return -ENODEV; - - up = bfin_sport_uart_ports[co->index]; - if (!up) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&up->port, co, baud, parity, bits, flow); -} - -static void sport_uart_console_putchar(struct uart_port *port, int ch) -{ - struct sport_uart_port *up = (struct sport_uart_port *)port; - - while (SPORT_GET_STAT(up) & TXF) - barrier(); - - tx_one_byte(up, ch); -} - -/* - * Interrupts are disabled on entering - */ -static void -sport_uart_console_write(struct console *co, const char *s, unsigned int count) -{ - struct sport_uart_port *up = bfin_sport_uart_ports[co->index]; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - if (SPORT_GET_TCR1(up) & TSPEN) - uart_console_write(&up->port, s, count, sport_uart_console_putchar); - else { - /* dummy data to start sport */ - while (SPORT_GET_STAT(up) & TXF) - barrier(); - SPORT_PUT_TX(up, 0xffff); - /* Enable transmit, then an interrupt will generated */ - SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); - SSYNC(); - - uart_console_write(&up->port, s, count, sport_uart_console_putchar); - - /* Although the hold register is empty, last byte is still in shift - * register and not sent out yet. So, put a dummy data into TX FIFO. - * Then, sport tx stops when last byte is shift out and the dummy - * data is moved into the shift register. - */ - while (SPORT_GET_STAT(up) & TXF) - barrier(); - SPORT_PUT_TX(up, 0xffff); - while (!(SPORT_GET_STAT(up) & TXHRE)) - barrier(); - - /* Stop sport tx transfer */ - SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); - SSYNC(); - } - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static struct uart_driver sport_uart_reg; - -static struct console sport_uart_console = { - .name = DEVICE_NAME, - .write = sport_uart_console_write, - .device = uart_console_device, - .setup = sport_uart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sport_uart_reg, -}; - -#define SPORT_UART_CONSOLE (&sport_uart_console) -#else -#define SPORT_UART_CONSOLE NULL -#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */ - - -static struct uart_driver sport_uart_reg = { - .owner = THIS_MODULE, - .driver_name = DRV_NAME, - .dev_name = DEVICE_NAME, - .major = 204, - .minor = 84, - .nr = BFIN_SPORT_UART_MAX_PORTS, - .cons = SPORT_UART_CONSOLE, -}; - -#ifdef CONFIG_PM -static int sport_uart_suspend(struct device *dev) -{ - struct sport_uart_port *sport = dev_get_drvdata(dev); - - dev_dbg(dev, "%s enter\n", __func__); - if (sport) - uart_suspend_port(&sport_uart_reg, &sport->port); - - return 0; -} - -static int sport_uart_resume(struct device *dev) -{ - struct sport_uart_port *sport = dev_get_drvdata(dev); - - dev_dbg(dev, "%s enter\n", __func__); - if (sport) - uart_resume_port(&sport_uart_reg, &sport->port); - - return 0; -} - -static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = { - .suspend = sport_uart_suspend, - .resume = sport_uart_resume, -}; -#endif - -static int __devinit sport_uart_probe(struct platform_device *pdev) -{ - struct resource *res; - struct sport_uart_port *sport; - int ret = 0; - - dev_dbg(&pdev->dev, "%s enter\n", __func__); - - if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) { - dev_err(&pdev->dev, "Wrong sport uart platform device id.\n"); - return -ENOENT; - } - - if (bfin_sport_uart_ports[pdev->id] == NULL) { - bfin_sport_uart_ports[pdev->id] = - kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL); - sport = bfin_sport_uart_ports[pdev->id]; - if (!sport) { - dev_err(&pdev->dev, - "Fail to malloc sport_uart_port\n"); - return -ENOMEM; - } - - ret = peripheral_request_list( - (unsigned short *)pdev->dev.platform_data, DRV_NAME); - if (ret) { - dev_err(&pdev->dev, - "Fail to request SPORT peripherals\n"); - goto out_error_free_mem; - } - - spin_lock_init(&sport->port.lock); - sport->port.fifosize = SPORT_TX_FIFO_SIZE, - sport->port.ops = &sport_uart_ops; - sport->port.line = pdev->id; - sport->port.iotype = UPIO_MEM; - sport->port.flags = UPF_BOOT_AUTOCONF; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - ret = -ENOENT; - goto out_error_free_peripherals; - } - - sport->port.membase = ioremap(res->start, resource_size(res)); - if (!sport->port.membase) { - dev_err(&pdev->dev, "Cannot map sport IO\n"); - ret = -ENXIO; - goto out_error_free_peripherals; - } - sport->port.mapbase = res->start; - - sport->port.irq = platform_get_irq(pdev, 0); - if (sport->port.irq < 0) { - dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n"); - ret = -ENOENT; - goto out_error_unmap; - } - - sport->err_irq = platform_get_irq(pdev, 1); - if (sport->err_irq < 0) { - dev_err(&pdev->dev, "No sport status IRQ specified\n"); - ret = -ENOENT; - goto out_error_unmap; - } -#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) - sport->cts_pin = -1; - else - sport->cts_pin = res->start; - - res = platform_get_resource(pdev, IORESOURCE_IO, 1); - if (res == NULL) - sport->rts_pin = -1; - else - sport->rts_pin = res->start; - - if (sport->rts_pin >= 0) - gpio_request(sport->rts_pin, DRV_NAME); -#endif - } - -#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE - if (!is_early_platform_device(pdev)) { -#endif - sport = bfin_sport_uart_ports[pdev->id]; - sport->port.dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, sport); - ret = uart_add_one_port(&sport_uart_reg, &sport->port); -#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE - } -#endif - if (!ret) - return 0; - - if (sport) { -out_error_unmap: - iounmap(sport->port.membase); -out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)pdev->dev.platform_data); -out_error_free_mem: - kfree(sport); - bfin_sport_uart_ports[pdev->id] = NULL; - } - - return ret; -} - -static int __devexit sport_uart_remove(struct platform_device *pdev) -{ - struct sport_uart_port *sport = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s enter\n", __func__); - dev_set_drvdata(&pdev->dev, NULL); - - if (sport) { - uart_remove_one_port(&sport_uart_reg, &sport->port); -#ifdef CONFIG_SERIAL_BFIN_CTSRTS - if (sport->rts_pin >= 0) - gpio_free(sport->rts_pin); -#endif - iounmap(sport->port.membase); - peripheral_free_list( - (unsigned short *)pdev->dev.platform_data); - kfree(sport); - bfin_sport_uart_ports[pdev->id] = NULL; - } - - return 0; -} - -static struct platform_driver sport_uart_driver = { - .probe = sport_uart_probe, - .remove = __devexit_p(sport_uart_remove), - .driver = { - .name = DRV_NAME, -#ifdef CONFIG_PM - .pm = &bfin_sport_uart_dev_pm_ops, -#endif - }, -}; - -#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE -static __initdata struct early_platform_driver early_sport_uart_driver = { - .class_str = CLASS_BFIN_SPORT_CONSOLE, - .pdrv = &sport_uart_driver, - .requested_id = EARLY_PLATFORM_ID_UNSET, -}; - -static int __init sport_uart_rs_console_init(void) -{ - early_platform_driver_register(&early_sport_uart_driver, DRV_NAME); - - early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE, - BFIN_SPORT_UART_MAX_PORTS, 0); - - register_console(&sport_uart_console); - - return 0; -} -console_initcall(sport_uart_rs_console_init); -#endif - -static int __init sport_uart_init(void) -{ - int ret; - - pr_info("Blackfin uart over sport driver\n"); - - ret = uart_register_driver(&sport_uart_reg); - if (ret) { - pr_err("failed to register %s:%d\n", - sport_uart_reg.driver_name, ret); - return ret; - } - - ret = platform_driver_register(&sport_uart_driver); - if (ret) { - pr_err("failed to register sport uart driver:%d\n", ret); - uart_unregister_driver(&sport_uart_reg); - } - - return ret; -} -module_init(sport_uart_init); - -static void __exit sport_uart_exit(void) -{ - platform_driver_unregister(&sport_uart_driver); - uart_unregister_driver(&sport_uart_reg); -} -module_exit(sport_uart_exit); - -MODULE_AUTHOR("Sonic Zhang, Roy Huang"); -MODULE_DESCRIPTION("Blackfin serial over SPORT driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h deleted file mode 100644 index 6d06ce1d5675..000000000000 --- a/drivers/serial/bfin_sport_uart.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Blackfin On-Chip Sport Emulated UART Driver - * - * Copyright 2006-2008 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -/* - * This driver and the hardware supported are in term of EE-191 of ADI. - * http://www.analog.com/static/imported-files/application_notes/EE191.pdf - * This application note describe how to implement a UART on a Sharc DSP, - * but this driver is implemented on Blackfin Processor. - * Transmit Frame Sync is not used by this driver to transfer data out. - */ - -#ifndef _BFIN_SPORT_UART_H -#define _BFIN_SPORT_UART_H - -#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */ -#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */ -#define OFFSET_TCLKDIV 0x08 /* Transmit Serial Clock Divider Register */ -#define OFFSET_TFSDIV 0x0C /* Transmit Frame Sync Divider Register */ -#define OFFSET_TX 0x10 /* Transmit Data Register */ -#define OFFSET_RX 0x18 /* Receive Data Register */ -#define OFFSET_RCR1 0x20 /* Receive Configuration 1 Register */ -#define OFFSET_RCR2 0x24 /* Receive Configuration 2 Register */ -#define OFFSET_RCLKDIV 0x28 /* Receive Serial Clock Divider Register */ -#define OFFSET_RFSDIV 0x2c /* Receive Frame Sync Divider Register */ -#define OFFSET_STAT 0x30 /* Status Register */ - -#define SPORT_GET_TCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR1)) -#define SPORT_GET_TCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR2)) -#define SPORT_GET_TCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV)) -#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV)) -#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX)) -#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX)) -/* - * If another interrupt fires while doing a 32-bit read from RX FIFO, - * a fake RX underflow error will be generated. So disable interrupts - * to prevent interruption while reading the FIFO. - */ -#define SPORT_GET_RX32(sport) \ -({ \ - unsigned int __ret; \ - if (ANOMALY_05000473) \ - local_irq_disable(); \ - __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \ - if (ANOMALY_05000473) \ - local_irq_enable(); \ - __ret; \ -}) -#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1)) -#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2)) -#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV)) -#define SPORT_GET_RFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RFSDIV)) -#define SPORT_GET_STAT(sport) bfin_read16(((sport)->port.membase + OFFSET_STAT)) - -#define SPORT_PUT_TCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR1), v) -#define SPORT_PUT_TCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR2), v) -#define SPORT_PUT_TCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v) -#define SPORT_PUT_TFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v) -#define SPORT_PUT_TX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TX), v) -#define SPORT_PUT_RX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RX), v) -#define SPORT_PUT_RCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR1), v) -#define SPORT_PUT_RCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR2), v) -#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v) -#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v) -#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v) - -#define SPORT_TX_FIFO_SIZE 8 - -#define SPORT_UART_GET_CTS(x) gpio_get_value(x->cts_pin) -#define SPORT_UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1) -#define SPORT_UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0) - -#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \ - || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \ - || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \ - || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS) -# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS -#endif - -#endif /* _BFIN_SPORT_UART_H */ diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c deleted file mode 100644 index b6acd19b458e..000000000000 --- a/drivers/serial/clps711x.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - * linux/drivers/char/clps711x.c - * - * Driver for CLPS711x serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * 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 - */ - -#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define UART_NR 2 - -#define SERIAL_CLPS711X_MAJOR 204 -#define SERIAL_CLPS711X_MINOR 40 -#define SERIAL_CLPS711X_NR UART_NR - -/* - * We use the relevant SYSCON register as a base address for these ports. - */ -#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) -#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) -#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) -#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) - -#define TX_IRQ(port) ((port)->irq) -#define RX_IRQ(port) ((port)->irq + 1) - -#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) - -#define tx_enabled(port) ((port)->unused[0]) - -static void clps711xuart_stop_tx(struct uart_port *port) -{ - if (tx_enabled(port)) { - disable_irq(TX_IRQ(port)); - tx_enabled(port) = 0; - } -} - -static void clps711xuart_start_tx(struct uart_port *port) -{ - if (!tx_enabled(port)) { - enable_irq(TX_IRQ(port)); - tx_enabled(port) = 1; - } -} - -static void clps711xuart_stop_rx(struct uart_port *port) -{ - disable_irq(RX_IRQ(port)); -} - -static void clps711xuart_enable_ms(struct uart_port *port) -{ -} - -static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; - unsigned int status, ch, flg; - - status = clps_readl(SYSFLG(port)); - while (!(status & SYSFLG_URXFE)) { - ch = clps_readl(UARTDR(port)); - - port->icount.rx++; - - flg = TTY_NORMAL; - - /* - * Note that the error handling code is - * out of the main execution path - */ - if (unlikely(ch & UART_ANY_ERR)) { - if (ch & UARTDR_PARERR) - port->icount.parity++; - else if (ch & UARTDR_FRMERR) - port->icount.frame++; - if (ch & UARTDR_OVERR) - port->icount.overrun++; - - ch &= port->read_status_mask; - - if (ch & UARTDR_PARERR) - flg = TTY_PARITY; - else if (ch & UARTDR_FRMERR) - flg = TTY_FRAME; - -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - /* - * CHECK: does overrun affect the current character? - * ASSUMPTION: it does not. - */ - uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); - - ignore_char: - status = clps_readl(SYSFLG(port)); - } - tty_flip_buffer_push(tty); - return IRQ_HANDLED; -} - -static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - clps_writel(port->x_char, UARTDR(port)); - port->icount.tx++; - port->x_char = 0; - return IRQ_HANDLED; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - clps711xuart_stop_tx(port); - return IRQ_HANDLED; - } - - count = port->fifosize >> 1; - do { - clps_writel(xmit->buf[xmit->tail], UARTDR(port)); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - clps711xuart_stop_tx(port); - - return IRQ_HANDLED; -} - -static unsigned int clps711xuart_tx_empty(struct uart_port *port) -{ - unsigned int status = clps_readl(SYSFLG(port)); - return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; -} - -static unsigned int clps711xuart_get_mctrl(struct uart_port *port) -{ - unsigned int port_addr; - unsigned int result = 0; - unsigned int status; - - port_addr = SYSFLG(port); - if (port_addr == SYSFLG1) { - status = clps_readl(SYSFLG1); - if (status & SYSFLG1_DCD) - result |= TIOCM_CAR; - if (status & SYSFLG1_DSR) - result |= TIOCM_DSR; - if (status & SYSFLG1_CTS) - result |= TIOCM_CTS; - } - - return result; -} - -static void -clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) -{ -} - -static void clps711xuart_break_ctl(struct uart_port *port, int break_state) -{ - unsigned long flags; - unsigned int ubrlcr; - - spin_lock_irqsave(&port->lock, flags); - ubrlcr = clps_readl(UBRLCR(port)); - if (break_state == -1) - ubrlcr |= UBRLCR_BREAK; - else - ubrlcr &= ~UBRLCR_BREAK; - clps_writel(ubrlcr, UBRLCR(port)); - spin_unlock_irqrestore(&port->lock, flags); -} - -static int clps711xuart_startup(struct uart_port *port) -{ - unsigned int syscon; - int retval; - - tx_enabled(port) = 1; - - /* - * Allocate the IRQs - */ - retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0, - "clps711xuart_tx", port); - if (retval) - return retval; - - retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0, - "clps711xuart_rx", port); - if (retval) { - free_irq(TX_IRQ(port), port); - return retval; - } - - /* - * enable the port - */ - syscon = clps_readl(SYSCON(port)); - syscon |= SYSCON_UARTEN; - clps_writel(syscon, SYSCON(port)); - - return 0; -} - -static void clps711xuart_shutdown(struct uart_port *port) -{ - unsigned int ubrlcr, syscon; - - /* - * Free the interrupt - */ - free_irq(TX_IRQ(port), port); /* TX interrupt */ - free_irq(RX_IRQ(port), port); /* RX interrupt */ - - /* - * disable the port - */ - syscon = clps_readl(SYSCON(port)); - syscon &= ~SYSCON_UARTEN; - clps_writel(syscon, SYSCON(port)); - - /* - * disable break condition and fifos - */ - ubrlcr = clps_readl(UBRLCR(port)); - ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); - clps_writel(ubrlcr, UBRLCR(port)); -} - -static void -clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int ubrlcr, baud, quot; - unsigned long flags; - - /* - * We don't implement CREAD. - */ - termios->c_cflag |= CREAD; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - switch (termios->c_cflag & CSIZE) { - case CS5: - ubrlcr = UBRLCR_WRDLEN5; - break; - case CS6: - ubrlcr = UBRLCR_WRDLEN6; - break; - case CS7: - ubrlcr = UBRLCR_WRDLEN7; - break; - default: // CS8 - ubrlcr = UBRLCR_WRDLEN8; - break; - } - if (termios->c_cflag & CSTOPB) - ubrlcr |= UBRLCR_XSTOP; - if (termios->c_cflag & PARENB) { - ubrlcr |= UBRLCR_PRTEN; - if (!(termios->c_cflag & PARODD)) - ubrlcr |= UBRLCR_EVENPRT; - } - if (port->fifosize > 1) - ubrlcr |= UBRLCR_FIFOEN; - - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UARTDR_OVERR; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; - if (termios->c_iflag & IGNBRK) { - /* - * If we're ignoring parity and break indicators, - * ignore overruns to (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UARTDR_OVERR; - } - - quot -= 1; - - clps_writel(ubrlcr | quot, UBRLCR(port)); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *clps711xuart_type(struct uart_port *port) -{ - return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; -} - -/* - * Configure/autoconfigure the port. - */ -static void clps711xuart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) - port->type = PORT_CLPS711X; -} - -static void clps711xuart_release_port(struct uart_port *port) -{ -} - -static int clps711xuart_request_port(struct uart_port *port) -{ - return 0; -} - -static struct uart_ops clps711x_pops = { - .tx_empty = clps711xuart_tx_empty, - .set_mctrl = clps711xuart_set_mctrl_null, - .get_mctrl = clps711xuart_get_mctrl, - .stop_tx = clps711xuart_stop_tx, - .start_tx = clps711xuart_start_tx, - .stop_rx = clps711xuart_stop_rx, - .enable_ms = clps711xuart_enable_ms, - .break_ctl = clps711xuart_break_ctl, - .startup = clps711xuart_startup, - .shutdown = clps711xuart_shutdown, - .set_termios = clps711xuart_set_termios, - .type = clps711xuart_type, - .config_port = clps711xuart_config_port, - .release_port = clps711xuart_release_port, - .request_port = clps711xuart_request_port, -}; - -static struct uart_port clps711x_ports[UART_NR] = { - { - .iobase = SYSCON1, - .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ - .uartclk = 3686400, - .fifosize = 16, - .ops = &clps711x_pops, - .line = 0, - .flags = UPF_BOOT_AUTOCONF, - }, - { - .iobase = SYSCON2, - .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ - .uartclk = 3686400, - .fifosize = 16, - .ops = &clps711x_pops, - .line = 1, - .flags = UPF_BOOT_AUTOCONF, - } -}; - -#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -static void clps711xuart_console_putchar(struct uart_port *port, int ch) -{ - while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) - barrier(); - clps_writel(ch, UARTDR(port)); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - * - * Note that this is called with interrupts already disabled - */ -static void -clps711xuart_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_port *port = clps711x_ports + co->index; - unsigned int status, syscon; - - /* - * Ensure that the port is enabled. - */ - syscon = clps_readl(SYSCON(port)); - clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); - - uart_console_write(port, s, count, clps711xuart_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the uart state. - */ - do { - status = clps_readl(SYSFLG(port)); - } while (status & SYSFLG_UBUSY); - - clps_writel(syscon, SYSCON(port)); -} - -static void __init -clps711xuart_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { - unsigned int ubrlcr, quot; - - ubrlcr = clps_readl(UBRLCR(port)); - - *parity = 'n'; - if (ubrlcr & UBRLCR_PRTEN) { - if (ubrlcr & UBRLCR_EVENPRT) - *parity = 'e'; - else - *parity = 'o'; - } - - if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) - *bits = 7; - else - *bits = 8; - - quot = ubrlcr & UBRLCR_BAUD_MASK; - *baud = port->uartclk / (16 * (quot + 1)); - } -} - -static int __init clps711xuart_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - port = uart_get_console(clps711x_ports, UART_NR, co); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - clps711xuart_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver clps711x_reg; -static struct console clps711x_console = { - .name = "ttyCL", - .write = clps711xuart_console_write, - .device = uart_console_device, - .setup = clps711xuart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &clps711x_reg, -}; - -static int __init clps711xuart_console_init(void) -{ - register_console(&clps711x_console); - return 0; -} -console_initcall(clps711xuart_console_init); - -#define CLPS711X_CONSOLE &clps711x_console -#else -#define CLPS711X_CONSOLE NULL -#endif - -static struct uart_driver clps711x_reg = { - .driver_name = "ttyCL", - .dev_name = "ttyCL", - .major = SERIAL_CLPS711X_MAJOR, - .minor = SERIAL_CLPS711X_MINOR, - .nr = UART_NR, - - .cons = CLPS711X_CONSOLE, -}; - -static int __init clps711xuart_init(void) -{ - int ret, i; - - printk(KERN_INFO "Serial: CLPS711x driver\n"); - - ret = uart_register_driver(&clps711x_reg); - if (ret) - return ret; - - for (i = 0; i < UART_NR; i++) - uart_add_one_port(&clps711x_reg, &clps711x_ports[i]); - - return 0; -} - -static void __exit clps711xuart_exit(void) -{ - int i; - - for (i = 0; i < UART_NR; i++) - uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]); - - uart_unregister_driver(&clps711x_reg); -} - -module_init(clps711xuart_init); -module_exit(clps711xuart_exit); - -MODULE_AUTHOR("Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("CLPS-711x generic serial driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); diff --git a/drivers/serial/cpm_uart/Makefile b/drivers/serial/cpm_uart/Makefile deleted file mode 100644 index e072724ea754..000000000000 --- a/drivers/serial/cpm_uart/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the Motorola 8xx FEC ethernet controller -# - -obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o - -# Select the correct platform objects. -cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o -cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o - -cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h deleted file mode 100644 index b754dcf0fda5..000000000000 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * linux/drivers/serial/cpm_uart.h - * - * Driver for CPM (SCC/SMC) serial ports - * - * Copyright (C) 2004 Freescale Semiconductor, Inc. - * - * 2006 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * 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. - * - */ -#ifndef CPM_UART_H -#define CPM_UART_H - -#include -#include - -#if defined(CONFIG_CPM2) -#include "cpm_uart_cpm2.h" -#elif defined(CONFIG_8xx) -#include "cpm_uart_cpm1.h" -#endif - -#define SERIAL_CPM_MAJOR 204 -#define SERIAL_CPM_MINOR 46 - -#define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC) -#define IS_DISCARDING(pinfo) (pinfo->flags & FLAG_DISCARDING) -#define FLAG_DISCARDING 0x00000004 /* when set, don't discard */ -#define FLAG_SMC 0x00000002 -#define FLAG_CONSOLE 0x00000001 - -#define UART_SMC1 fsid_smc1_uart -#define UART_SMC2 fsid_smc2_uart -#define UART_SCC1 fsid_scc1_uart -#define UART_SCC2 fsid_scc2_uart -#define UART_SCC3 fsid_scc3_uart -#define UART_SCC4 fsid_scc4_uart - -#define UART_NR fs_uart_nr - -#define RX_NUM_FIFO 4 -#define RX_BUF_SIZE 32 -#define TX_NUM_FIFO 4 -#define TX_BUF_SIZE 32 - -#define SCC_WAIT_CLOSING 100 - -#define GPIO_CTS 0 -#define GPIO_RTS 1 -#define GPIO_DCD 2 -#define GPIO_DSR 3 -#define GPIO_DTR 4 -#define GPIO_RI 5 - -#define NUM_GPIOS (GPIO_RI+1) - -struct uart_cpm_port { - struct uart_port port; - u16 rx_nrfifos; - u16 rx_fifosize; - u16 tx_nrfifos; - u16 tx_fifosize; - smc_t __iomem *smcp; - smc_uart_t __iomem *smcup; - scc_t __iomem *sccp; - scc_uart_t __iomem *sccup; - cbd_t __iomem *rx_bd_base; - cbd_t __iomem *rx_cur; - cbd_t __iomem *tx_bd_base; - cbd_t __iomem *tx_cur; - unsigned char *tx_buf; - unsigned char *rx_buf; - u32 flags; - struct clk *clk; - u8 brg; - uint dp_addr; - void *mem_addr; - dma_addr_t dma_addr; - u32 mem_size; - /* wait on close if needed */ - int wait_closing; - /* value to combine with opcode to form cpm command */ - u32 command; - int gpios[NUM_GPIOS]; -}; - -extern int cpm_uart_nr; -extern struct uart_cpm_port cpm_uart_ports[UART_NR]; - -/* these are located in their respective files */ -void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd); -void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, - struct device_node *np); -void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram); -int cpm_uart_init_portdesc(void); -int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); -void cpm_uart_freebuf(struct uart_cpm_port *pinfo); - -void smc1_lineif(struct uart_cpm_port *pinfo); -void smc2_lineif(struct uart_cpm_port *pinfo); -void scc1_lineif(struct uart_cpm_port *pinfo); -void scc2_lineif(struct uart_cpm_port *pinfo); -void scc3_lineif(struct uart_cpm_port *pinfo); -void scc4_lineif(struct uart_cpm_port *pinfo); - -/* - virtual to phys transtalion -*/ -static inline unsigned long cpu2cpm_addr(void *addr, - struct uart_cpm_port *pinfo) -{ - int offset; - u32 val = (u32)addr; - u32 mem = (u32)pinfo->mem_addr; - /* sane check */ - if (likely(val >= mem && val < mem + pinfo->mem_size)) { - offset = val - mem; - return pinfo->dma_addr + offset; - } - /* something nasty happened */ - BUG(); - return 0; -} - -static inline void *cpm2cpu_addr(unsigned long addr, - struct uart_cpm_port *pinfo) -{ - int offset; - u32 val = addr; - u32 dma = (u32)pinfo->dma_addr; - /* sane check */ - if (likely(val >= dma && val < dma + pinfo->mem_size)) { - offset = val - dma; - return pinfo->mem_addr + offset; - } - /* something nasty happened */ - BUG(); - return NULL; -} - - -#endif /* CPM_UART_H */ diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c deleted file mode 100644 index 8692ff98fc07..000000000000 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ /dev/null @@ -1,1443 +0,0 @@ -/* - * linux/drivers/serial/cpm_uart.c - * - * Driver for CPM (SCC/SMC) serial ports; core driver - * - * Based on arch/ppc/cpm2_io/uart.c by Dan Malek - * Based on ppc8xx.c by Thomas Gleixner - * Based on drivers/serial/amba.c by Russell King - * - * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) - * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * - * Copyright (C) 2004, 2007 Freescale Semiconductor, Inc. - * (C) 2004 Intracom, S.A. - * (C) 2005-2006 MontaVista Software, Inc. - * Vitaly Bordug - * - * 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include - -#include "cpm_uart.h" - - -/**************************************************************/ - -static int cpm_uart_tx_pump(struct uart_port *port); -static void cpm_uart_init_smc(struct uart_cpm_port *pinfo); -static void cpm_uart_init_scc(struct uart_cpm_port *pinfo); -static void cpm_uart_initbd(struct uart_cpm_port *pinfo); - -/**************************************************************/ - -#define HW_BUF_SPD_THRESHOLD 9600 - -/* - * Check, if transmit buffers are processed -*/ -static unsigned int cpm_uart_tx_empty(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - cbd_t __iomem *bdp = pinfo->tx_bd_base; - int ret = 0; - - while (1) { - if (in_be16(&bdp->cbd_sc) & BD_SC_READY) - break; - - if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) { - ret = TIOCSER_TEMT; - break; - } - bdp++; - } - - pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret); - - return ret; -} - -static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - - if (pinfo->gpios[GPIO_RTS] >= 0) - gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); - - if (pinfo->gpios[GPIO_DTR] >= 0) - gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); -} - -static unsigned int cpm_uart_get_mctrl(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - - if (pinfo->gpios[GPIO_CTS] >= 0) { - if (gpio_get_value(pinfo->gpios[GPIO_CTS])) - mctrl &= ~TIOCM_CTS; - } - - if (pinfo->gpios[GPIO_DSR] >= 0) { - if (gpio_get_value(pinfo->gpios[GPIO_DSR])) - mctrl &= ~TIOCM_DSR; - } - - if (pinfo->gpios[GPIO_DCD] >= 0) { - if (gpio_get_value(pinfo->gpios[GPIO_DCD])) - mctrl &= ~TIOCM_CAR; - } - - if (pinfo->gpios[GPIO_RI] >= 0) { - if (!gpio_get_value(pinfo->gpios[GPIO_RI])) - mctrl |= TIOCM_RNG; - } - - return mctrl; -} - -/* - * Stop transmitter - */ -static void cpm_uart_stop_tx(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - smc_t __iomem *smcp = pinfo->smcp; - scc_t __iomem *sccp = pinfo->sccp; - - pr_debug("CPM uart[%d]:stop tx\n", port->line); - - if (IS_SMC(pinfo)) - clrbits8(&smcp->smc_smcm, SMCM_TX); - else - clrbits16(&sccp->scc_sccm, UART_SCCM_TX); -} - -/* - * Start transmitter - */ -static void cpm_uart_start_tx(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - smc_t __iomem *smcp = pinfo->smcp; - scc_t __iomem *sccp = pinfo->sccp; - - pr_debug("CPM uart[%d]:start tx\n", port->line); - - if (IS_SMC(pinfo)) { - if (in_8(&smcp->smc_smcm) & SMCM_TX) - return; - } else { - if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX) - return; - } - - if (cpm_uart_tx_pump(port) != 0) { - if (IS_SMC(pinfo)) { - setbits8(&smcp->smc_smcm, SMCM_TX); - } else { - setbits16(&sccp->scc_sccm, UART_SCCM_TX); - } - } -} - -/* - * Stop receiver - */ -static void cpm_uart_stop_rx(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - smc_t __iomem *smcp = pinfo->smcp; - scc_t __iomem *sccp = pinfo->sccp; - - pr_debug("CPM uart[%d]:stop rx\n", port->line); - - if (IS_SMC(pinfo)) - clrbits8(&smcp->smc_smcm, SMCM_RX); - else - clrbits16(&sccp->scc_sccm, UART_SCCM_RX); -} - -/* - * Enable Modem status interrupts - */ -static void cpm_uart_enable_ms(struct uart_port *port) -{ - pr_debug("CPM uart[%d]:enable ms\n", port->line); -} - -/* - * Generate a break. - */ -static void cpm_uart_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - - pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line, - break_state); - - if (break_state) - cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); - else - cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); -} - -/* - * Transmit characters, refill buffer descriptor, if possible - */ -static void cpm_uart_int_tx(struct uart_port *port) -{ - pr_debug("CPM uart[%d]:TX INT\n", port->line); - - cpm_uart_tx_pump(port); -} - -#ifdef CONFIG_CONSOLE_POLL -static int serial_polled; -#endif - -/* - * Receive characters - */ -static void cpm_uart_int_rx(struct uart_port *port) -{ - int i; - unsigned char ch; - u8 *cp; - struct tty_struct *tty = port->state->port.tty; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - cbd_t __iomem *bdp; - u16 status; - unsigned int flg; - - pr_debug("CPM uart[%d]:RX INT\n", port->line); - - /* Just loop through the closed BDs and copy the characters into - * the buffer. - */ - bdp = pinfo->rx_cur; - for (;;) { -#ifdef CONFIG_CONSOLE_POLL - if (unlikely(serial_polled)) { - serial_polled = 0; - return; - } -#endif - /* get status */ - status = in_be16(&bdp->cbd_sc); - /* If this one is empty, return happy */ - if (status & BD_SC_EMPTY) - break; - - /* get number of characters, and check spce in flip-buffer */ - i = in_be16(&bdp->cbd_datlen); - - /* If we have not enough room in tty flip buffer, then we try - * later, which will be the next rx-interrupt or a timeout - */ - if(tty_buffer_request_room(tty, i) < i) { - printk(KERN_WARNING "No room in flip buffer\n"); - return; - } - - /* get pointer */ - cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); - - /* loop through the buffer */ - while (i-- > 0) { - ch = *cp++; - port->icount.rx++; - flg = TTY_NORMAL; - - if (status & - (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) - goto handle_error; - if (uart_handle_sysrq_char(port, ch)) - continue; -#ifdef CONFIG_CONSOLE_POLL - if (unlikely(serial_polled)) { - serial_polled = 0; - return; - } -#endif - error_return: - tty_insert_flip_char(tty, ch, flg); - - } /* End while (i--) */ - - /* This BD is ready to be used again. Clear status. get next */ - clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR | - BD_SC_OV | BD_SC_ID); - setbits16(&bdp->cbd_sc, BD_SC_EMPTY); - - if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) - bdp = pinfo->rx_bd_base; - else - bdp++; - - } /* End for (;;) */ - - /* Write back buffer pointer */ - pinfo->rx_cur = bdp; - - /* activate BH processing */ - tty_flip_buffer_push(tty); - - return; - - /* Error processing */ - - handle_error: - /* Statistics */ - if (status & BD_SC_BR) - port->icount.brk++; - if (status & BD_SC_PR) - port->icount.parity++; - if (status & BD_SC_FR) - port->icount.frame++; - if (status & BD_SC_OV) - port->icount.overrun++; - - /* Mask out ignored conditions */ - status &= port->read_status_mask; - - /* Handle the remaining ones */ - if (status & BD_SC_BR) - flg = TTY_BREAK; - else if (status & BD_SC_PR) - flg = TTY_PARITY; - else if (status & BD_SC_FR) - flg = TTY_FRAME; - - /* overrun does not affect the current character ! */ - if (status & BD_SC_OV) { - ch = 0; - flg = TTY_OVERRUN; - /* We skip this buffer */ - /* CHECK: Is really nothing senseful there */ - /* ASSUMPTION: it contains nothing valid */ - i = 0; - } -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif - goto error_return; -} - -/* - * Asynchron mode interrupt handler - */ -static irqreturn_t cpm_uart_int(int irq, void *data) -{ - u8 events; - struct uart_port *port = data; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - smc_t __iomem *smcp = pinfo->smcp; - scc_t __iomem *sccp = pinfo->sccp; - - pr_debug("CPM uart[%d]:IRQ\n", port->line); - - if (IS_SMC(pinfo)) { - events = in_8(&smcp->smc_smce); - out_8(&smcp->smc_smce, events); - if (events & SMCM_BRKE) - uart_handle_break(port); - if (events & SMCM_RX) - cpm_uart_int_rx(port); - if (events & SMCM_TX) - cpm_uart_int_tx(port); - } else { - events = in_be16(&sccp->scc_scce); - out_be16(&sccp->scc_scce, events); - if (events & UART_SCCM_BRKE) - uart_handle_break(port); - if (events & UART_SCCM_RX) - cpm_uart_int_rx(port); - if (events & UART_SCCM_TX) - cpm_uart_int_tx(port); - } - return (events) ? IRQ_HANDLED : IRQ_NONE; -} - -static int cpm_uart_startup(struct uart_port *port) -{ - int retval; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - - pr_debug("CPM uart[%d]:startup\n", port->line); - - /* If the port is not the console, make sure rx is disabled. */ - if (!(pinfo->flags & FLAG_CONSOLE)) { - /* Disable UART rx */ - if (IS_SMC(pinfo)) { - clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN); - clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX); - } else { - clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR); - clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX); - } - cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); - } - /* Install interrupt handler. */ - retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port); - if (retval) - return retval; - - /* Startup rx-int */ - if (IS_SMC(pinfo)) { - setbits8(&pinfo->smcp->smc_smcm, SMCM_RX); - setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN)); - } else { - setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX); - setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT)); - } - - return 0; -} - -inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo) -{ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(pinfo->wait_closing); -} - -/* - * Shutdown the uart - */ -static void cpm_uart_shutdown(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - - pr_debug("CPM uart[%d]:shutdown\n", port->line); - - /* free interrupt handler */ - free_irq(port->irq, port); - - /* If the port is not the console, disable Rx and Tx. */ - if (!(pinfo->flags & FLAG_CONSOLE)) { - /* Wait for all the BDs marked sent */ - while(!cpm_uart_tx_empty(port)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(2); - } - - if (pinfo->wait_closing) - cpm_uart_wait_until_send(pinfo); - - /* Stop uarts */ - if (IS_SMC(pinfo)) { - smc_t __iomem *smcp = pinfo->smcp; - clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); - clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX); - } else { - scc_t __iomem *sccp = pinfo->sccp; - clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); - clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); - } - - /* Shut them really down and reinit buffer descriptors */ - if (IS_SMC(pinfo)) { - out_be16(&pinfo->smcup->smc_brkcr, 0); - cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); - } else { - out_be16(&pinfo->sccup->scc_brkcr, 0); - cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX); - } - - cpm_uart_initbd(pinfo); - } -} - -static void cpm_uart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - int baud; - unsigned long flags; - u16 cval, scval, prev_mode; - int bits, sbits; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - smc_t __iomem *smcp = pinfo->smcp; - scc_t __iomem *sccp = pinfo->sccp; - - pr_debug("CPM uart[%d]:set_termios\n", port->line); - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - if (baud <= HW_BUF_SPD_THRESHOLD || - (pinfo->port.state && pinfo->port.state->port.tty->low_latency)) - pinfo->rx_fifosize = 1; - else - pinfo->rx_fifosize = RX_BUF_SIZE; - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ - cval = 0; - scval = 0; - - /* byte size */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = 5; - break; - case CS6: - bits = 6; - break; - case CS7: - bits = 7; - break; - case CS8: - bits = 8; - break; - /* Never happens, but GCC is too dumb to figure it out */ - default: - bits = 8; - break; - } - sbits = bits - 5; - - if (termios->c_cflag & CSTOPB) { - cval |= SMCMR_SL; /* Two stops */ - scval |= SCU_PSMR_SL; - bits++; - } - - if (termios->c_cflag & PARENB) { - cval |= SMCMR_PEN; - scval |= SCU_PSMR_PEN; - bits++; - if (!(termios->c_cflag & PARODD)) { - cval |= SMCMR_PM_EVEN; - scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); - } - } - - /* - * Update the timeout - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * Set up parity check flag - */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); - if (termios->c_iflag & INPCK) - port->read_status_mask |= BD_SC_FR | BD_SC_PR; - if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK)) - port->read_status_mask |= BD_SC_BR; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= BD_SC_BR; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= BD_SC_OV; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - port->read_status_mask &= ~BD_SC_EMPTY; - - spin_lock_irqsave(&port->lock, flags); - - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; - if (IS_SMC(pinfo)) { - /* - * MRBLR can be changed while an SMC/SCC is operating only - * if it is done in a single bus cycle with one 16-bit move - * (not two 8-bit bus cycles back-to-back). This occurs when - * the cp shifts control to the next RxBD, so the change does - * not take effect immediately. To guarantee the exact RxBD - * on which the change occurs, change MRBLR only while the - * SMC/SCC receiver is disabled. - */ - out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize); - - /* Set the mode register. We want to keep a copy of the - * enables, because we want to put them back if they were - * present. - */ - prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN); - /* Output in *one* operation, so we don't interrupt RX/TX if they - * were already enabled. */ - out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | - SMCMR_SM_UART | prev_mode); - } else { - out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); - out_be16(&sccp->scc_psmr, (sbits << 12) | scval); - } - - if (pinfo->clk) - clk_set_rate(pinfo->clk, baud); - else - cpm_set_brg(pinfo->brg - 1, baud); - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *cpm_uart_type(struct uart_port *port) -{ - pr_debug("CPM uart[%d]:uart_type\n", port->line); - - return port->type == PORT_CPM ? "CPM UART" : NULL; -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int cpm_uart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - int ret = 0; - - pr_debug("CPM uart[%d]:verify_port\n", port->line); - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -/* - * Transmit characters, refill buffer descriptor, if possible - */ -static int cpm_uart_tx_pump(struct uart_port *port) -{ - cbd_t __iomem *bdp; - u8 *p; - int count; - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - struct circ_buf *xmit = &port->state->xmit; - - /* Handle xon/xoff */ - if (port->x_char) { - /* Pick next descriptor and fill from buffer */ - bdp = pinfo->tx_cur; - - p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); - - *p++ = port->x_char; - - out_be16(&bdp->cbd_datlen, 1); - setbits16(&bdp->cbd_sc, BD_SC_READY); - /* Get next BD. */ - if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) - bdp = pinfo->tx_bd_base; - else - bdp++; - pinfo->tx_cur = bdp; - - port->icount.tx++; - port->x_char = 0; - return 1; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - cpm_uart_stop_tx(port); - return 0; - } - - /* Pick next descriptor and fill from buffer */ - bdp = pinfo->tx_cur; - - while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && - xmit->tail != xmit->head) { - count = 0; - p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); - while (count < pinfo->tx_fifosize) { - *p++ = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - count++; - if (xmit->head == xmit->tail) - break; - } - out_be16(&bdp->cbd_datlen, count); - setbits16(&bdp->cbd_sc, BD_SC_READY); - /* Get next BD. */ - if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) - bdp = pinfo->tx_bd_base; - else - bdp++; - } - pinfo->tx_cur = bdp; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) { - cpm_uart_stop_tx(port); - return 0; - } - - return 1; -} - -/* - * init buffer descriptors - */ -static void cpm_uart_initbd(struct uart_cpm_port *pinfo) -{ - int i; - u8 *mem_addr; - cbd_t __iomem *bdp; - - pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line); - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - mem_addr = pinfo->mem_addr; - bdp = pinfo->rx_cur = pinfo->rx_bd_base; - for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { - out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); - out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT); - mem_addr += pinfo->rx_fifosize; - } - - out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); - out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - bdp = pinfo->tx_cur = pinfo->tx_bd_base; - for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { - out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); - out_be16(&bdp->cbd_sc, BD_SC_INTRPT); - mem_addr += pinfo->tx_fifosize; - } - - out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); - out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT); -} - -static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) -{ - scc_t __iomem *scp; - scc_uart_t __iomem *sup; - - pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line); - - scp = pinfo->sccp; - sup = pinfo->sccup; - - /* Store address */ - out_be16(&pinfo->sccup->scc_genscc.scc_rbase, - (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); - out_be16(&pinfo->sccup->scc_genscc.scc_tbase, - (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); - - /* Set up the uart parameters in the - * parameter ram. - */ - - cpm_set_scc_fcr(sup); - - out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); - out_be16(&sup->scc_maxidl, pinfo->rx_fifosize); - out_be16(&sup->scc_brkcr, 1); - out_be16(&sup->scc_parec, 0); - out_be16(&sup->scc_frmec, 0); - out_be16(&sup->scc_nosec, 0); - out_be16(&sup->scc_brkec, 0); - out_be16(&sup->scc_uaddr1, 0); - out_be16(&sup->scc_uaddr2, 0); - out_be16(&sup->scc_toseq, 0); - out_be16(&sup->scc_char1, 0x8000); - out_be16(&sup->scc_char2, 0x8000); - out_be16(&sup->scc_char3, 0x8000); - out_be16(&sup->scc_char4, 0x8000); - out_be16(&sup->scc_char5, 0x8000); - out_be16(&sup->scc_char6, 0x8000); - out_be16(&sup->scc_char7, 0x8000); - out_be16(&sup->scc_char8, 0x8000); - out_be16(&sup->scc_rccm, 0xc0ff); - - /* Send the CPM an initialize command. - */ - cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - out_be32(&scp->scc_gsmrh, 0); - out_be32(&scp->scc_gsmrl, - SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Enable rx interrupts and clear all pending events. */ - out_be16(&scp->scc_sccm, 0); - out_be16(&scp->scc_scce, 0xffff); - out_be16(&scp->scc_dsr, 0x7e7e); - out_be16(&scp->scc_psmr, 0x3000); - - setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); -} - -static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) -{ - smc_t __iomem *sp; - smc_uart_t __iomem *up; - - pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line); - - sp = pinfo->smcp; - up = pinfo->smcup; - - /* Store address */ - out_be16(&pinfo->smcup->smc_rbase, - (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); - out_be16(&pinfo->smcup->smc_tbase, - (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); - -/* - * In case SMC1 is being relocated... - */ -#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH) - out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase)); - out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase)); - out_be32(&up->smc_rstate, 0); - out_be32(&up->smc_tstate, 0); - out_be16(&up->smc_brkcr, 1); /* number of break chars */ - out_be16(&up->smc_brkec, 0); -#endif - - /* Set up the uart parameters in the - * parameter ram. - */ - cpm_set_smc_fcr(up); - - /* Using idle character time requires some additional tuning. */ - out_be16(&up->smc_mrblr, pinfo->rx_fifosize); - out_be16(&up->smc_maxidl, pinfo->rx_fifosize); - out_be16(&up->smc_brklen, 0); - out_be16(&up->smc_brkec, 0); - out_be16(&up->smc_brkcr, 1); - - cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART); - - /* Enable only rx interrupts clear all pending events. */ - out_8(&sp->smc_smcm, 0); - out_8(&sp->smc_smce, 0xff); - - setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN); -} - -/* - * Initialize port. This is called from early_console stuff - * so we have to be careful here ! - */ -static int cpm_uart_request_port(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int ret; - - pr_debug("CPM uart[%d]:request port\n", port->line); - - if (pinfo->flags & FLAG_CONSOLE) - return 0; - - if (IS_SMC(pinfo)) { - clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); - clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); - } else { - clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); - clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); - } - - ret = cpm_uart_allocbuf(pinfo, 0); - - if (ret) - return ret; - - cpm_uart_initbd(pinfo); - if (IS_SMC(pinfo)) - cpm_uart_init_smc(pinfo); - else - cpm_uart_init_scc(pinfo); - - return 0; -} - -static void cpm_uart_release_port(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - - if (!(pinfo->flags & FLAG_CONSOLE)) - cpm_uart_freebuf(pinfo); -} - -/* - * Configure/autoconfigure the port. - */ -static void cpm_uart_config_port(struct uart_port *port, int flags) -{ - pr_debug("CPM uart[%d]:config_port\n", port->line); - - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_CPM; - cpm_uart_request_port(port); - } -} - -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_CPM_CONSOLE) -/* - * Write a string to the serial port - * Note that this is called with interrupts already disabled - */ -static void cpm_uart_early_write(struct uart_cpm_port *pinfo, - const char *string, u_int count) -{ - unsigned int i; - cbd_t __iomem *bdp, *bdbase; - unsigned char *cpm_outp_addr; - - /* Get the address of the host memory buffer. - */ - bdp = pinfo->tx_cur; - bdbase = pinfo->tx_bd_base; - - /* - * Now, do each character. This is not as bad as it looks - * since this is a holding FIFO and not a transmitting FIFO. - * We could add the complexity of filling the entire transmit - * buffer, but we would just wait longer between accesses...... - */ - for (i = 0; i < count; i++, string++) { - /* Wait for transmitter fifo to empty. - * Ready indicates output is ready, and xmt is doing - * that, not that it is ready for us to send. - */ - while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) - ; - - /* Send the character out. - * If the buffer address is in the CPM DPRAM, don't - * convert it. - */ - cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), - pinfo); - *cpm_outp_addr = *string; - - out_be16(&bdp->cbd_datlen, 1); - setbits16(&bdp->cbd_sc, BD_SC_READY); - - if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - - /* if a LF, also do CR... */ - if (*string == 10) { - while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) - ; - - cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), - pinfo); - *cpm_outp_addr = 13; - - out_be16(&bdp->cbd_datlen, 1); - setbits16(&bdp->cbd_sc, BD_SC_READY); - - if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) - ; - - pinfo->tx_cur = bdp; -} -#endif - -#ifdef CONFIG_CONSOLE_POLL -/* Serial polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -#define GDB_BUF_SIZE 512 /* power of 2, please */ - -static char poll_buf[GDB_BUF_SIZE]; -static char *pollp; -static int poll_chars; - -static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) -{ - u_char c, *cp; - volatile cbd_t *bdp; - int i; - - /* Get the address of the host memory buffer. - */ - bdp = pinfo->rx_cur; - while (bdp->cbd_sc & BD_SC_EMPTY) - ; - - /* If the buffer address is in the CPM DPRAM, don't - * convert it. - */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); - - if (obuf) { - i = c = bdp->cbd_datlen; - while (i-- > 0) - *obuf++ = *cp++; - } else - c = *cp; - bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); - bdp->cbd_sc |= BD_SC_EMPTY; - - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = pinfo->rx_bd_base; - else - bdp++; - pinfo->rx_cur = (cbd_t *)bdp; - - return (int)c; -} - -static int cpm_get_poll_char(struct uart_port *port) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - - if (!serial_polled) { - serial_polled = 1; - poll_chars = 0; - } - if (poll_chars <= 0) { - poll_chars = poll_wait_key(poll_buf, pinfo); - pollp = poll_buf; - } - poll_chars--; - return *pollp++; -} - -static void cpm_put_poll_char(struct uart_port *port, - unsigned char c) -{ - struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - static char ch[2]; - - ch[0] = (char)c; - cpm_uart_early_write(pinfo, ch, 1); -} -#endif /* CONFIG_CONSOLE_POLL */ - -static struct uart_ops cpm_uart_pops = { - .tx_empty = cpm_uart_tx_empty, - .set_mctrl = cpm_uart_set_mctrl, - .get_mctrl = cpm_uart_get_mctrl, - .stop_tx = cpm_uart_stop_tx, - .start_tx = cpm_uart_start_tx, - .stop_rx = cpm_uart_stop_rx, - .enable_ms = cpm_uart_enable_ms, - .break_ctl = cpm_uart_break_ctl, - .startup = cpm_uart_startup, - .shutdown = cpm_uart_shutdown, - .set_termios = cpm_uart_set_termios, - .type = cpm_uart_type, - .release_port = cpm_uart_release_port, - .request_port = cpm_uart_request_port, - .config_port = cpm_uart_config_port, - .verify_port = cpm_uart_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = cpm_get_poll_char, - .poll_put_char = cpm_put_poll_char, -#endif -}; - -struct uart_cpm_port cpm_uart_ports[UART_NR]; - -static int cpm_uart_init_port(struct device_node *np, - struct uart_cpm_port *pinfo) -{ - const u32 *data; - void __iomem *mem, *pram; - int len; - int ret; - int i; - - data = of_get_property(np, "clock", NULL); - if (data) { - struct clk *clk = clk_get(NULL, (const char*)data); - if (!IS_ERR(clk)) - pinfo->clk = clk; - } - if (!pinfo->clk) { - data = of_get_property(np, "fsl,cpm-brg", &len); - if (!data || len != 4) { - printk(KERN_ERR "CPM UART %s has no/invalid " - "fsl,cpm-brg property.\n", np->name); - return -EINVAL; - } - pinfo->brg = *data; - } - - data = of_get_property(np, "fsl,cpm-command", &len); - if (!data || len != 4) { - printk(KERN_ERR "CPM UART %s has no/invalid " - "fsl,cpm-command property.\n", np->name); - return -EINVAL; - } - pinfo->command = *data; - - mem = of_iomap(np, 0); - if (!mem) - return -ENOMEM; - - if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") || - of_device_is_compatible(np, "fsl,cpm2-scc-uart")) { - pinfo->sccp = mem; - pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np); - } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") || - of_device_is_compatible(np, "fsl,cpm2-smc-uart")) { - pinfo->flags |= FLAG_SMC; - pinfo->smcp = mem; - pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np); - } else { - ret = -ENODEV; - goto out_mem; - } - - if (!pram) { - ret = -ENOMEM; - goto out_mem; - } - - pinfo->tx_nrfifos = TX_NUM_FIFO; - pinfo->tx_fifosize = TX_BUF_SIZE; - pinfo->rx_nrfifos = RX_NUM_FIFO; - pinfo->rx_fifosize = RX_BUF_SIZE; - - pinfo->port.uartclk = ppc_proc_freq; - pinfo->port.mapbase = (unsigned long)mem; - pinfo->port.type = PORT_CPM; - pinfo->port.ops = &cpm_uart_pops, - pinfo->port.iotype = UPIO_MEM; - pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; - spin_lock_init(&pinfo->port.lock); - - pinfo->port.irq = of_irq_to_resource(np, 0, NULL); - if (pinfo->port.irq == NO_IRQ) { - ret = -EINVAL; - goto out_pram; - } - - for (i = 0; i < NUM_GPIOS; i++) - pinfo->gpios[i] = of_get_gpio(np, i); - -#ifdef CONFIG_PPC_EARLY_DEBUG_CPM - udbg_putc = NULL; -#endif - - return cpm_uart_request_port(&pinfo->port); - -out_pram: - cpm_uart_unmap_pram(pinfo, pram); -out_mem: - iounmap(mem); - return ret; -} - -#ifdef CONFIG_SERIAL_CPM_CONSOLE -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * Note that this is called with interrupts already disabled - */ -static void cpm_uart_console_write(struct console *co, const char *s, - u_int count) -{ - struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index]; - unsigned long flags; - int nolock = oops_in_progress; - - if (unlikely(nolock)) { - local_irq_save(flags); - } else { - spin_lock_irqsave(&pinfo->port.lock, flags); - } - - cpm_uart_early_write(pinfo, s, count); - - if (unlikely(nolock)) { - local_irq_restore(flags); - } else { - spin_unlock_irqrestore(&pinfo->port.lock, flags); - } -} - - -static int __init cpm_uart_console_setup(struct console *co, char *options) -{ - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - struct uart_cpm_port *pinfo; - struct uart_port *port; - - struct device_node *np = NULL; - int i = 0; - - if (co->index >= UART_NR) { - printk(KERN_ERR "cpm_uart: console index %d too high\n", - co->index); - return -ENODEV; - } - - do { - np = of_find_node_by_type(np, "serial"); - if (!np) - return -ENODEV; - - if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") && - !of_device_is_compatible(np, "fsl,cpm1-scc-uart") && - !of_device_is_compatible(np, "fsl,cpm2-smc-uart") && - !of_device_is_compatible(np, "fsl,cpm2-scc-uart")) - i--; - } while (i++ != co->index); - - pinfo = &cpm_uart_ports[co->index]; - - pinfo->flags |= FLAG_CONSOLE; - port = &pinfo->port; - - ret = cpm_uart_init_port(np, pinfo); - of_node_put(np); - if (ret) - return ret; - - if (options) { - uart_parse_options(options, &baud, &parity, &bits, &flow); - } else { - if ((baud = uart_baudrate()) == -1) - baud = 9600; - } - - if (IS_SMC(pinfo)) { - out_be16(&pinfo->smcup->smc_brkcr, 0); - cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); - clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); - clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); - } else { - out_be16(&pinfo->sccup->scc_brkcr, 0); - cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX); - clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); - clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); - } - - ret = cpm_uart_allocbuf(pinfo, 1); - - if (ret) - return ret; - - cpm_uart_initbd(pinfo); - - if (IS_SMC(pinfo)) - cpm_uart_init_smc(pinfo); - else - cpm_uart_init_scc(pinfo); - - uart_set_options(port, co, baud, parity, bits, flow); - cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); - - return 0; -} - -static struct uart_driver cpm_reg; -static struct console cpm_scc_uart_console = { - .name = "ttyCPM", - .write = cpm_uart_console_write, - .device = uart_console_device, - .setup = cpm_uart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &cpm_reg, -}; - -static int __init cpm_uart_console_init(void) -{ - register_console(&cpm_scc_uart_console); - return 0; -} - -console_initcall(cpm_uart_console_init); - -#define CPM_UART_CONSOLE &cpm_scc_uart_console -#else -#define CPM_UART_CONSOLE NULL -#endif - -static struct uart_driver cpm_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyCPM", - .dev_name = "ttyCPM", - .major = SERIAL_CPM_MAJOR, - .minor = SERIAL_CPM_MINOR, - .cons = CPM_UART_CONSOLE, - .nr = UART_NR, -}; - -static int probe_index; - -static int __devinit cpm_uart_probe(struct platform_device *ofdev, - const struct of_device_id *match) -{ - int index = probe_index++; - struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; - int ret; - - pinfo->port.line = index; - - if (index >= UART_NR) - return -ENODEV; - - dev_set_drvdata(&ofdev->dev, pinfo); - - /* initialize the device pointer for the port */ - pinfo->port.dev = &ofdev->dev; - - ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo); - if (ret) - return ret; - - return uart_add_one_port(&cpm_reg, &pinfo->port); -} - -static int __devexit cpm_uart_remove(struct platform_device *ofdev) -{ - struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); - return uart_remove_one_port(&cpm_reg, &pinfo->port); -} - -static struct of_device_id cpm_uart_match[] = { - { - .compatible = "fsl,cpm1-smc-uart", - }, - { - .compatible = "fsl,cpm1-scc-uart", - }, - { - .compatible = "fsl,cpm2-smc-uart", - }, - { - .compatible = "fsl,cpm2-scc-uart", - }, - {} -}; - -static struct of_platform_driver cpm_uart_driver = { - .driver = { - .name = "cpm_uart", - .owner = THIS_MODULE, - .of_match_table = cpm_uart_match, - }, - .probe = cpm_uart_probe, - .remove = cpm_uart_remove, - }; - -static int __init cpm_uart_init(void) -{ - int ret = uart_register_driver(&cpm_reg); - if (ret) - return ret; - - ret = of_register_platform_driver(&cpm_uart_driver); - if (ret) - uart_unregister_driver(&cpm_reg); - - return ret; -} - -static void __exit cpm_uart_exit(void) -{ - of_unregister_platform_driver(&cpm_uart_driver); - uart_unregister_driver(&cpm_reg); -} - -module_init(cpm_uart_init); -module_exit(cpm_uart_exit); - -MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis"); -MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c deleted file mode 100644 index 3fc1d66e32c6..000000000000 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * linux/drivers/serial/cpm_uart.c - * - * Driver for CPM (SCC/SMC) serial ports; CPM1 definitions - * - * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) - * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * - * Copyright (C) 2004 Freescale Semiconductor, Inc. - * (C) 2004 Intracom, S.A. - * (C) 2006 MontaVista Software, Inc. - * Vitaly Bordug - * - * 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 - -#include -#include -#include - -#include -#include - -#include - -#include "cpm_uart.h" - -/**************************************************************/ - -void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) -{ - cpm_command(port->command, cmd); -} - -void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, - struct device_node *np) -{ - return of_iomap(np, 1); -} - -void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) -{ - iounmap(pram); -} - -/* - * Allocate DP-Ram and memory buffers. We need to allocate a transmit and - * receive buffer descriptors from dual port ram, and a character - * buffer area from host mem. If we are allocating for the console we need - * to do it from bootmem - */ -int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) -{ - int dpmemsz, memsz; - u8 *dp_mem; - unsigned long dp_offset; - u8 *mem_addr; - dma_addr_t dma_addr = 0; - - pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); - - dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); - dp_offset = cpm_dpalloc(dpmemsz, 8); - if (IS_ERR_VALUE(dp_offset)) { - printk(KERN_ERR - "cpm_uart_cpm1.c: could not allocate buffer descriptors\n"); - return -ENOMEM; - } - dp_mem = cpm_dpram_addr(dp_offset); - - memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); - if (is_con) { - /* was hostalloc but changed cause it blows away the */ - /* large tlb mapping when pinning the kernel area */ - mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); - dma_addr = (u32)cpm_dpram_phys(mem_addr); - } else - mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, - GFP_KERNEL); - - if (mem_addr == NULL) { - cpm_dpfree(dp_offset); - printk(KERN_ERR - "cpm_uart_cpm1.c: could not allocate coherent memory\n"); - return -ENOMEM; - } - - pinfo->dp_addr = dp_offset; - pinfo->mem_addr = mem_addr; /* virtual address*/ - pinfo->dma_addr = dma_addr; /* physical address*/ - pinfo->mem_size = memsz; - - pinfo->rx_buf = mem_addr; - pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos - * pinfo->rx_fifosize); - - pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; - pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; - - return 0; -} - -void cpm_uart_freebuf(struct uart_cpm_port *pinfo) -{ - dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * - pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * - pinfo->tx_fifosize), pinfo->mem_addr, - pinfo->dma_addr); - - cpm_dpfree(pinfo->dp_addr); -} diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h deleted file mode 100644 index 10eecd6af6d4..000000000000 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h - * - * Driver for CPM (SCC/SMC) serial ports - * - * definitions for cpm1 - * - */ - -#ifndef CPM_UART_CPM1_H -#define CPM_UART_CPM1_H - -#include - -static inline void cpm_set_brg(int brg, int baud) -{ - cpm_setbrg(brg, baud); -} - -static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup) -{ - out_8(&sup->scc_genscc.scc_rfcr, SMC_EB); - out_8(&sup->scc_genscc.scc_tfcr, SMC_EB); -} - -static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up) -{ - out_8(&up->smc_rfcr, SMC_EB); - out_8(&up->smc_tfcr, SMC_EB); -} - -#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) - -#endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c deleted file mode 100644 index 814ac006393f..000000000000 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * linux/drivers/serial/cpm_uart_cpm2.c - * - * Driver for CPM (SCC/SMC) serial ports; CPM2 definitions - * - * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) - * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * - * Copyright (C) 2004 Freescale Semiconductor, Inc. - * (C) 2004 Intracom, S.A. - * (C) 2006 MontaVista Software, Inc. - * Vitaly Bordug - * - * 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 - -#include -#include -#include -#include - -#include -#include - -#include "cpm_uart.h" - -/**************************************************************/ - -void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) -{ - cpm_command(port->command, cmd); -} - -void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, - struct device_node *np) -{ - void __iomem *pram; - unsigned long offset; - struct resource res; - resource_size_t len; - - /* Don't remap parameter RAM if it has already been initialized - * during console setup. - */ - if (IS_SMC(port) && port->smcup) - return port->smcup; - else if (!IS_SMC(port) && port->sccup) - return port->sccup; - - if (of_address_to_resource(np, 1, &res)) - return NULL; - - len = resource_size(&res); - pram = ioremap(res.start, len); - if (!pram) - return NULL; - - if (!IS_SMC(port)) - return pram; - - if (len != 2) { - printk(KERN_WARNING "cpm_uart[%d]: device tree references " - "SMC pram, using boot loader/wrapper pram mapping. " - "Please fix your device tree to reference the pram " - "base register instead.\n", - port->port.line); - return pram; - } - - offset = cpm_dpalloc(PROFF_SMC_SIZE, 64); - out_be16(pram, offset); - iounmap(pram); - return cpm_muram_addr(offset); -} - -void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) -{ - if (!IS_SMC(port)) - iounmap(pram); -} - -/* - * Allocate DP-Ram and memory buffers. We need to allocate a transmit and - * receive buffer descriptors from dual port ram, and a character - * buffer area from host mem. If we are allocating for the console we need - * to do it from bootmem - */ -int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) -{ - int dpmemsz, memsz; - u8 __iomem *dp_mem; - unsigned long dp_offset; - u8 *mem_addr; - dma_addr_t dma_addr = 0; - - pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); - - dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); - dp_offset = cpm_dpalloc(dpmemsz, 8); - if (IS_ERR_VALUE(dp_offset)) { - printk(KERN_ERR - "cpm_uart_cpm.c: could not allocate buffer descriptors\n"); - return -ENOMEM; - } - - dp_mem = cpm_dpram_addr(dp_offset); - - memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); - if (is_con) { - mem_addr = kzalloc(memsz, GFP_NOWAIT); - dma_addr = virt_to_bus(mem_addr); - } - else - mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, - GFP_KERNEL); - - if (mem_addr == NULL) { - cpm_dpfree(dp_offset); - printk(KERN_ERR - "cpm_uart_cpm.c: could not allocate coherent memory\n"); - return -ENOMEM; - } - - pinfo->dp_addr = dp_offset; - pinfo->mem_addr = mem_addr; - pinfo->dma_addr = dma_addr; - pinfo->mem_size = memsz; - - pinfo->rx_buf = mem_addr; - pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos - * pinfo->rx_fifosize); - - pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem; - pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; - - return 0; -} - -void cpm_uart_freebuf(struct uart_cpm_port *pinfo) -{ - dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * - pinfo->rx_fifosize) + - L1_CACHE_ALIGN(pinfo->tx_nrfifos * - pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, - pinfo->dma_addr); - - cpm_dpfree(pinfo->dp_addr); -} diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h deleted file mode 100644 index 7194c63dcf5f..000000000000 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h - * - * Driver for CPM (SCC/SMC) serial ports - * - * definitions for cpm2 - * - */ - -#ifndef CPM_UART_CPM2_H -#define CPM_UART_CPM2_H - -#include - -static inline void cpm_set_brg(int brg, int baud) -{ - cpm_setbrg(brg, baud); -} - -static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup) -{ - out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB); - out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB); -} - -static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up) -{ - out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB); - out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB); -} - -#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) - -#endif diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c deleted file mode 100644 index bcc31f2140ac..000000000000 --- a/drivers/serial/crisv10.c +++ /dev/null @@ -1,4573 +0,0 @@ -/* - * Serial port driver for the ETRAX 100LX chip - * - * Copyright (C) 1998-2007 Axis Communications AB - * - * Many, many authors. Based once upon a time on serial.c for 16x50. - * - */ - -static char *serial_version = "$Revision: 1.25 $"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* non-arch dependent serial structures are in linux/serial.h */ -#include -/* while we keep our own stuff (struct e100_serial) in a local .h file */ -#include "crisv10.h" -#include -#include - -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -#ifndef CONFIG_ETRAX_FAST_TIMER -#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER" -#endif -#endif - -#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ - (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0) -#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" -#endif - -#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) -#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" -#endif - -/* - * All of the compatibilty code so we can compile serial.c against - * older kernels is hidden in serial_compat.h - */ -#if defined(LOCAL_HEADERS) -#include "serial_compat.h" -#endif - -struct tty_driver *serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -//#define SERIAL_DEBUG_INTR -//#define SERIAL_DEBUG_OPEN -//#define SERIAL_DEBUG_FLOW -//#define SERIAL_DEBUG_DATA -//#define SERIAL_DEBUG_THROTTLE -//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */ -//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */ - -/* Enable this to use serial interrupts to handle when you - expect the first received event on the serial port to - be an error, break or similar. Used to be able to flash IRMA - from eLinux */ -#define SERIAL_HANDLE_EARLY_ERRORS - -/* Currently 16 descriptors x 128 bytes = 2048 bytes */ -#define SERIAL_DESCR_BUF_SIZE 256 - -#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */ -#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE - -/* We don't want to load the system with massive fast timer interrupt - * on high baudrates so limit it to 250 us (4kHz) */ -#define MIN_FLUSH_TIME_USEC 250 - -/* Add an x here to log a lot of timer stuff */ -#define TIMERD(x) -/* Debug details of interrupt handling */ -#define DINTR1(x) /* irq on/off, errors */ -#define DINTR2(x) /* tx and rx */ -/* Debug flip buffer stuff */ -#define DFLIP(x) -/* Debug flow control and overview of data flow */ -#define DFLOW(x) -#define DBAUD(x) -#define DLOG_INT_TRIG(x) - -//#define DEBUG_LOG_INCLUDED -#ifndef DEBUG_LOG_INCLUDED -#define DEBUG_LOG(line, string, value) -#else -struct debug_log_info -{ - unsigned long time; - unsigned long timer_data; -// int line; - const char *string; - int value; -}; -#define DEBUG_LOG_SIZE 4096 - -struct debug_log_info debug_log[DEBUG_LOG_SIZE]; -int debug_log_pos = 0; - -#define DEBUG_LOG(_line, _string, _value) do { \ - if ((_line) == SERIAL_DEBUG_LINE) {\ - debug_log_func(_line, _string, _value); \ - }\ -}while(0) - -void debug_log_func(int line, const char *string, int value) -{ - if (debug_log_pos < DEBUG_LOG_SIZE) { - debug_log[debug_log_pos].time = jiffies; - debug_log[debug_log_pos].timer_data = *R_TIMER_DATA; -// debug_log[debug_log_pos].line = line; - debug_log[debug_log_pos].string = string; - debug_log[debug_log_pos].value = value; - debug_log_pos++; - } - /*printk(string, value);*/ -} -#endif - -#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS -/* Default number of timer ticks before flushing rx fifo - * When using "little data, low latency applications: use 0 - * When using "much data applications (PPP)" use ~5 - */ -#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 -#endif - -unsigned long timer_data_to_ns(unsigned long timer_data); - -static void change_speed(struct e100_serial *info); -static void rs_throttle(struct tty_struct * tty); -static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -static int rs_write(struct tty_struct *tty, - const unsigned char *buf, int count); -#ifdef CONFIG_ETRAX_RS485 -static int e100_write_rs485(struct tty_struct *tty, - const unsigned char *buf, int count); -#endif -static int get_lsr_info(struct e100_serial *info, unsigned int *value); - - -#define DEF_BAUD 115200 /* 115.2 kbit/s */ -#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ -/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ -#define DEF_TX 0x80 /* or SERIAL_CTRL_B */ - -/* offsets from R_SERIALx_CTRL */ - -#define REG_DATA 0 -#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */ -#define REG_TR_DATA 0 -#define REG_STATUS 1 -#define REG_TR_CTRL 1 -#define REG_REC_CTRL 2 -#define REG_BAUD 3 -#define REG_XOFF 4 /* this is a 32 bit register */ - -/* The bitfields are the same for all serial ports */ -#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd) -#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail) -#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err) -#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err) -#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun) - -#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK) - -/* Values for info->errorcode */ -#define ERRCODE_SET_BREAK (TTY_BREAK) -#define ERRCODE_INSERT 0x100 -#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK) - -#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop; - -/* - * General note regarding the use of IO_* macros in this file: - * - * We will use the bits defined for DMA channel 6 when using various - * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are - * the same for all channels (which of course they are). - * - * We will also use the bits defined for serial port 0 when writing commands - * to the different ports, as these bits too are the same for all ports. - */ - - -/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */ -static const unsigned long e100_ser_int_mask = 0 -#ifdef CONFIG_ETRAX_SERIAL_PORT0 -| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready) -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT1 -| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready) -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT2 -| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready) -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT3 -| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready) -#endif -; -unsigned long r_alt_ser_baudrate_shadow = 0; - -/* this is the data for the four serial ports in the etrax100 */ -/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ -/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ - -static struct e100_serial rs_table[] = { - { .baud = DEF_BAUD, - .ioport = (unsigned char *)R_SERIAL0_CTRL, - .irq = 1U << 12, /* uses DMA 6 and 7 */ - .oclrintradr = R_DMA_CH6_CLR_INTR, - .ofirstadr = R_DMA_CH6_FIRST, - .ocmdadr = R_DMA_CH6_CMD, - .ostatusadr = R_DMA_CH6_STATUS, - .iclrintradr = R_DMA_CH7_CLR_INTR, - .ifirstadr = R_DMA_CH7_FIRST, - .icmdadr = R_DMA_CH7_CMD, - .idescradr = R_DMA_CH7_DESCR, - .flags = STD_FLAGS, - .rx_ctrl = DEF_RX, - .tx_ctrl = DEF_TX, - .iseteop = 2, - .dma_owner = dma_ser0, - .io_if = if_serial_0, -#ifdef CONFIG_ETRAX_SERIAL_PORT0 - .enabled = 1, -#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT - .dma_out_enabled = 1, - .dma_out_nbr = SER0_TX_DMA_NBR, - .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, - .dma_out_irq_description = "serial 0 dma tr", -#else - .dma_out_enabled = 0, - .dma_out_nbr = UINT_MAX, - .dma_out_irq_nbr = 0, - .dma_out_irq_flags = 0, - .dma_out_irq_description = NULL, -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN - .dma_in_enabled = 1, - .dma_in_nbr = SER0_RX_DMA_NBR, - .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, - .dma_in_irq_description = "serial 0 dma rec", -#else - .dma_in_enabled = 0, - .dma_in_nbr = UINT_MAX, - .dma_in_irq_nbr = 0, - .dma_in_irq_flags = 0, - .dma_in_irq_description = NULL, -#endif -#else - .enabled = 0, - .io_if_description = NULL, - .dma_out_enabled = 0, - .dma_in_enabled = 0 -#endif - -}, /* ttyS0 */ -#ifndef CONFIG_SVINTO_SIM - { .baud = DEF_BAUD, - .ioport = (unsigned char *)R_SERIAL1_CTRL, - .irq = 1U << 16, /* uses DMA 8 and 9 */ - .oclrintradr = R_DMA_CH8_CLR_INTR, - .ofirstadr = R_DMA_CH8_FIRST, - .ocmdadr = R_DMA_CH8_CMD, - .ostatusadr = R_DMA_CH8_STATUS, - .iclrintradr = R_DMA_CH9_CLR_INTR, - .ifirstadr = R_DMA_CH9_FIRST, - .icmdadr = R_DMA_CH9_CMD, - .idescradr = R_DMA_CH9_DESCR, - .flags = STD_FLAGS, - .rx_ctrl = DEF_RX, - .tx_ctrl = DEF_TX, - .iseteop = 3, - .dma_owner = dma_ser1, - .io_if = if_serial_1, -#ifdef CONFIG_ETRAX_SERIAL_PORT1 - .enabled = 1, - .io_if_description = "ser1", -#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT - .dma_out_enabled = 1, - .dma_out_nbr = SER1_TX_DMA_NBR, - .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, - .dma_out_irq_description = "serial 1 dma tr", -#else - .dma_out_enabled = 0, - .dma_out_nbr = UINT_MAX, - .dma_out_irq_nbr = 0, - .dma_out_irq_flags = 0, - .dma_out_irq_description = NULL, -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN - .dma_in_enabled = 1, - .dma_in_nbr = SER1_RX_DMA_NBR, - .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, - .dma_in_irq_description = "serial 1 dma rec", -#else - .dma_in_enabled = 0, - .dma_in_enabled = 0, - .dma_in_nbr = UINT_MAX, - .dma_in_irq_nbr = 0, - .dma_in_irq_flags = 0, - .dma_in_irq_description = NULL, -#endif -#else - .enabled = 0, - .io_if_description = NULL, - .dma_in_irq_nbr = 0, - .dma_out_enabled = 0, - .dma_in_enabled = 0 -#endif -}, /* ttyS1 */ - - { .baud = DEF_BAUD, - .ioport = (unsigned char *)R_SERIAL2_CTRL, - .irq = 1U << 4, /* uses DMA 2 and 3 */ - .oclrintradr = R_DMA_CH2_CLR_INTR, - .ofirstadr = R_DMA_CH2_FIRST, - .ocmdadr = R_DMA_CH2_CMD, - .ostatusadr = R_DMA_CH2_STATUS, - .iclrintradr = R_DMA_CH3_CLR_INTR, - .ifirstadr = R_DMA_CH3_FIRST, - .icmdadr = R_DMA_CH3_CMD, - .idescradr = R_DMA_CH3_DESCR, - .flags = STD_FLAGS, - .rx_ctrl = DEF_RX, - .tx_ctrl = DEF_TX, - .iseteop = 0, - .dma_owner = dma_ser2, - .io_if = if_serial_2, -#ifdef CONFIG_ETRAX_SERIAL_PORT2 - .enabled = 1, - .io_if_description = "ser2", -#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT - .dma_out_enabled = 1, - .dma_out_nbr = SER2_TX_DMA_NBR, - .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, - .dma_out_irq_description = "serial 2 dma tr", -#else - .dma_out_enabled = 0, - .dma_out_nbr = UINT_MAX, - .dma_out_irq_nbr = 0, - .dma_out_irq_flags = 0, - .dma_out_irq_description = NULL, -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN - .dma_in_enabled = 1, - .dma_in_nbr = SER2_RX_DMA_NBR, - .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, - .dma_in_irq_description = "serial 2 dma rec", -#else - .dma_in_enabled = 0, - .dma_in_nbr = UINT_MAX, - .dma_in_irq_nbr = 0, - .dma_in_irq_flags = 0, - .dma_in_irq_description = NULL, -#endif -#else - .enabled = 0, - .io_if_description = NULL, - .dma_out_enabled = 0, - .dma_in_enabled = 0 -#endif - }, /* ttyS2 */ - - { .baud = DEF_BAUD, - .ioport = (unsigned char *)R_SERIAL3_CTRL, - .irq = 1U << 8, /* uses DMA 4 and 5 */ - .oclrintradr = R_DMA_CH4_CLR_INTR, - .ofirstadr = R_DMA_CH4_FIRST, - .ocmdadr = R_DMA_CH4_CMD, - .ostatusadr = R_DMA_CH4_STATUS, - .iclrintradr = R_DMA_CH5_CLR_INTR, - .ifirstadr = R_DMA_CH5_FIRST, - .icmdadr = R_DMA_CH5_CMD, - .idescradr = R_DMA_CH5_DESCR, - .flags = STD_FLAGS, - .rx_ctrl = DEF_RX, - .tx_ctrl = DEF_TX, - .iseteop = 1, - .dma_owner = dma_ser3, - .io_if = if_serial_3, -#ifdef CONFIG_ETRAX_SERIAL_PORT3 - .enabled = 1, - .io_if_description = "ser3", -#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT - .dma_out_enabled = 1, - .dma_out_nbr = SER3_TX_DMA_NBR, - .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, - .dma_out_irq_description = "serial 3 dma tr", -#else - .dma_out_enabled = 0, - .dma_out_nbr = UINT_MAX, - .dma_out_irq_nbr = 0, - .dma_out_irq_flags = 0, - .dma_out_irq_description = NULL, -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN - .dma_in_enabled = 1, - .dma_in_nbr = SER3_RX_DMA_NBR, - .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, - .dma_in_irq_description = "serial 3 dma rec", -#else - .dma_in_enabled = 0, - .dma_in_nbr = UINT_MAX, - .dma_in_irq_nbr = 0, - .dma_in_irq_flags = 0, - .dma_in_irq_description = NULL -#endif -#else - .enabled = 0, - .io_if_description = NULL, - .dma_out_enabled = 0, - .dma_in_enabled = 0 -#endif - } /* ttyS3 */ -#endif -}; - - -#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) - -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -static struct fast_timer fast_timers[NR_PORTS]; -#endif - -#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY -#define PROCSTAT(x) x -struct ser_statistics_type { - int overrun_cnt; - int early_errors_cnt; - int ser_ints_ok_cnt; - int errors_cnt; - unsigned long int processing_flip; - unsigned long processing_flip_still_room; - unsigned long int timeout_flush_cnt; - int rx_dma_ints; - int tx_dma_ints; - int rx_tot; - int tx_tot; -}; - -static struct ser_statistics_type ser_stat[NR_PORTS]; - -#else - -#define PROCSTAT(x) - -#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ - -/* RS-485 */ -#if defined(CONFIG_ETRAX_RS485) -#ifdef CONFIG_ETRAX_FAST_TIMER -static struct fast_timer fast_timers_rs485[NR_PORTS]; -#endif -#if defined(CONFIG_ETRAX_RS485_ON_PA) -static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; -#endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; -#endif -#endif - -/* Info and macros needed for each ports extra control/status signals. */ -#define E100_STRUCT_PORT(line, pinname) \ - ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ - (R_PORT_PA_DATA): ( \ - (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ - (R_PORT_PB_DATA):&dummy_ser[line])) - -#define E100_STRUCT_SHADOW(line, pinname) \ - ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ - (&port_pa_data_shadow): ( \ - (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ - (&port_pb_data_shadow):&dummy_ser[line])) -#define E100_STRUCT_MASK(line, pinname) \ - ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ - (1<= 0)? \ - (1< 3.3V to RS-232 driver -> -12V on RS-232 level - * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level - * - * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip - */ - -/* Output */ -#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) -/* Input */ -#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK) - -/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ -/* Is an output */ -#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask) - -/* Normally inputs */ -#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask) -#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask) - -/* Input */ -#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) - - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the memcpy_fromfs blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static DEFINE_MUTEX(tmp_buf_mutex); - -/* 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; - int bits; - - /* calc. number of bits / data byte */ - /* databits + startbit and 1 stopbit */ - if ((cflags & CSIZE) == CS7) - bits = 9; - else - bits = 10; - - if (cflags & CSTOPB) /* 2 stopbits ? */ - bits++; - - if (cflags & PARENB) /* parity bit ? */ - bits++; - - /* calc timeout */ - info->char_time_usec = ((bits * 1000000) / info->baud) + 1; - info->flush_time_usec = 4*info->char_time_usec; - if (info->flush_time_usec < MIN_FLUSH_TIME_USEC) - info->flush_time_usec = MIN_FLUSH_TIME_USEC; - -} - -/* - * This function maps from the Bxxxx defines in asm/termbits.h into real - * baud rates. - */ - -static int -cflag_to_baud(unsigned int cflag) -{ - static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }; - - static int ext_baud_table[] = { - 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000, - 0, 0, 0, 0, 0, 0, 0, 0 }; - - if (cflag & CBAUDEX) - return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; - else - return baud_table[cflag & CBAUD]; -} - -/* and this maps to an etrax100 hardware baud constant */ - -static unsigned char -cflag_to_etrax_baud(unsigned int cflag) -{ - char retval; - - static char baud_table[] = { - -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; - - static char ext_baud_table[] = { - -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 }; - - if (cflag & CBAUDEX) - retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; - else - retval = baud_table[cflag & CBAUD]; - - if (retval < 0) { - printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); - retval = 5; /* choose default 9600 instead */ - } - - return retval | (retval << 4); /* choose same for both TX and RX */ -} - - -/* Various static support functions */ - -/* Functions to set or clear DTR/RTS on the requested line */ -/* It is complicated by the fact that RTS is a serial port register, while - * DTR might not be implemented in the HW at all, and if it is, it can be on - * any general port. - */ - - -static inline void -e100_dtr(struct e100_serial *info, int set) -{ -#ifndef CONFIG_SVINTO_SIM - unsigned char mask = e100_modem_pins[info->line].dtr_mask; - -#ifdef SERIAL_DEBUG_IO - printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); - printk("ser%i shadow before 0x%02X get: %i\n", - info->line, *e100_modem_pins[info->line].dtr_shadow, - E100_DTR_GET(info)); -#endif - /* DTR is active low */ - { - unsigned long flags; - - local_irq_save(flags); - *e100_modem_pins[info->line].dtr_shadow &= ~mask; - *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; - local_irq_restore(flags); - } - -#ifdef SERIAL_DEBUG_IO - printk("ser%i shadow after 0x%02X get: %i\n", - info->line, *e100_modem_pins[info->line].dtr_shadow, - E100_DTR_GET(info)); -#endif -#endif -} - -/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive - * 0=0V , 1=3.3V - */ -static inline void -e100_rts(struct e100_serial *info, int set) -{ -#ifndef CONFIG_SVINTO_SIM - unsigned long flags; - local_irq_save(flags); - info->rx_ctrl &= ~E100_RTS_MASK; - info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ - info->ioport[REG_REC_CTRL] = info->rx_ctrl; - local_irq_restore(flags); -#ifdef SERIAL_DEBUG_IO - printk("ser%i rts %i\n", info->line, set); -#endif -#endif -} - - -/* If this behaves as a modem, RI and CD is an output */ -static inline void -e100_ri_out(struct e100_serial *info, int set) -{ -#ifndef CONFIG_SVINTO_SIM - /* RI is active low */ - { - unsigned char mask = e100_modem_pins[info->line].ri_mask; - unsigned long flags; - - local_irq_save(flags); - *e100_modem_pins[info->line].ri_shadow &= ~mask; - *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; - local_irq_restore(flags); - } -#endif -} -static inline void -e100_cd_out(struct e100_serial *info, int set) -{ -#ifndef CONFIG_SVINTO_SIM - /* CD is active low */ - { - unsigned char mask = e100_modem_pins[info->line].cd_mask; - unsigned long flags; - - local_irq_save(flags); - *e100_modem_pins[info->line].cd_shadow &= ~mask; - *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; - local_irq_restore(flags); - } -#endif -} - -static inline void -e100_disable_rx(struct e100_serial *info) -{ -#ifndef CONFIG_SVINTO_SIM - /* disable the receiver */ - info->ioport[REG_REC_CTRL] = - (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif -} - -static inline void -e100_enable_rx(struct e100_serial *info) -{ -#ifndef CONFIG_SVINTO_SIM - /* enable the receiver */ - info->ioport[REG_REC_CTRL] = - (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif -} - -/* the rx DMA uses both the dma_descr and the dma_eop interrupts */ - -static inline void -e100_disable_rxdma_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("rxdma_irq(%d): 0\n",info->line); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line)); - *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3); -} - -static inline void -e100_enable_rxdma_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("rxdma_irq(%d): 1\n",info->line); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line)); - *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3); -} - -/* the tx DMA uses only dma_descr interrupt */ - -static void e100_disable_txdma_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("txdma_irq(%d): 0\n",info->line); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line)); - *R_IRQ_MASK2_CLR = info->irq; -} - -static void e100_enable_txdma_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("txdma_irq(%d): 1\n",info->line); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line)); - *R_IRQ_MASK2_SET = info->irq; -} - -static void e100_disable_txdma_channel(struct e100_serial *info) -{ - unsigned long flags; - - /* Disable output DMA channel for the serial port in question - * ( set to something other than serialX) - */ - local_irq_save(flags); - DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line)); - if (info->line == 0) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) == - IO_STATE(R_GEN_CONFIG, dma6, serial0)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); - } - } else if (info->line == 1) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) == - IO_STATE(R_GEN_CONFIG, dma8, serial1)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); - } - } else if (info->line == 2) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) == - IO_STATE(R_GEN_CONFIG, dma2, serial2)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); - } - } else if (info->line == 3) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) == - IO_STATE(R_GEN_CONFIG, dma4, serial3)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); - } - } - *R_GEN_CONFIG = genconfig_shadow; - local_irq_restore(flags); -} - - -static void e100_enable_txdma_channel(struct e100_serial *info) -{ - unsigned long flags; - - local_irq_save(flags); - DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line)); - /* Enable output DMA channel for the serial port in question */ - if (info->line == 0) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); - } else if (info->line == 1) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); - } else if (info->line == 2) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); - } else if (info->line == 3) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); - } - *R_GEN_CONFIG = genconfig_shadow; - local_irq_restore(flags); -} - -static void e100_disable_rxdma_channel(struct e100_serial *info) -{ - unsigned long flags; - - /* Disable input DMA channel for the serial port in question - * ( set to something other than serialX) - */ - local_irq_save(flags); - if (info->line == 0) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) == - IO_STATE(R_GEN_CONFIG, dma7, serial0)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused); - } - } else if (info->line == 1) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) == - IO_STATE(R_GEN_CONFIG, dma9, serial1)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb); - } - } else if (info->line == 2) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) == - IO_STATE(R_GEN_CONFIG, dma3, serial2)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); - } - } else if (info->line == 3) { - if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) == - IO_STATE(R_GEN_CONFIG, dma5, serial3)) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); - } - } - *R_GEN_CONFIG = genconfig_shadow; - local_irq_restore(flags); -} - - -static void e100_enable_rxdma_channel(struct e100_serial *info) -{ - unsigned long flags; - - local_irq_save(flags); - /* Enable input DMA channel for the serial port in question */ - if (info->line == 0) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0); - } else if (info->line == 1) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1); - } else if (info->line == 2) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2); - } else if (info->line == 3) { - genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); - genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3); - } - *R_GEN_CONFIG = genconfig_shadow; - local_irq_restore(flags); -} - -#ifdef SERIAL_HANDLE_EARLY_ERRORS -/* in order to detect and fix errors on the first byte - we have to use the serial interrupts as well. */ - -static inline void -e100_disable_serial_data_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("ser_irq(%d): 0\n",info->line); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line)); - *R_IRQ_MASK1_CLR = (1U << (8+2*info->line)); -} - -static inline void -e100_enable_serial_data_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("ser_irq(%d): 1\n",info->line); - printk("**** %d = %d\n", - (8+2*info->line), - (1U << (8+2*info->line))); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line)); - *R_IRQ_MASK1_SET = (1U << (8+2*info->line)); -} -#endif - -static inline void -e100_disable_serial_tx_ready_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("ser_tx_irq(%d): 0\n",info->line); -#endif - DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line)); - *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line)); -} - -static inline void -e100_enable_serial_tx_ready_irq(struct e100_serial *info) -{ -#ifdef SERIAL_DEBUG_INTR - printk("ser_tx_irq(%d): 1\n",info->line); - printk("**** %d = %d\n", - (8+1+2*info->line), - (1U << (8+1+2*info->line))); -#endif - DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line)); - *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line)); -} - -static inline void e100_enable_rx_irq(struct e100_serial *info) -{ - if (info->uses_dma_in) - e100_enable_rxdma_irq(info); - else - e100_enable_serial_data_irq(info); -} -static inline void e100_disable_rx_irq(struct e100_serial *info) -{ - if (info->uses_dma_in) - e100_disable_rxdma_irq(info); - else - e100_disable_serial_data_irq(info); -} - -#if defined(CONFIG_ETRAX_RS485) -/* Enable RS-485 mode on selected port. This is UGLY. */ -static int -e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) -{ - struct e100_serial * info = (struct e100_serial *)tty->driver_data; - -#if defined(CONFIG_ETRAX_RS485_ON_PA) - *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); -#endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 1); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); -#endif - - info->rs485 = *r; - - /* Maximum delay before RTS equal to 1000 */ - if (info->rs485.delay_rts_before_send >= 1000) - info->rs485.delay_rts_before_send = 1000; - -/* printk("rts: on send = %i, after = %i, enabled = %i", - info->rs485.rts_on_send, - info->rs485.rts_after_sent, - info->rs485.enabled - ); -*/ - return 0; -} - -static int -e100_write_rs485(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct e100_serial * info = (struct e100_serial *)tty->driver_data; - int old_value = (info->rs485.flags) & SER_RS485_ENABLED; - - /* rs485 is always implicitly enabled if we're using the ioctl() - * but it doesn't have to be set in the serial_rs485 - * (to be backward compatible with old apps) - * So we store, set and restore it. - */ - info->rs485.flags |= SER_RS485_ENABLED; - /* rs_write now deals with RS485 if enabled */ - count = rs_write(tty, buf, count); - if (!old_value) - info->rs485.flags &= ~(SER_RS485_ENABLED); - return count; -} - -#ifdef CONFIG_ETRAX_FAST_TIMER -/* Timer function to toggle RTS when using FAST_TIMER */ -static void rs485_toggle_rts_timer_function(unsigned long data) -{ - struct e100_serial *info = (struct e100_serial *)data; - - fast_timers_rs485[info->line].function = NULL; - e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_enable_rx(info); - e100_enable_rx_irq(info); -#endif -} -#endif -#endif /* CONFIG_ETRAX_RS485 */ - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter using the XOFF registers, as necessary. - * ------------------------------------------------------------ - */ - -static void -rs_stop(struct tty_struct *tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - if (info) { - unsigned long flags; - unsigned long xoff; - - local_irq_save(flags); - DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n", - CIRC_CNT(info->xmit.head, - info->xmit.tail,SERIAL_XMIT_SIZE))); - - 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 ) { - xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); - } - - *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; - local_irq_restore(flags); - } -} - -static void -rs_start(struct tty_struct *tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - if (info) { - unsigned long flags; - unsigned long xoff; - - local_irq_save(flags); - DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n", - CIRC_CNT(info->xmit.head, - 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 ) { - xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); - } - - *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; - if (!info->uses_dma_out && - info->xmit.head != info->xmit.tail && info->xmit.buf) - e100_enable_serial_tx_ready_irq(info); - - local_irq_restore(flags); - } -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static void rs_sched_event(struct e100_serial *info, int event) -{ - if (info->event & (1 << event)) - return; - info->event |= 1 << event; - schedule_work(&info->work); -} - -/* The output DMA channel is free - use it to send as many chars as possible - * NOTES: - * We don't pay attention to info->x_char, which means if the TTY wants to - * use XON/XOFF it will set info->x_char but we won't send any X char! - * - * To implement this, we'd just start a DMA send of 1 byte pointing at a - * buffer containing the X char, and skip updating xmit. We'd also have to - * check if the last sent char was the X char when we enter this function - * the next time, to avoid updating xmit with the sent X value. - */ - -static void -transmit_chars_dma(struct e100_serial *info) -{ - unsigned int c, sentl; - struct etrax_dma_descr *descr; - -#ifdef CONFIG_SVINTO_SIM - /* This will output too little if tail is not 0 always since - * we don't reloop to send the other part. Anyway this SHOULD be a - * no-op - transmit_chars_dma would never really be called during sim - * since rs_write does not write into the xmit buffer then. - */ - if (info->xmit.tail) - printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); - if (info->xmit.head != info->xmit.tail) { - SIMCOUT(info->xmit.buf + info->xmit.tail, - CIRC_CNT(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE)); - info->xmit.head = info->xmit.tail; /* move back head */ - info->tr_running = 0; - } - return; -#endif - /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ - *info->oclrintradr = - IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | - IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - -#ifdef SERIAL_DEBUG_INTR - if (info->line == SERIAL_DEBUG_LINE) - printk("tc\n"); -#endif - if (!info->tr_running) { - /* weirdo... we shouldn't get here! */ - printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n"); - return; - } - - descr = &info->tr_descr; - - /* first get the amount of bytes sent during the last DMA transfer, - and update xmit accordingly */ - - /* if the stop bit was not set, all data has been sent */ - if (!(descr->status & d_stop)) { - sentl = descr->sw_len; - } else - /* otherwise we find the amount of data sent here */ - sentl = descr->hw_len; - - DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl)); - - /* update stats */ - info->icount.tx += sentl; - - /* update xmit buffer */ - info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1); - - /* if there is only a few chars left in the buf, wake up the blocked - write if any */ - if (CIRC_CNT(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE) < WAKEUP_CHARS) - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - - /* find out the largest amount of consecutive bytes we want to send now */ - - c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); - - /* Don't send all in one DMA transfer - divide it so we wake up - * application before all is sent - */ - - if (c >= 4*WAKEUP_CHARS) - c = c/2; - - if (c <= 0) { - /* our job here is done, don't schedule any new DMA transfer */ - info->tr_running = 0; - -#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) - if (info->rs485.flags & SER_RS485_ENABLED) { - /* Set a short timer to toggle RTS */ - start_one_shot_timer(&fast_timers_rs485[info->line], - rs485_toggle_rts_timer_function, - (unsigned long)info, - info->char_time_usec*2, - "RS-485"); - } -#endif /* RS485 */ - return; - } - - /* ok we can schedule a dma send of c chars starting at info->xmit.tail */ - /* set up the descriptor correctly for output */ - DFLOW(DEBUG_LOG(info->line, "TX %i\n", c)); - descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */ - descr->sw_len = c; - descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail); - descr->status = 0; - - *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */ - *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); - - /* DMA is now running (hopefully) */ -} /* transmit_chars_dma */ - -static void -start_transmit(struct e100_serial *info) -{ -#if 0 - if (info->line == SERIAL_DEBUG_LINE) - printk("x\n"); -#endif - - info->tr_descr.sw_len = 0; - info->tr_descr.hw_len = 0; - info->tr_descr.status = 0; - info->tr_running = 1; - if (info->uses_dma_out) - transmit_chars_dma(info); - else - e100_enable_serial_tx_ready_irq(info); -} /* start_transmit */ - -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -static int serial_fast_timer_started = 0; -static int serial_fast_timer_expired = 0; -static void flush_timeout_function(unsigned long data); -#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\ - unsigned long timer_flags; \ - local_irq_save(timer_flags); \ - if (fast_timers[info->line].function == NULL) { \ - serial_fast_timer_started++; \ - TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ - TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ - start_one_shot_timer(&fast_timers[info->line], \ - flush_timeout_function, \ - (unsigned long)info, \ - (usec), \ - string); \ - } \ - else { \ - TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \ - } \ - local_irq_restore(timer_flags); \ -} -#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec) - -#else -#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) -#define START_FLUSH_FAST_TIMER(info, string) -#endif - -static struct etrax_recv_buffer * -alloc_recv_buffer(unsigned int size) -{ - struct etrax_recv_buffer *buffer; - - if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) - return NULL; - - buffer->next = NULL; - buffer->length = 0; - buffer->error = TTY_NORMAL; - - return buffer; -} - -static void -append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) -{ - unsigned long flags; - - local_irq_save(flags); - - if (!info->first_recv_buffer) - info->first_recv_buffer = buffer; - else - info->last_recv_buffer->next = buffer; - - info->last_recv_buffer = buffer; - - info->recv_cnt += buffer->length; - if (info->recv_cnt > info->max_recv_cnt) - info->max_recv_cnt = info->recv_cnt; - - local_irq_restore(flags); -} - -static int -add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) -{ - struct etrax_recv_buffer *buffer; - if (info->uses_dma_in) { - if (!(buffer = alloc_recv_buffer(4))) - return 0; - - buffer->length = 1; - buffer->error = flag; - buffer->buffer[0] = data; - - append_recv_buffer(info, buffer); - - info->icount.rx++; - } else { - struct tty_struct *tty = info->port.tty; - tty_insert_flip_char(tty, data, flag); - info->icount.rx++; - } - - return 1; -} - -static unsigned int handle_descr_data(struct e100_serial *info, - struct etrax_dma_descr *descr, - unsigned int recvl) -{ - struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; - - if (info->recv_cnt + recvl > 65536) { - printk(KERN_CRIT - "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl); - return 0; - } - - buffer->length = recvl; - - if (info->errorcode == ERRCODE_SET_BREAK) - buffer->error = TTY_BREAK; - info->errorcode = 0; - - append_recv_buffer(info, buffer); - - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) - panic("%s: Failed to allocate memory for receive buffer!\n", __func__); - - descr->buf = virt_to_phys(buffer->buffer); - - return recvl; -} - -static unsigned int handle_all_descr_data(struct e100_serial *info) -{ - struct etrax_dma_descr *descr; - unsigned int recvl; - unsigned int ret = 0; - - while (1) - { - descr = &info->rec_descr[info->cur_rec_descr]; - - if (descr == phys_to_virt(*info->idescradr)) - break; - - if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS) - info->cur_rec_descr = 0; - - /* find out how many bytes were read */ - - /* if the eop bit was not set, all data has been received */ - if (!(descr->status & d_eop)) { - recvl = descr->sw_len; - } else { - /* otherwise we find the amount of data received here */ - recvl = descr->hw_len; - } - - /* Reset the status information */ - descr->status = 0; - - DFLOW( DEBUG_LOG(info->line, "RX %lu\n", recvl); - if (info->port.tty->stopped) { - unsigned char *buf = phys_to_virt(descr->buf); - DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]); - DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]); - DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]); - } - ); - - /* update stats */ - info->icount.rx += recvl; - - ret += handle_descr_data(info, descr, recvl); - } - - return ret; -} - -static void receive_chars_dma(struct e100_serial *info) -{ - struct tty_struct *tty; - unsigned char rstat; - -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - return; -#endif - - /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ - *info->iclrintradr = - IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | - IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - - tty = info->port.tty; - if (!tty) /* Something wrong... */ - return; - -#ifdef SERIAL_HANDLE_EARLY_ERRORS - if (info->uses_dma_in) - e100_enable_serial_data_irq(info); -#endif - - if (info->errorcode == ERRCODE_INSERT_BREAK) - add_char_and_flag(info, '\0', TTY_BREAK); - - handle_all_descr_data(info); - - /* Read the status register to detect errors */ - rstat = info->ioport[REG_STATUS]; - if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { - DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat)); - } - - if (rstat & SER_ERROR_MASK) { - /* If we got an error, we must reset it by reading the - * data_in field - */ - unsigned char data = info->ioport[REG_DATA]; - - PROCSTAT(ser_stat[info->line].errors_cnt++); - DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", - ((rstat & SER_ERROR_MASK) << 8) | data); - - if (rstat & SER_PAR_ERR_MASK) - add_char_and_flag(info, data, TTY_PARITY); - else if (rstat & SER_OVERRUN_MASK) - add_char_and_flag(info, data, TTY_OVERRUN); - else if (rstat & SER_FRAMING_ERR_MASK) - add_char_and_flag(info, data, TTY_FRAME); - } - - START_FLUSH_FAST_TIMER(info, "receive_chars"); - - /* Restart the receiving DMA */ - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); -} - -static int start_recv_dma(struct e100_serial *info) -{ - struct etrax_dma_descr *descr = info->rec_descr; - struct etrax_recv_buffer *buffer; - int i; - - /* Set up the receiving descriptors */ - for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) - panic("%s: Failed to allocate memory for receive buffer!\n", __func__); - - descr[i].ctrl = d_int; - descr[i].buf = virt_to_phys(buffer->buffer); - descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; - descr[i].hw_len = 0; - descr[i].status = 0; - descr[i].next = virt_to_phys(&descr[i+1]); - } - - /* Link the last descriptor to the first */ - descr[i-1].next = virt_to_phys(&descr[0]); - - /* Start with the first descriptor in the list */ - info->cur_rec_descr = 0; - - /* Start the DMA */ - *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]); - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); - - /* Input DMA should be running now */ - return 1; -} - -static void -start_receive(struct e100_serial *info) -{ -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - return; -#endif - if (info->uses_dma_in) { - /* reset the input dma channel to be sure it works */ - - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - - start_recv_dma(info); - } -} - - -/* the bits in the MASK2 register are laid out like this: - DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR - where I is the input channel and O is the output channel for the port. - info->irq is the bit number for the DMAO_DESCR so to check the others we - shift info->irq to the left. -*/ - -/* dma output channel interrupt handler - this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or - DMA8(ser1) when they have finished a descriptor with the intr flag set. -*/ - -static irqreturn_t -tr_interrupt(int irq, void *dev_id) -{ - struct e100_serial *info; - unsigned long ireg; - int i; - int handled = 0; - -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? tr_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return IRQ_HANDLED; -#endif - - /* find out the line that caused this irq and get it from rs_table */ - - ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ - - for (i = 0; i < NR_PORTS; i++) { - info = rs_table + i; - if (!info->enabled || !info->uses_dma_out) - continue; - /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ - if (ireg & info->irq) { - handled = 1; - /* we can send a new dma bunch. make it so. */ - DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i)); - /* Read jiffies_usec first, - * we want this time to be as late as possible - */ - PROCSTAT(ser_stat[info->line].tx_dma_ints++); - info->last_tx_active_usec = GET_JIFFIES_USEC(); - info->last_tx_active = jiffies; - transmit_chars_dma(info); - } - - /* FIXME: here we should really check for a change in the - status lines and if so call status_handle(info) */ - } - return IRQ_RETVAL(handled); -} /* tr_interrupt */ - -/* dma input channel interrupt handler */ - -static irqreturn_t -rec_interrupt(int irq, void *dev_id) -{ - struct e100_serial *info; - unsigned long ireg; - int i; - int handled = 0; - -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? rec_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return IRQ_HANDLED; -#endif - - /* find out the line that caused this irq and get it from rs_table */ - - ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ - - for (i = 0; i < NR_PORTS; i++) { - info = rs_table + i; - if (!info->enabled || !info->uses_dma_in) - continue; - /* check for both dma_eop and dma_descr for the input dma channel */ - if (ireg & ((info->irq << 2) | (info->irq << 3))) { - handled = 1; - /* we have received something */ - receive_chars_dma(info); - } - - /* FIXME: here we should really check for a change in the - status lines and if so call status_handle(info) */ - } - return IRQ_RETVAL(handled); -} /* rec_interrupt */ - -static int force_eop_if_needed(struct e100_serial *info) -{ - /* We check data_avail bit to determine if data has - * arrived since last time - */ - unsigned char rstat = info->ioport[REG_STATUS]; - - /* error or datavail? */ - if (rstat & SER_ERROR_MASK) { - /* Some error has occurred. If there has been valid data, an - * EOP interrupt will be made automatically. If no data, the - * normal ser_interrupt should be enabled and handle it. - * So do nothing! - */ - DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", - rstat | (info->line << 8)); - return 0; - } - - if (rstat & SER_DATA_AVAIL_MASK) { - /* Ok data, no error, count it */ - TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", - rstat | (info->line << 8))); - /* Read data to clear status flags */ - (void)info->ioport[REG_DATA]; - - info->forced_eop = 0; - START_FLUSH_FAST_TIMER(info, "magic"); - return 0; - } - - /* hit the timeout, force an EOP for the input - * dma channel if we haven't already - */ - if (!info->forced_eop) { - info->forced_eop = 1; - PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); - TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); - FORCE_EOP(info); - } - - return 1; -} - -static void flush_to_flip_buffer(struct e100_serial *info) -{ - struct tty_struct *tty; - struct etrax_recv_buffer *buffer; - unsigned long flags; - - local_irq_save(flags); - tty = info->port.tty; - - if (!tty) { - local_irq_restore(flags); - return; - } - - while ((buffer = info->first_recv_buffer) != NULL) { - unsigned int count = buffer->length; - - tty_insert_flip_string(tty, buffer->buffer, count); - info->recv_cnt -= count; - - if (count == buffer->length) { - info->first_recv_buffer = buffer->next; - kfree(buffer); - } else { - buffer->length -= count; - memmove(buffer->buffer, buffer->buffer + count, buffer->length); - buffer->error = TTY_NORMAL; - } - } - - if (!info->first_recv_buffer) - info->last_recv_buffer = NULL; - - local_irq_restore(flags); - - /* This includes a check for low-latency */ - tty_flip_buffer_push(tty); -} - -static void check_flush_timeout(struct e100_serial *info) -{ - /* Flip what we've got (if we can) */ - flush_to_flip_buffer(info); - - /* We might need to flip later, but not to fast - * since the system is busy processing input... */ - if (info->first_recv_buffer) - START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000); - - /* Force eop last, since data might have come while we're processing - * and if we started the slow timer above, we won't start a fast - * below. - */ - force_eop_if_needed(info); -} - -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -static void flush_timeout_function(unsigned long data) -{ - struct e100_serial *info = (struct e100_serial *)data; - - fast_timers[info->line].function = NULL; - serial_fast_timer_expired++; - TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); - TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); - check_flush_timeout(info); -} - -#else - -/* dma fifo/buffer timeout handler - forces an end-of-packet for the dma input channel if no chars - have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. -*/ - -static struct timer_list flush_timer; - -static void -timed_flush_handler(unsigned long ptr) -{ - struct e100_serial *info; - int i; - -#ifdef CONFIG_SVINTO_SIM - return; -#endif - - for (i = 0; i < NR_PORTS; i++) { - info = rs_table + i; - if (info->uses_dma_in) - check_flush_timeout(info); - } - - /* restart flush timer */ - mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); -} -#endif - -#ifdef SERIAL_HANDLE_EARLY_ERRORS - -/* If there is an error (ie break) when the DMA is running and - * there are no bytes in the fifo the DMA is stopped and we get no - * eop interrupt. Thus we have to monitor the first bytes on a DMA - * transfer, and if it is without error we can turn the serial - * interrupts off. - */ - -/* -BREAK handling on ETRAX 100: -ETRAX will generate interrupt although there is no stop bit between the -characters. - -Depending on how long the break sequence is, the end of the breaksequence -will look differently: -| indicates start/end of a character. - -B= Break character (0x00) with framing error. -E= Error byte with parity error received after B characters. -F= "Faked" valid byte received immediately after B characters. -V= Valid byte - -1. - B BL ___________________________ V -.._|__________|__________| |valid data | - -Multiple frame errors with data == 0x00 (B), -the timing matches up "perfectly" so no extra ending char is detected. -The RXD pin is 1 in the last interrupt, in that case -we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really -know if another byte will come and this really is case 2. below -(e.g F=0xFF or 0xFE) -If RXD pin is 0 we can expect another character (see 2. below). - - -2. - - B B E or F__________________..__ V -.._|__________|__________|______ | |valid data - "valid" or - parity error - -Multiple frame errors with data == 0x00 (B), -but the part of the break trigs is interpreted as a start bit (and possibly -some 0 bits followed by a number of 1 bits and a stop bit). -Depending on parity settings etc. this last character can be either -a fake "valid" char (F) or have a parity error (E). - -If the character is valid it will be put in the buffer, -we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt -will set the flags so the tty will handle it, -if it's an error byte it will not be put in the buffer -and we set info->errorcode = ERRCODE_INSERT_BREAK. - -To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp -of the last faulty char (B) and compares it with the current time: -If the time elapsed time is less then 2*char_time_usec we will assume -it's a faked F char and not a Valid char and set -info->errorcode = ERRCODE_SET_BREAK. - -Flaws in the above solution: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -We use the timer to distinguish a F character from a V character, -if a V character is to close after the break we might make the wrong decision. - -TODO: The break will be delayed until an F or V character is received. - -*/ - -static -struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) -{ - unsigned long data_read; - struct tty_struct *tty = info->port.tty; - - if (!tty) { - printk("!NO TTY!\n"); - return info; - } - - /* Read data and status at the same time */ - data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); -more_data: - if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) { - DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); - } - DINTR2(DEBUG_LOG(info->line, "ser_rx %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read))); - - if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) | - IO_MASK(R_SERIAL0_READ, par_err) | - IO_MASK(R_SERIAL0_READ, overrun) )) { - /* An error */ - info->last_rx_active_usec = GET_JIFFIES_USEC(); - info->last_rx_active = jiffies; - DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read)); - DLOG_INT_TRIG( - if (!log_int_trig1_pos) { - log_int_trig1_pos = log_int_pos; - log_int(rdpc(), 0, 0); - } - ); - - - if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) && - (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) { - /* Most likely a break, but we get interrupts over and - * over again. - */ - - if (!info->break_detected_cnt) { - DEBUG_LOG(info->line, "#BRK start\n", 0); - } - if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) { - /* The RX pin is high now, so the break - * must be over, but.... - * we can't really know if we will get another - * last byte ending the break or not. - * And we don't know if the byte (if any) will - * have an error or look valid. - */ - DEBUG_LOG(info->line, "# BL BRK\n", 0); - info->errorcode = ERRCODE_INSERT_BREAK; - } - info->break_detected_cnt++; - } else { - /* The error does not look like a break, but could be - * the end of one - */ - if (info->break_detected_cnt) { - DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); - info->errorcode = ERRCODE_INSERT_BREAK; - } else { - unsigned char data = IO_EXTRACT(R_SERIAL0_READ, - data_in, data_read); - char flag = TTY_NORMAL; - if (info->errorcode == ERRCODE_INSERT_BREAK) { - struct tty_struct *tty = info->port.tty; - tty_insert_flip_char(tty, 0, flag); - info->icount.rx++; - } - - if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) { - info->icount.parity++; - flag = TTY_PARITY; - } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) { - info->icount.overrun++; - flag = TTY_OVERRUN; - } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) { - info->icount.frame++; - flag = TTY_FRAME; - } - tty_insert_flip_char(tty, data, flag); - info->errorcode = 0; - } - info->break_detected_cnt = 0; - } - } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { - /* No error */ - DLOG_INT_TRIG( - if (!log_int_trig1_pos) { - if (log_int_pos >= log_int_size) { - log_int_pos = 0; - } - log_int_trig0_pos = log_int_pos; - log_int(rdpc(), 0, 0); - } - ); - tty_insert_flip_char(tty, - IO_EXTRACT(R_SERIAL0_READ, data_in, data_read), - TTY_NORMAL); - } else { - DEBUG_LOG(info->line, "ser_rx int but no data_avail %08lX\n", data_read); - } - - - info->icount.rx++; - data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); - if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { - DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)); - goto more_data; - } - - tty_flip_buffer_push(info->port.tty); - return info; -} - -static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) -{ - unsigned char rstat; - -#ifdef SERIAL_DEBUG_INTR - printk("Interrupt from serport %d\n", i); -#endif -/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ - if (!info->uses_dma_in) { - return handle_ser_rx_interrupt_no_dma(info); - } - /* DMA is used */ - rstat = info->ioport[REG_STATUS]; - if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { - DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); - } - - if (rstat & SER_ERROR_MASK) { - unsigned char data; - - info->last_rx_active_usec = GET_JIFFIES_USEC(); - info->last_rx_active = jiffies; - /* If we got an error, we must reset it by reading the - * data_in field - */ - data = info->ioport[REG_DATA]; - DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data)); - DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat)); - if (!data && (rstat & SER_FRAMING_ERR_MASK)) { - /* Most likely a break, but we get interrupts over and - * over again. - */ - - if (!info->break_detected_cnt) { - DEBUG_LOG(info->line, "#BRK start\n", 0); - } - if (rstat & SER_RXD_MASK) { - /* The RX pin is high now, so the break - * must be over, but.... - * we can't really know if we will get another - * last byte ending the break or not. - * And we don't know if the byte (if any) will - * have an error or look valid. - */ - DEBUG_LOG(info->line, "# BL BRK\n", 0); - info->errorcode = ERRCODE_INSERT_BREAK; - } - info->break_detected_cnt++; - } else { - /* The error does not look like a break, but could be - * the end of one - */ - if (info->break_detected_cnt) { - DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); - info->errorcode = ERRCODE_INSERT_BREAK; - } else { - if (info->errorcode == ERRCODE_INSERT_BREAK) { - info->icount.brk++; - add_char_and_flag(info, '\0', TTY_BREAK); - } - - if (rstat & SER_PAR_ERR_MASK) { - info->icount.parity++; - add_char_and_flag(info, data, TTY_PARITY); - } else if (rstat & SER_OVERRUN_MASK) { - info->icount.overrun++; - add_char_and_flag(info, data, TTY_OVERRUN); - } else if (rstat & SER_FRAMING_ERR_MASK) { - info->icount.frame++; - add_char_and_flag(info, data, TTY_FRAME); - } - - info->errorcode = 0; - } - info->break_detected_cnt = 0; - DEBUG_LOG(info->line, "#iERR s d %04X\n", - ((rstat & SER_ERROR_MASK) << 8) | data); - } - PROCSTAT(ser_stat[info->line].early_errors_cnt++); - } else { /* It was a valid byte, now let the DMA do the rest */ - unsigned long curr_time_u = GET_JIFFIES_USEC(); - unsigned long curr_time = jiffies; - - if (info->break_detected_cnt) { - /* Detect if this character is a new valid char or the - * last char in a break sequence: If LSBits are 0 and - * MSBits are high AND the time is close to the - * previous interrupt we should discard it. - */ - long elapsed_usec = - (curr_time - info->last_rx_active) * (1000000/HZ) + - curr_time_u - info->last_rx_active_usec; - if (elapsed_usec < 2*info->char_time_usec) { - DEBUG_LOG(info->line, "FBRK %i\n", info->line); - /* Report as BREAK (error) and let - * receive_chars_dma() handle it - */ - info->errorcode = ERRCODE_SET_BREAK; - } else { - DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line); - } - DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); - } - -#ifdef SERIAL_DEBUG_INTR - printk("** OK, disabling ser_interrupts\n"); -#endif - e100_disable_serial_data_irq(info); - DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); - info->break_detected_cnt = 0; - - PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); - } - /* Restarting the DMA never hurts */ - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); - START_FLUSH_FAST_TIMER(info, "ser_int"); - return info; -} /* handle_ser_rx_interrupt */ - -static void handle_ser_tx_interrupt(struct e100_serial *info) -{ - unsigned long flags; - - if (info->x_char) { - unsigned char rstat; - DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char)); - local_irq_save(flags); - rstat = info->ioport[REG_STATUS]; - DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); - - info->ioport[REG_TR_DATA] = info->x_char; - info->icount.tx++; - info->x_char = 0; - /* We must enable since it is disabled in ser_interrupt */ - e100_enable_serial_tx_ready_irq(info); - local_irq_restore(flags); - return; - } - if (info->uses_dma_out) { - unsigned char rstat; - int i; - /* We only use normal tx interrupt when sending x_char */ - DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0)); - local_irq_save(flags); - rstat = info->ioport[REG_STATUS]; - DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); - e100_disable_serial_tx_ready_irq(info); - if (info->port.tty->stopped) - rs_stop(info->port.tty); - /* Enable the DMA channel and tell it to continue */ - e100_enable_txdma_channel(info); - /* Wait 12 cycles before doing the DMA command */ - for(i = 6; i > 0; i--) - nop(); - - *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue); - local_irq_restore(flags); - return; - } - /* Normal char-by-char interrupt */ - if (info->xmit.head == info->xmit.tail - || info->port.tty->stopped - || info->port.tty->hw_stopped) { - DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", - info->port.tty->stopped)); - e100_disable_serial_tx_ready_irq(info); - info->tr_running = 0; - return; - } - DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail])); - /* Send a byte, rs485 timing is critical so turn of ints */ - local_irq_save(flags); - info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; - info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); - info->icount.tx++; - if (info->xmit.head == info->xmit.tail) { -#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) - if (info->rs485.flags & SER_RS485_ENABLED) { - /* Set a short timer to toggle RTS */ - start_one_shot_timer(&fast_timers_rs485[info->line], - rs485_toggle_rts_timer_function, - (unsigned long)info, - info->char_time_usec*2, - "RS-485"); - } -#endif /* RS485 */ - info->last_tx_active_usec = GET_JIFFIES_USEC(); - info->last_tx_active = jiffies; - e100_disable_serial_tx_ready_irq(info); - info->tr_running = 0; - DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0)); - } else { - /* We must enable since it is disabled in ser_interrupt */ - e100_enable_serial_tx_ready_irq(info); - } - local_irq_restore(flags); - - if (CIRC_CNT(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE) < WAKEUP_CHARS) - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - -} /* handle_ser_tx_interrupt */ - -/* result of time measurements: - * RX duration 54-60 us when doing something, otherwise 6-9 us - * ser_int duration: just sending: 8-15 us normally, up to 73 us - */ -static irqreturn_t -ser_interrupt(int irq, void *dev_id) -{ - static volatile int tx_started = 0; - struct e100_serial *info; - int i; - unsigned long flags; - unsigned long irq_mask1_rd; - unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */ - int handled = 0; - static volatile unsigned long reentered_ready_mask = 0; - - local_irq_save(flags); - irq_mask1_rd = *R_IRQ_MASK1_RD; - /* First handle all rx interrupts with ints disabled */ - info = rs_table; - irq_mask1_rd &= e100_ser_int_mask; - for (i = 0; i < NR_PORTS; i++) { - /* Which line caused the data irq? */ - if (irq_mask1_rd & data_mask) { - handled = 1; - handle_ser_rx_interrupt(info); - } - info += 1; - data_mask <<= 2; - } - /* Handle tx interrupts with interrupts enabled so we - * can take care of new data interrupts while transmitting - * We protect the tx part with the tx_started flag. - * We disable the tr_ready interrupts we are about to handle and - * unblock the serial interrupt so new serial interrupts may come. - * - * If we get a new interrupt: - * - it migth be due to synchronous serial ports. - * - serial irq will be blocked by general irq handler. - * - async data will be handled above (sync will be ignored). - * - tx_started flag will prevent us from trying to send again and - * we will exit fast - no need to unblock serial irq. - * - Next (sync) serial interrupt handler will be runned with - * disabled interrupt due to restore_flags() at end of function, - * so sync handler will not be preempted or reentered. - */ - if (!tx_started) { - unsigned long ready_mask; - unsigned long - tx_started = 1; - /* Only the tr_ready interrupts left */ - irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | - IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | - IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | - IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); - while (irq_mask1_rd) { - /* Disable those we are about to handle */ - *R_IRQ_MASK1_CLR = irq_mask1_rd; - /* Unblock the serial interrupt */ - *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); - - local_irq_enable(); - ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */ - info = rs_table; - for (i = 0; i < NR_PORTS; i++) { - /* Which line caused the ready irq? */ - if (irq_mask1_rd & ready_mask) { - handled = 1; - handle_ser_tx_interrupt(info); - } - info += 1; - ready_mask <<= 2; - } - /* handle_ser_tx_interrupt enables tr_ready interrupts */ - local_irq_disable(); - /* Handle reentered TX interrupt */ - irq_mask1_rd = reentered_ready_mask; - } - local_irq_disable(); - tx_started = 0; - } else { - unsigned long ready_mask; - ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | - IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | - IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | - IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); - if (ready_mask) { - reentered_ready_mask |= ready_mask; - /* Disable those we are about to handle */ - *R_IRQ_MASK1_CLR = ready_mask; - DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask)); - } - } - - local_irq_restore(flags); - return IRQ_RETVAL(handled); -} /* ser_interrupt */ -#endif - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ -static void -do_softint(struct work_struct *work) -{ - struct e100_serial *info; - struct tty_struct *tty; - - info = container_of(work, struct e100_serial, work); - - tty = info->port.tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) - tty_wakeup(tty); -} - -static int -startup(struct e100_serial * info) -{ - unsigned long flags; - unsigned long xmit_page; - int i; - - xmit_page = get_zeroed_page(GFP_KERNEL); - if (!xmit_page) - return -ENOMEM; - - local_irq_save(flags); - - /* if it was already initialized, skip this */ - - if (info->flags & ASYNC_INITIALIZED) { - local_irq_restore(flags); - free_page(xmit_page); - return 0; - } - - if (info->xmit.buf) - free_page(xmit_page); - else - info->xmit.buf = (unsigned char *) xmit_page; - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf); -#endif - -#ifdef CONFIG_SVINTO_SIM - /* Bits and pieces collected from below. Better to have them - in one ifdef:ed clause than to mix in a lot of ifdefs, - right? */ - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->xmit.head = info->xmit.tail = 0; - info->first_recv_buffer = info->last_recv_buffer = NULL; - info->recv_cnt = info->max_recv_cnt = 0; - - for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) - info->rec_descr[i].buf = NULL; - - /* No real action in the simulator, but may set info important - to ioctl. */ - change_speed(info); -#else - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - - /* - * Reset the DMA channels and make sure their interrupts are cleared - */ - - if (info->dma_in_enabled) { - info->uses_dma_in = 1; - e100_enable_rxdma_channel(info); - - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - - /* Wait until reset cycle is complete */ - while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - - /* Make sure the irqs are cleared */ - *info->iclrintradr = - IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | - IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - } else { - e100_disable_rxdma_channel(info); - } - - if (info->dma_out_enabled) { - info->uses_dma_out = 1; - e100_enable_txdma_channel(info); - *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - - while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - - /* Make sure the irqs are cleared */ - *info->oclrintradr = - IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | - IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - } else { - e100_disable_txdma_channel(info); - } - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->xmit.head = info->xmit.tail = 0; - info->first_recv_buffer = info->last_recv_buffer = NULL; - info->recv_cnt = info->max_recv_cnt = 0; - - for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) - info->rec_descr[i].buf = 0; - - /* - * and set the speed and other flags of the serial port - * this will start the rx/tx as well - */ -#ifdef SERIAL_HANDLE_EARLY_ERRORS - e100_enable_serial_data_irq(info); -#endif - change_speed(info); - - /* dummy read to reset any serial errors */ - - (void)info->ioport[REG_DATA]; - - /* enable the interrupts */ - if (info->uses_dma_out) - e100_enable_txdma_irq(info); - - e100_enable_rx_irq(info); - - info->tr_running = 0; /* to be sure we don't lock up the transmitter */ - - /* setup the dma input descriptor and start dma */ - - start_receive(info); - - /* for safety, make sure the descriptors last result is 0 bytes written */ - - info->tr_descr.sw_len = 0; - info->tr_descr.hw_len = 0; - info->tr_descr.status = 0; - - /* enable RTS/DTR last */ - - e100_rts(info, 1); - e100_dtr(info, 1); - -#endif /* CONFIG_SVINTO_SIM */ - - info->flags |= ASYNC_INITIALIZED; - - local_irq_restore(flags); - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void -shutdown(struct e100_serial * info) -{ - unsigned long flags; - struct etrax_dma_descr *descr = info->rec_descr; - struct etrax_recv_buffer *buffer; - int i; - -#ifndef CONFIG_SVINTO_SIM - /* shut down the transmitter and receiver */ - DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); - e100_disable_rx(info); - info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); - - /* disable interrupts, reset dma channels */ - if (info->uses_dma_in) { - e100_disable_rxdma_irq(info); - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - info->uses_dma_in = 0; - } else { - e100_disable_serial_data_irq(info); - } - - if (info->uses_dma_out) { - e100_disable_txdma_irq(info); - info->tr_running = 0; - *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - info->uses_dma_out = 0; - } else { - e100_disable_serial_tx_ready_irq(info); - info->tr_running = 0; - } - -#endif /* CONFIG_SVINTO_SIM */ - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....\n", info->line, - info->irq); -#endif - - local_irq_save(flags); - - if (info->xmit.buf) { - free_page((unsigned long)info->xmit.buf); - info->xmit.buf = NULL; - } - - for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) - if (descr[i].buf) { - buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; - kfree(buffer); - descr[i].buf = 0; - } - - 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 */ - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - - -/* change baud rate and other assorted parameters */ - -static void -change_speed(struct e100_serial *info) -{ - unsigned int cflag; - unsigned long xoff; - unsigned long flags; - /* first some safety checks */ - - if (!info->port.tty || !info->port.tty->termios) - return; - if (!info->ioport) - return; - - cflag = info->port.tty->termios->c_cflag; - - /* possibly, the tx/rx should be disabled first to do this safely */ - - /* change baud-rate and write it to the hardware */ - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { - /* Special baudrate */ - u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ - unsigned long alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); - /* R_ALT_SER_BAUDRATE selects the source */ - DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n", - (unsigned long)info->baud_base, info->custom_divisor)); - if (info->baud_base == SERIAL_PRESCALE_BASE) { - /* 0, 2-65535 (0=65536) */ - u16 divisor = info->custom_divisor; - /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */ - /* baudrate is 3.125MHz/custom_divisor */ - alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale); - alt_source = 0x11; - DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor)); - *R_SERIAL_PRESCALE = divisor; - info->baud = SERIAL_PRESCALE_BASE/divisor; - } -#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED - else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && - info->custom_divisor == 1) || - (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && - info->custom_divisor == 8)) { - /* ext_clk selected */ - alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); - DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); - info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; - } -#endif - else - { - /* Bad baudbase, we don't support using timer0 - * for baudrate. - */ - printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n", - (unsigned long)info->baud_base, info->custom_divisor); - } - r_alt_ser_baudrate_shadow &= ~mask; - r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); - *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; - } else { - /* Normal baudrate */ - /* Make sure we use normal baudrate */ - u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ - unsigned long alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); - r_alt_ser_baudrate_shadow &= ~mask; - r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -#ifndef CONFIG_SVINTO_SIM - *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -#endif /* CONFIG_SVINTO_SIM */ - - info->baud = cflag_to_baud(cflag); -#ifndef CONFIG_SVINTO_SIM - info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); -#endif /* CONFIG_SVINTO_SIM */ - } - -#ifndef CONFIG_SVINTO_SIM - /* start with default settings and then fill in changes */ - local_irq_save(flags); - /* 8 bit, no/even parity */ - info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | - IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | - IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); - - /* 8 bit, no/even parity, 1 stop bit, no cts */ - info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | - IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | - IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | - IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | - IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); - - if ((cflag & CSIZE) == CS7) { - /* set 7 bit mode */ - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); - info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); - } - - if (cflag & CSTOPB) { - /* set 2 stop bit mode */ - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); - } - - if (cflag & PARENB) { - /* enable parity */ - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); - info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); - } - - if (cflag & CMSPAR) { - /* enable stick parity, PARODD mean Mark which matches ETRAX */ - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick); - info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick); - } - if (cflag & PARODD) { - /* set odd parity (or Mark if CMSPAR) */ - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); - info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); - } - - if (cflag & CRTSCTS) { - /* enable automatic CTS handling */ - DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0)); - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); - } - - /* make sure the tx and rx are enabled */ - - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); - info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); - - /* actually write the control regs to the hardware */ - - info->ioport[REG_TR_CTRL] = info->tx_ctrl; - 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 ) { - 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); - } - - *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; - local_irq_restore(flags); -#endif /* !CONFIG_SVINTO_SIM */ - - update_char_time(info); - -} /* change_speed */ - -/* start transmitting chars NOW */ - -static void -rs_flush_chars(struct tty_struct *tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - - if (info->tr_running || - info->xmit.head == info->xmit.tail || - tty->stopped || - tty->hw_stopped || - !info->xmit.buf) - return; - -#ifdef SERIAL_DEBUG_FLOW - printk("rs_flush_chars\n"); -#endif - - /* this protection might not exactly be necessary here */ - - local_irq_save(flags); - start_transmit(info); - local_irq_restore(flags); -} - -static int rs_raw_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - - /* first some sanity checks */ - - if (!tty || !info->xmit.buf || !tmp_buf) - return 0; - -#ifdef SERIAL_DEBUG_DATA - if (info->line == SERIAL_DEBUG_LINE) - printk("rs_raw_write (%d), status %d\n", - count, info->ioport[REG_STATUS]); -#endif - -#ifdef CONFIG_SVINTO_SIM - /* Really simple. The output is here and now. */ - SIMCOUT(buf, count); - return count; -#endif - local_save_flags(flags); - DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); - DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); - - - /* The local_irq_disable/restore_flags pairs below are needed - * because the DMA interrupt handler moves the info->xmit values. - * the memcpy needs to be in the critical region unfortunately, - * because we need to read xmit values, memcpy, write xmit values - * in one atomic operation... this could perhaps be avoided by - * more clever design. - */ - local_irq_disable(); - while (count) { - c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE); - - if (count < c) - c = count; - if (c <= 0) - break; - - memcpy(info->xmit.buf + info->xmit.head, buf, c); - info->xmit.head = (info->xmit.head + c) & - (SERIAL_XMIT_SIZE-1); - buf += c; - count -= c; - ret += c; - } - local_irq_restore(flags); - - /* enable transmitter if not running, unless the tty is stopped - * this does not need IRQ protection since if tr_running == 0 - * the IRQ's are not running anyway for this port. - */ - DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret)); - - if (info->xmit.head != info->xmit.tail && - !tty->stopped && - !tty->hw_stopped && - !info->tr_running) { - start_transmit(info); - } - - return ret; -} /* raw_raw_write() */ - -static int -rs_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ -#if defined(CONFIG_ETRAX_RS485) - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - - if (info->rs485.flags & SER_RS485_ENABLED) - { - /* If we are in RS-485 mode, we need to toggle RTS and disable - * the receiver before initiating a DMA transfer - */ -#ifdef CONFIG_ETRAX_FAST_TIMER - /* Abort any started timer */ - fast_timers_rs485[info->line].function = NULL; - del_fast_timer(&fast_timers_rs485[info->line]); -#endif - e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND)); -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_disable_rx(info); - e100_enable_rx_irq(info); -#endif - if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) && - (info->rs485.delay_rts_before_send > 0)) - msleep(info->rs485.delay_rts_before_send); - } -#endif /* CONFIG_ETRAX_RS485 */ - - count = rs_raw_write(tty, buf, count); - -#if defined(CONFIG_ETRAX_RS485) - if (info->rs485.flags & SER_RS485_ENABLED) - { - unsigned int val; - /* If we are in RS-485 mode the following has to be done: - * wait until DMA is ready - * wait on transmit shift register - * toggle RTS - * enable the receiver - */ - - /* Sleep until all sent */ - tty_wait_until_sent(tty, 0); -#ifdef CONFIG_ETRAX_FAST_TIMER - /* Now sleep a little more so that shift register is empty */ - schedule_usleep(info->char_time_usec * 2); -#endif - /* wait on transmit shift register */ - do{ - get_lsr_info(info, &val); - }while (!(val & TIOCSER_TEMT)); - - e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); - -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_enable_rx(info); - e100_enable_rxdma_irq(info); -#endif - } -#endif /* CONFIG_ETRAX_RS485 */ - - return count; -} /* rs_write */ - - -/* how much space is available in the xmit buffer? */ - -static int -rs_write_room(struct tty_struct *tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - - return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -} - -/* How many chars are in the xmit buffer? - * This does not include any chars in the transmitter FIFO. - * Use wait_until_sent for waiting for FIFO drain. - */ - -static int -rs_chars_in_buffer(struct tty_struct *tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - - return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -} - -/* discard everything in the xmit buffer */ - -static void -rs_flush_buffer(struct tty_struct *tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - - local_irq_save(flags); - info->xmit.head = info->xmit.tail = 0; - local_irq_restore(flags); - - tty_wakeup(tty); -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - * - * Since we use DMA we don't check for info->x_char in transmit_chars_dma(), - * but we do it in handle_ser_tx_interrupt(). - * We disable DMA channel and enable tx ready interrupt and write the - * character when possible. - */ -static void rs_send_xchar(struct tty_struct *tty, char ch) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - local_irq_save(flags); - if (info->uses_dma_out) { - /* Put the DMA on hold and disable the channel */ - *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold); - while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) != - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold)); - e100_disable_txdma_channel(info); - } - - /* Must make sure transmitter is not stopped before we can transmit */ - if (tty->stopped) - rs_start(tty); - - /* Enable manual transmit interrupt and send from there */ - DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch)); - info->x_char = ch; - e100_enable_serial_tx_ready_irq(info); - local_irq_restore(flags); -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void -rs_throttle(struct tty_struct * tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %lu....\n", tty_name(tty, buf), - (unsigned long)tty->ldisc.chars_in_buffer(tty)); -#endif - 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) { - /* Turn off RTS line */ - e100_rts(info, 0); - } - if (I_IXOFF(tty)) - rs_send_xchar(tty, STOP_CHAR(tty)); - -} - -static void -rs_unthrottle(struct tty_struct * tty) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %lu....\n", tty_name(tty, buf), - (unsigned long)tty->ldisc.chars_in_buffer(tty)); -#endif - 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) { - /* Assert RTS line */ - e100_rts(info, 1); - } - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_send_xchar(tty, START_CHAR(tty)); - } - -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int -get_serial_info(struct e100_serial * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - /* this is all probably wrong, there are a lot of fields - * here that we don't have in e100_serial and maybe we - * should set them to something else than 0. - */ - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = (int)info->ioport; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int -set_serial_info(struct e100_serial *info, - struct serial_struct *new_info) -{ - struct serial_struct new_serial; - struct e100_serial old_info; - int retval = 0; - - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) - return -EFAULT; - - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - goto check_and_exit; - } - - if (info->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->custom_divisor = new_serial.custom_divisor; - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - check_and_exit: - if (info->flags & ASYNC_INITIALIZED) { - change_speed(info); - } else - retval = startup(info); - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int -get_lsr_info(struct e100_serial * info, unsigned int *value) -{ - unsigned int result = TIOCSER_TEMT; -#ifndef CONFIG_SVINTO_SIM - unsigned long curr_time = jiffies; - unsigned long curr_time_usec = GET_JIFFIES_USEC(); - unsigned long elapsed_usec = - (curr_time - info->last_tx_active) * 1000000/HZ + - curr_time_usec - info->last_tx_active_usec; - - if (info->xmit.head != info->xmit.tail || - elapsed_usec < 2*info->char_time_usec) { - result = 0; - } -#endif - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - -#ifdef SERIAL_DEBUG_IO -struct state_str -{ - int state; - const char *str; -}; - -const struct state_str control_state_str[] = { - {TIOCM_DTR, "DTR" }, - {TIOCM_RTS, "RTS"}, - {TIOCM_ST, "ST?" }, - {TIOCM_SR, "SR?" }, - {TIOCM_CTS, "CTS" }, - {TIOCM_CD, "CD" }, - {TIOCM_RI, "RI" }, - {TIOCM_DSR, "DSR" }, - {0, NULL } -}; - -char *get_control_state_str(int MLines, char *s) -{ - int i = 0; - - s[0]='\0'; - while (control_state_str[i].str != NULL) { - if (MLines & control_state_str[i].state) { - if (s[0] != '\0') { - strcat(s, ", "); - } - strcat(s, control_state_str[i].str); - } - i++; - } - return s; -} -#endif - -static int -rs_break(struct tty_struct *tty, int break_state) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - - if (!info->ioport) - return -EIO; - - local_irq_save(flags); - if (break_state == -1) { - /* Go to manual mode and set the txd pin to 0 */ - /* Clear bit 7 (txd) and 6 (tr_enable) */ - info->tx_ctrl &= 0x3F; - } else { - /* Set bit 7 (txd) and 6 (tr_enable) */ - info->tx_ctrl |= (0x80 | 0x40); - } - info->ioport[REG_TR_CTRL] = info->tx_ctrl; - local_irq_restore(flags); - return 0; -} - -static int -rs_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - - local_irq_save(flags); - - if (clear & TIOCM_RTS) - e100_rts(info, 0); - if (clear & TIOCM_DTR) - e100_dtr(info, 0); - /* Handle FEMALE behaviour */ - if (clear & TIOCM_RI) - e100_ri_out(info, 0); - if (clear & TIOCM_CD) - e100_cd_out(info, 0); - - if (set & TIOCM_RTS) - e100_rts(info, 1); - if (set & TIOCM_DTR) - e100_dtr(info, 1); - /* Handle FEMALE behaviour */ - if (set & TIOCM_RI) - e100_ri_out(info, 1); - if (set & TIOCM_CD) - e100_cd_out(info, 1); - - local_irq_restore(flags); - return 0; -} - -static int -rs_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned int result; - unsigned long flags; - - local_irq_save(flags); - - result = - (!E100_RTS_GET(info) ? TIOCM_RTS : 0) - | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) - | (!E100_RI_GET(info) ? TIOCM_RNG : 0) - | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) - | (!E100_CD_GET(info) ? TIOCM_CAR : 0) - | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); - - local_irq_restore(flags); - -#ifdef SERIAL_DEBUG_IO - printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", - info->line, result, result); - { - char s[100]; - - get_control_state_str(result, s); - printk(KERN_DEBUG "state: %s\n", s); - } -#endif - return result; - -} - - -static int -rs_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct e100_serial * info = (struct e100_serial *)tty->driver_data; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); - - case TIOCSERGSTRUCT: - if (copy_to_user((struct e100_serial *) arg, - info, sizeof(struct e100_serial))) - return -EFAULT; - return 0; - -#if defined(CONFIG_ETRAX_RS485) - case TIOCSERSETRS485: - { - /* In this ioctl we still use the old structure - * rs485_control for backward compatibility - * (if we use serial_rs485, then old user-level code - * wouldn't work anymore...). - * The use of this ioctl is deprecated: use TIOCSRS485 - * instead.*/ - struct rs485_control rs485ctrl; - struct serial_rs485 rs485data; - printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n"); - if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg, - sizeof(rs485ctrl))) - return -EFAULT; - - rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; - rs485data.flags = 0; - if (rs485data.delay_rts_before_send != 0) - rs485data.flags |= SER_RS485_RTS_BEFORE_SEND; - else - rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND); - - if (rs485ctrl.enabled) - rs485data.flags |= SER_RS485_ENABLED; - else - rs485data.flags &= ~(SER_RS485_ENABLED); - - if (rs485ctrl.rts_on_send) - rs485data.flags |= SER_RS485_RTS_ON_SEND; - else - rs485data.flags &= ~(SER_RS485_RTS_ON_SEND); - - if (rs485ctrl.rts_after_sent) - rs485data.flags |= SER_RS485_RTS_AFTER_SEND; - else - rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND); - - return e100_enable_rs485(tty, &rs485data); - } - - case TIOCSRS485: - { - /* This is the new version of TIOCSRS485, with new - * data structure serial_rs485 */ - struct serial_rs485 rs485data; - if (copy_from_user(&rs485data, (struct rs485_control *)arg, - sizeof(rs485data))) - return -EFAULT; - - return e100_enable_rs485(tty, &rs485data); - } - - case TIOCGRS485: - { - struct serial_rs485 *rs485data = - &(((struct e100_serial *)tty->driver_data)->rs485); - /* This is the ioctl to get RS485 data from user-space */ - if (copy_to_user((struct serial_rs485 *) arg, - rs485data, - sizeof(struct serial_rs485))) - return -EFAULT; - break; - } - - case TIOCSERWRRS485: - { - struct rs485_write rs485wr; - if (copy_from_user(&rs485wr, (struct rs485_write *)arg, - sizeof(rs485wr))) - return -EFAULT; - - return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size); - } -#endif - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void -rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - - change_speed(info); - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_start(tty); - } - -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * S structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void -rs_close(struct tty_struct *tty, struct file * filp) -{ - struct e100_serial * info = (struct e100_serial *)tty->driver_data; - unsigned long flags; - - if (!info) - return; - - /* interrupts are disabled for this entire function */ - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - local_irq_restore(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, - info->line, info->count); -#endif - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->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. - */ - printk(KERN_CRIT - "rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; - } - if (info->count) { - local_irq_restore(flags); - return; - } - info->flags |= ASYNC_CLOSING; - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - 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. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the serial receiver and the DMA receive interrupt. - */ -#ifdef SERIAL_HANDLE_EARLY_ERRORS - e100_disable_serial_data_irq(info); -#endif - -#ifndef CONFIG_SVINTO_SIM - e100_disable_rx(info); - e100_disable_rx_irq(info); - - if (info->flags & ASYNC_INITIALIZED) { - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important as we have a transmit FIFO! - */ - rs_wait_until_sent(tty, HZ); - } -#endif - - shutdown(info); - rs_flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) - schedule_timeout_interruptible(info->close_delay); - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); - - /* port closed */ - -#if defined(CONFIG_ETRAX_RS485) - if (info->rs485.flags & SER_RS485_ENABLED) { - info->rs485.flags &= ~(SER_RS485_ENABLED); -#if defined(CONFIG_ETRAX_RS485_ON_PA) - *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); -#endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 0); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); -#endif - } -#endif - - /* - * Release any allocated DMA irq's. - */ - if (info->dma_in_enabled) { - free_irq(info->dma_in_irq_nbr, info); - cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); - info->uses_dma_in = 0; -#ifdef SERIAL_DEBUG_OPEN - printk(KERN_DEBUG "DMA irq '%s' freed\n", - info->dma_in_irq_description); -#endif - } - if (info->dma_out_enabled) { - free_irq(info->dma_out_irq_nbr, info); - cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); - info->uses_dma_out = 0; -#ifdef SERIAL_DEBUG_OPEN - printk(KERN_DEBUG "DMA irq '%s' freed\n", - info->dma_out_irq_description); -#endif - } -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_wait_until_sent(struct tty_struct *tty, int timeout) -{ - unsigned long orig_jiffies; - struct e100_serial *info = (struct e100_serial *)tty->driver_data; - unsigned long curr_time = jiffies; - unsigned long curr_time_usec = GET_JIFFIES_USEC(); - long elapsed_usec = - (curr_time - info->last_tx_active) * (1000000/HZ) + - curr_time_usec - info->last_tx_active_usec; - - /* - * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO - * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) - */ - orig_jiffies = jiffies; - while (info->xmit.head != info->xmit.tail || /* More in send queue */ - (*info->ostatusadr & 0x007f) || /* more in FIFO */ - (elapsed_usec < 2*info->char_time_usec)) { - schedule_timeout_interruptible(1); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - curr_time = jiffies; - curr_time_usec = GET_JIFFIES_USEC(); - elapsed_usec = - (curr_time - info->last_tx_active) * (1000000/HZ) + - curr_time_usec - info->last_tx_active_usec; - } - set_current_state(TASK_RUNNING); -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -void -rs_hangup(struct tty_struct *tty) -{ - struct e100_serial * info = (struct e100_serial *)tty->driver_data; - - rs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int -block_til_ready(struct tty_struct *tty, struct file * filp, - struct e100_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int retval; - int do_clocal = 0, extra_count = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, - !(info->flags & ASYNC_CLOSING)); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) { - do_clocal = 1; - } - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyS%d, count = %d\n", - info->line, info->count); -#endif - local_irq_save(flags); - if (!tty_hung_up_p(filp)) { - extra_count++; - info->count--; - } - local_irq_restore(flags); - info->blocked_open++; - while (1) { - local_irq_save(flags); - /* assert RTS and DTR */ - e100_rts(info, 1); - e100_dtr(info, 1); - local_irq_restore(flags); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CLOSING) && do_clocal) - /* && (do_clocal || DCD_IS_ASSERTED) */ - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - tty_unlock(); - schedule(); - tty_lock(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); - if (extra_count) - info->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static void -deinit_port(struct e100_serial *info) -{ - if (info->dma_out_enabled) { - cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); - free_irq(info->dma_out_irq_nbr, info); - } - if (info->dma_in_enabled) { - cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); - free_irq(info->dma_in_irq_nbr, info); - } -} - -/* - * This routine is called whenever a serial port is opened. - * It performs the serial-specific initialization for the tty structure. - */ -static int -rs_open(struct tty_struct *tty, struct file * filp) -{ - struct e100_serial *info; - int retval, line; - unsigned long page; - int allocated_resources = 0; - - /* find which port we want to open */ - line = tty->index; - - if (line < 0 || line >= NR_PORTS) - return -ENODEV; - - /* find the corresponding e100_serial struct in the table */ - info = rs_table + line; - - /* don't allow the opening of ports that are not enabled in the HW config */ - if (!info->enabled) - return -ENODEV; - -#ifdef SERIAL_DEBUG_OPEN - printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, - info->count); -#endif - - info->count++; - tty->driver_data = info; - info->port.tty = tty; - - info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - return -ENOMEM; - } - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - - /* - * If the port is in the middle of closing, bail out now - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, - !(info->flags & ASYNC_CLOSING)); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * If DMA is enabled try to allocate the irq's. - */ - if (info->count == 1) { - allocated_resources = 1; - if (info->dma_in_enabled) { - if (request_irq(info->dma_in_irq_nbr, - rec_interrupt, - info->dma_in_irq_flags, - info->dma_in_irq_description, - info)) { - printk(KERN_WARNING "DMA irq '%s' busy; " - "falling back to non-DMA mode\n", - info->dma_in_irq_description); - /* Make sure we never try to use DMA in */ - /* for the port again. */ - info->dma_in_enabled = 0; - } else if (cris_request_dma(info->dma_in_nbr, - info->dma_in_irq_description, - DMA_VERBOSE_ON_ERROR, - info->dma_owner)) { - free_irq(info->dma_in_irq_nbr, info); - printk(KERN_WARNING "DMA '%s' busy; " - "falling back to non-DMA mode\n", - info->dma_in_irq_description); - /* Make sure we never try to use DMA in */ - /* for the port again. */ - info->dma_in_enabled = 0; - } -#ifdef SERIAL_DEBUG_OPEN - else - printk(KERN_DEBUG "DMA irq '%s' allocated\n", - info->dma_in_irq_description); -#endif - } - if (info->dma_out_enabled) { - if (request_irq(info->dma_out_irq_nbr, - tr_interrupt, - info->dma_out_irq_flags, - info->dma_out_irq_description, - info)) { - printk(KERN_WARNING "DMA irq '%s' busy; " - "falling back to non-DMA mode\n", - info->dma_out_irq_description); - /* Make sure we never try to use DMA out */ - /* for the port again. */ - info->dma_out_enabled = 0; - } else if (cris_request_dma(info->dma_out_nbr, - info->dma_out_irq_description, - DMA_VERBOSE_ON_ERROR, - info->dma_owner)) { - free_irq(info->dma_out_irq_nbr, info); - printk(KERN_WARNING "DMA '%s' busy; " - "falling back to non-DMA mode\n", - info->dma_out_irq_description); - /* Make sure we never try to use DMA out */ - /* for the port again. */ - info->dma_out_enabled = 0; - } -#ifdef SERIAL_DEBUG_OPEN - else - printk(KERN_DEBUG "DMA irq '%s' allocated\n", - info->dma_out_irq_description); -#endif - } - } - - /* - * Start up the serial port - */ - - retval = startup(info); - if (retval) { - if (allocated_resources) - deinit_port(info); - - /* FIXME Decrease count info->count here too? */ - return retval; - } - - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - if (allocated_resources) - deinit_port(info); - - return retval; - } - - if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - *tty->termios = info->normal_termios; - change_speed(info); - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open ttyS%d successful...\n", info->line); -#endif - DLOG_INT_TRIG( log_int_pos = 0); - - DFLIP( if (info->line == SERIAL_DEBUG_LINE) { - info->icount.rx = 0; - } ); - - return 0; -} - -#ifdef CONFIG_PROC_FS -/* - * /proc fs routines.... - */ - -static void seq_line_info(struct seq_file *m, struct e100_serial *info) -{ - unsigned long tmp; - - seq_printf(m, "%d: uart:E100 port:%lX irq:%d", - info->line, (unsigned long)info->ioport, info->irq); - - if (!info->ioport || (info->type == PORT_UNKNOWN)) { - seq_printf(m, "\n"); - return; - } - - seq_printf(m, " baud:%d", info->baud); - seq_printf(m, " tx:%lu rx:%lu", - (unsigned long)info->icount.tx, - (unsigned long)info->icount.rx); - tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); - if (tmp) - seq_printf(m, " tx_pend:%lu/%lu", - (unsigned long)tmp, - (unsigned long)SERIAL_XMIT_SIZE); - - seq_printf(m, " rx_pend:%lu/%lu", - (unsigned long)info->recv_cnt, - (unsigned long)info->max_recv_cnt); - -#if 1 - if (info->port.tty) { - if (info->port.tty->stopped) - seq_printf(m, " stopped:%i", - (int)info->port.tty->stopped); - if (info->port.tty->hw_stopped) - seq_printf(m, " hw_stopped:%i", - (int)info->port.tty->hw_stopped); - } - - { - unsigned char rstat = info->ioport[REG_STATUS]; - if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect)) - seq_printf(m, " xoff_detect:1"); - } - -#endif - - if (info->icount.frame) - seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame); - - if (info->icount.parity) - seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity); - - if (info->icount.brk) - seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk); - - if (info->icount.overrun) - seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - if (!E100_RTS_GET(info)) - seq_puts(m, "|RTS"); - if (!E100_CTS_GET(info)) - seq_puts(m, "|CTS"); - if (!E100_DTR_GET(info)) - seq_puts(m, "|DTR"); - if (!E100_DSR_GET(info)) - seq_puts(m, "|DSR"); - if (!E100_CD_GET(info)) - seq_puts(m, "|CD"); - if (!E100_RI_GET(info)) - seq_puts(m, "|RI"); - seq_puts(m, "\n"); -} - - -static int crisv10_proc_show(struct seq_file *m, void *v) -{ - int i; - - seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); - - for (i = 0; i < NR_PORTS; i++) { - if (!rs_table[i].enabled) - continue; - seq_line_info(m, &rs_table[i]); - } -#ifdef DEBUG_LOG_INCLUDED - for (i = 0; i < debug_log_pos; i++) { - seq_printf(m, "%-4i %lu.%lu ", - i, debug_log[i].time, - timer_data_to_ns(debug_log[i].timer_data)); - seq_printf(m, debug_log[i].string, debug_log[i].value); - } - seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE); - debug_log_pos = 0; -#endif - return 0; -} - -static int crisv10_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, crisv10_proc_show, NULL); -} - -static const struct file_operations crisv10_proc_fops = { - .owner = THIS_MODULE, - .open = crisv10_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - - -/* Finally, routines used to initialize the serial driver. */ - -static void show_serial_version(void) -{ - printk(KERN_INFO - "ETRAX 100LX serial-driver %s, " - "(c) 2000-2004 Axis Communications AB\r\n", - &serial_version[11]); /* "$Revision: x.yy" */ -} - -/* rs_init inits the driver at boot (using the module_init chain) */ - -static const struct tty_operations rs_ops = { - .open = rs_open, - .close = rs_close, - .write = rs_write, - .flush_chars = rs_flush_chars, - .write_room = rs_write_room, - .chars_in_buffer = rs_chars_in_buffer, - .flush_buffer = rs_flush_buffer, - .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, - .set_termios = rs_set_termios, - .stop = rs_stop, - .start = rs_start, - .hangup = rs_hangup, - .break_ctl = rs_break, - .send_xchar = rs_send_xchar, - .wait_until_sent = rs_wait_until_sent, - .tiocmget = rs_tiocmget, - .tiocmset = rs_tiocmset, -#ifdef CONFIG_PROC_FS - .proc_fops = &crisv10_proc_fops, -#endif -}; - -static int __init rs_init(void) -{ - int i; - struct e100_serial *info; - struct tty_driver *driver = alloc_tty_driver(NR_PORTS); - - if (!driver) - return -ENOMEM; - - show_serial_version(); - - /* Setup the timed flush handler system */ - -#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) - setup_timer(&flush_timer, timed_flush_handler, 0); - mod_timer(&flush_timer, jiffies + 5); -#endif - -#if defined(CONFIG_ETRAX_RS485) -#if defined(CONFIG_ETRAX_RS485_ON_PA) - if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, - rs485_pa_bit)) { - printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " - "RS485 pin\n"); - put_tty_driver(driver); - return -EBUSY; - } -#endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, - rs485_port_g_bit)) { - printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " - "RS485 pin\n"); - put_tty_driver(driver); - return -EBUSY; - } -#endif -#endif - - /* Initialize the tty_driver structure */ - - driver->driver_name = "serial"; - driver->name = "ttyS"; - driver->major = TTY_MAJOR; - driver->minor_start = 64; - driver->type = TTY_DRIVER_TYPE_SERIAL; - driver->subtype = SERIAL_TYPE_NORMAL; - driver->init_termios = tty_std_termios; - driver->init_termios.c_cflag = - 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; - - 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 */ - - for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { - if (info->enabled) { - if (cris_request_io_interface(info->io_if, - info->io_if_description)) { - printk(KERN_CRIT "ETRAX100LX async serial: " - "Could not allocate IO pins for " - "%s, port %d\n", - info->io_if_description, i); - info->enabled = 0; - } - } - info->uses_dma_in = 0; - info->uses_dma_out = 0; - info->line = i; - info->port.tty = NULL; - info->type = PORT_ETRAX; - info->tr_running = 0; - info->forced_eop = 0; - info->baud_base = DEF_BAUD_BASE; - info->custom_divisor = 0; - info->flags = 0; - info->close_delay = 5*HZ/10; - info->closing_wait = 30*HZ; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->normal_termios = driver->init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->xmit.buf = NULL; - info->xmit.tail = info->xmit.head = 0; - info->first_recv_buffer = info->last_recv_buffer = NULL; - info->recv_cnt = info->max_recv_cnt = 0; - info->last_tx_active_usec = 0; - info->last_tx_active = 0; - -#if defined(CONFIG_ETRAX_RS485) - /* Set sane defaults */ - info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); - info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; - info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND); - info->rs485.delay_rts_before_send = 0; - info->rs485.flags &= ~(SER_RS485_ENABLED); -#endif - INIT_WORK(&info->work, do_softint); - - if (info->enabled) { - printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n", - serial_driver->name, info->line, info->ioport); - } - } -#ifdef CONFIG_ETRAX_FAST_TIMER -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER - memset(fast_timers, 0, sizeof(fast_timers)); -#endif -#ifdef CONFIG_ETRAX_RS485 - memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485)); -#endif - fast_timer_init(); -#endif - -#ifndef CONFIG_SVINTO_SIM -#ifndef CONFIG_ETRAX_KGDB - /* Not needed in simulator. May only complicate stuff. */ - /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ - - if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, - IRQF_SHARED | IRQF_DISABLED, "serial ", driver)) - panic("%s: Failed to request irq8", __func__); - -#endif -#endif /* CONFIG_SVINTO_SIM */ - - return 0; -} - -/* this makes sure that rs_init is called during kernel boot */ - -module_init(rs_init); diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h deleted file mode 100644 index ea0beb46a10d..000000000000 --- a/drivers/serial/crisv10.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * serial.h: Arch-dep definitions for the Etrax100 serial driver. - * - * Copyright (C) 1998-2007 Axis Communications AB - */ - -#ifndef _ETRAX_SERIAL_H -#define _ETRAX_SERIAL_H - -#include -#include -#include -#include - -/* Software state per channel */ - -#ifdef __KERNEL__ -/* - * 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 - */ - -#define SERIAL_RECV_DESCRIPTORS 8 - -struct etrax_recv_buffer { - struct etrax_recv_buffer *next; - unsigned short length; - unsigned char error; - unsigned char pad; - - unsigned char buffer[0]; -}; - -struct e100_serial { - struct tty_port port; - int baud; - volatile u8 *ioport; /* R_SERIALx_CTRL */ - u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - - /* Output registers */ - volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ - volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */ - volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */ - const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */ - - /* Input registers */ - volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ - volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */ - volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */ - volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */ - - int flags; /* defined in tty.h */ - - u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ - u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ - u8 iseteop; /* bit number for R_SET_EOP for the input dma */ - int enabled; /* Set to 1 if the port is enabled in HW config */ - - u8 dma_out_enabled; /* Set to 1 if DMA should be used */ - u8 dma_in_enabled; /* Set to 1 if DMA should be used */ - - /* end of fields defined in rs_table[] in .c-file */ - int dma_owner; - unsigned int dma_in_nbr; - unsigned int dma_out_nbr; - unsigned int dma_in_irq_nbr; - unsigned int dma_out_irq_nbr; - unsigned long dma_in_irq_flags; - unsigned long dma_out_irq_flags; - char *dma_in_irq_description; - char *dma_out_irq_description; - - enum cris_io_interface io_if; - char *io_if_description; - - u8 uses_dma_in; /* Set to 1 if DMA is used */ - u8 uses_dma_out; /* Set to 1 if DMA is used */ - u8 forced_eop; /* a fifo eop has been forced */ - int baud_base; /* For special baudrates */ - int custom_divisor; /* For special baudrates */ - struct etrax_dma_descr tr_descr; - struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS]; - int cur_rec_descr; - - volatile int tr_running; /* 1 if output is running */ - - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int line; - int type; /* PORT_ETRAX */ - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - struct circ_buf xmit; - struct etrax_recv_buffer *first_recv_buffer; - struct etrax_recv_buffer *last_recv_buffer; - unsigned int recv_cnt; - unsigned int max_recv_cnt; - - struct work_struct work; - struct async_icount icount; /* error-statistics etc.*/ - struct ktermios normal_termios; - struct ktermios callout_termios; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - unsigned long char_time_usec; /* The time for 1 char, in usecs */ - unsigned long flush_time_usec; /* How often we should flush */ - unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ - unsigned long last_tx_active; /* Last tx time in jiffies */ - unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ - unsigned long last_rx_active; /* Last rx time in jiffies */ - - int break_detected_cnt; - int errorcode; - -#ifdef CONFIG_ETRAX_RS485 - struct serial_rs485 rs485; /* RS-485 support */ -#endif -}; - -/* this PORT is not in the standard serial.h. it's not actually used for - * anything since we only have one type of async serial-port anyway in this - * system. - */ - -#define PORT_ETRAX 1 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -#endif /* __KERNEL__ */ - -#endif /* !_ETRAX_SERIAL_H */ diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c deleted file mode 100644 index 57421d776329..000000000000 --- a/drivers/serial/dz.c +++ /dev/null @@ -1,955 +0,0 @@ -/* - * dz.c: Serial port driver for DECstations equipped - * with the DZ chipset. - * - * Copyright (C) 1998 Olivier A. D. Lebaillif - * - * Email: olivier.lebaillif@ifrsys.com - * - * Copyright (C) 2004, 2006, 2007 Maciej W. Rozycki - * - * [31-AUG-98] triemer - * Changed IRQ to use Harald's dec internals interrupts.h - * removed base_addr code - moving address assignment to setup.c - * Changed name of dz_init to rs_init to be consistent with tc code - * [13-NOV-98] triemer fixed code to receive characters - * after patches by harald to irq code. - * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout - * field from "current" - somewhere between 2.1.121 and 2.1.131 - Qua Jun 27 15:02:26 BRT 2001 - * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups - * - * Parts (C) 1999 David Airlie, airlied@linux.ie - * [07-SEP-99] Bugfixes - * - * [06-Jan-2002] Russell King - * Converted to new serial core - */ - -#undef DEBUG_DZ - -#if defined(CONFIG_SERIAL_DZ_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "dz.h" - - -MODULE_DESCRIPTION("DECstation DZ serial driver"); -MODULE_LICENSE("GPL"); - - -static char dz_name[] __initdata = "DECstation DZ serial driver version "; -static char dz_version[] __initdata = "1.04"; - -struct dz_port { - struct dz_mux *mux; - struct uart_port port; - unsigned int cflag; -}; - -struct dz_mux { - struct dz_port dport[DZ_NB_PORT]; - atomic_t map_guard; - atomic_t irq_guard; - int initialised; -}; - -static struct dz_mux dz_mux; - -static inline struct dz_port *to_dport(struct uart_port *uport) -{ - return container_of(uport, struct dz_port, port); -} - -/* - * ------------------------------------------------------------ - * dz_in () and dz_out () - * - * These routines are used to access the registers of the DZ - * chip, hiding relocation differences between implementation. - * ------------------------------------------------------------ - */ - -static u16 dz_in(struct dz_port *dport, unsigned offset) -{ - void __iomem *addr = dport->port.membase + offset; - - return readw(addr); -} - -static void dz_out(struct dz_port *dport, unsigned offset, u16 value) -{ - void __iomem *addr = dport->port.membase + offset; - - writew(value, addr); -} - -/* - * ------------------------------------------------------------ - * rs_stop () and rs_start () - * - * These routines are called before setting or resetting - * tty->stopped. They enable or disable transmitter interrupts, - * as necessary. - * ------------------------------------------------------------ - */ - -static void dz_stop_tx(struct uart_port *uport) -{ - struct dz_port *dport = to_dport(uport); - u16 tmp, mask = 1 << dport->port.line; - - tmp = dz_in(dport, DZ_TCR); /* read the TX flag */ - tmp &= ~mask; /* clear the TX flag */ - dz_out(dport, DZ_TCR, tmp); -} - -static void dz_start_tx(struct uart_port *uport) -{ - struct dz_port *dport = to_dport(uport); - u16 tmp, mask = 1 << dport->port.line; - - tmp = dz_in(dport, DZ_TCR); /* read the TX flag */ - tmp |= mask; /* set the TX flag */ - dz_out(dport, DZ_TCR, tmp); -} - -static void dz_stop_rx(struct uart_port *uport) -{ - struct dz_port *dport = to_dport(uport); - - dport->cflag &= ~DZ_RXENAB; - dz_out(dport, DZ_LPR, dport->cflag); -} - -static void dz_enable_ms(struct uart_port *uport) -{ - /* nothing to do */ -} - -/* - * ------------------------------------------------------------ - * - * Here start the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * dz_interrupt. They were separated out for readability's sake. - * - * Note: dz_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * dz_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * make drivers/serial/dz.s - * - * and look at the resulting assemble code in dz.s. - * - * ------------------------------------------------------------ - */ - -/* - * ------------------------------------------------------------ - * receive_char () - * - * This routine deals with inputs from any lines. - * ------------------------------------------------------------ - */ -static inline void dz_receive_chars(struct dz_mux *mux) -{ - struct uart_port *uport; - struct dz_port *dport = &mux->dport[0]; - struct tty_struct *tty = NULL; - struct uart_icount *icount; - int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 }; - unsigned char ch, flag; - u16 status; - int i; - - while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) { - dport = &mux->dport[LINE(status)]; - uport = &dport->port; - tty = uport->state->port.tty; /* point to the proper dev */ - - ch = UCHAR(status); /* grab the char */ - flag = TTY_NORMAL; - - icount = &uport->icount; - icount->rx++; - - if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) { - - /* - * There is no separate BREAK status bit, so treat - * null characters with framing errors as BREAKs; - * normally, otherwise. For this move the Framing - * Error bit to a simulated BREAK bit. - */ - if (!ch) { - status |= (status & DZ_FERR) >> - (ffs(DZ_FERR) - ffs(DZ_BREAK)); - status &= ~DZ_FERR; - } - - /* Handle SysRq/SAK & keep track of the statistics. */ - if (status & DZ_BREAK) { - icount->brk++; - if (uart_handle_break(uport)) - continue; - } else if (status & DZ_FERR) - icount->frame++; - else if (status & DZ_PERR) - icount->parity++; - if (status & DZ_OERR) - icount->overrun++; - - status &= uport->read_status_mask; - if (status & DZ_BREAK) - flag = TTY_BREAK; - else if (status & DZ_FERR) - flag = TTY_FRAME; - else if (status & DZ_PERR) - flag = TTY_PARITY; - - } - - if (uart_handle_sysrq_char(uport, ch)) - continue; - - uart_insert_char(uport, status, DZ_OERR, ch, flag); - lines_rx[LINE(status)] = 1; - } - for (i = 0; i < DZ_NB_PORT; i++) - if (lines_rx[i]) - tty_flip_buffer_push(mux->dport[i].port.state->port.tty); -} - -/* - * ------------------------------------------------------------ - * transmit_char () - * - * This routine deals with outputs to any lines. - * ------------------------------------------------------------ - */ -static inline void dz_transmit_chars(struct dz_mux *mux) -{ - struct dz_port *dport = &mux->dport[0]; - struct circ_buf *xmit; - unsigned char tmp; - u16 status; - - status = dz_in(dport, DZ_CSR); - dport = &mux->dport[LINE(status)]; - xmit = &dport->port.state->xmit; - - if (dport->port.x_char) { /* XON/XOFF chars */ - dz_out(dport, DZ_TDR, dport->port.x_char); - dport->port.icount.tx++; - dport->port.x_char = 0; - return; - } - /* If nothing to do or stopped or hardware stopped. */ - if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { - spin_lock(&dport->port.lock); - dz_stop_tx(&dport->port); - spin_unlock(&dport->port.lock); - return; - } - - /* - * If something to do... (remember the dz has no output fifo, - * so we go one char at a time) :-< - */ - tmp = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1); - dz_out(dport, DZ_TDR, tmp); - dport->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) - uart_write_wakeup(&dport->port); - - /* Are we are done. */ - if (uart_circ_empty(xmit)) { - spin_lock(&dport->port.lock); - dz_stop_tx(&dport->port); - spin_unlock(&dport->port.lock); - } -} - -/* - * ------------------------------------------------------------ - * check_modem_status() - * - * DS 3100 & 5100: Only valid for the MODEM line, duh! - * DS 5000/200: Valid for the MODEM and PRINTER line. - * ------------------------------------------------------------ - */ -static inline void check_modem_status(struct dz_port *dport) -{ - /* - * FIXME: - * 1. No status change interrupt; use a timer. - * 2. Handle the 3100/5000 as appropriate. --macro - */ - u16 status; - - /* If not the modem line just return. */ - if (dport->port.line != DZ_MODEM) - return; - - status = dz_in(dport, DZ_MSR); - - /* it's easy, since DSR2 is the only bit in the register */ - if (status) - dport->port.icount.dsr++; -} - -/* - * ------------------------------------------------------------ - * dz_interrupt () - * - * this is the main interrupt routine for the DZ chip. - * It deals with the multiple ports. - * ------------------------------------------------------------ - */ -static irqreturn_t dz_interrupt(int irq, void *dev_id) -{ - struct dz_mux *mux = dev_id; - struct dz_port *dport = &mux->dport[0]; - u16 status; - - /* get the reason why we just got an irq */ - status = dz_in(dport, DZ_CSR); - - if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE)) - dz_receive_chars(mux); - - if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE)) - dz_transmit_chars(mux); - - return IRQ_HANDLED; -} - -/* - * ------------------------------------------------------------------- - * Here ends the DZ interrupt routines. - * ------------------------------------------------------------------- - */ - -static unsigned int dz_get_mctrl(struct uart_port *uport) -{ - /* - * FIXME: Handle the 3100/5000 as appropriate. --macro - */ - struct dz_port *dport = to_dport(uport); - unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; - - if (dport->port.line == DZ_MODEM) { - if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR) - mctrl &= ~TIOCM_DSR; - } - - return mctrl; -} - -static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl) -{ - /* - * FIXME: Handle the 3100/5000 as appropriate. --macro - */ - struct dz_port *dport = to_dport(uport); - u16 tmp; - - if (dport->port.line == DZ_MODEM) { - tmp = dz_in(dport, DZ_TCR); - if (mctrl & TIOCM_DTR) - tmp &= ~DZ_MODEM_DTR; - else - tmp |= DZ_MODEM_DTR; - dz_out(dport, DZ_TCR, tmp); - } -} - -/* - * ------------------------------------------------------------------- - * startup () - * - * various initialization tasks - * ------------------------------------------------------------------- - */ -static int dz_startup(struct uart_port *uport) -{ - struct dz_port *dport = to_dport(uport); - struct dz_mux *mux = dport->mux; - unsigned long flags; - int irq_guard; - int ret; - u16 tmp; - - irq_guard = atomic_add_return(1, &mux->irq_guard); - if (irq_guard != 1) - return 0; - - ret = request_irq(dport->port.irq, dz_interrupt, - IRQF_SHARED, "dz", mux); - if (ret) { - atomic_add(-1, &mux->irq_guard); - printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq); - return ret; - } - - spin_lock_irqsave(&dport->port.lock, flags); - - /* Enable interrupts. */ - tmp = dz_in(dport, DZ_CSR); - tmp |= DZ_RIE | DZ_TIE; - dz_out(dport, DZ_CSR, tmp); - - spin_unlock_irqrestore(&dport->port.lock, flags); - - return 0; -} - -/* - * ------------------------------------------------------------------- - * shutdown () - * - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - * ------------------------------------------------------------------- - */ -static void dz_shutdown(struct uart_port *uport) -{ - struct dz_port *dport = to_dport(uport); - struct dz_mux *mux = dport->mux; - unsigned long flags; - int irq_guard; - u16 tmp; - - spin_lock_irqsave(&dport->port.lock, flags); - dz_stop_tx(&dport->port); - spin_unlock_irqrestore(&dport->port.lock, flags); - - irq_guard = atomic_add_return(-1, &mux->irq_guard); - if (!irq_guard) { - /* Disable interrupts. */ - tmp = dz_in(dport, DZ_CSR); - tmp &= ~(DZ_RIE | DZ_TIE); - dz_out(dport, DZ_CSR, tmp); - - free_irq(dport->port.irq, mux); - } -} - -/* - * ------------------------------------------------------------------- - * dz_tx_empty() -- get the transmitter empty status - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - * ------------------------------------------------------------------- - */ -static unsigned int dz_tx_empty(struct uart_port *uport) -{ - struct dz_port *dport = to_dport(uport); - unsigned short tmp, mask = 1 << dport->port.line; - - tmp = dz_in(dport, DZ_TCR); - tmp &= mask; - - return tmp ? 0 : TIOCSER_TEMT; -} - -static void dz_break_ctl(struct uart_port *uport, int break_state) -{ - /* - * FIXME: Can't access BREAK bits in TDR easily; - * reuse the code for polled TX. --macro - */ - struct dz_port *dport = to_dport(uport); - unsigned long flags; - unsigned short tmp, mask = 1 << dport->port.line; - - spin_lock_irqsave(&uport->lock, flags); - tmp = dz_in(dport, DZ_TCR); - if (break_state) - tmp |= mask; - else - tmp &= ~mask; - dz_out(dport, DZ_TCR, tmp); - spin_unlock_irqrestore(&uport->lock, flags); -} - -static int dz_encode_baud_rate(unsigned int baud) -{ - switch (baud) { - case 50: - return DZ_B50; - case 75: - return DZ_B75; - case 110: - return DZ_B110; - case 134: - return DZ_B134; - case 150: - return DZ_B150; - case 300: - return DZ_B300; - case 600: - return DZ_B600; - case 1200: - return DZ_B1200; - case 1800: - return DZ_B1800; - case 2000: - return DZ_B2000; - case 2400: - return DZ_B2400; - case 3600: - return DZ_B3600; - case 4800: - return DZ_B4800; - case 7200: - return DZ_B7200; - case 9600: - return DZ_B9600; - default: - return -1; - } -} - - -static void dz_reset(struct dz_port *dport) -{ - struct dz_mux *mux = dport->mux; - - if (mux->initialised) - return; - - dz_out(dport, DZ_CSR, DZ_CLR); - while (dz_in(dport, DZ_CSR) & DZ_CLR); - iob(); - - /* Enable scanning. */ - dz_out(dport, DZ_CSR, DZ_MSE); - - mux->initialised = 1; -} - -static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) -{ - struct dz_port *dport = to_dport(uport); - unsigned long flags; - unsigned int cflag, baud; - int bflag; - - cflag = dport->port.line; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cflag |= DZ_CS5; - break; - case CS6: - cflag |= DZ_CS6; - break; - case CS7: - cflag |= DZ_CS7; - break; - case CS8: - default: - cflag |= DZ_CS8; - } - - if (termios->c_cflag & CSTOPB) - cflag |= DZ_CSTOPB; - if (termios->c_cflag & PARENB) - cflag |= DZ_PARENB; - if (termios->c_cflag & PARODD) - cflag |= DZ_PARODD; - - baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600); - bflag = dz_encode_baud_rate(baud); - if (bflag < 0) { /* Try to keep unchanged. */ - baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600); - bflag = dz_encode_baud_rate(baud); - if (bflag < 0) { /* Resort to 9600. */ - baud = 9600; - bflag = DZ_B9600; - } - tty_termios_encode_baud_rate(termios, baud, baud); - } - cflag |= bflag; - - if (termios->c_cflag & CREAD) - cflag |= DZ_RXENAB; - - spin_lock_irqsave(&dport->port.lock, flags); - - uart_update_timeout(uport, termios->c_cflag, baud); - - dz_out(dport, DZ_LPR, cflag); - dport->cflag = cflag; - - /* setup accept flag */ - dport->port.read_status_mask = DZ_OERR; - if (termios->c_iflag & INPCK) - dport->port.read_status_mask |= DZ_FERR | DZ_PERR; - if (termios->c_iflag & (BRKINT | PARMRK)) - dport->port.read_status_mask |= DZ_BREAK; - - /* characters to ignore */ - uport->ignore_status_mask = 0; - if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) - dport->port.ignore_status_mask |= DZ_OERR; - if (termios->c_iflag & IGNPAR) - dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR; - if (termios->c_iflag & IGNBRK) - dport->port.ignore_status_mask |= DZ_BREAK; - - spin_unlock_irqrestore(&dport->port.lock, flags); -} - -/* - * Hack alert! - * Required solely so that the initial PROM-based console - * works undisturbed in parallel with this one. - */ -static void dz_pm(struct uart_port *uport, unsigned int state, - unsigned int oldstate) -{ - struct dz_port *dport = to_dport(uport); - unsigned long flags; - - spin_lock_irqsave(&dport->port.lock, flags); - if (state < 3) - dz_start_tx(&dport->port); - else - dz_stop_tx(&dport->port); - spin_unlock_irqrestore(&dport->port.lock, flags); -} - - -static const char *dz_type(struct uart_port *uport) -{ - return "DZ"; -} - -static void dz_release_port(struct uart_port *uport) -{ - struct dz_mux *mux = to_dport(uport)->mux; - int map_guard; - - iounmap(uport->membase); - uport->membase = NULL; - - map_guard = atomic_add_return(-1, &mux->map_guard); - if (!map_guard) - release_mem_region(uport->mapbase, dec_kn_slot_size); -} - -static int dz_map_port(struct uart_port *uport) -{ - if (!uport->membase) - uport->membase = ioremap_nocache(uport->mapbase, - dec_kn_slot_size); - if (!uport->membase) { - printk(KERN_ERR "dz: Cannot map MMIO\n"); - return -ENOMEM; - } - return 0; -} - -static int dz_request_port(struct uart_port *uport) -{ - struct dz_mux *mux = to_dport(uport)->mux; - int map_guard; - int ret; - - map_guard = atomic_add_return(1, &mux->map_guard); - if (map_guard == 1) { - if (!request_mem_region(uport->mapbase, dec_kn_slot_size, - "dz")) { - atomic_add(-1, &mux->map_guard); - printk(KERN_ERR - "dz: Unable to reserve MMIO resource\n"); - return -EBUSY; - } - } - ret = dz_map_port(uport); - if (ret) { - map_guard = atomic_add_return(-1, &mux->map_guard); - if (!map_guard) - release_mem_region(uport->mapbase, dec_kn_slot_size); - return ret; - } - return 0; -} - -static void dz_config_port(struct uart_port *uport, int flags) -{ - struct dz_port *dport = to_dport(uport); - - if (flags & UART_CONFIG_TYPE) { - if (dz_request_port(uport)) - return; - - uport->type = PORT_DZ; - - dz_reset(dport); - } -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - */ -static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ) - ret = -EINVAL; - if (ser->irq != uport->irq) - ret = -EINVAL; - return ret; -} - -static struct uart_ops dz_ops = { - .tx_empty = dz_tx_empty, - .get_mctrl = dz_get_mctrl, - .set_mctrl = dz_set_mctrl, - .stop_tx = dz_stop_tx, - .start_tx = dz_start_tx, - .stop_rx = dz_stop_rx, - .enable_ms = dz_enable_ms, - .break_ctl = dz_break_ctl, - .startup = dz_startup, - .shutdown = dz_shutdown, - .set_termios = dz_set_termios, - .pm = dz_pm, - .type = dz_type, - .release_port = dz_release_port, - .request_port = dz_request_port, - .config_port = dz_config_port, - .verify_port = dz_verify_port, -}; - -static void __init dz_init_ports(void) -{ - static int first = 1; - unsigned long base; - int line; - - if (!first) - return; - first = 0; - - if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100) - base = dec_kn_slot_base + KN01_DZ11; - else - base = dec_kn_slot_base + KN02_DZ11; - - for (line = 0; line < DZ_NB_PORT; line++) { - struct dz_port *dport = &dz_mux.dport[line]; - struct uart_port *uport = &dport->port; - - dport->mux = &dz_mux; - - uport->irq = dec_interrupt[DEC_IRQ_DZ11]; - uport->fifosize = 1; - uport->iotype = UPIO_MEM; - uport->flags = UPF_BOOT_AUTOCONF; - uport->ops = &dz_ops; - uport->line = line; - uport->mapbase = base; - } -} - -#ifdef CONFIG_SERIAL_DZ_CONSOLE -/* - * ------------------------------------------------------------------- - * dz_console_putchar() -- transmit a character - * - * Polled transmission. This is tricky. We need to mask transmit - * interrupts so that they do not interfere, enable the transmitter - * for the line requested and then wait till the transmit scanner - * requests data for this line. But it may request data for another - * line first, in which case we have to disable its transmitter and - * repeat waiting till our line pops up. Only then the character may - * be transmitted. Finally, the state of the transmitter mask is - * restored. Welcome to the world of PDP-11! - * ------------------------------------------------------------------- - */ -static void dz_console_putchar(struct uart_port *uport, int ch) -{ - struct dz_port *dport = to_dport(uport); - unsigned long flags; - unsigned short csr, tcr, trdy, mask; - int loops = 10000; - - spin_lock_irqsave(&dport->port.lock, flags); - csr = dz_in(dport, DZ_CSR); - dz_out(dport, DZ_CSR, csr & ~DZ_TIE); - tcr = dz_in(dport, DZ_TCR); - tcr |= 1 << dport->port.line; - mask = tcr; - dz_out(dport, DZ_TCR, mask); - iob(); - spin_unlock_irqrestore(&dport->port.lock, flags); - - do { - trdy = dz_in(dport, DZ_CSR); - if (!(trdy & DZ_TRDY)) - continue; - trdy = (trdy & DZ_TLINE) >> 8; - if (trdy == dport->port.line) - break; - mask &= ~(1 << trdy); - dz_out(dport, DZ_TCR, mask); - iob(); - udelay(2); - } while (--loops); - - if (loops) /* Cannot send otherwise. */ - dz_out(dport, DZ_TDR, ch); - - dz_out(dport, DZ_TCR, tcr); - dz_out(dport, DZ_CSR, csr); -} - -/* - * ------------------------------------------------------------------- - * dz_console_print () - * - * dz_console_print is registered for printk. - * The console must be locked when we get here. - * ------------------------------------------------------------------- - */ -static void dz_console_print(struct console *co, - const char *str, - unsigned int count) -{ - struct dz_port *dport = &dz_mux.dport[co->index]; -#ifdef DEBUG_DZ - prom_printf((char *) str); -#endif - uart_console_write(&dport->port, str, count, dz_console_putchar); -} - -static int __init dz_console_setup(struct console *co, char *options) -{ - struct dz_port *dport = &dz_mux.dport[co->index]; - struct uart_port *uport = &dport->port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - ret = dz_map_port(uport); - if (ret) - return ret; - - spin_lock_init(&dport->port.lock); /* For dz_pm(). */ - - dz_reset(dport); - dz_pm(uport, 0, -1); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&dport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver dz_reg; -static struct console dz_console = { - .name = "ttyS", - .write = dz_console_print, - .device = uart_console_device, - .setup = dz_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &dz_reg, -}; - -static int __init dz_serial_console_init(void) -{ - if (!IOASIC) { - dz_init_ports(); - register_console(&dz_console); - return 0; - } else - return -ENXIO; -} - -console_initcall(dz_serial_console_init); - -#define SERIAL_DZ_CONSOLE &dz_console -#else -#define SERIAL_DZ_CONSOLE NULL -#endif /* CONFIG_SERIAL_DZ_CONSOLE */ - -static struct uart_driver dz_reg = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = DZ_NB_PORT, - .cons = SERIAL_DZ_CONSOLE, -}; - -static int __init dz_init(void) -{ - int ret, i; - - if (IOASIC) - return -ENXIO; - - printk("%s%s\n", dz_name, dz_version); - - dz_init_ports(); - - ret = uart_register_driver(&dz_reg); - if (ret) - return ret; - - for (i = 0; i < DZ_NB_PORT; i++) - uart_add_one_port(&dz_reg, &dz_mux.dport[i].port); - - return 0; -} - -module_init(dz_init); diff --git a/drivers/serial/dz.h b/drivers/serial/dz.h deleted file mode 100644 index faf169ed27b3..000000000000 --- a/drivers/serial/dz.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * dz.h: Serial port driver for DECstations equipped - * with the DZ chipset. - * - * Copyright (C) 1998 Olivier A. D. Lebaillif - * - * Email: olivier.lebaillif@ifrsys.com - * - * Copyright (C) 2004, 2006 Maciej W. Rozycki - */ -#ifndef DZ_SERIAL_H -#define DZ_SERIAL_H - -/* - * Definitions for the Control and Status Register. - */ -#define DZ_TRDY 0x8000 /* Transmitter empty */ -#define DZ_TIE 0x4000 /* Transmitter Interrupt Enbl */ -#define DZ_TLINE 0x0300 /* Transmitter Line Number */ -#define DZ_RDONE 0x0080 /* Receiver data ready */ -#define DZ_RIE 0x0040 /* Receive Interrupt Enable */ -#define DZ_MSE 0x0020 /* Master Scan Enable */ -#define DZ_CLR 0x0010 /* Master reset */ -#define DZ_MAINT 0x0008 /* Loop Back Mode */ - -/* - * Definitions for the Receiver Buffer Register. - */ -#define DZ_RBUF_MASK 0x00FF /* Data Mask */ -#define DZ_LINE_MASK 0x0300 /* Line Mask */ -#define DZ_DVAL 0x8000 /* Valid Data indicator */ -#define DZ_OERR 0x4000 /* Overrun error indicator */ -#define DZ_FERR 0x2000 /* Frame error indicator */ -#define DZ_PERR 0x1000 /* Parity error indicator */ - -#define DZ_BREAK 0x0800 /* BREAK event software flag */ - -#define LINE(x) ((x & DZ_LINE_MASK) >> 8) /* Get the line number - from the input buffer */ -#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK)) - -/* - * Definitions for the Transmit Control Register. - */ -#define DZ_LINE_KEYBOARD 0x0001 -#define DZ_LINE_MOUSE 0x0002 -#define DZ_LINE_MODEM 0x0004 -#define DZ_LINE_PRINTER 0x0008 - -#define DZ_MODEM_RTS 0x0800 /* RTS for the modem line (2) */ -#define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */ -#define DZ_PRINT_RTS 0x0200 /* RTS for the prntr line (3) */ -#define DZ_PRINT_DTR 0x0100 /* DTR for the prntr line (3) */ -#define DZ_LNENB 0x000f /* Transmitter Line Enable */ - -/* - * Definitions for the Modem Status Register. - */ -#define DZ_MODEM_RI 0x0800 /* RI for the modem line (2) */ -#define DZ_MODEM_CD 0x0400 /* CD for the modem line (2) */ -#define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */ -#define DZ_MODEM_CTS 0x0100 /* CTS for the modem line (2) */ -#define DZ_PRINT_RI 0x0008 /* RI for the printer line (3) */ -#define DZ_PRINT_CD 0x0004 /* CD for the printer line (3) */ -#define DZ_PRINT_DSR 0x0002 /* DSR for the prntr line (3) */ -#define DZ_PRINT_CTS 0x0001 /* CTS for the prntr line (3) */ - -/* - * Definitions for the Transmit Data Register. - */ -#define DZ_BRK0 0x0100 /* Break assertion for line 0 */ -#define DZ_BRK1 0x0200 /* Break assertion for line 1 */ -#define DZ_BRK2 0x0400 /* Break assertion for line 2 */ -#define DZ_BRK3 0x0800 /* Break assertion for line 3 */ - -/* - * Definitions for the Line Parameter Register. - */ -#define DZ_KEYBOARD 0x0000 /* line 0 = keyboard */ -#define DZ_MOUSE 0x0001 /* line 1 = mouse */ -#define DZ_MODEM 0x0002 /* line 2 = modem */ -#define DZ_PRINTER 0x0003 /* line 3 = printer */ - -#define DZ_CSIZE 0x0018 /* Number of bits per byte (mask) */ -#define DZ_CS5 0x0000 /* 5 bits per byte */ -#define DZ_CS6 0x0008 /* 6 bits per byte */ -#define DZ_CS7 0x0010 /* 7 bits per byte */ -#define DZ_CS8 0x0018 /* 8 bits per byte */ - -#define DZ_CSTOPB 0x0020 /* 2 stop bits instead of one */ - -#define DZ_PARENB 0x0040 /* Parity enable */ -#define DZ_PARODD 0x0080 /* Odd parity instead of even */ - -#define DZ_CBAUD 0x0E00 /* Baud Rate (mask) */ -#define DZ_B50 0x0000 -#define DZ_B75 0x0100 -#define DZ_B110 0x0200 -#define DZ_B134 0x0300 -#define DZ_B150 0x0400 -#define DZ_B300 0x0500 -#define DZ_B600 0x0600 -#define DZ_B1200 0x0700 -#define DZ_B1800 0x0800 -#define DZ_B2000 0x0900 -#define DZ_B2400 0x0A00 -#define DZ_B3600 0x0B00 -#define DZ_B4800 0x0C00 -#define DZ_B7200 0x0D00 -#define DZ_B9600 0x0E00 - -#define DZ_RXENAB 0x1000 /* Receiver Enable */ - -/* - * Addresses for the DZ registers - */ -#define DZ_CSR 0x00 /* Control and Status Register */ -#define DZ_RBUF 0x08 /* Receive Buffer */ -#define DZ_LPR 0x08 /* Line Parameters Register */ -#define DZ_TCR 0x10 /* Transmitter Control Register */ -#define DZ_MSR 0x18 /* Modem Status Register */ -#define DZ_TDR 0x18 /* Transmit Data Register */ - -#define DZ_NB_PORT 4 - -#define DZ_XMIT_SIZE 4096 /* buffer size */ -#define DZ_WAKEUP_CHARS DZ_XMIT_SIZE/4 - -#endif /* DZ_SERIAL_H */ diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c deleted file mode 100644 index 53a468227056..000000000000 --- a/drivers/serial/icom.c +++ /dev/null @@ -1,1658 +0,0 @@ -/* - * icom.c - * - * Copyright (C) 2001 IBM Corporation. All rights reserved. - * - * Serial device driver. - * - * Based on code from serial.c - * - * 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 - * - */ -#define SERIAL_DO_RESTART -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "icom.h" - -/*#define ICOM_TRACE enable port trace capabilities */ - -#define ICOM_DRIVER_NAME "icom" -#define ICOM_VERSION_STR "1.3.1" -#define NR_PORTS 128 -#define ICOM_PORT ((struct icom_port *)port) -#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref) - -static const struct pci_device_id icom_pci_table[] = { - { - .vendor = PCI_VENDOR_ID_IBM, - .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = ADAPTER_V1, - }, - { - .vendor = PCI_VENDOR_ID_IBM, - .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, - .subvendor = PCI_VENDOR_ID_IBM, - .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, - .driver_data = ADAPTER_V2, - }, - { - .vendor = PCI_VENDOR_ID_IBM, - .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, - .subvendor = PCI_VENDOR_ID_IBM, - .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, - .driver_data = ADAPTER_V2, - }, - { - .vendor = PCI_VENDOR_ID_IBM, - .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, - .subvendor = PCI_VENDOR_ID_IBM, - .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, - .driver_data = ADAPTER_V2, - }, - { - .vendor = PCI_VENDOR_ID_IBM, - .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, - .subvendor = PCI_VENDOR_ID_IBM, - .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE, - .driver_data = ADAPTER_V2, - }, - {} -}; - -struct lookup_proc_table start_proc[4] = { - {NULL, ICOM_CONTROL_START_A}, - {NULL, ICOM_CONTROL_START_B}, - {NULL, ICOM_CONTROL_START_C}, - {NULL, ICOM_CONTROL_START_D} -}; - - -struct lookup_proc_table stop_proc[4] = { - {NULL, ICOM_CONTROL_STOP_A}, - {NULL, ICOM_CONTROL_STOP_B}, - {NULL, ICOM_CONTROL_STOP_C}, - {NULL, ICOM_CONTROL_STOP_D} -}; - -struct lookup_int_table int_mask_tbl[4] = { - {NULL, ICOM_INT_MASK_PRC_A}, - {NULL, ICOM_INT_MASK_PRC_B}, - {NULL, ICOM_INT_MASK_PRC_C}, - {NULL, ICOM_INT_MASK_PRC_D}, -}; - - -MODULE_DEVICE_TABLE(pci, icom_pci_table); - -static LIST_HEAD(icom_adapter_head); - -/* spinlock for adapter initialization and changing adapter operations */ -static spinlock_t icom_lock; - -#ifdef ICOM_TRACE -static inline void trace(struct icom_port *icom_port, char *trace_pt, - unsigned long trace_data) -{ - dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", - icom_port->port, trace_pt, trace_data); -} -#else -static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; -#endif -static void icom_kref_release(struct kref *kref); - -static void free_port_memory(struct icom_port *icom_port) -{ - struct pci_dev *dev = icom_port->adapter->pci_dev; - - trace(icom_port, "RET_PORT_MEM", 0); - if (icom_port->recv_buf) { - pci_free_consistent(dev, 4096, icom_port->recv_buf, - icom_port->recv_buf_pci); - icom_port->recv_buf = NULL; - } - if (icom_port->xmit_buf) { - pci_free_consistent(dev, 4096, icom_port->xmit_buf, - icom_port->xmit_buf_pci); - icom_port->xmit_buf = NULL; - } - if (icom_port->statStg) { - pci_free_consistent(dev, 4096, icom_port->statStg, - icom_port->statStg_pci); - icom_port->statStg = NULL; - } - - if (icom_port->xmitRestart) { - pci_free_consistent(dev, 4096, icom_port->xmitRestart, - icom_port->xmitRestart_pci); - icom_port->xmitRestart = NULL; - } -} - -static int __devinit get_port_memory(struct icom_port *icom_port) -{ - int index; - unsigned long stgAddr; - unsigned long startStgAddr; - unsigned long offset; - struct pci_dev *dev = icom_port->adapter->pci_dev; - - icom_port->xmit_buf = - pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci); - if (!icom_port->xmit_buf) { - dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); - return -ENOMEM; - } - - trace(icom_port, "GET_PORT_MEM", - (unsigned long) icom_port->xmit_buf); - - icom_port->recv_buf = - pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci); - if (!icom_port->recv_buf) { - dev_err(&dev->dev, "Can not allocate Receive buffer\n"); - free_port_memory(icom_port); - return -ENOMEM; - } - trace(icom_port, "GET_PORT_MEM", - (unsigned long) icom_port->recv_buf); - - icom_port->statStg = - pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci); - if (!icom_port->statStg) { - dev_err(&dev->dev, "Can not allocate Status buffer\n"); - free_port_memory(icom_port); - return -ENOMEM; - } - trace(icom_port, "GET_PORT_MEM", - (unsigned long) icom_port->statStg); - - icom_port->xmitRestart = - pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci); - if (!icom_port->xmitRestart) { - dev_err(&dev->dev, - "Can not allocate xmit Restart buffer\n"); - free_port_memory(icom_port); - return -ENOMEM; - } - - memset(icom_port->statStg, 0, 4096); - - /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that - indicates that frames are to be transmitted - */ - - stgAddr = (unsigned long) icom_port->statStg; - for (index = 0; index < NUM_XBUFFS; index++) { - trace(icom_port, "FOD_ADDR", stgAddr); - stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]); - if (index < (NUM_XBUFFS - 1)) { - memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); - icom_port->statStg->xmit[index].leLengthASD = - (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); - trace(icom_port, "FOD_ADDR", stgAddr); - trace(icom_port, "FOD_XBUFF", - (unsigned long) icom_port->xmit_buf); - icom_port->statStg->xmit[index].leBuffer = - cpu_to_le32(icom_port->xmit_buf_pci); - } else if (index == (NUM_XBUFFS - 1)) { - memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); - icom_port->statStg->xmit[index].leLengthASD = - (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); - trace(icom_port, "FOD_XBUFF", - (unsigned long) icom_port->xmit_buf); - icom_port->statStg->xmit[index].leBuffer = - cpu_to_le32(icom_port->xmit_buf_pci); - } else { - memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); - } - } - /* FIDs */ - startStgAddr = stgAddr; - - /* fill in every entry, even if no buffer */ - for (index = 0; index < NUM_RBUFFS; index++) { - trace(icom_port, "FID_ADDR", stgAddr); - stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]); - icom_port->statStg->rcv[index].leLength = 0; - icom_port->statStg->rcv[index].WorkingLength = - (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); - if (index < (NUM_RBUFFS - 1) ) { - offset = stgAddr - (unsigned long) icom_port->statStg; - icom_port->statStg->rcv[index].leNext = - cpu_to_le32(icom_port-> statStg_pci + offset); - trace(icom_port, "FID_RBUFF", - (unsigned long) icom_port->recv_buf); - icom_port->statStg->rcv[index].leBuffer = - cpu_to_le32(icom_port->recv_buf_pci); - } else if (index == (NUM_RBUFFS -1) ) { - offset = startStgAddr - (unsigned long) icom_port->statStg; - icom_port->statStg->rcv[index].leNext = - cpu_to_le32(icom_port-> statStg_pci + offset); - trace(icom_port, "FID_RBUFF", - (unsigned long) icom_port->recv_buf + 2048); - icom_port->statStg->rcv[index].leBuffer = - cpu_to_le32(icom_port->recv_buf_pci + 2048); - } else { - icom_port->statStg->rcv[index].leNext = 0; - icom_port->statStg->rcv[index].leBuffer = 0; - } - } - - return 0; -} - -static void stop_processor(struct icom_port *icom_port) -{ - unsigned long temp; - unsigned long flags; - int port; - - spin_lock_irqsave(&icom_lock, flags); - - port = icom_port->port; - if (port == 0 || port == 1) - stop_proc[port].global_control_reg = &icom_port->global_reg->control; - else - stop_proc[port].global_control_reg = &icom_port->global_reg->control_2; - - - if (port < 4) { - temp = readl(stop_proc[port].global_control_reg); - temp = - (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; - writel(temp, stop_proc[port].global_control_reg); - - /* write flush */ - readl(stop_proc[port].global_control_reg); - } else { - dev_err(&icom_port->adapter->pci_dev->dev, - "Invalid port assignment\n"); - } - - spin_unlock_irqrestore(&icom_lock, flags); -} - -static void start_processor(struct icom_port *icom_port) -{ - unsigned long temp; - unsigned long flags; - int port; - - spin_lock_irqsave(&icom_lock, flags); - - port = icom_port->port; - if (port == 0 || port == 1) - start_proc[port].global_control_reg = &icom_port->global_reg->control; - else - start_proc[port].global_control_reg = &icom_port->global_reg->control_2; - if (port < 4) { - temp = readl(start_proc[port].global_control_reg); - temp = - (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; - writel(temp, start_proc[port].global_control_reg); - - /* write flush */ - readl(start_proc[port].global_control_reg); - } else { - dev_err(&icom_port->adapter->pci_dev->dev, - "Invalid port assignment\n"); - } - - spin_unlock_irqrestore(&icom_lock, flags); -} - -static void load_code(struct icom_port *icom_port) -{ - const struct firmware *fw; - char __iomem *iram_ptr; - int index; - int status = 0; - void __iomem *dram_ptr = icom_port->dram; - dma_addr_t temp_pci; - unsigned char *new_page = NULL; - unsigned char cable_id = NO_CABLE; - struct pci_dev *dev = icom_port->adapter->pci_dev; - - /* Clear out any pending interrupts */ - writew(0x3FFF, icom_port->int_reg); - - trace(icom_port, "CLEAR_INTERRUPTS", 0); - - /* Stop processor */ - stop_processor(icom_port); - - /* Zero out DRAM */ - memset_io(dram_ptr, 0, 512); - - /* Load Call Setup into Adapter */ - if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) { - dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n"); - status = -1; - goto load_code_exit; - } - - if (fw->size > ICOM_DCE_IRAM_OFFSET) { - dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n"); - release_firmware(fw); - status = -1; - goto load_code_exit; - } - - iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET; - for (index = 0; index < fw->size; index++) - writeb(fw->data[index], &iram_ptr[index]); - - release_firmware(fw); - - /* Load Resident DCE portion of Adapter */ - if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) { - dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n"); - status = -1; - goto load_code_exit; - } - - if (fw->size > ICOM_IRAM_SIZE) { - dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n"); - release_firmware(fw); - status = -1; - goto load_code_exit; - } - - iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET; - for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++) - writeb(fw->data[index], &iram_ptr[index]); - - release_firmware(fw); - - /* Set Hardware level */ - if (icom_port->adapter->version == ADAPTER_V2) - writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); - - /* Start the processor in Adapter */ - start_processor(icom_port); - - writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL), - &(icom_port->dram->HDLCConfigReg)); - writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ - writeb(0x00, &(icom_port->dram->CmdReg)); - writeb(0x10, &(icom_port->dram->async_config3)); - writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC | - ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2)); - - /*Set up data in icom DRAM to indicate where personality - *code is located and its length. - */ - new_page = pci_alloc_consistent(dev, 4096, &temp_pci); - - if (!new_page) { - dev_err(&dev->dev, "Can not allocate DMA buffer\n"); - status = -1; - goto load_code_exit; - } - - if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) { - dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n"); - status = -1; - goto load_code_exit; - } - - if (fw->size > ICOM_DCE_IRAM_OFFSET) { - dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n"); - release_firmware(fw); - status = -1; - goto load_code_exit; - } - - for (index = 0; index < fw->size; index++) - new_page[index] = fw->data[index]; - - release_firmware(fw); - - writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); - writel(temp_pci, &icom_port->dram->mac_load_addr); - - /*Setting the syncReg to 0x80 causes adapter to start downloading - the personality code into adapter instruction RAM. - Once code is loaded, it will begin executing and, based on - information provided above, will start DMAing data from - shared memory to adapter DRAM. - */ - /* the wait loop below verifies this write operation has been done - and processed - */ - writeb(START_DOWNLOAD, &icom_port->dram->sync); - - /* Wait max 1 Sec for data download and processor to start */ - for (index = 0; index < 10; index++) { - msleep(100); - if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE) - break; - } - - if (index == 10) - status = -1; - - /* - * check Cable ID - */ - cable_id = readb(&icom_port->dram->cable_id); - - if (cable_id & ICOM_CABLE_ID_VALID) { - /* Get cable ID into the lower 4 bits (standard form) */ - cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4; - icom_port->cable_id = cable_id; - } else { - dev_err(&dev->dev,"Invalid or no cable attached\n"); - icom_port->cable_id = NO_CABLE; - } - - load_code_exit: - - if (status != 0) { - /* Clear out any pending interrupts */ - writew(0x3FFF, icom_port->int_reg); - - /* Turn off port */ - writeb(ICOM_DISABLE, &(icom_port->dram->disable)); - - /* Stop processor */ - stop_processor(icom_port); - - dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n"); - } - - if (new_page != NULL) - pci_free_consistent(dev, 4096, new_page, temp_pci); -} - -static int startup(struct icom_port *icom_port) -{ - unsigned long temp; - unsigned char cable_id, raw_cable_id; - unsigned long flags; - int port; - - trace(icom_port, "STARTUP", 0); - - if (!icom_port->dram) { - /* should NEVER be NULL */ - dev_err(&icom_port->adapter->pci_dev->dev, - "Unusable Port, port configuration missing\n"); - return -ENODEV; - } - - /* - * check Cable ID - */ - raw_cable_id = readb(&icom_port->dram->cable_id); - trace(icom_port, "CABLE_ID", raw_cable_id); - - /* Get cable ID into the lower 4 bits (standard form) */ - cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; - - /* Check for valid Cable ID */ - if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || - (cable_id != icom_port->cable_id)) { - - /* reload adapter code, pick up any potential changes in cable id */ - load_code(icom_port); - - /* still no sign of cable, error out */ - raw_cable_id = readb(&icom_port->dram->cable_id); - cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; - if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || - (icom_port->cable_id == NO_CABLE)) - return -EIO; - } - - /* - * Finally, clear and enable interrupts - */ - spin_lock_irqsave(&icom_lock, flags); - port = icom_port->port; - if (port == 0 || port == 1) - int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; - else - int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; - - if (port == 0 || port == 2) - writew(0x00FF, icom_port->int_reg); - else - writew(0x3F00, icom_port->int_reg); - if (port < 4) { - temp = readl(int_mask_tbl[port].global_int_mask); - writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); - - /* write flush */ - readl(int_mask_tbl[port].global_int_mask); - } else { - dev_err(&icom_port->adapter->pci_dev->dev, - "Invalid port assignment\n"); - } - - spin_unlock_irqrestore(&icom_lock, flags); - return 0; -} - -static void shutdown(struct icom_port *icom_port) -{ - unsigned long temp; - unsigned char cmdReg; - unsigned long flags; - int port; - - spin_lock_irqsave(&icom_lock, flags); - trace(icom_port, "SHUTDOWN", 0); - - /* - * disable all interrupts - */ - port = icom_port->port; - if (port == 0 || port == 1) - int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; - else - int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; - - if (port < 4) { - temp = readl(int_mask_tbl[port].global_int_mask); - writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); - - /* write flush */ - readl(int_mask_tbl[port].global_int_mask); - } else { - dev_err(&icom_port->adapter->pci_dev->dev, - "Invalid port assignment\n"); - } - spin_unlock_irqrestore(&icom_lock, flags); - - /* - * disable break condition - */ - cmdReg = readb(&icom_port->dram->CmdReg); - if (cmdReg & CMD_SND_BREAK) { - writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); - } -} - -static int icom_write(struct uart_port *port) -{ - unsigned long data_count; - unsigned char cmdReg; - unsigned long offset; - int temp_tail = port->state->xmit.tail; - - trace(ICOM_PORT, "WRITE", 0); - - if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & - SA_FLAGS_READY_TO_XMIT) { - trace(ICOM_PORT, "WRITE_FULL", 0); - return 0; - } - - data_count = 0; - while ((port->state->xmit.head != temp_tail) && - (data_count <= XMIT_BUFF_SZ)) { - - ICOM_PORT->xmit_buf[data_count++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - } - - if (data_count) { - ICOM_PORT->statStg->xmit[0].flags = - cpu_to_le16(SA_FLAGS_READY_TO_XMIT); - ICOM_PORT->statStg->xmit[0].leLength = - cpu_to_le16(data_count); - offset = - (unsigned long) &ICOM_PORT->statStg->xmit[0] - - (unsigned long) ICOM_PORT->statStg; - *ICOM_PORT->xmitRestart = - cpu_to_le32(ICOM_PORT->statStg_pci + offset); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg | CMD_XMIT_RCV_ENABLE, - &ICOM_PORT->dram->CmdReg); - writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd); - trace(ICOM_PORT, "WRITE_START", data_count); - /* write flush */ - readb(&ICOM_PORT->dram->StartXmitCmd); - } - - return data_count; -} - -static inline void check_modem_status(struct icom_port *icom_port) -{ - static char old_status = 0; - char delta_status; - unsigned char status; - - spin_lock(&icom_port->uart_port.lock); - - /*modem input register */ - status = readb(&icom_port->dram->isr); - trace(icom_port, "CHECK_MODEM", status); - delta_status = status ^ old_status; - if (delta_status) { - if (delta_status & ICOM_RI) - icom_port->uart_port.icount.rng++; - if (delta_status & ICOM_DSR) - icom_port->uart_port.icount.dsr++; - if (delta_status & ICOM_DCD) - uart_handle_dcd_change(&icom_port->uart_port, - delta_status & ICOM_DCD); - if (delta_status & ICOM_CTS) - uart_handle_cts_change(&icom_port->uart_port, - delta_status & ICOM_CTS); - - wake_up_interruptible(&icom_port->uart_port.state-> - port.delta_msr_wait); - old_status = status; - } - spin_unlock(&icom_port->uart_port.lock); -} - -static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) -{ - unsigned short int count; - int i; - - if (port_int_reg & (INT_XMIT_COMPLETED)) { - trace(icom_port, "XMIT_COMPLETE", 0); - - /* clear buffer in use bit */ - icom_port->statStg->xmit[0].flags &= - cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); - - count = (unsigned short int) - cpu_to_le16(icom_port->statStg->xmit[0].leLength); - icom_port->uart_port.icount.tx += count; - - for (i=0; iuart_port.state->xmit); i++) { - - icom_port->uart_port.state->xmit.tail++; - icom_port->uart_port.state->xmit.tail &= - (UART_XMIT_SIZE - 1); - } - - if (!icom_write(&icom_port->uart_port)) - /* activate write queue */ - uart_write_wakeup(&icom_port->uart_port); - } else - trace(icom_port, "XMIT_DISABLED", 0); -} - -static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) -{ - short int count, rcv_buff; - struct tty_struct *tty = icom_port->uart_port.state->port.tty; - unsigned short int status; - struct uart_icount *icount; - unsigned long offset; - unsigned char flag; - - trace(icom_port, "RCV_COMPLETE", 0); - rcv_buff = icom_port->next_rcv; - - status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); - while (status & SA_FL_RCV_DONE) { - int first = -1; - - trace(icom_port, "FID_STATUS", status); - count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); - - trace(icom_port, "RCV_COUNT", count); - - trace(icom_port, "REAL_COUNT", count); - - offset = - cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - - icom_port->recv_buf_pci; - - /* Block copy all but the last byte as this may have status */ - if (count > 0) { - first = icom_port->recv_buf[offset]; - tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1); - } - - icount = &icom_port->uart_port.icount; - icount->rx += count; - - /* Break detect logic */ - if ((status & SA_FLAGS_FRAME_ERROR) - && first == 0) { - status &= ~SA_FLAGS_FRAME_ERROR; - status |= SA_FLAGS_BREAK_DET; - trace(icom_port, "BREAK_DET", 0); - } - - flag = TTY_NORMAL; - - if (status & - (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | - SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { - - if (status & SA_FLAGS_BREAK_DET) - icount->brk++; - if (status & SA_FLAGS_PARITY_ERROR) - icount->parity++; - if (status & SA_FLAGS_FRAME_ERROR) - icount->frame++; - if (status & SA_FLAGS_OVERRUN) - icount->overrun++; - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - */ - if (status & icom_port->ignore_status_mask) { - trace(icom_port, "IGNORE_CHAR", 0); - goto ignore_char; - } - - status &= icom_port->read_status_mask; - - if (status & SA_FLAGS_BREAK_DET) { - flag = TTY_BREAK; - } else if (status & SA_FLAGS_PARITY_ERROR) { - trace(icom_port, "PARITY_ERROR", 0); - flag = TTY_PARITY; - } else if (status & SA_FLAGS_FRAME_ERROR) - flag = TTY_FRAME; - - } - - tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag); - - if (status & SA_FLAGS_OVERRUN) - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); -ignore_char: - icom_port->statStg->rcv[rcv_buff].flags = 0; - icom_port->statStg->rcv[rcv_buff].leLength = 0; - icom_port->statStg->rcv[rcv_buff].WorkingLength = - (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); - - rcv_buff++; - if (rcv_buff == NUM_RBUFFS) - rcv_buff = 0; - - status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); - } - icom_port->next_rcv = rcv_buff; - tty_flip_buffer_push(tty); -} - -static void process_interrupt(u16 port_int_reg, - struct icom_port *icom_port) -{ - - spin_lock(&icom_port->uart_port.lock); - trace(icom_port, "INTERRUPT", port_int_reg); - - if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) - xmit_interrupt(port_int_reg, icom_port); - - if (port_int_reg & INT_RCV_COMPLETED) - recv_interrupt(port_int_reg, icom_port); - - spin_unlock(&icom_port->uart_port.lock); -} - -static irqreturn_t icom_interrupt(int irq, void *dev_id) -{ - void __iomem * int_reg; - u32 adapter_interrupts; - u16 port_int_reg; - struct icom_adapter *icom_adapter; - struct icom_port *icom_port; - - /* find icom_port for this interrupt */ - icom_adapter = (struct icom_adapter *) dev_id; - - if (icom_adapter->version == ADAPTER_V2) { - int_reg = icom_adapter->base_addr + 0x8024; - - adapter_interrupts = readl(int_reg); - - if (adapter_interrupts & 0x00003FFF) { - /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */ - icom_port = &icom_adapter->port_info[2]; - port_int_reg = (u16) adapter_interrupts; - process_interrupt(port_int_reg, icom_port); - check_modem_status(icom_port); - } - if (adapter_interrupts & 0x3FFF0000) { - /* port 3 interrupt */ - icom_port = &icom_adapter->port_info[3]; - if (icom_port->status == ICOM_PORT_ACTIVE) { - port_int_reg = - (u16) (adapter_interrupts >> 16); - process_interrupt(port_int_reg, icom_port); - check_modem_status(icom_port); - } - } - - /* Clear out any pending interrupts */ - writel(adapter_interrupts, int_reg); - - int_reg = icom_adapter->base_addr + 0x8004; - } else { - int_reg = icom_adapter->base_addr + 0x4004; - } - - adapter_interrupts = readl(int_reg); - - if (adapter_interrupts & 0x00003FFF) { - /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */ - icom_port = &icom_adapter->port_info[0]; - port_int_reg = (u16) adapter_interrupts; - process_interrupt(port_int_reg, icom_port); - check_modem_status(icom_port); - } - if (adapter_interrupts & 0x3FFF0000) { - /* port 1 interrupt */ - icom_port = &icom_adapter->port_info[1]; - if (icom_port->status == ICOM_PORT_ACTIVE) { - port_int_reg = (u16) (adapter_interrupts >> 16); - process_interrupt(port_int_reg, icom_port); - check_modem_status(icom_port); - } - } - - /* Clear out any pending interrupts */ - writel(adapter_interrupts, int_reg); - - /* flush the write */ - adapter_interrupts = readl(int_reg); - - return IRQ_HANDLED; -} - -/* - * ------------------------------------------------------------------ - * Begin serial-core API - * ------------------------------------------------------------------ - */ -static unsigned int icom_tx_empty(struct uart_port *port) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & - SA_FLAGS_READY_TO_XMIT) - ret = TIOCSER_TEMT; - else - ret = 0; - - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - unsigned char local_osr; - - trace(ICOM_PORT, "SET_MODEM", 0); - local_osr = readb(&ICOM_PORT->dram->osr); - - if (mctrl & TIOCM_RTS) { - trace(ICOM_PORT, "RAISE_RTS", 0); - local_osr |= ICOM_RTS; - } else { - trace(ICOM_PORT, "LOWER_RTS", 0); - local_osr &= ~ICOM_RTS; - } - - if (mctrl & TIOCM_DTR) { - trace(ICOM_PORT, "RAISE_DTR", 0); - local_osr |= ICOM_DTR; - } else { - trace(ICOM_PORT, "LOWER_DTR", 0); - local_osr &= ~ICOM_DTR; - } - - writeb(local_osr, &ICOM_PORT->dram->osr); -} - -static unsigned int icom_get_mctrl(struct uart_port *port) -{ - unsigned char status; - unsigned int result; - - trace(ICOM_PORT, "GET_MODEM", 0); - - status = readb(&ICOM_PORT->dram->isr); - - result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) - | ((status & ICOM_RI) ? TIOCM_RNG : 0) - | ((status & ICOM_DSR) ? TIOCM_DSR : 0) - | ((status & ICOM_CTS) ? TIOCM_CTS : 0); - return result; -} - -static void icom_stop_tx(struct uart_port *port) -{ - unsigned char cmdReg; - - trace(ICOM_PORT, "STOP", 0); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); -} - -static void icom_start_tx(struct uart_port *port) -{ - unsigned char cmdReg; - - trace(ICOM_PORT, "START", 0); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) - writeb(cmdReg & ~CMD_HOLD_XMIT, - &ICOM_PORT->dram->CmdReg); - - icom_write(port); -} - -static void icom_send_xchar(struct uart_port *port, char ch) -{ - unsigned char xdata; - int index; - unsigned long flags; - - trace(ICOM_PORT, "SEND_XCHAR", ch); - - /* wait .1 sec to send char */ - for (index = 0; index < 10; index++) { - spin_lock_irqsave(&port->lock, flags); - xdata = readb(&ICOM_PORT->dram->xchar); - if (xdata == 0x00) { - trace(ICOM_PORT, "QUICK_WRITE", 0); - writeb(ch, &ICOM_PORT->dram->xchar); - - /* flush write operation */ - xdata = readb(&ICOM_PORT->dram->xchar); - spin_unlock_irqrestore(&port->lock, flags); - break; - } - spin_unlock_irqrestore(&port->lock, flags); - msleep(10); - } -} - -static void icom_stop_rx(struct uart_port *port) -{ - unsigned char cmdReg; - - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); -} - -static void icom_enable_ms(struct uart_port *port) -{ - /* no-op */ -} - -static void icom_break(struct uart_port *port, int break_state) -{ - unsigned char cmdReg; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - trace(ICOM_PORT, "BREAK", 0); - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - if (break_state == -1) { - writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); - } else { - writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); - } - spin_unlock_irqrestore(&port->lock, flags); -} - -static int icom_open(struct uart_port *port) -{ - int retval; - - kref_get(&ICOM_PORT->adapter->kref); - retval = startup(ICOM_PORT); - - if (retval) { - kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); - trace(ICOM_PORT, "STARTUP_ERROR", 0); - return retval; - } - - return 0; -} - -static void icom_close(struct uart_port *port) -{ - unsigned char cmdReg; - - trace(ICOM_PORT, "CLOSE", 0); - - /* stop receiver */ - cmdReg = readb(&ICOM_PORT->dram->CmdReg); - writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE, - &ICOM_PORT->dram->CmdReg); - - shutdown(ICOM_PORT); - - kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); -} - -static void icom_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old_termios) -{ - int baud; - unsigned cflag, iflag; - char new_config2; - char new_config3 = 0; - char tmp_byte; - int index; - int rcv_buff, xmit_buff; - unsigned long offset; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - trace(ICOM_PORT, "CHANGE_SPEED", 0); - - cflag = termios->c_cflag; - iflag = termios->c_iflag; - - new_config2 = ICOM_ACFG_DRIVE1; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: /* 5 bits/char */ - new_config2 |= ICOM_ACFG_5BPC; - break; - case CS6: /* 6 bits/char */ - new_config2 |= ICOM_ACFG_6BPC; - break; - case CS7: /* 7 bits/char */ - new_config2 |= ICOM_ACFG_7BPC; - break; - case CS8: /* 8 bits/char */ - new_config2 |= ICOM_ACFG_8BPC; - break; - default: - break; - } - if (cflag & CSTOPB) { - /* 2 stop bits */ - new_config2 |= ICOM_ACFG_2STOP_BIT; - } - if (cflag & PARENB) { - /* parity bit enabled */ - new_config2 |= ICOM_ACFG_PARITY_ENAB; - trace(ICOM_PORT, "PARENB", 0); - } - if (cflag & PARODD) { - /* odd parity */ - new_config2 |= ICOM_ACFG_PARITY_ODD; - trace(ICOM_PORT, "PARODD", 0); - } - - /* Determine divisor based on baud rate */ - baud = uart_get_baud_rate(port, termios, old_termios, - icom_acfg_baud[0], - icom_acfg_baud[BAUD_TABLE_LIMIT]); - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ - - for (index = 0; index < BAUD_TABLE_LIMIT; index++) { - if (icom_acfg_baud[index] == baud) { - new_config3 = index; - break; - } - } - - uart_update_timeout(port, cflag, baud); - - /* CTS flow control flag and modem status interrupts */ - tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); - if (cflag & CRTSCTS) - tmp_byte |= HDLC_HDW_FLOW; - else - tmp_byte &= ~HDLC_HDW_FLOW; - writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); - - /* - * Set up parity check flag - */ - ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; - if (iflag & INPCK) - ICOM_PORT->read_status_mask |= - SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR; - - if ((iflag & BRKINT) || (iflag & PARMRK)) - ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET; - - /* - * Characters to ignore - */ - ICOM_PORT->ignore_status_mask = 0; - if (iflag & IGNPAR) - ICOM_PORT->ignore_status_mask |= - SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR; - if (iflag & IGNBRK) { - ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (iflag & IGNPAR) - ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN; - } - - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE; - - /* Turn off Receiver to prepare for reset */ - writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg); - - for (index = 0; index < 10; index++) { - if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) { - break; - } - } - - /* clear all current buffers of data */ - for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) { - ICOM_PORT->statStg->rcv[rcv_buff].flags = 0; - ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0; - ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength = - (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); - } - - for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) { - ICOM_PORT->statStg->xmit[xmit_buff].flags = 0; - } - - /* activate changes and start xmit and receiver here */ - /* Enable the receiver */ - writeb(new_config3, &(ICOM_PORT->dram->async_config3)); - writeb(new_config2, &(ICOM_PORT->dram->async_config2)); - tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); - tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL; - writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); - writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */ - writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */ - - /* reset processor */ - writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg); - - for (index = 0; index < 10; index++) { - if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) { - break; - } - } - - /* Enable Transmitter and Reciever */ - offset = - (unsigned long) &ICOM_PORT->statStg->rcv[0] - - (unsigned long) ICOM_PORT->statStg; - writel(ICOM_PORT->statStg_pci + offset, - &ICOM_PORT->dram->RcvStatusAddr); - ICOM_PORT->next_rcv = 0; - ICOM_PORT->put_length = 0; - *ICOM_PORT->xmitRestart = 0; - writel(ICOM_PORT->xmitRestart_pci, - &ICOM_PORT->dram->XmitStatusAddr); - trace(ICOM_PORT, "XR_ENAB", 0); - writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *icom_type(struct uart_port *port) -{ - return "icom"; -} - -static void icom_release_port(struct uart_port *port) -{ -} - -static int icom_request_port(struct uart_port *port) -{ - return 0; -} - -static void icom_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_ICOM; -} - -static struct uart_ops icom_ops = { - .tx_empty = icom_tx_empty, - .set_mctrl = icom_set_mctrl, - .get_mctrl = icom_get_mctrl, - .stop_tx = icom_stop_tx, - .start_tx = icom_start_tx, - .send_xchar = icom_send_xchar, - .stop_rx = icom_stop_rx, - .enable_ms = icom_enable_ms, - .break_ctl = icom_break, - .startup = icom_open, - .shutdown = icom_close, - .set_termios = icom_set_termios, - .type = icom_type, - .release_port = icom_release_port, - .request_port = icom_request_port, - .config_port = icom_config_port, -}; - -#define ICOM_CONSOLE NULL - -static struct uart_driver icom_uart_driver = { - .owner = THIS_MODULE, - .driver_name = ICOM_DRIVER_NAME, - .dev_name = "ttyA", - .major = ICOM_MAJOR, - .minor = ICOM_MINOR_START, - .nr = NR_PORTS, - .cons = ICOM_CONSOLE, -}; - -static int __devinit icom_init_ports(struct icom_adapter *icom_adapter) -{ - u32 subsystem_id = icom_adapter->subsystem_id; - int i; - struct icom_port *icom_port; - - if (icom_adapter->version == ADAPTER_V1) { - icom_adapter->numb_ports = 2; - - for (i = 0; i < 2; i++) { - icom_port = &icom_adapter->port_info[i]; - icom_port->port = i; - icom_port->status = ICOM_PORT_ACTIVE; - icom_port->imbed_modem = ICOM_UNKNOWN; - } - } else { - if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) { - icom_adapter->numb_ports = 4; - - for (i = 0; i < 4; i++) { - icom_port = &icom_adapter->port_info[i]; - - icom_port->port = i; - icom_port->status = ICOM_PORT_ACTIVE; - icom_port->imbed_modem = ICOM_IMBED_MODEM; - } - } else { - icom_adapter->numb_ports = 4; - - icom_adapter->port_info[0].port = 0; - icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE; - - if (subsystem_id == - PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) { - icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM; - } else { - icom_adapter->port_info[0].imbed_modem = ICOM_RVX; - } - - icom_adapter->port_info[1].status = ICOM_PORT_OFF; - - icom_adapter->port_info[2].port = 2; - icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE; - icom_adapter->port_info[2].imbed_modem = ICOM_RVX; - icom_adapter->port_info[3].status = ICOM_PORT_OFF; - } - } - - return 0; -} - -static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num) -{ - if (icom_adapter->version == ADAPTER_V1) { - icom_port->global_reg = icom_adapter->base_addr + 0x4000; - icom_port->int_reg = icom_adapter->base_addr + - 0x4004 + 2 - 2 * port_num; - } else { - icom_port->global_reg = icom_adapter->base_addr + 0x8000; - if (icom_port->port < 2) - icom_port->int_reg = icom_adapter->base_addr + - 0x8004 + 2 - 2 * icom_port->port; - else - icom_port->int_reg = icom_adapter->base_addr + - 0x8024 + 2 - 2 * (icom_port->port - 2); - } -} -static int __devinit icom_load_ports(struct icom_adapter *icom_adapter) -{ - struct icom_port *icom_port; - int port_num; - - for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) { - - icom_port = &icom_adapter->port_info[port_num]; - - if (icom_port->status == ICOM_PORT_ACTIVE) { - icom_port_active(icom_port, icom_adapter, port_num); - icom_port->dram = icom_adapter->base_addr + - 0x2000 * icom_port->port; - - icom_port->adapter = icom_adapter; - - /* get port memory */ - if (get_port_memory(icom_port) != 0) { - dev_err(&icom_port->adapter->pci_dev->dev, - "Memory allocation for port FAILED\n"); - } - } - } - return 0; -} - -static int __devinit icom_alloc_adapter(struct icom_adapter - **icom_adapter_ref) -{ - int adapter_count = 0; - struct icom_adapter *icom_adapter; - struct icom_adapter *cur_adapter_entry; - struct list_head *tmp; - - icom_adapter = (struct icom_adapter *) - kzalloc(sizeof(struct icom_adapter), GFP_KERNEL); - - if (!icom_adapter) { - return -ENOMEM; - } - - list_for_each(tmp, &icom_adapter_head) { - cur_adapter_entry = - list_entry(tmp, struct icom_adapter, - icom_adapter_entry); - if (cur_adapter_entry->index != adapter_count) { - break; - } - adapter_count++; - } - - icom_adapter->index = adapter_count; - list_add_tail(&icom_adapter->icom_adapter_entry, tmp); - - *icom_adapter_ref = icom_adapter; - return 0; -} - -static void icom_free_adapter(struct icom_adapter *icom_adapter) -{ - list_del(&icom_adapter->icom_adapter_entry); - kfree(icom_adapter); -} - -static void icom_remove_adapter(struct icom_adapter *icom_adapter) -{ - struct icom_port *icom_port; - int index; - - for (index = 0; index < icom_adapter->numb_ports; index++) { - icom_port = &icom_adapter->port_info[index]; - - if (icom_port->status == ICOM_PORT_ACTIVE) { - dev_info(&icom_adapter->pci_dev->dev, - "Device removed\n"); - - uart_remove_one_port(&icom_uart_driver, - &icom_port->uart_port); - - /* be sure that DTR and RTS are dropped */ - writeb(0x00, &icom_port->dram->osr); - - /* Wait 0.1 Sec for simple Init to complete */ - msleep(100); - - /* Stop proccessor */ - stop_processor(icom_port); - - free_port_memory(icom_port); - } - } - - free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); - iounmap(icom_adapter->base_addr); - pci_release_regions(icom_adapter->pci_dev); - icom_free_adapter(icom_adapter); -} - -static void icom_kref_release(struct kref *kref) -{ - struct icom_adapter *icom_adapter; - - icom_adapter = to_icom_adapter(kref); - icom_remove_adapter(icom_adapter); -} - -static int __devinit icom_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - int index; - unsigned int command_reg; - int retval; - struct icom_adapter *icom_adapter; - struct icom_port *icom_port; - - retval = pci_enable_device(dev); - if (retval) { - dev_err(&dev->dev, "Device enable FAILED\n"); - return retval; - } - - if ( (retval = pci_request_regions(dev, "icom"))) { - dev_err(&dev->dev, "pci_request_regions FAILED\n"); - pci_disable_device(dev); - return retval; - } - - pci_set_master(dev); - - if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { - dev_err(&dev->dev, "PCI Config read FAILED\n"); - return retval; - } - - pci_write_config_dword(dev, PCI_COMMAND, - command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER - | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - - if (ent->driver_data == ADAPTER_V1) { - pci_write_config_dword(dev, 0x44, 0x8300830A); - } else { - pci_write_config_dword(dev, 0x44, 0x42004200); - pci_write_config_dword(dev, 0x48, 0x42004200); - } - - - retval = icom_alloc_adapter(&icom_adapter); - if (retval) { - dev_err(&dev->dev, "icom_alloc_adapter FAILED\n"); - retval = -EIO; - goto probe_exit0; - } - - icom_adapter->base_addr_pci = pci_resource_start(dev, 0); - icom_adapter->pci_dev = dev; - icom_adapter->version = ent->driver_data; - icom_adapter->subsystem_id = ent->subdevice; - - - retval = icom_init_ports(icom_adapter); - if (retval) { - dev_err(&dev->dev, "Port configuration failed\n"); - goto probe_exit1; - } - - icom_adapter->base_addr = pci_ioremap_bar(dev, 0); - - if (!icom_adapter->base_addr) - goto probe_exit1; - - /* save off irq and request irq line */ - if ( (retval = request_irq(dev->irq, icom_interrupt, - IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME, - (void *) icom_adapter))) { - goto probe_exit2; - } - - retval = icom_load_ports(icom_adapter); - - for (index = 0; index < icom_adapter->numb_ports; index++) { - icom_port = &icom_adapter->port_info[index]; - - if (icom_port->status == ICOM_PORT_ACTIVE) { - icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq; - icom_port->uart_port.type = PORT_ICOM; - icom_port->uart_port.iotype = UPIO_MEM; - icom_port->uart_port.membase = - (char *) icom_adapter->base_addr_pci; - icom_port->uart_port.fifosize = 16; - icom_port->uart_port.ops = &icom_ops; - icom_port->uart_port.line = - icom_port->port + icom_adapter->index * 4; - if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) { - icom_port->status = ICOM_PORT_OFF; - dev_err(&dev->dev, "Device add failed\n"); - } else - dev_info(&dev->dev, "Device added\n"); - } - } - - kref_init(&icom_adapter->kref); - return 0; - -probe_exit2: - iounmap(icom_adapter->base_addr); -probe_exit1: - icom_free_adapter(icom_adapter); - -probe_exit0: - pci_release_regions(dev); - pci_disable_device(dev); - - return retval; -} - -static void __devexit icom_remove(struct pci_dev *dev) -{ - struct icom_adapter *icom_adapter; - struct list_head *tmp; - - list_for_each(tmp, &icom_adapter_head) { - icom_adapter = list_entry(tmp, struct icom_adapter, - icom_adapter_entry); - if (icom_adapter->pci_dev == dev) { - kref_put(&icom_adapter->kref, icom_kref_release); - return; - } - } - - dev_err(&dev->dev, "Unable to find device to remove\n"); -} - -static struct pci_driver icom_pci_driver = { - .name = ICOM_DRIVER_NAME, - .id_table = icom_pci_table, - .probe = icom_probe, - .remove = __devexit_p(icom_remove), -}; - -static int __init icom_init(void) -{ - int ret; - - spin_lock_init(&icom_lock); - - ret = uart_register_driver(&icom_uart_driver); - if (ret) - return ret; - - ret = pci_register_driver(&icom_pci_driver); - - if (ret < 0) - uart_unregister_driver(&icom_uart_driver); - - return ret; -} - -static void __exit icom_exit(void) -{ - pci_unregister_driver(&icom_pci_driver); - uart_unregister_driver(&icom_uart_driver); -} - -module_init(icom_init); -module_exit(icom_exit); - -MODULE_AUTHOR("Michael Anderson "); -MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); -MODULE_SUPPORTED_DEVICE - ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("icom_call_setup.bin"); -MODULE_FIRMWARE("icom_res_dce.bin"); -MODULE_FIRMWARE("icom_asc.bin"); diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h deleted file mode 100644 index c8029e0025c9..000000000000 --- a/drivers/serial/icom.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * icom.h - * - * Copyright (C) 2001 Michael Anderson, IBM Corporation - * - * Serial device driver include file. - * - * 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 - -#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1) -static int icom_acfg_baud[] = { - 300, - 600, - 900, - 1200, - 1800, - 2400, - 3600, - 4800, - 7200, - 9600, - 14400, - 19200, - 28800, - 38400, - 57600, - 76800, - 115200, - 153600, - 230400, - 307200, - 460800, -}; - -struct icom_regs { - u32 control; /* Adapter Control Register */ - u32 interrupt; /* Adapter Interrupt Register */ - u32 int_mask; /* Adapter Interrupt Mask Reg */ - u32 int_pri; /* Adapter Interrupt Priority r */ - u32 int_reg_b; /* Adapter non-masked Interrupt */ - u32 resvd01; - u32 resvd02; - u32 resvd03; - u32 control_2; /* Adapter Control Register 2 */ - u32 interrupt_2; /* Adapter Interrupt Register 2 */ - u32 int_mask_2; /* Adapter Interrupt Mask 2 */ - u32 int_pri_2; /* Adapter Interrupt Prior 2 */ - u32 int_reg_2b; /* Adapter non-masked 2 */ -}; - -struct func_dram { - u32 reserved[108]; /* 0-1B0 reserved by personality code */ - u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ - u8 RcvStnAddr; /* 1B4 Receive Station Addr */ - u8 IdleState; /* 1B5 Idle State */ - u8 IdleMonitor; /* 1B6 Idle Monitor */ - u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ - u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ - u8 StartXmitCmd; /* 1BC Start Xmit Command */ - u8 HDLCConfigReg; /* 1BD Reserved */ - u8 CauseCode; /* 1BE Cause code for fatal error */ - u8 xchar; /* 1BF High priority send */ - u32 reserved3; /* 1C0-1C3 Reserved */ - u8 PrevCmdReg; /* 1C4 Reserved */ - u8 CmdReg; /* 1C5 Command Register */ - u8 async_config2; /* 1C6 Async Config Byte 2 */ - u8 async_config3; /* 1C7 Async Config Byte 3 */ - u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ - u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ - u8 misc_flags; /* 1DD misc flags */ -#define V2_HARDWARE 0x40 -#define ICOM_HDW_ACTIVE 0x01 - u8 call_length; /* 1DE Phone #/CFI buff ln */ - u8 call_length2; /* 1DF Upper byte (unused) */ - u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ - u16 timer_value; /* 1E4-1E5 general timer value */ - u8 timer_command; /* 1E6 general timer cmd */ - u8 dce_command; /* 1E7 dce command reg */ - u8 dce_cmd_status; /* 1E8 dce command stat */ - u8 x21_r1_ioff; /* 1E9 dce ready counter */ - u8 x21_r0_ioff; /* 1EA dce not ready ctr */ - u8 x21_ralt_ioff; /* 1EB dce CNR counter */ - u8 x21_r1_ion; /* 1EC dce ready I on ctr */ - u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ - u8 ier; /* 1EE Interrupt Enable */ - u8 isr; /* 1EF Input Signal Reg */ - u8 osr; /* 1F0 Output Signal Reg */ - u8 reset; /* 1F1 Reset/Reload Reg */ - u8 disable; /* 1F2 Disable Reg */ - u8 sync; /* 1F3 Sync Reg */ - u8 error_stat; /* 1F4 Error Status */ - u8 cable_id; /* 1F5 Cable ID */ - u8 cs_length; /* 1F6 CS Load Length */ - u8 mac_length; /* 1F7 Mac Load Length */ - u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ - u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ -}; - -/* - * adapter defines and structures - */ -#define ICOM_CONTROL_START_A 0x00000008 -#define ICOM_CONTROL_STOP_A 0x00000004 -#define ICOM_CONTROL_START_B 0x00000002 -#define ICOM_CONTROL_STOP_B 0x00000001 -#define ICOM_CONTROL_START_C 0x00000008 -#define ICOM_CONTROL_STOP_C 0x00000004 -#define ICOM_CONTROL_START_D 0x00000002 -#define ICOM_CONTROL_STOP_D 0x00000001 -#define ICOM_IRAM_OFFSET 0x1000 -#define ICOM_IRAM_SIZE 0x0C00 -#define ICOM_DCE_IRAM_OFFSET 0x0A00 -#define ICOM_CABLE_ID_VALID 0x01 -#define ICOM_CABLE_ID_MASK 0xF0 -#define ICOM_DISABLE 0x80 -#define CMD_XMIT_RCV_ENABLE 0xC0 -#define CMD_XMIT_ENABLE 0x40 -#define CMD_RCV_DISABLE 0x00 -#define CMD_RCV_ENABLE 0x80 -#define CMD_RESTART 0x01 -#define CMD_HOLD_XMIT 0x02 -#define CMD_SND_BREAK 0x04 -#define RS232_CABLE 0x06 -#define V24_CABLE 0x0E -#define V35_CABLE 0x0C -#define V36_CABLE 0x02 -#define NO_CABLE 0x00 -#define START_DOWNLOAD 0x80 -#define ICOM_INT_MASK_PRC_A 0x00003FFF -#define ICOM_INT_MASK_PRC_B 0x3FFF0000 -#define ICOM_INT_MASK_PRC_C 0x00003FFF -#define ICOM_INT_MASK_PRC_D 0x3FFF0000 -#define INT_RCV_COMPLETED 0x1000 -#define INT_XMIT_COMPLETED 0x2000 -#define INT_IDLE_DETECT 0x0800 -#define INT_RCV_DISABLED 0x0400 -#define INT_XMIT_DISABLED 0x0200 -#define INT_RCV_XMIT_SHUTDOWN 0x0100 -#define INT_FATAL_ERROR 0x0080 -#define INT_CABLE_PULL 0x0020 -#define INT_SIGNAL_CHANGE 0x0010 -#define HDLC_PPP_PURE_ASYNC 0x02 -#define HDLC_FF_FILL 0x00 -#define HDLC_HDW_FLOW 0x01 -#define START_XMIT 0x80 -#define ICOM_ACFG_DRIVE1 0x20 -#define ICOM_ACFG_NO_PARITY 0x00 -#define ICOM_ACFG_PARITY_ENAB 0x02 -#define ICOM_ACFG_PARITY_ODD 0x01 -#define ICOM_ACFG_8BPC 0x00 -#define ICOM_ACFG_7BPC 0x04 -#define ICOM_ACFG_6BPC 0x08 -#define ICOM_ACFG_5BPC 0x0C -#define ICOM_ACFG_1STOP_BIT 0x00 -#define ICOM_ACFG_2STOP_BIT 0x10 -#define ICOM_DTR 0x80 -#define ICOM_RTS 0x40 -#define ICOM_RI 0x08 -#define ICOM_DSR 0x80 -#define ICOM_DCD 0x20 -#define ICOM_CTS 0x40 - -#define NUM_XBUFFS 1 -#define NUM_RBUFFS 2 -#define RCV_BUFF_SZ 0x0200 -#define XMIT_BUFF_SZ 0x1000 -struct statusArea { - /**********************************************/ - /* Transmit Status Area */ - /**********************************************/ - struct xmit_status_area{ - u32 leNext; /* Next entry in Little Endian on Adapter */ - u32 leNextASD; - u32 leBuffer; /* Buffer for entry in LE for Adapter */ - u16 leLengthASD; - u16 leOffsetASD; - u16 leLength; /* Length of data in segment */ - u16 flags; -#define SA_FLAGS_DONE 0x0080 /* Done with Segment */ -#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ -#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ -#define SA_FLAGS_READY_TO_XMIT 0x0800 -#define SA_FLAGS_STAT_MASK 0x007F - } xmit[NUM_XBUFFS]; - - /**********************************************/ - /* Receive Status Area */ - /**********************************************/ - struct { - u32 leNext; /* Next entry in Little Endian on Adapter */ - u32 leNextASD; - u32 leBuffer; /* Buffer for entry in LE for Adapter */ - u16 WorkingLength; /* size of segment */ - u16 reserv01; - u16 leLength; /* Length of data in segment */ - u16 flags; -#define SA_FL_RCV_DONE 0x0010 /* Data ready */ -#define SA_FLAGS_OVERRUN 0x0040 -#define SA_FLAGS_PARITY_ERROR 0x0080 -#define SA_FLAGS_FRAME_ERROR 0x0001 -#define SA_FLAGS_FRAME_TRUNC 0x0002 -#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ -#define SA_FLAGS_RCV_MASK 0xFFE6 - } rcv[NUM_RBUFFS]; -}; - -struct icom_adapter; - - -#define ICOM_MAJOR 243 -#define ICOM_MINOR_START 0 - -struct icom_port { - struct uart_port uart_port; - u8 imbed_modem; -#define ICOM_UNKNOWN 1 -#define ICOM_RVX 2 -#define ICOM_IMBED_MODEM 3 - unsigned char cable_id; - unsigned char read_status_mask; - unsigned char ignore_status_mask; - void __iomem * int_reg; - struct icom_regs __iomem *global_reg; - struct func_dram __iomem *dram; - int port; - struct statusArea *statStg; - dma_addr_t statStg_pci; - u32 *xmitRestart; - dma_addr_t xmitRestart_pci; - unsigned char *xmit_buf; - dma_addr_t xmit_buf_pci; - unsigned char *recv_buf; - dma_addr_t recv_buf_pci; - int next_rcv; - int put_length; - int status; -#define ICOM_PORT_ACTIVE 1 /* Port exists. */ -#define ICOM_PORT_OFF 0 /* Port does not exist. */ - int load_in_progress; - struct icom_adapter *adapter; -}; - -struct icom_adapter { - void __iomem * base_addr; - unsigned long base_addr_pci; - struct pci_dev *pci_dev; - struct icom_port port_info[4]; - int index; - int version; -#define ADAPTER_V1 0x0001 -#define ADAPTER_V2 0x0002 - u32 subsystem_id; -#define FOUR_PORT_MODEL 0x0252 -#define V2_TWO_PORTS_RVX 0x021A -#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 - int numb_ports; - struct list_head icom_adapter_entry; - struct kref kref; -}; - -/* prototype */ -extern void iCom_sercons_init(void); - -struct lookup_proc_table { - u32 __iomem *global_control_reg; - unsigned long processor_id; -}; - -struct lookup_int_table { - u32 __iomem *global_int_mask; - unsigned long processor_id; -}; diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c deleted file mode 100644 index ab93763862d5..000000000000 --- a/drivers/serial/ifx6x60.c +++ /dev/null @@ -1,1406 +0,0 @@ -/**************************************************************************** - * - * Driver for the IFX 6x60 spi modem. - * - * Copyright (C) 2008 Option International - * Copyright (C) 2008 Filip Aben - * Denis Joseph Barrow - * Jan Dumon - * - * Copyright (C) 2009, 2010 Intel Corp - * Russ Gorby - * - * 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. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA - * - * Driver modified by Intel from Option gtm501l_spi.c - * - * Notes - * o The driver currently assumes a single device only. If you need to - * change this then look for saved_ifx_dev and add a device lookup - * o The driver is intended to be big-endian safe but has never been - * tested that way (no suitable hardware). There are a couple of FIXME - * notes by areas that may need addressing - * o Some of the GPIO naming/setup assumptions may need revisiting if - * you need to use this driver for another platform. - * - *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ifx6x60.h" - -#define IFX_SPI_MORE_MASK 0x10 -#define IFX_SPI_MORE_BIT 12 /* bit position in u16 */ -#define IFX_SPI_CTS_BIT 13 /* bit position in u16 */ -#define IFX_SPI_TTY_ID 0 -#define IFX_SPI_TIMEOUT_SEC 2 -#define IFX_SPI_HEADER_0 (-1) -#define IFX_SPI_HEADER_F (-2) - -/* forward reference */ -static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); - -/* local variables */ -static int spi_b16 = 1; /* 8 or 16 bit word length */ -static struct tty_driver *tty_drv; -static struct ifx_spi_device *saved_ifx_dev; -static struct lock_class_key ifx_spi_key; - -/* GPIO/GPE settings */ - -/** - * mrdy_set_high - set MRDY GPIO - * @ifx: device we are controlling - * - */ -static inline void mrdy_set_high(struct ifx_spi_device *ifx) -{ - gpio_set_value(ifx->gpio.mrdy, 1); -} - -/** - * mrdy_set_low - clear MRDY GPIO - * @ifx: device we are controlling - * - */ -static inline void mrdy_set_low(struct ifx_spi_device *ifx) -{ - gpio_set_value(ifx->gpio.mrdy, 0); -} - -/** - * ifx_spi_power_state_set - * @ifx_dev: our SPI device - * @val: bits to set - * - * Set bit in power status and signal power system if status becomes non-0 - */ -static void -ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&ifx_dev->power_lock, flags); - - /* - * if power status is already non-0, just update, else - * tell power system - */ - if (!ifx_dev->power_status) - pm_runtime_get(&ifx_dev->spi_dev->dev); - ifx_dev->power_status |= val; - - spin_unlock_irqrestore(&ifx_dev->power_lock, flags); -} - -/** - * ifx_spi_power_state_clear - clear power bit - * @ifx_dev: our SPI device - * @val: bits to clear - * - * clear bit in power status and signal power system if status becomes 0 - */ -static void -ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&ifx_dev->power_lock, flags); - - if (ifx_dev->power_status) { - ifx_dev->power_status &= ~val; - if (!ifx_dev->power_status) - pm_runtime_put(&ifx_dev->spi_dev->dev); - } - - spin_unlock_irqrestore(&ifx_dev->power_lock, flags); -} - -/** - * swap_buf - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf(u16 *buf, int len, void *end) -{ - int n; - - len = ((len + 1) >> 1); - if ((void *)&buf[len] > end) { - pr_err("swap_buf: swap exceeds boundary (%p > %p)!", - &buf[len], end); - return; - } - for (n = 0; n < len; n++) { - *buf = cpu_to_be16(*buf); - buf++; - } -} - -/** - * mrdy_assert - assert MRDY line - * @ifx_dev: our SPI device - * - * Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low - * now. - * - * FIXME: Can SRDY even go high as we are running this code ? - */ -static void mrdy_assert(struct ifx_spi_device *ifx_dev) -{ - int val = gpio_get_value(ifx_dev->gpio.srdy); - if (!val) { - if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING, - &ifx_dev->flags)) { - ifx_dev->spi_timer.expires = - jiffies + IFX_SPI_TIMEOUT_SEC*HZ; - add_timer(&ifx_dev->spi_timer); - - } - } - ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING); - mrdy_set_high(ifx_dev); -} - -/** - * ifx_spi_hangup - hang up an IFX device - * @ifx_dev: our SPI device - * - * Hang up the tty attached to the IFX device if one is currently - * open. If not take no action - */ -static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev) -{ - struct tty_port *pport = &ifx_dev->tty_port; - struct tty_struct *tty = tty_port_tty_get(pport); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } -} - -/** - * ifx_spi_timeout - SPI timeout - * @arg: our SPI device - * - * The SPI has timed out: hang up the tty. Users will then see a hangup - * and error events. - */ -static void ifx_spi_timeout(unsigned long arg) -{ - struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg; - - dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***"); - ifx_spi_ttyhangup(ifx_dev); - mrdy_set_low(ifx_dev); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); -} - -/* char/tty operations */ - -/** - * ifx_spi_tiocmget - get modem lines - * @tty: our tty device - * @filp: file handle issuing the request - * - * Map the signal state into Linux modem flags and report the value - * in Linux terms - */ -static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp) -{ - unsigned int value; - struct ifx_spi_device *ifx_dev = tty->driver_data; - - value = - (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) | - (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) | - (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) | - (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) | - (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) | - (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0); - return value; -} - -/** - * ifx_spi_tiocmset - set modem bits - * @tty: the tty structure - * @filp: file handle issuing the request - * @set: bits to set - * @clear: bits to clear - * - * The IFX6x60 only supports DTR and RTS. Set them accordingly - * and flag that an update to the modem is needed. - * - * FIXME: do we need to kick the tranfers when we do this ? - */ -static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp, - unsigned int set, unsigned int clear) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - - if (set & TIOCM_RTS) - set_bit(IFX_SPI_RTS, &ifx_dev->signal_state); - if (set & TIOCM_DTR) - set_bit(IFX_SPI_DTR, &ifx_dev->signal_state); - if (clear & TIOCM_RTS) - clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state); - if (clear & TIOCM_DTR) - clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state); - - set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state); - return 0; -} - -/** - * ifx_spi_open - called on tty open - * @tty: our tty device - * @filp: file handle being associated with the tty - * - * Open the tty interface. We let the tty_port layer do all the work - * for us. - * - * FIXME: Remove single device assumption and saved_ifx_dev - */ -static int ifx_spi_open(struct tty_struct *tty, struct file *filp) -{ - return tty_port_open(&saved_ifx_dev->tty_port, tty, filp); -} - -/** - * ifx_spi_close - called when our tty closes - * @tty: the tty being closed - * @filp: the file handle being closed - * - * Perform the close of the tty. We use the tty_port layer to do all - * our hard work. - */ -static void ifx_spi_close(struct tty_struct *tty, struct file *filp) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - tty_port_close(&ifx_dev->tty_port, tty, filp); - /* FIXME: should we do an ifx_spi_reset here ? */ -} - -/** - * ifx_decode_spi_header - decode received header - * @buffer: the received data - * @length: decoded length - * @more: decoded more flag - * @received_cts: status of cts we received - * - * Note how received_cts is handled -- if header is all F it is left - * the same as it was, if header is all 0 it is set to 0 otherwise it is - * taken from the incoming header. - * - * FIXME: endianness - */ -static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length, - unsigned char *more, unsigned char *received_cts) -{ - u16 h1; - u16 h2; - u16 *in_buffer = (u16 *)buffer; - - h1 = *in_buffer; - h2 = *(in_buffer+1); - - if (h1 == 0 && h2 == 0) { - *received_cts = 0; - return IFX_SPI_HEADER_0; - } else if (h1 == 0xffff && h2 == 0xffff) { - /* spi_slave_cts remains as it was */ - return IFX_SPI_HEADER_F; - } - - *length = h1 & 0xfff; /* upper bits of byte are flags */ - *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1; - *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1; - return 0; -} - -/** - * ifx_setup_spi_header - set header fields - * @txbuffer: pointer to start of SPI buffer - * @tx_count: bytes - * @more: indicate if more to follow - * - * Format up an SPI header for a transfer - * - * FIXME: endianness? - */ -static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count, - unsigned char more) -{ - *(u16 *)(txbuffer) = tx_count; - *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE; - txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK; -} - -/** - * ifx_spi_wakeup_serial - SPI space made - * @port_data: our SPI device - * - * We have emptied the FIFO enough that we want to get more data - * queued into it. Poke the line discipline via tty_wakeup so that - * it will feed us more bits - */ -static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev) -{ - struct tty_struct *tty; - - tty = tty_port_tty_get(&ifx_dev->tty_port); - if (!tty) - return; - tty_wakeup(tty); - tty_kref_put(tty); -} - -/** - * ifx_spi_prepare_tx_buffer - prepare transmit frame - * @ifx_dev: our SPI device - * - * The transmit buffr needs a header and various other bits of - * information followed by as much data as we can pull from the FIFO - * and transfer. This function formats up a suitable buffer in the - * ifx_dev->tx_buffer - * - * FIXME: performance - should we wake the tty when the queue is half - * empty ? - */ -static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev) -{ - int temp_count; - int queue_length; - int tx_count; - unsigned char *tx_buffer; - - tx_buffer = ifx_dev->tx_buffer; - memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE); - - /* make room for required SPI header */ - tx_buffer += IFX_SPI_HEADER_OVERHEAD; - tx_count = IFX_SPI_HEADER_OVERHEAD; - - /* clear to signal no more data if this turns out to be the - * last buffer sent in a sequence */ - ifx_dev->spi_more = 0; - - /* if modem cts is set, just send empty buffer */ - if (!ifx_dev->spi_slave_cts) { - /* see if there's tx data */ - queue_length = kfifo_len(&ifx_dev->tx_fifo); - if (queue_length != 0) { - /* data to mux -- see if there's room for it */ - temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE); - temp_count = kfifo_out_locked(&ifx_dev->tx_fifo, - tx_buffer, temp_count, - &ifx_dev->fifo_lock); - - /* update buffer pointer and data count in message */ - tx_buffer += temp_count; - tx_count += temp_count; - if (temp_count == queue_length) - /* poke port to get more data */ - ifx_spi_wakeup_serial(ifx_dev); - else /* more data in port, use next SPI message */ - ifx_dev->spi_more = 1; - } - } - /* have data and info for header -- set up SPI header in buffer */ - /* spi header needs payload size, not entire buffer size */ - ifx_spi_setup_spi_header(ifx_dev->tx_buffer, - tx_count-IFX_SPI_HEADER_OVERHEAD, - ifx_dev->spi_more); - /* swap actual data in the buffer */ - swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count, - &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]); - return tx_count; -} - -/** - * ifx_spi_write - line discipline write - * @tty: our tty device - * @buf: pointer to buffer to write (kernel space) - * @count: size of buffer - * - * Write the characters we have been given into the FIFO. If the device - * is not active then activate it, when the SRDY line is asserted back - * this will commence I/O - */ -static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - unsigned char *tmp_buf = (unsigned char *)buf; - int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count, - &ifx_dev->fifo_lock); - mrdy_assert(ifx_dev); - return tx_count; -} - -/** - * ifx_spi_chars_in_buffer - line discipline helper - * @tty: our tty device - * - * Report how much data we can accept before we drop bytes. As we use - * a simple FIFO this is nice and easy. - */ -static int ifx_spi_write_room(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo); -} - -/** - * ifx_spi_chars_in_buffer - line discipline helper - * @tty: our tty device - * - * Report how many characters we have buffered. In our case this is the - * number of bytes sitting in our transmit FIFO. - */ -static int ifx_spi_chars_in_buffer(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - return kfifo_len(&ifx_dev->tx_fifo); -} - -/** - * ifx_port_hangup - * @port: our tty port - * - * tty port hang up. Called when tty_hangup processing is invoked either - * by loss of carrier, or by software (eg vhangup). Serialized against - * activate/shutdown by the tty layer. - */ -static void ifx_spi_hangup(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - tty_port_hangup(&ifx_dev->tty_port); -} - -/** - * ifx_port_activate - * @port: our tty port - * - * tty port activate method - called for first open. Serialized - * with hangup and shutdown by the tty layer. - */ -static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = - container_of(port, struct ifx_spi_device, tty_port); - - /* clear any old data; can't do this in 'close' */ - kfifo_reset(&ifx_dev->tx_fifo); - - /* put port data into this tty */ - tty->driver_data = ifx_dev; - - /* allows flip string push from int context */ - tty->low_latency = 1; - - return 0; -} - -/** - * ifx_port_shutdown - * @port: our tty port - * - * tty port shutdown method - called for last port close. Serialized - * with hangup and activate by the tty layer. - */ -static void ifx_port_shutdown(struct tty_port *port) -{ - struct ifx_spi_device *ifx_dev = - container_of(port, struct ifx_spi_device, tty_port); - - mrdy_set_low(ifx_dev); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); - tasklet_kill(&ifx_dev->io_work_tasklet); -} - -static const struct tty_port_operations ifx_tty_port_ops = { - .activate = ifx_port_activate, - .shutdown = ifx_port_shutdown, -}; - -static const struct tty_operations ifx_spi_serial_ops = { - .open = ifx_spi_open, - .close = ifx_spi_close, - .write = ifx_spi_write, - .hangup = ifx_spi_hangup, - .write_room = ifx_spi_write_room, - .chars_in_buffer = ifx_spi_chars_in_buffer, - .tiocmget = ifx_spi_tiocmget, - .tiocmset = ifx_spi_tiocmset, -}; - -/** - * ifx_spi_insert_fip_string - queue received data - * @ifx_ser: our SPI device - * @chars: buffer we have received - * @size: number of chars reeived - * - * Queue bytes to the tty assuming the tty side is currently open. If - * not the discard the data. - */ -static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev, - unsigned char *chars, size_t size) -{ - struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port); - if (!tty) - return; - tty_insert_flip_string(tty, chars, size); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -/** - * ifx_spi_complete - SPI transfer completed - * @ctx: our SPI device - * - * An SPI transfer has completed. Process any received data and kick off - * any further transmits we can commence. - */ -static void ifx_spi_complete(void *ctx) -{ - struct ifx_spi_device *ifx_dev = ctx; - struct tty_struct *tty; - struct tty_ldisc *ldisc = NULL; - int length; - int actual_length; - unsigned char more; - unsigned char cts; - int local_write_pending = 0; - int queue_length; - int srdy; - int decode_result; - - mrdy_set_low(ifx_dev); - - if (!ifx_dev->spi_msg.status) { - /* check header validity, get comm flags */ - swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD, - &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]); - decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer, - &length, &more, &cts); - if (decode_result == IFX_SPI_HEADER_0) { - dev_dbg(&ifx_dev->spi_dev->dev, - "ignore input: invalid header 0"); - ifx_dev->spi_slave_cts = 0; - goto complete_exit; - } else if (decode_result == IFX_SPI_HEADER_F) { - dev_dbg(&ifx_dev->spi_dev->dev, - "ignore input: invalid header F"); - goto complete_exit; - } - - ifx_dev->spi_slave_cts = cts; - - actual_length = min((unsigned int)length, - ifx_dev->spi_msg.actual_length); - swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD), - actual_length, - &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]); - ifx_spi_insert_flip_string( - ifx_dev, - ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD, - (size_t)actual_length); - } else { - dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d", - ifx_dev->spi_msg.status); - } - -complete_exit: - if (ifx_dev->write_pending) { - ifx_dev->write_pending = 0; - local_write_pending = 1; - } - - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags)); - - queue_length = kfifo_len(&ifx_dev->tx_fifo); - srdy = gpio_get_value(ifx_dev->gpio.srdy); - if (!srdy) - ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY); - - /* schedule output if there is more to do */ - if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags)) - tasklet_schedule(&ifx_dev->io_work_tasklet); - else { - if (more || ifx_dev->spi_more || queue_length > 0 || - local_write_pending) { - if (ifx_dev->spi_slave_cts) { - if (more) - mrdy_assert(ifx_dev); - } else - mrdy_assert(ifx_dev); - } else { - /* - * poke line discipline driver if any for more data - * may or may not get more data to write - * for now, say not busy - */ - ifx_spi_power_state_clear(ifx_dev, - IFX_SPI_POWER_DATA_PENDING); - tty = tty_port_tty_get(&ifx_dev->tty_port); - if (tty) { - ldisc = tty_ldisc_ref(tty); - if (ldisc) { - ldisc->ops->write_wakeup(tty); - tty_ldisc_deref(ldisc); - } - tty_kref_put(tty); - } - } - } -} - -/** - * ifx_spio_io - I/O tasklet - * @data: our SPI device - * - * Queue data for transmission if possible and then kick off the - * transfer. - */ -static void ifx_spi_io(unsigned long data) -{ - int retval; - struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data; - - if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) { - if (ifx_dev->gpio.unack_srdy_int_nb > 0) - ifx_dev->gpio.unack_srdy_int_nb--; - - ifx_spi_prepare_tx_buffer(ifx_dev); - - spi_message_init(&ifx_dev->spi_msg); - INIT_LIST_HEAD(&ifx_dev->spi_msg.queue); - - ifx_dev->spi_msg.context = ifx_dev; - ifx_dev->spi_msg.complete = ifx_spi_complete; - - /* set up our spi transfer */ - /* note len is BYTES, not transfers */ - ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE; - ifx_dev->spi_xfer.cs_change = 0; - ifx_dev->spi_xfer.speed_hz = 12500000; - /* ifx_dev->spi_xfer.speed_hz = 390625; */ - ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8; - - ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; - ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; - - /* - * setup dma pointers - */ - if (ifx_dev->is_6160) { - ifx_dev->spi_msg.is_dma_mapped = 1; - ifx_dev->tx_dma = ifx_dev->tx_bus; - ifx_dev->rx_dma = ifx_dev->rx_bus; - ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma; - ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma; - } else { - ifx_dev->spi_msg.is_dma_mapped = 0; - ifx_dev->tx_dma = (dma_addr_t)0; - ifx_dev->rx_dma = (dma_addr_t)0; - ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0; - ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0; - } - - spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg); - - /* Assert MRDY. This may have already been done by the write - * routine. - */ - mrdy_assert(ifx_dev); - - retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg); - if (retval) { - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, - &ifx_dev->flags); - tasklet_schedule(&ifx_dev->io_work_tasklet); - return; - } - } else - ifx_dev->write_pending = 1; -} - -/** - * ifx_spi_free_port - free up the tty side - * @ifx_dev: IFX device going away - * - * Unregister and free up a port when the device goes away - */ -static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev) -{ - if (ifx_dev->tty_dev) - tty_unregister_device(tty_drv, ifx_dev->minor); - kfifo_free(&ifx_dev->tx_fifo); -} - -/** - * ifx_spi_create_port - create a new port - * @ifx_dev: our spi device - * - * Allocate and initialise the tty port that goes with this interface - * and add it to the tty layer so that it can be opened. - */ -static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) -{ - int ret = 0; - struct tty_port *pport = &ifx_dev->tty_port; - - spin_lock_init(&ifx_dev->fifo_lock); - lockdep_set_class_and_subclass(&ifx_dev->fifo_lock, - &ifx_spi_key, 0); - - if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) { - ret = -ENOMEM; - goto error_ret; - } - - pport->ops = &ifx_tty_port_ops; - tty_port_init(pport); - ifx_dev->minor = IFX_SPI_TTY_ID; - ifx_dev->tty_dev = tty_register_device(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__); - ret = PTR_ERR(ifx_dev->tty_dev); - goto error_ret; - } - return 0; - -error_ret: - ifx_spi_free_port(ifx_dev); - return ret; -} - -/** - * ifx_spi_handle_srdy - handle SRDY - * @ifx_dev: device asserting SRDY - * - * Check our device state and see what we need to kick off when SRDY - * is asserted. This usually means killing the timer and firing off the - * I/O processing. - */ -static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev) -{ - if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { - del_timer_sync(&ifx_dev->spi_timer); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); - } - - ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY); - - if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) - tasklet_schedule(&ifx_dev->io_work_tasklet); - else - set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); -} - -/** - * ifx_spi_srdy_interrupt - SRDY asserted - * @irq: our IRQ number - * @dev: our ifx device - * - * The modem asserted SRDY. Handle the srdy event - */ -static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev) -{ - struct ifx_spi_device *ifx_dev = dev; - ifx_dev->gpio.unack_srdy_int_nb++; - ifx_spi_handle_srdy(ifx_dev); - return IRQ_HANDLED; -} - -/** - * ifx_spi_reset_interrupt - Modem has changed reset state - * @irq: interrupt number - * @dev: our device pointer - * - * The modem has either entered or left reset state. Check the GPIO - * line to see which. - * - * FIXME: review locking on MR_INPROGRESS versus - * parallel unsolicited reset/solicited reset - */ -static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev) -{ - struct ifx_spi_device *ifx_dev = dev; - int val = gpio_get_value(ifx_dev->gpio.reset_out); - int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state); - - if (val == 0) { - /* entered reset */ - set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); - if (!solreset) { - /* unsolicited reset */ - ifx_spi_ttyhangup(ifx_dev); - } - } else { - /* exited reset */ - clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); - if (solreset) { - set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state); - wake_up(&ifx_dev->mdm_reset_wait); - } - } - return IRQ_HANDLED; -} - -/** - * ifx_spi_free_device - free device - * @ifx_dev: device to free - * - * Free the IFX device - */ -static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev) -{ - ifx_spi_free_port(ifx_dev); - dma_free_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - ifx_dev->tx_buffer, - ifx_dev->tx_bus); - dma_free_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - ifx_dev->rx_buffer, - ifx_dev->rx_bus); -} - -/** - * ifx_spi_reset - reset modem - * @ifx_dev: modem to reset - * - * Perform a reset on the modem - */ -static int ifx_spi_reset(struct ifx_spi_device *ifx_dev) -{ - int ret; - /* - * set up modem power, reset - * - * delays are required on some platforms for the modem - * to reset properly - */ - set_bit(MR_START, &ifx_dev->mdm_reset_state); - gpio_set_value(ifx_dev->gpio.po, 0); - gpio_set_value(ifx_dev->gpio.reset, 0); - msleep(25); - gpio_set_value(ifx_dev->gpio.reset, 1); - msleep(1); - gpio_set_value(ifx_dev->gpio.po, 1); - msleep(1); - gpio_set_value(ifx_dev->gpio.po, 0); - ret = wait_event_timeout(ifx_dev->mdm_reset_wait, - test_bit(MR_COMPLETE, - &ifx_dev->mdm_reset_state), - IFX_RESET_TIMEOUT); - if (!ret) - dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)", - ifx_dev->mdm_reset_state); - - ifx_dev->mdm_reset_state = 0; - return ret; -} - -/** - * ifx_spi_spi_probe - probe callback - * @spi: our possible matching SPI device - * - * Probe for a 6x60 modem on SPI bus. Perform any needed device and - * GPIO setup. - * - * FIXME: - * - Support for multiple devices - * - Split out MID specific GPIO handling eventually - */ - -static int ifx_spi_spi_probe(struct spi_device *spi) -{ - int ret; - int srdy; - struct ifx_modem_platform_data *pl_data = NULL; - struct ifx_spi_device *ifx_dev; - - if (saved_ifx_dev) { - dev_dbg(&spi->dev, "ignoring subsequent detection"); - return -ENODEV; - } - - /* initialize structure to hold our device variables */ - ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); - if (!ifx_dev) { - dev_err(&spi->dev, "spi device allocation failed"); - return -ENOMEM; - } - saved_ifx_dev = ifx_dev; - ifx_dev->spi_dev = spi; - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); - spin_lock_init(&ifx_dev->write_lock); - spin_lock_init(&ifx_dev->power_lock); - ifx_dev->power_status = 0; - init_timer(&ifx_dev->spi_timer); - ifx_dev->spi_timer.function = ifx_spi_timeout; - ifx_dev->spi_timer.data = (unsigned long)ifx_dev; - ifx_dev->is_6160 = pl_data->is_6160; - - /* ensure SPI protocol flags are initialized to enable transfer */ - ifx_dev->spi_more = 0; - ifx_dev->spi_slave_cts = 0; - - /*initialize transfer and dma buffers */ - ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - &ifx_dev->tx_bus, - GFP_KERNEL); - if (!ifx_dev->tx_buffer) { - dev_err(&spi->dev, "DMA-TX buffer allocation failed"); - ret = -ENOMEM; - goto error_ret; - } - ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - &ifx_dev->rx_bus, - GFP_KERNEL); - if (!ifx_dev->rx_buffer) { - dev_err(&spi->dev, "DMA-RX buffer allocation failed"); - ret = -ENOMEM; - goto error_ret; - } - - /* initialize waitq for modem reset */ - init_waitqueue_head(&ifx_dev->mdm_reset_wait); - - spi_set_drvdata(spi, ifx_dev); - tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io, - (unsigned long)ifx_dev); - - set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags); - - /* create our tty port */ - ret = ifx_spi_create_port(ifx_dev); - if (ret != 0) { - dev_err(&spi->dev, "create default tty port failed"); - goto error_ret; - } - - pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data; - if (pl_data) { - ifx_dev->gpio.reset = pl_data->rst_pmu; - ifx_dev->gpio.po = pl_data->pwr_on; - ifx_dev->gpio.mrdy = pl_data->mrdy; - ifx_dev->gpio.srdy = pl_data->srdy; - ifx_dev->gpio.reset_out = pl_data->rst_out; - } else { - dev_err(&spi->dev, "missing platform data!"); - ret = -ENODEV; - goto error_ret; - } - - dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d", - ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy, - ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out); - - /* Configure gpios */ - ret = gpio_request(ifx_dev->gpio.reset, "ifxModem"); - if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)", - ifx_dev->gpio.reset); - goto error_ret; - } - ret += gpio_direction_output(ifx_dev->gpio.reset, 0); - ret += gpio_export(ifx_dev->gpio.reset, 1); - if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)", - ifx_dev->gpio.reset); - ret = -EBUSY; - goto error_ret2; - } - - ret = gpio_request(ifx_dev->gpio.po, "ifxModem"); - ret += gpio_direction_output(ifx_dev->gpio.po, 0); - ret += gpio_export(ifx_dev->gpio.po, 1); - if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (ON)", - ifx_dev->gpio.po); - ret = -EBUSY; - goto error_ret3; - } - - ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem"); - if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)", - ifx_dev->gpio.mrdy); - goto error_ret3; - } - ret += gpio_export(ifx_dev->gpio.mrdy, 1); - ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0); - if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)", - ifx_dev->gpio.mrdy); - ret = -EBUSY; - goto error_ret4; - } - - ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem"); - if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)", - ifx_dev->gpio.srdy); - ret = -EBUSY; - goto error_ret4; - } - ret += gpio_export(ifx_dev->gpio.srdy, 1); - ret += gpio_direction_input(ifx_dev->gpio.srdy); - if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)", - ifx_dev->gpio.srdy); - ret = -EBUSY; - goto error_ret5; - } - - ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem"); - if (ret < 0) { - dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)", - ifx_dev->gpio.reset_out); - goto error_ret5; - } - ret += gpio_export(ifx_dev->gpio.reset_out, 1); - ret += gpio_direction_input(ifx_dev->gpio.reset_out); - if (ret) { - dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)", - ifx_dev->gpio.reset_out); - ret = -EBUSY; - goto error_ret6; - } - - ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out), - ifx_spi_reset_interrupt, - IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, - (void *)ifx_dev); - if (ret) { - dev_err(&spi->dev, "Unable to get irq %x\n", - gpio_to_irq(ifx_dev->gpio.reset_out)); - goto error_ret6; - } - - ret = ifx_spi_reset(ifx_dev); - - ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy), - ifx_spi_srdy_interrupt, - IRQF_TRIGGER_RISING, DRVNAME, - (void *)ifx_dev); - if (ret) { - dev_err(&spi->dev, "Unable to get irq %x", - gpio_to_irq(ifx_dev->gpio.srdy)); - goto error_ret7; - } - - /* set pm runtime power state and register with power system */ - pm_runtime_set_active(&spi->dev); - pm_runtime_enable(&spi->dev); - - /* handle case that modem is already signaling SRDY */ - /* no outgoing tty open at this point, this just satisfies the - * modem's read and should reset communication properly - */ - srdy = gpio_get_value(ifx_dev->gpio.srdy); - - if (srdy) { - mrdy_assert(ifx_dev); - ifx_spi_handle_srdy(ifx_dev); - } else - mrdy_set_low(ifx_dev); - return 0; - -error_ret7: - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); -error_ret6: - gpio_free(ifx_dev->gpio.srdy); -error_ret5: - gpio_free(ifx_dev->gpio.mrdy); -error_ret4: - gpio_free(ifx_dev->gpio.reset); -error_ret3: - gpio_free(ifx_dev->gpio.po); -error_ret2: - gpio_free(ifx_dev->gpio.reset_out); -error_ret: - ifx_spi_free_device(ifx_dev); - saved_ifx_dev = NULL; - return ret; -} - -/** - * ifx_spi_spi_remove - SPI device was removed - * @spi: SPI device - * - * FIXME: We should be shutting the device down here not in - * the module unload path. - */ - -static int ifx_spi_spi_remove(struct spi_device *spi) -{ - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - /* stop activity */ - tasklet_kill(&ifx_dev->io_work_tasklet); - /* free irq */ - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); - free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev); - - gpio_free(ifx_dev->gpio.srdy); - gpio_free(ifx_dev->gpio.mrdy); - gpio_free(ifx_dev->gpio.reset); - gpio_free(ifx_dev->gpio.po); - gpio_free(ifx_dev->gpio.reset_out); - - /* free allocations */ - ifx_spi_free_device(ifx_dev); - - saved_ifx_dev = NULL; - return 0; -} - -/** - * ifx_spi_spi_shutdown - called on SPI shutdown - * @spi: SPI device - * - * No action needs to be taken here - */ - -static void ifx_spi_spi_shutdown(struct spi_device *spi) -{ -} - -/* - * various suspends and resumes have nothing to do - * no hardware to save state for - */ - -/** - * ifx_spi_spi_suspend - suspend SPI on system suspend - * @dev: device being suspended - * - * Suspend the SPI side. No action needed on Intel MID platforms, may - * need extending for other systems. - */ -static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ - return 0; -} - -/** - * ifx_spi_spi_resume - resume SPI side on system resume - * @dev: device being suspended - * - * Suspend the SPI side. No action needed on Intel MID platforms, may - * need extending for other systems. - */ -static int ifx_spi_spi_resume(struct spi_device *spi) -{ - return 0; -} - -/** - * ifx_spi_pm_suspend - suspend modem on system suspend - * @dev: device being suspended - * - * Suspend the modem. No action needed on Intel MID platforms, may - * need extending for other systems. - */ -static int ifx_spi_pm_suspend(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_resume - resume modem on system resume - * @dev: device being suspended - * - * Allow the modem to resume. No action needed. - * - * FIXME: do we need to reset anything here ? - */ -static int ifx_spi_pm_resume(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_resume - suspend modem - * @dev: device being suspended - * - * Allow the modem to resume. No action needed. - */ -static int ifx_spi_pm_runtime_resume(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_suspend - suspend modem - * @dev: device being suspended - * - * Allow the modem to suspend and thus suspend to continue up the - * device tree. - */ -static int ifx_spi_pm_runtime_suspend(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_idle - check if modem idle - * @dev: our device - * - * Check conditions and queue runtime suspend if idle. - */ -static int ifx_spi_pm_runtime_idle(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - - if (!ifx_dev->power_status) - pm_runtime_suspend(dev); - - return 0; -} - -static const struct dev_pm_ops ifx_spi_pm = { - .resume = ifx_spi_pm_resume, - .suspend = ifx_spi_pm_suspend, - .runtime_resume = ifx_spi_pm_runtime_resume, - .runtime_suspend = ifx_spi_pm_runtime_suspend, - .runtime_idle = ifx_spi_pm_runtime_idle -}; - -static const struct spi_device_id ifx_id_table[] = { - {"ifx6160", 0}, - {"ifx6260", 0}, - { } -}; -MODULE_DEVICE_TABLE(spi, ifx_id_table); - -/* spi operations */ -static const struct spi_driver ifx_spi_driver_6160 = { - .driver = { - .name = "ifx6160", - .bus = &spi_bus_type, - .pm = &ifx_spi_pm, - .owner = THIS_MODULE}, - .probe = ifx_spi_spi_probe, - .shutdown = ifx_spi_spi_shutdown, - .remove = __devexit_p(ifx_spi_spi_remove), - .suspend = ifx_spi_spi_suspend, - .resume = ifx_spi_spi_resume, - .id_table = ifx_id_table -}; - -/** - * ifx_spi_exit - module exit - * - * Unload the module. - */ - -static void __exit ifx_spi_exit(void) -{ - /* unregister */ - tty_unregister_driver(tty_drv); - spi_unregister_driver((void *)&ifx_spi_driver_6160); -} - -/** - * ifx_spi_init - module entry point - * - * Initialise the SPI and tty interfaces for the IFX SPI driver - * We need to initialize upper-edge spi driver after the tty - * driver because otherwise the spi probe will race - */ - -static int __init ifx_spi_init(void) -{ - int result; - - tty_drv = alloc_tty_driver(1); - if (!tty_drv) { - pr_err("%s: alloc_tty_driver failed", DRVNAME); - return -ENOMEM; - } - - tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->owner = THIS_MODULE; - tty_drv->driver_name = DRVNAME; - tty_drv->name = TTYNAME; - tty_drv->minor_start = IFX_SPI_TTY_ID; - tty_drv->num = 1; - tty_drv->type = TTY_DRIVER_TYPE_SERIAL; - tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_drv->init_termios = tty_std_termios; - - tty_set_operations(tty_drv, &ifx_spi_serial_ops); - - result = tty_register_driver(tty_drv); - if (result) { - pr_err("%s: tty_register_driver failed(%d)", - DRVNAME, result); - put_tty_driver(tty_drv); - return result; - } - - result = spi_register_driver((void *)&ifx_spi_driver_6160); - if (result) { - pr_err("%s: spi_register_driver failed(%d)", - DRVNAME, result); - tty_unregister_driver(tty_drv); - } - return result; -} - -module_init(ifx_spi_init); -module_exit(ifx_spi_exit); - -MODULE_AUTHOR("Intel"); -MODULE_DESCRIPTION("IFX6x60 spi driver"); -MODULE_LICENSE("GPL"); -MODULE_INFO(Version, "0.1-IFX6x60"); diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h deleted file mode 100644 index deb7b8d977dc..000000000000 --- a/drivers/serial/ifx6x60.h +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************** - * - * Driver for the IFX spi modem. - * - * Copyright (C) 2009, 2010 Intel Corp - * Jim Stanley - * - * - * 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. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA - * - * - * - *****************************************************************************/ -#ifndef _IFX6X60_H -#define _IFX6X60_H - -#define DRVNAME "ifx6x60" -#define TTYNAME "ttyIFX" - -/* #define IFX_THROTTLE_CODE */ - -#define IFX_SPI_MAX_MINORS 1 -#define IFX_SPI_TRANSFER_SIZE 2048 -#define IFX_SPI_FIFO_SIZE 4096 - -#define IFX_SPI_HEADER_OVERHEAD 4 -#define IFX_RESET_TIMEOUT msecs_to_jiffies(50) - -/* device flags bitfield definitions */ -#define IFX_SPI_STATE_PRESENT 0 -#define IFX_SPI_STATE_IO_IN_PROGRESS 1 -#define IFX_SPI_STATE_IO_READY 2 -#define IFX_SPI_STATE_TIMER_PENDING 3 - -/* flow control bitfields */ -#define IFX_SPI_DCD 0 -#define IFX_SPI_CTS 1 -#define IFX_SPI_DSR 2 -#define IFX_SPI_RI 3 -#define IFX_SPI_DTR 4 -#define IFX_SPI_RTS 5 -#define IFX_SPI_TX_FC 6 -#define IFX_SPI_RX_FC 7 -#define IFX_SPI_UPDATE 8 - -#define IFX_SPI_PAYLOAD_SIZE (IFX_SPI_TRANSFER_SIZE - \ - IFX_SPI_HEADER_OVERHEAD) - -#define IFX_SPI_IRQ_TYPE DETECT_EDGE_RISING -#define IFX_SPI_GPIO_TARGET 0 -#define IFX_SPI_GPIO0 0x105 - -#define IFX_SPI_STATUS_TIMEOUT (2000*HZ) - -/* values for bits in power status byte */ -#define IFX_SPI_POWER_DATA_PENDING 1 -#define IFX_SPI_POWER_SRDY 2 - -struct ifx_spi_device { - /* Our SPI device */ - struct spi_device *spi_dev; - - /* Port specific data */ - struct kfifo tx_fifo; - spinlock_t fifo_lock; - unsigned long signal_state; - - /* TTY Layer logic */ - struct tty_port tty_port; - struct device *tty_dev; - int minor; - - /* Low level I/O work */ - struct tasklet_struct io_work_tasklet; - unsigned long flags; - dma_addr_t rx_dma; - dma_addr_t tx_dma; - - int is_6160; /* Modem type */ - - spinlock_t write_lock; - int write_pending; - spinlock_t power_lock; - unsigned char power_status; - - unsigned char *rx_buffer; - unsigned char *tx_buffer; - dma_addr_t rx_bus; - dma_addr_t tx_bus; - unsigned char spi_more; - unsigned char spi_slave_cts; - - struct timer_list spi_timer; - - struct spi_message spi_msg; - struct spi_transfer spi_xfer; - - struct { - /* gpio lines */ - unsigned short srdy; /* slave-ready gpio */ - unsigned short mrdy; /* master-ready gpio */ - unsigned short reset; /* modem-reset gpio */ - unsigned short po; /* modem-on gpio */ - unsigned short reset_out; /* modem-in-reset gpio */ - /* state/stats */ - int unack_srdy_int_nb; - } gpio; - - /* modem reset */ - unsigned long mdm_reset_state; -#define MR_START 0 -#define MR_INPROGRESS 1 -#define MR_COMPLETE 2 - wait_queue_head_t mdm_reset_wait; -}; - -#endif /* _IFX6X60_H */ diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c deleted file mode 100644 index dfcf4b1878aa..000000000000 --- a/drivers/serial/imx.c +++ /dev/null @@ -1,1380 +0,0 @@ -/* - * linux/drivers/serial/imx.c - * - * Driver for Motorola IMX serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Author: Sascha Hauer - * Copyright (C) 2004 Pengutronix - * - * Copyright (C) 2009 emlix GmbH - * Author: Fabian Godehardt (added IrDA support for iMX) - * - * 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 - * - * [29-Mar-2005] Mike Lee - * Added hardware handshake - */ - -#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* Register definitions */ -#define URXD0 0x0 /* Receiver Register */ -#define URTX0 0x40 /* Transmitter Register */ -#define UCR1 0x80 /* Control Register 1 */ -#define UCR2 0x84 /* Control Register 2 */ -#define UCR3 0x88 /* Control Register 3 */ -#define UCR4 0x8c /* Control Register 4 */ -#define UFCR 0x90 /* FIFO Control Register */ -#define USR1 0x94 /* Status Register 1 */ -#define USR2 0x98 /* Status Register 2 */ -#define UESC 0x9c /* Escape Character Register */ -#define UTIM 0xa0 /* Escape Timer Register */ -#define UBIR 0xa4 /* BRM Incremental Register */ -#define UBMR 0xa8 /* BRM Modulator Register */ -#define UBRC 0xac /* Baud Rate Count Register */ -#define MX2_ONEMS 0xb0 /* One Millisecond register */ -#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */ - -/* UART Control Register Bit Fields.*/ -#define URXD_CHARRDY (1<<15) -#define URXD_ERR (1<<14) -#define URXD_OVRRUN (1<<13) -#define URXD_FRMERR (1<<12) -#define URXD_BRK (1<<11) -#define URXD_PRERR (1<<10) -#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ -#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ -#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ -#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ -#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ -#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ -#define UCR1_IREN (1<<7) /* Infrared interface enable */ -#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ -#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ -#define UCR1_SNDBRK (1<<4) /* Send break */ -#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ -#define MX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, mx1 only */ -#define UCR1_DOZE (1<<1) /* Doze */ -#define UCR1_UARTEN (1<<0) /* UART enabled */ -#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ -#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ -#define UCR2_CTSC (1<<13) /* CTS pin control */ -#define UCR2_CTS (1<<12) /* Clear to send */ -#define UCR2_ESCEN (1<<11) /* Escape enable */ -#define UCR2_PREN (1<<8) /* Parity enable */ -#define UCR2_PROE (1<<7) /* Parity odd/even */ -#define UCR2_STPB (1<<6) /* Stop */ -#define UCR2_WS (1<<5) /* Word size */ -#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ -#define UCR2_TXEN (1<<2) /* Transmitter enabled */ -#define UCR2_RXEN (1<<1) /* Receiver enabled */ -#define UCR2_SRST (1<<0) /* SW reset */ -#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ -#define UCR3_PARERREN (1<<12) /* Parity enable */ -#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ -#define UCR3_DSR (1<<10) /* Data set ready */ -#define UCR3_DCD (1<<9) /* Data carrier detect */ -#define UCR3_RI (1<<8) /* Ring indicator */ -#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ -#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ -#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ -#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ -#define MX1_UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ -#define MX1_UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ -#define MX2_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */ -#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ -#define UCR3_BPEN (1<<0) /* Preset registers enable */ -#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */ -#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */ -#define UCR4_INVR (1<<9) /* Inverted infrared reception */ -#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ -#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ -#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ -#define UCR4_IRSC (1<<5) /* IR special case */ -#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ -#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ -#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ -#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ -#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ -#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ -#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) -#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ -#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ -#define USR1_RTSS (1<<14) /* RTS pin status */ -#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ -#define USR1_RTSD (1<<12) /* RTS delta */ -#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ -#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ -#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ -#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ -#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ -#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ -#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ -#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ -#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ -#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ -#define USR2_IDLE (1<<12) /* Idle condition */ -#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ -#define USR2_WAKE (1<<7) /* Wake */ -#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ -#define USR2_TXDC (1<<3) /* Transmitter complete */ -#define USR2_BRCD (1<<2) /* Break condition */ -#define USR2_ORE (1<<1) /* Overrun error */ -#define USR2_RDR (1<<0) /* Recv data ready */ -#define UTS_FRCPERR (1<<13) /* Force parity error */ -#define UTS_LOOP (1<<12) /* Loop tx and rx */ -#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ -#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ -#define UTS_TXFULL (1<<4) /* TxFIFO full */ -#define UTS_RXFULL (1<<3) /* RxFIFO full */ -#define UTS_SOFTRST (1<<0) /* Software reset */ - -/* We've been assigned a range on the "Low-density serial ports" major */ -#define SERIAL_IMX_MAJOR 207 -#define MINOR_START 16 -#define DEV_NAME "ttymxc" -#define MAX_INTERNAL_IRQ MXC_INTERNAL_IRQS - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo incase CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -#define DRIVER_NAME "IMX-uart" - -#define UART_NR 8 - -struct imx_port { - struct uart_port port; - struct timer_list timer; - unsigned int old_status; - int txirq,rxirq,rtsirq; - unsigned int have_rtscts:1; - unsigned int use_irda:1; - unsigned int irda_inv_rx:1; - unsigned int irda_inv_tx:1; - unsigned short trcv_delay; /* transceiver delay */ - struct clk *clk; -}; - -#ifdef CONFIG_IRDA -#define USE_IRDA(sport) ((sport)->use_irda) -#else -#define USE_IRDA(sport) (0) -#endif - -/* - * Handle any change of modem status signal since we were last called. - */ -static void imx_mctrl_check(struct imx_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void imx_timeout(unsigned long data) -{ - struct imx_port *sport = (struct imx_port *)data; - unsigned long flags; - - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - imx_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } -} - -/* - * interrupts disabled on entry - */ -static void imx_stop_tx(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; - - if (USE_IRDA(sport)) { - /* half duplex - wait for end of transmission */ - int n = 256; - while ((--n > 0) && - !(readl(sport->port.membase + USR2) & USR2_TXDC)) { - udelay(5); - barrier(); - } - /* - * irda transceiver - wait a bit more to avoid - * cutoff, hardware dependent - */ - udelay(sport->trcv_delay); - - /* - * half duplex - reactivate receive mode, - * flush receive pipe echo crap - */ - if (readl(sport->port.membase + USR2) & USR2_TXDC) { - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_TCEN); - writel(temp, sport->port.membase + UCR4); - - while (readl(sport->port.membase + URXD0) & - URXD_CHARRDY) - barrier(); - - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_DREN; - writel(temp, sport->port.membase + UCR4); - } - return; - } - - temp = readl(sport->port.membase + UCR1); - writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); -} - -/* - * interrupts disabled on entry - */ -static void imx_stop_rx(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; - - temp = readl(sport->port.membase + UCR2); - writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2); -} - -/* - * Set the modem control timer to fire immediately. - */ -static void imx_enable_ms(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - - mod_timer(&sport->timer, jiffies); -} - -static inline void imx_transmit_buffer(struct imx_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - - while (!uart_circ_empty(xmit) && - !(readl(sport->port.membase + UTS) & UTS_TXFULL)) { - /* send xmit->buf[xmit->tail] - * out the port here */ - writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - imx_stop_tx(&sport->port); -} - -/* - * interrupts disabled on entry - */ -static void imx_start_tx(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; - - if (USE_IRDA(sport)) { - /* half duplex in IrDA mode; have to disable receive mode */ - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_DREN); - writel(temp, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); - } - - temp = readl(sport->port.membase + UCR1); - writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); - - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_TRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_TCEN; - writel(temp, sport->port.membase + UCR4); - } - - if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) - imx_transmit_buffer(sport); -} - -static irqreturn_t imx_rtsint(int irq, void *dev_id) -{ - struct imx_port *sport = dev_id; - unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - - writel(USR1_RTSD, sport->port.membase + USR1); - uart_handle_cts_change(&sport->port, !!val); - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); - - spin_unlock_irqrestore(&sport->port.lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t imx_txint(int irq, void *dev_id) -{ - struct imx_port *sport = dev_id; - struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock,flags); - if (sport->port.x_char) - { - /* Send next char */ - writel(sport->port.x_char, sport->port.membase + URTX0); - goto out; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - imx_stop_tx(&sport->port); - goto out; - } - - imx_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - -out: - spin_unlock_irqrestore(&sport->port.lock,flags); - return IRQ_HANDLED; -} - -static irqreturn_t imx_rxint(int irq, void *dev_id) -{ - struct imx_port *sport = dev_id; - unsigned int rx,flg,ignored = 0; - struct tty_struct *tty = sport->port.state->port.tty; - unsigned long flags, temp; - - spin_lock_irqsave(&sport->port.lock,flags); - - while (readl(sport->port.membase + USR2) & USR2_RDR) { - flg = TTY_NORMAL; - sport->port.icount.rx++; - - rx = readl(sport->port.membase + URXD0); - - temp = readl(sport->port.membase + USR2); - if (temp & USR2_BRCD) { - writel(USR2_BRCD, sport->port.membase + USR2); - if (uart_handle_break(&sport->port)) - continue; - } - - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) - continue; - - if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { - if (rx & URXD_PRERR) - sport->port.icount.parity++; - else if (rx & URXD_FRMERR) - sport->port.icount.frame++; - if (rx & URXD_OVRRUN) - sport->port.icount.overrun++; - - if (rx & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out; - continue; - } - - rx &= sport->port.read_status_mask; - - if (rx & URXD_PRERR) - flg = TTY_PARITY; - else if (rx & URXD_FRMERR) - flg = TTY_FRAME; - if (rx & URXD_OVRRUN) - flg = TTY_OVERRUN; - -#ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; -#endif - } - - tty_insert_flip_char(tty, rx, flg); - } - -out: - spin_unlock_irqrestore(&sport->port.lock,flags); - tty_flip_buffer_push(tty); - return IRQ_HANDLED; -} - -static irqreturn_t imx_int(int irq, void *dev_id) -{ - struct imx_port *sport = dev_id; - unsigned int sts; - - sts = readl(sport->port.membase + USR1); - - if (sts & USR1_RRDY) - imx_rxint(irq, dev_id); - - if (sts & USR1_TRDY && - readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) - imx_txint(irq, dev_id); - - if (sts & USR1_RTSD) - imx_rtsint(irq, dev_id); - - return IRQ_HANDLED; -} - -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int imx_tx_empty(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - - return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; -} - -/* - * We have a modem side uart, so the meanings of RTS and CTS are inverted. - */ -static unsigned int imx_get_mctrl(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned int tmp = TIOCM_DSR | TIOCM_CAR; - - if (readl(sport->port.membase + USR1) & USR1_RTSS) - tmp |= TIOCM_CTS; - - if (readl(sport->port.membase + UCR2) & UCR2_CTS) - tmp |= TIOCM_RTS; - - return tmp; -} - -static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; - - temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; - - if (mctrl & TIOCM_RTS) - temp |= UCR2_CTS; - - writel(temp, sport->port.membase + UCR2); -} - -/* - * Interrupts always disabled. - */ -static void imx_break_ctl(struct uart_port *port, int break_state) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long flags, temp; - - spin_lock_irqsave(&sport->port.lock, flags); - - temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK; - - if ( break_state != 0 ) - temp |= UCR1_SNDBRK; - - writel(temp, sport->port.membase + UCR1); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -#define TXTL 2 /* reset default */ -#define RXTL 1 /* reset default */ - -static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) -{ - unsigned int val; - unsigned int ufcr_rfdiv; - - /* set receiver / transmitter trigger level. - * RFDIV is set such way to satisfy requested uartclk value - */ - val = TXTL << 10 | RXTL; - ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2) - / sport->port.uartclk; - - if(!ufcr_rfdiv) - ufcr_rfdiv = 1; - - val |= UFCR_RFDIV_REG(ufcr_rfdiv); - - writel(val, sport->port.membase + UFCR); - - return 0; -} - -/* half the RX buffer size */ -#define CTSTL 16 - -static int imx_startup(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - int retval; - unsigned long flags, temp; - - imx_setup_ufcr(sport, 0); - - /* disable the DREN bit (Data Ready interrupt enable) before - * requesting IRQs - */ - temp = readl(sport->port.membase + UCR4); - - if (USE_IRDA(sport)) - temp |= UCR4_IRSC; - - /* set the trigger level for CTS */ - temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF); - temp |= CTSTL<< UCR4_CTSTL_SHF; - - writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); - - if (USE_IRDA(sport)) { - /* reset fifo's and state machines */ - int i = 100; - temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && - (--i > 0)) { - udelay(1); - } - } - - /* - * Allocate the IRQ(s) i.MX1 has three interrupts whereas later - * chips only have one interrupt. - */ - if (sport->txirq > 0) { - retval = request_irq(sport->rxirq, imx_rxint, 0, - DRIVER_NAME, sport); - if (retval) - goto error_out1; - - retval = request_irq(sport->txirq, imx_txint, 0, - DRIVER_NAME, sport); - if (retval) - goto error_out2; - - /* do not use RTS IRQ on IrDA */ - if (!USE_IRDA(sport)) { - retval = request_irq(sport->rtsirq, imx_rtsint, - (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : - IRQF_TRIGGER_FALLING | - IRQF_TRIGGER_RISING, - DRIVER_NAME, sport); - if (retval) - goto error_out3; - } - } else { - retval = request_irq(sport->port.irq, imx_int, 0, - DRIVER_NAME, sport); - if (retval) { - free_irq(sport->port.irq, sport); - goto error_out1; - } - } - - /* - * Finally, clear and enable interrupts - */ - writel(USR1_RTSD, sport->port.membase + USR1); - - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; - - if (USE_IRDA(sport)) { - temp |= UCR1_IREN; - temp &= ~(UCR1_RTSDEN); - } - - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR2); - temp |= (UCR2_RXEN | UCR2_TXEN); - writel(temp, sport->port.membase + UCR2); - - if (USE_IRDA(sport)) { - /* clear RX-FIFO */ - int i = 64; - while ((--i > 0) && - (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { - barrier(); - } - } - - if (!cpu_is_mx1()) { - temp = readl(sport->port.membase + UCR3); - temp |= MX2_UCR3_RXDMUXSEL; - writel(temp, sport->port.membase + UCR3); - } - - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR4); - if (sport->irda_inv_rx) - temp |= UCR4_INVR; - else - temp &= ~(UCR4_INVR); - writel(temp | UCR4_DREN, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR3); - if (sport->irda_inv_tx) - temp |= UCR3_INVT; - else - temp &= ~(UCR3_INVT); - writel(temp, sport->port.membase + UCR3); - } - - /* - * Enable modem status interrupts - */ - spin_lock_irqsave(&sport->port.lock,flags); - imx_enable_ms(&sport->port); - spin_unlock_irqrestore(&sport->port.lock,flags); - - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = sport->port.dev->platform_data; - sport->irda_inv_rx = pdata->irda_inv_rx; - sport->irda_inv_tx = pdata->irda_inv_tx; - sport->trcv_delay = pdata->transceiver_delay; - if (pdata->irda_enable) - pdata->irda_enable(1); - } - - return 0; - -error_out3: - if (sport->txirq) - free_irq(sport->txirq, sport); -error_out2: - if (sport->rxirq) - free_irq(sport->rxirq, sport); -error_out1: - return retval; -} - -static void imx_shutdown(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; - - temp = readl(sport->port.membase + UCR2); - temp &= ~(UCR2_TXEN); - writel(temp, sport->port.membase + UCR2); - - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = sport->port.dev->platform_data; - if (pdata->irda_enable) - pdata->irda_enable(0); - } - - /* - * Stop our timer. - */ - del_timer_sync(&sport->timer); - - /* - * Free the interrupts - */ - if (sport->txirq > 0) { - if (!USE_IRDA(sport)) - free_irq(sport->rtsirq, sport); - free_irq(sport->txirq, sport); - free_irq(sport->rxirq, sport); - } else - free_irq(sport->port.irq, sport); - - /* - * Disable all interrupts, port and break condition. - */ - - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - if (USE_IRDA(sport)) - temp &= ~(UCR1_IREN); - - writel(temp, sport->port.membase + UCR1); -} - -static void -imx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct imx_port *sport = (struct imx_port *)port; - unsigned long flags; - unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; - unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - unsigned int div, ufcr; - unsigned long num, denom; - uint64_t tdiv64; - - /* - * If we don't support modem control lines, don't allow - * these to be set. - */ - if (0) { - termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); - termios->c_cflag |= CLOCAL; - } - - /* - * We only support CS7 and CS8. - */ - while ((termios->c_cflag & CSIZE) != CS7 && - (termios->c_cflag & CSIZE) != CS8) { - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= old_csize; - old_csize = CS8; - } - - if ((termios->c_cflag & CSIZE) == CS8) - ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS; - else - ucr2 = UCR2_SRST | UCR2_IRTS; - - if (termios->c_cflag & CRTSCTS) { - if( sport->have_rtscts ) { - ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; - } else { - termios->c_cflag &= ~CRTSCTS; - } - } - - if (termios->c_cflag & CSTOPB) - ucr2 |= UCR2_STPB; - if (termios->c_cflag & PARENB) { - ucr2 |= UCR2_PREN; - if (termios->c_cflag & PARODD) - ucr2 |= UCR2_PROE; - } - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); - quot = uart_get_divisor(port, baud); - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->port.read_status_mask = 0; - if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR); - if (termios->c_iflag & (BRKINT | PARMRK)) - sport->port.read_status_mask |= URXD_BRK; - - /* - * Characters to ignore - */ - sport->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= URXD_PRERR; - if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= URXD_BRK; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= URXD_OVRRUN; - } - - del_timer_sync(&sport->timer); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * disable interrupts and drain transmitter - */ - old_ucr1 = readl(sport->port.membase + UCR1); - writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), - sport->port.membase + UCR1); - - while ( !(readl(sport->port.membase + USR2) & USR2_TXDC)) - barrier(); - - /* then, disable everything */ - old_txrxen = readl(sport->port.membase + UCR2); - writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN), - sport->port.membase + UCR2); - old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - - if (USE_IRDA(sport)) { - /* - * use maximum available submodule frequency to - * avoid missing short pulses due to low sampling rate - */ - div = 1; - } else { - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) - div = 1; - } - - rational_best_approximation(16 * div * baud, sport->port.uartclk, - 1 << 16, 1 << 16, &num, &denom); - - tdiv64 = sport->port.uartclk; - tdiv64 *= num; - do_div(tdiv64, denom * 16 * div); - tty_termios_encode_baud_rate(termios, - (speed_t)tdiv64, (speed_t)tdiv64); - - num -= 1; - denom -= 1; - - ufcr = readl(sport->port.membase + UFCR); - ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); - writel(ufcr, sport->port.membase + UFCR); - - writel(num, sport->port.membase + UBIR); - writel(denom, sport->port.membase + UBMR); - - if (!cpu_is_mx1()) - writel(sport->port.uartclk / div / 1000, - sport->port.membase + MX2_ONEMS); - - writel(old_ucr1, sport->port.membase + UCR1); - - /* set the parity, stop bits and data size */ - writel(ucr2 | old_txrxen, sport->port.membase + UCR2); - - if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - imx_enable_ms(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *imx_type(struct uart_port *port) -{ - struct imx_port *sport = (struct imx_port *)port; - - return sport->port.type == PORT_IMX ? "IMX" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, mmres->end - mmres->start + 1); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - void *ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mmres) - return -ENODEV; - - ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1, - "imx-uart"); - - return ret ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void imx_config_port(struct uart_port *port, int flags) -{ - struct imx_port *sport = (struct imx_port *)port; - - if (flags & UART_CONFIG_TYPE && - imx_request_port(&sport->port) == 0) - sport->port.type = PORT_IMX; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_IMX and PORT_UNKNOWN - */ -static int -imx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct imx_port *sport = (struct imx_port *)port; - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != UPIO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -static struct uart_ops imx_pops = { - .tx_empty = imx_tx_empty, - .set_mctrl = imx_set_mctrl, - .get_mctrl = imx_get_mctrl, - .stop_tx = imx_stop_tx, - .start_tx = imx_start_tx, - .stop_rx = imx_stop_rx, - .enable_ms = imx_enable_ms, - .break_ctl = imx_break_ctl, - .startup = imx_startup, - .shutdown = imx_shutdown, - .set_termios = imx_set_termios, - .type = imx_type, - .release_port = imx_release_port, - .request_port = imx_request_port, - .config_port = imx_config_port, - .verify_port = imx_verify_port, -}; - -static struct imx_port *imx_ports[UART_NR]; - -#ifdef CONFIG_SERIAL_IMX_CONSOLE -static void imx_console_putchar(struct uart_port *port, int ch) -{ - struct imx_port *sport = (struct imx_port *)port; - - while (readl(sport->port.membase + UTS) & UTS_TXFULL) - barrier(); - - writel(ch, sport->port.membase + URTX0); -} - -/* - * Interrupts are disabled on entering - */ -static void -imx_console_write(struct console *co, const char *s, unsigned int count) -{ - struct imx_port *sport = imx_ports[co->index]; - unsigned int old_ucr1, old_ucr2, ucr1; - - /* - * First, save UCR1/2 and then disable interrupts - */ - ucr1 = old_ucr1 = readl(sport->port.membase + UCR1); - old_ucr2 = readl(sport->port.membase + UCR2); - - if (cpu_is_mx1()) - ucr1 |= MX1_UCR1_UARTCLKEN; - ucr1 |= UCR1_UARTEN; - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); - - writel(ucr1, sport->port.membase + UCR1); - - writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2); - - uart_console_write(&sport->port, s, count, imx_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore UCR1/2 - */ - while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); - - writel(old_ucr1, sport->port.membase + UCR1); - writel(old_ucr2, sport->port.membase + UCR2); -} - -/* - * If the port was already initialised (eg, by a boot loader), - * try to determine the current setup. - */ -static void __init -imx_console_get_options(struct imx_port *sport, int *baud, - int *parity, int *bits) -{ - - if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) { - /* ok, the port was enabled */ - unsigned int ucr2, ubir,ubmr, uartclk; - unsigned int baud_raw; - unsigned int ucfr_rfdiv; - - ucr2 = readl(sport->port.membase + UCR2); - - *parity = 'n'; - if (ucr2 & UCR2_PREN) { - if (ucr2 & UCR2_PROE) - *parity = 'o'; - else - *parity = 'e'; - } - - if (ucr2 & UCR2_WS) - *bits = 8; - else - *bits = 7; - - ubir = readl(sport->port.membase + UBIR) & 0xffff; - ubmr = readl(sport->port.membase + UBMR) & 0xffff; - - ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7; - if (ucfr_rfdiv == 6) - ucfr_rfdiv = 7; - else - ucfr_rfdiv = 6 - ucfr_rfdiv; - - uartclk = clk_get_rate(sport->clk); - uartclk /= ucfr_rfdiv; - - { /* - * The next code provides exact computation of - * baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1)) - * without need of float support or long long division, - * which would be required to prevent 32bit arithmetic overflow - */ - unsigned int mul = ubir + 1; - unsigned int div = 16 * (ubmr + 1); - unsigned int rem = uartclk % div; - - baud_raw = (uartclk / div) * mul; - baud_raw += (rem * mul + div / 2) / div; - *baud = (baud_raw + 50) / 100 * 100; - } - - if(*baud != baud_raw) - printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n", - baud_raw, *baud); - } -} - -static int __init -imx_console_setup(struct console *co, char *options) -{ - struct imx_port *sport; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) - co->index = 0; - sport = imx_ports[co->index]; - if(sport == NULL) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - imx_console_get_options(sport, &baud, &parity, &bits); - - imx_setup_ufcr(sport, 0); - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver imx_reg; -static struct console imx_console = { - .name = DEV_NAME, - .write = imx_console_write, - .device = uart_console_device, - .setup = imx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &imx_reg, -}; - -#define IMX_CONSOLE &imx_console -#else -#define IMX_CONSOLE NULL -#endif - -static struct uart_driver imx_reg = { - .owner = THIS_MODULE, - .driver_name = DRIVER_NAME, - .dev_name = DEV_NAME, - .major = SERIAL_IMX_MAJOR, - .minor = MINOR_START, - .nr = ARRAY_SIZE(imx_ports), - .cons = IMX_CONSOLE, -}; - -static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) -{ - struct imx_port *sport = platform_get_drvdata(dev); - - if (sport) - uart_suspend_port(&imx_reg, &sport->port); - - return 0; -} - -static int serial_imx_resume(struct platform_device *dev) -{ - struct imx_port *sport = platform_get_drvdata(dev); - - if (sport) - uart_resume_port(&imx_reg, &sport->port); - - return 0; -} - -static int serial_imx_probe(struct platform_device *pdev) -{ - struct imx_port *sport; - struct imxuart_platform_data *pdata; - void __iomem *base; - int ret = 0; - struct resource *res; - - sport = kzalloc(sizeof(*sport), GFP_KERNEL); - if (!sport) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto free; - } - - base = ioremap(res->start, PAGE_SIZE); - if (!base) { - ret = -ENOMEM; - goto free; - } - - sport->port.dev = &pdev->dev; - sport->port.mapbase = res->start; - sport->port.membase = base; - sport->port.type = PORT_IMX, - sport->port.iotype = UPIO_MEM; - sport->port.irq = platform_get_irq(pdev, 0); - sport->rxirq = platform_get_irq(pdev, 0); - sport->txirq = platform_get_irq(pdev, 1); - sport->rtsirq = platform_get_irq(pdev, 2); - sport->port.fifosize = 32; - sport->port.ops = &imx_pops; - sport->port.flags = UPF_BOOT_AUTOCONF; - sport->port.line = pdev->id; - init_timer(&sport->timer); - sport->timer.function = imx_timeout; - sport->timer.data = (unsigned long)sport; - - sport->clk = clk_get(&pdev->dev, "uart"); - if (IS_ERR(sport->clk)) { - ret = PTR_ERR(sport->clk); - goto unmap; - } - clk_enable(sport->clk); - - sport->port.uartclk = clk_get_rate(sport->clk); - - imx_ports[pdev->id] = sport; - - pdata = pdev->dev.platform_data; - if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) - sport->have_rtscts = 1; - -#ifdef CONFIG_IRDA - if (pdata && (pdata->flags & IMXUART_IRDA)) - sport->use_irda = 1; -#endif - - if (pdata && pdata->init) { - ret = pdata->init(pdev); - if (ret) - goto clkput; - } - - ret = uart_add_one_port(&imx_reg, &sport->port); - if (ret) - goto deinit; - platform_set_drvdata(pdev, &sport->port); - - return 0; -deinit: - if (pdata && pdata->exit) - pdata->exit(pdev); -clkput: - clk_put(sport->clk); - clk_disable(sport->clk); -unmap: - iounmap(sport->port.membase); -free: - kfree(sport); - - return ret; -} - -static int serial_imx_remove(struct platform_device *pdev) -{ - struct imxuart_platform_data *pdata; - struct imx_port *sport = platform_get_drvdata(pdev); - - pdata = pdev->dev.platform_data; - - platform_set_drvdata(pdev, NULL); - - if (sport) { - uart_remove_one_port(&imx_reg, &sport->port); - clk_put(sport->clk); - } - - clk_disable(sport->clk); - - if (pdata && pdata->exit) - pdata->exit(pdev); - - iounmap(sport->port.membase); - kfree(sport); - - return 0; -} - -static struct platform_driver serial_imx_driver = { - .probe = serial_imx_probe, - .remove = serial_imx_remove, - - .suspend = serial_imx_suspend, - .resume = serial_imx_resume, - .driver = { - .name = "imx-uart", - .owner = THIS_MODULE, - }, -}; - -static int __init imx_serial_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: IMX driver\n"); - - ret = uart_register_driver(&imx_reg); - if (ret) - return ret; - - ret = platform_driver_register(&serial_imx_driver); - if (ret != 0) - uart_unregister_driver(&imx_reg); - - return 0; -} - -static void __exit imx_serial_exit(void) -{ - platform_driver_unregister(&serial_imx_driver); - uart_unregister_driver(&imx_reg); -} - -module_init(imx_serial_init); -module_exit(imx_serial_exit); - -MODULE_AUTHOR("Sascha Hauer"); -MODULE_DESCRIPTION("IMX generic serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-uart"); diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c deleted file mode 100644 index ee43efc7bdcc..000000000000 --- a/drivers/serial/ioc3_serial.c +++ /dev/null @@ -1,2199 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. - */ - -/* - * This file contains a module version of the ioc3 serial driver. This - * includes all the support functions needed (support functions, etc.) - * and the serial driver itself. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Interesting things about the ioc3 - */ - -#define LOGICAL_PORTS 2 /* rs232(0) and rs422(1) */ -#define PORTS_PER_CARD 2 -#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS) -#define MAX_CARDS 8 -#define MAX_LOGICAL_PORTS (LOGICAL_PORTS_PER_CARD * MAX_CARDS) - -/* determine given the sio_ir what port it applies to */ -#define GET_PORT_FROM_SIO_IR(_x) (_x & SIO_IR_SA) ? 0 : 1 - - -/* - * we have 2 logical ports (rs232, rs422) for each physical port - * evens are rs232, odds are rs422 - */ -#define GET_PHYSICAL_PORT(_x) ((_x) >> 1) -#define GET_LOGICAL_PORT(_x) ((_x) & 1) -#define IS_PHYSICAL_PORT(_x) !((_x) & 1) -#define IS_RS232(_x) !((_x) & 1) - -static unsigned int Num_of_ioc3_cards; -static unsigned int Submodule_slot; - -/* defining this will get you LOTS of great debug info */ -//#define DEBUG_INTERRUPTS -#define DPRINT_CONFIG(_x...) ; -//#define DPRINT_CONFIG(_x...) printk _x -#define NOT_PROGRESS() ; -//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__) - -/* number of characters we want to transmit to the lower level at a time */ -#define MAX_CHARS 256 -#define FIFO_SIZE (MAX_CHARS-1) /* it's a uchar */ - -/* Device name we're using */ -#define DEVICE_NAME "ttySIOC" -#define DEVICE_MAJOR 204 -#define DEVICE_MINOR 116 - -/* flags for next_char_state */ -#define NCS_BREAK 0x1 -#define NCS_PARITY 0x2 -#define NCS_FRAMING 0x4 -#define NCS_OVERRUN 0x8 - -/* cause we need SOME parameters ... */ -#define MIN_BAUD_SUPPORTED 1200 -#define MAX_BAUD_SUPPORTED 115200 - -/* protocol types supported */ -#define PROTO_RS232 0 -#define PROTO_RS422 1 - -/* Notification types */ -#define N_DATA_READY 0x01 -#define N_OUTPUT_LOWAT 0x02 -#define N_BREAK 0x04 -#define N_PARITY_ERROR 0x08 -#define N_FRAMING_ERROR 0x10 -#define N_OVERRUN_ERROR 0x20 -#define N_DDCD 0x40 -#define N_DCTS 0x80 - -#define N_ALL_INPUT (N_DATA_READY | N_BREAK \ - | N_PARITY_ERROR | N_FRAMING_ERROR \ - | N_OVERRUN_ERROR | N_DDCD | N_DCTS) - -#define N_ALL_OUTPUT N_OUTPUT_LOWAT - -#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR \ - | N_OVERRUN_ERROR) - -#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK \ - | N_PARITY_ERROR | N_FRAMING_ERROR \ - | N_OVERRUN_ERROR | N_DDCD | N_DCTS) - -#define SER_CLK_SPEED(prediv) ((22000000 << 1) / prediv) -#define SER_DIVISOR(x, clk) (((clk) + (x) * 8) / ((x) * 16)) -#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div)) - -/* Some masks */ -#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \ - | UART_LCR_WLEN7 | UART_LCR_WLEN8) -#define LCR_MASK_STOP_BITS (UART_LCR_STOP) - -#define PENDING(_a, _p) (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable) - -#define RING_BUF_SIZE 4096 -#define BUF_SIZE_BIT SBBR_L_SIZE -#define PROD_CONS_MASK PROD_CONS_PTR_4K - -#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4) - -/* driver specific - one per card */ -struct ioc3_card { - struct { - /* uart ports are allocated here */ - struct uart_port icp_uart_port[LOGICAL_PORTS]; - /* the ioc3_port used for this port */ - struct ioc3_port *icp_port; - } ic_port[PORTS_PER_CARD]; - /* currently enabled interrupts */ - uint32_t ic_enable; -}; - -/* Local port info for each IOC3 serial port */ -struct ioc3_port { - /* handy reference material */ - struct uart_port *ip_port; - struct ioc3_card *ip_card; - struct ioc3_driver_data *ip_idd; - struct ioc3_submodule *ip_is; - - /* pci mem addresses for this port */ - struct ioc3_serialregs __iomem *ip_serial_regs; - struct ioc3_uartregs __iomem *ip_uart_regs; - - /* Ring buffer page for this port */ - dma_addr_t ip_dma_ringbuf; - /* vaddr of ring buffer */ - struct ring_buffer *ip_cpu_ringbuf; - - /* Rings for this port */ - struct ring *ip_inring; - struct ring *ip_outring; - - /* Hook to port specific values */ - struct port_hooks *ip_hooks; - - spinlock_t ip_lock; - - /* Various rx/tx parameters */ - int ip_baud; - int ip_tx_lowat; - int ip_rx_timeout; - - /* Copy of notification bits */ - int ip_notify; - - /* Shadow copies of various registers so we don't need to PIO - * read them constantly - */ - uint32_t ip_sscr; - uint32_t ip_tx_prod; - uint32_t ip_rx_cons; - unsigned char ip_flags; -}; - -/* tx low water mark. We need to notify the driver whenever tx is getting - * close to empty so it can refill the tx buffer and keep things going. - * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll - * have no trouble getting in more chars in time (I certainly hope so). - */ -#define TX_LOWAT_LATENCY 1000 -#define TX_LOWAT_HZ (1000000 / TX_LOWAT_LATENCY) -#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ) - -/* Flags per port */ -#define INPUT_HIGH 0x01 - /* used to signify that we have turned off the rx_high - * temporarily - we need to drain the fifo and don't - * want to get blasted with interrupts. - */ -#define DCD_ON 0x02 - /* DCD state is on */ -#define LOWAT_WRITTEN 0x04 -#define READ_ABORTED 0x08 - /* the read was aborted - used to avaoid infinate looping - * in the interrupt handler - */ -#define INPUT_ENABLE 0x10 - -/* Since each port has different register offsets and bitmasks - * for everything, we'll store those that we need in tables so we - * don't have to be constantly checking the port we are dealing with. - */ -struct port_hooks { - uint32_t intr_delta_dcd; - uint32_t intr_delta_cts; - uint32_t intr_tx_mt; - uint32_t intr_rx_timer; - uint32_t intr_rx_high; - uint32_t intr_tx_explicit; - uint32_t intr_clear; - uint32_t intr_all; - char rs422_select_pin; -}; - -static struct port_hooks hooks_array[PORTS_PER_CARD] = { - /* values for port A */ - { - .intr_delta_dcd = SIO_IR_SA_DELTA_DCD, - .intr_delta_cts = SIO_IR_SA_DELTA_CTS, - .intr_tx_mt = SIO_IR_SA_TX_MT, - .intr_rx_timer = SIO_IR_SA_RX_TIMER, - .intr_rx_high = SIO_IR_SA_RX_HIGH, - .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT, - .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL - | SIO_IR_SA_RX_HIGH - | SIO_IR_SA_RX_TIMER - | SIO_IR_SA_DELTA_DCD - | SIO_IR_SA_DELTA_CTS - | SIO_IR_SA_INT - | SIO_IR_SA_TX_EXPLICIT - | SIO_IR_SA_MEMERR), - .intr_all = SIO_IR_SA, - .rs422_select_pin = GPPR_UARTA_MODESEL_PIN, - }, - - /* values for port B */ - { - .intr_delta_dcd = SIO_IR_SB_DELTA_DCD, - .intr_delta_cts = SIO_IR_SB_DELTA_CTS, - .intr_tx_mt = SIO_IR_SB_TX_MT, - .intr_rx_timer = SIO_IR_SB_RX_TIMER, - .intr_rx_high = SIO_IR_SB_RX_HIGH, - .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT, - .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL - | SIO_IR_SB_RX_HIGH - | SIO_IR_SB_RX_TIMER - | SIO_IR_SB_DELTA_DCD - | SIO_IR_SB_DELTA_CTS - | SIO_IR_SB_INT - | SIO_IR_SB_TX_EXPLICIT - | SIO_IR_SB_MEMERR), - .intr_all = SIO_IR_SB, - .rs422_select_pin = GPPR_UARTB_MODESEL_PIN, - } -}; - -struct ring_entry { - union { - struct { - uint32_t alldata; - uint32_t allsc; - } all; - struct { - char data[4]; /* data bytes */ - char sc[4]; /* status/control */ - } s; - } u; -}; - -/* Test the valid bits in any of the 4 sc chars using "allsc" member */ -#define RING_ANY_VALID \ - ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101) - -#define ring_sc u.s.sc -#define ring_data u.s.data -#define ring_allsc u.all.allsc - -/* Number of entries per ring buffer. */ -#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry)) - -/* An individual ring */ -struct ring { - struct ring_entry entries[ENTRIES_PER_RING]; -}; - -/* The whole enchilada */ -struct ring_buffer { - struct ring TX_A; - struct ring RX_A; - struct ring TX_B; - struct ring RX_B; -}; - -/* Get a ring from a port struct */ -#define RING(_p, _wh) &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh) - -/* for Infinite loop detection */ -#define MAXITER 10000000 - - -/** - * set_baud - Baud rate setting code - * @port: port to set - * @baud: baud rate to use - */ -static int set_baud(struct ioc3_port *port, int baud) -{ - int divisor; - int actual_baud; - int diff; - int lcr, prediv; - struct ioc3_uartregs __iomem *uart; - - for (prediv = 6; prediv < 64; prediv++) { - divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv)); - if (!divisor) - continue; /* invalid divisor */ - actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv)); - - diff = actual_baud - baud; - if (diff < 0) - diff = -diff; - - /* if we're within 1% we've found a match */ - if (diff * 100 <= actual_baud) - break; - } - - /* if the above loop completed, we didn't match - * the baud rate. give up. - */ - if (prediv == 64) { - NOT_PROGRESS(); - return 1; - } - - uart = port->ip_uart_regs; - lcr = readb(&uart->iu_lcr); - - writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr); - writeb((unsigned char)divisor, &uart->iu_dll); - writeb((unsigned char)(divisor >> 8), &uart->iu_dlm); - writeb((unsigned char)prediv, &uart->iu_scr); - writeb((unsigned char)lcr, &uart->iu_lcr); - - return 0; -} - -/** - * get_ioc3_port - given a uart port, return the control structure - * @the_port: uart port to find - */ -static struct ioc3_port *get_ioc3_port(struct uart_port *the_port) -{ - struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev); - struct ioc3_card *card_ptr = idd->data[Submodule_slot]; - int ii, jj; - - if (!card_ptr) { - NOT_PROGRESS(); - return NULL; - } - for (ii = 0; ii < PORTS_PER_CARD; ii++) { - for (jj = 0; jj < LOGICAL_PORTS; jj++) { - if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj]) - return card_ptr->ic_port[ii].icp_port; - } - } - NOT_PROGRESS(); - return NULL; -} - -/** - * port_init - Initialize the sio and ioc3 hardware for a given port - * called per port from attach... - * @port: port to initialize - */ -static int inline port_init(struct ioc3_port *port) -{ - uint32_t sio_cr; - struct port_hooks *hooks = port->ip_hooks; - struct ioc3_uartregs __iomem *uart; - int reset_loop_counter = 0xfffff; - struct ioc3_driver_data *idd = port->ip_idd; - - /* Idle the IOC3 serial interface */ - writel(SSCR_RESET, &port->ip_serial_regs->sscr); - - /* Wait until any pending bus activity for this port has ceased */ - do { - sio_cr = readl(&idd->vma->sio_cr); - if (reset_loop_counter-- <= 0) { - printk(KERN_WARNING - "IOC3 unable to come out of reset" - " scr 0x%x\n", sio_cr); - return -1; - } - } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) && - (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA) - || sio_cr == SIO_CR_ARB_DIAG_TXB - || sio_cr == SIO_CR_ARB_DIAG_RXA - || sio_cr == SIO_CR_ARB_DIAG_RXB)); - - /* Finish reset sequence */ - writel(0, &port->ip_serial_regs->sscr); - - /* Once RESET is done, reload cached tx_prod and rx_cons values - * and set rings to empty by making prod == cons - */ - port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; - writel(port->ip_tx_prod, &port->ip_serial_regs->stpir); - port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; - writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir); - - /* Disable interrupts for this 16550 */ - uart = port->ip_uart_regs; - writeb(0, &uart->iu_lcr); - writeb(0, &uart->iu_ier); - - /* Set the default baud */ - set_baud(port, port->ip_baud); - - /* Set line control to 8 bits no parity */ - writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr); - /* UART_LCR_STOP == 1 stop */ - - /* Enable the FIFOs */ - writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr); - /* then reset 16550 FIFOs */ - writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - &uart->iu_fcr); - - /* Clear modem control register */ - writeb(0, &uart->iu_mcr); - - /* Clear deltas in modem status register */ - writel(0, &port->ip_serial_regs->shadow); - - /* Only do this once per port pair */ - if (port->ip_hooks == &hooks_array[0]) { - unsigned long ring_pci_addr; - uint32_t __iomem *sbbr_l, *sbbr_h; - - sbbr_l = &idd->vma->sbbr_l; - sbbr_h = &idd->vma->sbbr_h; - ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; - DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n", - __func__, (void *)ring_pci_addr)); - - writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h); - writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l); - } - - /* Set the receive timeout value to 10 msec */ - writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr); - - /* Set rx threshold, enable DMA */ - /* Set high water mark at 3/4 of full ring */ - port->ip_sscr = (ENTRIES_PER_RING * 3 / 4); - - /* uart experiences pauses at high baud rate reducing actual - * throughput by 10% or so unless we enable high speed polling - * XXX when this hardware bug is resolved we should revert to - * normal polling speed - */ - port->ip_sscr |= SSCR_HIGH_SPD; - - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - - /* Disable and clear all serial related interrupt bits */ - port->ip_card->ic_enable &= ~hooks->intr_clear; - ioc3_disable(port->ip_is, idd, hooks->intr_clear); - ioc3_ack(port->ip_is, idd, hooks->intr_clear); - return 0; -} - -/** - * enable_intrs - enable interrupts - * @port: port to enable - * @mask: mask to use - */ -static void enable_intrs(struct ioc3_port *port, uint32_t mask) -{ - if ((port->ip_card->ic_enable & mask) != mask) { - port->ip_card->ic_enable |= mask; - ioc3_enable(port->ip_is, port->ip_idd, mask); - } -} - -/** - * local_open - local open a port - * @port: port to open - */ -static inline int local_open(struct ioc3_port *port) -{ - int spiniter = 0; - - port->ip_flags = INPUT_ENABLE; - - /* Pause the DMA interface if necessary */ - if (port->ip_sscr & SSCR_DMA_EN) { - writel(port->ip_sscr | SSCR_DMA_PAUSE, - &port->ip_serial_regs->sscr); - while ((readl(&port->ip_serial_regs->sscr) - & SSCR_PAUSE_STATE) == 0) { - spiniter++; - if (spiniter > MAXITER) { - NOT_PROGRESS(); - return -1; - } - } - } - - /* Reset the input fifo. If the uart received chars while the port - * was closed and DMA is not enabled, the uart may have a bunch of - * chars hanging around in its rx fifo which will not be discarded - * by rclr in the upper layer. We must get rid of them here. - */ - writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR, - &port->ip_uart_regs->iu_fcr); - - writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr); - /* UART_LCR_STOP == 1 stop */ - - /* Re-enable DMA, set default threshold to intr whenever there is - * data available. - */ - port->ip_sscr &= ~SSCR_RX_THRESHOLD; - port->ip_sscr |= 1; /* default threshold */ - - /* Plug in the new sscr. This implicitly clears the DMA_PAUSE - * flag if it was set above - */ - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - port->ip_tx_lowat = 1; - return 0; -} - -/** - * set_rx_timeout - Set rx timeout and threshold values. - * @port: port to use - * @timeout: timeout value in ticks - */ -static inline int set_rx_timeout(struct ioc3_port *port, int timeout) -{ - int threshold; - - port->ip_rx_timeout = timeout; - - /* Timeout is in ticks. Let's figure out how many chars we - * can receive at the current baud rate in that interval - * and set the rx threshold to that amount. There are 4 chars - * per ring entry, so we'll divide the number of chars that will - * arrive in timeout by 4. - * So .... timeout * baud / 10 / HZ / 4, with HZ = 100. - */ - threshold = timeout * port->ip_baud / 4000; - if (threshold == 0) - threshold = 1; /* otherwise we'll intr all the time! */ - - if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD) - return 1; - - port->ip_sscr &= ~SSCR_RX_THRESHOLD; - port->ip_sscr |= threshold; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - - /* Now set the rx timeout to the given value - * again timeout * SRTR_HZ / HZ - */ - timeout = timeout * SRTR_HZ / 100; - if (timeout > SRTR_CNT) - timeout = SRTR_CNT; - writel(timeout, &port->ip_serial_regs->srtr); - return 0; -} - -/** - * config_port - config the hardware - * @port: port to config - * @baud: baud rate for the port - * @byte_size: data size - * @stop_bits: number of stop bits - * @parenb: parity enable ? - * @parodd: odd parity ? - */ -static inline int -config_port(struct ioc3_port *port, - int baud, int byte_size, int stop_bits, int parenb, int parodd) -{ - char lcr, sizebits; - int spiniter = 0; - - DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d " - "parodd %d\n", - __func__, ((struct uart_port *)port->ip_port)->line, - baud, byte_size, stop_bits, parenb, parodd)); - - if (set_baud(port, baud)) - return 1; - - switch (byte_size) { - case 5: - sizebits = UART_LCR_WLEN5; - break; - case 6: - sizebits = UART_LCR_WLEN6; - break; - case 7: - sizebits = UART_LCR_WLEN7; - break; - case 8: - sizebits = UART_LCR_WLEN8; - break; - default: - return 1; - } - - /* Pause the DMA interface if necessary */ - if (port->ip_sscr & SSCR_DMA_EN) { - writel(port->ip_sscr | SSCR_DMA_PAUSE, - &port->ip_serial_regs->sscr); - while ((readl(&port->ip_serial_regs->sscr) - & SSCR_PAUSE_STATE) == 0) { - spiniter++; - if (spiniter > MAXITER) - return -1; - } - } - - /* Clear relevant fields in lcr */ - lcr = readb(&port->ip_uart_regs->iu_lcr); - lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR | - UART_LCR_PARITY | LCR_MASK_STOP_BITS); - - /* Set byte size in lcr */ - lcr |= sizebits; - - /* Set parity */ - if (parenb) { - lcr |= UART_LCR_PARITY; - if (!parodd) - lcr |= UART_LCR_EPAR; - } - - /* Set stop bits */ - if (stop_bits) - lcr |= UART_LCR_STOP /* 2 stop bits */ ; - - writeb(lcr, &port->ip_uart_regs->iu_lcr); - - /* Re-enable the DMA interface if necessary */ - if (port->ip_sscr & SSCR_DMA_EN) { - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - port->ip_baud = baud; - - /* When we get within this number of ring entries of filling the - * entire ring on tx, place an EXPLICIT intr to generate a lowat - * notification when output has drained. - */ - port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4; - if (port->ip_tx_lowat == 0) - port->ip_tx_lowat = 1; - - set_rx_timeout(port, 2); - return 0; -} - -/** - * do_write - Write bytes to the port. Returns the number of bytes - * actually written. Called from transmit_chars - * @port: port to use - * @buf: the stuff to write - * @len: how many bytes in 'buf' - */ -static inline int do_write(struct ioc3_port *port, char *buf, int len) -{ - int prod_ptr, cons_ptr, total = 0; - struct ring *outring; - struct ring_entry *entry; - struct port_hooks *hooks = port->ip_hooks; - - BUG_ON(!(len >= 0)); - - prod_ptr = port->ip_tx_prod; - cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; - outring = port->ip_outring; - - /* Maintain a 1-entry red-zone. The ring buffer is full when - * (cons - prod) % ring_size is 1. Rather than do this subtraction - * in the body of the loop, I'll do it now. - */ - cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK; - - /* Stuff the bytes into the output */ - while ((prod_ptr != cons_ptr) && (len > 0)) { - int xx; - - /* Get 4 bytes (one ring entry) at a time */ - entry = (struct ring_entry *)((caddr_t) outring + prod_ptr); - - /* Invalidate all entries */ - entry->ring_allsc = 0; - - /* Copy in some bytes */ - for (xx = 0; (xx < 4) && (len > 0); xx++) { - entry->ring_data[xx] = *buf++; - entry->ring_sc[xx] = TXCB_VALID; - len--; - total++; - } - - /* If we are within some small threshold of filling up the - * entire ring buffer, we must place an EXPLICIT intr here - * to generate a lowat interrupt in case we subsequently - * really do fill up the ring and the caller goes to sleep. - * No need to place more than one though. - */ - if (!(port->ip_flags & LOWAT_WRITTEN) && - ((cons_ptr - prod_ptr) & PROD_CONS_MASK) - <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) { - port->ip_flags |= LOWAT_WRITTEN; - entry->ring_sc[0] |= TXCB_INT_WHEN_DONE; - } - - /* Go on to next entry */ - prod_ptr += sizeof(struct ring_entry); - prod_ptr &= PROD_CONS_MASK; - } - - /* If we sent something, start DMA if necessary */ - if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) { - port->ip_sscr |= SSCR_DMA_EN; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - - /* Store the new producer pointer. If tx is disabled, we stuff the - * data into the ring buffer, but we don't actually start tx. - */ - if (!uart_tx_stopped(port->ip_port)) { - writel(prod_ptr, &port->ip_serial_regs->stpir); - - /* If we are now transmitting, enable tx_mt interrupt so we - * can disable DMA if necessary when the tx finishes. - */ - if (total > 0) - enable_intrs(port, hooks->intr_tx_mt); - } - port->ip_tx_prod = prod_ptr; - - return total; -} - -/** - * disable_intrs - disable interrupts - * @port: port to enable - * @mask: mask to use - */ -static inline void disable_intrs(struct ioc3_port *port, uint32_t mask) -{ - if (port->ip_card->ic_enable & mask) { - ioc3_disable(port->ip_is, port->ip_idd, mask); - port->ip_card->ic_enable &= ~mask; - } -} - -/** - * set_notification - Modify event notification - * @port: port to use - * @mask: events mask - * @set_on: set ? - */ -static int set_notification(struct ioc3_port *port, int mask, int set_on) -{ - struct port_hooks *hooks = port->ip_hooks; - uint32_t intrbits, sscrbits; - - BUG_ON(!mask); - - intrbits = sscrbits = 0; - - if (mask & N_DATA_READY) - intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high); - if (mask & N_OUTPUT_LOWAT) - intrbits |= hooks->intr_tx_explicit; - if (mask & N_DDCD) { - intrbits |= hooks->intr_delta_dcd; - sscrbits |= SSCR_RX_RING_DCD; - } - if (mask & N_DCTS) - intrbits |= hooks->intr_delta_cts; - - if (set_on) { - enable_intrs(port, intrbits); - port->ip_notify |= mask; - port->ip_sscr |= sscrbits; - } else { - disable_intrs(port, intrbits); - port->ip_notify &= ~mask; - port->ip_sscr &= ~sscrbits; - } - - /* We require DMA if either DATA_READY or DDCD notification is - * currently requested. If neither of these is requested and - * there is currently no tx in progress, DMA may be disabled. - */ - if (port->ip_notify & (N_DATA_READY | N_DDCD)) - port->ip_sscr |= SSCR_DMA_EN; - else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt)) - port->ip_sscr &= ~SSCR_DMA_EN; - - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - return 0; -} - -/** - * set_mcr - set the master control reg - * @the_port: port to use - * @mask1: mcr mask - * @mask2: shadow mask - */ -static inline int set_mcr(struct uart_port *the_port, - int mask1, int mask2) -{ - struct ioc3_port *port = get_ioc3_port(the_port); - uint32_t shadow; - int spiniter = 0; - char mcr; - - if (!port) - return -1; - - /* Pause the DMA interface if necessary */ - if (port->ip_sscr & SSCR_DMA_EN) { - writel(port->ip_sscr | SSCR_DMA_PAUSE, - &port->ip_serial_regs->sscr); - while ((readl(&port->ip_serial_regs->sscr) - & SSCR_PAUSE_STATE) == 0) { - spiniter++; - if (spiniter > MAXITER) - return -1; - } - } - shadow = readl(&port->ip_serial_regs->shadow); - mcr = (shadow & 0xff000000) >> 24; - - /* Set new value */ - mcr |= mask1; - shadow |= mask2; - writeb(mcr, &port->ip_uart_regs->iu_mcr); - writel(shadow, &port->ip_serial_regs->shadow); - - /* Re-enable the DMA interface if necessary */ - if (port->ip_sscr & SSCR_DMA_EN) { - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - return 0; -} - -/** - * ioc3_set_proto - set the protocol for the port - * @port: port to use - * @proto: protocol to use - */ -static int ioc3_set_proto(struct ioc3_port *port, int proto) -{ - struct port_hooks *hooks = port->ip_hooks; - - switch (proto) { - default: - case PROTO_RS232: - /* Clear the appropriate GIO pin */ - DPRINT_CONFIG(("%s: rs232\n", __func__)); - writel(0, (&port->ip_idd->vma->gppr[0] - + hooks->rs422_select_pin)); - break; - - case PROTO_RS422: - /* Set the appropriate GIO pin */ - DPRINT_CONFIG(("%s: rs422\n", __func__)); - writel(1, (&port->ip_idd->vma->gppr[0] - + hooks->rs422_select_pin)); - break; - } - return 0; -} - -/** - * transmit_chars - upper level write, called with the_port->lock - * @the_port: port to write - */ -static void transmit_chars(struct uart_port *the_port) -{ - int xmit_count, tail, head; - int result; - char *start; - struct tty_struct *tty; - struct ioc3_port *port = get_ioc3_port(the_port); - struct uart_state *state; - - if (!the_port) - return; - if (!port) - return; - - state = the_port->state; - tty = state->port.tty; - - if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { - /* Nothing to do or hw stopped */ - set_notification(port, N_ALL_OUTPUT, 0); - return; - } - - head = state->xmit.head; - tail = state->xmit.tail; - start = (char *)&state->xmit.buf[tail]; - - /* write out all the data or until the end of the buffer */ - xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail); - if (xmit_count > 0) { - result = do_write(port, start, xmit_count); - if (result > 0) { - /* booking */ - xmit_count -= result; - the_port->icount.tx += result; - /* advance the pointers */ - tail += result; - tail &= UART_XMIT_SIZE - 1; - state->xmit.tail = tail; - start = (char *)&state->xmit.buf[tail]; - } - } - if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(the_port); - - if (uart_circ_empty(&state->xmit)) { - set_notification(port, N_OUTPUT_LOWAT, 0); - } else { - set_notification(port, N_OUTPUT_LOWAT, 1); - } -} - -/** - * ioc3_change_speed - change the speed of the port - * @the_port: port to change - * @new_termios: new termios settings - * @old_termios: old termios settings - */ -static void -ioc3_change_speed(struct uart_port *the_port, - struct ktermios *new_termios, struct ktermios *old_termios) -{ - struct ioc3_port *port = get_ioc3_port(the_port); - unsigned int cflag, iflag; - int baud; - int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; - struct uart_state *state = the_port->state; - - cflag = new_termios->c_cflag; - iflag = new_termios->c_iflag; - - switch (cflag & CSIZE) { - case CS5: - new_data = 5; - break; - case CS6: - new_data = 6; - break; - case CS7: - new_data = 7; - break; - case CS8: - new_data = 8; - break; - default: - /* cuz we always need a default ... */ - new_data = 5; - break; - } - if (cflag & CSTOPB) { - new_stop = 1; - } - if (cflag & PARENB) { - new_parity_enable = 1; - if (cflag & PARODD) - new_parity = 1; - } - baud = uart_get_baud_rate(the_port, new_termios, old_termios, - MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); - DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud, - the_port->line)); - - if (!the_port->fifosize) - the_port->fifosize = FIFO_SIZE; - uart_update_timeout(the_port, cflag, baud); - - the_port->ignore_status_mask = N_ALL_INPUT; - - state->port.tty->low_latency = 1; - - if (iflag & IGNPAR) - the_port->ignore_status_mask &= ~(N_PARITY_ERROR - | N_FRAMING_ERROR); - if (iflag & IGNBRK) { - the_port->ignore_status_mask &= ~N_BREAK; - if (iflag & IGNPAR) - the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; - } - if (!(cflag & CREAD)) { - /* ignore everything */ - the_port->ignore_status_mask &= ~N_DATA_READY; - } - - if (cflag & CRTSCTS) { - /* enable hardware flow control */ - port->ip_sscr |= SSCR_HFC_EN; - } - else { - /* disable hardware flow control */ - port->ip_sscr &= ~SSCR_HFC_EN; - } - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - - /* Set the configuration and proper notification call */ - DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o " - "config_port(baud %d data %d stop %d penable %d " - " parity %d), notification 0x%x\n", - __func__, (void *)port, the_port->line, cflag, baud, - new_data, new_stop, new_parity_enable, new_parity, - the_port->ignore_status_mask)); - - if ((config_port(port, baud, /* baud */ - new_data, /* byte size */ - new_stop, /* stop bits */ - new_parity_enable, /* set parity */ - new_parity)) >= 0) { /* parity 1==odd */ - set_notification(port, the_port->ignore_status_mask, 1); - } -} - -/** - * ic3_startup_local - Start up the serial port - returns >= 0 if no errors - * @the_port: Port to operate on - */ -static inline int ic3_startup_local(struct uart_port *the_port) -{ - struct ioc3_port *port; - - if (!the_port) { - NOT_PROGRESS(); - return -1; - } - - port = get_ioc3_port(the_port); - if (!port) { - NOT_PROGRESS(); - return -1; - } - - local_open(port); - - /* set the protocol */ - ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 : - PROTO_RS422); - return 0; -} - -/* - * ioc3_cb_output_lowat - called when the output low water mark is hit - * @port: port to output - */ -static void ioc3_cb_output_lowat(struct ioc3_port *port) -{ - unsigned long pflags; - - /* the_port->lock is set on the call here */ - if (port->ip_port) { - spin_lock_irqsave(&port->ip_port->lock, pflags); - transmit_chars(port->ip_port); - spin_unlock_irqrestore(&port->ip_port->lock, pflags); - } -} - -/* - * ioc3_cb_post_ncs - called for some basic errors - * @port: port to use - * @ncs: event - */ -static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs) -{ - struct uart_icount *icount; - - icount = &the_port->icount; - - if (ncs & NCS_BREAK) - icount->brk++; - if (ncs & NCS_FRAMING) - icount->frame++; - if (ncs & NCS_OVERRUN) - icount->overrun++; - if (ncs & NCS_PARITY) - icount->parity++; -} - -/** - * do_read - Read in bytes from the port. Return the number of bytes - * actually read. - * @the_port: port to use - * @buf: place to put the stuff we read - * @len: how big 'buf' is - */ - -static inline int do_read(struct uart_port *the_port, char *buf, int len) -{ - int prod_ptr, cons_ptr, total; - struct ioc3_port *port = get_ioc3_port(the_port); - struct ring *inring; - struct ring_entry *entry; - struct port_hooks *hooks = port->ip_hooks; - int byte_num; - char *sc; - int loop_counter; - - BUG_ON(!(len >= 0)); - BUG_ON(!port); - - /* There is a nasty timing issue in the IOC3. When the rx_timer - * expires or the rx_high condition arises, we take an interrupt. - * At some point while servicing the interrupt, we read bytes from - * the ring buffer and re-arm the rx_timer. However the rx_timer is - * not started until the first byte is received *after* it is armed, - * and any bytes pending in the rx construction buffers are not drained - * to memory until either there are 4 bytes available or the rx_timer - * expires. This leads to a potential situation where data is left - * in the construction buffers forever - 1 to 3 bytes were received - * after the interrupt was generated but before the rx_timer was - * re-armed. At that point as long as no subsequent bytes are received - * the timer will never be started and the bytes will remain in the - * construction buffer forever. The solution is to execute a DRAIN - * command after rearming the timer. This way any bytes received before - * the DRAIN will be drained to memory, and any bytes received after - * the DRAIN will start the TIMER and be drained when it expires. - * Luckily, this only needs to be done when the DMA buffer is empty - * since there is no requirement that this function return all - * available data as long as it returns some. - */ - /* Re-arm the timer */ - - writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir); - - prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; - cons_ptr = port->ip_rx_cons; - - if (prod_ptr == cons_ptr) { - int reset_dma = 0; - - /* Input buffer appears empty, do a flush. */ - - /* DMA must be enabled for this to work. */ - if (!(port->ip_sscr & SSCR_DMA_EN)) { - port->ip_sscr |= SSCR_DMA_EN; - reset_dma = 1; - } - - /* Potential race condition: we must reload the srpir after - * issuing the drain command, otherwise we could think the rx - * buffer is empty, then take a very long interrupt, and when - * we come back it's full and we wait forever for the drain to - * complete. - */ - writel(port->ip_sscr | SSCR_RX_DRAIN, - &port->ip_serial_regs->sscr); - prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; - - /* We must not wait for the DRAIN to complete unless there are - * at least 8 bytes (2 ring entries) available to receive the - * data otherwise the DRAIN will never complete and we'll - * deadlock here. - * In fact, to make things easier, I'll just ignore the flush if - * there is any data at all now available. - */ - if (prod_ptr == cons_ptr) { - loop_counter = 0; - while (readl(&port->ip_serial_regs->sscr) & - SSCR_RX_DRAIN) { - loop_counter++; - if (loop_counter > MAXITER) - return -1; - } - - /* SIGH. We have to reload the prod_ptr *again* since - * the drain may have caused it to change - */ - prod_ptr = readl(&port->ip_serial_regs->srpir) - & PROD_CONS_MASK; - } - if (reset_dma) { - port->ip_sscr &= ~SSCR_DMA_EN; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - } - inring = port->ip_inring; - port->ip_flags &= ~READ_ABORTED; - - total = 0; - loop_counter = 0xfffff; /* to avoid hangs */ - - /* Grab bytes from the hardware */ - while ((prod_ptr != cons_ptr) && (len > 0)) { - entry = (struct ring_entry *)((caddr_t) inring + cons_ptr); - - if (loop_counter-- <= 0) { - printk(KERN_WARNING "IOC3 serial: " - "possible hang condition/" - "port stuck on read (line %d).\n", - the_port->line); - break; - } - - /* According to the producer pointer, this ring entry - * must contain some data. But if the PIO happened faster - * than the DMA, the data may not be available yet, so let's - * wait until it arrives. - */ - if ((entry->ring_allsc & RING_ANY_VALID) == 0) { - /* Indicate the read is aborted so we don't disable - * the interrupt thinking that the consumer is - * congested. - */ - port->ip_flags |= READ_ABORTED; - len = 0; - break; - } - - /* Load the bytes/status out of the ring entry */ - for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) { - sc = &(entry->ring_sc[byte_num]); - - /* Check for change in modem state or overrun */ - if ((*sc & RXSB_MODEM_VALID) - && (port->ip_notify & N_DDCD)) { - /* Notify upper layer if DCD dropped */ - if ((port->ip_flags & DCD_ON) - && !(*sc & RXSB_DCD)) { - /* If we have already copied some data, - * return it. We'll pick up the carrier - * drop on the next pass. That way we - * don't throw away the data that has - * already been copied back to - * the caller's buffer. - */ - if (total > 0) { - len = 0; - break; - } - port->ip_flags &= ~DCD_ON; - - /* Turn off this notification so the - * carrier drop protocol won't see it - * again when it does a read. - */ - *sc &= ~RXSB_MODEM_VALID; - - /* To keep things consistent, we need - * to update the consumer pointer so - * the next reader won't come in and - * try to read the same ring entries - * again. This must be done here before - * the dcd change. - */ - - if ((entry->ring_allsc & RING_ANY_VALID) - == 0) { - cons_ptr += (int)sizeof - (struct ring_entry); - cons_ptr &= PROD_CONS_MASK; - } - writel(cons_ptr, - &port->ip_serial_regs->srcir); - port->ip_rx_cons = cons_ptr; - - /* Notify upper layer of carrier drop */ - if ((port->ip_notify & N_DDCD) - && port->ip_port) { - uart_handle_dcd_change - (port->ip_port, 0); - wake_up_interruptible - (&the_port->state-> - port.delta_msr_wait); - } - - /* If we had any data to return, we - * would have returned it above. - */ - return 0; - } - } - if (*sc & RXSB_MODEM_VALID) { - /* Notify that an input overrun occurred */ - if ((*sc & RXSB_OVERRUN) - && (port->ip_notify & N_OVERRUN_ERROR)) { - ioc3_cb_post_ncs(the_port, NCS_OVERRUN); - } - /* Don't look at this byte again */ - *sc &= ~RXSB_MODEM_VALID; - } - - /* Check for valid data or RX errors */ - if ((*sc & RXSB_DATA_VALID) && - ((*sc & (RXSB_PAR_ERR - | RXSB_FRAME_ERR | RXSB_BREAK)) - && (port->ip_notify & (N_PARITY_ERROR - | N_FRAMING_ERROR - | N_BREAK)))) { - /* There is an error condition on the next byte. - * If we have already transferred some bytes, - * we'll stop here. Otherwise if this is the - * first byte to be read, we'll just transfer - * it alone after notifying the - * upper layer of its status. - */ - if (total > 0) { - len = 0; - break; - } else { - if ((*sc & RXSB_PAR_ERR) && - (port-> - ip_notify & N_PARITY_ERROR)) { - ioc3_cb_post_ncs(the_port, - NCS_PARITY); - } - if ((*sc & RXSB_FRAME_ERR) && - (port-> - ip_notify & N_FRAMING_ERROR)) { - ioc3_cb_post_ncs(the_port, - NCS_FRAMING); - } - if ((*sc & RXSB_BREAK) - && (port->ip_notify & N_BREAK)) { - ioc3_cb_post_ncs - (the_port, NCS_BREAK); - } - len = 1; - } - } - if (*sc & RXSB_DATA_VALID) { - *sc &= ~RXSB_DATA_VALID; - *buf = entry->ring_data[byte_num]; - buf++; - len--; - total++; - } - } - - /* If we used up this entry entirely, go on to the next one, - * otherwise we must have run out of buffer space, so - * leave the consumer pointer here for the next read in case - * there are still unread bytes in this entry. - */ - if ((entry->ring_allsc & RING_ANY_VALID) == 0) { - cons_ptr += (int)sizeof(struct ring_entry); - cons_ptr &= PROD_CONS_MASK; - } - } - - /* Update consumer pointer and re-arm rx timer interrupt */ - writel(cons_ptr, &port->ip_serial_regs->srcir); - port->ip_rx_cons = cons_ptr; - - /* If we have now dipped below the rx high water mark and we have - * rx_high interrupt turned off, we can now turn it back on again. - */ - if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr) - & PROD_CONS_MASK) < - ((port-> - ip_sscr & - SSCR_RX_THRESHOLD) - << PROD_CONS_PTR_OFF))) { - port->ip_flags &= ~INPUT_HIGH; - enable_intrs(port, hooks->intr_rx_high); - } - return total; -} - -/** - * receive_chars - upper level read. - * @the_port: port to read from - */ -static int receive_chars(struct uart_port *the_port) -{ - struct tty_struct *tty; - unsigned char ch[MAX_CHARS]; - int read_count = 0, read_room, flip = 0; - struct uart_state *state = the_port->state; - struct ioc3_port *port = get_ioc3_port(the_port); - unsigned long pflags; - - /* Make sure all the pointers are "good" ones */ - if (!state) - return 0; - if (!state->port.tty) - return 0; - - if (!(port->ip_flags & INPUT_ENABLE)) - return 0; - - spin_lock_irqsave(&the_port->lock, pflags); - tty = state->port.tty; - - read_count = do_read(the_port, ch, MAX_CHARS); - if (read_count > 0) { - flip = 1; - read_room = tty_insert_flip_string(tty, ch, read_count); - the_port->icount.rx += read_count; - } - spin_unlock_irqrestore(&the_port->lock, pflags); - - if (flip) - tty_flip_buffer_push(tty); - - return read_count; -} - -/** - * ioc3uart_intr_one - lowest level (per port) interrupt handler. - * @is : submodule - * @idd: driver data - * @pending: interrupts to handle - */ - -static int inline -ioc3uart_intr_one(struct ioc3_submodule *is, - struct ioc3_driver_data *idd, - unsigned int pending) -{ - int port_num = GET_PORT_FROM_SIO_IR(pending); - struct port_hooks *hooks; - unsigned int rx_high_rd_aborted = 0; - unsigned long flags; - struct uart_port *the_port; - struct ioc3_port *port; - int loop_counter; - struct ioc3_card *card_ptr; - unsigned int sio_ir; - - card_ptr = idd->data[is->id]; - port = card_ptr->ic_port[port_num].icp_port; - hooks = port->ip_hooks; - - /* Possible race condition here: The tx_mt interrupt bit may be - * cleared without the intervention of the interrupt handler, - * e.g. by a write. If the top level interrupt handler reads a - * tx_mt, then some other processor does a write, starting up - * output, then we come in here, see the tx_mt and stop DMA, the - * output started by the other processor will hang. Thus we can - * only rely on tx_mt being legitimate if it is read while the - * port lock is held. Therefore this bit must be ignored in the - * passed in interrupt mask which was read by the top level - * interrupt handler since the port lock was not held at the time - * it was read. We can only rely on this bit being accurate if it - * is read while the port lock is held. So we'll clear it for now, - * and reload it later once we have the port lock. - */ - - sio_ir = pending & ~(hooks->intr_tx_mt); - spin_lock_irqsave(&port->ip_lock, flags); - - loop_counter = MAXITER; /* to avoid hangs */ - - do { - uint32_t shadow; - - if (loop_counter-- <= 0) { - printk(KERN_WARNING "IOC3 serial: " - "possible hang condition/" - "port stuck on interrupt (line %d).\n", - ((struct uart_port *)port->ip_port)->line); - break; - } - /* Handle a DCD change */ - if (sio_ir & hooks->intr_delta_dcd) { - ioc3_ack(is, idd, hooks->intr_delta_dcd); - shadow = readl(&port->ip_serial_regs->shadow); - - if ((port->ip_notify & N_DDCD) - && (shadow & SHADOW_DCD) - && (port->ip_port)) { - the_port = port->ip_port; - uart_handle_dcd_change(the_port, - shadow & SHADOW_DCD); - wake_up_interruptible - (&the_port->state->port.delta_msr_wait); - } else if ((port->ip_notify & N_DDCD) - && !(shadow & SHADOW_DCD)) { - /* Flag delta DCD/no DCD */ - uart_handle_dcd_change(port->ip_port, - shadow & SHADOW_DCD); - port->ip_flags |= DCD_ON; - } - } - - /* Handle a CTS change */ - if (sio_ir & hooks->intr_delta_cts) { - ioc3_ack(is, idd, hooks->intr_delta_cts); - shadow = readl(&port->ip_serial_regs->shadow); - - if ((port->ip_notify & N_DCTS) && (port->ip_port)) { - the_port = port->ip_port; - uart_handle_cts_change(the_port, shadow - & SHADOW_CTS); - wake_up_interruptible - (&the_port->state->port.delta_msr_wait); - } - } - - /* rx timeout interrupt. Must be some data available. Put this - * before the check for rx_high since servicing this condition - * may cause that condition to clear. - */ - if (sio_ir & hooks->intr_rx_timer) { - ioc3_ack(is, idd, hooks->intr_rx_timer); - if ((port->ip_notify & N_DATA_READY) - && (port->ip_port)) { - receive_chars(port->ip_port); - } - } - - /* rx high interrupt. Must be after rx_timer. */ - else if (sio_ir & hooks->intr_rx_high) { - /* Data available, notify upper layer */ - if ((port->ip_notify & N_DATA_READY) && port->ip_port) { - receive_chars(port->ip_port); - } - - /* We can't ACK this interrupt. If receive_chars didn't - * cause the condition to clear, we'll have to disable - * the interrupt until the data is drained. - * If the read was aborted, don't disable the interrupt - * as this may cause us to hang indefinitely. An - * aborted read generally means that this interrupt - * hasn't been delivered to the cpu yet anyway, even - * though we see it as asserted when we read the sio_ir. - */ - if ((sio_ir = PENDING(card_ptr, idd)) - & hooks->intr_rx_high) { - if (port->ip_flags & READ_ABORTED) { - rx_high_rd_aborted++; - } - else { - card_ptr->ic_enable &= ~hooks->intr_rx_high; - port->ip_flags |= INPUT_HIGH; - } - } - } - - /* We got a low water interrupt: notify upper layer to - * send more data. Must come before tx_mt since servicing - * this condition may cause that condition to clear. - */ - if (sio_ir & hooks->intr_tx_explicit) { - port->ip_flags &= ~LOWAT_WRITTEN; - ioc3_ack(is, idd, hooks->intr_tx_explicit); - if (port->ip_notify & N_OUTPUT_LOWAT) - ioc3_cb_output_lowat(port); - } - - /* Handle tx_mt. Must come after tx_explicit. */ - else if (sio_ir & hooks->intr_tx_mt) { - /* If we are expecting a lowat notification - * and we get to this point it probably means that for - * some reason the tx_explicit didn't work as expected - * (that can legitimately happen if the output buffer is - * filled up in just the right way). - * So send the notification now. - */ - if (port->ip_notify & N_OUTPUT_LOWAT) { - ioc3_cb_output_lowat(port); - - /* We need to reload the sio_ir since the lowat - * call may have caused another write to occur, - * clearing the tx_mt condition. - */ - sio_ir = PENDING(card_ptr, idd); - } - - /* If the tx_mt condition still persists even after the - * lowat call, we've got some work to do. - */ - if (sio_ir & hooks->intr_tx_mt) { - /* If we are not currently expecting DMA input, - * and the transmitter has just gone idle, - * there is no longer any reason for DMA, so - * disable it. - */ - if (!(port->ip_notify - & (N_DATA_READY | N_DDCD))) { - BUG_ON(!(port->ip_sscr - & SSCR_DMA_EN)); - port->ip_sscr &= ~SSCR_DMA_EN; - writel(port->ip_sscr, - &port->ip_serial_regs->sscr); - } - /* Prevent infinite tx_mt interrupt */ - card_ptr->ic_enable &= ~hooks->intr_tx_mt; - } - } - sio_ir = PENDING(card_ptr, idd); - - /* if the read was aborted and only hooks->intr_rx_high, - * clear hooks->intr_rx_high, so we do not loop forever. - */ - - if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) { - sio_ir &= ~hooks->intr_rx_high; - } - } while (sio_ir & hooks->intr_all); - - spin_unlock_irqrestore(&port->ip_lock, flags); - ioc3_enable(is, idd, card_ptr->ic_enable); - return 0; -} - -/** - * ioc3uart_intr - field all serial interrupts - * @is : submodule - * @idd: driver data - * @pending: interrupts to handle - * - */ - -static int ioc3uart_intr(struct ioc3_submodule *is, - struct ioc3_driver_data *idd, - unsigned int pending) -{ - int ret = 0; - - /* - * The upper level interrupt handler sends interrupts for both ports - * here. So we need to call for each port with its interrupts. - */ - - if (pending & SIO_IR_SA) - ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA); - if (pending & SIO_IR_SB) - ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB); - - return ret; -} - -/** - * ic3_type - * @port: Port to operate with (we ignore since we only have one port) - * - */ -static const char *ic3_type(struct uart_port *the_port) -{ - if (IS_RS232(the_port->line)) - return "SGI IOC3 Serial [rs232]"; - else - return "SGI IOC3 Serial [rs422]"; -} - -/** - * ic3_tx_empty - Is the transmitter empty? - * @port: Port to operate on - * - */ -static unsigned int ic3_tx_empty(struct uart_port *the_port) -{ - unsigned int ret = 0; - struct ioc3_port *port = get_ioc3_port(the_port); - - if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT) - ret = TIOCSER_TEMT; - return ret; -} - -/** - * ic3_stop_tx - stop the transmitter - * @port: Port to operate on - * - */ -static void ic3_stop_tx(struct uart_port *the_port) -{ - struct ioc3_port *port = get_ioc3_port(the_port); - - if (port) - set_notification(port, N_OUTPUT_LOWAT, 0); -} - -/** - * ic3_stop_rx - stop the receiver - * @port: Port to operate on - * - */ -static void ic3_stop_rx(struct uart_port *the_port) -{ - struct ioc3_port *port = get_ioc3_port(the_port); - - if (port) - port->ip_flags &= ~INPUT_ENABLE; -} - -/** - * null_void_function - * @port: Port to operate on - * - */ -static void null_void_function(struct uart_port *the_port) -{ -} - -/** - * ic3_shutdown - shut down the port - free irq and disable - * @port: port to shut down - * - */ -static void ic3_shutdown(struct uart_port *the_port) -{ - unsigned long port_flags; - struct ioc3_port *port; - struct uart_state *state; - - port = get_ioc3_port(the_port); - if (!port) - return; - - state = the_port->state; - wake_up_interruptible(&state->port.delta_msr_wait); - - spin_lock_irqsave(&the_port->lock, port_flags); - set_notification(port, N_ALL, 0); - spin_unlock_irqrestore(&the_port->lock, port_flags); -} - -/** - * ic3_set_mctrl - set control lines (dtr, rts, etc) - * @port: Port to operate on - * @mctrl: Lines to set/unset - * - */ -static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl) -{ - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - set_mcr(the_port, mcr, SHADOW_DTR); -} - -/** - * ic3_get_mctrl - get control line info - * @port: port to operate on - * - */ -static unsigned int ic3_get_mctrl(struct uart_port *the_port) -{ - struct ioc3_port *port = get_ioc3_port(the_port); - uint32_t shadow; - unsigned int ret = 0; - - if (!port) - return 0; - - shadow = readl(&port->ip_serial_regs->shadow); - if (shadow & SHADOW_DCD) - ret |= TIOCM_CD; - if (shadow & SHADOW_DR) - ret |= TIOCM_DSR; - if (shadow & SHADOW_CTS) - ret |= TIOCM_CTS; - return ret; -} - -/** - * ic3_start_tx - Start transmitter. Called with the_port->lock - * @port: Port to operate on - * - */ -static void ic3_start_tx(struct uart_port *the_port) -{ - struct ioc3_port *port = get_ioc3_port(the_port); - - if (port) { - set_notification(port, N_OUTPUT_LOWAT, 1); - enable_intrs(port, port->ip_hooks->intr_tx_mt); - } -} - -/** - * ic3_break_ctl - handle breaks - * @port: Port to operate on - * @break_state: Break state - * - */ -static void ic3_break_ctl(struct uart_port *the_port, int break_state) -{ -} - -/** - * ic3_startup - Start up the serial port - always return 0 (We're always on) - * @port: Port to operate on - * - */ -static int ic3_startup(struct uart_port *the_port) -{ - int retval; - struct ioc3_port *port; - struct ioc3_card *card_ptr; - unsigned long port_flags; - - if (!the_port) { - NOT_PROGRESS(); - return -ENODEV; - } - port = get_ioc3_port(the_port); - if (!port) { - NOT_PROGRESS(); - return -ENODEV; - } - card_ptr = port->ip_card; - port->ip_port = the_port; - - if (!card_ptr) { - NOT_PROGRESS(); - return -ENODEV; - } - - /* Start up the serial port */ - spin_lock_irqsave(&the_port->lock, port_flags); - retval = ic3_startup_local(the_port); - spin_unlock_irqrestore(&the_port->lock, port_flags); - return retval; -} - -/** - * ic3_set_termios - set termios stuff - * @port: port to operate on - * @termios: New settings - * @termios: Old - * - */ -static void -ic3_set_termios(struct uart_port *the_port, - struct ktermios *termios, struct ktermios *old_termios) -{ - unsigned long port_flags; - - spin_lock_irqsave(&the_port->lock, port_flags); - ioc3_change_speed(the_port, termios, old_termios); - spin_unlock_irqrestore(&the_port->lock, port_flags); -} - -/** - * ic3_request_port - allocate resources for port - no op.... - * @port: port to operate on - * - */ -static int ic3_request_port(struct uart_port *port) -{ - return 0; -} - -/* Associate the uart functions above - given to serial core */ -static struct uart_ops ioc3_ops = { - .tx_empty = ic3_tx_empty, - .set_mctrl = ic3_set_mctrl, - .get_mctrl = ic3_get_mctrl, - .stop_tx = ic3_stop_tx, - .start_tx = ic3_start_tx, - .stop_rx = ic3_stop_rx, - .enable_ms = null_void_function, - .break_ctl = ic3_break_ctl, - .startup = ic3_startup, - .shutdown = ic3_shutdown, - .set_termios = ic3_set_termios, - .type = ic3_type, - .release_port = null_void_function, - .request_port = ic3_request_port, -}; - -/* - * Boot-time initialization code - */ - -static struct uart_driver ioc3_uart = { - .owner = THIS_MODULE, - .driver_name = "ioc3_serial", - .dev_name = DEVICE_NAME, - .major = DEVICE_MAJOR, - .minor = DEVICE_MINOR, - .nr = MAX_LOGICAL_PORTS -}; - -/** - * ioc3_serial_core_attach - register with serial core - * This is done during pci probing - * @is: submodule struct for this - * @idd: handle for this card - */ -static inline int ioc3_serial_core_attach( struct ioc3_submodule *is, - struct ioc3_driver_data *idd) -{ - struct ioc3_port *port; - struct uart_port *the_port; - struct ioc3_card *card_ptr = idd->data[is->id]; - int ii, phys_port; - struct pci_dev *pdev = idd->pdev; - - DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n", - __func__, pdev, (void *)card_ptr)); - - if (!card_ptr) - return -ENODEV; - - /* once around for each logical port on this card */ - for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) { - phys_port = GET_PHYSICAL_PORT(ii); - the_port = &card_ptr->ic_port[phys_port]. - icp_uart_port[GET_LOGICAL_PORT(ii)]; - port = card_ptr->ic_port[phys_port].icp_port; - port->ip_port = the_port; - - DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n", - __func__, (void *)the_port, (void *)port, - phys_port, ii)); - - /* membase, iobase and mapbase just need to be non-0 */ - the_port->membase = (unsigned char __iomem *)1; - the_port->iobase = (pdev->bus->number << 16) | ii; - the_port->line = (Num_of_ioc3_cards << 2) | ii; - the_port->mapbase = 1; - the_port->type = PORT_16550A; - the_port->fifosize = FIFO_SIZE; - the_port->ops = &ioc3_ops; - the_port->irq = idd->irq_io; - the_port->dev = &pdev->dev; - - if (uart_add_one_port(&ioc3_uart, the_port) < 0) { - printk(KERN_WARNING - "%s: unable to add port %d bus %d\n", - __func__, the_port->line, pdev->bus->number); - } else { - DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n", - the_port->line, the_port->irq, pdev->bus->number)); - } - - /* all ports are rs232 for now */ - if (IS_PHYSICAL_PORT(ii)) - ioc3_set_proto(port, PROTO_RS232); - } - return 0; -} - -/** - * ioc3uart_remove - register detach function - * @is: submodule struct for this submodule - * @idd: ioc3 driver data for this submodule - */ - -static int ioc3uart_remove(struct ioc3_submodule *is, - struct ioc3_driver_data *idd) -{ - struct ioc3_card *card_ptr = idd->data[is->id]; - struct uart_port *the_port; - struct ioc3_port *port; - int ii; - - if (card_ptr) { - for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) { - the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)]. - icp_uart_port[GET_LOGICAL_PORT(ii)]; - if (the_port) - uart_remove_one_port(&ioc3_uart, the_port); - port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port; - if (port && IS_PHYSICAL_PORT(ii) - && (GET_PHYSICAL_PORT(ii) == 0)) { - pci_free_consistent(port->ip_idd->pdev, - TOTAL_RING_BUF_SIZE, - (void *)port->ip_cpu_ringbuf, - port->ip_dma_ringbuf); - kfree(port); - card_ptr->ic_port[GET_PHYSICAL_PORT(ii)]. - icp_port = NULL; - } - } - kfree(card_ptr); - idd->data[is->id] = NULL; - } - return 0; -} - -/** - * ioc3uart_probe - card probe function called from shim driver - * @is: submodule struct for this submodule - * @idd: ioc3 driver data for this card - */ - -static int __devinit -ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) -{ - struct pci_dev *pdev = idd->pdev; - struct ioc3_card *card_ptr; - int ret = 0; - struct ioc3_port *port; - struct ioc3_port *ports[PORTS_PER_CARD]; - int phys_port; - int cnt; - - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd)); - - card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL); - if (!card_ptr) { - printk(KERN_WARNING "ioc3_attach_one" - ": unable to get memory for the IOC3\n"); - return -ENOMEM; - } - idd->data[is->id] = card_ptr; - Submodule_slot = is->id; - - writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) | - ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) | - (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr); - - pci_write_config_dword(pdev, PCI_LAT, 0xff00); - - /* Enable serial port mode select generic PIO pins as outputs */ - ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL); - - /* Create port structures for each port */ - for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) { - port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL); - if (!port) { - printk(KERN_WARNING - "IOC3 serial memory not available for port\n"); - ret = -ENOMEM; - goto out4; - } - spin_lock_init(&port->ip_lock); - - /* we need to remember the previous ones, to point back to - * them farther down - setting up the ring buffers. - */ - ports[phys_port] = port; - - /* init to something useful */ - card_ptr->ic_port[phys_port].icp_port = port; - port->ip_is = is; - port->ip_idd = idd; - port->ip_baud = 9600; - port->ip_card = card_ptr; - port->ip_hooks = &hooks_array[phys_port]; - - /* Setup each port */ - if (phys_port == 0) { - port->ip_serial_regs = &idd->vma->port_a; - port->ip_uart_regs = &idd->vma->sregs.uarta; - - DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p " - "ip_uart_regs 0x%p\n", - __func__, - (void *)port->ip_serial_regs, - (void *)port->ip_uart_regs)); - - /* setup ring buffers */ - port->ip_cpu_ringbuf = pci_alloc_consistent(pdev, - TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf); - - BUG_ON(!((((int64_t) port->ip_dma_ringbuf) & - (TOTAL_RING_BUF_SIZE - 1)) == 0)); - port->ip_inring = RING(port, RX_A); - port->ip_outring = RING(port, TX_A); - DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p " - "ip_dma_ringbuf 0x%p, ip_inring 0x%p " - "ip_outring 0x%p\n", - __func__, - (void *)port->ip_cpu_ringbuf, - (void *)port->ip_dma_ringbuf, - (void *)port->ip_inring, - (void *)port->ip_outring)); - } - else { - port->ip_serial_regs = &idd->vma->port_b; - port->ip_uart_regs = &idd->vma->sregs.uartb; - - DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p " - "ip_uart_regs 0x%p\n", - __func__, - (void *)port->ip_serial_regs, - (void *)port->ip_uart_regs)); - - /* share the ring buffers */ - port->ip_dma_ringbuf = - ports[phys_port - 1]->ip_dma_ringbuf; - port->ip_cpu_ringbuf = - ports[phys_port - 1]->ip_cpu_ringbuf; - port->ip_inring = RING(port, RX_B); - port->ip_outring = RING(port, TX_B); - DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p " - "ip_dma_ringbuf 0x%p, ip_inring 0x%p " - "ip_outring 0x%p\n", - __func__, - (void *)port->ip_cpu_ringbuf, - (void *)port->ip_dma_ringbuf, - (void *)port->ip_inring, - (void *)port->ip_outring)); - } - - DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p", - __func__, - phys_port, (void *)port, (void *)card_ptr)); - DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n", - (void *)port->ip_serial_regs, - (void *)port->ip_uart_regs)); - - /* Initialize the hardware for IOC3 */ - port_init(port); - - DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p " - "outring 0x%p\n", - __func__, - phys_port, (void *)port, - (void *)port->ip_inring, - (void *)port->ip_outring)); - - } - - /* register port with the serial core */ - - if ((ret = ioc3_serial_core_attach(is, idd))) - goto out4; - - Num_of_ioc3_cards++; - - return ret; - - /* error exits that give back resources */ -out4: - for (cnt = 0; cnt < phys_port; cnt++) - kfree(ports[cnt]); - - kfree(card_ptr); - return ret; -} - -static struct ioc3_submodule ioc3uart_ops = { - .name = "IOC3uart", - .probe = ioc3uart_probe, - .remove = ioc3uart_remove, - /* call .intr for both ports initially */ - .irq_mask = SIO_IR_SA | SIO_IR_SB, - .intr = ioc3uart_intr, - .owner = THIS_MODULE, -}; - -/** - * ioc3_detect - module init called, - */ -static int __init ioc3uart_init(void) -{ - int ret; - - /* register with serial core */ - if ((ret = uart_register_driver(&ioc3_uart)) < 0) { - printk(KERN_WARNING - "%s: Couldn't register IOC3 uart serial driver\n", - __func__); - return ret; - } - ret = ioc3_register_submodule(&ioc3uart_ops); - if (ret) - uart_unregister_driver(&ioc3_uart); - return ret; -} - -static void __exit ioc3uart_exit(void) -{ - ioc3_unregister_submodule(&ioc3uart_ops); - uart_unregister_driver(&ioc3_uart); -} - -module_init(ioc3uart_init); -module_exit(ioc3uart_exit); - -MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); -MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c deleted file mode 100644 index fcfe82653ac8..000000000000 --- a/drivers/serial/ioc4_serial.c +++ /dev/null @@ -1,2953 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. - */ - - -/* - * This file contains a module version of the ioc4 serial driver. This - * includes all the support functions needed (support functions, etc.) - * and the serial driver itself. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * interesting things about the ioc4 - */ - -#define IOC4_NUM_SERIAL_PORTS 4 /* max ports per card */ -#define IOC4_NUM_CARDS 8 /* max cards per partition */ - -#define GET_SIO_IR(_n) (_n == 0) ? (IOC4_SIO_IR_S0) : \ - (_n == 1) ? (IOC4_SIO_IR_S1) : \ - (_n == 2) ? (IOC4_SIO_IR_S2) : \ - (IOC4_SIO_IR_S3) - -#define GET_OTHER_IR(_n) (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \ - (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \ - (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \ - (IOC4_OTHER_IR_S3_MEMERR) - - -/* - * All IOC4 registers are 32 bits wide. - */ - -/* - * PCI Memory Space Map - */ -#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */ -#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0) -#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1) -#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK (0xe << 1) -#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK (0x1 << 1) -#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5) -#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6) - -/* Interrupt types */ -#define IOC4_SIO_INTR_TYPE 0 -#define IOC4_OTHER_INTR_TYPE 1 -#define IOC4_NUM_INTR_TYPES 2 - -/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */ -#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */ -#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */ -#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */ -#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */ -#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */ -#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */ -#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */ -#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */ -#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */ -#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */ -#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */ -#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */ -#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */ -#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */ -#define IOC4_SIO_IR_S1_INT 0x00004000 /* */ -#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */ -#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */ -#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */ -#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */ -#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */ -#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */ -#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */ -#define IOC4_SIO_IR_S2_INT 0x00400000 /* */ -#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */ -#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */ -#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */ -#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */ -#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */ -#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */ -#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */ -#define IOC4_SIO_IR_S3_INT 0x40000000 /* */ -#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* */ - -/* Per device interrupt masks */ -#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \ - IOC4_SIO_IR_S0_RX_FULL | \ - IOC4_SIO_IR_S0_RX_HIGH | \ - IOC4_SIO_IR_S0_RX_TIMER | \ - IOC4_SIO_IR_S0_DELTA_DCD | \ - IOC4_SIO_IR_S0_DELTA_CTS | \ - IOC4_SIO_IR_S0_INT | \ - IOC4_SIO_IR_S0_TX_EXPLICIT) -#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \ - IOC4_SIO_IR_S1_RX_FULL | \ - IOC4_SIO_IR_S1_RX_HIGH | \ - IOC4_SIO_IR_S1_RX_TIMER | \ - IOC4_SIO_IR_S1_DELTA_DCD | \ - IOC4_SIO_IR_S1_DELTA_CTS | \ - IOC4_SIO_IR_S1_INT | \ - IOC4_SIO_IR_S1_TX_EXPLICIT) -#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \ - IOC4_SIO_IR_S2_RX_FULL | \ - IOC4_SIO_IR_S2_RX_HIGH | \ - IOC4_SIO_IR_S2_RX_TIMER | \ - IOC4_SIO_IR_S2_DELTA_DCD | \ - IOC4_SIO_IR_S2_DELTA_CTS | \ - IOC4_SIO_IR_S2_INT | \ - IOC4_SIO_IR_S2_TX_EXPLICIT) -#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \ - IOC4_SIO_IR_S3_RX_FULL | \ - IOC4_SIO_IR_S3_RX_HIGH | \ - IOC4_SIO_IR_S3_RX_TIMER | \ - IOC4_SIO_IR_S3_DELTA_DCD | \ - IOC4_SIO_IR_S3_DELTA_CTS | \ - IOC4_SIO_IR_S3_INT | \ - IOC4_SIO_IR_S3_TX_EXPLICIT) - -/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ -#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ -#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ -#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ -#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ -#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ -#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ -#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */ -#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */ -#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */ -#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */ - -#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \ - IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR) - -/* Bitmasks for IOC4_SIO_CR */ -#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */ -#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000 -#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010 -#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020 -#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030 -#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040 -#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050 -#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060 -#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070 -#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among - serial ports (ro) */ -/* Defs for some of the generic I/O pins */ -#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0 - mode sel */ -#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1 - mode sel */ -#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2 - mode sel */ -#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3 - mode sel */ - -#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling - uart 0 mode select */ -#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling - uart 1 mode select */ -#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling - uart 2 mode select */ -#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling - uart 3 mode select */ - -/* Bitmasks for serial RX status byte */ -#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */ -#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */ -#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */ -#define IOC4_RXSB_BREAK 0x08 /* Break character */ -#define IOC4_RXSB_CTS 0x10 /* State of CTS */ -#define IOC4_RXSB_DCD 0x20 /* State of DCD */ -#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */ -#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR - * & BREAK valid */ - -/* Bitmasks for serial TX control byte */ -#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */ -#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */ -#define IOC4_TXCB_VALID 0x40 /* Byte is valid */ -#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control reg */ -#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec */ - -/* Bitmasks for IOC4_SBBR_L */ -#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ - -/* Bitmasks for IOC4_SSCR_<3:0> */ -#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */ -#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ -#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */ -#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */ -#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */ -#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */ -#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */ -#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */ -#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */ -#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */ -#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels */ - -/* All producer/comsumer pointers are the same bitfield */ -#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */ -#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */ -#define IOC4_PROD_CONS_PTR_OFF 3 - -/* Bitmasks for IOC4_SRCIR_<3:0> */ -#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer */ - -/* Bitmasks for IOC4_SHADOW_<3:0> */ -#define IOC4_SHADOW_DR 0x00000001 /* Data ready */ -#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */ -#define IOC4_SHADOW_PE 0x00000004 /* Parity error */ -#define IOC4_SHADOW_FE 0x00000008 /* Framing error */ -#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */ -#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */ -#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */ -#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */ -#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */ -#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */ -#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */ -#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */ -#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */ -#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */ -#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ -#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ -#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled */ - -/* Bitmasks for IOC4_SRTR_<3:0> */ -#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */ -#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */ -#define IOC4_SRTR_CNT_VAL_SHIFT 16 -#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency */ - -/* Serial port register map used for DMA and PIO serial I/O */ -struct ioc4_serialregs { - uint32_t sscr; - uint32_t stpir; - uint32_t stcir; - uint32_t srpir; - uint32_t srcir; - uint32_t srtr; - uint32_t shadow; -}; - -/* IOC4 UART register map */ -struct ioc4_uartregs { - char i4u_lcr; - union { - char iir; /* read only */ - char fcr; /* write only */ - } u3; - union { - char ier; /* DLAB == 0 */ - char dlm; /* DLAB == 1 */ - } u2; - union { - char rbr; /* read only, DLAB == 0 */ - char thr; /* write only, DLAB == 0 */ - char dll; /* DLAB == 1 */ - } u1; - char i4u_scr; - char i4u_msr; - char i4u_lsr; - char i4u_mcr; -}; - -/* short names */ -#define i4u_dll u1.dll -#define i4u_ier u2.ier -#define i4u_dlm u2.dlm -#define i4u_fcr u3.fcr - -/* Serial port registers used for DMA serial I/O */ -struct ioc4_serial { - uint32_t sbbr01_l; - uint32_t sbbr01_h; - uint32_t sbbr23_l; - uint32_t sbbr23_h; - - struct ioc4_serialregs port_0; - struct ioc4_serialregs port_1; - struct ioc4_serialregs port_2; - struct ioc4_serialregs port_3; - struct ioc4_uartregs uart_0; - struct ioc4_uartregs uart_1; - struct ioc4_uartregs uart_2; - struct ioc4_uartregs uart_3; -} ioc4_serial; - -/* UART clock speed */ -#define IOC4_SER_XIN_CLK_66 66666667 -#define IOC4_SER_XIN_CLK_33 33333333 - -#define IOC4_W_IES 0 -#define IOC4_W_IEC 1 - -typedef void ioc4_intr_func_f(void *, uint32_t); -typedef ioc4_intr_func_f *ioc4_intr_func_t; - -static unsigned int Num_of_ioc4_cards; - -/* defining this will get you LOTS of great debug info */ -//#define DEBUG_INTERRUPTS -#define DPRINT_CONFIG(_x...) ; -//#define DPRINT_CONFIG(_x...) printk _x - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* number of characters we want to transmit to the lower level at a time */ -#define IOC4_MAX_CHARS 256 -#define IOC4_FIFO_CHARS 255 - -/* Device name we're using */ -#define DEVICE_NAME_RS232 "ttyIOC" -#define DEVICE_NAME_RS422 "ttyAIOC" -#define DEVICE_MAJOR 204 -#define DEVICE_MINOR_RS232 50 -#define DEVICE_MINOR_RS422 84 - - -/* register offsets */ -#define IOC4_SERIAL_OFFSET 0x300 - -/* flags for next_char_state */ -#define NCS_BREAK 0x1 -#define NCS_PARITY 0x2 -#define NCS_FRAMING 0x4 -#define NCS_OVERRUN 0x8 - -/* cause we need SOME parameters ... */ -#define MIN_BAUD_SUPPORTED 1200 -#define MAX_BAUD_SUPPORTED 115200 - -/* protocol types supported */ -#define PROTO_RS232 3 -#define PROTO_RS422 7 - -/* Notification types */ -#define N_DATA_READY 0x01 -#define N_OUTPUT_LOWAT 0x02 -#define N_BREAK 0x04 -#define N_PARITY_ERROR 0x08 -#define N_FRAMING_ERROR 0x10 -#define N_OVERRUN_ERROR 0x20 -#define N_DDCD 0x40 -#define N_DCTS 0x80 - -#define N_ALL_INPUT (N_DATA_READY | N_BREAK | \ - N_PARITY_ERROR | N_FRAMING_ERROR | \ - N_OVERRUN_ERROR | N_DDCD | N_DCTS) - -#define N_ALL_OUTPUT N_OUTPUT_LOWAT - -#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR) - -#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK | \ - N_PARITY_ERROR | N_FRAMING_ERROR | \ - N_OVERRUN_ERROR | N_DDCD | N_DCTS) - -#define SER_DIVISOR(_x, clk) (((clk) + (_x) * 8) / ((_x) * 16)) -#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div)) - -/* Some masks */ -#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \ - | UART_LCR_WLEN7 | UART_LCR_WLEN8) -#define LCR_MASK_STOP_BITS (UART_LCR_STOP) - -#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb) -#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw) - -/* Default to 4k buffers */ -#ifdef IOC4_1K_BUFFERS -#define RING_BUF_SIZE 1024 -#define IOC4_BUF_SIZE_BIT 0 -#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K -#else -#define RING_BUF_SIZE 4096 -#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE -#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K -#endif - -#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4) - -/* - * This is the entry saved by the driver - one per card - */ - -#define UART_PORT_MIN 0 -#define UART_PORT_RS232 UART_PORT_MIN -#define UART_PORT_RS422 1 -#define UART_PORT_COUNT 2 /* one for each mode */ - -struct ioc4_control { - int ic_irq; - struct { - /* uart ports are allocated here - 1 for rs232, 1 for rs422 */ - struct uart_port icp_uart_port[UART_PORT_COUNT]; - /* Handy reference material */ - struct ioc4_port *icp_port; - } ic_port[IOC4_NUM_SERIAL_PORTS]; - struct ioc4_soft *ic_soft; -}; - -/* - * per-IOC4 data structure - */ -#define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t)) -struct ioc4_soft { - struct ioc4_misc_regs __iomem *is_ioc4_misc_addr; - struct ioc4_serial __iomem *is_ioc4_serial_addr; - - /* Each interrupt type has an entry in the array */ - struct ioc4_intr_type { - - /* - * Each in-use entry in this array contains at least - * one nonzero bit in sd_bits; no two entries in this - * array have overlapping sd_bits values. - */ - struct ioc4_intr_info { - uint32_t sd_bits; - ioc4_intr_func_f *sd_intr; - void *sd_info; - } is_intr_info[MAX_IOC4_INTR_ENTS]; - - /* Number of entries active in the above array */ - atomic_t is_num_intrs; - } is_intr_type[IOC4_NUM_INTR_TYPES]; - - /* is_ir_lock must be held while - * modifying sio_ie values, so - * we can be sure that sio_ie is - * not changing when we read it - * along with sio_ir. - */ - spinlock_t is_ir_lock; /* SIO_IE[SC] mod lock */ -}; - -/* Local port info for each IOC4 serial ports */ -struct ioc4_port { - struct uart_port *ip_port; /* current active port ptr */ - /* Ptrs for all ports */ - struct uart_port *ip_all_ports[UART_PORT_COUNT]; - /* Back ptrs for this port */ - struct ioc4_control *ip_control; - struct pci_dev *ip_pdev; - struct ioc4_soft *ip_ioc4_soft; - - /* pci mem addresses */ - struct ioc4_misc_regs __iomem *ip_mem; - struct ioc4_serial __iomem *ip_serial; - struct ioc4_serialregs __iomem *ip_serial_regs; - struct ioc4_uartregs __iomem *ip_uart_regs; - - /* Ring buffer page for this port */ - dma_addr_t ip_dma_ringbuf; - /* vaddr of ring buffer */ - struct ring_buffer *ip_cpu_ringbuf; - - /* Rings for this port */ - struct ring *ip_inring; - struct ring *ip_outring; - - /* Hook to port specific values */ - struct hooks *ip_hooks; - - spinlock_t ip_lock; - - /* Various rx/tx parameters */ - int ip_baud; - int ip_tx_lowat; - int ip_rx_timeout; - - /* Copy of notification bits */ - int ip_notify; - - /* Shadow copies of various registers so we don't need to PIO - * read them constantly - */ - uint32_t ip_ienb; /* Enabled interrupts */ - uint32_t ip_sscr; - uint32_t ip_tx_prod; - uint32_t ip_rx_cons; - int ip_pci_bus_speed; - unsigned char ip_flags; -}; - -/* tx low water mark. We need to notify the driver whenever tx is getting - * close to empty so it can refill the tx buffer and keep things going. - * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll - * have no trouble getting in more chars in time (I certainly hope so). - */ -#define TX_LOWAT_LATENCY 1000 -#define TX_LOWAT_HZ (1000000 / TX_LOWAT_LATENCY) -#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ) - -/* Flags per port */ -#define INPUT_HIGH 0x01 -#define DCD_ON 0x02 -#define LOWAT_WRITTEN 0x04 -#define READ_ABORTED 0x08 -#define PORT_ACTIVE 0x10 -#define PORT_INACTIVE 0 /* This is the value when "off" */ - - -/* Since each port has different register offsets and bitmasks - * for everything, we'll store those that we need in tables so we - * don't have to be constantly checking the port we are dealing with. - */ -struct hooks { - uint32_t intr_delta_dcd; - uint32_t intr_delta_cts; - uint32_t intr_tx_mt; - uint32_t intr_rx_timer; - uint32_t intr_rx_high; - uint32_t intr_tx_explicit; - uint32_t intr_dma_error; - uint32_t intr_clear; - uint32_t intr_all; - int rs422_select_pin; -}; - -static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = { - /* Values for port 0 */ - { - IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS, - IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER, - IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT, - IOC4_OTHER_IR_S0_MEMERR, - (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL | - IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER | - IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS | - IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT), - IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN, - }, - - /* Values for port 1 */ - { - IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS, - IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER, - IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT, - IOC4_OTHER_IR_S1_MEMERR, - (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL | - IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER | - IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS | - IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT), - IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN, - }, - - /* Values for port 2 */ - { - IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS, - IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER, - IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT, - IOC4_OTHER_IR_S2_MEMERR, - (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL | - IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER | - IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS | - IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT), - IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN, - }, - - /* Values for port 3 */ - { - IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS, - IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER, - IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT, - IOC4_OTHER_IR_S3_MEMERR, - (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL | - IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER | - IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS | - IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT), - IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN, - } -}; - -/* A ring buffer entry */ -struct ring_entry { - union { - struct { - uint32_t alldata; - uint32_t allsc; - } all; - struct { - char data[4]; /* data bytes */ - char sc[4]; /* status/control */ - } s; - } u; -}; - -/* Test the valid bits in any of the 4 sc chars using "allsc" member */ -#define RING_ANY_VALID \ - ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101) - -#define ring_sc u.s.sc -#define ring_data u.s.data -#define ring_allsc u.all.allsc - -/* Number of entries per ring buffer. */ -#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry)) - -/* An individual ring */ -struct ring { - struct ring_entry entries[ENTRIES_PER_RING]; -}; - -/* The whole enchilada */ -struct ring_buffer { - struct ring TX_0_OR_2; - struct ring RX_0_OR_2; - struct ring TX_1_OR_3; - struct ring RX_1_OR_3; -}; - -/* Get a ring from a port struct */ -#define RING(_p, _wh) &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh) - -/* Infinite loop detection. - */ -#define MAXITER 10000000 - -/* Prototypes */ -static void receive_chars(struct uart_port *); -static void handle_intr(void *arg, uint32_t sio_ir); - -/* - * port_is_active - determines if this port is currently active - * @port: ptr to soft struct for this port - * @uart_port: uart port to test for - */ -static inline int port_is_active(struct ioc4_port *port, - struct uart_port *uart_port) -{ - if (port) { - if ((port->ip_flags & PORT_ACTIVE) - && (port->ip_port == uart_port)) - return 1; - } - return 0; -} - - -/** - * write_ireg - write the interrupt regs - * @ioc4_soft: ptr to soft struct for this port - * @val: value to write - * @which: which register - * @type: which ireg set - */ -static inline void -write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) -{ - struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr; - unsigned long flags; - - spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags); - - switch (type) { - case IOC4_SIO_INTR_TYPE: - switch (which) { - case IOC4_W_IES: - writel(val, &mem->sio_ies.raw); - break; - - case IOC4_W_IEC: - writel(val, &mem->sio_iec.raw); - break; - } - break; - - case IOC4_OTHER_INTR_TYPE: - switch (which) { - case IOC4_W_IES: - writel(val, &mem->other_ies.raw); - break; - - case IOC4_W_IEC: - writel(val, &mem->other_iec.raw); - break; - } - break; - - default: - break; - } - spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags); -} - -/** - * set_baud - Baud rate setting code - * @port: port to set - * @baud: baud rate to use - */ -static int set_baud(struct ioc4_port *port, int baud) -{ - int actual_baud; - int diff; - int lcr; - unsigned short divisor; - struct ioc4_uartregs __iomem *uart; - - divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed); - if (!divisor) - return 1; - actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed); - - diff = actual_baud - baud; - if (diff < 0) - diff = -diff; - - /* If we're within 1%, we've found a match */ - if (diff * 100 > actual_baud) - return 1; - - uart = port->ip_uart_regs; - lcr = readb(&uart->i4u_lcr); - writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr); - writeb((unsigned char)divisor, &uart->i4u_dll); - writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm); - writeb(lcr, &uart->i4u_lcr); - return 0; -} - - -/** - * get_ioc4_port - given a uart port, return the control structure - * @port: uart port - * @set: set this port as current - */ -static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set) -{ - struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev); - struct ioc4_control *control = idd->idd_serial_data; - struct ioc4_port *port; - int port_num, port_type; - - if (control) { - for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; - port_num++ ) { - port = control->ic_port[port_num].icp_port; - if (!port) - continue; - for (port_type = UART_PORT_MIN; - port_type < UART_PORT_COUNT; - port_type++) { - if (the_port == port->ip_all_ports - [port_type]) { - /* set local copy */ - if (set) { - port->ip_port = the_port; - } - return port; - } - } - } - } - return NULL; -} - -/* The IOC4 hardware provides no atomic way to determine if interrupts - * are pending since two reads are required to do so. The handler must - * read the SIO_IR and the SIO_IES, and take the logical and of the - * two. When this value is zero, all interrupts have been serviced and - * the handler may return. - * - * This has the unfortunate "hole" that, if some other CPU or - * some other thread or some higher level interrupt manages to - * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may - * think we have observed SIO_IR&SIO_IE==0 when in fact this - * condition never really occurred. - * - * To solve this, we use a simple spinlock that must be held - * whenever modifying SIO_IE; holding this lock while observing - * both SIO_IR and SIO_IE guarantees that we do not falsely - * conclude that no enabled interrupts are pending. - */ - -static inline uint32_t -pending_intrs(struct ioc4_soft *soft, int type) -{ - struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; - unsigned long flag; - uint32_t intrs = 0; - - BUG_ON(!((type == IOC4_SIO_INTR_TYPE) - || (type == IOC4_OTHER_INTR_TYPE))); - - spin_lock_irqsave(&soft->is_ir_lock, flag); - - switch (type) { - case IOC4_SIO_INTR_TYPE: - intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw); - break; - - case IOC4_OTHER_INTR_TYPE: - intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw); - - /* Don't process any ATA interrupte */ - intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); - break; - - default: - break; - } - spin_unlock_irqrestore(&soft->is_ir_lock, flag); - return intrs; -} - -/** - * port_init - Initialize the sio and ioc4 hardware for a given port - * called per port from attach... - * @port: port to initialize - */ -static int inline port_init(struct ioc4_port *port) -{ - uint32_t sio_cr; - struct hooks *hooks = port->ip_hooks; - struct ioc4_uartregs __iomem *uart; - - /* Idle the IOC4 serial interface */ - writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr); - - /* Wait until any pending bus activity for this port has ceased */ - do - sio_cr = readl(&port->ip_mem->sio_cr.raw); - while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE)); - - /* Finish reset sequence */ - writel(0, &port->ip_serial_regs->sscr); - - /* Once RESET is done, reload cached tx_prod and rx_cons values - * and set rings to empty by making prod == cons - */ - port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; - writel(port->ip_tx_prod, &port->ip_serial_regs->stpir); - port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; - writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); - - /* Disable interrupts for this 16550 */ - uart = port->ip_uart_regs; - writeb(0, &uart->i4u_lcr); - writeb(0, &uart->i4u_ier); - - /* Set the default baud */ - set_baud(port, port->ip_baud); - - /* Set line control to 8 bits no parity */ - writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr); - /* UART_LCR_STOP == 1 stop */ - - /* Enable the FIFOs */ - writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr); - /* then reset 16550 FIFOs */ - writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - &uart->i4u_fcr); - - /* Clear modem control register */ - writeb(0, &uart->i4u_mcr); - - /* Clear deltas in modem status register */ - readb(&uart->i4u_msr); - - /* Only do this once per port pair */ - if (port->ip_hooks == &hooks_array[0] - || port->ip_hooks == &hooks_array[2]) { - unsigned long ring_pci_addr; - uint32_t __iomem *sbbr_l; - uint32_t __iomem *sbbr_h; - - if (port->ip_hooks == &hooks_array[0]) { - sbbr_l = &port->ip_serial->sbbr01_l; - sbbr_h = &port->ip_serial->sbbr01_h; - } else { - sbbr_l = &port->ip_serial->sbbr23_l; - sbbr_h = &port->ip_serial->sbbr23_h; - } - - ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; - DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n", - __func__, ring_pci_addr)); - - writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h); - writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l); - } - - /* Set the receive timeout value to 10 msec */ - writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr); - - /* Set rx threshold, enable DMA */ - /* Set high water mark at 3/4 of full ring */ - port->ip_sscr = (ENTRIES_PER_RING * 3 / 4); - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - - /* Disable and clear all serial related interrupt bits */ - write_ireg(port->ip_ioc4_soft, hooks->intr_clear, - IOC4_W_IEC, IOC4_SIO_INTR_TYPE); - port->ip_ienb &= ~hooks->intr_clear; - writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw); - return 0; -} - -/** - * handle_dma_error_intr - service any pending DMA error interrupts for the - * given port - 2nd level called via sd_intr - * @arg: handler arg - * @other_ir: ioc4regs - */ -static void handle_dma_error_intr(void *arg, uint32_t other_ir) -{ - struct ioc4_port *port = (struct ioc4_port *)arg; - struct hooks *hooks = port->ip_hooks; - unsigned long flags; - - spin_lock_irqsave(&port->ip_lock, flags); - - /* ACK the interrupt */ - writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw); - - if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) { - printk(KERN_ERR - "PCI error address is 0x%llx, " - "master is serial port %c %s\n", - (((uint64_t)readl(&port->ip_mem->pci_err_addr_h) - << 32) - | readl(&port->ip_mem->pci_err_addr_l.raw)) - & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' + - ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) & - IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1), - (readl(&port->ip_mem->pci_err_addr_l.raw) - & IOC4_PCI_ERR_ADDR_MST_TYP_MSK) - ? "RX" : "TX"); - - if (readl(&port->ip_mem->pci_err_addr_l.raw) - & IOC4_PCI_ERR_ADDR_MUL_ERR) { - printk(KERN_ERR - "Multiple errors occurred\n"); - } - } - spin_unlock_irqrestore(&port->ip_lock, flags); - - /* Re-enable DMA error interrupts */ - write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES, - IOC4_OTHER_INTR_TYPE); -} - -/** - * intr_connect - interrupt connect function - * @soft: soft struct for this card - * @type: interrupt type - * @intrbits: bit pattern to set - * @intr: handler function - * @info: handler arg - */ -static void -intr_connect(struct ioc4_soft *soft, int type, - uint32_t intrbits, ioc4_intr_func_f * intr, void *info) -{ - int i; - struct ioc4_intr_info *intr_ptr; - - BUG_ON(!((type == IOC4_SIO_INTR_TYPE) - || (type == IOC4_OTHER_INTR_TYPE))); - - i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1; - BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0))); - - /* Save off the lower level interrupt handler */ - intr_ptr = &soft->is_intr_type[type].is_intr_info[i]; - intr_ptr->sd_bits = intrbits; - intr_ptr->sd_intr = intr; - intr_ptr->sd_info = info; -} - -/** - * ioc4_intr - Top level IOC4 interrupt handler. - * @irq: irq value - * @arg: handler arg - */ - -static irqreturn_t ioc4_intr(int irq, void *arg) -{ - struct ioc4_soft *soft; - uint32_t this_ir, this_mir; - int xx, num_intrs = 0; - int intr_type; - int handled = 0; - struct ioc4_intr_info *intr_info; - - soft = arg; - for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) { - num_intrs = (int)atomic_read( - &soft->is_intr_type[intr_type].is_num_intrs); - - this_mir = this_ir = pending_intrs(soft, intr_type); - - /* Farm out the interrupt to the various drivers depending on - * which interrupt bits are set. - */ - for (xx = 0; xx < num_intrs; xx++) { - intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx]; - if ((this_mir = this_ir & intr_info->sd_bits)) { - /* Disable owned interrupts, call handler */ - handled++; - write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC, - intr_type); - intr_info->sd_intr(intr_info->sd_info, this_mir); - this_ir &= ~this_mir; - } - } - } -#ifdef DEBUG_INTERRUPTS - { - struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; - unsigned long flag; - - spin_lock_irqsave(&soft->is_ir_lock, flag); - printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x " - "other_ir 0x%x other_ies 0x%x mask 0x%x\n", - __func__, __LINE__, - (void *)mem, readl(&mem->sio_ir.raw), - readl(&mem->sio_ies.raw), - readl(&mem->other_ir.raw), - readl(&mem->other_ies.raw), - IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); - spin_unlock_irqrestore(&soft->is_ir_lock, flag); - } -#endif - return handled ? IRQ_HANDLED : IRQ_NONE; -} - -/** - * ioc4_attach_local - Device initialization. - * Called at *_attach() time for each - * IOC4 with serial ports in the system. - * @idd: Master module data for this IOC4 - */ -static int inline ioc4_attach_local(struct ioc4_driver_data *idd) -{ - struct ioc4_port *port; - struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS]; - int port_number; - uint16_t ioc4_revid_min = 62; - uint16_t ioc4_revid; - struct pci_dev *pdev = idd->idd_pdev; - struct ioc4_control* control = idd->idd_serial_data; - struct ioc4_soft *soft = control->ic_soft; - void __iomem *ioc4_misc = idd->idd_misc_regs; - void __iomem *ioc4_serial = soft->is_ioc4_serial_addr; - - /* IOC4 firmware must be at least rev 62 */ - pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid); - - printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid); - if (ioc4_revid < ioc4_revid_min) { - printk(KERN_WARNING - "IOC4 serial not supported on firmware rev %d, " - "please upgrade to rev %d or higher\n", - ioc4_revid, ioc4_revid_min); - return -EPERM; - } - BUG_ON(ioc4_misc == NULL); - BUG_ON(ioc4_serial == NULL); - - /* Create port structures for each port */ - for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS; - port_number++) { - port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL); - if (!port) { - printk(KERN_WARNING - "IOC4 serial memory not available for port\n"); - return -ENOMEM; - } - spin_lock_init(&port->ip_lock); - - /* we need to remember the previous ones, to point back to - * them farther down - setting up the ring buffers. - */ - ports[port_number] = port; - - /* Allocate buffers and jumpstart the hardware. */ - control->ic_port[port_number].icp_port = port; - port->ip_ioc4_soft = soft; - port->ip_pdev = pdev; - port->ip_ienb = 0; - /* Use baud rate calculations based on detected PCI - * bus speed. Simply test whether the PCI clock is - * running closer to 66MHz or 33MHz. - */ - if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) { - port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66; - } else { - port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33; - } - port->ip_baud = 9600; - port->ip_control = control; - port->ip_mem = ioc4_misc; - port->ip_serial = ioc4_serial; - - /* point to the right hook */ - port->ip_hooks = &hooks_array[port_number]; - - /* Get direct hooks to the serial regs and uart regs - * for this port - */ - switch (port_number) { - case 0: - port->ip_serial_regs = &(port->ip_serial->port_0); - port->ip_uart_regs = &(port->ip_serial->uart_0); - break; - case 1: - port->ip_serial_regs = &(port->ip_serial->port_1); - port->ip_uart_regs = &(port->ip_serial->uart_1); - break; - case 2: - port->ip_serial_regs = &(port->ip_serial->port_2); - port->ip_uart_regs = &(port->ip_serial->uart_2); - break; - default: - case 3: - port->ip_serial_regs = &(port->ip_serial->port_3); - port->ip_uart_regs = &(port->ip_serial->uart_3); - break; - } - - /* ring buffers are 1 to a pair of ports */ - if (port_number && (port_number & 1)) { - /* odd use the evens buffer */ - port->ip_dma_ringbuf = - ports[port_number - 1]->ip_dma_ringbuf; - port->ip_cpu_ringbuf = - ports[port_number - 1]->ip_cpu_ringbuf; - port->ip_inring = RING(port, RX_1_OR_3); - port->ip_outring = RING(port, TX_1_OR_3); - - } else { - if (port->ip_dma_ringbuf == 0) { - port->ip_cpu_ringbuf = pci_alloc_consistent - (pdev, TOTAL_RING_BUF_SIZE, - &port->ip_dma_ringbuf); - - } - BUG_ON(!((((int64_t)port->ip_dma_ringbuf) & - (TOTAL_RING_BUF_SIZE - 1)) == 0)); - DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p " - "ip_dma_ringbuf 0x%p\n", - __func__, - (void *)port->ip_cpu_ringbuf, - (void *)port->ip_dma_ringbuf)); - port->ip_inring = RING(port, RX_0_OR_2); - port->ip_outring = RING(port, TX_0_OR_2); - } - DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p", - __func__, - port_number, (void *)port, (void *)control)); - DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n", - (void *)port->ip_serial_regs, - (void *)port->ip_uart_regs)); - - /* Initialize the hardware for IOC4 */ - port_init(port); - - DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p " - "outring 0x%p\n", - __func__, - port_number, (void *)port, - (void *)port->ip_inring, - (void *)port->ip_outring)); - - /* Attach interrupt handlers */ - intr_connect(soft, IOC4_SIO_INTR_TYPE, - GET_SIO_IR(port_number), - handle_intr, port); - - intr_connect(soft, IOC4_OTHER_INTR_TYPE, - GET_OTHER_IR(port_number), - handle_dma_error_intr, port); - } - return 0; -} - -/** - * enable_intrs - enable interrupts - * @port: port to enable - * @mask: mask to use - */ -static void enable_intrs(struct ioc4_port *port, uint32_t mask) -{ - struct hooks *hooks = port->ip_hooks; - - if ((port->ip_ienb & mask) != mask) { - write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES, - IOC4_SIO_INTR_TYPE); - port->ip_ienb |= mask; - } - - if (port->ip_ienb) - write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, - IOC4_W_IES, IOC4_OTHER_INTR_TYPE); -} - -/** - * local_open - local open a port - * @port: port to open - */ -static inline int local_open(struct ioc4_port *port) -{ - int spiniter = 0; - - port->ip_flags = PORT_ACTIVE; - - /* Pause the DMA interface if necessary */ - if (port->ip_sscr & IOC4_SSCR_DMA_EN) { - writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE, - &port->ip_serial_regs->sscr); - while((readl(&port->ip_serial_regs-> sscr) - & IOC4_SSCR_PAUSE_STATE) == 0) { - spiniter++; - if (spiniter > MAXITER) { - port->ip_flags = PORT_INACTIVE; - return -1; - } - } - } - - /* Reset the input fifo. If the uart received chars while the port - * was closed and DMA is not enabled, the uart may have a bunch of - * chars hanging around in its rx fifo which will not be discarded - * by rclr in the upper layer. We must get rid of them here. - */ - writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR, - &port->ip_uart_regs->i4u_fcr); - - writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr); - /* UART_LCR_STOP == 1 stop */ - - /* Re-enable DMA, set default threshold to intr whenever there is - * data available. - */ - port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD; - port->ip_sscr |= 1; /* default threshold */ - - /* Plug in the new sscr. This implicitly clears the DMA_PAUSE - * flag if it was set above - */ - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - port->ip_tx_lowat = 1; - return 0; -} - -/** - * set_rx_timeout - Set rx timeout and threshold values. - * @port: port to use - * @timeout: timeout value in ticks - */ -static inline int set_rx_timeout(struct ioc4_port *port, int timeout) -{ - int threshold; - - port->ip_rx_timeout = timeout; - - /* Timeout is in ticks. Let's figure out how many chars we - * can receive at the current baud rate in that interval - * and set the rx threshold to that amount. There are 4 chars - * per ring entry, so we'll divide the number of chars that will - * arrive in timeout by 4. - * So .... timeout * baud / 10 / HZ / 4, with HZ = 100. - */ - threshold = timeout * port->ip_baud / 4000; - if (threshold == 0) - threshold = 1; /* otherwise we'll intr all the time! */ - - if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD) - return 1; - - port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD; - port->ip_sscr |= threshold; - - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - - /* Now set the rx timeout to the given value - * again timeout * IOC4_SRTR_HZ / HZ - */ - timeout = timeout * IOC4_SRTR_HZ / 100; - if (timeout > IOC4_SRTR_CNT) - timeout = IOC4_SRTR_CNT; - - writel(timeout, &port->ip_serial_regs->srtr); - return 0; -} - -/** - * config_port - config the hardware - * @port: port to config - * @baud: baud rate for the port - * @byte_size: data size - * @stop_bits: number of stop bits - * @parenb: parity enable ? - * @parodd: odd parity ? - */ -static inline int -config_port(struct ioc4_port *port, - int baud, int byte_size, int stop_bits, int parenb, int parodd) -{ - char lcr, sizebits; - int spiniter = 0; - - DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n", - __func__, baud, byte_size, stop_bits, parenb, parodd)); - - if (set_baud(port, baud)) - return 1; - - switch (byte_size) { - case 5: - sizebits = UART_LCR_WLEN5; - break; - case 6: - sizebits = UART_LCR_WLEN6; - break; - case 7: - sizebits = UART_LCR_WLEN7; - break; - case 8: - sizebits = UART_LCR_WLEN8; - break; - default: - return 1; - } - - /* Pause the DMA interface if necessary */ - if (port->ip_sscr & IOC4_SSCR_DMA_EN) { - writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE, - &port->ip_serial_regs->sscr); - while((readl(&port->ip_serial_regs->sscr) - & IOC4_SSCR_PAUSE_STATE) == 0) { - spiniter++; - if (spiniter > MAXITER) - return -1; - } - } - - /* Clear relevant fields in lcr */ - lcr = readb(&port->ip_uart_regs->i4u_lcr); - lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR | - UART_LCR_PARITY | LCR_MASK_STOP_BITS); - - /* Set byte size in lcr */ - lcr |= sizebits; - - /* Set parity */ - if (parenb) { - lcr |= UART_LCR_PARITY; - if (!parodd) - lcr |= UART_LCR_EPAR; - } - - /* Set stop bits */ - if (stop_bits) - lcr |= UART_LCR_STOP /* 2 stop bits */ ; - - writeb(lcr, &port->ip_uart_regs->i4u_lcr); - - /* Re-enable the DMA interface if necessary */ - if (port->ip_sscr & IOC4_SSCR_DMA_EN) { - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - port->ip_baud = baud; - - /* When we get within this number of ring entries of filling the - * entire ring on tx, place an EXPLICIT intr to generate a lowat - * notification when output has drained. - */ - port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4; - if (port->ip_tx_lowat == 0) - port->ip_tx_lowat = 1; - - set_rx_timeout(port, 2); - - return 0; -} - -/** - * do_write - Write bytes to the port. Returns the number of bytes - * actually written. Called from transmit_chars - * @port: port to use - * @buf: the stuff to write - * @len: how many bytes in 'buf' - */ -static inline int do_write(struct ioc4_port *port, char *buf, int len) -{ - int prod_ptr, cons_ptr, total = 0; - struct ring *outring; - struct ring_entry *entry; - struct hooks *hooks = port->ip_hooks; - - BUG_ON(!(len >= 0)); - - prod_ptr = port->ip_tx_prod; - cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; - outring = port->ip_outring; - - /* Maintain a 1-entry red-zone. The ring buffer is full when - * (cons - prod) % ring_size is 1. Rather than do this subtraction - * in the body of the loop, I'll do it now. - */ - cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK; - - /* Stuff the bytes into the output */ - while ((prod_ptr != cons_ptr) && (len > 0)) { - int xx; - - /* Get 4 bytes (one ring entry) at a time */ - entry = (struct ring_entry *)((caddr_t) outring + prod_ptr); - - /* Invalidate all entries */ - entry->ring_allsc = 0; - - /* Copy in some bytes */ - for (xx = 0; (xx < 4) && (len > 0); xx++) { - entry->ring_data[xx] = *buf++; - entry->ring_sc[xx] = IOC4_TXCB_VALID; - len--; - total++; - } - - /* If we are within some small threshold of filling up the - * entire ring buffer, we must place an EXPLICIT intr here - * to generate a lowat interrupt in case we subsequently - * really do fill up the ring and the caller goes to sleep. - * No need to place more than one though. - */ - if (!(port->ip_flags & LOWAT_WRITTEN) && - ((cons_ptr - prod_ptr) & PROD_CONS_MASK) - <= port->ip_tx_lowat - * (int)sizeof(struct ring_entry)) { - port->ip_flags |= LOWAT_WRITTEN; - entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE; - } - - /* Go on to next entry */ - prod_ptr += sizeof(struct ring_entry); - prod_ptr &= PROD_CONS_MASK; - } - - /* If we sent something, start DMA if necessary */ - if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) { - port->ip_sscr |= IOC4_SSCR_DMA_EN; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - - /* Store the new producer pointer. If tx is disabled, we stuff the - * data into the ring buffer, but we don't actually start tx. - */ - if (!uart_tx_stopped(port->ip_port)) { - writel(prod_ptr, &port->ip_serial_regs->stpir); - - /* If we are now transmitting, enable tx_mt interrupt so we - * can disable DMA if necessary when the tx finishes. - */ - if (total > 0) - enable_intrs(port, hooks->intr_tx_mt); - } - port->ip_tx_prod = prod_ptr; - return total; -} - -/** - * disable_intrs - disable interrupts - * @port: port to enable - * @mask: mask to use - */ -static void disable_intrs(struct ioc4_port *port, uint32_t mask) -{ - struct hooks *hooks = port->ip_hooks; - - if (port->ip_ienb & mask) { - write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC, - IOC4_SIO_INTR_TYPE); - port->ip_ienb &= ~mask; - } - - if (!port->ip_ienb) - write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, - IOC4_W_IEC, IOC4_OTHER_INTR_TYPE); -} - -/** - * set_notification - Modify event notification - * @port: port to use - * @mask: events mask - * @set_on: set ? - */ -static int set_notification(struct ioc4_port *port, int mask, int set_on) -{ - struct hooks *hooks = port->ip_hooks; - uint32_t intrbits, sscrbits; - - BUG_ON(!mask); - - intrbits = sscrbits = 0; - - if (mask & N_DATA_READY) - intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high); - if (mask & N_OUTPUT_LOWAT) - intrbits |= hooks->intr_tx_explicit; - if (mask & N_DDCD) { - intrbits |= hooks->intr_delta_dcd; - sscrbits |= IOC4_SSCR_RX_RING_DCD; - } - if (mask & N_DCTS) - intrbits |= hooks->intr_delta_cts; - - if (set_on) { - enable_intrs(port, intrbits); - port->ip_notify |= mask; - port->ip_sscr |= sscrbits; - } else { - disable_intrs(port, intrbits); - port->ip_notify &= ~mask; - port->ip_sscr &= ~sscrbits; - } - - /* We require DMA if either DATA_READY or DDCD notification is - * currently requested. If neither of these is requested and - * there is currently no tx in progress, DMA may be disabled. - */ - if (port->ip_notify & (N_DATA_READY | N_DDCD)) - port->ip_sscr |= IOC4_SSCR_DMA_EN; - else if (!(port->ip_ienb & hooks->intr_tx_mt)) - port->ip_sscr &= ~IOC4_SSCR_DMA_EN; - - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - return 0; -} - -/** - * set_mcr - set the master control reg - * @the_port: port to use - * @mask1: mcr mask - * @mask2: shadow mask - */ -static inline int set_mcr(struct uart_port *the_port, - int mask1, int mask2) -{ - struct ioc4_port *port = get_ioc4_port(the_port, 0); - uint32_t shadow; - int spiniter = 0; - char mcr; - - if (!port) - return -1; - - /* Pause the DMA interface if necessary */ - if (port->ip_sscr & IOC4_SSCR_DMA_EN) { - writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE, - &port->ip_serial_regs->sscr); - while ((readl(&port->ip_serial_regs->sscr) - & IOC4_SSCR_PAUSE_STATE) == 0) { - spiniter++; - if (spiniter > MAXITER) - return -1; - } - } - shadow = readl(&port->ip_serial_regs->shadow); - mcr = (shadow & 0xff000000) >> 24; - - /* Set new value */ - mcr |= mask1; - shadow |= mask2; - - writeb(mcr, &port->ip_uart_regs->i4u_mcr); - writel(shadow, &port->ip_serial_regs->shadow); - - /* Re-enable the DMA interface if necessary */ - if (port->ip_sscr & IOC4_SSCR_DMA_EN) { - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - return 0; -} - -/** - * ioc4_set_proto - set the protocol for the port - * @port: port to use - * @proto: protocol to use - */ -static int ioc4_set_proto(struct ioc4_port *port, int proto) -{ - struct hooks *hooks = port->ip_hooks; - - switch (proto) { - case PROTO_RS232: - /* Clear the appropriate GIO pin */ - writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); - break; - - case PROTO_RS422: - /* Set the appropriate GIO pin */ - writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); - break; - - default: - return 1; - } - return 0; -} - -/** - * transmit_chars - upper level write, called with ip_lock - * @the_port: port to write - */ -static void transmit_chars(struct uart_port *the_port) -{ - int xmit_count, tail, head; - int result; - char *start; - struct tty_struct *tty; - struct ioc4_port *port = get_ioc4_port(the_port, 0); - struct uart_state *state; - - if (!the_port) - return; - if (!port) - return; - - state = the_port->state; - tty = state->port.tty; - - if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { - /* Nothing to do or hw stopped */ - set_notification(port, N_ALL_OUTPUT, 0); - return; - } - - head = state->xmit.head; - tail = state->xmit.tail; - start = (char *)&state->xmit.buf[tail]; - - /* write out all the data or until the end of the buffer */ - xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail); - if (xmit_count > 0) { - result = do_write(port, start, xmit_count); - if (result > 0) { - /* booking */ - xmit_count -= result; - the_port->icount.tx += result; - /* advance the pointers */ - tail += result; - tail &= UART_XMIT_SIZE - 1; - state->xmit.tail = tail; - start = (char *)&state->xmit.buf[tail]; - } - } - if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(the_port); - - if (uart_circ_empty(&state->xmit)) { - set_notification(port, N_OUTPUT_LOWAT, 0); - } else { - set_notification(port, N_OUTPUT_LOWAT, 1); - } -} - -/** - * ioc4_change_speed - change the speed of the port - * @the_port: port to change - * @new_termios: new termios settings - * @old_termios: old termios settings - */ -static void -ioc4_change_speed(struct uart_port *the_port, - struct ktermios *new_termios, struct ktermios *old_termios) -{ - struct ioc4_port *port = get_ioc4_port(the_port, 0); - int baud, bits; - unsigned cflag, iflag; - int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; - struct uart_state *state = the_port->state; - - cflag = new_termios->c_cflag; - iflag = new_termios->c_iflag; - - switch (cflag & CSIZE) { - case CS5: - new_data = 5; - bits = 7; - break; - case CS6: - new_data = 6; - bits = 8; - break; - case CS7: - new_data = 7; - bits = 9; - break; - case CS8: - new_data = 8; - bits = 10; - break; - default: - /* cuz we always need a default ... */ - new_data = 5; - bits = 7; - break; - } - if (cflag & CSTOPB) { - bits++; - new_stop = 1; - } - if (cflag & PARENB) { - bits++; - new_parity_enable = 1; - if (cflag & PARODD) - new_parity = 1; - } - baud = uart_get_baud_rate(the_port, new_termios, old_termios, - MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); - DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud)); - - /* default is 9600 */ - if (!baud) - baud = 9600; - - if (!the_port->fifosize) - the_port->fifosize = IOC4_FIFO_CHARS; - the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10)); - the_port->timeout += HZ / 50; /* Add .02 seconds of slop */ - - the_port->ignore_status_mask = N_ALL_INPUT; - - state->port.tty->low_latency = 1; - - if (iflag & IGNPAR) - the_port->ignore_status_mask &= ~(N_PARITY_ERROR - | N_FRAMING_ERROR); - if (iflag & IGNBRK) { - the_port->ignore_status_mask &= ~N_BREAK; - if (iflag & IGNPAR) - the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; - } - if (!(cflag & CREAD)) { - /* ignore everything */ - the_port->ignore_status_mask &= ~N_DATA_READY; - } - - if (cflag & CRTSCTS) { - port->ip_sscr |= IOC4_SSCR_HFC_EN; - } - else { - port->ip_sscr &= ~IOC4_SSCR_HFC_EN; - } - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - - /* Set the configuration and proper notification call */ - DPRINT_CONFIG(("%s : port 0x%p cflag 0%o " - "config_port(baud %d data %d stop %d p enable %d parity %d)," - " notification 0x%x\n", - __func__, (void *)port, cflag, baud, new_data, new_stop, - new_parity_enable, new_parity, the_port->ignore_status_mask)); - - if ((config_port(port, baud, /* baud */ - new_data, /* byte size */ - new_stop, /* stop bits */ - new_parity_enable, /* set parity */ - new_parity)) >= 0) { /* parity 1==odd */ - set_notification(port, the_port->ignore_status_mask, 1); - } -} - -/** - * ic4_startup_local - Start up the serial port - returns >= 0 if no errors - * @the_port: Port to operate on - */ -static inline int ic4_startup_local(struct uart_port *the_port) -{ - struct ioc4_port *port; - struct uart_state *state; - - if (!the_port) - return -1; - - port = get_ioc4_port(the_port, 0); - if (!port) - return -1; - - state = the_port->state; - - local_open(port); - - /* set the protocol - mapbase has the port type */ - ioc4_set_proto(port, the_port->mapbase); - - /* set the speed of the serial port */ - ioc4_change_speed(the_port, state->port.tty->termios, - (struct ktermios *)0); - - return 0; -} - -/* - * ioc4_cb_output_lowat - called when the output low water mark is hit - * @the_port: port to output - */ -static void ioc4_cb_output_lowat(struct uart_port *the_port) -{ - unsigned long pflags; - - /* ip_lock is set on the call here */ - if (the_port) { - spin_lock_irqsave(&the_port->lock, pflags); - transmit_chars(the_port); - spin_unlock_irqrestore(&the_port->lock, pflags); - } -} - -/** - * handle_intr - service any interrupts for the given port - 2nd level - * called via sd_intr - * @arg: handler arg - * @sio_ir: ioc4regs - */ -static void handle_intr(void *arg, uint32_t sio_ir) -{ - struct ioc4_port *port = (struct ioc4_port *)arg; - struct hooks *hooks = port->ip_hooks; - unsigned int rx_high_rd_aborted = 0; - unsigned long flags; - struct uart_port *the_port; - int loop_counter; - - /* Possible race condition here: The tx_mt interrupt bit may be - * cleared without the intervention of the interrupt handler, - * e.g. by a write. If the top level interrupt handler reads a - * tx_mt, then some other processor does a write, starting up - * output, then we come in here, see the tx_mt and stop DMA, the - * output started by the other processor will hang. Thus we can - * only rely on tx_mt being legitimate if it is read while the - * port lock is held. Therefore this bit must be ignored in the - * passed in interrupt mask which was read by the top level - * interrupt handler since the port lock was not held at the time - * it was read. We can only rely on this bit being accurate if it - * is read while the port lock is held. So we'll clear it for now, - * and reload it later once we have the port lock. - */ - sio_ir &= ~(hooks->intr_tx_mt); - - spin_lock_irqsave(&port->ip_lock, flags); - - loop_counter = MAXITER; /* to avoid hangs */ - - do { - uint32_t shadow; - - if ( loop_counter-- <= 0 ) { - printk(KERN_WARNING "IOC4 serial: " - "possible hang condition/" - "port stuck on interrupt.\n"); - break; - } - - /* Handle a DCD change */ - if (sio_ir & hooks->intr_delta_dcd) { - /* ACK the interrupt */ - writel(hooks->intr_delta_dcd, - &port->ip_mem->sio_ir.raw); - - shadow = readl(&port->ip_serial_regs->shadow); - - if ((port->ip_notify & N_DDCD) - && (shadow & IOC4_SHADOW_DCD) - && (port->ip_port)) { - the_port = port->ip_port; - the_port->icount.dcd = 1; - wake_up_interruptible - (&the_port->state->port.delta_msr_wait); - } else if ((port->ip_notify & N_DDCD) - && !(shadow & IOC4_SHADOW_DCD)) { - /* Flag delta DCD/no DCD */ - port->ip_flags |= DCD_ON; - } - } - - /* Handle a CTS change */ - if (sio_ir & hooks->intr_delta_cts) { - /* ACK the interrupt */ - writel(hooks->intr_delta_cts, - &port->ip_mem->sio_ir.raw); - - shadow = readl(&port->ip_serial_regs->shadow); - - if ((port->ip_notify & N_DCTS) - && (port->ip_port)) { - the_port = port->ip_port; - the_port->icount.cts = - (shadow & IOC4_SHADOW_CTS) ? 1 : 0; - wake_up_interruptible - (&the_port->state->port.delta_msr_wait); - } - } - - /* rx timeout interrupt. Must be some data available. Put this - * before the check for rx_high since servicing this condition - * may cause that condition to clear. - */ - if (sio_ir & hooks->intr_rx_timer) { - /* ACK the interrupt */ - writel(hooks->intr_rx_timer, - &port->ip_mem->sio_ir.raw); - - if ((port->ip_notify & N_DATA_READY) - && (port->ip_port)) { - /* ip_lock is set on call here */ - receive_chars(port->ip_port); - } - } - - /* rx high interrupt. Must be after rx_timer. */ - else if (sio_ir & hooks->intr_rx_high) { - /* Data available, notify upper layer */ - if ((port->ip_notify & N_DATA_READY) - && port->ip_port) { - /* ip_lock is set on call here */ - receive_chars(port->ip_port); - } - - /* We can't ACK this interrupt. If receive_chars didn't - * cause the condition to clear, we'll have to disable - * the interrupt until the data is drained. - * If the read was aborted, don't disable the interrupt - * as this may cause us to hang indefinitely. An - * aborted read generally means that this interrupt - * hasn't been delivered to the cpu yet anyway, even - * though we see it as asserted when we read the sio_ir. - */ - if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) { - if ((port->ip_flags & READ_ABORTED) == 0) { - port->ip_ienb &= ~hooks->intr_rx_high; - port->ip_flags |= INPUT_HIGH; - } else { - rx_high_rd_aborted++; - } - } - } - - /* We got a low water interrupt: notify upper layer to - * send more data. Must come before tx_mt since servicing - * this condition may cause that condition to clear. - */ - if (sio_ir & hooks->intr_tx_explicit) { - port->ip_flags &= ~LOWAT_WRITTEN; - - /* ACK the interrupt */ - writel(hooks->intr_tx_explicit, - &port->ip_mem->sio_ir.raw); - - if (port->ip_notify & N_OUTPUT_LOWAT) - ioc4_cb_output_lowat(port->ip_port); - } - - /* Handle tx_mt. Must come after tx_explicit. */ - else if (sio_ir & hooks->intr_tx_mt) { - /* If we are expecting a lowat notification - * and we get to this point it probably means that for - * some reason the tx_explicit didn't work as expected - * (that can legitimately happen if the output buffer is - * filled up in just the right way). - * So send the notification now. - */ - if (port->ip_notify & N_OUTPUT_LOWAT) { - ioc4_cb_output_lowat(port->ip_port); - - /* We need to reload the sio_ir since the lowat - * call may have caused another write to occur, - * clearing the tx_mt condition. - */ - sio_ir = PENDING(port); - } - - /* If the tx_mt condition still persists even after the - * lowat call, we've got some work to do. - */ - if (sio_ir & hooks->intr_tx_mt) { - - /* If we are not currently expecting DMA input, - * and the transmitter has just gone idle, - * there is no longer any reason for DMA, so - * disable it. - */ - if (!(port->ip_notify - & (N_DATA_READY | N_DDCD))) { - BUG_ON(!(port->ip_sscr - & IOC4_SSCR_DMA_EN)); - port->ip_sscr &= ~IOC4_SSCR_DMA_EN; - writel(port->ip_sscr, - &port->ip_serial_regs->sscr); - } - - /* Prevent infinite tx_mt interrupt */ - port->ip_ienb &= ~hooks->intr_tx_mt; - } - } - sio_ir = PENDING(port); - - /* if the read was aborted and only hooks->intr_rx_high, - * clear hooks->intr_rx_high, so we do not loop forever. - */ - - if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) { - sio_ir &= ~hooks->intr_rx_high; - } - } while (sio_ir & hooks->intr_all); - - spin_unlock_irqrestore(&port->ip_lock, flags); - - /* Re-enable interrupts before returning from interrupt handler. - * Getting interrupted here is okay. It'll just v() our semaphore, and - * we'll come through the loop again. - */ - - write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES, - IOC4_SIO_INTR_TYPE); -} - -/* - * ioc4_cb_post_ncs - called for some basic errors - * @port: port to use - * @ncs: event - */ -static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs) -{ - struct uart_icount *icount; - - icount = &the_port->icount; - - if (ncs & NCS_BREAK) - icount->brk++; - if (ncs & NCS_FRAMING) - icount->frame++; - if (ncs & NCS_OVERRUN) - icount->overrun++; - if (ncs & NCS_PARITY) - icount->parity++; -} - -/** - * do_read - Read in bytes from the port. Return the number of bytes - * actually read. - * @the_port: port to use - * @buf: place to put the stuff we read - * @len: how big 'buf' is - */ - -static inline int do_read(struct uart_port *the_port, unsigned char *buf, - int len) -{ - int prod_ptr, cons_ptr, total; - struct ioc4_port *port = get_ioc4_port(the_port, 0); - struct ring *inring; - struct ring_entry *entry; - struct hooks *hooks = port->ip_hooks; - int byte_num; - char *sc; - int loop_counter; - - BUG_ON(!(len >= 0)); - BUG_ON(!port); - - /* There is a nasty timing issue in the IOC4. When the rx_timer - * expires or the rx_high condition arises, we take an interrupt. - * At some point while servicing the interrupt, we read bytes from - * the ring buffer and re-arm the rx_timer. However the rx_timer is - * not started until the first byte is received *after* it is armed, - * and any bytes pending in the rx construction buffers are not drained - * to memory until either there are 4 bytes available or the rx_timer - * expires. This leads to a potential situation where data is left - * in the construction buffers forever - 1 to 3 bytes were received - * after the interrupt was generated but before the rx_timer was - * re-armed. At that point as long as no subsequent bytes are received - * the timer will never be started and the bytes will remain in the - * construction buffer forever. The solution is to execute a DRAIN - * command after rearming the timer. This way any bytes received before - * the DRAIN will be drained to memory, and any bytes received after - * the DRAIN will start the TIMER and be drained when it expires. - * Luckily, this only needs to be done when the DMA buffer is empty - * since there is no requirement that this function return all - * available data as long as it returns some. - */ - /* Re-arm the timer */ - writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); - - prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; - cons_ptr = port->ip_rx_cons; - - if (prod_ptr == cons_ptr) { - int reset_dma = 0; - - /* Input buffer appears empty, do a flush. */ - - /* DMA must be enabled for this to work. */ - if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) { - port->ip_sscr |= IOC4_SSCR_DMA_EN; - reset_dma = 1; - } - - /* Potential race condition: we must reload the srpir after - * issuing the drain command, otherwise we could think the rx - * buffer is empty, then take a very long interrupt, and when - * we come back it's full and we wait forever for the drain to - * complete. - */ - writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN, - &port->ip_serial_regs->sscr); - prod_ptr = readl(&port->ip_serial_regs->srpir) - & PROD_CONS_MASK; - - /* We must not wait for the DRAIN to complete unless there are - * at least 8 bytes (2 ring entries) available to receive the - * data otherwise the DRAIN will never complete and we'll - * deadlock here. - * In fact, to make things easier, I'll just ignore the flush if - * there is any data at all now available. - */ - if (prod_ptr == cons_ptr) { - loop_counter = 0; - while (readl(&port->ip_serial_regs->sscr) & - IOC4_SSCR_RX_DRAIN) { - loop_counter++; - if (loop_counter > MAXITER) - return -1; - } - - /* SIGH. We have to reload the prod_ptr *again* since - * the drain may have caused it to change - */ - prod_ptr = readl(&port->ip_serial_regs->srpir) - & PROD_CONS_MASK; - } - if (reset_dma) { - port->ip_sscr &= ~IOC4_SSCR_DMA_EN; - writel(port->ip_sscr, &port->ip_serial_regs->sscr); - } - } - inring = port->ip_inring; - port->ip_flags &= ~READ_ABORTED; - - total = 0; - loop_counter = 0xfffff; /* to avoid hangs */ - - /* Grab bytes from the hardware */ - while ((prod_ptr != cons_ptr) && (len > 0)) { - entry = (struct ring_entry *)((caddr_t)inring + cons_ptr); - - if ( loop_counter-- <= 0 ) { - printk(KERN_WARNING "IOC4 serial: " - "possible hang condition/" - "port stuck on read.\n"); - break; - } - - /* According to the producer pointer, this ring entry - * must contain some data. But if the PIO happened faster - * than the DMA, the data may not be available yet, so let's - * wait until it arrives. - */ - if ((entry->ring_allsc & RING_ANY_VALID) == 0) { - /* Indicate the read is aborted so we don't disable - * the interrupt thinking that the consumer is - * congested. - */ - port->ip_flags |= READ_ABORTED; - len = 0; - break; - } - - /* Load the bytes/status out of the ring entry */ - for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) { - sc = &(entry->ring_sc[byte_num]); - - /* Check for change in modem state or overrun */ - if ((*sc & IOC4_RXSB_MODEM_VALID) - && (port->ip_notify & N_DDCD)) { - /* Notify upper layer if DCD dropped */ - - if ((port->ip_flags & DCD_ON) - && !(*sc & IOC4_RXSB_DCD)) { - - /* If we have already copied some data, - * return it. We'll pick up the carrier - * drop on the next pass. That way we - * don't throw away the data that has - * already been copied back to - * the caller's buffer. - */ - if (total > 0) { - len = 0; - break; - } - port->ip_flags &= ~DCD_ON; - - /* Turn off this notification so the - * carrier drop protocol won't see it - * again when it does a read. - */ - *sc &= ~IOC4_RXSB_MODEM_VALID; - - /* To keep things consistent, we need - * to update the consumer pointer so - * the next reader won't come in and - * try to read the same ring entries - * again. This must be done here before - * the dcd change. - */ - - if ((entry->ring_allsc & RING_ANY_VALID) - == 0) { - cons_ptr += (int)sizeof - (struct ring_entry); - cons_ptr &= PROD_CONS_MASK; - } - writel(cons_ptr, - &port->ip_serial_regs->srcir); - port->ip_rx_cons = cons_ptr; - - /* Notify upper layer of carrier drop */ - if ((port->ip_notify & N_DDCD) - && port->ip_port) { - the_port->icount.dcd = 0; - wake_up_interruptible - (&the_port->state-> - port.delta_msr_wait); - } - - /* If we had any data to return, we - * would have returned it above. - */ - return 0; - } - } - if (*sc & IOC4_RXSB_MODEM_VALID) { - /* Notify that an input overrun occurred */ - if ((*sc & IOC4_RXSB_OVERRUN) - && (port->ip_notify & N_OVERRUN_ERROR)) { - ioc4_cb_post_ncs(the_port, NCS_OVERRUN); - } - /* Don't look at this byte again */ - *sc &= ~IOC4_RXSB_MODEM_VALID; - } - - /* Check for valid data or RX errors */ - if ((*sc & IOC4_RXSB_DATA_VALID) && - ((*sc & (IOC4_RXSB_PAR_ERR - | IOC4_RXSB_FRAME_ERR - | IOC4_RXSB_BREAK)) - && (port->ip_notify & (N_PARITY_ERROR - | N_FRAMING_ERROR - | N_BREAK)))) { - /* There is an error condition on the next byte. - * If we have already transferred some bytes, - * we'll stop here. Otherwise if this is the - * first byte to be read, we'll just transfer - * it alone after notifying the - * upper layer of its status. - */ - if (total > 0) { - len = 0; - break; - } else { - if ((*sc & IOC4_RXSB_PAR_ERR) && - (port->ip_notify & N_PARITY_ERROR)) { - ioc4_cb_post_ncs(the_port, - NCS_PARITY); - } - if ((*sc & IOC4_RXSB_FRAME_ERR) && - (port->ip_notify & N_FRAMING_ERROR)){ - ioc4_cb_post_ncs(the_port, - NCS_FRAMING); - } - if ((*sc & IOC4_RXSB_BREAK) - && (port->ip_notify & N_BREAK)) { - ioc4_cb_post_ncs - (the_port, - NCS_BREAK); - } - len = 1; - } - } - if (*sc & IOC4_RXSB_DATA_VALID) { - *sc &= ~IOC4_RXSB_DATA_VALID; - *buf = entry->ring_data[byte_num]; - buf++; - len--; - total++; - } - } - - /* If we used up this entry entirely, go on to the next one, - * otherwise we must have run out of buffer space, so - * leave the consumer pointer here for the next read in case - * there are still unread bytes in this entry. - */ - if ((entry->ring_allsc & RING_ANY_VALID) == 0) { - cons_ptr += (int)sizeof(struct ring_entry); - cons_ptr &= PROD_CONS_MASK; - } - } - - /* Update consumer pointer and re-arm rx timer interrupt */ - writel(cons_ptr, &port->ip_serial_regs->srcir); - port->ip_rx_cons = cons_ptr; - - /* If we have now dipped below the rx high water mark and we have - * rx_high interrupt turned off, we can now turn it back on again. - */ - if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr) - & PROD_CONS_MASK) < ((port->ip_sscr & - IOC4_SSCR_RX_THRESHOLD) - << IOC4_PROD_CONS_PTR_OFF))) { - port->ip_flags &= ~INPUT_HIGH; - enable_intrs(port, hooks->intr_rx_high); - } - return total; -} - -/** - * receive_chars - upper level read. Called with ip_lock. - * @the_port: port to read from - */ -static void receive_chars(struct uart_port *the_port) -{ - struct tty_struct *tty; - unsigned char ch[IOC4_MAX_CHARS]; - int read_count, request_count = IOC4_MAX_CHARS; - struct uart_icount *icount; - struct uart_state *state = the_port->state; - unsigned long pflags; - - /* Make sure all the pointers are "good" ones */ - if (!state) - return; - if (!state->port.tty) - return; - - spin_lock_irqsave(&the_port->lock, pflags); - tty = state->port.tty; - - request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS); - - if (request_count > 0) { - icount = &the_port->icount; - read_count = do_read(the_port, ch, request_count); - if (read_count > 0) { - tty_insert_flip_string(tty, ch, read_count); - icount->rx += read_count; - } - } - - spin_unlock_irqrestore(&the_port->lock, pflags); - - tty_flip_buffer_push(tty); -} - -/** - * ic4_type - What type of console are we? - * @port: Port to operate with (we ignore since we only have one port) - * - */ -static const char *ic4_type(struct uart_port *the_port) -{ - if (the_port->mapbase == PROTO_RS232) - return "SGI IOC4 Serial [rs232]"; - else - return "SGI IOC4 Serial [rs422]"; -} - -/** - * ic4_tx_empty - Is the transmitter empty? - * @port: Port to operate on - * - */ -static unsigned int ic4_tx_empty(struct uart_port *the_port) -{ - struct ioc4_port *port = get_ioc4_port(the_port, 0); - unsigned int ret = 0; - - if (port_is_active(port, the_port)) { - if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT) - ret = TIOCSER_TEMT; - } - return ret; -} - -/** - * ic4_stop_tx - stop the transmitter - * @port: Port to operate on - * - */ -static void ic4_stop_tx(struct uart_port *the_port) -{ - struct ioc4_port *port = get_ioc4_port(the_port, 0); - - if (port_is_active(port, the_port)) - set_notification(port, N_OUTPUT_LOWAT, 0); -} - -/** - * null_void_function - - * @port: Port to operate on - * - */ -static void null_void_function(struct uart_port *the_port) -{ -} - -/** - * ic4_shutdown - shut down the port - free irq and disable - * @port: Port to shut down - * - */ -static void ic4_shutdown(struct uart_port *the_port) -{ - unsigned long port_flags; - struct ioc4_port *port; - struct uart_state *state; - - port = get_ioc4_port(the_port, 0); - if (!port) - return; - - state = the_port->state; - port->ip_port = NULL; - - wake_up_interruptible(&state->port.delta_msr_wait); - - if (state->port.tty) - set_bit(TTY_IO_ERROR, &state->port.tty->flags); - - spin_lock_irqsave(&the_port->lock, port_flags); - set_notification(port, N_ALL, 0); - port->ip_flags = PORT_INACTIVE; - spin_unlock_irqrestore(&the_port->lock, port_flags); -} - -/** - * ic4_set_mctrl - set control lines (dtr, rts, etc) - * @port: Port to operate on - * @mctrl: Lines to set/unset - * - */ -static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl) -{ - unsigned char mcr = 0; - struct ioc4_port *port; - - port = get_ioc4_port(the_port, 0); - if (!port_is_active(port, the_port)) - return; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - set_mcr(the_port, mcr, IOC4_SHADOW_DTR); -} - -/** - * ic4_get_mctrl - get control line info - * @port: port to operate on - * - */ -static unsigned int ic4_get_mctrl(struct uart_port *the_port) -{ - struct ioc4_port *port = get_ioc4_port(the_port, 0); - uint32_t shadow; - unsigned int ret = 0; - - if (!port_is_active(port, the_port)) - return 0; - - shadow = readl(&port->ip_serial_regs->shadow); - if (shadow & IOC4_SHADOW_DCD) - ret |= TIOCM_CAR; - if (shadow & IOC4_SHADOW_DR) - ret |= TIOCM_DSR; - if (shadow & IOC4_SHADOW_CTS) - ret |= TIOCM_CTS; - return ret; -} - -/** - * ic4_start_tx - Start transmitter, flush any output - * @port: Port to operate on - * - */ -static void ic4_start_tx(struct uart_port *the_port) -{ - struct ioc4_port *port = get_ioc4_port(the_port, 0); - - if (port_is_active(port, the_port)) { - set_notification(port, N_OUTPUT_LOWAT, 1); - enable_intrs(port, port->ip_hooks->intr_tx_mt); - } -} - -/** - * ic4_break_ctl - handle breaks - * @port: Port to operate on - * @break_state: Break state - * - */ -static void ic4_break_ctl(struct uart_port *the_port, int break_state) -{ -} - -/** - * ic4_startup - Start up the serial port - * @port: Port to operate on - * - */ -static int ic4_startup(struct uart_port *the_port) -{ - int retval; - struct ioc4_port *port; - struct ioc4_control *control; - struct uart_state *state; - unsigned long port_flags; - - if (!the_port) - return -ENODEV; - port = get_ioc4_port(the_port, 1); - if (!port) - return -ENODEV; - state = the_port->state; - - control = port->ip_control; - if (!control) { - port->ip_port = NULL; - return -ENODEV; - } - - /* Start up the serial port */ - spin_lock_irqsave(&the_port->lock, port_flags); - retval = ic4_startup_local(the_port); - spin_unlock_irqrestore(&the_port->lock, port_flags); - return retval; -} - -/** - * ic4_set_termios - set termios stuff - * @port: port to operate on - * @termios: New settings - * @termios: Old - * - */ -static void -ic4_set_termios(struct uart_port *the_port, - struct ktermios *termios, struct ktermios *old_termios) -{ - unsigned long port_flags; - - spin_lock_irqsave(&the_port->lock, port_flags); - ioc4_change_speed(the_port, termios, old_termios); - spin_unlock_irqrestore(&the_port->lock, port_flags); -} - -/** - * ic4_request_port - allocate resources for port - no op.... - * @port: port to operate on - * - */ -static int ic4_request_port(struct uart_port *port) -{ - return 0; -} - -/* Associate the uart functions above - given to serial core */ - -static struct uart_ops ioc4_ops = { - .tx_empty = ic4_tx_empty, - .set_mctrl = ic4_set_mctrl, - .get_mctrl = ic4_get_mctrl, - .stop_tx = ic4_stop_tx, - .start_tx = ic4_start_tx, - .stop_rx = null_void_function, - .enable_ms = null_void_function, - .break_ctl = ic4_break_ctl, - .startup = ic4_startup, - .shutdown = ic4_shutdown, - .set_termios = ic4_set_termios, - .type = ic4_type, - .release_port = null_void_function, - .request_port = ic4_request_port, -}; - -/* - * Boot-time initialization code - */ - -static struct uart_driver ioc4_uart_rs232 = { - .owner = THIS_MODULE, - .driver_name = "ioc4_serial_rs232", - .dev_name = DEVICE_NAME_RS232, - .major = DEVICE_MAJOR, - .minor = DEVICE_MINOR_RS232, - .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS, -}; - -static struct uart_driver ioc4_uart_rs422 = { - .owner = THIS_MODULE, - .driver_name = "ioc4_serial_rs422", - .dev_name = DEVICE_NAME_RS422, - .major = DEVICE_MAJOR, - .minor = DEVICE_MINOR_RS422, - .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS, -}; - - -/** - * ioc4_serial_remove_one - detach function - * - * @idd: IOC4 master module data for this IOC4 - */ - -static int ioc4_serial_remove_one(struct ioc4_driver_data *idd) -{ - int port_num, port_type; - struct ioc4_control *control; - struct uart_port *the_port; - struct ioc4_port *port; - struct ioc4_soft *soft; - - /* If serial driver did not attach, don't try to detach */ - control = idd->idd_serial_data; - if (!control) - return 0; - - for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { - for (port_type = UART_PORT_MIN; - port_type < UART_PORT_COUNT; - port_type++) { - the_port = &control->ic_port[port_num].icp_uart_port - [port_type]; - if (the_port) { - switch (port_type) { - case UART_PORT_RS422: - uart_remove_one_port(&ioc4_uart_rs422, - the_port); - break; - default: - case UART_PORT_RS232: - uart_remove_one_port(&ioc4_uart_rs232, - the_port); - break; - } - } - } - port = control->ic_port[port_num].icp_port; - /* we allocate in pairs */ - if (!(port_num & 1) && port) { - pci_free_consistent(port->ip_pdev, - TOTAL_RING_BUF_SIZE, - port->ip_cpu_ringbuf, - port->ip_dma_ringbuf); - kfree(port); - } - } - soft = control->ic_soft; - if (soft) { - free_irq(control->ic_irq, soft); - if (soft->is_ioc4_serial_addr) { - iounmap(soft->is_ioc4_serial_addr); - release_mem_region((unsigned long) - soft->is_ioc4_serial_addr, - sizeof(struct ioc4_serial)); - } - kfree(soft); - } - kfree(control); - idd->idd_serial_data = NULL; - - return 0; -} - - -/** - * ioc4_serial_core_attach_rs232 - register with serial core - * This is done during pci probing - * @pdev: handle for this card - */ -static inline int -ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) -{ - struct ioc4_port *port; - struct uart_port *the_port; - struct ioc4_driver_data *idd = pci_get_drvdata(pdev); - struct ioc4_control *control = idd->idd_serial_data; - int port_num; - int port_type_idx; - struct uart_driver *u_driver; - - - DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", - __func__, pdev, (void *)control)); - - if (!control) - return -ENODEV; - - port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232 - : UART_PORT_RS422; - - u_driver = (port_type == PROTO_RS232) ? &ioc4_uart_rs232 - : &ioc4_uart_rs422; - - /* once around for each port on this card */ - for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { - the_port = &control->ic_port[port_num].icp_uart_port - [port_type_idx]; - port = control->ic_port[port_num].icp_port; - port->ip_all_ports[port_type_idx] = the_port; - - DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n", - __func__, (void *)the_port, - (void *)port, - port_type == PROTO_RS232 ? "rs232" : "rs422")); - - /* membase, iobase and mapbase just need to be non-0 */ - the_port->membase = (unsigned char __iomem *)1; - the_port->iobase = (pdev->bus->number << 16) | port_num; - the_port->line = (Num_of_ioc4_cards << 2) | port_num; - the_port->mapbase = port_type; - the_port->type = PORT_16550A; - the_port->fifosize = IOC4_FIFO_CHARS; - the_port->ops = &ioc4_ops; - the_port->irq = control->ic_irq; - the_port->dev = &pdev->dev; - spin_lock_init(&the_port->lock); - if (uart_add_one_port(u_driver, the_port) < 0) { - printk(KERN_WARNING - "%s: unable to add port %d bus %d\n", - __func__, the_port->line, pdev->bus->number); - } else { - DPRINT_CONFIG( - ("IOC4 serial port %d irq = %d, bus %d\n", - the_port->line, the_port->irq, pdev->bus->number)); - } - } - return 0; -} - -/** - * ioc4_serial_attach_one - register attach function - * called per card found from IOC4 master module. - * @idd: Master module data for this IOC4 - */ -int -ioc4_serial_attach_one(struct ioc4_driver_data *idd) -{ - unsigned long tmp_addr1; - struct ioc4_serial __iomem *serial; - struct ioc4_soft *soft; - struct ioc4_control *control; - int ret = 0; - - - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev, - idd->idd_pci_id)); - - /* PCI-RT does not bring out serial connections. - * Do not attach to this particular IOC4. - */ - if (idd->idd_variant == IOC4_VARIANT_PCI_RT) - return 0; - - /* request serial registers */ - tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; - - if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial), - "sioc4_uart")) { - printk(KERN_WARNING - "ioc4 (%p): unable to get request region for " - "uart space\n", (void *)idd->idd_pdev); - ret = -ENODEV; - goto out1; - } - serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial)); - if (!serial) { - printk(KERN_WARNING - "ioc4 (%p) : unable to remap ioc4 serial register\n", - (void *)idd->idd_pdev); - ret = -ENODEV; - goto out2; - } - DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", - __func__, (void *)idd->idd_misc_regs, - (void *)serial)); - - /* Get memory for the new card */ - control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL); - - if (!control) { - printk(KERN_WARNING "ioc4_attach_one" - ": unable to get memory for the IOC4\n"); - ret = -ENOMEM; - goto out2; - } - idd->idd_serial_data = control; - - /* Allocate the soft structure */ - soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL); - if (!soft) { - printk(KERN_WARNING - "ioc4 (%p): unable to get memory for the soft struct\n", - (void *)idd->idd_pdev); - ret = -ENOMEM; - goto out3; - } - - spin_lock_init(&soft->is_ir_lock); - soft->is_ioc4_misc_addr = idd->idd_misc_regs; - soft->is_ioc4_serial_addr = serial; - - /* Init the IOC4 */ - writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, - &idd->idd_misc_regs->sio_cr.raw); - - /* Enable serial port mode select generic PIO pins as outputs */ - writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL - | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL, - &idd->idd_misc_regs->gpcr_s.raw); - - /* Clear and disable all serial interrupts */ - write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); - writel(~0, &idd->idd_misc_regs->sio_ir.raw); - write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC, - IOC4_OTHER_INTR_TYPE); - writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw); - control->ic_soft = soft; - - /* Hook up interrupt handler */ - if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED, - "sgi-ioc4serial", soft)) { - control->ic_irq = idd->idd_pdev->irq; - } else { - printk(KERN_WARNING - "%s : request_irq fails for IRQ 0x%x\n ", - __func__, idd->idd_pdev->irq); - } - ret = ioc4_attach_local(idd); - if (ret) - goto out4; - - /* register port with the serial core - 1 rs232, 1 rs422 */ - - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232))) - goto out4; - - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422))) - goto out5; - - Num_of_ioc4_cards++; - - return ret; - - /* error exits that give back resources */ -out5: - ioc4_serial_remove_one(idd); -out4: - kfree(soft); -out3: - kfree(control); -out2: - if (serial) - iounmap(serial); - release_mem_region(tmp_addr1, sizeof(struct ioc4_serial)); -out1: - - return ret; -} - - -static struct ioc4_submodule ioc4_serial_submodule = { - .is_name = "IOC4_serial", - .is_owner = THIS_MODULE, - .is_probe = ioc4_serial_attach_one, - .is_remove = ioc4_serial_remove_one, -}; - -/** - * ioc4_serial_init - module init - */ -static int __init ioc4_serial_init(void) -{ - int ret; - - /* register with serial core */ - if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) { - printk(KERN_WARNING - "%s: Couldn't register rs232 IOC4 serial driver\n", - __func__); - goto out; - } - if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) { - printk(KERN_WARNING - "%s: Couldn't register rs422 IOC4 serial driver\n", - __func__); - goto out_uart_rs232; - } - - /* register with IOC4 main module */ - ret = ioc4_register_submodule(&ioc4_serial_submodule); - if (ret) - goto out_uart_rs422; - return 0; - -out_uart_rs422: - uart_unregister_driver(&ioc4_uart_rs422); -out_uart_rs232: - uart_unregister_driver(&ioc4_uart_rs232); -out: - return ret; -} - -static void __exit ioc4_serial_exit(void) -{ - ioc4_unregister_submodule(&ioc4_serial_submodule); - uart_unregister_driver(&ioc4_uart_rs232); - uart_unregister_driver(&ioc4_uart_rs422); -} - -late_initcall(ioc4_serial_init); /* Call only after tty init is done */ -module_exit(ioc4_serial_exit); - -MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); -MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c deleted file mode 100644 index ebff4a1d4bcc..000000000000 --- a/drivers/serial/ip22zilog.c +++ /dev/null @@ -1,1221 +0,0 @@ -/* - * Driver for Zilog serial chips found on SGI workstations and - * servers. This driver could actually be made more generic. - * - * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the - * old drivers/sgi/char/sgiserial.c code which itself is based of the original - * drivers/sbus/char/zs.c code. A lot of code has been simply moved over - * directly from there but much has been rewritten. Credits therefore go out - * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell - * for their work there. - * - * Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2002 David S. Miller (davem@redhat.com) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -#include "ip22zilog.h" - -/* - * On IP22 we need to delay after register accesses but we do not need to - * flush writes. - */ -#define ZSDELAY() udelay(5) -#define ZSDELAY_LONG() udelay(20) -#define ZS_WSYNC(channel) do { } while (0) - -#define NUM_IP22ZILOG 1 -#define NUM_CHANNELS (NUM_IP22ZILOG * 2) - -#define ZS_CLOCK 3672000 /* Zilog input clock rate. */ -#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ - -/* - * We wrap our port structure around the generic uart_port. - */ -struct uart_ip22zilog_port { - struct uart_port port; - - /* IRQ servicing chain. */ - struct uart_ip22zilog_port *next; - - /* Current values of Zilog write registers. */ - unsigned char curregs[NUM_ZSREGS]; - - unsigned int flags; -#define IP22ZILOG_FLAG_IS_CONS 0x00000004 -#define IP22ZILOG_FLAG_IS_KGDB 0x00000008 -#define IP22ZILOG_FLAG_MODEM_STATUS 0x00000010 -#define IP22ZILOG_FLAG_IS_CHANNEL_A 0x00000020 -#define IP22ZILOG_FLAG_REGS_HELD 0x00000040 -#define IP22ZILOG_FLAG_TX_STOPPED 0x00000080 -#define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100 -#define IP22ZILOG_FLAG_RESET_DONE 0x00000200 - - unsigned int tty_break; - - unsigned char parity_mask; - unsigned char prev_status; -}; - -#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel *)((PORT)->membase)) -#define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT)) -#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \ - (UART_ZILOG(PORT)->curregs[REGNUM]) -#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL) \ - ((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL)) -#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS) -#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB) -#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS) -#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A) -#define ZS_REGS_HELD(UP) ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD) -#define ZS_TX_STOPPED(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED) -#define ZS_TX_ACTIVE(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE) - -/* Reading and writing Zilog8530 registers. The delays are to make this - * driver work on the IP22 which needs a settling delay after each chip - * register access, other machines handle this in hardware via auxiliary - * flip-flops which implement the settle time we do in software. - * - * The port lock must be held and local IRQs must be disabled - * when {read,write}_zsreg is invoked. - */ -static unsigned char read_zsreg(struct zilog_channel *channel, - unsigned char reg) -{ - unsigned char retval; - - writeb(reg, &channel->control); - ZSDELAY(); - retval = readb(&channel->control); - ZSDELAY(); - - return retval; -} - -static void write_zsreg(struct zilog_channel *channel, - unsigned char reg, unsigned char value) -{ - writeb(reg, &channel->control); - ZSDELAY(); - writeb(value, &channel->control); - ZSDELAY(); -} - -static void ip22zilog_clear_fifo(struct zilog_channel *channel) -{ - int i; - - for (i = 0; i < 32; i++) { - unsigned char regval; - - regval = readb(&channel->control); - ZSDELAY(); - if (regval & Rx_CH_AV) - break; - - regval = read_zsreg(channel, R1); - readb(&channel->data); - ZSDELAY(); - - if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - } - } -} - -/* This function must only be called when the TX is not busy. The UART - * port lock must be held and local interrupts disabled. - */ -static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs) -{ - int i; - - /* Let pending transmits finish. */ - for (i = 0; i < 1000; i++) { - unsigned char stat = read_zsreg(channel, R1); - if (stat & ALL_SNT) - break; - udelay(100); - } - - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - ip22zilog_clear_fifo(channel); - - /* Disable all interrupts. */ - write_zsreg(channel, R1, - regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); - - /* Set parity, sync config, stop bits, and clock divisor. */ - write_zsreg(channel, R4, regs[R4]); - - /* Set misc. TX/RX control bits. */ - write_zsreg(channel, R10, regs[R10]); - - /* Set TX/RX controls sans the enable bits. */ - write_zsreg(channel, R3, regs[R3] & ~RxENAB); - write_zsreg(channel, R5, regs[R5] & ~TxENAB); - - /* Synchronous mode config. */ - write_zsreg(channel, R6, regs[R6]); - write_zsreg(channel, R7, regs[R7]); - - /* Don't mess with the interrupt vector (R2, unused by us) and - * master interrupt control (R9). We make sure this is setup - * properly at probe time then never touch it again. - */ - - /* Disable baud generator. */ - write_zsreg(channel, R14, regs[R14] & ~BRENAB); - - /* Clock mode control. */ - write_zsreg(channel, R11, regs[R11]); - - /* Lower and upper byte of baud rate generator divisor. */ - write_zsreg(channel, R12, regs[R12]); - write_zsreg(channel, R13, regs[R13]); - - /* Now rewrite R14, with BRENAB (if set). */ - write_zsreg(channel, R14, regs[R14]); - - /* External status interrupt control. */ - write_zsreg(channel, R15, regs[R15]); - - /* Reset external status interrupts. */ - write_zsreg(channel, R0, RES_EXT_INT); - write_zsreg(channel, R0, RES_EXT_INT); - - /* Rewrite R3/R5, this time without enables masked. */ - write_zsreg(channel, R3, regs[R3]); - write_zsreg(channel, R5, regs[R5]); - - /* Rewrite R1, this time without IRQ enabled masked. */ - write_zsreg(channel, R1, regs[R1]); -} - -/* Reprogram the Zilog channel HW registers with the copies found in the - * software state struct. If the transmitter is busy, we defer this update - * until the next TX complete interrupt. Else, we do it right now. - * - * The UART port lock must be held and local interrupts disabled. - */ -static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up, - struct zilog_channel *channel) -{ - if (!ZS_REGS_HELD(up)) { - if (ZS_TX_ACTIVE(up)) { - up->flags |= IP22ZILOG_FLAG_REGS_HELD; - } else { - __load_zsregs(channel, up->curregs); - } - } -} - -#define Rx_BRK 0x0100 /* BREAK event software flag. */ -#define Rx_SYS 0x0200 /* SysRq event software flag. */ - -static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up, - struct zilog_channel *channel) -{ - struct tty_struct *tty; - unsigned char ch, flag; - unsigned int r1; - - tty = NULL; - if (up->port.state != NULL && - up->port.state->port.tty != NULL) - tty = up->port.state->port.tty; - - for (;;) { - ch = readb(&channel->control); - ZSDELAY(); - if (!(ch & Rx_CH_AV)) - break; - - r1 = read_zsreg(channel, R1); - if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - } - - ch = readb(&channel->data); - ZSDELAY(); - - ch &= up->parity_mask; - - /* Handle the null char got when BREAK is removed. */ - if (!ch) - r1 |= up->tty_break; - - /* A real serial line, record the character and status. */ - flag = TTY_NORMAL; - up->port.icount.rx++; - if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) { - up->tty_break = 0; - - if (r1 & (Rx_SYS | Rx_BRK)) { - up->port.icount.brk++; - if (r1 & Rx_SYS) - continue; - r1 &= ~(PAR_ERR | CRC_ERR); - } - else if (r1 & PAR_ERR) - up->port.icount.parity++; - else if (r1 & CRC_ERR) - up->port.icount.frame++; - if (r1 & Rx_OVR) - up->port.icount.overrun++; - r1 &= up->port.read_status_mask; - if (r1 & Rx_BRK) - flag = TTY_BREAK; - else if (r1 & PAR_ERR) - flag = TTY_PARITY; - else if (r1 & CRC_ERR) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - continue; - - if (tty) - uart_insert_char(&up->port, r1, Rx_OVR, ch, flag); - } - return tty; -} - -static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, - struct zilog_channel *channel) -{ - unsigned char status; - - status = readb(&channel->control); - ZSDELAY(); - - writeb(RES_EXT_INT, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (up->curregs[R15] & BRKIE) { - if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) { - if (uart_handle_break(&up->port)) - up->tty_break = Rx_SYS; - else - up->tty_break = Rx_BRK; - } - } - - if (ZS_WANTS_MODEM_STATUS(up)) { - if (status & SYNC) - up->port.icount.dsr++; - - /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. - * But it does not tell us which bit has changed, we have to keep - * track of this ourselves. - */ - if ((status ^ up->prev_status) ^ DCD) - uart_handle_dcd_change(&up->port, - (status & DCD)); - if ((status ^ up->prev_status) ^ CTS) - uart_handle_cts_change(&up->port, - (status & CTS)); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); - } - - up->prev_status = status; -} - -static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, - struct zilog_channel *channel) -{ - struct circ_buf *xmit; - - if (ZS_IS_CONS(up)) { - unsigned char status = readb(&channel->control); - ZSDELAY(); - - /* TX still busy? Just wait for the next TX done interrupt. - * - * It can occur because of how we do serial console writes. It would - * be nice to transmit console writes just like we normally would for - * a TTY line. (ie. buffered and TX interrupt driven). That is not - * easy because console writes cannot sleep. One solution might be - * to poll on enough port->xmit space becomming free. -DaveM - */ - if (!(status & Tx_BUF_EMP)) - return; - } - - up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE; - - if (ZS_REGS_HELD(up)) { - __load_zsregs(channel, up->curregs); - up->flags &= ~IP22ZILOG_FLAG_REGS_HELD; - } - - if (ZS_TX_STOPPED(up)) { - up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED; - goto ack_tx_int; - } - - if (up->port.x_char) { - up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; - writeb(up->port.x_char, &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - - if (up->port.state == NULL) - goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; - if (uart_tx_stopped(&up->port)) - goto ack_tx_int; - - up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - return; - -ack_tx_int: - writeb(RES_Tx_P, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); -} - -static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) -{ - struct uart_ip22zilog_port *up = dev_id; - - while (up) { - struct zilog_channel *channel - = ZILOG_CHANNEL_FROM_PORT(&up->port); - struct tty_struct *tty; - unsigned char r3; - - spin_lock(&up->port.lock); - r3 = read_zsreg(channel, R3); - - /* Channel A */ - tty = NULL; - if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (r3 & CHARxIP) - tty = ip22zilog_receive_chars(up, channel); - if (r3 & CHAEXT) - ip22zilog_status_handle(up, channel); - if (r3 & CHATxIP) - ip22zilog_transmit_chars(up, channel); - } - spin_unlock(&up->port.lock); - - if (tty) - tty_flip_buffer_push(tty); - - /* Channel B */ - up = up->next; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - - spin_lock(&up->port.lock); - tty = NULL; - if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (r3 & CHBRxIP) - tty = ip22zilog_receive_chars(up, channel); - if (r3 & CHBEXT) - ip22zilog_status_handle(up, channel); - if (r3 & CHBTxIP) - ip22zilog_transmit_chars(up, channel); - } - spin_unlock(&up->port.lock); - - if (tty) - tty_flip_buffer_push(tty); - - up = up->next; - } - - return IRQ_HANDLED; -} - -/* A convenient way to quickly get R0 status. The caller must _not_ hold the - * port lock, it is acquired here. - */ -static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port) -{ - struct zilog_channel *channel; - unsigned char status; - - channel = ZILOG_CHANNEL_FROM_PORT(port); - status = readb(&channel->control); - ZSDELAY(); - - return status; -} - -/* The port lock is not held. */ -static unsigned int ip22zilog_tx_empty(struct uart_port *port) -{ - unsigned long flags; - unsigned char status; - unsigned int ret; - - spin_lock_irqsave(&port->lock, flags); - - status = ip22zilog_read_channel_status(port); - - spin_unlock_irqrestore(&port->lock, flags); - - if (status & Tx_BUF_EMP) - ret = TIOCSER_TEMT; - else - ret = 0; - - return ret; -} - -/* The port lock is held and interrupts are disabled. */ -static unsigned int ip22zilog_get_mctrl(struct uart_port *port) -{ - unsigned char status; - unsigned int ret; - - status = ip22zilog_read_channel_status(port); - - ret = 0; - if (status & DCD) - ret |= TIOCM_CAR; - if (status & SYNC) - ret |= TIOCM_DSR; - if (status & CTS) - ret |= TIOCM_CTS; - - return ret; -} - -/* The port lock is held and interrupts are disabled. */ -static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; - struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char set_bits, clear_bits; - - set_bits = clear_bits = 0; - - if (mctrl & TIOCM_RTS) - set_bits |= RTS; - else - clear_bits |= RTS; - if (mctrl & TIOCM_DTR) - set_bits |= DTR; - else - clear_bits |= DTR; - - /* NOTE: Not subject to 'transmitter active' rule. */ - up->curregs[R5] |= set_bits; - up->curregs[R5] &= ~clear_bits; - write_zsreg(channel, R5, up->curregs[R5]); -} - -/* The port lock is held and interrupts are disabled. */ -static void ip22zilog_stop_tx(struct uart_port *port) -{ - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; - - up->flags |= IP22ZILOG_FLAG_TX_STOPPED; -} - -/* The port lock is held and interrupts are disabled. */ -static void ip22zilog_start_tx(struct uart_port *port) -{ - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; - struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char status; - - up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; - up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED; - - status = readb(&channel->control); - ZSDELAY(); - - /* TX busy? Just wait for the TX done interrupt. */ - if (!(status & Tx_BUF_EMP)) - return; - - /* Send the first character to jump-start the TX done - * IRQ sending engine. - */ - if (port->x_char) { - writeb(port->x_char, &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - port->icount.tx++; - port->x_char = 0; - } else { - struct circ_buf *xmit = &port->state->xmit; - - writeb(xmit->buf[xmit->tail], &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - } -} - -/* The port lock is held and interrupts are disabled. */ -static void ip22zilog_stop_rx(struct uart_port *port) -{ - struct uart_ip22zilog_port *up = UART_ZILOG(port); - struct zilog_channel *channel; - - if (ZS_IS_CONS(up)) - return; - - channel = ZILOG_CHANNEL_FROM_PORT(port); - - /* Disable all RX interrupts. */ - up->curregs[R1] &= ~RxINT_MASK; - ip22zilog_maybe_update_regs(up, channel); -} - -/* The port lock is held. */ -static void ip22zilog_enable_ms(struct uart_port *port) -{ - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; - struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char new_reg; - - new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE); - if (new_reg != up->curregs[R15]) { - up->curregs[R15] = new_reg; - - /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(channel, R15, up->curregs[R15]); - } -} - -/* The port lock is not held. */ -static void ip22zilog_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; - struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char set_bits, clear_bits, new_reg; - unsigned long flags; - - set_bits = clear_bits = 0; - - if (break_state) - set_bits |= SND_BRK; - else - clear_bits |= SND_BRK; - - spin_lock_irqsave(&port->lock, flags); - - new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; - if (new_reg != up->curregs[R5]) { - up->curregs[R5] = new_reg; - - /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(channel, R5, up->curregs[R5]); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void __ip22zilog_reset(struct uart_ip22zilog_port *up) -{ - struct zilog_channel *channel; - int i; - - if (up->flags & IP22ZILOG_FLAG_RESET_DONE) - return; - - /* Let pending transmits finish. */ - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - for (i = 0; i < 1000; i++) { - unsigned char stat = read_zsreg(channel, R1); - if (stat & ALL_SNT) - break; - udelay(100); - } - - if (!ZS_IS_CHANNEL_A(up)) { - up++; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - } - write_zsreg(channel, R9, FHWRES); - ZSDELAY_LONG(); - (void) read_zsreg(channel, R0); - - up->flags |= IP22ZILOG_FLAG_RESET_DONE; - up->next->flags |= IP22ZILOG_FLAG_RESET_DONE; -} - -static void __ip22zilog_startup(struct uart_ip22zilog_port *up) -{ - struct zilog_channel *channel; - - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - - __ip22zilog_reset(up); - - __load_zsregs(channel, up->curregs); - /* set master interrupt enable */ - write_zsreg(channel, R9, up->curregs[R9]); - up->prev_status = readb(&channel->control); - - /* Enable receiver and transmitter. */ - up->curregs[R3] |= RxENAB; - up->curregs[R5] |= TxENAB; - - up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - ip22zilog_maybe_update_regs(up, channel); -} - -static int ip22zilog_startup(struct uart_port *port) -{ - struct uart_ip22zilog_port *up = UART_ZILOG(port); - unsigned long flags; - - if (ZS_IS_CONS(up)) - return 0; - - spin_lock_irqsave(&port->lock, flags); - __ip22zilog_startup(up); - spin_unlock_irqrestore(&port->lock, flags); - return 0; -} - -/* - * The test for ZS_IS_CONS is explained by the following e-mail: - ***** - * From: Russell King - * Date: Sun, 8 Dec 2002 10:18:38 +0000 - * - * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote: - * > I boot my 2.5 boxes using "console=ttyS0,9600" argument, - * > and I noticed that something is not right with reference - * > counting in this case. It seems that when the console - * > is open by kernel initially, this is not accounted - * > as an open, and uart_startup is not called. - * - * That is correct. We are unable to call uart_startup when the serial - * console is initialised because it may need to allocate memory (as - * request_irq does) and the memory allocators may not have been - * initialised. - * - * 1. initialise the port into a state where it can send characters in the - * console write method. - * - * 2. don't do the actual hardware shutdown in your shutdown() method (but - * do the normal software shutdown - ie, free irqs etc) - ***** - */ -static void ip22zilog_shutdown(struct uart_port *port) -{ - struct uart_ip22zilog_port *up = UART_ZILOG(port); - struct zilog_channel *channel; - unsigned long flags; - - if (ZS_IS_CONS(up)) - return; - - spin_lock_irqsave(&port->lock, flags); - - channel = ZILOG_CHANNEL_FROM_PORT(port); - - /* Disable receiver and transmitter. */ - up->curregs[R3] &= ~RxENAB; - up->curregs[R5] &= ~TxENAB; - - /* Disable all interrupts and BRK assertion. */ - up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - up->curregs[R5] &= ~SND_BRK; - ip22zilog_maybe_update_regs(up, channel); - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Shared by TTY driver and serial console setup. The port lock is held - * and local interrupts are disabled. - */ -static void -ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, - unsigned int iflag, int brg) -{ - - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - - /* Program BAUD and clock source. */ - up->curregs[R4] &= ~XCLK_MASK; - up->curregs[R4] |= X16CLK; - up->curregs[R12] = brg & 0xff; - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRENAB; - - /* Character size, stop bits, and parity. */ - up->curregs[3] &= ~RxN_MASK; - up->curregs[5] &= ~TxN_MASK; - switch (cflag & CSIZE) { - case CS5: - up->curregs[3] |= Rx5; - up->curregs[5] |= Tx5; - up->parity_mask = 0x1f; - break; - case CS6: - up->curregs[3] |= Rx6; - up->curregs[5] |= Tx6; - up->parity_mask = 0x3f; - break; - case CS7: - up->curregs[3] |= Rx7; - up->curregs[5] |= Tx7; - up->parity_mask = 0x7f; - break; - case CS8: - default: - up->curregs[3] |= Rx8; - up->curregs[5] |= Tx8; - up->parity_mask = 0xff; - break; - }; - up->curregs[4] &= ~0x0c; - if (cflag & CSTOPB) - up->curregs[4] |= SB2; - else - up->curregs[4] |= SB1; - if (cflag & PARENB) - up->curregs[4] |= PAR_ENAB; - else - up->curregs[4] &= ~PAR_ENAB; - if (!(cflag & PARODD)) - up->curregs[4] |= PAR_EVEN; - else - up->curregs[4] &= ~PAR_EVEN; - - up->port.read_status_mask = Rx_OVR; - if (iflag & INPCK) - up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= BRK_ABRT; - - up->port.ignore_status_mask = 0; - if (iflag & IGNPAR) - up->port.ignore_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & IGNBRK) { - up->port.ignore_status_mask |= BRK_ABRT; - if (iflag & IGNPAR) - up->port.ignore_status_mask |= Rx_OVR; - } - - if ((cflag & CREAD) == 0) - up->port.ignore_status_mask = 0xff; -} - -/* The port lock is not held. */ -static void -ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; - unsigned long flags; - int baud, brg; - - baud = uart_get_baud_rate(port, termios, old, 1200, 76800); - - spin_lock_irqsave(&up->port.lock, flags); - - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - - ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg); - - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->flags |= IP22ZILOG_FLAG_MODEM_STATUS; - else - up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS; - - ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); - uart_update_timeout(port, termios->c_cflag, baud); - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static const char *ip22zilog_type(struct uart_port *port) -{ - return "IP22-Zilog"; -} - -/* We do not request/release mappings of the registers here, this - * happens at early serial probe time. - */ -static void ip22zilog_release_port(struct uart_port *port) -{ -} - -static int ip22zilog_request_port(struct uart_port *port) -{ - return 0; -} - -/* These do not need to do anything interesting either. */ -static void ip22zilog_config_port(struct uart_port *port, int flags) -{ -} - -/* We do not support letting the user mess with the divisor, IRQ, etc. */ -static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -static struct uart_ops ip22zilog_pops = { - .tx_empty = ip22zilog_tx_empty, - .set_mctrl = ip22zilog_set_mctrl, - .get_mctrl = ip22zilog_get_mctrl, - .stop_tx = ip22zilog_stop_tx, - .start_tx = ip22zilog_start_tx, - .stop_rx = ip22zilog_stop_rx, - .enable_ms = ip22zilog_enable_ms, - .break_ctl = ip22zilog_break_ctl, - .startup = ip22zilog_startup, - .shutdown = ip22zilog_shutdown, - .set_termios = ip22zilog_set_termios, - .type = ip22zilog_type, - .release_port = ip22zilog_release_port, - .request_port = ip22zilog_request_port, - .config_port = ip22zilog_config_port, - .verify_port = ip22zilog_verify_port, -}; - -static struct uart_ip22zilog_port *ip22zilog_port_table; -static struct zilog_layout **ip22zilog_chip_regs; - -static struct uart_ip22zilog_port *ip22zilog_irq_chain; -static int zilog_irq = -1; - -static void * __init alloc_one_table(unsigned long size) -{ - return kzalloc(size, GFP_KERNEL); -} - -static void __init ip22zilog_alloc_tables(void) -{ - ip22zilog_port_table = (struct uart_ip22zilog_port *) - alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port)); - ip22zilog_chip_regs = (struct zilog_layout **) - alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *)); - - if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) { - panic("IP22-Zilog: Cannot allocate IP22-Zilog tables."); - } -} - -/* Get the address of the registers for IP22-Zilog instance CHIP. */ -static struct zilog_layout * __init get_zs(int chip) -{ - unsigned long base; - - if (chip < 0 || chip >= NUM_IP22ZILOG) { - panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip); - } - - /* Not probe-able, hard code it. */ - base = (unsigned long) &sgioc->uart; - - zilog_irq = SGI_SERIAL_IRQ; - request_mem_region(base, 8, "IP22-Zilog"); - - return (struct zilog_layout *) base; -} - -#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ - -#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE -static void ip22zilog_put_char(struct uart_port *port, int ch) -{ - struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); - int loops = ZS_PUT_CHAR_MAX_DELAY; - - /* This is a timed polling loop so do not switch the explicit - * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM - */ - do { - unsigned char val = readb(&channel->control); - if (val & Tx_BUF_EMP) { - ZSDELAY(); - break; - } - udelay(5); - } while (--loops); - - writeb(ch, &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); -} - -static void -ip22zilog_console_write(struct console *con, const char *s, unsigned int count) -{ - struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - uart_console_write(&up->port, s, count, ip22zilog_put_char); - udelay(2); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static int __init ip22zilog_console_setup(struct console *con, char *options) -{ - struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; - unsigned long flags; - int baud = 9600, bits = 8; - int parity = 'n'; - int flow = 'n'; - - up->flags |= IP22ZILOG_FLAG_IS_CONS; - - printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index); - - spin_lock_irqsave(&up->port.lock, flags); - - up->curregs[R15] |= BRKIE; - - __ip22zilog_startup(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(&up->port, con, baud, parity, bits, flow); -} - -static struct uart_driver ip22zilog_reg; - -static struct console ip22zilog_console = { - .name = "ttyS", - .write = ip22zilog_console_write, - .device = uart_console_device, - .setup = ip22zilog_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &ip22zilog_reg, -}; -#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */ - -static struct uart_driver ip22zilog_reg = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = NUM_CHANNELS, -#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE - .cons = &ip22zilog_console, -#endif -}; - -static void __init ip22zilog_prepare(void) -{ - struct uart_ip22zilog_port *up; - struct zilog_layout *rp; - int channel, chip; - - /* - * Temporary fix. - */ - for (channel = 0; channel < NUM_CHANNELS; channel++) - spin_lock_init(&ip22zilog_port_table[channel].port.lock); - - ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1]; - up = &ip22zilog_port_table[0]; - for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--) - up[channel].next = &up[channel - 1]; - up[channel].next = NULL; - - for (chip = 0; chip < NUM_IP22ZILOG; chip++) { - if (!ip22zilog_chip_regs[chip]) { - ip22zilog_chip_regs[chip] = rp = get_zs(chip); - - up[(chip * 2) + 0].port.membase = (char *) &rp->channelB; - up[(chip * 2) + 1].port.membase = (char *) &rp->channelA; - - /* In theory mapbase is the physical address ... */ - up[(chip * 2) + 0].port.mapbase = - (unsigned long) ioremap((unsigned long) &rp->channelB, 8); - up[(chip * 2) + 1].port.mapbase = - (unsigned long) ioremap((unsigned long) &rp->channelA, 8); - } - - /* Channel A */ - up[(chip * 2) + 0].port.iotype = UPIO_MEM; - up[(chip * 2) + 0].port.irq = zilog_irq; - up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 0].port.fifosize = 1; - up[(chip * 2) + 0].port.ops = &ip22zilog_pops; - up[(chip * 2) + 0].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 0].port.flags = 0; - up[(chip * 2) + 0].port.line = (chip * 2) + 0; - up[(chip * 2) + 0].flags = 0; - - /* Channel B */ - up[(chip * 2) + 1].port.iotype = UPIO_MEM; - up[(chip * 2) + 1].port.irq = zilog_irq; - up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 1].port.fifosize = 1; - up[(chip * 2) + 1].port.ops = &ip22zilog_pops; - up[(chip * 2) + 1].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 1].port.line = (chip * 2) + 1; - up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; - } - - for (channel = 0; channel < NUM_CHANNELS; channel++) { - struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel]; - int brg; - - /* Normal serial TTY. */ - up->parity_mask = 0xff; - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRENAB; - } -} - -static int __init ip22zilog_ports_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG); - - ip22zilog_prepare(); - - if (request_irq(zilog_irq, ip22zilog_interrupt, 0, - "IP22-Zilog", ip22zilog_irq_chain)) { - panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); - } - - ret = uart_register_driver(&ip22zilog_reg); - if (ret == 0) { - int i; - - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; - - uart_add_one_port(&ip22zilog_reg, &up->port); - } - } - - return ret; -} - -static int __init ip22zilog_init(void) -{ - /* IP22 Zilog setup is hard coded, no probing to do. */ - ip22zilog_alloc_tables(); - ip22zilog_ports_init(); - - return 0; -} - -static void __exit ip22zilog_exit(void) -{ - int i; - struct uart_ip22zilog_port *up; - - for (i = 0; i < NUM_CHANNELS; i++) { - up = &ip22zilog_port_table[i]; - - uart_remove_one_port(&ip22zilog_reg, &up->port); - } - - /* Free IO mem */ - up = &ip22zilog_port_table[0]; - for (i = 0; i < NUM_IP22ZILOG; i++) { - if (up[(i * 2) + 0].port.mapbase) { - iounmap((void*)up[(i * 2) + 0].port.mapbase); - up[(i * 2) + 0].port.mapbase = 0; - } - if (up[(i * 2) + 1].port.mapbase) { - iounmap((void*)up[(i * 2) + 1].port.mapbase); - up[(i * 2) + 1].port.mapbase = 0; - } - } - - uart_unregister_driver(&ip22zilog_reg); -} - -module_init(ip22zilog_init); -module_exit(ip22zilog_exit); - -/* David wrote it but I'm to blame for the bugs ... */ -MODULE_AUTHOR("Ralf Baechle "); -MODULE_DESCRIPTION("SGI Zilog serial port driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/ip22zilog.h b/drivers/serial/ip22zilog.h deleted file mode 100644 index a59a9a8341d2..000000000000 --- a/drivers/serial/ip22zilog.h +++ /dev/null @@ -1,281 +0,0 @@ -#ifndef _IP22_ZILOG_H -#define _IP22_ZILOG_H - -#include - -struct zilog_channel { -#ifdef __BIG_ENDIAN - volatile unsigned char unused0[3]; - volatile unsigned char control; - volatile unsigned char unused1[3]; - volatile unsigned char data; -#else /* __LITTLE_ENDIAN */ - volatile unsigned char control; - volatile unsigned char unused0[3]; - volatile unsigned char data; - volatile unsigned char unused1[3]; -#endif -}; - -struct zilog_layout { - struct zilog_channel channelB; - struct zilog_channel channelA; -}; - -#define NUM_ZSREGS 16 - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* The Zilog register set */ - -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ -#define RxINT_MASK 0x18 - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENAB 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ -#define RxN_MASK 0xc0 - -/* Write Register 4 */ - -#define PAR_ENAB 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ -#define XCLK_MASK 0xC0 - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define TxN_MASK 0x60 -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENAB 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ -#define CHB_Tx_EMPTY 0x00 -#define CHB_EXT_STAT 0x02 -#define CHB_Rx_AVAIL 0x04 -#define CHB_SPECIAL 0x06 -#define CHA_Tx_EMPTY 0x08 -#define CHA_EXT_STAT 0x0a -#define CHA_Rx_AVAIL 0x0c -#define CHA_SPECIAL 0x0e -#define STATUS_MASK 0x0e - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* Misc macros */ -#define ZS_CLEARERR(channel) do { writeb(ERR_RES, &channel->control); \ - udelay(5); } while(0) - -#define ZS_CLEARSTAT(channel) do { writeb(RES_EXT_INT, &channel->control); \ - udelay(5); } while(0) - -#define ZS_CLEARFIFO(channel) do { readb(&channel->data); \ - udelay(2); \ - readb(&channel->data); \ - udelay(2); \ - readb(&channel->data); \ - udelay(2); } while(0) - -#endif /* _IP22_ZILOG_H */ diff --git a/drivers/serial/jsm/Makefile b/drivers/serial/jsm/Makefile deleted file mode 100644 index e46b6e0f8b18..000000000000 --- a/drivers/serial/jsm/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for Jasmine adapter -# - -obj-$(CONFIG_SERIAL_JSM) += jsm.o - -jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o - diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h deleted file mode 100644 index 38a509c684cd..000000000000 --- a/drivers/serial/jsm/jsm.h +++ /dev/null @@ -1,388 +0,0 @@ -/************************************************************************ - * Copyright 2003 Digi International (www.digi.com) - * - * Copyright (C) 2004 IBM Corporation. All rights reserved. - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. - * - * Contact Information: - * Scott H Kilau - * Wendy Xiong - * - ***********************************************************************/ - -#ifndef __JSM_DRIVER_H -#define __JSM_DRIVER_H - -#include -#include /* To pick up the varions Linux types */ -#include -#include -#include - -/* - * Debugging levels can be set using debug insmod variable - * They can also be compiled out completely. - */ -enum { - DBG_INIT = 0x01, - DBG_BASIC = 0x02, - DBG_CORE = 0x04, - DBG_OPEN = 0x08, - DBG_CLOSE = 0x10, - DBG_READ = 0x20, - DBG_WRITE = 0x40, - DBG_IOCTL = 0x80, - DBG_PROC = 0x100, - DBG_PARAM = 0x200, - DBG_PSCAN = 0x400, - DBG_EVENT = 0x800, - DBG_DRAIN = 0x1000, - DBG_MSIGS = 0x2000, - DBG_MGMT = 0x4000, - DBG_INTR = 0x8000, - DBG_CARR = 0x10000, -}; - -#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \ - if ((DBG_##nlevel & jsm_debug)) \ - dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) - -#define MAXLINES 256 -#define MAXPORTS 8 -#define MAX_STOPS_SENT 5 - -/* Board type definitions */ - -#define T_NEO 0000 -#define T_CLASSIC 0001 -#define T_PCIBUS 0400 - -/* Board State Definitions */ - -#define BD_RUNNING 0x0 -#define BD_REASON 0x7f -#define BD_NOTFOUND 0x1 -#define BD_NOIOPORT 0x2 -#define BD_NOMEM 0x3 -#define BD_NOBIOS 0x4 -#define BD_NOFEP 0x5 -#define BD_FAILED 0x6 -#define BD_ALLOCATED 0x7 -#define BD_TRIBOOT 0x8 -#define BD_BADKME 0x80 - - -/* 4 extra for alignment play space */ -#define WRITEBUFLEN ((4096) + 4) -#define MYFLIPLEN N_TTY_BUF_SIZE - -#define JSM_VERSION "jsm: 1.2-1-INKERNEL" -#define JSM_PARTNUM "40002438_A-INKERNEL" - -struct jsm_board; -struct jsm_channel; - -/************************************************************************ - * Per board operations structure * - ************************************************************************/ -struct board_ops { - irq_handler_t intr; - void (*uart_init) (struct jsm_channel *ch); - void (*uart_off) (struct jsm_channel *ch); - void (*param) (struct jsm_channel *ch); - void (*assert_modem_signals) (struct jsm_channel *ch); - void (*flush_uart_write) (struct jsm_channel *ch); - void (*flush_uart_read) (struct jsm_channel *ch); - void (*disable_receiver) (struct jsm_channel *ch); - void (*enable_receiver) (struct jsm_channel *ch); - void (*send_break) (struct jsm_channel *ch); - void (*clear_break) (struct jsm_channel *ch, int); - void (*send_start_character) (struct jsm_channel *ch); - void (*send_stop_character) (struct jsm_channel *ch); - void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch); - u32 (*get_uart_bytes_left) (struct jsm_channel *ch); - void (*send_immediate_char) (struct jsm_channel *ch, unsigned char); -}; - - -/* - * Per-board information - */ -struct jsm_board -{ - int boardnum; /* Board number: 0-32 */ - - int type; /* Type of board */ - u8 rev; /* PCI revision ID */ - struct pci_dev *pci_dev; - u32 maxports; /* MAX ports this board can handle */ - - spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and - * the interrupt routine from each other. - */ - - u32 nasync; /* Number of ports on card */ - - u32 irq; /* Interrupt request number */ - - u64 membase; /* Start of base memory of the card */ - u64 membase_end; /* End of base memory of the card */ - - u8 __iomem *re_map_membase;/* Remapped memory of the card */ - - u64 iobase; /* Start of io base of the card */ - u64 iobase_end; /* End of io base of the card */ - - u32 bd_uart_offset; /* Space between each UART */ - - struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */ - char *flipbuf; /* Our flip buffer, alloced if board is found */ - - u32 bd_dividend; /* Board/UARTs specific dividend */ - - struct board_ops *bd_ops; - - struct list_head jsm_board_entry; -}; - -/************************************************************************ - * Device flag definitions for ch_flags. - ************************************************************************/ -#define CH_PRON 0x0001 /* Printer on string */ -#define CH_STOP 0x0002 /* Output is stopped */ -#define CH_STOPI 0x0004 /* Input is stopped */ -#define CH_CD 0x0008 /* Carrier is present */ -#define CH_FCAR 0x0010 /* Carrier forced on */ -#define CH_HANGUP 0x0020 /* Hangup received */ - -#define CH_RECEIVER_OFF 0x0040 /* Receiver is off */ -#define CH_OPENING 0x0080 /* Port in fragile open state */ -#define CH_CLOSING 0x0100 /* Port in fragile close state */ -#define CH_FIFO_ENABLED 0x0200 /* Port has FIFOs enabled */ -#define CH_TX_FIFO_EMPTY 0x0400 /* TX Fifo is completely empty */ -#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */ -#define CH_BREAK_SENDING 0x1000 /* Break is being sent */ -#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */ -#define CH_FLIPBUF_IN_USE 0x4000 /* Channel's flipbuf is in use */ -#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */ - -/* Our Read/Error/Write queue sizes */ -#define RQUEUEMASK 0x1FFF /* 8 K - 1 */ -#define EQUEUEMASK 0x1FFF /* 8 K - 1 */ -#define WQUEUEMASK 0x0FFF /* 4 K - 1 */ -#define RQUEUESIZE (RQUEUEMASK + 1) -#define EQUEUESIZE RQUEUESIZE -#define WQUEUESIZE (WQUEUEMASK + 1) - - -/************************************************************************ - * Channel information structure. - ************************************************************************/ -struct jsm_channel { - struct uart_port uart_port; - struct jsm_board *ch_bd; /* Board structure pointer */ - - spinlock_t ch_lock; /* provide for serialization */ - wait_queue_head_t ch_flags_wait; - - u32 ch_portnum; /* Port number, 0 offset. */ - u32 ch_open_count; /* open count */ - u32 ch_flags; /* Channel flags */ - - u64 ch_close_delay; /* How long we should drop RTS/DTR for */ - - tcflag_t ch_c_iflag; /* channel iflags */ - tcflag_t ch_c_cflag; /* channel cflags */ - tcflag_t ch_c_oflag; /* channel oflags */ - tcflag_t ch_c_lflag; /* channel lflags */ - u8 ch_stopc; /* Stop character */ - u8 ch_startc; /* Start character */ - - u8 ch_mostat; /* FEP output modem status */ - u8 ch_mistat; /* FEP input modem status */ - - struct neo_uart_struct __iomem *ch_neo_uart; /* Pointer to the "mapped" UART struct */ - u8 ch_cached_lsr; /* Cached value of the LSR register */ - - u8 *ch_rqueue; /* Our read queue buffer - malloc'ed */ - u16 ch_r_head; /* Head location of the read queue */ - u16 ch_r_tail; /* Tail location of the read queue */ - - u8 *ch_equeue; /* Our error queue buffer - malloc'ed */ - u16 ch_e_head; /* Head location of the error queue */ - u16 ch_e_tail; /* Tail location of the error queue */ - - u8 *ch_wqueue; /* Our write queue buffer - malloc'ed */ - u16 ch_w_head; /* Head location of the write queue */ - u16 ch_w_tail; /* Tail location of the write queue */ - - u64 ch_rxcount; /* total of data received so far */ - u64 ch_txcount; /* total of data transmitted so far */ - - u8 ch_r_tlevel; /* Receive Trigger level */ - u8 ch_t_tlevel; /* Transmit Trigger level */ - - u8 ch_r_watermark; /* Receive Watermark */ - - - u32 ch_stops_sent; /* How many times I have sent a stop character - * to try to stop the other guy sending. - */ - u64 ch_err_parity; /* Count of parity errors on channel */ - u64 ch_err_frame; /* Count of framing errors on channel */ - u64 ch_err_break; /* Count of breaks on channel */ - u64 ch_err_overrun; /* Count of overruns on channel */ - - u64 ch_xon_sends; /* Count of xons transmitted */ - u64 ch_xoff_sends; /* Count of xoffs transmitted */ -}; - - -/************************************************************************ - * Per channel/port NEO UART structure * - ************************************************************************ - * Base Structure Entries Usage Meanings to Host * - * * - * W = read write R = read only * - * U = Unused. * - ************************************************************************/ - -struct neo_uart_struct { - u8 txrx; /* WR RHR/THR - Holding Reg */ - u8 ier; /* WR IER - Interrupt Enable Reg */ - u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg */ - u8 lcr; /* WR LCR - Line Control Reg */ - u8 mcr; /* WR MCR - Modem Control Reg */ - u8 lsr; /* WR LSR - Line Status Reg */ - u8 msr; /* WR MSR - Modem Status Reg */ - u8 spr; /* WR SPR - Scratch Pad Reg */ - u8 fctr; /* WR FCTR - Feature Control Reg */ - u8 efr; /* WR EFR - Enhanced Function Reg */ - u8 tfifo; /* WR TXCNT/TXTRG - Transmit FIFO Reg */ - u8 rfifo; /* WR RXCNT/RXTRG - Recieve FIFO Reg */ - u8 xoffchar1; /* WR XOFF 1 - XOff Character 1 Reg */ - u8 xoffchar2; /* WR XOFF 2 - XOff Character 2 Reg */ - u8 xonchar1; /* WR XON 1 - Xon Character 1 Reg */ - u8 xonchar2; /* WR XON 2 - XOn Character 2 Reg */ - - u8 reserved1[0x2ff - 0x200]; /* U Reserved by Exar */ - u8 txrxburst[64]; /* RW 64 bytes of RX/TX FIFO Data */ - u8 reserved2[0x37f - 0x340]; /* U Reserved by Exar */ - u8 rxburst_with_errors[64]; /* R 64 bytes of RX FIFO Data + LSR */ -}; - -/* Where to read the extended interrupt register (32bits instead of 8bits) */ -#define UART_17158_POLL_ADDR_OFFSET 0x80 - -/* - * These are the redefinitions for the FCTR on the XR17C158, since - * Exar made them different than their earlier design. (XR16C854) - */ - -/* These are only applicable when table D is selected */ -#define UART_17158_FCTR_RTS_NODELAY 0x00 -#define UART_17158_FCTR_RTS_4DELAY 0x01 -#define UART_17158_FCTR_RTS_6DELAY 0x02 -#define UART_17158_FCTR_RTS_8DELAY 0x03 -#define UART_17158_FCTR_RTS_12DELAY 0x12 -#define UART_17158_FCTR_RTS_16DELAY 0x05 -#define UART_17158_FCTR_RTS_20DELAY 0x13 -#define UART_17158_FCTR_RTS_24DELAY 0x06 -#define UART_17158_FCTR_RTS_28DELAY 0x14 -#define UART_17158_FCTR_RTS_32DELAY 0x07 -#define UART_17158_FCTR_RTS_36DELAY 0x16 -#define UART_17158_FCTR_RTS_40DELAY 0x08 -#define UART_17158_FCTR_RTS_44DELAY 0x09 -#define UART_17158_FCTR_RTS_48DELAY 0x10 -#define UART_17158_FCTR_RTS_52DELAY 0x11 - -#define UART_17158_FCTR_RTS_IRDA 0x10 -#define UART_17158_FCTR_RS485 0x20 -#define UART_17158_FCTR_TRGA 0x00 -#define UART_17158_FCTR_TRGB 0x40 -#define UART_17158_FCTR_TRGC 0x80 -#define UART_17158_FCTR_TRGD 0xC0 - -/* 17158 trigger table selects.. */ -#define UART_17158_FCTR_BIT6 0x40 -#define UART_17158_FCTR_BIT7 0x80 - -/* 17158 TX/RX memmapped buffer offsets */ -#define UART_17158_RX_FIFOSIZE 64 -#define UART_17158_TX_FIFOSIZE 64 - -/* 17158 Extended IIR's */ -#define UART_17158_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */ -#define UART_17158_IIR_XONXOFF 0x10 /* Received an XON/XOFF char */ -#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20 /* CTS/DSR or RTS/DTR state change */ -#define UART_17158_IIR_FIFO_ENABLED 0xC0 /* 16550 FIFOs are Enabled */ - -/* - * These are the extended interrupts that get sent - * back to us from the UART's 32bit interrupt register - */ -#define UART_17158_RX_LINE_STATUS 0x1 /* RX Ready */ -#define UART_17158_RXRDY_TIMEOUT 0x2 /* RX Ready Timeout */ -#define UART_17158_TXRDY 0x3 /* TX Ready */ -#define UART_17158_MSR 0x4 /* Modem State Change */ -#define UART_17158_TX_AND_FIFO_CLR 0x40 /* Transmitter Holding Reg Empty */ -#define UART_17158_RX_FIFO_DATA_ERROR 0x80 /* UART detected an RX FIFO Data error */ - -/* - * These are the EXTENDED definitions for the 17C158's Interrupt - * Enable Register. - */ -#define UART_17158_EFR_ECB 0x10 /* Enhanced control bit */ -#define UART_17158_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */ -#define UART_17158_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */ -#define UART_17158_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */ -#define UART_17158_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */ - -#define UART_17158_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */ -#define UART_17158_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */ - -#define UART_17158_IER_RSVD1 0x10 /* Reserved by Exar */ -#define UART_17158_IER_XOFF 0x20 /* Xoff Interrupt Enable */ -#define UART_17158_IER_RTSDTR 0x40 /* Output Interrupt Enable */ -#define UART_17158_IER_CTSDSR 0x80 /* Input Interrupt Enable */ - -#define PCI_DEVICE_NEO_2DB9_PCI_NAME "Neo 2 - DB9 Universal PCI" -#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator" -#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI" -#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator" -#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM" - -/* - * Our Global Variables. - */ -extern struct uart_driver jsm_uart_driver; -extern struct board_ops jsm_neo_ops; -extern int jsm_debug; - -/************************************************************************* - * - * Prototypes for non-static functions used in more than one module - * - *************************************************************************/ -int jsm_tty_write(struct uart_port *port); -int jsm_tty_init(struct jsm_board *); -int jsm_uart_port_init(struct jsm_board *); -int jsm_remove_uart_port(struct jsm_board *); -void jsm_input(struct jsm_channel *ch); -void jsm_check_queue_flow_control(struct jsm_channel *ch); - -#endif diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c deleted file mode 100644 index 18f548449c63..000000000000 --- a/drivers/serial/jsm/jsm_driver.c +++ /dev/null @@ -1,297 +0,0 @@ -/************************************************************************ - * Copyright 2003 Digi International (www.digi.com) - * - * Copyright (C) 2004 IBM Corporation. All rights reserved. - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. - * - * Contact Information: - * Scott H Kilau - * Wendy Xiong - * - * - ***********************************************************************/ -#include -#include -#include - -#include "jsm.h" - -MODULE_AUTHOR("Digi International, http://www.digi.com"); -MODULE_DESCRIPTION("Driver for the Digi International " - "Neo PCI based product line"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("jsm"); - -#define JSM_DRIVER_NAME "jsm" -#define NR_PORTS 32 -#define JSM_MINOR_START 0 - -struct uart_driver jsm_uart_driver = { - .owner = THIS_MODULE, - .driver_name = JSM_DRIVER_NAME, - .dev_name = "ttyn", - .major = 0, - .minor = JSM_MINOR_START, - .nr = NR_PORTS, -}; - -static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state); -static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev); -static void jsm_io_resume(struct pci_dev *pdev); - -static struct pci_error_handlers jsm_err_handler = { - .error_detected = jsm_io_error_detected, - .slot_reset = jsm_io_slot_reset, - .resume = jsm_io_resume, -}; - -int jsm_debug; -module_param(jsm_debug, int, 0); -MODULE_PARM_DESC(jsm_debug, "Driver debugging level"); - -static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int rc = 0; - struct jsm_board *brd; - static int adapter_count = 0; - - rc = pci_enable_device(pdev); - if (rc) { - dev_err(&pdev->dev, "Device enable FAILED\n"); - goto out; - } - - rc = pci_request_regions(pdev, "jsm"); - if (rc) { - dev_err(&pdev->dev, "pci_request_region FAILED\n"); - goto out_disable_device; - } - - brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL); - if (!brd) { - dev_err(&pdev->dev, - "memory allocation for board structure failed\n"); - rc = -ENOMEM; - goto out_release_regions; - } - - /* store the info for the board we've found */ - brd->boardnum = adapter_count++; - brd->pci_dev = pdev; - if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM) - brd->maxports = 4; - else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8) - brd->maxports = 8; - else - brd->maxports = 2; - - spin_lock_init(&brd->bd_intr_lock); - - /* store which revision we have */ - brd->rev = pdev->revision; - - brd->irq = pdev->irq; - - jsm_printk(INIT, INFO, &brd->pci_dev, - "jsm_found_board - NEO adapter\n"); - - /* get the PCI Base Address Registers */ - brd->membase = pci_resource_start(pdev, 0); - brd->membase_end = pci_resource_end(pdev, 0); - - if (brd->membase & 1) - brd->membase &= ~3; - else - brd->membase &= ~15; - - /* Assign the board_ops struct */ - brd->bd_ops = &jsm_neo_ops; - - brd->bd_uart_offset = 0x200; - brd->bd_dividend = 921600; - - brd->re_map_membase = ioremap(brd->membase, 0x1000); - if (!brd->re_map_membase) { - dev_err(&pdev->dev, - "card has no PCI Memory resources, " - "failing board.\n"); - rc = -ENOMEM; - goto out_kfree_brd; - } - - rc = request_irq(brd->irq, brd->bd_ops->intr, - IRQF_SHARED, "JSM", brd); - if (rc) { - printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq); - goto out_iounmap; - } - - rc = jsm_tty_init(brd); - if (rc < 0) { - dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc); - rc = -ENXIO; - goto out_free_irq; - } - - rc = jsm_uart_port_init(brd); - if (rc < 0) { - /* XXX: leaking all resources from jsm_tty_init here! */ - dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc); - rc = -ENXIO; - goto out_free_irq; - } - - /* Log the information about the board */ - dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n", - adapter_count, brd->rev, brd->irq); - - /* - * allocate flip buffer for board. - * - * Okay to malloc with GFP_KERNEL, we are not at interrupt - * context, and there are no locks held. - */ - brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); - if (!brd->flipbuf) { - /* XXX: leaking all resources from jsm_tty_init and - jsm_uart_port_init here! */ - dev_err(&pdev->dev, "memory allocation for flipbuf failed\n"); - rc = -ENOMEM; - goto out_free_uart; - } - - pci_set_drvdata(pdev, brd); - pci_save_state(pdev); - - return 0; - out_free_uart: - jsm_remove_uart_port(brd); - out_free_irq: - jsm_remove_uart_port(brd); - free_irq(brd->irq, brd); - out_iounmap: - iounmap(brd->re_map_membase); - out_kfree_brd: - kfree(brd); - out_release_regions: - pci_release_regions(pdev); - out_disable_device: - pci_disable_device(pdev); - out: - return rc; -} - -static void __devexit jsm_remove_one(struct pci_dev *pdev) -{ - struct jsm_board *brd = pci_get_drvdata(pdev); - int i = 0; - - jsm_remove_uart_port(brd); - - free_irq(brd->irq, brd); - iounmap(brd->re_map_membase); - - /* Free all allocated channels structs */ - for (i = 0; i < brd->maxports; i++) { - if (brd->channels[i]) { - kfree(brd->channels[i]->ch_rqueue); - kfree(brd->channels[i]->ch_equeue); - kfree(brd->channels[i]->ch_wqueue); - kfree(brd->channels[i]); - } - } - - pci_release_regions(pdev); - pci_disable_device(pdev); - kfree(brd->flipbuf); - kfree(brd); -} - -static struct pci_device_id jsm_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, jsm_pci_tbl); - -static struct pci_driver jsm_driver = { - .name = "jsm", - .id_table = jsm_pci_tbl, - .probe = jsm_probe_one, - .remove = __devexit_p(jsm_remove_one), - .err_handler = &jsm_err_handler, -}; - -static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - struct jsm_board *brd = pci_get_drvdata(pdev); - - jsm_remove_uart_port(brd); - - return PCI_ERS_RESULT_NEED_RESET; -} - -static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev) -{ - int rc; - - rc = pci_enable_device(pdev); - - if (rc) - return PCI_ERS_RESULT_DISCONNECT; - - pci_set_master(pdev); - - return PCI_ERS_RESULT_RECOVERED; -} - -static void jsm_io_resume(struct pci_dev *pdev) -{ - struct jsm_board *brd = pci_get_drvdata(pdev); - - pci_restore_state(pdev); - - jsm_uart_port_init(brd); -} - -static int __init jsm_init_module(void) -{ - int rc; - - rc = uart_register_driver(&jsm_uart_driver); - if (!rc) { - rc = pci_register_driver(&jsm_driver); - if (rc) - uart_unregister_driver(&jsm_uart_driver); - } - return rc; -} - -static void __exit jsm_exit_module(void) -{ - pci_unregister_driver(&jsm_driver); - uart_unregister_driver(&jsm_uart_driver); -} - -module_init(jsm_init_module); -module_exit(jsm_exit_module); diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c deleted file mode 100644 index 7960d9633c15..000000000000 --- a/drivers/serial/jsm/jsm_neo.c +++ /dev/null @@ -1,1412 +0,0 @@ -/************************************************************************ - * Copyright 2003 Digi International (www.digi.com) - * - * Copyright (C) 2004 IBM Corporation. All rights reserved. - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. - * - * Contact Information: - * Scott H Kilau - * Wendy Xiong - * - ***********************************************************************/ -#include /* For udelay */ -#include /* For the various UART offsets */ -#include -#include -#include - -#include "jsm.h" /* Driver main header file */ - -static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; - -/* - * This function allows calls to ensure that all outstanding - * PCI writes have been completed, by doing a PCI read against - * a non-destructive, read-only location on the Neo card. - * - * In this case, we are reading the DVID (Read-only Device Identification) - * value of the Neo card. - */ -static inline void neo_pci_posting_flush(struct jsm_board *bd) -{ - readb(bd->re_map_membase + 0x8D); -} - -static void neo_set_cts_flow_control(struct jsm_channel *ch) -{ - u8 ier, efr; - ier = readb(&ch->ch_neo_uart->ier); - efr = readb(&ch->ch_neo_uart->efr); - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n"); - - /* Turn on auto CTS flow control */ - ier |= (UART_17158_IER_CTSDSR); - efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR); - - /* Turn off auto Xon flow control */ - efr &= ~(UART_17158_EFR_IXON); - - /* Why? Becuz Exar's spec says we have to zero it out before setting it */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Turn on UART enhanced bits */ - writeb(efr, &ch->ch_neo_uart->efr); - - /* Turn on table D, with 8 char hi/low watermarks */ - writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); - - /* Feed the UART our trigger levels */ - writeb(8, &ch->ch_neo_uart->tfifo); - ch->ch_t_tlevel = 8; - - writeb(ier, &ch->ch_neo_uart->ier); -} - -static void neo_set_rts_flow_control(struct jsm_channel *ch) -{ - u8 ier, efr; - ier = readb(&ch->ch_neo_uart->ier); - efr = readb(&ch->ch_neo_uart->efr); - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n"); - - /* Turn on auto RTS flow control */ - ier |= (UART_17158_IER_RTSDTR); - efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR); - - /* Turn off auto Xoff flow control */ - ier &= ~(UART_17158_IER_XOFF); - efr &= ~(UART_17158_EFR_IXOFF); - - /* Why? Becuz Exar's spec says we have to zero it out before setting it */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Turn on UART enhanced bits */ - writeb(efr, &ch->ch_neo_uart->efr); - - writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); - ch->ch_r_watermark = 4; - - writeb(56, &ch->ch_neo_uart->rfifo); - ch->ch_r_tlevel = 56; - - writeb(ier, &ch->ch_neo_uart->ier); - - /* - * From the Neo UART spec sheet: - * The auto RTS/DTR function must be started by asserting - * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after - * it is enabled. - */ - ch->ch_mostat |= (UART_MCR_RTS); -} - - -static void neo_set_ixon_flow_control(struct jsm_channel *ch) -{ - u8 ier, efr; - ier = readb(&ch->ch_neo_uart->ier); - efr = readb(&ch->ch_neo_uart->efr); - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n"); - - /* Turn off auto CTS flow control */ - ier &= ~(UART_17158_IER_CTSDSR); - efr &= ~(UART_17158_EFR_CTSDSR); - - /* Turn on auto Xon flow control */ - efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON); - - /* Why? Becuz Exar's spec says we have to zero it out before setting it */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Turn on UART enhanced bits */ - writeb(efr, &ch->ch_neo_uart->efr); - - writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); - ch->ch_r_watermark = 4; - - writeb(32, &ch->ch_neo_uart->rfifo); - ch->ch_r_tlevel = 32; - - /* Tell UART what start/stop chars it should be looking for */ - writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); - writeb(0, &ch->ch_neo_uart->xonchar2); - - writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); - writeb(0, &ch->ch_neo_uart->xoffchar2); - - writeb(ier, &ch->ch_neo_uart->ier); -} - -static void neo_set_ixoff_flow_control(struct jsm_channel *ch) -{ - u8 ier, efr; - ier = readb(&ch->ch_neo_uart->ier); - efr = readb(&ch->ch_neo_uart->efr); - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n"); - - /* Turn off auto RTS flow control */ - ier &= ~(UART_17158_IER_RTSDTR); - efr &= ~(UART_17158_EFR_RTSDTR); - - /* Turn on auto Xoff flow control */ - ier |= (UART_17158_IER_XOFF); - efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); - - /* Why? Becuz Exar's spec says we have to zero it out before setting it */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Turn on UART enhanced bits */ - writeb(efr, &ch->ch_neo_uart->efr); - - /* Turn on table D, with 8 char hi/low watermarks */ - writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); - - writeb(8, &ch->ch_neo_uart->tfifo); - ch->ch_t_tlevel = 8; - - /* Tell UART what start/stop chars it should be looking for */ - writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); - writeb(0, &ch->ch_neo_uart->xonchar2); - - writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); - writeb(0, &ch->ch_neo_uart->xoffchar2); - - writeb(ier, &ch->ch_neo_uart->ier); -} - -static void neo_set_no_input_flow_control(struct jsm_channel *ch) -{ - u8 ier, efr; - ier = readb(&ch->ch_neo_uart->ier); - efr = readb(&ch->ch_neo_uart->efr); - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n"); - - /* Turn off auto RTS flow control */ - ier &= ~(UART_17158_IER_RTSDTR); - efr &= ~(UART_17158_EFR_RTSDTR); - - /* Turn off auto Xoff flow control */ - ier &= ~(UART_17158_IER_XOFF); - if (ch->ch_c_iflag & IXON) - efr &= ~(UART_17158_EFR_IXOFF); - else - efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); - - /* Why? Becuz Exar's spec says we have to zero it out before setting it */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Turn on UART enhanced bits */ - writeb(efr, &ch->ch_neo_uart->efr); - - /* Turn on table D, with 8 char hi/low watermarks */ - writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); - - ch->ch_r_watermark = 0; - - writeb(16, &ch->ch_neo_uart->tfifo); - ch->ch_t_tlevel = 16; - - writeb(16, &ch->ch_neo_uart->rfifo); - ch->ch_r_tlevel = 16; - - writeb(ier, &ch->ch_neo_uart->ier); -} - -static void neo_set_no_output_flow_control(struct jsm_channel *ch) -{ - u8 ier, efr; - ier = readb(&ch->ch_neo_uart->ier); - efr = readb(&ch->ch_neo_uart->efr); - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n"); - - /* Turn off auto CTS flow control */ - ier &= ~(UART_17158_IER_CTSDSR); - efr &= ~(UART_17158_EFR_CTSDSR); - - /* Turn off auto Xon flow control */ - if (ch->ch_c_iflag & IXOFF) - efr &= ~(UART_17158_EFR_IXON); - else - efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON); - - /* Why? Becuz Exar's spec says we have to zero it out before setting it */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Turn on UART enhanced bits */ - writeb(efr, &ch->ch_neo_uart->efr); - - /* Turn on table D, with 8 char hi/low watermarks */ - writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); - - ch->ch_r_watermark = 0; - - writeb(16, &ch->ch_neo_uart->tfifo); - ch->ch_t_tlevel = 16; - - writeb(16, &ch->ch_neo_uart->rfifo); - ch->ch_r_tlevel = 16; - - writeb(ier, &ch->ch_neo_uart->ier); -} - -static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch) -{ - - /* if hardware flow control is set, then skip this whole thing */ - if (ch->ch_c_cflag & CRTSCTS) - return; - - jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n"); - - /* Tell UART what start/stop chars it should be looking for */ - writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); - writeb(0, &ch->ch_neo_uart->xonchar2); - - writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); - writeb(0, &ch->ch_neo_uart->xoffchar2); -} - -static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) -{ - int qleft = 0; - u8 linestatus = 0; - u8 error_mask = 0; - int n = 0; - int total = 0; - u16 head; - u16 tail; - - if (!ch) - return; - - /* cache head and tail of queue */ - head = ch->ch_r_head & RQUEUEMASK; - tail = ch->ch_r_tail & RQUEUEMASK; - - /* Get our cached LSR */ - linestatus = ch->ch_cached_lsr; - ch->ch_cached_lsr = 0; - - /* Store how much space we have left in the queue */ - if ((qleft = tail - head - 1) < 0) - qleft += RQUEUEMASK + 1; - - /* - * If the UART is not in FIFO mode, force the FIFO copy to - * NOT be run, by setting total to 0. - * - * On the other hand, if the UART IS in FIFO mode, then ask - * the UART to give us an approximation of data it has RX'ed. - */ - if (!(ch->ch_flags & CH_FIFO_ENABLED)) - total = 0; - else { - total = readb(&ch->ch_neo_uart->rfifo); - - /* - * EXAR chip bug - RX FIFO COUNT - Fudge factor. - * - * This resolves a problem/bug with the Exar chip that sometimes - * returns a bogus value in the rfifo register. - * The count can be any where from 0-3 bytes "off". - * Bizarre, but true. - */ - total -= 3; - } - - /* - * Finally, bound the copy to make sure we don't overflow - * our own queue... - * The byte by byte copy loop below this loop this will - * deal with the queue overflow possibility. - */ - total = min(total, qleft); - - while (total > 0) { - /* - * Grab the linestatus register, we need to check - * to see if there are any errors in the FIFO. - */ - linestatus = readb(&ch->ch_neo_uart->lsr); - - /* - * Break out if there is a FIFO error somewhere. - * This will allow us to go byte by byte down below, - * finding the exact location of the error. - */ - if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) - break; - - /* Make sure we don't go over the end of our queue */ - n = min(((u32) total), (RQUEUESIZE - (u32) head)); - - /* - * Cut down n even further if needed, this is to fix - * a problem with memcpy_fromio() with the Neo on the - * IBM pSeries platform. - * 15 bytes max appears to be the magic number. - */ - n = min((u32) n, (u32) 12); - - /* - * Since we are grabbing the linestatus register, which - * will reset some bits after our read, we need to ensure - * we don't miss our TX FIFO emptys. - */ - if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - - linestatus = 0; - - /* Copy data from uart to the queue */ - memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n); - /* - * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed - * that all the data currently in the FIFO is free of - * breaks and parity/frame/orun errors. - */ - memset(ch->ch_equeue + head, 0, n); - - /* Add to and flip head if needed */ - head = (head + n) & RQUEUEMASK; - total -= n; - qleft -= n; - ch->ch_rxcount += n; - } - - /* - * Create a mask to determine whether we should - * insert the character (if any) into our queue. - */ - if (ch->ch_c_iflag & IGNBRK) - error_mask |= UART_LSR_BI; - - /* - * Now cleanup any leftover bytes still in the UART. - * Also deal with any possible queue overflow here as well. - */ - while (1) { - - /* - * Its possible we have a linestatus from the loop above - * this, so we "OR" on any extra bits. - */ - linestatus |= readb(&ch->ch_neo_uart->lsr); - - /* - * If the chip tells us there is no more data pending to - * be read, we can then leave. - * But before we do, cache the linestatus, just in case. - */ - if (!(linestatus & UART_LSR_DR)) { - ch->ch_cached_lsr = linestatus; - break; - } - - /* No need to store this bit */ - linestatus &= ~UART_LSR_DR; - - /* - * Since we are grabbing the linestatus register, which - * will reset some bits after our read, we need to ensure - * we don't miss our TX FIFO emptys. - */ - if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) { - linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR); - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - } - - /* - * Discard character if we are ignoring the error mask. - */ - if (linestatus & error_mask) { - u8 discard; - linestatus = 0; - memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1); - continue; - } - - /* - * If our queue is full, we have no choice but to drop some data. - * The assumption is that HWFLOW or SWFLOW should have stopped - * things way way before we got to this point. - * - * I decided that I wanted to ditch the oldest data first, - * I hope thats okay with everyone? Yes? Good. - */ - while (qleft < 1) { - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Queue full, dropping DATA:%x LSR:%x\n", - ch->ch_rqueue[tail], ch->ch_equeue[tail]); - - ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK; - ch->ch_err_overrun++; - qleft++; - } - - memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1); - ch->ch_equeue[head] = (u8) linestatus; - - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]); - - /* Ditch any remaining linestatus value. */ - linestatus = 0; - - /* Add to and flip head if needed */ - head = (head + 1) & RQUEUEMASK; - - qleft--; - ch->ch_rxcount++; - } - - /* - * Write new final heads to channel structure. - */ - ch->ch_r_head = head & RQUEUEMASK; - ch->ch_e_head = head & EQUEUEMASK; - jsm_input(ch); -} - -static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) -{ - u16 head; - u16 tail; - int n; - int s; - int qlen; - u32 len_written = 0; - - if (!ch) - return; - - /* No data to write to the UART */ - if (ch->ch_w_tail == ch->ch_w_head) - return; - - /* If port is "stopped", don't send any data to the UART */ - if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) - return; - /* - * If FIFOs are disabled. Send data directly to txrx register - */ - if (!(ch->ch_flags & CH_FIFO_ENABLED)) { - u8 lsrbits = readb(&ch->ch_neo_uart->lsr); - - ch->ch_cached_lsr |= lsrbits; - if (ch->ch_cached_lsr & UART_LSR_THRE) { - ch->ch_cached_lsr &= ~(UART_LSR_THRE); - - writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx); - jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev, - "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]); - ch->ch_w_tail++; - ch->ch_w_tail &= WQUEUEMASK; - ch->ch_txcount++; - } - return; - } - - /* - * We have to do it this way, because of the EXAR TXFIFO count bug. - */ - if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) - return; - - n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; - - /* cache head and tail of queue */ - head = ch->ch_w_head & WQUEUEMASK; - tail = ch->ch_w_tail & WQUEUEMASK; - qlen = (head - tail) & WQUEUEMASK; - - /* Find minimum of the FIFO space, versus queue length */ - n = min(n, qlen); - - while (n > 0) { - - s = ((head >= tail) ? head : WQUEUESIZE) - tail; - s = min(s, n); - - if (s <= 0) - break; - - memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s); - /* Add and flip queue if needed */ - tail = (tail + s) & WQUEUEMASK; - n -= s; - ch->ch_txcount += s; - len_written += s; - } - - /* Update the final tail */ - ch->ch_w_tail = tail & WQUEUEMASK; - - if (len_written >= ch->ch_t_tlevel) - ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - - if (!jsm_tty_write(&ch->uart_port)) - uart_write_wakeup(&ch->uart_port); -} - -static void neo_parse_modem(struct jsm_channel *ch, u8 signals) -{ - u8 msignals = signals; - - jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, - "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals); - - /* Scrub off lower bits. They signify delta's, which I don't care about */ - /* Keep DDCD and DDSR though */ - msignals &= 0xf8; - - if (msignals & UART_MSR_DDCD) - uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD); - if (msignals & UART_MSR_DDSR) - uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS); - if (msignals & UART_MSR_DCD) - ch->ch_mistat |= UART_MSR_DCD; - else - ch->ch_mistat &= ~UART_MSR_DCD; - - if (msignals & UART_MSR_DSR) - ch->ch_mistat |= UART_MSR_DSR; - else - ch->ch_mistat &= ~UART_MSR_DSR; - - if (msignals & UART_MSR_RI) - ch->ch_mistat |= UART_MSR_RI; - else - ch->ch_mistat &= ~UART_MSR_RI; - - if (msignals & UART_MSR_CTS) - ch->ch_mistat |= UART_MSR_CTS; - else - ch->ch_mistat &= ~UART_MSR_CTS; - - jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, - "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n", - ch->ch_portnum, - !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR), - !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS), - !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS), - !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR), - !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI), - !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)); -} - -/* Make the UART raise any of the output signals we want up */ -static void neo_assert_modem_signals(struct jsm_channel *ch) -{ - if (!ch) - return; - - writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); -} - -/* - * Flush the WRITE FIFO on the Neo. - * - * NOTE: Channel lock MUST be held before calling this function! - */ -static void neo_flush_uart_write(struct jsm_channel *ch) -{ - u8 tmp = 0; - int i = 0; - - if (!ch) - return; - - writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); - - for (i = 0; i < 10; i++) { - - /* Check to see if the UART feels it completely flushed the FIFO. */ - tmp = readb(&ch->ch_neo_uart->isr_fcr); - if (tmp & 4) { - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, - "Still flushing TX UART... i: %d\n", i); - udelay(10); - } - else - break; - } - - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); -} - - -/* - * Flush the READ FIFO on the Neo. - * - * NOTE: Channel lock MUST be held before calling this function! - */ -static void neo_flush_uart_read(struct jsm_channel *ch) -{ - u8 tmp = 0; - int i = 0; - - if (!ch) - return; - - writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr); - - for (i = 0; i < 10; i++) { - - /* Check to see if the UART feels it completely flushed the FIFO. */ - tmp = readb(&ch->ch_neo_uart->isr_fcr); - if (tmp & 2) { - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, - "Still flushing RX UART... i: %d\n", i); - udelay(10); - } - else - break; - } -} - -/* - * No locks are assumed to be held when calling this function. - */ -static void neo_clear_break(struct jsm_channel *ch, int force) -{ - unsigned long lock_flags; - - spin_lock_irqsave(&ch->ch_lock, lock_flags); - - /* Turn break off, and unset some variables */ - if (ch->ch_flags & CH_BREAK_SENDING) { - u8 temp = readb(&ch->ch_neo_uart->lcr); - writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr); - - ch->ch_flags &= ~(CH_BREAK_SENDING); - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, - "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); - } - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); -} - -/* - * Parse the ISR register. - */ -static inline void neo_parse_isr(struct jsm_board *brd, u32 port) -{ - struct jsm_channel *ch; - u8 isr; - u8 cause; - unsigned long lock_flags; - - if (!brd) - return; - - if (port > brd->maxports) - return; - - ch = brd->channels[port]; - if (!ch) - return; - - /* Here we try to figure out what caused the interrupt to happen */ - while (1) { - - isr = readb(&ch->ch_neo_uart->isr_fcr); - - /* Bail if no pending interrupt */ - if (isr & UART_IIR_NO_INT) - break; - - /* - * Yank off the upper 2 bits, which just show that the FIFO's are enabled. - */ - isr &= ~(UART_17158_IIR_FIFO_ENABLED); - - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "%s:%d isr: %x\n", __FILE__, __LINE__, isr); - - if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) { - /* Read data from uart -> queue */ - neo_copy_data_from_uart_to_queue(ch); - - /* Call our tty layer to enforce queue flow control if needed. */ - spin_lock_irqsave(&ch->ch_lock, lock_flags); - jsm_check_queue_flow_control(ch); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - } - - if (isr & UART_IIR_THRI) { - /* Transfer data (if any) from Write Queue -> UART. */ - spin_lock_irqsave(&ch->ch_lock, lock_flags); - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - neo_copy_data_from_queue_to_uart(ch); - } - - if (isr & UART_17158_IIR_XONXOFF) { - cause = readb(&ch->ch_neo_uart->xoffchar1); - - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause); - - /* - * Since the UART detected either an XON or - * XOFF match, we need to figure out which - * one it was, so we can suspend or resume data flow. - */ - spin_lock_irqsave(&ch->ch_lock, lock_flags); - if (cause == UART_17158_XON_DETECT) { - /* Is output stopped right now, if so, resume it */ - if (brd->channels[port]->ch_flags & CH_STOP) { - ch->ch_flags &= ~(CH_STOP); - } - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Port %d. XON detected in incoming data\n", port); - } - else if (cause == UART_17158_XOFF_DETECT) { - if (!(brd->channels[port]->ch_flags & CH_STOP)) { - ch->ch_flags |= CH_STOP; - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Setting CH_STOP\n"); - } - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "Port: %d. XOFF detected in incoming data\n", port); - } - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - } - - if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) { - /* - * If we get here, this means the hardware is doing auto flow control. - * Check to see whether RTS/DTR or CTS/DSR caused this interrupt. - */ - cause = readb(&ch->ch_neo_uart->mcr); - - /* Which pin is doing auto flow? RTS or DTR? */ - spin_lock_irqsave(&ch->ch_lock, lock_flags); - if ((cause & 0x4) == 0) { - if (cause & UART_MCR_RTS) - ch->ch_mostat |= UART_MCR_RTS; - else - ch->ch_mostat &= ~(UART_MCR_RTS); - } else { - if (cause & UART_MCR_DTR) - ch->ch_mostat |= UART_MCR_DTR; - else - ch->ch_mostat &= ~(UART_MCR_DTR); - } - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - } - - /* Parse any modem signal changes */ - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "MOD_STAT: sending to parse_modem_sigs\n"); - neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); - } -} - -static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) -{ - struct jsm_channel *ch; - int linestatus; - unsigned long lock_flags; - - if (!brd) - return; - - if (port > brd->maxports) - return; - - ch = brd->channels[port]; - if (!ch) - return; - - linestatus = readb(&ch->ch_neo_uart->lsr); - - jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, - "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus); - - ch->ch_cached_lsr |= linestatus; - - if (ch->ch_cached_lsr & UART_LSR_DR) { - /* Read data from uart -> queue */ - neo_copy_data_from_uart_to_queue(ch); - spin_lock_irqsave(&ch->ch_lock, lock_flags); - jsm_check_queue_flow_control(ch); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - } - - /* - * This is a special flag. It indicates that at least 1 - * RX error (parity, framing, or break) has happened. - * Mark this in our struct, which will tell me that I have - *to do the special RX+LSR read for this FIFO load. - */ - if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d Got an RX error, need to parse LSR\n", - __FILE__, __LINE__, port); - - /* - * The next 3 tests should *NOT* happen, as the above test - * should encapsulate all 3... At least, thats what Exar says. - */ - - if (linestatus & UART_LSR_PE) { - ch->ch_err_parity++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port); - } - - if (linestatus & UART_LSR_FE) { - ch->ch_err_frame++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port); - } - - if (linestatus & UART_LSR_BI) { - ch->ch_err_break++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port); - } - - if (linestatus & UART_LSR_OE) { - /* - * Rx Oruns. Exar says that an orun will NOT corrupt - * the FIFO. It will just replace the holding register - * with this new data byte. So basically just ignore this. - * Probably we should eventually have an orun stat in our driver... - */ - ch->ch_err_overrun++; - jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, - "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port); - } - - if (linestatus & UART_LSR_THRE) { - spin_lock_irqsave(&ch->ch_lock, lock_flags); - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - - /* Transfer data (if any) from Write Queue -> UART. */ - neo_copy_data_from_queue_to_uart(ch); - } - else if (linestatus & UART_17158_TX_AND_FIFO_CLR) { - spin_lock_irqsave(&ch->ch_lock, lock_flags); - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - - /* Transfer data (if any) from Write Queue -> UART. */ - neo_copy_data_from_queue_to_uart(ch); - } -} - -/* - * neo_param() - * Send any/all changes to the line to the UART. - */ -static void neo_param(struct jsm_channel *ch) -{ - u8 lcr = 0; - u8 uart_lcr, ier; - u32 baud; - int quot; - struct jsm_board *bd; - - bd = ch->ch_bd; - if (!bd) - return; - - /* - * If baud rate is zero, flush queues, and set mval to drop DTR. - */ - if ((ch->ch_c_cflag & (CBAUD)) == 0) { - ch->ch_r_head = ch->ch_r_tail = 0; - ch->ch_e_head = ch->ch_e_tail = 0; - ch->ch_w_head = ch->ch_w_tail = 0; - - neo_flush_uart_write(ch); - neo_flush_uart_read(ch); - - ch->ch_flags |= (CH_BAUD0); - ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR); - neo_assert_modem_signals(ch); - return; - - } else { - int i; - unsigned int cflag; - static struct { - unsigned int rate; - unsigned int cflag; - } baud_rates[] = { - { 921600, B921600 }, - { 460800, B460800 }, - { 230400, B230400 }, - { 115200, B115200 }, - { 57600, B57600 }, - { 38400, B38400 }, - { 19200, B19200 }, - { 9600, B9600 }, - { 4800, B4800 }, - { 2400, B2400 }, - { 1200, B1200 }, - { 600, B600 }, - { 300, B300 }, - { 200, B200 }, - { 150, B150 }, - { 134, B134 }, - { 110, B110 }, - { 75, B75 }, - { 50, B50 }, - }; - - cflag = C_BAUD(ch->uart_port.state->port.tty); - baud = 9600; - for (i = 0; i < ARRAY_SIZE(baud_rates); i++) { - if (baud_rates[i].cflag == cflag) { - baud = baud_rates[i].rate; - break; - } - } - - if (ch->ch_flags & CH_BAUD0) - ch->ch_flags &= ~(CH_BAUD0); - } - - if (ch->ch_c_cflag & PARENB) - lcr |= UART_LCR_PARITY; - - if (!(ch->ch_c_cflag & PARODD)) - lcr |= UART_LCR_EPAR; - - /* - * Not all platforms support mark/space parity, - * so this will hide behind an ifdef. - */ -#ifdef CMSPAR - if (ch->ch_c_cflag & CMSPAR) - lcr |= UART_LCR_SPAR; -#endif - - if (ch->ch_c_cflag & CSTOPB) - lcr |= UART_LCR_STOP; - - switch (ch->ch_c_cflag & CSIZE) { - case CS5: - lcr |= UART_LCR_WLEN5; - break; - case CS6: - lcr |= UART_LCR_WLEN6; - break; - case CS7: - lcr |= UART_LCR_WLEN7; - break; - case CS8: - default: - lcr |= UART_LCR_WLEN8; - break; - } - - ier = readb(&ch->ch_neo_uart->ier); - uart_lcr = readb(&ch->ch_neo_uart->lcr); - - if (baud == 0) - baud = 9600; - - quot = ch->ch_bd->bd_dividend / baud; - - if (quot != 0) { - writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr); - writeb((quot & 0xff), &ch->ch_neo_uart->txrx); - writeb((quot >> 8), &ch->ch_neo_uart->ier); - writeb(lcr, &ch->ch_neo_uart->lcr); - } - - if (uart_lcr != lcr) - writeb(lcr, &ch->ch_neo_uart->lcr); - - if (ch->ch_c_cflag & CREAD) - ier |= (UART_IER_RDI | UART_IER_RLSI); - - ier |= (UART_IER_THRI | UART_IER_MSI); - - writeb(ier, &ch->ch_neo_uart->ier); - - /* Set new start/stop chars */ - neo_set_new_start_stop_chars(ch); - - if (ch->ch_c_cflag & CRTSCTS) - neo_set_cts_flow_control(ch); - else if (ch->ch_c_iflag & IXON) { - /* If start/stop is set to disable, then we should disable flow control */ - if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) - neo_set_no_output_flow_control(ch); - else - neo_set_ixon_flow_control(ch); - } - else - neo_set_no_output_flow_control(ch); - - if (ch->ch_c_cflag & CRTSCTS) - neo_set_rts_flow_control(ch); - else if (ch->ch_c_iflag & IXOFF) { - /* If start/stop is set to disable, then we should disable flow control */ - if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) - neo_set_no_input_flow_control(ch); - else - neo_set_ixoff_flow_control(ch); - } - else - neo_set_no_input_flow_control(ch); - /* - * Adjust the RX FIFO Trigger level if baud is less than 9600. - * Not exactly elegant, but this is needed because of the Exar chip's - * delay on firing off the RX FIFO interrupt on slower baud rates. - */ - if (baud < 9600) { - writeb(1, &ch->ch_neo_uart->rfifo); - ch->ch_r_tlevel = 1; - } - - neo_assert_modem_signals(ch); - - /* Get current status of the modem signals now */ - neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); - return; -} - -/* - * jsm_neo_intr() - * - * Neo specific interrupt handler. - */ -static irqreturn_t neo_intr(int irq, void *voidbrd) -{ - struct jsm_board *brd = voidbrd; - struct jsm_channel *ch; - int port = 0; - int type = 0; - int current_port; - u32 tmp; - u32 uart_poll; - unsigned long lock_flags; - unsigned long lock_flags2; - int outofloop_count = 0; - - /* Lock out the slow poller from running on this board. */ - spin_lock_irqsave(&brd->bd_intr_lock, lock_flags); - - /* - * Read in "extended" IRQ information from the 32bit Neo register. - * Bits 0-7: What port triggered the interrupt. - * Bits 8-31: Each 3bits indicate what type of interrupt occurred. - */ - uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET); - - jsm_printk(INTR, INFO, &brd->pci_dev, - "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll); - - if (!uart_poll) { - jsm_printk(INTR, INFO, &brd->pci_dev, - "Kernel interrupted to me, but no pending interrupts...\n"); - spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); - return IRQ_NONE; - } - - /* At this point, we have at least SOMETHING to service, dig further... */ - - current_port = 0; - - /* Loop on each port */ - while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){ - - tmp = uart_poll; - outofloop_count++; - - /* Check current port to see if it has interrupt pending */ - if ((tmp & jsm_offset_table[current_port]) != 0) { - port = current_port; - type = tmp >> (8 + (port * 3)); - type &= 0x7; - } else { - current_port++; - continue; - } - - jsm_printk(INTR, INFO, &brd->pci_dev, - "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type); - - /* Remove this port + type from uart_poll */ - uart_poll &= ~(jsm_offset_table[port]); - - if (!type) { - /* If no type, just ignore it, and move onto next port */ - jsm_printk(INTR, ERR, &brd->pci_dev, - "Interrupt with no type! port: %d\n", port); - continue; - } - - /* Switch on type of interrupt we have */ - switch (type) { - - case UART_17158_RXRDY_TIMEOUT: - /* - * RXRDY Time-out is cleared by reading data in the - * RX FIFO until it falls below the trigger level. - */ - - /* Verify the port is in range. */ - if (port > brd->nasync) - continue; - - ch = brd->channels[port]; - neo_copy_data_from_uart_to_queue(ch); - - /* Call our tty layer to enforce queue flow control if needed. */ - spin_lock_irqsave(&ch->ch_lock, lock_flags2); - jsm_check_queue_flow_control(ch); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); - - continue; - - case UART_17158_RX_LINE_STATUS: - /* - * RXRDY and RX LINE Status (logic OR of LSR[4:1]) - */ - neo_parse_lsr(brd, port); - continue; - - case UART_17158_TXRDY: - /* - * TXRDY interrupt clears after reading ISR register for the UART channel. - */ - - /* - * Yes, this is odd... - * Why would I check EVERY possibility of type of - * interrupt, when we know its TXRDY??? - * Becuz for some reason, even tho we got triggered for TXRDY, - * it seems to be occassionally wrong. Instead of TX, which - * it should be, I was getting things like RXDY too. Weird. - */ - neo_parse_isr(brd, port); - continue; - - case UART_17158_MSR: - /* - * MSR or flow control was seen. - */ - neo_parse_isr(brd, port); - continue; - - default: - /* - * The UART triggered us with a bogus interrupt type. - * It appears the Exar chip, when REALLY bogged down, will throw - * these once and awhile. - * Its harmless, just ignore it and move on. - */ - jsm_printk(INTR, ERR, &brd->pci_dev, - "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type); - continue; - } - } - - spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); - - jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n"); - return IRQ_HANDLED; -} - -/* - * Neo specific way of turning off the receiver. - * Used as a way to enforce queue flow control when in - * hardware flow control mode. - */ -static void neo_disable_receiver(struct jsm_channel *ch) -{ - u8 tmp = readb(&ch->ch_neo_uart->ier); - tmp &= ~(UART_IER_RDI); - writeb(tmp, &ch->ch_neo_uart->ier); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); -} - - -/* - * Neo specific way of turning on the receiver. - * Used as a way to un-enforce queue flow control when in - * hardware flow control mode. - */ -static void neo_enable_receiver(struct jsm_channel *ch) -{ - u8 tmp = readb(&ch->ch_neo_uart->ier); - tmp |= (UART_IER_RDI); - writeb(tmp, &ch->ch_neo_uart->ier); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); -} - -static void neo_send_start_character(struct jsm_channel *ch) -{ - if (!ch) - return; - - if (ch->ch_startc != __DISABLED_CHAR) { - ch->ch_xon_sends++; - writeb(ch->ch_startc, &ch->ch_neo_uart->txrx); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); - } -} - -static void neo_send_stop_character(struct jsm_channel *ch) -{ - if (!ch) - return; - - if (ch->ch_stopc != __DISABLED_CHAR) { - ch->ch_xoff_sends++; - writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); - } -} - -/* - * neo_uart_init - */ -static void neo_uart_init(struct jsm_channel *ch) -{ - writeb(0, &ch->ch_neo_uart->ier); - writeb(0, &ch->ch_neo_uart->efr); - writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr); - - /* Clear out UART and FIFO */ - readb(&ch->ch_neo_uart->txrx); - writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); - readb(&ch->ch_neo_uart->lsr); - readb(&ch->ch_neo_uart->msr); - - ch->ch_flags |= CH_FIFO_ENABLED; - - /* Assert any signals we want up */ - writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); -} - -/* - * Make the UART completely turn off. - */ -static void neo_uart_off(struct jsm_channel *ch) -{ - /* Turn off UART enhanced bits */ - writeb(0, &ch->ch_neo_uart->efr); - - /* Stop all interrupts from occurring. */ - writeb(0, &ch->ch_neo_uart->ier); -} - -static u32 neo_get_uart_bytes_left(struct jsm_channel *ch) -{ - u8 left = 0; - u8 lsr = readb(&ch->ch_neo_uart->lsr); - - /* We must cache the LSR as some of the bits get reset once read... */ - ch->ch_cached_lsr |= lsr; - - /* Determine whether the Transmitter is empty or not */ - if (!(lsr & UART_LSR_TEMT)) - left = 1; - else { - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - left = 0; - } - - return left; -} - -/* Channel lock MUST be held by the calling function! */ -static void neo_send_break(struct jsm_channel *ch) -{ - /* - * Set the time we should stop sending the break. - * If we are already sending a break, toss away the existing - * time to stop, and use this new value instead. - */ - - /* Tell the UART to start sending the break */ - if (!(ch->ch_flags & CH_BREAK_SENDING)) { - u8 temp = readb(&ch->ch_neo_uart->lcr); - writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr); - ch->ch_flags |= (CH_BREAK_SENDING); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); - } -} - -/* - * neo_send_immediate_char. - * - * Sends a specific character as soon as possible to the UART, - * jumping over any bytes that might be in the write queue. - * - * The channel lock MUST be held by the calling function. - */ -static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c) -{ - if (!ch) - return; - - writeb(c, &ch->ch_neo_uart->txrx); - - /* flush write operation */ - neo_pci_posting_flush(ch->ch_bd); -} - -struct board_ops jsm_neo_ops = { - .intr = neo_intr, - .uart_init = neo_uart_init, - .uart_off = neo_uart_off, - .param = neo_param, - .assert_modem_signals = neo_assert_modem_signals, - .flush_uart_write = neo_flush_uart_write, - .flush_uart_read = neo_flush_uart_read, - .disable_receiver = neo_disable_receiver, - .enable_receiver = neo_enable_receiver, - .send_break = neo_send_break, - .clear_break = neo_clear_break, - .send_start_character = neo_send_start_character, - .send_stop_character = neo_send_stop_character, - .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart, - .get_uart_bytes_left = neo_get_uart_bytes_left, - .send_immediate_char = neo_send_immediate_char -}; diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c deleted file mode 100644 index 7a4a914ecff0..000000000000 --- a/drivers/serial/jsm/jsm_tty.c +++ /dev/null @@ -1,910 +0,0 @@ -/************************************************************************ - * Copyright 2003 Digi International (www.digi.com) - * - * Copyright (C) 2004 IBM Corporation. All rights reserved. - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. - * - * Contact Information: - * Scott H Kilau - * Ananda Venkatarman - * Modifications: - * 01/19/06: changed jsm_input routine to use the dynamically allocated - * tty_buffer changes. Contributors: Scott Kilau and Ananda V. - ***********************************************************************/ -#include -#include -#include -#include /* For udelay */ -#include -#include - -#include "jsm.h" - -static DECLARE_BITMAP(linemap, MAXLINES); - -static void jsm_carrier(struct jsm_channel *ch); - -static inline int jsm_get_mstat(struct jsm_channel *ch) -{ - unsigned char mstat; - unsigned result; - - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n"); - - mstat = (ch->ch_mostat | ch->ch_mistat); - - result = 0; - - if (mstat & UART_MCR_DTR) - result |= TIOCM_DTR; - if (mstat & UART_MCR_RTS) - result |= TIOCM_RTS; - if (mstat & UART_MSR_CTS) - result |= TIOCM_CTS; - if (mstat & UART_MSR_DSR) - result |= TIOCM_DSR; - if (mstat & UART_MSR_RI) - result |= TIOCM_RI; - if (mstat & UART_MSR_DCD) - result |= TIOCM_CD; - - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); - return result; -} - -static unsigned int jsm_tty_tx_empty(struct uart_port *port) -{ - return TIOCSER_TEMT; -} - -/* - * Return modem signals to ld. - */ -static unsigned int jsm_tty_get_mctrl(struct uart_port *port) -{ - int result; - struct jsm_channel *channel = (struct jsm_channel *)port; - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); - - result = jsm_get_mstat(channel); - - if (result < 0) - return -ENXIO; - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); - - return result; -} - -/* - * jsm_set_modem_info() - * - * Set modem signals, called by ld. - */ -static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct jsm_channel *channel = (struct jsm_channel *)port; - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); - - if (mctrl & TIOCM_RTS) - channel->ch_mostat |= UART_MCR_RTS; - else - channel->ch_mostat &= ~UART_MCR_RTS; - - if (mctrl & TIOCM_DTR) - channel->ch_mostat |= UART_MCR_DTR; - else - channel->ch_mostat &= ~UART_MCR_DTR; - - channel->ch_bd->bd_ops->assert_modem_signals(channel); - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); - udelay(10); -} - -static void jsm_tty_start_tx(struct uart_port *port) -{ - struct jsm_channel *channel = (struct jsm_channel *)port; - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); - - channel->ch_flags &= ~(CH_STOP); - jsm_tty_write(port); - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); -} - -static void jsm_tty_stop_tx(struct uart_port *port) -{ - struct jsm_channel *channel = (struct jsm_channel *)port; - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); - - channel->ch_flags |= (CH_STOP); - - jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); -} - -static void jsm_tty_send_xchar(struct uart_port *port, char ch) -{ - unsigned long lock_flags; - struct jsm_channel *channel = (struct jsm_channel *)port; - struct ktermios *termios; - - spin_lock_irqsave(&port->lock, lock_flags); - termios = port->state->port.tty->termios; - if (ch == termios->c_cc[VSTART]) - channel->ch_bd->bd_ops->send_start_character(channel); - - if (ch == termios->c_cc[VSTOP]) - channel->ch_bd->bd_ops->send_stop_character(channel); - spin_unlock_irqrestore(&port->lock, lock_flags); -} - -static void jsm_tty_stop_rx(struct uart_port *port) -{ - struct jsm_channel *channel = (struct jsm_channel *)port; - - channel->ch_bd->bd_ops->disable_receiver(channel); -} - -static void jsm_tty_enable_ms(struct uart_port *port) -{ - /* Nothing needed */ -} - -static void jsm_tty_break(struct uart_port *port, int break_state) -{ - unsigned long lock_flags; - struct jsm_channel *channel = (struct jsm_channel *)port; - - spin_lock_irqsave(&port->lock, lock_flags); - if (break_state == -1) - channel->ch_bd->bd_ops->send_break(channel); - else - channel->ch_bd->bd_ops->clear_break(channel, 0); - - spin_unlock_irqrestore(&port->lock, lock_flags); -} - -static int jsm_tty_open(struct uart_port *port) -{ - struct jsm_board *brd; - struct jsm_channel *channel = (struct jsm_channel *)port; - struct ktermios *termios; - - /* Get board pointer from our array of majors we have allocated */ - brd = channel->ch_bd; - - /* - * Allocate channel buffers for read/write/error. - * Set flag, so we don't get trounced on. - */ - channel->ch_flags |= (CH_OPENING); - - /* Drop locks, as malloc with GFP_KERNEL can sleep */ - - if (!channel->ch_rqueue) { - channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL); - if (!channel->ch_rqueue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate read queue buf"); - return -ENOMEM; - } - } - if (!channel->ch_equeue) { - channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL); - if (!channel->ch_equeue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate error queue buf"); - return -ENOMEM; - } - } - if (!channel->ch_wqueue) { - channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL); - if (!channel->ch_wqueue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate write queue buf"); - return -ENOMEM; - } - } - - channel->ch_flags &= ~(CH_OPENING); - /* - * Initialize if neither terminal is open. - */ - jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, - "jsm_open: initializing channel in open...\n"); - - /* - * Flush input queues. - */ - channel->ch_r_head = channel->ch_r_tail = 0; - channel->ch_e_head = channel->ch_e_tail = 0; - channel->ch_w_head = channel->ch_w_tail = 0; - - brd->bd_ops->flush_uart_write(channel); - brd->bd_ops->flush_uart_read(channel); - - channel->ch_flags = 0; - channel->ch_cached_lsr = 0; - channel->ch_stops_sent = 0; - - 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; - channel->ch_c_lflag = termios->c_lflag; - channel->ch_startc = termios->c_cc[VSTART]; - channel->ch_stopc = termios->c_cc[VSTOP]; - - /* Tell UART to init itself */ - brd->bd_ops->uart_init(channel); - - /* - * Run param in case we changed anything - */ - brd->bd_ops->param(channel); - - jsm_carrier(channel); - - channel->ch_open_count++; - - jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n"); - return 0; -} - -static void jsm_tty_close(struct uart_port *port) -{ - struct jsm_board *bd; - struct ktermios *ts; - struct jsm_channel *channel = (struct jsm_channel *)port; - - jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); - - bd = channel->ch_bd; - ts = port->state->port.tty->termios; - - channel->ch_flags &= ~(CH_STOPI); - - channel->ch_open_count--; - - /* - * If we have HUPCL set, lower DTR and RTS - */ - if (channel->ch_c_cflag & HUPCL) { - jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, - "Close. HUPCL set, dropping DTR/RTS\n"); - - /* Drop RTS/DTR */ - channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS); - bd->bd_ops->assert_modem_signals(channel); - } - - /* Turn off UART interrupts for this port */ - channel->ch_bd->bd_ops->uart_off(channel); - - jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n"); -} - -static void jsm_tty_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old_termios) -{ - unsigned long lock_flags; - struct jsm_channel *channel = (struct jsm_channel *)port; - - spin_lock_irqsave(&port->lock, lock_flags); - channel->ch_c_cflag = termios->c_cflag; - channel->ch_c_iflag = termios->c_iflag; - channel->ch_c_oflag = termios->c_oflag; - channel->ch_c_lflag = termios->c_lflag; - channel->ch_startc = termios->c_cc[VSTART]; - channel->ch_stopc = termios->c_cc[VSTOP]; - - channel->ch_bd->bd_ops->param(channel); - jsm_carrier(channel); - spin_unlock_irqrestore(&port->lock, lock_flags); -} - -static const char *jsm_tty_type(struct uart_port *port) -{ - return "jsm"; -} - -static void jsm_tty_release_port(struct uart_port *port) -{ -} - -static int jsm_tty_request_port(struct uart_port *port) -{ - return 0; -} - -static void jsm_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_JSM; -} - -static struct uart_ops jsm_ops = { - .tx_empty = jsm_tty_tx_empty, - .set_mctrl = jsm_tty_set_mctrl, - .get_mctrl = jsm_tty_get_mctrl, - .stop_tx = jsm_tty_stop_tx, - .start_tx = jsm_tty_start_tx, - .send_xchar = jsm_tty_send_xchar, - .stop_rx = jsm_tty_stop_rx, - .enable_ms = jsm_tty_enable_ms, - .break_ctl = jsm_tty_break, - .startup = jsm_tty_open, - .shutdown = jsm_tty_close, - .set_termios = jsm_tty_set_termios, - .type = jsm_tty_type, - .release_port = jsm_tty_release_port, - .request_port = jsm_tty_request_port, - .config_port = jsm_config_port, -}; - -/* - * jsm_tty_init() - * - * Init the tty subsystem. Called once per board after board has been - * downloaded and init'ed. - */ -int __devinit jsm_tty_init(struct jsm_board *brd) -{ - int i; - void __iomem *vaddr; - struct jsm_channel *ch; - - if (!brd) - return -ENXIO; - - jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); - - /* - * Initialize board structure elements. - */ - - brd->nasync = brd->maxports; - - /* - * Allocate channel memory that might not have been allocated - * when the driver was first loaded. - */ - for (i = 0; i < brd->nasync; i++) { - if (!brd->channels[i]) { - - /* - * Okay to malloc with GFP_KERNEL, we are not at - * interrupt context, and there are no locks held. - */ - brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL); - if (!brd->channels[i]) { - jsm_printk(CORE, ERR, &brd->pci_dev, - "%s:%d Unable to allocate memory for channel struct\n", - __FILE__, __LINE__); - } - } - } - - ch = brd->channels[0]; - vaddr = brd->re_map_membase; - - /* Set up channel variables */ - for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { - - if (!brd->channels[i]) - continue; - - spin_lock_init(&ch->ch_lock); - - if (brd->bd_uart_offset == 0x200) - ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i); - - ch->ch_bd = brd; - ch->ch_portnum = i; - - /* .25 second delay */ - ch->ch_close_delay = 250; - - init_waitqueue_head(&ch->ch_flags_wait); - } - - jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); - return 0; -} - -int jsm_uart_port_init(struct jsm_board *brd) -{ - int i, rc; - unsigned int line; - struct jsm_channel *ch; - - if (!brd) - return -ENXIO; - - jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); - - /* - * Initialize board structure elements. - */ - - brd->nasync = brd->maxports; - - /* Set up channel variables */ - for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { - - if (!brd->channels[i]) - continue; - - brd->channels[i]->uart_port.irq = brd->irq; - brd->channels[i]->uart_port.uartclk = 14745600; - brd->channels[i]->uart_port.type = PORT_JSM; - brd->channels[i]->uart_port.iotype = UPIO_MEM; - brd->channels[i]->uart_port.membase = brd->re_map_membase; - brd->channels[i]->uart_port.fifosize = 16; - brd->channels[i]->uart_port.ops = &jsm_ops; - line = find_first_zero_bit(linemap, MAXLINES); - if (line >= MAXLINES) { - printk(KERN_INFO "jsm: linemap is full, added device failed\n"); - continue; - } else - set_bit(line, linemap); - brd->channels[i]->uart_port.line = line; - rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port); - if (rc){ - printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i); - return rc; - } - else - printk(KERN_INFO "jsm: Port %d added\n", i); - } - - jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); - return 0; -} - -int jsm_remove_uart_port(struct jsm_board *brd) -{ - int i; - struct jsm_channel *ch; - - if (!brd) - return -ENXIO; - - jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); - - /* - * Initialize board structure elements. - */ - - brd->nasync = brd->maxports; - - /* Set up channel variables */ - for (i = 0; i < brd->nasync; i++) { - - if (!brd->channels[i]) - continue; - - ch = brd->channels[i]; - - clear_bit(ch->uart_port.line, linemap); - uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); - } - - jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); - return 0; -} - -void jsm_input(struct jsm_channel *ch) -{ - struct jsm_board *bd; - struct tty_struct *tp; - u32 rmask; - u16 head; - u16 tail; - int data_len; - unsigned long lock_flags; - int len = 0; - int n = 0; - int s = 0; - int i = 0; - - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); - - if (!ch) - return; - - tp = ch->uart_port.state->port.tty; - - bd = ch->ch_bd; - if(!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, lock_flags); - - /* - *Figure the number of characters in the buffer. - *Exit immediately if none. - */ - - rmask = RQUEUEMASK; - - head = ch->ch_r_head & rmask; - tail = ch->ch_r_tail & rmask; - - data_len = (head - tail) & rmask; - if (data_len == 0) { - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - return; - } - - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); - - /* - *If the device is not open, or CREAD is off, flush - *input data and return immediately. - */ - if (!tp || - !(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); - ch->ch_r_head = tail; - - /* Force queue flow control to be released, if needed */ - jsm_check_queue_flow_control(ch); - - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - return; - } - - /* - * If we are throttled, simply don't read any data. - */ - if (ch->ch_flags & CH_STOPI) { - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Port %d throttled, not reading any data. head: %x tail: %x\n", - ch->ch_portnum, head, tail); - return; - } - - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n"); - - if (data_len <= 0) { - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); - return; - } - - len = tty_buffer_request_room(tp, data_len); - n = len; - - /* - * n now contains the most amount of data we can copy, - * bounded either by the flip buffer size or the amount - * of data the card actually has pending... - */ - while (n) { - s = ((head >= tail) ? head : RQUEUESIZE) - tail; - s = min(s, n); - - if (s <= 0) - break; - - /* - * If conditions are such that ld needs to see all - * UART errors, we will have to walk each character - * and error byte and send them to the buffer one at - * a time. - */ - - if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { - for (i = 0; i < s; i++) { - /* - * Give the Linux ld the flags in the - * format it likes. - */ - if (*(ch->ch_equeue +tail +i) & UART_LSR_BI) - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME); - else - tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL); - } - } else { - tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ; - } - tail += s; - n -= s; - /* Flip queue if needed */ - tail &= rmask; - } - - ch->ch_r_tail = tail & rmask; - ch->ch_e_tail = tail & rmask; - jsm_check_queue_flow_control(ch); - spin_unlock_irqrestore(&ch->ch_lock, lock_flags); - - /* Tell the tty layer its okay to "eat" the data now */ - tty_flip_buffer_push(tp); - - jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); -} - -static void jsm_carrier(struct jsm_channel *ch) -{ - struct jsm_board *bd; - - int virt_carrier = 0; - int phys_carrier = 0; - - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n"); - if (!ch) - return; - - bd = ch->ch_bd; - - if (!bd) - return; - - if (ch->ch_mistat & UART_MSR_DCD) { - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD); - phys_carrier = 1; - } - - if (ch->ch_c_cflag & CLOCAL) - virt_carrier = 1; - - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier); - - /* - * Test for a VIRTUAL carrier transition to HIGH. - */ - if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { - - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "carrier: virt DCD rose\n"); - - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL carrier transition to HIGH. - */ - if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { - - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - - jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, - "carrier: physical DCD rose\n"); - - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL transition to low, so long as we aren't - * currently ignoring physical transitions (which is what "virtual - * carrier" indicates). - * - * The transition of the virtual carrier to low really doesn't - * matter... it really only means "ignore carrier state", not - * "make pretend that carrier is there". - */ - if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) - && (phys_carrier == 0)) { - /* - * When carrier drops: - * - * Drop carrier on all open units. - * - * Flush queues, waking up any task waiting in the - * line discipline. - * - * Send a hangup to the control terminal. - * - * Enable all select calls. - */ - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Make sure that our cached values reflect the current reality. - */ - if (virt_carrier == 1) - ch->ch_flags |= CH_FCAR; - else - ch->ch_flags &= ~CH_FCAR; - - if (phys_carrier == 1) - ch->ch_flags |= CH_CD; - else - ch->ch_flags &= ~CH_CD; -} - - -void jsm_check_queue_flow_control(struct jsm_channel *ch) -{ - struct board_ops *bd_ops = ch->ch_bd->bd_ops; - int qleft; - - /* Store how much space we have left in the queue */ - if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) - qleft += RQUEUEMASK + 1; - - /* - * Check to see if we should enforce flow control on our queue because - * the ld (or user) isn't reading data out of our queue fast enuf. - * - * NOTE: This is done based on what the current flow control of the - * port is set for. - * - * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt. - * This will cause the UART's FIFO to back up, and force - * the RTS signal to be dropped. - * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to - * the other side, in hopes it will stop sending data to us. - * 3) NONE - Nothing we can do. We will simply drop any extra data - * that gets sent into us when the queue fills up. - */ - if (qleft < 256) { - /* HWFLOW */ - if (ch->ch_c_cflag & CRTSCTS) { - if(!(ch->ch_flags & CH_RECEIVER_OFF)) { - bd_ops->disable_receiver(ch); - ch->ch_flags |= (CH_RECEIVER_OFF); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n", - qleft); - } - } - /* SWFLOW */ - else if (ch->ch_c_iflag & IXOFF) { - if (ch->ch_stops_sent <= MAX_STOPS_SENT) { - bd_ops->send_stop_character(ch); - ch->ch_stops_sent++; - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Sending stop char! Times sent: %x\n", ch->ch_stops_sent); - } - } - } - - /* - * Check to see if we should unenforce flow control because - * ld (or user) finally read enuf data out of our queue. - * - * NOTE: This is done based on what the current flow control of the - * port is set for. - * - * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt. - * This will cause the UART's FIFO to raise RTS back up, - * which will allow the other side to start sending data again. - * 2) SWFLOW (IXOFF) - Send a start character to - * the other side, so it will start sending data to us again. - * 3) NONE - Do nothing. Since we didn't do anything to turn off the - * other side, we don't need to do anything now. - */ - if (qleft > (RQUEUESIZE / 2)) { - /* HWFLOW */ - if (ch->ch_c_cflag & CRTSCTS) { - if (ch->ch_flags & CH_RECEIVER_OFF) { - bd_ops->enable_receiver(ch); - ch->ch_flags &= ~(CH_RECEIVER_OFF); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, - "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n", - qleft); - } - } - /* SWFLOW */ - else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { - ch->ch_stops_sent = 0; - bd_ops->send_start_character(ch); - jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n"); - } - } -} - -/* - * jsm_tty_write() - * - * Take data from the user or kernel and send it out to the FEP. - * In here exists all the Transparent Print magic as well. - */ -int jsm_tty_write(struct uart_port *port) -{ - int bufcount; - int data_count = 0,data_count1 =0; - u16 head; - u16 tail; - u16 tmask; - u32 remain; - int temp_tail = port->state->xmit.tail; - struct jsm_channel *channel = (struct jsm_channel *)port; - - tmask = WQUEUEMASK; - head = (channel->ch_w_head) & tmask; - tail = (channel->ch_w_tail) & tmask; - - if ((bufcount = tail - head - 1) < 0) - bufcount += WQUEUESIZE; - - bufcount = min(bufcount, 56); - remain = WQUEUESIZE - head; - - data_count = 0; - if (bufcount >= remain) { - bufcount -= remain; - while ((port->state->xmit.head != temp_tail) && - (data_count < remain)) { - channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - data_count++; - } - if (data_count == remain) head = 0; - } - - data_count1 = 0; - if (bufcount > 0) { - remain = bufcount; - while ((port->state->xmit.head != temp_tail) && - (data_count1 < remain)) { - channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - data_count1++; - - } - } - - port->state->xmit.tail = temp_tail; - - data_count += data_count1; - if (data_count) { - head &= tmask; - channel->ch_w_head = head; - } - - if (data_count) { - channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); - } - - return data_count; -} diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c deleted file mode 100644 index 25a8bc565f40..000000000000 --- a/drivers/serial/kgdboc.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Based on the same principle as kgdboe using the NETPOLL api, this - * driver uses a console polling api to implement a gdb serial inteface - * which is multiplexed on a console port. - * - * Maintainer: Jason Wessel - * - * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#define MAX_CONFIG_LEN 40 - -static struct kgdb_io kgdboc_io_ops; - -/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ -static int configured = -1; - -static char config[MAX_CONFIG_LEN]; -static struct kparam_string kps = { - .string = config, - .maxlen = MAX_CONFIG_LEN, -}; - -static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ -static struct tty_driver *kgdb_tty_driver; -static int kgdb_tty_line; - -#ifdef CONFIG_KDB_KEYBOARD -static int kgdboc_reset_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) -{ - input_reset_device(dev); - - /* Retrun an error - we do not want to bind, just to reset */ - return -ENODEV; -} - -static void kgdboc_reset_disconnect(struct input_handle *handle) -{ - /* We do not expect anyone to actually bind to us */ - BUG(); -} - -static const struct input_device_id kgdboc_reset_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_KEY) }, - }, - { } -}; - -static struct input_handler kgdboc_reset_handler = { - .connect = kgdboc_reset_connect, - .disconnect = kgdboc_reset_disconnect, - .name = "kgdboc_reset", - .id_table = kgdboc_reset_ids, -}; - -static DEFINE_MUTEX(kgdboc_reset_mutex); - -static void kgdboc_restore_input_helper(struct work_struct *dummy) -{ - /* - * We need to take a mutex to prevent several instances of - * this work running on different CPUs so they don't try - * to register again already registered handler. - */ - mutex_lock(&kgdboc_reset_mutex); - - if (input_register_handler(&kgdboc_reset_handler) == 0) - input_unregister_handler(&kgdboc_reset_handler); - - mutex_unlock(&kgdboc_reset_mutex); -} - -static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper); - -static void kgdboc_restore_input(void) -{ - if (likely(system_state == SYSTEM_RUNNING)) - schedule_work(&kgdboc_restore_input_work); -} - -static int kgdboc_register_kbd(char **cptr) -{ - if (strncmp(*cptr, "kbd", 3) == 0) { - if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { - kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; - kdb_poll_idx++; - if (cptr[0][3] == ',') - *cptr += 4; - else - return 1; - } - } - return 0; -} - -static void kgdboc_unregister_kbd(void) -{ - int i; - - for (i = 0; i < kdb_poll_idx; i++) { - if (kdb_poll_funcs[i] == kdb_get_kbd_char) { - kdb_poll_idx--; - kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx]; - kdb_poll_funcs[kdb_poll_idx] = NULL; - i--; - } - } - flush_work_sync(&kgdboc_restore_input_work); -} -#else /* ! CONFIG_KDB_KEYBOARD */ -#define kgdboc_register_kbd(x) 0 -#define kgdboc_unregister_kbd() -#define kgdboc_restore_input() -#endif /* ! CONFIG_KDB_KEYBOARD */ - -static int kgdboc_option_setup(char *opt) -{ - if (strlen(opt) > MAX_CONFIG_LEN) { - printk(KERN_ERR "kgdboc: config string too long\n"); - return -ENOSPC; - } - strcpy(config, opt); - - return 0; -} - -__setup("kgdboc=", kgdboc_option_setup); - -static void cleanup_kgdboc(void) -{ - kgdboc_unregister_kbd(); - if (configured == 1) - kgdb_unregister_io_module(&kgdboc_io_ops); -} - -static int configure_kgdboc(void) -{ - struct tty_driver *p; - int tty_line = 0; - int err; - char *cptr = config; - struct console *cons; - - err = kgdboc_option_setup(config); - if (err || !strlen(config) || isspace(config[0])) - goto noconfig; - - err = -ENODEV; - kgdboc_io_ops.is_console = 0; - kgdb_tty_driver = NULL; - - kgdboc_use_kms = 0; - if (strncmp(cptr, "kms,", 4) == 0) { - cptr += 4; - kgdboc_use_kms = 1; - } - - if (kgdboc_register_kbd(&cptr)) - goto do_register; - - p = tty_find_polling_driver(cptr, &tty_line); - if (!p) - goto noconfig; - - cons = console_drivers; - while (cons) { - int idx; - if (cons->device && cons->device(cons, &idx) == p && - idx == tty_line) { - kgdboc_io_ops.is_console = 1; - break; - } - cons = cons->next; - } - - kgdb_tty_driver = p; - kgdb_tty_line = tty_line; - -do_register: - err = kgdb_register_io_module(&kgdboc_io_ops); - if (err) - goto noconfig; - - configured = 1; - - return 0; - -noconfig: - config[0] = 0; - configured = 0; - cleanup_kgdboc(); - - return err; -} - -static int __init init_kgdboc(void) -{ - /* Already configured? */ - if (configured == 1) - return 0; - - return configure_kgdboc(); -} - -static int kgdboc_get_char(void) -{ - if (!kgdb_tty_driver) - return -1; - return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, - kgdb_tty_line); -} - -static void kgdboc_put_char(u8 chr) -{ - if (!kgdb_tty_driver) - return; - kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, - kgdb_tty_line, chr); -} - -static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) -{ - int len = strlen(kmessage); - - if (len >= MAX_CONFIG_LEN) { - printk(KERN_ERR "kgdboc: config string too long\n"); - return -ENOSPC; - } - - /* Only copy in the string if the init function has not run yet */ - if (configured < 0) { - strcpy(config, kmessage); - return 0; - } - - if (kgdb_connected) { - printk(KERN_ERR - "kgdboc: Cannot reconfigure while KGDB is connected.\n"); - - return -EBUSY; - } - - strcpy(config, kmessage); - /* Chop out \n char as a result of echo */ - if (config[len - 1] == '\n') - config[len - 1] = '\0'; - - if (configured == 1) - cleanup_kgdboc(); - - /* Go and configure with the new params. */ - return configure_kgdboc(); -} - -static int dbg_restore_graphics; - -static void kgdboc_pre_exp_handler(void) -{ - if (!dbg_restore_graphics && kgdboc_use_kms) { - dbg_restore_graphics = 1; - con_debug_enter(vc_cons[fg_console].d); - } - /* Increment the module count when the debugger is active */ - if (!kgdb_connected) - try_module_get(THIS_MODULE); -} - -static void kgdboc_post_exp_handler(void) -{ - /* decrement the module count when the debugger detaches */ - if (!kgdb_connected) - module_put(THIS_MODULE); - if (kgdboc_use_kms && dbg_restore_graphics) { - dbg_restore_graphics = 0; - con_debug_leave(); - } - kgdboc_restore_input(); -} - -static struct kgdb_io kgdboc_io_ops = { - .name = "kgdboc", - .read_char = kgdboc_get_char, - .write_char = kgdboc_put_char, - .pre_exception = kgdboc_pre_exp_handler, - .post_exception = kgdboc_post_exp_handler, -}; - -#ifdef CONFIG_KGDB_SERIAL_CONSOLE -/* This is only available if kgdboc is a built in for early debugging */ -static int __init kgdboc_early_init(char *opt) -{ - /* save the first character of the config string because the - * init routine can destroy it. - */ - char save_ch; - - kgdboc_option_setup(opt); - save_ch = config[0]; - init_kgdboc(); - config[0] = save_ch; - return 0; -} - -early_param("ekgdboc", kgdboc_early_init); -#endif /* CONFIG_KGDB_SERIAL_CONSOLE */ - -module_init(init_kgdboc); -module_exit(cleanup_kgdboc); -module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); -MODULE_PARM_DESC(kgdboc, "[,baud]"); -MODULE_DESCRIPTION("KGDB Console TTY Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c deleted file mode 100644 index bea5c215460c..000000000000 --- a/drivers/serial/m32r_sio.c +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * m32r_sio.c - * - * Driver for M32R serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Based on drivers/serial/8250.c. - * - * Copyright (C) 2001 Russell King. - * Copyright (C) 2004 Hirokazu Takata - * - * 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. - */ - -/* - * A note about mapbase / membase - * - * mapbase is the physical address of the IO port. Currently, we don't - * support this very well, and it may well be dropped from this driver - * in future. As such, mapbase should be NULL. - * - * membase is an 'ioremapped' cookie. This is compatible with the old - * serial.c driver, and is currently the preferred form. - */ - -#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define PORT_M32R_BASE PORT_M32R_SIO -#define PORT_INDEX(x) (x - PORT_M32R_BASE + 1) -#define BAUD_RATE 115200 - -#include -#include "m32r_sio.h" -#include "m32r_sio_reg.h" - -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - -#define PASS_LIMIT 256 - -/* - * We default to IRQ0 for the "no irq" hack. Some - * machine types want others as well - they're free - * to redefine this in their header file. - */ -#define is_real_interrupt(irq) ((irq) != 0) - -#define BASE_BAUD 115200 - -/* Standard COM flags */ -#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) - -/* - * SERIAL_PORT_DFNS tells us about built-in ports that have no - * standard enumeration mechanism. Platforms that can find all - * serial ports via mechanisms like ACPI or PCI need not supply it. - */ -#if defined(CONFIG_PLAT_USRV) - -#define SERIAL_PORT_DFNS \ - /* UART CLK PORT IRQ FLAGS */ \ - { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */ - -#else /* !CONFIG_PLAT_USRV */ - -#if defined(CONFIG_SERIAL_M32R_PLDSIO) -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \ - STD_COM_FLAGS }, /* ttyS0 */ -#else -#define SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \ - STD_COM_FLAGS }, /* ttyS0 */ -#endif - -#endif /* !CONFIG_PLAT_USRV */ - -static struct old_serial_port old_serial_port[] = { - SERIAL_PORT_DFNS -}; - -#define UART_NR ARRAY_SIZE(old_serial_port) - -struct uart_sio_port { - struct uart_port port; - struct timer_list timer; /* "no irq" timer */ - struct list_head list; /* ports on this IRQ */ - unsigned short rev; - unsigned char acr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr_mask; /* mask of user bits */ - unsigned char mcr_force; /* mask of forced bits */ - unsigned char lsr_break_flag; - - /* - * We provide a per-port pm hook. - */ - void (*pm)(struct uart_port *port, - unsigned int state, unsigned int old); -}; - -struct irq_info { - spinlock_t lock; - struct list_head *head; -}; - -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)) -#define __sio_out(v,x) outw((v),(unsigned long)(x)) - -static inline void sio_set_baud_rate(unsigned long baud) -{ - unsigned short sbaud; - sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1; - __sio_out(sbaud, PLD_ESIO0BAUR); -} - -static void sio_reset(void) -{ - unsigned short tmp; - - tmp = __sio_in(PLD_ESIO0RXB); - tmp = __sio_in(PLD_ESIO0RXB); - tmp = __sio_in(PLD_ESIO0CR); - sio_set_baud_rate(BAUD_RATE); - __sio_out(0x0300, PLD_ESIO0CR); - __sio_out(0x0003, PLD_ESIO0CR); -} - -static void sio_init(void) -{ - unsigned short tmp; - - tmp = __sio_in(PLD_ESIO0RXB); - tmp = __sio_in(PLD_ESIO0RXB); - tmp = __sio_in(PLD_ESIO0CR); - __sio_out(0x0300, PLD_ESIO0CR); - __sio_out(0x0003, PLD_ESIO0CR); -} - -static void sio_error(int *status) -{ - printk("SIO0 error[%04x]\n", *status); - do { - sio_init(); - } while ((*status = __sio_in(PLD_ESIO0CR)) != 3); -} - -#else /* not CONFIG_SERIAL_M32R_PLDSIO */ - -#define __sio_in(x) inl(x) -#define __sio_out(v,x) outl((v),(x)) - -static inline void sio_set_baud_rate(unsigned long baud) -{ - unsigned long i, j; - - i = boot_cpu_data.bus_clock / (baud * 16); - j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud; - i -= 1; - j = (j + 1) >> 1; - - __sio_out(i, M32R_SIO0_BAUR_PORTL); - __sio_out(j, M32R_SIO0_RBAUR_PORTL); -} - -static void sio_reset(void) -{ - __sio_out(0x00000300, M32R_SIO0_CR_PORTL); /* init status */ - __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL); /* 8bit */ - __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL); /* 1stop non */ - sio_set_baud_rate(BAUD_RATE); - __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL); - __sio_out(0x00000003, M32R_SIO0_CR_PORTL); /* RXCEN */ -} - -static void sio_init(void) -{ - unsigned int tmp; - - tmp = __sio_in(M32R_SIO0_RXB_PORTL); - tmp = __sio_in(M32R_SIO0_RXB_PORTL); - tmp = __sio_in(M32R_SIO0_STS_PORTL); - __sio_out(0x00000003, M32R_SIO0_CR_PORTL); -} - -static void sio_error(int *status) -{ - printk("SIO0 error[%04x]\n", *status); - do { - sio_init(); - } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3); -} - -#endif /* CONFIG_SERIAL_M32R_PLDSIO */ - -static unsigned int sio_in(struct uart_sio_port *up, int offset) -{ - return __sio_in(up->port.iobase + offset); -} - -static void sio_out(struct uart_sio_port *up, int offset, int value) -{ - __sio_out(value, up->port.iobase + offset); -} - -static unsigned int serial_in(struct uart_sio_port *up, int offset) -{ - if (!offset) - return 0; - - return __sio_in(offset); -} - -static void serial_out(struct uart_sio_port *up, int offset, int value) -{ - if (!offset) - return; - - __sio_out(value, offset); -} - -static void m32r_sio_stop_tx(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void m32r_sio_start_tx(struct uart_port *port) -{ -#ifdef CONFIG_SERIAL_M32R_PLDSIO - struct uart_sio_port *up = (struct uart_sio_port *)port; - struct circ_buf *xmit = &up->port.state->xmit; - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - } - while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY); -#else - struct uart_sio_port *up = (struct uart_sio_port *)port; - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -#endif -} - -static void m32r_sio_stop_rx(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); -} - -static void m32r_sio_enable_ms(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void receive_chars(struct uart_sio_port *up, int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned char ch; - unsigned char flag; - int max_count = 256; - - do { - ch = sio_in(up, SIORXB); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - /* - * For statistics only - */ - if (*status & UART_LSR_BI) { - *status &= ~(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 (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ingored. - */ - *status &= up->port.read_status_mask; - - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } - - if (*status & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - if ((*status & up->port.ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); - - if (*status & UART_LSR_OE) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - ignore_char: - *status = serial_in(up, UART_LSR); - } while ((*status & UART_LSR_DR) && (max_count-- > 0)); - tty_flip_buffer_push(tty); -} - -static void transmit_chars(struct uart_sio_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { -#ifndef CONFIG_SERIAL_M32R_PLDSIO /* XXX */ - serial_out(up, UART_TX, up->port.x_char); -#endif - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - m32r_sio_stop_tx(&up->port); - return; - } - - count = up->port.fifosize; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - while (!(serial_in(up, UART_LSR) & UART_LSR_THRE)); - - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - DEBUG_INTR("THRE..."); - - if (uart_circ_empty(xmit)) - m32r_sio_stop_tx(&up->port); -} - -/* - * This handles the interrupt from one port. - */ -static inline void m32r_sio_handle_port(struct uart_sio_port *up, - unsigned int status) -{ - DEBUG_INTR("status = %x...", status); - - if (status & 0x04) - receive_chars(up, &status); - if (status & 0x01) - transmit_chars(up); -} - -/* - * This is the serial driver's interrupt routine. - * - * Arjan thinks the old way was overly complex, so it got simplified. - * Alan disagrees, saying that need the complexity to handle the weird - * nature of ISA shared interrupts. (This is a special exception.) - * - * In order to handle ISA shared interrupts properly, we need to check - * that all ports have been serviced, and therefore the ISA interrupt - * line has been de-asserted. - * - * This means we need to loop through all ports. checking that they - * don't have an interrupt pending. - */ -static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id) -{ - struct irq_info *i = dev_id; - struct list_head *l, *end = NULL; - int pass_counter = 0; - - DEBUG_INTR("m32r_sio_interrupt(%d)...", irq); - -#ifdef CONFIG_SERIAL_M32R_PLDSIO -// if (irq == PLD_IRQ_SIO0_SND) -// irq = PLD_IRQ_SIO0_RCV; -#else - if (irq == M32R_IRQ_SIO0_S) - irq = M32R_IRQ_SIO0_R; -#endif - - spin_lock(&i->lock); - - l = i->head; - do { - struct uart_sio_port *up; - unsigned int sts; - - up = list_entry(l, struct uart_sio_port, list); - - sts = sio_in(up, SIOSTS); - if (sts & 0x5) { - spin_lock(&up->port.lock); - m32r_sio_handle_port(up, sts); - spin_unlock(&up->port.lock); - - end = NULL; - } else if (end == NULL) - end = l; - - l = l->next; - - if (l == i->head && pass_counter++ > PASS_LIMIT) { - if (sts & 0xe0) - sio_error(&sts); - break; - } - } while (l != end); - - spin_unlock(&i->lock); - - DEBUG_INTR("end.\n"); - - return IRQ_HANDLED; -} - -/* - * To support ISA shared interrupts, we need to have one interrupt - * handler that ensures that the IRQ line has been deasserted - * before returning. Failing to do this will result in the IRQ - * line being stuck active, and, since ISA irqs are edge triggered, - * no more IRQs will be seen. - */ -static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up) -{ - spin_lock_irq(&i->lock); - - if (!list_empty(i->head)) { - if (i->head == &up->list) - i->head = i->head->next; - list_del(&up->list); - } else { - BUG_ON(i->head != &up->list); - i->head = NULL; - } - - spin_unlock_irq(&i->lock); -} - -static int serial_link_irq_chain(struct uart_sio_port *up) -{ - struct irq_info *i = irq_lists + up->port.irq; - int ret, irq_flags = 0; - - spin_lock_irq(&i->lock); - - if (i->head) { - list_add(&up->list, i->head); - spin_unlock_irq(&i->lock); - - ret = 0; - } else { - INIT_LIST_HEAD(&up->list); - i->head = &up->list; - spin_unlock_irq(&i->lock); - - ret = request_irq(up->port.irq, m32r_sio_interrupt, - irq_flags, "SIO0-RX", i); - ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt, - irq_flags, "SIO0-TX", i); - if (ret < 0) - serial_do_unlink(i, up); - } - - return ret; -} - -static void serial_unlink_irq_chain(struct uart_sio_port *up) -{ - struct irq_info *i = irq_lists + up->port.irq; - - BUG_ON(i->head == NULL); - - if (list_empty(i->head)) { - free_irq(up->port.irq, i); - free_irq(up->port.irq + 1, i); - } - - serial_do_unlink(i, up); -} - -/* - * This function is used to handle ports that do not have an interrupt. - */ -static void m32r_sio_timeout(unsigned long data) -{ - struct uart_sio_port *up = (struct uart_sio_port *)data; - unsigned int timeout; - unsigned int sts; - - sts = sio_in(up, SIOSTS); - if (sts & 0x5) { - spin_lock(&up->port.lock); - m32r_sio_handle_port(up, sts); - spin_unlock(&up->port.lock); - } - - timeout = up->port.timeout; - timeout = timeout > 6 ? (timeout / 2 - 2) : 1; - mod_timer(&up->timer, jiffies + timeout); -} - -static unsigned int m32r_sio_tx_empty(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - unsigned long flags; - unsigned int ret; - - 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); - - return ret; -} - -static unsigned int m32r_sio_get_mctrl(struct uart_port *port) -{ - return 0; -} - -static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - -} - -static void m32r_sio_break_ctl(struct uart_port *port, int break_state) -{ - -} - -static int m32r_sio_startup(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - int retval; - - sio_init(); - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!is_real_interrupt(up->port.irq)) { - unsigned int timeout = up->port.timeout; - - timeout = timeout > 6 ? (timeout / 2 - 2) : 1; - - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + timeout); - } else { - retval = serial_link_irq_chain(up); - if (retval) - return retval; - } - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - * - M32R_SIO: 0x0c - * - M32R_PLDSIO: 0x04 - */ - up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - sio_out(up, SIOTRCR, up->ier); - - /* - * And clear the interrupt registers again for luck. - */ - sio_reset(); - - return 0; -} - -static void m32r_sio_shutdown(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - /* - * Disable interrupts from this port - */ - up->ier = 0; - sio_out(up, SIOTRCR, 0); - - /* - * Disable break condition and FIFOs - */ - - sio_init(); - - if (!is_real_interrupt(up->port.irq)) - del_timer_sync(&up->timer); - else - serial_unlink_irq_chain(up); -} - -static unsigned int m32r_sio_get_divisor(struct uart_port *port, - unsigned int baud) -{ - return uart_get_divisor(port, baud); -} - -static void m32r_sio_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - unsigned char cval = 0; - unsigned long flags; - unsigned int baud, quot; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (termios->c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - /* - * Ask the core to calculate the divisor for us. - */ -#ifdef CONFIG_SERIAL_M32R_PLDSIO - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4); -#else - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); -#endif - quot = m32r_sio_get_divisor(port, baud); - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - sio_set_baud_rate(baud); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - up->lcr = cval; /* Save LCR */ - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void m32r_sio_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - if (up->pm) - up->pm(port, state, oldstate); -} - -/* - * Resource handling. This is complicated by the fact that resources - * depend on the port type. Maybe we should be claiming the standard - * 8250 ports, and then trying to get other resources as necessary? - */ -static int -m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res) -{ - unsigned int size = 8 << up->port.regshift; -#ifndef CONFIG_SERIAL_M32R_PLDSIO - unsigned long start; -#endif - int ret = 0; - - switch (up->port.iotype) { - case UPIO_MEM: - if (up->port.mapbase) { -#ifdef CONFIG_SERIAL_M32R_PLDSIO - *res = request_mem_region(up->port.mapbase, size, "serial"); -#else - start = up->port.mapbase; - *res = request_mem_region(start, size, "serial"); -#endif - if (!*res) - ret = -EBUSY; - } - break; - - case UPIO_PORT: - *res = request_region(up->port.iobase, size, "serial"); - if (!*res) - ret = -EBUSY; - break; - } - return ret; -} - -static void m32r_sio_release_port(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - unsigned long start, offset = 0, size = 0; - - size <<= up->port.regshift; - - switch (up->port.iotype) { - case UPIO_MEM: - if (up->port.mapbase) { - /* - * Unmap the area. - */ - iounmap(up->port.membase); - up->port.membase = NULL; - - start = up->port.mapbase; - - if (size) - release_mem_region(start + offset, size); - release_mem_region(start, 8 << up->port.regshift); - } - break; - - case UPIO_PORT: - start = up->port.iobase; - - if (size) - release_region(start + offset, size); - release_region(start + offset, 8 << up->port.regshift); - break; - - default: - break; - } -} - -static int m32r_sio_request_port(struct uart_port *port) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - struct resource *res = NULL; - int ret = 0; - - ret = m32r_sio_request_std_resource(up, &res); - - /* - * If we have a mapbase, then request that as well. - */ - if (ret == 0 && up->port.flags & UPF_IOREMAP) { - int size = res->end - res->start + 1; - - up->port.membase = ioremap(up->port.mapbase, size); - if (!up->port.membase) - ret = -ENOMEM; - } - - if (ret < 0) { - if (res) - release_resource(res); - } - - return ret; -} - -static void m32r_sio_config_port(struct uart_port *port, int flags) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - 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; - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -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)) - 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, - .get_mctrl = m32r_sio_get_mctrl, - .stop_tx = m32r_sio_stop_tx, - .start_tx = m32r_sio_start_tx, - .stop_rx = m32r_sio_stop_rx, - .enable_ms = m32r_sio_enable_ms, - .break_ctl = m32r_sio_break_ctl, - .startup = m32r_sio_startup, - .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, - .verify_port = m32r_sio_verify_port, -}; - -static struct uart_sio_port m32r_sio_ports[UART_NR]; - -static void __init m32r_sio_init_ports(void) -{ - struct uart_sio_port *up; - static int first = 1; - int i; - - if (!first) - return; - first = 0; - - for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port); - i++, up++) { - up->port.iobase = old_serial_port[i].port; - up->port.irq = irq_canonicalize(old_serial_port[i].irq); - up->port.uartclk = old_serial_port[i].baud_base * 16; - up->port.flags = old_serial_port[i].flags; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; - up->port.ops = &m32r_sio_pops; - } -} - -static void __init m32r_sio_register_ports(struct uart_driver *drv) -{ - int i; - - m32r_sio_init_ports(); - - for (i = 0; i < UART_NR; i++) { - struct uart_sio_port *up = &m32r_sio_ports[i]; - - up->port.line = i; - up->port.ops = &m32r_sio_pops; - init_timer(&up->timer); - up->timer.function = m32r_sio_timeout; - - /* - * ALPHA_KLUDGE_MCR needs to be killed. - */ - up->mcr_mask = ~ALPHA_KLUDGE_MCR; - up->mcr_force = ALPHA_KLUDGE_MCR; - - uart_add_one_port(drv, &up->port); - } -} - -#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE - -/* - * Wait for transmitter & holding register to empty - */ -static inline void wait_for_xmitr(struct uart_sio_port *up) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = sio_in(up, SIOSTS); - - if (--tmout == 0) - break; - udelay(1); - } while ((status & UART_EMPTY) != UART_EMPTY); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout) - udelay(1); - } -} - -static void m32r_sio_console_putchar(struct uart_port *port, int ch) -{ - struct uart_sio_port *up = (struct uart_sio_port *)port; - - wait_for_xmitr(up); - sio_out(up, SIOTXB, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void m32r_sio_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_sio_port *up = &m32r_sio_ports[co->index]; - unsigned int ier; - - /* - * First save the UER then disable the interrupts - */ - ier = sio_in(up, SIOTRCR); - sio_out(up, SIOTRCR, 0); - - uart_console_write(&up->port, s, count, m32r_sio_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - sio_out(up, SIOTRCR, ier); -} - -static int __init m32r_sio_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= UART_NR) - co->index = 0; - port = &m32r_sio_ports[co->index].port; - - /* - * Temporary fix. - */ - spin_lock_init(&port->lock); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver m32r_sio_reg; -static struct console m32r_sio_console = { - .name = "ttyS", - .write = m32r_sio_console_write, - .device = uart_console_device, - .setup = m32r_sio_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &m32r_sio_reg, -}; - -static int __init m32r_sio_console_init(void) -{ - sio_reset(); - sio_init(); - m32r_sio_init_ports(); - register_console(&m32r_sio_console); - return 0; -} -console_initcall(m32r_sio_console_init); - -#define M32R_SIO_CONSOLE &m32r_sio_console -#else -#define M32R_SIO_CONSOLE NULL -#endif - -static struct uart_driver m32r_sio_reg = { - .owner = THIS_MODULE, - .driver_name = "sio", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = UART_NR, - .cons = M32R_SIO_CONSOLE, -}; - -/** - * m32r_sio_suspend_port - suspend one serial port - * @line: serial line number - * - * Suspend one serial port. - */ -void m32r_sio_suspend_port(int line) -{ - uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port); -} - -/** - * m32r_sio_resume_port - resume one serial port - * @line: serial line number - * - * Resume one serial port. - */ -void m32r_sio_resume_port(int line) -{ - uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port); -} - -static int __init m32r_sio_init(void) -{ - int ret, i; - - printk(KERN_INFO "Serial: M32R SIO driver\n"); - - for (i = 0; i < nr_irqs; i++) - spin_lock_init(&irq_lists[i].lock); - - ret = uart_register_driver(&m32r_sio_reg); - if (ret >= 0) - m32r_sio_register_ports(&m32r_sio_reg); - - return ret; -} - -static void __exit m32r_sio_exit(void) -{ - int i; - - for (i = 0; i < UART_NR; i++) - uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port); - - uart_unregister_driver(&m32r_sio_reg); -} - -module_init(m32r_sio_init); -module_exit(m32r_sio_exit); - -EXPORT_SYMBOL(m32r_sio_suspend_port); -EXPORT_SYMBOL(m32r_sio_resume_port); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic M32R SIO serial driver"); diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h deleted file mode 100644 index e9b7e11793b1..000000000000 --- a/drivers/serial/m32r_sio.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * m32r_sio.h - * - * Driver for M32R serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Based on drivers/serial/8250.h. - * - * Copyright (C) 2001 Russell King. - * Copyright (C) 2004 Hirokazu Takata - * - * 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. - */ - - -struct m32r_sio_probe { - struct module *owner; - int (*pci_init_one)(struct pci_dev *dev); - void (*pci_remove_one)(struct pci_dev *dev); - void (*pnp_init)(void); -}; - -int m32r_sio_register_probe(struct m32r_sio_probe *probe); -void m32r_sio_unregister_probe(struct m32r_sio_probe *probe); -void m32r_sio_get_irq_map(unsigned int *map); -void m32r_sio_suspend_port(int line); -void m32r_sio_resume_port(int line); - -struct old_serial_port { - unsigned int uart; - unsigned int baud_base; - unsigned int port; - unsigned int irq; - unsigned int flags; - unsigned char io_type; - unsigned char __iomem *iomem_base; - unsigned short iomem_reg_shift; -}; - -#define _INLINE_ inline - -#define PROBE_RSA (1 << 0) -#define PROBE_ANY (~0) - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h deleted file mode 100644 index 4671473793e3..000000000000 --- a/drivers/serial/m32r_sio_reg.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * m32r_sio_reg.h - * - * Copyright (C) 1992, 1994 by Theodore Ts'o. - * Copyright (C) 2004 Hirokazu Takata - * - * Redistribution of this file is permitted under the terms of the GNU - * Public License (GPL) - * - * These are the UART port assignments, expressed as offsets from the base - * register. These assignments should hold for any serial port based on - * a 8250, 16450, or 16550(A). - */ - -#ifndef _M32R_SIO_REG_H -#define _M32R_SIO_REG_H - - -#ifdef CONFIG_SERIAL_M32R_PLDSIO - -#define SIOCR 0x000 -#define SIOMOD0 0x002 -#define SIOMOD1 0x004 -#define SIOSTS 0x006 -#define SIOTRCR 0x008 -#define SIOBAUR 0x00a -// #define SIORBAUR 0x018 -#define SIOTXB 0x00c -#define SIORXB 0x00e - -#define UART_RX ((unsigned long) PLD_ESIO0RXB) - /* In: Receive buffer (DLAB=0) */ -#define UART_TX ((unsigned long) PLD_ESIO0TXB) - /* Out: Transmit buffer (DLAB=0) */ -#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ -#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx - * In: Fifo count - * Out: Fifo custom trigger levels - * XR16C85x only */ - -#define UART_DLM 0 /* Out: Divisor Latch High (DLAB=1) */ -#define UART_IER ((unsigned long) PLD_ESIO0INTCR) - /* Out: Interrupt Enable Register */ -#define UART_FCTR 0 /* (LCR=BF) Feature Control Register - * XR16C85x only */ - -#define UART_IIR 0 /* In: Interrupt ID Register */ -#define UART_FCR 0 /* Out: FIFO Control Register */ -#define UART_EFR 0 /* I/O: Extended Features Register */ - /* (DLAB=1, 16C660 only) */ - -#define UART_LCR 0 /* Out: Line Control Register */ -#define UART_MCR 0 /* Out: Modem Control Register */ -#define UART_LSR ((unsigned long) PLD_ESIO0STS) - /* In: Line Status Register */ -#define UART_MSR 0 /* In: Modem Status Register */ -#define UART_SCR 0 /* I/O: Scratch Register */ -#define UART_EMSR 0 /* (LCR=BF) Extended Mode Select Register - * FCTR bit 6 selects SCR or EMSR - * XR16c85x only */ - -#else /* not CONFIG_SERIAL_M32R_PLDSIO */ - -#define SIOCR 0x000 -#define SIOMOD0 0x004 -#define SIOMOD1 0x008 -#define SIOSTS 0x00c -#define SIOTRCR 0x010 -#define SIOBAUR 0x014 -#define SIORBAUR 0x018 -#define SIOTXB 0x01c -#define SIORXB 0x020 - -#define UART_RX M32R_SIO0_RXB_PORTL /* In: Receive buffer (DLAB=0) */ -#define UART_TX M32R_SIO0_TXB_PORTL /* Out: Transmit buffer (DLAB=0) */ -#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ -#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx - * In: Fifo count - * Out: Fifo custom trigger levels - * XR16C85x only */ - -#define UART_DLM 0 /* Out: Divisor Latch High (DLAB=1) */ -#define UART_IER M32R_SIO0_TRCR_PORTL /* Out: Interrupt Enable Register */ -#define UART_FCTR 0 /* (LCR=BF) Feature Control Register - * XR16C85x only */ - -#define UART_IIR 0 /* In: Interrupt ID Register */ -#define UART_FCR 0 /* Out: FIFO Control Register */ -#define UART_EFR 0 /* I/O: Extended Features Register */ - /* (DLAB=1, 16C660 only) */ - -#define UART_LCR 0 /* Out: Line Control Register */ -#define UART_MCR 0 /* Out: Modem Control Register */ -#define UART_LSR M32R_SIO0_STS_PORTL /* In: Line Status Register */ -#define UART_MSR 0 /* In: Modem Status Register */ -#define UART_SCR 0 /* I/O: Scratch Register */ -#define UART_EMSR 0 /* (LCR=BF) Extended Mode Select Register - * FCTR bit 6 selects SCR or EMSR - * XR16c85x only */ - -#endif /* CONFIG_SERIAL_M32R_PLDSIO */ - -#define UART_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* - * These are the definitions for the Line Control Register - * - * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting - * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. - */ -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ -#define UART_LCR_SBC 0x40 /* Set break control */ -#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ -#define UART_LCR_EPAR 0x10 /* Even parity select */ -#define UART_LCR_PARITY 0x08 /* Parity Enable */ -#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */ -#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ -#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ -#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ -#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ - -/* - * These are the definitions for the Line Status Register - */ -#define UART_LSR_TEMT 0x02 /* Transmitter empty */ -#define UART_LSR_THRE 0x01 /* Transmit-hold-register empty */ -#define UART_LSR_BI 0x00 /* Break interrupt indicator */ -#define UART_LSR_FE 0x80 /* Frame error indicator */ -#define UART_LSR_PE 0x40 /* Parity error indicator */ -#define UART_LSR_OE 0x20 /* Overrun error indicator */ -#define UART_LSR_DR 0x04 /* Receiver data ready */ - -/* - * These are the definitions for the Interrupt Identification Register - */ -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ - -#define UART_IIR_MSI 0x00 /* Modem status interrupt */ -#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ -#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ -#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ - -/* - * These are the definitions for the Interrupt Enable Register - */ -#define UART_IER_MSI 0x00 /* Enable Modem status interrupt */ -#define UART_IER_RLSI 0x08 /* Enable receiver line status interrupt */ -#define UART_IER_THRI 0x03 /* Enable Transmitter holding register int. */ -#define UART_IER_RDI 0x04 /* Enable receiver data interrupt */ - -#endif /* _M32R_SIO_REG_H */ diff --git a/drivers/serial/max3100.c b/drivers/serial/max3100.c deleted file mode 100644 index beb1afa27d8d..000000000000 --- a/drivers/serial/max3100.c +++ /dev/null @@ -1,926 +0,0 @@ -/* - * - * Copyright (C) 2008 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. - * - * - * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have - * to use polling for flow control. TX empty IRQ is unusable, since - * writing conf clears FIFO buffer and we cannot have this interrupt - * always asking us for attention. - * - * Example platform data: - - static struct plat_max3100 max3100_plat_data = { - .loopback = 0, - .crystal = 0, - .poll_time = 100, - }; - - static struct spi_board_info spi_board_info[] = { - { - .modalias = "max3100", - .platform_data = &max3100_plat_data, - .irq = IRQ_EINT12, - .max_speed_hz = 5*1000*1000, - .chip_select = 0, - }, - }; - - * The initial minor number is 209 in the low-density serial port: - * mknod /dev/ttyMAX0 c 204 209 - */ - -#define MAX3100_MAJOR 204 -#define MAX3100_MINOR 209 -/* 4 MAX3100s should be enough for everyone */ -#define MAX_MAX3100 4 - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAX3100_C (1<<14) -#define MAX3100_D (0<<14) -#define MAX3100_W (1<<15) -#define MAX3100_RX (0<<15) - -#define MAX3100_WC (MAX3100_W | MAX3100_C) -#define MAX3100_RC (MAX3100_RX | MAX3100_C) -#define MAX3100_WD (MAX3100_W | MAX3100_D) -#define MAX3100_RD (MAX3100_RX | MAX3100_D) -#define MAX3100_CMD (3 << 14) - -#define MAX3100_T (1<<14) -#define MAX3100_R (1<<15) - -#define MAX3100_FEN (1<<13) -#define MAX3100_SHDN (1<<12) -#define MAX3100_TM (1<<11) -#define MAX3100_RM (1<<10) -#define MAX3100_PM (1<<9) -#define MAX3100_RAM (1<<8) -#define MAX3100_IR (1<<7) -#define MAX3100_ST (1<<6) -#define MAX3100_PE (1<<5) -#define MAX3100_L (1<<4) -#define MAX3100_BAUD (0xf) - -#define MAX3100_TE (1<<10) -#define MAX3100_RAFE (1<<10) -#define MAX3100_RTS (1<<9) -#define MAX3100_CTS (1<<9) -#define MAX3100_PT (1<<8) -#define MAX3100_DATA (0xff) - -#define MAX3100_RT (MAX3100_R | MAX3100_T) -#define MAX3100_RTC (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE) - -/* the following simulate a status reg for ignore_status_mask */ -#define MAX3100_STATUS_PE 1 -#define MAX3100_STATUS_FE 2 -#define MAX3100_STATUS_OE 4 - -struct max3100_port { - struct uart_port port; - struct spi_device *spi; - - int cts; /* last CTS received for flow ctrl */ - int tx_empty; /* last TX empty bit */ - - spinlock_t conf_lock; /* shared data */ - int conf_commit; /* need to make changes */ - int conf; /* configuration for the MAX31000 - * (bits 0-7, bits 8-11 are irqs) */ - int rts_commit; /* need to change rts */ - int rts; /* rts status */ - int baud; /* current baud rate */ - - int parity; /* keeps track if we should send parity */ -#define MAX3100_PARITY_ON 1 -#define MAX3100_PARITY_ODD 2 -#define MAX3100_7BIT 4 - int rx_enabled; /* if we should rx chars */ - - int irq; /* irq assigned to the max3100 */ - - int minor; /* minor number */ - int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ - int loopback; /* 1 if we are in loopback mode */ - - /* for handling irqs: need workqueue since we do spi_sync */ - struct workqueue_struct *workqueue; - struct work_struct work; - /* set to 1 to make the workhandler exit as soon as possible */ - int force_end_work; - /* need to know we are suspending to avoid deadlock on workqueue */ - int suspending; - - /* hook for suspending MAX3100 via dedicated pin */ - void (*max3100_hw_suspend) (int suspend); - - /* poll time (in ms) for ctrl lines */ - int poll_time; - /* and its timer */ - struct timer_list timer; -}; - -static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ -static DEFINE_MUTEX(max3100s_lock); /* race on probe */ - -static int max3100_do_parity(struct max3100_port *s, u16 c) -{ - int parity; - - if (s->parity & MAX3100_PARITY_ODD) - parity = 1; - else - parity = 0; - - if (s->parity & MAX3100_7BIT) - c &= 0x7f; - else - c &= 0xff; - - parity = parity ^ (hweight8(c) & 1); - return parity; -} - -static int max3100_check_parity(struct max3100_port *s, u16 c) -{ - return max3100_do_parity(s, c) == ((c >> 8) & 1); -} - -static void max3100_calc_parity(struct max3100_port *s, u16 *c) -{ - if (s->parity & MAX3100_7BIT) - *c &= 0x7f; - else - *c &= 0xff; - - if (s->parity & MAX3100_PARITY_ON) - *c |= max3100_do_parity(s, *c) << 8; -} - -static void max3100_work(struct work_struct *w); - -static void max3100_dowork(struct max3100_port *s) -{ - if (!s->force_end_work && !work_pending(&s->work) && - !freezing(current) && !s->suspending) - queue_work(s->workqueue, &s->work); -} - -static void max3100_timeout(unsigned long data) -{ - struct max3100_port *s = (struct max3100_port *)data; - - if (s->port.state) { - max3100_dowork(s); - mod_timer(&s->timer, jiffies + s->poll_time); - } -} - -static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) -{ - struct spi_message message; - u16 etx, erx; - int status; - struct spi_transfer tran = { - .tx_buf = &etx, - .rx_buf = &erx, - .len = 2, - }; - - etx = cpu_to_be16(tx); - spi_message_init(&message); - spi_message_add_tail(&tran, &message); - status = spi_sync(s->spi, &message); - if (status) { - dev_warn(&s->spi->dev, "error while calling spi_sync\n"); - return -EIO; - } - *rx = be16_to_cpu(erx); - s->tx_empty = (*rx & MAX3100_T) > 0; - dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx); - return 0; -} - -static int max3100_handlerx(struct max3100_port *s, u16 rx) -{ - unsigned int ch, flg, status = 0; - int ret = 0, cts; - - if (rx & MAX3100_R && s->rx_enabled) { - dev_dbg(&s->spi->dev, "%s\n", __func__); - ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff); - if (rx & MAX3100_RAFE) { - s->port.icount.frame++; - flg = TTY_FRAME; - status |= MAX3100_STATUS_FE; - } else { - if (s->parity & MAX3100_PARITY_ON) { - if (max3100_check_parity(s, rx)) { - s->port.icount.rx++; - flg = TTY_NORMAL; - } else { - s->port.icount.parity++; - flg = TTY_PARITY; - status |= MAX3100_STATUS_PE; - } - } else { - s->port.icount.rx++; - flg = TTY_NORMAL; - } - } - uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg); - ret = 1; - } - - cts = (rx & MAX3100_CTS) > 0; - if (s->cts != cts) { - s->cts = cts; - uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0); - } - - return ret; -} - -static void max3100_work(struct work_struct *w) -{ - struct max3100_port *s = container_of(w, struct max3100_port, work); - int rxchars; - u16 tx, rx; - int conf, cconf, rts, crts; - struct circ_buf *xmit = &s->port.state->xmit; - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - rxchars = 0; - do { - spin_lock(&s->conf_lock); - conf = s->conf; - cconf = s->conf_commit; - s->conf_commit = 0; - rts = s->rts; - crts = s->rts_commit; - s->rts_commit = 0; - spin_unlock(&s->conf_lock); - if (cconf) - max3100_sr(s, MAX3100_WC | conf, &rx); - if (crts) { - max3100_sr(s, MAX3100_WD | MAX3100_TE | - (s->rts ? MAX3100_RTS : 0), &rx); - rxchars += max3100_handlerx(s, rx); - } - - max3100_sr(s, MAX3100_RD, &rx); - rxchars += max3100_handlerx(s, rx); - - if (rx & MAX3100_T) { - tx = 0xffff; - if (s->port.x_char) { - tx = s->port.x_char; - s->port.icount.tx++; - s->port.x_char = 0; - } else if (!uart_circ_empty(xmit) && - !uart_tx_stopped(&s->port)) { - tx = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); - s->port.icount.tx++; - } - if (tx != 0xffff) { - max3100_calc_parity(s, &tx); - tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0); - max3100_sr(s, tx, &rx); - rxchars += max3100_handlerx(s, rx); - } - } - - if (rxchars > 16 && s->port.state->port.tty != NULL) { - tty_flip_buffer_push(s->port.state->port.tty); - rxchars = 0; - } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&s->port); - - } while (!s->force_end_work && - !freezing(current) && - ((rx & MAX3100_R) || - (!uart_circ_empty(xmit) && - !uart_tx_stopped(&s->port)))); - - if (rxchars > 0 && s->port.state->port.tty != NULL) - tty_flip_buffer_push(s->port.state->port.tty); -} - -static irqreturn_t max3100_irq(int irqno, void *dev_id) -{ - struct max3100_port *s = dev_id; - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - max3100_dowork(s); - return IRQ_HANDLED; -} - -static void max3100_enable_ms(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - if (s->poll_time > 0) - mod_timer(&s->timer, jiffies); - dev_dbg(&s->spi->dev, "%s\n", __func__); -} - -static void max3100_start_tx(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - max3100_dowork(s); -} - -static void max3100_stop_rx(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - s->rx_enabled = 0; - spin_lock(&s->conf_lock); - s->conf &= ~MAX3100_RM; - s->conf_commit = 1; - spin_unlock(&s->conf_lock); - max3100_dowork(s); -} - -static unsigned int max3100_tx_empty(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - /* may not be truly up-to-date */ - max3100_dowork(s); - return s->tx_empty; -} - -static unsigned int max3100_get_mctrl(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - /* may not be truly up-to-date */ - max3100_dowork(s); - /* always assert DCD and DSR since these lines are not wired */ - return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR; -} - -static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - int rts; - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - rts = (mctrl & TIOCM_RTS) > 0; - - spin_lock(&s->conf_lock); - if (s->rts != rts) { - s->rts = rts; - s->rts_commit = 1; - max3100_dowork(s); - } - spin_unlock(&s->conf_lock); -} - -static void -max3100_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - int baud = 0; - unsigned cflag; - u32 param_new, param_mask, parity = 0; - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - cflag = termios->c_cflag; - param_new = 0; - param_mask = 0; - - baud = tty_termios_baud_rate(termios); - param_new = s->conf & MAX3100_BAUD; - switch (baud) { - case 300: - if (s->crystal) - baud = s->baud; - else - param_new = 15; - break; - case 600: - param_new = 14 + s->crystal; - break; - case 1200: - param_new = 13 + s->crystal; - break; - case 2400: - param_new = 12 + s->crystal; - break; - case 4800: - param_new = 11 + s->crystal; - break; - case 9600: - param_new = 10 + s->crystal; - break; - case 19200: - param_new = 9 + s->crystal; - break; - case 38400: - param_new = 8 + s->crystal; - break; - case 57600: - param_new = 1 + s->crystal; - break; - case 115200: - param_new = 0 + s->crystal; - break; - case 230400: - if (s->crystal) - param_new = 0; - else - baud = s->baud; - break; - default: - baud = s->baud; - } - tty_termios_encode_baud_rate(termios, baud, baud); - s->baud = baud; - param_mask |= MAX3100_BAUD; - - if ((cflag & CSIZE) == CS8) { - param_new &= ~MAX3100_L; - parity &= ~MAX3100_7BIT; - } else { - param_new |= MAX3100_L; - parity |= MAX3100_7BIT; - cflag = (cflag & ~CSIZE) | CS7; - } - param_mask |= MAX3100_L; - - if (cflag & CSTOPB) - param_new |= MAX3100_ST; - else - param_new &= ~MAX3100_ST; - param_mask |= MAX3100_ST; - - if (cflag & PARENB) { - param_new |= MAX3100_PE; - parity |= MAX3100_PARITY_ON; - } else { - param_new &= ~MAX3100_PE; - parity &= ~MAX3100_PARITY_ON; - } - param_mask |= MAX3100_PE; - - if (cflag & PARODD) - parity |= MAX3100_PARITY_ODD; - else - parity &= ~MAX3100_PARITY_ODD; - - /* mask termios capabilities we don't support */ - cflag &= ~CMSPAR; - termios->c_cflag = cflag; - - s->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - s->port.ignore_status_mask |= - MAX3100_STATUS_PE | MAX3100_STATUS_FE | - MAX3100_STATUS_OE; - - /* we are sending char from a workqueue so enable */ - s->port.state->port.tty->low_latency = 1; - - if (s->poll_time > 0) - del_timer_sync(&s->timer); - - uart_update_timeout(port, termios->c_cflag, baud); - - spin_lock(&s->conf_lock); - s->conf = (s->conf & ~param_mask) | (param_new & param_mask); - s->conf_commit = 1; - s->parity = parity; - spin_unlock(&s->conf_lock); - max3100_dowork(s); - - if (UART_ENABLE_MS(&s->port, termios->c_cflag)) - max3100_enable_ms(&s->port); -} - -static void max3100_shutdown(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - if (s->suspending) - return; - - s->force_end_work = 1; - - if (s->poll_time > 0) - del_timer_sync(&s->timer); - - if (s->workqueue) { - flush_workqueue(s->workqueue); - destroy_workqueue(s->workqueue); - s->workqueue = NULL; - } - if (s->irq) - free_irq(s->irq, s); - - /* set shutdown mode to save power */ - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(1); - else { - u16 tx, rx; - - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(s, tx, &rx); - } -} - -static int max3100_startup(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - char b[12]; - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - s->conf = MAX3100_RM; - s->baud = s->crystal ? 230400 : 115200; - s->rx_enabled = 1; - - if (s->suspending) - return 0; - - s->force_end_work = 0; - s->parity = 0; - s->rts = 0; - - sprintf(b, "max3100-%d", s->minor); - s->workqueue = create_freezeable_workqueue(b); - if (!s->workqueue) { - dev_warn(&s->spi->dev, "cannot create workqueue\n"); - return -EBUSY; - } - INIT_WORK(&s->work, max3100_work); - - if (request_irq(s->irq, max3100_irq, - IRQF_TRIGGER_FALLING, "max3100", s) < 0) { - dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq); - s->irq = 0; - destroy_workqueue(s->workqueue); - s->workqueue = NULL; - return -EBUSY; - } - - if (s->loopback) { - u16 tx, rx; - tx = 0x4001; - max3100_sr(s, tx, &rx); - } - - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(0); - s->conf_commit = 1; - max3100_dowork(s); - /* wait for clock to settle */ - msleep(50); - - max3100_enable_ms(&s->port); - - return 0; -} - -static const char *max3100_type(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL; -} - -static void max3100_release_port(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); -} - -static void max3100_config_port(struct uart_port *port, int flags) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - if (flags & UART_CONFIG_TYPE) - s->port.type = PORT_MAX3100; -} - -static int max3100_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - int ret = -EINVAL; - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100) - ret = 0; - return ret; -} - -static void max3100_stop_tx(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); -} - -static int max3100_request_port(struct uart_port *port) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - return 0; -} - -static void max3100_break_ctl(struct uart_port *port, int break_state) -{ - struct max3100_port *s = container_of(port, - struct max3100_port, - port); - - dev_dbg(&s->spi->dev, "%s\n", __func__); -} - -static struct uart_ops max3100_ops = { - .tx_empty = max3100_tx_empty, - .set_mctrl = max3100_set_mctrl, - .get_mctrl = max3100_get_mctrl, - .stop_tx = max3100_stop_tx, - .start_tx = max3100_start_tx, - .stop_rx = max3100_stop_rx, - .enable_ms = max3100_enable_ms, - .break_ctl = max3100_break_ctl, - .startup = max3100_startup, - .shutdown = max3100_shutdown, - .set_termios = max3100_set_termios, - .type = max3100_type, - .release_port = max3100_release_port, - .request_port = max3100_request_port, - .config_port = max3100_config_port, - .verify_port = max3100_verify_port, -}; - -static struct uart_driver max3100_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "ttyMAX", - .dev_name = "ttyMAX", - .major = MAX3100_MAJOR, - .minor = MAX3100_MINOR, - .nr = MAX_MAX3100, -}; -static int uart_driver_registered; - -static int __devinit max3100_probe(struct spi_device *spi) -{ - int i, retval; - struct plat_max3100 *pdata; - u16 tx, rx; - - mutex_lock(&max3100s_lock); - - if (!uart_driver_registered) { - uart_driver_registered = 1; - retval = uart_register_driver(&max3100_uart_driver); - if (retval) { - printk(KERN_ERR "Couldn't register max3100 uart driver\n"); - mutex_unlock(&max3100s_lock); - return retval; - } - } - - for (i = 0; i < MAX_MAX3100; i++) - if (!max3100s[i]) - break; - if (i == MAX_MAX3100) { - dev_warn(&spi->dev, "too many MAX3100 chips\n"); - mutex_unlock(&max3100s_lock); - return -ENOMEM; - } - - max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); - if (!max3100s[i]) { - dev_warn(&spi->dev, - "kmalloc for max3100 structure %d failed!\n", i); - mutex_unlock(&max3100s_lock); - return -ENOMEM; - } - max3100s[i]->spi = spi; - max3100s[i]->irq = spi->irq; - spin_lock_init(&max3100s[i]->conf_lock); - dev_set_drvdata(&spi->dev, max3100s[i]); - pdata = spi->dev.platform_data; - max3100s[i]->crystal = pdata->crystal; - max3100s[i]->loopback = pdata->loopback; - max3100s[i]->poll_time = pdata->poll_time * HZ / 1000; - if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) - max3100s[i]->poll_time = 1; - max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; - max3100s[i]->minor = i; - init_timer(&max3100s[i]->timer); - max3100s[i]->timer.function = max3100_timeout; - max3100s[i]->timer.data = (unsigned long) max3100s[i]; - - dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); - max3100s[i]->port.irq = max3100s[i]->irq; - max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200; - max3100s[i]->port.fifosize = 16; - max3100s[i]->port.ops = &max3100_ops; - max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - max3100s[i]->port.line = i; - max3100s[i]->port.type = PORT_MAX3100; - max3100s[i]->port.dev = &spi->dev; - retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); - if (retval < 0) - dev_warn(&spi->dev, - "uart_add_one_port failed for line %d with error %d\n", - i, retval); - - /* set shutdown mode to save power. Will be woken-up on open */ - if (max3100s[i]->max3100_hw_suspend) - max3100s[i]->max3100_hw_suspend(1); - else { - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(max3100s[i], tx, &rx); - } - mutex_unlock(&max3100s_lock); - return 0; -} - -static int __devexit max3100_remove(struct spi_device *spi) -{ - struct max3100_port *s = dev_get_drvdata(&spi->dev); - int i; - - mutex_lock(&max3100s_lock); - - /* find out the index for the chip we are removing */ - for (i = 0; i < MAX_MAX3100; i++) - if (max3100s[i] == s) - break; - - dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i); - uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port); - kfree(max3100s[i]); - max3100s[i] = NULL; - - /* check if this is the last chip we have */ - for (i = 0; i < MAX_MAX3100; i++) - if (max3100s[i]) { - mutex_unlock(&max3100s_lock); - return 0; - } - pr_debug("removing max3100 driver\n"); - uart_unregister_driver(&max3100_uart_driver); - - mutex_unlock(&max3100s_lock); - return 0; -} - -#ifdef CONFIG_PM - -static int max3100_suspend(struct spi_device *spi, pm_message_t state) -{ - struct max3100_port *s = dev_get_drvdata(&spi->dev); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - disable_irq(s->irq); - - s->suspending = 1; - uart_suspend_port(&max3100_uart_driver, &s->port); - - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(1); - else { - /* no HW suspend, so do SW one */ - u16 tx, rx; - - tx = MAX3100_WC | MAX3100_SHDN; - max3100_sr(s, tx, &rx); - } - return 0; -} - -static int max3100_resume(struct spi_device *spi) -{ - struct max3100_port *s = dev_get_drvdata(&spi->dev); - - dev_dbg(&s->spi->dev, "%s\n", __func__); - - if (s->max3100_hw_suspend) - s->max3100_hw_suspend(0); - uart_resume_port(&max3100_uart_driver, &s->port); - s->suspending = 0; - - enable_irq(s->irq); - - s->conf_commit = 1; - if (s->workqueue) - max3100_dowork(s); - - return 0; -} - -#else -#define max3100_suspend NULL -#define max3100_resume NULL -#endif - -static struct spi_driver max3100_driver = { - .driver = { - .name = "max3100", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - - .probe = max3100_probe, - .remove = __devexit_p(max3100_remove), - .suspend = max3100_suspend, - .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_DESCRIPTION("MAX3100 driver"); -MODULE_AUTHOR("Christian Pellegrin "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:max3100"); diff --git a/drivers/serial/max3107-aava.c b/drivers/serial/max3107-aava.c deleted file mode 100644 index a1fe304f2f52..000000000000 --- a/drivers/serial/max3107-aava.c +++ /dev/null @@ -1,344 +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" - -/* GPIO direction to input function */ -static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset) -{ - struct max3107_port *s = container_of(chip, struct max3107_port, chip); - u16 buf[1]; /* Buffer for SPI transfer */ - - if (offset >= MAX3107_GPIO_COUNT) { - dev_err(&s->spi->dev, "Invalid GPIO\n"); - return -EINVAL; - } - - /* Read current GPIO configuration register */ - buf[0] = MAX3107_GPIOCFG_REG; - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { - dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n"); - return -EIO; - } - buf[0] &= MAX3107_SPI_RX_DATA_MASK; - - /* Set GPIO to input */ - buf[0] &= ~(0x0001 << offset); - - /* Write new GPIO configuration register value */ - buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG); - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 2)) { - dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n"); - return -EIO; - } - return 0; -} - -/* GPIO direction to output function */ -static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct max3107_port *s = container_of(chip, struct max3107_port, chip); - u16 buf[2]; /* Buffer for SPI transfers */ - - if (offset >= MAX3107_GPIO_COUNT) { - dev_err(&s->spi->dev, "Invalid GPIO\n"); - return -EINVAL; - } - - /* Read current GPIO configuration and data registers */ - buf[0] = MAX3107_GPIOCFG_REG; - buf[1] = MAX3107_GPIODATA_REG; - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) { - dev_err(&s->spi->dev, "SPI transfer gpio failed\n"); - return -EIO; - } - buf[0] &= MAX3107_SPI_RX_DATA_MASK; - buf[1] &= MAX3107_SPI_RX_DATA_MASK; - - /* Set GPIO to output */ - buf[0] |= (0x0001 << offset); - /* Set value */ - if (value) - buf[1] |= (0x0001 << offset); - else - buf[1] &= ~(0x0001 << offset); - - /* Write new GPIO configuration and data register values */ - buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG); - buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG); - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 4)) { - dev_err(&s->spi->dev, - "SPI transfer for GPIO conf data w failed\n"); - return -EIO; - } - return 0; -} - -/* GPIO value query function */ -static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct max3107_port *s = container_of(chip, struct max3107_port, chip); - u16 buf[1]; /* Buffer for SPI transfer */ - - if (offset >= MAX3107_GPIO_COUNT) { - dev_err(&s->spi->dev, "Invalid GPIO\n"); - return -EINVAL; - } - - /* Read current GPIO data register */ - buf[0] = MAX3107_GPIODATA_REG; - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { - dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n"); - return -EIO; - } - buf[0] &= MAX3107_SPI_RX_DATA_MASK; - - /* Return value */ - return buf[0] & (0x0001 << offset); -} - -/* GPIO value set function */ -static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct max3107_port *s = container_of(chip, struct max3107_port, chip); - u16 buf[2]; /* Buffer for SPI transfers */ - - if (offset >= MAX3107_GPIO_COUNT) { - dev_err(&s->spi->dev, "Invalid GPIO\n"); - return; - } - - /* Read current GPIO configuration registers*/ - buf[0] = MAX3107_GPIODATA_REG; - buf[1] = MAX3107_GPIOCFG_REG; - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) { - dev_err(&s->spi->dev, - "SPI transfer for GPIO data and config read failed\n"); - return; - } - buf[0] &= MAX3107_SPI_RX_DATA_MASK; - buf[1] &= MAX3107_SPI_RX_DATA_MASK; - - if (!(buf[1] & (0x0001 << offset))) { - /* Configured as input, can't set value */ - dev_warn(&s->spi->dev, - "Trying to set value for input GPIO\n"); - return; - } - - /* Set value */ - if (value) - buf[0] |= (0x0001 << offset); - else - buf[0] &= ~(0x0001 << offset); - - /* Write new GPIO data register value */ - buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG); - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n"); -} - -/* GPIO chip data */ -static struct gpio_chip max3107_gpio_chip = { - .owner = THIS_MODULE, - .direction_input = max3107_gpio_direction_in, - .direction_output = max3107_gpio_direction_out, - .get = max3107_gpio_get, - .set = max3107_gpio_set, - .can_sleep = 1, - .base = MAX3107_GPIO_BASE, - .ngpio = MAX3107_GPIO_COUNT, -}; - -/** - * max3107_aava_reset - reset on AAVA systems - * @spi: The SPI device we are probing - * - * Reset the device ready for probing. - */ - -static int max3107_aava_reset(struct spi_device *spi) -{ - /* Reset the chip */ - if (gpio_request(MAX3107_RESET_GPIO, "max3107")) { - pr_err("Requesting RESET GPIO failed\n"); - return -EIO; - } - if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) { - pr_err("Setting RESET GPIO to 0 failed\n"); - gpio_free(MAX3107_RESET_GPIO); - return -EIO; - } - msleep(MAX3107_RESET_DELAY); - if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) { - pr_err("Setting RESET GPIO to 1 failed\n"); - gpio_free(MAX3107_RESET_GPIO); - return -EIO; - } - gpio_free(MAX3107_RESET_GPIO); - msleep(MAX3107_WAKEUP_DELAY); - return 0; -} - -static int max3107_aava_configure(struct max3107_port *s) -{ - int retval; - - /* Initialize GPIO chip data */ - s->chip = max3107_gpio_chip; - s->chip.label = s->spi->modalias; - s->chip.dev = &s->spi->dev; - - /* Add GPIO chip */ - retval = gpiochip_add(&s->chip); - if (retval) { - dev_err(&s->spi->dev, "Adding GPIO chip failed\n"); - return retval; - } - - /* Temporary fix for EV2 boot problems, set modem reset to 0 */ - max3107_gpio_direction_out(&s->chip, 3, 0); - return 0; -} - -#if 0 -/* This will get enabled once we have the board stuff merged for this - specific case */ - -static const struct baud_table brg13_ext[] = { - { 300, MAX3107_BRG13_B300 }, - { 600, MAX3107_BRG13_B600 }, - { 1200, MAX3107_BRG13_B1200 }, - { 2400, MAX3107_BRG13_B2400 }, - { 4800, MAX3107_BRG13_B4800 }, - { 9600, MAX3107_BRG13_B9600 }, - { 19200, MAX3107_BRG13_B19200 }, - { 57600, MAX3107_BRG13_B57600 }, - { 115200, MAX3107_BRG13_B115200 }, - { 230400, MAX3107_BRG13_B230400 }, - { 460800, MAX3107_BRG13_B460800 }, - { 921600, MAX3107_BRG13_B921600 }, - { 0, 0 } -}; - -static void max3107_aava_init(struct max3107_port *s) -{ - /*override for AAVA SC specific*/ - if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) { - if (get_koski_build_id() <= KOSKI_EV2) - if (s->ext_clk) { - s->brg_cfg = MAX3107_BRG13_B9600; - s->baud_tbl = (struct baud_table *)brg13_ext; - } - } -} -#endif - -static int __devexit max3107_aava_remove(struct spi_device *spi) -{ - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - /* Remove GPIO chip */ - if (gpiochip_remove(&s->chip)) - dev_warn(&spi->dev, "Removing GPIO chip failed\n"); - - /* Then do the default remove */ - return max3107_remove(spi); -} - -/* Platform data */ -static struct max3107_plat aava_plat_data = { - .loopback = 0, - .ext_clk = 1, -/* .init = max3107_aava_init, */ - .configure = max3107_aava_configure, - .hw_suspend = max3107_hw_susp, - .polled_mode = 0, - .poll_time = 0, -}; - - -static int __devinit max3107_probe_aava(struct spi_device *spi) -{ - int err = max3107_aava_reset(spi); - if (err < 0) - return err; - return max3107_probe(spi, &aava_plat_data); -} - -/* Spi driver data */ -static struct spi_driver max3107_driver = { - .driver = { - .name = "aava-max3107", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = max3107_probe_aava, - .remove = __devexit_p(max3107_aava_remove), - .suspend = max3107_suspend, - .resume = max3107_resume, -}; - -/* Driver init function */ -static int __init max3107_init(void) -{ - return spi_register_driver(&max3107_driver); -} - -/* Driver exit function */ -static void __exit max3107_exit(void) -{ - spi_unregister_driver(&max3107_driver); -} - -module_init(max3107_init); -module_exit(max3107_exit); - -MODULE_DESCRIPTION("MAX3107 driver"); -MODULE_AUTHOR("Aavamobile"); -MODULE_ALIAS("aava-max3107-spi"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/serial/max3107.c b/drivers/serial/max3107.c deleted file mode 100644 index 910870edf708..000000000000 --- a/drivers/serial/max3107.c +++ /dev/null @@ -1,1213 +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 "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_freezeable_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", - .bus = &spi_bus_type, - .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("max3107-spi"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/serial/max3107.h b/drivers/serial/max3107.h deleted file mode 100644 index 7ab632392502..000000000000 --- a/drivers/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 stucture */ - 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/serial/mcf.c b/drivers/serial/mcf.c deleted file mode 100644 index 3394b7cc1722..000000000000 --- a/drivers/serial/mcf.c +++ /dev/null @@ -1,662 +0,0 @@ -/****************************************************************************/ - -/* - * mcf.c -- Freescale ColdFire UART driver - * - * (C) Copyright 2003-2007, 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. - */ - -/****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/****************************************************************************/ - -/* - * Some boards implement the DTR/DCD lines using GPIO lines, most - * don't. Dummy out the access macros for those that don't. Those - * that do should define these macros somewhere in there board - * specific inlude files. - */ -#if !defined(mcf_getppdcd) -#define mcf_getppdcd(p) (1) -#endif -#if !defined(mcf_getppdtr) -#define mcf_getppdtr(p) (1) -#endif -#if !defined(mcf_setppdtr) -#define mcf_setppdtr(p, v) do { } while (0) -#endif - -/****************************************************************************/ - -/* - * Local per-uart structure. - */ -struct mcf_uart { - struct uart_port port; - unsigned int sigs; /* Local copy of line sigs */ - unsigned char imr; /* Local IMR mirror */ -}; - -/****************************************************************************/ - -static unsigned int mcf_tx_empty(struct uart_port *port) -{ - return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ? - TIOCSER_TEMT : 0; -} - -/****************************************************************************/ - -static unsigned int mcf_get_mctrl(struct uart_port *port) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - unsigned int sigs; - - sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ? - 0 : TIOCM_CTS; - sigs |= (pp->sigs & TIOCM_RTS); - sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); - sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); - - return sigs; -} - -/****************************************************************************/ - -static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - - pp->sigs = sigs; - mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); - if (sigs & TIOCM_RTS) - writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); - else - writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0); -} - -/****************************************************************************/ - -static void mcf_start_tx(struct uart_port *port) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - - pp->imr |= MCFUART_UIR_TXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); -} - -/****************************************************************************/ - -static void mcf_stop_tx(struct uart_port *port) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - - pp->imr &= ~MCFUART_UIR_TXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); -} - -/****************************************************************************/ - -static void mcf_stop_rx(struct uart_port *port) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - - pp->imr &= ~MCFUART_UIR_RXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); -} - -/****************************************************************************/ - -static void mcf_break_ctl(struct uart_port *port, int break_state) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR); - else - writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR); - spin_unlock_irqrestore(&port->lock, flags); -} - -/****************************************************************************/ - -static void mcf_enable_ms(struct uart_port *port) -{ -} - -/****************************************************************************/ - -static int mcf_startup(struct uart_port *port) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - /* Reset UART, get it into known state... */ - writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); - writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); - - /* Enable the UART transmitter and receiver */ - writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, - port->membase + MCFUART_UCR); - - /* Enable RX interrupts now */ - pp->imr = MCFUART_UIR_RXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); - - spin_unlock_irqrestore(&port->lock, flags); - - return 0; -} - -/****************************************************************************/ - -static void mcf_shutdown(struct uart_port *port) -{ - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - /* Disable all interrupts now */ - pp->imr = 0; - writeb(pp->imr, port->membase + MCFUART_UIMR); - - /* Disable UART transmitter and receiver */ - writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); - writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); - - spin_unlock_irqrestore(&port->lock, flags); -} - -/****************************************************************************/ - -static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int baud, baudclk; -#if defined(CONFIG_M5272) - unsigned int baudfr; -#endif - unsigned char mr1, mr2; - - baud = uart_get_baud_rate(port, termios, old, 0, 230400); -#if defined(CONFIG_M5272) - baudclk = (MCF_BUSCLK / baud) / 32; - baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16; -#else - baudclk = ((MCF_BUSCLK / baud) + 16) / 32; -#endif - - mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; - mr2 = 0; - - switch (termios->c_cflag & CSIZE) { - case CS5: mr1 |= MCFUART_MR1_CS5; break; - case CS6: mr1 |= MCFUART_MR1_CS6; break; - case CS7: mr1 |= MCFUART_MR1_CS7; break; - case CS8: - default: mr1 |= MCFUART_MR1_CS8; break; - } - - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & CMSPAR) { - if (termios->c_cflag & PARODD) - mr1 |= MCFUART_MR1_PARITYMARK; - else - mr1 |= MCFUART_MR1_PARITYSPACE; - } else { - if (termios->c_cflag & PARODD) - mr1 |= MCFUART_MR1_PARITYODD; - else - mr1 |= MCFUART_MR1_PARITYEVEN; - } - } else { - mr1 |= MCFUART_MR1_PARITYNONE; - } - - if (termios->c_cflag & CSTOPB) - mr2 |= MCFUART_MR2_STOP2; - else - mr2 |= MCFUART_MR2_STOP1; - - if (termios->c_cflag & CRTSCTS) { - mr1 |= MCFUART_MR1_RXRTS; - mr2 |= MCFUART_MR2_TXCTS; - } - - spin_lock_irqsave(&port->lock, flags); - uart_update_timeout(port, termios->c_cflag, baud); - writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); - writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); - writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR); - writeb(mr1, port->membase + MCFUART_UMR); - writeb(mr2, port->membase + MCFUART_UMR); - writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1); - writeb((baudclk & 0xff), port->membase + MCFUART_UBG2); -#if defined(CONFIG_M5272) - writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD); -#endif - writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER, - port->membase + MCFUART_UCSR); - writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, - port->membase + MCFUART_UCR); - spin_unlock_irqrestore(&port->lock, flags); -} - -/****************************************************************************/ - -static void mcf_rx_chars(struct mcf_uart *pp) -{ - struct uart_port *port = &pp->port; - unsigned char status, ch, flag; - - while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { - ch = readb(port->membase + MCFUART_URB); - flag = TTY_NORMAL; - port->icount.rx++; - - if (status & MCFUART_USR_RXERR) { - writeb(MCFUART_UCR_CMDRESETERR, - port->membase + MCFUART_UCR); - - if (status & MCFUART_USR_RXBREAK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (status & MCFUART_USR_RXPARITY) { - port->icount.parity++; - } else if (status & MCFUART_USR_RXOVERRUN) { - port->icount.overrun++; - } else if (status & MCFUART_USR_RXFRAMING) { - port->icount.frame++; - } - - status &= port->read_status_mask; - - if (status & MCFUART_USR_RXBREAK) - flag = TTY_BREAK; - else if (status & MCFUART_USR_RXPARITY) - flag = TTY_PARITY; - else if (status & MCFUART_USR_RXFRAMING) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - continue; - uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); - } - - tty_flip_buffer_push(port->state->port.tty); -} - -/****************************************************************************/ - -static void mcf_tx_chars(struct mcf_uart *pp) -{ - struct uart_port *port = &pp->port; - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - /* Send special char - probably flow control */ - writeb(port->x_char, port->membase + MCFUART_UTB); - port->x_char = 0; - port->icount.tx++; - return; - } - - while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { - if (xmit->head == xmit->tail) - break; - writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (xmit->head == xmit->tail) { - pp->imr &= ~MCFUART_UIR_TXREADY; - writeb(pp->imr, port->membase + MCFUART_UIMR); - } -} - -/****************************************************************************/ - -static irqreturn_t mcf_interrupt(int irq, void *data) -{ - struct uart_port *port = data; - struct mcf_uart *pp = container_of(port, struct mcf_uart, port); - unsigned int isr; - irqreturn_t ret = IRQ_NONE; - - isr = readb(port->membase + MCFUART_UISR) & pp->imr; - - spin_lock(&port->lock); - if (isr & MCFUART_UIR_RXREADY) { - mcf_rx_chars(pp); - ret = IRQ_HANDLED; - } - if (isr & MCFUART_UIR_TXREADY) { - mcf_tx_chars(pp); - ret = IRQ_HANDLED; - } - spin_unlock(&port->lock); - - return ret; -} - -/****************************************************************************/ - -static void mcf_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_MCF; - port->fifosize = MCFUART_TXFIFOSIZE; - - /* Clear mask, so no surprise interrupts. */ - writeb(0, port->membase + MCFUART_UIMR); - - if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port)) - printk(KERN_ERR "MCF: unable to attach ColdFire UART %d " - "interrupt vector=%d\n", port->line, port->irq); -} - -/****************************************************************************/ - -static const char *mcf_type(struct uart_port *port) -{ - return (port->type == PORT_MCF) ? "ColdFire UART" : NULL; -} - -/****************************************************************************/ - -static int mcf_request_port(struct uart_port *port) -{ - /* UARTs always present */ - return 0; -} - -/****************************************************************************/ - -static void mcf_release_port(struct uart_port *port) -{ - /* Nothing to release... */ -} - -/****************************************************************************/ - -static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF)) - return -EINVAL; - return 0; -} - -/****************************************************************************/ - -/* - * Define the basic serial functions we support. - */ -static const struct uart_ops mcf_uart_ops = { - .tx_empty = mcf_tx_empty, - .get_mctrl = mcf_get_mctrl, - .set_mctrl = mcf_set_mctrl, - .start_tx = mcf_start_tx, - .stop_tx = mcf_stop_tx, - .stop_rx = mcf_stop_rx, - .enable_ms = mcf_enable_ms, - .break_ctl = mcf_break_ctl, - .startup = mcf_startup, - .shutdown = mcf_shutdown, - .set_termios = mcf_set_termios, - .type = mcf_type, - .request_port = mcf_request_port, - .release_port = mcf_release_port, - .config_port = mcf_config_port, - .verify_port = mcf_verify_port, -}; - -static struct mcf_uart mcf_ports[4]; - -#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) - -/****************************************************************************/ -#if defined(CONFIG_SERIAL_MCF_CONSOLE) -/****************************************************************************/ - -int __init early_mcf_setup(struct mcf_platform_uart *platp) -{ - struct uart_port *port; - int i; - - for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { - port = &mcf_ports[i].port; - - port->line = i; - port->type = PORT_MCF; - port->mapbase = platp[i].mapbase; - port->membase = (platp[i].membase) ? platp[i].membase : - (unsigned char __iomem *) port->mapbase; - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = MCF_BUSCLK; - port->flags = ASYNC_BOOT_AUTOCONF; - port->ops = &mcf_uart_ops; - } - - return 0; -} - -/****************************************************************************/ - -static void mcf_console_putc(struct console *co, const char c) -{ - struct uart_port *port = &(mcf_ports + co->index)->port; - int i; - - for (i = 0; (i < 0x10000); i++) { - if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) - break; - } - writeb(c, port->membase + MCFUART_UTB); - for (i = 0; (i < 0x10000); i++) { - if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) - break; - } -} - -/****************************************************************************/ - -static void mcf_console_write(struct console *co, const char *s, unsigned int count) -{ - for (; (count); count--, s++) { - mcf_console_putc(co, *s); - if (*s == '\n') - mcf_console_putc(co, '\r'); - } -} - -/****************************************************************************/ - -static int __init mcf_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = CONFIG_SERIAL_MCF_BAUDRATE; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if ((co->index < 0) || (co->index >= MCF_MAXPORTS)) - co->index = 0; - port = &mcf_ports[co->index].port; - if (port->membase == 0) - 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 mcf_driver; - -static struct console mcf_console = { - .name = "ttyS", - .write = mcf_console_write, - .device = uart_console_device, - .setup = mcf_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &mcf_driver, -}; - -static int __init mcf_console_init(void) -{ - register_console(&mcf_console); - return 0; -} - -console_initcall(mcf_console_init); - -#define MCF_CONSOLE &mcf_console - -/****************************************************************************/ -#else -/****************************************************************************/ - -#define MCF_CONSOLE NULL - -/****************************************************************************/ -#endif /* CONFIG_MCF_CONSOLE */ -/****************************************************************************/ - -/* - * Define the mcf UART driver structure. - */ -static struct uart_driver mcf_driver = { - .owner = THIS_MODULE, - .driver_name = "mcf", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = MCF_MAXPORTS, - .cons = MCF_CONSOLE, -}; - -/****************************************************************************/ - -static int __devinit mcf_probe(struct platform_device *pdev) -{ - struct mcf_platform_uart *platp = pdev->dev.platform_data; - struct uart_port *port; - int i; - - for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { - port = &mcf_ports[i].port; - - port->line = i; - port->type = PORT_MCF; - port->mapbase = platp[i].mapbase; - port->membase = (platp[i].membase) ? platp[i].membase : - (unsigned char __iomem *) platp[i].mapbase; - port->iotype = SERIAL_IO_MEM; - port->irq = platp[i].irq; - port->uartclk = MCF_BUSCLK; - port->ops = &mcf_uart_ops; - port->flags = ASYNC_BOOT_AUTOCONF; - - uart_add_one_port(&mcf_driver, port); - } - - return 0; -} - -/****************************************************************************/ - -static int __devexit mcf_remove(struct platform_device *pdev) -{ - struct uart_port *port; - int i; - - for (i = 0; (i < MCF_MAXPORTS); i++) { - port = &mcf_ports[i].port; - if (port) - uart_remove_one_port(&mcf_driver, port); - } - - return 0; -} - -/****************************************************************************/ - -static struct platform_driver mcf_platform_driver = { - .probe = mcf_probe, - .remove = __devexit_p(mcf_remove), - .driver = { - .name = "mcfuart", - .owner = THIS_MODULE, - }, -}; - -/****************************************************************************/ - -static int __init mcf_init(void) -{ - int rc; - - printk("ColdFire internal UART serial driver\n"); - - rc = uart_register_driver(&mcf_driver); - if (rc) - return rc; - rc = platform_driver_register(&mcf_platform_driver); - if (rc) - return rc; - return 0; -} - -/****************************************************************************/ - -static void __exit mcf_exit(void) -{ - platform_driver_unregister(&mcf_platform_driver); - uart_unregister_driver(&mcf_driver); -} - -/****************************************************************************/ - -module_init(mcf_init); -module_exit(mcf_exit); - -MODULE_AUTHOR("Greg Ungerer "); -MODULE_DESCRIPTION("Freescale ColdFire UART driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mcfuart"); - -/****************************************************************************/ diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c deleted file mode 100644 index d40010a22ecd..000000000000 --- a/drivers/serial/mfd.c +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * mfd.c: driver for High Speed UART device of Intel Medfield platform - * - * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ - * - * (C) Copyright 2010 Intel Corporation - * - * 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; version 2 - * of the License. - */ - -/* Notes: - * 1. DMA channel allocation: 0/1 channel are assigned to port 0, - * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans - * are used for RX, odd chans for TX - * - * 2. In A0 stepping, UART will not support TX half empty flag - * - * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always - * asserted, only when the HW is reset the DDCD and DDSR will - * be triggered - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MFD_HSU_A0_STEPPING 1 - -#define HSU_DMA_BUF_SIZE 2048 - -#define chan_readl(chan, offset) readl(chan->reg + offset) -#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) - -#define mfd_readl(obj, offset) readl(obj->reg + offset) -#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) - -#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10) - -struct hsu_dma_buffer { - u8 *buf; - dma_addr_t dma_addr; - u32 dma_size; - u32 ofs; -}; - -struct hsu_dma_chan { - u32 id; - enum dma_data_direction dirt; - struct uart_hsu_port *uport; - void __iomem *reg; - struct timer_list rx_timer; /* only needed by RX channel */ -}; - -struct uart_hsu_port { - struct uart_port port; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned int lsr_break_flag; - char name[12]; - int index; - struct device *dev; - - struct hsu_dma_chan *txc; - struct hsu_dma_chan *rxc; - struct hsu_dma_buffer txbuf; - struct hsu_dma_buffer rxbuf; - int use_dma; /* flag for DMA/PIO */ - int running; - int dma_tx_on; -}; - -/* Top level data structure of HSU */ -struct hsu_port { - void __iomem *reg; - unsigned long paddr; - unsigned long iolen; - u32 irq; - - struct uart_hsu_port port[3]; - struct hsu_dma_chan chans[10]; - - struct dentry *debugfs; -}; - -static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) -{ - unsigned int val; - - if (offset > UART_MSR) { - offset <<= 2; - val = readl(up->port.membase + offset); - } else - val = (unsigned int)readb(up->port.membase + offset); - - return val; -} - -static inline void serial_out(struct uart_hsu_port *up, int offset, int value) -{ - if (offset > UART_MSR) { - offset <<= 2; - writel(value, up->port.membase + offset); - } else { - unsigned char val = value & 0xff; - writeb(val, up->port.membase + offset); - } -} - -#ifdef CONFIG_DEBUG_FS - -#define HSU_REGS_BUFSIZE 1024 - -static int hsu_show_regs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t port_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct uart_hsu_port *up = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU port[%d] regs:\n", up->index); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static ssize_t dma_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hsu_dma_chan *chan = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU DMA channel [%d] regs:\n", chan->id); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static const struct file_operations port_regs_ops = { - .owner = THIS_MODULE, - .open = hsu_show_regs_open, - .read = port_show_regs, - .llseek = default_llseek, -}; - -static const struct file_operations dma_regs_ops = { - .owner = THIS_MODULE, - .open = hsu_show_regs_open, - .read = dma_show_regs, - .llseek = default_llseek, -}; - -static int hsu_debugfs_init(struct hsu_port *hsu) -{ - int i; - char name[32]; - - hsu->debugfs = debugfs_create_dir("hsu", NULL); - if (!hsu->debugfs) - return -ENOMEM; - - for (i = 0; i < 3; i++) { - snprintf(name, sizeof(name), "port_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); - } - - for (i = 0; i < 6; i++) { - snprintf(name, sizeof(name), "dma_chan_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); - } - - return 0; -} - -static void hsu_debugfs_remove(struct hsu_port *hsu) -{ - if (hsu->debugfs) - debugfs_remove_recursive(hsu->debugfs); -} - -#else -static inline int hsu_debugfs_init(struct hsu_port *hsu) -{ - return 0; -} - -static inline void hsu_debugfs_remove(struct hsu_port *hsu) -{ -} -#endif /* CONFIG_DEBUG_FS */ - -static void serial_hsu_enable_ms(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -void hsu_dma_tx(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - struct hsu_dma_buffer *dbuf = &up->txbuf; - int count; - - /* test_and_set_bit may be better, but anyway it's in lock protected mode */ - if (up->dma_tx_on) - return; - - /* Update the circ buf info */ - xmit->tail += dbuf->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - up->port.icount.tx += dbuf->ofs; - dbuf->ofs = 0; - - /* Disable the channel */ - chan_writel(up->txc, HSU_CH_CR, 0x0); - - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { - dma_sync_single_for_device(up->port.dev, - dbuf->dma_addr, - dbuf->dma_size, - DMA_TO_DEVICE); - - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dbuf->ofs = count; - - /* Reprogram the channel */ - chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); - chan_writel(up->txc, HSU_CH_D0TSR, count); - - /* Reenable the channel */ - chan_writel(up->txc, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24)); - up->dma_tx_on = 1; - chan_writel(up->txc, HSU_CH_CR, 0x1); - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); -} - -/* The buffer is already cache coherent */ -void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) -{ - dbuf->ofs = 0; - - chan_writel(rxc, HSU_CH_BSR, 32); - chan_writel(rxc, HSU_CH_MOTSR, 4); - - chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - chan_writel(rxc, HSU_CH_CR, 0x3); - - mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); -} - -/* Protected by spin_lock_irqsave(port->lock) */ -static void serial_hsu_start_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - if (up->use_dma) { - hsu_dma_tx(up); - } else if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_hsu_stop_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *txc = up->txc; - - if (up->use_dma) - chan_writel(txc, HSU_CH_CR, 0x0); - else if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -/* This is always called in spinlock protected mode, so - * modify timeout timer is safe here */ -void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) -{ - struct hsu_dma_buffer *dbuf = &up->rxbuf; - struct hsu_dma_chan *chan = up->rxc; - struct uart_port *port = &up->port; - struct tty_struct *tty = port->state->port.tty; - int count; - - if (!tty) - return; - - /* - * First need to know how many is already transferred, - * then check if its a timeout DMA irq, and return - * the trail bytes out, push them up and reenable the - * channel - */ - - /* Timeout IRQ, need wait some time, see Errata 2 */ - if (int_sts & 0xf00) - udelay(2); - - /* Stop the channel */ - chan_writel(chan, HSU_CH_CR, 0x0); - - count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; - if (!count) { - /* Restart the channel before we leave */ - chan_writel(chan, HSU_CH_CR, 0x3); - return; - } - del_timer(&chan->rx_timer); - - dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* - * Head will only wrap around when we recycle - * the DMA buffer, and when that happens, we - * explicitly set tail to 0. So head will - * always be greater than tail. - */ - tty_insert_flip_string(tty, dbuf->buf, count); - port->icount.rx += count; - - dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* Reprogram the channel */ - chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(chan, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - tty_flip_buffer_push(tty); - - chan_writel(chan, HSU_CH_CR, 0x3); - chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ; - add_timer(&chan->rx_timer); - -} - -static void serial_hsu_stop_rx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *chan = up->rxc; - - if (up->use_dma) - chan_writel(chan, HSU_CH_CR, 0x2); - else { - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); - } -} - -static inline void receive_chars(struct uart_hsu_port *up, int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned int ch, flag; - unsigned int max_count = 256; - - if (!tty) - return; - - do { - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - - dev_warn(up->dev, "We really rush into ERR/BI case" - "status = 0x%02x", *status); - /* For statistics only */ - if (*status & UART_LSR_BI) { - *status &= ~(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 (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* Mask off conditions which should be ignored. */ - *status &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - if (up->port.cons && - up->port.cons->index == up->port.line) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } -#endif - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - - uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); - ignore_char: - *status = serial_in(up, UART_LSR); - } while ((*status & UART_LSR_DR) && max_count--); - tty_flip_buffer_push(tty); -} - -static void transmit_chars(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_hsu_stop_tx(&up->port); - return; - } - -#ifndef MFD_HSU_A0_STEPPING - count = up->port.fifosize / 2; -#else - /* - * A0 only supports fully empty IRQ, and the first char written - * into it won't clear the EMPT bit, so we may need be cautious - * by useing a shorter buffer - */ - count = up->port.fifosize - 4; -#endif - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_hsu_stop_tx(&up->port); -} - -static inline void check_modem_status(struct uart_hsu_port *up) -{ - int status; - - status = serial_in(up, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - /* We may only get DDCD when HW init and reset */ - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - /* Will start/stop_tx accordingly */ - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -/* - * This handles the interrupt from one port. - */ -static irqreturn_t port_irq(int irq, void *dev_id) -{ - struct uart_hsu_port *up = dev_id; - unsigned int iir, lsr; - unsigned long flags; - - if (unlikely(!up->running)) - return IRQ_NONE; - - spin_lock_irqsave(&up->port.lock, flags); - if (up->use_dma) { - lsr = serial_in(up, UART_LSR); - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) - dev_warn(up->dev, - "Got lsr irq while using DMA, lsr = 0x%2x\n", - lsr); - check_modem_status(up); - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; - } - - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) { - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_NONE; - } - - lsr = serial_in(up, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr); - check_modem_status(up); - - /* lsr will be renewed during the receive_chars */ - if (lsr & UART_LSR_THRE) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; -} - -static inline void dma_chan_irq(struct hsu_dma_chan *chan) -{ - struct uart_hsu_port *up = chan->uport; - unsigned long flags; - u32 int_sts; - - spin_lock_irqsave(&up->port.lock, flags); - - if (!up->use_dma || !up->running) - goto exit; - - /* - * No matter what situation, need read clear the IRQ status - * There is a bug, see Errata 5, HSD 2900918 - */ - int_sts = chan_readl(chan, HSU_CH_SR); - - /* Rx channel */ - if (chan->dirt == DMA_FROM_DEVICE) - hsu_dma_rx(up, int_sts); - - /* Tx channel */ - if (chan->dirt == DMA_TO_DEVICE) { - chan_writel(chan, HSU_CH_CR, 0x0); - up->dma_tx_on = 0; - hsu_dma_tx(up); - } - -exit: - spin_unlock_irqrestore(&up->port.lock, flags); - return; -} - -static irqreturn_t dma_irq(int irq, void *dev_id) -{ - struct hsu_port *hsu = dev_id; - u32 int_sts, i; - - int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); - - /* Currently we only have 6 channels may be used */ - for (i = 0; i < 6; i++) { - if (int_sts & 0x1) - dma_chan_irq(&hsu->chans[i]); - int_sts >>= 1; - } - - return IRQ_HANDLED; -} - -static unsigned int serial_hsu_tx_empty(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - unsigned int ret; - - 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); - - return ret; -} - -static unsigned int serial_hsu_get_mctrl(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char status; - unsigned int ret; - - status = serial_in(up, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr |= up->mcr; - - serial_out(up, UART_MCR, mcr); -} - -static void serial_hsu_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* - * What special to do: - * 1. chose the 64B fifo mode - * 2. make sure not to select half empty mode for A0 stepping - * 3. start dma or pio depends on configuration - * 4. we only allocate dma memory when needed - */ -static int serial_hsu_startup(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - /* Clear the interrupt registers. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - /* Now, initialize the UART, default is 8n1 */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - - up->port.mctrl |= TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - if (!up->use_dma) - up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; - else - up->ier = 0; - serial_out(up, UART_IER, up->ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - - /* DMA init */ - if (up->use_dma) { - struct hsu_dma_buffer *dbuf; - struct circ_buf *xmit = &port->state->xmit; - - up->dma_tx_on = 0; - - /* First allocate the RX buffer */ - dbuf = &up->rxbuf; - dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); - if (!dbuf->buf) { - up->use_dma = 0; - goto exit; - } - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - HSU_DMA_BUF_SIZE, - DMA_FROM_DEVICE); - dbuf->dma_size = HSU_DMA_BUF_SIZE; - - /* Start the RX channel right now */ - hsu_dma_start_rx_chan(up->rxc, dbuf); - - /* Next init the TX DMA */ - dbuf = &up->txbuf; - dbuf->buf = xmit->buf; - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - dbuf->dma_size = UART_XMIT_SIZE; - - /* This should not be changed all around */ - chan_writel(up->txc, HSU_CH_BSR, 32); - chan_writel(up->txc, HSU_CH_MOTSR, 4); - dbuf->ofs = 0; - } - -exit: - /* And clear the interrupt registers again for luck. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - up->running = 1; - return 0; -} - -static void serial_hsu_shutdown(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - del_timer_sync(&up->rxc->rx_timer); - - /* Disable interrupts from this port */ - up->ier = 0; - serial_out(up, UART_IER, 0); - up->running = 0; - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); -} - -static void -serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct tty_struct *tty = port->state->port.tty; - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - u32 ps, mul; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - /* CMSPAR isn't supported by this driver */ - if (tty) - tty->termios->c_cflag &= ~CMSPAR; - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * The base clk is 50Mhz, and the baud rate come from: - * baud = 50M * MUL / (DIV * PS * DLAB) - * - * For those basic low baud rate we can get the direct - * scalar from 2746800, like 115200 = 2746800/24. For those - * higher baud rate, we handle them case by case, mainly by - * adjusting the MUL/PS registers, and DIV register is kept - * as default value 0x3d09 to make things simple - */ - baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - - quot = 1; - ps = 0x10; - mul = 0x3600; - switch (baud) { - case 3500000: - mul = 0x3345; - ps = 0xC; - break; - case 1843200: - mul = 0x2400; - break; - case 3000000: - case 2500000: - case 2000000: - case 1500000: - case 1000000: - case 500000: - /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ - mul = baud / 500000 * 0x9C4; - break; - default: - /* Use uart_get_divisor to get quot for other baud rates */ - quot = 0; - } - - if (!quot) - quot = uart_get_divisor(port, baud); - - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; - else if ((up->port.uartclk / quot) < (230400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; - - fcr |= UART_FCR_HSU_64B_FIFO; -#ifdef MFD_HSU_A0_STEPPING - /* A0 doesn't support half empty IRQ */ - fcr |= UART_FCR_FULL_EMPT_TXI; -#endif - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* Update the per-port timeout */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* Characters to ignore */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* Ignore all characters if CREAD is not set */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts, disable - * MSI by default - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE | UART_MCR_RTS; - else - up->mcr &= ~UART_MCR_AFE; - - serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ - serial_out(up, UART_LCR, cval); /* reset DLAB */ - serial_out(up, UART_MUL, mul); /* set MUL */ - serial_out(up, UART_PS, ps); /* set PS */ - up->lcr = cval; /* Save LCR */ - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -serial_hsu_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ -} - -static void serial_hsu_release_port(struct uart_port *port) -{ -} - -static int serial_hsu_request_port(struct uart_port *port) -{ - return 0; -} - -static void serial_hsu_config_port(struct uart_port *port, int flags) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - up->port.type = PORT_MFD; -} - -static int -serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* We don't want the core code to modify any port params */ - return -EINVAL; -} - -static const char * -serial_hsu_type(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - return up->name; -} - -/* Mainly for uart console use */ -static struct uart_hsu_port *serial_hsu_ports[3]; -static struct uart_driver serial_hsu_reg; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_hsu_port *up) -{ - unsigned int status, tmout = 1000; - - /* Wait up to 1ms for the character to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while (!(status & BOTH_EMPTY)); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) - udelay(1); - } -} - -static void serial_hsu_console_putchar(struct uart_port *port, int ch) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial_hsu_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_hsu_port *up = serial_hsu_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - 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 */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, serial_hsu_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static struct console serial_hsu_console; - -static int __init -serial_hsu_console_setup(struct console *co, char *options) -{ - struct uart_hsu_port *up; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - if (co->index == -1 || co->index >= serial_hsu_reg.nr) - co->index = 0; - up = serial_hsu_ports[co->index]; - if (!up) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - ret = uart_set_options(&up->port, co, baud, parity, bits, flow); - - return ret; -} - -static struct console serial_hsu_console = { - .name = "ttyMFD", - .write = serial_hsu_console_write, - .device = uart_console_device, - .setup = serial_hsu_console_setup, - .flags = CON_PRINTBUFFER, - .index = 2, - .data = &serial_hsu_reg, -}; -#endif - -struct uart_ops serial_hsu_pops = { - .tx_empty = serial_hsu_tx_empty, - .set_mctrl = serial_hsu_set_mctrl, - .get_mctrl = serial_hsu_get_mctrl, - .stop_tx = serial_hsu_stop_tx, - .start_tx = serial_hsu_start_tx, - .stop_rx = serial_hsu_stop_rx, - .enable_ms = serial_hsu_enable_ms, - .break_ctl = serial_hsu_break_ctl, - .startup = serial_hsu_startup, - .shutdown = serial_hsu_shutdown, - .set_termios = serial_hsu_set_termios, - .pm = serial_hsu_pm, - .type = serial_hsu_type, - .release_port = serial_hsu_release_port, - .request_port = serial_hsu_request_port, - .config_port = serial_hsu_config_port, - .verify_port = serial_hsu_verify_port, -}; - -static struct uart_driver serial_hsu_reg = { - .owner = THIS_MODULE, - .driver_name = "MFD serial", - .dev_name = "ttyMFD", - .major = TTY_MAJOR, - .minor = 128, - .nr = 3, -}; - -#ifdef CONFIG_PM -static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - /* Make sure this is not the internal dma controller */ - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_suspend_port(&serial_hsu_reg, &up->port); - } - - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int serial_hsu_resume(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) - dev_warn(&pdev->dev, - "HSU: can't re-enable device, try to continue\n"); - - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_resume_port(&serial_hsu_reg, &up->port); - } - return 0; -} -#else -#define serial_hsu_suspend NULL -#define serial_hsu_resume NULL -#endif - -/* temp global pointer before we settle down on using one or four PCI dev */ -static struct hsu_port *phsu; - -static int serial_hsu_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct uart_hsu_port *uport; - int index, ret; - - printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", - pdev->vendor, pdev->device); - - switch (pdev->device) { - case 0x081B: - index = 0; - break; - case 0x081C: - index = 1; - break; - case 0x081D: - index = 2; - break; - case 0x081E: - /* internal DMA controller */ - index = 3; - break; - default: - dev_err(&pdev->dev, "HSU: out of index!"); - return -ENODEV; - } - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - if (index == 3) { - /* DMA controller */ - ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - pci_set_drvdata(pdev, phsu); - } else { - /* UART port 0~2 */ - uport = &phsu->port[index]; - uport->port.irq = pdev->irq; - uport->port.dev = &pdev->dev; - uport->dev = &pdev->dev; - - ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - uart_add_one_port(&serial_hsu_reg, &uport->port); - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - if (index == 2) { - register_console(&serial_hsu_console); - uport->port.cons = &serial_hsu_console; - } -#endif - pci_set_drvdata(pdev, uport); - } - - return 0; - -err_disable: - pci_disable_device(pdev); - return ret; -} - -static void hsu_dma_rx_timeout(unsigned long data) -{ - struct hsu_dma_chan *chan = (void *)data; - struct uart_hsu_port *up = chan->uport; - struct hsu_dma_buffer *dbuf = &up->rxbuf; - int count = 0; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; - - if (!count) { - mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); - goto exit; - } - - hsu_dma_rx(up, 0); -exit: - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void hsu_global_init(void) -{ - struct hsu_port *hsu; - struct uart_hsu_port *uport; - struct hsu_dma_chan *dchan; - int i, ret; - - hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); - if (!hsu) - return; - - /* Get basic io resource and map it */ - hsu->paddr = 0xffa28000; - hsu->iolen = 0x1000; - - if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) - pr_warning("HSU: error in request mem region\n"); - - hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); - if (!hsu->reg) { - pr_err("HSU: error in ioremap\n"); - ret = -ENOMEM; - goto err_free_region; - } - - /* Initialise the 3 UART ports */ - uport = hsu->port; - for (i = 0; i < 3; i++) { - uport->port.type = PORT_MFD; - uport->port.iotype = UPIO_MEM; - uport->port.mapbase = (resource_size_t)hsu->paddr - + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - - sprintf(uport->name, "hsu_port%d", i); - uport->port.fifosize = 64; - uport->port.ops = &serial_hsu_pops; - uport->port.line = i; - uport->port.flags = UPF_IOREMAP; - /* set the scalable maxim support rate to 2746800 bps */ - uport->port.uartclk = 115200 * 24 * 16; - - uport->running = 0; - uport->txc = &hsu->chans[i * 2]; - uport->rxc = &hsu->chans[i * 2 + 1]; - - serial_hsu_ports[i] = uport; - uport->index = i; - uport++; - } - - /* Initialise 6 dma channels */ - dchan = hsu->chans; - for (i = 0; i < 6; i++) { - dchan->id = i; - dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - dchan->uport = &hsu->port[i/2]; - dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + - i * HSU_DMA_CHANS_REG_LENGTH; - - /* Work around for RX */ - if (dchan->dirt == DMA_FROM_DEVICE) { - init_timer(&dchan->rx_timer); - dchan->rx_timer.function = hsu_dma_rx_timeout; - dchan->rx_timer.data = (unsigned long)dchan; - } - dchan++; - } - - phsu = hsu; - hsu_debugfs_init(hsu); - return; - -err_free_region: - release_mem_region(hsu->paddr, hsu->iolen); - kfree(hsu); - return; -} - -static void serial_hsu_remove(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - if (!priv) - return; - - /* For port 0/1/2, priv is the address of uart_hsu_port */ - if (pdev->device != 0x081E) { - up = priv; - uart_remove_one_port(&serial_hsu_reg, &up->port); - } - - pci_set_drvdata(pdev, NULL); - free_irq(pdev->irq, priv); - pci_disable_device(pdev); -} - -/* First 3 are UART ports, and the 4th is the DMA */ -static const struct pci_device_id pci_ids[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, - {}, -}; - -static struct pci_driver hsu_pci_driver = { - .name = "HSU serial", - .id_table = pci_ids, - .probe = serial_hsu_probe, - .remove = __devexit_p(serial_hsu_remove), - .suspend = serial_hsu_suspend, - .resume = serial_hsu_resume, -}; - -static int __init hsu_pci_init(void) -{ - int ret; - - hsu_global_init(); - - ret = uart_register_driver(&serial_hsu_reg); - if (ret) - return ret; - - return pci_register_driver(&hsu_pci_driver); -} - -static void __exit hsu_pci_exit(void) -{ - pci_unregister_driver(&hsu_pci_driver); - uart_unregister_driver(&serial_hsu_reg); - - hsu_debugfs_remove(phsu); - - kfree(phsu); -} - -module_init(hsu_pci_init); -module_exit(hsu_pci_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:medfield-hsu"); diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c deleted file mode 100644 index 126ec7f568ec..000000000000 --- a/drivers/serial/mpc52xx_uart.c +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. - * - * FIXME According to the usermanual the status bits in the status register - * are only updated when the peripherals access the FIFO and not when the - * CPU access them. So since we use this bits to know when we stop writing - * and reading, they may not be updated in-time and a race condition may - * exists. But I haven't be able to prove this and I don't care. But if - * any problem arises, it might worth checking. The TX/RX FIFO Stats - * registers should be used in addition. - * Update: Actually, they seem updated ... At least the bits we use. - * - * - * Maintainer : Sylvain Munaut - * - * Some of the code has been inspired/copied from the 2.4 code written - * by Dale Farnsworth . - * - * Copyright (C) 2008 Freescale Semiconductor Inc. - * John Rigby - * Added support for MPC5121 - * Copyright (C) 2006 Secret Lab Technologies Ltd. - * Grant Likely - * Copyright (C) 2004-2006 Sylvain Munaut - * Copyright (C) 2003 MontaVista, Software, Inc. - * - * 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. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - - -/* We've been assigned a range on the "Low-density serial ports" major */ -#define SERIAL_PSC_MAJOR 204 -#define SERIAL_PSC_MINOR 148 - - -#define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */ - - -static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; - /* Rem: - We use the read_status_mask as a shadow of - * psc->mpc52xx_psc_imr - * - It's important that is array is all zero on start as we - * use it to know if it's initialized or not ! If it's not sure - * it's cleared, then a memset(...,0,...) should be added to - * the console_init - */ - -/* lookup table for matching device nodes to index numbers */ -static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; - -static void mpc52xx_uart_of_enumerate(void); - - -#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) - - -/* Forward declaration of the interruption handling routine */ -static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); -static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); - - -/* Simple macro to test if a port is console or not. This one is taken - * for serial_core.c and maybe should be moved to serial_core.h ? */ -#ifdef CONFIG_SERIAL_CORE_CONSOLE -#define uart_console(port) \ - ((port)->cons && (port)->cons->index == (port)->line) -#else -#define uart_console(port) (0) -#endif - -/* ======================================================================== */ -/* PSC fifo operations for isolating differences between 52xx and 512x */ -/* ======================================================================== */ - -struct psc_ops { - void (*fifo_init)(struct uart_port *port); - int (*raw_rx_rdy)(struct uart_port *port); - int (*raw_tx_rdy)(struct uart_port *port); - int (*rx_rdy)(struct uart_port *port); - int (*tx_rdy)(struct uart_port *port); - int (*tx_empty)(struct uart_port *port); - void (*stop_rx)(struct uart_port *port); - void (*start_tx)(struct uart_port *port); - void (*stop_tx)(struct uart_port *port); - void (*rx_clr_irq)(struct uart_port *port); - void (*tx_clr_irq)(struct uart_port *port); - void (*write_char)(struct uart_port *port, unsigned char c); - unsigned char (*read_char)(struct uart_port *port); - void (*cw_disable_ints)(struct uart_port *port); - void (*cw_restore_ints)(struct uart_port *port); - unsigned int (*set_baudrate)(struct uart_port *port, - struct ktermios *new, - struct ktermios *old); - int (*clock)(struct uart_port *port, int enable); - int (*fifoc_init)(void); - void (*fifoc_uninit)(void); - void (*get_irq)(struct uart_port *, struct device_node *); - irqreturn_t (*handle_irq)(struct uart_port *port); -}; - -/* setting the prescaler and divisor reg is common for all chips */ -static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc, - u16 prescaler, unsigned int divisor) -{ - /* select prescaler */ - out_be16(&psc->mpc52xx_psc_clock_select, prescaler); - out_8(&psc->ctur, divisor >> 8); - out_8(&psc->ctlr, divisor & 0xff); -} - -#ifdef CONFIG_PPC_MPC52xx -#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) -static void mpc52xx_psc_fifo_init(struct uart_port *port) -{ - struct mpc52xx_psc __iomem *psc = PSC(port); - struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); - - out_8(&fifo->rfcntl, 0x00); - out_be16(&fifo->rfalarm, 0x1ff); - out_8(&fifo->tfcntl, 0x07); - out_be16(&fifo->tfalarm, 0x80); - - port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; - out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); -} - -static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) -{ - return in_be16(&PSC(port)->mpc52xx_psc_status) - & MPC52xx_PSC_SR_RXRDY; -} - -static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) -{ - return in_be16(&PSC(port)->mpc52xx_psc_status) - & MPC52xx_PSC_SR_TXRDY; -} - - -static int mpc52xx_psc_rx_rdy(struct uart_port *port) -{ - return in_be16(&PSC(port)->mpc52xx_psc_isr) - & port->read_status_mask - & MPC52xx_PSC_IMR_RXRDY; -} - -static int mpc52xx_psc_tx_rdy(struct uart_port *port) -{ - return in_be16(&PSC(port)->mpc52xx_psc_isr) - & port->read_status_mask - & MPC52xx_PSC_IMR_TXRDY; -} - -static int mpc52xx_psc_tx_empty(struct uart_port *port) -{ - return in_be16(&PSC(port)->mpc52xx_psc_status) - & MPC52xx_PSC_SR_TXEMP; -} - -static void mpc52xx_psc_start_tx(struct uart_port *port) -{ - port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); -} - -static void mpc52xx_psc_stop_tx(struct uart_port *port) -{ - port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); -} - -static void mpc52xx_psc_stop_rx(struct uart_port *port) -{ - port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); -} - -static void mpc52xx_psc_rx_clr_irq(struct uart_port *port) -{ -} - -static void mpc52xx_psc_tx_clr_irq(struct uart_port *port) -{ -} - -static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c) -{ - out_8(&PSC(port)->mpc52xx_psc_buffer_8, c); -} - -static unsigned char mpc52xx_psc_read_char(struct uart_port *port) -{ - return in_8(&PSC(port)->mpc52xx_psc_buffer_8); -} - -static void mpc52xx_psc_cw_disable_ints(struct uart_port *port) -{ - out_be16(&PSC(port)->mpc52xx_psc_imr, 0); -} - -static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) -{ - out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); -} - -static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) -{ - unsigned int baud; - unsigned int divisor; - - /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */ - baud = uart_get_baud_rate(port, new, old, - port->uartclk / (32 * 0xffff) + 1, - port->uartclk / 32); - divisor = (port->uartclk + 16 * baud) / (32 * baud); - - /* enable the /32 prescaler and set the divisor */ - mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); - return baud; -} - -static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) -{ - unsigned int baud; - unsigned int divisor; - u16 prescaler; - - /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the - * ipb freq */ - baud = uart_get_baud_rate(port, new, old, - port->uartclk / (32 * 0xffff) + 1, - port->uartclk / 4); - divisor = (port->uartclk + 2 * baud) / (4 * baud); - - /* select the proper prescaler and set the divisor */ - if (divisor > 0xffff) { - divisor = (divisor + 4) / 8; - prescaler = 0xdd00; /* /32 */ - } else - prescaler = 0xff00; /* /4 */ - mpc52xx_set_divisor(PSC(port), prescaler, divisor); - return baud; -} - -static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) -{ - port->irqflags = IRQF_DISABLED; - port->irq = irq_of_parse_and_map(np, 0); -} - -/* 52xx specific interrupt handler. The caller holds the port lock */ -static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port) -{ - return mpc5xxx_uart_process_int(port); -} - -static struct psc_ops mpc52xx_psc_ops = { - .fifo_init = mpc52xx_psc_fifo_init, - .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, - .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, - .rx_rdy = mpc52xx_psc_rx_rdy, - .tx_rdy = mpc52xx_psc_tx_rdy, - .tx_empty = mpc52xx_psc_tx_empty, - .stop_rx = mpc52xx_psc_stop_rx, - .start_tx = mpc52xx_psc_start_tx, - .stop_tx = mpc52xx_psc_stop_tx, - .rx_clr_irq = mpc52xx_psc_rx_clr_irq, - .tx_clr_irq = mpc52xx_psc_tx_clr_irq, - .write_char = mpc52xx_psc_write_char, - .read_char = mpc52xx_psc_read_char, - .cw_disable_ints = mpc52xx_psc_cw_disable_ints, - .cw_restore_ints = mpc52xx_psc_cw_restore_ints, - .set_baudrate = mpc5200_psc_set_baudrate, - .get_irq = mpc52xx_psc_get_irq, - .handle_irq = mpc52xx_psc_handle_irq, -}; - -static struct psc_ops mpc5200b_psc_ops = { - .fifo_init = mpc52xx_psc_fifo_init, - .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, - .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, - .rx_rdy = mpc52xx_psc_rx_rdy, - .tx_rdy = mpc52xx_psc_tx_rdy, - .tx_empty = mpc52xx_psc_tx_empty, - .stop_rx = mpc52xx_psc_stop_rx, - .start_tx = mpc52xx_psc_start_tx, - .stop_tx = mpc52xx_psc_stop_tx, - .rx_clr_irq = mpc52xx_psc_rx_clr_irq, - .tx_clr_irq = mpc52xx_psc_tx_clr_irq, - .write_char = mpc52xx_psc_write_char, - .read_char = mpc52xx_psc_read_char, - .cw_disable_ints = mpc52xx_psc_cw_disable_ints, - .cw_restore_ints = mpc52xx_psc_cw_restore_ints, - .set_baudrate = mpc5200b_psc_set_baudrate, - .get_irq = mpc52xx_psc_get_irq, - .handle_irq = mpc52xx_psc_handle_irq, -}; - -#endif /* CONFIG_MPC52xx */ - -#ifdef CONFIG_PPC_MPC512x -#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) - -/* PSC FIFO Controller for mpc512x */ -struct psc_fifoc { - u32 fifoc_cmd; - u32 fifoc_int; - u32 fifoc_dma; - u32 fifoc_axe; - u32 fifoc_debug; -}; - -static struct psc_fifoc __iomem *psc_fifoc; -static unsigned int psc_fifoc_irq; - -static void mpc512x_psc_fifo_init(struct uart_port *port) -{ - /* /32 prescaler */ - out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00); - - out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); - out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); - out_be32(&FIFO_512x(port)->txalarm, 1); - out_be32(&FIFO_512x(port)->tximr, 0); - - out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); - out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); - out_be32(&FIFO_512x(port)->rxalarm, 1); - out_be32(&FIFO_512x(port)->rximr, 0); - - out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); - out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); -} - -static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) -{ - return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); -} - -static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) -{ - return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); -} - -static int mpc512x_psc_rx_rdy(struct uart_port *port) -{ - return in_be32(&FIFO_512x(port)->rxsr) - & in_be32(&FIFO_512x(port)->rximr) - & MPC512x_PSC_FIFO_ALARM; -} - -static int mpc512x_psc_tx_rdy(struct uart_port *port) -{ - return in_be32(&FIFO_512x(port)->txsr) - & in_be32(&FIFO_512x(port)->tximr) - & MPC512x_PSC_FIFO_ALARM; -} - -static int mpc512x_psc_tx_empty(struct uart_port *port) -{ - return in_be32(&FIFO_512x(port)->txsr) - & MPC512x_PSC_FIFO_EMPTY; -} - -static void mpc512x_psc_stop_rx(struct uart_port *port) -{ - unsigned long rx_fifo_imr; - - rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); - rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; - out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); -} - -static void mpc512x_psc_start_tx(struct uart_port *port) -{ - unsigned long tx_fifo_imr; - - tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); - tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; - out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); -} - -static void mpc512x_psc_stop_tx(struct uart_port *port) -{ - unsigned long tx_fifo_imr; - - tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); - tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; - out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); -} - -static void mpc512x_psc_rx_clr_irq(struct uart_port *port) -{ - out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); -} - -static void mpc512x_psc_tx_clr_irq(struct uart_port *port) -{ - out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); -} - -static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) -{ - out_8(&FIFO_512x(port)->txdata_8, c); -} - -static unsigned char mpc512x_psc_read_char(struct uart_port *port) -{ - return in_8(&FIFO_512x(port)->rxdata_8); -} - -static void mpc512x_psc_cw_disable_ints(struct uart_port *port) -{ - port->read_status_mask = - in_be32(&FIFO_512x(port)->tximr) << 16 | - in_be32(&FIFO_512x(port)->rximr); - out_be32(&FIFO_512x(port)->tximr, 0); - out_be32(&FIFO_512x(port)->rximr, 0); -} - -static void mpc512x_psc_cw_restore_ints(struct uart_port *port) -{ - out_be32(&FIFO_512x(port)->tximr, - (port->read_status_mask >> 16) & 0x7f); - out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); -} - -static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) -{ - unsigned int baud; - unsigned int divisor; - - /* - * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on - * pg. 30-10 that the chip supports a /32 and a /10 prescaler. - * Furthermore, it states that "After reset, the prescaler by 10 - * for the UART mode is selected", but the reset register value is - * 0x0000 which means a /32 prescaler. This is wrong. - * - * In reality using /32 prescaler doesn't work, as it is not supported! - * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide", - * Chapter 4.1 PSC in UART Mode. - * Calculate with a /16 prescaler here. - */ - - /* uartclk contains the ips freq */ - baud = uart_get_baud_rate(port, new, old, - port->uartclk / (16 * 0xffff) + 1, - port->uartclk / 16); - divisor = (port->uartclk + 8 * baud) / (16 * baud); - - /* enable the /16 prescaler and set the divisor */ - mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); - return baud; -} - -/* Init PSC FIFO Controller */ -static int __init mpc512x_psc_fifoc_init(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, - "fsl,mpc5121-psc-fifo"); - if (!np) { - pr_err("%s: Can't find FIFOC node\n", __func__); - return -ENODEV; - } - - psc_fifoc = of_iomap(np, 0); - if (!psc_fifoc) { - pr_err("%s: Can't map FIFOC\n", __func__); - of_node_put(np); - return -ENODEV; - } - - psc_fifoc_irq = irq_of_parse_and_map(np, 0); - of_node_put(np); - if (psc_fifoc_irq == NO_IRQ) { - pr_err("%s: Can't get FIFOC irq\n", __func__); - iounmap(psc_fifoc); - return -ENODEV; - } - - return 0; -} - -static void __exit mpc512x_psc_fifoc_uninit(void) -{ - iounmap(psc_fifoc); -} - -/* 512x specific interrupt handler. The caller holds the port lock */ -static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) -{ - unsigned long fifoc_int; - int psc_num; - - /* Read pending PSC FIFOC interrupts */ - fifoc_int = in_be32(&psc_fifoc->fifoc_int); - - /* Check if it is an interrupt for this port */ - psc_num = (port->mapbase & 0xf00) >> 8; - if (test_bit(psc_num, &fifoc_int) || - test_bit(psc_num + 16, &fifoc_int)) - return mpc5xxx_uart_process_int(port); - - return IRQ_NONE; -} - -static int mpc512x_psc_clock(struct uart_port *port, int enable) -{ - struct clk *psc_clk; - int psc_num; - char clk_name[10]; - - if (uart_console(port)) - return 0; - - psc_num = (port->mapbase & 0xf00) >> 8; - snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num); - psc_clk = clk_get(port->dev, clk_name); - if (IS_ERR(psc_clk)) { - dev_err(port->dev, "Failed to get PSC clock entry!\n"); - return -ENODEV; - } - - dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis"); - - if (enable) - clk_enable(psc_clk); - else - clk_disable(psc_clk); - - return 0; -} - -static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) -{ - port->irqflags = IRQF_SHARED; - port->irq = psc_fifoc_irq; -} - -static struct psc_ops mpc512x_psc_ops = { - .fifo_init = mpc512x_psc_fifo_init, - .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, - .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, - .rx_rdy = mpc512x_psc_rx_rdy, - .tx_rdy = mpc512x_psc_tx_rdy, - .tx_empty = mpc512x_psc_tx_empty, - .stop_rx = mpc512x_psc_stop_rx, - .start_tx = mpc512x_psc_start_tx, - .stop_tx = mpc512x_psc_stop_tx, - .rx_clr_irq = mpc512x_psc_rx_clr_irq, - .tx_clr_irq = mpc512x_psc_tx_clr_irq, - .write_char = mpc512x_psc_write_char, - .read_char = mpc512x_psc_read_char, - .cw_disable_ints = mpc512x_psc_cw_disable_ints, - .cw_restore_ints = mpc512x_psc_cw_restore_ints, - .set_baudrate = mpc512x_psc_set_baudrate, - .clock = mpc512x_psc_clock, - .fifoc_init = mpc512x_psc_fifoc_init, - .fifoc_uninit = mpc512x_psc_fifoc_uninit, - .get_irq = mpc512x_psc_get_irq, - .handle_irq = mpc512x_psc_handle_irq, -}; -#endif - -static struct psc_ops *psc_ops; - -/* ======================================================================== */ -/* UART operations */ -/* ======================================================================== */ - -static unsigned int -mpc52xx_uart_tx_empty(struct uart_port *port) -{ - return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0; -} - -static void -mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - if (mctrl & TIOCM_RTS) - out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); - else - out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); -} - -static unsigned int -mpc52xx_uart_get_mctrl(struct uart_port *port) -{ - unsigned int ret = TIOCM_DSR; - u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr); - - if (!(status & MPC52xx_PSC_CTS)) - ret |= TIOCM_CTS; - if (!(status & MPC52xx_PSC_DCD)) - ret |= TIOCM_CAR; - - return ret; -} - -static void -mpc52xx_uart_stop_tx(struct uart_port *port) -{ - /* port->lock taken by caller */ - psc_ops->stop_tx(port); -} - -static void -mpc52xx_uart_start_tx(struct uart_port *port) -{ - /* port->lock taken by caller */ - psc_ops->start_tx(port); -} - -static void -mpc52xx_uart_send_xchar(struct uart_port *port, char ch) -{ - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - - port->x_char = ch; - if (ch) { - /* Make sure tx interrupts are on */ - /* Truly necessary ??? They should be anyway */ - psc_ops->start_tx(port); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void -mpc52xx_uart_stop_rx(struct uart_port *port) -{ - /* port->lock taken by caller */ - psc_ops->stop_rx(port); -} - -static void -mpc52xx_uart_enable_ms(struct uart_port *port) -{ - struct mpc52xx_psc __iomem *psc = PSC(port); - - /* clear D_*-bits by reading them */ - in_8(&psc->mpc52xx_psc_ipcr); - /* enable CTS and DCD as IPC interrupts */ - out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); - - port->read_status_mask |= MPC52xx_PSC_IMR_IPC; - out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); -} - -static void -mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) -{ - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - - if (ctl == -1) - out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK); - else - out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static int -mpc52xx_uart_startup(struct uart_port *port) -{ - struct mpc52xx_psc __iomem *psc = PSC(port); - int ret; - - if (psc_ops->clock) { - ret = psc_ops->clock(port, 1); - if (ret) - return ret; - } - - /* Request IRQ */ - ret = request_irq(port->irq, mpc52xx_uart_int, - port->irqflags, "mpc52xx_psc_uart", port); - if (ret) - return ret; - - /* Reset/activate the port, clear and enable interrupts */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); - - out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ - - psc_ops->fifo_init(port); - - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); - - return 0; -} - -static void -mpc52xx_uart_shutdown(struct uart_port *port) -{ - struct mpc52xx_psc __iomem *psc = PSC(port); - - /* Shut down the port. Leave TX active if on a console port */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - if (!uart_console(port)) - out_8(&psc->command, MPC52xx_PSC_RST_TX); - - port->read_status_mask = 0; - out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); - - if (psc_ops->clock) - psc_ops->clock(port, 0); - - /* Release interrupt */ - free_irq(port->irq, port); -} - -static void -mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) -{ - struct mpc52xx_psc __iomem *psc = PSC(port); - unsigned long flags; - unsigned char mr1, mr2; - unsigned int j; - unsigned int baud; - - /* Prepare what we're gonna write */ - mr1 = 0; - - switch (new->c_cflag & CSIZE) { - case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; - break; - case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; - break; - case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; - break; - case CS8: - default: mr1 |= MPC52xx_PSC_MODE_8_BITS; - } - - if (new->c_cflag & PARENB) { - mr1 |= (new->c_cflag & PARODD) ? - MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; - } else - mr1 |= MPC52xx_PSC_MODE_PARNONE; - - - mr2 = 0; - - if (new->c_cflag & CSTOPB) - mr2 |= MPC52xx_PSC_MODE_TWO_STOP; - else - mr2 |= ((new->c_cflag & CSIZE) == CS5) ? - MPC52xx_PSC_MODE_ONE_STOP_5_BITS : - MPC52xx_PSC_MODE_ONE_STOP; - - if (new->c_cflag & CRTSCTS) { - mr1 |= MPC52xx_PSC_MODE_RXRTS; - mr2 |= MPC52xx_PSC_MODE_TXCTS; - } - - /* Get the lock */ - spin_lock_irqsave(&port->lock, flags); - - /* Do our best to flush TX & RX, so we don't lose anything */ - /* But we don't wait indefinitely ! */ - j = 5000000; /* Maximum wait */ - /* FIXME Can't receive chars since set_termios might be called at early - * boot for the console, all stuff is not yet ready to receive at that - * time and that just makes the kernel oops */ - /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ - while (!mpc52xx_uart_tx_empty(port) && --j) - udelay(1); - - if (!j) - printk(KERN_ERR "mpc52xx_uart.c: " - "Unable to flush RX & TX fifos in-time in set_termios." - "Some chars may have been lost.\n"); - - /* Reset the TX & RX */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); - - /* Send new mode settings */ - out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); - out_8(&psc->mode, mr1); - out_8(&psc->mode, mr2); - baud = psc_ops->set_baudrate(port, new, old); - - /* Update the per-port timeout */ - uart_update_timeout(port, new->c_cflag, baud); - - if (UART_ENABLE_MS(port, new->c_cflag)) - mpc52xx_uart_enable_ms(port); - - /* Reenable TX & RX */ - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); - - /* We're all set, release the lock */ - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char * -mpc52xx_uart_type(struct uart_port *port) -{ - /* - * We keep using PORT_MPC52xx for historic reasons although it applies - * for MPC512x, too, but print "MPC5xxx" to not irritate users - */ - return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL; -} - -static void -mpc52xx_uart_release_port(struct uart_port *port) -{ - /* remapped by us ? */ - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); -} - -static int -mpc52xx_uart_request_port(struct uart_port *port) -{ - int err; - - if (port->flags & UPF_IOREMAP) /* Need to remap ? */ - port->membase = ioremap(port->mapbase, - sizeof(struct mpc52xx_psc)); - - if (!port->membase) - return -EINVAL; - - err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), - "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; - - if (err && (port->flags & UPF_IOREMAP)) { - iounmap(port->membase); - port->membase = NULL; - } - - return err; -} - -static void -mpc52xx_uart_config_port(struct uart_port *port, int flags) -{ - if ((flags & UART_CONFIG_TYPE) - && (mpc52xx_uart_request_port(port) == 0)) - port->type = PORT_MPC52xx; -} - -static int -mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx) - return -EINVAL; - - if ((ser->irq != port->irq) || - (ser->io_type != UPIO_MEM) || - (ser->baud_base != port->uartclk) || - (ser->iomem_base != (void *)port->mapbase) || - (ser->hub6 != 0)) - return -EINVAL; - - return 0; -} - - -static struct uart_ops mpc52xx_uart_ops = { - .tx_empty = mpc52xx_uart_tx_empty, - .set_mctrl = mpc52xx_uart_set_mctrl, - .get_mctrl = mpc52xx_uart_get_mctrl, - .stop_tx = mpc52xx_uart_stop_tx, - .start_tx = mpc52xx_uart_start_tx, - .send_xchar = mpc52xx_uart_send_xchar, - .stop_rx = mpc52xx_uart_stop_rx, - .enable_ms = mpc52xx_uart_enable_ms, - .break_ctl = mpc52xx_uart_break_ctl, - .startup = mpc52xx_uart_startup, - .shutdown = mpc52xx_uart_shutdown, - .set_termios = mpc52xx_uart_set_termios, -/* .pm = mpc52xx_uart_pm, Not supported yet */ -/* .set_wake = mpc52xx_uart_set_wake, Not supported yet */ - .type = mpc52xx_uart_type, - .release_port = mpc52xx_uart_release_port, - .request_port = mpc52xx_uart_request_port, - .config_port = mpc52xx_uart_config_port, - .verify_port = mpc52xx_uart_verify_port -}; - - -/* ======================================================================== */ -/* Interrupt handling */ -/* ======================================================================== */ - -static inline int -mpc52xx_uart_int_rx_chars(struct uart_port *port) -{ - struct tty_struct *tty = port->state->port.tty; - unsigned char ch, flag; - unsigned short status; - - /* While we can read, do so ! */ - while (psc_ops->raw_rx_rdy(port)) { - /* Get the char */ - ch = psc_ops->read_char(port); - - /* Handle sysreq char */ -#ifdef SUPPORT_SYSRQ - if (uart_handle_sysrq_char(port, ch)) { - port->sysrq = 0; - continue; - } -#endif - - /* Store it */ - - flag = TTY_NORMAL; - port->icount.rx++; - - status = in_be16(&PSC(port)->mpc52xx_psc_status); - - if (status & (MPC52xx_PSC_SR_PE | - MPC52xx_PSC_SR_FE | - MPC52xx_PSC_SR_RB)) { - - if (status & MPC52xx_PSC_SR_RB) { - flag = TTY_BREAK; - uart_handle_break(port); - port->icount.brk++; - } else if (status & MPC52xx_PSC_SR_PE) { - flag = TTY_PARITY; - port->icount.parity++; - } - else if (status & MPC52xx_PSC_SR_FE) { - flag = TTY_FRAME; - port->icount.frame++; - } - - /* Clear error condition */ - out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); - - } - tty_insert_flip_char(tty, ch, flag); - if (status & MPC52xx_PSC_SR_OE) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - port->icount.overrun++; - } - } - - spin_unlock(&port->lock); - tty_flip_buffer_push(tty); - spin_lock(&port->lock); - - return psc_ops->raw_rx_rdy(port); -} - -static inline int -mpc52xx_uart_int_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - /* Process out of band chars */ - if (port->x_char) { - psc_ops->write_char(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return 1; - } - - /* Nothing to do ? */ - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mpc52xx_uart_stop_tx(port); - return 0; - } - - /* Send chars */ - while (psc_ops->raw_tx_rdy(port)) { - psc_ops->write_char(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - /* Wake up */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - /* Maybe we're done after all */ - if (uart_circ_empty(xmit)) { - mpc52xx_uart_stop_tx(port); - return 0; - } - - return 1; -} - -static irqreturn_t -mpc5xxx_uart_process_int(struct uart_port *port) -{ - unsigned long pass = ISR_PASS_LIMIT; - unsigned int keepgoing; - u8 status; - - /* While we have stuff to do, we continue */ - do { - /* If we don't find anything to do, we stop */ - keepgoing = 0; - - psc_ops->rx_clr_irq(port); - if (psc_ops->rx_rdy(port)) - keepgoing |= mpc52xx_uart_int_rx_chars(port); - - psc_ops->tx_clr_irq(port); - if (psc_ops->tx_rdy(port)) - keepgoing |= mpc52xx_uart_int_tx_chars(port); - - status = in_8(&PSC(port)->mpc52xx_psc_ipcr); - if (status & MPC52xx_PSC_D_DCD) - uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); - - if (status & MPC52xx_PSC_D_CTS) - uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS)); - - /* Limit number of iteration */ - if (!(--pass)) - keepgoing = 0; - - } while (keepgoing); - - return IRQ_HANDLED; -} - -static irqreturn_t -mpc52xx_uart_int(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - irqreturn_t ret; - - spin_lock(&port->lock); - - ret = psc_ops->handle_irq(port); - - spin_unlock(&port->lock); - - return ret; -} - -/* ======================================================================== */ -/* Console ( if applicable ) */ -/* ======================================================================== */ - -#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE - -static void __init -mpc52xx_console_get_options(struct uart_port *port, - int *baud, int *parity, int *bits, int *flow) -{ - struct mpc52xx_psc __iomem *psc = PSC(port); - unsigned char mr1; - - pr_debug("mpc52xx_console_get_options(port=%p)\n", port); - - /* Read the mode registers */ - out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); - mr1 = in_8(&psc->mode); - - /* CT{U,L}R are write-only ! */ - *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; - - /* Parse them */ - switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { - case MPC52xx_PSC_MODE_5_BITS: - *bits = 5; - break; - case MPC52xx_PSC_MODE_6_BITS: - *bits = 6; - break; - case MPC52xx_PSC_MODE_7_BITS: - *bits = 7; - break; - case MPC52xx_PSC_MODE_8_BITS: - default: - *bits = 8; - } - - if (mr1 & MPC52xx_PSC_MODE_PARNONE) - *parity = 'n'; - else - *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e'; -} - -static void -mpc52xx_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_port *port = &mpc52xx_uart_ports[co->index]; - unsigned int i, j; - - /* Disable interrupts */ - psc_ops->cw_disable_ints(port); - - /* Wait the TX buffer to be empty */ - j = 5000000; /* Maximum wait */ - while (!mpc52xx_uart_tx_empty(port) && --j) - udelay(1); - - /* Write all the chars */ - for (i = 0; i < count; i++, s++) { - /* Line return handling */ - if (*s == '\n') - psc_ops->write_char(port, '\r'); - - /* Send the char */ - psc_ops->write_char(port, *s); - - /* Wait the TX buffer to be empty */ - j = 20000; /* Maximum wait */ - while (!mpc52xx_uart_tx_empty(port) && --j) - udelay(1); - } - - /* Restore interrupt state */ - psc_ops->cw_restore_ints(port); -} - - -static int __init -mpc52xx_console_setup(struct console *co, char *options) -{ - struct uart_port *port = &mpc52xx_uart_ports[co->index]; - struct device_node *np = mpc52xx_uart_nodes[co->index]; - unsigned int uartclk; - struct resource res; - int ret; - - int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", - co, co->index, options); - - if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) { - pr_debug("PSC%x out of range\n", co->index); - return -EINVAL; - } - - if (!np) { - pr_debug("PSC%x not found in device tree\n", co->index); - return -EINVAL; - } - - pr_debug("Console on ttyPSC%x is %s\n", - co->index, mpc52xx_uart_nodes[co->index]->full_name); - - /* Fetch register locations */ - ret = of_address_to_resource(np, 0, &res); - if (ret) { - pr_debug("Could not get resources for PSC%x\n", co->index); - return ret; - } - - uartclk = mpc5xxx_get_bus_frequency(np); - if (uartclk == 0) { - pr_debug("Could not find uart clock frequency!\n"); - return -EINVAL; - } - - /* Basic port init. Needed since we use some uart_??? func before - * real init for early access */ - spin_lock_init(&port->lock); - port->uartclk = uartclk; - port->ops = &mpc52xx_uart_ops; - port->mapbase = res.start; - port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); - port->irq = irq_of_parse_and_map(np, 0); - - if (port->membase == NULL) - return -EINVAL; - - pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n", - (void *)port->mapbase, port->membase, - port->irq, port->uartclk); - - /* Setup the port parameters accoding to options */ - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); - - pr_debug("Setting console parameters: %i %i%c1 flow=%c\n", - baud, bits, parity, flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - - -static struct uart_driver mpc52xx_uart_driver; - -static struct console mpc52xx_console = { - .name = "ttyPSC", - .write = mpc52xx_console_write, - .device = uart_console_device, - .setup = mpc52xx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0) */ - .data = &mpc52xx_uart_driver, -}; - - -static int __init -mpc52xx_console_init(void) -{ - mpc52xx_uart_of_enumerate(); - register_console(&mpc52xx_console); - return 0; -} - -console_initcall(mpc52xx_console_init); - -#define MPC52xx_PSC_CONSOLE &mpc52xx_console -#else -#define MPC52xx_PSC_CONSOLE NULL -#endif - - -/* ======================================================================== */ -/* UART Driver */ -/* ======================================================================== */ - -static struct uart_driver mpc52xx_uart_driver = { - .driver_name = "mpc52xx_psc_uart", - .dev_name = "ttyPSC", - .major = SERIAL_PSC_MAJOR, - .minor = SERIAL_PSC_MINOR, - .nr = MPC52xx_PSC_MAXNUM, - .cons = MPC52xx_PSC_CONSOLE, -}; - -/* ======================================================================== */ -/* OF Platform Driver */ -/* ======================================================================== */ - -static struct of_device_id mpc52xx_uart_of_match[] = { -#ifdef CONFIG_PPC_MPC52xx - { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, }, - { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, - /* binding used by old lite5200 device trees: */ - { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, - /* binding used by efika: */ - { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, -#endif -#ifdef CONFIG_PPC_MPC512x - { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, -#endif - {}, -}; - -static int __devinit -mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match) -{ - int idx = -1; - unsigned int uartclk; - struct uart_port *port = NULL; - struct resource res; - int ret; - - dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match); - - /* Check validity & presence */ - for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++) - if (mpc52xx_uart_nodes[idx] == op->dev.of_node) - break; - if (idx >= MPC52xx_PSC_MAXNUM) - return -EINVAL; - pr_debug("Found %s assigned to ttyPSC%x\n", - mpc52xx_uart_nodes[idx]->full_name, idx); - - /* set the uart clock to the input clock of the psc, the different - * prescalers are taken into account in the set_baudrate() methods - * of the respective chip */ - uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node); - if (uartclk == 0) { - dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); - return -EINVAL; - } - - /* Init the port structure */ - port = &mpc52xx_uart_ports[idx]; - - spin_lock_init(&port->lock); - port->uartclk = uartclk; - port->fifosize = 512; - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF | - (uart_console(port) ? 0 : UPF_IOREMAP); - port->line = idx; - port->ops = &mpc52xx_uart_ops; - port->dev = &op->dev; - - /* Search for IRQ and mapbase */ - ret = of_address_to_resource(op->dev.of_node, 0, &res); - if (ret) - return ret; - - port->mapbase = res.start; - if (!port->mapbase) { - dev_dbg(&op->dev, "Could not allocate resources for PSC\n"); - return -EINVAL; - } - - psc_ops->get_irq(port, op->dev.of_node); - if (port->irq == NO_IRQ) { - dev_dbg(&op->dev, "Could not get irq\n"); - return -EINVAL; - } - - dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", - (void *)port->mapbase, port->irq, port->uartclk); - - /* Add the port to the uart sub-system */ - ret = uart_add_one_port(&mpc52xx_uart_driver, port); - if (ret) - return ret; - - dev_set_drvdata(&op->dev, (void *)port); - return 0; -} - -static int -mpc52xx_uart_of_remove(struct platform_device *op) -{ - struct uart_port *port = dev_get_drvdata(&op->dev); - dev_set_drvdata(&op->dev, NULL); - - if (port) - uart_remove_one_port(&mpc52xx_uart_driver, port); - - return 0; -} - -#ifdef CONFIG_PM -static int -mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) -{ - struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); - - if (port) - uart_suspend_port(&mpc52xx_uart_driver, port); - - return 0; -} - -static int -mpc52xx_uart_of_resume(struct platform_device *op) -{ - struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); - - if (port) - uart_resume_port(&mpc52xx_uart_driver, port); - - return 0; -} -#endif - -static void -mpc52xx_uart_of_assign(struct device_node *np) -{ - int i; - - /* Find the first free PSC number */ - for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { - if (mpc52xx_uart_nodes[i] == NULL) { - of_node_get(np); - mpc52xx_uart_nodes[i] = np; - return; - } - } -} - -static void -mpc52xx_uart_of_enumerate(void) -{ - static int enum_done; - struct device_node *np; - const struct of_device_id *match; - int i; - - if (enum_done) - return; - - /* Assign index to each PSC in device tree */ - for_each_matching_node(np, mpc52xx_uart_of_match) { - match = of_match_node(mpc52xx_uart_of_match, np); - psc_ops = match->data; - mpc52xx_uart_of_assign(np); - } - - enum_done = 1; - - for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { - if (mpc52xx_uart_nodes[i]) - pr_debug("%s assigned to ttyPSC%x\n", - mpc52xx_uart_nodes[i]->full_name, i); - } -} - -MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); - -static struct of_platform_driver mpc52xx_uart_of_driver = { - .probe = mpc52xx_uart_of_probe, - .remove = mpc52xx_uart_of_remove, -#ifdef CONFIG_PM - .suspend = mpc52xx_uart_of_suspend, - .resume = mpc52xx_uart_of_resume, -#endif - .driver = { - .name = "mpc52xx-psc-uart", - .owner = THIS_MODULE, - .of_match_table = mpc52xx_uart_of_match, - }, -}; - - -/* ======================================================================== */ -/* Module */ -/* ======================================================================== */ - -static int __init -mpc52xx_uart_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n"); - - ret = uart_register_driver(&mpc52xx_uart_driver); - if (ret) { - printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", - __FILE__, ret); - return ret; - } - - mpc52xx_uart_of_enumerate(); - - /* - * Map the PSC FIFO Controller and init if on MPC512x. - */ - if (psc_ops && psc_ops->fifoc_init) { - ret = psc_ops->fifoc_init(); - if (ret) - return ret; - } - - ret = of_register_platform_driver(&mpc52xx_uart_of_driver); - if (ret) { - printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n", - __FILE__, ret); - uart_unregister_driver(&mpc52xx_uart_driver); - return ret; - } - - return 0; -} - -static void __exit -mpc52xx_uart_exit(void) -{ - if (psc_ops->fifoc_uninit) - psc_ops->fifoc_uninit(); - - of_unregister_platform_driver(&mpc52xx_uart_of_driver); - uart_unregister_driver(&mpc52xx_uart_driver); -} - - -module_init(mpc52xx_uart_init); -module_exit(mpc52xx_uart_exit); - -MODULE_AUTHOR("Sylvain Munaut "); -MODULE_DESCRIPTION("Freescale MPC52xx PSC UART"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c deleted file mode 100644 index 6a9c6605666a..000000000000 --- a/drivers/serial/mpsc.c +++ /dev/null @@ -1,2159 +0,0 @@ -/* - * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240, - * GT64260, MV64340, MV64360, GT96100, ... ). - * - * Author: Mark A. Greer - * - * Based on an old MPSC driver that was in the linuxppc tree. It appears to - * have been created by Chris Zankel (formerly of MontaVista) but there - * is no proper Copyright so I'm not sure. Apparently, parts were also - * taken from PPCBoot (now U-Boot). Also based on drivers/serial/8250.c - * by Russell King. - * - * 2004 (c) MontaVista, Software, Inc. 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. - */ -/* - * The MPSC interface is much like a typical network controller's interface. - * That is, you set up separate rings of descriptors for transmitting and - * receiving data. There is also a pool of buffers with (one buffer per - * descriptor) that incoming data are dma'd into or outgoing data are dma'd - * out of. - * - * The MPSC requires two other controllers to be able to work. The Baud Rate - * Generator (BRG) provides a clock at programmable frequencies which determines - * the baud rate. The Serial DMA Controller (SDMA) takes incoming data from the - * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the - * MPSC. It is actually the SDMA interrupt that the driver uses to keep the - * transmit and receive "engines" going (i.e., indicate data has been - * transmitted or received). - * - * NOTES: - * - * 1) Some chips have an erratum where several regs cannot be - * read. To work around that, we keep a local copy of those regs in - * 'mpsc_port_info'. - * - * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr - * accesses system mem with coherency enabled. For that reason, the driver - * assumes that coherency for that ctlr has been disabled. This means - * that when in a cache coherent system, the driver has to manually manage - * the data cache on the areas that it touches because the dma_* macro are - * basically no-ops. - * - * 3) There is an erratum (on PPC) where you can't use the instruction to do - * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places - * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed. - * - * 4) AFAICT, hardware flow control isn't supported by the controller --MAG. - */ - - -#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define MPSC_NUM_CTLRS 2 - -/* - * Descriptors and buffers must be cache line aligned. - * Buffers lengths must be multiple of cache line size. - * Number of Tx & Rx descriptors must be powers of 2. - */ -#define MPSC_RXR_ENTRIES 32 -#define MPSC_RXRE_SIZE dma_get_cache_alignment() -#define MPSC_RXR_SIZE (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE) -#define MPSC_RXBE_SIZE dma_get_cache_alignment() -#define MPSC_RXB_SIZE (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE) - -#define MPSC_TXR_ENTRIES 32 -#define MPSC_TXRE_SIZE dma_get_cache_alignment() -#define MPSC_TXR_SIZE (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE) -#define MPSC_TXBE_SIZE dma_get_cache_alignment() -#define MPSC_TXB_SIZE (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE) - -#define MPSC_DMA_ALLOC_SIZE (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \ - + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */) - -/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */ -struct mpsc_rx_desc { - u16 bufsize; - u16 bytecnt; - u32 cmdstat; - u32 link; - u32 buf_ptr; -} __attribute((packed)); - -struct mpsc_tx_desc { - u16 bytecnt; - u16 shadow; - u32 cmdstat; - u32 link; - u32 buf_ptr; -} __attribute((packed)); - -/* - * Some regs that have the erratum that you can't read them are are shared - * between the two MPSC controllers. This struct contains those shared regs. - */ -struct mpsc_shared_regs { - phys_addr_t mpsc_routing_base_p; - phys_addr_t sdma_intr_base_p; - - void __iomem *mpsc_routing_base; - void __iomem *sdma_intr_base; - - u32 MPSC_MRR_m; - u32 MPSC_RCRR_m; - u32 MPSC_TCRR_m; - u32 SDMA_INTR_CAUSE_m; - u32 SDMA_INTR_MASK_m; -}; - -/* The main driver data structure */ -struct mpsc_port_info { - struct uart_port port; /* Overlay uart_port structure */ - - /* Internal driver state for this ctlr */ - u8 ready; - u8 rcv_data; - tcflag_t c_iflag; /* save termios->c_iflag */ - tcflag_t c_cflag; /* save termios->c_cflag */ - - /* Info passed in from platform */ - u8 mirror_regs; /* Need to mirror regs? */ - u8 cache_mgmt; /* Need manual cache mgmt? */ - u8 brg_can_tune; /* BRG has baud tuning? */ - u32 brg_clk_src; - u16 mpsc_max_idle; - int default_baud; - int default_bits; - int default_parity; - int default_flow; - - /* Physical addresses of various blocks of registers (from platform) */ - phys_addr_t mpsc_base_p; - phys_addr_t sdma_base_p; - phys_addr_t brg_base_p; - - /* Virtual addresses of various blocks of registers (from platform) */ - void __iomem *mpsc_base; - void __iomem *sdma_base; - void __iomem *brg_base; - - /* Descriptor ring and buffer allocations */ - void *dma_region; - dma_addr_t dma_region_p; - - dma_addr_t rxr; /* Rx descriptor ring */ - dma_addr_t rxr_p; /* Phys addr of rxr */ - u8 *rxb; /* Rx Ring I/O buf */ - u8 *rxb_p; /* Phys addr of rxb */ - u32 rxr_posn; /* First desc w/ Rx data */ - - dma_addr_t txr; /* Tx descriptor ring */ - dma_addr_t txr_p; /* Phys addr of txr */ - u8 *txb; /* Tx Ring I/O buf */ - u8 *txb_p; /* Phys addr of txb */ - int txr_head; /* Where new data goes */ - int txr_tail; /* Where sent data comes off */ - spinlock_t tx_lock; /* transmit lock */ - - /* Mirrored values of regs we can't read (if 'mirror_regs' set) */ - u32 MPSC_MPCR_m; - u32 MPSC_CHR_1_m; - u32 MPSC_CHR_2_m; - u32 MPSC_CHR_10_m; - u32 BRG_BCR_m; - struct mpsc_shared_regs *shared_regs; -}; - -/* Hooks to platform-specific code */ -int mpsc_platform_register_driver(void); -void mpsc_platform_unregister_driver(void); - -/* Hooks back in to mpsc common to be called by platform-specific code */ -struct mpsc_port_info *mpsc_device_probe(int index); -struct mpsc_port_info *mpsc_device_remove(int index); - -/* Main MPSC Configuration Register Offsets */ -#define MPSC_MMCRL 0x0000 -#define MPSC_MMCRH 0x0004 -#define MPSC_MPCR 0x0008 -#define MPSC_CHR_1 0x000c -#define MPSC_CHR_2 0x0010 -#define MPSC_CHR_3 0x0014 -#define MPSC_CHR_4 0x0018 -#define MPSC_CHR_5 0x001c -#define MPSC_CHR_6 0x0020 -#define MPSC_CHR_7 0x0024 -#define MPSC_CHR_8 0x0028 -#define MPSC_CHR_9 0x002c -#define MPSC_CHR_10 0x0030 -#define MPSC_CHR_11 0x0034 - -#define MPSC_MPCR_FRZ (1 << 9) -#define MPSC_MPCR_CL_5 0 -#define MPSC_MPCR_CL_6 1 -#define MPSC_MPCR_CL_7 2 -#define MPSC_MPCR_CL_8 3 -#define MPSC_MPCR_SBL_1 0 -#define MPSC_MPCR_SBL_2 1 - -#define MPSC_CHR_2_TEV (1<<1) -#define MPSC_CHR_2_TA (1<<7) -#define MPSC_CHR_2_TTCS (1<<9) -#define MPSC_CHR_2_REV (1<<17) -#define MPSC_CHR_2_RA (1<<23) -#define MPSC_CHR_2_CRD (1<<25) -#define MPSC_CHR_2_EH (1<<31) -#define MPSC_CHR_2_PAR_ODD 0 -#define MPSC_CHR_2_PAR_SPACE 1 -#define MPSC_CHR_2_PAR_EVEN 2 -#define MPSC_CHR_2_PAR_MARK 3 - -/* MPSC Signal Routing */ -#define MPSC_MRR 0x0000 -#define MPSC_RCRR 0x0004 -#define MPSC_TCRR 0x0008 - -/* Serial DMA Controller Interface Registers */ -#define SDMA_SDC 0x0000 -#define SDMA_SDCM 0x0008 -#define SDMA_RX_DESC 0x0800 -#define SDMA_RX_BUF_PTR 0x0808 -#define SDMA_SCRDP 0x0810 -#define SDMA_TX_DESC 0x0c00 -#define SDMA_SCTDP 0x0c10 -#define SDMA_SFTDP 0x0c14 - -#define SDMA_DESC_CMDSTAT_PE (1<<0) -#define SDMA_DESC_CMDSTAT_CDL (1<<1) -#define SDMA_DESC_CMDSTAT_FR (1<<3) -#define SDMA_DESC_CMDSTAT_OR (1<<6) -#define SDMA_DESC_CMDSTAT_BR (1<<9) -#define SDMA_DESC_CMDSTAT_MI (1<<10) -#define SDMA_DESC_CMDSTAT_A (1<<11) -#define SDMA_DESC_CMDSTAT_AM (1<<12) -#define SDMA_DESC_CMDSTAT_CT (1<<13) -#define SDMA_DESC_CMDSTAT_C (1<<14) -#define SDMA_DESC_CMDSTAT_ES (1<<15) -#define SDMA_DESC_CMDSTAT_L (1<<16) -#define SDMA_DESC_CMDSTAT_F (1<<17) -#define SDMA_DESC_CMDSTAT_P (1<<18) -#define SDMA_DESC_CMDSTAT_EI (1<<23) -#define SDMA_DESC_CMDSTAT_O (1<<31) - -#define SDMA_DESC_DFLT (SDMA_DESC_CMDSTAT_O \ - | SDMA_DESC_CMDSTAT_EI) - -#define SDMA_SDC_RFT (1<<0) -#define SDMA_SDC_SFM (1<<1) -#define SDMA_SDC_BLMR (1<<6) -#define SDMA_SDC_BLMT (1<<7) -#define SDMA_SDC_POVR (1<<8) -#define SDMA_SDC_RIFB (1<<9) - -#define SDMA_SDCM_ERD (1<<7) -#define SDMA_SDCM_AR (1<<15) -#define SDMA_SDCM_STD (1<<16) -#define SDMA_SDCM_TXD (1<<23) -#define SDMA_SDCM_AT (1<<31) - -#define SDMA_0_CAUSE_RXBUF (1<<0) -#define SDMA_0_CAUSE_RXERR (1<<1) -#define SDMA_0_CAUSE_TXBUF (1<<2) -#define SDMA_0_CAUSE_TXEND (1<<3) -#define SDMA_1_CAUSE_RXBUF (1<<8) -#define SDMA_1_CAUSE_RXERR (1<<9) -#define SDMA_1_CAUSE_TXBUF (1<<10) -#define SDMA_1_CAUSE_TXEND (1<<11) - -#define SDMA_CAUSE_RX_MASK (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \ - | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR) -#define SDMA_CAUSE_TX_MASK (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \ - | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND) - -/* SDMA Interrupt registers */ -#define SDMA_INTR_CAUSE 0x0000 -#define SDMA_INTR_MASK 0x0080 - -/* Baud Rate Generator Interface Registers */ -#define BRG_BCR 0x0000 -#define BRG_BTR 0x0004 - -/* - * Define how this driver is known to the outside (we've been assigned a - * range on the "Low-density serial ports" major). - */ -#define MPSC_MAJOR 204 -#define MPSC_MINOR_START 44 -#define MPSC_DRIVER_NAME "MPSC" -#define MPSC_DEV_NAME "ttyMM" -#define MPSC_VERSION "1.00" - -static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS]; -static struct mpsc_shared_regs mpsc_shared_regs; -static struct uart_driver mpsc_reg; - -static void mpsc_start_rx(struct mpsc_port_info *pi); -static void mpsc_free_ring_mem(struct mpsc_port_info *pi); -static void mpsc_release_port(struct uart_port *port); -/* - ****************************************************************************** - * - * Baud Rate Generator Routines (BRG) - * - ****************************************************************************** - */ -static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src) -{ - u32 v; - - v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); - v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18); - - if (pi->brg_can_tune) - v &= ~(1 << 25); - - if (pi->mirror_regs) - pi->BRG_BCR_m = v; - writel(v, pi->brg_base + BRG_BCR); - - writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000, - pi->brg_base + BRG_BTR); -} - -static void mpsc_brg_enable(struct mpsc_port_info *pi) -{ - u32 v; - - v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); - v |= (1 << 16); - - if (pi->mirror_regs) - pi->BRG_BCR_m = v; - writel(v, pi->brg_base + BRG_BCR); -} - -static void mpsc_brg_disable(struct mpsc_port_info *pi) -{ - u32 v; - - v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); - v &= ~(1 << 16); - - if (pi->mirror_regs) - pi->BRG_BCR_m = v; - writel(v, pi->brg_base + BRG_BCR); -} - -/* - * To set the baud, we adjust the CDV field in the BRG_BCR reg. - * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1. - * However, the input clock is divided by 16 in the MPSC b/c of how - * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our - * calculation by 16 to account for that. So the real calculation - * that accounts for the way the mpsc is set up is: - * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1. - */ -static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud) -{ - u32 cdv = (pi->port.uartclk / (baud << 5)) - 1; - u32 v; - - mpsc_brg_disable(pi); - v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); - v = (v & 0xffff0000) | (cdv & 0xffff); - - if (pi->mirror_regs) - pi->BRG_BCR_m = v; - writel(v, pi->brg_base + BRG_BCR); - mpsc_brg_enable(pi); -} - -/* - ****************************************************************************** - * - * Serial DMA Routines (SDMA) - * - ****************************************************************************** - */ - -static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size) -{ - u32 v; - - pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n", - pi->port.line, burst_size); - - burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */ - - if (burst_size < 2) - v = 0x0; /* 1 64-bit word */ - else if (burst_size < 4) - v = 0x1; /* 2 64-bit words */ - else if (burst_size < 8) - v = 0x2; /* 4 64-bit words */ - else - v = 0x3; /* 8 64-bit words */ - - writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12), - pi->sdma_base + SDMA_SDC); -} - -static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size) -{ - pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line, - burst_size); - - writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f, - pi->sdma_base + SDMA_SDC); - mpsc_sdma_burstsize(pi, burst_size); -} - -static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask) -{ - u32 old, v; - - pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask); - - old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m : - readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); - - mask &= 0xf; - if (pi->port.line) - mask <<= 8; - v &= ~mask; - - if (pi->mirror_regs) - pi->shared_regs->SDMA_INTR_MASK_m = v; - writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); - - if (pi->port.line) - old >>= 8; - return old & 0xf; -} - -static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask) -{ - u32 v; - - pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask); - - v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m - : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); - - mask &= 0xf; - if (pi->port.line) - mask <<= 8; - v |= mask; - - if (pi->mirror_regs) - pi->shared_regs->SDMA_INTR_MASK_m = v; - writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); -} - -static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line); - - if (pi->mirror_regs) - pi->shared_regs->SDMA_INTR_CAUSE_m = 0; - writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE - + pi->port.line); -} - -static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi, - struct mpsc_rx_desc *rxre_p) -{ - pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n", - pi->port.line, (u32)rxre_p); - - writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP); -} - -static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi, - struct mpsc_tx_desc *txre_p) -{ - writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP); - writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP); -} - -static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val) -{ - u32 v; - - v = readl(pi->sdma_base + SDMA_SDCM); - if (val) - v |= val; - else - v = 0; - wmb(); - writel(v, pi->sdma_base + SDMA_SDCM); - wmb(); -} - -static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi) -{ - return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD; -} - -static void mpsc_sdma_start_tx(struct mpsc_port_info *pi) -{ - struct mpsc_tx_desc *txre, *txre_p; - - /* If tx isn't running & there's a desc ready to go, start it */ - if (!mpsc_sdma_tx_active(pi)) { - txre = (struct mpsc_tx_desc *)(pi->txr - + (pi->txr_tail * MPSC_TXRE_SIZE)); - dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, - DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)txre, - (ulong)txre + MPSC_TXRE_SIZE); -#endif - - if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) { - txre_p = (struct mpsc_tx_desc *) - (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE)); - - mpsc_sdma_set_tx_ring(pi, txre_p); - mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD); - } - } -} - -static void mpsc_sdma_stop(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line); - - /* Abort any SDMA transfers */ - mpsc_sdma_cmd(pi, 0); - mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT); - - /* Clear the SDMA current and first TX and RX pointers */ - mpsc_sdma_set_tx_ring(pi, NULL); - mpsc_sdma_set_rx_ring(pi, NULL); - - /* Disable interrupts */ - mpsc_sdma_intr_mask(pi, 0xf); - mpsc_sdma_intr_ack(pi); -} - -/* - ****************************************************************************** - * - * Multi-Protocol Serial Controller Routines (MPSC) - * - ****************************************************************************** - */ - -static void mpsc_hw_init(struct mpsc_port_info *pi) -{ - u32 v; - - pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line); - - /* Set up clock routing */ - if (pi->mirror_regs) { - v = pi->shared_regs->MPSC_MRR_m; - v &= ~0x1c7; - pi->shared_regs->MPSC_MRR_m = v; - writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR); - - v = pi->shared_regs->MPSC_RCRR_m; - v = (v & ~0xf0f) | 0x100; - pi->shared_regs->MPSC_RCRR_m = v; - writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR); - - v = pi->shared_regs->MPSC_TCRR_m; - v = (v & ~0xf0f) | 0x100; - pi->shared_regs->MPSC_TCRR_m = v; - writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR); - } else { - v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR); - v &= ~0x1c7; - writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR); - - v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR); - v = (v & ~0xf0f) | 0x100; - writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR); - - v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR); - v = (v & ~0xf0f) | 0x100; - writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR); - } - - /* Put MPSC in UART mode & enabel Tx/Rx egines */ - writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL); - - /* No preamble, 16x divider, low-latency, */ - writel(0x04400400, pi->mpsc_base + MPSC_MMCRH); - mpsc_set_baudrate(pi, pi->default_baud); - - if (pi->mirror_regs) { - pi->MPSC_CHR_1_m = 0; - pi->MPSC_CHR_2_m = 0; - } - writel(0, pi->mpsc_base + MPSC_CHR_1); - writel(0, pi->mpsc_base + MPSC_CHR_2); - writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3); - writel(0, pi->mpsc_base + MPSC_CHR_4); - writel(0, pi->mpsc_base + MPSC_CHR_5); - writel(0, pi->mpsc_base + MPSC_CHR_6); - writel(0, pi->mpsc_base + MPSC_CHR_7); - writel(0, pi->mpsc_base + MPSC_CHR_8); - writel(0, pi->mpsc_base + MPSC_CHR_9); - writel(0, pi->mpsc_base + MPSC_CHR_10); -} - -static void mpsc_enter_hunt(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line); - - if (pi->mirror_regs) { - writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH, - pi->mpsc_base + MPSC_CHR_2); - /* Erratum prevents reading CHR_2 so just delay for a while */ - udelay(100); - } else { - writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH, - pi->mpsc_base + MPSC_CHR_2); - - while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH) - udelay(10); - } -} - -static void mpsc_freeze(struct mpsc_port_info *pi) -{ - u32 v; - - pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line); - - v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : - readl(pi->mpsc_base + MPSC_MPCR); - v |= MPSC_MPCR_FRZ; - - if (pi->mirror_regs) - pi->MPSC_MPCR_m = v; - writel(v, pi->mpsc_base + MPSC_MPCR); -} - -static void mpsc_unfreeze(struct mpsc_port_info *pi) -{ - u32 v; - - v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : - readl(pi->mpsc_base + MPSC_MPCR); - v &= ~MPSC_MPCR_FRZ; - - if (pi->mirror_regs) - pi->MPSC_MPCR_m = v; - writel(v, pi->mpsc_base + MPSC_MPCR); - - pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line); -} - -static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len) -{ - u32 v; - - pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len); - - v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : - readl(pi->mpsc_base + MPSC_MPCR); - v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12); - - if (pi->mirror_regs) - pi->MPSC_MPCR_m = v; - writel(v, pi->mpsc_base + MPSC_MPCR); -} - -static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len) -{ - u32 v; - - pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n", - pi->port.line, len); - - v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : - readl(pi->mpsc_base + MPSC_MPCR); - - v = (v & ~(1 << 14)) | ((len & 0x1) << 14); - - if (pi->mirror_regs) - pi->MPSC_MPCR_m = v; - writel(v, pi->mpsc_base + MPSC_MPCR); -} - -static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p) -{ - u32 v; - - pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p); - - v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m : - readl(pi->mpsc_base + MPSC_CHR_2); - - p &= 0x3; - v = (v & ~0xc000c) | (p << 18) | (p << 2); - - if (pi->mirror_regs) - pi->MPSC_CHR_2_m = v; - writel(v, pi->mpsc_base + MPSC_CHR_2); -} - -/* - ****************************************************************************** - * - * Driver Init Routines - * - ****************************************************************************** - */ - -static void mpsc_init_hw(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line); - - mpsc_brg_init(pi, pi->brg_clk_src); - mpsc_brg_enable(pi); - mpsc_sdma_init(pi, dma_get_cache_alignment()); /* burst a cacheline */ - mpsc_sdma_stop(pi); - mpsc_hw_init(pi); -} - -static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi) -{ - int rc = 0; - - pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n", - pi->port.line); - - if (!pi->dma_region) { - if (!dma_supported(pi->port.dev, 0xffffffff)) { - printk(KERN_ERR "MPSC: Inadequate DMA support\n"); - rc = -ENXIO; - } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev, - MPSC_DMA_ALLOC_SIZE, - &pi->dma_region_p, GFP_KERNEL)) - == NULL) { - printk(KERN_ERR "MPSC: Can't alloc Desc region\n"); - rc = -ENOMEM; - } - } - - return rc; -} - -static void mpsc_free_ring_mem(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line); - - if (pi->dma_region) { - dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE, - pi->dma_region, pi->dma_region_p); - pi->dma_region = NULL; - pi->dma_region_p = (dma_addr_t)NULL; - } -} - -static void mpsc_init_rings(struct mpsc_port_info *pi) -{ - struct mpsc_rx_desc *rxre; - struct mpsc_tx_desc *txre; - dma_addr_t dp, dp_p; - u8 *bp, *bp_p; - int i; - - pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line); - - BUG_ON(pi->dma_region == NULL); - - memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE); - - /* - * Descriptors & buffers are multiples of cacheline size and must be - * cacheline aligned. - */ - dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment()); - dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment()); - - /* - * Partition dma region into rx ring descriptor, rx buffers, - * tx ring descriptors, and tx buffers. - */ - pi->rxr = dp; - pi->rxr_p = dp_p; - dp += MPSC_RXR_SIZE; - dp_p += MPSC_RXR_SIZE; - - pi->rxb = (u8 *)dp; - pi->rxb_p = (u8 *)dp_p; - dp += MPSC_RXB_SIZE; - dp_p += MPSC_RXB_SIZE; - - pi->rxr_posn = 0; - - pi->txr = dp; - pi->txr_p = dp_p; - dp += MPSC_TXR_SIZE; - dp_p += MPSC_TXR_SIZE; - - pi->txb = (u8 *)dp; - pi->txb_p = (u8 *)dp_p; - - pi->txr_head = 0; - pi->txr_tail = 0; - - /* Init rx ring descriptors */ - dp = pi->rxr; - dp_p = pi->rxr_p; - bp = pi->rxb; - bp_p = pi->rxb_p; - - for (i = 0; i < MPSC_RXR_ENTRIES; i++) { - rxre = (struct mpsc_rx_desc *)dp; - - rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE); - rxre->bytecnt = cpu_to_be16(0); - rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O - | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F - | SDMA_DESC_CMDSTAT_L); - rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE); - rxre->buf_ptr = cpu_to_be32(bp_p); - - dp += MPSC_RXRE_SIZE; - dp_p += MPSC_RXRE_SIZE; - bp += MPSC_RXBE_SIZE; - bp_p += MPSC_RXBE_SIZE; - } - rxre->link = cpu_to_be32(pi->rxr_p); /* Wrap last back to first */ - - /* Init tx ring descriptors */ - dp = pi->txr; - dp_p = pi->txr_p; - bp = pi->txb; - bp_p = pi->txb_p; - - for (i = 0; i < MPSC_TXR_ENTRIES; i++) { - txre = (struct mpsc_tx_desc *)dp; - - txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE); - txre->buf_ptr = cpu_to_be32(bp_p); - - dp += MPSC_TXRE_SIZE; - dp_p += MPSC_TXRE_SIZE; - bp += MPSC_TXBE_SIZE; - bp_p += MPSC_TXBE_SIZE; - } - txre->link = cpu_to_be32(pi->txr_p); /* Wrap last back to first */ - - dma_cache_sync(pi->port.dev, (void *)pi->dma_region, - MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - flush_dcache_range((ulong)pi->dma_region, - (ulong)pi->dma_region - + MPSC_DMA_ALLOC_SIZE); -#endif - - return; -} - -static void mpsc_uninit_rings(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line); - - BUG_ON(pi->dma_region == NULL); - - pi->rxr = 0; - pi->rxr_p = 0; - pi->rxb = NULL; - pi->rxb_p = NULL; - pi->rxr_posn = 0; - - pi->txr = 0; - pi->txr_p = 0; - pi->txb = NULL; - pi->txb_p = NULL; - pi->txr_head = 0; - pi->txr_tail = 0; -} - -static int mpsc_make_ready(struct mpsc_port_info *pi) -{ - int rc; - - pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line); - - if (!pi->ready) { - mpsc_init_hw(pi); - if ((rc = mpsc_alloc_ring_mem(pi))) - return rc; - mpsc_init_rings(pi); - pi->ready = 1; - } - - return 0; -} - -#ifdef CONFIG_CONSOLE_POLL -static int serial_polled; -#endif - -/* - ****************************************************************************** - * - * Interrupt Handling Routines - * - ****************************************************************************** - */ - -static int mpsc_rx_intr(struct mpsc_port_info *pi) -{ - struct mpsc_rx_desc *rxre; - struct tty_struct *tty = pi->port.state->port.tty; - u32 cmdstat, bytes_in, i; - int rc = 0; - u8 *bp; - char flag = TTY_NORMAL; - - pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); - - rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE)); - - dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, - DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)rxre, - (ulong)rxre + MPSC_RXRE_SIZE); -#endif - - /* - * Loop through Rx descriptors handling ones that have been completed. - */ - while (!((cmdstat = be32_to_cpu(rxre->cmdstat)) - & SDMA_DESC_CMDSTAT_O)) { - bytes_in = be16_to_cpu(rxre->bytecnt); -#ifdef CONFIG_CONSOLE_POLL - if (unlikely(serial_polled)) { - serial_polled = 0; - return 0; - } -#endif - /* Following use of tty struct directly is deprecated */ - if (unlikely(tty_buffer_request_room(tty, bytes_in) - < bytes_in)) { - if (tty->low_latency) - tty_flip_buffer_push(tty); - /* - * If this failed then we will throw away the bytes - * but must do so to clear interrupts. - */ - } - - bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE); - dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE, - DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)bp, - (ulong)bp + MPSC_RXBE_SIZE); -#endif - - /* - * Other than for parity error, the manual provides little - * info on what data will be in a frame flagged by any of - * these errors. For parity error, it is the last byte in - * the buffer that had the error. As for the rest, I guess - * we'll assume there is no data in the buffer. - * If there is...it gets lost. - */ - if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR - | SDMA_DESC_CMDSTAT_FR - | SDMA_DESC_CMDSTAT_OR))) { - - pi->port.icount.rx++; - - if (cmdstat & SDMA_DESC_CMDSTAT_BR) { /* Break */ - pi->port.icount.brk++; - - if (uart_handle_break(&pi->port)) - goto next_frame; - } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) { - pi->port.icount.frame++; - } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) { - pi->port.icount.overrun++; - } - - cmdstat &= pi->port.read_status_mask; - - if (cmdstat & SDMA_DESC_CMDSTAT_BR) - flag = TTY_BREAK; - else if (cmdstat & SDMA_DESC_CMDSTAT_FR) - flag = TTY_FRAME; - else if (cmdstat & SDMA_DESC_CMDSTAT_OR) - flag = TTY_OVERRUN; - else if (cmdstat & SDMA_DESC_CMDSTAT_PE) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(&pi->port, *bp)) { - bp++; - bytes_in--; -#ifdef CONFIG_CONSOLE_POLL - if (unlikely(serial_polled)) { - serial_polled = 0; - return 0; - } -#endif - goto next_frame; - } - - if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR - | SDMA_DESC_CMDSTAT_FR - | SDMA_DESC_CMDSTAT_OR))) - && !(cmdstat & pi->port.ignore_status_mask)) { - tty_insert_flip_char(tty, *bp, flag); - } else { - for (i=0; iport.icount.rx += bytes_in; - } - -next_frame: - rxre->bytecnt = cpu_to_be16(0); - wmb(); - rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O - | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F - | SDMA_DESC_CMDSTAT_L); - wmb(); - dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, - DMA_BIDIRECTIONAL); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - flush_dcache_range((ulong)rxre, - (ulong)rxre + MPSC_RXRE_SIZE); -#endif - - /* Advance to next descriptor */ - pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1); - rxre = (struct mpsc_rx_desc *) - (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE)); - dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, - DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)rxre, - (ulong)rxre + MPSC_RXRE_SIZE); -#endif - rc = 1; - } - - /* Restart rx engine, if its stopped */ - if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0) - mpsc_start_rx(pi); - - tty_flip_buffer_push(tty); - return rc; -} - -static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr) -{ - struct mpsc_tx_desc *txre; - - txre = (struct mpsc_tx_desc *)(pi->txr - + (pi->txr_head * MPSC_TXRE_SIZE)); - - txre->bytecnt = cpu_to_be16(count); - txre->shadow = txre->bytecnt; - wmb(); /* ensure cmdstat is last field updated */ - txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F - | SDMA_DESC_CMDSTAT_L - | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0)); - wmb(); - dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, - DMA_BIDIRECTIONAL); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - flush_dcache_range((ulong)txre, - (ulong)txre + MPSC_TXRE_SIZE); -#endif -} - -static void mpsc_copy_tx_data(struct mpsc_port_info *pi) -{ - struct circ_buf *xmit = &pi->port.state->xmit; - u8 *bp; - u32 i; - - /* Make sure the desc ring isn't full */ - while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES) - < (MPSC_TXR_ENTRIES - 1)) { - if (pi->port.x_char) { - /* - * Ideally, we should use the TCS field in - * CHR_1 to put the x_char out immediately but - * errata prevents us from being able to read - * CHR_2 to know that its safe to write to - * CHR_1. Instead, just put it in-band with - * all the other Tx data. - */ - bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); - *bp = pi->port.x_char; - pi->port.x_char = 0; - i = 1; - } else if (!uart_circ_empty(xmit) - && !uart_tx_stopped(&pi->port)) { - i = min((u32)MPSC_TXBE_SIZE, - (u32)uart_circ_chars_pending(xmit)); - i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail, - UART_XMIT_SIZE)); - bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); - memcpy(bp, &xmit->buf[xmit->tail], i); - xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&pi->port); - } else { /* All tx data copied into ring bufs */ - return; - } - - dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE, - DMA_BIDIRECTIONAL); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - flush_dcache_range((ulong)bp, - (ulong)bp + MPSC_TXBE_SIZE); -#endif - mpsc_setup_tx_desc(pi, i, 1); - - /* Advance to next descriptor */ - pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1); - } -} - -static int mpsc_tx_intr(struct mpsc_port_info *pi) -{ - struct mpsc_tx_desc *txre; - int rc = 0; - unsigned long iflags; - - spin_lock_irqsave(&pi->tx_lock, iflags); - - if (!mpsc_sdma_tx_active(pi)) { - txre = (struct mpsc_tx_desc *)(pi->txr - + (pi->txr_tail * MPSC_TXRE_SIZE)); - - dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, - DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)txre, - (ulong)txre + MPSC_TXRE_SIZE); -#endif - - while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) { - rc = 1; - pi->port.icount.tx += be16_to_cpu(txre->bytecnt); - pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1); - - /* If no more data to tx, fall out of loop */ - if (pi->txr_head == pi->txr_tail) - break; - - txre = (struct mpsc_tx_desc *)(pi->txr - + (pi->txr_tail * MPSC_TXRE_SIZE)); - dma_cache_sync(pi->port.dev, (void *)txre, - MPSC_TXRE_SIZE, DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)txre, - (ulong)txre + MPSC_TXRE_SIZE); -#endif - } - - mpsc_copy_tx_data(pi); - mpsc_sdma_start_tx(pi); /* start next desc if ready */ - } - - spin_unlock_irqrestore(&pi->tx_lock, iflags); - return rc; -} - -/* - * This is the driver's interrupt handler. To avoid a race, we first clear - * the interrupt, then handle any completed Rx/Tx descriptors. When done - * handling those descriptors, we restart the Rx/Tx engines if they're stopped. - */ -static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id) -{ - struct mpsc_port_info *pi = dev_id; - ulong iflags; - int rc = IRQ_NONE; - - pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line); - - spin_lock_irqsave(&pi->port.lock, iflags); - mpsc_sdma_intr_ack(pi); - if (mpsc_rx_intr(pi)) - rc = IRQ_HANDLED; - if (mpsc_tx_intr(pi)) - rc = IRQ_HANDLED; - spin_unlock_irqrestore(&pi->port.lock, iflags); - - pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line); - return rc; -} - -/* - ****************************************************************************** - * - * serial_core.c Interface routines - * - ****************************************************************************** - */ -static uint mpsc_tx_empty(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - ulong iflags; - uint rc; - - spin_lock_irqsave(&pi->port.lock, iflags); - rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT; - spin_unlock_irqrestore(&pi->port.lock, iflags); - - return rc; -} - -static void mpsc_set_mctrl(struct uart_port *port, uint mctrl) -{ - /* Have no way to set modem control lines AFAICT */ -} - -static uint mpsc_get_mctrl(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - u32 mflags, status; - - status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m - : readl(pi->mpsc_base + MPSC_CHR_10); - - mflags = 0; - if (status & 0x1) - mflags |= TIOCM_CTS; - if (status & 0x2) - mflags |= TIOCM_CAR; - - return mflags | TIOCM_DSR; /* No way to tell if DSR asserted */ -} - -static void mpsc_stop_tx(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - - pr_debug("mpsc_stop_tx[%d]\n", port->line); - - mpsc_freeze(pi); -} - -static void mpsc_start_tx(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - unsigned long iflags; - - spin_lock_irqsave(&pi->tx_lock, iflags); - - mpsc_unfreeze(pi); - mpsc_copy_tx_data(pi); - mpsc_sdma_start_tx(pi); - - spin_unlock_irqrestore(&pi->tx_lock, iflags); - - pr_debug("mpsc_start_tx[%d]\n", port->line); -} - -static void mpsc_start_rx(struct mpsc_port_info *pi) -{ - pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line); - - if (pi->rcv_data) { - mpsc_enter_hunt(pi); - mpsc_sdma_cmd(pi, SDMA_SDCM_ERD); - } -} - -static void mpsc_stop_rx(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - - pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line); - - if (pi->mirror_regs) { - writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA, - pi->mpsc_base + MPSC_CHR_2); - /* Erratum prevents reading CHR_2 so just delay for a while */ - udelay(100); - } else { - writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA, - pi->mpsc_base + MPSC_CHR_2); - - while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA) - udelay(10); - } - - mpsc_sdma_cmd(pi, SDMA_SDCM_AR); -} - -static void mpsc_enable_ms(struct uart_port *port) -{ -} - -static void mpsc_break_ctl(struct uart_port *port, int ctl) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - ulong flags; - u32 v; - - v = ctl ? 0x00ff0000 : 0; - - spin_lock_irqsave(&pi->port.lock, flags); - if (pi->mirror_regs) - pi->MPSC_CHR_1_m = v; - writel(v, pi->mpsc_base + MPSC_CHR_1); - spin_unlock_irqrestore(&pi->port.lock, flags); -} - -static int mpsc_startup(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - u32 flag = 0; - int rc; - - pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n", - port->line, pi->port.irq); - - if ((rc = mpsc_make_ready(pi)) == 0) { - /* Setup IRQ handler */ - mpsc_sdma_intr_ack(pi); - - /* If irq's are shared, need to set flag */ - if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq) - flag = IRQF_SHARED; - - if (request_irq(pi->port.irq, mpsc_sdma_intr, flag, - "mpsc-sdma", pi)) - printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n", - pi->port.irq); - - mpsc_sdma_intr_unmask(pi, 0xf); - mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p - + (pi->rxr_posn * MPSC_RXRE_SIZE))); - } - - return rc; -} - -static void mpsc_shutdown(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - - pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line); - - mpsc_sdma_stop(pi); - free_irq(pi->port.irq, pi); -} - -static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - u32 baud; - ulong flags; - u32 chr_bits, stop_bits, par; - - pi->c_iflag = termios->c_iflag; - pi->c_cflag = termios->c_cflag; - - switch (termios->c_cflag & CSIZE) { - case CS5: - chr_bits = MPSC_MPCR_CL_5; - break; - case CS6: - chr_bits = MPSC_MPCR_CL_6; - break; - case CS7: - chr_bits = MPSC_MPCR_CL_7; - break; - case CS8: - default: - chr_bits = MPSC_MPCR_CL_8; - break; - } - - if (termios->c_cflag & CSTOPB) - stop_bits = MPSC_MPCR_SBL_2; - else - stop_bits = MPSC_MPCR_SBL_1; - - par = MPSC_CHR_2_PAR_EVEN; - if (termios->c_cflag & PARENB) - if (termios->c_cflag & PARODD) - par = MPSC_CHR_2_PAR_ODD; -#ifdef CMSPAR - if (termios->c_cflag & CMSPAR) { - if (termios->c_cflag & PARODD) - par = MPSC_CHR_2_PAR_MARK; - else - par = MPSC_CHR_2_PAR_SPACE; - } -#endif - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk); - - spin_lock_irqsave(&pi->port.lock, flags); - - uart_update_timeout(port, termios->c_cflag, baud); - - mpsc_set_char_length(pi, chr_bits); - mpsc_set_stop_bit_length(pi, stop_bits); - mpsc_set_parity(pi, par); - mpsc_set_baudrate(pi, baud); - - /* Characters/events to read */ - pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR; - - if (termios->c_iflag & INPCK) - pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE - | SDMA_DESC_CMDSTAT_FR; - - if (termios->c_iflag & (BRKINT | PARMRK)) - pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR; - - /* Characters/events to ignore */ - pi->port.ignore_status_mask = 0; - - if (termios->c_iflag & IGNPAR) - pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE - | SDMA_DESC_CMDSTAT_FR; - - if (termios->c_iflag & IGNBRK) { - pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR; - - if (termios->c_iflag & IGNPAR) - pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR; - } - - if ((termios->c_cflag & CREAD)) { - if (!pi->rcv_data) { - pi->rcv_data = 1; - mpsc_start_rx(pi); - } - } else if (pi->rcv_data) { - mpsc_stop_rx(port); - pi->rcv_data = 0; - } - - spin_unlock_irqrestore(&pi->port.lock, flags); -} - -static const char *mpsc_type(struct uart_port *port) -{ - pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME); - return MPSC_DRIVER_NAME; -} - -static int mpsc_request_port(struct uart_port *port) -{ - /* Should make chip/platform specific call */ - return 0; -} - -static void mpsc_release_port(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - - if (pi->ready) { - mpsc_uninit_rings(pi); - mpsc_free_ring_mem(pi); - pi->ready = 0; - } -} - -static void mpsc_config_port(struct uart_port *port, int flags) -{ -} - -static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - int rc = 0; - - pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line); - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC) - rc = -EINVAL; - else if (pi->port.irq != ser->irq) - rc = -EINVAL; - else if (ser->io_type != SERIAL_IO_MEM) - rc = -EINVAL; - else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */ - rc = -EINVAL; - else if ((void *)pi->port.mapbase != ser->iomem_base) - rc = -EINVAL; - else if (pi->port.iobase != ser->port) - rc = -EINVAL; - else if (ser->hub6 != 0) - rc = -EINVAL; - - return rc; -} -#ifdef CONFIG_CONSOLE_POLL -/* Serial polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static char poll_buf[2048]; -static int poll_ptr; -static int poll_cnt; -static void mpsc_put_poll_char(struct uart_port *port, - unsigned char c); - -static int mpsc_get_poll_char(struct uart_port *port) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - struct mpsc_rx_desc *rxre; - u32 cmdstat, bytes_in, i; - u8 *bp; - - if (!serial_polled) - serial_polled = 1; - - pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); - - if (poll_cnt) { - poll_cnt--; - return poll_buf[poll_ptr++]; - } - poll_ptr = 0; - poll_cnt = 0; - - while (poll_cnt == 0) { - rxre = (struct mpsc_rx_desc *)(pi->rxr + - (pi->rxr_posn*MPSC_RXRE_SIZE)); - dma_cache_sync(pi->port.dev, (void *)rxre, - MPSC_RXRE_SIZE, DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)rxre, - (ulong)rxre + MPSC_RXRE_SIZE); -#endif - /* - * Loop through Rx descriptors handling ones that have - * been completed. - */ - while (poll_cnt == 0 && - !((cmdstat = be32_to_cpu(rxre->cmdstat)) & - SDMA_DESC_CMDSTAT_O)){ - bytes_in = be16_to_cpu(rxre->bytecnt); - bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE); - dma_cache_sync(pi->port.dev, (void *) bp, - MPSC_RXBE_SIZE, DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)bp, - (ulong)bp + MPSC_RXBE_SIZE); -#endif - if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR | - SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) && - !(cmdstat & pi->port.ignore_status_mask)) { - poll_buf[poll_cnt] = *bp; - poll_cnt++; - } else { - for (i = 0; i < bytes_in; i++) { - poll_buf[poll_cnt] = *bp++; - poll_cnt++; - } - pi->port.icount.rx += bytes_in; - } - rxre->bytecnt = cpu_to_be16(0); - wmb(); - rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | - SDMA_DESC_CMDSTAT_EI | - SDMA_DESC_CMDSTAT_F | - SDMA_DESC_CMDSTAT_L); - wmb(); - dma_cache_sync(pi->port.dev, (void *)rxre, - MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - flush_dcache_range((ulong)rxre, - (ulong)rxre + MPSC_RXRE_SIZE); -#endif - - /* Advance to next descriptor */ - pi->rxr_posn = (pi->rxr_posn + 1) & - (MPSC_RXR_ENTRIES - 1); - rxre = (struct mpsc_rx_desc *)(pi->rxr + - (pi->rxr_posn * MPSC_RXRE_SIZE)); - dma_cache_sync(pi->port.dev, (void *)rxre, - MPSC_RXRE_SIZE, DMA_FROM_DEVICE); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - invalidate_dcache_range((ulong)rxre, - (ulong)rxre + MPSC_RXRE_SIZE); -#endif - } - - /* Restart rx engine, if its stopped */ - if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0) - mpsc_start_rx(pi); - } - if (poll_cnt) { - poll_cnt--; - return poll_buf[poll_ptr++]; - } - - return 0; -} - - -static void mpsc_put_poll_char(struct uart_port *port, - unsigned char c) -{ - struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - u32 data; - - data = readl(pi->mpsc_base + MPSC_MPCR); - writeb(c, pi->mpsc_base + MPSC_CHR_1); - mb(); - data = readl(pi->mpsc_base + MPSC_CHR_2); - data |= MPSC_CHR_2_TTCS; - writel(data, pi->mpsc_base + MPSC_CHR_2); - mb(); - - while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS); -} -#endif - -static struct uart_ops mpsc_pops = { - .tx_empty = mpsc_tx_empty, - .set_mctrl = mpsc_set_mctrl, - .get_mctrl = mpsc_get_mctrl, - .stop_tx = mpsc_stop_tx, - .start_tx = mpsc_start_tx, - .stop_rx = mpsc_stop_rx, - .enable_ms = mpsc_enable_ms, - .break_ctl = mpsc_break_ctl, - .startup = mpsc_startup, - .shutdown = mpsc_shutdown, - .set_termios = mpsc_set_termios, - .type = mpsc_type, - .release_port = mpsc_release_port, - .request_port = mpsc_request_port, - .config_port = mpsc_config_port, - .verify_port = mpsc_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = mpsc_get_poll_char, - .poll_put_char = mpsc_put_poll_char, -#endif -}; - -/* - ****************************************************************************** - * - * Console Interface Routines - * - ****************************************************************************** - */ - -#ifdef CONFIG_SERIAL_MPSC_CONSOLE -static void mpsc_console_write(struct console *co, const char *s, uint count) -{ - struct mpsc_port_info *pi = &mpsc_ports[co->index]; - u8 *bp, *dp, add_cr = 0; - int i; - unsigned long iflags; - - spin_lock_irqsave(&pi->tx_lock, iflags); - - while (pi->txr_head != pi->txr_tail) { - while (mpsc_sdma_tx_active(pi)) - udelay(100); - mpsc_sdma_intr_ack(pi); - mpsc_tx_intr(pi); - } - - while (mpsc_sdma_tx_active(pi)) - udelay(100); - - while (count > 0) { - bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); - - for (i = 0; i < MPSC_TXBE_SIZE; i++) { - if (count == 0) - break; - - if (add_cr) { - *(dp++) = '\r'; - add_cr = 0; - } else { - *(dp++) = *s; - - if (*(s++) == '\n') { /* add '\r' after '\n' */ - add_cr = 1; - count++; - } - } - - count--; - } - - dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE, - DMA_BIDIRECTIONAL); -#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) - if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ - flush_dcache_range((ulong)bp, - (ulong)bp + MPSC_TXBE_SIZE); -#endif - mpsc_setup_tx_desc(pi, i, 0); - pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1); - mpsc_sdma_start_tx(pi); - - while (mpsc_sdma_tx_active(pi)) - udelay(100); - - pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1); - } - - spin_unlock_irqrestore(&pi->tx_lock, iflags); -} - -static int __init mpsc_console_setup(struct console *co, char *options) -{ - struct mpsc_port_info *pi; - int baud, bits, parity, flow; - - pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options); - - if (co->index >= MPSC_NUM_CTLRS) - co->index = 0; - - pi = &mpsc_ports[co->index]; - - baud = pi->default_baud; - bits = pi->default_bits; - parity = pi->default_parity; - flow = pi->default_flow; - - if (!pi->port.ops) - return -ENODEV; - - spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */ - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&pi->port, co, baud, parity, bits, flow); -} - -static struct console mpsc_console = { - .name = MPSC_DEV_NAME, - .write = mpsc_console_write, - .device = uart_console_device, - .setup = mpsc_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &mpsc_reg, -}; - -static int __init mpsc_late_console_init(void) -{ - pr_debug("mpsc_late_console_init: Enter\n"); - - if (!(mpsc_console.flags & CON_ENABLED)) - register_console(&mpsc_console); - return 0; -} - -late_initcall(mpsc_late_console_init); - -#define MPSC_CONSOLE &mpsc_console -#else -#define MPSC_CONSOLE NULL -#endif -/* - ****************************************************************************** - * - * Dummy Platform Driver to extract & map shared register regions - * - ****************************************************************************** - */ -static void mpsc_resource_err(char *s) -{ - printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s); -} - -static int mpsc_shared_map_regs(struct platform_device *pd) -{ - struct resource *r; - - if ((r = platform_get_resource(pd, IORESOURCE_MEM, - MPSC_ROUTING_BASE_ORDER)) - && request_mem_region(r->start, - MPSC_ROUTING_REG_BLOCK_SIZE, - "mpsc_routing_regs")) { - mpsc_shared_regs.mpsc_routing_base = ioremap(r->start, - MPSC_ROUTING_REG_BLOCK_SIZE); - mpsc_shared_regs.mpsc_routing_base_p = r->start; - } else { - mpsc_resource_err("MPSC routing base"); - return -ENOMEM; - } - - if ((r = platform_get_resource(pd, IORESOURCE_MEM, - MPSC_SDMA_INTR_BASE_ORDER)) - && request_mem_region(r->start, - MPSC_SDMA_INTR_REG_BLOCK_SIZE, - "sdma_intr_regs")) { - mpsc_shared_regs.sdma_intr_base = ioremap(r->start, - MPSC_SDMA_INTR_REG_BLOCK_SIZE); - mpsc_shared_regs.sdma_intr_base_p = r->start; - } else { - iounmap(mpsc_shared_regs.mpsc_routing_base); - release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, - MPSC_ROUTING_REG_BLOCK_SIZE); - mpsc_resource_err("SDMA intr base"); - return -ENOMEM; - } - - return 0; -} - -static void mpsc_shared_unmap_regs(void) -{ - if (!mpsc_shared_regs.mpsc_routing_base) { - iounmap(mpsc_shared_regs.mpsc_routing_base); - release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, - MPSC_ROUTING_REG_BLOCK_SIZE); - } - if (!mpsc_shared_regs.sdma_intr_base) { - iounmap(mpsc_shared_regs.sdma_intr_base); - release_mem_region(mpsc_shared_regs.sdma_intr_base_p, - MPSC_SDMA_INTR_REG_BLOCK_SIZE); - } - - mpsc_shared_regs.mpsc_routing_base = NULL; - mpsc_shared_regs.sdma_intr_base = NULL; - - mpsc_shared_regs.mpsc_routing_base_p = 0; - mpsc_shared_regs.sdma_intr_base_p = 0; -} - -static int mpsc_shared_drv_probe(struct platform_device *dev) -{ - struct mpsc_shared_pdata *pdata; - int rc = -ENODEV; - - if (dev->id == 0) { - if (!(rc = mpsc_shared_map_regs(dev))) { - pdata = (struct mpsc_shared_pdata *) - dev->dev.platform_data; - - mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val; - mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val; - mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val; - mpsc_shared_regs.SDMA_INTR_CAUSE_m = - pdata->intr_cause_val; - mpsc_shared_regs.SDMA_INTR_MASK_m = - pdata->intr_mask_val; - - rc = 0; - } - } - - return rc; -} - -static int mpsc_shared_drv_remove(struct platform_device *dev) -{ - int rc = -ENODEV; - - if (dev->id == 0) { - mpsc_shared_unmap_regs(); - mpsc_shared_regs.MPSC_MRR_m = 0; - mpsc_shared_regs.MPSC_RCRR_m = 0; - mpsc_shared_regs.MPSC_TCRR_m = 0; - mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0; - mpsc_shared_regs.SDMA_INTR_MASK_m = 0; - rc = 0; - } - - return rc; -} - -static struct platform_driver mpsc_shared_driver = { - .probe = mpsc_shared_drv_probe, - .remove = mpsc_shared_drv_remove, - .driver = { - .name = MPSC_SHARED_NAME, - }, -}; - -/* - ****************************************************************************** - * - * Driver Interface Routines - * - ****************************************************************************** - */ -static struct uart_driver mpsc_reg = { - .owner = THIS_MODULE, - .driver_name = MPSC_DRIVER_NAME, - .dev_name = MPSC_DEV_NAME, - .major = MPSC_MAJOR, - .minor = MPSC_MINOR_START, - .nr = MPSC_NUM_CTLRS, - .cons = MPSC_CONSOLE, -}; - -static int mpsc_drv_map_regs(struct mpsc_port_info *pi, - struct platform_device *pd) -{ - struct resource *r; - - if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER)) - && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE, - "mpsc_regs")) { - pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE); - pi->mpsc_base_p = r->start; - } else { - mpsc_resource_err("MPSC base"); - goto err; - } - - if ((r = platform_get_resource(pd, IORESOURCE_MEM, - MPSC_SDMA_BASE_ORDER)) - && request_mem_region(r->start, - MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) { - pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE); - pi->sdma_base_p = r->start; - } else { - mpsc_resource_err("SDMA base"); - if (pi->mpsc_base) { - iounmap(pi->mpsc_base); - pi->mpsc_base = NULL; - } - goto err; - } - - if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER)) - && request_mem_region(r->start, - MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) { - pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE); - pi->brg_base_p = r->start; - } else { - mpsc_resource_err("BRG base"); - if (pi->mpsc_base) { - iounmap(pi->mpsc_base); - pi->mpsc_base = NULL; - } - if (pi->sdma_base) { - iounmap(pi->sdma_base); - pi->sdma_base = NULL; - } - goto err; - } - return 0; - -err: - return -ENOMEM; -} - -static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi) -{ - if (!pi->mpsc_base) { - iounmap(pi->mpsc_base); - release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE); - } - if (!pi->sdma_base) { - iounmap(pi->sdma_base); - release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE); - } - if (!pi->brg_base) { - iounmap(pi->brg_base); - release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE); - } - - pi->mpsc_base = NULL; - pi->sdma_base = NULL; - pi->brg_base = NULL; - - pi->mpsc_base_p = 0; - pi->sdma_base_p = 0; - pi->brg_base_p = 0; -} - -static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi, - struct platform_device *pd, int num) -{ - struct mpsc_pdata *pdata; - - pdata = (struct mpsc_pdata *)pd->dev.platform_data; - - pi->port.uartclk = pdata->brg_clk_freq; - pi->port.iotype = UPIO_MEM; - pi->port.line = num; - pi->port.type = PORT_MPSC; - pi->port.fifosize = MPSC_TXBE_SIZE; - pi->port.membase = pi->mpsc_base; - pi->port.mapbase = (ulong)pi->mpsc_base; - pi->port.ops = &mpsc_pops; - - pi->mirror_regs = pdata->mirror_regs; - pi->cache_mgmt = pdata->cache_mgmt; - pi->brg_can_tune = pdata->brg_can_tune; - pi->brg_clk_src = pdata->brg_clk_src; - pi->mpsc_max_idle = pdata->max_idle; - pi->default_baud = pdata->default_baud; - pi->default_bits = pdata->default_bits; - pi->default_parity = pdata->default_parity; - pi->default_flow = pdata->default_flow; - - /* Initial values of mirrored regs */ - pi->MPSC_CHR_1_m = pdata->chr_1_val; - pi->MPSC_CHR_2_m = pdata->chr_2_val; - pi->MPSC_CHR_10_m = pdata->chr_10_val; - pi->MPSC_MPCR_m = pdata->mpcr_val; - pi->BRG_BCR_m = pdata->bcr_val; - - pi->shared_regs = &mpsc_shared_regs; - - pi->port.irq = platform_get_irq(pd, 0); -} - -static int mpsc_drv_probe(struct platform_device *dev) -{ - struct mpsc_port_info *pi; - int rc = -ENODEV; - - pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id); - - if (dev->id < MPSC_NUM_CTLRS) { - pi = &mpsc_ports[dev->id]; - - if (!(rc = mpsc_drv_map_regs(pi, dev))) { - mpsc_drv_get_platform_data(pi, dev, dev->id); - pi->port.dev = &dev->dev; - - if (!(rc = mpsc_make_ready(pi))) { - spin_lock_init(&pi->tx_lock); - if (!(rc = uart_add_one_port(&mpsc_reg, - &pi->port))) { - rc = 0; - } else { - mpsc_release_port((struct uart_port *) - pi); - mpsc_drv_unmap_regs(pi); - } - } else { - mpsc_drv_unmap_regs(pi); - } - } - } - - return rc; -} - -static int mpsc_drv_remove(struct platform_device *dev) -{ - pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id); - - if (dev->id < MPSC_NUM_CTLRS) { - uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port); - mpsc_release_port((struct uart_port *) - &mpsc_ports[dev->id].port); - mpsc_drv_unmap_regs(&mpsc_ports[dev->id]); - return 0; - } else { - return -ENODEV; - } -} - -static struct platform_driver mpsc_driver = { - .probe = mpsc_drv_probe, - .remove = mpsc_drv_remove, - .driver = { - .name = MPSC_CTLR_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init mpsc_drv_init(void) -{ - int rc; - - printk(KERN_INFO "Serial: MPSC driver\n"); - - memset(mpsc_ports, 0, sizeof(mpsc_ports)); - memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); - - if (!(rc = uart_register_driver(&mpsc_reg))) { - if (!(rc = platform_driver_register(&mpsc_shared_driver))) { - if ((rc = platform_driver_register(&mpsc_driver))) { - platform_driver_unregister(&mpsc_shared_driver); - uart_unregister_driver(&mpsc_reg); - } - } else { - uart_unregister_driver(&mpsc_reg); - } - } - - return rc; -} - -static void __exit mpsc_drv_exit(void) -{ - platform_driver_unregister(&mpsc_driver); - platform_driver_unregister(&mpsc_shared_driver); - uart_unregister_driver(&mpsc_reg); - memset(mpsc_ports, 0, sizeof(mpsc_ports)); - memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); -} - -module_init(mpsc_drv_init); -module_exit(mpsc_drv_exit); - -MODULE_AUTHOR("Mark A. Greer "); -MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver"); -MODULE_VERSION(MPSC_VERSION); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR); -MODULE_ALIAS("platform:" MPSC_CTLR_NAME); diff --git a/drivers/serial/mrst_max3110.c b/drivers/serial/mrst_max3110.c deleted file mode 100644 index b62857bf2fdb..000000000000 --- a/drivers/serial/mrst_max3110.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * mrst_max3110.c - spi uart protocol driver for Maxim 3110 - * - * Copyright (c) 2008-2010, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * Note: - * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has - * 1 word. If SPI master controller doesn't support sclk frequency change, - * then the char need be sent out one by one with some delay - * - * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE - * interrupt for a low speed UART device - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "mrst_max3110.h" - -#define PR_FMT "mrst_max3110: " - -#define UART_TX_NEEDED 1 -#define CON_TX_NEEDED 2 -#define BIT_IRQ_PENDING 3 - -struct uart_max3110 { - struct uart_port port; - struct spi_device *spi; - char name[24]; - - wait_queue_head_t wq; - struct task_struct *main_thread; - struct task_struct *read_thread; - struct mutex thread_mutex;; - - u32 baud; - u16 cur_conf; - u8 clock; - u8 parity, word_7bits; - u16 irq; - - unsigned long uart_flags; - - /* console related */ - struct circ_buf con_xmit; -}; - -/* global data structure, may need be removed */ -static struct uart_max3110 *pmax; - -static void receive_chars(struct uart_max3110 *max, - unsigned char *str, int len); -static int max3110_read_multi(struct uart_max3110 *max, u8 *buf); -static void max3110_con_receive(struct uart_max3110 *max); - -static int max3110_write_then_read(struct uart_max3110 *max, - const void *txbuf, void *rxbuf, unsigned len, int always_fast) -{ - struct spi_device *spi = max->spi; - struct spi_message message; - struct spi_transfer x; - int ret; - - spi_message_init(&message); - memset(&x, 0, sizeof x); - x.len = len; - x.tx_buf = txbuf; - x.rx_buf = rxbuf; - spi_message_add_tail(&x, &message); - - if (always_fast) - x.speed_hz = spi->max_speed_hz; - else if (max->baud) - x.speed_hz = max->baud; - - /* Do the i/o */ - ret = spi_sync(spi, &message); - return ret; -} - -/* Write a 16b word to the device */ -static int max3110_out(struct uart_max3110 *max, const u16 out) -{ - void *buf; - u16 *obuf, *ibuf; - u8 ch; - int ret; - - buf = kzalloc(8, GFP_KERNEL | GFP_DMA); - if (!buf) - return -ENOMEM; - - obuf = buf; - ibuf = buf + 4; - *obuf = out; - ret = max3110_write_then_read(max, obuf, ibuf, 2, 1); - if (ret) { - pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n", - __func__, ret, out); - goto exit; - } - - /* If some valid data is read back */ - if (*ibuf & MAX3110_READ_DATA_AVAILABLE) { - ch = *ibuf & 0xff; - receive_chars(max, &ch, 1); - } - -exit: - kfree(buf); - return ret; -} - -/* - * This is usually used to read data from SPIC RX FIFO, which doesn't - * need any delay like flushing character out. - * - * Return how many valide bytes are read back - */ -static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf) -{ - void *buf; - u16 *obuf, *ibuf; - u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH]; - int i, j, blen; - - blen = M3110_RX_FIFO_DEPTH * sizeof(u16); - buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA); - if (!buf) { - pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__); - return 0; - } - - /* tx/rx always have the same length */ - obuf = buf; - ibuf = buf + blen; - - if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) { - kfree(buf); - return 0; - } - - /* If caller doesn't provide a buffer, then handle received char */ - pbuf = rxbuf ? rxbuf : valid_str; - - for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) { - if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) - pbuf[j++] = ibuf[i] & 0xff; - } - - if (j && (pbuf == valid_str)) - receive_chars(max, valid_str, j); - - kfree(buf); - return j; -} - -static void serial_m3110_con_putchar(struct uart_port *port, int ch) -{ - struct uart_max3110 *max = - container_of(port, struct uart_max3110, port); - struct circ_buf *xmit = &max->con_xmit; - - if (uart_circ_chars_free(xmit)) { - xmit->buf[xmit->head] = (char)ch; - xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1); - } -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void serial_m3110_con_write(struct console *co, - const char *s, unsigned int count) -{ - if (!pmax) - return; - - uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar); - - if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags)) - wake_up_process(pmax->main_thread); -} - -static int __init -serial_m3110_con_setup(struct console *co, char *options) -{ - struct uart_max3110 *max = pmax; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - pr_info(PR_FMT "setting up console\n"); - - if (co->index == -1) - co->index = 0; - - if (!max) { - pr_err(PR_FMT "pmax is NULL, return"); - return -ENODEV; - } - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&max->port, co, baud, parity, bits, flow); -} - -static struct tty_driver *serial_m3110_con_device(struct console *co, - int *index) -{ - struct uart_driver *p = co->data; - *index = co->index; - return p->tty_driver; -} - -static struct uart_driver serial_m3110_reg; -static struct console serial_m3110_console = { - .name = "ttyS", - .write = serial_m3110_con_write, - .device = serial_m3110_con_device, - .setup = serial_m3110_con_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_m3110_reg, -}; - -static unsigned int serial_m3110_tx_empty(struct uart_port *port) -{ - return 1; -} - -static void serial_m3110_stop_tx(struct uart_port *port) -{ - return; -} - -/* stop_rx will be called in spin_lock env */ -static void serial_m3110_stop_rx(struct uart_port *port) -{ - return; -} - -#define WORDS_PER_XFER 128 -static void send_circ_buf(struct uart_max3110 *max, - struct circ_buf *xmit) -{ - void *buf; - u16 *obuf, *ibuf; - u8 valid_str[WORDS_PER_XFER]; - int i, j, len, blen, dma_size, left, ret = 0; - - - dma_size = WORDS_PER_XFER * sizeof(u16) * 2; - buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA); - if (!buf) - return; - obuf = buf; - ibuf = buf + dma_size/2; - - while (!uart_circ_empty(xmit)) { - left = uart_circ_chars_pending(xmit); - while (left) { - len = min(left, WORDS_PER_XFER); - blen = len * sizeof(u16); - memset(ibuf, 0, blen); - - for (i = 0; i < len; i++) { - obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG; - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); - } - - /* Fail to send msg to console is not very critical */ - ret = max3110_write_then_read(max, obuf, ibuf, blen, 0); - if (ret) - pr_warning(PR_FMT "%s(): get err msg %d\n", - __func__, ret); - - for (i = 0, j = 0; i < len; i++) { - if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) - valid_str[j++] = ibuf[i] & 0xff; - } - - if (j) - receive_chars(max, valid_str, j); - - max->port.icount.tx += len; - left -= len; - } - } - - kfree(buf); -} - -static void transmit_char(struct uart_max3110 *max) -{ - struct uart_port *port = &max->port; - struct circ_buf *xmit = &port->state->xmit; - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - send_circ_buf(max, xmit); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - serial_m3110_stop_tx(port); -} - -/* - * This will be called by uart_write() and tty_write, can't - * go to sleep - */ -static void serial_m3110_start_tx(struct uart_port *port) -{ - struct uart_max3110 *max = - container_of(port, struct uart_max3110, port); - - if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags)) - wake_up_process(max->main_thread); -} - -static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) -{ - struct uart_port *port = &max->port; - struct tty_struct *tty; - int usable; - - /* If uart is not opened, just return */ - if (!port->state) - return; - - tty = port->state->port.tty; - if (!tty) - return; - - while (len) { - usable = tty_buffer_request_room(tty, len); - if (usable) { - tty_insert_flip_string(tty, str, usable); - str += usable; - port->icount.rx += usable; - } - len -= usable; - } - tty_flip_buffer_push(tty); -} - -/* - * This routine will be used in read_thread or RX IRQ handling, - * it will first do one round buffer read(8 words), if there is some - * valid RX data, will try to read 5 more rounds till all data - * is read out. - * - * Use stack space as data buffer to save some system load, and chose - * 504 Btyes as a threadhold to do a bulk push to upper tty layer when - * receiving bulk data, a much bigger buffer may cause stack overflow - */ -static void max3110_con_receive(struct uart_max3110 *max) -{ - int loop = 1, num, total = 0; - u8 recv_buf[512], *pbuf; - - pbuf = recv_buf; - do { - num = max3110_read_multi(max, pbuf); - - if (num) { - loop = 5; - pbuf += num; - total += num; - - if (total >= 504) { - receive_chars(max, recv_buf, total); - pbuf = recv_buf; - total = 0; - } - } - } while (--loop); - - if (total) - receive_chars(max, recv_buf, total); -} - -static int max3110_main_thread(void *_max) -{ - struct uart_max3110 *max = _max; - wait_queue_head_t *wq = &max->wq; - int ret = 0; - struct circ_buf *xmit = &max->con_xmit; - - init_waitqueue_head(wq); - pr_info(PR_FMT "start main thread\n"); - - do { - wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop()); - - mutex_lock(&max->thread_mutex); - - if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags)) - max3110_con_receive(max); - - /* first handle console output */ - if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags)) - send_circ_buf(max, xmit); - - /* handle uart output */ - if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags)) - transmit_char(max); - - mutex_unlock(&max->thread_mutex); - - } while (!kthread_should_stop()); - - return ret; -} - -static irqreturn_t serial_m3110_irq(int irq, void *dev_id) -{ - struct uart_max3110 *max = dev_id; - - /* max3110's irq is a falling edge, not level triggered, - * so no need to disable the irq */ - if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags)) - wake_up_process(max->main_thread); - - return IRQ_HANDLED; -} - -/* if don't use RX IRQ, then need a thread to polling read */ -static int max3110_read_thread(void *_max) -{ - struct uart_max3110 *max = _max; - - pr_info(PR_FMT "start read thread\n"); - do { - /* - * If can't acquire the mutex, it means the main thread - * is running which will also perform the rx job - */ - if (mutex_trylock(&max->thread_mutex)) { - max3110_con_receive(max); - mutex_unlock(&max->thread_mutex); - } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 20); - } while (!kthread_should_stop()); - - return 0; -} - -static int serial_m3110_startup(struct uart_port *port) -{ - struct uart_max3110 *max = - container_of(port, struct uart_max3110, port); - u16 config = 0; - int ret = 0; - - if (port->line != 0) { - pr_err(PR_FMT "uart port startup failed\n"); - return -1; - } - - /* Disable all IRQ and config it to 115200, 8n1 */ - config = WC_TAG | WC_FIFO_ENABLE - | WC_1_STOPBITS - | WC_8BIT_WORD - | WC_BAUD_DR2; - - /* as we use thread to handle tx/rx, need set low latency */ - port->state->port.tty->low_latency = 1; - - if (max->irq) { - max->read_thread = NULL; - ret = request_irq(max->irq, serial_m3110_irq, - IRQ_TYPE_EDGE_FALLING, "max3110", max); - if (ret) { - max->irq = 0; - pr_err(PR_FMT "unable to allocate IRQ, polling\n"); - } else { - /* Enable RX IRQ only */ - config |= WC_RXA_IRQ_ENABLE; - } - } - - if (max->irq == 0) { - /* If IRQ is disabled, start a read thread for input data */ - max->read_thread = - kthread_run(max3110_read_thread, max, "max3110_read"); - if (IS_ERR(max->read_thread)) { - ret = PTR_ERR(max->read_thread); - max->read_thread = NULL; - pr_err(PR_FMT "Can't create read thread!\n"); - return ret; - } - } - - ret = max3110_out(max, config); - if (ret) { - if (max->irq) - free_irq(max->irq, max); - if (max->read_thread) - kthread_stop(max->read_thread); - max->read_thread = NULL; - return ret; - } - - max->cur_conf = config; - return 0; -} - -static void serial_m3110_shutdown(struct uart_port *port) -{ - struct uart_max3110 *max = - container_of(port, struct uart_max3110, port); - u16 config; - - if (max->read_thread) { - kthread_stop(max->read_thread); - max->read_thread = NULL; - } - - if (max->irq) - free_irq(max->irq, max); - - /* Disable interrupts from this port */ - config = WC_TAG | WC_SW_SHDI; - max3110_out(max, config); -} - -static void serial_m3110_release_port(struct uart_port *port) -{ -} - -static int serial_m3110_request_port(struct uart_port *port) -{ - return 0; -} - -static void serial_m3110_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_MAX3100; -} - -static int -serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* we don't want the core code to modify any port params */ - return -EINVAL; -} - - -static const char *serial_m3110_type(struct uart_port *port) -{ - struct uart_max3110 *max = - container_of(port, struct uart_max3110, port); - return max->name; -} - -static void -serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_max3110 *max = - container_of(port, struct uart_max3110, port); - unsigned char cval; - unsigned int baud, parity = 0; - int clk_div = -1; - u16 new_conf = max->cur_conf; - - switch (termios->c_cflag & CSIZE) { - case CS7: - cval = UART_LCR_WLEN7; - new_conf |= WC_7BIT_WORD; - break; - default: - /* We only support CS7 & CS8 */ - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= CS8; - case CS8: - cval = UART_LCR_WLEN8; - new_conf |= WC_8BIT_WORD; - break; - } - - baud = uart_get_baud_rate(port, termios, old, 0, 230400); - - /* First calc the div for 1.8MHZ clock case */ - switch (baud) { - case 300: - clk_div = WC_BAUD_DR384; - break; - case 600: - clk_div = WC_BAUD_DR192; - break; - case 1200: - clk_div = WC_BAUD_DR96; - break; - case 2400: - clk_div = WC_BAUD_DR48; - break; - case 4800: - clk_div = WC_BAUD_DR24; - break; - case 9600: - clk_div = WC_BAUD_DR12; - break; - case 19200: - clk_div = WC_BAUD_DR6; - break; - case 38400: - clk_div = WC_BAUD_DR3; - break; - case 57600: - clk_div = WC_BAUD_DR2; - break; - case 115200: - clk_div = WC_BAUD_DR1; - break; - case 230400: - if (max->clock & MAX3110_HIGH_CLK) - break; - default: - /* Pick the previous baud rate */ - baud = max->baud; - clk_div = max->cur_conf & WC_BAUD_DIV_MASK; - tty_termios_encode_baud_rate(termios, baud, baud); - } - - if (max->clock & MAX3110_HIGH_CLK) { - clk_div += 1; - /* High clk version max3110 doesn't support B300 */ - if (baud == 300) { - baud = 600; - clk_div = WC_BAUD_DR384; - } - if (baud == 230400) - clk_div = WC_BAUD_DR1; - tty_termios_encode_baud_rate(termios, baud, baud); - } - - new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div; - - if (unlikely(termios->c_cflag & CMSPAR)) - termios->c_cflag &= ~CMSPAR; - - if (termios->c_cflag & CSTOPB) - new_conf |= WC_2_STOPBITS; - else - new_conf &= ~WC_2_STOPBITS; - - if (termios->c_cflag & PARENB) { - new_conf |= WC_PARITY_ENABLE; - parity |= UART_LCR_PARITY; - } else - new_conf &= ~WC_PARITY_ENABLE; - - if (!(termios->c_cflag & PARODD)) - parity |= UART_LCR_EPAR; - max->parity = parity; - - uart_update_timeout(port, termios->c_cflag, baud); - - new_conf |= WC_TAG; - if (new_conf != max->cur_conf) { - if (!max3110_out(max, new_conf)) { - max->cur_conf = new_conf; - max->baud = baud; - } - } -} - -/* Don't handle hw handshaking */ -static unsigned int serial_m3110_get_mctrl(struct uart_port *port) -{ - return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR; -} - -static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -static void serial_m3110_break_ctl(struct uart_port *port, int break_state) -{ -} - -static void serial_m3110_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ -} - -static void serial_m3110_enable_ms(struct uart_port *port) -{ -} - -struct uart_ops serial_m3110_ops = { - .tx_empty = serial_m3110_tx_empty, - .set_mctrl = serial_m3110_set_mctrl, - .get_mctrl = serial_m3110_get_mctrl, - .stop_tx = serial_m3110_stop_tx, - .start_tx = serial_m3110_start_tx, - .stop_rx = serial_m3110_stop_rx, - .enable_ms = serial_m3110_enable_ms, - .break_ctl = serial_m3110_break_ctl, - .startup = serial_m3110_startup, - .shutdown = serial_m3110_shutdown, - .set_termios = serial_m3110_set_termios, - .pm = serial_m3110_pm, - .type = serial_m3110_type, - .release_port = serial_m3110_release_port, - .request_port = serial_m3110_request_port, - .config_port = serial_m3110_config_port, - .verify_port = serial_m3110_verify_port, -}; - -static struct uart_driver serial_m3110_reg = { - .owner = THIS_MODULE, - .driver_name = "MRST serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = 1, - .cons = &serial_m3110_console, -}; - -#ifdef CONFIG_PM -static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state) -{ - struct uart_max3110 *max = spi_get_drvdata(spi); - - disable_irq(max->irq); - uart_suspend_port(&serial_m3110_reg, &max->port); - max3110_out(max, max->cur_conf | WC_SW_SHDI); - return 0; -} - -static int serial_m3110_resume(struct spi_device *spi) -{ - struct uart_max3110 *max = spi_get_drvdata(spi); - - max3110_out(max, max->cur_conf); - uart_resume_port(&serial_m3110_reg, &max->port); - enable_irq(max->irq); - return 0; -} -#else -#define serial_m3110_suspend NULL -#define serial_m3110_resume NULL -#endif - -static int __devinit serial_m3110_probe(struct spi_device *spi) -{ - struct uart_max3110 *max; - void *buffer; - u16 res; - int ret = 0; - - max = kzalloc(sizeof(*max), GFP_KERNEL); - if (!max) - return -ENOMEM; - - /* Set spi info */ - spi->bits_per_word = 16; - max->clock = MAX3110_HIGH_CLK; - - spi_setup(spi); - - max->port.type = PORT_MAX3100; - max->port.fifosize = 2; /* Only have 16b buffer */ - max->port.ops = &serial_m3110_ops; - max->port.line = 0; - max->port.dev = &spi->dev; - max->port.uartclk = 115200; - - max->spi = spi; - strcpy(max->name, spi->modalias); - max->irq = (u16)spi->irq; - - mutex_init(&max->thread_mutex); - - max->word_7bits = 0; - max->parity = 0; - max->baud = 0; - - max->cur_conf = 0; - max->uart_flags = 0; - - /* Check if reading configuration register returns something sane */ - - res = RC_TAG; - ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0); - if (ret < 0 || res == 0 || res == 0xffff) { - printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)", - res); - ret = -ENODEV; - goto err_get_page; - } - - buffer = (void *)__get_free_page(GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - goto err_get_page; - } - max->con_xmit.buf = buffer; - max->con_xmit.head = 0; - max->con_xmit.tail = 0; - - max->main_thread = kthread_run(max3110_main_thread, - max, "max3110_main"); - if (IS_ERR(max->main_thread)) { - ret = PTR_ERR(max->main_thread); - goto err_kthread; - } - - spi_set_drvdata(spi, max); - pmax = max; - - /* Give membase a psudo value to pass serial_core's check */ - max->port.membase = (void *)0xff110000; - uart_add_one_port(&serial_m3110_reg, &max->port); - - return 0; - -err_kthread: - free_page((unsigned long)buffer); -err_get_page: - kfree(max); - return ret; -} - -static int __devexit serial_m3110_remove(struct spi_device *dev) -{ - struct uart_max3110 *max = spi_get_drvdata(dev); - - if (!max) - return 0; - - uart_remove_one_port(&serial_m3110_reg, &max->port); - - free_page((unsigned long)max->con_xmit.buf); - - if (max->main_thread) - kthread_stop(max->main_thread); - - kfree(max); - return 0; -} - -static struct spi_driver uart_max3110_driver = { - .driver = { - .name = "spi_max3111", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = serial_m3110_probe, - .remove = __devexit_p(serial_m3110_remove), - .suspend = serial_m3110_suspend, - .resume = serial_m3110_resume, -}; - -static int __init serial_m3110_init(void) -{ - int ret = 0; - - ret = uart_register_driver(&serial_m3110_reg); - if (ret) - return ret; - - ret = spi_register_driver(&uart_max3110_driver); - if (ret) - uart_unregister_driver(&serial_m3110_reg); - - return ret; -} - -static void __exit serial_m3110_exit(void) -{ - spi_unregister_driver(&uart_max3110_driver); - uart_unregister_driver(&serial_m3110_reg); -} - -module_init(serial_m3110_init); -module_exit(serial_m3110_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("max3110-uart"); diff --git a/drivers/serial/mrst_max3110.h b/drivers/serial/mrst_max3110.h deleted file mode 100644 index d1ef43af397c..000000000000 --- a/drivers/serial/mrst_max3110.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _MRST_MAX3110_H -#define _MRST_MAX3110_H - -#define MAX3110_HIGH_CLK 0x1 /* 3.6864 MHZ */ -#define MAX3110_LOW_CLK 0x0 /* 1.8432 MHZ */ - -/* status bits for all 4 MAX3110 operate modes */ -#define MAX3110_READ_DATA_AVAILABLE (1 << 15) -#define MAX3110_WRITE_BUF_EMPTY (1 << 14) - -#define WC_TAG (3 << 14) -#define RC_TAG (1 << 14) -#define WD_TAG (2 << 14) -#define RD_TAG (0 << 14) - -/* bits def for write configuration */ -#define WC_FIFO_ENABLE_MASK (1 << 13) -#define WC_FIFO_ENABLE (0 << 13) - -#define WC_SW_SHDI (1 << 12) - -#define WC_IRQ_MASK (0xF << 8) -#define WC_TXE_IRQ_ENABLE (1 << 11) /* TX empty irq */ -#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX availabe irq */ -#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9) -#define WC_REC_ACT_IRQ_ENABLE (1 << 8) - -#define WC_IRDA_ENABLE (1 << 7) - -#define WC_STOPBITS_MASK (1 << 6) -#define WC_2_STOPBITS (1 << 6) -#define WC_1_STOPBITS (0 << 6) - -#define WC_PARITY_ENABLE_MASK (1 << 5) -#define WC_PARITY_ENABLE (1 << 5) - -#define WC_WORDLEN_MASK (1 << 4) -#define WC_7BIT_WORD (1 << 4) -#define WC_8BIT_WORD (0 << 4) - -#define WC_BAUD_DIV_MASK (0xF) -#define WC_BAUD_DR1 (0x0) -#define WC_BAUD_DR2 (0x1) -#define WC_BAUD_DR4 (0x2) -#define WC_BAUD_DR8 (0x3) -#define WC_BAUD_DR16 (0x4) -#define WC_BAUD_DR32 (0x5) -#define WC_BAUD_DR64 (0x6) -#define WC_BAUD_DR128 (0x7) -#define WC_BAUD_DR3 (0x8) -#define WC_BAUD_DR6 (0x9) -#define WC_BAUD_DR12 (0xA) -#define WC_BAUD_DR24 (0xB) -#define WC_BAUD_DR48 (0xC) -#define WC_BAUD_DR96 (0xD) -#define WC_BAUD_DR192 (0xE) -#define WC_BAUD_DR384 (0xF) - -#define M3110_RX_FIFO_DEPTH 8 -#endif diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c deleted file mode 100644 index 8e43a7b69e64..000000000000 --- a/drivers/serial/msm_serial.c +++ /dev/null @@ -1,758 +0,0 @@ -/* - * drivers/serial/msm_serial.c - driver for msm7k serial device and console - * - * Copyright (C) 2007 Google, Inc. - * Author: Robert Love - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -# define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "msm_serial.h" - -struct msm_port { - struct uart_port uart; - char name[16]; - struct clk *clk; - unsigned int imr; -}; - -static void msm_stop_tx(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); -} - -static void msm_start_tx(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - msm_port->imr |= UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); -} - -static void msm_stop_rx(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); - msm_write(port, msm_port->imr, UART_IMR); -} - -static void msm_enable_ms(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - msm_port->imr |= UART_IMR_DELTA_CTS; - msm_write(port, msm_port->imr, UART_IMR); -} - -static void handle_rx(struct uart_port *port) -{ - struct tty_struct *tty = port->state->port.tty; - unsigned int sr; - - /* - * Handle overrun. My understanding of the hardware is that overrun - * is not tied to the RX buffer, so we handle the case out of band. - */ - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { - port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - } - - /* and now the main RX loop */ - while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { - unsigned int c; - char flag = TTY_NORMAL; - - c = msm_read(port, UART_RF); - - if (sr & UART_SR_RX_BREAK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sr & UART_SR_PAR_FRAME_ERR) { - port->icount.frame++; - } else { - port->icount.rx++; - } - - /* Mask conditions we're ignorning. */ - sr &= port->read_status_mask; - - if (sr & UART_SR_RX_BREAK) { - flag = TTY_BREAK; - } else if (sr & UART_SR_PAR_FRAME_ERR) { - flag = TTY_FRAME; - } - - if (!uart_handle_sysrq_char(port, c)) - tty_insert_flip_char(tty, c, flag); - } - - tty_flip_buffer_push(tty); -} - -static void handle_tx(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - struct msm_port *msm_port = UART_TO_MSM(port); - int sent_tx; - - if (port->x_char) { - msm_write(port, port->x_char, UART_TF); - port->icount.tx++; - port->x_char = 0; - } - - while (msm_read(port, UART_SR) & UART_SR_TX_READY) { - if (uart_circ_empty(xmit)) { - /* disable tx interrupts */ - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); - break; - } - - msm_write(port, xmit->buf[xmit->tail], UART_TF); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - sent_tx = 1; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static void handle_delta_cts(struct uart_port *port) -{ - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); - port->icount.cts++; - wake_up_interruptible(&port->state->port.delta_msr_wait); -} - -static irqreturn_t msm_irq(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct msm_port *msm_port = UART_TO_MSM(port); - unsigned int misr; - - spin_lock(&port->lock); - misr = msm_read(port, UART_MISR); - msm_write(port, 0, UART_IMR); /* disable interrupt */ - - if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) - handle_rx(port); - if (misr & UART_IMR_TXLEV) - handle_tx(port); - if (misr & UART_IMR_DELTA_CTS) - handle_delta_cts(port); - - msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ - spin_unlock(&port->lock); - - return IRQ_HANDLED; -} - -static unsigned int msm_tx_empty(struct uart_port *port) -{ - return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; -} - -static unsigned int msm_get_mctrl(struct uart_port *port) -{ - return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; -} - -static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - unsigned int mr; - - mr = msm_read(port, UART_MR1); - - if (!(mctrl & TIOCM_RTS)) { - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); - } else { - mr |= UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); - } -} - -static void msm_break_ctl(struct uart_port *port, int break_ctl) -{ - if (break_ctl) - msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); - else - msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); -} - -static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) -{ - unsigned int baud_code, rxstale, watermark; - - switch (baud) { - case 300: - baud_code = UART_CSR_300; - rxstale = 1; - break; - case 600: - baud_code = UART_CSR_600; - rxstale = 1; - break; - case 1200: - baud_code = UART_CSR_1200; - rxstale = 1; - break; - case 2400: - baud_code = UART_CSR_2400; - rxstale = 1; - break; - case 4800: - baud_code = UART_CSR_4800; - rxstale = 1; - break; - case 9600: - baud_code = UART_CSR_9600; - rxstale = 2; - break; - case 14400: - baud_code = UART_CSR_14400; - rxstale = 3; - break; - case 19200: - baud_code = UART_CSR_19200; - rxstale = 4; - break; - case 28800: - baud_code = UART_CSR_28800; - rxstale = 6; - break; - case 38400: - baud_code = UART_CSR_38400; - rxstale = 8; - break; - case 57600: - baud_code = UART_CSR_57600; - rxstale = 16; - break; - case 115200: - default: - baud_code = UART_CSR_115200; - baud = 115200; - rxstale = 31; - break; - } - - msm_write(port, baud_code, UART_CSR); - - /* RX stale watermark */ - watermark = UART_IPR_STALE_LSB & rxstale; - watermark |= UART_IPR_RXSTALE_LAST; - watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2); - msm_write(port, watermark, UART_IPR); - - /* set RX watermark */ - watermark = (port->fifosize * 3) / 4; - msm_write(port, watermark, UART_RFWR); - - /* set TX watermark */ - msm_write(port, 10, UART_TFWR); - - return baud; -} - -static void msm_reset(struct uart_port *port) -{ - /* reset everything */ - msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); - msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); -} - -static void msm_init_clock(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - clk_enable(msm_port->clk); - msm_serial_set_mnd_regs(port); -} - -static int msm_startup(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - unsigned int data, rfr_level; - int ret; - - snprintf(msm_port->name, sizeof(msm_port->name), - "msm_serial%d", port->line); - - ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, - msm_port->name, port); - if (unlikely(ret)) - return ret; - - msm_init_clock(port); - - if (likely(port->fifosize > 12)) - rfr_level = port->fifosize - 12; - else - rfr_level = port->fifosize; - - /* set automatic RFR level */ - data = msm_read(port, UART_MR1); - data &= ~UART_MR1_AUTO_RFR_LEVEL1; - data &= ~UART_MR1_AUTO_RFR_LEVEL0; - data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); - data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; - msm_write(port, data, UART_MR1); - - /* make sure that RXSTALE count is non-zero */ - data = msm_read(port, UART_IPR); - if (unlikely(!data)) { - data |= UART_IPR_RXSTALE_LAST; - data |= UART_IPR_STALE_LSB; - msm_write(port, data, UART_IPR); - } - - msm_reset(port); - - msm_write(port, 0x05, UART_CR); /* enable TX & RX */ - - /* turn on RX and CTS interrupts */ - msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | - UART_IMR_CURRENT_CTS; - msm_write(port, msm_port->imr, UART_IMR); - - return 0; -} - -static void msm_shutdown(struct uart_port *port) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - msm_port->imr = 0; - msm_write(port, 0, UART_IMR); /* disable interrupts */ - - clk_disable(msm_port->clk); - - free_irq(port->irq, port); -} - -static void msm_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int baud, mr; - - spin_lock_irqsave(&port->lock, flags); - - /* calculate and set baud rate */ - baud = uart_get_baud_rate(port, termios, old, 300, 115200); - baud = msm_set_baud_rate(port, baud); - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); - - /* calculate parity */ - mr = msm_read(port, UART_MR2); - mr &= ~UART_MR2_PARITY_MODE; - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & PARODD) - mr |= UART_MR2_PARITY_MODE_ODD; - else if (termios->c_cflag & CMSPAR) - mr |= UART_MR2_PARITY_MODE_SPACE; - else - mr |= UART_MR2_PARITY_MODE_EVEN; - } - - /* calculate bits per char */ - mr &= ~UART_MR2_BITS_PER_CHAR; - switch (termios->c_cflag & CSIZE) { - case CS5: - mr |= UART_MR2_BITS_PER_CHAR_5; - break; - case CS6: - mr |= UART_MR2_BITS_PER_CHAR_6; - break; - case CS7: - mr |= UART_MR2_BITS_PER_CHAR_7; - break; - case CS8: - default: - mr |= UART_MR2_BITS_PER_CHAR_8; - break; - } - - /* calculate stop bits */ - mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); - if (termios->c_cflag & CSTOPB) - mr |= UART_MR2_STOP_BIT_LEN_TWO; - else - mr |= UART_MR2_STOP_BIT_LEN_ONE; - - /* set parity, bits per char, and stop bit */ - msm_write(port, mr, UART_MR2); - - /* calculate and set hardware flow control */ - mr = msm_read(port, UART_MR1); - mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); - if (termios->c_cflag & CRTSCTS) { - mr |= UART_MR1_CTS_CTL; - mr |= UART_MR1_RX_RDY_CTL; - } - msm_write(port, mr, UART_MR1); - - /* Configure status bits to ignore based on termio flags. */ - port->read_status_mask = 0; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_SR_PAR_FRAME_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART_SR_RX_BREAK; - - uart_update_timeout(port, termios->c_cflag, baud); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *msm_type(struct uart_port *port) -{ - return "MSM"; -} - -static void msm_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *resource; - resource_size_t size; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return; - size = resource->end - resource->start + 1; - - release_mem_region(port->mapbase, size); - iounmap(port->membase); - port->membase = NULL; -} - -static int msm_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *resource; - resource_size_t size; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - size = resource->end - resource->start + 1; - - if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial"))) - return -EBUSY; - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - release_mem_region(port->mapbase, size); - return -EBUSY; - } - - return 0; -} - -static void msm_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_MSM; - msm_request_port(port); - } -} - -static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)) - return -EINVAL; - if (unlikely(port->irq != ser->irq)) - return -EINVAL; - return 0; -} - -static void msm_power(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct msm_port *msm_port = UART_TO_MSM(port); - - switch (state) { - case 0: - clk_enable(msm_port->clk); - break; - case 3: - clk_disable(msm_port->clk); - break; - default: - printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); - } -} - -static struct uart_ops msm_uart_pops = { - .tx_empty = msm_tx_empty, - .set_mctrl = msm_set_mctrl, - .get_mctrl = msm_get_mctrl, - .stop_tx = msm_stop_tx, - .start_tx = msm_start_tx, - .stop_rx = msm_stop_rx, - .enable_ms = msm_enable_ms, - .break_ctl = msm_break_ctl, - .startup = msm_startup, - .shutdown = msm_shutdown, - .set_termios = msm_set_termios, - .type = msm_type, - .release_port = msm_release_port, - .request_port = msm_request_port, - .config_port = msm_config_port, - .verify_port = msm_verify_port, - .pm = msm_power, -}; - -static struct msm_port msm_uart_ports[] = { - { - .uart = { - .iotype = UPIO_MEM, - .ops = &msm_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 512, - .line = 0, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &msm_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 512, - .line = 1, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &msm_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, - .line = 2, - }, - }, -}; - -#define UART_NR ARRAY_SIZE(msm_uart_ports) - -static inline struct uart_port *get_port_from_line(unsigned int line) -{ - return &msm_uart_ports[line].uart; -} - -#ifdef CONFIG_SERIAL_MSM_CONSOLE - -static void msm_console_putchar(struct uart_port *port, int c) -{ - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) - ; - msm_write(port, c, UART_TF); -} - -static void msm_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_port *port; - struct msm_port *msm_port; - - BUG_ON(co->index < 0 || co->index >= UART_NR); - - port = get_port_from_line(co->index); - msm_port = UART_TO_MSM(port); - - spin_lock(&port->lock); - uart_console_write(port, s, count, msm_console_putchar); - spin_unlock(&port->lock); -} - -static int __init msm_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud, flow, bits, parity; - - if (unlikely(co->index >= UART_NR || co->index < 0)) - return -ENXIO; - - port = get_port_from_line(co->index); - - if (unlikely(!port->membase)) - return -ENXIO; - - port->cons = co; - - msm_init_clock(port); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - bits = 8; - parity = 'n'; - flow = 'n'; - msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE, - UART_MR2); /* 8N1 */ - - if (baud < 300 || baud > 115200) - baud = 115200; - msm_set_baud_rate(port, baud); - - msm_reset(port); - - printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver msm_uart_driver; - -static struct console msm_console = { - .name = "ttyMSM", - .write = msm_console_write, - .device = uart_console_device, - .setup = msm_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &msm_uart_driver, -}; - -#define MSM_CONSOLE (&msm_console) - -#else -#define MSM_CONSOLE NULL -#endif - -static struct uart_driver msm_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "msm_serial", - .dev_name = "ttyMSM", - .nr = UART_NR, - .cons = MSM_CONSOLE, -}; - -static int __init msm_serial_probe(struct platform_device *pdev) -{ - struct msm_port *msm_port; - struct resource *resource; - struct uart_port *port; - int irq; - - if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) - return -ENXIO; - - printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id); - - port = get_port_from_line(pdev->id); - port->dev = &pdev->dev; - msm_port = UART_TO_MSM(port); - - msm_port->clk = clk_get(&pdev->dev, "uart_clk"); - if (IS_ERR(msm_port->clk)) - return PTR_ERR(msm_port->clk); - port->uartclk = clk_get_rate(msm_port->clk); - printk(KERN_INFO "uartclk = %d\n", port->uartclk); - - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - port->mapbase = resource->start; - - irq = platform_get_irq(pdev, 0); - if (unlikely(irq < 0)) - return -ENXIO; - port->irq = irq; - - platform_set_drvdata(pdev, port); - - return uart_add_one_port(&msm_uart_driver, port); -} - -static int __devexit msm_serial_remove(struct platform_device *pdev) -{ - struct msm_port *msm_port = platform_get_drvdata(pdev); - - clk_put(msm_port->clk); - - return 0; -} - -static struct platform_driver msm_platform_driver = { - .remove = msm_serial_remove, - .driver = { - .name = "msm_serial", - .owner = THIS_MODULE, - }, -}; - -static int __init msm_serial_init(void) -{ - int ret; - - ret = uart_register_driver(&msm_uart_driver); - if (unlikely(ret)) - return ret; - - ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe); - if (unlikely(ret)) - uart_unregister_driver(&msm_uart_driver); - - printk(KERN_INFO "msm_serial: driver initialized\n"); - - return ret; -} - -static void __exit msm_serial_exit(void) -{ -#ifdef CONFIG_SERIAL_MSM_CONSOLE - unregister_console(&msm_console); -#endif - platform_driver_unregister(&msm_platform_driver); - uart_unregister_driver(&msm_uart_driver); -} - -module_init(msm_serial_init); -module_exit(msm_serial_exit); - -MODULE_AUTHOR("Robert Love "); -MODULE_DESCRIPTION("Driver for msm7x serial device"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h deleted file mode 100644 index f6ca9ca79e98..000000000000 --- a/drivers/serial/msm_serial.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * drivers/serial/msm_serial.h - * - * Copyright (C) 2007 Google, Inc. - * Author: Robert Love - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H -#define __DRIVERS_SERIAL_MSM_SERIAL_H - -#define UART_MR1 0x0000 - -#define UART_MR1_AUTO_RFR_LEVEL0 0x3F -#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_MR1_RX_RDY_CTL (1 << 7) -#define UART_MR1_CTS_CTL (1 << 6) - -#define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE (1 << 6) -#define UART_MR2_BITS_PER_CHAR 0x30 -#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) -#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) -#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) -#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) -#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) -#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) -#define UART_MR2_PARITY_MODE_NONE 0x0 -#define UART_MR2_PARITY_MODE_ODD 0x1 -#define UART_MR2_PARITY_MODE_EVEN 0x2 -#define UART_MR2_PARITY_MODE_SPACE 0x3 -#define UART_MR2_PARITY_MODE 0x3 - -#define UART_CSR 0x0008 -#define UART_CSR_115200 0xFF -#define UART_CSR_57600 0xEE -#define UART_CSR_38400 0xDD -#define UART_CSR_28800 0xCC -#define UART_CSR_19200 0xBB -#define UART_CSR_14400 0xAA -#define UART_CSR_9600 0x99 -#define UART_CSR_4800 0x77 -#define UART_CSR_2400 0x55 -#define UART_CSR_1200 0x44 -#define UART_CSR_600 0x33 -#define UART_CSR_300 0x22 - -#define UART_TF 0x000C - -#define UART_CR 0x0010 -#define UART_CR_CMD_NULL (0 << 4) -#define UART_CR_CMD_RESET_RX (1 << 4) -#define UART_CR_CMD_RESET_TX (2 << 4) -#define UART_CR_CMD_RESET_ERR (3 << 4) -#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) -#define UART_CR_CMD_START_BREAK (5 << 4) -#define UART_CR_CMD_STOP_BREAK (6 << 4) -#define UART_CR_CMD_RESET_CTS (7 << 4) -#define UART_CR_CMD_PACKET_MODE (9 << 4) -#define UART_CR_CMD_MODE_RESET (12 << 4) -#define UART_CR_CMD_SET_RFR (13 << 4) -#define UART_CR_CMD_RESET_RFR (14 << 4) -#define UART_CR_TX_DISABLE (1 << 3) -#define UART_CR_TX_ENABLE (1 << 3) -#define UART_CR_RX_DISABLE (1 << 3) -#define UART_CR_RX_ENABLE (1 << 3) - -#define UART_IMR 0x0014 -#define UART_IMR_TXLEV (1 << 0) -#define UART_IMR_RXSTALE (1 << 3) -#define UART_IMR_RXLEV (1 << 4) -#define UART_IMR_DELTA_CTS (1 << 5) -#define UART_IMR_CURRENT_CTS (1 << 6) - -#define UART_IPR_RXSTALE_LAST 0x20 -#define UART_IPR_STALE_LSB 0x1F -#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 - -#define UART_IPR 0x0018 -#define UART_TFWR 0x001C -#define UART_RFWR 0x0020 -#define UART_HCR 0x0024 - -#define UART_MREG 0x0028 -#define UART_NREG 0x002C -#define UART_DREG 0x0030 -#define UART_MNDREG 0x0034 -#define UART_IRDA 0x0038 -#define UART_MISR_MODE 0x0040 -#define UART_MISR_RESET 0x0044 -#define UART_MISR_EXPORT 0x0048 -#define UART_MISR_VAL 0x004C -#define UART_TEST_CTRL 0x0050 - -#define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR (1 << 7) -#define UART_SR_RX_BREAK (1 << 6) -#define UART_SR_PAR_FRAME_ERR (1 << 5) -#define UART_SR_OVERRUN (1 << 4) -#define UART_SR_TX_EMPTY (1 << 3) -#define UART_SR_TX_READY (1 << 2) -#define UART_SR_RX_FULL (1 << 1) -#define UART_SR_RX_READY (1 << 0) - -#define UART_RF 0x000C -#define UART_MISR 0x0010 -#define UART_ISR 0x0014 - -#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) - -static inline -void msm_write(struct uart_port *port, unsigned int val, unsigned int off) -{ - __raw_writel(val, port->membase + off); -} - -static inline -unsigned int msm_read(struct uart_port *port, unsigned int off) -{ - return __raw_readl(port->membase + off); -} - -/* - * Setup the MND registers to use the TCXO clock. - */ -static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) -{ - msm_write(port, 0x06, UART_MREG); - msm_write(port, 0xF1, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x1A, UART_MNDREG); -} - -/* - * Setup the MND registers to use the TCXO clock divided by 4. - */ -static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) -{ - msm_write(port, 0x18, UART_MREG); - msm_write(port, 0xF6, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x0A, UART_MNDREG); -} - -static inline -void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) -{ - if (port->uartclk == 19200000) - msm_serial_set_mnd_regs_tcxo(port); - else - msm_serial_set_mnd_regs_tcxoby4(port); -} - -/* - * TROUT has a specific defect that makes it report it's uartclk - * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special - * cases TROUT to use the right clock. - */ -#ifdef CONFIG_MACH_TROUT -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4 -#else -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk -#endif - -#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c deleted file mode 100644 index 9711e06a8374..000000000000 --- a/drivers/serial/mux.c +++ /dev/null @@ -1,633 +0,0 @@ -/* -** mux.c: -** serial driver for the Mux console found in some PA-RISC servers. -** -** (c) Copyright 2002 Ryan Bradetich -** (c) Copyright 2002 Hewlett-Packard Company -** -** 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 Driver currently only supports the console (port 0) on the MUX. -** Additional work will be needed on this driver to enable the full -** functionality of the MUX. -** -*/ - -#include -#include -#include -#include -#include -#include -#include /* for udelay */ -#include -#include -#include -#include - -#ifdef CONFIG_MAGIC_SYSRQ -#include -#define SUPPORT_SYSRQ -#endif - -#include - -#define MUX_OFFSET 0x800 -#define MUX_LINE_OFFSET 0x80 - -#define MUX_FIFO_SIZE 255 -#define MUX_POLL_DELAY (30 * HZ / 1000) - -#define IO_DATA_REG_OFFSET 0x3c -#define IO_DCOUNT_REG_OFFSET 0x40 - -#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000) -#define MUX_STATUS(status) ((status & 0xF000) == 0x8000) -#define MUX_BREAK(status) ((status & 0xF000) == 0x2000) - -#define MUX_NR 256 -static unsigned int port_cnt __read_mostly; -struct mux_port { - struct uart_port port; - int enabled; -}; -static struct mux_port mux_ports[MUX_NR]; - -static struct uart_driver mux_driver = { - .owner = THIS_MODULE, - .driver_name = "ttyB", - .dev_name = "ttyB", - .major = MUX_MAJOR, - .minor = 0, - .nr = MUX_NR, -}; - -static struct timer_list mux_timer; - -#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET) -#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET) - -/** - * get_mux_port_count - Get the number of available ports on the Mux. - * @dev: The parisc device. - * - * This function is used to determine the number of ports the Mux - * supports. The IODC data reports the number of ports the Mux - * can support, but there are cases where not all the Mux ports - * are connected. This function can override the IODC and - * return the true port count. - */ -static int __init get_mux_port_count(struct parisc_device *dev) -{ - int status; - u8 iodc_data[32]; - unsigned long bytecnt; - - /* If this is the built-in Mux for the K-Class (Eole CAP/MUX), - * we only need to allocate resources for 1 port since the - * other 7 ports are not connected. - */ - if(dev->id.hversion == 0x15) - return 1; - - status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); - BUG_ON(status != PDC_OK); - - /* Return the number of ports specified in the iodc data. */ - return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8; -} - -/** - * mux_tx_empty - Check if the transmitter fifo is empty. - * @port: Ptr to the uart_port. - * - * This function test if the transmitter fifo for the port - * described by 'port' is empty. If it is empty, this function - * should return TIOCSER_TEMT, otherwise return 0. - */ -static unsigned int mux_tx_empty(struct uart_port *port) -{ - return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT; -} - -/** - * mux_set_mctrl - Set the current state of the modem control inputs. - * @ports: Ptr to the uart_port. - * @mctrl: Modem control bits. - * - * The Serial MUX does not support CTS, DCD or DSR so this function - * is ignored. - */ -static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -/** - * mux_get_mctrl - Returns the current state of modem control inputs. - * @port: Ptr to the uart_port. - * - * The Serial MUX does not support CTS, DCD or DSR so these lines are - * treated as permanently active. - */ -static unsigned int mux_get_mctrl(struct uart_port *port) -{ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; -} - -/** - * mux_stop_tx - Stop transmitting characters. - * @port: Ptr to the uart_port. - * - * The Serial MUX does not support this function. - */ -static void mux_stop_tx(struct uart_port *port) -{ -} - -/** - * mux_start_tx - Start transmitting characters. - * @port: Ptr to the uart_port. - * - * The Serial Mux does not support this function. - */ -static void mux_start_tx(struct uart_port *port) -{ -} - -/** - * mux_stop_rx - Stop receiving characters. - * @port: Ptr to the uart_port. - * - * The Serial Mux does not support this function. - */ -static void mux_stop_rx(struct uart_port *port) -{ -} - -/** - * mux_enable_ms - Enable modum status interrupts. - * @port: Ptr to the uart_port. - * - * The Serial Mux does not support this function. - */ -static void mux_enable_ms(struct uart_port *port) -{ -} - -/** - * mux_break_ctl - Control the transmitssion of a break signal. - * @port: Ptr to the uart_port. - * @break_state: Raise/Lower the break signal. - * - * The Serial Mux does not support this function. - */ -static void mux_break_ctl(struct uart_port *port, int break_state) -{ -} - -/** - * mux_write - Write chars to the mux fifo. - * @port: Ptr to the uart_port. - * - * This function writes all the data from the uart buffer to - * the mux fifo. - */ -static void mux_write(struct uart_port *port) -{ - int count; - struct circ_buf *xmit = &port->state->xmit; - - if(port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if(uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mux_stop_tx(port); - return; - } - - count = (port->fifosize) - UART_GET_FIFO_CNT(port); - do { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if(uart_circ_empty(xmit)) - break; - - } while(--count > 0); - - while(UART_GET_FIFO_CNT(port)) - udelay(1); - - if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - mux_stop_tx(port); -} - -/** - * mux_read - Read chars from the mux fifo. - * @port: Ptr to the uart_port. - * - * This reads all available data from the mux's fifo and pushes - * the data to the tty layer. - */ -static void mux_read(struct uart_port *port) -{ - int data; - struct tty_struct *tty = port->state->port.tty; - __u32 start_count = port->icount.rx; - - while(1) { - data = __raw_readl(port->membase + IO_DATA_REG_OFFSET); - - if (MUX_STATUS(data)) - continue; - - if (MUX_EOFIFO(data)) - break; - - port->icount.rx++; - - if (MUX_BREAK(data)) { - port->icount.brk++; - if(uart_handle_break(port)) - continue; - } - - if (uart_handle_sysrq_char(port, data & 0xffu)) - continue; - - tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); - } - - if (start_count != port->icount.rx) { - tty_flip_buffer_push(tty); - } -} - -/** - * mux_startup - Initialize the port. - * @port: Ptr to the uart_port. - * - * Grab any resources needed for this port and start the - * mux timer. - */ -static int mux_startup(struct uart_port *port) -{ - mux_ports[port->line].enabled = 1; - return 0; -} - -/** - * mux_shutdown - Disable the port. - * @port: Ptr to the uart_port. - * - * Release any resources needed for the port. - */ -static void mux_shutdown(struct uart_port *port) -{ - mux_ports[port->line].enabled = 0; -} - -/** - * mux_set_termios - Chane port parameters. - * @port: Ptr to the uart_port. - * @termios: new termios settings. - * @old: old termios settings. - * - * The Serial Mux does not support this function. - */ -static void -mux_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ -} - -/** - * mux_type - Describe the port. - * @port: Ptr to the uart_port. - * - * Return a pointer to a string constant describing the - * specified port. - */ -static const char *mux_type(struct uart_port *port) -{ - return "Mux"; -} - -/** - * mux_release_port - Release memory and IO regions. - * @port: Ptr to the uart_port. - * - * Release any memory and IO region resources currently in use by - * the port. - */ -static void mux_release_port(struct uart_port *port) -{ -} - -/** - * mux_request_port - Request memory and IO regions. - * @port: Ptr to the uart_port. - * - * Request any memory and IO region resources required by the port. - * If any fail, no resources should be registered when this function - * returns, and it should return -EBUSY on failure. - */ -static int mux_request_port(struct uart_port *port) -{ - return 0; -} - -/** - * mux_config_port - Perform port autoconfiguration. - * @port: Ptr to the uart_port. - * @type: Bitmask of required configurations. - * - * Perform any autoconfiguration steps for the port. This function is - * called if the UPF_BOOT_AUTOCONF flag is specified for the port. - * [Note: This is required for now because of a bug in the Serial core. - * rmk has already submitted a patch to linus, should be available for - * 2.5.47.] - */ -static void mux_config_port(struct uart_port *port, int type) -{ - port->type = PORT_MUX; -} - -/** - * mux_verify_port - Verify the port information. - * @port: Ptr to the uart_port. - * @ser: Ptr to the serial information. - * - * Verify the new serial port information contained within serinfo is - * suitable for this port type. - */ -static int mux_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if(port->membase == NULL) - return -EINVAL; - - return 0; -} - -/** - * mux_drv_poll - Mux poll function. - * @unused: Unused variable - * - * This function periodically polls the Serial MUX to check for new data. - */ -static void mux_poll(unsigned long unused) -{ - int i; - - for(i = 0; i < port_cnt; ++i) { - if(!mux_ports[i].enabled) - continue; - - mux_read(&mux_ports[i].port); - mux_write(&mux_ports[i].port); - } - - mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); -} - - -#ifdef CONFIG_SERIAL_MUX_CONSOLE -static void mux_console_write(struct console *co, const char *s, unsigned count) -{ - /* Wait until the FIFO drains. */ - while(UART_GET_FIFO_CNT(&mux_ports[0].port)) - udelay(1); - - while(count--) { - if(*s == '\n') { - UART_PUT_CHAR(&mux_ports[0].port, '\r'); - } - UART_PUT_CHAR(&mux_ports[0].port, *s++); - } - -} - -static int mux_console_setup(struct console *co, char *options) -{ - return 0; -} - -struct tty_driver *mux_console_device(struct console *co, int *index) -{ - *index = co->index; - return mux_driver.tty_driver; -} - -static struct console mux_console = { - .name = "ttyB", - .write = mux_console_write, - .device = mux_console_device, - .setup = mux_console_setup, - .flags = CON_ENABLED | CON_PRINTBUFFER, - .index = 0, -}; - -#define MUX_CONSOLE &mux_console -#else -#define MUX_CONSOLE NULL -#endif - -static struct uart_ops mux_pops = { - .tx_empty = mux_tx_empty, - .set_mctrl = mux_set_mctrl, - .get_mctrl = mux_get_mctrl, - .stop_tx = mux_stop_tx, - .start_tx = mux_start_tx, - .stop_rx = mux_stop_rx, - .enable_ms = mux_enable_ms, - .break_ctl = mux_break_ctl, - .startup = mux_startup, - .shutdown = mux_shutdown, - .set_termios = mux_set_termios, - .type = mux_type, - .release_port = mux_release_port, - .request_port = mux_request_port, - .config_port = mux_config_port, - .verify_port = mux_verify_port, -}; - -/** - * mux_probe - Determine if the Serial Mux should claim this device. - * @dev: The parisc device. - * - * Deterimine if the Serial Mux should claim this chip (return 0) - * or not (return 1). - */ -static int __init mux_probe(struct parisc_device *dev) -{ - int i, status; - - int port_count = get_mux_port_count(dev); - printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count); - - dev_set_drvdata(&dev->dev, (void *)(long)port_count); - request_mem_region(dev->hpa.start + MUX_OFFSET, - port_count * MUX_LINE_OFFSET, "Mux"); - - if(!port_cnt) { - mux_driver.cons = MUX_CONSOLE; - - status = uart_register_driver(&mux_driver); - if(status) { - printk(KERN_ERR "Serial mux: Unable to register driver.\n"); - return 1; - } - } - - for(i = 0; i < port_count; ++i, ++port_cnt) { - struct uart_port *port = &mux_ports[port_cnt].port; - port->iobase = 0; - port->mapbase = dev->hpa.start + MUX_OFFSET + - (i * MUX_LINE_OFFSET); - port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); - port->iotype = UPIO_MEM; - port->type = PORT_MUX; - port->irq = NO_IRQ; - port->uartclk = 0; - port->fifosize = MUX_FIFO_SIZE; - port->ops = &mux_pops; - port->flags = UPF_BOOT_AUTOCONF; - port->line = port_cnt; - - /* The port->timeout needs to match what is present in - * uart_wait_until_sent in serial_core.c. Otherwise - * the time spent in msleep_interruptable will be very - * long, causing the appearance of a console hang. - */ - port->timeout = HZ / 50; - spin_lock_init(&port->lock); - - status = uart_add_one_port(&mux_driver, port); - BUG_ON(status); - } - - return 0; -} - -static int __devexit mux_remove(struct parisc_device *dev) -{ - int i, j; - int port_count = (long)dev_get_drvdata(&dev->dev); - - /* Find Port 0 for this card in the mux_ports list. */ - for(i = 0; i < port_cnt; ++i) { - if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET) - break; - } - BUG_ON(i + port_count > port_cnt); - - /* Release the resources associated with each port on the device. */ - for(j = 0; j < port_count; ++j, ++i) { - struct uart_port *port = &mux_ports[i].port; - - uart_remove_one_port(&mux_driver, port); - if(port->membase) - iounmap(port->membase); - } - - release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET); - return 0; -} - -/* Hack. This idea was taken from the 8250_gsc.c on how to properly order - * the serial port detection in the proper order. The idea is we always - * want the builtin mux to be detected before addin mux cards, so we - * specifically probe for the builtin mux cards first. - * - * This table only contains the parisc_device_id of known builtin mux - * devices. All other mux cards will be detected by the generic mux_tbl. - */ -static struct parisc_device_id builtin_mux_tbl[] = { - { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */ - { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */ - { 0, } -}; - -static struct parisc_device_id mux_tbl[] = { - { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D }, - { 0, } -}; - -MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl); -MODULE_DEVICE_TABLE(parisc, mux_tbl); - -static struct parisc_driver builtin_serial_mux_driver = { - .name = "builtin_serial_mux", - .id_table = builtin_mux_tbl, - .probe = mux_probe, - .remove = __devexit_p(mux_remove), -}; - -static struct parisc_driver serial_mux_driver = { - .name = "serial_mux", - .id_table = mux_tbl, - .probe = mux_probe, - .remove = __devexit_p(mux_remove), -}; - -/** - * mux_init - Serial MUX initialization procedure. - * - * Register the Serial MUX driver. - */ -static int __init mux_init(void) -{ - register_parisc_driver(&builtin_serial_mux_driver); - register_parisc_driver(&serial_mux_driver); - - if(port_cnt > 0) { - /* Start the Mux timer */ - init_timer(&mux_timer); - mux_timer.function = mux_poll; - mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); - -#ifdef CONFIG_SERIAL_MUX_CONSOLE - register_console(&mux_console); -#endif - } - - return 0; -} - -/** - * mux_exit - Serial MUX cleanup procedure. - * - * Unregister the Serial MUX driver from the tty layer. - */ -static void __exit mux_exit(void) -{ - /* Delete the Mux timer. */ - if(port_cnt > 0) { - del_timer(&mux_timer); -#ifdef CONFIG_SERIAL_MUX_CONSOLE - unregister_console(&mux_console); -#endif - } - - unregister_parisc_driver(&builtin_serial_mux_driver); - unregister_parisc_driver(&serial_mux_driver); - uart_unregister_driver(&mux_driver); -} - -module_init(mux_init); -module_exit(mux_exit); - -MODULE_AUTHOR("Ryan Bradetich"); -MODULE_DESCRIPTION("Serial MUX driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR); diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c deleted file mode 100644 index 7735c9f35fa0..000000000000 --- a/drivers/serial/netx-serial.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * drivers/serial/netx-serial.c - * - * Copyright (c) 2005 Sascha Hauer , Pengutronix - * - * 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. - * - * 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 - */ - -#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* We've been assigned a range on the "Low-density serial ports" major */ -#define SERIAL_NX_MAJOR 204 -#define MINOR_START 170 - -enum uart_regs { - UART_DR = 0x00, - UART_SR = 0x04, - UART_LINE_CR = 0x08, - UART_BAUDDIV_MSB = 0x0c, - UART_BAUDDIV_LSB = 0x10, - UART_CR = 0x14, - UART_FR = 0x18, - UART_IIR = 0x1c, - UART_ILPR = 0x20, - UART_RTS_CR = 0x24, - UART_RTS_LEAD = 0x28, - UART_RTS_TRAIL = 0x2c, - UART_DRV_ENABLE = 0x30, - UART_BRM_CR = 0x34, - UART_RXFIFO_IRQLEVEL = 0x38, - UART_TXFIFO_IRQLEVEL = 0x3c, -}; - -#define SR_FE (1<<0) -#define SR_PE (1<<1) -#define SR_BE (1<<2) -#define SR_OE (1<<3) - -#define LINE_CR_BRK (1<<0) -#define LINE_CR_PEN (1<<1) -#define LINE_CR_EPS (1<<2) -#define LINE_CR_STP2 (1<<3) -#define LINE_CR_FEN (1<<4) -#define LINE_CR_5BIT (0<<5) -#define LINE_CR_6BIT (1<<5) -#define LINE_CR_7BIT (2<<5) -#define LINE_CR_8BIT (3<<5) -#define LINE_CR_BITS_MASK (3<<5) - -#define CR_UART_EN (1<<0) -#define CR_SIREN (1<<1) -#define CR_SIRLP (1<<2) -#define CR_MSIE (1<<3) -#define CR_RIE (1<<4) -#define CR_TIE (1<<5) -#define CR_RTIE (1<<6) -#define CR_LBE (1<<7) - -#define FR_CTS (1<<0) -#define FR_DSR (1<<1) -#define FR_DCD (1<<2) -#define FR_BUSY (1<<3) -#define FR_RXFE (1<<4) -#define FR_TXFF (1<<5) -#define FR_RXFF (1<<6) -#define FR_TXFE (1<<7) - -#define IIR_MIS (1<<0) -#define IIR_RIS (1<<1) -#define IIR_TIS (1<<2) -#define IIR_RTIS (1<<3) -#define IIR_MASK 0xf - -#define RTS_CR_AUTO (1<<0) -#define RTS_CR_RTS (1<<1) -#define RTS_CR_COUNT (1<<2) -#define RTS_CR_MOD2 (1<<3) -#define RTS_CR_RTS_POL (1<<4) -#define RTS_CR_CTS_CTR (1<<5) -#define RTS_CR_CTS_POL (1<<6) -#define RTS_CR_STICK (1<<7) - -#define UART_PORT_SIZE 0x40 -#define DRIVER_NAME "netx-uart" - -struct netx_port { - struct uart_port port; -}; - -static void netx_stop_tx(struct uart_port *port) -{ - unsigned int val; - val = readl(port->membase + UART_CR); - writel(val & ~CR_TIE, port->membase + UART_CR); -} - -static void netx_stop_rx(struct uart_port *port) -{ - unsigned int val; - val = readl(port->membase + UART_CR); - writel(val & ~CR_RIE, port->membase + UART_CR); -} - -static void netx_enable_ms(struct uart_port *port) -{ - unsigned int val; - val = readl(port->membase + UART_CR); - writel(val | CR_MSIE, port->membase + UART_CR); -} - -static inline void netx_transmit_buffer(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - writel(port->x_char, port->membase + UART_DR); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { - netx_stop_tx(port); - return; - } - - do { - /* send xmit->buf[xmit->tail] - * out the port here */ - writel(xmit->buf[xmit->tail], port->membase + UART_DR); - xmit->tail = (xmit->tail + 1) & - (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (!(readl(port->membase + UART_FR) & FR_TXFF)); - - if (uart_circ_empty(xmit)) - netx_stop_tx(port); -} - -static void netx_start_tx(struct uart_port *port) -{ - writel( - readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR); - - if (!(readl(port->membase + UART_FR) & FR_TXFF)) - netx_transmit_buffer(port); -} - -static unsigned int netx_tx_empty(struct uart_port *port) -{ - return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT; -} - -static void netx_txint(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - netx_stop_tx(port); - return; - } - - netx_transmit_buffer(port); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static void netx_rxint(struct uart_port *port) -{ - unsigned char rx, flg, status; - struct tty_struct *tty = port->state->port.tty; - - while (!(readl(port->membase + UART_FR) & FR_RXFE)) { - rx = readl(port->membase + UART_DR); - flg = TTY_NORMAL; - port->icount.rx++; - status = readl(port->membase + UART_SR); - if (status & SR_BE) { - writel(0, port->membase + UART_SR); - if (uart_handle_break(port)) - continue; - } - - if (unlikely(status & (SR_FE | SR_PE | SR_OE))) { - - if (status & SR_PE) - port->icount.parity++; - else if (status & SR_FE) - port->icount.frame++; - if (status & SR_OE) - port->icount.overrun++; - - status &= port->read_status_mask; - - if (status & SR_BE) - flg = TTY_BREAK; - else if (status & SR_PE) - flg = TTY_PARITY; - else if (status & SR_FE) - flg = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, rx)) - continue; - - uart_insert_char(port, status, SR_OE, rx, flg); - } - - tty_flip_buffer_push(tty); - return; -} - -static irqreturn_t netx_int(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned long flags; - unsigned char status; - - spin_lock_irqsave(&port->lock,flags); - - status = readl(port->membase + UART_IIR) & IIR_MASK; - while (status) { - if (status & IIR_RIS) - netx_rxint(port); - if (status & IIR_TIS) - netx_txint(port); - if (status & IIR_MIS) { - if (readl(port->membase + UART_FR) & FR_CTS) - uart_handle_cts_change(port, 1); - else - uart_handle_cts_change(port, 0); - } - writel(0, port->membase + UART_IIR); - status = readl(port->membase + UART_IIR) & IIR_MASK; - } - - spin_unlock_irqrestore(&port->lock,flags); - return IRQ_HANDLED; -} - -static unsigned int netx_get_mctrl(struct uart_port *port) -{ - unsigned int ret = TIOCM_DSR | TIOCM_CAR; - - if (readl(port->membase + UART_FR) & FR_CTS) - ret |= TIOCM_CTS; - - return ret; -} - -static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - unsigned int val; - - /* FIXME: Locking needed ? */ - if (mctrl & TIOCM_RTS) { - val = readl(port->membase + UART_RTS_CR); - writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR); - } -} - -static void netx_break_ctl(struct uart_port *port, int break_state) -{ - unsigned int line_cr; - spin_lock_irq(&port->lock); - - line_cr = readl(port->membase + UART_LINE_CR); - if (break_state != 0) - line_cr |= LINE_CR_BRK; - else - line_cr &= ~LINE_CR_BRK; - writel(line_cr, port->membase + UART_LINE_CR); - - spin_unlock_irq(&port->lock); -} - -static int netx_startup(struct uart_port *port) -{ - int ret; - - ret = request_irq(port->irq, netx_int, 0, - DRIVER_NAME, port); - if (ret) { - dev_err(port->dev, "unable to grab irq%d\n",port->irq); - goto exit; - } - - writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN, - port->membase + UART_LINE_CR); - - writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN, - port->membase + UART_CR); - -exit: - return ret; -} - -static void netx_shutdown(struct uart_port *port) -{ - writel(0, port->membase + UART_CR) ; - - free_irq(port->irq, port); -} - -static void -netx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud, quot; - unsigned char old_cr; - unsigned char line_cr = LINE_CR_FEN; - unsigned char rts_cr = 0; - - switch (termios->c_cflag & CSIZE) { - case CS5: - line_cr |= LINE_CR_5BIT; - break; - case CS6: - line_cr |= LINE_CR_6BIT; - break; - case CS7: - line_cr |= LINE_CR_7BIT; - break; - case CS8: - line_cr |= LINE_CR_8BIT; - break; - } - - if (termios->c_cflag & CSTOPB) - line_cr |= LINE_CR_STP2; - - if (termios->c_cflag & PARENB) { - line_cr |= LINE_CR_PEN; - if (!(termios->c_cflag & PARODD)) - line_cr |= LINE_CR_EPS; - } - - if (termios->c_cflag & CRTSCTS) - rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL; - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = baud * 4096; - quot /= 1000; - quot *= 256; - quot /= 100000; - - spin_lock_irq(&port->lock); - - uart_update_timeout(port, termios->c_cflag, baud); - - old_cr = readl(port->membase + UART_CR); - - /* disable interrupts */ - writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE), - port->membase + UART_CR); - - /* drain transmitter */ - while (readl(port->membase + UART_FR) & FR_BUSY); - - /* disable UART */ - writel(old_cr & ~CR_UART_EN, port->membase + UART_CR); - - /* modem status interrupts */ - old_cr &= ~CR_MSIE; - if (UART_ENABLE_MS(port, termios->c_cflag)) - old_cr |= CR_MSIE; - - writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB); - writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB); - writel(line_cr, port->membase + UART_LINE_CR); - - writel(rts_cr, port->membase + UART_RTS_CR); - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= SR_PE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= SR_BE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= SR_PE; - } - - port->read_status_mask = 0; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= SR_BE; - if (termios->c_iflag & INPCK) - port->read_status_mask |= SR_PE | SR_FE; - - writel(old_cr, port->membase + UART_CR); - - spin_unlock_irq(&port->lock); -} - -static const char *netx_type(struct uart_port *port) -{ - return port->type == PORT_NETX ? "NETX" : NULL; -} - -static void netx_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, UART_PORT_SIZE); -} - -static int netx_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, UART_PORT_SIZE, - DRIVER_NAME) != NULL ? 0 : -EBUSY; -} - -static void netx_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0) - port->type = PORT_NETX; -} - -static int -netx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX) - ret = -EINVAL; - - return ret; -} - -static struct uart_ops netx_pops = { - .tx_empty = netx_tx_empty, - .set_mctrl = netx_set_mctrl, - .get_mctrl = netx_get_mctrl, - .stop_tx = netx_stop_tx, - .start_tx = netx_start_tx, - .stop_rx = netx_stop_rx, - .enable_ms = netx_enable_ms, - .break_ctl = netx_break_ctl, - .startup = netx_startup, - .shutdown = netx_shutdown, - .set_termios = netx_set_termios, - .type = netx_type, - .release_port = netx_release_port, - .request_port = netx_request_port, - .config_port = netx_config_port, - .verify_port = netx_verify_port, -}; - -static struct netx_port netx_ports[] = { - { - .port = { - .type = PORT_NETX, - .iotype = UPIO_MEM, - .membase = (char __iomem *)io_p2v(NETX_PA_UART0), - .mapbase = NETX_PA_UART0, - .irq = NETX_IRQ_UART0, - .uartclk = 100000000, - .fifosize = 16, - .flags = UPF_BOOT_AUTOCONF, - .ops = &netx_pops, - .line = 0, - }, - }, { - .port = { - .type = PORT_NETX, - .iotype = UPIO_MEM, - .membase = (char __iomem *)io_p2v(NETX_PA_UART1), - .mapbase = NETX_PA_UART1, - .irq = NETX_IRQ_UART1, - .uartclk = 100000000, - .fifosize = 16, - .flags = UPF_BOOT_AUTOCONF, - .ops = &netx_pops, - .line = 1, - }, - }, { - .port = { - .type = PORT_NETX, - .iotype = UPIO_MEM, - .membase = (char __iomem *)io_p2v(NETX_PA_UART2), - .mapbase = NETX_PA_UART2, - .irq = NETX_IRQ_UART2, - .uartclk = 100000000, - .fifosize = 16, - .flags = UPF_BOOT_AUTOCONF, - .ops = &netx_pops, - .line = 2, - }, - } -}; - -#ifdef CONFIG_SERIAL_NETX_CONSOLE - -static void netx_console_putchar(struct uart_port *port, int ch) -{ - while (readl(port->membase + UART_FR) & FR_BUSY); - writel(ch, port->membase + UART_DR); -} - -static void -netx_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_port *port = &netx_ports[co->index].port; - unsigned char cr_save; - - cr_save = readl(port->membase + UART_CR); - writel(cr_save | CR_UART_EN, port->membase + UART_CR); - - uart_console_write(port, s, count, netx_console_putchar); - - while (readl(port->membase + UART_FR) & FR_BUSY); - writel(cr_save, port->membase + UART_CR); -} - -static void __init -netx_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits, int *flow) -{ - unsigned char line_cr; - - *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) | - readl(port->membase + UART_BAUDDIV_LSB); - *baud *= 1000; - *baud /= 4096; - *baud *= 1000; - *baud /= 256; - *baud *= 100; - - line_cr = readl(port->membase + UART_LINE_CR); - *parity = 'n'; - if (line_cr & LINE_CR_PEN) { - if (line_cr & LINE_CR_EPS) - *parity = 'e'; - else - *parity = 'o'; - } - - switch (line_cr & LINE_CR_BITS_MASK) { - case LINE_CR_8BIT: - *bits = 8; - break; - case LINE_CR_7BIT: - *bits = 7; - break; - case LINE_CR_6BIT: - *bits = 6; - break; - case LINE_CR_5BIT: - *bits = 5; - break; - } - - if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO) - *flow = 'r'; -} - -static int __init -netx_console_setup(struct console *co, char *options) -{ - struct netx_port *sport; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports)) - co->index = 0; - sport = &netx_ports[co->index]; - - if (options) { - uart_parse_options(options, &baud, &parity, &bits, &flow); - } else { - /* if the UART is enabled, assume it has been correctly setup - * by the bootloader and get the options - */ - if (readl(sport->port.membase + UART_CR) & CR_UART_EN) { - netx_console_get_options(&sport->port, &baud, - &parity, &bits, &flow); - } - - } - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver netx_reg; -static struct console netx_console = { - .name = "ttyNX", - .write = netx_console_write, - .device = uart_console_device, - .setup = netx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &netx_reg, -}; - -static int __init netx_console_init(void) -{ - register_console(&netx_console); - return 0; -} -console_initcall(netx_console_init); - -#define NETX_CONSOLE &netx_console -#else -#define NETX_CONSOLE NULL -#endif - -static struct uart_driver netx_reg = { - .owner = THIS_MODULE, - .driver_name = DRIVER_NAME, - .dev_name = "ttyNX", - .major = SERIAL_NX_MAJOR, - .minor = MINOR_START, - .nr = ARRAY_SIZE(netx_ports), - .cons = NETX_CONSOLE, -}; - -static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct netx_port *sport = platform_get_drvdata(pdev); - - if (sport) - uart_suspend_port(&netx_reg, &sport->port); - - return 0; -} - -static int serial_netx_resume(struct platform_device *pdev) -{ - struct netx_port *sport = platform_get_drvdata(pdev); - - if (sport) - uart_resume_port(&netx_reg, &sport->port); - - return 0; -} - -static int serial_netx_probe(struct platform_device *pdev) -{ - struct uart_port *port = &netx_ports[pdev->id].port; - - dev_info(&pdev->dev, "initialising\n"); - - port->dev = &pdev->dev; - - writel(1, port->membase + UART_RXFIFO_IRQLEVEL); - uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port); - platform_set_drvdata(pdev, &netx_ports[pdev->id]); - - return 0; -} - -static int serial_netx_remove(struct platform_device *pdev) -{ - struct netx_port *sport = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (sport) - uart_remove_one_port(&netx_reg, &sport->port); - - return 0; -} - -static struct platform_driver serial_netx_driver = { - .probe = serial_netx_probe, - .remove = serial_netx_remove, - - .suspend = serial_netx_suspend, - .resume = serial_netx_resume, - - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init netx_serial_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: NetX driver\n"); - - ret = uart_register_driver(&netx_reg); - if (ret) - return ret; - - ret = platform_driver_register(&serial_netx_driver); - if (ret != 0) - uart_unregister_driver(&netx_reg); - - return 0; -} - -static void __exit netx_serial_exit(void) -{ - platform_driver_unregister(&serial_netx_driver); - uart_unregister_driver(&netx_reg); -} - -module_init(netx_serial_init); -module_exit(netx_serial_exit); - -MODULE_AUTHOR("Sascha Hauer"); -MODULE_DESCRIPTION("NetX serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c deleted file mode 100644 index de173671e3d0..000000000000 --- a/drivers/serial/nwpserial.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Serial Port driver for a NWP uart device - * - * Copyright (C) 2008 IBM Corp., Benjamin Krill - * - * 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. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NWPSERIAL_NR 2 - -#define NWPSERIAL_STATUS_RXVALID 0x1 -#define NWPSERIAL_STATUS_TXFULL 0x2 - -struct nwpserial_port { - struct uart_port port; - dcr_host_t dcr_host; - unsigned int ier; - unsigned int mcr; -}; - -static DEFINE_MUTEX(nwpserial_mutex); -static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR]; - -static void wait_for_bits(struct nwpserial_port *up, int bits) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = dcr_read(up->dcr_host, UART_LSR); - - if (--tmout == 0) - break; - udelay(1); - } while ((status & bits) != bits); -} - -#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE -static void nwpserial_console_putchar(struct uart_port *port, int c) -{ - struct nwpserial_port *up; - up = container_of(port, struct nwpserial_port, port); - /* check if tx buffer is full */ - wait_for_bits(up, UART_LSR_THRE); - dcr_write(up->dcr_host, UART_TX, c); - up->port.icount.tx++; -} - -static void -nwpserial_console_write(struct console *co, const char *s, unsigned int count) -{ - struct nwpserial_port *up = &nwpserial_ports[co->index]; - unsigned long flags; - int locked = 1; - - if (oops_in_progress) - locked = spin_trylock_irqsave(&up->port.lock, flags); - else - spin_lock_irqsave(&up->port.lock, flags); - - /* save and disable interrupt */ - up->ier = dcr_read(up->dcr_host, UART_IER); - dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI); - - uart_console_write(&up->port, s, count, nwpserial_console_putchar); - - /* wait for transmitter to become empty */ - while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0) - cpu_relax(); - - /* restore interrupt state */ - dcr_write(up->dcr_host, UART_IER, up->ier); - - if (locked) - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static struct uart_driver nwpserial_reg; -static struct console nwpserial_console = { - .name = "ttySQ", - .write = nwpserial_console_write, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &nwpserial_reg, -}; -#define NWPSERIAL_CONSOLE (&nwpserial_console) -#else -#define NWPSERIAL_CONSOLE NULL -#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ - -/**************************************************************************/ - -static int nwpserial_request_port(struct uart_port *port) -{ - return 0; -} - -static void nwpserial_release_port(struct uart_port *port) -{ - /* N/A */ -} - -static void nwpserial_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_NWPSERIAL; -} - -static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) -{ - struct nwpserial_port *up = dev_id; - struct tty_struct *tty = up->port.state->port.tty; - irqreturn_t ret; - unsigned int iir; - unsigned char ch; - - spin_lock(&up->port.lock); - - /* check if the uart was the interrupt source. */ - iir = dcr_read(up->dcr_host, UART_IIR); - if (!iir) { - ret = IRQ_NONE; - goto out; - } - - do { - up->port.icount.rx++; - ch = dcr_read(up->dcr_host, UART_RX); - if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) - tty_insert_flip_char(tty, ch, TTY_NORMAL); - } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR); - - tty_flip_buffer_push(tty); - ret = IRQ_HANDLED; - - /* clear interrupt */ - dcr_write(up->dcr_host, UART_IIR, 1); -out: - spin_unlock(&up->port.lock); - return ret; -} - -static int nwpserial_startup(struct uart_port *port) -{ - struct nwpserial_port *up; - int err; - - up = container_of(port, struct nwpserial_port, port); - - /* disable flow control by default */ - up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE; - dcr_write(up->dcr_host, UART_MCR, up->mcr); - - /* register interrupt handler */ - err = request_irq(up->port.irq, nwpserial_interrupt, - IRQF_SHARED, "nwpserial", up); - if (err) - return err; - - /* enable interrupts */ - up->ier = UART_IER_RDI; - dcr_write(up->dcr_host, UART_IER, up->ier); - - /* enable receiving */ - up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID; - - return 0; -} - -static void nwpserial_shutdown(struct uart_port *port) -{ - struct nwpserial_port *up; - up = container_of(port, struct nwpserial_port, port); - - /* disable receiving */ - up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; - - /* disable interrupts from this port */ - up->ier = 0; - dcr_write(up->dcr_host, UART_IER, up->ier); - - /* free irq */ - free_irq(up->port.irq, port); -} - -static int nwpserial_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - return -EINVAL; -} - -static const char *nwpserial_type(struct uart_port *port) -{ - return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL; -} - -static void nwpserial_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - struct nwpserial_port *up; - up = container_of(port, struct nwpserial_port, port); - - up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID - | NWPSERIAL_STATUS_TXFULL; - - up->port.ignore_status_mask = 0; - /* ignore all characters if CREAD is not set */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; - - /* Copy back the old hardware settings */ - if (old) - tty_termios_copy_hw(termios, old); -} - -static void nwpserial_break_ctl(struct uart_port *port, int ctl) -{ - /* N/A */ -} - -static void nwpserial_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - -static void nwpserial_stop_rx(struct uart_port *port) -{ - struct nwpserial_port *up; - up = container_of(port, struct nwpserial_port, port); - /* don't forward any more data (like !CREAD) */ - up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID; -} - -static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c) -{ - /* check if tx buffer is full */ - wait_for_bits(up, UART_LSR_THRE); - dcr_write(up->dcr_host, UART_TX, c); - up->port.icount.tx++; -} - -static void nwpserial_start_tx(struct uart_port *port) -{ - struct nwpserial_port *up; - struct circ_buf *xmit; - up = container_of(port, struct nwpserial_port, port); - xmit = &up->port.state->xmit; - - if (port->x_char) { - nwpserial_putchar(up, up->port.x_char); - port->x_char = 0; - } - - while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) { - nwpserial_putchar(up, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); - } -} - -static unsigned int nwpserial_get_mctrl(struct uart_port *port) -{ - return 0; -} - -static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* N/A */ -} - -static void nwpserial_stop_tx(struct uart_port *port) -{ - /* N/A */ -} - -static unsigned int nwpserial_tx_empty(struct uart_port *port) -{ - struct nwpserial_port *up; - unsigned long flags; - int ret; - up = container_of(port, struct nwpserial_port, port); - - spin_lock_irqsave(&up->port.lock, flags); - ret = dcr_read(up->dcr_host, UART_LSR); - spin_unlock_irqrestore(&up->port.lock, flags); - - return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0; -} - -static struct uart_ops nwpserial_pops = { - .tx_empty = nwpserial_tx_empty, - .set_mctrl = nwpserial_set_mctrl, - .get_mctrl = nwpserial_get_mctrl, - .stop_tx = nwpserial_stop_tx, - .start_tx = nwpserial_start_tx, - .stop_rx = nwpserial_stop_rx, - .enable_ms = nwpserial_enable_ms, - .break_ctl = nwpserial_break_ctl, - .startup = nwpserial_startup, - .shutdown = nwpserial_shutdown, - .set_termios = nwpserial_set_termios, - .type = nwpserial_type, - .release_port = nwpserial_release_port, - .request_port = nwpserial_request_port, - .config_port = nwpserial_config_port, - .verify_port = nwpserial_verify_port, -}; - -static struct uart_driver nwpserial_reg = { - .owner = THIS_MODULE, - .driver_name = "nwpserial", - .dev_name = "ttySQ", - .major = TTY_MAJOR, - .minor = 68, - .nr = NWPSERIAL_NR, - .cons = NWPSERIAL_CONSOLE, -}; - -int nwpserial_register_port(struct uart_port *port) -{ - struct nwpserial_port *up = NULL; - int ret = -1; - int i; - static int first = 1; - int dcr_len; - int dcr_base; - struct device_node *dn; - - mutex_lock(&nwpserial_mutex); - - dn = port->dev->of_node; - if (dn == NULL) - goto out; - - /* get dcr base. */ - dcr_base = dcr_resource_start(dn, 0); - - /* find matching entry */ - for (i = 0; i < NWPSERIAL_NR; i++) - if (nwpserial_ports[i].port.iobase == dcr_base) { - up = &nwpserial_ports[i]; - break; - } - - /* we didn't find a mtching entry, search for a free port */ - if (up == NULL) - for (i = 0; i < NWPSERIAL_NR; i++) - if (nwpserial_ports[i].port.type == PORT_UNKNOWN && - nwpserial_ports[i].port.iobase == 0) { - up = &nwpserial_ports[i]; - break; - } - - if (up == NULL) { - ret = -EBUSY; - goto out; - } - - if (first) - uart_register_driver(&nwpserial_reg); - first = 0; - - up->port.membase = port->membase; - up->port.irq = port->irq; - up->port.uartclk = port->uartclk; - up->port.fifosize = port->fifosize; - up->port.regshift = port->regshift; - up->port.iotype = port->iotype; - up->port.flags = port->flags; - up->port.mapbase = port->mapbase; - up->port.private_data = port->private_data; - - if (port->dev) - up->port.dev = port->dev; - - if (up->port.iobase != dcr_base) { - up->port.ops = &nwpserial_pops; - up->port.fifosize = 16; - - spin_lock_init(&up->port.lock); - - up->port.iobase = dcr_base; - dcr_len = dcr_resource_len(dn, 0); - - up->dcr_host = dcr_map(dn, dcr_base, dcr_len); - if (!DCR_MAP_OK(up->dcr_host)) { - printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL"); - goto out; - } - } - - ret = uart_add_one_port(&nwpserial_reg, &up->port); - if (ret == 0) - ret = up->port.line; - -out: - mutex_unlock(&nwpserial_mutex); - - return ret; -} -EXPORT_SYMBOL(nwpserial_register_port); - -void nwpserial_unregister_port(int line) -{ - struct nwpserial_port *up = &nwpserial_ports[line]; - mutex_lock(&nwpserial_mutex); - uart_remove_one_port(&nwpserial_reg, &up->port); - - up->port.type = PORT_UNKNOWN; - - mutex_unlock(&nwpserial_mutex); -} -EXPORT_SYMBOL(nwpserial_unregister_port); - -#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE -static int __init nwpserial_console_init(void) -{ - struct nwpserial_port *up = NULL; - struct device_node *dn; - const char *name; - int dcr_base; - int dcr_len; - int i; - - /* search for a free port */ - for (i = 0; i < NWPSERIAL_NR; i++) - if (nwpserial_ports[i].port.type == PORT_UNKNOWN) { - up = &nwpserial_ports[i]; - break; - } - - if (up == NULL) - return -1; - - name = of_get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) - return -1; - - dn = of_find_node_by_path(name); - if (!dn) - return -1; - - spin_lock_init(&up->port.lock); - up->port.ops = &nwpserial_pops; - up->port.type = PORT_NWPSERIAL; - up->port.fifosize = 16; - - dcr_base = dcr_resource_start(dn, 0); - dcr_len = dcr_resource_len(dn, 0); - up->port.iobase = dcr_base; - - up->dcr_host = dcr_map(dn, dcr_base, dcr_len); - if (!DCR_MAP_OK(up->dcr_host)) { - printk("Cannot map DCR resources for SERIAL"); - return -1; - } - register_console(&nwpserial_console); - return 0; -} -console_initcall(nwpserial_console_init); -#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c deleted file mode 100644 index 5c7abe4c94dd..000000000000 --- a/drivers/serial/of_serial.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Serial Port driver for Open Firmware platform devices - * - * Copyright (C) 2006 Arnd Bergmann , IBM Corp. - * - * 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. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct of_serial_info { - int type; - int line; -}; - -/* - * Fill a struct uart_port for a given device node - */ -static int __devinit of_platform_serial_setup(struct platform_device *ofdev, - int type, struct uart_port *port) -{ - struct resource resource; - struct device_node *np = ofdev->dev.of_node; - const __be32 *clk, *spd; - const __be32 *prop; - int ret, prop_size; - - memset(port, 0, sizeof *port); - spd = of_get_property(np, "current-speed", NULL); - clk = of_get_property(np, "clock-frequency", NULL); - if (!clk) { - dev_warn(&ofdev->dev, "no clock-frequency property set\n"); - return -ENODEV; - } - - ret = of_address_to_resource(np, 0, &resource); - if (ret) { - dev_warn(&ofdev->dev, "invalid address\n"); - return ret; - } - - spin_lock_init(&port->lock); - port->mapbase = resource.start; - - /* Check for shifted address mapping */ - prop = of_get_property(np, "reg-offset", &prop_size); - if (prop && (prop_size == sizeof(u32))) - port->mapbase += be32_to_cpup(prop); - - /* Check for registers offset within the devices address range */ - prop = of_get_property(np, "reg-shift", &prop_size); - if (prop && (prop_size == sizeof(u32))) - port->regshift = be32_to_cpup(prop); - - port->irq = irq_of_parse_and_map(np, 0); - port->iotype = UPIO_MEM; - port->type = type; - port->uartclk = be32_to_cpup(clk); - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP - | UPF_FIXED_PORT | UPF_FIXED_TYPE; - port->dev = &ofdev->dev; - /* If current-speed was set, then try not to change it. */ - if (spd) - port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd))); - - return 0; -} - -/* - * Try to register a serial port - */ -static int __devinit of_platform_serial_probe(struct platform_device *ofdev, - const struct of_device_id *id) -{ - struct of_serial_info *info; - struct uart_port port; - int port_type; - int ret; - - if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) - return -EBUSY; - - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - - port_type = (unsigned long)id->data; - ret = of_platform_serial_setup(ofdev, port_type, &port); - if (ret) - goto out; - - switch (port_type) { -#ifdef CONFIG_SERIAL_8250 - case PORT_8250 ... PORT_MAX_8250: - ret = serial8250_register_port(&port); - break; -#endif -#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL - case PORT_NWPSERIAL: - ret = nwpserial_register_port(&port); - break; -#endif - default: - /* need to add code for these */ - case PORT_UNKNOWN: - dev_info(&ofdev->dev, "Unknown serial port found, ignored\n"); - ret = -ENODEV; - break; - } - if (ret < 0) - goto out; - - info->type = port_type; - info->line = ret; - dev_set_drvdata(&ofdev->dev, info); - return 0; -out: - kfree(info); - irq_dispose_mapping(port.irq); - return ret; -} - -/* - * Release a line - */ -static int of_platform_serial_remove(struct platform_device *ofdev) -{ - struct of_serial_info *info = dev_get_drvdata(&ofdev->dev); - switch (info->type) { -#ifdef CONFIG_SERIAL_8250 - case PORT_8250 ... PORT_MAX_8250: - serial8250_unregister_port(info->line); - break; -#endif -#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL - case PORT_NWPSERIAL: - nwpserial_unregister_port(info->line); - break; -#endif - default: - /* need to add code for these */ - break; - } - kfree(info); - return 0; -} - -/* - * A few common types, add more as needed. - */ -static struct of_device_id __devinitdata of_platform_serial_table[] = { - { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, }, - { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, }, - { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, }, - { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, }, - { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, }, - { .type = "serial", .compatible = "ns16850", .data = (void *)PORT_16850, }, -#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL - { .type = "serial", .compatible = "ibm,qpace-nwp-serial", - .data = (void *)PORT_NWPSERIAL, }, -#endif - { .type = "serial", .data = (void *)PORT_UNKNOWN, }, - { /* end of list */ }, -}; - -static struct of_platform_driver of_platform_serial_driver = { - .driver = { - .name = "of_serial", - .owner = THIS_MODULE, - .of_match_table = of_platform_serial_table, - }, - .probe = of_platform_serial_probe, - .remove = of_platform_serial_remove, -}; - -static int __init of_platform_serial_init(void) -{ - return of_register_platform_driver(&of_platform_serial_driver); -} -module_init(of_platform_serial_init); - -static void __exit of_platform_serial_exit(void) -{ - return of_unregister_platform_driver(&of_platform_serial_driver); -}; -module_exit(of_platform_serial_exit); - -MODULE_AUTHOR("Arnd Bergmann "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices"); diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c deleted file mode 100644 index 7f2f01058789..000000000000 --- a/drivers/serial/omap-serial.c +++ /dev/null @@ -1,1359 +0,0 @@ -/* - * Driver for OMAP-UART controller. - * Based on drivers/serial/8250.c - * - * Copyright (C) 2010 Texas Instruments. - * - * Authors: - * Govindraj R - * Thara Gopinath - * - * 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. - * - * Note: This driver is made seperate from 8250 driver as we cannot - * over load 8250 driver with omap platform specific configuration for - * features like DMA, it makes easier to implement features like DMA and - * hardware flow control and software flow control configuration with - * this driver as required for the omap-platform. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -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_rx_timeout(unsigned long uart_no); -static int serial_omap_start_rxdma(struct uart_omap_port *up); - -static inline unsigned int serial_in(struct uart_omap_port *up, int offset) -{ - offset <<= up->port.regshift; - return readw(up->port.membase + offset); -} - -static inline void serial_out(struct uart_omap_port *up, int offset, int value) -{ - offset <<= up->port.regshift; - writew(value, up->port.membase + offset); -} - -static inline void serial_omap_clear_fifos(struct uart_omap_port *up) -{ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); -} - -/* - * serial_omap_get_divisor - calculate divisor value - * @port: uart port info - * @baud: baudrate for which divisor needs to be calculated. - * - * We have written our own function to get the divisor so as to support - * 13x mode. 3Mbps Baudrate as an different divisor. - * Reference OMAP TRM Chapter 17: - * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates - * referring to oversampling - divisor value - * baudrate 460,800 to 3,686,400 all have divisor 13 - * except 3,000,000 which has divisor value 16 - */ -static unsigned int -serial_omap_get_divisor(struct uart_port *port, unsigned int baud) -{ - unsigned int divisor; - - if (baud > OMAP_MODE13X_SPEED && baud != 3000000) - divisor = 13; - else - divisor = 16; - 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; - } -} - -static void serial_omap_enable_ms(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - - dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id); - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void serial_omap_stop_tx(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - - 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; - } - - if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_omap_stop_rx(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - - 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); -} - -static inline void receive_chars(struct uart_omap_port *up, int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned int flag; - unsigned char ch, lsr = *status; - 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; - up->lsr_break_flag = 0; - } -#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; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_omap_stop_tx(&up->port); - return; - } - count = up->port.fifosize / 4; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_omap_stop_tx(&up->port); -} - -static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) -{ - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_omap_start_tx(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - struct circ_buf *xmit; - unsigned int start; - int ret = 0; - - if (!up->use_dma) { - serial_omap_enable_ier_thri(up); - 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) { - 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); -} - -static unsigned int check_modem_status(struct uart_omap_port *up) -{ - unsigned int status; - - status = serial_in(up, UART_MSR); - status |= up->msr_saved_flags; - up->msr_saved_flags = 0; - if ((status & UART_MSR_ANY_DELTA) == 0) - return status; - - if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - up->port.state != NULL) { - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change - (&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change - (&up->port, status & UART_MSR_CTS); - wake_up_interruptible(&up->port.state->port.delta_msr_wait); - } - - return status; -} - -/** - * serial_omap_irq() - This handles the interrupt from one port - * @irq: uart port irq number - * @dev_id: uart port info - */ -static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) -{ - struct uart_omap_port *up = dev_id; - unsigned int iir, lsr; - unsigned long flags; - - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) - return IRQ_NONE; - - 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); - } - } - - check_modem_status(up); - if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - up->port_activity = jiffies; - return IRQ_HANDLED; -} - -static unsigned int serial_omap_tx_empty(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned long flags = 0; - unsigned int ret = 0; - - dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id); - 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); - - return ret; -} - -static unsigned int serial_omap_get_mctrl(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned char status; - unsigned int ret = 0; - - status = check_modem_status(up); - dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id); - - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned char mcr = 0; - - dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id); - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr |= up->mcr; - serial_out(up, UART_MCR, mcr); -} - -static void serial_omap_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned long flags = 0; - - dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id); - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static int serial_omap_startup(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned long flags = 0; - int retval; - - /* - * Allocate the IRQ - */ - retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags, - up->name, up); - if (retval) - return retval; - - dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id); - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial_omap_clear_fifos(up); - /* For Hardware flow control */ - serial_out(up, UART_MCR, UART_MCR_RTS); - - /* - * Clear the interrupt registers. - */ - (void) serial_in(up, UART_LSR); - if (serial_in(up, UART_LSR) & UART_LSR_DR) - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - /* - * Now, initialize the UART - */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); - spin_lock_irqsave(&up->port.lock, flags); - /* - * Most PC uarts need OUT2 raised to enable interrupts. - */ - up->port.mctrl |= TIOCM_OUT2; - serial_omap_set_mctrl(&up->port, up->port.mctrl); - 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_rx_timeout; - up->uart_dma.rx_timer.data = up->pdev->id; - /* 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 - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_out(up, UART_IER, up->ier); - - up->port_activity = jiffies; - return 0; -} - -static void serial_omap_shutdown(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned long flags = 0; - - dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id); - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_out(up, UART_IER, 0); - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - serial_omap_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); - serial_omap_clear_fifos(up); - - /* - * Read data port to reset things, and then free the irq - */ - 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; - } - free_irq(up->port.irq, up); -} - -static inline void -serial_omap_configure_xonxoff - (struct uart_omap_port *up, struct ktermios *termios) -{ - unsigned char efr = 0; - - up->lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); - serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB); - - serial_out(up, UART_XON1, termios->c_cc[VSTART]); - serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); - - /* clear SW control mode bits */ - efr = up->efr; - efr &= OMAP_UART_SW_CLR; - - /* - * IXON Flag: - * Enable XON/XOFF flow control on output. - * Transmit XON1, XOFF1 - */ - if (termios->c_iflag & IXON) - efr |= OMAP_UART_SW_TX; - - /* - * IXOFF Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. - */ - if (termios->c_iflag & IXOFF) - efr |= OMAP_UART_SW_RX; - - serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - - up->mcr = serial_in(up, UART_MCR); - - /* - * IXANY Flag: - * Enable any character to restart output. - * Operation resumes after receiving any - * character after recognition of the XOFF character - */ - if (termios->c_iflag & IXANY) - up->mcr |= UART_MCR_XONANY; - - serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - /* Enable special char function UARTi.EFR_REG[5] and - * load the new software flow control mode IXON or IXOFF - * and restore the UARTi.EFR_REG[4] ENHANCED_EN value. - */ - serial_out(up, UART_EFR, efr | UART_EFR_SCD); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - - serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); - serial_out(up, UART_LCR, up->lcr); -} - -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; - unsigned char cval = 0; - unsigned char efr = 0; - unsigned long flags = 0; - unsigned int baud, quot; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * Ask the core to calculate the divisor for us. - */ - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); - quot = serial_omap_get_divisor(port, baud); - - 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 - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* - * Characters to ignore - */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * Modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); - serial_out(up, UART_LCR, cval); /* reset DLAB */ - - /* FIFOs and DMA Settings */ - - /* FCR can be changed only when the - * baud clock is not running - * DLL_REG and DLH_REG set to 0. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_DLL, 0); - serial_out(up, UART_DLM, 0); - serial_out(up, UART_LCR, 0); - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - up->efr = serial_in(up, UART_EFR); - serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - up->mcr = serial_in(up, UART_MCR); - serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); - /* FIFO ENABLE, DMA MODE */ - serial_out(up, UART_FCR, up->fcr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - if (up->use_dma) { - serial_out(up, UART_TI752_TLR, 0); - serial_out(up, UART_OMAP_SCR, - (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8)); - } - - serial_out(up, UART_EFR, up->efr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_MCR, up->mcr); - - /* Protocol, Baud Rate, and Interrupt Settings */ - - serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - up->efr = serial_in(up, UART_EFR); - serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); - - serial_out(up, UART_LCR, 0); - serial_out(up, UART_IER, 0); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ - - serial_out(up, UART_LCR, 0); - serial_out(up, UART_IER, up->ier); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - serial_out(up, UART_EFR, up->efr); - serial_out(up, UART_LCR, cval); - - if (baud > 230400 && baud != 3000000) - serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE); - else - serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE); - - /* Hardware Flow Control Configuration */ - - if (termios->c_cflag & CRTSCTS) { - efr |= (UART_EFR_CTS | UART_EFR_RTS); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - - up->mcr = serial_in(up, UART_MCR); - serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - up->efr = serial_in(up, UART_EFR); - serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); - - serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); - serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); - serial_out(up, UART_LCR, cval); - } - - serial_omap_set_mctrl(&up->port, up->port.mctrl); - /* Software Flow Control Configuration */ - if (termios->c_iflag & (IXON | IXOFF)) - serial_omap_configure_xonxoff(up, termios); - - spin_unlock_irqrestore(&up->port.lock, flags); - dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id); -} - -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; - unsigned char efr; - - dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id); - 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); - serial_out(up, UART_LCR, 0); - - serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, efr); - serial_out(up, UART_LCR, 0); - /* Enable module level wake up */ - serial_out(up, UART_OMAP_WER, - (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0); -} - -static void serial_omap_release_port(struct uart_port *port) -{ - dev_dbg(port->dev, "serial_omap_release_port+\n"); -} - -static int serial_omap_request_port(struct uart_port *port) -{ - dev_dbg(port->dev, "serial_omap_request_port+\n"); - return 0; -} - -static void serial_omap_config_port(struct uart_port *port, int flags) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - - dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", - up->pdev->id); - up->port.type = PORT_OMAP; -} - -static int -serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* we don't want the core code to modify any port params */ - dev_dbg(port->dev, "serial_omap_verify_port+\n"); - return -EINVAL; -} - -static const char * -serial_omap_type(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - - dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id); - return up->name; -} - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static inline void wait_for_xmitr(struct uart_omap_port *up) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - for (tmout = 1000000; tmout; tmout--) { - unsigned int msr = serial_in(up, UART_MSR); - - up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; - if (msr & UART_MSR_CTS) - break; - - udelay(1); - } - } -} - -#ifdef CONFIG_CONSOLE_POLL - -static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -static int serial_omap_poll_get_char(struct uart_port *port) -{ - struct uart_omap_port *up = (struct uart_omap_port *)port; - unsigned int status = serial_in(up, UART_LSR); - - if (!(status & UART_LSR_DR)) - return NO_POLL_CHAR; - - return serial_in(up, UART_RX); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -#ifdef CONFIG_SERIAL_OMAP_CONSOLE - -static struct uart_omap_port *serial_omap_console_ports[4]; - -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; - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -static void -serial_omap_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_omap_port *up = serial_omap_console_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - 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 - */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, serial_omap_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - /* - * The receive handling will happen properly because the - * receive ready bit will still be set; it is not cleared - * on read. However, modem control will not, we must - * call it if we have saved something in the saved flags - * while processing with interrupts off. - */ - if (up->msr_saved_flags) - check_modem_status(up); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static int __init -serial_omap_console_setup(struct console *co, char *options) -{ - struct uart_omap_port *up; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (serial_omap_console_ports[co->index] == NULL) - return -ENODEV; - up = serial_omap_console_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&up->port, co, baud, parity, bits, flow); -} - -static struct console serial_omap_console = { - .name = OMAP_SERIAL_NAME, - .write = serial_omap_console_write, - .device = uart_console_device, - .setup = serial_omap_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_omap_reg, -}; - -static void serial_omap_add_console_port(struct uart_omap_port *up) -{ - serial_omap_console_ports[up->pdev->id] = up; -} - -#define OMAP_CONSOLE (&serial_omap_console) - -#else - -#define OMAP_CONSOLE NULL - -static inline void serial_omap_add_console_port(struct uart_omap_port *up) -{} - -#endif - -static struct uart_ops serial_omap_pops = { - .tx_empty = serial_omap_tx_empty, - .set_mctrl = serial_omap_set_mctrl, - .get_mctrl = serial_omap_get_mctrl, - .stop_tx = serial_omap_stop_tx, - .start_tx = serial_omap_start_tx, - .stop_rx = serial_omap_stop_rx, - .enable_ms = serial_omap_enable_ms, - .break_ctl = serial_omap_break_ctl, - .startup = serial_omap_startup, - .shutdown = serial_omap_shutdown, - .set_termios = serial_omap_set_termios, - .pm = serial_omap_pm, - .type = serial_omap_type, - .release_port = serial_omap_release_port, - .request_port = serial_omap_request_port, - .config_port = serial_omap_config_port, - .verify_port = serial_omap_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_put_char = serial_omap_poll_put_char, - .poll_get_char = serial_omap_poll_get_char, -#endif -}; - -static struct uart_driver serial_omap_reg = { - .owner = THIS_MODULE, - .driver_name = "OMAP-SERIAL", - .dev_name = OMAP_SERIAL_NAME, - .nr = OMAP_MAX_HSUART_PORTS, - .cons = OMAP_CONSOLE, -}; - -static int -serial_omap_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct uart_omap_port *up = platform_get_drvdata(pdev); - - if (up) - uart_suspend_port(&serial_omap_reg, &up->port); - return 0; -} - -static int serial_omap_resume(struct platform_device *dev) -{ - struct uart_omap_port *up = platform_get_drvdata(dev); - - if (up) - uart_resume_port(&serial_omap_reg, &up->port); - return 0; -} - -static void serial_omap_rx_timeout(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) < - RX_TIMEOUT) { - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_timeout)); - } 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_timeout)); - } - 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) { - 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_timeout)); - 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 = (struct uart_omap_port *)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 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; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; - } - - if (!request_mem_region(mem->start, (mem->end - mem->start) + 1, - pdev->dev.driver->name)) { - dev_err(&pdev->dev, "memory region already claimed\n"); - return -EBUSY; - } - - dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!dma_rx) { - ret = -EINVAL; - goto err; - } - - dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!dma_tx) { - ret = -EINVAL; - goto err; - } - - up = kzalloc(sizeof(*up), GFP_KERNEL); - if (up == NULL) { - ret = -ENOMEM; - goto do_release_region; - } - sprintf(up->name, "OMAP UART%d", pdev->id); - up->pdev = pdev; - up->port.dev = &pdev->dev; - up->port.type = PORT_OMAP; - up->port.iotype = UPIO_MEM; - up->port.irq = irq->start; - - up->port.regshift = 2; - up->port.fifosize = 64; - up->port.ops = &serial_omap_pops; - up->port.line = pdev->id; - - up->port.membase = omap_up_info->membase; - up->port.mapbase = omap_up_info->mapbase; - up->port.flags = omap_up_info->flags; - up->port.irqflags = omap_up_info->irqflags; - up->port.uartclk = omap_up_info->uartclk; - 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 = 4096; - up->uart_dma.rx_timeout = 2; - 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; - } - - ui[pdev->id] = up; - serial_omap_add_console_port(up); - - ret = uart_add_one_port(&serial_omap_reg, &up->port); - if (ret != 0) - goto do_release_region; - - platform_set_drvdata(pdev, up); - return 0; -err: - dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", - pdev->id, __func__, ret); -do_release_region: - release_mem_region(mem->start, (mem->end - mem->start) + 1); - return ret; -} - -static int serial_omap_remove(struct platform_device *dev) -{ - struct uart_omap_port *up = platform_get_drvdata(dev); - - platform_set_drvdata(dev, NULL); - if (up) { - uart_remove_one_port(&serial_omap_reg, &up->port); - kfree(up); - } - return 0; -} - -static struct platform_driver serial_omap_driver = { - .probe = serial_omap_probe, - .remove = serial_omap_remove, - - .suspend = serial_omap_suspend, - .resume = serial_omap_resume, - .driver = { - .name = DRIVER_NAME, - }, -}; - -static int __init serial_omap_init(void) -{ - int ret; - - ret = uart_register_driver(&serial_omap_reg); - if (ret != 0) - return ret; - ret = platform_driver_register(&serial_omap_driver); - if (ret != 0) - uart_unregister_driver(&serial_omap_reg); - return ret; -} - -static void __exit serial_omap_exit(void) -{ - platform_driver_unregister(&serial_omap_driver); - uart_unregister_driver(&serial_omap_reg); -} - -module_init(serial_omap_init); -module_exit(serial_omap_exit); - -MODULE_DESCRIPTION("OMAP High Speed UART driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/drivers/serial/pch_uart.c b/drivers/serial/pch_uart.c deleted file mode 100644 index 70a61458ec42..000000000000 --- a/drivers/serial/pch_uart.c +++ /dev/null @@ -1,1451 +0,0 @@ -/* - *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. - * - *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; version 2 of the License. - * - *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 - -enum { - PCH_UART_HANDLED_RX_INT_SHIFT, - PCH_UART_HANDLED_TX_INT_SHIFT, - PCH_UART_HANDLED_RX_ERR_INT_SHIFT, - PCH_UART_HANDLED_RX_TRG_INT_SHIFT, - PCH_UART_HANDLED_MS_INT_SHIFT, -}; - -enum { - PCH_UART_8LINE, - PCH_UART_2LINE, -}; - -#define PCH_UART_DRIVER_DEVICE "ttyPCH" - -#define PCH_UART_NR_GE_256FIFO 1 -#define PCH_UART_NR_GE_64FIFO 3 -#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO) -#define PCH_UART_NR PCH_UART_NR_GE - -#define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1)) -#define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1)) -#define PCH_UART_HANDLED_RX_ERR_INT (1<<((\ - PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1)) -#define PCH_UART_HANDLED_RX_TRG_INT (1<<((\ - PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) -#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) - -#define PCH_UART_RBR 0x00 -#define PCH_UART_THR 0x00 - -#define PCH_UART_IER_MASK (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\ - PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI) -#define PCH_UART_IER_ERBFI 0x00000001 -#define PCH_UART_IER_ETBEI 0x00000002 -#define PCH_UART_IER_ELSI 0x00000004 -#define PCH_UART_IER_EDSSI 0x00000008 - -#define PCH_UART_IIR_IP 0x00000001 -#define PCH_UART_IIR_IID 0x00000006 -#define PCH_UART_IIR_MSI 0x00000000 -#define PCH_UART_IIR_TRI 0x00000002 -#define PCH_UART_IIR_RRI 0x00000004 -#define PCH_UART_IIR_REI 0x00000006 -#define PCH_UART_IIR_TOI 0x00000008 -#define PCH_UART_IIR_FIFO256 0x00000020 -#define PCH_UART_IIR_FIFO64 PCH_UART_IIR_FIFO256 -#define PCH_UART_IIR_FE 0x000000C0 - -#define PCH_UART_FCR_FIFOE 0x00000001 -#define PCH_UART_FCR_RFR 0x00000002 -#define PCH_UART_FCR_TFR 0x00000004 -#define PCH_UART_FCR_DMS 0x00000008 -#define PCH_UART_FCR_FIFO256 0x00000020 -#define PCH_UART_FCR_RFTL 0x000000C0 - -#define PCH_UART_FCR_RFTL1 0x00000000 -#define PCH_UART_FCR_RFTL64 0x00000040 -#define PCH_UART_FCR_RFTL128 0x00000080 -#define PCH_UART_FCR_RFTL224 0x000000C0 -#define PCH_UART_FCR_RFTL16 PCH_UART_FCR_RFTL64 -#define PCH_UART_FCR_RFTL32 PCH_UART_FCR_RFTL128 -#define PCH_UART_FCR_RFTL56 PCH_UART_FCR_RFTL224 -#define PCH_UART_FCR_RFTL4 PCH_UART_FCR_RFTL64 -#define PCH_UART_FCR_RFTL8 PCH_UART_FCR_RFTL128 -#define PCH_UART_FCR_RFTL14 PCH_UART_FCR_RFTL224 -#define PCH_UART_FCR_RFTL_SHIFT 6 - -#define PCH_UART_LCR_WLS 0x00000003 -#define PCH_UART_LCR_STB 0x00000004 -#define PCH_UART_LCR_PEN 0x00000008 -#define PCH_UART_LCR_EPS 0x00000010 -#define PCH_UART_LCR_SP 0x00000020 -#define PCH_UART_LCR_SB 0x00000040 -#define PCH_UART_LCR_DLAB 0x00000080 -#define PCH_UART_LCR_NP 0x00000000 -#define PCH_UART_LCR_OP PCH_UART_LCR_PEN -#define PCH_UART_LCR_EP (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS) -#define PCH_UART_LCR_1P (PCH_UART_LCR_PEN | PCH_UART_LCR_SP) -#define PCH_UART_LCR_0P (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\ - PCH_UART_LCR_SP) - -#define PCH_UART_LCR_5BIT 0x00000000 -#define PCH_UART_LCR_6BIT 0x00000001 -#define PCH_UART_LCR_7BIT 0x00000002 -#define PCH_UART_LCR_8BIT 0x00000003 - -#define PCH_UART_MCR_DTR 0x00000001 -#define PCH_UART_MCR_RTS 0x00000002 -#define PCH_UART_MCR_OUT 0x0000000C -#define PCH_UART_MCR_LOOP 0x00000010 -#define PCH_UART_MCR_AFE 0x00000020 - -#define PCH_UART_LSR_DR 0x00000001 -#define PCH_UART_LSR_ERR (1<<7) - -#define PCH_UART_MSR_DCTS 0x00000001 -#define PCH_UART_MSR_DDSR 0x00000002 -#define PCH_UART_MSR_TERI 0x00000004 -#define PCH_UART_MSR_DDCD 0x00000008 -#define PCH_UART_MSR_CTS 0x00000010 -#define PCH_UART_MSR_DSR 0x00000020 -#define PCH_UART_MSR_RI 0x00000040 -#define PCH_UART_MSR_DCD 0x00000080 -#define PCH_UART_MSR_DELTA (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\ - PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD) - -#define PCH_UART_DLL 0x00 -#define PCH_UART_DLM 0x01 - -#define DIV_ROUND(a, b) (((a) + ((b)/2)) / (b)) - -#define PCH_UART_IID_RLS (PCH_UART_IIR_REI) -#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI) -#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI) -#define PCH_UART_IID_THRE (PCH_UART_IIR_TRI) -#define PCH_UART_IID_MS (PCH_UART_IIR_MSI) - -#define PCH_UART_HAL_PARITY_NONE (PCH_UART_LCR_NP) -#define PCH_UART_HAL_PARITY_ODD (PCH_UART_LCR_OP) -#define PCH_UART_HAL_PARITY_EVEN (PCH_UART_LCR_EP) -#define PCH_UART_HAL_PARITY_FIX1 (PCH_UART_LCR_1P) -#define PCH_UART_HAL_PARITY_FIX0 (PCH_UART_LCR_0P) -#define PCH_UART_HAL_5BIT (PCH_UART_LCR_5BIT) -#define PCH_UART_HAL_6BIT (PCH_UART_LCR_6BIT) -#define PCH_UART_HAL_7BIT (PCH_UART_LCR_7BIT) -#define PCH_UART_HAL_8BIT (PCH_UART_LCR_8BIT) -#define PCH_UART_HAL_STB1 0 -#define PCH_UART_HAL_STB2 (PCH_UART_LCR_STB) - -#define PCH_UART_HAL_CLR_TX_FIFO (PCH_UART_FCR_TFR) -#define PCH_UART_HAL_CLR_RX_FIFO (PCH_UART_FCR_RFR) -#define PCH_UART_HAL_CLR_ALL_FIFO (PCH_UART_HAL_CLR_TX_FIFO | \ - PCH_UART_HAL_CLR_RX_FIFO) - -#define PCH_UART_HAL_DMA_MODE0 0 -#define PCH_UART_HAL_FIFO_DIS 0 -#define PCH_UART_HAL_FIFO16 (PCH_UART_FCR_FIFOE) -#define PCH_UART_HAL_FIFO256 (PCH_UART_FCR_FIFOE | \ - PCH_UART_FCR_FIFO256) -#define PCH_UART_HAL_FIFO64 (PCH_UART_HAL_FIFO256) -#define PCH_UART_HAL_TRIGGER1 (PCH_UART_FCR_RFTL1) -#define PCH_UART_HAL_TRIGGER64 (PCH_UART_FCR_RFTL64) -#define PCH_UART_HAL_TRIGGER128 (PCH_UART_FCR_RFTL128) -#define PCH_UART_HAL_TRIGGER224 (PCH_UART_FCR_RFTL224) -#define PCH_UART_HAL_TRIGGER16 (PCH_UART_FCR_RFTL16) -#define PCH_UART_HAL_TRIGGER32 (PCH_UART_FCR_RFTL32) -#define PCH_UART_HAL_TRIGGER56 (PCH_UART_FCR_RFTL56) -#define PCH_UART_HAL_TRIGGER4 (PCH_UART_FCR_RFTL4) -#define PCH_UART_HAL_TRIGGER8 (PCH_UART_FCR_RFTL8) -#define PCH_UART_HAL_TRIGGER14 (PCH_UART_FCR_RFTL14) -#define PCH_UART_HAL_TRIGGER_L (PCH_UART_FCR_RFTL64) -#define PCH_UART_HAL_TRIGGER_M (PCH_UART_FCR_RFTL128) -#define PCH_UART_HAL_TRIGGER_H (PCH_UART_FCR_RFTL224) - -#define PCH_UART_HAL_RX_INT (PCH_UART_IER_ERBFI) -#define PCH_UART_HAL_TX_INT (PCH_UART_IER_ETBEI) -#define PCH_UART_HAL_RX_ERR_INT (PCH_UART_IER_ELSI) -#define PCH_UART_HAL_MS_INT (PCH_UART_IER_EDSSI) -#define PCH_UART_HAL_ALL_INT (PCH_UART_IER_MASK) - -#define PCH_UART_HAL_DTR (PCH_UART_MCR_DTR) -#define PCH_UART_HAL_RTS (PCH_UART_MCR_RTS) -#define PCH_UART_HAL_OUT (PCH_UART_MCR_OUT) -#define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) -#define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) - -struct pch_uart_buffer { - unsigned char *buf; - int size; -}; - -struct eg20t_port { - struct uart_port port; - int port_type; - void __iomem *membase; - resource_size_t mapbase; - unsigned int iobase; - struct pci_dev *pdev; - int fifo_size; - int base_baud; - int start_tx; - int start_rx; - int tx_empty; - int int_dis_flag; - int trigger; - int trigger_level; - struct pch_uart_buffer rxbuf; - unsigned int dmsr; - unsigned int fcr; - unsigned int use_dma; - unsigned int use_dma_flag; - struct dma_async_tx_descriptor *desc_tx; - struct dma_async_tx_descriptor *desc_rx; - struct pch_dma_slave param_tx; - struct pch_dma_slave param_rx; - struct dma_chan *chan_tx; - struct dma_chan *chan_rx; - struct scatterlist sg_tx; - struct scatterlist sg_rx; - int tx_dma_use; - void *rx_buf_virt; - dma_addr_t rx_buf_dma; -}; - -static unsigned int default_baud = 9600; -static const int trigger_level_256[4] = { 1, 64, 128, 224 }; -static const int trigger_level_64[4] = { 1, 16, 32, 56 }; -static const int trigger_level_16[4] = { 1, 4, 8, 14 }; -static const int trigger_level_1[4] = { 1, 1, 1, 1 }; - -static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, - int base_baud) -{ - struct eg20t_port *priv = pci_get_drvdata(pdev); - - priv->trigger_level = 1; - priv->fcr = 0; -} - -static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base) -{ - unsigned int msr = ioread8(base + UART_MSR); - priv->dmsr |= msr & PCH_UART_MSR_DELTA; - - return msr; -} - -static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, - unsigned int flag) -{ - u8 ier = ioread8(priv->membase + UART_IER); - ier |= flag & PCH_UART_IER_MASK; - iowrite8(ier, priv->membase + UART_IER); -} - -static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv, - unsigned int flag) -{ - u8 ier = ioread8(priv->membase + UART_IER); - ier &= ~(flag & PCH_UART_IER_MASK); - iowrite8(ier, priv->membase + UART_IER); -} - -static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud, - unsigned int parity, unsigned int bits, - unsigned int stb) -{ - unsigned int dll, dlm, lcr; - int div; - - div = DIV_ROUND(priv->base_baud / 16, baud); - if (div < 0 || USHRT_MAX <= div) { - pr_err("Invalid Baud(div=0x%x)\n", div); - return -EINVAL; - } - - dll = (unsigned int)div & 0x00FFU; - dlm = ((unsigned int)div >> 8) & 0x00FFU; - - if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) { - pr_err("Invalid parity(0x%x)\n", parity); - return -EINVAL; - } - - if (bits & ~PCH_UART_LCR_WLS) { - pr_err("Invalid bits(0x%x)\n", bits); - return -EINVAL; - } - - if (stb & ~PCH_UART_LCR_STB) { - pr_err("Invalid STB(0x%x)\n", stb); - return -EINVAL; - } - - lcr = parity; - lcr |= bits; - lcr |= stb; - - pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n", - __func__, baud, div, lcr, jiffies); - iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); - iowrite8(dll, priv->membase + PCH_UART_DLL); - iowrite8(dlm, priv->membase + PCH_UART_DLM); - iowrite8(lcr, priv->membase + UART_LCR); - - return 0; -} - -static int pch_uart_hal_fifo_reset(struct eg20t_port *priv, - unsigned int flag) -{ - if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) { - pr_err("%s:Invalid flag(0x%x)\n", __func__, flag); - return -EINVAL; - } - - iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR); - iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag, - priv->membase + UART_FCR); - iowrite8(priv->fcr, priv->membase + UART_FCR); - - return 0; -} - -static int pch_uart_hal_set_fifo(struct eg20t_port *priv, - unsigned int dmamode, - unsigned int fifo_size, unsigned int trigger) -{ - u8 fcr; - - if (dmamode & ~PCH_UART_FCR_DMS) { - pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode); - return -EINVAL; - } - - if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) { - pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size); - return -EINVAL; - } - - if (trigger & ~PCH_UART_FCR_RFTL) { - pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger); - return -EINVAL; - } - - switch (priv->fifo_size) { - case 256: - priv->trigger_level = - trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT]; - break; - case 64: - priv->trigger_level = - trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT]; - break; - case 16: - priv->trigger_level = - trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT]; - break; - default: - priv->trigger_level = - trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT]; - break; - } - fcr = - dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR; - iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR); - iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR, - priv->membase + UART_FCR); - iowrite8(fcr, priv->membase + UART_FCR); - priv->fcr = fcr; - - return 0; -} - -static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) -{ - priv->dmsr = 0; - return get_msr(priv, priv->membase); -} - -static int pch_uart_hal_write(struct eg20t_port *priv, - const unsigned char *buf, int tx_size) -{ - int i; - unsigned int thr; - - for (i = 0; i < tx_size;) { - thr = buf[i++]; - iowrite8(thr, priv->membase + PCH_UART_THR); - } - return i; -} - -static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, - int rx_size) -{ - int i; - u8 rbr, lsr; - - lsr = ioread8(priv->membase + UART_LSR); - for (i = 0, lsr = ioread8(priv->membase + UART_LSR); - i < rx_size && lsr & UART_LSR_DR; - lsr = ioread8(priv->membase + UART_LSR)) { - rbr = ioread8(priv->membase + PCH_UART_RBR); - buf[i++] = rbr; - } - return i; -} - -static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) -{ - unsigned int iir; - int ret; - - iir = ioread8(priv->membase + UART_IIR); - ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); - return ret; -} - -static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) -{ - return ioread8(priv->membase + UART_LSR); -} - -static void pch_uart_hal_set_break(struct eg20t_port *priv, int on) -{ - unsigned int lcr; - - lcr = ioread8(priv->membase + UART_LCR); - if (on) - lcr |= PCH_UART_LCR_SB; - else - lcr &= ~PCH_UART_LCR_SB; - - iowrite8(lcr, priv->membase + UART_LCR); -} - -static int push_rx(struct eg20t_port *priv, const unsigned char *buf, - int size) -{ - struct uart_port *port; - struct tty_struct *tty; - - port = &priv->port; - tty = tty_port_tty_get(&port->state->port); - if (!tty) { - pr_debug("%s:tty is busy now", __func__); - return -EBUSY; - } - - tty_insert_flip_string(tty, buf, size); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - - return 0; -} - -static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) -{ - int ret; - struct uart_port *port = &priv->port; - - if (port->x_char) { - pr_debug("%s:X character send %02x (%lu)\n", __func__, - port->x_char, jiffies); - buf[0] = port->x_char; - port->x_char = 0; - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -static int dma_push_rx(struct eg20t_port *priv, int size) -{ - struct tty_struct *tty; - int room; - struct uart_port *port = &priv->port; - - port = &priv->port; - tty = tty_port_tty_get(&port->state->port); - if (!tty) { - pr_debug("%s:tty is busy now", __func__); - return 0; - } - - room = tty_buffer_request_room(tty, size); - - if (room < size) - dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", - size - room); - if (!room) - return room; - - tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size); - - port->icount.rx += room; - tty_kref_put(tty); - - return room; -} - -static void pch_free_dma(struct uart_port *port) -{ - struct eg20t_port *priv; - priv = container_of(port, struct eg20t_port, port); - - if (priv->chan_tx) { - dma_release_channel(priv->chan_tx); - priv->chan_tx = NULL; - } - if (priv->chan_rx) { - dma_release_channel(priv->chan_rx); - priv->chan_rx = NULL; - } - if (sg_dma_address(&priv->sg_rx)) - dma_free_coherent(port->dev, port->fifosize, - sg_virt(&priv->sg_rx), - sg_dma_address(&priv->sg_rx)); - - return; -} - -static bool filter(struct dma_chan *chan, void *slave) -{ - struct pch_dma_slave *param = slave; - - if ((chan->chan_id == param->chan_id) && (param->dma_dev == - chan->device->dev)) { - chan->private = param; - return true; - } else { - return false; - } -} - -static void pch_request_dma(struct uart_port *port) -{ - dma_cap_mask_t mask; - struct dma_chan *chan; - struct pci_dev *dma_dev; - struct pch_dma_slave *param; - struct eg20t_port *priv = - container_of(port, struct eg20t_port, port); - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev - information */ - /* Set Tx DMA */ - param = &priv->param_tx; - param->dma_dev = &dma_dev->dev; - param->chan_id = priv->port.line; - param->tx_reg = port->mapbase + UART_TX; - chan = dma_request_channel(mask, filter, param); - if (!chan) { - pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__); - return; - } - priv->chan_tx = chan; - - /* Set Rx DMA */ - param = &priv->param_rx; - param->dma_dev = &dma_dev->dev; - param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */ - param->rx_reg = port->mapbase + UART_RX; - chan = dma_request_channel(mask, filter, param); - if (!chan) { - pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__); - dma_release_channel(priv->chan_tx); - return; - } - - /* Get Consistent memory for DMA */ - priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize, - &priv->rx_buf_dma, GFP_KERNEL); - priv->chan_rx = chan; -} - -static void pch_dma_rx_complete(void *arg) -{ - struct eg20t_port *priv = arg; - struct uart_port *port = &priv->port; - struct tty_struct *tty = tty_port_tty_get(&port->state->port); - - if (!tty) { - pr_debug("%s:tty is busy now", __func__); - return; - } - - if (dma_push_rx(priv, priv->trigger_level)) - tty_flip_buffer_push(tty); - - tty_kref_put(tty); -} - -static void pch_dma_tx_complete(void *arg) -{ - struct eg20t_port *priv = arg; - struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; - - xmit->tail += sg_dma_len(&priv->sg_tx); - xmit->tail &= UART_XMIT_SIZE - 1; - port->icount.tx += sg_dma_len(&priv->sg_tx); - - async_tx_ack(priv->desc_tx); - priv->tx_dma_use = 0; -} - -static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size) -{ - int count = 0; - struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; - - if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size) - goto pop_tx_end; - - do { - int cnt_to_end = - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - int sz = min(size - count, cnt_to_end); - memcpy(&buf[count], &xmit->buf[xmit->tail], sz); - xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1); - count += sz; - } while (!uart_circ_empty(xmit) && count < size); - -pop_tx_end: - pr_debug("%d characters. Remained %d characters. (%lu)\n", - count, size - count, jiffies); - - return count; -} - -static int handle_rx_to(struct eg20t_port *priv) -{ - struct pch_uart_buffer *buf; - int rx_size; - int ret; - if (!priv->start_rx) { - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); - return 0; - } - buf = &priv->rxbuf; - do { - rx_size = pch_uart_hal_read(priv, buf->buf, buf->size); - ret = push_rx(priv, buf->buf, rx_size); - if (ret) - return 0; - } while (rx_size == buf->size); - - return PCH_UART_HANDLED_RX_INT; -} - -static int handle_rx(struct eg20t_port *priv) -{ - return handle_rx_to(priv); -} - -static int dma_handle_rx(struct eg20t_port *priv) -{ - struct uart_port *port = &priv->port; - struct dma_async_tx_descriptor *desc; - struct scatterlist *sg; - - priv = container_of(port, struct eg20t_port, port); - sg = &priv->sg_rx; - - sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */ - - sg_dma_len(sg) = priv->fifo_size; - - sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt), - sg_dma_len(sg), (unsigned long)priv->rx_buf_virt & - ~PAGE_MASK); - - sg_dma_address(sg) = priv->rx_buf_dma; - - desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx, - sg, 1, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT); - if (!desc) - return 0; - - priv->desc_rx = desc; - desc->callback = pch_dma_rx_complete; - desc->callback_param = priv; - desc->tx_submit(desc); - dma_async_issue_pending(priv->chan_rx); - - return PCH_UART_HANDLED_RX_INT; -} - -static unsigned int handle_tx(struct eg20t_port *priv) -{ - struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; - int ret; - int fifo_size; - int tx_size; - int size; - int tx_empty; - - if (!priv->start_tx) { - pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies); - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); - priv->tx_empty = 1; - return 0; - } - - fifo_size = max(priv->fifo_size, 1); - tx_empty = 1; - if (pop_tx_x(priv, xmit->buf)) { - pch_uart_hal_write(priv, xmit->buf, 1); - port->icount.tx++; - tx_empty = 0; - fifo_size--; - } - size = min(xmit->head - xmit->tail, fifo_size); - tx_size = pop_tx(priv, xmit->buf, size); - if (tx_size > 0) { - ret = pch_uart_hal_write(priv, xmit->buf, tx_size); - port->icount.tx += ret; - tx_empty = 0; - } - - priv->tx_empty = tx_empty; - - if (tx_empty) - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); - - return PCH_UART_HANDLED_TX_INT; -} - -static unsigned int dma_handle_tx(struct eg20t_port *priv) -{ - struct uart_port *port = &priv->port; - struct circ_buf *xmit = &port->state->xmit; - struct scatterlist *sg = &priv->sg_tx; - int nent; - int fifo_size; - int tx_empty; - struct dma_async_tx_descriptor *desc; - - if (!priv->start_tx) { - pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies); - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); - priv->tx_empty = 1; - return 0; - } - - fifo_size = max(priv->fifo_size, 1); - tx_empty = 1; - if (pop_tx_x(priv, xmit->buf)) { - pch_uart_hal_write(priv, xmit->buf, 1); - port->icount.tx++; - tx_empty = 0; - fifo_size--; - } - - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); - - priv->tx_dma_use = 1; - - sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */ - - sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf), - UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK); - - nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE); - if (!nent) { - pr_err("%s:dma_map_sg Failed\n", __func__); - return 0; - } - - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + - sg->offset; - sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, - UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, - xmit->tail, UART_XMIT_SIZE)); - - desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx, - sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("%s:device_prep_slave_sg Failed\n", __func__); - return 0; - } - - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); - - priv->desc_tx = desc; - desc->callback = pch_dma_tx_complete; - desc->callback_param = priv; - - desc->tx_submit(desc); - - dma_async_issue_pending(priv->chan_tx); - - return PCH_UART_HANDLED_TX_INT; -} - -static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr) -{ - u8 fcr = ioread8(priv->membase + UART_FCR); - - /* Reset FIFO */ - fcr |= UART_FCR_CLEAR_RCVR; - iowrite8(fcr, priv->membase + UART_FCR); - - if (lsr & PCH_UART_LSR_ERR) - dev_err(&priv->pdev->dev, "Error data in FIFO\n"); - - if (lsr & UART_LSR_FE) - dev_err(&priv->pdev->dev, "Framing Error\n"); - - if (lsr & UART_LSR_PE) - dev_err(&priv->pdev->dev, "Parity Error\n"); - - if (lsr & UART_LSR_OE) - dev_err(&priv->pdev->dev, "Overrun Error\n"); -} - -static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) -{ - struct eg20t_port *priv = dev_id; - unsigned int handled; - u8 lsr; - int ret = 0; - unsigned int iid; - unsigned long flags; - - spin_lock_irqsave(&priv->port.lock, flags); - handled = 0; - while ((iid = pch_uart_hal_get_iid(priv)) > 1) { - switch (iid) { - case PCH_UART_IID_RLS: /* Receiver Line Status */ - lsr = pch_uart_hal_get_line_status(priv); - if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE | - UART_LSR_PE | UART_LSR_OE)) { - pch_uart_err_ir(priv, lsr); - ret = PCH_UART_HANDLED_RX_ERR_INT; - } - break; - case PCH_UART_IID_RDR: /* Received Data Ready */ - if (priv->use_dma) - ret = dma_handle_rx(priv); - else - ret = handle_rx(priv); - break; - case PCH_UART_IID_RDR_TO: /* Received Data Ready - (FIFO Timeout) */ - ret = handle_rx_to(priv); - break; - case PCH_UART_IID_THRE: /* Transmitter Holding Register - Empty */ - if (priv->use_dma) - ret = dma_handle_tx(priv); - else - ret = handle_tx(priv); - break; - case PCH_UART_IID_MS: /* Modem Status */ - ret = PCH_UART_HANDLED_MS_INT; - break; - default: /* Never junp to this label */ - pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies); - ret = -1; - break; - } - handled |= (unsigned int)ret; - } - if (handled == 0 && iid <= 1) { - if (priv->int_dis_flag) - priv->int_dis_flag = 0; - } - - spin_unlock_irqrestore(&priv->port.lock, flags); - return IRQ_RETVAL(handled); -} - -/* This function tests whether the transmitter fifo and shifter for the port - described by 'port' is empty. */ -static unsigned int pch_uart_tx_empty(struct uart_port *port) -{ - struct eg20t_port *priv; - int ret; - priv = container_of(port, struct eg20t_port, port); - if (priv->tx_empty) - ret = TIOCSER_TEMT; - else - ret = 0; - - return ret; -} - -/* Returns the current state of modem control inputs. */ -static unsigned int pch_uart_get_mctrl(struct uart_port *port) -{ - struct eg20t_port *priv; - u8 modem; - unsigned int ret = 0; - - priv = container_of(port, struct eg20t_port, port); - modem = pch_uart_hal_get_modem(priv); - - if (modem & UART_MSR_DCD) - ret |= TIOCM_CAR; - - if (modem & UART_MSR_RI) - ret |= TIOCM_RNG; - - if (modem & UART_MSR_DSR) - ret |= TIOCM_DSR; - - if (modem & UART_MSR_CTS) - ret |= TIOCM_CTS; - - return ret; -} - -static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - u32 mcr = 0; - unsigned int dat; - struct eg20t_port *priv = container_of(port, struct eg20t_port, port); - - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - if (mctrl) { - dat = pch_uart_get_mctrl(port); - dat |= mcr; - iowrite8(dat, priv->membase + UART_MCR); - } -} - -static void pch_uart_stop_tx(struct uart_port *port) -{ - struct eg20t_port *priv; - priv = container_of(port, struct eg20t_port, port); - priv->start_tx = 0; - priv->tx_dma_use = 0; -} - -static void pch_uart_start_tx(struct uart_port *port) -{ - struct eg20t_port *priv; - - priv = container_of(port, struct eg20t_port, port); - - if (priv->use_dma) - if (priv->tx_dma_use) - return; - - priv->start_tx = 1; - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); -} - -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); - priv->int_dis_flag = 1; -} - -/* Enable the modem status interrupts. */ -static void pch_uart_enable_ms(struct uart_port *port) -{ - struct eg20t_port *priv; - priv = container_of(port, struct eg20t_port, port); - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT); -} - -/* Control the transmission of a break signal. */ -static void pch_uart_break_ctl(struct uart_port *port, int ctl) -{ - struct eg20t_port *priv; - unsigned long flags; - - priv = container_of(port, struct eg20t_port, port); - spin_lock_irqsave(&port->lock, flags); - pch_uart_hal_set_break(priv, ctl); - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Grab any interrupt resources and initialise any low level driver state. */ -static int pch_uart_startup(struct uart_port *port) -{ - struct eg20t_port *priv; - int ret; - int fifo_size; - int trigger_level; - - priv = container_of(port, struct eg20t_port, port); - priv->tx_empty = 1; - port->uartclk = priv->base_baud; - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); - ret = pch_uart_hal_set_line(priv, default_baud, - PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT, - PCH_UART_HAL_STB1); - if (ret) - return ret; - - switch (priv->fifo_size) { - case 256: - fifo_size = PCH_UART_HAL_FIFO256; - break; - case 64: - fifo_size = PCH_UART_HAL_FIFO64; - break; - case 16: - fifo_size = PCH_UART_HAL_FIFO16; - case 1: - default: - fifo_size = PCH_UART_HAL_FIFO_DIS; - break; - } - - switch (priv->trigger) { - case PCH_UART_HAL_TRIGGER1: - trigger_level = 1; - break; - case PCH_UART_HAL_TRIGGER_L: - trigger_level = priv->fifo_size / 4; - break; - case PCH_UART_HAL_TRIGGER_M: - trigger_level = priv->fifo_size / 2; - break; - case PCH_UART_HAL_TRIGGER_H: - default: - trigger_level = priv->fifo_size - (priv->fifo_size / 8); - break; - } - - priv->trigger_level = trigger_level; - ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0, - fifo_size, priv->trigger); - if (ret < 0) - return ret; - - ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED, - KBUILD_MODNAME, priv); - if (ret < 0) - return ret; - - if (priv->use_dma) - pch_request_dma(port); - - priv->start_rx = 1; - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); - uart_update_timeout(port, CS8, default_baud); - - return 0; -} - -static void pch_uart_shutdown(struct uart_port *port) -{ - struct eg20t_port *priv; - int ret; - - priv = container_of(port, struct eg20t_port, port); - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); - pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO); - ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0, - PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1); - if (ret) - pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); - - if (priv->use_dma_flag) - pch_free_dma(port); - - free_irq(priv->port.irq, priv); -} - -/* Change the port parameters, including word length, parity, stop - *bits. Update read_status_mask and ignore_status_mask to indicate - *the types of events we are interested in receiving. */ -static void pch_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - int baud; - int rtn; - unsigned int parity, bits, stb; - struct eg20t_port *priv; - unsigned long flags; - - priv = container_of(port, struct eg20t_port, port); - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = PCH_UART_HAL_5BIT; - break; - case CS6: - bits = PCH_UART_HAL_6BIT; - break; - case CS7: - bits = PCH_UART_HAL_7BIT; - break; - default: /* CS8 */ - bits = PCH_UART_HAL_8BIT; - break; - } - if (termios->c_cflag & CSTOPB) - stb = PCH_UART_HAL_STB2; - else - stb = PCH_UART_HAL_STB1; - - if (termios->c_cflag & PARENB) { - if (!(termios->c_cflag & PARODD)) - parity = PCH_UART_HAL_PARITY_ODD; - else - parity = PCH_UART_HAL_PARITY_EVEN; - - } else { - parity = PCH_UART_HAL_PARITY_NONE; - } - termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - - spin_lock_irqsave(&port->lock, flags); - - uart_update_timeout(port, termios->c_cflag, baud); - rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); - if (rtn) - goto out; - - /* Don't rewrite B0 */ - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); - -out: - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *pch_uart_type(struct uart_port *port) -{ - return KBUILD_MODNAME; -} - -static void pch_uart_release_port(struct uart_port *port) -{ - struct eg20t_port *priv; - - priv = container_of(port, struct eg20t_port, port); - pci_iounmap(priv->pdev, priv->membase); - pci_release_regions(priv->pdev); -} - -static int pch_uart_request_port(struct uart_port *port) -{ - struct eg20t_port *priv; - int ret; - void __iomem *membase; - - priv = container_of(port, struct eg20t_port, port); - ret = pci_request_regions(priv->pdev, KBUILD_MODNAME); - if (ret < 0) - return -EBUSY; - - membase = pci_iomap(priv->pdev, 1, 0); - if (!membase) { - pci_release_regions(priv->pdev); - return -EBUSY; - } - priv->membase = port->membase = membase; - - return 0; -} - -static void pch_uart_config_port(struct uart_port *port, int type) -{ - struct eg20t_port *priv; - - priv = container_of(port, struct eg20t_port, port); - if (type & UART_CONFIG_TYPE) { - port->type = priv->port_type; - pch_uart_request_port(port); - } -} - -static int pch_uart_verify_port(struct uart_port *port, - struct serial_struct *serinfo) -{ - struct eg20t_port *priv; - - priv = container_of(port, struct eg20t_port, port); - if (serinfo->flags & UPF_LOW_LATENCY) { - pr_info("PCH UART : Use PIO Mode (without DMA)\n"); - priv->use_dma = 0; - serinfo->flags &= ~UPF_LOW_LATENCY; - } else { -#ifndef CONFIG_PCH_DMA - pr_err("%s : PCH DMA is not Loaded.\n", __func__); - return -EOPNOTSUPP; -#endif - priv->use_dma = 1; - priv->use_dma_flag = 1; - pr_info("PCH UART : Use DMA Mode\n"); - } - - return 0; -} - -static struct uart_ops pch_uart_ops = { - .tx_empty = pch_uart_tx_empty, - .set_mctrl = pch_uart_set_mctrl, - .get_mctrl = pch_uart_get_mctrl, - .stop_tx = pch_uart_stop_tx, - .start_tx = pch_uart_start_tx, - .stop_rx = pch_uart_stop_rx, - .enable_ms = pch_uart_enable_ms, - .break_ctl = pch_uart_break_ctl, - .startup = pch_uart_startup, - .shutdown = pch_uart_shutdown, - .set_termios = pch_uart_set_termios, -/* .pm = pch_uart_pm, Not supported yet */ -/* .set_wake = pch_uart_set_wake, Not supported yet */ - .type = pch_uart_type, - .release_port = pch_uart_release_port, - .request_port = pch_uart_request_port, - .config_port = pch_uart_config_port, - .verify_port = pch_uart_verify_port -}; - -static struct uart_driver pch_uart_driver = { - .owner = THIS_MODULE, - .driver_name = KBUILD_MODNAME, - .dev_name = PCH_UART_DRIVER_DEVICE, - .major = 0, - .minor = 0, - .nr = PCH_UART_NR, -}; - -static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, - int port_type) -{ - struct eg20t_port *priv; - int ret; - unsigned int iobase; - unsigned int mapbase; - unsigned char *rxbuf; - int fifosize, base_baud; - static int num; - - priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL); - if (priv == NULL) - goto init_port_alloc_err; - - rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); - if (!rxbuf) - goto init_port_free_txbuf; - - switch (port_type) { - case PORT_UNKNOWN: - fifosize = 256; /* UART0 */ - base_baud = 1843200; /* 1.8432MHz */ - break; - case PORT_8250: - fifosize = 64; /* UART1~3 */ - base_baud = 1843200; /* 1.8432MHz */ - break; - default: - dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type); - goto init_port_hal_free; - } - - iobase = pci_resource_start(pdev, 0); - mapbase = pci_resource_start(pdev, 1); - priv->mapbase = mapbase; - priv->iobase = iobase; - priv->pdev = pdev; - priv->tx_empty = 1; - priv->rxbuf.buf = rxbuf; - priv->rxbuf.size = PAGE_SIZE; - - priv->fifo_size = fifosize; - priv->base_baud = base_baud; - priv->port_type = PORT_MAX_8250 + port_type + 1; - priv->port.dev = &pdev->dev; - priv->port.iobase = iobase; - priv->port.membase = NULL; - priv->port.mapbase = mapbase; - priv->port.irq = pdev->irq; - priv->port.iotype = UPIO_PORT; - priv->port.ops = &pch_uart_ops; - priv->port.flags = UPF_BOOT_AUTOCONF; - priv->port.fifosize = fifosize; - priv->port.line = num++; - priv->trigger = PCH_UART_HAL_TRIGGER_M; - - pci_set_drvdata(pdev, priv); - pch_uart_hal_request(pdev, fifosize, base_baud); - ret = uart_add_one_port(&pch_uart_driver, &priv->port); - if (ret < 0) - goto init_port_hal_free; - - return priv; - -init_port_hal_free: - free_page((unsigned long)rxbuf); -init_port_free_txbuf: - kfree(priv); -init_port_alloc_err: - - return NULL; -} - -static void pch_uart_exit_port(struct eg20t_port *priv) -{ - uart_remove_one_port(&pch_uart_driver, &priv->port); - pci_set_drvdata(priv->pdev, NULL); - free_page((unsigned long)priv->rxbuf.buf); -} - -static void pch_uart_pci_remove(struct pci_dev *pdev) -{ - struct eg20t_port *priv; - - priv = (struct eg20t_port *)pci_get_drvdata(pdev); - pch_uart_exit_port(priv); - pci_disable_device(pdev); - kfree(priv); - return; -} -#ifdef CONFIG_PM -static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct eg20t_port *priv = pci_get_drvdata(pdev); - - uart_suspend_port(&pch_uart_driver, &priv->port); - - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int pch_uart_pci_resume(struct pci_dev *pdev) -{ - struct eg20t_port *priv = pci_get_drvdata(pdev); - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, - "%s-pci_enable_device failed(ret=%d) ", __func__, ret); - return ret; - } - - uart_resume_port(&pch_uart_driver, &priv->port); - - return 0; -} -#else -#define pch_uart_pci_suspend NULL -#define pch_uart_pci_resume NULL -#endif - -static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811), - .driver_data = PCH_UART_8LINE}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812), - .driver_data = PCH_UART_2LINE}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813), - .driver_data = PCH_UART_2LINE}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814), - .driver_data = PCH_UART_2LINE}, - {0,}, -}; - -static int __devinit pch_uart_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int ret; - struct eg20t_port *priv; - - ret = pci_enable_device(pdev); - if (ret < 0) - goto probe_error; - - priv = pch_uart_init_port(pdev, id->driver_data); - if (!priv) { - ret = -EBUSY; - goto probe_disable_device; - } - pci_set_drvdata(pdev, priv); - - return ret; - -probe_disable_device: - pci_disable_device(pdev); -probe_error: - return ret; -} - -static struct pci_driver pch_uart_pci_driver = { - .name = "pch_uart", - .id_table = pch_uart_pci_id, - .probe = pch_uart_pci_probe, - .remove = __devexit_p(pch_uart_pci_remove), - .suspend = pch_uart_pci_suspend, - .resume = pch_uart_pci_resume, -}; - -static int __init pch_uart_module_init(void) -{ - int ret; - - /* register as UART driver */ - ret = uart_register_driver(&pch_uart_driver); - if (ret < 0) - return ret; - - /* register as PCI driver */ - ret = pci_register_driver(&pch_uart_pci_driver); - if (ret < 0) - uart_unregister_driver(&pch_uart_driver); - - return ret; -} -module_init(pch_uart_module_init); - -static void __exit pch_uart_module_exit(void) -{ - pci_unregister_driver(&pch_uart_pci_driver); - uart_unregister_driver(&pch_uart_driver); -} -module_exit(pch_uart_module_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); -module_param(default_baud, uint, S_IRUGO); diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c deleted file mode 100644 index 5b9cde79e4ea..000000000000 --- a/drivers/serial/pmac_zilog.c +++ /dev/null @@ -1,2208 +0,0 @@ -/* - * linux/drivers/serial/pmac_zilog.c - * - * Driver for PowerMac Z85c30 based ESCC cell found in the - * "macio" ASICs of various PowerMac models - * - * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * Derived from drivers/macintosh/macserial.c by Paul Mackerras - * and drivers/serial/sunzilog.c by David S. Miller - * - * Hrm... actually, I ripped most of sunzilog (Thanks David !) and - * adapted special tweaks needed for us. I don't think it's worth - * merging back those though. The DMA code still has to get in - * and once done, I expect that driver to remain fairly stable in - * the long term, unless we change the driver model again... - * - * 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 - * - * 2004-08-06 Harald Welte - * - Enable BREAK interrupt - * - Add support for sysreq - * - * TODO: - Add DMA support - * - Defer port shutdown to a few seconds after close - * - maybe put something right into uap->clk_divisor - */ - -#undef DEBUG -#undef DEBUG_HARD -#undef USE_CTRL_O_SYSRQ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_PPC_PMAC -#include -#include -#include -#include -#include -#else -#include -#define of_machine_is_compatible(x) (0) -#endif - -#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include - -#include "pmac_zilog.h" - -/* Not yet implemented */ -#undef HAS_DBDMA - -static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt )"; -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports."); -MODULE_LICENSE("GPL"); - -#ifdef CONFIG_SERIAL_PMACZILOG_TTYS -#define PMACZILOG_MAJOR TTY_MAJOR -#define PMACZILOG_MINOR 64 -#define PMACZILOG_NAME "ttyS" -#else -#define PMACZILOG_MAJOR 204 -#define PMACZILOG_MINOR 192 -#define PMACZILOG_NAME "ttyPZ" -#endif - - -/* - * For the sake of early serial console, we can do a pre-probe - * (optional) of the ports at rather early boot time. - */ -static struct uart_pmac_port pmz_ports[MAX_ZS_PORTS]; -static int pmz_ports_count; -static DEFINE_MUTEX(pmz_irq_mutex); - -static struct uart_driver pmz_uart_reg = { - .owner = THIS_MODULE, - .driver_name = PMACZILOG_NAME, - .dev_name = PMACZILOG_NAME, - .major = PMACZILOG_MAJOR, - .minor = PMACZILOG_MINOR, -}; - - -/* - * Load all registers to reprogram the port - * This function must only be called when the TX is not busy. The UART - * port lock must be held and local interrupts disabled. - */ -static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs) -{ - int i; - - if (ZS_IS_ASLEEP(uap)) - return; - - /* Let pending transmits finish. */ - for (i = 0; i < 1000; i++) { - unsigned char stat = read_zsreg(uap, R1); - if (stat & ALL_SNT) - break; - udelay(100); - } - - ZS_CLEARERR(uap); - zssync(uap); - ZS_CLEARFIFO(uap); - zssync(uap); - ZS_CLEARERR(uap); - - /* Disable all interrupts. */ - write_zsreg(uap, R1, - regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); - - /* Set parity, sync config, stop bits, and clock divisor. */ - write_zsreg(uap, R4, regs[R4]); - - /* Set misc. TX/RX control bits. */ - write_zsreg(uap, R10, regs[R10]); - - /* Set TX/RX controls sans the enable bits. */ - write_zsreg(uap, R3, regs[R3] & ~RxENABLE); - write_zsreg(uap, R5, regs[R5] & ~TxENABLE); - - /* now set R7 "prime" on ESCC */ - write_zsreg(uap, R15, regs[R15] | EN85C30); - write_zsreg(uap, R7, regs[R7P]); - - /* make sure we use R7 "non-prime" on ESCC */ - write_zsreg(uap, R15, regs[R15] & ~EN85C30); - - /* Synchronous mode config. */ - write_zsreg(uap, R6, regs[R6]); - write_zsreg(uap, R7, regs[R7]); - - /* Disable baud generator. */ - write_zsreg(uap, R14, regs[R14] & ~BRENAB); - - /* Clock mode control. */ - write_zsreg(uap, R11, regs[R11]); - - /* Lower and upper byte of baud rate generator divisor. */ - write_zsreg(uap, R12, regs[R12]); - write_zsreg(uap, R13, regs[R13]); - - /* Now rewrite R14, with BRENAB (if set). */ - write_zsreg(uap, R14, regs[R14]); - - /* Reset external status interrupts. */ - write_zsreg(uap, R0, RES_EXT_INT); - write_zsreg(uap, R0, RES_EXT_INT); - - /* Rewrite R3/R5, this time without enables masked. */ - write_zsreg(uap, R3, regs[R3]); - write_zsreg(uap, R5, regs[R5]); - - /* Rewrite R1, this time without IRQ enabled masked. */ - write_zsreg(uap, R1, regs[R1]); - - /* Enable interrupts */ - write_zsreg(uap, R9, regs[R9]); -} - -/* - * We do like sunzilog to avoid disrupting pending Tx - * Reprogram the Zilog channel HW registers with the copies found in the - * software state struct. If the transmitter is busy, we defer this update - * until the next TX complete interrupt. Else, we do it right now. - * - * The UART port lock must be held and local interrupts disabled. - */ -static void pmz_maybe_update_regs(struct uart_pmac_port *uap) -{ - if (!ZS_REGS_HELD(uap)) { - if (ZS_TX_ACTIVE(uap)) { - uap->flags |= PMACZILOG_FLAG_REGS_HELD; - } else { - pmz_debug("pmz: maybe_update_regs: updating\n"); - pmz_load_zsregs(uap, uap->curregs); - } - } -} - -static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) -{ - struct tty_struct *tty = NULL; - unsigned char ch, r1, drop, error, flag; - int loops = 0; - - /* The interrupt can be enabled when the port isn't open, typically - * that happens when using one port is open and the other closed (stale - * interrupt) or when one port is used as a console. - */ - if (!ZS_IS_OPEN(uap)) { - pmz_debug("pmz: draining input\n"); - /* Port is closed, drain input data */ - for (;;) { - if ((++loops) > 1000) - goto flood; - (void)read_zsreg(uap, R1); - write_zsreg(uap, R0, ERR_RES); - (void)read_zsdata(uap); - ch = read_zsreg(uap, R0); - if (!(ch & Rx_CH_AV)) - break; - } - return NULL; - } - - /* Sanity check, make sure the old bug is no longer happening */ - if (uap->port.state == NULL || uap->port.state->port.tty == NULL) { - WARN_ON(1); - (void)read_zsdata(uap); - return NULL; - } - tty = uap->port.state->port.tty; - - while (1) { - error = 0; - drop = 0; - - r1 = read_zsreg(uap, R1); - ch = read_zsdata(uap); - - if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - write_zsreg(uap, R0, ERR_RES); - zssync(uap); - } - - ch &= uap->parity_mask; - if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) { - uap->flags &= ~PMACZILOG_FLAG_BREAK; - } - -#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE) -#ifdef USE_CTRL_O_SYSRQ - /* Handle the SysRq ^O Hack */ - if (ch == '\x0f') { - uap->port.sysrq = jiffies + HZ*5; - goto next_char; - } -#endif /* USE_CTRL_O_SYSRQ */ - if (uap->port.sysrq) { - int swallow; - spin_unlock(&uap->port.lock); - swallow = uart_handle_sysrq_char(&uap->port, ch); - spin_lock(&uap->port.lock); - if (swallow) - goto next_char; - } -#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */ - - /* A real serial line, record the character and status. */ - if (drop) - goto next_char; - - flag = TTY_NORMAL; - uap->port.icount.rx++; - - if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) { - error = 1; - if (r1 & BRK_ABRT) { - pmz_debug("pmz: got break !\n"); - r1 &= ~(PAR_ERR | CRC_ERR); - uap->port.icount.brk++; - if (uart_handle_break(&uap->port)) - goto next_char; - } - else if (r1 & PAR_ERR) - uap->port.icount.parity++; - else if (r1 & CRC_ERR) - uap->port.icount.frame++; - if (r1 & Rx_OVR) - uap->port.icount.overrun++; - r1 &= uap->port.read_status_mask; - if (r1 & BRK_ABRT) - flag = TTY_BREAK; - else if (r1 & PAR_ERR) - flag = TTY_PARITY; - else if (r1 & CRC_ERR) - flag = TTY_FRAME; - } - - if (uap->port.ignore_status_mask == 0xff || - (r1 & uap->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if (r1 & Rx_OVR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - next_char: - /* We can get stuck in an infinite loop getting char 0 when the - * line is in a wrong HW state, we break that here. - * When that happens, I disable the receive side of the driver. - * Note that what I've been experiencing is a real irq loop where - * I'm getting flooded regardless of the actual port speed. - * Something stange is going on with the HW - */ - if ((++loops) > 1000) - goto flood; - ch = read_zsreg(uap, R0); - if (!(ch & Rx_CH_AV)) - break; - } - - return tty; - flood: - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - write_zsreg(uap, R1, uap->curregs[R1]); - zssync(uap); - pmz_error("pmz: rx irq flood !\n"); - return tty; -} - -static void pmz_status_handle(struct uart_pmac_port *uap) -{ - unsigned char status; - - status = read_zsreg(uap, R0); - write_zsreg(uap, R0, RES_EXT_INT); - zssync(uap); - - if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) { - if (status & SYNC_HUNT) - uap->port.icount.dsr++; - - /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. - * But it does not tell us which bit has changed, we have to keep - * track of this ourselves. - * The CTS input is inverted for some reason. -- paulus - */ - if ((status ^ uap->prev_status) & DCD) - uart_handle_dcd_change(&uap->port, - (status & DCD)); - if ((status ^ uap->prev_status) & CTS) - uart_handle_cts_change(&uap->port, - !(status & CTS)); - - wake_up_interruptible(&uap->port.state->port.delta_msr_wait); - } - - if (status & BRK_ABRT) - uap->flags |= PMACZILOG_FLAG_BREAK; - - uap->prev_status = status; -} - -static void pmz_transmit_chars(struct uart_pmac_port *uap) -{ - struct circ_buf *xmit; - - if (ZS_IS_ASLEEP(uap)) - return; - if (ZS_IS_CONS(uap)) { - unsigned char status = read_zsreg(uap, R0); - - /* TX still busy? Just wait for the next TX done interrupt. - * - * It can occur because of how we do serial console writes. It would - * be nice to transmit console writes just like we normally would for - * a TTY line. (ie. buffered and TX interrupt driven). That is not - * easy because console writes cannot sleep. One solution might be - * to poll on enough port->xmit space becomming free. -DaveM - */ - if (!(status & Tx_BUF_EMP)) - return; - } - - uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE; - - if (ZS_REGS_HELD(uap)) { - pmz_load_zsregs(uap, uap->curregs); - uap->flags &= ~PMACZILOG_FLAG_REGS_HELD; - } - - if (ZS_TX_STOPPED(uap)) { - uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; - goto ack_tx_int; - } - - /* Under some circumstances, we see interrupts reported for - * a closed channel. The interrupt mask in R1 is clear, but - * R3 still signals the interrupts and we see them when taking - * an interrupt for the other channel (this could be a qemu - * bug but since the ESCC doc doesn't specify precsiely whether - * R3 interrup status bits are masked by R1 interrupt enable - * bits, better safe than sorry). --BenH. - */ - if (!ZS_IS_OPEN(uap)) - goto ack_tx_int; - - if (uap->port.x_char) { - uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(uap, uap->port.x_char); - zssync(uap); - uap->port.icount.tx++; - uap->port.x_char = 0; - return; - } - - if (uap->port.state == NULL) - goto ack_tx_int; - xmit = &uap->port.state->xmit; - if (uart_circ_empty(xmit)) { - uart_write_wakeup(&uap->port); - goto ack_tx_int; - } - if (uart_tx_stopped(&uap->port)) - goto ack_tx_int; - - uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; - write_zsdata(uap, xmit->buf[xmit->tail]); - zssync(uap); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); - - return; - -ack_tx_int: - write_zsreg(uap, R0, RES_Tx_P); - zssync(uap); -} - -/* Hrm... we register that twice, fixme later.... */ -static irqreturn_t pmz_interrupt(int irq, void *dev_id) -{ - struct uart_pmac_port *uap = dev_id; - struct uart_pmac_port *uap_a; - struct uart_pmac_port *uap_b; - int rc = IRQ_NONE; - struct tty_struct *tty; - u8 r3; - - uap_a = pmz_get_port_A(uap); - uap_b = uap_a->mate; - - spin_lock(&uap_a->port.lock); - r3 = read_zsreg(uap_a, R3); - -#ifdef DEBUG_HARD - pmz_debug("irq, r3: %x\n", r3); -#endif - /* Channel A */ - tty = NULL; - if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - write_zsreg(uap_a, R0, RES_H_IUS); - zssync(uap_a); - if (r3 & CHAEXT) - pmz_status_handle(uap_a); - if (r3 & CHARxIP) - tty = pmz_receive_chars(uap_a); - if (r3 & CHATxIP) - pmz_transmit_chars(uap_a); - rc = IRQ_HANDLED; - } - spin_unlock(&uap_a->port.lock); - if (tty != NULL) - tty_flip_buffer_push(tty); - - if (uap_b->node == NULL) - goto out; - - spin_lock(&uap_b->port.lock); - tty = NULL; - if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - write_zsreg(uap_b, R0, RES_H_IUS); - zssync(uap_b); - if (r3 & CHBEXT) - pmz_status_handle(uap_b); - if (r3 & CHBRxIP) - tty = pmz_receive_chars(uap_b); - if (r3 & CHBTxIP) - pmz_transmit_chars(uap_b); - rc = IRQ_HANDLED; - } - spin_unlock(&uap_b->port.lock); - if (tty != NULL) - tty_flip_buffer_push(tty); - - out: -#ifdef DEBUG_HARD - pmz_debug("irq done.\n"); -#endif - return rc; -} - -/* - * Peek the status register, lock not held by caller - */ -static inline u8 pmz_peek_status(struct uart_pmac_port *uap) -{ - unsigned long flags; - u8 status; - - spin_lock_irqsave(&uap->port.lock, flags); - status = read_zsreg(uap, R0); - spin_unlock_irqrestore(&uap->port.lock, flags); - - return status; -} - -/* - * Check if transmitter is empty - * The port lock is not held. - */ -static unsigned int pmz_tx_empty(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned char status; - - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return TIOCSER_TEMT; - - status = pmz_peek_status(to_pmz(port)); - if (status & Tx_BUF_EMP) - return TIOCSER_TEMT; - return 0; -} - -/* - * Set Modem Control (RTS & DTR) bits - * The port lock is held and interrupts are disabled. - * Note: Shall we really filter out RTS on external ports or - * should that be dealt at higher level only ? - */ -static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned char set_bits, clear_bits; - - /* Do nothing for irda for now... */ - if (ZS_IS_IRDA(uap)) - return; - /* We get called during boot with a port not up yet */ - if (ZS_IS_ASLEEP(uap) || - !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap))) - return; - - set_bits = clear_bits = 0; - - if (ZS_IS_INTMODEM(uap)) { - if (mctrl & TIOCM_RTS) - set_bits |= RTS; - else - clear_bits |= RTS; - } - if (mctrl & TIOCM_DTR) - set_bits |= DTR; - else - clear_bits |= DTR; - - /* NOTE: Not subject to 'transmitter active' rule. */ - uap->curregs[R5] |= set_bits; - uap->curregs[R5] &= ~clear_bits; - if (ZS_IS_ASLEEP(uap)) - return; - write_zsreg(uap, R5, uap->curregs[R5]); - pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n", - set_bits, clear_bits, uap->curregs[R5]); - zssync(uap); -} - -/* - * Get Modem Control bits (only the input ones, the core will - * or that with a cached value of the control ones) - * The port lock is held and interrupts are disabled. - */ -static unsigned int pmz_get_mctrl(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned char status; - unsigned int ret; - - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return 0; - - status = read_zsreg(uap, R0); - - ret = 0; - if (status & DCD) - ret |= TIOCM_CAR; - if (status & SYNC_HUNT) - ret |= TIOCM_DSR; - if (!(status & CTS)) - ret |= TIOCM_CTS; - - return ret; -} - -/* - * Stop TX side. Dealt like sunzilog at next Tx interrupt, - * though for DMA, we will have to do a bit more. - * The port lock is held and interrupts are disabled. - */ -static void pmz_stop_tx(struct uart_port *port) -{ - to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED; -} - -/* - * Kick the Tx side. - * The port lock is held and interrupts are disabled. - */ -static void pmz_start_tx(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned char status; - - pmz_debug("pmz: start_tx()\n"); - - uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; - uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; - - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return; - - status = read_zsreg(uap, R0); - - /* TX busy? Just wait for the TX done interrupt. */ - if (!(status & Tx_BUF_EMP)) - return; - - /* Send the first character to jump-start the TX done - * IRQ sending engine. - */ - if (port->x_char) { - write_zsdata(uap, port->x_char); - zssync(uap); - port->icount.tx++; - port->x_char = 0; - } else { - struct circ_buf *xmit = &port->state->xmit; - - write_zsdata(uap, xmit->buf[xmit->tail]); - zssync(uap); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); - } - pmz_debug("pmz: start_tx() done.\n"); -} - -/* - * Stop Rx side, basically disable emitting of - * Rx interrupts on the port. We don't disable the rx - * side of the chip proper though - * The port lock is held. - */ -static void pmz_stop_rx(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - - if (ZS_IS_ASLEEP(uap) || uap->node == NULL) - return; - - pmz_debug("pmz: stop_rx()()\n"); - - /* Disable all RX interrupts. */ - uap->curregs[R1] &= ~RxINT_MASK; - pmz_maybe_update_regs(uap); - - pmz_debug("pmz: stop_rx() done.\n"); -} - -/* - * Enable modem status change interrupts - * The port lock is held. - */ -static void pmz_enable_ms(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned char new_reg; - - if (ZS_IS_IRDA(uap) || uap->node == NULL) - return; - new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE); - if (new_reg != uap->curregs[R15]) { - uap->curregs[R15] = new_reg; - - if (ZS_IS_ASLEEP(uap)) - return; - /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(uap, R15, uap->curregs[R15]); - } -} - -/* - * Control break state emission - * The port lock is not held. - */ -static void pmz_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned char set_bits, clear_bits, new_reg; - unsigned long flags; - - if (uap->node == NULL) - return; - set_bits = clear_bits = 0; - - if (break_state) - set_bits |= SND_BRK; - else - clear_bits |= SND_BRK; - - spin_lock_irqsave(&port->lock, flags); - - new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; - if (new_reg != uap->curregs[R5]) { - uap->curregs[R5] = new_reg; - - /* NOTE: Not subject to 'transmitter active' rule. */ - if (ZS_IS_ASLEEP(uap)) { - spin_unlock_irqrestore(&port->lock, flags); - return; - } - write_zsreg(uap, R5, uap->curregs[R5]); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -#ifdef CONFIG_PPC_PMAC - -/* - * Turn power on or off to the SCC and associated stuff - * (port drivers, modem, IR port, etc.) - * Returns the number of milliseconds we should wait before - * trying to use the port. - */ -static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) -{ - int delay = 0; - int rc; - - if (state) { - rc = pmac_call_feature( - PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1); - pmz_debug("port power on result: %d\n", rc); - if (ZS_IS_INTMODEM(uap)) { - rc = pmac_call_feature( - PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1); - delay = 2500; /* wait for 2.5s before using */ - pmz_debug("modem power result: %d\n", rc); - } - } else { - /* TODO: Make that depend on a timer, don't power down - * immediately - */ - if (ZS_IS_INTMODEM(uap)) { - rc = pmac_call_feature( - PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0); - pmz_debug("port power off result: %d\n", rc); - } - pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0); - } - return delay; -} - -#else - -static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) -{ - return 0; -} - -#endif /* !CONFIG_PPC_PMAC */ - -/* - * FixZeroBug....Works around a bug in the SCC receving channel. - * Inspired from Darwin code, 15 Sept. 2000 -DanM - * - * The following sequence prevents a problem that is seen with O'Hare ASICs - * (most versions -- also with some Heathrow and Hydra ASICs) where a zero - * at the input to the receiver becomes 'stuck' and locks up the receiver. - * This problem can occur as a result of a zero bit at the receiver input - * coincident with any of the following events: - * - * The SCC is initialized (hardware or software). - * A framing error is detected. - * The clocking option changes from synchronous or X1 asynchronous - * clocking to X16, X32, or X64 asynchronous clocking. - * The decoding mode is changed among NRZ, NRZI, FM0, or FM1. - * - * This workaround attempts to recover from the lockup condition by placing - * the SCC in synchronous loopback mode with a fast clock before programming - * any of the asynchronous modes. - */ -static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap) -{ - write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); - zssync(uap); - udelay(10); - write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV); - zssync(uap); - - write_zsreg(uap, 4, X1CLK | MONSYNC); - write_zsreg(uap, 3, Rx8); - write_zsreg(uap, 5, Tx8 | RTS); - write_zsreg(uap, 9, NV); /* Didn't we already do this? */ - write_zsreg(uap, 11, RCBR | TCBR); - write_zsreg(uap, 12, 0); - write_zsreg(uap, 13, 0); - write_zsreg(uap, 14, (LOOPBAK | BRSRC)); - write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB)); - write_zsreg(uap, 3, Rx8 | RxENABLE); - write_zsreg(uap, 0, RES_EXT_INT); - write_zsreg(uap, 0, RES_EXT_INT); - write_zsreg(uap, 0, RES_EXT_INT); /* to kill some time */ - - /* The channel should be OK now, but it is probably receiving - * loopback garbage. - * Switch to asynchronous mode, disable the receiver, - * and discard everything in the receive buffer. - */ - write_zsreg(uap, 9, NV); - write_zsreg(uap, 4, X16CLK | SB_MASK); - write_zsreg(uap, 3, Rx8); - - while (read_zsreg(uap, 0) & Rx_CH_AV) { - (void)read_zsreg(uap, 8); - write_zsreg(uap, 0, RES_EXT_INT); - write_zsreg(uap, 0, ERR_RES); - } -} - -/* - * Real startup routine, powers up the hardware and sets up - * the SCC. Returns a delay in ms where you need to wait before - * actually using the port, this is typically the internal modem - * powerup delay. This routine expect the lock to be taken. - */ -static int __pmz_startup(struct uart_pmac_port *uap) -{ - int pwr_delay = 0; - - memset(&uap->curregs, 0, sizeof(uap->curregs)); - - /* Power up the SCC & underlying hardware (modem/irda) */ - pwr_delay = pmz_set_scc_power(uap, 1); - - /* Nice buggy HW ... */ - pmz_fix_zero_bug_scc(uap); - - /* Reset the channel */ - uap->curregs[R9] = 0; - write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); - zssync(uap); - udelay(10); - write_zsreg(uap, 9, 0); - zssync(uap); - - /* Clear the interrupt registers */ - write_zsreg(uap, R1, 0); - write_zsreg(uap, R0, ERR_RES); - write_zsreg(uap, R0, ERR_RES); - write_zsreg(uap, R0, RES_H_IUS); - write_zsreg(uap, R0, RES_H_IUS); - - /* Setup some valid baud rate */ - uap->curregs[R4] = X16CLK | SB1; - uap->curregs[R3] = Rx8; - uap->curregs[R5] = Tx8 | RTS; - if (!ZS_IS_IRDA(uap)) - uap->curregs[R5] |= DTR; - uap->curregs[R12] = 0; - uap->curregs[R13] = 0; - uap->curregs[R14] = BRENAB; - - /* Clear handshaking, enable BREAK interrupts */ - uap->curregs[R15] = BRKIE; - - /* Master interrupt enable */ - uap->curregs[R9] |= NV | MIE; - - pmz_load_zsregs(uap, uap->curregs); - - /* Enable receiver and transmitter. */ - write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE); - write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE); - - /* Remember status for DCD/CTS changes */ - uap->prev_status = read_zsreg(uap, R0); - - return pwr_delay; -} - -static void pmz_irda_reset(struct uart_pmac_port *uap) -{ - uap->curregs[R5] |= DTR; - write_zsreg(uap, R5, uap->curregs[R5]); - zssync(uap); - mdelay(110); - uap->curregs[R5] &= ~DTR; - write_zsreg(uap, R5, uap->curregs[R5]); - zssync(uap); - mdelay(10); -} - -/* - * This is the "normal" startup routine, using the above one - * wrapped with the lock and doing a schedule delay - */ -static int pmz_startup(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned long flags; - int pwr_delay = 0; - - pmz_debug("pmz: startup()\n"); - - if (ZS_IS_ASLEEP(uap)) - return -EAGAIN; - if (uap->node == NULL) - return -ENODEV; - - mutex_lock(&pmz_irq_mutex); - - uap->flags |= PMACZILOG_FLAG_IS_OPEN; - - /* A console is never powered down. Else, power up and - * initialize the chip - */ - if (!ZS_IS_CONS(uap)) { - spin_lock_irqsave(&port->lock, flags); - pwr_delay = __pmz_startup(uap); - spin_unlock_irqrestore(&port->lock, flags); - } - - pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; - if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, - "SCC", uap)) { - pmz_error("Unable to register zs interrupt handler.\n"); - pmz_set_scc_power(uap, 0); - mutex_unlock(&pmz_irq_mutex); - return -ENXIO; - } - - mutex_unlock(&pmz_irq_mutex); - - /* Right now, we deal with delay by blocking here, I'll be - * smarter later on - */ - if (pwr_delay != 0) { - pmz_debug("pmz: delaying %d ms\n", pwr_delay); - msleep(pwr_delay); - } - - /* IrDA reset is done now */ - if (ZS_IS_IRDA(uap)) - pmz_irda_reset(uap); - - /* Enable interrupts emission from the chip */ - spin_lock_irqsave(&port->lock, flags); - uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; - if (!ZS_IS_EXTCLK(uap)) - uap->curregs[R1] |= EXT_INT_ENAB; - write_zsreg(uap, R1, uap->curregs[R1]); - spin_unlock_irqrestore(&port->lock, flags); - - pmz_debug("pmz: startup() done.\n"); - - return 0; -} - -static void pmz_shutdown(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned long flags; - - pmz_debug("pmz: shutdown()\n"); - - if (uap->node == NULL) - return; - - mutex_lock(&pmz_irq_mutex); - - /* Release interrupt handler */ - free_irq(uap->port.irq, uap); - - spin_lock_irqsave(&port->lock, flags); - - uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; - - if (!ZS_IS_OPEN(uap->mate)) - pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; - - /* Disable interrupts */ - if (!ZS_IS_ASLEEP(uap)) { - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - write_zsreg(uap, R1, uap->curregs[R1]); - zssync(uap); - } - - if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) { - spin_unlock_irqrestore(&port->lock, flags); - mutex_unlock(&pmz_irq_mutex); - return; - } - - /* Disable receiver and transmitter. */ - uap->curregs[R3] &= ~RxENABLE; - uap->curregs[R5] &= ~TxENABLE; - - /* Disable all interrupts and BRK assertion. */ - uap->curregs[R5] &= ~SND_BRK; - pmz_maybe_update_regs(uap); - - /* Shut the chip down */ - pmz_set_scc_power(uap, 0); - - spin_unlock_irqrestore(&port->lock, flags); - - mutex_unlock(&pmz_irq_mutex); - - pmz_debug("pmz: shutdown() done.\n"); -} - -/* Shared by TTY driver and serial console setup. The port lock is held - * and local interrupts are disabled. - */ -static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, - unsigned int iflag, unsigned long baud) -{ - int brg; - - /* Switch to external clocking for IrDA high clock rates. That - * code could be re-used for Midi interfaces with different - * multipliers - */ - if (baud >= 115200 && ZS_IS_IRDA(uap)) { - uap->curregs[R4] = X1CLK; - uap->curregs[R11] = RCTRxCP | TCTRxCP; - uap->curregs[R14] = 0; /* BRG off */ - uap->curregs[R12] = 0; - uap->curregs[R13] = 0; - uap->flags |= PMACZILOG_FLAG_IS_EXTCLK; - } else { - switch (baud) { - case ZS_CLOCK/16: /* 230400 */ - uap->curregs[R4] = X16CLK; - uap->curregs[R11] = 0; - uap->curregs[R14] = 0; - break; - case ZS_CLOCK/32: /* 115200 */ - uap->curregs[R4] = X32CLK; - uap->curregs[R11] = 0; - uap->curregs[R14] = 0; - break; - default: - uap->curregs[R4] = X16CLK; - uap->curregs[R11] = TCBR | RCBR; - brg = BPS_TO_BRG(baud, ZS_CLOCK / 16); - uap->curregs[R12] = (brg & 255); - uap->curregs[R13] = ((brg >> 8) & 255); - uap->curregs[R14] = BRENAB; - } - uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK; - } - - /* Character size, stop bits, and parity. */ - uap->curregs[3] &= ~RxN_MASK; - uap->curregs[5] &= ~TxN_MASK; - - switch (cflag & CSIZE) { - case CS5: - uap->curregs[3] |= Rx5; - uap->curregs[5] |= Tx5; - uap->parity_mask = 0x1f; - break; - case CS6: - uap->curregs[3] |= Rx6; - uap->curregs[5] |= Tx6; - uap->parity_mask = 0x3f; - break; - case CS7: - uap->curregs[3] |= Rx7; - uap->curregs[5] |= Tx7; - uap->parity_mask = 0x7f; - break; - case CS8: - default: - uap->curregs[3] |= Rx8; - uap->curregs[5] |= Tx8; - uap->parity_mask = 0xff; - break; - }; - uap->curregs[4] &= ~(SB_MASK); - if (cflag & CSTOPB) - uap->curregs[4] |= SB2; - else - uap->curregs[4] |= SB1; - if (cflag & PARENB) - uap->curregs[4] |= PAR_ENAB; - else - uap->curregs[4] &= ~PAR_ENAB; - if (!(cflag & PARODD)) - uap->curregs[4] |= PAR_EVEN; - else - uap->curregs[4] &= ~PAR_EVEN; - - uap->port.read_status_mask = Rx_OVR; - if (iflag & INPCK) - uap->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) - uap->port.read_status_mask |= BRK_ABRT; - - uap->port.ignore_status_mask = 0; - if (iflag & IGNPAR) - uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & IGNBRK) { - uap->port.ignore_status_mask |= BRK_ABRT; - if (iflag & IGNPAR) - uap->port.ignore_status_mask |= Rx_OVR; - } - - if ((cflag & CREAD) == 0) - uap->port.ignore_status_mask = 0xff; -} - - -/* - * Set the irda codec on the imac to the specified baud rate. - */ -static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) -{ - u8 cmdbyte; - int t, version; - - switch (*baud) { - /* SIR modes */ - case 2400: - cmdbyte = 0x53; - break; - case 4800: - cmdbyte = 0x52; - break; - case 9600: - cmdbyte = 0x51; - break; - case 19200: - cmdbyte = 0x50; - break; - case 38400: - cmdbyte = 0x4f; - break; - case 57600: - cmdbyte = 0x4e; - break; - case 115200: - cmdbyte = 0x4d; - break; - /* The FIR modes aren't really supported at this point, how - * do we select the speed ? via the FCR on KeyLargo ? - */ - case 1152000: - cmdbyte = 0; - break; - case 4000000: - cmdbyte = 0; - break; - default: /* 9600 */ - cmdbyte = 0x51; - *baud = 9600; - break; - } - - /* Wait for transmitter to drain */ - t = 10000; - while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0 - || (read_zsreg(uap, R1) & ALL_SNT) == 0) { - if (--t <= 0) { - pmz_error("transmitter didn't drain\n"); - return; - } - udelay(10); - } - - /* Drain the receiver too */ - t = 100; - (void)read_zsdata(uap); - (void)read_zsdata(uap); - (void)read_zsdata(uap); - mdelay(10); - while (read_zsreg(uap, R0) & Rx_CH_AV) { - read_zsdata(uap); - mdelay(10); - if (--t <= 0) { - pmz_error("receiver didn't drain\n"); - return; - } - } - - /* Switch to command mode */ - uap->curregs[R5] |= DTR; - write_zsreg(uap, R5, uap->curregs[R5]); - zssync(uap); - mdelay(1); - - /* Switch SCC to 19200 */ - pmz_convert_to_zs(uap, CS8, 0, 19200); - pmz_load_zsregs(uap, uap->curregs); - mdelay(1); - - /* Write get_version command byte */ - write_zsdata(uap, 1); - t = 5000; - while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { - if (--t <= 0) { - pmz_error("irda_setup timed out on get_version byte\n"); - goto out; - } - udelay(10); - } - version = read_zsdata(uap); - - if (version < 4) { - pmz_info("IrDA: dongle version %d not supported\n", version); - goto out; - } - - /* Send speed mode */ - write_zsdata(uap, cmdbyte); - t = 5000; - while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { - if (--t <= 0) { - pmz_error("irda_setup timed out on speed mode byte\n"); - goto out; - } - udelay(10); - } - t = read_zsdata(uap); - if (t != cmdbyte) - pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte); - - pmz_info("IrDA setup for %ld bps, dongle version: %d\n", - *baud, version); - - (void)read_zsdata(uap); - (void)read_zsdata(uap); - (void)read_zsdata(uap); - - out: - /* Switch back to data mode */ - uap->curregs[R5] &= ~DTR; - write_zsreg(uap, R5, uap->curregs[R5]); - zssync(uap); - - (void)read_zsdata(uap); - (void)read_zsdata(uap); - (void)read_zsdata(uap); -} - - -static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned long baud; - - pmz_debug("pmz: set_termios()\n"); - - if (ZS_IS_ASLEEP(uap)) - return; - - memcpy(&uap->termios_cache, termios, sizeof(struct ktermios)); - - /* XXX Check which revs of machines actually allow 1 and 4Mb speeds - * on the IR dongle. Note that the IRTTY driver currently doesn't know - * about the FIR mode and high speed modes. So these are unused. For - * implementing proper support for these, we should probably add some - * DMA as well, at least on the Rx side, which isn't a simple thing - * at this point. - */ - if (ZS_IS_IRDA(uap)) { - /* Calc baud rate */ - baud = uart_get_baud_rate(port, termios, old, 1200, 4000000); - pmz_debug("pmz: switch IRDA to %ld bauds\n", baud); - /* Cet the irda codec to the right rate */ - pmz_irda_setup(uap, &baud); - /* Set final baud rate */ - pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud); - pmz_load_zsregs(uap, uap->curregs); - zssync(uap); - } else { - baud = uart_get_baud_rate(port, termios, old, 1200, 230400); - pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud); - /* Make sure modem status interrupts are correctly configured */ - if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) { - uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE; - uap->flags |= PMACZILOG_FLAG_MODEM_STATUS; - } else { - uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE); - uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS; - } - - /* Load registers to the chip */ - pmz_maybe_update_regs(uap); - } - uart_update_timeout(port, termios->c_cflag, baud); - - pmz_debug("pmz: set_termios() done.\n"); -} - -/* The port lock is not held. */ -static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_pmac_port *uap = to_pmz(port); - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - /* Disable IRQs on the port */ - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - write_zsreg(uap, R1, uap->curregs[R1]); - - /* Setup new port configuration */ - __pmz_set_termios(port, termios, old); - - /* Re-enable IRQs on the port */ - if (ZS_IS_OPEN(uap)) { - uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; - if (!ZS_IS_EXTCLK(uap)) - uap->curregs[R1] |= EXT_INT_ENAB; - write_zsreg(uap, R1, uap->curregs[R1]); - } - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *pmz_type(struct uart_port *port) -{ - struct uart_pmac_port *uap = to_pmz(port); - - if (ZS_IS_IRDA(uap)) - return "Z85c30 ESCC - Infrared port"; - else if (ZS_IS_INTMODEM(uap)) - return "Z85c30 ESCC - Internal modem"; - return "Z85c30 ESCC - Serial port"; -} - -/* We do not request/release mappings of the registers here, this - * happens at early serial probe time. - */ -static void pmz_release_port(struct uart_port *port) -{ -} - -static int pmz_request_port(struct uart_port *port) -{ - return 0; -} - -/* These do not need to do anything interesting either. */ -static void pmz_config_port(struct uart_port *port, int flags) -{ -} - -/* We do not support letting the user mess with the divisor, IRQ, etc. */ -static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -#ifdef CONFIG_CONSOLE_POLL - -static int pmz_poll_get_char(struct uart_port *port) -{ - struct uart_pmac_port *uap = (struct uart_pmac_port *)port; - - while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) - udelay(5); - return read_zsdata(uap); -} - -static void pmz_poll_put_char(struct uart_port *port, unsigned char c) -{ - struct uart_pmac_port *uap = (struct uart_pmac_port *)port; - - /* Wait for the transmit buffer to empty. */ - while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) - udelay(5); - write_zsdata(uap, c); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -static struct uart_ops pmz_pops = { - .tx_empty = pmz_tx_empty, - .set_mctrl = pmz_set_mctrl, - .get_mctrl = pmz_get_mctrl, - .stop_tx = pmz_stop_tx, - .start_tx = pmz_start_tx, - .stop_rx = pmz_stop_rx, - .enable_ms = pmz_enable_ms, - .break_ctl = pmz_break_ctl, - .startup = pmz_startup, - .shutdown = pmz_shutdown, - .set_termios = pmz_set_termios, - .type = pmz_type, - .release_port = pmz_release_port, - .request_port = pmz_request_port, - .config_port = pmz_config_port, - .verify_port = pmz_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = pmz_poll_get_char, - .poll_put_char = pmz_poll_put_char, -#endif -}; - -#ifdef CONFIG_PPC_PMAC - -/* - * Setup one port structure after probing, HW is down at this point, - * Unlike sunzilog, we don't need to pre-init the spinlock as we don't - * register our console before uart_add_one_port() is called - */ -static int __init pmz_init_port(struct uart_pmac_port *uap) -{ - struct device_node *np = uap->node; - const char *conn; - const struct slot_names_prop { - int count; - char name[1]; - } *slots; - int len; - struct resource r_ports, r_rxdma, r_txdma; - - /* - * Request & map chip registers - */ - if (of_address_to_resource(np, 0, &r_ports)) - return -ENODEV; - uap->port.mapbase = r_ports.start; - uap->port.membase = ioremap(uap->port.mapbase, 0x1000); - - uap->control_reg = uap->port.membase; - uap->data_reg = uap->control_reg + 0x10; - - /* - * Request & map DBDMA registers - */ -#ifdef HAS_DBDMA - if (of_address_to_resource(np, 1, &r_txdma) == 0 && - of_address_to_resource(np, 2, &r_rxdma) == 0) - uap->flags |= PMACZILOG_FLAG_HAS_DMA; -#else - memset(&r_txdma, 0, sizeof(struct resource)); - memset(&r_rxdma, 0, sizeof(struct resource)); -#endif - if (ZS_HAS_DMA(uap)) { - uap->tx_dma_regs = ioremap(r_txdma.start, 0x100); - if (uap->tx_dma_regs == NULL) { - uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; - goto no_dma; - } - uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100); - if (uap->rx_dma_regs == NULL) { - iounmap(uap->tx_dma_regs); - uap->tx_dma_regs = NULL; - uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; - goto no_dma; - } - uap->tx_dma_irq = irq_of_parse_and_map(np, 1); - uap->rx_dma_irq = irq_of_parse_and_map(np, 2); - } -no_dma: - - /* - * Detect port type - */ - if (of_device_is_compatible(np, "cobalt")) - uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; - conn = of_get_property(np, "AAPL,connector", &len); - if (conn && (strcmp(conn, "infrared") == 0)) - uap->flags |= PMACZILOG_FLAG_IS_IRDA; - uap->port_type = PMAC_SCC_ASYNC; - /* 1999 Powerbook G3 has slot-names property instead */ - slots = of_get_property(np, "slot-names", &len); - if (slots && slots->count > 0) { - if (strcmp(slots->name, "IrDA") == 0) - uap->flags |= PMACZILOG_FLAG_IS_IRDA; - else if (strcmp(slots->name, "Modem") == 0) - uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; - } - if (ZS_IS_IRDA(uap)) - uap->port_type = PMAC_SCC_IRDA; - if (ZS_IS_INTMODEM(uap)) { - struct device_node* i2c_modem = - of_find_node_by_name(NULL, "i2c-modem"); - if (i2c_modem) { - const char* mid = - of_get_property(i2c_modem, "modem-id", NULL); - if (mid) switch(*mid) { - case 0x04 : - case 0x05 : - case 0x07 : - case 0x08 : - case 0x0b : - case 0x0c : - uap->port_type = PMAC_SCC_I2S1; - } - printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n", - mid ? (*mid) : 0); - of_node_put(i2c_modem); - } else { - printk(KERN_INFO "pmac_zilog: serial modem detected\n"); - } - } - - /* - * Init remaining bits of "port" structure - */ - uap->port.iotype = UPIO_MEM; - uap->port.irq = irq_of_parse_and_map(np, 0); - uap->port.uartclk = ZS_CLOCK; - uap->port.fifosize = 1; - uap->port.ops = &pmz_pops; - uap->port.type = PORT_PMAC_ZILOG; - uap->port.flags = 0; - - /* - * Fixup for the port on Gatwick for which the device-tree has - * missing interrupts. Normally, the macio_dev would contain - * fixed up interrupt info, but we use the device-tree directly - * here due to early probing so we need the fixup too. - */ - if (uap->port.irq == NO_IRQ && - np->parent && np->parent->parent && - of_device_is_compatible(np->parent->parent, "gatwick")) { - /* IRQs on gatwick are offset by 64 */ - uap->port.irq = irq_create_mapping(NULL, 64 + 15); - uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4); - uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5); - } - - /* Setup some valid baud rate information in the register - * shadows so we don't write crap there before baud rate is - * first initialized. - */ - pmz_convert_to_zs(uap, CS8, 0, 9600); - - return 0; -} - -/* - * Get rid of a port on module removal - */ -static void pmz_dispose_port(struct uart_pmac_port *uap) -{ - struct device_node *np; - - np = uap->node; - iounmap(uap->rx_dma_regs); - iounmap(uap->tx_dma_regs); - iounmap(uap->control_reg); - uap->node = NULL; - of_node_put(np); - memset(uap, 0, sizeof(struct uart_pmac_port)); -} - -/* - * Called upon match with an escc node in the device-tree. - */ -static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) -{ - int i; - - /* Iterate the pmz_ports array to find a matching entry - */ - for (i = 0; i < MAX_ZS_PORTS; i++) - if (pmz_ports[i].node == mdev->ofdev.dev.of_node) { - struct uart_pmac_port *uap = &pmz_ports[i]; - - uap->dev = mdev; - dev_set_drvdata(&mdev->ofdev.dev, uap); - if (macio_request_resources(uap->dev, "pmac_zilog")) - printk(KERN_WARNING "%s: Failed to request resource" - ", port still active\n", - uap->node->name); - else - uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; - return 0; - } - return -ENODEV; -} - -/* - * That one should not be called, macio isn't really a hotswap device, - * we don't expect one of those serial ports to go away... - */ -static int pmz_detach(struct macio_dev *mdev) -{ - struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - - if (!uap) - return -ENODEV; - - if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) { - macio_release_resources(uap->dev); - uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED; - } - dev_set_drvdata(&mdev->ofdev.dev, NULL); - uap->dev = NULL; - - return 0; -} - - -static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) -{ - struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - struct uart_state *state; - unsigned long flags; - - if (uap == NULL) { - printk("HRM... pmz_suspend with NULL uap\n"); - return 0; - } - - if (pm_state.event == mdev->ofdev.dev.power.power_state.event) - return 0; - - pmz_debug("suspend, switching to state %d\n", pm_state.event); - - state = pmz_uart_reg.state + uap->port.line; - - mutex_lock(&pmz_irq_mutex); - mutex_lock(&state->port.mutex); - - spin_lock_irqsave(&uap->port.lock, flags); - - if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) { - /* Disable receiver and transmitter. */ - uap->curregs[R3] &= ~RxENABLE; - uap->curregs[R5] &= ~TxENABLE; - - /* Disable all interrupts and BRK assertion. */ - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - uap->curregs[R5] &= ~SND_BRK; - pmz_load_zsregs(uap, uap->curregs); - uap->flags |= PMACZILOG_FLAG_IS_ASLEEP; - mb(); - } - - spin_unlock_irqrestore(&uap->port.lock, flags); - - if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate)) - if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { - pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; - disable_irq(uap->port.irq); - } - - if (ZS_IS_CONS(uap)) - uap->port.cons->flags &= ~CON_ENABLED; - - /* Shut the chip down */ - pmz_set_scc_power(uap, 0); - - mutex_unlock(&state->port.mutex); - mutex_unlock(&pmz_irq_mutex); - - pmz_debug("suspend, switching complete\n"); - - mdev->ofdev.dev.power.power_state = pm_state; - - return 0; -} - - -static int pmz_resume(struct macio_dev *mdev) -{ - struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); - struct uart_state *state; - unsigned long flags; - int pwr_delay = 0; - - if (uap == NULL) - return 0; - - if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON) - return 0; - - pmz_debug("resume, switching to state 0\n"); - - state = pmz_uart_reg.state + uap->port.line; - - mutex_lock(&pmz_irq_mutex); - mutex_lock(&state->port.mutex); - - spin_lock_irqsave(&uap->port.lock, flags); - if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) { - spin_unlock_irqrestore(&uap->port.lock, flags); - goto bail; - } - pwr_delay = __pmz_startup(uap); - - /* Take care of config that may have changed while asleep */ - __pmz_set_termios(&uap->port, &uap->termios_cache, NULL); - - if (ZS_IS_OPEN(uap)) { - /* Enable interrupts */ - uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; - if (!ZS_IS_EXTCLK(uap)) - uap->curregs[R1] |= EXT_INT_ENAB; - write_zsreg(uap, R1, uap->curregs[R1]); - } - - spin_unlock_irqrestore(&uap->port.lock, flags); - - if (ZS_IS_CONS(uap)) - uap->port.cons->flags |= CON_ENABLED; - - /* Re-enable IRQ on the controller */ - if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { - pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; - enable_irq(uap->port.irq); - } - - bail: - mutex_unlock(&state->port.mutex); - mutex_unlock(&pmz_irq_mutex); - - /* Right now, we deal with delay by blocking here, I'll be - * smarter later on - */ - if (pwr_delay != 0) { - pmz_debug("pmz: delaying %d ms\n", pwr_delay); - msleep(pwr_delay); - } - - pmz_debug("resume, switching complete\n"); - - mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON; - - return 0; -} - -/* - * Probe all ports in the system and build the ports array, we register - * with the serial layer at this point, the macio-type probing is only - * used later to "attach" to the sysfs tree so we get power management - * events - */ -static int __init pmz_probe(void) -{ - struct device_node *node_p, *node_a, *node_b, *np; - int count = 0; - int rc; - - /* - * Find all escc chips in the system - */ - node_p = of_find_node_by_name(NULL, "escc"); - while (node_p) { - /* - * First get channel A/B node pointers - * - * TODO: Add routines with proper locking to do that... - */ - node_a = node_b = NULL; - for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) { - if (strncmp(np->name, "ch-a", 4) == 0) - node_a = of_node_get(np); - else if (strncmp(np->name, "ch-b", 4) == 0) - node_b = of_node_get(np); - } - if (!node_a && !node_b) { - of_node_put(node_a); - of_node_put(node_b); - printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n", - (!node_a) ? 'a' : 'b', node_p->full_name); - goto next; - } - - /* - * Fill basic fields in the port structures - */ - pmz_ports[count].mate = &pmz_ports[count+1]; - pmz_ports[count+1].mate = &pmz_ports[count]; - pmz_ports[count].flags = PMACZILOG_FLAG_IS_CHANNEL_A; - pmz_ports[count].node = node_a; - pmz_ports[count+1].node = node_b; - pmz_ports[count].port.line = count; - pmz_ports[count+1].port.line = count+1; - - /* - * Setup the ports for real - */ - rc = pmz_init_port(&pmz_ports[count]); - if (rc == 0 && node_b != NULL) - rc = pmz_init_port(&pmz_ports[count+1]); - if (rc != 0) { - of_node_put(node_a); - of_node_put(node_b); - memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port)); - memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port)); - goto next; - } - count += 2; -next: - node_p = of_find_node_by_name(node_p, "escc"); - } - pmz_ports_count = count; - - return 0; -} - -#else - -extern struct platform_device scc_a_pdev, scc_b_pdev; - -static int __init pmz_init_port(struct uart_pmac_port *uap) -{ - struct resource *r_ports; - int irq; - - r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0); - irq = platform_get_irq(uap->node, 0); - if (!r_ports || !irq) - return -ENODEV; - - uap->port.mapbase = r_ports->start; - uap->port.membase = (unsigned char __iomem *) r_ports->start; - uap->port.iotype = UPIO_MEM; - uap->port.irq = irq; - uap->port.uartclk = ZS_CLOCK; - uap->port.fifosize = 1; - uap->port.ops = &pmz_pops; - uap->port.type = PORT_PMAC_ZILOG; - uap->port.flags = 0; - - uap->control_reg = uap->port.membase; - uap->data_reg = uap->control_reg + 4; - uap->port_type = 0; - - pmz_convert_to_zs(uap, CS8, 0, 9600); - - return 0; -} - -static int __init pmz_probe(void) -{ - int err; - - pmz_ports_count = 0; - - pmz_ports[0].mate = &pmz_ports[1]; - pmz_ports[0].port.line = 0; - pmz_ports[0].flags = PMACZILOG_FLAG_IS_CHANNEL_A; - pmz_ports[0].node = &scc_a_pdev; - err = pmz_init_port(&pmz_ports[0]); - if (err) - return err; - pmz_ports_count++; - - pmz_ports[1].mate = &pmz_ports[0]; - pmz_ports[1].port.line = 1; - pmz_ports[1].flags = 0; - pmz_ports[1].node = &scc_b_pdev; - err = pmz_init_port(&pmz_ports[1]); - if (err) - return err; - pmz_ports_count++; - - return 0; -} - -static void pmz_dispose_port(struct uart_pmac_port *uap) -{ - memset(uap, 0, sizeof(struct uart_pmac_port)); -} - -static int __init pmz_attach(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < pmz_ports_count; i++) - if (pmz_ports[i].node == pdev) - return 0; - return -ENODEV; -} - -static int __exit pmz_detach(struct platform_device *pdev) -{ - return 0; -} - -#endif /* !CONFIG_PPC_PMAC */ - -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - -static void pmz_console_write(struct console *con, const char *s, unsigned int count); -static int __init pmz_console_setup(struct console *co, char *options); - -static struct console pmz_console = { - .name = PMACZILOG_NAME, - .write = pmz_console_write, - .device = uart_console_device, - .setup = pmz_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &pmz_uart_reg, -}; - -#define PMACZILOG_CONSOLE &pmz_console -#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ -#define PMACZILOG_CONSOLE (NULL) -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - -/* - * Register the driver, console driver and ports with the serial - * core - */ -static int __init pmz_register(void) -{ - int i, rc; - - pmz_uart_reg.nr = pmz_ports_count; - pmz_uart_reg.cons = PMACZILOG_CONSOLE; - - /* - * Register this driver with the serial core - */ - rc = uart_register_driver(&pmz_uart_reg); - if (rc) - return rc; - - /* - * Register each port with the serial core - */ - for (i = 0; i < pmz_ports_count; i++) { - struct uart_pmac_port *uport = &pmz_ports[i]; - /* NULL node may happen on wallstreet */ - if (uport->node != NULL) - rc = uart_add_one_port(&pmz_uart_reg, &uport->port); - if (rc) - goto err_out; - } - - return 0; -err_out: - while (i-- > 0) { - struct uart_pmac_port *uport = &pmz_ports[i]; - uart_remove_one_port(&pmz_uart_reg, &uport->port); - } - uart_unregister_driver(&pmz_uart_reg); - return rc; -} - -#ifdef CONFIG_PPC_PMAC - -static struct of_device_id pmz_match[] = -{ - { - .name = "ch-a", - }, - { - .name = "ch-b", - }, - {}, -}; -MODULE_DEVICE_TABLE (of, pmz_match); - -static struct macio_driver pmz_driver = { - .driver = { - .name = "pmac_zilog", - .owner = THIS_MODULE, - .of_match_table = pmz_match, - }, - .probe = pmz_attach, - .remove = pmz_detach, - .suspend = pmz_suspend, - .resume = pmz_resume, -}; - -#else - -static struct platform_driver pmz_driver = { - .remove = __exit_p(pmz_detach), - .driver = { - .name = "scc", - .owner = THIS_MODULE, - }, -}; - -#endif /* !CONFIG_PPC_PMAC */ - -static int __init init_pmz(void) -{ - int rc, i; - printk(KERN_INFO "%s\n", version); - - /* - * First, we need to do a direct OF-based probe pass. We - * do that because we want serial console up before the - * macio stuffs calls us back, and since that makes it - * easier to pass the proper number of channels to - * uart_register_driver() - */ - if (pmz_ports_count == 0) - pmz_probe(); - - /* - * Bail early if no port found - */ - if (pmz_ports_count == 0) - return -ENODEV; - - /* - * Now we register with the serial layer - */ - rc = pmz_register(); - if (rc) { - printk(KERN_ERR - "pmac_zilog: Error registering serial device, disabling pmac_zilog.\n" - "pmac_zilog: Did another serial driver already claim the minors?\n"); - /* effectively "pmz_unprobe()" */ - for (i=0; i < pmz_ports_count; i++) - pmz_dispose_port(&pmz_ports[i]); - return rc; - } - - /* - * Then we register the macio driver itself - */ -#ifdef CONFIG_PPC_PMAC - return macio_register_driver(&pmz_driver); -#else - return platform_driver_probe(&pmz_driver, pmz_attach); -#endif -} - -static void __exit exit_pmz(void) -{ - int i; - -#ifdef CONFIG_PPC_PMAC - /* Get rid of macio-driver (detach from macio) */ - macio_unregister_driver(&pmz_driver); -#else - platform_driver_unregister(&pmz_driver); -#endif - - for (i = 0; i < pmz_ports_count; i++) { - struct uart_pmac_port *uport = &pmz_ports[i]; - if (uport->node != NULL) { - uart_remove_one_port(&pmz_uart_reg, &uport->port); - pmz_dispose_port(uport); - } - } - /* Unregister UART driver */ - uart_unregister_driver(&pmz_uart_reg); -} - -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - -static void pmz_console_putchar(struct uart_port *port, int ch) -{ - struct uart_pmac_port *uap = (struct uart_pmac_port *)port; - - /* Wait for the transmit buffer to empty. */ - while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) - udelay(5); - write_zsdata(uap, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void pmz_console_write(struct console *con, const char *s, unsigned int count) -{ - struct uart_pmac_port *uap = &pmz_ports[con->index]; - unsigned long flags; - - if (ZS_IS_ASLEEP(uap)) - return; - spin_lock_irqsave(&uap->port.lock, flags); - - /* Turn of interrupts and enable the transmitter. */ - write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB); - write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR); - - uart_console_write(&uap->port, s, count, pmz_console_putchar); - - /* Restore the values in the registers. */ - write_zsreg(uap, R1, uap->curregs[1]); - /* Don't disable the transmitter. */ - - spin_unlock_irqrestore(&uap->port.lock, flags); -} - -/* - * Setup the serial console - */ -static int __init pmz_console_setup(struct console *co, char *options) -{ - struct uart_pmac_port *uap; - struct uart_port *port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - unsigned long pwr_delay; - - /* - * XServe's default to 57600 bps - */ - if (of_machine_is_compatible("RackMac1,1") - || of_machine_is_compatible("RackMac1,2") - || of_machine_is_compatible("MacRISC4")) - baud = 57600; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= pmz_ports_count) - co->index = 0; - uap = &pmz_ports[co->index]; - if (uap->node == NULL) - return -ENODEV; - port = &uap->port; - - /* - * Mark port as beeing a console - */ - uap->flags |= PMACZILOG_FLAG_IS_CONS; - - /* - * Temporary fix for uart layer who didn't setup the spinlock yet - */ - spin_lock_init(&port->lock); - - /* - * Enable the hardware - */ - pwr_delay = __pmz_startup(uap); - if (pwr_delay) - mdelay(pwr_delay); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static int __init pmz_console_init(void) -{ - /* Probe ports */ - pmz_probe(); - - /* TODO: Autoprobe console based on OF */ - /* pmz_console.index = i; */ - register_console(&pmz_console); - - return 0; - -} -console_initcall(pmz_console_init); -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - -module_init(init_pmz); -module_exit(exit_pmz); diff --git a/drivers/serial/pmac_zilog.h b/drivers/serial/pmac_zilog.h deleted file mode 100644 index cbc34fbb1b20..000000000000 --- a/drivers/serial/pmac_zilog.h +++ /dev/null @@ -1,396 +0,0 @@ -#ifndef __PMAC_ZILOG_H__ -#define __PMAC_ZILOG_H__ - -#ifdef CONFIG_PPC_PMAC -#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg) -#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg) -#define pmz_info(fmt, arg...) dev_info(&uap->dev->ofdev.dev, fmt, ## arg) -#else -#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg) -#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg) -#define pmz_info(fmt, arg...) dev_info(&uap->node->dev, fmt, ## arg) -#endif - -/* - * At most 2 ESCCs with 2 ports each - */ -#define MAX_ZS_PORTS 4 - -/* - * We wrap our port structure around the generic uart_port. - */ -#define NUM_ZSREGS 17 - -struct uart_pmac_port { - struct uart_port port; - struct uart_pmac_port *mate; - -#ifdef CONFIG_PPC_PMAC - /* macio_dev for the escc holding this port (maybe be null on - * early inited port) - */ - struct macio_dev *dev; - /* device node to this port, this points to one of 2 childs - * of "escc" node (ie. ch-a or ch-b) - */ - struct device_node *node; -#else - struct platform_device *node; -#endif - - /* Port type as obtained from device tree (IRDA, modem, ...) */ - int port_type; - u8 curregs[NUM_ZSREGS]; - - unsigned int flags; -#define PMACZILOG_FLAG_IS_CONS 0x00000001 -#define PMACZILOG_FLAG_IS_KGDB 0x00000002 -#define PMACZILOG_FLAG_MODEM_STATUS 0x00000004 -#define PMACZILOG_FLAG_IS_CHANNEL_A 0x00000008 -#define PMACZILOG_FLAG_REGS_HELD 0x00000010 -#define PMACZILOG_FLAG_TX_STOPPED 0x00000020 -#define PMACZILOG_FLAG_TX_ACTIVE 0x00000040 -#define PMACZILOG_FLAG_ENABLED 0x00000080 -#define PMACZILOG_FLAG_IS_IRDA 0x00000100 -#define PMACZILOG_FLAG_IS_INTMODEM 0x00000200 -#define PMACZILOG_FLAG_HAS_DMA 0x00000400 -#define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800 -#define PMACZILOG_FLAG_IS_ASLEEP 0x00001000 -#define PMACZILOG_FLAG_IS_OPEN 0x00002000 -#define PMACZILOG_FLAG_IS_IRQ_ON 0x00004000 -#define PMACZILOG_FLAG_IS_EXTCLK 0x00008000 -#define PMACZILOG_FLAG_BREAK 0x00010000 - - unsigned char parity_mask; - unsigned char prev_status; - - volatile u8 __iomem *control_reg; - volatile u8 __iomem *data_reg; - -#ifdef CONFIG_PPC_PMAC - unsigned int tx_dma_irq; - unsigned int rx_dma_irq; - volatile struct dbdma_regs __iomem *tx_dma_regs; - volatile struct dbdma_regs __iomem *rx_dma_regs; -#endif - - struct ktermios termios_cache; -}; - -#define to_pmz(p) ((struct uart_pmac_port *)(p)) - -static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap) -{ - if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A) - return uap; - return uap->mate; -} - -/* - * Register accessors. Note that we don't need to enforce a recovery - * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip, - * though if we try to use this driver on older machines, we might have - * to add it back - */ -static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg) -{ - if (reg != 0) - writeb(reg, port->control_reg); - return readb(port->control_reg); -} - -static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value) -{ - if (reg != 0) - writeb(reg, port->control_reg); - writeb(value, port->control_reg); -} - -static inline u8 read_zsdata(struct uart_pmac_port *port) -{ - return readb(port->data_reg); -} - -static inline void write_zsdata(struct uart_pmac_port *port, u8 data) -{ - writeb(data, port->data_reg); -} - -static inline void zssync(struct uart_pmac_port *port) -{ - (void)readb(port->control_reg); -} - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */ - -/* The Zilog register set */ - -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 -#define R7P 16 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ -#define RxINT_MASK 0x18 - -#define WT_RDY_RT 0x20 /* W/Req reflects recv if 1, xmit if 0 */ -#define WT_FN_RDYFN 0x40 /* W/Req pin is DMA request if 1, wait if 0 */ -#define WT_RDY_ENAB 0x80 /* Enable W/Req pin */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ -#define RxN_MASK 0xc0 - -/* Write Register 4 */ - -#define PAR_ENAB 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ -#define SB_MASK 0xc - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ -#define XCLK_MASK 0xC0 - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENABLE 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define TxN_MASK 0x60 -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 7' (Some enhanced feature control) */ -#define ENEXREAD 0x40 /* Enable read of some write registers */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENAB 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define EN85C30 1 /* Enable some 85c30-enhanced registers */ -#define ZCIE 2 /* Zero count IE */ -#define ENSTFIFO 4 /* Enable status FIFO (SDLC) */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ -#define CHB_Tx_EMPTY 0x00 -#define CHB_EXT_STAT 0x02 -#define CHB_Rx_AVAIL 0x04 -#define CHB_SPECIAL 0x06 -#define CHA_Tx_EMPTY 0x08 -#define CHA_EXT_STAT 0x0a -#define CHA_Rx_AVAIL 0x0c -#define CHA_SPECIAL 0x0e -#define STATUS_MASK 0x06 - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* Misc macros */ -#define ZS_CLEARERR(port) (write_zsreg(port, 0, ERR_RES)) -#define ZS_CLEARFIFO(port) do { volatile unsigned char garbage; \ - garbage = read_zsdata(port); \ - garbage = read_zsdata(port); \ - garbage = read_zsdata(port); \ - } while(0) - -#define ZS_IS_CONS(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CONS) -#define ZS_IS_KGDB(UP) ((UP)->flags & PMACZILOG_FLAG_IS_KGDB) -#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A) -#define ZS_REGS_HELD(UP) ((UP)->flags & PMACZILOG_FLAG_REGS_HELD) -#define ZS_TX_STOPPED(UP) ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED) -#define ZS_TX_ACTIVE(UP) ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE) -#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS) -#define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA) -#define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM) -#define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA) -#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP) -#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN) -#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON) -#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK) - -#endif /* __PMAC_ZILOG_H__ */ diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c deleted file mode 100644 index 0aa75a97531c..000000000000 --- a/drivers/serial/pnx8xxx_uart.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * UART driver for PNX8XXX SoCs - * - * Author: Per Hallsmark per.hallsmark@mvista.com - * Ported to 2.6 kernel by EmbeddedAlley - * Reworked by Vitaly Wool - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * 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. - * - */ - -#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* We'll be using StrongARM sa1100 serial port major/minor */ -#define SERIAL_PNX8XXX_MAJOR 204 -#define MINOR_START 5 - -#define NR_PORTS 2 - -#define PNX8XXX_ISR_PASS_LIMIT 256 - -/* - * Convert from ignore_status_mask or read_status_mask to FIFO - * and interrupt status bits - */ -#define SM_TO_FIFO(x) ((x) >> 10) -#define SM_TO_ISTAT(x) ((x) & 0x000001ff) -#define FIFO_TO_SM(x) ((x) << 10) -#define ISTAT_TO_SM(x) ((x) & 0x000001ff) - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x1000 - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo incase CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -extern struct pnx8xxx_port pnx8xxx_ports[]; - -static inline int serial_in(struct pnx8xxx_port *sport, int offset) -{ - return (__raw_readl(sport->port.membase + offset)); -} - -static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value) -{ - __raw_writel(value, sport->port.membase + offset); -} - -/* - * Handle any change of modem status signal since we were last called. - */ -static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void pnx8xxx_timeout(unsigned long data) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data; - unsigned long flags; - - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - pnx8xxx_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } -} - -/* - * interrupts disabled on entry - */ -static void pnx8xxx_stop_tx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - u32 ien; - - /* Disable TX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX); - - /* Clear all pending TX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); -} - -/* - * interrupts may not be disabled on entry - */ -static void pnx8xxx_start_tx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - u32 ien; - - /* Clear all pending TX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); - - /* Enable TX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX); -} - -/* - * Interrupts enabled - */ -static void pnx8xxx_stop_rx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - u32 ien; - - /* Disable RX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX); - - /* Clear all pending RX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX); -} - -/* - * Set the modem control timer to fire immediately. - */ -static void pnx8xxx_enable_ms(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - - mod_timer(&sport->timer, jiffies); -} - -static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) -{ - struct tty_struct *tty = sport->port.state->port.tty; - unsigned int status, ch, flg; - - status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | - ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); - while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) { - ch = serial_in(sport, PNX8XXX_FIFO) & 0xff; - - sport->port.icount.rx++; - - flg = TTY_NORMAL; - - /* - * note that the error handling code is - * out of the main execution path - */ - if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE | - PNX8XXX_UART_FIFO_RXPAR | - PNX8XXX_UART_FIFO_RXBRK) | - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) { - if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) { - status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)); - sport->port.icount.brk++; - if (uart_handle_break(&sport->port)) - goto ignore_char; - } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) - sport->port.icount.parity++; - else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) - sport->port.icount.frame++; - if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN)) - sport->port.icount.overrun++; - - status &= sport->port.read_status_mask; - - if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) - flg = TTY_PARITY; - else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) - flg = TTY_FRAME; - -#ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; -#endif - } - - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char; - - uart_insert_char(&sport->port, status, - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg); - - ignore_char: - serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) | - PNX8XXX_UART_LCR_RX_NEXT); - status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | - ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); - } - tty_flip_buffer_push(tty); -} - -static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - - if (sport->port.x_char) { - serial_out(sport, PNX8XXX_FIFO, sport->port.x_char); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - /* - * Check the modem control lines before - * transmitting anything. - */ - pnx8xxx_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - pnx8xxx_stop_tx(&sport->port); - return; - } - - /* - * TX while bytes available - */ - while (((serial_in(sport, PNX8XXX_FIFO) & - PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) { - serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - pnx8xxx_stop_tx(&sport->port); -} - -static irqreturn_t pnx8xxx_int(int irq, void *dev_id) -{ - struct pnx8xxx_port *sport = dev_id; - unsigned int status; - - spin_lock(&sport->port.lock); - /* Get the interrupts */ - status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN); - - /* Byte or break signal received */ - if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK)) - pnx8xxx_rx_chars(sport); - - /* TX holding register empty - transmit a byte */ - if (status & PNX8XXX_UART_INT_TX) - pnx8xxx_tx_chars(sport); - - /* Clear the ISTAT register */ - serial_out(sport, PNX8XXX_ICLR, status); - - spin_unlock(&sport->port.lock); - return IRQ_HANDLED; -} - -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int pnx8xxx_tx_empty(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - - return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT; -} - -static unsigned int pnx8xxx_get_mctrl(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - unsigned int mctrl = TIOCM_DSR; - unsigned int msr; - - /* REVISIT */ - - msr = serial_in(sport, PNX8XXX_MCR); - - mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0; - mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0; - - return mctrl; -} - -static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -#if 0 /* FIXME */ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - unsigned int msr; -#endif -} - -/* - * Interrupts always disabled. - */ -static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - unsigned long flags; - unsigned int lcr; - - spin_lock_irqsave(&sport->port.lock, flags); - lcr = serial_in(sport, PNX8XXX_LCR); - if (break_state == -1) - lcr |= PNX8XXX_UART_LCR_TXBREAK; - else - lcr &= ~PNX8XXX_UART_LCR_TXBREAK; - serial_out(sport, PNX8XXX_LCR, lcr); - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static int pnx8xxx_startup(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - int retval; - - /* - * Allocate the IRQ - */ - retval = request_irq(sport->port.irq, pnx8xxx_int, 0, - "pnx8xxx-uart", sport); - if (retval) - return retval; - - /* - * Finally, clear and enable interrupts - */ - - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) | - PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - /* - * Enable modem status interrupts - */ - spin_lock_irq(&sport->port.lock); - pnx8xxx_enable_ms(&sport->port); - spin_unlock_irq(&sport->port.lock); - - return 0; -} - -static void pnx8xxx_shutdown(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - int lcr; - - /* - * Stop our timer. - */ - del_timer_sync(&sport->timer); - - /* - * Disable all interrupts - */ - serial_out(sport, PNX8XXX_IEN, 0); - - /* - * Reset the Tx and Rx FIFOS, disable the break condition - */ - lcr = serial_in(sport, PNX8XXX_LCR); - lcr &= ~PNX8XXX_UART_LCR_TXBREAK; - lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST; - serial_out(sport, PNX8XXX_LCR, lcr); - - /* - * Clear all interrupts - */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - /* - * Free the interrupt - */ - free_irq(sport->port.irq, sport); -} - -static void -pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - unsigned long flags; - unsigned int lcr_fcr, old_ien, baud, quot; - unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - - /* - * We only support CS7 and CS8. - */ - while ((termios->c_cflag & CSIZE) != CS7 && - (termios->c_cflag & CSIZE) != CS8) { - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= old_csize; - old_csize = CS8; - } - - if ((termios->c_cflag & CSIZE) == CS8) - lcr_fcr = PNX8XXX_UART_LCR_8BIT; - else - lcr_fcr = 0; - - if (termios->c_cflag & CSTOPB) - lcr_fcr |= PNX8XXX_UART_LCR_2STOPB; - if (termios->c_cflag & PARENB) { - lcr_fcr |= PNX8XXX_UART_LCR_PAREN; - if (!(termios->c_cflag & PARODD)) - lcr_fcr |= PNX8XXX_UART_LCR_PAREVN; - } - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) | - ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) | - ISTAT_TO_SM(PNX8XXX_UART_INT_RX); - if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & (BRKINT | PARMRK)) - sport->port.read_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); - - /* - * Characters to ignore - */ - sport->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN); - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_RX); - - del_timer_sync(&sport->timer); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * disable interrupts and drain transmitter - */ - old_ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | - PNX8XXX_UART_INT_ALLRX)); - - while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA) - barrier(); - - /* then, disable everything */ - serial_out(sport, PNX8XXX_IEN, 0); - - /* Reset the Rx and Tx FIFOs too */ - lcr_fcr |= PNX8XXX_UART_LCR_TX_RST; - lcr_fcr |= PNX8XXX_UART_LCR_RX_RST; - - /* set the parity, stop bits and data size */ - serial_out(sport, PNX8XXX_LCR, lcr_fcr); - - /* set the baud rate */ - quot -= 1; - serial_out(sport, PNX8XXX_BAUD, quot); - - serial_out(sport, PNX8XXX_ICLR, -1); - - serial_out(sport, PNX8XXX_IEN, old_ien); - - if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - pnx8xxx_enable_ms(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *pnx8xxx_type(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - - return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void pnx8xxx_release_port(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int pnx8xxx_request_port(struct uart_port *port) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, - "pnx8xxx-uart") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void pnx8xxx_config_port(struct uart_port *port, int flags) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - - if (flags & UART_CONFIG_TYPE && - pnx8xxx_request_port(&sport->port) == 0) - sport->port.type = PORT_PNX8XXX; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_PNX8XXX and PORT_UNKNOWN - */ -static int -pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -static struct uart_ops pnx8xxx_pops = { - .tx_empty = pnx8xxx_tx_empty, - .set_mctrl = pnx8xxx_set_mctrl, - .get_mctrl = pnx8xxx_get_mctrl, - .stop_tx = pnx8xxx_stop_tx, - .start_tx = pnx8xxx_start_tx, - .stop_rx = pnx8xxx_stop_rx, - .enable_ms = pnx8xxx_enable_ms, - .break_ctl = pnx8xxx_break_ctl, - .startup = pnx8xxx_startup, - .shutdown = pnx8xxx_shutdown, - .set_termios = pnx8xxx_set_termios, - .type = pnx8xxx_type, - .release_port = pnx8xxx_release_port, - .request_port = pnx8xxx_request_port, - .config_port = pnx8xxx_config_port, - .verify_port = pnx8xxx_verify_port, -}; - - -/* - * Setup the PNX8XXX serial ports. - * - * Note also that we support "console=ttySx" where "x" is either 0 or 1. - */ -static void __init pnx8xxx_init_ports(void) -{ - static int first = 1; - int i; - - if (!first) - return; - first = 0; - - for (i = 0; i < NR_PORTS; i++) { - init_timer(&pnx8xxx_ports[i].timer); - pnx8xxx_ports[i].timer.function = pnx8xxx_timeout; - pnx8xxx_ports[i].timer.data = (unsigned long)&pnx8xxx_ports[i]; - pnx8xxx_ports[i].port.ops = &pnx8xxx_pops; - } -} - -#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE - -static void pnx8xxx_console_putchar(struct uart_port *port, int ch) -{ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - int status; - - do { - /* Wait for UART_TX register to empty */ - status = serial_in(sport, PNX8XXX_FIFO); - } while (status & PNX8XXX_UART_FIFO_TXFIFO); - serial_out(sport, PNX8XXX_FIFO, ch); -} - -/* - * Interrupts are disabled on entering - */static void -pnx8xxx_console_write(struct console *co, const char *s, unsigned int count) -{ - struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index]; - unsigned int old_ien, status; - - /* - * First, save IEN and then disable interrupts - */ - old_ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | - PNX8XXX_UART_INT_ALLRX)); - - uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore IEN - */ - do { - /* Wait for UART_TX register to empty */ - status = serial_in(sport, PNX8XXX_FIFO); - } while (status & PNX8XXX_UART_FIFO_TXFIFO); - - /* Clear TX and EMPTY interrupt */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX | - PNX8XXX_UART_INT_EMPTY); - - serial_out(sport, PNX8XXX_IEN, old_ien); -} - -static int __init -pnx8xxx_console_setup(struct console *co, char *options) -{ - struct pnx8xxx_port *sport; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= NR_PORTS) - co->index = 0; - sport = &pnx8xxx_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver pnx8xxx_reg; -static struct console pnx8xxx_console = { - .name = "ttyS", - .write = pnx8xxx_console_write, - .device = uart_console_device, - .setup = pnx8xxx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &pnx8xxx_reg, -}; - -static int __init pnx8xxx_rs_console_init(void) -{ - pnx8xxx_init_ports(); - register_console(&pnx8xxx_console); - return 0; -} -console_initcall(pnx8xxx_rs_console_init); - -#define PNX8XXX_CONSOLE &pnx8xxx_console -#else -#define PNX8XXX_CONSOLE NULL -#endif - -static struct uart_driver pnx8xxx_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyS", - .dev_name = "ttyS", - .major = SERIAL_PNX8XXX_MAJOR, - .minor = MINOR_START, - .nr = NR_PORTS, - .cons = PNX8XXX_CONSOLE, -}; - -static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - return uart_suspend_port(&pnx8xxx_reg, &sport->port); -} - -static int pnx8xxx_serial_resume(struct platform_device *pdev) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - return uart_resume_port(&pnx8xxx_reg, &sport->port); -} - -static int pnx8xxx_serial_probe(struct platform_device *pdev) -{ - struct resource *res = pdev->resource; - int i; - - for (i = 0; i < pdev->num_resources; i++, res++) { - if (!(res->flags & IORESOURCE_MEM)) - continue; - - for (i = 0; i < NR_PORTS; i++) { - if (pnx8xxx_ports[i].port.mapbase != res->start) - continue; - - pnx8xxx_ports[i].port.dev = &pdev->dev; - uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port); - platform_set_drvdata(pdev, &pnx8xxx_ports[i]); - break; - } - } - - return 0; -} - -static int pnx8xxx_serial_remove(struct platform_device *pdev) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (sport) - uart_remove_one_port(&pnx8xxx_reg, &sport->port); - - return 0; -} - -static struct platform_driver pnx8xxx_serial_driver = { - .driver = { - .name = "pnx8xxx-uart", - .owner = THIS_MODULE, - }, - .probe = pnx8xxx_serial_probe, - .remove = pnx8xxx_serial_remove, - .suspend = pnx8xxx_serial_suspend, - .resume = pnx8xxx_serial_resume, -}; - -static int __init pnx8xxx_serial_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: PNX8XXX driver\n"); - - pnx8xxx_init_ports(); - - ret = uart_register_driver(&pnx8xxx_reg); - if (ret == 0) { - ret = platform_driver_register(&pnx8xxx_serial_driver); - if (ret) - uart_unregister_driver(&pnx8xxx_reg); - } - return ret; -} - -static void __exit pnx8xxx_serial_exit(void) -{ - platform_driver_unregister(&pnx8xxx_serial_driver); - uart_unregister_driver(&pnx8xxx_reg); -} - -module_init(pnx8xxx_serial_init); -module_exit(pnx8xxx_serial_exit); - -MODULE_AUTHOR("Embedded Alley Solutions, Inc."); -MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR); -MODULE_ALIAS("platform:pnx8xxx-uart"); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c deleted file mode 100644 index 1102a39b44f5..000000000000 --- a/drivers/serial/pxa.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * linux/drivers/serial/pxa.c - * - * Based on drivers/serial/8250.c by Russell King. - * - * Author: Nicolas Pitre - * Created: Feb 20, 2003 - * Copyright: (C) 2003 Monta Vista Software, Inc. - * - * 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. - * - * Note 1: This driver is made separate from the already too overloaded - * 8250.c because it needs some kirks of its own and that'll make it - * easier to add DMA support. - * - * Note 2: I'm too sick of device allocation policies for serial ports. - * If someone else wants to request an "official" allocation of major/minor - * for this driver please be my guest. And don't forget that new hardware - * to come from Intel might have more than 3 or 4 of those UARTs. Let's - * hope for a better port registration and dynamic device allocation scheme - * with the serial core maintainer satisfaction to appear soon. - */ - - -#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct uart_pxa_port { - struct uart_port port; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned int lsr_break_flag; - struct clk *clk; - char *name; -}; - -static inline unsigned int serial_in(struct uart_pxa_port *up, int offset) -{ - offset <<= 2; - return readl(up->port.membase + offset); -} - -static inline void serial_out(struct uart_pxa_port *up, int offset, int value) -{ - offset <<= 2; - writel(value, up->port.membase + offset); -} - -static void serial_pxa_enable_ms(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void serial_pxa_stop_tx(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - - if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_pxa_stop_rx(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); -} - -static inline void receive_chars(struct uart_pxa_port *up, int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned int ch, flag; - int max_count = 256; - - do { - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - /* - * For statistics only - */ - if (*status & UART_LSR_BI) { - *status &= ~(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 (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - *status &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_PXA_CONSOLE - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } -#endif - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - - uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); - - ignore_char: - *status = serial_in(up, UART_LSR); - } while ((*status & UART_LSR_DR) && (max_count-- > 0)); - tty_flip_buffer_push(tty); -} - -static void transmit_chars(struct uart_pxa_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_pxa_stop_tx(&up->port); - return; - } - - count = up->port.fifosize / 2; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - - if (uart_circ_empty(xmit)) - serial_pxa_stop_tx(&up->port); -} - -static void serial_pxa_start_tx(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static inline void check_modem_status(struct uart_pxa_port *up) -{ - int status; - - status = serial_in(up, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -/* - * This handles the interrupt from one port. - */ -static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) -{ - struct uart_pxa_port *up = dev_id; - unsigned int iir, lsr; - - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) - return IRQ_NONE; - lsr = serial_in(up, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr); - check_modem_status(up); - if (lsr & UART_LSR_THRE) - transmit_chars(up); - return IRQ_HANDLED; -} - -static unsigned int serial_pxa_tx_empty(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned long flags; - unsigned int ret; - - 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); - - return ret; -} - -static unsigned int serial_pxa_get_mctrl(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned char status; - unsigned int ret; - - status = serial_in(up, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr |= up->mcr; - - serial_out(up, UART_MCR, mcr); -} - -static void serial_pxa_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -#if 0 -static void serial_pxa_dma_init(struct pxa_uart *up) -{ - up->rxdma = - pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up); - if (up->rxdma < 0) - goto out; - up->txdma = - pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up); - if (up->txdma < 0) - goto err_txdma; - up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL); - if (!up->dmadesc) - goto err_alloc; - - /* ... */ -err_alloc: - pxa_free_dma(up->txdma); -err_rxdma: - pxa_free_dma(up->rxdma); -out: - return; -} -#endif - -static int serial_pxa_startup(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned long flags; - int retval; - - if (port->line == 3) /* HWUART */ - up->mcr |= UART_MCR_AFE; - else - up->mcr = 0; - - up->port.uartclk = clk_get_rate(up->clk); - - /* - * Allocate the IRQ - */ - retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up); - if (retval) - return retval; - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - /* - * Clear the interrupt registers. - */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - /* - * Now, initialize the UART - */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl |= TIOCM_OUT2; - serial_pxa_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; - serial_out(up, UART_IER, up->ier); - - /* - * And clear the interrupt registers again for luck. - */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - return 0; -} - -static void serial_pxa_shutdown(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned long flags; - - free_irq(up->port.irq, up); - - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_out(up, UART_IER, 0); - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - serial_pxa_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); -} - -static void -serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - unsigned int dll; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; - else if ((up->port.uartclk / quot) < (230400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Ensure the port will be enabled. - * This is required especially for serial console. - */ - up->ier |= UART_IER_UUE; - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* - * Characters to ignore - */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; - else - up->mcr &= ~UART_MCR_AFE; - - serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ - - /* - * work around Errata #75 according to Intel(R) PXA27x Processor Family - * Specification Update (Nov 2005) - */ - dll = serial_in(up, UART_DLL); - WARN_ON(dll != (quot & 0xff)); - - serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ - serial_out(up, UART_LCR, cval); /* reset DLAB */ - up->lcr = cval; /* Save LCR */ - serial_pxa_set_mctrl(&up->port, up->port.mctrl); - serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -serial_pxa_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - - if (!state) - clk_enable(up->clk); - else - clk_disable(up->clk); -} - -static void serial_pxa_release_port(struct uart_port *port) -{ -} - -static int serial_pxa_request_port(struct uart_port *port) -{ - return 0; -} - -static void serial_pxa_config_port(struct uart_port *port, int flags) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - up->port.type = PORT_PXA; -} - -static int -serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* we don't want the core code to modify any port params */ - return -EINVAL; -} - -static const char * -serial_pxa_type(struct uart_port *port) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - return up->name; -} - -static struct uart_pxa_port *serial_pxa_ports[4]; -static struct uart_driver serial_pxa_reg; - -#ifdef CONFIG_SERIAL_PXA_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* - * Wait for transmitter & holding register to empty - */ -static inline void wait_for_xmitr(struct uart_pxa_port *up) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) - udelay(1); - } -} - -static void serial_pxa_console_putchar(struct uart_port *port, int ch) -{ - struct uart_pxa_port *up = (struct uart_pxa_port *)port; - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -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; - - clk_enable(up->clk); - - /* - * First save the IER then disable the interrupts - */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, UART_IER_UUE); - - uart_console_write(&up->port, s, count, serial_pxa_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - - clk_disable(up->clk); -} - -static int __init -serial_pxa_console_setup(struct console *co, char *options) -{ - struct uart_pxa_port *up; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index == -1 || co->index >= serial_pxa_reg.nr) - co->index = 0; - up = serial_pxa_ports[co->index]; - if (!up) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&up->port, co, baud, parity, bits, flow); -} - -static struct console serial_pxa_console = { - .name = "ttyS", - .write = serial_pxa_console_write, - .device = uart_console_device, - .setup = serial_pxa_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_pxa_reg, -}; - -#define PXA_CONSOLE &serial_pxa_console -#else -#define PXA_CONSOLE NULL -#endif - -struct uart_ops serial_pxa_pops = { - .tx_empty = serial_pxa_tx_empty, - .set_mctrl = serial_pxa_set_mctrl, - .get_mctrl = serial_pxa_get_mctrl, - .stop_tx = serial_pxa_stop_tx, - .start_tx = serial_pxa_start_tx, - .stop_rx = serial_pxa_stop_rx, - .enable_ms = serial_pxa_enable_ms, - .break_ctl = serial_pxa_break_ctl, - .startup = serial_pxa_startup, - .shutdown = serial_pxa_shutdown, - .set_termios = serial_pxa_set_termios, - .pm = serial_pxa_pm, - .type = serial_pxa_type, - .release_port = serial_pxa_release_port, - .request_port = serial_pxa_request_port, - .config_port = serial_pxa_config_port, - .verify_port = serial_pxa_verify_port, -}; - -static struct uart_driver serial_pxa_reg = { - .owner = THIS_MODULE, - .driver_name = "PXA serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = 4, - .cons = PXA_CONSOLE, -}; - -#ifdef CONFIG_PM -static int serial_pxa_suspend(struct device *dev) -{ - struct uart_pxa_port *sport = dev_get_drvdata(dev); - - if (sport) - uart_suspend_port(&serial_pxa_reg, &sport->port); - - return 0; -} - -static int serial_pxa_resume(struct device *dev) -{ - struct uart_pxa_port *sport = dev_get_drvdata(dev); - - if (sport) - uart_resume_port(&serial_pxa_reg, &sport->port); - - return 0; -} - -static const struct dev_pm_ops serial_pxa_pm_ops = { - .suspend = serial_pxa_suspend, - .resume = serial_pxa_resume, -}; -#endif - -static int serial_pxa_probe(struct platform_device *dev) -{ - struct uart_pxa_port *sport; - struct resource *mmres, *irqres; - int ret; - - mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) - return -ENODEV; - - sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); - if (!sport) - return -ENOMEM; - - sport->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(sport->clk)) { - ret = PTR_ERR(sport->clk); - goto err_free; - } - - sport->port.type = PORT_PXA; - sport->port.iotype = UPIO_MEM; - sport->port.mapbase = mmres->start; - sport->port.irq = irqres->start; - sport->port.fifosize = 64; - sport->port.ops = &serial_pxa_pops; - sport->port.line = dev->id; - sport->port.dev = &dev->dev; - sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - sport->port.uartclk = clk_get_rate(sport->clk); - - switch (dev->id) { - case 0: sport->name = "FFUART"; break; - case 1: sport->name = "BTUART"; break; - case 2: sport->name = "STUART"; break; - case 3: sport->name = "HWUART"; break; - default: - sport->name = "???"; - break; - } - - sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); - if (!sport->port.membase) { - ret = -ENOMEM; - goto err_clk; - } - - serial_pxa_ports[dev->id] = sport; - - uart_add_one_port(&serial_pxa_reg, &sport->port); - platform_set_drvdata(dev, sport); - - return 0; - - err_clk: - clk_put(sport->clk); - err_free: - kfree(sport); - return ret; -} - -static int serial_pxa_remove(struct platform_device *dev) -{ - struct uart_pxa_port *sport = platform_get_drvdata(dev); - - platform_set_drvdata(dev, NULL); - - uart_remove_one_port(&serial_pxa_reg, &sport->port); - clk_put(sport->clk); - kfree(sport); - - return 0; -} - -static struct platform_driver serial_pxa_driver = { - .probe = serial_pxa_probe, - .remove = serial_pxa_remove, - - .driver = { - .name = "pxa2xx-uart", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &serial_pxa_pm_ops, -#endif - }, -}; - -int __init serial_pxa_init(void) -{ - int ret; - - ret = uart_register_driver(&serial_pxa_reg); - if (ret != 0) - return ret; - - ret = platform_driver_register(&serial_pxa_driver); - if (ret != 0) - uart_unregister_driver(&serial_pxa_reg); - - return ret; -} - -void __exit serial_pxa_exit(void) -{ - platform_driver_unregister(&serial_pxa_driver); - uart_unregister_driver(&serial_pxa_reg); -} - -module_init(serial_pxa_init); -module_exit(serial_pxa_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-uart"); diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c deleted file mode 100644 index fed1a9a1ffb4..000000000000 --- a/drivers/serial/s3c2400.c +++ /dev/null @@ -1,106 +0,0 @@ -/* linux/drivers/serial/s3c240.c - * - * Driver for Samsung SoC onboard UARTs. - * - * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include "samsung.h" - -static int s3c2400_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - clk->divisor = 1; - clk->name = "pclk"; - - return 0; -} - -static int s3c2400_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - return 0; -} - -static int s3c2400_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n", - port, port->mapbase, cfg); - - wr_regl(port, S3C2410_UCON, cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -static struct s3c24xx_uart_info s3c2400_uart_inf = { - .name = "Samsung S3C2400 UART", - .type = PORT_S3C2400, - .fifosize = 16, - .rx_fifomask = S3C2410_UFSTAT_RXMASK, - .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2410_UFSTAT_RXFULL, - .tx_fifofull = S3C2410_UFSTAT_TXFULL, - .tx_fifomask = S3C2410_UFSTAT_TXMASK, - .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, - .get_clksrc = s3c2400_serial_getsource, - .set_clksrc = s3c2400_serial_setsource, - .reset_port = s3c2400_serial_resetport, -}; - -static int s3c2400_serial_probe(struct platform_device *dev) -{ - return s3c24xx_serial_probe(dev, &s3c2400_uart_inf); -} - -static struct platform_driver s3c2400_serial_driver = { - .probe = s3c2400_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s3c2400-uart", - .owner = THIS_MODULE, - }, -}; - -s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf); - -static inline int s3c2400_serial_init(void) -{ - return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf); -} - -static inline void s3c2400_serial_exit(void) -{ - platform_driver_unregister(&s3c2400_serial_driver); -} - -module_init(s3c2400_serial_init); -module_exit(s3c2400_serial_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver"); -MODULE_ALIAS("platform:s3c2400-uart"); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c deleted file mode 100644 index 73f089d3efd6..000000000000 --- a/drivers/serial/s3c2410.c +++ /dev/null @@ -1,118 +0,0 @@ -/* linux/drivers/serial/s3c2410.c - * - * Driver for Samsung S3C2410 SoC onboard UARTs. - * - * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "samsung.h" - -static int s3c2410_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - if (strcmp(clk->name, "uclk") == 0) - ucon |= S3C2410_UCON_UCLK; - else - ucon &= ~S3C2410_UCON_UCLK; - - wr_regl(port, S3C2410_UCON, ucon); - return 0; -} - -static int s3c2410_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - clk->divisor = 1; - clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; - - return 0; -} - -static int s3c2410_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n", - port, port->mapbase, cfg); - - wr_regl(port, S3C2410_UCON, cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -static struct s3c24xx_uart_info s3c2410_uart_inf = { - .name = "Samsung S3C2410 UART", - .type = PORT_S3C2410, - .fifosize = 16, - .rx_fifomask = S3C2410_UFSTAT_RXMASK, - .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2410_UFSTAT_RXFULL, - .tx_fifofull = S3C2410_UFSTAT_TXFULL, - .tx_fifomask = S3C2410_UFSTAT_TXMASK, - .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, - .get_clksrc = s3c2410_serial_getsource, - .set_clksrc = s3c2410_serial_setsource, - .reset_port = s3c2410_serial_resetport, -}; - -static int s3c2410_serial_probe(struct platform_device *dev) -{ - return s3c24xx_serial_probe(dev, &s3c2410_uart_inf); -} - -static struct platform_driver s3c2410_serial_driver = { - .probe = s3c2410_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s3c2410-uart", - .owner = THIS_MODULE, - }, -}; - -s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf); - -static int __init s3c2410_serial_init(void) -{ - return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf); -} - -static void __exit s3c2410_serial_exit(void) -{ - platform_driver_unregister(&s3c2410_serial_driver); -} - -module_init(s3c2410_serial_init); -module_exit(s3c2410_serial_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver"); -MODULE_ALIAS("platform:s3c2410-uart"); diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c deleted file mode 100644 index 1700b1a2fb7e..000000000000 --- a/drivers/serial/s3c2412.c +++ /dev/null @@ -1,152 +0,0 @@ -/* linux/drivers/serial/s3c2412.c - * - * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs. - * - * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "samsung.h" - -static int s3c2412_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - ucon &= ~S3C2412_UCON_CLKMASK; - - if (strcmp(clk->name, "uclk") == 0) - ucon |= S3C2440_UCON_UCLK; - else if (strcmp(clk->name, "pclk") == 0) - ucon |= S3C2440_UCON_PCLK; - else if (strcmp(clk->name, "usysclk") == 0) - ucon |= S3C2412_UCON_USYSCLK; - else { - printk(KERN_ERR "unknown clock source %s\n", clk->name); - return -EINVAL; - } - - wr_regl(port, S3C2410_UCON, ucon); - return 0; -} - - -static int s3c2412_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - switch (ucon & S3C2412_UCON_CLKMASK) { - case S3C2412_UCON_UCLK: - clk->divisor = 1; - clk->name = "uclk"; - break; - - case S3C2412_UCON_PCLK: - case S3C2412_UCON_PCLK2: - clk->divisor = 1; - clk->name = "pclk"; - break; - - case S3C2412_UCON_USYSCLK: - clk->divisor = 1; - clk->name = "usysclk"; - break; - } - - return 0; -} - -static int s3c2412_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - dbg("%s: port=%p (%08lx), cfg=%p\n", - __func__, port, port->mapbase, cfg); - - /* ensure we don't change the clock settings... */ - - ucon &= S3C2412_UCON_CLKMASK; - - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -static struct s3c24xx_uart_info s3c2412_uart_inf = { - .name = "Samsung S3C2412 UART", - .type = PORT_S3C2412, - .fifosize = 64, - .has_divslot = 1, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .get_clksrc = s3c2412_serial_getsource, - .set_clksrc = s3c2412_serial_setsource, - .reset_port = s3c2412_serial_resetport, -}; - -/* device management */ - -static int s3c2412_serial_probe(struct platform_device *dev) -{ - dbg("s3c2440_serial_probe: dev=%p\n", dev); - return s3c24xx_serial_probe(dev, &s3c2412_uart_inf); -} - -static struct platform_driver s3c2412_serial_driver = { - .probe = s3c2412_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s3c2412-uart", - .owner = THIS_MODULE, - }, -}; - -s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf); - -static inline int s3c2412_serial_init(void) -{ - return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf); -} - -static inline void s3c2412_serial_exit(void) -{ - platform_driver_unregister(&s3c2412_serial_driver); -} - -module_init(s3c2412_serial_init); -module_exit(s3c2412_serial_exit); - -MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c2412-uart"); diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c deleted file mode 100644 index 094cc3904b13..000000000000 --- a/drivers/serial/s3c2440.c +++ /dev/null @@ -1,181 +0,0 @@ -/* linux/drivers/serial/s3c2440.c - * - * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs. - * - * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "samsung.h" - - -static int s3c2440_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - /* todo - proper fclk<>nonfclk switch. */ - - ucon &= ~S3C2440_UCON_CLKMASK; - - if (strcmp(clk->name, "uclk") == 0) - ucon |= S3C2440_UCON_UCLK; - else if (strcmp(clk->name, "pclk") == 0) - ucon |= S3C2440_UCON_PCLK; - else if (strcmp(clk->name, "fclk") == 0) - ucon |= S3C2440_UCON_FCLK; - else { - printk(KERN_ERR "unknown clock source %s\n", clk->name); - return -EINVAL; - } - - wr_regl(port, S3C2410_UCON, ucon); - return 0; -} - - -static int s3c2440_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - unsigned long ucon0, ucon1, ucon2; - - switch (ucon & S3C2440_UCON_CLKMASK) { - case S3C2440_UCON_UCLK: - clk->divisor = 1; - clk->name = "uclk"; - break; - - case S3C2440_UCON_PCLK: - case S3C2440_UCON_PCLK2: - clk->divisor = 1; - clk->name = "pclk"; - break; - - case S3C2440_UCON_FCLK: - /* the fun of calculating the uart divisors on - * the s3c2440 */ - - ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON); - ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON); - ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON); - - printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2); - - ucon0 &= S3C2440_UCON0_DIVMASK; - ucon1 &= S3C2440_UCON1_DIVMASK; - ucon2 &= S3C2440_UCON2_DIVMASK; - - if (ucon0 != 0) { - clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT; - clk->divisor += 6; - } else if (ucon1 != 0) { - clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT; - clk->divisor += 21; - } else if (ucon2 != 0) { - clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT; - clk->divisor += 36; - } else { - /* manual calims 44, seems to be 9 */ - clk->divisor = 9; - } - - clk->name = "fclk"; - break; - } - - return 0; -} - -static int s3c2440_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n", - port, port->mapbase, cfg); - - /* ensure we don't change the clock settings... */ - - ucon &= (S3C2440_UCON0_DIVMASK | (3<<10)); - - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -static struct s3c24xx_uart_info s3c2440_uart_inf = { - .name = "Samsung S3C2440 UART", - .type = PORT_S3C2440, - .fifosize = 64, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .get_clksrc = s3c2440_serial_getsource, - .set_clksrc = s3c2440_serial_setsource, - .reset_port = s3c2440_serial_resetport, -}; - -/* device management */ - -static int s3c2440_serial_probe(struct platform_device *dev) -{ - dbg("s3c2440_serial_probe: dev=%p\n", dev); - return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); -} - -static struct platform_driver s3c2440_serial_driver = { - .probe = s3c2440_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s3c2440-uart", - .owner = THIS_MODULE, - }, -}; - -s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf); - -static int __init s3c2440_serial_init(void) -{ - return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf); -} - -static void __exit s3c2440_serial_exit(void) -{ - platform_driver_unregister(&s3c2440_serial_driver); -} - -module_init(s3c2440_serial_init); -module_exit(s3c2440_serial_exit); - -MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c2440-uart"); diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c deleted file mode 100644 index fad6083ca427..000000000000 --- a/drivers/serial/s3c24a0.c +++ /dev/null @@ -1,118 +0,0 @@ -/* linux/drivers/serial/s3c24a0.c - * - * Driver for Samsung S3C24A0 SoC onboard UARTs. - * - * Based on drivers/serial/s3c2410.c - * - * Author: Sandeep Patil - * - * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "samsung.h" - -static int s3c24a0_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - if (strcmp(clk->name, "uclk") == 0) - ucon |= S3C2410_UCON_UCLK; - else - ucon &= ~S3C2410_UCON_UCLK; - - wr_regl(port, S3C2410_UCON, ucon); - return 0; -} - -static int s3c24a0_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - clk->divisor = 1; - clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; - - return 0; -} - -static int s3c24a0_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n", - port, port->mapbase, cfg); - - wr_regl(port, S3C2410_UCON, cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -static struct s3c24xx_uart_info s3c24a0_uart_inf = { - .name = "Samsung S3C24A0 UART", - .type = PORT_S3C2410, - .fifosize = 16, - .rx_fifomask = S3C24A0_UFSTAT_RXMASK, - .rx_fifoshift = S3C24A0_UFSTAT_RXSHIFT, - .rx_fifofull = S3C24A0_UFSTAT_RXFULL, - .tx_fifofull = S3C24A0_UFSTAT_TXFULL, - .tx_fifomask = S3C24A0_UFSTAT_TXMASK, - .tx_fifoshift = S3C24A0_UFSTAT_TXSHIFT, - .get_clksrc = s3c24a0_serial_getsource, - .set_clksrc = s3c24a0_serial_setsource, - .reset_port = s3c24a0_serial_resetport, -}; - -static int s3c24a0_serial_probe(struct platform_device *dev) -{ - return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf); -} - -static struct platform_driver s3c24a0_serial_driver = { - .probe = s3c24a0_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s3c24a0-uart", - .owner = THIS_MODULE, - }, -}; - -s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); - -static int __init s3c24a0_serial_init(void) -{ - return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); -} - -static void __exit s3c24a0_serial_exit(void) -{ - platform_driver_unregister(&s3c24a0_serial_driver); -} - -module_init(s3c24a0_serial_init); -module_exit(s3c24a0_serial_exit); - diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c deleted file mode 100644 index 4be92ab50058..000000000000 --- a/drivers/serial/s3c6400.c +++ /dev/null @@ -1,152 +0,0 @@ -/* linux/drivers/serial/s3c6400.c - * - * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs. - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "samsung.h" - -static int s3c6400_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - if (strcmp(clk->name, "uclk0") == 0) { - ucon &= ~S3C6400_UCON_CLKMASK; - ucon |= S3C6400_UCON_UCLK0; - } else if (strcmp(clk->name, "uclk1") == 0) - ucon |= S3C6400_UCON_UCLK1; - else if (strcmp(clk->name, "pclk") == 0) { - /* See notes about transitioning from UCLK to PCLK */ - ucon &= ~S3C6400_UCON_UCLK0; - } else { - printk(KERN_ERR "unknown clock source %s\n", clk->name); - return -EINVAL; - } - - wr_regl(port, S3C2410_UCON, ucon); - return 0; -} - - -static int s3c6400_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - u32 ucon = rd_regl(port, S3C2410_UCON); - - clk->divisor = 1; - - switch (ucon & S3C6400_UCON_CLKMASK) { - case S3C6400_UCON_UCLK0: - clk->name = "uclk0"; - break; - - case S3C6400_UCON_UCLK1: - clk->name = "uclk1"; - break; - - case S3C6400_UCON_PCLK: - case S3C6400_UCON_PCLK2: - clk->name = "pclk"; - break; - } - - return 0; -} - -static int s3c6400_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n", - port, port->mapbase, cfg); - - /* ensure we don't change the clock settings... */ - - ucon &= S3C6400_UCON_CLKMASK; - - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -static struct s3c24xx_uart_info s3c6400_uart_inf = { - .name = "Samsung S3C6400 UART", - .type = PORT_S3C6400, - .fifosize = 64, - .has_divslot = 1, - .rx_fifomask = S3C2440_UFSTAT_RXMASK, - .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, - .rx_fifofull = S3C2440_UFSTAT_RXFULL, - .tx_fifofull = S3C2440_UFSTAT_TXFULL, - .tx_fifomask = S3C2440_UFSTAT_TXMASK, - .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, - .get_clksrc = s3c6400_serial_getsource, - .set_clksrc = s3c6400_serial_setsource, - .reset_port = s3c6400_serial_resetport, -}; - -/* device management */ - -static int s3c6400_serial_probe(struct platform_device *dev) -{ - dbg("s3c6400_serial_probe: dev=%p\n", dev); - return s3c24xx_serial_probe(dev, &s3c6400_uart_inf); -} - -static struct platform_driver s3c6400_serial_driver = { - .probe = s3c6400_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s3c6400-uart", - .owner = THIS_MODULE, - }, -}; - -s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf); - -static int __init s3c6400_serial_init(void) -{ - return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf); -} - -static void __exit s3c6400_serial_exit(void) -{ - platform_driver_unregister(&s3c6400_serial_driver); -} - -module_init(s3c6400_serial_init); -module_exit(s3c6400_serial_exit); - -MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c6400-uart"); diff --git a/drivers/serial/s5pv210.c b/drivers/serial/s5pv210.c deleted file mode 100644 index 6ebccd70a707..000000000000 --- a/drivers/serial/s5pv210.c +++ /dev/null @@ -1,162 +0,0 @@ -/* linux/drivers/serial/s5pv210.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * Based on drivers/serial/s3c6400.c - * - * Driver for Samsung S5PV210 SoC UARTs. - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "samsung.h" - -static int s5pv210_serial_setsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - struct s3c2410_uartcfg *cfg = port->dev->platform_data; - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - if ((cfg->clocks_size) == 1) - return 0; - - if (strcmp(clk->name, "pclk") == 0) - ucon &= ~S5PV210_UCON_CLKMASK; - else if (strcmp(clk->name, "uclk1") == 0) - ucon |= S5PV210_UCON_CLKMASK; - else { - printk(KERN_ERR "unknown clock source %s\n", clk->name); - return -EINVAL; - } - - wr_regl(port, S3C2410_UCON, ucon); - return 0; -} - - -static int s5pv210_serial_getsource(struct uart_port *port, - struct s3c24xx_uart_clksrc *clk) -{ - struct s3c2410_uartcfg *cfg = port->dev->platform_data; - u32 ucon = rd_regl(port, S3C2410_UCON); - - clk->divisor = 1; - - if ((cfg->clocks_size) == 1) - return 0; - - switch (ucon & S5PV210_UCON_CLKMASK) { - case S5PV210_UCON_PCLK: - clk->name = "pclk"; - break; - case S5PV210_UCON_UCLK: - clk->name = "uclk1"; - break; - } - - return 0; -} - -static int s5pv210_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - unsigned long ucon = rd_regl(port, S3C2410_UCON); - - ucon &= S5PV210_UCON_CLKMASK; - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); - wr_regl(port, S3C2410_ULCON, cfg->ulcon); - - /* reset both fifos */ - wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); - wr_regl(port, S3C2410_UFCON, cfg->ufcon); - - return 0; -} - -#define S5PV210_UART_DEFAULT_INFO(fifo_size) \ - .name = "Samsung S5PV210 UART0", \ - .type = PORT_S3C6400, \ - .fifosize = fifo_size, \ - .has_divslot = 1, \ - .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ - .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ - .rx_fifofull = S5PV210_UFSTAT_RXFULL, \ - .tx_fifofull = S5PV210_UFSTAT_TXFULL, \ - .tx_fifomask = S5PV210_UFSTAT_TXMASK, \ - .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, \ - .get_clksrc = s5pv210_serial_getsource, \ - .set_clksrc = s5pv210_serial_setsource, \ - .reset_port = s5pv210_serial_resetport - -static struct s3c24xx_uart_info s5p_port_fifo256 = { - S5PV210_UART_DEFAULT_INFO(256), -}; - -static struct s3c24xx_uart_info s5p_port_fifo64 = { - S5PV210_UART_DEFAULT_INFO(64), -}; - -static struct s3c24xx_uart_info s5p_port_fifo16 = { - S5PV210_UART_DEFAULT_INFO(16), -}; - -static struct s3c24xx_uart_info *s5p_uart_inf[] = { - [0] = &s5p_port_fifo256, - [1] = &s5p_port_fifo64, - [2] = &s5p_port_fifo16, - [3] = &s5p_port_fifo16, -}; - -/* device management */ -static int s5p_serial_probe(struct platform_device *pdev) -{ - return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]); -} - -static struct platform_driver s5p_serial_driver = { - .probe = s5p_serial_probe, - .remove = __devexit_p(s3c24xx_serial_remove), - .driver = { - .name = "s5pv210-uart", - .owner = THIS_MODULE, - }, -}; - -static int __init s5pv210_serial_console_init(void) -{ - return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf); -} - -console_initcall(s5pv210_serial_console_init); - -static int __init s5p_serial_init(void) -{ - return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf); -} - -static void __exit s5p_serial_exit(void) -{ - platform_driver_unregister(&s5p_serial_driver); -} - -module_init(s5p_serial_init); -module_exit(s5p_serial_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s5pv210-uart"); -MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support"); -MODULE_AUTHOR("Thomas Abraham "); diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c deleted file mode 100644 index 2199d819a987..000000000000 --- a/drivers/serial/sa1100.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - * linux/drivers/char/sa1100.c - * - * Driver for SA11x0 serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * 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 - */ - -#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* We've been assigned a range on the "Low-density serial ports" major */ -#define SERIAL_SA1100_MAJOR 204 -#define MINOR_START 5 - -#define NR_PORTS 3 - -#define SA1100_ISR_PASS_LIMIT 256 - -/* - * Convert from ignore_status_mask or read_status_mask to UTSR[01] - */ -#define SM_TO_UTSR0(x) ((x) & 0xff) -#define SM_TO_UTSR1(x) ((x) >> 8) -#define UTSR0_TO_SM(x) ((x)) -#define UTSR1_TO_SM(x) ((x) << 8) - -#define UART_GET_UTCR0(sport) __raw_readl((sport)->port.membase + UTCR0) -#define UART_GET_UTCR1(sport) __raw_readl((sport)->port.membase + UTCR1) -#define UART_GET_UTCR2(sport) __raw_readl((sport)->port.membase + UTCR2) -#define UART_GET_UTCR3(sport) __raw_readl((sport)->port.membase + UTCR3) -#define UART_GET_UTSR0(sport) __raw_readl((sport)->port.membase + UTSR0) -#define UART_GET_UTSR1(sport) __raw_readl((sport)->port.membase + UTSR1) -#define UART_GET_CHAR(sport) __raw_readl((sport)->port.membase + UTDR) - -#define UART_PUT_UTCR0(sport,v) __raw_writel((v),(sport)->port.membase + UTCR0) -#define UART_PUT_UTCR1(sport,v) __raw_writel((v),(sport)->port.membase + UTCR1) -#define UART_PUT_UTCR2(sport,v) __raw_writel((v),(sport)->port.membase + UTCR2) -#define UART_PUT_UTCR3(sport,v) __raw_writel((v),(sport)->port.membase + UTCR3) -#define UART_PUT_UTSR0(sport,v) __raw_writel((v),(sport)->port.membase + UTSR0) -#define UART_PUT_UTSR1(sport,v) __raw_writel((v),(sport)->port.membase + UTSR1) -#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR) - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x24 - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo incase CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -struct sa1100_port { - struct uart_port port; - struct timer_list timer; - unsigned int old_status; -}; - -/* - * Handle any change of modem status signal since we were last called. - */ -static void sa1100_mctrl_check(struct sa1100_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void sa1100_timeout(unsigned long data) -{ - struct sa1100_port *sport = (struct sa1100_port *)data; - unsigned long flags; - - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - sa1100_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } -} - -/* - * interrupts disabled on entry - */ -static void sa1100_stop_tx(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - u32 utcr3; - - utcr3 = UART_GET_UTCR3(sport); - UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE); - sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS); -} - -/* - * port locked and interrupts disabled - */ -static void sa1100_start_tx(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - u32 utcr3; - - utcr3 = UART_GET_UTCR3(sport); - sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS); - UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE); -} - -/* - * Interrupts enabled - */ -static void sa1100_stop_rx(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - u32 utcr3; - - utcr3 = UART_GET_UTCR3(sport); - UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE); -} - -/* - * Set the modem control timer to fire immediately. - */ -static void sa1100_enable_ms(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - mod_timer(&sport->timer, jiffies); -} - -static void -sa1100_rx_chars(struct sa1100_port *sport) -{ - struct tty_struct *tty = sport->port.state->port.tty; - unsigned int status, ch, flg; - - status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | - UTSR0_TO_SM(UART_GET_UTSR0(sport)); - while (status & UTSR1_TO_SM(UTSR1_RNE)) { - ch = UART_GET_CHAR(sport); - - sport->port.icount.rx++; - - flg = TTY_NORMAL; - - /* - * note that the error handling code is - * out of the main execution path - */ - if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) { - if (status & UTSR1_TO_SM(UTSR1_PRE)) - sport->port.icount.parity++; - else if (status & UTSR1_TO_SM(UTSR1_FRE)) - sport->port.icount.frame++; - if (status & UTSR1_TO_SM(UTSR1_ROR)) - sport->port.icount.overrun++; - - status &= sport->port.read_status_mask; - - if (status & UTSR1_TO_SM(UTSR1_PRE)) - flg = TTY_PARITY; - else if (status & UTSR1_TO_SM(UTSR1_FRE)) - flg = TTY_FRAME; - -#ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; -#endif - } - - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char; - - uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg); - - ignore_char: - status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | - UTSR0_TO_SM(UART_GET_UTSR0(sport)); - } - tty_flip_buffer_push(tty); -} - -static void sa1100_tx_chars(struct sa1100_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - - if (sport->port.x_char) { - UART_PUT_CHAR(sport, sport->port.x_char); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - /* - * Check the modem control lines before - * transmitting anything. - */ - sa1100_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - sa1100_stop_tx(&sport->port); - return; - } - - /* - * Tried using FIFO (not checking TNF) for fifo fill: - * still had the '4 bytes repeated' problem. - */ - while (UART_GET_UTSR1(sport) & UTSR1_TNF) { - UART_PUT_CHAR(sport, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - sa1100_stop_tx(&sport->port); -} - -static irqreturn_t sa1100_int(int irq, void *dev_id) -{ - struct sa1100_port *sport = dev_id; - unsigned int status, pass_counter = 0; - - spin_lock(&sport->port.lock); - status = UART_GET_UTSR0(sport); - status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; - do { - if (status & (UTSR0_RFS | UTSR0_RID)) { - /* Clear the receiver idle bit, if set */ - if (status & UTSR0_RID) - UART_PUT_UTSR0(sport, UTSR0_RID); - sa1100_rx_chars(sport); - } - - /* Clear the relevant break bits */ - if (status & (UTSR0_RBB | UTSR0_REB)) - UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB)); - - if (status & UTSR0_RBB) - sport->port.icount.brk++; - - if (status & UTSR0_REB) - uart_handle_break(&sport->port); - - if (status & UTSR0_TFS) - sa1100_tx_chars(sport); - if (pass_counter++ > SA1100_ISR_PASS_LIMIT) - break; - status = UART_GET_UTSR0(sport); - status &= SM_TO_UTSR0(sport->port.read_status_mask) | - ~UTSR0_TFS; - } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); - spin_unlock(&sport->port.lock); - - return IRQ_HANDLED; -} - -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int sa1100_tx_empty(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT; -} - -static unsigned int sa1100_get_mctrl(struct uart_port *port) -{ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -} - -static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -/* - * Interrupts always disabled. - */ -static void sa1100_break_ctl(struct uart_port *port, int break_state) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - unsigned long flags; - unsigned int utcr3; - - spin_lock_irqsave(&sport->port.lock, flags); - utcr3 = UART_GET_UTCR3(sport); - if (break_state == -1) - utcr3 |= UTCR3_BRK; - else - utcr3 &= ~UTCR3_BRK; - UART_PUT_UTCR3(sport, utcr3); - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static int sa1100_startup(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - int retval; - - /* - * Allocate the IRQ - */ - retval = request_irq(sport->port.irq, sa1100_int, 0, - "sa11x0-uart", sport); - if (retval) - return retval; - - /* - * Finally, clear and enable interrupts - */ - UART_PUT_UTSR0(sport, -1); - UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE); - - /* - * Enable modem status interrupts - */ - spin_lock_irq(&sport->port.lock); - sa1100_enable_ms(&sport->port); - spin_unlock_irq(&sport->port.lock); - - return 0; -} - -static void sa1100_shutdown(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - /* - * Stop our timer. - */ - del_timer_sync(&sport->timer); - - /* - * Free the interrupt - */ - free_irq(sport->port.irq, sport); - - /* - * Disable all interrupts, port and break condition. - */ - UART_PUT_UTCR3(sport, 0); -} - -static void -sa1100_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - unsigned long flags; - unsigned int utcr0, old_utcr3, baud, quot; - unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - - /* - * We only support CS7 and CS8. - */ - while ((termios->c_cflag & CSIZE) != CS7 && - (termios->c_cflag & CSIZE) != CS8) { - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= old_csize; - old_csize = CS8; - } - - if ((termios->c_cflag & CSIZE) == CS8) - utcr0 = UTCR0_DSS; - else - utcr0 = 0; - - if (termios->c_cflag & CSTOPB) - utcr0 |= UTCR0_SBS; - if (termios->c_cflag & PARENB) { - utcr0 |= UTCR0_PE; - if (!(termios->c_cflag & PARODD)) - utcr0 |= UTCR0_OES; - } - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS); - sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); - if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= - UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); - if (termios->c_iflag & (BRKINT | PARMRK)) - sport->port.read_status_mask |= - UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); - - /* - * Characters to ignore - */ - sport->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); - if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= - UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - UTSR1_TO_SM(UTSR1_ROR); - } - - del_timer_sync(&sport->timer); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * disable interrupts and drain transmitter - */ - old_utcr3 = UART_GET_UTCR3(sport); - UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)); - - while (UART_GET_UTSR1(sport) & UTSR1_TBY) - barrier(); - - /* then, disable everything */ - UART_PUT_UTCR3(sport, 0); - - /* set the parity, stop bits and data size */ - UART_PUT_UTCR0(sport, utcr0); - - /* set the baud rate */ - quot -= 1; - UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8)); - UART_PUT_UTCR2(sport, (quot & 0xff)); - - UART_PUT_UTSR0(sport, -1); - - UART_PUT_UTCR3(sport, old_utcr3); - - if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - sa1100_enable_ms(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *sa1100_type(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - return sport->port.type == PORT_SA1100 ? "SA1100" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void sa1100_release_port(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int sa1100_request_port(struct uart_port *port) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, - "sa11x0-uart") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void sa1100_config_port(struct uart_port *port, int flags) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - if (flags & UART_CONFIG_TYPE && - sa1100_request_port(&sport->port) == 0) - sport->port.type = PORT_SA1100; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_SA1100 and PORT_UNKNOWN - */ -static int -sa1100_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -static struct uart_ops sa1100_pops = { - .tx_empty = sa1100_tx_empty, - .set_mctrl = sa1100_set_mctrl, - .get_mctrl = sa1100_get_mctrl, - .stop_tx = sa1100_stop_tx, - .start_tx = sa1100_start_tx, - .stop_rx = sa1100_stop_rx, - .enable_ms = sa1100_enable_ms, - .break_ctl = sa1100_break_ctl, - .startup = sa1100_startup, - .shutdown = sa1100_shutdown, - .set_termios = sa1100_set_termios, - .type = sa1100_type, - .release_port = sa1100_release_port, - .request_port = sa1100_request_port, - .config_port = sa1100_config_port, - .verify_port = sa1100_verify_port, -}; - -static struct sa1100_port sa1100_ports[NR_PORTS]; - -/* - * Setup the SA1100 serial ports. Note that we don't include the IrDA - * port here since we have our own SIR/FIR driver (see drivers/net/irda) - * - * Note also that we support "console=ttySAx" where "x" is either 0 or 1. - * Which serial port this ends up being depends on the machine you're - * running this kernel on. I'm not convinced that this is a good idea, - * but that's the way it traditionally works. - * - * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer - * used here. - */ -static void __init sa1100_init_ports(void) -{ - static int first = 1; - int i; - - if (!first) - return; - first = 0; - - for (i = 0; i < NR_PORTS; i++) { - sa1100_ports[i].port.uartclk = 3686400; - sa1100_ports[i].port.ops = &sa1100_pops; - sa1100_ports[i].port.fifosize = 8; - sa1100_ports[i].port.line = i; - sa1100_ports[i].port.iotype = UPIO_MEM; - init_timer(&sa1100_ports[i].timer); - sa1100_ports[i].timer.function = sa1100_timeout; - sa1100_ports[i].timer.data = (unsigned long)&sa1100_ports[i]; - } - - /* - * make transmit lines outputs, so that when the port - * is closed, the output is in the MARK state. - */ - PPDR |= PPC_TXD1 | PPC_TXD3; - PPSR |= PPC_TXD1 | PPC_TXD3; -} - -void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns) -{ - if (fns->get_mctrl) - sa1100_pops.get_mctrl = fns->get_mctrl; - if (fns->set_mctrl) - sa1100_pops.set_mctrl = fns->set_mctrl; - - sa1100_pops.pm = fns->pm; - sa1100_pops.set_wake = fns->set_wake; -} - -void __init sa1100_register_uart(int idx, int port) -{ - if (idx >= NR_PORTS) { - printk(KERN_ERR "%s: bad index number %d\n", __func__, idx); - return; - } - - switch (port) { - case 1: - sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0; - sa1100_ports[idx].port.mapbase = _Ser1UTCR0; - sa1100_ports[idx].port.irq = IRQ_Ser1UART; - sa1100_ports[idx].port.flags = UPF_BOOT_AUTOCONF; - break; - - case 2: - sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0; - sa1100_ports[idx].port.mapbase = _Ser2UTCR0; - sa1100_ports[idx].port.irq = IRQ_Ser2ICP; - sa1100_ports[idx].port.flags = UPF_BOOT_AUTOCONF; - break; - - case 3: - sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0; - sa1100_ports[idx].port.mapbase = _Ser3UTCR0; - sa1100_ports[idx].port.irq = IRQ_Ser3UART; - sa1100_ports[idx].port.flags = UPF_BOOT_AUTOCONF; - break; - - default: - printk(KERN_ERR "%s: bad port number %d\n", __func__, port); - } -} - - -#ifdef CONFIG_SERIAL_SA1100_CONSOLE -static void sa1100_console_putchar(struct uart_port *port, int ch) -{ - struct sa1100_port *sport = (struct sa1100_port *)port; - - while (!(UART_GET_UTSR1(sport) & UTSR1_TNF)) - barrier(); - UART_PUT_CHAR(sport, ch); -} - -/* - * Interrupts are disabled on entering - */ -static void -sa1100_console_write(struct console *co, const char *s, unsigned int count) -{ - struct sa1100_port *sport = &sa1100_ports[co->index]; - unsigned int old_utcr3, status; - - /* - * First, save UTCR3 and then disable interrupts - */ - old_utcr3 = UART_GET_UTCR3(sport); - UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) | - UTCR3_TXE); - - uart_console_write(&sport->port, s, count, sa1100_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore UTCR3 - */ - do { - status = UART_GET_UTSR1(sport); - } while (status & UTSR1_TBY); - UART_PUT_UTCR3(sport, old_utcr3); -} - -/* - * If the port was already initialised (eg, by a boot loader), - * try to determine the current setup. - */ -static void __init -sa1100_console_get_options(struct sa1100_port *sport, int *baud, - int *parity, int *bits) -{ - unsigned int utcr3; - - utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE); - if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) { - /* ok, the port was enabled */ - unsigned int utcr0, quot; - - utcr0 = UART_GET_UTCR0(sport); - - *parity = 'n'; - if (utcr0 & UTCR0_PE) { - if (utcr0 & UTCR0_OES) - *parity = 'e'; - else - *parity = 'o'; - } - - if (utcr0 & UTCR0_DSS) - *bits = 8; - else - *bits = 7; - - quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8; - quot &= 0xfff; - *baud = sport->port.uartclk / (16 * (quot + 1)); - } -} - -static int __init -sa1100_console_setup(struct console *co, char *options) -{ - struct sa1100_port *sport; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= NR_PORTS) - co->index = 0; - sport = &sa1100_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - sa1100_console_get_options(sport, &baud, &parity, &bits); - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver sa1100_reg; -static struct console sa1100_console = { - .name = "ttySA", - .write = sa1100_console_write, - .device = uart_console_device, - .setup = sa1100_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sa1100_reg, -}; - -static int __init sa1100_rs_console_init(void) -{ - sa1100_init_ports(); - register_console(&sa1100_console); - return 0; -} -console_initcall(sa1100_rs_console_init); - -#define SA1100_CONSOLE &sa1100_console -#else -#define SA1100_CONSOLE NULL -#endif - -static struct uart_driver sa1100_reg = { - .owner = THIS_MODULE, - .driver_name = "ttySA", - .dev_name = "ttySA", - .major = SERIAL_SA1100_MAJOR, - .minor = MINOR_START, - .nr = NR_PORTS, - .cons = SA1100_CONSOLE, -}; - -static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state) -{ - struct sa1100_port *sport = platform_get_drvdata(dev); - - if (sport) - uart_suspend_port(&sa1100_reg, &sport->port); - - return 0; -} - -static int sa1100_serial_resume(struct platform_device *dev) -{ - struct sa1100_port *sport = platform_get_drvdata(dev); - - if (sport) - uart_resume_port(&sa1100_reg, &sport->port); - - return 0; -} - -static int sa1100_serial_probe(struct platform_device *dev) -{ - struct resource *res = dev->resource; - int i; - - for (i = 0; i < dev->num_resources; i++, res++) - if (res->flags & IORESOURCE_MEM) - break; - - if (i < dev->num_resources) { - for (i = 0; i < NR_PORTS; i++) { - if (sa1100_ports[i].port.mapbase != res->start) - continue; - - sa1100_ports[i].port.dev = &dev->dev; - uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port); - platform_set_drvdata(dev, &sa1100_ports[i]); - break; - } - } - - return 0; -} - -static int sa1100_serial_remove(struct platform_device *pdev) -{ - struct sa1100_port *sport = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (sport) - uart_remove_one_port(&sa1100_reg, &sport->port); - - return 0; -} - -static struct platform_driver sa11x0_serial_driver = { - .probe = sa1100_serial_probe, - .remove = sa1100_serial_remove, - .suspend = sa1100_serial_suspend, - .resume = sa1100_serial_resume, - .driver = { - .name = "sa11x0-uart", - .owner = THIS_MODULE, - }, -}; - -static int __init sa1100_serial_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: SA11x0 driver\n"); - - sa1100_init_ports(); - - ret = uart_register_driver(&sa1100_reg); - if (ret == 0) { - ret = platform_driver_register(&sa11x0_serial_driver); - if (ret) - uart_unregister_driver(&sa1100_reg); - } - return ret; -} - -static void __exit sa1100_serial_exit(void) -{ - platform_driver_unregister(&sa11x0_serial_driver); - uart_unregister_driver(&sa1100_reg); -} - -module_init(sa1100_serial_init); -module_exit(sa1100_serial_exit); - -MODULE_AUTHOR("Deep Blue Solutions Ltd"); -MODULE_DESCRIPTION("SA1100 generic serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR); -MODULE_ALIAS("platform:sa11x0-uart"); diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c deleted file mode 100644 index 7ac2bf5167cd..000000000000 --- a/drivers/serial/samsung.c +++ /dev/null @@ -1,1487 +0,0 @@ -/* linux/drivers/serial/samsuing.c - * - * Driver core for Samsung SoC onboard UARTs. - * - * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -/* Hote on 2410 error handling - * - * The s3c2410 manual has a love/hate affair with the contents of the - * UERSTAT register in the UART blocks, and keeps marking some of the - * error bits as reserved. Having checked with the s3c2410x01, - * it copes with BREAKs properly, so I am happy to ignore the RESERVED - * feature from the latter versions of the manual. - * - * If it becomes aparrent that latter versions of the 2410 remove these - * bits, then action will have to be taken to differentiate the versions - * and change the policy on BREAK - * - * BJD, 04-Nov-2004 -*/ - -#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include "samsung.h" - -/* UART name and device definitions */ - -#define S3C24XX_SERIAL_NAME "ttySAC" -#define S3C24XX_SERIAL_MAJOR 204 -#define S3C24XX_SERIAL_MINOR 64 - -/* macros to change one thing to another */ - -#define tx_enabled(port) ((port)->unused[0]) -#define rx_enabled(port) ((port)->unused[1]) - -/* flag to ignore all characters comming in */ -#define RXSTAT_DUMMY_READ (0x10000000) - -static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port) -{ - return container_of(port, struct s3c24xx_uart_port, port); -} - -/* translate a port to the device name */ - -static inline const char *s3c24xx_serial_portname(struct uart_port *port) -{ - return to_platform_device(port->dev)->name; -} - -static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) -{ - return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE); -} - -static void s3c24xx_serial_rx_enable(struct uart_port *port) -{ - unsigned long flags; - unsigned int ucon, ufcon; - int count = 10000; - - spin_lock_irqsave(&port->lock, flags); - - while (--count && !s3c24xx_serial_txempty_nofifo(port)) - udelay(100); - - ufcon = rd_regl(port, S3C2410_UFCON); - ufcon |= S3C2410_UFCON_RESETRX; - wr_regl(port, S3C2410_UFCON, ufcon); - - ucon = rd_regl(port, S3C2410_UCON); - ucon |= S3C2410_UCON_RXIRQMODE; - wr_regl(port, S3C2410_UCON, ucon); - - rx_enabled(port) = 1; - spin_unlock_irqrestore(&port->lock, flags); -} - -static void s3c24xx_serial_rx_disable(struct uart_port *port) -{ - unsigned long flags; - unsigned int ucon; - - spin_lock_irqsave(&port->lock, flags); - - ucon = rd_regl(port, S3C2410_UCON); - ucon &= ~S3C2410_UCON_RXIRQMODE; - wr_regl(port, S3C2410_UCON, ucon); - - rx_enabled(port) = 0; - spin_unlock_irqrestore(&port->lock, flags); -} - -static void s3c24xx_serial_stop_tx(struct uart_port *port) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - - if (tx_enabled(port)) { - disable_irq_nosync(ourport->tx_irq); - tx_enabled(port) = 0; - if (port->flags & UPF_CONS_FLOW) - s3c24xx_serial_rx_enable(port); - } -} - -static void s3c24xx_serial_start_tx(struct uart_port *port) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - - if (!tx_enabled(port)) { - if (port->flags & UPF_CONS_FLOW) - s3c24xx_serial_rx_disable(port); - - enable_irq(ourport->tx_irq); - tx_enabled(port) = 1; - } -} - - -static void s3c24xx_serial_stop_rx(struct uart_port *port) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - - if (rx_enabled(port)) { - dbg("s3c24xx_serial_stop_rx: port=%p\n", port); - disable_irq_nosync(ourport->rx_irq); - rx_enabled(port) = 0; - } -} - -static void s3c24xx_serial_enable_ms(struct uart_port *port) -{ -} - -static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port) -{ - return to_ourport(port)->info; -} - -static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port) -{ - if (port->dev == NULL) - return NULL; - - return (struct s3c2410_uartcfg *)port->dev->platform_data; -} - -static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, - unsigned long ufstat) -{ - struct s3c24xx_uart_info *info = ourport->info; - - if (ufstat & info->rx_fifofull) - return info->fifosize; - - return (ufstat & info->rx_fifomask) >> info->rx_fifoshift; -} - - -/* ? - where has parity gone?? */ -#define S3C2410_UERSTAT_PARITY (0x1000) - -static irqreturn_t -s3c24xx_serial_rx_chars(int irq, void *dev_id) -{ - struct s3c24xx_uart_port *ourport = dev_id; - struct uart_port *port = &ourport->port; - struct tty_struct *tty = port->state->port.tty; - unsigned int ufcon, ch, flag, ufstat, uerstat; - int max_count = 64; - - while (max_count-- > 0) { - ufcon = rd_regl(port, S3C2410_UFCON); - ufstat = rd_regl(port, S3C2410_UFSTAT); - - if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) - break; - - uerstat = rd_regl(port, S3C2410_UERSTAT); - ch = rd_regb(port, S3C2410_URXH); - - if (port->flags & UPF_CONS_FLOW) { - int txe = s3c24xx_serial_txempty_nofifo(port); - - if (rx_enabled(port)) { - if (!txe) { - rx_enabled(port) = 0; - continue; - } - } else { - if (txe) { - ufcon |= S3C2410_UFCON_RESETRX; - wr_regl(port, S3C2410_UFCON, ufcon); - rx_enabled(port) = 1; - goto out; - } - continue; - } - } - - /* insert the character into the buffer */ - - flag = TTY_NORMAL; - port->icount.rx++; - - if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { - dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", - ch, uerstat); - - /* check for break */ - if (uerstat & S3C2410_UERSTAT_BREAK) { - dbg("break!\n"); - port->icount.brk++; - if (uart_handle_break(port)) - goto ignore_char; - } - - if (uerstat & S3C2410_UERSTAT_FRAME) - port->icount.frame++; - if (uerstat & S3C2410_UERSTAT_OVERRUN) - port->icount.overrun++; - - uerstat &= port->read_status_mask; - - if (uerstat & S3C2410_UERSTAT_BREAK) - flag = TTY_BREAK; - else if (uerstat & S3C2410_UERSTAT_PARITY) - flag = TTY_PARITY; - else if (uerstat & (S3C2410_UERSTAT_FRAME | - S3C2410_UERSTAT_OVERRUN)) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, - ch, flag); - - ignore_char: - continue; - } - tty_flip_buffer_push(tty); - - out: - return IRQ_HANDLED; -} - -static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) -{ - struct s3c24xx_uart_port *ourport = id; - struct uart_port *port = &ourport->port; - struct circ_buf *xmit = &port->state->xmit; - int count = 256; - - if (port->x_char) { - wr_regb(port, S3C2410_UTXH, port->x_char); - port->icount.tx++; - port->x_char = 0; - goto out; - } - - /* if there isnt anything more to transmit, or the uart is now - * stopped, disable the uart and exit - */ - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - s3c24xx_serial_stop_tx(port); - goto out; - } - - /* try and drain the buffer... */ - - while (!uart_circ_empty(xmit) && count-- > 0) { - if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) - break; - - wr_regb(port, S3C2410_UTXH, 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); - - if (uart_circ_empty(xmit)) - s3c24xx_serial_stop_tx(port); - - out: - return IRQ_HANDLED; -} - -static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); - unsigned long ufcon = rd_regl(port, S3C2410_UFCON); - - if (ufcon & S3C2410_UFCON_FIFOMODE) { - if ((ufstat & info->tx_fifomask) != 0 || - (ufstat & info->tx_fifofull)) - return 0; - - return 1; - } - - return s3c24xx_serial_txempty_nofifo(port); -} - -/* no modem control lines */ -static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) -{ - unsigned int umstat = rd_regb(port, S3C2410_UMSTAT); - - if (umstat & S3C2410_UMSTAT_CTS) - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; - else - return TIOCM_CAR | TIOCM_DSR; -} - -static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* todo - possibly remove AFC and do manual CTS */ -} - -static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) -{ - unsigned long flags; - unsigned int ucon; - - spin_lock_irqsave(&port->lock, flags); - - ucon = rd_regl(port, S3C2410_UCON); - - if (break_state) - ucon |= S3C2410_UCON_SBREAK; - else - ucon &= ~S3C2410_UCON_SBREAK; - - wr_regl(port, S3C2410_UCON, ucon); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void s3c24xx_serial_shutdown(struct uart_port *port) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - - if (ourport->tx_claimed) { - free_irq(ourport->tx_irq, ourport); - tx_enabled(port) = 0; - ourport->tx_claimed = 0; - } - - if (ourport->rx_claimed) { - free_irq(ourport->rx_irq, ourport); - ourport->rx_claimed = 0; - rx_enabled(port) = 0; - } -} - - -static int s3c24xx_serial_startup(struct uart_port *port) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - int ret; - - dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", - port->mapbase, port->membase); - - rx_enabled(port) = 1; - - ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, - s3c24xx_serial_portname(port), ourport); - - if (ret != 0) { - printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); - return ret; - } - - ourport->rx_claimed = 1; - - dbg("requesting tx irq...\n"); - - tx_enabled(port) = 1; - - ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, - s3c24xx_serial_portname(port), ourport); - - if (ret) { - printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); - goto err; - } - - ourport->tx_claimed = 1; - - dbg("s3c24xx_serial_startup ok\n"); - - /* the port reset code should have done the correct - * register setup for the port controls */ - - return ret; - - err: - s3c24xx_serial_shutdown(port); - return ret; -} - -/* power power management control */ - -static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, - unsigned int old) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - - ourport->pm_level = level; - - switch (level) { - case 3: - if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) - clk_disable(ourport->baudclk); - - clk_disable(ourport->clk); - break; - - case 0: - clk_enable(ourport->clk); - - if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) - clk_enable(ourport->baudclk); - - break; - default: - printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level); - } -} - -/* baud rate calculation - * - * The UARTs on the S3C2410/S3C2440 can take their clocks from a number - * of different sources, including the peripheral clock ("pclk") and an - * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk") - * with a programmable extra divisor. - * - * The following code goes through the clock sources, and calculates the - * baud clocks (and the resultant actual baud rates) and then tries to - * pick the closest one and select that. - * -*/ - - -#define MAX_CLKS (8) - -static struct s3c24xx_uart_clksrc tmp_clksrc = { - .name = "pclk", - .min_baud = 0, - .max_baud = 0, - .divisor = 1, -}; - -static inline int -s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - - return (info->get_clksrc)(port, c); -} - -static inline int -s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - - return (info->set_clksrc)(port, c); -} - -struct baud_calc { - struct s3c24xx_uart_clksrc *clksrc; - unsigned int calc; - unsigned int divslot; - unsigned int quot; - struct clk *src; -}; - -static int s3c24xx_serial_calcbaud(struct baud_calc *calc, - struct uart_port *port, - struct s3c24xx_uart_clksrc *clksrc, - unsigned int baud) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - unsigned long rate; - - calc->src = clk_get(port->dev, clksrc->name); - if (calc->src == NULL || IS_ERR(calc->src)) - return 0; - - rate = clk_get_rate(calc->src); - rate /= clksrc->divisor; - - calc->clksrc = clksrc; - - if (ourport->info->has_divslot) { - unsigned long div = rate / baud; - - /* The UDIVSLOT register on the newer UARTs allows us to - * get a divisor adjustment of 1/16th on the baud clock. - * - * We don't keep the UDIVSLOT value (the 16ths we calculated - * by not multiplying the baud by 16) as it is easy enough - * to recalculate. - */ - - calc->quot = div / 16; - calc->calc = rate / div; - } else { - calc->quot = (rate + (8 * baud)) / (16 * baud); - calc->calc = (rate / (calc->quot * 16)); - } - - calc->quot--; - return 1; -} - -static unsigned int s3c24xx_serial_getclk(struct uart_port *port, - struct s3c24xx_uart_clksrc **clksrc, - struct clk **clk, - unsigned int baud) -{ - struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); - struct s3c24xx_uart_clksrc *clkp; - struct baud_calc res[MAX_CLKS]; - struct baud_calc *resptr, *best, *sptr; - int i; - - clkp = cfg->clocks; - best = NULL; - - if (cfg->clocks_size < 2) { - if (cfg->clocks_size == 0) - clkp = &tmp_clksrc; - - /* check to see if we're sourcing fclk, and if so we're - * going to have to update the clock source - */ - - if (strcmp(clkp->name, "fclk") == 0) { - struct s3c24xx_uart_clksrc src; - - s3c24xx_serial_getsource(port, &src); - - /* check that the port already using fclk, and if - * not, then re-select fclk - */ - - if (strcmp(src.name, clkp->name) == 0) { - s3c24xx_serial_setsource(port, clkp); - s3c24xx_serial_getsource(port, &src); - } - - clkp->divisor = src.divisor; - } - - s3c24xx_serial_calcbaud(res, port, clkp, baud); - best = res; - resptr = best + 1; - } else { - resptr = res; - - for (i = 0; i < cfg->clocks_size; i++, clkp++) { - if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud)) - resptr++; - } - } - - /* ok, we now need to select the best clock we found */ - - if (!best) { - unsigned int deviation = (1<<30)|((1<<30)-1); - int calc_deviation; - - for (sptr = res; sptr < resptr; sptr++) { - calc_deviation = baud - sptr->calc; - if (calc_deviation < 0) - calc_deviation = -calc_deviation; - - if (calc_deviation < deviation) { - best = sptr; - deviation = calc_deviation; - } - } - } - - /* store results to pass back */ - - *clksrc = best->clksrc; - *clk = best->src; - - return best->quot; -} - -/* udivslot_table[] - * - * This table takes the fractional value of the baud divisor and gives - * the recommended setting for the UDIVSLOT register. - */ -static u16 udivslot_table[16] = { - [0] = 0x0000, - [1] = 0x0080, - [2] = 0x0808, - [3] = 0x0888, - [4] = 0x2222, - [5] = 0x4924, - [6] = 0x4A52, - [7] = 0x54AA, - [8] = 0x5555, - [9] = 0xD555, - [10] = 0xD5D5, - [11] = 0xDDD5, - [12] = 0xDDDD, - [13] = 0xDFDD, - [14] = 0xDFDF, - [15] = 0xFFDF, -}; - -static void s3c24xx_serial_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); - struct s3c24xx_uart_port *ourport = to_ourport(port); - struct s3c24xx_uart_clksrc *clksrc = NULL; - struct clk *clk = NULL; - unsigned long flags; - unsigned int baud, quot; - unsigned int ulcon; - unsigned int umcon; - unsigned int udivslot = 0; - - /* - * We don't support modem control lines. - */ - termios->c_cflag &= ~(HUPCL | CMSPAR); - termios->c_cflag |= CLOCAL; - - /* - * Ask the core to calculate the divisor for us. - */ - - baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); - - if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) - quot = port->custom_divisor; - else - quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); - - /* check to see if we need to change clock source */ - - if (ourport->clksrc != clksrc || ourport->baudclk != clk) { - dbg("selecting clock %p\n", clk); - s3c24xx_serial_setsource(port, clksrc); - - if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { - clk_disable(ourport->baudclk); - ourport->baudclk = NULL; - } - - clk_enable(clk); - - ourport->clksrc = clksrc; - ourport->baudclk = clk; - ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; - } - - if (ourport->info->has_divslot) { - unsigned int div = ourport->baudclk_rate / baud; - - if (cfg->has_fracval) { - udivslot = (div & 15); - dbg("fracval = %04x\n", udivslot); - } else { - udivslot = udivslot_table[div & 15]; - dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); - } - } - - switch (termios->c_cflag & CSIZE) { - case CS5: - dbg("config: 5bits/char\n"); - ulcon = S3C2410_LCON_CS5; - break; - case CS6: - dbg("config: 6bits/char\n"); - ulcon = S3C2410_LCON_CS6; - break; - case CS7: - dbg("config: 7bits/char\n"); - ulcon = S3C2410_LCON_CS7; - break; - case CS8: - default: - dbg("config: 8bits/char\n"); - ulcon = S3C2410_LCON_CS8; - break; - } - - /* preserve original lcon IR settings */ - ulcon |= (cfg->ulcon & S3C2410_LCON_IRM); - - if (termios->c_cflag & CSTOPB) - ulcon |= S3C2410_LCON_STOPB; - - umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; - - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & PARODD) - ulcon |= S3C2410_LCON_PODD; - else - ulcon |= S3C2410_LCON_PEVEN; - } else { - ulcon |= S3C2410_LCON_PNONE; - } - - spin_lock_irqsave(&port->lock, flags); - - dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", - ulcon, quot, udivslot); - - wr_regl(port, S3C2410_ULCON, ulcon); - wr_regl(port, S3C2410_UBRDIV, quot); - wr_regl(port, S3C2410_UMCON, umcon); - - if (ourport->info->has_divslot) - wr_regl(port, S3C2443_DIVSLOT, udivslot); - - dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", - rd_regl(port, S3C2410_ULCON), - rd_regl(port, S3C2410_UCON), - rd_regl(port, S3C2410_UFCON)); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * Which character status flags are we interested in? - */ - port->read_status_mask = S3C2410_UERSTAT_OVERRUN; - if (termios->c_iflag & INPCK) - port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY; - - /* - * Which character status flags should we ignore? - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN; - if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) - port->ignore_status_mask |= S3C2410_UERSTAT_FRAME; - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= RXSTAT_DUMMY_READ; - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *s3c24xx_serial_type(struct uart_port *port) -{ - switch (port->type) { - case PORT_S3C2410: - return "S3C2410"; - case PORT_S3C2440: - return "S3C2440"; - case PORT_S3C2412: - return "S3C2412"; - case PORT_S3C6400: - return "S3C6400/10"; - default: - return NULL; - } -} - -#define MAP_SIZE (0x100) - -static void s3c24xx_serial_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, MAP_SIZE); -} - -static int s3c24xx_serial_request_port(struct uart_port *port) -{ - const char *name = s3c24xx_serial_portname(port); - return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY; -} - -static void s3c24xx_serial_config_port(struct uart_port *port, int flags) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - - if (flags & UART_CONFIG_TYPE && - s3c24xx_serial_request_port(port) == 0) - port->type = info->type; -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int -s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - - if (ser->type != PORT_UNKNOWN && ser->type != info->type) - return -EINVAL; - - return 0; -} - - -#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE - -static struct console s3c24xx_serial_console; - -#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console -#else -#define S3C24XX_SERIAL_CONSOLE NULL -#endif - -static struct uart_ops s3c24xx_serial_ops = { - .pm = s3c24xx_serial_pm, - .tx_empty = s3c24xx_serial_tx_empty, - .get_mctrl = s3c24xx_serial_get_mctrl, - .set_mctrl = s3c24xx_serial_set_mctrl, - .stop_tx = s3c24xx_serial_stop_tx, - .start_tx = s3c24xx_serial_start_tx, - .stop_rx = s3c24xx_serial_stop_rx, - .enable_ms = s3c24xx_serial_enable_ms, - .break_ctl = s3c24xx_serial_break_ctl, - .startup = s3c24xx_serial_startup, - .shutdown = s3c24xx_serial_shutdown, - .set_termios = s3c24xx_serial_set_termios, - .type = s3c24xx_serial_type, - .release_port = s3c24xx_serial_release_port, - .request_port = s3c24xx_serial_request_port, - .config_port = s3c24xx_serial_config_port, - .verify_port = s3c24xx_serial_verify_port, -}; - - -static struct uart_driver s3c24xx_uart_drv = { - .owner = THIS_MODULE, - .dev_name = "s3c2410_serial", - .nr = CONFIG_SERIAL_SAMSUNG_UARTS, - .cons = S3C24XX_SERIAL_CONSOLE, - .driver_name = S3C24XX_SERIAL_NAME, - .major = S3C24XX_SERIAL_MAJOR, - .minor = S3C24XX_SERIAL_MINOR, -}; - -static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { - [0] = { - .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), - .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX0, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - } - }, - [1] = { - .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), - .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX1, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - } - }, -#if CONFIG_SERIAL_SAMSUNG_UARTS > 2 - - [2] = { - .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), - .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX2, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - } - }, -#endif -#if CONFIG_SERIAL_SAMSUNG_UARTS > 3 - [3] = { - .port = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), - .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX3, - .uartclk = 0, - .fifosize = 16, - .ops = &s3c24xx_serial_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 3, - } - } -#endif -}; - -/* s3c24xx_serial_resetport - * - * wrapper to call the specific reset for this port (reset the fifos - * and the settings) -*/ - -static inline int s3c24xx_serial_resetport(struct uart_port *port, - struct s3c2410_uartcfg *cfg) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - - return (info->reset_port)(port, cfg); -} - - -#ifdef CONFIG_CPU_FREQ - -static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c24xx_uart_port *port; - struct uart_port *uport; - - port = container_of(nb, struct s3c24xx_uart_port, freq_transition); - uport = &port->port; - - /* check to see if port is enabled */ - - if (port->pm_level != 0) - return 0; - - /* try and work out if the baudrate is changing, we can detect - * a change in rate, but we do not have support for detecting - * a disturbance in the clock-rate over the change. - */ - - if (IS_ERR(port->clk)) - goto exit; - - if (port->baudclk_rate == clk_get_rate(port->clk)) - goto exit; - - if (val == CPUFREQ_PRECHANGE) { - /* we should really shut the port down whilst the - * frequency change is in progress. */ - - } else if (val == CPUFREQ_POSTCHANGE) { - struct ktermios *termios; - struct tty_struct *tty; - - if (uport->state == NULL) - goto exit; - - tty = uport->state->port.tty; - - if (tty == NULL) - goto exit; - - termios = tty->termios; - - if (termios == NULL) { - printk(KERN_WARNING "%s: no termios?\n", __func__); - goto exit; - } - - s3c24xx_serial_set_termios(uport, termios, NULL); - } - - exit: - return 0; -} - -static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) -{ - port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition; - - return cpufreq_register_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) -{ - cpufreq_unregister_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) -{ - return 0; -} - -static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) -{ -} -#endif - -/* s3c24xx_serial_init_port - * - * initialise a single serial port from the platform device given - */ - -static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, - struct s3c24xx_uart_info *info, - struct platform_device *platdev) -{ - struct uart_port *port = &ourport->port; - struct s3c2410_uartcfg *cfg; - struct resource *res; - int ret; - - dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev); - - if (platdev == NULL) - return -ENODEV; - - cfg = s3c24xx_dev_to_cfg(&platdev->dev); - - if (port->mapbase != 0) - return 0; - - if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) { - printk(KERN_ERR "%s: port %d bigger than %d\n", __func__, - cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS); - return -ERANGE; - } - - /* setup info for port */ - port->dev = &platdev->dev; - ourport->info = info; - - /* copy the info in from provided structure */ - ourport->port.fifosize = info->fifosize; - - dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport); - - port->uartclk = 1; - - if (cfg->uart_flags & UPF_CONS_FLOW) { - dbg("s3c24xx_serial_init_port: enabling flow control\n"); - port->flags |= UPF_CONS_FLOW; - } - - /* sort our the physical and virtual addresses for each UART */ - - res = platform_get_resource(platdev, IORESOURCE_MEM, 0); - if (res == NULL) { - printk(KERN_ERR "failed to find memory resource for uart\n"); - return -EINVAL; - } - - dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); - - port->mapbase = res->start; - port->membase = S3C_VA_UART + (res->start & 0xfffff); - ret = platform_get_irq(platdev, 0); - if (ret < 0) - port->irq = 0; - else { - port->irq = ret; - ourport->rx_irq = ret; - ourport->tx_irq = ret + 1; - } - - ret = platform_get_irq(platdev, 1); - if (ret > 0) - ourport->tx_irq = ret; - - ourport->clk = clk_get(&platdev->dev, "uart"); - - dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", - port->mapbase, port->membase, port->irq, - ourport->rx_irq, ourport->tx_irq, port->uartclk); - - /* reset the fifos (and setup the uart) */ - s3c24xx_serial_resetport(port, cfg); - return 0; -} - -static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct uart_port *port = s3c24xx_dev_to_port(dev); - struct s3c24xx_uart_port *ourport = to_ourport(port); - - return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name); -} - -static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); - -/* Device driver serial port probe */ - -static int probe_index; - -int s3c24xx_serial_probe(struct platform_device *dev, - struct s3c24xx_uart_info *info) -{ - struct s3c24xx_uart_port *ourport; - int ret; - - dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index); - - ourport = &s3c24xx_serial_ports[probe_index]; - probe_index++; - - dbg("%s: initialising port %p...\n", __func__, ourport); - - ret = s3c24xx_serial_init_port(ourport, info, dev); - if (ret < 0) - goto probe_err; - - dbg("%s: adding port\n", __func__); - uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); - platform_set_drvdata(dev, &ourport->port); - - ret = device_create_file(&dev->dev, &dev_attr_clock_source); - if (ret < 0) - printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); - - ret = s3c24xx_serial_cpufreq_register(ourport); - if (ret < 0) - dev_err(&dev->dev, "failed to add cpufreq notifier\n"); - - return 0; - - probe_err: - return ret; -} - -EXPORT_SYMBOL_GPL(s3c24xx_serial_probe); - -int __devexit s3c24xx_serial_remove(struct platform_device *dev) -{ - struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); - - if (port) { - s3c24xx_serial_cpufreq_deregister(to_ourport(port)); - device_remove_file(&dev->dev, &dev_attr_clock_source); - uart_remove_one_port(&s3c24xx_uart_drv, port); - } - - return 0; -} - -EXPORT_SYMBOL_GPL(s3c24xx_serial_remove); - -/* UART power management code */ - -#ifdef CONFIG_PM - -static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state) -{ - struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); - - if (port) - uart_suspend_port(&s3c24xx_uart_drv, port); - - return 0; -} - -static int s3c24xx_serial_resume(struct platform_device *dev) -{ - struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); - struct s3c24xx_uart_port *ourport = to_ourport(port); - - if (port) { - clk_enable(ourport->clk); - s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); - clk_disable(ourport->clk); - - uart_resume_port(&s3c24xx_uart_drv, port); - } - - return 0; -} -#endif - -int s3c24xx_serial_init(struct platform_driver *drv, - struct s3c24xx_uart_info *info) -{ - dbg("s3c24xx_serial_init(%p,%p)\n", drv, info); - -#ifdef CONFIG_PM - drv->suspend = s3c24xx_serial_suspend; - drv->resume = s3c24xx_serial_resume; -#endif - - return platform_driver_register(drv); -} - -EXPORT_SYMBOL_GPL(s3c24xx_serial_init); - -/* module initialisation code */ - -static int __init s3c24xx_serial_modinit(void) -{ - int ret; - - ret = uart_register_driver(&s3c24xx_uart_drv); - if (ret < 0) { - printk(KERN_ERR "failed to register UART driver\n"); - return -1; - } - - return 0; -} - -static void __exit s3c24xx_serial_modexit(void) -{ - uart_unregister_driver(&s3c24xx_uart_drv); -} - -module_init(s3c24xx_serial_modinit); -module_exit(s3c24xx_serial_modexit); - -/* Console code */ - -#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE - -static struct uart_port *cons_uart; - -static int -s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) -{ - struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - unsigned long ufstat, utrstat; - - if (ufcon & S3C2410_UFCON_FIFOMODE) { - /* fifo mode - check amount of data in fifo registers... */ - - ufstat = rd_regl(port, S3C2410_UFSTAT); - return (ufstat & info->tx_fifofull) ? 0 : 1; - } - - /* in non-fifo mode, we go and use the tx buffer empty */ - - utrstat = rd_regl(port, S3C2410_UTRSTAT); - return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0; -} - -static void -s3c24xx_serial_console_putchar(struct uart_port *port, int ch) -{ - unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); - while (!s3c24xx_serial_console_txrdy(port, ufcon)) - barrier(); - wr_regb(cons_uart, S3C2410_UTXH, ch); -} - -static void -s3c24xx_serial_console_write(struct console *co, const char *s, - unsigned int count) -{ - uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); -} - -static void __init -s3c24xx_serial_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - struct s3c24xx_uart_clksrc clksrc; - struct clk *clk; - unsigned int ulcon; - unsigned int ucon; - unsigned int ubrdiv; - unsigned long rate; - - ulcon = rd_regl(port, S3C2410_ULCON); - ucon = rd_regl(port, S3C2410_UCON); - ubrdiv = rd_regl(port, S3C2410_UBRDIV); - - dbg("s3c24xx_serial_get_options: port=%p\n" - "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n", - port, ulcon, ucon, ubrdiv); - - if ((ucon & 0xf) != 0) { - /* consider the serial port configured if the tx/rx mode set */ - - switch (ulcon & S3C2410_LCON_CSMASK) { - case S3C2410_LCON_CS5: - *bits = 5; - break; - case S3C2410_LCON_CS6: - *bits = 6; - break; - case S3C2410_LCON_CS7: - *bits = 7; - break; - default: - case S3C2410_LCON_CS8: - *bits = 8; - break; - } - - switch (ulcon & S3C2410_LCON_PMASK) { - case S3C2410_LCON_PEVEN: - *parity = 'e'; - break; - - case S3C2410_LCON_PODD: - *parity = 'o'; - break; - - case S3C2410_LCON_PNONE: - default: - *parity = 'n'; - } - - /* now calculate the baud rate */ - - s3c24xx_serial_getsource(port, &clksrc); - - clk = clk_get(port->dev, clksrc.name); - if (!IS_ERR(clk) && clk != NULL) - rate = clk_get_rate(clk) / clksrc.divisor; - else - rate = 1; - - - *baud = rate / (16 * (ubrdiv + 1)); - dbg("calculated baud %d\n", *baud); - } - -} - -/* s3c24xx_serial_init_ports - * - * initialise the serial ports from the machine provided initialisation - * data. -*/ - -static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info) -{ - struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports; - struct platform_device **platdev_ptr; - int i; - - dbg("s3c24xx_serial_init_ports: initialising ports...\n"); - - platdev_ptr = s3c24xx_uart_devs; - - for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) { - s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr); - } - - return 0; -} - -static int __init -s3c24xx_serial_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n", - co, co->index, options); - - /* is this a valid port */ - - if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS) - co->index = 0; - - port = &s3c24xx_serial_ports[co->index].port; - - /* is the port configured? */ - - if (port->mapbase == 0x0) { - co->index = 0; - port = &s3c24xx_serial_ports[co->index].port; - } - - cons_uart = port; - - dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index); - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - s3c24xx_serial_get_options(port, &baud, &parity, &bits); - - dbg("s3c24xx_serial_console_setup: baud %d\n", baud); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -/* s3c24xx_serial_initconsole - * - * initialise the console from one of the uart drivers -*/ - -static struct console s3c24xx_serial_console = { - .name = S3C24XX_SERIAL_NAME, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .index = -1, - .write = s3c24xx_serial_console_write, - .setup = s3c24xx_serial_console_setup -}; - -int s3c24xx_serial_initconsole(struct platform_driver *drv, - struct s3c24xx_uart_info **info) - -{ - struct platform_device *dev = s3c24xx_uart_devs[0]; - - dbg("s3c24xx_serial_initconsole\n"); - - /* select driver based on the cpu */ - - if (dev == NULL) { - printk(KERN_ERR "s3c24xx: no devices for console init\n"); - return 0; - } - - if (strcmp(dev->name, drv->driver.name) != 0) - return 0; - - s3c24xx_serial_console.data = &s3c24xx_uart_drv; - s3c24xx_serial_init_ports(info); - - register_console(&s3c24xx_serial_console); - return 0; -} - -#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */ - -MODULE_DESCRIPTION("Samsung SoC Serial port driver"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h deleted file mode 100644 index 0ac06a07d25f..000000000000 --- a/drivers/serial/samsung.h +++ /dev/null @@ -1,120 +0,0 @@ -/* linux/drivers/serial/samsung.h - * - * Driver for Samsung SoC onboard UARTs. - * - * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * - * 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. -*/ - -struct s3c24xx_uart_info { - char *name; - unsigned int type; - unsigned int fifosize; - unsigned long rx_fifomask; - unsigned long rx_fifoshift; - unsigned long rx_fifofull; - unsigned long tx_fifomask; - unsigned long tx_fifoshift; - unsigned long tx_fifofull; - - /* uart port features */ - - unsigned int has_divslot:1; - - /* clock source control */ - - int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); - int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); - - /* uart controls */ - int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *); -}; - -struct s3c24xx_uart_port { - unsigned char rx_claimed; - unsigned char tx_claimed; - unsigned int pm_level; - unsigned long baudclk_rate; - - unsigned int rx_irq; - unsigned int tx_irq; - - struct s3c24xx_uart_info *info; - struct s3c24xx_uart_clksrc *clksrc; - struct clk *clk; - struct clk *baudclk; - struct uart_port port; - -#ifdef CONFIG_CPU_FREQ - struct notifier_block freq_transition; -#endif -}; - -/* conversion functions */ - -#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev) -#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data) - -/* register access controls */ - -#define portaddr(port, reg) ((port)->membase + (reg)) - -#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) -#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) - -#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) -#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) - -extern int s3c24xx_serial_probe(struct platform_device *dev, - struct s3c24xx_uart_info *uart); - -extern int __devexit s3c24xx_serial_remove(struct platform_device *dev); - -extern int s3c24xx_serial_initconsole(struct platform_driver *drv, - struct s3c24xx_uart_info **uart); - -extern int s3c24xx_serial_init(struct platform_driver *drv, - struct s3c24xx_uart_info *info); - -#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE - -#define s3c24xx_console_init(__drv, __inf) \ -static int __init s3c_serial_console_init(void) \ -{ \ - struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS]; \ - int i; \ - \ - for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) \ - uinfo[i] = __inf; \ - return s3c24xx_serial_initconsole(__drv, uinfo); \ -} \ - \ -console_initcall(s3c_serial_console_init) - -#else -#define s3c24xx_console_init(drv, inf) extern void no_console(void) -#endif - -#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG - -extern void printascii(const char *); - -static void dbg(const char *fmt, ...) -{ - va_list va; - char buff[256]; - - va_start(va, fmt); - vsprintf(buff, fmt, va); - va_end(va); - - printascii(buff); -} - -#else -#define dbg(x...) do { } while (0) -#endif diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c deleted file mode 100644 index a2f2b3254499..000000000000 --- a/drivers/serial/sb1250-duart.c +++ /dev/null @@ -1,976 +0,0 @@ -/* - * drivers/serial/sb1250-duart.c - * - * Support for the asynchronous serial interface (DUART) included - * in the BCM1250 and derived System-On-a-Chip (SOC) devices. - * - * Copyright (c) 2007 Maciej W. Rozycki - * - * Derived from drivers/char/sb1250_duart.c for which the following - * copyright applies: - * - * Copyright (c) 2000, 2001, 2002, 2003, 2004 Broadcom Corporation - * - * 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. - * - * References: - * - * "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation - */ - -#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - - -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) -#include -#include - -#define SBD_CHANREGS(line) A_BCM1480_DUART_CHANREG((line), 0) -#define SBD_CTRLREGS(line) A_BCM1480_DUART_CTRLREG((line), 0) -#define SBD_INT(line) (K_BCM1480_INT_UART_0 + (line)) - -#define DUART_CHANREG_SPACING BCM1480_DUART_CHANREG_SPACING - -#define R_DUART_IMRREG(line) R_BCM1480_DUART_IMRREG(line) -#define R_DUART_INCHREG(line) R_BCM1480_DUART_INCHREG(line) -#define R_DUART_ISRREG(line) R_BCM1480_DUART_ISRREG(line) - -#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) -#include -#include - -#define SBD_CHANREGS(line) A_DUART_CHANREG((line), 0) -#define SBD_CTRLREGS(line) A_DUART_CTRLREG(0) -#define SBD_INT(line) (K_INT_UART_0 + (line)) - -#else -#error invalid SB1250 UART configuration - -#endif - - -MODULE_AUTHOR("Maciej W. Rozycki "); -MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver"); -MODULE_LICENSE("GPL"); - - -#define DUART_MAX_CHIP 2 -#define DUART_MAX_SIDE 2 - -/* - * Per-port state. - */ -struct sbd_port { - struct sbd_duart *duart; - struct uart_port port; - unsigned char __iomem *memctrl; - int tx_stopped; - int initialised; -}; - -/* - * Per-DUART state for the shared register space. - */ -struct sbd_duart { - struct sbd_port sport[2]; - unsigned long mapctrl; - atomic_t map_guard; -}; - -#define to_sport(uport) container_of(uport, struct sbd_port, port) - -static struct sbd_duart sbd_duarts[DUART_MAX_CHIP]; - - -/* - * Reading and writing SB1250 DUART registers. - * - * There are three register spaces: two per-channel ones and - * a shared one. We have to define accessors appropriately. - * All registers are 64-bit and all but the Baud Rate Clock - * registers only define 8 least significant bits. There is - * also a workaround to take into account. Raw accessors use - * the full register width, but cooked ones truncate it - * intentionally so that the rest of the driver does not care. - */ -static u64 __read_sbdchn(struct sbd_port *sport, int reg) -{ - void __iomem *csr = sport->port.membase + reg; - - return __raw_readq(csr); -} - -static u64 __read_sbdshr(struct sbd_port *sport, int reg) -{ - void __iomem *csr = sport->memctrl + reg; - - return __raw_readq(csr); -} - -static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value) -{ - void __iomem *csr = sport->port.membase + reg; - - __raw_writeq(value, csr); -} - -static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value) -{ - void __iomem *csr = sport->memctrl + reg; - - __raw_writeq(value, csr); -} - -/* - * In bug 1956, we get glitches that can mess up uart registers. This - * "read-mode-reg after any register access" is an accepted workaround. - */ -static void __war_sbd1956(struct sbd_port *sport) -{ - __read_sbdchn(sport, R_DUART_MODE_REG_1); - __read_sbdchn(sport, R_DUART_MODE_REG_2); -} - -static unsigned char read_sbdchn(struct sbd_port *sport, int reg) -{ - unsigned char retval; - - retval = __read_sbdchn(sport, reg); - if (SIBYTE_1956_WAR) - __war_sbd1956(sport); - return retval; -} - -static unsigned char read_sbdshr(struct sbd_port *sport, int reg) -{ - unsigned char retval; - - retval = __read_sbdshr(sport, reg); - if (SIBYTE_1956_WAR) - __war_sbd1956(sport); - return retval; -} - -static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value) -{ - __write_sbdchn(sport, reg, value); - if (SIBYTE_1956_WAR) - __war_sbd1956(sport); -} - -static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value) -{ - __write_sbdshr(sport, reg, value); - if (SIBYTE_1956_WAR) - __war_sbd1956(sport); -} - - -static int sbd_receive_ready(struct sbd_port *sport) -{ - return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY; -} - -static int sbd_receive_drain(struct sbd_port *sport) -{ - int loops = 10000; - - while (sbd_receive_ready(sport) && --loops) - read_sbdchn(sport, R_DUART_RX_HOLD); - return loops; -} - -static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport) -{ - return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY; -} - -static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport) -{ - int loops = 10000; - - while (!sbd_transmit_ready(sport) && --loops) - udelay(2); - return loops; -} - -static int sbd_transmit_empty(struct sbd_port *sport) -{ - return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT; -} - -static int sbd_line_drain(struct sbd_port *sport) -{ - int loops = 10000; - - while (!sbd_transmit_empty(sport) && --loops) - udelay(2); - return loops; -} - - -static unsigned int sbd_tx_empty(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - - return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0; -} - -static unsigned int sbd_get_mctrl(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - unsigned int mctrl, status; - - status = read_sbdshr(sport, R_DUART_IN_PORT); - status >>= (uport->line) % 2; - mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) | - (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) | - (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) | - (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0); - return mctrl; -} - -static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl) -{ - struct sbd_port *sport = to_sport(uport); - unsigned int clr = 0, set = 0, mode2; - - if (mctrl & TIOCM_DTR) - set |= M_DUART_SET_OPR2; - else - clr |= M_DUART_CLR_OPR2; - if (mctrl & TIOCM_RTS) - set |= M_DUART_SET_OPR0; - else - clr |= M_DUART_CLR_OPR0; - clr <<= (uport->line) % 2; - set <<= (uport->line) % 2; - - mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2); - mode2 &= ~M_DUART_CHAN_MODE; - if (mctrl & TIOCM_LOOP) - mode2 |= V_DUART_CHAN_MODE_LCL_LOOP; - else - mode2 |= V_DUART_CHAN_MODE_NORMAL; - - write_sbdshr(sport, R_DUART_CLEAR_OPR, clr); - write_sbdshr(sport, R_DUART_SET_OPR, set); - write_sbdchn(sport, R_DUART_MODE_REG_2, mode2); -} - -static void sbd_stop_tx(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS); - sport->tx_stopped = 1; -}; - -static void sbd_start_tx(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - unsigned int mask; - - /* Enable tx interrupts. */ - mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); - mask |= M_DUART_IMR_TX; - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); - - /* Go!, go!, go!... */ - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); - sport->tx_stopped = 0; -}; - -static void sbd_stop_rx(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0); -}; - -static void sbd_enable_ms(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - - write_sbdchn(sport, R_DUART_AUXCTL_X, - M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA); -} - -static void sbd_break_ctl(struct uart_port *uport, int break_state) -{ - struct sbd_port *sport = to_sport(uport); - - if (break_state == -1) - write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK); - else - write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK); -} - - -static void sbd_receive_chars(struct sbd_port *sport) -{ - struct uart_port *uport = &sport->port; - struct uart_icount *icount; - unsigned int status, ch, flag; - int count; - - for (count = 16; count; count--) { - status = read_sbdchn(sport, R_DUART_STATUS); - if (!(status & M_DUART_RX_RDY)) - break; - - ch = read_sbdchn(sport, R_DUART_RX_HOLD); - - flag = TTY_NORMAL; - - icount = &uport->icount; - icount->rx++; - - if (unlikely(status & - (M_DUART_RCVD_BRK | M_DUART_FRM_ERR | - M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) { - if (status & M_DUART_RCVD_BRK) { - icount->brk++; - if (uart_handle_break(uport)) - continue; - } else if (status & M_DUART_FRM_ERR) - icount->frame++; - else if (status & M_DUART_PARITY_ERR) - icount->parity++; - if (status & M_DUART_OVRUN_ERR) - icount->overrun++; - - status &= uport->read_status_mask; - if (status & M_DUART_RCVD_BRK) - flag = TTY_BREAK; - else if (status & M_DUART_FRM_ERR) - flag = TTY_FRAME; - else if (status & M_DUART_PARITY_ERR) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(uport, ch)) - continue; - - uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag); - } - - tty_flip_buffer_push(uport->state->port.tty); -} - -static void sbd_transmit_chars(struct sbd_port *sport) -{ - struct uart_port *uport = &sport->port; - struct circ_buf *xmit = &sport->port.state->xmit; - unsigned int mask; - int stop_tx; - - /* XON/XOFF chars. */ - if (sport->port.x_char) { - write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - /* If nothing to do or stopped or hardware stopped. */ - stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)); - - /* Send char. */ - if (!stop_tx) { - write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - } - - /* Are we are done? */ - if (stop_tx || uart_circ_empty(xmit)) { - /* Disable tx interrupts. */ - mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); - mask &= ~M_DUART_IMR_TX; - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); - } -} - -static void sbd_status_handle(struct sbd_port *sport) -{ - struct uart_port *uport = &sport->port; - unsigned int delta; - - delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2)); - delta >>= (uport->line) % 2; - - if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG)) - uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL)); - - if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG)) - uport->icount.dsr++; - - if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) << - S_DUART_IN_PIN_CHNG)) - wake_up_interruptible(&uport->state->port.delta_msr_wait); -} - -static irqreturn_t sbd_interrupt(int irq, void *dev_id) -{ - struct sbd_port *sport = dev_id; - struct uart_port *uport = &sport->port; - irqreturn_t status = IRQ_NONE; - unsigned int intstat; - int count; - - for (count = 16; count; count--) { - intstat = read_sbdshr(sport, - R_DUART_ISRREG((uport->line) % 2)); - intstat &= read_sbdshr(sport, - R_DUART_IMRREG((uport->line) % 2)); - intstat &= M_DUART_ISR_ALL; - if (!intstat) - break; - - if (intstat & M_DUART_ISR_RX) - sbd_receive_chars(sport); - if (intstat & M_DUART_ISR_IN) - sbd_status_handle(sport); - if (intstat & M_DUART_ISR_TX) - sbd_transmit_chars(sport); - - status = IRQ_HANDLED; - } - - return status; -} - - -static int sbd_startup(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - unsigned int mode1; - int ret; - - ret = request_irq(sport->port.irq, sbd_interrupt, - IRQF_SHARED, "sb1250-duart", sport); - if (ret) - return ret; - - /* Clear the receive FIFO. */ - sbd_receive_drain(sport); - - /* Clear the interrupt registers. */ - write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT); - read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2)); - - /* Set rx/tx interrupt to FIFO available. */ - mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1); - mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT); - write_sbdchn(sport, R_DUART_MODE_REG_1, mode1); - - /* Disable tx, enable rx. */ - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN); - sport->tx_stopped = 1; - - /* Enable interrupts. */ - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), - M_DUART_IMR_IN | M_DUART_IMR_RX); - - return 0; -} - -static void sbd_shutdown(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS); - sport->tx_stopped = 1; - free_irq(sport->port.irq, sport); -} - - -static void sbd_init_port(struct sbd_port *sport) -{ - struct uart_port *uport = &sport->port; - - if (sport->initialised) - return; - - /* There is no DUART reset feature, so just set some sane defaults. */ - write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX); - write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX); - write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8); - write_sbdchn(sport, R_DUART_MODE_REG_2, 0); - write_sbdchn(sport, R_DUART_FULL_CTL, - V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15)); - write_sbdchn(sport, R_DUART_OPCR_X, 0); - write_sbdchn(sport, R_DUART_AUXCTL_X, 0); - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0); - - sport->initialised = 1; -} - -static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) -{ - struct sbd_port *sport = to_sport(uport); - unsigned int mode1 = 0, mode2 = 0, aux = 0; - unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0; - unsigned int oldmode1, oldmode2, oldaux; - unsigned int baud, brg; - unsigned int command; - - mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD | - M_DUART_BITS_PER_CHAR); - mode2mask |= ~M_DUART_STOP_BIT_LEN_2; - auxmask |= ~M_DUART_CTS_CHNG_ENA; - - /* Byte size. */ - switch (termios->c_cflag & CSIZE) { - case CS5: - case CS6: - /* Unsupported, leave unchanged. */ - mode1mask |= M_DUART_PARITY_MODE; - break; - case CS7: - mode1 |= V_DUART_BITS_PER_CHAR_7; - break; - case CS8: - default: - mode1 |= V_DUART_BITS_PER_CHAR_8; - break; - } - - /* Parity and stop bits. */ - if (termios->c_cflag & CSTOPB) - mode2 |= M_DUART_STOP_BIT_LEN_2; - else - mode2 |= M_DUART_STOP_BIT_LEN_1; - if (termios->c_cflag & PARENB) - mode1 |= V_DUART_PARITY_MODE_ADD; - else - mode1 |= V_DUART_PARITY_MODE_NONE; - if (termios->c_cflag & PARODD) - mode1 |= M_DUART_PARITY_TYPE_ODD; - else - mode1 |= M_DUART_PARITY_TYPE_EVEN; - - baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000); - brg = V_DUART_BAUD_RATE(baud); - /* The actual lower bound is 1221bps, so compensate. */ - if (brg > M_DUART_CLK_COUNTER) - brg = M_DUART_CLK_COUNTER; - - uart_update_timeout(uport, termios->c_cflag, baud); - - uport->read_status_mask = M_DUART_OVRUN_ERR; - if (termios->c_iflag & INPCK) - uport->read_status_mask |= M_DUART_FRM_ERR | - M_DUART_PARITY_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) - uport->read_status_mask |= M_DUART_RCVD_BRK; - - uport->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - uport->ignore_status_mask |= M_DUART_FRM_ERR | - M_DUART_PARITY_ERR; - if (termios->c_iflag & IGNBRK) { - uport->ignore_status_mask |= M_DUART_RCVD_BRK; - if (termios->c_iflag & IGNPAR) - uport->ignore_status_mask |= M_DUART_OVRUN_ERR; - } - - if (termios->c_cflag & CREAD) - command = M_DUART_RX_EN; - else - command = M_DUART_RX_DIS; - - if (termios->c_cflag & CRTSCTS) - aux |= M_DUART_CTS_CHNG_ENA; - else - aux &= ~M_DUART_CTS_CHNG_ENA; - - spin_lock(&uport->lock); - - if (sport->tx_stopped) - command |= M_DUART_TX_DIS; - else - command |= M_DUART_TX_EN; - - oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask; - oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask; - oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask; - - if (!sport->tx_stopped) - sbd_line_drain(sport); - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS); - - write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1); - write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2); - write_sbdchn(sport, R_DUART_CLK_SEL, brg); - write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux); - - write_sbdchn(sport, R_DUART_CMD, command); - - spin_unlock(&uport->lock); -} - - -static const char *sbd_type(struct uart_port *uport) -{ - return "SB1250 DUART"; -} - -static void sbd_release_port(struct uart_port *uport) -{ - struct sbd_port *sport = to_sport(uport); - struct sbd_duart *duart = sport->duart; - int map_guard; - - iounmap(sport->memctrl); - sport->memctrl = NULL; - iounmap(uport->membase); - uport->membase = NULL; - - map_guard = atomic_add_return(-1, &duart->map_guard); - if (!map_guard) - release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING); - release_mem_region(uport->mapbase, DUART_CHANREG_SPACING); -} - -static int sbd_map_port(struct uart_port *uport) -{ - const char *err = KERN_ERR "sbd: Cannot map MMIO\n"; - struct sbd_port *sport = to_sport(uport); - struct sbd_duart *duart = sport->duart; - - if (!uport->membase) - uport->membase = ioremap_nocache(uport->mapbase, - DUART_CHANREG_SPACING); - if (!uport->membase) { - printk(err); - return -ENOMEM; - } - - if (!sport->memctrl) - sport->memctrl = ioremap_nocache(duart->mapctrl, - DUART_CHANREG_SPACING); - if (!sport->memctrl) { - printk(err); - iounmap(uport->membase); - uport->membase = NULL; - return -ENOMEM; - } - - return 0; -} - -static int sbd_request_port(struct uart_port *uport) -{ - const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n"; - struct sbd_duart *duart = to_sport(uport)->duart; - int map_guard; - int ret = 0; - - if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING, - "sb1250-duart")) { - printk(err); - return -EBUSY; - } - map_guard = atomic_add_return(1, &duart->map_guard); - if (map_guard == 1) { - if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING, - "sb1250-duart")) { - atomic_add(-1, &duart->map_guard); - printk(err); - ret = -EBUSY; - } - } - if (!ret) { - ret = sbd_map_port(uport); - if (ret) { - map_guard = atomic_add_return(-1, &duart->map_guard); - if (!map_guard) - release_mem_region(duart->mapctrl, - DUART_CHANREG_SPACING); - } - } - if (ret) { - release_mem_region(uport->mapbase, DUART_CHANREG_SPACING); - return ret; - } - return 0; -} - -static void sbd_config_port(struct uart_port *uport, int flags) -{ - struct sbd_port *sport = to_sport(uport); - - if (flags & UART_CONFIG_TYPE) { - if (sbd_request_port(uport)) - return; - - uport->type = PORT_SB1250_DUART; - - sbd_init_port(sport); - } -} - -static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART) - ret = -EINVAL; - if (ser->irq != uport->irq) - ret = -EINVAL; - if (ser->baud_base != uport->uartclk / 16) - ret = -EINVAL; - return ret; -} - - -static const struct uart_ops sbd_ops = { - .tx_empty = sbd_tx_empty, - .set_mctrl = sbd_set_mctrl, - .get_mctrl = sbd_get_mctrl, - .stop_tx = sbd_stop_tx, - .start_tx = sbd_start_tx, - .stop_rx = sbd_stop_rx, - .enable_ms = sbd_enable_ms, - .break_ctl = sbd_break_ctl, - .startup = sbd_startup, - .shutdown = sbd_shutdown, - .set_termios = sbd_set_termios, - .type = sbd_type, - .release_port = sbd_release_port, - .request_port = sbd_request_port, - .config_port = sbd_config_port, - .verify_port = sbd_verify_port, -}; - -/* Initialize SB1250 DUART port structures. */ -static void __init sbd_probe_duarts(void) -{ - static int probed; - int chip, side; - int max_lines, line; - - if (probed) - return; - - /* Set the number of available units based on the SOC type. */ - switch (soc_type) { - case K_SYS_SOC_TYPE_BCM1x55: - case K_SYS_SOC_TYPE_BCM1x80: - max_lines = 4; - break; - default: - /* Assume at least two serial ports at the normal address. */ - max_lines = 2; - break; - } - - probed = 1; - - for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines; - chip++) { - sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line); - - for (side = 0; side < DUART_MAX_SIDE && line < max_lines; - side++, line++) { - struct sbd_port *sport = &sbd_duarts[chip].sport[side]; - struct uart_port *uport = &sport->port; - - sport->duart = &sbd_duarts[chip]; - - uport->irq = SBD_INT(line); - uport->uartclk = 100000000 / 20 * 16; - uport->fifosize = 16; - uport->iotype = UPIO_MEM; - uport->flags = UPF_BOOT_AUTOCONF; - uport->ops = &sbd_ops; - uport->line = line; - uport->mapbase = SBD_CHANREGS(line); - } - } -} - - -#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE -/* - * Serial console stuff. Very basic, polling driver for doing serial - * console output. The console_sem is held by the caller, so we - * shouldn't be interrupted for more console activity. - */ -static void sbd_console_putchar(struct uart_port *uport, int ch) -{ - struct sbd_port *sport = to_sport(uport); - - sbd_transmit_drain(sport); - write_sbdchn(sport, R_DUART_TX_HOLD, ch); -} - -static void sbd_console_write(struct console *co, const char *s, - unsigned int count) -{ - int chip = co->index / DUART_MAX_SIDE; - int side = co->index % DUART_MAX_SIDE; - struct sbd_port *sport = &sbd_duarts[chip].sport[side]; - struct uart_port *uport = &sport->port; - unsigned long flags; - unsigned int mask; - - /* Disable transmit interrupts and enable the transmitter. */ - spin_lock_irqsave(&uport->lock, flags); - mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), - mask & ~M_DUART_IMR_TX); - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); - spin_unlock_irqrestore(&uport->lock, flags); - - uart_console_write(&sport->port, s, count, sbd_console_putchar); - - /* Restore transmit interrupts and the transmitter enable. */ - spin_lock_irqsave(&uport->lock, flags); - sbd_line_drain(sport); - if (sport->tx_stopped) - write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS); - write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); - spin_unlock_irqrestore(&uport->lock, flags); -} - -static int __init sbd_console_setup(struct console *co, char *options) -{ - int chip = co->index / DUART_MAX_SIDE; - int side = co->index % DUART_MAX_SIDE; - struct sbd_port *sport = &sbd_duarts[chip].sport[side]; - struct uart_port *uport = &sport->port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - if (!sport->duart) - return -ENXIO; - - ret = sbd_map_port(uport); - if (ret) - return ret; - - sbd_init_port(sport); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(uport, co, baud, parity, bits, flow); -} - -static struct uart_driver sbd_reg; -static struct console sbd_console = { - .name = "duart", - .write = sbd_console_write, - .device = uart_console_device, - .setup = sbd_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sbd_reg -}; - -static int __init sbd_serial_console_init(void) -{ - sbd_probe_duarts(); - register_console(&sbd_console); - - return 0; -} - -console_initcall(sbd_serial_console_init); - -#define SERIAL_SB1250_DUART_CONSOLE &sbd_console -#else -#define SERIAL_SB1250_DUART_CONSOLE NULL -#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */ - - -static struct uart_driver sbd_reg = { - .owner = THIS_MODULE, - .driver_name = "sb1250_duart", - .dev_name = "duart", - .major = TTY_MAJOR, - .minor = SB1250_DUART_MINOR_BASE, - .nr = DUART_MAX_CHIP * DUART_MAX_SIDE, - .cons = SERIAL_SB1250_DUART_CONSOLE, -}; - -/* Set up the driver and register it. */ -static int __init sbd_init(void) -{ - int i, ret; - - sbd_probe_duarts(); - - ret = uart_register_driver(&sbd_reg); - if (ret) - return ret; - - for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) { - struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE]; - struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE]; - struct uart_port *uport = &sport->port; - - if (sport->duart) - uart_add_one_port(&sbd_reg, uport); - } - - return 0; -} - -/* Unload the driver. Unregister stuff, get ready to go away. */ -static void __exit sbd_exit(void) -{ - int i; - - for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) { - struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE]; - struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE]; - struct uart_port *uport = &sport->port; - - if (sport->duart) - uart_remove_one_port(&sbd_reg, uport); - } - - uart_unregister_driver(&sbd_reg); -} - -module_init(sbd_init); -module_exit(sbd_exit); diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c deleted file mode 100644 index 75038ad2b242..000000000000 --- a/drivers/serial/sc26xx.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices. - * - * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -#define SC26XX_MAJOR 204 -#define SC26XX_MINOR_START 205 -#define SC26XX_NR 2 - -struct uart_sc26xx_port { - struct uart_port port[2]; - u8 dsr_mask[2]; - u8 cts_mask[2]; - u8 dcd_mask[2]; - u8 ri_mask[2]; - u8 dtr_mask[2]; - u8 rts_mask[2]; - u8 imr; -}; - -/* register common to both ports */ -#define RD_ISR 0x14 -#define RD_IPR 0x34 - -#define WR_ACR 0x10 -#define WR_IMR 0x14 -#define WR_OPCR 0x34 -#define WR_OPR_SET 0x38 -#define WR_OPR_CLR 0x3C - -/* access common register */ -#define READ_SC(p, r) readb((p)->membase + RD_##r) -#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r) - -/* register per port */ -#define RD_PORT_MRx 0x00 -#define RD_PORT_SR 0x04 -#define RD_PORT_RHR 0x0c - -#define WR_PORT_MRx 0x00 -#define WR_PORT_CSR 0x04 -#define WR_PORT_CR 0x08 -#define WR_PORT_THR 0x0c - -/* SR bits */ -#define SR_BREAK (1 << 7) -#define SR_FRAME (1 << 6) -#define SR_PARITY (1 << 5) -#define SR_OVERRUN (1 << 4) -#define SR_TXRDY (1 << 2) -#define SR_RXRDY (1 << 0) - -#define CR_RES_MR (1 << 4) -#define CR_RES_RX (2 << 4) -#define CR_RES_TX (3 << 4) -#define CR_STRT_BRK (6 << 4) -#define CR_STOP_BRK (7 << 4) -#define CR_DIS_TX (1 << 3) -#define CR_ENA_TX (1 << 2) -#define CR_DIS_RX (1 << 1) -#define CR_ENA_RX (1 << 0) - -/* ISR bits */ -#define ISR_RXRDYB (1 << 5) -#define ISR_TXRDYB (1 << 4) -#define ISR_RXRDYA (1 << 1) -#define ISR_TXRDYA (1 << 0) - -/* IMR bits */ -#define IMR_RXRDY (1 << 1) -#define IMR_TXRDY (1 << 0) - -/* access port register */ -static inline u8 read_sc_port(struct uart_port *p, u8 reg) -{ - return readb(p->membase + p->line * 0x20 + reg); -} - -static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val) -{ - writeb(val, p->membase + p->line * 0x20 + reg); -} - -#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r) -#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v) - -static void sc26xx_enable_irq(struct uart_port *port, int mask) -{ - struct uart_sc26xx_port *up; - int line = port->line; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - - up->imr |= mask << (line * 4); - WRITE_SC(port, IMR, up->imr); -} - -static void sc26xx_disable_irq(struct uart_port *port, int mask) -{ - struct uart_sc26xx_port *up; - int line = port->line; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - - up->imr &= ~(mask << (line * 4)); - WRITE_SC(port, IMR, up->imr); -} - -static struct tty_struct *receive_chars(struct uart_port *port) -{ - struct tty_struct *tty = NULL; - int limit = 10000; - unsigned char ch; - char flag; - u8 status; - - if (port->state != NULL) /* Unopened serial console */ - tty = port->state->port.tty; - - while (limit-- > 0) { - status = READ_SC_PORT(port, SR); - if (!(status & SR_RXRDY)) - break; - ch = READ_SC_PORT(port, RHR); - - flag = TTY_NORMAL; - port->icount.rx++; - - if (unlikely(status & (SR_BREAK | SR_FRAME | - SR_PARITY | SR_OVERRUN))) { - if (status & SR_BREAK) { - status &= ~(SR_PARITY | SR_FRAME); - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (status & SR_PARITY) - port->icount.parity++; - else if (status & SR_FRAME) - port->icount.frame++; - if (status & SR_OVERRUN) - port->icount.overrun++; - - status &= port->read_status_mask; - if (status & SR_BREAK) - flag = TTY_BREAK; - else if (status & SR_PARITY) - flag = TTY_PARITY; - else if (status & SR_FRAME) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - continue; - - if (status & port->ignore_status_mask) - continue; - - tty_insert_flip_char(tty, ch, flag); - } - return tty; -} - -static void transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit; - - if (!port->state) - return; - - xmit = &port->state->xmit; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - sc26xx_disable_irq(port, IMR_TXRDY); - return; - } - while (!uart_circ_empty(xmit)) { - if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) - break; - - WRITE_SC_PORT(port, THR, 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 sc26xx_interrupt(int irq, void *dev_id) -{ - struct uart_sc26xx_port *up = dev_id; - struct tty_struct *tty; - unsigned long flags; - u8 isr; - - spin_lock_irqsave(&up->port[0].lock, flags); - - tty = NULL; - isr = READ_SC(&up->port[0], ISR); - if (isr & ISR_TXRDYA) - transmit_chars(&up->port[0]); - if (isr & ISR_RXRDYA) - tty = receive_chars(&up->port[0]); - - spin_unlock(&up->port[0].lock); - - if (tty) - tty_flip_buffer_push(tty); - - spin_lock(&up->port[1].lock); - - tty = NULL; - if (isr & ISR_TXRDYB) - transmit_chars(&up->port[1]); - if (isr & ISR_RXRDYB) - tty = receive_chars(&up->port[1]); - - spin_unlock_irqrestore(&up->port[1].lock, flags); - - if (tty) - tty_flip_buffer_push(tty); - - return IRQ_HANDLED; -} - -/* port->lock is not held. */ -static unsigned int sc26xx_tx_empty(struct uart_port *port) -{ - return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0; -} - -/* port->lock held by caller. */ -static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_sc26xx_port *up; - int line = port->line; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - - if (up->dtr_mask[line]) { - if (mctrl & TIOCM_DTR) - WRITE_SC(port, OPR_SET, up->dtr_mask[line]); - else - WRITE_SC(port, OPR_CLR, up->dtr_mask[line]); - } - if (up->rts_mask[line]) { - if (mctrl & TIOCM_RTS) - WRITE_SC(port, OPR_SET, up->rts_mask[line]); - else - WRITE_SC(port, OPR_CLR, up->rts_mask[line]); - } -} - -/* port->lock is held by caller and interrupts are disabled. */ -static unsigned int sc26xx_get_mctrl(struct uart_port *port) -{ - struct uart_sc26xx_port *up; - int line = port->line; - unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; - u8 ipr; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - ipr = READ_SC(port, IPR) ^ 0xff; - - if (up->dsr_mask[line]) { - mctrl &= ~TIOCM_DSR; - mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0; - } - if (up->cts_mask[line]) { - mctrl &= ~TIOCM_CTS; - mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0; - } - if (up->dcd_mask[line]) { - mctrl &= ~TIOCM_CAR; - mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0; - } - if (up->ri_mask[line]) { - mctrl &= ~TIOCM_RNG; - mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0; - } - return mctrl; -} - -/* port->lock held by caller. */ -static void sc26xx_stop_tx(struct uart_port *port) -{ - return; -} - -/* port->lock held by caller. */ -static void sc26xx_start_tx(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - while (!uart_circ_empty(xmit)) { - if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { - sc26xx_enable_irq(port, IMR_TXRDY); - break; - } - WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } -} - -/* port->lock held by caller. */ -static void sc26xx_stop_rx(struct uart_port *port) -{ -} - -/* port->lock held by caller. */ -static void sc26xx_enable_ms(struct uart_port *port) -{ -} - -/* port->lock is not held. */ -static void sc26xx_break_ctl(struct uart_port *port, int break_state) -{ - if (break_state == -1) - WRITE_SC_PORT(port, CR, CR_STRT_BRK); - else - WRITE_SC_PORT(port, CR, CR_STOP_BRK); -} - -/* port->lock is not held. */ -static int sc26xx_startup(struct uart_port *port) -{ - sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); - WRITE_SC(port, OPCR, 0); - - /* reset tx and rx */ - WRITE_SC_PORT(port, CR, CR_RES_RX); - WRITE_SC_PORT(port, CR, CR_RES_TX); - - /* start rx/tx */ - WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); - - /* enable irqs */ - sc26xx_enable_irq(port, IMR_RXRDY); - return 0; -} - -/* port->lock is not held. */ -static void sc26xx_shutdown(struct uart_port *port) -{ - /* disable interrupst */ - sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); - - /* stop tx/rx */ - WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); -} - -/* port->lock is not held. */ -static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - unsigned int quot = uart_get_divisor(port, baud); - unsigned int iflag, cflag; - unsigned long flags; - u8 mr1, mr2, csr; - - spin_lock_irqsave(&port->lock, flags); - - while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) - udelay(2); - - WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); - - iflag = termios->c_iflag; - cflag = termios->c_cflag; - - port->read_status_mask = SR_OVERRUN; - if (iflag & INPCK) - port->read_status_mask |= SR_PARITY | SR_FRAME; - if (iflag & (BRKINT | PARMRK)) - port->read_status_mask |= SR_BREAK; - - port->ignore_status_mask = 0; - if (iflag & IGNBRK) - port->ignore_status_mask |= SR_BREAK; - if ((cflag & CREAD) == 0) - port->ignore_status_mask |= SR_BREAK | SR_FRAME | - SR_PARITY | SR_OVERRUN; - - switch (cflag & CSIZE) { - case CS5: - mr1 = 0x00; - break; - case CS6: - mr1 = 0x01; - break; - case CS7: - mr1 = 0x02; - break; - default: - case CS8: - mr1 = 0x03; - break; - } - mr2 = 0x07; - if (cflag & CSTOPB) - mr2 = 0x0f; - if (cflag & PARENB) { - if (cflag & PARODD) - mr1 |= (1 << 2); - } else - mr1 |= (2 << 3); - - switch (baud) { - case 50: - csr = 0x00; - break; - case 110: - csr = 0x11; - break; - case 134: - csr = 0x22; - break; - case 200: - csr = 0x33; - break; - case 300: - csr = 0x44; - break; - case 600: - csr = 0x55; - break; - case 1200: - csr = 0x66; - break; - case 2400: - csr = 0x88; - break; - case 4800: - csr = 0x99; - break; - default: - case 9600: - csr = 0xbb; - break; - case 19200: - csr = 0xcc; - break; - } - - WRITE_SC_PORT(port, CR, CR_RES_MR); - WRITE_SC_PORT(port, MRx, mr1); - WRITE_SC_PORT(port, MRx, mr2); - - WRITE_SC(port, ACR, 0x80); - WRITE_SC_PORT(port, CSR, csr); - - /* reset tx and rx */ - WRITE_SC_PORT(port, CR, CR_RES_RX); - WRITE_SC_PORT(port, CR, CR_RES_TX); - - WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); - while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) - udelay(2); - - /* XXX */ - uart_update_timeout(port, cflag, - (port->uartclk / (16 * quot))); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *sc26xx_type(struct uart_port *port) -{ - return "SC26XX"; -} - -static void sc26xx_release_port(struct uart_port *port) -{ -} - -static int sc26xx_request_port(struct uart_port *port) -{ - return 0; -} - -static void sc26xx_config_port(struct uart_port *port, int flags) -{ -} - -static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -static struct uart_ops sc26xx_ops = { - .tx_empty = sc26xx_tx_empty, - .set_mctrl = sc26xx_set_mctrl, - .get_mctrl = sc26xx_get_mctrl, - .stop_tx = sc26xx_stop_tx, - .start_tx = sc26xx_start_tx, - .stop_rx = sc26xx_stop_rx, - .enable_ms = sc26xx_enable_ms, - .break_ctl = sc26xx_break_ctl, - .startup = sc26xx_startup, - .shutdown = sc26xx_shutdown, - .set_termios = sc26xx_set_termios, - .type = sc26xx_type, - .release_port = sc26xx_release_port, - .request_port = sc26xx_request_port, - .config_port = sc26xx_config_port, - .verify_port = sc26xx_verify_port, -}; - -static struct uart_port *sc26xx_port; - -#ifdef CONFIG_SERIAL_SC26XX_CONSOLE -static void sc26xx_console_putchar(struct uart_port *port, char c) -{ - unsigned long flags; - int limit = 1000000; - - spin_lock_irqsave(&port->lock, flags); - - while (limit-- > 0) { - if (READ_SC_PORT(port, SR) & SR_TXRDY) { - WRITE_SC_PORT(port, THR, c); - break; - } - udelay(2); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void sc26xx_console_write(struct console *con, const char *s, unsigned n) -{ - struct uart_port *port = sc26xx_port; - int i; - - for (i = 0; i < n; i++) { - if (*s == '\n') - sc26xx_console_putchar(port, '\r'); - sc26xx_console_putchar(port, *s++); - } -} - -static int __init sc26xx_console_setup(struct console *con, char *options) -{ - struct uart_port *port = sc26xx_port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (port->type != PORT_SC26XX) - return -1; - - printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index); - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, con, baud, parity, bits, flow); -} - -static struct uart_driver sc26xx_reg; -static struct console sc26xx_console = { - .name = "ttySC", - .write = sc26xx_console_write, - .device = uart_console_device, - .setup = sc26xx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sc26xx_reg, -}; -#define SC26XX_CONSOLE &sc26xx_console -#else -#define SC26XX_CONSOLE NULL -#endif - -static struct uart_driver sc26xx_reg = { - .owner = THIS_MODULE, - .driver_name = "SC26xx", - .dev_name = "ttySC", - .major = SC26XX_MAJOR, - .minor = SC26XX_MINOR_START, - .nr = SC26XX_NR, - .cons = SC26XX_CONSOLE, -}; - -static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) -{ - unsigned int bit = (flags >> bitpos) & 15; - - return bit ? (1 << (bit - 1)) : 0; -} - -static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up, - int line, unsigned int data) -{ - up->dtr_mask[line] = sc26xx_flags2mask(data, 0); - up->rts_mask[line] = sc26xx_flags2mask(data, 4); - up->dsr_mask[line] = sc26xx_flags2mask(data, 8); - up->cts_mask[line] = sc26xx_flags2mask(data, 12); - up->dcd_mask[line] = sc26xx_flags2mask(data, 16); - up->ri_mask[line] = sc26xx_flags2mask(data, 20); -} - -static int __devinit sc26xx_probe(struct platform_device *dev) -{ - struct resource *res; - struct uart_sc26xx_port *up; - unsigned int *sc26xx_data = dev->dev.platform_data; - int err; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - up = kzalloc(sizeof *up, GFP_KERNEL); - if (unlikely(!up)) - return -ENOMEM; - - up->port[0].line = 0; - up->port[0].ops = &sc26xx_ops; - up->port[0].type = PORT_SC26XX; - up->port[0].uartclk = (29491200 / 16); /* arbitrary */ - - up->port[0].mapbase = res->start; - up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40); - up->port[0].iotype = UPIO_MEM; - up->port[0].irq = platform_get_irq(dev, 0); - - up->port[0].dev = &dev->dev; - - sc26xx_init_masks(up, 0, sc26xx_data[0]); - - sc26xx_port = &up->port[0]; - - up->port[1].line = 1; - up->port[1].ops = &sc26xx_ops; - up->port[1].type = PORT_SC26XX; - up->port[1].uartclk = (29491200 / 16); /* arbitrary */ - - up->port[1].mapbase = up->port[0].mapbase; - up->port[1].membase = up->port[0].membase; - up->port[1].iotype = UPIO_MEM; - up->port[1].irq = up->port[0].irq; - - up->port[1].dev = &dev->dev; - - sc26xx_init_masks(up, 1, sc26xx_data[1]); - - err = uart_register_driver(&sc26xx_reg); - if (err) - goto out_free_port; - - sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor; - - err = uart_add_one_port(&sc26xx_reg, &up->port[0]); - if (err) - goto out_unregister_driver; - - err = uart_add_one_port(&sc26xx_reg, &up->port[1]); - if (err) - goto out_remove_port0; - - err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up); - if (err) - goto out_remove_ports; - - dev_set_drvdata(&dev->dev, up); - return 0; - -out_remove_ports: - uart_remove_one_port(&sc26xx_reg, &up->port[1]); -out_remove_port0: - uart_remove_one_port(&sc26xx_reg, &up->port[0]); - -out_unregister_driver: - uart_unregister_driver(&sc26xx_reg); - -out_free_port: - kfree(up); - sc26xx_port = NULL; - return err; -} - - -static int __exit sc26xx_driver_remove(struct platform_device *dev) -{ - struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev); - - free_irq(up->port[0].irq, up); - - uart_remove_one_port(&sc26xx_reg, &up->port[0]); - uart_remove_one_port(&sc26xx_reg, &up->port[1]); - - uart_unregister_driver(&sc26xx_reg); - - kfree(up); - sc26xx_port = NULL; - - dev_set_drvdata(&dev->dev, NULL); - return 0; -} - -static struct platform_driver sc26xx_driver = { - .probe = sc26xx_probe, - .remove = __devexit_p(sc26xx_driver_remove), - .driver = { - .name = "SC26xx", - .owner = THIS_MODULE, - }, -}; - -static int __init sc26xx_init(void) -{ - return platform_driver_register(&sc26xx_driver); -} - -static void __exit sc26xx_exit(void) -{ - platform_driver_unregister(&sc26xx_driver); -} - -module_init(sc26xx_init); -module_exit(sc26xx_exit); - - -MODULE_AUTHOR("Thomas Bogendörfer"); -MODULE_DESCRIPTION("SC681/SC2692 serial driver"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:SC26xx"); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c deleted file mode 100644 index 460a72d91bb7..000000000000 --- a/drivers/serial/serial_core.c +++ /dev/null @@ -1,2578 +0,0 @@ -/* - * linux/drivers/char/core.c - * - * Driver core for serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * Copyright 1999 ARM Limited - * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. - * - * 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 /* for serial_state and serial_icounter_struct */ -#include -#include -#include - -#include -#include - -/* - * This is used to lock changes in serial line configuration. - */ -static DEFINE_MUTEX(port_mutex); - -/* - * lockdep: port->lock is initialized in two places, but we - * want only one lock-class: - */ -static struct lock_class_key port_lock_key; - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) - -#ifdef CONFIG_SERIAL_CORE_CONSOLE -#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) -#else -#define uart_console(port) (0) -#endif - -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - struct ktermios *old_termios); -static void __uart_wait_until_sent(struct uart_port *port, int timeout); -static void uart_change_pm(struct uart_state *state, int pm_state); - -/* - * This routine is used by the interrupt handler to schedule processing in - * the software interrupt portion of the driver. - */ -void uart_write_wakeup(struct uart_port *port) -{ - struct uart_state *state = port->state; - /* - * This means you called this function _after_ the port was - * closed. No cookie for you. - */ - BUG_ON(!state); - tasklet_schedule(&state->tlet); -} - -static void uart_stop(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - port->ops->stop_tx(port); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void __uart_start(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - - if (!uart_circ_empty(&state->xmit) && state->xmit.buf && - !tty->stopped && !tty->hw_stopped) - port->ops->start_tx(port); -} - -static void uart_start(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - __uart_start(tty); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void uart_tasklet_action(unsigned long data) -{ - struct uart_state *state = (struct uart_state *)data; - tty_wakeup(state->port.tty); -} - -static inline void -uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) -{ - unsigned long flags; - unsigned int old; - - spin_lock_irqsave(&port->lock, flags); - old = port->mctrl; - port->mctrl = (old & ~clear) | set; - if (old != port->mctrl) - port->ops->set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); -} - -#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) -#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) - -/* - * Startup the port. This will be called once per open. All calls - * will be serialised by the per-port mutex. - */ -static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) -{ - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - unsigned long page; - int retval = 0; - - if (port->flags & ASYNC_INITIALIZED) - return 0; - - /* - * Set the TTY IO error marker - we will only clear this - * once we have successfully opened the port. Also set - * up the tty->alt_speed kludge - */ - set_bit(TTY_IO_ERROR, &tty->flags); - - if (uport->type == PORT_UNKNOWN) - return 0; - - /* - * Initialise and allocate the transmit and temporary - * buffer. - */ - if (!state->xmit.buf) { - /* This is protected by the per port mutex */ - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - state->xmit.buf = (unsigned char *) page; - uart_circ_clear(&state->xmit); - } - - retval = uport->ops->startup(uport); - if (retval == 0) { - if (init_hw) { - /* - * Initialise the hardware port settings. - */ - uart_change_speed(tty, state, NULL); - - /* - * Setup the RTS and DTR signals once the - * port is open and ready to respond. - */ - if (tty->termios->c_cflag & CBAUD) - uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); - } - - if (port->flags & ASYNC_CTS_FLOW) { - spin_lock_irq(&uport->lock); - if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) - tty->hw_stopped = 1; - spin_unlock_irq(&uport->lock); - } - - set_bit(ASYNCB_INITIALIZED, &port->flags); - - clear_bit(TTY_IO_ERROR, &tty->flags); - } - - if (retval && capable(CAP_SYS_ADMIN)) - retval = 0; - - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. Calls to - * uart_shutdown are serialised by the per-port semaphore. - */ -static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) -{ - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - - /* - * Set the TTY IO error marker - */ - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - - if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { - /* - * Turn off DTR and RTS early. - */ - if (!tty || (tty->termios->c_cflag & HUPCL)) - uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free - * the irq here so the queue might never be woken up. Note - * that we won't end up waiting on delta_msr_wait again since - * any outstanding file descriptors should be pointing at - * hung_up_tty_fops now. - */ - wake_up_interruptible(&port->delta_msr_wait); - - /* - * Free the IRQ and disable the port. - */ - uport->ops->shutdown(uport); - - /* - * Ensure that the IRQ handler isn't running on another CPU. - */ - synchronize_irq(uport->irq); - } - - /* - * kill off our tasklet - */ - tasklet_kill(&state->tlet); - - /* - * Free the transmit buffer page. - */ - if (state->xmit.buf) { - free_page((unsigned long)state->xmit.buf); - state->xmit.buf = NULL; - } -} - -/** - * uart_update_timeout - update per-port FIFO timeout. - * @port: uart_port structure describing the port - * @cflag: termios cflag value - * @baud: speed of the port - * - * Set the port FIFO timeout value. The @cflag value should - * reflect the actual hardware settings. - */ -void -uart_update_timeout(struct uart_port *port, unsigned int cflag, - unsigned int baud) -{ - unsigned int bits; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: - bits = 7; - break; - case CS6: - bits = 8; - break; - case CS7: - bits = 9; - break; - default: - bits = 10; - break; /* CS8 */ - } - - if (cflag & CSTOPB) - bits++; - if (cflag & PARENB) - bits++; - - /* - * The total number of bits to be transmitted in the fifo. - */ - bits = bits * port->fifosize; - - /* - * Figure the timeout to send the above number of bits. - * Add .02 seconds of slop - */ - port->timeout = (HZ * bits) / baud + HZ/50; -} - -EXPORT_SYMBOL(uart_update_timeout); - -/** - * uart_get_baud_rate - return baud rate for a particular port - * @port: uart_port structure describing the port in question. - * @termios: desired termios settings. - * @old: old termios (or NULL) - * @min: minimum acceptable baud rate - * @max: maximum acceptable baud rate - * - * Decode the termios structure into a numeric baud rate, - * taking account of the magic 38400 baud rate (with spd_* - * flags), and mapping the %B0 rate to 9600 baud. - * - * If the new baud rate is invalid, try the old termios setting. - * If it's still invalid, we try 9600 baud. - * - * Update the @termios structure to reflect the baud rate - * we're actually going to be using. Don't do this for the case - * where B0 is requested ("hang up"). - */ -unsigned int -uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, - struct ktermios *old, unsigned int min, unsigned int max) -{ - unsigned int try, baud, altbaud = 38400; - int hung_up = 0; - upf_t flags = port->flags & UPF_SPD_MASK; - - if (flags == UPF_SPD_HI) - altbaud = 57600; - else if (flags == UPF_SPD_VHI) - altbaud = 115200; - else if (flags == UPF_SPD_SHI) - altbaud = 230400; - else if (flags == UPF_SPD_WARP) - altbaud = 460800; - - for (try = 0; try < 2; try++) { - baud = tty_termios_baud_rate(termios); - - /* - * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... - * Die! Die! Die! - */ - if (baud == 38400) - baud = altbaud; - - /* - * Special case: B0 rate. - */ - if (baud == 0) { - hung_up = 1; - baud = 9600; - } - - if (baud >= min && baud <= max) - return baud; - - /* - * Oops, the quotient was zero. Try again with - * the old baud rate if possible. - */ - termios->c_cflag &= ~CBAUD; - if (old) { - baud = tty_termios_baud_rate(old); - if (!hung_up) - tty_termios_encode_baud_rate(termios, - baud, baud); - old = NULL; - continue; - } - - /* - * As a last resort, if the range cannot be met then clip to - * the nearest chip supported rate. - */ - if (!hung_up) { - if (baud <= min) - tty_termios_encode_baud_rate(termios, - min + 1, min + 1); - else - tty_termios_encode_baud_rate(termios, - max - 1, max - 1); - } - } - /* Should never happen */ - WARN_ON(1); - return 0; -} - -EXPORT_SYMBOL(uart_get_baud_rate); - -/** - * uart_get_divisor - return uart clock divisor - * @port: uart_port structure describing the port. - * @baud: desired baud rate - * - * Calculate the uart clock divisor for the port. - */ -unsigned int -uart_get_divisor(struct uart_port *port, unsigned int baud) -{ - unsigned int quot; - - /* - * Old custom speed handling. - */ - if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) - quot = port->custom_divisor; - else - quot = (port->uartclk + (8 * baud)) / (16 * baud); - - return quot; -} - -EXPORT_SYMBOL(uart_get_divisor); - -/* FIXME: Consistent locking policy */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - struct ktermios *old_termios) -{ - struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; - struct ktermios *termios; - - /* - * 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) - return; - - termios = tty->termios; - - /* - * Set flags based on termios cflag - */ - if (termios->c_cflag & CRTSCTS) - set_bit(ASYNCB_CTS_FLOW, &port->flags); - else - clear_bit(ASYNCB_CTS_FLOW, &port->flags); - - if (termios->c_cflag & CLOCAL) - clear_bit(ASYNCB_CHECK_CD, &port->flags); - else - set_bit(ASYNCB_CHECK_CD, &port->flags); - - uport->ops->set_termios(uport, termios, old_termios); -} - -static inline int __uart_put_char(struct uart_port *port, - struct circ_buf *circ, unsigned char c) -{ - unsigned long flags; - int ret = 0; - - if (!circ->buf) - return 0; - - spin_lock_irqsave(&port->lock, flags); - if (uart_circ_chars_free(circ) != 0) { - circ->buf[circ->head] = c; - circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); - ret = 1; - } - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -static int uart_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct uart_state *state = tty->driver_data; - - return __uart_put_char(state->uart_port, &state->xmit, ch); -} - -static void uart_flush_chars(struct tty_struct *tty) -{ - uart_start(tty); -} - -static int uart_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port; - struct circ_buf *circ; - unsigned long flags; - int c, ret = 0; - - /* - * This means you called this function _after_ the port was - * closed. No cookie for you. - */ - if (!state) { - WARN_ON(1); - return -EL3HLT; - } - - port = state->uart_port; - circ = &state->xmit; - - if (!circ->buf) - return 0; - - spin_lock_irqsave(&port->lock, flags); - while (1) { - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(circ->buf + circ->head, buf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } - spin_unlock_irqrestore(&port->lock, flags); - - uart_start(tty); - return ret; -} - -static int uart_write_room(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - unsigned long flags; - int ret; - - spin_lock_irqsave(&state->uart_port->lock, flags); - ret = uart_circ_chars_free(&state->xmit); - spin_unlock_irqrestore(&state->uart_port->lock, flags); - return ret; -} - -static int uart_chars_in_buffer(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - unsigned long flags; - int ret; - - spin_lock_irqsave(&state->uart_port->lock, flags); - ret = uart_circ_chars_pending(&state->xmit); - spin_unlock_irqrestore(&state->uart_port->lock, flags); - return ret; -} - -static void uart_flush_buffer(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port; - unsigned long flags; - - /* - * This means you called this function _after_ the port was - * closed. No cookie for you. - */ - if (!state) { - WARN_ON(1); - return; - } - - port = state->uart_port; - pr_debug("uart_flush_buffer(%d) called\n", tty->index); - - spin_lock_irqsave(&port->lock, flags); - uart_circ_clear(&state->xmit); - if (port->ops->flush_buffer) - port->ops->flush_buffer(port); - spin_unlock_irqrestore(&port->lock, flags); - tty_wakeup(tty); -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void uart_send_xchar(struct tty_struct *tty, char ch) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - unsigned long flags; - - if (port->ops->send_xchar) - port->ops->send_xchar(port, ch); - else { - port->x_char = ch; - if (ch) { - spin_lock_irqsave(&port->lock, flags); - port->ops->start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); - } - } -} - -static void uart_throttle(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - - if (I_IXOFF(tty)) - uart_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios->c_cflag & CRTSCTS) - uart_clear_mctrl(state->uart_port, TIOCM_RTS); -} - -static void uart_unthrottle(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - - if (I_IXOFF(tty)) { - if (port->x_char) - port->x_char = 0; - else - uart_send_xchar(tty, START_CHAR(tty)); - } - - if (tty->termios->c_cflag & CRTSCTS) - uart_set_mctrl(port, TIOCM_RTS); -} - -static int uart_get_info(struct uart_state *state, - struct serial_struct __user *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); - - tmp.type = uport->type; - tmp.line = uport->line; - tmp.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 = port->close_delay / 10; - tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - 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; - - mutex_unlock(&port->mutex); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int uart_set_info(struct tty_struct *tty, struct uart_state *state, - struct serial_struct __user *newinfo) -{ - 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; - if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; - - new_serial.irq = irq_canonicalize(new_serial.irq); - close_delay = new_serial.close_delay * 10; - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.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; - - /* - * Since changing the 'type' of the port changes its resource - * allocations, we should treat type changes the same as - * IO port changes. - */ - 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); - - old_flags = uport->flags; - new_flags = new_serial.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) || - (close_delay != port->close_delay) || - (closing_wait != port->closing_wait) || - (new_serial.xmit_fifo_size && - new_serial.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; - goto check_and_exit; - } - - /* - * Ask the low level driver to verify the settings. - */ - if (uport->ops->verify_port) - retval = uport->ops->verify_port(uport, &new_serial); - - if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)) - retval = -EINVAL; - - if (retval) - goto exit; - - if (change_port || change_irq) { - retval = -EBUSY; - - /* - * Make sure that we are the sole user of this port. - */ - if (tty_port_users(port) > 1) - goto exit; - - /* - * We need to shutdown the serial port at the old - * port/type/irq combination. - */ - uart_shutdown(tty, state); - } - - if (change_port) { - unsigned long old_iobase, old_mapbase; - unsigned int old_type, old_iotype, old_hub6, old_shift; - - old_iobase = uport->iobase; - old_mapbase = uport->mapbase; - old_type = uport->type; - old_hub6 = uport->hub6; - old_iotype = uport->iotype; - old_shift = uport->regshift; - - /* - * Free and release old regions - */ - if (old_type != PORT_UNKNOWN) - 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; - - /* - * Claim and map the new regions - */ - if (uport->type != PORT_UNKNOWN) { - retval = uport->ops->request_port(uport); - } else { - /* Always success - Jean II */ - retval = 0; - } - - /* - * If we fail to request resources for the - * new port, try to restore the old settings. - */ - if (retval && old_type != PORT_UNKNOWN) { - uport->iobase = old_iobase; - uport->type = old_type; - uport->hub6 = old_hub6; - uport->iotype = old_iotype; - uport->regshift = old_shift; - uport->mapbase = old_mapbase; - retval = uport->ops->request_port(uport); - /* - * If we failed to restore the old settings, - * we fail like this. - */ - if (retval) - uport->type = PORT_UNKNOWN; - - /* - * We failed anyway. - */ - retval = -EBUSY; - /* Added to return the correct error -Ram Gupta */ - goto exit; - } - } - - if (change_irq) - uport->irq = new_serial.irq; - if (!(uport->flags & UPF_FIXED_PORT)) - uport->uartclk = new_serial.baud_base * 16; - uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | - (new_flags & UPF_CHANGE_MASK); - uport->custom_divisor = new_serial.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 (port->tty) - port->tty->low_latency = - (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; - - check_and_exit: - retval = 0; - if (uport->type == PORT_UNKNOWN) - goto exit; - if (port->flags & ASYNC_INITIALIZED) { - if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || - old_custom_divisor != uport->custom_divisor) { - /* - * If they're setting up a custom divisor or speed, - * instead of clearing it, then bitch about it. No - * need to rate-limit; it's CAP_SYS_ADMIN only. - */ - if (uport->flags & UPF_SPD_MASK) { - char buf[64]; - printk(KERN_NOTICE - "%s sets custom speed on %s. This " - "is deprecated.\n", current->comm, - tty_name(port->tty, buf)); - } - uart_change_speed(tty, state, NULL); - } - } else - retval = uart_startup(tty, state, 1); - exit: - mutex_unlock(&port->mutex); - return retval; -} - -/** - * uart_get_lsr_info - get line status register info - * @tty: tty associated with the UART - * @state: UART being queried - * @value: returned modem value - * - * Note: uart_ioctl protects us against hangups. - */ -static int uart_get_lsr_info(struct tty_struct *tty, - struct uart_state *state, unsigned int __user *value) -{ - struct uart_port *uport = state->uart_port; - unsigned int result; - - result = uport->ops->tx_empty(uport); - - /* - * If we're about to load something into the transmit - * register, we'll pretend the transmitter isn't empty to - * avoid a race condition (depending on when the transmit - * interrupt happens). - */ - if (uport->x_char || - ((uart_circ_chars_pending(&state->xmit) > 0) && - !tty->stopped && !tty->hw_stopped)) - result &= ~TIOCSER_TEMT; - - return put_user(result, value); -} - -static int uart_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; - int result = -EIO; - - mutex_lock(&port->mutex); - if ((!file || !tty_hung_up_p(file)) && - !(tty->flags & (1 << TTY_IO_ERROR))) { - result = uport->mctrl; - - spin_lock_irq(&uport->lock); - result |= uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); - } - mutex_unlock(&port->mutex); - - return result; -} - -static int -uart_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - int ret = -EIO; - - mutex_lock(&port->mutex); - if ((!file || !tty_hung_up_p(file)) && - !(tty->flags & (1 << TTY_IO_ERROR))) { - uart_update_mctrl(uport, set, clear); - ret = 0; - } - mutex_unlock(&port->mutex); - return ret; -} - -static int uart_break_ctl(struct tty_struct *tty, int break_state) -{ - struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; - struct uart_port *uport = state->uart_port; - - mutex_lock(&port->mutex); - - if (uport->type != PORT_UNKNOWN) - uport->ops->break_ctl(uport, break_state); - - mutex_unlock(&port->mutex); - return 0; -} - -static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) -{ - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - int flags, ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* - * Take the per-port semaphore. This prevents count from - * changing, and hence any extra opens of the port while - * we're auto-configuring. - */ - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; - - ret = -EBUSY; - if (tty_port_users(port) == 1) { - uart_shutdown(tty, state); - - /* - * If we already have a port type configured, - * we must release its resources. - */ - if (uport->type != PORT_UNKNOWN) - uport->ops->release_port(uport); - - flags = UART_CONFIG_TYPE; - if (uport->flags & UPF_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; - - /* - * This will claim the ports resources if - * a port is found. - */ - uport->ops->config_port(uport, flags); - - ret = uart_startup(tty, state, 1); - } - mutex_unlock(&port->mutex); - return ret; -} - -/* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - * - * FIXME: This wants extracting into a common all driver implementation - * of TIOCMWAIT using tty_port. - */ -static int -uart_wait_modem_status(struct uart_state *state, unsigned long arg) -{ - struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - DECLARE_WAITQUEUE(wait, current); - struct uart_icount cprev, cnow; - int ret; - - /* - * note the counters on entry - */ - spin_lock_irq(&uport->lock); - memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - - /* - * Force modem status interrupts on - */ - uport->ops->enable_ms(uport); - spin_unlock_irq(&uport->lock); - - add_wait_queue(&port->delta_msr_wait, &wait); - for (;;) { - spin_lock_irq(&uport->lock); - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&uport->lock); - - set_current_state(TASK_INTERRUPTIBLE); - - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - ret = 0; - break; - } - - schedule(); - - /* see if a signal did it */ - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - cprev = cnow; - } - - current->state = TASK_RUNNING; - remove_wait_queue(&port->delta_msr_wait, &wait); - - return ret; -} - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int uart_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct uart_state *state = tty->driver_data; - struct uart_icount cnow; - struct uart_port *uport = state->uart_port; - - spin_lock_irq(&uport->lock); - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&uport->lock); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - -/* - * Called via sys_ioctl. We can use spin_lock_irq() here. - */ -static int -uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; - void __user *uarg = (void __user *)arg; - int ret = -ENOIOCTLCMD; - - - /* - * These ioctls don't rely on the hardware to be present. - */ - switch (cmd) { - case TIOCGSERIAL: - ret = uart_get_info(state, uarg); - break; - - case TIOCSSERIAL: - ret = uart_set_info(tty, state, uarg); - break; - - case TIOCSERCONFIG: - ret = uart_do_autoconfig(tty, state); - break; - - case TIOCSERGWILD: /* obsolete */ - case TIOCSERSWILD: /* obsolete */ - ret = 0; - break; - } - - if (ret != -ENOIOCTLCMD) - goto out; - - if (tty->flags & (1 << TTY_IO_ERROR)) { - ret = -EIO; - goto out; - } - - /* - * The following should only be used when hardware is present. - */ - switch (cmd) { - case TIOCMIWAIT: - ret = uart_wait_modem_status(state, arg); - break; - } - - if (ret != -ENOIOCTLCMD) - goto out; - - mutex_lock(&port->mutex); - - if (tty_hung_up_p(filp)) { - ret = -EIO; - goto out_up; - } - - /* - * All these rely on hardware being present and need to be - * protected against the tty being hung up. - */ - switch (cmd) { - case TIOCSERGETLSR: /* Get line status register */ - ret = uart_get_lsr_info(tty, state, uarg); - break; - - default: { - struct uart_port *uport = state->uart_port; - if (uport->ops->ioctl) - ret = uport->ops->ioctl(uport, cmd, arg); - break; - } - } -out_up: - mutex_unlock(&port->mutex); -out: - return ret; -} - -static void uart_set_ldisc(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *uport = state->uart_port; - - if (uport->ops->set_ldisc) - uport->ops->set_ldisc(uport, tty->termios->c_line); -} - -static void uart_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct uart_state *state = tty->driver_data; - unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; - - - /* - * These are the bits that are used to setup various - * flags in the low level driver. We can ignore the Bfoo - * bits in c_cflag; c_[io]speed will always be set - * appropriately by set_termios() in tty_ioctl.c - */ -#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) { - return; - } - - uart_change_speed(tty, state, old_termios); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) - uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR); - /* Handle transition away from B0 status */ - else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { - unsigned int mask = TIOCM_DTR; - if (!(cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) - mask |= TIOCM_RTS; - uart_set_mctrl(state->uart_port, mask); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&state->uart_port->lock, flags); - tty->hw_stopped = 0; - __uart_start(tty); - spin_unlock_irqrestore(&state->uart_port->lock, flags); - } - /* Handle turning on CRTSCTS */ - else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { - spin_lock_irqsave(&state->uart_port->lock, flags); - if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) { - tty->hw_stopped = 1; - state->uart_port->ops->stop_tx(state->uart_port); - } - spin_unlock_irqrestore(&state->uart_port->lock, flags); - } -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&state->uart_port.open_wait); -#endif -} - -/* - * In 2.4.5, calls to this will be serialized via the BKL in - * linux/drivers/char/tty_io.c:tty_release() - * linux/drivers/char/tty_io.c:do_tty_handup() - */ -static void uart_close(struct tty_struct *tty, struct file *filp) -{ - struct uart_state *state = tty->driver_data; - struct tty_port *port; - struct uart_port *uport; - unsigned long flags; - - BUG_ON(!tty_locked()); - - if (!state) - return; - - uport = state->uart_port; - port = &state->port; - - pr_debug("uart_close(%d) called\n", uport->line); - - mutex_lock(&port->mutex); - spin_lock_irqsave(&port->lock, flags); - - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&port->lock, flags); - goto done; - } - - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. port->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. - */ - printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " - "port->count is %d\n", port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", - tty->name, port->count); - port->count = 0; - } - if (port->count) { - spin_unlock_irqrestore(&port->lock, flags); - goto done; - } - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters by - * setting tty->closing. - */ - tty->closing = 1; - spin_unlock_irqrestore(&port->lock, flags); - - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { - /* - * hack: open-coded tty_wait_until_sent to avoid - * recursive tty_lock - */ - long timeout = msecs_to_jiffies(port->closing_wait); - if (wait_event_interruptible_timeout(tty->write_wait, - !tty_chars_in_buffer(tty), timeout) >= 0) - __uart_wait_until_sent(uport, timeout); - } - - /* - * At this point, we stop accepting input. To do this, we - * disable the receive line status interrupts. - */ - if (port->flags & ASYNC_INITIALIZED) { - unsigned long flags; - spin_lock_irqsave(&uport->lock, flags); - uport->ops->stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - __uart_wait_until_sent(uport, uport->timeout); - } - - uart_shutdown(tty, state); - uart_flush_buffer(tty); - - tty_ldisc_flush(tty); - - tty_port_tty_set(port, NULL); - spin_lock_irqsave(&port->lock, flags); - tty->closing = 0; - - if (port->blocked_open) { - spin_unlock_irqrestore(&port->lock, flags); - if (port->close_delay) - msleep_interruptible(port->close_delay); - spin_lock_irqsave(&port->lock, flags); - } else if (!uart_console(uport)) { - spin_unlock_irqrestore(&port->lock, flags); - uart_change_pm(state, 3); - spin_lock_irqsave(&port->lock, flags); - } - - /* - * Wake up anyone trying to open this port. - */ - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); - spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&port->open_wait); - -done: - mutex_unlock(&port->mutex); -} - -static void __uart_wait_until_sent(struct uart_port *port, int timeout) -{ - unsigned long char_time, expire; - - if (port->type == PORT_UNKNOWN || port->fifosize == 0) - return; - - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (port->timeout - HZ/50) / port->fifosize; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than port->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*port->timeout. - */ - if (timeout == 0 || timeout > 2 * port->timeout) - timeout = 2 * port->timeout; - - expire = jiffies + timeout; - - pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", - port->line, jiffies, expire); - - /* - * Check whether the transmitter is empty every 'char_time'. - * 'timeout' / 'expire' give us the maximum amount of time - * we wait. - */ - while (!port->ops->tx_empty(port)) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (time_after(jiffies, expire)) - break; - } - set_current_state(TASK_RUNNING); /* might not be needed */ -} - -static void uart_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - - tty_lock(); - __uart_wait_until_sent(port, timeout); - tty_unlock(); -} - -/* - * This is called with the BKL held in - * linux/drivers/char/tty_io.c:do_tty_hangup() - * We're called from the eventd thread, so we can sleep for - * a _short_ time only. - */ -static void uart_hangup(struct tty_struct *tty) -{ - struct uart_state *state = tty->driver_data; - struct tty_port *port = &state->port; - unsigned long flags; - - BUG_ON(!tty_locked()); - pr_debug("uart_hangup(%d)\n", state->uart_port->line); - - mutex_lock(&port->mutex); - if (port->flags & ASYNC_NORMAL_ACTIVE) { - uart_flush_buffer(tty); - uart_shutdown(tty, state); - spin_lock_irqsave(&port->lock, flags); - port->count = 0; - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); - spin_unlock_irqrestore(&port->lock, flags); - tty_port_tty_set(port, NULL); - wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&port->delta_msr_wait); - } - mutex_unlock(&port->mutex); -} - -/** - * uart_update_termios - update the terminal hw settings - * @tty: tty associated with UART - * @state: UART to update - * - * Copy across the serial console cflag setting into the termios settings - * for the initial open of the port. This allows continuity between the - * kernel settings, and the settings init adopts when it opens the port - * for the first time. - */ -static void uart_update_termios(struct tty_struct *tty, - struct uart_state *state) -{ - struct uart_port *port = state->uart_port; - - if (uart_console(port) && port->cons->cflag) { - tty->termios->c_cflag = port->cons->cflag; - port->cons->cflag = 0; - } - - /* - * If the device failed to grab its irq resources, - * or some other error occurred, don't try to talk - * to the port hardware. - */ - if (!(tty->flags & (1 << TTY_IO_ERROR))) { - /* - * Make termios settings take effect. - */ - uart_change_speed(tty, state, NULL); - - /* - * And finally enable the RTS and DTR signals. - */ - if (tty->termios->c_cflag & CBAUD) - uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } -} - -static int uart_carrier_raised(struct tty_port *port) -{ - struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; - int mctrl; - spin_lock_irq(&uport->lock); - uport->ops->enable_ms(uport); - mctrl = uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); - if (mctrl & TIOCM_CAR) - return 1; - return 0; -} - -static void uart_dtr_rts(struct tty_port *port, int onoff) -{ - struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; - - if (onoff) { - uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); - - /* - * If this is the first open to succeed, - * adjust things to suit. - */ - if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags)) - uart_update_termios(port->tty, state); - } - else - uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); -} - -static struct uart_state *uart_get(struct uart_driver *drv, int line) -{ - struct uart_state *state; - struct tty_port *port; - int ret = 0; - - state = drv->state + line; - port = &state->port; - if (mutex_lock_interruptible(&port->mutex)) { - ret = -ERESTARTSYS; - goto err; - } - - port->count++; - if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { - ret = -ENXIO; - goto err_unlock; - } - return state; - - err_unlock: - port->count--; - mutex_unlock(&port->mutex); - err: - return ERR_PTR(ret); -} - -/* - * calls to uart_open are serialised by the BKL in - * fs/char_dev.c:chrdev_open() - * Note that if this fails, then uart_close() _will_ be called. - * - * In time, we want to scrap the "opening nonpresent ports" - * behaviour and implement an alternative way for setserial - * to set base addresses/ports/types. This will allow us to - * get rid of a certain amount of extra tests. - */ -static int uart_open(struct tty_struct *tty, struct file *filp) -{ - struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; - struct uart_state *state; - struct tty_port *port; - int retval, line = tty->index; - - BUG_ON(!tty_locked()); - pr_debug("uart_open(%d) called\n", line); - - /* - * tty->driver->num won't change, so we won't fail here with - * tty->driver_data set to something non-NULL (and therefore - * we won't get caught by uart_close()). - */ - retval = -ENODEV; - if (line >= tty->driver->num) - goto fail; - - /* - * We take the semaphore inside uart_get to guarantee that we won't - * be re-entered while allocating the state structure, or while we - * request any IRQs that the driver may need. This also has the nice - * side-effect that it delays the action of uart_hangup, so we can - * guarantee that state->port.tty will always contain something - * reasonable. - */ - state = uart_get(drv, line); - if (IS_ERR(state)) { - retval = PTR_ERR(state); - goto fail; - } - port = &state->port; - - /* - * Once we set tty->driver_data here, we are guaranteed that - * uart_close() will decrement the driver module use count. - * Any failures from here onwards should not touch the count. - */ - tty->driver_data = state; - state->uart_port->state = state; - tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; - tty->alt_speed = 0; - tty_port_tty_set(port, tty); - - /* - * If the port is in the middle of closing, bail out now. - */ - if (tty_hung_up_p(filp)) { - retval = -EAGAIN; - port->count--; - mutex_unlock(&port->mutex); - goto fail; - } - - /* - * Make sure the device is in D0 state. - */ - if (port->count == 1) - uart_change_pm(state, 0); - - /* - * Start up the serial port. - */ - retval = uart_startup(tty, state, 0); - - /* - * If we succeeded, wait until the port is ready. - */ - mutex_unlock(&port->mutex); - if (retval == 0) - retval = tty_port_block_til_ready(port, tty, filp); - -fail: - return retval; -} - -static const char *uart_type(struct uart_port *port) -{ - const char *str = NULL; - - if (port->ops->type) - str = port->ops->type(port); - - if (!str) - str = "unknown"; - - return str; -} - -#ifdef CONFIG_PROC_FS - -static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) -{ - struct uart_state *state = drv->state + i; - struct tty_port *port = &state->port; - int pm_state; - struct uart_port *uport = state->uart_port; - char stat_buf[32]; - unsigned int status; - int mmio; - - if (!uport) - return; - - mmio = uport->iotype >= UPIO_MEM; - seq_printf(m, "%d: uart:%s %s%08llX irq:%d", - uport->line, uart_type(uport), - mmio ? "mmio:0x" : "port:", - mmio ? (unsigned long long)uport->mapbase - : (unsigned long long)uport->iobase, - uport->irq); - - if (uport->type == PORT_UNKNOWN) { - seq_putc(m, '\n'); - return; - } - - if (capable(CAP_SYS_ADMIN)) { - mutex_lock(&port->mutex); - pm_state = state->pm_state; - if (pm_state) - uart_change_pm(state, 0); - spin_lock_irq(&uport->lock); - status = uport->ops->get_mctrl(uport); - spin_unlock_irq(&uport->lock); - if (pm_state) - uart_change_pm(state, pm_state); - mutex_unlock(&port->mutex); - - seq_printf(m, " tx:%d rx:%d", - uport->icount.tx, uport->icount.rx); - if (uport->icount.frame) - seq_printf(m, " fe:%d", - uport->icount.frame); - if (uport->icount.parity) - seq_printf(m, " pe:%d", - uport->icount.parity); - if (uport->icount.brk) - seq_printf(m, " brk:%d", - uport->icount.brk); - if (uport->icount.overrun) - seq_printf(m, " oe:%d", - uport->icount.overrun); - -#define INFOBIT(bit, str) \ - if (uport->mctrl & (bit)) \ - strncat(stat_buf, (str), sizeof(stat_buf) - \ - strlen(stat_buf) - 2) -#define STATBIT(bit, str) \ - if (status & (bit)) \ - strncat(stat_buf, (str), sizeof(stat_buf) - \ - strlen(stat_buf) - 2) - - stat_buf[0] = '\0'; - stat_buf[1] = '\0'; - INFOBIT(TIOCM_RTS, "|RTS"); - STATBIT(TIOCM_CTS, "|CTS"); - INFOBIT(TIOCM_DTR, "|DTR"); - STATBIT(TIOCM_DSR, "|DSR"); - STATBIT(TIOCM_CAR, "|CD"); - STATBIT(TIOCM_RNG, "|RI"); - if (stat_buf[0]) - stat_buf[0] = ' '; - - seq_puts(m, stat_buf); - } - seq_putc(m, '\n'); -#undef STATBIT -#undef INFOBIT -} - -static int uart_proc_show(struct seq_file *m, void *v) -{ - struct tty_driver *ttydrv = m->private; - struct uart_driver *drv = ttydrv->driver_state; - int i; - - seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", - "", "", ""); - for (i = 0; i < drv->nr; i++) - uart_line_info(m, drv, i); - return 0; -} - -static int uart_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, uart_proc_show, PDE(inode)->data); -} - -static const struct file_operations uart_proc_fops = { - .owner = THIS_MODULE, - .open = uart_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) -/* - * uart_console_write - write a console message to a serial port - * @port: the port to write the message - * @s: array of characters - * @count: number of characters in string to write - * @write: function to write character to port - */ -void uart_console_write(struct uart_port *port, const char *s, - unsigned int count, - void (*putchar)(struct uart_port *, int)) -{ - unsigned int i; - - for (i = 0; i < count; i++, s++) { - if (*s == '\n') - putchar(port, '\r'); - putchar(port, *s); - } -} -EXPORT_SYMBOL_GPL(uart_console_write); - -/* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ -struct uart_port * __init -uart_get_console(struct uart_port *ports, int nr, struct console *co) -{ - int idx = co->index; - - if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && - ports[idx].membase == NULL)) - for (idx = 0; idx < nr; idx++) - if (ports[idx].iobase != 0 || - ports[idx].membase != NULL) - break; - - co->index = idx; - - return ports + idx; -} - -/** - * uart_parse_options - Parse serial port baud/parity/bits/flow contro. - * @options: pointer to option string - * @baud: pointer to an 'int' variable for the baud rate. - * @parity: pointer to an 'int' variable for the parity. - * @bits: pointer to an 'int' variable for the number of data bits. - * @flow: pointer to an 'int' variable for the flow control character. - * - * uart_parse_options decodes a string containing the serial console - * options. The format of the string is , - * eg: 115200n8r - */ -void -uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) -{ - char *s = options; - - *baud = simple_strtoul(s, NULL, 10); - while (*s >= '0' && *s <= '9') - s++; - if (*s) - *parity = *s++; - if (*s) - *bits = *s++ - '0'; - if (*s) - *flow = *s; -} -EXPORT_SYMBOL_GPL(uart_parse_options); - -struct baud_rates { - unsigned int rate; - unsigned int cflag; -}; - -static const struct baud_rates baud_rates[] = { - { 921600, B921600 }, - { 460800, B460800 }, - { 230400, B230400 }, - { 115200, B115200 }, - { 57600, B57600 }, - { 38400, B38400 }, - { 19200, B19200 }, - { 9600, B9600 }, - { 4800, B4800 }, - { 2400, B2400 }, - { 1200, B1200 }, - { 0, B38400 } -}; - -/** - * uart_set_options - setup the serial console parameters - * @port: pointer to the serial ports uart_port structure - * @co: console pointer - * @baud: baud rate - * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) - * @bits: number of data bits - * @flow: flow control character - 'r' (rts) - */ -int -uart_set_options(struct uart_port *port, struct console *co, - int baud, int parity, int bits, int flow) -{ - struct ktermios termios; - static struct ktermios dummy; - int i; - - /* - * Ensure that the serial console lock is initialised - * early. - */ - spin_lock_init(&port->lock); - lockdep_set_class(&port->lock, &port_lock_key); - - memset(&termios, 0, sizeof(struct ktermios)); - - termios.c_cflag = CREAD | HUPCL | CLOCAL; - - /* - * Construct a cflag setting. - */ - for (i = 0; baud_rates[i].rate; i++) - if (baud_rates[i].rate <= baud) - break; - - termios.c_cflag |= baud_rates[i].cflag; - - if (bits == 7) - termios.c_cflag |= CS7; - else - termios.c_cflag |= CS8; - - switch (parity) { - case 'o': case 'O': - termios.c_cflag |= PARODD; - /*fall through*/ - case 'e': case 'E': - termios.c_cflag |= PARENB; - break; - } - - if (flow == 'r') - termios.c_cflag |= CRTSCTS; - - /* - * some uarts on other side don't support no flow control. - * So we set * DTR in host uart to make them happy - */ - port->mctrl |= TIOCM_DTR; - - port->ops->set_termios(port, &termios, &dummy); - /* - * Allow the setting of the UART parameters with a NULL console - * too: - */ - if (co) - co->cflag = termios.c_cflag; - - return 0; -} -EXPORT_SYMBOL_GPL(uart_set_options); -#endif /* CONFIG_SERIAL_CORE_CONSOLE */ - -static void uart_change_pm(struct uart_state *state, int pm_state) -{ - struct uart_port *port = state->uart_port; - - if (state->pm_state != pm_state) { - if (port->ops->pm) - port->ops->pm(port, pm_state, state->pm_state); - state->pm_state = pm_state; - } -} - -struct uart_match { - struct uart_port *port; - struct uart_driver *driver; -}; - -static int serial_match_port(struct device *dev, void *data) -{ - struct uart_match *match = data; - struct tty_driver *tty_drv = match->driver->tty_driver; - dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + - match->port->line; - - return dev->devt == devt; /* Actually, only one tty per port */ -} - -int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) -{ - struct uart_state *state = drv->state + uport->line; - struct tty_port *port = &state->port; - struct device *tty_dev; - struct uart_match match = {uport, drv}; - struct tty_struct *tty; - - mutex_lock(&port->mutex); - - /* Must be inside the mutex lock until we convert to tty_port */ - tty = port->tty; - - tty_dev = device_find_child(uport->dev, &match, serial_match_port); - if (device_may_wakeup(tty_dev)) { - if (!enable_irq_wake(uport->irq)) - uport->irq_wake = 1; - put_device(tty_dev); - mutex_unlock(&port->mutex); - return 0; - } - if (console_suspend_enabled || !uart_console(uport)) - uport->suspended = 1; - - if (port->flags & ASYNC_INITIALIZED) { - const struct uart_ops *ops = uport->ops; - int tries; - - if (console_suspend_enabled || !uart_console(uport)) { - set_bit(ASYNCB_SUSPENDED, &port->flags); - clear_bit(ASYNCB_INITIALIZED, &port->flags); - - spin_lock_irq(&uport->lock); - ops->stop_tx(uport); - ops->set_mctrl(uport, 0); - ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); - } - - /* - * Wait for the transmitter to empty. - */ - for (tries = 3; !ops->tx_empty(uport) && tries; tries--) - msleep(10); - if (!tries) - printk(KERN_ERR "%s%s%s%d: Unable to drain " - "transmitter\n", - uport->dev ? dev_name(uport->dev) : "", - uport->dev ? ": " : "", - drv->dev_name, - drv->tty_driver->name_base + uport->line); - - if (console_suspend_enabled || !uart_console(uport)) - ops->shutdown(uport); - } - - /* - * Disable the console device before suspending. - */ - if (console_suspend_enabled && uart_console(uport)) - console_stop(uport->cons); - - if (console_suspend_enabled || !uart_console(uport)) - uart_change_pm(state, 3); - - mutex_unlock(&port->mutex); - - return 0; -} - -int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) -{ - struct uart_state *state = drv->state + uport->line; - struct tty_port *port = &state->port; - struct device *tty_dev; - struct uart_match match = {uport, drv}; - struct ktermios termios; - - mutex_lock(&port->mutex); - - tty_dev = device_find_child(uport->dev, &match, serial_match_port); - if (!uport->suspended && device_may_wakeup(tty_dev)) { - if (uport->irq_wake) { - disable_irq_wake(uport->irq); - uport->irq_wake = 0; - } - mutex_unlock(&port->mutex); - return 0; - } - uport->suspended = 0; - - /* - * Re-enable the console device after suspending. - */ - if (console_suspend_enabled && uart_console(uport)) { - /* - * First try to use the console cflag setting. - */ - memset(&termios, 0, sizeof(struct ktermios)); - termios.c_cflag = uport->cons->cflag; - - /* - * If that's unset, use the tty termios setting. - */ - if (port->tty && port->tty->termios && termios.c_cflag == 0) - termios = *(port->tty->termios); - - uart_change_pm(state, 0); - uport->ops->set_termios(uport, &termios, NULL); - console_start(uport->cons); - } - - if (port->flags & ASYNC_SUSPENDED) { - const struct uart_ops *ops = uport->ops; - int ret; - - uart_change_pm(state, 0); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, 0); - spin_unlock_irq(&uport->lock); - if (console_suspend_enabled || !uart_console(uport)) { - /* Protected by port mutex for now */ - struct tty_struct *tty = port->tty; - ret = ops->startup(uport); - if (ret == 0) { - if (tty) - uart_change_speed(tty, state, NULL); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, uport->mctrl); - ops->start_tx(uport); - spin_unlock_irq(&uport->lock); - set_bit(ASYNCB_INITIALIZED, &port->flags); - } else { - /* - * Failed to resume - maybe hardware went away? - * Clear the "initialized" flag so we won't try - * to call the low level drivers shutdown method. - */ - uart_shutdown(tty, state); - } - } - - clear_bit(ASYNCB_SUSPENDED, &port->flags); - } - - mutex_unlock(&port->mutex); - - return 0; -} - -static inline void -uart_report_port(struct uart_driver *drv, struct uart_port *port) -{ - char address[64]; - - switch (port->iotype) { - case UPIO_PORT: - snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); - break; - case UPIO_HUB6: - snprintf(address, sizeof(address), - "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); - break; - case UPIO_MEM: - case UPIO_MEM32: - case UPIO_AU: - case UPIO_TSI: - case UPIO_DWAPB: - case UPIO_DWAPB32: - snprintf(address, sizeof(address), - "MMIO 0x%llx", (unsigned long long)port->mapbase); - break; - default: - strlcpy(address, "*unknown*", sizeof(address)); - break; - } - - printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", - port->dev ? dev_name(port->dev) : "", - port->dev ? ": " : "", - drv->dev_name, - drv->tty_driver->name_base + port->line, - address, port->irq, uart_type(port)); -} - -static void -uart_configure_port(struct uart_driver *drv, struct uart_state *state, - struct uart_port *port) -{ - unsigned int flags; - - /* - * If there isn't a port here, don't do anything further. - */ - if (!port->iobase && !port->mapbase && !port->membase) - return; - - /* - * Now do the auto configuration stuff. Note that config_port - * is expected to claim the resources and map the port for us. - */ - flags = 0; - if (port->flags & UPF_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; - if (port->flags & UPF_BOOT_AUTOCONF) { - if (!(port->flags & UPF_FIXED_TYPE)) { - port->type = PORT_UNKNOWN; - flags |= UART_CONFIG_TYPE; - } - port->ops->config_port(port, flags); - } - - if (port->type != PORT_UNKNOWN) { - unsigned long flags; - - uart_report_port(drv, port); - - /* Power up port for set_mctrl() */ - uart_change_pm(state, 0); - - /* - * Ensure that the modem control lines are de-activated. - * keep the DTR setting that is set in uart_set_options() - * We probably don't need a spinlock around this, but - */ - spin_lock_irqsave(&port->lock, flags); - port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * If this driver supports console, and it hasn't been - * successfully registered yet, try to re-register it. - * It may be that the port was not available. - */ - if (port->cons && !(port->cons->flags & CON_ENABLED)) - register_console(port->cons); - - /* - * Power down all ports by default, except the - * console if we have one. - */ - if (!uart_console(port)) - uart_change_pm(state, 3); - } -} - -#ifdef CONFIG_CONSOLE_POLL - -static int uart_poll_init(struct tty_driver *driver, int line, char *options) -{ - struct uart_driver *drv = driver->driver_state; - struct uart_state *state = drv->state + line; - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (!state || !state->uart_port) - return -1; - - port = state->uart_port; - if (!(port->ops->poll_get_char && port->ops->poll_put_char)) - return -1; - - if (options) { - uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(port, NULL, baud, parity, bits, flow); - } - - return 0; -} - -static int uart_poll_get_char(struct tty_driver *driver, int line) -{ - struct uart_driver *drv = driver->driver_state; - struct uart_state *state = drv->state + line; - struct uart_port *port; - - if (!state || !state->uart_port) - return -1; - - port = state->uart_port; - return port->ops->poll_get_char(port); -} - -static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) -{ - struct uart_driver *drv = driver->driver_state; - struct uart_state *state = drv->state + line; - struct uart_port *port; - - if (!state || !state->uart_port) - return; - - port = state->uart_port; - port->ops->poll_put_char(port, ch); -} -#endif - -static const struct tty_operations uart_ops = { - .open = uart_open, - .close = uart_close, - .write = uart_write, - .put_char = uart_put_char, - .flush_chars = uart_flush_chars, - .write_room = uart_write_room, - .chars_in_buffer= uart_chars_in_buffer, - .flush_buffer = uart_flush_buffer, - .ioctl = uart_ioctl, - .throttle = uart_throttle, - .unthrottle = uart_unthrottle, - .send_xchar = uart_send_xchar, - .set_termios = uart_set_termios, - .set_ldisc = uart_set_ldisc, - .stop = uart_stop, - .start = uart_start, - .hangup = uart_hangup, - .break_ctl = uart_break_ctl, - .wait_until_sent= uart_wait_until_sent, -#ifdef CONFIG_PROC_FS - .proc_fops = &uart_proc_fops, -#endif - .tiocmget = uart_tiocmget, - .tiocmset = uart_tiocmset, - .get_icount = uart_get_icount, -#ifdef CONFIG_CONSOLE_POLL - .poll_init = uart_poll_init, - .poll_get_char = uart_poll_get_char, - .poll_put_char = uart_poll_put_char, -#endif -}; - -static const struct tty_port_operations uart_port_ops = { - .carrier_raised = uart_carrier_raised, - .dtr_rts = uart_dtr_rts, -}; - -/** - * uart_register_driver - register a driver with the uart core layer - * @drv: low level driver structure - * - * Register a uart driver with the core driver. We in turn register - * with the tty layer, and initialise the core driver per-port state. - * - * We have a proc file in /proc/tty/driver which is named after the - * normal driver. - * - * drv->port should be NULL, and the per-port structures should be - * registered using uart_add_one_port after this call has succeeded. - */ -int uart_register_driver(struct uart_driver *drv) -{ - struct tty_driver *normal; - int i, retval; - - BUG_ON(drv->state); - - /* - * Maybe we should be using a slab cache for this, especially if - * we have a large number of ports to handle. - */ - drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); - if (!drv->state) - goto out; - - normal = alloc_tty_driver(drv->nr); - if (!normal) - goto out_kfree; - - drv->tty_driver = normal; - - normal->owner = drv->owner; - normal->driver_name = drv->driver_name; - normal->name = drv->dev_name; - normal->major = drv->major; - normal->minor_start = drv->minor; - normal->type = TTY_DRIVER_TYPE_SERIAL; - normal->subtype = SERIAL_TYPE_NORMAL; - normal->init_termios = tty_std_termios; - normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; - normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - normal->driver_state = drv; - tty_set_operations(normal, &uart_ops); - - /* - * Initialise the UART state(s). - */ - for (i = 0; i < drv->nr; i++) { - struct uart_state *state = drv->state + i; - struct tty_port *port = &state->port; - - tty_port_init(port); - port->ops = &uart_port_ops; - port->close_delay = 500; /* .5 seconds */ - port->closing_wait = 30000; /* 30 seconds */ - tasklet_init(&state->tlet, uart_tasklet_action, - (unsigned long)state); - } - - retval = tty_register_driver(normal); - if (retval >= 0) - return retval; - - put_tty_driver(normal); -out_kfree: - kfree(drv->state); -out: - return -ENOMEM; -} - -/** - * uart_unregister_driver - remove a driver from the uart core layer - * @drv: low level driver structure - * - * Remove all references to a driver from the core driver. The low - * level driver must have removed all its ports via the - * uart_remove_one_port() if it registered them with uart_add_one_port(). - * (ie, drv->port == NULL) - */ -void uart_unregister_driver(struct uart_driver *drv) -{ - struct tty_driver *p = drv->tty_driver; - tty_unregister_driver(p); - put_tty_driver(p); - kfree(drv->state); - drv->tty_driver = NULL; -} - -struct tty_driver *uart_console_device(struct console *co, int *index) -{ - struct uart_driver *p = co->data; - *index = co->index; - return p->tty_driver; -} - -/** - * uart_add_one_port - attach a driver-defined port structure - * @drv: pointer to the uart low level driver structure for this port - * @uport: uart port structure to use for this port. - * - * This allows the driver to register its own uart_port structure - * with the core driver. The main purpose is to allow the low - * level uart drivers to expand uart_port, rather than having yet - * more levels of structures. - */ -int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) -{ - struct uart_state *state; - struct tty_port *port; - int ret = 0; - struct device *tty_dev; - - BUG_ON(in_interrupt()); - - if (uport->line >= drv->nr) - return -EINVAL; - - state = drv->state + uport->line; - port = &state->port; - - mutex_lock(&port_mutex); - mutex_lock(&port->mutex); - if (state->uart_port) { - ret = -EINVAL; - goto out; - } - - state->uart_port = uport; - state->pm_state = -1; - - uport->cons = drv->cons; - uport->state = state; - - /* - * If this port is a console, then the spinlock is already - * initialised. - */ - if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { - spin_lock_init(&uport->lock); - lockdep_set_class(&uport->lock, &port_lock_key); - } - - uart_configure_port(drv, state, 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); - if (likely(!IS_ERR(tty_dev))) { - device_init_wakeup(tty_dev, 1); - device_set_wakeup_enable(tty_dev, 0); - } else - printk(KERN_ERR "Cannot register tty device on line %d\n", - uport->line); - - /* - * Ensure UPF_DEAD is not set. - */ - uport->flags &= ~UPF_DEAD; - - out: - mutex_unlock(&port->mutex); - mutex_unlock(&port_mutex); - - return ret; -} - -/** - * uart_remove_one_port - detach a driver defined port structure - * @drv: pointer to the uart low level driver structure for this port - * @uport: uart port structure for this port - * - * This unhooks (and hangs up) the specified port structure from the - * core driver. No further calls will be made to the low-level code - * for this port. - */ -int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) -{ - struct uart_state *state = drv->state + uport->line; - struct tty_port *port = &state->port; - - BUG_ON(in_interrupt()); - - if (state->uart_port != uport) - printk(KERN_ALERT "Removing wrong port: %p != %p\n", - state->uart_port, uport); - - mutex_lock(&port_mutex); - - /* - * Mark the port "dead" - this prevents any opens from - * succeeding while we shut down the port. - */ - mutex_lock(&port->mutex); - uport->flags |= UPF_DEAD; - mutex_unlock(&port->mutex); - - /* - * Remove the devices from the tty layer - */ - tty_unregister_device(drv->tty_driver, uport->line); - - if (port->tty) - tty_vhangup(port->tty); - - /* - * Free the port IO and memory resources, if any. - */ - if (uport->type != PORT_UNKNOWN) - uport->ops->release_port(uport); - - /* - * Indicate that there isn't a port here anymore. - */ - uport->type = PORT_UNKNOWN; - - /* - * Kill the tasklet, and free resources. - */ - tasklet_kill(&state->tlet); - - state->uart_port = NULL; - mutex_unlock(&port_mutex); - - return 0; -} - -/* - * Are the two ports equivalent? - */ -int uart_match_port(struct uart_port *port1, struct uart_port *port2) -{ - if (port1->iotype != port2->iotype) - return 0; - - switch (port1->iotype) { - case UPIO_PORT: - return (port1->iobase == port2->iobase); - case UPIO_HUB6: - return (port1->iobase == port2->iobase) && - (port1->hub6 == port2->hub6); - case UPIO_MEM: - case UPIO_MEM32: - case UPIO_AU: - case UPIO_TSI: - case UPIO_DWAPB: - case UPIO_DWAPB32: - return (port1->mapbase == port2->mapbase); - } - return 0; -} -EXPORT_SYMBOL(uart_match_port); - -EXPORT_SYMBOL(uart_write_wakeup); -EXPORT_SYMBOL(uart_register_driver); -EXPORT_SYMBOL(uart_unregister_driver); -EXPORT_SYMBOL(uart_suspend_port); -EXPORT_SYMBOL(uart_resume_port); -EXPORT_SYMBOL(uart_add_one_port); -EXPORT_SYMBOL(uart_remove_one_port); - -MODULE_DESCRIPTION("Serial driver core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c deleted file mode 100644 index 93760b2ea172..000000000000 --- a/drivers/serial/serial_cs.c +++ /dev/null @@ -1,869 +0,0 @@ -/*====================================================================== - - A driver for PCMCIA serial devices - - serial_cs.c 1.134 2002/05/04 05:48:53 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "8250.h" - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* Enable the speaker? */ -static int do_sound = 1; -/* Skip strict UART tests? */ -static int buggy_uart; - -module_param(do_sound, int, 0444); -module_param(buggy_uart, int, 0444); - -/*====================================================================*/ - -/* Table of multi-port card ID's */ - -struct serial_quirk { - unsigned int manfid; - unsigned int prodid; - int multi; /* 1 = multifunction, > 1 = # ports */ - void (*config)(struct pcmcia_device *); - void (*setup)(struct pcmcia_device *, struct uart_port *); - void (*wakeup)(struct pcmcia_device *); - int (*post)(struct pcmcia_device *); -}; - -struct serial_info { - struct pcmcia_device *p_dev; - int ndev; - int multi; - int slave; - int manfid; - int prodid; - int c950ctrl; - int line[4]; - const struct serial_quirk *quirk; -}; - -struct serial_cfg_mem { - tuple_t tuple; - cisparse_t parse; - u_char buf[256]; -}; - -/* - * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6" - * manfid 0x0160, 0x0104 - * This card appears to have a 14.7456MHz clock. - */ -/* Generic Modem: MD55x (GPRS/EDGE) have - * Elan VPU16551 UART with 14.7456MHz oscillator - * manfid 0x015D, 0x4C45 - */ -static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port) -{ - port->uartclk = 14745600; -} - -static int quirk_post_ibm(struct pcmcia_device *link) -{ - u8 val; - int ret; - - ret = pcmcia_read_config_byte(link, 0x800, &val); - if (ret) - goto failed; - - ret = pcmcia_write_config_byte(link, 0x800, val | 1); - if (ret) - goto failed; - return 0; - - failed: - return -ENODEV; -} - -/* - * Nokia cards are not really multiport cards. Shouldn't this - * be handled by setting the quirk entry .multi = 0 | 1 ? - */ -static void quirk_config_nokia(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - - if (info->multi > 1) - info->multi = 1; -} - -static void quirk_wakeup_oxsemi(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - - if (info->c950ctrl) - outb(12, info->c950ctrl + 1); -} - -/* request_region? oxsemi branch does no request_region too... */ -/* - * This sequence is needed to properly initialize MC45 attached to OXCF950. - * I tried decreasing these msleep()s, but it worked properly (survived - * 1000 stop/start operations) with these timeouts (or bigger). - */ -static void quirk_wakeup_possio_gcc(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - unsigned int ctrl = info->c950ctrl; - - outb(0xA, ctrl + 1); - msleep(100); - outb(0xE, ctrl + 1); - msleep(300); - outb(0xC, ctrl + 1); - msleep(100); - outb(0xE, ctrl + 1); - msleep(200); - outb(0xF, ctrl + 1); - msleep(100); - outb(0xE, ctrl + 1); - msleep(100); - outb(0xC, ctrl + 1); -} - -/* - * Socket Dual IO: this enables irq's for second port - */ -static void quirk_config_socket(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - - if (info->multi) - link->config_flags |= CONF_ENABLE_ESR; -} - -static const struct serial_quirk quirks[] = { - { - .manfid = 0x0160, - .prodid = 0x0104, - .multi = -1, - .setup = quirk_setup_brainboxes_0104, - }, { - .manfid = 0x015D, - .prodid = 0x4C45, - .multi = -1, - .setup = quirk_setup_brainboxes_0104, - }, { - .manfid = MANFID_IBM, - .prodid = ~0, - .multi = -1, - .post = quirk_post_ibm, - }, { - .manfid = MANFID_INTEL, - .prodid = PRODID_INTEL_DUAL_RS232, - .multi = 2, - }, { - .manfid = MANFID_NATINST, - .prodid = PRODID_NATINST_QUAD_RS232, - .multi = 4, - }, { - .manfid = MANFID_NOKIA, - .prodid = ~0, - .multi = -1, - .config = quirk_config_nokia, - }, { - .manfid = MANFID_OMEGA, - .prodid = PRODID_OMEGA_QSP_100, - .multi = 4, - }, { - .manfid = MANFID_OXSEMI, - .prodid = ~0, - .multi = -1, - .wakeup = quirk_wakeup_oxsemi, - }, { - .manfid = MANFID_POSSIO, - .prodid = PRODID_POSSIO_GCC, - .multi = -1, - .wakeup = quirk_wakeup_possio_gcc, - }, { - .manfid = MANFID_QUATECH, - .prodid = PRODID_QUATECH_DUAL_RS232, - .multi = 2, - }, { - .manfid = MANFID_QUATECH, - .prodid = PRODID_QUATECH_DUAL_RS232_D1, - .multi = 2, - }, { - .manfid = MANFID_QUATECH, - .prodid = PRODID_QUATECH_DUAL_RS232_G, - .multi = 2, - }, { - .manfid = MANFID_QUATECH, - .prodid = PRODID_QUATECH_QUAD_RS232, - .multi = 4, - }, { - .manfid = MANFID_SOCKET, - .prodid = PRODID_SOCKET_DUAL_RS232, - .multi = 2, - .config = quirk_config_socket, - }, { - .manfid = MANFID_SOCKET, - .prodid = ~0, - .multi = -1, - .config = quirk_config_socket, - } -}; - - -static int serial_config(struct pcmcia_device * link); - - -static void serial_remove(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - int i; - - dev_dbg(&link->dev, "serial_release\n"); - - /* - * Recheck to see if the device is still configured. - */ - for (i = 0; i < info->ndev; i++) - serial8250_unregister_port(info->line[i]); - - if (!info->slave) - pcmcia_disable_device(link); -} - -static int serial_suspend(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - int i; - - for (i = 0; i < info->ndev; i++) - serial8250_suspend_port(info->line[i]); - - return 0; -} - -static int serial_resume(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - int i; - - for (i = 0; i < info->ndev; i++) - serial8250_resume_port(info->line[i]); - - if (info->quirk && info->quirk->wakeup) - info->quirk->wakeup(link); - - return 0; -} - -static int serial_probe(struct pcmcia_device *link) -{ - struct serial_info *info; - - dev_dbg(&link->dev, "serial_attach()\n"); - - /* Create new serial device */ - info = kzalloc(sizeof (*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ; - if (do_sound) - link->config_flags |= CONF_ENABLE_SPKR; - - return serial_config(link); -} - -static void serial_detach(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - - dev_dbg(&link->dev, "serial_detach\n"); - - /* - * Ensure that the ports have been released. - */ - serial_remove(link); - - /* free bits */ - kfree(info); -} - -/*====================================================================*/ - -static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, - unsigned int iobase, int irq) -{ - struct uart_port port; - 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; - if (buggy_uart) - port.flags |= UPF_BUGGY_UART; - - if (info->quirk && info->quirk->setup) - info->quirk->setup(handle, &port); - - line = serial8250_register_port(&port); - if (line < 0) { - printk(KERN_NOTICE "serial_cs: serial8250_register_port() at " - "0x%04lx, irq %d failed\n", (u_long)iobase, irq); - return -EINVAL; - } - - info->line[info->ndev] = line; - info->ndev++; - - return 0; -} - -/*====================================================================*/ - -static int pfc_config(struct pcmcia_device *p_dev) -{ - unsigned int port = 0; - struct serial_info *info = p_dev->priv; - - if ((p_dev->resource[1]->end != 0) && - (resource_size(p_dev->resource[1]) == 8)) { - port = p_dev->resource[1]->start; - info->slave = 1; - } else if ((info->manfid == MANFID_OSITECH) && - (resource_size(p_dev->resource[0]) == 0x40)) { - port = p_dev->resource[0]->start + 0x28; - info->slave = 1; - } - if (info->slave) - return setup_serial(p_dev, info, port, p_dev->irq); - - dev_warn(&p_dev->dev, "no usable port range found, giving up\n"); - return -ENODEV; -} - -static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - static const int size_table[2] = { 8, 16 }; - int *try = priv_data; - - if (p_dev->resource[0]->start == 0) - return -ENODEV; - - if ((*try & 0x1) == 0) - p_dev->io_lines = 16; - - if (p_dev->resource[0]->end != size_table[(*try >> 1)]) - return -ENODEV; - - p_dev->resource[0]->end = 8; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - return pcmcia_request_io(p_dev); -} - -static int simple_config_check_notpicky(struct pcmcia_device *p_dev, - void *priv_data) -{ - static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - int j; - - if (p_dev->io_lines > 3) - return -ENODEV; - - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = 8; - - for (j = 0; j < 5; j++) { - p_dev->resource[0]->start = base[j]; - p_dev->io_lines = base[j] ? 16 : 3; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int simple_config(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - int i = -ENODEV, try; - - /* First pass: look for a config entry that looks normal. - * Two tries: without IO aliases, then with aliases */ - link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO; - for (try = 0; try < 4; try++) - if (!pcmcia_loop_config(link, simple_config_check, &try)) - goto found_port; - - /* Second pass: try to find an entry that isn't picky about - its base address, then try to grab any standard serial port - address, and finally try to get any free port. */ - if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) - goto found_port; - - dev_warn(&link->dev, "no usable port range found, giving up\n"); - return -1; - -found_port: - if (info->multi && (info->manfid == MANFID_3COM)) - link->config_index &= ~(0x08); - - /* - * Apply any configuration quirks. - */ - if (info->quirk && info->quirk->config) - info->quirk->config(link); - - i = pcmcia_enable_device(link); - if (i != 0) - return -1; - return setup_serial(link, info, link->resource[0]->start, link->irq); -} - -static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - int *multi = priv_data; - - if (p_dev->resource[1]->end) - return -EINVAL; - - /* The quad port cards have bad CIS's, so just look for a - window larger than 8 ports and assume it will be right */ - if (p_dev->resource[0]->end <= 8) - return -EINVAL; - - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = *multi * 8; - - if (pcmcia_request_io(p_dev)) - return -ENODEV; - return 0; -} - -static int multi_config_check_notpicky(struct pcmcia_device *p_dev, - void *priv_data) -{ - int *base2 = priv_data; - - if (!p_dev->resource[0]->end || !p_dev->resource[1]->end) - return -ENODEV; - - p_dev->resource[0]->end = p_dev->resource[1]->end = 8; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - if (pcmcia_request_io(p_dev)) - return -ENODEV; - - *base2 = p_dev->resource[0]->start + 8; - return 0; -} - -static int multi_config(struct pcmcia_device *link) -{ - struct serial_info *info = link->priv; - int i, base2 = 0; - - link->config_flags |= CONF_AUTO_SET_IO; - /* First, look for a generic full-sized window */ - if (!pcmcia_loop_config(link, multi_config_check, &info->multi)) - base2 = link->resource[0]->start + 8; - else { - /* If that didn't work, look for two windows */ - info->multi = 2; - if (pcmcia_loop_config(link, multi_config_check_notpicky, - &base2)) { - dev_warn(&link->dev, "no usable port range " - "found, giving up\n"); - return -ENODEV; - } - } - - if (!link->irq) - dev_warn(&link->dev, "no usable IRQ found, continuing...\n"); - - /* - * Apply any configuration quirks. - */ - if (info->quirk && info->quirk->config) - info->quirk->config(link); - - i = pcmcia_enable_device(link); - if (i != 0) - return -ENODEV; - - /* The Oxford Semiconductor OXCF950 cards are in fact single-port: - * 8 registers are for the UART, the others are extra registers. - * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too. - */ - if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && - info->prodid == PRODID_POSSIO_GCC)) { - int err; - - if (link->config_index == 1 || - link->config_index == 3) { - err = setup_serial(link, info, base2, - link->irq); - base2 = link->resource[0]->start; - } else { - err = setup_serial(link, info, link->resource[0]->start, - link->irq); - } - info->c950ctrl = base2; - - /* - * FIXME: We really should wake up the port prior to - * handing it over to the serial layer. - */ - if (info->quirk && info->quirk->wakeup) - info->quirk->wakeup(link); - - return 0; - } - - setup_serial(link, info, link->resource[0]->start, link->irq); - for (i = 0; i < info->multi - 1; i++) - setup_serial(link, info, base2 + (8 * i), - link->irq); - return 0; -} - -static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data) -{ - struct serial_info *info = p_dev->priv; - - if (!p_dev->resource[0]->end) - return -EINVAL; - - if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0)) - info->multi = p_dev->resource[0]->end >> 3; - - if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8) - && (p_dev->resource[1]->end == 8)) - info->multi = 2; - - return 0; /* break */ -} - - -static int serial_config(struct pcmcia_device * link) -{ - struct serial_info *info = link->priv; - int i; - - dev_dbg(&link->dev, "serial_config\n"); - - /* Is this a compliant multifunction card? */ - info->multi = (link->socket->functions > 1); - - /* Is this a multiport card? */ - info->manfid = link->manf_id; - info->prodid = link->card_id; - - for (i = 0; i < ARRAY_SIZE(quirks); i++) - if ((quirks[i].manfid == ~0 || - quirks[i].manfid == info->manfid) && - (quirks[i].prodid == ~0 || - quirks[i].prodid == info->prodid)) { - info->quirk = &quirks[i]; - break; - } - - /* Another check for dual-serial cards: look for either serial or - multifunction cards that ask for appropriate IO port ranges */ - if ((info->multi == 0) && - (link->has_func_id) && - (link->socket->pcmcia_pfc == 0) && - ((link->func_id == CISTPL_FUNCID_MULTI) || - (link->func_id == CISTPL_FUNCID_SERIAL))) - pcmcia_loop_config(link, serial_check_for_multi, info); - - /* - * Apply any multi-port quirk. - */ - if (info->quirk && info->quirk->multi != -1) - info->multi = info->quirk->multi; - - dev_info(&link->dev, - "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n", - link->manf_id, link->card_id, - link->socket->pcmcia_pfc, info->multi, info->quirk); - if (link->socket->pcmcia_pfc) - i = pfc_config(link); - else if (info->multi > 1) - i = multi_config(link); - else - i = simple_config(link); - - if (i || info->ndev == 0) - goto failed; - - /* - * Apply any post-init quirk. FIXME: This should really happen - * before we register the port, since it might already be in use. - */ - if (info->quirk && info->quirk->post) - if (info->quirk->post(link)) - goto failed; - - return 0; - -failed: - dev_warn(&link->dev, "failed to initialize\n"); - serial_remove(link); - return -ENODEV; -} - -static struct pcmcia_device_id serial_ids[] = { - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab), - PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea), - PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023), - PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a), - PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29), - PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed), - PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101), - PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070), - PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562), - PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070), - PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020), - PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f), - PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c), - PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3), - PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15), - PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77), - PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302), - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301), - PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276), - PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), - PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */ - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */ - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */ - PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), - PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */ - PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50), - PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51), - PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52), - PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53), - PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180), - PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */ - PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */ - PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */ - PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e), - PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b), - PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025), - PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045), - PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052), - PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */ - PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */ - PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae), - PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef), - PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), - PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef), - PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0), - PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e), - PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a), - PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02), - PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa), - PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76), - PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95), - PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed), - PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65), - PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b), - PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6), - PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb), - PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447), - PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f), - PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f), - PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383), - PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e), - PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), - PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41), - PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), - PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), - PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), - PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38), - PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"), - PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"), - PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"), - PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ - PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */ - PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ - PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ - PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ - PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"), - PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"), - PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"), - PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3), - PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676), - PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), - PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), - PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b), - /* too generic */ - /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */ - /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */ - PCMCIA_DEVICE_FUNC_ID(2), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, serial_ids); - -MODULE_FIRMWARE("cis/PCMLM28.cis"); -MODULE_FIRMWARE("cis/DP83903.cis"); -MODULE_FIRMWARE("cis/3CCFEM556.cis"); -MODULE_FIRMWARE("cis/3CXEM556.cis"); -MODULE_FIRMWARE("cis/SW_8xx_SER.cis"); -MODULE_FIRMWARE("cis/SW_7xx_SER.cis"); -MODULE_FIRMWARE("cis/SW_555_SER.cis"); -MODULE_FIRMWARE("cis/MT5634ZLX.cis"); -MODULE_FIRMWARE("cis/COMpad2.cis"); -MODULE_FIRMWARE("cis/COMpad4.cis"); -MODULE_FIRMWARE("cis/RS-COM-2P.cis"); - -static struct pcmcia_driver serial_cs_driver = { - .owner = THIS_MODULE, - .name = "serial_cs", - .probe = serial_probe, - .remove = serial_detach, - .id_table = serial_ids, - .suspend = serial_suspend, - .resume = serial_resume, -}; - -static int __init init_serial_cs(void) -{ - return pcmcia_register_driver(&serial_cs_driver); -} - -static void __exit exit_serial_cs(void) -{ - pcmcia_unregister_driver(&serial_cs_driver); -} - -module_init(init_serial_cs); -module_exit(exit_serial_cs); - -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c deleted file mode 100644 index b1962025b1aa..000000000000 --- a/drivers/serial/serial_ks8695.c +++ /dev/null @@ -1,705 +0,0 @@ -/* - * drivers/serial/serial_ks8695.c - * - * Driver for KS8695 serial ports - * - * Based on drivers/serial/serial_amba.c, by Kam Lee. - * - * Copyright 2002-2005 Micrel Inc. - * - * 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. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - - -#define SERIAL_KS8695_MAJOR 204 -#define SERIAL_KS8695_MINOR 16 -#define SERIAL_KS8695_DEVNAME "ttyAM" - -#define SERIAL_KS8695_NR 1 - -/* - * Access macros for the KS8695 UART - */ -#define UART_GET_CHAR(p) (__raw_readl((p)->membase + KS8695_URRB) & 0xFF) -#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + KS8695_URTH) -#define UART_GET_FCR(p) __raw_readl((p)->membase + KS8695_URFC) -#define UART_PUT_FCR(p, c) __raw_writel((c), (p)->membase + KS8695_URFC) -#define UART_GET_MSR(p) __raw_readl((p)->membase + KS8695_URMS) -#define UART_GET_LSR(p) __raw_readl((p)->membase + KS8695_URLS) -#define UART_GET_LCR(p) __raw_readl((p)->membase + KS8695_URLC) -#define UART_PUT_LCR(p, c) __raw_writel((c), (p)->membase + KS8695_URLC) -#define UART_GET_MCR(p) __raw_readl((p)->membase + KS8695_URMC) -#define UART_PUT_MCR(p, c) __raw_writel((c), (p)->membase + KS8695_URMC) -#define UART_GET_BRDR(p) __raw_readl((p)->membase + KS8695_URBD) -#define UART_PUT_BRDR(p, c) __raw_writel((c), (p)->membase + KS8695_URBD) - -#define KS8695_CLR_TX_INT() __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST) - -#define UART_DUMMY_LSR_RX 0x100 -#define UART_PORT_SIZE (KS8695_USR - KS8695_URRB + 4) - -static inline int tx_enabled(struct uart_port *port) -{ - return port->unused[0] & 1; -} - -static inline int rx_enabled(struct uart_port *port) -{ - return port->unused[0] & 2; -} - -static inline int ms_enabled(struct uart_port *port) -{ - return port->unused[0] & 4; -} - -static inline void ms_enable(struct uart_port *port, int enabled) -{ - if(enabled) - port->unused[0] |= 4; - else - port->unused[0] &= ~4; -} - -static inline void rx_enable(struct uart_port *port, int enabled) -{ - if(enabled) - port->unused[0] |= 2; - else - port->unused[0] &= ~2; -} - -static inline void tx_enable(struct uart_port *port, int enabled) -{ - if(enabled) - port->unused[0] |= 1; - else - port->unused[0] &= ~1; -} - - -#ifdef SUPPORT_SYSRQ -static struct console ks8695_console; -#endif - -static void ks8695uart_stop_tx(struct uart_port *port) -{ - if (tx_enabled(port)) { - /* use disable_irq_nosync() and not disable_irq() to avoid self - * imposed deadlock by not waiting for irq handler to end, - * since this ks8695uart_stop_tx() is called from interrupt context. - */ - disable_irq_nosync(KS8695_IRQ_UART_TX); - tx_enable(port, 0); - } -} - -static void ks8695uart_start_tx(struct uart_port *port) -{ - if (!tx_enabled(port)) { - enable_irq(KS8695_IRQ_UART_TX); - tx_enable(port, 1); - } -} - -static void ks8695uart_stop_rx(struct uart_port *port) -{ - if (rx_enabled(port)) { - disable_irq(KS8695_IRQ_UART_RX); - rx_enable(port, 0); - } -} - -static void ks8695uart_enable_ms(struct uart_port *port) -{ - if (!ms_enabled(port)) { - enable_irq(KS8695_IRQ_UART_MODEM_STATUS); - ms_enable(port,1); - } -} - -static void ks8695uart_disable_ms(struct uart_port *port) -{ - if (ms_enabled(port)) { - disable_irq(KS8695_IRQ_UART_MODEM_STATUS); - ms_enable(port,0); - } -} - -static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct tty_struct *tty = port->state->port.tty; - unsigned int status, ch, lsr, flg, max_count = 256; - - status = UART_GET_LSR(port); /* clears pending LSR interrupts */ - while ((status & URLS_URDR) && max_count--) { - ch = UART_GET_CHAR(port); - flg = TTY_NORMAL; - - port->icount.rx++; - - /* - * Note that the error handling code is - * out of the main execution path - */ - lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX; - if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) { - if (lsr & URLS_URBI) { - lsr &= ~(URLS_URFE | URLS_URPE); - port->icount.brk++; - if (uart_handle_break(port)) - goto ignore_char; - } - if (lsr & URLS_URPE) - port->icount.parity++; - if (lsr & URLS_URFE) - port->icount.frame++; - if (lsr & URLS_URROE) - port->icount.overrun++; - - lsr &= port->read_status_mask; - - if (lsr & URLS_URBI) - flg = TTY_BREAK; - else if (lsr & URLS_URPE) - flg = TTY_PARITY; - else if (lsr & URLS_URFE) - flg = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, URLS_URROE, ch, flg); - -ignore_char: - status = UART_GET_LSR(port); - } - tty_flip_buffer_push(tty); - - return IRQ_HANDLED; -} - - -static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; - unsigned int count; - - if (port->x_char) { - KS8695_CLR_TX_INT(); - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return IRQ_HANDLED; - } - - if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { - ks8695uart_stop_tx(port); - return IRQ_HANDLED; - } - - count = 16; /* fifo size */ - while (!uart_circ_empty(xmit) && (count-- > 0)) { - KS8695_CLR_TX_INT(); - UART_PUT_CHAR(port, 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); - - if (uart_circ_empty(xmit)) - ks8695uart_stop_tx(port); - - return IRQ_HANDLED; -} - -static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned int status; - - /* - * clear modem interrupt by reading MSR - */ - status = UART_GET_MSR(port); - - if (status & URMS_URDDCD) - uart_handle_dcd_change(port, status & URMS_URDDCD); - - if (status & URMS_URDDST) - port->icount.dsr++; - - if (status & URMS_URDCTS) - uart_handle_cts_change(port, status & URMS_URDCTS); - - if (status & URMS_URTERI) - port->icount.rng++; - - wake_up_interruptible(&port->state->port.delta_msr_wait); - - return IRQ_HANDLED; -} - -static unsigned int ks8695uart_tx_empty(struct uart_port *port) -{ - return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0; -} - -static unsigned int ks8695uart_get_mctrl(struct uart_port *port) -{ - unsigned int result = 0; - unsigned int status; - - status = UART_GET_MSR(port); - if (status & URMS_URDCD) - result |= TIOCM_CAR; - if (status & URMS_URDSR) - result |= TIOCM_DSR; - if (status & URMS_URCTS) - result |= TIOCM_CTS; - if (status & URMS_URRI) - result |= TIOCM_RI; - - return result; -} - -static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl) -{ - unsigned int mcr; - - mcr = UART_GET_MCR(port); - if (mctrl & TIOCM_RTS) - mcr |= URMC_URRTS; - else - mcr &= ~URMC_URRTS; - - if (mctrl & TIOCM_DTR) - mcr |= URMC_URDTR; - else - mcr &= ~URMC_URDTR; - - UART_PUT_MCR(port, mcr); -} - -static void ks8695uart_break_ctl(struct uart_port *port, int break_state) -{ - unsigned int lcr; - - lcr = UART_GET_LCR(port); - - if (break_state == -1) - lcr |= URLC_URSBC; - else - lcr &= ~URLC_URSBC; - - UART_PUT_LCR(port, lcr); -} - -static int ks8695uart_startup(struct uart_port *port) -{ - int retval; - - set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN); - tx_enable(port, 0); - rx_enable(port, 1); - ms_enable(port, 1); - - /* - * Allocate the IRQ - */ - retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port); - if (retval) - goto err_tx; - - retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port); - if (retval) - goto err_rx; - - retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port); - if (retval) - goto err_ls; - - retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port); - if (retval) - goto err_ms; - - return 0; - -err_ms: - free_irq(KS8695_IRQ_UART_LINE_STATUS, port); -err_ls: - free_irq(KS8695_IRQ_UART_RX, port); -err_rx: - free_irq(KS8695_IRQ_UART_TX, port); -err_tx: - return retval; -} - -static void ks8695uart_shutdown(struct uart_port *port) -{ - /* - * Free the interrupt - */ - free_irq(KS8695_IRQ_UART_RX, port); - free_irq(KS8695_IRQ_UART_TX, port); - free_irq(KS8695_IRQ_UART_MODEM_STATUS, port); - free_irq(KS8695_IRQ_UART_LINE_STATUS, port); - - /* disable break condition and fifos */ - UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC); - UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE); -} - -static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) -{ - unsigned int lcr, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - switch (termios->c_cflag & CSIZE) { - case CS5: - lcr = URCL_5; - break; - case CS6: - lcr = URCL_6; - break; - case CS7: - lcr = URCL_7; - break; - default: - lcr = URCL_8; - break; - } - - /* stop bits */ - if (termios->c_cflag & CSTOPB) - lcr |= URLC_URSB; - - /* parity */ - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ - if (termios->c_cflag & PARODD) - lcr |= URPE_MARK; - else - lcr |= URPE_SPACE; - } - else if (termios->c_cflag & PARODD) - lcr |= URPE_ODD; - else - lcr |= URPE_EVEN; - } - - if (port->fifosize > 1) - fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE; - - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = URLS_URROE; - if (termios->c_iflag & INPCK) - port->read_status_mask |= (URLS_URFE | URLS_URPE); - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= URLS_URBI; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= (URLS_URFE | URLS_URPE); - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= URLS_URBI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= URLS_URROE; - } - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_LSR_RX; - - /* first, disable everything */ - if (UART_ENABLE_MS(port, termios->c_cflag)) - ks8695uart_enable_ms(port); - else - ks8695uart_disable_ms(port); - - /* Set baud rate */ - UART_PUT_BRDR(port, quot); - - UART_PUT_LCR(port, lcr); - UART_PUT_FCR(port, fcr); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *ks8695uart_type(struct uart_port *port) -{ - return port->type == PORT_KS8695 ? "KS8695" : NULL; -} - -/* - * Release the memory region(s) being used by 'port' - */ -static void ks8695uart_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int ks8695uart_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, UART_PORT_SIZE, - "serial_ks8695") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void ks8695uart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_KS8695; - ks8695uart_request_port(port); - } -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695) - ret = -EINVAL; - if (ser->irq != port->irq) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops ks8695uart_pops = { - .tx_empty = ks8695uart_tx_empty, - .set_mctrl = ks8695uart_set_mctrl, - .get_mctrl = ks8695uart_get_mctrl, - .stop_tx = ks8695uart_stop_tx, - .start_tx = ks8695uart_start_tx, - .stop_rx = ks8695uart_stop_rx, - .enable_ms = ks8695uart_enable_ms, - .break_ctl = ks8695uart_break_ctl, - .startup = ks8695uart_startup, - .shutdown = ks8695uart_shutdown, - .set_termios = ks8695uart_set_termios, - .type = ks8695uart_type, - .release_port = ks8695uart_release_port, - .request_port = ks8695uart_request_port, - .config_port = ks8695uart_config_port, - .verify_port = ks8695uart_verify_port, -}; - -static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = { - { - .membase = (void *) KS8695_UART_VA, - .mapbase = KS8695_UART_VA, - .iotype = SERIAL_IO_MEM, - .irq = KS8695_IRQ_UART_TX, - .uartclk = KS8695_CLOCK_RATE * 16, - .fifosize = 16, - .ops = &ks8695uart_pops, - .flags = ASYNC_BOOT_AUTOCONF, - .line = 0, - } -}; - -#ifdef CONFIG_SERIAL_KS8695_CONSOLE -static void ks8695_console_putchar(struct uart_port *port, int ch) -{ - while (!(UART_GET_LSR(port) & URLS_URTHRE)) - barrier(); - - UART_PUT_CHAR(port, ch); -} - -static void ks8695_console_write(struct console *co, const char *s, u_int count) -{ - struct uart_port *port = ks8695uart_ports + co->index; - - uart_console_write(port, s, count, ks8695_console_putchar); -} - -static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -{ - unsigned int lcr; - - lcr = UART_GET_LCR(port); - - switch (lcr & URLC_PARITY) { - case URPE_ODD: - *parity = 'o'; - break; - case URPE_EVEN: - *parity = 'e'; - break; - default: - *parity = 'n'; - } - - switch (lcr & URLC_URCL) { - case URCL_5: - *bits = 5; - break; - case URCL_6: - *bits = 6; - break; - case URCL_7: - *bits = 7; - break; - default: - *bits = 8; - } - - *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF); - *baud /= 16; - *baud &= 0xFFFFFFF0; -} - -static int __init ks8695_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - ks8695_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver ks8695_reg; - -static struct console ks8695_console = { - .name = SERIAL_KS8695_DEVNAME, - .write = ks8695_console_write, - .device = uart_console_device, - .setup = ks8695_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &ks8695_reg, -}; - -static int __init ks8695_console_init(void) -{ - add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL); - register_console(&ks8695_console); - return 0; -} - -console_initcall(ks8695_console_init); - -#define KS8695_CONSOLE &ks8695_console -#else -#define KS8695_CONSOLE NULL -#endif - -static struct uart_driver ks8695_reg = { - .owner = THIS_MODULE, - .driver_name = "serial_ks8695", - .dev_name = SERIAL_KS8695_DEVNAME, - .major = SERIAL_KS8695_MAJOR, - .minor = SERIAL_KS8695_MINOR, - .nr = SERIAL_KS8695_NR, - .cons = KS8695_CONSOLE, -}; - -static int __init ks8695uart_init(void) -{ - int i, ret; - - printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n"); - - ret = uart_register_driver(&ks8695_reg); - if (ret) - return ret; - - for (i = 0; i < SERIAL_KS8695_NR; i++) - uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]); - - return 0; -} - -static void __exit ks8695uart_exit(void) -{ - int i; - - for (i = 0; i < SERIAL_KS8695_NR; i++) - uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]); - uart_unregister_driver(&ks8695_reg); -} - -module_init(ks8695uart_init); -module_exit(ks8695uart_exit); - -MODULE_DESCRIPTION("KS8695 serial port driver"); -MODULE_AUTHOR("Micrel Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c deleted file mode 100644 index ea744707c4d6..000000000000 --- a/drivers/serial/serial_lh7a40x.c +++ /dev/null @@ -1,682 +0,0 @@ -/* drivers/serial/serial_lh7a40x.c - * - * Copyright (C) 2004 Coastal Environmental Systems - * - * 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. - * - */ - -/* Driver for Sharp LH7A40X embedded serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. - * - * --- - * - * This driver supports the embedded UARTs of the Sharp LH7A40X series - * CPUs. While similar to the 16550 and other UART chips, there is - * nothing close to register compatibility. Moreover, some of the - * modem control lines are not available, either in the chip or they - * are lacking in the board-level implementation. - * - * - Use of SIRDIS - * For simplicity, we disable the IR functions of any UART whenever - * we enable it. - * - */ - - -#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DEV_MAJOR 204 -#define DEV_MINOR 16 -#define DEV_NR 3 - -#define ISR_LOOP_LIMIT 256 - -#define UR(p,o) _UR ((p)->membase, o) -#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) -#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m) -#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m) - -#define UART_REG_SIZE 32 - -#define UART_R_DATA (0x00) -#define UART_R_FCON (0x04) -#define UART_R_BRCON (0x08) -#define UART_R_CON (0x0c) -#define UART_R_STATUS (0x10) -#define UART_R_RAWISR (0x14) -#define UART_R_INTEN (0x18) -#define UART_R_ISR (0x1c) - -#define UARTEN (0x01) /* UART enable */ -#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */ - -#define RxEmpty (0x10) -#define TxEmpty (0x80) -#define TxFull (0x20) -#define nRxRdy RxEmpty -#define nTxRdy TxFull -#define TxBusy (0x08) - -#define RxBreak (0x0800) -#define RxOverrunError (0x0400) -#define RxParityError (0x0200) -#define RxFramingError (0x0100) -#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError) - -#define DCD (0x04) -#define DSR (0x02) -#define CTS (0x01) - -#define RxInt (0x01) -#define TxInt (0x02) -#define ModemInt (0x04) -#define RxTimeoutInt (0x08) - -#define MSEOI (0x10) - -#define WLEN_8 (0x60) -#define WLEN_7 (0x40) -#define WLEN_6 (0x20) -#define WLEN_5 (0x00) -#define WLEN (0x60) /* Mask for all word-length bits */ -#define STP2 (0x08) -#define PEN (0x02) /* Parity Enable */ -#define EPS (0x04) /* Even Parity Set */ -#define FEN (0x10) /* FIFO Enable */ -#define BRK (0x01) /* Send Break */ - - -struct uart_port_lh7a40x { - struct uart_port port; - unsigned int statusPrev; /* Most recently read modem status */ -}; - -static void lh7a40xuart_stop_tx (struct uart_port* port) -{ - BIT_CLR (port, UART_R_INTEN, TxInt); -} - -static void lh7a40xuart_start_tx (struct uart_port* port) -{ - BIT_SET (port, UART_R_INTEN, TxInt); - - /* *** FIXME: do I need to check for startup of the - transmitter? The old driver did, but AMBA - doesn't . */ -} - -static void lh7a40xuart_stop_rx (struct uart_port* port) -{ - BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); -} - -static void lh7a40xuart_enable_ms (struct uart_port* port) -{ - BIT_SET (port, UART_R_INTEN, ModemInt); -} - -static void lh7a40xuart_rx_chars (struct uart_port* port) -{ - struct tty_struct* tty = port->state->port.tty; - int cbRxMax = 256; /* (Gross) limit on receive */ - unsigned int data; /* Received data and status */ - unsigned int flag; - - while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { - data = UR (port, UART_R_DATA); - flag = TTY_NORMAL; - ++port->icount.rx; - - if (unlikely(data & RxError)) { - if (data & RxBreak) { - data &= ~(RxFramingError | RxParityError); - ++port->icount.brk; - if (uart_handle_break (port)) - continue; - } - else if (data & RxParityError) - ++port->icount.parity; - else if (data & RxFramingError) - ++port->icount.frame; - if (data & RxOverrunError) - ++port->icount.overrun; - - /* Mask by termios, leave Rx'd byte */ - data &= port->read_status_mask | 0xff; - - if (data & RxBreak) - flag = TTY_BREAK; - else if (data & RxParityError) - flag = TTY_PARITY; - else if (data & RxFramingError) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char (port, (unsigned char) data)) - continue; - - uart_insert_char(port, data, RxOverrunError, data, flag); - } - tty_flip_buffer_push (tty); - return; -} - -static void lh7a40xuart_tx_chars (struct uart_port* port) -{ - struct circ_buf* xmit = &port->state->xmit; - int cbTxMax = port->fifosize; - - if (port->x_char) { - UR (port, UART_R_DATA) = port->x_char; - ++port->icount.tx; - port->x_char = 0; - return; - } - if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { - lh7a40xuart_stop_tx (port); - return; - } - - /* Unlike the AMBA UART, the lh7a40x UART does not guarantee - that at least half of the FIFO is empty. Instead, we check - status for every character. Using the AMBA method causes - the transmitter to drop characters. */ - - do { - UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - ++port->icount.tx; - if (uart_circ_empty(xmit)) - break; - } while (!(UR (port, UART_R_STATUS) & nTxRdy) - && cbTxMax--); - - if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) - uart_write_wakeup (port); - - if (uart_circ_empty (xmit)) - lh7a40xuart_stop_tx (port); -} - -static void lh7a40xuart_modem_status (struct uart_port* port) -{ - unsigned int status = UR (port, UART_R_STATUS); - unsigned int delta - = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; - - BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ - - if (!delta) /* Only happens if we missed 2 transitions */ - return; - - ((struct uart_port_lh7a40x*) port)->statusPrev = status; - - if (delta & DCD) - uart_handle_dcd_change (port, status & DCD); - - if (delta & DSR) - ++port->icount.dsr; - - if (delta & CTS) - uart_handle_cts_change (port, status & CTS); - - wake_up_interruptible (&port->state->port.delta_msr_wait); -} - -static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) -{ - struct uart_port* port = dev_id; - unsigned int cLoopLimit = ISR_LOOP_LIMIT; - unsigned int isr = UR (port, UART_R_ISR); - - - do { - if (isr & (RxInt | RxTimeoutInt)) - lh7a40xuart_rx_chars(port); - if (isr & ModemInt) - lh7a40xuart_modem_status (port); - if (isr & TxInt) - lh7a40xuart_tx_chars (port); - - if (--cLoopLimit == 0) - break; - - isr = UR (port, UART_R_ISR); - } while (isr & (RxInt | TxInt | RxTimeoutInt)); - - return IRQ_HANDLED; -} - -static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) -{ - return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; -} - -static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) -{ - unsigned int result = 0; - unsigned int status = UR (port, UART_R_STATUS); - - if (status & DCD) - result |= TIOCM_CAR; - if (status & DSR) - result |= TIOCM_DSR; - if (status & CTS) - result |= TIOCM_CTS; - - return result; -} - -static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) -{ - /* None of the ports supports DTR. UART1 supports RTS through GPIO. */ - /* Note, kernel appears to be setting DTR and RTS on console. */ - - /* *** FIXME: this deserves more work. There's some work in - tracing all of the IO pins. */ -#if 0 - if( port->mapbase == UART1_PHYS) { - gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); - - if (mctrl & TIOCM_RTS) - gpio->pbdr &= ~GPIOB_UART1_RTS; - else - gpio->pbdr |= GPIOB_UART1_RTS; - } -#endif -} - -static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ - else - BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ - spin_unlock_irqrestore(&port->lock, flags); -} - -static int lh7a40xuart_startup (struct uart_port* port) -{ - int retval; - - retval = request_irq (port->irq, lh7a40xuart_int, 0, - "serial_lh7a40x", port); - if (retval) - return retval; - - /* Initial modem control-line settings */ - ((struct uart_port_lh7a40x*) port)->statusPrev - = UR (port, UART_R_STATUS); - - /* There is presently no configuration option to enable IR. - Thus, we always disable it. */ - - BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); - BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); - - return 0; -} - -static void lh7a40xuart_shutdown (struct uart_port* port) -{ - free_irq (port->irq, port); - BIT_CLR (port, UART_R_FCON, BRK | FEN); - BIT_CLR (port, UART_R_CON, UARTEN); -} - -static void lh7a40xuart_set_termios (struct uart_port* port, - struct ktermios* termios, - struct ktermios* old) -{ - unsigned int con; - unsigned int inten; - unsigned int fcon; - unsigned long flags; - unsigned int baud; - unsigned int quot; - - baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); - quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ - - switch (termios->c_cflag & CSIZE) { - case CS5: - fcon = WLEN_5; - break; - case CS6: - fcon = WLEN_6; - break; - case CS7: - fcon = WLEN_7; - break; - case CS8: - default: - fcon = WLEN_8; - break; - } - if (termios->c_cflag & CSTOPB) - fcon |= STP2; - if (termios->c_cflag & PARENB) { - fcon |= PEN; - if (!(termios->c_cflag & PARODD)) - fcon |= EPS; - } - if (port->fifosize > 1) - fcon |= FEN; - - spin_lock_irqsave (&port->lock, flags); - - uart_update_timeout (port, termios->c_cflag, baud); - - port->read_status_mask = RxOverrunError; - if (termios->c_iflag & INPCK) - port->read_status_mask |= RxFramingError | RxParityError; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= RxBreak; - - /* Figure mask for status we ignore */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= RxFramingError | RxParityError; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= RxBreak; - /* Ignore overrun when ignorning parity */ - /* *** FIXME: is this in the right place? */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= RxOverrunError; - } - - /* Ignore all receive errors when receive disabled */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= RxError; - - con = UR (port, UART_R_CON); - inten = (UR (port, UART_R_INTEN) & ~ModemInt); - - if (UART_ENABLE_MS (port, termios->c_cflag)) - inten |= ModemInt; - - BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */ - UR (port, UART_R_INTEN) = 0; /* Disable interrupts */ - UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */ - UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */ - UR (port, UART_R_INTEN) = inten; /* Enable interrupts */ - UR (port, UART_R_CON) = con; /* Restore UART mode */ - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char* lh7a40xuart_type (struct uart_port* port) -{ - return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; -} - -static void lh7a40xuart_release_port (struct uart_port* port) -{ - release_mem_region (port->mapbase, UART_REG_SIZE); -} - -static int lh7a40xuart_request_port (struct uart_port* port) -{ - return request_mem_region (port->mapbase, UART_REG_SIZE, - "serial_lh7a40x") != NULL - ? 0 : -EBUSY; -} - -static void lh7a40xuart_config_port (struct uart_port* port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_LH7A40X; - lh7a40xuart_request_port (port); - } -} - -static int lh7a40xuart_verify_port (struct uart_port* port, - struct serial_struct* ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) - ret = -EINVAL; - if (ser->baud_base < 9600) /* *** FIXME: is this true? */ - ret = -EINVAL; - return ret; -} - -static struct uart_ops lh7a40x_uart_ops = { - .tx_empty = lh7a40xuart_tx_empty, - .set_mctrl = lh7a40xuart_set_mctrl, - .get_mctrl = lh7a40xuart_get_mctrl, - .stop_tx = lh7a40xuart_stop_tx, - .start_tx = lh7a40xuart_start_tx, - .stop_rx = lh7a40xuart_stop_rx, - .enable_ms = lh7a40xuart_enable_ms, - .break_ctl = lh7a40xuart_break_ctl, - .startup = lh7a40xuart_startup, - .shutdown = lh7a40xuart_shutdown, - .set_termios = lh7a40xuart_set_termios, - .type = lh7a40xuart_type, - .release_port = lh7a40xuart_release_port, - .request_port = lh7a40xuart_request_port, - .config_port = lh7a40xuart_config_port, - .verify_port = lh7a40xuart_verify_port, -}; - -static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { - { - .port = { - .membase = (void*) io_p2v (UART1_PHYS), - .mapbase = UART1_PHYS, - .iotype = UPIO_MEM, - .irq = IRQ_UART1INTR, - .uartclk = 14745600/2, - .fifosize = 16, - .ops = &lh7a40x_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - { - .port = { - .membase = (void*) io_p2v (UART2_PHYS), - .mapbase = UART2_PHYS, - .iotype = UPIO_MEM, - .irq = IRQ_UART2INTR, - .uartclk = 14745600/2, - .fifosize = 16, - .ops = &lh7a40x_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - { - .port = { - .membase = (void*) io_p2v (UART3_PHYS), - .mapbase = UART3_PHYS, - .iotype = UPIO_MEM, - .irq = IRQ_UART3INTR, - .uartclk = 14745600/2, - .fifosize = 16, - .ops = &lh7a40x_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, -}; - -#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE -# define LH7A40X_CONSOLE NULL -#else -# define LH7A40X_CONSOLE &lh7a40x_console - -static void lh7a40xuart_console_putchar(struct uart_port *port, int ch) -{ - while (UR(port, UART_R_STATUS) & nTxRdy) - ; - UR(port, UART_R_DATA) = ch; -} - -static void lh7a40xuart_console_write (struct console* co, - const char* s, - unsigned int count) -{ - struct uart_port* port = &lh7a40x_ports[co->index].port; - unsigned int con = UR (port, UART_R_CON); - unsigned int inten = UR (port, UART_R_INTEN); - - - UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */ - BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ - - uart_console_write(port, s, count, lh7a40xuart_console_putchar); - - /* Wait until all characters are sent */ - while (UR (port, UART_R_STATUS) & TxBusy) - ; - - /* Restore control and interrupt mask */ - UR (port, UART_R_CON) = con; - UR (port, UART_R_INTEN) = inten; -} - -static void __init lh7a40xuart_console_get_options (struct uart_port* port, - int* baud, - int* parity, - int* bits) -{ - if (UR (port, UART_R_CON) & UARTEN) { - unsigned int fcon = UR (port, UART_R_FCON); - unsigned int quot = UR (port, UART_R_BRCON) + 1; - - switch (fcon & (PEN | EPS)) { - default: *parity = 'n'; break; - case PEN: *parity = 'o'; break; - case PEN | EPS: *parity = 'e'; break; - } - - switch (fcon & WLEN) { - default: - case WLEN_8: *bits = 8; break; - case WLEN_7: *bits = 7; break; - case WLEN_6: *bits = 6; break; - case WLEN_5: *bits = 5; break; - } - - *baud = port->uartclk/(16*quot); - } -} - -static int __init lh7a40xuart_console_setup (struct console* co, char* options) -{ - struct uart_port* port; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index >= DEV_NR) /* Bounds check on device number */ - co->index = 0; - port = &lh7a40x_ports[co->index].port; - - if (options) - uart_parse_options (options, &baud, &parity, &bits, &flow); - else - lh7a40xuart_console_get_options (port, &baud, &parity, &bits); - - return uart_set_options (port, co, baud, parity, bits, flow); -} - -static struct uart_driver lh7a40x_reg; -static struct console lh7a40x_console = { - .name = "ttyAM", - .write = lh7a40xuart_console_write, - .device = uart_console_device, - .setup = lh7a40xuart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &lh7a40x_reg, -}; - -static int __init lh7a40xuart_console_init(void) -{ - register_console (&lh7a40x_console); - return 0; -} - -console_initcall (lh7a40xuart_console_init); - -#endif - -static struct uart_driver lh7a40x_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyAM", - .dev_name = "ttyAM", - .major = DEV_MAJOR, - .minor = DEV_MINOR, - .nr = DEV_NR, - .cons = LH7A40X_CONSOLE, -}; - -static int __init lh7a40xuart_init(void) -{ - int ret; - - printk (KERN_INFO "serial: LH7A40X serial driver\n"); - - ret = uart_register_driver (&lh7a40x_reg); - - if (ret == 0) { - int i; - - for (i = 0; i < DEV_NR; i++) { - /* UART3, when used, requires GPIO pin reallocation */ - if (lh7a40x_ports[i].port.mapbase == UART3_PHYS) - GPIO_PINMUX |= 1<<3; - uart_add_one_port (&lh7a40x_reg, - &lh7a40x_ports[i].port); - } - } - return ret; -} - -static void __exit lh7a40xuart_exit(void) -{ - int i; - - for (i = 0; i < DEV_NR; i++) - uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); - - uart_unregister_driver (&lh7a40x_reg); -} - -module_init (lh7a40xuart_init); -module_exit (lh7a40xuart_exit); - -MODULE_AUTHOR ("Marc Singer"); -MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); -MODULE_LICENSE ("GPL"); diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c deleted file mode 100644 index c50e9fbbf743..000000000000 --- a/drivers/serial/serial_txx9.c +++ /dev/null @@ -1,1344 +0,0 @@ -/* - * drivers/serial/serial_txx9.c - * - * Derived from many drivers using generic_serial interface, - * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c - * (was in Linux/VR tree) by Jim Pick. - * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick - * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) - * Copyright (C) 2000-2002 Toshiba Corporation - * - * 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. - * - * Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller - */ - -#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static char *serial_version = "1.11"; -static char *serial_name = "TX39/49 Serial driver"; - -#define PASS_LIMIT 256 - -#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) -/* "ttyS" is used for standard serial driver */ -#define TXX9_TTY_NAME "ttyTX" -#define TXX9_TTY_MINOR_START 196 -#define TXX9_TTY_MAJOR 204 -#else -/* acts like standard serial driver */ -#define TXX9_TTY_NAME "ttyS" -#define TXX9_TTY_MINOR_START 64 -#define TXX9_TTY_MAJOR TTY_MAJOR -#endif - -/* flag aliases */ -#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART -#define UPF_TXX9_USE_SCLK UPF_MAGIC_MULTIPLIER - -#ifdef CONFIG_PCI -/* support for Toshiba TC86C001 SIO */ -#define ENABLE_SERIAL_TXX9_PCI -#endif - -/* - * Number of serial ports - */ -#define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS - -struct uart_txx9_port { - struct uart_port port; - /* No additional info for now */ -}; - -#define TXX9_REGION_SIZE 0x24 - -/* TXX9 Serial Registers */ -#define TXX9_SILCR 0x00 -#define TXX9_SIDICR 0x04 -#define TXX9_SIDISR 0x08 -#define TXX9_SICISR 0x0c -#define TXX9_SIFCR 0x10 -#define TXX9_SIFLCR 0x14 -#define TXX9_SIBGR 0x18 -#define TXX9_SITFIFO 0x1c -#define TXX9_SIRFIFO 0x20 - -/* SILCR : Line Control */ -#define TXX9_SILCR_SCS_MASK 0x00000060 -#define TXX9_SILCR_SCS_IMCLK 0x00000000 -#define TXX9_SILCR_SCS_IMCLK_BG 0x00000020 -#define TXX9_SILCR_SCS_SCLK 0x00000040 -#define TXX9_SILCR_SCS_SCLK_BG 0x00000060 -#define TXX9_SILCR_UEPS 0x00000010 -#define TXX9_SILCR_UPEN 0x00000008 -#define TXX9_SILCR_USBL_MASK 0x00000004 -#define TXX9_SILCR_USBL_1BIT 0x00000000 -#define TXX9_SILCR_USBL_2BIT 0x00000004 -#define TXX9_SILCR_UMODE_MASK 0x00000003 -#define TXX9_SILCR_UMODE_8BIT 0x00000000 -#define TXX9_SILCR_UMODE_7BIT 0x00000001 - -/* SIDICR : DMA/Int. Control */ -#define TXX9_SIDICR_TDE 0x00008000 -#define TXX9_SIDICR_RDE 0x00004000 -#define TXX9_SIDICR_TIE 0x00002000 -#define TXX9_SIDICR_RIE 0x00001000 -#define TXX9_SIDICR_SPIE 0x00000800 -#define TXX9_SIDICR_CTSAC 0x00000600 -#define TXX9_SIDICR_STIE_MASK 0x0000003f -#define TXX9_SIDICR_STIE_OERS 0x00000020 -#define TXX9_SIDICR_STIE_CTSS 0x00000010 -#define TXX9_SIDICR_STIE_RBRKD 0x00000008 -#define TXX9_SIDICR_STIE_TRDY 0x00000004 -#define TXX9_SIDICR_STIE_TXALS 0x00000002 -#define TXX9_SIDICR_STIE_UBRKD 0x00000001 - -/* SIDISR : DMA/Int. Status */ -#define TXX9_SIDISR_UBRK 0x00008000 -#define TXX9_SIDISR_UVALID 0x00004000 -#define TXX9_SIDISR_UFER 0x00002000 -#define TXX9_SIDISR_UPER 0x00001000 -#define TXX9_SIDISR_UOER 0x00000800 -#define TXX9_SIDISR_ERI 0x00000400 -#define TXX9_SIDISR_TOUT 0x00000200 -#define TXX9_SIDISR_TDIS 0x00000100 -#define TXX9_SIDISR_RDIS 0x00000080 -#define TXX9_SIDISR_STIS 0x00000040 -#define TXX9_SIDISR_RFDN_MASK 0x0000001f - -/* SICISR : Change Int. Status */ -#define TXX9_SICISR_OERS 0x00000020 -#define TXX9_SICISR_CTSS 0x00000010 -#define TXX9_SICISR_RBRKD 0x00000008 -#define TXX9_SICISR_TRDY 0x00000004 -#define TXX9_SICISR_TXALS 0x00000002 -#define TXX9_SICISR_UBRKD 0x00000001 - -/* SIFCR : FIFO Control */ -#define TXX9_SIFCR_SWRST 0x00008000 -#define TXX9_SIFCR_RDIL_MASK 0x00000180 -#define TXX9_SIFCR_RDIL_1 0x00000000 -#define TXX9_SIFCR_RDIL_4 0x00000080 -#define TXX9_SIFCR_RDIL_8 0x00000100 -#define TXX9_SIFCR_RDIL_12 0x00000180 -#define TXX9_SIFCR_RDIL_MAX 0x00000180 -#define TXX9_SIFCR_TDIL_MASK 0x00000018 -#define TXX9_SIFCR_TDIL_MASK 0x00000018 -#define TXX9_SIFCR_TDIL_1 0x00000000 -#define TXX9_SIFCR_TDIL_4 0x00000001 -#define TXX9_SIFCR_TDIL_8 0x00000010 -#define TXX9_SIFCR_TDIL_MAX 0x00000010 -#define TXX9_SIFCR_TFRST 0x00000004 -#define TXX9_SIFCR_RFRST 0x00000002 -#define TXX9_SIFCR_FRSTE 0x00000001 -#define TXX9_SIO_TX_FIFO 8 -#define TXX9_SIO_RX_FIFO 16 - -/* SIFLCR : Flow Control */ -#define TXX9_SIFLCR_RCS 0x00001000 -#define TXX9_SIFLCR_TES 0x00000800 -#define TXX9_SIFLCR_RTSSC 0x00000200 -#define TXX9_SIFLCR_RSDE 0x00000100 -#define TXX9_SIFLCR_TSDE 0x00000080 -#define TXX9_SIFLCR_RTSTL_MASK 0x0000001e -#define TXX9_SIFLCR_RTSTL_MAX 0x0000001e -#define TXX9_SIFLCR_TBRK 0x00000001 - -/* SIBGR : Baudrate Control */ -#define TXX9_SIBGR_BCLK_MASK 0x00000300 -#define TXX9_SIBGR_BCLK_T0 0x00000000 -#define TXX9_SIBGR_BCLK_T2 0x00000100 -#define TXX9_SIBGR_BCLK_T4 0x00000200 -#define TXX9_SIBGR_BCLK_T6 0x00000300 -#define TXX9_SIBGR_BRD_MASK 0x000000ff - -static inline unsigned int sio_in(struct uart_txx9_port *up, int offset) -{ - switch (up->port.iotype) { - default: - return __raw_readl(up->port.membase + offset); - case UPIO_PORT: - return inl(up->port.iobase + offset); - } -} - -static inline void -sio_out(struct uart_txx9_port *up, int offset, int value) -{ - switch (up->port.iotype) { - default: - __raw_writel(value, up->port.membase + offset); - break; - case UPIO_PORT: - outl(value, up->port.iobase + offset); - break; - } -} - -static inline void -sio_mask(struct uart_txx9_port *up, int offset, unsigned int value) -{ - sio_out(up, offset, sio_in(up, offset) & ~value); -} -static inline void -sio_set(struct uart_txx9_port *up, int offset, unsigned int value) -{ - sio_out(up, offset, sio_in(up, offset) | value); -} - -static inline void -sio_quot_set(struct uart_txx9_port *up, int quot) -{ - quot >>= 1; - if (quot < 256) - sio_out(up, TXX9_SIBGR, quot | TXX9_SIBGR_BCLK_T0); - else if (quot < (256 << 2)) - sio_out(up, TXX9_SIBGR, (quot >> 2) | TXX9_SIBGR_BCLK_T2); - else if (quot < (256 << 4)) - sio_out(up, TXX9_SIBGR, (quot >> 4) | TXX9_SIBGR_BCLK_T4); - else if (quot < (256 << 6)) - sio_out(up, TXX9_SIBGR, (quot >> 6) | TXX9_SIBGR_BCLK_T6); - else - sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6); -} - -static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port) -{ - return container_of(port, struct uart_txx9_port, port); -} - -static void serial_txx9_stop_tx(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); -} - -static void serial_txx9_start_tx(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); -} - -static void serial_txx9_stop_rx(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; -} - -static void serial_txx9_enable_ms(struct uart_port *port) -{ - /* TXX9-SIO can not control DTR... */ -} - -static void serial_txx9_initialize(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned int tmout = 10000; - - sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); - /* TX4925 BUG WORKAROUND. Accessing SIOC register - * immediately after soft reset causes bus error. */ - mmiowb(); - udelay(1); - while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout) - udelay(1); - /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ - sio_set(up, TXX9_SIFCR, - TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1); - /* initial settings */ - sio_out(up, TXX9_SILCR, - TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | - ((up->port.flags & UPF_TXX9_USE_SCLK) ? - TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); - sio_quot_set(up, uart_get_divisor(port, 9600)); - sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); - sio_out(up, TXX9_SIDICR, 0); -} - -static inline void -receive_chars(struct uart_txx9_port *up, unsigned int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned char ch; - unsigned int disr = *status; - int max_count = 256; - char flag; - unsigned int next_ignore_status_mask; - - do { - ch = sio_in(up, TXX9_SIRFIFO); - flag = TTY_NORMAL; - up->port.icount.rx++; - - /* mask out RFDN_MASK bit added by previous overrun */ - next_ignore_status_mask = - up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK; - if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER | - TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { - /* - * For statistics only - */ - if (disr & TXX9_SIDISR_UBRK) { - disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER); - 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 (disr & TXX9_SIDISR_UPER) - up->port.icount.parity++; - else if (disr & TXX9_SIDISR_UFER) - up->port.icount.frame++; - if (disr & TXX9_SIDISR_UOER) { - up->port.icount.overrun++; - /* - * The receiver read buffer still hold - * a char which caused overrun. - * Ignore next char by adding RFDN_MASK - * to ignore_status_mask temporarily. - */ - next_ignore_status_mask |= - TXX9_SIDISR_RFDN_MASK; - } - - /* - * Mask off conditions which should be ingored. - */ - disr &= up->port.read_status_mask; - - if (disr & TXX9_SIDISR_UBRK) { - flag = TTY_BREAK; - } else if (disr & TXX9_SIDISR_UPER) - flag = TTY_PARITY; - else if (disr & TXX9_SIDISR_UFER) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - - uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); - - ignore_char: - up->port.ignore_status_mask = next_ignore_status_mask; - disr = sio_in(up, TXX9_SIDISR); - } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); - spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); - *status = disr; -} - -static inline void transmit_chars(struct uart_txx9_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - sio_out(up, TXX9_SITFIFO, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_txx9_stop_tx(&up->port); - return; - } - - count = TXX9_SIO_TX_FIFO; - do { - sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_txx9_stop_tx(&up->port); -} - -static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) -{ - int pass_counter = 0; - struct uart_txx9_port *up = dev_id; - unsigned int status; - - while (1) { - spin_lock(&up->port.lock); - status = sio_in(up, TXX9_SIDISR); - if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE)) - status &= ~TXX9_SIDISR_TDIS; - if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | - TXX9_SIDISR_TOUT))) { - spin_unlock(&up->port.lock); - break; - } - - if (status & TXX9_SIDISR_RDIS) - receive_chars(up, &status); - if (status & TXX9_SIDISR_TDIS) - transmit_chars(up); - /* Clear TX/RX Int. Status */ - sio_mask(up, TXX9_SIDISR, - TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | - TXX9_SIDISR_TOUT); - spin_unlock(&up->port.lock); - - if (pass_counter++ > PASS_LIMIT) - break; - } - - return pass_counter ? IRQ_HANDLED : IRQ_NONE; -} - -static unsigned int serial_txx9_tx_empty(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&up->port.lock, flags); - ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); - - return ret; -} - -static unsigned int serial_txx9_get_mctrl(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned int ret; - - /* no modem control lines */ - ret = TIOCM_CAR | TIOCM_DSR; - ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS; - ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS; - - return ret; -} - -static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - - if (mctrl & TIOCM_RTS) - sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); - else - sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); -} - -static void serial_txx9_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); - else - sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL) -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_txx9_port *up) -{ - unsigned int tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - while (--tmout && - !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS)) - udelay(1); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) - udelay(1); - } -} -#endif - -#ifdef CONFIG_CONSOLE_POLL -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int serial_txx9_get_poll_char(struct uart_port *port) -{ - unsigned int ier; - unsigned char c; - struct uart_txx9_port *up = to_uart_txx9_port(port); - - /* - * First save the IER then disable the interrupts - */ - ier = sio_in(up, TXX9_SIDICR); - sio_out(up, TXX9_SIDICR, 0); - - while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID) - ; - - c = sio_in(up, TXX9_SIRFIFO); - - /* - * Finally, clear RX interrupt status - * and restore the IER - */ - sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS); - sio_out(up, TXX9_SIDICR, ier); - return c; -} - - -static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) -{ - unsigned int ier; - struct uart_txx9_port *up = to_uart_txx9_port(port); - - /* - * First save the IER then disable the interrupts - */ - ier = sio_in(up, TXX9_SIDICR); - sio_out(up, TXX9_SIDICR, 0); - - wait_for_xmitr(up); - /* - * Send the character out. - * If a LF, also do CR... - */ - sio_out(up, TXX9_SITFIFO, c); - if (c == 10) { - wait_for_xmitr(up); - sio_out(up, TXX9_SITFIFO, 13); - } - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - sio_out(up, TXX9_SIDICR, ier); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -static int serial_txx9_startup(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned long flags; - int retval; - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - sio_set(up, TXX9_SIFCR, - TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); - /* clear reset */ - sio_mask(up, TXX9_SIFCR, - TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); - sio_out(up, TXX9_SIDICR, 0); - - /* - * Clear the interrupt registers. - */ - sio_out(up, TXX9_SIDISR, 0); - - retval = request_irq(up->port.irq, serial_txx9_interrupt, - IRQF_SHARED, "serial_txx9", up); - if (retval) - return retval; - - /* - * Now, initialize the UART - */ - spin_lock_irqsave(&up->port.lock, flags); - serial_txx9_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Enable RX/TX */ - sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); - - /* - * Finally, enable interrupts. - */ - sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE); - - return 0; -} - -static void serial_txx9_shutdown(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned long flags; - - /* - * Disable interrupts from this port - */ - sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */ - - spin_lock_irqsave(&up->port.lock, flags); - serial_txx9_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Disable break condition - */ - sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); - -#ifdef CONFIG_SERIAL_TXX9_CONSOLE - if (up->port.cons && up->port.line == up->port.cons->index) { - free_irq(up->port.irq, up); - return; - } -#endif - /* reset FIFOs */ - sio_set(up, TXX9_SIFCR, - TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); - /* clear reset */ - sio_mask(up, TXX9_SIFCR, - TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); - - /* Disable RX/TX */ - sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); - - free_irq(up->port.irq, up); -} - -static void -serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - unsigned int cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - - /* - * We don't support modem control lines. - */ - termios->c_cflag &= ~(HUPCL | CMSPAR); - termios->c_cflag |= CLOCAL; - - cval = sio_in(up, TXX9_SILCR); - /* byte size and parity */ - cval &= ~TXX9_SILCR_UMODE_MASK; - switch (termios->c_cflag & CSIZE) { - case CS7: - cval |= TXX9_SILCR_UMODE_7BIT; - break; - default: - case CS5: /* not supported */ - case CS6: /* not supported */ - case CS8: - cval |= TXX9_SILCR_UMODE_8BIT; - break; - } - - cval &= ~TXX9_SILCR_USBL_MASK; - if (termios->c_cflag & CSTOPB) - cval |= TXX9_SILCR_USBL_2BIT; - else - cval |= TXX9_SILCR_USBL_1BIT; - cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS); - if (termios->c_cflag & PARENB) - cval |= TXX9_SILCR_UPEN; - if (!(termios->c_cflag & PARODD)) - cval |= TXX9_SILCR_UEPS; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2); - quot = uart_get_divisor(port, baud); - - /* Set up FIFOs */ - /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ - fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1; - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = TXX9_SIDISR_UOER | - TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; - if (termios->c_iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= TXX9_SIDISR_UBRK; - - /* - * Characteres to ignore - */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= TXX9_SIDISR_UBRK; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= TXX9_SIDISR_UOER; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= TXX9_SIDISR_RDIS; - - /* CTS flow control flag */ - if ((termios->c_cflag & CRTSCTS) && - (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) { - sio_set(up, TXX9_SIFLCR, - TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); - } else { - sio_mask(up, TXX9_SIFLCR, - TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); - } - - sio_out(up, TXX9_SILCR, cval); - sio_quot_set(up, quot); - sio_out(up, TXX9_SIFCR, fcr); - - serial_txx9_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -serial_txx9_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - /* - * If oldstate was -1 this is called from - * uart_configure_port(). In this case do not initialize the - * port now, because the port was already initialized (for - * non-console port) or should not be initialized here (for - * console port). If we initialized the port here we lose - * serial console settings. - */ - if (state == 0 && oldstate != -1) - serial_txx9_initialize(port); -} - -static int serial_txx9_request_resource(struct uart_txx9_port *up) -{ - unsigned int size = TXX9_REGION_SIZE; - int ret = 0; - - switch (up->port.iotype) { - default: - if (!up->port.mapbase) - break; - - if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) { - ret = -EBUSY; - break; - } - - if (up->port.flags & UPF_IOREMAP) { - up->port.membase = ioremap(up->port.mapbase, size); - if (!up->port.membase) { - release_mem_region(up->port.mapbase, size); - ret = -ENOMEM; - } - } - break; - - case UPIO_PORT: - if (!request_region(up->port.iobase, size, "serial_txx9")) - ret = -EBUSY; - break; - } - return ret; -} - -static void serial_txx9_release_resource(struct uart_txx9_port *up) -{ - unsigned int size = TXX9_REGION_SIZE; - - switch (up->port.iotype) { - default: - if (!up->port.mapbase) - break; - - if (up->port.flags & UPF_IOREMAP) { - iounmap(up->port.membase); - up->port.membase = NULL; - } - - release_mem_region(up->port.mapbase, size); - break; - - case UPIO_PORT: - release_region(up->port.iobase, size); - break; - } -} - -static void serial_txx9_release_port(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - serial_txx9_release_resource(up); -} - -static int serial_txx9_request_port(struct uart_port *port) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - return serial_txx9_request_resource(up); -} - -static void serial_txx9_config_port(struct uart_port *port, int uflags) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - int ret; - - /* - * Find the region that we can probe for. This in turn - * tells us whether we can probe for the type of port. - */ - ret = serial_txx9_request_resource(up); - if (ret < 0) - return; - port->type = PORT_TXX9; - up->port.fifosize = TXX9_SIO_TX_FIFO; - -#ifdef CONFIG_SERIAL_TXX9_CONSOLE - if (up->port.line == up->port.cons->index) - return; -#endif - serial_txx9_initialize(port); -} - -static const char * -serial_txx9_type(struct uart_port *port) -{ - return "txx9"; -} - -static struct uart_ops serial_txx9_pops = { - .tx_empty = serial_txx9_tx_empty, - .set_mctrl = serial_txx9_set_mctrl, - .get_mctrl = serial_txx9_get_mctrl, - .stop_tx = serial_txx9_stop_tx, - .start_tx = serial_txx9_start_tx, - .stop_rx = serial_txx9_stop_rx, - .enable_ms = serial_txx9_enable_ms, - .break_ctl = serial_txx9_break_ctl, - .startup = serial_txx9_startup, - .shutdown = serial_txx9_shutdown, - .set_termios = serial_txx9_set_termios, - .pm = serial_txx9_pm, - .type = serial_txx9_type, - .release_port = serial_txx9_release_port, - .request_port = serial_txx9_request_port, - .config_port = serial_txx9_config_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = serial_txx9_get_poll_char, - .poll_put_char = serial_txx9_put_poll_char, -#endif -}; - -static struct uart_txx9_port serial_txx9_ports[UART_NR]; - -static void __init serial_txx9_register_ports(struct uart_driver *drv, - struct device *dev) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; - - up->port.line = i; - up->port.ops = &serial_txx9_pops; - up->port.dev = dev; - if (up->port.iobase || up->port.mapbase) - uart_add_one_port(drv, &up->port); - } -} - -#ifdef CONFIG_SERIAL_TXX9_CONSOLE - -static void serial_txx9_console_putchar(struct uart_port *port, int ch) -{ - struct uart_txx9_port *up = to_uart_txx9_port(port); - - wait_for_xmitr(up); - sio_out(up, TXX9_SITFIFO, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial_txx9_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_txx9_port *up = &serial_txx9_ports[co->index]; - unsigned int ier, flcr; - - /* - * First save the UER then disable the interrupts - */ - ier = sio_in(up, TXX9_SIDICR); - sio_out(up, TXX9_SIDICR, 0); - /* - * Disable flow-control if enabled (and unnecessary) - */ - flcr = sio_in(up, TXX9_SIFLCR); - if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) - sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES); - - uart_console_write(&up->port, s, count, serial_txx9_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - sio_out(up, TXX9_SIFLCR, flcr); - sio_out(up, TXX9_SIDICR, ier); -} - -static int __init serial_txx9_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - struct uart_txx9_port *up; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= UART_NR) - co->index = 0; - up = &serial_txx9_ports[co->index]; - port = &up->port; - if (!port->ops) - return -ENODEV; - - serial_txx9_initialize(&up->port); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver serial_txx9_reg; -static struct console serial_txx9_console = { - .name = TXX9_TTY_NAME, - .write = serial_txx9_console_write, - .device = uart_console_device, - .setup = serial_txx9_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_txx9_reg, -}; - -static int __init serial_txx9_console_init(void) -{ - register_console(&serial_txx9_console); - return 0; -} -console_initcall(serial_txx9_console_init); - -#define SERIAL_TXX9_CONSOLE &serial_txx9_console -#else -#define SERIAL_TXX9_CONSOLE NULL -#endif - -static struct uart_driver serial_txx9_reg = { - .owner = THIS_MODULE, - .driver_name = "serial_txx9", - .dev_name = TXX9_TTY_NAME, - .major = TXX9_TTY_MAJOR, - .minor = TXX9_TTY_MINOR_START, - .nr = UART_NR, - .cons = SERIAL_TXX9_CONSOLE, -}; - -int __init early_serial_txx9_setup(struct uart_port *port) -{ - if (port->line >= ARRAY_SIZE(serial_txx9_ports)) - return -ENODEV; - - serial_txx9_ports[port->line].port = *port; - serial_txx9_ports[port->line].port.ops = &serial_txx9_pops; - serial_txx9_ports[port->line].port.flags |= - UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; - return 0; -} - -static DEFINE_MUTEX(serial_txx9_mutex); - -/** - * serial_txx9_register_port - register a serial port - * @port: serial port template - * - * Configure the serial port specified by the request. - * - * 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. - */ -static int __devinit serial_txx9_register_port(struct uart_port *port) -{ - int i; - struct uart_txx9_port *uart; - int ret = -ENOSPC; - - mutex_lock(&serial_txx9_mutex); - for (i = 0; i < UART_NR; i++) { - uart = &serial_txx9_ports[i]; - if (uart_match_port(&uart->port, port)) { - uart_remove_one_port(&serial_txx9_reg, &uart->port); - break; - } - } - if (i == UART_NR) { - /* Find unused port */ - for (i = 0; i < UART_NR; i++) { - uart = &serial_txx9_ports[i]; - if (!(uart->port.iobase || uart->port.mapbase)) - break; - } - } - if (i < UART_NR) { - uart->port.iobase = port->iobase; - uart->port.membase = port->membase; - uart->port.irq = port->irq; - uart->port.uartclk = port->uartclk; - uart->port.iotype = port->iotype; - uart->port.flags = port->flags - | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; - uart->port.mapbase = port->mapbase; - if (port->dev) - uart->port.dev = port->dev; - ret = uart_add_one_port(&serial_txx9_reg, &uart->port); - if (ret == 0) - ret = uart->port.line; - } - mutex_unlock(&serial_txx9_mutex); - return ret; -} - -/** - * serial_txx9_unregister_port - remove a txx9 serial port at runtime - * @line: serial line number - * - * Remove one serial port. This may not be called from interrupt - * context. We hand the port back to the our control. - */ -static void __devexit serial_txx9_unregister_port(int line) -{ - struct uart_txx9_port *uart = &serial_txx9_ports[line]; - - mutex_lock(&serial_txx9_mutex); - uart_remove_one_port(&serial_txx9_reg, &uart->port); - uart->port.flags = 0; - uart->port.type = PORT_UNKNOWN; - uart->port.iobase = 0; - uart->port.mapbase = 0; - uart->port.membase = NULL; - uart->port.dev = NULL; - mutex_unlock(&serial_txx9_mutex); -} - -/* - * Register a set of serial devices attached to a platform device. - */ -static int __devinit serial_txx9_probe(struct platform_device *dev) -{ - struct uart_port *p = dev->dev.platform_data; - struct uart_port port; - int ret, i; - - memset(&port, 0, sizeof(struct uart_port)); - for (i = 0; p && p->uartclk != 0; p++, i++) { - port.iobase = p->iobase; - port.membase = p->membase; - port.irq = p->irq; - port.uartclk = p->uartclk; - port.iotype = p->iotype; - port.flags = p->flags; - port.mapbase = p->mapbase; - port.dev = &dev->dev; - ret = serial_txx9_register_port(&port); - if (ret < 0) { - dev_err(&dev->dev, "unable to register port at index %d " - "(IO%lx MEM%llx IRQ%d): %d\n", i, - p->iobase, (unsigned long long)p->mapbase, - p->irq, ret); - } - } - return 0; -} - -/* - * Remove serial ports registered against a platform device. - */ -static int __devexit serial_txx9_remove(struct platform_device *dev) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; - - if (up->port.dev == &dev->dev) - serial_txx9_unregister_port(i); - } - return 0; -} - -#ifdef CONFIG_PM -static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_suspend_port(&serial_txx9_reg, &up->port); - } - - return 0; -} - -static int serial_txx9_resume(struct platform_device *dev) -{ - int i; - - for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; - - if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) - uart_resume_port(&serial_txx9_reg, &up->port); - } - - return 0; -} -#endif - -static struct platform_driver serial_txx9_plat_driver = { - .probe = serial_txx9_probe, - .remove = __devexit_p(serial_txx9_remove), -#ifdef CONFIG_PM - .suspend = serial_txx9_suspend, - .resume = serial_txx9_resume, -#endif - .driver = { - .name = "serial_txx9", - .owner = THIS_MODULE, - }, -}; - -#ifdef ENABLE_SERIAL_TXX9_PCI -/* - * Probe one serial board. Unfortunately, there is no rhyme nor reason - * to the arrangement of serial ports on a PCI card. - */ -static int __devinit -pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) -{ - struct uart_port port; - int line; - int rc; - - rc = pci_enable_device(dev); - if (rc) - return rc; - - memset(&port, 0, sizeof(port)); - port.ops = &serial_txx9_pops; - port.flags |= UPF_TXX9_HAVE_CTS_LINE; - port.uartclk = 66670000; - port.irq = dev->irq; - port.iotype = UPIO_PORT; - port.iobase = pci_resource_start(dev, 1); - port.dev = &dev->dev; - line = serial_txx9_register_port(&port); - if (line < 0) { - printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line); - pci_disable_device(dev); - return line; - } - pci_set_drvdata(dev, &serial_txx9_ports[line]); - - return 0; -} - -static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) -{ - struct uart_txx9_port *up = pci_get_drvdata(dev); - - pci_set_drvdata(dev, NULL); - - if (up) { - serial_txx9_unregister_port(up->port.line); - pci_disable_device(dev); - } -} - -#ifdef CONFIG_PM -static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) -{ - struct uart_txx9_port *up = pci_get_drvdata(dev); - - if (up) - uart_suspend_port(&serial_txx9_reg, &up->port); - pci_save_state(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); - return 0; -} - -static int pciserial_txx9_resume_one(struct pci_dev *dev) -{ - struct uart_txx9_port *up = pci_get_drvdata(dev); - - pci_set_power_state(dev, PCI_D0); - pci_restore_state(dev); - if (up) - uart_resume_port(&serial_txx9_reg, &up->port); - return 0; -} -#endif - -static const struct pci_device_id serial_txx9_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) }, - { 0, } -}; - -static struct pci_driver serial_txx9_pci_driver = { - .name = "serial_txx9", - .probe = pciserial_txx9_init_one, - .remove = __devexit_p(pciserial_txx9_remove_one), -#ifdef CONFIG_PM - .suspend = pciserial_txx9_suspend_one, - .resume = pciserial_txx9_resume_one, -#endif - .id_table = serial_txx9_pci_tbl, -}; - -MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl); -#endif /* ENABLE_SERIAL_TXX9_PCI */ - -static struct platform_device *serial_txx9_plat_devs; - -static int __init serial_txx9_init(void) -{ - int ret; - - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); - - ret = uart_register_driver(&serial_txx9_reg); - if (ret) - goto out; - - serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1); - if (!serial_txx9_plat_devs) { - ret = -ENOMEM; - goto unreg_uart_drv; - } - - ret = platform_device_add(serial_txx9_plat_devs); - if (ret) - goto put_dev; - - serial_txx9_register_ports(&serial_txx9_reg, - &serial_txx9_plat_devs->dev); - - ret = platform_driver_register(&serial_txx9_plat_driver); - if (ret) - goto del_dev; - -#ifdef ENABLE_SERIAL_TXX9_PCI - ret = pci_register_driver(&serial_txx9_pci_driver); -#endif - if (ret == 0) - goto out; - - del_dev: - platform_device_del(serial_txx9_plat_devs); - put_dev: - platform_device_put(serial_txx9_plat_devs); - unreg_uart_drv: - uart_unregister_driver(&serial_txx9_reg); - out: - return ret; -} - -static void __exit serial_txx9_exit(void) -{ - int i; - -#ifdef ENABLE_SERIAL_TXX9_PCI - pci_unregister_driver(&serial_txx9_pci_driver); -#endif - platform_driver_unregister(&serial_txx9_plat_driver); - platform_device_unregister(serial_txx9_plat_devs); - for (i = 0; i < UART_NR; i++) { - struct uart_txx9_port *up = &serial_txx9_ports[i]; - if (up->port.iobase || up->port.mapbase) - uart_remove_one_port(&serial_txx9_reg, &up->port); - } - - uart_unregister_driver(&serial_txx9_reg); -} - -module_init(serial_txx9_init); -module_exit(serial_txx9_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("TX39/49 serial driver"); - -MODULE_ALIAS_CHARDEV_MAJOR(TXX9_TTY_MAJOR); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c deleted file mode 100644 index c291b3add1d2..000000000000 --- a/drivers/serial/sh-sci.c +++ /dev/null @@ -1,2027 +0,0 @@ -/* - * drivers/serial/sh-sci.c - * - * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) - * - * Copyright (C) 2002 - 2008 Paul Mundt - * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). - * - * based off of the old drivers/char/sh-sci.c by: - * - * Copyright (C) 1999, 2000 Niibe Yutaka - * Copyright (C) 2000 Sugioka Toshinobu - * Modified to support multiple serial ports. Stuart Menefy (May 2000). - * Modified to support SecureEdge. David McCullough (2002) - * Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003). - * Removed SH7300 support (Jul 2007). - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SUPERH -#include -#endif - -#ifdef CONFIG_H8300 -#include -#endif - -#include "sh-sci.h" - -struct sci_port { - struct uart_port port; - - /* Port type */ - unsigned int type; - - /* Port IRQs: ERI, RXI, TXI, BRI (optional) */ - unsigned int irqs[SCIx_NR_IRQS]; - - /* Port enable callback */ - void (*enable)(struct uart_port *port); - - /* Port disable callback */ - void (*disable)(struct uart_port *port); - - /* Break timer */ - struct timer_list break_timer; - int break_flag; - - /* Interface clock */ - struct clk *iclk; - /* Function clock */ - struct clk *fclk; - - struct list_head node; - struct dma_chan *chan_tx; - struct dma_chan *chan_rx; -#ifdef CONFIG_SERIAL_SH_SCI_DMA - struct device *dma_dev; - unsigned int slave_tx; - unsigned int slave_rx; - struct dma_async_tx_descriptor *desc_tx; - struct dma_async_tx_descriptor *desc_rx[2]; - dma_cookie_t cookie_tx; - dma_cookie_t cookie_rx[2]; - dma_cookie_t active_rx; - struct scatterlist sg_tx; - unsigned int sg_len_tx; - struct scatterlist sg_rx[2]; - size_t buf_len_rx; - struct sh_dmae_slave param_tx; - struct sh_dmae_slave param_rx; - struct work_struct work_tx; - struct work_struct work_rx; - struct timer_list rx_timer; - unsigned int rx_timeout; -#endif -}; - -struct sh_sci_priv { - spinlock_t lock; - struct list_head ports; - struct notifier_block clk_nb; -}; - -/* Function prototypes */ -static void sci_stop_tx(struct uart_port *port); - -#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS - -static struct sci_port sci_ports[SCI_NPORTS]; -static struct uart_driver sci_uart_driver; - -static inline struct sci_port * -to_sci_port(struct uart_port *uart) -{ - return container_of(uart, struct sci_port, port); -} - -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) - -#ifdef CONFIG_CONSOLE_POLL -static inline void handle_error(struct uart_port *port) -{ - /* Clear error flags */ - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); -} - -static int sci_poll_get_char(struct uart_port *port) -{ - unsigned short status; - int c; - - do { - status = sci_in(port, SCxSR); - if (status & SCxSR_ERRORS(port)) { - handle_error(port); - continue; - } - break; - } while (1); - - if (!(status & SCxSR_RDxF(port))) - return NO_POLL_CHAR; - - c = sci_in(port, SCxRDR); - - /* Dummy read */ - sci_in(port, SCxSR); - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - - return c; -} -#endif - -static void sci_poll_put_char(struct uart_port *port, unsigned char c) -{ - unsigned short status; - - do { - status = sci_in(port, SCxSR); - } while (!(status & SCxSR_TDxE(port))); - - sci_out(port, SCxTDR, c); - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); -} -#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ - -#if defined(__H8300H__) || defined(__H8300S__) -static void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - int ch = (port->mapbase - SMR0) >> 3; - - /* set DDR regs */ - H8300_GPIO_DDR(h8300_sci_pins[ch].port, - h8300_sci_pins[ch].rx, - H8300_GPIO_INPUT); - H8300_GPIO_DDR(h8300_sci_pins[ch].port, - h8300_sci_pins[ch].tx, - H8300_GPIO_OUTPUT); - - /* tx mark output*/ - H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - if (port->mapbase == 0xA4400000) { - __raw_writew(__raw_readw(PACR) & 0xffc0, PACR); - __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR); - } else if (port->mapbase == 0xA4410000) - __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR); -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721) -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - unsigned short data; - - if (cflag & CRTSCTS) { - /* enable RTS/CTS */ - if (port->mapbase == 0xa4430000) { /* SCIF0 */ - /* Clear PTCR bit 9-2; enable all scif pins but sck */ - data = __raw_readw(PORT_PTCR); - __raw_writew((data & 0xfc03), PORT_PTCR); - } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ - /* Clear PVCR bit 9-2 */ - data = __raw_readw(PORT_PVCR); - __raw_writew((data & 0xfc03), PORT_PVCR); - } - } else { - if (port->mapbase == 0xa4430000) { /* SCIF0 */ - /* Clear PTCR bit 5-2; enable only tx and rx */ - data = __raw_readw(PORT_PTCR); - __raw_writew((data & 0xffc3), PORT_PTCR); - } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ - /* Clear PVCR bit 5-2 */ - data = __raw_readw(PORT_PVCR); - __raw_writew((data & 0xffc3), PORT_PVCR); - } - } -} -#elif defined(CONFIG_CPU_SH3) -/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - unsigned short data; - - /* We need to set SCPCR to enable RTS/CTS */ - data = __raw_readw(SCPCR); - /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ - __raw_writew(data & 0x0fcf, SCPCR); - - if (!(cflag & CRTSCTS)) { - /* We need to set SCPCR to enable RTS/CTS */ - data = __raw_readw(SCPCR); - /* Clear out SCP7MD1,0, SCP4MD1,0, - Set SCP6MD1,0 = {01} (output) */ - __raw_writew((data & 0x0fcf) | 0x1000, SCPCR); - - data = __raw_readb(SCPDR); - /* Set /RTS2 (bit6) = 0 */ - __raw_writeb(data & 0xbf, SCPDR); - } -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7722) -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - unsigned short data; - - if (port->mapbase == 0xffe00000) { - data = __raw_readw(PSCR); - data &= ~0x03cf; - if (!(cflag & CRTSCTS)) - data |= 0x0340; - - __raw_writew(data, PSCR); - } -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) || \ - defined(CONFIG_CPU_SUBTYPE_SHX3) -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - if (!(cflag & CRTSCTS)) - __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */ -} -#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A) -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - if (!(cflag & CRTSCTS)) - __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */ -} -#else -static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) -{ - /* Nothing to do */ -} -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) -static int scif_txfill(struct uart_port *port) -{ - return sci_in(port, SCTFDR) & 0xff; -} - -static int scif_txroom(struct uart_port *port) -{ - return SCIF_TXROOM_MAX - scif_txfill(port); -} - -static int scif_rxfill(struct uart_port *port) -{ - return sci_in(port, SCRFDR) & 0xff; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7763) -static int scif_txfill(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000 || - port->mapbase == 0xffe08000) - /* SCIF0/1*/ - return sci_in(port, SCTFDR) & 0xff; - else - /* SCIF2 */ - return sci_in(port, SCFDR) >> 8; -} - -static int scif_txroom(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000 || - port->mapbase == 0xffe08000) - /* SCIF0/1*/ - return SCIF_TXROOM_MAX - scif_txfill(port); - else - /* SCIF2 */ - return SCIF2_TXROOM_MAX - scif_txfill(port); -} - -static int scif_rxfill(struct uart_port *port) -{ - if ((port->mapbase == 0xffe00000) || - (port->mapbase == 0xffe08000)) { - /* SCIF0/1*/ - return sci_in(port, SCRFDR) & 0xff; - } else { - /* SCIF2 */ - return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; - } -} -#elif defined(CONFIG_ARCH_SH7372) -static int scif_txfill(struct uart_port *port) -{ - if (port->type == PORT_SCIFA) - return sci_in(port, SCFDR) >> 8; - else - return sci_in(port, SCTFDR); -} - -static int scif_txroom(struct uart_port *port) -{ - return port->fifosize - scif_txfill(port); -} - -static int scif_rxfill(struct uart_port *port) -{ - if (port->type == PORT_SCIFA) - return sci_in(port, SCFDR) & SCIF_RFDC_MASK; - else - return sci_in(port, SCRFDR); -} -#else -static int scif_txfill(struct uart_port *port) -{ - return sci_in(port, SCFDR) >> 8; -} - -static int scif_txroom(struct uart_port *port) -{ - return SCIF_TXROOM_MAX - scif_txfill(port); -} - -static int scif_rxfill(struct uart_port *port) -{ - return sci_in(port, SCFDR) & SCIF_RFDC_MASK; -} -#endif - -static int sci_txfill(struct uart_port *port) -{ - return !(sci_in(port, SCxSR) & SCI_TDRE); -} - -static int sci_txroom(struct uart_port *port) -{ - return !sci_txfill(port); -} - -static int sci_rxfill(struct uart_port *port) -{ - return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; -} - -/* ********************************************************************** * - * the interrupt related routines * - * ********************************************************************** */ - -static void sci_transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - unsigned int stopped = uart_tx_stopped(port); - unsigned short status; - unsigned short ctrl; - int count; - - status = sci_in(port, SCxSR); - if (!(status & SCxSR_TDxE(port))) { - ctrl = sci_in(port, SCSCR); - if (uart_circ_empty(xmit)) - ctrl &= ~SCI_CTRL_FLAGS_TIE; - else - ctrl |= SCI_CTRL_FLAGS_TIE; - sci_out(port, SCSCR, ctrl); - return; - } - - if (port->type == PORT_SCI) - count = sci_txroom(port); - else - count = scif_txroom(port); - - do { - unsigned char c; - - if (port->x_char) { - c = port->x_char; - port->x_char = 0; - } else if (!uart_circ_empty(xmit) && !stopped) { - c = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else { - break; - } - - sci_out(port, SCxTDR, c); - - port->icount.tx++; - } while (--count > 0); - - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { - sci_stop_tx(port); - } else { - ctrl = sci_in(port, SCSCR); - - if (port->type != PORT_SCI) { - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - } - - ctrl |= SCI_CTRL_FLAGS_TIE; - sci_out(port, SCSCR, ctrl); - } -} - -/* On SH3, SCIF may read end-of-break as a space->mark char */ -#define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); }) - -static inline void sci_receive_chars(struct uart_port *port) -{ - struct sci_port *sci_port = to_sci_port(port); - struct tty_struct *tty = port->state->port.tty; - int i, count, copied = 0; - unsigned short status; - unsigned char flag; - - status = sci_in(port, SCxSR); - if (!(status & SCxSR_RDxF(port))) - return; - - while (1) { - if (port->type == PORT_SCI) - count = sci_rxfill(port); - else - count = scif_rxfill(port); - - /* Don't copy more bytes than there is room for in the buffer */ - count = tty_buffer_request_room(tty, count); - - /* If for any reason we can't copy more data, we're done! */ - if (count == 0) - break; - - if (port->type == PORT_SCI) { - char c = sci_in(port, SCxRDR); - if (uart_handle_sysrq_char(port, c) || - sci_port->break_flag) - count = 0; - else - tty_insert_flip_char(tty, c, TTY_NORMAL); - } else { - for (i = 0; i < count; i++) { - char c = sci_in(port, SCxRDR); - status = sci_in(port, SCxSR); -#if defined(CONFIG_CPU_SH3) - /* Skip "chars" during break */ - if (sci_port->break_flag) { - if ((c == 0) && - (status & SCxSR_FER(port))) { - count--; i--; - continue; - } - - /* Nonzero => end-of-break */ - dev_dbg(port->dev, "debounce<%02x>\n", c); - sci_port->break_flag = 0; - - if (STEPFN(c)) { - count--; i--; - continue; - } - } -#endif /* CONFIG_CPU_SH3 */ - if (uart_handle_sysrq_char(port, c)) { - count--; i--; - continue; - } - - /* Store data and status */ - if (status & SCxSR_FER(port)) { - flag = TTY_FRAME; - dev_notice(port->dev, "frame error\n"); - } else if (status & SCxSR_PER(port)) { - flag = TTY_PARITY; - dev_notice(port->dev, "parity error\n"); - } else - flag = TTY_NORMAL; - - tty_insert_flip_char(tty, c, flag); - } - } - - sci_in(port, SCxSR); /* dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - - copied += count; - port->icount.rx += count; - } - - if (copied) { - /* Tell the rest of the system the news. New characters! */ - tty_flip_buffer_push(tty); - } else { - sci_in(port, SCxSR); /* dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - } -} - -#define SCI_BREAK_JIFFIES (HZ/20) -/* The sci generates interrupts during the break, - * 1 per millisecond or so during the break period, for 9600 baud. - * So dont bother disabling interrupts. - * But dont want more than 1 break event. - * Use a kernel timer to periodically poll the rx line until - * the break is finished. - */ -static void sci_schedule_break_timer(struct sci_port *port) -{ - port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES; - add_timer(&port->break_timer); -} -/* Ensure that two consecutive samples find the break over. */ -static void sci_break_timer(unsigned long data) -{ - struct sci_port *port = (struct sci_port *)data; - - if (sci_rxd_in(&port->port) == 0) { - port->break_flag = 1; - sci_schedule_break_timer(port); - } else if (port->break_flag == 1) { - /* break is over. */ - port->break_flag = 2; - sci_schedule_break_timer(port); - } else - port->break_flag = 0; -} - -static inline int sci_handle_errors(struct uart_port *port) -{ - int copied = 0; - unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->state->port.tty; - - if (status & SCxSR_ORER(port)) { - /* overrun error */ - if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) - copied++; - - dev_notice(port->dev, "overrun error"); - } - - if (status & SCxSR_FER(port)) { - if (sci_rxd_in(port) == 0) { - /* Notify of BREAK */ - struct sci_port *sci_port = to_sci_port(port); - - if (!sci_port->break_flag) { - sci_port->break_flag = 1; - sci_schedule_break_timer(sci_port); - - /* Do sysrq handling. */ - if (uart_handle_break(port)) - return 0; - - dev_dbg(port->dev, "BREAK detected\n"); - - if (tty_insert_flip_char(tty, 0, TTY_BREAK)) - copied++; - } - - } else { - /* frame error */ - if (tty_insert_flip_char(tty, 0, TTY_FRAME)) - copied++; - - dev_notice(port->dev, "frame error\n"); - } - } - - if (status & SCxSR_PER(port)) { - /* parity error */ - if (tty_insert_flip_char(tty, 0, TTY_PARITY)) - copied++; - - dev_notice(port->dev, "parity error"); - } - - if (copied) - tty_flip_buffer_push(tty); - - return copied; -} - -static inline int sci_handle_fifo_overrun(struct uart_port *port) -{ - struct tty_struct *tty = port->state->port.tty; - int copied = 0; - - if (port->type != PORT_SCIF) - return 0; - - if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) { - sci_out(port, SCLSR, 0); - - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - tty_flip_buffer_push(tty); - - dev_notice(port->dev, "overrun error\n"); - copied++; - } - - return copied; -} - -static inline int sci_handle_breaks(struct uart_port *port) -{ - int copied = 0; - unsigned short status = sci_in(port, SCxSR); - struct tty_struct *tty = port->state->port.tty; - struct sci_port *s = to_sci_port(port); - - if (uart_handle_break(port)) - return 0; - - if (!s->break_flag && status & SCxSR_BRK(port)) { -#if defined(CONFIG_CPU_SH3) - /* Debounce break */ - s->break_flag = 1; -#endif - /* Notify of BREAK */ - if (tty_insert_flip_char(tty, 0, TTY_BREAK)) - copied++; - - dev_dbg(port->dev, "BREAK detected\n"); - } - - if (copied) - tty_flip_buffer_push(tty); - - copied += sci_handle_fifo_overrun(port); - - return copied; -} - -static irqreturn_t sci_rx_interrupt(int irq, void *ptr) -{ -#ifdef CONFIG_SERIAL_SH_SCI_DMA - struct uart_port *port = ptr; - struct sci_port *s = to_sci_port(port); - - if (s->chan_rx) { - u16 scr = sci_in(port, SCSCR); - u16 ssr = sci_in(port, SCxSR); - - /* Disable future Rx interrupts */ - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - disable_irq_nosync(irq); - scr |= 0x4000; - } else { - scr &= ~SCI_CTRL_FLAGS_RIE; - } - sci_out(port, SCSCR, scr); - /* Clear current interrupt */ - sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); - dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", - jiffies, s->rx_timeout); - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); - - return IRQ_HANDLED; - } -#endif - - /* I think sci_receive_chars has to be called irrespective - * of whether the I_IXOFF is set, otherwise, how is the interrupt - * to be disabled? - */ - sci_receive_chars(ptr); - - return IRQ_HANDLED; -} - -static irqreturn_t sci_tx_interrupt(int irq, void *ptr) -{ - struct uart_port *port = ptr; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - sci_transmit_chars(port); - spin_unlock_irqrestore(&port->lock, flags); - - return IRQ_HANDLED; -} - -static irqreturn_t sci_er_interrupt(int irq, void *ptr) -{ - struct uart_port *port = ptr; - - /* Handle errors */ - if (port->type == PORT_SCI) { - if (sci_handle_errors(port)) { - /* discard character in rx buffer */ - sci_in(port, SCxSR); - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - } - } else { - sci_handle_fifo_overrun(port); - sci_rx_interrupt(irq, ptr); - } - - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); - - /* Kick the transmission */ - sci_tx_interrupt(irq, ptr); - - return IRQ_HANDLED; -} - -static irqreturn_t sci_br_interrupt(int irq, void *ptr) -{ - struct uart_port *port = ptr; - - /* Handle BREAKs */ - sci_handle_breaks(port); - sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); - - return IRQ_HANDLED; -} - -static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) -{ - unsigned short ssr_status, scr_status, err_enabled; - struct uart_port *port = ptr; - struct sci_port *s = to_sci_port(port); - irqreturn_t ret = IRQ_NONE; - - ssr_status = sci_in(port, SCxSR); - scr_status = sci_in(port, SCSCR); - err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE); - - /* Tx Interrupt */ - if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) && - !s->chan_tx) - ret = sci_tx_interrupt(irq, ptr); - /* - * Rx Interrupt: if we're using DMA, the DMA controller clears RDF / - * DR flags - */ - if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) && - (scr_status & SCI_CTRL_FLAGS_RIE)) - ret = sci_rx_interrupt(irq, ptr); - /* Error Interrupt */ - if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled) - ret = sci_er_interrupt(irq, ptr); - /* Break Interrupt */ - if ((ssr_status & SCxSR_BRK(port)) && err_enabled) - ret = sci_br_interrupt(irq, ptr); - - return ret; -} - -/* - * Here we define a transistion notifier so that we can update all of our - * ports' baud rate when the peripheral clock changes. - */ -static int sci_notifier(struct notifier_block *self, - unsigned long phase, void *p) -{ - struct sh_sci_priv *priv = container_of(self, - struct sh_sci_priv, clk_nb); - struct sci_port *sci_port; - unsigned long flags; - - if ((phase == CPUFREQ_POSTCHANGE) || - (phase == CPUFREQ_RESUMECHANGE)) { - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(sci_port, &priv->ports, node) - sci_port->port.uartclk = clk_get_rate(sci_port->iclk); - spin_unlock_irqrestore(&priv->lock, flags); - } - - return NOTIFY_OK; -} - -static void sci_clk_enable(struct uart_port *port) -{ - struct sci_port *sci_port = to_sci_port(port); - - clk_enable(sci_port->iclk); - sci_port->port.uartclk = clk_get_rate(sci_port->iclk); - clk_enable(sci_port->fclk); -} - -static void sci_clk_disable(struct uart_port *port) -{ - struct sci_port *sci_port = to_sci_port(port); - - clk_disable(sci_port->fclk); - clk_disable(sci_port->iclk); -} - -static int sci_request_irq(struct sci_port *port) -{ - int i; - irqreturn_t (*handlers[4])(int irq, void *ptr) = { - sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, - sci_br_interrupt, - }; - const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full", - "SCI Transmit Data Empty", "SCI Break" }; - - if (port->irqs[0] == port->irqs[1]) { - if (unlikely(!port->irqs[0])) - return -ENODEV; - - if (request_irq(port->irqs[0], sci_mpxed_interrupt, - IRQF_DISABLED, "sci", port)) { - dev_err(port->port.dev, "Can't allocate IRQ\n"); - return -ENODEV; - } - } else { - for (i = 0; i < ARRAY_SIZE(handlers); i++) { - if (unlikely(!port->irqs[i])) - continue; - - if (request_irq(port->irqs[i], handlers[i], - IRQF_DISABLED, desc[i], port)) { - dev_err(port->port.dev, "Can't allocate IRQ\n"); - return -ENODEV; - } - } - } - - return 0; -} - -static void sci_free_irq(struct sci_port *port) -{ - int i; - - if (port->irqs[0] == port->irqs[1]) - free_irq(port->irqs[0], port); - else { - for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { - if (!port->irqs[i]) - continue; - - free_irq(port->irqs[i], port); - } - } -} - -static unsigned int sci_tx_empty(struct uart_port *port) -{ - unsigned short status = sci_in(port, SCxSR); - unsigned short in_tx_fifo = scif_txfill(port); - - return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; -} - -static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ - /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ - /* If you have signals for DTR and DCD, please implement here. */ -} - -static unsigned int sci_get_mctrl(struct uart_port *port) -{ - /* This routine is used for getting signals of: DTR, DCD, DSR, RI, - and CTS/RTS */ - - return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; -} - -#ifdef CONFIG_SERIAL_SH_SCI_DMA -static void sci_dma_tx_complete(void *arg) -{ - struct sci_port *s = arg; - struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned long flags; - - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - - spin_lock_irqsave(&port->lock, flags); - - xmit->tail += sg_dma_len(&s->sg_tx); - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += sg_dma_len(&s->sg_tx); - - async_tx_ack(s->desc_tx); - s->cookie_tx = -EINVAL; - s->desc_tx = NULL; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!uart_circ_empty(xmit)) { - schedule_work(&s->work_tx); - } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = sci_in(port, SCSCR); - sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Locking: called with port lock held */ -static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty, - size_t count) -{ - struct uart_port *port = &s->port; - int i, active, room; - - room = tty_buffer_request_room(tty, count); - - if (s->active_rx == s->cookie_rx[0]) { - active = 0; - } else if (s->active_rx == s->cookie_rx[1]) { - active = 1; - } else { - dev_err(port->dev, "cookie %d not found!\n", s->active_rx); - return 0; - } - - if (room < count) - dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", - count - room); - if (!room) - return room; - - for (i = 0; i < room; i++) - tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i], - TTY_NORMAL); - - port->icount.rx += room; - - return room; -} - -static void sci_dma_rx_complete(void *arg) -{ - struct sci_port *s = arg; - struct uart_port *port = &s->port; - struct tty_struct *tty = port->state->port.tty; - unsigned long flags; - int count; - - dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); - - spin_lock_irqsave(&port->lock, flags); - - count = sci_dma_rx_push(s, tty, s->buf_len_rx); - - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); - - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(tty); - - schedule_work(&s->work_rx); -} - -static void sci_start_rx(struct uart_port *port); -static void sci_start_tx(struct uart_port *port); - -static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_rx; - struct uart_port *port = &s->port; - - s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; - dma_release_channel(chan); - if (sg_dma_address(&s->sg_rx[0])) - dma_free_coherent(port->dev, s->buf_len_rx * 2, - sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0])); - if (enable_pio) - sci_start_rx(port); -} - -static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_tx; - struct uart_port *port = &s->port; - - s->chan_tx = NULL; - s->cookie_tx = -EINVAL; - dma_release_channel(chan); - if (enable_pio) - sci_start_tx(port); -} - -static void sci_submit_rx(struct sci_port *s) -{ - struct dma_chan *chan = s->chan_rx; - int i; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - struct dma_async_tx_descriptor *desc; - - desc = chan->device->device_prep_slave_sg(chan, - sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT); - - if (desc) { - s->desc_rx[i] = desc; - desc->callback = sci_dma_rx_complete; - desc->callback_param = s; - s->cookie_rx[i] = desc->tx_submit(desc); - } - - if (!desc || s->cookie_rx[i] < 0) { - if (i) { - async_tx_ack(s->desc_rx[0]); - s->cookie_rx[0] = -EINVAL; - } - if (desc) { - async_tx_ack(desc); - s->cookie_rx[i] = -EINVAL; - } - dev_warn(s->port.dev, - "failed to re-start DMA, using PIO\n"); - sci_rx_dma_release(s, true); - return; - } - dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, - s->cookie_rx[i], i); - } - - s->active_rx = s->cookie_rx[0]; - - dma_async_issue_pending(chan); -} - -static void work_fn_rx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_rx); - struct uart_port *port = &s->port; - struct dma_async_tx_descriptor *desc; - int new; - - if (s->active_rx == s->cookie_rx[0]) { - new = 0; - } else if (s->active_rx == s->cookie_rx[1]) { - new = 1; - } else { - dev_err(port->dev, "cookie %d not found!\n", s->active_rx); - return; - } - desc = s->desc_rx[new]; - - if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != - DMA_SUCCESS) { - /* Handle incomplete DMA receive */ - struct tty_struct *tty = port->state->port.tty; - struct dma_chan *chan = s->chan_rx; - struct sh_desc *sh_desc = container_of(desc, struct sh_desc, - async_tx); - unsigned long flags; - int count; - - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); - dev_dbg(port->dev, "Read %u bytes with cookie %d\n", - sh_desc->partial, sh_desc->cookie); - - spin_lock_irqsave(&port->lock, flags); - count = sci_dma_rx_push(s, tty, sh_desc->partial); - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(tty); - - sci_submit_rx(s); - - return; - } - - s->cookie_rx[new] = desc->tx_submit(desc); - if (s->cookie_rx[new] < 0) { - dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); - sci_rx_dma_release(s, true); - return; - } - - s->active_rx = s->cookie_rx[!new]; - - dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, - s->cookie_rx[new], new, s->active_rx); -} - -static void work_fn_tx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_tx); - struct dma_async_tx_descriptor *desc; - struct dma_chan *chan = s->chan_tx; - struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; - struct scatterlist *sg = &s->sg_tx; - - /* - * DMA is idle now. - * Port xmit buffer is already mapped, and it is one page... Just adjust - * offsets and lengths. Since it is a circular buffer, we have to - * transmit till the end, and then the rest. Take the port lock to get a - * consistent xmit buffer state. - */ - spin_lock_irq(&port->lock); - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + - sg->offset; - sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); - spin_unlock_irq(&port->lock); - - BUG_ON(!sg_dma_len(sg)); - - desc = chan->device->device_prep_slave_sg(chan, - sg, s->sg_len_tx, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); - - spin_lock_irq(&port->lock); - s->desc_tx = desc; - desc->callback = sci_dma_tx_complete; - desc->callback_param = s; - spin_unlock_irq(&port->lock); - s->cookie_tx = desc->tx_submit(desc); - if (s->cookie_tx < 0) { - dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, - xmit->buf, xmit->tail, xmit->head, s->cookie_tx); - - dma_async_issue_pending(chan); -} -#endif - -static void sci_start_tx(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - unsigned short ctrl; - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = sci_in(port, SCSCR); - if (s->chan_tx) - new = scr | 0x8000; - else - new = scr & ~0x8000; - if (new != scr) - sci_out(port, SCSCR, new); - } - if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && - s->cookie_tx < 0) - schedule_work(&s->work_tx); -#endif - if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = sci_in(port, SCSCR); - sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE); - } -} - -static void sci_stop_tx(struct uart_port *port) -{ - unsigned short ctrl; - - /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = sci_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x8000; - ctrl &= ~SCI_CTRL_FLAGS_TIE; - sci_out(port, SCSCR, ctrl); -} - -static void sci_start_rx(struct uart_port *port) -{ - unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; - - /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ - ctrl |= sci_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; - sci_out(port, SCSCR, ctrl); -} - -static void sci_stop_rx(struct uart_port *port) -{ - unsigned short ctrl; - - /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ - ctrl = sci_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; - ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); - sci_out(port, SCSCR, ctrl); -} - -static void sci_enable_ms(struct uart_port *port) -{ - /* Nothing here yet .. */ -} - -static void sci_break_ctl(struct uart_port *port, int break_state) -{ - /* Nothing here yet .. */ -} - -#ifdef CONFIG_SERIAL_SH_SCI_DMA -static bool filter(struct dma_chan *chan, void *slave) -{ - struct sh_dmae_slave *param = slave; - - dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, - param->slave_id); - - if (param->dma_dev == chan->device->dev) { - chan->private = param; - return true; - } else { - return false; - } -} - -static void rx_timer_fn(unsigned long arg) -{ - struct sci_port *s = (struct sci_port *)arg; - struct uart_port *port = &s->port; - u16 scr = sci_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~0x4000; - enable_irq(s->irqs[1]); - } - sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE); - dev_dbg(port->dev, "DMA Rx timed out\n"); - schedule_work(&s->work_rx); -} - -static void sci_request_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - struct sh_dmae_slave *param; - struct dma_chan *chan; - dma_cap_mask_t mask; - int nent; - - dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, - port->line, s->dma_dev); - - if (!s->dma_dev) - return; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - param = &s->param_tx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ - param->slave_id = s->slave_tx; - param->dma_dev = s->dma_dev; - - s->cookie_tx = -EINVAL; - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); - if (chan) { - s->chan_tx = chan; - sg_init_table(&s->sg_tx, 1); - /* UART circular tx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); - sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); - nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); - if (!nent) - sci_tx_dma_release(s, false); - else - dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, - sg_dma_len(&s->sg_tx), - port->state->xmit.buf, sg_dma_address(&s->sg_tx)); - - s->sg_len_tx = nent; - - INIT_WORK(&s->work_tx, work_fn_tx); - } - - param = &s->param_rx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ - param->slave_id = s->slave_rx; - param->dma_dev = s->dma_dev; - - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); - if (chan) { - dma_addr_t dma[2]; - void *buf[2]; - int i; - - s->chan_rx = chan; - - s->buf_len_rx = 2 * max(16, (int)port->fifosize); - buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2, - &dma[0], GFP_KERNEL); - - if (!buf[0]) { - dev_warn(port->dev, - "failed to allocate dma buffer, using PIO\n"); - sci_rx_dma_release(s, true); - return; - } - - buf[1] = buf[0] + s->buf_len_rx; - dma[1] = dma[0] + s->buf_len_rx; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - - sg_init_table(sg, 1); - sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, - (int)buf[i] & ~PAGE_MASK); - sg_dma_address(sg) = dma[i]; - } - - INIT_WORK(&s->work_rx, work_fn_rx); - setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); - - sci_submit_rx(s); - } -} - -static void sci_free_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - if (!s->dma_dev) - return; - - if (s->chan_tx) - sci_tx_dma_release(s, false); - if (s->chan_rx) - sci_rx_dma_release(s, false); -} -#endif - -static int sci_startup(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - - if (s->enable) - s->enable(port); - - sci_request_irq(s); -#ifdef CONFIG_SERIAL_SH_SCI_DMA - sci_request_dma(port); -#endif - sci_start_tx(port); - sci_start_rx(port); - - return 0; -} - -static void sci_shutdown(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - - sci_stop_rx(port); - sci_stop_tx(port); -#ifdef CONFIG_SERIAL_SH_SCI_DMA - sci_free_dma(port); -#endif - sci_free_irq(s); - - if (s->disable) - s->disable(port); -} - -static void sci_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ -#ifdef CONFIG_SERIAL_SH_SCI_DMA - struct sci_port *s = to_sci_port(port); -#endif - unsigned int status, baud, smr_val, max_baud; - int t = -1; - u16 scfcr = 0; - - /* - * earlyprintk comes here early on with port->uartclk set to zero. - * the clock framework is not up and running at this point so here - * we assume that 115200 is the maximum baud rate. please note that - * the baud rate is not programmed during earlyprintk - it is assumed - * that the previous boot loader has enabled required clocks and - * setup the baud rate generator hardware for us already. - */ - max_baud = port->uartclk ? port->uartclk / 16 : 115200; - - baud = uart_get_baud_rate(port, termios, old, 0, max_baud); - if (likely(baud && port->uartclk)) - t = SCBRR_VALUE(baud, port->uartclk); - - do { - status = sci_in(port, SCxSR); - } while (!(status & SCxSR_TEND(port))); - - sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ - - if (port->type != PORT_SCI) - sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST); - - smr_val = sci_in(port, SCSMR) & 3; - if ((termios->c_cflag & CSIZE) == CS7) - smr_val |= 0x40; - if (termios->c_cflag & PARENB) - smr_val |= 0x20; - if (termios->c_cflag & PARODD) - smr_val |= 0x30; - if (termios->c_cflag & CSTOPB) - smr_val |= 0x08; - - uart_update_timeout(port, termios->c_cflag, baud); - - sci_out(port, SCSMR, smr_val); - - dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, - SCSCR_INIT(port)); - - if (t > 0) { - if (t >= 256) { - sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); - t >>= 2; - } else - sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); - - sci_out(port, SCBRR, t); - udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ - } - - sci_init_pins(port, termios->c_cflag); - sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0)); - - sci_out(port, SCSCR, SCSCR_INIT(port)); - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - /* - * Calculate delay for 1.5 DMA buffers: see - * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits - * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function - * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." - * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO - * sizes), but it has been found out experimentally, that this is not - * enough: the driver too often needlessly runs on a DMA timeout. 20ms - * as a minimum seem to work perfectly. - */ - if (s->chan_rx) { - s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / - port->fifosize / 2; - dev_dbg(port->dev, - "DMA Rx t-out %ums, tty t-out %u jiffies\n", - s->rx_timeout * 1000 / HZ, port->timeout); - if (s->rx_timeout < msecs_to_jiffies(20)) - s->rx_timeout = msecs_to_jiffies(20); - } -#endif - - if ((termios->c_cflag & CREAD) != 0) - sci_start_rx(port); -} - -static const char *sci_type(struct uart_port *port) -{ - switch (port->type) { - case PORT_IRDA: - return "irda"; - case PORT_SCI: - return "sci"; - case PORT_SCIF: - return "scif"; - case PORT_SCIFA: - return "scifa"; - case PORT_SCIFB: - return "scifb"; - } - - return NULL; -} - -static void sci_release_port(struct uart_port *port) -{ - /* Nothing here yet .. */ -} - -static int sci_request_port(struct uart_port *port) -{ - /* Nothing here yet .. */ - return 0; -} - -static void sci_config_port(struct uart_port *port, int flags) -{ - struct sci_port *s = to_sci_port(port); - - port->type = s->type; - - if (port->membase) - return; - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, 0x40); - - if (IS_ERR(port->membase)) - dev_err(port->dev, "can't remap port#%d\n", port->line); - } else { - /* - * For the simple (and majority of) cases where we don't - * need to do any remapping, just cast the cookie - * directly. - */ - port->membase = (void __iomem *)port->mapbase; - } -} - -static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct sci_port *s = to_sci_port(port); - - if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) - return -EINVAL; - if (ser->baud_base < 2400) - /* No paper tape reader for Mitch.. */ - return -EINVAL; - - return 0; -} - -static struct uart_ops sci_uart_ops = { - .tx_empty = sci_tx_empty, - .set_mctrl = sci_set_mctrl, - .get_mctrl = sci_get_mctrl, - .start_tx = sci_start_tx, - .stop_tx = sci_stop_tx, - .stop_rx = sci_stop_rx, - .enable_ms = sci_enable_ms, - .break_ctl = sci_break_ctl, - .startup = sci_startup, - .shutdown = sci_shutdown, - .set_termios = sci_set_termios, - .type = sci_type, - .release_port = sci_release_port, - .request_port = sci_request_port, - .config_port = sci_config_port, - .verify_port = sci_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = sci_poll_get_char, - .poll_put_char = sci_poll_put_char, -#endif -}; - -static int __devinit sci_init_single(struct platform_device *dev, - struct sci_port *sci_port, - unsigned int index, - struct plat_sci_port *p) -{ - struct uart_port *port = &sci_port->port; - - port->ops = &sci_uart_ops; - port->iotype = UPIO_MEM; - port->line = index; - - switch (p->type) { - case PORT_SCIFB: - port->fifosize = 256; - break; - case PORT_SCIFA: - port->fifosize = 64; - break; - case PORT_SCIF: - port->fifosize = 16; - break; - default: - port->fifosize = 1; - break; - } - - if (dev) { - sci_port->iclk = clk_get(&dev->dev, "sci_ick"); - if (IS_ERR(sci_port->iclk)) { - sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); - if (IS_ERR(sci_port->iclk)) { - dev_err(&dev->dev, "can't get iclk\n"); - return PTR_ERR(sci_port->iclk); - } - } - - /* - * The function clock is optional, ignore it if we can't - * find it. - */ - sci_port->fclk = clk_get(&dev->dev, "sci_fck"); - if (IS_ERR(sci_port->fclk)) - sci_port->fclk = NULL; - - sci_port->enable = sci_clk_enable; - sci_port->disable = sci_clk_disable; - port->dev = &dev->dev; - } - - sci_port->break_timer.data = (unsigned long)sci_port; - sci_port->break_timer.function = sci_break_timer; - init_timer(&sci_port->break_timer); - - port->mapbase = p->mapbase; - port->membase = p->membase; - - port->irq = p->irqs[SCIx_TXI_IRQ]; - port->flags = p->flags; - sci_port->type = port->type = p->type; - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - sci_port->dma_dev = p->dma_dev; - sci_port->slave_tx = p->dma_slave_tx; - sci_port->slave_rx = p->dma_slave_rx; - - dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__, - p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); -#endif - - memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); - return 0; -} - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static struct tty_driver *serial_console_device(struct console *co, int *index) -{ - struct uart_driver *p = &sci_uart_driver; - *index = co->index; - return p->tty_driver; -} - -static void serial_console_putchar(struct uart_port *port, int ch) -{ - sci_poll_put_char(port, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void serial_console_write(struct console *co, const char *s, - unsigned count) -{ - struct uart_port *port = co->data; - struct sci_port *sci_port = to_sci_port(port); - unsigned short bits; - - if (sci_port->enable) - sci_port->enable(port); - - uart_console_write(port, s, count, serial_console_putchar); - - /* wait until fifo is empty and last bit has been transmitted */ - bits = SCxSR_TDxE(port) | SCxSR_TEND(port); - while ((sci_in(port, SCxSR) & bits) != bits) - cpu_relax(); - - if (sci_port->disable) - sci_port->disable(port); -} - -static int __devinit serial_console_setup(struct console *co, char *options) -{ - struct sci_port *sci_port; - struct uart_port *port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= SCI_NPORTS) - co->index = 0; - - if (co->data) { - port = co->data; - sci_port = to_sci_port(port); - } else { - sci_port = &sci_ports[co->index]; - port = &sci_port->port; - co->data = port; - } - - /* - * Also need to check port->type, we don't actually have any - * UPIO_PORT ports, but uart_report_port() handily misreports - * it anyways if we don't have a port available by the time this is - * called. - */ - if (!port->type) - return -ENODEV; - - sci_config_port(port, 0); - - if (sci_port->enable) - sci_port->enable(port); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - ret = uart_set_options(port, co, baud, parity, bits, flow); -#if defined(__H8300H__) || defined(__H8300S__) - /* disable rx interrupt */ - if (ret == 0) - sci_stop_rx(port); -#endif - /* TODO: disable clock */ - return ret; -} - -static struct console serial_console = { - .name = "ttySC", - .device = serial_console_device, - .write = serial_console_write, - .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init sci_console_init(void) -{ - register_console(&serial_console); - return 0; -} -console_initcall(sci_console_init); - -static struct sci_port early_serial_port; -static struct console early_serial_console = { - .name = "early_ttySC", - .write = serial_console_write, - .flags = CON_PRINTBUFFER, -}; -static char early_serial_buf[32]; - -#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ - -#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) -#define SCI_CONSOLE (&serial_console) -#else -#define SCI_CONSOLE 0 -#endif - -static char banner[] __initdata = - KERN_INFO "SuperH SCI(F) driver initialized\n"; - -static struct uart_driver sci_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "sci", - .dev_name = "ttySC", - .major = SCI_MAJOR, - .minor = SCI_MINOR_START, - .nr = SCI_NPORTS, - .cons = SCI_CONSOLE, -}; - - -static int sci_remove(struct platform_device *dev) -{ - struct sh_sci_priv *priv = platform_get_drvdata(dev); - struct sci_port *p; - unsigned long flags; - - cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); - - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(p, &priv->ports, node) { - uart_remove_one_port(&sci_uart_driver, &p->port); - clk_put(p->iclk); - clk_put(p->fclk); - } - spin_unlock_irqrestore(&priv->lock, flags); - - kfree(priv); - return 0; -} - -static int __devinit sci_probe_single(struct platform_device *dev, - unsigned int index, - struct plat_sci_port *p, - struct sci_port *sciport) -{ - struct sh_sci_priv *priv = platform_get_drvdata(dev); - unsigned long flags; - int ret; - - /* Sanity check */ - if (unlikely(index >= SCI_NPORTS)) { - dev_notice(&dev->dev, "Attempting to register port " - "%d when only %d are available.\n", - index+1, SCI_NPORTS); - dev_notice(&dev->dev, "Consider bumping " - "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); - return 0; - } - - ret = sci_init_single(dev, sciport, index, p); - if (ret) - return ret; - - ret = uart_add_one_port(&sci_uart_driver, &sciport->port); - if (ret) - return ret; - - INIT_LIST_HEAD(&sciport->node); - - spin_lock_irqsave(&priv->lock, flags); - list_add(&sciport->node, &priv->ports); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -/* - * Register a set of serial devices attached to a platform device. The - * list is terminated with a zero flags entry, which means we expect - * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need - * remapping (such as sh64) should also set UPF_IOREMAP. - */ -static int __devinit sci_probe(struct platform_device *dev) -{ - struct plat_sci_port *p = dev->dev.platform_data; - struct sh_sci_priv *priv; - int i, ret = -EINVAL; - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE - if (is_early_platform_device(dev)) { - if (dev->id == -1) - return -ENOTSUPP; - early_serial_console.index = dev->id; - early_serial_console.data = &early_serial_port.port; - sci_init_single(NULL, &early_serial_port, dev->id, p); - serial_console_setup(&early_serial_console, early_serial_buf); - if (!strstr(early_serial_buf, "keep")) - early_serial_console.flags |= CON_BOOT; - register_console(&early_serial_console); - return 0; - } -#endif - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - INIT_LIST_HEAD(&priv->ports); - spin_lock_init(&priv->lock); - platform_set_drvdata(dev, priv); - - priv->clk_nb.notifier_call = sci_notifier; - cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); - - if (dev->id != -1) { - ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); - if (ret) - goto err_unreg; - } else { - for (i = 0; p && p->flags != 0; p++, i++) { - ret = sci_probe_single(dev, i, p, &sci_ports[i]); - if (ret) - goto err_unreg; - } - } - -#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) -{ - struct sh_sci_priv *priv = dev_get_drvdata(dev); - struct sci_port *p; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(p, &priv->ports, node) - uart_suspend_port(&sci_uart_driver, &p->port); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static int sci_resume(struct device *dev) -{ - struct sh_sci_priv *priv = dev_get_drvdata(dev); - struct sci_port *p; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(p, &priv->ports, node) - uart_resume_port(&sci_uart_driver, &p->port); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static const struct dev_pm_ops sci_dev_pm_ops = { - .suspend = sci_suspend, - .resume = sci_resume, -}; - -static struct platform_driver sci_driver = { - .probe = sci_probe, - .remove = sci_remove, - .driver = { - .name = "sh-sci", - .owner = THIS_MODULE, - .pm = &sci_dev_pm_ops, - }, -}; - -static int __init sci_init(void) -{ - int ret; - - printk(banner); - - ret = uart_register_driver(&sci_uart_driver); - if (likely(ret == 0)) { - ret = platform_driver_register(&sci_driver); - if (unlikely(ret)) - uart_unregister_driver(&sci_uart_driver); - } - - return ret; -} - -static void __exit sci_exit(void) -{ - platform_driver_unregister(&sci_driver); - uart_unregister_driver(&sci_uart_driver); -} - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -early_platform_init_buffer("earlyprintk", &sci_driver, - early_serial_buf, ARRAY_SIZE(early_serial_buf)); -#endif -module_init(sci_init); -module_exit(sci_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:sh-sci"); diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h deleted file mode 100644 index 4bc614e4221c..000000000000 --- a/drivers/serial/sh-sci.h +++ /dev/null @@ -1,660 +0,0 @@ -#include -#include -#include - -#if defined(CONFIG_H83007) || defined(CONFIG_H83068) -#include -#endif -#if defined(CONFIG_H8S2678) -#include -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7707) || \ - defined(CONFIG_CPU_SUBTYPE_SH7708) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) -# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ -# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) -# define SCIF0 0xA4400000 -# define SCIF2 0xA4410000 -# define SCSMR_Ir 0xA44A0000 -# define IRDA_SCIF SCIF0 -# define SCPCR 0xA4000116 -# define SCPDR 0xA4000136 - -/* Set the clock source, - * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input - * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output - */ -# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) || \ - defined(CONFIG_ARCH_SH7372) -# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define PORT_PTCR 0xA405011EUL -# define PORT_PVCR 0xA4050122UL -# define SCIF_ORER 0x0200 /* overrun error bit */ -#elif defined(CONFIG_SH_RTS7751R2D) -# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */ -# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ - defined(CONFIG_CPU_SUBTYPE_SH7091) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751R) -# define SCSPTR1 0xffe0001c /* 8 bit SCI */ -# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ - 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ - 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) -# define SCSPTR0 0xfe600024 /* 16 bit SCIF */ -# define SCSPTR1 0xfe610024 /* 16 bit SCIF */ -# define SCSPTR2 0xfe620024 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) -# define SCSPTR0 0xA4400000 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define PACR 0xa4050100 -# define PBCR 0xa4050102 -# define SCSCR_INIT(port) 0x3B -#elif defined(CONFIG_CPU_SUBTYPE_SH7343) -# define SCSPTR0 0xffe00010 /* 16 bit SCIF */ -# define SCSPTR1 0xffe10010 /* 16 bit SCIF */ -# define SCSPTR2 0xffe20010 /* 16 bit SCIF */ -# define SCSPTR3 0xffe30010 /* 16 bit SCIF */ -# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7722) -# define PADR 0xA4050120 -# define PSDR 0xA405013e -# define PWDR 0xA4050166 -# define PSCR 0xA405011E -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7366) -# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */ -# define SCSPTR0 SCPDR0 -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) -# define SCSPTR0 0xa4050160 -# define SCSPTR1 0xa405013e -# define SCSPTR2 0xa4050160 -# define SCSPTR3 0xa405013e -# define SCSPTR4 0xa4050128 -# define SCSPTR5 0xa4050128 -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7724) -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \ - 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ - 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) -#elif defined(CONFIG_CPU_SUBTYPE_SH4_202) -# define SCSPTR2 0xffe80020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) -# define SCIF_BASE_ADDR 0x01030000 -# define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR -# define SCIF_PTR2_OFFS 0x0000020 -# define SCIF_LSR2_OFFS 0x0000024 -# define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */ -# define SCLSR2 ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) -#elif defined(CONFIG_H8S2678) -# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ -# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) -#elif defined(CONFIG_CPU_SUBTYPE_SH7757) -# define SCSPTR0 0xfe4b0020 -# define SCSPTR1 0xfe4b0020 -# define SCSPTR2 0xfe4b0020 -# define SCIF_ORER 0x0001 -# define SCSCR_INIT(port) 0x38 -# define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7763) -# define SCSPTR0 0xffe00024 /* 16 bit SCIF */ -# define SCSPTR1 0xffe08024 /* 16 bit SCIF */ -# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7770) -# define SCSPTR0 0xff923020 /* 16 bit SCIF */ -# define SCSPTR1 0xff924020 /* 16 bit SCIF */ -# define SCSPTR2 0xff925020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) -# define SCSPTR0 0xffe00024 /* 16 bit SCIF */ -# define SCSPTR1 0xffe10024 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* Overrun error bit */ - -#if defined(CONFIG_SH_SH2007) -/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */ -# define SCSCR_INIT(port) 0x38 -#else -/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */ -# define SCSCR_INIT(port) 0x3a -#endif - -#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) -# define SCSPTR0 0xffea0024 /* 16 bit SCIF */ -# define SCSPTR1 0xffeb0024 /* 16 bit SCIF */ -# define SCSPTR2 0xffec0024 /* 16 bit SCIF */ -# define SCSPTR3 0xffed0024 /* 16 bit SCIF */ -# define SCSPTR4 0xffee0024 /* 16 bit SCIF */ -# define SCSPTR5 0xffef0024 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* Overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ - defined(CONFIG_CPU_SUBTYPE_SH7203) || \ - defined(CONFIG_CPU_SUBTYPE_SH7206) || \ - defined(CONFIG_CPU_SUBTYPE_SH7263) -# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ -# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ -# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ -# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */ -# if defined(CONFIG_CPU_SUBTYPE_SH7201) -# define SCSPTR4 0xfffeA020 /* 16 bit SCIF */ -# define SCSPTR5 0xfffeA820 /* 16 bit SCIF */ -# define SCSPTR6 0xfffeB020 /* 16 bit SCIF */ -# define SCSPTR7 0xfffeB820 /* 16 bit SCIF */ -# endif -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7619) -# define SCSPTR0 0xf8400020 /* 16 bit SCIF */ -# define SCSPTR1 0xf8410020 /* 16 bit SCIF */ -# define SCSPTR2 0xf8420020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#elif defined(CONFIG_CPU_SUBTYPE_SHX3) -# define SCSPTR0 0xffc30020 /* 16 bit SCIF */ -# define SCSPTR1 0xffc40020 /* 16 bit SCIF */ -# define SCSPTR2 0xffc50020 /* 16 bit SCIF */ -# define SCSPTR3 0xffc60020 /* 16 bit SCIF */ -# define SCIF_ORER 0x0001 /* Overrun error bit */ -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#else -# error CPU subtype not defined -#endif - -/* SCSCR */ -#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ -#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ -#define SCI_CTRL_FLAGS_TE 0x20 /* all */ -#define SCI_CTRL_FLAGS_RE 0x10 /* all */ -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \ - defined(CONFIG_CPU_SUBTYPE_SH7091) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7722) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) || \ - defined(CONFIG_CPU_SUBTYPE_SHX3) -#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7724) -#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8) -#else -#define SCI_CTRL_FLAGS_REIE 0 -#endif -/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ -/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ - -/* SCxSR SCI */ -#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ -/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ - -#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) - -/* SCxSR SCIF */ -#define SCIF_ER 0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_TEND 0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_TDFE 0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_BRK 0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_FER 0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_PER 0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ -#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ - -#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) || \ - defined(CONFIG_ARCH_SH7372) -# define SCIF_ORER 0x0200 -# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) -# define SCIF_RFDC_MASK 0x007f -# define SCIF_TXROOM_MAX 64 -#elif defined(CONFIG_CPU_SUBTYPE_SH7763) -# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK ) -# define SCIF_RFDC_MASK 0x007f -# define SCIF_TXROOM_MAX 64 -/* SH7763 SCIF2 support */ -# define SCIF2_RFDC_MASK 0x001f -# define SCIF2_TXROOM_MAX 16 -#else -# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) -# define SCIF_RFDC_MASK 0x001f -# define SCIF_TXROOM_MAX 16 -#endif - -#ifndef SCIF_ORER -#define SCIF_ORER 0x0000 -#endif - -#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) -#define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) -#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) -#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) -#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) -#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) -#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) -#define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER) - -#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) || \ - defined(CONFIG_ARCH_SH7372) -# define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc) -# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73) -# define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf) -# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3) -#else -# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) -# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) -# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) -#endif - -/* SCFCR */ -#define SCFCR_RFRST 0x0002 -#define SCFCR_TFRST 0x0004 -#define SCFCR_TCRST 0x4000 -#define SCFCR_MCE 0x0008 - -#define SCI_MAJOR 204 -#define SCI_MINOR_START 8 - -/* Generic serial flags */ -#define SCI_RX_THROTTLE 0x0000001 - -#define SCI_MAGIC 0xbabeface - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define SCI_EVENT_WRITE_WAKEUP 0 - -#define SCI_IN(size, offset) \ - if ((size) == 8) { \ - return ioread8(port->membase + (offset)); \ - } else { \ - return ioread16(port->membase + (offset)); \ - } -#define SCI_OUT(size, offset, value) \ - if ((size) == 8) { \ - iowrite8(value, port->membase + (offset)); \ - } else if ((size) == 16) { \ - iowrite16(value, port->membase + (offset)); \ - } - -#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ - static inline unsigned int sci_##name##_in(struct uart_port *port) \ - { \ - if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ - SCI_IN(scif_size, scif_offset) \ - } else { /* PORT_SCI or PORT_SCIFA */ \ - SCI_IN(sci_size, sci_offset); \ - } \ - } \ - static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ - { \ - if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ - SCI_OUT(scif_size, scif_offset, value) \ - } else { /* PORT_SCI or PORT_SCIFA */ \ - SCI_OUT(sci_size, sci_offset, value); \ - } \ - } - -#ifdef CONFIG_H8300 -/* h8300 don't have SCIF */ -#define CPU_SCIF_FNS(name) \ - static inline unsigned int sci_##name##_in(struct uart_port *port) \ - { \ - return 0; \ - } \ - static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ - { \ - } -#else -#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ - static inline unsigned int sci_##name##_in(struct uart_port *port) \ - { \ - SCI_IN(scif_size, scif_offset); \ - } \ - static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ - { \ - SCI_OUT(scif_size, scif_offset, value); \ - } -#endif - -#define CPU_SCI_FNS(name, sci_offset, sci_size) \ - static inline unsigned int sci_##name##_in(struct uart_port* port) \ - { \ - SCI_IN(sci_size, sci_offset); \ - } \ - static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \ - { \ - SCI_OUT(sci_size, sci_offset, value); \ - } - -#if defined(CONFIG_CPU_SH3) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) || \ - defined(CONFIG_ARCH_SH7372) -#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) -#define SCIF_FNS(name, scif_offset, scif_size) \ - CPU_SCIF_FNS(name, scif_offset, scif_size) -#elif defined(CONFIG_ARCH_SH7372) -#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \ - CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) -#define SCIF_FNS(name, scif_offset, scif_size) \ - CPU_SCIF_FNS(name, scif_offset, scif_size) -#else -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) -#endif -#elif defined(__H8300H__) || defined(__H8300S__) -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ - defined(CONFIG_CPU_SUBTYPE_SH7724) - #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) - #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) -#else -#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ - sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ - h8_sci_offset, h8_sci_size) \ - CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) -#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ - CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) - -SCIF_FNS(SCSMR, 0x00, 16) -SCIF_FNS(SCBRR, 0x04, 8) -SCIF_FNS(SCSCR, 0x08, 16) -SCIF_FNS(SCTDSR, 0x0c, 8) -SCIF_FNS(SCFER, 0x10, 16) -SCIF_FNS(SCxSR, 0x14, 16) -SCIF_FNS(SCFCR, 0x18, 16) -SCIF_FNS(SCFDR, 0x1c, 16) -SCIF_FNS(SCxTDR, 0x20, 8) -SCIF_FNS(SCxRDR, 0x24, 8) -SCIF_FNS(SCLSR, 0x00, 0) -#elif defined(CONFIG_ARCH_SH7372) -SCIF_FNS(SCSMR, 0x00, 16) -SCIF_FNS(SCBRR, 0x04, 8) -SCIF_FNS(SCSCR, 0x08, 16) -SCIF_FNS(SCTDSR, 0x0c, 16) -SCIF_FNS(SCFER, 0x10, 16) -SCIF_FNS(SCxSR, 0x14, 16) -SCIF_FNS(SCFCR, 0x18, 16) -SCIF_FNS(SCFDR, 0x1c, 16) -SCIF_FNS(SCTFDR, 0x38, 16) -SCIF_FNS(SCRFDR, 0x3c, 16) -SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8) -SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8) -SCIF_FNS(SCLSR, 0x00, 0) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ - defined(CONFIG_CPU_SUBTYPE_SH7724) -SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) -SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) -SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) -SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8) -SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16) -SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8) -SCIx_FNS(SCSPTR, 0, 0, 0, 0) -SCIF_FNS(SCTDSR, 0x0c, 8) -SCIF_FNS(SCFER, 0x10, 16) -SCIF_FNS(SCFCR, 0x18, 16) -SCIF_FNS(SCFDR, 0x1c, 16) -SCIF_FNS(SCLSR, 0x24, 16) -#else -/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ -/* name off sz off sz off sz off sz off sz*/ -SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8) -SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8) -SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8) -SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8) -SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) -SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) -SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786) -SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) -SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) -SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) -SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) -SCIF_FNS(SCLSR, 0, 0, 0x28, 16) -#elif defined(CONFIG_CPU_SUBTYPE_SH7763) -SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) -SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) -SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) -SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) -SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) -SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) -SCIF_FNS(SCLSR, 0, 0, 0x28, 16) -#else -SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) -#if defined(CONFIG_CPU_SUBTYPE_SH7722) -SCIF_FNS(SCSPTR, 0, 0, 0, 0) -#else -SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) -#endif -SCIF_FNS(SCLSR, 0, 0, 0x24, 16) -#endif -#endif -#define sci_in(port, reg) sci_##reg##_in(port) -#define sci_out(port, reg, value) sci_##reg##_out(port, value) - -/* H8/300 series SCI pins assignment */ -#if defined(__H8300H__) || defined(__H8300S__) -static const struct __attribute__((packed)) { - int port; /* GPIO port no */ - unsigned short rx,tx; /* GPIO bit no */ -} h8300_sci_pins[] = { -#if defined(CONFIG_H83007) || defined(CONFIG_H83068) - { /* SCI0 */ - .port = H8300_GPIO_P9, - .rx = H8300_GPIO_B2, - .tx = H8300_GPIO_B0, - }, - { /* SCI1 */ - .port = H8300_GPIO_P9, - .rx = H8300_GPIO_B3, - .tx = H8300_GPIO_B1, - }, - { /* SCI2 */ - .port = H8300_GPIO_PB, - .rx = H8300_GPIO_B7, - .tx = H8300_GPIO_B6, - } -#elif defined(CONFIG_H8S2678) - { /* SCI0 */ - .port = H8300_GPIO_P3, - .rx = H8300_GPIO_B2, - .tx = H8300_GPIO_B0, - }, - { /* SCI1 */ - .port = H8300_GPIO_P3, - .rx = H8300_GPIO_B3, - .tx = H8300_GPIO_B1, - }, - { /* SCI2 */ - .port = H8300_GPIO_P5, - .rx = H8300_GPIO_B1, - .tx = H8300_GPIO_B0, - } -#endif -}; -#endif - -#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ - defined(CONFIG_CPU_SUBTYPE_SH7707) || \ - defined(CONFIG_CPU_SUBTYPE_SH7708) || \ - defined(CONFIG_CPU_SUBTYPE_SH7709) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xfffffe80) - return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */ - return 1; -} -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ - defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ - defined(CONFIG_CPU_SUBTYPE_SH7091) -static inline int sci_rxd_in(struct uart_port *port) -{ - if (port->mapbase == 0xffe00000) - return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ - return 1; -} -#elif defined(__H8300H__) || defined(__H8300S__) -static inline int sci_rxd_in(struct uart_port *port) -{ - int ch = (port->mapbase - SMR0) >> 3; - return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; -} -#else /* default case for non-SCI processors */ -static inline int sci_rxd_in(struct uart_port *port) -{ - return 1; -} -#endif - -/* - * Values for the BitRate Register (SCBRR) - * - * The values are actually divisors for a frequency which can - * be internal to the SH3 (14.7456MHz) or derived from an external - * clock source. This driver assumes the internal clock is used; - * to support using an external clock source, config options or - * possibly command-line options would need to be added. - * - * Also, to support speeds below 2400 (why?) the lower 2 bits of - * the SCSMR register would also need to be set to non-zero values. - * - * -- Greg Banks 27Feb2000 - * - * Answer: The SCBRR register is only eight bits, and the value in - * it gets larger with lower baud rates. At around 2400 (depending on - * the peripherial module clock) you run out of bits. However the - * lower two bits of SCSMR allow the module clock to be divided down, - * scaling the value which is needed in SCBRR. - * - * -- Stuart Menefy - 23 May 2000 - * - * I meant, why would anyone bother with bitrates below 2400. - * - * -- Greg Banks - 7Jul2000 - * - * You "speedist"! How will I use my 110bps ASR-33 teletype with paper - * tape reader as a console! - * - * -- Mitch Davis - 15 Jul 2000 - */ - -#if (defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) || \ - defined(CONFIG_CPU_SUBTYPE_SH7786)) && \ - !defined(CONFIG_SH_SH2007) -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7367) || \ - defined(CONFIG_ARCH_SH7377) || \ - defined(CONFIG_ARCH_SH7372) -#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ - defined(CONFIG_CPU_SUBTYPE_SH7724) -static inline int scbrr_calc(struct uart_port *port, int bps, int clk) -{ - if (port->type == PORT_SCIF) - return (clk+16*bps)/(32*bps)-1; - else - return ((clk*2)+16*bps)/(16*bps)-1; -} -#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk) -#elif defined(__H8300H__) || defined(__H8300S__) -#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1) -#else /* Generic SH */ -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) -#endif diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c deleted file mode 100644 index cff9a306660f..000000000000 --- a/drivers/serial/sn_console.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * C-Brick Serial Port (and console) driver for SGI Altix machines. - * - * This driver is NOT suitable for talking to the l1-controller for - * anything other than 'console activities' --- please use the l1 - * driver for that. - * - * - * Copyright (c) 2004-2006 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for mdelay */ -#include -#include - -#include -#include -#include - -/* number of characters we can transmit to the SAL console at a time */ -#define SN_SAL_MAX_CHARS 120 - -/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to - * avoid losing chars, (always has to be a power of 2) */ -#define SN_SAL_BUFFER_SIZE (64 * (1 << 10)) - -#define SN_SAL_UART_FIFO_DEPTH 16 -#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10) - -/* sn_transmit_chars() calling args */ -#define TRANSMIT_BUFFERED 0 -#define TRANSMIT_RAW 1 - -/* To use dynamic numbers only and not use the assigned major and minor, - * define the following.. */ - /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */ -#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */ - -/* Device name we're using */ -#define DEVICE_NAME "ttySG" -#define DEVICE_NAME_DYNAMIC "ttySG0" /* need full name for misc_register */ -/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */ -#define DEVICE_MAJOR 204 -#define DEVICE_MINOR 40 - -#ifdef CONFIG_MAGIC_SYSRQ -static char sysrq_serial_str[] = "\eSYS"; -static char *sysrq_serial_ptr = sysrq_serial_str; -static unsigned long sysrq_requested; -#endif /* CONFIG_MAGIC_SYSRQ */ - -/* - * Port definition - this kinda drives it all - */ -struct sn_cons_port { - struct timer_list sc_timer; - struct uart_port sc_port; - struct sn_sal_ops { - int (*sal_puts_raw) (const char *s, int len); - int (*sal_puts) (const char *s, int len); - int (*sal_getc) (void); - int (*sal_input_pending) (void); - void (*sal_wakeup_transmit) (struct sn_cons_port *, int); - } *sc_ops; - unsigned long sc_interrupt_timeout; - int sc_is_asynch; -}; - -static struct sn_cons_port sal_console_port; -static int sn_process_input; - -/* Only used if USE_DYNAMIC_MINOR is set to 1 */ -static struct miscdevice misc; /* used with misc_register for dynamic */ - -extern void early_sn_setup(void); - -#undef DEBUG -#ifdef DEBUG -static int sn_debug_printf(const char *fmt, ...); -#define DPRINTF(x...) sn_debug_printf(x) -#else -#define DPRINTF(x...) do { } while (0) -#endif - -/* Prototypes */ -static int snt_hw_puts_raw(const char *, int); -static int snt_hw_puts_buffered(const char *, int); -static int snt_poll_getc(void); -static int snt_poll_input_pending(void); -static int snt_intr_getc(void); -static int snt_intr_input_pending(void); -static void sn_transmit_chars(struct sn_cons_port *, int); - -/* A table for polling: - */ -static struct sn_sal_ops poll_ops = { - .sal_puts_raw = snt_hw_puts_raw, - .sal_puts = snt_hw_puts_raw, - .sal_getc = snt_poll_getc, - .sal_input_pending = snt_poll_input_pending -}; - -/* A table for interrupts enabled */ -static struct sn_sal_ops intr_ops = { - .sal_puts_raw = snt_hw_puts_raw, - .sal_puts = snt_hw_puts_buffered, - .sal_getc = snt_intr_getc, - .sal_input_pending = snt_intr_input_pending, - .sal_wakeup_transmit = sn_transmit_chars -}; - -/* the console does output in two distinctly different ways: - * synchronous (raw) and asynchronous (buffered). initally, early_printk - * does synchronous output. any data written goes directly to the SAL - * to be output (incidentally, it is internally buffered by the SAL) - * after interrupts and timers are initialized and available for use, - * the console init code switches to asynchronous output. this is - * also the earliest opportunity to begin polling for console input. - * after console initialization, console output and tty (serial port) - * output is buffered and sent to the SAL asynchronously (either by - * timer callback or by UART interrupt) */ - -/* routines for running the console in polling mode */ - -/** - * snt_poll_getc - Get a character from the console in polling mode - * - */ -static int snt_poll_getc(void) -{ - int ch; - - ia64_sn_console_getc(&ch); - return ch; -} - -/** - * snt_poll_input_pending - Check if any input is waiting - polling mode. - * - */ -static int snt_poll_input_pending(void) -{ - int status, input; - - status = ia64_sn_console_check(&input); - return !status && input; -} - -/* routines for an interrupt driven console (normal) */ - -/** - * snt_intr_getc - Get a character from the console, interrupt mode - * - */ -static int snt_intr_getc(void) -{ - return ia64_sn_console_readc(); -} - -/** - * snt_intr_input_pending - Check if input is pending, interrupt mode - * - */ -static int snt_intr_input_pending(void) -{ - return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV; -} - -/* these functions are polled and interrupt */ - -/** - * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode - * @s: String - * @len: Length - * - */ -static int snt_hw_puts_raw(const char *s, int len) -{ - /* this will call the PROM and not return until this is done */ - return ia64_sn_console_putb(s, len); -} - -/** - * snt_hw_puts_buffered - Send string to console, polled or interrupt mode - * @s: String - * @len: Length - * - */ -static int snt_hw_puts_buffered(const char *s, int len) -{ - /* queue data to the PROM */ - return ia64_sn_console_xmit_chars((char *)s, len); -} - -/* uart interface structs - * These functions are associated with the uart_port that the serial core - * infrastructure calls. - * - * Note: Due to how the console works, many routines are no-ops. - */ - -/** - * snp_type - What type of console are we? - * @port: Port to operate with (we ignore since we only have one port) - * - */ -static const char *snp_type(struct uart_port *port) -{ - return ("SGI SN L1"); -} - -/** - * snp_tx_empty - Is the transmitter empty? We pretend we're always empty - * @port: Port to operate on (we ignore since we only have one port) - * - */ -static unsigned int snp_tx_empty(struct uart_port *port) -{ - return 1; -} - -/** - * snp_stop_tx - stop the transmitter - no-op for us - * @port: Port to operat eon - we ignore - no-op function - * - */ -static void snp_stop_tx(struct uart_port *port) -{ -} - -/** - * snp_release_port - Free i/o and resources for port - no-op for us - * @port: Port to operate on - we ignore - no-op function - * - */ -static void snp_release_port(struct uart_port *port) -{ -} - -/** - * snp_enable_ms - Force modem status interrupts on - no-op for us - * @port: Port to operate on - we ignore - no-op function - * - */ -static void snp_enable_ms(struct uart_port *port) -{ -} - -/** - * snp_shutdown - shut down the port - free irq and disable - no-op for us - * @port: Port to shut down - we ignore - * - */ -static void snp_shutdown(struct uart_port *port) -{ -} - -/** - * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console - * @port: Port to operate on - we ignore - * @mctrl: Lines to set/unset - we ignore - * - */ -static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -/** - * snp_get_mctrl - get contorl line info, we just return a static value - * @port: port to operate on - we only have one port so we ignore this - * - */ -static unsigned int snp_get_mctrl(struct uart_port *port) -{ - return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS; -} - -/** - * snp_stop_rx - Stop the receiver - we ignor ethis - * @port: Port to operate on - we ignore - * - */ -static void snp_stop_rx(struct uart_port *port) -{ -} - -/** - * snp_start_tx - Start transmitter - * @port: Port to operate on - * - */ -static void snp_start_tx(struct uart_port *port) -{ - if (sal_console_port.sc_ops->sal_wakeup_transmit) - sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port, - TRANSMIT_BUFFERED); - -} - -/** - * snp_break_ctl - handle breaks - ignored by us - * @port: Port to operate on - * @break_state: Break state - * - */ -static void snp_break_ctl(struct uart_port *port, int break_state) -{ -} - -/** - * snp_startup - Start up the serial port - always return 0 (We're always on) - * @port: Port to operate on - * - */ -static int snp_startup(struct uart_port *port) -{ - return 0; -} - -/** - * snp_set_termios - set termios stuff - we ignore these - * @port: port to operate on - * @termios: New settings - * @termios: Old - * - */ -static void -snp_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ -} - -/** - * snp_request_port - allocate resources for port - ignored by us - * @port: port to operate on - * - */ -static int snp_request_port(struct uart_port *port) -{ - return 0; -} - -/** - * snp_config_port - allocate resources, set up - we ignore, we're always on - * @port: Port to operate on - * @flags: flags used for port setup - * - */ -static void snp_config_port(struct uart_port *port, int flags) -{ -} - -/* Associate the uart functions above - given to serial core */ - -static struct uart_ops sn_console_ops = { - .tx_empty = snp_tx_empty, - .set_mctrl = snp_set_mctrl, - .get_mctrl = snp_get_mctrl, - .stop_tx = snp_stop_tx, - .start_tx = snp_start_tx, - .stop_rx = snp_stop_rx, - .enable_ms = snp_enable_ms, - .break_ctl = snp_break_ctl, - .startup = snp_startup, - .shutdown = snp_shutdown, - .set_termios = snp_set_termios, - .pm = NULL, - .type = snp_type, - .release_port = snp_release_port, - .request_port = snp_request_port, - .config_port = snp_config_port, - .verify_port = NULL, -}; - -/* End of uart struct functions and defines */ - -#ifdef DEBUG - -/** - * sn_debug_printf - close to hardware debugging printf - * @fmt: printf format - * - * This is as "close to the metal" as we can get, used when the driver - * itself may be broken. - * - */ -static int sn_debug_printf(const char *fmt, ...) -{ - static char printk_buf[1024]; - int printed_len; - va_list args; - - va_start(args, fmt); - printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); - - if (!sal_console_port.sc_ops) { - sal_console_port.sc_ops = &poll_ops; - early_sn_setup(); - } - sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len); - - va_end(args); - return printed_len; -} -#endif /* DEBUG */ - -/* - * Interrupt handling routines. - */ - -/** - * sn_receive_chars - Grab characters, pass them to tty layer - * @port: Port to operate on - * @flags: irq flags - * - * Note: If we're not registered with the serial core infrastructure yet, - * we don't try to send characters to it... - * - */ -static void -sn_receive_chars(struct sn_cons_port *port, unsigned long flags) -{ - int ch; - struct tty_struct *tty; - - if (!port) { - printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n"); - return; - } - - if (!port->sc_ops) { - printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receieve\n"); - return; - } - - if (port->sc_port.state) { - /* The serial_core stuffs are initialized, use them */ - tty = port->sc_port.state->port.tty; - } - else { - /* Not registered yet - can't pass to tty layer. */ - tty = NULL; - } - - while (port->sc_ops->sal_input_pending()) { - ch = port->sc_ops->sal_getc(); - if (ch < 0) { - printk(KERN_ERR "sn_console: An error occured while " - "obtaining data from the console (0x%0x)\n", ch); - break; - } -#ifdef CONFIG_MAGIC_SYSRQ - if (sysrq_requested) { - unsigned long sysrq_timeout = sysrq_requested + HZ*5; - - sysrq_requested = 0; - if (ch && time_before(jiffies, sysrq_timeout)) { - spin_unlock_irqrestore(&port->sc_port.lock, flags); - handle_sysrq(ch); - spin_lock_irqsave(&port->sc_port.lock, flags); - /* ignore actual sysrq command char */ - continue; - } - } - if (ch == *sysrq_serial_ptr) { - if (!(*++sysrq_serial_ptr)) { - sysrq_requested = jiffies; - sysrq_serial_ptr = sysrq_serial_str; - } - /* - * ignore the whole sysrq string except for the - * leading escape - */ - if (ch != '\e') - continue; - } - else - sysrq_serial_ptr = sysrq_serial_str; -#endif /* CONFIG_MAGIC_SYSRQ */ - - /* record the character to pass up to the tty layer */ - if (tty) { - if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0) - break; - } - port->sc_port.icount.rx++; - } - - if (tty) - tty_flip_buffer_push(tty); -} - -/** - * sn_transmit_chars - grab characters from serial core, send off - * @port: Port to operate on - * @raw: Transmit raw or buffered - * - * Note: If we're early, before we're registered with serial core, the - * writes are going through sn_sal_console_write because that's how - * register_console has been set up. We currently could have asynch - * polls calling this function due to sn_sal_switch_to_asynch but we can - * ignore them until we register with the serial core stuffs. - * - */ -static void sn_transmit_chars(struct sn_cons_port *port, int raw) -{ - int xmit_count, tail, head, loops, ii; - int result; - char *start; - struct circ_buf *xmit; - - if (!port) - return; - - BUG_ON(!port->sc_is_asynch); - - if (port->sc_port.state) { - /* We're initialized, using serial core infrastructure */ - xmit = &port->sc_port.state->xmit; - } else { - /* Probably sn_sal_switch_to_asynch has been run but serial core isn't - * initialized yet. Just return. Writes are going through - * sn_sal_console_write (due to register_console) at this time. - */ - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) { - /* Nothing to do. */ - ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT); - return; - } - - head = xmit->head; - tail = xmit->tail; - start = &xmit->buf[tail]; - - /* twice around gets the tail to the end of the buffer and - * then to the head, if needed */ - loops = (head < tail) ? 2 : 1; - - for (ii = 0; ii < loops; ii++) { - xmit_count = (head < tail) ? - (UART_XMIT_SIZE - tail) : (head - tail); - - if (xmit_count > 0) { - if (raw == TRANSMIT_RAW) - result = - port->sc_ops->sal_puts_raw(start, - xmit_count); - else - result = - port->sc_ops->sal_puts(start, xmit_count); -#ifdef DEBUG - if (!result) - DPRINTF("`"); -#endif - if (result > 0) { - xmit_count -= result; - port->sc_port.icount.tx += result; - tail += result; - tail &= UART_XMIT_SIZE - 1; - xmit->tail = tail; - start = &xmit->buf[tail]; - } - } - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&port->sc_port); - - if (uart_circ_empty(xmit)) - snp_stop_tx(&port->sc_port); /* no-op for us */ -} - -/** - * sn_sal_interrupt - Handle console interrupts - * @irq: irq #, useful for debug statements - * @dev_id: our pointer to our port (sn_cons_port which contains the uart port) - * - */ -static irqreturn_t sn_sal_interrupt(int irq, void *dev_id) -{ - struct sn_cons_port *port = (struct sn_cons_port *)dev_id; - unsigned long flags; - int status = ia64_sn_console_intr_status(); - - if (!port) - return IRQ_NONE; - - spin_lock_irqsave(&port->sc_port.lock, flags); - if (status & SAL_CONSOLE_INTR_RECV) { - sn_receive_chars(port, flags); - } - if (status & SAL_CONSOLE_INTR_XMIT) { - sn_transmit_chars(port, TRANSMIT_BUFFERED); - } - spin_unlock_irqrestore(&port->sc_port.lock, flags); - return IRQ_HANDLED; -} - -/** - * sn_sal_timer_poll - this function handles polled console mode - * @data: A pointer to our sn_cons_port (which contains the uart port) - * - * data is the pointer that init_timer will store for us. This function is - * associated with init_timer to see if there is any console traffic. - * Obviously not used in interrupt mode - * - */ -static void sn_sal_timer_poll(unsigned long data) -{ - struct sn_cons_port *port = (struct sn_cons_port *)data; - unsigned long flags; - - if (!port) - return; - - if (!port->sc_port.irq) { - spin_lock_irqsave(&port->sc_port.lock, flags); - if (sn_process_input) - sn_receive_chars(port, flags); - sn_transmit_chars(port, TRANSMIT_RAW); - spin_unlock_irqrestore(&port->sc_port.lock, flags); - mod_timer(&port->sc_timer, - jiffies + port->sc_interrupt_timeout); - } -} - -/* - * Boot-time initialization code - */ - -/** - * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch) - * @port: Our sn_cons_port (which contains the uart port) - * - * So this is used by sn_sal_serial_console_init (early on, before we're - * registered with serial core). It's also used by sn_sal_module_init - * right after we've registered with serial core. The later only happens - * if we didn't already come through here via sn_sal_serial_console_init. - * - */ -static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port) -{ - unsigned long flags; - - if (!port) - return; - - DPRINTF("sn_console: about to switch to asynchronous console\n"); - - /* without early_printk, we may be invoked late enough to race - * with other cpus doing console IO at this point, however - * console interrupts will never be enabled */ - spin_lock_irqsave(&port->sc_port.lock, flags); - - /* early_printk invocation may have done this for us */ - if (!port->sc_ops) - port->sc_ops = &poll_ops; - - /* we can't turn on the console interrupt (as request_irq - * calls kmalloc, which isn't set up yet), so we rely on a - * timer to poll for input and push data from the console - * buffer. - */ - init_timer(&port->sc_timer); - port->sc_timer.function = sn_sal_timer_poll; - port->sc_timer.data = (unsigned long)port; - - if (IS_RUNNING_ON_SIMULATOR()) - port->sc_interrupt_timeout = 6; - else { - /* 960cps / 16 char FIFO = 60HZ - * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */ - port->sc_interrupt_timeout = - HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS; - } - mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout); - - port->sc_is_asynch = 1; - spin_unlock_irqrestore(&port->sc_port.lock, flags); -} - -/** - * sn_sal_switch_to_interrupts - Switch to interrupt driven mode - * @port: Our sn_cons_port (which contains the uart port) - * - * In sn_sal_module_init, after we're registered with serial core and - * the port is added, this function is called to switch us to interrupt - * mode. We were previously in asynch/polling mode (using init_timer). - * - * We attempt to switch to interrupt mode here by calling - * request_irq. If that works out, we enable receive interrupts. - */ -static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port) -{ - unsigned long flags; - - if (port) { - DPRINTF("sn_console: switching to interrupt driven console\n"); - - if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, - IRQF_DISABLED | IRQF_SHARED, - "SAL console driver", port) >= 0) { - spin_lock_irqsave(&port->sc_port.lock, flags); - port->sc_port.irq = SGI_UART_VECTOR; - port->sc_ops = &intr_ops; - - /* turn on receive interrupts */ - ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); - spin_unlock_irqrestore(&port->sc_port.lock, flags); - } - else { - printk(KERN_INFO - "sn_console: console proceeding in polled mode\n"); - } - } -} - -/* - * Kernel console definitions - */ - -static void sn_sal_console_write(struct console *, const char *, unsigned); -static int sn_sal_console_setup(struct console *, char *); -static struct uart_driver sal_console_uart; -extern struct tty_driver *uart_console_device(struct console *, int *); - -static struct console sal_console = { - .name = DEVICE_NAME, - .write = sn_sal_console_write, - .device = uart_console_device, - .setup = sn_sal_console_setup, - .index = -1, /* unspecified */ - .data = &sal_console_uart, -}; - -#define SAL_CONSOLE &sal_console - -static struct uart_driver sal_console_uart = { - .owner = THIS_MODULE, - .driver_name = "sn_console", - .dev_name = DEVICE_NAME, - .major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */ - .minor = 0, - .nr = 1, /* one port */ - .cons = SAL_CONSOLE, -}; - -/** - * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core - * - * Before this is called, we've been printing kernel messages in a special - * early mode not making use of the serial core infrastructure. When our - * driver is loaded for real, we register the driver and port with serial - * core and try to enable interrupt driven mode. - * - */ -static int __init sn_sal_module_init(void) -{ - int retval; - - if (!ia64_platform_is("sn2")) - return 0; - - printk(KERN_INFO "sn_console: Console driver init\n"); - - if (USE_DYNAMIC_MINOR == 1) { - misc.minor = MISC_DYNAMIC_MINOR; - misc.name = DEVICE_NAME_DYNAMIC; - retval = misc_register(&misc); - if (retval != 0) { - printk(KERN_WARNING "Failed to register console " - "device using misc_register.\n"); - return -ENODEV; - } - sal_console_uart.major = MISC_MAJOR; - sal_console_uart.minor = misc.minor; - } else { - sal_console_uart.major = DEVICE_MAJOR; - sal_console_uart.minor = DEVICE_MINOR; - } - - /* We register the driver and the port before switching to interrupts - * or async above so the proper uart structures are populated */ - - if (uart_register_driver(&sal_console_uart) < 0) { - printk - ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n", - __LINE__); - return -ENODEV; - } - - spin_lock_init(&sal_console_port.sc_port.lock); - - /* Setup the port struct with the minimum needed */ - sal_console_port.sc_port.membase = (char *)1; /* just needs to be non-zero */ - sal_console_port.sc_port.type = PORT_16550A; - sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS; - sal_console_port.sc_port.ops = &sn_console_ops; - sal_console_port.sc_port.line = 0; - - if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) { - /* error - not sure what I'd do - so I'll do nothing */ - printk(KERN_ERR "%s: unable to add port\n", __func__); - } - - /* when this driver is compiled in, the console initialization - * will have already switched us into asynchronous operation - * before we get here through the module initcalls */ - if (!sal_console_port.sc_is_asynch) { - sn_sal_switch_to_asynch(&sal_console_port); - } - - /* at this point (module_init) we can try to turn on interrupts */ - if (!IS_RUNNING_ON_SIMULATOR()) { - sn_sal_switch_to_interrupts(&sal_console_port); - } - sn_process_input = 1; - return 0; -} - -/** - * sn_sal_module_exit - When we're unloaded, remove the driver/port - * - */ -static void __exit sn_sal_module_exit(void) -{ - del_timer_sync(&sal_console_port.sc_timer); - uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port); - uart_unregister_driver(&sal_console_uart); - misc_deregister(&misc); -} - -module_init(sn_sal_module_init); -module_exit(sn_sal_module_exit); - -/** - * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required - * @puts_raw : puts function to do the writing - * @s: input string - * @count: length - * - * We need a \r ahead of every \n for direct writes through - * ia64_sn_console_putb (what sal_puts_raw below actually does). - * - */ - -static void puts_raw_fixed(int (*puts_raw) (const char *s, int len), - const char *s, int count) -{ - const char *s1; - - /* Output '\r' before each '\n' */ - while ((s1 = memchr(s, '\n', count)) != NULL) { - puts_raw(s, s1 - s); - puts_raw("\r\n", 2); - count -= s1 + 1 - s; - s = s1 + 1; - } - puts_raw(s, count); -} - -/** - * sn_sal_console_write - Print statements before serial core available - * @console: Console to operate on - we ignore since we have just one - * @s: String to send - * @count: length - * - * This is referenced in the console struct. It is used for early - * console printing before we register with serial core and for things - * such as kdb. The console_lock must be held when we get here. - * - * This function has some code for trying to print output even if the lock - * is held. We try to cover the case where a lock holder could have died. - * We don't use this special case code if we're not registered with serial - * core yet. After we're registered with serial core, the only time this - * function would be used is for high level kernel output like magic sys req, - * kdb, and printk's. - */ -static void -sn_sal_console_write(struct console *co, const char *s, unsigned count) -{ - unsigned long flags = 0; - struct sn_cons_port *port = &sal_console_port; - static int stole_lock = 0; - - BUG_ON(!port->sc_is_asynch); - - /* We can't look at the xmit buffer if we're not registered with serial core - * yet. So only do the fancy recovery after registering - */ - if (!port->sc_port.state) { - /* Not yet registered with serial core - simple case */ - puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); - return; - } - - /* somebody really wants this output, might be an - * oops, kdb, panic, etc. make sure they get it. */ - if (spin_is_locked(&port->sc_port.lock)) { - int lhead = port->sc_port.state->xmit.head; - int ltail = port->sc_port.state->xmit.tail; - int counter, got_lock = 0; - - /* - * We attempt to determine if someone has died with the - * lock. We wait ~20 secs after the head and tail ptrs - * stop moving and assume the lock holder is not functional - * and plow ahead. If the lock is freed within the time out - * period we re-get the lock and go ahead normally. We also - * remember if we have plowed ahead so that we don't have - * to wait out the time out period again - the asumption - * is that we will time out again. - */ - - for (counter = 0; counter < 150; mdelay(125), counter++) { - if (!spin_is_locked(&port->sc_port.lock) - || stole_lock) { - if (!stole_lock) { - spin_lock_irqsave(&port->sc_port.lock, - flags); - got_lock = 1; - } - break; - } else { - /* still locked */ - if ((lhead != port->sc_port.state->xmit.head) - || (ltail != - port->sc_port.state->xmit.tail)) { - lhead = - port->sc_port.state->xmit.head; - ltail = - port->sc_port.state->xmit.tail; - counter = 0; - } - } - } - /* flush anything in the serial core xmit buffer, raw */ - sn_transmit_chars(port, 1); - if (got_lock) { - spin_unlock_irqrestore(&port->sc_port.lock, flags); - stole_lock = 0; - } else { - /* fell thru */ - stole_lock = 1; - } - puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); - } else { - stole_lock = 0; - spin_lock_irqsave(&port->sc_port.lock, flags); - sn_transmit_chars(port, 1); - spin_unlock_irqrestore(&port->sc_port.lock, flags); - - puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); - } -} - - -/** - * sn_sal_console_setup - Set up console for early printing - * @co: Console to work with - * @options: Options to set - * - * Altix console doesn't do anything with baud rates, etc, anyway. - * - * This isn't required since not providing the setup function in the - * console struct is ok. However, other patches like KDB plop something - * here so providing it is easier. - * - */ -static int sn_sal_console_setup(struct console *co, char *options) -{ - return 0; -} - -/** - * sn_sal_console_write_early - simple early output routine - * @co - console struct - * @s - string to print - * @count - count - * - * Simple function to provide early output, before even - * sn_sal_serial_console_init is called. Referenced in the - * console struct registerd in sn_serial_console_early_setup. - * - */ -static void __init -sn_sal_console_write_early(struct console *co, const char *s, unsigned count) -{ - puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count); -} - -/* Used for very early console printing - again, before - * sn_sal_serial_console_init is run */ -static struct console sal_console_early __initdata = { - .name = "sn_sal", - .write = sn_sal_console_write_early, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/** - * sn_serial_console_early_setup - Sets up early console output support - * - * Register a console early on... This is for output before even - * sn_sal_serial_cosnole_init is called. This function is called from - * setup.c. This allows us to do really early polled writes. When - * sn_sal_serial_console_init is called, this console is unregistered - * and a new one registered. - */ -int __init sn_serial_console_early_setup(void) -{ - if (!ia64_platform_is("sn2")) - return -1; - - sal_console_port.sc_ops = &poll_ops; - spin_lock_init(&sal_console_port.sc_port.lock); - early_sn_setup(); /* Find SAL entry points */ - register_console(&sal_console_early); - - return 0; -} - -/** - * sn_sal_serial_console_init - Early console output - set up for register - * - * This function is called when regular console init happens. Because we - * support even earlier console output with sn_serial_console_early_setup - * (called from setup.c directly), this function unregisters the really - * early console. - * - * Note: Even if setup.c doesn't register sal_console_early, unregistering - * it here doesn't hurt anything. - * - */ -static int __init sn_sal_serial_console_init(void) -{ - if (ia64_platform_is("sn2")) { - sn_sal_switch_to_asynch(&sal_console_port); - DPRINTF("sn_sal_serial_console_init : register console\n"); - register_console(&sal_console); - unregister_console(&sal_console_early); - } - return 0; -} - -console_initcall(sn_sal_serial_console_init); diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c deleted file mode 100644 index 6381a0282ee7..000000000000 --- a/drivers/serial/suncore.c +++ /dev/null @@ -1,247 +0,0 @@ -/* suncore.c - * - * Common SUN serial routines. Based entirely - * upon drivers/sbus/char/sunserial.c which is: - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * - * Adaptation to new UART layer is: - * - * Copyright (C) 2002 David S. Miller (davem@redhat.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "suncore.h" - -static int sunserial_current_minor = 64; - -int sunserial_register_minors(struct uart_driver *drv, int count) -{ - int err = 0; - - drv->minor = sunserial_current_minor; - drv->nr += count; - /* Register the driver on the first call */ - if (drv->nr == count) - err = uart_register_driver(drv); - if (err == 0) { - sunserial_current_minor += count; - drv->tty_driver->name_base = drv->minor - 64; - } - return err; -} -EXPORT_SYMBOL(sunserial_register_minors); - -void sunserial_unregister_minors(struct uart_driver *drv, int count) -{ - drv->nr -= count; - sunserial_current_minor -= count; - - if (drv->nr == 0) - uart_unregister_driver(drv); -} -EXPORT_SYMBOL(sunserial_unregister_minors); - -int sunserial_console_match(struct console *con, struct device_node *dp, - struct uart_driver *drv, int line, bool ignore_line) -{ - if (!con) - return 0; - - drv->cons = con; - - if (of_console_device != dp) - return 0; - - if (!ignore_line) { - int off = 0; - - if (of_console_options && - *of_console_options == 'b') - off = 1; - - if ((line & 1) != off) - return 0; - } - - if (!console_set_on_cmdline) { - con->index = line; - add_preferred_console(con->name, line, NULL); - } - return 1; -} -EXPORT_SYMBOL(sunserial_console_match); - -void sunserial_console_termios(struct console *con, struct device_node *uart_dp) -{ - const char *mode, *s; - char mode_prop[] = "ttyX-mode"; - int baud, bits, stop, cflag; - char parity; - - if (!strcmp(uart_dp->name, "rsc") || - !strcmp(uart_dp->name, "rsc-console") || - !strcmp(uart_dp->name, "rsc-control")) { - mode = of_get_property(uart_dp, - "ssp-console-modes", NULL); - if (!mode) - mode = "115200,8,n,1,-"; - } else if (!strcmp(uart_dp->name, "lom-console")) { - mode = "9600,8,n,1,-"; - } else { - struct device_node *dp; - char c; - - c = 'a'; - if (of_console_options) - c = *of_console_options; - - mode_prop[3] = c; - - dp = of_find_node_by_path("/options"); - mode = of_get_property(dp, mode_prop, NULL); - if (!mode) - mode = "9600,8,n,1,-"; - } - - cflag = CREAD | HUPCL | CLOCAL; - - s = mode; - baud = simple_strtoul(s, NULL, 0); - s = strchr(s, ','); - bits = simple_strtoul(++s, NULL, 0); - s = strchr(s, ','); - parity = *(++s); - s = strchr(s, ','); - stop = simple_strtoul(++s, NULL, 0); - s = strchr(s, ','); - /* XXX handshake is not handled here. */ - - switch (baud) { - case 150: cflag |= B150; break; - case 300: cflag |= B300; break; - case 600: cflag |= B600; break; - case 1200: cflag |= B1200; break; - case 2400: cflag |= B2400; break; - case 4800: cflag |= B4800; break; - case 9600: cflag |= B9600; break; - case 19200: cflag |= B19200; break; - case 38400: cflag |= B38400; break; - case 57600: cflag |= B57600; break; - case 115200: cflag |= B115200; break; - case 230400: cflag |= B230400; break; - case 460800: cflag |= B460800; break; - default: baud = 9600; cflag |= B9600; break; - } - - switch (bits) { - case 5: cflag |= CS5; break; - case 6: cflag |= CS6; break; - case 7: cflag |= CS7; break; - case 8: cflag |= CS8; break; - default: cflag |= CS8; break; - } - - switch (parity) { - case 'o': cflag |= (PARENB | PARODD); break; - case 'e': cflag |= PARENB; break; - case 'n': default: break; - } - - switch (stop) { - case 2: cflag |= CSTOPB; break; - case 1: default: break; - } - - con->cflag = cflag; -} - -/* Sun serial MOUSE auto baud rate detection. */ -static struct mouse_baud_cflag { - int baud; - unsigned int cflag; -} mouse_baud_table[] = { - { 1200, B1200 }, - { 2400, B2400 }, - { 4800, B4800 }, - { 9600, B9600 }, - { -1, ~0 }, - { -1, ~0 }, -}; - -unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud) -{ - int i; - - for (i = 0; mouse_baud_table[i].baud != -1; i++) - if (mouse_baud_table[i].cflag == (cflag & CBAUD)) - break; - - i += 1; - if (mouse_baud_table[i].baud == -1) - i = 0; - - *new_baud = mouse_baud_table[i].baud; - return mouse_baud_table[i].cflag; -} - -EXPORT_SYMBOL(suncore_mouse_baud_cflag_next); - -/* Basically, when the baud rate is wrong the mouse spits out - * breaks to us. - */ -int suncore_mouse_baud_detection(unsigned char ch, int is_break) -{ - static int mouse_got_break = 0; - static int ctr = 0; - - if (is_break) { - /* Let a few normal bytes go by before we jump the gun - * and say we need to try another baud rate. - */ - if (mouse_got_break && ctr < 8) - return 1; - - /* Ok, we need to try another baud. */ - ctr = 0; - mouse_got_break = 1; - return 2; - } - if (mouse_got_break) { - ctr++; - if (ch == 0x87) { - /* Correct baud rate determined. */ - mouse_got_break = 0; - } - return 1; - } - return 0; -} - -EXPORT_SYMBOL(suncore_mouse_baud_detection); - -static int __init suncore_init(void) -{ - return 0; -} - -static void __exit suncore_exit(void) -{ -} - -module_init(suncore_init); -module_exit(suncore_exit); - -MODULE_AUTHOR("Eddie C. Dost, David S. Miller"); -MODULE_DESCRIPTION("Sun serial common layer"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h deleted file mode 100644 index db2057936c31..000000000000 --- a/drivers/serial/suncore.h +++ /dev/null @@ -1,33 +0,0 @@ -/* suncore.h - * - * Generic SUN serial/kbd/ms layer. Based entirely - * upon drivers/sbus/char/sunserial.h which is: - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * - * Port to new UART layer is: - * - * Copyright (C) 2002 David S. Miller (davem@redhat.com) - */ - -#ifndef _SERIAL_SUN_H -#define _SERIAL_SUN_H - -/* Serial keyboard defines for L1-A processing... */ -#define SUNKBD_RESET 0xff -#define SUNKBD_L1 0x01 -#define SUNKBD_UP 0x80 -#define SUNKBD_A 0x4d - -extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); -extern int suncore_mouse_baud_detection(unsigned char, int); - -extern int sunserial_register_minors(struct uart_driver *, int); -extern void sunserial_unregister_minors(struct uart_driver *, int); - -extern int sunserial_console_match(struct console *, struct device_node *, - struct uart_driver *, int, bool); -extern void sunserial_console_termios(struct console *, - struct device_node *); - -#endif /* !(_SERIAL_SUN_H) */ diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c deleted file mode 100644 index c9014868297d..000000000000 --- a/drivers/serial/sunhv.c +++ /dev/null @@ -1,661 +0,0 @@ -/* sunhv.c: Serial driver for SUN4V hypervisor console. - * - * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -#include "suncore.h" - -#define CON_BREAK ((long)-1) -#define CON_HUP ((long)-2) - -#define IGNORE_BREAK 0x1 -#define IGNORE_ALL 0x2 - -static char *con_write_page; -static char *con_read_page; - -static int hung_up = 0; - -static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit) -{ - while (!uart_circ_empty(xmit)) { - long status = sun4v_con_putchar(xmit->buf[xmit->tail]); - - if (status != HV_EOK) - break; - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } -} - -static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit) -{ - while (!uart_circ_empty(xmit)) { - unsigned long ra = __pa(xmit->buf + xmit->tail); - unsigned long len, status, sent; - - len = CIRC_CNT_TO_END(xmit->head, xmit->tail, - UART_XMIT_SIZE); - status = sun4v_con_write(ra, len, &sent); - if (status != HV_EOK) - break; - xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1); - port->icount.tx += sent; - } -} - -static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty) -{ - int saw_console_brk = 0; - int limit = 10000; - - while (limit-- > 0) { - long status; - long c = sun4v_con_getchar(&status); - - if (status == HV_EWOULDBLOCK) - break; - - if (c == CON_BREAK) { - if (uart_handle_break(port)) - continue; - saw_console_brk = 1; - c = 0; - } - - if (c == CON_HUP) { - hung_up = 1; - uart_handle_dcd_change(port, 0); - } else if (hung_up) { - hung_up = 0; - uart_handle_dcd_change(port, 1); - } - - if (tty == NULL) { - uart_handle_sysrq_char(port, c); - continue; - } - - port->icount.rx++; - - if (uart_handle_sysrq_char(port, c)) - continue; - - tty_insert_flip_char(tty, c, TTY_NORMAL); - } - - return saw_console_brk; -} - -static int receive_chars_read(struct uart_port *port, struct tty_struct *tty) -{ - int saw_console_brk = 0; - int limit = 10000; - - while (limit-- > 0) { - unsigned long ra = __pa(con_read_page); - unsigned long bytes_read, i; - long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read); - - if (stat != HV_EOK) { - bytes_read = 0; - - if (stat == CON_BREAK) { - if (uart_handle_break(port)) - continue; - saw_console_brk = 1; - *con_read_page = 0; - bytes_read = 1; - } else if (stat == CON_HUP) { - hung_up = 1; - uart_handle_dcd_change(port, 0); - continue; - } else { - /* HV_EWOULDBLOCK, etc. */ - break; - } - } - - if (hung_up) { - hung_up = 0; - uart_handle_dcd_change(port, 1); - } - - for (i = 0; i < bytes_read; i++) - uart_handle_sysrq_char(port, con_read_page[i]); - - if (tty == NULL) - continue; - - port->icount.rx += bytes_read; - - tty_insert_flip_string(tty, con_read_page, bytes_read); - } - - return saw_console_brk; -} - -struct sunhv_ops { - void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit); - int (*receive_chars)(struct uart_port *port, struct tty_struct *tty); -}; - -static struct sunhv_ops bychar_ops = { - .transmit_chars = transmit_chars_putchar, - .receive_chars = receive_chars_getchar, -}; - -static struct sunhv_ops bywrite_ops = { - .transmit_chars = transmit_chars_write, - .receive_chars = receive_chars_read, -}; - -static struct sunhv_ops *sunhv_ops = &bychar_ops; - -static struct tty_struct *receive_chars(struct uart_port *port) -{ - struct tty_struct *tty = NULL; - - if (port->state != NULL) /* Unopened serial console */ - tty = port->state->port.tty; - - if (sunhv_ops->receive_chars(port, tty)) - sun_do_break(); - - return tty; -} - -static void transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit; - - if (!port->state) - return; - - xmit = &port->state->xmit; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - sunhv_ops->transmit_chars(port, xmit); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static irqreturn_t sunhv_interrupt(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct tty_struct *tty; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - tty = receive_chars(port); - transmit_chars(port); - spin_unlock_irqrestore(&port->lock, flags); - - if (tty) - tty_flip_buffer_push(tty); - - return IRQ_HANDLED; -} - -/* port->lock is not held. */ -static unsigned int sunhv_tx_empty(struct uart_port *port) -{ - /* Transmitter is always empty for us. If the circ buffer - * is non-empty or there is an x_char pending, our caller - * will do the right thing and ignore what we return here. - */ - return TIOCSER_TEMT; -} - -/* port->lock held by caller. */ -static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - return; -} - -/* port->lock is held by caller and interrupts are disabled. */ -static unsigned int sunhv_get_mctrl(struct uart_port *port) -{ - return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; -} - -/* port->lock held by caller. */ -static void sunhv_stop_tx(struct uart_port *port) -{ - return; -} - -/* port->lock held by caller. */ -static void sunhv_start_tx(struct uart_port *port) -{ - transmit_chars(port); -} - -/* port->lock is not held. */ -static void sunhv_send_xchar(struct uart_port *port, char ch) -{ - unsigned long flags; - int limit = 10000; - - spin_lock_irqsave(&port->lock, flags); - - while (limit-- > 0) { - long status = sun4v_con_putchar(ch); - if (status == HV_EOK) - break; - udelay(1); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* port->lock held by caller. */ -static void sunhv_stop_rx(struct uart_port *port) -{ -} - -/* port->lock held by caller. */ -static void sunhv_enable_ms(struct uart_port *port) -{ -} - -/* port->lock is not held. */ -static void sunhv_break_ctl(struct uart_port *port, int break_state) -{ - if (break_state) { - unsigned long flags; - int limit = 10000; - - spin_lock_irqsave(&port->lock, flags); - - while (limit-- > 0) { - long status = sun4v_con_putchar(CON_BREAK); - if (status == HV_EOK) - break; - udelay(1); - } - - spin_unlock_irqrestore(&port->lock, flags); - } -} - -/* port->lock is not held. */ -static int sunhv_startup(struct uart_port *port) -{ - return 0; -} - -/* port->lock is not held. */ -static void sunhv_shutdown(struct uart_port *port) -{ -} - -/* port->lock is not held. */ -static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - unsigned int quot = uart_get_divisor(port, baud); - unsigned int iflag, cflag; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - - iflag = termios->c_iflag; - cflag = termios->c_cflag; - - port->ignore_status_mask = 0; - if (iflag & IGNBRK) - port->ignore_status_mask |= IGNORE_BREAK; - if ((cflag & CREAD) == 0) - port->ignore_status_mask |= IGNORE_ALL; - - /* XXX */ - uart_update_timeout(port, cflag, - (port->uartclk / (16 * quot))); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *sunhv_type(struct uart_port *port) -{ - return "SUN4V HCONS"; -} - -static void sunhv_release_port(struct uart_port *port) -{ -} - -static int sunhv_request_port(struct uart_port *port) -{ - return 0; -} - -static void sunhv_config_port(struct uart_port *port, int flags) -{ -} - -static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -static struct uart_ops sunhv_pops = { - .tx_empty = sunhv_tx_empty, - .set_mctrl = sunhv_set_mctrl, - .get_mctrl = sunhv_get_mctrl, - .stop_tx = sunhv_stop_tx, - .start_tx = sunhv_start_tx, - .send_xchar = sunhv_send_xchar, - .stop_rx = sunhv_stop_rx, - .enable_ms = sunhv_enable_ms, - .break_ctl = sunhv_break_ctl, - .startup = sunhv_startup, - .shutdown = sunhv_shutdown, - .set_termios = sunhv_set_termios, - .type = sunhv_type, - .release_port = sunhv_release_port, - .request_port = sunhv_request_port, - .config_port = sunhv_config_port, - .verify_port = sunhv_verify_port, -}; - -static struct uart_driver sunhv_reg = { - .owner = THIS_MODULE, - .driver_name = "sunhv", - .dev_name = "ttyS", - .major = TTY_MAJOR, -}; - -static struct uart_port *sunhv_port; - -/* Copy 's' into the con_write_page, decoding "\n" into - * "\r\n" along the way. We have to return two lengths - * because the caller needs to know how much to advance - * 's' and also how many bytes to output via con_write_page. - */ -static int fill_con_write_page(const char *s, unsigned int n, - unsigned long *page_bytes) -{ - const char *orig_s = s; - char *p = con_write_page; - int left = PAGE_SIZE; - - while (n--) { - if (*s == '\n') { - if (left < 2) - break; - *p++ = '\r'; - left--; - } else if (left < 1) - break; - *p++ = *s++; - left--; - } - *page_bytes = p - con_write_page; - return s - orig_s; -} - -static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n) -{ - struct uart_port *port = sunhv_port; - unsigned long flags; - int locked = 1; - - local_irq_save(flags); - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else - spin_lock(&port->lock); - - while (n > 0) { - unsigned long ra = __pa(con_write_page); - unsigned long page_bytes; - unsigned int cpy = fill_con_write_page(s, n, - &page_bytes); - - n -= cpy; - s += cpy; - while (page_bytes > 0) { - unsigned long written; - int limit = 1000000; - - while (limit--) { - unsigned long stat; - - stat = sun4v_con_write(ra, page_bytes, - &written); - if (stat == HV_EOK) - break; - udelay(1); - } - if (limit < 0) - break; - page_bytes -= written; - ra += written; - } - } - - if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); -} - -static inline void sunhv_console_putchar(struct uart_port *port, char c) -{ - int limit = 1000000; - - while (limit-- > 0) { - long status = sun4v_con_putchar(c); - if (status == HV_EOK) - break; - udelay(1); - } -} - -static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n) -{ - struct uart_port *port = sunhv_port; - unsigned long flags; - int i, locked = 1; - - local_irq_save(flags); - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else - spin_lock(&port->lock); - - for (i = 0; i < n; i++) { - if (*s == '\n') - sunhv_console_putchar(port, '\r'); - sunhv_console_putchar(port, *s++); - } - - if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); -} - -static struct console sunhv_console = { - .name = "ttyHV", - .write = sunhv_console_write_bychar, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sunhv_reg, -}; - -static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match) -{ - struct uart_port *port; - unsigned long minor; - int err; - - if (op->archdata.irqs[0] == 0xffffffff) - return -ENODEV; - - port = kzalloc(sizeof(struct uart_port), GFP_KERNEL); - if (unlikely(!port)) - return -ENOMEM; - - minor = 1; - if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 && - minor >= 1) { - err = -ENOMEM; - con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!con_write_page) - goto out_free_port; - - con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!con_read_page) - goto out_free_con_write_page; - - sunhv_console.write = sunhv_console_write_paged; - sunhv_ops = &bywrite_ops; - } - - sunhv_port = port; - - port->line = 0; - port->ops = &sunhv_pops; - port->type = PORT_SUNHV; - port->uartclk = ( 29491200 / 16 ); /* arbitrary */ - - port->membase = (unsigned char __iomem *) __pa(port); - - port->irq = op->archdata.irqs[0]; - - port->dev = &op->dev; - - err = sunserial_register_minors(&sunhv_reg, 1); - if (err) - goto out_free_con_read_page; - - sunserial_console_match(&sunhv_console, op->dev.of_node, - &sunhv_reg, port->line, false); - - err = uart_add_one_port(&sunhv_reg, port); - if (err) - goto out_unregister_driver; - - err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port); - if (err) - goto out_remove_port; - - dev_set_drvdata(&op->dev, port); - - return 0; - -out_remove_port: - uart_remove_one_port(&sunhv_reg, port); - -out_unregister_driver: - sunserial_unregister_minors(&sunhv_reg, 1); - -out_free_con_read_page: - kfree(con_read_page); - -out_free_con_write_page: - kfree(con_write_page); - -out_free_port: - kfree(port); - sunhv_port = NULL; - return err; -} - -static int __devexit hv_remove(struct platform_device *dev) -{ - struct uart_port *port = dev_get_drvdata(&dev->dev); - - free_irq(port->irq, port); - - uart_remove_one_port(&sunhv_reg, port); - - sunserial_unregister_minors(&sunhv_reg, 1); - - kfree(port); - sunhv_port = NULL; - - dev_set_drvdata(&dev->dev, NULL); - - return 0; -} - -static const struct of_device_id hv_match[] = { - { - .name = "console", - .compatible = "qcn", - }, - { - .name = "console", - .compatible = "SUNW,sun4v-console", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, hv_match); - -static struct of_platform_driver hv_driver = { - .driver = { - .name = "hv", - .owner = THIS_MODULE, - .of_match_table = hv_match, - }, - .probe = hv_probe, - .remove = __devexit_p(hv_remove), -}; - -static int __init sunhv_init(void) -{ - if (tlb_type != hypervisor) - return -ENODEV; - - return of_register_platform_driver(&hv_driver); -} - -static void __exit sunhv_exit(void) -{ - of_unregister_platform_driver(&hv_driver); -} - -module_init(sunhv_init); -module_exit(sunhv_exit); - -MODULE_AUTHOR("David S. Miller"); -MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); -MODULE_VERSION("2.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c deleted file mode 100644 index 5b246b18f42f..000000000000 --- a/drivers/serial/sunsab.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) - * - * Rewrote buffer handling to use CIRC(Circular Buffer) macros. - * Maxim Krasnyanskiy - * - * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud - * rates to be programmed into the UART. Also eliminated a lot of - * duplicated code in the console setup. - * Theodore Ts'o , 2001-Oct-12 - * - * Ported to new 2.5.x UART layer. - * David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -#include "suncore.h" -#include "sunsab.h" - -struct uart_sunsab_port { - struct uart_port port; /* Generic UART port */ - union sab82532_async_regs __iomem *regs; /* Chip registers */ - unsigned long irqflags; /* IRQ state flags */ - int dsr; /* Current DSR state */ - unsigned int cec_timeout; /* Chip poll timeout... */ - unsigned int tec_timeout; /* likewise */ - unsigned char interrupt_mask0;/* ISR0 masking */ - unsigned char interrupt_mask1;/* ISR1 masking */ - unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ - unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ - unsigned int gis_shift; - int type; /* SAB82532 version */ - - /* Setting configuration bits while the transmitter is active - * can cause garbage characters to get emitted by the chip. - * Therefore, we cache such writes here and do the real register - * write the next time the transmitter becomes idle. - */ - unsigned int cached_ebrg; - unsigned char cached_mode; - unsigned char cached_pvr; - unsigned char cached_dafo; -}; - -/* - * This assumes you have a 29.4912 MHz clock for your UART. - */ -#define SAB_BASE_BAUD ( 29491200 / 16 ) - -static char *sab82532_version[16] = { - "V1.0", "V2.0", "V3.2", "V(0x03)", - "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)", - "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)", - "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)" -}; - -#define SAB82532_MAX_TEC_TIMEOUT 200000 /* 1 character time (at 50 baud) */ -#define SAB82532_MAX_CEC_TIMEOUT 50000 /* 2.5 TX CLKs (at 50 baud) */ - -#define SAB82532_RECV_FIFO_SIZE 32 /* Standard async fifo sizes */ -#define SAB82532_XMIT_FIFO_SIZE 32 - -static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up) -{ - int timeout = up->tec_timeout; - - while ((readb(&up->regs->r.star) & SAB82532_STAR_TEC) && --timeout) - udelay(1); -} - -static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up) -{ - int timeout = up->cec_timeout; - - while ((readb(&up->regs->r.star) & SAB82532_STAR_CEC) && --timeout) - udelay(1); -} - -static struct tty_struct * -receive_chars(struct uart_sunsab_port *up, - union sab82532_irq_status *stat) -{ - struct tty_struct *tty = NULL; - unsigned char buf[32]; - int saw_console_brk = 0; - int free_fifo = 0; - int count = 0; - int i; - - if (up->port.state != NULL) /* Unopened serial console */ - tty = up->port.state->port.tty; - - /* Read number of BYTES (Character + Status) available. */ - if (stat->sreg.isr0 & SAB82532_ISR0_RPF) { - count = SAB82532_RECV_FIFO_SIZE; - free_fifo++; - } - - if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { - count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1); - free_fifo++; - } - - /* Issue a FIFO read command in case we where idle. */ - if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { - sunsab_cec_wait(up); - writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr); - return tty; - } - - if (stat->sreg.isr0 & SAB82532_ISR0_RFO) - free_fifo++; - - /* Read the FIFO. */ - for (i = 0; i < count; i++) - buf[i] = readb(&up->regs->r.rfifo[i]); - - /* Issue Receive Message Complete command. */ - if (free_fifo) { - sunsab_cec_wait(up); - writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr); - } - - /* Count may be zero for BRK, so we check for it here */ - if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) && - (up->port.line == up->port.cons->index)) - saw_console_brk = 1; - - for (i = 0; i < count; i++) { - unsigned char ch = buf[i], flag; - - if (tty == NULL) { - uart_handle_sysrq_char(&up->port, ch); - continue; - } - - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(stat->sreg.isr0 & (SAB82532_ISR0_PERR | - SAB82532_ISR0_FERR | - SAB82532_ISR0_RFO)) || - unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) { - /* - * For statistics only - */ - if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { - stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR | - SAB82532_ISR0_FERR); - 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)) - continue; - } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR) - up->port.icount.parity++; - else if (stat->sreg.isr0 & SAB82532_ISR0_FERR) - up->port.icount.frame++; - if (stat->sreg.isr0 & SAB82532_ISR0_RFO) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ingored. - */ - stat->sreg.isr0 &= (up->port.read_status_mask & 0xff); - stat->sreg.isr1 &= ((up->port.read_status_mask >> 8) & 0xff); - - if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { - flag = TTY_BREAK; - } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR) - flag = TTY_PARITY; - else if (stat->sreg.isr0 & SAB82532_ISR0_FERR) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - continue; - - if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 && - (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0) - tty_insert_flip_char(tty, ch, flag); - if (stat->sreg.isr0 & SAB82532_ISR0_RFO) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - if (saw_console_brk) - sun_do_break(); - - return tty; -} - -static void sunsab_stop_tx(struct uart_port *); -static void sunsab_tx_idle(struct uart_sunsab_port *); - -static void transmit_chars(struct uart_sunsab_port *up, - union sab82532_irq_status *stat) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int i; - - if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) { - up->interrupt_mask1 |= SAB82532_IMR1_ALLS; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - set_bit(SAB82532_ALLS, &up->irqflags); - } - -#if 0 /* bde@nwlink.com says this check causes problems */ - if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR)) - return; -#endif - - if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW)) - return; - - set_bit(SAB82532_XPR, &up->irqflags); - sunsab_tx_idle(up); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - up->interrupt_mask1 |= SAB82532_IMR1_XPR; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - return; - } - - up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); - writeb(up->interrupt_mask1, &up->regs->w.imr1); - clear_bit(SAB82532_ALLS, &up->irqflags); - - /* Stuff 32 bytes into Transmit FIFO. */ - clear_bit(SAB82532_XPR, &up->irqflags); - for (i = 0; i < up->port.fifosize; i++) { - writeb(xmit->buf[xmit->tail], - &up->regs->w.xfifo[i]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - /* Issue a Transmit Frame command. */ - sunsab_cec_wait(up); - writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - sunsab_stop_tx(&up->port); -} - -static void check_status(struct uart_sunsab_port *up, - union sab82532_irq_status *stat) -{ - if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) - uart_handle_dcd_change(&up->port, - !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD)); - - if (stat->sreg.isr1 & SAB82532_ISR1_CSC) - uart_handle_cts_change(&up->port, - (readb(&up->regs->r.star) & SAB82532_STAR_CTS)); - - if ((readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ^ up->dsr) { - up->dsr = (readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ? 0 : 1; - up->port.icount.dsr++; - } - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -static irqreturn_t sunsab_interrupt(int irq, void *dev_id) -{ - struct uart_sunsab_port *up = dev_id; - struct tty_struct *tty; - union sab82532_irq_status status; - unsigned long flags; - unsigned char gis; - - spin_lock_irqsave(&up->port.lock, flags); - - status.stat = 0; - gis = readb(&up->regs->r.gis) >> up->gis_shift; - if (gis & 1) - status.sreg.isr0 = readb(&up->regs->r.isr0); - if (gis & 2) - status.sreg.isr1 = readb(&up->regs->r.isr1); - - tty = NULL; - if (status.stat) { - if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | - SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || - (status.sreg.isr1 & SAB82532_ISR1_BRK)) - tty = receive_chars(up, &status); - if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || - (status.sreg.isr1 & SAB82532_ISR1_CSC)) - check_status(up, &status); - if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR)) - transmit_chars(up, &status); - } - - spin_unlock_irqrestore(&up->port.lock, flags); - - if (tty) - tty_flip_buffer_push(tty); - - return IRQ_HANDLED; -} - -/* port->lock is not held. */ -static unsigned int sunsab_tx_empty(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - int ret; - - /* Do not need a lock for a state test like this. */ - if (test_bit(SAB82532_ALLS, &up->irqflags)) - ret = TIOCSER_TEMT; - else - ret = 0; - - return ret; -} - -/* port->lock held by caller. */ -static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - - if (mctrl & TIOCM_RTS) { - up->cached_mode &= ~SAB82532_MODE_FRTS; - up->cached_mode |= SAB82532_MODE_RTS; - } else { - up->cached_mode |= (SAB82532_MODE_FRTS | - SAB82532_MODE_RTS); - } - if (mctrl & TIOCM_DTR) { - up->cached_pvr &= ~(up->pvr_dtr_bit); - } else { - up->cached_pvr |= up->pvr_dtr_bit; - } - - set_bit(SAB82532_REGS_PENDING, &up->irqflags); - if (test_bit(SAB82532_XPR, &up->irqflags)) - sunsab_tx_idle(up); -} - -/* port->lock is held by caller and interrupts are disabled. */ -static unsigned int sunsab_get_mctrl(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned char val; - unsigned int result; - - result = 0; - - val = readb(&up->regs->r.pvr); - result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR; - - val = readb(&up->regs->r.vstr); - result |= (val & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR; - - val = readb(&up->regs->r.star); - result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0; - - return result; -} - -/* port->lock held by caller. */ -static void sunsab_stop_tx(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - - up->interrupt_mask1 |= SAB82532_IMR1_XPR; - writeb(up->interrupt_mask1, &up->regs->w.imr1); -} - -/* port->lock held by caller. */ -static void sunsab_tx_idle(struct uart_sunsab_port *up) -{ - if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) { - u8 tmp; - - clear_bit(SAB82532_REGS_PENDING, &up->irqflags); - writeb(up->cached_mode, &up->regs->rw.mode); - writeb(up->cached_pvr, &up->regs->rw.pvr); - writeb(up->cached_dafo, &up->regs->w.dafo); - - writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr); - tmp = readb(&up->regs->rw.ccr2); - tmp &= ~0xc0; - tmp |= (up->cached_ebrg >> 2) & 0xc0; - writeb(tmp, &up->regs->rw.ccr2); - } -} - -/* port->lock held by caller. */ -static void sunsab_start_tx(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - struct circ_buf *xmit = &up->port.state->xmit; - int i; - - up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); - writeb(up->interrupt_mask1, &up->regs->w.imr1); - - if (!test_bit(SAB82532_XPR, &up->irqflags)) - return; - - clear_bit(SAB82532_ALLS, &up->irqflags); - clear_bit(SAB82532_XPR, &up->irqflags); - - for (i = 0; i < up->port.fifosize; i++) { - writeb(xmit->buf[xmit->tail], - &up->regs->w.xfifo[i]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - /* Issue a Transmit Frame command. */ - sunsab_cec_wait(up); - writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); -} - -/* port->lock is not held. */ -static void sunsab_send_xchar(struct uart_port *port, char ch) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - sunsab_tec_wait(up); - writeb(ch, &up->regs->w.tic); - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* port->lock held by caller. */ -static void sunsab_stop_rx(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - - up->interrupt_mask0 |= SAB82532_IMR0_TCD; - writeb(up->interrupt_mask1, &up->regs->w.imr0); -} - -/* port->lock held by caller. */ -static void sunsab_enable_ms(struct uart_port *port) -{ - /* For now we always receive these interrupts. */ -} - -/* port->lock is not held. */ -static void sunsab_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned long flags; - unsigned char val; - - spin_lock_irqsave(&up->port.lock, flags); - - val = up->cached_dafo; - if (break_state) - val |= SAB82532_DAFO_XBRK; - else - val &= ~SAB82532_DAFO_XBRK; - up->cached_dafo = val; - - set_bit(SAB82532_REGS_PENDING, &up->irqflags); - if (test_bit(SAB82532_XPR, &up->irqflags)) - sunsab_tx_idle(up); - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* port->lock is not held. */ -static int sunsab_startup(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned long flags; - unsigned char tmp; - int err = request_irq(up->port.irq, sunsab_interrupt, - IRQF_SHARED, "sab", up); - if (err) - return err; - - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Wait for any commands or immediate characters - */ - sunsab_cec_wait(up); - sunsab_tec_wait(up); - - /* - * Clear the FIFO buffers. - */ - writeb(SAB82532_CMDR_RRES, &up->regs->w.cmdr); - sunsab_cec_wait(up); - writeb(SAB82532_CMDR_XRES, &up->regs->w.cmdr); - - /* - * Clear the interrupt registers. - */ - (void) readb(&up->regs->r.isr0); - (void) readb(&up->regs->r.isr1); - - /* - * Now, initialize the UART - */ - writeb(0, &up->regs->w.ccr0); /* power-down */ - writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | - SAB82532_CCR0_SM_ASYNC, &up->regs->w.ccr0); - writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &up->regs->w.ccr1); - writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | - SAB82532_CCR2_TOE, &up->regs->w.ccr2); - writeb(0, &up->regs->w.ccr3); - writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); - up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS | - SAB82532_MODE_RAC); - writeb(up->cached_mode, &up->regs->w.mode); - writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); - - tmp = readb(&up->regs->rw.ccr0); - tmp |= SAB82532_CCR0_PU; /* power-up */ - writeb(tmp, &up->regs->rw.ccr0); - - /* - * Finally, enable interrupts - */ - up->interrupt_mask0 = (SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | - SAB82532_IMR0_PLLA); - writeb(up->interrupt_mask0, &up->regs->w.imr0); - up->interrupt_mask1 = (SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | - SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | - SAB82532_IMR1_CSC | SAB82532_IMR1_XON | - SAB82532_IMR1_XPR); - writeb(up->interrupt_mask1, &up->regs->w.imr1); - set_bit(SAB82532_ALLS, &up->irqflags); - set_bit(SAB82532_XPR, &up->irqflags); - - spin_unlock_irqrestore(&up->port.lock, flags); - - return 0; -} - -/* port->lock is not held. */ -static void sunsab_shutdown(struct uart_port *port) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - /* Disable Interrupts */ - up->interrupt_mask0 = 0xff; - writeb(up->interrupt_mask0, &up->regs->w.imr0); - up->interrupt_mask1 = 0xff; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - - /* Disable break condition */ - up->cached_dafo = readb(&up->regs->rw.dafo); - up->cached_dafo &= ~SAB82532_DAFO_XBRK; - writeb(up->cached_dafo, &up->regs->rw.dafo); - - /* Disable Receiver */ - up->cached_mode &= ~SAB82532_MODE_RAC; - writeb(up->cached_mode, &up->regs->rw.mode); - - /* - * XXX FIXME - * - * If the chip is powered down here the system hangs/crashes during - * reboot or shutdown. This needs to be investigated further, - * similar behaviour occurs in 2.4 when the driver is configured - * as a module only. One hint may be that data is sometimes - * transmitted at 9600 baud during shutdown (regardless of the - * speed the chip was configured for when the port was open). - */ -#if 0 - /* Power Down */ - tmp = readb(&up->regs->rw.ccr0); - tmp &= ~SAB82532_CCR0_PU; - writeb(tmp, &up->regs->rw.ccr0); -#endif - - spin_unlock_irqrestore(&up->port.lock, flags); - free_irq(up->port.irq, up); -} - -/* - * This is used to figure out the divisor speeds. - * - * The formula is: Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)), - * - * with 0 <= N < 64 and 0 <= M < 16 - */ - -static void calc_ebrg(int baud, int *n_ret, int *m_ret) -{ - int n, m; - - if (baud == 0) { - *n_ret = 0; - *m_ret = 0; - return; - } - - /* - * We scale numbers by 10 so that we get better accuracy - * without having to use floating point. Here we increment m - * until n is within the valid range. - */ - n = (SAB_BASE_BAUD * 10) / baud; - m = 0; - while (n >= 640) { - n = n / 2; - m++; - } - n = (n+5) / 10; - /* - * We try very hard to avoid speeds with M == 0 since they may - * not work correctly for XTAL frequences above 10 MHz. - */ - if ((m == 0) && ((n & 1) == 0)) { - n = n / 2; - m++; - } - *n_ret = n - 1; - *m_ret = m; -} - -/* Internal routine, port->lock is held and local interrupts are disabled. */ -static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag, - unsigned int iflag, unsigned int baud, - unsigned int quot) -{ - unsigned char dafo; - int bits, n, m; - - /* Byte size and parity */ - switch (cflag & CSIZE) { - case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; - case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; - case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; - case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; - } - - if (cflag & CSTOPB) { - dafo |= SAB82532_DAFO_STOP; - bits++; - } - - if (cflag & PARENB) { - dafo |= SAB82532_DAFO_PARE; - bits++; - } - - if (cflag & PARODD) { - dafo |= SAB82532_DAFO_PAR_ODD; - } else { - dafo |= SAB82532_DAFO_PAR_EVEN; - } - up->cached_dafo = dafo; - - calc_ebrg(baud, &n, &m); - - up->cached_ebrg = n | (m << 6); - - up->tec_timeout = (10 * 1000000) / baud; - up->cec_timeout = up->tec_timeout >> 2; - - /* CTS flow control flags */ - /* We encode read_status_mask and ignore_status_mask like so: - * - * --------------------- - * | ... | ISR1 | ISR0 | - * --------------------- - * .. 15 8 7 0 - */ - - up->port.read_status_mask = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | - SAB82532_ISR0_RFO | SAB82532_ISR0_RPF | - SAB82532_ISR0_CDSC); - up->port.read_status_mask |= (SAB82532_ISR1_CSC | - SAB82532_ISR1_ALLS | - SAB82532_ISR1_XPR) << 8; - if (iflag & INPCK) - up->port.read_status_mask |= (SAB82532_ISR0_PERR | - SAB82532_ISR0_FERR); - if (iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8); - - /* - * Characteres to ignore - */ - up->port.ignore_status_mask = 0; - if (iflag & IGNPAR) - up->port.ignore_status_mask |= (SAB82532_ISR0_PERR | - SAB82532_ISR0_FERR); - if (iflag & IGNBRK) { - up->port.ignore_status_mask |= (SAB82532_ISR1_BRK << 8); - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (iflag & IGNPAR) - up->port.ignore_status_mask |= SAB82532_ISR0_RFO; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - up->port.ignore_status_mask |= (SAB82532_ISR0_RPF | - SAB82532_ISR0_TCD); - - uart_update_timeout(&up->port, cflag, - (up->port.uartclk / (16 * quot))); - - /* Now schedule a register update when the chip's - * transmitter is idle. - */ - up->cached_mode |= SAB82532_MODE_RAC; - set_bit(SAB82532_REGS_PENDING, &up->irqflags); - if (test_bit(SAB82532_XPR, &up->irqflags)) - sunsab_tx_idle(up); -} - -/* port->lock is not held. */ -static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; - unsigned long flags; - unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - unsigned int quot = uart_get_divisor(port, baud); - - spin_lock_irqsave(&up->port.lock, flags); - sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static const char *sunsab_type(struct uart_port *port) -{ - struct uart_sunsab_port *up = (void *)port; - static char buf[36]; - - sprintf(buf, "SAB82532 %s", sab82532_version[up->type]); - return buf; -} - -static void sunsab_release_port(struct uart_port *port) -{ -} - -static int sunsab_request_port(struct uart_port *port) -{ - return 0; -} - -static void sunsab_config_port(struct uart_port *port, int flags) -{ -} - -static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -static struct uart_ops sunsab_pops = { - .tx_empty = sunsab_tx_empty, - .set_mctrl = sunsab_set_mctrl, - .get_mctrl = sunsab_get_mctrl, - .stop_tx = sunsab_stop_tx, - .start_tx = sunsab_start_tx, - .send_xchar = sunsab_send_xchar, - .stop_rx = sunsab_stop_rx, - .enable_ms = sunsab_enable_ms, - .break_ctl = sunsab_break_ctl, - .startup = sunsab_startup, - .shutdown = sunsab_shutdown, - .set_termios = sunsab_set_termios, - .type = sunsab_type, - .release_port = sunsab_release_port, - .request_port = sunsab_request_port, - .config_port = sunsab_config_port, - .verify_port = sunsab_verify_port, -}; - -static struct uart_driver sunsab_reg = { - .owner = THIS_MODULE, - .driver_name = "sunsab", - .dev_name = "ttyS", - .major = TTY_MAJOR, -}; - -static struct uart_sunsab_port *sunsab_ports; - -#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE - -static void sunsab_console_putchar(struct uart_port *port, int c) -{ - struct uart_sunsab_port *up = (struct uart_sunsab_port *)port; - - sunsab_tec_wait(up); - writeb(c, &up->regs->w.tic); -} - -static void sunsab_console_write(struct console *con, const char *s, unsigned n) -{ - struct uart_sunsab_port *up = &sunsab_ports[con->index]; - unsigned long flags; - int locked = 1; - - 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, n, sunsab_console_putchar); - sunsab_tec_wait(up); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static int sunsab_console_setup(struct console *con, char *options) -{ - struct uart_sunsab_port *up = &sunsab_ports[con->index]; - unsigned long flags; - unsigned int baud, quot; - - /* - * The console framework calls us for each and every port - * registered. Defer the console setup until the requested - * port has been properly discovered. A bit of a hack, - * though... - */ - if (up->port.type != PORT_SUNSAB) - return -1; - - printk("Console: ttyS%d (SAB82532)\n", - (sunsab_reg.minor - 64) + con->index); - - sunserial_console_termios(con, up->port.dev->of_node); - - switch (con->cflag & CBAUD) { - case B150: baud = 150; break; - case B300: baud = 300; break; - case B600: baud = 600; break; - case B1200: baud = 1200; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - default: case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - case B57600: baud = 57600; break; - case B115200: baud = 115200; break; - case B230400: baud = 230400; break; - case B460800: baud = 460800; break; - }; - - /* - * Temporary fix. - */ - spin_lock_init(&up->port.lock); - - /* - * Initialize the hardware - */ - sunsab_startup(&up->port); - - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Finally, enable interrupts - */ - up->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | - SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; - writeb(up->interrupt_mask0, &up->regs->w.imr0); - up->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | - SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | - SAB82532_IMR1_CSC | SAB82532_IMR1_XON | - SAB82532_IMR1_XPR; - writeb(up->interrupt_mask1, &up->regs->w.imr1); - - quot = uart_get_divisor(&up->port, baud); - sunsab_convert_to_sab(up, con->cflag, 0, baud, quot); - sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - - spin_unlock_irqrestore(&up->port.lock, flags); - - return 0; -} - -static struct console sunsab_console = { - .name = "ttyS", - .write = sunsab_console_write, - .device = uart_console_device, - .setup = sunsab_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sunsab_reg, -}; - -static inline struct console *SUNSAB_CONSOLE(void) -{ - return &sunsab_console; -} -#else -#define SUNSAB_CONSOLE() (NULL) -#define sunsab_console_init() do { } while (0) -#endif - -static int __devinit sunsab_init_one(struct uart_sunsab_port *up, - struct platform_device *op, - unsigned long offset, - int line) -{ - up->port.line = line; - up->port.dev = &op->dev; - - up->port.mapbase = op->resource[0].start + offset; - up->port.membase = of_ioremap(&op->resource[0], offset, - sizeof(union sab82532_async_regs), - "sab"); - if (!up->port.membase) - return -ENOMEM; - up->regs = (union sab82532_async_regs __iomem *) up->port.membase; - - up->port.irq = op->archdata.irqs[0]; - - up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; - up->port.iotype = UPIO_MEM; - - writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); - - up->port.ops = &sunsab_pops; - up->port.type = PORT_SUNSAB; - up->port.uartclk = SAB_BASE_BAUD; - - up->type = readb(&up->regs->r.vstr) & 0x0f; - writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); - writeb(0xff, &up->regs->w.pim); - if ((up->port.line & 0x1) == 0) { - up->pvr_dsr_bit = (1 << 0); - up->pvr_dtr_bit = (1 << 1); - up->gis_shift = 2; - } else { - up->pvr_dsr_bit = (1 << 3); - up->pvr_dtr_bit = (1 << 2); - up->gis_shift = 0; - } - up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); - writeb(up->cached_pvr, &up->regs->w.pvr); - up->cached_mode = readb(&up->regs->rw.mode); - up->cached_mode |= SAB82532_MODE_FRTS; - writeb(up->cached_mode, &up->regs->rw.mode); - up->cached_mode |= SAB82532_MODE_RTS; - writeb(up->cached_mode, &up->regs->rw.mode); - - up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; - up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; - - return 0; -} - -static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match) -{ - static int inst; - struct uart_sunsab_port *up; - int err; - - up = &sunsab_ports[inst * 2]; - - err = sunsab_init_one(&up[0], op, - 0, - (inst * 2) + 0); - if (err) - goto out; - - err = sunsab_init_one(&up[1], op, - sizeof(union sab82532_async_regs), - (inst * 2) + 1); - if (err) - goto out1; - - sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node, - &sunsab_reg, up[0].port.line, - false); - - sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node, - &sunsab_reg, up[1].port.line, - false); - - err = uart_add_one_port(&sunsab_reg, &up[0].port); - if (err) - goto out2; - - err = uart_add_one_port(&sunsab_reg, &up[1].port); - if (err) - goto out3; - - dev_set_drvdata(&op->dev, &up[0]); - - inst++; - - return 0; - -out3: - uart_remove_one_port(&sunsab_reg, &up[0].port); -out2: - of_iounmap(&op->resource[0], - up[1].port.membase, - sizeof(union sab82532_async_regs)); -out1: - of_iounmap(&op->resource[0], - up[0].port.membase, - sizeof(union sab82532_async_regs)); -out: - return err; -} - -static int __devexit sab_remove(struct platform_device *op) -{ - struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); - - uart_remove_one_port(&sunsab_reg, &up[1].port); - uart_remove_one_port(&sunsab_reg, &up[0].port); - of_iounmap(&op->resource[0], - up[1].port.membase, - sizeof(union sab82532_async_regs)); - of_iounmap(&op->resource[0], - up[0].port.membase, - sizeof(union sab82532_async_regs)); - - dev_set_drvdata(&op->dev, NULL); - - return 0; -} - -static const struct of_device_id sab_match[] = { - { - .name = "se", - }, - { - .name = "serial", - .compatible = "sab82532", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, sab_match); - -static struct of_platform_driver sab_driver = { - .driver = { - .name = "sab", - .owner = THIS_MODULE, - .of_match_table = sab_match, - }, - .probe = sab_probe, - .remove = __devexit_p(sab_remove), -}; - -static int __init sunsab_init(void) -{ - struct device_node *dp; - int err; - int num_channels = 0; - - for_each_node_by_name(dp, "se") - num_channels += 2; - for_each_node_by_name(dp, "serial") { - if (of_device_is_compatible(dp, "sab82532")) - num_channels += 2; - } - - if (num_channels) { - sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) * - num_channels, GFP_KERNEL); - if (!sunsab_ports) - return -ENOMEM; - - err = sunserial_register_minors(&sunsab_reg, num_channels); - if (err) { - kfree(sunsab_ports); - sunsab_ports = NULL; - - return err; - } - } - - return of_register_platform_driver(&sab_driver); -} - -static void __exit sunsab_exit(void) -{ - of_unregister_platform_driver(&sab_driver); - if (sunsab_reg.nr) { - sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); - } - - kfree(sunsab_ports); - sunsab_ports = NULL; -} - -module_init(sunsab_init); -module_exit(sunsab_exit); - -MODULE_AUTHOR("Eddie C. Dost and David S. Miller"); -MODULE_DESCRIPTION("Sun SAB82532 serial port driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h deleted file mode 100644 index b78e1f7b8050..000000000000 --- a/drivers/serial/sunsab.h +++ /dev/null @@ -1,322 +0,0 @@ -/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - */ - -#ifndef _SUNSAB_H -#define _SUNSAB_H - -struct sab82532_async_rd_regs { - u8 rfifo[0x20]; /* Receive FIFO */ - u8 star; /* Status Register */ - u8 __pad1; - u8 mode; /* Mode Register */ - u8 timr; /* Timer Register */ - u8 xon; /* XON Character */ - u8 xoff; /* XOFF Character */ - u8 tcr; /* Termination Character Register */ - u8 dafo; /* Data Format */ - u8 rfc; /* RFIFO Control Register */ - u8 __pad2; - u8 rbcl; /* Receive Byte Count Low */ - u8 rbch; /* Receive Byte Count High */ - u8 ccr0; /* Channel Configuration Register 0 */ - u8 ccr1; /* Channel Configuration Register 1 */ - u8 ccr2; /* Channel Configuration Register 2 */ - u8 ccr3; /* Channel Configuration Register 3 */ - u8 __pad3[4]; - u8 vstr; /* Version Status Register */ - u8 __pad4[3]; - u8 gis; /* Global Interrupt Status */ - u8 ipc; /* Interrupt Port Configuration */ - u8 isr0; /* Interrupt Status 0 */ - u8 isr1; /* Interrupt Status 1 */ - u8 pvr; /* Port Value Register */ - u8 pis; /* Port Interrupt Status */ - u8 pcr; /* Port Configuration Register */ - u8 ccr4; /* Channel Configuration Register 4 */ -}; - -struct sab82532_async_wr_regs { - u8 xfifo[0x20]; /* Transmit FIFO */ - u8 cmdr; /* Command Register */ - u8 __pad1; - u8 mode; - u8 timr; - u8 xon; - u8 xoff; - u8 tcr; - u8 dafo; - u8 rfc; - u8 __pad2; - u8 xbcl; /* Transmit Byte Count Low */ - u8 xbch; /* Transmit Byte Count High */ - u8 ccr0; - u8 ccr1; - u8 ccr2; - u8 ccr3; - u8 tsax; /* Time-Slot Assignment Reg. Transmit */ - u8 tsar; /* Time-Slot Assignment Reg. Receive */ - u8 xccr; /* Transmit Channel Capacity Register */ - u8 rccr; /* Receive Channel Capacity Register */ - u8 bgr; /* Baud Rate Generator Register */ - u8 tic; /* Transmit Immediate Character */ - u8 mxn; /* Mask XON Character */ - u8 mxf; /* Mask XOFF Character */ - u8 iva; /* Interrupt Vector Address */ - u8 ipc; - u8 imr0; /* Interrupt Mask Register 0 */ - u8 imr1; /* Interrupt Mask Register 1 */ - u8 pvr; - u8 pim; /* Port Interrupt Mask */ - u8 pcr; - u8 ccr4; -}; - -struct sab82532_async_rw_regs { /* Read/Write registers */ - u8 __pad1[0x20]; - u8 __pad2; - u8 __pad3; - u8 mode; - u8 timr; - u8 xon; - u8 xoff; - u8 tcr; - u8 dafo; - u8 rfc; - u8 __pad4; - u8 __pad5; - u8 __pad6; - u8 ccr0; - u8 ccr1; - u8 ccr2; - u8 ccr3; - u8 __pad7; - u8 __pad8; - u8 __pad9; - u8 __pad10; - u8 __pad11; - u8 __pad12; - u8 __pad13; - u8 __pad14; - u8 __pad15; - u8 ipc; - u8 __pad16; - u8 __pad17; - u8 pvr; - u8 __pad18; - u8 pcr; - u8 ccr4; -}; - -union sab82532_async_regs { - __volatile__ struct sab82532_async_rd_regs r; - __volatile__ struct sab82532_async_wr_regs w; - __volatile__ struct sab82532_async_rw_regs rw; -}; - -union sab82532_irq_status { - unsigned short stat; - struct { - unsigned char isr0; - unsigned char isr1; - } sreg; -}; - -/* irqflags bits */ -#define SAB82532_ALLS 0x00000001 -#define SAB82532_XPR 0x00000002 -#define SAB82532_REGS_PENDING 0x00000004 - -/* RFIFO Status Byte */ -#define SAB82532_RSTAT_PE 0x80 -#define SAB82532_RSTAT_FE 0x40 -#define SAB82532_RSTAT_PARITY 0x01 - -/* Status Register (STAR) */ -#define SAB82532_STAR_XDOV 0x80 -#define SAB82532_STAR_XFW 0x40 -#define SAB82532_STAR_RFNE 0x20 -#define SAB82532_STAR_FCS 0x10 -#define SAB82532_STAR_TEC 0x08 -#define SAB82532_STAR_CEC 0x04 -#define SAB82532_STAR_CTS 0x02 - -/* Command Register (CMDR) */ -#define SAB82532_CMDR_RMC 0x80 -#define SAB82532_CMDR_RRES 0x40 -#define SAB82532_CMDR_RFRD 0x20 -#define SAB82532_CMDR_STI 0x10 -#define SAB82532_CMDR_XF 0x08 -#define SAB82532_CMDR_XRES 0x01 - -/* Mode Register (MODE) */ -#define SAB82532_MODE_FRTS 0x40 -#define SAB82532_MODE_FCTS 0x20 -#define SAB82532_MODE_FLON 0x10 -#define SAB82532_MODE_RAC 0x08 -#define SAB82532_MODE_RTS 0x04 -#define SAB82532_MODE_TRS 0x02 -#define SAB82532_MODE_TLP 0x01 - -/* Timer Register (TIMR) */ -#define SAB82532_TIMR_CNT_MASK 0xe0 -#define SAB82532_TIMR_VALUE_MASK 0x1f - -/* Data Format (DAFO) */ -#define SAB82532_DAFO_XBRK 0x40 -#define SAB82532_DAFO_STOP 0x20 -#define SAB82532_DAFO_PAR_SPACE 0x00 -#define SAB82532_DAFO_PAR_ODD 0x08 -#define SAB82532_DAFO_PAR_EVEN 0x10 -#define SAB82532_DAFO_PAR_MARK 0x18 -#define SAB82532_DAFO_PARE 0x04 -#define SAB82532_DAFO_CHL8 0x00 -#define SAB82532_DAFO_CHL7 0x01 -#define SAB82532_DAFO_CHL6 0x02 -#define SAB82532_DAFO_CHL5 0x03 - -/* RFIFO Control Register (RFC) */ -#define SAB82532_RFC_DPS 0x40 -#define SAB82532_RFC_DXS 0x20 -#define SAB82532_RFC_RFDF 0x10 -#define SAB82532_RFC_RFTH_1 0x00 -#define SAB82532_RFC_RFTH_4 0x04 -#define SAB82532_RFC_RFTH_16 0x08 -#define SAB82532_RFC_RFTH_32 0x0c -#define SAB82532_RFC_TCDE 0x01 - -/* Received Byte Count High (RBCH) */ -#define SAB82532_RBCH_DMA 0x80 -#define SAB82532_RBCH_CAS 0x20 - -/* Transmit Byte Count High (XBCH) */ -#define SAB82532_XBCH_DMA 0x80 -#define SAB82532_XBCH_CAS 0x20 -#define SAB82532_XBCH_XC 0x10 - -/* Channel Configuration Register 0 (CCR0) */ -#define SAB82532_CCR0_PU 0x80 -#define SAB82532_CCR0_MCE 0x40 -#define SAB82532_CCR0_SC_NRZ 0x00 -#define SAB82532_CCR0_SC_NRZI 0x08 -#define SAB82532_CCR0_SC_FM0 0x10 -#define SAB82532_CCR0_SC_FM1 0x14 -#define SAB82532_CCR0_SC_MANCH 0x18 -#define SAB82532_CCR0_SM_HDLC 0x00 -#define SAB82532_CCR0_SM_SDLC_LOOP 0x01 -#define SAB82532_CCR0_SM_BISYNC 0x02 -#define SAB82532_CCR0_SM_ASYNC 0x03 - -/* Channel Configuration Register 1 (CCR1) */ -#define SAB82532_CCR1_ODS 0x10 -#define SAB82532_CCR1_BCR 0x08 -#define SAB82532_CCR1_CM_MASK 0x07 - -/* Channel Configuration Register 2 (CCR2) */ -#define SAB82532_CCR2_SOC1 0x80 -#define SAB82532_CCR2_SOC0 0x40 -#define SAB82532_CCR2_BR9 0x80 -#define SAB82532_CCR2_BR8 0x40 -#define SAB82532_CCR2_BDF 0x20 -#define SAB82532_CCR2_SSEL 0x10 -#define SAB82532_CCR2_XCS0 0x20 -#define SAB82532_CCR2_RCS0 0x10 -#define SAB82532_CCR2_TOE 0x08 -#define SAB82532_CCR2_RWX 0x04 -#define SAB82532_CCR2_DIV 0x01 - -/* Channel Configuration Register 3 (CCR3) */ -#define SAB82532_CCR3_PSD 0x01 - -/* Time Slot Assignment Register Transmit (TSAX) */ -#define SAB82532_TSAX_TSNX_MASK 0xfc -#define SAB82532_TSAX_XCS2 0x02 /* see also CCR2 */ -#define SAB82532_TSAX_XCS1 0x01 - -/* Time Slot Assignment Register Receive (TSAR) */ -#define SAB82532_TSAR_TSNR_MASK 0xfc -#define SAB82532_TSAR_RCS2 0x02 /* see also CCR2 */ -#define SAB82532_TSAR_RCS1 0x01 - -/* Version Status Register (VSTR) */ -#define SAB82532_VSTR_CD 0x80 -#define SAB82532_VSTR_DPLA 0x40 -#define SAB82532_VSTR_VN_MASK 0x0f -#define SAB82532_VSTR_VN_1 0x00 -#define SAB82532_VSTR_VN_2 0x01 -#define SAB82532_VSTR_VN_3_2 0x02 - -/* Global Interrupt Status Register (GIS) */ -#define SAB82532_GIS_PI 0x80 -#define SAB82532_GIS_ISA1 0x08 -#define SAB82532_GIS_ISA0 0x04 -#define SAB82532_GIS_ISB1 0x02 -#define SAB82532_GIS_ISB0 0x01 - -/* Interrupt Vector Address (IVA) */ -#define SAB82532_IVA_MASK 0xf1 - -/* Interrupt Port Configuration (IPC) */ -#define SAB82532_IPC_VIS 0x80 -#define SAB82532_IPC_SLA1 0x10 -#define SAB82532_IPC_SLA0 0x08 -#define SAB82532_IPC_CASM 0x04 -#define SAB82532_IPC_IC_OPEN_DRAIN 0x00 -#define SAB82532_IPC_IC_ACT_LOW 0x01 -#define SAB82532_IPC_IC_ACT_HIGH 0x03 - -/* Interrupt Status Register 0 (ISR0) */ -#define SAB82532_ISR0_TCD 0x80 -#define SAB82532_ISR0_TIME 0x40 -#define SAB82532_ISR0_PERR 0x20 -#define SAB82532_ISR0_FERR 0x10 -#define SAB82532_ISR0_PLLA 0x08 -#define SAB82532_ISR0_CDSC 0x04 -#define SAB82532_ISR0_RFO 0x02 -#define SAB82532_ISR0_RPF 0x01 - -/* Interrupt Status Register 1 (ISR1) */ -#define SAB82532_ISR1_BRK 0x80 -#define SAB82532_ISR1_BRKT 0x40 -#define SAB82532_ISR1_ALLS 0x20 -#define SAB82532_ISR1_XOFF 0x10 -#define SAB82532_ISR1_TIN 0x08 -#define SAB82532_ISR1_CSC 0x04 -#define SAB82532_ISR1_XON 0x02 -#define SAB82532_ISR1_XPR 0x01 - -/* Interrupt Mask Register 0 (IMR0) */ -#define SAB82532_IMR0_TCD 0x80 -#define SAB82532_IMR0_TIME 0x40 -#define SAB82532_IMR0_PERR 0x20 -#define SAB82532_IMR0_FERR 0x10 -#define SAB82532_IMR0_PLLA 0x08 -#define SAB82532_IMR0_CDSC 0x04 -#define SAB82532_IMR0_RFO 0x02 -#define SAB82532_IMR0_RPF 0x01 - -/* Interrupt Mask Register 1 (IMR1) */ -#define SAB82532_IMR1_BRK 0x80 -#define SAB82532_IMR1_BRKT 0x40 -#define SAB82532_IMR1_ALLS 0x20 -#define SAB82532_IMR1_XOFF 0x10 -#define SAB82532_IMR1_TIN 0x08 -#define SAB82532_IMR1_CSC 0x04 -#define SAB82532_IMR1_XON 0x02 -#define SAB82532_IMR1_XPR 0x01 - -/* Port Interrupt Status Register (PIS) */ -#define SAB82532_PIS_SYNC_B 0x08 -#define SAB82532_PIS_DTR_B 0x04 -#define SAB82532_PIS_DTR_A 0x02 -#define SAB82532_PIS_SYNC_A 0x01 - -/* Channel Configuration Register 4 (CCR4) */ -#define SAB82532_CCR4_MCK4 0x80 -#define SAB82532_CCR4_EBRG 0x40 -#define SAB82532_CCR4_TST1 0x20 -#define SAB82532_CCR4_ICD 0x10 - - -#endif /* !(_SUNSAB_H) */ diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c deleted file mode 100644 index 551ebfe3ccbb..000000000000 --- a/drivers/serial/sunsu.c +++ /dev/null @@ -1,1608 +0,0 @@ -/* - * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998-1999 Pete Zaitcev (zaitcev@yahoo.com) - * - * This is mainly a variation of 8250.c, credits go to authors mentioned - * therein. In fact this driver should be merged into the generic 8250.c - * infrastructure perhaps using a 8250_sparc.c module. - * - * Fixed to use tty_get_baud_rate(). - * Theodore Ts'o , 2001-Oct-12 - * - * Converted to new 2.5.x UART layer. - * David S. Miller (davem@davemloft.net), 2002-Jul-29 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SERIO -#include -#endif -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -#include "suncore.h" - -/* We are on a NS PC87303 clocked with 24.0 MHz, which results - * in a UART clock of 1.8462 MHz. - */ -#define SU_BASE_BAUD (1846200 / 16) - -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)" }; - -/* - * 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] = { - { "unknown", 1, 0 }, - { "8250", 1, 0 }, - { "16450", 1, 0 }, - { "16550", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "Cirrus", 1, 0 }, - { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, - { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "Startech", 1, 0 }, - { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO } -}; - -struct uart_sunsu_port { - struct uart_port port; - unsigned char acr; - unsigned char ier; - unsigned short rev; - unsigned char lcr; - unsigned int lsr_break_flag; - unsigned int cflag; - - /* Probing information. */ - enum su_type su_type; - unsigned int type_probed; /* XXX Stupid */ - unsigned long reg_size; - -#ifdef CONFIG_SERIO - struct serio serio; - int serio_open; -#endif -}; - -static unsigned int serial_in(struct uart_sunsu_port *up, int offset) -{ - offset <<= up->port.regshift; - - switch (up->port.iotype) { - case UPIO_HUB6: - outb(up->port.hub6 - 1 + offset, up->port.iobase); - return inb(up->port.iobase + 1); - - case UPIO_MEM: - return readb(up->port.membase + offset); - - default: - return inb(up->port.iobase + offset); - } -} - -static void serial_out(struct uart_sunsu_port *up, int offset, int value) -{ -#ifndef CONFIG_SPARC64 - /* - * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are - * connected with a gate then go to SlavIO. When IRQ4 goes tristated - * gate outputs a logical one. Since we use level triggered interrupts - * we have lockup and watchdog reset. We cannot mask IRQ because - * keyboard shares IRQ with us (Word has it as Bob Smelik's design). - * This problem is similar to what Alpha people suffer, see serial.c. - */ - if (offset == UART_MCR) - value |= UART_MCR_OUT2; -#endif - offset <<= up->port.regshift; - - switch (up->port.iotype) { - case UPIO_HUB6: - outb(up->port.hub6 - 1 + offset, up->port.iobase); - outb(value, up->port.iobase + 1); - break; - - case UPIO_MEM: - writeb(value, up->port.membase + offset); - break; - - default: - outb(value, up->port.iobase + offset); - } -} - -/* - * We used to support using pause I/O for certain machines. We - * haven't supported this for a while, but just in case it's badly - * needed for certain old 386 machines, I've left these #define's - * in.... - */ -#define serial_inp(up, offset) serial_in(up, offset) -#define serial_outp(up, offset, value) serial_out(up, offset, value) - - -/* - * For the 16C950 - */ -static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); -} - -#if 0 /* Unused currently */ -static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset) -{ - unsigned int value; - - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); - - return value; -} -#endif - -#ifdef CONFIG_SERIAL_8250_RSA -/* - * Attempts to turn on the RSA FIFO. Returns zero on failure. - * We set the port uart clock rate if we succeed. - */ -static int __enable_rsa(struct uart_sunsu_port *up) -{ - unsigned char mode; - int result; - - mode = serial_inp(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; - - return result; -} - -static void enable_rsa(struct uart_sunsu_port *up) -{ - if (up->port.type == PORT_RSA) { - if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - __enable_rsa(up); - spin_unlock_irq(&up->port.lock); - } - if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_outp(up, UART_RSA_FRR, 0); - } -} - -/* - * Attempts to turn off the RSA FIFO. Returns zero on failure. - * It is unknown why interrupts were disabled in here. However, - * the caller is expected to preserve this behaviour by grabbing - * the spinlock before calling this function. - */ -static void disable_rsa(struct uart_sunsu_port *up) -{ - unsigned char mode; - int result; - - if (up->port.type == PORT_RSA && - up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - - mode = serial_inp(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_inp(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); - } -} -#endif /* CONFIG_SERIAL_8250_RSA */ - -static inline void __stop_tx(struct uart_sunsu_port *p) -{ - if (p->ier & UART_IER_THRI) { - p->ier &= ~UART_IER_THRI; - serial_out(p, UART_IER, p->ier); - } -} - -static void sunsu_stop_tx(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - - __stop_tx(up); - - /* - * We really want to stop the transmitter from sending. - */ - if (up->port.type == PORT_16C950) { - up->acr |= UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void sunsu_start_tx(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } - - /* - * Re-enable the transmitter if we disabled it. - */ - if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { - up->acr &= ~UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void sunsu_stop_rx(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); -} - -static void sunsu_enable_ms(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static struct tty_struct * -receive_chars(struct uart_sunsu_port *up, unsigned char *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned char ch, flag; - int max_count = 256; - int saw_console_brk = 0; - - do { - ch = serial_inp(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - /* - * For statistics only - */ - if (*status & UART_LSR_BI) { - *status &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - if (up->port.cons != NULL && - up->port.line == up->port.cons->index) - saw_console_brk = 1; - /* - * 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 (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ingored. - */ - *status &= up->port.read_status_mask; - - if (up->port.cons != NULL && - up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } - - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - if ((*status & up->port.ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); - if (*status & UART_LSR_OE) - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - ignore_char: - *status = serial_inp(up, UART_LSR); - } while ((*status & UART_LSR_DR) && (max_count-- > 0)); - - if (saw_console_brk) - sun_do_break(); - - return tty; -} - -static void transmit_chars(struct uart_sunsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_outp(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_tx_stopped(&up->port)) { - sunsu_stop_tx(&up->port); - return; - } - if (uart_circ_empty(xmit)) { - __stop_tx(up); - return; - } - - count = up->port.fifosize; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - __stop_tx(up); -} - -static void check_modem_status(struct uart_sunsu_port *up) -{ - int status; - - status = serial_in(up, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) -{ - struct uart_sunsu_port *up = dev_id; - unsigned long flags; - unsigned char status; - - spin_lock_irqsave(&up->port.lock, flags); - - do { - struct tty_struct *tty; - - status = serial_inp(up, UART_LSR); - tty = NULL; - if (status & UART_LSR_DR) - tty = receive_chars(up, &status); - check_modem_status(up); - if (status & UART_LSR_THRE) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - - if (tty) - tty_flip_buffer_push(tty); - - spin_lock_irqsave(&up->port.lock, flags); - - } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); - - spin_unlock_irqrestore(&up->port.lock, flags); - - return IRQ_HANDLED; -} - -/* Separate interrupt handling path for keyboard/mouse ports. */ - -static void -sunsu_change_speed(struct uart_port *port, unsigned int cflag, - unsigned int iflag, unsigned int quot); - -static void sunsu_change_mouse_baud(struct uart_sunsu_port *up) -{ - unsigned int cur_cflag = up->cflag; - int quot, new_baud; - - up->cflag &= ~CBAUD; - up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud); - - quot = up->port.uartclk / (16 * new_baud); - - sunsu_change_speed(&up->port, up->cflag, 0, quot); -} - -static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) -{ - do { - unsigned char ch = serial_inp(up, UART_RX); - - /* Stop-A is handled by drivers/char/keyboard.c now. */ - if (up->su_type == SU_PORT_KBD) { -#ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0); -#endif - } else if (up->su_type == SU_PORT_MS) { - int ret = suncore_mouse_baud_detection(ch, is_break); - - switch (ret) { - case 2: - sunsu_change_mouse_baud(up); - /* fallthru */ - case 1: - break; - - case 0: -#ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0); -#endif - break; - }; - } - } while (serial_in(up, UART_LSR) & UART_LSR_DR); -} - -static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id) -{ - struct uart_sunsu_port *up = dev_id; - - if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) { - unsigned char status = serial_inp(up, UART_LSR); - - if ((status & UART_LSR_DR) || (status & UART_LSR_BI)) - receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0); - } - - return IRQ_HANDLED; -} - -static unsigned int sunsu_tx_empty(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned long flags; - unsigned int ret; - - 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); - - return ret; -} - -static unsigned int sunsu_get_mctrl(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned char status; - unsigned int ret; - - status = serial_in(up, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - serial_out(up, UART_MCR, mcr); -} - -static void sunsu_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static int sunsu_startup(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned long flags; - int retval; - - if (up->port.type == PORT_16C950) { - /* Wake up and initialize UART */ - up->acr = 0; - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_IER, 0); - serial_outp(up, UART_LCR, 0); - serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, UART_EFR_ECB); - serial_outp(up, UART_LCR, 0); - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - enable_rsa(up); -#endif - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); - } - - /* - * Clear the interrupt registers. - */ - (void) serial_inp(up, UART_LSR); - (void) serial_inp(up, UART_RX); - (void) serial_inp(up, UART_IIR); - (void) serial_inp(up, UART_MSR); - - /* - * At this point, there's no way the LSR could still be 0xff; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(up->port.flags & UPF_BUGGY_UART) && - (serial_inp(up, UART_LSR) == 0xff)) { - printk("ttyS%d: LSR safety check engaged!\n", up->port.line); - return -ENODEV; - } - - if (up->su_type != SU_PORT_PORT) { - retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt, - IRQF_SHARED, su_typev[up->su_type], up); - } else { - retval = request_irq(up->port.irq, sunsu_serial_interrupt, - IRQF_SHARED, su_typev[up->su_type], up); - } - if (retval) { - printk("su: Cannot register IRQ %d\n", up->port.irq); - return retval; - } - - /* - * Now, initialize the UART - */ - serial_outp(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - - up->port.mctrl |= TIOCM_OUT2; - - sunsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_outp(up, UART_IER, up->ier); - - if (up->port.flags & UPF_FOURPORT) { - unsigned int icp; - /* - * Enable interrupts on the AST Fourport board - */ - icp = (up->port.iobase & 0xfe0) | 0x01f; - outb_p(0x80, icp); - (void) inb_p(icp); - } - - /* - * And clear the interrupt registers again for luck. - */ - (void) serial_inp(up, UART_LSR); - (void) serial_inp(up, UART_RX); - (void) serial_inp(up, UART_IIR); - (void) serial_inp(up, UART_MSR); - - return 0; -} - -static void sunsu_shutdown(struct uart_port *port) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned long flags; - - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_outp(up, UART_IER, 0); - - spin_lock_irqsave(&up->port.lock, flags); - if (up->port.flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((up->port.iobase & 0xfe0) | 0x1f); - up->port.mctrl |= TIOCM_OUT1; - } else - up->port.mctrl &= ~TIOCM_OUT2; - - sunsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_outp(up, UART_FCR, 0); - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - disable_rsa(up); -#endif - - /* - * Read data port to reset things. - */ - (void) serial_in(up, UART_RX); - - free_irq(up->port.irq, up); -} - -static void -sunsu_change_speed(struct uart_port *port, unsigned int cflag, - unsigned int iflag, unsigned int quot) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - unsigned char cval, fcr = 0; - unsigned long flags; - - switch (cflag & CSIZE) { - case CS5: - cval = 0x00; - break; - case CS6: - cval = 0x01; - break; - case CS7: - cval = 0x02; - break; - default: - case CS8: - cval = 0x03; - break; - } - - if (cflag & CSTOPB) - cval |= 0x04; - if (cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - /* - * Work around a bug in the Oxford Semiconductor 952 rev B - * chip which causes it to seriously miscalculate baud rates - * when DLL is 0. - */ - if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 && - up->rev == 0x5201) - quot ++; - - if (uart_config[up->port.type].flags & UART_USE_FIFO) { - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; -#ifdef CONFIG_SERIAL_8250_RSA - else if (up->port.type == PORT_RSA) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; -#endif - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; - } - if (up->port.type == PORT_16750) - fcr |= UART_FCR7_64BYTE; - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, cflag, (port->uartclk / (16 * quot))); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ - up->port.ignore_status_mask = 0; - if (iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - if (uart_config[up->port.type].flags & UART_STARTECH) { - serial_outp(up, UART_LCR, 0xBF); - serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0); - } - serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ - if (up->port.type == PORT_16750) - serial_outp(up, UART_FCR, fcr); /* set fcr */ - serial_outp(up, UART_LCR, cval); /* reset DLAB */ - up->lcr = cval; /* Save LCR */ - if (up->port.type != PORT_16750) { - if (fcr & UART_FCR_ENABLE_FIFO) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - } - serial_outp(up, UART_FCR, fcr); /* set fcr */ - } - - up->cflag = cflag; - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -sunsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud, quot; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot); -} - -static void sunsu_release_port(struct uart_port *port) -{ -} - -static int sunsu_request_port(struct uart_port *port) -{ - return 0; -} - -static void sunsu_config_port(struct uart_port *port, int flags) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; - - if (flags & UART_CONFIG_TYPE) { - /* - * We are supposed to call autoconfig here, but this requires - * splitting all the OBP probing crap from the UART probing. - * We'll do it when we kill sunsu.c altogether. - */ - port->type = up->type_probed; /* XXX */ - } -} - -static int -sunsu_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -static const char * -sunsu_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 sunsu_pops = { - .tx_empty = sunsu_tx_empty, - .set_mctrl = sunsu_set_mctrl, - .get_mctrl = sunsu_get_mctrl, - .stop_tx = sunsu_stop_tx, - .start_tx = sunsu_start_tx, - .stop_rx = sunsu_stop_rx, - .enable_ms = sunsu_enable_ms, - .break_ctl = sunsu_break_ctl, - .startup = sunsu_startup, - .shutdown = sunsu_shutdown, - .set_termios = sunsu_set_termios, - .type = sunsu_type, - .release_port = sunsu_release_port, - .request_port = sunsu_request_port, - .config_port = sunsu_config_port, - .verify_port = sunsu_verify_port, -}; - -#define UART_NR 4 - -static struct uart_sunsu_port sunsu_ports[UART_NR]; - -#ifdef CONFIG_SERIO - -static DEFINE_SPINLOCK(sunsu_serio_lock); - -static int sunsu_serio_write(struct serio *serio, unsigned char ch) -{ - struct uart_sunsu_port *up = serio->port_data; - unsigned long flags; - int lsr; - - spin_lock_irqsave(&sunsu_serio_lock, flags); - - do { - lsr = serial_in(up, UART_LSR); - } while (!(lsr & UART_LSR_THRE)); - - /* Send the character out. */ - serial_out(up, UART_TX, ch); - - spin_unlock_irqrestore(&sunsu_serio_lock, flags); - - return 0; -} - -static int sunsu_serio_open(struct serio *serio) -{ - struct uart_sunsu_port *up = serio->port_data; - unsigned long flags; - int ret; - - spin_lock_irqsave(&sunsu_serio_lock, flags); - if (!up->serio_open) { - up->serio_open = 1; - ret = 0; - } else - ret = -EBUSY; - spin_unlock_irqrestore(&sunsu_serio_lock, flags); - - return ret; -} - -static void sunsu_serio_close(struct serio *serio) -{ - struct uart_sunsu_port *up = serio->port_data; - unsigned long flags; - - spin_lock_irqsave(&sunsu_serio_lock, flags); - up->serio_open = 0; - spin_unlock_irqrestore(&sunsu_serio_lock, flags); -} - -#endif /* CONFIG_SERIO */ - -static void sunsu_autoconfig(struct uart_sunsu_port *up) -{ - unsigned char status1, status2, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - unsigned long flags; - - if (up->su_type == SU_PORT_NONE) - return; - - up->type_probed = PORT_UNKNOWN; - up->port.iotype = UPIO_MEM; - - spin_lock_irqsave(&up->port.lock, flags); - - if (!(up->port.flags & UPF_BUGGY_UART)) { - /* - * Do a simple existence test first; if we fail this, there's - * no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against false - * positives due to ISA bus float. The assumption is that - * 0x80 is a non-existent port; which should be safe since - * include/asm/io.h also makes this assumption. - */ - scratch = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, 0x0f); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_inp(up, UART_IER); - serial_outp(up, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) - goto out; /* We failed; there's nothing here */ - } - - save_mcr = serial_in(up, UART_MCR); - save_lcr = serial_in(up, UART_LCR); - - /* - * Check to see if a UART is really there. Certain broken - * internal modems based on the Rockwell chipset fail this - * test, because they apparently don't implement the loopback - * test mode. So this test is skipped on the COM 1 through - * COM 4 ports. This *should* be safe, since no board - * manufacturer would be stupid enough to design a board - * that conflicts with COM 1-4 --- we hope! - */ - if (!(up->port.flags & UPF_SKIP_TEST)) { - serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(up, UART_MSR) & 0xF0; - serial_outp(up, UART_MCR, save_mcr); - if (status1 != 0x90) - goto out; /* We failed loopback test */ - } - serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */ - serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */ - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(up, UART_IIR) >> 6; - switch (scratch) { - case 0: - up->port.type = PORT_16450; - break; - case 1: - up->port.type = PORT_UNKNOWN; - break; - case 2: - up->port.type = PORT_16550; - break; - case 3: - up->port.type = PORT_16550A; - break; - } - if (up->port.type == PORT_16550A) { - /* Check for Startech UART's */ - serial_outp(up, UART_LCR, UART_LCR_DLAB); - if (serial_in(up, UART_EFR) == 0) { - up->port.type = PORT_16650; - } else { - serial_outp(up, UART_LCR, 0xBF); - if (serial_in(up, UART_EFR) == 0) - up->port.type = PORT_16650V2; - } - } - if (up->port.type == PORT_16550A) { - /* Check for TI 16750 */ - serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB); - serial_outp(up, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(up, UART_IIR) >> 5; - if (scratch == 7) { - /* - * If this is a 16750, and not a cheap UART - * clone, then it should only go into 64 byte - * mode if the UART_FCR7_64BYTE bit was set - * while UART_LCR_DLAB was latched. - */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(up, UART_IIR) >> 5; - if (scratch == 6) - up->port.type = PORT_16750; - } - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - } - serial_outp(up, UART_LCR, save_lcr); - if (up->port.type == PORT_16450) { - scratch = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0xa5); - status1 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0x5a); - status2 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, scratch); - - if ((status1 != 0xa5) || (status2 != 0x5a)) - up->port.type = PORT_8250; - } - - up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; - - if (up->port.type == PORT_UNKNOWN) - goto out; - up->type_probed = up->port.type; /* XXX */ - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_8250_RSA - if (up->port.type == PORT_RSA) - serial_outp(up, UART_RSA_FRR, 0); -#endif - serial_outp(up, UART_MCR, save_mcr); - serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(up, UART_FCR, 0); - (void)serial_in(up, UART_RX); - serial_outp(up, UART_IER, 0); - -out: - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static struct uart_driver sunsu_reg = { - .owner = THIS_MODULE, - .driver_name = "sunsu", - .dev_name = "ttyS", - .major = TTY_MAJOR, -}; - -static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up) -{ - int quot, baud; -#ifdef CONFIG_SERIO - struct serio *serio; -#endif - - if (up->su_type == SU_PORT_KBD) { - up->cflag = B1200 | CS8 | CLOCAL | CREAD; - baud = 1200; - } else { - up->cflag = B4800 | CS8 | CLOCAL | CREAD; - baud = 4800; - } - quot = up->port.uartclk / (16 * baud); - - sunsu_autoconfig(up); - if (up->port.type == PORT_UNKNOWN) - return -ENODEV; - - printk("%s: %s port at %llx, irq %u\n", - up->port.dev->of_node->full_name, - (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse", - (unsigned long long) up->port.mapbase, - up->port.irq); - -#ifdef CONFIG_SERIO - serio = &up->serio; - serio->port_data = up; - - serio->id.type = SERIO_RS232; - if (up->su_type == SU_PORT_KBD) { - serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "sukbd", sizeof(serio->name)); - } else { - serio->id.proto = SERIO_SUN; - serio->id.extra = 1; - strlcpy(serio->name, "sums", sizeof(serio->name)); - } - strlcpy(serio->phys, - (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), - sizeof(serio->phys)); - - serio->write = sunsu_serio_write; - serio->open = sunsu_serio_open; - serio->close = sunsu_serio_close; - serio->dev.parent = up->port.dev; - - serio_register_port(serio); -#endif - - sunsu_change_speed(&up->port, up->cflag, 0, quot); - - sunsu_startup(&up->port); - return 0; -} - -/* - * ------------------------------------------------------------ - * Serial console driver - * ------------------------------------------------------------ - */ - -#ifdef CONFIG_SERIAL_SUNSU_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* - * Wait for transmitter & holding register to empty - */ -static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) - udelay(1); - } -} - -static void sunsu_console_putchar(struct uart_port *port, int ch) -{ - struct uart_sunsu_port *up = (struct uart_sunsu_port *)port; - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void sunsu_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_sunsu_port *up = &sunsu_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - 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 UER then disable the interrupts - */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, sunsu_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -/* - * Setup initial baud/bits/parity. We do two things here: - * - construct a cflag setting for the first su_open() - * - initialize the serial port - * Return non-zero if we didn't find a serial port. - */ -static int __init sunsu_console_setup(struct console *co, char *options) -{ - static struct ktermios dummy; - struct ktermios termios; - struct uart_port *port; - - printk("Console: ttyS%d (SU)\n", - (sunsu_reg.minor - 64) + co->index); - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index >= UART_NR) - co->index = 0; - port = &sunsu_ports[co->index].port; - - /* - * Temporary fix. - */ - spin_lock_init(&port->lock); - - /* Get firmware console settings. */ - sunserial_console_termios(co, port->dev->of_node); - - memset(&termios, 0, sizeof(struct ktermios)); - termios.c_cflag = co->cflag; - port->mctrl |= TIOCM_DTR; - port->ops->set_termios(port, &termios, &dummy); - - return 0; -} - -static struct console sunsu_console = { - .name = "ttyS", - .write = sunsu_console_write, - .device = uart_console_device, - .setup = sunsu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sunsu_reg, -}; - -/* - * Register console. - */ - -static inline struct console *SUNSU_CONSOLE(void) -{ - return &sunsu_console; -} -#else -#define SUNSU_CONSOLE() (NULL) -#define sunsu_serial_console_init() do { } while (0) -#endif - -static enum su_type __devinit su_get_type(struct device_node *dp) -{ - struct device_node *ap = of_find_node_by_path("/aliases"); - - if (ap) { - const char *keyb = of_get_property(ap, "keyboard", NULL); - const char *ms = of_get_property(ap, "mouse", NULL); - - if (keyb) { - if (dp == of_find_node_by_path(keyb)) - return SU_PORT_KBD; - } - if (ms) { - if (dp == of_find_node_by_path(ms)) - return SU_PORT_MS; - } - } - - return SU_PORT_PORT; -} - -static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match) -{ - static int inst; - struct device_node *dp = op->dev.of_node; - struct uart_sunsu_port *up; - struct resource *rp; - enum su_type type; - bool ignore_line; - int err; - - type = su_get_type(dp); - if (type == SU_PORT_PORT) { - if (inst >= UART_NR) - return -EINVAL; - up = &sunsu_ports[inst]; - } else { - up = kzalloc(sizeof(*up), GFP_KERNEL); - if (!up) - return -ENOMEM; - } - - up->port.line = inst; - - spin_lock_init(&up->port.lock); - - up->su_type = type; - - rp = &op->resource[0]; - up->port.mapbase = rp->start; - up->reg_size = (rp->end - rp->start) + 1; - up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); - if (!up->port.membase) { - if (type != SU_PORT_PORT) - kfree(up); - return -ENOMEM; - } - - up->port.irq = op->archdata.irqs[0]; - - up->port.dev = &op->dev; - - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); - - err = 0; - if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) { - err = sunsu_kbd_ms_init(up); - if (err) { - of_iounmap(&op->resource[0], - up->port.membase, up->reg_size); - kfree(up); - return err; - } - dev_set_drvdata(&op->dev, up); - - return 0; - } - - up->port.flags |= UPF_BOOT_AUTOCONF; - - sunsu_autoconfig(up); - - err = -ENODEV; - if (up->port.type == PORT_UNKNOWN) - goto out_unmap; - - up->port.ops = &sunsu_pops; - - ignore_line = false; - if (!strcmp(dp->name, "rsc-console") || - !strcmp(dp->name, "lom-console")) - ignore_line = true; - - sunserial_console_match(SUNSU_CONSOLE(), dp, - &sunsu_reg, up->port.line, - ignore_line); - err = uart_add_one_port(&sunsu_reg, &up->port); - if (err) - goto out_unmap; - - dev_set_drvdata(&op->dev, up); - - inst++; - - return 0; - -out_unmap: - of_iounmap(&op->resource[0], up->port.membase, up->reg_size); - return err; -} - -static int __devexit su_remove(struct platform_device *op) -{ - struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); - bool kbdms = false; - - if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) - kbdms = true; - - if (kbdms) { -#ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); -#endif - } else if (up->port.type != PORT_UNKNOWN) - uart_remove_one_port(&sunsu_reg, &up->port); - - if (up->port.membase) - of_iounmap(&op->resource[0], up->port.membase, up->reg_size); - - if (kbdms) - kfree(up); - - dev_set_drvdata(&op->dev, NULL); - - return 0; -} - -static const struct of_device_id su_match[] = { - { - .name = "su", - }, - { - .name = "su_pnp", - }, - { - .name = "serial", - .compatible = "su", - }, - { - .type = "serial", - .compatible = "su", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, su_match); - -static struct of_platform_driver su_driver = { - .driver = { - .name = "su", - .owner = THIS_MODULE, - .of_match_table = su_match, - }, - .probe = su_probe, - .remove = __devexit_p(su_remove), -}; - -static int __init sunsu_init(void) -{ - struct device_node *dp; - int err; - int num_uart = 0; - - for_each_node_by_name(dp, "su") { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } - for_each_node_by_name(dp, "su_pnp") { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } - for_each_node_by_name(dp, "serial") { - if (of_device_is_compatible(dp, "su")) { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } - } - for_each_node_by_type(dp, "serial") { - if (of_device_is_compatible(dp, "su")) { - if (su_get_type(dp) == SU_PORT_PORT) - num_uart++; - } - } - - if (num_uart) { - err = sunserial_register_minors(&sunsu_reg, num_uart); - if (err) - return err; - } - - err = of_register_platform_driver(&su_driver); - if (err && num_uart) - sunserial_unregister_minors(&sunsu_reg, num_uart); - - return err; -} - -static void __exit sunsu_exit(void) -{ - if (sunsu_reg.nr) - sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr); -} - -module_init(sunsu_init); -module_exit(sunsu_exit); - -MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller"); -MODULE_DESCRIPTION("Sun SU serial port driver"); -MODULE_VERSION("2.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c deleted file mode 100644 index c1967ac1c07f..000000000000 --- a/drivers/serial/sunzilog.c +++ /dev/null @@ -1,1655 +0,0 @@ -/* sunzilog.c: Zilog serial driver for Sparc systems. - * - * Driver for Zilog serial chips found on Sun workstations and - * servers. This driver could actually be made more generic. - * - * This is based on the old drivers/sbus/char/zs.c code. A lot - * of code has been simply moved over directly from there but - * much has been rewritten. Credits therefore go out to Eddie - * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their - * work there. - * - * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SERIO -#include -#endif -#include -#include - -#include -#include -#include - -#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - -#include "suncore.h" -#include "sunzilog.h" - -/* On 32-bit sparcs we need to delay after register accesses - * to accommodate sun4 systems, but we do not need to flush writes. - * On 64-bit sparc we only need to flush single writes to ensure - * completion. - */ -#ifndef CONFIG_SPARC64 -#define ZSDELAY() udelay(5) -#define ZSDELAY_LONG() udelay(20) -#define ZS_WSYNC(channel) do { } while (0) -#else -#define ZSDELAY() -#define ZSDELAY_LONG() -#define ZS_WSYNC(__channel) \ - readb(&((__channel)->control)) -#endif - -#define ZS_CLOCK 4915200 /* Zilog input clock rate. */ -#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ - -/* - * We wrap our port structure around the generic uart_port. - */ -struct uart_sunzilog_port { - struct uart_port port; - - /* IRQ servicing chain. */ - struct uart_sunzilog_port *next; - - /* Current values of Zilog write registers. */ - unsigned char curregs[NUM_ZSREGS]; - - unsigned int flags; -#define SUNZILOG_FLAG_CONS_KEYB 0x00000001 -#define SUNZILOG_FLAG_CONS_MOUSE 0x00000002 -#define SUNZILOG_FLAG_IS_CONS 0x00000004 -#define SUNZILOG_FLAG_IS_KGDB 0x00000008 -#define SUNZILOG_FLAG_MODEM_STATUS 0x00000010 -#define SUNZILOG_FLAG_IS_CHANNEL_A 0x00000020 -#define SUNZILOG_FLAG_REGS_HELD 0x00000040 -#define SUNZILOG_FLAG_TX_STOPPED 0x00000080 -#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100 -#define SUNZILOG_FLAG_ESCC 0x00000200 -#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400 - - unsigned int cflag; - - unsigned char parity_mask; - unsigned char prev_status; - -#ifdef CONFIG_SERIO - struct serio serio; - int serio_open; -#endif -}; - -static void sunzilog_putchar(struct uart_port *port, int ch); - -#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) -#define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) - -#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB) -#define ZS_IS_MOUSE(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE) -#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS) -#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB) -#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS) -#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A) -#define ZS_REGS_HELD(UP) ((UP)->flags & SUNZILOG_FLAG_REGS_HELD) -#define ZS_TX_STOPPED(UP) ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED) -#define ZS_TX_ACTIVE(UP) ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE) - -/* Reading and writing Zilog8530 registers. The delays are to make this - * driver work on the Sun4 which needs a settling delay after each chip - * register access, other machines handle this in hardware via auxiliary - * flip-flops which implement the settle time we do in software. - * - * The port lock must be held and local IRQs must be disabled - * when {read,write}_zsreg is invoked. - */ -static unsigned char read_zsreg(struct zilog_channel __iomem *channel, - unsigned char reg) -{ - unsigned char retval; - - writeb(reg, &channel->control); - ZSDELAY(); - retval = readb(&channel->control); - ZSDELAY(); - - return retval; -} - -static void write_zsreg(struct zilog_channel __iomem *channel, - unsigned char reg, unsigned char value) -{ - writeb(reg, &channel->control); - ZSDELAY(); - writeb(value, &channel->control); - ZSDELAY(); -} - -static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) -{ - int i; - - for (i = 0; i < 32; i++) { - unsigned char regval; - - regval = readb(&channel->control); - ZSDELAY(); - if (regval & Rx_CH_AV) - break; - - regval = read_zsreg(channel, R1); - readb(&channel->data); - ZSDELAY(); - - if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - } - } -} - -/* This function must only be called when the TX is not busy. The UART - * port lock must be held and local interrupts disabled. - */ -static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) -{ - int i; - int escc; - unsigned char r15; - - /* Let pending transmits finish. */ - for (i = 0; i < 1000; i++) { - unsigned char stat = read_zsreg(channel, R1); - if (stat & ALL_SNT) - break; - udelay(100); - } - - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - sunzilog_clear_fifo(channel); - - /* Disable all interrupts. */ - write_zsreg(channel, R1, - regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); - - /* Set parity, sync config, stop bits, and clock divisor. */ - write_zsreg(channel, R4, regs[R4]); - - /* Set misc. TX/RX control bits. */ - write_zsreg(channel, R10, regs[R10]); - - /* Set TX/RX controls sans the enable bits. */ - write_zsreg(channel, R3, regs[R3] & ~RxENAB); - write_zsreg(channel, R5, regs[R5] & ~TxENAB); - - /* Synchronous mode config. */ - write_zsreg(channel, R6, regs[R6]); - write_zsreg(channel, R7, regs[R7]); - - /* Don't mess with the interrupt vector (R2, unused by us) and - * master interrupt control (R9). We make sure this is setup - * properly at probe time then never touch it again. - */ - - /* Disable baud generator. */ - write_zsreg(channel, R14, regs[R14] & ~BRENAB); - - /* Clock mode control. */ - write_zsreg(channel, R11, regs[R11]); - - /* Lower and upper byte of baud rate generator divisor. */ - write_zsreg(channel, R12, regs[R12]); - write_zsreg(channel, R13, regs[R13]); - - /* Now rewrite R14, with BRENAB (if set). */ - write_zsreg(channel, R14, regs[R14]); - - /* External status interrupt control. */ - write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN); - - /* ESCC Extension Register */ - r15 = read_zsreg(channel, R15); - if (r15 & 0x01) { - write_zsreg(channel, R7, regs[R7p]); - - /* External status interrupt and FIFO control. */ - write_zsreg(channel, R15, regs[R15] & ~WR7pEN); - escc = 1; - } else { - /* Clear FIFO bit case it is an issue */ - regs[R15] &= ~FIFOEN; - escc = 0; - } - - /* Reset external status interrupts. */ - write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */ - write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */ - - /* Rewrite R3/R5, this time without enables masked. */ - write_zsreg(channel, R3, regs[R3]); - write_zsreg(channel, R5, regs[R5]); - - /* Rewrite R1, this time without IRQ enabled masked. */ - write_zsreg(channel, R1, regs[R1]); - - return escc; -} - -/* Reprogram the Zilog channel HW registers with the copies found in the - * software state struct. If the transmitter is busy, we defer this update - * until the next TX complete interrupt. Else, we do it right now. - * - * The UART port lock must be held and local interrupts disabled. - */ -static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up, - struct zilog_channel __iomem *channel) -{ - if (!ZS_REGS_HELD(up)) { - if (ZS_TX_ACTIVE(up)) { - up->flags |= SUNZILOG_FLAG_REGS_HELD; - } else { - __load_zsregs(channel, up->curregs); - } - } -} - -static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up) -{ - unsigned int cur_cflag = up->cflag; - int brg, new_baud; - - up->cflag &= ~CBAUD; - up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud); - - brg = BPS_TO_BRG(new_baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(&up->port)); -} - -static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, - unsigned char ch, int is_break) -{ - if (ZS_IS_KEYB(up)) { - /* Stop-A is handled by drivers/char/keyboard.c now. */ -#ifdef CONFIG_SERIO - if (up->serio_open) - serio_interrupt(&up->serio, ch, 0); -#endif - } else if (ZS_IS_MOUSE(up)) { - int ret = suncore_mouse_baud_detection(ch, is_break); - - switch (ret) { - case 2: - sunzilog_change_mouse_baud(up); - /* fallthru */ - case 1: - break; - - case 0: -#ifdef CONFIG_SERIO - if (up->serio_open) - serio_interrupt(&up->serio, ch, 0); -#endif - break; - }; - } -} - -static struct tty_struct * -sunzilog_receive_chars(struct uart_sunzilog_port *up, - struct zilog_channel __iomem *channel) -{ - struct tty_struct *tty; - unsigned char ch, r1, flag; - - tty = NULL; - if (up->port.state != NULL && /* Unopened serial console */ - up->port.state->port.tty != NULL) /* Keyboard || mouse */ - tty = up->port.state->port.tty; - - for (;;) { - - r1 = read_zsreg(channel, R1); - if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - } - - ch = readb(&channel->control); - ZSDELAY(); - - /* This funny hack depends upon BRK_ABRT not interfering - * with the other bits we care about in R1. - */ - if (ch & BRK_ABRT) - r1 |= BRK_ABRT; - - if (!(ch & Rx_CH_AV)) - break; - - ch = readb(&channel->data); - ZSDELAY(); - - ch &= up->parity_mask; - - if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) { - sunzilog_kbdms_receive_chars(up, ch, 0); - continue; - } - - if (tty == NULL) { - uart_handle_sysrq_char(&up->port, ch); - continue; - } - - /* A real serial line, record the character and status. */ - flag = TTY_NORMAL; - up->port.icount.rx++; - if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) { - if (r1 & BRK_ABRT) { - r1 &= ~(PAR_ERR | CRC_ERR); - up->port.icount.brk++; - if (uart_handle_break(&up->port)) - continue; - } - else if (r1 & PAR_ERR) - up->port.icount.parity++; - else if (r1 & CRC_ERR) - up->port.icount.frame++; - if (r1 & Rx_OVR) - up->port.icount.overrun++; - r1 &= up->port.read_status_mask; - if (r1 & BRK_ABRT) - flag = TTY_BREAK; - else if (r1 & PAR_ERR) - flag = TTY_PARITY; - else if (r1 & CRC_ERR) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(&up->port, ch)) - continue; - - if (up->port.ignore_status_mask == 0xff || - (r1 & up->port.ignore_status_mask) == 0) { - tty_insert_flip_char(tty, ch, flag); - } - if (r1 & Rx_OVR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - return tty; -} - -static void sunzilog_status_handle(struct uart_sunzilog_port *up, - struct zilog_channel __iomem *channel) -{ - unsigned char status; - - status = readb(&channel->control); - ZSDELAY(); - - writeb(RES_EXT_INT, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (status & BRK_ABRT) { - if (ZS_IS_MOUSE(up)) - sunzilog_kbdms_receive_chars(up, 0, 1); - if (ZS_IS_CONS(up)) { - /* Wait for BREAK to deassert to avoid potentially - * confusing the PROM. - */ - while (1) { - status = readb(&channel->control); - ZSDELAY(); - if (!(status & BRK_ABRT)) - break; - } - sun_do_break(); - return; - } - } - - if (ZS_WANTS_MODEM_STATUS(up)) { - if (status & SYNC) - up->port.icount.dsr++; - - /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. - * But it does not tell us which bit has changed, we have to keep - * track of this ourselves. - */ - if ((status ^ up->prev_status) ^ DCD) - uart_handle_dcd_change(&up->port, - (status & DCD)); - if ((status ^ up->prev_status) ^ CTS) - uart_handle_cts_change(&up->port, - (status & CTS)); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); - } - - up->prev_status = status; -} - -static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, - struct zilog_channel __iomem *channel) -{ - struct circ_buf *xmit; - - if (ZS_IS_CONS(up)) { - unsigned char status = readb(&channel->control); - ZSDELAY(); - - /* TX still busy? Just wait for the next TX done interrupt. - * - * It can occur because of how we do serial console writes. It would - * be nice to transmit console writes just like we normally would for - * a TTY line. (ie. buffered and TX interrupt driven). That is not - * easy because console writes cannot sleep. One solution might be - * to poll on enough port->xmit space becomming free. -DaveM - */ - if (!(status & Tx_BUF_EMP)) - return; - } - - up->flags &= ~SUNZILOG_FLAG_TX_ACTIVE; - - if (ZS_REGS_HELD(up)) { - __load_zsregs(channel, up->curregs); - up->flags &= ~SUNZILOG_FLAG_REGS_HELD; - } - - if (ZS_TX_STOPPED(up)) { - up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; - goto ack_tx_int; - } - - if (up->port.x_char) { - up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(up->port.x_char, &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - - if (up->port.state == NULL) - goto ack_tx_int; - xmit = &up->port.state->xmit; - if (uart_circ_empty(xmit)) - goto ack_tx_int; - - if (uart_tx_stopped(&up->port)) - goto ack_tx_int; - - up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - writeb(xmit->buf[xmit->tail], &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - return; - -ack_tx_int: - writeb(RES_Tx_P, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); -} - -static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) -{ - struct uart_sunzilog_port *up = dev_id; - - while (up) { - struct zilog_channel __iomem *channel - = ZILOG_CHANNEL_FROM_PORT(&up->port); - struct tty_struct *tty; - unsigned char r3; - - spin_lock(&up->port.lock); - r3 = read_zsreg(channel, R3); - - /* Channel A */ - tty = NULL; - if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (r3 & CHARxIP) - tty = sunzilog_receive_chars(up, channel); - if (r3 & CHAEXT) - sunzilog_status_handle(up, channel); - if (r3 & CHATxIP) - sunzilog_transmit_chars(up, channel); - } - spin_unlock(&up->port.lock); - - if (tty) - tty_flip_buffer_push(tty); - - /* Channel B */ - up = up->next; - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - - spin_lock(&up->port.lock); - tty = NULL; - if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - writeb(RES_H_IUS, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - - if (r3 & CHBRxIP) - tty = sunzilog_receive_chars(up, channel); - if (r3 & CHBEXT) - sunzilog_status_handle(up, channel); - if (r3 & CHBTxIP) - sunzilog_transmit_chars(up, channel); - } - spin_unlock(&up->port.lock); - - if (tty) - tty_flip_buffer_push(tty); - - up = up->next; - } - - return IRQ_HANDLED; -} - -/* A convenient way to quickly get R0 status. The caller must _not_ hold the - * port lock, it is acquired here. - */ -static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port) -{ - struct zilog_channel __iomem *channel; - unsigned char status; - - channel = ZILOG_CHANNEL_FROM_PORT(port); - status = readb(&channel->control); - ZSDELAY(); - - return status; -} - -/* The port lock is not held. */ -static unsigned int sunzilog_tx_empty(struct uart_port *port) -{ - unsigned long flags; - unsigned char status; - unsigned int ret; - - spin_lock_irqsave(&port->lock, flags); - - status = sunzilog_read_channel_status(port); - - spin_unlock_irqrestore(&port->lock, flags); - - if (status & Tx_BUF_EMP) - ret = TIOCSER_TEMT; - else - ret = 0; - - return ret; -} - -/* The port lock is held and interrupts are disabled. */ -static unsigned int sunzilog_get_mctrl(struct uart_port *port) -{ - unsigned char status; - unsigned int ret; - - status = sunzilog_read_channel_status(port); - - ret = 0; - if (status & DCD) - ret |= TIOCM_CAR; - if (status & SYNC) - ret |= TIOCM_DSR; - if (status & CTS) - ret |= TIOCM_CTS; - - return ret; -} - -/* The port lock is held and interrupts are disabled. */ -static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char set_bits, clear_bits; - - set_bits = clear_bits = 0; - - if (mctrl & TIOCM_RTS) - set_bits |= RTS; - else - clear_bits |= RTS; - if (mctrl & TIOCM_DTR) - set_bits |= DTR; - else - clear_bits |= DTR; - - /* NOTE: Not subject to 'transmitter active' rule. */ - up->curregs[R5] |= set_bits; - up->curregs[R5] &= ~clear_bits; - write_zsreg(channel, R5, up->curregs[R5]); -} - -/* The port lock is held and interrupts are disabled. */ -static void sunzilog_stop_tx(struct uart_port *port) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - - up->flags |= SUNZILOG_FLAG_TX_STOPPED; -} - -/* The port lock is held and interrupts are disabled. */ -static void sunzilog_start_tx(struct uart_port *port) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char status; - - up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; - - status = readb(&channel->control); - ZSDELAY(); - - /* TX busy? Just wait for the TX done interrupt. */ - if (!(status & Tx_BUF_EMP)) - return; - - /* Send the first character to jump-start the TX done - * IRQ sending engine. - */ - if (port->x_char) { - writeb(port->x_char, &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - port->icount.tx++; - port->x_char = 0; - } else { - struct circ_buf *xmit = &port->state->xmit; - - writeb(xmit->buf[xmit->tail], &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - } -} - -/* The port lock is held. */ -static void sunzilog_stop_rx(struct uart_port *port) -{ - struct uart_sunzilog_port *up = UART_ZILOG(port); - struct zilog_channel __iomem *channel; - - if (ZS_IS_CONS(up)) - return; - - channel = ZILOG_CHANNEL_FROM_PORT(port); - - /* Disable all RX interrupts. */ - up->curregs[R1] &= ~RxINT_MASK; - sunzilog_maybe_update_regs(up, channel); -} - -/* The port lock is held. */ -static void sunzilog_enable_ms(struct uart_port *port) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char new_reg; - - new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE); - if (new_reg != up->curregs[R15]) { - up->curregs[R15] = new_reg; - - /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN); - } -} - -/* The port lock is not held. */ -static void sunzilog_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); - unsigned char set_bits, clear_bits, new_reg; - unsigned long flags; - - set_bits = clear_bits = 0; - - if (break_state) - set_bits |= SND_BRK; - else - clear_bits |= SND_BRK; - - spin_lock_irqsave(&port->lock, flags); - - new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; - if (new_reg != up->curregs[R5]) { - up->curregs[R5] = new_reg; - - /* NOTE: Not subject to 'transmitter active' rule. */ - write_zsreg(channel, R5, up->curregs[R5]); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void __sunzilog_startup(struct uart_sunzilog_port *up) -{ - struct zilog_channel __iomem *channel; - - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - up->prev_status = readb(&channel->control); - - /* Enable receiver and transmitter. */ - up->curregs[R3] |= RxENAB; - up->curregs[R5] |= TxENAB; - - up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - sunzilog_maybe_update_regs(up, channel); -} - -static int sunzilog_startup(struct uart_port *port) -{ - struct uart_sunzilog_port *up = UART_ZILOG(port); - unsigned long flags; - - if (ZS_IS_CONS(up)) - return 0; - - spin_lock_irqsave(&port->lock, flags); - __sunzilog_startup(up); - spin_unlock_irqrestore(&port->lock, flags); - return 0; -} - -/* - * The test for ZS_IS_CONS is explained by the following e-mail: - ***** - * From: Russell King - * Date: Sun, 8 Dec 2002 10:18:38 +0000 - * - * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote: - * > I boot my 2.5 boxes using "console=ttyS0,9600" argument, - * > and I noticed that something is not right with reference - * > counting in this case. It seems that when the console - * > is open by kernel initially, this is not accounted - * > as an open, and uart_startup is not called. - * - * That is correct. We are unable to call uart_startup when the serial - * console is initialised because it may need to allocate memory (as - * request_irq does) and the memory allocators may not have been - * initialised. - * - * 1. initialise the port into a state where it can send characters in the - * console write method. - * - * 2. don't do the actual hardware shutdown in your shutdown() method (but - * do the normal software shutdown - ie, free irqs etc) - ***** - */ -static void sunzilog_shutdown(struct uart_port *port) -{ - struct uart_sunzilog_port *up = UART_ZILOG(port); - struct zilog_channel __iomem *channel; - unsigned long flags; - - if (ZS_IS_CONS(up)) - return; - - spin_lock_irqsave(&port->lock, flags); - - channel = ZILOG_CHANNEL_FROM_PORT(port); - - /* Disable receiver and transmitter. */ - up->curregs[R3] &= ~RxENAB; - up->curregs[R5] &= ~TxENAB; - - /* Disable all interrupts and BRK assertion. */ - up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); - up->curregs[R5] &= ~SND_BRK; - sunzilog_maybe_update_regs(up, channel); - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Shared by TTY driver and serial console setup. The port lock is held - * and local interrupts are disabled. - */ -static void -sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, - unsigned int iflag, int brg) -{ - - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - - /* Program BAUD and clock source. */ - up->curregs[R4] &= ~XCLK_MASK; - up->curregs[R4] |= X16CLK; - up->curregs[R12] = brg & 0xff; - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRSRC | BRENAB; - - /* Character size, stop bits, and parity. */ - up->curregs[R3] &= ~RxN_MASK; - up->curregs[R5] &= ~TxN_MASK; - switch (cflag & CSIZE) { - case CS5: - up->curregs[R3] |= Rx5; - up->curregs[R5] |= Tx5; - up->parity_mask = 0x1f; - break; - case CS6: - up->curregs[R3] |= Rx6; - up->curregs[R5] |= Tx6; - up->parity_mask = 0x3f; - break; - case CS7: - up->curregs[R3] |= Rx7; - up->curregs[R5] |= Tx7; - up->parity_mask = 0x7f; - break; - case CS8: - default: - up->curregs[R3] |= Rx8; - up->curregs[R5] |= Tx8; - up->parity_mask = 0xff; - break; - }; - up->curregs[R4] &= ~0x0c; - if (cflag & CSTOPB) - up->curregs[R4] |= SB2; - else - up->curregs[R4] |= SB1; - if (cflag & PARENB) - up->curregs[R4] |= PAR_ENAB; - else - up->curregs[R4] &= ~PAR_ENAB; - if (!(cflag & PARODD)) - up->curregs[R4] |= PAR_EVEN; - else - up->curregs[R4] &= ~PAR_EVEN; - - up->port.read_status_mask = Rx_OVR; - if (iflag & INPCK) - up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) - up->port.read_status_mask |= BRK_ABRT; - - up->port.ignore_status_mask = 0; - if (iflag & IGNPAR) - up->port.ignore_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & IGNBRK) { - up->port.ignore_status_mask |= BRK_ABRT; - if (iflag & IGNPAR) - up->port.ignore_status_mask |= Rx_OVR; - } - - if ((cflag & CREAD) == 0) - up->port.ignore_status_mask = 0xff; -} - -/* The port lock is not held. */ -static void -sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - unsigned long flags; - int baud, brg; - - baud = uart_get_baud_rate(port, termios, old, 1200, 76800); - - spin_lock_irqsave(&up->port.lock, flags); - - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - - sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg); - - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->flags |= SUNZILOG_FLAG_MODEM_STATUS; - else - up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS; - - up->cflag = termios->c_cflag; - - sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); - - uart_update_timeout(port, termios->c_cflag, baud); - - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static const char *sunzilog_type(struct uart_port *port) -{ - struct uart_sunzilog_port *up = UART_ZILOG(port); - - return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs"; -} - -/* We do not request/release mappings of the registers here, this - * happens at early serial probe time. - */ -static void sunzilog_release_port(struct uart_port *port) -{ -} - -static int sunzilog_request_port(struct uart_port *port) -{ - return 0; -} - -/* These do not need to do anything interesting either. */ -static void sunzilog_config_port(struct uart_port *port, int flags) -{ -} - -/* We do not support letting the user mess with the divisor, IRQ, etc. */ -static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -#ifdef CONFIG_CONSOLE_POLL -static int sunzilog_get_poll_char(struct uart_port *port) -{ - unsigned char ch, r1; - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; - struct zilog_channel __iomem *channel - = ZILOG_CHANNEL_FROM_PORT(&up->port); - - - r1 = read_zsreg(channel, R1); - if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - writeb(ERR_RES, &channel->control); - ZSDELAY(); - ZS_WSYNC(channel); - } - - ch = readb(&channel->control); - ZSDELAY(); - - /* This funny hack depends upon BRK_ABRT not interfering - * with the other bits we care about in R1. - */ - if (ch & BRK_ABRT) - r1 |= BRK_ABRT; - - if (!(ch & Rx_CH_AV)) - return NO_POLL_CHAR; - - ch = readb(&channel->data); - ZSDELAY(); - - ch &= up->parity_mask; - return ch; -} - -static void sunzilog_put_poll_char(struct uart_port *port, - unsigned char ch) -{ - struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; - - sunzilog_putchar(&up->port, ch); -} -#endif /* CONFIG_CONSOLE_POLL */ - -static struct uart_ops sunzilog_pops = { - .tx_empty = sunzilog_tx_empty, - .set_mctrl = sunzilog_set_mctrl, - .get_mctrl = sunzilog_get_mctrl, - .stop_tx = sunzilog_stop_tx, - .start_tx = sunzilog_start_tx, - .stop_rx = sunzilog_stop_rx, - .enable_ms = sunzilog_enable_ms, - .break_ctl = sunzilog_break_ctl, - .startup = sunzilog_startup, - .shutdown = sunzilog_shutdown, - .set_termios = sunzilog_set_termios, - .type = sunzilog_type, - .release_port = sunzilog_release_port, - .request_port = sunzilog_request_port, - .config_port = sunzilog_config_port, - .verify_port = sunzilog_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = sunzilog_get_poll_char, - .poll_put_char = sunzilog_put_poll_char, -#endif -}; - -static int uart_chip_count; -static struct uart_sunzilog_port *sunzilog_port_table; -static struct zilog_layout __iomem **sunzilog_chip_regs; - -static struct uart_sunzilog_port *sunzilog_irq_chain; - -static struct uart_driver sunzilog_reg = { - .owner = THIS_MODULE, - .driver_name = "sunzilog", - .dev_name = "ttyS", - .major = TTY_MAJOR, -}; - -static int __init sunzilog_alloc_tables(int num_sunzilog) -{ - struct uart_sunzilog_port *up; - unsigned long size; - int num_channels = num_sunzilog * 2; - int i; - - size = num_channels * sizeof(struct uart_sunzilog_port); - sunzilog_port_table = kzalloc(size, GFP_KERNEL); - if (!sunzilog_port_table) - return -ENOMEM; - - for (i = 0; i < num_channels; i++) { - up = &sunzilog_port_table[i]; - - spin_lock_init(&up->port.lock); - - if (i == 0) - sunzilog_irq_chain = up; - - if (i < num_channels - 1) - up->next = up + 1; - else - up->next = NULL; - } - - size = num_sunzilog * sizeof(struct zilog_layout __iomem *); - sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); - if (!sunzilog_chip_regs) { - kfree(sunzilog_port_table); - sunzilog_irq_chain = NULL; - return -ENOMEM; - } - - return 0; -} - -static void sunzilog_free_tables(void) -{ - kfree(sunzilog_port_table); - sunzilog_irq_chain = NULL; - kfree(sunzilog_chip_regs); -} - -#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ - -static void sunzilog_putchar(struct uart_port *port, int ch) -{ - struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); - int loops = ZS_PUT_CHAR_MAX_DELAY; - - /* This is a timed polling loop so do not switch the explicit - * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM - */ - do { - unsigned char val = readb(&channel->control); - if (val & Tx_BUF_EMP) { - ZSDELAY(); - break; - } - udelay(5); - } while (--loops); - - writeb(ch, &channel->data); - ZSDELAY(); - ZS_WSYNC(channel); -} - -#ifdef CONFIG_SERIO - -static DEFINE_SPINLOCK(sunzilog_serio_lock); - -static int sunzilog_serio_write(struct serio *serio, unsigned char ch) -{ - struct uart_sunzilog_port *up = serio->port_data; - unsigned long flags; - - spin_lock_irqsave(&sunzilog_serio_lock, flags); - - sunzilog_putchar(&up->port, ch); - - spin_unlock_irqrestore(&sunzilog_serio_lock, flags); - - return 0; -} - -static int sunzilog_serio_open(struct serio *serio) -{ - struct uart_sunzilog_port *up = serio->port_data; - unsigned long flags; - int ret; - - spin_lock_irqsave(&sunzilog_serio_lock, flags); - if (!up->serio_open) { - up->serio_open = 1; - ret = 0; - } else - ret = -EBUSY; - spin_unlock_irqrestore(&sunzilog_serio_lock, flags); - - return ret; -} - -static void sunzilog_serio_close(struct serio *serio) -{ - struct uart_sunzilog_port *up = serio->port_data; - unsigned long flags; - - spin_lock_irqsave(&sunzilog_serio_lock, flags); - up->serio_open = 0; - spin_unlock_irqrestore(&sunzilog_serio_lock, flags); -} - -#endif /* CONFIG_SERIO */ - -#ifdef CONFIG_SERIAL_SUNZILOG_CONSOLE -static void -sunzilog_console_write(struct console *con, const char *s, unsigned int count) -{ - struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; - unsigned long flags; - int locked = 1; - - 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, sunzilog_putchar); - udelay(2); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static int __init sunzilog_console_setup(struct console *con, char *options) -{ - struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; - unsigned long flags; - int baud, brg; - - if (up->port.type != PORT_SUNZILOG) - return -1; - - printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n", - (sunzilog_reg.minor - 64) + con->index, con->index); - - /* Get firmware console settings. */ - sunserial_console_termios(con, up->port.dev->of_node); - - /* Firmware console speed is limited to 150-->38400 baud so - * this hackish cflag thing is OK. - */ - switch (con->cflag & CBAUD) { - case B150: baud = 150; break; - case B300: baud = 300; break; - case B600: baud = 600; break; - case B1200: baud = 1200; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - default: case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - }; - - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - - spin_lock_irqsave(&up->port.lock, flags); - - up->curregs[R15] |= BRKIE; - sunzilog_convert_to_zs(up, con->cflag, 0, brg); - - sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - __sunzilog_startup(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - - return 0; -} - -static struct console sunzilog_console_ops = { - .name = "ttyS", - .write = sunzilog_console_write, - .device = uart_console_device, - .setup = sunzilog_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sunzilog_reg, -}; - -static inline struct console *SUNZILOG_CONSOLE(void) -{ - return &sunzilog_console_ops; -} - -#else -#define SUNZILOG_CONSOLE() (NULL) -#endif - -static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) -{ - int baud, brg; - - if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { - up->cflag = B1200 | CS8 | CLOCAL | CREAD; - baud = 1200; - } else { - up->cflag = B4800 | CS8 | CLOCAL | CREAD; - baud = 4800; - } - - up->curregs[R15] |= BRKIE; - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - sunzilog_convert_to_zs(up, up->cflag, 0, brg); - sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - __sunzilog_startup(up); -} - -#ifdef CONFIG_SERIO -static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up) -{ - struct serio *serio = &up->serio; - - serio->port_data = up; - - serio->id.type = SERIO_RS232; - if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { - serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "zskbd", sizeof(serio->name)); - } else { - serio->id.proto = SERIO_SUN; - serio->id.extra = 1; - strlcpy(serio->name, "zsms", sizeof(serio->name)); - } - strlcpy(serio->phys, - ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ? - "zs/serio0" : "zs/serio1"), - sizeof(serio->phys)); - - serio->write = sunzilog_serio_write; - serio->open = sunzilog_serio_open; - serio->close = sunzilog_serio_close; - serio->dev.parent = up->port.dev; - - serio_register_port(serio); -} -#endif - -static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) -{ - struct zilog_channel __iomem *channel; - unsigned long flags; - int baud, brg; - - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - - spin_lock_irqsave(&up->port.lock, flags); - if (ZS_IS_CHANNEL_A(up)) { - write_zsreg(channel, R9, FHWRES); - ZSDELAY_LONG(); - (void) read_zsreg(channel, R0); - } - - if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | - SUNZILOG_FLAG_CONS_MOUSE)) { - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R6] = 0x00; /* SDLC Address */ - up->curregs[R7] = 0x7E; /* SDLC Flag */ - up->curregs[R9] = NV; - up->curregs[R7p] = 0x00; - sunzilog_init_kbdms(up); - /* Only enable interrupts if an ISR handler available */ - if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) - up->curregs[R9] |= MIE; - write_zsreg(channel, R9, up->curregs[R9]); - } else { - /* Normal serial TTY. */ - up->parity_mask = 0xff; - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R6] = 0x00; /* SDLC Address */ - up->curregs[R7] = 0x7E; /* SDLC Flag */ - up->curregs[R9] = NV; - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - baud = 9600; - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRSRC | BRENAB; - up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */ - up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL; - if (__load_zsregs(channel, up->curregs)) { - up->flags |= SUNZILOG_FLAG_ESCC; - } - /* Only enable interrupts if an ISR handler available */ - if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) - up->curregs[R9] |= MIE; - write_zsreg(channel, R9, up->curregs[R9]); - } - - spin_unlock_irqrestore(&up->port.lock, flags); - -#ifdef CONFIG_SERIO - if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | - SUNZILOG_FLAG_CONS_MOUSE)) - sunzilog_register_serio(up); -#endif -} - -static int zilog_irq = -1; - -static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match) -{ - static int kbm_inst, uart_inst; - int inst; - struct uart_sunzilog_port *up; - struct zilog_layout __iomem *rp; - int keyboard_mouse = 0; - int err; - - if (of_find_property(op->dev.of_node, "keyboard", NULL)) - keyboard_mouse = 1; - - /* uarts must come before keyboards/mice */ - if (keyboard_mouse) - inst = uart_chip_count + kbm_inst; - else - inst = uart_inst; - - sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, - sizeof(struct zilog_layout), - "zs"); - if (!sunzilog_chip_regs[inst]) - return -ENOMEM; - - rp = sunzilog_chip_regs[inst]; - - if (zilog_irq == -1) - zilog_irq = op->archdata.irqs[0]; - - up = &sunzilog_port_table[inst * 2]; - - /* Channel A */ - up[0].port.mapbase = op->resource[0].start + 0x00; - up[0].port.membase = (void __iomem *) &rp->channelA; - up[0].port.iotype = UPIO_MEM; - up[0].port.irq = op->archdata.irqs[0]; - up[0].port.uartclk = ZS_CLOCK; - up[0].port.fifosize = 1; - up[0].port.ops = &sunzilog_pops; - up[0].port.type = PORT_SUNZILOG; - up[0].port.flags = 0; - up[0].port.line = (inst * 2) + 0; - up[0].port.dev = &op->dev; - up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; - if (keyboard_mouse) - up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; - sunzilog_init_hw(&up[0]); - - /* Channel B */ - up[1].port.mapbase = op->resource[0].start + 0x04; - up[1].port.membase = (void __iomem *) &rp->channelB; - up[1].port.iotype = UPIO_MEM; - up[1].port.irq = op->archdata.irqs[0]; - up[1].port.uartclk = ZS_CLOCK; - up[1].port.fifosize = 1; - up[1].port.ops = &sunzilog_pops; - up[1].port.type = PORT_SUNZILOG; - up[1].port.flags = 0; - up[1].port.line = (inst * 2) + 1; - up[1].port.dev = &op->dev; - up[1].flags |= 0; - if (keyboard_mouse) - up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; - sunzilog_init_hw(&up[1]); - - if (!keyboard_mouse) { - if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node, - &sunzilog_reg, up[0].port.line, - false)) - up->flags |= SUNZILOG_FLAG_IS_CONS; - err = uart_add_one_port(&sunzilog_reg, &up[0].port); - if (err) { - of_iounmap(&op->resource[0], - rp, sizeof(struct zilog_layout)); - return err; - } - if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node, - &sunzilog_reg, up[1].port.line, - false)) - up->flags |= SUNZILOG_FLAG_IS_CONS; - err = uart_add_one_port(&sunzilog_reg, &up[1].port); - if (err) { - uart_remove_one_port(&sunzilog_reg, &up[0].port); - of_iounmap(&op->resource[0], - rp, sizeof(struct zilog_layout)); - return err; - } - uart_inst++; - } else { - printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) " - "is a %s\n", - dev_name(&op->dev), - (unsigned long long) up[0].port.mapbase, - op->archdata.irqs[0], sunzilog_type(&up[0].port)); - printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) " - "is a %s\n", - dev_name(&op->dev), - (unsigned long long) up[1].port.mapbase, - op->archdata.irqs[0], sunzilog_type(&up[1].port)); - kbm_inst++; - } - - dev_set_drvdata(&op->dev, &up[0]); - - return 0; -} - -static void __devexit zs_remove_one(struct uart_sunzilog_port *up) -{ - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { -#ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); -#endif - } else - uart_remove_one_port(&sunzilog_reg, &up->port); -} - -static int __devexit zs_remove(struct platform_device *op) -{ - struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev); - struct zilog_layout __iomem *regs; - - zs_remove_one(&up[0]); - zs_remove_one(&up[1]); - - regs = sunzilog_chip_regs[up[0].port.line / 2]; - of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); - - dev_set_drvdata(&op->dev, NULL); - - return 0; -} - -static const struct of_device_id zs_match[] = { - { - .name = "zs", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, zs_match); - -static struct of_platform_driver zs_driver = { - .driver = { - .name = "zs", - .owner = THIS_MODULE, - .of_match_table = zs_match, - }, - .probe = zs_probe, - .remove = __devexit_p(zs_remove), -}; - -static int __init sunzilog_init(void) -{ - struct device_node *dp; - int err; - int num_keybms = 0; - int num_sunzilog = 0; - - for_each_node_by_name(dp, "zs") { - num_sunzilog++; - if (of_find_property(dp, "keyboard", NULL)) - num_keybms++; - } - - if (num_sunzilog) { - err = sunzilog_alloc_tables(num_sunzilog); - if (err) - goto out; - - uart_chip_count = num_sunzilog - num_keybms; - - err = sunserial_register_minors(&sunzilog_reg, - uart_chip_count * 2); - if (err) - goto out_free_tables; - } - - err = of_register_platform_driver(&zs_driver); - if (err) - goto out_unregister_uart; - - if (zilog_irq != -1) { - struct uart_sunzilog_port *up = sunzilog_irq_chain; - err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, - "zs", sunzilog_irq_chain); - if (err) - goto out_unregister_driver; - - /* Enable Interrupts */ - while (up) { - struct zilog_channel __iomem *channel; - - /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */ - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - up->flags |= SUNZILOG_FLAG_ISR_HANDLER; - up->curregs[R9] |= MIE; - write_zsreg(channel, R9, up->curregs[R9]); - up = up->next; - } - } - -out: - return err; - -out_unregister_driver: - of_unregister_platform_driver(&zs_driver); - -out_unregister_uart: - if (num_sunzilog) { - sunserial_unregister_minors(&sunzilog_reg, num_sunzilog); - sunzilog_reg.cons = NULL; - } - -out_free_tables: - sunzilog_free_tables(); - goto out; -} - -static void __exit sunzilog_exit(void) -{ - of_unregister_platform_driver(&zs_driver); - - if (zilog_irq != -1) { - struct uart_sunzilog_port *up = sunzilog_irq_chain; - - /* Disable Interrupts */ - while (up) { - struct zilog_channel __iomem *channel; - - /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */ - channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER; - up->curregs[R9] &= ~MIE; - write_zsreg(channel, R9, up->curregs[R9]); - up = up->next; - } - - free_irq(zilog_irq, sunzilog_irq_chain); - zilog_irq = -1; - } - - if (sunzilog_reg.nr) { - sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr); - sunzilog_free_tables(); - } -} - -module_init(sunzilog_init); -module_exit(sunzilog_exit); - -MODULE_AUTHOR("David S. Miller"); -MODULE_DESCRIPTION("Sun Zilog serial port driver"); -MODULE_VERSION("2.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h deleted file mode 100644 index 5dec7b47cc38..000000000000 --- a/drivers/serial/sunzilog.h +++ /dev/null @@ -1,289 +0,0 @@ -#ifndef _SUNZILOG_H -#define _SUNZILOG_H - -struct zilog_channel { - volatile unsigned char control; - volatile unsigned char __pad1; - volatile unsigned char data; - volatile unsigned char __pad2; -}; - -struct zilog_layout { - struct zilog_channel channelB; - struct zilog_channel channelA; -}; - -#define NUM_ZSREGS 17 -#define R7p 16 /* Written as R7 with P15 bit 0 set */ - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* The Zilog register set */ - -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ -#define RxINT_MASK 0x18 - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENAB 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ -#define RxN_MASK 0xc0 - -/* Write Register 4 */ - -#define PAR_ENAB 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ -#define XCLK_MASK 0xC0 - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define TxN_MASK 0x60 -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 7' (ESCC Only) */ -#define AUTO_TxFLAG 1 /* Automatic Tx SDLC Flag */ -#define AUTO_EOM_RST 2 /* Automatic EOM Reset */ -#define AUTOnRTS 4 /* Automatic /RTS pin deactivation */ -#define RxFIFO_LVL 8 /* Receive FIFO interrupt level */ -#define nDTRnREQ 0x10 /* /DTR/REQ timing */ -#define TxFIFO_LVL 0x20 /* Transmit FIFO interrupt level */ -#define EXT_RD_EN 0x40 /* Extended read register enable */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define SWIACK 0x20 /* Software Interrupt Ack (not on NMOS) */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENAB 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define WR7pEN 1 /* WR7' Enable (ESCC only) */ -#define ZCIE 2 /* Zero count IE */ -#define FIFOEN 4 /* FIFO Enable (ESCC only) */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ -#define CHB_Tx_EMPTY 0x00 -#define CHB_EXT_STAT 0x02 -#define CHB_Rx_AVAIL 0x04 -#define CHB_SPECIAL 0x06 -#define CHA_Tx_EMPTY 0x08 -#define CHA_EXT_STAT 0x0a -#define CHA_Rx_AVAIL 0x0c -#define CHA_SPECIAL 0x0e -#define STATUS_MASK 0x0e - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 6 (LSB frame byte count [Not on NMOS]) */ - -/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* Misc macros */ -#define ZS_CLEARERR(channel) do { sbus_writeb(ERR_RES, &channel->control); \ - udelay(5); } while(0) - -#define ZS_CLEARSTAT(channel) do { sbus_writeb(RES_EXT_INT, &channel->control); \ - udelay(5); } while(0) - -#define ZS_CLEARFIFO(channel) do { sbus_readb(&channel->data); \ - udelay(2); \ - sbus_readb(&channel->data); \ - udelay(2); \ - sbus_readb(&channel->data); \ - udelay(2); } while(0) - -#endif /* _SUNZILOG_H */ diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c deleted file mode 100644 index 1f36b7eb7351..000000000000 --- a/drivers/serial/timbuart.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * timbuart.c timberdale FPGA UART driver - * Copyright (c) 2009 Intel Corporation - * - * 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. - * - * 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. - */ - -/* Supports: - * Timberdale FPGA UART - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "timbuart.h" - -struct timbuart_port { - struct uart_port port; - struct tasklet_struct tasklet; - int usedma; - u32 last_ier; - struct platform_device *dev; -}; - -static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, - 921600, 1843200, 3250000}; - -static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier); - -static irqreturn_t timbuart_handleinterrupt(int irq, void *devid); - -static void timbuart_stop_rx(struct uart_port *port) -{ - /* spin lock held by upper layer, disable all RX interrupts */ - u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS; - iowrite32(ier, port->membase + TIMBUART_IER); -} - -static void timbuart_stop_tx(struct uart_port *port) -{ - /* spinlock held by upper layer, disable TX interrupt */ - u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE; - iowrite32(ier, port->membase + TIMBUART_IER); -} - -static void timbuart_start_tx(struct uart_port *port) -{ - struct timbuart_port *uart = - container_of(port, struct timbuart_port, port); - - /* do not transfer anything here -> fire off the tasklet */ - tasklet_schedule(&uart->tasklet); -} - -static unsigned int timbuart_tx_empty(struct uart_port *port) -{ - u32 isr = ioread32(port->membase + TIMBUART_ISR); - - return (isr & TXBE) ? TIOCSER_TEMT : 0; -} - -static void timbuart_flush_buffer(struct uart_port *port) -{ - if (!timbuart_tx_empty(port)) { - u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | - TIMBUART_CTRL_FLSHTX; - - iowrite8(ctl, port->membase + TIMBUART_CTRL); - iowrite32(TXBF, port->membase + TIMBUART_ISR); - } -} - -static void timbuart_rx_chars(struct uart_port *port) -{ - struct tty_struct *tty = port->state->port.tty; - - while (ioread32(port->membase + TIMBUART_ISR) & RXDP) { - u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); - port->icount.rx++; - tty_insert_flip_char(tty, ch, TTY_NORMAL); - } - - spin_unlock(&port->lock); - tty_flip_buffer_push(port->state->port.tty); - spin_lock(&port->lock); - - dev_dbg(port->dev, "%s - total read %d bytes\n", - __func__, port->icount.rx); -} - -static void timbuart_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) && - !uart_circ_empty(xmit)) { - iowrite8(xmit->buf[xmit->tail], - port->membase + TIMBUART_TXFIFO); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - dev_dbg(port->dev, - "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", - __func__, - port->icount.tx, - ioread8(port->membase + TIMBUART_CTRL), - port->mctrl & TIOCM_RTS, - ioread8(port->membase + TIMBUART_BAUDRATE)); -} - -static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) -{ - struct timbuart_port *uart = - container_of(port, struct timbuart_port, port); - struct circ_buf *xmit = &port->state->xmit; - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - if (port->x_char) - return; - - if (isr & TXFLAGS) { - timbuart_tx_chars(port); - /* clear all TX interrupts */ - iowrite32(TXFLAGS, port->membase + TIMBUART_ISR); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - } else - /* Re-enable any tx interrupt */ - *ier |= uart->last_ier & TXFLAGS; - - /* enable interrupts if there are chars in the transmit buffer, - * Or if we delivered some bytes and want the almost empty interrupt - * we wake up the upper layer later when we got the interrupt - * to give it some time to go out... - */ - if (!uart_circ_empty(xmit)) - *ier |= TXBAE; - - dev_dbg(port->dev, "%s - leaving\n", __func__); -} - -void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier) -{ - if (isr & RXFLAGS) { - /* Some RX status is set */ - if (isr & RXBF) { - u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | - TIMBUART_CTRL_FLSHRX; - iowrite8(ctl, port->membase + TIMBUART_CTRL); - port->icount.overrun++; - } else if (isr & (RXDP)) - timbuart_rx_chars(port); - - /* ack all RX interrupts */ - iowrite32(RXFLAGS, port->membase + TIMBUART_ISR); - } - - /* always have the RX interrupts enabled */ - *ier |= RXBAF | RXBF | RXTT; - - dev_dbg(port->dev, "%s - leaving\n", __func__); -} - -void timbuart_tasklet(unsigned long arg) -{ - struct timbuart_port *uart = (struct timbuart_port *)arg; - u32 isr, ier = 0; - - spin_lock(&uart->port.lock); - - isr = ioread32(uart->port.membase + TIMBUART_ISR); - dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); - - if (!uart->usedma) - timbuart_handle_tx_port(&uart->port, isr, &ier); - - timbuart_mctrl_check(&uart->port, isr, &ier); - - if (!uart->usedma) - timbuart_handle_rx_port(&uart->port, isr, &ier); - - iowrite32(ier, uart->port.membase + TIMBUART_IER); - - spin_unlock(&uart->port.lock); - dev_dbg(uart->port.dev, "%s leaving\n", __func__); -} - -static unsigned int timbuart_get_mctrl(struct uart_port *port) -{ - u8 cts = ioread8(port->membase + TIMBUART_CTRL); - dev_dbg(port->dev, "%s - cts %x\n", __func__, cts); - - if (cts & TIMBUART_CTRL_CTS) - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; - else - return TIOCM_DSR | TIOCM_CAR; -} - -static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - dev_dbg(port->dev, "%s - %x\n", __func__, mctrl); - - if (mctrl & TIOCM_RTS) - iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); - else - iowrite8(0, port->membase + TIMBUART_CTRL); -} - -static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) -{ - unsigned int cts; - - if (isr & CTS_DELTA) { - /* ack */ - iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR); - cts = timbuart_get_mctrl(port); - uart_handle_cts_change(port, cts & TIOCM_CTS); - wake_up_interruptible(&port->state->port.delta_msr_wait); - } - - *ier |= CTS_DELTA; -} - -static void timbuart_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - -static void timbuart_break_ctl(struct uart_port *port, int ctl) -{ - /* N/A */ -} - -static int timbuart_startup(struct uart_port *port) -{ - struct timbuart_port *uart = - container_of(port, struct timbuart_port, port); - - dev_dbg(port->dev, "%s\n", __func__); - - iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL); - iowrite32(0x1ff, port->membase + TIMBUART_ISR); - /* Enable all but TX interrupts */ - iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA, - port->membase + TIMBUART_IER); - - return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED, - "timb-uart", uart); -} - -static void timbuart_shutdown(struct uart_port *port) -{ - struct timbuart_port *uart = - container_of(port, struct timbuart_port, port); - dev_dbg(port->dev, "%s\n", __func__); - free_irq(port->irq, uart); - iowrite32(0, port->membase + TIMBUART_IER); -} - -static int get_bindex(int baud) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(baudrates); i++) - if (baud <= baudrates[i]) - return i; - - return -1; -} - -static void timbuart_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud; - short bindex; - unsigned long flags; - - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - bindex = get_bindex(baud); - dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); - - if (bindex < 0) - bindex = 0; - baud = baudrates[bindex]; - - /* The serial layer calls into this once with old = NULL when setting - up initially */ - if (old) - tty_termios_copy_hw(termios, old); - tty_termios_encode_baud_rate(termios, baud, baud); - - spin_lock_irqsave(&port->lock, flags); - iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); - uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *timbuart_type(struct uart_port *port) -{ - return port->type == PORT_UNKNOWN ? "timbuart" : NULL; -} - -/* We do not request/release mappings of the registers here, - * currently it's done in the proble function. - */ -static void timbuart_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - int size = - resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - release_mem_region(port->mapbase, size); -} - -static int timbuart_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - int size = - resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); - - if (!request_mem_region(port->mapbase, size, "timb-uart")) - return -EBUSY; - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_mem_region(port->mapbase, size); - return -ENOMEM; - } - } - - return 0; -} - -static irqreturn_t timbuart_handleinterrupt(int irq, void *devid) -{ - struct timbuart_port *uart = (struct timbuart_port *)devid; - - if (ioread8(uart->port.membase + TIMBUART_IPR)) { - uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER); - - /* disable interrupts, the tasklet enables them again */ - iowrite32(0, uart->port.membase + TIMBUART_IER); - - /* fire off bottom half */ - tasklet_schedule(&uart->tasklet); - - return IRQ_HANDLED; - } else - return IRQ_NONE; -} - -/* - * Configure/autoconfigure the port. - */ -static void timbuart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_TIMBUART; - timbuart_request_port(port); - } -} - -static int timbuart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - /* we don't want the core code to modify any port params */ - return -EINVAL; -} - -static struct uart_ops timbuart_ops = { - .tx_empty = timbuart_tx_empty, - .set_mctrl = timbuart_set_mctrl, - .get_mctrl = timbuart_get_mctrl, - .stop_tx = timbuart_stop_tx, - .start_tx = timbuart_start_tx, - .flush_buffer = timbuart_flush_buffer, - .stop_rx = timbuart_stop_rx, - .enable_ms = timbuart_enable_ms, - .break_ctl = timbuart_break_ctl, - .startup = timbuart_startup, - .shutdown = timbuart_shutdown, - .set_termios = timbuart_set_termios, - .type = timbuart_type, - .release_port = timbuart_release_port, - .request_port = timbuart_request_port, - .config_port = timbuart_config_port, - .verify_port = timbuart_verify_port -}; - -static struct uart_driver timbuart_driver = { - .owner = THIS_MODULE, - .driver_name = "timberdale_uart", - .dev_name = "ttyTU", - .major = TIMBUART_MAJOR, - .minor = TIMBUART_MINOR, - .nr = 1 -}; - -static int __devinit timbuart_probe(struct platform_device *dev) -{ - int err, irq; - struct timbuart_port *uart; - struct resource *iomem; - - dev_dbg(&dev->dev, "%s\n", __func__); - - uart = kzalloc(sizeof(*uart), GFP_KERNEL); - if (!uart) { - err = -EINVAL; - goto err_mem; - } - - uart->usedma = 0; - - uart->port.uartclk = 3250000 * 16; - uart->port.fifosize = TIMBUART_FIFO_SIZE; - uart->port.regshift = 2; - uart->port.iotype = UPIO_MEM; - uart->port.ops = &timbuart_ops; - uart->port.irq = 0; - uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; - uart->port.line = 0; - uart->port.dev = &dev->dev; - - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!iomem) { - err = -ENOMEM; - goto err_register; - } - uart->port.mapbase = iomem->start; - uart->port.membase = NULL; - - irq = platform_get_irq(dev, 0); - if (irq < 0) { - err = -EINVAL; - goto err_register; - } - uart->port.irq = irq; - - tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); - - err = uart_register_driver(&timbuart_driver); - if (err) - goto err_register; - - err = uart_add_one_port(&timbuart_driver, &uart->port); - if (err) - goto err_add_port; - - platform_set_drvdata(dev, uart); - - return 0; - -err_add_port: - uart_unregister_driver(&timbuart_driver); -err_register: - kfree(uart); -err_mem: - printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n", - err); - - return err; -} - -static int __devexit timbuart_remove(struct platform_device *dev) -{ - struct timbuart_port *uart = platform_get_drvdata(dev); - - tasklet_kill(&uart->tasklet); - uart_remove_one_port(&timbuart_driver, &uart->port); - uart_unregister_driver(&timbuart_driver); - kfree(uart); - - return 0; -} - -static struct platform_driver timbuart_platform_driver = { - .driver = { - .name = "timb-uart", - .owner = THIS_MODULE, - }, - .probe = timbuart_probe, - .remove = __devexit_p(timbuart_remove), -}; - -/*--------------------------------------------------------------------------*/ - -static int __init timbuart_init(void) -{ - return platform_driver_register(&timbuart_platform_driver); -} - -static void __exit timbuart_exit(void) -{ - platform_driver_unregister(&timbuart_platform_driver); -} - -module_init(timbuart_init); -module_exit(timbuart_exit); - -MODULE_DESCRIPTION("Timberdale UART driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:timb-uart"); - diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h deleted file mode 100644 index 7e566766bc43..000000000000 --- a/drivers/serial/timbuart.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * timbuart.c timberdale FPGA GPIO driver - * Copyright (c) 2009 Intel Corporation - * - * 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. - * - * 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. - */ - -/* Supports: - * Timberdale FPGA UART - */ - -#ifndef _TIMBUART_H -#define _TIMBUART_H - -#define TIMBUART_FIFO_SIZE 2048 - -#define TIMBUART_RXFIFO 0x08 -#define TIMBUART_TXFIFO 0x0c -#define TIMBUART_IER 0x10 -#define TIMBUART_IPR 0x14 -#define TIMBUART_ISR 0x18 -#define TIMBUART_CTRL 0x1c -#define TIMBUART_BAUDRATE 0x20 - -#define TIMBUART_CTRL_RTS 0x01 -#define TIMBUART_CTRL_CTS 0x02 -#define TIMBUART_CTRL_FLSHTX 0x40 -#define TIMBUART_CTRL_FLSHRX 0x80 - -#define TXBF 0x01 -#define TXBAE 0x02 -#define CTS_DELTA 0x04 -#define RXDP 0x08 -#define RXBAF 0x10 -#define RXBF 0x20 -#define RXTT 0x40 -#define RXBNAE 0x80 -#define TXBE 0x100 - -#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE) -#define TXFLAGS (TXBF | TXBAE) - -#define TIMBUART_MAJOR 204 -#define TIMBUART_MINOR 192 - -#endif /* _TIMBUART_H */ - diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c deleted file mode 100644 index d2fce865b731..000000000000 --- a/drivers/serial/uartlite.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * uartlite.c: Serial driver for Xilinx uartlite serial controller - * - * Copyright (C) 2006 Peter Korsgaard - * Copyright (C) 2007 Secret Lab Technologies Ltd. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) -#include -#include -#include -#include - -/* Match table for of_platform binding */ -static struct of_device_id ulite_of_match[] __devinitdata = { - { .compatible = "xlnx,opb-uartlite-1.00.b", }, - { .compatible = "xlnx,xps-uartlite-1.00.a", }, - {} -}; -MODULE_DEVICE_TABLE(of, ulite_of_match); - -#endif - -#define ULITE_NAME "ttyUL" -#define ULITE_MAJOR 204 -#define ULITE_MINOR 187 -#define ULITE_NR_UARTS 4 - -/* --------------------------------------------------------------------- - * Register definitions - * - * For register details see datasheet: - * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf - */ - -#define ULITE_RX 0x00 -#define ULITE_TX 0x04 -#define ULITE_STATUS 0x08 -#define ULITE_CONTROL 0x0c - -#define ULITE_REGION 16 - -#define ULITE_STATUS_RXVALID 0x01 -#define ULITE_STATUS_RXFULL 0x02 -#define ULITE_STATUS_TXEMPTY 0x04 -#define ULITE_STATUS_TXFULL 0x08 -#define ULITE_STATUS_IE 0x10 -#define ULITE_STATUS_OVERRUN 0x20 -#define ULITE_STATUS_FRAME 0x40 -#define ULITE_STATUS_PARITY 0x80 - -#define ULITE_CONTROL_RST_TX 0x01 -#define ULITE_CONTROL_RST_RX 0x02 -#define ULITE_CONTROL_IE 0x10 - - -static struct uart_port ulite_ports[ULITE_NR_UARTS]; - -/* --------------------------------------------------------------------- - * Core UART driver operations - */ - -static int ulite_receive(struct uart_port *port, int stat) -{ - struct tty_struct *tty = port->state->port.tty; - unsigned char ch = 0; - char flag = TTY_NORMAL; - - if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN - | ULITE_STATUS_FRAME)) == 0) - return 0; - - /* stats */ - if (stat & ULITE_STATUS_RXVALID) { - port->icount.rx++; - ch = ioread32be(port->membase + ULITE_RX); - - if (stat & ULITE_STATUS_PARITY) - port->icount.parity++; - } - - if (stat & ULITE_STATUS_OVERRUN) - port->icount.overrun++; - - if (stat & ULITE_STATUS_FRAME) - port->icount.frame++; - - - /* drop byte with parity error if IGNPAR specificed */ - if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY) - stat &= ~ULITE_STATUS_RXVALID; - - stat &= port->read_status_mask; - - if (stat & ULITE_STATUS_PARITY) - flag = TTY_PARITY; - - - stat &= ~port->ignore_status_mask; - - if (stat & ULITE_STATUS_RXVALID) - tty_insert_flip_char(tty, ch, flag); - - if (stat & ULITE_STATUS_FRAME) - tty_insert_flip_char(tty, 0, TTY_FRAME); - - if (stat & ULITE_STATUS_OVERRUN) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - - return 1; -} - -static int ulite_transmit(struct uart_port *port, int stat) -{ - struct circ_buf *xmit = &port->state->xmit; - - if (stat & ULITE_STATUS_TXFULL) - return 0; - - if (port->x_char) { - iowrite32be(port->x_char, port->membase + ULITE_TX); - port->x_char = 0; - port->icount.tx++; - return 1; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return 0; - - iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); - port->icount.tx++; - - /* wake up */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - return 1; -} - -static irqreturn_t ulite_isr(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - int busy, n = 0; - - do { - int stat = ioread32be(port->membase + ULITE_STATUS); - busy = ulite_receive(port, stat); - busy |= ulite_transmit(port, stat); - n++; - } while (busy); - - /* work done? */ - if (n > 1) { - tty_flip_buffer_push(port->state->port.tty); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } -} - -static unsigned int ulite_tx_empty(struct uart_port *port) -{ - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&port->lock, flags); - ret = ioread32be(port->membase + ULITE_STATUS); - spin_unlock_irqrestore(&port->lock, flags); - - return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; -} - -static unsigned int ulite_get_mctrl(struct uart_port *port) -{ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -} - -static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* N/A */ -} - -static void ulite_stop_tx(struct uart_port *port) -{ - /* N/A */ -} - -static void ulite_start_tx(struct uart_port *port) -{ - ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS)); -} - -static void ulite_stop_rx(struct uart_port *port) -{ - /* don't forward any more data (like !CREAD) */ - port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY - | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; -} - -static void ulite_enable_ms(struct uart_port *port) -{ - /* N/A */ -} - -static void ulite_break_ctl(struct uart_port *port, int ctl) -{ - /* N/A */ -} - -static int ulite_startup(struct uart_port *port) -{ - int ret; - - ret = request_irq(port->irq, ulite_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port); - if (ret) - return ret; - - iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, - port->membase + ULITE_CONTROL); - iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); - - return 0; -} - -static void ulite_shutdown(struct uart_port *port) -{ - iowrite32be(0, port->membase + ULITE_CONTROL); - ioread32be(port->membase + ULITE_CONTROL); /* dummy */ - free_irq(port->irq, port); -} - -static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned long flags; - unsigned int baud; - - spin_lock_irqsave(&port->lock, flags); - - port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN - | ULITE_STATUS_TXFULL; - - if (termios->c_iflag & INPCK) - port->read_status_mask |= - ULITE_STATUS_PARITY | ULITE_STATUS_FRAME; - - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= ULITE_STATUS_PARITY - | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; - - /* ignore all characters if CREAD is not set */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= - ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY - | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; - - /* update timeout */ - baud = uart_get_baud_rate(port, termios, old, 0, 460800); - uart_update_timeout(port, termios->c_cflag, baud); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *ulite_type(struct uart_port *port) -{ - return port->type == PORT_UARTLITE ? "uartlite" : NULL; -} - -static void ulite_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, ULITE_REGION); - iounmap(port->membase); - port->membase = NULL; -} - -static int ulite_request_port(struct uart_port *port) -{ - pr_debug("ulite console: port=%p; port->mapbase=%llx\n", - port, (unsigned long long) port->mapbase); - - if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) { - dev_err(port->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = ioremap(port->mapbase, ULITE_REGION); - if (!port->membase) { - dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, ULITE_REGION); - return -EBUSY; - } - - return 0; -} - -static void ulite_config_port(struct uart_port *port, int flags) -{ - if (!ulite_request_port(port)) - port->type = PORT_UARTLITE; -} - -static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* we don't want the core code to modify any port params */ - return -EINVAL; -} - -#ifdef CONFIG_CONSOLE_POLL -static int ulite_get_poll_char(struct uart_port *port) -{ - if (!(ioread32be(port->membase + ULITE_STATUS) - & ULITE_STATUS_RXVALID)) - return NO_POLL_CHAR; - - return ioread32be(port->membase + ULITE_RX); -} - -static void ulite_put_poll_char(struct uart_port *port, unsigned char ch) -{ - while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL) - cpu_relax(); - - /* write char to device */ - iowrite32be(ch, port->membase + ULITE_TX); -} -#endif - -static struct uart_ops ulite_ops = { - .tx_empty = ulite_tx_empty, - .set_mctrl = ulite_set_mctrl, - .get_mctrl = ulite_get_mctrl, - .stop_tx = ulite_stop_tx, - .start_tx = ulite_start_tx, - .stop_rx = ulite_stop_rx, - .enable_ms = ulite_enable_ms, - .break_ctl = ulite_break_ctl, - .startup = ulite_startup, - .shutdown = ulite_shutdown, - .set_termios = ulite_set_termios, - .type = ulite_type, - .release_port = ulite_release_port, - .request_port = ulite_request_port, - .config_port = ulite_config_port, - .verify_port = ulite_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = ulite_get_poll_char, - .poll_put_char = ulite_put_poll_char, -#endif -}; - -/* --------------------------------------------------------------------- - * Console driver operations - */ - -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE -static void ulite_console_wait_tx(struct uart_port *port) -{ - int i; - u8 val; - - /* Spin waiting for TX fifo to have space available */ - for (i = 0; i < 100000; i++) { - val = ioread32be(port->membase + ULITE_STATUS); - if ((val & ULITE_STATUS_TXFULL) == 0) - break; - cpu_relax(); - } -} - -static void ulite_console_putchar(struct uart_port *port, int ch) -{ - ulite_console_wait_tx(port); - iowrite32be(ch, port->membase + ULITE_TX); -} - -static void ulite_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_port *port = &ulite_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - if (oops_in_progress) { - locked = spin_trylock_irqsave(&port->lock, flags); - } else - spin_lock_irqsave(&port->lock, flags); - - /* save and disable interrupt */ - ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - iowrite32be(0, port->membase + ULITE_CONTROL); - - uart_console_write(port, s, count, ulite_console_putchar); - - ulite_console_wait_tx(port); - - /* restore interrupt state */ - if (ier) - iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); - - if (locked) - spin_unlock_irqrestore(&port->lock, flags); -} - -static int __devinit ulite_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index < 0 || co->index >= ULITE_NR_UARTS) - return -EINVAL; - - port = &ulite_ports[co->index]; - - /* Has the device been initialized yet? */ - if (!port->mapbase) { - pr_debug("console on ttyUL%i not present\n", co->index); - return -ENODEV; - } - - /* not initialized yet? */ - if (!port->membase) { - if (ulite_request_port(port)) - 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 ulite_uart_driver; - -static struct console ulite_console = { - .name = ULITE_NAME, - .write = ulite_console_write, - .device = uart_console_device, - .setup = ulite_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */ - .data = &ulite_uart_driver, -}; - -static int __init ulite_console_init(void) -{ - register_console(&ulite_console); - return 0; -} - -console_initcall(ulite_console_init); - -#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ - -static struct uart_driver ulite_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "uartlite", - .dev_name = ULITE_NAME, - .major = ULITE_MAJOR, - .minor = ULITE_MINOR, - .nr = ULITE_NR_UARTS, -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE - .cons = &ulite_console, -#endif -}; - -/* --------------------------------------------------------------------- - * Port assignment functions (mapping devices to uart_port structures) - */ - -/** ulite_assign: register a uartlite device with the driver - * - * @dev: pointer to device structure - * @id: requested id number. Pass -1 for automatic port assignment - * @base: base address of uartlite registers - * @irq: irq number for uartlite - * - * Returns: 0 on success, <0 otherwise - */ -static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) -{ - struct uart_port *port; - int rc; - - /* if id = -1; then scan for a free id and use that */ - if (id < 0) { - for (id = 0; id < ULITE_NR_UARTS; id++) - if (ulite_ports[id].mapbase == 0) - break; - } - if (id < 0 || id >= ULITE_NR_UARTS) { - dev_err(dev, "%s%i too large\n", ULITE_NAME, id); - return -EINVAL; - } - - if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) { - dev_err(dev, "cannot assign to %s%i; it is already in use\n", - ULITE_NAME, id); - return -EBUSY; - } - - port = &ulite_ports[id]; - - spin_lock_init(&port->lock); - port->fifosize = 16; - port->regshift = 2; - port->iotype = UPIO_MEM; - port->iobase = 1; /* mark port in use */ - port->mapbase = base; - port->membase = NULL; - port->ops = &ulite_ops; - port->irq = irq; - port->flags = UPF_BOOT_AUTOCONF; - port->dev = dev; - port->type = PORT_UNKNOWN; - port->line = id; - - dev_set_drvdata(dev, port); - - /* Register the port */ - rc = uart_add_one_port(&ulite_uart_driver, port); - if (rc) { - dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc); - port->mapbase = 0; - dev_set_drvdata(dev, NULL); - return rc; - } - - return 0; -} - -/** ulite_release: register a uartlite device with the driver - * - * @dev: pointer to device structure - */ -static int __devexit ulite_release(struct device *dev) -{ - struct uart_port *port = dev_get_drvdata(dev); - int rc = 0; - - if (port) { - rc = uart_remove_one_port(&ulite_uart_driver, port); - dev_set_drvdata(dev, NULL); - port->mapbase = 0; - } - - return rc; -} - -/* --------------------------------------------------------------------- - * Platform bus binding - */ - -static int __devinit ulite_probe(struct platform_device *pdev) -{ - struct resource *res, *res2; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; - - return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); -} - -static int __devexit ulite_remove(struct platform_device *pdev) -{ - return ulite_release(&pdev->dev); -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:uartlite"); - -static struct platform_driver ulite_platform_driver = { - .probe = ulite_probe, - .remove = __devexit_p(ulite_remove), - .driver = { - .owner = THIS_MODULE, - .name = "uartlite", - }, -}; - -/* --------------------------------------------------------------------- - * OF bus bindings - */ -#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) -static int __devinit -ulite_of_probe(struct platform_device *op, const struct of_device_id *match) -{ - struct resource res; - const unsigned int *id; - int irq, rc; - - dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match); - - rc = of_address_to_resource(op->dev.of_node, 0, &res); - if (rc) { - dev_err(&op->dev, "invalid address\n"); - return rc; - } - - irq = irq_of_parse_and_map(op->dev.of_node, 0); - - id = of_get_property(op->dev.of_node, "port-number", NULL); - - return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); -} - -static int __devexit ulite_of_remove(struct platform_device *op) -{ - return ulite_release(&op->dev); -} - -static struct of_platform_driver ulite_of_driver = { - .probe = ulite_of_probe, - .remove = __devexit_p(ulite_of_remove), - .driver = { - .name = "uartlite", - .owner = THIS_MODULE, - .of_match_table = ulite_of_match, - }, -}; - -/* Registration helpers to keep the number of #ifdefs to a minimum */ -static inline int __init ulite_of_register(void) -{ - pr_debug("uartlite: calling of_register_platform_driver()\n"); - return of_register_platform_driver(&ulite_of_driver); -} - -static inline void __exit ulite_of_unregister(void) -{ - of_unregister_platform_driver(&ulite_of_driver); -} -#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ -/* Appropriate config not enabled; do nothing helpers */ -static inline int __init ulite_of_register(void) { return 0; } -static inline void __exit ulite_of_unregister(void) { } -#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ - -/* --------------------------------------------------------------------- - * Module setup/teardown - */ - -int __init ulite_init(void) -{ - int ret; - - pr_debug("uartlite: calling uart_register_driver()\n"); - ret = uart_register_driver(&ulite_uart_driver); - if (ret) - goto err_uart; - - ret = ulite_of_register(); - if (ret) - goto err_of; - - pr_debug("uartlite: calling platform_driver_register()\n"); - ret = platform_driver_register(&ulite_platform_driver); - if (ret) - goto err_plat; - - return 0; - -err_plat: - ulite_of_unregister(); -err_of: - uart_unregister_driver(&ulite_uart_driver); -err_uart: - printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); - return ret; -} - -void __exit ulite_exit(void) -{ - platform_driver_unregister(&ulite_platform_driver); - ulite_of_unregister(); - uart_unregister_driver(&ulite_uart_driver); -} - -module_init(ulite_init); -module_exit(ulite_exit); - -MODULE_AUTHOR("Peter Korsgaard "); -MODULE_DESCRIPTION("Xilinx uartlite serial driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c deleted file mode 100644 index 3f4848e2174a..000000000000 --- a/drivers/serial/ucc_uart.c +++ /dev/null @@ -1,1537 +0,0 @@ -/* - * Freescale QUICC Engine UART device driver - * - * Author: Timur Tabi - * - * Copyright 2007 Freescale Semiconductor, Inc. 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. - * - * This driver adds support for UART devices via Freescale's QUICC Engine - * found on some Freescale SOCs. - * - * If Soft-UART support is needed but not already present, then this driver - * will request and upload the "Soft-UART" microcode upon probe. The - * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X" - * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC, - * (e.g. "11" for 1.1). - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* - * The GUMR flag for Soft UART. This would normally be defined in qe.h, - * but Soft-UART is a hack and we want to keep everything related to it in - * this file. - */ -#define UCC_SLOW_GUMR_H_SUART 0x00004000 /* Soft-UART */ - -/* - * soft_uart is 1 if we need to use Soft-UART mode - */ -static int soft_uart; -/* - * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise. - */ -static int firmware_loaded; - -/* Enable this macro to configure all serial ports in internal loopback - mode */ -/* #define LOOPBACK */ - -/* The major and minor device numbers are defined in - * http://www.lanana.org/docs/device-list/devices-2.6+.txt. For the QE - * UART, we have major number 204 and minor numbers 46 - 49, which are the - * same as for the CPM2. This decision was made because no Freescale part - * has both a CPM and a QE. - */ -#define SERIAL_QE_MAJOR 204 -#define SERIAL_QE_MINOR 46 - -/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */ -#define UCC_MAX_UART 4 - -/* The number of buffer descriptors for receiving characters. */ -#define RX_NUM_FIFO 4 - -/* The number of buffer descriptors for transmitting characters. */ -#define TX_NUM_FIFO 4 - -/* The maximum size of the character buffer for a single RX BD. */ -#define RX_BUF_SIZE 32 - -/* The maximum size of the character buffer for a single TX BD. */ -#define TX_BUF_SIZE 32 - -/* - * The number of jiffies to wait after receiving a close command before the - * device is actually closed. This allows the last few characters to be - * sent over the wire. - */ -#define UCC_WAIT_CLOSING 100 - -struct ucc_uart_pram { - struct ucc_slow_pram common; - u8 res1[8]; /* reserved */ - __be16 maxidl; /* Maximum idle chars */ - __be16 idlc; /* temp idle counter */ - __be16 brkcr; /* Break count register */ - __be16 parec; /* receive parity error counter */ - __be16 frmec; /* receive framing error counter */ - __be16 nosec; /* receive noise counter */ - __be16 brkec; /* receive break condition counter */ - __be16 brkln; /* last received break length */ - __be16 uaddr[2]; /* UART address character 1 & 2 */ - __be16 rtemp; /* Temp storage */ - __be16 toseq; /* Transmit out of sequence char */ - __be16 cchars[8]; /* control characters 1-8 */ - __be16 rccm; /* receive control character mask */ - __be16 rccr; /* receive control character register */ - __be16 rlbc; /* receive last break character */ - __be16 res2; /* reserved */ - __be32 res3; /* reserved, should be cleared */ - u8 res4; /* reserved, should be cleared */ - u8 res5[3]; /* reserved, should be cleared */ - __be32 res6; /* reserved, should be cleared */ - __be32 res7; /* reserved, should be cleared */ - __be32 res8; /* reserved, should be cleared */ - __be32 res9; /* reserved, should be cleared */ - __be32 res10; /* reserved, should be cleared */ - __be32 res11; /* reserved, should be cleared */ - __be32 res12; /* reserved, should be cleared */ - __be32 res13; /* reserved, should be cleared */ -/* The rest is for Soft-UART only */ - __be16 supsmr; /* 0x90, Shadow UPSMR */ - __be16 res92; /* 0x92, reserved, initialize to 0 */ - __be32 rx_state; /* 0x94, RX state, initialize to 0 */ - __be32 rx_cnt; /* 0x98, RX count, initialize to 0 */ - u8 rx_length; /* 0x9C, Char length, set to 1+CL+PEN+1+SL */ - u8 rx_bitmark; /* 0x9D, reserved, initialize to 0 */ - u8 rx_temp_dlst_qe; /* 0x9E, reserved, initialize to 0 */ - u8 res14[0xBC - 0x9F]; /* reserved */ - __be32 dump_ptr; /* 0xBC, Dump pointer */ - __be32 rx_frame_rem; /* 0xC0, reserved, initialize to 0 */ - u8 rx_frame_rem_size; /* 0xC4, reserved, initialize to 0 */ - u8 tx_mode; /* 0xC5, mode, 0=AHDLC, 1=UART */ - __be16 tx_state; /* 0xC6, TX state */ - u8 res15[0xD0 - 0xC8]; /* reserved */ - __be32 resD0; /* 0xD0, reserved, initialize to 0 */ - u8 resD4; /* 0xD4, reserved, initialize to 0 */ - __be16 resD5; /* 0xD5, reserved, initialize to 0 */ -} __attribute__ ((packed)); - -/* SUPSMR definitions, for Soft-UART only */ -#define UCC_UART_SUPSMR_SL 0x8000 -#define UCC_UART_SUPSMR_RPM_MASK 0x6000 -#define UCC_UART_SUPSMR_RPM_ODD 0x0000 -#define UCC_UART_SUPSMR_RPM_LOW 0x2000 -#define UCC_UART_SUPSMR_RPM_EVEN 0x4000 -#define UCC_UART_SUPSMR_RPM_HIGH 0x6000 -#define UCC_UART_SUPSMR_PEN 0x1000 -#define UCC_UART_SUPSMR_TPM_MASK 0x0C00 -#define UCC_UART_SUPSMR_TPM_ODD 0x0000 -#define UCC_UART_SUPSMR_TPM_LOW 0x0400 -#define UCC_UART_SUPSMR_TPM_EVEN 0x0800 -#define UCC_UART_SUPSMR_TPM_HIGH 0x0C00 -#define UCC_UART_SUPSMR_FRZ 0x0100 -#define UCC_UART_SUPSMR_UM_MASK 0x00c0 -#define UCC_UART_SUPSMR_UM_NORMAL 0x0000 -#define UCC_UART_SUPSMR_UM_MAN_MULTI 0x0040 -#define UCC_UART_SUPSMR_UM_AUTO_MULTI 0x00c0 -#define UCC_UART_SUPSMR_CL_MASK 0x0030 -#define UCC_UART_SUPSMR_CL_8 0x0030 -#define UCC_UART_SUPSMR_CL_7 0x0020 -#define UCC_UART_SUPSMR_CL_6 0x0010 -#define UCC_UART_SUPSMR_CL_5 0x0000 - -#define UCC_UART_TX_STATE_AHDLC 0x00 -#define UCC_UART_TX_STATE_UART 0x01 -#define UCC_UART_TX_STATE_X1 0x00 -#define UCC_UART_TX_STATE_X16 0x80 - -#define UCC_UART_PRAM_ALIGNMENT 0x100 - -#define UCC_UART_SIZE_OF_BD UCC_SLOW_SIZE_OF_BD -#define NUM_CONTROL_CHARS 8 - -/* Private per-port data structure */ -struct uart_qe_port { - struct uart_port port; - struct ucc_slow __iomem *uccp; - struct ucc_uart_pram __iomem *uccup; - struct ucc_slow_info us_info; - struct ucc_slow_private *us_private; - struct device_node *np; - unsigned int ucc_num; /* First ucc is 0, not 1 */ - - u16 rx_nrfifos; - u16 rx_fifosize; - u16 tx_nrfifos; - u16 tx_fifosize; - int wait_closing; - u32 flags; - struct qe_bd *rx_bd_base; - struct qe_bd *rx_cur; - struct qe_bd *tx_bd_base; - struct qe_bd *tx_cur; - unsigned char *tx_buf; - unsigned char *rx_buf; - void *bd_virt; /* virtual address of the BD buffers */ - dma_addr_t bd_dma_addr; /* bus address of the BD buffers */ - unsigned int bd_size; /* size of BD buffer space */ -}; - -static struct uart_driver ucc_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "ucc_uart", - .dev_name = "ttyQE", - .major = SERIAL_QE_MAJOR, - .minor = SERIAL_QE_MINOR, - .nr = UCC_MAX_UART, -}; - -/* - * Virtual to physical address translation. - * - * Given the virtual address for a character buffer, this function returns - * the physical (DMA) equivalent. - */ -static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port) -{ - if (likely((addr >= qe_port->bd_virt)) && - (addr < (qe_port->bd_virt + qe_port->bd_size))) - return qe_port->bd_dma_addr + (addr - qe_port->bd_virt); - - /* something nasty happened */ - printk(KERN_ERR "%s: addr=%p\n", __func__, addr); - BUG(); - return 0; -} - -/* - * Physical to virtual address translation. - * - * Given the physical (DMA) address for a character buffer, this function - * returns the virtual equivalent. - */ -static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port) -{ - /* sanity check */ - if (likely((addr >= qe_port->bd_dma_addr) && - (addr < (qe_port->bd_dma_addr + qe_port->bd_size)))) - return qe_port->bd_virt + (addr - qe_port->bd_dma_addr); - - /* something nasty happened */ - printk(KERN_ERR "%s: addr=%x\n", __func__, addr); - BUG(); - return NULL; -} - -/* - * Return 1 if the QE is done transmitting all buffers for this port - * - * This function scans each BD in sequence. If we find a BD that is not - * ready (READY=1), then we return 0 indicating that the QE is still sending - * data. If we reach the last BD (WRAP=1), then we know we've scanned - * the entire list, and all BDs are done. - */ -static unsigned int qe_uart_tx_empty(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - struct qe_bd *bdp = qe_port->tx_bd_base; - - while (1) { - if (in_be16(&bdp->status) & BD_SC_READY) - /* This BD is not done, so return "not done" */ - return 0; - - if (in_be16(&bdp->status) & BD_SC_WRAP) - /* - * This BD is done and it's the last one, so return - * "done" - */ - return 1; - - bdp++; - }; -} - -/* - * Set the modem control lines - * - * Although the QE can control the modem control lines (e.g. CTS), we - * don't need that support. This function must exist, however, otherwise - * the kernel will panic. - */ -void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -/* - * Get the current modem control line status - * - * Although the QE can control the modem control lines (e.g. CTS), this - * driver currently doesn't support that, so we always return Carrier - * Detect, Data Set Ready, and Clear To Send. - */ -static unsigned int qe_uart_get_mctrl(struct uart_port *port) -{ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; -} - -/* - * Disable the transmit interrupt. - * - * Although this function is called "stop_tx", it does not actually stop - * transmission of data. Instead, it tells the QE to not generate an - * interrupt when the UCC is finished sending characters. - */ -static void qe_uart_stop_tx(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - - clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); -} - -/* - * Transmit as many characters to the HW as possible. - * - * This function will attempt to stuff of all the characters from the - * kernel's transmit buffer into TX BDs. - * - * A return value of non-zero indicates that it successfully stuffed all - * characters from the kernel buffer. - * - * A return value of zero indicates that there are still characters in the - * kernel's buffer that have not been transmitted, but there are no more BDs - * available. This function should be called again after a BD has been made - * available. - */ -static int qe_uart_tx_pump(struct uart_qe_port *qe_port) -{ - struct qe_bd *bdp; - unsigned char *p; - unsigned int count; - struct uart_port *port = &qe_port->port; - struct circ_buf *xmit = &port->state->xmit; - - bdp = qe_port->rx_cur; - - /* Handle xon/xoff */ - if (port->x_char) { - /* Pick next descriptor and fill from buffer */ - bdp = qe_port->tx_cur; - - p = qe2cpu_addr(bdp->buf, qe_port); - - *p++ = port->x_char; - out_be16(&bdp->length, 1); - setbits16(&bdp->status, BD_SC_READY); - /* Get next BD. */ - if (in_be16(&bdp->status) & BD_SC_WRAP) - bdp = qe_port->tx_bd_base; - else - bdp++; - qe_port->tx_cur = bdp; - - port->icount.tx++; - port->x_char = 0; - return 1; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - qe_uart_stop_tx(port); - return 0; - } - - /* Pick next descriptor and fill from buffer */ - bdp = qe_port->tx_cur; - - while (!(in_be16(&bdp->status) & BD_SC_READY) && - (xmit->tail != xmit->head)) { - count = 0; - p = qe2cpu_addr(bdp->buf, qe_port); - while (count < qe_port->tx_fifosize) { - *p++ = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - count++; - if (xmit->head == xmit->tail) - break; - } - - out_be16(&bdp->length, count); - setbits16(&bdp->status, BD_SC_READY); - - /* Get next BD. */ - if (in_be16(&bdp->status) & BD_SC_WRAP) - bdp = qe_port->tx_bd_base; - else - bdp++; - } - qe_port->tx_cur = bdp; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) { - /* The kernel buffer is empty, so turn off TX interrupts. We - don't need to be told when the QE is finished transmitting - the data. */ - qe_uart_stop_tx(port); - return 0; - } - - return 1; -} - -/* - * Start transmitting data - * - * This function will start transmitting any available data, if the port - * isn't already transmitting data. - */ -static void qe_uart_start_tx(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - - /* If we currently are transmitting, then just return */ - if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) - return; - - /* Otherwise, pump the port and start transmission */ - if (qe_uart_tx_pump(qe_port)) - setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); -} - -/* - * Stop transmitting data - */ -static void qe_uart_stop_rx(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - - clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); -} - -/* - * Enable status change interrupts - * - * We don't support status change interrupts, but we need to define this - * function otherwise the kernel will panic. - */ -static void qe_uart_enable_ms(struct uart_port *port) -{ -} - -/* Start or stop sending break signal - * - * This function controls the sending of a break signal. If break_state=1, - * then we start sending a break signal. If break_state=0, then we stop - * sending the break signal. - */ -static void qe_uart_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - - if (break_state) - ucc_slow_stop_tx(qe_port->us_private); - else - ucc_slow_restart_tx(qe_port->us_private); -} - -/* ISR helper function for receiving character. - * - * This function is called by the ISR to handling receiving characters - */ -static void qe_uart_int_rx(struct uart_qe_port *qe_port) -{ - int i; - unsigned char ch, *cp; - struct uart_port *port = &qe_port->port; - struct tty_struct *tty = port->state->port.tty; - struct qe_bd *bdp; - u16 status; - unsigned int flg; - - /* Just loop through the closed BDs and copy the characters into - * the buffer. - */ - bdp = qe_port->rx_cur; - while (1) { - status = in_be16(&bdp->status); - - /* If this one is empty, then we assume we've read them all */ - if (status & BD_SC_EMPTY) - break; - - /* get number of characters, and check space in RX buffer */ - i = in_be16(&bdp->length); - - /* If we don't have enough room in RX buffer for the entire BD, - * then we try later, which will be the next RX interrupt. - */ - if (tty_buffer_request_room(tty, i) < i) { - dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n"); - return; - } - - /* get pointer */ - cp = qe2cpu_addr(bdp->buf, qe_port); - - /* loop through the buffer */ - while (i-- > 0) { - ch = *cp++; - port->icount.rx++; - flg = TTY_NORMAL; - - if (!i && status & - (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) - goto handle_error; - if (uart_handle_sysrq_char(port, ch)) - continue; - -error_return: - tty_insert_flip_char(tty, ch, flg); - - } - - /* This BD is ready to be used again. Clear status. get next */ - clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR | - BD_SC_OV | BD_SC_ID, BD_SC_EMPTY); - if (in_be16(&bdp->status) & BD_SC_WRAP) - bdp = qe_port->rx_bd_base; - else - bdp++; - - } - - /* Write back buffer pointer */ - qe_port->rx_cur = bdp; - - /* Activate BH processing */ - tty_flip_buffer_push(tty); - - return; - - /* Error processing */ - -handle_error: - /* Statistics */ - if (status & BD_SC_BR) - port->icount.brk++; - if (status & BD_SC_PR) - port->icount.parity++; - if (status & BD_SC_FR) - port->icount.frame++; - if (status & BD_SC_OV) - port->icount.overrun++; - - /* Mask out ignored conditions */ - status &= port->read_status_mask; - - /* Handle the remaining ones */ - if (status & BD_SC_BR) - flg = TTY_BREAK; - else if (status & BD_SC_PR) - flg = TTY_PARITY; - else if (status & BD_SC_FR) - flg = TTY_FRAME; - - /* Overrun does not affect the current character ! */ - if (status & BD_SC_OV) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif - goto error_return; -} - -/* Interrupt handler - * - * This interrupt handler is called after a BD is processed. - */ -static irqreturn_t qe_uart_int(int irq, void *data) -{ - struct uart_qe_port *qe_port = (struct uart_qe_port *) data; - struct ucc_slow __iomem *uccp = qe_port->uccp; - u16 events; - - /* Clear the interrupts */ - events = in_be16(&uccp->ucce); - out_be16(&uccp->ucce, events); - - if (events & UCC_UART_UCCE_BRKE) - uart_handle_break(&qe_port->port); - - if (events & UCC_UART_UCCE_RX) - qe_uart_int_rx(qe_port); - - if (events & UCC_UART_UCCE_TX) - qe_uart_tx_pump(qe_port); - - return events ? IRQ_HANDLED : IRQ_NONE; -} - -/* Initialize buffer descriptors - * - * This function initializes all of the RX and TX buffer descriptors. - */ -static void qe_uart_initbd(struct uart_qe_port *qe_port) -{ - int i; - void *bd_virt; - struct qe_bd *bdp; - - /* Set the physical address of the host memory buffers in the buffer - * descriptors, and the virtual address for us to work with. - */ - bd_virt = qe_port->bd_virt; - bdp = qe_port->rx_bd_base; - qe_port->rx_cur = qe_port->rx_bd_base; - for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) { - out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT); - out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); - out_be16(&bdp->length, 0); - bd_virt += qe_port->rx_fifosize; - bdp++; - } - - /* */ - out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); - out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); - out_be16(&bdp->length, 0); - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - bd_virt = qe_port->bd_virt + - L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); - qe_port->tx_cur = qe_port->tx_bd_base; - bdp = qe_port->tx_bd_base; - for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) { - out_be16(&bdp->status, BD_SC_INTRPT); - out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); - out_be16(&bdp->length, 0); - bd_virt += qe_port->tx_fifosize; - bdp++; - } - - /* Loopback requires the preamble bit to be set on the first TX BD */ -#ifdef LOOPBACK - setbits16(&qe_port->tx_cur->status, BD_SC_P); -#endif - - out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT); - out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); - out_be16(&bdp->length, 0); -} - -/* - * Initialize a UCC for UART. - * - * This function configures a given UCC to be used as a UART device. Basic - * UCC initialization is handled in qe_uart_request_port(). This function - * does all the UART-specific stuff. - */ -static void qe_uart_init_ucc(struct uart_qe_port *qe_port) -{ - u32 cecr_subblock; - struct ucc_slow __iomem *uccp = qe_port->uccp; - struct ucc_uart_pram *uccup = qe_port->uccup; - - unsigned int i; - - /* First, disable TX and RX in the UCC */ - ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); - - /* Program the UCC UART parameter RAM */ - out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE); - out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE); - out_be16(&uccup->common.mrblr, qe_port->rx_fifosize); - out_be16(&uccup->maxidl, 0x10); - out_be16(&uccup->brkcr, 1); - out_be16(&uccup->parec, 0); - out_be16(&uccup->frmec, 0); - out_be16(&uccup->nosec, 0); - out_be16(&uccup->brkec, 0); - out_be16(&uccup->uaddr[0], 0); - out_be16(&uccup->uaddr[1], 0); - out_be16(&uccup->toseq, 0); - for (i = 0; i < 8; i++) - out_be16(&uccup->cchars[i], 0xC000); - out_be16(&uccup->rccm, 0xc0ff); - - /* Configure the GUMR registers for UART */ - if (soft_uart) { - /* Soft-UART requires a 1X multiplier for TX */ - clrsetbits_be32(&uccp->gumr_l, - UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | - UCC_SLOW_GUMR_L_RDCR_MASK, - UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 | - UCC_SLOW_GUMR_L_RDCR_16); - - clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW, - UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX); - } else { - clrsetbits_be32(&uccp->gumr_l, - UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | - UCC_SLOW_GUMR_L_RDCR_MASK, - UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 | - UCC_SLOW_GUMR_L_RDCR_16); - - clrsetbits_be32(&uccp->gumr_h, - UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX, - UCC_SLOW_GUMR_H_RFW); - } - -#ifdef LOOPBACK - clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, - UCC_SLOW_GUMR_L_DIAG_LOOP); - clrsetbits_be32(&uccp->gumr_h, - UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN, - UCC_SLOW_GUMR_H_CDS); -#endif - - /* Disable rx interrupts and clear all pending events. */ - out_be16(&uccp->uccm, 0); - out_be16(&uccp->ucce, 0xffff); - out_be16(&uccp->udsr, 0x7e7e); - - /* Initialize UPSMR */ - out_be16(&uccp->upsmr, 0); - - if (soft_uart) { - out_be16(&uccup->supsmr, 0x30); - out_be16(&uccup->res92, 0); - out_be32(&uccup->rx_state, 0); - out_be32(&uccup->rx_cnt, 0); - out_8(&uccup->rx_bitmark, 0); - out_8(&uccup->rx_length, 10); - out_be32(&uccup->dump_ptr, 0x4000); - out_8(&uccup->rx_temp_dlst_qe, 0); - out_be32(&uccup->rx_frame_rem, 0); - out_8(&uccup->rx_frame_rem_size, 0); - /* Soft-UART requires TX to be 1X */ - out_8(&uccup->tx_mode, - UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1); - out_be16(&uccup->tx_state, 0); - out_8(&uccup->resD4, 0); - out_be16(&uccup->resD5, 0); - - /* Set UART mode. - * Enable receive and transmit. - */ - - /* From the microcode errata: - * 1.GUMR_L register, set mode=0010 (QMC). - * 2.Set GUMR_H[17] bit. (UART/AHDLC mode). - * 3.Set GUMR_H[19:20] (Transparent mode) - * 4.Clear GUMR_H[26] (RFW) - * ... - * 6.Receiver must use 16x over sampling - */ - clrsetbits_be32(&uccp->gumr_l, - UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | - UCC_SLOW_GUMR_L_RDCR_MASK, - UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 | - UCC_SLOW_GUMR_L_RDCR_16); - - clrsetbits_be32(&uccp->gumr_h, - UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN, - UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX | - UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL); - -#ifdef LOOPBACK - clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, - UCC_SLOW_GUMR_L_DIAG_LOOP); - clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP | - UCC_SLOW_GUMR_H_CDS); -#endif - - cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); - qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, - QE_CR_PROTOCOL_UNSPECIFIED, 0); - } else { - cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); - qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, - QE_CR_PROTOCOL_UART, 0); - } -} - -/* - * Initialize the port. - */ -static int qe_uart_startup(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - int ret; - - /* - * If we're using Soft-UART mode, then we need to make sure the - * firmware has been uploaded first. - */ - if (soft_uart && !firmware_loaded) { - dev_err(port->dev, "Soft-UART firmware not uploaded\n"); - return -ENODEV; - } - - qe_uart_initbd(qe_port); - qe_uart_init_ucc(qe_port); - - /* Install interrupt handler. */ - ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart", - qe_port); - if (ret) { - dev_err(port->dev, "could not claim IRQ %u\n", port->irq); - return ret; - } - - /* Startup rx-int */ - setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); - ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX); - - return 0; -} - -/* - * Shutdown the port. - */ -static void qe_uart_shutdown(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - struct ucc_slow __iomem *uccp = qe_port->uccp; - unsigned int timeout = 20; - - /* Disable RX and TX */ - - /* Wait for all the BDs marked sent */ - while (!qe_uart_tx_empty(port)) { - if (!--timeout) { - dev_warn(port->dev, "shutdown timeout\n"); - break; - } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(2); - } - - if (qe_port->wait_closing) { - /* Wait a bit longer */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(qe_port->wait_closing); - } - - /* Stop uarts */ - ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); - clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX); - - /* Shut them really down and reinit buffer descriptors */ - ucc_slow_graceful_stop_tx(qe_port->us_private); - qe_uart_initbd(qe_port); - - free_irq(port->irq, qe_port); -} - -/* - * Set the serial port parameters. - */ -static void qe_uart_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - struct ucc_slow __iomem *uccp = qe_port->uccp; - unsigned int baud; - unsigned long flags; - u16 upsmr = in_be16(&uccp->upsmr); - struct ucc_uart_pram __iomem *uccup = qe_port->uccup; - u16 supsmr = in_be16(&uccup->supsmr); - u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */ - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ - - /* byte size */ - upsmr &= UCC_UART_UPSMR_CL_MASK; - supsmr &= UCC_UART_SUPSMR_CL_MASK; - - switch (termios->c_cflag & CSIZE) { - case CS5: - upsmr |= UCC_UART_UPSMR_CL_5; - supsmr |= UCC_UART_SUPSMR_CL_5; - char_length += 5; - break; - case CS6: - upsmr |= UCC_UART_UPSMR_CL_6; - supsmr |= UCC_UART_SUPSMR_CL_6; - char_length += 6; - break; - case CS7: - upsmr |= UCC_UART_UPSMR_CL_7; - supsmr |= UCC_UART_SUPSMR_CL_7; - char_length += 7; - break; - default: /* case CS8 */ - upsmr |= UCC_UART_UPSMR_CL_8; - supsmr |= UCC_UART_SUPSMR_CL_8; - char_length += 8; - break; - } - - /* If CSTOPB is set, we want two stop bits */ - if (termios->c_cflag & CSTOPB) { - upsmr |= UCC_UART_UPSMR_SL; - supsmr |= UCC_UART_SUPSMR_SL; - char_length++; /* + SL */ - } - - if (termios->c_cflag & PARENB) { - upsmr |= UCC_UART_UPSMR_PEN; - supsmr |= UCC_UART_SUPSMR_PEN; - char_length++; /* + PEN */ - - if (!(termios->c_cflag & PARODD)) { - upsmr &= ~(UCC_UART_UPSMR_RPM_MASK | - UCC_UART_UPSMR_TPM_MASK); - upsmr |= UCC_UART_UPSMR_RPM_EVEN | - UCC_UART_UPSMR_TPM_EVEN; - supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK | - UCC_UART_SUPSMR_TPM_MASK); - supsmr |= UCC_UART_SUPSMR_RPM_EVEN | - UCC_UART_SUPSMR_TPM_EVEN; - } - } - - /* - * Set up parity check flag - */ - port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; - if (termios->c_iflag & INPCK) - port->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= BD_SC_BR; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= BD_SC_BR; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= BD_SC_OV; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - port->read_status_mask &= ~BD_SC_EMPTY; - - baud = uart_get_baud_rate(port, termios, old, 0, 115200); - - /* Do we really need a spinlock here? */ - spin_lock_irqsave(&port->lock, flags); - - out_be16(&uccp->upsmr, upsmr); - if (soft_uart) { - out_be16(&uccup->supsmr, supsmr); - out_8(&uccup->rx_length, char_length); - - /* Soft-UART requires a 1X multiplier for TX */ - qe_setbrg(qe_port->us_info.rx_clock, baud, 16); - qe_setbrg(qe_port->us_info.tx_clock, baud, 1); - } else { - qe_setbrg(qe_port->us_info.rx_clock, baud, 16); - qe_setbrg(qe_port->us_info.tx_clock, baud, 16); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* - * Return a pointer to a string that describes what kind of port this is. - */ -static const char *qe_uart_type(struct uart_port *port) -{ - return "QE"; -} - -/* - * Allocate any memory and I/O resources required by the port. - */ -static int qe_uart_request_port(struct uart_port *port) -{ - int ret; - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - struct ucc_slow_info *us_info = &qe_port->us_info; - struct ucc_slow_private *uccs; - unsigned int rx_size, tx_size; - void *bd_virt; - dma_addr_t bd_dma_addr = 0; - - ret = ucc_slow_init(us_info, &uccs); - if (ret) { - dev_err(port->dev, "could not initialize UCC%u\n", - qe_port->ucc_num); - return ret; - } - - qe_port->us_private = uccs; - qe_port->uccp = uccs->us_regs; - qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram; - qe_port->rx_bd_base = uccs->rx_bd; - qe_port->tx_bd_base = uccs->tx_bd; - - /* - * Allocate the transmit and receive data buffers. - */ - - rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); - tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize); - - bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr, - GFP_KERNEL); - if (!bd_virt) { - dev_err(port->dev, "could not allocate buffer descriptors\n"); - return -ENOMEM; - } - - qe_port->bd_virt = bd_virt; - qe_port->bd_dma_addr = bd_dma_addr; - qe_port->bd_size = rx_size + tx_size; - - qe_port->rx_buf = bd_virt; - qe_port->tx_buf = qe_port->rx_buf + rx_size; - - return 0; -} - -/* - * Configure the port. - * - * We say we're a CPM-type port because that's mostly true. Once the device - * is configured, this driver operates almost identically to the CPM serial - * driver. - */ -static void qe_uart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_CPM; - qe_uart_request_port(port); - } -} - -/* - * Release any memory and I/O resources that were allocated in - * qe_uart_request_port(). - */ -static void qe_uart_release_port(struct uart_port *port) -{ - struct uart_qe_port *qe_port = - container_of(port, struct uart_qe_port, port); - struct ucc_slow_private *uccs = qe_port->us_private; - - dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt, - qe_port->bd_dma_addr); - - ucc_slow_free(uccs); -} - -/* - * Verify that the data in serial_struct is suitable for this device. - */ -static int qe_uart_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) - return -EINVAL; - - if (ser->irq < 0 || ser->irq >= nr_irqs) - return -EINVAL; - - if (ser->baud_base < 9600) - return -EINVAL; - - return 0; -} -/* UART operations - * - * Details on these functions can be found in Documentation/serial/driver - */ -static struct uart_ops qe_uart_pops = { - .tx_empty = qe_uart_tx_empty, - .set_mctrl = qe_uart_set_mctrl, - .get_mctrl = qe_uart_get_mctrl, - .stop_tx = qe_uart_stop_tx, - .start_tx = qe_uart_start_tx, - .stop_rx = qe_uart_stop_rx, - .enable_ms = qe_uart_enable_ms, - .break_ctl = qe_uart_break_ctl, - .startup = qe_uart_startup, - .shutdown = qe_uart_shutdown, - .set_termios = qe_uart_set_termios, - .type = qe_uart_type, - .release_port = qe_uart_release_port, - .request_port = qe_uart_request_port, - .config_port = qe_uart_config_port, - .verify_port = qe_uart_verify_port, -}; - -/* - * Obtain the SOC model number and revision level - * - * This function parses the device tree to obtain the SOC model. It then - * reads the SVR register to the revision. - * - * The device tree stores the SOC model two different ways. - * - * The new way is: - * - * cpu@0 { - * compatible = "PowerPC,8323"; - * device_type = "cpu"; - * ... - * - * - * The old way is: - * PowerPC,8323@0 { - * device_type = "cpu"; - * ... - * - * This code first checks the new way, and then the old way. - */ -static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) -{ - struct device_node *np; - const char *soc_string; - unsigned int svr; - unsigned int soc; - - /* Find the CPU node */ - np = of_find_node_by_type(NULL, "cpu"); - if (!np) - return 0; - /* Find the compatible property */ - soc_string = of_get_property(np, "compatible", NULL); - if (!soc_string) - /* No compatible property, so try the name. */ - soc_string = np->name; - - /* Extract the SOC number from the "PowerPC," string */ - if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) - return 0; - - /* Get the revision from the SVR */ - svr = mfspr(SPRN_SVR); - *rev_h = (svr >> 4) & 0xf; - *rev_l = svr & 0xf; - - return soc; -} - -/* - * requst_firmware_nowait() callback function - * - * This function is called by the kernel when a firmware is made available, - * or if it times out waiting for the firmware. - */ -static void uart_firmware_cont(const struct firmware *fw, void *context) -{ - struct qe_firmware *firmware; - struct device *dev = context; - int ret; - - if (!fw) { - dev_err(dev, "firmware not found\n"); - return; - } - - firmware = (struct qe_firmware *) fw->data; - - if (firmware->header.length != fw->size) { - dev_err(dev, "invalid firmware\n"); - goto out; - } - - ret = qe_upload_firmware(firmware); - if (ret) { - dev_err(dev, "could not load firmware\n"); - goto out; - } - - firmware_loaded = 1; - out: - release_firmware(fw); -} - -static int ucc_uart_probe(struct platform_device *ofdev, - const struct of_device_id *match) -{ - struct device_node *np = ofdev->dev.of_node; - const unsigned int *iprop; /* Integer OF properties */ - const char *sprop; /* String OF properties */ - struct uart_qe_port *qe_port = NULL; - struct resource res; - int ret; - - /* - * Determine if we need Soft-UART mode - */ - if (of_find_property(np, "soft-uart", NULL)) { - dev_dbg(&ofdev->dev, "using Soft-UART mode\n"); - soft_uart = 1; - } - - /* - * If we are using Soft-UART, determine if we need to upload the - * firmware, too. - */ - if (soft_uart) { - struct qe_firmware_info *qe_fw_info; - - qe_fw_info = qe_get_firmware_info(); - - /* Check if the firmware has been uploaded. */ - if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) { - firmware_loaded = 1; - } else { - char filename[32]; - unsigned int soc; - unsigned int rev_h; - unsigned int rev_l; - - soc = soc_info(&rev_h, &rev_l); - if (!soc) { - dev_err(&ofdev->dev, "unknown CPU model\n"); - return -ENXIO; - } - sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin", - soc, rev_h, rev_l); - - dev_info(&ofdev->dev, "waiting for firmware %s\n", - filename); - - /* - * We call request_firmware_nowait instead of - * request_firmware so that the driver can load and - * initialize the ports without holding up the rest of - * the kernel. If hotplug support is enabled in the - * kernel, then we use it. - */ - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, filename, &ofdev->dev, - GFP_KERNEL, &ofdev->dev, uart_firmware_cont); - if (ret) { - dev_err(&ofdev->dev, - "could not load firmware %s\n", - filename); - return ret; - } - } - } - - qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL); - if (!qe_port) { - dev_err(&ofdev->dev, "can't allocate QE port structure\n"); - return -ENOMEM; - } - - /* Search for IRQ and mapbase */ - ret = of_address_to_resource(np, 0, &res); - if (ret) { - dev_err(&ofdev->dev, "missing 'reg' property in device tree\n"); - kfree(qe_port); - return ret; - } - if (!res.start) { - dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n"); - kfree(qe_port); - return -EINVAL; - } - qe_port->port.mapbase = res.start; - - /* Get the UCC number (device ID) */ - /* UCCs are numbered 1-7 */ - iprop = of_get_property(np, "cell-index", NULL); - if (!iprop) { - iprop = of_get_property(np, "device-id", NULL); - if (!iprop) { - kfree(qe_port); - dev_err(&ofdev->dev, "UCC is unspecified in " - "device tree\n"); - return -EINVAL; - } - } - - if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) { - dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop); - kfree(qe_port); - return -ENODEV; - } - qe_port->ucc_num = *iprop - 1; - - /* - * In the future, we should not require the BRG to be specified in the - * device tree. If no clock-source is specified, then just pick a BRG - * to use. This requires a new QE library function that manages BRG - * assignments. - */ - - sprop = of_get_property(np, "rx-clock-name", NULL); - if (!sprop) { - dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n"); - kfree(qe_port); - return -ENODEV; - } - - qe_port->us_info.rx_clock = qe_clock_source(sprop); - if ((qe_port->us_info.rx_clock < QE_BRG1) || - (qe_port->us_info.rx_clock > QE_BRG16)) { - dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n"); - kfree(qe_port); - return -ENODEV; - } - -#ifdef LOOPBACK - /* In internal loopback mode, TX and RX must use the same clock */ - qe_port->us_info.tx_clock = qe_port->us_info.rx_clock; -#else - sprop = of_get_property(np, "tx-clock-name", NULL); - if (!sprop) { - dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n"); - kfree(qe_port); - return -ENODEV; - } - qe_port->us_info.tx_clock = qe_clock_source(sprop); -#endif - if ((qe_port->us_info.tx_clock < QE_BRG1) || - (qe_port->us_info.tx_clock > QE_BRG16)) { - dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n"); - kfree(qe_port); - return -ENODEV; - } - - /* Get the port number, numbered 0-3 */ - iprop = of_get_property(np, "port-number", NULL); - if (!iprop) { - dev_err(&ofdev->dev, "missing port-number in device tree\n"); - kfree(qe_port); - return -EINVAL; - } - qe_port->port.line = *iprop; - if (qe_port->port.line >= UCC_MAX_UART) { - dev_err(&ofdev->dev, "port-number must be 0-%u\n", - UCC_MAX_UART - 1); - kfree(qe_port); - return -EINVAL; - } - - qe_port->port.irq = irq_of_parse_and_map(np, 0); - if (qe_port->port.irq == NO_IRQ) { - dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", - qe_port->ucc_num + 1); - kfree(qe_port); - return -EINVAL; - } - - /* - * Newer device trees have an "fsl,qe" compatible property for the QE - * node, but we still need to support older device trees. - */ - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!np) { - np = of_find_node_by_type(NULL, "qe"); - if (!np) { - dev_err(&ofdev->dev, "could not find 'qe' node\n"); - kfree(qe_port); - return -EINVAL; - } - } - - iprop = of_get_property(np, "brg-frequency", NULL); - if (!iprop) { - dev_err(&ofdev->dev, - "missing brg-frequency in device tree\n"); - kfree(qe_port); - return -EINVAL; - } - - if (*iprop) - qe_port->port.uartclk = *iprop; - else { - /* - * Older versions of U-Boot do not initialize the brg-frequency - * property, so in this case we assume the BRG frequency is - * half the QE bus frequency. - */ - iprop = of_get_property(np, "bus-frequency", NULL); - if (!iprop) { - dev_err(&ofdev->dev, - "missing QE bus-frequency in device tree\n"); - kfree(qe_port); - return -EINVAL; - } - if (*iprop) - qe_port->port.uartclk = *iprop / 2; - else { - dev_err(&ofdev->dev, - "invalid QE bus-frequency in device tree\n"); - kfree(qe_port); - return -EINVAL; - } - } - - spin_lock_init(&qe_port->port.lock); - qe_port->np = np; - qe_port->port.dev = &ofdev->dev; - qe_port->port.ops = &qe_uart_pops; - qe_port->port.iotype = UPIO_MEM; - - qe_port->tx_nrfifos = TX_NUM_FIFO; - qe_port->tx_fifosize = TX_BUF_SIZE; - qe_port->rx_nrfifos = RX_NUM_FIFO; - qe_port->rx_fifosize = RX_BUF_SIZE; - - qe_port->wait_closing = UCC_WAIT_CLOSING; - qe_port->port.fifosize = 512; - qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; - - qe_port->us_info.ucc_num = qe_port->ucc_num; - qe_port->us_info.regs = (phys_addr_t) res.start; - qe_port->us_info.irq = qe_port->port.irq; - - qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos; - qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos; - - /* Make sure ucc_slow_init() initializes both TX and RX */ - qe_port->us_info.init_tx = 1; - qe_port->us_info.init_rx = 1; - - /* Add the port to the uart sub-system. This will cause - * qe_uart_config_port() to be called, so the us_info structure must - * be initialized. - */ - ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port); - if (ret) { - dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n", - qe_port->port.line); - kfree(qe_port); - return ret; - } - - dev_set_drvdata(&ofdev->dev, qe_port); - - dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n", - qe_port->ucc_num + 1, qe_port->port.line); - - /* Display the mknod command for this device */ - dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n", - qe_port->port.line, SERIAL_QE_MAJOR, - SERIAL_QE_MINOR + qe_port->port.line); - - return 0; -} - -static int ucc_uart_remove(struct platform_device *ofdev) -{ - struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev); - - dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line); - - uart_remove_one_port(&ucc_uart_driver, &qe_port->port); - - dev_set_drvdata(&ofdev->dev, NULL); - kfree(qe_port); - - return 0; -} - -static struct of_device_id ucc_uart_match[] = { - { - .type = "serial", - .compatible = "ucc_uart", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ucc_uart_match); - -static struct of_platform_driver ucc_uart_of_driver = { - .driver = { - .name = "ucc_uart", - .owner = THIS_MODULE, - .of_match_table = ucc_uart_match, - }, - .probe = ucc_uart_probe, - .remove = ucc_uart_remove, -}; - -static int __init ucc_uart_init(void) -{ - int ret; - - printk(KERN_INFO "Freescale QUICC Engine UART device driver\n"); -#ifdef LOOPBACK - printk(KERN_INFO "ucc-uart: Using loopback mode\n"); -#endif - - ret = uart_register_driver(&ucc_uart_driver); - if (ret) { - printk(KERN_ERR "ucc-uart: could not register UART driver\n"); - return ret; - } - - ret = of_register_platform_driver(&ucc_uart_of_driver); - if (ret) - printk(KERN_ERR - "ucc-uart: could not register platform driver\n"); - - return ret; -} - -static void __exit ucc_uart_exit(void) -{ - printk(KERN_INFO - "Freescale QUICC Engine UART device driver unloading\n"); - - of_unregister_platform_driver(&ucc_uart_of_driver); - uart_unregister_driver(&ucc_uart_driver); -} - -module_init(ucc_uart_init); -module_exit(ucc_uart_exit); - -MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART"); -MODULE_AUTHOR("Timur Tabi "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR); - diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c deleted file mode 100644 index 3beb6ab4fa68..000000000000 --- a/drivers/serial/vr41xx_siu.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Driver for NEC VR4100 series Serial Interface Unit. - * - * Copyright (C) 2004-2008 Yoichi Yuasa - * - * Based on drivers/serial/8250.c, by Russell King. - * - * 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 - */ - -#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SIU_BAUD_BASE 1152000 -#define SIU_MAJOR 204 -#define SIU_MINOR_BASE 82 - -#define RX_MAX_COUNT 256 -#define TX_MAX_COUNT 15 - -#define SIUIRSEL 0x08 - #define TMICMODE 0x20 - #define TMICTX 0x10 - #define IRMSEL 0x0c - #define IRMSEL_HP 0x08 - #define IRMSEL_TEMIC 0x04 - #define IRMSEL_SHARP 0x00 - #define IRUSESEL 0x02 - #define SIRSEL 0x01 - -static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { - [0 ... SIU_PORTS_MAX-1] = { - .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), - .irq = -1, - }, -}; - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE -static uint8_t lsr_break_flag[SIU_PORTS_MAX]; -#endif - -#define siu_read(port, offset) readb((port)->membase + (offset)) -#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset)) - -void vr41xx_select_siu_interface(siu_interface_t interface) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - if (interface == SIU_INTERFACE_IRDA) - irsel |= SIRSEL; - else - irsel &= ~SIRSEL; - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface); - -void vr41xx_use_irda(irda_use_t use) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - if (use == FIR_USE_IRDA) - irsel |= IRUSESEL; - else - irsel &= ~IRUSESEL; - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_use_irda); - -void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed) -{ - struct uart_port *port; - unsigned long flags; - uint8_t irsel; - - port = &siu_uart_ports[0]; - - spin_lock_irqsave(&port->lock, flags); - - irsel = siu_read(port, SIUIRSEL); - irsel &= ~(IRMSEL | TMICTX | TMICMODE); - switch (module) { - case SHARP_IRDA: - irsel |= IRMSEL_SHARP; - break; - case TEMIC_IRDA: - irsel |= IRMSEL_TEMIC | TMICMODE; - if (speed == IRDA_TX_4MBPS) - irsel |= TMICTX; - break; - case HP_IRDA: - irsel |= IRMSEL_HP; - break; - default: - break; - } - siu_write(port, SIUIRSEL, irsel); - - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(vr41xx_select_irda_module); - -static inline void siu_clear_fifo(struct uart_port *port) -{ - siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO); - siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - siu_write(port, UART_FCR, 0); -} - -static inline unsigned long siu_port_size(struct uart_port *port) -{ - switch (port->type) { - case PORT_VR41XX_SIU: - return 11UL; - case PORT_VR41XX_DSIU: - return 8UL; - } - - return 0; -} - -static inline unsigned int siu_check_type(struct uart_port *port) -{ - if (port->line == 0) - return PORT_VR41XX_SIU; - if (port->line == 1 && port->irq != -1) - return PORT_VR41XX_DSIU; - - return PORT_UNKNOWN; -} - -static inline const char *siu_type_name(struct uart_port *port) -{ - switch (port->type) { - case PORT_VR41XX_SIU: - return "SIU"; - case PORT_VR41XX_DSIU: - return "DSIU"; - } - - return NULL; -} - -static unsigned int siu_tx_empty(struct uart_port *port) -{ - uint8_t lsr; - - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_TEMT) - return TIOCSER_TEMT; - - return 0; -} - -static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - uint8_t mcr = 0; - - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - siu_write(port, UART_MCR, mcr); -} - -static unsigned int siu_get_mctrl(struct uart_port *port) -{ - uint8_t msr; - unsigned int mctrl = 0; - - msr = siu_read(port, UART_MSR); - if (msr & UART_MSR_DCD) - mctrl |= TIOCM_CAR; - if (msr & UART_MSR_RI) - mctrl |= TIOCM_RNG; - if (msr & UART_MSR_DSR) - mctrl |= TIOCM_DSR; - if (msr & UART_MSR_CTS) - mctrl |= TIOCM_CTS; - - return mctrl; -} - -static void siu_stop_tx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_THRI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_start_tx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier |= UART_IER_THRI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_stop_rx(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_RLSI; - siu_write(port, UART_IER, ier); - - port->read_status_mask &= ~UART_LSR_DR; - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_enable_ms(struct uart_port *port) -{ - unsigned long flags; - uint8_t ier; - - spin_lock_irqsave(&port->lock, flags); - - ier = siu_read(port, UART_IER); - ier |= UART_IER_MSI; - siu_write(port, UART_IER, ier); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_break_ctl(struct uart_port *port, int ctl) -{ - unsigned long flags; - uint8_t lcr; - - spin_lock_irqsave(&port->lock, flags); - - lcr = siu_read(port, UART_LCR); - if (ctl == -1) - lcr |= UART_LCR_SBC; - else - lcr &= ~UART_LCR_SBC; - siu_write(port, UART_LCR, lcr); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static inline void receive_chars(struct uart_port *port, uint8_t *status) -{ - struct tty_struct *tty; - uint8_t lsr, ch; - char flag; - int max_count = RX_MAX_COUNT; - - tty = port->state->port.tty; - lsr = *status; - - do { - ch = siu_read(port, UART_RX); - port->icount.rx++; - flag = TTY_NORMAL; - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE - lsr |= lsr_break_flag[port->line]; - lsr_break_flag[port->line] = 0; -#endif - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE | - UART_LSR_PE | UART_LSR_OE))) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - - if (uart_handle_break(port)) - goto ignore_char; - } - - if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_PE) - port->icount.parity++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - lsr &= port->read_status_mask; - if (lsr & UART_LSR_BI) - flag = TTY_BREAK; - if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - - ignore_char: - lsr = siu_read(port, UART_LSR); - } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); - - tty_flip_buffer_push(tty); - - *status = lsr; -} - -static inline void check_modem_status(struct uart_port *port) -{ - uint8_t msr; - - msr = siu_read(port, UART_MSR); - if ((msr & UART_MSR_ANY_DELTA) == 0) - return; - if (msr & UART_MSR_DDCD) - uart_handle_dcd_change(port, msr & UART_MSR_DCD); - if (msr & UART_MSR_TERI) - port->icount.rng++; - if (msr & UART_MSR_DDSR) - port->icount.dsr++; - if (msr & UART_MSR_DCTS) - uart_handle_cts_change(port, msr & UART_MSR_CTS); - - wake_up_interruptible(&port->state->port.delta_msr_wait); -} - -static inline void transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit; - int max_count = TX_MAX_COUNT; - - xmit = &port->state->xmit; - - if (port->x_char) { - siu_write(port, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - siu_stop_tx(port); - return; - } - - do { - siu_write(port, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (max_count-- > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - siu_stop_tx(port); -} - -static irqreturn_t siu_interrupt(int irq, void *dev_id) -{ - struct uart_port *port; - uint8_t iir, lsr; - - port = (struct uart_port *)dev_id; - - iir = siu_read(port, UART_IIR); - if (iir & UART_IIR_NO_INT) - return IRQ_NONE; - - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(port, &lsr); - - check_modem_status(port); - - if (lsr & UART_LSR_THRE) - transmit_chars(port); - - return IRQ_HANDLED; -} - -static int siu_startup(struct uart_port *port) -{ - int retval; - - if (port->membase == NULL) - return -ENODEV; - - siu_clear_fifo(port); - - (void)siu_read(port, UART_LSR); - (void)siu_read(port, UART_RX); - (void)siu_read(port, UART_IIR); - (void)siu_read(port, UART_MSR); - - if (siu_read(port, UART_LSR) == 0xff) - return -ENODEV; - - retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port); - if (retval) - return retval; - - if (port->type == PORT_VR41XX_DSIU) - vr41xx_enable_dsiuint(DSIUINT_ALL); - - siu_write(port, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irq(&port->lock); - siu_set_mctrl(port, port->mctrl); - spin_unlock_irq(&port->lock); - - siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI); - - (void)siu_read(port, UART_LSR); - (void)siu_read(port, UART_RX); - (void)siu_read(port, UART_IIR); - (void)siu_read(port, UART_MSR); - - return 0; -} - -static void siu_shutdown(struct uart_port *port) -{ - unsigned long flags; - uint8_t lcr; - - siu_write(port, UART_IER, 0); - - spin_lock_irqsave(&port->lock, flags); - - port->mctrl &= ~TIOCM_OUT2; - siu_set_mctrl(port, port->mctrl); - - spin_unlock_irqrestore(&port->lock, flags); - - lcr = siu_read(port, UART_LCR); - lcr &= ~UART_LCR_SBC; - siu_write(port, UART_LCR, lcr); - - siu_clear_fifo(port); - - (void)siu_read(port, UART_RX); - - if (port->type == PORT_VR41XX_DSIU) - vr41xx_disable_dsiuint(DSIUINT_ALL); - - free_irq(port->irq, port); -} - -static void siu_set_termios(struct uart_port *port, struct ktermios *new, - struct ktermios *old) -{ - tcflag_t c_cflag, c_iflag; - uint8_t lcr, fcr, ier; - unsigned int baud, quot; - unsigned long flags; - - c_cflag = new->c_cflag; - switch (c_cflag & CSIZE) { - case CS5: - lcr = UART_LCR_WLEN5; - break; - case CS6: - lcr = UART_LCR_WLEN6; - break; - case CS7: - lcr = UART_LCR_WLEN7; - break; - default: - lcr = UART_LCR_WLEN8; - break; - } - - if (c_cflag & CSTOPB) - lcr |= UART_LCR_STOP; - if (c_cflag & PARENB) - lcr |= UART_LCR_PARITY; - if ((c_cflag & PARODD) != PARODD) - lcr |= UART_LCR_EPAR; - if (c_cflag & CMSPAR) - lcr |= UART_LCR_SPAR; - - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; - - spin_lock_irqsave(&port->lock, flags); - - uart_update_timeout(port, c_cflag, baud); - - c_iflag = new->c_iflag; - - port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; - if (c_iflag & INPCK) - port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART_LSR_BI; - - port->ignore_status_mask = 0; - if (c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_LSR_BI; - if (c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_OE; - } - - if ((c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_LSR_DR; - - ier = siu_read(port, UART_IER); - ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(port, c_cflag)) - ier |= UART_IER_MSI; - siu_write(port, UART_IER, ier); - - siu_write(port, UART_LCR, lcr | UART_LCR_DLAB); - - siu_write(port, UART_DLL, (uint8_t)quot); - siu_write(port, UART_DLM, (uint8_t)(quot >> 8)); - - siu_write(port, UART_LCR, lcr); - - siu_write(port, UART_FCR, fcr); - - siu_set_mctrl(port, port->mctrl); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) -{ - switch (state) { - case 0: - switch (port->type) { - case PORT_VR41XX_SIU: - vr41xx_supply_clock(SIU_CLOCK); - break; - case PORT_VR41XX_DSIU: - vr41xx_supply_clock(DSIU_CLOCK); - break; - } - break; - case 3: - switch (port->type) { - case PORT_VR41XX_SIU: - vr41xx_mask_clock(SIU_CLOCK); - break; - case PORT_VR41XX_DSIU: - vr41xx_mask_clock(DSIU_CLOCK); - break; - } - break; - } -} - -static const char *siu_type(struct uart_port *port) -{ - return siu_type_name(port); -} - -static void siu_release_port(struct uart_port *port) -{ - unsigned long size; - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - size = siu_port_size(port); - release_mem_region(port->mapbase, size); -} - -static int siu_request_port(struct uart_port *port) -{ - unsigned long size; - struct resource *res; - - size = siu_port_size(port); - res = request_mem_region(port->mapbase, size, siu_type_name(port)); - if (res == NULL) - return -EBUSY; - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_resource(res); - return -ENOMEM; - } - } - - return 0; -} - -static void siu_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = siu_check_type(port); - (void)siu_request_port(port); - } -} - -static int siu_verify_port(struct uart_port *port, struct serial_struct *serial) -{ - if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU) - return -EINVAL; - if (port->irq != serial->irq) - return -EINVAL; - if (port->iotype != serial->io_type) - return -EINVAL; - if (port->mapbase != (unsigned long)serial->iomem_base) - return -EINVAL; - - return 0; -} - -static struct uart_ops siu_uart_ops = { - .tx_empty = siu_tx_empty, - .set_mctrl = siu_set_mctrl, - .get_mctrl = siu_get_mctrl, - .stop_tx = siu_stop_tx, - .start_tx = siu_start_tx, - .stop_rx = siu_stop_rx, - .enable_ms = siu_enable_ms, - .break_ctl = siu_break_ctl, - .startup = siu_startup, - .shutdown = siu_shutdown, - .set_termios = siu_set_termios, - .pm = siu_pm, - .type = siu_type, - .release_port = siu_release_port, - .request_port = siu_request_port, - .config_port = siu_config_port, - .verify_port = siu_verify_port, -}; - -static int siu_init_ports(struct platform_device *pdev) -{ - struct uart_port *port; - struct resource *res; - int *type = pdev->dev.platform_data; - int i; - - if (!type) - return 0; - - port = siu_uart_ports; - for (i = 0; i < SIU_PORTS_MAX; i++) { - port->type = type[i]; - if (port->type == PORT_UNKNOWN) - continue; - port->irq = platform_get_irq(pdev, i); - port->uartclk = SIU_BAUD_BASE * 16; - port->fifosize = 16; - port->regshift = 0; - port->iotype = UPIO_MEM; - port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - port->line = i; - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - port->mapbase = res->start; - port++; - } - - return i; -} - -#ifdef CONFIG_SERIAL_VR41XX_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static void wait_for_xmitr(struct uart_port *port) -{ - int timeout = 10000; - uint8_t lsr, msr; - - do { - lsr = siu_read(port, UART_LSR); - if (lsr & UART_LSR_BI) - lsr_break_flag[port->line] = UART_LSR_BI; - - if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) - break; - } while (timeout-- > 0); - - if (port->flags & UPF_CONS_FLOW) { - timeout = 1000000; - - do { - msr = siu_read(port, UART_MSR); - if ((msr & UART_MSR_CTS) != 0) - break; - } while (timeout-- > 0); - } -} - -static void siu_console_putchar(struct uart_port *port, int ch) -{ - wait_for_xmitr(port); - siu_write(port, UART_TX, ch); -} - -static void siu_console_write(struct console *con, const char *s, unsigned count) -{ - struct uart_port *port; - uint8_t ier; - - port = &siu_uart_ports[con->index]; - - ier = siu_read(port, UART_IER); - siu_write(port, UART_IER, 0); - - uart_console_write(port, s, count, siu_console_putchar); - - wait_for_xmitr(port); - siu_write(port, UART_IER, ier); -} - -static int __init siu_console_setup(struct console *con, char *options) -{ - struct uart_port *port; - int baud = 9600; - int parity = 'n'; - int bits = 8; - int flow = 'n'; - - if (con->index >= SIU_PORTS_MAX) - con->index = 0; - - port = &siu_uart_ports[con->index]; - if (port->membase == NULL) { - if (port->mapbase == 0) - return -ENODEV; - port->membase = ioremap(port->mapbase, siu_port_size(port)); - } - - if (port->type == PORT_VR41XX_SIU) - vr41xx_select_siu_interface(SIU_INTERFACE_RS232C); - - if (options != NULL) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, con, baud, parity, bits, flow); -} - -static struct uart_driver siu_uart_driver; - -static struct console siu_console = { - .name = "ttyVR", - .write = siu_console_write, - .device = uart_console_device, - .setup = siu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &siu_uart_driver, -}; - -static int __devinit siu_console_init(void) -{ - struct uart_port *port; - int i; - - for (i = 0; i < SIU_PORTS_MAX; i++) { - port = &siu_uart_ports[i]; - port->ops = &siu_uart_ops; - } - - register_console(&siu_console); - - return 0; -} - -console_initcall(siu_console_init); - -void __init vr41xx_siu_early_setup(struct uart_port *port) -{ - if (port->type == PORT_UNKNOWN) - return; - - siu_uart_ports[port->line].line = port->line; - siu_uart_ports[port->line].type = port->type; - siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; - siu_uart_ports[port->line].mapbase = port->mapbase; - siu_uart_ports[port->line].mapbase = port->mapbase; - siu_uart_ports[port->line].ops = &siu_uart_ops; -} - -#define SERIAL_VR41XX_CONSOLE &siu_console -#else -#define SERIAL_VR41XX_CONSOLE NULL -#endif - -static struct uart_driver siu_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "SIU", - .dev_name = "ttyVR", - .major = SIU_MAJOR, - .minor = SIU_MINOR_BASE, - .cons = SERIAL_VR41XX_CONSOLE, -}; - -static int __devinit siu_probe(struct platform_device *dev) -{ - struct uart_port *port; - int num, i, retval; - - num = siu_init_ports(dev); - if (num <= 0) - return -ENODEV; - - siu_uart_driver.nr = num; - retval = uart_register_driver(&siu_uart_driver); - if (retval) - return retval; - - for (i = 0; i < num; i++) { - port = &siu_uart_ports[i]; - port->ops = &siu_uart_ops; - port->dev = &dev->dev; - - retval = uart_add_one_port(&siu_uart_driver, port); - if (retval < 0) { - port->dev = NULL; - break; - } - } - - if (i == 0 && retval < 0) { - uart_unregister_driver(&siu_uart_driver); - return retval; - } - - return 0; -} - -static int __devexit siu_remove(struct platform_device *dev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if (port->dev == &dev->dev) { - uart_remove_one_port(&siu_uart_driver, port); - port->dev = NULL; - } - } - - uart_unregister_driver(&siu_uart_driver); - - return 0; -} - -static int siu_suspend(struct platform_device *dev, pm_message_t state) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if ((port->type == PORT_VR41XX_SIU || - port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) - uart_suspend_port(&siu_uart_driver, port); - - } - - return 0; -} - -static int siu_resume(struct platform_device *dev) -{ - struct uart_port *port; - int i; - - for (i = 0; i < siu_uart_driver.nr; i++) { - port = &siu_uart_ports[i]; - if ((port->type == PORT_VR41XX_SIU || - port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) - uart_resume_port(&siu_uart_driver, port); - } - - return 0; -} - -static struct platform_driver siu_device_driver = { - .probe = siu_probe, - .remove = __devexit_p(siu_remove), - .suspend = siu_suspend, - .resume = siu_resume, - .driver = { - .name = "SIU", - .owner = THIS_MODULE, - }, -}; - -static int __init vr41xx_siu_init(void) -{ - return platform_driver_register(&siu_device_driver); -} - -static void __exit vr41xx_siu_exit(void) -{ - platform_driver_unregister(&siu_device_driver); -} - -module_init(vr41xx_siu_init); -module_exit(vr41xx_siu_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:SIU"); diff --git a/drivers/serial/vt8500_serial.c b/drivers/serial/vt8500_serial.c deleted file mode 100644 index 322bf56c0d89..000000000000 --- a/drivers/serial/vt8500_serial.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * drivers/serial/vt8500_serial.c - * - * Copyright (C) 2010 Alexey Charkov - * - * Based on msm_serial.c, which is: - * Copyright (C) 2007 Google, Inc. - * Author: Robert Love - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -# define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * UART Register offsets - */ - -#define VT8500_URTDR 0x0000 /* Transmit data */ -#define VT8500_URRDR 0x0004 /* Receive data */ -#define VT8500_URDIV 0x0008 /* Clock/Baud rate divisor */ -#define VT8500_URLCR 0x000C /* Line control */ -#define VT8500_URICR 0x0010 /* IrDA control */ -#define VT8500_URIER 0x0014 /* Interrupt enable */ -#define VT8500_URISR 0x0018 /* Interrupt status */ -#define VT8500_URUSR 0x001c /* UART status */ -#define VT8500_URFCR 0x0020 /* FIFO control */ -#define VT8500_URFIDX 0x0024 /* FIFO index */ -#define VT8500_URBKR 0x0028 /* Break signal count */ -#define VT8500_URTOD 0x002c /* Time out divisor */ -#define VT8500_TXFIFO 0x1000 /* Transmit FIFO (16x8) */ -#define VT8500_RXFIFO 0x1020 /* Receive FIFO (16x10) */ - -/* - * Interrupt enable and status bits - */ - -#define TXDE (1 << 0) /* Tx Data empty */ -#define RXDF (1 << 1) /* Rx Data full */ -#define TXFAE (1 << 2) /* Tx FIFO almost empty */ -#define TXFE (1 << 3) /* Tx FIFO empty */ -#define RXFAF (1 << 4) /* Rx FIFO almost full */ -#define RXFF (1 << 5) /* Rx FIFO full */ -#define TXUDR (1 << 6) /* Tx underrun */ -#define RXOVER (1 << 7) /* Rx overrun */ -#define PER (1 << 8) /* Parity error */ -#define FER (1 << 9) /* Frame error */ -#define TCTS (1 << 10) /* Toggle of CTS */ -#define RXTOUT (1 << 11) /* Rx timeout */ -#define BKDONE (1 << 12) /* Break signal done */ -#define ERR (1 << 13) /* AHB error response */ - -#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) -#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) - -struct vt8500_port { - struct uart_port uart; - char name[16]; - struct clk *clk; - unsigned int ier; -}; - -static inline void vt8500_write(struct uart_port *port, unsigned int val, - unsigned int off) -{ - writel(val, port->membase + off); -} - -static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off) -{ - return readl(port->membase + off); -} - -static void vt8500_stop_tx(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = container_of(port, - struct vt8500_port, - uart); - - vt8500_port->ier &= ~TX_FIFO_INTS; - vt8500_write(port, vt8500_port->ier, VT8500_URIER); -} - -static void vt8500_stop_rx(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = container_of(port, - struct vt8500_port, - uart); - - vt8500_port->ier &= ~RX_FIFO_INTS; - vt8500_write(port, vt8500_port->ier, VT8500_URIER); -} - -static void vt8500_enable_ms(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = container_of(port, - struct vt8500_port, - uart); - - vt8500_port->ier |= TCTS; - vt8500_write(port, vt8500_port->ier, VT8500_URIER); -} - -static void handle_rx(struct uart_port *port) -{ - struct tty_struct *tty = tty_port_tty_get(&port->state->port); - if (!tty) { - /* Discard data: no tty available */ - int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8; - u16 ch; - while (count--) - ch = readw(port->membase + VT8500_RXFIFO); - return; - } - - /* - * Handle overrun - */ - if ((vt8500_read(port, VT8500_URISR) & RXOVER)) { - port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - /* and now the main RX loop */ - while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) { - unsigned int c; - char flag = TTY_NORMAL; - - c = readw(port->membase + VT8500_RXFIFO) & 0x3ff; - - /* Mask conditions we're ignorning. */ - c &= ~port->read_status_mask; - - if (c & FER) { - port->icount.frame++; - flag = TTY_FRAME; - } else if (c & PER) { - port->icount.parity++; - flag = TTY_PARITY; - } - port->icount.rx++; - - if (!uart_handle_sysrq_char(port, c)) - tty_insert_flip_char(tty, c, flag); - } - - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static void handle_tx(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - if (port->x_char) { - writeb(port->x_char, port->membase + VT8500_TXFIFO); - port->icount.tx++; - port->x_char = 0; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - vt8500_stop_tx(port); - return; - } - - while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) { - if (uart_circ_empty(xmit)) - break; - - writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - vt8500_stop_tx(port); -} - -static void vt8500_start_tx(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = container_of(port, - struct vt8500_port, - uart); - - vt8500_port->ier &= ~TX_FIFO_INTS; - vt8500_write(port, vt8500_port->ier, VT8500_URIER); - handle_tx(port); - vt8500_port->ier |= TX_FIFO_INTS; - vt8500_write(port, vt8500_port->ier, VT8500_URIER); -} - -static void handle_delta_cts(struct uart_port *port) -{ - port->icount.cts++; - wake_up_interruptible(&port->state->port.delta_msr_wait); -} - -static irqreturn_t vt8500_irq(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned long isr; - - spin_lock(&port->lock); - isr = vt8500_read(port, VT8500_URISR); - - /* Acknowledge active status bits */ - vt8500_write(port, isr, VT8500_URISR); - - if (isr & RX_FIFO_INTS) - handle_rx(port); - if (isr & TX_FIFO_INTS) - handle_tx(port); - if (isr & TCTS) - handle_delta_cts(port); - - spin_unlock(&port->lock); - - return IRQ_HANDLED; -} - -static unsigned int vt8500_tx_empty(struct uart_port *port) -{ - return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ? - TIOCSER_TEMT : 0; -} - -static unsigned int vt8500_get_mctrl(struct uart_port *port) -{ - unsigned int usr; - - usr = vt8500_read(port, VT8500_URUSR); - if (usr & (1 << 4)) - return TIOCM_CTS; - else - return 0; -} - -static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -static void vt8500_break_ctl(struct uart_port *port, int break_ctl) -{ - if (break_ctl) - vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9), - VT8500_URLCR); -} - -static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud) -{ - unsigned long div; - unsigned int loops = 1000; - - div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff); - - if (unlikely((baud < 900) || (baud > 921600))) - div |= 7; - else - div |= (921600 / baud) - 1; - - while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops) - cpu_relax(); - vt8500_write(port, div, VT8500_URDIV); - - return baud; -} - -static int vt8500_startup(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = - container_of(port, struct vt8500_port, uart); - int ret; - - snprintf(vt8500_port->name, sizeof(vt8500_port->name), - "vt8500_serial%d", port->line); - - ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH, - vt8500_port->name, port); - if (unlikely(ret)) - return ret; - - vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */ - - return 0; -} - -static void vt8500_shutdown(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = - container_of(port, struct vt8500_port, uart); - - vt8500_port->ier = 0; - - /* disable interrupts and FIFOs */ - vt8500_write(&vt8500_port->uart, 0, VT8500_URIER); - vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR); - free_irq(port->irq, port); -} - -static void vt8500_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - struct vt8500_port *vt8500_port = - container_of(port, struct vt8500_port, uart); - unsigned long flags; - unsigned int baud, lcr; - unsigned int loops = 1000; - - spin_lock_irqsave(&port->lock, flags); - - /* calculate and set baud rate */ - baud = uart_get_baud_rate(port, termios, old, 900, 921600); - baud = vt8500_set_baud_rate(port, baud); - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); - - /* calculate parity */ - lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); - lcr &= ~((1 << 5) | (1 << 4)); - if (termios->c_cflag & PARENB) { - lcr |= (1 << 4); - termios->c_cflag &= ~CMSPAR; - if (termios->c_cflag & PARODD) - lcr |= (1 << 5); - } - - /* calculate bits per char */ - lcr &= ~(1 << 2); - switch (termios->c_cflag & CSIZE) { - case CS7: - break; - case CS8: - default: - lcr |= (1 << 2); - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= CS8; - break; - } - - /* calculate stop bits */ - lcr &= ~(1 << 3); - if (termios->c_cflag & CSTOPB) - lcr |= (1 << 3); - - /* set parity, bits per char, and stop bit */ - vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); - - /* Configure status bits to ignore based on termio flags. */ - port->read_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->read_status_mask = FER | PER; - - uart_update_timeout(port, termios->c_cflag, baud); - - /* Reset FIFOs */ - vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR); - while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc) - && --loops) - cpu_relax(); - - /* Every possible FIFO-related interrupt */ - vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS; - - /* - * CTS flow control - */ - if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag)) - vt8500_port->ier |= TCTS; - - vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR); - vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *vt8500_type(struct uart_port *port) -{ - struct vt8500_port *vt8500_port = - container_of(port, struct vt8500_port, uart); - return vt8500_port->name; -} - -static void vt8500_release_port(struct uart_port *port) -{ -} - -static int vt8500_request_port(struct uart_port *port) -{ - return 0; -} - -static void vt8500_config_port(struct uart_port *port, int flags) -{ - port->type = PORT_VT8500; -} - -static int vt8500_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500)) - return -EINVAL; - if (unlikely(port->irq != ser->irq)) - return -EINVAL; - return 0; -} - -static struct vt8500_port *vt8500_uart_ports[4]; -static struct uart_driver vt8500_uart_driver; - -#ifdef CONFIG_SERIAL_VT8500_CONSOLE - -static inline void wait_for_xmitr(struct uart_port *port) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - do { - status = vt8500_read(port, VT8500_URFIDX); - - if (--tmout == 0) - break; - udelay(1); - } while (status & 0x10); -} - -static void vt8500_console_putchar(struct uart_port *port, int c) -{ - wait_for_xmitr(port); - writeb(c, port->membase + VT8500_TXFIFO); -} - -static void vt8500_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index]; - unsigned long ier; - - BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr); - - ier = vt8500_read(&vt8500_port->uart, VT8500_URIER); - vt8500_write(&vt8500_port->uart, VT8500_URIER, 0); - - uart_console_write(&vt8500_port->uart, s, count, - vt8500_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and switch back to FIFO - */ - wait_for_xmitr(&vt8500_port->uart); - vt8500_write(&vt8500_port->uart, VT8500_URIER, ier); -} - -static int __init vt8500_console_setup(struct console *co, char *options) -{ - struct vt8500_port *vt8500_port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0)) - return -ENXIO; - - vt8500_port = vt8500_uart_ports[co->index]; - - if (!vt8500_port) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&vt8500_port->uart, - co, baud, parity, bits, flow); -} - -static struct console vt8500_console = { - .name = "ttyWMT", - .write = vt8500_console_write, - .device = uart_console_device, - .setup = vt8500_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &vt8500_uart_driver, -}; - -#define VT8500_CONSOLE (&vt8500_console) - -#else -#define VT8500_CONSOLE NULL -#endif - -static struct uart_ops vt8500_uart_pops = { - .tx_empty = vt8500_tx_empty, - .set_mctrl = vt8500_set_mctrl, - .get_mctrl = vt8500_get_mctrl, - .stop_tx = vt8500_stop_tx, - .start_tx = vt8500_start_tx, - .stop_rx = vt8500_stop_rx, - .enable_ms = vt8500_enable_ms, - .break_ctl = vt8500_break_ctl, - .startup = vt8500_startup, - .shutdown = vt8500_shutdown, - .set_termios = vt8500_set_termios, - .type = vt8500_type, - .release_port = vt8500_release_port, - .request_port = vt8500_request_port, - .config_port = vt8500_config_port, - .verify_port = vt8500_verify_port, -}; - -static struct uart_driver vt8500_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "vt8500_serial", - .dev_name = "ttyWMT", - .nr = 6, - .cons = VT8500_CONSOLE, -}; - -static int __init vt8500_serial_probe(struct platform_device *pdev) -{ - struct vt8500_port *vt8500_port; - struct resource *mmres, *irqres; - int ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) - return -ENODEV; - - vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL); - if (!vt8500_port) - return -ENOMEM; - - vt8500_port->uart.type = PORT_VT8500; - vt8500_port->uart.iotype = UPIO_MEM; - vt8500_port->uart.mapbase = mmres->start; - vt8500_port->uart.irq = irqres->start; - vt8500_port->uart.fifosize = 16; - vt8500_port->uart.ops = &vt8500_uart_pops; - vt8500_port->uart.line = pdev->id; - vt8500_port->uart.dev = &pdev->dev; - vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - vt8500_port->uart.uartclk = 24000000; - - snprintf(vt8500_port->name, sizeof(vt8500_port->name), - "VT8500 UART%d", pdev->id); - - vt8500_port->uart.membase = ioremap(mmres->start, - mmres->end - mmres->start + 1); - if (!vt8500_port->uart.membase) { - ret = -ENOMEM; - goto err; - } - - vt8500_uart_ports[pdev->id] = vt8500_port; - - uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart); - - platform_set_drvdata(pdev, vt8500_port); - - return 0; - -err: - kfree(vt8500_port); - return ret; -} - -static int __devexit vt8500_serial_remove(struct platform_device *pdev) -{ - struct vt8500_port *vt8500_port = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart); - kfree(vt8500_port); - - return 0; -} - -static struct platform_driver vt8500_platform_driver = { - .probe = vt8500_serial_probe, - .remove = vt8500_serial_remove, - .driver = { - .name = "vt8500_serial", - .owner = THIS_MODULE, - }, -}; - -static int __init vt8500_serial_init(void) -{ - int ret; - - ret = uart_register_driver(&vt8500_uart_driver); - if (unlikely(ret)) - return ret; - - ret = platform_driver_register(&vt8500_platform_driver); - - if (unlikely(ret)) - uart_unregister_driver(&vt8500_uart_driver); - - return ret; -} - -static void __exit vt8500_serial_exit(void) -{ -#ifdef CONFIG_SERIAL_VT8500_CONSOLE - unregister_console(&vt8500_console); -#endif - platform_driver_unregister(&vt8500_platform_driver); - uart_unregister_driver(&vt8500_uart_driver); -} - -module_init(vt8500_serial_init); -module_exit(vt8500_serial_exit); - -MODULE_AUTHOR("Alexey Charkov "); -MODULE_DESCRIPTION("Driver for vt8500 serial device"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c deleted file mode 100644 index 1a7fd3e70315..000000000000 --- a/drivers/serial/zs.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * zs.c: Serial port driver for IOASIC DECstations. - * - * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. - * Derived from drivers/macintosh/macserial.c by Harald Koerfgen. - * - * DECstation changes - * Copyright (C) 1998-2000 Harald Koerfgen - * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki - * - * For the rest of the code the original Copyright applies: - * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * - * Note: for IOASIC systems the wiring is as follows: - * - * mouse/keyboard: - * DIN-7 MJ-4 signal SCC - * 2 1 TxD <- A.TxD - * 3 4 RxD -> A.RxD - * - * EIA-232/EIA-423: - * DB-25 MMJ-6 signal SCC - * 2 2 TxD <- B.TxD - * 3 5 RxD -> B.RxD - * 4 RTS <- ~A.RTS - * 5 CTS -> ~B.CTS - * 6 6 DSR -> ~A.SYNC - * 8 CD -> ~B.DCD - * 12 DSRS(DCE) -> ~A.CTS (*) - * 15 TxC -> B.TxC - * 17 RxC -> B.RxC - * 20 1 DTR <- ~A.DTR - * 22 RI -> ~A.DCD - * 23 DSRS(DTE) <- ~B.RTS - * - * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE) - * is shared with DSRS(DTE) at pin 23. - * - * As you can immediately notice the wiring of the RTS, DTR and DSR signals - * is a bit odd. This makes the handling of port B unnecessarily - * complicated and prevents the use of some automatic modes of operation. - */ - -#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "zs.h" - - -MODULE_AUTHOR("Maciej W. Rozycki "); -MODULE_DESCRIPTION("DECstation Z85C30 serial driver"); -MODULE_LICENSE("GPL"); - - -static char zs_name[] __initdata = "DECstation Z85C30 serial driver version "; -static char zs_version[] __initdata = "0.10"; - -/* - * It would be nice to dynamically allocate everything that - * depends on ZS_NUM_SCCS, so we could support any number of - * Z85C30s, but for now... - */ -#define ZS_NUM_SCCS 2 /* Max # of ZS chips supported. */ -#define ZS_NUM_CHAN 2 /* 2 channels per chip. */ -#define ZS_CHAN_A 0 /* Index of the channel A. */ -#define ZS_CHAN_B 1 /* Index of the channel B. */ -#define ZS_CHAN_IO_SIZE 8 /* IOMEM space size. */ -#define ZS_CHAN_IO_STRIDE 4 /* Register alignment. */ -#define ZS_CHAN_IO_OFFSET 1 /* The SCC resides on the high byte - of the 16-bit IOBUS. */ -#define ZS_CLOCK 7372800 /* Z85C30 PCLK input clock rate. */ - -#define to_zport(uport) container_of(uport, struct zs_port, port) - -struct zs_parms { - resource_size_t scc[ZS_NUM_SCCS]; - int irq[ZS_NUM_SCCS]; -}; - -static struct zs_scc zs_sccs[ZS_NUM_SCCS]; - -static u8 zs_init_regs[ZS_NUM_REGS] __initdata = { - 0, /* write 0 */ - PAR_SPEC, /* write 1 */ - 0, /* write 2 */ - 0, /* write 3 */ - X16CLK | SB1, /* write 4 */ - 0, /* write 5 */ - 0, 0, 0, /* write 6, 7, 8 */ - MIE | DLC | NV, /* write 9 */ - NRZ, /* write 10 */ - TCBR | RCBR, /* write 11 */ - 0, 0, /* BRG time constant, write 12 + 13 */ - BRSRC | BRENABL, /* write 14 */ - 0, /* write 15 */ -}; - -/* - * Debugging. - */ -#undef ZS_DEBUG_REGS - - -/* - * Reading and writing Z85C30 registers. - */ -static void recovery_delay(void) -{ - udelay(2); -} - -static u8 read_zsreg(struct zs_port *zport, int reg) -{ - void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET; - u8 retval; - - if (reg != 0) { - writeb(reg & 0xf, control); - fast_iob(); - recovery_delay(); - } - retval = readb(control); - recovery_delay(); - return retval; -} - -static void write_zsreg(struct zs_port *zport, int reg, u8 value) -{ - void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET; - - if (reg != 0) { - writeb(reg & 0xf, control); - fast_iob(); recovery_delay(); - } - writeb(value, control); - fast_iob(); - recovery_delay(); - return; -} - -static u8 read_zsdata(struct zs_port *zport) -{ - void __iomem *data = zport->port.membase + - ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET; - u8 retval; - - retval = readb(data); - recovery_delay(); - return retval; -} - -static void write_zsdata(struct zs_port *zport, u8 value) -{ - void __iomem *data = zport->port.membase + - ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET; - - writeb(value, data); - fast_iob(); - recovery_delay(); - return; -} - -#ifdef ZS_DEBUG_REGS -void zs_dump(void) -{ - struct zs_port *zport; - int i, j; - - for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { - zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN]; - - if (!zport->scc) - continue; - - for (j = 0; j < 16; j++) - printk("W%-2d = 0x%02x\t", j, zport->regs[j]); - printk("\n"); - for (j = 0; j < 16; j++) - printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j)); - printk("\n\n"); - } -} -#endif - - -static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq) -{ - if (irq) - spin_lock_irq(lock); - else - spin_lock(lock); -} - -static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq) -{ - if (irq) - spin_unlock_irq(lock); - else - spin_unlock(lock); -} - -static int zs_receive_drain(struct zs_port *zport) -{ - int loops = 10000; - - while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops) - read_zsdata(zport); - return loops; -} - -static int zs_transmit_drain(struct zs_port *zport, int irq) -{ - struct zs_scc *scc = zport->scc; - int loops = 10000; - - while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) { - zs_spin_unlock_cond_irq(&scc->zlock, irq); - udelay(2); - zs_spin_lock_cond_irq(&scc->zlock, irq); - } - return loops; -} - -static int zs_line_drain(struct zs_port *zport, int irq) -{ - struct zs_scc *scc = zport->scc; - int loops = 10000; - - while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) { - zs_spin_unlock_cond_irq(&scc->zlock, irq); - udelay(2); - zs_spin_lock_cond_irq(&scc->zlock, irq); - } - return loops; -} - - -static void load_zsregs(struct zs_port *zport, u8 *regs, int irq) -{ - /* Let the current transmission finish. */ - zs_line_drain(zport, irq); - /* Load 'em up. */ - write_zsreg(zport, R3, regs[3] & ~RxENABLE); - write_zsreg(zport, R5, regs[5] & ~TxENAB); - write_zsreg(zport, R4, regs[4]); - write_zsreg(zport, R9, regs[9]); - write_zsreg(zport, R1, regs[1]); - write_zsreg(zport, R2, regs[2]); - write_zsreg(zport, R10, regs[10]); - write_zsreg(zport, R14, regs[14] & ~BRENABL); - write_zsreg(zport, R11, regs[11]); - write_zsreg(zport, R12, regs[12]); - write_zsreg(zport, R13, regs[13]); - write_zsreg(zport, R14, regs[14]); - write_zsreg(zport, R15, regs[15]); - if (regs[3] & RxENABLE) - write_zsreg(zport, R3, regs[3]); - if (regs[5] & TxENAB) - write_zsreg(zport, R5, regs[5]); - return; -} - - -/* - * Status handling routines. - */ - -/* - * zs_tx_empty() -- get the transmitter empty status - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static unsigned int zs_tx_empty(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - unsigned long flags; - u8 status; - - spin_lock_irqsave(&scc->zlock, flags); - status = read_zsreg(zport, R1); - spin_unlock_irqrestore(&scc->zlock, flags); - - return status & ALL_SNT ? TIOCSER_TEMT : 0; -} - -static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a, - struct zs_port *zport_b) -{ - u8 status_a, status_b; - unsigned int mctrl; - - status_a = read_zsreg(zport_a, R0); - status_b = read_zsreg(zport_b, R0); - - mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) | - ((status_b & DCD) ? TIOCM_CAR : 0) | - ((status_a & DCD) ? TIOCM_RNG : 0) | - ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0); - - return mctrl; -} - -static unsigned int zs_raw_get_mctrl(struct zs_port *zport) -{ - struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; - - return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0; -} - -static unsigned int zs_raw_xor_mctrl(struct zs_port *zport) -{ - struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; - unsigned int mmask, mctrl, delta; - u8 mask_a, mask_b; - - if (zport == zport_a) - return 0; - - mask_a = zport_a->regs[15]; - mask_b = zport->regs[15]; - - mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) | - ((mask_b & DCDIE) ? TIOCM_CAR : 0) | - ((mask_a & DCDIE) ? TIOCM_RNG : 0) | - ((mask_a & SYNCIE) ? TIOCM_DSR : 0); - - mctrl = zport->mctrl; - if (mmask) { - mctrl &= ~mmask; - mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask; - } - - delta = mctrl ^ zport->mctrl; - if (delta) - zport->mctrl = mctrl; - - return delta; -} - -static unsigned int zs_get_mctrl(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - unsigned int mctrl; - - spin_lock(&scc->zlock); - mctrl = zs_raw_get_mctrl(zport); - spin_unlock(&scc->zlock); - - return mctrl; -} - -static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; - u8 oldloop, newloop; - - spin_lock(&scc->zlock); - if (zport != zport_a) { - if (mctrl & TIOCM_DTR) - zport_a->regs[5] |= DTR; - else - zport_a->regs[5] &= ~DTR; - if (mctrl & TIOCM_RTS) - zport_a->regs[5] |= RTS; - else - zport_a->regs[5] &= ~RTS; - write_zsreg(zport_a, R5, zport_a->regs[5]); - } - - /* Rarely modified, so don't poke at hardware unless necessary. */ - oldloop = zport->regs[14]; - newloop = oldloop; - if (mctrl & TIOCM_LOOP) - newloop |= LOOPBAK; - else - newloop &= ~LOOPBAK; - if (newloop != oldloop) { - zport->regs[14] = newloop; - write_zsreg(zport, R14, zport->regs[14]); - } - spin_unlock(&scc->zlock); -} - -static void zs_raw_stop_tx(struct zs_port *zport) -{ - write_zsreg(zport, R0, RES_Tx_P); - zport->tx_stopped = 1; -} - -static void zs_stop_tx(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - - spin_lock(&scc->zlock); - zs_raw_stop_tx(zport); - spin_unlock(&scc->zlock); -} - -static void zs_raw_transmit_chars(struct zs_port *); - -static void zs_start_tx(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - - spin_lock(&scc->zlock); - if (zport->tx_stopped) { - zs_transmit_drain(zport, 0); - zport->tx_stopped = 0; - zs_raw_transmit_chars(zport); - } - spin_unlock(&scc->zlock); -} - -static void zs_stop_rx(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; - - spin_lock(&scc->zlock); - zport->regs[15] &= ~BRKIE; - zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB); - zport->regs[1] |= RxINT_DISAB; - - if (zport != zport_a) { - /* A-side DCD tracks RI and SYNC tracks DSR. */ - zport_a->regs[15] &= ~(DCDIE | SYNCIE); - write_zsreg(zport_a, R15, zport_a->regs[15]); - if (!(zport_a->regs[15] & BRKIE)) { - zport_a->regs[1] &= ~EXT_INT_ENAB; - write_zsreg(zport_a, R1, zport_a->regs[1]); - } - - /* This-side DCD tracks DCD and CTS tracks CTS. */ - zport->regs[15] &= ~(DCDIE | CTSIE); - zport->regs[1] &= ~EXT_INT_ENAB; - } else { - /* DCD tracks RI and SYNC tracks DSR for the B side. */ - if (!(zport->regs[15] & (DCDIE | SYNCIE))) - zport->regs[1] &= ~EXT_INT_ENAB; - } - - write_zsreg(zport, R15, zport->regs[15]); - write_zsreg(zport, R1, zport->regs[1]); - spin_unlock(&scc->zlock); -} - -static void zs_enable_ms(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; - - if (zport == zport_a) - return; - - spin_lock(&scc->zlock); - - /* Clear Ext interrupts if not being handled already. */ - if (!(zport_a->regs[1] & EXT_INT_ENAB)) - write_zsreg(zport_a, R0, RES_EXT_INT); - - /* A-side DCD tracks RI and SYNC tracks DSR. */ - zport_a->regs[1] |= EXT_INT_ENAB; - zport_a->regs[15] |= DCDIE | SYNCIE; - - /* This-side DCD tracks DCD and CTS tracks CTS. */ - zport->regs[15] |= DCDIE | CTSIE; - - zs_raw_xor_mctrl(zport); - - write_zsreg(zport_a, R1, zport_a->regs[1]); - write_zsreg(zport_a, R15, zport_a->regs[15]); - write_zsreg(zport, R15, zport->regs[15]); - spin_unlock(&scc->zlock); -} - -static void zs_break_ctl(struct uart_port *uport, int break_state) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - unsigned long flags; - - spin_lock_irqsave(&scc->zlock, flags); - if (break_state == -1) - zport->regs[5] |= SND_BRK; - else - zport->regs[5] &= ~SND_BRK; - write_zsreg(zport, R5, zport->regs[5]); - spin_unlock_irqrestore(&scc->zlock, flags); -} - - -/* - * Interrupt handling routines. - */ -#define Rx_BRK 0x0100 /* BREAK event software flag. */ -#define Rx_SYS 0x0200 /* SysRq event software flag. */ - -static void zs_receive_chars(struct zs_port *zport) -{ - struct uart_port *uport = &zport->port; - struct zs_scc *scc = zport->scc; - struct uart_icount *icount; - unsigned int avail, status, ch, flag; - int count; - - for (count = 16; count; count--) { - spin_lock(&scc->zlock); - avail = read_zsreg(zport, R0) & Rx_CH_AV; - spin_unlock(&scc->zlock); - if (!avail) - break; - - spin_lock(&scc->zlock); - status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR); - ch = read_zsdata(zport); - spin_unlock(&scc->zlock); - - flag = TTY_NORMAL; - - icount = &uport->icount; - icount->rx++; - - /* Handle the null char got when BREAK is removed. */ - if (!ch) - status |= zport->tty_break; - if (unlikely(status & - (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) { - zport->tty_break = 0; - - /* Reset the error indication. */ - if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) { - spin_lock(&scc->zlock); - write_zsreg(zport, R0, ERR_RES); - spin_unlock(&scc->zlock); - } - - if (status & (Rx_SYS | Rx_BRK)) { - icount->brk++; - /* SysRq discards the null char. */ - if (status & Rx_SYS) - continue; - } else if (status & FRM_ERR) - icount->frame++; - else if (status & PAR_ERR) - icount->parity++; - if (status & Rx_OVR) - icount->overrun++; - - status &= uport->read_status_mask; - if (status & Rx_BRK) - flag = TTY_BREAK; - else if (status & FRM_ERR) - flag = TTY_FRAME; - else if (status & PAR_ERR) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(uport, ch)) - continue; - - uart_insert_char(uport, status, Rx_OVR, ch, flag); - } - - tty_flip_buffer_push(uport->state->port.tty); -} - -static void zs_raw_transmit_chars(struct zs_port *zport) -{ - struct circ_buf *xmit = &zport->port.state->xmit; - - /* XON/XOFF chars. */ - if (zport->port.x_char) { - write_zsdata(zport, zport->port.x_char); - zport->port.icount.tx++; - zport->port.x_char = 0; - return; - } - - /* If nothing to do or stopped or hardware stopped. */ - if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) { - zs_raw_stop_tx(zport); - return; - } - - /* Send char. */ - write_zsdata(zport, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - zport->port.icount.tx++; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&zport->port); - - /* Are we are done? */ - if (uart_circ_empty(xmit)) - zs_raw_stop_tx(zport); -} - -static void zs_transmit_chars(struct zs_port *zport) -{ - struct zs_scc *scc = zport->scc; - - spin_lock(&scc->zlock); - zs_raw_transmit_chars(zport); - spin_unlock(&scc->zlock); -} - -static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a) -{ - struct uart_port *uport = &zport->port; - struct zs_scc *scc = zport->scc; - unsigned int delta; - u8 status, brk; - - spin_lock(&scc->zlock); - - /* Get status from Read Register 0. */ - status = read_zsreg(zport, R0); - - if (zport->regs[15] & BRKIE) { - brk = status & BRK_ABRT; - if (brk && !zport->brk) { - spin_unlock(&scc->zlock); - if (uart_handle_break(uport)) - zport->tty_break = Rx_SYS; - else - zport->tty_break = Rx_BRK; - spin_lock(&scc->zlock); - } - zport->brk = brk; - } - - if (zport != zport_a) { - delta = zs_raw_xor_mctrl(zport); - spin_unlock(&scc->zlock); - - if (delta & TIOCM_CTS) - uart_handle_cts_change(uport, - zport->mctrl & TIOCM_CTS); - if (delta & TIOCM_CAR) - uart_handle_dcd_change(uport, - zport->mctrl & TIOCM_CAR); - if (delta & TIOCM_RNG) - uport->icount.dsr++; - if (delta & TIOCM_DSR) - uport->icount.rng++; - - if (delta) - wake_up_interruptible(&uport->state->port.delta_msr_wait); - - spin_lock(&scc->zlock); - } - - /* Clear the status condition... */ - write_zsreg(zport, R0, RES_EXT_INT); - - spin_unlock(&scc->zlock); -} - -/* - * This is the Z85C30 driver's generic interrupt routine. - */ -static irqreturn_t zs_interrupt(int irq, void *dev_id) -{ - struct zs_scc *scc = dev_id; - struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; - struct zs_port *zport_b = &scc->zport[ZS_CHAN_B]; - irqreturn_t status = IRQ_NONE; - u8 zs_intreg; - int count; - - /* - * NOTE: The read register 3, which holds the irq status, - * does so for both channels on each chip. Although - * the status value itself must be read from the A - * channel and is only valid when read from channel A. - * Yes... broken hardware... - */ - for (count = 16; count; count--) { - spin_lock(&scc->zlock); - zs_intreg = read_zsreg(zport_a, R3); - spin_unlock(&scc->zlock); - if (!zs_intreg) - break; - - /* - * We do not like losing characters, so we prioritise - * interrupt sources a little bit differently than - * the SCC would, was it allowed to. - */ - if (zs_intreg & CHBRxIP) - zs_receive_chars(zport_b); - if (zs_intreg & CHARxIP) - zs_receive_chars(zport_a); - if (zs_intreg & CHBEXT) - zs_status_handle(zport_b, zport_a); - if (zs_intreg & CHAEXT) - zs_status_handle(zport_a, zport_a); - if (zs_intreg & CHBTxIP) - zs_transmit_chars(zport_b); - if (zs_intreg & CHATxIP) - zs_transmit_chars(zport_a); - - status = IRQ_HANDLED; - } - - return status; -} - - -/* - * Finally, routines used to initialize the serial port. - */ -static int zs_startup(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - unsigned long flags; - int irq_guard; - int ret; - - irq_guard = atomic_add_return(1, &scc->irq_guard); - if (irq_guard == 1) { - ret = request_irq(zport->port.irq, zs_interrupt, - IRQF_SHARED, "scc", scc); - if (ret) { - atomic_add(-1, &scc->irq_guard); - printk(KERN_ERR "zs: can't get irq %d\n", - zport->port.irq); - return ret; - } - } - - spin_lock_irqsave(&scc->zlock, flags); - - /* Clear the receive FIFO. */ - zs_receive_drain(zport); - - /* Clear the interrupt registers. */ - write_zsreg(zport, R0, ERR_RES); - write_zsreg(zport, R0, RES_Tx_P); - /* But Ext only if not being handled already. */ - if (!(zport->regs[1] & EXT_INT_ENAB)) - write_zsreg(zport, R0, RES_EXT_INT); - - /* Finally, enable sequencing and interrupts. */ - zport->regs[1] &= ~RxINT_MASK; - zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB; - zport->regs[3] |= RxENABLE; - zport->regs[15] |= BRKIE; - write_zsreg(zport, R1, zport->regs[1]); - write_zsreg(zport, R3, zport->regs[3]); - write_zsreg(zport, R5, zport->regs[5]); - write_zsreg(zport, R15, zport->regs[15]); - - /* Record the current state of RR0. */ - zport->mctrl = zs_raw_get_mctrl(zport); - zport->brk = read_zsreg(zport, R0) & BRK_ABRT; - - zport->tx_stopped = 1; - - spin_unlock_irqrestore(&scc->zlock, flags); - - return 0; -} - -static void zs_shutdown(struct uart_port *uport) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - unsigned long flags; - int irq_guard; - - spin_lock_irqsave(&scc->zlock, flags); - - zport->regs[3] &= ~RxENABLE; - write_zsreg(zport, R5, zport->regs[5]); - write_zsreg(zport, R3, zport->regs[3]); - - spin_unlock_irqrestore(&scc->zlock, flags); - - irq_guard = atomic_add_return(-1, &scc->irq_guard); - if (!irq_guard) - free_irq(zport->port.irq, scc); -} - - -static void zs_reset(struct zs_port *zport) -{ - struct zs_scc *scc = zport->scc; - int irq; - unsigned long flags; - - spin_lock_irqsave(&scc->zlock, flags); - irq = !irqs_disabled_flags(flags); - if (!scc->initialised) { - /* Reset the pointer first, just in case... */ - read_zsreg(zport, R0); - /* And let the current transmission finish. */ - zs_line_drain(zport, irq); - write_zsreg(zport, R9, FHWRES); - udelay(10); - write_zsreg(zport, R9, 0); - scc->initialised = 1; - } - load_zsregs(zport, zport->regs, irq); - spin_unlock_irqrestore(&scc->zlock, flags); -} - -static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, - struct ktermios *old_termios) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; - int irq; - unsigned int baud, brg; - unsigned long flags; - - spin_lock_irqsave(&scc->zlock, flags); - irq = !irqs_disabled_flags(flags); - - /* Byte size. */ - zport->regs[3] &= ~RxNBITS_MASK; - zport->regs[5] &= ~TxNBITS_MASK; - switch (termios->c_cflag & CSIZE) { - case CS5: - zport->regs[3] |= Rx5; - zport->regs[5] |= Tx5; - break; - case CS6: - zport->regs[3] |= Rx6; - zport->regs[5] |= Tx6; - break; - case CS7: - zport->regs[3] |= Rx7; - zport->regs[5] |= Tx7; - break; - case CS8: - default: - zport->regs[3] |= Rx8; - zport->regs[5] |= Tx8; - break; - } - - /* Parity and stop bits. */ - zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN); - if (termios->c_cflag & CSTOPB) - zport->regs[4] |= SB2; - else - zport->regs[4] |= SB1; - if (termios->c_cflag & PARENB) - zport->regs[4] |= PAR_ENA; - if (!(termios->c_cflag & PARODD)) - zport->regs[4] |= PAR_EVEN; - switch (zport->clk_mode) { - case 64: - zport->regs[4] |= X64CLK; - break; - case 32: - zport->regs[4] |= X32CLK; - break; - case 16: - zport->regs[4] |= X16CLK; - break; - case 1: - zport->regs[4] |= X1CLK; - break; - default: - BUG(); - } - - baud = uart_get_baud_rate(uport, termios, old_termios, 0, - uport->uartclk / zport->clk_mode / 4); - - brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode); - zport->regs[12] = brg & 0xff; - zport->regs[13] = (brg >> 8) & 0xff; - - uart_update_timeout(uport, termios->c_cflag, baud); - - uport->read_status_mask = Rx_OVR; - if (termios->c_iflag & INPCK) - uport->read_status_mask |= FRM_ERR | PAR_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) - uport->read_status_mask |= Rx_BRK; - - uport->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - uport->ignore_status_mask |= FRM_ERR | PAR_ERR; - if (termios->c_iflag & IGNBRK) { - uport->ignore_status_mask |= Rx_BRK; - if (termios->c_iflag & IGNPAR) - uport->ignore_status_mask |= Rx_OVR; - } - - if (termios->c_cflag & CREAD) - zport->regs[3] |= RxENABLE; - else - zport->regs[3] &= ~RxENABLE; - - if (zport != zport_a) { - if (!(termios->c_cflag & CLOCAL)) { - zport->regs[15] |= DCDIE; - } else - zport->regs[15] &= ~DCDIE; - if (termios->c_cflag & CRTSCTS) { - zport->regs[15] |= CTSIE; - } else - zport->regs[15] &= ~CTSIE; - zs_raw_xor_mctrl(zport); - } - - /* Load up the new values. */ - load_zsregs(zport, zport->regs, irq); - - spin_unlock_irqrestore(&scc->zlock, flags); -} - -/* - * Hack alert! - * Required solely so that the initial PROM-based console - * works undisturbed in parallel with this one. - */ -static void zs_pm(struct uart_port *uport, unsigned int state, - unsigned int oldstate) -{ - struct zs_port *zport = to_zport(uport); - - if (state < 3) - zport->regs[5] |= TxENAB; - else - zport->regs[5] &= ~TxENAB; - write_zsreg(zport, R5, zport->regs[5]); -} - - -static const char *zs_type(struct uart_port *uport) -{ - return "Z85C30 SCC"; -} - -static void zs_release_port(struct uart_port *uport) -{ - iounmap(uport->membase); - uport->membase = 0; - release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); -} - -static int zs_map_port(struct uart_port *uport) -{ - if (!uport->membase) - uport->membase = ioremap_nocache(uport->mapbase, - ZS_CHAN_IO_SIZE); - if (!uport->membase) { - printk(KERN_ERR "zs: Cannot map MMIO\n"); - return -ENOMEM; - } - return 0; -} - -static int zs_request_port(struct uart_port *uport) -{ - int ret; - - if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) { - printk(KERN_ERR "zs: Unable to reserve MMIO resource\n"); - return -EBUSY; - } - ret = zs_map_port(uport); - if (ret) { - release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); - return ret; - } - return 0; -} - -static void zs_config_port(struct uart_port *uport, int flags) -{ - struct zs_port *zport = to_zport(uport); - - if (flags & UART_CONFIG_TYPE) { - if (zs_request_port(uport)) - return; - - uport->type = PORT_ZS; - - zs_reset(zport); - } -} - -static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser) -{ - struct zs_port *zport = to_zport(uport); - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS) - ret = -EINVAL; - if (ser->irq != uport->irq) - ret = -EINVAL; - if (ser->baud_base != uport->uartclk / zport->clk_mode / 4) - ret = -EINVAL; - return ret; -} - - -static struct uart_ops zs_ops = { - .tx_empty = zs_tx_empty, - .set_mctrl = zs_set_mctrl, - .get_mctrl = zs_get_mctrl, - .stop_tx = zs_stop_tx, - .start_tx = zs_start_tx, - .stop_rx = zs_stop_rx, - .enable_ms = zs_enable_ms, - .break_ctl = zs_break_ctl, - .startup = zs_startup, - .shutdown = zs_shutdown, - .set_termios = zs_set_termios, - .pm = zs_pm, - .type = zs_type, - .release_port = zs_release_port, - .request_port = zs_request_port, - .config_port = zs_config_port, - .verify_port = zs_verify_port, -}; - -/* - * Initialize Z85C30 port structures. - */ -static int __init zs_probe_sccs(void) -{ - static int probed; - struct zs_parms zs_parms; - int chip, side, irq; - int n_chips = 0; - int i; - - if (probed) - return 0; - - irq = dec_interrupt[DEC_IRQ_SCC0]; - if (irq >= 0) { - zs_parms.scc[n_chips] = IOASIC_SCC0; - zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0]; - n_chips++; - } - irq = dec_interrupt[DEC_IRQ_SCC1]; - if (irq >= 0) { - zs_parms.scc[n_chips] = IOASIC_SCC1; - zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1]; - n_chips++; - } - if (!n_chips) - return -ENXIO; - - probed = 1; - - for (chip = 0; chip < n_chips; chip++) { - spin_lock_init(&zs_sccs[chip].zlock); - for (side = 0; side < ZS_NUM_CHAN; side++) { - struct zs_port *zport = &zs_sccs[chip].zport[side]; - struct uart_port *uport = &zport->port; - - zport->scc = &zs_sccs[chip]; - zport->clk_mode = 16; - - uport->irq = zs_parms.irq[chip]; - uport->uartclk = ZS_CLOCK; - uport->fifosize = 1; - uport->iotype = UPIO_MEM; - uport->flags = UPF_BOOT_AUTOCONF; - uport->ops = &zs_ops; - uport->line = chip * ZS_NUM_CHAN + side; - uport->mapbase = dec_kn_slot_base + - zs_parms.scc[chip] + - (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE; - - for (i = 0; i < ZS_NUM_REGS; i++) - zport->regs[i] = zs_init_regs[i]; - } - } - - return 0; -} - - -#ifdef CONFIG_SERIAL_ZS_CONSOLE -static void zs_console_putchar(struct uart_port *uport, int ch) -{ - struct zs_port *zport = to_zport(uport); - struct zs_scc *scc = zport->scc; - int irq; - unsigned long flags; - - spin_lock_irqsave(&scc->zlock, flags); - irq = !irqs_disabled_flags(flags); - if (zs_transmit_drain(zport, irq)) - write_zsdata(zport, ch); - spin_unlock_irqrestore(&scc->zlock, flags); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void zs_console_write(struct console *co, const char *s, - unsigned int count) -{ - int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; - struct zs_port *zport = &zs_sccs[chip].zport[side]; - struct zs_scc *scc = zport->scc; - unsigned long flags; - u8 txint, txenb; - int irq; - - /* Disable transmit interrupts and enable the transmitter. */ - spin_lock_irqsave(&scc->zlock, flags); - txint = zport->regs[1]; - txenb = zport->regs[5]; - if (txint & TxINT_ENAB) { - zport->regs[1] = txint & ~TxINT_ENAB; - write_zsreg(zport, R1, zport->regs[1]); - } - if (!(txenb & TxENAB)) { - zport->regs[5] = txenb | TxENAB; - write_zsreg(zport, R5, zport->regs[5]); - } - spin_unlock_irqrestore(&scc->zlock, flags); - - uart_console_write(&zport->port, s, count, zs_console_putchar); - - /* Restore transmit interrupts and the transmitter enable. */ - spin_lock_irqsave(&scc->zlock, flags); - irq = !irqs_disabled_flags(flags); - zs_line_drain(zport, irq); - if (!(txenb & TxENAB)) { - zport->regs[5] &= ~TxENAB; - write_zsreg(zport, R5, zport->regs[5]); - } - if (txint & TxINT_ENAB) { - zport->regs[1] |= TxINT_ENAB; - write_zsreg(zport, R1, zport->regs[1]); - } - spin_unlock_irqrestore(&scc->zlock, flags); -} - -/* - * Setup serial console baud/bits/parity. We do two things here: - * - construct a cflag setting for the first uart_open() - * - initialise the serial port - * Return non-zero if we didn't find a serial port. - */ -static int __init zs_console_setup(struct console *co, char *options) -{ - int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; - struct zs_port *zport = &zs_sccs[chip].zport[side]; - struct uart_port *uport = &zport->port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - ret = zs_map_port(uport); - if (ret) - return ret; - - zs_reset(zport); - zs_pm(uport, 0, -1); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(uport, co, baud, parity, bits, flow); -} - -static struct uart_driver zs_reg; -static struct console zs_console = { - .name = "ttyS", - .write = zs_console_write, - .device = uart_console_device, - .setup = zs_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &zs_reg, -}; - -/* - * Register console. - */ -static int __init zs_serial_console_init(void) -{ - int ret; - - ret = zs_probe_sccs(); - if (ret) - return ret; - register_console(&zs_console); - - return 0; -} - -console_initcall(zs_serial_console_init); - -#define SERIAL_ZS_CONSOLE &zs_console -#else -#define SERIAL_ZS_CONSOLE NULL -#endif /* CONFIG_SERIAL_ZS_CONSOLE */ - -static struct uart_driver zs_reg = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = ZS_NUM_SCCS * ZS_NUM_CHAN, - .cons = SERIAL_ZS_CONSOLE, -}; - -/* zs_init inits the driver. */ -static int __init zs_init(void) -{ - int i, ret; - - pr_info("%s%s\n", zs_name, zs_version); - - /* Find out how many Z85C30 SCCs we have. */ - ret = zs_probe_sccs(); - if (ret) - return ret; - - ret = uart_register_driver(&zs_reg); - if (ret) - return ret; - - for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { - struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; - struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; - struct uart_port *uport = &zport->port; - - if (zport->scc) - uart_add_one_port(&zs_reg, uport); - } - - return 0; -} - -static void __exit zs_exit(void) -{ - int i; - - for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) { - struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; - struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; - struct uart_port *uport = &zport->port; - - if (zport->scc) - uart_remove_one_port(&zs_reg, uport); - } - - uart_unregister_driver(&zs_reg); -} - -module_init(zs_init); -module_exit(zs_exit); diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h deleted file mode 100644 index aa921b57d827..000000000000 --- a/drivers/serial/zs.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * zs.h: Definitions for the DECstation Z85C30 serial driver. - * - * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. - * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen. - * - * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2004, 2005, 2007 Maciej W. Rozycki - */ -#ifndef _SERIAL_ZS_H -#define _SERIAL_ZS_H - -#ifdef __KERNEL__ - -#define ZS_NUM_REGS 16 - -/* - * This is our internal structure for each serial port's state. - */ -struct zs_port { - struct zs_scc *scc; /* Containing SCC. */ - struct uart_port port; /* Underlying UART. */ - - int clk_mode; /* May be 1, 16, 32, or 64. */ - - unsigned int tty_break; /* Set on BREAK condition. */ - int tx_stopped; /* Output is suspended. */ - - unsigned int mctrl; /* State of modem lines. */ - u8 brk; /* BREAK state from RR0. */ - - u8 regs[ZS_NUM_REGS]; /* Channel write registers. */ -}; - -/* - * Per-SCC state for locking and the interrupt handler. - */ -struct zs_scc { - struct zs_port zport[2]; - spinlock_t zlock; - atomic_t irq_guard; - int initialised; -}; - -#endif /* __KERNEL__ */ - -/* - * Conversion routines to/from brg time constants from/to bits per second. - */ -#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* - * The Zilog register set. - */ - -/* Write Register 0 (Command) */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */ -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */ -#define RxINT_ERR 0x18 /* Int on error only */ -#define RxINT_MASK 0x18 - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register 2 (Interrupt Vector) */ - -/* Write Register 3 (Receive Parameters and Control) */ -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ -#define RxNBITS_MASK 0xc0 - -/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */ -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ -#define SB_MASK 0xc - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xc0 /* x64 clock mode */ -#define XCLK_MASK 0xc0 - -/* Write Register 5 (Transmit Parameters and Controls) */ -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define TxNBITS_MASK 0x60 -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (Transmit Buffer) */ - -/* Write Register 9 (Master Interrupt Control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode Control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */ - -/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */ - -/* Write Register 14 (Miscellaneous Control Bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (External/Status Interrupt Control) */ -#define WR7P_EN 1 /* WR7 Prime SDLC Feature Enable */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 (Special Receive Condition Status) */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity Error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define FRM_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (Interrupt Vector (WR2) -- channel A). */ - -/* Read Register 2 (Modified Interrupt Vector -- channel B). */ - -/* Read Register 3 (Interrupt Pending Bits -- channel A only). */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */ - -/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */ - -/* Read Register 8 (Receive Data) */ - -/* Read Register 10 (Miscellaneous Status Bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */ - -/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */ - -/* Read Register 15 (External/Status Interrupt Control (WR15)) */ - -#endif /* _SERIAL_ZS_H */ diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index d3685f071b8d..396277216e4f 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_R3964) += n_r3964.o obj-y += vt/ obj-$(CONFIG_HVC_DRIVER) += hvc/ +obj-y += serial/ diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c new file mode 100644 index 000000000000..d89aa38c5cf0 --- /dev/null +++ b/drivers/tty/serial/21285.c @@ -0,0 +1,513 @@ +/* + * linux/drivers/serial/21285.c + * + * Driver for the serial port on the 21285 StrongArm-110 core logic chip. + * + * Based on drivers/char/serial.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define BAUD_BASE (mem_fclk_21285/64) + +#define SERIAL_21285_NAME "ttyFB" +#define SERIAL_21285_MAJOR 204 +#define SERIAL_21285_MINOR 4 + +#define RXSTAT_DUMMY_READ 0x80000000 +#define RXSTAT_FRAME (1 << 0) +#define RXSTAT_PARITY (1 << 1) +#define RXSTAT_OVERRUN (1 << 2) +#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN) + +#define H_UBRLCR_BREAK (1 << 0) +#define H_UBRLCR_PARENB (1 << 1) +#define H_UBRLCR_PAREVN (1 << 2) +#define H_UBRLCR_STOPB (1 << 3) +#define H_UBRLCR_FIFO (1 << 4) + +static const char serial21285_name[] = "Footbridge UART"; + +#define tx_enabled(port) ((port)->unused[0]) +#define rx_enabled(port) ((port)->unused[1]) + +/* + * The documented expression for selecting the divisor is: + * BAUD_BASE / baud - 1 + * However, typically BAUD_BASE is not divisible by baud, so + * we want to select the divisor that gives us the minimum + * error. Therefore, we want: + * int(BAUD_BASE / baud - 0.5) -> + * int(BAUD_BASE / baud - (baud >> 1) / baud) -> + * int((BAUD_BASE - (baud >> 1)) / baud) + */ + +static void serial21285_stop_tx(struct uart_port *port) +{ + if (tx_enabled(port)) { + disable_irq_nosync(IRQ_CONTX); + tx_enabled(port) = 0; + } +} + +static void serial21285_start_tx(struct uart_port *port) +{ + if (!tx_enabled(port)) { + enable_irq(IRQ_CONTX); + tx_enabled(port) = 1; + } +} + +static void serial21285_stop_rx(struct uart_port *port) +{ + if (rx_enabled(port)) { + disable_irq_nosync(IRQ_CONRX); + rx_enabled(port) = 0; + } +} + +static void serial21285_enable_ms(struct uart_port *port) +{ +} + +static irqreturn_t serial21285_rx_chars(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = port->state->port.tty; + unsigned int status, ch, flag, rxs, max_count = 256; + + status = *CSR_UARTFLG; + while (!(status & 0x10) && max_count--) { + ch = *CSR_UARTDR; + flag = TTY_NORMAL; + port->icount.rx++; + + rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ; + if (unlikely(rxs & RXSTAT_ANYERR)) { + if (rxs & RXSTAT_PARITY) + port->icount.parity++; + else if (rxs & RXSTAT_FRAME) + port->icount.frame++; + if (rxs & RXSTAT_OVERRUN) + port->icount.overrun++; + + rxs &= port->read_status_mask; + + if (rxs & RXSTAT_PARITY) + flag = TTY_PARITY; + else if (rxs & RXSTAT_FRAME) + flag = TTY_FRAME; + } + + uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag); + + status = *CSR_UARTFLG; + } + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +static irqreturn_t serial21285_tx_chars(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct circ_buf *xmit = &port->state->xmit; + int count = 256; + + if (port->x_char) { + *CSR_UARTDR = port->x_char; + port->icount.tx++; + port->x_char = 0; + goto out; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + serial21285_stop_tx(port); + goto out; + } + + do { + *CSR_UARTDR = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + serial21285_stop_tx(port); + + out: + return IRQ_HANDLED; +} + +static unsigned int serial21285_tx_empty(struct uart_port *port) +{ + return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT; +} + +/* no modem control lines */ +static unsigned int serial21285_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void serial21285_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int h_lcr; + + spin_lock_irqsave(&port->lock, flags); + h_lcr = *CSR_H_UBRLCR; + if (break_state) + h_lcr |= H_UBRLCR_BREAK; + else + h_lcr &= ~H_UBRLCR_BREAK; + *CSR_H_UBRLCR = h_lcr; + spin_unlock_irqrestore(&port->lock, flags); +} + +static int serial21285_startup(struct uart_port *port) +{ + int ret; + + tx_enabled(port) = 1; + rx_enabled(port) = 1; + + ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0, + serial21285_name, port); + if (ret == 0) { + ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0, + serial21285_name, port); + if (ret) + free_irq(IRQ_CONRX, port); + } + + return ret; +} + +static void serial21285_shutdown(struct uart_port *port) +{ + free_irq(IRQ_CONTX, port); + free_irq(IRQ_CONRX, port); +} + +static void +serial21285_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, quot, h_lcr, b; + + /* + * We don't support modem control lines. + */ + termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); + termios->c_cflag |= CLOCAL; + + /* + * We don't support BREAK character recognition. + */ + termios->c_iflag &= ~(IGNBRK | BRKINT); + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + b = port->uartclk / (16 * quot); + tty_termios_encode_baud_rate(termios, b, b); + + switch (termios->c_cflag & CSIZE) { + case CS5: + h_lcr = 0x00; + break; + case CS6: + h_lcr = 0x20; + break; + case CS7: + h_lcr = 0x40; + break; + default: /* CS8 */ + h_lcr = 0x60; + break; + } + + if (termios->c_cflag & CSTOPB) + h_lcr |= H_UBRLCR_STOPB; + if (termios->c_cflag & PARENB) { + h_lcr |= H_UBRLCR_PARENB; + if (!(termios->c_cflag & PARODD)) + h_lcr |= H_UBRLCR_PAREVN; + } + + if (port->fifosize) + h_lcr |= H_UBRLCR_FIFO; + + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * Which character status flags are we interested in? + */ + port->read_status_mask = RXSTAT_OVERRUN; + if (termios->c_iflag & INPCK) + port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + + /* + * Which character status flags should we ignore? + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RXSTAT_OVERRUN; + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + + quot -= 1; + + *CSR_UARTCON = 0; + *CSR_L_UBRLCR = quot & 0xff; + *CSR_M_UBRLCR = (quot >> 8) & 0x0f; + *CSR_H_UBRLCR = h_lcr; + *CSR_UARTCON = 1; + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *serial21285_type(struct uart_port *port) +{ + return port->type == PORT_21285 ? "DC21285" : NULL; +} + +static void serial21285_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 32); +} + +static int serial21285_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, 32, serial21285_name) + != NULL ? 0 : -EBUSY; +} + +static void serial21285_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0) + port->type = PORT_21285; +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) + ret = -EINVAL; + if (ser->irq != NO_IRQ) + ret = -EINVAL; + if (ser->baud_base != port->uartclk / 16) + ret = -EINVAL; + return ret; +} + +static struct uart_ops serial21285_ops = { + .tx_empty = serial21285_tx_empty, + .get_mctrl = serial21285_get_mctrl, + .set_mctrl = serial21285_set_mctrl, + .stop_tx = serial21285_stop_tx, + .start_tx = serial21285_start_tx, + .stop_rx = serial21285_stop_rx, + .enable_ms = serial21285_enable_ms, + .break_ctl = serial21285_break_ctl, + .startup = serial21285_startup, + .shutdown = serial21285_shutdown, + .set_termios = serial21285_set_termios, + .type = serial21285_type, + .release_port = serial21285_release_port, + .request_port = serial21285_request_port, + .config_port = serial21285_config_port, + .verify_port = serial21285_verify_port, +}; + +static struct uart_port serial21285_port = { + .mapbase = 0x42000160, + .iotype = UPIO_MEM, + .irq = NO_IRQ, + .fifosize = 16, + .ops = &serial21285_ops, + .flags = UPF_BOOT_AUTOCONF, +}; + +static void serial21285_setup_ports(void) +{ + serial21285_port.uartclk = mem_fclk_21285 / 4; +} + +#ifdef CONFIG_SERIAL_21285_CONSOLE +static void serial21285_console_putchar(struct uart_port *port, int ch) +{ + while (*CSR_UARTFLG & 0x20) + barrier(); + *CSR_UARTDR = ch; +} + +static void +serial21285_console_write(struct console *co, const char *s, + unsigned int count) +{ + uart_console_write(&serial21285_port, s, count, serial21285_console_putchar); +} + +static void __init +serial21285_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (*CSR_UARTCON == 1) { + unsigned int tmp; + + tmp = *CSR_H_UBRLCR; + switch (tmp & 0x60) { + case 0x00: + *bits = 5; + break; + case 0x20: + *bits = 6; + break; + case 0x40: + *bits = 7; + break; + default: + case 0x60: + *bits = 8; + break; + } + + if (tmp & H_UBRLCR_PARENB) { + *parity = 'o'; + if (tmp & H_UBRLCR_PAREVN) + *parity = 'e'; + } + + tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8); + + *baud = port->uartclk / (16 * (tmp + 1)); + } +} + +static int __init serial21285_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &serial21285_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (machine_is_personal_server()) + baud = 57600; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + serial21285_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver serial21285_reg; + +static struct console serial21285_console = +{ + .name = SERIAL_21285_NAME, + .write = serial21285_console_write, + .device = uart_console_device, + .setup = serial21285_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &serial21285_reg, +}; + +static int __init rs285_console_init(void) +{ + serial21285_setup_ports(); + register_console(&serial21285_console); + return 0; +} +console_initcall(rs285_console_init); + +#define SERIAL_21285_CONSOLE &serial21285_console +#else +#define SERIAL_21285_CONSOLE NULL +#endif + +static struct uart_driver serial21285_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyFB", + .dev_name = "ttyFB", + .major = SERIAL_21285_MAJOR, + .minor = SERIAL_21285_MINOR, + .nr = 1, + .cons = SERIAL_21285_CONSOLE, +}; + +static int __init serial21285_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: 21285 driver\n"); + + serial21285_setup_ports(); + + ret = uart_register_driver(&serial21285_reg); + if (ret == 0) + uart_add_one_port(&serial21285_reg, &serial21285_port); + + return ret; +} + +static void __exit serial21285_exit(void) +{ + uart_remove_one_port(&serial21285_reg, &serial21285_port); + uart_unregister_driver(&serial21285_reg); +} + +module_init(serial21285_init); +module_exit(serial21285_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver"); +MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c new file mode 100644 index 000000000000..be0ebce36e54 --- /dev/null +++ b/drivers/tty/serial/68328serial.c @@ -0,0 +1,1472 @@ +/* 68328serial.c: Serial port driver for 68328 microcontroller + * + * Copyright (C) 1995 David S. Miller + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1998, 1999 D. Jeff Dionne + * Copyright (C) 1999 Vladimir Gurevich + * Copyright (C) 2002-2003 David McCullough + * Copyright (C) 2002 Greg Ungerer + * + * VZ Support/Fixes Evan Stawnyczy + * Multiple UART support Daniel Potts + * Power management support Daniel Potts + * VZ Second Serial Port enable Phil Wilshire + * 2.4/2.5 port David McCullough + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* (es) */ +/* note: perhaps we can murge these files, so that you can just + * define 1 of them, and they can sort that out for themselves + */ +#if defined(CONFIG_M68EZ328) +#include +#else +#if defined(CONFIG_M68VZ328) +#include +#else +#include +#endif /* CONFIG_M68VZ328 */ +#endif /* CONFIG_M68EZ328 */ + +#include "68328serial.h" + +/* Turn off usage of real serial interrupt code, to "support" Copilot */ +#ifdef CONFIG_XCOPILOT_BUGS +#undef USE_INTS +#else +#define USE_INTS +#endif + +static struct m68k_serial m68k_soft[NR_PORTS]; + +static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; + +/* multiple ports are contiguous in memory */ +m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; + +struct tty_struct m68k_ttys; +struct m68k_serial *m68k_consinfo = 0; + +#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */ + +struct tty_driver *serial_driver; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Debugging... DEBUG_INTR is bad to use when one of the zs + * lines is your console ;( + */ +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#define RS_ISR_PASS_LIMIT 256 + +static void change_speed(struct m68k_serial *info); + +/* + * Setup for console. Argument comes from the boot command line. + */ + +/* note: this is messy, but it works, again, perhaps defined somewhere else?*/ +#ifdef CONFIG_M68VZ328 +#define CONSOLE_BAUD_RATE 19200 +#define DEFAULT_CBAUD B19200 +#endif + + +#ifndef CONSOLE_BAUD_RATE +#define CONSOLE_BAUD_RATE 9600 +#define DEFAULT_CBAUD B9600 +#endif + + +static int m68328_console_initted = 0; +static int m68328_console_baud = CONSOLE_BAUD_RATE; +static int m68328_console_cbaud = DEFAULT_CBAUD; + + +static inline int serial_paranoia_check(struct m68k_serial *info, + char *name, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct %s in %s\n"; + static const char *badinfo = + "Warning: null m68k_serial for %s in %s\n"; + + if (!info) { + printk(badinfo, name, routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, name, routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor speeds and the timeouts + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 0 }; + +/* Sets or clears DTR/RTS on the requested line */ +static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) +{ + if (set) { + /* set the RTS/CTS line */ + } else { + /* clear it */ + } + return; +} + +/* Utility routines */ +static inline int get_baud(struct m68k_serial *ss) +{ + unsigned long result = 115200; + unsigned short int baud = uart_addr[ss->line].ubaud; + if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400; + result >>= GET_FIELD(baud, UBAUD_DIVIDE); + + return result; +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_stop")) + return; + + local_irq_save(flags); + uart->ustcnt &= ~USTCNT_TXEN; + local_irq_restore(flags); +} + +static int rs_put_char(char ch) +{ + int flags, loops = 0; + + local_irq_save(flags); + + while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) { + loops++; + udelay(5); + } + + UTX_TXDATA = ch; + udelay(5); + local_irq_restore(flags); + return 1; +} + +static void rs_start(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_start")) + return; + + local_irq_save(flags); + if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) { +#ifdef USE_INTS + uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; +#else + uart->ustcnt |= USTCNT_TXEN; +#endif + } + local_irq_restore(flags); +} + +/* Drop into either the boot monitor or kadb upon receiving a break + * from keyboard/console input. + */ +static void batten_down_hatches(void) +{ + /* Drop into the debugger */ +} + +static void status_handle(struct m68k_serial *info, unsigned short status) +{ +#if 0 + if(status & DCD) { + if((info->port.tty->termios->c_cflag & CRTSCTS) && + ((info->curregs[3] & AUTO_ENAB)==0)) { + info->curregs[3] |= AUTO_ENAB; + info->pendregs[3] |= AUTO_ENAB; + write_zsreg(info->m68k_channel, 3, info->curregs[3]); + } + } else { + if((info->curregs[3] & AUTO_ENAB)) { + info->curregs[3] &= ~AUTO_ENAB; + info->pendregs[3] &= ~AUTO_ENAB; + write_zsreg(info->m68k_channel, 3, info->curregs[3]); + } + } +#endif + /* If this is console input and this is a + * 'break asserted' status change interrupt + * see if we can drop into the debugger + */ + if((status & URX_BREAK) && info->break_abort) + batten_down_hatches(); + return; +} + +static void receive_chars(struct m68k_serial *info, unsigned short rx) +{ + struct tty_struct *tty = info->port.tty; + m68328_uart *uart = &uart_addr[info->line]; + unsigned char ch, flag; + + /* + * This do { } while() loop will get ALL chars out of Rx FIFO + */ +#ifndef CONFIG_XCOPILOT_BUGS + do { +#endif + ch = GET_FIELD(rx, URX_RXDATA); + + if(info->is_cons) { + if(URX_BREAK & rx) { /* whee, break received */ + status_handle(info, rx); + return; +#ifdef CONFIG_MAGIC_SYSRQ + } else if (ch == 0x10) { /* ^P */ + show_state(); + show_free_areas(); + show_buffers(); +/* show_net_buffers(); */ + return; + } else if (ch == 0x12) { /* ^R */ + emergency_restart(); + return; +#endif /* CONFIG_MAGIC_SYSRQ */ + } + } + + if(!tty) + goto clear_and_exit; + + flag = TTY_NORMAL; + + if(rx & URX_PARITY_ERROR) { + flag = TTY_PARITY; + status_handle(info, rx); + } else if(rx & URX_OVRUN) { + flag = TTY_OVERRUN; + status_handle(info, rx); + } else if(rx & URX_FRAME_ERROR) { + flag = TTY_FRAME; + status_handle(info, rx); + } + tty_insert_flip_char(tty, ch, flag); +#ifndef CONFIG_XCOPILOT_BUGS + } while((rx = uart->urx.w) & URX_DATA_READY); +#endif + + tty_schedule_flip(tty); + +clear_and_exit: + return; +} + +static void transmit_chars(struct m68k_serial *info) +{ + m68328_uart *uart = &uart_addr[info->line]; + + if (info->x_char) { + /* Send next char */ + uart->utx.b.txdata = info->x_char; + info->x_char = 0; + goto clear_and_return; + } + + if((info->xmit_cnt <= 0) || info->port.tty->stopped) { + /* That's peculiar... TX ints off */ + uart->ustcnt &= ~USTCNT_TX_INTR_MASK; + goto clear_and_return; + } + + /* Send char */ + uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + + if (info->xmit_cnt < WAKEUP_CHARS) + schedule_work(&info->tqueue); + + if(info->xmit_cnt <= 0) { + /* All done for now... TX ints off */ + uart->ustcnt &= ~USTCNT_TX_INTR_MASK; + goto clear_and_return; + } + +clear_and_return: + /* Clear interrupt (should be auto)*/ + return; +} + +/* + * This is the serial driver's generic interrupt routine + */ +irqreturn_t rs_interrupt(int irq, void *dev_id) +{ + struct m68k_serial *info = dev_id; + m68328_uart *uart; + unsigned short rx; + unsigned short tx; + + uart = &uart_addr[info->line]; + rx = uart->urx.w; + +#ifdef USE_INTS + tx = uart->utx.w; + + if (rx & URX_DATA_READY) receive_chars(info, rx); + if (tx & UTX_TX_AVAIL) transmit_chars(info); +#else + receive_chars(info, rx); +#endif + return IRQ_HANDLED; +} + +static void do_softint(struct work_struct *work) +{ + struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); + struct tty_struct *tty; + + tty = info->port.tty; + if (!tty) + return; +#if 0 + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + tty_wakeup(tty); + } +#endif +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(struct work_struct *work) +{ + struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup); + struct tty_struct *tty; + + tty = info->port.tty; + if (!tty) + return; + + tty_hangup(tty); +} + + +static int startup(struct m68k_serial * info) +{ + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + if (info->flags & S_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + + local_irq_save(flags); + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + + uart->ustcnt = USTCNT_UEN; + info->xmit_fifo_size = 1; + uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; + (void)uart->urx.w; + + /* + * Finally, enable sequencing and interrupts + */ +#ifdef USE_INTS + uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | + USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK; +#else + uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; +#endif + + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ + + change_speed(info); + + info->flags |= S_INITIALIZED; + local_irq_restore(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct m68k_serial * info) +{ + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + uart->ustcnt = 0; /* All off! */ + if (!(info->flags & S_INITIALIZED)) + return; + + local_irq_save(flags); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + + info->flags &= ~S_INITIALIZED; + local_irq_restore(flags); +} + +struct { + int divisor, prescale; +} +#ifndef CONFIG_M68VZ328 + hw_baud_table[18] = { + {0,0}, /* 0 */ + {0,0}, /* 50 */ + {0,0}, /* 75 */ + {0,0}, /* 110 */ + {0,0}, /* 134 */ + {0,0}, /* 150 */ + {0,0}, /* 200 */ + {7,0x26}, /* 300 */ + {6,0x26}, /* 600 */ + {5,0x26}, /* 1200 */ + {0,0}, /* 1800 */ + {4,0x26}, /* 2400 */ + {3,0x26}, /* 4800 */ + {2,0x26}, /* 9600 */ + {1,0x26}, /* 19200 */ + {0,0x26}, /* 38400 */ + {1,0x38}, /* 57600 */ + {0,0x38}, /* 115200 */ +}; +#else + hw_baud_table[18] = { + {0,0}, /* 0 */ + {0,0}, /* 50 */ + {0,0}, /* 75 */ + {0,0}, /* 110 */ + {0,0}, /* 134 */ + {0,0}, /* 150 */ + {0,0}, /* 200 */ + {0,0}, /* 300 */ + {7,0x26}, /* 600 */ + {6,0x26}, /* 1200 */ + {0,0}, /* 1800 */ + {5,0x26}, /* 2400 */ + {4,0x26}, /* 4800 */ + {3,0x26}, /* 9600 */ + {2,0x26}, /* 19200 */ + {1,0x26}, /* 38400 */ + {0,0x26}, /* 57600 */ + {1,0x38}, /* 115200 */ +}; +#endif +/* rate = 1036800 / ((65 - prescale) * (1<line]; + unsigned short port; + unsigned short ustcnt; + unsigned cflag; + int i; + + if (!info->port.tty || !info->port.tty->termios) + return; + cflag = info->port.tty->termios->c_cflag; + if (!(port = info->port)) + return; + + ustcnt = uart->ustcnt; + uart->ustcnt = ustcnt & ~USTCNT_TXEN; + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i = (i & ~CBAUDEX) + B38400; + } + + info->baud = baud_table[i]; + uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | + PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); + + ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); + + if ((cflag & CSIZE) == CS8) + ustcnt |= USTCNT_8_7; + + if (cflag & CSTOPB) + ustcnt |= USTCNT_STOP; + + if (cflag & PARENB) + ustcnt |= USTCNT_PARITYEN; + if (cflag & PARODD) + ustcnt |= USTCNT_ODD_EVEN; + +#ifdef CONFIG_SERIAL_68328_RTS_CTS + if (cflag & CRTSCTS) { + uart->utx.w &= ~ UTX_NOCTS; + } else { + uart->utx.w |= UTX_NOCTS; + } +#endif + + ustcnt |= USTCNT_TXEN; + + uart->ustcnt = ustcnt; + return; +} + +/* + * Fair output driver allows a process to speak. + */ +static void rs_fair_output(void) +{ + int left; /* Output no more than that */ + unsigned long flags; + struct m68k_serial *info = &m68k_soft[0]; + char c; + + if (info == 0) return; + if (info->xmit_buf == 0) return; + + local_irq_save(flags); + left = info->xmit_cnt; + while (left != 0) { + c = info->xmit_buf[info->xmit_tail]; + info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + local_irq_restore(flags); + + rs_put_char(c); + + local_irq_save(flags); + left = min(info->xmit_cnt, left-1); + } + + /* Last character is being transmitted now (hopefully). */ + udelay(5); + + local_irq_restore(flags); + return; +} + +/* + * m68k_console_print is registered for printk. + */ +void console_print_68328(const char *p) +{ + char c; + + while((c=*(p++)) != 0) { + if(c == '\n') + rs_put_char('\r'); + rs_put_char(c); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + rs_fair_output(); + + return; +} + +static void rs_set_ldisc(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) + return; + + info->is_cons = (tty->termios->c_line == N_TTY); + + printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off"); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) + return; +#ifndef USE_INTS + for(;;) { +#endif + + /* Enable transmitter */ + local_irq_save(flags); + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) { + local_irq_restore(flags); + return; + } + +#ifdef USE_INTS + uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; +#else + uart->ustcnt |= USTCNT_TXEN; +#endif + +#ifdef USE_INTS + if (uart->utx.w & UTX_TX_AVAIL) { +#else + if (1) { +#endif + /* Send char */ + uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + +#ifndef USE_INTS + while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); + } +#endif + local_irq_restore(flags); +} + +extern void console_printn(const char * b, int count); + +static int rs_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + local_save_flags(flags); + while (1) { + local_irq_disable(); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + local_irq_restore(flags); + + if (c <= 0) + break; + + memcpy(info->xmit_buf + info->xmit_head, buf, c); + + local_irq_disable(); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + local_irq_restore(flags); + buf += c; + count -= c; + total += c; + } + + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { + /* Enable transmitter */ + local_irq_disable(); +#ifndef USE_INTS + while(info->xmit_cnt) { +#endif + + uart->ustcnt |= USTCNT_TXEN; +#ifdef USE_INTS + uart->ustcnt |= USTCNT_TX_INTR_MASK; +#else + while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); +#endif + if (uart->utx.w & UTX_TX_AVAIL) { + uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + +#ifndef USE_INTS + } +#endif + local_irq_restore(flags); + } + + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->name, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) + return; + local_irq_save(flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + local_irq_restore(flags); + tty_wakeup(tty); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + /* Turn off RTS line (do this atomic) */ +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + + /* Assert RTS line (do this atomic) */ +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct m68k_serial * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +static int set_serial_info(struct m68k_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct m68k_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; + old_info = *info; + + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~S_USR_MASK) != + (info->flags & ~S_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~S_USR_MASK) | + (new_serial.flags & S_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~S_FLAGS) | + (new_serial.flags & S_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + +check_and_exit: + retval = startup(info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct m68k_serial * info, unsigned int *value) +{ +#ifdef CONFIG_SERIAL_68328_RTS_CTS + m68328_uart *uart = &uart_addr[info->line]; +#endif + unsigned char status; + unsigned long flags; + + local_irq_save(flags); +#ifdef CONFIG_SERIAL_68328_RTS_CTS + status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0; +#else + status = 0; +#endif + local_irq_restore(flags); + return put_user(status, value); +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break(struct m68k_serial * info, unsigned int duration) +{ + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + if (!info->port) + return; + local_irq_save(flags); +#ifdef USE_INTS + uart->utx.w |= UTX_SEND_BREAK; + msleep_interruptible(duration); + uart->utx.w &= ~UTX_SEND_BREAK; +#endif + local_irq_restore(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + int retval; + + if (serial_paranoia_check(info, tty->name, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, 250); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg*(100) : 250); + return 0; + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + case TIOCSERGSTRUCT: + if (copy_to_user((struct m68k_serial *) arg, + info, sizeof(struct m68k_serial))) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; + + change_speed(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * S structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + m68328_uart *uart = &uart_addr[info->line]; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->name, "rs_close")) + return; + + local_irq_save(flags); + + if (tty_hung_up_p(filp)) { + local_irq_restore(flags); + return; + } + + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->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. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttyS%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + local_irq_restore(flags); + return; + } + info->flags |= S_CLOSING; + /* + * 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 (info->closing_wait != S_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + + uart->ustcnt &= ~USTCNT_RXEN; + uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); + + shutdown(info); + rs_flush_buffer(tty); + + tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->port.tty = NULL; +#warning "This is not and has never been valid so fix it" +#if 0 + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } +#endif + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs(info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); + wake_up_interruptible(&info->close_wait); + local_irq_restore(flags); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void rs_hangup(struct tty_struct *tty) +{ + struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_hangup")) + return; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~S_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct m68k_serial *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & S_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & S_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= S_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + info->count--; + info->blocked_open++; + while (1) { + local_irq_disable(); + m68k_rtsdtr(info, 1); + local_irq_enable(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & S_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & S_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & S_CLOSING) && do_clocal) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + tty_unlock(); + schedule(); + tty_lock(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; + + if (retval) + return retval; + info->flags |= S_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its S structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct m68k_serial *info; + int retval, line; + + line = tty->index; + + if (line >= NR_PORTS || line < 0) /* we have exactly one */ + return -ENODEV; + + info = &m68k_soft[line]; + + if (serial_paranoia_check(info, tty->name, "rs_open")) + return -ENODEV; + + info->count++; + tty->driver_data = info; + info->port.tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + return block_til_ready(tty, filp, info); +} + +/* Finally, routines used to initialize the serial driver. */ + +static void show_serial_version(void) +{ + printk("MC68328 serial driver version 1.00\n"); +} + +static const struct tty_operations rs_ops = { + .open = rs_open, + .close = rs_close, + .write = rs_write, + .flush_chars = rs_flush_chars, + .write_room = rs_write_room, + .chars_in_buffer = rs_chars_in_buffer, + .flush_buffer = rs_flush_buffer, + .ioctl = rs_ioctl, + .throttle = rs_throttle, + .unthrottle = rs_unthrottle, + .set_termios = rs_set_termios, + .stop = rs_stop, + .start = rs_start, + .hangup = rs_hangup, + .set_ldisc = rs_set_ldisc, +}; + +/* rs_init inits the driver */ +static int __init +rs68328_init(void) +{ + int flags, i; + struct m68k_serial *info; + + serial_driver = alloc_tty_driver(NR_PORTS); + if (!serial_driver) + return -ENOMEM; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + /* SPARC: Not all of this is exactly right for us. */ + + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + 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 = + m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; + 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;imagic = SERIAL_MAGIC; + info->port = (int) &uart_addr[i]; + info->port.tty = NULL; + info->irq = uart_irqs[i]; + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + INIT_WORK(&info->tqueue, do_softint); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->line = i; + info->is_cons = 1; /* Means shortcuts work */ + + printk("%s%d at 0x%08x (irq = %d)", serial_driver->name, info->line, + info->port, info->irq); + printk(" is a builtin MC68328 UART\n"); + +#ifdef CONFIG_M68VZ328 + if (i > 0 ) + PJSEL &= 0xCF; /* PSW enable second port output */ +#endif + + if (request_irq(uart_irqs[i], + rs_interrupt, + IRQF_DISABLED, + "M68328_UART", info)) + panic("Unable to attach 68328 serial interrupt\n"); + } + local_irq_restore(flags); + return 0; +} + +module_init(rs68328_init); + + + +static void m68328_set_baud(void) +{ + unsigned short ustcnt; + int i; + + ustcnt = USTCNT; + USTCNT = ustcnt & ~USTCNT_TXEN; + +again: + for (i = 0; i < ARRAY_SIZE(baud_table); i++) + if (baud_table[i] == m68328_console_baud) + break; + if (i >= ARRAY_SIZE(baud_table)) { + m68328_console_baud = 9600; + goto again; + } + + UBAUD = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | + PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); + ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7); + ustcnt |= USTCNT_8_7; + ustcnt |= USTCNT_TXEN; + USTCNT = ustcnt; + m68328_console_initted = 1; + return; +} + + +int m68328_console_setup(struct console *cp, char *arg) +{ + int i, n = CONSOLE_BAUD_RATE; + + if (!cp) + return(-1); + + if (arg) + n = simple_strtoul(arg,NULL,0); + + for (i = 0; i < ARRAY_SIZE(baud_table); i++) + if (baud_table[i] == n) + break; + if (i < ARRAY_SIZE(baud_table)) { + m68328_console_baud = n; + m68328_console_cbaud = 0; + if (i > 15) { + m68328_console_cbaud |= CBAUDEX; + i -= 15; + } + m68328_console_cbaud |= i; + } + + m68328_set_baud(); /* make sure baud rate changes */ + return(0); +} + + +static struct tty_driver *m68328_console_device(struct console *c, int *index) +{ + *index = c->index; + return serial_driver; +} + + +void m68328_console_write (struct console *co, const char *str, + unsigned int count) +{ + if (!m68328_console_initted) + m68328_set_baud(); + while (count--) { + if (*str == '\n') + rs_put_char('\r'); + rs_put_char( *str++ ); + } +} + + +static struct console m68328_driver = { + .name = "ttyS", + .write = m68328_console_write, + .device = m68328_console_device, + .setup = m68328_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + + +static int __init m68328_console_init(void) +{ + register_console(&m68328_driver); + return 0; +} + +console_initcall(m68328_console_init); diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h new file mode 100644 index 000000000000..664ceb0a158c --- /dev/null +++ b/drivers/tty/serial/68328serial.h @@ -0,0 +1,188 @@ +/* 68328serial.h: Definitions for the mc68328 serial driver. + * + * Copyright (C) 1995 David S. Miller + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1998, 1999 D. Jeff Dionne + * Copyright (C) 1999 Vladimir Gurevich + * + * VZ Support/Fixes Evan Stawnyczy + */ + +#ifndef _MC683XX_SERIAL_H +#define _MC683XX_SERIAL_H + + +struct serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; /* FIXME: We don't have AT&T Hub6 boards! */ + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + int reserved[4]; +}; + +/* + * For the close wait times, 0 means wait forever for serial port to + * flush its output. 65535 means don't wait at all. + */ +#define S_CLOSING_WAIT_INF 0 +#define S_CLOSING_WAIT_NONE 65535 + +/* + * Definitions for S_struct (and serial_struct) flags field + */ +#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define S_SPD_MASK 0x0030 +#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ + +#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define S_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define S_FLAGS 0x0FFF /* Possible legal S flags */ +#define S_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define S_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define S_CLOSING 0x08000000 /* Serial port is closing */ +#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +/* Software state per channel */ + +#ifdef __KERNEL__ + +/* + * I believe this is the optimal setting that reduces the number of interrupts. + * At high speeds the output might become a little "bursted" (use USTCNT_TXHE + * if that bothers you), but in most cases it will not, since we try to + * transmit characters every time rs_interrupt is called. Thus, quite often + * you'll see that a receive interrupt occures before the transmit one. + * -- Vladimir Gurevich + */ +#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) + +/* + * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special + * "Old data interrupt" which occures whenever the data stay in the FIFO + * longer than 30 bits time. This allows us to use FIFO without compromising + * latency. '328 does not have this feature and without the real 328-based + * board I would assume that RXRE is the safest setting. + * + * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of + * interrupts. RXFE (receive queue full) causes the system to lose data + * at least at 115200 baud + * + * If your board is busy doing other stuff, you might consider to use + * RXRE (data ready intrrupt) instead. + * + * The other option is to make these INTR masks run-time configurable, so + * that people can dynamically adapt them according to the current usage. + * -- Vladimir Gurevich + */ + +/* (es) */ +#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) +#elif defined(CONFIG_M68328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) +#else +#error Please, define the Rx interrupt events for your CPU +#endif +/* (/es) */ + +/* + * 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 m68k_serial { + char soft_carrier; /* Use soft carrier on this channel */ + char break_abort; /* Is serial console in, so process brk/abrt */ + char is_cons; /* Is this our console. */ + + /* We need to know the current clock divisor + * to read the bps rate the chip has currently + * loaded. + */ + unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ + int baud; + int magic; + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct work_struct tqueue; + struct work_struct tqueue_hangup; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; +}; + + +#define SERIAL_MAGIC 0x5301 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ +#define SERIAL_XMIT_SIZE 4096 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +/* + * Define the number of ports supported and their irqs. + */ +#define NR_PORTS 1 +#define UART_IRQ_DEFNS {UART_IRQ_NUM} + +#endif /* __KERNEL__ */ +#endif /* !(_MC683XX_SERIAL_H) */ diff --git a/drivers/tty/serial/68360serial.c b/drivers/tty/serial/68360serial.c new file mode 100644 index 000000000000..88b13356ec10 --- /dev/null +++ b/drivers/tty/serial/68360serial.c @@ -0,0 +1,2978 @@ +/* + * UART driver for 68360 CPM SCC or SMC + * Copyright (c) 2000 D. Jeff Dionne , + * Copyright (c) 2000 Michael Leslie + * Copyright (c) 1997 Dan Malek + * + * I used the serial.c driver as the framework for this driver. + * Give credit to those guys. + * The original code was written for the MBX860 board. I tried to make + * it generic, but there may be some assumptions in the structures that + * have to be fixed later. + * To save porting time, I did not bother to change any object names + * that are not accessed outside of this file. + * It still needs lots of work........When it was easy, I included code + * to support the SCCs, but this has never been tested, nor is it complete. + * Only the SCCs support modem control, so that is not complete either. + * + * This module exports the following rs232 io functions: + * + * int rs_360_init(void); + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_KGDB +extern void breakpoint(void); +extern void set_debug_traps(void); +extern int kgdb_output_string (const char* s, unsigned int count); +#endif + + +/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */ +#include +#include + +/* this defines the index into rs_table for the port to use + */ +#ifndef CONFIG_SERIAL_CONSOLE_PORT +#define CONFIG_SERIAL_CONSOLE_PORT 1 /* ie SMC2 - note USE_SMC2 must be defined */ +#endif +/* #endif */ + +#if 0 +/* SCC2 for console + */ +#undef CONFIG_SERIAL_CONSOLE_PORT +#define CONFIG_SERIAL_CONSOLE_PORT 2 +#endif + + +#define TX_WAKEUP ASYNC_SHARE_IRQ + +static char *serial_name = "CPM UART driver"; +static char *serial_version = "0.03"; + +static struct tty_driver *serial_driver; +int serial_console_setup(struct console *co, char *options); + +/* + * Serial driver configuration section. Here are the various options: + */ +#define SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + +#define _INLINE_ inline + +#define DBG_CNT(s) + +/* We overload some of the items in the data structure to meet our + * needs. For example, the port address is the CPM parameter ram + * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and + * 2 SMCs. The "hub6" field is used to indicate the channel number, with + * a flag indicating SCC or SMC, and the number is used as an index into + * the CPM parameter area for this device. + * The "type" field is currently set to 0, for PORT_UNKNOWN. It is + * not currently used. I should probably use it to indicate the port + * type of SMC or SCC. + * The SMCs do not support any modem control signals. + */ +#define smc_scc_num hub6 +#define NUM_IS_SCC ((int)0x00010000) +#define PORT_NUM(P) ((P) & 0x0000ffff) + + +#if defined (CONFIG_UCQUICC) + +volatile extern void *_periph_base; +/* sipex transceiver + * mode bits for are on pins + * + * SCC2 d16..19 + * SCC3 d20..23 + * SCC4 d24..27 + */ +#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1))) + +static uint sipex_mode_bits = 0x00000000; + +#endif + +/* There is no `serial_state' defined back here in 2.0. + * Try to get by with serial_struct + */ +/* #define serial_state serial_struct */ + +/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few + * extras: */ + +#if 0 +struct async_icount_24 { + __u32 cts, dsr, rng, dcd, tx, rx; + __u32 frame, parity, overrun, brk; + __u32 buf_overrun; +} icount; +#endif + +#if 0 + +struct serial_state { + int magic; + int baud_base; + unsigned long port; + int irq; + int flags; + int hub6; + int type; + int line; + int revision; /* Chip revision (950) */ + int xmit_fifo_size; + int custom_divisor; + int count; + u8 *iomem_base; + u16 iomem_reg_shift; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + struct async_icount_24 icount; + int io_type; + struct async_struct *info; +}; +#endif + +#define SSTATE_MAGIC 0x5302 + + + +/* SMC2 is sometimes used for low performance TDM interfaces. Define + * this as 1 if you want SMC2 as a serial port UART managed by this driver. + * Define this as 0 if you wish to use SMC2 for something else. + */ +#define USE_SMC2 1 + +#if 0 +/* Define SCC to ttySx mapping. */ +#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ + +/* Define which SCC is the first one to use for a serial port. These + * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used + * for Ethernet, and the first available SCC for serial UART is SCC2. + * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and + * interrupt vectors in the table below to match. + */ +#define SCC_IDX_BASE 1 /* table index */ +#endif + + +/* Processors other than the 860 only get SMCs configured by default. + * Either they don't have SCCs or they are allocated somewhere else. + * Of course, there are now 860s without some SCCs, so we will need to + * address that someday. + * The Embedded Planet Multimedia I/O cards use TDM interfaces to the + * stereo codec parts, and we use SMC2 to help support that. + */ +static struct serial_state rs_table[] = { +/* type line PORT IRQ FLAGS smc_scc_num (F.K.A. hub6) */ + { 0, 0, PRSLOT_SMC1, CPMVEC_SMC1, 0, 0 } /* SMC1 ttyS0 */ +#if USE_SMC2 + ,{ 0, 0, PRSLOT_SMC2, CPMVEC_SMC2, 0, 1 } /* SMC2 ttyS1 */ +#endif + +#if defined(CONFIG_SERIAL_68360_SCC) + ,{ 0, 0, PRSLOT_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) } /* SCC2 ttyS2 */ + ,{ 0, 0, PRSLOT_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) } /* SCC3 ttyS3 */ + ,{ 0, 0, PRSLOT_SCC4, CPMVEC_SCC4, 0, (NUM_IS_SCC | 3) } /* SCC4 ttyS4 */ +#endif +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +/* The number of buffer descriptors and their sizes. + */ +#define RX_NUM_FIFO 4 +#define RX_BUF_SIZE 32 +#define TX_NUM_FIFO 4 +#define TX_BUF_SIZE 32 + +#define CONSOLE_NUM_FIFO 2 +#define CONSOLE_BUF_SIZE 4 + +char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE]; + +/* The async_struct in serial.h does not really give us what we + * need, so define our own here. + */ +typedef struct serial_info { + int magic; + int flags; + + struct serial_state *state; + /* struct serial_struct *state; */ + /* struct async_struct *state; */ + + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int line; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int blocked_open; /* # of blocked opens */ + struct work_struct tqueue; + struct work_struct tqueue_hangup; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + +/* CPM Buffer Descriptor pointers. + */ + QUICC_BD *rx_bd_base; + QUICC_BD *rx_cur; + QUICC_BD *tx_bd_base; + QUICC_BD *tx_cur; +} ser_info_t; + + +/* since kmalloc_init() does not get called until much after this initialization: */ +static ser_info_t quicc_ser_info[NR_PORTS]; +static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE]; +static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE]; + +static void change_speed(ser_info_t *info); +static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout); + +static inline int serial_paranoia_check(ser_info_t *info, + char *name, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, name, routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, name, routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor speeds and the timeouts, + * indexed by the termio value. The generic CPM functions are responsible + * for setting and assigning baud rate generators for us. + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; + +/* This sucks. There is a better way: */ +#if defined(CONFIG_CONSOLE_9600) + #define CONSOLE_BAUDRATE 9600 +#elif defined(CONFIG_CONSOLE_19200) + #define CONSOLE_BAUDRATE 19200 +#elif defined(CONFIG_CONSOLE_115200) + #define CONSOLE_BAUDRATE 115200 +#else + #warning "console baud rate undefined" + #define CONSOLE_BAUDRATE 9600 +#endif + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_360_stop(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + int idx; + unsigned long flags; + volatile struct scc_regs *sccp; + volatile struct smc_regs *smcp; + + if (serial_paranoia_check(info, tty->name, "rs_stop")) + return; + + local_irq_save(flags); + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + sccp->scc_sccm &= ~UART_SCCM_TX; + } else { + /* smcp = &cpmp->cp_smc[idx]; */ + smcp = &pquicc->smc_regs[idx]; + smcp->smc_smcm &= ~SMCM_TX; + } + local_irq_restore(flags); +} + + +static void rs_360_start(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + int idx; + unsigned long flags; + volatile struct scc_regs *sccp; + volatile struct smc_regs *smcp; + + if (serial_paranoia_check(info, tty->name, "rs_stop")) + return; + + local_irq_save(flags); + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + sccp->scc_sccm |= UART_SCCM_TX; + } else { + smcp = &pquicc->smc_regs[idx]; + smcp->smc_smcm |= SMCM_TX; + } + local_irq_restore(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +static _INLINE_ void receive_chars(ser_info_t *info) +{ + struct tty_struct *tty = info->port.tty; + unsigned char ch, flag, *cp; + /*int ignored = 0;*/ + int i; + ushort status; + struct async_icount *icount; + /* struct async_icount_24 *icount; */ + volatile QUICC_BD *bdp; + + icount = &info->state->icount; + + /* Just loop through the closed BDs and copy the characters into + * the buffer. + */ + bdp = info->rx_cur; + for (;;) { + if (bdp->status & BD_SC_EMPTY) /* If this one is empty */ + break; /* we are all done */ + + /* The read status mask tell us what we should do with + * incoming characters, especially if errors occur. + * One special case is the use of BD_SC_EMPTY. If + * this is not set, we are supposed to be ignoring + * inputs. In this case, just mark the buffer empty and + * continue. + */ + if (!(info->read_status_mask & BD_SC_EMPTY)) { + bdp->status |= BD_SC_EMPTY; + bdp->status &= + ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); + + if (bdp->status & BD_SC_WRAP) + bdp = info->rx_bd_base; + else + bdp++; + continue; + } + + /* Get the number of characters and the buffer pointer. + */ + i = bdp->length; + /* cp = (unsigned char *)__va(bdp->buf); */ + cp = (char *)bdp->buf; + status = bdp->status; + + while (i-- > 0) { + ch = *cp++; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, status); +#endif + flag = TTY_NORMAL; + + if (status & (BD_SC_BR | BD_SC_FR | + BD_SC_PR | BD_SC_OV)) { + /* + * For statistics only + */ + if (status & BD_SC_BR) + icount->brk++; + else if (status & BD_SC_PR) + icount->parity++; + else if (status & BD_SC_FR) + icount->frame++; + if (status & BD_SC_OV) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + if (status & info->ignore_status_mask) { + if (++ignored > 100) + break; + continue; + } + */ + status &= info->read_status_mask; + + if (status & (BD_SC_BR)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (status & BD_SC_PR) + flag = TTY_PARITY; + else if (status & BD_SC_FR) + flag = TTY_FRAME; + } + tty_insert_flip_char(tty, ch, flag); + if (status & BD_SC_OV) + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + /* This BD is ready to be used again. Clear status. + * Get next BD. + */ + bdp->status |= BD_SC_EMPTY; + bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); + + if (bdp->status & BD_SC_WRAP) + bdp = info->rx_bd_base; + else + bdp++; + } + + info->rx_cur = (QUICC_BD *)bdp; + + tty_schedule_flip(tty); +} + +static _INLINE_ void receive_break(ser_info_t *info) +{ + struct tty_struct *tty = info->port.tty; + + info->state->icount.brk++; + /* Check to see if there is room in the tty buffer for + * the break. If not, we exit now, losing the break. FIXME + */ + tty_insert_flip_char(tty, 0, TTY_BREAK); + tty_schedule_flip(tty); +} + +static _INLINE_ void transmit_chars(ser_info_t *info) +{ + + if ((info->flags & TX_WAKEUP) || + (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) { + schedule_work(&info->tqueue); + } + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif +} + +#ifdef notdef + /* I need to do this for the SCCs, so it is left as a reminder. + */ +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + int status; + /* struct async_icount *icount; */ + struct async_icount_24 *icount; + + status = serial_in(info, UART_MSR); + + if (status & UART_MSR_ANY_DELTA) { + icount = &info->state->icount; + /* update input line counters */ + if (status & UART_MSR_TERI) + icount->rng++; + if (status & UART_MSR_DDSR) + icount->dsr++; + if (status & UART_MSR_DDCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & UART_MSR_DCD)) + hardpps(); +#endif + } + if (status & UART_MSR_DCTS) + icount->cts++; + wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) + wake_up_interruptible(&info->open_wait); + else { +#ifdef SERIAL_DEBUG_OPEN + printk("scheduling hangup..."); +#endif + queue_task(&info->tqueue_hangup, + &tq_scheduler); + } + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->port.tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->port.tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!(status & UART_MSR_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->port.tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + } + } +} +#endif + +/* + * This is the serial driver's interrupt routine for a single port + */ +/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */ +static void rs_360_interrupt(int vec, void *dev_id) +{ + u_char events; + int idx; + ser_info_t *info; + volatile struct smc_regs *smcp; + volatile struct scc_regs *sccp; + + info = dev_id; + + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + events = sccp->scc_scce; + if (events & SCCM_RX) + receive_chars(info); + if (events & SCCM_TX) + transmit_chars(info); + sccp->scc_scce = events; + } else { + smcp = &pquicc->smc_regs[idx]; + events = smcp->smc_smce; + if (events & SMCM_BRKE) + receive_break(info); + if (events & SMCM_RX) + receive_chars(info); + if (events & SMCM_TX) + transmit_chars(info); + smcp->smc_smce = events; + } + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d, %x)...", + info->state->smc_scc_num, events); +#endif +#ifdef modem_control + check_modem_status(info); +#endif + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + + +static void do_softint(void *private_) +{ + ser_info_t *info = (ser_info_t *) private_; + struct tty_struct *tty; + + tty = info->port.tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); +} + + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->port.tty; + if (!tty) + return; + + tty_hangup(tty); +} + + +static int startup(ser_info_t *info) +{ + unsigned long flags; + int retval=0; + int idx; + /*struct serial_state *state = info->state;*/ + volatile struct smc_regs *smcp; + volatile struct scc_regs *sccp; + volatile struct smc_uart_pram *up; + volatile struct uart_pram *scup; + + + local_irq_save(flags); + + if (info->flags & ASYNC_INITIALIZED) { + goto errout; + } + +#ifdef maybe + if (!state->port || !state->type) { + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + goto errout; + } +#endif + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + +#ifdef modem_control + info->MCR = 0; + if (info->port.tty->termios->c_cflag & CBAUD) + info->MCR = UART_MCR_DTR | UART_MCR_RTS; +#endif + + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + + /* + * and set the speed of the serial port + */ + change_speed(info); + + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + scup = &pquicc->pram[info->state->port].scc.pscc.u; + + scup->mrblr = RX_BUF_SIZE; + scup->max_idl = RX_BUF_SIZE; + + sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + } else { + smcp = &pquicc->smc_regs[idx]; + + /* Enable interrupts and I/O. + */ + smcp->smc_smcm |= (SMCM_RX | SMCM_TX); + smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); + + /* We can tune the buffer length and idle characters + * to take advantage of the entire incoming buffer size. + * If mrblr is something other than 1, maxidl has to be + * non-zero or we never get an interrupt. The maxidl + * is the number of character times we wait after reception + * of the last character before we decide no more characters + * are coming. + */ + /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */ + /* holy unionized structures, Batman: */ + up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; + + up->mrblr = RX_BUF_SIZE; + up->max_idl = RX_BUF_SIZE; + + up->brkcr = 1; /* number of break chars */ + } + + info->flags |= ASYNC_INITIALIZED; + local_irq_restore(flags); + return 0; + +errout: + local_irq_restore(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(ser_info_t *info) +{ + unsigned long flags; + struct serial_state *state; + int idx; + volatile struct smc_regs *smcp; + volatile struct scc_regs *sccp; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + local_irq_save(flags); + + idx = PORT_NUM(state->smc_scc_num); + if (state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#ifdef CONFIG_SERIAL_CONSOLE + /* We can't disable the transmitter if this is the + * system console. + */ + if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) +#endif + sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + } else { + smcp = &pquicc->smc_regs[idx]; + + /* Disable interrupts and I/O. + */ + smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); +#ifdef CONFIG_SERIAL_CONSOLE + /* We can't disable the transmitter if this is the + * system console. + */ + if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) +#endif + smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + } + + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + local_irq_restore(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(ser_info_t *info) +{ + int baud_rate; + unsigned cflag, cval, scval, prev_mode; + int i, bits, sbits, idx; + unsigned long flags; + struct serial_state *state; + volatile struct smc_regs *smcp; + volatile struct scc_regs *sccp; + + if (!info->port.tty || !info->port.tty->termios) + return; + cflag = info->port.tty->termios->c_cflag; + + state = info->state; + + /* Character length programmed into the mode register is the + * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, + * 1 or 2 stop bits, minus 1. + * The value 'bits' counts this for us. + */ + cval = 0; + scval = 0; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: bits = 5; break; + case CS6: bits = 6; break; + case CS7: bits = 7; break; + case CS8: bits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: bits = 8; break; + } + sbits = bits - 5; + + if (cflag & CSTOPB) { + cval |= SMCMR_SL; /* Two stops */ + scval |= SCU_PMSR_SL; + bits++; + } + if (cflag & PARENB) { + cval |= SMCMR_PEN; + scval |= SCU_PMSR_PEN; + bits++; + } + if (!(cflag & PARODD)) { + cval |= SMCMR_PM_EVEN; + scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); + } + + /* Determine divisor based on baud rate */ + i = cflag & CBAUD; + if (i >= (sizeof(baud_table)/sizeof(int))) + baud_rate = 9600; + else + baud_rate = baud_table[i]; + + info->timeout = (TX_BUF_SIZE*HZ*bits); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + +#ifdef modem_control + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + if (info->flags & ASYNC_HARDPPS_CD) + info->IER |= UART_IER_MSI; + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + serial_out(info, UART_IER, info->IER); +#endif + + /* + * Set up parity check flag + */ + info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); + if (I_INPCK(info->port.tty)) + info->read_status_mask |= BD_SC_FR | BD_SC_PR; + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) + info->read_status_mask |= BD_SC_BR; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->port.tty)) + info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; + if (I_IGNBRK(info->port.tty)) { + info->ignore_status_mask |= BD_SC_BR; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->port.tty)) + info->ignore_status_mask |= BD_SC_OV; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->read_status_mask &= ~BD_SC_EMPTY; + local_irq_save(flags); + + /* Start bit has not been added (so don't, because we would just + * subtract it later), and we need to add one for the number of + * stops bits (there is always at least one). + */ + bits++; + idx = PORT_NUM(state->smc_scc_num); + if (state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + sccp->scc_psmr = (sbits << 12) | scval; + } else { + smcp = &pquicc->smc_regs[idx]; + + /* Set the mode register. We want to keep a copy of the + * enables, because we want to put them back if they were + * present. + */ + prev_mode = smcp->smc_smcmr; + smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; + smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); + } + + m360_cpm_setbrg((state - rs_table), baud_rate); + + local_irq_restore(flags); +} + +static void rs_360_put_char(struct tty_struct *tty, unsigned char ch) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + volatile QUICC_BD *bdp; + + if (serial_paranoia_check(info, tty->name, "rs_put_char")) + return 0; + + if (!tty) + return 0; + + bdp = info->tx_cur; + while (bdp->status & BD_SC_READY); + + /* *((char *)__va(bdp->buf)) = ch; */ + *((char *)bdp->buf) = ch; + bdp->length = 1; + bdp->status |= BD_SC_READY; + + /* Get next BD. + */ + if (bdp->status & BD_SC_WRAP) + bdp = info->tx_bd_base; + else + bdp++; + + info->tx_cur = (QUICC_BD *)bdp; + return 1; + +} + +static int rs_360_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + int c, ret = 0; + ser_info_t *info = (ser_info_t *)tty->driver_data; + volatile QUICC_BD *bdp; + +#ifdef CONFIG_KGDB + /* Try to let stub handle output. Returns true if it did. */ + if (kgdb_output_string(buf, count)) + return ret; +#endif + + if (serial_paranoia_check(info, tty->name, "rs_write")) + return 0; + + if (!tty) + return 0; + + bdp = info->tx_cur; + + while (1) { + c = min(count, TX_BUF_SIZE); + + if (c <= 0) + break; + + if (bdp->status & BD_SC_READY) { + info->flags |= TX_WAKEUP; + break; + } + + /* memcpy(__va(bdp->buf), buf, c); */ + memcpy((void *)bdp->buf, buf, c); + + bdp->length = c; + bdp->status |= BD_SC_READY; + + buf += c; + count -= c; + ret += c; + + /* Get next BD. + */ + if (bdp->status & BD_SC_WRAP) + bdp = info->tx_bd_base; + else + bdp++; + info->tx_cur = (QUICC_BD *)bdp; + } + return ret; +} + +static int rs_360_write_room(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->name, "rs_write_room")) + return 0; + + if ((info->tx_cur->status & BD_SC_READY) == 0) { + info->flags &= ~TX_WAKEUP; + ret = TX_BUF_SIZE; + } + else { + info->flags |= TX_WAKEUP; + ret = 0; + } + return ret; +} + +/* I could track this with transmit counters....maybe later. +*/ +static int rs_360_chars_in_buffer(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) + return 0; + return 0; +} + +static void rs_360_flush_buffer(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) + return; + + /* There is nothing to "flush", whatever we gave the CPM + * is on its way out. + */ + tty_wakeup(tty); + info->flags &= ~TX_WAKEUP; +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_360_send_xchar(struct tty_struct *tty, char ch) +{ + volatile QUICC_BD *bdp; + + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "rs_send_char")) + return; + + bdp = info->tx_cur; + while (bdp->status & BD_SC_READY); + + /* *((char *)__va(bdp->buf)) = ch; */ + *((char *)bdp->buf) = ch; + bdp->length = 1; + bdp->status |= BD_SC_READY; + + /* Get next BD. + */ + if (bdp->status & BD_SC_WRAP) + bdp = info->tx_bd_base; + else + bdp++; + + info->tx_cur = (QUICC_BD *)bdp; +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_360_throttle(struct tty_struct * tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->name, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_360_send_xchar(tty, STOP_CHAR(tty)); + +#ifdef modem_control + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~UART_MCR_RTS; + + local_irq_disable(); + serial_out(info, UART_MCR, info->MCR); + local_irq_enable(); +#endif +} + +static void rs_360_unthrottle(struct tty_struct * tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_360_send_xchar(tty, START_CHAR(tty)); + } +#ifdef modem_control + if (tty->termios->c_cflag & CRTSCTS) + info->MCR |= UART_MCR_RTS; + local_irq_disable(); + serial_out(info, UART_MCR, info->MCR); + local_irq_enable(); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +#ifdef maybe +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + + local_irq_disable(); + status = serial_in(info, UART_LSR); + local_irq_enable(); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + return put_user(result,value); +} +#endif + +static int rs_360_tiocmget(struct tty_struct *tty, struct file *file) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + unsigned int result = 0; +#ifdef modem_control + unsigned char control, status; + + if (serial_paranoia_check(info, tty->name, __func__)) + return -ENODEV; + + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + + control = info->MCR; + local_irq_disable(); + status = serial_in(info, UART_MSR); + local_irq_enable(); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) +#ifdef TIOCM_OUT1 + | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) + | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) +#endif + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); +#endif + return result; +} + +static int rs_360_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ +#ifdef modem_control + ser_info_t *info = (ser_info_t *)tty->driver_data; + unsigned int arg; + + if (serial_paranoia_check(info, tty->name, __func__)) + return -ENODEV; + + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + /* FIXME: locking on info->mcr */ + if (set & TIOCM_RTS) + info->mcr |= UART_MCR_RTS; + if (set & TIOCM_DTR) + info->mcr |= UART_MCR_DTR; + if (clear & TIOCM_RTS) + info->MCR &= ~UART_MCR_RTS; + if (clear & TIOCM_DTR) + info->MCR &= ~UART_MCR_DTR; + +#ifdef TIOCM_OUT1 + if (set & TIOCM_OUT1) + info->MCR |= UART_MCR_OUT1; + if (set & TIOCM_OUT2) + info->MCR |= UART_MCR_OUT2; + if (clear & TIOCM_OUT1) + info->MCR &= ~UART_MCR_OUT1; + if (clear & TIOCM_OUT2) + info->MCR &= ~UART_MCR_OUT2; +#endif + + local_irq_disable(); + serial_out(info, UART_MCR, info->MCR); + local_irq_enable(); +#endif + return 0; +} + +/* Sending a break is a two step process on the SMC/SCC. It is accomplished + * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT + * command. We take advantage of the begin/end functions to make this + * happen. + */ +static ushort smc_chan_map[] = { + CPM_CR_CH_SMC1, + CPM_CR_CH_SMC2 +}; + +static ushort scc_chan_map[] = { + CPM_CR_CH_SCC1, + CPM_CR_CH_SCC2, + CPM_CR_CH_SCC3, + CPM_CR_CH_SCC4 +}; + +static void begin_break(ser_info_t *info) +{ + volatile QUICC *cp; + ushort chan; + int idx; + + cp = pquicc; + + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) + chan = scc_chan_map[idx]; + else + chan = smc_chan_map[idx]; + + cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); +} + +static void end_break(ser_info_t *info) +{ + volatile QUICC *cp; + ushort chan; + int idx; + + cp = pquicc; + + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) + chan = scc_chan_map[idx]; + else + chan = smc_chan_map[idx]; + + cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break(ser_info_t *info, unsigned int duration) +{ +#ifdef SERIAL_DEBUG_SEND_BREAK + printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); +#endif + begin_break(info); + msleep_interruptible(duration); + end_break(info); +#ifdef SERIAL_DEBUG_SEND_BREAK + printk("done jiffies=%lu\n", jiffies); +#endif +} + + +/* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ +static int rs_360_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + struct async_icount cnow; + + local_irq_disable(); + cnow = info->state->icount; + local_irq_enable(); + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + + return 0; +} + +static int rs_360_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + ser_info_t *info = (ser_info_t *)tty->driver_data; + int retval; + struct async_icount cnow; + /* struct async_icount_24 cnow;*/ /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + + if (serial_paranoia_check(info, tty->name, "rs_ioctl")) + return -ENODEV; + + if (cmd != TIOCMIWAIT) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + if (!arg) { + send_break(info, 250); /* 1/4 second */ + if (signal_pending(current)) + return -EINTR; + } + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + send_break(info, arg ? arg*100 : 250); + if (signal_pending(current)) + return -EINTR; + return 0; + case TIOCSBRK: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + begin_break(info); + return 0; + case TIOCCBRK: + retval = tty_check_change(tty); + if (retval) + return retval; + end_break(info); + return 0; +#ifdef maybe + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); +#endif + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: +#ifdef modem_control + local_irq_disable(); + /* note the counters on entry */ + cprev = info->state->icount; + local_irq_enable(); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + local_irq_disable(); + cnow = info->state->icount; /* atomic copy */ + local_irq_enable(); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ +#else + return 0; +#endif + + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* FIX UP modem control here someday...... +*/ +static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + + change_speed(info); + +#ifdef modem_control + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(tty->termios->c_cflag & CBAUD)) { + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + local_irq_disable(); + serial_out(info, UART_MCR, info->MCR); + local_irq_enable(); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (tty->termios->c_cflag & CBAUD)) { + info->MCR |= UART_MCR_DTR; + if (!tty->hw_stopped || + !(tty->termios->c_cflag & CRTSCTS)) { + info->MCR |= UART_MCR_RTS; + } + local_irq_disable(); + serial_out(info, UART_MCR, info->MCR); + local_irq_enable(); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_360_start(tty); + } +#endif + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_360_close(struct tty_struct *tty, struct file * filp) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + /* struct async_state *state; */ + struct serial_state *state; + unsigned long flags; + int idx; + volatile struct smc_regs *smcp; + volatile struct scc_regs *sccp; + + if (!info || serial_paranoia_check(info, tty->name, "rs_close")) + return; + + state = info->state; + + local_irq_save(flags); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + local_irq_restore(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->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. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + DBG_CNT("before DEC-2"); + local_irq_restore(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * 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 (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~BD_SC_EMPTY; + if (info->flags & ASYNC_INITIALIZED) { + + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) { + sccp = &pquicc->scc_regs[idx]; + sccp->scc_sccm &= ~UART_SCCM_RX; + sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR; + } else { + smcp = &pquicc->smc_regs[idx]; + smcp->smc_smcm &= ~SMCM_RX; + smcp->smc_smcmr &= ~SMCMR_REN; + } + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_360_wait_until_sent(tty, info->timeout); + } + shutdown(info); + rs_360_flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->port.tty = NULL; + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs(info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + local_irq_restore(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + unsigned long orig_jiffies, char_time; + /*int lsr;*/ + volatile QUICC_BD *bdp; + + if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) + return; + +#ifdef maybe + if (info->state->type == PORT_UNKNOWN) + return; +#endif + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = 1; + if (timeout) + char_time = min(char_time, (unsigned long)timeout); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + + /* We go through the loop at least once because we can't tell + * exactly when the last character exits the shifter. There can + * be at least two characters waiting to be sent after the buffers + * are empty. + */ + do { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif +/* current->counter = 0; make us low-priority */ + msleep_interruptible(jiffies_to_msecs(char_time)); + if (signal_pending(current)) + break; + if (timeout && (time_after(jiffies, orig_jiffies + timeout))) + break; + /* The 'tx_cur' is really the next buffer to send. We + * have to back up to the previous BD and wait for it + * to go. This isn't perfect, because all this indicates + * is the buffer is available. There are still characters + * in the CPM FIFO. + */ + bdp = info->tx_cur; + if (bdp == info->tx_bd_base) + bdp += (TX_NUM_FIFO-1); + else + bdp--; + } while (bdp->status & BD_SC_READY); + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_360_hangup(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->name, "rs_hangup")) + return; + + state = info->state; + + rs_360_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + ser_info_t *info) +{ +#ifdef DO_THIS_LATER + DECLARE_WAITQUEUE(wait, current); +#endif + struct serial_state *state = info->state; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + * If this is an SMC port, we don't have modem control to wait + * for, so just get out here. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR)) || + !(info->state->smc_scc_num & NUM_IS_SCC)) { + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; +#ifdef DO_THIS_LATER + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + local_irq_disable(); + if (!tty_hung_up_p(filp)) + state->count--; + local_irq_enable(); + info->blocked_open++; + while (1) { + local_irq_disable(); + if (tty->termios->c_cflag & CBAUD) + serial_out(info, UART_MCR, + serial_inp(info, UART_MCR) | + (UART_MCR_DTR | UART_MCR_RTS)); + local_irq_enable(); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, UART_MSR) & + UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + tty_unlock(); + schedule(); + tty_lock(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif +#endif /* DO_THIS_LATER */ + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, ser_info_t **ret_info) +{ + struct serial_state *sstate; + + sstate = rs_table + line; + if (sstate->info) { + sstate->count++; + *ret_info = (ser_info_t *)sstate->info; + return 0; + } + else { + return -ENOMEM; + } +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_360_open(struct tty_struct *tty, struct file * filp) +{ + ser_info_t *info; + int retval, line; + + line = tty->index; + if ((line < 0) || (line >= NR_PORTS)) + return -ENODEV; + retval = get_async_struct(line, &info); + if (retval) + return retval; + if (serial_paranoia_check(info, tty->name, "rs_open")) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s, count = %d\n", tty->name, info->state->count); +#endif + tty->driver_data = info; + info->port.tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s successful...", tty->name); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ +#ifdef notdef + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; +#endif + int ret; + + ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", + state->line, + (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC", + (unsigned int)(state->port), state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + +#ifdef notdef + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->port.tty = NULL; + } + local_irq_disable(); + status = serial_in(info, UART_MSR); + control = info ? info->MCR : serial_in(info, UART_MCR); + local_irq_enable(); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & UART_MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & UART_MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & UART_MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & UART_MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & UART_MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & UART_MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); +#endif + return ret; +} + +int rs_360_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + len += line_info(page + len, &rs_table[i]); + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); +} + + +/* + * The serial console driver used during boot. Note that these names + * clash with those found in "serial.c", so we currently can't support + * the 16xxx uarts and these at the same time. I will fix this to become + * an indirect function call from tty_io.c (or something). + */ + +#ifdef CONFIG_SERIAL_CONSOLE + +/* + * Print a string to the serial port trying not to disturb any possible + * real use of the port... + */ +static void my_console_write(int idx, const char *s, + unsigned count) +{ + struct serial_state *ser; + ser_info_t *info; + unsigned i; + QUICC_BD *bdp, *bdbase; + volatile struct smc_uart_pram *up; + volatile u_char *cp; + + ser = rs_table + idx; + + + /* If the port has been initialized for general use, we have + * to use the buffer descriptors allocated there. Otherwise, + * we simply use the single buffer allocated. + */ + if ((info = (ser_info_t *)ser->info) != NULL) { + bdp = info->tx_cur; + bdbase = info->tx_bd_base; + } + else { + /* Pointer to UART in parameter ram. + */ + /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ + up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; + + /* Get the address of the host memory buffer. + */ + bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); + } + + /* + * We need to gracefully shut down the transmitter, disable + * interrupts, then send our bytes out. + */ + + /* + * Now, do each character. This is not as bad as it looks + * since this is a holding FIFO and not a transmitting FIFO. + * We could add the complexity of filling the entire transmit + * buffer, but we would just wait longer between accesses...... + */ + for (i = 0; i < count; i++, s++) { + /* Wait for transmitter fifo to empty. + * Ready indicates output is ready, and xmt is doing + * that, not that it is ready for us to send. + */ + while (bdp->status & BD_SC_READY); + + /* Send the character out. + */ + cp = bdp->buf; + *cp = *s; + + bdp->length = 1; + bdp->status |= BD_SC_READY; + + if (bdp->status & BD_SC_WRAP) + bdp = bdbase; + else + bdp++; + + /* if a LF, also do CR... */ + if (*s == 10) { + while (bdp->status & BD_SC_READY); + /* cp = __va(bdp->buf); */ + cp = bdp->buf; + *cp = 13; + bdp->length = 1; + bdp->status |= BD_SC_READY; + + if (bdp->status & BD_SC_WRAP) { + bdp = bdbase; + } + else { + bdp++; + } + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + while (bdp->status & BD_SC_READY); + + if (info) + info->tx_cur = (QUICC_BD *)bdp; +} + +static void serial_console_write(struct console *c, const char *s, + unsigned count) +{ +#ifdef CONFIG_KGDB + /* Try to let stub handle output. Returns true if it did. */ + if (kgdb_output_string(s, count)) + return; +#endif + my_console_write(c->index, s, count); +} + + + +/*void console_print_68360(const char *p) +{ + const char *cp = p; + int i; + + for (i=0;cp[i]!=0;i++); + + serial_console_write (p, i); + + //Comment this if you want to have a strict interrupt-driven output + //rs_fair_output(); + + return; +}*/ + + + + + + +#ifdef CONFIG_XMON +int +xmon_360_write(const char *s, unsigned count) +{ + my_console_write(0, s, count); + return(count); +} +#endif + +#ifdef CONFIG_KGDB +void +putDebugChar(char ch) +{ + my_console_write(0, &ch, 1); +} +#endif + +/* + * Receive character from the serial port. This only works well + * before the port is initialized for real use. + */ +static int my_console_wait_key(int idx, int xmon, char *obuf) +{ + struct serial_state *ser; + u_char c, *cp; + ser_info_t *info; + QUICC_BD *bdp; + volatile struct smc_uart_pram *up; + int i; + + ser = rs_table + idx; + + /* Get the address of the host memory buffer. + * If the port has been initialized for general use, we must + * use information from the port structure. + */ + if ((info = (ser_info_t *)ser->info)) + bdp = info->rx_cur; + else + /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */ + bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); + + /* Pointer to UART in parameter ram. + */ + /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ + up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; + + /* + * We need to gracefully shut down the receiver, disable + * interrupts, then read the input. + * XMON just wants a poll. If no character, return -1, else + * return the character. + */ + if (!xmon) { + while (bdp->status & BD_SC_EMPTY); + } + else { + if (bdp->status & BD_SC_EMPTY) + return -1; + } + + cp = (char *)bdp->buf; + + if (obuf) { + i = c = bdp->length; + while (i-- > 0) + *obuf++ = *cp++; + } + else { + c = *cp; + } + bdp->status |= BD_SC_EMPTY; + + if (info) { + if (bdp->status & BD_SC_WRAP) { + bdp = info->rx_bd_base; + } + else { + bdp++; + } + info->rx_cur = (QUICC_BD *)bdp; + } + + return((int)c); +} + +static int serial_console_wait_key(struct console *co) +{ + return(my_console_wait_key(co->index, 0, NULL)); +} + +#ifdef CONFIG_XMON +int +xmon_360_read_poll(void) +{ + return(my_console_wait_key(0, 1, NULL)); +} + +int +xmon_360_read_char(void) +{ + return(my_console_wait_key(0, 0, NULL)); +} +#endif + +#ifdef CONFIG_KGDB +static char kgdb_buf[RX_BUF_SIZE], *kgdp; +static int kgdb_chars; + +unsigned char +getDebugChar(void) +{ + if (kgdb_chars <= 0) { + kgdb_chars = my_console_wait_key(0, 0, kgdb_buf); + kgdp = kgdb_buf; + } + kgdb_chars--; + + return(*kgdp++); +} + +void kgdb_interruptible(int state) +{ +} +void kgdb_map_scc(void) +{ + struct serial_state *ser; + uint mem_addr; + volatile QUICC_BD *bdp; + volatile smc_uart_t *up; + + cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + + /* To avoid data cache CPM DMA coherency problems, allocate a + * buffer in the CPM DPRAM. This will work until the CPM and + * serial ports are initialized. At that time a memory buffer + * will be allocated. + * The port is already initialized from the boot procedure, all + * we do here is give it a different buffer and make it a FIFO. + */ + + ser = rs_table; + + /* Right now, assume we are using SMCs. + */ + up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; + + /* Allocate space for an input FIFO, plus a few bytes for output. + * Allocate bytes to maintain word alignment. + */ + mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; + bdp->buf = mem_addr; + + bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase]; + bdp->buf = mem_addr+RX_BUF_SIZE; + + up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */ + up->smc_maxidl = RX_BUF_SIZE; +} +#endif + +static struct tty_struct *serial_console_device(struct console *c, int *index) +{ + *index = c->index; + return serial_driver; +} + + +struct console sercons = { + .name = "ttyS", + .write = serial_console_write, + .device = serial_console_device, + .wait_key = serial_console_wait_key, + .setup = serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = CONFIG_SERIAL_CONSOLE_PORT, +}; + + + +/* + * Register console. + */ +long console_360_init(long kmem_start, long kmem_end) +{ + register_console(&sercons); + /*register_console (console_print_68360); - 2.0.38 only required a write + function pointer. */ + return kmem_start; +} + +#endif + +/* Index in baud rate table of the default console baud rate. +*/ +static int baud_idx; + +static const struct tty_operations rs_360_ops = { + .owner = THIS_MODULE, + .open = rs_360_open, + .close = rs_360_close, + .write = rs_360_write, + .put_char = rs_360_put_char, + .write_room = rs_360_write_room, + .chars_in_buffer = rs_360_chars_in_buffer, + .flush_buffer = rs_360_flush_buffer, + .ioctl = rs_360_ioctl, + .throttle = rs_360_throttle, + .unthrottle = rs_360_unthrottle, + /* .send_xchar = rs_360_send_xchar, */ + .set_termios = rs_360_set_termios, + .stop = rs_360_stop, + .start = rs_360_start, + .hangup = rs_360_hangup, + /* .wait_until_sent = rs_360_wait_until_sent, */ + /* .read_proc = rs_360_read_proc, */ + .tiocmget = rs_360_tiocmget, + .tiocmset = rs_360_tiocmset, +}; + +static int __init rs_360_init(void) +{ + struct serial_state * state; + ser_info_t *info; + void *mem_addr; + uint dp_addr, iobits; + int i, j, idx; + ushort chan; + QUICC_BD *bdp; + volatile QUICC *cp; + volatile struct smc_regs *sp; + volatile struct smc_uart_pram *up; + volatile struct scc_regs *scp; + volatile struct uart_pram *sup; + /* volatile immap_t *immap; */ + + serial_driver = alloc_tty_driver(NR_PORTS); + if (!serial_driver) + return -1; + + show_serial_version(); + + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + 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 = + baud_idx | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(serial_driver, &rs_360_ops); + + if (tty_register_driver(serial_driver)) + panic("Couldn't register serial driver\n"); + + cp = pquicc; /* Get pointer to Communication Processor */ + /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ + + + /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. + */ + /* The "standard" configuration through the 860. + */ +/* immap->im_ioport.iop_papar |= 0x00fc; */ +/* immap->im_ioport.iop_padir &= ~0x00fc; */ +/* immap->im_ioport.iop_paodr &= ~0x00fc; */ + cp->pio_papar |= 0x00fc; + cp->pio_padir &= ~0x00fc; + /* cp->pio_paodr &= ~0x00fc; */ + + + /* Since we don't yet do modem control, connect the port C pins + * as general purpose I/O. This will assert CTS and CD for the + * SCC ports. + */ + /* FIXME: see 360um p.7-365 and 860um p.34-12 + * I can't make sense of these bits - mleslie*/ +/* immap->im_ioport.iop_pcdir |= 0x03c6; */ +/* immap->im_ioport.iop_pcpar &= ~0x03c6; */ + +/* cp->pio_pcdir |= 0x03c6; */ +/* cp->pio_pcpar &= ~0x03c6; */ + + + + /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and + * BRG4 to SCC3. + */ + cp->si_sicr &= ~0x00ffff00; + cp->si_sicr |= 0x001b1200; + +#ifdef CONFIG_PP04 + /* Frequentis PP04 forced to RS-232 until we know better. + * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4. + */ + immap->im_ioport.iop_pcdir |= 0x000c; + immap->im_ioport.iop_pcpar &= ~0x000c; + immap->im_ioport.iop_pcdat &= ~0x000c; + + /* This enables the TX driver. + */ + cp->cp_pbpar &= ~0x6000; + cp->cp_pbdat &= ~0x6000; +#endif + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n", + i, (unsigned int)(state->irq), + (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC"); + +#ifdef CONFIG_SERIAL_CONSOLE + /* If we just printed the message on the console port, and + * we are about to initialize it for general use, we have + * to wait a couple of character times for the CR/NL to + * make it out of the transmit buffer. + */ + if (i == CONFIG_SERIAL_CONSOLE_PORT) + mdelay(8); + + +/* idx = PORT_NUM(info->state->smc_scc_num); */ +/* if (info->state->smc_scc_num & NUM_IS_SCC) */ +/* chan = scc_chan_map[idx]; */ +/* else */ +/* chan = smc_chan_map[idx]; */ + +/* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */ +/* while (cp->cp_cr & CPM_CR_FLG); */ + +#endif + /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */ + info = &quicc_ser_info[i]; + if (info) { + memset (info, 0, sizeof(ser_info_t)); + info->magic = SERIAL_MAGIC; + info->line = i; + info->flags = state->flags; + INIT_WORK(&info->tqueue, do_softint, info); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->state = state; + state->info = (struct async_struct *)info; + + /* We need to allocate a transmit and receive buffer + * descriptors from dual port ram, and a character + * buffer area from host mem. + */ + dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO); + + /* Allocate space for FIFOs in the host memory. + * (for now this is from a static array of buffers :( + */ + /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */ + /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */ + mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE]; + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + bdp = (QUICC_BD *)((uint)pquicc + dp_addr); + info->rx_cur = info->rx_bd_base = bdp; + + /* initialize rx buffer descriptors */ + for (j=0; j<(RX_NUM_FIFO-1); j++) { + bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; + bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; + mem_addr += RX_BUF_SIZE; + bdp++; + } + bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; + bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; + + + idx = PORT_NUM(info->state->smc_scc_num); + if (info->state->smc_scc_num & NUM_IS_SCC) { + +#if defined (CONFIG_UCQUICC) && 1 + /* set the transceiver mode to RS232 */ + sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */ + sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02); + *(uint *)_periph_base = sipex_mode_bits; + /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */ +#endif + } + + dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO); + + /* Allocate space for FIFOs in the host memory. + */ + /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */ + /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */ + mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE]; + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ + bdp = (QUICC_BD *)((uint)pquicc + dp_addr); + info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp; + + /* initialize tx buffer descriptors */ + for (j=0; j<(TX_NUM_FIFO-1); j++) { + bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; + bdp->status = BD_SC_INTRPT; + mem_addr += TX_BUF_SIZE; + bdp++; + } + bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; + bdp->status = (BD_SC_WRAP | BD_SC_INTRPT); + + if (info->state->smc_scc_num & NUM_IS_SCC) { + scp = &pquicc->scc_regs[idx]; + sup = &pquicc->pram[info->state->port].scc.pscc.u; + sup->rbase = dp_addr; + sup->tbase = dp_addr; + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->rfcr = SMC_EB; + sup->tfcr = SMC_EB; + + /* Set this to 1 for now, so we get single + * character interrupts. Using idle character + * time requires some additional tuning. + */ + sup->mrblr = 1; + sup->max_idl = 0; + sup->brkcr = 1; + sup->parec = 0; + sup->frmer = 0; + sup->nosec = 0; + sup->brkec = 0; + sup->uaddr1 = 0; + sup->uaddr2 = 0; + sup->toseq = 0; + { + int i; + for (i=0;i<8;i++) + sup->cc[i] = 0x8000; + } + sup->rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + chan = scc_chan_map[idx]; + + /* execute the INIT RX & TX PARAMS command for this channel. */ + cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + scp->scc_gsmr.w.high = 0; + scp->scc_gsmr.w.low = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + scp->scc_sccm = 0; + scp->scc_scce = 0xffff; + scp->scc_dsr = 0x7e7e; + scp->scc_psmr = 0x3000; + + /* If the port is the console, enable Rx and Tx. + */ +#ifdef CONFIG_SERIAL_CONSOLE + if (i == CONFIG_SERIAL_CONSOLE_PORT) + scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + } + else { + /* Configure SMCs Tx/Rx instead of port B + * parallel I/O. + */ + up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; + up->rbase = dp_addr; + + iobits = 0xc0 << (idx * 4); + cp->pip_pbpar |= iobits; + cp->pip_pbdir &= ~iobits; + cp->pip_pbodr &= ~iobits; + + + /* Connect the baud rate generator to the + * SMC based upon index in rs_table. Also + * make sure it is connected to NMSI. + */ + cp->si_simode &= ~(0xffff << (idx * 16)); + cp->si_simode |= (i << ((idx * 16) + 12)); + + up->tbase = dp_addr; + + /* Set up the uart parameters in the + * parameter ram. + */ + up->rfcr = SMC_EB; + up->tfcr = SMC_EB; + + /* Set this to 1 for now, so we get single + * character interrupts. Using idle character + * time requires some additional tuning. + */ + up->mrblr = 1; + up->max_idl = 0; + up->brkcr = 1; + + /* Send the CPM an initialize command. + */ + chan = smc_chan_map[idx]; + + cp->cp_cr = mk_cr_cmd(chan, + CPM_CR_INIT_TRX) | CPM_CR_FLG; +#ifdef CONFIG_SERIAL_CONSOLE + if (i == CONFIG_SERIAL_CONSOLE_PORT) + printk(""); +#endif + while (cp->cp_cr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp = &cp->smc_regs[idx]; + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Disable all interrupts and clear all pending + * events. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* If the port is the console, enable Rx and Tx. + */ +#ifdef CONFIG_SERIAL_CONSOLE + if (i == CONFIG_SERIAL_CONSOLE_PORT) + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +#endif + } + + /* Install interrupt handler. + */ + /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */ + /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */ + request_irq(state->irq, rs_360_interrupt, + IRQ_FLG_LOCK, "ttyS", (void *)info); + + /* Set up the baud rate generator. + */ + m360_cpm_setbrg(i, baud_table[baud_idx]); + + } + } + + return 0; +} +module_init(rs_360_init); + +/* This must always be called before the rs_360_init() function, otherwise + * it blows away the port control information. + */ +//static int __init serial_console_setup( struct console *co, char *options) +int serial_console_setup( struct console *co, char *options) +{ + struct serial_state *ser; + uint mem_addr, dp_addr, bidx, idx, iobits; + ushort chan; + QUICC_BD *bdp; + volatile QUICC *cp; + volatile struct smc_regs *sp; + volatile struct scc_regs *scp; + volatile struct smc_uart_pram *up; + volatile struct uart_pram *sup; + +/* mleslie TODO: + * add something to the 68k bootloader to store a desired initial console baud rate */ + +/* bd_t *bd; */ /* a board info struct used by EPPC-bug */ +/* bd = (bd_t *)__res; */ + + for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) + /* if (bd->bi_baudrate == baud_table[bidx]) */ + if (CONSOLE_BAUDRATE == baud_table[bidx]) + break; + + /* co->cflag = CREAD|CLOCAL|bidx|CS8; */ + baud_idx = bidx; + + ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; + + cp = pquicc; /* Get pointer to Communication Processor */ + + idx = PORT_NUM(ser->smc_scc_num); + if (ser->smc_scc_num & NUM_IS_SCC) { + + /* TODO: need to set up SCC pin assignment etc. here */ + + } + else { + iobits = 0xc0 << (idx * 4); + cp->pip_pbpar |= iobits; + cp->pip_pbdir &= ~iobits; + cp->pip_pbodr &= ~iobits; + + /* Connect the baud rate generator to the + * SMC based upon index in rs_table. Also + * make sure it is connected to NMSI. + */ + cp->si_simode &= ~(0xffff << (idx * 16)); + cp->si_simode |= (idx << ((idx * 16) + 12)); + } + + /* When we get here, the CPM has been reset, so we need + * to configure the port. + * We need to allocate a transmit and receive buffer descriptor + * from dual port ram, and a character buffer area from host mem. + */ + + /* Allocate space for two buffer descriptors in the DP ram. + */ + dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO); + + /* Allocate space for two 2 byte FIFOs in the host memory. + */ + /* mem_addr = m360_cpm_hostalloc(8); */ + mem_addr = (uint)console_fifos; + + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ + bdp = (QUICC_BD *)((uint)pquicc + dp_addr); + bdp->buf = (char *)mem_addr; + (bdp+1)->buf = (char *)(mem_addr+4); + + /* For the receive, set empty and wrap. + * For transmit, set wrap. + */ + bdp->status = BD_SC_EMPTY | BD_SC_WRAP; + (bdp+1)->status = BD_SC_WRAP; + + /* Set up the uart parameters in the parameter ram. + */ + if (ser->smc_scc_num & NUM_IS_SCC) { + scp = &cp->scc_regs[idx]; + /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */ + sup = &pquicc->pram[ser->port].scc.pscc.u; + + sup->rbase = dp_addr; + sup->tbase = dp_addr + sizeof(QUICC_BD); + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->rfcr = SMC_EB; + sup->tfcr = SMC_EB; + + /* Set this to 1 for now, so we get single + * character interrupts. Using idle character + * time requires some additional tuning. + */ + sup->mrblr = 1; + sup->max_idl = 0; + sup->brkcr = 1; + sup->parec = 0; + sup->frmer = 0; + sup->nosec = 0; + sup->brkec = 0; + sup->uaddr1 = 0; + sup->uaddr2 = 0; + sup->toseq = 0; + { + int i; + for (i=0;i<8;i++) + sup->cc[i] = 0x8000; + } + sup->rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + chan = scc_chan_map[idx]; + + cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + scp->scc_gsmr.w.high = 0; + scp->scc_gsmr.w.low = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + scp->scc_sccm = 0; + scp->scc_scce = 0xffff; + scp->scc_dsr = 0x7e7e; + scp->scc_psmr = 0x3000; + + scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + } + else { + /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */ + up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; + + up->rbase = dp_addr; /* Base of receive buffer desc. */ + up->tbase = dp_addr+sizeof(QUICC_BD); /* Base of xmt buffer desc. */ + up->rfcr = SMC_EB; + up->tfcr = SMC_EB; + + /* Set this to 1 for now, so we get single character interrupts. + */ + up->mrblr = 1; /* receive buffer length */ + up->max_idl = 0; /* wait forever for next char */ + + /* Send the CPM an initialize command. + */ + chan = smc_chan_map[idx]; + cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp = &cp->smc_regs[idx]; + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* And finally, enable Rx and Tx. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; + } + + /* Set up the baud rate generator. + */ + /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */ + m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE); + + return 0; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c new file mode 100644 index 000000000000..b25e6e490530 --- /dev/null +++ b/drivers/tty/serial/8250.c @@ -0,0 +1,3377 @@ +/* + * linux/drivers/char/8250.c + * + * Driver for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King. + * + * 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. + * + * A note about mapbase / membase + * + * mapbase is the physical address of the IO port. + * membase is an 'ioremapped' cookie. + */ + +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "8250.h" + +#ifdef CONFIG_SPARC +#include "suncore.h" +#endif + +/* + * Configuration: + * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option + * is unsafe when used on edge-triggered interrupts. + */ +static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; + +static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; + +static struct uart_driver serial8250_reg; + +static int serial_index(struct uart_port *port) +{ + return (serial8250_reg.minor - 64) + port->line; +} + +static unsigned int skip_txen_test; /* force skip of txen test at init time */ + +/* + * Debugging. + */ +#if 0 +#define DEBUG_AUTOCONF(fmt...) printk(fmt) +#else +#define DEBUG_AUTOCONF(fmt...) do { } while (0) +#endif + +#if 0 +#define DEBUG_INTR(fmt...) printk(fmt) +#else +#define DEBUG_INTR(fmt...) do { } while (0) +#endif + +#define PASS_LIMIT 256 + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + + +/* + * We default to IRQ0 for the "no irq" hack. Some + * machine types want others as well - they're free + * to redefine this in their header file. + */ +#define is_real_interrupt(irq) ((irq) != 0) + +#ifdef CONFIG_SERIAL_8250_DETECT_IRQ +#define CONFIG_SERIAL_DETECT_IRQ 1 +#endif +#ifdef CONFIG_SERIAL_8250_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS 1 +#endif + +/* + * HUB6 is always on. This will be removed once the header + * files have been cleaned. + */ +#define CONFIG_HUB6 1 + +#include +/* + * SERIAL_PORT_DFNS tells us about built-in ports that have no + * standard enumeration mechanism. Platforms that can find all + * serial ports via mechanisms like ACPI or PCI need not supply it. + */ +#ifndef SERIAL_PORT_DFNS +#define SERIAL_PORT_DFNS +#endif + +static const struct old_serial_port old_serial_port[] = { + SERIAL_PORT_DFNS /* defined in asm/serial.h */ +}; + +#define UART_NR CONFIG_SERIAL_8250_NR_UARTS + +#ifdef CONFIG_SERIAL_8250_RSA + +#define PORT_RSA_MAX 4 +static unsigned long probe_rsa[PORT_RSA_MAX]; +static unsigned int probe_rsa_count; +#endif /* CONFIG_SERIAL_8250_RSA */ + +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; +}; + +struct irq_info { + struct hlist_node node; + int irq; + spinlock_t lock; /* Protects list not the hash */ + struct list_head *head; +}; + +#define NR_IRQ_HASH 32 /* Can be adjusted later */ +static struct hlist_head irq_lists[NR_IRQ_HASH]; +static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ + +/* + * Here we define the default xmit fifo size used for each type of UART. + */ +static const struct serial8250_config uart_config[] = { + [PORT_UNKNOWN] = { + .name = "unknown", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_8250] = { + .name = "8250", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16450] = { + .name = "16450", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550] = { + .name = "16550", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550A] = { + .name = "16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_CIRRUS] = { + .name = "Cirrus", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16650] = { + .name = "ST16650", + .fifo_size = 1, + .tx_loadsz = 1, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16650V2] = { + .name = "ST16650V2", + .fifo_size = 32, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16750] = { + .name = "TI16750", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR7_64BYTE, + .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, + }, + [PORT_STARTECH] = { + .name = "Startech", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16C950] = { + .name = "16C950/954", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16654] = { + .name = "ST16654", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16850] = { + .name = "XR16850", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_RSA] = { + .name = "RSA", + .fifo_size = 2048, + .tx_loadsz = 2048, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, + .flags = UART_CAP_FIFO, + }, + [PORT_NS16550A] = { + .name = "NS16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_NATSEMI, + }, + [PORT_XSCALE] = { + .name = "XScale", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_UUE, + }, + [PORT_RM9000] = { + .name = "RM9000", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_OCTEON] = { + .name = "OCTEON", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_AR7] = { + .name = "AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_U6_16550A] = { + .name = "U6_16550A", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, +}; + +#if defined(CONFIG_MIPS_ALCHEMY) + +/* Au1x00 UART hardware has a weird register layout */ +static const u8 au_io_in_map[] = { + [UART_RX] = 0, + [UART_IER] = 2, + [UART_IIR] = 3, + [UART_LCR] = 5, + [UART_MCR] = 6, + [UART_LSR] = 7, + [UART_MSR] = 8, +}; + +static const u8 au_io_out_map[] = { + [UART_TX] = 1, + [UART_IER] = 2, + [UART_FCR] = 4, + [UART_LCR] = 5, + [UART_MCR] = 6, +}; + +/* sane hardware needs no mapping */ +static inline int map_8250_in_reg(struct uart_port *p, int offset) +{ + if (p->iotype != UPIO_AU) + return offset; + return au_io_in_map[offset]; +} + +static inline int map_8250_out_reg(struct uart_port *p, int offset) +{ + if (p->iotype != UPIO_AU) + return offset; + return au_io_out_map[offset]; +} + +#elif defined(CONFIG_SERIAL_8250_RM9K) + +static const u8 + regmap_in[8] = { + [UART_RX] = 0x00, + [UART_IER] = 0x0c, + [UART_IIR] = 0x14, + [UART_LCR] = 0x1c, + [UART_MCR] = 0x20, + [UART_LSR] = 0x24, + [UART_MSR] = 0x28, + [UART_SCR] = 0x2c + }, + regmap_out[8] = { + [UART_TX] = 0x04, + [UART_IER] = 0x0c, + [UART_FCR] = 0x18, + [UART_LCR] = 0x1c, + [UART_MCR] = 0x20, + [UART_LSR] = 0x24, + [UART_MSR] = 0x28, + [UART_SCR] = 0x2c + }; + +static inline int map_8250_in_reg(struct uart_port *p, int offset) +{ + if (p->iotype != UPIO_RM9000) + return offset; + return regmap_in[offset]; +} + +static inline int map_8250_out_reg(struct uart_port *p, int offset) +{ + if (p->iotype != UPIO_RM9000) + return offset; + return regmap_out[offset]; +} + +#else + +/* sane hardware needs no mapping */ +#define map_8250_in_reg(up, offset) (offset) +#define map_8250_out_reg(up, offset) (offset) + +#endif + +static unsigned int hub6_serial_in(struct uart_port *p, int offset) +{ + offset = map_8250_in_reg(p, offset) << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + return inb(p->iobase + 1); +} + +static void hub6_serial_out(struct uart_port *p, int offset, int value) +{ + offset = map_8250_out_reg(p, offset) << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + outb(value, p->iobase + 1); +} + +static unsigned int mem_serial_in(struct uart_port *p, int offset) +{ + offset = map_8250_in_reg(p, offset) << p->regshift; + return readb(p->membase + offset); +} + +static void mem_serial_out(struct uart_port *p, int offset, int value) +{ + offset = map_8250_out_reg(p, offset) << p->regshift; + writeb(value, p->membase + offset); +} + +static void mem32_serial_out(struct uart_port *p, int offset, int value) +{ + offset = map_8250_out_reg(p, offset) << p->regshift; + writel(value, p->membase + offset); +} + +static unsigned int mem32_serial_in(struct uart_port *p, int offset) +{ + offset = map_8250_in_reg(p, offset) << p->regshift; + return readl(p->membase + offset); +} + +static unsigned int au_serial_in(struct uart_port *p, int offset) +{ + offset = map_8250_in_reg(p, offset) << p->regshift; + return __raw_readl(p->membase + offset); +} + +static void au_serial_out(struct uart_port *p, int offset, int value) +{ + offset = map_8250_out_reg(p, offset) << p->regshift; + __raw_writel(value, p->membase + offset); +} + +static unsigned int tsi_serial_in(struct uart_port *p, int offset) +{ + unsigned int tmp; + offset = map_8250_in_reg(p, offset) << p->regshift; + if (offset == UART_IIR) { + tmp = readl(p->membase + (UART_IIR & ~3)); + return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */ + } else + return readb(p->membase + offset); +} + +static void tsi_serial_out(struct uart_port *p, int offset, int value) +{ + offset = map_8250_out_reg(p, offset) << p->regshift; + if (!((offset == UART_IER) && (value & UART_IER_UUE))) + writeb(value, p->membase + offset); +} + +/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ +static inline void dwapb_save_out_value(struct uart_port *p, int offset, + int value) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + + if (offset == UART_LCR) + up->lcr = value; +} + +/* Read the IER to ensure any interrupt is cleared before returning from ISR. */ +static inline void dwapb_check_clear_ier(struct uart_port *p, int offset) +{ + if (offset == UART_TX || offset == UART_IER) + p->serial_in(p, UART_IER); +} + +static void dwapb_serial_out(struct uart_port *p, int offset, int value) +{ + int save_offset = offset; + offset = map_8250_out_reg(p, offset) << p->regshift; + dwapb_save_out_value(p, save_offset, value); + writeb(value, p->membase + offset); + dwapb_check_clear_ier(p, save_offset); +} + +static void dwapb32_serial_out(struct uart_port *p, int offset, int value) +{ + int save_offset = offset; + offset = map_8250_out_reg(p, offset) << p->regshift; + dwapb_save_out_value(p, save_offset, value); + writel(value, p->membase + offset); + dwapb_check_clear_ier(p, save_offset); +} + +static unsigned int io_serial_in(struct uart_port *p, int offset) +{ + offset = map_8250_in_reg(p, offset) << p->regshift; + return inb(p->iobase + offset); +} + +static void io_serial_out(struct uart_port *p, int offset, int value) +{ + offset = map_8250_out_reg(p, offset) << p->regshift; + outb(value, p->iobase + offset); +} + +static void set_io_from_upio(struct uart_port *p) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + switch (p->iotype) { + case UPIO_HUB6: + p->serial_in = hub6_serial_in; + p->serial_out = hub6_serial_out; + break; + + case UPIO_MEM: + p->serial_in = mem_serial_in; + p->serial_out = mem_serial_out; + break; + + case UPIO_RM9000: + case UPIO_MEM32: + p->serial_in = mem32_serial_in; + p->serial_out = mem32_serial_out; + break; + + case UPIO_AU: + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; + break; + + case UPIO_TSI: + p->serial_in = tsi_serial_in; + p->serial_out = tsi_serial_out; + break; + + case UPIO_DWAPB: + p->serial_in = mem_serial_in; + p->serial_out = dwapb_serial_out; + break; + + case UPIO_DWAPB32: + p->serial_in = mem32_serial_in; + p->serial_out = dwapb32_serial_out; + break; + + default: + p->serial_in = io_serial_in; + p->serial_out = io_serial_out; + break; + } + /* Remember loaded iotype */ + up->cur_iotype = p->iotype; +} + +static void +serial_out_sync(struct uart_8250_port *up, int offset, int value) +{ + struct uart_port *p = &up->port; + switch (p->iotype) { + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: + case UPIO_DWAPB: + case UPIO_DWAPB32: + p->serial_out(p, offset, value); + p->serial_in(p, UART_LCR); /* safe, no side-effects */ + break; + default: + p->serial_out(p, offset, value); + } +} + +#define serial_in(up, offset) \ + (up->port.serial_in(&(up)->port, (offset))) +#define serial_out(up, offset, value) \ + (up->port.serial_out(&(up)->port, (offset), (value))) +/* + * We used to support using pause I/O for certain machines. We + * haven't supported this for a while, but just in case it's badly + * needed for certain old 386 machines, I've left these #define's + * in.... + */ +#define serial_inp(up, offset) serial_in(up, offset) +#define serial_outp(up, offset, value) serial_out(up, offset, value) + +/* Uart divisor latch read */ +static inline int _serial_dl_read(struct uart_8250_port *up) +{ + return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static inline void _serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_outp(up, UART_DLL, value & 0xff); + serial_outp(up, UART_DLM, value >> 8 & 0xff); +} + +#if defined(CONFIG_MIPS_ALCHEMY) +/* Au1x00 haven't got a standard divisor latch */ +static int serial_dl_read(struct uart_8250_port *up) +{ + if (up->port.iotype == UPIO_AU) + return __raw_readl(up->port.membase + 0x28); + else + return _serial_dl_read(up); +} + +static void serial_dl_write(struct uart_8250_port *up, int value) +{ + if (up->port.iotype == UPIO_AU) + __raw_writel(value, up->port.membase + 0x28); + else + _serial_dl_write(up, value); +} +#elif defined(CONFIG_SERIAL_8250_RM9K) +static int serial_dl_read(struct uart_8250_port *up) +{ + return (up->port.iotype == UPIO_RM9000) ? + (((__raw_readl(up->port.membase + 0x10) << 8) | + (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : + _serial_dl_read(up); +} + +static void serial_dl_write(struct uart_8250_port *up, int value) +{ + if (up->port.iotype == UPIO_RM9000) { + __raw_writel(value, up->port.membase + 0x08); + __raw_writel(value >> 8, up->port.membase + 0x10); + } else { + _serial_dl_write(up, value); + } +} +#else +#define serial_dl_read(up) _serial_dl_read(up) +#define serial_dl_write(up, value) _serial_dl_write(up, value) +#endif + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} + +/* + * FIFO support. + */ +static void serial8250_clear_fifos(struct uart_8250_port *p) +{ + if (p->capabilities & UART_CAP_FIFO) { + serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(p, UART_FCR, 0); + } +} + +/* + * IER sleep support. UARTs which have EFRs need the "extended + * capability" bit enabled. Note that on XR16C850s, we need to + * reset LCR to write to IER. + */ +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +{ + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { + serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_outp(p, UART_EFR, UART_EFR_ECB); + serial_outp(p, UART_LCR, 0); + } + serial_outp(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_outp(p, UART_EFR, 0); + serial_outp(p, UART_LCR, 0); + } + } +} + +#ifdef CONFIG_SERIAL_8250_RSA +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __enable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + mode = serial_inp(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_inp(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +static void enable_rsa(struct uart_8250_port *up) +{ + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + __enable_rsa(up); + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_outp(up, UART_RSA_FRR, 0); + } +} + +/* + * Attempts to turn off the RSA FIFO. Returns zero on failure. + * It is unknown why interrupts were disabled in here. However, + * the caller is expected to preserve this behaviour by grabbing + * the spinlock before calling this function. + */ +static void disable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; + spin_unlock_irq(&up->port.lock); + } +} +#endif /* CONFIG_SERIAL_8250_RSA */ + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct uart_8250_port *up) +{ + unsigned char old_fcr, old_mcr, old_lcr; + unsigned short old_dl; + int count; + + old_lcr = serial_inp(up, UART_LCR); + serial_outp(up, UART_LCR, 0); + old_fcr = serial_inp(up, UART_FCR); + old_mcr = serial_inp(up, UART_MCR); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(up, UART_MCR, UART_MCR_LOOP); + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); + serial_outp(up, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_outp(up, UART_TX, count); + mdelay(20);/* FIXME - schedule_timeout */ + for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_inp(up, UART_RX); + serial_outp(up, UART_FCR, old_fcr); + serial_outp(up, UART_MCR, old_mcr); + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_dl_write(up, old_dl); + serial_outp(up, UART_LCR, old_lcr); + + return count; +} + +/* + * Read UART ID using the divisor method - set DLL and DLM to zero + * and the revision will be in DLL and device type in DLM. We + * preserve the device state across this. + */ +static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) +{ + unsigned char old_dll, old_dlm, old_lcr; + unsigned int id; + + old_lcr = serial_inp(p, UART_LCR); + serial_outp(p, UART_LCR, UART_LCR_CONF_MODE_A); + + old_dll = serial_inp(p, UART_DLL); + old_dlm = serial_inp(p, UART_DLM); + + serial_outp(p, UART_DLL, 0); + serial_outp(p, UART_DLM, 0); + + id = serial_inp(p, UART_DLL) | serial_inp(p, UART_DLM) << 8; + + serial_outp(p, UART_DLL, old_dll); + serial_outp(p, UART_DLM, old_dlm); + serial_outp(p, UART_LCR, old_lcr); + + return id; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_has_efr(struct uart_8250_port *up) +{ + unsigned int id1, id2, id3, rev; + + /* + * Everything with an EFR has SLEEP + */ + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + + /* + * Check for Oxford Semiconductor 16C950. + * + * EFR [4] must be set else this test fails. + * + * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) + * claims that it's needed for 952 dual UART's (which are not + * recommended for new designs). + */ + up->acr = 0; + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0x00); + id1 = serial_icr_read(up, UART_ID1); + id2 = serial_icr_read(up, UART_ID2); + id3 = serial_icr_read(up, UART_ID3); + rev = serial_icr_read(up, UART_REV); + + DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); + + if (id1 == 0x16 && id2 == 0xC9 && + (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { + up->port.type = PORT_16C950; + + /* + * Enable work around for the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + if (id3 == 0x52 && rev == 0x01) + up->bugs |= UART_BUG_QUOT; + return; + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and then + * reading back DLL and DLM. The chip type depends on the DLM + * value read back: + * 0x10 - XR16C850 and the DLL contains the chip revision. + * 0x12 - XR16C2850. + * 0x14 - XR16C854. + */ + id1 = autoconfig_read_divisor_id(up); + DEBUG_AUTOCONF("850id=%04x ", id1); + + id2 = id1 >> 8; + if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { + up->port.type = PORT_16850; + return; + } + + /* + * It wasn't an XR16C850. + * + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(up) == 64) + up->port.type = PORT_16654; + else + up->port.type = PORT_16650V2; +} + +/* + * We detected a chip without a FIFO. Only two fall into + * this category - the original 8250 and the 16450. The + * 16450 has a scratch register (accessible with LCR=0) + */ +static void autoconfig_8250(struct uart_8250_port *up) +{ + unsigned char scratch, status1, status2; + + up->port.type = PORT_8250; + + scratch = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, scratch); + + if (status1 == 0xa5 && status2 == 0x5a) + up->port.type = PORT_16450; +} + +static int broken_efr(struct uart_8250_port *up) +{ + /* + * Exar ST16C2550 "A2" devices incorrectly detect as + * having an EFR, and report an ID of 0x0201. See + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + */ + if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) + return 1; + + return 0; +} + +/* + * We know that the chip has FIFOs. Does it have an EFR? The + * EFR is located in the same register position as the IIR and + * we know the top two bits of the IIR are currently set. The + * EFR should contain zero. Try to read the EFR. + */ +static void autoconfig_16550a(struct uart_8250_port *up) +{ + unsigned char status1, status2; + unsigned int iersave; + + up->port.type = PORT_16550A; + up->capabilities |= UART_CAP_FIFO; + + /* + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. + */ + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + if (serial_in(up, UART_EFR) == 0) { + serial_outp(up, UART_EFR, 0xA8); + if (serial_in(up, UART_EFR) != 0) { + DEBUG_AUTOCONF("EFRv1 "); + up->port.type = PORT_16650; + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + } else { + DEBUG_AUTOCONF("Motorola 8xxx DUART "); + } + serial_outp(up, UART_EFR, 0); + return; + } + + /* + * Maybe it requires 0xbf to be written to the LCR. + * (other ST16C650V2 UARTs, TI16C752A, etc) + */ + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { + DEBUG_AUTOCONF("EFRv2 "); + autoconfig_has_efr(up); + return; + } + + /* + * Check for a National Semiconductor SuperIO chip. + * Attempt to switch to bank 2, read the value of the LOOP bit + * from EXCR1. Switch back to bank 0, change it in MCR. Then + * switch back to bank 2, read it from EXCR1 again and check + * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 + */ + serial_outp(up, UART_LCR, 0); + status1 = serial_in(up, UART_MCR); + serial_outp(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + + if (!((status2 ^ status1) & UART_MCR_LOOP)) { + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial_outp(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_MCR, status1); + + if ((status2 ^ status1) & UART_MCR_LOOP) { + unsigned short quot; + + serial_outp(up, UART_LCR, 0xE0); + + quot = serial_dl_read(up); + quot <<= 3; + + status1 = serial_in(up, 0x04); /* EXCR2 */ + status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ + status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ + serial_outp(up, 0x04, status1); + + serial_dl_write(up, quot); + + serial_outp(up, UART_LCR, 0); + + up->port.uartclk = 921600*16; + up->port.type = PORT_NS16550A; + up->capabilities |= UART_NATSEMI; + return; + } + } + + /* + * No EFR. Try to detect a TI16750, which only sets bit 5 of + * the IIR when 64 byte FIFO mode is enabled when DLAB is set. + * Try setting it with and without DLAB set. Cheap clones + * set bit 5 without DLAB set. + */ + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status2 = serial_in(up, UART_IIR) >> 5; + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_LCR, 0); + + DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + + if (status1 == 6 && status2 == 7) { + up->port.type = PORT_16750; + up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; + return; + } + + /* + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's + * internal UARTs. + * We're going to explicitly set the UUE bit to 0 before + * trying to write and read a 1 just to make sure it's not + * already a 1 and maybe locked there before we even start start. + */ + iersave = serial_in(up, UART_IER); + serial_outp(up, UART_IER, iersave & ~UART_IER_UUE); + if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ + serial_outp(up, UART_IER, iersave | UART_IER_UUE); + if (serial_in(up, UART_IER) & UART_IER_UUE) { + /* + * It's an Xscale. + * We'll leave the UART_IER_UUE bit set to 1 (enabled). + */ + DEBUG_AUTOCONF("Xscale "); + up->port.type = PORT_XSCALE; + up->capabilities |= UART_CAP_UUE; + return; + } + } else { + /* + * If we got here we couldn't force the IER_UUE bit to 0. + * Log it and continue. + */ + DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); + } + serial_outp(up, UART_IER, iersave); + + /* + * We distinguish between 16550A and U6 16550A by counting + * how many bytes are in the FIFO. + */ + if (up->port.type == PORT_16550A && size_fifo(up) == 64) { + up->port.type = PORT_U6_16550A; + up->capabilities |= UART_CAP_AFE; + } +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) +{ + unsigned char status1, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + unsigned long flags; + + if (!up->port.iobase && !up->port.mapbase && !up->port.membase) + return; + + DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", + serial_index(&up->port), up->port.iobase, up->port.membase); + + /* + * We really do need global IRQs disabled here - we're going to + * be frobbing the chips IRQ enable register to see if it exists. + */ + spin_lock_irqsave(&up->port.lock, flags); + + up->capabilities = 0; + up->bugs = 0; + + if (!(up->port.flags & UPF_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + * + * Note: this is safe as long as MCR bit 4 is clear + * and the device is in "PC" mode. + */ + scratch = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + /* + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ + scratch2 = serial_inp(up, UART_IER) & 0x0f; + serial_outp(up, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_inp(up, UART_IER) & 0x0f; + serial_outp(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here + */ + DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", + scratch2, scratch3); + goto out; + } + } + + save_mcr = serial_in(up, UART_MCR); + save_lcr = serial_in(up, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(up->port.flags & UPF_SKIP_TEST)) { + serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(up, UART_MSR) & 0xF0; + serial_outp(up, UART_MCR, save_mcr); + if (status1 != 0x90) { + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); + goto out; + } + } + + /* + * We're pretty sure there's a port here. Lets find out what + * type of port it is. The IIR top two bits allows us to find + * out if it's 8250 or 16450, 16550, 16550A or later. This + * determines what we test for next. + * + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_outp(up, UART_EFR, 0); + serial_outp(up, UART_LCR, 0); + + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + + DEBUG_AUTOCONF("iir=%d ", scratch); + + switch (scratch) { + case 0: + autoconfig_8250(up); + break; + case 1: + up->port.type = PORT_UNKNOWN; + break; + case 2: + up->port.type = PORT_16550; + break; + case 3: + autoconfig_16550a(up); + break; + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Only probe for RSA ports if we got the region. + */ + if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) { + int i; + + for (i = 0 ; i < probe_rsa_count; ++i) { + if (probe_rsa[i] == up->port.iobase && + __enable_rsa(up)) { + up->port.type = PORT_RSA; + break; + } + } + } +#endif + + serial_outp(up, UART_LCR, save_lcr); + + if (up->capabilities != uart_config[up->port.type].flags) { + printk(KERN_WARNING + "ttyS%d: detected caps %08x should be %08x\n", + serial_index(&up->port), up->capabilities, + uart_config[up->port.type].flags); + } + + up->port.fifosize = uart_config[up->port.type].fifo_size; + up->capabilities = uart_config[up->port.type].flags; + up->tx_loadsz = uart_config[up->port.type].tx_loadsz; + + if (up->port.type == PORT_UNKNOWN) + goto out; + + /* + * Reset the UART. + */ +#ifdef CONFIG_SERIAL_8250_RSA + if (up->port.type == PORT_RSA) + serial_outp(up, UART_RSA_FRR, 0); +#endif + serial_outp(up, UART_MCR, save_mcr); + serial8250_clear_fifos(up); + serial_in(up, UART_RX); + if (up->capabilities & UART_CAP_UUE) + serial_outp(up, UART_IER, UART_IER_UUE); + else + serial_outp(up, UART_IER, 0); + + out: + spin_unlock_irqrestore(&up->port.lock, flags); + DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); +} + +static void autoconfig_irq(struct uart_8250_port *up) +{ + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; + unsigned long irqs; + int irq; + + if (up->port.flags & UPF_FOURPORT) { + ICP = (up->port.iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + (void) inb_p(ICP); + } + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_inp(up, UART_MCR); + save_ier = serial_inp(up, UART_IER); + serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_outp(up, UART_MCR, 0); + udelay(10); + if (up->port.flags & UPF_FOURPORT) { + serial_outp(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_outp(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ + (void)serial_inp(up, UART_LSR); + (void)serial_inp(up, UART_RX); + (void)serial_inp(up, UART_IIR); + (void)serial_inp(up, UART_MSR); + serial_outp(up, UART_TX, 0xFF); + udelay(20); + irq = probe_irq_off(irqs); + + serial_outp(up, UART_MCR, save_mcr); + serial_outp(up, UART_IER, save_ier); + + if (up->port.flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); + + up->port.irq = (irq > 0) ? irq : 0; +} + +static inline void __stop_tx(struct uart_8250_port *p) +{ + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } +} + +static void serial8250_stop_tx(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + __stop_tx(up); + + /* + * We really want to stop the transmitter from sending. + */ + if (up->port.type == PORT_16C950) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void transmit_chars(struct uart_8250_port *up); + +static void serial8250_start_tx(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + + if (up->bugs & UART_BUG_TXEN) { + unsigned char lsr; + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if ((up->port.type == PORT_RM9000) ? + (lsr & UART_LSR_THRE) : + (lsr & UART_LSR_TEMT)) + transmit_chars(up); + } + } + + /* + * Re-enable the transmitter if we disabled it. + */ + if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_stop_rx(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +} + +static void serial8250_enable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +} + +static void +receive_chars(struct uart_8250_port *up, unsigned int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned char ch, lsr = *status; + int max_count = 256; + char flag; + + do { + if (likely(lsr & UART_LSR_DR)) + ch = serial_inp(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will + * set UART_LSR_BI without setting UART_LSR_DR when + * it receives a break. To avoid reading from the + * receive buffer without UART_LSR_DR bit set, we + * just force the read character to be 0 + */ + ch = 0; + + flag = TTY_NORMAL; + up->port.icount.rx++; + + lsr |= up->lsr_saved_flags; + up->lsr_saved_flags = 0; + + 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; + + if (lsr & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + 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_inp(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); + *status = lsr; +} + +static void transmit_chars(struct uart_8250_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { + serial_outp(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_tx_stopped(&up->port)) { + serial8250_stop_tx(&up->port); + return; + } + if (uart_circ_empty(xmit)) { + __stop_tx(up); + return; + } + + count = up->tx_loadsz; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + DEBUG_INTR("THRE..."); + + if (uart_circ_empty(xmit)) + __stop_tx(up); +} + +static unsigned int check_modem_status(struct uart_8250_port *up) +{ + unsigned int status = serial_in(up, UART_MSR); + + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && + up->port.state != NULL) { + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + } + + return status; +} + +/* + * This handles the interrupt from one port. + */ +static void serial8250_handle_port(struct uart_8250_port *up) +{ + unsigned int status; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + + status = serial_inp(up, UART_LSR); + + DEBUG_INTR("status = %x...", status); + + if (status & (UART_LSR_DR | UART_LSR_BI)) + receive_chars(up, &status); + check_modem_status(up); + if (status & UART_LSR_THRE) + transmit_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +/* + * This is the serial driver's interrupt routine. + * + * Arjan thinks the old way was overly complex, so it got simplified. + * Alan disagrees, saying that need the complexity to handle the weird + * nature of ISA shared interrupts. (This is a special exception.) + * + * In order to handle ISA shared interrupts properly, we need to check + * that all ports have been serviced, and therefore the ISA interrupt + * line has been de-asserted. + * + * This means we need to loop through all ports. checking that they + * don't have an interrupt pending. + */ +static irqreturn_t serial8250_interrupt(int irq, void *dev_id) +{ + struct irq_info *i = dev_id; + struct list_head *l, *end = NULL; + int pass_counter = 0, handled = 0; + + DEBUG_INTR("serial8250_interrupt(%d)...", irq); + + spin_lock(&i->lock); + + l = i->head; + do { + struct uart_8250_port *up; + unsigned int iir; + + up = list_entry(l, struct uart_8250_port, list); + + iir = serial_in(up, UART_IIR); + if (!(iir & UART_IIR_NO_INT)) { + serial8250_handle_port(up); + + handled = 1; + + end = NULL; + } else if ((up->port.iotype == UPIO_DWAPB || + up->port.iotype == UPIO_DWAPB32) && + (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { + /* The DesignWare APB UART has an Busy Detect (0x07) + * interrupt meaning an LCR write attempt occured while the + * UART was busy. The interrupt must be cleared by reading + * the UART status register (USR) and the LCR re-written. */ + unsigned int status; + status = *(volatile u32 *)up->port.private_data; + serial_out(up, UART_LCR, up->lcr); + + handled = 1; + + end = NULL; + } else if (end == NULL) + end = l; + + l = l->next; + + if (l == i->head && pass_counter++ > PASS_LIMIT) { + /* If we hit this, we're dead. */ + printk_ratelimited(KERN_ERR + "serial8250: too much work for irq%d\n", irq); + break; + } + } while (l != end); + + spin_unlock(&i->lock); + + DEBUG_INTR("end.\n"); + + return IRQ_RETVAL(handled); +} + +/* + * To support ISA shared interrupts, we need to have one interrupt + * handler that ensures that the IRQ line has been deasserted + * before returning. Failing to do this will result in the IRQ + * line being stuck active, and, since ISA irqs are edge triggered, + * no more IRQs will be seen. + */ +static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) +{ + spin_lock_irq(&i->lock); + + if (!list_empty(i->head)) { + if (i->head == &up->list) + i->head = i->head->next; + list_del(&up->list); + } else { + BUG_ON(i->head != &up->list); + i->head = NULL; + } + spin_unlock_irq(&i->lock); + /* List empty so throw away the hash node */ + if (i->head == NULL) { + hlist_del(&i->node); + kfree(i); + } +} + +static int serial_link_irq_chain(struct uart_8250_port *up) +{ + struct hlist_head *h; + struct hlist_node *n; + struct irq_info *i; + int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; + + mutex_lock(&hash_mutex); + + h = &irq_lists[up->port.irq % NR_IRQ_HASH]; + + hlist_for_each(n, h) { + i = hlist_entry(n, struct irq_info, node); + if (i->irq == up->port.irq) + break; + } + + if (n == NULL) { + i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); + if (i == NULL) { + mutex_unlock(&hash_mutex); + return -ENOMEM; + } + spin_lock_init(&i->lock); + i->irq = up->port.irq; + hlist_add_head(&i->node, h); + } + mutex_unlock(&hash_mutex); + + spin_lock_irq(&i->lock); + + if (i->head) { + list_add(&up->list, i->head); + spin_unlock_irq(&i->lock); + + ret = 0; + } else { + INIT_LIST_HEAD(&up->list); + i->head = &up->list; + spin_unlock_irq(&i->lock); + irq_flags |= up->port.irqflags; + ret = request_irq(up->port.irq, serial8250_interrupt, + irq_flags, "serial", i); + if (ret < 0) + serial_do_unlink(i, up); + } + + return ret; +} + +static void serial_unlink_irq_chain(struct uart_8250_port *up) +{ + struct irq_info *i; + struct hlist_node *n; + struct hlist_head *h; + + mutex_lock(&hash_mutex); + + h = &irq_lists[up->port.irq % NR_IRQ_HASH]; + + hlist_for_each(n, h) { + i = hlist_entry(n, struct irq_info, node); + if (i->irq == up->port.irq) + break; + } + + BUG_ON(n == NULL); + BUG_ON(i->head == NULL); + + if (list_empty(i->head)) + free_irq(up->port.irq, i); + + serial_do_unlink(i, up); + mutex_unlock(&hash_mutex); +} + +/* + * This function is used to handle ports that do not have an + * interrupt. This doesn't work very well for 16450's, but gives + * barely passable results for a 16550A. (Although at the expense + * of much CPU overhead). + */ +static void serial8250_timeout(unsigned long data) +{ + struct uart_8250_port *up = (struct uart_8250_port *)data; + unsigned int iir; + + iir = serial_in(up, UART_IIR); + if (!(iir & UART_IIR_NO_INT)) + serial8250_handle_port(up); + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); +} + +static void serial8250_backup_timeout(unsigned long data) +{ + struct uart_8250_port *up = (struct uart_8250_port *)data; + unsigned int iir, ier = 0, lsr; + unsigned long flags; + + /* + * Must disable interrupts or else we risk racing with the interrupt + * based handler. + */ + if (is_real_interrupt(up->port.irq)) { + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + } + + iir = serial_in(up, UART_IIR); + + /* + * This should be a safe test for anyone who doesn't trust the + * IIR bits on their UART, but it's specifically designed for + * the "Diva" UART used on the management processor on many HP + * ia64 and parisc boxes. + */ + spin_lock_irqsave(&up->port.lock, flags); + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + spin_unlock_irqrestore(&up->port.lock, flags); + if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && + (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && + (lsr & UART_LSR_THRE)) { + iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); + iir |= UART_IIR_THRI; + } + + if (!(iir & UART_IIR_NO_INT)) + serial8250_handle_port(up); + + if (is_real_interrupt(up->port.irq)) + serial_out(up, UART_IER, ier); + + /* Standard timer interval plus 0.2s to keep the port running */ + mod_timer(&up->timer, + jiffies + uart_poll_timeout(&up->port) + HZ / 5); +} + +static unsigned int serial8250_tx_empty(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + unsigned int lsr; + + spin_lock_irqsave(&up->port.lock, flags); + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + spin_unlock_irqrestore(&up->port.lock, flags); + + return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int serial8250_get_mctrl(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned int status; + unsigned int ret; + + status = check_modem_status(up); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + + serial_out(up, UART_MCR, mcr); +} + +static void serial8250_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + for (;;) { + status = serial_in(up, UART_LSR); + + up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + + if ((status & bits) == bits) + break; + if (--tmout == 0) + break; + udelay(1); + } + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + unsigned int tmout; + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + udelay(1); + touch_nmi_watchdog(); + } + } +} + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial8250_get_poll_char(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned char lsr = serial_inp(up, UART_LSR); + + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; + + return serial_inp(up, UART_RX); +} + + +static void serial8250_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(up, UART_TX, c); + if (c == 10) { + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_TX, 13); + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_IER, ier); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +static int serial8250_startup(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + unsigned char lsr, iir; + int retval; + + up->port.fifosize = uart_config[up->port.type].fifo_size; + up->tx_loadsz = uart_config[up->port.type].tx_loadsz; + up->capabilities = uart_config[up->port.type].flags; + up->mcr = 0; + + if (up->port.iotype != up->cur_iotype) + set_io_from_upio(port); + + if (up->port.type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_IER, 0); + serial_outp(up, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_LCR, 0); + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + enable_rsa(up); +#endif + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial8250_clear_fifos(up); + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(up, UART_LSR); + (void) serial_inp(up, UART_RX); + (void) serial_inp(up, UART_IIR); + (void) serial_inp(up, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(up->port.flags & UPF_BUGGY_UART) && + (serial_inp(up, UART_LSR) == 0xff)) { + printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(&up->port)); + return -ENODEV; + } + + /* + * For a XR16C850, we need to set the trigger levels + */ + if (up->port.type == PORT_16850) { + unsigned char fctr; + + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + + fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_outp(up, UART_TRG, UART_TRG_96); + serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_outp(up, UART_TRG, UART_TRG_96); + + serial_outp(up, UART_LCR, 0); + } + + if (is_real_interrupt(up->port.irq)) { + unsigned char iir1; + /* + * Test for UARTs that do not reassert THRE when the + * transmitter is idle and the interrupt has already + * been cleared. Real 16550s should always reassert + * this interrupt whenever the transmitter is idle and + * the interrupt is enabled. Delays are necessary to + * allow register changes to become visible. + */ + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.irqflags & IRQF_SHARED) + disable_irq_nosync(up->port.irq); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_out_sync(up, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + iir1 = serial_in(up, UART_IIR); + serial_out(up, UART_IER, 0); + serial_out_sync(up, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir = serial_in(up, UART_IIR); + serial_out(up, UART_IER, 0); + + if (up->port.irqflags & IRQF_SHARED) + enable_irq(up->port.irq); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * If the interrupt is not reasserted, setup a timer to + * kick the UART on a regular basis. + */ + if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { + up->bugs |= UART_BUG_THRE; + pr_debug("ttyS%d - using backup timer\n", + serial_index(port)); + } + } + + /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + uart_poll_timeout(port) + HZ / 5); + } + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!is_real_interrupt(up->port.irq)) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else { + retval = serial_link_irq_chain(up); + if (retval) + return retval; + } + + /* + * Now, initialize the UART + */ + serial_outp(up, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_FOURPORT) { + if (!is_real_interrupt(up->port.irq)) + up->port.mctrl |= TIOCM_OUT1; + } else + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + if (is_real_interrupt(up->port.irq)) + up->port.mctrl |= TIOCM_OUT2; + + serial8250_set_mctrl(&up->port, up->port.mctrl); + + /* Serial over Lan (SoL) hack: + Intel 8257x Gigabit ethernet chips have a + 16550 emulation, to be used for Serial Over Lan. + Those chips take a longer time than a normal + serial device to signalize that a transmission + data was queued. Due to that, the above test generally + fails. One solution would be to delay the reading of + iir. However, this is not reliable, since the timeout + is variable. So, let's just don't test if we receive + TX irq. This way, we'll never enable UART_BUG_TXEN. + */ + if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) + goto dont_test_tx_en; + + /* + * Do a quick test to see if we receive an + * interrupt when we enable the TX irq. + */ + serial_outp(up, UART_IER, UART_IER_THRI); + lsr = serial_in(up, UART_LSR); + iir = serial_in(up, UART_IIR); + serial_outp(up, UART_IER, 0); + + if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { + up->bugs |= UART_BUG_TXEN; + pr_debug("ttyS%d - enabling bad tx status workarounds\n", + serial_index(port)); + } + } else { + up->bugs &= ~UART_BUG_TXEN; + } + +dont_test_tx_en: + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Clear the interrupt registers again for luck, and clear the + * saved flags to avoid getting false values from polling + * routines or the previous session. + */ + serial_inp(up, UART_LSR); + serial_inp(up, UART_RX); + serial_inp(up, UART_IIR); + serial_inp(up, UART_MSR); + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_outp(up, UART_IER, up->ier); + + if (up->port.flags & UPF_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ + icp = (up->port.iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + (void) inb_p(icp); + } + + return 0; +} + +static void serial8250_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned long flags; + + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_outp(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((up->port.iobase & 0xfe0) | 0x1f); + up->port.mctrl |= TIOCM_OUT1; + } else + up->port.mctrl &= ~TIOCM_OUT2; + + serial8250_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); + serial8250_clear_fifos(up); + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + disable_rsa(up); +#endif + + /* + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ + (void) serial_in(up, UART_RX); + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (is_real_interrupt(up->port.irq)) + serial_unlink_irq_chain(up); +} + +static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud) +{ + unsigned int quot; + + /* + * Handle magic divisors for baud rates above baud_base on + * SMSC SuperIO chips. + */ + if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/4)) + quot = 0x8001; + else if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/8)) + quot = 0x8002; + else + quot = uart_get_divisor(port, baud); + + return quot; +} + +void +serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned char cval, fcr = 0; + unsigned long flags; + unsigned int baud, quot; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (termios->c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); + quot = serial8250_get_divisor(port, baud); + + /* + * Oxford Semi 952 rev B workaround + */ + if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) + quot++; + + if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) { + if (baud < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = uart_config[up->port.type].fcr; + } + + /* + * MCR-based auto flow control. When AFE is enabled, RTS will be + * deasserted when the receive FIFO contains more characters than + * the trigger, or the MCR RTS bit is cleared. In the case where + * the remote UART is not using CTS auto flow control, we must + * have sufficient FIFO entries for the latency of the remote + * UART to respond. IOW, at least 32 bytes of FIFO. + */ + if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) { + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + } + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (!(up->bugs & UART_BUG_NOMSR) && + UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + if (up->capabilities & UART_CAP_UUE) + up->ier |= UART_IER_UUE | UART_IER_RTOIE; + + serial_out(up, UART_IER, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; + /* + * TI16C752/Startech hardware flow control. FIXME: + * - TI16C752 requires control thresholds to be set. + * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. + */ + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + + serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_outp(up, UART_EFR, efr); + } + +#ifdef CONFIG_ARCH_OMAP + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (cpu_is_omap1510() && is_omap_port(up)) { + if (baud == 115200) { + quot = 1; + serial_out(up, UART_OMAP_OSC_12M_SEL, 1); + } else + serial_out(up, UART_OMAP_OSC_12M_SEL, 0); + } +#endif + + if (up->capabilities & UART_NATSEMI) { + /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ + serial_outp(up, UART_LCR, 0xe0); + } else { + serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + } + + serial_dl_write(up, quot); + + /* + * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR + * is written without DLAB set, this mode will be disabled. + */ + if (up->port.type == PORT_16750) + serial_outp(up, UART_FCR, fcr); + + serial_outp(up, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + if (up->port.type != PORT_16750) { + if (fcr & UART_FCR_ENABLE_FIFO) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_outp(up, UART_FCR, fcr); /* set fcr */ + } + serial8250_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} +EXPORT_SYMBOL(serial8250_do_set_termios); + +static void +serial8250_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + if (port->set_termios) + port->set_termios(port, termios, old); + else + serial8250_do_set_termios(port, termios, old); +} + +static void +serial8250_set_ldisc(struct uart_port *port, int new) +{ + if (new == N_PPS) { + port->flags |= UPF_HARDPPS_CD; + serial8250_enable_ms(port); + } else + port->flags &= ~UPF_HARDPPS_CD; +} + + +void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *p = + container_of(port, struct uart_8250_port, port); + + serial8250_set_sleep(p, state != 0); +} +EXPORT_SYMBOL(serial8250_do_pm); + +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + if (port->pm) + port->pm(port, state, oldstate); + else + serial8250_do_pm(port, state, oldstate); +} + +static unsigned int serial8250_port_size(struct uart_8250_port *pt) +{ + if (pt->port.iotype == UPIO_AU) + return 0x1000; +#ifdef CONFIG_ARCH_OMAP + if (is_omap_port(pt)) + return 0x16 << pt->port.regshift; +#endif + return 8 << pt->port.regshift; +} + +/* + * Resource handling. + */ +static int serial8250_request_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + int ret = 0; + + switch (up->port.iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: + case UPIO_DWAPB: + case UPIO_DWAPB32: + if (!up->port.mapbase) + break; + + if (!request_mem_region(up->port.mapbase, size, "serial")) { + ret = -EBUSY; + break; + } + + if (up->port.flags & UPF_IOREMAP) { + up->port.membase = ioremap_nocache(up->port.mapbase, + size); + if (!up->port.membase) { + release_mem_region(up->port.mapbase, size); + ret = -ENOMEM; + } + } + break; + + case UPIO_HUB6: + case UPIO_PORT: + if (!request_region(up->port.iobase, size, "serial")) + ret = -EBUSY; + break; + } + return ret; +} + +static void serial8250_release_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + + switch (up->port.iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM: + case UPIO_DWAPB: + case UPIO_DWAPB32: + if (!up->port.mapbase) + break; + + if (up->port.flags & UPF_IOREMAP) { + iounmap(up->port.membase); + up->port.membase = NULL; + } + + release_mem_region(up->port.mapbase, size); + break; + + case UPIO_HUB6: + case UPIO_PORT: + release_region(up->port.iobase, size); + break; + } +} + +static int serial8250_request_rsa_resource(struct uart_8250_port *up) +{ + unsigned long start = UART_RSA_BASE << up->port.regshift; + unsigned int size = 8 << up->port.regshift; + int ret = -EINVAL; + + switch (up->port.iotype) { + case UPIO_HUB6: + case UPIO_PORT: + start += up->port.iobase; + if (request_region(start, size, "serial-rsa")) + ret = 0; + else + ret = -EBUSY; + break; + } + + return ret; +} + +static void serial8250_release_rsa_resource(struct uart_8250_port *up) +{ + unsigned long offset = UART_RSA_BASE << up->port.regshift; + unsigned int size = 8 << up->port.regshift; + + switch (up->port.iotype) { + case UPIO_HUB6: + case UPIO_PORT: + release_region(up->port.iobase + offset, size); + break; + } +} + +static void serial8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + serial8250_release_std_resource(up); + if (up->port.type == PORT_RSA) + serial8250_release_rsa_resource(up); +} + +static int serial8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + int ret = 0; + + ret = serial8250_request_std_resource(up); + if (ret == 0 && up->port.type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + serial8250_release_std_resource(up); + } + + return ret; +} + +static void serial8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + int probeflags = PROBE_ANY; + int ret; + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial8250_request_std_resource(up); + if (ret < 0) + return; + + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + probeflags &= ~PROBE_RSA; + + if (up->port.iotype != up->cur_iotype) + set_io_from_upio(port); + + if (flags & UART_CONFIG_TYPE) + autoconfig(up, probeflags); + + /* if access method is AU, it is a 16550 with a quirk */ + if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) + up->bugs |= UART_BUG_NOMSR; + + if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + autoconfig_irq(up); + + if (up->port.type != PORT_RSA && probeflags & PROBE_RSA) + serial8250_release_rsa_resource(up); + if (up->port.type == PORT_UNKNOWN) + serial8250_release_std_resource(up); +} + +static int +serial8250_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) || ser->type == PORT_CIRRUS || + ser->type == PORT_STARTECH) + return -EINVAL; + return 0; +} + +static const char * +serial8250_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 serial8250_pops = { + .tx_empty = serial8250_tx_empty, + .set_mctrl = serial8250_set_mctrl, + .get_mctrl = serial8250_get_mctrl, + .stop_tx = serial8250_stop_tx, + .start_tx = serial8250_start_tx, + .stop_rx = serial8250_stop_rx, + .enable_ms = serial8250_enable_ms, + .break_ctl = serial8250_break_ctl, + .startup = serial8250_startup, + .shutdown = serial8250_shutdown, + .set_termios = serial8250_set_termios, + .set_ldisc = serial8250_set_ldisc, + .pm = serial8250_pm, + .type = serial8250_type, + .release_port = serial8250_release_port, + .request_port = serial8250_request_port, + .config_port = serial8250_config_port, + .verify_port = serial8250_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif +}; + +static struct uart_8250_port serial8250_ports[UART_NR]; + +static void (*serial8250_isa_config)(int port, struct uart_port *up, + unsigned short *capabilities); + +void serial8250_set_isa_configurator( + void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) +{ + serial8250_isa_config = v; +} +EXPORT_SYMBOL(serial8250_set_isa_configurator); + +static void __init serial8250_isa_init_ports(void) +{ + struct uart_8250_port *up; + static int first = 1; + int i, irqflag = 0; + + if (!first) + return; + first = 0; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + up->port.line = i; + spin_lock_init(&up->port.lock); + + init_timer(&up->timer); + up->timer.function = serial8250_timeout; + + /* + * ALPHA_KLUDGE_MCR needs to be killed. + */ + up->mcr_mask = ~ALPHA_KLUDGE_MCR; + up->mcr_force = ALPHA_KLUDGE_MCR; + + up->port.ops = &serial8250_pops; + } + + if (share_irqs) + irqflag = IRQF_SHARED; + + for (i = 0, up = serial8250_ports; + i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; + i++, up++) { + up->port.iobase = old_serial_port[i].port; + up->port.irq = irq_canonicalize(old_serial_port[i].irq); + up->port.irqflags = old_serial_port[i].irqflags; + up->port.uartclk = old_serial_port[i].baud_base * 16; + up->port.flags = old_serial_port[i].flags; + up->port.hub6 = old_serial_port[i].hub6; + up->port.membase = old_serial_port[i].iomem_base; + up->port.iotype = old_serial_port[i].io_type; + up->port.regshift = old_serial_port[i].iomem_reg_shift; + set_io_from_upio(&up->port); + up->port.irqflags |= irqflag; + if (serial8250_isa_config != NULL) + serial8250_isa_config(i, &up->port, &up->capabilities); + + } +} + +static void +serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) +{ + up->port.type = type; + up->port.fifosize = uart_config[type].fifo_size; + up->capabilities = uart_config[type].flags; + up->tx_loadsz = uart_config[type].tx_loadsz; +} + +static void __init +serial8250_register_ports(struct uart_driver *drv, struct device *dev) +{ + int i; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + up->cur_iotype = 0xFF; + } + + serial8250_isa_init_ports(); + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + up->port.dev = dev; + + if (up->port.flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(up, up->port.type); + + uart_add_one_port(drv, &up->port); + } +} + +#ifdef CONFIG_SERIAL_8250_CONSOLE + +static void serial8250_console_putchar(struct uart_port *port, int ch) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_out(up, UART_TX, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +serial8250_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_8250_port *up = &serial8250_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + touch_nmi_watchdog(); + + local_irq_save(flags); + if (up->port.sysrq) { + /* serial8250_handle_port() already took the lock */ + 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 + */ + ier = serial_in(up, UART_IER); + + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + + uart_console_write(&up->port, s, count, serial8250_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_out(up, UART_IER, ier); + + /* + * The receive handling will happen properly because the + * receive ready bit will still be set; it is not cleared + * on read. However, modem control will not, we must + * call it if we have saved something in the saved flags + * while processing with interrupts off. + */ + if (up->msr_saved_flags) + check_modem_status(up); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init serial8250_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= nr_uarts) + co->index = 0; + port = &serial8250_ports[co->index].port; + if (!port->iobase && !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 int serial8250_console_early_setup(void) +{ + return serial8250_find_port_for_earlycon(); +} + +static struct console serial8250_console = { + .name = "ttyS", + .write = serial8250_console_write, + .device = uart_console_device, + .setup = serial8250_console_setup, + .early_setup = serial8250_console_early_setup, + .flags = CON_PRINTBUFFER | CON_ANYTIME, + .index = -1, + .data = &serial8250_reg, +}; + +static int __init serial8250_console_init(void) +{ + if (nr_uarts > UART_NR) + nr_uarts = UART_NR; + + serial8250_isa_init_ports(); + register_console(&serial8250_console); + return 0; +} +console_initcall(serial8250_console_init); + +int serial8250_find_port(struct uart_port *p) +{ + int line; + struct uart_port *port; + + for (line = 0; line < nr_uarts; line++) { + port = &serial8250_ports[line].port; + if (uart_match_port(p, port)) + return line; + } + return -ENODEV; +} + +#define SERIAL8250_CONSOLE &serial8250_console +#else +#define SERIAL8250_CONSOLE NULL +#endif + +static struct uart_driver serial8250_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .cons = SERIAL8250_CONSOLE, +}; + +/* + * early_serial_setup - early registration for 8250 ports + * + * Setup an 8250 port structure prior to console initialisation. Use + * after console initialisation will cause undefined behaviour. + */ +int __init early_serial_setup(struct uart_port *port) +{ + struct uart_port *p; + + if (port->line >= ARRAY_SIZE(serial8250_ports)) + return -ENODEV; + + serial8250_isa_init_ports(); + p = &serial8250_ports[port->line].port; + p->iobase = port->iobase; + p->membase = port->membase; + p->irq = port->irq; + p->irqflags = port->irqflags; + p->uartclk = port->uartclk; + p->fifosize = port->fifosize; + p->regshift = port->regshift; + p->iotype = port->iotype; + p->flags = port->flags; + p->mapbase = port->mapbase; + p->private_data = port->private_data; + p->type = port->type; + p->line = port->line; + + set_io_from_upio(p); + if (port->serial_in) + p->serial_in = port->serial_in; + if (port->serial_out) + p->serial_out = port->serial_out; + + return 0; +} + +/** + * serial8250_suspend_port - suspend one serial port + * @line: serial line number + * + * Suspend one serial port. + */ +void serial8250_suspend_port(int line) +{ + uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port); +} + +/** + * serial8250_resume_port - resume one serial port + * @line: serial line number + * + * Resume one serial port. + */ +void serial8250_resume_port(int line) +{ + struct uart_8250_port *up = &serial8250_ports[line]; + + if (up->capabilities & UART_NATSEMI) { + unsigned char tmp; + + /* Ensure it's still in high speed mode */ + serial_outp(up, UART_LCR, 0xE0); + + tmp = serial_in(up, 0x04); /* EXCR2 */ + tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ + tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ + serial_outp(up, 0x04, tmp); + + serial_outp(up, UART_LCR, 0); + } + uart_resume_port(&serial8250_reg, &up->port); +} + +/* + * Register a set of serial devices attached to a platform device. The + * list is terminated with a zero flags entry, which means we expect + * all entries to have at least UPF_BOOT_AUTOCONF set. + */ +static int __devinit serial8250_probe(struct platform_device *dev) +{ + struct plat_serial8250_port *p = dev->dev.platform_data; + struct uart_port port; + int ret, i, irqflag = 0; + + memset(&port, 0, sizeof(struct uart_port)); + + 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.set_termios = p->set_termios; + port.pm = p->pm; + port.dev = &dev->dev; + port.irqflags |= irqflag; + ret = serial8250_register_port(&port); + if (ret < 0) { + dev_err(&dev->dev, "unable to register port at index %d " + "(IO%lx MEM%llx IRQ%d): %d\n", i, + p->iobase, (unsigned long long)p->mapbase, + p->irq, ret); + } + } + return 0; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial8250_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < nr_uarts; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.dev == &dev->dev) + serial8250_unregister_port(i); + } + return 0; +} + +static int serial8250_suspend(struct platform_device *dev, pm_message_t state) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_suspend_port(&serial8250_reg, &up->port); + } + + return 0; +} + +static int serial8250_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_8250_port *up = &serial8250_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + serial8250_resume_port(i); + } + + return 0; +} + +static struct platform_driver serial8250_isa_driver = { + .probe = serial8250_probe, + .remove = __devexit_p(serial8250_remove), + .suspend = serial8250_suspend, + .resume = serial8250_resume, + .driver = { + .name = "serial8250", + .owner = THIS_MODULE, + }, +}; + +/* + * This "device" covers _all_ ISA 8250-compatible serial devices listed + * in the table in include/asm/serial.h + */ +static struct platform_device *serial8250_isa_devs; + +/* + * serial8250_register_port and serial8250_unregister_port allows for + * 16x50 serial ports to be configured at run-time, to support PCMCIA + * modems and PCI multiport cards. + */ +static DEFINE_MUTEX(serial_mutex); + +static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) +{ + int i; + + /* + * First, find a port entry which matches. + */ + for (i = 0; i < nr_uarts; i++) + if (uart_match_port(&serial8250_ports[i].port, port)) + return &serial8250_ports[i]; + + /* + * We didn't find a matching entry, so look for the first + * free entry. We look for one which hasn't been previously + * used (indicated by zero iobase). + */ + for (i = 0; i < nr_uarts; i++) + if (serial8250_ports[i].port.type == PORT_UNKNOWN && + serial8250_ports[i].port.iobase == 0) + return &serial8250_ports[i]; + + /* + * That also failed. Last resort is to find any entry which + * doesn't have a real port associated with it. + */ + for (i = 0; i < nr_uarts; i++) + if (serial8250_ports[i].port.type == PORT_UNKNOWN) + return &serial8250_ports[i]; + + return NULL; +} + +/** + * 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 *uart; + int ret = -ENOSPC; + + if (port->uartclk == 0) + return -EINVAL; + + mutex_lock(&serial_mutex); + + uart = serial8250_find_match_or_unused(port); + if (uart) { + uart_remove_one_port(&serial8250_reg, &uart->port); + + uart->port.iobase = port->iobase; + uart->port.membase = port->membase; + uart->port.irq = port->irq; + uart->port.irqflags = port->irqflags; + uart->port.uartclk = port->uartclk; + uart->port.fifosize = port->fifosize; + uart->port.regshift = port->regshift; + uart->port.iotype = port->iotype; + uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; + uart->port.mapbase = port->mapbase; + uart->port.private_data = port->private_data; + if (port->dev) + uart->port.dev = port->dev; + + if (port->flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(uart, port->type); + + set_io_from_upio(&uart->port); + /* Possibly override default I/O functions. */ + if (port->serial_in) + uart->port.serial_in = port->serial_in; + if (port->serial_out) + uart->port.serial_out = port->serial_out; + /* Possibly override set_termios call */ + if (port->set_termios) + uart->port.set_termios = port->set_termios; + if (port->pm) + uart->port.pm = port->pm; + + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, + &uart->capabilities); + + ret = uart_add_one_port(&serial8250_reg, &uart->port); + if (ret == 0) + ret = uart->port.line; + } + mutex_unlock(&serial_mutex); + + return ret; +} +EXPORT_SYMBOL(serial8250_register_port); + +/** + * serial8250_unregister_port - remove a 16x50 serial port at runtime + * @line: serial line number + * + * Remove one serial port. This may not be called from interrupt + * context. We hand the port back to the our control. + */ +void serial8250_unregister_port(int line) +{ + struct uart_8250_port *uart = &serial8250_ports[line]; + + mutex_lock(&serial_mutex); + uart_remove_one_port(&serial8250_reg, &uart->port); + if (serial8250_isa_devs) { + uart->port.flags &= ~UPF_BOOT_AUTOCONF; + uart->port.type = PORT_UNKNOWN; + uart->port.dev = &serial8250_isa_devs->dev; + uart_add_one_port(&serial8250_reg, &uart->port); + } else { + uart->port.dev = NULL; + } + mutex_unlock(&serial_mutex); +} +EXPORT_SYMBOL(serial8250_unregister_port); + +static int __init serial8250_init(void) +{ + int ret; + + if (nr_uarts > UART_NR) + nr_uarts = UART_NR; + + printk(KERN_INFO "Serial: 8250/16550 driver, " + "%d ports, IRQ sharing %sabled\n", nr_uarts, + share_irqs ? "en" : "dis"); + +#ifdef CONFIG_SPARC + ret = sunserial_register_minors(&serial8250_reg, UART_NR); +#else + serial8250_reg.nr = UART_NR; + ret = uart_register_driver(&serial8250_reg); +#endif + if (ret) + goto out; + + serial8250_isa_devs = platform_device_alloc("serial8250", + PLAT8250_DEV_LEGACY); + if (!serial8250_isa_devs) { + ret = -ENOMEM; + goto unreg_uart_drv; + } + + ret = platform_device_add(serial8250_isa_devs); + if (ret) + goto put_dev; + + serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); + + ret = platform_driver_register(&serial8250_isa_driver); + if (ret == 0) + goto out; + + platform_device_del(serial8250_isa_devs); +put_dev: + platform_device_put(serial8250_isa_devs); +unreg_uart_drv: +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else + uart_unregister_driver(&serial8250_reg); +#endif +out: + return ret; +} + +static void __exit serial8250_exit(void) +{ + struct platform_device *isa_dev = serial8250_isa_devs; + + /* + * This tells serial8250_unregister_port() not to re-register + * the ports (thereby making serial8250_isa_driver permanently + * in use.) + */ + serial8250_isa_devs = NULL; + + platform_driver_unregister(&serial8250_isa_driver); + platform_device_unregister(isa_dev); + +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else + uart_unregister_driver(&serial8250_reg); +#endif +} + +module_init(serial8250_init); +module_exit(serial8250_exit); + +EXPORT_SYMBOL(serial8250_suspend_port); +EXPORT_SYMBOL(serial8250_resume_port); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); + +module_param(share_irqs, uint, 0644); +MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" + " (unsafe)"); + +module_param(nr_uarts, uint, 0644); +MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); + +module_param(skip_txen_test, uint, 0644); +MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); + +#ifdef CONFIG_SERIAL_8250_RSA +module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); +MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); +#endif +MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR); diff --git a/drivers/tty/serial/8250.h b/drivers/tty/serial/8250.h new file mode 100644 index 000000000000..6e19ea3e48d5 --- /dev/null +++ b/drivers/tty/serial/8250.h @@ -0,0 +1,80 @@ +/* + * linux/drivers/char/8250.h + * + * Driver for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King. + * + * 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. + */ + +#include + +struct old_serial_port { + unsigned int uart; + unsigned int baud_base; + unsigned int port; + unsigned int irq; + unsigned int flags; + unsigned char hub6; + unsigned char io_type; + unsigned char *iomem_base; + unsigned short iomem_reg_shift; + unsigned long irqflags; +}; + +/* + * This replaces serial_uart_config in include/linux/serial.h + */ +struct serial8250_config { + const char *name; + unsigned short fifo_size; + unsigned short tx_loadsz; + unsigned char fcr; + unsigned int flags; +}; + +#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */ +#define UART_CAP_EFR (1 << 9) /* UART has EFR */ +#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */ +#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */ +#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ + +#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ +#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 PROBE_RSA (1 << 0) +#define PROBE_ANY (~0) + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +#ifdef CONFIG_SERIAL_8250_SHARE_IRQ +#define SERIAL8250_SHARE_IRQS 1 +#else +#define SERIAL8250_SHARE_IRQS 0 +#endif + +#if defined(__alpha__) && !defined(CONFIG_PCI) +/* + * Digital did something really horribly wrong with the OUT1 and OUT2 + * lines on at least some ALPHA's. The failure mode is that if either + * is cleared, the machine locks up with endless interrupts. + */ +#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) +#elif defined(CONFIG_SBC8560) +/* + * WindRiver did something similarly broken on their SBC8560 board. The + * UART tristates its IRQ output while OUT2 is clear, but they pulled + * the interrupt line _up_ instead of down, so if we register the IRQ + * while the UART is in that state, we die in an IRQ storm. */ +#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2) +#else +#define ALPHA_KLUDGE_MCR 0 +#endif diff --git a/drivers/tty/serial/8250_accent.c b/drivers/tty/serial/8250_accent.c new file mode 100644 index 000000000000..9c10262f2469 --- /dev/null +++ b/drivers/tty/serial/8250_accent.c @@ -0,0 +1,47 @@ +/* + * linux/drivers/serial/8250_accent.c + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * 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. + */ +#include +#include +#include + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port accent_data[] = { + PORT(0x330, 4), + PORT(0x338, 4), + { }, +}; + +static struct platform_device accent_device = { + .name = "serial8250", + .id = PLAT8250_DEV_ACCENT, + .dev = { + .platform_data = accent_data, + }, +}; + +static int __init accent_init(void) +{ + return platform_device_register(&accent_device); +} + +module_init(accent_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_acorn.c b/drivers/tty/serial/8250_acorn.c new file mode 100644 index 000000000000..b0ce8c56f1a4 --- /dev/null +++ b/drivers/tty/serial/8250_acorn.c @@ -0,0 +1,141 @@ +/* + * linux/drivers/serial/acorn.c + * + * Copyright (C) 1996-2003 Russell King. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "8250.h" + +#define MAX_PORTS 3 + +struct serial_card_type { + unsigned int num_ports; + unsigned int uartclk; + unsigned int type; + unsigned int offset[MAX_PORTS]; +}; + +struct serial_card_info { + unsigned int num_ports; + int ports[MAX_PORTS]; + void __iomem *vaddr; +}; + +static int __devinit +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; + unsigned long bus_addr; + unsigned int i; + + info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->num_ports = type->num_ports; + + bus_addr = ecard_resource_start(ec, type->type); + info->vaddr = ecardm_iomap(ec, type->type, 0, 0); + if (!info->vaddr) { + kfree(info); + return -ENOMEM; + } + + 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; + + for (i = 0; i < info->num_ports; i ++) { + port.membase = info->vaddr + type->offset[i]; + port.mapbase = bus_addr + type->offset[i]; + + info->ports[i] = serial8250_register_port(&port); + } + + return 0; +} + +static void __devexit serial_card_remove(struct expansion_card *ec) +{ + struct serial_card_info *info = ecard_get_drvdata(ec); + int i; + + ecard_set_drvdata(ec, NULL); + + for (i = 0; i < info->num_ports; i++) + if (info->ports[i] > 0) + serial8250_unregister_port(info->ports[i]); + + kfree(info); +} + +static struct serial_card_type atomwide_type = { + .num_ports = 3, + .uartclk = 7372800, + .type = ECARD_RES_IOCSLOW, + .offset = { 0x2800, 0x2400, 0x2000 }, +}; + +static struct serial_card_type serport_type = { + .num_ports = 2, + .uartclk = 3686400, + .type = ECARD_RES_IOCSLOW, + .offset = { 0x2000, 0x2020 }, +}; + +static const struct ecard_id serial_cids[] = { + { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, &atomwide_type }, + { MANU_SERPORT, PROD_SERPORT_DSPORT, &serport_type }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver serial_card_driver = { + .probe = serial_card_probe, + .remove = __devexit_p(serial_card_remove), + .id_table = serial_cids, + .drv = { + .name = "8250_acorn", + }, +}; + +static int __init serial_card_init(void) +{ + return ecard_register_driver(&serial_card_driver); +} + +static void __exit serial_card_exit(void) +{ + ecard_remove_driver(&serial_card_driver); +} + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver"); +MODULE_LICENSE("GPL"); + +module_init(serial_card_init); +module_exit(serial_card_exit); diff --git a/drivers/tty/serial/8250_boca.c b/drivers/tty/serial/8250_boca.c new file mode 100644 index 000000000000..3bfe0f7b26fb --- /dev/null +++ b/drivers/tty/serial/8250_boca.c @@ -0,0 +1,61 @@ +/* + * linux/drivers/serial/8250_boca.c + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * 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. + */ +#include +#include +#include + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port boca_data[] = { + PORT(0x100, 12), + PORT(0x108, 12), + PORT(0x110, 12), + PORT(0x118, 12), + PORT(0x120, 12), + PORT(0x128, 12), + PORT(0x130, 12), + PORT(0x138, 12), + PORT(0x140, 12), + PORT(0x148, 12), + PORT(0x150, 12), + PORT(0x158, 12), + PORT(0x160, 12), + PORT(0x168, 12), + PORT(0x170, 12), + PORT(0x178, 12), + { }, +}; + +static struct platform_device boca_device = { + .name = "serial8250", + .id = PLAT8250_DEV_BOCA, + .dev = { + .platform_data = boca_data, + }, +}; + +static int __init boca_init(void) +{ + return platform_device_register(&boca_device); +} + +module_init(boca_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("8250 serial probe module for Boca cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_early.c b/drivers/tty/serial/8250_early.c new file mode 100644 index 000000000000..eaafb98debed --- /dev/null +++ b/drivers/tty/serial/8250_early.c @@ -0,0 +1,287 @@ +/* + * Early serial console for 8250/16550 devices + * + * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas + * + * 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. + * + * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King, + * and on early_printk.c by Andi Kleen. + * + * This is for use before the serial driver has initialized, in + * particular, before the UARTs have been discovered and named. + * Instead of specifying the console device as, e.g., "ttyS0", + * we locate the device directly by its MMIO or I/O port address. + * + * The user can specify the device directly, e.g., + * earlycon=uart8250,io,0x3f8,9600n8 + * earlycon=uart8250,mmio,0xff5e0000,115200n8 + * earlycon=uart8250,mmio32,0xff5e0000,115200n8 + * or + * console=uart8250,io,0x3f8,9600n8 + * console=uart8250,mmio,0xff5e0000,115200n8 + * console=uart8250,mmio32,0xff5e0000,115200n8 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FIX_EARLYCON_MEM +#include +#include +#endif + +struct early_serial8250_device { + struct uart_port port; + char options[16]; /* e.g., 115200n8 */ + unsigned int baud; +}; + +static struct early_serial8250_device early_device; + +static unsigned int __init serial_in(struct uart_port *port, int offset) +{ + switch (port->iotype) { + case UPIO_MEM: + return readb(port->membase + offset); + case UPIO_MEM32: + return readl(port->membase + (offset << 2)); + case UPIO_PORT: + return inb(port->iobase + offset); + default: + return 0; + } +} + +static void __init serial_out(struct uart_port *port, int offset, int value) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb(value, port->membase + offset); + break; + case UPIO_MEM32: + writel(value, port->membase + (offset << 2)); + break; + case UPIO_PORT: + outb(value, port->iobase + offset); + break; + } +} + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static void __init wait_for_xmitr(struct uart_port *port) +{ + unsigned int status; + + for (;;) { + status = serial_in(port, UART_LSR); + if ((status & BOTH_EMPTY) == BOTH_EMPTY) + return; + cpu_relax(); + } +} + +static void __init serial_putc(struct uart_port *port, int c) +{ + wait_for_xmitr(port); + serial_out(port, UART_TX, c); +} + +static void __init early_serial8250_write(struct console *console, + const char *s, unsigned int count) +{ + struct uart_port *port = &early_device.port; + unsigned int ier; + + /* Save the IER and disable interrupts */ + ier = serial_in(port, UART_IER); + serial_out(port, UART_IER, 0); + + uart_console_write(port, s, count, serial_putc); + + /* Wait for transmitter to become empty and restore the IER */ + wait_for_xmitr(port); + serial_out(port, UART_IER, ier); +} + +static unsigned int __init probe_baud(struct uart_port *port) +{ + unsigned char lcr, dll, dlm; + unsigned int quot; + + lcr = serial_in(port, UART_LCR); + serial_out(port, UART_LCR, lcr | UART_LCR_DLAB); + dll = serial_in(port, UART_DLL); + dlm = serial_in(port, UART_DLM); + serial_out(port, UART_LCR, lcr); + + quot = (dlm << 8) | dll; + return (port->uartclk / 16) / quot; +} + +static void __init init_port(struct early_serial8250_device *device) +{ + struct uart_port *port = &device->port; + unsigned int divisor; + unsigned char c; + + serial_out(port, UART_LCR, 0x3); /* 8n1 */ + serial_out(port, UART_IER, 0); /* no interrupt */ + serial_out(port, UART_FCR, 0); /* no fifo */ + serial_out(port, UART_MCR, 0x3); /* DTR + RTS */ + + divisor = port->uartclk / (16 * device->baud); + c = serial_in(port, UART_LCR); + serial_out(port, UART_LCR, c | UART_LCR_DLAB); + serial_out(port, UART_DLL, divisor & 0xff); + serial_out(port, UART_DLM, (divisor >> 8) & 0xff); + serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); +} + +static int __init parse_options(struct early_serial8250_device *device, + char *options) +{ + struct uart_port *port = &device->port; + int mmio, mmio32, length; + + if (!options) + return -ENODEV; + + port->uartclk = BASE_BAUD * 16; + + mmio = !strncmp(options, "mmio,", 5); + mmio32 = !strncmp(options, "mmio32,", 7); + if (mmio || mmio32) { + port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); + port->mapbase = simple_strtoul(options + (mmio ? 5 : 7), + &options, 0); + if (mmio32) + port->regshift = 2; +#ifdef CONFIG_FIX_EARLYCON_MEM + set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, + port->mapbase & PAGE_MASK); + port->membase = + (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + port->membase += port->mapbase & ~PAGE_MASK; +#else + port->membase = ioremap_nocache(port->mapbase, 64); + if (!port->membase) { + printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", + __func__, + (unsigned long long) port->mapbase); + return -ENOMEM; + } +#endif + } else if (!strncmp(options, "io,", 3)) { + port->iotype = UPIO_PORT; + port->iobase = simple_strtoul(options + 3, &options, 0); + mmio = 0; + } else + return -EINVAL; + + options = strchr(options, ','); + if (options) { + options++; + device->baud = simple_strtoul(options, NULL, 0); + length = min(strcspn(options, " "), sizeof(device->options)); + strncpy(device->options, options, length); + } else { + device->baud = probe_baud(port); + snprintf(device->options, sizeof(device->options), "%u", + device->baud); + } + + if (mmio || mmio32) + printk(KERN_INFO + "Early serial console at MMIO%s 0x%llx (options '%s')\n", + mmio32 ? "32" : "", + (unsigned long long)port->mapbase, + device->options); + else + printk(KERN_INFO + "Early serial console at I/O port 0x%lx (options '%s')\n", + port->iobase, + device->options); + + return 0; +} + +static struct console early_serial8250_console __initdata = { + .name = "uart", + .write = early_serial8250_write, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1, +}; + +static int __init early_serial8250_setup(char *options) +{ + struct early_serial8250_device *device = &early_device; + int err; + + if (device->port.membase || device->port.iobase) + return 0; + + err = parse_options(device, options); + if (err < 0) + return err; + + init_port(device); + return 0; +} + +int __init setup_early_serial8250_console(char *cmdline) +{ + char *options; + int err; + + options = strstr(cmdline, "uart8250,"); + if (!options) { + options = strstr(cmdline, "uart,"); + if (!options) + return 0; + } + + options = strchr(cmdline, ',') + 1; + err = early_serial8250_setup(options); + if (err < 0) + return err; + + register_console(&early_serial8250_console); + + return 0; +} + +int serial8250_find_port_for_earlycon(void) +{ + struct early_serial8250_device *device = &early_device; + struct uart_port *port = &device->port; + int line; + int ret; + + if (!device->port.membase && !device->port.iobase) + return -ENODEV; + + line = serial8250_find_port(port); + if (line < 0) + return -ENODEV; + + ret = update_console_cmdline("uart", 8250, + "ttyS", line, device->options); + if (ret < 0) + ret = update_console_cmdline("uart", 0, + "ttyS", line, device->options); + + return ret; +} + +early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/tty/serial/8250_exar_st16c554.c b/drivers/tty/serial/8250_exar_st16c554.c new file mode 100644 index 000000000000..567143ace159 --- /dev/null +++ b/drivers/tty/serial/8250_exar_st16c554.c @@ -0,0 +1,52 @@ +/* + * linux/drivers/serial/8250_exar.c + * + * Written by Paul B Schroeder < pschroeder "at" uplogix "dot" com > + * Based on 8250_boca. + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * 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. + */ +#include +#include +#include + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port exar_data[] = { + PORT(0x100, 5), + PORT(0x108, 5), + PORT(0x110, 5), + PORT(0x118, 5), + { }, +}; + +static struct platform_device exar_device = { + .name = "serial8250", + .id = PLAT8250_DEV_EXAR_ST16C554, + .dev = { + .platform_data = exar_data, + }, +}; + +static int __init exar_init(void) +{ + return platform_device_register(&exar_device); +} + +module_init(exar_init); + +MODULE_AUTHOR("Paul B Schroeder"); +MODULE_DESCRIPTION("8250 serial probe module for Exar cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_fourport.c b/drivers/tty/serial/8250_fourport.c new file mode 100644 index 000000000000..6375d68b7913 --- /dev/null +++ b/drivers/tty/serial/8250_fourport.c @@ -0,0 +1,53 @@ +/* + * linux/drivers/serial/8250_fourport.c + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * 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. + */ +#include +#include +#include + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \ + } + +static struct plat_serial8250_port fourport_data[] = { + PORT(0x1a0, 9), + PORT(0x1a8, 9), + PORT(0x1b0, 9), + PORT(0x1b8, 9), + PORT(0x2a0, 5), + PORT(0x2a8, 5), + PORT(0x2b0, 5), + PORT(0x2b8, 5), + { }, +}; + +static struct platform_device fourport_device = { + .name = "serial8250", + .id = PLAT8250_DEV_FOURPORT, + .dev = { + .platform_data = fourport_data, + }, +}; + +static int __init fourport_init(void) +{ + return platform_device_register(&fourport_device); +} + +module_init(fourport_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_gsc.c b/drivers/tty/serial/8250_gsc.c new file mode 100644 index 000000000000..d8c0ffbfa6e3 --- /dev/null +++ b/drivers/tty/serial/8250_gsc.c @@ -0,0 +1,122 @@ +/* + * Serial Device Initialisation for Lasi/Asp/Wax/Dino + * + * (c) Copyright Matthew Wilcox 2001-2002 + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "8250.h" + +static int __init serial_init_chip(struct parisc_device *dev) +{ + struct uart_port port; + unsigned long address; + int err; + + if (!dev->irq) { + /* We find some unattached serial ports by walking native + * busses. These should be silently ignored. Otherwise, + * what we have here is a missing parent device, so tell + * the user what they're missing. + */ + if (parisc_parent(dev)->id.hw_type != HPHW_IOA) + printk(KERN_INFO + "Serial: device 0x%llx not configured.\n" + "Enable support for Wax, Lasi, Asp or Dino.\n", + (unsigned long long)dev->hpa.start); + return -ENODEV; + } + + address = dev->hpa.start; + if (dev->id.sversion != 0x8d) + address += 0x800; + + memset(&port, 0, sizeof(port)); + 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); + if (err < 0) { + printk(KERN_WARNING + "serial8250_register_port returned error %d\n", err); + iounmap(port.membase); + return err; + } + + return 0; +} + +static struct parisc_device_id serial_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d }, + { 0 } +}; + +/* Hack. Some machines have SERIAL_0 attached to Lasi and SERIAL_1 + * attached to Dino. Unfortunately, Dino appears before Lasi in the device + * tree. To ensure that ttyS0 == SERIAL_0, we register two drivers; one + * which only knows about Lasi and then a second which will find all the + * other serial ports. HPUX ignores this problem. + */ +static struct parisc_device_id lasi_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */ + { 0 } +}; + + +MODULE_DEVICE_TABLE(parisc, serial_tbl); + +static struct parisc_driver lasi_driver = { + .name = "serial_1", + .id_table = lasi_tbl, + .probe = serial_init_chip, +}; + +static struct parisc_driver serial_driver = { + .name = "serial", + .id_table = serial_tbl, + .probe = serial_init_chip, +}; + +static int __init probe_serial_gsc(void) +{ + register_parisc_driver(&lasi_driver); + register_parisc_driver(&serial_driver); + return 0; +} + +module_init(probe_serial_gsc); + +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_hp300.c b/drivers/tty/serial/8250_hp300.c new file mode 100644 index 000000000000..c13438c93012 --- /dev/null +++ b/drivers/tty/serial/8250_hp300.c @@ -0,0 +1,327 @@ +/* + * Driver for the 98626/98644/internal serial interface on hp300/hp400 + * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs) + * + * Ported from 2.2 and modified to use the normal 8250 driver + * by Kars de Jong , May 2004. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI) +#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? +#endif + +#ifdef CONFIG_HPAPCI +struct hp300_port +{ + struct hp300_port *next; /* next port */ + int line; /* line (tty) number */ +}; + +static struct hp300_port *hp300_ports; +#endif + +#ifdef CONFIG_HPDCA + +static int __devinit hpdca_init_one(struct dio_dev *d, + const struct dio_device_id *ent); +static void __devexit hpdca_remove_one(struct dio_dev *d); + +static struct dio_device_id hpdca_dio_tbl[] = { + { DIO_ID_DCA0 }, + { DIO_ID_DCA0REM }, + { DIO_ID_DCA1 }, + { DIO_ID_DCA1REM }, + { 0 } +}; + +static struct dio_driver hpdca_driver = { + .name = "hpdca", + .id_table = hpdca_dio_tbl, + .probe = hpdca_init_one, + .remove = __devexit_p(hpdca_remove_one), +}; + +#endif + +static unsigned int num_ports; + +extern int hp300_uart_scode; + +/* Offset to UART registers from base of DCA */ +#define UART_OFFSET 17 + +#define DCA_ID 0x01 /* ID (read), reset (write) */ +#define DCA_IC 0x03 /* Interrupt control */ + +/* Interrupt control */ +#define DCA_IC_IE 0x80 /* Master interrupt enable */ + +#define HPDCA_BAUD_BASE 153600 + +/* Base address of the Frodo part */ +#define FRODO_BASE (0x41c000) + +/* + * Where we find the 8250-like APCI ports, and how far apart they are. + */ +#define FRODO_APCIBASE 0x0 +#define FRODO_APCISPACE 0x20 +#define FRODO_APCI_OFFSET(x) (FRODO_APCIBASE + ((x) * FRODO_APCISPACE)) + +#define HPAPCI_BAUD_BASE 500400 + +#ifdef CONFIG_SERIAL_8250_CONSOLE +/* + * Parse the bootinfo to find descriptions for headless console and + * debug serial ports and register them with the 8250 driver. + * This function should be called before serial_console_init() is called + * to make sure the serial console will be available for use. IA-64 kernel + * calls this function from setup_arch() after the EFI and ACPI tables have + * been parsed. + */ +int __init hp300_setup_serial_console(void) +{ + int scode; + struct uart_port port; + + memset(&port, 0, sizeof(port)); + + if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX) + return 0; + + if (DIO_SCINHOLE(hp300_uart_scode)) + return 0; + + scode = hp300_uart_scode; + + /* Memory mapped I/O */ + port.iotype = UPIO_MEM; + port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; + port.type = PORT_UNKNOWN; + + /* Check for APCI console */ + if (scode == 256) { +#ifdef CONFIG_HPAPCI + printk(KERN_INFO "Serial console is HP APCI 1\n"); + + port.uartclk = HPAPCI_BAUD_BASE * 16; + port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1)); + port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); + port.regshift = 2; + add_preferred_console("ttyS", port.line, "9600n8"); +#else + printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); + return 0; +#endif + } else { +#ifdef CONFIG_HPDCA + unsigned long pa = dio_scodetophysaddr(scode); + if (!pa) + return 0; + + printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); + + port.uartclk = HPDCA_BAUD_BASE * 16; + port.mapbase = (pa + UART_OFFSET); + port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); + port.regshift = 1; + port.irq = DIO_IPL(pa + DIO_VIRADDRBASE); + + /* Enable board-interrupts */ + out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); + + if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) + add_preferred_console("ttyS", port.line, "9600n8"); +#else + printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); + return 0; +#endif + } + + if (early_serial_setup(&port) < 0) + printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); + return 0; +} +#endif /* CONFIG_SERIAL_8250_CONSOLE */ + +#ifdef CONFIG_HPDCA +static int __devinit hpdca_init_one(struct dio_dev *d, + const struct dio_device_id *ent) +{ + struct uart_port port; + int line; + +#ifdef CONFIG_SERIAL_8250_CONSOLE + if (hp300_uart_scode == d->scode) { + /* Already got it. */ + return 0; + } +#endif + memset(&port, 0, sizeof(struct uart_port)); + + /* Memory mapped I/O */ + port.iotype = UPIO_MEM; + port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; + port.irq = d->ipl; + port.uartclk = HPDCA_BAUD_BASE * 16; + port.mapbase = (d->resource.start + UART_OFFSET); + port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); + port.regshift = 1; + port.dev = &d->dev; + line = serial8250_register_port(&port); + + if (line < 0) { + printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" + " irq %d failed\n", d->scode, port.irq); + return -ENOMEM; + } + + /* Enable board-interrupts */ + out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); + dio_set_drvdata(d, (void *)line); + + /* Reset the DCA */ + out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff); + udelay(100); + + num_ports++; + + return 0; +} +#endif + +static int __init hp300_8250_init(void) +{ + static int called; +#ifdef CONFIG_HPAPCI + int line; + unsigned long base; + struct uart_port uport; + struct hp300_port *port; + int i; +#endif + if (called) + return -ENODEV; + called = 1; + + if (!MACH_IS_HP300) + return -ENODEV; + +#ifdef CONFIG_HPDCA + dio_register_driver(&hpdca_driver); +#endif +#ifdef CONFIG_HPAPCI + if (hp300_model < HP_400) { + if (!num_ports) + return -ENODEV; + return 0; + } + /* These models have the Frodo chip. + * Port 0 is reserved for the Apollo Domain keyboard. + * Port 1 is either the console or the DCA. + */ + for (i = 1; i < 4; i++) { + /* Port 1 is the console on a 425e, on other machines it's + * mapped to DCA. + */ +#ifdef CONFIG_SERIAL_8250_CONSOLE + if (i == 1) + continue; +#endif + + /* Create new serial device */ + port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + memset(&uport, 0, sizeof(struct uart_port)); + + base = (FRODO_BASE + FRODO_APCI_OFFSET(i)); + + /* Memory mapped I/O */ + uport.iotype = UPIO_MEM; + uport.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; + + line = serial8250_register_port(&uport); + + if (line < 0) { + printk(KERN_NOTICE "8250_hp300: register_serial() APCI" + " %d irq %d failed\n", i, uport.irq); + kfree(port); + continue; + } + + port->line = line; + port->next = hp300_ports; + hp300_ports = port; + + num_ports++; + } +#endif + + /* Any boards found? */ + if (!num_ports) + return -ENODEV; + + return 0; +} + +#ifdef CONFIG_HPDCA +static void __devexit hpdca_remove_one(struct dio_dev *d) +{ + int line; + + line = (int) dio_get_drvdata(d); + if (d->resource.start) { + /* Disable board-interrupts */ + out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0); + } + serial8250_unregister_port(line); +} +#endif + +static void __exit hp300_8250_exit(void) +{ +#ifdef CONFIG_HPAPCI + struct hp300_port *port, *to_free; + + for (port = hp300_ports; port; ) { + serial8250_unregister_port(port->line); + to_free = port; + port = port->next; + kfree(to_free); + } + + hp300_ports = NULL; +#endif +#ifdef CONFIG_HPDCA + dio_unregister_driver(&hpdca_driver); +#endif +} + +module_init(hp300_8250_init); +module_exit(hp300_8250_exit); +MODULE_DESCRIPTION("HP DCA/APCI serial driver"); +MODULE_AUTHOR("Kars de Jong "); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_hub6.c b/drivers/tty/serial/8250_hub6.c new file mode 100644 index 000000000000..7609150e7d5e --- /dev/null +++ b/drivers/tty/serial/8250_hub6.c @@ -0,0 +1,58 @@ +/* + * linux/drivers/serial/8250_hub6.c + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * 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. + */ +#include +#include +#include + +#define HUB6(card,port) \ + { \ + .iobase = 0x302, \ + .irq = 3, \ + .uartclk = 1843200, \ + .iotype = UPIO_HUB6, \ + .flags = UPF_BOOT_AUTOCONF, \ + .hub6 = (card) << 6 | (port) << 3 | 1, \ + } + +static struct plat_serial8250_port hub6_data[] = { + HUB6(0, 0), + HUB6(0, 1), + HUB6(0, 2), + HUB6(0, 3), + HUB6(0, 4), + HUB6(0, 5), + HUB6(1, 0), + HUB6(1, 1), + HUB6(1, 2), + HUB6(1, 3), + HUB6(1, 4), + HUB6(1, 5), + { }, +}; + +static struct platform_device hub6_device = { + .name = "serial8250", + .id = PLAT8250_DEV_HUB6, + .dev = { + .platform_data = hub6_data, + }, +}; + +static int __init hub6_init(void) +{ + return platform_device_register(&hub6_device); +} + +module_init(hub6_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_mca.c b/drivers/tty/serial/8250_mca.c new file mode 100644 index 000000000000..d10be944ad44 --- /dev/null +++ b/drivers/tty/serial/8250_mca.c @@ -0,0 +1,63 @@ +/* + * linux/drivers/serial/8250_mca.c + * + * Copyright (C) 2005 Russell King. + * Data taken from include/asm-i386/serial.h + * + * 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. + */ +#include +#include +#include +#include + +/* + * FIXME: Should we be doing AUTO_IRQ here? + */ +#ifdef CONFIG_SERIAL_8250_DETECT_IRQ +#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ +#else +#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST +#endif + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = MCA_FLAGS, \ + } + +static struct plat_serial8250_port mca_data[] = { + PORT(0x3220, 3), + PORT(0x3228, 3), + PORT(0x4220, 3), + PORT(0x4228, 3), + PORT(0x5220, 3), + PORT(0x5228, 3), + { }, +}; + +static struct platform_device mca_device = { + .name = "serial8250", + .id = PLAT8250_DEV_MCA, + .dev = { + .platform_data = mca_data, + }, +}; + +static int __init mca_init(void) +{ + if (!MCA_bus) + return -ENODEV; + return platform_device_register(&mca_device); +} + +module_init(mca_init); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("8250 serial probe module for MCA ports"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c new file mode 100644 index 000000000000..8b8930f700b5 --- /dev/null +++ b/drivers/tty/serial/8250_pci.c @@ -0,0 +1,3850 @@ +/* + * linux/drivers/char/8250_pci.c + * + * Probe module for 8250/16550-type PCI serial ports. + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "8250.h" + +#undef SERIAL_DEBUG_PCI + +/* + * init function returns: + * > 0 - number of ports + * = 0 - use board->num_ports + * < 0 - error + */ +struct pci_serial_quirk { + u32 vendor; + u32 device; + u32 subvendor; + u32 subdevice; + int (*init)(struct pci_dev *dev); + int (*setup)(struct serial_private *, + const struct pciserial_board *, + struct uart_port *, int); + void (*exit)(struct pci_dev *dev); +}; + +#define PCI_NUM_BAR_RESOURCES 6 + +struct serial_private { + struct pci_dev *dev; + unsigned int nr; + void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES]; + struct pci_serial_quirk *quirk; + int line[0]; +}; + +static void moan_device(const char *str, struct pci_dev *dev) +{ + printk(KERN_WARNING + "%s: %s\n" + "Please send the output of lspci -vv, this\n" + "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" + "manufacturer and name of serial board or\n" + "modem board to rmk+serial@arm.linux.org.uk.\n", + pci_name(dev), str, dev->vendor, dev->device, + dev->subsystem_vendor, dev->subsystem_device); +} + +static int +setup_port(struct serial_private *priv, struct uart_port *port, + int bar, int offset, int regshift) +{ + struct pci_dev *dev = priv->dev; + unsigned long base, len; + + if (bar >= PCI_NUM_BAR_RESOURCES) + return -EINVAL; + + base = pci_resource_start(dev, bar); + + if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { + len = pci_resource_len(dev, bar); + + if (!priv->remapped_bar[bar]) + priv->remapped_bar[bar] = ioremap_nocache(base, len); + 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; + } else { + port->iotype = UPIO_PORT; + port->iobase = base + offset; + port->mapbase = 0; + port->membase = NULL; + port->regshift = 0; + } + return 0; +} + +/* + * ADDI-DATA GmbH communication cards + */ +static int addidata_apci7800_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar = 0, offset = board->first_offset; + bar = FL_GET_BASE(board->flags); + + if (idx < 2) { + offset += idx * board->uart_offset; + } else if ((idx >= 2) && (idx < 4)) { + bar += 1; + offset += ((idx - 2) * board->uart_offset); + } else if ((idx >= 4) && (idx < 6)) { + bar += 2; + offset += ((idx - 4) * board->uart_offset); + } else if (idx >= 6) { + bar += 3; + offset += ((idx - 6) * board->uart_offset); + } + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +/* + * AFAVLAB uses a different mixture of BARs and offsets + * Not that ugly ;) -- HW + */ +static int +afavlab_setup(struct serial_private *priv, const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar, offset = board->first_offset; + + bar = FL_GET_BASE(board->flags); + if (idx < 4) + bar += idx; + else { + bar = 4; + offset += (idx - 4) * board->uart_offset; + } + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +/* + * HP's Remote Management Console. The Diva chip came in several + * different versions. N-class, L2000 and A500 have two Diva chips, each + * with 3 UARTs (the third UART on the second chip is unused). Superdome + * and Keystone have one Diva chip with 3 UARTs. Some later machines have + * one Diva chip, but it has been expanded to 5 UARTs. + */ +static int pci_hp_diva_init(struct pci_dev *dev) +{ + int rc = 0; + + switch (dev->subsystem_device) { + case PCI_DEVICE_ID_HP_DIVA_TOSCA1: + case PCI_DEVICE_ID_HP_DIVA_HALFDOME: + case PCI_DEVICE_ID_HP_DIVA_KEYSTONE: + case PCI_DEVICE_ID_HP_DIVA_EVEREST: + rc = 3; + break; + case PCI_DEVICE_ID_HP_DIVA_TOSCA2: + rc = 2; + break; + case PCI_DEVICE_ID_HP_DIVA_MAESTRO: + rc = 4; + break; + case PCI_DEVICE_ID_HP_DIVA_POWERBAR: + case PCI_DEVICE_ID_HP_DIVA_HURRICANE: + rc = 1; + break; + } + + return rc; +} + +/* + * HP's Diva chip puts the 4th/5th serial port further out, and + * some serial ports are supposed to be hidden on certain models. + */ +static int +pci_hp_diva_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int offset = board->first_offset; + unsigned int bar = FL_GET_BASE(board->flags); + + switch (priv->dev->subsystem_device) { + case PCI_DEVICE_ID_HP_DIVA_MAESTRO: + if (idx == 3) + idx++; + break; + case PCI_DEVICE_ID_HP_DIVA_EVEREST: + if (idx > 0) + idx++; + if (idx > 2) + idx++; + break; + } + if (idx > 2) + offset = 0x18; + + offset += idx * board->uart_offset; + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +/* + * Added for EKF Intel i960 serial boards + */ +static int pci_inteli960ni_init(struct pci_dev *dev) +{ + unsigned long oldval; + + if (!(dev->subsystem_device & 0x1000)) + return -ENODEV; + + /* is firmware started? */ + pci_read_config_dword(dev, 0x44, (void *)&oldval); + if (oldval == 0x00001000L) { /* RESET value */ + printk(KERN_DEBUG "Local i960 firmware missing"); + return -ENODEV; + } + return 0; +} + +/* + * Some PCI serial cards using the PLX 9050 PCI interface chip require + * that the card interrupt be explicitly enabled or disabled. This + * seems to be mainly needed on card using the PLX which also use I/O + * mapped memory. + */ +static int pci_plx9050_init(struct pci_dev *dev) +{ + u8 irq_config; + void __iomem *p; + + if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) { + moan_device("no memory in bar 0", dev); + return 0; + } + + irq_config = 0x41; + if (dev->vendor == PCI_VENDOR_ID_PANACOM || + dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) + irq_config = 0x43; + + if ((dev->vendor == PCI_VENDOR_ID_PLX) && + (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) + /* + * As the megawolf cards have the int pins active + * high, and have 2 UART chips, both ints must be + * enabled on the 9050. Also, the UARTS are set in + * 16450 mode by default, so we have to enable the + * 16C950 'enhanced' mode so that we can use the + * deep FIFOs + */ + irq_config = 0x5b; + /* + * enable/disable interrupts + */ + p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); + if (p == NULL) + return -ENOMEM; + writel(irq_config, p + 0x4c); + + /* + * Read the register back to ensure that it took effect. + */ + readl(p + 0x4c); + iounmap(p); + + return 0; +} + +static void __devexit pci_plx9050_exit(struct pci_dev *dev) +{ + u8 __iomem *p; + + if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) + return; + + /* + * disable interrupts + */ + p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); + if (p != NULL) { + writel(0, p + 0x4c); + + /* + * Read the register back to ensure that it took effect. + */ + readl(p + 0x4c); + iounmap(p); + } +} + +#define NI8420_INT_ENABLE_REG 0x38 +#define NI8420_INT_ENABLE_BIT 0x2000 + +static void __devexit pci_ni8420_exit(struct pci_dev *dev) +{ + void __iomem *p; + unsigned long base, len; + unsigned int bar = 0; + + if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { + moan_device("no memory in bar", dev); + return; + } + + base = pci_resource_start(dev, bar); + len = pci_resource_len(dev, bar); + p = ioremap_nocache(base, len); + if (p == NULL) + return; + + /* Disable the CPU Interrupt */ + writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT), + p + NI8420_INT_ENABLE_REG); + iounmap(p); +} + + +/* MITE registers */ +#define MITE_IOWBSR1 0xc4 +#define MITE_IOWCR1 0xf4 +#define MITE_LCIMR1 0x08 +#define MITE_LCIMR2 0x10 + +#define MITE_LCIMR2_CLR_CPU_IE (1 << 30) + +static void __devexit pci_ni8430_exit(struct pci_dev *dev) +{ + void __iomem *p; + unsigned long base, len; + unsigned int bar = 0; + + if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { + moan_device("no memory in bar", dev); + return; + } + + base = pci_resource_start(dev, bar); + len = pci_resource_len(dev, bar); + p = ioremap_nocache(base, len); + if (p == NULL) + return; + + /* Disable the CPU Interrupt */ + writel(MITE_LCIMR2_CLR_CPU_IE, p + MITE_LCIMR2); + iounmap(p); +} + +/* 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) +{ + unsigned int bar, offset = board->first_offset; + + bar = 0; + + if (idx < 4) { + /* first four channels map to 0, 0x100, 0x200, 0x300 */ + offset += idx * board->uart_offset; + } else if (idx < 8) { + /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */ + offset += idx * board->uart_offset + 0xC00; + } else /* we have only 8 ports on PMC-OCTALPRO */ + return 1; + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +/* +* This does initialization for PMC OCTALPRO cards: +* maps the device memory, resets the UARTs (needed, bc +* if the module is removed and inserted again, the card +* is in the sleep mode) and enables global interrupt. +*/ + +/* global control register offset for SBS PMC-OctalPro */ +#define OCT_REG_CR_OFF 0x500 + +static int sbs_init(struct pci_dev *dev) +{ + u8 __iomem *p; + + p = pci_ioremap_bar(dev, 0); + + if (p == NULL) + return -ENOMEM; + /* Set bit-4 Control Register (UART RESET) in to reset the uarts */ + writeb(0x10, p + OCT_REG_CR_OFF); + udelay(50); + writeb(0x0, p + OCT_REG_CR_OFF); + + /* Set bit-2 (INTENABLE) of Control Register */ + writeb(0x4, p + OCT_REG_CR_OFF); + iounmap(p); + + return 0; +} + +/* + * Disables the global interrupt of PMC-OctalPro + */ + +static void __devexit sbs_exit(struct pci_dev *dev) +{ + u8 __iomem *p; + + p = pci_ioremap_bar(dev, 0); + /* FIXME: What if resource_len < OCT_REG_CR_OFF */ + if (p != NULL) + writeb(0, p + OCT_REG_CR_OFF); + iounmap(p); +} + +/* + * SIIG serial cards have an PCI interface chip which also controls + * the UART clocking frequency. Each UART can be clocked independently + * (except cards equiped with 4 UARTs) and initial clocking settings + * are stored in the EEPROM chip. It can cause problems because this + * version of serial driver doesn't support differently clocked UART's + * on single PCI card. To prevent this, initialization functions set + * high frequency clocking for all UART's on given card. It is safe (I + * hope) because it doesn't touch EEPROM settings to prevent conflicts + * with other OSes (like M$ DOS). + * + * SIIG support added by Andrey Panin , 10/1999 + * + * There is two family of SIIG serial cards with different PCI + * interface chip and different configuration methods: + * - 10x cards have control registers in IO and/or memory space; + * - 20x cards have control registers in standard PCI configuration space. + * + * Note: all 10x cards have PCI device ids 0x10.. + * all 20x cards have PCI device ids 0x20.. + * + * There are also Quartet Serial cards which use Oxford Semiconductor + * 16954 quad UART PCI chip clocked by 18.432 MHz quartz. + * + * Note: some SIIG cards are probed by the parport_serial object. + */ + +#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) + +static int pci_siig10x_init(struct pci_dev *dev) +{ + u16 data; + void __iomem *p; + + switch (dev->device & 0xfff8) { + case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ + data = 0xffdf; + break; + case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ + data = 0xf7ff; + break; + default: /* 1S1P, 4S */ + data = 0xfffb; + break; + } + + p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); + if (p == NULL) + return -ENOMEM; + + writew(readw(p + 0x28) & data, p + 0x28); + readw(p + 0x28); + iounmap(p); + return 0; +} + +#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) + +static int pci_siig20x_init(struct pci_dev *dev) +{ + u8 data; + + /* Change clock frequency for the first UART. */ + pci_read_config_byte(dev, 0x6f, &data); + pci_write_config_byte(dev, 0x6f, data & 0xef); + + /* If this card has 2 UART, we have to do the same with second UART. */ + if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || + ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { + pci_read_config_byte(dev, 0x73, &data); + pci_write_config_byte(dev, 0x73, data & 0xef); + } + return 0; +} + +static int pci_siig_init(struct pci_dev *dev) +{ + unsigned int type = dev->device & 0xff00; + + if (type == 0x1000) + return pci_siig10x_init(dev); + else if (type == 0x2000) + return pci_siig20x_init(dev); + + moan_device("Unknown SIIG card", dev); + return -ENODEV; +} + +static int pci_siig_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0; + + if (idx > 3) { + bar = 4; + offset = (idx - 4) * 8; + } + + return setup_port(priv, port, bar, offset, 0); +} + +/* + * Timedia has an explosion of boards, and to avoid the PCI table from + * growing *huge*, we use this function to collapse some 70 entries + * in the PCI table into one, for sanity's and compactness's sake. + */ +static const unsigned short timedia_single_port[] = { + 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 +}; + +static const unsigned short timedia_dual_port[] = { + 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, + 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, + 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, + 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, + 0xD079, 0 +}; + +static const unsigned short timedia_quad_port[] = { + 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, + 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, + 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, + 0xB157, 0 +}; + +static const unsigned short timedia_eight_port[] = { + 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, + 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 +}; + +static const struct timedia_struct { + int num; + const unsigned short *ids; +} timedia_data[] = { + { 1, timedia_single_port }, + { 2, timedia_dual_port }, + { 4, timedia_quad_port }, + { 8, timedia_eight_port } +}; + +static int pci_timedia_init(struct pci_dev *dev) +{ + const unsigned short *ids; + int i, j; + + for (i = 0; i < ARRAY_SIZE(timedia_data); i++) { + ids = timedia_data[i].ids; + for (j = 0; ids[j]; j++) + if (dev->subsystem_device == ids[j]) + return timedia_data[i].num; + } + return 0; +} + +/* + * Timedia/SUNIX uses a mixture of BARs and offsets + * Ugh, this is ugly as all hell --- TYT + */ +static int +pci_timedia_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar = 0, offset = board->first_offset; + + switch (idx) { + case 0: + bar = 0; + break; + case 1: + offset = board->uart_offset; + bar = 0; + break; + case 2: + bar = 1; + break; + case 3: + offset = board->uart_offset; + /* FALLTHROUGH */ + case 4: /* BAR 2 */ + case 5: /* BAR 3 */ + case 6: /* BAR 4 */ + case 7: /* BAR 5 */ + bar = idx - 2; + } + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +/* + * Some Titan cards are also a little weird + */ +static int +titan_400l_800l_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar, offset = board->first_offset; + + switch (idx) { + case 0: + bar = 1; + break; + case 1: + bar = 2; + break; + default: + bar = 4; + offset = (idx - 2) * board->uart_offset; + } + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +static int pci_xircom_init(struct pci_dev *dev) +{ + msleep(100); + return 0; +} + +static int pci_ni8420_init(struct pci_dev *dev) +{ + void __iomem *p; + unsigned long base, len; + unsigned int bar = 0; + + if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { + moan_device("no memory in bar", dev); + return 0; + } + + base = pci_resource_start(dev, bar); + len = pci_resource_len(dev, bar); + p = ioremap_nocache(base, len); + if (p == NULL) + return -ENOMEM; + + /* Enable CPU Interrupt */ + writel(readl(p + NI8420_INT_ENABLE_REG) | NI8420_INT_ENABLE_BIT, + p + NI8420_INT_ENABLE_REG); + + iounmap(p); + return 0; +} + +#define MITE_IOWBSR1_WSIZE 0xa +#define MITE_IOWBSR1_WIN_OFFSET 0x800 +#define MITE_IOWBSR1_WENAB (1 << 7) +#define MITE_LCIMR1_IO_IE_0 (1 << 24) +#define MITE_LCIMR2_SET_CPU_IE (1 << 31) +#define MITE_IOWCR1_RAMSEL_MASK 0xfffffffe + +static int pci_ni8430_init(struct pci_dev *dev) +{ + void __iomem *p; + unsigned long base, len; + u32 device_window; + unsigned int bar = 0; + + if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) { + moan_device("no memory in bar", dev); + return 0; + } + + base = pci_resource_start(dev, bar); + len = pci_resource_len(dev, bar); + p = ioremap_nocache(base, len); + if (p == NULL) + return -ENOMEM; + + /* Set device window address and size in BAR0 */ + device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00) + | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE; + writel(device_window, p + MITE_IOWBSR1); + + /* Set window access to go to RAMSEL IO address space */ + writel((readl(p + MITE_IOWCR1) & MITE_IOWCR1_RAMSEL_MASK), + p + MITE_IOWCR1); + + /* Enable IO Bus Interrupt 0 */ + writel(MITE_LCIMR1_IO_IE_0, p + MITE_LCIMR1); + + /* Enable CPU Interrupt */ + writel(MITE_LCIMR2_SET_CPU_IE, p + MITE_LCIMR2); + + iounmap(p); + return 0; +} + +/* UART Port Control Register */ +#define NI8430_PORTCON 0x0f +#define NI8430_PORTCON_TXVR_ENABLE (1 << 3) + +static int +pci_ni8430_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + void __iomem *p; + unsigned long base, len; + unsigned int bar, offset = board->first_offset; + + if (idx >= board->num_ports) + return 1; + + bar = FL_GET_BASE(board->flags); + offset += idx * board->uart_offset; + + base = pci_resource_start(priv->dev, bar); + len = pci_resource_len(priv->dev, bar); + p = ioremap_nocache(base, len); + + /* enable the transciever */ + writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE, + p + offset + NI8430_PORTCON); + + iounmap(p); + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + + +static int pci_netmos_init(struct pci_dev *dev) +{ + /* subdevice 0x00PS means

parallel, serial */ + unsigned int num_serial = dev->subsystem_device & 0xf; + + if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) || + (dev->device == PCI_DEVICE_ID_NETMOS_9865)) + return 0; + if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && + dev->subsystem_device == 0x0299) + return 0; + + if (num_serial == 0) + return -ENODEV; + return num_serial; +} + +/* + * These chips are available with optionally one parallel port and up to + * two serial ports. Unfortunately they all have the same product id. + * + * Basic configuration is done over a region of 32 I/O ports. The base + * ioport is called INTA or INTC, depending on docs/other drivers. + * + * The region of the 32 I/O ports is configured in POSIO0R... + */ + +/* registers */ +#define ITE_887x_MISCR 0x9c +#define ITE_887x_INTCBAR 0x78 +#define ITE_887x_UARTBAR 0x7c +#define ITE_887x_PS0BAR 0x10 +#define ITE_887x_POSIO0 0x60 + +/* I/O space size */ +#define ITE_887x_IOSIZE 32 +/* I/O space size (bits 26-24; 8 bytes = 011b) */ +#define ITE_887x_POSIO_IOSIZE_8 (3 << 24) +/* I/O space size (bits 26-24; 32 bytes = 101b) */ +#define ITE_887x_POSIO_IOSIZE_32 (5 << 24) +/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */ +#define ITE_887x_POSIO_SPEED (3 << 29) +/* enable IO_Space bit */ +#define ITE_887x_POSIO_ENABLE (1 << 31) + +static int pci_ite887x_init(struct pci_dev *dev) +{ + /* inta_addr are the configuration addresses of the ITE */ + static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, + 0x200, 0x280, 0 }; + int ret, i, type; + struct resource *iobase = NULL; + u32 miscr, uartbar, ioport; + + /* search for the base-ioport */ + i = 0; + while (inta_addr[i] && iobase == NULL) { + iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, + "ite887x"); + if (iobase != NULL) { + /* write POSIO0R - speed | size | ioport */ + pci_write_config_dword(dev, ITE_887x_POSIO0, + ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | + ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]); + /* write INTCBAR - ioport */ + pci_write_config_dword(dev, ITE_887x_INTCBAR, + inta_addr[i]); + ret = inb(inta_addr[i]); + if (ret != 0xff) { + /* ioport connected */ + break; + } + release_region(iobase->start, ITE_887x_IOSIZE); + iobase = NULL; + } + i++; + } + + if (!inta_addr[i]) { + printk(KERN_ERR "ite887x: could not find iobase\n"); + return -ENODEV; + } + + /* start of undocumented type checking (see parport_pc.c) */ + type = inb(iobase->start + 0x18) & 0x0f; + + switch (type) { + case 0x2: /* ITE8871 (1P) */ + case 0xa: /* ITE8875 (1P) */ + ret = 0; + break; + case 0xe: /* ITE8872 (2S1P) */ + ret = 2; + break; + case 0x6: /* ITE8873 (1S) */ + ret = 1; + break; + case 0x8: /* ITE8874 (2S) */ + ret = 2; + break; + default: + moan_device("Unknown ITE887x", dev); + ret = -ENODEV; + } + + /* configure all serial ports */ + for (i = 0; i < ret; i++) { + /* read the I/O port from the device */ + pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)), + &ioport); + ioport &= 0x0000FF00; /* the actual base address */ + pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)), + ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | + ITE_887x_POSIO_IOSIZE_8 | ioport); + + /* write the ioport to the UARTBAR */ + pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar); + uartbar &= ~(0xffff << (16 * i)); /* clear half the reg */ + uartbar |= (ioport << (16 * i)); /* set the ioport */ + pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar); + + /* get current config */ + pci_read_config_dword(dev, ITE_887x_MISCR, &miscr); + /* disable interrupts (UARTx_Routing[3:0]) */ + miscr &= ~(0xf << (12 - 4 * i)); + /* activate the UART (UARTx_En) */ + miscr |= 1 << (23 - i); + /* write new config with activated UART */ + pci_write_config_dword(dev, ITE_887x_MISCR, miscr); + } + + if (ret <= 0) { + /* the device has no UARTs if we get here */ + release_region(iobase->start, ITE_887x_IOSIZE); + } + + return ret; +} + +static void __devexit pci_ite887x_exit(struct pci_dev *dev) +{ + u32 ioport; + /* the ioport is bit 0-15 in POSIO0R */ + pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport); + ioport &= 0xffff; + release_region(ioport, ITE_887x_IOSIZE); +} + +/* + * Oxford Semiconductor Inc. + * Check that device is part of the Tornado range of devices, then determine + * the number of ports available on the device. + */ +static int pci_oxsemi_tornado_init(struct pci_dev *dev) +{ + u8 __iomem *p; + unsigned long deviceID; + unsigned int number_uarts = 0; + + /* OxSemi Tornado devices are all 0xCxxx */ + if (dev->vendor == PCI_VENDOR_ID_OXSEMI && + (dev->device & 0xF000) != 0xC000) + return 0; + + p = pci_iomap(dev, 0, 5); + if (p == NULL) + return -ENOMEM; + + deviceID = ioread32(p); + /* Tornado device */ + if (deviceID == 0x07000200) { + number_uarts = ioread8(p + 4); + printk(KERN_DEBUG + "%d ports detected on Oxford PCI Express device\n", + number_uarts); + } + pci_iounmap(dev, p); + return number_uarts; +} + +static int +pci_default_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + unsigned int bar, offset = board->first_offset, maxnr; + + bar = FL_GET_BASE(board->flags); + if (board->flags & FL_BASE_BARS) + bar += idx; + else + offset += idx * board->uart_offset; + + maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> + (board->reg_shift + 3); + + if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) + return 1; + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +static int +ce4100_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_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; + + return ret; +} + +static int skip_tx_en_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + port->flags |= UPF_NO_TXEN_TEST; + printk(KERN_DEBUG "serial8250: skipping TxEn test for device " + "[%04x:%04x] subsystem [%04x:%04x]\n", + priv->dev->vendor, + priv->dev->device, + priv->dev->subsystem_vendor, + priv->dev->subsystem_device); + + return pci_default_setup(priv, board, port, idx); +} + +/* This should be in linux/pci_ids.h */ +#define PCI_VENDOR_ID_SBSMODULARIO 0x124B +#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B +#define PCI_DEVICE_ID_OCTPRO 0x0001 +#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108 +#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208 +#define PCI_SUBDEVICE_ID_POCTAL232 0x0308 +#define PCI_SUBDEVICE_ID_POCTAL422 0x0408 +#define PCI_VENDOR_ID_ADVANTECH 0x13fe +#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 +#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 +#define PCI_DEVICE_ID_TITAN_200I 0x8028 +#define PCI_DEVICE_ID_TITAN_400I 0x8048 +#define PCI_DEVICE_ID_TITAN_800I 0x8088 +#define PCI_DEVICE_ID_TITAN_800EH 0xA007 +#define PCI_DEVICE_ID_TITAN_800EHB 0xA008 +#define PCI_DEVICE_ID_TITAN_400EH 0xA009 +#define PCI_DEVICE_ID_TITAN_100E 0xA010 +#define PCI_DEVICE_ID_TITAN_200E 0xA012 +#define PCI_DEVICE_ID_TITAN_400E 0xA013 +#define PCI_DEVICE_ID_TITAN_800E 0xA014 +#define PCI_DEVICE_ID_TITAN_200EI 0xA016 +#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 +#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 + +/* Unknown vendors/cards - this should not be in linux/pci_ids.h */ +#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 + +/* + * Master list of serial port init/setup/exit quirks. + * This does not describe the general nature of the port. + * (ie, baud base, number and location of ports, etc) + * + * This list is ordered alphabetically by vendor then device. + * Specific entries must come before more generic entries. + */ +static struct pci_serial_quirk pci_serial_quirks[] __refdata = { + /* + * ADDI-DATA GmbH communication cards + */ + { + .vendor = PCI_VENDOR_ID_ADDIDATA_OLD, + .device = PCI_DEVICE_ID_ADDIDATA_APCI7800, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = addidata_apci7800_setup, + }, + /* + * AFAVLAB cards - these may be called via parport_serial + * It is not clear whether this applies to all products. + */ + { + .vendor = PCI_VENDOR_ID_AFAVLAB, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = afavlab_setup, + }, + /* + * HP Diva + */ + { + .vendor = PCI_VENDOR_ID_HP, + .device = PCI_DEVICE_ID_HP_DIVA, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_hp_diva_init, + .setup = pci_hp_diva_setup, + }, + /* + * Intel + */ + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_80960_RP, + .subvendor = 0xe4bf, + .subdevice = PCI_ANY_ID, + .init = pci_inteli960ni_init, + .setup = pci_default_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_8257X_SOL, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = skip_tx_en_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82573L_SOL, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = skip_tx_en_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82573E_SOL, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = skip_tx_en_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_CE4100_UART, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = ce4100_serial_setup, + }, + /* + * ITE + */ + { + .vendor = PCI_VENDOR_ID_ITE, + .device = PCI_DEVICE_ID_ITE_8872, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ite887x_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ite887x_exit), + }, + /* + * National Instruments + */ + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI23216, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI2328, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI2324, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI2322, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI2324I, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI2322I, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8420_23216, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8420_2328, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8420_2324, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8420_2322, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8422_2324, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8422_2322, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8420_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_ni8420_exit), + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8430_setup, + .exit = __devexit_p(pci_ni8430_exit), + }, + /* + * Panacom + */ + { + .vendor = PCI_VENDOR_ID_PANACOM, + .device = PCI_DEVICE_ID_PANACOM_QUADMODEM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, + { + .vendor = PCI_VENDOR_ID_PANACOM, + .device = PCI_DEVICE_ID_PANACOM_DUALMODEM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, + /* + * PLX + */ + { + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_9030, + .subvendor = PCI_SUBVENDOR_ID_PERLE, + .subdevice = PCI_ANY_ID, + .setup = pci_default_setup, + }, + { + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_9050, + .subvendor = PCI_SUBVENDOR_ID_EXSYS, + .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, + { + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_9050, + .subvendor = PCI_SUBVENDOR_ID_KEYSPAN, + .subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, + { + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_9050, + .subvendor = PCI_VENDOR_ID_PLX, + .subdevice = PCI_SUBDEVICE_ID_UNKNOWN_0x1584, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, + { + .vendor = PCI_VENDOR_ID_PLX, + .device = PCI_DEVICE_ID_PLX_ROMULUS, + .subvendor = PCI_VENDOR_ID_PLX, + .subdevice = PCI_DEVICE_ID_PLX_ROMULUS, + .init = pci_plx9050_init, + .setup = pci_default_setup, + .exit = __devexit_p(pci_plx9050_exit), + }, + /* + * SBS Technologies, Inc., PMC-OCTALPRO 232 + */ + { + .vendor = PCI_VENDOR_ID_SBSMODULARIO, + .device = PCI_DEVICE_ID_OCTPRO, + .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, + .subdevice = PCI_SUBDEVICE_ID_OCTPRO232, + .init = sbs_init, + .setup = sbs_setup, + .exit = __devexit_p(sbs_exit), + }, + /* + * SBS Technologies, Inc., PMC-OCTALPRO 422 + */ + { + .vendor = PCI_VENDOR_ID_SBSMODULARIO, + .device = PCI_DEVICE_ID_OCTPRO, + .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, + .subdevice = PCI_SUBDEVICE_ID_OCTPRO422, + .init = sbs_init, + .setup = sbs_setup, + .exit = __devexit_p(sbs_exit), + }, + /* + * SBS Technologies, Inc., P-Octal 232 + */ + { + .vendor = PCI_VENDOR_ID_SBSMODULARIO, + .device = PCI_DEVICE_ID_OCTPRO, + .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, + .subdevice = PCI_SUBDEVICE_ID_POCTAL232, + .init = sbs_init, + .setup = sbs_setup, + .exit = __devexit_p(sbs_exit), + }, + /* + * SBS Technologies, Inc., P-Octal 422 + */ + { + .vendor = PCI_VENDOR_ID_SBSMODULARIO, + .device = PCI_DEVICE_ID_OCTPRO, + .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO, + .subdevice = PCI_SUBDEVICE_ID_POCTAL422, + .init = sbs_init, + .setup = sbs_setup, + .exit = __devexit_p(sbs_exit), + }, + /* + * SIIG cards - these may be called via parport_serial + */ + { + .vendor = PCI_VENDOR_ID_SIIG, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_siig_init, + .setup = pci_siig_setup, + }, + /* + * Titan cards + */ + { + .vendor = PCI_VENDOR_ID_TITAN, + .device = PCI_DEVICE_ID_TITAN_400L, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = titan_400l_800l_setup, + }, + { + .vendor = PCI_VENDOR_ID_TITAN, + .device = PCI_DEVICE_ID_TITAN_800L, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = titan_400l_800l_setup, + }, + /* + * Timedia cards + */ + { + .vendor = PCI_VENDOR_ID_TIMEDIA, + .device = PCI_DEVICE_ID_TIMEDIA_1889, + .subvendor = PCI_VENDOR_ID_TIMEDIA, + .subdevice = PCI_ANY_ID, + .init = pci_timedia_init, + .setup = pci_timedia_setup, + }, + { + .vendor = PCI_VENDOR_ID_TIMEDIA, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_timedia_setup, + }, + /* + * Xircom cards + */ + { + .vendor = PCI_VENDOR_ID_XIRCOM, + .device = PCI_DEVICE_ID_XIRCOM_X3201_MDM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_xircom_init, + .setup = pci_default_setup, + }, + /* + * Netmos cards - these may be called via parport_serial + */ + { + .vendor = PCI_VENDOR_ID_NETMOS, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_netmos_init, + .setup = pci_default_setup, + }, + /* + * For Oxford Semiconductor and Mainpine + */ + { + .vendor = PCI_VENDOR_ID_OXSEMI, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_default_setup, + }, + { + .vendor = PCI_VENDOR_ID_MAINPINE, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_oxsemi_tornado_init, + .setup = pci_default_setup, + }, + /* + * Default "match everything" terminator entry + */ + { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_default_setup, + } +}; + +static inline int quirk_id_matches(u32 quirk_id, u32 dev_id) +{ + return quirk_id == PCI_ANY_ID || quirk_id == dev_id; +} + +static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) +{ + struct pci_serial_quirk *quirk; + + for (quirk = pci_serial_quirks; ; quirk++) + if (quirk_id_matches(quirk->vendor, dev->vendor) && + quirk_id_matches(quirk->device, dev->device) && + quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) && + quirk_id_matches(quirk->subdevice, dev->subsystem_device)) + break; + return quirk; +} + +static inline int get_pci_irq(struct pci_dev *dev, + const struct pciserial_board *board) +{ + if (board->flags & FL_NOIRQ) + return 0; + else + return dev->irq; +} + +/* + * This is the configuration table for all of the PCI serial boards + * which we support. It is directly indexed by the pci_board_num_t enum + * value, which is encoded in the pci_device_id PCI probe table's + * driver_data member. + * + * The makeup of these names are: + * pbn_bn{_bt}_n_baud{_offsetinhex} + * + * bn = PCI BAR number + * bt = Index using PCI BARs + * n = number of serial ports + * baud = baud rate + * offsetinhex = offset for each sequential port (in hex) + * + * This table is sorted by (in order): bn, bt, baud, offsetindex, n. + * + * Please note: in theory if n = 1, _bt infix should make no difference. + * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200 + */ +enum pci_board_num_t { + pbn_default = 0, + + pbn_b0_1_115200, + pbn_b0_2_115200, + pbn_b0_4_115200, + pbn_b0_5_115200, + pbn_b0_8_115200, + + pbn_b0_1_921600, + pbn_b0_2_921600, + pbn_b0_4_921600, + + pbn_b0_2_1130000, + + pbn_b0_4_1152000, + + pbn_b0_2_1843200, + pbn_b0_4_1843200, + + pbn_b0_2_1843200_200, + pbn_b0_4_1843200_200, + pbn_b0_8_1843200_200, + + pbn_b0_1_4000000, + + pbn_b0_bt_1_115200, + pbn_b0_bt_2_115200, + pbn_b0_bt_4_115200, + pbn_b0_bt_8_115200, + + pbn_b0_bt_1_460800, + pbn_b0_bt_2_460800, + pbn_b0_bt_4_460800, + + pbn_b0_bt_1_921600, + pbn_b0_bt_2_921600, + pbn_b0_bt_4_921600, + pbn_b0_bt_8_921600, + + pbn_b1_1_115200, + pbn_b1_2_115200, + pbn_b1_4_115200, + pbn_b1_8_115200, + pbn_b1_16_115200, + + pbn_b1_1_921600, + pbn_b1_2_921600, + pbn_b1_4_921600, + pbn_b1_8_921600, + + pbn_b1_2_1250000, + + pbn_b1_bt_1_115200, + pbn_b1_bt_2_115200, + pbn_b1_bt_4_115200, + + pbn_b1_bt_2_921600, + + pbn_b1_1_1382400, + pbn_b1_2_1382400, + pbn_b1_4_1382400, + pbn_b1_8_1382400, + + pbn_b2_1_115200, + pbn_b2_2_115200, + pbn_b2_4_115200, + pbn_b2_8_115200, + + pbn_b2_1_460800, + pbn_b2_4_460800, + pbn_b2_8_460800, + pbn_b2_16_460800, + + pbn_b2_1_921600, + pbn_b2_4_921600, + pbn_b2_8_921600, + + pbn_b2_8_1152000, + + pbn_b2_bt_1_115200, + pbn_b2_bt_2_115200, + pbn_b2_bt_4_115200, + + pbn_b2_bt_2_921600, + pbn_b2_bt_4_921600, + + pbn_b3_2_115200, + pbn_b3_4_115200, + pbn_b3_8_115200, + + pbn_b4_bt_2_921600, + pbn_b4_bt_4_921600, + pbn_b4_bt_8_921600, + + /* + * Board-specific versions. + */ + pbn_panacom, + pbn_panacom2, + pbn_panacom4, + pbn_exsys_4055, + pbn_plx_romulus, + pbn_oxsemi, + pbn_oxsemi_1_4000000, + pbn_oxsemi_2_4000000, + pbn_oxsemi_4_4000000, + pbn_oxsemi_8_4000000, + pbn_intel_i960, + pbn_sgi_ioc3, + pbn_computone_4, + pbn_computone_6, + pbn_computone_8, + pbn_sbsxrsio, + pbn_exar_XR17C152, + pbn_exar_XR17C154, + pbn_exar_XR17C158, + pbn_exar_ibm_saturn, + pbn_pasemi_1682M, + pbn_ni8430_2, + pbn_ni8430_4, + pbn_ni8430_8, + pbn_ni8430_16, + pbn_ADDIDATA_PCIe_1_3906250, + pbn_ADDIDATA_PCIe_2_3906250, + pbn_ADDIDATA_PCIe_4_3906250, + pbn_ADDIDATA_PCIe_8_3906250, + pbn_ce4100_1_115200, +}; + +/* + * uart_offset - the space between channels + * reg_shift - describes how the UART registers are mapped + * to PCI memory by the card. + * For example IER register on SBS, Inc. PMC-OctPro is located at + * offset 0x10 from the UART base, while UART_IER is defined as 1 + * in include/linux/serial_reg.h, + * see first lines of serial_in() and serial_out() in 8250.c +*/ + +static struct pciserial_board pci_boards[] __devinitdata = { + [pbn_default] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_1_115200] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_2_115200] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_4_115200] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_5_115200] = { + .flags = FL_BASE0, + .num_ports = 5, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_8_115200] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_1_921600] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b0_2_921600] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b0_4_921600] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + + [pbn_b0_2_1130000] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 1130000, + .uart_offset = 8, + }, + + [pbn_b0_4_1152000] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1152000, + .uart_offset = 8, + }, + + [pbn_b0_2_1843200] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 1843200, + .uart_offset = 8, + }, + [pbn_b0_4_1843200] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1843200, + .uart_offset = 8, + }, + + [pbn_b0_2_1843200_200] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 1843200, + .uart_offset = 0x200, + }, + [pbn_b0_4_1843200_200] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1843200, + .uart_offset = 0x200, + }, + [pbn_b0_8_1843200_200] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 1843200, + .uart_offset = 0x200, + }, + [pbn_b0_1_4000000] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 4000000, + .uart_offset = 8, + }, + + [pbn_b0_bt_1_115200] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_bt_2_115200] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_bt_4_115200] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b0_bt_8_115200] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, + + [pbn_b0_bt_1_460800] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 1, + .base_baud = 460800, + .uart_offset = 8, + }, + [pbn_b0_bt_2_460800] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 460800, + .uart_offset = 8, + }, + [pbn_b0_bt_4_460800] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 460800, + .uart_offset = 8, + }, + + [pbn_b0_bt_1_921600] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b0_bt_2_921600] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b0_bt_4_921600] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b0_bt_8_921600] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 8, + }, + + [pbn_b1_1_115200] = { + .flags = FL_BASE1, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b1_2_115200] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b1_4_115200] = { + .flags = FL_BASE1, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b1_8_115200] = { + .flags = FL_BASE1, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b1_16_115200] = { + .flags = FL_BASE1, + .num_ports = 16, + .base_baud = 115200, + .uart_offset = 8, + }, + + [pbn_b1_1_921600] = { + .flags = FL_BASE1, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b1_2_921600] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b1_4_921600] = { + .flags = FL_BASE1, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b1_8_921600] = { + .flags = FL_BASE1, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b1_2_1250000] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 1250000, + .uart_offset = 8, + }, + + [pbn_b1_bt_1_115200] = { + .flags = FL_BASE1|FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b1_bt_2_115200] = { + .flags = FL_BASE1|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b1_bt_4_115200] = { + .flags = FL_BASE1|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + + [pbn_b1_bt_2_921600] = { + .flags = FL_BASE1|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + + [pbn_b1_1_1382400] = { + .flags = FL_BASE1, + .num_ports = 1, + .base_baud = 1382400, + .uart_offset = 8, + }, + [pbn_b1_2_1382400] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 1382400, + .uart_offset = 8, + }, + [pbn_b1_4_1382400] = { + .flags = FL_BASE1, + .num_ports = 4, + .base_baud = 1382400, + .uart_offset = 8, + }, + [pbn_b1_8_1382400] = { + .flags = FL_BASE1, + .num_ports = 8, + .base_baud = 1382400, + .uart_offset = 8, + }, + + [pbn_b2_1_115200] = { + .flags = FL_BASE2, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b2_2_115200] = { + .flags = FL_BASE2, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b2_4_115200] = { + .flags = FL_BASE2, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b2_8_115200] = { + .flags = FL_BASE2, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, + + [pbn_b2_1_460800] = { + .flags = FL_BASE2, + .num_ports = 1, + .base_baud = 460800, + .uart_offset = 8, + }, + [pbn_b2_4_460800] = { + .flags = FL_BASE2, + .num_ports = 4, + .base_baud = 460800, + .uart_offset = 8, + }, + [pbn_b2_8_460800] = { + .flags = FL_BASE2, + .num_ports = 8, + .base_baud = 460800, + .uart_offset = 8, + }, + [pbn_b2_16_460800] = { + .flags = FL_BASE2, + .num_ports = 16, + .base_baud = 460800, + .uart_offset = 8, + }, + + [pbn_b2_1_921600] = { + .flags = FL_BASE2, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b2_4_921600] = { + .flags = FL_BASE2, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b2_8_921600] = { + .flags = FL_BASE2, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 8, + }, + + [pbn_b2_8_1152000] = { + .flags = FL_BASE2, + .num_ports = 8, + .base_baud = 1152000, + .uart_offset = 8, + }, + + [pbn_b2_bt_1_115200] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b2_bt_2_115200] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b2_bt_4_115200] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + + [pbn_b2_bt_2_921600] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b2_bt_4_921600] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + + [pbn_b3_2_115200] = { + .flags = FL_BASE3, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b3_4_115200] = { + .flags = FL_BASE3, + .num_ports = 4, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_b3_8_115200] = { + .flags = FL_BASE3, + .num_ports = 8, + .base_baud = 115200, + .uart_offset = 8, + }, + + [pbn_b4_bt_2_921600] = { + .flags = FL_BASE4, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b4_bt_4_921600] = { + .flags = FL_BASE4, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b4_bt_8_921600] = { + .flags = FL_BASE4, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 8, + }, + + /* + * Entries following this are board-specific. + */ + + /* + * Panacom - IOMEM + */ + [pbn_panacom] = { + .flags = FL_BASE2, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x400, + .reg_shift = 7, + }, + [pbn_panacom2] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x400, + .reg_shift = 7, + }, + [pbn_panacom4] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x400, + .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, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8 << 2, + .reg_shift = 2, + .first_offset = 0x03, + }, + + /* + * This board uses the size of PCI Base region 0 to + * signal now many ports are available + */ + [pbn_oxsemi] = { + .flags = FL_BASE0|FL_REGION_SZ_CAP, + .num_ports = 32, + .base_baud = 115200, + .uart_offset = 8, + }, + [pbn_oxsemi_1_4000000] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_oxsemi_2_4000000] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_oxsemi_4_4000000] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_oxsemi_8_4000000] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + + + /* + * EKF addition for i960 Boards form EKF with serial port. + * Max 256 ports. + */ + [pbn_intel_i960] = { + .flags = FL_BASE0, + .num_ports = 32, + .base_baud = 921600, + .uart_offset = 8 << 2, + .reg_shift = 2, + .first_offset = 0x10000, + }, + [pbn_sgi_ioc3] = { + .flags = FL_BASE0|FL_NOIRQ, + .num_ports = 1, + .base_baud = 458333, + .uart_offset = 8, + .reg_shift = 0, + .first_offset = 0x20178, + }, + + /* + * Computone - uses IOMEM. + */ + [pbn_computone_4] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x40, + .reg_shift = 2, + .first_offset = 0x200, + }, + [pbn_computone_6] = { + .flags = FL_BASE0, + .num_ports = 6, + .base_baud = 921600, + .uart_offset = 0x40, + .reg_shift = 2, + .first_offset = 0x200, + }, + [pbn_computone_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x40, + .reg_shift = 2, + .first_offset = 0x200, + }, + [pbn_sbsxrsio] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 460800, + .uart_offset = 256, + .reg_shift = 4, + }, + /* + * Exar Corp. XR17C15[248] Dual/Quad/Octal UART + * Only basic 16550A support. + * XR17C15[24] are not tested, but they should work. + */ + [pbn_exar_XR17C152] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_XR17C154] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_XR17C158] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_exar_ibm_saturn] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 0x200, + }, + + /* + * PA Semi PWRficient PA6T-1682M on-chip UART + */ + [pbn_pasemi_1682M] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 8333333, + }, + /* + * National Instruments 843x + */ + [pbn_ni8430_16] = { + .flags = FL_BASE0, + .num_ports = 16, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8430_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8430_4] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8430_2] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + /* + * ADDI-DATA GmbH PCI-Express communication cards + */ + [pbn_ADDIDATA_PCIe_1_3906250] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 3906250, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_ADDIDATA_PCIe_2_3906250] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 3906250, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_ADDIDATA_PCIe_4_3906250] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 3906250, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_ADDIDATA_PCIe_8_3906250] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 3906250, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_ce4100_1_115200] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .reg_shift = 2, + }, +}; + +static const struct pci_device_id softmodem_blacklist[] = { + { 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 */ +}; + +/* + * Given a complete unknown PCI device, try to use some heuristics to + * guess what the configuration might be, based on the pitiful PCI + * serial specs. Returns 0 on success, 1 on failure. + */ +static int __devinit +serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) +{ + const struct pci_device_id *blacklist; + int num_iomem, num_port, first_port = -1, i; + + /* + * If it is not a communications device or the programming + * interface is greater than 6, give up. + * + * (Should we try to make guesses for multiport serial devices + * later?) + */ + if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || + (dev->class & 0xff) > 6) + return -ENODEV; + + /* + * Do not access blacklisted devices that are known not to + * feature serial ports. + */ + for (blacklist = softmodem_blacklist; + blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist); + blacklist++) { + if (dev->vendor == blacklist->vendor && + dev->device == blacklist->device) + return -ENODEV; + } + + num_iomem = num_port = 0; + for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { + if (pci_resource_flags(dev, i) & IORESOURCE_IO) { + num_port++; + if (first_port == -1) + first_port = i; + } + if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + num_iomem++; + } + + /* + * If there is 1 or 0 iomem regions, and exactly one port, + * use it. We guess the number of ports based on the IO + * region size. + */ + if (num_iomem <= 1 && num_port == 1) { + board->flags = first_port; + board->num_ports = pci_resource_len(dev, first_port) / 8; + return 0; + } + + /* + * Now guess if we've got a board which indexes by BARs. + * Each IO BAR should be 8 bytes, and they should follow + * consecutively. + */ + first_port = -1; + num_port = 0; + for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { + if (pci_resource_flags(dev, i) & IORESOURCE_IO && + pci_resource_len(dev, i) == 8 && + (first_port == -1 || (first_port + num_port) == i)) { + num_port++; + if (first_port == -1) + first_port = i; + } + } + + if (num_port > 1) { + board->flags = first_port | FL_BASE_BARS; + board->num_ports = num_port; + return 0; + } + + return -ENODEV; +} + +static inline int +serial_pci_matches(const struct pciserial_board *board, + const struct pciserial_board *guessed) +{ + return + board->num_ports == guessed->num_ports && + board->base_baud == guessed->base_baud && + board->uart_offset == guessed->uart_offset && + board->reg_shift == guessed->reg_shift && + board->first_offset == guessed->first_offset; +} + +struct serial_private * +pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) +{ + struct uart_port serial_port; + struct serial_private *priv; + struct pci_serial_quirk *quirk; + int rc, nr_ports, i; + + nr_ports = board->num_ports; + + /* + * Find an init and setup quirks. + */ + quirk = find_quirk(dev); + + /* + * Run the new-style initialization function. + * The initialization function returns: + * <0 - error + * 0 - use board->num_ports + * >0 - number of ports + */ + if (quirk->init) { + rc = quirk->init(dev); + if (rc < 0) { + priv = ERR_PTR(rc); + goto err_out; + } + if (rc) + nr_ports = rc; + } + + priv = kzalloc(sizeof(struct serial_private) + + sizeof(unsigned int) * nr_ports, + GFP_KERNEL); + if (!priv) { + priv = ERR_PTR(-ENOMEM); + goto err_deinit; + } + + 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; + + for (i = 0; i < nr_ports; i++) { + if (quirk->setup(priv, board, &serial_port, 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); +#endif + + priv->line[i] = serial8250_register_port(&serial_port); + if (priv->line[i] < 0) { + printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); + break; + } + } + priv->nr = i; + return priv; + +err_deinit: + if (quirk->exit) + quirk->exit(dev); +err_out: + return priv; +} +EXPORT_SYMBOL_GPL(pciserial_init_ports); + +void pciserial_remove_ports(struct serial_private *priv) +{ + struct pci_serial_quirk *quirk; + int i; + + for (i = 0; i < priv->nr; i++) + serial8250_unregister_port(priv->line[i]); + + for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { + if (priv->remapped_bar[i]) + iounmap(priv->remapped_bar[i]); + priv->remapped_bar[i] = NULL; + } + + /* + * Find the exit quirks. + */ + quirk = find_quirk(priv->dev); + if (quirk->exit) + quirk->exit(priv->dev); + + kfree(priv); +} +EXPORT_SYMBOL_GPL(pciserial_remove_ports); + +void pciserial_suspend_ports(struct serial_private *priv) +{ + int i; + + for (i = 0; i < priv->nr; i++) + if (priv->line[i] >= 0) + serial8250_suspend_port(priv->line[i]); +} +EXPORT_SYMBOL_GPL(pciserial_suspend_ports); + +void pciserial_resume_ports(struct serial_private *priv) +{ + int i; + + /* + * Ensure that the board is correctly configured. + */ + if (priv->quirk->init) + priv->quirk->init(priv->dev); + + for (i = 0; i < priv->nr; i++) + if (priv->line[i] >= 0) + serial8250_resume_port(priv->line[i]); +} +EXPORT_SYMBOL_GPL(pciserial_resume_ports); + +/* + * Probe one serial board. Unfortunately, there is no rhyme nor reason + * to the arrangement of serial ports on a PCI card. + */ +static int __devinit +pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct serial_private *priv; + const struct pciserial_board *board; + struct pciserial_board tmp; + int rc; + + if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { + printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", + ent->driver_data); + return -EINVAL; + } + + board = &pci_boards[ent->driver_data]; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + if (ent->driver_data == pbn_default) { + /* + * Use a copy of the pci_board entry for this; + * avoid changing entries in the table. + */ + memcpy(&tmp, board, sizeof(struct pciserial_board)); + board = &tmp; + + /* + * We matched one of our class entries. Try to + * determine the parameters of this board. + */ + rc = serial_pci_guess_board(dev, &tmp); + if (rc) + goto disable; + } else { + /* + * We matched an explicit entry. If we are able to + * detect this boards settings with our heuristic, + * then we no longer need this entry. + */ + memcpy(&tmp, &pci_boards[pbn_default], + sizeof(struct pciserial_board)); + rc = serial_pci_guess_board(dev, &tmp); + if (rc == 0 && serial_pci_matches(board, &tmp)) + moan_device("Redundant entry in serial pci_table.", + dev); + } + + priv = pciserial_init_ports(dev, board); + if (!IS_ERR(priv)) { + pci_set_drvdata(dev, priv); + return 0; + } + + rc = PTR_ERR(priv); + + disable: + pci_disable_device(dev); + return rc; +} + +static void __devexit pciserial_remove_one(struct pci_dev *dev) +{ + struct serial_private *priv = pci_get_drvdata(dev); + + pci_set_drvdata(dev, NULL); + + pciserial_remove_ports(priv); + + pci_disable_device(dev); +} + +#ifdef CONFIG_PM +static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) +{ + struct serial_private *priv = pci_get_drvdata(dev); + + if (priv) + pciserial_suspend_ports(priv); + + pci_save_state(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + return 0; +} + +static int pciserial_resume_one(struct pci_dev *dev) +{ + int err; + struct serial_private *priv = pci_get_drvdata(dev); + + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + + if (priv) { + /* + * The device may have been disabled. Re-enable it. + */ + err = pci_enable_device(dev); + /* FIXME: We cannot simply error out here */ + if (err) + printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); + pciserial_resume_ports(priv); + } + return 0; +} +#endif + +static struct pci_device_id serial_pci_tbl[] = { + /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ + { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, + PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, + pbn_b2_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, + pbn_b1_8_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, + pbn_b1_4_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, + pbn_b1_2_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, + pbn_b1_8_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, + pbn_b1_4_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, + pbn_b1_2_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0, + pbn_b1_4_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0, + pbn_b1_4_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0, + pbn_b1_2_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, + pbn_b1_4_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0, + pbn_b1_2_1250000 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0, + pbn_b0_2_1843200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0, + pbn_b0_4_1843200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_AFAVLAB, + PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0, + pbn_b0_4_1152000 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT, + 0, 0, pbn_exar_ibm_saturn }, + + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_1_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_460800 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_115200 }, + + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_921600 }, + /* + * VScom SPCOM800, from sl@s.pl + */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_921600 }, + /* Unknown card - subdevice 0x1584 */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_PLX, + PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_KEYSPAN, + PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, + pbn_panacom }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_panacom4 }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_panacom2 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_VENDOR_ID_ESDGMBH, + PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, + pbn_b2_4_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, + pbn_b2_8_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, + pbn_b2_16_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, + pbn_b2_16_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, + pbn_b2_4_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, + pbn_b2_8_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_EXSYS, + PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0, + pbn_exsys_4055 }, + /* + * Megawolf Romulus PCI Serial Card, from Mike Hudson + * (Exoray@isys.ca) + */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, + 0x10b5, 0x106a, 0, 0, + pbn_plx_romulus }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL, + 0, 0, + pbn_b0_4_1152000 }, + { PCI_VENDOR_ID_OXSEMI, 0x9505, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, + + /* + * The below card is a little controversial since it is the + * subject of a PCI vendor/device ID clash. (See + * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html). + * For now just used the hex ID 0x950a. + */ + { PCI_VENDOR_ID_OXSEMI, 0x950a, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_OXSEMI, 0x950a, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_2_1130000 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, + PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958, + PCI_ANY_ID , PCI_ANY_ID, 0, 0, + pbn_b2_8_1152000 }, + + /* + * Oxford Semiconductor Inc. Tornado PCI express device range. + */ + { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_4_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_4_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_8_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_8_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */ + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + /* + * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado + */ + { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */ + PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */ + PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */ + PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0, + pbn_oxsemi_4_4000000 }, + { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */ + PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0, + pbn_oxsemi_8_4000000 }, + /* + * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards, + * from skokodyn@yahoo.com + */ + { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0, + pbn_sbsxrsio }, + { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0, + pbn_sbsxrsio }, + { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0, + pbn_sbsxrsio }, + { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0, + pbn_sbsxrsio }, + + /* + * Digitan DS560-558, from jimd@esoft.com + */ + { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_115200 }, + + /* + * Titan Electronic cards + * The 400L and 800L have a custom setup quirk. + */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_8_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_4_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_8_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_460800 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_460800 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_460800 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_921600 }, + + /* + * Computone devices submitted by Doug McNash dmcnash@computone.com + */ + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, + 0, 0, pbn_computone_4 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, + 0, 0, pbn_computone_8 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, + 0, 0, pbn_computone_6 }, + + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_921600 }, + + /* + * AFAVLAB serial card, from Harald Welte + */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_460800 }, + + /* + * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408). + * Cards are identified by their subsystem vendor IDs, which + * (in hex) match the model number. + * + * Note that JC140x are RS422/485 cards which require ox950 + * ACR = 0x10, and as such are not currently fully supported. + */ + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1204, 0x0004, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1208, 0x0004, 0, 0, + pbn_b0_4_921600 }, +/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1402, 0x0002, 0, 0, + pbn_b0_2_921600 }, */ +/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1404, 0x0004, 0, 0, + pbn_b0_4_921600 }, */ + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1, + 0x1208, 0x0004, 0, 0, + pbn_b0_4_921600 }, + + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, + 0x1204, 0x0004, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, + 0x1208, 0x0004, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3, + 0x1208, 0x0004, 0, 0, + pbn_b0_4_921600 }, + /* + * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com + */ + { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_1382400 }, + + /* + * Dell Remote Access Card III - Tim_T_Murphy@Dell.com + */ + { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_1382400 }, + + /* + * RAStel 2 port modem, gerg@moreton.com.au + */ + { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + + /* + * EKF addition for i960 Boards form EKF with serial port + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP, + 0xE4BF, PCI_ANY_ID, 0, 0, + pbn_intel_i960 }, + + /* + * Xircom Cardbus/Ethernet combos + */ + { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_115200 }, + /* + * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry) + */ + { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_115200 }, + + /* + * Untested PCI modems, sent in from various folks... + */ + + /* + * Elsa Model 56K PCI Modem, from Andreas Rath + */ + { PCI_VENDOR_ID_ROCKWELL, 0x1004, + 0x1048, 0x1500, 0, 0, + pbn_b1_1_115200 }, + + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, + 0xFF00, 0, 0, 0, + pbn_sgi_ioc3 }, + + /* + * HP Diva card + */ + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA, + PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0, + pbn_b1_1_115200 }, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_5_115200 }, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_115200 }, + + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b3_2_115200 }, + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b3_4_115200 }, + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b3_8_115200 }, + + /* + * Exar Corp. XR17C15[248] Dual/Quad/Octal UART + */ + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C152 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C154 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17C158 }, + + /* + * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) + */ + { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_115200 }, + /* + * ITE + */ + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b1_bt_1_115200 }, + + /* + * IntaShield IS-200 + */ + { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */ + pbn_b2_2_115200 }, + /* + * IntaShield IS-400 + */ + { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ + pbn_b2_4_115200 }, + /* + * Perle PCI-RAS cards + */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4, + 0, 0, pbn_b2_4_921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, + PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8, + 0, 0, pbn_b2_8_921600 }, + + /* + * Mainpine series cards: Fairly standard layout but fools + * parts of the autodetect in some cases and uses otherwise + * unmatched communications subclasses in the PCI Express case + */ + + { /* RockForceDUO */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0200, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceQUATRO */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0300, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceDUO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0400, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceQUATRO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0500, + 0, 0, pbn_b0_4_115200 }, + { /* RockForce+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0600, + 0, 0, pbn_b0_2_115200 }, + { /* RockForce+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0700, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceOCTO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0800, + 0, 0, pbn_b0_8_115200 }, + { /* RockForceDUO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0C00, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceQUARTRO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0D00, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceOCTO+ */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x1D00, + 0, 0, pbn_b0_8_115200 }, + { /* RockForceD1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2000, + 0, 0, pbn_b0_1_115200 }, + { /* RockForceF1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2100, + 0, 0, pbn_b0_1_115200 }, + { /* RockForceD2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2200, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceF2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2300, + 0, 0, pbn_b0_2_115200 }, + { /* RockForceD4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2400, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceF4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2500, + 0, 0, pbn_b0_4_115200 }, + { /* RockForceD8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2600, + 0, 0, pbn_b0_8_115200 }, + { /* RockForceF8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2700, + 0, 0, pbn_b0_8_115200 }, + { /* IQ Express D1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3000, + 0, 0, pbn_b0_1_115200 }, + { /* IQ Express F1 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3100, + 0, 0, pbn_b0_1_115200 }, + { /* IQ Express D2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3200, + 0, 0, pbn_b0_2_115200 }, + { /* IQ Express F2 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3300, + 0, 0, pbn_b0_2_115200 }, + { /* IQ Express D4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3400, + 0, 0, pbn_b0_4_115200 }, + { /* IQ Express F4 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3500, + 0, 0, pbn_b0_4_115200 }, + { /* IQ Express D8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3C00, + 0, 0, pbn_b0_8_115200 }, + { /* IQ Express F8 */ + PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3D00, + 0, 0, pbn_b0_8_115200 }, + + + /* + * PA Semi PA6T-1682M on-chip UART + */ + { PCI_VENDOR_ID_PASEMI, 0xa004, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pasemi_1682M }, + + /* + * National Instruments + */ + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_16_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_4_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_2_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_4_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_2_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_16_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_4_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_2_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_4_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_bt_2_115200 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_2 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_2 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_4 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_4 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_8 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_8 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_16 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_16 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_2 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_2 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_4 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_4 }, + + /* + * ADDI-DATA GmbH communication cards + */ + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7500, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7420, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7300, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_ADDIDATA_OLD, + PCI_DEVICE_ID_ADDIDATA_APCI7800, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b1_8_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7500_2, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7420_2, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7300_2, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7500_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_4_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7420_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_2_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7300_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCI7800_3, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_b0_8_115200 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCIe7500, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_ADDIDATA_PCIe_4_3906250 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCIe7420, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_ADDIDATA_PCIe_2_3906250 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCIe7300, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_ADDIDATA_PCIe_1_3906250 }, + + { PCI_VENDOR_ID_ADDIDATA, + PCI_DEVICE_ID_ADDIDATA_APCIe7800, + PCI_ANY_ID, + PCI_ANY_ID, + 0, + 0, + pbn_ADDIDATA_PCIe_8_3906250 }, + + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, + PCI_VENDOR_ID_IBM, 0x0299, + 0, 0, pbn_b0_bt_2_115200 }, + + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, + 0xA000, 0x1000, + 0, 0, pbn_b0_1_115200 }, + + /* + * Best Connectivity PCI Multi I/O cards + */ + + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x1000, + 0, 0, pbn_b0_1_115200 }, + + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x3004, + 0, 0, pbn_b0_bt_4_115200 }, + /* Intel CE4100 */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ce4100_1_115200 }, + + + /* + * These entries match devices with class COMMUNICATION_SERIAL, + * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL + */ + { PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, + 0xffff00, pbn_default }, + { PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MODEM << 8, + 0xffff00, pbn_default }, + { PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, + 0xffff00, pbn_default }, + { 0, } +}; + +static struct pci_driver serial_pci_driver = { + .name = "serial", + .probe = pciserial_init_one, + .remove = __devexit_p(pciserial_remove_one), +#ifdef CONFIG_PM + .suspend = pciserial_suspend_one, + .resume = pciserial_resume_one, +#endif + .id_table = serial_pci_tbl, +}; + +static int __init serial8250_pci_init(void) +{ + return pci_register_driver(&serial_pci_driver); +} + +static void __exit serial8250_pci_exit(void) +{ + pci_unregister_driver(&serial_pci_driver); +} + +module_init(serial8250_pci_init); +module_exit(serial8250_pci_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); +MODULE_DEVICE_TABLE(pci, serial_pci_tbl); diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c new file mode 100644 index 000000000000..4822cb50cd0f --- /dev/null +++ b/drivers/tty/serial/8250_pnp.c @@ -0,0 +1,523 @@ +/* + * linux/drivers/char/8250_pnp.c + * + * Probe module for 8250/16550-type ISAPNP serial ports. + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * Ported to the Linux PnP Layer - (C) Adam Belay. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "8250.h" + +#define UNKNOWN_DEV 0x3000 + + +static const struct pnp_device_id pnp_dev_table[] = { + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { "AAC000F", 0 }, + /* Anchor Datacomm BV */ + /* SXPro 144 External Data Fax Modem Plug & Play */ + { "ADC0001", 0 }, + /* SXPro 288 External Data Fax Modem Plug & Play */ + { "ADC0002", 0 }, + /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */ + { "AEI0250", 0 }, + /* Actiontec ISA PNP 56K X2 Fax Modem */ + { "AEI1240", 0 }, + /* Rockwell 56K ACF II Fax+Data+Voice Modem */ + { "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ }, + /* AZT3005 PnP SOUND DEVICE */ + { "AZT4001", 0 }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { "BDP3336", 0 }, + /* Boca Research */ + /* Boca Complete Ofc Communicator 14.4 Data-FAX */ + { "BRI0A49", 0 }, + /* Boca Research 33,600 ACF Modem */ + { "BRI1400", 0 }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { "BRI3400", 0 }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { "BRI0A49", 0 }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { "BDP3336", 0 }, + /* Computer Peripherals Inc */ + /* EuroViVa CommCenter-33.6 SP PnP */ + { "CPI4050", 0 }, + /* Creative Labs */ + /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ + { "CTL3001", 0 }, + /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ + { "CTL3011", 0 }, + /* Davicom ISA 33.6K Modem */ + { "DAV0336", 0 }, + /* Creative */ + /* Creative Modem Blaster Flash56 DI5601-1 */ + { "DMB1032", 0 }, + /* Creative Modem Blaster V.90 DI5660 */ + { "DMB2001", 0 }, + /* E-Tech */ + /* E-Tech CyberBULLET PC56RVP */ + { "ETT0002", 0 }, + /* FUJITSU */ + /* Fujitsu 33600 PnP-I2 R Plug & Play */ + { "FUJ0202", 0 }, + /* Fujitsu FMV-FX431 Plug & Play */ + { "FUJ0205", 0 }, + /* Fujitsu 33600 PnP-I4 R Plug & Play */ + { "FUJ0206", 0 }, + /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ + { "FUJ0209", 0 }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { "GVC000F", 0 }, + /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */ + { "GVC0303", 0 }, + /* Hayes */ + /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ + { "HAY0001", 0 }, + /* Hayes Optima 336 V.34 + FAX + Voice PnP */ + { "HAY000C", 0 }, + /* Hayes Optima 336B V.34 + FAX + Voice PnP */ + { "HAY000D", 0 }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { "HAY5670", 0 }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { "HAY5674", 0 }, + /* Hayes Accura 56K Fax Modem PnP */ + { "HAY5675", 0 }, + /* Hayes 288, V.34 + FAX */ + { "HAYF000", 0 }, + /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ + { "HAYF001", 0 }, + /* IBM */ + /* IBM Thinkpad 701 Internal Modem Voice */ + { "IBM0033", 0 }, + /* Intertex */ + /* Intertex 28k8 33k6 Voice EXT PnP */ + { "IXDC801", 0 }, + /* Intertex 33k6 56k Voice EXT PnP */ + { "IXDC901", 0 }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { "IXDD801", 0 }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { "IXDD901", 0 }, + /* Intertex 28k8 33k6 Voice SP INT PnP */ + { "IXDF401", 0 }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { "IXDF801", 0 }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { "IXDF901", 0 }, + /* Kortex International */ + /* KORTEX 28800 Externe PnP */ + { "KOR4522", 0 }, + /* KXPro 33.6 Vocal ASVD PnP */ + { "KORF661", 0 }, + /* Lasat */ + /* LASAT Internet 33600 PnP */ + { "LAS4040", 0 }, + /* Lasat Safire 560 PnP */ + { "LAS4540", 0 }, + /* Lasat Safire 336 PnP */ + { "LAS5440", 0 }, + /* Microcom, Inc. */ + /* Microcom TravelPorte FAST V.34 Plug & Play */ + { "MNP0281", 0 }, + /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ + { "MNP0336", 0 }, + /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ + { "MNP0339", 0 }, + /* Microcom DeskPorte 28.8P Plug & Play */ + { "MNP0342", 0 }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { "MNP0500", 0 }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { "MNP0501", 0 }, + /* Microcom DeskPorte 28.8S Internal Plug & Play */ + { "MNP0502", 0 }, + /* Motorola */ + /* Motorola BitSURFR Plug & Play */ + { "MOT1105", 0 }, + /* Motorola TA210 Plug & Play */ + { "MOT1111", 0 }, + /* Motorola HMTA 200 (ISDN) Plug & Play */ + { "MOT1114", 0 }, + /* Motorola BitSURFR Plug & Play */ + { "MOT1115", 0 }, + /* Motorola Lifestyle 28.8 Internal */ + { "MOT1190", 0 }, + /* Motorola V.3400 Plug & Play */ + { "MOT1501", 0 }, + /* Motorola Lifestyle 28.8 V.34 Plug & Play */ + { "MOT1502", 0 }, + /* Motorola Power 28.8 V.34 Plug & Play */ + { "MOT1505", 0 }, + /* Motorola ModemSURFR External 28.8 Plug & Play */ + { "MOT1509", 0 }, + /* Motorola Premier 33.6 Desktop Plug & Play */ + { "MOT150A", 0 }, + /* Motorola VoiceSURFR 56K External PnP */ + { "MOT150F", 0 }, + /* Motorola ModemSURFR 56K External PnP */ + { "MOT1510", 0 }, + /* Motorola ModemSURFR 56K Internal PnP */ + { "MOT1550", 0 }, + /* Motorola ModemSURFR Internal 28.8 Plug & Play */ + { "MOT1560", 0 }, + /* Motorola Premier 33.6 Internal Plug & Play */ + { "MOT1580", 0 }, + /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ + { "MOT15B0", 0 }, + /* Motorola VoiceSURFR 56K Internal PnP */ + { "MOT15F0", 0 }, + /* Com 1 */ + /* Deskline K56 Phone System PnP */ + { "MVX00A1", 0 }, + /* PC Rider K56 Phone System PnP */ + { "MVX00F2", 0 }, + /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */ + { "nEC8241", 0 }, + /* Pace 56 Voice Internal Plug & Play Modem */ + { "PMC2430", 0 }, + /* Generic */ + /* Generic standard PC COM port */ + { "PNP0500", 0 }, + /* Generic 16550A-compatible COM port */ + { "PNP0501", 0 }, + /* Compaq 14400 Modem */ + { "PNPC000", 0 }, + /* Compaq 2400/9600 Modem */ + { "PNPC001", 0 }, + /* Dial-Up Networking Serial Cable between 2 PCs */ + { "PNPC031", 0 }, + /* Dial-Up Networking Parallel Cable between 2 PCs */ + { "PNPC032", 0 }, + /* Standard 9600 bps Modem */ + { "PNPC100", 0 }, + /* Standard 14400 bps Modem */ + { "PNPC101", 0 }, + /* Standard 28800 bps Modem*/ + { "PNPC102", 0 }, + /* Standard Modem*/ + { "PNPC103", 0 }, + /* Standard 9600 bps Modem*/ + { "PNPC104", 0 }, + /* Standard 14400 bps Modem*/ + { "PNPC105", 0 }, + /* Standard 28800 bps Modem*/ + { "PNPC106", 0 }, + /* Standard Modem */ + { "PNPC107", 0 }, + /* Standard 9600 bps Modem */ + { "PNPC108", 0 }, + /* Standard 14400 bps Modem */ + { "PNPC109", 0 }, + /* Standard 28800 bps Modem */ + { "PNPC10A", 0 }, + /* Standard Modem */ + { "PNPC10B", 0 }, + /* Standard 9600 bps Modem */ + { "PNPC10C", 0 }, + /* Standard 14400 bps Modem */ + { "PNPC10D", 0 }, + /* Standard 28800 bps Modem */ + { "PNPC10E", 0 }, + /* Standard Modem */ + { "PNPC10F", 0 }, + /* Standard PCMCIA Card Modem */ + { "PNP2000", 0 }, + /* Rockwell */ + /* Modular Technology */ + /* Rockwell 33.6 DPF Internal PnP */ + /* Modular Technology 33.6 Internal PnP */ + { "ROK0030", 0 }, + /* Kortex International */ + /* KORTEX 14400 Externe PnP */ + { "ROK0100", 0 }, + /* Rockwell 28.8 */ + { "ROK4120", 0 }, + /* Viking Components, Inc */ + /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ + { "ROK4920", 0 }, + /* Rockwell */ + /* British Telecom */ + /* Modular Technology */ + /* Rockwell 33.6 DPF External PnP */ + /* BT Prologue 33.6 External PnP */ + /* Modular Technology 33.6 External PnP */ + { "RSS00A0", 0 }, + /* Viking 56K FAX INT */ + { "RSS0262", 0 }, + /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */ + { "RSS0250", 0 }, + /* SupraExpress 28.8 Data/Fax PnP modem */ + { "SUP1310", 0 }, + /* SupraExpress 336i PnP Voice Modem */ + { "SUP1381", 0 }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { "SUP1421", 0 }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { "SUP1590", 0 }, + /* SupraExpress 336i Sp ASVD */ + { "SUP1620", 0 }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { "SUP1760", 0 }, + /* SupraExpress 56i Sp Intl */ + { "SUP2171", 0 }, + /* Phoebe Micro */ + /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ + { "TEX0011", 0 }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { "UAC000F", 0 }, + /* 3Com Corp. */ + /* Gateway Telepath IIvi 33.6 */ + { "USR0000", 0 }, + /* U.S. Robotics Sporster 33.6K Fax INT PnP */ + { "USR0002", 0 }, + /* Sportster Vi 14.4 PnP FAX Voicemail */ + { "USR0004", 0 }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { "USR0006", 0 }, + /* U.S. Robotics 33.6K Voice EXT PnP */ + { "USR0007", 0 }, + /* U.S. Robotics Courier V.Everything INT PnP */ + { "USR0009", 0 }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { "USR2002", 0 }, + /* U.S. Robotics 56K Voice INT PnP */ + { "USR2070", 0 }, + /* U.S. Robotics 56K Voice EXT PnP */ + { "USR2080", 0 }, + /* U.S. Robotics 56K FAX INT */ + { "USR3031", 0 }, + /* U.S. Robotics 56K FAX INT */ + { "USR3050", 0 }, + /* U.S. Robotics 56K Voice INT PnP */ + { "USR3070", 0 }, + /* U.S. Robotics 56K Voice EXT PnP */ + { "USR3080", 0 }, + /* U.S. Robotics 56K Voice INT PnP */ + { "USR3090", 0 }, + /* U.S. Robotics 56K Message */ + { "USR9100", 0 }, + /* U.S. Robotics 56K FAX EXT PnP*/ + { "USR9160", 0 }, + /* U.S. Robotics 56K FAX INT PnP*/ + { "USR9170", 0 }, + /* U.S. Robotics 56K Voice EXT PnP*/ + { "USR9180", 0 }, + /* U.S. Robotics 56K Voice INT PnP*/ + { "USR9190", 0 }, + /* Wacom tablets */ + { "WACFXXX", 0 }, + /* Compaq touchscreen */ + { "FPI2002", 0 }, + /* Fujitsu Stylistic touchscreens */ + { "FUJ02B2", 0 }, + { "FUJ02B3", 0 }, + /* Fujitsu Stylistic LT touchscreens */ + { "FUJ02B4", 0 }, + /* Passive Fujitsu Stylistic touchscreens */ + { "FUJ02B6", 0 }, + { "FUJ02B7", 0 }, + { "FUJ02B8", 0 }, + { "FUJ02B9", 0 }, + { "FUJ02BC", 0 }, + /* Fujitsu Wacom Tablet PC device */ + { "FUJ02E5", 0 }, + /* Fujitsu P-series tablet PC device */ + { "FUJ02E6", 0 }, + /* Fujitsu Wacom 2FGT Tablet PC device */ + { "FUJ02E7", 0 }, + /* Fujitsu Wacom 1FGT Tablet PC device */ + { "FUJ02E9", 0 }, + /* + * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in + * disguise) + */ + { "LTS0001", 0 }, + /* Rockwell's (PORALiNK) 33600 INT PNP */ + { "WCI0003", 0 }, + /* Unknown PnP modems */ + { "PNPCXXX", UNKNOWN_DEV }, + /* More unknown PnP modems */ + { "PNPDXXX", UNKNOWN_DEV }, + { "", 0 } +}; + +MODULE_DEVICE_TABLE(pnp, pnp_dev_table); + +static char *modem_names[] __devinitdata = { + "MODEM", "Modem", "modem", "FAX", "Fax", "fax", + "56K", "56k", "K56", "33.6", "28.8", "14.4", + "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", + "33600", "28800", "14400", "V.90", "V.34", "V.32", NULL +}; + +static int __devinit check_name(char *name) +{ + char **tmp; + + for (tmp = modem_names; *tmp; tmp++) + if (strstr(name, *tmp)) + return 1; + + return 0; +} + +static int __devinit check_resources(struct pnp_dev *dev) +{ + resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8}; + int i; + + for (i = 0; i < ARRAY_SIZE(base); i++) { + if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8)) + return 1; + } + + return 0; +} + +/* + * Given a complete unknown PnP device, try to use some heuristics to + * detect modems. Currently use such heuristic set: + * - dev->name or dev->bus->name must contain "modem" substring; + * - device must have only one IO region (8 byte long) with base address + * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. + * + * Such detection looks very ugly, but can detect at least some of numerous + * PnP modems, alternatively we must hardcode all modems in pnp_devices[] + * table. + */ +static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) +{ + if (!(check_name(pnp_dev_name(dev)) || + (dev->card && check_name(dev->card->name)))) + return -ENODEV; + + if (check_resources(dev)) + return 0; + + return -ENODEV; +} + +static int __devinit +serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) +{ + struct uart_port port; + int ret, line, flags = dev_id->driver_data; + + if (flags & UNKNOWN_DEV) { + ret = serial_pnp_guess_board(dev, &flags); + if (ret < 0) + return ret; + } + + memset(&port, 0, sizeof(struct uart_port)); + if (pnp_irq_valid(dev, 0)) + port.irq = pnp_irq(dev, 0); + if (pnp_port_valid(dev, 0)) { + port.iobase = pnp_port_start(dev, 0); + 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; + } 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); +#endif + + 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; + + line = serial8250_register_port(&port); + if (line < 0) + return -ENODEV; + + pnp_set_drvdata(dev, (void *)((long)line + 1)); + return 0; +} + +static void __devexit serial_pnp_remove(struct pnp_dev *dev) +{ + long line = (long)pnp_get_drvdata(dev); + if (line) + serial8250_unregister_port(line - 1); +} + +#ifdef CONFIG_PM +static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state) +{ + long line = (long)pnp_get_drvdata(dev); + + if (!line) + return -ENODEV; + serial8250_suspend_port(line - 1); + return 0; +} + +static int serial_pnp_resume(struct pnp_dev *dev) +{ + long line = (long)pnp_get_drvdata(dev); + + if (!line) + return -ENODEV; + serial8250_resume_port(line - 1); + return 0; +} +#else +#define serial_pnp_suspend NULL +#define serial_pnp_resume NULL +#endif /* CONFIG_PM */ + +static struct pnp_driver serial_pnp_driver = { + .name = "serial", + .probe = serial_pnp_probe, + .remove = __devexit_p(serial_pnp_remove), + .suspend = serial_pnp_suspend, + .resume = serial_pnp_resume, + .id_table = pnp_dev_table, +}; + +static int __init serial8250_pnp_init(void) +{ + return pnp_register_driver(&serial_pnp_driver); +} + +static void __exit serial8250_pnp_exit(void) +{ + pnp_unregister_driver(&serial_pnp_driver); +} + +module_init(serial8250_pnp_init); +module_exit(serial8250_pnp_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver"); diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig new file mode 100644 index 000000000000..c1df7676a73d --- /dev/null +++ b/drivers/tty/serial/Kconfig @@ -0,0 +1,1598 @@ +# +# Serial device configuration +# + +menu "Serial drivers" + depends on HAS_IOMEM + +# +# The new 8250/16550 serial drivers +config SERIAL_8250 + tristate "8250/16550 and compatible serial support" + select SERIAL_CORE + ---help--- + This selects whether you want to include the driver for the standard + serial ports. The standard answer is Y. People who might say N + here are those that are setting up dedicated Ethernet WWW/FTP + servers, or users that have one of the various bus mice instead of a + serial mouse and don't intend to use their machine's standard serial + port for anything. (Note that the Cyclades and Stallion multi + serial port drivers do not need this driver built in for them to + work.) + + To compile this driver as a module, choose M here: the + module will be called 8250. + [WARNING: Do not compile this driver as a module if you are using + non-standard serial ports, since the configuration information will + be lost when the driver is unloaded. This limitation may be lifted + in the future.] + + BTW1: If you have a mouseman serial mouse which is not recognized by + the X window system, try running gpm first. + + BTW2: If you intend to use a software modem (also called Winmodem) + under Linux, forget it. These modems are crippled and require + proprietary drivers which are only available under Windows. + + Most people will say Y or M here, so that they can use serial mice, + modems and similar devices connecting to the standard serial ports. + +config SERIAL_8250_CONSOLE + bool "Console on 8250/16550 and compatible serial port" + depends on SERIAL_8250=y + select SERIAL_CORE_CONSOLE + ---help--- + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). This could be useful if some terminal or printer is connected + to that serial port. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyS1". (Try "man bootparam" or see the documentation of + your boot loader (grub or lilo or loadlin) about how to pass options + to the kernel at boot time.) + + If you don't have a VGA card installed and you say Y here, the + kernel will automatically use the first serial line, /dev/ttyS0, as + system console. + + You can set that using a kernel command line option such as + "console=uart8250,io,0x3f8,9600n8" + "console=uart8250,mmio,0xff5e0000,115200n8". + and it will switch to normal serial console when the corresponding + port is ready. + "earlycon=uart8250,io,0x3f8,9600n8" + "earlycon=uart8250,mmio,0xff5e0000,115200n8". + it will not only setup early console. + + If unsure, say N. + +config FIX_EARLYCON_MEM + bool + depends on X86 + default y + +config SERIAL_8250_GSC + tristate + depends on SERIAL_8250 && GSC + default SERIAL_8250 + +config SERIAL_8250_PCI + tristate "8250/16550 PCI device support" if EMBEDDED + depends on SERIAL_8250 && PCI + default SERIAL_8250 + help + This builds standard PCI serial support. You may be able to + disable this feature if you only need legacy serial support. + Saves about 9K. + +config SERIAL_8250_PNP + tristate "8250/16550 PNP device support" if EMBEDDED + depends on SERIAL_8250 && PNP + default SERIAL_8250 + help + This builds standard PNP serial support. You may be able to + disable this feature if you only need legacy serial support. + +config SERIAL_8250_HP300 + tristate + depends on SERIAL_8250 && HP300 + default SERIAL_8250 + +config SERIAL_8250_CS + tristate "8250/16550 PCMCIA device support" + depends on PCMCIA && SERIAL_8250 + ---help--- + Say Y here to enable support for 16-bit PCMCIA serial devices, + including serial port cards, modems, and the modem functions of + multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are + credit-card size devices often used with laptops.) + + To compile this driver as a module, choose M here: the + module will be called serial_cs. + + If unsure, say N. + +config SERIAL_8250_NR_UARTS + int "Maximum number of 8250/16550 serial ports" + depends on SERIAL_8250 + default "4" + help + Set this to the number of serial ports you want the driver + to support. This includes any ports discovered via ACPI or + PCI enumeration and any ports that may be added at run-time + via hot-plug, or any ISA multi-port serial cards. + +config SERIAL_8250_RUNTIME_UARTS + int "Number of 8250/16550 serial ports to register at runtime" + depends on SERIAL_8250 + range 0 SERIAL_8250_NR_UARTS + default "4" + help + Set this to the maximum number of serial ports you want + the kernel to register at boot time. This can be overridden + with the module parameter "nr_uarts", or boot-time parameter + 8250.nr_uarts + +config SERIAL_8250_EXTENDED + bool "Extended 8250/16550 serial driver options" + depends on SERIAL_8250 + help + If you wish to use any non-standard features of the standard "dumb" + driver, say Y here. This includes HUB6 support, shared serial + interrupts, special multiport support, support for more than the + four COM 1/2/3/4 boards, etc. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about serial driver options. If unsure, say N. + +config SERIAL_8250_MANY_PORTS + bool "Support more than 4 legacy serial ports" + depends on SERIAL_8250_EXTENDED && !IA64 + help + Say Y here if you have dumb serial boards other than the four + standard COM 1/2/3/4 ports. This may happen if you have an AST + FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available + from ), or other custom + serial port hardware which acts similar to standard serial port + hardware. If you only use the standard COM 1/2/3/4 ports, you can + say N here to save some memory. You can also say Y if you have an + "intelligent" multiport card such as Cyclades, Digiboards, etc. + +# +# Multi-port serial cards +# + +config SERIAL_8250_FOURPORT + tristate "Support Fourport cards" + depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS + help + Say Y here if you have an AST FourPort serial board. + + To compile this driver as a module, choose M here: the module + will be called 8250_fourport. + +config SERIAL_8250_ACCENT + tristate "Support Accent cards" + depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS + help + Say Y here if you have an Accent Async serial board. + + To compile this driver as a module, choose M here: the module + will be called 8250_accent. + +config SERIAL_8250_BOCA + tristate "Support Boca cards" + depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS + help + Say Y here if you have a Boca serial board. Please read the Boca + mini-HOWTO, available from + + To compile this driver as a module, choose M here: the module + will be called 8250_boca. + +config SERIAL_8250_EXAR_ST16C554 + tristate "Support Exar ST16C554/554D Quad UART" + depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS + help + The Uplogix Envoy TU301 uses this Exar Quad UART. If you are + tinkering with your Envoy TU301, or have a machine with this UART, + say Y here. + + To compile this driver as a module, choose M here: the module + will be called 8250_exar_st16c554. + +config SERIAL_8250_HUB6 + tristate "Support Hub6 cards" + depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS + help + Say Y here if you have a HUB6 serial board. + + To compile this driver as a module, choose M here: the module + will be called 8250_hub6. + +config SERIAL_8250_SHARE_IRQ + bool "Support for sharing serial interrupts" + depends on SERIAL_8250_EXTENDED + help + Some serial boards have hardware support which allows multiple dumb + serial ports on the same board to share a single IRQ. To enable + support for this in the serial driver, say Y here. + +config SERIAL_8250_DETECT_IRQ + bool "Autodetect IRQ on standard ports (unsafe)" + depends on SERIAL_8250_EXTENDED + help + Say Y here if you want the kernel to try to guess which IRQ + to use for your serial port. + + This is considered unsafe; it is far better to configure the IRQ in + a boot script using the setserial command. + + If unsure, say N. + +config SERIAL_8250_RSA + bool "Support RSA serial ports" + depends on SERIAL_8250_EXTENDED + help + ::: To be written ::: + +config SERIAL_8250_MCA + tristate "Support 8250-type ports on MCA buses" + depends on SERIAL_8250 != n && MCA + help + Say Y here if you have a MCA serial ports. + + To compile this driver as a module, choose M here: the module + will be called 8250_mca. + +config SERIAL_8250_ACORN + tristate "Acorn expansion card serial port support" + depends on ARCH_ACORN && SERIAL_8250 + help + If you have an Atomwide Serial card or Serial Port card for an Acorn + system, say Y to this option. The driver can handle 1, 2, or 3 port + cards. If unsure, say N. + +config SERIAL_8250_RM9K + bool "Support for MIPS RM9xxx integrated serial port" + depends on SERIAL_8250 != n && SERIAL_RM9000 + select SERIAL_8250_SHARE_IRQ + help + Selecting this option will add support for the integrated serial + port hardware found on MIPS RM9122 and similar processors. + If unsure, say N. + +comment "Non-8250 serial port support" + +config SERIAL_AMBA_PL010 + tristate "ARM AMBA PL010 serial port support" + depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) + select SERIAL_CORE + help + This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have + an Integrator/AP or Integrator/PP2 platform, or if you have a + Cirrus Logic EP93xx CPU, say Y or M here. + + If unsure, say N. + +config SERIAL_AMBA_PL010_CONSOLE + bool "Support for console on AMBA serial port" + depends on SERIAL_AMBA_PL010=y + select SERIAL_CORE_CONSOLE + ---help--- + Say Y here if you wish to use an AMBA PrimeCell UART as the system + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyAM0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_AMBA_PL011 + tristate "ARM AMBA PL011 serial port support" + depends on ARM_AMBA + select SERIAL_CORE + help + This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have + an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M + here. + + If unsure, say N. + +config SERIAL_AMBA_PL011_CONSOLE + bool "Support for console on AMBA serial port" + depends on SERIAL_AMBA_PL011=y + select SERIAL_CORE_CONSOLE + ---help--- + Say Y here if you wish to use an AMBA PrimeCell UART as the system + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyAMA0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_SB1250_DUART + tristate "BCM1xxx on-chip DUART serial support" + depends on SIBYTE_SB1xxx_SOC=y + select SERIAL_CORE + default y + ---help--- + Support for the asynchronous serial interface (DUART) included in + the BCM1250 and derived System-On-a-Chip (SOC) devices. Note that + the letter D in DUART stands for "dual", which is how the device + is implemented. Depending on the SOC configuration there may be + one or more DUARTs available of which all are handled. + + If unsure, say Y. To compile this driver as a module, choose M here: + the module will be called sb1250-duart. + +config SERIAL_SB1250_DUART_CONSOLE + bool "Support for console on a BCM1xxx DUART serial port" + depends on SERIAL_SB1250_DUART=y + select SERIAL_CORE_CONSOLE + default y + ---help--- + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + If unsure, say Y. + +config SERIAL_ATMEL + bool "AT91 / AT32 on-chip serial port support" + depends on (ARM && ARCH_AT91) || AVR32 + select SERIAL_CORE + help + This enables the driver for the on-chip UARTs of the Atmel + AT91 and AT32 processors. + +config SERIAL_ATMEL_CONSOLE + bool "Support for console on AT91 / AT32 serial port" + depends on SERIAL_ATMEL=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use an on-chip UART on a Atmel + AT91 or AT32 processor as the system console (the system + console is the device which receives all kernel messages and + warnings and which allows logins in single user mode). + +config SERIAL_ATMEL_PDC + bool "Support DMA transfers on AT91 / AT32 serial port" + depends on SERIAL_ATMEL + default y + help + Say Y here if you wish to use the PDC to do DMA transfers to + and from the Atmel AT91 / AT32 serial port. In order to + actually use DMA transfers, make sure that the use_dma_tx + and use_dma_rx members in the atmel_uart_data struct is set + appropriately for each port. + + Note that break and error handling currently doesn't work + properly when DMA is enabled. Make sure that ports where + this matters don't use DMA. + +config SERIAL_ATMEL_TTYAT + bool "Install as device ttyATn instead of ttySn" + depends on SERIAL_ATMEL=y + help + Say Y here if you wish to have the internal AT91 / AT32 UARTs + appear as /dev/ttyATn (major 204, minor starting at 154) + instead of the normal /dev/ttySn (major 4, minor starting at + 64). This is necessary if you also want other UARTs, such as + external 8250/16C550 compatible UARTs. + The ttySn nodes are legally reserved for the 8250 serial driver + but are often misused by other serial drivers. + + To use this, you should create suitable ttyATn device nodes in + /dev/, and pass "console=ttyATn" to the kernel. + + Say Y if you have an external 8250/16C550 UART. If unsure, say N. + +config SERIAL_KS8695 + bool "Micrel KS8695 (Centaur) serial port support" + depends on ARCH_KS8695 + select SERIAL_CORE + help + This selects the Micrel Centaur KS8695 UART. Say Y here. + +config SERIAL_KS8695_CONSOLE + bool "Support for console on KS8695 (Centaur) serial port" + depends on SERIAL_KS8695=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use a KS8695 (Centaur) UART as the + system console (the system console is the device which + receives all kernel messages and warnings and which allows + logins in single user mode). + +config SERIAL_CLPS711X + tristate "CLPS711X serial port support" + depends on ARM && ARCH_CLPS711X + select SERIAL_CORE + help + ::: To be written ::: + +config SERIAL_CLPS711X_CONSOLE + bool "Support for console on CLPS711X serial port" + depends on SERIAL_CLPS711X=y + select SERIAL_CORE_CONSOLE + help + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyCL1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_SAMSUNG + tristate "Samsung SoC serial support" + depends on ARM && PLAT_SAMSUNG + select SERIAL_CORE + help + Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, + providing /dev/ttySAC0, 1 and 2 (note, some machines may not + provide all of these ports, depending on how the serial port + pins are configured. + +config SERIAL_SAMSUNG_UARTS_4 + bool + depends on ARM && PLAT_SAMSUNG + default y if CPU_S3C2443 + help + Internal node for the common case of 4 Samsung compatible UARTs + +config SERIAL_SAMSUNG_UARTS + int + depends on ARM && PLAT_SAMSUNG + default 2 if ARCH_S3C2400 + default 6 if ARCH_S5P6450 + default 4 if SERIAL_SAMSUNG_UARTS_4 + default 3 + help + Select the number of available UART ports for the Samsung S3C + serial driver + +config SERIAL_SAMSUNG_DEBUG + bool "Samsung SoC serial debug" + depends on SERIAL_SAMSUNG && DEBUG_LL + help + Add support for debugging the serial driver. Since this is + generally being used as a console, we use our own output + routines that go via the low-level debug printascii() + function. + +config SERIAL_SAMSUNG_CONSOLE + bool "Support for console on Samsung SoC serial port" + depends on SERIAL_SAMSUNG=y + select SERIAL_CORE_CONSOLE + help + Allow selection of the S3C24XX on-board serial ports for use as + an virtual console. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySACx". (Try "man bootparam" or see the documentation of + your boot loader about how to pass options to the kernel at + boot time.) + +config SERIAL_S3C2400 + tristate "Samsung S3C2410 Serial port support" + depends on ARM && SERIAL_SAMSUNG && CPU_S3C2400 + default y if CPU_S3C2400 + help + Serial port support for the Samsung S3C2400 SoC + +config SERIAL_S3C2410 + tristate "Samsung S3C2410 Serial port support" + depends on SERIAL_SAMSUNG && CPU_S3C2410 + default y if CPU_S3C2410 + help + Serial port support for the Samsung S3C2410 SoC + +config SERIAL_S3C2412 + tristate "Samsung S3C2412/S3C2413 Serial port support" + depends on SERIAL_SAMSUNG && CPU_S3C2412 + default y if CPU_S3C2412 + help + Serial port support for the Samsung S3C2412 and S3C2413 SoC + +config SERIAL_S3C2440 + tristate "Samsung S3C2440/S3C2442/S3C2416 Serial port support" + depends on SERIAL_SAMSUNG && (CPU_S3C2440 || CPU_S3C2442 || CPU_S3C2416) + default y if CPU_S3C2440 + default y if CPU_S3C2442 + select SERIAL_SAMSUNG_UARTS_4 if CPU_S3C2416 + help + Serial port support for the Samsung S3C2440, S3C2416 and S3C2442 SoC + +config SERIAL_S3C24A0 + tristate "Samsung S3C24A0 Serial port support" + depends on SERIAL_SAMSUNG && CPU_S3C24A0 + default y if CPU_S3C24A0 + help + Serial port support for the Samsung S3C24A0 SoC + +config SERIAL_S3C6400 + tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support" + depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100) + select SERIAL_SAMSUNG_UARTS_4 + default y + help + Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450 + and S5PC100 SoCs + +config SERIAL_S5PV210 + tristate "Samsung S5PV210 Serial port support" + depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310) + select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310) + default y + help + Serial port support for Samsung's S5P Family of SoC's + + +config SERIAL_MAX3100 + tristate "MAX3100 support" + depends on SPI + select SERIAL_CORE + help + MAX3100 chip support + +config SERIAL_MAX3107 + tristate "MAX3107 support" + depends on SPI + select SERIAL_CORE + help + MAX3107 chip support + +config SERIAL_MAX3107_AAVA + tristate "MAX3107 AAVA platform support" + depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB + select SERIAL_CORE + help + Support for the MAX3107 chip configuration found on the AAVA + platform. Includes the extra initialisation and GPIO support + neded for this device. + +config SERIAL_DZ + bool "DECstation DZ serial driver" + depends on MACH_DECSTATION && 32BIT + select SERIAL_CORE + default y + ---help--- + DZ11-family serial controllers for DECstations and VAXstations, + including the DC7085, M7814, and M7819. + +config SERIAL_DZ_CONSOLE + bool "Support console on DECstation DZ serial driver" + depends on SERIAL_DZ=y + select SERIAL_CORE_CONSOLE + default y + ---help--- + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + Note that the firmware uses ttyS3 as the serial console on + DECstations that use this driver. + + If unsure, say Y. + +config SERIAL_ZS + tristate "DECstation Z85C30 serial support" + depends on MACH_DECSTATION + select SERIAL_CORE + default y + ---help--- + Support for the Zilog 85C350 serial communications controller used + for serial ports in newer DECstation systems. These include the + DECsystem 5900 and all models of the DECstation and DECsystem 5000 + systems except from model 200. + + If unsure, say Y. To compile this driver as a module, choose M here: + the module will be called zs. + +config SERIAL_ZS_CONSOLE + bool "Support for console on a DECstation Z85C30 serial port" + depends on SERIAL_ZS=y + select SERIAL_CORE_CONSOLE + default y + ---help--- + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + Note that the firmware uses ttyS1 as the serial console on the + Maxine and ttyS3 on the others using this driver. + + If unsure, say Y. + +config SERIAL_21285 + tristate "DC21285 serial port support" + depends on ARM && FOOTBRIDGE + select SERIAL_CORE + help + If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ + PCI bridge you can enable its onboard serial port by enabling this + option. + +config SERIAL_21285_CONSOLE + bool "Console on DC21285 serial port" + depends on SERIAL_21285=y + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the 21285 footbridge you can + make it the console by answering Y to this option. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyFB". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_MPSC + bool "Marvell MPSC serial port support" + depends on PPC32 && MV64X60 + select SERIAL_CORE + help + Say Y here if you want to use the Marvell MPSC serial controller. + +config SERIAL_MPSC_CONSOLE + bool "Support for console on Marvell MPSC serial port" + depends on SERIAL_MPSC + select SERIAL_CORE_CONSOLE + help + Say Y here if you want to support a serial console on a Marvell MPSC. + +config SERIAL_PXA + bool "PXA serial port support" + depends on ARCH_PXA || ARCH_MMP + select SERIAL_CORE + help + If you have a machine based on an Intel XScale PXA2xx CPU you + can enable its onboard serial ports by enabling this option. + +config SERIAL_PXA_CONSOLE + bool "Console on PXA serial port" + depends on SERIAL_PXA + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Intel XScale PXA + CPU you can make it the console by answering Y to this option. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySA0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_SA1100 + bool "SA1100 serial port support" + depends on ARM && ARCH_SA1100 + select SERIAL_CORE + help + If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you + can enable its onboard serial port by enabling this option. + Please read for further + info. + +config SERIAL_SA1100_CONSOLE + bool "Console on SA1100 serial port" + depends on SERIAL_SA1100 + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the SA1100/SA1110 StrongARM + CPU you can make it the console by answering Y to this option. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySA0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_MRST_MAX3110 + tristate "SPI UART driver for Max3110" + depends on SPI_DW_PCI + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + help + This is the UART protocol driver for the MAX3110 device on + the Intel Moorestown platform. On other systems use the max3100 + driver. + +config SERIAL_MFD_HSU + tristate "Medfield High Speed UART support" + depends on PCI + select SERIAL_CORE + +config SERIAL_MFD_HSU_CONSOLE + boolean "Medfile HSU serial console support" + depends on SERIAL_MFD_HSU=y + select SERIAL_CORE_CONSOLE + +config SERIAL_BFIN + tristate "Blackfin serial port support" + depends on BLACKFIN + select SERIAL_CORE + select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561) + help + Add support for the built-in UARTs on the Blackfin. + + To compile this driver as a module, choose M here: the + module will be called bfin_5xx. + +config SERIAL_BFIN_CONSOLE + bool "Console on Blackfin serial port" + depends on SERIAL_BFIN=y + select SERIAL_CORE_CONSOLE + +choice + prompt "UART Mode" + depends on SERIAL_BFIN + default SERIAL_BFIN_DMA + help + This driver supports the built-in serial ports of the Blackfin family + of CPUs + +config SERIAL_BFIN_DMA + bool "DMA mode" + depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n + help + This driver works under DMA mode. If this option is selected, the + blackfin simple dma driver is also enabled. + +config SERIAL_BFIN_PIO + bool "PIO mode" + help + This driver works under PIO mode. + +endchoice + +config SERIAL_BFIN_UART0 + bool "Enable UART0" + depends on SERIAL_BFIN + help + Enable UART0 + +config BFIN_UART0_CTSRTS + bool "Enable UART0 hardware flow control" + depends on SERIAL_BFIN_UART0 + help + Enable hardware flow control in the driver. + +config SERIAL_BFIN_UART1 + bool "Enable UART1" + depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561) + help + Enable UART1 + +config BFIN_UART1_CTSRTS + bool "Enable UART1 hardware flow control" + depends on SERIAL_BFIN_UART1 + help + Enable hardware flow control in the driver. + +config SERIAL_BFIN_UART2 + bool "Enable UART2" + depends on SERIAL_BFIN && (BF54x || BF538 || BF539) + help + Enable UART2 + +config BFIN_UART2_CTSRTS + bool "Enable UART2 hardware flow control" + depends on SERIAL_BFIN_UART2 + help + Enable hardware flow control in the driver. + +config SERIAL_BFIN_UART3 + bool "Enable UART3" + depends on SERIAL_BFIN && (BF54x) + help + Enable UART3 + +config BFIN_UART3_CTSRTS + bool "Enable UART3 hardware flow control" + depends on SERIAL_BFIN_UART3 + help + Enable hardware flow control in the driver. + +config SERIAL_IMX + bool "IMX serial port support" + depends on ARM && (ARCH_IMX || ARCH_MXC) + select SERIAL_CORE + select RATIONAL + help + If you have a machine based on a Motorola IMX CPU you + can enable its onboard serial port by enabling this option. + +config SERIAL_IMX_CONSOLE + bool "Console on IMX serial port" + depends on SERIAL_IMX + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Motorola IMX + CPU you can make it the console by answering Y to this option. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySA0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_UARTLITE + tristate "Xilinx uartlite serial port support" + depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE + select SERIAL_CORE + help + Say Y here if you want to use the Xilinx uartlite serial controller. + + To compile this driver as a module, choose M here: the + module will be called uartlite. + +config SERIAL_UARTLITE_CONSOLE + bool "Support for console on Xilinx uartlite serial port" + depends on SERIAL_UARTLITE=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use a Xilinx uartlite as the system + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + +config SERIAL_SUNCORE + bool + depends on SPARC + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + default y + +config SERIAL_SUNZILOG + tristate "Sun Zilog8530 serial support" + depends on SPARC + help + This driver supports the Zilog8530 serial ports found on many Sparc + systems. Say Y or M if you want to be able to these serial ports. + +config SERIAL_SUNZILOG_CONSOLE + bool "Console on Sun Zilog8530 serial port" + depends on SERIAL_SUNZILOG=y + help + If you would like to be able to use the Zilog8530 serial port + on your Sparc system as the console, you can do so by answering + Y to this option. + +config SERIAL_SUNSU + tristate "Sun SU serial support" + depends on SPARC && PCI + help + This driver supports the 8250 serial ports that run the keyboard and + mouse on (PCI) UltraSPARC systems. Say Y or M if you want to be able + to these serial ports. + +config SERIAL_SUNSU_CONSOLE + bool "Console on Sun SU serial port" + depends on SERIAL_SUNSU=y + help + If you would like to be able to use the SU serial port + on your Sparc system as the console, you can do so by answering + Y to this option. + +config SERIAL_MUX + tristate "Serial MUX support" + depends on GSC + select SERIAL_CORE + default y + ---help--- + Saying Y here will enable the hardware MUX serial driver for + the Nova, K class systems and D class with a 'remote control card'. + The hardware MUX is not 8250/16550 compatible therefore the + /dev/ttyB0 device is shared between the Serial MUX and the PDC + software console. The following steps need to be completed to use + the Serial MUX: + + 1. create the device entry (mknod /dev/ttyB0 c 11 0) + 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 + 3. Add device ttyB0 to /etc/securetty (if you want to log on as + root on this console.) + 4. Change the kernel command console parameter to: console=ttyB0 + +config SERIAL_MUX_CONSOLE + bool "Support for console on serial MUX" + depends on SERIAL_MUX=y + select SERIAL_CORE_CONSOLE + default y + +config PDC_CONSOLE + bool "PDC software console support" + depends on PARISC && !SERIAL_MUX && VT + default n + help + Saying Y here will enable the software based PDC console to be + used as the system console. This is useful for machines in + which the hardware based console has not been written yet. The + following steps must be competed to use the PDC console: + + 1. create the device entry (mknod /dev/ttyB0 c 11 0) + 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 + 3. Add device ttyB0 to /etc/securetty (if you want to log on as + root on this console.) + 4. Change the kernel command console parameter to: console=ttyB0 + +config SERIAL_SUNSAB + tristate "Sun Siemens SAB82532 serial support" + depends on SPARC && PCI + help + This driver supports the Siemens SAB82532 DUSCC serial ports on newer + (PCI) UltraSPARC systems. Say Y or M if you want to be able to these + serial ports. + +config SERIAL_SUNSAB_CONSOLE + bool "Console on Sun Siemens SAB82532 serial port" + depends on SERIAL_SUNSAB=y + help + If you would like to be able to use the SAB82532 serial port + on your Sparc system as the console, you can do so by answering + Y to this option. + +config SERIAL_SUNHV + bool "Sun4v Hypervisor Console support" + depends on SPARC64 + help + This driver supports the console device found on SUN4V Sparc + systems. Say Y if you want to be able to use this device. + +config SERIAL_IP22_ZILOG + tristate "SGI Zilog8530 serial support" + depends on SGI_HAS_ZILOG + select SERIAL_CORE + help + This driver supports the Zilog8530 serial ports found on SGI + systems. Say Y or M if you want to be able to these serial ports. + +config SERIAL_IP22_ZILOG_CONSOLE + bool "Console on SGI Zilog8530 serial port" + depends on SERIAL_IP22_ZILOG=y + select SERIAL_CORE_CONSOLE + +config SERIAL_SH_SCI + tristate "SuperH SCI(F) serial port support" + depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE) + select SERIAL_CORE + +config SERIAL_SH_SCI_NR_UARTS + int "Maximum number of SCI(F) serial ports" + depends on SERIAL_SH_SCI + default "2" + +config SERIAL_SH_SCI_CONSOLE + bool "Support for console on SuperH SCI(F)" + depends on SERIAL_SH_SCI=y + select SERIAL_CORE_CONSOLE + +config SERIAL_SH_SCI_DMA + bool "DMA support" + depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL + +config SERIAL_PNX8XXX + bool "Enable PNX8XXX SoCs' UART Support" + depends on MIPS && (SOC_PNX8550 || SOC_PNX833X) + select SERIAL_CORE + help + If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 + and you want to use serial ports, say Y. Otherwise, say N. + +config SERIAL_PNX8XXX_CONSOLE + bool "Enable PNX8XX0 serial console" + depends on SERIAL_PNX8XXX + select SERIAL_CORE_CONSOLE + help + 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_CORE + tristate + +config SERIAL_CORE_CONSOLE + bool + +config CONSOLE_POLL + bool + +config SERIAL_68328 + bool "68328 serial support" + depends on M68328 || M68EZ328 || M68VZ328 + help + This driver supports the built-in serial port of the Motorola 68328 + (standard, EZ and VZ varieties). + +config SERIAL_68328_RTS_CTS + bool "Support RTS/CTS on 68328 serial port" + depends on SERIAL_68328 + +config SERIAL_MCF + bool "Coldfire serial support" + depends on COLDFIRE + select SERIAL_CORE + help + This serial driver supports the Freescale Coldfire serial ports. + +config SERIAL_MCF_BAUDRATE + int "Default baudrate for Coldfire serial ports" + depends on SERIAL_MCF + default 19200 + help + This setting lets you define what the default baudrate is for the + ColdFire serial ports. The usual default varies from board to board, + and this setting is a way of catering for that. + +config SERIAL_MCF_CONSOLE + bool "Coldfire serial console support" + depends on SERIAL_MCF + select SERIAL_CORE_CONSOLE + help + Enable a ColdFire internal serial port to be the system console. + +config SERIAL_68360_SMC + bool "68360 SMC uart support" + depends on M68360 + help + This driver supports the SMC serial ports of the Motorola 68360 CPU. + +config SERIAL_68360_SCC + bool "68360 SCC uart support" + depends on M68360 + help + This driver supports the SCC serial ports of the Motorola 68360 CPU. + +config SERIAL_68360 + bool + depends on SERIAL_68360_SMC || SERIAL_68360_SCC + default y + +config SERIAL_PMACZILOG + tristate "Mac or PowerMac z85c30 ESCC support" + depends on (M68K && MAC) || (PPC_OF && PPC_PMAC) + select SERIAL_CORE + help + This driver supports the Zilog z85C30 serial ports found on + (Power)Mac machines. + Say Y or M if you want to be able to these serial ports. + +config SERIAL_PMACZILOG_TTYS + bool "Use ttySn device nodes for Zilog z85c30" + depends on SERIAL_PMACZILOG + help + The pmac_zilog driver for the z85C30 chip on many powermacs + historically used the device numbers for /dev/ttySn. The + 8250 serial port driver also uses these numbers, which means + the two drivers being unable to coexist; you could not use + both z85C30 and 8250 type ports at the same time. + + If this option is not selected, the pmac_zilog driver will + use the device numbers allocated for /dev/ttyPZn. This allows + the pmac_zilog and 8250 drivers to co-exist, but may cause + existing userspace setups to break. Programs that need to + access the built-in serial ports on powermacs will need to + be reconfigured to use /dev/ttyPZn instead of /dev/ttySn. + + If you enable this option, any z85c30 ports in the system will + be registered as ttyS0 onwards as in the past, and you will be + unable to use the 8250 module for PCMCIA or other 16C550-style + UARTs. + + Say N unless you need the z85c30 ports on your (Power)Mac + to appear as /dev/ttySn. + +config SERIAL_PMACZILOG_CONSOLE + bool "Console on Mac or PowerMac z85c30 serial port" + depends on SERIAL_PMACZILOG=y + select SERIAL_CORE_CONSOLE + help + If you would like to be able to use the z85c30 serial port + on your (Power)Mac as the console, you can do so by answering + Y to this option. + +config SERIAL_LH7A40X + tristate "Sharp LH7A40X embedded UART support" + depends on ARM && ARCH_LH7A40X + select SERIAL_CORE + help + This enables support for the three on-board UARTs of the + Sharp LH7A40X series CPUs. Choose Y or M. + +config SERIAL_LH7A40X_CONSOLE + bool "Support for console on Sharp LH7A40X serial port" + depends on SERIAL_LH7A40X=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use one of the serial ports as the + system console--the system console is the device which + receives all kernel messages and warnings and which allows + logins in single user mode. + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the default system console, but + you can alter that using a kernel command line, for example + "console=ttyAM1". + +config SERIAL_CPM + tristate "CPM SCC/SMC serial port support" + depends on CPM2 || 8xx + select SERIAL_CORE + help + This driver supports the SCC and SMC serial ports on Motorola + embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx) + +config SERIAL_CPM_CONSOLE + bool "Support for console on CPM SCC/SMC serial port" + depends on SERIAL_CPM=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use a SCC or SMC CPM UART as the system + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyCPM0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_SGI_L1_CONSOLE + bool "SGI Altix L1 serial console support" + depends on IA64_GENERIC || IA64_SGI_SN2 + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + help + If you have an SGI Altix and you would like to use the system + controller serial port as your console (you want this!), + say Y. Otherwise, say N. + +config SERIAL_MPC52xx + tristate "Freescale MPC52xx/MPC512x family PSC serial support" + depends on PPC_MPC52xx || PPC_MPC512x + select SERIAL_CORE + help + This driver supports MPC52xx and MPC512x PSC serial ports. If you would + like to use them, you must answer Y or M to this option. Note that + for use as console, it must be included in kernel and not as a + module. + +config SERIAL_MPC52xx_CONSOLE + bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port" + depends on SERIAL_MPC52xx=y + select SERIAL_CORE_CONSOLE + help + Select this options if you'd like to use one of the PSC serial port + of the Freescale MPC52xx family as a console. + +config SERIAL_MPC52xx_CONSOLE_BAUD + int "Freescale MPC52xx/MPC512x family PSC serial port baud" + depends on SERIAL_MPC52xx_CONSOLE=y + default "9600" + help + Select the MPC52xx console baud rate. + This value is only used if the bootloader doesn't pass in the + console baudrate + +config SERIAL_ICOM + tristate "IBM Multiport Serial Adapter" + depends on PCI && (PPC_ISERIES || PPC_PSERIES) + select SERIAL_CORE + select FW_LOADER + help + This driver is for a family of multiport serial adapters + including 2 port RVX, 2 port internal modem, 4 port internal + modem and a split 1 port RVX and 1 port internal modem. + + This driver can also be built as a module. If so, the module + will be called icom. + +config SERIAL_M32R_SIO + bool "M32R SIO I/F" + depends on M32R + default y + select SERIAL_CORE + help + Say Y here if you want to use the M32R serial controller. + +config SERIAL_M32R_SIO_CONSOLE + bool "use SIO console" + depends on SERIAL_M32R_SIO=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you want to support a serial console. + + If you use an M3T-M32700UT or an OPSPUT platform, + please say also y for SERIAL_M32R_PLDSIO. + +config SERIAL_M32R_PLDSIO + bool "M32R SIO I/F on a PLD" + depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT) + default n + help + Say Y here if you want to use the M32R serial controller + on a PLD (Programmable Logic Device). + + If you use an M3T-M32700UT or an OPSPUT platform, + please say Y. + +config SERIAL_TXX9 + bool "TMPTX39XX/49XX SIO support" + depends on HAS_TXX9_SERIAL + select SERIAL_CORE + default y + +config HAS_TXX9_SERIAL + bool + +config SERIAL_TXX9_NR_UARTS + int "Maximum number of TMPTX39XX/49XX SIO ports" + depends on SERIAL_TXX9 + default "6" + +config SERIAL_TXX9_CONSOLE + bool "TMPTX39XX/49XX SIO Console support" + depends on SERIAL_TXX9=y + select SERIAL_CORE_CONSOLE + +config SERIAL_TXX9_STDSERIAL + bool "TX39XX/49XX SIO act as standard serial" + depends on !SERIAL_8250 && SERIAL_TXX9 + +config SERIAL_VR41XX + tristate "NEC VR4100 series Serial Interface Unit support" + depends on CPU_VR41XX + select SERIAL_CORE + help + If you have a NEC VR4100 series processor and you want to use + Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU) + (not include VR4111/VR4121 DSIU), say Y. Otherwise, say N. + +config SERIAL_VR41XX_CONSOLE + bool "Enable NEC VR4100 series Serial Interface Unit console" + depends on SERIAL_VR41XX=y + select SERIAL_CORE_CONSOLE + help + If you have a NEC VR4100 series processor and you want to use + a console on a serial port, say Y. Otherwise, say N. + +config SERIAL_JSM + tristate "Digi International NEO PCI Support" + depends on PCI + select SERIAL_CORE + help + This is a driver for Digi International's Neo series + of cards which provide multiple serial ports. You would need + something like this to connect more than two modems to your Linux + box, for instance in order to become a dial-in server. This driver + supports PCI boards only. + + If you have a card like this, say Y here, otherwise say N. + + To compile this driver as a module, choose M here: the + module will be called jsm. + +config SERIAL_SGI_IOC4 + tristate "SGI IOC4 controller serial support" + depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4 + select SERIAL_CORE + help + If you have an SGI Altix with an IOC4 based Base IO card + and wish to use the serial ports on this card, say Y. + Otherwise, say N. + +config SERIAL_SGI_IOC3 + tristate "SGI Altix IOC3 serial support" + depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3 + select SERIAL_CORE + help + If you have an SGI Altix with an IOC3 serial card, + say Y or M. Otherwise, say N. + +config SERIAL_MSM + bool "MSM on-chip serial port support" + depends on ARM && ARCH_MSM + select SERIAL_CORE + +config SERIAL_MSM_CONSOLE + bool "MSM serial console support" + depends on SERIAL_MSM=y + select SERIAL_CORE_CONSOLE + +config SERIAL_VT8500 + bool "VIA VT8500 on-chip serial port support" + depends on ARM && ARCH_VT8500 + select SERIAL_CORE + +config SERIAL_VT8500_CONSOLE + bool "VIA VT8500 serial console support" + depends on SERIAL_VT8500=y + select SERIAL_CORE_CONSOLE + +config SERIAL_NETX + tristate "NetX serial port support" + depends on ARM && ARCH_NETX + select SERIAL_CORE + help + If you have a machine based on a Hilscher NetX SoC you + can enable its onboard serial port by enabling this option. + + To compile this driver as a module, choose M here: the + module will be called netx-serial. + +config SERIAL_NETX_CONSOLE + bool "Console on NetX serial port" + depends on SERIAL_NETX=y + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the Hilscher NetX SoC + you can make it the console by answering Y to this option. + +config SERIAL_OF_PLATFORM + tristate "Serial port on Open Firmware platform bus" + depends on OF + depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL + help + If you have a PowerPC based system that has serial ports + on a platform specific bus, you should enable this option. + Currently, only 8250 compatible ports are supported, but + others can easily be added. + +config SERIAL_OMAP + tristate "OMAP serial port support" + depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4 + select SERIAL_CORE + help + If you have a machine based on an Texas Instruments OMAP CPU you + can enable its onboard serial ports by enabling this option. + + By enabling this option you take advantage of dma feature available + with the omap-serial driver. DMA support can be enabled from platform + data. + +config SERIAL_OMAP_CONSOLE + bool "Console on OMAP serial port" + depends on SERIAL_OMAP + select SERIAL_CORE_CONSOLE + help + Select this option if you would like to use omap serial port as + console. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyOx". (Try "man bootparam" or see the documentation of + your boot loader about how to pass options to the kernel at + boot time.) + +config SERIAL_OF_PLATFORM_NWPSERIAL + tristate "NWP serial port driver" + depends on PPC_OF && PPC_DCR + select SERIAL_OF_PLATFORM + select SERIAL_CORE_CONSOLE + select SERIAL_CORE + help + This driver supports the cell network processor nwp serial + device. + +config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE + bool "Console on NWP serial port" + depends on SERIAL_OF_PLATFORM_NWPSERIAL=y + select SERIAL_CORE_CONSOLE + help + Support for Console on the NWP serial ports. + +config SERIAL_QE + tristate "Freescale QUICC Engine serial port support" + depends on QUICC_ENGINE + select SERIAL_CORE + select FW_LOADER + default n + help + This driver supports the QE serial ports on Freescale embedded + PowerPC that contain a QUICC Engine. + +config SERIAL_SC26XX + tristate "SC2681/SC2692 serial port support" + depends on SNI_RM + select SERIAL_CORE + help + This is a driver for the onboard serial ports of + older RM400 machines. + +config SERIAL_SC26XX_CONSOLE + bool "Console on SC2681/SC2692 serial port" + depends on SERIAL_SC26XX + select SERIAL_CORE_CONSOLE + help + Support for Console on SC2681/SC2692 serial ports. + +config SERIAL_BFIN_SPORT + tristate "Blackfin SPORT emulate UART" + depends on BLACKFIN + select SERIAL_CORE + help + Enable SPORT emulate UART on Blackfin series. + + To compile this driver as a module, choose M here: the + module will be called bfin_sport_uart. + +config SERIAL_BFIN_SPORT_CONSOLE + bool "Console on Blackfin sport emulated uart" + depends on SERIAL_BFIN_SPORT=y + select SERIAL_CORE_CONSOLE + +config SERIAL_BFIN_SPORT0_UART + bool "Enable UART over SPORT0" + depends on SERIAL_BFIN_SPORT && !(BF542 || BF544) + help + Enable UART over SPORT0 + +config SERIAL_BFIN_SPORT0_UART_CTSRTS + bool "Enable UART over SPORT0 hardware flow control" + depends on SERIAL_BFIN_SPORT0_UART + help + Enable hardware flow control in the driver. + +config SERIAL_BFIN_SPORT1_UART + bool "Enable UART over SPORT1" + depends on SERIAL_BFIN_SPORT + help + Enable UART over SPORT1 + +config SERIAL_BFIN_SPORT1_UART_CTSRTS + bool "Enable UART over SPORT1 hardware flow control" + depends on SERIAL_BFIN_SPORT1_UART + help + Enable hardware flow control in the driver. + +config SERIAL_BFIN_SPORT2_UART + bool "Enable UART over SPORT2" + depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) + help + Enable UART over SPORT2 + +config SERIAL_BFIN_SPORT2_UART_CTSRTS + bool "Enable UART over SPORT2 hardware flow control" + depends on SERIAL_BFIN_SPORT2_UART + help + Enable hardware flow control in the driver. + +config SERIAL_BFIN_SPORT3_UART + bool "Enable UART over SPORT3" + depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) + help + Enable UART over SPORT3 + +config SERIAL_BFIN_SPORT3_UART_CTSRTS + bool "Enable UART over SPORT3 hardware flow control" + depends on SERIAL_BFIN_SPORT3_UART + help + Enable hardware flow control in the driver. + +config SERIAL_TIMBERDALE + tristate "Support for timberdale UART" + select SERIAL_CORE + ---help--- + Add support for UART controller on timberdale. + +config SERIAL_BCM63XX + tristate "bcm63xx serial port support" + select SERIAL_CORE + depends on BCM63XX + help + If you have a bcm63xx CPU, you can enable its onboard + serial port by enabling this options. + + To compile this driver as a module, choose M here: the + module will be called bcm963xx_uart. + +config SERIAL_BCM63XX_CONSOLE + bool "Console on bcm63xx serial port" + depends on SERIAL_BCM63XX=y + select SERIAL_CORE_CONSOLE + help + If you have enabled the serial port on the bcm63xx CPU + you can make it the console by answering Y to this option. + +config SERIAL_GRLIB_GAISLER_APBUART + tristate "GRLIB APBUART serial support" + depends on OF + ---help--- + Add support for the GRLIB APBUART serial port. + +config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE + bool "Console on GRLIB APBUART serial port" + depends on SERIAL_GRLIB_GAISLER_APBUART=y + select SERIAL_CORE_CONSOLE + help + Support for running a console on the GRLIB APBUART + +config SERIAL_ALTERA_JTAGUART + tristate "Altera JTAG UART support" + select SERIAL_CORE + help + This driver supports the Altera JTAG UART port. + +config SERIAL_ALTERA_JTAGUART_CONSOLE + bool "Altera JTAG UART console support" + depends on SERIAL_ALTERA_JTAGUART=y + select SERIAL_CORE_CONSOLE + help + Enable a Altera JTAG UART port to be the system console. + +config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS + bool "Bypass output when no connection" + depends on SERIAL_ALTERA_JTAGUART_CONSOLE + select SERIAL_CORE_CONSOLE + help + Bypass console output and keep going even if there is no + JTAG terminal connection with the host. + +config SERIAL_ALTERA_UART + tristate "Altera UART support" + select SERIAL_CORE + help + This driver supports the Altera softcore UART port. + +config SERIAL_ALTERA_UART_MAXPORTS + int "Maximum number of Altera UART ports" + depends on SERIAL_ALTERA_UART + default 4 + help + This setting lets you define the maximum number of the Altera + UART ports. The usual default varies from board to board, and + this setting is a way of catering for that. + +config SERIAL_ALTERA_UART_BAUDRATE + int "Default baudrate for Altera UART ports" + depends on SERIAL_ALTERA_UART + default 115200 + help + This setting lets you define what the default baudrate is for the + Altera UART ports. The usual default varies from board to board, + and this setting is a way of catering for that. + +config SERIAL_ALTERA_UART_CONSOLE + bool "Altera UART console support" + depends on SERIAL_ALTERA_UART=y + select SERIAL_CORE_CONSOLE + help + Enable a Altera UART port to be the system console. + +config SERIAL_IFX6X60 + tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" + depends on GPIOLIB && SPI && EXPERIMENTAL + help + Support for the IFX6x60 modem devices on Intel MID platforms. + +config SERIAL_PCH_UART + tristate "Intel EG20T PCH UART" + depends on PCI && DMADEVICES + select SERIAL_CORE + select PCH_DMA + help + This driver is for PCH(Platform controller Hub) UART of Intel EG20T + which is an IOH(Input/Output Hub) for x86 embedded processor. + Enabling PCH_DMA, this PCH UART works as DMA mode. +endmenu diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile new file mode 100644 index 000000000000..8ea92e9c73b0 --- /dev/null +++ b/drivers/tty/serial/Makefile @@ -0,0 +1,94 @@ +# +# Makefile for the kernel serial device drivers. +# + +obj-$(CONFIG_SERIAL_CORE) += serial_core.o +obj-$(CONFIG_SERIAL_21285) += 21285.o + +# These Sparc drivers have to appear before others such as 8250 +# which share ttySx minor node space. Otherwise console device +# names change and other unplesantries. +obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o +obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o +obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o +obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o +obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o + +obj-$(CONFIG_SERIAL_8250) += 8250.o +obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o +obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o +obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o +obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o +obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o +obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o +obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o +obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o +obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o +obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o +obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o +obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o +obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o +obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o +obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o +obj-$(CONFIG_SERIAL_PXA) += pxa.o +obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o +obj-$(CONFIG_SERIAL_SA1100) += sa1100.o +obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o +obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o +obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o +obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o +obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o +obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o +obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o +obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o +obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o +obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o +obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o +obj-$(CONFIG_SERIAL_MAX3100) += max3100.o +obj-$(CONFIG_SERIAL_MAX3107) += max3107.o +obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o +obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o +obj-$(CONFIG_SERIAL_MUX) += mux.o +obj-$(CONFIG_SERIAL_68328) += 68328serial.o +obj-$(CONFIG_SERIAL_68360) += 68360serial.o +obj-$(CONFIG_SERIAL_MCF) += mcf.o +obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o +obj-$(CONFIG_SERIAL_DZ) += dz.o +obj-$(CONFIG_SERIAL_ZS) += zs.o +obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o +obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o +obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ +obj-$(CONFIG_SERIAL_IMX) += imx.o +obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o +obj-$(CONFIG_SERIAL_ICOM) += icom.o +obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o +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_JSM) += jsm/ +obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o +obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o +obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o +obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o +obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o +obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o +obj-$(CONFIG_SERIAL_MSM) += msm_serial.o +obj-$(CONFIG_SERIAL_NETX) += netx-serial.o +obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o +obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o +obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o +obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o +obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o +obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o +obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o +obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o +obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o +obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o +obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o +obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o +obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o +obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c new file mode 100644 index 000000000000..f9b49b5ff5e1 --- /dev/null +++ b/drivers/tty/serial/altera_jtaguart.c @@ -0,0 +1,504 @@ +/* + * altera_jtaguart.c -- Altera JTAG UART driver + * + * Based on mcf.c -- Freescale ColdFire UART driver + * + * (C) Copyright 2003-2007, Greg Ungerer + * (C) Copyright 2008, Thomas Chou + * (C) Copyright 2010, Tobias Klauser + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "altera_jtaguart" + +/* + * Altera JTAG UART register definitions according to the Altera JTAG UART + * datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf + */ + +#define ALTERA_JTAGUART_SIZE 8 + +#define ALTERA_JTAGUART_DATA_REG 0 + +#define ALTERA_JTAGUART_DATA_DATA_MSK 0x000000FF +#define ALTERA_JTAGUART_DATA_RVALID_MSK 0x00008000 +#define ALTERA_JTAGUART_DATA_RAVAIL_MSK 0xFFFF0000 +#define ALTERA_JTAGUART_DATA_RAVAIL_OFF 16 + +#define ALTERA_JTAGUART_CONTROL_REG 4 + +#define ALTERA_JTAGUART_CONTROL_RE_MSK 0x00000001 +#define ALTERA_JTAGUART_CONTROL_WE_MSK 0x00000002 +#define ALTERA_JTAGUART_CONTROL_RI_MSK 0x00000100 +#define ALTERA_JTAGUART_CONTROL_RI_OFF 8 +#define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200 +#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400 +#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000 +#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16 + +/* + * Local per-uart structure. + */ +struct altera_jtaguart { + struct uart_port port; + unsigned int sigs; /* Local copy of line sigs */ + unsigned long imr; /* Local IMR mirror */ +}; + +static unsigned int altera_jtaguart_tx_empty(struct uart_port *port) +{ + return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & + ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0; +} + +static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs) +{ +} + +static void altera_jtaguart_start_tx(struct uart_port *port) +{ + struct altera_jtaguart *pp = + container_of(port, struct altera_jtaguart, port); + + pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK; + writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); +} + +static void altera_jtaguart_stop_tx(struct uart_port *port) +{ + struct altera_jtaguart *pp = + container_of(port, struct altera_jtaguart, port); + + pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; + writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); +} + +static void altera_jtaguart_stop_rx(struct uart_port *port) +{ + struct altera_jtaguart *pp = + container_of(port, struct altera_jtaguart, port); + + pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK; + writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); +} + +static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state) +{ +} + +static void altera_jtaguart_enable_ms(struct uart_port *port) +{ +} + +static void altera_jtaguart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + /* Just copy the old termios settings back */ + if (old) + tty_termios_copy_hw(termios, old); +} + +static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp) +{ + struct uart_port *port = &pp->port; + unsigned char ch, flag; + unsigned long status; + + while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) & + ALTERA_JTAGUART_DATA_RVALID_MSK) { + ch = status & ALTERA_JTAGUART_DATA_DATA_MSK; + flag = TTY_NORMAL; + port->icount.rx++; + + if (uart_handle_sysrq_char(port, ch)) + continue; + uart_insert_char(port, 0, 0, ch, flag); + } + + tty_flip_buffer_push(port->state->port.tty); +} + +static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp) +{ + struct uart_port *port = &pp->port; + struct circ_buf *xmit = &port->state->xmit; + unsigned int pending, count; + + if (port->x_char) { + /* Send special char - probably flow control */ + writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG); + port->x_char = 0; + port->icount.tx++; + return; + } + + pending = uart_circ_chars_pending(xmit); + if (pending > 0) { + count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & + ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >> + ALTERA_JTAGUART_CONTROL_WSPACE_OFF; + if (count > pending) + count = pending; + if (count > 0) { + pending -= count; + while (count--) { + writel(xmit->buf[xmit->tail], + port->membase + ALTERA_JTAGUART_DATA_REG); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + if (pending < WAKEUP_CHARS) + uart_write_wakeup(port); + } + } + + if (pending == 0) { + pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK; + writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + } +} + +static irqreturn_t altera_jtaguart_interrupt(int irq, void *data) +{ + struct uart_port *port = data; + struct altera_jtaguart *pp = + container_of(port, struct altera_jtaguart, port); + unsigned int isr; + + isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >> + ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr; + + spin_lock(&port->lock); + + if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK) + altera_jtaguart_rx_chars(pp); + if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK) + altera_jtaguart_tx_chars(pp); + + spin_unlock(&port->lock); + + return IRQ_RETVAL(isr); +} + +static void altera_jtaguart_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_ALTERA_JTAGUART; + + /* Clear mask, so no surprise interrupts. */ + writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG); +} + +static int altera_jtaguart_startup(struct uart_port *port) +{ + struct altera_jtaguart *pp = + container_of(port, struct altera_jtaguart, port); + unsigned long flags; + int ret; + + ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED, + DRV_NAME, port); + if (ret) { + pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d " + "interrupt vector=%d\n", port->line, port->irq); + return ret; + } + + spin_lock_irqsave(&port->lock, flags); + + /* Enable RX interrupts now */ + pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK; + writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void altera_jtaguart_shutdown(struct uart_port *port) +{ + struct altera_jtaguart *pp = + container_of(port, struct altera_jtaguart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* Disable all interrupts now */ + pp->imr = 0; + writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG); + + spin_unlock_irqrestore(&port->lock, flags); + + free_irq(port->irq, port); +} + +static const char *altera_jtaguart_type(struct uart_port *port) +{ + return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL; +} + +static int altera_jtaguart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void altera_jtaguart_release_port(struct uart_port *port) +{ + /* Nothing to release... */ +} + +static int altera_jtaguart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART) + return -EINVAL; + return 0; +} + +/* + * Define the basic serial functions we support. + */ +static struct uart_ops altera_jtaguart_ops = { + .tx_empty = altera_jtaguart_tx_empty, + .get_mctrl = altera_jtaguart_get_mctrl, + .set_mctrl = altera_jtaguart_set_mctrl, + .start_tx = altera_jtaguart_start_tx, + .stop_tx = altera_jtaguart_stop_tx, + .stop_rx = altera_jtaguart_stop_rx, + .enable_ms = altera_jtaguart_enable_ms, + .break_ctl = altera_jtaguart_break_ctl, + .startup = altera_jtaguart_startup, + .shutdown = altera_jtaguart_shutdown, + .set_termios = altera_jtaguart_set_termios, + .type = altera_jtaguart_type, + .request_port = altera_jtaguart_request_port, + .release_port = altera_jtaguart_release_port, + .config_port = altera_jtaguart_config_port, + .verify_port = altera_jtaguart_verify_port, +}; + +#define ALTERA_JTAGUART_MAXPORTS 1 +static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; + +#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) + +int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart + *platp) +{ + struct uart_port *port; + int i; + + for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) { + port = &altera_jtaguart_ports[i].port; + + port->line = i; + port->type = PORT_ALTERA_JTAGUART; + port->mapbase = platp[i].mapbase; + port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); + port->iotype = SERIAL_IO_MEM; + port->irq = platp[i].irq; + port->flags = ASYNC_BOOT_AUTOCONF; + port->ops = &altera_jtaguart_ops; + } + + return 0; +} + +#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) +static void altera_jtaguart_console_putc(struct console *co, const char c) +{ + struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; + unsigned long status; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) & + ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { + if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) { + spin_unlock_irqrestore(&port->lock, flags); + return; /* no connection activity */ + } + spin_unlock_irqrestore(&port->lock, flags); + cpu_relax(); + spin_lock_irqsave(&port->lock, flags); + } + writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); + spin_unlock_irqrestore(&port->lock, flags); +} +#else +static void altera_jtaguart_console_putc(struct console *co, const char c) +{ + struct uart_port *port = &(altera_jtaguart_ports + co->index)->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) & + ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) { + spin_unlock_irqrestore(&port->lock, flags); + cpu_relax(); + spin_lock_irqsave(&port->lock, flags); + } + writel(c, port->membase + ALTERA_JTAGUART_DATA_REG); + spin_unlock_irqrestore(&port->lock, flags); +} +#endif + +static void altera_jtaguart_console_write(struct console *co, const char *s, + unsigned int count) +{ + for (; count; count--, s++) { + altera_jtaguart_console_putc(co, *s); + if (*s == '\n') + altera_jtaguart_console_putc(co, '\r'); + } +} + +static int __init altera_jtaguart_console_setup(struct console *co, + char *options) +{ + struct uart_port *port; + + if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS) + return -EINVAL; + port = &altera_jtaguart_ports[co->index].port; + if (port->membase == 0) + return -ENODEV; + return 0; +} + +static struct uart_driver altera_jtaguart_driver; + +static struct console altera_jtaguart_console = { + .name = "ttyJ", + .write = altera_jtaguart_console_write, + .device = uart_console_device, + .setup = altera_jtaguart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &altera_jtaguart_driver, +}; + +static int __init altera_jtaguart_console_init(void) +{ + register_console(&altera_jtaguart_console); + return 0; +} + +console_initcall(altera_jtaguart_console_init); + +#define ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console) + +#else + +#define ALTERA_JTAGUART_CONSOLE NULL + +#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */ + +static struct uart_driver altera_jtaguart_driver = { + .owner = THIS_MODULE, + .driver_name = "altera_jtaguart", + .dev_name = "ttyJ", + .major = ALTERA_JTAGUART_MAJOR, + .minor = ALTERA_JTAGUART_MINOR, + .nr = ALTERA_JTAGUART_MAXPORTS, + .cons = ALTERA_JTAGUART_CONSOLE, +}; + +static int __devinit altera_jtaguart_probe(struct platform_device *pdev) +{ + struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data; + struct uart_port *port; + int i; + + for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) { + port = &altera_jtaguart_ports[i].port; + + port->line = i; + port->type = PORT_ALTERA_JTAGUART; + port->mapbase = platp[i].mapbase; + port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); + port->iotype = SERIAL_IO_MEM; + port->irq = platp[i].irq; + port->ops = &altera_jtaguart_ops; + port->flags = ASYNC_BOOT_AUTOCONF; + + uart_add_one_port(&altera_jtaguart_driver, port); + } + + return 0; +} + +static int __devexit altera_jtaguart_remove(struct platform_device *pdev) +{ + struct uart_port *port; + int i; + + for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) { + port = &altera_jtaguart_ports[i].port; + if (port) + uart_remove_one_port(&altera_jtaguart_driver, port); + } + + return 0; +} + +static struct platform_driver altera_jtaguart_platform_driver = { + .probe = altera_jtaguart_probe, + .remove = __devexit_p(altera_jtaguart_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init altera_jtaguart_init(void) +{ + int rc; + + rc = uart_register_driver(&altera_jtaguart_driver); + if (rc) + return rc; + rc = platform_driver_register(&altera_jtaguart_platform_driver); + if (rc) { + uart_unregister_driver(&altera_jtaguart_driver); + return rc; + } + return 0; +} + +static void __exit altera_jtaguart_exit(void) +{ + platform_driver_unregister(&altera_jtaguart_platform_driver); + uart_unregister_driver(&altera_jtaguart_driver); +} + +module_init(altera_jtaguart_init); +module_exit(altera_jtaguart_exit); + +MODULE_DESCRIPTION("Altera JTAG UART driver"); +MODULE_AUTHOR("Thomas Chou "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c new file mode 100644 index 000000000000..721216292a50 --- /dev/null +++ b/drivers/tty/serial/altera_uart.c @@ -0,0 +1,608 @@ +/* + * altera_uart.c -- Altera UART driver + * + * Based on mcf.c -- Freescale ColdFire UART driver + * + * (C) Copyright 2003-2007, Greg Ungerer + * (C) Copyright 2008, Thomas Chou + * (C) Copyright 2010, Tobias Klauser + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "altera_uart" +#define SERIAL_ALTERA_MAJOR 204 +#define SERIAL_ALTERA_MINOR 213 + +/* + * Altera UART register definitions according to the Nios UART datasheet: + * http://www.altera.com/literature/ds/ds_nios_uart.pdf + */ + +#define ALTERA_UART_SIZE 32 + +#define ALTERA_UART_RXDATA_REG 0 +#define ALTERA_UART_TXDATA_REG 4 +#define ALTERA_UART_STATUS_REG 8 +#define ALTERA_UART_CONTROL_REG 12 +#define ALTERA_UART_DIVISOR_REG 16 +#define ALTERA_UART_EOP_REG 20 + +#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */ +#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */ +#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */ +#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */ +#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */ +#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */ +#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */ +#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */ +#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */ +#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */ +#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */ +#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */ + + /* Enable interrupt on... */ +#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */ +#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */ +#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */ +#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */ +#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */ +#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */ +#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */ +#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */ +#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/ + +#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */ +#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */ +#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */ +#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */ + +/* + * Local per-uart structure. + */ +struct altera_uart { + struct uart_port port; + struct timer_list tmr; + unsigned int sigs; /* Local copy of line sigs */ + unsigned short imr; /* Local IMR mirror */ +}; + +static u32 altera_uart_readl(struct uart_port *port, int reg) +{ + struct altera_uart_platform_uart *platp = port->private_data; + + return readl(port->membase + (reg << platp->bus_shift)); +} + +static void altera_uart_writel(struct uart_port *port, u32 dat, int reg) +{ + struct altera_uart_platform_uart *platp = port->private_data; + + writel(dat, port->membase + (reg << platp->bus_shift)); +} + +static unsigned int altera_uart_tx_empty(struct uart_port *port) +{ + return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0; +} + +static unsigned int altera_uart_get_mctrl(struct uart_port *port) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned int sigs; + + sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; + sigs |= (pp->sigs & TIOCM_RTS); + + return sigs; +} + +static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + + pp->sigs = sigs; + if (sigs & TIOCM_RTS) + pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; + else + pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); +} + +static void altera_uart_start_tx(struct uart_port *port) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + + pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); +} + +static void altera_uart_stop_tx(struct uart_port *port) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + + pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); +} + +static void altera_uart_stop_rx(struct uart_port *port) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + + pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); +} + +static void altera_uart_break_ctl(struct uart_port *port, int break_state) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; + else + pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void altera_uart_enable_ms(struct uart_port *port) +{ +} + +static void altera_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, baudclk; + + baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + baudclk = port->uartclk / baud; + + if (old) + tty_termios_copy_hw(termios, old); + tty_termios_encode_baud_rate(termios, baud, baud); + + spin_lock_irqsave(&port->lock, flags); + uart_update_timeout(port, termios->c_cflag, baud); + altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void altera_uart_rx_chars(struct altera_uart *pp) +{ + struct uart_port *port = &pp->port; + unsigned char ch, flag; + unsigned short status; + + while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) & + ALTERA_UART_STATUS_RRDY_MSK) { + ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG); + flag = TTY_NORMAL; + port->icount.rx++; + + if (status & ALTERA_UART_STATUS_E_MSK) { + altera_uart_writel(port, status, + ALTERA_UART_STATUS_REG); + + if (status & ALTERA_UART_STATUS_BRK_MSK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (status & ALTERA_UART_STATUS_PE_MSK) { + port->icount.parity++; + } else if (status & ALTERA_UART_STATUS_ROE_MSK) { + port->icount.overrun++; + } else if (status & ALTERA_UART_STATUS_FE_MSK) { + port->icount.frame++; + } + + status &= port->read_status_mask; + + if (status & ALTERA_UART_STATUS_BRK_MSK) + flag = TTY_BREAK; + else if (status & ALTERA_UART_STATUS_PE_MSK) + flag = TTY_PARITY; + else if (status & ALTERA_UART_STATUS_FE_MSK) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch, + flag); + } + + tty_flip_buffer_push(port->state->port.tty); +} + +static void altera_uart_tx_chars(struct altera_uart *pp) +{ + struct uart_port *port = &pp->port; + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + /* Send special char - probably flow control */ + altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG); + port->x_char = 0; + port->icount.tx++; + return; + } + + while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TRDY_MSK) { + if (xmit->head == xmit->tail) + break; + altera_uart_writel(port, xmit->buf[xmit->tail], + ALTERA_UART_TXDATA_REG); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (xmit->head == xmit->tail) { + pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + } +} + +static irqreturn_t altera_uart_interrupt(int irq, void *data) +{ + struct uart_port *port = data; + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned int isr; + + isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr; + + spin_lock(&port->lock); + if (isr & ALTERA_UART_STATUS_RRDY_MSK) + altera_uart_rx_chars(pp); + if (isr & ALTERA_UART_STATUS_TRDY_MSK) + altera_uart_tx_chars(pp); + spin_unlock(&port->lock); + + return IRQ_RETVAL(isr); +} + +static void altera_uart_timer(unsigned long data) +{ + struct uart_port *port = (void *)data; + struct altera_uart *pp = container_of(port, struct altera_uart, port); + + altera_uart_interrupt(0, port); + mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); +} + +static void altera_uart_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_ALTERA_UART; + + /* Clear mask, so no surprise interrupts. */ + altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG); + /* Clear status register */ + altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG); +} + +static int altera_uart_startup(struct uart_port *port) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned long flags; + int ret; + + if (!port->irq) { + setup_timer(&pp->tmr, altera_uart_timer, (unsigned long)port); + mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); + return 0; + } + + ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED, + DRV_NAME, port); + if (ret) { + pr_err(DRV_NAME ": unable to attach Altera UART %d " + "interrupt vector=%d\n", port->line, port->irq); + return ret; + } + + spin_lock_irqsave(&port->lock, flags); + + /* Enable RX interrupts now */ + pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void altera_uart_shutdown(struct uart_port *port) +{ + struct altera_uart *pp = container_of(port, struct altera_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* Disable all interrupts now */ + pp->imr = 0; + writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + + spin_unlock_irqrestore(&port->lock, flags); + + if (port->irq) + free_irq(port->irq, port); + else + del_timer_sync(&pp->tmr); +} + +static const char *altera_uart_type(struct uart_port *port) +{ + return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL; +} + +static int altera_uart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void altera_uart_release_port(struct uart_port *port) +{ + /* Nothing to release... */ +} + +static int altera_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART)) + return -EINVAL; + return 0; +} + +/* + * Define the basic serial functions we support. + */ +static struct uart_ops altera_uart_ops = { + .tx_empty = altera_uart_tx_empty, + .get_mctrl = altera_uart_get_mctrl, + .set_mctrl = altera_uart_set_mctrl, + .start_tx = altera_uart_start_tx, + .stop_tx = altera_uart_stop_tx, + .stop_rx = altera_uart_stop_rx, + .enable_ms = altera_uart_enable_ms, + .break_ctl = altera_uart_break_ctl, + .startup = altera_uart_startup, + .shutdown = altera_uart_shutdown, + .set_termios = altera_uart_set_termios, + .type = altera_uart_type, + .request_port = altera_uart_request_port, + .release_port = altera_uart_release_port, + .config_port = altera_uart_config_port, + .verify_port = altera_uart_verify_port, +}; + +static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; + +#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) + +int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) +{ + struct uart_port *port; + int i; + + for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) { + port = &altera_uart_ports[i].port; + + port->line = i; + port->type = PORT_ALTERA_UART; + port->mapbase = platp[i].mapbase; + port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); + port->iotype = SERIAL_IO_MEM; + port->irq = platp[i].irq; + port->uartclk = platp[i].uartclk; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &altera_uart_ops; + port->private_data = platp; + } + + return 0; +} + +static void altera_uart_console_putc(struct uart_port *port, const char c) +{ + while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TRDY_MSK)) + cpu_relax(); + + writel(c, port->membase + ALTERA_UART_TXDATA_REG); +} + +static void altera_uart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = &(altera_uart_ports + co->index)->port; + + for (; count; count--, s++) { + altera_uart_console_putc(port, *s); + if (*s == '\n') + altera_uart_console_putc(port, '\r'); + } +} + +static int __init altera_uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS) + return -EINVAL; + port = &altera_uart_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 altera_uart_driver; + +static struct console altera_uart_console = { + .name = "ttyAL", + .write = altera_uart_console_write, + .device = uart_console_device, + .setup = altera_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &altera_uart_driver, +}; + +static int __init altera_uart_console_init(void) +{ + register_console(&altera_uart_console); + return 0; +} + +console_initcall(altera_uart_console_init); + +#define ALTERA_UART_CONSOLE (&altera_uart_console) + +#else + +#define ALTERA_UART_CONSOLE NULL + +#endif /* CONFIG_ALTERA_UART_CONSOLE */ + +/* + * Define the altera_uart UART driver structure. + */ +static struct uart_driver altera_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRV_NAME, + .dev_name = "ttyAL", + .major = SERIAL_ALTERA_MAJOR, + .minor = SERIAL_ALTERA_MINOR, + .nr = CONFIG_SERIAL_ALTERA_UART_MAXPORTS, + .cons = ALTERA_UART_CONSOLE, +}; + +static int __devinit altera_uart_probe(struct platform_device *pdev) +{ + struct altera_uart_platform_uart *platp = pdev->dev.platform_data; + struct uart_port *port; + struct resource *res_mem; + struct resource *res_irq; + int i = pdev->id; + + /* -1 emphasizes that the platform must have one port, no .N suffix */ + if (i == -1) + i = 0; + + if (i >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS) + return -EINVAL; + + port = &altera_uart_ports[i].port; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem) + port->mapbase = res_mem->start; + else if (platp->mapbase) + port->mapbase = platp->mapbase; + else + return -EINVAL; + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res_irq) + port->irq = res_irq->start; + else if (platp->irq) + port->irq = platp->irq; + + port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); + if (!port->membase) + return -ENOMEM; + + port->line = i; + port->type = PORT_ALTERA_UART; + port->iotype = SERIAL_IO_MEM; + port->uartclk = platp->uartclk; + port->ops = &altera_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->private_data = platp; + + uart_add_one_port(&altera_uart_driver, port); + + return 0; +} + +static int __devexit altera_uart_remove(struct platform_device *pdev) +{ + struct uart_port *port = &altera_uart_ports[pdev->id].port; + + uart_remove_one_port(&altera_uart_driver, port); + return 0; +} + +static struct platform_driver altera_uart_platform_driver = { + .probe = altera_uart_probe, + .remove = __devexit_p(altera_uart_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = NULL, + }, +}; + +static int __init altera_uart_init(void) +{ + int rc; + + rc = uart_register_driver(&altera_uart_driver); + if (rc) + return rc; + rc = platform_driver_register(&altera_uart_platform_driver); + if (rc) { + uart_unregister_driver(&altera_uart_driver); + return rc; + } + return 0; +} + +static void __exit altera_uart_exit(void) +{ + platform_driver_unregister(&altera_uart_platform_driver); + uart_unregister_driver(&altera_uart_driver); +} + +module_init(altera_uart_init); +module_exit(altera_uart_exit); + +MODULE_DESCRIPTION("Altera UART driver"); +MODULE_AUTHOR("Thomas Chou "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR); diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c new file mode 100644 index 000000000000..2904aa044126 --- /dev/null +++ b/drivers/tty/serial/amba-pl010.c @@ -0,0 +1,825 @@ +/* + * linux/drivers/char/amba.c + * + * Driver for AMBA serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + * + * This is a generic driver for ARM AMBA-type serial ports. They + * have a lot of 16550-like features, but are not register compatible. + * Note that although they do have CTS, DCD and DSR inputs, they do + * not have an RI input, nor do they have DTR or RTS outputs. If + * required, these have to be supplied via some other means (eg, GPIO) + * and hooked into this driver. + */ + +#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define UART_NR 8 + +#define SERIAL_AMBA_MAJOR 204 +#define SERIAL_AMBA_MINOR 16 +#define SERIAL_AMBA_NR UART_NR + +#define AMBA_ISR_PASS_LIMIT 256 + +#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) + +#define UART_DUMMY_RSR_RX 256 +#define UART_PORT_SIZE 64 + +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_amba_port { + struct uart_port port; + struct clk *clk; + struct amba_device *dev; + struct amba_pl010_data *data; + unsigned int old_status; +}; + +static void pl010_stop_tx(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int cr; + + cr = readb(uap->port.membase + UART010_CR); + cr &= ~UART010_CR_TIE; + writel(cr, uap->port.membase + UART010_CR); +} + +static void pl010_start_tx(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int cr; + + cr = readb(uap->port.membase + UART010_CR); + cr |= UART010_CR_TIE; + writel(cr, uap->port.membase + UART010_CR); +} + +static void pl010_stop_rx(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int cr; + + cr = readb(uap->port.membase + UART010_CR); + cr &= ~(UART010_CR_RIE | UART010_CR_RTIE); + writel(cr, uap->port.membase + UART010_CR); +} + +static void pl010_enable_ms(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int cr; + + cr = readb(uap->port.membase + UART010_CR); + cr |= UART010_CR_MSIE; + writel(cr, uap->port.membase + UART010_CR); +} + +static void pl010_rx_chars(struct uart_amba_port *uap) +{ + struct tty_struct *tty = uap->port.state->port.tty; + unsigned int status, ch, flag, rsr, max_count = 256; + + status = readb(uap->port.membase + UART01x_FR); + while (UART_RX_DATA(status) && max_count--) { + ch = readb(uap->port.membase + UART01x_DR); + flag = TTY_NORMAL; + + uap->port.icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; + if (unlikely(rsr & UART01x_RSR_ANY)) { + writel(0, uap->port.membase + UART01x_ECR); + + if (rsr & UART01x_RSR_BE) { + rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); + uap->port.icount.brk++; + if (uart_handle_break(&uap->port)) + goto ignore_char; + } else if (rsr & UART01x_RSR_PE) + uap->port.icount.parity++; + else if (rsr & UART01x_RSR_FE) + uap->port.icount.frame++; + if (rsr & UART01x_RSR_OE) + uap->port.icount.overrun++; + + rsr &= uap->port.read_status_mask; + + if (rsr & UART01x_RSR_BE) + flag = TTY_BREAK; + else if (rsr & UART01x_RSR_PE) + flag = TTY_PARITY; + else if (rsr & UART01x_RSR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&uap->port, ch)) + goto ignore_char; + + uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); + + ignore_char: + status = readb(uap->port.membase + UART01x_FR); + } + spin_unlock(&uap->port.lock); + tty_flip_buffer_push(tty); + spin_lock(&uap->port.lock); +} + +static void pl010_tx_chars(struct uart_amba_port *uap) +{ + struct circ_buf *xmit = &uap->port.state->xmit; + int count; + + if (uap->port.x_char) { + writel(uap->port.x_char, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + uap->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + pl010_stop_tx(&uap->port); + return; + } + + count = uap->port.fifosize >> 1; + do { + writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uap->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + + if (uart_circ_empty(xmit)) + pl010_stop_tx(&uap->port); +} + +static void pl010_modem_status(struct uart_amba_port *uap) +{ + unsigned int status, delta; + + writel(0, uap->port.membase + UART010_ICR); + + status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + + delta = status ^ uap->old_status; + uap->old_status = status; + + if (!delta) + return; + + if (delta & UART01x_FR_DCD) + uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); + + if (delta & UART01x_FR_DSR) + uap->port.icount.dsr++; + + if (delta & UART01x_FR_CTS) + uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); +} + +static irqreturn_t pl010_int(int irq, void *dev_id) +{ + struct uart_amba_port *uap = dev_id; + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + int handled = 0; + + spin_lock(&uap->port.lock); + + status = readb(uap->port.membase + UART010_IIR); + if (status) { + do { + if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) + pl010_rx_chars(uap); + if (status & UART010_IIR_MIS) + pl010_modem_status(uap); + if (status & UART010_IIR_TIS) + pl010_tx_chars(uap); + + if (pass_counter-- == 0) + break; + + status = readb(uap->port.membase + UART010_IIR); + } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS | + UART010_IIR_TIS)); + handled = 1; + } + + spin_unlock(&uap->port.lock); + + return IRQ_RETVAL(handled); +} + +static unsigned int pl010_tx_empty(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int status = readb(uap->port.membase + UART01x_FR); + return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; +} + +static unsigned int pl010_get_mctrl(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int result = 0; + unsigned int status; + + status = readb(uap->port.membase + UART01x_FR); + if (status & UART01x_FR_DCD) + result |= TIOCM_CAR; + if (status & UART01x_FR_DSR) + result |= TIOCM_DSR; + if (status & UART01x_FR_CTS) + result |= TIOCM_CTS; + + return result; +} + +static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + if (uap->data) + uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl); +} + +static void pl010_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned long flags; + unsigned int lcr_h; + + spin_lock_irqsave(&uap->port.lock, flags); + lcr_h = readb(uap->port.membase + UART010_LCRH); + if (break_state == -1) + lcr_h |= UART01x_LCRH_BRK; + else + lcr_h &= ~UART01x_LCRH_BRK; + writel(lcr_h, uap->port.membase + UART010_LCRH); + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +static int pl010_startup(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + int retval; + + /* + * Try to enable the clock producer. + */ + retval = clk_enable(uap->clk); + if (retval) + goto out; + + uap->port.uartclk = clk_get_rate(uap->clk); + + /* + * Allocate the IRQ + */ + retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap); + if (retval) + goto clk_dis; + + /* + * initialise the old status of the modem signals + */ + uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + + /* + * Finally, enable interrupts + */ + writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE, + uap->port.membase + UART010_CR); + + return 0; + + clk_dis: + clk_disable(uap->clk); + out: + return retval; +} + +static void pl010_shutdown(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + /* + * Free the interrupt + */ + free_irq(uap->port.irq, uap); + + /* + * disable all interrupts, disable the port + */ + writel(0, uap->port.membase + UART010_CR); + + /* disable break condition and fifos */ + writel(readb(uap->port.membase + UART010_LCRH) & + ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), + uap->port.membase + UART010_LCRH); + + /* + * Shut down the clock producer + */ + clk_disable(uap->clk); +} + +static void +pl010_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int lcr_h, old_cr; + unsigned long flags; + unsigned int baud, quot; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); + quot = uart_get_divisor(port, baud); + + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr_h = UART01x_LCRH_WLEN_5; + break; + case CS6: + lcr_h = UART01x_LCRH_WLEN_6; + break; + case CS7: + lcr_h = UART01x_LCRH_WLEN_7; + break; + default: // CS8 + lcr_h = UART01x_LCRH_WLEN_8; + break; + } + if (termios->c_cflag & CSTOPB) + lcr_h |= UART01x_LCRH_STP2; + if (termios->c_cflag & PARENB) { + lcr_h |= UART01x_LCRH_PEN; + if (!(termios->c_cflag & PARODD)) + lcr_h |= UART01x_LCRH_EPS; + } + if (uap->port.fifosize > 1) + lcr_h |= UART01x_LCRH_FEN; + + spin_lock_irqsave(&uap->port.lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + uap->port.read_status_mask = UART01x_RSR_OE; + if (termios->c_iflag & INPCK) + uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + uap->port.read_status_mask |= UART01x_RSR_BE; + + /* + * Characters to ignore + */ + uap->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + if (termios->c_iflag & IGNBRK) { + uap->port.ignore_status_mask |= UART01x_RSR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + uap->port.ignore_status_mask |= UART01x_RSR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX; + + /* first, disable everything */ + old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE; + + if (UART_ENABLE_MS(port, termios->c_cflag)) + old_cr |= UART010_CR_MSIE; + + writel(0, uap->port.membase + UART010_CR); + + /* Set baud rate */ + quot -= 1; + writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM); + writel(quot & 0xff, uap->port.membase + UART010_LCRL); + + /* + * ----------v----------v----------v----------v----- + * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * ----------^----------^----------^----------^----- + */ + writel(lcr_h, uap->port.membase + UART010_LCRH); + writel(old_cr, uap->port.membase + UART010_CR); + + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +static void pl010_set_ldisc(struct uart_port *port, int new) +{ + if (new == N_PPS) { + port->flags |= UPF_HARDPPS_CD; + pl010_enable_ms(port); + } else + port->flags &= ~UPF_HARDPPS_CD; +} + +static const char *pl010_type(struct uart_port *port) +{ + return port->type == PORT_AMBA ? "AMBA" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void pl010_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int pl010_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void pl010_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_AMBA; + pl010_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= nr_irqs) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops amba_pl010_pops = { + .tx_empty = pl010_tx_empty, + .set_mctrl = pl010_set_mctrl, + .get_mctrl = pl010_get_mctrl, + .stop_tx = pl010_stop_tx, + .start_tx = pl010_start_tx, + .stop_rx = pl010_stop_rx, + .enable_ms = pl010_enable_ms, + .break_ctl = pl010_break_ctl, + .startup = pl010_startup, + .shutdown = pl010_shutdown, + .set_termios = pl010_set_termios, + .set_ldisc = pl010_set_ldisc, + .type = pl010_type, + .release_port = pl010_release_port, + .request_port = pl010_request_port, + .config_port = pl010_config_port, + .verify_port = pl010_verify_port, +}; + +static struct uart_amba_port *amba_ports[UART_NR]; + +#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE + +static void pl010_console_putchar(struct uart_port *port, int ch) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int status; + + do { + status = readb(uap->port.membase + UART01x_FR); + barrier(); + } while (!UART_TX_READY(status)); + writel(ch, uap->port.membase + UART01x_DR); +} + +static void +pl010_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_amba_port *uap = amba_ports[co->index]; + unsigned int status, old_cr; + + clk_enable(uap->clk); + + /* + * First save the CR then disable the interrupts + */ + old_cr = readb(uap->port.membase + UART010_CR); + writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR); + + uart_console_write(&uap->port, s, count, pl010_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = readb(uap->port.membase + UART01x_FR); + barrier(); + } while (status & UART01x_FR_BUSY); + writel(old_cr, uap->port.membase + UART010_CR); + + clk_disable(uap->clk); +} + +static void __init +pl010_console_get_options(struct uart_amba_port *uap, int *baud, + int *parity, int *bits) +{ + if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = readb(uap->port.membase + UART010_LCRH); + + *parity = 'n'; + if (lcr_h & UART01x_LCRH_PEN) { + if (lcr_h & UART01x_LCRH_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) + *bits = 7; + else + *bits = 8; + + quot = readb(uap->port.membase + UART010_LCRL) | + readb(uap->port.membase + UART010_LCRM) << 8; + *baud = uap->port.uartclk / (16 * (quot + 1)); + } +} + +static int __init pl010_console_setup(struct console *co, char *options) +{ + struct uart_amba_port *uap; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + uap = amba_ports[co->index]; + if (!uap) + return -ENODEV; + + uap->port.uartclk = clk_get_rate(uap->clk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + pl010_console_get_options(uap, &baud, &parity, &bits); + + return uart_set_options(&uap->port, co, baud, parity, bits, flow); +} + +static struct uart_driver amba_reg; +static struct console amba_console = { + .name = "ttyAM", + .write = pl010_console_write, + .device = uart_console_device, + .setup = pl010_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &amba_reg, +}; + +#define AMBA_CONSOLE &amba_console +#else +#define AMBA_CONSOLE NULL +#endif + +static struct uart_driver amba_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyAM", + .dev_name = "ttyAM", + .major = SERIAL_AMBA_MAJOR, + .minor = SERIAL_AMBA_MINOR, + .nr = UART_NR, + .cons = AMBA_CONSOLE, +}; + +static int pl010_probe(struct amba_device *dev, struct amba_id *id) +{ + struct uart_amba_port *uap; + void __iomem *base; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) + if (amba_ports[i] == NULL) + break; + + if (i == ARRAY_SIZE(amba_ports)) { + ret = -EBUSY; + goto out; + } + + uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); + if (!uap) { + ret = -ENOMEM; + goto out; + } + + base = ioremap(dev->res.start, resource_size(&dev->res)); + if (!base) { + ret = -ENOMEM; + goto free; + } + + uap->clk = clk_get(&dev->dev, NULL); + if (IS_ERR(uap->clk)) { + ret = PTR_ERR(uap->clk); + goto unmap; + } + + uap->port.dev = &dev->dev; + uap->port.mapbase = dev->res.start; + uap->port.membase = base; + uap->port.iotype = UPIO_MEM; + uap->port.irq = dev->irq[0]; + uap->port.fifosize = 16; + uap->port.ops = &amba_pl010_pops; + uap->port.flags = UPF_BOOT_AUTOCONF; + uap->port.line = i; + uap->dev = dev; + uap->data = dev->dev.platform_data; + + amba_ports[i] = uap; + + amba_set_drvdata(dev, uap); + ret = uart_add_one_port(&amba_reg, &uap->port); + if (ret) { + amba_set_drvdata(dev, NULL); + amba_ports[i] = NULL; + clk_put(uap->clk); + unmap: + iounmap(base); + free: + kfree(uap); + } + out: + return ret; +} + +static int pl010_remove(struct amba_device *dev) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + int i; + + amba_set_drvdata(dev, NULL); + + uart_remove_one_port(&amba_reg, &uap->port); + + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) + if (amba_ports[i] == uap) + amba_ports[i] = NULL; + + iounmap(uap->port.membase); + clk_put(uap->clk); + kfree(uap); + return 0; +} + +static int pl010_suspend(struct amba_device *dev, pm_message_t state) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + + if (uap) + uart_suspend_port(&amba_reg, &uap->port); + + return 0; +} + +static int pl010_resume(struct amba_device *dev) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + + if (uap) + uart_resume_port(&amba_reg, &uap->port); + + return 0; +} + +static struct amba_id pl010_ids[] = { + { + .id = 0x00041010, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver pl010_driver = { + .drv = { + .name = "uart-pl010", + }, + .id_table = pl010_ids, + .probe = pl010_probe, + .remove = pl010_remove, + .suspend = pl010_suspend, + .resume = pl010_resume, +}; + +static int __init pl010_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: AMBA driver\n"); + + ret = uart_register_driver(&amba_reg); + if (ret == 0) { + ret = amba_driver_register(&pl010_driver); + if (ret) + uart_unregister_driver(&amba_reg); + } + return ret; +} + +static void __exit pl010_exit(void) +{ + amba_driver_unregister(&pl010_driver); + uart_unregister_driver(&amba_reg); +} + +module_init(pl010_init); +module_exit(pl010_exit); + +MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("ARM AMBA serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c new file mode 100644 index 000000000000..e76d7d000128 --- /dev/null +++ b/drivers/tty/serial/amba-pl011.c @@ -0,0 +1,1519 @@ +/* + * linux/drivers/char/amba.c + * + * Driver for AMBA serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2010 ST-Ericsson SA + * + * 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 + * + * This is a generic driver for ARM AMBA-type serial ports. They + * have a lot of 16550-like features, but are not register compatible. + * Note that although they do have CTS, DCD and DSR inputs, they do + * not have an RI input, nor do they have DTR or RTS outputs. If + * required, these have to be supplied via some other means (eg, GPIO) + * and hooked into this driver. + */ + +#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define UART_NR 14 + +#define SERIAL_AMBA_MAJOR 204 +#define SERIAL_AMBA_MINOR 64 +#define SERIAL_AMBA_NR UART_NR + +#define AMBA_ISR_PASS_LIMIT 256 + +#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) +#define UART_DUMMY_DR_RX (1 << 16) + +/* There is by now at least one vendor with differing details, so handle it */ +struct vendor_data { + unsigned int ifls; + unsigned int fifosize; + unsigned int lcrh_tx; + unsigned int lcrh_rx; + bool oversampling; + bool dma_threshold; +}; + +static struct vendor_data vendor_arm = { + .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fifosize = 16, + .lcrh_tx = UART011_LCRH, + .lcrh_rx = UART011_LCRH, + .oversampling = false, + .dma_threshold = false, +}; + +static struct vendor_data vendor_st = { + .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .fifosize = 64, + .lcrh_tx = ST_UART011_LCRH_TX, + .lcrh_rx = ST_UART011_LCRH_RX, + .oversampling = true, + .dma_threshold = true, +}; + +/* Deals with DMA transactions */ +struct pl011_dmatx_data { + struct dma_chan *chan; + struct scatterlist sg; + char *buf; + bool queued; +}; + +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_amba_port { + struct uart_port port; + struct clk *clk; + const struct vendor_data *vendor; + unsigned int dmacr; /* dma control reg */ + unsigned int im; /* interrupt mask */ + unsigned int old_status; + unsigned int fifosize; /* vendor-specific */ + unsigned int lcrh_tx; /* vendor-specific */ + unsigned int lcrh_rx; /* vendor-specific */ + bool autorts; + char type[12]; +#ifdef CONFIG_DMA_ENGINE + /* DMA stuff */ + bool using_dma; + struct pl011_dmatx_data dmatx; +#endif +}; + +/* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, + * no custom DMA interfaces are supported. + */ +#ifdef CONFIG_DMA_ENGINE + +#define PL011_DMA_BUFFER_SIZE PAGE_SIZE + +static void pl011_dma_probe_initcall(struct uart_amba_port *uap) +{ + /* DMA is the sole user of the platform data right now */ + struct amba_pl011_data *plat = uap->port.dev->platform_data; + struct dma_slave_config tx_conf = { + .dst_addr = uap->port.mapbase + UART01x_DR, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .direction = DMA_TO_DEVICE, + .dst_maxburst = uap->fifosize >> 1, + }; + struct dma_chan *chan; + dma_cap_mask_t mask; + + /* We need platform data */ + if (!plat || !plat->dma_filter) { + dev_info(uap->port.dev, "no DMA platform data\n"); + return; + } + + /* Try to acquire a generic DMA engine slave channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); + if (!chan) { + dev_err(uap->port.dev, "no TX DMA channel!\n"); + return; + } + + dmaengine_slave_config(chan, &tx_conf); + uap->dmatx.chan = chan; + + dev_info(uap->port.dev, "DMA channel TX %s\n", + dma_chan_name(uap->dmatx.chan)); +} + +#ifndef MODULE +/* + * Stack up the UARTs and let the above initcall be done at device + * initcall time, because the serial driver is called as an arch + * initcall, and at this time the DMA subsystem is not yet registered. + * At this point the driver will switch over to using DMA where desired. + */ +struct dma_uap { + struct list_head node; + struct uart_amba_port *uap; +}; + +static LIST_HEAD(pl011_dma_uarts); + +static int __init pl011_dma_initcall(void) +{ + struct list_head *node, *tmp; + + list_for_each_safe(node, tmp, &pl011_dma_uarts) { + struct dma_uap *dmau = list_entry(node, struct dma_uap, node); + pl011_dma_probe_initcall(dmau->uap); + list_del(node); + kfree(dmau); + } + return 0; +} + +device_initcall(pl011_dma_initcall); + +static void pl011_dma_probe(struct uart_amba_port *uap) +{ + struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); + if (dmau) { + dmau->uap = uap; + list_add_tail(&dmau->node, &pl011_dma_uarts); + } +} +#else +static void pl011_dma_probe(struct uart_amba_port *uap) +{ + pl011_dma_probe_initcall(uap); +} +#endif + +static void pl011_dma_remove(struct uart_amba_port *uap) +{ + /* TODO: remove the initcall if it has not yet executed */ + if (uap->dmatx.chan) + dma_release_channel(uap->dmatx.chan); +} + + +/* Forward declare this for the refill routine */ +static int pl011_dma_tx_refill(struct uart_amba_port *uap); + +/* + * The current DMA TX buffer has been sent. + * Try to queue up another DMA buffer. + */ +static void pl011_dma_tx_callback(void *data) +{ + struct uart_amba_port *uap = data; + struct pl011_dmatx_data *dmatx = &uap->dmatx; + unsigned long flags; + u16 dmacr; + + spin_lock_irqsave(&uap->port.lock, flags); + if (uap->dmatx.queued) + dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, + DMA_TO_DEVICE); + + dmacr = uap->dmacr; + uap->dmacr = dmacr & ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + + /* + * If TX DMA was disabled, it means that we've stopped the DMA for + * some reason (eg, XOFF received, or we want to send an X-char.) + * + * Note: we need to be careful here of a potential race between DMA + * and the rest of the driver - if the driver disables TX DMA while + * a TX buffer completing, we must update the tx queued status to + * get further refills (hence we check dmacr). + */ + if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || + uart_circ_empty(&uap->port.state->xmit)) { + uap->dmatx.queued = false; + spin_unlock_irqrestore(&uap->port.lock, flags); + return; + } + + if (pl011_dma_tx_refill(uap) <= 0) { + /* + * We didn't queue a DMA buffer for some reason, but we + * have data pending to be sent. Re-enable the TX IRQ. + */ + uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + } + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +/* + * Try to refill the TX DMA buffer. + * Locking: called with port lock held and IRQs disabled. + * Returns: + * 1 if we queued up a TX DMA buffer. + * 0 if we didn't want to handle this by DMA + * <0 on error + */ +static int pl011_dma_tx_refill(struct uart_amba_port *uap) +{ + struct pl011_dmatx_data *dmatx = &uap->dmatx; + struct dma_chan *chan = dmatx->chan; + struct dma_device *dma_dev = chan->device; + struct dma_async_tx_descriptor *desc; + struct circ_buf *xmit = &uap->port.state->xmit; + unsigned int count; + + /* + * Try to avoid the overhead involved in using DMA if the + * transaction fits in the first half of the FIFO, by using + * the standard interrupt handling. This ensures that we + * issue a uart_write_wakeup() at the appropriate time. + */ + count = uart_circ_chars_pending(xmit); + if (count < (uap->fifosize >> 1)) { + uap->dmatx.queued = false; + return 0; + } + + /* + * Bodge: don't send the last character by DMA, as this + * will prevent XON from notifying us to restart DMA. + */ + count -= 1; + + /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */ + if (count > PL011_DMA_BUFFER_SIZE) + count = PL011_DMA_BUFFER_SIZE; + + if (xmit->tail < xmit->head) + memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); + else { + size_t first = UART_XMIT_SIZE - xmit->tail; + size_t second = xmit->head; + + memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); + if (second) + memcpy(&dmatx->buf[first], &xmit->buf[0], second); + } + + dmatx->sg.length = count; + + if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { + uap->dmatx.queued = false; + dev_dbg(uap->port.dev, "unable to map TX DMA\n"); + return -EBUSY; + } + + desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); + uap->dmatx.queued = false; + /* + * If DMA cannot be used right now, we complete this + * transaction via IRQ and let the TTY layer retry. + */ + dev_dbg(uap->port.dev, "TX DMA busy\n"); + return -EBUSY; + } + + /* Some data to go along to the callback */ + desc->callback = pl011_dma_tx_callback; + desc->callback_param = uap; + + /* All errors should happen at prepare time */ + dmaengine_submit(desc); + + /* Fire the DMA transaction */ + dma_dev->device_issue_pending(chan); + + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + uap->dmatx.queued = true; + + /* + * Now we know that DMA will fire, so advance the ring buffer + * with the stuff we just dispatched. + */ + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + uap->port.icount.tx += count; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + + return 1; +} + +/* + * We received a transmit interrupt without a pending X-char but with + * pending characters. + * Locking: called with port lock held and IRQs disabled. + * Returns: + * false if we want to use PIO to transmit + * true if we queued a DMA buffer + */ +static bool pl011_dma_tx_irq(struct uart_amba_port *uap) +{ + if (!uap->using_dma) + return false; + + /* + * If we already have a TX buffer queued, but received a + * TX interrupt, it will be because we've just sent an X-char. + * Ensure the TX DMA is enabled and the TX IRQ is disabled. + */ + if (uap->dmatx.queued) { + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + uap->im &= ~UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + return true; + } + + /* + * We don't have a TX buffer queued, so try to queue one. + * If we succesfully queued a buffer, mask the TX IRQ. + */ + if (pl011_dma_tx_refill(uap) > 0) { + uap->im &= ~UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + return true; + } + return false; +} + +/* + * Stop the DMA transmit (eg, due to received XOFF). + * Locking: called with port lock held and IRQs disabled. + */ +static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) +{ + if (uap->dmatx.queued) { + uap->dmacr &= ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + } +} + +/* + * Try to start a DMA transmit, or in the case of an XON/OFF + * character queued for send, try to get that character out ASAP. + * Locking: called with port lock held and IRQs disabled. + * Returns: + * false if we want the TX IRQ to be enabled + * true if we have a buffer queued + */ +static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) +{ + u16 dmacr; + + if (!uap->using_dma) + return false; + + if (!uap->port.x_char) { + /* no X-char, try to push chars out in DMA mode */ + bool ret = true; + + if (!uap->dmatx.queued) { + if (pl011_dma_tx_refill(uap) > 0) { + uap->im &= ~UART011_TXIM; + ret = true; + } else { + uap->im |= UART011_TXIM; + ret = false; + } + writew(uap->im, uap->port.membase + UART011_IMSC); + } else if (!(uap->dmacr & UART011_TXDMAE)) { + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, + uap->port.membase + UART011_DMACR); + } + return ret; + } + + /* + * We have an X-char to send. Disable DMA to prevent it loading + * the TX fifo, and then see if we can stuff it into the FIFO. + */ + dmacr = uap->dmacr; + uap->dmacr &= ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + + if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { + /* + * No space in the FIFO, so enable the transmit interrupt + * so we know when there is space. Note that once we've + * loaded the character, we should just re-enable DMA. + */ + return false; + } + + writew(uap->port.x_char, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + uap->port.x_char = 0; + + /* Success - restore the DMA state */ + uap->dmacr = dmacr; + writew(dmacr, uap->port.membase + UART011_DMACR); + + return true; +} + +/* + * Flush the transmit buffer. + * Locking: called with port lock held and IRQs disabled. + */ +static void pl011_dma_flush_buffer(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + if (!uap->using_dma) + return; + + /* Avoid deadlock with the DMA engine callback */ + spin_unlock(&uap->port.lock); + dmaengine_terminate_all(uap->dmatx.chan); + spin_lock(&uap->port.lock); + if (uap->dmatx.queued) { + dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, + DMA_TO_DEVICE); + uap->dmatx.queued = false; + uap->dmacr &= ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + } +} + + +static void pl011_dma_startup(struct uart_amba_port *uap) +{ + if (!uap->dmatx.chan) + return; + + uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); + if (!uap->dmatx.buf) { + dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); + uap->port.fifosize = uap->fifosize; + return; + } + + sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); + + /* The DMA buffer is now the FIFO the TTY subsystem can use */ + uap->port.fifosize = PL011_DMA_BUFFER_SIZE; + uap->using_dma = true; + + /* Turn on DMA error (RX/TX will be enabled on demand) */ + uap->dmacr |= UART011_DMAONERR; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + + /* + * ST Micro variants has some specific dma burst threshold + * compensation. Set this to 16 bytes, so burst will only + * be issued above/below 16 bytes. + */ + if (uap->vendor->dma_threshold) + writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, + uap->port.membase + ST_UART011_DMAWM); +} + +static void pl011_dma_shutdown(struct uart_amba_port *uap) +{ + if (!uap->using_dma) + return; + + /* Disable RX and TX DMA */ + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) + barrier(); + + spin_lock_irq(&uap->port.lock); + uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + spin_unlock_irq(&uap->port.lock); + + /* In theory, this should already be done by pl011_dma_flush_buffer */ + dmaengine_terminate_all(uap->dmatx.chan); + if (uap->dmatx.queued) { + dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, + DMA_TO_DEVICE); + uap->dmatx.queued = false; + } + + kfree(uap->dmatx.buf); + + uap->using_dma = false; +} + +#else +/* Blank functions if the DMA engine is not available */ +static inline void pl011_dma_probe(struct uart_amba_port *uap) +{ +} + +static inline void pl011_dma_remove(struct uart_amba_port *uap) +{ +} + +static inline void pl011_dma_startup(struct uart_amba_port *uap) +{ +} + +static inline void pl011_dma_shutdown(struct uart_amba_port *uap) +{ +} + +static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap) +{ + return false; +} + +static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) +{ +} + +static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) +{ + return false; +} + +#define pl011_dma_flush_buffer NULL +#endif + + +static void pl011_stop_tx(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + uap->im &= ~UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + pl011_dma_tx_stop(uap); +} + +static void pl011_start_tx(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + if (!pl011_dma_tx_start(uap)) { + uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + } +} + +static void pl011_stop_rx(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| + UART011_PEIM|UART011_BEIM|UART011_OEIM); + writew(uap->im, uap->port.membase + UART011_IMSC); +} + +static void pl011_enable_ms(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; + writew(uap->im, uap->port.membase + UART011_IMSC); +} + +static void pl011_rx_chars(struct uart_amba_port *uap) +{ + struct tty_struct *tty = uap->port.state->port.tty; + unsigned int status, ch, flag, max_count = 256; + + status = readw(uap->port.membase + UART01x_FR); + while ((status & UART01x_FR_RXFE) == 0 && max_count--) { + ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX; + flag = TTY_NORMAL; + uap->port.icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (unlikely(ch & UART_DR_ERROR)) { + if (ch & UART011_DR_BE) { + ch &= ~(UART011_DR_FE | UART011_DR_PE); + uap->port.icount.brk++; + if (uart_handle_break(&uap->port)) + goto ignore_char; + } else if (ch & UART011_DR_PE) + uap->port.icount.parity++; + else if (ch & UART011_DR_FE) + uap->port.icount.frame++; + if (ch & UART011_DR_OE) + uap->port.icount.overrun++; + + ch &= uap->port.read_status_mask; + + if (ch & UART011_DR_BE) + flag = TTY_BREAK; + else if (ch & UART011_DR_PE) + flag = TTY_PARITY; + else if (ch & UART011_DR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&uap->port, ch & 255)) + goto ignore_char; + + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); + + ignore_char: + status = readw(uap->port.membase + UART01x_FR); + } + spin_unlock(&uap->port.lock); + tty_flip_buffer_push(tty); + spin_lock(&uap->port.lock); +} + +static void pl011_tx_chars(struct uart_amba_port *uap) +{ + struct circ_buf *xmit = &uap->port.state->xmit; + int count; + + if (uap->port.x_char) { + writew(uap->port.x_char, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + uap->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + pl011_stop_tx(&uap->port); + return; + } + + /* If we are using DMA mode, try to send some characters. */ + if (pl011_dma_tx_irq(uap)) + return; + + count = uap->fifosize >> 1; + do { + writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uap->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + + if (uart_circ_empty(xmit)) + pl011_stop_tx(&uap->port); +} + +static void pl011_modem_status(struct uart_amba_port *uap) +{ + unsigned int status, delta; + + status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + + delta = status ^ uap->old_status; + uap->old_status = status; + + if (!delta) + return; + + if (delta & UART01x_FR_DCD) + uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); + + if (delta & UART01x_FR_DSR) + uap->port.icount.dsr++; + + if (delta & UART01x_FR_CTS) + uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); +} + +static irqreturn_t pl011_int(int irq, void *dev_id) +{ + struct uart_amba_port *uap = dev_id; + unsigned long flags; + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + int handled = 0; + + spin_lock_irqsave(&uap->port.lock, flags); + + status = readw(uap->port.membase + UART011_MIS); + if (status) { + do { + writew(status & ~(UART011_TXIS|UART011_RTIS| + UART011_RXIS), + uap->port.membase + UART011_ICR); + + if (status & (UART011_RTIS|UART011_RXIS)) + pl011_rx_chars(uap); + if (status & (UART011_DSRMIS|UART011_DCDMIS| + UART011_CTSMIS|UART011_RIMIS)) + pl011_modem_status(uap); + if (status & UART011_TXIS) + pl011_tx_chars(uap); + + if (pass_counter-- == 0) + break; + + status = readw(uap->port.membase + UART011_MIS); + } while (status != 0); + handled = 1; + } + + spin_unlock_irqrestore(&uap->port.lock, flags); + + return IRQ_RETVAL(handled); +} + +static unsigned int pl01x_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) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int result = 0; + unsigned int status = readw(uap->port.membase + UART01x_FR); + +#define TIOCMBIT(uartbit, tiocmbit) \ + if (status & uartbit) \ + result |= tiocmbit + + TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); + TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); + TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); + TIOCMBIT(UART011_FR_RI, TIOCM_RNG); +#undef TIOCMBIT + return result; +} + +static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int cr; + + cr = readw(uap->port.membase + UART011_CR); + +#define TIOCMBIT(tiocmbit, uartbit) \ + if (mctrl & tiocmbit) \ + cr |= uartbit; \ + else \ + cr &= ~uartbit + + TIOCMBIT(TIOCM_RTS, UART011_CR_RTS); + TIOCMBIT(TIOCM_DTR, UART011_CR_DTR); + TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1); + TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2); + TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE); + + if (uap->autorts) { + /* We need to disable auto-RTS if we want to turn RTS off */ + TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN); + } +#undef TIOCMBIT + + writew(cr, uap->port.membase + UART011_CR); +} + +static void pl011_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned long flags; + unsigned int lcr_h; + + spin_lock_irqsave(&uap->port.lock, flags); + lcr_h = readw(uap->port.membase + uap->lcrh_tx); + if (break_state == -1) + lcr_h |= UART01x_LCRH_BRK; + else + lcr_h &= ~UART01x_LCRH_BRK; + writew(lcr_h, uap->port.membase + uap->lcrh_tx); + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +#ifdef CONFIG_CONSOLE_POLL +static int pl010_get_poll_char(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int status; + + status = readw(uap->port.membase + UART01x_FR); + if (status & UART01x_FR_RXFE) + return NO_POLL_CHAR; + + return readw(uap->port.membase + UART01x_DR); +} + +static void pl010_put_poll_char(struct uart_port *port, + unsigned char ch) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + barrier(); + + writew(ch, uap->port.membase + UART01x_DR); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +static int pl011_startup(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int cr; + int retval; + + /* + * Try to enable the clock producer. + */ + retval = clk_enable(uap->clk); + if (retval) + goto out; + + uap->port.uartclk = clk_get_rate(uap->clk); + + /* + * Allocate the IRQ + */ + retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); + if (retval) + goto clk_dis; + + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + + /* + * Provoke TX FIFO interrupt into asserting. + */ + cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; + writew(cr, uap->port.membase + UART011_CR); + writew(0, uap->port.membase + UART011_FBRD); + writew(1, uap->port.membase + UART011_IBRD); + writew(0, uap->port.membase + uap->lcrh_rx); + if (uap->lcrh_tx != uap->lcrh_rx) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, uap->port.membase + UART011_MIS); + writew(0, uap->port.membase + uap->lcrh_tx); + } + writew(0, uap->port.membase + UART01x_DR); + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) + barrier(); + + cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; + writew(cr, uap->port.membase + UART011_CR); + + /* Clear pending error interrupts */ + writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, + uap->port.membase + UART011_ICR); + + /* + * initialise the old status of the modem signals + */ + uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + + /* Startup DMA */ + pl011_dma_startup(uap); + + /* + * Finally, enable interrupts + */ + spin_lock_irq(&uap->port.lock); + uap->im = UART011_RXIM | UART011_RTIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + spin_unlock_irq(&uap->port.lock); + + return 0; + + clk_dis: + clk_disable(uap->clk); + out: + return retval; +} + +static void pl011_shutdown_channel(struct uart_amba_port *uap, + unsigned int lcrh) +{ + unsigned long val; + + val = readw(uap->port.membase + lcrh); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + writew(val, uap->port.membase + lcrh); +} + +static void pl011_shutdown(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + /* + * disable all interrupts + */ + spin_lock_irq(&uap->port.lock); + uap->im = 0; + writew(uap->im, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); + spin_unlock_irq(&uap->port.lock); + + pl011_dma_shutdown(uap); + + /* + * Free the interrupt + */ + free_irq(uap->port.irq, uap); + + /* + * disable the port + */ + uap->autorts = false; + writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR); + + /* + * disable break condition and fifos + */ + pl011_shutdown_channel(uap, uap->lcrh_rx); + if (uap->lcrh_rx != uap->lcrh_tx) + pl011_shutdown_channel(uap, uap->lcrh_tx); + + /* + * Shut down the clock producer + */ + clk_disable(uap->clk); +} + +static void +pl011_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int lcr_h, old_cr; + unsigned long flags; + unsigned int baud, quot, clkdiv; + + if (uap->vendor->oversampling) + clkdiv = 8; + else + clkdiv = 16; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, + port->uartclk / clkdiv); + + if (baud > port->uartclk/16) + quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); + else + quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); + + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr_h = UART01x_LCRH_WLEN_5; + break; + case CS6: + lcr_h = UART01x_LCRH_WLEN_6; + break; + case CS7: + lcr_h = UART01x_LCRH_WLEN_7; + break; + default: // CS8 + lcr_h = UART01x_LCRH_WLEN_8; + break; + } + if (termios->c_cflag & CSTOPB) + lcr_h |= UART01x_LCRH_STP2; + if (termios->c_cflag & PARENB) { + lcr_h |= UART01x_LCRH_PEN; + if (!(termios->c_cflag & PARODD)) + lcr_h |= UART01x_LCRH_EPS; + } + if (uap->fifosize > 1) + lcr_h |= UART01x_LCRH_FEN; + + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UART011_DR_OE | 255; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART011_DR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART011_DR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART011_DR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_DR_RX; + + if (UART_ENABLE_MS(port, termios->c_cflag)) + pl011_enable_ms(port); + + /* first, disable everything */ + old_cr = readw(port->membase + UART011_CR); + writew(0, port->membase + UART011_CR); + + if (termios->c_cflag & CRTSCTS) { + if (old_cr & UART011_CR_RTS) + old_cr |= UART011_CR_RTSEN; + + old_cr |= UART011_CR_CTSEN; + uap->autorts = true; + } else { + old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN); + uap->autorts = false; + } + + if (uap->vendor->oversampling) { + if (baud > port->uartclk / 16) + old_cr |= ST_UART011_CR_OVSFACT; + else + old_cr &= ~ST_UART011_CR_OVSFACT; + } + + /* Set baud rate */ + writew(quot & 0x3f, port->membase + UART011_FBRD); + writew(quot >> 6, port->membase + UART011_IBRD); + + /* + * ----------v----------v----------v----------v----- + * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * ----------^----------^----------^----------^----- + */ + writew(lcr_h, port->membase + uap->lcrh_rx); + if (uap->lcrh_rx != uap->lcrh_tx) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, uap->port.membase + UART011_MIS); + writew(lcr_h, port->membase + uap->lcrh_tx); + } + writew(old_cr, port->membase + UART011_CR); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *pl011_type(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + return uap->port.type == PORT_AMBA ? uap->type : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void pl010_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, SZ_4K); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int pl010_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void pl010_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_AMBA; + pl010_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= nr_irqs) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops amba_pl011_pops = { + .tx_empty = pl01x_tx_empty, + .set_mctrl = pl011_set_mctrl, + .get_mctrl = pl01x_get_mctrl, + .stop_tx = pl011_stop_tx, + .start_tx = pl011_start_tx, + .stop_rx = pl011_stop_rx, + .enable_ms = pl011_enable_ms, + .break_ctl = pl011_break_ctl, + .startup = pl011_startup, + .shutdown = pl011_shutdown, + .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, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = pl010_get_poll_char, + .poll_put_char = pl010_put_poll_char, +#endif +}; + +static struct uart_amba_port *amba_ports[UART_NR]; + +#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE + +static void pl011_console_putchar(struct uart_port *port, int ch) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + barrier(); + writew(ch, uap->port.membase + UART01x_DR); +} + +static void +pl011_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_amba_port *uap = amba_ports[co->index]; + unsigned int status, old_cr, new_cr; + + clk_enable(uap->clk); + + /* + * First save the CR then disable the interrupts + */ + old_cr = readw(uap->port.membase + UART011_CR); + new_cr = old_cr & ~UART011_CR_CTSEN; + new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; + writew(new_cr, uap->port.membase + UART011_CR); + + uart_console_write(&uap->port, s, count, pl011_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = readw(uap->port.membase + UART01x_FR); + } while (status & UART01x_FR_BUSY); + writew(old_cr, uap->port.membase + UART011_CR); + + clk_disable(uap->clk); +} + +static void __init +pl011_console_get_options(struct uart_amba_port *uap, int *baud, + int *parity, int *bits) +{ + if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { + unsigned int lcr_h, ibrd, fbrd; + + lcr_h = readw(uap->port.membase + uap->lcrh_tx); + + *parity = 'n'; + if (lcr_h & UART01x_LCRH_PEN) { + if (lcr_h & UART01x_LCRH_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) + *bits = 7; + else + *bits = 8; + + ibrd = readw(uap->port.membase + UART011_IBRD); + fbrd = readw(uap->port.membase + UART011_FBRD); + + *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); + + if (uap->vendor->oversampling) { + if (readw(uap->port.membase + UART011_CR) + & ST_UART011_CR_OVSFACT) + *baud *= 2; + } + } +} + +static int __init pl011_console_setup(struct console *co, char *options) +{ + struct uart_amba_port *uap; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + uap = amba_ports[co->index]; + if (!uap) + return -ENODEV; + + uap->port.uartclk = clk_get_rate(uap->clk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + pl011_console_get_options(uap, &baud, &parity, &bits); + + return uart_set_options(&uap->port, co, baud, parity, bits, flow); +} + +static struct uart_driver amba_reg; +static struct console amba_console = { + .name = "ttyAMA", + .write = pl011_console_write, + .device = uart_console_device, + .setup = pl011_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &amba_reg, +}; + +#define AMBA_CONSOLE (&amba_console) +#else +#define AMBA_CONSOLE NULL +#endif + +static struct uart_driver amba_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyAMA", + .dev_name = "ttyAMA", + .major = SERIAL_AMBA_MAJOR, + .minor = SERIAL_AMBA_MINOR, + .nr = UART_NR, + .cons = AMBA_CONSOLE, +}; + +static int pl011_probe(struct amba_device *dev, struct amba_id *id) +{ + struct uart_amba_port *uap; + struct vendor_data *vendor = id->data; + void __iomem *base; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) + if (amba_ports[i] == NULL) + break; + + if (i == ARRAY_SIZE(amba_ports)) { + ret = -EBUSY; + goto out; + } + + uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); + if (uap == NULL) { + ret = -ENOMEM; + goto out; + } + + base = ioremap(dev->res.start, resource_size(&dev->res)); + if (!base) { + ret = -ENOMEM; + goto free; + } + + uap->clk = clk_get(&dev->dev, NULL); + if (IS_ERR(uap->clk)) { + ret = PTR_ERR(uap->clk); + goto unmap; + } + + uap->vendor = vendor; + uap->lcrh_rx = vendor->lcrh_rx; + uap->lcrh_tx = vendor->lcrh_tx; + uap->fifosize = vendor->fifosize; + uap->port.dev = &dev->dev; + uap->port.mapbase = dev->res.start; + uap->port.membase = base; + uap->port.iotype = UPIO_MEM; + uap->port.irq = dev->irq[0]; + uap->port.fifosize = uap->fifosize; + uap->port.ops = &amba_pl011_pops; + uap->port.flags = UPF_BOOT_AUTOCONF; + uap->port.line = i; + pl011_dma_probe(uap); + + snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + + amba_ports[i] = uap; + + amba_set_drvdata(dev, uap); + ret = uart_add_one_port(&amba_reg, &uap->port); + if (ret) { + amba_set_drvdata(dev, NULL); + amba_ports[i] = NULL; + pl011_dma_remove(uap); + clk_put(uap->clk); + unmap: + iounmap(base); + free: + kfree(uap); + } + out: + return ret; +} + +static int pl011_remove(struct amba_device *dev) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + int i; + + amba_set_drvdata(dev, NULL); + + uart_remove_one_port(&amba_reg, &uap->port); + + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) + if (amba_ports[i] == uap) + amba_ports[i] = NULL; + + pl011_dma_remove(uap); + iounmap(uap->port.membase); + clk_put(uap->clk); + kfree(uap); + return 0; +} + +#ifdef CONFIG_PM +static int pl011_suspend(struct amba_device *dev, pm_message_t state) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + + if (!uap) + return -EINVAL; + + return uart_suspend_port(&amba_reg, &uap->port); +} + +static int pl011_resume(struct amba_device *dev) +{ + struct uart_amba_port *uap = amba_get_drvdata(dev); + + if (!uap) + return -EINVAL; + + return uart_resume_port(&amba_reg, &uap->port); +} +#endif + +static struct amba_id pl011_ids[] = { + { + .id = 0x00041011, + .mask = 0x000fffff, + .data = &vendor_arm, + }, + { + .id = 0x00380802, + .mask = 0x00ffffff, + .data = &vendor_st, + }, + { 0, 0 }, +}; + +static struct amba_driver pl011_driver = { + .drv = { + .name = "uart-pl011", + }, + .id_table = pl011_ids, + .probe = pl011_probe, + .remove = pl011_remove, +#ifdef CONFIG_PM + .suspend = pl011_suspend, + .resume = pl011_resume, +#endif +}; + +static int __init pl011_init(void) +{ + int ret; + printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); + + ret = uart_register_driver(&amba_reg); + if (ret == 0) { + ret = amba_driver_register(&pl011_driver); + if (ret) + uart_unregister_driver(&amba_reg); + } + return ret; +} + +static void __exit pl011_exit(void) +{ + amba_driver_unregister(&pl011_driver); + uart_unregister_driver(&amba_reg); +} + +/* + * While this can be a module, if builtin it's most likely the console + * So let's leave module_exit but move module_init to an earlier place + */ +arch_initcall(pl011_init); +module_exit(pl011_exit); + +MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("ARM AMBA serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c new file mode 100644 index 000000000000..095a5d562618 --- /dev/null +++ b/drivers/tty/serial/apbuart.c @@ -0,0 +1,709 @@ +/* + * Driver for GRLIB serial ports (APBUART) + * + * Based on linux/drivers/serial/amba.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2003 Konrad Eisele + * Copyright (C) 2006 Daniel Hellstrom , Aeroflex Gaisler AB + * Copyright (C) 2008 Gilead Kutnick + * Copyright (C) 2009 Kristoffer Glembo , Aeroflex Gaisler AB + */ + +#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apbuart.h" + +#define SERIAL_APBUART_MAJOR TTY_MAJOR +#define SERIAL_APBUART_MINOR 64 +#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */ + +static void apbuart_tx_chars(struct uart_port *port); + +static void apbuart_stop_tx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CTRL(port); + cr &= ~UART_CTRL_TI; + UART_PUT_CTRL(port, cr); +} + +static void apbuart_start_tx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CTRL(port); + cr |= UART_CTRL_TI; + UART_PUT_CTRL(port, cr); + + if (UART_GET_STATUS(port) & UART_STATUS_THE) + apbuart_tx_chars(port); +} + +static void apbuart_stop_rx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CTRL(port); + cr &= ~(UART_CTRL_RI); + UART_PUT_CTRL(port, cr); +} + +static void apbuart_enable_ms(struct uart_port *port) +{ + /* No modem status change interrupts for APBUART */ +} + +static void apbuart_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = port->state->port.tty; + unsigned int status, ch, rsr, flag; + unsigned int max_chars = port->fifosize; + + status = UART_GET_STATUS(port); + + while (UART_RX_DATA(status) && (max_chars--)) { + + ch = UART_GET_CHAR(port); + flag = TTY_NORMAL; + + port->icount.rx++; + + rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX; + UART_PUT_STATUS(port, 0); + if (rsr & UART_STATUS_ERR) { + + if (rsr & UART_STATUS_BR) { + rsr &= ~(UART_STATUS_FE | UART_STATUS_PE); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } else if (rsr & UART_STATUS_PE) { + port->icount.parity++; + } else if (rsr & UART_STATUS_FE) { + port->icount.frame++; + } + if (rsr & UART_STATUS_OE) + port->icount.overrun++; + + rsr &= port->read_status_mask; + + if (rsr & UART_STATUS_PE) + flag = TTY_PARITY; + else if (rsr & UART_STATUS_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag); + + + ignore_char: + status = UART_GET_STATUS(port); + } + + tty_flip_buffer_push(tty); +} + +static void apbuart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + int count; + + if (port->x_char) { + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + apbuart_stop_tx(port); + return; + } + + /* amba: fill FIFO */ + count = port->fifosize >> 1; + do { + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + apbuart_stop_tx(port); +} + +static irqreturn_t apbuart_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned int status; + + spin_lock(&port->lock); + + status = UART_GET_STATUS(port); + if (status & UART_STATUS_DR) + apbuart_rx_chars(port); + if (status & UART_STATUS_THE) + apbuart_tx_chars(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int apbuart_tx_empty(struct uart_port *port) +{ + unsigned int status = UART_GET_STATUS(port); + return status & UART_STATUS_THE ? TIOCSER_TEMT : 0; +} + +static unsigned int apbuart_get_mctrl(struct uart_port *port) +{ + /* The GRLIB APBUART handles flow control in hardware */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* The GRLIB APBUART handles flow control in hardware */ +} + +static void apbuart_break_ctl(struct uart_port *port, int break_state) +{ + /* We don't support sending break */ +} + +static int apbuart_startup(struct uart_port *port) +{ + int retval; + unsigned int cr; + + /* Allocate the IRQ */ + retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port); + if (retval) + return retval; + + /* Finally, enable interrupts */ + cr = UART_GET_CTRL(port); + UART_PUT_CTRL(port, + cr | UART_CTRL_RE | UART_CTRL_TE | + UART_CTRL_RI | UART_CTRL_TI); + + return 0; +} + +static void apbuart_shutdown(struct uart_port *port) +{ + unsigned int cr; + + /* disable all interrupts, disable the port */ + cr = UART_GET_CTRL(port); + UART_PUT_CTRL(port, + cr & ~(UART_CTRL_RE | UART_CTRL_TE | + UART_CTRL_RI | UART_CTRL_TI)); + + /* Free the interrupt */ + free_irq(port->irq, port); +} + +static void apbuart_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + unsigned int cr; + unsigned long flags; + unsigned int baud, quot; + + /* Ask the core to calculate the divisor for us. */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + if (baud == 0) + panic("invalid baudrate %i\n", port->uartclk / 16); + + /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */ + quot = (uart_get_divisor(port, baud)) * 2; + cr = UART_GET_CTRL(port); + cr &= ~(UART_CTRL_PE | UART_CTRL_PS); + + if (termios->c_cflag & PARENB) { + cr |= UART_CTRL_PE; + if ((termios->c_cflag & PARODD)) + cr |= UART_CTRL_PS; + } + + /* Enable flow control. */ + if (termios->c_cflag & CRTSCTS) + cr |= UART_CTRL_FL; + + spin_lock_irqsave(&port->lock, flags); + + /* Update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UART_STATUS_OE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE; + + /* Characters to ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE; + + /* Ignore all characters if CREAD is not set. */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_RSR_RX; + + /* Set baud rate */ + quot -= 1; + UART_PUT_SCAL(port, quot); + UART_PUT_CTRL(port, cr); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *apbuart_type(struct uart_port *port) +{ + return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL; +} + +static void apbuart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 0x100); +} + +static int apbuart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, 0x100, "grlib-apbuart") + != NULL ? 0 : -EBUSY; + return 0; +} + +/* Configure/autoconfigure the port */ +static void apbuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_APBUART; + apbuart_request_port(port); + } +} + +/* Verify the new serial_struct (for TIOCSSERIAL) */ +static int apbuart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops grlib_apbuart_ops = { + .tx_empty = apbuart_tx_empty, + .set_mctrl = apbuart_set_mctrl, + .get_mctrl = apbuart_get_mctrl, + .stop_tx = apbuart_stop_tx, + .start_tx = apbuart_start_tx, + .stop_rx = apbuart_stop_rx, + .enable_ms = apbuart_enable_ms, + .break_ctl = apbuart_break_ctl, + .startup = apbuart_startup, + .shutdown = apbuart_shutdown, + .set_termios = apbuart_set_termios, + .type = apbuart_type, + .release_port = apbuart_release_port, + .request_port = apbuart_request_port, + .config_port = apbuart_config_port, + .verify_port = apbuart_verify_port, +}; + +static struct uart_port grlib_apbuart_ports[UART_NR]; +static struct device_node *grlib_apbuart_nodes[UART_NR]; + +static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber) +{ + int ctrl, loop = 0; + int status; + int fifosize; + unsigned long flags; + + ctrl = UART_GET_CTRL(port); + + /* + * Enable the transceiver and wait for it to be ready to send data. + * Clear interrupts so that this process will not be externally + * interrupted in the middle (which can cause the transceiver to + * drain prematurely). + */ + + local_irq_save(flags); + + UART_PUT_CTRL(port, ctrl | UART_CTRL_TE); + + while (!UART_TX_READY(UART_GET_STATUS(port))) + loop++; + + /* + * Disable the transceiver so data isn't actually sent during the + * actual test. + */ + + UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE)); + + fifosize = 1; + UART_PUT_CHAR(port, 0); + + /* + * So long as transmitting a character increments the tranceivier FIFO + * length the FIFO must be at least that big. These bytes will + * automatically drain off of the FIFO. + */ + + status = UART_GET_STATUS(port); + while (((status >> 20) & 0x3F) == fifosize) { + fifosize++; + UART_PUT_CHAR(port, 0); + status = UART_GET_STATUS(port); + } + + fifosize--; + + UART_PUT_CTRL(port, ctrl); + local_irq_restore(flags); + + if (fifosize == 0) + fifosize = 1; + + return fifosize; +} + +static void apbuart_flush_fifo(struct uart_port *port) +{ + int i; + + for (i = 0; i < port->fifosize; i++) + UART_GET_CHAR(port); +} + + +/* ======================================================================== */ +/* Console driver, if enabled */ +/* ======================================================================== */ + +#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE + +static void apbuart_console_putchar(struct uart_port *port, int ch) +{ + unsigned int status; + do { + status = UART_GET_STATUS(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, ch); +} + +static void +apbuart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &grlib_apbuart_ports[co->index]; + unsigned int status, old_cr, new_cr; + + /* First save the CR then disable the interrupts */ + old_cr = UART_GET_CTRL(port); + new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI); + UART_PUT_CTRL(port, new_cr); + + uart_console_write(port, s, count, apbuart_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = UART_GET_STATUS(port); + } while (!UART_TX_READY(status)); + UART_PUT_CTRL(port, old_cr); +} + +static void __init +apbuart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) { + + unsigned int quot, status; + status = UART_GET_STATUS(port); + + *parity = 'n'; + if (status & UART_CTRL_PE) { + if ((status & UART_CTRL_PS) == 0) + *parity = 'e'; + else + *parity = 'o'; + } + + *bits = 8; + quot = UART_GET_SCAL(port) / 8; + *baud = port->uartclk / (16 * (quot + 1)); + } +} + +static int __init apbuart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n", + co, co->index, options); + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= grlib_apbuart_port_nr) + co->index = 0; + + port = &grlib_apbuart_ports[co->index]; + + spin_lock_init(&port->lock); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + apbuart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver grlib_apbuart_driver; + +static struct console grlib_apbuart_console = { + .name = "ttyS", + .write = apbuart_console_write, + .device = uart_console_device, + .setup = apbuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &grlib_apbuart_driver, +}; + + +static int grlib_apbuart_configure(void); + +static int __init apbuart_console_init(void) +{ + if (grlib_apbuart_configure()) + return -ENODEV; + register_console(&grlib_apbuart_console); + return 0; +} + +console_initcall(apbuart_console_init); + +#define APBUART_CONSOLE (&grlib_apbuart_console) +#else +#define APBUART_CONSOLE NULL +#endif + +static struct uart_driver grlib_apbuart_driver = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = SERIAL_APBUART_MAJOR, + .minor = SERIAL_APBUART_MINOR, + .nr = UART_NR, + .cons = APBUART_CONSOLE, +}; + + +/* ======================================================================== */ +/* OF Platform Driver */ +/* ======================================================================== */ + +static int __devinit apbuart_probe(struct platform_device *op, + const struct of_device_id *match) +{ + int i = -1; + struct uart_port *port = NULL; + + i = 0; + for (i = 0; i < grlib_apbuart_port_nr; i++) { + if (op->dev.of_node == grlib_apbuart_nodes[i]) + break; + } + + port = &grlib_apbuart_ports[i]; + port->dev = &op->dev; + + uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port); + + apbuart_flush_fifo((struct uart_port *) port); + + printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n", + (unsigned long long) port->mapbase, port->irq); + return 0; +} + +static struct of_device_id __initdata apbuart_match[] = { + { + .name = "GAISLER_APBUART", + }, + { + .name = "01_00c", + }, + {}, +}; + +static struct of_platform_driver grlib_apbuart_of_driver = { + .probe = apbuart_probe, + .driver = { + .owner = THIS_MODULE, + .name = "grlib-apbuart", + .of_match_table = apbuart_match, + }, +}; + + +static int grlib_apbuart_configure(void) +{ + struct device_node *np, *rp; + const u32 *prop; + int freq_khz, line = 0; + + /* Get bus frequency */ + rp = of_find_node_by_path("/"); + if (!rp) + return -ENODEV; + rp = of_get_next_child(rp, NULL); + if (!rp) + return -ENODEV; + prop = of_get_property(rp, "clock-frequency", NULL); + if (!prop) + return -ENODEV; + freq_khz = *prop; + + for_each_matching_node(np, apbuart_match) { + const int *irqs, *ampopts; + const struct amba_prom_registers *regs; + struct uart_port *port; + unsigned long addr; + + ampopts = of_get_property(np, "ampopts", NULL); + if (ampopts && (*ampopts == 0)) + continue; /* Ignore if used by another OS instance */ + + irqs = of_get_property(np, "interrupts", NULL); + regs = of_get_property(np, "reg", NULL); + + if (!irqs || !regs) + continue; + + grlib_apbuart_nodes[line] = np; + + addr = regs->phys_addr; + + port = &grlib_apbuart_ports[line]; + + port->mapbase = addr; + port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map)); + port->irq = *irqs; + port->iotype = UPIO_MEM; + port->ops = &grlib_apbuart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->line = line; + port->uartclk = freq_khz * 1000; + port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line); + line++; + + /* We support maximum UART_NR uarts ... */ + if (line == UART_NR) + break; + } + + grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line; + return line ? 0 : -ENODEV; +} + +static int __init grlib_apbuart_init(void) +{ + int ret; + + /* Find all APBUARTS in device the tree and initialize their ports */ + ret = grlib_apbuart_configure(); + if (ret) + return ret; + + printk(KERN_INFO "Serial: GRLIB APBUART driver\n"); + + ret = uart_register_driver(&grlib_apbuart_driver); + + if (ret) { + printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", + __FILE__, ret); + return ret; + } + + ret = of_register_platform_driver(&grlib_apbuart_of_driver); + if (ret) { + printk(KERN_ERR + "%s: of_register_platform_driver failed (%i)\n", + __FILE__, ret); + uart_unregister_driver(&grlib_apbuart_driver); + return ret; + } + + return ret; +} + +static void __exit grlib_apbuart_exit(void) +{ + int i; + + for (i = 0; i < grlib_apbuart_port_nr; i++) + uart_remove_one_port(&grlib_apbuart_driver, + &grlib_apbuart_ports[i]); + + uart_unregister_driver(&grlib_apbuart_driver); + of_unregister_platform_driver(&grlib_apbuart_of_driver); +} + +module_init(grlib_apbuart_init); +module_exit(grlib_apbuart_exit); + +MODULE_AUTHOR("Aeroflex Gaisler AB"); +MODULE_DESCRIPTION("GRLIB APBUART serial driver"); +MODULE_VERSION("2.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/apbuart.h b/drivers/tty/serial/apbuart.h new file mode 100644 index 000000000000..5faf87c8d2bc --- /dev/null +++ b/drivers/tty/serial/apbuart.h @@ -0,0 +1,64 @@ +#ifndef __GRLIB_APBUART_H__ +#define __GRLIB_APBUART_H__ + +#include + +#define UART_NR 8 +static int grlib_apbuart_port_nr; + +struct grlib_apbuart_regs_map { + u32 data; + u32 status; + u32 ctrl; + u32 scaler; +}; + +struct amba_prom_registers { + unsigned int phys_addr; + unsigned int reg_size; +}; + +/* + * The following defines the bits in the APBUART Status Registers. + */ +#define UART_STATUS_DR 0x00000001 /* Data Ready */ +#define UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */ +#define UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */ +#define UART_STATUS_BR 0x00000008 /* Break Error */ +#define UART_STATUS_OE 0x00000010 /* RX Overrun Error */ +#define UART_STATUS_PE 0x00000020 /* RX Parity Error */ +#define UART_STATUS_FE 0x00000040 /* RX Framing Error */ +#define UART_STATUS_ERR 0x00000078 /* Error Mask */ + +/* + * The following defines the bits in the APBUART Ctrl Registers. + */ +#define UART_CTRL_RE 0x00000001 /* Receiver enable */ +#define UART_CTRL_TE 0x00000002 /* Transmitter enable */ +#define UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */ +#define UART_CTRL_TI 0x00000008 /* Transmitter irq */ +#define UART_CTRL_PS 0x00000010 /* Parity select */ +#define UART_CTRL_PE 0x00000020 /* Parity enable */ +#define UART_CTRL_FL 0x00000040 /* Flow control enable */ +#define UART_CTRL_LB 0x00000080 /* Loopback enable */ + +#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase)) + +#define APBBASE_DATA_P(port) (&(APBBASE(port)->data)) +#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status)) +#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl)) +#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler)) + +#define UART_GET_CHAR(port) (__raw_readl(APBBASE_DATA_P(port))) +#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port))) +#define UART_GET_STATUS(port) (__raw_readl(APBBASE_STATUS_P(port))) +#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port))) +#define UART_GET_CTRL(port) (__raw_readl(APBBASE_CTRL_P(port))) +#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port))) +#define UART_GET_SCAL(port) (__raw_readl(APBBASE_SCALAR_P(port))) +#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port))) + +#define UART_RX_DATA(s) (((s) & UART_STATUS_DR) != 0) +#define UART_TX_READY(s) (((s) & UART_STATUS_THE) != 0) + +#endif /* __GRLIB_APBUART_H__ */ diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c new file mode 100644 index 000000000000..3892666b5fbd --- /dev/null +++ b/drivers/tty/serial/atmel_serial.c @@ -0,0 +1,1808 @@ +/* + * linux/drivers/char/atmel_serial.c + * + * Driver for Atmel AT91 / AT32 Serial ports + * Copyright (C) 2003 Rick Bronson + * + * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * DMA support added by Chip Coldwell. + * + * 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 +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef CONFIG_ARM +#include +#include +#endif + +#define PDC_BUFFER_SIZE 512 +/* Revisit: We should calculate this based on the actual port settings */ +#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ + +#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +static void atmel_start_rx(struct uart_port *port); +static void atmel_stop_rx(struct uart_port *port); + +#ifdef CONFIG_SERIAL_ATMEL_TTYAT + +/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we + * should coexist with the 8250 driver, such as if we have an external 16C550 + * UART. */ +#define SERIAL_ATMEL_MAJOR 204 +#define MINOR_START 154 +#define ATMEL_DEVICENAME "ttyAT" + +#else + +/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port + * name, but it is legally reserved for the 8250 driver. */ +#define SERIAL_ATMEL_MAJOR TTY_MAJOR +#define MINOR_START 64 +#define ATMEL_DEVICENAME "ttyS" + +#endif + +#define ATMEL_ISR_PASS_LIMIT 256 + +/* UART registers. CR is write-only, hence no GET macro */ +#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) +#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) +#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) +#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER) +#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR) +#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR) +#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR) +#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR) +#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR) +#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR) +#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) +#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) +#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) + + /* PDC registers */ +#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) +#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) + +#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) +#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR) +#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR) +#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR) +#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR) + +#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) +#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) +#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) + +static int (*atmel_open_hook)(struct uart_port *); +static void (*atmel_close_hook)(struct uart_port *); + +struct atmel_dma_buffer { + unsigned char *buf; + dma_addr_t dma_addr; + unsigned int dma_size; + unsigned int ofs; +}; + +struct atmel_uart_char { + u16 status; + u16 ch; +}; + +#define ATMEL_SERIAL_RINGSIZE 1024 + +/* + * We wrap our port structure around the generic uart_port. + */ +struct atmel_uart_port { + struct uart_port uart; /* uart */ + struct clk *clk; /* uart clock */ + int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ + u32 backup_imr; /* IMR saved during suspend */ + int break_active; /* break being received */ + + short use_dma_rx; /* enable PDC receiver */ + short pdc_rx_idx; /* current PDC RX buffer */ + struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ + + short use_dma_tx; /* enable PDC transmitter */ + struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ + + struct tasklet_struct tasklet; + unsigned int irq_status; + unsigned int irq_status_prev; + + struct circ_buf rx_ring; + + struct serial_rs485 rs485; /* rs485 settings */ + unsigned int tx_done_mask; +}; + +static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; + +#ifdef SUPPORT_SYSRQ +static struct console atmel_console; +#endif + +static inline struct atmel_uart_port * +to_atmel_uart_port(struct uart_port *uart) +{ + return container_of(uart, struct atmel_uart_port, uart); +} + +#ifdef CONFIG_SERIAL_ATMEL_PDC +static bool atmel_use_dma_rx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_rx; +} + +static bool atmel_use_dma_tx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_tx; +} +#else +static bool atmel_use_dma_rx(struct uart_port *port) +{ + return false; +} + +static bool atmel_use_dma_tx(struct uart_port *port) +{ + return false; +} +#endif + +/* Enable or disable the rs485 support */ +void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int mode; + + spin_lock(&port->lock); + + /* Disable interrupts */ + UART_PUT_IDR(port, atmel_port->tx_done_mask); + + mode = UART_GET_MR(port); + + /* Resetting serial mode to RS232 (0x0) */ + mode &= ~ATMEL_US_USMODE; + + atmel_port->rs485 = *rs485conf; + + if (rs485conf->flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; + if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) + UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); + mode |= ATMEL_US_USMODE_RS485; + } else { + dev_dbg(port->dev, "Setting UART to RS232\n"); + if (atmel_use_dma_tx(port)) + atmel_port->tx_done_mask = ATMEL_US_ENDTX | + ATMEL_US_TXBUFE; + else + atmel_port->tx_done_mask = ATMEL_US_TXRDY; + } + UART_PUT_MR(port, mode); + + /* Enable interrupts */ + UART_PUT_IER(port, atmel_port->tx_done_mask); + + spin_unlock(&port->lock); + +} + +/* + * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. + */ +static u_int atmel_tx_empty(struct uart_port *port) +{ + return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0; +} + +/* + * Set state of the modem control output lines + */ +static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) +{ + unsigned int control = 0; + unsigned int mode; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + +#ifdef CONFIG_ARCH_AT91RM9200 + if (cpu_is_at91rm9200()) { + /* + * AT91RM9200 Errata #39: RTS0 is not internally connected + * to PA21. We need to drive the pin manually. + */ + if (port->mapbase == AT91RM9200_BASE_US0) { + if (mctrl & TIOCM_RTS) + at91_set_gpio_value(AT91_PIN_PA21, 0); + else + at91_set_gpio_value(AT91_PIN_PA21, 1); + } + } +#endif + + if (mctrl & TIOCM_RTS) + control |= ATMEL_US_RTSEN; + else + control |= ATMEL_US_RTSDIS; + + if (mctrl & TIOCM_DTR) + control |= ATMEL_US_DTREN; + else + control |= ATMEL_US_DTRDIS; + + UART_PUT_CR(port, control); + + /* Local loopback mode? */ + mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE; + if (mctrl & TIOCM_LOOP) + mode |= ATMEL_US_CHMODE_LOC_LOOP; + else + mode |= ATMEL_US_CHMODE_NORMAL; + + /* Resetting serial mode to RS232 (0x0) */ + mode &= ~ATMEL_US_USMODE; + + if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + UART_PUT_TTGR(port, + atmel_port->rs485.delay_rts_after_send); + mode |= ATMEL_US_USMODE_RS485; + } else { + dev_dbg(port->dev, "Setting UART to RS232\n"); + } + UART_PUT_MR(port, mode); +} + +/* + * Get state of the modem control input lines + */ +static u_int atmel_get_mctrl(struct uart_port *port) +{ + unsigned int status, ret = 0; + + status = UART_GET_CSR(port); + + /* + * The control signals are active low. + */ + if (!(status & ATMEL_US_DCD)) + ret |= TIOCM_CD; + if (!(status & ATMEL_US_CTS)) + ret |= TIOCM_CTS; + if (!(status & ATMEL_US_DSR)) + ret |= TIOCM_DSR; + if (!(status & ATMEL_US_RI)) + ret |= TIOCM_RI; + + return ret; +} + +/* + * Stop transmitting. + */ +static void atmel_stop_tx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + } + /* Disable interrupts */ + UART_PUT_IDR(port, atmel_port->tx_done_mask); + + if (atmel_port->rs485.flags & SER_RS485_ENABLED) + atmel_start_rx(port); +} + +/* + * Start transmitting. + */ +static void atmel_start_tx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + /* The transmitter is already running. Yes, we + really need this.*/ + return; + + if (atmel_port->rs485.flags & SER_RS485_ENABLED) + atmel_stop_rx(port); + + /* re-enable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + } + /* Enable interrupts */ + UART_PUT_IER(port, atmel_port->tx_done_mask); +} + +/* + * start receiving - port is in process of being opened. + */ +static void atmel_start_rx(struct uart_port *port) +{ + UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + + if (atmel_use_dma_rx(port)) { + /* enable PDC controller */ + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); + UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + } else { + UART_PUT_IER(port, ATMEL_US_RXRDY); + } +} + +/* + * Stop receiving - port is in process of being closed. + */ +static void atmel_stop_rx(struct uart_port *port) +{ + if (atmel_use_dma_rx(port)) { + /* disable PDC receive */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); + } else { + UART_PUT_IDR(port, ATMEL_US_RXRDY); + } +} + +/* + * Enable modem status interrupts + */ +static void atmel_enable_ms(struct uart_port *port) +{ + UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC + | ATMEL_US_DCDIC | ATMEL_US_CTSIC); +} + +/* + * Control the transmission of a break signal + */ +static void atmel_break_ctl(struct uart_port *port, int break_state) +{ + if (break_state != 0) + UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ + else + UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ +} + +/* + * Stores the incoming character in the ring buffer + */ +static void +atmel_buffer_rx_char(struct uart_port *port, unsigned int status, + unsigned int ch) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *ring = &atmel_port->rx_ring; + struct atmel_uart_char *c; + + if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE)) + /* Buffer overflow, ignore char */ + return; + + c = &((struct atmel_uart_char *)ring->buf)[ring->head]; + c->status = status; + c->ch = ch; + + /* Make sure the character is stored before we update head. */ + smp_wmb(); + + ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1); +} + +/* + * Deal with parity, framing and overrun errors. + */ +static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) +{ + /* clear error */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + + if (status & ATMEL_US_RXBRK) { + /* ignore side-effect */ + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); + port->icount.brk++; + } + if (status & ATMEL_US_PARE) + port->icount.parity++; + if (status & ATMEL_US_FRAME) + port->icount.frame++; + if (status & ATMEL_US_OVRE) + port->icount.overrun++; +} + +/* + * Characters received (called from interrupt handler) + */ +static void atmel_rx_chars(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status, ch; + + status = UART_GET_CSR(port); + while (status & ATMEL_US_RXRDY) { + ch = UART_GET_CHAR(port); + + /* + * note that the error handling code is + * out of the main execution path + */ + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME + | ATMEL_US_OVRE | ATMEL_US_RXBRK) + || atmel_port->break_active)) { + + /* clear error */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + + if (status & ATMEL_US_RXBRK + && !atmel_port->break_active) { + atmel_port->break_active = 1; + UART_PUT_IER(port, ATMEL_US_RXBRK); + } else { + /* + * This is either the end-of-break + * condition or we've received at + * least one character without RXBRK + * being set. In both cases, the next + * RXBRK will indicate start-of-break. + */ + UART_PUT_IDR(port, ATMEL_US_RXBRK); + status &= ~ATMEL_US_RXBRK; + atmel_port->break_active = 0; + } + } + + atmel_buffer_rx_char(port, status, ch); + status = UART_GET_CSR(port); + } + + tasklet_schedule(&atmel_port->tasklet); +} + +/* + * Transmit characters (called from tasklet with TXRDY interrupt + * disabled) + */ +static void atmel_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) { + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + while (UART_GET_CSR(port) & atmel_port->tx_done_mask) { + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + 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); + + if (!uart_circ_empty(xmit)) + /* Enable interrupts */ + UART_PUT_IER(port, atmel_port->tx_done_mask); +} + +/* + * receive interrupt handler. + */ +static void +atmel_handle_receive(struct uart_port *port, unsigned int pending) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_rx(port)) { + /* + * PDC receive. Just schedule the tasklet and let it + * figure out the details. + * + * TODO: We're not handling error flags correctly at + * the moment. + */ + if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { + UART_PUT_IDR(port, (ATMEL_US_ENDRX + | ATMEL_US_TIMEOUT)); + tasklet_schedule(&atmel_port->tasklet); + } + + if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | + ATMEL_US_FRAME | ATMEL_US_PARE)) + atmel_pdc_rxerr(port, pending); + } + + /* Interrupt receive */ + if (pending & ATMEL_US_RXRDY) + atmel_rx_chars(port); + else if (pending & ATMEL_US_RXBRK) { + /* + * End of break detected. If it came along with a + * character, atmel_rx_chars will handle it. + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_port->break_active = 0; + } +} + +/* + * transmit interrupt handler. (Transmit is IRQF_NODELAY safe) + */ +static void +atmel_handle_transmit(struct uart_port *port, unsigned int pending) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (pending & atmel_port->tx_done_mask) { + /* Either PDC or interrupt transmission */ + UART_PUT_IDR(port, atmel_port->tx_done_mask); + tasklet_schedule(&atmel_port->tasklet); + } +} + +/* + * status flags interrupt handler. + */ +static void +atmel_handle_status(struct uart_port *port, unsigned int pending, + unsigned int status) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC + | ATMEL_US_CTSIC)) { + atmel_port->irq_status = status; + tasklet_schedule(&atmel_port->tasklet); + } +} + +/* + * Interrupt handler + */ +static irqreturn_t atmel_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned int status, pending, pass_counter = 0; + + do { + status = UART_GET_CSR(port); + pending = status & UART_GET_IMR(port); + if (!pending) + break; + + atmel_handle_receive(port, pending); + atmel_handle_status(port, pending, status); + atmel_handle_transmit(port, pending); + } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); + + return pass_counter ? IRQ_HANDLED : IRQ_NONE; +} + +/* + * Called from tasklet with ENDTX and TXBUFE interrupts disabled. + */ +static void atmel_tx_dma(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *xmit = &port->state->xmit; + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + int count; + + /* nothing left to transmit? */ + if (UART_GET_TCR(port)) + return; + + xmit->tail += pdc->ofs; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += pdc->ofs; + pdc->ofs = 0; + + /* more to transmit - setup next transfer */ + + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + dma_sync_single_for_device(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); + + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + pdc->ofs = count; + + UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); + UART_PUT_TCR(port, count); + /* re-enable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + /* Enable interrupts */ + UART_PUT_IER(port, atmel_port->tx_done_mask); + } else { + if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + /* DMA done, stop TX, start RX for RS485 */ + atmel_start_rx(port); + } + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void atmel_rx_from_ring(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *ring = &atmel_port->rx_ring; + unsigned int flg; + unsigned int status; + + while (ring->head != ring->tail) { + struct atmel_uart_char c; + + /* Make sure c is loaded after head. */ + smp_rmb(); + + c = ((struct atmel_uart_char *)ring->buf)[ring->tail]; + + ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1); + + port->icount.rx++; + status = c.status; + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME + | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { + if (status & ATMEL_US_RXBRK) { + /* ignore side-effect */ + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); + + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + if (status & ATMEL_US_PARE) + port->icount.parity++; + if (status & ATMEL_US_FRAME) + port->icount.frame++; + if (status & ATMEL_US_OVRE) + port->icount.overrun++; + + status &= port->read_status_mask; + + if (status & ATMEL_US_RXBRK) + flg = TTY_BREAK; + else if (status & ATMEL_US_PARE) + flg = TTY_PARITY; + else if (status & ATMEL_US_FRAME) + flg = TTY_FRAME; + } + + + if (uart_handle_sysrq_char(port, c.ch)) + continue; + + uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); + } + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(port->state->port.tty); + spin_lock(&port->lock); +} + +static void atmel_rx_from_dma(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->state->port.tty; + struct atmel_dma_buffer *pdc; + int rx_idx = atmel_port->pdc_rx_idx; + unsigned int head; + unsigned int tail; + unsigned int count; + + do { + /* Reset the UART timeout early so that we don't miss one */ + UART_PUT_CR(port, ATMEL_US_STTTO); + + pdc = &atmel_port->pdc_rx[rx_idx]; + head = UART_GET_RPR(port) - pdc->dma_addr; + tail = pdc->ofs; + + /* If the PDC has switched buffers, RPR won't contain + * any address within the current buffer. Since head + * is unsigned, we just need a one-way comparison to + * find out. + * + * In this case, we just need to consume the entire + * buffer and resubmit it for DMA. This will clear the + * ENDRX bit as well, so that we can safely re-enable + * all interrupts below. + */ + head = min(head, pdc->dma_size); + + if (likely(head != tail)) { + dma_sync_single_for_cpu(port->dev, pdc->dma_addr, + pdc->dma_size, DMA_FROM_DEVICE); + + /* + * head will only wrap around when we recycle + * the DMA buffer, and when that happens, we + * explicitly set tail to 0. So head will + * always be greater than tail. + */ + count = head - tail; + + tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); + + dma_sync_single_for_device(port->dev, pdc->dma_addr, + pdc->dma_size, DMA_FROM_DEVICE); + + port->icount.rx += count; + pdc->ofs = head; + } + + /* + * If the current buffer is full, we need to check if + * the next one contains any additional data. + */ + if (head >= pdc->dma_size) { + pdc->ofs = 0; + UART_PUT_RNPR(port, pdc->dma_addr); + UART_PUT_RNCR(port, pdc->dma_size); + + rx_idx = !rx_idx; + atmel_port->pdc_rx_idx = rx_idx; + } + } while (head >= pdc->dma_size); + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(tty); + spin_lock(&port->lock); + + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); +} + +/* + * tasklet handling tty stuff outside the interrupt handler. + */ +static void atmel_tasklet_func(unsigned long data) +{ + struct uart_port *port = (struct uart_port *)data; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status; + unsigned int status_change; + + /* The interrupt handler does not take the lock */ + spin_lock(&port->lock); + + if (atmel_use_dma_tx(port)) + atmel_tx_dma(port); + else + atmel_tx_chars(port); + + status = atmel_port->irq_status; + status_change = status ^ atmel_port->irq_status_prev; + + if (status_change & (ATMEL_US_RI | ATMEL_US_DSR + | ATMEL_US_DCD | ATMEL_US_CTS)) { + /* TODO: All reads to CSR will clear these interrupts! */ + if (status_change & ATMEL_US_RI) + port->icount.rng++; + if (status_change & ATMEL_US_DSR) + port->icount.dsr++; + if (status_change & ATMEL_US_DCD) + uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); + if (status_change & ATMEL_US_CTS) + uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + + atmel_port->irq_status_prev = status; + } + + if (atmel_use_dma_rx(port)) + atmel_rx_from_dma(port); + else + atmel_rx_from_ring(port); + + spin_unlock(&port->lock); +} + +/* + * Perform initialization and enable port for reception + */ +static int atmel_startup(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->state->port.tty; + int retval; + + /* + * Ensure that no interrupts are enabled otherwise when + * request_irq() is called we could get stuck trying to + * handle an unexpected interrupt + */ + UART_PUT_IDR(port, -1); + + /* + * Allocate the IRQ + */ + retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, + tty ? tty->name : "atmel_serial", port); + if (retval) { + printk("atmel_serial: atmel_startup - Can't get irq\n"); + return retval; + } + + /* + * Initialize DMA (if necessary) + */ + if (atmel_use_dma_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); + if (pdc->buf == NULL) { + if (i != 0) { + dma_unmap_single(port->dev, + atmel_port->pdc_rx[0].dma_addr, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + kfree(atmel_port->pdc_rx[0].buf); + } + free_irq(port->irq, port); + return -ENOMEM; + } + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + pdc->dma_size = PDC_BUFFER_SIZE; + pdc->ofs = 0; + } + + atmel_port->pdc_rx_idx = 0; + + UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); + UART_PUT_RCR(port, PDC_BUFFER_SIZE); + + UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); + UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + } + if (atmel_use_dma_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + struct circ_buf *xmit = &port->state->xmit; + + pdc->buf = xmit->buf; + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + pdc->dma_size = UART_XMIT_SIZE; + pdc->ofs = 0; + } + + /* + * If there is a specific "open" function (to register + * control line interrupts) + */ + if (atmel_open_hook) { + retval = atmel_open_hook(port); + if (retval) { + free_irq(port->irq, port); + return retval; + } + } + + /* Save current CSR for comparison in atmel_tasklet_func() */ + atmel_port->irq_status_prev = UART_GET_CSR(port); + atmel_port->irq_status = atmel_port->irq_status_prev; + + /* + * Finally, enable the serial port + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + /* enable xmit & rcvr */ + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + + if (atmel_use_dma_rx(port)) { + /* set UART timeout */ + UART_PUT_RTOR(port, PDC_RX_TIMEOUT); + UART_PUT_CR(port, ATMEL_US_STTTO); + + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + /* enable PDC controller */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + } else { + /* enable receive only */ + UART_PUT_IER(port, ATMEL_US_RXRDY); + } + + return 0; +} + +/* + * Disable the port + */ +static void atmel_shutdown(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* + * Ensure everything is stopped. + */ + atmel_stop_rx(port); + atmel_stop_tx(port); + + /* + * Shut-down the DMA. + */ + if (atmel_use_dma_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_FROM_DEVICE); + kfree(pdc->buf); + } + } + if (atmel_use_dma_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); + } + + /* + * Disable all interrupts, port and break condition. + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, -1); + + /* + * Free the interrupt + */ + free_irq(port->irq, port); + + /* + * If there is a specific "close" function (to unregister + * control line interrupts) + */ + if (atmel_close_hook) + atmel_close_hook(port); +} + +/* + * Flush any TX data submitted for DMA. Called when the TX circular + * buffer is reset. + */ +static void atmel_flush_buffer(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + UART_PUT_TCR(port, 0); + atmel_port->pdc_tx.ofs = 0; + } +} + +/* + * Power / Clock management. + */ +static void atmel_serial_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + switch (state) { + case 0: + /* + * Enable the peripheral clock for this serial port. + * This is called on uart_open() or a resume event. + */ + clk_enable(atmel_port->clk); + + /* re-enable interrupts if we disabled some on suspend */ + UART_PUT_IER(port, atmel_port->backup_imr); + break; + case 3: + /* Back up the interrupt mask and disable all interrupts */ + atmel_port->backup_imr = UART_GET_IMR(port); + UART_PUT_IDR(port, -1); + + /* + * Disable the peripheral clock for this serial port. + * This is called on uart_close() or a suspend event. + */ + clk_disable(atmel_port->clk); + break; + default: + printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); + } +} + +/* + * Change the port parameters + */ +static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int mode, imr, quot, baud; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + /* Get current mode register */ + mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL + | ATMEL_US_NBSTOP | ATMEL_US_PAR + | ATMEL_US_USMODE); + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + quot = uart_get_divisor(port, baud); + + if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + quot /= 8; + mode |= ATMEL_US_USCLKS_MCK_DIV8; + } + + /* byte size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + mode |= ATMEL_US_CHRL_5; + break; + case CS6: + mode |= ATMEL_US_CHRL_6; + break; + case CS7: + mode |= ATMEL_US_CHRL_7; + break; + default: + mode |= ATMEL_US_CHRL_8; + break; + } + + /* stop bits */ + if (termios->c_cflag & CSTOPB) + mode |= ATMEL_US_NBSTOP_2; + + /* parity */ + if (termios->c_cflag & PARENB) { + /* Mark or Space parity */ + if (termios->c_cflag & CMSPAR) { + if (termios->c_cflag & PARODD) + mode |= ATMEL_US_PAR_MARK; + else + mode |= ATMEL_US_PAR_SPACE; + } else if (termios->c_cflag & PARODD) + mode |= ATMEL_US_PAR_ODD; + else + mode |= ATMEL_US_PAR_EVEN; + } else + mode |= ATMEL_US_PAR_NONE; + + /* hardware handshake (RTS/CTS) */ + if (termios->c_cflag & CRTSCTS) + mode |= ATMEL_US_USMODE_HWHS; + else + mode |= ATMEL_US_USMODE_NORMAL; + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = ATMEL_US_OVRE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= ATMEL_US_RXBRK; + + if (atmel_use_dma_rx(port)) + /* need to enable error interrupts */ + UART_PUT_IER(port, port->read_status_mask); + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= ATMEL_US_RXBRK; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= ATMEL_US_OVRE; + } + /* TODO: Ignore all characters if CREAD is set.*/ + + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * save/disable interrupts. The tty layer will ensure that the + * transmitter is empty if requested by the caller, so there's + * no need to wait for it here. + */ + imr = UART_GET_IMR(port); + UART_PUT_IDR(port, -1); + + /* disable receiver and transmitter */ + UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); + + /* Resetting serial mode to RS232 (0x0) */ + mode &= ~ATMEL_US_USMODE; + + if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + dev_dbg(port->dev, "Setting UART to RS485\n"); + if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + UART_PUT_TTGR(port, + atmel_port->rs485.delay_rts_after_send); + mode |= ATMEL_US_USMODE_RS485; + } else { + dev_dbg(port->dev, "Setting UART to RS232\n"); + } + + /* set the parity, stop bits and data size */ + UART_PUT_MR(port, mode); + + /* set the baud rate */ + UART_PUT_BRGR(port, quot); + UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + + /* restore interrupts */ + UART_PUT_IER(port, imr); + + /* CTS flow-control and modem-status interrupts */ + if (UART_ENABLE_MS(port, termios->c_cflag)) + port->ops->enable_ms(port); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * Return string describing the specified port + */ +static const char *atmel_type(struct uart_port *port) +{ + return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void atmel_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = pdev->resource[0].end - pdev->resource[0].start + 1; + + release_mem_region(port->mapbase, size); + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int atmel_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = pdev->resource[0].end - pdev->resource[0].start + 1; + + if (!request_mem_region(port->mapbase, size, "atmel_serial")) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, size); + if (port->membase == NULL) { + release_mem_region(port->mapbase, size); + return -ENOMEM; + } + } + + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void atmel_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_ATMEL; + atmel_request_port(port); + } +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + */ +static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL) + ret = -EINVAL; + if (port->irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + ret = -EINVAL; + if (port->uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)port->mapbase != ser->iomem_base) + ret = -EINVAL; + if (port->iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +#ifdef CONFIG_CONSOLE_POLL +static int atmel_poll_get_char(struct uart_port *port) +{ + while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY)) + cpu_relax(); + + return UART_GET_CHAR(port); +} + +static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) +{ + while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + cpu_relax(); + + UART_PUT_CHAR(port, ch); +} +#endif + +static int +atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) +{ + struct serial_rs485 rs485conf; + + switch (cmd) { + case TIOCSRS485: + if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg, + sizeof(rs485conf))) + return -EFAULT; + + atmel_config_rs485(port, &rs485conf); + break; + + case TIOCGRS485: + if (copy_to_user((struct serial_rs485 *) arg, + &(to_atmel_uart_port(port)->rs485), + sizeof(rs485conf))) + return -EFAULT; + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + + + +static struct uart_ops atmel_pops = { + .tx_empty = atmel_tx_empty, + .set_mctrl = atmel_set_mctrl, + .get_mctrl = atmel_get_mctrl, + .stop_tx = atmel_stop_tx, + .start_tx = atmel_start_tx, + .stop_rx = atmel_stop_rx, + .enable_ms = atmel_enable_ms, + .break_ctl = atmel_break_ctl, + .startup = atmel_startup, + .shutdown = atmel_shutdown, + .flush_buffer = atmel_flush_buffer, + .set_termios = atmel_set_termios, + .type = atmel_type, + .release_port = atmel_release_port, + .request_port = atmel_request_port, + .config_port = atmel_config_port, + .verify_port = atmel_verify_port, + .pm = atmel_serial_pm, + .ioctl = atmel_ioctl, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = atmel_poll_get_char, + .poll_put_char = atmel_poll_put_char, +#endif +}; + +/* + * Configure the port from the platform device resource info. + */ +static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, + struct platform_device *pdev) +{ + struct uart_port *port = &atmel_port->uart; + struct atmel_uart_data *data = pdev->dev.platform_data; + + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &atmel_pops; + port->fifosize = 1; + port->line = pdev->id; + port->dev = &pdev->dev; + port->mapbase = pdev->resource[0].start; + port->irq = pdev->resource[1].start; + + tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + (unsigned long)port); + + memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); + + if (data->regs) + /* Already mapped by setup code */ + port->membase = data->regs; + else { + port->flags |= UPF_IOREMAP; + port->membase = NULL; + } + + /* for console, the clock could already be configured */ + if (!atmel_port->clk) { + atmel_port->clk = clk_get(&pdev->dev, "usart"); + clk_enable(atmel_port->clk); + port->uartclk = clk_get_rate(atmel_port->clk); + clk_disable(atmel_port->clk); + /* only enable clock when USART is in use */ + } + + atmel_port->use_dma_rx = data->use_dma_rx; + atmel_port->use_dma_tx = data->use_dma_tx; + atmel_port->rs485 = data->rs485; + /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */ + if (atmel_port->rs485.flags & SER_RS485_ENABLED) + atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; + else if (atmel_use_dma_tx(port)) { + port->fifosize = PDC_BUFFER_SIZE; + atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE; + } else { + atmel_port->tx_done_mask = ATMEL_US_TXRDY; + } +} + +/* + * Register board-specific modem-control line handlers. + */ +void __init atmel_register_uart_fns(struct atmel_port_fns *fns) +{ + if (fns->enable_ms) + atmel_pops.enable_ms = fns->enable_ms; + if (fns->get_mctrl) + atmel_pops.get_mctrl = fns->get_mctrl; + if (fns->set_mctrl) + atmel_pops.set_mctrl = fns->set_mctrl; + atmel_open_hook = fns->open; + atmel_close_hook = fns->close; + atmel_pops.pm = fns->pm; + atmel_pops.set_wake = fns->set_wake; +} + +#ifdef CONFIG_SERIAL_ATMEL_CONSOLE +static void atmel_console_putchar(struct uart_port *port, int ch) +{ + while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + cpu_relax(); + UART_PUT_CHAR(port, ch); +} + +/* + * Interrupts are disabled on entering + */ +static void atmel_console_write(struct console *co, const char *s, u_int count) +{ + struct uart_port *port = &atmel_ports[co->index].uart; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status, imr; + unsigned int pdc_tx; + + /* + * First, save IMR and then disable interrupts + */ + imr = UART_GET_IMR(port); + UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask); + + /* Store PDC transmit status and disable it */ + pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN; + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + + uart_console_write(port, s, count, atmel_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore IMR + */ + do { + status = UART_GET_CSR(port); + } while (!(status & ATMEL_US_TXRDY)); + + /* Restore PDC transmit status */ + if (pdc_tx) + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + + /* set interrupts back the way they were */ + UART_PUT_IER(port, imr); +} + +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init atmel_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + unsigned int mr, quot; + + /* + * If the baud rate generator isn't running, the port wasn't + * initialized by the boot loader. + */ + quot = UART_GET_BRGR(port) & ATMEL_US_CD; + if (!quot) + return; + + mr = UART_GET_MR(port) & ATMEL_US_CHRL; + if (mr == ATMEL_US_CHRL_8) + *bits = 8; + else + *bits = 7; + + mr = UART_GET_MR(port) & ATMEL_US_PAR; + if (mr == ATMEL_US_PAR_EVEN) + *parity = 'e'; + else if (mr == ATMEL_US_PAR_ODD) + *parity = 'o'; + + /* + * The serial core only rounds down when matching this to a + * supported baud rate. Make sure we don't end up slightly + * lower than one of those, as it would make us fall through + * to a much lower baud rate than we really want. + */ + *baud = port->uartclk / (16 * (quot - 1)); +} + +static int __init atmel_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &atmel_ports[co->index].uart; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (port->membase == NULL) { + /* Port not initialized yet - delay setup */ + return -ENODEV; + } + + clk_enable(atmel_ports[co->index].clk); + + UART_PUT_IDR(port, -1); + UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + atmel_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver atmel_uart; + +static struct console atmel_console = { + .name = ATMEL_DEVICENAME, + .write = atmel_console_write, + .device = uart_console_device, + .setup = atmel_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &atmel_uart, +}; + +#define ATMEL_CONSOLE_DEVICE (&atmel_console) + +/* + * Early console initialization (before VM subsystem initialized). + */ +static int __init atmel_console_init(void) +{ + if (atmel_default_console_device) { + add_preferred_console(ATMEL_DEVICENAME, + atmel_default_console_device->id, NULL); + atmel_init_port(&atmel_ports[atmel_default_console_device->id], + atmel_default_console_device); + register_console(&atmel_console); + } + + return 0; +} + +console_initcall(atmel_console_init); + +/* + * Late console initialization. + */ +static int __init atmel_late_console_init(void) +{ + if (atmel_default_console_device + && !(atmel_console.flags & CON_ENABLED)) + register_console(&atmel_console); + + return 0; +} + +core_initcall(atmel_late_console_init); + +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return port->cons && port->cons->index == port->line; +} + +#else +#define ATMEL_CONSOLE_DEVICE NULL + +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return false; +} +#endif + +static struct uart_driver atmel_uart = { + .owner = THIS_MODULE, + .driver_name = "atmel_serial", + .dev_name = ATMEL_DEVICENAME, + .major = SERIAL_ATMEL_MAJOR, + .minor = MINOR_START, + .nr = ATMEL_MAX_UART, + .cons = ATMEL_CONSOLE_DEVICE, +}; + +#ifdef CONFIG_PM +static bool atmel_serial_clk_will_stop(void) +{ +#ifdef CONFIG_ARCH_AT91 + return at91_suspend_entering_slow_clock(); +#else + return false; +#endif +} + +static int atmel_serial_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_is_console_port(port) && console_suspend_enabled) { + /* Drain the TX shifter */ + while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) + cpu_relax(); + } + + /* we can not wake up if we're running on slow clock */ + atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); + if (atmel_serial_clk_will_stop()) + device_set_wakeup_enable(&pdev->dev, 0); + + uart_suspend_port(&atmel_uart, port); + + return 0; +} + +static int atmel_serial_resume(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + uart_resume_port(&atmel_uart, port); + device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); + + return 0; +} +#else +#define atmel_serial_suspend NULL +#define atmel_serial_resume NULL +#endif + +static int __devinit atmel_serial_probe(struct platform_device *pdev) +{ + struct atmel_uart_port *port; + void *data; + int ret; + + BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); + + port = &atmel_ports[pdev->id]; + port->backup_imr = 0; + + atmel_init_port(port, pdev); + + if (!atmel_use_dma_rx(&port->uart)) { + ret = -ENOMEM; + data = kmalloc(sizeof(struct atmel_uart_char) + * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); + if (!data) + goto err_alloc_ring; + port->rx_ring.buf = data; + } + + ret = uart_add_one_port(&atmel_uart, &port->uart); + if (ret) + goto err_add_port; + +#ifdef CONFIG_SERIAL_ATMEL_CONSOLE + if (atmel_is_console_port(&port->uart) + && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { + /* + * The serial core enabled the clock for us, so undo + * the clk_enable() in atmel_console_setup() + */ + clk_disable(port->clk); + } +#endif + + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, port); + + return 0; + +err_add_port: + kfree(port->rx_ring.buf); + port->rx_ring.buf = NULL; +err_alloc_ring: + if (!atmel_is_console_port(&port->uart)) { + clk_put(port->clk); + port->clk = NULL; + } + + return ret; +} + +static int __devexit atmel_serial_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + int ret = 0; + + device_init_wakeup(&pdev->dev, 0); + platform_set_drvdata(pdev, NULL); + + ret = uart_remove_one_port(&atmel_uart, port); + + tasklet_kill(&atmel_port->tasklet); + kfree(atmel_port->rx_ring.buf); + + /* "port" is allocated statically, so we shouldn't free it */ + + clk_put(atmel_port->clk); + + return ret; +} + +static struct platform_driver atmel_serial_driver = { + .probe = atmel_serial_probe, + .remove = __devexit_p(atmel_serial_remove), + .suspend = atmel_serial_suspend, + .resume = atmel_serial_resume, + .driver = { + .name = "atmel_usart", + .owner = THIS_MODULE, + }, +}; + +static int __init atmel_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&atmel_uart); + if (ret) + return ret; + + ret = platform_driver_register(&atmel_serial_driver); + if (ret) + uart_unregister_driver(&atmel_uart); + + return ret; +} + +static void __exit atmel_serial_exit(void) +{ + platform_driver_unregister(&atmel_serial_driver); + uart_unregister_driver(&atmel_uart); +} + +module_init(atmel_serial_init); +module_exit(atmel_serial_exit); + +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:atmel_usart"); diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c new file mode 100644 index 000000000000..a1a0e55d0807 --- /dev/null +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -0,0 +1,891 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Derived from many drivers using generic_serial interface. + * + * Copyright (C) 2008 Maxime Bizon + * + * Serial driver for BCM63xx integrated UART. + * + * Hardware flow control was _not_ tested since I only have RX/TX on + * my board. + */ + +#if defined(CONFIG_SERIAL_BCM63XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define BCM63XX_NR_UARTS 2 + +static struct uart_port ports[BCM63XX_NR_UARTS]; + +/* + * rx interrupt mask / stat + * + * mask: + * - rx fifo full + * - rx fifo above threshold + * - rx fifo not empty for too long + */ +#define UART_RX_INT_MASK (UART_IR_MASK(UART_IR_RXOVER) | \ + UART_IR_MASK(UART_IR_RXTHRESH) | \ + UART_IR_MASK(UART_IR_RXTIMEOUT)) + +#define UART_RX_INT_STAT (UART_IR_STAT(UART_IR_RXOVER) | \ + UART_IR_STAT(UART_IR_RXTHRESH) | \ + UART_IR_STAT(UART_IR_RXTIMEOUT)) + +/* + * tx interrupt mask / stat + * + * mask: + * - tx fifo empty + * - tx fifo below threshold + */ +#define UART_TX_INT_MASK (UART_IR_MASK(UART_IR_TXEMPTY) | \ + UART_IR_MASK(UART_IR_TXTRESH)) + +#define UART_TX_INT_STAT (UART_IR_STAT(UART_IR_TXEMPTY) | \ + UART_IR_STAT(UART_IR_TXTRESH)) + +/* + * external input interrupt + * + * mask: any edge on CTS, DCD + */ +#define UART_EXTINP_INT_MASK (UART_EXTINP_IRMASK(UART_EXTINP_IR_CTS) | \ + UART_EXTINP_IRMASK(UART_EXTINP_IR_DCD)) + +/* + * handy uart register accessor + */ +static inline unsigned int bcm_uart_readl(struct uart_port *port, + unsigned int offset) +{ + return bcm_readl(port->membase + offset); +} + +static inline void bcm_uart_writel(struct uart_port *port, + unsigned int value, unsigned int offset) +{ + bcm_writel(value, port->membase + offset); +} + +/* + * serial core request to check if uart tx fifo is empty + */ +static unsigned int bcm_uart_tx_empty(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_IR_REG); + return (val & UART_IR_STAT(UART_IR_TXEMPTY)) ? 1 : 0; +} + +/* + * serial core request to set RTS and DTR pin state and loopback mode + */ +static void bcm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_MCTL_REG); + val &= ~(UART_MCTL_DTR_MASK | UART_MCTL_RTS_MASK); + /* invert of written value is reflected on the pin */ + if (!(mctrl & TIOCM_DTR)) + val |= UART_MCTL_DTR_MASK; + if (!(mctrl & TIOCM_RTS)) + val |= UART_MCTL_RTS_MASK; + bcm_uart_writel(port, val, UART_MCTL_REG); + + val = bcm_uart_readl(port, UART_CTL_REG); + if (mctrl & TIOCM_LOOP) + val |= UART_CTL_LOOPBACK_MASK; + else + val &= ~UART_CTL_LOOPBACK_MASK; + bcm_uart_writel(port, val, UART_CTL_REG); +} + +/* + * serial core request to return RI, CTS, DCD and DSR pin state + */ +static unsigned int bcm_uart_get_mctrl(struct uart_port *port) +{ + unsigned int val, mctrl; + + mctrl = 0; + val = bcm_uart_readl(port, UART_EXTINP_REG); + if (val & UART_EXTINP_RI_MASK) + mctrl |= TIOCM_RI; + if (val & UART_EXTINP_CTS_MASK) + mctrl |= TIOCM_CTS; + if (val & UART_EXTINP_DCD_MASK) + mctrl |= TIOCM_CD; + if (val & UART_EXTINP_DSR_MASK) + mctrl |= TIOCM_DSR; + return mctrl; +} + +/* + * serial core request to disable tx ASAP (used for flow control) + */ +static void bcm_uart_stop_tx(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_CTL_REG); + val &= ~(UART_CTL_TXEN_MASK); + bcm_uart_writel(port, val, UART_CTL_REG); + + val = bcm_uart_readl(port, UART_IR_REG); + val &= ~UART_TX_INT_MASK; + bcm_uart_writel(port, val, UART_IR_REG); +} + +/* + * serial core request to (re)enable tx + */ +static void bcm_uart_start_tx(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_IR_REG); + val |= UART_TX_INT_MASK; + bcm_uart_writel(port, val, UART_IR_REG); + + val = bcm_uart_readl(port, UART_CTL_REG); + val |= UART_CTL_TXEN_MASK; + bcm_uart_writel(port, val, UART_CTL_REG); +} + +/* + * serial core request to stop rx, called before port shutdown + */ +static void bcm_uart_stop_rx(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_IR_REG); + val &= ~UART_RX_INT_MASK; + bcm_uart_writel(port, val, UART_IR_REG); +} + +/* + * serial core request to enable modem status interrupt reporting + */ +static void bcm_uart_enable_ms(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_IR_REG); + val |= UART_IR_MASK(UART_IR_EXTIP); + bcm_uart_writel(port, val, UART_IR_REG); +} + +/* + * serial core request to start/stop emitting break char + */ +static void bcm_uart_break_ctl(struct uart_port *port, int ctl) +{ + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&port->lock, flags); + + val = bcm_uart_readl(port, UART_CTL_REG); + if (ctl) + val |= UART_CTL_XMITBRK_MASK; + else + val &= ~UART_CTL_XMITBRK_MASK; + bcm_uart_writel(port, val, UART_CTL_REG); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * return port type in string format + */ +static const char *bcm_uart_type(struct uart_port *port) +{ + return (port->type == PORT_BCM63XX) ? "bcm63xx_uart" : NULL; +} + +/* + * read all chars in rx fifo and send them to core + */ +static void bcm_uart_do_rx(struct uart_port *port) +{ + struct tty_struct *tty; + unsigned int max_count; + + /* limit number of char read in interrupt, should not be + * higher than fifo size anyway since we're much faster than + * serial port */ + max_count = 32; + tty = port->state->port.tty; + do { + unsigned int iestat, c, cstat; + char flag; + + /* get overrun/fifo empty information from ier + * register */ + iestat = bcm_uart_readl(port, UART_IR_REG); + if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) + break; + + cstat = c = bcm_uart_readl(port, UART_FIFO_REG); + port->icount.rx++; + flag = TTY_NORMAL; + c &= 0xff; + + if (unlikely((cstat & UART_FIFO_ANYERR_MASK))) { + /* do stats first */ + if (cstat & UART_FIFO_BRKDET_MASK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + + if (cstat & UART_FIFO_PARERR_MASK) + port->icount.parity++; + if (cstat & UART_FIFO_FRAMEERR_MASK) + port->icount.frame++; + + /* update flag wrt read_status_mask */ + cstat &= port->read_status_mask; + if (cstat & UART_FIFO_BRKDET_MASK) + flag = TTY_BREAK; + if (cstat & UART_FIFO_FRAMEERR_MASK) + flag = TTY_FRAME; + if (cstat & UART_FIFO_PARERR_MASK) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(port, c)) + continue; + + if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + if ((cstat & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, c, flag); + + } while (--max_count); + + tty_flip_buffer_push(tty); +} + +/* + * fill tx fifo with chars to send, stop when fifo is about to be full + * or when all chars have been sent. + */ +static void bcm_uart_do_tx(struct uart_port *port) +{ + struct circ_buf *xmit; + unsigned int val, max_count; + + if (port->x_char) { + bcm_uart_writel(port, port->x_char, UART_FIFO_REG); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_tx_stopped(port)) { + bcm_uart_stop_tx(port); + return; + } + + xmit = &port->state->xmit; + if (uart_circ_empty(xmit)) + goto txq_empty; + + val = bcm_uart_readl(port, UART_MCTL_REG); + val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; + max_count = port->fifosize - val; + + while (max_count--) { + unsigned int c; + + c = xmit->buf[xmit->tail]; + bcm_uart_writel(port, c, UART_FIFO_REG); + 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); + + if (uart_circ_empty(xmit)) + goto txq_empty; + return; + +txq_empty: + /* nothing to send, disable transmit interrupt */ + val = bcm_uart_readl(port, UART_IR_REG); + val &= ~UART_TX_INT_MASK; + bcm_uart_writel(port, val, UART_IR_REG); + return; +} + +/* + * process uart interrupt + */ +static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id) +{ + struct uart_port *port; + unsigned int irqstat; + + port = dev_id; + spin_lock(&port->lock); + + irqstat = bcm_uart_readl(port, UART_IR_REG); + if (irqstat & UART_RX_INT_STAT) + bcm_uart_do_rx(port); + + if (irqstat & UART_TX_INT_STAT) + bcm_uart_do_tx(port); + + if (irqstat & UART_IR_MASK(UART_IR_EXTIP)) { + unsigned int estat; + + estat = bcm_uart_readl(port, UART_EXTINP_REG); + if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_CTS)) + uart_handle_cts_change(port, + estat & UART_EXTINP_CTS_MASK); + if (estat & UART_EXTINP_IRSTAT(UART_EXTINP_IR_DCD)) + uart_handle_dcd_change(port, + estat & UART_EXTINP_DCD_MASK); + } + + spin_unlock(&port->lock); + return IRQ_HANDLED; +} + +/* + * enable rx & tx operation on uart + */ +static void bcm_uart_enable(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_CTL_REG); + val |= (UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); + bcm_uart_writel(port, val, UART_CTL_REG); +} + +/* + * disable rx & tx operation on uart + */ +static void bcm_uart_disable(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_CTL_REG); + val &= ~(UART_CTL_BRGEN_MASK | UART_CTL_TXEN_MASK | + UART_CTL_RXEN_MASK); + bcm_uart_writel(port, val, UART_CTL_REG); +} + +/* + * clear all unread data in rx fifo and unsent data in tx fifo + */ +static void bcm_uart_flush(struct uart_port *port) +{ + unsigned int val; + + /* empty rx and tx fifo */ + val = bcm_uart_readl(port, UART_CTL_REG); + val |= UART_CTL_RSTRXFIFO_MASK | UART_CTL_RSTTXFIFO_MASK; + bcm_uart_writel(port, val, UART_CTL_REG); + + /* read any pending char to make sure all irq status are + * cleared */ + (void)bcm_uart_readl(port, UART_FIFO_REG); +} + +/* + * serial core request to initialize uart and start rx operation + */ +static int bcm_uart_startup(struct uart_port *port) +{ + unsigned int val; + int ret; + + /* mask all irq and flush port */ + bcm_uart_disable(port); + bcm_uart_writel(port, 0, UART_IR_REG); + bcm_uart_flush(port); + + /* clear any pending external input interrupt */ + (void)bcm_uart_readl(port, UART_EXTINP_REG); + + /* set rx/tx fifo thresh to fifo half size */ + val = bcm_uart_readl(port, UART_MCTL_REG); + val &= ~(UART_MCTL_RXFIFOTHRESH_MASK | UART_MCTL_TXFIFOTHRESH_MASK); + val |= (port->fifosize / 2) << UART_MCTL_RXFIFOTHRESH_SHIFT; + val |= (port->fifosize / 2) << UART_MCTL_TXFIFOTHRESH_SHIFT; + bcm_uart_writel(port, val, UART_MCTL_REG); + + /* set rx fifo timeout to 1 char time */ + val = bcm_uart_readl(port, UART_CTL_REG); + val &= ~UART_CTL_RXTMOUTCNT_MASK; + val |= 1 << UART_CTL_RXTMOUTCNT_SHIFT; + bcm_uart_writel(port, val, UART_CTL_REG); + + /* report any edge on dcd and cts */ + val = UART_EXTINP_INT_MASK; + val |= UART_EXTINP_DCD_NOSENSE_MASK; + val |= UART_EXTINP_CTS_NOSENSE_MASK; + bcm_uart_writel(port, val, UART_EXTINP_REG); + + /* register irq and enable rx interrupts */ + ret = request_irq(port->irq, bcm_uart_interrupt, 0, + bcm_uart_type(port), port); + if (ret) + return ret; + bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG); + bcm_uart_enable(port); + return 0; +} + +/* + * serial core request to flush & disable uart + */ +static void bcm_uart_shutdown(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + bcm_uart_writel(port, 0, UART_IR_REG); + spin_unlock_irqrestore(&port->lock, flags); + + bcm_uart_disable(port); + bcm_uart_flush(port); + free_irq(port->irq, port); +} + +/* + * serial core request to change current uart setting + */ +static void bcm_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + unsigned int ctl, baud, quot, ier; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* disable uart while changing speed */ + bcm_uart_disable(port); + bcm_uart_flush(port); + + /* update Control register */ + ctl = bcm_uart_readl(port, UART_CTL_REG); + ctl &= ~UART_CTL_BITSPERSYM_MASK; + + switch (new->c_cflag & CSIZE) { + case CS5: + ctl |= (0 << UART_CTL_BITSPERSYM_SHIFT); + break; + case CS6: + ctl |= (1 << UART_CTL_BITSPERSYM_SHIFT); + break; + case CS7: + ctl |= (2 << UART_CTL_BITSPERSYM_SHIFT); + break; + default: + ctl |= (3 << UART_CTL_BITSPERSYM_SHIFT); + break; + } + + ctl &= ~UART_CTL_STOPBITS_MASK; + if (new->c_cflag & CSTOPB) + ctl |= UART_CTL_STOPBITS_2; + else + ctl |= UART_CTL_STOPBITS_1; + + ctl &= ~(UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK); + if (new->c_cflag & PARENB) + ctl |= (UART_CTL_RXPAREN_MASK | UART_CTL_TXPAREN_MASK); + ctl &= ~(UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK); + if (new->c_cflag & PARODD) + ctl |= (UART_CTL_RXPAREVEN_MASK | UART_CTL_TXPAREVEN_MASK); + bcm_uart_writel(port, ctl, UART_CTL_REG); + + /* update Baudword register */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + quot = uart_get_divisor(port, baud) - 1; + bcm_uart_writel(port, quot, UART_BAUD_REG); + + /* update Interrupt register */ + ier = bcm_uart_readl(port, UART_IR_REG); + + ier &= ~UART_IR_MASK(UART_IR_EXTIP); + if (UART_ENABLE_MS(port, new->c_cflag)) + ier |= UART_IR_MASK(UART_IR_EXTIP); + + bcm_uart_writel(port, ier, UART_IR_REG); + + /* update read/ignore mask */ + port->read_status_mask = UART_FIFO_VALID_MASK; + if (new->c_iflag & INPCK) { + port->read_status_mask |= UART_FIFO_FRAMEERR_MASK; + port->read_status_mask |= UART_FIFO_PARERR_MASK; + } + if (new->c_iflag & (BRKINT)) + port->read_status_mask |= UART_FIFO_BRKDET_MASK; + + port->ignore_status_mask = 0; + if (new->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_FIFO_PARERR_MASK; + if (new->c_iflag & IGNBRK) + port->ignore_status_mask |= UART_FIFO_BRKDET_MASK; + if (!(new->c_cflag & CREAD)) + port->ignore_status_mask |= UART_FIFO_VALID_MASK; + + uart_update_timeout(port, new->c_cflag, baud); + bcm_uart_enable(port); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * serial core request to claim uart iomem + */ +static int bcm_uart_request_port(struct uart_port *port) +{ + unsigned int size; + + size = RSET_UART_SIZE; + if (!request_mem_region(port->mapbase, size, "bcm63xx")) { + dev_err(port->dev, "Memory region busy\n"); + return -EBUSY; + } + + port->membase = ioremap(port->mapbase, size); + if (!port->membase) { + dev_err(port->dev, "Unable to map registers\n"); + release_mem_region(port->mapbase, size); + return -EBUSY; + } + return 0; +} + +/* + * serial core request to release uart iomem + */ +static void bcm_uart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, RSET_UART_SIZE); + iounmap(port->membase); +} + +/* + * serial core request to do any port required autoconfiguration + */ +static void bcm_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + if (bcm_uart_request_port(port)) + return; + port->type = PORT_BCM63XX; + } +} + +/* + * serial core request to check that port information in serinfo are + * suitable + */ +static int bcm_uart_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + if (port->type != PORT_BCM63XX) + return -EINVAL; + if (port->irq != serinfo->irq) + return -EINVAL; + if (port->iotype != serinfo->io_type) + return -EINVAL; + if (port->mapbase != (unsigned long)serinfo->iomem_base) + return -EINVAL; + return 0; +} + +/* serial core callbacks */ +static struct uart_ops bcm_uart_ops = { + .tx_empty = bcm_uart_tx_empty, + .get_mctrl = bcm_uart_get_mctrl, + .set_mctrl = bcm_uart_set_mctrl, + .start_tx = bcm_uart_start_tx, + .stop_tx = bcm_uart_stop_tx, + .stop_rx = bcm_uart_stop_rx, + .enable_ms = bcm_uart_enable_ms, + .break_ctl = bcm_uart_break_ctl, + .startup = bcm_uart_startup, + .shutdown = bcm_uart_shutdown, + .set_termios = bcm_uart_set_termios, + .type = bcm_uart_type, + .release_port = bcm_uart_release_port, + .request_port = bcm_uart_request_port, + .config_port = bcm_uart_config_port, + .verify_port = bcm_uart_verify_port, +}; + + + +#ifdef CONFIG_SERIAL_BCM63XX_CONSOLE +static inline void wait_for_xmitr(struct uart_port *port) +{ + unsigned int tmout; + + /* Wait up to 10ms for the character(s) to be sent. */ + tmout = 10000; + while (--tmout) { + unsigned int val; + + val = bcm_uart_readl(port, UART_IR_REG); + if (val & UART_IR_STAT(UART_IR_TXEMPTY)) + break; + udelay(1); + } + + /* Wait up to 1s for flow control if necessary */ + if (port->flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout) { + unsigned int val; + + val = bcm_uart_readl(port, UART_EXTINP_REG); + if (val & UART_EXTINP_CTS_MASK) + break; + udelay(1); + } + } +} + +/* + * output given char + */ +static void bcm_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmitr(port); + bcm_uart_writel(port, ch, UART_FIFO_REG); +} + +/* + * console core request to output given string + */ +static void bcm_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port; + unsigned long flags; + int locked; + + port = &ports[co->index]; + + local_irq_save(flags); + if (port->sysrq) { + /* bcm_uart_interrupt() already took the lock */ + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else { + spin_lock(&port->lock); + locked = 1; + } + + /* call helper to deal with \r\n */ + uart_console_write(port, s, count, bcm_console_putchar); + + /* and wait for char to be transmitted */ + wait_for_xmitr(port); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +/* + * console core request to setup given console, find matching uart + * port and setup it. + */ +static int bcm_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= BCM63XX_NR_UARTS) + return -EINVAL; + port = &ports[co->index]; + 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 bcm_uart_driver; + +static struct console bcm63xx_console = { + .name = "ttyS", + .write = bcm_console_write, + .device = uart_console_device, + .setup = bcm_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &bcm_uart_driver, +}; + +static int __init bcm63xx_console_init(void) +{ + register_console(&bcm63xx_console); + return 0; +} + +console_initcall(bcm63xx_console_init); + +#define BCM63XX_CONSOLE (&bcm63xx_console) +#else +#define BCM63XX_CONSOLE NULL +#endif /* CONFIG_SERIAL_BCM63XX_CONSOLE */ + +static struct uart_driver bcm_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "bcm63xx_uart", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = BCM63XX_NR_UARTS, + .cons = BCM63XX_CONSOLE, +}; + +/* + * platform driver probe/remove callback + */ +static int __devinit bcm_uart_probe(struct platform_device *pdev) +{ + struct resource *res_mem, *res_irq; + struct uart_port *port; + struct clk *clk; + int ret; + + if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) + return -EINVAL; + + if (ports[pdev->id].membase) + return -EBUSY; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -ENODEV; + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) + return -ENODEV; + + clk = clk_get(&pdev->dev, "periph"); + if (IS_ERR(clk)) + return -ENODEV; + + port = &ports[pdev->id]; + memset(port, 0, sizeof(*port)); + port->iotype = UPIO_MEM; + port->mapbase = res_mem->start; + port->irq = res_irq->start; + port->ops = &bcm_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = &pdev->dev; + port->fifosize = 16; + port->uartclk = clk_get_rate(clk) / 2; + port->line = pdev->id; + clk_put(clk); + + ret = uart_add_one_port(&bcm_uart_driver, port); + if (ret) { + ports[pdev->id].membase = 0; + return ret; + } + platform_set_drvdata(pdev, port); + return 0; +} + +static int __devexit bcm_uart_remove(struct platform_device *pdev) +{ + struct uart_port *port; + + port = platform_get_drvdata(pdev); + uart_remove_one_port(&bcm_uart_driver, port); + platform_set_drvdata(pdev, NULL); + /* mark port as free */ + ports[pdev->id].membase = 0; + return 0; +} + +/* + * platform driver stuff + */ +static struct platform_driver bcm_uart_platform_driver = { + .probe = bcm_uart_probe, + .remove = __devexit_p(bcm_uart_remove), + .driver = { + .owner = THIS_MODULE, + .name = "bcm63xx_uart", + }, +}; + +static int __init bcm_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&bcm_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&bcm_uart_platform_driver); + if (ret) + uart_unregister_driver(&bcm_uart_driver); + + return ret; +} + +static void __exit bcm_uart_exit(void) +{ + platform_driver_unregister(&bcm_uart_platform_driver); + uart_unregister_driver(&bcm_uart_driver); +} + +module_init(bcm_uart_init); +module_exit(bcm_uart_exit); + +MODULE_AUTHOR("Maxime Bizon "); +MODULE_DESCRIPTION("Broadcom 63 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase) +#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr) +#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v)) +#include + +#ifdef CONFIG_SERIAL_BFIN_MODULE +# undef CONFIG_EARLY_PRINTK +#endif + +#ifdef CONFIG_SERIAL_BFIN_MODULE +# undef CONFIG_EARLY_PRINTK +#endif + +/* UART name and device definitions */ +#define BFIN_SERIAL_DEV_NAME "ttyBF" +#define BFIN_SERIAL_MAJOR 204 +#define BFIN_SERIAL_MINOR 64 + +static struct bfin_serial_port *bfin_serial_ports[BFIN_UART_NR_PORTS]; + +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + +# ifndef CONFIG_SERIAL_BFIN_PIO +# error KGDB only support UART in PIO mode. +# endif + +static int kgdboc_port_line; +static int kgdboc_break_enabled; +#endif +/* + * Setup for console. Argument comes from the menuconfig + */ +#define DMA_RX_XCOUNT 512 +#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT) + +#define DMA_RX_FLUSH_JIFFIES (HZ / 50) + +#ifdef CONFIG_SERIAL_BFIN_DMA +static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart); +#else +static void bfin_serial_tx_chars(struct bfin_serial_port *uart); +#endif + +static void bfin_serial_reset_irda(struct uart_port *port); + +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->cts_pin < 0) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + /* CTS PIN is negative assertive. */ + if (UART_GET_CTS(uart)) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + if (uart->rts_pin < 0) + return; + + /* RTS PIN is negative assertive. */ + if (mctrl & TIOCM_RTS) + UART_ENABLE_RTS(uart); + else + UART_DISABLE_RTS(uart); +} + +/* + * Handle any change of modem status signal. + */ +static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + unsigned int status; + + status = bfin_serial_get_mctrl(&uart->port); + uart_handle_cts_change(&uart->port, status & TIOCM_CTS); +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + uart->scts = 1; + UART_CLEAR_SCTS(uart); + UART_CLEAR_IER(uart, EDSSI); +#endif + + return IRQ_HANDLED; +} +#else +static unsigned int bfin_serial_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} +#endif + +/* + * interrupts are disabled on entry + */ +static void bfin_serial_stop_tx(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; +#ifdef CONFIG_SERIAL_BFIN_DMA + struct circ_buf *xmit = &uart->port.state->xmit; +#endif + + while (!(UART_GET_LSR(uart) & TEMT)) + cpu_relax(); + +#ifdef CONFIG_SERIAL_BFIN_DMA + disable_dma(uart->tx_dma_channel); + xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx += uart->tx_count; + uart->tx_count = 0; + uart->tx_done = 1; +#else +#ifdef CONFIG_BF54x + /* Clear TFI bit */ + UART_PUT_LSR(uart, TFI); +#endif + UART_CLEAR_IER(uart, ETBEI); +#endif +} + +/* + * port is locked and interrupts are disabled + */ +static void bfin_serial_start_tx(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + struct tty_struct *tty = uart->port.state->port.tty; + +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif + + /* + * To avoid losting RX interrupt, we reset IR function + * before sending data. + */ + if (tty->termios->c_line == N_IRDA) + bfin_serial_reset_irda(port); + +#ifdef CONFIG_SERIAL_BFIN_DMA + if (uart->tx_done) + bfin_serial_dma_tx_chars(uart); +#else + UART_SET_IER(uart, ETBEI); + bfin_serial_tx_chars(uart); +#endif +} + +/* + * Interrupts are enabled + */ +static void bfin_serial_stop_rx(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + UART_CLEAR_IER(uart, ERBFI); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void bfin_serial_enable_ms(struct uart_port *port) +{ +} + + +#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO) +# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold) +# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v)) +#else +# define UART_GET_ANOMALY_THRESHOLD(uart) 0 +# define UART_SET_ANOMALY_THRESHOLD(uart, v) +#endif + +#ifdef CONFIG_SERIAL_BFIN_PIO +static void bfin_serial_rx_chars(struct bfin_serial_port *uart) +{ + struct tty_struct *tty = NULL; + unsigned int status, ch, flg; + static struct timeval anomaly_start = { .tv_sec = 0 }; + + status = UART_GET_LSR(uart); + UART_CLEAR_LSR(uart); + + ch = UART_GET_CHAR(uart); + uart->port.icount.rx++; + +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + if (kgdb_connected && kgdboc_port_line == uart->port.line + && kgdboc_break_enabled) + if (ch == 0x3) {/* Ctrl + C */ + kgdb_breakpoint(); + return; + } + + if (!uart->port.state || !uart->port.state->port.tty) + return; +#endif + tty = uart->port.state->port.tty; + + if (ANOMALY_05000363) { + /* The BF533 (and BF561) family of processors have a nice anomaly + * where they continuously generate characters for a "single" break. + * We have to basically ignore this flood until the "next" valid + * character comes across. Due to the nature of the flood, it is + * not possible to reliably catch bytes that are sent too quickly + * after this break. So application code talking to the Blackfin + * which sends a break signal must allow at least 1.5 character + * times after the end of the break for things to stabilize. This + * timeout was picked as it must absolutely be larger than 1 + * character time +/- some percent. So 1.5 sounds good. All other + * Blackfin families operate properly. Woo. + */ + if (anomaly_start.tv_sec) { + struct timeval curr; + suseconds_t usecs; + + if ((~ch & (~ch + 1)) & 0xff) + goto known_good_char; + + do_gettimeofday(&curr); + if (curr.tv_sec - anomaly_start.tv_sec > 1) + goto known_good_char; + + usecs = 0; + if (curr.tv_sec != anomaly_start.tv_sec) + usecs += USEC_PER_SEC; + usecs += curr.tv_usec - anomaly_start.tv_usec; + + if (usecs > UART_GET_ANOMALY_THRESHOLD(uart)) + goto known_good_char; + + if (ch) + anomaly_start.tv_sec = 0; + else + anomaly_start = curr; + + return; + + known_good_char: + status &= ~BI; + anomaly_start.tv_sec = 0; + } + } + + if (status & BI) { + if (ANOMALY_05000363) + if (bfin_revid() < 5) + do_gettimeofday(&anomaly_start); + uart->port.icount.brk++; + if (uart_handle_break(&uart->port)) + goto ignore_char; + status &= ~(PE | FE); + } + if (status & PE) + uart->port.icount.parity++; + if (status & OE) + uart->port.icount.overrun++; + if (status & FE) + uart->port.icount.frame++; + + status &= uart->port.read_status_mask; + + if (status & BI) + flg = TTY_BREAK; + else if (status & PE) + flg = TTY_PARITY; + else if (status & FE) + flg = TTY_FRAME; + else + flg = TTY_NORMAL; + + if (uart_handle_sysrq_char(&uart->port, ch)) + goto ignore_char; + + uart_insert_char(&uart->port, status, OE, ch, flg); + + ignore_char: + tty_flip_buffer_push(tty); +} + +static void bfin_serial_tx_chars(struct bfin_serial_port *uart) +{ + struct circ_buf *xmit = &uart->port.state->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { +#ifdef CONFIG_BF54x + /* Clear TFI bit */ + UART_PUT_LSR(uart, TFI); +#endif + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ + UART_CLEAR_IER(uart, ETBEI); + return; + } + + if (uart->port.x_char) { + UART_PUT_CHAR(uart, uart->port.x_char); + uart->port.icount.tx++; + uart->port.x_char = 0; + } + + while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) { + UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); +} + +static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + + spin_lock(&uart->port.lock); + while (UART_GET_LSR(uart) & DR) + bfin_serial_rx_chars(uart); + spin_unlock(&uart->port.lock); + + return IRQ_HANDLED; +} + +static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif + spin_lock(&uart->port.lock); + if (UART_GET_LSR(uart) & THRE) + bfin_serial_tx_chars(uart); + spin_unlock(&uart->port.lock); + + return IRQ_HANDLED; +} +#endif + +#ifdef CONFIG_SERIAL_BFIN_DMA +static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) +{ + struct circ_buf *xmit = &uart->port.state->xmit; + + uart->tx_done = 0; + + if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { + uart->tx_count = 0; + uart->tx_done = 1; + return; + } + + if (uart->port.x_char) { + UART_PUT_CHAR(uart, uart->port.x_char); + uart->port.icount.tx++; + uart->port.x_char = 0; + } + + uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail)) + uart->tx_count = UART_XMIT_SIZE - xmit->tail; + blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail), + (unsigned long)(xmit->buf+xmit->tail+uart->tx_count)); + set_dma_config(uart->tx_dma_channel, + set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, + INTR_ON_BUF, + DIMENSION_LINEAR, + DATA_SIZE_8, + DMA_SYNC_RESTART)); + set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); + set_dma_x_count(uart->tx_dma_channel, uart->tx_count); + set_dma_x_modify(uart->tx_dma_channel, 1); + SSYNC(); + enable_dma(uart->tx_dma_channel); + + UART_SET_IER(uart, ETBEI); +} + +static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) +{ + struct tty_struct *tty = uart->port.state->port.tty; + int i, flg, status; + + status = UART_GET_LSR(uart); + UART_CLEAR_LSR(uart); + + uart->port.icount.rx += + CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, + UART_XMIT_SIZE); + + if (status & BI) { + uart->port.icount.brk++; + if (uart_handle_break(&uart->port)) + goto dma_ignore_char; + status &= ~(PE | FE); + } + if (status & PE) + uart->port.icount.parity++; + if (status & OE) + uart->port.icount.overrun++; + if (status & FE) + uart->port.icount.frame++; + + status &= uart->port.read_status_mask; + + if (status & BI) + flg = TTY_BREAK; + else if (status & PE) + flg = TTY_PARITY; + else if (status & FE) + flg = TTY_FRAME; + else + flg = TTY_NORMAL; + + for (i = uart->rx_dma_buf.tail; ; i++) { + if (i >= UART_XMIT_SIZE) + i = 0; + if (i == uart->rx_dma_buf.head) + break; + if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) + uart_insert_char(&uart->port, status, OE, + uart->rx_dma_buf.buf[i], flg); + } + + dma_ignore_char: + tty_flip_buffer_push(tty); +} + +void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) +{ + int x_pos, pos; + + dma_disable_irq(uart->tx_dma_channel); + dma_disable_irq(uart->rx_dma_channel); + spin_lock_bh(&uart->port.lock); + + /* 2D DMA RX buffer ring is used. Because curr_y_count and + * curr_x_count can't be read as an atomic operation, + * curr_y_count should be read before curr_x_count. When + * curr_x_count is read, curr_y_count may already indicate + * next buffer line. But, the position calculated here is + * still indicate the old line. The wrong position data may + * be smaller than current buffer tail, which cause garbages + * are received if it is not prohibit. + */ + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + x_pos = get_dma_curr_xcount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) + uart->rx_dma_nrows = 0; + x_pos = DMA_RX_XCOUNT - x_pos; + if (x_pos == DMA_RX_XCOUNT) + x_pos = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; + /* Ignore receiving data if new position is in the same line of + * current buffer tail and small. + */ + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; + } + + spin_unlock_bh(&uart->port.lock); + dma_enable_irq(uart->tx_dma_channel); + dma_enable_irq(uart->rx_dma_channel); + + mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); +} + +static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + struct circ_buf *xmit = &uart->port.state->xmit; + +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) { + uart->scts = 0; + uart_handle_cts_change(&uart->port, uart->scts); + } +#endif + + spin_lock(&uart->port.lock); + if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { + disable_dma(uart->tx_dma_channel); + clear_dma_irqstat(uart->tx_dma_channel); + /* Anomaly notes: + * 05000215 - we always clear ETBEI within last UART TX + * interrupt to end a string. It is always set + * when start a new tx. + */ + UART_CLEAR_IER(uart, ETBEI); + xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); + uart->port.icount.tx += uart->tx_count; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uart->port); + + bfin_serial_dma_tx_chars(uart); + } + + spin_unlock(&uart->port.lock); + return IRQ_HANDLED; +} + +static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) +{ + struct bfin_serial_port *uart = dev_id; + unsigned short irqstat; + int x_pos, pos; + + spin_lock(&uart->port.lock); + irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); + clear_dma_irqstat(uart->rx_dma_channel); + + uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); + x_pos = get_dma_curr_xcount(uart->rx_dma_channel); + uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; + if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) + uart->rx_dma_nrows = 0; + + pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; + if (pos > uart->rx_dma_buf.tail || + uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { + uart->rx_dma_buf.head = pos; + bfin_serial_dma_rx_chars(uart); + uart->rx_dma_buf.tail = uart->rx_dma_buf.head; + } + + spin_unlock(&uart->port.lock); + + return IRQ_HANDLED; +} +#endif + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int bfin_serial_tx_empty(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned short lsr; + + lsr = UART_GET_LSR(uart); + if (lsr & TEMT) + return TIOCSER_TEMT; + else + return 0; +} + +static void bfin_serial_break_ctl(struct uart_port *port, int break_state) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + u16 lcr = UART_GET_LCR(uart); + if (break_state) + lcr |= SB; + else + lcr &= ~SB; + UART_PUT_LCR(uart, lcr); + SSYNC(); +} + +static int bfin_serial_startup(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + +#ifdef CONFIG_SERIAL_BFIN_DMA + dma_addr_t dma_handle; + + if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) { + printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n"); + return -EBUSY; + } + + if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) { + printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n"); + free_dma(uart->rx_dma_channel); + return -EBUSY; + } + + set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart); + set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart); + + uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); + uart->rx_dma_buf.head = 0; + uart->rx_dma_buf.tail = 0; + uart->rx_dma_nrows = 0; + + set_dma_config(uart->rx_dma_channel, + set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, + INTR_ON_ROW, DIMENSION_2D, + DATA_SIZE_8, + DMA_SYNC_RESTART)); + set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT); + set_dma_x_modify(uart->rx_dma_channel, 1); + set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT); + set_dma_y_modify(uart->rx_dma_channel, 1); + set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf); + enable_dma(uart->rx_dma_channel); + + uart->rx_dma_timer.data = (unsigned long)(uart); + uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout; + uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; + add_timer(&(uart->rx_dma_timer)); +#else +# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled) + kgdboc_break_enabled = 0; + else { +# endif + if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, + "BFIN_UART_RX", uart)) { + printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); + return -EBUSY; + } + + if (request_irq + (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, + "BFIN_UART_TX", uart)) { + printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); + free_irq(uart->port.irq, uart); + return -EBUSY; + } + +# ifdef CONFIG_BF54x + { + /* + * UART2 and UART3 on BF548 share interrupt PINs and DMA + * controllers with SPORT2 and SPORT3. UART rx and tx + * interrupts are generated in PIO mode only when configure + * their peripheral mapping registers properly, which means + * request corresponding DMA channels in PIO mode as well. + */ + unsigned uart_dma_ch_rx, uart_dma_ch_tx; + + switch (uart->port.irq) { + case IRQ_UART3_RX: + uart_dma_ch_rx = CH_UART3_RX; + uart_dma_ch_tx = CH_UART3_TX; + break; + case IRQ_UART2_RX: + uart_dma_ch_rx = CH_UART2_RX; + uart_dma_ch_tx = CH_UART2_TX; + break; + default: + uart_dma_ch_rx = uart_dma_ch_tx = 0; + break; + }; + + if (uart_dma_ch_rx && + request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { + printk(KERN_NOTICE"Fail to attach UART interrupt\n"); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + if (uart_dma_ch_tx && + request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { + printk(KERN_NOTICE "Fail to attach UART interrupt\n"); + free_dma(uart_dma_ch_rx); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + } +# endif +# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + } +# endif +#endif + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->cts_pin >= 0) { + if (request_irq(gpio_to_irq(uart->cts_pin), + bfin_serial_mctrl_cts_int, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_DISABLED, "BFIN_UART_CTS", uart)) { + uart->cts_pin = -1; + pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n"); + } + } + if (uart->rts_pin >= 0) { + gpio_direction_output(uart->rts_pin, 0); + } +#endif +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->cts_pin >= 0 && request_irq(uart->status_irq, + bfin_serial_mctrl_cts_int, + IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + uart->cts_pin = -1; + pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n"); + } + + /* CTS RTS PINs are negative assertive. */ + UART_PUT_MCR(uart, ACTS); + UART_SET_IER(uart, EDSSI); +#endif + + UART_SET_IER(uart, ERBFI); + return 0; +} + +static void bfin_serial_shutdown(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + +#ifdef CONFIG_SERIAL_BFIN_DMA + disable_dma(uart->tx_dma_channel); + free_dma(uart->tx_dma_channel); + disable_dma(uart->rx_dma_channel); + free_dma(uart->rx_dma_channel); + del_timer(&(uart->rx_dma_timer)); + dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); +#else +#ifdef CONFIG_BF54x + switch (uart->port.irq) { + case IRQ_UART3_RX: + free_dma(CH_UART3_RX); + free_dma(CH_UART3_TX); + break; + case IRQ_UART2_RX: + free_dma(CH_UART2_RX); + free_dma(CH_UART2_TX); + break; + default: + break; + }; +#endif + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq+1, uart); +#endif + +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->cts_pin >= 0) + free_irq(gpio_to_irq(uart->cts_pin), uart); +#endif +#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS + if (uart->cts_pin >= 0) + free_irq(uart->status_irq, uart); +#endif +} + +static void +bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned long flags; + unsigned int baud, quot; + unsigned short val, ier, lcr = 0; + + switch (termios->c_cflag & CSIZE) { + case CS8: + lcr = WLS(8); + break; + case CS7: + lcr = WLS(7); + break; + case CS6: + lcr = WLS(6); + break; + case CS5: + lcr = WLS(5); + break; + default: + printk(KERN_ERR "%s: word lengh not supported\n", + __func__); + } + + /* Anomaly notes: + * 05000231 - STOP bit is always set to 1 whatever the user is set. + */ + if (termios->c_cflag & CSTOPB) { + if (ANOMALY_05000231) + printk(KERN_WARNING "STOP bits other than 1 is not " + "supported in case of anomaly 05000231.\n"); + else + lcr |= STB; + } + if (termios->c_cflag & PARENB) + lcr |= PEN; + if (!(termios->c_cflag & PARODD)) + lcr |= EPS; + if (termios->c_cflag & CMSPAR) + lcr |= STP; + + spin_lock_irqsave(&uart->port.lock, flags); + + port->read_status_mask = OE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= (FE | PE); + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= BI; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= FE | PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= OE; + } + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + /* If discipline is not IRDA, apply ANOMALY_05000230 */ + if (termios->c_line != N_IRDA) + quot -= ANOMALY_05000230; + + UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); + + /* Disable UART */ + ier = UART_GET_IER(uart); + UART_DISABLE_INTS(uart); + + /* Set DLAB in LCR to Access DLL and DLH */ + UART_SET_DLAB(uart); + + UART_PUT_DLL(uart, quot & 0xFF); + UART_PUT_DLH(uart, (quot >> 8) & 0xFF); + SSYNC(); + + /* Clear DLAB in LCR to Access THR RBR IER */ + UART_CLEAR_DLAB(uart); + + UART_PUT_LCR(uart, lcr); + + /* Enable UART */ + UART_ENABLE_INTS(uart, ier); + + val = UART_GET_GCTL(uart); + val |= UCEN; + UART_PUT_GCTL(uart, val); + + /* Port speed changed, update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&uart->port.lock, flags); +} + +static const char *bfin_serial_type(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void bfin_serial_release_port(struct uart_port *port) +{ +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int bfin_serial_request_port(struct uart_port *port) +{ + return 0; +} + +/* + * Configure/autoconfigure the port. + */ +static void bfin_serial_config_port(struct uart_port *port, int flags) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + if (flags & UART_CONFIG_TYPE && + bfin_serial_request_port(&uart->port) == 0) + uart->port.type = PORT_BFIN; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_BFIN and PORT_UNKNOWN + */ +static int +bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return 0; +} + +/* + * Enable the IrDA function if tty->ldisc.num is N_IRDA. + * In other cases, disable IrDA function. + */ +static void bfin_serial_set_ldisc(struct uart_port *port, int ld) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned short val; + + switch (ld) { + case N_IRDA: + val = UART_GET_GCTL(uart); + val |= (IREN | RPOLC); + UART_PUT_GCTL(uart, val); + break; + default: + val = UART_GET_GCTL(uart); + val &= ~(IREN | RPOLC); + UART_PUT_GCTL(uart, val); + } +} + +static void bfin_serial_reset_irda(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned short val; + + val = UART_GET_GCTL(uart); + val &= ~(IREN | RPOLC); + UART_PUT_GCTL(uart, val); + SSYNC(); + val |= (IREN | RPOLC); + UART_PUT_GCTL(uart, val); + SSYNC(); +} + +#ifdef CONFIG_CONSOLE_POLL +/* Anomaly notes: + * 05000099 - Because we only use THRE in poll_put and DR in poll_get, + * losing other bits of UART_LSR is not a problem here. + */ +static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + while (!(UART_GET_LSR(uart) & THRE)) + cpu_relax(); + + UART_CLEAR_DLAB(uart); + UART_PUT_CHAR(uart, (unsigned char)chr); +} + +static int bfin_serial_poll_get_char(struct uart_port *port) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + unsigned char chr; + + while (!(UART_GET_LSR(uart) & DR)) + cpu_relax(); + + UART_CLEAR_DLAB(uart); + chr = UART_GET_CHAR(uart); + + return chr; +} +#endif + +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) +static void bfin_kgdboc_port_shutdown(struct uart_port *port) +{ + if (kgdboc_break_enabled) { + kgdboc_break_enabled = 0; + bfin_serial_shutdown(port); + } +} + +static int bfin_kgdboc_port_startup(struct uart_port *port) +{ + kgdboc_port_line = port->line; + kgdboc_break_enabled = !bfin_serial_startup(port); + return 0; +} +#endif + +static struct uart_ops bfin_serial_pops = { + .tx_empty = bfin_serial_tx_empty, + .set_mctrl = bfin_serial_set_mctrl, + .get_mctrl = bfin_serial_get_mctrl, + .stop_tx = bfin_serial_stop_tx, + .start_tx = bfin_serial_start_tx, + .stop_rx = bfin_serial_stop_rx, + .enable_ms = bfin_serial_enable_ms, + .break_ctl = bfin_serial_break_ctl, + .startup = bfin_serial_startup, + .shutdown = bfin_serial_shutdown, + .set_termios = bfin_serial_set_termios, + .set_ldisc = bfin_serial_set_ldisc, + .type = bfin_serial_type, + .release_port = bfin_serial_release_port, + .request_port = bfin_serial_request_port, + .config_port = bfin_serial_config_port, + .verify_port = bfin_serial_verify_port, +#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ + defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) + .kgdboc_port_startup = bfin_kgdboc_port_startup, + .kgdboc_port_shutdown = bfin_kgdboc_port_shutdown, +#endif +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = bfin_serial_poll_put_char, + .poll_get_char = bfin_serial_poll_get_char, +#endif +}; + +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, + int *parity, int *bits) +{ + unsigned short status; + + status = UART_GET_IER(uart) & (ERBFI | ETBEI); + if (status == (ERBFI | ETBEI)) { + /* ok, the port was enabled */ + u16 lcr, dlh, dll; + + lcr = UART_GET_LCR(uart); + + *parity = 'n'; + if (lcr & PEN) { + if (lcr & EPS) + *parity = 'e'; + else + *parity = 'o'; + } + switch (lcr & 0x03) { + case 0: *bits = 5; break; + case 1: *bits = 6; break; + case 2: *bits = 7; break; + case 3: *bits = 8; break; + } + /* Set DLAB in LCR to Access DLL and DLH */ + UART_SET_DLAB(uart); + + dll = UART_GET_DLL(uart); + dlh = UART_GET_DLH(uart); + + /* Clear DLAB in LCR to Access THR RBR IER */ + UART_CLEAR_DLAB(uart); + + *baud = get_sclk() / (16*(dll | dlh << 8)); + } + pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); +} + +static struct uart_driver bfin_serial_reg; + +static void bfin_serial_console_putchar(struct uart_port *port, int ch) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + while (!(UART_GET_LSR(uart) & THRE)) + barrier(); + UART_PUT_CHAR(uart, ch); +} + +#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || + defined (CONFIG_EARLY_PRINTK) */ + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE +#define CLASS_BFIN_CONSOLE "bfin-console" +/* + * Interrupts are disabled on entering + */ +static void +bfin_serial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct bfin_serial_port *uart = bfin_serial_ports[co->index]; + unsigned long flags; + + spin_lock_irqsave(&uart->port.lock, flags); + uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); + spin_unlock_irqrestore(&uart->port.lock, flags); + +} + +static int __init +bfin_serial_console_setup(struct console *co, char *options) +{ + struct bfin_serial_port *uart; + int baud = 57600; + int bits = 8; + int parity = 'n'; +# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) + int flow = 'r'; +# else + int flow = 'n'; +# endif + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index < 0 || co->index >= BFIN_UART_NR_PORTS) + return -ENODEV; + + uart = bfin_serial_ports[co->index]; + if (!uart) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + bfin_serial_console_get_options(uart, &baud, &parity, &bits); + + return uart_set_options(&uart->port, co, baud, parity, bits, flow); +} + +static struct console bfin_serial_console = { + .name = BFIN_SERIAL_DEV_NAME, + .write = bfin_serial_console_write, + .device = uart_console_device, + .setup = bfin_serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &bfin_serial_reg, +}; +#define BFIN_SERIAL_CONSOLE &bfin_serial_console +#else +#define BFIN_SERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ + +#ifdef CONFIG_EARLY_PRINTK +static struct bfin_serial_port bfin_earlyprintk_port; +#define CLASS_BFIN_EARLYPRINTK "bfin-earlyprintk" + +/* + * Interrupts are disabled on entering + */ +static void +bfin_earlyprintk_console_write(struct console *co, const char *s, unsigned int count) +{ + unsigned long flags; + + if (bfin_earlyprintk_port.port.line != co->index) + return; + + spin_lock_irqsave(&bfin_earlyprintk_port.port.lock, flags); + uart_console_write(&bfin_earlyprintk_port.port, s, count, + bfin_serial_console_putchar); + spin_unlock_irqrestore(&bfin_earlyprintk_port.port.lock, flags); +} + +/* + * This should have a .setup or .early_setup in it, but then things get called + * without the command line options, and the baud rate gets messed up - so + * don't let the common infrastructure play with things. (see calls to setup + * & earlysetup in ./kernel/printk.c:register_console() + */ +static struct __initdata console bfin_early_serial_console = { + .name = "early_BFuart", + .write = bfin_earlyprintk_console_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &bfin_serial_reg, +}; +#endif + +static struct uart_driver bfin_serial_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = BFIN_SERIAL_DEV_NAME, + .major = BFIN_SERIAL_MAJOR, + .minor = BFIN_SERIAL_MINOR, + .nr = BFIN_UART_NR_PORTS, + .cons = BFIN_SERIAL_CONSOLE, +}; + +static int bfin_serial_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + + return uart_suspend_port(&bfin_serial_reg, &uart->port); +} + +static int bfin_serial_resume(struct platform_device *pdev) +{ + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + + return uart_resume_port(&bfin_serial_reg, &uart->port); +} + +static int bfin_serial_probe(struct platform_device *pdev) +{ + struct resource *res; + struct bfin_serial_port *uart = NULL; + int ret = 0; + + if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) { + dev_err(&pdev->dev, "Wrong bfin uart platform device id.\n"); + return -ENOENT; + } + + if (bfin_serial_ports[pdev->id] == NULL) { + + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) { + dev_err(&pdev->dev, + "fail to malloc bfin_serial_port\n"); + return -ENOMEM; + } + bfin_serial_ports[pdev->id] = uart; + +#ifdef CONFIG_EARLY_PRINTK + if (!(bfin_earlyprintk_port.port.membase + && bfin_earlyprintk_port.port.line == pdev->id)) { + /* + * If the peripheral PINs of current port is allocated + * in earlyprintk probe stage, don't do it again. + */ +#endif + ret = peripheral_request_list( + (unsigned short *)pdev->dev.platform_data, DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, + "fail to request bfin serial peripherals\n"); + goto out_error_free_mem; + } +#ifdef CONFIG_EARLY_PRINTK + } +#endif + + spin_lock_init(&uart->port.lock); + uart->port.uartclk = get_sclk(); + uart->port.fifosize = BFIN_UART_TX_FIFO_SIZE; + uart->port.ops = &bfin_serial_pops; + uart->port.line = pdev->id; + uart->port.iotype = UPIO_MEM; + uart->port.flags = UPF_BOOT_AUTOCONF; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + ret = -ENOENT; + goto out_error_free_peripherals; + } + + uart->port.membase = ioremap(res->start, + res->end - res->start); + if (!uart->port.membase) { + dev_err(&pdev->dev, "Cannot map uart IO\n"); + ret = -ENXIO; + goto out_error_free_peripherals; + } + uart->port.mapbase = res->start; + + uart->port.irq = platform_get_irq(pdev, 0); + if (uart->port.irq < 0) { + dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + + uart->status_irq = platform_get_irq(pdev, 1); + if (uart->status_irq < 0) { + dev_err(&pdev->dev, "No uart status IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + +#ifdef CONFIG_SERIAL_BFIN_DMA + uart->tx_done = 1; + uart->tx_count = 0; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (res == NULL) { + dev_err(&pdev->dev, "No uart TX DMA channel specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + uart->tx_dma_channel = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (res == NULL) { + dev_err(&pdev->dev, "No uart RX DMA channel specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + uart->rx_dma_channel = res->start; + + init_timer(&(uart->rx_dma_timer)); +#endif + +#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ + defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) + uart->cts_pin = -1; + else + uart->cts_pin = res->start; + + res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (res == NULL) + uart->rts_pin = -1; + else + uart->rts_pin = res->start; +# if defined(CONFIG_SERIAL_BFIN_CTSRTS) + if (uart->rts_pin >= 0) + gpio_request(uart->rts_pin, DRIVER_NAME); +# endif +#endif + } + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE + if (!is_early_platform_device(pdev)) { +#endif + uart = bfin_serial_ports[pdev->id]; + uart->port.dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, uart); + ret = uart_add_one_port(&bfin_serial_reg, &uart->port); +#ifdef CONFIG_SERIAL_BFIN_CONSOLE + } +#endif + + if (!ret) + return 0; + + if (uart) { +out_error_unmap: + iounmap(uart->port.membase); +out_error_free_peripherals: + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); +out_error_free_mem: + kfree(uart); + bfin_serial_ports[pdev->id] = NULL; + } + + return ret; +} + +static int __devexit bfin_serial_remove(struct platform_device *pdev) +{ + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + + dev_set_drvdata(&pdev->dev, NULL); + + if (uart) { + uart_remove_one_port(&bfin_serial_reg, &uart->port); +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (uart->rts_pin >= 0) + gpio_free(uart->rts_pin); +#endif + iounmap(uart->port.membase); + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); + kfree(uart); + bfin_serial_ports[pdev->id] = NULL; + } + + return 0; +} + +static struct platform_driver bfin_serial_driver = { + .probe = bfin_serial_probe, + .remove = __devexit_p(bfin_serial_remove), + .suspend = bfin_serial_suspend, + .resume = bfin_serial_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) +static __initdata struct early_platform_driver early_bfin_serial_driver = { + .class_str = CLASS_BFIN_CONSOLE, + .pdrv = &bfin_serial_driver, + .requested_id = EARLY_PLATFORM_ID_UNSET, +}; + +static int __init bfin_serial_rs_console_init(void) +{ + early_platform_driver_register(&early_bfin_serial_driver, DRIVER_NAME); + + early_platform_driver_probe(CLASS_BFIN_CONSOLE, BFIN_UART_NR_PORTS, 0); + + register_console(&bfin_serial_console); + + return 0; +} +console_initcall(bfin_serial_rs_console_init); +#endif + +#ifdef CONFIG_EARLY_PRINTK +/* + * Memory can't be allocated dynamically during earlyprink init stage. + * So, do individual probe for earlyprink with a static uart port variable. + */ +static int bfin_earlyprintk_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + + if (pdev->id < 0 || pdev->id >= BFIN_UART_NR_PORTS) { + dev_err(&pdev->dev, "Wrong earlyprintk platform device id.\n"); + return -ENOENT; + } + + ret = peripheral_request_list( + (unsigned short *)pdev->dev.platform_data, DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, + "fail to request bfin serial peripherals\n"); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + ret = -ENOENT; + goto out_error_free_peripherals; + } + + bfin_earlyprintk_port.port.membase = ioremap(res->start, + res->end - res->start); + if (!bfin_earlyprintk_port.port.membase) { + dev_err(&pdev->dev, "Cannot map uart IO\n"); + ret = -ENXIO; + goto out_error_free_peripherals; + } + bfin_earlyprintk_port.port.mapbase = res->start; + bfin_earlyprintk_port.port.line = pdev->id; + bfin_earlyprintk_port.port.uartclk = get_sclk(); + bfin_earlyprintk_port.port.fifosize = BFIN_UART_TX_FIFO_SIZE; + spin_lock_init(&bfin_earlyprintk_port.port.lock); + + return 0; + +out_error_free_peripherals: + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); + + return ret; +} + +static struct platform_driver bfin_earlyprintk_driver = { + .probe = bfin_earlyprintk_probe, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = { + .class_str = CLASS_BFIN_EARLYPRINTK, + .pdrv = &bfin_earlyprintk_driver, + .requested_id = EARLY_PLATFORM_ID_UNSET, +}; + +struct console __init *bfin_earlyserial_init(unsigned int port, + unsigned int cflag) +{ + struct ktermios t; + char port_name[20]; + + if (port < 0 || port >= BFIN_UART_NR_PORTS) + return NULL; + + /* + * Only probe resource of the given port in earlyprintk boot arg. + * The expected port id should be indicated in port name string. + */ + snprintf(port_name, 20, DRIVER_NAME ".%d", port); + early_platform_driver_register(&early_bfin_earlyprintk_driver, + port_name); + early_platform_driver_probe(CLASS_BFIN_EARLYPRINTK, 1, 0); + + if (!bfin_earlyprintk_port.port.membase) + return NULL; + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE + /* + * If we are using early serial, don't let the normal console rewind + * log buffer, since that causes things to be printed multiple times + */ + bfin_serial_console.flags &= ~CON_PRINTBUFFER; +#endif + + bfin_early_serial_console.index = port; + t.c_cflag = cflag; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = port; + bfin_serial_set_termios(&bfin_earlyprintk_port.port, &t, &t); + + return &bfin_early_serial_console; +} +#endif /* CONFIG_EARLY_PRINTK */ + +static int __init bfin_serial_init(void) +{ + int ret; + + pr_info("Blackfin serial driver\n"); + + ret = uart_register_driver(&bfin_serial_reg); + if (ret) { + pr_err("failed to register %s:%d\n", + bfin_serial_reg.driver_name, ret); + } + + ret = platform_driver_register(&bfin_serial_driver); + if (ret) { + pr_err("fail to register bfin uart\n"); + uart_unregister_driver(&bfin_serial_reg); + } + + return ret; +} + +static void __exit bfin_serial_exit(void) +{ + platform_driver_unregister(&bfin_serial_driver); + uart_unregister_driver(&bfin_serial_reg); +} + + +module_init(bfin_serial_init); +module_exit(bfin_serial_exit); + +MODULE_AUTHOR("Sonic Zhang, Aubrey Li"); +MODULE_DESCRIPTION("Blackfin generic serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR); +MODULE_ALIAS("platform:bfin-uart"); diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c new file mode 100644 index 000000000000..e95c524d9d18 --- /dev/null +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -0,0 +1,935 @@ +/* + * Blackfin On-Chip Sport Emulated UART Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +/* + * This driver and the hardware supported are in term of EE-191 of ADI. + * http://www.analog.com/static/imported-files/application_notes/EE191.pdf + * This application note describe how to implement a UART on a Sharc DSP, + * but this driver is implemented on Blackfin Processor. + * Transmit Frame Sync is not used by this driver to transfer data out. + */ + +/* #define DEBUG */ + +#define DRV_NAME "bfin-sport-uart" +#define DEVICE_NAME "ttySS" +#define pr_fmt(fmt) DRV_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bfin_sport_uart.h" + +struct sport_uart_port { + struct uart_port port; + int err_irq; + unsigned short csize; + unsigned short rxmask; + unsigned short txmask1; + unsigned short txmask2; + unsigned char stopb; +/* unsigned char parib; */ +#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS + int cts_pin; + int rts_pin; +#endif +}; + +static int sport_uart_tx_chars(struct sport_uart_port *up); +static void sport_stop_tx(struct uart_port *port); + +static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) +{ + pr_debug("%s value:%x, mask1=0x%x, mask2=0x%x\n", __func__, value, + up->txmask1, up->txmask2); + + /* Place Start and Stop bits */ + __asm__ __volatile__ ( + "%[val] <<= 1;" + "%[val] = %[val] & %[mask1];" + "%[val] = %[val] | %[mask2];" + : [val]"+d"(value) + : [mask1]"d"(up->txmask1), [mask2]"d"(up->txmask2) + : "ASTAT" + ); + pr_debug("%s value:%x\n", __func__, value); + + SPORT_PUT_TX(up, value); +} + +static inline unsigned char rx_one_byte(struct sport_uart_port *up) +{ + unsigned int value; + unsigned char extract; + u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; + + if ((up->csize + up->stopb) > 7) + value = SPORT_GET_RX32(up); + else + value = SPORT_GET_RX(up); + + pr_debug("%s value:%x, cs=%d, mask=0x%x\n", __func__, value, + up->csize, up->rxmask); + + /* Extract data */ + __asm__ __volatile__ ( + "%[extr] = 0;" + "%[mask1] = %[rxmask];" + "%[mask2] = 0x0200(Z);" + "%[shift] = 0;" + "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" + ".Lloop_s:" + "%[tmp] = extract(%[val], %[mask1].L)(Z);" + "%[tmp] <<= %[shift];" + "%[extr] = %[extr] | %[tmp];" + "%[mask1] = %[mask1] - %[mask2];" + ".Lloop_e:" + "%[shift] += 1;" + : [extr]"=&d"(extract), [shift]"=&d"(tmp_shift), [tmp]"=&d"(tmp), + [mask1]"=&d"(tmp_mask1), [mask2]"=&d"(tmp_mask2) + : [val]"d"(value), [rxmask]"d"(up->rxmask), [lc]"a"(up->csize) + : "ASTAT", "LB0", "LC0", "LT0" + ); + + pr_debug(" extract:%x\n", extract); + return extract; +} + +static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate) +{ + int tclkdiv, rclkdiv; + unsigned int sclk = get_sclk(); + + /* Set TCR1 and TCR2, TFSR is not enabled for uart */ + SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); + SPORT_PUT_TCR2(up, size + 1); + pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); + + /* Set RCR1 and RCR2 */ + SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK)); + SPORT_PUT_RCR2(up, (size + 1) * 2 - 1); + pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); + + tclkdiv = sclk / (2 * baud_rate) - 1; + /* The actual uart baud rate of devices vary between +/-2%. The sport + * RX sample rate should be faster than the double of the worst case, + * otherwise, wrong data are received. So, set sport RX clock to be + * 3% faster. + */ + rclkdiv = sclk / (2 * baud_rate * 2 * 97 / 100) - 1; + SPORT_PUT_TCLKDIV(up, tclkdiv); + SPORT_PUT_RCLKDIV(up, rclkdiv); + SSYNC(); + pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, rclkdiv:%d\n", + __func__, sclk, baud_rate, tclkdiv, rclkdiv); + + return 0; +} + +static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) +{ + struct sport_uart_port *up = dev_id; + struct tty_struct *tty = up->port.state->port.tty; + unsigned int ch; + + spin_lock(&up->port.lock); + + while (SPORT_GET_STAT(up) & RXNE) { + ch = rx_one_byte(up); + up->port.icount.rx++; + + if (!uart_handle_sysrq_char(&up->port, ch)) + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } + tty_flip_buffer_push(tty); + + spin_unlock(&up->port.lock); + + return IRQ_HANDLED; +} + +static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) +{ + struct sport_uart_port *up = dev_id; + + spin_lock(&up->port.lock); + sport_uart_tx_chars(up); + spin_unlock(&up->port.lock); + + return IRQ_HANDLED; +} + +static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) +{ + struct sport_uart_port *up = dev_id; + struct tty_struct *tty = up->port.state->port.tty; + unsigned int stat = SPORT_GET_STAT(up); + + spin_lock(&up->port.lock); + + /* Overflow in RX FIFO */ + if (stat & ROVF) { + up->port.icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */ + } + /* These should not happen */ + if (stat & (TOVF | TUVF | RUVF)) { + pr_err("SPORT Error:%s %s %s\n", + (stat & TOVF) ? "TX overflow" : "", + (stat & TUVF) ? "TX underflow" : "", + (stat & RUVF) ? "RX underflow" : ""); + SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); + SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); + } + SSYNC(); + + spin_unlock(&up->port.lock); + return IRQ_HANDLED; +} + +#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS +static unsigned int sport_get_mctrl(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + if (up->cts_pin < 0) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + /* CTS PIN is negative assertive. */ + if (SPORT_UART_GET_CTS(up)) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + if (up->rts_pin < 0) + return; + + /* RTS PIN is negative assertive. */ + if (mctrl & TIOCM_RTS) + SPORT_UART_ENABLE_RTS(up); + else + SPORT_UART_DISABLE_RTS(up); +} + +/* + * Handle any change of modem status signal. + */ +static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id) +{ + struct sport_uart_port *up = (struct sport_uart_port *)dev_id; + unsigned int status; + + status = sport_get_mctrl(&up->port); + uart_handle_cts_change(&up->port, status & TIOCM_CTS); + + return IRQ_HANDLED; +} +#else +static unsigned int sport_get_mctrl(struct uart_port *port) +{ + pr_debug("%s enter\n", __func__); + return TIOCM_CTS | TIOCM_CD | TIOCM_DSR; +} + +static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + pr_debug("%s enter\n", __func__); +} +#endif + +/* Reqeust IRQ, Setup clock */ +static int sport_startup(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + int ret; + + pr_debug("%s enter\n", __func__); + ret = request_irq(up->port.irq, sport_uart_rx_irq, 0, + "SPORT_UART_RX", up); + if (ret) { + dev_err(port->dev, "unable to request SPORT RX interrupt\n"); + return ret; + } + + ret = request_irq(up->port.irq+1, sport_uart_tx_irq, 0, + "SPORT_UART_TX", up); + if (ret) { + dev_err(port->dev, "unable to request SPORT TX interrupt\n"); + goto fail1; + } + + ret = request_irq(up->err_irq, sport_uart_err_irq, 0, + "SPORT_UART_STATUS", up); + if (ret) { + dev_err(port->dev, "unable to request SPORT status interrupt\n"); + goto fail2; + } + +#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS + if (up->cts_pin >= 0) { + if (request_irq(gpio_to_irq(up->cts_pin), + sport_mctrl_cts_int, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) { + up->cts_pin = -1; + dev_info(port->dev, "Unable to attach BlackFin UART \ + over SPORT CTS interrupt. So, disable it.\n"); + } + } + if (up->rts_pin >= 0) + gpio_direction_output(up->rts_pin, 0); +#endif + + return 0; + fail2: + free_irq(up->port.irq+1, up); + fail1: + free_irq(up->port.irq, up); + + return ret; +} + +/* + * sport_uart_tx_chars + * + * ret 1 means need to enable sport. + * ret 0 means do nothing. + */ +static int sport_uart_tx_chars(struct sport_uart_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + + if (SPORT_GET_STAT(up) & TXF) + return 0; + + if (up->port.x_char) { + tx_one_byte(up, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + /* The waiting loop to stop SPORT TX from TX interrupt is + * too long. This may block SPORT RX interrupts and cause + * RX FIFO overflow. So, do stop sport TX only after the last + * char in TX FIFO is moved into the shift register. + */ + if (SPORT_GET_STAT(up) & TXHRE) + sport_stop_tx(&up->port); + return 0; + } + + while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) { + tx_one_byte(up, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); + up->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + return 1; +} + +static unsigned int sport_tx_empty(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + unsigned int stat; + + stat = SPORT_GET_STAT(up); + pr_debug("%s stat:%04x\n", __func__, stat); + if (stat & TXHRE) { + return TIOCSER_TEMT; + } else + return 0; +} + +static void sport_stop_tx(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __func__); + + if (!(SPORT_GET_TCR1(up) & TSPEN)) + return; + + /* Although the hold register is empty, last byte is still in shift + * register and not sent out yet. So, put a dummy data into TX FIFO. + * Then, sport tx stops when last byte is shift out and the dummy + * data is moved into the shift register. + */ + SPORT_PUT_TX(up, 0xffff); + while (!(SPORT_GET_STAT(up) & TXHRE)) + cpu_relax(); + + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); + SSYNC(); + + return; +} + +static void sport_start_tx(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __func__); + + /* Write data into SPORT FIFO before enable SPROT to transmit */ + if (sport_uart_tx_chars(up)) { + /* Enable transmit, then an interrupt will generated */ + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); + SSYNC(); + } + + pr_debug("%s exit\n", __func__); +} + +static void sport_stop_rx(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __func__); + /* Disable sport to stop rx */ + SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); + SSYNC(); +} + +static void sport_enable_ms(struct uart_port *port) +{ + pr_debug("%s enter\n", __func__); +} + +static void sport_break_ctl(struct uart_port *port, int break_state) +{ + pr_debug("%s enter\n", __func__); +} + +static void sport_shutdown(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + dev_dbg(port->dev, "%s enter\n", __func__); + + /* Disable sport */ + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); + SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); + SSYNC(); + + free_irq(up->port.irq, up); + free_irq(up->port.irq+1, up); + free_irq(up->err_irq, up); +#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS + if (up->cts_pin >= 0) + free_irq(gpio_to_irq(up->cts_pin), up); +#endif +} + +static const char *sport_type(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __func__); + return up->port.type == PORT_BFIN_SPORT ? "BFIN-SPORT-UART" : NULL; +} + +static void sport_release_port(struct uart_port *port) +{ + pr_debug("%s enter\n", __func__); +} + +static int sport_request_port(struct uart_port *port) +{ + pr_debug("%s enter\n", __func__); + return 0; +} + +static void sport_config_port(struct uart_port *port, int flags) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __func__); + up->port.type = PORT_BFIN_SPORT; +} + +static int sport_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + pr_debug("%s enter\n", __func__); + return 0; +} + +static void sport_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + unsigned long flags; + int i; + + pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); + + switch (termios->c_cflag & CSIZE) { + case CS8: + up->csize = 8; + break; + case CS7: + up->csize = 7; + break; + case CS6: + up->csize = 6; + break; + case CS5: + up->csize = 5; + break; + default: + pr_warning("requested word length not supported\n"); + } + + if (termios->c_cflag & CSTOPB) { + up->stopb = 1; + } + if (termios->c_cflag & PARENB) { + pr_warning("PAREN bits is not supported yet\n"); + /* up->parib = 1; */ + } + + spin_lock_irqsave(&up->port.lock, flags); + + port->read_status_mask = 0; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + + /* RX extract mask */ + up->rxmask = 0x01 | (((up->csize + up->stopb) * 2 - 1) << 0x8); + /* TX masks, 8 bit data and 1 bit stop for example: + * mask1 = b#0111111110 + * mask2 = b#1000000000 + */ + for (i = 0, up->txmask1 = 0; i < up->csize; i++) + up->txmask1 |= (1<txmask2 = (1<stopb) { + ++i; + up->txmask2 |= (1<txmask1 <<= 1; + up->txmask2 <<= 1; + /* uart baud rate */ + port->uartclk = uart_get_baud_rate(port, termios, old, 0, get_sclk()/16); + + /* Disable UART */ + SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); + SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); + + sport_uart_setup(up, up->csize + up->stopb, port->uartclk); + + /* driver TX line high after config, one dummy data is + * necessary to stop sport after shift one byte + */ + SPORT_PUT_TX(up, 0xffff); + SPORT_PUT_TX(up, 0xffff); + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); + SSYNC(); + while (!(SPORT_GET_STAT(up) & TXHRE)) + cpu_relax(); + SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); + SSYNC(); + + /* Port speed changed, update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, port->uartclk); + + /* Enable sport rx */ + SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) | RSPEN); + SSYNC(); + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +struct uart_ops sport_uart_ops = { + .tx_empty = sport_tx_empty, + .set_mctrl = sport_set_mctrl, + .get_mctrl = sport_get_mctrl, + .stop_tx = sport_stop_tx, + .start_tx = sport_start_tx, + .stop_rx = sport_stop_rx, + .enable_ms = sport_enable_ms, + .break_ctl = sport_break_ctl, + .startup = sport_startup, + .shutdown = sport_shutdown, + .set_termios = sport_set_termios, + .type = sport_type, + .release_port = sport_release_port, + .request_port = sport_request_port, + .config_port = sport_config_port, + .verify_port = sport_verify_port, +}; + +#define BFIN_SPORT_UART_MAX_PORTS 4 + +static struct sport_uart_port *bfin_sport_uart_ports[BFIN_SPORT_UART_MAX_PORTS]; + +#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE +#define CLASS_BFIN_SPORT_CONSOLE "bfin-sport-console" + +static int __init +sport_uart_console_setup(struct console *co, char *options) +{ + struct sport_uart_port *up; + int baud = 57600; + int bits = 8; + int parity = 'n'; +# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS + int flow = 'r'; +# else + int flow = 'n'; +# endif + + /* Check whether an invalid uart number has been specified */ + if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS) + return -ENODEV; + + up = bfin_sport_uart_ports[co->index]; + if (!up) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&up->port, co, baud, parity, bits, flow); +} + +static void sport_uart_console_putchar(struct uart_port *port, int ch) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + while (SPORT_GET_STAT(up) & TXF) + barrier(); + + tx_one_byte(up, ch); +} + +/* + * Interrupts are disabled on entering + */ +static void +sport_uart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct sport_uart_port *up = bfin_sport_uart_ports[co->index]; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + + if (SPORT_GET_TCR1(up) & TSPEN) + uart_console_write(&up->port, s, count, sport_uart_console_putchar); + else { + /* dummy data to start sport */ + while (SPORT_GET_STAT(up) & TXF) + barrier(); + SPORT_PUT_TX(up, 0xffff); + /* Enable transmit, then an interrupt will generated */ + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); + SSYNC(); + + uart_console_write(&up->port, s, count, sport_uart_console_putchar); + + /* Although the hold register is empty, last byte is still in shift + * register and not sent out yet. So, put a dummy data into TX FIFO. + * Then, sport tx stops when last byte is shift out and the dummy + * data is moved into the shift register. + */ + while (SPORT_GET_STAT(up) & TXF) + barrier(); + SPORT_PUT_TX(up, 0xffff); + while (!(SPORT_GET_STAT(up) & TXHRE)) + barrier(); + + /* Stop sport tx transfer */ + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); + SSYNC(); + } + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static struct uart_driver sport_uart_reg; + +static struct console sport_uart_console = { + .name = DEVICE_NAME, + .write = sport_uart_console_write, + .device = uart_console_device, + .setup = sport_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sport_uart_reg, +}; + +#define SPORT_UART_CONSOLE (&sport_uart_console) +#else +#define SPORT_UART_CONSOLE NULL +#endif /* CONFIG_SERIAL_BFIN_SPORT_CONSOLE */ + + +static struct uart_driver sport_uart_reg = { + .owner = THIS_MODULE, + .driver_name = DRV_NAME, + .dev_name = DEVICE_NAME, + .major = 204, + .minor = 84, + .nr = BFIN_SPORT_UART_MAX_PORTS, + .cons = SPORT_UART_CONSOLE, +}; + +#ifdef CONFIG_PM +static int sport_uart_suspend(struct device *dev) +{ + struct sport_uart_port *sport = dev_get_drvdata(dev); + + dev_dbg(dev, "%s enter\n", __func__); + if (sport) + uart_suspend_port(&sport_uart_reg, &sport->port); + + return 0; +} + +static int sport_uart_resume(struct device *dev) +{ + struct sport_uart_port *sport = dev_get_drvdata(dev); + + dev_dbg(dev, "%s enter\n", __func__); + if (sport) + uart_resume_port(&sport_uart_reg, &sport->port); + + return 0; +} + +static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = { + .suspend = sport_uart_suspend, + .resume = sport_uart_resume, +}; +#endif + +static int __devinit sport_uart_probe(struct platform_device *pdev) +{ + struct resource *res; + struct sport_uart_port *sport; + int ret = 0; + + dev_dbg(&pdev->dev, "%s enter\n", __func__); + + if (pdev->id < 0 || pdev->id >= BFIN_SPORT_UART_MAX_PORTS) { + dev_err(&pdev->dev, "Wrong sport uart platform device id.\n"); + return -ENOENT; + } + + if (bfin_sport_uart_ports[pdev->id] == NULL) { + bfin_sport_uart_ports[pdev->id] = + kzalloc(sizeof(struct sport_uart_port), GFP_KERNEL); + sport = bfin_sport_uart_ports[pdev->id]; + if (!sport) { + dev_err(&pdev->dev, + "Fail to malloc sport_uart_port\n"); + return -ENOMEM; + } + + ret = peripheral_request_list( + (unsigned short *)pdev->dev.platform_data, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, + "Fail to request SPORT peripherals\n"); + goto out_error_free_mem; + } + + spin_lock_init(&sport->port.lock); + sport->port.fifosize = SPORT_TX_FIFO_SIZE, + sport->port.ops = &sport_uart_ops; + sport->port.line = pdev->id; + sport->port.iotype = UPIO_MEM; + sport->port.flags = UPF_BOOT_AUTOCONF; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + ret = -ENOENT; + goto out_error_free_peripherals; + } + + sport->port.membase = ioremap(res->start, resource_size(res)); + if (!sport->port.membase) { + dev_err(&pdev->dev, "Cannot map sport IO\n"); + ret = -ENXIO; + goto out_error_free_peripherals; + } + sport->port.mapbase = res->start; + + sport->port.irq = platform_get_irq(pdev, 0); + if (sport->port.irq < 0) { + dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + + sport->err_irq = platform_get_irq(pdev, 1); + if (sport->err_irq < 0) { + dev_err(&pdev->dev, "No sport status IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } +#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) + sport->cts_pin = -1; + else + sport->cts_pin = res->start; + + res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (res == NULL) + sport->rts_pin = -1; + else + sport->rts_pin = res->start; + + if (sport->rts_pin >= 0) + gpio_request(sport->rts_pin, DRV_NAME); +#endif + } + +#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE + if (!is_early_platform_device(pdev)) { +#endif + sport = bfin_sport_uart_ports[pdev->id]; + sport->port.dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, sport); + ret = uart_add_one_port(&sport_uart_reg, &sport->port); +#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE + } +#endif + if (!ret) + return 0; + + if (sport) { +out_error_unmap: + iounmap(sport->port.membase); +out_error_free_peripherals: + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); +out_error_free_mem: + kfree(sport); + bfin_sport_uart_ports[pdev->id] = NULL; + } + + return ret; +} + +static int __devexit sport_uart_remove(struct platform_device *pdev) +{ + struct sport_uart_port *sport = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s enter\n", __func__); + dev_set_drvdata(&pdev->dev, NULL); + + if (sport) { + uart_remove_one_port(&sport_uart_reg, &sport->port); +#ifdef CONFIG_SERIAL_BFIN_CTSRTS + if (sport->rts_pin >= 0) + gpio_free(sport->rts_pin); +#endif + iounmap(sport->port.membase); + peripheral_free_list( + (unsigned short *)pdev->dev.platform_data); + kfree(sport); + bfin_sport_uart_ports[pdev->id] = NULL; + } + + return 0; +} + +static struct platform_driver sport_uart_driver = { + .probe = sport_uart_probe, + .remove = __devexit_p(sport_uart_remove), + .driver = { + .name = DRV_NAME, +#ifdef CONFIG_PM + .pm = &bfin_sport_uart_dev_pm_ops, +#endif + }, +}; + +#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE +static __initdata struct early_platform_driver early_sport_uart_driver = { + .class_str = CLASS_BFIN_SPORT_CONSOLE, + .pdrv = &sport_uart_driver, + .requested_id = EARLY_PLATFORM_ID_UNSET, +}; + +static int __init sport_uart_rs_console_init(void) +{ + early_platform_driver_register(&early_sport_uart_driver, DRV_NAME); + + early_platform_driver_probe(CLASS_BFIN_SPORT_CONSOLE, + BFIN_SPORT_UART_MAX_PORTS, 0); + + register_console(&sport_uart_console); + + return 0; +} +console_initcall(sport_uart_rs_console_init); +#endif + +static int __init sport_uart_init(void) +{ + int ret; + + pr_info("Blackfin uart over sport driver\n"); + + ret = uart_register_driver(&sport_uart_reg); + if (ret) { + pr_err("failed to register %s:%d\n", + sport_uart_reg.driver_name, ret); + return ret; + } + + ret = platform_driver_register(&sport_uart_driver); + if (ret) { + pr_err("failed to register sport uart driver:%d\n", ret); + uart_unregister_driver(&sport_uart_reg); + } + + return ret; +} +module_init(sport_uart_init); + +static void __exit sport_uart_exit(void) +{ + platform_driver_unregister(&sport_uart_driver); + uart_unregister_driver(&sport_uart_reg); +} +module_exit(sport_uart_exit); + +MODULE_AUTHOR("Sonic Zhang, Roy Huang"); +MODULE_DESCRIPTION("Blackfin serial over SPORT driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/bfin_sport_uart.h b/drivers/tty/serial/bfin_sport_uart.h new file mode 100644 index 000000000000..6d06ce1d5675 --- /dev/null +++ b/drivers/tty/serial/bfin_sport_uart.h @@ -0,0 +1,86 @@ +/* + * Blackfin On-Chip Sport Emulated UART Driver + * + * Copyright 2006-2008 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +/* + * This driver and the hardware supported are in term of EE-191 of ADI. + * http://www.analog.com/static/imported-files/application_notes/EE191.pdf + * This application note describe how to implement a UART on a Sharc DSP, + * but this driver is implemented on Blackfin Processor. + * Transmit Frame Sync is not used by this driver to transfer data out. + */ + +#ifndef _BFIN_SPORT_UART_H +#define _BFIN_SPORT_UART_H + +#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */ +#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */ +#define OFFSET_TCLKDIV 0x08 /* Transmit Serial Clock Divider Register */ +#define OFFSET_TFSDIV 0x0C /* Transmit Frame Sync Divider Register */ +#define OFFSET_TX 0x10 /* Transmit Data Register */ +#define OFFSET_RX 0x18 /* Receive Data Register */ +#define OFFSET_RCR1 0x20 /* Receive Configuration 1 Register */ +#define OFFSET_RCR2 0x24 /* Receive Configuration 2 Register */ +#define OFFSET_RCLKDIV 0x28 /* Receive Serial Clock Divider Register */ +#define OFFSET_RFSDIV 0x2c /* Receive Frame Sync Divider Register */ +#define OFFSET_STAT 0x30 /* Status Register */ + +#define SPORT_GET_TCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR1)) +#define SPORT_GET_TCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR2)) +#define SPORT_GET_TCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV)) +#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV)) +#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX)) +#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX)) +/* + * If another interrupt fires while doing a 32-bit read from RX FIFO, + * a fake RX underflow error will be generated. So disable interrupts + * to prevent interruption while reading the FIFO. + */ +#define SPORT_GET_RX32(sport) \ +({ \ + unsigned int __ret; \ + if (ANOMALY_05000473) \ + local_irq_disable(); \ + __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \ + if (ANOMALY_05000473) \ + local_irq_enable(); \ + __ret; \ +}) +#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1)) +#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2)) +#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV)) +#define SPORT_GET_RFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RFSDIV)) +#define SPORT_GET_STAT(sport) bfin_read16(((sport)->port.membase + OFFSET_STAT)) + +#define SPORT_PUT_TCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR1), v) +#define SPORT_PUT_TCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR2), v) +#define SPORT_PUT_TCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v) +#define SPORT_PUT_TFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v) +#define SPORT_PUT_TX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TX), v) +#define SPORT_PUT_RX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RX), v) +#define SPORT_PUT_RCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR1), v) +#define SPORT_PUT_RCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR2), v) +#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v) +#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v) +#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v) + +#define SPORT_TX_FIFO_SIZE 8 + +#define SPORT_UART_GET_CTS(x) gpio_get_value(x->cts_pin) +#define SPORT_UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1) +#define SPORT_UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0) + +#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \ + || defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \ + || defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \ + || defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS) +# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS +#endif + +#endif /* _BFIN_SPORT_UART_H */ diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c new file mode 100644 index 000000000000..b6acd19b458e --- /dev/null +++ b/drivers/tty/serial/clps711x.c @@ -0,0 +1,579 @@ +/* + * linux/drivers/char/clps711x.c + * + * Driver for CLPS711x serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + */ + +#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define UART_NR 2 + +#define SERIAL_CLPS711X_MAJOR 204 +#define SERIAL_CLPS711X_MINOR 40 +#define SERIAL_CLPS711X_NR UART_NR + +/* + * We use the relevant SYSCON register as a base address for these ports. + */ +#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) +#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) +#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) +#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) + +#define TX_IRQ(port) ((port)->irq) +#define RX_IRQ(port) ((port)->irq + 1) + +#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) + +#define tx_enabled(port) ((port)->unused[0]) + +static void clps711xuart_stop_tx(struct uart_port *port) +{ + if (tx_enabled(port)) { + disable_irq(TX_IRQ(port)); + tx_enabled(port) = 0; + } +} + +static void clps711xuart_start_tx(struct uart_port *port) +{ + if (!tx_enabled(port)) { + enable_irq(TX_IRQ(port)); + tx_enabled(port) = 1; + } +} + +static void clps711xuart_stop_rx(struct uart_port *port) +{ + disable_irq(RX_IRQ(port)); +} + +static void clps711xuart_enable_ms(struct uart_port *port) +{ +} + +static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = port->state->port.tty; + unsigned int status, ch, flg; + + status = clps_readl(SYSFLG(port)); + while (!(status & SYSFLG_URXFE)) { + ch = clps_readl(UARTDR(port)); + + port->icount.rx++; + + flg = TTY_NORMAL; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (unlikely(ch & UART_ANY_ERR)) { + if (ch & UARTDR_PARERR) + port->icount.parity++; + else if (ch & UARTDR_FRMERR) + port->icount.frame++; + if (ch & UARTDR_OVERR) + port->icount.overrun++; + + ch &= port->read_status_mask; + + if (ch & UARTDR_PARERR) + flg = TTY_PARITY; + else if (ch & UARTDR_FRMERR) + flg = TTY_FRAME; + +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + } + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + /* + * CHECK: does overrun affect the current character? + * ASSUMPTION: it does not. + */ + uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); + + ignore_char: + status = clps_readl(SYSFLG(port)); + } + tty_flip_buffer_push(tty); + return IRQ_HANDLED; +} + +static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct circ_buf *xmit = &port->state->xmit; + int count; + + if (port->x_char) { + clps_writel(port->x_char, UARTDR(port)); + port->icount.tx++; + port->x_char = 0; + return IRQ_HANDLED; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + clps711xuart_stop_tx(port); + return IRQ_HANDLED; + } + + count = port->fifosize >> 1; + do { + clps_writel(xmit->buf[xmit->tail], UARTDR(port)); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + clps711xuart_stop_tx(port); + + return IRQ_HANDLED; +} + +static unsigned int clps711xuart_tx_empty(struct uart_port *port) +{ + unsigned int status = clps_readl(SYSFLG(port)); + return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; +} + +static unsigned int clps711xuart_get_mctrl(struct uart_port *port) +{ + unsigned int port_addr; + unsigned int result = 0; + unsigned int status; + + port_addr = SYSFLG(port); + if (port_addr == SYSFLG1) { + status = clps_readl(SYSFLG1); + if (status & SYSFLG1_DCD) + result |= TIOCM_CAR; + if (status & SYSFLG1_DSR) + result |= TIOCM_DSR; + if (status & SYSFLG1_CTS) + result |= TIOCM_CTS; + } + + return result; +} + +static void +clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) +{ +} + +static void clps711xuart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int ubrlcr; + + spin_lock_irqsave(&port->lock, flags); + ubrlcr = clps_readl(UBRLCR(port)); + if (break_state == -1) + ubrlcr |= UBRLCR_BREAK; + else + ubrlcr &= ~UBRLCR_BREAK; + clps_writel(ubrlcr, UBRLCR(port)); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int clps711xuart_startup(struct uart_port *port) +{ + unsigned int syscon; + int retval; + + tx_enabled(port) = 1; + + /* + * Allocate the IRQs + */ + retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0, + "clps711xuart_tx", port); + if (retval) + return retval; + + retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0, + "clps711xuart_rx", port); + if (retval) { + free_irq(TX_IRQ(port), port); + return retval; + } + + /* + * enable the port + */ + syscon = clps_readl(SYSCON(port)); + syscon |= SYSCON_UARTEN; + clps_writel(syscon, SYSCON(port)); + + return 0; +} + +static void clps711xuart_shutdown(struct uart_port *port) +{ + unsigned int ubrlcr, syscon; + + /* + * Free the interrupt + */ + free_irq(TX_IRQ(port), port); /* TX interrupt */ + free_irq(RX_IRQ(port), port); /* RX interrupt */ + + /* + * disable the port + */ + syscon = clps_readl(SYSCON(port)); + syscon &= ~SYSCON_UARTEN; + clps_writel(syscon, SYSCON(port)); + + /* + * disable break condition and fifos + */ + ubrlcr = clps_readl(UBRLCR(port)); + ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); + clps_writel(ubrlcr, UBRLCR(port)); +} + +static void +clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int ubrlcr, baud, quot; + unsigned long flags; + + /* + * We don't implement CREAD. + */ + termios->c_cflag |= CREAD; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + switch (termios->c_cflag & CSIZE) { + case CS5: + ubrlcr = UBRLCR_WRDLEN5; + break; + case CS6: + ubrlcr = UBRLCR_WRDLEN6; + break; + case CS7: + ubrlcr = UBRLCR_WRDLEN7; + break; + default: // CS8 + ubrlcr = UBRLCR_WRDLEN8; + break; + } + if (termios->c_cflag & CSTOPB) + ubrlcr |= UBRLCR_XSTOP; + if (termios->c_cflag & PARENB) { + ubrlcr |= UBRLCR_PRTEN; + if (!(termios->c_cflag & PARODD)) + ubrlcr |= UBRLCR_EVENPRT; + } + if (port->fifosize > 1) + ubrlcr |= UBRLCR_FIFOEN; + + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UARTDR_OVERR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; + if (termios->c_iflag & IGNBRK) { + /* + * If we're ignoring parity and break indicators, + * ignore overruns to (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UARTDR_OVERR; + } + + quot -= 1; + + clps_writel(ubrlcr | quot, UBRLCR(port)); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *clps711xuart_type(struct uart_port *port) +{ + return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; +} + +/* + * Configure/autoconfigure the port. + */ +static void clps711xuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_CLPS711X; +} + +static void clps711xuart_release_port(struct uart_port *port) +{ +} + +static int clps711xuart_request_port(struct uart_port *port) +{ + return 0; +} + +static struct uart_ops clps711x_pops = { + .tx_empty = clps711xuart_tx_empty, + .set_mctrl = clps711xuart_set_mctrl_null, + .get_mctrl = clps711xuart_get_mctrl, + .stop_tx = clps711xuart_stop_tx, + .start_tx = clps711xuart_start_tx, + .stop_rx = clps711xuart_stop_rx, + .enable_ms = clps711xuart_enable_ms, + .break_ctl = clps711xuart_break_ctl, + .startup = clps711xuart_startup, + .shutdown = clps711xuart_shutdown, + .set_termios = clps711xuart_set_termios, + .type = clps711xuart_type, + .config_port = clps711xuart_config_port, + .release_port = clps711xuart_release_port, + .request_port = clps711xuart_request_port, +}; + +static struct uart_port clps711x_ports[UART_NR] = { + { + .iobase = SYSCON1, + .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ + .uartclk = 3686400, + .fifosize = 16, + .ops = &clps711x_pops, + .line = 0, + .flags = UPF_BOOT_AUTOCONF, + }, + { + .iobase = SYSCON2, + .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ + .uartclk = 3686400, + .fifosize = 16, + .ops = &clps711x_pops, + .line = 1, + .flags = UPF_BOOT_AUTOCONF, + } +}; + +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE +static void clps711xuart_console_putchar(struct uart_port *port, int ch) +{ + while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) + barrier(); + clps_writel(ch, UARTDR(port)); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + * + * Note that this is called with interrupts already disabled + */ +static void +clps711xuart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = clps711x_ports + co->index; + unsigned int status, syscon; + + /* + * Ensure that the port is enabled. + */ + syscon = clps_readl(SYSCON(port)); + clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); + + uart_console_write(port, s, count, clps711xuart_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the uart state. + */ + do { + status = clps_readl(SYSFLG(port)); + } while (status & SYSFLG_UBUSY); + + clps_writel(syscon, SYSCON(port)); +} + +static void __init +clps711xuart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { + unsigned int ubrlcr, quot; + + ubrlcr = clps_readl(UBRLCR(port)); + + *parity = 'n'; + if (ubrlcr & UBRLCR_PRTEN) { + if (ubrlcr & UBRLCR_EVENPRT) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) + *bits = 7; + else + *bits = 8; + + quot = ubrlcr & UBRLCR_BAUD_MASK; + *baud = port->uartclk / (16 * (quot + 1)); + } +} + +static int __init clps711xuart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + port = uart_get_console(clps711x_ports, UART_NR, co); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + clps711xuart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver clps711x_reg; +static struct console clps711x_console = { + .name = "ttyCL", + .write = clps711xuart_console_write, + .device = uart_console_device, + .setup = clps711xuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &clps711x_reg, +}; + +static int __init clps711xuart_console_init(void) +{ + register_console(&clps711x_console); + return 0; +} +console_initcall(clps711xuart_console_init); + +#define CLPS711X_CONSOLE &clps711x_console +#else +#define CLPS711X_CONSOLE NULL +#endif + +static struct uart_driver clps711x_reg = { + .driver_name = "ttyCL", + .dev_name = "ttyCL", + .major = SERIAL_CLPS711X_MAJOR, + .minor = SERIAL_CLPS711X_MINOR, + .nr = UART_NR, + + .cons = CLPS711X_CONSOLE, +}; + +static int __init clps711xuart_init(void) +{ + int ret, i; + + printk(KERN_INFO "Serial: CLPS711x driver\n"); + + ret = uart_register_driver(&clps711x_reg); + if (ret) + return ret; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&clps711x_reg, &clps711x_ports[i]); + + return 0; +} + +static void __exit clps711xuart_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]); + + uart_unregister_driver(&clps711x_reg); +} + +module_init(clps711xuart_init); +module_exit(clps711xuart_exit); + +MODULE_AUTHOR("Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("CLPS-711x generic serial driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile new file mode 100644 index 000000000000..e072724ea754 --- /dev/null +++ b/drivers/tty/serial/cpm_uart/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the Motorola 8xx FEC ethernet controller +# + +obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o + +# Select the correct platform objects. +cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o +cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o + +cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h new file mode 100644 index 000000000000..b754dcf0fda5 --- /dev/null +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -0,0 +1,147 @@ +/* + * linux/drivers/serial/cpm_uart.h + * + * Driver for CPM (SCC/SMC) serial ports + * + * Copyright (C) 2004 Freescale Semiconductor, Inc. + * + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * 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. + * + */ +#ifndef CPM_UART_H +#define CPM_UART_H + +#include +#include + +#if defined(CONFIG_CPM2) +#include "cpm_uart_cpm2.h" +#elif defined(CONFIG_8xx) +#include "cpm_uart_cpm1.h" +#endif + +#define SERIAL_CPM_MAJOR 204 +#define SERIAL_CPM_MINOR 46 + +#define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC) +#define IS_DISCARDING(pinfo) (pinfo->flags & FLAG_DISCARDING) +#define FLAG_DISCARDING 0x00000004 /* when set, don't discard */ +#define FLAG_SMC 0x00000002 +#define FLAG_CONSOLE 0x00000001 + +#define UART_SMC1 fsid_smc1_uart +#define UART_SMC2 fsid_smc2_uart +#define UART_SCC1 fsid_scc1_uart +#define UART_SCC2 fsid_scc2_uart +#define UART_SCC3 fsid_scc3_uart +#define UART_SCC4 fsid_scc4_uart + +#define UART_NR fs_uart_nr + +#define RX_NUM_FIFO 4 +#define RX_BUF_SIZE 32 +#define TX_NUM_FIFO 4 +#define TX_BUF_SIZE 32 + +#define SCC_WAIT_CLOSING 100 + +#define GPIO_CTS 0 +#define GPIO_RTS 1 +#define GPIO_DCD 2 +#define GPIO_DSR 3 +#define GPIO_DTR 4 +#define GPIO_RI 5 + +#define NUM_GPIOS (GPIO_RI+1) + +struct uart_cpm_port { + struct uart_port port; + u16 rx_nrfifos; + u16 rx_fifosize; + u16 tx_nrfifos; + u16 tx_fifosize; + smc_t __iomem *smcp; + smc_uart_t __iomem *smcup; + scc_t __iomem *sccp; + scc_uart_t __iomem *sccup; + cbd_t __iomem *rx_bd_base; + cbd_t __iomem *rx_cur; + cbd_t __iomem *tx_bd_base; + cbd_t __iomem *tx_cur; + unsigned char *tx_buf; + unsigned char *rx_buf; + u32 flags; + struct clk *clk; + u8 brg; + uint dp_addr; + void *mem_addr; + dma_addr_t dma_addr; + u32 mem_size; + /* wait on close if needed */ + int wait_closing; + /* value to combine with opcode to form cpm command */ + u32 command; + int gpios[NUM_GPIOS]; +}; + +extern int cpm_uart_nr; +extern struct uart_cpm_port cpm_uart_ports[UART_NR]; + +/* these are located in their respective files */ +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd); +void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np); +void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram); +int cpm_uart_init_portdesc(void); +int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); +void cpm_uart_freebuf(struct uart_cpm_port *pinfo); + +void smc1_lineif(struct uart_cpm_port *pinfo); +void smc2_lineif(struct uart_cpm_port *pinfo); +void scc1_lineif(struct uart_cpm_port *pinfo); +void scc2_lineif(struct uart_cpm_port *pinfo); +void scc3_lineif(struct uart_cpm_port *pinfo); +void scc4_lineif(struct uart_cpm_port *pinfo); + +/* + virtual to phys transtalion +*/ +static inline unsigned long cpu2cpm_addr(void *addr, + struct uart_cpm_port *pinfo) +{ + int offset; + u32 val = (u32)addr; + u32 mem = (u32)pinfo->mem_addr; + /* sane check */ + if (likely(val >= mem && val < mem + pinfo->mem_size)) { + offset = val - mem; + return pinfo->dma_addr + offset; + } + /* something nasty happened */ + BUG(); + return 0; +} + +static inline void *cpm2cpu_addr(unsigned long addr, + struct uart_cpm_port *pinfo) +{ + int offset; + u32 val = addr; + u32 dma = (u32)pinfo->dma_addr; + /* sane check */ + if (likely(val >= dma && val < dma + pinfo->mem_size)) { + offset = val - dma; + return pinfo->mem_addr + offset; + } + /* something nasty happened */ + BUG(); + return NULL; +} + + +#endif /* CPM_UART_H */ diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c new file mode 100644 index 000000000000..8692ff98fc07 --- /dev/null +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -0,0 +1,1443 @@ +/* + * linux/drivers/serial/cpm_uart.c + * + * Driver for CPM (SCC/SMC) serial ports; core driver + * + * Based on arch/ppc/cpm2_io/uart.c by Dan Malek + * Based on ppc8xx.c by Thomas Gleixner + * Based on drivers/serial/amba.c by Russell King + * + * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) + * Pantelis Antoniou (panto@intracom.gr) (CPM1) + * + * Copyright (C) 2004, 2007 Freescale Semiconductor, Inc. + * (C) 2004 Intracom, S.A. + * (C) 2005-2006 MontaVista Software, Inc. + * Vitaly Bordug + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include + +#include "cpm_uart.h" + + +/**************************************************************/ + +static int cpm_uart_tx_pump(struct uart_port *port); +static void cpm_uart_init_smc(struct uart_cpm_port *pinfo); +static void cpm_uart_init_scc(struct uart_cpm_port *pinfo); +static void cpm_uart_initbd(struct uart_cpm_port *pinfo); + +/**************************************************************/ + +#define HW_BUF_SPD_THRESHOLD 9600 + +/* + * Check, if transmit buffers are processed +*/ +static unsigned int cpm_uart_tx_empty(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + cbd_t __iomem *bdp = pinfo->tx_bd_base; + int ret = 0; + + while (1) { + if (in_be16(&bdp->cbd_sc) & BD_SC_READY) + break; + + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) { + ret = TIOCSER_TEMT; + break; + } + bdp++; + } + + pr_debug("CPM uart[%d]:tx_empty: %d\n", port->line, ret); + + return ret; +} + +static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + if (pinfo->gpios[GPIO_RTS] >= 0) + gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); + + if (pinfo->gpios[GPIO_DTR] >= 0) + gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); +} + +static unsigned int cpm_uart_get_mctrl(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + if (pinfo->gpios[GPIO_CTS] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_CTS])) + mctrl &= ~TIOCM_CTS; + } + + if (pinfo->gpios[GPIO_DSR] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_DSR])) + mctrl &= ~TIOCM_DSR; + } + + if (pinfo->gpios[GPIO_DCD] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_DCD])) + mctrl &= ~TIOCM_CAR; + } + + if (pinfo->gpios[GPIO_RI] >= 0) { + if (!gpio_get_value(pinfo->gpios[GPIO_RI])) + mctrl |= TIOCM_RNG; + } + + return mctrl; +} + +/* + * Stop transmitter + */ +static void cpm_uart_stop_tx(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; + + pr_debug("CPM uart[%d]:stop tx\n", port->line); + + if (IS_SMC(pinfo)) + clrbits8(&smcp->smc_smcm, SMCM_TX); + else + clrbits16(&sccp->scc_sccm, UART_SCCM_TX); +} + +/* + * Start transmitter + */ +static void cpm_uart_start_tx(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; + + pr_debug("CPM uart[%d]:start tx\n", port->line); + + if (IS_SMC(pinfo)) { + if (in_8(&smcp->smc_smcm) & SMCM_TX) + return; + } else { + if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX) + return; + } + + if (cpm_uart_tx_pump(port) != 0) { + if (IS_SMC(pinfo)) { + setbits8(&smcp->smc_smcm, SMCM_TX); + } else { + setbits16(&sccp->scc_sccm, UART_SCCM_TX); + } + } +} + +/* + * Stop receiver + */ +static void cpm_uart_stop_rx(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; + + pr_debug("CPM uart[%d]:stop rx\n", port->line); + + if (IS_SMC(pinfo)) + clrbits8(&smcp->smc_smcm, SMCM_RX); + else + clrbits16(&sccp->scc_sccm, UART_SCCM_RX); +} + +/* + * Enable Modem status interrupts + */ +static void cpm_uart_enable_ms(struct uart_port *port) +{ + pr_debug("CPM uart[%d]:enable ms\n", port->line); +} + +/* + * Generate a break. + */ +static void cpm_uart_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line, + break_state); + + if (break_state) + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); + else + cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); +} + +/* + * Transmit characters, refill buffer descriptor, if possible + */ +static void cpm_uart_int_tx(struct uart_port *port) +{ + pr_debug("CPM uart[%d]:TX INT\n", port->line); + + cpm_uart_tx_pump(port); +} + +#ifdef CONFIG_CONSOLE_POLL +static int serial_polled; +#endif + +/* + * Receive characters + */ +static void cpm_uart_int_rx(struct uart_port *port) +{ + int i; + unsigned char ch; + u8 *cp; + struct tty_struct *tty = port->state->port.tty; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + cbd_t __iomem *bdp; + u16 status; + unsigned int flg; + + pr_debug("CPM uart[%d]:RX INT\n", port->line); + + /* Just loop through the closed BDs and copy the characters into + * the buffer. + */ + bdp = pinfo->rx_cur; + for (;;) { +#ifdef CONFIG_CONSOLE_POLL + if (unlikely(serial_polled)) { + serial_polled = 0; + return; + } +#endif + /* get status */ + status = in_be16(&bdp->cbd_sc); + /* If this one is empty, return happy */ + if (status & BD_SC_EMPTY) + break; + + /* get number of characters, and check spce in flip-buffer */ + i = in_be16(&bdp->cbd_datlen); + + /* If we have not enough room in tty flip buffer, then we try + * later, which will be the next rx-interrupt or a timeout + */ + if(tty_buffer_request_room(tty, i) < i) { + printk(KERN_WARNING "No room in flip buffer\n"); + return; + } + + /* get pointer */ + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); + + /* loop through the buffer */ + while (i-- > 0) { + ch = *cp++; + port->icount.rx++; + flg = TTY_NORMAL; + + if (status & + (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) + goto handle_error; + if (uart_handle_sysrq_char(port, ch)) + continue; +#ifdef CONFIG_CONSOLE_POLL + if (unlikely(serial_polled)) { + serial_polled = 0; + return; + } +#endif + error_return: + tty_insert_flip_char(tty, ch, flg); + + } /* End while (i--) */ + + /* This BD is ready to be used again. Clear status. get next */ + clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR | + BD_SC_OV | BD_SC_ID); + setbits16(&bdp->cbd_sc, BD_SC_EMPTY); + + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) + bdp = pinfo->rx_bd_base; + else + bdp++; + + } /* End for (;;) */ + + /* Write back buffer pointer */ + pinfo->rx_cur = bdp; + + /* activate BH processing */ + tty_flip_buffer_push(tty); + + return; + + /* Error processing */ + + handle_error: + /* Statistics */ + if (status & BD_SC_BR) + port->icount.brk++; + if (status & BD_SC_PR) + port->icount.parity++; + if (status & BD_SC_FR) + port->icount.frame++; + if (status & BD_SC_OV) + port->icount.overrun++; + + /* Mask out ignored conditions */ + status &= port->read_status_mask; + + /* Handle the remaining ones */ + if (status & BD_SC_BR) + flg = TTY_BREAK; + else if (status & BD_SC_PR) + flg = TTY_PARITY; + else if (status & BD_SC_FR) + flg = TTY_FRAME; + + /* overrun does not affect the current character ! */ + if (status & BD_SC_OV) { + ch = 0; + flg = TTY_OVERRUN; + /* We skip this buffer */ + /* CHECK: Is really nothing senseful there */ + /* ASSUMPTION: it contains nothing valid */ + i = 0; + } +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + goto error_return; +} + +/* + * Asynchron mode interrupt handler + */ +static irqreturn_t cpm_uart_int(int irq, void *data) +{ + u8 events; + struct uart_port *port = data; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; + + pr_debug("CPM uart[%d]:IRQ\n", port->line); + + if (IS_SMC(pinfo)) { + events = in_8(&smcp->smc_smce); + out_8(&smcp->smc_smce, events); + if (events & SMCM_BRKE) + uart_handle_break(port); + if (events & SMCM_RX) + cpm_uart_int_rx(port); + if (events & SMCM_TX) + cpm_uart_int_tx(port); + } else { + events = in_be16(&sccp->scc_scce); + out_be16(&sccp->scc_scce, events); + if (events & UART_SCCM_BRKE) + uart_handle_break(port); + if (events & UART_SCCM_RX) + cpm_uart_int_rx(port); + if (events & UART_SCCM_TX) + cpm_uart_int_tx(port); + } + return (events) ? IRQ_HANDLED : IRQ_NONE; +} + +static int cpm_uart_startup(struct uart_port *port) +{ + int retval; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + pr_debug("CPM uart[%d]:startup\n", port->line); + + /* If the port is not the console, make sure rx is disabled. */ + if (!(pinfo->flags & FLAG_CONSOLE)) { + /* Disable UART rx */ + if (IS_SMC(pinfo)) { + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN); + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX); + } else { + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR); + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX); + } + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); + } + /* Install interrupt handler. */ + retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port); + if (retval) + return retval; + + /* Startup rx-int */ + if (IS_SMC(pinfo)) { + setbits8(&pinfo->smcp->smc_smcm, SMCM_RX); + setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN)); + } else { + setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX); + setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT)); + } + + return 0; +} + +inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(pinfo->wait_closing); +} + +/* + * Shutdown the uart + */ +static void cpm_uart_shutdown(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + pr_debug("CPM uart[%d]:shutdown\n", port->line); + + /* free interrupt handler */ + free_irq(port->irq, port); + + /* If the port is not the console, disable Rx and Tx. */ + if (!(pinfo->flags & FLAG_CONSOLE)) { + /* Wait for all the BDs marked sent */ + while(!cpm_uart_tx_empty(port)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(2); + } + + if (pinfo->wait_closing) + cpm_uart_wait_until_send(pinfo); + + /* Stop uarts */ + if (IS_SMC(pinfo)) { + smc_t __iomem *smcp = pinfo->smcp; + clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); + clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX); + } else { + scc_t __iomem *sccp = pinfo->sccp; + clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + } + + /* Shut them really down and reinit buffer descriptors */ + if (IS_SMC(pinfo)) { + out_be16(&pinfo->smcup->smc_brkcr, 0); + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); + } else { + out_be16(&pinfo->sccup->scc_brkcr, 0); + cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX); + } + + cpm_uart_initbd(pinfo); + } +} + +static void cpm_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + int baud; + unsigned long flags; + u16 cval, scval, prev_mode; + int bits, sbits; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; + + pr_debug("CPM uart[%d]:set_termios\n", port->line); + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + if (baud <= HW_BUF_SPD_THRESHOLD || + (pinfo->port.state && pinfo->port.state->port.tty->low_latency)) + pinfo->rx_fifosize = 1; + else + pinfo->rx_fifosize = RX_BUF_SIZE; + + /* Character length programmed into the mode register is the + * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, + * 1 or 2 stop bits, minus 1. + * The value 'bits' counts this for us. + */ + cval = 0; + scval = 0; + + /* byte size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + bits = 5; + break; + case CS6: + bits = 6; + break; + case CS7: + bits = 7; + break; + case CS8: + bits = 8; + break; + /* Never happens, but GCC is too dumb to figure it out */ + default: + bits = 8; + break; + } + sbits = bits - 5; + + if (termios->c_cflag & CSTOPB) { + cval |= SMCMR_SL; /* Two stops */ + scval |= SCU_PSMR_SL; + bits++; + } + + if (termios->c_cflag & PARENB) { + cval |= SMCMR_PEN; + scval |= SCU_PSMR_PEN; + bits++; + if (!(termios->c_cflag & PARODD)) { + cval |= SMCMR_PM_EVEN; + scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); + } + } + + /* + * Update the timeout + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); + if (termios->c_iflag & INPCK) + port->read_status_mask |= BD_SC_FR | BD_SC_PR; + if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK)) + port->read_status_mask |= BD_SC_BR; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= BD_SC_BR; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= BD_SC_OV; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->read_status_mask &= ~BD_SC_EMPTY; + + spin_lock_irqsave(&port->lock, flags); + + /* Start bit has not been added (so don't, because we would just + * subtract it later), and we need to add one for the number of + * stops bits (there is always at least one). + */ + bits++; + if (IS_SMC(pinfo)) { + /* + * MRBLR can be changed while an SMC/SCC is operating only + * if it is done in a single bus cycle with one 16-bit move + * (not two 8-bit bus cycles back-to-back). This occurs when + * the cp shifts control to the next RxBD, so the change does + * not take effect immediately. To guarantee the exact RxBD + * on which the change occurs, change MRBLR only while the + * SMC/SCC receiver is disabled. + */ + out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize); + + /* Set the mode register. We want to keep a copy of the + * enables, because we want to put them back if they were + * present. + */ + prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN); + /* Output in *one* operation, so we don't interrupt RX/TX if they + * were already enabled. */ + out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | + SMCMR_SM_UART | prev_mode); + } else { + out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); + out_be16(&sccp->scc_psmr, (sbits << 12) | scval); + } + + if (pinfo->clk) + clk_set_rate(pinfo->clk, baud); + else + cpm_set_brg(pinfo->brg - 1, baud); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *cpm_uart_type(struct uart_port *port) +{ + pr_debug("CPM uart[%d]:uart_type\n", port->line); + + return port->type == PORT_CPM ? "CPM UART" : NULL; +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int cpm_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + + pr_debug("CPM uart[%d]:verify_port\n", port->line); + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= nr_irqs) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +/* + * Transmit characters, refill buffer descriptor, if possible + */ +static int cpm_uart_tx_pump(struct uart_port *port) +{ + cbd_t __iomem *bdp; + u8 *p; + int count; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + struct circ_buf *xmit = &port->state->xmit; + + /* Handle xon/xoff */ + if (port->x_char) { + /* Pick next descriptor and fill from buffer */ + bdp = pinfo->tx_cur; + + p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); + + *p++ = port->x_char; + + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); + /* Get next BD. */ + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) + bdp = pinfo->tx_bd_base; + else + bdp++; + pinfo->tx_cur = bdp; + + port->icount.tx++; + port->x_char = 0; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + cpm_uart_stop_tx(port); + return 0; + } + + /* Pick next descriptor and fill from buffer */ + bdp = pinfo->tx_cur; + + while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && + xmit->tail != xmit->head) { + count = 0; + p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); + while (count < pinfo->tx_fifosize) { + *p++ = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + count++; + if (xmit->head == xmit->tail) + break; + } + out_be16(&bdp->cbd_datlen, count); + setbits16(&bdp->cbd_sc, BD_SC_READY); + /* Get next BD. */ + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) + bdp = pinfo->tx_bd_base; + else + bdp++; + } + pinfo->tx_cur = bdp; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) { + cpm_uart_stop_tx(port); + return 0; + } + + return 1; +} + +/* + * init buffer descriptors + */ +static void cpm_uart_initbd(struct uart_cpm_port *pinfo) +{ + int i; + u8 *mem_addr; + cbd_t __iomem *bdp; + + pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + mem_addr = pinfo->mem_addr; + bdp = pinfo->rx_cur = pinfo->rx_bd_base; + for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT); + mem_addr += pinfo->rx_fifosize; + } + + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); + bdp = pinfo->tx_cur = pinfo->tx_bd_base; + for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_INTRPT); + mem_addr += pinfo->tx_fifosize; + } + + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT); +} + +static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) +{ + scc_t __iomem *scp; + scc_uart_t __iomem *sup; + + pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line); + + scp = pinfo->sccp; + sup = pinfo->sccup; + + /* Store address */ + out_be16(&pinfo->sccup->scc_genscc.scc_rbase, + (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); + out_be16(&pinfo->sccup->scc_genscc.scc_tbase, + (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); + + /* Set up the uart parameters in the + * parameter ram. + */ + + cpm_set_scc_fcr(sup); + + out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); + out_be16(&sup->scc_maxidl, pinfo->rx_fifosize); + out_be16(&sup->scc_brkcr, 1); + out_be16(&sup->scc_parec, 0); + out_be16(&sup->scc_frmec, 0); + out_be16(&sup->scc_nosec, 0); + out_be16(&sup->scc_brkec, 0); + out_be16(&sup->scc_uaddr1, 0); + out_be16(&sup->scc_uaddr2, 0); + out_be16(&sup->scc_toseq, 0); + out_be16(&sup->scc_char1, 0x8000); + out_be16(&sup->scc_char2, 0x8000); + out_be16(&sup->scc_char3, 0x8000); + out_be16(&sup->scc_char4, 0x8000); + out_be16(&sup->scc_char5, 0x8000); + out_be16(&sup->scc_char6, 0x8000); + out_be16(&sup->scc_char7, 0x8000); + out_be16(&sup->scc_char8, 0x8000); + out_be16(&sup->scc_rccm, 0xc0ff); + + /* Send the CPM an initialize command. + */ + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + out_be32(&scp->scc_gsmrh, 0); + out_be32(&scp->scc_gsmrl, + SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Enable rx interrupts and clear all pending events. */ + out_be16(&scp->scc_sccm, 0); + out_be16(&scp->scc_scce, 0xffff); + out_be16(&scp->scc_dsr, 0x7e7e); + out_be16(&scp->scc_psmr, 0x3000); + + setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); +} + +static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) +{ + smc_t __iomem *sp; + smc_uart_t __iomem *up; + + pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line); + + sp = pinfo->smcp; + up = pinfo->smcup; + + /* Store address */ + out_be16(&pinfo->smcup->smc_rbase, + (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); + out_be16(&pinfo->smcup->smc_tbase, + (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); + +/* + * In case SMC1 is being relocated... + */ +#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH) + out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase)); + out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase)); + out_be32(&up->smc_rstate, 0); + out_be32(&up->smc_tstate, 0); + out_be16(&up->smc_brkcr, 1); /* number of break chars */ + out_be16(&up->smc_brkec, 0); +#endif + + /* Set up the uart parameters in the + * parameter ram. + */ + cpm_set_smc_fcr(up); + + /* Using idle character time requires some additional tuning. */ + out_be16(&up->smc_mrblr, pinfo->rx_fifosize); + out_be16(&up->smc_maxidl, pinfo->rx_fifosize); + out_be16(&up->smc_brklen, 0); + out_be16(&up->smc_brkec, 0); + out_be16(&up->smc_brkcr, 1); + + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART); + + /* Enable only rx interrupts clear all pending events. */ + out_8(&sp->smc_smcm, 0); + out_8(&sp->smc_smce, 0xff); + + setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN); +} + +/* + * Initialize port. This is called from early_console stuff + * so we have to be careful here ! + */ +static int cpm_uart_request_port(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + int ret; + + pr_debug("CPM uart[%d]:request port\n", port->line); + + if (pinfo->flags & FLAG_CONSOLE) + return 0; + + if (IS_SMC(pinfo)) { + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); + } else { + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + } + + ret = cpm_uart_allocbuf(pinfo, 0); + + if (ret) + return ret; + + cpm_uart_initbd(pinfo); + if (IS_SMC(pinfo)) + cpm_uart_init_smc(pinfo); + else + cpm_uart_init_scc(pinfo); + + return 0; +} + +static void cpm_uart_release_port(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + if (!(pinfo->flags & FLAG_CONSOLE)) + cpm_uart_freebuf(pinfo); +} + +/* + * Configure/autoconfigure the port. + */ +static void cpm_uart_config_port(struct uart_port *port, int flags) +{ + pr_debug("CPM uart[%d]:config_port\n", port->line); + + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_CPM; + cpm_uart_request_port(port); + } +} + +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_CPM_CONSOLE) +/* + * Write a string to the serial port + * Note that this is called with interrupts already disabled + */ +static void cpm_uart_early_write(struct uart_cpm_port *pinfo, + const char *string, u_int count) +{ + unsigned int i; + cbd_t __iomem *bdp, *bdbase; + unsigned char *cpm_outp_addr; + + /* Get the address of the host memory buffer. + */ + bdp = pinfo->tx_cur; + bdbase = pinfo->tx_bd_base; + + /* + * Now, do each character. This is not as bad as it looks + * since this is a holding FIFO and not a transmitting FIFO. + * We could add the complexity of filling the entire transmit + * buffer, but we would just wait longer between accesses...... + */ + for (i = 0; i < count; i++, string++) { + /* Wait for transmitter fifo to empty. + * Ready indicates output is ready, and xmt is doing + * that, not that it is ready for us to send. + */ + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) + ; + + /* Send the character out. + * If the buffer address is in the CPM DPRAM, don't + * convert it. + */ + cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), + pinfo); + *cpm_outp_addr = *string; + + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); + + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) + bdp = bdbase; + else + bdp++; + + /* if a LF, also do CR... */ + if (*string == 10) { + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) + ; + + cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), + pinfo); + *cpm_outp_addr = 13; + + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); + + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) + bdp = bdbase; + else + bdp++; + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) + ; + + pinfo->tx_cur = bdp; +} +#endif + +#ifdef CONFIG_CONSOLE_POLL +/* Serial polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char poll_buf[GDB_BUF_SIZE]; +static char *pollp; +static int poll_chars; + +static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) +{ + u_char c, *cp; + volatile cbd_t *bdp; + int i; + + /* Get the address of the host memory buffer. + */ + bdp = pinfo->rx_cur; + while (bdp->cbd_sc & BD_SC_EMPTY) + ; + + /* If the buffer address is in the CPM DPRAM, don't + * convert it. + */ + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + + if (obuf) { + i = c = bdp->cbd_datlen; + while (i-- > 0) + *obuf++ = *cp++; + } else + c = *cp; + bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); + bdp->cbd_sc |= BD_SC_EMPTY; + + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = pinfo->rx_bd_base; + else + bdp++; + pinfo->rx_cur = (cbd_t *)bdp; + + return (int)c; +} + +static int cpm_get_poll_char(struct uart_port *port) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + if (!serial_polled) { + serial_polled = 1; + poll_chars = 0; + } + if (poll_chars <= 0) { + poll_chars = poll_wait_key(poll_buf, pinfo); + pollp = poll_buf; + } + poll_chars--; + return *pollp++; +} + +static void cpm_put_poll_char(struct uart_port *port, + unsigned char c) +{ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + static char ch[2]; + + ch[0] = (char)c; + cpm_uart_early_write(pinfo, ch, 1); +} +#endif /* CONFIG_CONSOLE_POLL */ + +static struct uart_ops cpm_uart_pops = { + .tx_empty = cpm_uart_tx_empty, + .set_mctrl = cpm_uart_set_mctrl, + .get_mctrl = cpm_uart_get_mctrl, + .stop_tx = cpm_uart_stop_tx, + .start_tx = cpm_uart_start_tx, + .stop_rx = cpm_uart_stop_rx, + .enable_ms = cpm_uart_enable_ms, + .break_ctl = cpm_uart_break_ctl, + .startup = cpm_uart_startup, + .shutdown = cpm_uart_shutdown, + .set_termios = cpm_uart_set_termios, + .type = cpm_uart_type, + .release_port = cpm_uart_release_port, + .request_port = cpm_uart_request_port, + .config_port = cpm_uart_config_port, + .verify_port = cpm_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = cpm_get_poll_char, + .poll_put_char = cpm_put_poll_char, +#endif +}; + +struct uart_cpm_port cpm_uart_ports[UART_NR]; + +static int cpm_uart_init_port(struct device_node *np, + struct uart_cpm_port *pinfo) +{ + const u32 *data; + void __iomem *mem, *pram; + int len; + int ret; + int i; + + data = of_get_property(np, "clock", NULL); + if (data) { + struct clk *clk = clk_get(NULL, (const char*)data); + if (!IS_ERR(clk)) + pinfo->clk = clk; + } + if (!pinfo->clk) { + data = of_get_property(np, "fsl,cpm-brg", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-brg property.\n", np->name); + return -EINVAL; + } + pinfo->brg = *data; + } + + data = of_get_property(np, "fsl,cpm-command", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-command property.\n", np->name); + return -EINVAL; + } + pinfo->command = *data; + + mem = of_iomap(np, 0); + if (!mem) + return -ENOMEM; + + if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") || + of_device_is_compatible(np, "fsl,cpm2-scc-uart")) { + pinfo->sccp = mem; + pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np); + } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") || + of_device_is_compatible(np, "fsl,cpm2-smc-uart")) { + pinfo->flags |= FLAG_SMC; + pinfo->smcp = mem; + pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np); + } else { + ret = -ENODEV; + goto out_mem; + } + + if (!pram) { + ret = -ENOMEM; + goto out_mem; + } + + pinfo->tx_nrfifos = TX_NUM_FIFO; + pinfo->tx_fifosize = TX_BUF_SIZE; + pinfo->rx_nrfifos = RX_NUM_FIFO; + pinfo->rx_fifosize = RX_BUF_SIZE; + + pinfo->port.uartclk = ppc_proc_freq; + pinfo->port.mapbase = (unsigned long)mem; + pinfo->port.type = PORT_CPM; + pinfo->port.ops = &cpm_uart_pops, + pinfo->port.iotype = UPIO_MEM; + pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; + spin_lock_init(&pinfo->port.lock); + + pinfo->port.irq = of_irq_to_resource(np, 0, NULL); + if (pinfo->port.irq == NO_IRQ) { + ret = -EINVAL; + goto out_pram; + } + + for (i = 0; i < NUM_GPIOS; i++) + pinfo->gpios[i] = of_get_gpio(np, i); + +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM + udbg_putc = NULL; +#endif + + return cpm_uart_request_port(&pinfo->port); + +out_pram: + cpm_uart_unmap_pram(pinfo, pram); +out_mem: + iounmap(mem); + return ret; +} + +#ifdef CONFIG_SERIAL_CPM_CONSOLE +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * Note that this is called with interrupts already disabled + */ +static void cpm_uart_console_write(struct console *co, const char *s, + u_int count) +{ + struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index]; + unsigned long flags; + int nolock = oops_in_progress; + + if (unlikely(nolock)) { + local_irq_save(flags); + } else { + spin_lock_irqsave(&pinfo->port.lock, flags); + } + + cpm_uart_early_write(pinfo, s, count); + + if (unlikely(nolock)) { + local_irq_restore(flags); + } else { + spin_unlock_irqrestore(&pinfo->port.lock, flags); + } +} + + +static int __init cpm_uart_console_setup(struct console *co, char *options) +{ + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + struct uart_cpm_port *pinfo; + struct uart_port *port; + + struct device_node *np = NULL; + int i = 0; + + if (co->index >= UART_NR) { + printk(KERN_ERR "cpm_uart: console index %d too high\n", + co->index); + return -ENODEV; + } + + do { + np = of_find_node_by_type(np, "serial"); + if (!np) + return -ENODEV; + + if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") && + !of_device_is_compatible(np, "fsl,cpm1-scc-uart") && + !of_device_is_compatible(np, "fsl,cpm2-smc-uart") && + !of_device_is_compatible(np, "fsl,cpm2-scc-uart")) + i--; + } while (i++ != co->index); + + pinfo = &cpm_uart_ports[co->index]; + + pinfo->flags |= FLAG_CONSOLE; + port = &pinfo->port; + + ret = cpm_uart_init_port(np, pinfo); + of_node_put(np); + if (ret) + return ret; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + } else { + if ((baud = uart_baudrate()) == -1) + baud = 9600; + } + + if (IS_SMC(pinfo)) { + out_be16(&pinfo->smcup->smc_brkcr, 0); + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); + } else { + out_be16(&pinfo->sccup->scc_brkcr, 0); + cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX); + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + } + + ret = cpm_uart_allocbuf(pinfo, 1); + + if (ret) + return ret; + + cpm_uart_initbd(pinfo); + + if (IS_SMC(pinfo)) + cpm_uart_init_smc(pinfo); + else + cpm_uart_init_scc(pinfo); + + uart_set_options(port, co, baud, parity, bits, flow); + cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); + + return 0; +} + +static struct uart_driver cpm_reg; +static struct console cpm_scc_uart_console = { + .name = "ttyCPM", + .write = cpm_uart_console_write, + .device = uart_console_device, + .setup = cpm_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &cpm_reg, +}; + +static int __init cpm_uart_console_init(void) +{ + register_console(&cpm_scc_uart_console); + return 0; +} + +console_initcall(cpm_uart_console_init); + +#define CPM_UART_CONSOLE &cpm_scc_uart_console +#else +#define CPM_UART_CONSOLE NULL +#endif + +static struct uart_driver cpm_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyCPM", + .dev_name = "ttyCPM", + .major = SERIAL_CPM_MAJOR, + .minor = SERIAL_CPM_MINOR, + .cons = CPM_UART_CONSOLE, + .nr = UART_NR, +}; + +static int probe_index; + +static int __devinit cpm_uart_probe(struct platform_device *ofdev, + const struct of_device_id *match) +{ + int index = probe_index++; + struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; + int ret; + + pinfo->port.line = index; + + if (index >= UART_NR) + return -ENODEV; + + dev_set_drvdata(&ofdev->dev, pinfo); + + /* initialize the device pointer for the port */ + pinfo->port.dev = &ofdev->dev; + + ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo); + if (ret) + return ret; + + return uart_add_one_port(&cpm_reg, &pinfo->port); +} + +static int __devexit cpm_uart_remove(struct platform_device *ofdev) +{ + struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); + return uart_remove_one_port(&cpm_reg, &pinfo->port); +} + +static struct of_device_id cpm_uart_match[] = { + { + .compatible = "fsl,cpm1-smc-uart", + }, + { + .compatible = "fsl,cpm1-scc-uart", + }, + { + .compatible = "fsl,cpm2-smc-uart", + }, + { + .compatible = "fsl,cpm2-scc-uart", + }, + {} +}; + +static struct of_platform_driver cpm_uart_driver = { + .driver = { + .name = "cpm_uart", + .owner = THIS_MODULE, + .of_match_table = cpm_uart_match, + }, + .probe = cpm_uart_probe, + .remove = cpm_uart_remove, + }; + +static int __init cpm_uart_init(void) +{ + int ret = uart_register_driver(&cpm_reg); + if (ret) + return ret; + + ret = of_register_platform_driver(&cpm_uart_driver); + if (ret) + uart_unregister_driver(&cpm_reg); + + return ret; +} + +static void __exit cpm_uart_exit(void) +{ + of_unregister_platform_driver(&cpm_uart_driver); + uart_unregister_driver(&cpm_reg); +} + +module_init(cpm_uart_init); +module_exit(cpm_uart_exit); + +MODULE_AUTHOR("Kumar Gala/Antoniou Pantelis"); +MODULE_DESCRIPTION("CPM SCC/SMC port driver $Revision: 0.01 $"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(SERIAL_CPM_MAJOR, SERIAL_CPM_MINOR); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c new file mode 100644 index 000000000000..3fc1d66e32c6 --- /dev/null +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c @@ -0,0 +1,138 @@ +/* + * linux/drivers/serial/cpm_uart.c + * + * Driver for CPM (SCC/SMC) serial ports; CPM1 definitions + * + * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) + * Pantelis Antoniou (panto@intracom.gr) (CPM1) + * + * Copyright (C) 2004 Freescale Semiconductor, Inc. + * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug + * + * 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 + +#include +#include +#include + +#include +#include + +#include + +#include "cpm_uart.h" + +/**************************************************************/ + +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + cpm_command(port->command, cmd); +} + +void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np) +{ + return of_iomap(np, 1); +} + +void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) +{ + iounmap(pram); +} + +/* + * Allocate DP-Ram and memory buffers. We need to allocate a transmit and + * receive buffer descriptors from dual port ram, and a character + * buffer area from host mem. If we are allocating for the console we need + * to do it from bootmem + */ +int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) +{ + int dpmemsz, memsz; + u8 *dp_mem; + unsigned long dp_offset; + u8 *mem_addr; + dma_addr_t dma_addr = 0; + + pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); + + dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); + dp_offset = cpm_dpalloc(dpmemsz, 8); + if (IS_ERR_VALUE(dp_offset)) { + printk(KERN_ERR + "cpm_uart_cpm1.c: could not allocate buffer descriptors\n"); + return -ENOMEM; + } + dp_mem = cpm_dpram_addr(dp_offset); + + memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); + if (is_con) { + /* was hostalloc but changed cause it blows away the */ + /* large tlb mapping when pinning the kernel area */ + mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); + dma_addr = (u32)cpm_dpram_phys(mem_addr); + } else + mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, + GFP_KERNEL); + + if (mem_addr == NULL) { + cpm_dpfree(dp_offset); + printk(KERN_ERR + "cpm_uart_cpm1.c: could not allocate coherent memory\n"); + return -ENOMEM; + } + + pinfo->dp_addr = dp_offset; + pinfo->mem_addr = mem_addr; /* virtual address*/ + pinfo->dma_addr = dma_addr; /* physical address*/ + pinfo->mem_size = memsz; + + pinfo->rx_buf = mem_addr; + pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos + * pinfo->rx_fifosize); + + pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; + pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; + + return 0; +} + +void cpm_uart_freebuf(struct uart_cpm_port *pinfo) +{ + dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * + pinfo->rx_fifosize) + + L1_CACHE_ALIGN(pinfo->tx_nrfifos * + pinfo->tx_fifosize), pinfo->mem_addr, + pinfo->dma_addr); + + cpm_dpfree(pinfo->dp_addr); +} diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h new file mode 100644 index 000000000000..10eecd6af6d4 --- /dev/null +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h @@ -0,0 +1,34 @@ +/* + * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h + * + * Driver for CPM (SCC/SMC) serial ports + * + * definitions for cpm1 + * + */ + +#ifndef CPM_UART_CPM1_H +#define CPM_UART_CPM1_H + +#include + +static inline void cpm_set_brg(int brg, int baud) +{ + cpm_setbrg(brg, baud); +} + +static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup) +{ + out_8(&sup->scc_genscc.scc_rfcr, SMC_EB); + out_8(&sup->scc_genscc.scc_tfcr, SMC_EB); +} + +static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up) +{ + out_8(&up->smc_rfcr, SMC_EB); + out_8(&up->smc_tfcr, SMC_EB); +} + +#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) + +#endif diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c new file mode 100644 index 000000000000..814ac006393f --- /dev/null +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c @@ -0,0 +1,174 @@ +/* + * linux/drivers/serial/cpm_uart_cpm2.c + * + * Driver for CPM (SCC/SMC) serial ports; CPM2 definitions + * + * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) + * Pantelis Antoniou (panto@intracom.gr) (CPM1) + * + * Copyright (C) 2004 Freescale Semiconductor, Inc. + * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug + * + * 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 + +#include +#include +#include +#include + +#include +#include + +#include "cpm_uart.h" + +/**************************************************************/ + +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + cpm_command(port->command, cmd); +} + +void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np) +{ + void __iomem *pram; + unsigned long offset; + struct resource res; + resource_size_t len; + + /* Don't remap parameter RAM if it has already been initialized + * during console setup. + */ + if (IS_SMC(port) && port->smcup) + return port->smcup; + else if (!IS_SMC(port) && port->sccup) + return port->sccup; + + if (of_address_to_resource(np, 1, &res)) + return NULL; + + len = resource_size(&res); + pram = ioremap(res.start, len); + if (!pram) + return NULL; + + if (!IS_SMC(port)) + return pram; + + if (len != 2) { + printk(KERN_WARNING "cpm_uart[%d]: device tree references " + "SMC pram, using boot loader/wrapper pram mapping. " + "Please fix your device tree to reference the pram " + "base register instead.\n", + port->port.line); + return pram; + } + + offset = cpm_dpalloc(PROFF_SMC_SIZE, 64); + out_be16(pram, offset); + iounmap(pram); + return cpm_muram_addr(offset); +} + +void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) +{ + if (!IS_SMC(port)) + iounmap(pram); +} + +/* + * Allocate DP-Ram and memory buffers. We need to allocate a transmit and + * receive buffer descriptors from dual port ram, and a character + * buffer area from host mem. If we are allocating for the console we need + * to do it from bootmem + */ +int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) +{ + int dpmemsz, memsz; + u8 __iomem *dp_mem; + unsigned long dp_offset; + u8 *mem_addr; + dma_addr_t dma_addr = 0; + + pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line); + + dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos); + dp_offset = cpm_dpalloc(dpmemsz, 8); + if (IS_ERR_VALUE(dp_offset)) { + printk(KERN_ERR + "cpm_uart_cpm.c: could not allocate buffer descriptors\n"); + return -ENOMEM; + } + + dp_mem = cpm_dpram_addr(dp_offset); + + memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); + if (is_con) { + mem_addr = kzalloc(memsz, GFP_NOWAIT); + dma_addr = virt_to_bus(mem_addr); + } + else + mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr, + GFP_KERNEL); + + if (mem_addr == NULL) { + cpm_dpfree(dp_offset); + printk(KERN_ERR + "cpm_uart_cpm.c: could not allocate coherent memory\n"); + return -ENOMEM; + } + + pinfo->dp_addr = dp_offset; + pinfo->mem_addr = mem_addr; + pinfo->dma_addr = dma_addr; + pinfo->mem_size = memsz; + + pinfo->rx_buf = mem_addr; + pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos + * pinfo->rx_fifosize); + + pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem; + pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; + + return 0; +} + +void cpm_uart_freebuf(struct uart_cpm_port *pinfo) +{ + dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos * + pinfo->rx_fifosize) + + L1_CACHE_ALIGN(pinfo->tx_nrfifos * + pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, + pinfo->dma_addr); + + cpm_dpfree(pinfo->dp_addr); +} diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h new file mode 100644 index 000000000000..7194c63dcf5f --- /dev/null +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h @@ -0,0 +1,34 @@ +/* + * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h + * + * Driver for CPM (SCC/SMC) serial ports + * + * definitions for cpm2 + * + */ + +#ifndef CPM_UART_CPM2_H +#define CPM_UART_CPM2_H + +#include + +static inline void cpm_set_brg(int brg, int baud) +{ + cpm_setbrg(brg, baud); +} + +static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup) +{ + out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB); +} + +static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up) +{ + out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB); +} + +#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) + +#endif diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c new file mode 100644 index 000000000000..bcc31f2140ac --- /dev/null +++ b/drivers/tty/serial/crisv10.c @@ -0,0 +1,4573 @@ +/* + * Serial port driver for the ETRAX 100LX chip + * + * Copyright (C) 1998-2007 Axis Communications AB + * + * Many, many authors. Based once upon a time on serial.c for 16x50. + * + */ + +static char *serial_version = "$Revision: 1.25 $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* non-arch dependent serial structures are in linux/serial.h */ +#include +/* while we keep our own stuff (struct e100_serial) in a local .h file */ +#include "crisv10.h" +#include +#include + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +#ifndef CONFIG_ETRAX_FAST_TIMER +#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER" +#endif +#endif + +#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ + (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0) +#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" +#endif + +#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) +#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" +#endif + +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in serial_compat.h + */ +#if defined(LOCAL_HEADERS) +#include "serial_compat.h" +#endif + +struct tty_driver *serial_driver; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +//#define SERIAL_DEBUG_INTR +//#define SERIAL_DEBUG_OPEN +//#define SERIAL_DEBUG_FLOW +//#define SERIAL_DEBUG_DATA +//#define SERIAL_DEBUG_THROTTLE +//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */ +//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */ + +/* Enable this to use serial interrupts to handle when you + expect the first received event on the serial port to + be an error, break or similar. Used to be able to flash IRMA + from eLinux */ +#define SERIAL_HANDLE_EARLY_ERRORS + +/* Currently 16 descriptors x 128 bytes = 2048 bytes */ +#define SERIAL_DESCR_BUF_SIZE 256 + +#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */ +#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE + +/* We don't want to load the system with massive fast timer interrupt + * on high baudrates so limit it to 250 us (4kHz) */ +#define MIN_FLUSH_TIME_USEC 250 + +/* Add an x here to log a lot of timer stuff */ +#define TIMERD(x) +/* Debug details of interrupt handling */ +#define DINTR1(x) /* irq on/off, errors */ +#define DINTR2(x) /* tx and rx */ +/* Debug flip buffer stuff */ +#define DFLIP(x) +/* Debug flow control and overview of data flow */ +#define DFLOW(x) +#define DBAUD(x) +#define DLOG_INT_TRIG(x) + +//#define DEBUG_LOG_INCLUDED +#ifndef DEBUG_LOG_INCLUDED +#define DEBUG_LOG(line, string, value) +#else +struct debug_log_info +{ + unsigned long time; + unsigned long timer_data; +// int line; + const char *string; + int value; +}; +#define DEBUG_LOG_SIZE 4096 + +struct debug_log_info debug_log[DEBUG_LOG_SIZE]; +int debug_log_pos = 0; + +#define DEBUG_LOG(_line, _string, _value) do { \ + if ((_line) == SERIAL_DEBUG_LINE) {\ + debug_log_func(_line, _string, _value); \ + }\ +}while(0) + +void debug_log_func(int line, const char *string, int value) +{ + if (debug_log_pos < DEBUG_LOG_SIZE) { + debug_log[debug_log_pos].time = jiffies; + debug_log[debug_log_pos].timer_data = *R_TIMER_DATA; +// debug_log[debug_log_pos].line = line; + debug_log[debug_log_pos].string = string; + debug_log[debug_log_pos].value = value; + debug_log_pos++; + } + /*printk(string, value);*/ +} +#endif + +#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS +/* Default number of timer ticks before flushing rx fifo + * When using "little data, low latency applications: use 0 + * When using "much data applications (PPP)" use ~5 + */ +#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 +#endif + +unsigned long timer_data_to_ns(unsigned long timer_data); + +static void change_speed(struct e100_serial *info); +static void rs_throttle(struct tty_struct * tty); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); +static int rs_write(struct tty_struct *tty, + const unsigned char *buf, int count); +#ifdef CONFIG_ETRAX_RS485 +static int e100_write_rs485(struct tty_struct *tty, + const unsigned char *buf, int count); +#endif +static int get_lsr_info(struct e100_serial *info, unsigned int *value); + + +#define DEF_BAUD 115200 /* 115.2 kbit/s */ +#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ +/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ +#define DEF_TX 0x80 /* or SERIAL_CTRL_B */ + +/* offsets from R_SERIALx_CTRL */ + +#define REG_DATA 0 +#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */ +#define REG_TR_DATA 0 +#define REG_STATUS 1 +#define REG_TR_CTRL 1 +#define REG_REC_CTRL 2 +#define REG_BAUD 3 +#define REG_XOFF 4 /* this is a 32 bit register */ + +/* The bitfields are the same for all serial ports */ +#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd) +#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail) +#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err) +#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err) +#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun) + +#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK) + +/* Values for info->errorcode */ +#define ERRCODE_SET_BREAK (TTY_BREAK) +#define ERRCODE_INSERT 0x100 +#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK) + +#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop; + +/* + * General note regarding the use of IO_* macros in this file: + * + * We will use the bits defined for DMA channel 6 when using various + * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are + * the same for all channels (which of course they are). + * + * We will also use the bits defined for serial port 0 when writing commands + * to the different ports, as these bits too are the same for all ports. + */ + + +/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */ +static const unsigned long e100_ser_int_mask = 0 +#ifdef CONFIG_ETRAX_SERIAL_PORT0 +| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready) +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT1 +| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready) +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT2 +| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready) +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT3 +| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready) +#endif +; +unsigned long r_alt_ser_baudrate_shadow = 0; + +/* this is the data for the four serial ports in the etrax100 */ +/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ +/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ + +static struct e100_serial rs_table[] = { + { .baud = DEF_BAUD, + .ioport = (unsigned char *)R_SERIAL0_CTRL, + .irq = 1U << 12, /* uses DMA 6 and 7 */ + .oclrintradr = R_DMA_CH6_CLR_INTR, + .ofirstadr = R_DMA_CH6_FIRST, + .ocmdadr = R_DMA_CH6_CMD, + .ostatusadr = R_DMA_CH6_STATUS, + .iclrintradr = R_DMA_CH7_CLR_INTR, + .ifirstadr = R_DMA_CH7_FIRST, + .icmdadr = R_DMA_CH7_CMD, + .idescradr = R_DMA_CH7_DESCR, + .flags = STD_FLAGS, + .rx_ctrl = DEF_RX, + .tx_ctrl = DEF_TX, + .iseteop = 2, + .dma_owner = dma_ser0, + .io_if = if_serial_0, +#ifdef CONFIG_ETRAX_SERIAL_PORT0 + .enabled = 1, +#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT + .dma_out_enabled = 1, + .dma_out_nbr = SER0_TX_DMA_NBR, + .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR, + .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_description = "serial 0 dma tr", +#else + .dma_out_enabled = 0, + .dma_out_nbr = UINT_MAX, + .dma_out_irq_nbr = 0, + .dma_out_irq_flags = 0, + .dma_out_irq_description = NULL, +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN + .dma_in_enabled = 1, + .dma_in_nbr = SER0_RX_DMA_NBR, + .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR, + .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_description = "serial 0 dma rec", +#else + .dma_in_enabled = 0, + .dma_in_nbr = UINT_MAX, + .dma_in_irq_nbr = 0, + .dma_in_irq_flags = 0, + .dma_in_irq_description = NULL, +#endif +#else + .enabled = 0, + .io_if_description = NULL, + .dma_out_enabled = 0, + .dma_in_enabled = 0 +#endif + +}, /* ttyS0 */ +#ifndef CONFIG_SVINTO_SIM + { .baud = DEF_BAUD, + .ioport = (unsigned char *)R_SERIAL1_CTRL, + .irq = 1U << 16, /* uses DMA 8 and 9 */ + .oclrintradr = R_DMA_CH8_CLR_INTR, + .ofirstadr = R_DMA_CH8_FIRST, + .ocmdadr = R_DMA_CH8_CMD, + .ostatusadr = R_DMA_CH8_STATUS, + .iclrintradr = R_DMA_CH9_CLR_INTR, + .ifirstadr = R_DMA_CH9_FIRST, + .icmdadr = R_DMA_CH9_CMD, + .idescradr = R_DMA_CH9_DESCR, + .flags = STD_FLAGS, + .rx_ctrl = DEF_RX, + .tx_ctrl = DEF_TX, + .iseteop = 3, + .dma_owner = dma_ser1, + .io_if = if_serial_1, +#ifdef CONFIG_ETRAX_SERIAL_PORT1 + .enabled = 1, + .io_if_description = "ser1", +#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT + .dma_out_enabled = 1, + .dma_out_nbr = SER1_TX_DMA_NBR, + .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR, + .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_description = "serial 1 dma tr", +#else + .dma_out_enabled = 0, + .dma_out_nbr = UINT_MAX, + .dma_out_irq_nbr = 0, + .dma_out_irq_flags = 0, + .dma_out_irq_description = NULL, +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN + .dma_in_enabled = 1, + .dma_in_nbr = SER1_RX_DMA_NBR, + .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR, + .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_description = "serial 1 dma rec", +#else + .dma_in_enabled = 0, + .dma_in_enabled = 0, + .dma_in_nbr = UINT_MAX, + .dma_in_irq_nbr = 0, + .dma_in_irq_flags = 0, + .dma_in_irq_description = NULL, +#endif +#else + .enabled = 0, + .io_if_description = NULL, + .dma_in_irq_nbr = 0, + .dma_out_enabled = 0, + .dma_in_enabled = 0 +#endif +}, /* ttyS1 */ + + { .baud = DEF_BAUD, + .ioport = (unsigned char *)R_SERIAL2_CTRL, + .irq = 1U << 4, /* uses DMA 2 and 3 */ + .oclrintradr = R_DMA_CH2_CLR_INTR, + .ofirstadr = R_DMA_CH2_FIRST, + .ocmdadr = R_DMA_CH2_CMD, + .ostatusadr = R_DMA_CH2_STATUS, + .iclrintradr = R_DMA_CH3_CLR_INTR, + .ifirstadr = R_DMA_CH3_FIRST, + .icmdadr = R_DMA_CH3_CMD, + .idescradr = R_DMA_CH3_DESCR, + .flags = STD_FLAGS, + .rx_ctrl = DEF_RX, + .tx_ctrl = DEF_TX, + .iseteop = 0, + .dma_owner = dma_ser2, + .io_if = if_serial_2, +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + .enabled = 1, + .io_if_description = "ser2", +#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT + .dma_out_enabled = 1, + .dma_out_nbr = SER2_TX_DMA_NBR, + .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR, + .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_description = "serial 2 dma tr", +#else + .dma_out_enabled = 0, + .dma_out_nbr = UINT_MAX, + .dma_out_irq_nbr = 0, + .dma_out_irq_flags = 0, + .dma_out_irq_description = NULL, +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN + .dma_in_enabled = 1, + .dma_in_nbr = SER2_RX_DMA_NBR, + .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR, + .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_description = "serial 2 dma rec", +#else + .dma_in_enabled = 0, + .dma_in_nbr = UINT_MAX, + .dma_in_irq_nbr = 0, + .dma_in_irq_flags = 0, + .dma_in_irq_description = NULL, +#endif +#else + .enabled = 0, + .io_if_description = NULL, + .dma_out_enabled = 0, + .dma_in_enabled = 0 +#endif + }, /* ttyS2 */ + + { .baud = DEF_BAUD, + .ioport = (unsigned char *)R_SERIAL3_CTRL, + .irq = 1U << 8, /* uses DMA 4 and 5 */ + .oclrintradr = R_DMA_CH4_CLR_INTR, + .ofirstadr = R_DMA_CH4_FIRST, + .ocmdadr = R_DMA_CH4_CMD, + .ostatusadr = R_DMA_CH4_STATUS, + .iclrintradr = R_DMA_CH5_CLR_INTR, + .ifirstadr = R_DMA_CH5_FIRST, + .icmdadr = R_DMA_CH5_CMD, + .idescradr = R_DMA_CH5_DESCR, + .flags = STD_FLAGS, + .rx_ctrl = DEF_RX, + .tx_ctrl = DEF_TX, + .iseteop = 1, + .dma_owner = dma_ser3, + .io_if = if_serial_3, +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + .enabled = 1, + .io_if_description = "ser3", +#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT + .dma_out_enabled = 1, + .dma_out_nbr = SER3_TX_DMA_NBR, + .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR, + .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_description = "serial 3 dma tr", +#else + .dma_out_enabled = 0, + .dma_out_nbr = UINT_MAX, + .dma_out_irq_nbr = 0, + .dma_out_irq_flags = 0, + .dma_out_irq_description = NULL, +#endif +#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN + .dma_in_enabled = 1, + .dma_in_nbr = SER3_RX_DMA_NBR, + .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR, + .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_description = "serial 3 dma rec", +#else + .dma_in_enabled = 0, + .dma_in_nbr = UINT_MAX, + .dma_in_irq_nbr = 0, + .dma_in_irq_flags = 0, + .dma_in_irq_description = NULL +#endif +#else + .enabled = 0, + .io_if_description = NULL, + .dma_out_enabled = 0, + .dma_in_enabled = 0 +#endif + } /* ttyS3 */ +#endif +}; + + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static struct fast_timer fast_timers[NR_PORTS]; +#endif + +#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY +#define PROCSTAT(x) x +struct ser_statistics_type { + int overrun_cnt; + int early_errors_cnt; + int ser_ints_ok_cnt; + int errors_cnt; + unsigned long int processing_flip; + unsigned long processing_flip_still_room; + unsigned long int timeout_flush_cnt; + int rx_dma_ints; + int tx_dma_ints; + int rx_tot; + int tx_tot; +}; + +static struct ser_statistics_type ser_stat[NR_PORTS]; + +#else + +#define PROCSTAT(x) + +#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ + +/* RS-485 */ +#if defined(CONFIG_ETRAX_RS485) +#ifdef CONFIG_ETRAX_FAST_TIMER +static struct fast_timer fast_timers_rs485[NR_PORTS]; +#endif +#if defined(CONFIG_ETRAX_RS485_ON_PA) +static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; +#endif +#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) +static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; +#endif +#endif + +/* Info and macros needed for each ports extra control/status signals. */ +#define E100_STRUCT_PORT(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (R_PORT_PA_DATA): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (R_PORT_PB_DATA):&dummy_ser[line])) + +#define E100_STRUCT_SHADOW(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (&port_pa_data_shadow): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (&port_pb_data_shadow):&dummy_ser[line])) +#define E100_STRUCT_MASK(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (1<= 0)? \ + (1< 3.3V to RS-232 driver -> -12V on RS-232 level + * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level + * + * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip + */ + +/* Output */ +#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) +/* Input */ +#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK) + +/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ +/* Is an output */ +#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask) + +/* Normally inputs */ +#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask) +#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask) + +/* Input */ +#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) + + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +static DEFINE_MUTEX(tmp_buf_mutex); + +/* 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; + int bits; + + /* calc. number of bits / data byte */ + /* databits + startbit and 1 stopbit */ + if ((cflags & CSIZE) == CS7) + bits = 9; + else + bits = 10; + + if (cflags & CSTOPB) /* 2 stopbits ? */ + bits++; + + if (cflags & PARENB) /* parity bit ? */ + bits++; + + /* calc timeout */ + info->char_time_usec = ((bits * 1000000) / info->baud) + 1; + info->flush_time_usec = 4*info->char_time_usec; + if (info->flush_time_usec < MIN_FLUSH_TIME_USEC) + info->flush_time_usec = MIN_FLUSH_TIME_USEC; + +} + +/* + * This function maps from the Bxxxx defines in asm/termbits.h into real + * baud rates. + */ + +static int +cflag_to_baud(unsigned int cflag) +{ + static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 }; + + static int ext_baud_table[] = { + 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000, + 0, 0, 0, 0, 0, 0, 0, 0 }; + + if (cflag & CBAUDEX) + return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; + else + return baud_table[cflag & CBAUD]; +} + +/* and this maps to an etrax100 hardware baud constant */ + +static unsigned char +cflag_to_etrax_baud(unsigned int cflag) +{ + char retval; + + static char baud_table[] = { + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; + + static char ext_baud_table[] = { + -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 }; + + if (cflag & CBAUDEX) + retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; + else + retval = baud_table[cflag & CBAUD]; + + if (retval < 0) { + printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); + retval = 5; /* choose default 9600 instead */ + } + + return retval | (retval << 4); /* choose same for both TX and RX */ +} + + +/* Various static support functions */ + +/* Functions to set or clear DTR/RTS on the requested line */ +/* It is complicated by the fact that RTS is a serial port register, while + * DTR might not be implemented in the HW at all, and if it is, it can be on + * any general port. + */ + + +static inline void +e100_dtr(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + unsigned char mask = e100_modem_pins[info->line].dtr_mask; + +#ifdef SERIAL_DEBUG_IO + printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); + printk("ser%i shadow before 0x%02X get: %i\n", + info->line, *e100_modem_pins[info->line].dtr_shadow, + E100_DTR_GET(info)); +#endif + /* DTR is active low */ + { + unsigned long flags; + + local_irq_save(flags); + *e100_modem_pins[info->line].dtr_shadow &= ~mask; + *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; + local_irq_restore(flags); + } + +#ifdef SERIAL_DEBUG_IO + printk("ser%i shadow after 0x%02X get: %i\n", + info->line, *e100_modem_pins[info->line].dtr_shadow, + E100_DTR_GET(info)); +#endif +#endif +} + +/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive + * 0=0V , 1=3.3V + */ +static inline void +e100_rts(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + unsigned long flags; + local_irq_save(flags); + info->rx_ctrl &= ~E100_RTS_MASK; + info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ + info->ioport[REG_REC_CTRL] = info->rx_ctrl; + local_irq_restore(flags); +#ifdef SERIAL_DEBUG_IO + printk("ser%i rts %i\n", info->line, set); +#endif +#endif +} + + +/* If this behaves as a modem, RI and CD is an output */ +static inline void +e100_ri_out(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + /* RI is active low */ + { + unsigned char mask = e100_modem_pins[info->line].ri_mask; + unsigned long flags; + + local_irq_save(flags); + *e100_modem_pins[info->line].ri_shadow &= ~mask; + *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; + local_irq_restore(flags); + } +#endif +} +static inline void +e100_cd_out(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + /* CD is active low */ + { + unsigned char mask = e100_modem_pins[info->line].cd_mask; + unsigned long flags; + + local_irq_save(flags); + *e100_modem_pins[info->line].cd_shadow &= ~mask; + *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; + local_irq_restore(flags); + } +#endif +} + +static inline void +e100_disable_rx(struct e100_serial *info) +{ +#ifndef CONFIG_SVINTO_SIM + /* disable the receiver */ + info->ioport[REG_REC_CTRL] = + (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); +#endif +} + +static inline void +e100_enable_rx(struct e100_serial *info) +{ +#ifndef CONFIG_SVINTO_SIM + /* enable the receiver */ + info->ioport[REG_REC_CTRL] = + (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); +#endif +} + +/* the rx DMA uses both the dma_descr and the dma_eop interrupts */ + +static inline void +e100_disable_rxdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("rxdma_irq(%d): 0\n",info->line); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line)); + *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3); +} + +static inline void +e100_enable_rxdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("rxdma_irq(%d): 1\n",info->line); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line)); + *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3); +} + +/* the tx DMA uses only dma_descr interrupt */ + +static void e100_disable_txdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("txdma_irq(%d): 0\n",info->line); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line)); + *R_IRQ_MASK2_CLR = info->irq; +} + +static void e100_enable_txdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("txdma_irq(%d): 1\n",info->line); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line)); + *R_IRQ_MASK2_SET = info->irq; +} + +static void e100_disable_txdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + /* Disable output DMA channel for the serial port in question + * ( set to something other than serialX) + */ + local_irq_save(flags); + DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line)); + if (info->line == 0) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) == + IO_STATE(R_GEN_CONFIG, dma6, serial0)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); + } + } else if (info->line == 1) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) == + IO_STATE(R_GEN_CONFIG, dma8, serial1)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); + } + } else if (info->line == 2) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) == + IO_STATE(R_GEN_CONFIG, dma2, serial2)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); + } + } else if (info->line == 3) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) == + IO_STATE(R_GEN_CONFIG, dma4, serial3)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); + } + } + *R_GEN_CONFIG = genconfig_shadow; + local_irq_restore(flags); +} + + +static void e100_enable_txdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + local_irq_save(flags); + DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line)); + /* Enable output DMA channel for the serial port in question */ + if (info->line == 0) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); + } else if (info->line == 1) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); + } else if (info->line == 2) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); + } else if (info->line == 3) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); + } + *R_GEN_CONFIG = genconfig_shadow; + local_irq_restore(flags); +} + +static void e100_disable_rxdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + /* Disable input DMA channel for the serial port in question + * ( set to something other than serialX) + */ + local_irq_save(flags); + if (info->line == 0) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) == + IO_STATE(R_GEN_CONFIG, dma7, serial0)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused); + } + } else if (info->line == 1) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) == + IO_STATE(R_GEN_CONFIG, dma9, serial1)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb); + } + } else if (info->line == 2) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) == + IO_STATE(R_GEN_CONFIG, dma3, serial2)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); + } + } else if (info->line == 3) { + if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) == + IO_STATE(R_GEN_CONFIG, dma5, serial3)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); + } + } + *R_GEN_CONFIG = genconfig_shadow; + local_irq_restore(flags); +} + + +static void e100_enable_rxdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + local_irq_save(flags); + /* Enable input DMA channel for the serial port in question */ + if (info->line == 0) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0); + } else if (info->line == 1) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1); + } else if (info->line == 2) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2); + } else if (info->line == 3) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3); + } + *R_GEN_CONFIG = genconfig_shadow; + local_irq_restore(flags); +} + +#ifdef SERIAL_HANDLE_EARLY_ERRORS +/* in order to detect and fix errors on the first byte + we have to use the serial interrupts as well. */ + +static inline void +e100_disable_serial_data_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("ser_irq(%d): 0\n",info->line); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line)); + *R_IRQ_MASK1_CLR = (1U << (8+2*info->line)); +} + +static inline void +e100_enable_serial_data_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("ser_irq(%d): 1\n",info->line); + printk("**** %d = %d\n", + (8+2*info->line), + (1U << (8+2*info->line))); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line)); + *R_IRQ_MASK1_SET = (1U << (8+2*info->line)); +} +#endif + +static inline void +e100_disable_serial_tx_ready_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("ser_tx_irq(%d): 0\n",info->line); +#endif + DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line)); + *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line)); +} + +static inline void +e100_enable_serial_tx_ready_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("ser_tx_irq(%d): 1\n",info->line); + printk("**** %d = %d\n", + (8+1+2*info->line), + (1U << (8+1+2*info->line))); +#endif + DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line)); + *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line)); +} + +static inline void e100_enable_rx_irq(struct e100_serial *info) +{ + if (info->uses_dma_in) + e100_enable_rxdma_irq(info); + else + e100_enable_serial_data_irq(info); +} +static inline void e100_disable_rx_irq(struct e100_serial *info) +{ + if (info->uses_dma_in) + e100_disable_rxdma_irq(info); + else + e100_disable_serial_data_irq(info); +} + +#if defined(CONFIG_ETRAX_RS485) +/* Enable RS-485 mode on selected port. This is UGLY. */ +static int +e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + +#if defined(CONFIG_ETRAX_RS485_ON_PA) + *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); +#endif +#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, + rs485_port_g_bit, 1); +#endif +#if defined(CONFIG_ETRAX_RS485_LTC1387) + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, + CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, + CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); +#endif + + info->rs485 = *r; + + /* Maximum delay before RTS equal to 1000 */ + if (info->rs485.delay_rts_before_send >= 1000) + info->rs485.delay_rts_before_send = 1000; + +/* printk("rts: on send = %i, after = %i, enabled = %i", + info->rs485.rts_on_send, + info->rs485.rts_after_sent, + info->rs485.enabled + ); +*/ + return 0; +} + +static int +e100_write_rs485(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + int old_value = (info->rs485.flags) & SER_RS485_ENABLED; + + /* rs485 is always implicitly enabled if we're using the ioctl() + * but it doesn't have to be set in the serial_rs485 + * (to be backward compatible with old apps) + * So we store, set and restore it. + */ + info->rs485.flags |= SER_RS485_ENABLED; + /* rs_write now deals with RS485 if enabled */ + count = rs_write(tty, buf, count); + if (!old_value) + info->rs485.flags &= ~(SER_RS485_ENABLED); + return count; +} + +#ifdef CONFIG_ETRAX_FAST_TIMER +/* Timer function to toggle RTS when using FAST_TIMER */ +static void rs485_toggle_rts_timer_function(unsigned long data) +{ + struct e100_serial *info = (struct e100_serial *)data; + + fast_timers_rs485[info->line].function = NULL; + e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_enable_rx(info); + e100_enable_rx_irq(info); +#endif +} +#endif +#endif /* CONFIG_ETRAX_RS485 */ + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter using the XOFF registers, as necessary. + * ------------------------------------------------------------ + */ + +static void +rs_stop(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + if (info) { + unsigned long flags; + unsigned long xoff; + + local_irq_save(flags); + DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n", + CIRC_CNT(info->xmit.head, + info->xmit.tail,SERIAL_XMIT_SIZE))); + + 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 ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; + local_irq_restore(flags); + } +} + +static void +rs_start(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + if (info) { + unsigned long flags; + unsigned long xoff; + + local_irq_save(flags); + DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n", + CIRC_CNT(info->xmit.head, + 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 ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; + if (!info->uses_dma_out && + info->xmit.head != info->xmit.tail && info->xmit.buf) + e100_enable_serial_tx_ready_irq(info); + + local_irq_restore(flags); + } +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static void rs_sched_event(struct e100_serial *info, int event) +{ + if (info->event & (1 << event)) + return; + info->event |= 1 << event; + schedule_work(&info->work); +} + +/* The output DMA channel is free - use it to send as many chars as possible + * NOTES: + * We don't pay attention to info->x_char, which means if the TTY wants to + * use XON/XOFF it will set info->x_char but we won't send any X char! + * + * To implement this, we'd just start a DMA send of 1 byte pointing at a + * buffer containing the X char, and skip updating xmit. We'd also have to + * check if the last sent char was the X char when we enter this function + * the next time, to avoid updating xmit with the sent X value. + */ + +static void +transmit_chars_dma(struct e100_serial *info) +{ + unsigned int c, sentl; + struct etrax_dma_descr *descr; + +#ifdef CONFIG_SVINTO_SIM + /* This will output too little if tail is not 0 always since + * we don't reloop to send the other part. Anyway this SHOULD be a + * no-op - transmit_chars_dma would never really be called during sim + * since rs_write does not write into the xmit buffer then. + */ + if (info->xmit.tail) + printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); + if (info->xmit.head != info->xmit.tail) { + SIMCOUT(info->xmit.buf + info->xmit.tail, + CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE)); + info->xmit.head = info->xmit.tail; /* move back head */ + info->tr_running = 0; + } + return; +#endif + /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + +#ifdef SERIAL_DEBUG_INTR + if (info->line == SERIAL_DEBUG_LINE) + printk("tc\n"); +#endif + if (!info->tr_running) { + /* weirdo... we shouldn't get here! */ + printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n"); + return; + } + + descr = &info->tr_descr; + + /* first get the amount of bytes sent during the last DMA transfer, + and update xmit accordingly */ + + /* if the stop bit was not set, all data has been sent */ + if (!(descr->status & d_stop)) { + sentl = descr->sw_len; + } else + /* otherwise we find the amount of data sent here */ + sentl = descr->hw_len; + + DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl)); + + /* update stats */ + info->icount.tx += sentl; + + /* update xmit buffer */ + info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1); + + /* if there is only a few chars left in the buf, wake up the blocked + write if any */ + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + + /* find out the largest amount of consecutive bytes we want to send now */ + + c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + + /* Don't send all in one DMA transfer - divide it so we wake up + * application before all is sent + */ + + if (c >= 4*WAKEUP_CHARS) + c = c/2; + + if (c <= 0) { + /* our job here is done, don't schedule any new DMA transfer */ + info->tr_running = 0; + +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) + if (info->rs485.flags & SER_RS485_ENABLED) { + /* Set a short timer to toggle RTS */ + start_one_shot_timer(&fast_timers_rs485[info->line], + rs485_toggle_rts_timer_function, + (unsigned long)info, + info->char_time_usec*2, + "RS-485"); + } +#endif /* RS485 */ + return; + } + + /* ok we can schedule a dma send of c chars starting at info->xmit.tail */ + /* set up the descriptor correctly for output */ + DFLOW(DEBUG_LOG(info->line, "TX %i\n", c)); + descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */ + descr->sw_len = c; + descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail); + descr->status = 0; + + *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */ + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); + + /* DMA is now running (hopefully) */ +} /* transmit_chars_dma */ + +static void +start_transmit(struct e100_serial *info) +{ +#if 0 + if (info->line == SERIAL_DEBUG_LINE) + printk("x\n"); +#endif + + info->tr_descr.sw_len = 0; + info->tr_descr.hw_len = 0; + info->tr_descr.status = 0; + info->tr_running = 1; + if (info->uses_dma_out) + transmit_chars_dma(info); + else + e100_enable_serial_tx_ready_irq(info); +} /* start_transmit */ + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static int serial_fast_timer_started = 0; +static int serial_fast_timer_expired = 0; +static void flush_timeout_function(unsigned long data); +#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\ + unsigned long timer_flags; \ + local_irq_save(timer_flags); \ + if (fast_timers[info->line].function == NULL) { \ + serial_fast_timer_started++; \ + TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ + TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ + start_one_shot_timer(&fast_timers[info->line], \ + flush_timeout_function, \ + (unsigned long)info, \ + (usec), \ + string); \ + } \ + else { \ + TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \ + } \ + local_irq_restore(timer_flags); \ +} +#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec) + +#else +#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) +#define START_FLUSH_FAST_TIMER(info, string) +#endif + +static struct etrax_recv_buffer * +alloc_recv_buffer(unsigned int size) +{ + struct etrax_recv_buffer *buffer; + + if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + return NULL; + + buffer->next = NULL; + buffer->length = 0; + buffer->error = TTY_NORMAL; + + return buffer; +} + +static void +append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) +{ + unsigned long flags; + + local_irq_save(flags); + + if (!info->first_recv_buffer) + info->first_recv_buffer = buffer; + else + info->last_recv_buffer->next = buffer; + + info->last_recv_buffer = buffer; + + info->recv_cnt += buffer->length; + if (info->recv_cnt > info->max_recv_cnt) + info->max_recv_cnt = info->recv_cnt; + + local_irq_restore(flags); +} + +static int +add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) +{ + struct etrax_recv_buffer *buffer; + if (info->uses_dma_in) { + if (!(buffer = alloc_recv_buffer(4))) + return 0; + + buffer->length = 1; + buffer->error = flag; + buffer->buffer[0] = data; + + append_recv_buffer(info, buffer); + + info->icount.rx++; + } else { + struct tty_struct *tty = info->port.tty; + tty_insert_flip_char(tty, data, flag); + info->icount.rx++; + } + + return 1; +} + +static unsigned int handle_descr_data(struct e100_serial *info, + struct etrax_dma_descr *descr, + unsigned int recvl) +{ + struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; + + if (info->recv_cnt + recvl > 65536) { + printk(KERN_CRIT + "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl); + return 0; + } + + buffer->length = recvl; + + if (info->errorcode == ERRCODE_SET_BREAK) + buffer->error = TTY_BREAK; + info->errorcode = 0; + + append_recv_buffer(info, buffer); + + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic("%s: Failed to allocate memory for receive buffer!\n", __func__); + + descr->buf = virt_to_phys(buffer->buffer); + + return recvl; +} + +static unsigned int handle_all_descr_data(struct e100_serial *info) +{ + struct etrax_dma_descr *descr; + unsigned int recvl; + unsigned int ret = 0; + + while (1) + { + descr = &info->rec_descr[info->cur_rec_descr]; + + if (descr == phys_to_virt(*info->idescradr)) + break; + + if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS) + info->cur_rec_descr = 0; + + /* find out how many bytes were read */ + + /* if the eop bit was not set, all data has been received */ + if (!(descr->status & d_eop)) { + recvl = descr->sw_len; + } else { + /* otherwise we find the amount of data received here */ + recvl = descr->hw_len; + } + + /* Reset the status information */ + descr->status = 0; + + DFLOW( DEBUG_LOG(info->line, "RX %lu\n", recvl); + if (info->port.tty->stopped) { + unsigned char *buf = phys_to_virt(descr->buf); + DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]); + DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]); + DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]); + } + ); + + /* update stats */ + info->icount.rx += recvl; + + ret += handle_descr_data(info, descr, recvl); + } + + return ret; +} + +static void receive_chars_dma(struct e100_serial *info) +{ + struct tty_struct *tty; + unsigned char rstat; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + return; +#endif + + /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + + tty = info->port.tty; + if (!tty) /* Something wrong... */ + return; + +#ifdef SERIAL_HANDLE_EARLY_ERRORS + if (info->uses_dma_in) + e100_enable_serial_data_irq(info); +#endif + + if (info->errorcode == ERRCODE_INSERT_BREAK) + add_char_and_flag(info, '\0', TTY_BREAK); + + handle_all_descr_data(info); + + /* Read the status register to detect errors */ + rstat = info->ioport[REG_STATUS]; + if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { + DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat)); + } + + if (rstat & SER_ERROR_MASK) { + /* If we got an error, we must reset it by reading the + * data_in field + */ + unsigned char data = info->ioport[REG_DATA]; + + PROCSTAT(ser_stat[info->line].errors_cnt++); + DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + + if (rstat & SER_PAR_ERR_MASK) + add_char_and_flag(info, data, TTY_PARITY); + else if (rstat & SER_OVERRUN_MASK) + add_char_and_flag(info, data, TTY_OVERRUN); + else if (rstat & SER_FRAMING_ERR_MASK) + add_char_and_flag(info, data, TTY_FRAME); + } + + START_FLUSH_FAST_TIMER(info, "receive_chars"); + + /* Restart the receiving DMA */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); +} + +static int start_recv_dma(struct e100_serial *info) +{ + struct etrax_dma_descr *descr = info->rec_descr; + struct etrax_recv_buffer *buffer; + int i; + + /* Set up the receiving descriptors */ + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic("%s: Failed to allocate memory for receive buffer!\n", __func__); + + descr[i].ctrl = d_int; + descr[i].buf = virt_to_phys(buffer->buffer); + descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; + descr[i].hw_len = 0; + descr[i].status = 0; + descr[i].next = virt_to_phys(&descr[i+1]); + } + + /* Link the last descriptor to the first */ + descr[i-1].next = virt_to_phys(&descr[0]); + + /* Start with the first descriptor in the list */ + info->cur_rec_descr = 0; + + /* Start the DMA */ + *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]); + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); + + /* Input DMA should be running now */ + return 1; +} + +static void +start_receive(struct e100_serial *info) +{ +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + return; +#endif + if (info->uses_dma_in) { + /* reset the input dma channel to be sure it works */ + + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + start_recv_dma(info); + } +} + + +/* the bits in the MASK2 register are laid out like this: + DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR + where I is the input channel and O is the output channel for the port. + info->irq is the bit number for the DMAO_DESCR so to check the others we + shift info->irq to the left. +*/ + +/* dma output channel interrupt handler + this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or + DMA8(ser1) when they have finished a descriptor with the intr flag set. +*/ + +static irqreturn_t +tr_interrupt(int irq, void *dev_id) +{ + struct e100_serial *info; + unsigned long ireg; + int i; + int handled = 0; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + { + const char *s = "What? tr_interrupt in simulator??\n"; + SIMCOUT(s,strlen(s)); + } + return IRQ_HANDLED; +#endif + + /* find out the line that caused this irq and get it from rs_table */ + + ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ + + for (i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + if (!info->enabled || !info->uses_dma_out) + continue; + /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ + if (ireg & info->irq) { + handled = 1; + /* we can send a new dma bunch. make it so. */ + DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i)); + /* Read jiffies_usec first, + * we want this time to be as late as possible + */ + PROCSTAT(ser_stat[info->line].tx_dma_ints++); + info->last_tx_active_usec = GET_JIFFIES_USEC(); + info->last_tx_active = jiffies; + transmit_chars_dma(info); + } + + /* FIXME: here we should really check for a change in the + status lines and if so call status_handle(info) */ + } + return IRQ_RETVAL(handled); +} /* tr_interrupt */ + +/* dma input channel interrupt handler */ + +static irqreturn_t +rec_interrupt(int irq, void *dev_id) +{ + struct e100_serial *info; + unsigned long ireg; + int i; + int handled = 0; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + { + const char *s = "What? rec_interrupt in simulator??\n"; + SIMCOUT(s,strlen(s)); + } + return IRQ_HANDLED; +#endif + + /* find out the line that caused this irq and get it from rs_table */ + + ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ + + for (i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + if (!info->enabled || !info->uses_dma_in) + continue; + /* check for both dma_eop and dma_descr for the input dma channel */ + if (ireg & ((info->irq << 2) | (info->irq << 3))) { + handled = 1; + /* we have received something */ + receive_chars_dma(info); + } + + /* FIXME: here we should really check for a change in the + status lines and if so call status_handle(info) */ + } + return IRQ_RETVAL(handled); +} /* rec_interrupt */ + +static int force_eop_if_needed(struct e100_serial *info) +{ + /* We check data_avail bit to determine if data has + * arrived since last time + */ + unsigned char rstat = info->ioport[REG_STATUS]; + + /* error or datavail? */ + if (rstat & SER_ERROR_MASK) { + /* Some error has occurred. If there has been valid data, an + * EOP interrupt will be made automatically. If no data, the + * normal ser_interrupt should be enabled and handle it. + * So do nothing! + */ + DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", + rstat | (info->line << 8)); + return 0; + } + + if (rstat & SER_DATA_AVAIL_MASK) { + /* Ok data, no error, count it */ + TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", + rstat | (info->line << 8))); + /* Read data to clear status flags */ + (void)info->ioport[REG_DATA]; + + info->forced_eop = 0; + START_FLUSH_FAST_TIMER(info, "magic"); + return 0; + } + + /* hit the timeout, force an EOP for the input + * dma channel if we haven't already + */ + if (!info->forced_eop) { + info->forced_eop = 1; + PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); + TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); + FORCE_EOP(info); + } + + return 1; +} + +static void flush_to_flip_buffer(struct e100_serial *info) +{ + struct tty_struct *tty; + struct etrax_recv_buffer *buffer; + unsigned long flags; + + local_irq_save(flags); + tty = info->port.tty; + + if (!tty) { + local_irq_restore(flags); + return; + } + + while ((buffer = info->first_recv_buffer) != NULL) { + unsigned int count = buffer->length; + + tty_insert_flip_string(tty, buffer->buffer, count); + info->recv_cnt -= count; + + if (count == buffer->length) { + info->first_recv_buffer = buffer->next; + kfree(buffer); + } else { + buffer->length -= count; + memmove(buffer->buffer, buffer->buffer + count, buffer->length); + buffer->error = TTY_NORMAL; + } + } + + if (!info->first_recv_buffer) + info->last_recv_buffer = NULL; + + local_irq_restore(flags); + + /* This includes a check for low-latency */ + tty_flip_buffer_push(tty); +} + +static void check_flush_timeout(struct e100_serial *info) +{ + /* Flip what we've got (if we can) */ + flush_to_flip_buffer(info); + + /* We might need to flip later, but not to fast + * since the system is busy processing input... */ + if (info->first_recv_buffer) + START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000); + + /* Force eop last, since data might have come while we're processing + * and if we started the slow timer above, we won't start a fast + * below. + */ + force_eop_if_needed(info); +} + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static void flush_timeout_function(unsigned long data) +{ + struct e100_serial *info = (struct e100_serial *)data; + + fast_timers[info->line].function = NULL; + serial_fast_timer_expired++; + TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); + TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); + check_flush_timeout(info); +} + +#else + +/* dma fifo/buffer timeout handler + forces an end-of-packet for the dma input channel if no chars + have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. +*/ + +static struct timer_list flush_timer; + +static void +timed_flush_handler(unsigned long ptr) +{ + struct e100_serial *info; + int i; + +#ifdef CONFIG_SVINTO_SIM + return; +#endif + + for (i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + if (info->uses_dma_in) + check_flush_timeout(info); + } + + /* restart flush timer */ + mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); +} +#endif + +#ifdef SERIAL_HANDLE_EARLY_ERRORS + +/* If there is an error (ie break) when the DMA is running and + * there are no bytes in the fifo the DMA is stopped and we get no + * eop interrupt. Thus we have to monitor the first bytes on a DMA + * transfer, and if it is without error we can turn the serial + * interrupts off. + */ + +/* +BREAK handling on ETRAX 100: +ETRAX will generate interrupt although there is no stop bit between the +characters. + +Depending on how long the break sequence is, the end of the breaksequence +will look differently: +| indicates start/end of a character. + +B= Break character (0x00) with framing error. +E= Error byte with parity error received after B characters. +F= "Faked" valid byte received immediately after B characters. +V= Valid byte + +1. + B BL ___________________________ V +.._|__________|__________| |valid data | + +Multiple frame errors with data == 0x00 (B), +the timing matches up "perfectly" so no extra ending char is detected. +The RXD pin is 1 in the last interrupt, in that case +we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really +know if another byte will come and this really is case 2. below +(e.g F=0xFF or 0xFE) +If RXD pin is 0 we can expect another character (see 2. below). + + +2. + + B B E or F__________________..__ V +.._|__________|__________|______ | |valid data + "valid" or + parity error + +Multiple frame errors with data == 0x00 (B), +but the part of the break trigs is interpreted as a start bit (and possibly +some 0 bits followed by a number of 1 bits and a stop bit). +Depending on parity settings etc. this last character can be either +a fake "valid" char (F) or have a parity error (E). + +If the character is valid it will be put in the buffer, +we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt +will set the flags so the tty will handle it, +if it's an error byte it will not be put in the buffer +and we set info->errorcode = ERRCODE_INSERT_BREAK. + +To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp +of the last faulty char (B) and compares it with the current time: +If the time elapsed time is less then 2*char_time_usec we will assume +it's a faked F char and not a Valid char and set +info->errorcode = ERRCODE_SET_BREAK. + +Flaws in the above solution: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We use the timer to distinguish a F character from a V character, +if a V character is to close after the break we might make the wrong decision. + +TODO: The break will be delayed until an F or V character is received. + +*/ + +static +struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) +{ + unsigned long data_read; + struct tty_struct *tty = info->port.tty; + + if (!tty) { + printk("!NO TTY!\n"); + return info; + } + + /* Read data and status at the same time */ + data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); +more_data: + if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) { + DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); + } + DINTR2(DEBUG_LOG(info->line, "ser_rx %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read))); + + if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) | + IO_MASK(R_SERIAL0_READ, par_err) | + IO_MASK(R_SERIAL0_READ, overrun) )) { + /* An error */ + info->last_rx_active_usec = GET_JIFFIES_USEC(); + info->last_rx_active = jiffies; + DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read)); + DLOG_INT_TRIG( + if (!log_int_trig1_pos) { + log_int_trig1_pos = log_int_pos; + log_int(rdpc(), 0, 0); + } + ); + + + if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) && + (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) { + /* Most likely a break, but we get interrupts over and + * over again. + */ + + if (!info->break_detected_cnt) { + DEBUG_LOG(info->line, "#BRK start\n", 0); + } + if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) { + /* The RX pin is high now, so the break + * must be over, but.... + * we can't really know if we will get another + * last byte ending the break or not. + * And we don't know if the byte (if any) will + * have an error or look valid. + */ + DEBUG_LOG(info->line, "# BL BRK\n", 0); + info->errorcode = ERRCODE_INSERT_BREAK; + } + info->break_detected_cnt++; + } else { + /* The error does not look like a break, but could be + * the end of one + */ + if (info->break_detected_cnt) { + DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); + info->errorcode = ERRCODE_INSERT_BREAK; + } else { + unsigned char data = IO_EXTRACT(R_SERIAL0_READ, + data_in, data_read); + char flag = TTY_NORMAL; + if (info->errorcode == ERRCODE_INSERT_BREAK) { + struct tty_struct *tty = info->port.tty; + tty_insert_flip_char(tty, 0, flag); + info->icount.rx++; + } + + if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) { + info->icount.parity++; + flag = TTY_PARITY; + } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) { + info->icount.overrun++; + flag = TTY_OVERRUN; + } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) { + info->icount.frame++; + flag = TTY_FRAME; + } + tty_insert_flip_char(tty, data, flag); + info->errorcode = 0; + } + info->break_detected_cnt = 0; + } + } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { + /* No error */ + DLOG_INT_TRIG( + if (!log_int_trig1_pos) { + if (log_int_pos >= log_int_size) { + log_int_pos = 0; + } + log_int_trig0_pos = log_int_pos; + log_int(rdpc(), 0, 0); + } + ); + tty_insert_flip_char(tty, + IO_EXTRACT(R_SERIAL0_READ, data_in, data_read), + TTY_NORMAL); + } else { + DEBUG_LOG(info->line, "ser_rx int but no data_avail %08lX\n", data_read); + } + + + info->icount.rx++; + data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); + if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { + DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)); + goto more_data; + } + + tty_flip_buffer_push(info->port.tty); + return info; +} + +static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) +{ + unsigned char rstat; + +#ifdef SERIAL_DEBUG_INTR + printk("Interrupt from serport %d\n", i); +#endif +/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ + if (!info->uses_dma_in) { + return handle_ser_rx_interrupt_no_dma(info); + } + /* DMA is used */ + rstat = info->ioport[REG_STATUS]; + if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { + DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); + } + + if (rstat & SER_ERROR_MASK) { + unsigned char data; + + info->last_rx_active_usec = GET_JIFFIES_USEC(); + info->last_rx_active = jiffies; + /* If we got an error, we must reset it by reading the + * data_in field + */ + data = info->ioport[REG_DATA]; + DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data)); + DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat)); + if (!data && (rstat & SER_FRAMING_ERR_MASK)) { + /* Most likely a break, but we get interrupts over and + * over again. + */ + + if (!info->break_detected_cnt) { + DEBUG_LOG(info->line, "#BRK start\n", 0); + } + if (rstat & SER_RXD_MASK) { + /* The RX pin is high now, so the break + * must be over, but.... + * we can't really know if we will get another + * last byte ending the break or not. + * And we don't know if the byte (if any) will + * have an error or look valid. + */ + DEBUG_LOG(info->line, "# BL BRK\n", 0); + info->errorcode = ERRCODE_INSERT_BREAK; + } + info->break_detected_cnt++; + } else { + /* The error does not look like a break, but could be + * the end of one + */ + if (info->break_detected_cnt) { + DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); + info->errorcode = ERRCODE_INSERT_BREAK; + } else { + if (info->errorcode == ERRCODE_INSERT_BREAK) { + info->icount.brk++; + add_char_and_flag(info, '\0', TTY_BREAK); + } + + if (rstat & SER_PAR_ERR_MASK) { + info->icount.parity++; + add_char_and_flag(info, data, TTY_PARITY); + } else if (rstat & SER_OVERRUN_MASK) { + info->icount.overrun++; + add_char_and_flag(info, data, TTY_OVERRUN); + } else if (rstat & SER_FRAMING_ERR_MASK) { + info->icount.frame++; + add_char_and_flag(info, data, TTY_FRAME); + } + + info->errorcode = 0; + } + info->break_detected_cnt = 0; + DEBUG_LOG(info->line, "#iERR s d %04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + } + PROCSTAT(ser_stat[info->line].early_errors_cnt++); + } else { /* It was a valid byte, now let the DMA do the rest */ + unsigned long curr_time_u = GET_JIFFIES_USEC(); + unsigned long curr_time = jiffies; + + if (info->break_detected_cnt) { + /* Detect if this character is a new valid char or the + * last char in a break sequence: If LSBits are 0 and + * MSBits are high AND the time is close to the + * previous interrupt we should discard it. + */ + long elapsed_usec = + (curr_time - info->last_rx_active) * (1000000/HZ) + + curr_time_u - info->last_rx_active_usec; + if (elapsed_usec < 2*info->char_time_usec) { + DEBUG_LOG(info->line, "FBRK %i\n", info->line); + /* Report as BREAK (error) and let + * receive_chars_dma() handle it + */ + info->errorcode = ERRCODE_SET_BREAK; + } else { + DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line); + } + DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); + } + +#ifdef SERIAL_DEBUG_INTR + printk("** OK, disabling ser_interrupts\n"); +#endif + e100_disable_serial_data_irq(info); + DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); + info->break_detected_cnt = 0; + + PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); + } + /* Restarting the DMA never hurts */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); + START_FLUSH_FAST_TIMER(info, "ser_int"); + return info; +} /* handle_ser_rx_interrupt */ + +static void handle_ser_tx_interrupt(struct e100_serial *info) +{ + unsigned long flags; + + if (info->x_char) { + unsigned char rstat; + DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char)); + local_irq_save(flags); + rstat = info->ioport[REG_STATUS]; + DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); + + info->ioport[REG_TR_DATA] = info->x_char; + info->icount.tx++; + info->x_char = 0; + /* We must enable since it is disabled in ser_interrupt */ + e100_enable_serial_tx_ready_irq(info); + local_irq_restore(flags); + return; + } + if (info->uses_dma_out) { + unsigned char rstat; + int i; + /* We only use normal tx interrupt when sending x_char */ + DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0)); + local_irq_save(flags); + rstat = info->ioport[REG_STATUS]; + DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); + e100_disable_serial_tx_ready_irq(info); + if (info->port.tty->stopped) + rs_stop(info->port.tty); + /* Enable the DMA channel and tell it to continue */ + e100_enable_txdma_channel(info); + /* Wait 12 cycles before doing the DMA command */ + for(i = 6; i > 0; i--) + nop(); + + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue); + local_irq_restore(flags); + return; + } + /* Normal char-by-char interrupt */ + if (info->xmit.head == info->xmit.tail + || info->port.tty->stopped + || info->port.tty->hw_stopped) { + DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", + info->port.tty->stopped)); + e100_disable_serial_tx_ready_irq(info); + info->tr_running = 0; + return; + } + DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail])); + /* Send a byte, rs485 timing is critical so turn of ints */ + local_irq_save(flags); + info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; + info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); + info->icount.tx++; + if (info->xmit.head == info->xmit.tail) { +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) + if (info->rs485.flags & SER_RS485_ENABLED) { + /* Set a short timer to toggle RTS */ + start_one_shot_timer(&fast_timers_rs485[info->line], + rs485_toggle_rts_timer_function, + (unsigned long)info, + info->char_time_usec*2, + "RS-485"); + } +#endif /* RS485 */ + info->last_tx_active_usec = GET_JIFFIES_USEC(); + info->last_tx_active = jiffies; + e100_disable_serial_tx_ready_irq(info); + info->tr_running = 0; + DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0)); + } else { + /* We must enable since it is disabled in ser_interrupt */ + e100_enable_serial_tx_ready_irq(info); + } + local_irq_restore(flags); + + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +} /* handle_ser_tx_interrupt */ + +/* result of time measurements: + * RX duration 54-60 us when doing something, otherwise 6-9 us + * ser_int duration: just sending: 8-15 us normally, up to 73 us + */ +static irqreturn_t +ser_interrupt(int irq, void *dev_id) +{ + static volatile int tx_started = 0; + struct e100_serial *info; + int i; + unsigned long flags; + unsigned long irq_mask1_rd; + unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */ + int handled = 0; + static volatile unsigned long reentered_ready_mask = 0; + + local_irq_save(flags); + irq_mask1_rd = *R_IRQ_MASK1_RD; + /* First handle all rx interrupts with ints disabled */ + info = rs_table; + irq_mask1_rd &= e100_ser_int_mask; + for (i = 0; i < NR_PORTS; i++) { + /* Which line caused the data irq? */ + if (irq_mask1_rd & data_mask) { + handled = 1; + handle_ser_rx_interrupt(info); + } + info += 1; + data_mask <<= 2; + } + /* Handle tx interrupts with interrupts enabled so we + * can take care of new data interrupts while transmitting + * We protect the tx part with the tx_started flag. + * We disable the tr_ready interrupts we are about to handle and + * unblock the serial interrupt so new serial interrupts may come. + * + * If we get a new interrupt: + * - it migth be due to synchronous serial ports. + * - serial irq will be blocked by general irq handler. + * - async data will be handled above (sync will be ignored). + * - tx_started flag will prevent us from trying to send again and + * we will exit fast - no need to unblock serial irq. + * - Next (sync) serial interrupt handler will be runned with + * disabled interrupt due to restore_flags() at end of function, + * so sync handler will not be preempted or reentered. + */ + if (!tx_started) { + unsigned long ready_mask; + unsigned long + tx_started = 1; + /* Only the tr_ready interrupts left */ + irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | + IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | + IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | + IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); + while (irq_mask1_rd) { + /* Disable those we are about to handle */ + *R_IRQ_MASK1_CLR = irq_mask1_rd; + /* Unblock the serial interrupt */ + *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); + + local_irq_enable(); + ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */ + info = rs_table; + for (i = 0; i < NR_PORTS; i++) { + /* Which line caused the ready irq? */ + if (irq_mask1_rd & ready_mask) { + handled = 1; + handle_ser_tx_interrupt(info); + } + info += 1; + ready_mask <<= 2; + } + /* handle_ser_tx_interrupt enables tr_ready interrupts */ + local_irq_disable(); + /* Handle reentered TX interrupt */ + irq_mask1_rd = reentered_ready_mask; + } + local_irq_disable(); + tx_started = 0; + } else { + unsigned long ready_mask; + ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | + IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | + IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | + IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); + if (ready_mask) { + reentered_ready_mask |= ready_mask; + /* Disable those we are about to handle */ + *R_IRQ_MASK1_CLR = ready_mask; + DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask)); + } + } + + local_irq_restore(flags); + return IRQ_RETVAL(handled); +} /* ser_interrupt */ +#endif + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void +do_softint(struct work_struct *work) +{ + struct e100_serial *info; + struct tty_struct *tty; + + info = container_of(work, struct e100_serial, work); + + tty = info->port.tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) + tty_wakeup(tty); +} + +static int +startup(struct e100_serial * info) +{ + unsigned long flags; + unsigned long xmit_page; + int i; + + xmit_page = get_zeroed_page(GFP_KERNEL); + if (!xmit_page) + return -ENOMEM; + + local_irq_save(flags); + + /* if it was already initialized, skip this */ + + if (info->flags & ASYNC_INITIALIZED) { + local_irq_restore(flags); + free_page(xmit_page); + return 0; + } + + if (info->xmit.buf) + free_page(xmit_page); + else + info->xmit.buf = (unsigned char *) xmit_page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf); +#endif + +#ifdef CONFIG_SVINTO_SIM + /* Bits and pieces collected from below. Better to have them + in one ifdef:ed clause than to mix in a lot of ifdefs, + right? */ + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + + info->xmit.head = info->xmit.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = NULL; + + /* No real action in the simulator, but may set info important + to ioctl. */ + change_speed(info); +#else + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + + /* + * Reset the DMA channels and make sure their interrupts are cleared + */ + + if (info->dma_in_enabled) { + info->uses_dma_in = 1; + e100_enable_rxdma_channel(info); + + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + + /* Wait until reset cycle is complete */ + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + /* Make sure the irqs are cleared */ + *info->iclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + } else { + e100_disable_rxdma_channel(info); + } + + if (info->dma_out_enabled) { + info->uses_dma_out = 1; + e100_enable_txdma_channel(info); + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + + /* Make sure the irqs are cleared */ + *info->oclrintradr = + IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | + IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); + } else { + e100_disable_txdma_channel(info); + } + + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + + info->xmit.head = info->xmit.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = 0; + + /* + * and set the speed and other flags of the serial port + * this will start the rx/tx as well + */ +#ifdef SERIAL_HANDLE_EARLY_ERRORS + e100_enable_serial_data_irq(info); +#endif + change_speed(info); + + /* dummy read to reset any serial errors */ + + (void)info->ioport[REG_DATA]; + + /* enable the interrupts */ + if (info->uses_dma_out) + e100_enable_txdma_irq(info); + + e100_enable_rx_irq(info); + + info->tr_running = 0; /* to be sure we don't lock up the transmitter */ + + /* setup the dma input descriptor and start dma */ + + start_receive(info); + + /* for safety, make sure the descriptors last result is 0 bytes written */ + + info->tr_descr.sw_len = 0; + info->tr_descr.hw_len = 0; + info->tr_descr.status = 0; + + /* enable RTS/DTR last */ + + e100_rts(info, 1); + e100_dtr(info, 1); + +#endif /* CONFIG_SVINTO_SIM */ + + info->flags |= ASYNC_INITIALIZED; + + local_irq_restore(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void +shutdown(struct e100_serial * info) +{ + unsigned long flags; + struct etrax_dma_descr *descr = info->rec_descr; + struct etrax_recv_buffer *buffer; + int i; + +#ifndef CONFIG_SVINTO_SIM + /* shut down the transmitter and receiver */ + DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); + e100_disable_rx(info); + info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); + + /* disable interrupts, reset dma channels */ + if (info->uses_dma_in) { + e100_disable_rxdma_irq(info); + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + info->uses_dma_in = 0; + } else { + e100_disable_serial_data_irq(info); + } + + if (info->uses_dma_out) { + e100_disable_txdma_irq(info); + info->tr_running = 0; + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + info->uses_dma_out = 0; + } else { + e100_disable_serial_tx_ready_irq(info); + info->tr_running = 0; + } + +#endif /* CONFIG_SVINTO_SIM */ + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....\n", info->line, + info->irq); +#endif + + local_irq_save(flags); + + if (info->xmit.buf) { + free_page((unsigned long)info->xmit.buf); + info->xmit.buf = NULL; + } + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + if (descr[i].buf) { + buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; + kfree(buffer); + descr[i].buf = 0; + } + + 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 */ + } + + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + local_irq_restore(flags); +} + + +/* change baud rate and other assorted parameters */ + +static void +change_speed(struct e100_serial *info) +{ + unsigned int cflag; + unsigned long xoff; + unsigned long flags; + /* first some safety checks */ + + if (!info->port.tty || !info->port.tty->termios) + return; + if (!info->ioport) + return; + + cflag = info->port.tty->termios->c_cflag; + + /* possibly, the tx/rx should be disabled first to do this safely */ + + /* change baud-rate and write it to the hardware */ + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { + /* Special baudrate */ + u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ + unsigned long alt_source = + IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | + IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); + /* R_ALT_SER_BAUDRATE selects the source */ + DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n", + (unsigned long)info->baud_base, info->custom_divisor)); + if (info->baud_base == SERIAL_PRESCALE_BASE) { + /* 0, 2-65535 (0=65536) */ + u16 divisor = info->custom_divisor; + /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */ + /* baudrate is 3.125MHz/custom_divisor */ + alt_source = + IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) | + IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale); + alt_source = 0x11; + DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor)); + *R_SERIAL_PRESCALE = divisor; + info->baud = SERIAL_PRESCALE_BASE/divisor; + } +#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED + else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && + info->custom_divisor == 1) || + (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && + info->custom_divisor == 8)) { + /* ext_clk selected */ + alt_source = + IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | + IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); + DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); + info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; + } +#endif + else + { + /* Bad baudbase, we don't support using timer0 + * for baudrate. + */ + printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n", + (unsigned long)info->baud_base, info->custom_divisor); + } + r_alt_ser_baudrate_shadow &= ~mask; + r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); + *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; + } else { + /* Normal baudrate */ + /* Make sure we use normal baudrate */ + u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ + unsigned long alt_source = + IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | + IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); + r_alt_ser_baudrate_shadow &= ~mask; + r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); +#ifndef CONFIG_SVINTO_SIM + *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; +#endif /* CONFIG_SVINTO_SIM */ + + info->baud = cflag_to_baud(cflag); +#ifndef CONFIG_SVINTO_SIM + info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); +#endif /* CONFIG_SVINTO_SIM */ + } + +#ifndef CONFIG_SVINTO_SIM + /* start with default settings and then fill in changes */ + local_irq_save(flags); + /* 8 bit, no/even parity */ + info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | + IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); + + /* 8 bit, no/even parity, 1 stop bit, no cts */ + info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | + IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | + IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | + IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); + + if ((cflag & CSIZE) == CS7) { + /* set 7 bit mode */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); + } + + if (cflag & CSTOPB) { + /* set 2 stop bit mode */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); + } + + if (cflag & PARENB) { + /* enable parity */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); + } + + if (cflag & CMSPAR) { + /* enable stick parity, PARODD mean Mark which matches ETRAX */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick); + } + if (cflag & PARODD) { + /* set odd parity (or Mark if CMSPAR) */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); + } + + if (cflag & CRTSCTS) { + /* enable automatic CTS handling */ + DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0)); + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); + } + + /* make sure the tx and rx are enabled */ + + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); + + /* actually write the control regs to the hardware */ + + info->ioport[REG_TR_CTRL] = info->tx_ctrl; + 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 ) { + 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); + } + + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; + local_irq_restore(flags); +#endif /* !CONFIG_SVINTO_SIM */ + + update_char_time(info); + +} /* change_speed */ + +/* start transmitting chars NOW */ + +static void +rs_flush_chars(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + if (info->tr_running || + info->xmit.head == info->xmit.tail || + tty->stopped || + tty->hw_stopped || + !info->xmit.buf) + return; + +#ifdef SERIAL_DEBUG_FLOW + printk("rs_flush_chars\n"); +#endif + + /* this protection might not exactly be necessary here */ + + local_irq_save(flags); + start_transmit(info); + local_irq_restore(flags); +} + +static int rs_raw_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + /* first some sanity checks */ + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + +#ifdef SERIAL_DEBUG_DATA + if (info->line == SERIAL_DEBUG_LINE) + printk("rs_raw_write (%d), status %d\n", + count, info->ioport[REG_STATUS]); +#endif + +#ifdef CONFIG_SVINTO_SIM + /* Really simple. The output is here and now. */ + SIMCOUT(buf, count); + return count; +#endif + local_save_flags(flags); + DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); + DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); + + + /* The local_irq_disable/restore_flags pairs below are needed + * because the DMA interrupt handler moves the info->xmit values. + * the memcpy needs to be in the critical region unfortunately, + * because we need to read xmit values, memcpy, write xmit values + * in one atomic operation... this could perhaps be avoided by + * more clever design. + */ + local_irq_disable(); + while (count) { + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) + break; + + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = (info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1); + buf += c; + count -= c; + ret += c; + } + local_irq_restore(flags); + + /* enable transmitter if not running, unless the tty is stopped + * this does not need IRQ protection since if tr_running == 0 + * the IRQ's are not running anyway for this port. + */ + DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret)); + + if (info->xmit.head != info->xmit.tail && + !tty->stopped && + !tty->hw_stopped && + !info->tr_running) { + start_transmit(info); + } + + return ret; +} /* raw_raw_write() */ + +static int +rs_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ +#if defined(CONFIG_ETRAX_RS485) + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + if (info->rs485.flags & SER_RS485_ENABLED) + { + /* If we are in RS-485 mode, we need to toggle RTS and disable + * the receiver before initiating a DMA transfer + */ +#ifdef CONFIG_ETRAX_FAST_TIMER + /* Abort any started timer */ + fast_timers_rs485[info->line].function = NULL; + del_fast_timer(&fast_timers_rs485[info->line]); +#endif + e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND)); +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_disable_rx(info); + e100_enable_rx_irq(info); +#endif + if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) && + (info->rs485.delay_rts_before_send > 0)) + msleep(info->rs485.delay_rts_before_send); + } +#endif /* CONFIG_ETRAX_RS485 */ + + count = rs_raw_write(tty, buf, count); + +#if defined(CONFIG_ETRAX_RS485) + if (info->rs485.flags & SER_RS485_ENABLED) + { + unsigned int val; + /* If we are in RS-485 mode the following has to be done: + * wait until DMA is ready + * wait on transmit shift register + * toggle RTS + * enable the receiver + */ + + /* Sleep until all sent */ + tty_wait_until_sent(tty, 0); +#ifdef CONFIG_ETRAX_FAST_TIMER + /* Now sleep a little more so that shift register is empty */ + schedule_usleep(info->char_time_usec * 2); +#endif + /* wait on transmit shift register */ + do{ + get_lsr_info(info, &val); + }while (!(val & TIOCSER_TEMT)); + + e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); + +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_enable_rx(info); + e100_enable_rxdma_irq(info); +#endif + } +#endif /* CONFIG_ETRAX_RS485 */ + + return count; +} /* rs_write */ + + +/* how much space is available in the xmit buffer? */ + +static int +rs_write_room(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +/* How many chars are in the xmit buffer? + * This does not include any chars in the transmitter FIFO. + * Use wait_until_sent for waiting for FIFO drain. + */ + +static int +rs_chars_in_buffer(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +/* discard everything in the xmit buffer */ + +static void +rs_flush_buffer(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + local_irq_save(flags); + info->xmit.head = info->xmit.tail = 0; + local_irq_restore(flags); + + tty_wakeup(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + * + * Since we use DMA we don't check for info->x_char in transmit_chars_dma(), + * but we do it in handle_ser_tx_interrupt(). + * We disable DMA channel and enable tx ready interrupt and write the + * character when possible. + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + local_irq_save(flags); + if (info->uses_dma_out) { + /* Put the DMA on hold and disable the channel */ + *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) != + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold)); + e100_disable_txdma_channel(info); + } + + /* Must make sure transmitter is not stopped before we can transmit */ + if (tty->stopped) + rs_start(tty); + + /* Enable manual transmit interrupt and send from there */ + DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch)); + info->x_char = ch; + e100_enable_serial_tx_ready_irq(info); + local_irq_restore(flags); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void +rs_throttle(struct tty_struct * tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %lu....\n", tty_name(tty, buf), + (unsigned long)tty->ldisc.chars_in_buffer(tty)); +#endif + 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) { + /* Turn off RTS line */ + e100_rts(info, 0); + } + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + +} + +static void +rs_unthrottle(struct tty_struct * tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %lu....\n", tty_name(tty, buf), + (unsigned long)tty->ldisc.chars_in_buffer(tty)); +#endif + 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) { + /* Assert RTS line */ + e100_rts(info, 1); + } + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int +get_serial_info(struct e100_serial * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + /* this is all probably wrong, there are a lot of fields + * here that we don't have in e100_serial and maybe we + * should set them to something else than 0. + */ + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = (int)info->ioport; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int +set_serial_info(struct e100_serial *info, + struct serial_struct *new_info) +{ + struct serial_struct new_serial; + struct e100_serial old_info; + int retval = 0; + + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; + + old_info = *info; + + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->custom_divisor = new_serial.custom_divisor; + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + check_and_exit: + if (info->flags & ASYNC_INITIALIZED) { + change_speed(info); + } else + retval = startup(info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int +get_lsr_info(struct e100_serial * info, unsigned int *value) +{ + unsigned int result = TIOCSER_TEMT; +#ifndef CONFIG_SVINTO_SIM + unsigned long curr_time = jiffies; + unsigned long curr_time_usec = GET_JIFFIES_USEC(); + unsigned long elapsed_usec = + (curr_time - info->last_tx_active) * 1000000/HZ + + curr_time_usec - info->last_tx_active_usec; + + if (info->xmit.head != info->xmit.tail || + elapsed_usec < 2*info->char_time_usec) { + result = 0; + } +#endif + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +#ifdef SERIAL_DEBUG_IO +struct state_str +{ + int state; + const char *str; +}; + +const struct state_str control_state_str[] = { + {TIOCM_DTR, "DTR" }, + {TIOCM_RTS, "RTS"}, + {TIOCM_ST, "ST?" }, + {TIOCM_SR, "SR?" }, + {TIOCM_CTS, "CTS" }, + {TIOCM_CD, "CD" }, + {TIOCM_RI, "RI" }, + {TIOCM_DSR, "DSR" }, + {0, NULL } +}; + +char *get_control_state_str(int MLines, char *s) +{ + int i = 0; + + s[0]='\0'; + while (control_state_str[i].str != NULL) { + if (MLines & control_state_str[i].state) { + if (s[0] != '\0') { + strcat(s, ", "); + } + strcat(s, control_state_str[i].str); + } + i++; + } + return s; +} +#endif + +static int +rs_break(struct tty_struct *tty, int break_state) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + if (!info->ioport) + return -EIO; + + local_irq_save(flags); + if (break_state == -1) { + /* Go to manual mode and set the txd pin to 0 */ + /* Clear bit 7 (txd) and 6 (tr_enable) */ + info->tx_ctrl &= 0x3F; + } else { + /* Set bit 7 (txd) and 6 (tr_enable) */ + info->tx_ctrl |= (0x80 | 0x40); + } + info->ioport[REG_TR_CTRL] = info->tx_ctrl; + local_irq_restore(flags); + return 0; +} + +static int +rs_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + local_irq_save(flags); + + if (clear & TIOCM_RTS) + e100_rts(info, 0); + if (clear & TIOCM_DTR) + e100_dtr(info, 0); + /* Handle FEMALE behaviour */ + if (clear & TIOCM_RI) + e100_ri_out(info, 0); + if (clear & TIOCM_CD) + e100_cd_out(info, 0); + + if (set & TIOCM_RTS) + e100_rts(info, 1); + if (set & TIOCM_DTR) + e100_dtr(info, 1); + /* Handle FEMALE behaviour */ + if (set & TIOCM_RI) + e100_ri_out(info, 1); + if (set & TIOCM_CD) + e100_cd_out(info, 1); + + local_irq_restore(flags); + return 0; +} + +static int +rs_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned int result; + unsigned long flags; + + local_irq_save(flags); + + result = + (!E100_RTS_GET(info) ? TIOCM_RTS : 0) + | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) + | (!E100_RI_GET(info) ? TIOCM_RNG : 0) + | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) + | (!E100_CD_GET(info) ? TIOCM_CAR : 0) + | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); + + local_irq_restore(flags); + +#ifdef SERIAL_DEBUG_IO + printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", + info->line, result, result); + { + char s[100]; + + get_control_state_str(result, s); + printk(KERN_DEBUG "state: %s\n", s); + } +#endif + return result; + +} + + +static int +rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct e100_serial *) arg, + info, sizeof(struct e100_serial))) + return -EFAULT; + return 0; + +#if defined(CONFIG_ETRAX_RS485) + case TIOCSERSETRS485: + { + /* In this ioctl we still use the old structure + * rs485_control for backward compatibility + * (if we use serial_rs485, then old user-level code + * wouldn't work anymore...). + * The use of this ioctl is deprecated: use TIOCSRS485 + * instead.*/ + struct rs485_control rs485ctrl; + struct serial_rs485 rs485data; + printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n"); + if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg, + sizeof(rs485ctrl))) + return -EFAULT; + + rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; + rs485data.flags = 0; + if (rs485data.delay_rts_before_send != 0) + rs485data.flags |= SER_RS485_RTS_BEFORE_SEND; + else + rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND); + + if (rs485ctrl.enabled) + rs485data.flags |= SER_RS485_ENABLED; + else + rs485data.flags &= ~(SER_RS485_ENABLED); + + if (rs485ctrl.rts_on_send) + rs485data.flags |= SER_RS485_RTS_ON_SEND; + else + rs485data.flags &= ~(SER_RS485_RTS_ON_SEND); + + if (rs485ctrl.rts_after_sent) + rs485data.flags |= SER_RS485_RTS_AFTER_SEND; + else + rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND); + + return e100_enable_rs485(tty, &rs485data); + } + + case TIOCSRS485: + { + /* This is the new version of TIOCSRS485, with new + * data structure serial_rs485 */ + struct serial_rs485 rs485data; + if (copy_from_user(&rs485data, (struct rs485_control *)arg, + sizeof(rs485data))) + return -EFAULT; + + return e100_enable_rs485(tty, &rs485data); + } + + case TIOCGRS485: + { + struct serial_rs485 *rs485data = + &(((struct e100_serial *)tty->driver_data)->rs485); + /* This is the ioctl to get RS485 data from user-space */ + if (copy_to_user((struct serial_rs485 *) arg, + rs485data, + sizeof(struct serial_rs485))) + return -EFAULT; + break; + } + + case TIOCSERWRRS485: + { + struct rs485_write rs485wr; + if (copy_from_user(&rs485wr, (struct rs485_write *)arg, + sizeof(rs485wr))) + return -EFAULT; + + return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size); + } +#endif + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void +rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + change_speed(info); + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * S structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void +rs_close(struct tty_struct *tty, struct file * filp) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + if (!info) + return; + + /* interrupts are disabled for this entire function */ + + local_irq_save(flags); + + if (tty_hung_up_p(filp)) { + local_irq_restore(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, + info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->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. + */ + printk(KERN_CRIT + "rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + local_irq_restore(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + 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. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the serial receiver and the DMA receive interrupt. + */ +#ifdef SERIAL_HANDLE_EARLY_ERRORS + e100_disable_serial_data_irq(info); +#endif + +#ifndef CONFIG_SVINTO_SIM + e100_disable_rx(info); + e100_disable_rx_irq(info); + + if (info->flags & ASYNC_INITIALIZED) { + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important as we have a transmit FIFO! + */ + rs_wait_until_sent(tty, HZ); + } +#endif + + shutdown(info); + rs_flush_buffer(tty); + tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->port.tty = NULL; + if (info->blocked_open) { + if (info->close_delay) + schedule_timeout_interruptible(info->close_delay); + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + local_irq_restore(flags); + + /* port closed */ + +#if defined(CONFIG_ETRAX_RS485) + if (info->rs485.flags & SER_RS485_ENABLED) { + info->rs485.flags &= ~(SER_RS485_ENABLED); +#if defined(CONFIG_ETRAX_RS485_ON_PA) + *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); +#endif +#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, + rs485_port_g_bit, 0); +#endif +#if defined(CONFIG_ETRAX_RS485_LTC1387) + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, + CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); + REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, + CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); +#endif + } +#endif + + /* + * Release any allocated DMA irq's. + */ + if (info->dma_in_enabled) { + free_irq(info->dma_in_irq_nbr, info); + cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); + info->uses_dma_in = 0; +#ifdef SERIAL_DEBUG_OPEN + printk(KERN_DEBUG "DMA irq '%s' freed\n", + info->dma_in_irq_description); +#endif + } + if (info->dma_out_enabled) { + free_irq(info->dma_out_irq_nbr, info); + cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); + info->uses_dma_out = 0; +#ifdef SERIAL_DEBUG_OPEN + printk(KERN_DEBUG "DMA irq '%s' freed\n", + info->dma_out_irq_description); +#endif + } +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + unsigned long orig_jiffies; + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long curr_time = jiffies; + unsigned long curr_time_usec = GET_JIFFIES_USEC(); + long elapsed_usec = + (curr_time - info->last_tx_active) * (1000000/HZ) + + curr_time_usec - info->last_tx_active_usec; + + /* + * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO + * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) + */ + orig_jiffies = jiffies; + while (info->xmit.head != info->xmit.tail || /* More in send queue */ + (*info->ostatusadr & 0x007f) || /* more in FIFO */ + (elapsed_usec < 2*info->char_time_usec)) { + schedule_timeout_interruptible(1); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + curr_time = jiffies; + curr_time_usec = GET_JIFFIES_USEC(); + elapsed_usec = + (curr_time - info->last_tx_active) * (1000000/HZ) + + curr_time_usec - info->last_tx_active_usec; + } + set_current_state(TASK_RUNNING); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void +rs_hangup(struct tty_struct *tty) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int +block_til_ready(struct tty_struct *tty, struct file * filp, + struct e100_serial *info) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int retval; + int do_clocal = 0, extra_count = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + wait_event_interruptible_tty(info->close_wait, + !(info->flags & ASYNC_CLOSING)); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) { + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttyS%d, count = %d\n", + info->line, info->count); +#endif + local_irq_save(flags); + if (!tty_hung_up_p(filp)) { + extra_count++; + info->count--; + } + local_irq_restore(flags); + info->blocked_open++; + while (1) { + local_irq_save(flags); + /* assert RTS and DTR */ + e100_rts(info, 1); + e100_dtr(info, 1); + local_irq_restore(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CLOSING) && do_clocal) + /* && (do_clocal || DCD_IS_ASSERTED) */ + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + tty_unlock(); + schedule(); + tty_lock(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static void +deinit_port(struct e100_serial *info) +{ + if (info->dma_out_enabled) { + cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); + free_irq(info->dma_out_irq_nbr, info); + } + if (info->dma_in_enabled) { + cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); + free_irq(info->dma_in_irq_nbr, info); + } +} + +/* + * This routine is called whenever a serial port is opened. + * It performs the serial-specific initialization for the tty structure. + */ +static int +rs_open(struct tty_struct *tty, struct file * filp) +{ + struct e100_serial *info; + int retval, line; + unsigned long page; + int allocated_resources = 0; + + /* find which port we want to open */ + line = tty->index; + + if (line < 0 || line >= NR_PORTS) + return -ENODEV; + + /* find the corresponding e100_serial struct in the table */ + info = rs_table + line; + + /* don't allow the opening of ports that are not enabled in the HW config */ + if (!info->enabled) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, + info->count); +#endif + + info->count++; + tty->driver_data = info; + info->port.tty = tty; + + info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is in the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + wait_event_interruptible_tty(info->close_wait, + !(info->flags & ASYNC_CLOSING)); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If DMA is enabled try to allocate the irq's. + */ + if (info->count == 1) { + allocated_resources = 1; + if (info->dma_in_enabled) { + if (request_irq(info->dma_in_irq_nbr, + rec_interrupt, + info->dma_in_irq_flags, + info->dma_in_irq_description, + info)) { + printk(KERN_WARNING "DMA irq '%s' busy; " + "falling back to non-DMA mode\n", + info->dma_in_irq_description); + /* Make sure we never try to use DMA in */ + /* for the port again. */ + info->dma_in_enabled = 0; + } else if (cris_request_dma(info->dma_in_nbr, + info->dma_in_irq_description, + DMA_VERBOSE_ON_ERROR, + info->dma_owner)) { + free_irq(info->dma_in_irq_nbr, info); + printk(KERN_WARNING "DMA '%s' busy; " + "falling back to non-DMA mode\n", + info->dma_in_irq_description); + /* Make sure we never try to use DMA in */ + /* for the port again. */ + info->dma_in_enabled = 0; + } +#ifdef SERIAL_DEBUG_OPEN + else + printk(KERN_DEBUG "DMA irq '%s' allocated\n", + info->dma_in_irq_description); +#endif + } + if (info->dma_out_enabled) { + if (request_irq(info->dma_out_irq_nbr, + tr_interrupt, + info->dma_out_irq_flags, + info->dma_out_irq_description, + info)) { + printk(KERN_WARNING "DMA irq '%s' busy; " + "falling back to non-DMA mode\n", + info->dma_out_irq_description); + /* Make sure we never try to use DMA out */ + /* for the port again. */ + info->dma_out_enabled = 0; + } else if (cris_request_dma(info->dma_out_nbr, + info->dma_out_irq_description, + DMA_VERBOSE_ON_ERROR, + info->dma_owner)) { + free_irq(info->dma_out_irq_nbr, info); + printk(KERN_WARNING "DMA '%s' busy; " + "falling back to non-DMA mode\n", + info->dma_out_irq_description); + /* Make sure we never try to use DMA out */ + /* for the port again. */ + info->dma_out_enabled = 0; + } +#ifdef SERIAL_DEBUG_OPEN + else + printk(KERN_DEBUG "DMA irq '%s' allocated\n", + info->dma_out_irq_description); +#endif + } + } + + /* + * Start up the serial port + */ + + retval = startup(info); + if (retval) { + if (allocated_resources) + deinit_port(info); + + /* FIXME Decrease count info->count here too? */ + return retval; + } + + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + if (allocated_resources) + deinit_port(info); + + return retval; + } + + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + *tty->termios = info->normal_termios; + change_speed(info); + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttyS%d successful...\n", info->line); +#endif + DLOG_INT_TRIG( log_int_pos = 0); + + DFLIP( if (info->line == SERIAL_DEBUG_LINE) { + info->icount.rx = 0; + } ); + + return 0; +} + +#ifdef CONFIG_PROC_FS +/* + * /proc fs routines.... + */ + +static void seq_line_info(struct seq_file *m, struct e100_serial *info) +{ + unsigned long tmp; + + seq_printf(m, "%d: uart:E100 port:%lX irq:%d", + info->line, (unsigned long)info->ioport, info->irq); + + if (!info->ioport || (info->type == PORT_UNKNOWN)) { + seq_printf(m, "\n"); + return; + } + + seq_printf(m, " baud:%d", info->baud); + seq_printf(m, " tx:%lu rx:%lu", + (unsigned long)info->icount.tx, + (unsigned long)info->icount.rx); + tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + if (tmp) + seq_printf(m, " tx_pend:%lu/%lu", + (unsigned long)tmp, + (unsigned long)SERIAL_XMIT_SIZE); + + seq_printf(m, " rx_pend:%lu/%lu", + (unsigned long)info->recv_cnt, + (unsigned long)info->max_recv_cnt); + +#if 1 + if (info->port.tty) { + if (info->port.tty->stopped) + seq_printf(m, " stopped:%i", + (int)info->port.tty->stopped); + if (info->port.tty->hw_stopped) + seq_printf(m, " hw_stopped:%i", + (int)info->port.tty->hw_stopped); + } + + { + unsigned char rstat = info->ioport[REG_STATUS]; + if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect)) + seq_printf(m, " xoff_detect:1"); + } + +#endif + + if (info->icount.frame) + seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame); + + if (info->icount.parity) + seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity); + + if (info->icount.brk) + seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk); + + if (info->icount.overrun) + seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + if (!E100_RTS_GET(info)) + seq_puts(m, "|RTS"); + if (!E100_CTS_GET(info)) + seq_puts(m, "|CTS"); + if (!E100_DTR_GET(info)) + seq_puts(m, "|DTR"); + if (!E100_DSR_GET(info)) + seq_puts(m, "|DSR"); + if (!E100_CD_GET(info)) + seq_puts(m, "|CD"); + if (!E100_RI_GET(info)) + seq_puts(m, "|RI"); + seq_puts(m, "\n"); +} + + +static int crisv10_proc_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); + + for (i = 0; i < NR_PORTS; i++) { + if (!rs_table[i].enabled) + continue; + seq_line_info(m, &rs_table[i]); + } +#ifdef DEBUG_LOG_INCLUDED + for (i = 0; i < debug_log_pos; i++) { + seq_printf(m, "%-4i %lu.%lu ", + i, debug_log[i].time, + timer_data_to_ns(debug_log[i].timer_data)); + seq_printf(m, debug_log[i].string, debug_log[i].value); + } + seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE); + debug_log_pos = 0; +#endif + return 0; +} + +static int crisv10_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, crisv10_proc_show, NULL); +} + +static const struct file_operations crisv10_proc_fops = { + .owner = THIS_MODULE, + .open = crisv10_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + + +/* Finally, routines used to initialize the serial driver. */ + +static void show_serial_version(void) +{ + printk(KERN_INFO + "ETRAX 100LX serial-driver %s, " + "(c) 2000-2004 Axis Communications AB\r\n", + &serial_version[11]); /* "$Revision: x.yy" */ +} + +/* rs_init inits the driver at boot (using the module_init chain) */ + +static const struct tty_operations rs_ops = { + .open = rs_open, + .close = rs_close, + .write = rs_write, + .flush_chars = rs_flush_chars, + .write_room = rs_write_room, + .chars_in_buffer = rs_chars_in_buffer, + .flush_buffer = rs_flush_buffer, + .ioctl = rs_ioctl, + .throttle = rs_throttle, + .unthrottle = rs_unthrottle, + .set_termios = rs_set_termios, + .stop = rs_stop, + .start = rs_start, + .hangup = rs_hangup, + .break_ctl = rs_break, + .send_xchar = rs_send_xchar, + .wait_until_sent = rs_wait_until_sent, + .tiocmget = rs_tiocmget, + .tiocmset = rs_tiocmset, +#ifdef CONFIG_PROC_FS + .proc_fops = &crisv10_proc_fops, +#endif +}; + +static int __init rs_init(void) +{ + int i; + struct e100_serial *info; + struct tty_driver *driver = alloc_tty_driver(NR_PORTS); + + if (!driver) + return -ENOMEM; + + show_serial_version(); + + /* Setup the timed flush handler system */ + +#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) + setup_timer(&flush_timer, timed_flush_handler, 0); + mod_timer(&flush_timer, jiffies + 5); +#endif + +#if defined(CONFIG_ETRAX_RS485) +#if defined(CONFIG_ETRAX_RS485_ON_PA) + if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, + rs485_pa_bit)) { + printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " + "RS485 pin\n"); + put_tty_driver(driver); + return -EBUSY; + } +#endif +#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) + if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, + rs485_port_g_bit)) { + printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " + "RS485 pin\n"); + put_tty_driver(driver); + return -EBUSY; + } +#endif +#endif + + /* Initialize the tty_driver structure */ + + driver->driver_name = "serial"; + driver->name = "ttyS"; + driver->major = TTY_MAJOR; + driver->minor_start = 64; + driver->type = TTY_DRIVER_TYPE_SERIAL; + driver->subtype = SERIAL_TYPE_NORMAL; + driver->init_termios = tty_std_termios; + driver->init_termios.c_cflag = + 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; + + 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 */ + + for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { + if (info->enabled) { + if (cris_request_io_interface(info->io_if, + info->io_if_description)) { + printk(KERN_CRIT "ETRAX100LX async serial: " + "Could not allocate IO pins for " + "%s, port %d\n", + info->io_if_description, i); + info->enabled = 0; + } + } + info->uses_dma_in = 0; + info->uses_dma_out = 0; + info->line = i; + info->port.tty = NULL; + info->type = PORT_ETRAX; + info->tr_running = 0; + info->forced_eop = 0; + info->baud_base = DEF_BAUD_BASE; + info->custom_divisor = 0; + info->flags = 0; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->normal_termios = driver->init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->xmit.buf = NULL; + info->xmit.tail = info->xmit.head = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + info->last_tx_active_usec = 0; + info->last_tx_active = 0; + +#if defined(CONFIG_ETRAX_RS485) + /* Set sane defaults */ + info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); + info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; + info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND); + info->rs485.delay_rts_before_send = 0; + info->rs485.flags &= ~(SER_RS485_ENABLED); +#endif + INIT_WORK(&info->work, do_softint); + + if (info->enabled) { + printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n", + serial_driver->name, info->line, info->ioport); + } + } +#ifdef CONFIG_ETRAX_FAST_TIMER +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER + memset(fast_timers, 0, sizeof(fast_timers)); +#endif +#ifdef CONFIG_ETRAX_RS485 + memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485)); +#endif + fast_timer_init(); +#endif + +#ifndef CONFIG_SVINTO_SIM +#ifndef CONFIG_ETRAX_KGDB + /* Not needed in simulator. May only complicate stuff. */ + /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ + + if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, + IRQF_SHARED | IRQF_DISABLED, "serial ", driver)) + panic("%s: Failed to request irq8", __func__); + +#endif +#endif /* CONFIG_SVINTO_SIM */ + + return 0; +} + +/* this makes sure that rs_init is called during kernel boot */ + +module_init(rs_init); diff --git a/drivers/tty/serial/crisv10.h b/drivers/tty/serial/crisv10.h new file mode 100644 index 000000000000..ea0beb46a10d --- /dev/null +++ b/drivers/tty/serial/crisv10.h @@ -0,0 +1,147 @@ +/* + * serial.h: Arch-dep definitions for the Etrax100 serial driver. + * + * Copyright (C) 1998-2007 Axis Communications AB + */ + +#ifndef _ETRAX_SERIAL_H +#define _ETRAX_SERIAL_H + +#include +#include +#include +#include + +/* Software state per channel */ + +#ifdef __KERNEL__ +/* + * 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 + */ + +#define SERIAL_RECV_DESCRIPTORS 8 + +struct etrax_recv_buffer { + struct etrax_recv_buffer *next; + unsigned short length; + unsigned char error; + unsigned char pad; + + unsigned char buffer[0]; +}; + +struct e100_serial { + struct tty_port port; + int baud; + volatile u8 *ioport; /* R_SERIALx_CTRL */ + u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + + /* Output registers */ + volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */ + volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */ + const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */ + + /* Input registers */ + volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */ + volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */ + volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */ + + int flags; /* defined in tty.h */ + + u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ + u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ + u8 iseteop; /* bit number for R_SET_EOP for the input dma */ + int enabled; /* Set to 1 if the port is enabled in HW config */ + + u8 dma_out_enabled; /* Set to 1 if DMA should be used */ + u8 dma_in_enabled; /* Set to 1 if DMA should be used */ + + /* end of fields defined in rs_table[] in .c-file */ + int dma_owner; + unsigned int dma_in_nbr; + unsigned int dma_out_nbr; + unsigned int dma_in_irq_nbr; + unsigned int dma_out_irq_nbr; + unsigned long dma_in_irq_flags; + unsigned long dma_out_irq_flags; + char *dma_in_irq_description; + char *dma_out_irq_description; + + enum cris_io_interface io_if; + char *io_if_description; + + u8 uses_dma_in; /* Set to 1 if DMA is used */ + u8 uses_dma_out; /* Set to 1 if DMA is used */ + u8 forced_eop; /* a fifo eop has been forced */ + int baud_base; /* For special baudrates */ + int custom_divisor; /* For special baudrates */ + struct etrax_dma_descr tr_descr; + struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS]; + int cur_rec_descr; + + volatile int tr_running; /* 1 if output is running */ + + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int line; + int type; /* PORT_ETRAX */ + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + struct circ_buf xmit; + struct etrax_recv_buffer *first_recv_buffer; + struct etrax_recv_buffer *last_recv_buffer; + unsigned int recv_cnt; + unsigned int max_recv_cnt; + + struct work_struct work; + struct async_icount icount; /* error-statistics etc.*/ + struct ktermios normal_termios; + struct ktermios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + unsigned long char_time_usec; /* The time for 1 char, in usecs */ + unsigned long flush_time_usec; /* How often we should flush */ + unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ + unsigned long last_tx_active; /* Last tx time in jiffies */ + unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ + unsigned long last_rx_active; /* Last rx time in jiffies */ + + int break_detected_cnt; + int errorcode; + +#ifdef CONFIG_ETRAX_RS485 + struct serial_rs485 rs485; /* RS-485 support */ +#endif +}; + +/* this PORT is not in the standard serial.h. it's not actually used for + * anything since we only have one type of async serial-port anyway in this + * system. + */ + +#define PORT_ETRAX 1 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +#endif /* __KERNEL__ */ + +#endif /* !_ETRAX_SERIAL_H */ diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c new file mode 100644 index 000000000000..57421d776329 --- /dev/null +++ b/drivers/tty/serial/dz.c @@ -0,0 +1,955 @@ +/* + * dz.c: Serial port driver for DECstations equipped + * with the DZ chipset. + * + * Copyright (C) 1998 Olivier A. D. Lebaillif + * + * Email: olivier.lebaillif@ifrsys.com + * + * Copyright (C) 2004, 2006, 2007 Maciej W. Rozycki + * + * [31-AUG-98] triemer + * Changed IRQ to use Harald's dec internals interrupts.h + * removed base_addr code - moving address assignment to setup.c + * Changed name of dz_init to rs_init to be consistent with tc code + * [13-NOV-98] triemer fixed code to receive characters + * after patches by harald to irq code. + * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout + * field from "current" - somewhere between 2.1.121 and 2.1.131 + Qua Jun 27 15:02:26 BRT 2001 + * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups + * + * Parts (C) 1999 David Airlie, airlied@linux.ie + * [07-SEP-99] Bugfixes + * + * [06-Jan-2002] Russell King + * Converted to new serial core + */ + +#undef DEBUG_DZ + +#if defined(CONFIG_SERIAL_DZ_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "dz.h" + + +MODULE_DESCRIPTION("DECstation DZ serial driver"); +MODULE_LICENSE("GPL"); + + +static char dz_name[] __initdata = "DECstation DZ serial driver version "; +static char dz_version[] __initdata = "1.04"; + +struct dz_port { + struct dz_mux *mux; + struct uart_port port; + unsigned int cflag; +}; + +struct dz_mux { + struct dz_port dport[DZ_NB_PORT]; + atomic_t map_guard; + atomic_t irq_guard; + int initialised; +}; + +static struct dz_mux dz_mux; + +static inline struct dz_port *to_dport(struct uart_port *uport) +{ + return container_of(uport, struct dz_port, port); +} + +/* + * ------------------------------------------------------------ + * dz_in () and dz_out () + * + * These routines are used to access the registers of the DZ + * chip, hiding relocation differences between implementation. + * ------------------------------------------------------------ + */ + +static u16 dz_in(struct dz_port *dport, unsigned offset) +{ + void __iomem *addr = dport->port.membase + offset; + + return readw(addr); +} + +static void dz_out(struct dz_port *dport, unsigned offset, u16 value) +{ + void __iomem *addr = dport->port.membase + offset; + + writew(value, addr); +} + +/* + * ------------------------------------------------------------ + * rs_stop () and rs_start () + * + * These routines are called before setting or resetting + * tty->stopped. They enable or disable transmitter interrupts, + * as necessary. + * ------------------------------------------------------------ + */ + +static void dz_stop_tx(struct uart_port *uport) +{ + struct dz_port *dport = to_dport(uport); + u16 tmp, mask = 1 << dport->port.line; + + tmp = dz_in(dport, DZ_TCR); /* read the TX flag */ + tmp &= ~mask; /* clear the TX flag */ + dz_out(dport, DZ_TCR, tmp); +} + +static void dz_start_tx(struct uart_port *uport) +{ + struct dz_port *dport = to_dport(uport); + u16 tmp, mask = 1 << dport->port.line; + + tmp = dz_in(dport, DZ_TCR); /* read the TX flag */ + tmp |= mask; /* set the TX flag */ + dz_out(dport, DZ_TCR, tmp); +} + +static void dz_stop_rx(struct uart_port *uport) +{ + struct dz_port *dport = to_dport(uport); + + dport->cflag &= ~DZ_RXENAB; + dz_out(dport, DZ_LPR, dport->cflag); +} + +static void dz_enable_ms(struct uart_port *uport) +{ + /* nothing to do */ +} + +/* + * ------------------------------------------------------------ + * + * Here start the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * dz_interrupt. They were separated out for readability's sake. + * + * Note: dz_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * dz_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * make drivers/serial/dz.s + * + * and look at the resulting assemble code in dz.s. + * + * ------------------------------------------------------------ + */ + +/* + * ------------------------------------------------------------ + * receive_char () + * + * This routine deals with inputs from any lines. + * ------------------------------------------------------------ + */ +static inline void dz_receive_chars(struct dz_mux *mux) +{ + struct uart_port *uport; + struct dz_port *dport = &mux->dport[0]; + struct tty_struct *tty = NULL; + struct uart_icount *icount; + int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 }; + unsigned char ch, flag; + u16 status; + int i; + + while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) { + dport = &mux->dport[LINE(status)]; + uport = &dport->port; + tty = uport->state->port.tty; /* point to the proper dev */ + + ch = UCHAR(status); /* grab the char */ + flag = TTY_NORMAL; + + icount = &uport->icount; + icount->rx++; + + if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) { + + /* + * There is no separate BREAK status bit, so treat + * null characters with framing errors as BREAKs; + * normally, otherwise. For this move the Framing + * Error bit to a simulated BREAK bit. + */ + if (!ch) { + status |= (status & DZ_FERR) >> + (ffs(DZ_FERR) - ffs(DZ_BREAK)); + status &= ~DZ_FERR; + } + + /* Handle SysRq/SAK & keep track of the statistics. */ + if (status & DZ_BREAK) { + icount->brk++; + if (uart_handle_break(uport)) + continue; + } else if (status & DZ_FERR) + icount->frame++; + else if (status & DZ_PERR) + icount->parity++; + if (status & DZ_OERR) + icount->overrun++; + + status &= uport->read_status_mask; + if (status & DZ_BREAK) + flag = TTY_BREAK; + else if (status & DZ_FERR) + flag = TTY_FRAME; + else if (status & DZ_PERR) + flag = TTY_PARITY; + + } + + if (uart_handle_sysrq_char(uport, ch)) + continue; + + uart_insert_char(uport, status, DZ_OERR, ch, flag); + lines_rx[LINE(status)] = 1; + } + for (i = 0; i < DZ_NB_PORT; i++) + if (lines_rx[i]) + tty_flip_buffer_push(mux->dport[i].port.state->port.tty); +} + +/* + * ------------------------------------------------------------ + * transmit_char () + * + * This routine deals with outputs to any lines. + * ------------------------------------------------------------ + */ +static inline void dz_transmit_chars(struct dz_mux *mux) +{ + struct dz_port *dport = &mux->dport[0]; + struct circ_buf *xmit; + unsigned char tmp; + u16 status; + + status = dz_in(dport, DZ_CSR); + dport = &mux->dport[LINE(status)]; + xmit = &dport->port.state->xmit; + + if (dport->port.x_char) { /* XON/XOFF chars */ + dz_out(dport, DZ_TDR, dport->port.x_char); + dport->port.icount.tx++; + dport->port.x_char = 0; + return; + } + /* If nothing to do or stopped or hardware stopped. */ + if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) { + spin_lock(&dport->port.lock); + dz_stop_tx(&dport->port); + spin_unlock(&dport->port.lock); + return; + } + + /* + * If something to do... (remember the dz has no output fifo, + * so we go one char at a time) :-< + */ + tmp = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1); + dz_out(dport, DZ_TDR, tmp); + dport->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS) + uart_write_wakeup(&dport->port); + + /* Are we are done. */ + if (uart_circ_empty(xmit)) { + spin_lock(&dport->port.lock); + dz_stop_tx(&dport->port); + spin_unlock(&dport->port.lock); + } +} + +/* + * ------------------------------------------------------------ + * check_modem_status() + * + * DS 3100 & 5100: Only valid for the MODEM line, duh! + * DS 5000/200: Valid for the MODEM and PRINTER line. + * ------------------------------------------------------------ + */ +static inline void check_modem_status(struct dz_port *dport) +{ + /* + * FIXME: + * 1. No status change interrupt; use a timer. + * 2. Handle the 3100/5000 as appropriate. --macro + */ + u16 status; + + /* If not the modem line just return. */ + if (dport->port.line != DZ_MODEM) + return; + + status = dz_in(dport, DZ_MSR); + + /* it's easy, since DSR2 is the only bit in the register */ + if (status) + dport->port.icount.dsr++; +} + +/* + * ------------------------------------------------------------ + * dz_interrupt () + * + * this is the main interrupt routine for the DZ chip. + * It deals with the multiple ports. + * ------------------------------------------------------------ + */ +static irqreturn_t dz_interrupt(int irq, void *dev_id) +{ + struct dz_mux *mux = dev_id; + struct dz_port *dport = &mux->dport[0]; + u16 status; + + /* get the reason why we just got an irq */ + status = dz_in(dport, DZ_CSR); + + if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE)) + dz_receive_chars(mux); + + if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE)) + dz_transmit_chars(mux); + + return IRQ_HANDLED; +} + +/* + * ------------------------------------------------------------------- + * Here ends the DZ interrupt routines. + * ------------------------------------------------------------------- + */ + +static unsigned int dz_get_mctrl(struct uart_port *uport) +{ + /* + * FIXME: Handle the 3100/5000 as appropriate. --macro + */ + struct dz_port *dport = to_dport(uport); + unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + + if (dport->port.line == DZ_MODEM) { + if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR) + mctrl &= ~TIOCM_DSR; + } + + return mctrl; +} + +static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl) +{ + /* + * FIXME: Handle the 3100/5000 as appropriate. --macro + */ + struct dz_port *dport = to_dport(uport); + u16 tmp; + + if (dport->port.line == DZ_MODEM) { + tmp = dz_in(dport, DZ_TCR); + if (mctrl & TIOCM_DTR) + tmp &= ~DZ_MODEM_DTR; + else + tmp |= DZ_MODEM_DTR; + dz_out(dport, DZ_TCR, tmp); + } +} + +/* + * ------------------------------------------------------------------- + * startup () + * + * various initialization tasks + * ------------------------------------------------------------------- + */ +static int dz_startup(struct uart_port *uport) +{ + struct dz_port *dport = to_dport(uport); + struct dz_mux *mux = dport->mux; + unsigned long flags; + int irq_guard; + int ret; + u16 tmp; + + irq_guard = atomic_add_return(1, &mux->irq_guard); + if (irq_guard != 1) + return 0; + + ret = request_irq(dport->port.irq, dz_interrupt, + IRQF_SHARED, "dz", mux); + if (ret) { + atomic_add(-1, &mux->irq_guard); + printk(KERN_ERR "dz: Cannot get IRQ %d!\n", dport->port.irq); + return ret; + } + + spin_lock_irqsave(&dport->port.lock, flags); + + /* Enable interrupts. */ + tmp = dz_in(dport, DZ_CSR); + tmp |= DZ_RIE | DZ_TIE; + dz_out(dport, DZ_CSR, tmp); + + spin_unlock_irqrestore(&dport->port.lock, flags); + + return 0; +} + +/* + * ------------------------------------------------------------------- + * shutdown () + * + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + * ------------------------------------------------------------------- + */ +static void dz_shutdown(struct uart_port *uport) +{ + struct dz_port *dport = to_dport(uport); + struct dz_mux *mux = dport->mux; + unsigned long flags; + int irq_guard; + u16 tmp; + + spin_lock_irqsave(&dport->port.lock, flags); + dz_stop_tx(&dport->port); + spin_unlock_irqrestore(&dport->port.lock, flags); + + irq_guard = atomic_add_return(-1, &mux->irq_guard); + if (!irq_guard) { + /* Disable interrupts. */ + tmp = dz_in(dport, DZ_CSR); + tmp &= ~(DZ_RIE | DZ_TIE); + dz_out(dport, DZ_CSR, tmp); + + free_irq(dport->port.irq, mux); + } +} + +/* + * ------------------------------------------------------------------- + * dz_tx_empty() -- get the transmitter empty status + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + * ------------------------------------------------------------------- + */ +static unsigned int dz_tx_empty(struct uart_port *uport) +{ + struct dz_port *dport = to_dport(uport); + unsigned short tmp, mask = 1 << dport->port.line; + + tmp = dz_in(dport, DZ_TCR); + tmp &= mask; + + return tmp ? 0 : TIOCSER_TEMT; +} + +static void dz_break_ctl(struct uart_port *uport, int break_state) +{ + /* + * FIXME: Can't access BREAK bits in TDR easily; + * reuse the code for polled TX. --macro + */ + struct dz_port *dport = to_dport(uport); + unsigned long flags; + unsigned short tmp, mask = 1 << dport->port.line; + + spin_lock_irqsave(&uport->lock, flags); + tmp = dz_in(dport, DZ_TCR); + if (break_state) + tmp |= mask; + else + tmp &= ~mask; + dz_out(dport, DZ_TCR, tmp); + spin_unlock_irqrestore(&uport->lock, flags); +} + +static int dz_encode_baud_rate(unsigned int baud) +{ + switch (baud) { + case 50: + return DZ_B50; + case 75: + return DZ_B75; + case 110: + return DZ_B110; + case 134: + return DZ_B134; + case 150: + return DZ_B150; + case 300: + return DZ_B300; + case 600: + return DZ_B600; + case 1200: + return DZ_B1200; + case 1800: + return DZ_B1800; + case 2000: + return DZ_B2000; + case 2400: + return DZ_B2400; + case 3600: + return DZ_B3600; + case 4800: + return DZ_B4800; + case 7200: + return DZ_B7200; + case 9600: + return DZ_B9600; + default: + return -1; + } +} + + +static void dz_reset(struct dz_port *dport) +{ + struct dz_mux *mux = dport->mux; + + if (mux->initialised) + return; + + dz_out(dport, DZ_CSR, DZ_CLR); + while (dz_in(dport, DZ_CSR) & DZ_CLR); + iob(); + + /* Enable scanning. */ + dz_out(dport, DZ_CSR, DZ_MSE); + + mux->initialised = 1; +} + +static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, + struct ktermios *old_termios) +{ + struct dz_port *dport = to_dport(uport); + unsigned long flags; + unsigned int cflag, baud; + int bflag; + + cflag = dport->port.line; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cflag |= DZ_CS5; + break; + case CS6: + cflag |= DZ_CS6; + break; + case CS7: + cflag |= DZ_CS7; + break; + case CS8: + default: + cflag |= DZ_CS8; + } + + if (termios->c_cflag & CSTOPB) + cflag |= DZ_CSTOPB; + if (termios->c_cflag & PARENB) + cflag |= DZ_PARENB; + if (termios->c_cflag & PARODD) + cflag |= DZ_PARODD; + + baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600); + bflag = dz_encode_baud_rate(baud); + if (bflag < 0) { /* Try to keep unchanged. */ + baud = uart_get_baud_rate(uport, old_termios, NULL, 50, 9600); + bflag = dz_encode_baud_rate(baud); + if (bflag < 0) { /* Resort to 9600. */ + baud = 9600; + bflag = DZ_B9600; + } + tty_termios_encode_baud_rate(termios, baud, baud); + } + cflag |= bflag; + + if (termios->c_cflag & CREAD) + cflag |= DZ_RXENAB; + + spin_lock_irqsave(&dport->port.lock, flags); + + uart_update_timeout(uport, termios->c_cflag, baud); + + dz_out(dport, DZ_LPR, cflag); + dport->cflag = cflag; + + /* setup accept flag */ + dport->port.read_status_mask = DZ_OERR; + if (termios->c_iflag & INPCK) + dport->port.read_status_mask |= DZ_FERR | DZ_PERR; + if (termios->c_iflag & (BRKINT | PARMRK)) + dport->port.read_status_mask |= DZ_BREAK; + + /* characters to ignore */ + uport->ignore_status_mask = 0; + if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) + dport->port.ignore_status_mask |= DZ_OERR; + if (termios->c_iflag & IGNPAR) + dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR; + if (termios->c_iflag & IGNBRK) + dport->port.ignore_status_mask |= DZ_BREAK; + + spin_unlock_irqrestore(&dport->port.lock, flags); +} + +/* + * Hack alert! + * Required solely so that the initial PROM-based console + * works undisturbed in parallel with this one. + */ +static void dz_pm(struct uart_port *uport, unsigned int state, + unsigned int oldstate) +{ + struct dz_port *dport = to_dport(uport); + unsigned long flags; + + spin_lock_irqsave(&dport->port.lock, flags); + if (state < 3) + dz_start_tx(&dport->port); + else + dz_stop_tx(&dport->port); + spin_unlock_irqrestore(&dport->port.lock, flags); +} + + +static const char *dz_type(struct uart_port *uport) +{ + return "DZ"; +} + +static void dz_release_port(struct uart_port *uport) +{ + struct dz_mux *mux = to_dport(uport)->mux; + int map_guard; + + iounmap(uport->membase); + uport->membase = NULL; + + map_guard = atomic_add_return(-1, &mux->map_guard); + if (!map_guard) + release_mem_region(uport->mapbase, dec_kn_slot_size); +} + +static int dz_map_port(struct uart_port *uport) +{ + if (!uport->membase) + uport->membase = ioremap_nocache(uport->mapbase, + dec_kn_slot_size); + if (!uport->membase) { + printk(KERN_ERR "dz: Cannot map MMIO\n"); + return -ENOMEM; + } + return 0; +} + +static int dz_request_port(struct uart_port *uport) +{ + struct dz_mux *mux = to_dport(uport)->mux; + int map_guard; + int ret; + + map_guard = atomic_add_return(1, &mux->map_guard); + if (map_guard == 1) { + if (!request_mem_region(uport->mapbase, dec_kn_slot_size, + "dz")) { + atomic_add(-1, &mux->map_guard); + printk(KERN_ERR + "dz: Unable to reserve MMIO resource\n"); + return -EBUSY; + } + } + ret = dz_map_port(uport); + if (ret) { + map_guard = atomic_add_return(-1, &mux->map_guard); + if (!map_guard) + release_mem_region(uport->mapbase, dec_kn_slot_size); + return ret; + } + return 0; +} + +static void dz_config_port(struct uart_port *uport, int flags) +{ + struct dz_port *dport = to_dport(uport); + + if (flags & UART_CONFIG_TYPE) { + if (dz_request_port(uport)) + return; + + uport->type = PORT_DZ; + + dz_reset(dport); + } +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + */ +static int dz_verify_port(struct uart_port *uport, struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ) + ret = -EINVAL; + if (ser->irq != uport->irq) + ret = -EINVAL; + return ret; +} + +static struct uart_ops dz_ops = { + .tx_empty = dz_tx_empty, + .get_mctrl = dz_get_mctrl, + .set_mctrl = dz_set_mctrl, + .stop_tx = dz_stop_tx, + .start_tx = dz_start_tx, + .stop_rx = dz_stop_rx, + .enable_ms = dz_enable_ms, + .break_ctl = dz_break_ctl, + .startup = dz_startup, + .shutdown = dz_shutdown, + .set_termios = dz_set_termios, + .pm = dz_pm, + .type = dz_type, + .release_port = dz_release_port, + .request_port = dz_request_port, + .config_port = dz_config_port, + .verify_port = dz_verify_port, +}; + +static void __init dz_init_ports(void) +{ + static int first = 1; + unsigned long base; + int line; + + if (!first) + return; + first = 0; + + if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100) + base = dec_kn_slot_base + KN01_DZ11; + else + base = dec_kn_slot_base + KN02_DZ11; + + for (line = 0; line < DZ_NB_PORT; line++) { + struct dz_port *dport = &dz_mux.dport[line]; + struct uart_port *uport = &dport->port; + + dport->mux = &dz_mux; + + uport->irq = dec_interrupt[DEC_IRQ_DZ11]; + uport->fifosize = 1; + uport->iotype = UPIO_MEM; + uport->flags = UPF_BOOT_AUTOCONF; + uport->ops = &dz_ops; + uport->line = line; + uport->mapbase = base; + } +} + +#ifdef CONFIG_SERIAL_DZ_CONSOLE +/* + * ------------------------------------------------------------------- + * dz_console_putchar() -- transmit a character + * + * Polled transmission. This is tricky. We need to mask transmit + * interrupts so that they do not interfere, enable the transmitter + * for the line requested and then wait till the transmit scanner + * requests data for this line. But it may request data for another + * line first, in which case we have to disable its transmitter and + * repeat waiting till our line pops up. Only then the character may + * be transmitted. Finally, the state of the transmitter mask is + * restored. Welcome to the world of PDP-11! + * ------------------------------------------------------------------- + */ +static void dz_console_putchar(struct uart_port *uport, int ch) +{ + struct dz_port *dport = to_dport(uport); + unsigned long flags; + unsigned short csr, tcr, trdy, mask; + int loops = 10000; + + spin_lock_irqsave(&dport->port.lock, flags); + csr = dz_in(dport, DZ_CSR); + dz_out(dport, DZ_CSR, csr & ~DZ_TIE); + tcr = dz_in(dport, DZ_TCR); + tcr |= 1 << dport->port.line; + mask = tcr; + dz_out(dport, DZ_TCR, mask); + iob(); + spin_unlock_irqrestore(&dport->port.lock, flags); + + do { + trdy = dz_in(dport, DZ_CSR); + if (!(trdy & DZ_TRDY)) + continue; + trdy = (trdy & DZ_TLINE) >> 8; + if (trdy == dport->port.line) + break; + mask &= ~(1 << trdy); + dz_out(dport, DZ_TCR, mask); + iob(); + udelay(2); + } while (--loops); + + if (loops) /* Cannot send otherwise. */ + dz_out(dport, DZ_TDR, ch); + + dz_out(dport, DZ_TCR, tcr); + dz_out(dport, DZ_CSR, csr); +} + +/* + * ------------------------------------------------------------------- + * dz_console_print () + * + * dz_console_print is registered for printk. + * The console must be locked when we get here. + * ------------------------------------------------------------------- + */ +static void dz_console_print(struct console *co, + const char *str, + unsigned int count) +{ + struct dz_port *dport = &dz_mux.dport[co->index]; +#ifdef DEBUG_DZ + prom_printf((char *) str); +#endif + uart_console_write(&dport->port, str, count, dz_console_putchar); +} + +static int __init dz_console_setup(struct console *co, char *options) +{ + struct dz_port *dport = &dz_mux.dport[co->index]; + struct uart_port *uport = &dport->port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + ret = dz_map_port(uport); + if (ret) + return ret; + + spin_lock_init(&dport->port.lock); /* For dz_pm(). */ + + dz_reset(dport); + dz_pm(uport, 0, -1); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&dport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver dz_reg; +static struct console dz_console = { + .name = "ttyS", + .write = dz_console_print, + .device = uart_console_device, + .setup = dz_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &dz_reg, +}; + +static int __init dz_serial_console_init(void) +{ + if (!IOASIC) { + dz_init_ports(); + register_console(&dz_console); + return 0; + } else + return -ENXIO; +} + +console_initcall(dz_serial_console_init); + +#define SERIAL_DZ_CONSOLE &dz_console +#else +#define SERIAL_DZ_CONSOLE NULL +#endif /* CONFIG_SERIAL_DZ_CONSOLE */ + +static struct uart_driver dz_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = DZ_NB_PORT, + .cons = SERIAL_DZ_CONSOLE, +}; + +static int __init dz_init(void) +{ + int ret, i; + + if (IOASIC) + return -ENXIO; + + printk("%s%s\n", dz_name, dz_version); + + dz_init_ports(); + + ret = uart_register_driver(&dz_reg); + if (ret) + return ret; + + for (i = 0; i < DZ_NB_PORT; i++) + uart_add_one_port(&dz_reg, &dz_mux.dport[i].port); + + return 0; +} + +module_init(dz_init); diff --git a/drivers/tty/serial/dz.h b/drivers/tty/serial/dz.h new file mode 100644 index 000000000000..faf169ed27b3 --- /dev/null +++ b/drivers/tty/serial/dz.h @@ -0,0 +1,129 @@ +/* + * dz.h: Serial port driver for DECstations equipped + * with the DZ chipset. + * + * Copyright (C) 1998 Olivier A. D. Lebaillif + * + * Email: olivier.lebaillif@ifrsys.com + * + * Copyright (C) 2004, 2006 Maciej W. Rozycki + */ +#ifndef DZ_SERIAL_H +#define DZ_SERIAL_H + +/* + * Definitions for the Control and Status Register. + */ +#define DZ_TRDY 0x8000 /* Transmitter empty */ +#define DZ_TIE 0x4000 /* Transmitter Interrupt Enbl */ +#define DZ_TLINE 0x0300 /* Transmitter Line Number */ +#define DZ_RDONE 0x0080 /* Receiver data ready */ +#define DZ_RIE 0x0040 /* Receive Interrupt Enable */ +#define DZ_MSE 0x0020 /* Master Scan Enable */ +#define DZ_CLR 0x0010 /* Master reset */ +#define DZ_MAINT 0x0008 /* Loop Back Mode */ + +/* + * Definitions for the Receiver Buffer Register. + */ +#define DZ_RBUF_MASK 0x00FF /* Data Mask */ +#define DZ_LINE_MASK 0x0300 /* Line Mask */ +#define DZ_DVAL 0x8000 /* Valid Data indicator */ +#define DZ_OERR 0x4000 /* Overrun error indicator */ +#define DZ_FERR 0x2000 /* Frame error indicator */ +#define DZ_PERR 0x1000 /* Parity error indicator */ + +#define DZ_BREAK 0x0800 /* BREAK event software flag */ + +#define LINE(x) ((x & DZ_LINE_MASK) >> 8) /* Get the line number + from the input buffer */ +#define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK)) + +/* + * Definitions for the Transmit Control Register. + */ +#define DZ_LINE_KEYBOARD 0x0001 +#define DZ_LINE_MOUSE 0x0002 +#define DZ_LINE_MODEM 0x0004 +#define DZ_LINE_PRINTER 0x0008 + +#define DZ_MODEM_RTS 0x0800 /* RTS for the modem line (2) */ +#define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */ +#define DZ_PRINT_RTS 0x0200 /* RTS for the prntr line (3) */ +#define DZ_PRINT_DTR 0x0100 /* DTR for the prntr line (3) */ +#define DZ_LNENB 0x000f /* Transmitter Line Enable */ + +/* + * Definitions for the Modem Status Register. + */ +#define DZ_MODEM_RI 0x0800 /* RI for the modem line (2) */ +#define DZ_MODEM_CD 0x0400 /* CD for the modem line (2) */ +#define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */ +#define DZ_MODEM_CTS 0x0100 /* CTS for the modem line (2) */ +#define DZ_PRINT_RI 0x0008 /* RI for the printer line (3) */ +#define DZ_PRINT_CD 0x0004 /* CD for the printer line (3) */ +#define DZ_PRINT_DSR 0x0002 /* DSR for the prntr line (3) */ +#define DZ_PRINT_CTS 0x0001 /* CTS for the prntr line (3) */ + +/* + * Definitions for the Transmit Data Register. + */ +#define DZ_BRK0 0x0100 /* Break assertion for line 0 */ +#define DZ_BRK1 0x0200 /* Break assertion for line 1 */ +#define DZ_BRK2 0x0400 /* Break assertion for line 2 */ +#define DZ_BRK3 0x0800 /* Break assertion for line 3 */ + +/* + * Definitions for the Line Parameter Register. + */ +#define DZ_KEYBOARD 0x0000 /* line 0 = keyboard */ +#define DZ_MOUSE 0x0001 /* line 1 = mouse */ +#define DZ_MODEM 0x0002 /* line 2 = modem */ +#define DZ_PRINTER 0x0003 /* line 3 = printer */ + +#define DZ_CSIZE 0x0018 /* Number of bits per byte (mask) */ +#define DZ_CS5 0x0000 /* 5 bits per byte */ +#define DZ_CS6 0x0008 /* 6 bits per byte */ +#define DZ_CS7 0x0010 /* 7 bits per byte */ +#define DZ_CS8 0x0018 /* 8 bits per byte */ + +#define DZ_CSTOPB 0x0020 /* 2 stop bits instead of one */ + +#define DZ_PARENB 0x0040 /* Parity enable */ +#define DZ_PARODD 0x0080 /* Odd parity instead of even */ + +#define DZ_CBAUD 0x0E00 /* Baud Rate (mask) */ +#define DZ_B50 0x0000 +#define DZ_B75 0x0100 +#define DZ_B110 0x0200 +#define DZ_B134 0x0300 +#define DZ_B150 0x0400 +#define DZ_B300 0x0500 +#define DZ_B600 0x0600 +#define DZ_B1200 0x0700 +#define DZ_B1800 0x0800 +#define DZ_B2000 0x0900 +#define DZ_B2400 0x0A00 +#define DZ_B3600 0x0B00 +#define DZ_B4800 0x0C00 +#define DZ_B7200 0x0D00 +#define DZ_B9600 0x0E00 + +#define DZ_RXENAB 0x1000 /* Receiver Enable */ + +/* + * Addresses for the DZ registers + */ +#define DZ_CSR 0x00 /* Control and Status Register */ +#define DZ_RBUF 0x08 /* Receive Buffer */ +#define DZ_LPR 0x08 /* Line Parameters Register */ +#define DZ_TCR 0x10 /* Transmitter Control Register */ +#define DZ_MSR 0x18 /* Modem Status Register */ +#define DZ_TDR 0x18 /* Transmit Data Register */ + +#define DZ_NB_PORT 4 + +#define DZ_XMIT_SIZE 4096 /* buffer size */ +#define DZ_WAKEUP_CHARS DZ_XMIT_SIZE/4 + +#endif /* DZ_SERIAL_H */ diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c new file mode 100644 index 000000000000..53a468227056 --- /dev/null +++ b/drivers/tty/serial/icom.c @@ -0,0 +1,1658 @@ +/* + * icom.c + * + * Copyright (C) 2001 IBM Corporation. All rights reserved. + * + * Serial device driver. + * + * Based on code from serial.c + * + * 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 + * + */ +#define SERIAL_DO_RESTART +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "icom.h" + +/*#define ICOM_TRACE enable port trace capabilities */ + +#define ICOM_DRIVER_NAME "icom" +#define ICOM_VERSION_STR "1.3.1" +#define NR_PORTS 128 +#define ICOM_PORT ((struct icom_port *)port) +#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref) + +static const struct pci_device_id icom_pci_table[] = { + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = ADAPTER_V1, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, + .driver_data = ADAPTER_V2, + }, + { + .vendor = PCI_VENDOR_ID_IBM, + .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE, + .driver_data = ADAPTER_V2, + }, + {} +}; + +struct lookup_proc_table start_proc[4] = { + {NULL, ICOM_CONTROL_START_A}, + {NULL, ICOM_CONTROL_START_B}, + {NULL, ICOM_CONTROL_START_C}, + {NULL, ICOM_CONTROL_START_D} +}; + + +struct lookup_proc_table stop_proc[4] = { + {NULL, ICOM_CONTROL_STOP_A}, + {NULL, ICOM_CONTROL_STOP_B}, + {NULL, ICOM_CONTROL_STOP_C}, + {NULL, ICOM_CONTROL_STOP_D} +}; + +struct lookup_int_table int_mask_tbl[4] = { + {NULL, ICOM_INT_MASK_PRC_A}, + {NULL, ICOM_INT_MASK_PRC_B}, + {NULL, ICOM_INT_MASK_PRC_C}, + {NULL, ICOM_INT_MASK_PRC_D}, +}; + + +MODULE_DEVICE_TABLE(pci, icom_pci_table); + +static LIST_HEAD(icom_adapter_head); + +/* spinlock for adapter initialization and changing adapter operations */ +static spinlock_t icom_lock; + +#ifdef ICOM_TRACE +static inline void trace(struct icom_port *icom_port, char *trace_pt, + unsigned long trace_data) +{ + dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", + icom_port->port, trace_pt, trace_data); +} +#else +static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; +#endif +static void icom_kref_release(struct kref *kref); + +static void free_port_memory(struct icom_port *icom_port) +{ + struct pci_dev *dev = icom_port->adapter->pci_dev; + + trace(icom_port, "RET_PORT_MEM", 0); + if (icom_port->recv_buf) { + pci_free_consistent(dev, 4096, icom_port->recv_buf, + icom_port->recv_buf_pci); + icom_port->recv_buf = NULL; + } + if (icom_port->xmit_buf) { + pci_free_consistent(dev, 4096, icom_port->xmit_buf, + icom_port->xmit_buf_pci); + icom_port->xmit_buf = NULL; + } + if (icom_port->statStg) { + pci_free_consistent(dev, 4096, icom_port->statStg, + icom_port->statStg_pci); + icom_port->statStg = NULL; + } + + if (icom_port->xmitRestart) { + pci_free_consistent(dev, 4096, icom_port->xmitRestart, + icom_port->xmitRestart_pci); + icom_port->xmitRestart = NULL; + } +} + +static int __devinit get_port_memory(struct icom_port *icom_port) +{ + int index; + unsigned long stgAddr; + unsigned long startStgAddr; + unsigned long offset; + struct pci_dev *dev = icom_port->adapter->pci_dev; + + icom_port->xmit_buf = + pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci); + if (!icom_port->xmit_buf) { + dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); + return -ENOMEM; + } + + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->xmit_buf); + + icom_port->recv_buf = + pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci); + if (!icom_port->recv_buf) { + dev_err(&dev->dev, "Can not allocate Receive buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->recv_buf); + + icom_port->statStg = + pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci); + if (!icom_port->statStg) { + dev_err(&dev->dev, "Can not allocate Status buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + trace(icom_port, "GET_PORT_MEM", + (unsigned long) icom_port->statStg); + + icom_port->xmitRestart = + pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci); + if (!icom_port->xmitRestart) { + dev_err(&dev->dev, + "Can not allocate xmit Restart buffer\n"); + free_port_memory(icom_port); + return -ENOMEM; + } + + memset(icom_port->statStg, 0, 4096); + + /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that + indicates that frames are to be transmitted + */ + + stgAddr = (unsigned long) icom_port->statStg; + for (index = 0; index < NUM_XBUFFS; index++) { + trace(icom_port, "FOD_ADDR", stgAddr); + stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]); + if (index < (NUM_XBUFFS - 1)) { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + icom_port->statStg->xmit[index].leLengthASD = + (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + trace(icom_port, "FOD_ADDR", stgAddr); + trace(icom_port, "FOD_XBUFF", + (unsigned long) icom_port->xmit_buf); + icom_port->statStg->xmit[index].leBuffer = + cpu_to_le32(icom_port->xmit_buf_pci); + } else if (index == (NUM_XBUFFS - 1)) { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + icom_port->statStg->xmit[index].leLengthASD = + (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ); + trace(icom_port, "FOD_XBUFF", + (unsigned long) icom_port->xmit_buf); + icom_port->statStg->xmit[index].leBuffer = + cpu_to_le32(icom_port->xmit_buf_pci); + } else { + memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); + } + } + /* FIDs */ + startStgAddr = stgAddr; + + /* fill in every entry, even if no buffer */ + for (index = 0; index < NUM_RBUFFS; index++) { + trace(icom_port, "FID_ADDR", stgAddr); + stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]); + icom_port->statStg->rcv[index].leLength = 0; + icom_port->statStg->rcv[index].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + if (index < (NUM_RBUFFS - 1) ) { + offset = stgAddr - (unsigned long) icom_port->statStg; + icom_port->statStg->rcv[index].leNext = + cpu_to_le32(icom_port-> statStg_pci + offset); + trace(icom_port, "FID_RBUFF", + (unsigned long) icom_port->recv_buf); + icom_port->statStg->rcv[index].leBuffer = + cpu_to_le32(icom_port->recv_buf_pci); + } else if (index == (NUM_RBUFFS -1) ) { + offset = startStgAddr - (unsigned long) icom_port->statStg; + icom_port->statStg->rcv[index].leNext = + cpu_to_le32(icom_port-> statStg_pci + offset); + trace(icom_port, "FID_RBUFF", + (unsigned long) icom_port->recv_buf + 2048); + icom_port->statStg->rcv[index].leBuffer = + cpu_to_le32(icom_port->recv_buf_pci + 2048); + } else { + icom_port->statStg->rcv[index].leNext = 0; + icom_port->statStg->rcv[index].leBuffer = 0; + } + } + + return 0; +} + +static void stop_processor(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + + port = icom_port->port; + if (port == 0 || port == 1) + stop_proc[port].global_control_reg = &icom_port->global_reg->control; + else + stop_proc[port].global_control_reg = &icom_port->global_reg->control_2; + + + if (port < 4) { + temp = readl(stop_proc[port].global_control_reg); + temp = + (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; + writel(temp, stop_proc[port].global_control_reg); + + /* write flush */ + readl(stop_proc[port].global_control_reg); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); +} + +static void start_processor(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + + port = icom_port->port; + if (port == 0 || port == 1) + start_proc[port].global_control_reg = &icom_port->global_reg->control; + else + start_proc[port].global_control_reg = &icom_port->global_reg->control_2; + if (port < 4) { + temp = readl(start_proc[port].global_control_reg); + temp = + (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; + writel(temp, start_proc[port].global_control_reg); + + /* write flush */ + readl(start_proc[port].global_control_reg); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); +} + +static void load_code(struct icom_port *icom_port) +{ + const struct firmware *fw; + char __iomem *iram_ptr; + int index; + int status = 0; + void __iomem *dram_ptr = icom_port->dram; + dma_addr_t temp_pci; + unsigned char *new_page = NULL; + unsigned char cable_id = NO_CABLE; + struct pci_dev *dev = icom_port->adapter->pci_dev; + + /* Clear out any pending interrupts */ + writew(0x3FFF, icom_port->int_reg); + + trace(icom_port, "CLEAR_INTERRUPTS", 0); + + /* Stop processor */ + stop_processor(icom_port); + + /* Zero out DRAM */ + memset_io(dram_ptr, 0, 512); + + /* Load Call Setup into Adapter */ + if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_DCE_IRAM_OFFSET) { + dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET; + for (index = 0; index < fw->size; index++) + writeb(fw->data[index], &iram_ptr[index]); + + release_firmware(fw); + + /* Load Resident DCE portion of Adapter */ + if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_IRAM_SIZE) { + dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET; + for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++) + writeb(fw->data[index], &iram_ptr[index]); + + release_firmware(fw); + + /* Set Hardware level */ + if (icom_port->adapter->version == ADAPTER_V2) + writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); + + /* Start the processor in Adapter */ + start_processor(icom_port); + + writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL), + &(icom_port->dram->HDLCConfigReg)); + writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0x00, &(icom_port->dram->CmdReg)); + writeb(0x10, &(icom_port->dram->async_config3)); + writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC | + ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2)); + + /*Set up data in icom DRAM to indicate where personality + *code is located and its length. + */ + new_page = pci_alloc_consistent(dev, 4096, &temp_pci); + + if (!new_page) { + dev_err(&dev->dev, "Can not allocate DMA buffer\n"); + status = -1; + goto load_code_exit; + } + + if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) { + dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n"); + status = -1; + goto load_code_exit; + } + + if (fw->size > ICOM_DCE_IRAM_OFFSET) { + dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n"); + release_firmware(fw); + status = -1; + goto load_code_exit; + } + + for (index = 0; index < fw->size; index++) + new_page[index] = fw->data[index]; + + release_firmware(fw); + + writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); + writel(temp_pci, &icom_port->dram->mac_load_addr); + + /*Setting the syncReg to 0x80 causes adapter to start downloading + the personality code into adapter instruction RAM. + Once code is loaded, it will begin executing and, based on + information provided above, will start DMAing data from + shared memory to adapter DRAM. + */ + /* the wait loop below verifies this write operation has been done + and processed + */ + writeb(START_DOWNLOAD, &icom_port->dram->sync); + + /* Wait max 1 Sec for data download and processor to start */ + for (index = 0; index < 10; index++) { + msleep(100); + if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE) + break; + } + + if (index == 10) + status = -1; + + /* + * check Cable ID + */ + cable_id = readb(&icom_port->dram->cable_id); + + if (cable_id & ICOM_CABLE_ID_VALID) { + /* Get cable ID into the lower 4 bits (standard form) */ + cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4; + icom_port->cable_id = cable_id; + } else { + dev_err(&dev->dev,"Invalid or no cable attached\n"); + icom_port->cable_id = NO_CABLE; + } + + load_code_exit: + + if (status != 0) { + /* Clear out any pending interrupts */ + writew(0x3FFF, icom_port->int_reg); + + /* Turn off port */ + writeb(ICOM_DISABLE, &(icom_port->dram->disable)); + + /* Stop processor */ + stop_processor(icom_port); + + dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n"); + } + + if (new_page != NULL) + pci_free_consistent(dev, 4096, new_page, temp_pci); +} + +static int startup(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned char cable_id, raw_cable_id; + unsigned long flags; + int port; + + trace(icom_port, "STARTUP", 0); + + if (!icom_port->dram) { + /* should NEVER be NULL */ + dev_err(&icom_port->adapter->pci_dev->dev, + "Unusable Port, port configuration missing\n"); + return -ENODEV; + } + + /* + * check Cable ID + */ + raw_cable_id = readb(&icom_port->dram->cable_id); + trace(icom_port, "CABLE_ID", raw_cable_id); + + /* Get cable ID into the lower 4 bits (standard form) */ + cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; + + /* Check for valid Cable ID */ + if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || + (cable_id != icom_port->cable_id)) { + + /* reload adapter code, pick up any potential changes in cable id */ + load_code(icom_port); + + /* still no sign of cable, error out */ + raw_cable_id = readb(&icom_port->dram->cable_id); + cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; + if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || + (icom_port->cable_id == NO_CABLE)) + return -EIO; + } + + /* + * Finally, clear and enable interrupts + */ + spin_lock_irqsave(&icom_lock, flags); + port = icom_port->port; + if (port == 0 || port == 1) + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; + else + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; + + if (port == 0 || port == 2) + writew(0x00FF, icom_port->int_reg); + else + writew(0x3F00, icom_port->int_reg); + if (port < 4) { + temp = readl(int_mask_tbl[port].global_int_mask); + writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); + + /* write flush */ + readl(int_mask_tbl[port].global_int_mask); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + + spin_unlock_irqrestore(&icom_lock, flags); + return 0; +} + +static void shutdown(struct icom_port *icom_port) +{ + unsigned long temp; + unsigned char cmdReg; + unsigned long flags; + int port; + + spin_lock_irqsave(&icom_lock, flags); + trace(icom_port, "SHUTDOWN", 0); + + /* + * disable all interrupts + */ + port = icom_port->port; + if (port == 0 || port == 1) + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; + else + int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; + + if (port < 4) { + temp = readl(int_mask_tbl[port].global_int_mask); + writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); + + /* write flush */ + readl(int_mask_tbl[port].global_int_mask); + } else { + dev_err(&icom_port->adapter->pci_dev->dev, + "Invalid port assignment\n"); + } + spin_unlock_irqrestore(&icom_lock, flags); + + /* + * disable break condition + */ + cmdReg = readb(&icom_port->dram->CmdReg); + if (cmdReg & CMD_SND_BREAK) { + writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); + } +} + +static int icom_write(struct uart_port *port) +{ + unsigned long data_count; + unsigned char cmdReg; + unsigned long offset; + int temp_tail = port->state->xmit.tail; + + trace(ICOM_PORT, "WRITE", 0); + + if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) { + trace(ICOM_PORT, "WRITE_FULL", 0); + return 0; + } + + data_count = 0; + while ((port->state->xmit.head != temp_tail) && + (data_count <= XMIT_BUFF_SZ)) { + + ICOM_PORT->xmit_buf[data_count++] = + port->state->xmit.buf[temp_tail]; + + temp_tail++; + temp_tail &= (UART_XMIT_SIZE - 1); + } + + if (data_count) { + ICOM_PORT->statStg->xmit[0].flags = + cpu_to_le16(SA_FLAGS_READY_TO_XMIT); + ICOM_PORT->statStg->xmit[0].leLength = + cpu_to_le16(data_count); + offset = + (unsigned long) &ICOM_PORT->statStg->xmit[0] - + (unsigned long) ICOM_PORT->statStg; + *ICOM_PORT->xmitRestart = + cpu_to_le32(ICOM_PORT->statStg_pci + offset); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_XMIT_RCV_ENABLE, + &ICOM_PORT->dram->CmdReg); + writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd); + trace(ICOM_PORT, "WRITE_START", data_count); + /* write flush */ + readb(&ICOM_PORT->dram->StartXmitCmd); + } + + return data_count; +} + +static inline void check_modem_status(struct icom_port *icom_port) +{ + static char old_status = 0; + char delta_status; + unsigned char status; + + spin_lock(&icom_port->uart_port.lock); + + /*modem input register */ + status = readb(&icom_port->dram->isr); + trace(icom_port, "CHECK_MODEM", status); + delta_status = status ^ old_status; + if (delta_status) { + if (delta_status & ICOM_RI) + icom_port->uart_port.icount.rng++; + if (delta_status & ICOM_DSR) + icom_port->uart_port.icount.dsr++; + if (delta_status & ICOM_DCD) + uart_handle_dcd_change(&icom_port->uart_port, + delta_status & ICOM_DCD); + if (delta_status & ICOM_CTS) + uart_handle_cts_change(&icom_port->uart_port, + delta_status & ICOM_CTS); + + wake_up_interruptible(&icom_port->uart_port.state-> + port.delta_msr_wait); + old_status = status; + } + spin_unlock(&icom_port->uart_port.lock); +} + +static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) +{ + unsigned short int count; + int i; + + if (port_int_reg & (INT_XMIT_COMPLETED)) { + trace(icom_port, "XMIT_COMPLETE", 0); + + /* clear buffer in use bit */ + icom_port->statStg->xmit[0].flags &= + cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); + + count = (unsigned short int) + cpu_to_le16(icom_port->statStg->xmit[0].leLength); + icom_port->uart_port.icount.tx += count; + + for (i=0; iuart_port.state->xmit); i++) { + + icom_port->uart_port.state->xmit.tail++; + icom_port->uart_port.state->xmit.tail &= + (UART_XMIT_SIZE - 1); + } + + if (!icom_write(&icom_port->uart_port)) + /* activate write queue */ + uart_write_wakeup(&icom_port->uart_port); + } else + trace(icom_port, "XMIT_DISABLED", 0); +} + +static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) +{ + short int count, rcv_buff; + struct tty_struct *tty = icom_port->uart_port.state->port.tty; + unsigned short int status; + struct uart_icount *icount; + unsigned long offset; + unsigned char flag; + + trace(icom_port, "RCV_COMPLETE", 0); + rcv_buff = icom_port->next_rcv; + + status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + while (status & SA_FL_RCV_DONE) { + int first = -1; + + trace(icom_port, "FID_STATUS", status); + count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); + + trace(icom_port, "RCV_COUNT", count); + + trace(icom_port, "REAL_COUNT", count); + + offset = + cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - + icom_port->recv_buf_pci; + + /* Block copy all but the last byte as this may have status */ + if (count > 0) { + first = icom_port->recv_buf[offset]; + tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1); + } + + icount = &icom_port->uart_port.icount; + icount->rx += count; + + /* Break detect logic */ + if ((status & SA_FLAGS_FRAME_ERROR) + && first == 0) { + status &= ~SA_FLAGS_FRAME_ERROR; + status |= SA_FLAGS_BREAK_DET; + trace(icom_port, "BREAK_DET", 0); + } + + flag = TTY_NORMAL; + + if (status & + (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | + SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { + + if (status & SA_FLAGS_BREAK_DET) + icount->brk++; + if (status & SA_FLAGS_PARITY_ERROR) + icount->parity++; + if (status & SA_FLAGS_FRAME_ERROR) + icount->frame++; + if (status & SA_FLAGS_OVERRUN) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (status & icom_port->ignore_status_mask) { + trace(icom_port, "IGNORE_CHAR", 0); + goto ignore_char; + } + + status &= icom_port->read_status_mask; + + if (status & SA_FLAGS_BREAK_DET) { + flag = TTY_BREAK; + } else if (status & SA_FLAGS_PARITY_ERROR) { + trace(icom_port, "PARITY_ERROR", 0); + flag = TTY_PARITY; + } else if (status & SA_FLAGS_FRAME_ERROR) + flag = TTY_FRAME; + + } + + tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag); + + if (status & SA_FLAGS_OVERRUN) + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); +ignore_char: + icom_port->statStg->rcv[rcv_buff].flags = 0; + icom_port->statStg->rcv[rcv_buff].leLength = 0; + icom_port->statStg->rcv[rcv_buff].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + + rcv_buff++; + if (rcv_buff == NUM_RBUFFS) + rcv_buff = 0; + + status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); + } + icom_port->next_rcv = rcv_buff; + tty_flip_buffer_push(tty); +} + +static void process_interrupt(u16 port_int_reg, + struct icom_port *icom_port) +{ + + spin_lock(&icom_port->uart_port.lock); + trace(icom_port, "INTERRUPT", port_int_reg); + + if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) + xmit_interrupt(port_int_reg, icom_port); + + if (port_int_reg & INT_RCV_COMPLETED) + recv_interrupt(port_int_reg, icom_port); + + spin_unlock(&icom_port->uart_port.lock); +} + +static irqreturn_t icom_interrupt(int irq, void *dev_id) +{ + void __iomem * int_reg; + u32 adapter_interrupts; + u16 port_int_reg; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; + + /* find icom_port for this interrupt */ + icom_adapter = (struct icom_adapter *) dev_id; + + if (icom_adapter->version == ADAPTER_V2) { + int_reg = icom_adapter->base_addr + 0x8024; + + adapter_interrupts = readl(int_reg); + + if (adapter_interrupts & 0x00003FFF) { + /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */ + icom_port = &icom_adapter->port_info[2]; + port_int_reg = (u16) adapter_interrupts; + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + if (adapter_interrupts & 0x3FFF0000) { + /* port 3 interrupt */ + icom_port = &icom_adapter->port_info[3]; + if (icom_port->status == ICOM_PORT_ACTIVE) { + port_int_reg = + (u16) (adapter_interrupts >> 16); + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + } + + /* Clear out any pending interrupts */ + writel(adapter_interrupts, int_reg); + + int_reg = icom_adapter->base_addr + 0x8004; + } else { + int_reg = icom_adapter->base_addr + 0x4004; + } + + adapter_interrupts = readl(int_reg); + + if (adapter_interrupts & 0x00003FFF) { + /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */ + icom_port = &icom_adapter->port_info[0]; + port_int_reg = (u16) adapter_interrupts; + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + if (adapter_interrupts & 0x3FFF0000) { + /* port 1 interrupt */ + icom_port = &icom_adapter->port_info[1]; + if (icom_port->status == ICOM_PORT_ACTIVE) { + port_int_reg = (u16) (adapter_interrupts >> 16); + process_interrupt(port_int_reg, icom_port); + check_modem_status(icom_port); + } + } + + /* Clear out any pending interrupts */ + writel(adapter_interrupts, int_reg); + + /* flush the write */ + adapter_interrupts = readl(int_reg); + + return IRQ_HANDLED; +} + +/* + * ------------------------------------------------------------------ + * Begin serial-core API + * ------------------------------------------------------------------ + */ +static unsigned int icom_tx_empty(struct uart_port *port) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & + SA_FLAGS_READY_TO_XMIT) + ret = TIOCSER_TEMT; + else + ret = 0; + + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned char local_osr; + + trace(ICOM_PORT, "SET_MODEM", 0); + local_osr = readb(&ICOM_PORT->dram->osr); + + if (mctrl & TIOCM_RTS) { + trace(ICOM_PORT, "RAISE_RTS", 0); + local_osr |= ICOM_RTS; + } else { + trace(ICOM_PORT, "LOWER_RTS", 0); + local_osr &= ~ICOM_RTS; + } + + if (mctrl & TIOCM_DTR) { + trace(ICOM_PORT, "RAISE_DTR", 0); + local_osr |= ICOM_DTR; + } else { + trace(ICOM_PORT, "LOWER_DTR", 0); + local_osr &= ~ICOM_DTR; + } + + writeb(local_osr, &ICOM_PORT->dram->osr); +} + +static unsigned int icom_get_mctrl(struct uart_port *port) +{ + unsigned char status; + unsigned int result; + + trace(ICOM_PORT, "GET_MODEM", 0); + + status = readb(&ICOM_PORT->dram->isr); + + result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) + | ((status & ICOM_RI) ? TIOCM_RNG : 0) + | ((status & ICOM_DSR) ? TIOCM_DSR : 0) + | ((status & ICOM_CTS) ? TIOCM_CTS : 0); + return result; +} + +static void icom_stop_tx(struct uart_port *port) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "STOP", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); +} + +static void icom_start_tx(struct uart_port *port) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "START", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) + writeb(cmdReg & ~CMD_HOLD_XMIT, + &ICOM_PORT->dram->CmdReg); + + icom_write(port); +} + +static void icom_send_xchar(struct uart_port *port, char ch) +{ + unsigned char xdata; + int index; + unsigned long flags; + + trace(ICOM_PORT, "SEND_XCHAR", ch); + + /* wait .1 sec to send char */ + for (index = 0; index < 10; index++) { + spin_lock_irqsave(&port->lock, flags); + xdata = readb(&ICOM_PORT->dram->xchar); + if (xdata == 0x00) { + trace(ICOM_PORT, "QUICK_WRITE", 0); + writeb(ch, &ICOM_PORT->dram->xchar); + + /* flush write operation */ + xdata = readb(&ICOM_PORT->dram->xchar); + spin_unlock_irqrestore(&port->lock, flags); + break; + } + spin_unlock_irqrestore(&port->lock, flags); + msleep(10); + } +} + +static void icom_stop_rx(struct uart_port *port) +{ + unsigned char cmdReg; + + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); +} + +static void icom_enable_ms(struct uart_port *port) +{ + /* no-op */ +} + +static void icom_break(struct uart_port *port, int break_state) +{ + unsigned char cmdReg; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + trace(ICOM_PORT, "BREAK", 0); + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + if (break_state == -1) { + writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + } else { + writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static int icom_open(struct uart_port *port) +{ + int retval; + + kref_get(&ICOM_PORT->adapter->kref); + retval = startup(ICOM_PORT); + + if (retval) { + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); + trace(ICOM_PORT, "STARTUP_ERROR", 0); + return retval; + } + + return 0; +} + +static void icom_close(struct uart_port *port) +{ + unsigned char cmdReg; + + trace(ICOM_PORT, "CLOSE", 0); + + /* stop receiver */ + cmdReg = readb(&ICOM_PORT->dram->CmdReg); + writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE, + &ICOM_PORT->dram->CmdReg); + + shutdown(ICOM_PORT); + + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); +} + +static void icom_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old_termios) +{ + int baud; + unsigned cflag, iflag; + char new_config2; + char new_config3 = 0; + char tmp_byte; + int index; + int rcv_buff, xmit_buff; + unsigned long offset; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + trace(ICOM_PORT, "CHANGE_SPEED", 0); + + cflag = termios->c_cflag; + iflag = termios->c_iflag; + + new_config2 = ICOM_ACFG_DRIVE1; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: /* 5 bits/char */ + new_config2 |= ICOM_ACFG_5BPC; + break; + case CS6: /* 6 bits/char */ + new_config2 |= ICOM_ACFG_6BPC; + break; + case CS7: /* 7 bits/char */ + new_config2 |= ICOM_ACFG_7BPC; + break; + case CS8: /* 8 bits/char */ + new_config2 |= ICOM_ACFG_8BPC; + break; + default: + break; + } + if (cflag & CSTOPB) { + /* 2 stop bits */ + new_config2 |= ICOM_ACFG_2STOP_BIT; + } + if (cflag & PARENB) { + /* parity bit enabled */ + new_config2 |= ICOM_ACFG_PARITY_ENAB; + trace(ICOM_PORT, "PARENB", 0); + } + if (cflag & PARODD) { + /* odd parity */ + new_config2 |= ICOM_ACFG_PARITY_ODD; + trace(ICOM_PORT, "PARODD", 0); + } + + /* Determine divisor based on baud rate */ + baud = uart_get_baud_rate(port, termios, old_termios, + icom_acfg_baud[0], + icom_acfg_baud[BAUD_TABLE_LIMIT]); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + + for (index = 0; index < BAUD_TABLE_LIMIT; index++) { + if (icom_acfg_baud[index] == baud) { + new_config3 = index; + break; + } + } + + uart_update_timeout(port, cflag, baud); + + /* CTS flow control flag and modem status interrupts */ + tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + if (cflag & CRTSCTS) + tmp_byte |= HDLC_HDW_FLOW; + else + tmp_byte &= ~HDLC_HDW_FLOW; + writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + + /* + * Set up parity check flag + */ + ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; + if (iflag & INPCK) + ICOM_PORT->read_status_mask |= + SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR; + + if ((iflag & BRKINT) || (iflag & PARMRK)) + ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET; + + /* + * Characters to ignore + */ + ICOM_PORT->ignore_status_mask = 0; + if (iflag & IGNPAR) + ICOM_PORT->ignore_status_mask |= + SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR; + if (iflag & IGNBRK) { + ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (iflag & IGNPAR) + ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN; + } + + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE; + + /* Turn off Receiver to prepare for reset */ + writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg); + + for (index = 0; index < 10; index++) { + if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) { + break; + } + } + + /* clear all current buffers of data */ + for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) { + ICOM_PORT->statStg->rcv[rcv_buff].flags = 0; + ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0; + ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength = + (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); + } + + for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) { + ICOM_PORT->statStg->xmit[xmit_buff].flags = 0; + } + + /* activate changes and start xmit and receiver here */ + /* Enable the receiver */ + writeb(new_config3, &(ICOM_PORT->dram->async_config3)); + writeb(new_config2, &(ICOM_PORT->dram->async_config2)); + tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg)); + tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL; + writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg)); + writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */ + writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */ + + /* reset processor */ + writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg); + + for (index = 0; index < 10; index++) { + if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) { + break; + } + } + + /* Enable Transmitter and Reciever */ + offset = + (unsigned long) &ICOM_PORT->statStg->rcv[0] - + (unsigned long) ICOM_PORT->statStg; + writel(ICOM_PORT->statStg_pci + offset, + &ICOM_PORT->dram->RcvStatusAddr); + ICOM_PORT->next_rcv = 0; + ICOM_PORT->put_length = 0; + *ICOM_PORT->xmitRestart = 0; + writel(ICOM_PORT->xmitRestart_pci, + &ICOM_PORT->dram->XmitStatusAddr); + trace(ICOM_PORT, "XR_ENAB", 0); + writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *icom_type(struct uart_port *port) +{ + return "icom"; +} + +static void icom_release_port(struct uart_port *port) +{ +} + +static int icom_request_port(struct uart_port *port) +{ + return 0; +} + +static void icom_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_ICOM; +} + +static struct uart_ops icom_ops = { + .tx_empty = icom_tx_empty, + .set_mctrl = icom_set_mctrl, + .get_mctrl = icom_get_mctrl, + .stop_tx = icom_stop_tx, + .start_tx = icom_start_tx, + .send_xchar = icom_send_xchar, + .stop_rx = icom_stop_rx, + .enable_ms = icom_enable_ms, + .break_ctl = icom_break, + .startup = icom_open, + .shutdown = icom_close, + .set_termios = icom_set_termios, + .type = icom_type, + .release_port = icom_release_port, + .request_port = icom_request_port, + .config_port = icom_config_port, +}; + +#define ICOM_CONSOLE NULL + +static struct uart_driver icom_uart_driver = { + .owner = THIS_MODULE, + .driver_name = ICOM_DRIVER_NAME, + .dev_name = "ttyA", + .major = ICOM_MAJOR, + .minor = ICOM_MINOR_START, + .nr = NR_PORTS, + .cons = ICOM_CONSOLE, +}; + +static int __devinit icom_init_ports(struct icom_adapter *icom_adapter) +{ + u32 subsystem_id = icom_adapter->subsystem_id; + int i; + struct icom_port *icom_port; + + if (icom_adapter->version == ADAPTER_V1) { + icom_adapter->numb_ports = 2; + + for (i = 0; i < 2; i++) { + icom_port = &icom_adapter->port_info[i]; + icom_port->port = i; + icom_port->status = ICOM_PORT_ACTIVE; + icom_port->imbed_modem = ICOM_UNKNOWN; + } + } else { + if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) { + icom_adapter->numb_ports = 4; + + for (i = 0; i < 4; i++) { + icom_port = &icom_adapter->port_info[i]; + + icom_port->port = i; + icom_port->status = ICOM_PORT_ACTIVE; + icom_port->imbed_modem = ICOM_IMBED_MODEM; + } + } else { + icom_adapter->numb_ports = 4; + + icom_adapter->port_info[0].port = 0; + icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE; + + if (subsystem_id == + PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) { + icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM; + } else { + icom_adapter->port_info[0].imbed_modem = ICOM_RVX; + } + + icom_adapter->port_info[1].status = ICOM_PORT_OFF; + + icom_adapter->port_info[2].port = 2; + icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE; + icom_adapter->port_info[2].imbed_modem = ICOM_RVX; + icom_adapter->port_info[3].status = ICOM_PORT_OFF; + } + } + + return 0; +} + +static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num) +{ + if (icom_adapter->version == ADAPTER_V1) { + icom_port->global_reg = icom_adapter->base_addr + 0x4000; + icom_port->int_reg = icom_adapter->base_addr + + 0x4004 + 2 - 2 * port_num; + } else { + icom_port->global_reg = icom_adapter->base_addr + 0x8000; + if (icom_port->port < 2) + icom_port->int_reg = icom_adapter->base_addr + + 0x8004 + 2 - 2 * icom_port->port; + else + icom_port->int_reg = icom_adapter->base_addr + + 0x8024 + 2 - 2 * (icom_port->port - 2); + } +} +static int __devinit icom_load_ports(struct icom_adapter *icom_adapter) +{ + struct icom_port *icom_port; + int port_num; + + for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) { + + icom_port = &icom_adapter->port_info[port_num]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + icom_port_active(icom_port, icom_adapter, port_num); + icom_port->dram = icom_adapter->base_addr + + 0x2000 * icom_port->port; + + icom_port->adapter = icom_adapter; + + /* get port memory */ + if (get_port_memory(icom_port) != 0) { + dev_err(&icom_port->adapter->pci_dev->dev, + "Memory allocation for port FAILED\n"); + } + } + } + return 0; +} + +static int __devinit icom_alloc_adapter(struct icom_adapter + **icom_adapter_ref) +{ + int adapter_count = 0; + struct icom_adapter *icom_adapter; + struct icom_adapter *cur_adapter_entry; + struct list_head *tmp; + + icom_adapter = (struct icom_adapter *) + kzalloc(sizeof(struct icom_adapter), GFP_KERNEL); + + if (!icom_adapter) { + return -ENOMEM; + } + + list_for_each(tmp, &icom_adapter_head) { + cur_adapter_entry = + list_entry(tmp, struct icom_adapter, + icom_adapter_entry); + if (cur_adapter_entry->index != adapter_count) { + break; + } + adapter_count++; + } + + icom_adapter->index = adapter_count; + list_add_tail(&icom_adapter->icom_adapter_entry, tmp); + + *icom_adapter_ref = icom_adapter; + return 0; +} + +static void icom_free_adapter(struct icom_adapter *icom_adapter) +{ + list_del(&icom_adapter->icom_adapter_entry); + kfree(icom_adapter); +} + +static void icom_remove_adapter(struct icom_adapter *icom_adapter) +{ + struct icom_port *icom_port; + int index; + + for (index = 0; index < icom_adapter->numb_ports; index++) { + icom_port = &icom_adapter->port_info[index]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + dev_info(&icom_adapter->pci_dev->dev, + "Device removed\n"); + + uart_remove_one_port(&icom_uart_driver, + &icom_port->uart_port); + + /* be sure that DTR and RTS are dropped */ + writeb(0x00, &icom_port->dram->osr); + + /* Wait 0.1 Sec for simple Init to complete */ + msleep(100); + + /* Stop proccessor */ + stop_processor(icom_port); + + free_port_memory(icom_port); + } + } + + free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); + iounmap(icom_adapter->base_addr); + pci_release_regions(icom_adapter->pci_dev); + icom_free_adapter(icom_adapter); +} + +static void icom_kref_release(struct kref *kref) +{ + struct icom_adapter *icom_adapter; + + icom_adapter = to_icom_adapter(kref); + icom_remove_adapter(icom_adapter); +} + +static int __devinit icom_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + int index; + unsigned int command_reg; + int retval; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; + + retval = pci_enable_device(dev); + if (retval) { + dev_err(&dev->dev, "Device enable FAILED\n"); + return retval; + } + + if ( (retval = pci_request_regions(dev, "icom"))) { + dev_err(&dev->dev, "pci_request_regions FAILED\n"); + pci_disable_device(dev); + return retval; + } + + pci_set_master(dev); + + if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + dev_err(&dev->dev, "PCI Config read FAILED\n"); + return retval; + } + + pci_write_config_dword(dev, PCI_COMMAND, + command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER + | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + + if (ent->driver_data == ADAPTER_V1) { + pci_write_config_dword(dev, 0x44, 0x8300830A); + } else { + pci_write_config_dword(dev, 0x44, 0x42004200); + pci_write_config_dword(dev, 0x48, 0x42004200); + } + + + retval = icom_alloc_adapter(&icom_adapter); + if (retval) { + dev_err(&dev->dev, "icom_alloc_adapter FAILED\n"); + retval = -EIO; + goto probe_exit0; + } + + icom_adapter->base_addr_pci = pci_resource_start(dev, 0); + icom_adapter->pci_dev = dev; + icom_adapter->version = ent->driver_data; + icom_adapter->subsystem_id = ent->subdevice; + + + retval = icom_init_ports(icom_adapter); + if (retval) { + dev_err(&dev->dev, "Port configuration failed\n"); + goto probe_exit1; + } + + icom_adapter->base_addr = pci_ioremap_bar(dev, 0); + + if (!icom_adapter->base_addr) + goto probe_exit1; + + /* save off irq and request irq line */ + if ( (retval = request_irq(dev->irq, icom_interrupt, + IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME, + (void *) icom_adapter))) { + goto probe_exit2; + } + + retval = icom_load_ports(icom_adapter); + + for (index = 0; index < icom_adapter->numb_ports; index++) { + icom_port = &icom_adapter->port_info[index]; + + if (icom_port->status == ICOM_PORT_ACTIVE) { + icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq; + icom_port->uart_port.type = PORT_ICOM; + icom_port->uart_port.iotype = UPIO_MEM; + icom_port->uart_port.membase = + (char *) icom_adapter->base_addr_pci; + icom_port->uart_port.fifosize = 16; + icom_port->uart_port.ops = &icom_ops; + icom_port->uart_port.line = + icom_port->port + icom_adapter->index * 4; + if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) { + icom_port->status = ICOM_PORT_OFF; + dev_err(&dev->dev, "Device add failed\n"); + } else + dev_info(&dev->dev, "Device added\n"); + } + } + + kref_init(&icom_adapter->kref); + return 0; + +probe_exit2: + iounmap(icom_adapter->base_addr); +probe_exit1: + icom_free_adapter(icom_adapter); + +probe_exit0: + pci_release_regions(dev); + pci_disable_device(dev); + + return retval; +} + +static void __devexit icom_remove(struct pci_dev *dev) +{ + struct icom_adapter *icom_adapter; + struct list_head *tmp; + + list_for_each(tmp, &icom_adapter_head) { + icom_adapter = list_entry(tmp, struct icom_adapter, + icom_adapter_entry); + if (icom_adapter->pci_dev == dev) { + kref_put(&icom_adapter->kref, icom_kref_release); + return; + } + } + + dev_err(&dev->dev, "Unable to find device to remove\n"); +} + +static struct pci_driver icom_pci_driver = { + .name = ICOM_DRIVER_NAME, + .id_table = icom_pci_table, + .probe = icom_probe, + .remove = __devexit_p(icom_remove), +}; + +static int __init icom_init(void) +{ + int ret; + + spin_lock_init(&icom_lock); + + ret = uart_register_driver(&icom_uart_driver); + if (ret) + return ret; + + ret = pci_register_driver(&icom_pci_driver); + + if (ret < 0) + uart_unregister_driver(&icom_uart_driver); + + return ret; +} + +static void __exit icom_exit(void) +{ + pci_unregister_driver(&icom_pci_driver); + uart_unregister_driver(&icom_uart_driver); +} + +module_init(icom_init); +module_exit(icom_exit); + +MODULE_AUTHOR("Michael Anderson "); +MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); +MODULE_SUPPORTED_DEVICE + ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("icom_call_setup.bin"); +MODULE_FIRMWARE("icom_res_dce.bin"); +MODULE_FIRMWARE("icom_asc.bin"); diff --git a/drivers/tty/serial/icom.h b/drivers/tty/serial/icom.h new file mode 100644 index 000000000000..c8029e0025c9 --- /dev/null +++ b/drivers/tty/serial/icom.h @@ -0,0 +1,287 @@ +/* + * icom.h + * + * Copyright (C) 2001 Michael Anderson, IBM Corporation + * + * Serial device driver include file. + * + * 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 + +#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1) +static int icom_acfg_baud[] = { + 300, + 600, + 900, + 1200, + 1800, + 2400, + 3600, + 4800, + 7200, + 9600, + 14400, + 19200, + 28800, + 38400, + 57600, + 76800, + 115200, + 153600, + 230400, + 307200, + 460800, +}; + +struct icom_regs { + u32 control; /* Adapter Control Register */ + u32 interrupt; /* Adapter Interrupt Register */ + u32 int_mask; /* Adapter Interrupt Mask Reg */ + u32 int_pri; /* Adapter Interrupt Priority r */ + u32 int_reg_b; /* Adapter non-masked Interrupt */ + u32 resvd01; + u32 resvd02; + u32 resvd03; + u32 control_2; /* Adapter Control Register 2 */ + u32 interrupt_2; /* Adapter Interrupt Register 2 */ + u32 int_mask_2; /* Adapter Interrupt Mask 2 */ + u32 int_pri_2; /* Adapter Interrupt Prior 2 */ + u32 int_reg_2b; /* Adapter non-masked 2 */ +}; + +struct func_dram { + u32 reserved[108]; /* 0-1B0 reserved by personality code */ + u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ + u8 RcvStnAddr; /* 1B4 Receive Station Addr */ + u8 IdleState; /* 1B5 Idle State */ + u8 IdleMonitor; /* 1B6 Idle Monitor */ + u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ + u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ + u8 StartXmitCmd; /* 1BC Start Xmit Command */ + u8 HDLCConfigReg; /* 1BD Reserved */ + u8 CauseCode; /* 1BE Cause code for fatal error */ + u8 xchar; /* 1BF High priority send */ + u32 reserved3; /* 1C0-1C3 Reserved */ + u8 PrevCmdReg; /* 1C4 Reserved */ + u8 CmdReg; /* 1C5 Command Register */ + u8 async_config2; /* 1C6 Async Config Byte 2 */ + u8 async_config3; /* 1C7 Async Config Byte 3 */ + u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ + u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ + u8 misc_flags; /* 1DD misc flags */ +#define V2_HARDWARE 0x40 +#define ICOM_HDW_ACTIVE 0x01 + u8 call_length; /* 1DE Phone #/CFI buff ln */ + u8 call_length2; /* 1DF Upper byte (unused) */ + u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ + u16 timer_value; /* 1E4-1E5 general timer value */ + u8 timer_command; /* 1E6 general timer cmd */ + u8 dce_command; /* 1E7 dce command reg */ + u8 dce_cmd_status; /* 1E8 dce command stat */ + u8 x21_r1_ioff; /* 1E9 dce ready counter */ + u8 x21_r0_ioff; /* 1EA dce not ready ctr */ + u8 x21_ralt_ioff; /* 1EB dce CNR counter */ + u8 x21_r1_ion; /* 1EC dce ready I on ctr */ + u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ + u8 ier; /* 1EE Interrupt Enable */ + u8 isr; /* 1EF Input Signal Reg */ + u8 osr; /* 1F0 Output Signal Reg */ + u8 reset; /* 1F1 Reset/Reload Reg */ + u8 disable; /* 1F2 Disable Reg */ + u8 sync; /* 1F3 Sync Reg */ + u8 error_stat; /* 1F4 Error Status */ + u8 cable_id; /* 1F5 Cable ID */ + u8 cs_length; /* 1F6 CS Load Length */ + u8 mac_length; /* 1F7 Mac Load Length */ + u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ + u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ +}; + +/* + * adapter defines and structures + */ +#define ICOM_CONTROL_START_A 0x00000008 +#define ICOM_CONTROL_STOP_A 0x00000004 +#define ICOM_CONTROL_START_B 0x00000002 +#define ICOM_CONTROL_STOP_B 0x00000001 +#define ICOM_CONTROL_START_C 0x00000008 +#define ICOM_CONTROL_STOP_C 0x00000004 +#define ICOM_CONTROL_START_D 0x00000002 +#define ICOM_CONTROL_STOP_D 0x00000001 +#define ICOM_IRAM_OFFSET 0x1000 +#define ICOM_IRAM_SIZE 0x0C00 +#define ICOM_DCE_IRAM_OFFSET 0x0A00 +#define ICOM_CABLE_ID_VALID 0x01 +#define ICOM_CABLE_ID_MASK 0xF0 +#define ICOM_DISABLE 0x80 +#define CMD_XMIT_RCV_ENABLE 0xC0 +#define CMD_XMIT_ENABLE 0x40 +#define CMD_RCV_DISABLE 0x00 +#define CMD_RCV_ENABLE 0x80 +#define CMD_RESTART 0x01 +#define CMD_HOLD_XMIT 0x02 +#define CMD_SND_BREAK 0x04 +#define RS232_CABLE 0x06 +#define V24_CABLE 0x0E +#define V35_CABLE 0x0C +#define V36_CABLE 0x02 +#define NO_CABLE 0x00 +#define START_DOWNLOAD 0x80 +#define ICOM_INT_MASK_PRC_A 0x00003FFF +#define ICOM_INT_MASK_PRC_B 0x3FFF0000 +#define ICOM_INT_MASK_PRC_C 0x00003FFF +#define ICOM_INT_MASK_PRC_D 0x3FFF0000 +#define INT_RCV_COMPLETED 0x1000 +#define INT_XMIT_COMPLETED 0x2000 +#define INT_IDLE_DETECT 0x0800 +#define INT_RCV_DISABLED 0x0400 +#define INT_XMIT_DISABLED 0x0200 +#define INT_RCV_XMIT_SHUTDOWN 0x0100 +#define INT_FATAL_ERROR 0x0080 +#define INT_CABLE_PULL 0x0020 +#define INT_SIGNAL_CHANGE 0x0010 +#define HDLC_PPP_PURE_ASYNC 0x02 +#define HDLC_FF_FILL 0x00 +#define HDLC_HDW_FLOW 0x01 +#define START_XMIT 0x80 +#define ICOM_ACFG_DRIVE1 0x20 +#define ICOM_ACFG_NO_PARITY 0x00 +#define ICOM_ACFG_PARITY_ENAB 0x02 +#define ICOM_ACFG_PARITY_ODD 0x01 +#define ICOM_ACFG_8BPC 0x00 +#define ICOM_ACFG_7BPC 0x04 +#define ICOM_ACFG_6BPC 0x08 +#define ICOM_ACFG_5BPC 0x0C +#define ICOM_ACFG_1STOP_BIT 0x00 +#define ICOM_ACFG_2STOP_BIT 0x10 +#define ICOM_DTR 0x80 +#define ICOM_RTS 0x40 +#define ICOM_RI 0x08 +#define ICOM_DSR 0x80 +#define ICOM_DCD 0x20 +#define ICOM_CTS 0x40 + +#define NUM_XBUFFS 1 +#define NUM_RBUFFS 2 +#define RCV_BUFF_SZ 0x0200 +#define XMIT_BUFF_SZ 0x1000 +struct statusArea { + /**********************************************/ + /* Transmit Status Area */ + /**********************************************/ + struct xmit_status_area{ + u32 leNext; /* Next entry in Little Endian on Adapter */ + u32 leNextASD; + u32 leBuffer; /* Buffer for entry in LE for Adapter */ + u16 leLengthASD; + u16 leOffsetASD; + u16 leLength; /* Length of data in segment */ + u16 flags; +#define SA_FLAGS_DONE 0x0080 /* Done with Segment */ +#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ +#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ +#define SA_FLAGS_READY_TO_XMIT 0x0800 +#define SA_FLAGS_STAT_MASK 0x007F + } xmit[NUM_XBUFFS]; + + /**********************************************/ + /* Receive Status Area */ + /**********************************************/ + struct { + u32 leNext; /* Next entry in Little Endian on Adapter */ + u32 leNextASD; + u32 leBuffer; /* Buffer for entry in LE for Adapter */ + u16 WorkingLength; /* size of segment */ + u16 reserv01; + u16 leLength; /* Length of data in segment */ + u16 flags; +#define SA_FL_RCV_DONE 0x0010 /* Data ready */ +#define SA_FLAGS_OVERRUN 0x0040 +#define SA_FLAGS_PARITY_ERROR 0x0080 +#define SA_FLAGS_FRAME_ERROR 0x0001 +#define SA_FLAGS_FRAME_TRUNC 0x0002 +#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ +#define SA_FLAGS_RCV_MASK 0xFFE6 + } rcv[NUM_RBUFFS]; +}; + +struct icom_adapter; + + +#define ICOM_MAJOR 243 +#define ICOM_MINOR_START 0 + +struct icom_port { + struct uart_port uart_port; + u8 imbed_modem; +#define ICOM_UNKNOWN 1 +#define ICOM_RVX 2 +#define ICOM_IMBED_MODEM 3 + unsigned char cable_id; + unsigned char read_status_mask; + unsigned char ignore_status_mask; + void __iomem * int_reg; + struct icom_regs __iomem *global_reg; + struct func_dram __iomem *dram; + int port; + struct statusArea *statStg; + dma_addr_t statStg_pci; + u32 *xmitRestart; + dma_addr_t xmitRestart_pci; + unsigned char *xmit_buf; + dma_addr_t xmit_buf_pci; + unsigned char *recv_buf; + dma_addr_t recv_buf_pci; + int next_rcv; + int put_length; + int status; +#define ICOM_PORT_ACTIVE 1 /* Port exists. */ +#define ICOM_PORT_OFF 0 /* Port does not exist. */ + int load_in_progress; + struct icom_adapter *adapter; +}; + +struct icom_adapter { + void __iomem * base_addr; + unsigned long base_addr_pci; + struct pci_dev *pci_dev; + struct icom_port port_info[4]; + int index; + int version; +#define ADAPTER_V1 0x0001 +#define ADAPTER_V2 0x0002 + u32 subsystem_id; +#define FOUR_PORT_MODEL 0x0252 +#define V2_TWO_PORTS_RVX 0x021A +#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 + int numb_ports; + struct list_head icom_adapter_entry; + struct kref kref; +}; + +/* prototype */ +extern void iCom_sercons_init(void); + +struct lookup_proc_table { + u32 __iomem *global_control_reg; + unsigned long processor_id; +}; + +struct lookup_int_table { + u32 __iomem *global_int_mask; + unsigned long processor_id; +}; diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c new file mode 100644 index 000000000000..ab93763862d5 --- /dev/null +++ b/drivers/tty/serial/ifx6x60.c @@ -0,0 +1,1406 @@ +/**************************************************************************** + * + * Driver for the IFX 6x60 spi modem. + * + * Copyright (C) 2008 Option International + * Copyright (C) 2008 Filip Aben + * Denis Joseph Barrow + * Jan Dumon + * + * Copyright (C) 2009, 2010 Intel Corp + * Russ Gorby + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + * Driver modified by Intel from Option gtm501l_spi.c + * + * Notes + * o The driver currently assumes a single device only. If you need to + * change this then look for saved_ifx_dev and add a device lookup + * o The driver is intended to be big-endian safe but has never been + * tested that way (no suitable hardware). There are a couple of FIXME + * notes by areas that may need addressing + * o Some of the GPIO naming/setup assumptions may need revisiting if + * you need to use this driver for another platform. + * + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifx6x60.h" + +#define IFX_SPI_MORE_MASK 0x10 +#define IFX_SPI_MORE_BIT 12 /* bit position in u16 */ +#define IFX_SPI_CTS_BIT 13 /* bit position in u16 */ +#define IFX_SPI_TTY_ID 0 +#define IFX_SPI_TIMEOUT_SEC 2 +#define IFX_SPI_HEADER_0 (-1) +#define IFX_SPI_HEADER_F (-2) + +/* forward reference */ +static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); + +/* local variables */ +static int spi_b16 = 1; /* 8 or 16 bit word length */ +static struct tty_driver *tty_drv; +static struct ifx_spi_device *saved_ifx_dev; +static struct lock_class_key ifx_spi_key; + +/* GPIO/GPE settings */ + +/** + * mrdy_set_high - set MRDY GPIO + * @ifx: device we are controlling + * + */ +static inline void mrdy_set_high(struct ifx_spi_device *ifx) +{ + gpio_set_value(ifx->gpio.mrdy, 1); +} + +/** + * mrdy_set_low - clear MRDY GPIO + * @ifx: device we are controlling + * + */ +static inline void mrdy_set_low(struct ifx_spi_device *ifx) +{ + gpio_set_value(ifx->gpio.mrdy, 0); +} + +/** + * ifx_spi_power_state_set + * @ifx_dev: our SPI device + * @val: bits to set + * + * Set bit in power status and signal power system if status becomes non-0 + */ +static void +ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val) +{ + unsigned long flags; + + spin_lock_irqsave(&ifx_dev->power_lock, flags); + + /* + * if power status is already non-0, just update, else + * tell power system + */ + if (!ifx_dev->power_status) + pm_runtime_get(&ifx_dev->spi_dev->dev); + ifx_dev->power_status |= val; + + spin_unlock_irqrestore(&ifx_dev->power_lock, flags); +} + +/** + * ifx_spi_power_state_clear - clear power bit + * @ifx_dev: our SPI device + * @val: bits to clear + * + * clear bit in power status and signal power system if status becomes 0 + */ +static void +ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val) +{ + unsigned long flags; + + spin_lock_irqsave(&ifx_dev->power_lock, flags); + + if (ifx_dev->power_status) { + ifx_dev->power_status &= ~val; + if (!ifx_dev->power_status) + pm_runtime_put(&ifx_dev->spi_dev->dev); + } + + spin_unlock_irqrestore(&ifx_dev->power_lock, flags); +} + +/** + * swap_buf + * @buf: our buffer + * @len : number of bytes (not words) in the buffer + * @end: end of buffer + * + * Swap the contents of a buffer into big endian format + */ +static inline void swap_buf(u16 *buf, int len, void *end) +{ + int n; + + len = ((len + 1) >> 1); + if ((void *)&buf[len] > end) { + pr_err("swap_buf: swap exceeds boundary (%p > %p)!", + &buf[len], end); + return; + } + for (n = 0; n < len; n++) { + *buf = cpu_to_be16(*buf); + buf++; + } +} + +/** + * mrdy_assert - assert MRDY line + * @ifx_dev: our SPI device + * + * Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low + * now. + * + * FIXME: Can SRDY even go high as we are running this code ? + */ +static void mrdy_assert(struct ifx_spi_device *ifx_dev) +{ + int val = gpio_get_value(ifx_dev->gpio.srdy); + if (!val) { + if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING, + &ifx_dev->flags)) { + ifx_dev->spi_timer.expires = + jiffies + IFX_SPI_TIMEOUT_SEC*HZ; + add_timer(&ifx_dev->spi_timer); + + } + } + ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING); + mrdy_set_high(ifx_dev); +} + +/** + * ifx_spi_hangup - hang up an IFX device + * @ifx_dev: our SPI device + * + * Hang up the tty attached to the IFX device if one is currently + * open. If not take no action + */ +static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev) +{ + struct tty_port *pport = &ifx_dev->tty_port; + struct tty_struct *tty = tty_port_tty_get(pport); + if (tty) { + tty_hangup(tty); + tty_kref_put(tty); + } +} + +/** + * ifx_spi_timeout - SPI timeout + * @arg: our SPI device + * + * The SPI has timed out: hang up the tty. Users will then see a hangup + * and error events. + */ +static void ifx_spi_timeout(unsigned long arg) +{ + struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg; + + dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***"); + ifx_spi_ttyhangup(ifx_dev); + mrdy_set_low(ifx_dev); + clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); +} + +/* char/tty operations */ + +/** + * ifx_spi_tiocmget - get modem lines + * @tty: our tty device + * @filp: file handle issuing the request + * + * Map the signal state into Linux modem flags and report the value + * in Linux terms + */ +static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp) +{ + unsigned int value; + struct ifx_spi_device *ifx_dev = tty->driver_data; + + value = + (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) | + (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) | + (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) | + (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) | + (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) | + (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0); + return value; +} + +/** + * ifx_spi_tiocmset - set modem bits + * @tty: the tty structure + * @filp: file handle issuing the request + * @set: bits to set + * @clear: bits to clear + * + * The IFX6x60 only supports DTR and RTS. Set them accordingly + * and flag that an update to the modem is needed. + * + * FIXME: do we need to kick the tranfers when we do this ? + */ +static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp, + unsigned int set, unsigned int clear) +{ + struct ifx_spi_device *ifx_dev = tty->driver_data; + + if (set & TIOCM_RTS) + set_bit(IFX_SPI_RTS, &ifx_dev->signal_state); + if (set & TIOCM_DTR) + set_bit(IFX_SPI_DTR, &ifx_dev->signal_state); + if (clear & TIOCM_RTS) + clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state); + if (clear & TIOCM_DTR) + clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state); + + set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state); + return 0; +} + +/** + * ifx_spi_open - called on tty open + * @tty: our tty device + * @filp: file handle being associated with the tty + * + * Open the tty interface. We let the tty_port layer do all the work + * for us. + * + * FIXME: Remove single device assumption and saved_ifx_dev + */ +static int ifx_spi_open(struct tty_struct *tty, struct file *filp) +{ + return tty_port_open(&saved_ifx_dev->tty_port, tty, filp); +} + +/** + * ifx_spi_close - called when our tty closes + * @tty: the tty being closed + * @filp: the file handle being closed + * + * Perform the close of the tty. We use the tty_port layer to do all + * our hard work. + */ +static void ifx_spi_close(struct tty_struct *tty, struct file *filp) +{ + struct ifx_spi_device *ifx_dev = tty->driver_data; + tty_port_close(&ifx_dev->tty_port, tty, filp); + /* FIXME: should we do an ifx_spi_reset here ? */ +} + +/** + * ifx_decode_spi_header - decode received header + * @buffer: the received data + * @length: decoded length + * @more: decoded more flag + * @received_cts: status of cts we received + * + * Note how received_cts is handled -- if header is all F it is left + * the same as it was, if header is all 0 it is set to 0 otherwise it is + * taken from the incoming header. + * + * FIXME: endianness + */ +static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length, + unsigned char *more, unsigned char *received_cts) +{ + u16 h1; + u16 h2; + u16 *in_buffer = (u16 *)buffer; + + h1 = *in_buffer; + h2 = *(in_buffer+1); + + if (h1 == 0 && h2 == 0) { + *received_cts = 0; + return IFX_SPI_HEADER_0; + } else if (h1 == 0xffff && h2 == 0xffff) { + /* spi_slave_cts remains as it was */ + return IFX_SPI_HEADER_F; + } + + *length = h1 & 0xfff; /* upper bits of byte are flags */ + *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1; + *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1; + return 0; +} + +/** + * ifx_setup_spi_header - set header fields + * @txbuffer: pointer to start of SPI buffer + * @tx_count: bytes + * @more: indicate if more to follow + * + * Format up an SPI header for a transfer + * + * FIXME: endianness? + */ +static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count, + unsigned char more) +{ + *(u16 *)(txbuffer) = tx_count; + *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE; + txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK; +} + +/** + * ifx_spi_wakeup_serial - SPI space made + * @port_data: our SPI device + * + * We have emptied the FIFO enough that we want to get more data + * queued into it. Poke the line discipline via tty_wakeup so that + * it will feed us more bits + */ +static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev) +{ + struct tty_struct *tty; + + tty = tty_port_tty_get(&ifx_dev->tty_port); + if (!tty) + return; + tty_wakeup(tty); + tty_kref_put(tty); +} + +/** + * ifx_spi_prepare_tx_buffer - prepare transmit frame + * @ifx_dev: our SPI device + * + * The transmit buffr needs a header and various other bits of + * information followed by as much data as we can pull from the FIFO + * and transfer. This function formats up a suitable buffer in the + * ifx_dev->tx_buffer + * + * FIXME: performance - should we wake the tty when the queue is half + * empty ? + */ +static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev) +{ + int temp_count; + int queue_length; + int tx_count; + unsigned char *tx_buffer; + + tx_buffer = ifx_dev->tx_buffer; + memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE); + + /* make room for required SPI header */ + tx_buffer += IFX_SPI_HEADER_OVERHEAD; + tx_count = IFX_SPI_HEADER_OVERHEAD; + + /* clear to signal no more data if this turns out to be the + * last buffer sent in a sequence */ + ifx_dev->spi_more = 0; + + /* if modem cts is set, just send empty buffer */ + if (!ifx_dev->spi_slave_cts) { + /* see if there's tx data */ + queue_length = kfifo_len(&ifx_dev->tx_fifo); + if (queue_length != 0) { + /* data to mux -- see if there's room for it */ + temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE); + temp_count = kfifo_out_locked(&ifx_dev->tx_fifo, + tx_buffer, temp_count, + &ifx_dev->fifo_lock); + + /* update buffer pointer and data count in message */ + tx_buffer += temp_count; + tx_count += temp_count; + if (temp_count == queue_length) + /* poke port to get more data */ + ifx_spi_wakeup_serial(ifx_dev); + else /* more data in port, use next SPI message */ + ifx_dev->spi_more = 1; + } + } + /* have data and info for header -- set up SPI header in buffer */ + /* spi header needs payload size, not entire buffer size */ + ifx_spi_setup_spi_header(ifx_dev->tx_buffer, + tx_count-IFX_SPI_HEADER_OVERHEAD, + ifx_dev->spi_more); + /* swap actual data in the buffer */ + swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count, + &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]); + return tx_count; +} + +/** + * ifx_spi_write - line discipline write + * @tty: our tty device + * @buf: pointer to buffer to write (kernel space) + * @count: size of buffer + * + * Write the characters we have been given into the FIFO. If the device + * is not active then activate it, when the SRDY line is asserted back + * this will commence I/O + */ +static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, + int count) +{ + struct ifx_spi_device *ifx_dev = tty->driver_data; + unsigned char *tmp_buf = (unsigned char *)buf; + int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count, + &ifx_dev->fifo_lock); + mrdy_assert(ifx_dev); + return tx_count; +} + +/** + * ifx_spi_chars_in_buffer - line discipline helper + * @tty: our tty device + * + * Report how much data we can accept before we drop bytes. As we use + * a simple FIFO this is nice and easy. + */ +static int ifx_spi_write_room(struct tty_struct *tty) +{ + struct ifx_spi_device *ifx_dev = tty->driver_data; + return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo); +} + +/** + * ifx_spi_chars_in_buffer - line discipline helper + * @tty: our tty device + * + * Report how many characters we have buffered. In our case this is the + * number of bytes sitting in our transmit FIFO. + */ +static int ifx_spi_chars_in_buffer(struct tty_struct *tty) +{ + struct ifx_spi_device *ifx_dev = tty->driver_data; + return kfifo_len(&ifx_dev->tx_fifo); +} + +/** + * ifx_port_hangup + * @port: our tty port + * + * tty port hang up. Called when tty_hangup processing is invoked either + * by loss of carrier, or by software (eg vhangup). Serialized against + * activate/shutdown by the tty layer. + */ +static void ifx_spi_hangup(struct tty_struct *tty) +{ + struct ifx_spi_device *ifx_dev = tty->driver_data; + tty_port_hangup(&ifx_dev->tty_port); +} + +/** + * ifx_port_activate + * @port: our tty port + * + * tty port activate method - called for first open. Serialized + * with hangup and shutdown by the tty layer. + */ +static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty) +{ + struct ifx_spi_device *ifx_dev = + container_of(port, struct ifx_spi_device, tty_port); + + /* clear any old data; can't do this in 'close' */ + kfifo_reset(&ifx_dev->tx_fifo); + + /* put port data into this tty */ + tty->driver_data = ifx_dev; + + /* allows flip string push from int context */ + tty->low_latency = 1; + + return 0; +} + +/** + * ifx_port_shutdown + * @port: our tty port + * + * tty port shutdown method - called for last port close. Serialized + * with hangup and activate by the tty layer. + */ +static void ifx_port_shutdown(struct tty_port *port) +{ + struct ifx_spi_device *ifx_dev = + container_of(port, struct ifx_spi_device, tty_port); + + mrdy_set_low(ifx_dev); + clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); + tasklet_kill(&ifx_dev->io_work_tasklet); +} + +static const struct tty_port_operations ifx_tty_port_ops = { + .activate = ifx_port_activate, + .shutdown = ifx_port_shutdown, +}; + +static const struct tty_operations ifx_spi_serial_ops = { + .open = ifx_spi_open, + .close = ifx_spi_close, + .write = ifx_spi_write, + .hangup = ifx_spi_hangup, + .write_room = ifx_spi_write_room, + .chars_in_buffer = ifx_spi_chars_in_buffer, + .tiocmget = ifx_spi_tiocmget, + .tiocmset = ifx_spi_tiocmset, +}; + +/** + * ifx_spi_insert_fip_string - queue received data + * @ifx_ser: our SPI device + * @chars: buffer we have received + * @size: number of chars reeived + * + * Queue bytes to the tty assuming the tty side is currently open. If + * not the discard the data. + */ +static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev, + unsigned char *chars, size_t size) +{ + struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port); + if (!tty) + return; + tty_insert_flip_string(tty, chars, size); + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + +/** + * ifx_spi_complete - SPI transfer completed + * @ctx: our SPI device + * + * An SPI transfer has completed. Process any received data and kick off + * any further transmits we can commence. + */ +static void ifx_spi_complete(void *ctx) +{ + struct ifx_spi_device *ifx_dev = ctx; + struct tty_struct *tty; + struct tty_ldisc *ldisc = NULL; + int length; + int actual_length; + unsigned char more; + unsigned char cts; + int local_write_pending = 0; + int queue_length; + int srdy; + int decode_result; + + mrdy_set_low(ifx_dev); + + if (!ifx_dev->spi_msg.status) { + /* check header validity, get comm flags */ + swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD, + &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]); + decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer, + &length, &more, &cts); + if (decode_result == IFX_SPI_HEADER_0) { + dev_dbg(&ifx_dev->spi_dev->dev, + "ignore input: invalid header 0"); + ifx_dev->spi_slave_cts = 0; + goto complete_exit; + } else if (decode_result == IFX_SPI_HEADER_F) { + dev_dbg(&ifx_dev->spi_dev->dev, + "ignore input: invalid header F"); + goto complete_exit; + } + + ifx_dev->spi_slave_cts = cts; + + actual_length = min((unsigned int)length, + ifx_dev->spi_msg.actual_length); + swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD), + actual_length, + &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]); + ifx_spi_insert_flip_string( + ifx_dev, + ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD, + (size_t)actual_length); + } else { + dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d", + ifx_dev->spi_msg.status); + } + +complete_exit: + if (ifx_dev->write_pending) { + ifx_dev->write_pending = 0; + local_write_pending = 1; + } + + clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags)); + + queue_length = kfifo_len(&ifx_dev->tx_fifo); + srdy = gpio_get_value(ifx_dev->gpio.srdy); + if (!srdy) + ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY); + + /* schedule output if there is more to do */ + if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags)) + tasklet_schedule(&ifx_dev->io_work_tasklet); + else { + if (more || ifx_dev->spi_more || queue_length > 0 || + local_write_pending) { + if (ifx_dev->spi_slave_cts) { + if (more) + mrdy_assert(ifx_dev); + } else + mrdy_assert(ifx_dev); + } else { + /* + * poke line discipline driver if any for more data + * may or may not get more data to write + * for now, say not busy + */ + ifx_spi_power_state_clear(ifx_dev, + IFX_SPI_POWER_DATA_PENDING); + tty = tty_port_tty_get(&ifx_dev->tty_port); + if (tty) { + ldisc = tty_ldisc_ref(tty); + if (ldisc) { + ldisc->ops->write_wakeup(tty); + tty_ldisc_deref(ldisc); + } + tty_kref_put(tty); + } + } + } +} + +/** + * ifx_spio_io - I/O tasklet + * @data: our SPI device + * + * Queue data for transmission if possible and then kick off the + * transfer. + */ +static void ifx_spi_io(unsigned long data) +{ + int retval; + struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data; + + if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) { + if (ifx_dev->gpio.unack_srdy_int_nb > 0) + ifx_dev->gpio.unack_srdy_int_nb--; + + ifx_spi_prepare_tx_buffer(ifx_dev); + + spi_message_init(&ifx_dev->spi_msg); + INIT_LIST_HEAD(&ifx_dev->spi_msg.queue); + + ifx_dev->spi_msg.context = ifx_dev; + ifx_dev->spi_msg.complete = ifx_spi_complete; + + /* set up our spi transfer */ + /* note len is BYTES, not transfers */ + ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE; + ifx_dev->spi_xfer.cs_change = 0; + ifx_dev->spi_xfer.speed_hz = 12500000; + /* ifx_dev->spi_xfer.speed_hz = 390625; */ + ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8; + + ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; + ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; + + /* + * setup dma pointers + */ + if (ifx_dev->is_6160) { + ifx_dev->spi_msg.is_dma_mapped = 1; + ifx_dev->tx_dma = ifx_dev->tx_bus; + ifx_dev->rx_dma = ifx_dev->rx_bus; + ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma; + ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma; + } else { + ifx_dev->spi_msg.is_dma_mapped = 0; + ifx_dev->tx_dma = (dma_addr_t)0; + ifx_dev->rx_dma = (dma_addr_t)0; + ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0; + ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0; + } + + spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg); + + /* Assert MRDY. This may have already been done by the write + * routine. + */ + mrdy_assert(ifx_dev); + + retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg); + if (retval) { + clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, + &ifx_dev->flags); + tasklet_schedule(&ifx_dev->io_work_tasklet); + return; + } + } else + ifx_dev->write_pending = 1; +} + +/** + * ifx_spi_free_port - free up the tty side + * @ifx_dev: IFX device going away + * + * Unregister and free up a port when the device goes away + */ +static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev) +{ + if (ifx_dev->tty_dev) + tty_unregister_device(tty_drv, ifx_dev->minor); + kfifo_free(&ifx_dev->tx_fifo); +} + +/** + * ifx_spi_create_port - create a new port + * @ifx_dev: our spi device + * + * Allocate and initialise the tty port that goes with this interface + * and add it to the tty layer so that it can be opened. + */ +static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) +{ + int ret = 0; + struct tty_port *pport = &ifx_dev->tty_port; + + spin_lock_init(&ifx_dev->fifo_lock); + lockdep_set_class_and_subclass(&ifx_dev->fifo_lock, + &ifx_spi_key, 0); + + if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) { + ret = -ENOMEM; + goto error_ret; + } + + pport->ops = &ifx_tty_port_ops; + tty_port_init(pport); + ifx_dev->minor = IFX_SPI_TTY_ID; + ifx_dev->tty_dev = tty_register_device(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__); + ret = PTR_ERR(ifx_dev->tty_dev); + goto error_ret; + } + return 0; + +error_ret: + ifx_spi_free_port(ifx_dev); + return ret; +} + +/** + * ifx_spi_handle_srdy - handle SRDY + * @ifx_dev: device asserting SRDY + * + * Check our device state and see what we need to kick off when SRDY + * is asserted. This usually means killing the timer and firing off the + * I/O processing. + */ +static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev) +{ + if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { + del_timer_sync(&ifx_dev->spi_timer); + clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); + } + + ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY); + + if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) + tasklet_schedule(&ifx_dev->io_work_tasklet); + else + set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); +} + +/** + * ifx_spi_srdy_interrupt - SRDY asserted + * @irq: our IRQ number + * @dev: our ifx device + * + * The modem asserted SRDY. Handle the srdy event + */ +static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev) +{ + struct ifx_spi_device *ifx_dev = dev; + ifx_dev->gpio.unack_srdy_int_nb++; + ifx_spi_handle_srdy(ifx_dev); + return IRQ_HANDLED; +} + +/** + * ifx_spi_reset_interrupt - Modem has changed reset state + * @irq: interrupt number + * @dev: our device pointer + * + * The modem has either entered or left reset state. Check the GPIO + * line to see which. + * + * FIXME: review locking on MR_INPROGRESS versus + * parallel unsolicited reset/solicited reset + */ +static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev) +{ + struct ifx_spi_device *ifx_dev = dev; + int val = gpio_get_value(ifx_dev->gpio.reset_out); + int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state); + + if (val == 0) { + /* entered reset */ + set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); + if (!solreset) { + /* unsolicited reset */ + ifx_spi_ttyhangup(ifx_dev); + } + } else { + /* exited reset */ + clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); + if (solreset) { + set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state); + wake_up(&ifx_dev->mdm_reset_wait); + } + } + return IRQ_HANDLED; +} + +/** + * ifx_spi_free_device - free device + * @ifx_dev: device to free + * + * Free the IFX device + */ +static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev) +{ + ifx_spi_free_port(ifx_dev); + dma_free_coherent(&ifx_dev->spi_dev->dev, + IFX_SPI_TRANSFER_SIZE, + ifx_dev->tx_buffer, + ifx_dev->tx_bus); + dma_free_coherent(&ifx_dev->spi_dev->dev, + IFX_SPI_TRANSFER_SIZE, + ifx_dev->rx_buffer, + ifx_dev->rx_bus); +} + +/** + * ifx_spi_reset - reset modem + * @ifx_dev: modem to reset + * + * Perform a reset on the modem + */ +static int ifx_spi_reset(struct ifx_spi_device *ifx_dev) +{ + int ret; + /* + * set up modem power, reset + * + * delays are required on some platforms for the modem + * to reset properly + */ + set_bit(MR_START, &ifx_dev->mdm_reset_state); + gpio_set_value(ifx_dev->gpio.po, 0); + gpio_set_value(ifx_dev->gpio.reset, 0); + msleep(25); + gpio_set_value(ifx_dev->gpio.reset, 1); + msleep(1); + gpio_set_value(ifx_dev->gpio.po, 1); + msleep(1); + gpio_set_value(ifx_dev->gpio.po, 0); + ret = wait_event_timeout(ifx_dev->mdm_reset_wait, + test_bit(MR_COMPLETE, + &ifx_dev->mdm_reset_state), + IFX_RESET_TIMEOUT); + if (!ret) + dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)", + ifx_dev->mdm_reset_state); + + ifx_dev->mdm_reset_state = 0; + return ret; +} + +/** + * ifx_spi_spi_probe - probe callback + * @spi: our possible matching SPI device + * + * Probe for a 6x60 modem on SPI bus. Perform any needed device and + * GPIO setup. + * + * FIXME: + * - Support for multiple devices + * - Split out MID specific GPIO handling eventually + */ + +static int ifx_spi_spi_probe(struct spi_device *spi) +{ + int ret; + int srdy; + struct ifx_modem_platform_data *pl_data = NULL; + struct ifx_spi_device *ifx_dev; + + if (saved_ifx_dev) { + dev_dbg(&spi->dev, "ignoring subsequent detection"); + return -ENODEV; + } + + /* initialize structure to hold our device variables */ + ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); + if (!ifx_dev) { + dev_err(&spi->dev, "spi device allocation failed"); + return -ENOMEM; + } + saved_ifx_dev = ifx_dev; + ifx_dev->spi_dev = spi; + clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); + spin_lock_init(&ifx_dev->write_lock); + spin_lock_init(&ifx_dev->power_lock); + ifx_dev->power_status = 0; + init_timer(&ifx_dev->spi_timer); + ifx_dev->spi_timer.function = ifx_spi_timeout; + ifx_dev->spi_timer.data = (unsigned long)ifx_dev; + ifx_dev->is_6160 = pl_data->is_6160; + + /* ensure SPI protocol flags are initialized to enable transfer */ + ifx_dev->spi_more = 0; + ifx_dev->spi_slave_cts = 0; + + /*initialize transfer and dma buffers */ + ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev, + IFX_SPI_TRANSFER_SIZE, + &ifx_dev->tx_bus, + GFP_KERNEL); + if (!ifx_dev->tx_buffer) { + dev_err(&spi->dev, "DMA-TX buffer allocation failed"); + ret = -ENOMEM; + goto error_ret; + } + ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev, + IFX_SPI_TRANSFER_SIZE, + &ifx_dev->rx_bus, + GFP_KERNEL); + if (!ifx_dev->rx_buffer) { + dev_err(&spi->dev, "DMA-RX buffer allocation failed"); + ret = -ENOMEM; + goto error_ret; + } + + /* initialize waitq for modem reset */ + init_waitqueue_head(&ifx_dev->mdm_reset_wait); + + spi_set_drvdata(spi, ifx_dev); + tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io, + (unsigned long)ifx_dev); + + set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags); + + /* create our tty port */ + ret = ifx_spi_create_port(ifx_dev); + if (ret != 0) { + dev_err(&spi->dev, "create default tty port failed"); + goto error_ret; + } + + pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data; + if (pl_data) { + ifx_dev->gpio.reset = pl_data->rst_pmu; + ifx_dev->gpio.po = pl_data->pwr_on; + ifx_dev->gpio.mrdy = pl_data->mrdy; + ifx_dev->gpio.srdy = pl_data->srdy; + ifx_dev->gpio.reset_out = pl_data->rst_out; + } else { + dev_err(&spi->dev, "missing platform data!"); + ret = -ENODEV; + goto error_ret; + } + + dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d", + ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy, + ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out); + + /* Configure gpios */ + ret = gpio_request(ifx_dev->gpio.reset, "ifxModem"); + if (ret < 0) { + dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)", + ifx_dev->gpio.reset); + goto error_ret; + } + ret += gpio_direction_output(ifx_dev->gpio.reset, 0); + ret += gpio_export(ifx_dev->gpio.reset, 1); + if (ret) { + dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)", + ifx_dev->gpio.reset); + ret = -EBUSY; + goto error_ret2; + } + + ret = gpio_request(ifx_dev->gpio.po, "ifxModem"); + ret += gpio_direction_output(ifx_dev->gpio.po, 0); + ret += gpio_export(ifx_dev->gpio.po, 1); + if (ret) { + dev_err(&spi->dev, "Unable to configure GPIO%d (ON)", + ifx_dev->gpio.po); + ret = -EBUSY; + goto error_ret3; + } + + ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem"); + if (ret < 0) { + dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)", + ifx_dev->gpio.mrdy); + goto error_ret3; + } + ret += gpio_export(ifx_dev->gpio.mrdy, 1); + ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0); + if (ret) { + dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)", + ifx_dev->gpio.mrdy); + ret = -EBUSY; + goto error_ret4; + } + + ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem"); + if (ret < 0) { + dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)", + ifx_dev->gpio.srdy); + ret = -EBUSY; + goto error_ret4; + } + ret += gpio_export(ifx_dev->gpio.srdy, 1); + ret += gpio_direction_input(ifx_dev->gpio.srdy); + if (ret) { + dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)", + ifx_dev->gpio.srdy); + ret = -EBUSY; + goto error_ret5; + } + + ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem"); + if (ret < 0) { + dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)", + ifx_dev->gpio.reset_out); + goto error_ret5; + } + ret += gpio_export(ifx_dev->gpio.reset_out, 1); + ret += gpio_direction_input(ifx_dev->gpio.reset_out); + if (ret) { + dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)", + ifx_dev->gpio.reset_out); + ret = -EBUSY; + goto error_ret6; + } + + ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out), + ifx_spi_reset_interrupt, + IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, + (void *)ifx_dev); + if (ret) { + dev_err(&spi->dev, "Unable to get irq %x\n", + gpio_to_irq(ifx_dev->gpio.reset_out)); + goto error_ret6; + } + + ret = ifx_spi_reset(ifx_dev); + + ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy), + ifx_spi_srdy_interrupt, + IRQF_TRIGGER_RISING, DRVNAME, + (void *)ifx_dev); + if (ret) { + dev_err(&spi->dev, "Unable to get irq %x", + gpio_to_irq(ifx_dev->gpio.srdy)); + goto error_ret7; + } + + /* set pm runtime power state and register with power system */ + pm_runtime_set_active(&spi->dev); + pm_runtime_enable(&spi->dev); + + /* handle case that modem is already signaling SRDY */ + /* no outgoing tty open at this point, this just satisfies the + * modem's read and should reset communication properly + */ + srdy = gpio_get_value(ifx_dev->gpio.srdy); + + if (srdy) { + mrdy_assert(ifx_dev); + ifx_spi_handle_srdy(ifx_dev); + } else + mrdy_set_low(ifx_dev); + return 0; + +error_ret7: + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); +error_ret6: + gpio_free(ifx_dev->gpio.srdy); +error_ret5: + gpio_free(ifx_dev->gpio.mrdy); +error_ret4: + gpio_free(ifx_dev->gpio.reset); +error_ret3: + gpio_free(ifx_dev->gpio.po); +error_ret2: + gpio_free(ifx_dev->gpio.reset_out); +error_ret: + ifx_spi_free_device(ifx_dev); + saved_ifx_dev = NULL; + return ret; +} + +/** + * ifx_spi_spi_remove - SPI device was removed + * @spi: SPI device + * + * FIXME: We should be shutting the device down here not in + * the module unload path. + */ + +static int ifx_spi_spi_remove(struct spi_device *spi) +{ + struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); + /* stop activity */ + tasklet_kill(&ifx_dev->io_work_tasklet); + /* free irq */ + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev); + + gpio_free(ifx_dev->gpio.srdy); + gpio_free(ifx_dev->gpio.mrdy); + gpio_free(ifx_dev->gpio.reset); + gpio_free(ifx_dev->gpio.po); + gpio_free(ifx_dev->gpio.reset_out); + + /* free allocations */ + ifx_spi_free_device(ifx_dev); + + saved_ifx_dev = NULL; + return 0; +} + +/** + * ifx_spi_spi_shutdown - called on SPI shutdown + * @spi: SPI device + * + * No action needs to be taken here + */ + +static void ifx_spi_spi_shutdown(struct spi_device *spi) +{ +} + +/* + * various suspends and resumes have nothing to do + * no hardware to save state for + */ + +/** + * ifx_spi_spi_suspend - suspend SPI on system suspend + * @dev: device being suspended + * + * Suspend the SPI side. No action needed on Intel MID platforms, may + * need extending for other systems. + */ +static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg) +{ + return 0; +} + +/** + * ifx_spi_spi_resume - resume SPI side on system resume + * @dev: device being suspended + * + * Suspend the SPI side. No action needed on Intel MID platforms, may + * need extending for other systems. + */ +static int ifx_spi_spi_resume(struct spi_device *spi) +{ + return 0; +} + +/** + * ifx_spi_pm_suspend - suspend modem on system suspend + * @dev: device being suspended + * + * Suspend the modem. No action needed on Intel MID platforms, may + * need extending for other systems. + */ +static int ifx_spi_pm_suspend(struct device *dev) +{ + return 0; +} + +/** + * ifx_spi_pm_resume - resume modem on system resume + * @dev: device being suspended + * + * Allow the modem to resume. No action needed. + * + * FIXME: do we need to reset anything here ? + */ +static int ifx_spi_pm_resume(struct device *dev) +{ + return 0; +} + +/** + * ifx_spi_pm_runtime_resume - suspend modem + * @dev: device being suspended + * + * Allow the modem to resume. No action needed. + */ +static int ifx_spi_pm_runtime_resume(struct device *dev) +{ + return 0; +} + +/** + * ifx_spi_pm_runtime_suspend - suspend modem + * @dev: device being suspended + * + * Allow the modem to suspend and thus suspend to continue up the + * device tree. + */ +static int ifx_spi_pm_runtime_suspend(struct device *dev) +{ + return 0; +} + +/** + * ifx_spi_pm_runtime_idle - check if modem idle + * @dev: our device + * + * Check conditions and queue runtime suspend if idle. + */ +static int ifx_spi_pm_runtime_idle(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); + + if (!ifx_dev->power_status) + pm_runtime_suspend(dev); + + return 0; +} + +static const struct dev_pm_ops ifx_spi_pm = { + .resume = ifx_spi_pm_resume, + .suspend = ifx_spi_pm_suspend, + .runtime_resume = ifx_spi_pm_runtime_resume, + .runtime_suspend = ifx_spi_pm_runtime_suspend, + .runtime_idle = ifx_spi_pm_runtime_idle +}; + +static const struct spi_device_id ifx_id_table[] = { + {"ifx6160", 0}, + {"ifx6260", 0}, + { } +}; +MODULE_DEVICE_TABLE(spi, ifx_id_table); + +/* spi operations */ +static const struct spi_driver ifx_spi_driver_6160 = { + .driver = { + .name = "ifx6160", + .bus = &spi_bus_type, + .pm = &ifx_spi_pm, + .owner = THIS_MODULE}, + .probe = ifx_spi_spi_probe, + .shutdown = ifx_spi_spi_shutdown, + .remove = __devexit_p(ifx_spi_spi_remove), + .suspend = ifx_spi_spi_suspend, + .resume = ifx_spi_spi_resume, + .id_table = ifx_id_table +}; + +/** + * ifx_spi_exit - module exit + * + * Unload the module. + */ + +static void __exit ifx_spi_exit(void) +{ + /* unregister */ + tty_unregister_driver(tty_drv); + spi_unregister_driver((void *)&ifx_spi_driver_6160); +} + +/** + * ifx_spi_init - module entry point + * + * Initialise the SPI and tty interfaces for the IFX SPI driver + * We need to initialize upper-edge spi driver after the tty + * driver because otherwise the spi probe will race + */ + +static int __init ifx_spi_init(void) +{ + int result; + + tty_drv = alloc_tty_driver(1); + if (!tty_drv) { + pr_err("%s: alloc_tty_driver failed", DRVNAME); + return -ENOMEM; + } + + tty_drv->magic = TTY_DRIVER_MAGIC; + tty_drv->owner = THIS_MODULE; + tty_drv->driver_name = DRVNAME; + tty_drv->name = TTYNAME; + tty_drv->minor_start = IFX_SPI_TTY_ID; + tty_drv->num = 1; + tty_drv->type = TTY_DRIVER_TYPE_SERIAL; + tty_drv->subtype = SERIAL_TYPE_NORMAL; + tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_drv->init_termios = tty_std_termios; + + tty_set_operations(tty_drv, &ifx_spi_serial_ops); + + result = tty_register_driver(tty_drv); + if (result) { + pr_err("%s: tty_register_driver failed(%d)", + DRVNAME, result); + put_tty_driver(tty_drv); + return result; + } + + result = spi_register_driver((void *)&ifx_spi_driver_6160); + if (result) { + pr_err("%s: spi_register_driver failed(%d)", + DRVNAME, result); + tty_unregister_driver(tty_drv); + } + return result; +} + +module_init(ifx_spi_init); +module_exit(ifx_spi_exit); + +MODULE_AUTHOR("Intel"); +MODULE_DESCRIPTION("IFX6x60 spi driver"); +MODULE_LICENSE("GPL"); +MODULE_INFO(Version, "0.1-IFX6x60"); diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h new file mode 100644 index 000000000000..deb7b8d977dc --- /dev/null +++ b/drivers/tty/serial/ifx6x60.h @@ -0,0 +1,129 @@ +/**************************************************************************** + * + * Driver for the IFX spi modem. + * + * Copyright (C) 2009, 2010 Intel Corp + * Jim Stanley + * + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + * + * + *****************************************************************************/ +#ifndef _IFX6X60_H +#define _IFX6X60_H + +#define DRVNAME "ifx6x60" +#define TTYNAME "ttyIFX" + +/* #define IFX_THROTTLE_CODE */ + +#define IFX_SPI_MAX_MINORS 1 +#define IFX_SPI_TRANSFER_SIZE 2048 +#define IFX_SPI_FIFO_SIZE 4096 + +#define IFX_SPI_HEADER_OVERHEAD 4 +#define IFX_RESET_TIMEOUT msecs_to_jiffies(50) + +/* device flags bitfield definitions */ +#define IFX_SPI_STATE_PRESENT 0 +#define IFX_SPI_STATE_IO_IN_PROGRESS 1 +#define IFX_SPI_STATE_IO_READY 2 +#define IFX_SPI_STATE_TIMER_PENDING 3 + +/* flow control bitfields */ +#define IFX_SPI_DCD 0 +#define IFX_SPI_CTS 1 +#define IFX_SPI_DSR 2 +#define IFX_SPI_RI 3 +#define IFX_SPI_DTR 4 +#define IFX_SPI_RTS 5 +#define IFX_SPI_TX_FC 6 +#define IFX_SPI_RX_FC 7 +#define IFX_SPI_UPDATE 8 + +#define IFX_SPI_PAYLOAD_SIZE (IFX_SPI_TRANSFER_SIZE - \ + IFX_SPI_HEADER_OVERHEAD) + +#define IFX_SPI_IRQ_TYPE DETECT_EDGE_RISING +#define IFX_SPI_GPIO_TARGET 0 +#define IFX_SPI_GPIO0 0x105 + +#define IFX_SPI_STATUS_TIMEOUT (2000*HZ) + +/* values for bits in power status byte */ +#define IFX_SPI_POWER_DATA_PENDING 1 +#define IFX_SPI_POWER_SRDY 2 + +struct ifx_spi_device { + /* Our SPI device */ + struct spi_device *spi_dev; + + /* Port specific data */ + struct kfifo tx_fifo; + spinlock_t fifo_lock; + unsigned long signal_state; + + /* TTY Layer logic */ + struct tty_port tty_port; + struct device *tty_dev; + int minor; + + /* Low level I/O work */ + struct tasklet_struct io_work_tasklet; + unsigned long flags; + dma_addr_t rx_dma; + dma_addr_t tx_dma; + + int is_6160; /* Modem type */ + + spinlock_t write_lock; + int write_pending; + spinlock_t power_lock; + unsigned char power_status; + + unsigned char *rx_buffer; + unsigned char *tx_buffer; + dma_addr_t rx_bus; + dma_addr_t tx_bus; + unsigned char spi_more; + unsigned char spi_slave_cts; + + struct timer_list spi_timer; + + struct spi_message spi_msg; + struct spi_transfer spi_xfer; + + struct { + /* gpio lines */ + unsigned short srdy; /* slave-ready gpio */ + unsigned short mrdy; /* master-ready gpio */ + unsigned short reset; /* modem-reset gpio */ + unsigned short po; /* modem-on gpio */ + unsigned short reset_out; /* modem-in-reset gpio */ + /* state/stats */ + int unack_srdy_int_nb; + } gpio; + + /* modem reset */ + unsigned long mdm_reset_state; +#define MR_START 0 +#define MR_INPROGRESS 1 +#define MR_COMPLETE 2 + wait_queue_head_t mdm_reset_wait; +}; + +#endif /* _IFX6X60_H */ diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c new file mode 100644 index 000000000000..dfcf4b1878aa --- /dev/null +++ b/drivers/tty/serial/imx.c @@ -0,0 +1,1380 @@ +/* + * linux/drivers/serial/imx.c + * + * Driver for Motorola IMX serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Author: Sascha Hauer + * Copyright (C) 2004 Pengutronix + * + * Copyright (C) 2009 emlix GmbH + * Author: Fabian Godehardt (added IrDA support for iMX) + * + * 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 + * + * [29-Mar-2005] Mike Lee + * Added hardware handshake + */ + +#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Register definitions */ +#define URXD0 0x0 /* Receiver Register */ +#define URTX0 0x40 /* Transmitter Register */ +#define UCR1 0x80 /* Control Register 1 */ +#define UCR2 0x84 /* Control Register 2 */ +#define UCR3 0x88 /* Control Register 3 */ +#define UCR4 0x8c /* Control Register 4 */ +#define UFCR 0x90 /* FIFO Control Register */ +#define USR1 0x94 /* Status Register 1 */ +#define USR2 0x98 /* Status Register 2 */ +#define UESC 0x9c /* Escape Character Register */ +#define UTIM 0xa0 /* Escape Timer Register */ +#define UBIR 0xa4 /* BRM Incremental Register */ +#define UBMR 0xa8 /* BRM Modulator Register */ +#define UBRC 0xac /* Baud Rate Count Register */ +#define MX2_ONEMS 0xb0 /* One Millisecond register */ +#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */ + +/* UART Control Register Bit Fields.*/ +#define URXD_CHARRDY (1<<15) +#define URXD_ERR (1<<14) +#define URXD_OVRRUN (1<<13) +#define URXD_FRMERR (1<<12) +#define URXD_BRK (1<<11) +#define URXD_PRERR (1<<10) +#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ +#define UCR1_ADBR (1<<14) /* Auto detect baud rate */ +#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ +#define UCR1_IDEN (1<<12) /* Idle condition interrupt */ +#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ +#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_IREN (1<<7) /* Infrared interface enable */ +#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ +#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ +#define UCR1_SNDBRK (1<<4) /* Send break */ +#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define MX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, mx1 only */ +#define UCR1_DOZE (1<<1) /* Doze */ +#define UCR1_UARTEN (1<<0) /* UART enabled */ +#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ +#define UCR2_IRTS (1<<14) /* Ignore RTS pin */ +#define UCR2_CTSC (1<<13) /* CTS pin control */ +#define UCR2_CTS (1<<12) /* Clear to send */ +#define UCR2_ESCEN (1<<11) /* Escape enable */ +#define UCR2_PREN (1<<8) /* Parity enable */ +#define UCR2_PROE (1<<7) /* Parity odd/even */ +#define UCR2_STPB (1<<6) /* Stop */ +#define UCR2_WS (1<<5) /* Word size */ +#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */ +#define UCR2_TXEN (1<<2) /* Transmitter enabled */ +#define UCR2_RXEN (1<<1) /* Receiver enabled */ +#define UCR2_SRST (1<<0) /* SW reset */ +#define UCR3_DTREN (1<<13) /* DTR interrupt enable */ +#define UCR3_PARERREN (1<<12) /* Parity enable */ +#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */ +#define UCR3_DSR (1<<10) /* Data set ready */ +#define UCR3_DCD (1<<9) /* Data carrier detect */ +#define UCR3_RI (1<<8) /* Ring indicator */ +#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ +#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ +#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ +#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ +#define MX1_UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */ +#define MX1_UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */ +#define MX2_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */ +#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ +#define UCR3_BPEN (1<<0) /* Preset registers enable */ +#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */ +#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */ +#define UCR4_INVR (1<<9) /* Inverted infrared reception */ +#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ +#define UCR4_WKEN (1<<7) /* Wake interrupt enable */ +#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IRSC (1<<5) /* IR special case */ +#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ +#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ +#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ +#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ +#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ +#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) +#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ +#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */ +#define USR1_RTSD (1<<12) /* RTS delta */ +#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ +#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ +#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ +#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ +#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ +#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */ +#define USR2_ADET (1<<15) /* Auto baud rate detect complete */ +#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ +#define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ +#define USR2_WAKE (1<<7) /* Wake */ +#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ +#define USR2_TXDC (1<<3) /* Transmitter complete */ +#define USR2_BRCD (1<<2) /* Break condition */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Recv data ready */ +#define UTS_FRCPERR (1<<13) /* Force parity error */ +#define UTS_LOOP (1<<12) /* Loop tx and rx */ +#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ +#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ +#define UTS_TXFULL (1<<4) /* TxFIFO full */ +#define UTS_RXFULL (1<<3) /* RxFIFO full */ +#define UTS_SOFTRST (1<<0) /* Software reset */ + +/* We've been assigned a range on the "Low-density serial ports" major */ +#define SERIAL_IMX_MAJOR 207 +#define MINOR_START 16 +#define DEV_NAME "ttymxc" +#define MAX_INTERNAL_IRQ MXC_INTERNAL_IRQS + +/* + * This determines how often we check the modem status signals + * for any change. They generally aren't connected to an IRQ + * so we have to poll them. We also check immediately before + * filling the TX fifo incase CTS has been dropped. + */ +#define MCTRL_TIMEOUT (250*HZ/1000) + +#define DRIVER_NAME "IMX-uart" + +#define UART_NR 8 + +struct imx_port { + struct uart_port port; + struct timer_list timer; + unsigned int old_status; + int txirq,rxirq,rtsirq; + unsigned int have_rtscts:1; + unsigned int use_irda:1; + unsigned int irda_inv_rx:1; + unsigned int irda_inv_tx:1; + unsigned short trcv_delay; /* transceiver delay */ + struct clk *clk; +}; + +#ifdef CONFIG_IRDA +#define USE_IRDA(sport) ((sport)->use_irda) +#else +#define USE_IRDA(sport) (0) +#endif + +/* + * Handle any change of modem status signal since we were last called. + */ +static void imx_mctrl_check(struct imx_port *sport) +{ + unsigned int status, changed; + + status = sport->port.ops->get_mctrl(&sport->port); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); +} + +/* + * This is our per-port timeout handler, for checking the + * modem status signals. + */ +static void imx_timeout(unsigned long data) +{ + struct imx_port *sport = (struct imx_port *)data; + unsigned long flags; + + if (sport->port.state) { + spin_lock_irqsave(&sport->port.lock, flags); + imx_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +} + +/* + * interrupts disabled on entry + */ +static void imx_stop_tx(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; + + if (USE_IRDA(sport)) { + /* half duplex - wait for end of transmission */ + int n = 256; + while ((--n > 0) && + !(readl(sport->port.membase + USR2) & USR2_TXDC)) { + udelay(5); + barrier(); + } + /* + * irda transceiver - wait a bit more to avoid + * cutoff, hardware dependent + */ + udelay(sport->trcv_delay); + + /* + * half duplex - reactivate receive mode, + * flush receive pipe echo crap + */ + if (readl(sport->port.membase + USR2) & USR2_TXDC) { + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_TCEN); + writel(temp, sport->port.membase + UCR4); + + while (readl(sport->port.membase + URXD0) & + URXD_CHARRDY) + barrier(); + + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_DREN; + writel(temp, sport->port.membase + UCR4); + } + return; + } + + temp = readl(sport->port.membase + UCR1); + writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); +} + +/* + * interrupts disabled on entry + */ +static void imx_stop_rx(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; + + temp = readl(sport->port.membase + UCR2); + writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void imx_enable_ms(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + + mod_timer(&sport->timer, jiffies); +} + +static inline void imx_transmit_buffer(struct imx_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + + while (!uart_circ_empty(xmit) && + !(readl(sport->port.membase + UTS) & UTS_TXFULL)) { + /* send xmit->buf[xmit->tail] + * out the port here */ + writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + imx_stop_tx(&sport->port); +} + +/* + * interrupts disabled on entry + */ +static void imx_start_tx(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; + + if (USE_IRDA(sport)) { + /* half duplex in IrDA mode; have to disable receive mode */ + temp = readl(sport->port.membase + UCR4); + temp &= ~(UCR4_DREN); + writel(temp, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RRDYEN); + writel(temp, sport->port.membase + UCR1); + } + + temp = readl(sport->port.membase + UCR1); + writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_TRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, sport->port.membase + UCR4); + } + + if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) + imx_transmit_buffer(sport); +} + +static irqreturn_t imx_rtsint(int irq, void *dev_id) +{ + struct imx_port *sport = dev_id; + unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + + writel(USR1_RTSD, sport->port.membase + USR1); + uart_handle_cts_change(&sport->port, !!val); + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); + + spin_unlock_irqrestore(&sport->port.lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t imx_txint(int irq, void *dev_id) +{ + struct imx_port *sport = dev_id; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock,flags); + if (sport->port.x_char) + { + /* Send next char */ + writel(sport->port.x_char, sport->port.membase + URTX0); + goto out; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + imx_stop_tx(&sport->port); + goto out; + } + + imx_transmit_buffer(sport); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + +out: + spin_unlock_irqrestore(&sport->port.lock,flags); + return IRQ_HANDLED; +} + +static irqreturn_t imx_rxint(int irq, void *dev_id) +{ + struct imx_port *sport = dev_id; + unsigned int rx,flg,ignored = 0; + struct tty_struct *tty = sport->port.state->port.tty; + unsigned long flags, temp; + + spin_lock_irqsave(&sport->port.lock,flags); + + while (readl(sport->port.membase + USR2) & USR2_RDR) { + flg = TTY_NORMAL; + sport->port.icount.rx++; + + rx = readl(sport->port.membase + URXD0); + + temp = readl(sport->port.membase + USR2); + if (temp & USR2_BRCD) { + writel(USR2_BRCD, sport->port.membase + USR2); + if (uart_handle_break(&sport->port)) + continue; + } + + if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + continue; + + if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { + if (rx & URXD_PRERR) + sport->port.icount.parity++; + else if (rx & URXD_FRMERR) + sport->port.icount.frame++; + if (rx & URXD_OVRRUN) + sport->port.icount.overrun++; + + if (rx & sport->port.ignore_status_mask) { + if (++ignored > 100) + goto out; + continue; + } + + rx &= sport->port.read_status_mask; + + if (rx & URXD_PRERR) + flg = TTY_PARITY; + else if (rx & URXD_FRMERR) + flg = TTY_FRAME; + if (rx & URXD_OVRRUN) + flg = TTY_OVERRUN; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } + + tty_insert_flip_char(tty, rx, flg); + } + +out: + spin_unlock_irqrestore(&sport->port.lock,flags); + tty_flip_buffer_push(tty); + return IRQ_HANDLED; +} + +static irqreturn_t imx_int(int irq, void *dev_id) +{ + struct imx_port *sport = dev_id; + unsigned int sts; + + sts = readl(sport->port.membase + USR1); + + if (sts & USR1_RRDY) + imx_rxint(irq, dev_id); + + if (sts & USR1_TRDY && + readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) + imx_txint(irq, dev_id); + + if (sts & USR1_RTSD) + imx_rtsint(irq, dev_id); + + return IRQ_HANDLED; +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int imx_tx_empty(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + + return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; +} + +/* + * We have a modem side uart, so the meanings of RTS and CTS are inverted. + */ +static unsigned int imx_get_mctrl(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned int tmp = TIOCM_DSR | TIOCM_CAR; + + if (readl(sport->port.membase + USR1) & USR1_RTSS) + tmp |= TIOCM_CTS; + + if (readl(sport->port.membase + UCR2) & UCR2_CTS) + tmp |= TIOCM_RTS; + + return tmp; +} + +static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; + + temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; + + if (mctrl & TIOCM_RTS) + temp |= UCR2_CTS; + + writel(temp, sport->port.membase + UCR2); +} + +/* + * Interrupts always disabled. + */ +static void imx_break_ctl(struct uart_port *port, int break_state) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long flags, temp; + + spin_lock_irqsave(&sport->port.lock, flags); + + temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK; + + if ( break_state != 0 ) + temp |= UCR1_SNDBRK; + + writel(temp, sport->port.membase + UCR1); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +#define TXTL 2 /* reset default */ +#define RXTL 1 /* reset default */ + +static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) +{ + unsigned int val; + unsigned int ufcr_rfdiv; + + /* set receiver / transmitter trigger level. + * RFDIV is set such way to satisfy requested uartclk value + */ + val = TXTL << 10 | RXTL; + ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2) + / sport->port.uartclk; + + if(!ufcr_rfdiv) + ufcr_rfdiv = 1; + + val |= UFCR_RFDIV_REG(ufcr_rfdiv); + + writel(val, sport->port.membase + UFCR); + + return 0; +} + +/* half the RX buffer size */ +#define CTSTL 16 + +static int imx_startup(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + int retval; + unsigned long flags, temp; + + imx_setup_ufcr(sport, 0); + + /* disable the DREN bit (Data Ready interrupt enable) before + * requesting IRQs + */ + temp = readl(sport->port.membase + UCR4); + + if (USE_IRDA(sport)) + temp |= UCR4_IRSC; + + /* set the trigger level for CTS */ + temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF); + temp |= CTSTL<< UCR4_CTSTL_SHF; + + writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + + if (USE_IRDA(sport)) { + /* reset fifo's and state machines */ + int i = 100; + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && + (--i > 0)) { + udelay(1); + } + } + + /* + * Allocate the IRQ(s) i.MX1 has three interrupts whereas later + * chips only have one interrupt. + */ + if (sport->txirq > 0) { + retval = request_irq(sport->rxirq, imx_rxint, 0, + DRIVER_NAME, sport); + if (retval) + goto error_out1; + + retval = request_irq(sport->txirq, imx_txint, 0, + DRIVER_NAME, sport); + if (retval) + goto error_out2; + + /* do not use RTS IRQ on IrDA */ + if (!USE_IRDA(sport)) { + retval = request_irq(sport->rtsirq, imx_rtsint, + (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + DRIVER_NAME, sport); + if (retval) + goto error_out3; + } + } else { + retval = request_irq(sport->port.irq, imx_int, 0, + DRIVER_NAME, sport); + if (retval) { + free_irq(sport->port.irq, sport); + goto error_out1; + } + } + + /* + * Finally, clear and enable interrupts + */ + writel(USR1_RTSD, sport->port.membase + USR1); + + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; + + if (USE_IRDA(sport)) { + temp |= UCR1_IREN; + temp &= ~(UCR1_RTSDEN); + } + + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR2); + temp |= (UCR2_RXEN | UCR2_TXEN); + writel(temp, sport->port.membase + UCR2); + + if (USE_IRDA(sport)) { + /* clear RX-FIFO */ + int i = 64; + while ((--i > 0) && + (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { + barrier(); + } + } + + if (!cpu_is_mx1()) { + temp = readl(sport->port.membase + UCR3); + temp |= MX2_UCR3_RXDMUXSEL; + writel(temp, sport->port.membase + UCR3); + } + + if (USE_IRDA(sport)) { + temp = readl(sport->port.membase + UCR4); + if (sport->irda_inv_rx) + temp |= UCR4_INVR; + else + temp &= ~(UCR4_INVR); + writel(temp | UCR4_DREN, sport->port.membase + UCR4); + + temp = readl(sport->port.membase + UCR3); + if (sport->irda_inv_tx) + temp |= UCR3_INVT; + else + temp &= ~(UCR3_INVT); + writel(temp, sport->port.membase + UCR3); + } + + /* + * Enable modem status interrupts + */ + spin_lock_irqsave(&sport->port.lock,flags); + imx_enable_ms(&sport->port); + spin_unlock_irqrestore(&sport->port.lock,flags); + + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + sport->irda_inv_rx = pdata->irda_inv_rx; + sport->irda_inv_tx = pdata->irda_inv_tx; + sport->trcv_delay = pdata->transceiver_delay; + if (pdata->irda_enable) + pdata->irda_enable(1); + } + + return 0; + +error_out3: + if (sport->txirq) + free_irq(sport->txirq, sport); +error_out2: + if (sport->rxirq) + free_irq(sport->rxirq, sport); +error_out1: + return retval; +} + +static void imx_shutdown(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long temp; + + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_TXEN); + writel(temp, sport->port.membase + UCR2); + + if (USE_IRDA(sport)) { + struct imxuart_platform_data *pdata; + pdata = sport->port.dev->platform_data; + if (pdata->irda_enable) + pdata->irda_enable(0); + } + + /* + * Stop our timer. + */ + del_timer_sync(&sport->timer); + + /* + * Free the interrupts + */ + if (sport->txirq > 0) { + if (!USE_IRDA(sport)) + free_irq(sport->rtsirq, sport); + free_irq(sport->txirq, sport); + free_irq(sport->rxirq, sport); + } else + free_irq(sport->port.irq, sport); + + /* + * Disable all interrupts, port and break condition. + */ + + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + if (USE_IRDA(sport)) + temp &= ~(UCR1_IREN); + + writel(temp, sport->port.membase + UCR1); +} + +static void +imx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned long flags; + unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + unsigned int div, ufcr; + unsigned long num, denom; + uint64_t tdiv64; + + /* + * If we don't support modem control lines, don't allow + * these to be set. + */ + if (0) { + termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); + termios->c_cflag |= CLOCAL; + } + + /* + * We only support CS7 and CS8. + */ + while ((termios->c_cflag & CSIZE) != CS7 && + (termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS8) + ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS; + else + ucr2 = UCR2_SRST | UCR2_IRTS; + + if (termios->c_cflag & CRTSCTS) { + if( sport->have_rtscts ) { + ucr2 &= ~UCR2_IRTS; + ucr2 |= UCR2_CTSC; + } else { + termios->c_cflag &= ~CRTSCTS; + } + } + + if (termios->c_cflag & CSTOPB) + ucr2 |= UCR2_STPB; + if (termios->c_cflag & PARENB) { + ucr2 |= UCR2_PREN; + if (termios->c_cflag & PARODD) + ucr2 |= UCR2_PROE; + } + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + quot = uart_get_divisor(port, baud); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask = 0; + if (termios->c_iflag & INPCK) + sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR); + if (termios->c_iflag & (BRKINT | PARMRK)) + sport->port.read_status_mask |= URXD_BRK; + + /* + * Characters to ignore + */ + sport->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= URXD_PRERR; + if (termios->c_iflag & IGNBRK) { + sport->port.ignore_status_mask |= URXD_BRK; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= URXD_OVRRUN; + } + + del_timer_sync(&sport->timer); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * disable interrupts and drain transmitter + */ + old_ucr1 = readl(sport->port.membase + UCR1); + writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), + sport->port.membase + UCR1); + + while ( !(readl(sport->port.membase + USR2) & USR2_TXDC)) + barrier(); + + /* then, disable everything */ + old_txrxen = readl(sport->port.membase + UCR2); + writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN), + sport->port.membase + UCR2); + old_txrxen &= (UCR2_TXEN | UCR2_RXEN); + + if (USE_IRDA(sport)) { + /* + * use maximum available submodule frequency to + * avoid missing short pulses due to low sampling rate + */ + div = 1; + } else { + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) + div = 1; + } + + rational_best_approximation(16 * div * baud, sport->port.uartclk, + 1 << 16, 1 << 16, &num, &denom); + + tdiv64 = sport->port.uartclk; + tdiv64 *= num; + do_div(tdiv64, denom * 16 * div); + tty_termios_encode_baud_rate(termios, + (speed_t)tdiv64, (speed_t)tdiv64); + + num -= 1; + denom -= 1; + + ufcr = readl(sport->port.membase + UFCR); + ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); + writel(ufcr, sport->port.membase + UFCR); + + writel(num, sport->port.membase + UBIR); + writel(denom, sport->port.membase + UBMR); + + if (!cpu_is_mx1()) + writel(sport->port.uartclk / div / 1000, + sport->port.membase + MX2_ONEMS); + + writel(old_ucr1, sport->port.membase + UCR1); + + /* set the parity, stop bits and data size */ + writel(ucr2 | old_txrxen, sport->port.membase + UCR2); + + if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) + imx_enable_ms(&sport->port); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static const char *imx_type(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + + return sport->port.type == PORT_IMX ? "IMX" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void imx_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *mmres; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mmres->start, mmres->end - mmres->start + 1); +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int imx_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *mmres; + void *ret; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mmres) + return -ENODEV; + + ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1, + "imx-uart"); + + return ret ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void imx_config_port(struct uart_port *port, int flags) +{ + struct imx_port *sport = (struct imx_port *)port; + + if (flags & UART_CONFIG_TYPE && + imx_request_port(&sport->port) == 0) + sport->port.type = PORT_IMX; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_IMX and PORT_UNKNOWN + */ +static int +imx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct imx_port *sport = (struct imx_port *)port; + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX) + ret = -EINVAL; + if (sport->port.irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != UPIO_MEM) + ret = -EINVAL; + if (sport->port.uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)sport->port.mapbase != ser->iomem_base) + ret = -EINVAL; + if (sport->port.iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +static struct uart_ops imx_pops = { + .tx_empty = imx_tx_empty, + .set_mctrl = imx_set_mctrl, + .get_mctrl = imx_get_mctrl, + .stop_tx = imx_stop_tx, + .start_tx = imx_start_tx, + .stop_rx = imx_stop_rx, + .enable_ms = imx_enable_ms, + .break_ctl = imx_break_ctl, + .startup = imx_startup, + .shutdown = imx_shutdown, + .set_termios = imx_set_termios, + .type = imx_type, + .release_port = imx_release_port, + .request_port = imx_request_port, + .config_port = imx_config_port, + .verify_port = imx_verify_port, +}; + +static struct imx_port *imx_ports[UART_NR]; + +#ifdef CONFIG_SERIAL_IMX_CONSOLE +static void imx_console_putchar(struct uart_port *port, int ch) +{ + struct imx_port *sport = (struct imx_port *)port; + + while (readl(sport->port.membase + UTS) & UTS_TXFULL) + barrier(); + + writel(ch, sport->port.membase + URTX0); +} + +/* + * Interrupts are disabled on entering + */ +static void +imx_console_write(struct console *co, const char *s, unsigned int count) +{ + struct imx_port *sport = imx_ports[co->index]; + unsigned int old_ucr1, old_ucr2, ucr1; + + /* + * First, save UCR1/2 and then disable interrupts + */ + ucr1 = old_ucr1 = readl(sport->port.membase + UCR1); + old_ucr2 = readl(sport->port.membase + UCR2); + + if (cpu_is_mx1()) + ucr1 |= MX1_UCR1_UARTCLKEN; + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); + + writel(ucr1, sport->port.membase + UCR1); + + writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2); + + uart_console_write(&sport->port, s, count, imx_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore UCR1/2 + */ + while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); + + writel(old_ucr1, sport->port.membase + UCR1); + writel(old_ucr2, sport->port.membase + UCR2); +} + +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +imx_console_get_options(struct imx_port *sport, int *baud, + int *parity, int *bits) +{ + + if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) { + /* ok, the port was enabled */ + unsigned int ucr2, ubir,ubmr, uartclk; + unsigned int baud_raw; + unsigned int ucfr_rfdiv; + + ucr2 = readl(sport->port.membase + UCR2); + + *parity = 'n'; + if (ucr2 & UCR2_PREN) { + if (ucr2 & UCR2_PROE) + *parity = 'o'; + else + *parity = 'e'; + } + + if (ucr2 & UCR2_WS) + *bits = 8; + else + *bits = 7; + + ubir = readl(sport->port.membase + UBIR) & 0xffff; + ubmr = readl(sport->port.membase + UBMR) & 0xffff; + + ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7; + if (ucfr_rfdiv == 6) + ucfr_rfdiv = 7; + else + ucfr_rfdiv = 6 - ucfr_rfdiv; + + uartclk = clk_get_rate(sport->clk); + uartclk /= ucfr_rfdiv; + + { /* + * The next code provides exact computation of + * baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1)) + * without need of float support or long long division, + * which would be required to prevent 32bit arithmetic overflow + */ + unsigned int mul = ubir + 1; + unsigned int div = 16 * (ubmr + 1); + unsigned int rem = uartclk % div; + + baud_raw = (uartclk / div) * mul; + baud_raw += (rem * mul + div / 2) / div; + *baud = (baud_raw + 50) / 100 * 100; + } + + if(*baud != baud_raw) + printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n", + baud_raw, *baud); + } +} + +static int __init +imx_console_setup(struct console *co, char *options) +{ + struct imx_port *sport; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) + co->index = 0; + sport = imx_ports[co->index]; + if(sport == NULL) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + imx_console_get_options(sport, &baud, &parity, &bits); + + imx_setup_ufcr(sport, 0); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver imx_reg; +static struct console imx_console = { + .name = DEV_NAME, + .write = imx_console_write, + .device = uart_console_device, + .setup = imx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &imx_reg, +}; + +#define IMX_CONSOLE &imx_console +#else +#define IMX_CONSOLE NULL +#endif + +static struct uart_driver imx_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = DEV_NAME, + .major = SERIAL_IMX_MAJOR, + .minor = MINOR_START, + .nr = ARRAY_SIZE(imx_ports), + .cons = IMX_CONSOLE, +}; + +static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) +{ + struct imx_port *sport = platform_get_drvdata(dev); + + if (sport) + uart_suspend_port(&imx_reg, &sport->port); + + return 0; +} + +static int serial_imx_resume(struct platform_device *dev) +{ + struct imx_port *sport = platform_get_drvdata(dev); + + if (sport) + uart_resume_port(&imx_reg, &sport->port); + + return 0; +} + +static int serial_imx_probe(struct platform_device *pdev) +{ + struct imx_port *sport; + struct imxuart_platform_data *pdata; + void __iomem *base; + int ret = 0; + struct resource *res; + + sport = kzalloc(sizeof(*sport), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto free; + } + + base = ioremap(res->start, PAGE_SIZE); + if (!base) { + ret = -ENOMEM; + goto free; + } + + sport->port.dev = &pdev->dev; + sport->port.mapbase = res->start; + sport->port.membase = base; + sport->port.type = PORT_IMX, + sport->port.iotype = UPIO_MEM; + sport->port.irq = platform_get_irq(pdev, 0); + sport->rxirq = platform_get_irq(pdev, 0); + sport->txirq = platform_get_irq(pdev, 1); + sport->rtsirq = platform_get_irq(pdev, 2); + sport->port.fifosize = 32; + sport->port.ops = &imx_pops; + sport->port.flags = UPF_BOOT_AUTOCONF; + sport->port.line = pdev->id; + init_timer(&sport->timer); + sport->timer.function = imx_timeout; + sport->timer.data = (unsigned long)sport; + + sport->clk = clk_get(&pdev->dev, "uart"); + if (IS_ERR(sport->clk)) { + ret = PTR_ERR(sport->clk); + goto unmap; + } + clk_enable(sport->clk); + + sport->port.uartclk = clk_get_rate(sport->clk); + + imx_ports[pdev->id] = sport; + + pdata = pdev->dev.platform_data; + if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + sport->have_rtscts = 1; + +#ifdef CONFIG_IRDA + if (pdata && (pdata->flags & IMXUART_IRDA)) + sport->use_irda = 1; +#endif + + if (pdata && pdata->init) { + ret = pdata->init(pdev); + if (ret) + goto clkput; + } + + ret = uart_add_one_port(&imx_reg, &sport->port); + if (ret) + goto deinit; + platform_set_drvdata(pdev, &sport->port); + + return 0; +deinit: + if (pdata && pdata->exit) + pdata->exit(pdev); +clkput: + clk_put(sport->clk); + clk_disable(sport->clk); +unmap: + iounmap(sport->port.membase); +free: + kfree(sport); + + return ret; +} + +static int serial_imx_remove(struct platform_device *pdev) +{ + struct imxuart_platform_data *pdata; + struct imx_port *sport = platform_get_drvdata(pdev); + + pdata = pdev->dev.platform_data; + + platform_set_drvdata(pdev, NULL); + + if (sport) { + uart_remove_one_port(&imx_reg, &sport->port); + clk_put(sport->clk); + } + + clk_disable(sport->clk); + + if (pdata && pdata->exit) + pdata->exit(pdev); + + iounmap(sport->port.membase); + kfree(sport); + + return 0; +} + +static struct platform_driver serial_imx_driver = { + .probe = serial_imx_probe, + .remove = serial_imx_remove, + + .suspend = serial_imx_suspend, + .resume = serial_imx_resume, + .driver = { + .name = "imx-uart", + .owner = THIS_MODULE, + }, +}; + +static int __init imx_serial_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: IMX driver\n"); + + ret = uart_register_driver(&imx_reg); + if (ret) + return ret; + + ret = platform_driver_register(&serial_imx_driver); + if (ret != 0) + uart_unregister_driver(&imx_reg); + + return 0; +} + +static void __exit imx_serial_exit(void) +{ + platform_driver_unregister(&serial_imx_driver); + uart_unregister_driver(&imx_reg); +} + +module_init(imx_serial_init); +module_exit(imx_serial_exit); + +MODULE_AUTHOR("Sascha Hauer"); +MODULE_DESCRIPTION("IMX generic serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:imx-uart"); diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c new file mode 100644 index 000000000000..ee43efc7bdcc --- /dev/null +++ b/drivers/tty/serial/ioc3_serial.c @@ -0,0 +1,2199 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * This file contains a module version of the ioc3 serial driver. This + * includes all the support functions needed (support functions, etc.) + * and the serial driver itself. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Interesting things about the ioc3 + */ + +#define LOGICAL_PORTS 2 /* rs232(0) and rs422(1) */ +#define PORTS_PER_CARD 2 +#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS) +#define MAX_CARDS 8 +#define MAX_LOGICAL_PORTS (LOGICAL_PORTS_PER_CARD * MAX_CARDS) + +/* determine given the sio_ir what port it applies to */ +#define GET_PORT_FROM_SIO_IR(_x) (_x & SIO_IR_SA) ? 0 : 1 + + +/* + * we have 2 logical ports (rs232, rs422) for each physical port + * evens are rs232, odds are rs422 + */ +#define GET_PHYSICAL_PORT(_x) ((_x) >> 1) +#define GET_LOGICAL_PORT(_x) ((_x) & 1) +#define IS_PHYSICAL_PORT(_x) !((_x) & 1) +#define IS_RS232(_x) !((_x) & 1) + +static unsigned int Num_of_ioc3_cards; +static unsigned int Submodule_slot; + +/* defining this will get you LOTS of great debug info */ +//#define DEBUG_INTERRUPTS +#define DPRINT_CONFIG(_x...) ; +//#define DPRINT_CONFIG(_x...) printk _x +#define NOT_PROGRESS() ; +//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__) + +/* number of characters we want to transmit to the lower level at a time */ +#define MAX_CHARS 256 +#define FIFO_SIZE (MAX_CHARS-1) /* it's a uchar */ + +/* Device name we're using */ +#define DEVICE_NAME "ttySIOC" +#define DEVICE_MAJOR 204 +#define DEVICE_MINOR 116 + +/* flags for next_char_state */ +#define NCS_BREAK 0x1 +#define NCS_PARITY 0x2 +#define NCS_FRAMING 0x4 +#define NCS_OVERRUN 0x8 + +/* cause we need SOME parameters ... */ +#define MIN_BAUD_SUPPORTED 1200 +#define MAX_BAUD_SUPPORTED 115200 + +/* protocol types supported */ +#define PROTO_RS232 0 +#define PROTO_RS422 1 + +/* Notification types */ +#define N_DATA_READY 0x01 +#define N_OUTPUT_LOWAT 0x02 +#define N_BREAK 0x04 +#define N_PARITY_ERROR 0x08 +#define N_FRAMING_ERROR 0x10 +#define N_OVERRUN_ERROR 0x20 +#define N_DDCD 0x40 +#define N_DCTS 0x80 + +#define N_ALL_INPUT (N_DATA_READY | N_BREAK \ + | N_PARITY_ERROR | N_FRAMING_ERROR \ + | N_OVERRUN_ERROR | N_DDCD | N_DCTS) + +#define N_ALL_OUTPUT N_OUTPUT_LOWAT + +#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR \ + | N_OVERRUN_ERROR) + +#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK \ + | N_PARITY_ERROR | N_FRAMING_ERROR \ + | N_OVERRUN_ERROR | N_DDCD | N_DCTS) + +#define SER_CLK_SPEED(prediv) ((22000000 << 1) / prediv) +#define SER_DIVISOR(x, clk) (((clk) + (x) * 8) / ((x) * 16)) +#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div)) + +/* Some masks */ +#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \ + | UART_LCR_WLEN7 | UART_LCR_WLEN8) +#define LCR_MASK_STOP_BITS (UART_LCR_STOP) + +#define PENDING(_a, _p) (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable) + +#define RING_BUF_SIZE 4096 +#define BUF_SIZE_BIT SBBR_L_SIZE +#define PROD_CONS_MASK PROD_CONS_PTR_4K + +#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4) + +/* driver specific - one per card */ +struct ioc3_card { + struct { + /* uart ports are allocated here */ + struct uart_port icp_uart_port[LOGICAL_PORTS]; + /* the ioc3_port used for this port */ + struct ioc3_port *icp_port; + } ic_port[PORTS_PER_CARD]; + /* currently enabled interrupts */ + uint32_t ic_enable; +}; + +/* Local port info for each IOC3 serial port */ +struct ioc3_port { + /* handy reference material */ + struct uart_port *ip_port; + struct ioc3_card *ip_card; + struct ioc3_driver_data *ip_idd; + struct ioc3_submodule *ip_is; + + /* pci mem addresses for this port */ + struct ioc3_serialregs __iomem *ip_serial_regs; + struct ioc3_uartregs __iomem *ip_uart_regs; + + /* Ring buffer page for this port */ + dma_addr_t ip_dma_ringbuf; + /* vaddr of ring buffer */ + struct ring_buffer *ip_cpu_ringbuf; + + /* Rings for this port */ + struct ring *ip_inring; + struct ring *ip_outring; + + /* Hook to port specific values */ + struct port_hooks *ip_hooks; + + spinlock_t ip_lock; + + /* Various rx/tx parameters */ + int ip_baud; + int ip_tx_lowat; + int ip_rx_timeout; + + /* Copy of notification bits */ + int ip_notify; + + /* Shadow copies of various registers so we don't need to PIO + * read them constantly + */ + uint32_t ip_sscr; + uint32_t ip_tx_prod; + uint32_t ip_rx_cons; + unsigned char ip_flags; +}; + +/* tx low water mark. We need to notify the driver whenever tx is getting + * close to empty so it can refill the tx buffer and keep things going. + * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll + * have no trouble getting in more chars in time (I certainly hope so). + */ +#define TX_LOWAT_LATENCY 1000 +#define TX_LOWAT_HZ (1000000 / TX_LOWAT_LATENCY) +#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ) + +/* Flags per port */ +#define INPUT_HIGH 0x01 + /* used to signify that we have turned off the rx_high + * temporarily - we need to drain the fifo and don't + * want to get blasted with interrupts. + */ +#define DCD_ON 0x02 + /* DCD state is on */ +#define LOWAT_WRITTEN 0x04 +#define READ_ABORTED 0x08 + /* the read was aborted - used to avaoid infinate looping + * in the interrupt handler + */ +#define INPUT_ENABLE 0x10 + +/* Since each port has different register offsets and bitmasks + * for everything, we'll store those that we need in tables so we + * don't have to be constantly checking the port we are dealing with. + */ +struct port_hooks { + uint32_t intr_delta_dcd; + uint32_t intr_delta_cts; + uint32_t intr_tx_mt; + uint32_t intr_rx_timer; + uint32_t intr_rx_high; + uint32_t intr_tx_explicit; + uint32_t intr_clear; + uint32_t intr_all; + char rs422_select_pin; +}; + +static struct port_hooks hooks_array[PORTS_PER_CARD] = { + /* values for port A */ + { + .intr_delta_dcd = SIO_IR_SA_DELTA_DCD, + .intr_delta_cts = SIO_IR_SA_DELTA_CTS, + .intr_tx_mt = SIO_IR_SA_TX_MT, + .intr_rx_timer = SIO_IR_SA_RX_TIMER, + .intr_rx_high = SIO_IR_SA_RX_HIGH, + .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT, + .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL + | SIO_IR_SA_RX_HIGH + | SIO_IR_SA_RX_TIMER + | SIO_IR_SA_DELTA_DCD + | SIO_IR_SA_DELTA_CTS + | SIO_IR_SA_INT + | SIO_IR_SA_TX_EXPLICIT + | SIO_IR_SA_MEMERR), + .intr_all = SIO_IR_SA, + .rs422_select_pin = GPPR_UARTA_MODESEL_PIN, + }, + + /* values for port B */ + { + .intr_delta_dcd = SIO_IR_SB_DELTA_DCD, + .intr_delta_cts = SIO_IR_SB_DELTA_CTS, + .intr_tx_mt = SIO_IR_SB_TX_MT, + .intr_rx_timer = SIO_IR_SB_RX_TIMER, + .intr_rx_high = SIO_IR_SB_RX_HIGH, + .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT, + .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL + | SIO_IR_SB_RX_HIGH + | SIO_IR_SB_RX_TIMER + | SIO_IR_SB_DELTA_DCD + | SIO_IR_SB_DELTA_CTS + | SIO_IR_SB_INT + | SIO_IR_SB_TX_EXPLICIT + | SIO_IR_SB_MEMERR), + .intr_all = SIO_IR_SB, + .rs422_select_pin = GPPR_UARTB_MODESEL_PIN, + } +}; + +struct ring_entry { + union { + struct { + uint32_t alldata; + uint32_t allsc; + } all; + struct { + char data[4]; /* data bytes */ + char sc[4]; /* status/control */ + } s; + } u; +}; + +/* Test the valid bits in any of the 4 sc chars using "allsc" member */ +#define RING_ANY_VALID \ + ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101) + +#define ring_sc u.s.sc +#define ring_data u.s.data +#define ring_allsc u.all.allsc + +/* Number of entries per ring buffer. */ +#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry)) + +/* An individual ring */ +struct ring { + struct ring_entry entries[ENTRIES_PER_RING]; +}; + +/* The whole enchilada */ +struct ring_buffer { + struct ring TX_A; + struct ring RX_A; + struct ring TX_B; + struct ring RX_B; +}; + +/* Get a ring from a port struct */ +#define RING(_p, _wh) &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh) + +/* for Infinite loop detection */ +#define MAXITER 10000000 + + +/** + * set_baud - Baud rate setting code + * @port: port to set + * @baud: baud rate to use + */ +static int set_baud(struct ioc3_port *port, int baud) +{ + int divisor; + int actual_baud; + int diff; + int lcr, prediv; + struct ioc3_uartregs __iomem *uart; + + for (prediv = 6; prediv < 64; prediv++) { + divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv)); + if (!divisor) + continue; /* invalid divisor */ + actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv)); + + diff = actual_baud - baud; + if (diff < 0) + diff = -diff; + + /* if we're within 1% we've found a match */ + if (diff * 100 <= actual_baud) + break; + } + + /* if the above loop completed, we didn't match + * the baud rate. give up. + */ + if (prediv == 64) { + NOT_PROGRESS(); + return 1; + } + + uart = port->ip_uart_regs; + lcr = readb(&uart->iu_lcr); + + writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr); + writeb((unsigned char)divisor, &uart->iu_dll); + writeb((unsigned char)(divisor >> 8), &uart->iu_dlm); + writeb((unsigned char)prediv, &uart->iu_scr); + writeb((unsigned char)lcr, &uart->iu_lcr); + + return 0; +} + +/** + * get_ioc3_port - given a uart port, return the control structure + * @the_port: uart port to find + */ +static struct ioc3_port *get_ioc3_port(struct uart_port *the_port) +{ + struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev); + struct ioc3_card *card_ptr = idd->data[Submodule_slot]; + int ii, jj; + + if (!card_ptr) { + NOT_PROGRESS(); + return NULL; + } + for (ii = 0; ii < PORTS_PER_CARD; ii++) { + for (jj = 0; jj < LOGICAL_PORTS; jj++) { + if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj]) + return card_ptr->ic_port[ii].icp_port; + } + } + NOT_PROGRESS(); + return NULL; +} + +/** + * port_init - Initialize the sio and ioc3 hardware for a given port + * called per port from attach... + * @port: port to initialize + */ +static int inline port_init(struct ioc3_port *port) +{ + uint32_t sio_cr; + struct port_hooks *hooks = port->ip_hooks; + struct ioc3_uartregs __iomem *uart; + int reset_loop_counter = 0xfffff; + struct ioc3_driver_data *idd = port->ip_idd; + + /* Idle the IOC3 serial interface */ + writel(SSCR_RESET, &port->ip_serial_regs->sscr); + + /* Wait until any pending bus activity for this port has ceased */ + do { + sio_cr = readl(&idd->vma->sio_cr); + if (reset_loop_counter-- <= 0) { + printk(KERN_WARNING + "IOC3 unable to come out of reset" + " scr 0x%x\n", sio_cr); + return -1; + } + } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) && + (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA) + || sio_cr == SIO_CR_ARB_DIAG_TXB + || sio_cr == SIO_CR_ARB_DIAG_RXA + || sio_cr == SIO_CR_ARB_DIAG_RXB)); + + /* Finish reset sequence */ + writel(0, &port->ip_serial_regs->sscr); + + /* Once RESET is done, reload cached tx_prod and rx_cons values + * and set rings to empty by making prod == cons + */ + port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; + writel(port->ip_tx_prod, &port->ip_serial_regs->stpir); + port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; + writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir); + + /* Disable interrupts for this 16550 */ + uart = port->ip_uart_regs; + writeb(0, &uart->iu_lcr); + writeb(0, &uart->iu_ier); + + /* Set the default baud */ + set_baud(port, port->ip_baud); + + /* Set line control to 8 bits no parity */ + writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr); + /* UART_LCR_STOP == 1 stop */ + + /* Enable the FIFOs */ + writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr); + /* then reset 16550 FIFOs */ + writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + &uart->iu_fcr); + + /* Clear modem control register */ + writeb(0, &uart->iu_mcr); + + /* Clear deltas in modem status register */ + writel(0, &port->ip_serial_regs->shadow); + + /* Only do this once per port pair */ + if (port->ip_hooks == &hooks_array[0]) { + unsigned long ring_pci_addr; + uint32_t __iomem *sbbr_l, *sbbr_h; + + sbbr_l = &idd->vma->sbbr_l; + sbbr_h = &idd->vma->sbbr_h; + ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; + DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n", + __func__, (void *)ring_pci_addr)); + + writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h); + writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l); + } + + /* Set the receive timeout value to 10 msec */ + writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr); + + /* Set rx threshold, enable DMA */ + /* Set high water mark at 3/4 of full ring */ + port->ip_sscr = (ENTRIES_PER_RING * 3 / 4); + + /* uart experiences pauses at high baud rate reducing actual + * throughput by 10% or so unless we enable high speed polling + * XXX when this hardware bug is resolved we should revert to + * normal polling speed + */ + port->ip_sscr |= SSCR_HIGH_SPD; + + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + + /* Disable and clear all serial related interrupt bits */ + port->ip_card->ic_enable &= ~hooks->intr_clear; + ioc3_disable(port->ip_is, idd, hooks->intr_clear); + ioc3_ack(port->ip_is, idd, hooks->intr_clear); + return 0; +} + +/** + * enable_intrs - enable interrupts + * @port: port to enable + * @mask: mask to use + */ +static void enable_intrs(struct ioc3_port *port, uint32_t mask) +{ + if ((port->ip_card->ic_enable & mask) != mask) { + port->ip_card->ic_enable |= mask; + ioc3_enable(port->ip_is, port->ip_idd, mask); + } +} + +/** + * local_open - local open a port + * @port: port to open + */ +static inline int local_open(struct ioc3_port *port) +{ + int spiniter = 0; + + port->ip_flags = INPUT_ENABLE; + + /* Pause the DMA interface if necessary */ + if (port->ip_sscr & SSCR_DMA_EN) { + writel(port->ip_sscr | SSCR_DMA_PAUSE, + &port->ip_serial_regs->sscr); + while ((readl(&port->ip_serial_regs->sscr) + & SSCR_PAUSE_STATE) == 0) { + spiniter++; + if (spiniter > MAXITER) { + NOT_PROGRESS(); + return -1; + } + } + } + + /* Reset the input fifo. If the uart received chars while the port + * was closed and DMA is not enabled, the uart may have a bunch of + * chars hanging around in its rx fifo which will not be discarded + * by rclr in the upper layer. We must get rid of them here. + */ + writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR, + &port->ip_uart_regs->iu_fcr); + + writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr); + /* UART_LCR_STOP == 1 stop */ + + /* Re-enable DMA, set default threshold to intr whenever there is + * data available. + */ + port->ip_sscr &= ~SSCR_RX_THRESHOLD; + port->ip_sscr |= 1; /* default threshold */ + + /* Plug in the new sscr. This implicitly clears the DMA_PAUSE + * flag if it was set above + */ + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + port->ip_tx_lowat = 1; + return 0; +} + +/** + * set_rx_timeout - Set rx timeout and threshold values. + * @port: port to use + * @timeout: timeout value in ticks + */ +static inline int set_rx_timeout(struct ioc3_port *port, int timeout) +{ + int threshold; + + port->ip_rx_timeout = timeout; + + /* Timeout is in ticks. Let's figure out how many chars we + * can receive at the current baud rate in that interval + * and set the rx threshold to that amount. There are 4 chars + * per ring entry, so we'll divide the number of chars that will + * arrive in timeout by 4. + * So .... timeout * baud / 10 / HZ / 4, with HZ = 100. + */ + threshold = timeout * port->ip_baud / 4000; + if (threshold == 0) + threshold = 1; /* otherwise we'll intr all the time! */ + + if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD) + return 1; + + port->ip_sscr &= ~SSCR_RX_THRESHOLD; + port->ip_sscr |= threshold; + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + + /* Now set the rx timeout to the given value + * again timeout * SRTR_HZ / HZ + */ + timeout = timeout * SRTR_HZ / 100; + if (timeout > SRTR_CNT) + timeout = SRTR_CNT; + writel(timeout, &port->ip_serial_regs->srtr); + return 0; +} + +/** + * config_port - config the hardware + * @port: port to config + * @baud: baud rate for the port + * @byte_size: data size + * @stop_bits: number of stop bits + * @parenb: parity enable ? + * @parodd: odd parity ? + */ +static inline int +config_port(struct ioc3_port *port, + int baud, int byte_size, int stop_bits, int parenb, int parodd) +{ + char lcr, sizebits; + int spiniter = 0; + + DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d " + "parodd %d\n", + __func__, ((struct uart_port *)port->ip_port)->line, + baud, byte_size, stop_bits, parenb, parodd)); + + if (set_baud(port, baud)) + return 1; + + switch (byte_size) { + case 5: + sizebits = UART_LCR_WLEN5; + break; + case 6: + sizebits = UART_LCR_WLEN6; + break; + case 7: + sizebits = UART_LCR_WLEN7; + break; + case 8: + sizebits = UART_LCR_WLEN8; + break; + default: + return 1; + } + + /* Pause the DMA interface if necessary */ + if (port->ip_sscr & SSCR_DMA_EN) { + writel(port->ip_sscr | SSCR_DMA_PAUSE, + &port->ip_serial_regs->sscr); + while ((readl(&port->ip_serial_regs->sscr) + & SSCR_PAUSE_STATE) == 0) { + spiniter++; + if (spiniter > MAXITER) + return -1; + } + } + + /* Clear relevant fields in lcr */ + lcr = readb(&port->ip_uart_regs->iu_lcr); + lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR | + UART_LCR_PARITY | LCR_MASK_STOP_BITS); + + /* Set byte size in lcr */ + lcr |= sizebits; + + /* Set parity */ + if (parenb) { + lcr |= UART_LCR_PARITY; + if (!parodd) + lcr |= UART_LCR_EPAR; + } + + /* Set stop bits */ + if (stop_bits) + lcr |= UART_LCR_STOP /* 2 stop bits */ ; + + writeb(lcr, &port->ip_uart_regs->iu_lcr); + + /* Re-enable the DMA interface if necessary */ + if (port->ip_sscr & SSCR_DMA_EN) { + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + port->ip_baud = baud; + + /* When we get within this number of ring entries of filling the + * entire ring on tx, place an EXPLICIT intr to generate a lowat + * notification when output has drained. + */ + port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4; + if (port->ip_tx_lowat == 0) + port->ip_tx_lowat = 1; + + set_rx_timeout(port, 2); + return 0; +} + +/** + * do_write - Write bytes to the port. Returns the number of bytes + * actually written. Called from transmit_chars + * @port: port to use + * @buf: the stuff to write + * @len: how many bytes in 'buf' + */ +static inline int do_write(struct ioc3_port *port, char *buf, int len) +{ + int prod_ptr, cons_ptr, total = 0; + struct ring *outring; + struct ring_entry *entry; + struct port_hooks *hooks = port->ip_hooks; + + BUG_ON(!(len >= 0)); + + prod_ptr = port->ip_tx_prod; + cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; + outring = port->ip_outring; + + /* Maintain a 1-entry red-zone. The ring buffer is full when + * (cons - prod) % ring_size is 1. Rather than do this subtraction + * in the body of the loop, I'll do it now. + */ + cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK; + + /* Stuff the bytes into the output */ + while ((prod_ptr != cons_ptr) && (len > 0)) { + int xx; + + /* Get 4 bytes (one ring entry) at a time */ + entry = (struct ring_entry *)((caddr_t) outring + prod_ptr); + + /* Invalidate all entries */ + entry->ring_allsc = 0; + + /* Copy in some bytes */ + for (xx = 0; (xx < 4) && (len > 0); xx++) { + entry->ring_data[xx] = *buf++; + entry->ring_sc[xx] = TXCB_VALID; + len--; + total++; + } + + /* If we are within some small threshold of filling up the + * entire ring buffer, we must place an EXPLICIT intr here + * to generate a lowat interrupt in case we subsequently + * really do fill up the ring and the caller goes to sleep. + * No need to place more than one though. + */ + if (!(port->ip_flags & LOWAT_WRITTEN) && + ((cons_ptr - prod_ptr) & PROD_CONS_MASK) + <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) { + port->ip_flags |= LOWAT_WRITTEN; + entry->ring_sc[0] |= TXCB_INT_WHEN_DONE; + } + + /* Go on to next entry */ + prod_ptr += sizeof(struct ring_entry); + prod_ptr &= PROD_CONS_MASK; + } + + /* If we sent something, start DMA if necessary */ + if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) { + port->ip_sscr |= SSCR_DMA_EN; + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + + /* Store the new producer pointer. If tx is disabled, we stuff the + * data into the ring buffer, but we don't actually start tx. + */ + if (!uart_tx_stopped(port->ip_port)) { + writel(prod_ptr, &port->ip_serial_regs->stpir); + + /* If we are now transmitting, enable tx_mt interrupt so we + * can disable DMA if necessary when the tx finishes. + */ + if (total > 0) + enable_intrs(port, hooks->intr_tx_mt); + } + port->ip_tx_prod = prod_ptr; + + return total; +} + +/** + * disable_intrs - disable interrupts + * @port: port to enable + * @mask: mask to use + */ +static inline void disable_intrs(struct ioc3_port *port, uint32_t mask) +{ + if (port->ip_card->ic_enable & mask) { + ioc3_disable(port->ip_is, port->ip_idd, mask); + port->ip_card->ic_enable &= ~mask; + } +} + +/** + * set_notification - Modify event notification + * @port: port to use + * @mask: events mask + * @set_on: set ? + */ +static int set_notification(struct ioc3_port *port, int mask, int set_on) +{ + struct port_hooks *hooks = port->ip_hooks; + uint32_t intrbits, sscrbits; + + BUG_ON(!mask); + + intrbits = sscrbits = 0; + + if (mask & N_DATA_READY) + intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high); + if (mask & N_OUTPUT_LOWAT) + intrbits |= hooks->intr_tx_explicit; + if (mask & N_DDCD) { + intrbits |= hooks->intr_delta_dcd; + sscrbits |= SSCR_RX_RING_DCD; + } + if (mask & N_DCTS) + intrbits |= hooks->intr_delta_cts; + + if (set_on) { + enable_intrs(port, intrbits); + port->ip_notify |= mask; + port->ip_sscr |= sscrbits; + } else { + disable_intrs(port, intrbits); + port->ip_notify &= ~mask; + port->ip_sscr &= ~sscrbits; + } + + /* We require DMA if either DATA_READY or DDCD notification is + * currently requested. If neither of these is requested and + * there is currently no tx in progress, DMA may be disabled. + */ + if (port->ip_notify & (N_DATA_READY | N_DDCD)) + port->ip_sscr |= SSCR_DMA_EN; + else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt)) + port->ip_sscr &= ~SSCR_DMA_EN; + + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + return 0; +} + +/** + * set_mcr - set the master control reg + * @the_port: port to use + * @mask1: mcr mask + * @mask2: shadow mask + */ +static inline int set_mcr(struct uart_port *the_port, + int mask1, int mask2) +{ + struct ioc3_port *port = get_ioc3_port(the_port); + uint32_t shadow; + int spiniter = 0; + char mcr; + + if (!port) + return -1; + + /* Pause the DMA interface if necessary */ + if (port->ip_sscr & SSCR_DMA_EN) { + writel(port->ip_sscr | SSCR_DMA_PAUSE, + &port->ip_serial_regs->sscr); + while ((readl(&port->ip_serial_regs->sscr) + & SSCR_PAUSE_STATE) == 0) { + spiniter++; + if (spiniter > MAXITER) + return -1; + } + } + shadow = readl(&port->ip_serial_regs->shadow); + mcr = (shadow & 0xff000000) >> 24; + + /* Set new value */ + mcr |= mask1; + shadow |= mask2; + writeb(mcr, &port->ip_uart_regs->iu_mcr); + writel(shadow, &port->ip_serial_regs->shadow); + + /* Re-enable the DMA interface if necessary */ + if (port->ip_sscr & SSCR_DMA_EN) { + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + return 0; +} + +/** + * ioc3_set_proto - set the protocol for the port + * @port: port to use + * @proto: protocol to use + */ +static int ioc3_set_proto(struct ioc3_port *port, int proto) +{ + struct port_hooks *hooks = port->ip_hooks; + + switch (proto) { + default: + case PROTO_RS232: + /* Clear the appropriate GIO pin */ + DPRINT_CONFIG(("%s: rs232\n", __func__)); + writel(0, (&port->ip_idd->vma->gppr[0] + + hooks->rs422_select_pin)); + break; + + case PROTO_RS422: + /* Set the appropriate GIO pin */ + DPRINT_CONFIG(("%s: rs422\n", __func__)); + writel(1, (&port->ip_idd->vma->gppr[0] + + hooks->rs422_select_pin)); + break; + } + return 0; +} + +/** + * transmit_chars - upper level write, called with the_port->lock + * @the_port: port to write + */ +static void transmit_chars(struct uart_port *the_port) +{ + int xmit_count, tail, head; + int result; + char *start; + struct tty_struct *tty; + struct ioc3_port *port = get_ioc3_port(the_port); + struct uart_state *state; + + if (!the_port) + return; + if (!port) + return; + + state = the_port->state; + tty = state->port.tty; + + if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { + /* Nothing to do or hw stopped */ + set_notification(port, N_ALL_OUTPUT, 0); + return; + } + + head = state->xmit.head; + tail = state->xmit.tail; + start = (char *)&state->xmit.buf[tail]; + + /* write out all the data or until the end of the buffer */ + xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail); + if (xmit_count > 0) { + result = do_write(port, start, xmit_count); + if (result > 0) { + /* booking */ + xmit_count -= result; + the_port->icount.tx += result; + /* advance the pointers */ + tail += result; + tail &= UART_XMIT_SIZE - 1; + state->xmit.tail = tail; + start = (char *)&state->xmit.buf[tail]; + } + } + if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS) + uart_write_wakeup(the_port); + + if (uart_circ_empty(&state->xmit)) { + set_notification(port, N_OUTPUT_LOWAT, 0); + } else { + set_notification(port, N_OUTPUT_LOWAT, 1); + } +} + +/** + * ioc3_change_speed - change the speed of the port + * @the_port: port to change + * @new_termios: new termios settings + * @old_termios: old termios settings + */ +static void +ioc3_change_speed(struct uart_port *the_port, + struct ktermios *new_termios, struct ktermios *old_termios) +{ + struct ioc3_port *port = get_ioc3_port(the_port); + unsigned int cflag, iflag; + int baud; + int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; + struct uart_state *state = the_port->state; + + cflag = new_termios->c_cflag; + iflag = new_termios->c_iflag; + + switch (cflag & CSIZE) { + case CS5: + new_data = 5; + break; + case CS6: + new_data = 6; + break; + case CS7: + new_data = 7; + break; + case CS8: + new_data = 8; + break; + default: + /* cuz we always need a default ... */ + new_data = 5; + break; + } + if (cflag & CSTOPB) { + new_stop = 1; + } + if (cflag & PARENB) { + new_parity_enable = 1; + if (cflag & PARODD) + new_parity = 1; + } + baud = uart_get_baud_rate(the_port, new_termios, old_termios, + MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); + DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud, + the_port->line)); + + if (!the_port->fifosize) + the_port->fifosize = FIFO_SIZE; + uart_update_timeout(the_port, cflag, baud); + + the_port->ignore_status_mask = N_ALL_INPUT; + + state->port.tty->low_latency = 1; + + if (iflag & IGNPAR) + the_port->ignore_status_mask &= ~(N_PARITY_ERROR + | N_FRAMING_ERROR); + if (iflag & IGNBRK) { + the_port->ignore_status_mask &= ~N_BREAK; + if (iflag & IGNPAR) + the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; + } + if (!(cflag & CREAD)) { + /* ignore everything */ + the_port->ignore_status_mask &= ~N_DATA_READY; + } + + if (cflag & CRTSCTS) { + /* enable hardware flow control */ + port->ip_sscr |= SSCR_HFC_EN; + } + else { + /* disable hardware flow control */ + port->ip_sscr &= ~SSCR_HFC_EN; + } + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + + /* Set the configuration and proper notification call */ + DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o " + "config_port(baud %d data %d stop %d penable %d " + " parity %d), notification 0x%x\n", + __func__, (void *)port, the_port->line, cflag, baud, + new_data, new_stop, new_parity_enable, new_parity, + the_port->ignore_status_mask)); + + if ((config_port(port, baud, /* baud */ + new_data, /* byte size */ + new_stop, /* stop bits */ + new_parity_enable, /* set parity */ + new_parity)) >= 0) { /* parity 1==odd */ + set_notification(port, the_port->ignore_status_mask, 1); + } +} + +/** + * ic3_startup_local - Start up the serial port - returns >= 0 if no errors + * @the_port: Port to operate on + */ +static inline int ic3_startup_local(struct uart_port *the_port) +{ + struct ioc3_port *port; + + if (!the_port) { + NOT_PROGRESS(); + return -1; + } + + port = get_ioc3_port(the_port); + if (!port) { + NOT_PROGRESS(); + return -1; + } + + local_open(port); + + /* set the protocol */ + ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 : + PROTO_RS422); + return 0; +} + +/* + * ioc3_cb_output_lowat - called when the output low water mark is hit + * @port: port to output + */ +static void ioc3_cb_output_lowat(struct ioc3_port *port) +{ + unsigned long pflags; + + /* the_port->lock is set on the call here */ + if (port->ip_port) { + spin_lock_irqsave(&port->ip_port->lock, pflags); + transmit_chars(port->ip_port); + spin_unlock_irqrestore(&port->ip_port->lock, pflags); + } +} + +/* + * ioc3_cb_post_ncs - called for some basic errors + * @port: port to use + * @ncs: event + */ +static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs) +{ + struct uart_icount *icount; + + icount = &the_port->icount; + + if (ncs & NCS_BREAK) + icount->brk++; + if (ncs & NCS_FRAMING) + icount->frame++; + if (ncs & NCS_OVERRUN) + icount->overrun++; + if (ncs & NCS_PARITY) + icount->parity++; +} + +/** + * do_read - Read in bytes from the port. Return the number of bytes + * actually read. + * @the_port: port to use + * @buf: place to put the stuff we read + * @len: how big 'buf' is + */ + +static inline int do_read(struct uart_port *the_port, char *buf, int len) +{ + int prod_ptr, cons_ptr, total; + struct ioc3_port *port = get_ioc3_port(the_port); + struct ring *inring; + struct ring_entry *entry; + struct port_hooks *hooks = port->ip_hooks; + int byte_num; + char *sc; + int loop_counter; + + BUG_ON(!(len >= 0)); + BUG_ON(!port); + + /* There is a nasty timing issue in the IOC3. When the rx_timer + * expires or the rx_high condition arises, we take an interrupt. + * At some point while servicing the interrupt, we read bytes from + * the ring buffer and re-arm the rx_timer. However the rx_timer is + * not started until the first byte is received *after* it is armed, + * and any bytes pending in the rx construction buffers are not drained + * to memory until either there are 4 bytes available or the rx_timer + * expires. This leads to a potential situation where data is left + * in the construction buffers forever - 1 to 3 bytes were received + * after the interrupt was generated but before the rx_timer was + * re-armed. At that point as long as no subsequent bytes are received + * the timer will never be started and the bytes will remain in the + * construction buffer forever. The solution is to execute a DRAIN + * command after rearming the timer. This way any bytes received before + * the DRAIN will be drained to memory, and any bytes received after + * the DRAIN will start the TIMER and be drained when it expires. + * Luckily, this only needs to be done when the DMA buffer is empty + * since there is no requirement that this function return all + * available data as long as it returns some. + */ + /* Re-arm the timer */ + + writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir); + + prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; + cons_ptr = port->ip_rx_cons; + + if (prod_ptr == cons_ptr) { + int reset_dma = 0; + + /* Input buffer appears empty, do a flush. */ + + /* DMA must be enabled for this to work. */ + if (!(port->ip_sscr & SSCR_DMA_EN)) { + port->ip_sscr |= SSCR_DMA_EN; + reset_dma = 1; + } + + /* Potential race condition: we must reload the srpir after + * issuing the drain command, otherwise we could think the rx + * buffer is empty, then take a very long interrupt, and when + * we come back it's full and we wait forever for the drain to + * complete. + */ + writel(port->ip_sscr | SSCR_RX_DRAIN, + &port->ip_serial_regs->sscr); + prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; + + /* We must not wait for the DRAIN to complete unless there are + * at least 8 bytes (2 ring entries) available to receive the + * data otherwise the DRAIN will never complete and we'll + * deadlock here. + * In fact, to make things easier, I'll just ignore the flush if + * there is any data at all now available. + */ + if (prod_ptr == cons_ptr) { + loop_counter = 0; + while (readl(&port->ip_serial_regs->sscr) & + SSCR_RX_DRAIN) { + loop_counter++; + if (loop_counter > MAXITER) + return -1; + } + + /* SIGH. We have to reload the prod_ptr *again* since + * the drain may have caused it to change + */ + prod_ptr = readl(&port->ip_serial_regs->srpir) + & PROD_CONS_MASK; + } + if (reset_dma) { + port->ip_sscr &= ~SSCR_DMA_EN; + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + } + inring = port->ip_inring; + port->ip_flags &= ~READ_ABORTED; + + total = 0; + loop_counter = 0xfffff; /* to avoid hangs */ + + /* Grab bytes from the hardware */ + while ((prod_ptr != cons_ptr) && (len > 0)) { + entry = (struct ring_entry *)((caddr_t) inring + cons_ptr); + + if (loop_counter-- <= 0) { + printk(KERN_WARNING "IOC3 serial: " + "possible hang condition/" + "port stuck on read (line %d).\n", + the_port->line); + break; + } + + /* According to the producer pointer, this ring entry + * must contain some data. But if the PIO happened faster + * than the DMA, the data may not be available yet, so let's + * wait until it arrives. + */ + if ((entry->ring_allsc & RING_ANY_VALID) == 0) { + /* Indicate the read is aborted so we don't disable + * the interrupt thinking that the consumer is + * congested. + */ + port->ip_flags |= READ_ABORTED; + len = 0; + break; + } + + /* Load the bytes/status out of the ring entry */ + for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) { + sc = &(entry->ring_sc[byte_num]); + + /* Check for change in modem state or overrun */ + if ((*sc & RXSB_MODEM_VALID) + && (port->ip_notify & N_DDCD)) { + /* Notify upper layer if DCD dropped */ + if ((port->ip_flags & DCD_ON) + && !(*sc & RXSB_DCD)) { + /* If we have already copied some data, + * return it. We'll pick up the carrier + * drop on the next pass. That way we + * don't throw away the data that has + * already been copied back to + * the caller's buffer. + */ + if (total > 0) { + len = 0; + break; + } + port->ip_flags &= ~DCD_ON; + + /* Turn off this notification so the + * carrier drop protocol won't see it + * again when it does a read. + */ + *sc &= ~RXSB_MODEM_VALID; + + /* To keep things consistent, we need + * to update the consumer pointer so + * the next reader won't come in and + * try to read the same ring entries + * again. This must be done here before + * the dcd change. + */ + + if ((entry->ring_allsc & RING_ANY_VALID) + == 0) { + cons_ptr += (int)sizeof + (struct ring_entry); + cons_ptr &= PROD_CONS_MASK; + } + writel(cons_ptr, + &port->ip_serial_regs->srcir); + port->ip_rx_cons = cons_ptr; + + /* Notify upper layer of carrier drop */ + if ((port->ip_notify & N_DDCD) + && port->ip_port) { + uart_handle_dcd_change + (port->ip_port, 0); + wake_up_interruptible + (&the_port->state-> + port.delta_msr_wait); + } + + /* If we had any data to return, we + * would have returned it above. + */ + return 0; + } + } + if (*sc & RXSB_MODEM_VALID) { + /* Notify that an input overrun occurred */ + if ((*sc & RXSB_OVERRUN) + && (port->ip_notify & N_OVERRUN_ERROR)) { + ioc3_cb_post_ncs(the_port, NCS_OVERRUN); + } + /* Don't look at this byte again */ + *sc &= ~RXSB_MODEM_VALID; + } + + /* Check for valid data or RX errors */ + if ((*sc & RXSB_DATA_VALID) && + ((*sc & (RXSB_PAR_ERR + | RXSB_FRAME_ERR | RXSB_BREAK)) + && (port->ip_notify & (N_PARITY_ERROR + | N_FRAMING_ERROR + | N_BREAK)))) { + /* There is an error condition on the next byte. + * If we have already transferred some bytes, + * we'll stop here. Otherwise if this is the + * first byte to be read, we'll just transfer + * it alone after notifying the + * upper layer of its status. + */ + if (total > 0) { + len = 0; + break; + } else { + if ((*sc & RXSB_PAR_ERR) && + (port-> + ip_notify & N_PARITY_ERROR)) { + ioc3_cb_post_ncs(the_port, + NCS_PARITY); + } + if ((*sc & RXSB_FRAME_ERR) && + (port-> + ip_notify & N_FRAMING_ERROR)) { + ioc3_cb_post_ncs(the_port, + NCS_FRAMING); + } + if ((*sc & RXSB_BREAK) + && (port->ip_notify & N_BREAK)) { + ioc3_cb_post_ncs + (the_port, NCS_BREAK); + } + len = 1; + } + } + if (*sc & RXSB_DATA_VALID) { + *sc &= ~RXSB_DATA_VALID; + *buf = entry->ring_data[byte_num]; + buf++; + len--; + total++; + } + } + + /* If we used up this entry entirely, go on to the next one, + * otherwise we must have run out of buffer space, so + * leave the consumer pointer here for the next read in case + * there are still unread bytes in this entry. + */ + if ((entry->ring_allsc & RING_ANY_VALID) == 0) { + cons_ptr += (int)sizeof(struct ring_entry); + cons_ptr &= PROD_CONS_MASK; + } + } + + /* Update consumer pointer and re-arm rx timer interrupt */ + writel(cons_ptr, &port->ip_serial_regs->srcir); + port->ip_rx_cons = cons_ptr; + + /* If we have now dipped below the rx high water mark and we have + * rx_high interrupt turned off, we can now turn it back on again. + */ + if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr) + & PROD_CONS_MASK) < + ((port-> + ip_sscr & + SSCR_RX_THRESHOLD) + << PROD_CONS_PTR_OFF))) { + port->ip_flags &= ~INPUT_HIGH; + enable_intrs(port, hooks->intr_rx_high); + } + return total; +} + +/** + * receive_chars - upper level read. + * @the_port: port to read from + */ +static int receive_chars(struct uart_port *the_port) +{ + struct tty_struct *tty; + unsigned char ch[MAX_CHARS]; + int read_count = 0, read_room, flip = 0; + struct uart_state *state = the_port->state; + struct ioc3_port *port = get_ioc3_port(the_port); + unsigned long pflags; + + /* Make sure all the pointers are "good" ones */ + if (!state) + return 0; + if (!state->port.tty) + return 0; + + if (!(port->ip_flags & INPUT_ENABLE)) + return 0; + + spin_lock_irqsave(&the_port->lock, pflags); + tty = state->port.tty; + + read_count = do_read(the_port, ch, MAX_CHARS); + if (read_count > 0) { + flip = 1; + read_room = tty_insert_flip_string(tty, ch, read_count); + the_port->icount.rx += read_count; + } + spin_unlock_irqrestore(&the_port->lock, pflags); + + if (flip) + tty_flip_buffer_push(tty); + + return read_count; +} + +/** + * ioc3uart_intr_one - lowest level (per port) interrupt handler. + * @is : submodule + * @idd: driver data + * @pending: interrupts to handle + */ + +static int inline +ioc3uart_intr_one(struct ioc3_submodule *is, + struct ioc3_driver_data *idd, + unsigned int pending) +{ + int port_num = GET_PORT_FROM_SIO_IR(pending); + struct port_hooks *hooks; + unsigned int rx_high_rd_aborted = 0; + unsigned long flags; + struct uart_port *the_port; + struct ioc3_port *port; + int loop_counter; + struct ioc3_card *card_ptr; + unsigned int sio_ir; + + card_ptr = idd->data[is->id]; + port = card_ptr->ic_port[port_num].icp_port; + hooks = port->ip_hooks; + + /* Possible race condition here: The tx_mt interrupt bit may be + * cleared without the intervention of the interrupt handler, + * e.g. by a write. If the top level interrupt handler reads a + * tx_mt, then some other processor does a write, starting up + * output, then we come in here, see the tx_mt and stop DMA, the + * output started by the other processor will hang. Thus we can + * only rely on tx_mt being legitimate if it is read while the + * port lock is held. Therefore this bit must be ignored in the + * passed in interrupt mask which was read by the top level + * interrupt handler since the port lock was not held at the time + * it was read. We can only rely on this bit being accurate if it + * is read while the port lock is held. So we'll clear it for now, + * and reload it later once we have the port lock. + */ + + sio_ir = pending & ~(hooks->intr_tx_mt); + spin_lock_irqsave(&port->ip_lock, flags); + + loop_counter = MAXITER; /* to avoid hangs */ + + do { + uint32_t shadow; + + if (loop_counter-- <= 0) { + printk(KERN_WARNING "IOC3 serial: " + "possible hang condition/" + "port stuck on interrupt (line %d).\n", + ((struct uart_port *)port->ip_port)->line); + break; + } + /* Handle a DCD change */ + if (sio_ir & hooks->intr_delta_dcd) { + ioc3_ack(is, idd, hooks->intr_delta_dcd); + shadow = readl(&port->ip_serial_regs->shadow); + + if ((port->ip_notify & N_DDCD) + && (shadow & SHADOW_DCD) + && (port->ip_port)) { + the_port = port->ip_port; + uart_handle_dcd_change(the_port, + shadow & SHADOW_DCD); + wake_up_interruptible + (&the_port->state->port.delta_msr_wait); + } else if ((port->ip_notify & N_DDCD) + && !(shadow & SHADOW_DCD)) { + /* Flag delta DCD/no DCD */ + uart_handle_dcd_change(port->ip_port, + shadow & SHADOW_DCD); + port->ip_flags |= DCD_ON; + } + } + + /* Handle a CTS change */ + if (sio_ir & hooks->intr_delta_cts) { + ioc3_ack(is, idd, hooks->intr_delta_cts); + shadow = readl(&port->ip_serial_regs->shadow); + + if ((port->ip_notify & N_DCTS) && (port->ip_port)) { + the_port = port->ip_port; + uart_handle_cts_change(the_port, shadow + & SHADOW_CTS); + wake_up_interruptible + (&the_port->state->port.delta_msr_wait); + } + } + + /* rx timeout interrupt. Must be some data available. Put this + * before the check for rx_high since servicing this condition + * may cause that condition to clear. + */ + if (sio_ir & hooks->intr_rx_timer) { + ioc3_ack(is, idd, hooks->intr_rx_timer); + if ((port->ip_notify & N_DATA_READY) + && (port->ip_port)) { + receive_chars(port->ip_port); + } + } + + /* rx high interrupt. Must be after rx_timer. */ + else if (sio_ir & hooks->intr_rx_high) { + /* Data available, notify upper layer */ + if ((port->ip_notify & N_DATA_READY) && port->ip_port) { + receive_chars(port->ip_port); + } + + /* We can't ACK this interrupt. If receive_chars didn't + * cause the condition to clear, we'll have to disable + * the interrupt until the data is drained. + * If the read was aborted, don't disable the interrupt + * as this may cause us to hang indefinitely. An + * aborted read generally means that this interrupt + * hasn't been delivered to the cpu yet anyway, even + * though we see it as asserted when we read the sio_ir. + */ + if ((sio_ir = PENDING(card_ptr, idd)) + & hooks->intr_rx_high) { + if (port->ip_flags & READ_ABORTED) { + rx_high_rd_aborted++; + } + else { + card_ptr->ic_enable &= ~hooks->intr_rx_high; + port->ip_flags |= INPUT_HIGH; + } + } + } + + /* We got a low water interrupt: notify upper layer to + * send more data. Must come before tx_mt since servicing + * this condition may cause that condition to clear. + */ + if (sio_ir & hooks->intr_tx_explicit) { + port->ip_flags &= ~LOWAT_WRITTEN; + ioc3_ack(is, idd, hooks->intr_tx_explicit); + if (port->ip_notify & N_OUTPUT_LOWAT) + ioc3_cb_output_lowat(port); + } + + /* Handle tx_mt. Must come after tx_explicit. */ + else if (sio_ir & hooks->intr_tx_mt) { + /* If we are expecting a lowat notification + * and we get to this point it probably means that for + * some reason the tx_explicit didn't work as expected + * (that can legitimately happen if the output buffer is + * filled up in just the right way). + * So send the notification now. + */ + if (port->ip_notify & N_OUTPUT_LOWAT) { + ioc3_cb_output_lowat(port); + + /* We need to reload the sio_ir since the lowat + * call may have caused another write to occur, + * clearing the tx_mt condition. + */ + sio_ir = PENDING(card_ptr, idd); + } + + /* If the tx_mt condition still persists even after the + * lowat call, we've got some work to do. + */ + if (sio_ir & hooks->intr_tx_mt) { + /* If we are not currently expecting DMA input, + * and the transmitter has just gone idle, + * there is no longer any reason for DMA, so + * disable it. + */ + if (!(port->ip_notify + & (N_DATA_READY | N_DDCD))) { + BUG_ON(!(port->ip_sscr + & SSCR_DMA_EN)); + port->ip_sscr &= ~SSCR_DMA_EN; + writel(port->ip_sscr, + &port->ip_serial_regs->sscr); + } + /* Prevent infinite tx_mt interrupt */ + card_ptr->ic_enable &= ~hooks->intr_tx_mt; + } + } + sio_ir = PENDING(card_ptr, idd); + + /* if the read was aborted and only hooks->intr_rx_high, + * clear hooks->intr_rx_high, so we do not loop forever. + */ + + if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) { + sio_ir &= ~hooks->intr_rx_high; + } + } while (sio_ir & hooks->intr_all); + + spin_unlock_irqrestore(&port->ip_lock, flags); + ioc3_enable(is, idd, card_ptr->ic_enable); + return 0; +} + +/** + * ioc3uart_intr - field all serial interrupts + * @is : submodule + * @idd: driver data + * @pending: interrupts to handle + * + */ + +static int ioc3uart_intr(struct ioc3_submodule *is, + struct ioc3_driver_data *idd, + unsigned int pending) +{ + int ret = 0; + + /* + * The upper level interrupt handler sends interrupts for both ports + * here. So we need to call for each port with its interrupts. + */ + + if (pending & SIO_IR_SA) + ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA); + if (pending & SIO_IR_SB) + ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB); + + return ret; +} + +/** + * ic3_type + * @port: Port to operate with (we ignore since we only have one port) + * + */ +static const char *ic3_type(struct uart_port *the_port) +{ + if (IS_RS232(the_port->line)) + return "SGI IOC3 Serial [rs232]"; + else + return "SGI IOC3 Serial [rs422]"; +} + +/** + * ic3_tx_empty - Is the transmitter empty? + * @port: Port to operate on + * + */ +static unsigned int ic3_tx_empty(struct uart_port *the_port) +{ + unsigned int ret = 0; + struct ioc3_port *port = get_ioc3_port(the_port); + + if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT) + ret = TIOCSER_TEMT; + return ret; +} + +/** + * ic3_stop_tx - stop the transmitter + * @port: Port to operate on + * + */ +static void ic3_stop_tx(struct uart_port *the_port) +{ + struct ioc3_port *port = get_ioc3_port(the_port); + + if (port) + set_notification(port, N_OUTPUT_LOWAT, 0); +} + +/** + * ic3_stop_rx - stop the receiver + * @port: Port to operate on + * + */ +static void ic3_stop_rx(struct uart_port *the_port) +{ + struct ioc3_port *port = get_ioc3_port(the_port); + + if (port) + port->ip_flags &= ~INPUT_ENABLE; +} + +/** + * null_void_function + * @port: Port to operate on + * + */ +static void null_void_function(struct uart_port *the_port) +{ +} + +/** + * ic3_shutdown - shut down the port - free irq and disable + * @port: port to shut down + * + */ +static void ic3_shutdown(struct uart_port *the_port) +{ + unsigned long port_flags; + struct ioc3_port *port; + struct uart_state *state; + + port = get_ioc3_port(the_port); + if (!port) + return; + + state = the_port->state; + wake_up_interruptible(&state->port.delta_msr_wait); + + spin_lock_irqsave(&the_port->lock, port_flags); + set_notification(port, N_ALL, 0); + spin_unlock_irqrestore(&the_port->lock, port_flags); +} + +/** + * ic3_set_mctrl - set control lines (dtr, rts, etc) + * @port: Port to operate on + * @mctrl: Lines to set/unset + * + */ +static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl) +{ + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + set_mcr(the_port, mcr, SHADOW_DTR); +} + +/** + * ic3_get_mctrl - get control line info + * @port: port to operate on + * + */ +static unsigned int ic3_get_mctrl(struct uart_port *the_port) +{ + struct ioc3_port *port = get_ioc3_port(the_port); + uint32_t shadow; + unsigned int ret = 0; + + if (!port) + return 0; + + shadow = readl(&port->ip_serial_regs->shadow); + if (shadow & SHADOW_DCD) + ret |= TIOCM_CD; + if (shadow & SHADOW_DR) + ret |= TIOCM_DSR; + if (shadow & SHADOW_CTS) + ret |= TIOCM_CTS; + return ret; +} + +/** + * ic3_start_tx - Start transmitter. Called with the_port->lock + * @port: Port to operate on + * + */ +static void ic3_start_tx(struct uart_port *the_port) +{ + struct ioc3_port *port = get_ioc3_port(the_port); + + if (port) { + set_notification(port, N_OUTPUT_LOWAT, 1); + enable_intrs(port, port->ip_hooks->intr_tx_mt); + } +} + +/** + * ic3_break_ctl - handle breaks + * @port: Port to operate on + * @break_state: Break state + * + */ +static void ic3_break_ctl(struct uart_port *the_port, int break_state) +{ +} + +/** + * ic3_startup - Start up the serial port - always return 0 (We're always on) + * @port: Port to operate on + * + */ +static int ic3_startup(struct uart_port *the_port) +{ + int retval; + struct ioc3_port *port; + struct ioc3_card *card_ptr; + unsigned long port_flags; + + if (!the_port) { + NOT_PROGRESS(); + return -ENODEV; + } + port = get_ioc3_port(the_port); + if (!port) { + NOT_PROGRESS(); + return -ENODEV; + } + card_ptr = port->ip_card; + port->ip_port = the_port; + + if (!card_ptr) { + NOT_PROGRESS(); + return -ENODEV; + } + + /* Start up the serial port */ + spin_lock_irqsave(&the_port->lock, port_flags); + retval = ic3_startup_local(the_port); + spin_unlock_irqrestore(&the_port->lock, port_flags); + return retval; +} + +/** + * ic3_set_termios - set termios stuff + * @port: port to operate on + * @termios: New settings + * @termios: Old + * + */ +static void +ic3_set_termios(struct uart_port *the_port, + struct ktermios *termios, struct ktermios *old_termios) +{ + unsigned long port_flags; + + spin_lock_irqsave(&the_port->lock, port_flags); + ioc3_change_speed(the_port, termios, old_termios); + spin_unlock_irqrestore(&the_port->lock, port_flags); +} + +/** + * ic3_request_port - allocate resources for port - no op.... + * @port: port to operate on + * + */ +static int ic3_request_port(struct uart_port *port) +{ + return 0; +} + +/* Associate the uart functions above - given to serial core */ +static struct uart_ops ioc3_ops = { + .tx_empty = ic3_tx_empty, + .set_mctrl = ic3_set_mctrl, + .get_mctrl = ic3_get_mctrl, + .stop_tx = ic3_stop_tx, + .start_tx = ic3_start_tx, + .stop_rx = ic3_stop_rx, + .enable_ms = null_void_function, + .break_ctl = ic3_break_ctl, + .startup = ic3_startup, + .shutdown = ic3_shutdown, + .set_termios = ic3_set_termios, + .type = ic3_type, + .release_port = null_void_function, + .request_port = ic3_request_port, +}; + +/* + * Boot-time initialization code + */ + +static struct uart_driver ioc3_uart = { + .owner = THIS_MODULE, + .driver_name = "ioc3_serial", + .dev_name = DEVICE_NAME, + .major = DEVICE_MAJOR, + .minor = DEVICE_MINOR, + .nr = MAX_LOGICAL_PORTS +}; + +/** + * ioc3_serial_core_attach - register with serial core + * This is done during pci probing + * @is: submodule struct for this + * @idd: handle for this card + */ +static inline int ioc3_serial_core_attach( struct ioc3_submodule *is, + struct ioc3_driver_data *idd) +{ + struct ioc3_port *port; + struct uart_port *the_port; + struct ioc3_card *card_ptr = idd->data[is->id]; + int ii, phys_port; + struct pci_dev *pdev = idd->pdev; + + DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n", + __func__, pdev, (void *)card_ptr)); + + if (!card_ptr) + return -ENODEV; + + /* once around for each logical port on this card */ + for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) { + phys_port = GET_PHYSICAL_PORT(ii); + the_port = &card_ptr->ic_port[phys_port]. + icp_uart_port[GET_LOGICAL_PORT(ii)]; + port = card_ptr->ic_port[phys_port].icp_port; + port->ip_port = the_port; + + DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n", + __func__, (void *)the_port, (void *)port, + phys_port, ii)); + + /* membase, iobase and mapbase just need to be non-0 */ + the_port->membase = (unsigned char __iomem *)1; + the_port->iobase = (pdev->bus->number << 16) | ii; + the_port->line = (Num_of_ioc3_cards << 2) | ii; + the_port->mapbase = 1; + the_port->type = PORT_16550A; + the_port->fifosize = FIFO_SIZE; + the_port->ops = &ioc3_ops; + the_port->irq = idd->irq_io; + the_port->dev = &pdev->dev; + + if (uart_add_one_port(&ioc3_uart, the_port) < 0) { + printk(KERN_WARNING + "%s: unable to add port %d bus %d\n", + __func__, the_port->line, pdev->bus->number); + } else { + DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n", + the_port->line, the_port->irq, pdev->bus->number)); + } + + /* all ports are rs232 for now */ + if (IS_PHYSICAL_PORT(ii)) + ioc3_set_proto(port, PROTO_RS232); + } + return 0; +} + +/** + * ioc3uart_remove - register detach function + * @is: submodule struct for this submodule + * @idd: ioc3 driver data for this submodule + */ + +static int ioc3uart_remove(struct ioc3_submodule *is, + struct ioc3_driver_data *idd) +{ + struct ioc3_card *card_ptr = idd->data[is->id]; + struct uart_port *the_port; + struct ioc3_port *port; + int ii; + + if (card_ptr) { + for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) { + the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)]. + icp_uart_port[GET_LOGICAL_PORT(ii)]; + if (the_port) + uart_remove_one_port(&ioc3_uart, the_port); + port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port; + if (port && IS_PHYSICAL_PORT(ii) + && (GET_PHYSICAL_PORT(ii) == 0)) { + pci_free_consistent(port->ip_idd->pdev, + TOTAL_RING_BUF_SIZE, + (void *)port->ip_cpu_ringbuf, + port->ip_dma_ringbuf); + kfree(port); + card_ptr->ic_port[GET_PHYSICAL_PORT(ii)]. + icp_port = NULL; + } + } + kfree(card_ptr); + idd->data[is->id] = NULL; + } + return 0; +} + +/** + * ioc3uart_probe - card probe function called from shim driver + * @is: submodule struct for this submodule + * @idd: ioc3 driver data for this card + */ + +static int __devinit +ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) +{ + struct pci_dev *pdev = idd->pdev; + struct ioc3_card *card_ptr; + int ret = 0; + struct ioc3_port *port; + struct ioc3_port *ports[PORTS_PER_CARD]; + int phys_port; + int cnt; + + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd)); + + card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL); + if (!card_ptr) { + printk(KERN_WARNING "ioc3_attach_one" + ": unable to get memory for the IOC3\n"); + return -ENOMEM; + } + idd->data[is->id] = card_ptr; + Submodule_slot = is->id; + + writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) | + ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) | + (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr); + + pci_write_config_dword(pdev, PCI_LAT, 0xff00); + + /* Enable serial port mode select generic PIO pins as outputs */ + ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL); + + /* Create port structures for each port */ + for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) { + port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL); + if (!port) { + printk(KERN_WARNING + "IOC3 serial memory not available for port\n"); + ret = -ENOMEM; + goto out4; + } + spin_lock_init(&port->ip_lock); + + /* we need to remember the previous ones, to point back to + * them farther down - setting up the ring buffers. + */ + ports[phys_port] = port; + + /* init to something useful */ + card_ptr->ic_port[phys_port].icp_port = port; + port->ip_is = is; + port->ip_idd = idd; + port->ip_baud = 9600; + port->ip_card = card_ptr; + port->ip_hooks = &hooks_array[phys_port]; + + /* Setup each port */ + if (phys_port == 0) { + port->ip_serial_regs = &idd->vma->port_a; + port->ip_uart_regs = &idd->vma->sregs.uarta; + + DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p " + "ip_uart_regs 0x%p\n", + __func__, + (void *)port->ip_serial_regs, + (void *)port->ip_uart_regs)); + + /* setup ring buffers */ + port->ip_cpu_ringbuf = pci_alloc_consistent(pdev, + TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf); + + BUG_ON(!((((int64_t) port->ip_dma_ringbuf) & + (TOTAL_RING_BUF_SIZE - 1)) == 0)); + port->ip_inring = RING(port, RX_A); + port->ip_outring = RING(port, TX_A); + DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p " + "ip_dma_ringbuf 0x%p, ip_inring 0x%p " + "ip_outring 0x%p\n", + __func__, + (void *)port->ip_cpu_ringbuf, + (void *)port->ip_dma_ringbuf, + (void *)port->ip_inring, + (void *)port->ip_outring)); + } + else { + port->ip_serial_regs = &idd->vma->port_b; + port->ip_uart_regs = &idd->vma->sregs.uartb; + + DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p " + "ip_uart_regs 0x%p\n", + __func__, + (void *)port->ip_serial_regs, + (void *)port->ip_uart_regs)); + + /* share the ring buffers */ + port->ip_dma_ringbuf = + ports[phys_port - 1]->ip_dma_ringbuf; + port->ip_cpu_ringbuf = + ports[phys_port - 1]->ip_cpu_ringbuf; + port->ip_inring = RING(port, RX_B); + port->ip_outring = RING(port, TX_B); + DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p " + "ip_dma_ringbuf 0x%p, ip_inring 0x%p " + "ip_outring 0x%p\n", + __func__, + (void *)port->ip_cpu_ringbuf, + (void *)port->ip_dma_ringbuf, + (void *)port->ip_inring, + (void *)port->ip_outring)); + } + + DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p", + __func__, + phys_port, (void *)port, (void *)card_ptr)); + DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n", + (void *)port->ip_serial_regs, + (void *)port->ip_uart_regs)); + + /* Initialize the hardware for IOC3 */ + port_init(port); + + DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p " + "outring 0x%p\n", + __func__, + phys_port, (void *)port, + (void *)port->ip_inring, + (void *)port->ip_outring)); + + } + + /* register port with the serial core */ + + if ((ret = ioc3_serial_core_attach(is, idd))) + goto out4; + + Num_of_ioc3_cards++; + + return ret; + + /* error exits that give back resources */ +out4: + for (cnt = 0; cnt < phys_port; cnt++) + kfree(ports[cnt]); + + kfree(card_ptr); + return ret; +} + +static struct ioc3_submodule ioc3uart_ops = { + .name = "IOC3uart", + .probe = ioc3uart_probe, + .remove = ioc3uart_remove, + /* call .intr for both ports initially */ + .irq_mask = SIO_IR_SA | SIO_IR_SB, + .intr = ioc3uart_intr, + .owner = THIS_MODULE, +}; + +/** + * ioc3_detect - module init called, + */ +static int __init ioc3uart_init(void) +{ + int ret; + + /* register with serial core */ + if ((ret = uart_register_driver(&ioc3_uart)) < 0) { + printk(KERN_WARNING + "%s: Couldn't register IOC3 uart serial driver\n", + __func__); + return ret; + } + ret = ioc3_register_submodule(&ioc3uart_ops); + if (ret) + uart_unregister_driver(&ioc3_uart); + return ret; +} + +static void __exit ioc3uart_exit(void) +{ + ioc3_unregister_submodule(&ioc3uart_ops); + uart_unregister_driver(&ioc3_uart); +} + +module_init(ioc3uart_init); +module_exit(ioc3uart_exit); + +MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); +MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c new file mode 100644 index 000000000000..fcfe82653ac8 --- /dev/null +++ b/drivers/tty/serial/ioc4_serial.c @@ -0,0 +1,2953 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * This file contains a module version of the ioc4 serial driver. This + * includes all the support functions needed (support functions, etc.) + * and the serial driver itself. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * interesting things about the ioc4 + */ + +#define IOC4_NUM_SERIAL_PORTS 4 /* max ports per card */ +#define IOC4_NUM_CARDS 8 /* max cards per partition */ + +#define GET_SIO_IR(_n) (_n == 0) ? (IOC4_SIO_IR_S0) : \ + (_n == 1) ? (IOC4_SIO_IR_S1) : \ + (_n == 2) ? (IOC4_SIO_IR_S2) : \ + (IOC4_SIO_IR_S3) + +#define GET_OTHER_IR(_n) (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \ + (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \ + (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \ + (IOC4_OTHER_IR_S3_MEMERR) + + +/* + * All IOC4 registers are 32 bits wide. + */ + +/* + * PCI Memory Space Map + */ +#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */ +#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0) +#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1) +#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK (0xe << 1) +#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK (0x1 << 1) +#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5) +#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6) + +/* Interrupt types */ +#define IOC4_SIO_INTR_TYPE 0 +#define IOC4_OTHER_INTR_TYPE 1 +#define IOC4_NUM_INTR_TYPES 2 + +/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */ +#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */ +#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */ +#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */ +#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */ +#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */ +#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */ +#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */ +#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */ +#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */ +#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */ +#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */ +#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */ +#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */ +#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */ +#define IOC4_SIO_IR_S1_INT 0x00004000 /* */ +#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */ +#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */ +#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */ +#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */ +#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */ +#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */ +#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */ +#define IOC4_SIO_IR_S2_INT 0x00400000 /* */ +#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */ +#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */ +#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */ +#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */ +#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */ +#define IOC4_SIO_IR_S3_INT 0x40000000 /* */ +#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* */ + +/* Per device interrupt masks */ +#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \ + IOC4_SIO_IR_S0_RX_FULL | \ + IOC4_SIO_IR_S0_RX_HIGH | \ + IOC4_SIO_IR_S0_RX_TIMER | \ + IOC4_SIO_IR_S0_DELTA_DCD | \ + IOC4_SIO_IR_S0_DELTA_CTS | \ + IOC4_SIO_IR_S0_INT | \ + IOC4_SIO_IR_S0_TX_EXPLICIT) +#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \ + IOC4_SIO_IR_S1_RX_FULL | \ + IOC4_SIO_IR_S1_RX_HIGH | \ + IOC4_SIO_IR_S1_RX_TIMER | \ + IOC4_SIO_IR_S1_DELTA_DCD | \ + IOC4_SIO_IR_S1_DELTA_CTS | \ + IOC4_SIO_IR_S1_INT | \ + IOC4_SIO_IR_S1_TX_EXPLICIT) +#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \ + IOC4_SIO_IR_S2_RX_FULL | \ + IOC4_SIO_IR_S2_RX_HIGH | \ + IOC4_SIO_IR_S2_RX_TIMER | \ + IOC4_SIO_IR_S2_DELTA_DCD | \ + IOC4_SIO_IR_S2_DELTA_CTS | \ + IOC4_SIO_IR_S2_INT | \ + IOC4_SIO_IR_S2_TX_EXPLICIT) +#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \ + IOC4_SIO_IR_S3_RX_FULL | \ + IOC4_SIO_IR_S3_RX_HIGH | \ + IOC4_SIO_IR_S3_RX_TIMER | \ + IOC4_SIO_IR_S3_DELTA_DCD | \ + IOC4_SIO_IR_S3_DELTA_CTS | \ + IOC4_SIO_IR_S3_INT | \ + IOC4_SIO_IR_S3_TX_EXPLICIT) + +/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ +#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ +#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ +#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ +#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ +#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ +#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */ +#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */ +#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */ +#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */ + +#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \ + IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR) + +/* Bitmasks for IOC4_SIO_CR */ +#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */ +#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000 +#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010 +#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020 +#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030 +#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040 +#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050 +#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060 +#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070 +#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among + serial ports (ro) */ +/* Defs for some of the generic I/O pins */ +#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0 + mode sel */ +#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1 + mode sel */ +#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2 + mode sel */ +#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3 + mode sel */ + +#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling + uart 0 mode select */ +#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling + uart 1 mode select */ +#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling + uart 2 mode select */ +#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling + uart 3 mode select */ + +/* Bitmasks for serial RX status byte */ +#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */ +#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */ +#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */ +#define IOC4_RXSB_BREAK 0x08 /* Break character */ +#define IOC4_RXSB_CTS 0x10 /* State of CTS */ +#define IOC4_RXSB_DCD 0x20 /* State of DCD */ +#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */ +#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR + * & BREAK valid */ + +/* Bitmasks for serial TX control byte */ +#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */ +#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */ +#define IOC4_TXCB_VALID 0x40 /* Byte is valid */ +#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control reg */ +#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec */ + +/* Bitmasks for IOC4_SBBR_L */ +#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ + +/* Bitmasks for IOC4_SSCR_<3:0> */ +#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */ +#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ +#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */ +#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */ +#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */ +#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */ +#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */ +#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */ +#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */ +#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */ +#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels */ + +/* All producer/comsumer pointers are the same bitfield */ +#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */ +#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */ +#define IOC4_PROD_CONS_PTR_OFF 3 + +/* Bitmasks for IOC4_SRCIR_<3:0> */ +#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer */ + +/* Bitmasks for IOC4_SHADOW_<3:0> */ +#define IOC4_SHADOW_DR 0x00000001 /* Data ready */ +#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */ +#define IOC4_SHADOW_PE 0x00000004 /* Parity error */ +#define IOC4_SHADOW_FE 0x00000008 /* Framing error */ +#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */ +#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */ +#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */ +#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */ +#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */ +#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */ +#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */ +#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */ +#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */ +#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */ +#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ +#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ +#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled */ + +/* Bitmasks for IOC4_SRTR_<3:0> */ +#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */ +#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */ +#define IOC4_SRTR_CNT_VAL_SHIFT 16 +#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency */ + +/* Serial port register map used for DMA and PIO serial I/O */ +struct ioc4_serialregs { + uint32_t sscr; + uint32_t stpir; + uint32_t stcir; + uint32_t srpir; + uint32_t srcir; + uint32_t srtr; + uint32_t shadow; +}; + +/* IOC4 UART register map */ +struct ioc4_uartregs { + char i4u_lcr; + union { + char iir; /* read only */ + char fcr; /* write only */ + } u3; + union { + char ier; /* DLAB == 0 */ + char dlm; /* DLAB == 1 */ + } u2; + union { + char rbr; /* read only, DLAB == 0 */ + char thr; /* write only, DLAB == 0 */ + char dll; /* DLAB == 1 */ + } u1; + char i4u_scr; + char i4u_msr; + char i4u_lsr; + char i4u_mcr; +}; + +/* short names */ +#define i4u_dll u1.dll +#define i4u_ier u2.ier +#define i4u_dlm u2.dlm +#define i4u_fcr u3.fcr + +/* Serial port registers used for DMA serial I/O */ +struct ioc4_serial { + uint32_t sbbr01_l; + uint32_t sbbr01_h; + uint32_t sbbr23_l; + uint32_t sbbr23_h; + + struct ioc4_serialregs port_0; + struct ioc4_serialregs port_1; + struct ioc4_serialregs port_2; + struct ioc4_serialregs port_3; + struct ioc4_uartregs uart_0; + struct ioc4_uartregs uart_1; + struct ioc4_uartregs uart_2; + struct ioc4_uartregs uart_3; +} ioc4_serial; + +/* UART clock speed */ +#define IOC4_SER_XIN_CLK_66 66666667 +#define IOC4_SER_XIN_CLK_33 33333333 + +#define IOC4_W_IES 0 +#define IOC4_W_IEC 1 + +typedef void ioc4_intr_func_f(void *, uint32_t); +typedef ioc4_intr_func_f *ioc4_intr_func_t; + +static unsigned int Num_of_ioc4_cards; + +/* defining this will get you LOTS of great debug info */ +//#define DEBUG_INTERRUPTS +#define DPRINT_CONFIG(_x...) ; +//#define DPRINT_CONFIG(_x...) printk _x + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* number of characters we want to transmit to the lower level at a time */ +#define IOC4_MAX_CHARS 256 +#define IOC4_FIFO_CHARS 255 + +/* Device name we're using */ +#define DEVICE_NAME_RS232 "ttyIOC" +#define DEVICE_NAME_RS422 "ttyAIOC" +#define DEVICE_MAJOR 204 +#define DEVICE_MINOR_RS232 50 +#define DEVICE_MINOR_RS422 84 + + +/* register offsets */ +#define IOC4_SERIAL_OFFSET 0x300 + +/* flags for next_char_state */ +#define NCS_BREAK 0x1 +#define NCS_PARITY 0x2 +#define NCS_FRAMING 0x4 +#define NCS_OVERRUN 0x8 + +/* cause we need SOME parameters ... */ +#define MIN_BAUD_SUPPORTED 1200 +#define MAX_BAUD_SUPPORTED 115200 + +/* protocol types supported */ +#define PROTO_RS232 3 +#define PROTO_RS422 7 + +/* Notification types */ +#define N_DATA_READY 0x01 +#define N_OUTPUT_LOWAT 0x02 +#define N_BREAK 0x04 +#define N_PARITY_ERROR 0x08 +#define N_FRAMING_ERROR 0x10 +#define N_OVERRUN_ERROR 0x20 +#define N_DDCD 0x40 +#define N_DCTS 0x80 + +#define N_ALL_INPUT (N_DATA_READY | N_BREAK | \ + N_PARITY_ERROR | N_FRAMING_ERROR | \ + N_OVERRUN_ERROR | N_DDCD | N_DCTS) + +#define N_ALL_OUTPUT N_OUTPUT_LOWAT + +#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR) + +#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK | \ + N_PARITY_ERROR | N_FRAMING_ERROR | \ + N_OVERRUN_ERROR | N_DDCD | N_DCTS) + +#define SER_DIVISOR(_x, clk) (((clk) + (_x) * 8) / ((_x) * 16)) +#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div)) + +/* Some masks */ +#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \ + | UART_LCR_WLEN7 | UART_LCR_WLEN8) +#define LCR_MASK_STOP_BITS (UART_LCR_STOP) + +#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb) +#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw) + +/* Default to 4k buffers */ +#ifdef IOC4_1K_BUFFERS +#define RING_BUF_SIZE 1024 +#define IOC4_BUF_SIZE_BIT 0 +#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K +#else +#define RING_BUF_SIZE 4096 +#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE +#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K +#endif + +#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4) + +/* + * This is the entry saved by the driver - one per card + */ + +#define UART_PORT_MIN 0 +#define UART_PORT_RS232 UART_PORT_MIN +#define UART_PORT_RS422 1 +#define UART_PORT_COUNT 2 /* one for each mode */ + +struct ioc4_control { + int ic_irq; + struct { + /* uart ports are allocated here - 1 for rs232, 1 for rs422 */ + struct uart_port icp_uart_port[UART_PORT_COUNT]; + /* Handy reference material */ + struct ioc4_port *icp_port; + } ic_port[IOC4_NUM_SERIAL_PORTS]; + struct ioc4_soft *ic_soft; +}; + +/* + * per-IOC4 data structure + */ +#define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t)) +struct ioc4_soft { + struct ioc4_misc_regs __iomem *is_ioc4_misc_addr; + struct ioc4_serial __iomem *is_ioc4_serial_addr; + + /* Each interrupt type has an entry in the array */ + struct ioc4_intr_type { + + /* + * Each in-use entry in this array contains at least + * one nonzero bit in sd_bits; no two entries in this + * array have overlapping sd_bits values. + */ + struct ioc4_intr_info { + uint32_t sd_bits; + ioc4_intr_func_f *sd_intr; + void *sd_info; + } is_intr_info[MAX_IOC4_INTR_ENTS]; + + /* Number of entries active in the above array */ + atomic_t is_num_intrs; + } is_intr_type[IOC4_NUM_INTR_TYPES]; + + /* is_ir_lock must be held while + * modifying sio_ie values, so + * we can be sure that sio_ie is + * not changing when we read it + * along with sio_ir. + */ + spinlock_t is_ir_lock; /* SIO_IE[SC] mod lock */ +}; + +/* Local port info for each IOC4 serial ports */ +struct ioc4_port { + struct uart_port *ip_port; /* current active port ptr */ + /* Ptrs for all ports */ + struct uart_port *ip_all_ports[UART_PORT_COUNT]; + /* Back ptrs for this port */ + struct ioc4_control *ip_control; + struct pci_dev *ip_pdev; + struct ioc4_soft *ip_ioc4_soft; + + /* pci mem addresses */ + struct ioc4_misc_regs __iomem *ip_mem; + struct ioc4_serial __iomem *ip_serial; + struct ioc4_serialregs __iomem *ip_serial_regs; + struct ioc4_uartregs __iomem *ip_uart_regs; + + /* Ring buffer page for this port */ + dma_addr_t ip_dma_ringbuf; + /* vaddr of ring buffer */ + struct ring_buffer *ip_cpu_ringbuf; + + /* Rings for this port */ + struct ring *ip_inring; + struct ring *ip_outring; + + /* Hook to port specific values */ + struct hooks *ip_hooks; + + spinlock_t ip_lock; + + /* Various rx/tx parameters */ + int ip_baud; + int ip_tx_lowat; + int ip_rx_timeout; + + /* Copy of notification bits */ + int ip_notify; + + /* Shadow copies of various registers so we don't need to PIO + * read them constantly + */ + uint32_t ip_ienb; /* Enabled interrupts */ + uint32_t ip_sscr; + uint32_t ip_tx_prod; + uint32_t ip_rx_cons; + int ip_pci_bus_speed; + unsigned char ip_flags; +}; + +/* tx low water mark. We need to notify the driver whenever tx is getting + * close to empty so it can refill the tx buffer and keep things going. + * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll + * have no trouble getting in more chars in time (I certainly hope so). + */ +#define TX_LOWAT_LATENCY 1000 +#define TX_LOWAT_HZ (1000000 / TX_LOWAT_LATENCY) +#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ) + +/* Flags per port */ +#define INPUT_HIGH 0x01 +#define DCD_ON 0x02 +#define LOWAT_WRITTEN 0x04 +#define READ_ABORTED 0x08 +#define PORT_ACTIVE 0x10 +#define PORT_INACTIVE 0 /* This is the value when "off" */ + + +/* Since each port has different register offsets and bitmasks + * for everything, we'll store those that we need in tables so we + * don't have to be constantly checking the port we are dealing with. + */ +struct hooks { + uint32_t intr_delta_dcd; + uint32_t intr_delta_cts; + uint32_t intr_tx_mt; + uint32_t intr_rx_timer; + uint32_t intr_rx_high; + uint32_t intr_tx_explicit; + uint32_t intr_dma_error; + uint32_t intr_clear; + uint32_t intr_all; + int rs422_select_pin; +}; + +static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = { + /* Values for port 0 */ + { + IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS, + IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER, + IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT, + IOC4_OTHER_IR_S0_MEMERR, + (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL | + IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER | + IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS | + IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT), + IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN, + }, + + /* Values for port 1 */ + { + IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS, + IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER, + IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT, + IOC4_OTHER_IR_S1_MEMERR, + (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL | + IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER | + IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS | + IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT), + IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN, + }, + + /* Values for port 2 */ + { + IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS, + IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER, + IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT, + IOC4_OTHER_IR_S2_MEMERR, + (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL | + IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER | + IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS | + IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT), + IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN, + }, + + /* Values for port 3 */ + { + IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS, + IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER, + IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT, + IOC4_OTHER_IR_S3_MEMERR, + (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL | + IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER | + IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS | + IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT), + IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN, + } +}; + +/* A ring buffer entry */ +struct ring_entry { + union { + struct { + uint32_t alldata; + uint32_t allsc; + } all; + struct { + char data[4]; /* data bytes */ + char sc[4]; /* status/control */ + } s; + } u; +}; + +/* Test the valid bits in any of the 4 sc chars using "allsc" member */ +#define RING_ANY_VALID \ + ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101) + +#define ring_sc u.s.sc +#define ring_data u.s.data +#define ring_allsc u.all.allsc + +/* Number of entries per ring buffer. */ +#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry)) + +/* An individual ring */ +struct ring { + struct ring_entry entries[ENTRIES_PER_RING]; +}; + +/* The whole enchilada */ +struct ring_buffer { + struct ring TX_0_OR_2; + struct ring RX_0_OR_2; + struct ring TX_1_OR_3; + struct ring RX_1_OR_3; +}; + +/* Get a ring from a port struct */ +#define RING(_p, _wh) &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh) + +/* Infinite loop detection. + */ +#define MAXITER 10000000 + +/* Prototypes */ +static void receive_chars(struct uart_port *); +static void handle_intr(void *arg, uint32_t sio_ir); + +/* + * port_is_active - determines if this port is currently active + * @port: ptr to soft struct for this port + * @uart_port: uart port to test for + */ +static inline int port_is_active(struct ioc4_port *port, + struct uart_port *uart_port) +{ + if (port) { + if ((port->ip_flags & PORT_ACTIVE) + && (port->ip_port == uart_port)) + return 1; + } + return 0; +} + + +/** + * write_ireg - write the interrupt regs + * @ioc4_soft: ptr to soft struct for this port + * @val: value to write + * @which: which register + * @type: which ireg set + */ +static inline void +write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type) +{ + struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr; + unsigned long flags; + + spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags); + + switch (type) { + case IOC4_SIO_INTR_TYPE: + switch (which) { + case IOC4_W_IES: + writel(val, &mem->sio_ies.raw); + break; + + case IOC4_W_IEC: + writel(val, &mem->sio_iec.raw); + break; + } + break; + + case IOC4_OTHER_INTR_TYPE: + switch (which) { + case IOC4_W_IES: + writel(val, &mem->other_ies.raw); + break; + + case IOC4_W_IEC: + writel(val, &mem->other_iec.raw); + break; + } + break; + + default: + break; + } + spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags); +} + +/** + * set_baud - Baud rate setting code + * @port: port to set + * @baud: baud rate to use + */ +static int set_baud(struct ioc4_port *port, int baud) +{ + int actual_baud; + int diff; + int lcr; + unsigned short divisor; + struct ioc4_uartregs __iomem *uart; + + divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed); + if (!divisor) + return 1; + actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed); + + diff = actual_baud - baud; + if (diff < 0) + diff = -diff; + + /* If we're within 1%, we've found a match */ + if (diff * 100 > actual_baud) + return 1; + + uart = port->ip_uart_regs; + lcr = readb(&uart->i4u_lcr); + writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr); + writeb((unsigned char)divisor, &uart->i4u_dll); + writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm); + writeb(lcr, &uart->i4u_lcr); + return 0; +} + + +/** + * get_ioc4_port - given a uart port, return the control structure + * @port: uart port + * @set: set this port as current + */ +static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set) +{ + struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev); + struct ioc4_control *control = idd->idd_serial_data; + struct ioc4_port *port; + int port_num, port_type; + + if (control) { + for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; + port_num++ ) { + port = control->ic_port[port_num].icp_port; + if (!port) + continue; + for (port_type = UART_PORT_MIN; + port_type < UART_PORT_COUNT; + port_type++) { + if (the_port == port->ip_all_ports + [port_type]) { + /* set local copy */ + if (set) { + port->ip_port = the_port; + } + return port; + } + } + } + } + return NULL; +} + +/* The IOC4 hardware provides no atomic way to determine if interrupts + * are pending since two reads are required to do so. The handler must + * read the SIO_IR and the SIO_IES, and take the logical and of the + * two. When this value is zero, all interrupts have been serviced and + * the handler may return. + * + * This has the unfortunate "hole" that, if some other CPU or + * some other thread or some higher level interrupt manages to + * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may + * think we have observed SIO_IR&SIO_IE==0 when in fact this + * condition never really occurred. + * + * To solve this, we use a simple spinlock that must be held + * whenever modifying SIO_IE; holding this lock while observing + * both SIO_IR and SIO_IE guarantees that we do not falsely + * conclude that no enabled interrupts are pending. + */ + +static inline uint32_t +pending_intrs(struct ioc4_soft *soft, int type) +{ + struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; + unsigned long flag; + uint32_t intrs = 0; + + BUG_ON(!((type == IOC4_SIO_INTR_TYPE) + || (type == IOC4_OTHER_INTR_TYPE))); + + spin_lock_irqsave(&soft->is_ir_lock, flag); + + switch (type) { + case IOC4_SIO_INTR_TYPE: + intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw); + break; + + case IOC4_OTHER_INTR_TYPE: + intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw); + + /* Don't process any ATA interrupte */ + intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); + break; + + default: + break; + } + spin_unlock_irqrestore(&soft->is_ir_lock, flag); + return intrs; +} + +/** + * port_init - Initialize the sio and ioc4 hardware for a given port + * called per port from attach... + * @port: port to initialize + */ +static int inline port_init(struct ioc4_port *port) +{ + uint32_t sio_cr; + struct hooks *hooks = port->ip_hooks; + struct ioc4_uartregs __iomem *uart; + + /* Idle the IOC4 serial interface */ + writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr); + + /* Wait until any pending bus activity for this port has ceased */ + do + sio_cr = readl(&port->ip_mem->sio_cr.raw); + while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE)); + + /* Finish reset sequence */ + writel(0, &port->ip_serial_regs->sscr); + + /* Once RESET is done, reload cached tx_prod and rx_cons values + * and set rings to empty by making prod == cons + */ + port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; + writel(port->ip_tx_prod, &port->ip_serial_regs->stpir); + port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; + writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); + + /* Disable interrupts for this 16550 */ + uart = port->ip_uart_regs; + writeb(0, &uart->i4u_lcr); + writeb(0, &uart->i4u_ier); + + /* Set the default baud */ + set_baud(port, port->ip_baud); + + /* Set line control to 8 bits no parity */ + writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr); + /* UART_LCR_STOP == 1 stop */ + + /* Enable the FIFOs */ + writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr); + /* then reset 16550 FIFOs */ + writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + &uart->i4u_fcr); + + /* Clear modem control register */ + writeb(0, &uart->i4u_mcr); + + /* Clear deltas in modem status register */ + readb(&uart->i4u_msr); + + /* Only do this once per port pair */ + if (port->ip_hooks == &hooks_array[0] + || port->ip_hooks == &hooks_array[2]) { + unsigned long ring_pci_addr; + uint32_t __iomem *sbbr_l; + uint32_t __iomem *sbbr_h; + + if (port->ip_hooks == &hooks_array[0]) { + sbbr_l = &port->ip_serial->sbbr01_l; + sbbr_h = &port->ip_serial->sbbr01_h; + } else { + sbbr_l = &port->ip_serial->sbbr23_l; + sbbr_h = &port->ip_serial->sbbr23_h; + } + + ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; + DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n", + __func__, ring_pci_addr)); + + writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h); + writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l); + } + + /* Set the receive timeout value to 10 msec */ + writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr); + + /* Set rx threshold, enable DMA */ + /* Set high water mark at 3/4 of full ring */ + port->ip_sscr = (ENTRIES_PER_RING * 3 / 4); + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + + /* Disable and clear all serial related interrupt bits */ + write_ireg(port->ip_ioc4_soft, hooks->intr_clear, + IOC4_W_IEC, IOC4_SIO_INTR_TYPE); + port->ip_ienb &= ~hooks->intr_clear; + writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw); + return 0; +} + +/** + * handle_dma_error_intr - service any pending DMA error interrupts for the + * given port - 2nd level called via sd_intr + * @arg: handler arg + * @other_ir: ioc4regs + */ +static void handle_dma_error_intr(void *arg, uint32_t other_ir) +{ + struct ioc4_port *port = (struct ioc4_port *)arg; + struct hooks *hooks = port->ip_hooks; + unsigned long flags; + + spin_lock_irqsave(&port->ip_lock, flags); + + /* ACK the interrupt */ + writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw); + + if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) { + printk(KERN_ERR + "PCI error address is 0x%llx, " + "master is serial port %c %s\n", + (((uint64_t)readl(&port->ip_mem->pci_err_addr_h) + << 32) + | readl(&port->ip_mem->pci_err_addr_l.raw)) + & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' + + ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) & + IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1), + (readl(&port->ip_mem->pci_err_addr_l.raw) + & IOC4_PCI_ERR_ADDR_MST_TYP_MSK) + ? "RX" : "TX"); + + if (readl(&port->ip_mem->pci_err_addr_l.raw) + & IOC4_PCI_ERR_ADDR_MUL_ERR) { + printk(KERN_ERR + "Multiple errors occurred\n"); + } + } + spin_unlock_irqrestore(&port->ip_lock, flags); + + /* Re-enable DMA error interrupts */ + write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES, + IOC4_OTHER_INTR_TYPE); +} + +/** + * intr_connect - interrupt connect function + * @soft: soft struct for this card + * @type: interrupt type + * @intrbits: bit pattern to set + * @intr: handler function + * @info: handler arg + */ +static void +intr_connect(struct ioc4_soft *soft, int type, + uint32_t intrbits, ioc4_intr_func_f * intr, void *info) +{ + int i; + struct ioc4_intr_info *intr_ptr; + + BUG_ON(!((type == IOC4_SIO_INTR_TYPE) + || (type == IOC4_OTHER_INTR_TYPE))); + + i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1; + BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0))); + + /* Save off the lower level interrupt handler */ + intr_ptr = &soft->is_intr_type[type].is_intr_info[i]; + intr_ptr->sd_bits = intrbits; + intr_ptr->sd_intr = intr; + intr_ptr->sd_info = info; +} + +/** + * ioc4_intr - Top level IOC4 interrupt handler. + * @irq: irq value + * @arg: handler arg + */ + +static irqreturn_t ioc4_intr(int irq, void *arg) +{ + struct ioc4_soft *soft; + uint32_t this_ir, this_mir; + int xx, num_intrs = 0; + int intr_type; + int handled = 0; + struct ioc4_intr_info *intr_info; + + soft = arg; + for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) { + num_intrs = (int)atomic_read( + &soft->is_intr_type[intr_type].is_num_intrs); + + this_mir = this_ir = pending_intrs(soft, intr_type); + + /* Farm out the interrupt to the various drivers depending on + * which interrupt bits are set. + */ + for (xx = 0; xx < num_intrs; xx++) { + intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx]; + if ((this_mir = this_ir & intr_info->sd_bits)) { + /* Disable owned interrupts, call handler */ + handled++; + write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC, + intr_type); + intr_info->sd_intr(intr_info->sd_info, this_mir); + this_ir &= ~this_mir; + } + } + } +#ifdef DEBUG_INTERRUPTS + { + struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; + unsigned long flag; + + spin_lock_irqsave(&soft->is_ir_lock, flag); + printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x " + "other_ir 0x%x other_ies 0x%x mask 0x%x\n", + __func__, __LINE__, + (void *)mem, readl(&mem->sio_ir.raw), + readl(&mem->sio_ies.raw), + readl(&mem->other_ir.raw), + readl(&mem->other_ies.raw), + IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR); + spin_unlock_irqrestore(&soft->is_ir_lock, flag); + } +#endif + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +/** + * ioc4_attach_local - Device initialization. + * Called at *_attach() time for each + * IOC4 with serial ports in the system. + * @idd: Master module data for this IOC4 + */ +static int inline ioc4_attach_local(struct ioc4_driver_data *idd) +{ + struct ioc4_port *port; + struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS]; + int port_number; + uint16_t ioc4_revid_min = 62; + uint16_t ioc4_revid; + struct pci_dev *pdev = idd->idd_pdev; + struct ioc4_control* control = idd->idd_serial_data; + struct ioc4_soft *soft = control->ic_soft; + void __iomem *ioc4_misc = idd->idd_misc_regs; + void __iomem *ioc4_serial = soft->is_ioc4_serial_addr; + + /* IOC4 firmware must be at least rev 62 */ + pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid); + + printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid); + if (ioc4_revid < ioc4_revid_min) { + printk(KERN_WARNING + "IOC4 serial not supported on firmware rev %d, " + "please upgrade to rev %d or higher\n", + ioc4_revid, ioc4_revid_min); + return -EPERM; + } + BUG_ON(ioc4_misc == NULL); + BUG_ON(ioc4_serial == NULL); + + /* Create port structures for each port */ + for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS; + port_number++) { + port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL); + if (!port) { + printk(KERN_WARNING + "IOC4 serial memory not available for port\n"); + return -ENOMEM; + } + spin_lock_init(&port->ip_lock); + + /* we need to remember the previous ones, to point back to + * them farther down - setting up the ring buffers. + */ + ports[port_number] = port; + + /* Allocate buffers and jumpstart the hardware. */ + control->ic_port[port_number].icp_port = port; + port->ip_ioc4_soft = soft; + port->ip_pdev = pdev; + port->ip_ienb = 0; + /* Use baud rate calculations based on detected PCI + * bus speed. Simply test whether the PCI clock is + * running closer to 66MHz or 33MHz. + */ + if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) { + port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66; + } else { + port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33; + } + port->ip_baud = 9600; + port->ip_control = control; + port->ip_mem = ioc4_misc; + port->ip_serial = ioc4_serial; + + /* point to the right hook */ + port->ip_hooks = &hooks_array[port_number]; + + /* Get direct hooks to the serial regs and uart regs + * for this port + */ + switch (port_number) { + case 0: + port->ip_serial_regs = &(port->ip_serial->port_0); + port->ip_uart_regs = &(port->ip_serial->uart_0); + break; + case 1: + port->ip_serial_regs = &(port->ip_serial->port_1); + port->ip_uart_regs = &(port->ip_serial->uart_1); + break; + case 2: + port->ip_serial_regs = &(port->ip_serial->port_2); + port->ip_uart_regs = &(port->ip_serial->uart_2); + break; + default: + case 3: + port->ip_serial_regs = &(port->ip_serial->port_3); + port->ip_uart_regs = &(port->ip_serial->uart_3); + break; + } + + /* ring buffers are 1 to a pair of ports */ + if (port_number && (port_number & 1)) { + /* odd use the evens buffer */ + port->ip_dma_ringbuf = + ports[port_number - 1]->ip_dma_ringbuf; + port->ip_cpu_ringbuf = + ports[port_number - 1]->ip_cpu_ringbuf; + port->ip_inring = RING(port, RX_1_OR_3); + port->ip_outring = RING(port, TX_1_OR_3); + + } else { + if (port->ip_dma_ringbuf == 0) { + port->ip_cpu_ringbuf = pci_alloc_consistent + (pdev, TOTAL_RING_BUF_SIZE, + &port->ip_dma_ringbuf); + + } + BUG_ON(!((((int64_t)port->ip_dma_ringbuf) & + (TOTAL_RING_BUF_SIZE - 1)) == 0)); + DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p " + "ip_dma_ringbuf 0x%p\n", + __func__, + (void *)port->ip_cpu_ringbuf, + (void *)port->ip_dma_ringbuf)); + port->ip_inring = RING(port, RX_0_OR_2); + port->ip_outring = RING(port, TX_0_OR_2); + } + DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p", + __func__, + port_number, (void *)port, (void *)control)); + DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n", + (void *)port->ip_serial_regs, + (void *)port->ip_uart_regs)); + + /* Initialize the hardware for IOC4 */ + port_init(port); + + DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p " + "outring 0x%p\n", + __func__, + port_number, (void *)port, + (void *)port->ip_inring, + (void *)port->ip_outring)); + + /* Attach interrupt handlers */ + intr_connect(soft, IOC4_SIO_INTR_TYPE, + GET_SIO_IR(port_number), + handle_intr, port); + + intr_connect(soft, IOC4_OTHER_INTR_TYPE, + GET_OTHER_IR(port_number), + handle_dma_error_intr, port); + } + return 0; +} + +/** + * enable_intrs - enable interrupts + * @port: port to enable + * @mask: mask to use + */ +static void enable_intrs(struct ioc4_port *port, uint32_t mask) +{ + struct hooks *hooks = port->ip_hooks; + + if ((port->ip_ienb & mask) != mask) { + write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES, + IOC4_SIO_INTR_TYPE); + port->ip_ienb |= mask; + } + + if (port->ip_ienb) + write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, + IOC4_W_IES, IOC4_OTHER_INTR_TYPE); +} + +/** + * local_open - local open a port + * @port: port to open + */ +static inline int local_open(struct ioc4_port *port) +{ + int spiniter = 0; + + port->ip_flags = PORT_ACTIVE; + + /* Pause the DMA interface if necessary */ + if (port->ip_sscr & IOC4_SSCR_DMA_EN) { + writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE, + &port->ip_serial_regs->sscr); + while((readl(&port->ip_serial_regs-> sscr) + & IOC4_SSCR_PAUSE_STATE) == 0) { + spiniter++; + if (spiniter > MAXITER) { + port->ip_flags = PORT_INACTIVE; + return -1; + } + } + } + + /* Reset the input fifo. If the uart received chars while the port + * was closed and DMA is not enabled, the uart may have a bunch of + * chars hanging around in its rx fifo which will not be discarded + * by rclr in the upper layer. We must get rid of them here. + */ + writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR, + &port->ip_uart_regs->i4u_fcr); + + writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr); + /* UART_LCR_STOP == 1 stop */ + + /* Re-enable DMA, set default threshold to intr whenever there is + * data available. + */ + port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD; + port->ip_sscr |= 1; /* default threshold */ + + /* Plug in the new sscr. This implicitly clears the DMA_PAUSE + * flag if it was set above + */ + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + port->ip_tx_lowat = 1; + return 0; +} + +/** + * set_rx_timeout - Set rx timeout and threshold values. + * @port: port to use + * @timeout: timeout value in ticks + */ +static inline int set_rx_timeout(struct ioc4_port *port, int timeout) +{ + int threshold; + + port->ip_rx_timeout = timeout; + + /* Timeout is in ticks. Let's figure out how many chars we + * can receive at the current baud rate in that interval + * and set the rx threshold to that amount. There are 4 chars + * per ring entry, so we'll divide the number of chars that will + * arrive in timeout by 4. + * So .... timeout * baud / 10 / HZ / 4, with HZ = 100. + */ + threshold = timeout * port->ip_baud / 4000; + if (threshold == 0) + threshold = 1; /* otherwise we'll intr all the time! */ + + if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD) + return 1; + + port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD; + port->ip_sscr |= threshold; + + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + + /* Now set the rx timeout to the given value + * again timeout * IOC4_SRTR_HZ / HZ + */ + timeout = timeout * IOC4_SRTR_HZ / 100; + if (timeout > IOC4_SRTR_CNT) + timeout = IOC4_SRTR_CNT; + + writel(timeout, &port->ip_serial_regs->srtr); + return 0; +} + +/** + * config_port - config the hardware + * @port: port to config + * @baud: baud rate for the port + * @byte_size: data size + * @stop_bits: number of stop bits + * @parenb: parity enable ? + * @parodd: odd parity ? + */ +static inline int +config_port(struct ioc4_port *port, + int baud, int byte_size, int stop_bits, int parenb, int parodd) +{ + char lcr, sizebits; + int spiniter = 0; + + DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n", + __func__, baud, byte_size, stop_bits, parenb, parodd)); + + if (set_baud(port, baud)) + return 1; + + switch (byte_size) { + case 5: + sizebits = UART_LCR_WLEN5; + break; + case 6: + sizebits = UART_LCR_WLEN6; + break; + case 7: + sizebits = UART_LCR_WLEN7; + break; + case 8: + sizebits = UART_LCR_WLEN8; + break; + default: + return 1; + } + + /* Pause the DMA interface if necessary */ + if (port->ip_sscr & IOC4_SSCR_DMA_EN) { + writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE, + &port->ip_serial_regs->sscr); + while((readl(&port->ip_serial_regs->sscr) + & IOC4_SSCR_PAUSE_STATE) == 0) { + spiniter++; + if (spiniter > MAXITER) + return -1; + } + } + + /* Clear relevant fields in lcr */ + lcr = readb(&port->ip_uart_regs->i4u_lcr); + lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR | + UART_LCR_PARITY | LCR_MASK_STOP_BITS); + + /* Set byte size in lcr */ + lcr |= sizebits; + + /* Set parity */ + if (parenb) { + lcr |= UART_LCR_PARITY; + if (!parodd) + lcr |= UART_LCR_EPAR; + } + + /* Set stop bits */ + if (stop_bits) + lcr |= UART_LCR_STOP /* 2 stop bits */ ; + + writeb(lcr, &port->ip_uart_regs->i4u_lcr); + + /* Re-enable the DMA interface if necessary */ + if (port->ip_sscr & IOC4_SSCR_DMA_EN) { + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + port->ip_baud = baud; + + /* When we get within this number of ring entries of filling the + * entire ring on tx, place an EXPLICIT intr to generate a lowat + * notification when output has drained. + */ + port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4; + if (port->ip_tx_lowat == 0) + port->ip_tx_lowat = 1; + + set_rx_timeout(port, 2); + + return 0; +} + +/** + * do_write - Write bytes to the port. Returns the number of bytes + * actually written. Called from transmit_chars + * @port: port to use + * @buf: the stuff to write + * @len: how many bytes in 'buf' + */ +static inline int do_write(struct ioc4_port *port, char *buf, int len) +{ + int prod_ptr, cons_ptr, total = 0; + struct ring *outring; + struct ring_entry *entry; + struct hooks *hooks = port->ip_hooks; + + BUG_ON(!(len >= 0)); + + prod_ptr = port->ip_tx_prod; + cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK; + outring = port->ip_outring; + + /* Maintain a 1-entry red-zone. The ring buffer is full when + * (cons - prod) % ring_size is 1. Rather than do this subtraction + * in the body of the loop, I'll do it now. + */ + cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK; + + /* Stuff the bytes into the output */ + while ((prod_ptr != cons_ptr) && (len > 0)) { + int xx; + + /* Get 4 bytes (one ring entry) at a time */ + entry = (struct ring_entry *)((caddr_t) outring + prod_ptr); + + /* Invalidate all entries */ + entry->ring_allsc = 0; + + /* Copy in some bytes */ + for (xx = 0; (xx < 4) && (len > 0); xx++) { + entry->ring_data[xx] = *buf++; + entry->ring_sc[xx] = IOC4_TXCB_VALID; + len--; + total++; + } + + /* If we are within some small threshold of filling up the + * entire ring buffer, we must place an EXPLICIT intr here + * to generate a lowat interrupt in case we subsequently + * really do fill up the ring and the caller goes to sleep. + * No need to place more than one though. + */ + if (!(port->ip_flags & LOWAT_WRITTEN) && + ((cons_ptr - prod_ptr) & PROD_CONS_MASK) + <= port->ip_tx_lowat + * (int)sizeof(struct ring_entry)) { + port->ip_flags |= LOWAT_WRITTEN; + entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE; + } + + /* Go on to next entry */ + prod_ptr += sizeof(struct ring_entry); + prod_ptr &= PROD_CONS_MASK; + } + + /* If we sent something, start DMA if necessary */ + if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) { + port->ip_sscr |= IOC4_SSCR_DMA_EN; + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + + /* Store the new producer pointer. If tx is disabled, we stuff the + * data into the ring buffer, but we don't actually start tx. + */ + if (!uart_tx_stopped(port->ip_port)) { + writel(prod_ptr, &port->ip_serial_regs->stpir); + + /* If we are now transmitting, enable tx_mt interrupt so we + * can disable DMA if necessary when the tx finishes. + */ + if (total > 0) + enable_intrs(port, hooks->intr_tx_mt); + } + port->ip_tx_prod = prod_ptr; + return total; +} + +/** + * disable_intrs - disable interrupts + * @port: port to enable + * @mask: mask to use + */ +static void disable_intrs(struct ioc4_port *port, uint32_t mask) +{ + struct hooks *hooks = port->ip_hooks; + + if (port->ip_ienb & mask) { + write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC, + IOC4_SIO_INTR_TYPE); + port->ip_ienb &= ~mask; + } + + if (!port->ip_ienb) + write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, + IOC4_W_IEC, IOC4_OTHER_INTR_TYPE); +} + +/** + * set_notification - Modify event notification + * @port: port to use + * @mask: events mask + * @set_on: set ? + */ +static int set_notification(struct ioc4_port *port, int mask, int set_on) +{ + struct hooks *hooks = port->ip_hooks; + uint32_t intrbits, sscrbits; + + BUG_ON(!mask); + + intrbits = sscrbits = 0; + + if (mask & N_DATA_READY) + intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high); + if (mask & N_OUTPUT_LOWAT) + intrbits |= hooks->intr_tx_explicit; + if (mask & N_DDCD) { + intrbits |= hooks->intr_delta_dcd; + sscrbits |= IOC4_SSCR_RX_RING_DCD; + } + if (mask & N_DCTS) + intrbits |= hooks->intr_delta_cts; + + if (set_on) { + enable_intrs(port, intrbits); + port->ip_notify |= mask; + port->ip_sscr |= sscrbits; + } else { + disable_intrs(port, intrbits); + port->ip_notify &= ~mask; + port->ip_sscr &= ~sscrbits; + } + + /* We require DMA if either DATA_READY or DDCD notification is + * currently requested. If neither of these is requested and + * there is currently no tx in progress, DMA may be disabled. + */ + if (port->ip_notify & (N_DATA_READY | N_DDCD)) + port->ip_sscr |= IOC4_SSCR_DMA_EN; + else if (!(port->ip_ienb & hooks->intr_tx_mt)) + port->ip_sscr &= ~IOC4_SSCR_DMA_EN; + + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + return 0; +} + +/** + * set_mcr - set the master control reg + * @the_port: port to use + * @mask1: mcr mask + * @mask2: shadow mask + */ +static inline int set_mcr(struct uart_port *the_port, + int mask1, int mask2) +{ + struct ioc4_port *port = get_ioc4_port(the_port, 0); + uint32_t shadow; + int spiniter = 0; + char mcr; + + if (!port) + return -1; + + /* Pause the DMA interface if necessary */ + if (port->ip_sscr & IOC4_SSCR_DMA_EN) { + writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE, + &port->ip_serial_regs->sscr); + while ((readl(&port->ip_serial_regs->sscr) + & IOC4_SSCR_PAUSE_STATE) == 0) { + spiniter++; + if (spiniter > MAXITER) + return -1; + } + } + shadow = readl(&port->ip_serial_regs->shadow); + mcr = (shadow & 0xff000000) >> 24; + + /* Set new value */ + mcr |= mask1; + shadow |= mask2; + + writeb(mcr, &port->ip_uart_regs->i4u_mcr); + writel(shadow, &port->ip_serial_regs->shadow); + + /* Re-enable the DMA interface if necessary */ + if (port->ip_sscr & IOC4_SSCR_DMA_EN) { + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + return 0; +} + +/** + * ioc4_set_proto - set the protocol for the port + * @port: port to use + * @proto: protocol to use + */ +static int ioc4_set_proto(struct ioc4_port *port, int proto) +{ + struct hooks *hooks = port->ip_hooks; + + switch (proto) { + case PROTO_RS232: + /* Clear the appropriate GIO pin */ + writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); + break; + + case PROTO_RS422: + /* Set the appropriate GIO pin */ + writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw)); + break; + + default: + return 1; + } + return 0; +} + +/** + * transmit_chars - upper level write, called with ip_lock + * @the_port: port to write + */ +static void transmit_chars(struct uart_port *the_port) +{ + int xmit_count, tail, head; + int result; + char *start; + struct tty_struct *tty; + struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct uart_state *state; + + if (!the_port) + return; + if (!port) + return; + + state = the_port->state; + tty = state->port.tty; + + if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { + /* Nothing to do or hw stopped */ + set_notification(port, N_ALL_OUTPUT, 0); + return; + } + + head = state->xmit.head; + tail = state->xmit.tail; + start = (char *)&state->xmit.buf[tail]; + + /* write out all the data or until the end of the buffer */ + xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail); + if (xmit_count > 0) { + result = do_write(port, start, xmit_count); + if (result > 0) { + /* booking */ + xmit_count -= result; + the_port->icount.tx += result; + /* advance the pointers */ + tail += result; + tail &= UART_XMIT_SIZE - 1; + state->xmit.tail = tail; + start = (char *)&state->xmit.buf[tail]; + } + } + if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS) + uart_write_wakeup(the_port); + + if (uart_circ_empty(&state->xmit)) { + set_notification(port, N_OUTPUT_LOWAT, 0); + } else { + set_notification(port, N_OUTPUT_LOWAT, 1); + } +} + +/** + * ioc4_change_speed - change the speed of the port + * @the_port: port to change + * @new_termios: new termios settings + * @old_termios: old termios settings + */ +static void +ioc4_change_speed(struct uart_port *the_port, + struct ktermios *new_termios, struct ktermios *old_termios) +{ + struct ioc4_port *port = get_ioc4_port(the_port, 0); + int baud, bits; + unsigned cflag, iflag; + int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; + struct uart_state *state = the_port->state; + + cflag = new_termios->c_cflag; + iflag = new_termios->c_iflag; + + switch (cflag & CSIZE) { + case CS5: + new_data = 5; + bits = 7; + break; + case CS6: + new_data = 6; + bits = 8; + break; + case CS7: + new_data = 7; + bits = 9; + break; + case CS8: + new_data = 8; + bits = 10; + break; + default: + /* cuz we always need a default ... */ + new_data = 5; + bits = 7; + break; + } + if (cflag & CSTOPB) { + bits++; + new_stop = 1; + } + if (cflag & PARENB) { + bits++; + new_parity_enable = 1; + if (cflag & PARODD) + new_parity = 1; + } + baud = uart_get_baud_rate(the_port, new_termios, old_termios, + MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); + DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud)); + + /* default is 9600 */ + if (!baud) + baud = 9600; + + if (!the_port->fifosize) + the_port->fifosize = IOC4_FIFO_CHARS; + the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10)); + the_port->timeout += HZ / 50; /* Add .02 seconds of slop */ + + the_port->ignore_status_mask = N_ALL_INPUT; + + state->port.tty->low_latency = 1; + + if (iflag & IGNPAR) + the_port->ignore_status_mask &= ~(N_PARITY_ERROR + | N_FRAMING_ERROR); + if (iflag & IGNBRK) { + the_port->ignore_status_mask &= ~N_BREAK; + if (iflag & IGNPAR) + the_port->ignore_status_mask &= ~N_OVERRUN_ERROR; + } + if (!(cflag & CREAD)) { + /* ignore everything */ + the_port->ignore_status_mask &= ~N_DATA_READY; + } + + if (cflag & CRTSCTS) { + port->ip_sscr |= IOC4_SSCR_HFC_EN; + } + else { + port->ip_sscr &= ~IOC4_SSCR_HFC_EN; + } + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + + /* Set the configuration and proper notification call */ + DPRINT_CONFIG(("%s : port 0x%p cflag 0%o " + "config_port(baud %d data %d stop %d p enable %d parity %d)," + " notification 0x%x\n", + __func__, (void *)port, cflag, baud, new_data, new_stop, + new_parity_enable, new_parity, the_port->ignore_status_mask)); + + if ((config_port(port, baud, /* baud */ + new_data, /* byte size */ + new_stop, /* stop bits */ + new_parity_enable, /* set parity */ + new_parity)) >= 0) { /* parity 1==odd */ + set_notification(port, the_port->ignore_status_mask, 1); + } +} + +/** + * ic4_startup_local - Start up the serial port - returns >= 0 if no errors + * @the_port: Port to operate on + */ +static inline int ic4_startup_local(struct uart_port *the_port) +{ + struct ioc4_port *port; + struct uart_state *state; + + if (!the_port) + return -1; + + port = get_ioc4_port(the_port, 0); + if (!port) + return -1; + + state = the_port->state; + + local_open(port); + + /* set the protocol - mapbase has the port type */ + ioc4_set_proto(port, the_port->mapbase); + + /* set the speed of the serial port */ + ioc4_change_speed(the_port, state->port.tty->termios, + (struct ktermios *)0); + + return 0; +} + +/* + * ioc4_cb_output_lowat - called when the output low water mark is hit + * @the_port: port to output + */ +static void ioc4_cb_output_lowat(struct uart_port *the_port) +{ + unsigned long pflags; + + /* ip_lock is set on the call here */ + if (the_port) { + spin_lock_irqsave(&the_port->lock, pflags); + transmit_chars(the_port); + spin_unlock_irqrestore(&the_port->lock, pflags); + } +} + +/** + * handle_intr - service any interrupts for the given port - 2nd level + * called via sd_intr + * @arg: handler arg + * @sio_ir: ioc4regs + */ +static void handle_intr(void *arg, uint32_t sio_ir) +{ + struct ioc4_port *port = (struct ioc4_port *)arg; + struct hooks *hooks = port->ip_hooks; + unsigned int rx_high_rd_aborted = 0; + unsigned long flags; + struct uart_port *the_port; + int loop_counter; + + /* Possible race condition here: The tx_mt interrupt bit may be + * cleared without the intervention of the interrupt handler, + * e.g. by a write. If the top level interrupt handler reads a + * tx_mt, then some other processor does a write, starting up + * output, then we come in here, see the tx_mt and stop DMA, the + * output started by the other processor will hang. Thus we can + * only rely on tx_mt being legitimate if it is read while the + * port lock is held. Therefore this bit must be ignored in the + * passed in interrupt mask which was read by the top level + * interrupt handler since the port lock was not held at the time + * it was read. We can only rely on this bit being accurate if it + * is read while the port lock is held. So we'll clear it for now, + * and reload it later once we have the port lock. + */ + sio_ir &= ~(hooks->intr_tx_mt); + + spin_lock_irqsave(&port->ip_lock, flags); + + loop_counter = MAXITER; /* to avoid hangs */ + + do { + uint32_t shadow; + + if ( loop_counter-- <= 0 ) { + printk(KERN_WARNING "IOC4 serial: " + "possible hang condition/" + "port stuck on interrupt.\n"); + break; + } + + /* Handle a DCD change */ + if (sio_ir & hooks->intr_delta_dcd) { + /* ACK the interrupt */ + writel(hooks->intr_delta_dcd, + &port->ip_mem->sio_ir.raw); + + shadow = readl(&port->ip_serial_regs->shadow); + + if ((port->ip_notify & N_DDCD) + && (shadow & IOC4_SHADOW_DCD) + && (port->ip_port)) { + the_port = port->ip_port; + the_port->icount.dcd = 1; + wake_up_interruptible + (&the_port->state->port.delta_msr_wait); + } else if ((port->ip_notify & N_DDCD) + && !(shadow & IOC4_SHADOW_DCD)) { + /* Flag delta DCD/no DCD */ + port->ip_flags |= DCD_ON; + } + } + + /* Handle a CTS change */ + if (sio_ir & hooks->intr_delta_cts) { + /* ACK the interrupt */ + writel(hooks->intr_delta_cts, + &port->ip_mem->sio_ir.raw); + + shadow = readl(&port->ip_serial_regs->shadow); + + if ((port->ip_notify & N_DCTS) + && (port->ip_port)) { + the_port = port->ip_port; + the_port->icount.cts = + (shadow & IOC4_SHADOW_CTS) ? 1 : 0; + wake_up_interruptible + (&the_port->state->port.delta_msr_wait); + } + } + + /* rx timeout interrupt. Must be some data available. Put this + * before the check for rx_high since servicing this condition + * may cause that condition to clear. + */ + if (sio_ir & hooks->intr_rx_timer) { + /* ACK the interrupt */ + writel(hooks->intr_rx_timer, + &port->ip_mem->sio_ir.raw); + + if ((port->ip_notify & N_DATA_READY) + && (port->ip_port)) { + /* ip_lock is set on call here */ + receive_chars(port->ip_port); + } + } + + /* rx high interrupt. Must be after rx_timer. */ + else if (sio_ir & hooks->intr_rx_high) { + /* Data available, notify upper layer */ + if ((port->ip_notify & N_DATA_READY) + && port->ip_port) { + /* ip_lock is set on call here */ + receive_chars(port->ip_port); + } + + /* We can't ACK this interrupt. If receive_chars didn't + * cause the condition to clear, we'll have to disable + * the interrupt until the data is drained. + * If the read was aborted, don't disable the interrupt + * as this may cause us to hang indefinitely. An + * aborted read generally means that this interrupt + * hasn't been delivered to the cpu yet anyway, even + * though we see it as asserted when we read the sio_ir. + */ + if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) { + if ((port->ip_flags & READ_ABORTED) == 0) { + port->ip_ienb &= ~hooks->intr_rx_high; + port->ip_flags |= INPUT_HIGH; + } else { + rx_high_rd_aborted++; + } + } + } + + /* We got a low water interrupt: notify upper layer to + * send more data. Must come before tx_mt since servicing + * this condition may cause that condition to clear. + */ + if (sio_ir & hooks->intr_tx_explicit) { + port->ip_flags &= ~LOWAT_WRITTEN; + + /* ACK the interrupt */ + writel(hooks->intr_tx_explicit, + &port->ip_mem->sio_ir.raw); + + if (port->ip_notify & N_OUTPUT_LOWAT) + ioc4_cb_output_lowat(port->ip_port); + } + + /* Handle tx_mt. Must come after tx_explicit. */ + else if (sio_ir & hooks->intr_tx_mt) { + /* If we are expecting a lowat notification + * and we get to this point it probably means that for + * some reason the tx_explicit didn't work as expected + * (that can legitimately happen if the output buffer is + * filled up in just the right way). + * So send the notification now. + */ + if (port->ip_notify & N_OUTPUT_LOWAT) { + ioc4_cb_output_lowat(port->ip_port); + + /* We need to reload the sio_ir since the lowat + * call may have caused another write to occur, + * clearing the tx_mt condition. + */ + sio_ir = PENDING(port); + } + + /* If the tx_mt condition still persists even after the + * lowat call, we've got some work to do. + */ + if (sio_ir & hooks->intr_tx_mt) { + + /* If we are not currently expecting DMA input, + * and the transmitter has just gone idle, + * there is no longer any reason for DMA, so + * disable it. + */ + if (!(port->ip_notify + & (N_DATA_READY | N_DDCD))) { + BUG_ON(!(port->ip_sscr + & IOC4_SSCR_DMA_EN)); + port->ip_sscr &= ~IOC4_SSCR_DMA_EN; + writel(port->ip_sscr, + &port->ip_serial_regs->sscr); + } + + /* Prevent infinite tx_mt interrupt */ + port->ip_ienb &= ~hooks->intr_tx_mt; + } + } + sio_ir = PENDING(port); + + /* if the read was aborted and only hooks->intr_rx_high, + * clear hooks->intr_rx_high, so we do not loop forever. + */ + + if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) { + sio_ir &= ~hooks->intr_rx_high; + } + } while (sio_ir & hooks->intr_all); + + spin_unlock_irqrestore(&port->ip_lock, flags); + + /* Re-enable interrupts before returning from interrupt handler. + * Getting interrupted here is okay. It'll just v() our semaphore, and + * we'll come through the loop again. + */ + + write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES, + IOC4_SIO_INTR_TYPE); +} + +/* + * ioc4_cb_post_ncs - called for some basic errors + * @port: port to use + * @ncs: event + */ +static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs) +{ + struct uart_icount *icount; + + icount = &the_port->icount; + + if (ncs & NCS_BREAK) + icount->brk++; + if (ncs & NCS_FRAMING) + icount->frame++; + if (ncs & NCS_OVERRUN) + icount->overrun++; + if (ncs & NCS_PARITY) + icount->parity++; +} + +/** + * do_read - Read in bytes from the port. Return the number of bytes + * actually read. + * @the_port: port to use + * @buf: place to put the stuff we read + * @len: how big 'buf' is + */ + +static inline int do_read(struct uart_port *the_port, unsigned char *buf, + int len) +{ + int prod_ptr, cons_ptr, total; + struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ring *inring; + struct ring_entry *entry; + struct hooks *hooks = port->ip_hooks; + int byte_num; + char *sc; + int loop_counter; + + BUG_ON(!(len >= 0)); + BUG_ON(!port); + + /* There is a nasty timing issue in the IOC4. When the rx_timer + * expires or the rx_high condition arises, we take an interrupt. + * At some point while servicing the interrupt, we read bytes from + * the ring buffer and re-arm the rx_timer. However the rx_timer is + * not started until the first byte is received *after* it is armed, + * and any bytes pending in the rx construction buffers are not drained + * to memory until either there are 4 bytes available or the rx_timer + * expires. This leads to a potential situation where data is left + * in the construction buffers forever - 1 to 3 bytes were received + * after the interrupt was generated but before the rx_timer was + * re-armed. At that point as long as no subsequent bytes are received + * the timer will never be started and the bytes will remain in the + * construction buffer forever. The solution is to execute a DRAIN + * command after rearming the timer. This way any bytes received before + * the DRAIN will be drained to memory, and any bytes received after + * the DRAIN will start the TIMER and be drained when it expires. + * Luckily, this only needs to be done when the DMA buffer is empty + * since there is no requirement that this function return all + * available data as long as it returns some. + */ + /* Re-arm the timer */ + writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir); + + prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK; + cons_ptr = port->ip_rx_cons; + + if (prod_ptr == cons_ptr) { + int reset_dma = 0; + + /* Input buffer appears empty, do a flush. */ + + /* DMA must be enabled for this to work. */ + if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) { + port->ip_sscr |= IOC4_SSCR_DMA_EN; + reset_dma = 1; + } + + /* Potential race condition: we must reload the srpir after + * issuing the drain command, otherwise we could think the rx + * buffer is empty, then take a very long interrupt, and when + * we come back it's full and we wait forever for the drain to + * complete. + */ + writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN, + &port->ip_serial_regs->sscr); + prod_ptr = readl(&port->ip_serial_regs->srpir) + & PROD_CONS_MASK; + + /* We must not wait for the DRAIN to complete unless there are + * at least 8 bytes (2 ring entries) available to receive the + * data otherwise the DRAIN will never complete and we'll + * deadlock here. + * In fact, to make things easier, I'll just ignore the flush if + * there is any data at all now available. + */ + if (prod_ptr == cons_ptr) { + loop_counter = 0; + while (readl(&port->ip_serial_regs->sscr) & + IOC4_SSCR_RX_DRAIN) { + loop_counter++; + if (loop_counter > MAXITER) + return -1; + } + + /* SIGH. We have to reload the prod_ptr *again* since + * the drain may have caused it to change + */ + prod_ptr = readl(&port->ip_serial_regs->srpir) + & PROD_CONS_MASK; + } + if (reset_dma) { + port->ip_sscr &= ~IOC4_SSCR_DMA_EN; + writel(port->ip_sscr, &port->ip_serial_regs->sscr); + } + } + inring = port->ip_inring; + port->ip_flags &= ~READ_ABORTED; + + total = 0; + loop_counter = 0xfffff; /* to avoid hangs */ + + /* Grab bytes from the hardware */ + while ((prod_ptr != cons_ptr) && (len > 0)) { + entry = (struct ring_entry *)((caddr_t)inring + cons_ptr); + + if ( loop_counter-- <= 0 ) { + printk(KERN_WARNING "IOC4 serial: " + "possible hang condition/" + "port stuck on read.\n"); + break; + } + + /* According to the producer pointer, this ring entry + * must contain some data. But if the PIO happened faster + * than the DMA, the data may not be available yet, so let's + * wait until it arrives. + */ + if ((entry->ring_allsc & RING_ANY_VALID) == 0) { + /* Indicate the read is aborted so we don't disable + * the interrupt thinking that the consumer is + * congested. + */ + port->ip_flags |= READ_ABORTED; + len = 0; + break; + } + + /* Load the bytes/status out of the ring entry */ + for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) { + sc = &(entry->ring_sc[byte_num]); + + /* Check for change in modem state or overrun */ + if ((*sc & IOC4_RXSB_MODEM_VALID) + && (port->ip_notify & N_DDCD)) { + /* Notify upper layer if DCD dropped */ + + if ((port->ip_flags & DCD_ON) + && !(*sc & IOC4_RXSB_DCD)) { + + /* If we have already copied some data, + * return it. We'll pick up the carrier + * drop on the next pass. That way we + * don't throw away the data that has + * already been copied back to + * the caller's buffer. + */ + if (total > 0) { + len = 0; + break; + } + port->ip_flags &= ~DCD_ON; + + /* Turn off this notification so the + * carrier drop protocol won't see it + * again when it does a read. + */ + *sc &= ~IOC4_RXSB_MODEM_VALID; + + /* To keep things consistent, we need + * to update the consumer pointer so + * the next reader won't come in and + * try to read the same ring entries + * again. This must be done here before + * the dcd change. + */ + + if ((entry->ring_allsc & RING_ANY_VALID) + == 0) { + cons_ptr += (int)sizeof + (struct ring_entry); + cons_ptr &= PROD_CONS_MASK; + } + writel(cons_ptr, + &port->ip_serial_regs->srcir); + port->ip_rx_cons = cons_ptr; + + /* Notify upper layer of carrier drop */ + if ((port->ip_notify & N_DDCD) + && port->ip_port) { + the_port->icount.dcd = 0; + wake_up_interruptible + (&the_port->state-> + port.delta_msr_wait); + } + + /* If we had any data to return, we + * would have returned it above. + */ + return 0; + } + } + if (*sc & IOC4_RXSB_MODEM_VALID) { + /* Notify that an input overrun occurred */ + if ((*sc & IOC4_RXSB_OVERRUN) + && (port->ip_notify & N_OVERRUN_ERROR)) { + ioc4_cb_post_ncs(the_port, NCS_OVERRUN); + } + /* Don't look at this byte again */ + *sc &= ~IOC4_RXSB_MODEM_VALID; + } + + /* Check for valid data or RX errors */ + if ((*sc & IOC4_RXSB_DATA_VALID) && + ((*sc & (IOC4_RXSB_PAR_ERR + | IOC4_RXSB_FRAME_ERR + | IOC4_RXSB_BREAK)) + && (port->ip_notify & (N_PARITY_ERROR + | N_FRAMING_ERROR + | N_BREAK)))) { + /* There is an error condition on the next byte. + * If we have already transferred some bytes, + * we'll stop here. Otherwise if this is the + * first byte to be read, we'll just transfer + * it alone after notifying the + * upper layer of its status. + */ + if (total > 0) { + len = 0; + break; + } else { + if ((*sc & IOC4_RXSB_PAR_ERR) && + (port->ip_notify & N_PARITY_ERROR)) { + ioc4_cb_post_ncs(the_port, + NCS_PARITY); + } + if ((*sc & IOC4_RXSB_FRAME_ERR) && + (port->ip_notify & N_FRAMING_ERROR)){ + ioc4_cb_post_ncs(the_port, + NCS_FRAMING); + } + if ((*sc & IOC4_RXSB_BREAK) + && (port->ip_notify & N_BREAK)) { + ioc4_cb_post_ncs + (the_port, + NCS_BREAK); + } + len = 1; + } + } + if (*sc & IOC4_RXSB_DATA_VALID) { + *sc &= ~IOC4_RXSB_DATA_VALID; + *buf = entry->ring_data[byte_num]; + buf++; + len--; + total++; + } + } + + /* If we used up this entry entirely, go on to the next one, + * otherwise we must have run out of buffer space, so + * leave the consumer pointer here for the next read in case + * there are still unread bytes in this entry. + */ + if ((entry->ring_allsc & RING_ANY_VALID) == 0) { + cons_ptr += (int)sizeof(struct ring_entry); + cons_ptr &= PROD_CONS_MASK; + } + } + + /* Update consumer pointer and re-arm rx timer interrupt */ + writel(cons_ptr, &port->ip_serial_regs->srcir); + port->ip_rx_cons = cons_ptr; + + /* If we have now dipped below the rx high water mark and we have + * rx_high interrupt turned off, we can now turn it back on again. + */ + if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr) + & PROD_CONS_MASK) < ((port->ip_sscr & + IOC4_SSCR_RX_THRESHOLD) + << IOC4_PROD_CONS_PTR_OFF))) { + port->ip_flags &= ~INPUT_HIGH; + enable_intrs(port, hooks->intr_rx_high); + } + return total; +} + +/** + * receive_chars - upper level read. Called with ip_lock. + * @the_port: port to read from + */ +static void receive_chars(struct uart_port *the_port) +{ + struct tty_struct *tty; + unsigned char ch[IOC4_MAX_CHARS]; + int read_count, request_count = IOC4_MAX_CHARS; + struct uart_icount *icount; + struct uart_state *state = the_port->state; + unsigned long pflags; + + /* Make sure all the pointers are "good" ones */ + if (!state) + return; + if (!state->port.tty) + return; + + spin_lock_irqsave(&the_port->lock, pflags); + tty = state->port.tty; + + request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS); + + if (request_count > 0) { + icount = &the_port->icount; + read_count = do_read(the_port, ch, request_count); + if (read_count > 0) { + tty_insert_flip_string(tty, ch, read_count); + icount->rx += read_count; + } + } + + spin_unlock_irqrestore(&the_port->lock, pflags); + + tty_flip_buffer_push(tty); +} + +/** + * ic4_type - What type of console are we? + * @port: Port to operate with (we ignore since we only have one port) + * + */ +static const char *ic4_type(struct uart_port *the_port) +{ + if (the_port->mapbase == PROTO_RS232) + return "SGI IOC4 Serial [rs232]"; + else + return "SGI IOC4 Serial [rs422]"; +} + +/** + * ic4_tx_empty - Is the transmitter empty? + * @port: Port to operate on + * + */ +static unsigned int ic4_tx_empty(struct uart_port *the_port) +{ + struct ioc4_port *port = get_ioc4_port(the_port, 0); + unsigned int ret = 0; + + if (port_is_active(port, the_port)) { + if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT) + ret = TIOCSER_TEMT; + } + return ret; +} + +/** + * ic4_stop_tx - stop the transmitter + * @port: Port to operate on + * + */ +static void ic4_stop_tx(struct uart_port *the_port) +{ + struct ioc4_port *port = get_ioc4_port(the_port, 0); + + if (port_is_active(port, the_port)) + set_notification(port, N_OUTPUT_LOWAT, 0); +} + +/** + * null_void_function - + * @port: Port to operate on + * + */ +static void null_void_function(struct uart_port *the_port) +{ +} + +/** + * ic4_shutdown - shut down the port - free irq and disable + * @port: Port to shut down + * + */ +static void ic4_shutdown(struct uart_port *the_port) +{ + unsigned long port_flags; + struct ioc4_port *port; + struct uart_state *state; + + port = get_ioc4_port(the_port, 0); + if (!port) + return; + + state = the_port->state; + port->ip_port = NULL; + + wake_up_interruptible(&state->port.delta_msr_wait); + + if (state->port.tty) + set_bit(TTY_IO_ERROR, &state->port.tty->flags); + + spin_lock_irqsave(&the_port->lock, port_flags); + set_notification(port, N_ALL, 0); + port->ip_flags = PORT_INACTIVE; + spin_unlock_irqrestore(&the_port->lock, port_flags); +} + +/** + * ic4_set_mctrl - set control lines (dtr, rts, etc) + * @port: Port to operate on + * @mctrl: Lines to set/unset + * + */ +static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl) +{ + unsigned char mcr = 0; + struct ioc4_port *port; + + port = get_ioc4_port(the_port, 0); + if (!port_is_active(port, the_port)) + return; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + set_mcr(the_port, mcr, IOC4_SHADOW_DTR); +} + +/** + * ic4_get_mctrl - get control line info + * @port: port to operate on + * + */ +static unsigned int ic4_get_mctrl(struct uart_port *the_port) +{ + struct ioc4_port *port = get_ioc4_port(the_port, 0); + uint32_t shadow; + unsigned int ret = 0; + + if (!port_is_active(port, the_port)) + return 0; + + shadow = readl(&port->ip_serial_regs->shadow); + if (shadow & IOC4_SHADOW_DCD) + ret |= TIOCM_CAR; + if (shadow & IOC4_SHADOW_DR) + ret |= TIOCM_DSR; + if (shadow & IOC4_SHADOW_CTS) + ret |= TIOCM_CTS; + return ret; +} + +/** + * ic4_start_tx - Start transmitter, flush any output + * @port: Port to operate on + * + */ +static void ic4_start_tx(struct uart_port *the_port) +{ + struct ioc4_port *port = get_ioc4_port(the_port, 0); + + if (port_is_active(port, the_port)) { + set_notification(port, N_OUTPUT_LOWAT, 1); + enable_intrs(port, port->ip_hooks->intr_tx_mt); + } +} + +/** + * ic4_break_ctl - handle breaks + * @port: Port to operate on + * @break_state: Break state + * + */ +static void ic4_break_ctl(struct uart_port *the_port, int break_state) +{ +} + +/** + * ic4_startup - Start up the serial port + * @port: Port to operate on + * + */ +static int ic4_startup(struct uart_port *the_port) +{ + int retval; + struct ioc4_port *port; + struct ioc4_control *control; + struct uart_state *state; + unsigned long port_flags; + + if (!the_port) + return -ENODEV; + port = get_ioc4_port(the_port, 1); + if (!port) + return -ENODEV; + state = the_port->state; + + control = port->ip_control; + if (!control) { + port->ip_port = NULL; + return -ENODEV; + } + + /* Start up the serial port */ + spin_lock_irqsave(&the_port->lock, port_flags); + retval = ic4_startup_local(the_port); + spin_unlock_irqrestore(&the_port->lock, port_flags); + return retval; +} + +/** + * ic4_set_termios - set termios stuff + * @port: port to operate on + * @termios: New settings + * @termios: Old + * + */ +static void +ic4_set_termios(struct uart_port *the_port, + struct ktermios *termios, struct ktermios *old_termios) +{ + unsigned long port_flags; + + spin_lock_irqsave(&the_port->lock, port_flags); + ioc4_change_speed(the_port, termios, old_termios); + spin_unlock_irqrestore(&the_port->lock, port_flags); +} + +/** + * ic4_request_port - allocate resources for port - no op.... + * @port: port to operate on + * + */ +static int ic4_request_port(struct uart_port *port) +{ + return 0; +} + +/* Associate the uart functions above - given to serial core */ + +static struct uart_ops ioc4_ops = { + .tx_empty = ic4_tx_empty, + .set_mctrl = ic4_set_mctrl, + .get_mctrl = ic4_get_mctrl, + .stop_tx = ic4_stop_tx, + .start_tx = ic4_start_tx, + .stop_rx = null_void_function, + .enable_ms = null_void_function, + .break_ctl = ic4_break_ctl, + .startup = ic4_startup, + .shutdown = ic4_shutdown, + .set_termios = ic4_set_termios, + .type = ic4_type, + .release_port = null_void_function, + .request_port = ic4_request_port, +}; + +/* + * Boot-time initialization code + */ + +static struct uart_driver ioc4_uart_rs232 = { + .owner = THIS_MODULE, + .driver_name = "ioc4_serial_rs232", + .dev_name = DEVICE_NAME_RS232, + .major = DEVICE_MAJOR, + .minor = DEVICE_MINOR_RS232, + .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS, +}; + +static struct uart_driver ioc4_uart_rs422 = { + .owner = THIS_MODULE, + .driver_name = "ioc4_serial_rs422", + .dev_name = DEVICE_NAME_RS422, + .major = DEVICE_MAJOR, + .minor = DEVICE_MINOR_RS422, + .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS, +}; + + +/** + * ioc4_serial_remove_one - detach function + * + * @idd: IOC4 master module data for this IOC4 + */ + +static int ioc4_serial_remove_one(struct ioc4_driver_data *idd) +{ + int port_num, port_type; + struct ioc4_control *control; + struct uart_port *the_port; + struct ioc4_port *port; + struct ioc4_soft *soft; + + /* If serial driver did not attach, don't try to detach */ + control = idd->idd_serial_data; + if (!control) + return 0; + + for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { + for (port_type = UART_PORT_MIN; + port_type < UART_PORT_COUNT; + port_type++) { + the_port = &control->ic_port[port_num].icp_uart_port + [port_type]; + if (the_port) { + switch (port_type) { + case UART_PORT_RS422: + uart_remove_one_port(&ioc4_uart_rs422, + the_port); + break; + default: + case UART_PORT_RS232: + uart_remove_one_port(&ioc4_uart_rs232, + the_port); + break; + } + } + } + port = control->ic_port[port_num].icp_port; + /* we allocate in pairs */ + if (!(port_num & 1) && port) { + pci_free_consistent(port->ip_pdev, + TOTAL_RING_BUF_SIZE, + port->ip_cpu_ringbuf, + port->ip_dma_ringbuf); + kfree(port); + } + } + soft = control->ic_soft; + if (soft) { + free_irq(control->ic_irq, soft); + if (soft->is_ioc4_serial_addr) { + iounmap(soft->is_ioc4_serial_addr); + release_mem_region((unsigned long) + soft->is_ioc4_serial_addr, + sizeof(struct ioc4_serial)); + } + kfree(soft); + } + kfree(control); + idd->idd_serial_data = NULL; + + return 0; +} + + +/** + * ioc4_serial_core_attach_rs232 - register with serial core + * This is done during pci probing + * @pdev: handle for this card + */ +static inline int +ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) +{ + struct ioc4_port *port; + struct uart_port *the_port; + struct ioc4_driver_data *idd = pci_get_drvdata(pdev); + struct ioc4_control *control = idd->idd_serial_data; + int port_num; + int port_type_idx; + struct uart_driver *u_driver; + + + DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", + __func__, pdev, (void *)control)); + + if (!control) + return -ENODEV; + + port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232 + : UART_PORT_RS422; + + u_driver = (port_type == PROTO_RS232) ? &ioc4_uart_rs232 + : &ioc4_uart_rs422; + + /* once around for each port on this card */ + for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { + the_port = &control->ic_port[port_num].icp_uart_port + [port_type_idx]; + port = control->ic_port[port_num].icp_port; + port->ip_all_ports[port_type_idx] = the_port; + + DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n", + __func__, (void *)the_port, + (void *)port, + port_type == PROTO_RS232 ? "rs232" : "rs422")); + + /* membase, iobase and mapbase just need to be non-0 */ + the_port->membase = (unsigned char __iomem *)1; + the_port->iobase = (pdev->bus->number << 16) | port_num; + the_port->line = (Num_of_ioc4_cards << 2) | port_num; + the_port->mapbase = port_type; + the_port->type = PORT_16550A; + the_port->fifosize = IOC4_FIFO_CHARS; + the_port->ops = &ioc4_ops; + the_port->irq = control->ic_irq; + the_port->dev = &pdev->dev; + spin_lock_init(&the_port->lock); + if (uart_add_one_port(u_driver, the_port) < 0) { + printk(KERN_WARNING + "%s: unable to add port %d bus %d\n", + __func__, the_port->line, pdev->bus->number); + } else { + DPRINT_CONFIG( + ("IOC4 serial port %d irq = %d, bus %d\n", + the_port->line, the_port->irq, pdev->bus->number)); + } + } + return 0; +} + +/** + * ioc4_serial_attach_one - register attach function + * called per card found from IOC4 master module. + * @idd: Master module data for this IOC4 + */ +int +ioc4_serial_attach_one(struct ioc4_driver_data *idd) +{ + unsigned long tmp_addr1; + struct ioc4_serial __iomem *serial; + struct ioc4_soft *soft; + struct ioc4_control *control; + int ret = 0; + + + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev, + idd->idd_pci_id)); + + /* PCI-RT does not bring out serial connections. + * Do not attach to this particular IOC4. + */ + if (idd->idd_variant == IOC4_VARIANT_PCI_RT) + return 0; + + /* request serial registers */ + tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; + + if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial), + "sioc4_uart")) { + printk(KERN_WARNING + "ioc4 (%p): unable to get request region for " + "uart space\n", (void *)idd->idd_pdev); + ret = -ENODEV; + goto out1; + } + serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial)); + if (!serial) { + printk(KERN_WARNING + "ioc4 (%p) : unable to remap ioc4 serial register\n", + (void *)idd->idd_pdev); + ret = -ENODEV; + goto out2; + } + DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", + __func__, (void *)idd->idd_misc_regs, + (void *)serial)); + + /* Get memory for the new card */ + control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL); + + if (!control) { + printk(KERN_WARNING "ioc4_attach_one" + ": unable to get memory for the IOC4\n"); + ret = -ENOMEM; + goto out2; + } + idd->idd_serial_data = control; + + /* Allocate the soft structure */ + soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL); + if (!soft) { + printk(KERN_WARNING + "ioc4 (%p): unable to get memory for the soft struct\n", + (void *)idd->idd_pdev); + ret = -ENOMEM; + goto out3; + } + + spin_lock_init(&soft->is_ir_lock); + soft->is_ioc4_misc_addr = idd->idd_misc_regs; + soft->is_ioc4_serial_addr = serial; + + /* Init the IOC4 */ + writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT, + &idd->idd_misc_regs->sio_cr.raw); + + /* Enable serial port mode select generic PIO pins as outputs */ + writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL + | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL, + &idd->idd_misc_regs->gpcr_s.raw); + + /* Clear and disable all serial interrupts */ + write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE); + writel(~0, &idd->idd_misc_regs->sio_ir.raw); + write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC, + IOC4_OTHER_INTR_TYPE); + writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw); + control->ic_soft = soft; + + /* Hook up interrupt handler */ + if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED, + "sgi-ioc4serial", soft)) { + control->ic_irq = idd->idd_pdev->irq; + } else { + printk(KERN_WARNING + "%s : request_irq fails for IRQ 0x%x\n ", + __func__, idd->idd_pdev->irq); + } + ret = ioc4_attach_local(idd); + if (ret) + goto out4; + + /* register port with the serial core - 1 rs232, 1 rs422 */ + + if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232))) + goto out4; + + if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422))) + goto out5; + + Num_of_ioc4_cards++; + + return ret; + + /* error exits that give back resources */ +out5: + ioc4_serial_remove_one(idd); +out4: + kfree(soft); +out3: + kfree(control); +out2: + if (serial) + iounmap(serial); + release_mem_region(tmp_addr1, sizeof(struct ioc4_serial)); +out1: + + return ret; +} + + +static struct ioc4_submodule ioc4_serial_submodule = { + .is_name = "IOC4_serial", + .is_owner = THIS_MODULE, + .is_probe = ioc4_serial_attach_one, + .is_remove = ioc4_serial_remove_one, +}; + +/** + * ioc4_serial_init - module init + */ +static int __init ioc4_serial_init(void) +{ + int ret; + + /* register with serial core */ + if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) { + printk(KERN_WARNING + "%s: Couldn't register rs232 IOC4 serial driver\n", + __func__); + goto out; + } + if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) { + printk(KERN_WARNING + "%s: Couldn't register rs422 IOC4 serial driver\n", + __func__); + goto out_uart_rs232; + } + + /* register with IOC4 main module */ + ret = ioc4_register_submodule(&ioc4_serial_submodule); + if (ret) + goto out_uart_rs422; + return 0; + +out_uart_rs422: + uart_unregister_driver(&ioc4_uart_rs422); +out_uart_rs232: + uart_unregister_driver(&ioc4_uart_rs232); +out: + return ret; +} + +static void __exit ioc4_serial_exit(void) +{ + ioc4_unregister_submodule(&ioc4_serial_submodule); + uart_unregister_driver(&ioc4_uart_rs232); + uart_unregister_driver(&ioc4_uart_rs422); +} + +late_initcall(ioc4_serial_init); /* Call only after tty init is done */ +module_exit(ioc4_serial_exit); + +MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); +MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c new file mode 100644 index 000000000000..ebff4a1d4bcc --- /dev/null +++ b/drivers/tty/serial/ip22zilog.c @@ -0,0 +1,1221 @@ +/* + * Driver for Zilog serial chips found on SGI workstations and + * servers. This driver could actually be made more generic. + * + * This is based on the drivers/serial/sunzilog.c code as of 2.6.0-test7 and the + * old drivers/sgi/char/sgiserial.c code which itself is based of the original + * drivers/sbus/char/zs.c code. A lot of code has been simply moved over + * directly from there but much has been rewritten. Credits therefore go out + * to David S. Miller, Eddie C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell + * for their work there. + * + * Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_SERIAL_IP22_ZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include "ip22zilog.h" + +/* + * On IP22 we need to delay after register accesses but we do not need to + * flush writes. + */ +#define ZSDELAY() udelay(5) +#define ZSDELAY_LONG() udelay(20) +#define ZS_WSYNC(channel) do { } while (0) + +#define NUM_IP22ZILOG 1 +#define NUM_CHANNELS (NUM_IP22ZILOG * 2) + +#define ZS_CLOCK 3672000 /* Zilog input clock rate. */ +#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ + +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_ip22zilog_port { + struct uart_port port; + + /* IRQ servicing chain. */ + struct uart_ip22zilog_port *next; + + /* Current values of Zilog write registers. */ + unsigned char curregs[NUM_ZSREGS]; + + unsigned int flags; +#define IP22ZILOG_FLAG_IS_CONS 0x00000004 +#define IP22ZILOG_FLAG_IS_KGDB 0x00000008 +#define IP22ZILOG_FLAG_MODEM_STATUS 0x00000010 +#define IP22ZILOG_FLAG_IS_CHANNEL_A 0x00000020 +#define IP22ZILOG_FLAG_REGS_HELD 0x00000040 +#define IP22ZILOG_FLAG_TX_STOPPED 0x00000080 +#define IP22ZILOG_FLAG_TX_ACTIVE 0x00000100 +#define IP22ZILOG_FLAG_RESET_DONE 0x00000200 + + unsigned int tty_break; + + unsigned char parity_mask; + unsigned char prev_status; +}; + +#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel *)((PORT)->membase)) +#define UART_ZILOG(PORT) ((struct uart_ip22zilog_port *)(PORT)) +#define IP22ZILOG_GET_CURR_REG(PORT, REGNUM) \ + (UART_ZILOG(PORT)->curregs[REGNUM]) +#define IP22ZILOG_SET_CURR_REG(PORT, REGNUM, REGVAL) \ + ((UART_ZILOG(PORT)->curregs[REGNUM]) = (REGVAL)) +#define ZS_IS_CONS(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CONS) +#define ZS_IS_KGDB(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_KGDB) +#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & IP22ZILOG_FLAG_MODEM_STATUS) +#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & IP22ZILOG_FLAG_IS_CHANNEL_A) +#define ZS_REGS_HELD(UP) ((UP)->flags & IP22ZILOG_FLAG_REGS_HELD) +#define ZS_TX_STOPPED(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_STOPPED) +#define ZS_TX_ACTIVE(UP) ((UP)->flags & IP22ZILOG_FLAG_TX_ACTIVE) + +/* Reading and writing Zilog8530 registers. The delays are to make this + * driver work on the IP22 which needs a settling delay after each chip + * register access, other machines handle this in hardware via auxiliary + * flip-flops which implement the settle time we do in software. + * + * The port lock must be held and local IRQs must be disabled + * when {read,write}_zsreg is invoked. + */ +static unsigned char read_zsreg(struct zilog_channel *channel, + unsigned char reg) +{ + unsigned char retval; + + writeb(reg, &channel->control); + ZSDELAY(); + retval = readb(&channel->control); + ZSDELAY(); + + return retval; +} + +static void write_zsreg(struct zilog_channel *channel, + unsigned char reg, unsigned char value) +{ + writeb(reg, &channel->control); + ZSDELAY(); + writeb(value, &channel->control); + ZSDELAY(); +} + +static void ip22zilog_clear_fifo(struct zilog_channel *channel) +{ + int i; + + for (i = 0; i < 32; i++) { + unsigned char regval; + + regval = readb(&channel->control); + ZSDELAY(); + if (regval & Rx_CH_AV) + break; + + regval = read_zsreg(channel, R1); + readb(&channel->data); + ZSDELAY(); + + if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + } +} + +/* This function must only be called when the TX is not busy. The UART + * port lock must be held and local interrupts disabled. + */ +static void __load_zsregs(struct zilog_channel *channel, unsigned char *regs) +{ + int i; + + /* Let pending transmits finish. */ + for (i = 0; i < 1000; i++) { + unsigned char stat = read_zsreg(channel, R1); + if (stat & ALL_SNT) + break; + udelay(100); + } + + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + ip22zilog_clear_fifo(channel); + + /* Disable all interrupts. */ + write_zsreg(channel, R1, + regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); + + /* Set parity, sync config, stop bits, and clock divisor. */ + write_zsreg(channel, R4, regs[R4]); + + /* Set misc. TX/RX control bits. */ + write_zsreg(channel, R10, regs[R10]); + + /* Set TX/RX controls sans the enable bits. */ + write_zsreg(channel, R3, regs[R3] & ~RxENAB); + write_zsreg(channel, R5, regs[R5] & ~TxENAB); + + /* Synchronous mode config. */ + write_zsreg(channel, R6, regs[R6]); + write_zsreg(channel, R7, regs[R7]); + + /* Don't mess with the interrupt vector (R2, unused by us) and + * master interrupt control (R9). We make sure this is setup + * properly at probe time then never touch it again. + */ + + /* Disable baud generator. */ + write_zsreg(channel, R14, regs[R14] & ~BRENAB); + + /* Clock mode control. */ + write_zsreg(channel, R11, regs[R11]); + + /* Lower and upper byte of baud rate generator divisor. */ + write_zsreg(channel, R12, regs[R12]); + write_zsreg(channel, R13, regs[R13]); + + /* Now rewrite R14, with BRENAB (if set). */ + write_zsreg(channel, R14, regs[R14]); + + /* External status interrupt control. */ + write_zsreg(channel, R15, regs[R15]); + + /* Reset external status interrupts. */ + write_zsreg(channel, R0, RES_EXT_INT); + write_zsreg(channel, R0, RES_EXT_INT); + + /* Rewrite R3/R5, this time without enables masked. */ + write_zsreg(channel, R3, regs[R3]); + write_zsreg(channel, R5, regs[R5]); + + /* Rewrite R1, this time without IRQ enabled masked. */ + write_zsreg(channel, R1, regs[R1]); +} + +/* Reprogram the Zilog channel HW registers with the copies found in the + * software state struct. If the transmitter is busy, we defer this update + * until the next TX complete interrupt. Else, we do it right now. + * + * The UART port lock must be held and local interrupts disabled. + */ +static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up, + struct zilog_channel *channel) +{ + if (!ZS_REGS_HELD(up)) { + if (ZS_TX_ACTIVE(up)) { + up->flags |= IP22ZILOG_FLAG_REGS_HELD; + } else { + __load_zsregs(channel, up->curregs); + } + } +} + +#define Rx_BRK 0x0100 /* BREAK event software flag. */ +#define Rx_SYS 0x0200 /* SysRq event software flag. */ + +static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up, + struct zilog_channel *channel) +{ + struct tty_struct *tty; + unsigned char ch, flag; + unsigned int r1; + + tty = NULL; + if (up->port.state != NULL && + up->port.state->port.tty != NULL) + tty = up->port.state->port.tty; + + for (;;) { + ch = readb(&channel->control); + ZSDELAY(); + if (!(ch & Rx_CH_AV)) + break; + + r1 = read_zsreg(channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + + ch = readb(&channel->data); + ZSDELAY(); + + ch &= up->parity_mask; + + /* Handle the null char got when BREAK is removed. */ + if (!ch) + r1 |= up->tty_break; + + /* A real serial line, record the character and status. */ + flag = TTY_NORMAL; + up->port.icount.rx++; + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) { + up->tty_break = 0; + + if (r1 & (Rx_SYS | Rx_BRK)) { + up->port.icount.brk++; + if (r1 & Rx_SYS) + continue; + r1 &= ~(PAR_ERR | CRC_ERR); + } + else if (r1 & PAR_ERR) + up->port.icount.parity++; + else if (r1 & CRC_ERR) + up->port.icount.frame++; + if (r1 & Rx_OVR) + up->port.icount.overrun++; + r1 &= up->port.read_status_mask; + if (r1 & Rx_BRK) + flag = TTY_BREAK; + else if (r1 & PAR_ERR) + flag = TTY_PARITY; + else if (r1 & CRC_ERR) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + + if (tty) + uart_insert_char(&up->port, r1, Rx_OVR, ch, flag); + } + return tty; +} + +static void ip22zilog_status_handle(struct uart_ip22zilog_port *up, + struct zilog_channel *channel) +{ + unsigned char status; + + status = readb(&channel->control); + ZSDELAY(); + + writeb(RES_EXT_INT, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (up->curregs[R15] & BRKIE) { + if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) { + if (uart_handle_break(&up->port)) + up->tty_break = Rx_SYS; + else + up->tty_break = Rx_BRK; + } + } + + if (ZS_WANTS_MODEM_STATUS(up)) { + if (status & SYNC) + up->port.icount.dsr++; + + /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. + * But it does not tell us which bit has changed, we have to keep + * track of this ourselves. + */ + if ((status ^ up->prev_status) ^ DCD) + uart_handle_dcd_change(&up->port, + (status & DCD)); + if ((status ^ up->prev_status) ^ CTS) + uart_handle_cts_change(&up->port, + (status & CTS)); + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + } + + up->prev_status = status; +} + +static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, + struct zilog_channel *channel) +{ + struct circ_buf *xmit; + + if (ZS_IS_CONS(up)) { + unsigned char status = readb(&channel->control); + ZSDELAY(); + + /* TX still busy? Just wait for the next TX done interrupt. + * + * It can occur because of how we do serial console writes. It would + * be nice to transmit console writes just like we normally would for + * a TTY line. (ie. buffered and TX interrupt driven). That is not + * easy because console writes cannot sleep. One solution might be + * to poll on enough port->xmit space becomming free. -DaveM + */ + if (!(status & Tx_BUF_EMP)) + return; + } + + up->flags &= ~IP22ZILOG_FLAG_TX_ACTIVE; + + if (ZS_REGS_HELD(up)) { + __load_zsregs(channel, up->curregs); + up->flags &= ~IP22ZILOG_FLAG_REGS_HELD; + } + + if (ZS_TX_STOPPED(up)) { + up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED; + goto ack_tx_int; + } + + if (up->port.x_char) { + up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; + writeb(up->port.x_char, &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + + if (up->port.state == NULL) + goto ack_tx_int; + xmit = &up->port.state->xmit; + if (uart_circ_empty(xmit)) + goto ack_tx_int; + if (uart_tx_stopped(&up->port)) + goto ack_tx_int; + + up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; + writeb(xmit->buf[xmit->tail], &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + return; + +ack_tx_int: + writeb(RES_Tx_P, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); +} + +static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id) +{ + struct uart_ip22zilog_port *up = dev_id; + + while (up) { + struct zilog_channel *channel + = ZILOG_CHANNEL_FROM_PORT(&up->port); + struct tty_struct *tty; + unsigned char r3; + + spin_lock(&up->port.lock); + r3 = read_zsreg(channel, R3); + + /* Channel A */ + tty = NULL; + if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (r3 & CHARxIP) + tty = ip22zilog_receive_chars(up, channel); + if (r3 & CHAEXT) + ip22zilog_status_handle(up, channel); + if (r3 & CHATxIP) + ip22zilog_transmit_chars(up, channel); + } + spin_unlock(&up->port.lock); + + if (tty) + tty_flip_buffer_push(tty); + + /* Channel B */ + up = up->next; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + + spin_lock(&up->port.lock); + tty = NULL; + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (r3 & CHBRxIP) + tty = ip22zilog_receive_chars(up, channel); + if (r3 & CHBEXT) + ip22zilog_status_handle(up, channel); + if (r3 & CHBTxIP) + ip22zilog_transmit_chars(up, channel); + } + spin_unlock(&up->port.lock); + + if (tty) + tty_flip_buffer_push(tty); + + up = up->next; + } + + return IRQ_HANDLED; +} + +/* A convenient way to quickly get R0 status. The caller must _not_ hold the + * port lock, it is acquired here. + */ +static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port) +{ + struct zilog_channel *channel; + unsigned char status; + + channel = ZILOG_CHANNEL_FROM_PORT(port); + status = readb(&channel->control); + ZSDELAY(); + + return status; +} + +/* The port lock is not held. */ +static unsigned int ip22zilog_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned char status; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + + status = ip22zilog_read_channel_status(port); + + spin_unlock_irqrestore(&port->lock, flags); + + if (status & Tx_BUF_EMP) + ret = TIOCSER_TEMT; + else + ret = 0; + + return ret; +} + +/* The port lock is held and interrupts are disabled. */ +static unsigned int ip22zilog_get_mctrl(struct uart_port *port) +{ + unsigned char status; + unsigned int ret; + + status = ip22zilog_read_channel_status(port); + + ret = 0; + if (status & DCD) + ret |= TIOCM_CAR; + if (status & SYNC) + ret |= TIOCM_DSR; + if (status & CTS) + ret |= TIOCM_CTS; + + return ret; +} + +/* The port lock is held and interrupts are disabled. */ +static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char set_bits, clear_bits; + + set_bits = clear_bits = 0; + + if (mctrl & TIOCM_RTS) + set_bits |= RTS; + else + clear_bits |= RTS; + if (mctrl & TIOCM_DTR) + set_bits |= DTR; + else + clear_bits |= DTR; + + /* NOTE: Not subject to 'transmitter active' rule. */ + up->curregs[R5] |= set_bits; + up->curregs[R5] &= ~clear_bits; + write_zsreg(channel, R5, up->curregs[R5]); +} + +/* The port lock is held and interrupts are disabled. */ +static void ip22zilog_stop_tx(struct uart_port *port) +{ + struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + + up->flags |= IP22ZILOG_FLAG_TX_STOPPED; +} + +/* The port lock is held and interrupts are disabled. */ +static void ip22zilog_start_tx(struct uart_port *port) +{ + struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char status; + + up->flags |= IP22ZILOG_FLAG_TX_ACTIVE; + up->flags &= ~IP22ZILOG_FLAG_TX_STOPPED; + + status = readb(&channel->control); + ZSDELAY(); + + /* TX busy? Just wait for the TX done interrupt. */ + if (!(status & Tx_BUF_EMP)) + return; + + /* Send the first character to jump-start the TX done + * IRQ sending engine. + */ + if (port->x_char) { + writeb(port->x_char, &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + port->icount.tx++; + port->x_char = 0; + } else { + struct circ_buf *xmit = &port->state->xmit; + + writeb(xmit->buf[xmit->tail], &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + } +} + +/* The port lock is held and interrupts are disabled. */ +static void ip22zilog_stop_rx(struct uart_port *port) +{ + struct uart_ip22zilog_port *up = UART_ZILOG(port); + struct zilog_channel *channel; + + if (ZS_IS_CONS(up)) + return; + + channel = ZILOG_CHANNEL_FROM_PORT(port); + + /* Disable all RX interrupts. */ + up->curregs[R1] &= ~RxINT_MASK; + ip22zilog_maybe_update_regs(up, channel); +} + +/* The port lock is held. */ +static void ip22zilog_enable_ms(struct uart_port *port) +{ + struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char new_reg; + + new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE); + if (new_reg != up->curregs[R15]) { + up->curregs[R15] = new_reg; + + /* NOTE: Not subject to 'transmitter active' rule. */ + write_zsreg(channel, R15, up->curregs[R15]); + } +} + +/* The port lock is not held. */ +static void ip22zilog_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char set_bits, clear_bits, new_reg; + unsigned long flags; + + set_bits = clear_bits = 0; + + if (break_state) + set_bits |= SND_BRK; + else + clear_bits |= SND_BRK; + + spin_lock_irqsave(&port->lock, flags); + + new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != up->curregs[R5]) { + up->curregs[R5] = new_reg; + + /* NOTE: Not subject to 'transmitter active' rule. */ + write_zsreg(channel, R5, up->curregs[R5]); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void __ip22zilog_reset(struct uart_ip22zilog_port *up) +{ + struct zilog_channel *channel; + int i; + + if (up->flags & IP22ZILOG_FLAG_RESET_DONE) + return; + + /* Let pending transmits finish. */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + for (i = 0; i < 1000; i++) { + unsigned char stat = read_zsreg(channel, R1); + if (stat & ALL_SNT) + break; + udelay(100); + } + + if (!ZS_IS_CHANNEL_A(up)) { + up++; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + } + write_zsreg(channel, R9, FHWRES); + ZSDELAY_LONG(); + (void) read_zsreg(channel, R0); + + up->flags |= IP22ZILOG_FLAG_RESET_DONE; + up->next->flags |= IP22ZILOG_FLAG_RESET_DONE; +} + +static void __ip22zilog_startup(struct uart_ip22zilog_port *up) +{ + struct zilog_channel *channel; + + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + + __ip22zilog_reset(up); + + __load_zsregs(channel, up->curregs); + /* set master interrupt enable */ + write_zsreg(channel, R9, up->curregs[R9]); + up->prev_status = readb(&channel->control); + + /* Enable receiver and transmitter. */ + up->curregs[R3] |= RxENAB; + up->curregs[R5] |= TxENAB; + + up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + ip22zilog_maybe_update_regs(up, channel); +} + +static int ip22zilog_startup(struct uart_port *port) +{ + struct uart_ip22zilog_port *up = UART_ZILOG(port); + unsigned long flags; + + if (ZS_IS_CONS(up)) + return 0; + + spin_lock_irqsave(&port->lock, flags); + __ip22zilog_startup(up); + spin_unlock_irqrestore(&port->lock, flags); + return 0; +} + +/* + * The test for ZS_IS_CONS is explained by the following e-mail: + ***** + * From: Russell King + * Date: Sun, 8 Dec 2002 10:18:38 +0000 + * + * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote: + * > I boot my 2.5 boxes using "console=ttyS0,9600" argument, + * > and I noticed that something is not right with reference + * > counting in this case. It seems that when the console + * > is open by kernel initially, this is not accounted + * > as an open, and uart_startup is not called. + * + * That is correct. We are unable to call uart_startup when the serial + * console is initialised because it may need to allocate memory (as + * request_irq does) and the memory allocators may not have been + * initialised. + * + * 1. initialise the port into a state where it can send characters in the + * console write method. + * + * 2. don't do the actual hardware shutdown in your shutdown() method (but + * do the normal software shutdown - ie, free irqs etc) + ***** + */ +static void ip22zilog_shutdown(struct uart_port *port) +{ + struct uart_ip22zilog_port *up = UART_ZILOG(port); + struct zilog_channel *channel; + unsigned long flags; + + if (ZS_IS_CONS(up)) + return; + + spin_lock_irqsave(&port->lock, flags); + + channel = ZILOG_CHANNEL_FROM_PORT(port); + + /* Disable receiver and transmitter. */ + up->curregs[R3] &= ~RxENAB; + up->curregs[R5] &= ~TxENAB; + + /* Disable all interrupts and BRK assertion. */ + up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + up->curregs[R5] &= ~SND_BRK; + ip22zilog_maybe_update_regs(up, channel); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Shared by TTY driver and serial console setup. The port lock is held + * and local interrupts are disabled. + */ +static void +ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, + unsigned int iflag, int brg) +{ + + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + + /* Program BAUD and clock source. */ + up->curregs[R4] &= ~XCLK_MASK; + up->curregs[R4] |= X16CLK; + up->curregs[R12] = brg & 0xff; + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRENAB; + + /* Character size, stop bits, and parity. */ + up->curregs[3] &= ~RxN_MASK; + up->curregs[5] &= ~TxN_MASK; + switch (cflag & CSIZE) { + case CS5: + up->curregs[3] |= Rx5; + up->curregs[5] |= Tx5; + up->parity_mask = 0x1f; + break; + case CS6: + up->curregs[3] |= Rx6; + up->curregs[5] |= Tx6; + up->parity_mask = 0x3f; + break; + case CS7: + up->curregs[3] |= Rx7; + up->curregs[5] |= Tx7; + up->parity_mask = 0x7f; + break; + case CS8: + default: + up->curregs[3] |= Rx8; + up->curregs[5] |= Tx8; + up->parity_mask = 0xff; + break; + }; + up->curregs[4] &= ~0x0c; + if (cflag & CSTOPB) + up->curregs[4] |= SB2; + else + up->curregs[4] |= SB1; + if (cflag & PARENB) + up->curregs[4] |= PAR_ENAB; + else + up->curregs[4] &= ~PAR_ENAB; + if (!(cflag & PARODD)) + up->curregs[4] |= PAR_EVEN; + else + up->curregs[4] &= ~PAR_EVEN; + + up->port.read_status_mask = Rx_OVR; + if (iflag & INPCK) + up->port.read_status_mask |= CRC_ERR | PAR_ERR; + if (iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= BRK_ABRT; + + up->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= CRC_ERR | PAR_ERR; + if (iflag & IGNBRK) { + up->port.ignore_status_mask |= BRK_ABRT; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= Rx_OVR; + } + + if ((cflag & CREAD) == 0) + up->port.ignore_status_mask = 0xff; +} + +/* The port lock is not held. */ +static void +ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port; + unsigned long flags; + int baud, brg; + + baud = uart_get_baud_rate(port, termios, old, 1200, 76800); + + spin_lock_irqsave(&up->port.lock, flags); + + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + + ip22zilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg); + + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->flags |= IP22ZILOG_FLAG_MODEM_STATUS; + else + up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS; + + ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static const char *ip22zilog_type(struct uart_port *port) +{ + return "IP22-Zilog"; +} + +/* We do not request/release mappings of the registers here, this + * happens at early serial probe time. + */ +static void ip22zilog_release_port(struct uart_port *port) +{ +} + +static int ip22zilog_request_port(struct uart_port *port) +{ + return 0; +} + +/* These do not need to do anything interesting either. */ +static void ip22zilog_config_port(struct uart_port *port, int flags) +{ +} + +/* We do not support letting the user mess with the divisor, IRQ, etc. */ +static int ip22zilog_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static struct uart_ops ip22zilog_pops = { + .tx_empty = ip22zilog_tx_empty, + .set_mctrl = ip22zilog_set_mctrl, + .get_mctrl = ip22zilog_get_mctrl, + .stop_tx = ip22zilog_stop_tx, + .start_tx = ip22zilog_start_tx, + .stop_rx = ip22zilog_stop_rx, + .enable_ms = ip22zilog_enable_ms, + .break_ctl = ip22zilog_break_ctl, + .startup = ip22zilog_startup, + .shutdown = ip22zilog_shutdown, + .set_termios = ip22zilog_set_termios, + .type = ip22zilog_type, + .release_port = ip22zilog_release_port, + .request_port = ip22zilog_request_port, + .config_port = ip22zilog_config_port, + .verify_port = ip22zilog_verify_port, +}; + +static struct uart_ip22zilog_port *ip22zilog_port_table; +static struct zilog_layout **ip22zilog_chip_regs; + +static struct uart_ip22zilog_port *ip22zilog_irq_chain; +static int zilog_irq = -1; + +static void * __init alloc_one_table(unsigned long size) +{ + return kzalloc(size, GFP_KERNEL); +} + +static void __init ip22zilog_alloc_tables(void) +{ + ip22zilog_port_table = (struct uart_ip22zilog_port *) + alloc_one_table(NUM_CHANNELS * sizeof(struct uart_ip22zilog_port)); + ip22zilog_chip_regs = (struct zilog_layout **) + alloc_one_table(NUM_IP22ZILOG * sizeof(struct zilog_layout *)); + + if (ip22zilog_port_table == NULL || ip22zilog_chip_regs == NULL) { + panic("IP22-Zilog: Cannot allocate IP22-Zilog tables."); + } +} + +/* Get the address of the registers for IP22-Zilog instance CHIP. */ +static struct zilog_layout * __init get_zs(int chip) +{ + unsigned long base; + + if (chip < 0 || chip >= NUM_IP22ZILOG) { + panic("IP22-Zilog: Illegal chip number %d in get_zs.", chip); + } + + /* Not probe-able, hard code it. */ + base = (unsigned long) &sgioc->uart; + + zilog_irq = SGI_SERIAL_IRQ; + request_mem_region(base, 8, "IP22-Zilog"); + + return (struct zilog_layout *) base; +} + +#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ + +#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE +static void ip22zilog_put_char(struct uart_port *port, int ch) +{ + struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port); + int loops = ZS_PUT_CHAR_MAX_DELAY; + + /* This is a timed polling loop so do not switch the explicit + * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM + */ + do { + unsigned char val = readb(&channel->control); + if (val & Tx_BUF_EMP) { + ZSDELAY(); + break; + } + udelay(5); + } while (--loops); + + writeb(ch, &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); +} + +static void +ip22zilog_console_write(struct console *con, const char *s, unsigned int count) +{ + struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + uart_console_write(&up->port, s, count, ip22zilog_put_char); + udelay(2); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static int __init ip22zilog_console_setup(struct console *con, char *options) +{ + struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index]; + unsigned long flags; + int baud = 9600, bits = 8; + int parity = 'n'; + int flow = 'n'; + + up->flags |= IP22ZILOG_FLAG_IS_CONS; + + printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index); + + spin_lock_irqsave(&up->port.lock, flags); + + up->curregs[R15] |= BRKIE; + + __ip22zilog_startup(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(&up->port, con, baud, parity, bits, flow); +} + +static struct uart_driver ip22zilog_reg; + +static struct console ip22zilog_console = { + .name = "ttyS", + .write = ip22zilog_console_write, + .device = uart_console_device, + .setup = ip22zilog_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ip22zilog_reg, +}; +#endif /* CONFIG_SERIAL_IP22_ZILOG_CONSOLE */ + +static struct uart_driver ip22zilog_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = NUM_CHANNELS, +#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE + .cons = &ip22zilog_console, +#endif +}; + +static void __init ip22zilog_prepare(void) +{ + struct uart_ip22zilog_port *up; + struct zilog_layout *rp; + int channel, chip; + + /* + * Temporary fix. + */ + for (channel = 0; channel < NUM_CHANNELS; channel++) + spin_lock_init(&ip22zilog_port_table[channel].port.lock); + + ip22zilog_irq_chain = &ip22zilog_port_table[NUM_CHANNELS - 1]; + up = &ip22zilog_port_table[0]; + for (channel = NUM_CHANNELS - 1 ; channel > 0; channel--) + up[channel].next = &up[channel - 1]; + up[channel].next = NULL; + + for (chip = 0; chip < NUM_IP22ZILOG; chip++) { + if (!ip22zilog_chip_regs[chip]) { + ip22zilog_chip_regs[chip] = rp = get_zs(chip); + + up[(chip * 2) + 0].port.membase = (char *) &rp->channelB; + up[(chip * 2) + 1].port.membase = (char *) &rp->channelA; + + /* In theory mapbase is the physical address ... */ + up[(chip * 2) + 0].port.mapbase = + (unsigned long) ioremap((unsigned long) &rp->channelB, 8); + up[(chip * 2) + 1].port.mapbase = + (unsigned long) ioremap((unsigned long) &rp->channelA, 8); + } + + /* Channel A */ + up[(chip * 2) + 0].port.iotype = UPIO_MEM; + up[(chip * 2) + 0].port.irq = zilog_irq; + up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; + up[(chip * 2) + 0].port.fifosize = 1; + up[(chip * 2) + 0].port.ops = &ip22zilog_pops; + up[(chip * 2) + 0].port.type = PORT_IP22ZILOG; + up[(chip * 2) + 0].port.flags = 0; + up[(chip * 2) + 0].port.line = (chip * 2) + 0; + up[(chip * 2) + 0].flags = 0; + + /* Channel B */ + up[(chip * 2) + 1].port.iotype = UPIO_MEM; + up[(chip * 2) + 1].port.irq = zilog_irq; + up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; + up[(chip * 2) + 1].port.fifosize = 1; + up[(chip * 2) + 1].port.ops = &ip22zilog_pops; + up[(chip * 2) + 1].port.type = PORT_IP22ZILOG; + up[(chip * 2) + 1].port.line = (chip * 2) + 1; + up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; + } + + for (channel = 0; channel < NUM_CHANNELS; channel++) { + struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel]; + int brg; + + /* Normal serial TTY. */ + up->parity_mask = 0xff; + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R9] = NV | MIE; + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRENAB; + } +} + +static int __init ip22zilog_ports_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: IP22 Zilog driver (%d chips).\n", NUM_IP22ZILOG); + + ip22zilog_prepare(); + + if (request_irq(zilog_irq, ip22zilog_interrupt, 0, + "IP22-Zilog", ip22zilog_irq_chain)) { + panic("IP22-Zilog: Unable to register zs interrupt handler.\n"); + } + + ret = uart_register_driver(&ip22zilog_reg); + if (ret == 0) { + int i; + + for (i = 0; i < NUM_CHANNELS; i++) { + struct uart_ip22zilog_port *up = &ip22zilog_port_table[i]; + + uart_add_one_port(&ip22zilog_reg, &up->port); + } + } + + return ret; +} + +static int __init ip22zilog_init(void) +{ + /* IP22 Zilog setup is hard coded, no probing to do. */ + ip22zilog_alloc_tables(); + ip22zilog_ports_init(); + + return 0; +} + +static void __exit ip22zilog_exit(void) +{ + int i; + struct uart_ip22zilog_port *up; + + for (i = 0; i < NUM_CHANNELS; i++) { + up = &ip22zilog_port_table[i]; + + uart_remove_one_port(&ip22zilog_reg, &up->port); + } + + /* Free IO mem */ + up = &ip22zilog_port_table[0]; + for (i = 0; i < NUM_IP22ZILOG; i++) { + if (up[(i * 2) + 0].port.mapbase) { + iounmap((void*)up[(i * 2) + 0].port.mapbase); + up[(i * 2) + 0].port.mapbase = 0; + } + if (up[(i * 2) + 1].port.mapbase) { + iounmap((void*)up[(i * 2) + 1].port.mapbase); + up[(i * 2) + 1].port.mapbase = 0; + } + } + + uart_unregister_driver(&ip22zilog_reg); +} + +module_init(ip22zilog_init); +module_exit(ip22zilog_exit); + +/* David wrote it but I'm to blame for the bugs ... */ +MODULE_AUTHOR("Ralf Baechle "); +MODULE_DESCRIPTION("SGI Zilog serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/ip22zilog.h b/drivers/tty/serial/ip22zilog.h new file mode 100644 index 000000000000..a59a9a8341d2 --- /dev/null +++ b/drivers/tty/serial/ip22zilog.h @@ -0,0 +1,281 @@ +#ifndef _IP22_ZILOG_H +#define _IP22_ZILOG_H + +#include + +struct zilog_channel { +#ifdef __BIG_ENDIAN + volatile unsigned char unused0[3]; + volatile unsigned char control; + volatile unsigned char unused1[3]; + volatile unsigned char data; +#else /* __LITTLE_ENDIAN */ + volatile unsigned char control; + volatile unsigned char unused0[3]; + volatile unsigned char data; + volatile unsigned char unused1[3]; +#endif +}; + +struct zilog_layout { + struct zilog_channel channelB; + struct zilog_channel channelA; +}; + +#define NUM_ZSREGS 16 + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ +#define RxINT_MASK 0x18 + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENAB 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxN_MASK 0xc0 + +/* Write Register 4 */ + +#define PAR_ENAB 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ +#define XCLK_MASK 0xC0 + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxN_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENAB 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define CRC_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ +#define CHB_Tx_EMPTY 0x00 +#define CHB_EXT_STAT 0x02 +#define CHB_Rx_AVAIL 0x04 +#define CHB_SPECIAL 0x06 +#define CHA_Tx_EMPTY 0x08 +#define CHA_EXT_STAT 0x0a +#define CHA_Rx_AVAIL 0x0c +#define CHA_SPECIAL 0x0e +#define STATUS_MASK 0x0e + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* Misc macros */ +#define ZS_CLEARERR(channel) do { writeb(ERR_RES, &channel->control); \ + udelay(5); } while(0) + +#define ZS_CLEARSTAT(channel) do { writeb(RES_EXT_INT, &channel->control); \ + udelay(5); } while(0) + +#define ZS_CLEARFIFO(channel) do { readb(&channel->data); \ + udelay(2); \ + readb(&channel->data); \ + udelay(2); \ + readb(&channel->data); \ + udelay(2); } while(0) + +#endif /* _IP22_ZILOG_H */ diff --git a/drivers/tty/serial/jsm/Makefile b/drivers/tty/serial/jsm/Makefile new file mode 100644 index 000000000000..e46b6e0f8b18 --- /dev/null +++ b/drivers/tty/serial/jsm/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Jasmine adapter +# + +obj-$(CONFIG_SERIAL_JSM) += jsm.o + +jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o + diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h new file mode 100644 index 000000000000..38a509c684cd --- /dev/null +++ b/drivers/tty/serial/jsm/jsm.h @@ -0,0 +1,388 @@ +/************************************************************************ + * Copyright 2003 Digi International (www.digi.com) + * + * Copyright (C) 2004 IBM Corporation. All rights reserved. + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. + * + * Contact Information: + * Scott H Kilau + * Wendy Xiong + * + ***********************************************************************/ + +#ifndef __JSM_DRIVER_H +#define __JSM_DRIVER_H + +#include +#include /* To pick up the varions Linux types */ +#include +#include +#include + +/* + * Debugging levels can be set using debug insmod variable + * They can also be compiled out completely. + */ +enum { + DBG_INIT = 0x01, + DBG_BASIC = 0x02, + DBG_CORE = 0x04, + DBG_OPEN = 0x08, + DBG_CLOSE = 0x10, + DBG_READ = 0x20, + DBG_WRITE = 0x40, + DBG_IOCTL = 0x80, + DBG_PROC = 0x100, + DBG_PARAM = 0x200, + DBG_PSCAN = 0x400, + DBG_EVENT = 0x800, + DBG_DRAIN = 0x1000, + DBG_MSIGS = 0x2000, + DBG_MGMT = 0x4000, + DBG_INTR = 0x8000, + DBG_CARR = 0x10000, +}; + +#define jsm_printk(nlevel, klevel, pdev, fmt, args...) \ + if ((DBG_##nlevel & jsm_debug)) \ + dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) + +#define MAXLINES 256 +#define MAXPORTS 8 +#define MAX_STOPS_SENT 5 + +/* Board type definitions */ + +#define T_NEO 0000 +#define T_CLASSIC 0001 +#define T_PCIBUS 0400 + +/* Board State Definitions */ + +#define BD_RUNNING 0x0 +#define BD_REASON 0x7f +#define BD_NOTFOUND 0x1 +#define BD_NOIOPORT 0x2 +#define BD_NOMEM 0x3 +#define BD_NOBIOS 0x4 +#define BD_NOFEP 0x5 +#define BD_FAILED 0x6 +#define BD_ALLOCATED 0x7 +#define BD_TRIBOOT 0x8 +#define BD_BADKME 0x80 + + +/* 4 extra for alignment play space */ +#define WRITEBUFLEN ((4096) + 4) +#define MYFLIPLEN N_TTY_BUF_SIZE + +#define JSM_VERSION "jsm: 1.2-1-INKERNEL" +#define JSM_PARTNUM "40002438_A-INKERNEL" + +struct jsm_board; +struct jsm_channel; + +/************************************************************************ + * Per board operations structure * + ************************************************************************/ +struct board_ops { + irq_handler_t intr; + void (*uart_init) (struct jsm_channel *ch); + void (*uart_off) (struct jsm_channel *ch); + void (*param) (struct jsm_channel *ch); + void (*assert_modem_signals) (struct jsm_channel *ch); + void (*flush_uart_write) (struct jsm_channel *ch); + void (*flush_uart_read) (struct jsm_channel *ch); + void (*disable_receiver) (struct jsm_channel *ch); + void (*enable_receiver) (struct jsm_channel *ch); + void (*send_break) (struct jsm_channel *ch); + void (*clear_break) (struct jsm_channel *ch, int); + void (*send_start_character) (struct jsm_channel *ch); + void (*send_stop_character) (struct jsm_channel *ch); + void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch); + u32 (*get_uart_bytes_left) (struct jsm_channel *ch); + void (*send_immediate_char) (struct jsm_channel *ch, unsigned char); +}; + + +/* + * Per-board information + */ +struct jsm_board +{ + int boardnum; /* Board number: 0-32 */ + + int type; /* Type of board */ + u8 rev; /* PCI revision ID */ + struct pci_dev *pci_dev; + u32 maxports; /* MAX ports this board can handle */ + + spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and + * the interrupt routine from each other. + */ + + u32 nasync; /* Number of ports on card */ + + u32 irq; /* Interrupt request number */ + + u64 membase; /* Start of base memory of the card */ + u64 membase_end; /* End of base memory of the card */ + + u8 __iomem *re_map_membase;/* Remapped memory of the card */ + + u64 iobase; /* Start of io base of the card */ + u64 iobase_end; /* End of io base of the card */ + + u32 bd_uart_offset; /* Space between each UART */ + + struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */ + char *flipbuf; /* Our flip buffer, alloced if board is found */ + + u32 bd_dividend; /* Board/UARTs specific dividend */ + + struct board_ops *bd_ops; + + struct list_head jsm_board_entry; +}; + +/************************************************************************ + * Device flag definitions for ch_flags. + ************************************************************************/ +#define CH_PRON 0x0001 /* Printer on string */ +#define CH_STOP 0x0002 /* Output is stopped */ +#define CH_STOPI 0x0004 /* Input is stopped */ +#define CH_CD 0x0008 /* Carrier is present */ +#define CH_FCAR 0x0010 /* Carrier forced on */ +#define CH_HANGUP 0x0020 /* Hangup received */ + +#define CH_RECEIVER_OFF 0x0040 /* Receiver is off */ +#define CH_OPENING 0x0080 /* Port in fragile open state */ +#define CH_CLOSING 0x0100 /* Port in fragile close state */ +#define CH_FIFO_ENABLED 0x0200 /* Port has FIFOs enabled */ +#define CH_TX_FIFO_EMPTY 0x0400 /* TX Fifo is completely empty */ +#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */ +#define CH_BREAK_SENDING 0x1000 /* Break is being sent */ +#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */ +#define CH_FLIPBUF_IN_USE 0x4000 /* Channel's flipbuf is in use */ +#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */ + +/* Our Read/Error/Write queue sizes */ +#define RQUEUEMASK 0x1FFF /* 8 K - 1 */ +#define EQUEUEMASK 0x1FFF /* 8 K - 1 */ +#define WQUEUEMASK 0x0FFF /* 4 K - 1 */ +#define RQUEUESIZE (RQUEUEMASK + 1) +#define EQUEUESIZE RQUEUESIZE +#define WQUEUESIZE (WQUEUEMASK + 1) + + +/************************************************************************ + * Channel information structure. + ************************************************************************/ +struct jsm_channel { + struct uart_port uart_port; + struct jsm_board *ch_bd; /* Board structure pointer */ + + spinlock_t ch_lock; /* provide for serialization */ + wait_queue_head_t ch_flags_wait; + + u32 ch_portnum; /* Port number, 0 offset. */ + u32 ch_open_count; /* open count */ + u32 ch_flags; /* Channel flags */ + + u64 ch_close_delay; /* How long we should drop RTS/DTR for */ + + tcflag_t ch_c_iflag; /* channel iflags */ + tcflag_t ch_c_cflag; /* channel cflags */ + tcflag_t ch_c_oflag; /* channel oflags */ + tcflag_t ch_c_lflag; /* channel lflags */ + u8 ch_stopc; /* Stop character */ + u8 ch_startc; /* Start character */ + + u8 ch_mostat; /* FEP output modem status */ + u8 ch_mistat; /* FEP input modem status */ + + struct neo_uart_struct __iomem *ch_neo_uart; /* Pointer to the "mapped" UART struct */ + u8 ch_cached_lsr; /* Cached value of the LSR register */ + + u8 *ch_rqueue; /* Our read queue buffer - malloc'ed */ + u16 ch_r_head; /* Head location of the read queue */ + u16 ch_r_tail; /* Tail location of the read queue */ + + u8 *ch_equeue; /* Our error queue buffer - malloc'ed */ + u16 ch_e_head; /* Head location of the error queue */ + u16 ch_e_tail; /* Tail location of the error queue */ + + u8 *ch_wqueue; /* Our write queue buffer - malloc'ed */ + u16 ch_w_head; /* Head location of the write queue */ + u16 ch_w_tail; /* Tail location of the write queue */ + + u64 ch_rxcount; /* total of data received so far */ + u64 ch_txcount; /* total of data transmitted so far */ + + u8 ch_r_tlevel; /* Receive Trigger level */ + u8 ch_t_tlevel; /* Transmit Trigger level */ + + u8 ch_r_watermark; /* Receive Watermark */ + + + u32 ch_stops_sent; /* How many times I have sent a stop character + * to try to stop the other guy sending. + */ + u64 ch_err_parity; /* Count of parity errors on channel */ + u64 ch_err_frame; /* Count of framing errors on channel */ + u64 ch_err_break; /* Count of breaks on channel */ + u64 ch_err_overrun; /* Count of overruns on channel */ + + u64 ch_xon_sends; /* Count of xons transmitted */ + u64 ch_xoff_sends; /* Count of xoffs transmitted */ +}; + + +/************************************************************************ + * Per channel/port NEO UART structure * + ************************************************************************ + * Base Structure Entries Usage Meanings to Host * + * * + * W = read write R = read only * + * U = Unused. * + ************************************************************************/ + +struct neo_uart_struct { + u8 txrx; /* WR RHR/THR - Holding Reg */ + u8 ier; /* WR IER - Interrupt Enable Reg */ + u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg */ + u8 lcr; /* WR LCR - Line Control Reg */ + u8 mcr; /* WR MCR - Modem Control Reg */ + u8 lsr; /* WR LSR - Line Status Reg */ + u8 msr; /* WR MSR - Modem Status Reg */ + u8 spr; /* WR SPR - Scratch Pad Reg */ + u8 fctr; /* WR FCTR - Feature Control Reg */ + u8 efr; /* WR EFR - Enhanced Function Reg */ + u8 tfifo; /* WR TXCNT/TXTRG - Transmit FIFO Reg */ + u8 rfifo; /* WR RXCNT/RXTRG - Recieve FIFO Reg */ + u8 xoffchar1; /* WR XOFF 1 - XOff Character 1 Reg */ + u8 xoffchar2; /* WR XOFF 2 - XOff Character 2 Reg */ + u8 xonchar1; /* WR XON 1 - Xon Character 1 Reg */ + u8 xonchar2; /* WR XON 2 - XOn Character 2 Reg */ + + u8 reserved1[0x2ff - 0x200]; /* U Reserved by Exar */ + u8 txrxburst[64]; /* RW 64 bytes of RX/TX FIFO Data */ + u8 reserved2[0x37f - 0x340]; /* U Reserved by Exar */ + u8 rxburst_with_errors[64]; /* R 64 bytes of RX FIFO Data + LSR */ +}; + +/* Where to read the extended interrupt register (32bits instead of 8bits) */ +#define UART_17158_POLL_ADDR_OFFSET 0x80 + +/* + * These are the redefinitions for the FCTR on the XR17C158, since + * Exar made them different than their earlier design. (XR16C854) + */ + +/* These are only applicable when table D is selected */ +#define UART_17158_FCTR_RTS_NODELAY 0x00 +#define UART_17158_FCTR_RTS_4DELAY 0x01 +#define UART_17158_FCTR_RTS_6DELAY 0x02 +#define UART_17158_FCTR_RTS_8DELAY 0x03 +#define UART_17158_FCTR_RTS_12DELAY 0x12 +#define UART_17158_FCTR_RTS_16DELAY 0x05 +#define UART_17158_FCTR_RTS_20DELAY 0x13 +#define UART_17158_FCTR_RTS_24DELAY 0x06 +#define UART_17158_FCTR_RTS_28DELAY 0x14 +#define UART_17158_FCTR_RTS_32DELAY 0x07 +#define UART_17158_FCTR_RTS_36DELAY 0x16 +#define UART_17158_FCTR_RTS_40DELAY 0x08 +#define UART_17158_FCTR_RTS_44DELAY 0x09 +#define UART_17158_FCTR_RTS_48DELAY 0x10 +#define UART_17158_FCTR_RTS_52DELAY 0x11 + +#define UART_17158_FCTR_RTS_IRDA 0x10 +#define UART_17158_FCTR_RS485 0x20 +#define UART_17158_FCTR_TRGA 0x00 +#define UART_17158_FCTR_TRGB 0x40 +#define UART_17158_FCTR_TRGC 0x80 +#define UART_17158_FCTR_TRGD 0xC0 + +/* 17158 trigger table selects.. */ +#define UART_17158_FCTR_BIT6 0x40 +#define UART_17158_FCTR_BIT7 0x80 + +/* 17158 TX/RX memmapped buffer offsets */ +#define UART_17158_RX_FIFOSIZE 64 +#define UART_17158_TX_FIFOSIZE 64 + +/* 17158 Extended IIR's */ +#define UART_17158_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */ +#define UART_17158_IIR_XONXOFF 0x10 /* Received an XON/XOFF char */ +#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20 /* CTS/DSR or RTS/DTR state change */ +#define UART_17158_IIR_FIFO_ENABLED 0xC0 /* 16550 FIFOs are Enabled */ + +/* + * These are the extended interrupts that get sent + * back to us from the UART's 32bit interrupt register + */ +#define UART_17158_RX_LINE_STATUS 0x1 /* RX Ready */ +#define UART_17158_RXRDY_TIMEOUT 0x2 /* RX Ready Timeout */ +#define UART_17158_TXRDY 0x3 /* TX Ready */ +#define UART_17158_MSR 0x4 /* Modem State Change */ +#define UART_17158_TX_AND_FIFO_CLR 0x40 /* Transmitter Holding Reg Empty */ +#define UART_17158_RX_FIFO_DATA_ERROR 0x80 /* UART detected an RX FIFO Data error */ + +/* + * These are the EXTENDED definitions for the 17C158's Interrupt + * Enable Register. + */ +#define UART_17158_EFR_ECB 0x10 /* Enhanced control bit */ +#define UART_17158_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */ +#define UART_17158_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */ +#define UART_17158_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */ +#define UART_17158_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */ + +#define UART_17158_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */ +#define UART_17158_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */ + +#define UART_17158_IER_RSVD1 0x10 /* Reserved by Exar */ +#define UART_17158_IER_XOFF 0x20 /* Xoff Interrupt Enable */ +#define UART_17158_IER_RTSDTR 0x40 /* Output Interrupt Enable */ +#define UART_17158_IER_CTSDSR 0x80 /* Input Interrupt Enable */ + +#define PCI_DEVICE_NEO_2DB9_PCI_NAME "Neo 2 - DB9 Universal PCI" +#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator" +#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI" +#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator" +#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM" + +/* + * Our Global Variables. + */ +extern struct uart_driver jsm_uart_driver; +extern struct board_ops jsm_neo_ops; +extern int jsm_debug; + +/************************************************************************* + * + * Prototypes for non-static functions used in more than one module + * + *************************************************************************/ +int jsm_tty_write(struct uart_port *port); +int jsm_tty_init(struct jsm_board *); +int jsm_uart_port_init(struct jsm_board *); +int jsm_remove_uart_port(struct jsm_board *); +void jsm_input(struct jsm_channel *ch); +void jsm_check_queue_flow_control(struct jsm_channel *ch); + +#endif diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c new file mode 100644 index 000000000000..18f548449c63 --- /dev/null +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -0,0 +1,297 @@ +/************************************************************************ + * Copyright 2003 Digi International (www.digi.com) + * + * Copyright (C) 2004 IBM Corporation. All rights reserved. + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. + * + * Contact Information: + * Scott H Kilau + * Wendy Xiong + * + * + ***********************************************************************/ +#include +#include +#include + +#include "jsm.h" + +MODULE_AUTHOR("Digi International, http://www.digi.com"); +MODULE_DESCRIPTION("Driver for the Digi International " + "Neo PCI based product line"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("jsm"); + +#define JSM_DRIVER_NAME "jsm" +#define NR_PORTS 32 +#define JSM_MINOR_START 0 + +struct uart_driver jsm_uart_driver = { + .owner = THIS_MODULE, + .driver_name = JSM_DRIVER_NAME, + .dev_name = "ttyn", + .major = 0, + .minor = JSM_MINOR_START, + .nr = NR_PORTS, +}; + +static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state); +static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev); +static void jsm_io_resume(struct pci_dev *pdev); + +static struct pci_error_handlers jsm_err_handler = { + .error_detected = jsm_io_error_detected, + .slot_reset = jsm_io_slot_reset, + .resume = jsm_io_resume, +}; + +int jsm_debug; +module_param(jsm_debug, int, 0); +MODULE_PARM_DESC(jsm_debug, "Driver debugging level"); + +static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc = 0; + struct jsm_board *brd; + static int adapter_count = 0; + + rc = pci_enable_device(pdev); + if (rc) { + dev_err(&pdev->dev, "Device enable FAILED\n"); + goto out; + } + + rc = pci_request_regions(pdev, "jsm"); + if (rc) { + dev_err(&pdev->dev, "pci_request_region FAILED\n"); + goto out_disable_device; + } + + brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL); + if (!brd) { + dev_err(&pdev->dev, + "memory allocation for board structure failed\n"); + rc = -ENOMEM; + goto out_release_regions; + } + + /* store the info for the board we've found */ + brd->boardnum = adapter_count++; + brd->pci_dev = pdev; + if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM) + brd->maxports = 4; + else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8) + brd->maxports = 8; + else + brd->maxports = 2; + + spin_lock_init(&brd->bd_intr_lock); + + /* store which revision we have */ + brd->rev = pdev->revision; + + brd->irq = pdev->irq; + + jsm_printk(INIT, INFO, &brd->pci_dev, + "jsm_found_board - NEO adapter\n"); + + /* get the PCI Base Address Registers */ + brd->membase = pci_resource_start(pdev, 0); + brd->membase_end = pci_resource_end(pdev, 0); + + if (brd->membase & 1) + brd->membase &= ~3; + else + brd->membase &= ~15; + + /* Assign the board_ops struct */ + brd->bd_ops = &jsm_neo_ops; + + brd->bd_uart_offset = 0x200; + brd->bd_dividend = 921600; + + brd->re_map_membase = ioremap(brd->membase, 0x1000); + if (!brd->re_map_membase) { + dev_err(&pdev->dev, + "card has no PCI Memory resources, " + "failing board.\n"); + rc = -ENOMEM; + goto out_kfree_brd; + } + + rc = request_irq(brd->irq, brd->bd_ops->intr, + IRQF_SHARED, "JSM", brd); + if (rc) { + printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq); + goto out_iounmap; + } + + rc = jsm_tty_init(brd); + if (rc < 0) { + dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc); + rc = -ENXIO; + goto out_free_irq; + } + + rc = jsm_uart_port_init(brd); + if (rc < 0) { + /* XXX: leaking all resources from jsm_tty_init here! */ + dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc); + rc = -ENXIO; + goto out_free_irq; + } + + /* Log the information about the board */ + dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n", + adapter_count, brd->rev, brd->irq); + + /* + * allocate flip buffer for board. + * + * Okay to malloc with GFP_KERNEL, we are not at interrupt + * context, and there are no locks held. + */ + brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); + if (!brd->flipbuf) { + /* XXX: leaking all resources from jsm_tty_init and + jsm_uart_port_init here! */ + dev_err(&pdev->dev, "memory allocation for flipbuf failed\n"); + rc = -ENOMEM; + goto out_free_uart; + } + + pci_set_drvdata(pdev, brd); + pci_save_state(pdev); + + return 0; + out_free_uart: + jsm_remove_uart_port(brd); + out_free_irq: + jsm_remove_uart_port(brd); + free_irq(brd->irq, brd); + out_iounmap: + iounmap(brd->re_map_membase); + out_kfree_brd: + kfree(brd); + out_release_regions: + pci_release_regions(pdev); + out_disable_device: + pci_disable_device(pdev); + out: + return rc; +} + +static void __devexit jsm_remove_one(struct pci_dev *pdev) +{ + struct jsm_board *brd = pci_get_drvdata(pdev); + int i = 0; + + jsm_remove_uart_port(brd); + + free_irq(brd->irq, brd); + iounmap(brd->re_map_membase); + + /* Free all allocated channels structs */ + for (i = 0; i < brd->maxports; i++) { + if (brd->channels[i]) { + kfree(brd->channels[i]->ch_rqueue); + kfree(brd->channels[i]->ch_equeue); + kfree(brd->channels[i]->ch_wqueue); + kfree(brd->channels[i]); + } + } + + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(brd->flipbuf); + kfree(brd); +} + +static struct pci_device_id jsm_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 }, + { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, jsm_pci_tbl); + +static struct pci_driver jsm_driver = { + .name = "jsm", + .id_table = jsm_pci_tbl, + .probe = jsm_probe_one, + .remove = __devexit_p(jsm_remove_one), + .err_handler = &jsm_err_handler, +}; + +static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct jsm_board *brd = pci_get_drvdata(pdev); + + jsm_remove_uart_port(brd); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev) +{ + int rc; + + rc = pci_enable_device(pdev); + + if (rc) + return PCI_ERS_RESULT_DISCONNECT; + + pci_set_master(pdev); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void jsm_io_resume(struct pci_dev *pdev) +{ + struct jsm_board *brd = pci_get_drvdata(pdev); + + pci_restore_state(pdev); + + jsm_uart_port_init(brd); +} + +static int __init jsm_init_module(void) +{ + int rc; + + rc = uart_register_driver(&jsm_uart_driver); + if (!rc) { + rc = pci_register_driver(&jsm_driver); + if (rc) + uart_unregister_driver(&jsm_uart_driver); + } + return rc; +} + +static void __exit jsm_exit_module(void) +{ + pci_unregister_driver(&jsm_driver); + uart_unregister_driver(&jsm_uart_driver); +} + +module_init(jsm_init_module); +module_exit(jsm_exit_module); diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c new file mode 100644 index 000000000000..7960d9633c15 --- /dev/null +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -0,0 +1,1412 @@ +/************************************************************************ + * Copyright 2003 Digi International (www.digi.com) + * + * Copyright (C) 2004 IBM Corporation. All rights reserved. + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. + * + * Contact Information: + * Scott H Kilau + * Wendy Xiong + * + ***********************************************************************/ +#include /* For udelay */ +#include /* For the various UART offsets */ +#include +#include +#include + +#include "jsm.h" /* Driver main header file */ + +static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + +/* + * This function allows calls to ensure that all outstanding + * PCI writes have been completed, by doing a PCI read against + * a non-destructive, read-only location on the Neo card. + * + * In this case, we are reading the DVID (Read-only Device Identification) + * value of the Neo card. + */ +static inline void neo_pci_posting_flush(struct jsm_board *bd) +{ + readb(bd->re_map_membase + 0x8D); +} + +static void neo_set_cts_flow_control(struct jsm_channel *ch) +{ + u8 ier, efr; + ier = readb(&ch->ch_neo_uart->ier); + efr = readb(&ch->ch_neo_uart->efr); + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n"); + + /* Turn on auto CTS flow control */ + ier |= (UART_17158_IER_CTSDSR); + efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR); + + /* Turn off auto Xon flow control */ + efr &= ~(UART_17158_EFR_IXON); + + /* Why? Becuz Exar's spec says we have to zero it out before setting it */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Turn on UART enhanced bits */ + writeb(efr, &ch->ch_neo_uart->efr); + + /* Turn on table D, with 8 char hi/low watermarks */ + writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); + + /* Feed the UART our trigger levels */ + writeb(8, &ch->ch_neo_uart->tfifo); + ch->ch_t_tlevel = 8; + + writeb(ier, &ch->ch_neo_uart->ier); +} + +static void neo_set_rts_flow_control(struct jsm_channel *ch) +{ + u8 ier, efr; + ier = readb(&ch->ch_neo_uart->ier); + efr = readb(&ch->ch_neo_uart->efr); + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n"); + + /* Turn on auto RTS flow control */ + ier |= (UART_17158_IER_RTSDTR); + efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR); + + /* Turn off auto Xoff flow control */ + ier &= ~(UART_17158_IER_XOFF); + efr &= ~(UART_17158_EFR_IXOFF); + + /* Why? Becuz Exar's spec says we have to zero it out before setting it */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Turn on UART enhanced bits */ + writeb(efr, &ch->ch_neo_uart->efr); + + writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); + ch->ch_r_watermark = 4; + + writeb(56, &ch->ch_neo_uart->rfifo); + ch->ch_r_tlevel = 56; + + writeb(ier, &ch->ch_neo_uart->ier); + + /* + * From the Neo UART spec sheet: + * The auto RTS/DTR function must be started by asserting + * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after + * it is enabled. + */ + ch->ch_mostat |= (UART_MCR_RTS); +} + + +static void neo_set_ixon_flow_control(struct jsm_channel *ch) +{ + u8 ier, efr; + ier = readb(&ch->ch_neo_uart->ier); + efr = readb(&ch->ch_neo_uart->efr); + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n"); + + /* Turn off auto CTS flow control */ + ier &= ~(UART_17158_IER_CTSDSR); + efr &= ~(UART_17158_EFR_CTSDSR); + + /* Turn on auto Xon flow control */ + efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON); + + /* Why? Becuz Exar's spec says we have to zero it out before setting it */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Turn on UART enhanced bits */ + writeb(efr, &ch->ch_neo_uart->efr); + + writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); + ch->ch_r_watermark = 4; + + writeb(32, &ch->ch_neo_uart->rfifo); + ch->ch_r_tlevel = 32; + + /* Tell UART what start/stop chars it should be looking for */ + writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); + writeb(0, &ch->ch_neo_uart->xonchar2); + + writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); + writeb(0, &ch->ch_neo_uart->xoffchar2); + + writeb(ier, &ch->ch_neo_uart->ier); +} + +static void neo_set_ixoff_flow_control(struct jsm_channel *ch) +{ + u8 ier, efr; + ier = readb(&ch->ch_neo_uart->ier); + efr = readb(&ch->ch_neo_uart->efr); + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n"); + + /* Turn off auto RTS flow control */ + ier &= ~(UART_17158_IER_RTSDTR); + efr &= ~(UART_17158_EFR_RTSDTR); + + /* Turn on auto Xoff flow control */ + ier |= (UART_17158_IER_XOFF); + efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); + + /* Why? Becuz Exar's spec says we have to zero it out before setting it */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Turn on UART enhanced bits */ + writeb(efr, &ch->ch_neo_uart->efr); + + /* Turn on table D, with 8 char hi/low watermarks */ + writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); + + writeb(8, &ch->ch_neo_uart->tfifo); + ch->ch_t_tlevel = 8; + + /* Tell UART what start/stop chars it should be looking for */ + writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); + writeb(0, &ch->ch_neo_uart->xonchar2); + + writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); + writeb(0, &ch->ch_neo_uart->xoffchar2); + + writeb(ier, &ch->ch_neo_uart->ier); +} + +static void neo_set_no_input_flow_control(struct jsm_channel *ch) +{ + u8 ier, efr; + ier = readb(&ch->ch_neo_uart->ier); + efr = readb(&ch->ch_neo_uart->efr); + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n"); + + /* Turn off auto RTS flow control */ + ier &= ~(UART_17158_IER_RTSDTR); + efr &= ~(UART_17158_EFR_RTSDTR); + + /* Turn off auto Xoff flow control */ + ier &= ~(UART_17158_IER_XOFF); + if (ch->ch_c_iflag & IXON) + efr &= ~(UART_17158_EFR_IXOFF); + else + efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); + + /* Why? Becuz Exar's spec says we have to zero it out before setting it */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Turn on UART enhanced bits */ + writeb(efr, &ch->ch_neo_uart->efr); + + /* Turn on table D, with 8 char hi/low watermarks */ + writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); + + ch->ch_r_watermark = 0; + + writeb(16, &ch->ch_neo_uart->tfifo); + ch->ch_t_tlevel = 16; + + writeb(16, &ch->ch_neo_uart->rfifo); + ch->ch_r_tlevel = 16; + + writeb(ier, &ch->ch_neo_uart->ier); +} + +static void neo_set_no_output_flow_control(struct jsm_channel *ch) +{ + u8 ier, efr; + ier = readb(&ch->ch_neo_uart->ier); + efr = readb(&ch->ch_neo_uart->efr); + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n"); + + /* Turn off auto CTS flow control */ + ier &= ~(UART_17158_IER_CTSDSR); + efr &= ~(UART_17158_EFR_CTSDSR); + + /* Turn off auto Xon flow control */ + if (ch->ch_c_iflag & IXOFF) + efr &= ~(UART_17158_EFR_IXON); + else + efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON); + + /* Why? Becuz Exar's spec says we have to zero it out before setting it */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Turn on UART enhanced bits */ + writeb(efr, &ch->ch_neo_uart->efr); + + /* Turn on table D, with 8 char hi/low watermarks */ + writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); + + ch->ch_r_watermark = 0; + + writeb(16, &ch->ch_neo_uart->tfifo); + ch->ch_t_tlevel = 16; + + writeb(16, &ch->ch_neo_uart->rfifo); + ch->ch_r_tlevel = 16; + + writeb(ier, &ch->ch_neo_uart->ier); +} + +static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch) +{ + + /* if hardware flow control is set, then skip this whole thing */ + if (ch->ch_c_cflag & CRTSCTS) + return; + + jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n"); + + /* Tell UART what start/stop chars it should be looking for */ + writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); + writeb(0, &ch->ch_neo_uart->xonchar2); + + writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); + writeb(0, &ch->ch_neo_uart->xoffchar2); +} + +static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) +{ + int qleft = 0; + u8 linestatus = 0; + u8 error_mask = 0; + int n = 0; + int total = 0; + u16 head; + u16 tail; + + if (!ch) + return; + + /* cache head and tail of queue */ + head = ch->ch_r_head & RQUEUEMASK; + tail = ch->ch_r_tail & RQUEUEMASK; + + /* Get our cached LSR */ + linestatus = ch->ch_cached_lsr; + ch->ch_cached_lsr = 0; + + /* Store how much space we have left in the queue */ + if ((qleft = tail - head - 1) < 0) + qleft += RQUEUEMASK + 1; + + /* + * If the UART is not in FIFO mode, force the FIFO copy to + * NOT be run, by setting total to 0. + * + * On the other hand, if the UART IS in FIFO mode, then ask + * the UART to give us an approximation of data it has RX'ed. + */ + if (!(ch->ch_flags & CH_FIFO_ENABLED)) + total = 0; + else { + total = readb(&ch->ch_neo_uart->rfifo); + + /* + * EXAR chip bug - RX FIFO COUNT - Fudge factor. + * + * This resolves a problem/bug with the Exar chip that sometimes + * returns a bogus value in the rfifo register. + * The count can be any where from 0-3 bytes "off". + * Bizarre, but true. + */ + total -= 3; + } + + /* + * Finally, bound the copy to make sure we don't overflow + * our own queue... + * The byte by byte copy loop below this loop this will + * deal with the queue overflow possibility. + */ + total = min(total, qleft); + + while (total > 0) { + /* + * Grab the linestatus register, we need to check + * to see if there are any errors in the FIFO. + */ + linestatus = readb(&ch->ch_neo_uart->lsr); + + /* + * Break out if there is a FIFO error somewhere. + * This will allow us to go byte by byte down below, + * finding the exact location of the error. + */ + if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) + break; + + /* Make sure we don't go over the end of our queue */ + n = min(((u32) total), (RQUEUESIZE - (u32) head)); + + /* + * Cut down n even further if needed, this is to fix + * a problem with memcpy_fromio() with the Neo on the + * IBM pSeries platform. + * 15 bytes max appears to be the magic number. + */ + n = min((u32) n, (u32) 12); + + /* + * Since we are grabbing the linestatus register, which + * will reset some bits after our read, we need to ensure + * we don't miss our TX FIFO emptys. + */ + if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + + linestatus = 0; + + /* Copy data from uart to the queue */ + memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n); + /* + * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed + * that all the data currently in the FIFO is free of + * breaks and parity/frame/orun errors. + */ + memset(ch->ch_equeue + head, 0, n); + + /* Add to and flip head if needed */ + head = (head + n) & RQUEUEMASK; + total -= n; + qleft -= n; + ch->ch_rxcount += n; + } + + /* + * Create a mask to determine whether we should + * insert the character (if any) into our queue. + */ + if (ch->ch_c_iflag & IGNBRK) + error_mask |= UART_LSR_BI; + + /* + * Now cleanup any leftover bytes still in the UART. + * Also deal with any possible queue overflow here as well. + */ + while (1) { + + /* + * Its possible we have a linestatus from the loop above + * this, so we "OR" on any extra bits. + */ + linestatus |= readb(&ch->ch_neo_uart->lsr); + + /* + * If the chip tells us there is no more data pending to + * be read, we can then leave. + * But before we do, cache the linestatus, just in case. + */ + if (!(linestatus & UART_LSR_DR)) { + ch->ch_cached_lsr = linestatus; + break; + } + + /* No need to store this bit */ + linestatus &= ~UART_LSR_DR; + + /* + * Since we are grabbing the linestatus register, which + * will reset some bits after our read, we need to ensure + * we don't miss our TX FIFO emptys. + */ + if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) { + linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR); + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + } + + /* + * Discard character if we are ignoring the error mask. + */ + if (linestatus & error_mask) { + u8 discard; + linestatus = 0; + memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1); + continue; + } + + /* + * If our queue is full, we have no choice but to drop some data. + * The assumption is that HWFLOW or SWFLOW should have stopped + * things way way before we got to this point. + * + * I decided that I wanted to ditch the oldest data first, + * I hope thats okay with everyone? Yes? Good. + */ + while (qleft < 1) { + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + "Queue full, dropping DATA:%x LSR:%x\n", + ch->ch_rqueue[tail], ch->ch_equeue[tail]); + + ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK; + ch->ch_err_overrun++; + qleft++; + } + + memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1); + ch->ch_equeue[head] = (u8) linestatus; + + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]); + + /* Ditch any remaining linestatus value. */ + linestatus = 0; + + /* Add to and flip head if needed */ + head = (head + 1) & RQUEUEMASK; + + qleft--; + ch->ch_rxcount++; + } + + /* + * Write new final heads to channel structure. + */ + ch->ch_r_head = head & RQUEUEMASK; + ch->ch_e_head = head & EQUEUEMASK; + jsm_input(ch); +} + +static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) +{ + u16 head; + u16 tail; + int n; + int s; + int qlen; + u32 len_written = 0; + + if (!ch) + return; + + /* No data to write to the UART */ + if (ch->ch_w_tail == ch->ch_w_head) + return; + + /* If port is "stopped", don't send any data to the UART */ + if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) + return; + /* + * If FIFOs are disabled. Send data directly to txrx register + */ + if (!(ch->ch_flags & CH_FIFO_ENABLED)) { + u8 lsrbits = readb(&ch->ch_neo_uart->lsr); + + ch->ch_cached_lsr |= lsrbits; + if (ch->ch_cached_lsr & UART_LSR_THRE) { + ch->ch_cached_lsr &= ~(UART_LSR_THRE); + + writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx); + jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev, + "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]); + ch->ch_w_tail++; + ch->ch_w_tail &= WQUEUEMASK; + ch->ch_txcount++; + } + return; + } + + /* + * We have to do it this way, because of the EXAR TXFIFO count bug. + */ + if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) + return; + + n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; + + /* cache head and tail of queue */ + head = ch->ch_w_head & WQUEUEMASK; + tail = ch->ch_w_tail & WQUEUEMASK; + qlen = (head - tail) & WQUEUEMASK; + + /* Find minimum of the FIFO space, versus queue length */ + n = min(n, qlen); + + while (n > 0) { + + s = ((head >= tail) ? head : WQUEUESIZE) - tail; + s = min(s, n); + + if (s <= 0) + break; + + memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s); + /* Add and flip queue if needed */ + tail = (tail + s) & WQUEUEMASK; + n -= s; + ch->ch_txcount += s; + len_written += s; + } + + /* Update the final tail */ + ch->ch_w_tail = tail & WQUEUEMASK; + + if (len_written >= ch->ch_t_tlevel) + ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + + if (!jsm_tty_write(&ch->uart_port)) + uart_write_wakeup(&ch->uart_port); +} + +static void neo_parse_modem(struct jsm_channel *ch, u8 signals) +{ + u8 msignals = signals; + + jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, + "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals); + + /* Scrub off lower bits. They signify delta's, which I don't care about */ + /* Keep DDCD and DDSR though */ + msignals &= 0xf8; + + if (msignals & UART_MSR_DDCD) + uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD); + if (msignals & UART_MSR_DDSR) + uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS); + if (msignals & UART_MSR_DCD) + ch->ch_mistat |= UART_MSR_DCD; + else + ch->ch_mistat &= ~UART_MSR_DCD; + + if (msignals & UART_MSR_DSR) + ch->ch_mistat |= UART_MSR_DSR; + else + ch->ch_mistat &= ~UART_MSR_DSR; + + if (msignals & UART_MSR_RI) + ch->ch_mistat |= UART_MSR_RI; + else + ch->ch_mistat &= ~UART_MSR_RI; + + if (msignals & UART_MSR_CTS) + ch->ch_mistat |= UART_MSR_CTS; + else + ch->ch_mistat &= ~UART_MSR_CTS; + + jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, + "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n", + ch->ch_portnum, + !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI), + !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)); +} + +/* Make the UART raise any of the output signals we want up */ +static void neo_assert_modem_signals(struct jsm_channel *ch) +{ + if (!ch) + return; + + writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); +} + +/* + * Flush the WRITE FIFO on the Neo. + * + * NOTE: Channel lock MUST be held before calling this function! + */ +static void neo_flush_uart_write(struct jsm_channel *ch) +{ + u8 tmp = 0; + int i = 0; + + if (!ch) + return; + + writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); + + for (i = 0; i < 10; i++) { + + /* Check to see if the UART feels it completely flushed the FIFO. */ + tmp = readb(&ch->ch_neo_uart->isr_fcr); + if (tmp & 4) { + jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, + "Still flushing TX UART... i: %d\n", i); + udelay(10); + } + else + break; + } + + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); +} + + +/* + * Flush the READ FIFO on the Neo. + * + * NOTE: Channel lock MUST be held before calling this function! + */ +static void neo_flush_uart_read(struct jsm_channel *ch) +{ + u8 tmp = 0; + int i = 0; + + if (!ch) + return; + + writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr); + + for (i = 0; i < 10; i++) { + + /* Check to see if the UART feels it completely flushed the FIFO. */ + tmp = readb(&ch->ch_neo_uart->isr_fcr); + if (tmp & 2) { + jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, + "Still flushing RX UART... i: %d\n", i); + udelay(10); + } + else + break; + } +} + +/* + * No locks are assumed to be held when calling this function. + */ +static void neo_clear_break(struct jsm_channel *ch, int force) +{ + unsigned long lock_flags; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + /* Turn break off, and unset some variables */ + if (ch->ch_flags & CH_BREAK_SENDING) { + u8 temp = readb(&ch->ch_neo_uart->lcr); + writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr); + + ch->ch_flags &= ~(CH_BREAK_SENDING); + jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, + "clear break Finishing UART_LCR_SBC! finished: %lx\n", jiffies); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); + } + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); +} + +/* + * Parse the ISR register. + */ +static inline void neo_parse_isr(struct jsm_board *brd, u32 port) +{ + struct jsm_channel *ch; + u8 isr; + u8 cause; + unsigned long lock_flags; + + if (!brd) + return; + + if (port > brd->maxports) + return; + + ch = brd->channels[port]; + if (!ch) + return; + + /* Here we try to figure out what caused the interrupt to happen */ + while (1) { + + isr = readb(&ch->ch_neo_uart->isr_fcr); + + /* Bail if no pending interrupt */ + if (isr & UART_IIR_NO_INT) + break; + + /* + * Yank off the upper 2 bits, which just show that the FIFO's are enabled. + */ + isr &= ~(UART_17158_IIR_FIFO_ENABLED); + + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "%s:%d isr: %x\n", __FILE__, __LINE__, isr); + + if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) { + /* Read data from uart -> queue */ + neo_copy_data_from_uart_to_queue(ch); + + /* Call our tty layer to enforce queue flow control if needed. */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + jsm_check_queue_flow_control(ch); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + } + + if (isr & UART_IIR_THRI) { + /* Transfer data (if any) from Write Queue -> UART. */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + neo_copy_data_from_queue_to_uart(ch); + } + + if (isr & UART_17158_IIR_XONXOFF) { + cause = readb(&ch->ch_neo_uart->xoffchar1); + + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause); + + /* + * Since the UART detected either an XON or + * XOFF match, we need to figure out which + * one it was, so we can suspend or resume data flow. + */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + if (cause == UART_17158_XON_DETECT) { + /* Is output stopped right now, if so, resume it */ + if (brd->channels[port]->ch_flags & CH_STOP) { + ch->ch_flags &= ~(CH_STOP); + } + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "Port %d. XON detected in incoming data\n", port); + } + else if (cause == UART_17158_XOFF_DETECT) { + if (!(brd->channels[port]->ch_flags & CH_STOP)) { + ch->ch_flags |= CH_STOP; + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "Setting CH_STOP\n"); + } + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "Port: %d. XOFF detected in incoming data\n", port); + } + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + } + + if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) { + /* + * If we get here, this means the hardware is doing auto flow control. + * Check to see whether RTS/DTR or CTS/DSR caused this interrupt. + */ + cause = readb(&ch->ch_neo_uart->mcr); + + /* Which pin is doing auto flow? RTS or DTR? */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + if ((cause & 0x4) == 0) { + if (cause & UART_MCR_RTS) + ch->ch_mostat |= UART_MCR_RTS; + else + ch->ch_mostat &= ~(UART_MCR_RTS); + } else { + if (cause & UART_MCR_DTR) + ch->ch_mostat |= UART_MCR_DTR; + else + ch->ch_mostat &= ~(UART_MCR_DTR); + } + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + } + + /* Parse any modem signal changes */ + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "MOD_STAT: sending to parse_modem_sigs\n"); + neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); + } +} + +static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) +{ + struct jsm_channel *ch; + int linestatus; + unsigned long lock_flags; + + if (!brd) + return; + + if (port > brd->maxports) + return; + + ch = brd->channels[port]; + if (!ch) + return; + + linestatus = readb(&ch->ch_neo_uart->lsr); + + jsm_printk(INTR, INFO, &ch->ch_bd->pci_dev, + "%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus); + + ch->ch_cached_lsr |= linestatus; + + if (ch->ch_cached_lsr & UART_LSR_DR) { + /* Read data from uart -> queue */ + neo_copy_data_from_uart_to_queue(ch); + spin_lock_irqsave(&ch->ch_lock, lock_flags); + jsm_check_queue_flow_control(ch); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + } + + /* + * This is a special flag. It indicates that at least 1 + * RX error (parity, framing, or break) has happened. + * Mark this in our struct, which will tell me that I have + *to do the special RX+LSR read for this FIFO load. + */ + if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) + jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, + "%s:%d Port: %d Got an RX error, need to parse LSR\n", + __FILE__, __LINE__, port); + + /* + * The next 3 tests should *NOT* happen, as the above test + * should encapsulate all 3... At least, thats what Exar says. + */ + + if (linestatus & UART_LSR_PE) { + ch->ch_err_parity++; + jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, + "%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port); + } + + if (linestatus & UART_LSR_FE) { + ch->ch_err_frame++; + jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, + "%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port); + } + + if (linestatus & UART_LSR_BI) { + ch->ch_err_break++; + jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, + "%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port); + } + + if (linestatus & UART_LSR_OE) { + /* + * Rx Oruns. Exar says that an orun will NOT corrupt + * the FIFO. It will just replace the holding register + * with this new data byte. So basically just ignore this. + * Probably we should eventually have an orun stat in our driver... + */ + ch->ch_err_overrun++; + jsm_printk(INTR, DEBUG, &ch->ch_bd->pci_dev, + "%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port); + } + + if (linestatus & UART_LSR_THRE) { + spin_lock_irqsave(&ch->ch_lock, lock_flags); + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + /* Transfer data (if any) from Write Queue -> UART. */ + neo_copy_data_from_queue_to_uart(ch); + } + else if (linestatus & UART_17158_TX_AND_FIFO_CLR) { + spin_lock_irqsave(&ch->ch_lock, lock_flags); + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + /* Transfer data (if any) from Write Queue -> UART. */ + neo_copy_data_from_queue_to_uart(ch); + } +} + +/* + * neo_param() + * Send any/all changes to the line to the UART. + */ +static void neo_param(struct jsm_channel *ch) +{ + u8 lcr = 0; + u8 uart_lcr, ier; + u32 baud; + int quot; + struct jsm_board *bd; + + bd = ch->ch_bd; + if (!bd) + return; + + /* + * If baud rate is zero, flush queues, and set mval to drop DTR. + */ + if ((ch->ch_c_cflag & (CBAUD)) == 0) { + ch->ch_r_head = ch->ch_r_tail = 0; + ch->ch_e_head = ch->ch_e_tail = 0; + ch->ch_w_head = ch->ch_w_tail = 0; + + neo_flush_uart_write(ch); + neo_flush_uart_read(ch); + + ch->ch_flags |= (CH_BAUD0); + ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR); + neo_assert_modem_signals(ch); + return; + + } else { + int i; + unsigned int cflag; + static struct { + unsigned int rate; + unsigned int cflag; + } baud_rates[] = { + { 921600, B921600 }, + { 460800, B460800 }, + { 230400, B230400 }, + { 115200, B115200 }, + { 57600, B57600 }, + { 38400, B38400 }, + { 19200, B19200 }, + { 9600, B9600 }, + { 4800, B4800 }, + { 2400, B2400 }, + { 1200, B1200 }, + { 600, B600 }, + { 300, B300 }, + { 200, B200 }, + { 150, B150 }, + { 134, B134 }, + { 110, B110 }, + { 75, B75 }, + { 50, B50 }, + }; + + cflag = C_BAUD(ch->uart_port.state->port.tty); + baud = 9600; + for (i = 0; i < ARRAY_SIZE(baud_rates); i++) { + if (baud_rates[i].cflag == cflag) { + baud = baud_rates[i].rate; + break; + } + } + + if (ch->ch_flags & CH_BAUD0) + ch->ch_flags &= ~(CH_BAUD0); + } + + if (ch->ch_c_cflag & PARENB) + lcr |= UART_LCR_PARITY; + + if (!(ch->ch_c_cflag & PARODD)) + lcr |= UART_LCR_EPAR; + + /* + * Not all platforms support mark/space parity, + * so this will hide behind an ifdef. + */ +#ifdef CMSPAR + if (ch->ch_c_cflag & CMSPAR) + lcr |= UART_LCR_SPAR; +#endif + + if (ch->ch_c_cflag & CSTOPB) + lcr |= UART_LCR_STOP; + + switch (ch->ch_c_cflag & CSIZE) { + case CS5: + lcr |= UART_LCR_WLEN5; + break; + case CS6: + lcr |= UART_LCR_WLEN6; + break; + case CS7: + lcr |= UART_LCR_WLEN7; + break; + case CS8: + default: + lcr |= UART_LCR_WLEN8; + break; + } + + ier = readb(&ch->ch_neo_uart->ier); + uart_lcr = readb(&ch->ch_neo_uart->lcr); + + if (baud == 0) + baud = 9600; + + quot = ch->ch_bd->bd_dividend / baud; + + if (quot != 0) { + writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr); + writeb((quot & 0xff), &ch->ch_neo_uart->txrx); + writeb((quot >> 8), &ch->ch_neo_uart->ier); + writeb(lcr, &ch->ch_neo_uart->lcr); + } + + if (uart_lcr != lcr) + writeb(lcr, &ch->ch_neo_uart->lcr); + + if (ch->ch_c_cflag & CREAD) + ier |= (UART_IER_RDI | UART_IER_RLSI); + + ier |= (UART_IER_THRI | UART_IER_MSI); + + writeb(ier, &ch->ch_neo_uart->ier); + + /* Set new start/stop chars */ + neo_set_new_start_stop_chars(ch); + + if (ch->ch_c_cflag & CRTSCTS) + neo_set_cts_flow_control(ch); + else if (ch->ch_c_iflag & IXON) { + /* If start/stop is set to disable, then we should disable flow control */ + if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) + neo_set_no_output_flow_control(ch); + else + neo_set_ixon_flow_control(ch); + } + else + neo_set_no_output_flow_control(ch); + + if (ch->ch_c_cflag & CRTSCTS) + neo_set_rts_flow_control(ch); + else if (ch->ch_c_iflag & IXOFF) { + /* If start/stop is set to disable, then we should disable flow control */ + if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) + neo_set_no_input_flow_control(ch); + else + neo_set_ixoff_flow_control(ch); + } + else + neo_set_no_input_flow_control(ch); + /* + * Adjust the RX FIFO Trigger level if baud is less than 9600. + * Not exactly elegant, but this is needed because of the Exar chip's + * delay on firing off the RX FIFO interrupt on slower baud rates. + */ + if (baud < 9600) { + writeb(1, &ch->ch_neo_uart->rfifo); + ch->ch_r_tlevel = 1; + } + + neo_assert_modem_signals(ch); + + /* Get current status of the modem signals now */ + neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); + return; +} + +/* + * jsm_neo_intr() + * + * Neo specific interrupt handler. + */ +static irqreturn_t neo_intr(int irq, void *voidbrd) +{ + struct jsm_board *brd = voidbrd; + struct jsm_channel *ch; + int port = 0; + int type = 0; + int current_port; + u32 tmp; + u32 uart_poll; + unsigned long lock_flags; + unsigned long lock_flags2; + int outofloop_count = 0; + + /* Lock out the slow poller from running on this board. */ + spin_lock_irqsave(&brd->bd_intr_lock, lock_flags); + + /* + * Read in "extended" IRQ information from the 32bit Neo register. + * Bits 0-7: What port triggered the interrupt. + * Bits 8-31: Each 3bits indicate what type of interrupt occurred. + */ + uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET); + + jsm_printk(INTR, INFO, &brd->pci_dev, + "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll); + + if (!uart_poll) { + jsm_printk(INTR, INFO, &brd->pci_dev, + "Kernel interrupted to me, but no pending interrupts...\n"); + spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); + return IRQ_NONE; + } + + /* At this point, we have at least SOMETHING to service, dig further... */ + + current_port = 0; + + /* Loop on each port */ + while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){ + + tmp = uart_poll; + outofloop_count++; + + /* Check current port to see if it has interrupt pending */ + if ((tmp & jsm_offset_table[current_port]) != 0) { + port = current_port; + type = tmp >> (8 + (port * 3)); + type &= 0x7; + } else { + current_port++; + continue; + } + + jsm_printk(INTR, INFO, &brd->pci_dev, + "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type); + + /* Remove this port + type from uart_poll */ + uart_poll &= ~(jsm_offset_table[port]); + + if (!type) { + /* If no type, just ignore it, and move onto next port */ + jsm_printk(INTR, ERR, &brd->pci_dev, + "Interrupt with no type! port: %d\n", port); + continue; + } + + /* Switch on type of interrupt we have */ + switch (type) { + + case UART_17158_RXRDY_TIMEOUT: + /* + * RXRDY Time-out is cleared by reading data in the + * RX FIFO until it falls below the trigger level. + */ + + /* Verify the port is in range. */ + if (port > brd->nasync) + continue; + + ch = brd->channels[port]; + neo_copy_data_from_uart_to_queue(ch); + + /* Call our tty layer to enforce queue flow control if needed. */ + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + jsm_check_queue_flow_control(ch); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + + continue; + + case UART_17158_RX_LINE_STATUS: + /* + * RXRDY and RX LINE Status (logic OR of LSR[4:1]) + */ + neo_parse_lsr(brd, port); + continue; + + case UART_17158_TXRDY: + /* + * TXRDY interrupt clears after reading ISR register for the UART channel. + */ + + /* + * Yes, this is odd... + * Why would I check EVERY possibility of type of + * interrupt, when we know its TXRDY??? + * Becuz for some reason, even tho we got triggered for TXRDY, + * it seems to be occassionally wrong. Instead of TX, which + * it should be, I was getting things like RXDY too. Weird. + */ + neo_parse_isr(brd, port); + continue; + + case UART_17158_MSR: + /* + * MSR or flow control was seen. + */ + neo_parse_isr(brd, port); + continue; + + default: + /* + * The UART triggered us with a bogus interrupt type. + * It appears the Exar chip, when REALLY bogged down, will throw + * these once and awhile. + * Its harmless, just ignore it and move on. + */ + jsm_printk(INTR, ERR, &brd->pci_dev, + "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type); + continue; + } + } + + spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); + + jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n"); + return IRQ_HANDLED; +} + +/* + * Neo specific way of turning off the receiver. + * Used as a way to enforce queue flow control when in + * hardware flow control mode. + */ +static void neo_disable_receiver(struct jsm_channel *ch) +{ + u8 tmp = readb(&ch->ch_neo_uart->ier); + tmp &= ~(UART_IER_RDI); + writeb(tmp, &ch->ch_neo_uart->ier); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); +} + + +/* + * Neo specific way of turning on the receiver. + * Used as a way to un-enforce queue flow control when in + * hardware flow control mode. + */ +static void neo_enable_receiver(struct jsm_channel *ch) +{ + u8 tmp = readb(&ch->ch_neo_uart->ier); + tmp |= (UART_IER_RDI); + writeb(tmp, &ch->ch_neo_uart->ier); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); +} + +static void neo_send_start_character(struct jsm_channel *ch) +{ + if (!ch) + return; + + if (ch->ch_startc != __DISABLED_CHAR) { + ch->ch_xon_sends++; + writeb(ch->ch_startc, &ch->ch_neo_uart->txrx); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); + } +} + +static void neo_send_stop_character(struct jsm_channel *ch) +{ + if (!ch) + return; + + if (ch->ch_stopc != __DISABLED_CHAR) { + ch->ch_xoff_sends++; + writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); + } +} + +/* + * neo_uart_init + */ +static void neo_uart_init(struct jsm_channel *ch) +{ + writeb(0, &ch->ch_neo_uart->ier); + writeb(0, &ch->ch_neo_uart->efr); + writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr); + + /* Clear out UART and FIFO */ + readb(&ch->ch_neo_uart->txrx); + writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); + readb(&ch->ch_neo_uart->lsr); + readb(&ch->ch_neo_uart->msr); + + ch->ch_flags |= CH_FIFO_ENABLED; + + /* Assert any signals we want up */ + writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); +} + +/* + * Make the UART completely turn off. + */ +static void neo_uart_off(struct jsm_channel *ch) +{ + /* Turn off UART enhanced bits */ + writeb(0, &ch->ch_neo_uart->efr); + + /* Stop all interrupts from occurring. */ + writeb(0, &ch->ch_neo_uart->ier); +} + +static u32 neo_get_uart_bytes_left(struct jsm_channel *ch) +{ + u8 left = 0; + u8 lsr = readb(&ch->ch_neo_uart->lsr); + + /* We must cache the LSR as some of the bits get reset once read... */ + ch->ch_cached_lsr |= lsr; + + /* Determine whether the Transmitter is empty or not */ + if (!(lsr & UART_LSR_TEMT)) + left = 1; + else { + ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); + left = 0; + } + + return left; +} + +/* Channel lock MUST be held by the calling function! */ +static void neo_send_break(struct jsm_channel *ch) +{ + /* + * Set the time we should stop sending the break. + * If we are already sending a break, toss away the existing + * time to stop, and use this new value instead. + */ + + /* Tell the UART to start sending the break */ + if (!(ch->ch_flags & CH_BREAK_SENDING)) { + u8 temp = readb(&ch->ch_neo_uart->lcr); + writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr); + ch->ch_flags |= (CH_BREAK_SENDING); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); + } +} + +/* + * neo_send_immediate_char. + * + * Sends a specific character as soon as possible to the UART, + * jumping over any bytes that might be in the write queue. + * + * The channel lock MUST be held by the calling function. + */ +static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c) +{ + if (!ch) + return; + + writeb(c, &ch->ch_neo_uart->txrx); + + /* flush write operation */ + neo_pci_posting_flush(ch->ch_bd); +} + +struct board_ops jsm_neo_ops = { + .intr = neo_intr, + .uart_init = neo_uart_init, + .uart_off = neo_uart_off, + .param = neo_param, + .assert_modem_signals = neo_assert_modem_signals, + .flush_uart_write = neo_flush_uart_write, + .flush_uart_read = neo_flush_uart_read, + .disable_receiver = neo_disable_receiver, + .enable_receiver = neo_enable_receiver, + .send_break = neo_send_break, + .clear_break = neo_clear_break, + .send_start_character = neo_send_start_character, + .send_stop_character = neo_send_stop_character, + .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart, + .get_uart_bytes_left = neo_get_uart_bytes_left, + .send_immediate_char = neo_send_immediate_char +}; diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c new file mode 100644 index 000000000000..7a4a914ecff0 --- /dev/null +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -0,0 +1,910 @@ +/************************************************************************ + * Copyright 2003 Digi International (www.digi.com) + * + * Copyright (C) 2004 IBM Corporation. All rights reserved. + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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. + * + * Contact Information: + * Scott H Kilau + * Ananda Venkatarman + * Modifications: + * 01/19/06: changed jsm_input routine to use the dynamically allocated + * tty_buffer changes. Contributors: Scott Kilau and Ananda V. + ***********************************************************************/ +#include +#include +#include +#include /* For udelay */ +#include +#include + +#include "jsm.h" + +static DECLARE_BITMAP(linemap, MAXLINES); + +static void jsm_carrier(struct jsm_channel *ch); + +static inline int jsm_get_mstat(struct jsm_channel *ch) +{ + unsigned char mstat; + unsigned result; + + jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n"); + + mstat = (ch->ch_mostat | ch->ch_mistat); + + result = 0; + + if (mstat & UART_MCR_DTR) + result |= TIOCM_DTR; + if (mstat & UART_MCR_RTS) + result |= TIOCM_RTS; + if (mstat & UART_MSR_CTS) + result |= TIOCM_CTS; + if (mstat & UART_MSR_DSR) + result |= TIOCM_DSR; + if (mstat & UART_MSR_RI) + result |= TIOCM_RI; + if (mstat & UART_MSR_DCD) + result |= TIOCM_CD; + + jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); + return result; +} + +static unsigned int jsm_tty_tx_empty(struct uart_port *port) +{ + return TIOCSER_TEMT; +} + +/* + * Return modem signals to ld. + */ +static unsigned int jsm_tty_get_mctrl(struct uart_port *port) +{ + int result; + struct jsm_channel *channel = (struct jsm_channel *)port; + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + + result = jsm_get_mstat(channel); + + if (result < 0) + return -ENXIO; + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); + + return result; +} + +/* + * jsm_set_modem_info() + * + * Set modem signals, called by ld. + */ +static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct jsm_channel *channel = (struct jsm_channel *)port; + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + + if (mctrl & TIOCM_RTS) + channel->ch_mostat |= UART_MCR_RTS; + else + channel->ch_mostat &= ~UART_MCR_RTS; + + if (mctrl & TIOCM_DTR) + channel->ch_mostat |= UART_MCR_DTR; + else + channel->ch_mostat &= ~UART_MCR_DTR; + + channel->ch_bd->bd_ops->assert_modem_signals(channel); + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); + udelay(10); +} + +static void jsm_tty_start_tx(struct uart_port *port) +{ + struct jsm_channel *channel = (struct jsm_channel *)port; + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + + channel->ch_flags &= ~(CH_STOP); + jsm_tty_write(port); + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); +} + +static void jsm_tty_stop_tx(struct uart_port *port) +{ + struct jsm_channel *channel = (struct jsm_channel *)port; + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); + + channel->ch_flags |= (CH_STOP); + + jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); +} + +static void jsm_tty_send_xchar(struct uart_port *port, char ch) +{ + unsigned long lock_flags; + struct jsm_channel *channel = (struct jsm_channel *)port; + struct ktermios *termios; + + spin_lock_irqsave(&port->lock, lock_flags); + termios = port->state->port.tty->termios; + if (ch == termios->c_cc[VSTART]) + channel->ch_bd->bd_ops->send_start_character(channel); + + if (ch == termios->c_cc[VSTOP]) + channel->ch_bd->bd_ops->send_stop_character(channel); + spin_unlock_irqrestore(&port->lock, lock_flags); +} + +static void jsm_tty_stop_rx(struct uart_port *port) +{ + struct jsm_channel *channel = (struct jsm_channel *)port; + + channel->ch_bd->bd_ops->disable_receiver(channel); +} + +static void jsm_tty_enable_ms(struct uart_port *port) +{ + /* Nothing needed */ +} + +static void jsm_tty_break(struct uart_port *port, int break_state) +{ + unsigned long lock_flags; + struct jsm_channel *channel = (struct jsm_channel *)port; + + spin_lock_irqsave(&port->lock, lock_flags); + if (break_state == -1) + channel->ch_bd->bd_ops->send_break(channel); + else + channel->ch_bd->bd_ops->clear_break(channel, 0); + + spin_unlock_irqrestore(&port->lock, lock_flags); +} + +static int jsm_tty_open(struct uart_port *port) +{ + struct jsm_board *brd; + struct jsm_channel *channel = (struct jsm_channel *)port; + struct ktermios *termios; + + /* Get board pointer from our array of majors we have allocated */ + brd = channel->ch_bd; + + /* + * Allocate channel buffers for read/write/error. + * Set flag, so we don't get trounced on. + */ + channel->ch_flags |= (CH_OPENING); + + /* Drop locks, as malloc with GFP_KERNEL can sleep */ + + if (!channel->ch_rqueue) { + channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL); + if (!channel->ch_rqueue) { + jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, + "unable to allocate read queue buf"); + return -ENOMEM; + } + } + if (!channel->ch_equeue) { + channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL); + if (!channel->ch_equeue) { + jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, + "unable to allocate error queue buf"); + return -ENOMEM; + } + } + if (!channel->ch_wqueue) { + channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL); + if (!channel->ch_wqueue) { + jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, + "unable to allocate write queue buf"); + return -ENOMEM; + } + } + + channel->ch_flags &= ~(CH_OPENING); + /* + * Initialize if neither terminal is open. + */ + jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, + "jsm_open: initializing channel in open...\n"); + + /* + * Flush input queues. + */ + channel->ch_r_head = channel->ch_r_tail = 0; + channel->ch_e_head = channel->ch_e_tail = 0; + channel->ch_w_head = channel->ch_w_tail = 0; + + brd->bd_ops->flush_uart_write(channel); + brd->bd_ops->flush_uart_read(channel); + + channel->ch_flags = 0; + channel->ch_cached_lsr = 0; + channel->ch_stops_sent = 0; + + 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; + channel->ch_c_lflag = termios->c_lflag; + channel->ch_startc = termios->c_cc[VSTART]; + channel->ch_stopc = termios->c_cc[VSTOP]; + + /* Tell UART to init itself */ + brd->bd_ops->uart_init(channel); + + /* + * Run param in case we changed anything + */ + brd->bd_ops->param(channel); + + jsm_carrier(channel); + + channel->ch_open_count++; + + jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n"); + return 0; +} + +static void jsm_tty_close(struct uart_port *port) +{ + struct jsm_board *bd; + struct ktermios *ts; + struct jsm_channel *channel = (struct jsm_channel *)port; + + jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); + + bd = channel->ch_bd; + ts = port->state->port.tty->termios; + + channel->ch_flags &= ~(CH_STOPI); + + channel->ch_open_count--; + + /* + * If we have HUPCL set, lower DTR and RTS + */ + if (channel->ch_c_cflag & HUPCL) { + jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, + "Close. HUPCL set, dropping DTR/RTS\n"); + + /* Drop RTS/DTR */ + channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS); + bd->bd_ops->assert_modem_signals(channel); + } + + /* Turn off UART interrupts for this port */ + channel->ch_bd->bd_ops->uart_off(channel); + + jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n"); +} + +static void jsm_tty_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old_termios) +{ + unsigned long lock_flags; + struct jsm_channel *channel = (struct jsm_channel *)port; + + spin_lock_irqsave(&port->lock, lock_flags); + channel->ch_c_cflag = termios->c_cflag; + channel->ch_c_iflag = termios->c_iflag; + channel->ch_c_oflag = termios->c_oflag; + channel->ch_c_lflag = termios->c_lflag; + channel->ch_startc = termios->c_cc[VSTART]; + channel->ch_stopc = termios->c_cc[VSTOP]; + + channel->ch_bd->bd_ops->param(channel); + jsm_carrier(channel); + spin_unlock_irqrestore(&port->lock, lock_flags); +} + +static const char *jsm_tty_type(struct uart_port *port) +{ + return "jsm"; +} + +static void jsm_tty_release_port(struct uart_port *port) +{ +} + +static int jsm_tty_request_port(struct uart_port *port) +{ + return 0; +} + +static void jsm_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_JSM; +} + +static struct uart_ops jsm_ops = { + .tx_empty = jsm_tty_tx_empty, + .set_mctrl = jsm_tty_set_mctrl, + .get_mctrl = jsm_tty_get_mctrl, + .stop_tx = jsm_tty_stop_tx, + .start_tx = jsm_tty_start_tx, + .send_xchar = jsm_tty_send_xchar, + .stop_rx = jsm_tty_stop_rx, + .enable_ms = jsm_tty_enable_ms, + .break_ctl = jsm_tty_break, + .startup = jsm_tty_open, + .shutdown = jsm_tty_close, + .set_termios = jsm_tty_set_termios, + .type = jsm_tty_type, + .release_port = jsm_tty_release_port, + .request_port = jsm_tty_request_port, + .config_port = jsm_config_port, +}; + +/* + * jsm_tty_init() + * + * Init the tty subsystem. Called once per board after board has been + * downloaded and init'ed. + */ +int __devinit jsm_tty_init(struct jsm_board *brd) +{ + int i; + void __iomem *vaddr; + struct jsm_channel *ch; + + if (!brd) + return -ENXIO; + + jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); + + /* + * Initialize board structure elements. + */ + + brd->nasync = brd->maxports; + + /* + * Allocate channel memory that might not have been allocated + * when the driver was first loaded. + */ + for (i = 0; i < brd->nasync; i++) { + if (!brd->channels[i]) { + + /* + * Okay to malloc with GFP_KERNEL, we are not at + * interrupt context, and there are no locks held. + */ + brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL); + if (!brd->channels[i]) { + jsm_printk(CORE, ERR, &brd->pci_dev, + "%s:%d Unable to allocate memory for channel struct\n", + __FILE__, __LINE__); + } + } + } + + ch = brd->channels[0]; + vaddr = brd->re_map_membase; + + /* Set up channel variables */ + for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { + + if (!brd->channels[i]) + continue; + + spin_lock_init(&ch->ch_lock); + + if (brd->bd_uart_offset == 0x200) + ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i); + + ch->ch_bd = brd; + ch->ch_portnum = i; + + /* .25 second delay */ + ch->ch_close_delay = 250; + + init_waitqueue_head(&ch->ch_flags_wait); + } + + jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); + return 0; +} + +int jsm_uart_port_init(struct jsm_board *brd) +{ + int i, rc; + unsigned int line; + struct jsm_channel *ch; + + if (!brd) + return -ENXIO; + + jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); + + /* + * Initialize board structure elements. + */ + + brd->nasync = brd->maxports; + + /* Set up channel variables */ + for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { + + if (!brd->channels[i]) + continue; + + brd->channels[i]->uart_port.irq = brd->irq; + brd->channels[i]->uart_port.uartclk = 14745600; + brd->channels[i]->uart_port.type = PORT_JSM; + brd->channels[i]->uart_port.iotype = UPIO_MEM; + brd->channels[i]->uart_port.membase = brd->re_map_membase; + brd->channels[i]->uart_port.fifosize = 16; + brd->channels[i]->uart_port.ops = &jsm_ops; + line = find_first_zero_bit(linemap, MAXLINES); + if (line >= MAXLINES) { + printk(KERN_INFO "jsm: linemap is full, added device failed\n"); + continue; + } else + set_bit(line, linemap); + brd->channels[i]->uart_port.line = line; + rc = uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port); + if (rc){ + printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i); + return rc; + } + else + printk(KERN_INFO "jsm: Port %d added\n", i); + } + + jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); + return 0; +} + +int jsm_remove_uart_port(struct jsm_board *brd) +{ + int i; + struct jsm_channel *ch; + + if (!brd) + return -ENXIO; + + jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); + + /* + * Initialize board structure elements. + */ + + brd->nasync = brd->maxports; + + /* Set up channel variables */ + for (i = 0; i < brd->nasync; i++) { + + if (!brd->channels[i]) + continue; + + ch = brd->channels[i]; + + clear_bit(ch->uart_port.line, linemap); + uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); + } + + jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); + return 0; +} + +void jsm_input(struct jsm_channel *ch) +{ + struct jsm_board *bd; + struct tty_struct *tp; + u32 rmask; + u16 head; + u16 tail; + int data_len; + unsigned long lock_flags; + int len = 0; + int n = 0; + int s = 0; + int i = 0; + + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); + + if (!ch) + return; + + tp = ch->uart_port.state->port.tty; + + bd = ch->ch_bd; + if(!bd) + return; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + /* + *Figure the number of characters in the buffer. + *Exit immediately if none. + */ + + rmask = RQUEUEMASK; + + head = ch->ch_r_head & rmask; + tail = ch->ch_r_tail & rmask; + + data_len = (head - tail) & rmask; + if (data_len == 0) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + return; + } + + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); + + /* + *If the device is not open, or CREAD is off, flush + *input data and return immediately. + */ + if (!tp || + !(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); + ch->ch_r_head = tail; + + /* Force queue flow control to be released, if needed */ + jsm_check_queue_flow_control(ch); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + return; + } + + /* + * If we are throttled, simply don't read any data. + */ + if (ch->ch_flags & CH_STOPI) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + "Port %d throttled, not reading any data. head: %x tail: %x\n", + ch->ch_portnum, head, tail); + return; + } + + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n"); + + if (data_len <= 0) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); + return; + } + + len = tty_buffer_request_room(tp, data_len); + n = len; + + /* + * n now contains the most amount of data we can copy, + * bounded either by the flip buffer size or the amount + * of data the card actually has pending... + */ + while (n) { + s = ((head >= tail) ? head : RQUEUESIZE) - tail; + s = min(s, n); + + if (s <= 0) + break; + + /* + * If conditions are such that ld needs to see all + * UART errors, we will have to walk each character + * and error byte and send them to the buffer one at + * a time. + */ + + if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { + for (i = 0; i < s; i++) { + /* + * Give the Linux ld the flags in the + * format it likes. + */ + if (*(ch->ch_equeue +tail +i) & UART_LSR_BI) + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK); + else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY); + else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME); + else + tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL); + } + } else { + tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ; + } + tail += s; + n -= s; + /* Flip queue if needed */ + tail &= rmask; + } + + ch->ch_r_tail = tail & rmask; + ch->ch_e_tail = tail & rmask; + jsm_check_queue_flow_control(ch); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + /* Tell the tty layer its okay to "eat" the data now */ + tty_flip_buffer_push(tp); + + jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); +} + +static void jsm_carrier(struct jsm_channel *ch) +{ + struct jsm_board *bd; + + int virt_carrier = 0; + int phys_carrier = 0; + + jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n"); + if (!ch) + return; + + bd = ch->ch_bd; + + if (!bd) + return; + + if (ch->ch_mistat & UART_MSR_DCD) { + jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, + "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD); + phys_carrier = 1; + } + + if (ch->ch_c_cflag & CLOCAL) + virt_carrier = 1; + + jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, + "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier); + + /* + * Test for a VIRTUAL carrier transition to HIGH. + */ + if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { + + /* + * When carrier rises, wake any threads waiting + * for carrier in the open routine. + */ + + jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, + "carrier: virt DCD rose\n"); + + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Test for a PHYSICAL carrier transition to HIGH. + */ + if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { + + /* + * When carrier rises, wake any threads waiting + * for carrier in the open routine. + */ + + jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, + "carrier: physical DCD rose\n"); + + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Test for a PHYSICAL transition to low, so long as we aren't + * currently ignoring physical transitions (which is what "virtual + * carrier" indicates). + * + * The transition of the virtual carrier to low really doesn't + * matter... it really only means "ignore carrier state", not + * "make pretend that carrier is there". + */ + if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) + && (phys_carrier == 0)) { + /* + * When carrier drops: + * + * Drop carrier on all open units. + * + * Flush queues, waking up any task waiting in the + * line discipline. + * + * Send a hangup to the control terminal. + * + * Enable all select calls. + */ + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Make sure that our cached values reflect the current reality. + */ + if (virt_carrier == 1) + ch->ch_flags |= CH_FCAR; + else + ch->ch_flags &= ~CH_FCAR; + + if (phys_carrier == 1) + ch->ch_flags |= CH_CD; + else + ch->ch_flags &= ~CH_CD; +} + + +void jsm_check_queue_flow_control(struct jsm_channel *ch) +{ + struct board_ops *bd_ops = ch->ch_bd->bd_ops; + int qleft; + + /* Store how much space we have left in the queue */ + if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) + qleft += RQUEUEMASK + 1; + + /* + * Check to see if we should enforce flow control on our queue because + * the ld (or user) isn't reading data out of our queue fast enuf. + * + * NOTE: This is done based on what the current flow control of the + * port is set for. + * + * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt. + * This will cause the UART's FIFO to back up, and force + * the RTS signal to be dropped. + * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to + * the other side, in hopes it will stop sending data to us. + * 3) NONE - Nothing we can do. We will simply drop any extra data + * that gets sent into us when the queue fills up. + */ + if (qleft < 256) { + /* HWFLOW */ + if (ch->ch_c_cflag & CRTSCTS) { + if(!(ch->ch_flags & CH_RECEIVER_OFF)) { + bd_ops->disable_receiver(ch); + ch->ch_flags |= (CH_RECEIVER_OFF); + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n", + qleft); + } + } + /* SWFLOW */ + else if (ch->ch_c_iflag & IXOFF) { + if (ch->ch_stops_sent <= MAX_STOPS_SENT) { + bd_ops->send_stop_character(ch); + ch->ch_stops_sent++; + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + "Sending stop char! Times sent: %x\n", ch->ch_stops_sent); + } + } + } + + /* + * Check to see if we should unenforce flow control because + * ld (or user) finally read enuf data out of our queue. + * + * NOTE: This is done based on what the current flow control of the + * port is set for. + * + * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt. + * This will cause the UART's FIFO to raise RTS back up, + * which will allow the other side to start sending data again. + * 2) SWFLOW (IXOFF) - Send a start character to + * the other side, so it will start sending data to us again. + * 3) NONE - Do nothing. Since we didn't do anything to turn off the + * other side, we don't need to do anything now. + */ + if (qleft > (RQUEUESIZE / 2)) { + /* HWFLOW */ + if (ch->ch_c_cflag & CRTSCTS) { + if (ch->ch_flags & CH_RECEIVER_OFF) { + bd_ops->enable_receiver(ch); + ch->ch_flags &= ~(CH_RECEIVER_OFF); + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, + "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n", + qleft); + } + } + /* SWFLOW */ + else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { + ch->ch_stops_sent = 0; + bd_ops->send_start_character(ch); + jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n"); + } + } +} + +/* + * jsm_tty_write() + * + * Take data from the user or kernel and send it out to the FEP. + * In here exists all the Transparent Print magic as well. + */ +int jsm_tty_write(struct uart_port *port) +{ + int bufcount; + int data_count = 0,data_count1 =0; + u16 head; + u16 tail; + u16 tmask; + u32 remain; + int temp_tail = port->state->xmit.tail; + struct jsm_channel *channel = (struct jsm_channel *)port; + + tmask = WQUEUEMASK; + head = (channel->ch_w_head) & tmask; + tail = (channel->ch_w_tail) & tmask; + + if ((bufcount = tail - head - 1) < 0) + bufcount += WQUEUESIZE; + + bufcount = min(bufcount, 56); + remain = WQUEUESIZE - head; + + data_count = 0; + if (bufcount >= remain) { + bufcount -= remain; + while ((port->state->xmit.head != temp_tail) && + (data_count < remain)) { + channel->ch_wqueue[head++] = + port->state->xmit.buf[temp_tail]; + + temp_tail++; + temp_tail &= (UART_XMIT_SIZE - 1); + data_count++; + } + if (data_count == remain) head = 0; + } + + data_count1 = 0; + if (bufcount > 0) { + remain = bufcount; + while ((port->state->xmit.head != temp_tail) && + (data_count1 < remain)) { + channel->ch_wqueue[head++] = + port->state->xmit.buf[temp_tail]; + + temp_tail++; + temp_tail &= (UART_XMIT_SIZE - 1); + data_count1++; + + } + } + + port->state->xmit.tail = temp_tail; + + data_count += data_count1; + if (data_count) { + head &= tmask; + channel->ch_w_head = head; + } + + if (data_count) { + channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); + } + + return data_count; +} diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c new file mode 100644 index 000000000000..25a8bc565f40 --- /dev/null +++ b/drivers/tty/serial/kgdboc.c @@ -0,0 +1,328 @@ +/* + * Based on the same principle as kgdboe using the NETPOLL api, this + * driver uses a console polling api to implement a gdb serial inteface + * which is multiplexed on a console port. + * + * Maintainer: Jason Wessel + * + * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CONFIG_LEN 40 + +static struct kgdb_io kgdboc_io_ops; + +/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ +static int configured = -1; + +static char config[MAX_CONFIG_LEN]; +static struct kparam_string kps = { + .string = config, + .maxlen = MAX_CONFIG_LEN, +}; + +static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ +static struct tty_driver *kgdb_tty_driver; +static int kgdb_tty_line; + +#ifdef CONFIG_KDB_KEYBOARD +static int kgdboc_reset_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + input_reset_device(dev); + + /* Retrun an error - we do not want to bind, just to reset */ + return -ENODEV; +} + +static void kgdboc_reset_disconnect(struct input_handle *handle) +{ + /* We do not expect anyone to actually bind to us */ + BUG(); +} + +static const struct input_device_id kgdboc_reset_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { } +}; + +static struct input_handler kgdboc_reset_handler = { + .connect = kgdboc_reset_connect, + .disconnect = kgdboc_reset_disconnect, + .name = "kgdboc_reset", + .id_table = kgdboc_reset_ids, +}; + +static DEFINE_MUTEX(kgdboc_reset_mutex); + +static void kgdboc_restore_input_helper(struct work_struct *dummy) +{ + /* + * We need to take a mutex to prevent several instances of + * this work running on different CPUs so they don't try + * to register again already registered handler. + */ + mutex_lock(&kgdboc_reset_mutex); + + if (input_register_handler(&kgdboc_reset_handler) == 0) + input_unregister_handler(&kgdboc_reset_handler); + + mutex_unlock(&kgdboc_reset_mutex); +} + +static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper); + +static void kgdboc_restore_input(void) +{ + if (likely(system_state == SYSTEM_RUNNING)) + schedule_work(&kgdboc_restore_input_work); +} + +static int kgdboc_register_kbd(char **cptr) +{ + if (strncmp(*cptr, "kbd", 3) == 0) { + if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { + kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; + kdb_poll_idx++; + if (cptr[0][3] == ',') + *cptr += 4; + else + return 1; + } + } + return 0; +} + +static void kgdboc_unregister_kbd(void) +{ + int i; + + for (i = 0; i < kdb_poll_idx; i++) { + if (kdb_poll_funcs[i] == kdb_get_kbd_char) { + kdb_poll_idx--; + kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx]; + kdb_poll_funcs[kdb_poll_idx] = NULL; + i--; + } + } + flush_work_sync(&kgdboc_restore_input_work); +} +#else /* ! CONFIG_KDB_KEYBOARD */ +#define kgdboc_register_kbd(x) 0 +#define kgdboc_unregister_kbd() +#define kgdboc_restore_input() +#endif /* ! CONFIG_KDB_KEYBOARD */ + +static int kgdboc_option_setup(char *opt) +{ + if (strlen(opt) > MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } + strcpy(config, opt); + + return 0; +} + +__setup("kgdboc=", kgdboc_option_setup); + +static void cleanup_kgdboc(void) +{ + kgdboc_unregister_kbd(); + if (configured == 1) + kgdb_unregister_io_module(&kgdboc_io_ops); +} + +static int configure_kgdboc(void) +{ + struct tty_driver *p; + int tty_line = 0; + int err; + char *cptr = config; + struct console *cons; + + err = kgdboc_option_setup(config); + if (err || !strlen(config) || isspace(config[0])) + goto noconfig; + + err = -ENODEV; + kgdboc_io_ops.is_console = 0; + kgdb_tty_driver = NULL; + + kgdboc_use_kms = 0; + if (strncmp(cptr, "kms,", 4) == 0) { + cptr += 4; + kgdboc_use_kms = 1; + } + + if (kgdboc_register_kbd(&cptr)) + goto do_register; + + p = tty_find_polling_driver(cptr, &tty_line); + if (!p) + goto noconfig; + + cons = console_drivers; + while (cons) { + int idx; + if (cons->device && cons->device(cons, &idx) == p && + idx == tty_line) { + kgdboc_io_ops.is_console = 1; + break; + } + cons = cons->next; + } + + kgdb_tty_driver = p; + kgdb_tty_line = tty_line; + +do_register: + err = kgdb_register_io_module(&kgdboc_io_ops); + if (err) + goto noconfig; + + configured = 1; + + return 0; + +noconfig: + config[0] = 0; + configured = 0; + cleanup_kgdboc(); + + return err; +} + +static int __init init_kgdboc(void) +{ + /* Already configured? */ + if (configured == 1) + return 0; + + return configure_kgdboc(); +} + +static int kgdboc_get_char(void) +{ + if (!kgdb_tty_driver) + return -1; + return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, + kgdb_tty_line); +} + +static void kgdboc_put_char(u8 chr) +{ + if (!kgdb_tty_driver) + return; + kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, + kgdb_tty_line, chr); +} + +static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) +{ + int len = strlen(kmessage); + + if (len >= MAX_CONFIG_LEN) { + printk(KERN_ERR "kgdboc: config string too long\n"); + return -ENOSPC; + } + + /* Only copy in the string if the init function has not run yet */ + if (configured < 0) { + strcpy(config, kmessage); + return 0; + } + + if (kgdb_connected) { + printk(KERN_ERR + "kgdboc: Cannot reconfigure while KGDB is connected.\n"); + + return -EBUSY; + } + + strcpy(config, kmessage); + /* Chop out \n char as a result of echo */ + if (config[len - 1] == '\n') + config[len - 1] = '\0'; + + if (configured == 1) + cleanup_kgdboc(); + + /* Go and configure with the new params. */ + return configure_kgdboc(); +} + +static int dbg_restore_graphics; + +static void kgdboc_pre_exp_handler(void) +{ + if (!dbg_restore_graphics && kgdboc_use_kms) { + dbg_restore_graphics = 1; + con_debug_enter(vc_cons[fg_console].d); + } + /* Increment the module count when the debugger is active */ + if (!kgdb_connected) + try_module_get(THIS_MODULE); +} + +static void kgdboc_post_exp_handler(void) +{ + /* decrement the module count when the debugger detaches */ + if (!kgdb_connected) + module_put(THIS_MODULE); + if (kgdboc_use_kms && dbg_restore_graphics) { + dbg_restore_graphics = 0; + con_debug_leave(); + } + kgdboc_restore_input(); +} + +static struct kgdb_io kgdboc_io_ops = { + .name = "kgdboc", + .read_char = kgdboc_get_char, + .write_char = kgdboc_put_char, + .pre_exception = kgdboc_pre_exp_handler, + .post_exception = kgdboc_post_exp_handler, +}; + +#ifdef CONFIG_KGDB_SERIAL_CONSOLE +/* This is only available if kgdboc is a built in for early debugging */ +static int __init kgdboc_early_init(char *opt) +{ + /* save the first character of the config string because the + * init routine can destroy it. + */ + char save_ch; + + kgdboc_option_setup(opt); + save_ch = config[0]; + init_kgdboc(); + config[0] = save_ch; + return 0; +} + +early_param("ekgdboc", kgdboc_early_init); +#endif /* CONFIG_KGDB_SERIAL_CONSOLE */ + +module_init(init_kgdboc); +module_exit(cleanup_kgdboc); +module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); +MODULE_PARM_DESC(kgdboc, "[,baud]"); +MODULE_DESCRIPTION("KGDB Console TTY Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c new file mode 100644 index 000000000000..bea5c215460c --- /dev/null +++ b/drivers/tty/serial/m32r_sio.c @@ -0,0 +1,1192 @@ +/* + * m32r_sio.c + * + * Driver for M32R serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/serial/8250.c. + * + * Copyright (C) 2001 Russell King. + * Copyright (C) 2004 Hirokazu Takata + * + * 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. + */ + +/* + * A note about mapbase / membase + * + * mapbase is the physical address of the IO port. Currently, we don't + * support this very well, and it may well be dropped from this driver + * in future. As such, mapbase should be NULL. + * + * membase is an 'ioremapped' cookie. This is compatible with the old + * serial.c driver, and is currently the preferred form. + */ + +#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PORT_M32R_BASE PORT_M32R_SIO +#define PORT_INDEX(x) (x - PORT_M32R_BASE + 1) +#define BAUD_RATE 115200 + +#include +#include "m32r_sio.h" +#include "m32r_sio_reg.h" + +/* + * Debugging. + */ +#if 0 +#define DEBUG_AUTOCONF(fmt...) printk(fmt) +#else +#define DEBUG_AUTOCONF(fmt...) do { } while (0) +#endif + +#if 0 +#define DEBUG_INTR(fmt...) printk(fmt) +#else +#define DEBUG_INTR(fmt...) do { } while (0) +#endif + +#define PASS_LIMIT 256 + +/* + * We default to IRQ0 for the "no irq" hack. Some + * machine types want others as well - they're free + * to redefine this in their header file. + */ +#define is_real_interrupt(irq) ((irq) != 0) + +#define BASE_BAUD 115200 + +/* Standard COM flags */ +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) + +/* + * SERIAL_PORT_DFNS tells us about built-in ports that have no + * standard enumeration mechanism. Platforms that can find all + * serial ports via mechanisms like ACPI or PCI need not supply it. + */ +#if defined(CONFIG_PLAT_USRV) + +#define SERIAL_PORT_DFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS }, /* ttyS1 */ + +#else /* !CONFIG_PLAT_USRV */ + +#if defined(CONFIG_SERIAL_M32R_PLDSIO) +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, \ + STD_COM_FLAGS }, /* ttyS0 */ +#else +#define SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, \ + STD_COM_FLAGS }, /* ttyS0 */ +#endif + +#endif /* !CONFIG_PLAT_USRV */ + +static struct old_serial_port old_serial_port[] = { + SERIAL_PORT_DFNS +}; + +#define UART_NR ARRAY_SIZE(old_serial_port) + +struct uart_sio_port { + struct uart_port port; + struct timer_list timer; /* "no irq" timer */ + struct list_head list; /* ports on this IRQ */ + unsigned short rev; + unsigned char acr; + unsigned char ier; + unsigned char lcr; + unsigned char mcr_mask; /* mask of user bits */ + unsigned char mcr_force; /* mask of forced bits */ + unsigned char lsr_break_flag; + + /* + * We provide a per-port pm hook. + */ + void (*pm)(struct uart_port *port, + unsigned int state, unsigned int old); +}; + +struct irq_info { + spinlock_t lock; + struct list_head *head; +}; + +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)) +#define __sio_out(v,x) outw((v),(unsigned long)(x)) + +static inline void sio_set_baud_rate(unsigned long baud) +{ + unsigned short sbaud; + sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1; + __sio_out(sbaud, PLD_ESIO0BAUR); +} + +static void sio_reset(void) +{ + unsigned short tmp; + + tmp = __sio_in(PLD_ESIO0RXB); + tmp = __sio_in(PLD_ESIO0RXB); + tmp = __sio_in(PLD_ESIO0CR); + sio_set_baud_rate(BAUD_RATE); + __sio_out(0x0300, PLD_ESIO0CR); + __sio_out(0x0003, PLD_ESIO0CR); +} + +static void sio_init(void) +{ + unsigned short tmp; + + tmp = __sio_in(PLD_ESIO0RXB); + tmp = __sio_in(PLD_ESIO0RXB); + tmp = __sio_in(PLD_ESIO0CR); + __sio_out(0x0300, PLD_ESIO0CR); + __sio_out(0x0003, PLD_ESIO0CR); +} + +static void sio_error(int *status) +{ + printk("SIO0 error[%04x]\n", *status); + do { + sio_init(); + } while ((*status = __sio_in(PLD_ESIO0CR)) != 3); +} + +#else /* not CONFIG_SERIAL_M32R_PLDSIO */ + +#define __sio_in(x) inl(x) +#define __sio_out(v,x) outl((v),(x)) + +static inline void sio_set_baud_rate(unsigned long baud) +{ + unsigned long i, j; + + i = boot_cpu_data.bus_clock / (baud * 16); + j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud; + i -= 1; + j = (j + 1) >> 1; + + __sio_out(i, M32R_SIO0_BAUR_PORTL); + __sio_out(j, M32R_SIO0_RBAUR_PORTL); +} + +static void sio_reset(void) +{ + __sio_out(0x00000300, M32R_SIO0_CR_PORTL); /* init status */ + __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL); /* 8bit */ + __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL); /* 1stop non */ + sio_set_baud_rate(BAUD_RATE); + __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL); + __sio_out(0x00000003, M32R_SIO0_CR_PORTL); /* RXCEN */ +} + +static void sio_init(void) +{ + unsigned int tmp; + + tmp = __sio_in(M32R_SIO0_RXB_PORTL); + tmp = __sio_in(M32R_SIO0_RXB_PORTL); + tmp = __sio_in(M32R_SIO0_STS_PORTL); + __sio_out(0x00000003, M32R_SIO0_CR_PORTL); +} + +static void sio_error(int *status) +{ + printk("SIO0 error[%04x]\n", *status); + do { + sio_init(); + } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3); +} + +#endif /* CONFIG_SERIAL_M32R_PLDSIO */ + +static unsigned int sio_in(struct uart_sio_port *up, int offset) +{ + return __sio_in(up->port.iobase + offset); +} + +static void sio_out(struct uart_sio_port *up, int offset, int value) +{ + __sio_out(value, up->port.iobase + offset); +} + +static unsigned int serial_in(struct uart_sio_port *up, int offset) +{ + if (!offset) + return 0; + + return __sio_in(offset); +} + +static void serial_out(struct uart_sio_port *up, int offset, int value) +{ + if (!offset) + return; + + __sio_out(value, offset); +} + +static void m32r_sio_stop_tx(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + if (up->ier & UART_IER_THRI) { + up->ier &= ~UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void m32r_sio_start_tx(struct uart_port *port) +{ +#ifdef CONFIG_SERIAL_M32R_PLDSIO + struct uart_sio_port *up = (struct uart_sio_port *)port; + struct circ_buf *xmit = &up->port.state->xmit; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + } + while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY); +#else + struct uart_sio_port *up = (struct uart_sio_port *)port; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +#endif +} + +static void m32r_sio_stop_rx(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +} + +static void m32r_sio_enable_ms(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +} + +static void receive_chars(struct uart_sio_port *up, int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned char ch; + unsigned char flag; + int max_count = 256; + + do { + ch = sio_in(up, SIORXB); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(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 (*status & UART_LSR_PE) + up->port.icount.parity++; + else if (*status & UART_LSR_FE) + up->port.icount.frame++; + if (*status & UART_LSR_OE) + up->port.icount.overrun++; + + /* + * Mask off conditions which should be ingored. + */ + *status &= up->port.read_status_mask; + + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + *status |= up->lsr_break_flag; + up->lsr_break_flag = 0; + } + + if (*status & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + flag = TTY_BREAK; + } else if (*status & UART_LSR_PE) + flag = TTY_PARITY; + else if (*status & UART_LSR_FE) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + if ((*status & up->port.ignore_status_mask) == 0) + tty_insert_flip_char(tty, ch, flag); + + if (*status & UART_LSR_OE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character. + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + ignore_char: + *status = serial_in(up, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); + tty_flip_buffer_push(tty); +} + +static void transmit_chars(struct uart_sio_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { +#ifndef CONFIG_SERIAL_M32R_PLDSIO /* XXX */ + serial_out(up, UART_TX, up->port.x_char); +#endif + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + m32r_sio_stop_tx(&up->port); + return; + } + + count = up->port.fifosize; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + while (!(serial_in(up, UART_LSR) & UART_LSR_THRE)); + + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + DEBUG_INTR("THRE..."); + + if (uart_circ_empty(xmit)) + m32r_sio_stop_tx(&up->port); +} + +/* + * This handles the interrupt from one port. + */ +static inline void m32r_sio_handle_port(struct uart_sio_port *up, + unsigned int status) +{ + DEBUG_INTR("status = %x...", status); + + if (status & 0x04) + receive_chars(up, &status); + if (status & 0x01) + transmit_chars(up); +} + +/* + * This is the serial driver's interrupt routine. + * + * Arjan thinks the old way was overly complex, so it got simplified. + * Alan disagrees, saying that need the complexity to handle the weird + * nature of ISA shared interrupts. (This is a special exception.) + * + * In order to handle ISA shared interrupts properly, we need to check + * that all ports have been serviced, and therefore the ISA interrupt + * line has been de-asserted. + * + * This means we need to loop through all ports. checking that they + * don't have an interrupt pending. + */ +static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id) +{ + struct irq_info *i = dev_id; + struct list_head *l, *end = NULL; + int pass_counter = 0; + + DEBUG_INTR("m32r_sio_interrupt(%d)...", irq); + +#ifdef CONFIG_SERIAL_M32R_PLDSIO +// if (irq == PLD_IRQ_SIO0_SND) +// irq = PLD_IRQ_SIO0_RCV; +#else + if (irq == M32R_IRQ_SIO0_S) + irq = M32R_IRQ_SIO0_R; +#endif + + spin_lock(&i->lock); + + l = i->head; + do { + struct uart_sio_port *up; + unsigned int sts; + + up = list_entry(l, struct uart_sio_port, list); + + sts = sio_in(up, SIOSTS); + if (sts & 0x5) { + spin_lock(&up->port.lock); + m32r_sio_handle_port(up, sts); + spin_unlock(&up->port.lock); + + end = NULL; + } else if (end == NULL) + end = l; + + l = l->next; + + if (l == i->head && pass_counter++ > PASS_LIMIT) { + if (sts & 0xe0) + sio_error(&sts); + break; + } + } while (l != end); + + spin_unlock(&i->lock); + + DEBUG_INTR("end.\n"); + + return IRQ_HANDLED; +} + +/* + * To support ISA shared interrupts, we need to have one interrupt + * handler that ensures that the IRQ line has been deasserted + * before returning. Failing to do this will result in the IRQ + * line being stuck active, and, since ISA irqs are edge triggered, + * no more IRQs will be seen. + */ +static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up) +{ + spin_lock_irq(&i->lock); + + if (!list_empty(i->head)) { + if (i->head == &up->list) + i->head = i->head->next; + list_del(&up->list); + } else { + BUG_ON(i->head != &up->list); + i->head = NULL; + } + + spin_unlock_irq(&i->lock); +} + +static int serial_link_irq_chain(struct uart_sio_port *up) +{ + struct irq_info *i = irq_lists + up->port.irq; + int ret, irq_flags = 0; + + spin_lock_irq(&i->lock); + + if (i->head) { + list_add(&up->list, i->head); + spin_unlock_irq(&i->lock); + + ret = 0; + } else { + INIT_LIST_HEAD(&up->list); + i->head = &up->list; + spin_unlock_irq(&i->lock); + + ret = request_irq(up->port.irq, m32r_sio_interrupt, + irq_flags, "SIO0-RX", i); + ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt, + irq_flags, "SIO0-TX", i); + if (ret < 0) + serial_do_unlink(i, up); + } + + return ret; +} + +static void serial_unlink_irq_chain(struct uart_sio_port *up) +{ + struct irq_info *i = irq_lists + up->port.irq; + + BUG_ON(i->head == NULL); + + if (list_empty(i->head)) { + free_irq(up->port.irq, i); + free_irq(up->port.irq + 1, i); + } + + serial_do_unlink(i, up); +} + +/* + * This function is used to handle ports that do not have an interrupt. + */ +static void m32r_sio_timeout(unsigned long data) +{ + struct uart_sio_port *up = (struct uart_sio_port *)data; + unsigned int timeout; + unsigned int sts; + + sts = sio_in(up, SIOSTS); + if (sts & 0x5) { + spin_lock(&up->port.lock); + m32r_sio_handle_port(up, sts); + spin_unlock(&up->port.lock); + } + + timeout = up->port.timeout; + timeout = timeout > 6 ? (timeout / 2 - 2) : 1; + mod_timer(&up->timer, jiffies + timeout); +} + +static unsigned int m32r_sio_tx_empty(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + unsigned long flags; + unsigned int ret; + + 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); + + return ret; +} + +static unsigned int m32r_sio_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + +} + +static void m32r_sio_break_ctl(struct uart_port *port, int break_state) +{ + +} + +static int m32r_sio_startup(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + int retval; + + sio_init(); + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!is_real_interrupt(up->port.irq)) { + unsigned int timeout = up->port.timeout; + + timeout = timeout > 6 ? (timeout / 2 - 2) : 1; + + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + timeout); + } else { + retval = serial_link_irq_chain(up); + if (retval) + return retval; + } + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + * - M32R_SIO: 0x0c + * - M32R_PLDSIO: 0x04 + */ + up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + sio_out(up, SIOTRCR, up->ier); + + /* + * And clear the interrupt registers again for luck. + */ + sio_reset(); + + return 0; +} + +static void m32r_sio_shutdown(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + /* + * Disable interrupts from this port + */ + up->ier = 0; + sio_out(up, SIOTRCR, 0); + + /* + * Disable break condition and FIFOs + */ + + sio_init(); + + if (!is_real_interrupt(up->port.irq)) + del_timer_sync(&up->timer); + else + serial_unlink_irq_chain(up); +} + +static unsigned int m32r_sio_get_divisor(struct uart_port *port, + unsigned int baud) +{ + return uart_get_divisor(port, baud); +} + +static void m32r_sio_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + unsigned char cval = 0; + unsigned long flags; + unsigned int baud, quot; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (termios->c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* + * Ask the core to calculate the divisor for us. + */ +#ifdef CONFIG_SERIAL_M32R_PLDSIO + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4); +#else + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); +#endif + quot = m32r_sio_get_divisor(port, baud); + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + sio_set_baud_rate(baud); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + + serial_out(up, UART_IER, up->ier); + + up->lcr = cval; /* Save LCR */ + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void m32r_sio_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + if (up->pm) + up->pm(port, state, oldstate); +} + +/* + * Resource handling. This is complicated by the fact that resources + * depend on the port type. Maybe we should be claiming the standard + * 8250 ports, and then trying to get other resources as necessary? + */ +static int +m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res) +{ + unsigned int size = 8 << up->port.regshift; +#ifndef CONFIG_SERIAL_M32R_PLDSIO + unsigned long start; +#endif + int ret = 0; + + switch (up->port.iotype) { + case UPIO_MEM: + if (up->port.mapbase) { +#ifdef CONFIG_SERIAL_M32R_PLDSIO + *res = request_mem_region(up->port.mapbase, size, "serial"); +#else + start = up->port.mapbase; + *res = request_mem_region(start, size, "serial"); +#endif + if (!*res) + ret = -EBUSY; + } + break; + + case UPIO_PORT: + *res = request_region(up->port.iobase, size, "serial"); + if (!*res) + ret = -EBUSY; + break; + } + return ret; +} + +static void m32r_sio_release_port(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + unsigned long start, offset = 0, size = 0; + + size <<= up->port.regshift; + + switch (up->port.iotype) { + case UPIO_MEM: + if (up->port.mapbase) { + /* + * Unmap the area. + */ + iounmap(up->port.membase); + up->port.membase = NULL; + + start = up->port.mapbase; + + if (size) + release_mem_region(start + offset, size); + release_mem_region(start, 8 << up->port.regshift); + } + break; + + case UPIO_PORT: + start = up->port.iobase; + + if (size) + release_region(start + offset, size); + release_region(start + offset, 8 << up->port.regshift); + break; + + default: + break; + } +} + +static int m32r_sio_request_port(struct uart_port *port) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + struct resource *res = NULL; + int ret = 0; + + ret = m32r_sio_request_std_resource(up, &res); + + /* + * If we have a mapbase, then request that as well. + */ + if (ret == 0 && up->port.flags & UPF_IOREMAP) { + int size = res->end - res->start + 1; + + up->port.membase = ioremap(up->port.mapbase, size); + if (!up->port.membase) + ret = -ENOMEM; + } + + if (ret < 0) { + if (res) + release_resource(res); + } + + return ret; +} + +static void m32r_sio_config_port(struct uart_port *port, int flags) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + 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; + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +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)) + 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, + .get_mctrl = m32r_sio_get_mctrl, + .stop_tx = m32r_sio_stop_tx, + .start_tx = m32r_sio_start_tx, + .stop_rx = m32r_sio_stop_rx, + .enable_ms = m32r_sio_enable_ms, + .break_ctl = m32r_sio_break_ctl, + .startup = m32r_sio_startup, + .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, + .verify_port = m32r_sio_verify_port, +}; + +static struct uart_sio_port m32r_sio_ports[UART_NR]; + +static void __init m32r_sio_init_ports(void) +{ + struct uart_sio_port *up; + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port); + i++, up++) { + up->port.iobase = old_serial_port[i].port; + up->port.irq = irq_canonicalize(old_serial_port[i].irq); + up->port.uartclk = old_serial_port[i].baud_base * 16; + up->port.flags = old_serial_port[i].flags; + up->port.membase = old_serial_port[i].iomem_base; + up->port.iotype = old_serial_port[i].io_type; + up->port.regshift = old_serial_port[i].iomem_reg_shift; + up->port.ops = &m32r_sio_pops; + } +} + +static void __init m32r_sio_register_ports(struct uart_driver *drv) +{ + int i; + + m32r_sio_init_ports(); + + for (i = 0; i < UART_NR; i++) { + struct uart_sio_port *up = &m32r_sio_ports[i]; + + up->port.line = i; + up->port.ops = &m32r_sio_pops; + init_timer(&up->timer); + up->timer.function = m32r_sio_timeout; + + /* + * ALPHA_KLUDGE_MCR needs to be killed. + */ + up->mcr_mask = ~ALPHA_KLUDGE_MCR; + up->mcr_force = ALPHA_KLUDGE_MCR; + + uart_add_one_port(drv, &up->port); + } +} + +#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct uart_sio_port *up) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = sio_in(up, SIOSTS); + + if (--tmout == 0) + break; + udelay(1); + } while ((status & UART_EMPTY) != UART_EMPTY); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout) + udelay(1); + } +} + +static void m32r_sio_console_putchar(struct uart_port *port, int ch) +{ + struct uart_sio_port *up = (struct uart_sio_port *)port; + + wait_for_xmitr(up); + sio_out(up, SIOTXB, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void m32r_sio_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_sio_port *up = &m32r_sio_ports[co->index]; + unsigned int ier; + + /* + * First save the UER then disable the interrupts + */ + ier = sio_in(up, SIOTRCR); + sio_out(up, SIOTRCR, 0); + + uart_console_write(&up->port, s, count, m32r_sio_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + sio_out(up, SIOTRCR, ier); +} + +static int __init m32r_sio_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &m32r_sio_ports[co->index].port; + + /* + * Temporary fix. + */ + spin_lock_init(&port->lock); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver m32r_sio_reg; +static struct console m32r_sio_console = { + .name = "ttyS", + .write = m32r_sio_console_write, + .device = uart_console_device, + .setup = m32r_sio_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &m32r_sio_reg, +}; + +static int __init m32r_sio_console_init(void) +{ + sio_reset(); + sio_init(); + m32r_sio_init_ports(); + register_console(&m32r_sio_console); + return 0; +} +console_initcall(m32r_sio_console_init); + +#define M32R_SIO_CONSOLE &m32r_sio_console +#else +#define M32R_SIO_CONSOLE NULL +#endif + +static struct uart_driver m32r_sio_reg = { + .owner = THIS_MODULE, + .driver_name = "sio", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = UART_NR, + .cons = M32R_SIO_CONSOLE, +}; + +/** + * m32r_sio_suspend_port - suspend one serial port + * @line: serial line number + * + * Suspend one serial port. + */ +void m32r_sio_suspend_port(int line) +{ + uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port); +} + +/** + * m32r_sio_resume_port - resume one serial port + * @line: serial line number + * + * Resume one serial port. + */ +void m32r_sio_resume_port(int line) +{ + uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port); +} + +static int __init m32r_sio_init(void) +{ + int ret, i; + + printk(KERN_INFO "Serial: M32R SIO driver\n"); + + for (i = 0; i < nr_irqs; i++) + spin_lock_init(&irq_lists[i].lock); + + ret = uart_register_driver(&m32r_sio_reg); + if (ret >= 0) + m32r_sio_register_ports(&m32r_sio_reg); + + return ret; +} + +static void __exit m32r_sio_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port); + + uart_unregister_driver(&m32r_sio_reg); +} + +module_init(m32r_sio_init); +module_exit(m32r_sio_exit); + +EXPORT_SYMBOL(m32r_sio_suspend_port); +EXPORT_SYMBOL(m32r_sio_resume_port); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic M32R SIO serial driver"); diff --git a/drivers/tty/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h new file mode 100644 index 000000000000..e9b7e11793b1 --- /dev/null +++ b/drivers/tty/serial/m32r_sio.h @@ -0,0 +1,48 @@ +/* + * m32r_sio.h + * + * Driver for M32R serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/serial/8250.h. + * + * Copyright (C) 2001 Russell King. + * Copyright (C) 2004 Hirokazu Takata + * + * 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. + */ + + +struct m32r_sio_probe { + struct module *owner; + int (*pci_init_one)(struct pci_dev *dev); + void (*pci_remove_one)(struct pci_dev *dev); + void (*pnp_init)(void); +}; + +int m32r_sio_register_probe(struct m32r_sio_probe *probe); +void m32r_sio_unregister_probe(struct m32r_sio_probe *probe); +void m32r_sio_get_irq_map(unsigned int *map); +void m32r_sio_suspend_port(int line); +void m32r_sio_resume_port(int line); + +struct old_serial_port { + unsigned int uart; + unsigned int baud_base; + unsigned int port; + unsigned int irq; + unsigned int flags; + unsigned char io_type; + unsigned char __iomem *iomem_base; + unsigned short iomem_reg_shift; +}; + +#define _INLINE_ inline + +#define PROBE_RSA (1 << 0) +#define PROBE_ANY (~0) + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) diff --git a/drivers/tty/serial/m32r_sio_reg.h b/drivers/tty/serial/m32r_sio_reg.h new file mode 100644 index 000000000000..4671473793e3 --- /dev/null +++ b/drivers/tty/serial/m32r_sio_reg.h @@ -0,0 +1,152 @@ +/* + * m32r_sio_reg.h + * + * Copyright (C) 1992, 1994 by Theodore Ts'o. + * Copyright (C) 2004 Hirokazu Takata + * + * Redistribution of this file is permitted under the terms of the GNU + * Public License (GPL) + * + * These are the UART port assignments, expressed as offsets from the base + * register. These assignments should hold for any serial port based on + * a 8250, 16450, or 16550(A). + */ + +#ifndef _M32R_SIO_REG_H +#define _M32R_SIO_REG_H + + +#ifdef CONFIG_SERIAL_M32R_PLDSIO + +#define SIOCR 0x000 +#define SIOMOD0 0x002 +#define SIOMOD1 0x004 +#define SIOSTS 0x006 +#define SIOTRCR 0x008 +#define SIOBAUR 0x00a +// #define SIORBAUR 0x018 +#define SIOTXB 0x00c +#define SIORXB 0x00e + +#define UART_RX ((unsigned long) PLD_ESIO0RXB) + /* In: Receive buffer (DLAB=0) */ +#define UART_TX ((unsigned long) PLD_ESIO0TXB) + /* Out: Transmit buffer (DLAB=0) */ +#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ +#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx + * In: Fifo count + * Out: Fifo custom trigger levels + * XR16C85x only */ + +#define UART_DLM 0 /* Out: Divisor Latch High (DLAB=1) */ +#define UART_IER ((unsigned long) PLD_ESIO0INTCR) + /* Out: Interrupt Enable Register */ +#define UART_FCTR 0 /* (LCR=BF) Feature Control Register + * XR16C85x only */ + +#define UART_IIR 0 /* In: Interrupt ID Register */ +#define UART_FCR 0 /* Out: FIFO Control Register */ +#define UART_EFR 0 /* I/O: Extended Features Register */ + /* (DLAB=1, 16C660 only) */ + +#define UART_LCR 0 /* Out: Line Control Register */ +#define UART_MCR 0 /* Out: Modem Control Register */ +#define UART_LSR ((unsigned long) PLD_ESIO0STS) + /* In: Line Status Register */ +#define UART_MSR 0 /* In: Modem Status Register */ +#define UART_SCR 0 /* I/O: Scratch Register */ +#define UART_EMSR 0 /* (LCR=BF) Extended Mode Select Register + * FCTR bit 6 selects SCR or EMSR + * XR16c85x only */ + +#else /* not CONFIG_SERIAL_M32R_PLDSIO */ + +#define SIOCR 0x000 +#define SIOMOD0 0x004 +#define SIOMOD1 0x008 +#define SIOSTS 0x00c +#define SIOTRCR 0x010 +#define SIOBAUR 0x014 +#define SIORBAUR 0x018 +#define SIOTXB 0x01c +#define SIORXB 0x020 + +#define UART_RX M32R_SIO0_RXB_PORTL /* In: Receive buffer (DLAB=0) */ +#define UART_TX M32R_SIO0_TXB_PORTL /* Out: Transmit buffer (DLAB=0) */ +#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ +#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx + * In: Fifo count + * Out: Fifo custom trigger levels + * XR16C85x only */ + +#define UART_DLM 0 /* Out: Divisor Latch High (DLAB=1) */ +#define UART_IER M32R_SIO0_TRCR_PORTL /* Out: Interrupt Enable Register */ +#define UART_FCTR 0 /* (LCR=BF) Feature Control Register + * XR16C85x only */ + +#define UART_IIR 0 /* In: Interrupt ID Register */ +#define UART_FCR 0 /* Out: FIFO Control Register */ +#define UART_EFR 0 /* I/O: Extended Features Register */ + /* (DLAB=1, 16C660 only) */ + +#define UART_LCR 0 /* Out: Line Control Register */ +#define UART_MCR 0 /* Out: Modem Control Register */ +#define UART_LSR M32R_SIO0_STS_PORTL /* In: Line Status Register */ +#define UART_MSR 0 /* In: Modem Status Register */ +#define UART_SCR 0 /* I/O: Scratch Register */ +#define UART_EMSR 0 /* (LCR=BF) Extended Mode Select Register + * FCTR bit 6 selects SCR or EMSR + * XR16c85x only */ + +#endif /* CONFIG_SERIAL_M32R_PLDSIO */ + +#define UART_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * These are the definitions for the Line Control Register + * + * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting + * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. + */ +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ +#define UART_LCR_SBC 0x40 /* Set break control */ +#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ +#define UART_LCR_EPAR 0x10 /* Even parity select */ +#define UART_LCR_PARITY 0x08 /* Parity Enable */ +#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */ +#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ +#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ +#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ +#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ + +/* + * These are the definitions for the Line Status Register + */ +#define UART_LSR_TEMT 0x02 /* Transmitter empty */ +#define UART_LSR_THRE 0x01 /* Transmit-hold-register empty */ +#define UART_LSR_BI 0x00 /* Break interrupt indicator */ +#define UART_LSR_FE 0x80 /* Frame error indicator */ +#define UART_LSR_PE 0x40 /* Parity error indicator */ +#define UART_LSR_OE 0x20 /* Overrun error indicator */ +#define UART_LSR_DR 0x04 /* Receiver data ready */ + +/* + * These are the definitions for the Interrupt Identification Register + */ +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ + +/* + * These are the definitions for the Interrupt Enable Register + */ +#define UART_IER_MSI 0x00 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x08 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x03 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x04 /* Enable receiver data interrupt */ + +#endif /* _M32R_SIO_REG_H */ diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c new file mode 100644 index 000000000000..beb1afa27d8d --- /dev/null +++ b/drivers/tty/serial/max3100.c @@ -0,0 +1,926 @@ +/* + * + * Copyright (C) 2008 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. + * + * + * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have + * to use polling for flow control. TX empty IRQ is unusable, since + * writing conf clears FIFO buffer and we cannot have this interrupt + * always asking us for attention. + * + * Example platform data: + + static struct plat_max3100 max3100_plat_data = { + .loopback = 0, + .crystal = 0, + .poll_time = 100, + }; + + static struct spi_board_info spi_board_info[] = { + { + .modalias = "max3100", + .platform_data = &max3100_plat_data, + .irq = IRQ_EINT12, + .max_speed_hz = 5*1000*1000, + .chip_select = 0, + }, + }; + + * The initial minor number is 209 in the low-density serial port: + * mknod /dev/ttyMAX0 c 204 209 + */ + +#define MAX3100_MAJOR 204 +#define MAX3100_MINOR 209 +/* 4 MAX3100s should be enough for everyone */ +#define MAX_MAX3100 4 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX3100_C (1<<14) +#define MAX3100_D (0<<14) +#define MAX3100_W (1<<15) +#define MAX3100_RX (0<<15) + +#define MAX3100_WC (MAX3100_W | MAX3100_C) +#define MAX3100_RC (MAX3100_RX | MAX3100_C) +#define MAX3100_WD (MAX3100_W | MAX3100_D) +#define MAX3100_RD (MAX3100_RX | MAX3100_D) +#define MAX3100_CMD (3 << 14) + +#define MAX3100_T (1<<14) +#define MAX3100_R (1<<15) + +#define MAX3100_FEN (1<<13) +#define MAX3100_SHDN (1<<12) +#define MAX3100_TM (1<<11) +#define MAX3100_RM (1<<10) +#define MAX3100_PM (1<<9) +#define MAX3100_RAM (1<<8) +#define MAX3100_IR (1<<7) +#define MAX3100_ST (1<<6) +#define MAX3100_PE (1<<5) +#define MAX3100_L (1<<4) +#define MAX3100_BAUD (0xf) + +#define MAX3100_TE (1<<10) +#define MAX3100_RAFE (1<<10) +#define MAX3100_RTS (1<<9) +#define MAX3100_CTS (1<<9) +#define MAX3100_PT (1<<8) +#define MAX3100_DATA (0xff) + +#define MAX3100_RT (MAX3100_R | MAX3100_T) +#define MAX3100_RTC (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE) + +/* the following simulate a status reg for ignore_status_mask */ +#define MAX3100_STATUS_PE 1 +#define MAX3100_STATUS_FE 2 +#define MAX3100_STATUS_OE 4 + +struct max3100_port { + struct uart_port port; + struct spi_device *spi; + + int cts; /* last CTS received for flow ctrl */ + int tx_empty; /* last TX empty bit */ + + spinlock_t conf_lock; /* shared data */ + int conf_commit; /* need to make changes */ + int conf; /* configuration for the MAX31000 + * (bits 0-7, bits 8-11 are irqs) */ + int rts_commit; /* need to change rts */ + int rts; /* rts status */ + int baud; /* current baud rate */ + + int parity; /* keeps track if we should send parity */ +#define MAX3100_PARITY_ON 1 +#define MAX3100_PARITY_ODD 2 +#define MAX3100_7BIT 4 + int rx_enabled; /* if we should rx chars */ + + int irq; /* irq assigned to the max3100 */ + + int minor; /* minor number */ + int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ + int loopback; /* 1 if we are in loopback mode */ + + /* for handling irqs: need workqueue since we do spi_sync */ + struct workqueue_struct *workqueue; + struct work_struct work; + /* set to 1 to make the workhandler exit as soon as possible */ + int force_end_work; + /* need to know we are suspending to avoid deadlock on workqueue */ + int suspending; + + /* hook for suspending MAX3100 via dedicated pin */ + void (*max3100_hw_suspend) (int suspend); + + /* poll time (in ms) for ctrl lines */ + int poll_time; + /* and its timer */ + struct timer_list timer; +}; + +static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ +static DEFINE_MUTEX(max3100s_lock); /* race on probe */ + +static int max3100_do_parity(struct max3100_port *s, u16 c) +{ + int parity; + + if (s->parity & MAX3100_PARITY_ODD) + parity = 1; + else + parity = 0; + + if (s->parity & MAX3100_7BIT) + c &= 0x7f; + else + c &= 0xff; + + parity = parity ^ (hweight8(c) & 1); + return parity; +} + +static int max3100_check_parity(struct max3100_port *s, u16 c) +{ + return max3100_do_parity(s, c) == ((c >> 8) & 1); +} + +static void max3100_calc_parity(struct max3100_port *s, u16 *c) +{ + if (s->parity & MAX3100_7BIT) + *c &= 0x7f; + else + *c &= 0xff; + + if (s->parity & MAX3100_PARITY_ON) + *c |= max3100_do_parity(s, *c) << 8; +} + +static void max3100_work(struct work_struct *w); + +static void max3100_dowork(struct max3100_port *s) +{ + if (!s->force_end_work && !work_pending(&s->work) && + !freezing(current) && !s->suspending) + queue_work(s->workqueue, &s->work); +} + +static void max3100_timeout(unsigned long data) +{ + struct max3100_port *s = (struct max3100_port *)data; + + if (s->port.state) { + max3100_dowork(s); + mod_timer(&s->timer, jiffies + s->poll_time); + } +} + +static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) +{ + struct spi_message message; + u16 etx, erx; + int status; + struct spi_transfer tran = { + .tx_buf = &etx, + .rx_buf = &erx, + .len = 2, + }; + + etx = cpu_to_be16(tx); + spi_message_init(&message); + spi_message_add_tail(&tran, &message); + status = spi_sync(s->spi, &message); + if (status) { + dev_warn(&s->spi->dev, "error while calling spi_sync\n"); + return -EIO; + } + *rx = be16_to_cpu(erx); + s->tx_empty = (*rx & MAX3100_T) > 0; + dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx); + return 0; +} + +static int max3100_handlerx(struct max3100_port *s, u16 rx) +{ + unsigned int ch, flg, status = 0; + int ret = 0, cts; + + if (rx & MAX3100_R && s->rx_enabled) { + dev_dbg(&s->spi->dev, "%s\n", __func__); + ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff); + if (rx & MAX3100_RAFE) { + s->port.icount.frame++; + flg = TTY_FRAME; + status |= MAX3100_STATUS_FE; + } else { + if (s->parity & MAX3100_PARITY_ON) { + if (max3100_check_parity(s, rx)) { + s->port.icount.rx++; + flg = TTY_NORMAL; + } else { + s->port.icount.parity++; + flg = TTY_PARITY; + status |= MAX3100_STATUS_PE; + } + } else { + s->port.icount.rx++; + flg = TTY_NORMAL; + } + } + uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg); + ret = 1; + } + + cts = (rx & MAX3100_CTS) > 0; + if (s->cts != cts) { + s->cts = cts; + uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0); + } + + return ret; +} + +static void max3100_work(struct work_struct *w) +{ + struct max3100_port *s = container_of(w, struct max3100_port, work); + int rxchars; + u16 tx, rx; + int conf, cconf, rts, crts; + struct circ_buf *xmit = &s->port.state->xmit; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + rxchars = 0; + do { + spin_lock(&s->conf_lock); + conf = s->conf; + cconf = s->conf_commit; + s->conf_commit = 0; + rts = s->rts; + crts = s->rts_commit; + s->rts_commit = 0; + spin_unlock(&s->conf_lock); + if (cconf) + max3100_sr(s, MAX3100_WC | conf, &rx); + if (crts) { + max3100_sr(s, MAX3100_WD | MAX3100_TE | + (s->rts ? MAX3100_RTS : 0), &rx); + rxchars += max3100_handlerx(s, rx); + } + + max3100_sr(s, MAX3100_RD, &rx); + rxchars += max3100_handlerx(s, rx); + + if (rx & MAX3100_T) { + tx = 0xffff; + if (s->port.x_char) { + tx = s->port.x_char; + s->port.icount.tx++; + s->port.x_char = 0; + } else if (!uart_circ_empty(xmit) && + !uart_tx_stopped(&s->port)) { + tx = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & + (UART_XMIT_SIZE - 1); + s->port.icount.tx++; + } + if (tx != 0xffff) { + max3100_calc_parity(s, &tx); + tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0); + max3100_sr(s, tx, &rx); + rxchars += max3100_handlerx(s, rx); + } + } + + if (rxchars > 16 && s->port.state->port.tty != NULL) { + tty_flip_buffer_push(s->port.state->port.tty); + rxchars = 0; + } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&s->port); + + } while (!s->force_end_work && + !freezing(current) && + ((rx & MAX3100_R) || + (!uart_circ_empty(xmit) && + !uart_tx_stopped(&s->port)))); + + if (rxchars > 0 && s->port.state->port.tty != NULL) + tty_flip_buffer_push(s->port.state->port.tty); +} + +static irqreturn_t max3100_irq(int irqno, void *dev_id) +{ + struct max3100_port *s = dev_id; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + max3100_dowork(s); + return IRQ_HANDLED; +} + +static void max3100_enable_ms(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + if (s->poll_time > 0) + mod_timer(&s->timer, jiffies); + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static void max3100_start_tx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + max3100_dowork(s); +} + +static void max3100_stop_rx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + s->rx_enabled = 0; + spin_lock(&s->conf_lock); + s->conf &= ~MAX3100_RM; + s->conf_commit = 1; + spin_unlock(&s->conf_lock); + max3100_dowork(s); +} + +static unsigned int max3100_tx_empty(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + /* may not be truly up-to-date */ + max3100_dowork(s); + return s->tx_empty; +} + +static unsigned int max3100_get_mctrl(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + /* may not be truly up-to-date */ + max3100_dowork(s); + /* always assert DCD and DSR since these lines are not wired */ + return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR; +} + +static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int rts; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + rts = (mctrl & TIOCM_RTS) > 0; + + spin_lock(&s->conf_lock); + if (s->rts != rts) { + s->rts = rts; + s->rts_commit = 1; + max3100_dowork(s); + } + spin_unlock(&s->conf_lock); +} + +static void +max3100_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int baud = 0; + unsigned cflag; + u32 param_new, param_mask, parity = 0; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + cflag = termios->c_cflag; + param_new = 0; + param_mask = 0; + + baud = tty_termios_baud_rate(termios); + param_new = s->conf & MAX3100_BAUD; + switch (baud) { + case 300: + if (s->crystal) + baud = s->baud; + else + param_new = 15; + break; + case 600: + param_new = 14 + s->crystal; + break; + case 1200: + param_new = 13 + s->crystal; + break; + case 2400: + param_new = 12 + s->crystal; + break; + case 4800: + param_new = 11 + s->crystal; + break; + case 9600: + param_new = 10 + s->crystal; + break; + case 19200: + param_new = 9 + s->crystal; + break; + case 38400: + param_new = 8 + s->crystal; + break; + case 57600: + param_new = 1 + s->crystal; + break; + case 115200: + param_new = 0 + s->crystal; + break; + case 230400: + if (s->crystal) + param_new = 0; + else + baud = s->baud; + break; + default: + baud = s->baud; + } + tty_termios_encode_baud_rate(termios, baud, baud); + s->baud = baud; + param_mask |= MAX3100_BAUD; + + if ((cflag & CSIZE) == CS8) { + param_new &= ~MAX3100_L; + parity &= ~MAX3100_7BIT; + } else { + param_new |= MAX3100_L; + parity |= MAX3100_7BIT; + cflag = (cflag & ~CSIZE) | CS7; + } + param_mask |= MAX3100_L; + + if (cflag & CSTOPB) + param_new |= MAX3100_ST; + else + param_new &= ~MAX3100_ST; + param_mask |= MAX3100_ST; + + if (cflag & PARENB) { + param_new |= MAX3100_PE; + parity |= MAX3100_PARITY_ON; + } else { + param_new &= ~MAX3100_PE; + parity &= ~MAX3100_PARITY_ON; + } + param_mask |= MAX3100_PE; + + if (cflag & PARODD) + parity |= MAX3100_PARITY_ODD; + else + parity &= ~MAX3100_PARITY_ODD; + + /* mask termios capabilities we don't support */ + cflag &= ~CMSPAR; + termios->c_cflag = cflag; + + s->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + s->port.ignore_status_mask |= + MAX3100_STATUS_PE | MAX3100_STATUS_FE | + MAX3100_STATUS_OE; + + /* we are sending char from a workqueue so enable */ + s->port.state->port.tty->low_latency = 1; + + if (s->poll_time > 0) + del_timer_sync(&s->timer); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_lock(&s->conf_lock); + s->conf = (s->conf & ~param_mask) | (param_new & param_mask); + s->conf_commit = 1; + s->parity = parity; + spin_unlock(&s->conf_lock); + max3100_dowork(s); + + if (UART_ENABLE_MS(&s->port, termios->c_cflag)) + max3100_enable_ms(&s->port); +} + +static void max3100_shutdown(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (s->suspending) + return; + + s->force_end_work = 1; + + if (s->poll_time > 0) + del_timer_sync(&s->timer); + + if (s->workqueue) { + flush_workqueue(s->workqueue); + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + } + if (s->irq) + free_irq(s->irq, s); + + /* set shutdown mode to save power */ + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(1); + else { + u16 tx, rx; + + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(s, tx, &rx); + } +} + +static int max3100_startup(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + char b[12]; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + s->conf = MAX3100_RM; + s->baud = s->crystal ? 230400 : 115200; + s->rx_enabled = 1; + + if (s->suspending) + return 0; + + s->force_end_work = 0; + s->parity = 0; + s->rts = 0; + + sprintf(b, "max3100-%d", s->minor); + s->workqueue = create_freezeable_workqueue(b); + if (!s->workqueue) { + dev_warn(&s->spi->dev, "cannot create workqueue\n"); + return -EBUSY; + } + INIT_WORK(&s->work, max3100_work); + + if (request_irq(s->irq, max3100_irq, + IRQF_TRIGGER_FALLING, "max3100", s) < 0) { + dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq); + s->irq = 0; + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + return -EBUSY; + } + + if (s->loopback) { + u16 tx, rx; + tx = 0x4001; + max3100_sr(s, tx, &rx); + } + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(0); + s->conf_commit = 1; + max3100_dowork(s); + /* wait for clock to settle */ + msleep(50); + + max3100_enable_ms(&s->port); + + return 0; +} + +static const char *max3100_type(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL; +} + +static void max3100_release_port(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static void max3100_config_port(struct uart_port *port, int flags) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (flags & UART_CONFIG_TYPE) + s->port.type = PORT_MAX3100; +} + +static int max3100_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int ret = -EINVAL; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100) + ret = 0; + return ret; +} + +static void max3100_stop_tx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static int max3100_request_port(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + return 0; +} + +static void max3100_break_ctl(struct uart_port *port, int break_state) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static struct uart_ops max3100_ops = { + .tx_empty = max3100_tx_empty, + .set_mctrl = max3100_set_mctrl, + .get_mctrl = max3100_get_mctrl, + .stop_tx = max3100_stop_tx, + .start_tx = max3100_start_tx, + .stop_rx = max3100_stop_rx, + .enable_ms = max3100_enable_ms, + .break_ctl = max3100_break_ctl, + .startup = max3100_startup, + .shutdown = max3100_shutdown, + .set_termios = max3100_set_termios, + .type = max3100_type, + .release_port = max3100_release_port, + .request_port = max3100_request_port, + .config_port = max3100_config_port, + .verify_port = max3100_verify_port, +}; + +static struct uart_driver max3100_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "ttyMAX", + .dev_name = "ttyMAX", + .major = MAX3100_MAJOR, + .minor = MAX3100_MINOR, + .nr = MAX_MAX3100, +}; +static int uart_driver_registered; + +static int __devinit max3100_probe(struct spi_device *spi) +{ + int i, retval; + struct plat_max3100 *pdata; + u16 tx, rx; + + mutex_lock(&max3100s_lock); + + if (!uart_driver_registered) { + uart_driver_registered = 1; + retval = uart_register_driver(&max3100_uart_driver); + if (retval) { + printk(KERN_ERR "Couldn't register max3100 uart driver\n"); + mutex_unlock(&max3100s_lock); + return retval; + } + } + + for (i = 0; i < MAX_MAX3100; i++) + if (!max3100s[i]) + break; + if (i == MAX_MAX3100) { + dev_warn(&spi->dev, "too many MAX3100 chips\n"); + mutex_unlock(&max3100s_lock); + return -ENOMEM; + } + + max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); + if (!max3100s[i]) { + dev_warn(&spi->dev, + "kmalloc for max3100 structure %d failed!\n", i); + mutex_unlock(&max3100s_lock); + return -ENOMEM; + } + max3100s[i]->spi = spi; + max3100s[i]->irq = spi->irq; + spin_lock_init(&max3100s[i]->conf_lock); + dev_set_drvdata(&spi->dev, max3100s[i]); + pdata = spi->dev.platform_data; + max3100s[i]->crystal = pdata->crystal; + max3100s[i]->loopback = pdata->loopback; + max3100s[i]->poll_time = pdata->poll_time * HZ / 1000; + if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) + max3100s[i]->poll_time = 1; + max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; + max3100s[i]->minor = i; + init_timer(&max3100s[i]->timer); + max3100s[i]->timer.function = max3100_timeout; + max3100s[i]->timer.data = (unsigned long) max3100s[i]; + + dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); + max3100s[i]->port.irq = max3100s[i]->irq; + max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200; + max3100s[i]->port.fifosize = 16; + max3100s[i]->port.ops = &max3100_ops; + max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + max3100s[i]->port.line = i; + max3100s[i]->port.type = PORT_MAX3100; + max3100s[i]->port.dev = &spi->dev; + retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); + if (retval < 0) + dev_warn(&spi->dev, + "uart_add_one_port failed for line %d with error %d\n", + i, retval); + + /* set shutdown mode to save power. Will be woken-up on open */ + if (max3100s[i]->max3100_hw_suspend) + max3100s[i]->max3100_hw_suspend(1); + else { + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(max3100s[i], tx, &rx); + } + mutex_unlock(&max3100s_lock); + return 0; +} + +static int __devexit max3100_remove(struct spi_device *spi) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + int i; + + mutex_lock(&max3100s_lock); + + /* find out the index for the chip we are removing */ + for (i = 0; i < MAX_MAX3100; i++) + if (max3100s[i] == s) + break; + + dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i); + uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port); + kfree(max3100s[i]); + max3100s[i] = NULL; + + /* check if this is the last chip we have */ + for (i = 0; i < MAX_MAX3100; i++) + if (max3100s[i]) { + mutex_unlock(&max3100s_lock); + return 0; + } + pr_debug("removing max3100 driver\n"); + uart_unregister_driver(&max3100_uart_driver); + + mutex_unlock(&max3100s_lock); + return 0; +} + +#ifdef CONFIG_PM + +static int max3100_suspend(struct spi_device *spi, pm_message_t state) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + disable_irq(s->irq); + + s->suspending = 1; + uart_suspend_port(&max3100_uart_driver, &s->port); + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(1); + else { + /* no HW suspend, so do SW one */ + u16 tx, rx; + + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(s, tx, &rx); + } + return 0; +} + +static int max3100_resume(struct spi_device *spi) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(0); + uart_resume_port(&max3100_uart_driver, &s->port); + s->suspending = 0; + + enable_irq(s->irq); + + s->conf_commit = 1; + if (s->workqueue) + max3100_dowork(s); + + return 0; +} + +#else +#define max3100_suspend NULL +#define max3100_resume NULL +#endif + +static struct spi_driver max3100_driver = { + .driver = { + .name = "max3100", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = max3100_probe, + .remove = __devexit_p(max3100_remove), + .suspend = max3100_suspend, + .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_DESCRIPTION("MAX3100 driver"); +MODULE_AUTHOR("Christian Pellegrin "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:max3100"); diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c new file mode 100644 index 000000000000..a1fe304f2f52 --- /dev/null +++ b/drivers/tty/serial/max3107-aava.c @@ -0,0 +1,344 @@ +/* + * 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" + +/* GPIO direction to input function */ +static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct max3107_port *s = container_of(chip, struct max3107_port, chip); + u16 buf[1]; /* Buffer for SPI transfer */ + + if (offset >= MAX3107_GPIO_COUNT) { + dev_err(&s->spi->dev, "Invalid GPIO\n"); + return -EINVAL; + } + + /* Read current GPIO configuration register */ + buf[0] = MAX3107_GPIOCFG_REG; + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { + dev_err(&s->spi->dev, "SPI transfer GPIO read failed\n"); + return -EIO; + } + buf[0] &= MAX3107_SPI_RX_DATA_MASK; + + /* Set GPIO to input */ + buf[0] &= ~(0x0001 << offset); + + /* Write new GPIO configuration register value */ + buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG); + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, NULL, 2)) { + dev_err(&s->spi->dev, "SPI transfer GPIO write failed\n"); + return -EIO; + } + return 0; +} + +/* GPIO direction to output function */ +static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct max3107_port *s = container_of(chip, struct max3107_port, chip); + u16 buf[2]; /* Buffer for SPI transfers */ + + if (offset >= MAX3107_GPIO_COUNT) { + dev_err(&s->spi->dev, "Invalid GPIO\n"); + return -EINVAL; + } + + /* Read current GPIO configuration and data registers */ + buf[0] = MAX3107_GPIOCFG_REG; + buf[1] = MAX3107_GPIODATA_REG; + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) { + dev_err(&s->spi->dev, "SPI transfer gpio failed\n"); + return -EIO; + } + buf[0] &= MAX3107_SPI_RX_DATA_MASK; + buf[1] &= MAX3107_SPI_RX_DATA_MASK; + + /* Set GPIO to output */ + buf[0] |= (0x0001 << offset); + /* Set value */ + if (value) + buf[1] |= (0x0001 << offset); + else + buf[1] &= ~(0x0001 << offset); + + /* Write new GPIO configuration and data register values */ + buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG); + buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG); + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, NULL, 4)) { + dev_err(&s->spi->dev, + "SPI transfer for GPIO conf data w failed\n"); + return -EIO; + } + return 0; +} + +/* GPIO value query function */ +static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct max3107_port *s = container_of(chip, struct max3107_port, chip); + u16 buf[1]; /* Buffer for SPI transfer */ + + if (offset >= MAX3107_GPIO_COUNT) { + dev_err(&s->spi->dev, "Invalid GPIO\n"); + return -EINVAL; + } + + /* Read current GPIO data register */ + buf[0] = MAX3107_GPIODATA_REG; + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { + dev_err(&s->spi->dev, "SPI transfer GPIO data r failed\n"); + return -EIO; + } + buf[0] &= MAX3107_SPI_RX_DATA_MASK; + + /* Return value */ + return buf[0] & (0x0001 << offset); +} + +/* GPIO value set function */ +static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct max3107_port *s = container_of(chip, struct max3107_port, chip); + u16 buf[2]; /* Buffer for SPI transfers */ + + if (offset >= MAX3107_GPIO_COUNT) { + dev_err(&s->spi->dev, "Invalid GPIO\n"); + return; + } + + /* Read current GPIO configuration registers*/ + buf[0] = MAX3107_GPIODATA_REG; + buf[1] = MAX3107_GPIOCFG_REG; + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) { + dev_err(&s->spi->dev, + "SPI transfer for GPIO data and config read failed\n"); + return; + } + buf[0] &= MAX3107_SPI_RX_DATA_MASK; + buf[1] &= MAX3107_SPI_RX_DATA_MASK; + + if (!(buf[1] & (0x0001 << offset))) { + /* Configured as input, can't set value */ + dev_warn(&s->spi->dev, + "Trying to set value for input GPIO\n"); + return; + } + + /* Set value */ + if (value) + buf[0] |= (0x0001 << offset); + else + buf[0] &= ~(0x0001 << offset); + + /* Write new GPIO data register value */ + buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG); + /* Perform SPI transfer */ + if (max3107_rw(s, (u8 *)buf, NULL, 2)) + dev_err(&s->spi->dev, "SPI transfer GPIO data w failed\n"); +} + +/* GPIO chip data */ +static struct gpio_chip max3107_gpio_chip = { + .owner = THIS_MODULE, + .direction_input = max3107_gpio_direction_in, + .direction_output = max3107_gpio_direction_out, + .get = max3107_gpio_get, + .set = max3107_gpio_set, + .can_sleep = 1, + .base = MAX3107_GPIO_BASE, + .ngpio = MAX3107_GPIO_COUNT, +}; + +/** + * max3107_aava_reset - reset on AAVA systems + * @spi: The SPI device we are probing + * + * Reset the device ready for probing. + */ + +static int max3107_aava_reset(struct spi_device *spi) +{ + /* Reset the chip */ + if (gpio_request(MAX3107_RESET_GPIO, "max3107")) { + pr_err("Requesting RESET GPIO failed\n"); + return -EIO; + } + if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) { + pr_err("Setting RESET GPIO to 0 failed\n"); + gpio_free(MAX3107_RESET_GPIO); + return -EIO; + } + msleep(MAX3107_RESET_DELAY); + if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) { + pr_err("Setting RESET GPIO to 1 failed\n"); + gpio_free(MAX3107_RESET_GPIO); + return -EIO; + } + gpio_free(MAX3107_RESET_GPIO); + msleep(MAX3107_WAKEUP_DELAY); + return 0; +} + +static int max3107_aava_configure(struct max3107_port *s) +{ + int retval; + + /* Initialize GPIO chip data */ + s->chip = max3107_gpio_chip; + s->chip.label = s->spi->modalias; + s->chip.dev = &s->spi->dev; + + /* Add GPIO chip */ + retval = gpiochip_add(&s->chip); + if (retval) { + dev_err(&s->spi->dev, "Adding GPIO chip failed\n"); + return retval; + } + + /* Temporary fix for EV2 boot problems, set modem reset to 0 */ + max3107_gpio_direction_out(&s->chip, 3, 0); + return 0; +} + +#if 0 +/* This will get enabled once we have the board stuff merged for this + specific case */ + +static const struct baud_table brg13_ext[] = { + { 300, MAX3107_BRG13_B300 }, + { 600, MAX3107_BRG13_B600 }, + { 1200, MAX3107_BRG13_B1200 }, + { 2400, MAX3107_BRG13_B2400 }, + { 4800, MAX3107_BRG13_B4800 }, + { 9600, MAX3107_BRG13_B9600 }, + { 19200, MAX3107_BRG13_B19200 }, + { 57600, MAX3107_BRG13_B57600 }, + { 115200, MAX3107_BRG13_B115200 }, + { 230400, MAX3107_BRG13_B230400 }, + { 460800, MAX3107_BRG13_B460800 }, + { 921600, MAX3107_BRG13_B921600 }, + { 0, 0 } +}; + +static void max3107_aava_init(struct max3107_port *s) +{ + /*override for AAVA SC specific*/ + if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) { + if (get_koski_build_id() <= KOSKI_EV2) + if (s->ext_clk) { + s->brg_cfg = MAX3107_BRG13_B9600; + s->baud_tbl = (struct baud_table *)brg13_ext; + } + } +} +#endif + +static int __devexit max3107_aava_remove(struct spi_device *spi) +{ + struct max3107_port *s = dev_get_drvdata(&spi->dev); + + /* Remove GPIO chip */ + if (gpiochip_remove(&s->chip)) + dev_warn(&spi->dev, "Removing GPIO chip failed\n"); + + /* Then do the default remove */ + return max3107_remove(spi); +} + +/* Platform data */ +static struct max3107_plat aava_plat_data = { + .loopback = 0, + .ext_clk = 1, +/* .init = max3107_aava_init, */ + .configure = max3107_aava_configure, + .hw_suspend = max3107_hw_susp, + .polled_mode = 0, + .poll_time = 0, +}; + + +static int __devinit max3107_probe_aava(struct spi_device *spi) +{ + int err = max3107_aava_reset(spi); + if (err < 0) + return err; + return max3107_probe(spi, &aava_plat_data); +} + +/* Spi driver data */ +static struct spi_driver max3107_driver = { + .driver = { + .name = "aava-max3107", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = max3107_probe_aava, + .remove = __devexit_p(max3107_aava_remove), + .suspend = max3107_suspend, + .resume = max3107_resume, +}; + +/* Driver init function */ +static int __init max3107_init(void) +{ + return spi_register_driver(&max3107_driver); +} + +/* Driver exit function */ +static void __exit max3107_exit(void) +{ + spi_unregister_driver(&max3107_driver); +} + +module_init(max3107_init); +module_exit(max3107_exit); + +MODULE_DESCRIPTION("MAX3107 driver"); +MODULE_AUTHOR("Aavamobile"); +MODULE_ALIAS("aava-max3107-spi"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c new file mode 100644 index 000000000000..910870edf708 --- /dev/null +++ b/drivers/tty/serial/max3107.c @@ -0,0 +1,1213 @@ +/* + * 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 "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_freezeable_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", + .bus = &spi_bus_type, + .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("max3107-spi"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h new file mode 100644 index 000000000000..7ab632392502 --- /dev/null +++ b/drivers/tty/serial/max3107.h @@ -0,0 +1,441 @@ +/* + * 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 stucture */ + 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/mcf.c b/drivers/tty/serial/mcf.c new file mode 100644 index 000000000000..3394b7cc1722 --- /dev/null +++ b/drivers/tty/serial/mcf.c @@ -0,0 +1,662 @@ +/****************************************************************************/ + +/* + * mcf.c -- Freescale ColdFire UART driver + * + * (C) Copyright 2003-2007, 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. + */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ + +/* + * Some boards implement the DTR/DCD lines using GPIO lines, most + * don't. Dummy out the access macros for those that don't. Those + * that do should define these macros somewhere in there board + * specific inlude files. + */ +#if !defined(mcf_getppdcd) +#define mcf_getppdcd(p) (1) +#endif +#if !defined(mcf_getppdtr) +#define mcf_getppdtr(p) (1) +#endif +#if !defined(mcf_setppdtr) +#define mcf_setppdtr(p, v) do { } while (0) +#endif + +/****************************************************************************/ + +/* + * Local per-uart structure. + */ +struct mcf_uart { + struct uart_port port; + unsigned int sigs; /* Local copy of line sigs */ + unsigned char imr; /* Local IMR mirror */ +}; + +/****************************************************************************/ + +static unsigned int mcf_tx_empty(struct uart_port *port) +{ + return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ? + TIOCSER_TEMT : 0; +} + +/****************************************************************************/ + +static unsigned int mcf_get_mctrl(struct uart_port *port) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned int sigs; + + sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ? + 0 : TIOCM_CTS; + sigs |= (pp->sigs & TIOCM_RTS); + sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); + sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); + + return sigs; +} + +/****************************************************************************/ + +static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + + pp->sigs = sigs; + mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); + if (sigs & TIOCM_RTS) + writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); + else + writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0); +} + +/****************************************************************************/ + +static void mcf_start_tx(struct uart_port *port) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + + pp->imr |= MCFUART_UIR_TXREADY; + writeb(pp->imr, port->membase + MCFUART_UIMR); +} + +/****************************************************************************/ + +static void mcf_stop_tx(struct uart_port *port) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + + pp->imr &= ~MCFUART_UIR_TXREADY; + writeb(pp->imr, port->membase + MCFUART_UIMR); +} + +/****************************************************************************/ + +static void mcf_stop_rx(struct uart_port *port) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + + pp->imr &= ~MCFUART_UIR_RXREADY; + writeb(pp->imr, port->membase + MCFUART_UIMR); +} + +/****************************************************************************/ + +static void mcf_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR); + else + writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +static void mcf_enable_ms(struct uart_port *port) +{ +} + +/****************************************************************************/ + +static int mcf_startup(struct uart_port *port) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* Reset UART, get it into known state... */ + writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); + writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); + + /* Enable the UART transmitter and receiver */ + writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, + port->membase + MCFUART_UCR); + + /* Enable RX interrupts now */ + pp->imr = MCFUART_UIR_RXREADY; + writeb(pp->imr, port->membase + MCFUART_UIMR); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +/****************************************************************************/ + +static void mcf_shutdown(struct uart_port *port) +{ + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* Disable all interrupts now */ + pp->imr = 0; + writeb(pp->imr, port->membase + MCFUART_UIMR); + + /* Disable UART transmitter and receiver */ + writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); + writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, baudclk; +#if defined(CONFIG_M5272) + unsigned int baudfr; +#endif + unsigned char mr1, mr2; + + baud = uart_get_baud_rate(port, termios, old, 0, 230400); +#if defined(CONFIG_M5272) + baudclk = (MCF_BUSCLK / baud) / 32; + baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16; +#else + baudclk = ((MCF_BUSCLK / baud) + 16) / 32; +#endif + + mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; + mr2 = 0; + + switch (termios->c_cflag & CSIZE) { + case CS5: mr1 |= MCFUART_MR1_CS5; break; + case CS6: mr1 |= MCFUART_MR1_CS6; break; + case CS7: mr1 |= MCFUART_MR1_CS7; break; + case CS8: + default: mr1 |= MCFUART_MR1_CS8; break; + } + + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & CMSPAR) { + if (termios->c_cflag & PARODD) + mr1 |= MCFUART_MR1_PARITYMARK; + else + mr1 |= MCFUART_MR1_PARITYSPACE; + } else { + if (termios->c_cflag & PARODD) + mr1 |= MCFUART_MR1_PARITYODD; + else + mr1 |= MCFUART_MR1_PARITYEVEN; + } + } else { + mr1 |= MCFUART_MR1_PARITYNONE; + } + + if (termios->c_cflag & CSTOPB) + mr2 |= MCFUART_MR2_STOP2; + else + mr2 |= MCFUART_MR2_STOP1; + + if (termios->c_cflag & CRTSCTS) { + mr1 |= MCFUART_MR1_RXRTS; + mr2 |= MCFUART_MR2_TXCTS; + } + + spin_lock_irqsave(&port->lock, flags); + uart_update_timeout(port, termios->c_cflag, baud); + writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); + writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); + writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR); + writeb(mr1, port->membase + MCFUART_UMR); + writeb(mr2, port->membase + MCFUART_UMR); + writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1); + writeb((baudclk & 0xff), port->membase + MCFUART_UBG2); +#if defined(CONFIG_M5272) + writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD); +#endif + writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER, + port->membase + MCFUART_UCSR); + writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, + port->membase + MCFUART_UCR); + spin_unlock_irqrestore(&port->lock, flags); +} + +/****************************************************************************/ + +static void mcf_rx_chars(struct mcf_uart *pp) +{ + struct uart_port *port = &pp->port; + unsigned char status, ch, flag; + + while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { + ch = readb(port->membase + MCFUART_URB); + flag = TTY_NORMAL; + port->icount.rx++; + + if (status & MCFUART_USR_RXERR) { + writeb(MCFUART_UCR_CMDRESETERR, + port->membase + MCFUART_UCR); + + if (status & MCFUART_USR_RXBREAK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (status & MCFUART_USR_RXPARITY) { + port->icount.parity++; + } else if (status & MCFUART_USR_RXOVERRUN) { + port->icount.overrun++; + } else if (status & MCFUART_USR_RXFRAMING) { + port->icount.frame++; + } + + status &= port->read_status_mask; + + if (status & MCFUART_USR_RXBREAK) + flag = TTY_BREAK; + else if (status & MCFUART_USR_RXPARITY) + flag = TTY_PARITY; + else if (status & MCFUART_USR_RXFRAMING) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); + } + + tty_flip_buffer_push(port->state->port.tty); +} + +/****************************************************************************/ + +static void mcf_tx_chars(struct mcf_uart *pp) +{ + struct uart_port *port = &pp->port; + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + /* Send special char - probably flow control */ + writeb(port->x_char, port->membase + MCFUART_UTB); + port->x_char = 0; + port->icount.tx++; + return; + } + + while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { + if (xmit->head == xmit->tail) + break; + writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (xmit->head == xmit->tail) { + pp->imr &= ~MCFUART_UIR_TXREADY; + writeb(pp->imr, port->membase + MCFUART_UIMR); + } +} + +/****************************************************************************/ + +static irqreturn_t mcf_interrupt(int irq, void *data) +{ + struct uart_port *port = data; + struct mcf_uart *pp = container_of(port, struct mcf_uart, port); + unsigned int isr; + irqreturn_t ret = IRQ_NONE; + + isr = readb(port->membase + MCFUART_UISR) & pp->imr; + + spin_lock(&port->lock); + if (isr & MCFUART_UIR_RXREADY) { + mcf_rx_chars(pp); + ret = IRQ_HANDLED; + } + if (isr & MCFUART_UIR_TXREADY) { + mcf_tx_chars(pp); + ret = IRQ_HANDLED; + } + spin_unlock(&port->lock); + + return ret; +} + +/****************************************************************************/ + +static void mcf_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_MCF; + port->fifosize = MCFUART_TXFIFOSIZE; + + /* Clear mask, so no surprise interrupts. */ + writeb(0, port->membase + MCFUART_UIMR); + + if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port)) + printk(KERN_ERR "MCF: unable to attach ColdFire UART %d " + "interrupt vector=%d\n", port->line, port->irq); +} + +/****************************************************************************/ + +static const char *mcf_type(struct uart_port *port) +{ + return (port->type == PORT_MCF) ? "ColdFire UART" : NULL; +} + +/****************************************************************************/ + +static int mcf_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +/****************************************************************************/ + +static void mcf_release_port(struct uart_port *port) +{ + /* Nothing to release... */ +} + +/****************************************************************************/ + +static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF)) + return -EINVAL; + return 0; +} + +/****************************************************************************/ + +/* + * Define the basic serial functions we support. + */ +static const struct uart_ops mcf_uart_ops = { + .tx_empty = mcf_tx_empty, + .get_mctrl = mcf_get_mctrl, + .set_mctrl = mcf_set_mctrl, + .start_tx = mcf_start_tx, + .stop_tx = mcf_stop_tx, + .stop_rx = mcf_stop_rx, + .enable_ms = mcf_enable_ms, + .break_ctl = mcf_break_ctl, + .startup = mcf_startup, + .shutdown = mcf_shutdown, + .set_termios = mcf_set_termios, + .type = mcf_type, + .request_port = mcf_request_port, + .release_port = mcf_release_port, + .config_port = mcf_config_port, + .verify_port = mcf_verify_port, +}; + +static struct mcf_uart mcf_ports[4]; + +#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) + +/****************************************************************************/ +#if defined(CONFIG_SERIAL_MCF_CONSOLE) +/****************************************************************************/ + +int __init early_mcf_setup(struct mcf_platform_uart *platp) +{ + struct uart_port *port; + int i; + + for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { + port = &mcf_ports[i].port; + + port->line = i; + port->type = PORT_MCF; + port->mapbase = platp[i].mapbase; + port->membase = (platp[i].membase) ? platp[i].membase : + (unsigned char __iomem *) port->mapbase; + port->iotype = SERIAL_IO_MEM; + port->irq = platp[i].irq; + port->uartclk = MCF_BUSCLK; + port->flags = ASYNC_BOOT_AUTOCONF; + port->ops = &mcf_uart_ops; + } + + return 0; +} + +/****************************************************************************/ + +static void mcf_console_putc(struct console *co, const char c) +{ + struct uart_port *port = &(mcf_ports + co->index)->port; + int i; + + for (i = 0; (i < 0x10000); i++) { + if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) + break; + } + writeb(c, port->membase + MCFUART_UTB); + for (i = 0; (i < 0x10000); i++) { + if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) + break; + } +} + +/****************************************************************************/ + +static void mcf_console_write(struct console *co, const char *s, unsigned int count) +{ + for (; (count); count--, s++) { + mcf_console_putc(co, *s); + if (*s == '\n') + mcf_console_putc(co, '\r'); + } +} + +/****************************************************************************/ + +static int __init mcf_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = CONFIG_SERIAL_MCF_BAUDRATE; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if ((co->index < 0) || (co->index >= MCF_MAXPORTS)) + co->index = 0; + port = &mcf_ports[co->index].port; + if (port->membase == 0) + 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 mcf_driver; + +static struct console mcf_console = { + .name = "ttyS", + .write = mcf_console_write, + .device = uart_console_device, + .setup = mcf_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &mcf_driver, +}; + +static int __init mcf_console_init(void) +{ + register_console(&mcf_console); + return 0; +} + +console_initcall(mcf_console_init); + +#define MCF_CONSOLE &mcf_console + +/****************************************************************************/ +#else +/****************************************************************************/ + +#define MCF_CONSOLE NULL + +/****************************************************************************/ +#endif /* CONFIG_MCF_CONSOLE */ +/****************************************************************************/ + +/* + * Define the mcf UART driver structure. + */ +static struct uart_driver mcf_driver = { + .owner = THIS_MODULE, + .driver_name = "mcf", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = MCF_MAXPORTS, + .cons = MCF_CONSOLE, +}; + +/****************************************************************************/ + +static int __devinit mcf_probe(struct platform_device *pdev) +{ + struct mcf_platform_uart *platp = pdev->dev.platform_data; + struct uart_port *port; + int i; + + for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { + port = &mcf_ports[i].port; + + port->line = i; + port->type = PORT_MCF; + port->mapbase = platp[i].mapbase; + port->membase = (platp[i].membase) ? platp[i].membase : + (unsigned char __iomem *) platp[i].mapbase; + port->iotype = SERIAL_IO_MEM; + port->irq = platp[i].irq; + port->uartclk = MCF_BUSCLK; + port->ops = &mcf_uart_ops; + port->flags = ASYNC_BOOT_AUTOCONF; + + uart_add_one_port(&mcf_driver, port); + } + + return 0; +} + +/****************************************************************************/ + +static int __devexit mcf_remove(struct platform_device *pdev) +{ + struct uart_port *port; + int i; + + for (i = 0; (i < MCF_MAXPORTS); i++) { + port = &mcf_ports[i].port; + if (port) + uart_remove_one_port(&mcf_driver, port); + } + + return 0; +} + +/****************************************************************************/ + +static struct platform_driver mcf_platform_driver = { + .probe = mcf_probe, + .remove = __devexit_p(mcf_remove), + .driver = { + .name = "mcfuart", + .owner = THIS_MODULE, + }, +}; + +/****************************************************************************/ + +static int __init mcf_init(void) +{ + int rc; + + printk("ColdFire internal UART serial driver\n"); + + rc = uart_register_driver(&mcf_driver); + if (rc) + return rc; + rc = platform_driver_register(&mcf_platform_driver); + if (rc) + return rc; + return 0; +} + +/****************************************************************************/ + +static void __exit mcf_exit(void) +{ + platform_driver_unregister(&mcf_platform_driver); + uart_unregister_driver(&mcf_driver); +} + +/****************************************************************************/ + +module_init(mcf_init); +module_exit(mcf_exit); + +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("Freescale ColdFire UART driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mcfuart"); + +/****************************************************************************/ diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c new file mode 100644 index 000000000000..d40010a22ecd --- /dev/null +++ b/drivers/tty/serial/mfd.c @@ -0,0 +1,1513 @@ +/* + * mfd.c: driver for High Speed UART device of Intel Medfield platform + * + * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ + * + * (C) Copyright 2010 Intel Corporation + * + * 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; version 2 + * of the License. + */ + +/* Notes: + * 1. DMA channel allocation: 0/1 channel are assigned to port 0, + * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans + * are used for RX, odd chans for TX + * + * 2. In A0 stepping, UART will not support TX half empty flag + * + * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always + * asserted, only when the HW is reset the DDCD and DDSR will + * be triggered + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MFD_HSU_A0_STEPPING 1 + +#define HSU_DMA_BUF_SIZE 2048 + +#define chan_readl(chan, offset) readl(chan->reg + offset) +#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) + +#define mfd_readl(obj, offset) readl(obj->reg + offset) +#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) + +#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10) + +struct hsu_dma_buffer { + u8 *buf; + dma_addr_t dma_addr; + u32 dma_size; + u32 ofs; +}; + +struct hsu_dma_chan { + u32 id; + enum dma_data_direction dirt; + struct uart_hsu_port *uport; + void __iomem *reg; + struct timer_list rx_timer; /* only needed by RX channel */ +}; + +struct uart_hsu_port { + struct uart_port port; + unsigned char ier; + unsigned char lcr; + unsigned char mcr; + unsigned int lsr_break_flag; + char name[12]; + int index; + struct device *dev; + + struct hsu_dma_chan *txc; + struct hsu_dma_chan *rxc; + struct hsu_dma_buffer txbuf; + struct hsu_dma_buffer rxbuf; + int use_dma; /* flag for DMA/PIO */ + int running; + int dma_tx_on; +}; + +/* Top level data structure of HSU */ +struct hsu_port { + void __iomem *reg; + unsigned long paddr; + unsigned long iolen; + u32 irq; + + struct uart_hsu_port port[3]; + struct hsu_dma_chan chans[10]; + + struct dentry *debugfs; +}; + +static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) +{ + unsigned int val; + + if (offset > UART_MSR) { + offset <<= 2; + val = readl(up->port.membase + offset); + } else + val = (unsigned int)readb(up->port.membase + offset); + + return val; +} + +static inline void serial_out(struct uart_hsu_port *up, int offset, int value) +{ + if (offset > UART_MSR) { + offset <<= 2; + writel(value, up->port.membase + offset); + } else { + unsigned char val = value & 0xff; + writeb(val, up->port.membase + offset); + } +} + +#ifdef CONFIG_DEBUG_FS + +#define HSU_REGS_BUFSIZE 1024 + +static int hsu_show_regs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t port_show_regs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct uart_hsu_port *up = file->private_data; + char *buf; + u32 len = 0; + ssize_t ret; + + buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); + if (!buf) + return 0; + + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "MFD HSU port[%d] regs:\n", up->index); + + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "=================================\n"); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); + + if (len > HSU_REGS_BUFSIZE) + len = HSU_REGS_BUFSIZE; + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret; +} + +static ssize_t dma_show_regs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hsu_dma_chan *chan = file->private_data; + char *buf; + u32 len = 0; + ssize_t ret; + + buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); + if (!buf) + return 0; + + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "MFD HSU DMA channel [%d] regs:\n", chan->id); + + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "=================================\n"); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); + len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, + "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); + + if (len > HSU_REGS_BUFSIZE) + len = HSU_REGS_BUFSIZE; + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret; +} + +static const struct file_operations port_regs_ops = { + .owner = THIS_MODULE, + .open = hsu_show_regs_open, + .read = port_show_regs, + .llseek = default_llseek, +}; + +static const struct file_operations dma_regs_ops = { + .owner = THIS_MODULE, + .open = hsu_show_regs_open, + .read = dma_show_regs, + .llseek = default_llseek, +}; + +static int hsu_debugfs_init(struct hsu_port *hsu) +{ + int i; + char name[32]; + + hsu->debugfs = debugfs_create_dir("hsu", NULL); + if (!hsu->debugfs) + return -ENOMEM; + + for (i = 0; i < 3; i++) { + snprintf(name, sizeof(name), "port_%d_regs", i); + debugfs_create_file(name, S_IFREG | S_IRUGO, + hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); + } + + for (i = 0; i < 6; i++) { + snprintf(name, sizeof(name), "dma_chan_%d_regs", i); + debugfs_create_file(name, S_IFREG | S_IRUGO, + hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); + } + + return 0; +} + +static void hsu_debugfs_remove(struct hsu_port *hsu) +{ + if (hsu->debugfs) + debugfs_remove_recursive(hsu->debugfs); +} + +#else +static inline int hsu_debugfs_init(struct hsu_port *hsu) +{ + return 0; +} + +static inline void hsu_debugfs_remove(struct hsu_port *hsu) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +static void serial_hsu_enable_ms(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +} + +void hsu_dma_tx(struct uart_hsu_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + struct hsu_dma_buffer *dbuf = &up->txbuf; + int count; + + /* test_and_set_bit may be better, but anyway it's in lock protected mode */ + if (up->dma_tx_on) + return; + + /* Update the circ buf info */ + xmit->tail += dbuf->ofs; + xmit->tail &= UART_XMIT_SIZE - 1; + + up->port.icount.tx += dbuf->ofs; + dbuf->ofs = 0; + + /* Disable the channel */ + chan_writel(up->txc, HSU_CH_CR, 0x0); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { + dma_sync_single_for_device(up->port.dev, + dbuf->dma_addr, + dbuf->dma_size, + DMA_TO_DEVICE); + + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + dbuf->ofs = count; + + /* Reprogram the channel */ + chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); + chan_writel(up->txc, HSU_CH_D0TSR, count); + + /* Reenable the channel */ + chan_writel(up->txc, HSU_CH_DCR, 0x1 + | (0x1 << 8) + | (0x1 << 16) + | (0x1 << 24)); + up->dma_tx_on = 1; + chan_writel(up->txc, HSU_CH_CR, 0x1); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); +} + +/* The buffer is already cache coherent */ +void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) +{ + dbuf->ofs = 0; + + chan_writel(rxc, HSU_CH_BSR, 32); + chan_writel(rxc, HSU_CH_MOTSR, 4); + + chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); + chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); + chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) + | (0x1 << 16) + | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ + ); + chan_writel(rxc, HSU_CH_CR, 0x3); + + mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); +} + +/* Protected by spin_lock_irqsave(port->lock) */ +static void serial_hsu_start_tx(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + + if (up->use_dma) { + hsu_dma_tx(up); + } else if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void serial_hsu_stop_tx(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + struct hsu_dma_chan *txc = up->txc; + + if (up->use_dma) + chan_writel(txc, HSU_CH_CR, 0x0); + else if (up->ier & UART_IER_THRI) { + up->ier &= ~UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +/* This is always called in spinlock protected mode, so + * modify timeout timer is safe here */ +void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) +{ + struct hsu_dma_buffer *dbuf = &up->rxbuf; + struct hsu_dma_chan *chan = up->rxc; + struct uart_port *port = &up->port; + struct tty_struct *tty = port->state->port.tty; + int count; + + if (!tty) + return; + + /* + * First need to know how many is already transferred, + * then check if its a timeout DMA irq, and return + * the trail bytes out, push them up and reenable the + * channel + */ + + /* Timeout IRQ, need wait some time, see Errata 2 */ + if (int_sts & 0xf00) + udelay(2); + + /* Stop the channel */ + chan_writel(chan, HSU_CH_CR, 0x0); + + count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; + if (!count) { + /* Restart the channel before we leave */ + chan_writel(chan, HSU_CH_CR, 0x3); + return; + } + del_timer(&chan->rx_timer); + + dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, + dbuf->dma_size, DMA_FROM_DEVICE); + + /* + * Head will only wrap around when we recycle + * the DMA buffer, and when that happens, we + * explicitly set tail to 0. So head will + * always be greater than tail. + */ + tty_insert_flip_string(tty, dbuf->buf, count); + port->icount.rx += count; + + dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, + dbuf->dma_size, DMA_FROM_DEVICE); + + /* Reprogram the channel */ + chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); + chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); + chan_writel(chan, HSU_CH_DCR, 0x1 + | (0x1 << 8) + | (0x1 << 16) + | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ + ); + tty_flip_buffer_push(tty); + + chan_writel(chan, HSU_CH_CR, 0x3); + chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ; + add_timer(&chan->rx_timer); + +} + +static void serial_hsu_stop_rx(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + struct hsu_dma_chan *chan = up->rxc; + + if (up->use_dma) + chan_writel(chan, HSU_CH_CR, 0x2); + else { + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); + } +} + +static inline void receive_chars(struct uart_hsu_port *up, int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned int ch, flag; + unsigned int max_count = 256; + + if (!tty) + return; + + do { + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + + dev_warn(up->dev, "We really rush into ERR/BI case" + "status = 0x%02x", *status); + /* For statistics only */ + if (*status & UART_LSR_BI) { + *status &= ~(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 (*status & UART_LSR_PE) + up->port.icount.parity++; + else if (*status & UART_LSR_FE) + up->port.icount.frame++; + if (*status & UART_LSR_OE) + up->port.icount.overrun++; + + /* Mask off conditions which should be ignored. */ + *status &= up->port.read_status_mask; + +#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE + if (up->port.cons && + up->port.cons->index == up->port.line) { + /* Recover the break flag from console xmit */ + *status |= up->lsr_break_flag; + up->lsr_break_flag = 0; + } +#endif + if (*status & UART_LSR_BI) { + flag = TTY_BREAK; + } else if (*status & UART_LSR_PE) + flag = TTY_PARITY; + else if (*status & UART_LSR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + + uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); + ignore_char: + *status = serial_in(up, UART_LSR); + } while ((*status & UART_LSR_DR) && max_count--); + tty_flip_buffer_push(tty); +} + +static void transmit_chars(struct uart_hsu_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { + serial_out(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + serial_hsu_stop_tx(&up->port); + return; + } + +#ifndef MFD_HSU_A0_STEPPING + count = up->port.fifosize / 2; +#else + /* + * A0 only supports fully empty IRQ, and the first char written + * into it won't clear the EMPT bit, so we may need be cautious + * by useing a shorter buffer + */ + count = up->port.fifosize - 4; +#endif + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) + serial_hsu_stop_tx(&up->port); +} + +static inline void check_modem_status(struct uart_hsu_port *up) +{ + int status; + + status = serial_in(up, UART_MSR); + + if ((status & UART_MSR_ANY_DELTA) == 0) + return; + + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + /* We may only get DDCD when HW init and reset */ + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + /* Will start/stop_tx accordingly */ + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); +} + +/* + * This handles the interrupt from one port. + */ +static irqreturn_t port_irq(int irq, void *dev_id) +{ + struct uart_hsu_port *up = dev_id; + unsigned int iir, lsr; + unsigned long flags; + + if (unlikely(!up->running)) + return IRQ_NONE; + + spin_lock_irqsave(&up->port.lock, flags); + if (up->use_dma) { + lsr = serial_in(up, UART_LSR); + if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) + dev_warn(up->dev, + "Got lsr irq while using DMA, lsr = 0x%2x\n", + lsr); + check_modem_status(up); + spin_unlock_irqrestore(&up->port.lock, flags); + return IRQ_HANDLED; + } + + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) { + spin_unlock_irqrestore(&up->port.lock, flags); + return IRQ_NONE; + } + + lsr = serial_in(up, UART_LSR); + if (lsr & UART_LSR_DR) + receive_chars(up, &lsr); + check_modem_status(up); + + /* lsr will be renewed during the receive_chars */ + if (lsr & UART_LSR_THRE) + transmit_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + return IRQ_HANDLED; +} + +static inline void dma_chan_irq(struct hsu_dma_chan *chan) +{ + struct uart_hsu_port *up = chan->uport; + unsigned long flags; + u32 int_sts; + + spin_lock_irqsave(&up->port.lock, flags); + + if (!up->use_dma || !up->running) + goto exit; + + /* + * No matter what situation, need read clear the IRQ status + * There is a bug, see Errata 5, HSD 2900918 + */ + int_sts = chan_readl(chan, HSU_CH_SR); + + /* Rx channel */ + if (chan->dirt == DMA_FROM_DEVICE) + hsu_dma_rx(up, int_sts); + + /* Tx channel */ + if (chan->dirt == DMA_TO_DEVICE) { + chan_writel(chan, HSU_CH_CR, 0x0); + up->dma_tx_on = 0; + hsu_dma_tx(up); + } + +exit: + spin_unlock_irqrestore(&up->port.lock, flags); + return; +} + +static irqreturn_t dma_irq(int irq, void *dev_id) +{ + struct hsu_port *hsu = dev_id; + u32 int_sts, i; + + int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); + + /* Currently we only have 6 channels may be used */ + for (i = 0; i < 6; i++) { + if (int_sts & 0x1) + dma_chan_irq(&hsu->chans[i]); + int_sts >>= 1; + } + + return IRQ_HANDLED; +} + +static unsigned int serial_hsu_tx_empty(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + unsigned long flags; + unsigned int ret; + + 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); + + return ret; +} + +static unsigned int serial_hsu_get_mctrl(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + unsigned char status; + unsigned int ret; + + status = serial_in(up, UART_MSR); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr |= up->mcr; + + serial_out(up, UART_MCR, mcr); +} + +static void serial_hsu_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +/* + * What special to do: + * 1. chose the 64B fifo mode + * 2. make sure not to select half empty mode for A0 stepping + * 3. start dma or pio depends on configuration + * 4. we only allocate dma memory when needed + */ +static int serial_hsu_startup(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + unsigned long flags; + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); + + /* Clear the interrupt registers. */ + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + + /* Now, initialize the UART, default is 8n1 */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&up->port.lock, flags); + + up->port.mctrl |= TIOCM_OUT2; + serial_hsu_set_mctrl(&up->port, up->port.mctrl); + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + if (!up->use_dma) + up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; + else + up->ier = 0; + serial_out(up, UART_IER, up->ier); + + spin_unlock_irqrestore(&up->port.lock, flags); + + /* DMA init */ + if (up->use_dma) { + struct hsu_dma_buffer *dbuf; + struct circ_buf *xmit = &port->state->xmit; + + up->dma_tx_on = 0; + + /* First allocate the RX buffer */ + dbuf = &up->rxbuf; + dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); + if (!dbuf->buf) { + up->use_dma = 0; + goto exit; + } + dbuf->dma_addr = dma_map_single(port->dev, + dbuf->buf, + HSU_DMA_BUF_SIZE, + DMA_FROM_DEVICE); + dbuf->dma_size = HSU_DMA_BUF_SIZE; + + /* Start the RX channel right now */ + hsu_dma_start_rx_chan(up->rxc, dbuf); + + /* Next init the TX DMA */ + dbuf = &up->txbuf; + dbuf->buf = xmit->buf; + dbuf->dma_addr = dma_map_single(port->dev, + dbuf->buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + dbuf->dma_size = UART_XMIT_SIZE; + + /* This should not be changed all around */ + chan_writel(up->txc, HSU_CH_BSR, 32); + chan_writel(up->txc, HSU_CH_MOTSR, 4); + dbuf->ofs = 0; + } + +exit: + /* And clear the interrupt registers again for luck. */ + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + + up->running = 1; + return 0; +} + +static void serial_hsu_shutdown(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + unsigned long flags; + + del_timer_sync(&up->rxc->rx_timer); + + /* Disable interrupts from this port */ + up->ier = 0; + serial_out(up, UART_IER, 0); + up->running = 0; + + spin_lock_irqsave(&up->port.lock, flags); + up->port.mctrl &= ~TIOCM_OUT2; + serial_hsu_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* Disable break condition and FIFOs */ + serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); +} + +static void +serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + struct tty_struct *tty = port->state->port.tty; + unsigned char cval, fcr = 0; + unsigned long flags; + unsigned int baud, quot; + u32 ps, mul; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + /* CMSPAR isn't supported by this driver */ + if (tty) + tty->termios->c_cflag &= ~CMSPAR; + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * The base clk is 50Mhz, and the baud rate come from: + * baud = 50M * MUL / (DIV * PS * DLAB) + * + * For those basic low baud rate we can get the direct + * scalar from 2746800, like 115200 = 2746800/24. For those + * higher baud rate, we handle them case by case, mainly by + * adjusting the MUL/PS registers, and DIV register is kept + * as default value 0x3d09 to make things simple + */ + baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + + quot = 1; + ps = 0x10; + mul = 0x3600; + switch (baud) { + case 3500000: + mul = 0x3345; + ps = 0xC; + break; + case 1843200: + mul = 0x2400; + break; + case 3000000: + case 2500000: + case 2000000: + case 1500000: + case 1000000: + case 500000: + /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ + mul = baud / 500000 * 0x9C4; + break; + default: + /* Use uart_get_divisor to get quot for other baud rates */ + quot = 0; + } + + if (!quot) + quot = uart_get_divisor(port, baud); + + if ((up->port.uartclk / quot) < (2400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; + else if ((up->port.uartclk / quot) < (230400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; + + fcr |= UART_FCR_HSU_64B_FIFO; +#ifdef MFD_HSU_A0_STEPPING + /* A0 doesn't support half empty IRQ */ + fcr |= UART_FCR_FULL_EMPT_TXI; +#endif + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* Update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* Characters to ignore */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* Ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts, disable + * MSI by default + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + + serial_out(up, UART_IER, up->ier); + + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE | UART_MCR_RTS; + else + up->mcr &= ~UART_MCR_AFE; + + serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(up, UART_LCR, cval); /* reset DLAB */ + serial_out(up, UART_MUL, mul); /* set MUL */ + serial_out(up, UART_PS, ps); /* set PS */ + up->lcr = cval; /* Save LCR */ + serial_hsu_set_mctrl(&up->port, up->port.mctrl); + serial_out(up, UART_FCR, fcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void +serial_hsu_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ +} + +static void serial_hsu_release_port(struct uart_port *port) +{ +} + +static int serial_hsu_request_port(struct uart_port *port) +{ + return 0; +} + +static void serial_hsu_config_port(struct uart_port *port, int flags) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + up->port.type = PORT_MFD; +} + +static int +serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* We don't want the core code to modify any port params */ + return -EINVAL; +} + +static const char * +serial_hsu_type(struct uart_port *port) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + return up->name; +} + +/* Mainly for uart console use */ +static struct uart_hsu_port *serial_hsu_ports[3]; +static struct uart_driver serial_hsu_reg; + +#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* Wait for transmitter & holding register to empty */ +static inline void wait_for_xmitr(struct uart_hsu_port *up) +{ + unsigned int status, tmout = 1000; + + /* Wait up to 1ms for the character to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while (!(status & BOTH_EMPTY)); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) + udelay(1); + } +} + +static void serial_hsu_console_putchar(struct uart_port *port, int ch) +{ + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + + wait_for_xmitr(up); + serial_out(up, UART_TX, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +serial_hsu_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_hsu_port *up = serial_hsu_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + 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 */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + + uart_console_write(&up->port, s, count, serial_hsu_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static struct console serial_hsu_console; + +static int __init +serial_hsu_console_setup(struct console *co, char *options) +{ + struct uart_hsu_port *up; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + if (co->index == -1 || co->index >= serial_hsu_reg.nr) + co->index = 0; + up = serial_hsu_ports[co->index]; + if (!up) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + ret = uart_set_options(&up->port, co, baud, parity, bits, flow); + + return ret; +} + +static struct console serial_hsu_console = { + .name = "ttyMFD", + .write = serial_hsu_console_write, + .device = uart_console_device, + .setup = serial_hsu_console_setup, + .flags = CON_PRINTBUFFER, + .index = 2, + .data = &serial_hsu_reg, +}; +#endif + +struct uart_ops serial_hsu_pops = { + .tx_empty = serial_hsu_tx_empty, + .set_mctrl = serial_hsu_set_mctrl, + .get_mctrl = serial_hsu_get_mctrl, + .stop_tx = serial_hsu_stop_tx, + .start_tx = serial_hsu_start_tx, + .stop_rx = serial_hsu_stop_rx, + .enable_ms = serial_hsu_enable_ms, + .break_ctl = serial_hsu_break_ctl, + .startup = serial_hsu_startup, + .shutdown = serial_hsu_shutdown, + .set_termios = serial_hsu_set_termios, + .pm = serial_hsu_pm, + .type = serial_hsu_type, + .release_port = serial_hsu_release_port, + .request_port = serial_hsu_request_port, + .config_port = serial_hsu_config_port, + .verify_port = serial_hsu_verify_port, +}; + +static struct uart_driver serial_hsu_reg = { + .owner = THIS_MODULE, + .driver_name = "MFD serial", + .dev_name = "ttyMFD", + .major = TTY_MAJOR, + .minor = 128, + .nr = 3, +}; + +#ifdef CONFIG_PM +static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) +{ + void *priv = pci_get_drvdata(pdev); + struct uart_hsu_port *up; + + /* Make sure this is not the internal dma controller */ + if (priv && (pdev->device != 0x081E)) { + up = priv; + uart_suspend_port(&serial_hsu_reg, &up->port); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int serial_hsu_resume(struct pci_dev *pdev) +{ + void *priv = pci_get_drvdata(pdev); + struct uart_hsu_port *up; + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + ret = pci_enable_device(pdev); + if (ret) + dev_warn(&pdev->dev, + "HSU: can't re-enable device, try to continue\n"); + + if (priv && (pdev->device != 0x081E)) { + up = priv; + uart_resume_port(&serial_hsu_reg, &up->port); + } + return 0; +} +#else +#define serial_hsu_suspend NULL +#define serial_hsu_resume NULL +#endif + +/* temp global pointer before we settle down on using one or four PCI dev */ +static struct hsu_port *phsu; + +static int serial_hsu_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct uart_hsu_port *uport; + int index, ret; + + printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", + pdev->vendor, pdev->device); + + switch (pdev->device) { + case 0x081B: + index = 0; + break; + case 0x081C: + index = 1; + break; + case 0x081D: + index = 2; + break; + case 0x081E: + /* internal DMA controller */ + index = 3; + break; + default: + dev_err(&pdev->dev, "HSU: out of index!"); + return -ENODEV; + } + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + if (index == 3) { + /* DMA controller */ + ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); + if (ret) { + dev_err(&pdev->dev, "can not get IRQ\n"); + goto err_disable; + } + pci_set_drvdata(pdev, phsu); + } else { + /* UART port 0~2 */ + uport = &phsu->port[index]; + uport->port.irq = pdev->irq; + uport->port.dev = &pdev->dev; + uport->dev = &pdev->dev; + + ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); + if (ret) { + dev_err(&pdev->dev, "can not get IRQ\n"); + goto err_disable; + } + uart_add_one_port(&serial_hsu_reg, &uport->port); + +#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE + if (index == 2) { + register_console(&serial_hsu_console); + uport->port.cons = &serial_hsu_console; + } +#endif + pci_set_drvdata(pdev, uport); + } + + return 0; + +err_disable: + pci_disable_device(pdev); + return ret; +} + +static void hsu_dma_rx_timeout(unsigned long data) +{ + struct hsu_dma_chan *chan = (void *)data; + struct uart_hsu_port *up = chan->uport; + struct hsu_dma_buffer *dbuf = &up->rxbuf; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + + count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; + + if (!count) { + mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); + goto exit; + } + + hsu_dma_rx(up, 0); +exit: + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void hsu_global_init(void) +{ + struct hsu_port *hsu; + struct uart_hsu_port *uport; + struct hsu_dma_chan *dchan; + int i, ret; + + hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); + if (!hsu) + return; + + /* Get basic io resource and map it */ + hsu->paddr = 0xffa28000; + hsu->iolen = 0x1000; + + if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) + pr_warning("HSU: error in request mem region\n"); + + hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); + if (!hsu->reg) { + pr_err("HSU: error in ioremap\n"); + ret = -ENOMEM; + goto err_free_region; + } + + /* Initialise the 3 UART ports */ + uport = hsu->port; + for (i = 0; i < 3; i++) { + uport->port.type = PORT_MFD; + uport->port.iotype = UPIO_MEM; + uport->port.mapbase = (resource_size_t)hsu->paddr + + HSU_PORT_REG_OFFSET + + i * HSU_PORT_REG_LENGTH; + uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET + + i * HSU_PORT_REG_LENGTH; + + sprintf(uport->name, "hsu_port%d", i); + uport->port.fifosize = 64; + uport->port.ops = &serial_hsu_pops; + uport->port.line = i; + uport->port.flags = UPF_IOREMAP; + /* set the scalable maxim support rate to 2746800 bps */ + uport->port.uartclk = 115200 * 24 * 16; + + uport->running = 0; + uport->txc = &hsu->chans[i * 2]; + uport->rxc = &hsu->chans[i * 2 + 1]; + + serial_hsu_ports[i] = uport; + uport->index = i; + uport++; + } + + /* Initialise 6 dma channels */ + dchan = hsu->chans; + for (i = 0; i < 6; i++) { + dchan->id = i; + dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + dchan->uport = &hsu->port[i/2]; + dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + + i * HSU_DMA_CHANS_REG_LENGTH; + + /* Work around for RX */ + if (dchan->dirt == DMA_FROM_DEVICE) { + init_timer(&dchan->rx_timer); + dchan->rx_timer.function = hsu_dma_rx_timeout; + dchan->rx_timer.data = (unsigned long)dchan; + } + dchan++; + } + + phsu = hsu; + hsu_debugfs_init(hsu); + return; + +err_free_region: + release_mem_region(hsu->paddr, hsu->iolen); + kfree(hsu); + return; +} + +static void serial_hsu_remove(struct pci_dev *pdev) +{ + void *priv = pci_get_drvdata(pdev); + struct uart_hsu_port *up; + + if (!priv) + return; + + /* For port 0/1/2, priv is the address of uart_hsu_port */ + if (pdev->device != 0x081E) { + up = priv; + uart_remove_one_port(&serial_hsu_reg, &up->port); + } + + pci_set_drvdata(pdev, NULL); + free_irq(pdev->irq, priv); + pci_disable_device(pdev); +} + +/* First 3 are UART ports, and the 4th is the DMA */ +static const struct pci_device_id pci_ids[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, + {}, +}; + +static struct pci_driver hsu_pci_driver = { + .name = "HSU serial", + .id_table = pci_ids, + .probe = serial_hsu_probe, + .remove = __devexit_p(serial_hsu_remove), + .suspend = serial_hsu_suspend, + .resume = serial_hsu_resume, +}; + +static int __init hsu_pci_init(void) +{ + int ret; + + hsu_global_init(); + + ret = uart_register_driver(&serial_hsu_reg); + if (ret) + return ret; + + return pci_register_driver(&hsu_pci_driver); +} + +static void __exit hsu_pci_exit(void) +{ + pci_unregister_driver(&hsu_pci_driver); + uart_unregister_driver(&serial_hsu_reg); + + hsu_debugfs_remove(phsu); + + kfree(phsu); +} + +module_init(hsu_pci_init); +module_exit(hsu_pci_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:medfield-hsu"); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c new file mode 100644 index 000000000000..126ec7f568ec --- /dev/null +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -0,0 +1,1527 @@ +/* + * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. + * + * FIXME According to the usermanual the status bits in the status register + * are only updated when the peripherals access the FIFO and not when the + * CPU access them. So since we use this bits to know when we stop writing + * and reading, they may not be updated in-time and a race condition may + * exists. But I haven't be able to prove this and I don't care. But if + * any problem arises, it might worth checking. The TX/RX FIFO Stats + * registers should be used in addition. + * Update: Actually, they seem updated ... At least the bits we use. + * + * + * Maintainer : Sylvain Munaut + * + * Some of the code has been inspired/copied from the 2.4 code written + * by Dale Farnsworth . + * + * Copyright (C) 2008 Freescale Semiconductor Inc. + * John Rigby + * Added support for MPC5121 + * Copyright (C) 2006 Secret Lab Technologies Ltd. + * Grant Likely + * Copyright (C) 2004-2006 Sylvain Munaut + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * 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. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + + +/* We've been assigned a range on the "Low-density serial ports" major */ +#define SERIAL_PSC_MAJOR 204 +#define SERIAL_PSC_MINOR 148 + + +#define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */ + + +static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; + /* Rem: - We use the read_status_mask as a shadow of + * psc->mpc52xx_psc_imr + * - It's important that is array is all zero on start as we + * use it to know if it's initialized or not ! If it's not sure + * it's cleared, then a memset(...,0,...) should be added to + * the console_init + */ + +/* lookup table for matching device nodes to index numbers */ +static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM]; + +static void mpc52xx_uart_of_enumerate(void); + + +#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase)) + + +/* Forward declaration of the interruption handling routine */ +static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); +static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); + + +/* Simple macro to test if a port is console or not. This one is taken + * for serial_core.c and maybe should be moved to serial_core.h ? */ +#ifdef CONFIG_SERIAL_CORE_CONSOLE +#define uart_console(port) \ + ((port)->cons && (port)->cons->index == (port)->line) +#else +#define uart_console(port) (0) +#endif + +/* ======================================================================== */ +/* PSC fifo operations for isolating differences between 52xx and 512x */ +/* ======================================================================== */ + +struct psc_ops { + void (*fifo_init)(struct uart_port *port); + int (*raw_rx_rdy)(struct uart_port *port); + int (*raw_tx_rdy)(struct uart_port *port); + int (*rx_rdy)(struct uart_port *port); + int (*tx_rdy)(struct uart_port *port); + int (*tx_empty)(struct uart_port *port); + void (*stop_rx)(struct uart_port *port); + void (*start_tx)(struct uart_port *port); + void (*stop_tx)(struct uart_port *port); + void (*rx_clr_irq)(struct uart_port *port); + void (*tx_clr_irq)(struct uart_port *port); + void (*write_char)(struct uart_port *port, unsigned char c); + unsigned char (*read_char)(struct uart_port *port); + void (*cw_disable_ints)(struct uart_port *port); + void (*cw_restore_ints)(struct uart_port *port); + unsigned int (*set_baudrate)(struct uart_port *port, + struct ktermios *new, + struct ktermios *old); + int (*clock)(struct uart_port *port, int enable); + int (*fifoc_init)(void); + void (*fifoc_uninit)(void); + void (*get_irq)(struct uart_port *, struct device_node *); + irqreturn_t (*handle_irq)(struct uart_port *port); +}; + +/* setting the prescaler and divisor reg is common for all chips */ +static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc, + u16 prescaler, unsigned int divisor) +{ + /* select prescaler */ + out_be16(&psc->mpc52xx_psc_clock_select, prescaler); + out_8(&psc->ctur, divisor >> 8); + out_8(&psc->ctlr, divisor & 0xff); +} + +#ifdef CONFIG_PPC_MPC52xx +#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) +static void mpc52xx_psc_fifo_init(struct uart_port *port) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); + + out_8(&fifo->rfcntl, 0x00); + out_be16(&fifo->rfalarm, 0x1ff); + out_8(&fifo->tfcntl, 0x07); + out_be16(&fifo->tfalarm, 0x80); + + port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); +} + +static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status) + & MPC52xx_PSC_SR_RXRDY; +} + +static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status) + & MPC52xx_PSC_SR_TXRDY; +} + + +static int mpc52xx_psc_rx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_isr) + & port->read_status_mask + & MPC52xx_PSC_IMR_RXRDY; +} + +static int mpc52xx_psc_tx_rdy(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_isr) + & port->read_status_mask + & MPC52xx_PSC_IMR_TXRDY; +} + +static int mpc52xx_psc_tx_empty(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status) + & MPC52xx_PSC_SR_TXEMP; +} + +static void mpc52xx_psc_start_tx(struct uart_port *port) +{ + port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static void mpc52xx_psc_stop_tx(struct uart_port *port) +{ + port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static void mpc52xx_psc_stop_rx(struct uart_port *port) +{ + port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static void mpc52xx_psc_rx_clr_irq(struct uart_port *port) +{ +} + +static void mpc52xx_psc_tx_clr_irq(struct uart_port *port) +{ +} + +static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c) +{ + out_8(&PSC(port)->mpc52xx_psc_buffer_8, c); +} + +static unsigned char mpc52xx_psc_read_char(struct uart_port *port) +{ + return in_8(&PSC(port)->mpc52xx_psc_buffer_8); +} + +static void mpc52xx_psc_cw_disable_ints(struct uart_port *port) +{ + out_be16(&PSC(port)->mpc52xx_psc_imr, 0); +} + +static void mpc52xx_psc_cw_restore_ints(struct uart_port *port) +{ + out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); +} + +static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + unsigned int baud; + unsigned int divisor; + + /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */ + baud = uart_get_baud_rate(port, new, old, + port->uartclk / (32 * 0xffff) + 1, + port->uartclk / 32); + divisor = (port->uartclk + 16 * baud) / (32 * baud); + + /* enable the /32 prescaler and set the divisor */ + mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); + return baud; +} + +static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + unsigned int baud; + unsigned int divisor; + u16 prescaler; + + /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the + * ipb freq */ + baud = uart_get_baud_rate(port, new, old, + port->uartclk / (32 * 0xffff) + 1, + port->uartclk / 4); + divisor = (port->uartclk + 2 * baud) / (4 * baud); + + /* select the proper prescaler and set the divisor */ + if (divisor > 0xffff) { + divisor = (divisor + 4) / 8; + prescaler = 0xdd00; /* /32 */ + } else + prescaler = 0xff00; /* /4 */ + mpc52xx_set_divisor(PSC(port), prescaler, divisor); + return baud; +} + +static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) +{ + port->irqflags = IRQF_DISABLED; + port->irq = irq_of_parse_and_map(np, 0); +} + +/* 52xx specific interrupt handler. The caller holds the port lock */ +static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port) +{ + return mpc5xxx_uart_process_int(port); +} + +static struct psc_ops mpc52xx_psc_ops = { + .fifo_init = mpc52xx_psc_fifo_init, + .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, + .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, + .rx_rdy = mpc52xx_psc_rx_rdy, + .tx_rdy = mpc52xx_psc_tx_rdy, + .tx_empty = mpc52xx_psc_tx_empty, + .stop_rx = mpc52xx_psc_stop_rx, + .start_tx = mpc52xx_psc_start_tx, + .stop_tx = mpc52xx_psc_stop_tx, + .rx_clr_irq = mpc52xx_psc_rx_clr_irq, + .tx_clr_irq = mpc52xx_psc_tx_clr_irq, + .write_char = mpc52xx_psc_write_char, + .read_char = mpc52xx_psc_read_char, + .cw_disable_ints = mpc52xx_psc_cw_disable_ints, + .cw_restore_ints = mpc52xx_psc_cw_restore_ints, + .set_baudrate = mpc5200_psc_set_baudrate, + .get_irq = mpc52xx_psc_get_irq, + .handle_irq = mpc52xx_psc_handle_irq, +}; + +static struct psc_ops mpc5200b_psc_ops = { + .fifo_init = mpc52xx_psc_fifo_init, + .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, + .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy, + .rx_rdy = mpc52xx_psc_rx_rdy, + .tx_rdy = mpc52xx_psc_tx_rdy, + .tx_empty = mpc52xx_psc_tx_empty, + .stop_rx = mpc52xx_psc_stop_rx, + .start_tx = mpc52xx_psc_start_tx, + .stop_tx = mpc52xx_psc_stop_tx, + .rx_clr_irq = mpc52xx_psc_rx_clr_irq, + .tx_clr_irq = mpc52xx_psc_tx_clr_irq, + .write_char = mpc52xx_psc_write_char, + .read_char = mpc52xx_psc_read_char, + .cw_disable_ints = mpc52xx_psc_cw_disable_ints, + .cw_restore_ints = mpc52xx_psc_cw_restore_ints, + .set_baudrate = mpc5200b_psc_set_baudrate, + .get_irq = mpc52xx_psc_get_irq, + .handle_irq = mpc52xx_psc_handle_irq, +}; + +#endif /* CONFIG_MPC52xx */ + +#ifdef CONFIG_PPC_MPC512x +#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) + +/* PSC FIFO Controller for mpc512x */ +struct psc_fifoc { + u32 fifoc_cmd; + u32 fifoc_int; + u32 fifoc_dma; + u32 fifoc_axe; + u32 fifoc_debug; +}; + +static struct psc_fifoc __iomem *psc_fifoc; +static unsigned int psc_fifoc_irq; + +static void mpc512x_psc_fifo_init(struct uart_port *port) +{ + /* /32 prescaler */ + out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00); + + out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); + out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); + out_be32(&FIFO_512x(port)->txalarm, 1); + out_be32(&FIFO_512x(port)->tximr, 0); + + out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); + out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); + out_be32(&FIFO_512x(port)->rxalarm, 1); + out_be32(&FIFO_512x(port)->rximr, 0); + + out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); + out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); +} + +static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) +{ + return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); +} + +static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) +{ + return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); +} + +static int mpc512x_psc_rx_rdy(struct uart_port *port) +{ + return in_be32(&FIFO_512x(port)->rxsr) + & in_be32(&FIFO_512x(port)->rximr) + & MPC512x_PSC_FIFO_ALARM; +} + +static int mpc512x_psc_tx_rdy(struct uart_port *port) +{ + return in_be32(&FIFO_512x(port)->txsr) + & in_be32(&FIFO_512x(port)->tximr) + & MPC512x_PSC_FIFO_ALARM; +} + +static int mpc512x_psc_tx_empty(struct uart_port *port) +{ + return in_be32(&FIFO_512x(port)->txsr) + & MPC512x_PSC_FIFO_EMPTY; +} + +static void mpc512x_psc_stop_rx(struct uart_port *port) +{ + unsigned long rx_fifo_imr; + + rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); + rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); +} + +static void mpc512x_psc_start_tx(struct uart_port *port) +{ + unsigned long tx_fifo_imr; + + tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); + tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); +} + +static void mpc512x_psc_stop_tx(struct uart_port *port) +{ + unsigned long tx_fifo_imr; + + tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); + tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); +} + +static void mpc512x_psc_rx_clr_irq(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); +} + +static void mpc512x_psc_tx_clr_irq(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); +} + +static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) +{ + out_8(&FIFO_512x(port)->txdata_8, c); +} + +static unsigned char mpc512x_psc_read_char(struct uart_port *port) +{ + return in_8(&FIFO_512x(port)->rxdata_8); +} + +static void mpc512x_psc_cw_disable_ints(struct uart_port *port) +{ + port->read_status_mask = + in_be32(&FIFO_512x(port)->tximr) << 16 | + in_be32(&FIFO_512x(port)->rximr); + out_be32(&FIFO_512x(port)->tximr, 0); + out_be32(&FIFO_512x(port)->rximr, 0); +} + +static void mpc512x_psc_cw_restore_ints(struct uart_port *port) +{ + out_be32(&FIFO_512x(port)->tximr, + (port->read_status_mask >> 16) & 0x7f); + out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); +} + +static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + unsigned int baud; + unsigned int divisor; + + /* + * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on + * pg. 30-10 that the chip supports a /32 and a /10 prescaler. + * Furthermore, it states that "After reset, the prescaler by 10 + * for the UART mode is selected", but the reset register value is + * 0x0000 which means a /32 prescaler. This is wrong. + * + * In reality using /32 prescaler doesn't work, as it is not supported! + * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide", + * Chapter 4.1 PSC in UART Mode. + * Calculate with a /16 prescaler here. + */ + + /* uartclk contains the ips freq */ + baud = uart_get_baud_rate(port, new, old, + port->uartclk / (16 * 0xffff) + 1, + port->uartclk / 16); + divisor = (port->uartclk + 8 * baud) / (16 * baud); + + /* enable the /16 prescaler and set the divisor */ + mpc52xx_set_divisor(PSC(port), 0xdd00, divisor); + return baud; +} + +/* Init PSC FIFO Controller */ +static int __init mpc512x_psc_fifoc_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, + "fsl,mpc5121-psc-fifo"); + if (!np) { + pr_err("%s: Can't find FIFOC node\n", __func__); + return -ENODEV; + } + + psc_fifoc = of_iomap(np, 0); + if (!psc_fifoc) { + pr_err("%s: Can't map FIFOC\n", __func__); + of_node_put(np); + return -ENODEV; + } + + psc_fifoc_irq = irq_of_parse_and_map(np, 0); + of_node_put(np); + if (psc_fifoc_irq == NO_IRQ) { + pr_err("%s: Can't get FIFOC irq\n", __func__); + iounmap(psc_fifoc); + return -ENODEV; + } + + return 0; +} + +static void __exit mpc512x_psc_fifoc_uninit(void) +{ + iounmap(psc_fifoc); +} + +/* 512x specific interrupt handler. The caller holds the port lock */ +static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) +{ + unsigned long fifoc_int; + int psc_num; + + /* Read pending PSC FIFOC interrupts */ + fifoc_int = in_be32(&psc_fifoc->fifoc_int); + + /* Check if it is an interrupt for this port */ + psc_num = (port->mapbase & 0xf00) >> 8; + if (test_bit(psc_num, &fifoc_int) || + test_bit(psc_num + 16, &fifoc_int)) + return mpc5xxx_uart_process_int(port); + + return IRQ_NONE; +} + +static int mpc512x_psc_clock(struct uart_port *port, int enable) +{ + struct clk *psc_clk; + int psc_num; + char clk_name[10]; + + if (uart_console(port)) + return 0; + + psc_num = (port->mapbase & 0xf00) >> 8; + snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num); + psc_clk = clk_get(port->dev, clk_name); + if (IS_ERR(psc_clk)) { + dev_err(port->dev, "Failed to get PSC clock entry!\n"); + return -ENODEV; + } + + dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis"); + + if (enable) + clk_enable(psc_clk); + else + clk_disable(psc_clk); + + return 0; +} + +static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) +{ + port->irqflags = IRQF_SHARED; + port->irq = psc_fifoc_irq; +} + +static struct psc_ops mpc512x_psc_ops = { + .fifo_init = mpc512x_psc_fifo_init, + .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, + .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, + .rx_rdy = mpc512x_psc_rx_rdy, + .tx_rdy = mpc512x_psc_tx_rdy, + .tx_empty = mpc512x_psc_tx_empty, + .stop_rx = mpc512x_psc_stop_rx, + .start_tx = mpc512x_psc_start_tx, + .stop_tx = mpc512x_psc_stop_tx, + .rx_clr_irq = mpc512x_psc_rx_clr_irq, + .tx_clr_irq = mpc512x_psc_tx_clr_irq, + .write_char = mpc512x_psc_write_char, + .read_char = mpc512x_psc_read_char, + .cw_disable_ints = mpc512x_psc_cw_disable_ints, + .cw_restore_ints = mpc512x_psc_cw_restore_ints, + .set_baudrate = mpc512x_psc_set_baudrate, + .clock = mpc512x_psc_clock, + .fifoc_init = mpc512x_psc_fifoc_init, + .fifoc_uninit = mpc512x_psc_fifoc_uninit, + .get_irq = mpc512x_psc_get_irq, + .handle_irq = mpc512x_psc_handle_irq, +}; +#endif + +static struct psc_ops *psc_ops; + +/* ======================================================================== */ +/* UART operations */ +/* ======================================================================== */ + +static unsigned int +mpc52xx_uart_tx_empty(struct uart_port *port) +{ + return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0; +} + +static void +mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + if (mctrl & TIOCM_RTS) + out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); + else + out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); +} + +static unsigned int +mpc52xx_uart_get_mctrl(struct uart_port *port) +{ + unsigned int ret = TIOCM_DSR; + u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + + if (!(status & MPC52xx_PSC_CTS)) + ret |= TIOCM_CTS; + if (!(status & MPC52xx_PSC_DCD)) + ret |= TIOCM_CAR; + + return ret; +} + +static void +mpc52xx_uart_stop_tx(struct uart_port *port) +{ + /* port->lock taken by caller */ + psc_ops->stop_tx(port); +} + +static void +mpc52xx_uart_start_tx(struct uart_port *port) +{ + /* port->lock taken by caller */ + psc_ops->start_tx(port); +} + +static void +mpc52xx_uart_send_xchar(struct uart_port *port, char ch) +{ + unsigned long flags; + spin_lock_irqsave(&port->lock, flags); + + port->x_char = ch; + if (ch) { + /* Make sure tx interrupts are on */ + /* Truly necessary ??? They should be anyway */ + psc_ops->start_tx(port); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +mpc52xx_uart_stop_rx(struct uart_port *port) +{ + /* port->lock taken by caller */ + psc_ops->stop_rx(port); +} + +static void +mpc52xx_uart_enable_ms(struct uart_port *port) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + + /* clear D_*-bits by reading them */ + in_8(&psc->mpc52xx_psc_ipcr); + /* enable CTS and DCD as IPC interrupts */ + out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); + + port->read_status_mask |= MPC52xx_PSC_IMR_IPC; + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); +} + +static void +mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) +{ + unsigned long flags; + spin_lock_irqsave(&port->lock, flags); + + if (ctl == -1) + out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK); + else + out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static int +mpc52xx_uart_startup(struct uart_port *port) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + int ret; + + if (psc_ops->clock) { + ret = psc_ops->clock(port, 1); + if (ret) + return ret; + } + + /* Request IRQ */ + ret = request_irq(port->irq, mpc52xx_uart_int, + port->irqflags, "mpc52xx_psc_uart", port); + if (ret) + return ret; + + /* Reset/activate the port, clear and enable interrupts */ + out_8(&psc->command, MPC52xx_PSC_RST_RX); + out_8(&psc->command, MPC52xx_PSC_RST_TX); + + out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ + + psc_ops->fifo_init(port); + + out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); + + return 0; +} + +static void +mpc52xx_uart_shutdown(struct uart_port *port) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + + /* Shut down the port. Leave TX active if on a console port */ + out_8(&psc->command, MPC52xx_PSC_RST_RX); + if (!uart_console(port)) + out_8(&psc->command, MPC52xx_PSC_RST_TX); + + port->read_status_mask = 0; + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); + + if (psc_ops->clock) + psc_ops->clock(port, 0); + + /* Release interrupt */ + free_irq(port->irq, port); +} + +static void +mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, + struct ktermios *old) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + unsigned long flags; + unsigned char mr1, mr2; + unsigned int j; + unsigned int baud; + + /* Prepare what we're gonna write */ + mr1 = 0; + + switch (new->c_cflag & CSIZE) { + case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; + break; + case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; + break; + case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; + break; + case CS8: + default: mr1 |= MPC52xx_PSC_MODE_8_BITS; + } + + if (new->c_cflag & PARENB) { + mr1 |= (new->c_cflag & PARODD) ? + MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; + } else + mr1 |= MPC52xx_PSC_MODE_PARNONE; + + + mr2 = 0; + + if (new->c_cflag & CSTOPB) + mr2 |= MPC52xx_PSC_MODE_TWO_STOP; + else + mr2 |= ((new->c_cflag & CSIZE) == CS5) ? + MPC52xx_PSC_MODE_ONE_STOP_5_BITS : + MPC52xx_PSC_MODE_ONE_STOP; + + if (new->c_cflag & CRTSCTS) { + mr1 |= MPC52xx_PSC_MODE_RXRTS; + mr2 |= MPC52xx_PSC_MODE_TXCTS; + } + + /* Get the lock */ + spin_lock_irqsave(&port->lock, flags); + + /* Do our best to flush TX & RX, so we don't lose anything */ + /* But we don't wait indefinitely ! */ + j = 5000000; /* Maximum wait */ + /* FIXME Can't receive chars since set_termios might be called at early + * boot for the console, all stuff is not yet ready to receive at that + * time and that just makes the kernel oops */ + /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ + while (!mpc52xx_uart_tx_empty(port) && --j) + udelay(1); + + if (!j) + printk(KERN_ERR "mpc52xx_uart.c: " + "Unable to flush RX & TX fifos in-time in set_termios." + "Some chars may have been lost.\n"); + + /* Reset the TX & RX */ + out_8(&psc->command, MPC52xx_PSC_RST_RX); + out_8(&psc->command, MPC52xx_PSC_RST_TX); + + /* Send new mode settings */ + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); + out_8(&psc->mode, mr1); + out_8(&psc->mode, mr2); + baud = psc_ops->set_baudrate(port, new, old); + + /* Update the per-port timeout */ + uart_update_timeout(port, new->c_cflag, baud); + + if (UART_ENABLE_MS(port, new->c_cflag)) + mpc52xx_uart_enable_ms(port); + + /* Reenable TX & RX */ + out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); + + /* We're all set, release the lock */ + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char * +mpc52xx_uart_type(struct uart_port *port) +{ + /* + * We keep using PORT_MPC52xx for historic reasons although it applies + * for MPC512x, too, but print "MPC5xxx" to not irritate users + */ + return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL; +} + +static void +mpc52xx_uart_release_port(struct uart_port *port) +{ + /* remapped by us ? */ + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); +} + +static int +mpc52xx_uart_request_port(struct uart_port *port) +{ + int err; + + if (port->flags & UPF_IOREMAP) /* Need to remap ? */ + port->membase = ioremap(port->mapbase, + sizeof(struct mpc52xx_psc)); + + if (!port->membase) + return -EINVAL; + + err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), + "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; + + if (err && (port->flags & UPF_IOREMAP)) { + iounmap(port->membase); + port->membase = NULL; + } + + return err; +} + +static void +mpc52xx_uart_config_port(struct uart_port *port, int flags) +{ + if ((flags & UART_CONFIG_TYPE) + && (mpc52xx_uart_request_port(port) == 0)) + port->type = PORT_MPC52xx; +} + +static int +mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx) + return -EINVAL; + + if ((ser->irq != port->irq) || + (ser->io_type != UPIO_MEM) || + (ser->baud_base != port->uartclk) || + (ser->iomem_base != (void *)port->mapbase) || + (ser->hub6 != 0)) + return -EINVAL; + + return 0; +} + + +static struct uart_ops mpc52xx_uart_ops = { + .tx_empty = mpc52xx_uart_tx_empty, + .set_mctrl = mpc52xx_uart_set_mctrl, + .get_mctrl = mpc52xx_uart_get_mctrl, + .stop_tx = mpc52xx_uart_stop_tx, + .start_tx = mpc52xx_uart_start_tx, + .send_xchar = mpc52xx_uart_send_xchar, + .stop_rx = mpc52xx_uart_stop_rx, + .enable_ms = mpc52xx_uart_enable_ms, + .break_ctl = mpc52xx_uart_break_ctl, + .startup = mpc52xx_uart_startup, + .shutdown = mpc52xx_uart_shutdown, + .set_termios = mpc52xx_uart_set_termios, +/* .pm = mpc52xx_uart_pm, Not supported yet */ +/* .set_wake = mpc52xx_uart_set_wake, Not supported yet */ + .type = mpc52xx_uart_type, + .release_port = mpc52xx_uart_release_port, + .request_port = mpc52xx_uart_request_port, + .config_port = mpc52xx_uart_config_port, + .verify_port = mpc52xx_uart_verify_port +}; + + +/* ======================================================================== */ +/* Interrupt handling */ +/* ======================================================================== */ + +static inline int +mpc52xx_uart_int_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = port->state->port.tty; + unsigned char ch, flag; + unsigned short status; + + /* While we can read, do so ! */ + while (psc_ops->raw_rx_rdy(port)) { + /* Get the char */ + ch = psc_ops->read_char(port); + + /* Handle sysreq char */ +#ifdef SUPPORT_SYSRQ + if (uart_handle_sysrq_char(port, ch)) { + port->sysrq = 0; + continue; + } +#endif + + /* Store it */ + + flag = TTY_NORMAL; + port->icount.rx++; + + status = in_be16(&PSC(port)->mpc52xx_psc_status); + + if (status & (MPC52xx_PSC_SR_PE | + MPC52xx_PSC_SR_FE | + MPC52xx_PSC_SR_RB)) { + + if (status & MPC52xx_PSC_SR_RB) { + flag = TTY_BREAK; + uart_handle_break(port); + port->icount.brk++; + } else if (status & MPC52xx_PSC_SR_PE) { + flag = TTY_PARITY; + port->icount.parity++; + } + else if (status & MPC52xx_PSC_SR_FE) { + flag = TTY_FRAME; + port->icount.frame++; + } + + /* Clear error condition */ + out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); + + } + tty_insert_flip_char(tty, ch, flag); + if (status & MPC52xx_PSC_SR_OE) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + port->icount.overrun++; + } + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(tty); + spin_lock(&port->lock); + + return psc_ops->raw_rx_rdy(port); +} + +static inline int +mpc52xx_uart_int_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + /* Process out of band chars */ + if (port->x_char) { + psc_ops->write_char(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return 1; + } + + /* Nothing to do ? */ + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + mpc52xx_uart_stop_tx(port); + return 0; + } + + /* Send chars */ + while (psc_ops->raw_tx_rdy(port)) { + psc_ops->write_char(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + /* Wake up */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* Maybe we're done after all */ + if (uart_circ_empty(xmit)) { + mpc52xx_uart_stop_tx(port); + return 0; + } + + return 1; +} + +static irqreturn_t +mpc5xxx_uart_process_int(struct uart_port *port) +{ + unsigned long pass = ISR_PASS_LIMIT; + unsigned int keepgoing; + u8 status; + + /* While we have stuff to do, we continue */ + do { + /* If we don't find anything to do, we stop */ + keepgoing = 0; + + psc_ops->rx_clr_irq(port); + if (psc_ops->rx_rdy(port)) + keepgoing |= mpc52xx_uart_int_rx_chars(port); + + psc_ops->tx_clr_irq(port); + if (psc_ops->tx_rdy(port)) + keepgoing |= mpc52xx_uart_int_tx_chars(port); + + status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + if (status & MPC52xx_PSC_D_DCD) + uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); + + if (status & MPC52xx_PSC_D_CTS) + uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS)); + + /* Limit number of iteration */ + if (!(--pass)) + keepgoing = 0; + + } while (keepgoing); + + return IRQ_HANDLED; +} + +static irqreturn_t +mpc52xx_uart_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + irqreturn_t ret; + + spin_lock(&port->lock); + + ret = psc_ops->handle_irq(port); + + spin_unlock(&port->lock); + + return ret; +} + +/* ======================================================================== */ +/* Console ( if applicable ) */ +/* ======================================================================== */ + +#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE + +static void __init +mpc52xx_console_get_options(struct uart_port *port, + int *baud, int *parity, int *bits, int *flow) +{ + struct mpc52xx_psc __iomem *psc = PSC(port); + unsigned char mr1; + + pr_debug("mpc52xx_console_get_options(port=%p)\n", port); + + /* Read the mode registers */ + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); + mr1 = in_8(&psc->mode); + + /* CT{U,L}R are write-only ! */ + *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; + + /* Parse them */ + switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { + case MPC52xx_PSC_MODE_5_BITS: + *bits = 5; + break; + case MPC52xx_PSC_MODE_6_BITS: + *bits = 6; + break; + case MPC52xx_PSC_MODE_7_BITS: + *bits = 7; + break; + case MPC52xx_PSC_MODE_8_BITS: + default: + *bits = 8; + } + + if (mr1 & MPC52xx_PSC_MODE_PARNONE) + *parity = 'n'; + else + *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e'; +} + +static void +mpc52xx_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &mpc52xx_uart_ports[co->index]; + unsigned int i, j; + + /* Disable interrupts */ + psc_ops->cw_disable_ints(port); + + /* Wait the TX buffer to be empty */ + j = 5000000; /* Maximum wait */ + while (!mpc52xx_uart_tx_empty(port) && --j) + udelay(1); + + /* Write all the chars */ + for (i = 0; i < count; i++, s++) { + /* Line return handling */ + if (*s == '\n') + psc_ops->write_char(port, '\r'); + + /* Send the char */ + psc_ops->write_char(port, *s); + + /* Wait the TX buffer to be empty */ + j = 20000; /* Maximum wait */ + while (!mpc52xx_uart_tx_empty(port) && --j) + udelay(1); + } + + /* Restore interrupt state */ + psc_ops->cw_restore_ints(port); +} + + +static int __init +mpc52xx_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &mpc52xx_uart_ports[co->index]; + struct device_node *np = mpc52xx_uart_nodes[co->index]; + unsigned int uartclk; + struct resource res; + int ret; + + int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n", + co, co->index, options); + + if ((co->index < 0) || (co->index >= MPC52xx_PSC_MAXNUM)) { + pr_debug("PSC%x out of range\n", co->index); + return -EINVAL; + } + + if (!np) { + pr_debug("PSC%x not found in device tree\n", co->index); + return -EINVAL; + } + + pr_debug("Console on ttyPSC%x is %s\n", + co->index, mpc52xx_uart_nodes[co->index]->full_name); + + /* Fetch register locations */ + ret = of_address_to_resource(np, 0, &res); + if (ret) { + pr_debug("Could not get resources for PSC%x\n", co->index); + return ret; + } + + uartclk = mpc5xxx_get_bus_frequency(np); + if (uartclk == 0) { + pr_debug("Could not find uart clock frequency!\n"); + return -EINVAL; + } + + /* Basic port init. Needed since we use some uart_??? func before + * real init for early access */ + spin_lock_init(&port->lock); + port->uartclk = uartclk; + port->ops = &mpc52xx_uart_ops; + port->mapbase = res.start; + port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc)); + port->irq = irq_of_parse_and_map(np, 0); + + if (port->membase == NULL) + return -EINVAL; + + pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n", + (void *)port->mapbase, port->membase, + port->irq, port->uartclk); + + /* Setup the port parameters accoding to options */ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); + + pr_debug("Setting console parameters: %i %i%c1 flow=%c\n", + baud, bits, parity, flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + + +static struct uart_driver mpc52xx_uart_driver; + +static struct console mpc52xx_console = { + .name = "ttyPSC", + .write = mpc52xx_console_write, + .device = uart_console_device, + .setup = mpc52xx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, /* Specified on the cmdline (e.g. console=ttyPSC0) */ + .data = &mpc52xx_uart_driver, +}; + + +static int __init +mpc52xx_console_init(void) +{ + mpc52xx_uart_of_enumerate(); + register_console(&mpc52xx_console); + return 0; +} + +console_initcall(mpc52xx_console_init); + +#define MPC52xx_PSC_CONSOLE &mpc52xx_console +#else +#define MPC52xx_PSC_CONSOLE NULL +#endif + + +/* ======================================================================== */ +/* UART Driver */ +/* ======================================================================== */ + +static struct uart_driver mpc52xx_uart_driver = { + .driver_name = "mpc52xx_psc_uart", + .dev_name = "ttyPSC", + .major = SERIAL_PSC_MAJOR, + .minor = SERIAL_PSC_MINOR, + .nr = MPC52xx_PSC_MAXNUM, + .cons = MPC52xx_PSC_CONSOLE, +}; + +/* ======================================================================== */ +/* OF Platform Driver */ +/* ======================================================================== */ + +static struct of_device_id mpc52xx_uart_of_match[] = { +#ifdef CONFIG_PPC_MPC52xx + { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, }, + { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, + /* binding used by old lite5200 device trees: */ + { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, + /* binding used by efika: */ + { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, +#endif +#ifdef CONFIG_PPC_MPC512x + { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, +#endif + {}, +}; + +static int __devinit +mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match) +{ + int idx = -1; + unsigned int uartclk; + struct uart_port *port = NULL; + struct resource res; + int ret; + + dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match); + + /* Check validity & presence */ + for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++) + if (mpc52xx_uart_nodes[idx] == op->dev.of_node) + break; + if (idx >= MPC52xx_PSC_MAXNUM) + return -EINVAL; + pr_debug("Found %s assigned to ttyPSC%x\n", + mpc52xx_uart_nodes[idx]->full_name, idx); + + /* set the uart clock to the input clock of the psc, the different + * prescalers are taken into account in the set_baudrate() methods + * of the respective chip */ + uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node); + if (uartclk == 0) { + dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); + return -EINVAL; + } + + /* Init the port structure */ + port = &mpc52xx_uart_ports[idx]; + + spin_lock_init(&port->lock); + port->uartclk = uartclk; + port->fifosize = 512; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF | + (uart_console(port) ? 0 : UPF_IOREMAP); + port->line = idx; + port->ops = &mpc52xx_uart_ops; + port->dev = &op->dev; + + /* Search for IRQ and mapbase */ + ret = of_address_to_resource(op->dev.of_node, 0, &res); + if (ret) + return ret; + + port->mapbase = res.start; + if (!port->mapbase) { + dev_dbg(&op->dev, "Could not allocate resources for PSC\n"); + return -EINVAL; + } + + psc_ops->get_irq(port, op->dev.of_node); + if (port->irq == NO_IRQ) { + dev_dbg(&op->dev, "Could not get irq\n"); + return -EINVAL; + } + + dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", + (void *)port->mapbase, port->irq, port->uartclk); + + /* Add the port to the uart sub-system */ + ret = uart_add_one_port(&mpc52xx_uart_driver, port); + if (ret) + return ret; + + dev_set_drvdata(&op->dev, (void *)port); + return 0; +} + +static int +mpc52xx_uart_of_remove(struct platform_device *op) +{ + struct uart_port *port = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + + if (port) + uart_remove_one_port(&mpc52xx_uart_driver, port); + + return 0; +} + +#ifdef CONFIG_PM +static int +mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) +{ + struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); + + if (port) + uart_suspend_port(&mpc52xx_uart_driver, port); + + return 0; +} + +static int +mpc52xx_uart_of_resume(struct platform_device *op) +{ + struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); + + if (port) + uart_resume_port(&mpc52xx_uart_driver, port); + + return 0; +} +#endif + +static void +mpc52xx_uart_of_assign(struct device_node *np) +{ + int i; + + /* Find the first free PSC number */ + for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { + if (mpc52xx_uart_nodes[i] == NULL) { + of_node_get(np); + mpc52xx_uart_nodes[i] = np; + return; + } + } +} + +static void +mpc52xx_uart_of_enumerate(void) +{ + static int enum_done; + struct device_node *np; + const struct of_device_id *match; + int i; + + if (enum_done) + return; + + /* Assign index to each PSC in device tree */ + for_each_matching_node(np, mpc52xx_uart_of_match) { + match = of_match_node(mpc52xx_uart_of_match, np); + psc_ops = match->data; + mpc52xx_uart_of_assign(np); + } + + enum_done = 1; + + for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { + if (mpc52xx_uart_nodes[i]) + pr_debug("%s assigned to ttyPSC%x\n", + mpc52xx_uart_nodes[i]->full_name, i); + } +} + +MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); + +static struct of_platform_driver mpc52xx_uart_of_driver = { + .probe = mpc52xx_uart_of_probe, + .remove = mpc52xx_uart_of_remove, +#ifdef CONFIG_PM + .suspend = mpc52xx_uart_of_suspend, + .resume = mpc52xx_uart_of_resume, +#endif + .driver = { + .name = "mpc52xx-psc-uart", + .owner = THIS_MODULE, + .of_match_table = mpc52xx_uart_of_match, + }, +}; + + +/* ======================================================================== */ +/* Module */ +/* ======================================================================== */ + +static int __init +mpc52xx_uart_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n"); + + ret = uart_register_driver(&mpc52xx_uart_driver); + if (ret) { + printk(KERN_ERR "%s: uart_register_driver failed (%i)\n", + __FILE__, ret); + return ret; + } + + mpc52xx_uart_of_enumerate(); + + /* + * Map the PSC FIFO Controller and init if on MPC512x. + */ + if (psc_ops && psc_ops->fifoc_init) { + ret = psc_ops->fifoc_init(); + if (ret) + return ret; + } + + ret = of_register_platform_driver(&mpc52xx_uart_of_driver); + if (ret) { + printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n", + __FILE__, ret); + uart_unregister_driver(&mpc52xx_uart_driver); + return ret; + } + + return 0; +} + +static void __exit +mpc52xx_uart_exit(void) +{ + if (psc_ops->fifoc_uninit) + psc_ops->fifoc_uninit(); + + of_unregister_platform_driver(&mpc52xx_uart_of_driver); + uart_unregister_driver(&mpc52xx_uart_driver); +} + + +module_init(mpc52xx_uart_init); +module_exit(mpc52xx_uart_exit); + +MODULE_AUTHOR("Sylvain Munaut "); +MODULE_DESCRIPTION("Freescale MPC52xx PSC UART"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c new file mode 100644 index 000000000000..6a9c6605666a --- /dev/null +++ b/drivers/tty/serial/mpsc.c @@ -0,0 +1,2159 @@ +/* + * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240, + * GT64260, MV64340, MV64360, GT96100, ... ). + * + * Author: Mark A. Greer + * + * Based on an old MPSC driver that was in the linuxppc tree. It appears to + * have been created by Chris Zankel (formerly of MontaVista) but there + * is no proper Copyright so I'm not sure. Apparently, parts were also + * taken from PPCBoot (now U-Boot). Also based on drivers/serial/8250.c + * by Russell King. + * + * 2004 (c) MontaVista, Software, Inc. 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. + */ +/* + * The MPSC interface is much like a typical network controller's interface. + * That is, you set up separate rings of descriptors for transmitting and + * receiving data. There is also a pool of buffers with (one buffer per + * descriptor) that incoming data are dma'd into or outgoing data are dma'd + * out of. + * + * The MPSC requires two other controllers to be able to work. The Baud Rate + * Generator (BRG) provides a clock at programmable frequencies which determines + * the baud rate. The Serial DMA Controller (SDMA) takes incoming data from the + * MPSC and DMA's it into memory or DMA's outgoing data and passes it to the + * MPSC. It is actually the SDMA interrupt that the driver uses to keep the + * transmit and receive "engines" going (i.e., indicate data has been + * transmitted or received). + * + * NOTES: + * + * 1) Some chips have an erratum where several regs cannot be + * read. To work around that, we keep a local copy of those regs in + * 'mpsc_port_info'. + * + * 2) Some chips have an erratum where the ctlr will hang when the SDMA ctlr + * accesses system mem with coherency enabled. For that reason, the driver + * assumes that coherency for that ctlr has been disabled. This means + * that when in a cache coherent system, the driver has to manually manage + * the data cache on the areas that it touches because the dma_* macro are + * basically no-ops. + * + * 3) There is an erratum (on PPC) where you can't use the instruction to do + * a DMA_TO_DEVICE/cache clean so DMA_BIDIRECTIONAL/flushes are used in places + * where a DMA_TO_DEVICE/clean would have [otherwise] sufficed. + * + * 4) AFAICT, hardware flow control isn't supported by the controller --MAG. + */ + + +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MPSC_NUM_CTLRS 2 + +/* + * Descriptors and buffers must be cache line aligned. + * Buffers lengths must be multiple of cache line size. + * Number of Tx & Rx descriptors must be powers of 2. + */ +#define MPSC_RXR_ENTRIES 32 +#define MPSC_RXRE_SIZE dma_get_cache_alignment() +#define MPSC_RXR_SIZE (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE) +#define MPSC_RXBE_SIZE dma_get_cache_alignment() +#define MPSC_RXB_SIZE (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE) + +#define MPSC_TXR_ENTRIES 32 +#define MPSC_TXRE_SIZE dma_get_cache_alignment() +#define MPSC_TXR_SIZE (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE) +#define MPSC_TXBE_SIZE dma_get_cache_alignment() +#define MPSC_TXB_SIZE (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE) + +#define MPSC_DMA_ALLOC_SIZE (MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \ + + MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */) + +/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */ +struct mpsc_rx_desc { + u16 bufsize; + u16 bytecnt; + u32 cmdstat; + u32 link; + u32 buf_ptr; +} __attribute((packed)); + +struct mpsc_tx_desc { + u16 bytecnt; + u16 shadow; + u32 cmdstat; + u32 link; + u32 buf_ptr; +} __attribute((packed)); + +/* + * Some regs that have the erratum that you can't read them are are shared + * between the two MPSC controllers. This struct contains those shared regs. + */ +struct mpsc_shared_regs { + phys_addr_t mpsc_routing_base_p; + phys_addr_t sdma_intr_base_p; + + void __iomem *mpsc_routing_base; + void __iomem *sdma_intr_base; + + u32 MPSC_MRR_m; + u32 MPSC_RCRR_m; + u32 MPSC_TCRR_m; + u32 SDMA_INTR_CAUSE_m; + u32 SDMA_INTR_MASK_m; +}; + +/* The main driver data structure */ +struct mpsc_port_info { + struct uart_port port; /* Overlay uart_port structure */ + + /* Internal driver state for this ctlr */ + u8 ready; + u8 rcv_data; + tcflag_t c_iflag; /* save termios->c_iflag */ + tcflag_t c_cflag; /* save termios->c_cflag */ + + /* Info passed in from platform */ + u8 mirror_regs; /* Need to mirror regs? */ + u8 cache_mgmt; /* Need manual cache mgmt? */ + u8 brg_can_tune; /* BRG has baud tuning? */ + u32 brg_clk_src; + u16 mpsc_max_idle; + int default_baud; + int default_bits; + int default_parity; + int default_flow; + + /* Physical addresses of various blocks of registers (from platform) */ + phys_addr_t mpsc_base_p; + phys_addr_t sdma_base_p; + phys_addr_t brg_base_p; + + /* Virtual addresses of various blocks of registers (from platform) */ + void __iomem *mpsc_base; + void __iomem *sdma_base; + void __iomem *brg_base; + + /* Descriptor ring and buffer allocations */ + void *dma_region; + dma_addr_t dma_region_p; + + dma_addr_t rxr; /* Rx descriptor ring */ + dma_addr_t rxr_p; /* Phys addr of rxr */ + u8 *rxb; /* Rx Ring I/O buf */ + u8 *rxb_p; /* Phys addr of rxb */ + u32 rxr_posn; /* First desc w/ Rx data */ + + dma_addr_t txr; /* Tx descriptor ring */ + dma_addr_t txr_p; /* Phys addr of txr */ + u8 *txb; /* Tx Ring I/O buf */ + u8 *txb_p; /* Phys addr of txb */ + int txr_head; /* Where new data goes */ + int txr_tail; /* Where sent data comes off */ + spinlock_t tx_lock; /* transmit lock */ + + /* Mirrored values of regs we can't read (if 'mirror_regs' set) */ + u32 MPSC_MPCR_m; + u32 MPSC_CHR_1_m; + u32 MPSC_CHR_2_m; + u32 MPSC_CHR_10_m; + u32 BRG_BCR_m; + struct mpsc_shared_regs *shared_regs; +}; + +/* Hooks to platform-specific code */ +int mpsc_platform_register_driver(void); +void mpsc_platform_unregister_driver(void); + +/* Hooks back in to mpsc common to be called by platform-specific code */ +struct mpsc_port_info *mpsc_device_probe(int index); +struct mpsc_port_info *mpsc_device_remove(int index); + +/* Main MPSC Configuration Register Offsets */ +#define MPSC_MMCRL 0x0000 +#define MPSC_MMCRH 0x0004 +#define MPSC_MPCR 0x0008 +#define MPSC_CHR_1 0x000c +#define MPSC_CHR_2 0x0010 +#define MPSC_CHR_3 0x0014 +#define MPSC_CHR_4 0x0018 +#define MPSC_CHR_5 0x001c +#define MPSC_CHR_6 0x0020 +#define MPSC_CHR_7 0x0024 +#define MPSC_CHR_8 0x0028 +#define MPSC_CHR_9 0x002c +#define MPSC_CHR_10 0x0030 +#define MPSC_CHR_11 0x0034 + +#define MPSC_MPCR_FRZ (1 << 9) +#define MPSC_MPCR_CL_5 0 +#define MPSC_MPCR_CL_6 1 +#define MPSC_MPCR_CL_7 2 +#define MPSC_MPCR_CL_8 3 +#define MPSC_MPCR_SBL_1 0 +#define MPSC_MPCR_SBL_2 1 + +#define MPSC_CHR_2_TEV (1<<1) +#define MPSC_CHR_2_TA (1<<7) +#define MPSC_CHR_2_TTCS (1<<9) +#define MPSC_CHR_2_REV (1<<17) +#define MPSC_CHR_2_RA (1<<23) +#define MPSC_CHR_2_CRD (1<<25) +#define MPSC_CHR_2_EH (1<<31) +#define MPSC_CHR_2_PAR_ODD 0 +#define MPSC_CHR_2_PAR_SPACE 1 +#define MPSC_CHR_2_PAR_EVEN 2 +#define MPSC_CHR_2_PAR_MARK 3 + +/* MPSC Signal Routing */ +#define MPSC_MRR 0x0000 +#define MPSC_RCRR 0x0004 +#define MPSC_TCRR 0x0008 + +/* Serial DMA Controller Interface Registers */ +#define SDMA_SDC 0x0000 +#define SDMA_SDCM 0x0008 +#define SDMA_RX_DESC 0x0800 +#define SDMA_RX_BUF_PTR 0x0808 +#define SDMA_SCRDP 0x0810 +#define SDMA_TX_DESC 0x0c00 +#define SDMA_SCTDP 0x0c10 +#define SDMA_SFTDP 0x0c14 + +#define SDMA_DESC_CMDSTAT_PE (1<<0) +#define SDMA_DESC_CMDSTAT_CDL (1<<1) +#define SDMA_DESC_CMDSTAT_FR (1<<3) +#define SDMA_DESC_CMDSTAT_OR (1<<6) +#define SDMA_DESC_CMDSTAT_BR (1<<9) +#define SDMA_DESC_CMDSTAT_MI (1<<10) +#define SDMA_DESC_CMDSTAT_A (1<<11) +#define SDMA_DESC_CMDSTAT_AM (1<<12) +#define SDMA_DESC_CMDSTAT_CT (1<<13) +#define SDMA_DESC_CMDSTAT_C (1<<14) +#define SDMA_DESC_CMDSTAT_ES (1<<15) +#define SDMA_DESC_CMDSTAT_L (1<<16) +#define SDMA_DESC_CMDSTAT_F (1<<17) +#define SDMA_DESC_CMDSTAT_P (1<<18) +#define SDMA_DESC_CMDSTAT_EI (1<<23) +#define SDMA_DESC_CMDSTAT_O (1<<31) + +#define SDMA_DESC_DFLT (SDMA_DESC_CMDSTAT_O \ + | SDMA_DESC_CMDSTAT_EI) + +#define SDMA_SDC_RFT (1<<0) +#define SDMA_SDC_SFM (1<<1) +#define SDMA_SDC_BLMR (1<<6) +#define SDMA_SDC_BLMT (1<<7) +#define SDMA_SDC_POVR (1<<8) +#define SDMA_SDC_RIFB (1<<9) + +#define SDMA_SDCM_ERD (1<<7) +#define SDMA_SDCM_AR (1<<15) +#define SDMA_SDCM_STD (1<<16) +#define SDMA_SDCM_TXD (1<<23) +#define SDMA_SDCM_AT (1<<31) + +#define SDMA_0_CAUSE_RXBUF (1<<0) +#define SDMA_0_CAUSE_RXERR (1<<1) +#define SDMA_0_CAUSE_TXBUF (1<<2) +#define SDMA_0_CAUSE_TXEND (1<<3) +#define SDMA_1_CAUSE_RXBUF (1<<8) +#define SDMA_1_CAUSE_RXERR (1<<9) +#define SDMA_1_CAUSE_TXBUF (1<<10) +#define SDMA_1_CAUSE_TXEND (1<<11) + +#define SDMA_CAUSE_RX_MASK (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \ + | SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR) +#define SDMA_CAUSE_TX_MASK (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \ + | SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND) + +/* SDMA Interrupt registers */ +#define SDMA_INTR_CAUSE 0x0000 +#define SDMA_INTR_MASK 0x0080 + +/* Baud Rate Generator Interface Registers */ +#define BRG_BCR 0x0000 +#define BRG_BTR 0x0004 + +/* + * Define how this driver is known to the outside (we've been assigned a + * range on the "Low-density serial ports" major). + */ +#define MPSC_MAJOR 204 +#define MPSC_MINOR_START 44 +#define MPSC_DRIVER_NAME "MPSC" +#define MPSC_DEV_NAME "ttyMM" +#define MPSC_VERSION "1.00" + +static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS]; +static struct mpsc_shared_regs mpsc_shared_regs; +static struct uart_driver mpsc_reg; + +static void mpsc_start_rx(struct mpsc_port_info *pi); +static void mpsc_free_ring_mem(struct mpsc_port_info *pi); +static void mpsc_release_port(struct uart_port *port); +/* + ****************************************************************************** + * + * Baud Rate Generator Routines (BRG) + * + ****************************************************************************** + */ +static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src) +{ + u32 v; + + v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); + v = (v & ~(0xf << 18)) | ((clk_src & 0xf) << 18); + + if (pi->brg_can_tune) + v &= ~(1 << 25); + + if (pi->mirror_regs) + pi->BRG_BCR_m = v; + writel(v, pi->brg_base + BRG_BCR); + + writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000, + pi->brg_base + BRG_BTR); +} + +static void mpsc_brg_enable(struct mpsc_port_info *pi) +{ + u32 v; + + v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); + v |= (1 << 16); + + if (pi->mirror_regs) + pi->BRG_BCR_m = v; + writel(v, pi->brg_base + BRG_BCR); +} + +static void mpsc_brg_disable(struct mpsc_port_info *pi) +{ + u32 v; + + v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); + v &= ~(1 << 16); + + if (pi->mirror_regs) + pi->BRG_BCR_m = v; + writel(v, pi->brg_base + BRG_BCR); +} + +/* + * To set the baud, we adjust the CDV field in the BRG_BCR reg. + * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1. + * However, the input clock is divided by 16 in the MPSC b/c of how + * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our + * calculation by 16 to account for that. So the real calculation + * that accounts for the way the mpsc is set up is: + * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1. + */ +static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud) +{ + u32 cdv = (pi->port.uartclk / (baud << 5)) - 1; + u32 v; + + mpsc_brg_disable(pi); + v = (pi->mirror_regs) ? pi->BRG_BCR_m : readl(pi->brg_base + BRG_BCR); + v = (v & 0xffff0000) | (cdv & 0xffff); + + if (pi->mirror_regs) + pi->BRG_BCR_m = v; + writel(v, pi->brg_base + BRG_BCR); + mpsc_brg_enable(pi); +} + +/* + ****************************************************************************** + * + * Serial DMA Routines (SDMA) + * + ****************************************************************************** + */ + +static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size) +{ + u32 v; + + pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n", + pi->port.line, burst_size); + + burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */ + + if (burst_size < 2) + v = 0x0; /* 1 64-bit word */ + else if (burst_size < 4) + v = 0x1; /* 2 64-bit words */ + else if (burst_size < 8) + v = 0x2; /* 4 64-bit words */ + else + v = 0x3; /* 8 64-bit words */ + + writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12), + pi->sdma_base + SDMA_SDC); +} + +static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size) +{ + pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line, + burst_size); + + writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f, + pi->sdma_base + SDMA_SDC); + mpsc_sdma_burstsize(pi, burst_size); +} + +static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask) +{ + u32 old, v; + + pr_debug("mpsc_sdma_intr_mask[%d]: mask: 0x%x\n", pi->port.line, mask); + + old = v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m : + readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); + + mask &= 0xf; + if (pi->port.line) + mask <<= 8; + v &= ~mask; + + if (pi->mirror_regs) + pi->shared_regs->SDMA_INTR_MASK_m = v; + writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); + + if (pi->port.line) + old >>= 8; + return old & 0xf; +} + +static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask) +{ + u32 v; + + pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask); + + v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m + : readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); + + mask &= 0xf; + if (pi->port.line) + mask <<= 8; + v |= mask; + + if (pi->mirror_regs) + pi->shared_regs->SDMA_INTR_MASK_m = v; + writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK); +} + +static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line); + + if (pi->mirror_regs) + pi->shared_regs->SDMA_INTR_CAUSE_m = 0; + writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE + + pi->port.line); +} + +static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi, + struct mpsc_rx_desc *rxre_p) +{ + pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n", + pi->port.line, (u32)rxre_p); + + writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP); +} + +static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi, + struct mpsc_tx_desc *txre_p) +{ + writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP); + writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP); +} + +static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val) +{ + u32 v; + + v = readl(pi->sdma_base + SDMA_SDCM); + if (val) + v |= val; + else + v = 0; + wmb(); + writel(v, pi->sdma_base + SDMA_SDCM); + wmb(); +} + +static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi) +{ + return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD; +} + +static void mpsc_sdma_start_tx(struct mpsc_port_info *pi) +{ + struct mpsc_tx_desc *txre, *txre_p; + + /* If tx isn't running & there's a desc ready to go, start it */ + if (!mpsc_sdma_tx_active(pi)) { + txre = (struct mpsc_tx_desc *)(pi->txr + + (pi->txr_tail * MPSC_TXRE_SIZE)); + dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, + DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)txre, + (ulong)txre + MPSC_TXRE_SIZE); +#endif + + if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) { + txre_p = (struct mpsc_tx_desc *) + (pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE)); + + mpsc_sdma_set_tx_ring(pi, txre_p); + mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD); + } + } +} + +static void mpsc_sdma_stop(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line); + + /* Abort any SDMA transfers */ + mpsc_sdma_cmd(pi, 0); + mpsc_sdma_cmd(pi, SDMA_SDCM_AR | SDMA_SDCM_AT); + + /* Clear the SDMA current and first TX and RX pointers */ + mpsc_sdma_set_tx_ring(pi, NULL); + mpsc_sdma_set_rx_ring(pi, NULL); + + /* Disable interrupts */ + mpsc_sdma_intr_mask(pi, 0xf); + mpsc_sdma_intr_ack(pi); +} + +/* + ****************************************************************************** + * + * Multi-Protocol Serial Controller Routines (MPSC) + * + ****************************************************************************** + */ + +static void mpsc_hw_init(struct mpsc_port_info *pi) +{ + u32 v; + + pr_debug("mpsc_hw_init[%d]: Initializing hardware\n", pi->port.line); + + /* Set up clock routing */ + if (pi->mirror_regs) { + v = pi->shared_regs->MPSC_MRR_m; + v &= ~0x1c7; + pi->shared_regs->MPSC_MRR_m = v; + writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR); + + v = pi->shared_regs->MPSC_RCRR_m; + v = (v & ~0xf0f) | 0x100; + pi->shared_regs->MPSC_RCRR_m = v; + writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR); + + v = pi->shared_regs->MPSC_TCRR_m; + v = (v & ~0xf0f) | 0x100; + pi->shared_regs->MPSC_TCRR_m = v; + writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR); + } else { + v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR); + v &= ~0x1c7; + writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR); + + v = readl(pi->shared_regs->mpsc_routing_base + MPSC_RCRR); + v = (v & ~0xf0f) | 0x100; + writel(v, pi->shared_regs->mpsc_routing_base + MPSC_RCRR); + + v = readl(pi->shared_regs->mpsc_routing_base + MPSC_TCRR); + v = (v & ~0xf0f) | 0x100; + writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR); + } + + /* Put MPSC in UART mode & enabel Tx/Rx egines */ + writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL); + + /* No preamble, 16x divider, low-latency, */ + writel(0x04400400, pi->mpsc_base + MPSC_MMCRH); + mpsc_set_baudrate(pi, pi->default_baud); + + if (pi->mirror_regs) { + pi->MPSC_CHR_1_m = 0; + pi->MPSC_CHR_2_m = 0; + } + writel(0, pi->mpsc_base + MPSC_CHR_1); + writel(0, pi->mpsc_base + MPSC_CHR_2); + writel(pi->mpsc_max_idle, pi->mpsc_base + MPSC_CHR_3); + writel(0, pi->mpsc_base + MPSC_CHR_4); + writel(0, pi->mpsc_base + MPSC_CHR_5); + writel(0, pi->mpsc_base + MPSC_CHR_6); + writel(0, pi->mpsc_base + MPSC_CHR_7); + writel(0, pi->mpsc_base + MPSC_CHR_8); + writel(0, pi->mpsc_base + MPSC_CHR_9); + writel(0, pi->mpsc_base + MPSC_CHR_10); +} + +static void mpsc_enter_hunt(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line); + + if (pi->mirror_regs) { + writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_EH, + pi->mpsc_base + MPSC_CHR_2); + /* Erratum prevents reading CHR_2 so just delay for a while */ + udelay(100); + } else { + writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH, + pi->mpsc_base + MPSC_CHR_2); + + while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH) + udelay(10); + } +} + +static void mpsc_freeze(struct mpsc_port_info *pi) +{ + u32 v; + + pr_debug("mpsc_freeze[%d]: Freezing\n", pi->port.line); + + v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : + readl(pi->mpsc_base + MPSC_MPCR); + v |= MPSC_MPCR_FRZ; + + if (pi->mirror_regs) + pi->MPSC_MPCR_m = v; + writel(v, pi->mpsc_base + MPSC_MPCR); +} + +static void mpsc_unfreeze(struct mpsc_port_info *pi) +{ + u32 v; + + v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : + readl(pi->mpsc_base + MPSC_MPCR); + v &= ~MPSC_MPCR_FRZ; + + if (pi->mirror_regs) + pi->MPSC_MPCR_m = v; + writel(v, pi->mpsc_base + MPSC_MPCR); + + pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line); +} + +static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len) +{ + u32 v; + + pr_debug("mpsc_set_char_length[%d]: char len: %d\n", pi->port.line,len); + + v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : + readl(pi->mpsc_base + MPSC_MPCR); + v = (v & ~(0x3 << 12)) | ((len & 0x3) << 12); + + if (pi->mirror_regs) + pi->MPSC_MPCR_m = v; + writel(v, pi->mpsc_base + MPSC_MPCR); +} + +static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len) +{ + u32 v; + + pr_debug("mpsc_set_stop_bit_length[%d]: stop bits: %d\n", + pi->port.line, len); + + v = (pi->mirror_regs) ? pi->MPSC_MPCR_m : + readl(pi->mpsc_base + MPSC_MPCR); + + v = (v & ~(1 << 14)) | ((len & 0x1) << 14); + + if (pi->mirror_regs) + pi->MPSC_MPCR_m = v; + writel(v, pi->mpsc_base + MPSC_MPCR); +} + +static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p) +{ + u32 v; + + pr_debug("mpsc_set_parity[%d]: parity bits: 0x%x\n", pi->port.line, p); + + v = (pi->mirror_regs) ? pi->MPSC_CHR_2_m : + readl(pi->mpsc_base + MPSC_CHR_2); + + p &= 0x3; + v = (v & ~0xc000c) | (p << 18) | (p << 2); + + if (pi->mirror_regs) + pi->MPSC_CHR_2_m = v; + writel(v, pi->mpsc_base + MPSC_CHR_2); +} + +/* + ****************************************************************************** + * + * Driver Init Routines + * + ****************************************************************************** + */ + +static void mpsc_init_hw(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line); + + mpsc_brg_init(pi, pi->brg_clk_src); + mpsc_brg_enable(pi); + mpsc_sdma_init(pi, dma_get_cache_alignment()); /* burst a cacheline */ + mpsc_sdma_stop(pi); + mpsc_hw_init(pi); +} + +static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi) +{ + int rc = 0; + + pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n", + pi->port.line); + + if (!pi->dma_region) { + if (!dma_supported(pi->port.dev, 0xffffffff)) { + printk(KERN_ERR "MPSC: Inadequate DMA support\n"); + rc = -ENXIO; + } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev, + MPSC_DMA_ALLOC_SIZE, + &pi->dma_region_p, GFP_KERNEL)) + == NULL) { + printk(KERN_ERR "MPSC: Can't alloc Desc region\n"); + rc = -ENOMEM; + } + } + + return rc; +} + +static void mpsc_free_ring_mem(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line); + + if (pi->dma_region) { + dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE, + pi->dma_region, pi->dma_region_p); + pi->dma_region = NULL; + pi->dma_region_p = (dma_addr_t)NULL; + } +} + +static void mpsc_init_rings(struct mpsc_port_info *pi) +{ + struct mpsc_rx_desc *rxre; + struct mpsc_tx_desc *txre; + dma_addr_t dp, dp_p; + u8 *bp, *bp_p; + int i; + + pr_debug("mpsc_init_rings[%d]: Initializing rings\n", pi->port.line); + + BUG_ON(pi->dma_region == NULL); + + memset(pi->dma_region, 0, MPSC_DMA_ALLOC_SIZE); + + /* + * Descriptors & buffers are multiples of cacheline size and must be + * cacheline aligned. + */ + dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment()); + dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment()); + + /* + * Partition dma region into rx ring descriptor, rx buffers, + * tx ring descriptors, and tx buffers. + */ + pi->rxr = dp; + pi->rxr_p = dp_p; + dp += MPSC_RXR_SIZE; + dp_p += MPSC_RXR_SIZE; + + pi->rxb = (u8 *)dp; + pi->rxb_p = (u8 *)dp_p; + dp += MPSC_RXB_SIZE; + dp_p += MPSC_RXB_SIZE; + + pi->rxr_posn = 0; + + pi->txr = dp; + pi->txr_p = dp_p; + dp += MPSC_TXR_SIZE; + dp_p += MPSC_TXR_SIZE; + + pi->txb = (u8 *)dp; + pi->txb_p = (u8 *)dp_p; + + pi->txr_head = 0; + pi->txr_tail = 0; + + /* Init rx ring descriptors */ + dp = pi->rxr; + dp_p = pi->rxr_p; + bp = pi->rxb; + bp_p = pi->rxb_p; + + for (i = 0; i < MPSC_RXR_ENTRIES; i++) { + rxre = (struct mpsc_rx_desc *)dp; + + rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE); + rxre->bytecnt = cpu_to_be16(0); + rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O + | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F + | SDMA_DESC_CMDSTAT_L); + rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE); + rxre->buf_ptr = cpu_to_be32(bp_p); + + dp += MPSC_RXRE_SIZE; + dp_p += MPSC_RXRE_SIZE; + bp += MPSC_RXBE_SIZE; + bp_p += MPSC_RXBE_SIZE; + } + rxre->link = cpu_to_be32(pi->rxr_p); /* Wrap last back to first */ + + /* Init tx ring descriptors */ + dp = pi->txr; + dp_p = pi->txr_p; + bp = pi->txb; + bp_p = pi->txb_p; + + for (i = 0; i < MPSC_TXR_ENTRIES; i++) { + txre = (struct mpsc_tx_desc *)dp; + + txre->link = cpu_to_be32(dp_p + MPSC_TXRE_SIZE); + txre->buf_ptr = cpu_to_be32(bp_p); + + dp += MPSC_TXRE_SIZE; + dp_p += MPSC_TXRE_SIZE; + bp += MPSC_TXBE_SIZE; + bp_p += MPSC_TXBE_SIZE; + } + txre->link = cpu_to_be32(pi->txr_p); /* Wrap last back to first */ + + dma_cache_sync(pi->port.dev, (void *)pi->dma_region, + MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + flush_dcache_range((ulong)pi->dma_region, + (ulong)pi->dma_region + + MPSC_DMA_ALLOC_SIZE); +#endif + + return; +} + +static void mpsc_uninit_rings(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line); + + BUG_ON(pi->dma_region == NULL); + + pi->rxr = 0; + pi->rxr_p = 0; + pi->rxb = NULL; + pi->rxb_p = NULL; + pi->rxr_posn = 0; + + pi->txr = 0; + pi->txr_p = 0; + pi->txb = NULL; + pi->txb_p = NULL; + pi->txr_head = 0; + pi->txr_tail = 0; +} + +static int mpsc_make_ready(struct mpsc_port_info *pi) +{ + int rc; + + pr_debug("mpsc_make_ready[%d]: Making cltr ready\n", pi->port.line); + + if (!pi->ready) { + mpsc_init_hw(pi); + if ((rc = mpsc_alloc_ring_mem(pi))) + return rc; + mpsc_init_rings(pi); + pi->ready = 1; + } + + return 0; +} + +#ifdef CONFIG_CONSOLE_POLL +static int serial_polled; +#endif + +/* + ****************************************************************************** + * + * Interrupt Handling Routines + * + ****************************************************************************** + */ + +static int mpsc_rx_intr(struct mpsc_port_info *pi) +{ + struct mpsc_rx_desc *rxre; + struct tty_struct *tty = pi->port.state->port.tty; + u32 cmdstat, bytes_in, i; + int rc = 0; + u8 *bp; + char flag = TTY_NORMAL; + + pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); + + rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE)); + + dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, + DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)rxre, + (ulong)rxre + MPSC_RXRE_SIZE); +#endif + + /* + * Loop through Rx descriptors handling ones that have been completed. + */ + while (!((cmdstat = be32_to_cpu(rxre->cmdstat)) + & SDMA_DESC_CMDSTAT_O)) { + bytes_in = be16_to_cpu(rxre->bytecnt); +#ifdef CONFIG_CONSOLE_POLL + if (unlikely(serial_polled)) { + serial_polled = 0; + return 0; + } +#endif + /* Following use of tty struct directly is deprecated */ + if (unlikely(tty_buffer_request_room(tty, bytes_in) + < bytes_in)) { + if (tty->low_latency) + tty_flip_buffer_push(tty); + /* + * If this failed then we will throw away the bytes + * but must do so to clear interrupts. + */ + } + + bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE); + dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE, + DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)bp, + (ulong)bp + MPSC_RXBE_SIZE); +#endif + + /* + * Other than for parity error, the manual provides little + * info on what data will be in a frame flagged by any of + * these errors. For parity error, it is the last byte in + * the buffer that had the error. As for the rest, I guess + * we'll assume there is no data in the buffer. + * If there is...it gets lost. + */ + if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR + | SDMA_DESC_CMDSTAT_FR + | SDMA_DESC_CMDSTAT_OR))) { + + pi->port.icount.rx++; + + if (cmdstat & SDMA_DESC_CMDSTAT_BR) { /* Break */ + pi->port.icount.brk++; + + if (uart_handle_break(&pi->port)) + goto next_frame; + } else if (cmdstat & SDMA_DESC_CMDSTAT_FR) { + pi->port.icount.frame++; + } else if (cmdstat & SDMA_DESC_CMDSTAT_OR) { + pi->port.icount.overrun++; + } + + cmdstat &= pi->port.read_status_mask; + + if (cmdstat & SDMA_DESC_CMDSTAT_BR) + flag = TTY_BREAK; + else if (cmdstat & SDMA_DESC_CMDSTAT_FR) + flag = TTY_FRAME; + else if (cmdstat & SDMA_DESC_CMDSTAT_OR) + flag = TTY_OVERRUN; + else if (cmdstat & SDMA_DESC_CMDSTAT_PE) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(&pi->port, *bp)) { + bp++; + bytes_in--; +#ifdef CONFIG_CONSOLE_POLL + if (unlikely(serial_polled)) { + serial_polled = 0; + return 0; + } +#endif + goto next_frame; + } + + if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR + | SDMA_DESC_CMDSTAT_FR + | SDMA_DESC_CMDSTAT_OR))) + && !(cmdstat & pi->port.ignore_status_mask)) { + tty_insert_flip_char(tty, *bp, flag); + } else { + for (i=0; iport.icount.rx += bytes_in; + } + +next_frame: + rxre->bytecnt = cpu_to_be16(0); + wmb(); + rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O + | SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F + | SDMA_DESC_CMDSTAT_L); + wmb(); + dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, + DMA_BIDIRECTIONAL); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + flush_dcache_range((ulong)rxre, + (ulong)rxre + MPSC_RXRE_SIZE); +#endif + + /* Advance to next descriptor */ + pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1); + rxre = (struct mpsc_rx_desc *) + (pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE)); + dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, + DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)rxre, + (ulong)rxre + MPSC_RXRE_SIZE); +#endif + rc = 1; + } + + /* Restart rx engine, if its stopped */ + if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0) + mpsc_start_rx(pi); + + tty_flip_buffer_push(tty); + return rc; +} + +static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr) +{ + struct mpsc_tx_desc *txre; + + txre = (struct mpsc_tx_desc *)(pi->txr + + (pi->txr_head * MPSC_TXRE_SIZE)); + + txre->bytecnt = cpu_to_be16(count); + txre->shadow = txre->bytecnt; + wmb(); /* ensure cmdstat is last field updated */ + txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F + | SDMA_DESC_CMDSTAT_L + | ((intr) ? SDMA_DESC_CMDSTAT_EI : 0)); + wmb(); + dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, + DMA_BIDIRECTIONAL); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + flush_dcache_range((ulong)txre, + (ulong)txre + MPSC_TXRE_SIZE); +#endif +} + +static void mpsc_copy_tx_data(struct mpsc_port_info *pi) +{ + struct circ_buf *xmit = &pi->port.state->xmit; + u8 *bp; + u32 i; + + /* Make sure the desc ring isn't full */ + while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES) + < (MPSC_TXR_ENTRIES - 1)) { + if (pi->port.x_char) { + /* + * Ideally, we should use the TCS field in + * CHR_1 to put the x_char out immediately but + * errata prevents us from being able to read + * CHR_2 to know that its safe to write to + * CHR_1. Instead, just put it in-band with + * all the other Tx data. + */ + bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); + *bp = pi->port.x_char; + pi->port.x_char = 0; + i = 1; + } else if (!uart_circ_empty(xmit) + && !uart_tx_stopped(&pi->port)) { + i = min((u32)MPSC_TXBE_SIZE, + (u32)uart_circ_chars_pending(xmit)); + i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail, + UART_XMIT_SIZE)); + bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); + memcpy(bp, &xmit->buf[xmit->tail], i); + xmit->tail = (xmit->tail + i) & (UART_XMIT_SIZE - 1); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&pi->port); + } else { /* All tx data copied into ring bufs */ + return; + } + + dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE, + DMA_BIDIRECTIONAL); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + flush_dcache_range((ulong)bp, + (ulong)bp + MPSC_TXBE_SIZE); +#endif + mpsc_setup_tx_desc(pi, i, 1); + + /* Advance to next descriptor */ + pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1); + } +} + +static int mpsc_tx_intr(struct mpsc_port_info *pi) +{ + struct mpsc_tx_desc *txre; + int rc = 0; + unsigned long iflags; + + spin_lock_irqsave(&pi->tx_lock, iflags); + + if (!mpsc_sdma_tx_active(pi)) { + txre = (struct mpsc_tx_desc *)(pi->txr + + (pi->txr_tail * MPSC_TXRE_SIZE)); + + dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE, + DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)txre, + (ulong)txre + MPSC_TXRE_SIZE); +#endif + + while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) { + rc = 1; + pi->port.icount.tx += be16_to_cpu(txre->bytecnt); + pi->txr_tail = (pi->txr_tail+1) & (MPSC_TXR_ENTRIES-1); + + /* If no more data to tx, fall out of loop */ + if (pi->txr_head == pi->txr_tail) + break; + + txre = (struct mpsc_tx_desc *)(pi->txr + + (pi->txr_tail * MPSC_TXRE_SIZE)); + dma_cache_sync(pi->port.dev, (void *)txre, + MPSC_TXRE_SIZE, DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)txre, + (ulong)txre + MPSC_TXRE_SIZE); +#endif + } + + mpsc_copy_tx_data(pi); + mpsc_sdma_start_tx(pi); /* start next desc if ready */ + } + + spin_unlock_irqrestore(&pi->tx_lock, iflags); + return rc; +} + +/* + * This is the driver's interrupt handler. To avoid a race, we first clear + * the interrupt, then handle any completed Rx/Tx descriptors. When done + * handling those descriptors, we restart the Rx/Tx engines if they're stopped. + */ +static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id) +{ + struct mpsc_port_info *pi = dev_id; + ulong iflags; + int rc = IRQ_NONE; + + pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Received\n",pi->port.line); + + spin_lock_irqsave(&pi->port.lock, iflags); + mpsc_sdma_intr_ack(pi); + if (mpsc_rx_intr(pi)) + rc = IRQ_HANDLED; + if (mpsc_tx_intr(pi)) + rc = IRQ_HANDLED; + spin_unlock_irqrestore(&pi->port.lock, iflags); + + pr_debug("mpsc_sdma_intr[%d]: SDMA Interrupt Handled\n", pi->port.line); + return rc; +} + +/* + ****************************************************************************** + * + * serial_core.c Interface routines + * + ****************************************************************************** + */ +static uint mpsc_tx_empty(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + ulong iflags; + uint rc; + + spin_lock_irqsave(&pi->port.lock, iflags); + rc = mpsc_sdma_tx_active(pi) ? 0 : TIOCSER_TEMT; + spin_unlock_irqrestore(&pi->port.lock, iflags); + + return rc; +} + +static void mpsc_set_mctrl(struct uart_port *port, uint mctrl) +{ + /* Have no way to set modem control lines AFAICT */ +} + +static uint mpsc_get_mctrl(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + u32 mflags, status; + + status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m + : readl(pi->mpsc_base + MPSC_CHR_10); + + mflags = 0; + if (status & 0x1) + mflags |= TIOCM_CTS; + if (status & 0x2) + mflags |= TIOCM_CAR; + + return mflags | TIOCM_DSR; /* No way to tell if DSR asserted */ +} + +static void mpsc_stop_tx(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + + pr_debug("mpsc_stop_tx[%d]\n", port->line); + + mpsc_freeze(pi); +} + +static void mpsc_start_tx(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + unsigned long iflags; + + spin_lock_irqsave(&pi->tx_lock, iflags); + + mpsc_unfreeze(pi); + mpsc_copy_tx_data(pi); + mpsc_sdma_start_tx(pi); + + spin_unlock_irqrestore(&pi->tx_lock, iflags); + + pr_debug("mpsc_start_tx[%d]\n", port->line); +} + +static void mpsc_start_rx(struct mpsc_port_info *pi) +{ + pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line); + + if (pi->rcv_data) { + mpsc_enter_hunt(pi); + mpsc_sdma_cmd(pi, SDMA_SDCM_ERD); + } +} + +static void mpsc_stop_rx(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + + pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line); + + if (pi->mirror_regs) { + writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA, + pi->mpsc_base + MPSC_CHR_2); + /* Erratum prevents reading CHR_2 so just delay for a while */ + udelay(100); + } else { + writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA, + pi->mpsc_base + MPSC_CHR_2); + + while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA) + udelay(10); + } + + mpsc_sdma_cmd(pi, SDMA_SDCM_AR); +} + +static void mpsc_enable_ms(struct uart_port *port) +{ +} + +static void mpsc_break_ctl(struct uart_port *port, int ctl) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + ulong flags; + u32 v; + + v = ctl ? 0x00ff0000 : 0; + + spin_lock_irqsave(&pi->port.lock, flags); + if (pi->mirror_regs) + pi->MPSC_CHR_1_m = v; + writel(v, pi->mpsc_base + MPSC_CHR_1); + spin_unlock_irqrestore(&pi->port.lock, flags); +} + +static int mpsc_startup(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + u32 flag = 0; + int rc; + + pr_debug("mpsc_startup[%d]: Starting up MPSC, irq: %d\n", + port->line, pi->port.irq); + + if ((rc = mpsc_make_ready(pi)) == 0) { + /* Setup IRQ handler */ + mpsc_sdma_intr_ack(pi); + + /* If irq's are shared, need to set flag */ + if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq) + flag = IRQF_SHARED; + + if (request_irq(pi->port.irq, mpsc_sdma_intr, flag, + "mpsc-sdma", pi)) + printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n", + pi->port.irq); + + mpsc_sdma_intr_unmask(pi, 0xf); + mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p + + (pi->rxr_posn * MPSC_RXRE_SIZE))); + } + + return rc; +} + +static void mpsc_shutdown(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + + pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line); + + mpsc_sdma_stop(pi); + free_irq(pi->port.irq, pi); +} + +static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + u32 baud; + ulong flags; + u32 chr_bits, stop_bits, par; + + pi->c_iflag = termios->c_iflag; + pi->c_cflag = termios->c_cflag; + + switch (termios->c_cflag & CSIZE) { + case CS5: + chr_bits = MPSC_MPCR_CL_5; + break; + case CS6: + chr_bits = MPSC_MPCR_CL_6; + break; + case CS7: + chr_bits = MPSC_MPCR_CL_7; + break; + case CS8: + default: + chr_bits = MPSC_MPCR_CL_8; + break; + } + + if (termios->c_cflag & CSTOPB) + stop_bits = MPSC_MPCR_SBL_2; + else + stop_bits = MPSC_MPCR_SBL_1; + + par = MPSC_CHR_2_PAR_EVEN; + if (termios->c_cflag & PARENB) + if (termios->c_cflag & PARODD) + par = MPSC_CHR_2_PAR_ODD; +#ifdef CMSPAR + if (termios->c_cflag & CMSPAR) { + if (termios->c_cflag & PARODD) + par = MPSC_CHR_2_PAR_MARK; + else + par = MPSC_CHR_2_PAR_SPACE; + } +#endif + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk); + + spin_lock_irqsave(&pi->port.lock, flags); + + uart_update_timeout(port, termios->c_cflag, baud); + + mpsc_set_char_length(pi, chr_bits); + mpsc_set_stop_bit_length(pi, stop_bits); + mpsc_set_parity(pi, par); + mpsc_set_baudrate(pi, baud); + + /* Characters/events to read */ + pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR; + + if (termios->c_iflag & INPCK) + pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE + | SDMA_DESC_CMDSTAT_FR; + + if (termios->c_iflag & (BRKINT | PARMRK)) + pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR; + + /* Characters/events to ignore */ + pi->port.ignore_status_mask = 0; + + if (termios->c_iflag & IGNPAR) + pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE + | SDMA_DESC_CMDSTAT_FR; + + if (termios->c_iflag & IGNBRK) { + pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR; + + if (termios->c_iflag & IGNPAR) + pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR; + } + + if ((termios->c_cflag & CREAD)) { + if (!pi->rcv_data) { + pi->rcv_data = 1; + mpsc_start_rx(pi); + } + } else if (pi->rcv_data) { + mpsc_stop_rx(port); + pi->rcv_data = 0; + } + + spin_unlock_irqrestore(&pi->port.lock, flags); +} + +static const char *mpsc_type(struct uart_port *port) +{ + pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME); + return MPSC_DRIVER_NAME; +} + +static int mpsc_request_port(struct uart_port *port) +{ + /* Should make chip/platform specific call */ + return 0; +} + +static void mpsc_release_port(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + + if (pi->ready) { + mpsc_uninit_rings(pi); + mpsc_free_ring_mem(pi); + pi->ready = 0; + } +} + +static void mpsc_config_port(struct uart_port *port, int flags) +{ +} + +static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + int rc = 0; + + pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line); + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPSC) + rc = -EINVAL; + else if (pi->port.irq != ser->irq) + rc = -EINVAL; + else if (ser->io_type != SERIAL_IO_MEM) + rc = -EINVAL; + else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */ + rc = -EINVAL; + else if ((void *)pi->port.mapbase != ser->iomem_base) + rc = -EINVAL; + else if (pi->port.iobase != ser->port) + rc = -EINVAL; + else if (ser->hub6 != 0) + rc = -EINVAL; + + return rc; +} +#ifdef CONFIG_CONSOLE_POLL +/* Serial polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static char poll_buf[2048]; +static int poll_ptr; +static int poll_cnt; +static void mpsc_put_poll_char(struct uart_port *port, + unsigned char c); + +static int mpsc_get_poll_char(struct uart_port *port) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + struct mpsc_rx_desc *rxre; + u32 cmdstat, bytes_in, i; + u8 *bp; + + if (!serial_polled) + serial_polled = 1; + + pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); + + if (poll_cnt) { + poll_cnt--; + return poll_buf[poll_ptr++]; + } + poll_ptr = 0; + poll_cnt = 0; + + while (poll_cnt == 0) { + rxre = (struct mpsc_rx_desc *)(pi->rxr + + (pi->rxr_posn*MPSC_RXRE_SIZE)); + dma_cache_sync(pi->port.dev, (void *)rxre, + MPSC_RXRE_SIZE, DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)rxre, + (ulong)rxre + MPSC_RXRE_SIZE); +#endif + /* + * Loop through Rx descriptors handling ones that have + * been completed. + */ + while (poll_cnt == 0 && + !((cmdstat = be32_to_cpu(rxre->cmdstat)) & + SDMA_DESC_CMDSTAT_O)){ + bytes_in = be16_to_cpu(rxre->bytecnt); + bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE); + dma_cache_sync(pi->port.dev, (void *) bp, + MPSC_RXBE_SIZE, DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)bp, + (ulong)bp + MPSC_RXBE_SIZE); +#endif + if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR | + SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) && + !(cmdstat & pi->port.ignore_status_mask)) { + poll_buf[poll_cnt] = *bp; + poll_cnt++; + } else { + for (i = 0; i < bytes_in; i++) { + poll_buf[poll_cnt] = *bp++; + poll_cnt++; + } + pi->port.icount.rx += bytes_in; + } + rxre->bytecnt = cpu_to_be16(0); + wmb(); + rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | + SDMA_DESC_CMDSTAT_EI | + SDMA_DESC_CMDSTAT_F | + SDMA_DESC_CMDSTAT_L); + wmb(); + dma_cache_sync(pi->port.dev, (void *)rxre, + MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + flush_dcache_range((ulong)rxre, + (ulong)rxre + MPSC_RXRE_SIZE); +#endif + + /* Advance to next descriptor */ + pi->rxr_posn = (pi->rxr_posn + 1) & + (MPSC_RXR_ENTRIES - 1); + rxre = (struct mpsc_rx_desc *)(pi->rxr + + (pi->rxr_posn * MPSC_RXRE_SIZE)); + dma_cache_sync(pi->port.dev, (void *)rxre, + MPSC_RXRE_SIZE, DMA_FROM_DEVICE); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + invalidate_dcache_range((ulong)rxre, + (ulong)rxre + MPSC_RXRE_SIZE); +#endif + } + + /* Restart rx engine, if its stopped */ + if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0) + mpsc_start_rx(pi); + } + if (poll_cnt) { + poll_cnt--; + return poll_buf[poll_ptr++]; + } + + return 0; +} + + +static void mpsc_put_poll_char(struct uart_port *port, + unsigned char c) +{ + struct mpsc_port_info *pi = (struct mpsc_port_info *)port; + u32 data; + + data = readl(pi->mpsc_base + MPSC_MPCR); + writeb(c, pi->mpsc_base + MPSC_CHR_1); + mb(); + data = readl(pi->mpsc_base + MPSC_CHR_2); + data |= MPSC_CHR_2_TTCS; + writel(data, pi->mpsc_base + MPSC_CHR_2); + mb(); + + while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS); +} +#endif + +static struct uart_ops mpsc_pops = { + .tx_empty = mpsc_tx_empty, + .set_mctrl = mpsc_set_mctrl, + .get_mctrl = mpsc_get_mctrl, + .stop_tx = mpsc_stop_tx, + .start_tx = mpsc_start_tx, + .stop_rx = mpsc_stop_rx, + .enable_ms = mpsc_enable_ms, + .break_ctl = mpsc_break_ctl, + .startup = mpsc_startup, + .shutdown = mpsc_shutdown, + .set_termios = mpsc_set_termios, + .type = mpsc_type, + .release_port = mpsc_release_port, + .request_port = mpsc_request_port, + .config_port = mpsc_config_port, + .verify_port = mpsc_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = mpsc_get_poll_char, + .poll_put_char = mpsc_put_poll_char, +#endif +}; + +/* + ****************************************************************************** + * + * Console Interface Routines + * + ****************************************************************************** + */ + +#ifdef CONFIG_SERIAL_MPSC_CONSOLE +static void mpsc_console_write(struct console *co, const char *s, uint count) +{ + struct mpsc_port_info *pi = &mpsc_ports[co->index]; + u8 *bp, *dp, add_cr = 0; + int i; + unsigned long iflags; + + spin_lock_irqsave(&pi->tx_lock, iflags); + + while (pi->txr_head != pi->txr_tail) { + while (mpsc_sdma_tx_active(pi)) + udelay(100); + mpsc_sdma_intr_ack(pi); + mpsc_tx_intr(pi); + } + + while (mpsc_sdma_tx_active(pi)) + udelay(100); + + while (count > 0) { + bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE); + + for (i = 0; i < MPSC_TXBE_SIZE; i++) { + if (count == 0) + break; + + if (add_cr) { + *(dp++) = '\r'; + add_cr = 0; + } else { + *(dp++) = *s; + + if (*(s++) == '\n') { /* add '\r' after '\n' */ + add_cr = 1; + count++; + } + } + + count--; + } + + dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE, + DMA_BIDIRECTIONAL); +#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) + if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */ + flush_dcache_range((ulong)bp, + (ulong)bp + MPSC_TXBE_SIZE); +#endif + mpsc_setup_tx_desc(pi, i, 0); + pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1); + mpsc_sdma_start_tx(pi); + + while (mpsc_sdma_tx_active(pi)) + udelay(100); + + pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1); + } + + spin_unlock_irqrestore(&pi->tx_lock, iflags); +} + +static int __init mpsc_console_setup(struct console *co, char *options) +{ + struct mpsc_port_info *pi; + int baud, bits, parity, flow; + + pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options); + + if (co->index >= MPSC_NUM_CTLRS) + co->index = 0; + + pi = &mpsc_ports[co->index]; + + baud = pi->default_baud; + bits = pi->default_bits; + parity = pi->default_parity; + flow = pi->default_flow; + + if (!pi->port.ops) + return -ENODEV; + + spin_lock_init(&pi->port.lock); /* Temporary fix--copied from 8250.c */ + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&pi->port, co, baud, parity, bits, flow); +} + +static struct console mpsc_console = { + .name = MPSC_DEV_NAME, + .write = mpsc_console_write, + .device = uart_console_device, + .setup = mpsc_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &mpsc_reg, +}; + +static int __init mpsc_late_console_init(void) +{ + pr_debug("mpsc_late_console_init: Enter\n"); + + if (!(mpsc_console.flags & CON_ENABLED)) + register_console(&mpsc_console); + return 0; +} + +late_initcall(mpsc_late_console_init); + +#define MPSC_CONSOLE &mpsc_console +#else +#define MPSC_CONSOLE NULL +#endif +/* + ****************************************************************************** + * + * Dummy Platform Driver to extract & map shared register regions + * + ****************************************************************************** + */ +static void mpsc_resource_err(char *s) +{ + printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s); +} + +static int mpsc_shared_map_regs(struct platform_device *pd) +{ + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, + MPSC_ROUTING_BASE_ORDER)) + && request_mem_region(r->start, + MPSC_ROUTING_REG_BLOCK_SIZE, + "mpsc_routing_regs")) { + mpsc_shared_regs.mpsc_routing_base = ioremap(r->start, + MPSC_ROUTING_REG_BLOCK_SIZE); + mpsc_shared_regs.mpsc_routing_base_p = r->start; + } else { + mpsc_resource_err("MPSC routing base"); + return -ENOMEM; + } + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, + MPSC_SDMA_INTR_BASE_ORDER)) + && request_mem_region(r->start, + MPSC_SDMA_INTR_REG_BLOCK_SIZE, + "sdma_intr_regs")) { + mpsc_shared_regs.sdma_intr_base = ioremap(r->start, + MPSC_SDMA_INTR_REG_BLOCK_SIZE); + mpsc_shared_regs.sdma_intr_base_p = r->start; + } else { + iounmap(mpsc_shared_regs.mpsc_routing_base); + release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, + MPSC_ROUTING_REG_BLOCK_SIZE); + mpsc_resource_err("SDMA intr base"); + return -ENOMEM; + } + + return 0; +} + +static void mpsc_shared_unmap_regs(void) +{ + if (!mpsc_shared_regs.mpsc_routing_base) { + iounmap(mpsc_shared_regs.mpsc_routing_base); + release_mem_region(mpsc_shared_regs.mpsc_routing_base_p, + MPSC_ROUTING_REG_BLOCK_SIZE); + } + if (!mpsc_shared_regs.sdma_intr_base) { + iounmap(mpsc_shared_regs.sdma_intr_base); + release_mem_region(mpsc_shared_regs.sdma_intr_base_p, + MPSC_SDMA_INTR_REG_BLOCK_SIZE); + } + + mpsc_shared_regs.mpsc_routing_base = NULL; + mpsc_shared_regs.sdma_intr_base = NULL; + + mpsc_shared_regs.mpsc_routing_base_p = 0; + mpsc_shared_regs.sdma_intr_base_p = 0; +} + +static int mpsc_shared_drv_probe(struct platform_device *dev) +{ + struct mpsc_shared_pdata *pdata; + int rc = -ENODEV; + + if (dev->id == 0) { + if (!(rc = mpsc_shared_map_regs(dev))) { + pdata = (struct mpsc_shared_pdata *) + dev->dev.platform_data; + + mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val; + mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val; + mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val; + mpsc_shared_regs.SDMA_INTR_CAUSE_m = + pdata->intr_cause_val; + mpsc_shared_regs.SDMA_INTR_MASK_m = + pdata->intr_mask_val; + + rc = 0; + } + } + + return rc; +} + +static int mpsc_shared_drv_remove(struct platform_device *dev) +{ + int rc = -ENODEV; + + if (dev->id == 0) { + mpsc_shared_unmap_regs(); + mpsc_shared_regs.MPSC_MRR_m = 0; + mpsc_shared_regs.MPSC_RCRR_m = 0; + mpsc_shared_regs.MPSC_TCRR_m = 0; + mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0; + mpsc_shared_regs.SDMA_INTR_MASK_m = 0; + rc = 0; + } + + return rc; +} + +static struct platform_driver mpsc_shared_driver = { + .probe = mpsc_shared_drv_probe, + .remove = mpsc_shared_drv_remove, + .driver = { + .name = MPSC_SHARED_NAME, + }, +}; + +/* + ****************************************************************************** + * + * Driver Interface Routines + * + ****************************************************************************** + */ +static struct uart_driver mpsc_reg = { + .owner = THIS_MODULE, + .driver_name = MPSC_DRIVER_NAME, + .dev_name = MPSC_DEV_NAME, + .major = MPSC_MAJOR, + .minor = MPSC_MINOR_START, + .nr = MPSC_NUM_CTLRS, + .cons = MPSC_CONSOLE, +}; + +static int mpsc_drv_map_regs(struct mpsc_port_info *pi, + struct platform_device *pd) +{ + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER)) + && request_mem_region(r->start, MPSC_REG_BLOCK_SIZE, + "mpsc_regs")) { + pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE); + pi->mpsc_base_p = r->start; + } else { + mpsc_resource_err("MPSC base"); + goto err; + } + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, + MPSC_SDMA_BASE_ORDER)) + && request_mem_region(r->start, + MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) { + pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE); + pi->sdma_base_p = r->start; + } else { + mpsc_resource_err("SDMA base"); + if (pi->mpsc_base) { + iounmap(pi->mpsc_base); + pi->mpsc_base = NULL; + } + goto err; + } + + if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER)) + && request_mem_region(r->start, + MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) { + pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE); + pi->brg_base_p = r->start; + } else { + mpsc_resource_err("BRG base"); + if (pi->mpsc_base) { + iounmap(pi->mpsc_base); + pi->mpsc_base = NULL; + } + if (pi->sdma_base) { + iounmap(pi->sdma_base); + pi->sdma_base = NULL; + } + goto err; + } + return 0; + +err: + return -ENOMEM; +} + +static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi) +{ + if (!pi->mpsc_base) { + iounmap(pi->mpsc_base); + release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE); + } + if (!pi->sdma_base) { + iounmap(pi->sdma_base); + release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE); + } + if (!pi->brg_base) { + iounmap(pi->brg_base); + release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE); + } + + pi->mpsc_base = NULL; + pi->sdma_base = NULL; + pi->brg_base = NULL; + + pi->mpsc_base_p = 0; + pi->sdma_base_p = 0; + pi->brg_base_p = 0; +} + +static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi, + struct platform_device *pd, int num) +{ + struct mpsc_pdata *pdata; + + pdata = (struct mpsc_pdata *)pd->dev.platform_data; + + pi->port.uartclk = pdata->brg_clk_freq; + pi->port.iotype = UPIO_MEM; + pi->port.line = num; + pi->port.type = PORT_MPSC; + pi->port.fifosize = MPSC_TXBE_SIZE; + pi->port.membase = pi->mpsc_base; + pi->port.mapbase = (ulong)pi->mpsc_base; + pi->port.ops = &mpsc_pops; + + pi->mirror_regs = pdata->mirror_regs; + pi->cache_mgmt = pdata->cache_mgmt; + pi->brg_can_tune = pdata->brg_can_tune; + pi->brg_clk_src = pdata->brg_clk_src; + pi->mpsc_max_idle = pdata->max_idle; + pi->default_baud = pdata->default_baud; + pi->default_bits = pdata->default_bits; + pi->default_parity = pdata->default_parity; + pi->default_flow = pdata->default_flow; + + /* Initial values of mirrored regs */ + pi->MPSC_CHR_1_m = pdata->chr_1_val; + pi->MPSC_CHR_2_m = pdata->chr_2_val; + pi->MPSC_CHR_10_m = pdata->chr_10_val; + pi->MPSC_MPCR_m = pdata->mpcr_val; + pi->BRG_BCR_m = pdata->bcr_val; + + pi->shared_regs = &mpsc_shared_regs; + + pi->port.irq = platform_get_irq(pd, 0); +} + +static int mpsc_drv_probe(struct platform_device *dev) +{ + struct mpsc_port_info *pi; + int rc = -ENODEV; + + pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id); + + if (dev->id < MPSC_NUM_CTLRS) { + pi = &mpsc_ports[dev->id]; + + if (!(rc = mpsc_drv_map_regs(pi, dev))) { + mpsc_drv_get_platform_data(pi, dev, dev->id); + pi->port.dev = &dev->dev; + + if (!(rc = mpsc_make_ready(pi))) { + spin_lock_init(&pi->tx_lock); + if (!(rc = uart_add_one_port(&mpsc_reg, + &pi->port))) { + rc = 0; + } else { + mpsc_release_port((struct uart_port *) + pi); + mpsc_drv_unmap_regs(pi); + } + } else { + mpsc_drv_unmap_regs(pi); + } + } + } + + return rc; +} + +static int mpsc_drv_remove(struct platform_device *dev) +{ + pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id); + + if (dev->id < MPSC_NUM_CTLRS) { + uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port); + mpsc_release_port((struct uart_port *) + &mpsc_ports[dev->id].port); + mpsc_drv_unmap_regs(&mpsc_ports[dev->id]); + return 0; + } else { + return -ENODEV; + } +} + +static struct platform_driver mpsc_driver = { + .probe = mpsc_drv_probe, + .remove = mpsc_drv_remove, + .driver = { + .name = MPSC_CTLR_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init mpsc_drv_init(void) +{ + int rc; + + printk(KERN_INFO "Serial: MPSC driver\n"); + + memset(mpsc_ports, 0, sizeof(mpsc_ports)); + memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); + + if (!(rc = uart_register_driver(&mpsc_reg))) { + if (!(rc = platform_driver_register(&mpsc_shared_driver))) { + if ((rc = platform_driver_register(&mpsc_driver))) { + platform_driver_unregister(&mpsc_shared_driver); + uart_unregister_driver(&mpsc_reg); + } + } else { + uart_unregister_driver(&mpsc_reg); + } + } + + return rc; +} + +static void __exit mpsc_drv_exit(void) +{ + platform_driver_unregister(&mpsc_driver); + platform_driver_unregister(&mpsc_shared_driver); + uart_unregister_driver(&mpsc_reg); + memset(mpsc_ports, 0, sizeof(mpsc_ports)); + memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); +} + +module_init(mpsc_drv_init); +module_exit(mpsc_drv_exit); + +MODULE_AUTHOR("Mark A. Greer "); +MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver"); +MODULE_VERSION(MPSC_VERSION); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR); +MODULE_ALIAS("platform:" MPSC_CTLR_NAME); diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c new file mode 100644 index 000000000000..b62857bf2fdb --- /dev/null +++ b/drivers/tty/serial/mrst_max3110.c @@ -0,0 +1,919 @@ +/* + * mrst_max3110.c - spi uart protocol driver for Maxim 3110 + * + * Copyright (c) 2008-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Note: + * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has + * 1 word. If SPI master controller doesn't support sclk frequency change, + * then the char need be sent out one by one with some delay + * + * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE + * interrupt for a low speed UART device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mrst_max3110.h" + +#define PR_FMT "mrst_max3110: " + +#define UART_TX_NEEDED 1 +#define CON_TX_NEEDED 2 +#define BIT_IRQ_PENDING 3 + +struct uart_max3110 { + struct uart_port port; + struct spi_device *spi; + char name[24]; + + wait_queue_head_t wq; + struct task_struct *main_thread; + struct task_struct *read_thread; + struct mutex thread_mutex;; + + u32 baud; + u16 cur_conf; + u8 clock; + u8 parity, word_7bits; + u16 irq; + + unsigned long uart_flags; + + /* console related */ + struct circ_buf con_xmit; +}; + +/* global data structure, may need be removed */ +static struct uart_max3110 *pmax; + +static void receive_chars(struct uart_max3110 *max, + unsigned char *str, int len); +static int max3110_read_multi(struct uart_max3110 *max, u8 *buf); +static void max3110_con_receive(struct uart_max3110 *max); + +static int max3110_write_then_read(struct uart_max3110 *max, + const void *txbuf, void *rxbuf, unsigned len, int always_fast) +{ + struct spi_device *spi = max->spi; + struct spi_message message; + struct spi_transfer x; + int ret; + + spi_message_init(&message); + memset(&x, 0, sizeof x); + x.len = len; + x.tx_buf = txbuf; + x.rx_buf = rxbuf; + spi_message_add_tail(&x, &message); + + if (always_fast) + x.speed_hz = spi->max_speed_hz; + else if (max->baud) + x.speed_hz = max->baud; + + /* Do the i/o */ + ret = spi_sync(spi, &message); + return ret; +} + +/* Write a 16b word to the device */ +static int max3110_out(struct uart_max3110 *max, const u16 out) +{ + void *buf; + u16 *obuf, *ibuf; + u8 ch; + int ret; + + buf = kzalloc(8, GFP_KERNEL | GFP_DMA); + if (!buf) + return -ENOMEM; + + obuf = buf; + ibuf = buf + 4; + *obuf = out; + ret = max3110_write_then_read(max, obuf, ibuf, 2, 1); + if (ret) { + pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n", + __func__, ret, out); + goto exit; + } + + /* If some valid data is read back */ + if (*ibuf & MAX3110_READ_DATA_AVAILABLE) { + ch = *ibuf & 0xff; + receive_chars(max, &ch, 1); + } + +exit: + kfree(buf); + return ret; +} + +/* + * This is usually used to read data from SPIC RX FIFO, which doesn't + * need any delay like flushing character out. + * + * Return how many valide bytes are read back + */ +static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf) +{ + void *buf; + u16 *obuf, *ibuf; + u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH]; + int i, j, blen; + + blen = M3110_RX_FIFO_DEPTH * sizeof(u16); + buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA); + if (!buf) { + pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__); + return 0; + } + + /* tx/rx always have the same length */ + obuf = buf; + ibuf = buf + blen; + + if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) { + kfree(buf); + return 0; + } + + /* If caller doesn't provide a buffer, then handle received char */ + pbuf = rxbuf ? rxbuf : valid_str; + + for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) { + if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) + pbuf[j++] = ibuf[i] & 0xff; + } + + if (j && (pbuf == valid_str)) + receive_chars(max, valid_str, j); + + kfree(buf); + return j; +} + +static void serial_m3110_con_putchar(struct uart_port *port, int ch) +{ + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + struct circ_buf *xmit = &max->con_xmit; + + if (uart_circ_chars_free(xmit)) { + xmit->buf[xmit->head] = (char)ch; + xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1); + } +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void serial_m3110_con_write(struct console *co, + const char *s, unsigned int count) +{ + if (!pmax) + return; + + uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar); + + if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags)) + wake_up_process(pmax->main_thread); +} + +static int __init +serial_m3110_con_setup(struct console *co, char *options) +{ + struct uart_max3110 *max = pmax; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + pr_info(PR_FMT "setting up console\n"); + + if (co->index == -1) + co->index = 0; + + if (!max) { + pr_err(PR_FMT "pmax is NULL, return"); + return -ENODEV; + } + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&max->port, co, baud, parity, bits, flow); +} + +static struct tty_driver *serial_m3110_con_device(struct console *co, + int *index) +{ + struct uart_driver *p = co->data; + *index = co->index; + return p->tty_driver; +} + +static struct uart_driver serial_m3110_reg; +static struct console serial_m3110_console = { + .name = "ttyS", + .write = serial_m3110_con_write, + .device = serial_m3110_con_device, + .setup = serial_m3110_con_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &serial_m3110_reg, +}; + +static unsigned int serial_m3110_tx_empty(struct uart_port *port) +{ + return 1; +} + +static void serial_m3110_stop_tx(struct uart_port *port) +{ + return; +} + +/* stop_rx will be called in spin_lock env */ +static void serial_m3110_stop_rx(struct uart_port *port) +{ + return; +} + +#define WORDS_PER_XFER 128 +static void send_circ_buf(struct uart_max3110 *max, + struct circ_buf *xmit) +{ + void *buf; + u16 *obuf, *ibuf; + u8 valid_str[WORDS_PER_XFER]; + int i, j, len, blen, dma_size, left, ret = 0; + + + dma_size = WORDS_PER_XFER * sizeof(u16) * 2; + buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA); + if (!buf) + return; + obuf = buf; + ibuf = buf + dma_size/2; + + while (!uart_circ_empty(xmit)) { + left = uart_circ_chars_pending(xmit); + while (left) { + len = min(left, WORDS_PER_XFER); + blen = len * sizeof(u16); + memset(ibuf, 0, blen); + + for (i = 0; i < len; i++) { + obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG; + xmit->tail = (xmit->tail + 1) & + (UART_XMIT_SIZE - 1); + } + + /* Fail to send msg to console is not very critical */ + ret = max3110_write_then_read(max, obuf, ibuf, blen, 0); + if (ret) + pr_warning(PR_FMT "%s(): get err msg %d\n", + __func__, ret); + + for (i = 0, j = 0; i < len; i++) { + if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) + valid_str[j++] = ibuf[i] & 0xff; + } + + if (j) + receive_chars(max, valid_str, j); + + max->port.icount.tx += len; + left -= len; + } + } + + kfree(buf); +} + +static void transmit_char(struct uart_max3110 *max) +{ + struct uart_port *port = &max->port; + struct circ_buf *xmit = &port->state->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + send_circ_buf(max, xmit); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + serial_m3110_stop_tx(port); +} + +/* + * This will be called by uart_write() and tty_write, can't + * go to sleep + */ +static void serial_m3110_start_tx(struct uart_port *port) +{ + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + + if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags)) + wake_up_process(max->main_thread); +} + +static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) +{ + struct uart_port *port = &max->port; + struct tty_struct *tty; + int usable; + + /* If uart is not opened, just return */ + if (!port->state) + return; + + tty = port->state->port.tty; + if (!tty) + return; + + while (len) { + usable = tty_buffer_request_room(tty, len); + if (usable) { + tty_insert_flip_string(tty, str, usable); + str += usable; + port->icount.rx += usable; + } + len -= usable; + } + tty_flip_buffer_push(tty); +} + +/* + * This routine will be used in read_thread or RX IRQ handling, + * it will first do one round buffer read(8 words), if there is some + * valid RX data, will try to read 5 more rounds till all data + * is read out. + * + * Use stack space as data buffer to save some system load, and chose + * 504 Btyes as a threadhold to do a bulk push to upper tty layer when + * receiving bulk data, a much bigger buffer may cause stack overflow + */ +static void max3110_con_receive(struct uart_max3110 *max) +{ + int loop = 1, num, total = 0; + u8 recv_buf[512], *pbuf; + + pbuf = recv_buf; + do { + num = max3110_read_multi(max, pbuf); + + if (num) { + loop = 5; + pbuf += num; + total += num; + + if (total >= 504) { + receive_chars(max, recv_buf, total); + pbuf = recv_buf; + total = 0; + } + } + } while (--loop); + + if (total) + receive_chars(max, recv_buf, total); +} + +static int max3110_main_thread(void *_max) +{ + struct uart_max3110 *max = _max; + wait_queue_head_t *wq = &max->wq; + int ret = 0; + struct circ_buf *xmit = &max->con_xmit; + + init_waitqueue_head(wq); + pr_info(PR_FMT "start main thread\n"); + + do { + wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop()); + + mutex_lock(&max->thread_mutex); + + if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags)) + max3110_con_receive(max); + + /* first handle console output */ + if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags)) + send_circ_buf(max, xmit); + + /* handle uart output */ + if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags)) + transmit_char(max); + + mutex_unlock(&max->thread_mutex); + + } while (!kthread_should_stop()); + + return ret; +} + +static irqreturn_t serial_m3110_irq(int irq, void *dev_id) +{ + struct uart_max3110 *max = dev_id; + + /* max3110's irq is a falling edge, not level triggered, + * so no need to disable the irq */ + if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags)) + wake_up_process(max->main_thread); + + return IRQ_HANDLED; +} + +/* if don't use RX IRQ, then need a thread to polling read */ +static int max3110_read_thread(void *_max) +{ + struct uart_max3110 *max = _max; + + pr_info(PR_FMT "start read thread\n"); + do { + /* + * If can't acquire the mutex, it means the main thread + * is running which will also perform the rx job + */ + if (mutex_trylock(&max->thread_mutex)) { + max3110_con_receive(max); + mutex_unlock(&max->thread_mutex); + } + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 20); + } while (!kthread_should_stop()); + + return 0; +} + +static int serial_m3110_startup(struct uart_port *port) +{ + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + u16 config = 0; + int ret = 0; + + if (port->line != 0) { + pr_err(PR_FMT "uart port startup failed\n"); + return -1; + } + + /* Disable all IRQ and config it to 115200, 8n1 */ + config = WC_TAG | WC_FIFO_ENABLE + | WC_1_STOPBITS + | WC_8BIT_WORD + | WC_BAUD_DR2; + + /* as we use thread to handle tx/rx, need set low latency */ + port->state->port.tty->low_latency = 1; + + if (max->irq) { + max->read_thread = NULL; + ret = request_irq(max->irq, serial_m3110_irq, + IRQ_TYPE_EDGE_FALLING, "max3110", max); + if (ret) { + max->irq = 0; + pr_err(PR_FMT "unable to allocate IRQ, polling\n"); + } else { + /* Enable RX IRQ only */ + config |= WC_RXA_IRQ_ENABLE; + } + } + + if (max->irq == 0) { + /* If IRQ is disabled, start a read thread for input data */ + max->read_thread = + kthread_run(max3110_read_thread, max, "max3110_read"); + if (IS_ERR(max->read_thread)) { + ret = PTR_ERR(max->read_thread); + max->read_thread = NULL; + pr_err(PR_FMT "Can't create read thread!\n"); + return ret; + } + } + + ret = max3110_out(max, config); + if (ret) { + if (max->irq) + free_irq(max->irq, max); + if (max->read_thread) + kthread_stop(max->read_thread); + max->read_thread = NULL; + return ret; + } + + max->cur_conf = config; + return 0; +} + +static void serial_m3110_shutdown(struct uart_port *port) +{ + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + u16 config; + + if (max->read_thread) { + kthread_stop(max->read_thread); + max->read_thread = NULL; + } + + if (max->irq) + free_irq(max->irq, max); + + /* Disable interrupts from this port */ + config = WC_TAG | WC_SW_SHDI; + max3110_out(max, config); +} + +static void serial_m3110_release_port(struct uart_port *port) +{ +} + +static int serial_m3110_request_port(struct uart_port *port) +{ + return 0; +} + +static void serial_m3110_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_MAX3100; +} + +static int +serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + + +static const char *serial_m3110_type(struct uart_port *port) +{ + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + return max->name; +} + +static void +serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_max3110 *max = + container_of(port, struct uart_max3110, port); + unsigned char cval; + unsigned int baud, parity = 0; + int clk_div = -1; + u16 new_conf = max->cur_conf; + + switch (termios->c_cflag & CSIZE) { + case CS7: + cval = UART_LCR_WLEN7; + new_conf |= WC_7BIT_WORD; + break; + default: + /* We only support CS7 & CS8 */ + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + case CS8: + cval = UART_LCR_WLEN8; + new_conf |= WC_8BIT_WORD; + break; + } + + baud = uart_get_baud_rate(port, termios, old, 0, 230400); + + /* First calc the div for 1.8MHZ clock case */ + switch (baud) { + case 300: + clk_div = WC_BAUD_DR384; + break; + case 600: + clk_div = WC_BAUD_DR192; + break; + case 1200: + clk_div = WC_BAUD_DR96; + break; + case 2400: + clk_div = WC_BAUD_DR48; + break; + case 4800: + clk_div = WC_BAUD_DR24; + break; + case 9600: + clk_div = WC_BAUD_DR12; + break; + case 19200: + clk_div = WC_BAUD_DR6; + break; + case 38400: + clk_div = WC_BAUD_DR3; + break; + case 57600: + clk_div = WC_BAUD_DR2; + break; + case 115200: + clk_div = WC_BAUD_DR1; + break; + case 230400: + if (max->clock & MAX3110_HIGH_CLK) + break; + default: + /* Pick the previous baud rate */ + baud = max->baud; + clk_div = max->cur_conf & WC_BAUD_DIV_MASK; + tty_termios_encode_baud_rate(termios, baud, baud); + } + + if (max->clock & MAX3110_HIGH_CLK) { + clk_div += 1; + /* High clk version max3110 doesn't support B300 */ + if (baud == 300) { + baud = 600; + clk_div = WC_BAUD_DR384; + } + if (baud == 230400) + clk_div = WC_BAUD_DR1; + tty_termios_encode_baud_rate(termios, baud, baud); + } + + new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div; + + if (unlikely(termios->c_cflag & CMSPAR)) + termios->c_cflag &= ~CMSPAR; + + if (termios->c_cflag & CSTOPB) + new_conf |= WC_2_STOPBITS; + else + new_conf &= ~WC_2_STOPBITS; + + if (termios->c_cflag & PARENB) { + new_conf |= WC_PARITY_ENABLE; + parity |= UART_LCR_PARITY; + } else + new_conf &= ~WC_PARITY_ENABLE; + + if (!(termios->c_cflag & PARODD)) + parity |= UART_LCR_EPAR; + max->parity = parity; + + uart_update_timeout(port, termios->c_cflag, baud); + + new_conf |= WC_TAG; + if (new_conf != max->cur_conf) { + if (!max3110_out(max, new_conf)) { + max->cur_conf = new_conf; + max->baud = baud; + } + } +} + +/* Don't handle hw handshaking */ +static unsigned int serial_m3110_get_mctrl(struct uart_port *port) +{ + return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR; +} + +static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void serial_m3110_break_ctl(struct uart_port *port, int break_state) +{ +} + +static void serial_m3110_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ +} + +static void serial_m3110_enable_ms(struct uart_port *port) +{ +} + +struct uart_ops serial_m3110_ops = { + .tx_empty = serial_m3110_tx_empty, + .set_mctrl = serial_m3110_set_mctrl, + .get_mctrl = serial_m3110_get_mctrl, + .stop_tx = serial_m3110_stop_tx, + .start_tx = serial_m3110_start_tx, + .stop_rx = serial_m3110_stop_rx, + .enable_ms = serial_m3110_enable_ms, + .break_ctl = serial_m3110_break_ctl, + .startup = serial_m3110_startup, + .shutdown = serial_m3110_shutdown, + .set_termios = serial_m3110_set_termios, + .pm = serial_m3110_pm, + .type = serial_m3110_type, + .release_port = serial_m3110_release_port, + .request_port = serial_m3110_request_port, + .config_port = serial_m3110_config_port, + .verify_port = serial_m3110_verify_port, +}; + +static struct uart_driver serial_m3110_reg = { + .owner = THIS_MODULE, + .driver_name = "MRST serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = 1, + .cons = &serial_m3110_console, +}; + +#ifdef CONFIG_PM +static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state) +{ + struct uart_max3110 *max = spi_get_drvdata(spi); + + disable_irq(max->irq); + uart_suspend_port(&serial_m3110_reg, &max->port); + max3110_out(max, max->cur_conf | WC_SW_SHDI); + return 0; +} + +static int serial_m3110_resume(struct spi_device *spi) +{ + struct uart_max3110 *max = spi_get_drvdata(spi); + + max3110_out(max, max->cur_conf); + uart_resume_port(&serial_m3110_reg, &max->port); + enable_irq(max->irq); + return 0; +} +#else +#define serial_m3110_suspend NULL +#define serial_m3110_resume NULL +#endif + +static int __devinit serial_m3110_probe(struct spi_device *spi) +{ + struct uart_max3110 *max; + void *buffer; + u16 res; + int ret = 0; + + max = kzalloc(sizeof(*max), GFP_KERNEL); + if (!max) + return -ENOMEM; + + /* Set spi info */ + spi->bits_per_word = 16; + max->clock = MAX3110_HIGH_CLK; + + spi_setup(spi); + + max->port.type = PORT_MAX3100; + max->port.fifosize = 2; /* Only have 16b buffer */ + max->port.ops = &serial_m3110_ops; + max->port.line = 0; + max->port.dev = &spi->dev; + max->port.uartclk = 115200; + + max->spi = spi; + strcpy(max->name, spi->modalias); + max->irq = (u16)spi->irq; + + mutex_init(&max->thread_mutex); + + max->word_7bits = 0; + max->parity = 0; + max->baud = 0; + + max->cur_conf = 0; + max->uart_flags = 0; + + /* Check if reading configuration register returns something sane */ + + res = RC_TAG; + ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0); + if (ret < 0 || res == 0 || res == 0xffff) { + printk(KERN_ERR "MAX3111 deemed not present (conf reg %04x)", + res); + ret = -ENODEV; + goto err_get_page; + } + + buffer = (void *)__get_free_page(GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + goto err_get_page; + } + max->con_xmit.buf = buffer; + max->con_xmit.head = 0; + max->con_xmit.tail = 0; + + max->main_thread = kthread_run(max3110_main_thread, + max, "max3110_main"); + if (IS_ERR(max->main_thread)) { + ret = PTR_ERR(max->main_thread); + goto err_kthread; + } + + spi_set_drvdata(spi, max); + pmax = max; + + /* Give membase a psudo value to pass serial_core's check */ + max->port.membase = (void *)0xff110000; + uart_add_one_port(&serial_m3110_reg, &max->port); + + return 0; + +err_kthread: + free_page((unsigned long)buffer); +err_get_page: + kfree(max); + return ret; +} + +static int __devexit serial_m3110_remove(struct spi_device *dev) +{ + struct uart_max3110 *max = spi_get_drvdata(dev); + + if (!max) + return 0; + + uart_remove_one_port(&serial_m3110_reg, &max->port); + + free_page((unsigned long)max->con_xmit.buf); + + if (max->main_thread) + kthread_stop(max->main_thread); + + kfree(max); + return 0; +} + +static struct spi_driver uart_max3110_driver = { + .driver = { + .name = "spi_max3111", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = serial_m3110_probe, + .remove = __devexit_p(serial_m3110_remove), + .suspend = serial_m3110_suspend, + .resume = serial_m3110_resume, +}; + +static int __init serial_m3110_init(void) +{ + int ret = 0; + + ret = uart_register_driver(&serial_m3110_reg); + if (ret) + return ret; + + ret = spi_register_driver(&uart_max3110_driver); + if (ret) + uart_unregister_driver(&serial_m3110_reg); + + return ret; +} + +static void __exit serial_m3110_exit(void) +{ + spi_unregister_driver(&uart_max3110_driver); + uart_unregister_driver(&serial_m3110_reg); +} + +module_init(serial_m3110_init); +module_exit(serial_m3110_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("max3110-uart"); diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h new file mode 100644 index 000000000000..d1ef43af397c --- /dev/null +++ b/drivers/tty/serial/mrst_max3110.h @@ -0,0 +1,60 @@ +#ifndef _MRST_MAX3110_H +#define _MRST_MAX3110_H + +#define MAX3110_HIGH_CLK 0x1 /* 3.6864 MHZ */ +#define MAX3110_LOW_CLK 0x0 /* 1.8432 MHZ */ + +/* status bits for all 4 MAX3110 operate modes */ +#define MAX3110_READ_DATA_AVAILABLE (1 << 15) +#define MAX3110_WRITE_BUF_EMPTY (1 << 14) + +#define WC_TAG (3 << 14) +#define RC_TAG (1 << 14) +#define WD_TAG (2 << 14) +#define RD_TAG (0 << 14) + +/* bits def for write configuration */ +#define WC_FIFO_ENABLE_MASK (1 << 13) +#define WC_FIFO_ENABLE (0 << 13) + +#define WC_SW_SHDI (1 << 12) + +#define WC_IRQ_MASK (0xF << 8) +#define WC_TXE_IRQ_ENABLE (1 << 11) /* TX empty irq */ +#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX availabe irq */ +#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9) +#define WC_REC_ACT_IRQ_ENABLE (1 << 8) + +#define WC_IRDA_ENABLE (1 << 7) + +#define WC_STOPBITS_MASK (1 << 6) +#define WC_2_STOPBITS (1 << 6) +#define WC_1_STOPBITS (0 << 6) + +#define WC_PARITY_ENABLE_MASK (1 << 5) +#define WC_PARITY_ENABLE (1 << 5) + +#define WC_WORDLEN_MASK (1 << 4) +#define WC_7BIT_WORD (1 << 4) +#define WC_8BIT_WORD (0 << 4) + +#define WC_BAUD_DIV_MASK (0xF) +#define WC_BAUD_DR1 (0x0) +#define WC_BAUD_DR2 (0x1) +#define WC_BAUD_DR4 (0x2) +#define WC_BAUD_DR8 (0x3) +#define WC_BAUD_DR16 (0x4) +#define WC_BAUD_DR32 (0x5) +#define WC_BAUD_DR64 (0x6) +#define WC_BAUD_DR128 (0x7) +#define WC_BAUD_DR3 (0x8) +#define WC_BAUD_DR6 (0x9) +#define WC_BAUD_DR12 (0xA) +#define WC_BAUD_DR24 (0xB) +#define WC_BAUD_DR48 (0xC) +#define WC_BAUD_DR96 (0xD) +#define WC_BAUD_DR192 (0xE) +#define WC_BAUD_DR384 (0xF) + +#define M3110_RX_FIFO_DEPTH 8 +#endif diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c new file mode 100644 index 000000000000..8e43a7b69e64 --- /dev/null +++ b/drivers/tty/serial/msm_serial.c @@ -0,0 +1,758 @@ +/* + * drivers/serial/msm_serial.c - driver for msm7k serial device and console + * + * Copyright (C) 2007 Google, Inc. + * Author: Robert Love + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +# define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_serial.h" + +struct msm_port { + struct uart_port uart; + char name[16]; + struct clk *clk; + unsigned int imr; +}; + +static void msm_stop_tx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr &= ~UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_start_tx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr |= UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_stop_rx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_enable_ms(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr |= UART_IMR_DELTA_CTS; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void handle_rx(struct uart_port *port) +{ + struct tty_struct *tty = port->state->port.tty; + unsigned int sr; + + /* + * Handle overrun. My understanding of the hardware is that overrun + * is not tied to the RX buffer, so we handle the case out of band. + */ + if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + } + + /* and now the main RX loop */ + while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { + unsigned int c; + char flag = TTY_NORMAL; + + c = msm_read(port, UART_RF); + + if (sr & UART_SR_RX_BREAK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sr & UART_SR_PAR_FRAME_ERR) { + port->icount.frame++; + } else { + port->icount.rx++; + } + + /* Mask conditions we're ignorning. */ + sr &= port->read_status_mask; + + if (sr & UART_SR_RX_BREAK) { + flag = TTY_BREAK; + } else if (sr & UART_SR_PAR_FRAME_ERR) { + flag = TTY_FRAME; + } + + if (!uart_handle_sysrq_char(port, c)) + tty_insert_flip_char(tty, c, flag); + } + + tty_flip_buffer_push(tty); +} + +static void handle_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + struct msm_port *msm_port = UART_TO_MSM(port); + int sent_tx; + + if (port->x_char) { + msm_write(port, port->x_char, UART_TF); + port->icount.tx++; + port->x_char = 0; + } + + while (msm_read(port, UART_SR) & UART_SR_TX_READY) { + if (uart_circ_empty(xmit)) { + /* disable tx interrupts */ + msm_port->imr &= ~UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); + break; + } + + msm_write(port, xmit->buf[xmit->tail], UART_TF); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + sent_tx = 1; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void handle_delta_cts(struct uart_port *port) +{ + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + port->icount.cts++; + wake_up_interruptible(&port->state->port.delta_msr_wait); +} + +static irqreturn_t msm_irq(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int misr; + + spin_lock(&port->lock); + misr = msm_read(port, UART_MISR); + msm_write(port, 0, UART_IMR); /* disable interrupt */ + + if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) + handle_rx(port); + if (misr & UART_IMR_TXLEV) + handle_tx(port); + if (misr & UART_IMR_DELTA_CTS) + handle_delta_cts(port); + + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int msm_tx_empty(struct uart_port *port) +{ + return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; +} + +static unsigned int msm_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; +} + +static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int mr; + + mr = msm_read(port, UART_MR1); + + if (!(mctrl & TIOCM_RTS)) { + mr &= ~UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); + } else { + mr |= UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + } +} + +static void msm_break_ctl(struct uart_port *port, int break_ctl) +{ + if (break_ctl) + msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); + else + msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); +} + +static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) +{ + unsigned int baud_code, rxstale, watermark; + + switch (baud) { + case 300: + baud_code = UART_CSR_300; + rxstale = 1; + break; + case 600: + baud_code = UART_CSR_600; + rxstale = 1; + break; + case 1200: + baud_code = UART_CSR_1200; + rxstale = 1; + break; + case 2400: + baud_code = UART_CSR_2400; + rxstale = 1; + break; + case 4800: + baud_code = UART_CSR_4800; + rxstale = 1; + break; + case 9600: + baud_code = UART_CSR_9600; + rxstale = 2; + break; + case 14400: + baud_code = UART_CSR_14400; + rxstale = 3; + break; + case 19200: + baud_code = UART_CSR_19200; + rxstale = 4; + break; + case 28800: + baud_code = UART_CSR_28800; + rxstale = 6; + break; + case 38400: + baud_code = UART_CSR_38400; + rxstale = 8; + break; + case 57600: + baud_code = UART_CSR_57600; + rxstale = 16; + break; + case 115200: + default: + baud_code = UART_CSR_115200; + baud = 115200; + rxstale = 31; + break; + } + + msm_write(port, baud_code, UART_CSR); + + /* RX stale watermark */ + watermark = UART_IPR_STALE_LSB & rxstale; + watermark |= UART_IPR_RXSTALE_LAST; + watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2); + msm_write(port, watermark, UART_IPR); + + /* set RX watermark */ + watermark = (port->fifosize * 3) / 4; + msm_write(port, watermark, UART_RFWR); + + /* set TX watermark */ + msm_write(port, 10, UART_TFWR); + + return baud; +} + +static void msm_reset(struct uart_port *port) +{ + /* reset everything */ + msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); +} + +static void msm_init_clock(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + clk_enable(msm_port->clk); + msm_serial_set_mnd_regs(port); +} + +static int msm_startup(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int data, rfr_level; + int ret; + + snprintf(msm_port->name, sizeof(msm_port->name), + "msm_serial%d", port->line); + + ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, + msm_port->name, port); + if (unlikely(ret)) + return ret; + + msm_init_clock(port); + + if (likely(port->fifosize > 12)) + rfr_level = port->fifosize - 12; + else + rfr_level = port->fifosize; + + /* set automatic RFR level */ + data = msm_read(port, UART_MR1); + data &= ~UART_MR1_AUTO_RFR_LEVEL1; + data &= ~UART_MR1_AUTO_RFR_LEVEL0; + data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); + data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; + msm_write(port, data, UART_MR1); + + /* make sure that RXSTALE count is non-zero */ + data = msm_read(port, UART_IPR); + if (unlikely(!data)) { + data |= UART_IPR_RXSTALE_LAST; + data |= UART_IPR_STALE_LSB; + msm_write(port, data, UART_IPR); + } + + msm_reset(port); + + msm_write(port, 0x05, UART_CR); /* enable TX & RX */ + + /* turn on RX and CTS interrupts */ + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | + UART_IMR_CURRENT_CTS; + msm_write(port, msm_port->imr, UART_IMR); + + return 0; +} + +static void msm_shutdown(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + msm_port->imr = 0; + msm_write(port, 0, UART_IMR); /* disable interrupts */ + + clk_disable(msm_port->clk); + + free_irq(port->irq, port); +} + +static void msm_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, mr; + + spin_lock_irqsave(&port->lock, flags); + + /* calculate and set baud rate */ + baud = uart_get_baud_rate(port, termios, old, 300, 115200); + baud = msm_set_baud_rate(port, baud); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + /* calculate parity */ + mr = msm_read(port, UART_MR2); + mr &= ~UART_MR2_PARITY_MODE; + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + mr |= UART_MR2_PARITY_MODE_ODD; + else if (termios->c_cflag & CMSPAR) + mr |= UART_MR2_PARITY_MODE_SPACE; + else + mr |= UART_MR2_PARITY_MODE_EVEN; + } + + /* calculate bits per char */ + mr &= ~UART_MR2_BITS_PER_CHAR; + switch (termios->c_cflag & CSIZE) { + case CS5: + mr |= UART_MR2_BITS_PER_CHAR_5; + break; + case CS6: + mr |= UART_MR2_BITS_PER_CHAR_6; + break; + case CS7: + mr |= UART_MR2_BITS_PER_CHAR_7; + break; + case CS8: + default: + mr |= UART_MR2_BITS_PER_CHAR_8; + break; + } + + /* calculate stop bits */ + mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); + if (termios->c_cflag & CSTOPB) + mr |= UART_MR2_STOP_BIT_LEN_TWO; + else + mr |= UART_MR2_STOP_BIT_LEN_ONE; + + /* set parity, bits per char, and stop bit */ + msm_write(port, mr, UART_MR2); + + /* calculate and set hardware flow control */ + mr = msm_read(port, UART_MR1); + mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); + if (termios->c_cflag & CRTSCTS) { + mr |= UART_MR1_CTS_CTL; + mr |= UART_MR1_RX_RDY_CTL; + } + msm_write(port, mr, UART_MR1); + + /* Configure status bits to ignore based on termio flags. */ + port->read_status_mask = 0; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_SR_PAR_FRAME_ERR; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_SR_RX_BREAK; + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *msm_type(struct uart_port *port) +{ + return "MSM"; +} + +static void msm_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *resource; + resource_size_t size; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!resource)) + return; + size = resource->end - resource->start + 1; + + release_mem_region(port->mapbase, size); + iounmap(port->membase); + port->membase = NULL; +} + +static int msm_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *resource; + resource_size_t size; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!resource)) + return -ENXIO; + size = resource->end - resource->start + 1; + + if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial"))) + return -EBUSY; + + port->membase = ioremap(port->mapbase, size); + if (!port->membase) { + release_mem_region(port->mapbase, size); + return -EBUSY; + } + + return 0; +} + +static void msm_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_MSM; + msm_request_port(port); + } +} + +static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)) + return -EINVAL; + if (unlikely(port->irq != ser->irq)) + return -EINVAL; + return 0; +} + +static void msm_power(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + switch (state) { + case 0: + clk_enable(msm_port->clk); + break; + case 3: + clk_disable(msm_port->clk); + break; + default: + printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); + } +} + +static struct uart_ops msm_uart_pops = { + .tx_empty = msm_tx_empty, + .set_mctrl = msm_set_mctrl, + .get_mctrl = msm_get_mctrl, + .stop_tx = msm_stop_tx, + .start_tx = msm_start_tx, + .stop_rx = msm_stop_rx, + .enable_ms = msm_enable_ms, + .break_ctl = msm_break_ctl, + .startup = msm_startup, + .shutdown = msm_shutdown, + .set_termios = msm_set_termios, + .type = msm_type, + .release_port = msm_release_port, + .request_port = msm_request_port, + .config_port = msm_config_port, + .verify_port = msm_verify_port, + .pm = msm_power, +}; + +static struct msm_port msm_uart_ports[] = { + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 512, + .line = 0, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 512, + .line = 1, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 64, + .line = 2, + }, + }, +}; + +#define UART_NR ARRAY_SIZE(msm_uart_ports) + +static inline struct uart_port *get_port_from_line(unsigned int line) +{ + return &msm_uart_ports[line].uart; +} + +#ifdef CONFIG_SERIAL_MSM_CONSOLE + +static void msm_console_putchar(struct uart_port *port, int c) +{ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + ; + msm_write(port, c, UART_TF); +} + +static void msm_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port; + struct msm_port *msm_port; + + BUG_ON(co->index < 0 || co->index >= UART_NR); + + port = get_port_from_line(co->index); + msm_port = UART_TO_MSM(port); + + spin_lock(&port->lock); + uart_console_write(port, s, count, msm_console_putchar); + spin_unlock(&port->lock); +} + +static int __init msm_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud, flow, bits, parity; + + if (unlikely(co->index >= UART_NR || co->index < 0)) + return -ENXIO; + + port = get_port_from_line(co->index); + + if (unlikely(!port->membase)) + return -ENXIO; + + port->cons = co; + + msm_init_clock(port); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + bits = 8; + parity = 'n'; + flow = 'n'; + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE, + UART_MR2); /* 8N1 */ + + if (baud < 300 || baud > 115200) + baud = 115200; + msm_set_baud_rate(port, baud); + + msm_reset(port); + + printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver msm_uart_driver; + +static struct console msm_console = { + .name = "ttyMSM", + .write = msm_console_write, + .device = uart_console_device, + .setup = msm_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &msm_uart_driver, +}; + +#define MSM_CONSOLE (&msm_console) + +#else +#define MSM_CONSOLE NULL +#endif + +static struct uart_driver msm_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "msm_serial", + .dev_name = "ttyMSM", + .nr = UART_NR, + .cons = MSM_CONSOLE, +}; + +static int __init msm_serial_probe(struct platform_device *pdev) +{ + struct msm_port *msm_port; + struct resource *resource; + struct uart_port *port; + int irq; + + if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) + return -ENXIO; + + printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id); + + port = get_port_from_line(pdev->id); + port->dev = &pdev->dev; + msm_port = UART_TO_MSM(port); + + msm_port->clk = clk_get(&pdev->dev, "uart_clk"); + if (IS_ERR(msm_port->clk)) + return PTR_ERR(msm_port->clk); + port->uartclk = clk_get_rate(msm_port->clk); + printk(KERN_INFO "uartclk = %d\n", port->uartclk); + + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!resource)) + return -ENXIO; + port->mapbase = resource->start; + + irq = platform_get_irq(pdev, 0); + if (unlikely(irq < 0)) + return -ENXIO; + port->irq = irq; + + platform_set_drvdata(pdev, port); + + return uart_add_one_port(&msm_uart_driver, port); +} + +static int __devexit msm_serial_remove(struct platform_device *pdev) +{ + struct msm_port *msm_port = platform_get_drvdata(pdev); + + clk_put(msm_port->clk); + + return 0; +} + +static struct platform_driver msm_platform_driver = { + .remove = msm_serial_remove, + .driver = { + .name = "msm_serial", + .owner = THIS_MODULE, + }, +}; + +static int __init msm_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&msm_uart_driver); + if (unlikely(ret)) + return ret; + + ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe); + if (unlikely(ret)) + uart_unregister_driver(&msm_uart_driver); + + printk(KERN_INFO "msm_serial: driver initialized\n"); + + return ret; +} + +static void __exit msm_serial_exit(void) +{ +#ifdef CONFIG_SERIAL_MSM_CONSOLE + unregister_console(&msm_console); +#endif + platform_driver_unregister(&msm_platform_driver); + uart_unregister_driver(&msm_uart_driver); +} + +module_init(msm_serial_init); +module_exit(msm_serial_exit); + +MODULE_AUTHOR("Robert Love "); +MODULE_DESCRIPTION("Driver for msm7x serial device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h new file mode 100644 index 000000000000..f6ca9ca79e98 --- /dev/null +++ b/drivers/tty/serial/msm_serial.h @@ -0,0 +1,173 @@ +/* + * drivers/serial/msm_serial.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Robert Love + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H +#define __DRIVERS_SERIAL_MSM_SERIAL_H + +#define UART_MR1 0x0000 + +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define UART_MR1_RX_RDY_CTL (1 << 7) +#define UART_MR1_CTS_CTL (1 << 6) + +#define UART_MR2 0x0004 +#define UART_MR2_ERROR_MODE (1 << 6) +#define UART_MR2_BITS_PER_CHAR 0x30 +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define UART_MR2_PARITY_MODE_NONE 0x0 +#define UART_MR2_PARITY_MODE_ODD 0x1 +#define UART_MR2_PARITY_MODE_EVEN 0x2 +#define UART_MR2_PARITY_MODE_SPACE 0x3 +#define UART_MR2_PARITY_MODE 0x3 + +#define UART_CSR 0x0008 +#define UART_CSR_115200 0xFF +#define UART_CSR_57600 0xEE +#define UART_CSR_38400 0xDD +#define UART_CSR_28800 0xCC +#define UART_CSR_19200 0xBB +#define UART_CSR_14400 0xAA +#define UART_CSR_9600 0x99 +#define UART_CSR_4800 0x77 +#define UART_CSR_2400 0x55 +#define UART_CSR_1200 0x44 +#define UART_CSR_600 0x33 +#define UART_CSR_300 0x22 + +#define UART_TF 0x000C + +#define UART_CR 0x0010 +#define UART_CR_CMD_NULL (0 << 4) +#define UART_CR_CMD_RESET_RX (1 << 4) +#define UART_CR_CMD_RESET_TX (2 << 4) +#define UART_CR_CMD_RESET_ERR (3 << 4) +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define UART_CR_CMD_START_BREAK (5 << 4) +#define UART_CR_CMD_STOP_BREAK (6 << 4) +#define UART_CR_CMD_RESET_CTS (7 << 4) +#define UART_CR_CMD_PACKET_MODE (9 << 4) +#define UART_CR_CMD_MODE_RESET (12 << 4) +#define UART_CR_CMD_SET_RFR (13 << 4) +#define UART_CR_CMD_RESET_RFR (14 << 4) +#define UART_CR_TX_DISABLE (1 << 3) +#define UART_CR_TX_ENABLE (1 << 3) +#define UART_CR_RX_DISABLE (1 << 3) +#define UART_CR_RX_ENABLE (1 << 3) + +#define UART_IMR 0x0014 +#define UART_IMR_TXLEV (1 << 0) +#define UART_IMR_RXSTALE (1 << 3) +#define UART_IMR_RXLEV (1 << 4) +#define UART_IMR_DELTA_CTS (1 << 5) +#define UART_IMR_CURRENT_CTS (1 << 6) + +#define UART_IPR_RXSTALE_LAST 0x20 +#define UART_IPR_STALE_LSB 0x1F +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 + +#define UART_IPR 0x0018 +#define UART_TFWR 0x001C +#define UART_RFWR 0x0020 +#define UART_HCR 0x0024 + +#define UART_MREG 0x0028 +#define UART_NREG 0x002C +#define UART_DREG 0x0030 +#define UART_MNDREG 0x0034 +#define UART_IRDA 0x0038 +#define UART_MISR_MODE 0x0040 +#define UART_MISR_RESET 0x0044 +#define UART_MISR_EXPORT 0x0048 +#define UART_MISR_VAL 0x004C +#define UART_TEST_CTRL 0x0050 + +#define UART_SR 0x0008 +#define UART_SR_HUNT_CHAR (1 << 7) +#define UART_SR_RX_BREAK (1 << 6) +#define UART_SR_PAR_FRAME_ERR (1 << 5) +#define UART_SR_OVERRUN (1 << 4) +#define UART_SR_TX_EMPTY (1 << 3) +#define UART_SR_TX_READY (1 << 2) +#define UART_SR_RX_FULL (1 << 1) +#define UART_SR_RX_READY (1 << 0) + +#define UART_RF 0x000C +#define UART_MISR 0x0010 +#define UART_ISR 0x0014 + +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) + +static inline +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + __raw_writel(val, port->membase + off); +} + +static inline +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return __raw_readl(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); +} + +static inline +void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) +{ + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else + msm_serial_set_mnd_regs_tcxoby4(port); +} + +/* + * TROUT has a specific defect that makes it report it's uartclk + * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special + * cases TROUT to use the right clock. + */ +#ifdef CONFIG_MACH_TROUT +#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4 +#else +#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk +#endif + +#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c new file mode 100644 index 000000000000..9711e06a8374 --- /dev/null +++ b/drivers/tty/serial/mux.c @@ -0,0 +1,633 @@ +/* +** mux.c: +** serial driver for the Mux console found in some PA-RISC servers. +** +** (c) Copyright 2002 Ryan Bradetich +** (c) Copyright 2002 Hewlett-Packard Company +** +** 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 Driver currently only supports the console (port 0) on the MUX. +** Additional work will be needed on this driver to enable the full +** functionality of the MUX. +** +*/ + +#include +#include +#include +#include +#include +#include +#include /* for udelay */ +#include +#include +#include +#include + +#ifdef CONFIG_MAGIC_SYSRQ +#include +#define SUPPORT_SYSRQ +#endif + +#include + +#define MUX_OFFSET 0x800 +#define MUX_LINE_OFFSET 0x80 + +#define MUX_FIFO_SIZE 255 +#define MUX_POLL_DELAY (30 * HZ / 1000) + +#define IO_DATA_REG_OFFSET 0x3c +#define IO_DCOUNT_REG_OFFSET 0x40 + +#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000) +#define MUX_STATUS(status) ((status & 0xF000) == 0x8000) +#define MUX_BREAK(status) ((status & 0xF000) == 0x2000) + +#define MUX_NR 256 +static unsigned int port_cnt __read_mostly; +struct mux_port { + struct uart_port port; + int enabled; +}; +static struct mux_port mux_ports[MUX_NR]; + +static struct uart_driver mux_driver = { + .owner = THIS_MODULE, + .driver_name = "ttyB", + .dev_name = "ttyB", + .major = MUX_MAJOR, + .minor = 0, + .nr = MUX_NR, +}; + +static struct timer_list mux_timer; + +#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET) +#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET) + +/** + * get_mux_port_count - Get the number of available ports on the Mux. + * @dev: The parisc device. + * + * This function is used to determine the number of ports the Mux + * supports. The IODC data reports the number of ports the Mux + * can support, but there are cases where not all the Mux ports + * are connected. This function can override the IODC and + * return the true port count. + */ +static int __init get_mux_port_count(struct parisc_device *dev) +{ + int status; + u8 iodc_data[32]; + unsigned long bytecnt; + + /* If this is the built-in Mux for the K-Class (Eole CAP/MUX), + * we only need to allocate resources for 1 port since the + * other 7 ports are not connected. + */ + if(dev->id.hversion == 0x15) + return 1; + + status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); + BUG_ON(status != PDC_OK); + + /* Return the number of ports specified in the iodc data. */ + return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8; +} + +/** + * mux_tx_empty - Check if the transmitter fifo is empty. + * @port: Ptr to the uart_port. + * + * This function test if the transmitter fifo for the port + * described by 'port' is empty. If it is empty, this function + * should return TIOCSER_TEMT, otherwise return 0. + */ +static unsigned int mux_tx_empty(struct uart_port *port) +{ + return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT; +} + +/** + * mux_set_mctrl - Set the current state of the modem control inputs. + * @ports: Ptr to the uart_port. + * @mctrl: Modem control bits. + * + * The Serial MUX does not support CTS, DCD or DSR so this function + * is ignored. + */ +static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/** + * mux_get_mctrl - Returns the current state of modem control inputs. + * @port: Ptr to the uart_port. + * + * The Serial MUX does not support CTS, DCD or DSR so these lines are + * treated as permanently active. + */ +static unsigned int mux_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/** + * mux_stop_tx - Stop transmitting characters. + * @port: Ptr to the uart_port. + * + * The Serial MUX does not support this function. + */ +static void mux_stop_tx(struct uart_port *port) +{ +} + +/** + * mux_start_tx - Start transmitting characters. + * @port: Ptr to the uart_port. + * + * The Serial Mux does not support this function. + */ +static void mux_start_tx(struct uart_port *port) +{ +} + +/** + * mux_stop_rx - Stop receiving characters. + * @port: Ptr to the uart_port. + * + * The Serial Mux does not support this function. + */ +static void mux_stop_rx(struct uart_port *port) +{ +} + +/** + * mux_enable_ms - Enable modum status interrupts. + * @port: Ptr to the uart_port. + * + * The Serial Mux does not support this function. + */ +static void mux_enable_ms(struct uart_port *port) +{ +} + +/** + * mux_break_ctl - Control the transmitssion of a break signal. + * @port: Ptr to the uart_port. + * @break_state: Raise/Lower the break signal. + * + * The Serial Mux does not support this function. + */ +static void mux_break_ctl(struct uart_port *port, int break_state) +{ +} + +/** + * mux_write - Write chars to the mux fifo. + * @port: Ptr to the uart_port. + * + * This function writes all the data from the uart buffer to + * the mux fifo. + */ +static void mux_write(struct uart_port *port) +{ + int count; + struct circ_buf *xmit = &port->state->xmit; + + if(port->x_char) { + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if(uart_circ_empty(xmit) || uart_tx_stopped(port)) { + mux_stop_tx(port); + return; + } + + count = (port->fifosize) - UART_GET_FIFO_CNT(port); + do { + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if(uart_circ_empty(xmit)) + break; + + } while(--count > 0); + + while(UART_GET_FIFO_CNT(port)) + udelay(1); + + if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + mux_stop_tx(port); +} + +/** + * mux_read - Read chars from the mux fifo. + * @port: Ptr to the uart_port. + * + * This reads all available data from the mux's fifo and pushes + * the data to the tty layer. + */ +static void mux_read(struct uart_port *port) +{ + int data; + struct tty_struct *tty = port->state->port.tty; + __u32 start_count = port->icount.rx; + + while(1) { + data = __raw_readl(port->membase + IO_DATA_REG_OFFSET); + + if (MUX_STATUS(data)) + continue; + + if (MUX_EOFIFO(data)) + break; + + port->icount.rx++; + + if (MUX_BREAK(data)) { + port->icount.brk++; + if(uart_handle_break(port)) + continue; + } + + if (uart_handle_sysrq_char(port, data & 0xffu)) + continue; + + tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); + } + + if (start_count != port->icount.rx) { + tty_flip_buffer_push(tty); + } +} + +/** + * mux_startup - Initialize the port. + * @port: Ptr to the uart_port. + * + * Grab any resources needed for this port and start the + * mux timer. + */ +static int mux_startup(struct uart_port *port) +{ + mux_ports[port->line].enabled = 1; + return 0; +} + +/** + * mux_shutdown - Disable the port. + * @port: Ptr to the uart_port. + * + * Release any resources needed for the port. + */ +static void mux_shutdown(struct uart_port *port) +{ + mux_ports[port->line].enabled = 0; +} + +/** + * mux_set_termios - Chane port parameters. + * @port: Ptr to the uart_port. + * @termios: new termios settings. + * @old: old termios settings. + * + * The Serial Mux does not support this function. + */ +static void +mux_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ +} + +/** + * mux_type - Describe the port. + * @port: Ptr to the uart_port. + * + * Return a pointer to a string constant describing the + * specified port. + */ +static const char *mux_type(struct uart_port *port) +{ + return "Mux"; +} + +/** + * mux_release_port - Release memory and IO regions. + * @port: Ptr to the uart_port. + * + * Release any memory and IO region resources currently in use by + * the port. + */ +static void mux_release_port(struct uart_port *port) +{ +} + +/** + * mux_request_port - Request memory and IO regions. + * @port: Ptr to the uart_port. + * + * Request any memory and IO region resources required by the port. + * If any fail, no resources should be registered when this function + * returns, and it should return -EBUSY on failure. + */ +static int mux_request_port(struct uart_port *port) +{ + return 0; +} + +/** + * mux_config_port - Perform port autoconfiguration. + * @port: Ptr to the uart_port. + * @type: Bitmask of required configurations. + * + * Perform any autoconfiguration steps for the port. This function is + * called if the UPF_BOOT_AUTOCONF flag is specified for the port. + * [Note: This is required for now because of a bug in the Serial core. + * rmk has already submitted a patch to linus, should be available for + * 2.5.47.] + */ +static void mux_config_port(struct uart_port *port, int type) +{ + port->type = PORT_MUX; +} + +/** + * mux_verify_port - Verify the port information. + * @port: Ptr to the uart_port. + * @ser: Ptr to the serial information. + * + * Verify the new serial port information contained within serinfo is + * suitable for this port type. + */ +static int mux_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if(port->membase == NULL) + return -EINVAL; + + return 0; +} + +/** + * mux_drv_poll - Mux poll function. + * @unused: Unused variable + * + * This function periodically polls the Serial MUX to check for new data. + */ +static void mux_poll(unsigned long unused) +{ + int i; + + for(i = 0; i < port_cnt; ++i) { + if(!mux_ports[i].enabled) + continue; + + mux_read(&mux_ports[i].port); + mux_write(&mux_ports[i].port); + } + + mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); +} + + +#ifdef CONFIG_SERIAL_MUX_CONSOLE +static void mux_console_write(struct console *co, const char *s, unsigned count) +{ + /* Wait until the FIFO drains. */ + while(UART_GET_FIFO_CNT(&mux_ports[0].port)) + udelay(1); + + while(count--) { + if(*s == '\n') { + UART_PUT_CHAR(&mux_ports[0].port, '\r'); + } + UART_PUT_CHAR(&mux_ports[0].port, *s++); + } + +} + +static int mux_console_setup(struct console *co, char *options) +{ + return 0; +} + +struct tty_driver *mux_console_device(struct console *co, int *index) +{ + *index = co->index; + return mux_driver.tty_driver; +} + +static struct console mux_console = { + .name = "ttyB", + .write = mux_console_write, + .device = mux_console_device, + .setup = mux_console_setup, + .flags = CON_ENABLED | CON_PRINTBUFFER, + .index = 0, +}; + +#define MUX_CONSOLE &mux_console +#else +#define MUX_CONSOLE NULL +#endif + +static struct uart_ops mux_pops = { + .tx_empty = mux_tx_empty, + .set_mctrl = mux_set_mctrl, + .get_mctrl = mux_get_mctrl, + .stop_tx = mux_stop_tx, + .start_tx = mux_start_tx, + .stop_rx = mux_stop_rx, + .enable_ms = mux_enable_ms, + .break_ctl = mux_break_ctl, + .startup = mux_startup, + .shutdown = mux_shutdown, + .set_termios = mux_set_termios, + .type = mux_type, + .release_port = mux_release_port, + .request_port = mux_request_port, + .config_port = mux_config_port, + .verify_port = mux_verify_port, +}; + +/** + * mux_probe - Determine if the Serial Mux should claim this device. + * @dev: The parisc device. + * + * Deterimine if the Serial Mux should claim this chip (return 0) + * or not (return 1). + */ +static int __init mux_probe(struct parisc_device *dev) +{ + int i, status; + + int port_count = get_mux_port_count(dev); + printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count); + + dev_set_drvdata(&dev->dev, (void *)(long)port_count); + request_mem_region(dev->hpa.start + MUX_OFFSET, + port_count * MUX_LINE_OFFSET, "Mux"); + + if(!port_cnt) { + mux_driver.cons = MUX_CONSOLE; + + status = uart_register_driver(&mux_driver); + if(status) { + printk(KERN_ERR "Serial mux: Unable to register driver.\n"); + return 1; + } + } + + for(i = 0; i < port_count; ++i, ++port_cnt) { + struct uart_port *port = &mux_ports[port_cnt].port; + port->iobase = 0; + port->mapbase = dev->hpa.start + MUX_OFFSET + + (i * MUX_LINE_OFFSET); + port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); + port->iotype = UPIO_MEM; + port->type = PORT_MUX; + port->irq = NO_IRQ; + port->uartclk = 0; + port->fifosize = MUX_FIFO_SIZE; + port->ops = &mux_pops; + port->flags = UPF_BOOT_AUTOCONF; + port->line = port_cnt; + + /* The port->timeout needs to match what is present in + * uart_wait_until_sent in serial_core.c. Otherwise + * the time spent in msleep_interruptable will be very + * long, causing the appearance of a console hang. + */ + port->timeout = HZ / 50; + spin_lock_init(&port->lock); + + status = uart_add_one_port(&mux_driver, port); + BUG_ON(status); + } + + return 0; +} + +static int __devexit mux_remove(struct parisc_device *dev) +{ + int i, j; + int port_count = (long)dev_get_drvdata(&dev->dev); + + /* Find Port 0 for this card in the mux_ports list. */ + for(i = 0; i < port_cnt; ++i) { + if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET) + break; + } + BUG_ON(i + port_count > port_cnt); + + /* Release the resources associated with each port on the device. */ + for(j = 0; j < port_count; ++j, ++i) { + struct uart_port *port = &mux_ports[i].port; + + uart_remove_one_port(&mux_driver, port); + if(port->membase) + iounmap(port->membase); + } + + release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET); + return 0; +} + +/* Hack. This idea was taken from the 8250_gsc.c on how to properly order + * the serial port detection in the proper order. The idea is we always + * want the builtin mux to be detected before addin mux cards, so we + * specifically probe for the builtin mux cards first. + * + * This table only contains the parisc_device_id of known builtin mux + * devices. All other mux cards will be detected by the generic mux_tbl. + */ +static struct parisc_device_id builtin_mux_tbl[] = { + { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */ + { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */ + { 0, } +}; + +static struct parisc_device_id mux_tbl[] = { + { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D }, + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl); +MODULE_DEVICE_TABLE(parisc, mux_tbl); + +static struct parisc_driver builtin_serial_mux_driver = { + .name = "builtin_serial_mux", + .id_table = builtin_mux_tbl, + .probe = mux_probe, + .remove = __devexit_p(mux_remove), +}; + +static struct parisc_driver serial_mux_driver = { + .name = "serial_mux", + .id_table = mux_tbl, + .probe = mux_probe, + .remove = __devexit_p(mux_remove), +}; + +/** + * mux_init - Serial MUX initialization procedure. + * + * Register the Serial MUX driver. + */ +static int __init mux_init(void) +{ + register_parisc_driver(&builtin_serial_mux_driver); + register_parisc_driver(&serial_mux_driver); + + if(port_cnt > 0) { + /* Start the Mux timer */ + init_timer(&mux_timer); + mux_timer.function = mux_poll; + mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); + +#ifdef CONFIG_SERIAL_MUX_CONSOLE + register_console(&mux_console); +#endif + } + + return 0; +} + +/** + * mux_exit - Serial MUX cleanup procedure. + * + * Unregister the Serial MUX driver from the tty layer. + */ +static void __exit mux_exit(void) +{ + /* Delete the Mux timer. */ + if(port_cnt > 0) { + del_timer(&mux_timer); +#ifdef CONFIG_SERIAL_MUX_CONSOLE + unregister_console(&mux_console); +#endif + } + + unregister_parisc_driver(&builtin_serial_mux_driver); + unregister_parisc_driver(&serial_mux_driver); + uart_unregister_driver(&mux_driver); +} + +module_init(mux_init); +module_exit(mux_exit); + +MODULE_AUTHOR("Ryan Bradetich"); +MODULE_DESCRIPTION("Serial MUX driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR); diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c new file mode 100644 index 000000000000..7735c9f35fa0 --- /dev/null +++ b/drivers/tty/serial/netx-serial.c @@ -0,0 +1,750 @@ +/* + * drivers/serial/netx-serial.c + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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. + * + * 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 + */ + +#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* We've been assigned a range on the "Low-density serial ports" major */ +#define SERIAL_NX_MAJOR 204 +#define MINOR_START 170 + +enum uart_regs { + UART_DR = 0x00, + UART_SR = 0x04, + UART_LINE_CR = 0x08, + UART_BAUDDIV_MSB = 0x0c, + UART_BAUDDIV_LSB = 0x10, + UART_CR = 0x14, + UART_FR = 0x18, + UART_IIR = 0x1c, + UART_ILPR = 0x20, + UART_RTS_CR = 0x24, + UART_RTS_LEAD = 0x28, + UART_RTS_TRAIL = 0x2c, + UART_DRV_ENABLE = 0x30, + UART_BRM_CR = 0x34, + UART_RXFIFO_IRQLEVEL = 0x38, + UART_TXFIFO_IRQLEVEL = 0x3c, +}; + +#define SR_FE (1<<0) +#define SR_PE (1<<1) +#define SR_BE (1<<2) +#define SR_OE (1<<3) + +#define LINE_CR_BRK (1<<0) +#define LINE_CR_PEN (1<<1) +#define LINE_CR_EPS (1<<2) +#define LINE_CR_STP2 (1<<3) +#define LINE_CR_FEN (1<<4) +#define LINE_CR_5BIT (0<<5) +#define LINE_CR_6BIT (1<<5) +#define LINE_CR_7BIT (2<<5) +#define LINE_CR_8BIT (3<<5) +#define LINE_CR_BITS_MASK (3<<5) + +#define CR_UART_EN (1<<0) +#define CR_SIREN (1<<1) +#define CR_SIRLP (1<<2) +#define CR_MSIE (1<<3) +#define CR_RIE (1<<4) +#define CR_TIE (1<<5) +#define CR_RTIE (1<<6) +#define CR_LBE (1<<7) + +#define FR_CTS (1<<0) +#define FR_DSR (1<<1) +#define FR_DCD (1<<2) +#define FR_BUSY (1<<3) +#define FR_RXFE (1<<4) +#define FR_TXFF (1<<5) +#define FR_RXFF (1<<6) +#define FR_TXFE (1<<7) + +#define IIR_MIS (1<<0) +#define IIR_RIS (1<<1) +#define IIR_TIS (1<<2) +#define IIR_RTIS (1<<3) +#define IIR_MASK 0xf + +#define RTS_CR_AUTO (1<<0) +#define RTS_CR_RTS (1<<1) +#define RTS_CR_COUNT (1<<2) +#define RTS_CR_MOD2 (1<<3) +#define RTS_CR_RTS_POL (1<<4) +#define RTS_CR_CTS_CTR (1<<5) +#define RTS_CR_CTS_POL (1<<6) +#define RTS_CR_STICK (1<<7) + +#define UART_PORT_SIZE 0x40 +#define DRIVER_NAME "netx-uart" + +struct netx_port { + struct uart_port port; +}; + +static void netx_stop_tx(struct uart_port *port) +{ + unsigned int val; + val = readl(port->membase + UART_CR); + writel(val & ~CR_TIE, port->membase + UART_CR); +} + +static void netx_stop_rx(struct uart_port *port) +{ + unsigned int val; + val = readl(port->membase + UART_CR); + writel(val & ~CR_RIE, port->membase + UART_CR); +} + +static void netx_enable_ms(struct uart_port *port) +{ + unsigned int val; + val = readl(port->membase + UART_CR); + writel(val | CR_MSIE, port->membase + UART_CR); +} + +static inline void netx_transmit_buffer(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + writel(port->x_char, port->membase + UART_DR); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { + netx_stop_tx(port); + return; + } + + do { + /* send xmit->buf[xmit->tail] + * out the port here */ + writel(xmit->buf[xmit->tail], port->membase + UART_DR); + xmit->tail = (xmit->tail + 1) & + (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (!(readl(port->membase + UART_FR) & FR_TXFF)); + + if (uart_circ_empty(xmit)) + netx_stop_tx(port); +} + +static void netx_start_tx(struct uart_port *port) +{ + writel( + readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR); + + if (!(readl(port->membase + UART_FR) & FR_TXFF)) + netx_transmit_buffer(port); +} + +static unsigned int netx_tx_empty(struct uart_port *port) +{ + return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT; +} + +static void netx_txint(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + netx_stop_tx(port); + return; + } + + netx_transmit_buffer(port); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void netx_rxint(struct uart_port *port) +{ + unsigned char rx, flg, status; + struct tty_struct *tty = port->state->port.tty; + + while (!(readl(port->membase + UART_FR) & FR_RXFE)) { + rx = readl(port->membase + UART_DR); + flg = TTY_NORMAL; + port->icount.rx++; + status = readl(port->membase + UART_SR); + if (status & SR_BE) { + writel(0, port->membase + UART_SR); + if (uart_handle_break(port)) + continue; + } + + if (unlikely(status & (SR_FE | SR_PE | SR_OE))) { + + if (status & SR_PE) + port->icount.parity++; + else if (status & SR_FE) + port->icount.frame++; + if (status & SR_OE) + port->icount.overrun++; + + status &= port->read_status_mask; + + if (status & SR_BE) + flg = TTY_BREAK; + else if (status & SR_PE) + flg = TTY_PARITY; + else if (status & SR_FE) + flg = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, rx)) + continue; + + uart_insert_char(port, status, SR_OE, rx, flg); + } + + tty_flip_buffer_push(tty); + return; +} + +static irqreturn_t netx_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned long flags; + unsigned char status; + + spin_lock_irqsave(&port->lock,flags); + + status = readl(port->membase + UART_IIR) & IIR_MASK; + while (status) { + if (status & IIR_RIS) + netx_rxint(port); + if (status & IIR_TIS) + netx_txint(port); + if (status & IIR_MIS) { + if (readl(port->membase + UART_FR) & FR_CTS) + uart_handle_cts_change(port, 1); + else + uart_handle_cts_change(port, 0); + } + writel(0, port->membase + UART_IIR); + status = readl(port->membase + UART_IIR) & IIR_MASK; + } + + spin_unlock_irqrestore(&port->lock,flags); + return IRQ_HANDLED; +} + +static unsigned int netx_get_mctrl(struct uart_port *port) +{ + unsigned int ret = TIOCM_DSR | TIOCM_CAR; + + if (readl(port->membase + UART_FR) & FR_CTS) + ret |= TIOCM_CTS; + + return ret; +} + +static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int val; + + /* FIXME: Locking needed ? */ + if (mctrl & TIOCM_RTS) { + val = readl(port->membase + UART_RTS_CR); + writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR); + } +} + +static void netx_break_ctl(struct uart_port *port, int break_state) +{ + unsigned int line_cr; + spin_lock_irq(&port->lock); + + line_cr = readl(port->membase + UART_LINE_CR); + if (break_state != 0) + line_cr |= LINE_CR_BRK; + else + line_cr &= ~LINE_CR_BRK; + writel(line_cr, port->membase + UART_LINE_CR); + + spin_unlock_irq(&port->lock); +} + +static int netx_startup(struct uart_port *port) +{ + int ret; + + ret = request_irq(port->irq, netx_int, 0, + DRIVER_NAME, port); + if (ret) { + dev_err(port->dev, "unable to grab irq%d\n",port->irq); + goto exit; + } + + writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN, + port->membase + UART_LINE_CR); + + writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN, + port->membase + UART_CR); + +exit: + return ret; +} + +static void netx_shutdown(struct uart_port *port) +{ + writel(0, port->membase + UART_CR) ; + + free_irq(port->irq, port); +} + +static void +netx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud, quot; + unsigned char old_cr; + unsigned char line_cr = LINE_CR_FEN; + unsigned char rts_cr = 0; + + switch (termios->c_cflag & CSIZE) { + case CS5: + line_cr |= LINE_CR_5BIT; + break; + case CS6: + line_cr |= LINE_CR_6BIT; + break; + case CS7: + line_cr |= LINE_CR_7BIT; + break; + case CS8: + line_cr |= LINE_CR_8BIT; + break; + } + + if (termios->c_cflag & CSTOPB) + line_cr |= LINE_CR_STP2; + + if (termios->c_cflag & PARENB) { + line_cr |= LINE_CR_PEN; + if (!(termios->c_cflag & PARODD)) + line_cr |= LINE_CR_EPS; + } + + if (termios->c_cflag & CRTSCTS) + rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = baud * 4096; + quot /= 1000; + quot *= 256; + quot /= 100000; + + spin_lock_irq(&port->lock); + + uart_update_timeout(port, termios->c_cflag, baud); + + old_cr = readl(port->membase + UART_CR); + + /* disable interrupts */ + writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE), + port->membase + UART_CR); + + /* drain transmitter */ + while (readl(port->membase + UART_FR) & FR_BUSY); + + /* disable UART */ + writel(old_cr & ~CR_UART_EN, port->membase + UART_CR); + + /* modem status interrupts */ + old_cr &= ~CR_MSIE; + if (UART_ENABLE_MS(port, termios->c_cflag)) + old_cr |= CR_MSIE; + + writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB); + writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB); + writel(line_cr, port->membase + UART_LINE_CR); + + writel(rts_cr, port->membase + UART_RTS_CR); + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= SR_PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= SR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= SR_PE; + } + + port->read_status_mask = 0; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SR_BE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= SR_PE | SR_FE; + + writel(old_cr, port->membase + UART_CR); + + spin_unlock_irq(&port->lock); +} + +static const char *netx_type(struct uart_port *port) +{ + return port->type == PORT_NETX ? "NETX" : NULL; +} + +static void netx_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); +} + +static int netx_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, + DRIVER_NAME) != NULL ? 0 : -EBUSY; +} + +static void netx_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0) + port->type = PORT_NETX; +} + +static int +netx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX) + ret = -EINVAL; + + return ret; +} + +static struct uart_ops netx_pops = { + .tx_empty = netx_tx_empty, + .set_mctrl = netx_set_mctrl, + .get_mctrl = netx_get_mctrl, + .stop_tx = netx_stop_tx, + .start_tx = netx_start_tx, + .stop_rx = netx_stop_rx, + .enable_ms = netx_enable_ms, + .break_ctl = netx_break_ctl, + .startup = netx_startup, + .shutdown = netx_shutdown, + .set_termios = netx_set_termios, + .type = netx_type, + .release_port = netx_release_port, + .request_port = netx_request_port, + .config_port = netx_config_port, + .verify_port = netx_verify_port, +}; + +static struct netx_port netx_ports[] = { + { + .port = { + .type = PORT_NETX, + .iotype = UPIO_MEM, + .membase = (char __iomem *)io_p2v(NETX_PA_UART0), + .mapbase = NETX_PA_UART0, + .irq = NETX_IRQ_UART0, + .uartclk = 100000000, + .fifosize = 16, + .flags = UPF_BOOT_AUTOCONF, + .ops = &netx_pops, + .line = 0, + }, + }, { + .port = { + .type = PORT_NETX, + .iotype = UPIO_MEM, + .membase = (char __iomem *)io_p2v(NETX_PA_UART1), + .mapbase = NETX_PA_UART1, + .irq = NETX_IRQ_UART1, + .uartclk = 100000000, + .fifosize = 16, + .flags = UPF_BOOT_AUTOCONF, + .ops = &netx_pops, + .line = 1, + }, + }, { + .port = { + .type = PORT_NETX, + .iotype = UPIO_MEM, + .membase = (char __iomem *)io_p2v(NETX_PA_UART2), + .mapbase = NETX_PA_UART2, + .irq = NETX_IRQ_UART2, + .uartclk = 100000000, + .fifosize = 16, + .flags = UPF_BOOT_AUTOCONF, + .ops = &netx_pops, + .line = 2, + }, + } +}; + +#ifdef CONFIG_SERIAL_NETX_CONSOLE + +static void netx_console_putchar(struct uart_port *port, int ch) +{ + while (readl(port->membase + UART_FR) & FR_BUSY); + writel(ch, port->membase + UART_DR); +} + +static void +netx_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &netx_ports[co->index].port; + unsigned char cr_save; + + cr_save = readl(port->membase + UART_CR); + writel(cr_save | CR_UART_EN, port->membase + UART_CR); + + uart_console_write(port, s, count, netx_console_putchar); + + while (readl(port->membase + UART_FR) & FR_BUSY); + writel(cr_save, port->membase + UART_CR); +} + +static void __init +netx_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits, int *flow) +{ + unsigned char line_cr; + + *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) | + readl(port->membase + UART_BAUDDIV_LSB); + *baud *= 1000; + *baud /= 4096; + *baud *= 1000; + *baud /= 256; + *baud *= 100; + + line_cr = readl(port->membase + UART_LINE_CR); + *parity = 'n'; + if (line_cr & LINE_CR_PEN) { + if (line_cr & LINE_CR_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + switch (line_cr & LINE_CR_BITS_MASK) { + case LINE_CR_8BIT: + *bits = 8; + break; + case LINE_CR_7BIT: + *bits = 7; + break; + case LINE_CR_6BIT: + *bits = 6; + break; + case LINE_CR_5BIT: + *bits = 5; + break; + } + + if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO) + *flow = 'r'; +} + +static int __init +netx_console_setup(struct console *co, char *options) +{ + struct netx_port *sport; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports)) + co->index = 0; + sport = &netx_ports[co->index]; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + } else { + /* if the UART is enabled, assume it has been correctly setup + * by the bootloader and get the options + */ + if (readl(sport->port.membase + UART_CR) & CR_UART_EN) { + netx_console_get_options(&sport->port, &baud, + &parity, &bits, &flow); + } + + } + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver netx_reg; +static struct console netx_console = { + .name = "ttyNX", + .write = netx_console_write, + .device = uart_console_device, + .setup = netx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &netx_reg, +}; + +static int __init netx_console_init(void) +{ + register_console(&netx_console); + return 0; +} +console_initcall(netx_console_init); + +#define NETX_CONSOLE &netx_console +#else +#define NETX_CONSOLE NULL +#endif + +static struct uart_driver netx_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = "ttyNX", + .major = SERIAL_NX_MAJOR, + .minor = MINOR_START, + .nr = ARRAY_SIZE(netx_ports), + .cons = NETX_CONSOLE, +}; + +static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct netx_port *sport = platform_get_drvdata(pdev); + + if (sport) + uart_suspend_port(&netx_reg, &sport->port); + + return 0; +} + +static int serial_netx_resume(struct platform_device *pdev) +{ + struct netx_port *sport = platform_get_drvdata(pdev); + + if (sport) + uart_resume_port(&netx_reg, &sport->port); + + return 0; +} + +static int serial_netx_probe(struct platform_device *pdev) +{ + struct uart_port *port = &netx_ports[pdev->id].port; + + dev_info(&pdev->dev, "initialising\n"); + + port->dev = &pdev->dev; + + writel(1, port->membase + UART_RXFIFO_IRQLEVEL); + uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port); + platform_set_drvdata(pdev, &netx_ports[pdev->id]); + + return 0; +} + +static int serial_netx_remove(struct platform_device *pdev) +{ + struct netx_port *sport = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (sport) + uart_remove_one_port(&netx_reg, &sport->port); + + return 0; +} + +static struct platform_driver serial_netx_driver = { + .probe = serial_netx_probe, + .remove = serial_netx_remove, + + .suspend = serial_netx_suspend, + .resume = serial_netx_resume, + + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init netx_serial_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: NetX driver\n"); + + ret = uart_register_driver(&netx_reg); + if (ret) + return ret; + + ret = platform_driver_register(&serial_netx_driver); + if (ret != 0) + uart_unregister_driver(&netx_reg); + + return 0; +} + +static void __exit netx_serial_exit(void) +{ + platform_driver_unregister(&serial_netx_driver); + uart_unregister_driver(&netx_reg); +} + +module_init(netx_serial_init); +module_exit(netx_serial_exit); + +MODULE_AUTHOR("Sascha Hauer"); +MODULE_DESCRIPTION("NetX serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c new file mode 100644 index 000000000000..de173671e3d0 --- /dev/null +++ b/drivers/tty/serial/nwpserial.c @@ -0,0 +1,477 @@ +/* + * Serial Port driver for a NWP uart device + * + * Copyright (C) 2008 IBM Corp., Benjamin Krill + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NWPSERIAL_NR 2 + +#define NWPSERIAL_STATUS_RXVALID 0x1 +#define NWPSERIAL_STATUS_TXFULL 0x2 + +struct nwpserial_port { + struct uart_port port; + dcr_host_t dcr_host; + unsigned int ier; + unsigned int mcr; +}; + +static DEFINE_MUTEX(nwpserial_mutex); +static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR]; + +static void wait_for_bits(struct nwpserial_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = dcr_read(up->dcr_host, UART_LSR); + + if (--tmout == 0) + break; + udelay(1); + } while ((status & bits) != bits); +} + +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE +static void nwpserial_console_putchar(struct uart_port *port, int c) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + /* check if tx buffer is full */ + wait_for_bits(up, UART_LSR_THRE); + dcr_write(up->dcr_host, UART_TX, c); + up->port.icount.tx++; +} + +static void +nwpserial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct nwpserial_port *up = &nwpserial_ports[co->index]; + unsigned long flags; + int locked = 1; + + if (oops_in_progress) + locked = spin_trylock_irqsave(&up->port.lock, flags); + else + spin_lock_irqsave(&up->port.lock, flags); + + /* save and disable interrupt */ + up->ier = dcr_read(up->dcr_host, UART_IER); + dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI); + + uart_console_write(&up->port, s, count, nwpserial_console_putchar); + + /* wait for transmitter to become empty */ + while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0) + cpu_relax(); + + /* restore interrupt state */ + dcr_write(up->dcr_host, UART_IER, up->ier); + + if (locked) + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static struct uart_driver nwpserial_reg; +static struct console nwpserial_console = { + .name = "ttySQ", + .write = nwpserial_console_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &nwpserial_reg, +}; +#define NWPSERIAL_CONSOLE (&nwpserial_console) +#else +#define NWPSERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ + +/**************************************************************************/ + +static int nwpserial_request_port(struct uart_port *port) +{ + return 0; +} + +static void nwpserial_release_port(struct uart_port *port) +{ + /* N/A */ +} + +static void nwpserial_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_NWPSERIAL; +} + +static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) +{ + struct nwpserial_port *up = dev_id; + struct tty_struct *tty = up->port.state->port.tty; + irqreturn_t ret; + unsigned int iir; + unsigned char ch; + + spin_lock(&up->port.lock); + + /* check if the uart was the interrupt source. */ + iir = dcr_read(up->dcr_host, UART_IIR); + if (!iir) { + ret = IRQ_NONE; + goto out; + } + + do { + up->port.icount.rx++; + ch = dcr_read(up->dcr_host, UART_RX); + if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR); + + tty_flip_buffer_push(tty); + ret = IRQ_HANDLED; + + /* clear interrupt */ + dcr_write(up->dcr_host, UART_IIR, 1); +out: + spin_unlock(&up->port.lock); + return ret; +} + +static int nwpserial_startup(struct uart_port *port) +{ + struct nwpserial_port *up; + int err; + + up = container_of(port, struct nwpserial_port, port); + + /* disable flow control by default */ + up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE; + dcr_write(up->dcr_host, UART_MCR, up->mcr); + + /* register interrupt handler */ + err = request_irq(up->port.irq, nwpserial_interrupt, + IRQF_SHARED, "nwpserial", up); + if (err) + return err; + + /* enable interrupts */ + up->ier = UART_IER_RDI; + dcr_write(up->dcr_host, UART_IER, up->ier); + + /* enable receiving */ + up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID; + + return 0; +} + +static void nwpserial_shutdown(struct uart_port *port) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + + /* disable receiving */ + up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; + + /* disable interrupts from this port */ + up->ier = 0; + dcr_write(up->dcr_host, UART_IER, up->ier); + + /* free irq */ + free_irq(up->port.irq, port); +} + +static int nwpserial_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + return -EINVAL; +} + +static const char *nwpserial_type(struct uart_port *port) +{ + return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL; +} + +static void nwpserial_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + + up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID + | NWPSERIAL_STATUS_TXFULL; + + up->port.ignore_status_mask = 0; + /* ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; + + /* Copy back the old hardware settings */ + if (old) + tty_termios_copy_hw(termios, old); +} + +static void nwpserial_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static void nwpserial_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void nwpserial_stop_rx(struct uart_port *port) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + /* don't forward any more data (like !CREAD) */ + up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID; +} + +static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c) +{ + /* check if tx buffer is full */ + wait_for_bits(up, UART_LSR_THRE); + dcr_write(up->dcr_host, UART_TX, c); + up->port.icount.tx++; +} + +static void nwpserial_start_tx(struct uart_port *port) +{ + struct nwpserial_port *up; + struct circ_buf *xmit; + up = container_of(port, struct nwpserial_port, port); + xmit = &up->port.state->xmit; + + if (port->x_char) { + nwpserial_putchar(up, up->port.x_char); + port->x_char = 0; + } + + while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) { + nwpserial_putchar(up, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); + } +} + +static unsigned int nwpserial_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* N/A */ +} + +static void nwpserial_stop_tx(struct uart_port *port) +{ + /* N/A */ +} + +static unsigned int nwpserial_tx_empty(struct uart_port *port) +{ + struct nwpserial_port *up; + unsigned long flags; + int ret; + up = container_of(port, struct nwpserial_port, port); + + spin_lock_irqsave(&up->port.lock, flags); + ret = dcr_read(up->dcr_host, UART_LSR); + spin_unlock_irqrestore(&up->port.lock, flags); + + return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0; +} + +static struct uart_ops nwpserial_pops = { + .tx_empty = nwpserial_tx_empty, + .set_mctrl = nwpserial_set_mctrl, + .get_mctrl = nwpserial_get_mctrl, + .stop_tx = nwpserial_stop_tx, + .start_tx = nwpserial_start_tx, + .stop_rx = nwpserial_stop_rx, + .enable_ms = nwpserial_enable_ms, + .break_ctl = nwpserial_break_ctl, + .startup = nwpserial_startup, + .shutdown = nwpserial_shutdown, + .set_termios = nwpserial_set_termios, + .type = nwpserial_type, + .release_port = nwpserial_release_port, + .request_port = nwpserial_request_port, + .config_port = nwpserial_config_port, + .verify_port = nwpserial_verify_port, +}; + +static struct uart_driver nwpserial_reg = { + .owner = THIS_MODULE, + .driver_name = "nwpserial", + .dev_name = "ttySQ", + .major = TTY_MAJOR, + .minor = 68, + .nr = NWPSERIAL_NR, + .cons = NWPSERIAL_CONSOLE, +}; + +int nwpserial_register_port(struct uart_port *port) +{ + struct nwpserial_port *up = NULL; + int ret = -1; + int i; + static int first = 1; + int dcr_len; + int dcr_base; + struct device_node *dn; + + mutex_lock(&nwpserial_mutex); + + dn = port->dev->of_node; + if (dn == NULL) + goto out; + + /* get dcr base. */ + dcr_base = dcr_resource_start(dn, 0); + + /* find matching entry */ + for (i = 0; i < NWPSERIAL_NR; i++) + if (nwpserial_ports[i].port.iobase == dcr_base) { + up = &nwpserial_ports[i]; + break; + } + + /* we didn't find a mtching entry, search for a free port */ + if (up == NULL) + for (i = 0; i < NWPSERIAL_NR; i++) + if (nwpserial_ports[i].port.type == PORT_UNKNOWN && + nwpserial_ports[i].port.iobase == 0) { + up = &nwpserial_ports[i]; + break; + } + + if (up == NULL) { + ret = -EBUSY; + goto out; + } + + if (first) + uart_register_driver(&nwpserial_reg); + first = 0; + + up->port.membase = port->membase; + up->port.irq = port->irq; + up->port.uartclk = port->uartclk; + up->port.fifosize = port->fifosize; + up->port.regshift = port->regshift; + up->port.iotype = port->iotype; + up->port.flags = port->flags; + up->port.mapbase = port->mapbase; + up->port.private_data = port->private_data; + + if (port->dev) + up->port.dev = port->dev; + + if (up->port.iobase != dcr_base) { + up->port.ops = &nwpserial_pops; + up->port.fifosize = 16; + + spin_lock_init(&up->port.lock); + + up->port.iobase = dcr_base; + dcr_len = dcr_resource_len(dn, 0); + + up->dcr_host = dcr_map(dn, dcr_base, dcr_len); + if (!DCR_MAP_OK(up->dcr_host)) { + printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL"); + goto out; + } + } + + ret = uart_add_one_port(&nwpserial_reg, &up->port); + if (ret == 0) + ret = up->port.line; + +out: + mutex_unlock(&nwpserial_mutex); + + return ret; +} +EXPORT_SYMBOL(nwpserial_register_port); + +void nwpserial_unregister_port(int line) +{ + struct nwpserial_port *up = &nwpserial_ports[line]; + mutex_lock(&nwpserial_mutex); + uart_remove_one_port(&nwpserial_reg, &up->port); + + up->port.type = PORT_UNKNOWN; + + mutex_unlock(&nwpserial_mutex); +} +EXPORT_SYMBOL(nwpserial_unregister_port); + +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE +static int __init nwpserial_console_init(void) +{ + struct nwpserial_port *up = NULL; + struct device_node *dn; + const char *name; + int dcr_base; + int dcr_len; + int i; + + /* search for a free port */ + for (i = 0; i < NWPSERIAL_NR; i++) + if (nwpserial_ports[i].port.type == PORT_UNKNOWN) { + up = &nwpserial_ports[i]; + break; + } + + if (up == NULL) + return -1; + + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) + return -1; + + dn = of_find_node_by_path(name); + if (!dn) + return -1; + + spin_lock_init(&up->port.lock); + up->port.ops = &nwpserial_pops; + up->port.type = PORT_NWPSERIAL; + up->port.fifosize = 16; + + dcr_base = dcr_resource_start(dn, 0); + dcr_len = dcr_resource_len(dn, 0); + up->port.iobase = dcr_base; + + up->dcr_host = dcr_map(dn, dcr_base, dcr_len); + if (!DCR_MAP_OK(up->dcr_host)) { + printk("Cannot map DCR resources for SERIAL"); + return -1; + } + register_console(&nwpserial_console); + return 0; +} +console_initcall(nwpserial_console_init); +#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c new file mode 100644 index 000000000000..5c7abe4c94dd --- /dev/null +++ b/drivers/tty/serial/of_serial.c @@ -0,0 +1,201 @@ +/* + * Serial Port driver for Open Firmware platform devices + * + * Copyright (C) 2006 Arnd Bergmann , IBM Corp. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct of_serial_info { + int type; + int line; +}; + +/* + * Fill a struct uart_port for a given device node + */ +static int __devinit of_platform_serial_setup(struct platform_device *ofdev, + int type, struct uart_port *port) +{ + struct resource resource; + struct device_node *np = ofdev->dev.of_node; + const __be32 *clk, *spd; + const __be32 *prop; + int ret, prop_size; + + memset(port, 0, sizeof *port); + spd = of_get_property(np, "current-speed", NULL); + clk = of_get_property(np, "clock-frequency", NULL); + if (!clk) { + dev_warn(&ofdev->dev, "no clock-frequency property set\n"); + return -ENODEV; + } + + ret = of_address_to_resource(np, 0, &resource); + if (ret) { + dev_warn(&ofdev->dev, "invalid address\n"); + return ret; + } + + spin_lock_init(&port->lock); + port->mapbase = resource.start; + + /* Check for shifted address mapping */ + prop = of_get_property(np, "reg-offset", &prop_size); + if (prop && (prop_size == sizeof(u32))) + port->mapbase += be32_to_cpup(prop); + + /* Check for registers offset within the devices address range */ + prop = of_get_property(np, "reg-shift", &prop_size); + if (prop && (prop_size == sizeof(u32))) + port->regshift = be32_to_cpup(prop); + + port->irq = irq_of_parse_and_map(np, 0); + port->iotype = UPIO_MEM; + port->type = type; + port->uartclk = be32_to_cpup(clk); + port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP + | UPF_FIXED_PORT | UPF_FIXED_TYPE; + port->dev = &ofdev->dev; + /* If current-speed was set, then try not to change it. */ + if (spd) + port->custom_divisor = be32_to_cpup(clk) / (16 * (be32_to_cpup(spd))); + + return 0; +} + +/* + * Try to register a serial port + */ +static int __devinit of_platform_serial_probe(struct platform_device *ofdev, + const struct of_device_id *id) +{ + struct of_serial_info *info; + struct uart_port port; + int port_type; + int ret; + + if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) + return -EBUSY; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + + port_type = (unsigned long)id->data; + ret = of_platform_serial_setup(ofdev, port_type, &port); + if (ret) + goto out; + + switch (port_type) { +#ifdef CONFIG_SERIAL_8250 + case PORT_8250 ... PORT_MAX_8250: + ret = serial8250_register_port(&port); + break; +#endif +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL + case PORT_NWPSERIAL: + ret = nwpserial_register_port(&port); + break; +#endif + default: + /* need to add code for these */ + case PORT_UNKNOWN: + dev_info(&ofdev->dev, "Unknown serial port found, ignored\n"); + ret = -ENODEV; + break; + } + if (ret < 0) + goto out; + + info->type = port_type; + info->line = ret; + dev_set_drvdata(&ofdev->dev, info); + return 0; +out: + kfree(info); + irq_dispose_mapping(port.irq); + return ret; +} + +/* + * Release a line + */ +static int of_platform_serial_remove(struct platform_device *ofdev) +{ + struct of_serial_info *info = dev_get_drvdata(&ofdev->dev); + switch (info->type) { +#ifdef CONFIG_SERIAL_8250 + case PORT_8250 ... PORT_MAX_8250: + serial8250_unregister_port(info->line); + break; +#endif +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL + case PORT_NWPSERIAL: + nwpserial_unregister_port(info->line); + break; +#endif + default: + /* need to add code for these */ + break; + } + kfree(info); + return 0; +} + +/* + * A few common types, add more as needed. + */ +static struct of_device_id __devinitdata of_platform_serial_table[] = { + { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, }, + { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, }, + { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, }, + { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, }, + { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, }, + { .type = "serial", .compatible = "ns16850", .data = (void *)PORT_16850, }, +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL + { .type = "serial", .compatible = "ibm,qpace-nwp-serial", + .data = (void *)PORT_NWPSERIAL, }, +#endif + { .type = "serial", .data = (void *)PORT_UNKNOWN, }, + { /* end of list */ }, +}; + +static struct of_platform_driver of_platform_serial_driver = { + .driver = { + .name = "of_serial", + .owner = THIS_MODULE, + .of_match_table = of_platform_serial_table, + }, + .probe = of_platform_serial_probe, + .remove = of_platform_serial_remove, +}; + +static int __init of_platform_serial_init(void) +{ + return of_register_platform_driver(&of_platform_serial_driver); +} +module_init(of_platform_serial_init); + +static void __exit of_platform_serial_exit(void) +{ + return of_unregister_platform_driver(&of_platform_serial_driver); +}; +module_exit(of_platform_serial_exit); + +MODULE_AUTHOR("Arnd Bergmann "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices"); diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c new file mode 100644 index 000000000000..7f2f01058789 --- /dev/null +++ b/drivers/tty/serial/omap-serial.c @@ -0,0 +1,1359 @@ +/* + * Driver for OMAP-UART controller. + * Based on drivers/serial/8250.c + * + * Copyright (C) 2010 Texas Instruments. + * + * Authors: + * Govindraj R + * Thara Gopinath + * + * 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. + * + * Note: This driver is made seperate from 8250 driver as we cannot + * over load 8250 driver with omap platform specific configuration for + * features like DMA, it makes easier to implement features like DMA and + * hardware flow control and software flow control configuration with + * this driver as required for the omap-platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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_rx_timeout(unsigned long uart_no); +static int serial_omap_start_rxdma(struct uart_omap_port *up); + +static inline unsigned int serial_in(struct uart_omap_port *up, int offset) +{ + offset <<= up->port.regshift; + return readw(up->port.membase + offset); +} + +static inline void serial_out(struct uart_omap_port *up, int offset, int value) +{ + offset <<= up->port.regshift; + writew(value, up->port.membase + offset); +} + +static inline void serial_omap_clear_fifos(struct uart_omap_port *up) +{ + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); +} + +/* + * serial_omap_get_divisor - calculate divisor value + * @port: uart port info + * @baud: baudrate for which divisor needs to be calculated. + * + * We have written our own function to get the divisor so as to support + * 13x mode. 3Mbps Baudrate as an different divisor. + * Reference OMAP TRM Chapter 17: + * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates + * referring to oversampling - divisor value + * baudrate 460,800 to 3,686,400 all have divisor 13 + * except 3,000,000 which has divisor value 16 + */ +static unsigned int +serial_omap_get_divisor(struct uart_port *port, unsigned int baud) +{ + unsigned int divisor; + + if (baud > OMAP_MODE13X_SPEED && baud != 3000000) + divisor = 13; + else + divisor = 16; + 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; + } +} + +static void serial_omap_enable_ms(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id); + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +} + +static void serial_omap_stop_tx(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + 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; + } + + if (up->ier & UART_IER_THRI) { + up->ier &= ~UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void serial_omap_stop_rx(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + 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); +} + +static inline void receive_chars(struct uart_omap_port *up, int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned int flag; + unsigned char ch, lsr = *status; + 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; + up->lsr_break_flag = 0; + } +#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; + int count; + + if (up->port.x_char) { + serial_out(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + serial_omap_stop_tx(&up->port); + return; + } + count = up->port.fifosize / 4; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) + serial_omap_stop_tx(&up->port); +} + +static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) +{ + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void serial_omap_start_tx(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + struct circ_buf *xmit; + unsigned int start; + int ret = 0; + + if (!up->use_dma) { + serial_omap_enable_ier_thri(up); + 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) { + 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); +} + +static unsigned int check_modem_status(struct uart_omap_port *up) +{ + unsigned int status; + + status = serial_in(up, UART_MSR); + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if ((status & UART_MSR_ANY_DELTA) == 0) + return status; + + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && + up->port.state != NULL) { + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change + (&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change + (&up->port, status & UART_MSR_CTS); + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + } + + return status; +} + +/** + * serial_omap_irq() - This handles the interrupt from one port + * @irq: uart port irq number + * @dev_id: uart port info + */ +static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) +{ + struct uart_omap_port *up = dev_id; + unsigned int iir, lsr; + unsigned long flags; + + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + return IRQ_NONE; + + 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); + } + } + + check_modem_status(up); + if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) + transmit_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + up->port_activity = jiffies; + return IRQ_HANDLED; +} + +static unsigned int serial_omap_tx_empty(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + unsigned int ret = 0; + + dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id); + 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); + + return ret; +} + +static unsigned int serial_omap_get_mctrl(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned char status; + unsigned int ret = 0; + + status = check_modem_status(up); + dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id); + + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned char mcr = 0; + + dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id); + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr |= up->mcr; + serial_out(up, UART_MCR, mcr); +} + +static void serial_omap_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + + dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id); + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static int serial_omap_startup(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags, + up->name, up); + if (retval) + return retval; + + dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id); + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial_omap_clear_fifos(up); + /* For Hardware flow control */ + serial_out(up, UART_MCR, UART_MCR_RTS); + + /* + * Clear the interrupt registers. + */ + (void) serial_in(up, UART_LSR); + if (serial_in(up, UART_LSR) & UART_LSR_DR) + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); + spin_lock_irqsave(&up->port.lock, flags); + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + up->port.mctrl |= TIOCM_OUT2; + serial_omap_set_mctrl(&up->port, up->port.mctrl); + 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_rx_timeout; + up->uart_dma.rx_timer.data = up->pdev->id; + /* 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 + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + + up->port_activity = jiffies; + return 0; +} + +static void serial_omap_shutdown(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned long flags = 0; + + dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id); + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_out(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + up->port.mctrl &= ~TIOCM_OUT2; + serial_omap_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial_omap_clear_fifos(up); + + /* + * Read data port to reset things, and then free the irq + */ + 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; + } + free_irq(up->port.irq, up); +} + +static inline void +serial_omap_configure_xonxoff + (struct uart_omap_port *up, struct ktermios *termios) +{ + unsigned char efr = 0; + + up->lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB); + + serial_out(up, UART_XON1, termios->c_cc[VSTART]); + serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); + + /* clear SW control mode bits */ + efr = up->efr; + efr &= OMAP_UART_SW_CLR; + + /* + * IXON Flag: + * Enable XON/XOFF flow control on output. + * Transmit XON1, XOFF1 + */ + if (termios->c_iflag & IXON) + efr |= OMAP_UART_SW_TX; + + /* + * IXOFF Flag: + * Enable XON/XOFF flow control on input. + * Receiver compares XON1, XOFF1. + */ + if (termios->c_iflag & IXOFF) + efr |= OMAP_UART_SW_RX; + + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + + up->mcr = serial_in(up, UART_MCR); + + /* + * IXANY Flag: + * Enable any character to restart output. + * Operation resumes after receiving any + * character after recognition of the XOFF character + */ + if (termios->c_iflag & IXANY) + up->mcr |= UART_MCR_XONANY; + + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); + /* Enable special char function UARTi.EFR_REG[5] and + * load the new software flow control mode IXON or IXOFF + * and restore the UARTi.EFR_REG[4] ENHANCED_EN value. + */ + serial_out(up, UART_EFR, efr | UART_EFR_SCD); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + + serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR); + serial_out(up, UART_LCR, up->lcr); +} + +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; + unsigned char cval = 0; + unsigned char efr = 0; + unsigned long flags = 0; + unsigned int baud, quot; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Ask the core to calculate the divisor for us. + */ + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); + quot = serial_omap_get_divisor(port, baud); + + 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 + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * Modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); + serial_out(up, UART_LCR, cval); /* reset DLAB */ + + /* FIFOs and DMA Settings */ + + /* FCR can be changed only when the + * baud clock is not running + * DLL_REG and DLH_REG set to 0. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_DLL, 0); + serial_out(up, UART_DLM, 0); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + up->mcr = serial_in(up, UART_MCR); + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + /* FIFO ENABLE, DMA MODE */ + serial_out(up, UART_FCR, up->fcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + if (up->use_dma) { + serial_out(up, UART_TI752_TLR, 0); + serial_out(up, UART_OMAP_SCR, + (UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8)); + } + + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, up->mcr); + + /* Protocol, Baud Rate, and Interrupt Settings */ + + serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + + serial_out(up, UART_LCR, 0); + serial_out(up, UART_IER, 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ + + serial_out(up, UART_LCR, 0); + serial_out(up, UART_IER, up->ier); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_LCR, cval); + + if (baud > 230400 && baud != 3000000) + serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE); + else + serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE); + + /* Hardware Flow Control Configuration */ + + if (termios->c_cflag & CRTSCTS) { + efr |= (UART_EFR_CTS | UART_EFR_RTS); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + + up->mcr = serial_in(up, UART_MCR); + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + up->efr = serial_in(up, UART_EFR); + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); + + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); + serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS); + serial_out(up, UART_LCR, cval); + } + + serial_omap_set_mctrl(&up->port, up->port.mctrl); + /* Software Flow Control Configuration */ + if (termios->c_iflag & (IXON | IXOFF)) + serial_omap_configure_xonxoff(up, termios); + + spin_unlock_irqrestore(&up->port.lock, flags); + dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id); +} + +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; + unsigned char efr; + + dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id); + 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); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, efr); + serial_out(up, UART_LCR, 0); + /* Enable module level wake up */ + serial_out(up, UART_OMAP_WER, + (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0); +} + +static void serial_omap_release_port(struct uart_port *port) +{ + dev_dbg(port->dev, "serial_omap_release_port+\n"); +} + +static int serial_omap_request_port(struct uart_port *port) +{ + dev_dbg(port->dev, "serial_omap_request_port+\n"); + return 0; +} + +static void serial_omap_config_port(struct uart_port *port, int flags) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", + up->pdev->id); + up->port.type = PORT_OMAP; +} + +static int +serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + dev_dbg(port->dev, "serial_omap_verify_port+\n"); + return -EINVAL; +} + +static const char * +serial_omap_type(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + + dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id); + return up->name; +} + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static inline void wait_for_xmitr(struct uart_omap_port *up) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + + udelay(1); + } + } +} + +#ifdef CONFIG_CONSOLE_POLL + +static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + wait_for_xmitr(up); + serial_out(up, UART_TX, ch); +} + +static int serial_omap_poll_get_char(struct uart_port *port) +{ + struct uart_omap_port *up = (struct uart_omap_port *)port; + unsigned int status = serial_in(up, UART_LSR); + + if (!(status & UART_LSR_DR)) + return NO_POLL_CHAR; + + return serial_in(up, UART_RX); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE + +static struct uart_omap_port *serial_omap_console_ports[4]; + +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; + + wait_for_xmitr(up); + serial_out(up, UART_TX, ch); +} + +static void +serial_omap_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_omap_port *up = serial_omap_console_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + 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 + */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + + uart_console_write(&up->port, s, count, serial_omap_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); + /* + * The receive handling will happen properly because the + * receive ready bit will still be set; it is not cleared + * on read. However, modem control will not, we must + * call it if we have saved something in the saved flags + * while processing with interrupts off. + */ + if (up->msr_saved_flags) + check_modem_status(up); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init +serial_omap_console_setup(struct console *co, char *options) +{ + struct uart_omap_port *up; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (serial_omap_console_ports[co->index] == NULL) + return -ENODEV; + up = serial_omap_console_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&up->port, co, baud, parity, bits, flow); +} + +static struct console serial_omap_console = { + .name = OMAP_SERIAL_NAME, + .write = serial_omap_console_write, + .device = uart_console_device, + .setup = serial_omap_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &serial_omap_reg, +}; + +static void serial_omap_add_console_port(struct uart_omap_port *up) +{ + serial_omap_console_ports[up->pdev->id] = up; +} + +#define OMAP_CONSOLE (&serial_omap_console) + +#else + +#define OMAP_CONSOLE NULL + +static inline void serial_omap_add_console_port(struct uart_omap_port *up) +{} + +#endif + +static struct uart_ops serial_omap_pops = { + .tx_empty = serial_omap_tx_empty, + .set_mctrl = serial_omap_set_mctrl, + .get_mctrl = serial_omap_get_mctrl, + .stop_tx = serial_omap_stop_tx, + .start_tx = serial_omap_start_tx, + .stop_rx = serial_omap_stop_rx, + .enable_ms = serial_omap_enable_ms, + .break_ctl = serial_omap_break_ctl, + .startup = serial_omap_startup, + .shutdown = serial_omap_shutdown, + .set_termios = serial_omap_set_termios, + .pm = serial_omap_pm, + .type = serial_omap_type, + .release_port = serial_omap_release_port, + .request_port = serial_omap_request_port, + .config_port = serial_omap_config_port, + .verify_port = serial_omap_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = serial_omap_poll_put_char, + .poll_get_char = serial_omap_poll_get_char, +#endif +}; + +static struct uart_driver serial_omap_reg = { + .owner = THIS_MODULE, + .driver_name = "OMAP-SERIAL", + .dev_name = OMAP_SERIAL_NAME, + .nr = OMAP_MAX_HSUART_PORTS, + .cons = OMAP_CONSOLE, +}; + +static int +serial_omap_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct uart_omap_port *up = platform_get_drvdata(pdev); + + if (up) + uart_suspend_port(&serial_omap_reg, &up->port); + return 0; +} + +static int serial_omap_resume(struct platform_device *dev) +{ + struct uart_omap_port *up = platform_get_drvdata(dev); + + if (up) + uart_resume_port(&serial_omap_reg, &up->port); + return 0; +} + +static void serial_omap_rx_timeout(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) < + RX_TIMEOUT) { + mod_timer(&up->uart_dma.rx_timer, jiffies + + usecs_to_jiffies(up->uart_dma.rx_timeout)); + } 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_timeout)); + } + 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) { + 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_timeout)); + 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 = (struct uart_omap_port *)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 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; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "no mem resource?\n"); + return -ENODEV; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -ENODEV; + } + + if (!request_mem_region(mem->start, (mem->end - mem->start) + 1, + pdev->dev.driver->name)) { + dev_err(&pdev->dev, "memory region already claimed\n"); + return -EBUSY; + } + + dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); + if (!dma_rx) { + ret = -EINVAL; + goto err; + } + + dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); + if (!dma_tx) { + ret = -EINVAL; + goto err; + } + + up = kzalloc(sizeof(*up), GFP_KERNEL); + if (up == NULL) { + ret = -ENOMEM; + goto do_release_region; + } + sprintf(up->name, "OMAP UART%d", pdev->id); + up->pdev = pdev; + up->port.dev = &pdev->dev; + up->port.type = PORT_OMAP; + up->port.iotype = UPIO_MEM; + up->port.irq = irq->start; + + up->port.regshift = 2; + up->port.fifosize = 64; + up->port.ops = &serial_omap_pops; + up->port.line = pdev->id; + + up->port.membase = omap_up_info->membase; + up->port.mapbase = omap_up_info->mapbase; + up->port.flags = omap_up_info->flags; + up->port.irqflags = omap_up_info->irqflags; + up->port.uartclk = omap_up_info->uartclk; + 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 = 4096; + up->uart_dma.rx_timeout = 2; + 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; + } + + ui[pdev->id] = up; + serial_omap_add_console_port(up); + + ret = uart_add_one_port(&serial_omap_reg, &up->port); + if (ret != 0) + goto do_release_region; + + platform_set_drvdata(pdev, up); + return 0; +err: + dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", + pdev->id, __func__, ret); +do_release_region: + release_mem_region(mem->start, (mem->end - mem->start) + 1); + return ret; +} + +static int serial_omap_remove(struct platform_device *dev) +{ + struct uart_omap_port *up = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + if (up) { + uart_remove_one_port(&serial_omap_reg, &up->port); + kfree(up); + } + return 0; +} + +static struct platform_driver serial_omap_driver = { + .probe = serial_omap_probe, + .remove = serial_omap_remove, + + .suspend = serial_omap_suspend, + .resume = serial_omap_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init serial_omap_init(void) +{ + int ret; + + ret = uart_register_driver(&serial_omap_reg); + if (ret != 0) + return ret; + ret = platform_driver_register(&serial_omap_driver); + if (ret != 0) + uart_unregister_driver(&serial_omap_reg); + return ret; +} + +static void __exit serial_omap_exit(void) +{ + platform_driver_unregister(&serial_omap_driver); + uart_unregister_driver(&serial_omap_reg); +} + +module_init(serial_omap_init); +module_exit(serial_omap_exit); + +MODULE_DESCRIPTION("OMAP High Speed UART driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c new file mode 100644 index 000000000000..70a61458ec42 --- /dev/null +++ b/drivers/tty/serial/pch_uart.c @@ -0,0 +1,1451 @@ +/* + *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + * + *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; version 2 of the License. + * + *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 + +enum { + PCH_UART_HANDLED_RX_INT_SHIFT, + PCH_UART_HANDLED_TX_INT_SHIFT, + PCH_UART_HANDLED_RX_ERR_INT_SHIFT, + PCH_UART_HANDLED_RX_TRG_INT_SHIFT, + PCH_UART_HANDLED_MS_INT_SHIFT, +}; + +enum { + PCH_UART_8LINE, + PCH_UART_2LINE, +}; + +#define PCH_UART_DRIVER_DEVICE "ttyPCH" + +#define PCH_UART_NR_GE_256FIFO 1 +#define PCH_UART_NR_GE_64FIFO 3 +#define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO) +#define PCH_UART_NR PCH_UART_NR_GE + +#define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_RX_ERR_INT (1<<((\ + PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_RX_TRG_INT (1<<((\ + PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) + +#define PCH_UART_RBR 0x00 +#define PCH_UART_THR 0x00 + +#define PCH_UART_IER_MASK (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\ + PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI) +#define PCH_UART_IER_ERBFI 0x00000001 +#define PCH_UART_IER_ETBEI 0x00000002 +#define PCH_UART_IER_ELSI 0x00000004 +#define PCH_UART_IER_EDSSI 0x00000008 + +#define PCH_UART_IIR_IP 0x00000001 +#define PCH_UART_IIR_IID 0x00000006 +#define PCH_UART_IIR_MSI 0x00000000 +#define PCH_UART_IIR_TRI 0x00000002 +#define PCH_UART_IIR_RRI 0x00000004 +#define PCH_UART_IIR_REI 0x00000006 +#define PCH_UART_IIR_TOI 0x00000008 +#define PCH_UART_IIR_FIFO256 0x00000020 +#define PCH_UART_IIR_FIFO64 PCH_UART_IIR_FIFO256 +#define PCH_UART_IIR_FE 0x000000C0 + +#define PCH_UART_FCR_FIFOE 0x00000001 +#define PCH_UART_FCR_RFR 0x00000002 +#define PCH_UART_FCR_TFR 0x00000004 +#define PCH_UART_FCR_DMS 0x00000008 +#define PCH_UART_FCR_FIFO256 0x00000020 +#define PCH_UART_FCR_RFTL 0x000000C0 + +#define PCH_UART_FCR_RFTL1 0x00000000 +#define PCH_UART_FCR_RFTL64 0x00000040 +#define PCH_UART_FCR_RFTL128 0x00000080 +#define PCH_UART_FCR_RFTL224 0x000000C0 +#define PCH_UART_FCR_RFTL16 PCH_UART_FCR_RFTL64 +#define PCH_UART_FCR_RFTL32 PCH_UART_FCR_RFTL128 +#define PCH_UART_FCR_RFTL56 PCH_UART_FCR_RFTL224 +#define PCH_UART_FCR_RFTL4 PCH_UART_FCR_RFTL64 +#define PCH_UART_FCR_RFTL8 PCH_UART_FCR_RFTL128 +#define PCH_UART_FCR_RFTL14 PCH_UART_FCR_RFTL224 +#define PCH_UART_FCR_RFTL_SHIFT 6 + +#define PCH_UART_LCR_WLS 0x00000003 +#define PCH_UART_LCR_STB 0x00000004 +#define PCH_UART_LCR_PEN 0x00000008 +#define PCH_UART_LCR_EPS 0x00000010 +#define PCH_UART_LCR_SP 0x00000020 +#define PCH_UART_LCR_SB 0x00000040 +#define PCH_UART_LCR_DLAB 0x00000080 +#define PCH_UART_LCR_NP 0x00000000 +#define PCH_UART_LCR_OP PCH_UART_LCR_PEN +#define PCH_UART_LCR_EP (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS) +#define PCH_UART_LCR_1P (PCH_UART_LCR_PEN | PCH_UART_LCR_SP) +#define PCH_UART_LCR_0P (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\ + PCH_UART_LCR_SP) + +#define PCH_UART_LCR_5BIT 0x00000000 +#define PCH_UART_LCR_6BIT 0x00000001 +#define PCH_UART_LCR_7BIT 0x00000002 +#define PCH_UART_LCR_8BIT 0x00000003 + +#define PCH_UART_MCR_DTR 0x00000001 +#define PCH_UART_MCR_RTS 0x00000002 +#define PCH_UART_MCR_OUT 0x0000000C +#define PCH_UART_MCR_LOOP 0x00000010 +#define PCH_UART_MCR_AFE 0x00000020 + +#define PCH_UART_LSR_DR 0x00000001 +#define PCH_UART_LSR_ERR (1<<7) + +#define PCH_UART_MSR_DCTS 0x00000001 +#define PCH_UART_MSR_DDSR 0x00000002 +#define PCH_UART_MSR_TERI 0x00000004 +#define PCH_UART_MSR_DDCD 0x00000008 +#define PCH_UART_MSR_CTS 0x00000010 +#define PCH_UART_MSR_DSR 0x00000020 +#define PCH_UART_MSR_RI 0x00000040 +#define PCH_UART_MSR_DCD 0x00000080 +#define PCH_UART_MSR_DELTA (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\ + PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD) + +#define PCH_UART_DLL 0x00 +#define PCH_UART_DLM 0x01 + +#define DIV_ROUND(a, b) (((a) + ((b)/2)) / (b)) + +#define PCH_UART_IID_RLS (PCH_UART_IIR_REI) +#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI) +#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI) +#define PCH_UART_IID_THRE (PCH_UART_IIR_TRI) +#define PCH_UART_IID_MS (PCH_UART_IIR_MSI) + +#define PCH_UART_HAL_PARITY_NONE (PCH_UART_LCR_NP) +#define PCH_UART_HAL_PARITY_ODD (PCH_UART_LCR_OP) +#define PCH_UART_HAL_PARITY_EVEN (PCH_UART_LCR_EP) +#define PCH_UART_HAL_PARITY_FIX1 (PCH_UART_LCR_1P) +#define PCH_UART_HAL_PARITY_FIX0 (PCH_UART_LCR_0P) +#define PCH_UART_HAL_5BIT (PCH_UART_LCR_5BIT) +#define PCH_UART_HAL_6BIT (PCH_UART_LCR_6BIT) +#define PCH_UART_HAL_7BIT (PCH_UART_LCR_7BIT) +#define PCH_UART_HAL_8BIT (PCH_UART_LCR_8BIT) +#define PCH_UART_HAL_STB1 0 +#define PCH_UART_HAL_STB2 (PCH_UART_LCR_STB) + +#define PCH_UART_HAL_CLR_TX_FIFO (PCH_UART_FCR_TFR) +#define PCH_UART_HAL_CLR_RX_FIFO (PCH_UART_FCR_RFR) +#define PCH_UART_HAL_CLR_ALL_FIFO (PCH_UART_HAL_CLR_TX_FIFO | \ + PCH_UART_HAL_CLR_RX_FIFO) + +#define PCH_UART_HAL_DMA_MODE0 0 +#define PCH_UART_HAL_FIFO_DIS 0 +#define PCH_UART_HAL_FIFO16 (PCH_UART_FCR_FIFOE) +#define PCH_UART_HAL_FIFO256 (PCH_UART_FCR_FIFOE | \ + PCH_UART_FCR_FIFO256) +#define PCH_UART_HAL_FIFO64 (PCH_UART_HAL_FIFO256) +#define PCH_UART_HAL_TRIGGER1 (PCH_UART_FCR_RFTL1) +#define PCH_UART_HAL_TRIGGER64 (PCH_UART_FCR_RFTL64) +#define PCH_UART_HAL_TRIGGER128 (PCH_UART_FCR_RFTL128) +#define PCH_UART_HAL_TRIGGER224 (PCH_UART_FCR_RFTL224) +#define PCH_UART_HAL_TRIGGER16 (PCH_UART_FCR_RFTL16) +#define PCH_UART_HAL_TRIGGER32 (PCH_UART_FCR_RFTL32) +#define PCH_UART_HAL_TRIGGER56 (PCH_UART_FCR_RFTL56) +#define PCH_UART_HAL_TRIGGER4 (PCH_UART_FCR_RFTL4) +#define PCH_UART_HAL_TRIGGER8 (PCH_UART_FCR_RFTL8) +#define PCH_UART_HAL_TRIGGER14 (PCH_UART_FCR_RFTL14) +#define PCH_UART_HAL_TRIGGER_L (PCH_UART_FCR_RFTL64) +#define PCH_UART_HAL_TRIGGER_M (PCH_UART_FCR_RFTL128) +#define PCH_UART_HAL_TRIGGER_H (PCH_UART_FCR_RFTL224) + +#define PCH_UART_HAL_RX_INT (PCH_UART_IER_ERBFI) +#define PCH_UART_HAL_TX_INT (PCH_UART_IER_ETBEI) +#define PCH_UART_HAL_RX_ERR_INT (PCH_UART_IER_ELSI) +#define PCH_UART_HAL_MS_INT (PCH_UART_IER_EDSSI) +#define PCH_UART_HAL_ALL_INT (PCH_UART_IER_MASK) + +#define PCH_UART_HAL_DTR (PCH_UART_MCR_DTR) +#define PCH_UART_HAL_RTS (PCH_UART_MCR_RTS) +#define PCH_UART_HAL_OUT (PCH_UART_MCR_OUT) +#define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) +#define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) + +struct pch_uart_buffer { + unsigned char *buf; + int size; +}; + +struct eg20t_port { + struct uart_port port; + int port_type; + void __iomem *membase; + resource_size_t mapbase; + unsigned int iobase; + struct pci_dev *pdev; + int fifo_size; + int base_baud; + int start_tx; + int start_rx; + int tx_empty; + int int_dis_flag; + int trigger; + int trigger_level; + struct pch_uart_buffer rxbuf; + unsigned int dmsr; + unsigned int fcr; + unsigned int use_dma; + unsigned int use_dma_flag; + struct dma_async_tx_descriptor *desc_tx; + struct dma_async_tx_descriptor *desc_rx; + struct pch_dma_slave param_tx; + struct pch_dma_slave param_rx; + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + struct scatterlist sg_tx; + struct scatterlist sg_rx; + int tx_dma_use; + void *rx_buf_virt; + dma_addr_t rx_buf_dma; +}; + +static unsigned int default_baud = 9600; +static const int trigger_level_256[4] = { 1, 64, 128, 224 }; +static const int trigger_level_64[4] = { 1, 16, 32, 56 }; +static const int trigger_level_16[4] = { 1, 4, 8, 14 }; +static const int trigger_level_1[4] = { 1, 1, 1, 1 }; + +static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, + int base_baud) +{ + struct eg20t_port *priv = pci_get_drvdata(pdev); + + priv->trigger_level = 1; + priv->fcr = 0; +} + +static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base) +{ + unsigned int msr = ioread8(base + UART_MSR); + priv->dmsr |= msr & PCH_UART_MSR_DELTA; + + return msr; +} + +static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, + unsigned int flag) +{ + u8 ier = ioread8(priv->membase + UART_IER); + ier |= flag & PCH_UART_IER_MASK; + iowrite8(ier, priv->membase + UART_IER); +} + +static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv, + unsigned int flag) +{ + u8 ier = ioread8(priv->membase + UART_IER); + ier &= ~(flag & PCH_UART_IER_MASK); + iowrite8(ier, priv->membase + UART_IER); +} + +static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud, + unsigned int parity, unsigned int bits, + unsigned int stb) +{ + unsigned int dll, dlm, lcr; + int div; + + div = DIV_ROUND(priv->base_baud / 16, baud); + if (div < 0 || USHRT_MAX <= div) { + pr_err("Invalid Baud(div=0x%x)\n", div); + return -EINVAL; + } + + dll = (unsigned int)div & 0x00FFU; + dlm = ((unsigned int)div >> 8) & 0x00FFU; + + if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) { + pr_err("Invalid parity(0x%x)\n", parity); + return -EINVAL; + } + + if (bits & ~PCH_UART_LCR_WLS) { + pr_err("Invalid bits(0x%x)\n", bits); + return -EINVAL; + } + + if (stb & ~PCH_UART_LCR_STB) { + pr_err("Invalid STB(0x%x)\n", stb); + return -EINVAL; + } + + lcr = parity; + lcr |= bits; + lcr |= stb; + + pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n", + __func__, baud, div, lcr, jiffies); + iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); + iowrite8(dll, priv->membase + PCH_UART_DLL); + iowrite8(dlm, priv->membase + PCH_UART_DLM); + iowrite8(lcr, priv->membase + UART_LCR); + + return 0; +} + +static int pch_uart_hal_fifo_reset(struct eg20t_port *priv, + unsigned int flag) +{ + if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) { + pr_err("%s:Invalid flag(0x%x)\n", __func__, flag); + return -EINVAL; + } + + iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR); + iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag, + priv->membase + UART_FCR); + iowrite8(priv->fcr, priv->membase + UART_FCR); + + return 0; +} + +static int pch_uart_hal_set_fifo(struct eg20t_port *priv, + unsigned int dmamode, + unsigned int fifo_size, unsigned int trigger) +{ + u8 fcr; + + if (dmamode & ~PCH_UART_FCR_DMS) { + pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode); + return -EINVAL; + } + + if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) { + pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size); + return -EINVAL; + } + + if (trigger & ~PCH_UART_FCR_RFTL) { + pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger); + return -EINVAL; + } + + switch (priv->fifo_size) { + case 256: + priv->trigger_level = + trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT]; + break; + case 64: + priv->trigger_level = + trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT]; + break; + case 16: + priv->trigger_level = + trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT]; + break; + default: + priv->trigger_level = + trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT]; + break; + } + fcr = + dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR; + iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR); + iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR, + priv->membase + UART_FCR); + iowrite8(fcr, priv->membase + UART_FCR); + priv->fcr = fcr; + + return 0; +} + +static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) +{ + priv->dmsr = 0; + return get_msr(priv, priv->membase); +} + +static int pch_uart_hal_write(struct eg20t_port *priv, + const unsigned char *buf, int tx_size) +{ + int i; + unsigned int thr; + + for (i = 0; i < tx_size;) { + thr = buf[i++]; + iowrite8(thr, priv->membase + PCH_UART_THR); + } + return i; +} + +static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, + int rx_size) +{ + int i; + u8 rbr, lsr; + + lsr = ioread8(priv->membase + UART_LSR); + for (i = 0, lsr = ioread8(priv->membase + UART_LSR); + i < rx_size && lsr & UART_LSR_DR; + lsr = ioread8(priv->membase + UART_LSR)) { + rbr = ioread8(priv->membase + PCH_UART_RBR); + buf[i++] = rbr; + } + return i; +} + +static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) +{ + unsigned int iir; + int ret; + + iir = ioread8(priv->membase + UART_IIR); + ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); + return ret; +} + +static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) +{ + return ioread8(priv->membase + UART_LSR); +} + +static void pch_uart_hal_set_break(struct eg20t_port *priv, int on) +{ + unsigned int lcr; + + lcr = ioread8(priv->membase + UART_LCR); + if (on) + lcr |= PCH_UART_LCR_SB; + else + lcr &= ~PCH_UART_LCR_SB; + + iowrite8(lcr, priv->membase + UART_LCR); +} + +static int push_rx(struct eg20t_port *priv, const unsigned char *buf, + int size) +{ + struct uart_port *port; + struct tty_struct *tty; + + port = &priv->port; + tty = tty_port_tty_get(&port->state->port); + if (!tty) { + pr_debug("%s:tty is busy now", __func__); + return -EBUSY; + } + + tty_insert_flip_string(tty, buf, size); + tty_flip_buffer_push(tty); + tty_kref_put(tty); + + return 0; +} + +static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) +{ + int ret; + struct uart_port *port = &priv->port; + + if (port->x_char) { + pr_debug("%s:X character send %02x (%lu)\n", __func__, + port->x_char, jiffies); + buf[0] = port->x_char; + port->x_char = 0; + ret = 1; + } else { + ret = 0; + } + + return ret; +} + +static int dma_push_rx(struct eg20t_port *priv, int size) +{ + struct tty_struct *tty; + int room; + struct uart_port *port = &priv->port; + + port = &priv->port; + tty = tty_port_tty_get(&port->state->port); + if (!tty) { + pr_debug("%s:tty is busy now", __func__); + return 0; + } + + room = tty_buffer_request_room(tty, size); + + if (room < size) + dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", + size - room); + if (!room) + return room; + + tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size); + + port->icount.rx += room; + tty_kref_put(tty); + + return room; +} + +static void pch_free_dma(struct uart_port *port) +{ + struct eg20t_port *priv; + priv = container_of(port, struct eg20t_port, port); + + if (priv->chan_tx) { + dma_release_channel(priv->chan_tx); + priv->chan_tx = NULL; + } + if (priv->chan_rx) { + dma_release_channel(priv->chan_rx); + priv->chan_rx = NULL; + } + if (sg_dma_address(&priv->sg_rx)) + dma_free_coherent(port->dev, port->fifosize, + sg_virt(&priv->sg_rx), + sg_dma_address(&priv->sg_rx)); + + return; +} + +static bool filter(struct dma_chan *chan, void *slave) +{ + struct pch_dma_slave *param = slave; + + if ((chan->chan_id == param->chan_id) && (param->dma_dev == + chan->device->dev)) { + chan->private = param; + return true; + } else { + return false; + } +} + +static void pch_request_dma(struct uart_port *port) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + struct pci_dev *dma_dev; + struct pch_dma_slave *param; + struct eg20t_port *priv = + container_of(port, struct eg20t_port, port); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev + information */ + /* Set Tx DMA */ + param = &priv->param_tx; + param->dma_dev = &dma_dev->dev; + param->chan_id = priv->port.line; + param->tx_reg = port->mapbase + UART_TX; + chan = dma_request_channel(mask, filter, param); + if (!chan) { + pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__); + return; + } + priv->chan_tx = chan; + + /* Set Rx DMA */ + param = &priv->param_rx; + param->dma_dev = &dma_dev->dev; + param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */ + param->rx_reg = port->mapbase + UART_RX; + chan = dma_request_channel(mask, filter, param); + if (!chan) { + pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__); + dma_release_channel(priv->chan_tx); + return; + } + + /* Get Consistent memory for DMA */ + priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize, + &priv->rx_buf_dma, GFP_KERNEL); + priv->chan_rx = chan; +} + +static void pch_dma_rx_complete(void *arg) +{ + struct eg20t_port *priv = arg; + struct uart_port *port = &priv->port; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + + if (!tty) { + pr_debug("%s:tty is busy now", __func__); + return; + } + + if (dma_push_rx(priv, priv->trigger_level)) + tty_flip_buffer_push(tty); + + tty_kref_put(tty); +} + +static void pch_dma_tx_complete(void *arg) +{ + struct eg20t_port *priv = arg; + struct uart_port *port = &priv->port; + struct circ_buf *xmit = &port->state->xmit; + + xmit->tail += sg_dma_len(&priv->sg_tx); + xmit->tail &= UART_XMIT_SIZE - 1; + port->icount.tx += sg_dma_len(&priv->sg_tx); + + async_tx_ack(priv->desc_tx); + priv->tx_dma_use = 0; +} + +static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size) +{ + int count = 0; + struct uart_port *port = &priv->port; + struct circ_buf *xmit = &port->state->xmit; + + if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size) + goto pop_tx_end; + + do { + int cnt_to_end = + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + int sz = min(size - count, cnt_to_end); + memcpy(&buf[count], &xmit->buf[xmit->tail], sz); + xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1); + count += sz; + } while (!uart_circ_empty(xmit) && count < size); + +pop_tx_end: + pr_debug("%d characters. Remained %d characters. (%lu)\n", + count, size - count, jiffies); + + return count; +} + +static int handle_rx_to(struct eg20t_port *priv) +{ + struct pch_uart_buffer *buf; + int rx_size; + int ret; + if (!priv->start_rx) { + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); + return 0; + } + buf = &priv->rxbuf; + do { + rx_size = pch_uart_hal_read(priv, buf->buf, buf->size); + ret = push_rx(priv, buf->buf, rx_size); + if (ret) + return 0; + } while (rx_size == buf->size); + + return PCH_UART_HANDLED_RX_INT; +} + +static int handle_rx(struct eg20t_port *priv) +{ + return handle_rx_to(priv); +} + +static int dma_handle_rx(struct eg20t_port *priv) +{ + struct uart_port *port = &priv->port; + struct dma_async_tx_descriptor *desc; + struct scatterlist *sg; + + priv = container_of(port, struct eg20t_port, port); + sg = &priv->sg_rx; + + sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */ + + sg_dma_len(sg) = priv->fifo_size; + + sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt), + sg_dma_len(sg), (unsigned long)priv->rx_buf_virt & + ~PAGE_MASK); + + sg_dma_address(sg) = priv->rx_buf_dma; + + desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx, + sg, 1, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT); + if (!desc) + return 0; + + priv->desc_rx = desc; + desc->callback = pch_dma_rx_complete; + desc->callback_param = priv; + desc->tx_submit(desc); + dma_async_issue_pending(priv->chan_rx); + + return PCH_UART_HANDLED_RX_INT; +} + +static unsigned int handle_tx(struct eg20t_port *priv) +{ + struct uart_port *port = &priv->port; + struct circ_buf *xmit = &port->state->xmit; + int ret; + int fifo_size; + int tx_size; + int size; + int tx_empty; + + if (!priv->start_tx) { + pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); + priv->tx_empty = 1; + return 0; + } + + fifo_size = max(priv->fifo_size, 1); + tx_empty = 1; + if (pop_tx_x(priv, xmit->buf)) { + pch_uart_hal_write(priv, xmit->buf, 1); + port->icount.tx++; + tx_empty = 0; + fifo_size--; + } + size = min(xmit->head - xmit->tail, fifo_size); + tx_size = pop_tx(priv, xmit->buf, size); + if (tx_size > 0) { + ret = pch_uart_hal_write(priv, xmit->buf, tx_size); + port->icount.tx += ret; + tx_empty = 0; + } + + priv->tx_empty = tx_empty; + + if (tx_empty) + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); + + return PCH_UART_HANDLED_TX_INT; +} + +static unsigned int dma_handle_tx(struct eg20t_port *priv) +{ + struct uart_port *port = &priv->port; + struct circ_buf *xmit = &port->state->xmit; + struct scatterlist *sg = &priv->sg_tx; + int nent; + int fifo_size; + int tx_empty; + struct dma_async_tx_descriptor *desc; + + if (!priv->start_tx) { + pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); + priv->tx_empty = 1; + return 0; + } + + fifo_size = max(priv->fifo_size, 1); + tx_empty = 1; + if (pop_tx_x(priv, xmit->buf)) { + pch_uart_hal_write(priv, xmit->buf, 1); + port->icount.tx++; + tx_empty = 0; + fifo_size--; + } + + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); + + priv->tx_dma_use = 1; + + sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */ + + sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf), + UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK); + + nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE); + if (!nent) { + pr_err("%s:dma_map_sg Failed\n", __func__); + return 0; + } + + sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); + sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + + sg->offset; + sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, + UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, + xmit->tail, UART_XMIT_SIZE)); + + desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx, + sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + pr_err("%s:device_prep_slave_sg Failed\n", __func__); + return 0; + } + + dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + + priv->desc_tx = desc; + desc->callback = pch_dma_tx_complete; + desc->callback_param = priv; + + desc->tx_submit(desc); + + dma_async_issue_pending(priv->chan_tx); + + return PCH_UART_HANDLED_TX_INT; +} + +static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr) +{ + u8 fcr = ioread8(priv->membase + UART_FCR); + + /* Reset FIFO */ + fcr |= UART_FCR_CLEAR_RCVR; + iowrite8(fcr, priv->membase + UART_FCR); + + if (lsr & PCH_UART_LSR_ERR) + dev_err(&priv->pdev->dev, "Error data in FIFO\n"); + + if (lsr & UART_LSR_FE) + dev_err(&priv->pdev->dev, "Framing Error\n"); + + if (lsr & UART_LSR_PE) + dev_err(&priv->pdev->dev, "Parity Error\n"); + + if (lsr & UART_LSR_OE) + dev_err(&priv->pdev->dev, "Overrun Error\n"); +} + +static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) +{ + struct eg20t_port *priv = dev_id; + unsigned int handled; + u8 lsr; + int ret = 0; + unsigned int iid; + unsigned long flags; + + spin_lock_irqsave(&priv->port.lock, flags); + handled = 0; + while ((iid = pch_uart_hal_get_iid(priv)) > 1) { + switch (iid) { + case PCH_UART_IID_RLS: /* Receiver Line Status */ + lsr = pch_uart_hal_get_line_status(priv); + if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE | + UART_LSR_PE | UART_LSR_OE)) { + pch_uart_err_ir(priv, lsr); + ret = PCH_UART_HANDLED_RX_ERR_INT; + } + break; + case PCH_UART_IID_RDR: /* Received Data Ready */ + if (priv->use_dma) + ret = dma_handle_rx(priv); + else + ret = handle_rx(priv); + break; + case PCH_UART_IID_RDR_TO: /* Received Data Ready + (FIFO Timeout) */ + ret = handle_rx_to(priv); + break; + case PCH_UART_IID_THRE: /* Transmitter Holding Register + Empty */ + if (priv->use_dma) + ret = dma_handle_tx(priv); + else + ret = handle_tx(priv); + break; + case PCH_UART_IID_MS: /* Modem Status */ + ret = PCH_UART_HANDLED_MS_INT; + break; + default: /* Never junp to this label */ + pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies); + ret = -1; + break; + } + handled |= (unsigned int)ret; + } + if (handled == 0 && iid <= 1) { + if (priv->int_dis_flag) + priv->int_dis_flag = 0; + } + + spin_unlock_irqrestore(&priv->port.lock, flags); + return IRQ_RETVAL(handled); +} + +/* This function tests whether the transmitter fifo and shifter for the port + described by 'port' is empty. */ +static unsigned int pch_uart_tx_empty(struct uart_port *port) +{ + struct eg20t_port *priv; + int ret; + priv = container_of(port, struct eg20t_port, port); + if (priv->tx_empty) + ret = TIOCSER_TEMT; + else + ret = 0; + + return ret; +} + +/* Returns the current state of modem control inputs. */ +static unsigned int pch_uart_get_mctrl(struct uart_port *port) +{ + struct eg20t_port *priv; + u8 modem; + unsigned int ret = 0; + + priv = container_of(port, struct eg20t_port, port); + modem = pch_uart_hal_get_modem(priv); + + if (modem & UART_MSR_DCD) + ret |= TIOCM_CAR; + + if (modem & UART_MSR_RI) + ret |= TIOCM_RNG; + + if (modem & UART_MSR_DSR) + ret |= TIOCM_DSR; + + if (modem & UART_MSR_CTS) + ret |= TIOCM_CTS; + + return ret; +} + +static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + u32 mcr = 0; + unsigned int dat; + struct eg20t_port *priv = container_of(port, struct eg20t_port, port); + + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + if (mctrl) { + dat = pch_uart_get_mctrl(port); + dat |= mcr; + iowrite8(dat, priv->membase + UART_MCR); + } +} + +static void pch_uart_stop_tx(struct uart_port *port) +{ + struct eg20t_port *priv; + priv = container_of(port, struct eg20t_port, port); + priv->start_tx = 0; + priv->tx_dma_use = 0; +} + +static void pch_uart_start_tx(struct uart_port *port) +{ + struct eg20t_port *priv; + + priv = container_of(port, struct eg20t_port, port); + + if (priv->use_dma) + if (priv->tx_dma_use) + return; + + priv->start_tx = 1; + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); +} + +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); + priv->int_dis_flag = 1; +} + +/* Enable the modem status interrupts. */ +static void pch_uart_enable_ms(struct uart_port *port) +{ + struct eg20t_port *priv; + priv = container_of(port, struct eg20t_port, port); + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT); +} + +/* Control the transmission of a break signal. */ +static void pch_uart_break_ctl(struct uart_port *port, int ctl) +{ + struct eg20t_port *priv; + unsigned long flags; + + priv = container_of(port, struct eg20t_port, port); + spin_lock_irqsave(&port->lock, flags); + pch_uart_hal_set_break(priv, ctl); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Grab any interrupt resources and initialise any low level driver state. */ +static int pch_uart_startup(struct uart_port *port) +{ + struct eg20t_port *priv; + int ret; + int fifo_size; + int trigger_level; + + priv = container_of(port, struct eg20t_port, port); + priv->tx_empty = 1; + port->uartclk = priv->base_baud; + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); + ret = pch_uart_hal_set_line(priv, default_baud, + PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT, + PCH_UART_HAL_STB1); + if (ret) + return ret; + + switch (priv->fifo_size) { + case 256: + fifo_size = PCH_UART_HAL_FIFO256; + break; + case 64: + fifo_size = PCH_UART_HAL_FIFO64; + break; + case 16: + fifo_size = PCH_UART_HAL_FIFO16; + case 1: + default: + fifo_size = PCH_UART_HAL_FIFO_DIS; + break; + } + + switch (priv->trigger) { + case PCH_UART_HAL_TRIGGER1: + trigger_level = 1; + break; + case PCH_UART_HAL_TRIGGER_L: + trigger_level = priv->fifo_size / 4; + break; + case PCH_UART_HAL_TRIGGER_M: + trigger_level = priv->fifo_size / 2; + break; + case PCH_UART_HAL_TRIGGER_H: + default: + trigger_level = priv->fifo_size - (priv->fifo_size / 8); + break; + } + + priv->trigger_level = trigger_level; + ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0, + fifo_size, priv->trigger); + if (ret < 0) + return ret; + + ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED, + KBUILD_MODNAME, priv); + if (ret < 0) + return ret; + + if (priv->use_dma) + pch_request_dma(port); + + priv->start_rx = 1; + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); + uart_update_timeout(port, CS8, default_baud); + + return 0; +} + +static void pch_uart_shutdown(struct uart_port *port) +{ + struct eg20t_port *priv; + int ret; + + priv = container_of(port, struct eg20t_port, port); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); + pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO); + ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0, + PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1); + if (ret) + pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); + + if (priv->use_dma_flag) + pch_free_dma(port); + + free_irq(priv->port.irq, priv); +} + +/* Change the port parameters, including word length, parity, stop + *bits. Update read_status_mask and ignore_status_mask to indicate + *the types of events we are interested in receiving. */ +static void pch_uart_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + int baud; + int rtn; + unsigned int parity, bits, stb; + struct eg20t_port *priv; + unsigned long flags; + + priv = container_of(port, struct eg20t_port, port); + switch (termios->c_cflag & CSIZE) { + case CS5: + bits = PCH_UART_HAL_5BIT; + break; + case CS6: + bits = PCH_UART_HAL_6BIT; + break; + case CS7: + bits = PCH_UART_HAL_7BIT; + break; + default: /* CS8 */ + bits = PCH_UART_HAL_8BIT; + break; + } + if (termios->c_cflag & CSTOPB) + stb = PCH_UART_HAL_STB2; + else + stb = PCH_UART_HAL_STB1; + + if (termios->c_cflag & PARENB) { + if (!(termios->c_cflag & PARODD)) + parity = PCH_UART_HAL_PARITY_ODD; + else + parity = PCH_UART_HAL_PARITY_EVEN; + + } else { + parity = PCH_UART_HAL_PARITY_NONE; + } + termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + + spin_lock_irqsave(&port->lock, flags); + + uart_update_timeout(port, termios->c_cflag, baud); + rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); + if (rtn) + goto out; + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + +out: + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *pch_uart_type(struct uart_port *port) +{ + return KBUILD_MODNAME; +} + +static void pch_uart_release_port(struct uart_port *port) +{ + struct eg20t_port *priv; + + priv = container_of(port, struct eg20t_port, port); + pci_iounmap(priv->pdev, priv->membase); + pci_release_regions(priv->pdev); +} + +static int pch_uart_request_port(struct uart_port *port) +{ + struct eg20t_port *priv; + int ret; + void __iomem *membase; + + priv = container_of(port, struct eg20t_port, port); + ret = pci_request_regions(priv->pdev, KBUILD_MODNAME); + if (ret < 0) + return -EBUSY; + + membase = pci_iomap(priv->pdev, 1, 0); + if (!membase) { + pci_release_regions(priv->pdev); + return -EBUSY; + } + priv->membase = port->membase = membase; + + return 0; +} + +static void pch_uart_config_port(struct uart_port *port, int type) +{ + struct eg20t_port *priv; + + priv = container_of(port, struct eg20t_port, port); + if (type & UART_CONFIG_TYPE) { + port->type = priv->port_type; + pch_uart_request_port(port); + } +} + +static int pch_uart_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + struct eg20t_port *priv; + + priv = container_of(port, struct eg20t_port, port); + if (serinfo->flags & UPF_LOW_LATENCY) { + pr_info("PCH UART : Use PIO Mode (without DMA)\n"); + priv->use_dma = 0; + serinfo->flags &= ~UPF_LOW_LATENCY; + } else { +#ifndef CONFIG_PCH_DMA + pr_err("%s : PCH DMA is not Loaded.\n", __func__); + return -EOPNOTSUPP; +#endif + priv->use_dma = 1; + priv->use_dma_flag = 1; + pr_info("PCH UART : Use DMA Mode\n"); + } + + return 0; +} + +static struct uart_ops pch_uart_ops = { + .tx_empty = pch_uart_tx_empty, + .set_mctrl = pch_uart_set_mctrl, + .get_mctrl = pch_uart_get_mctrl, + .stop_tx = pch_uart_stop_tx, + .start_tx = pch_uart_start_tx, + .stop_rx = pch_uart_stop_rx, + .enable_ms = pch_uart_enable_ms, + .break_ctl = pch_uart_break_ctl, + .startup = pch_uart_startup, + .shutdown = pch_uart_shutdown, + .set_termios = pch_uart_set_termios, +/* .pm = pch_uart_pm, Not supported yet */ +/* .set_wake = pch_uart_set_wake, Not supported yet */ + .type = pch_uart_type, + .release_port = pch_uart_release_port, + .request_port = pch_uart_request_port, + .config_port = pch_uart_config_port, + .verify_port = pch_uart_verify_port +}; + +static struct uart_driver pch_uart_driver = { + .owner = THIS_MODULE, + .driver_name = KBUILD_MODNAME, + .dev_name = PCH_UART_DRIVER_DEVICE, + .major = 0, + .minor = 0, + .nr = PCH_UART_NR, +}; + +static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, + int port_type) +{ + struct eg20t_port *priv; + int ret; + unsigned int iobase; + unsigned int mapbase; + unsigned char *rxbuf; + int fifosize, base_baud; + static int num; + + priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL); + if (priv == NULL) + goto init_port_alloc_err; + + rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!rxbuf) + goto init_port_free_txbuf; + + switch (port_type) { + case PORT_UNKNOWN: + fifosize = 256; /* UART0 */ + base_baud = 1843200; /* 1.8432MHz */ + break; + case PORT_8250: + fifosize = 64; /* UART1~3 */ + base_baud = 1843200; /* 1.8432MHz */ + break; + default: + dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type); + goto init_port_hal_free; + } + + iobase = pci_resource_start(pdev, 0); + mapbase = pci_resource_start(pdev, 1); + priv->mapbase = mapbase; + priv->iobase = iobase; + priv->pdev = pdev; + priv->tx_empty = 1; + priv->rxbuf.buf = rxbuf; + priv->rxbuf.size = PAGE_SIZE; + + priv->fifo_size = fifosize; + priv->base_baud = base_baud; + priv->port_type = PORT_MAX_8250 + port_type + 1; + priv->port.dev = &pdev->dev; + priv->port.iobase = iobase; + priv->port.membase = NULL; + priv->port.mapbase = mapbase; + priv->port.irq = pdev->irq; + priv->port.iotype = UPIO_PORT; + priv->port.ops = &pch_uart_ops; + priv->port.flags = UPF_BOOT_AUTOCONF; + priv->port.fifosize = fifosize; + priv->port.line = num++; + priv->trigger = PCH_UART_HAL_TRIGGER_M; + + pci_set_drvdata(pdev, priv); + pch_uart_hal_request(pdev, fifosize, base_baud); + ret = uart_add_one_port(&pch_uart_driver, &priv->port); + if (ret < 0) + goto init_port_hal_free; + + return priv; + +init_port_hal_free: + free_page((unsigned long)rxbuf); +init_port_free_txbuf: + kfree(priv); +init_port_alloc_err: + + return NULL; +} + +static void pch_uart_exit_port(struct eg20t_port *priv) +{ + uart_remove_one_port(&pch_uart_driver, &priv->port); + pci_set_drvdata(priv->pdev, NULL); + free_page((unsigned long)priv->rxbuf.buf); +} + +static void pch_uart_pci_remove(struct pci_dev *pdev) +{ + struct eg20t_port *priv; + + priv = (struct eg20t_port *)pci_get_drvdata(pdev); + pch_uart_exit_port(priv); + pci_disable_device(pdev); + kfree(priv); + return; +} +#ifdef CONFIG_PM +static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct eg20t_port *priv = pci_get_drvdata(pdev); + + uart_suspend_port(&pch_uart_driver, &priv->port); + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int pch_uart_pci_resume(struct pci_dev *pdev) +{ + struct eg20t_port *priv = pci_get_drvdata(pdev); + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s-pci_enable_device failed(ret=%d) ", __func__, ret); + return ret; + } + + uart_resume_port(&pch_uart_driver, &priv->port); + + return 0; +} +#else +#define pch_uart_pci_suspend NULL +#define pch_uart_pci_resume NULL +#endif + +static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811), + .driver_data = PCH_UART_8LINE}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812), + .driver_data = PCH_UART_2LINE}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813), + .driver_data = PCH_UART_2LINE}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814), + .driver_data = PCH_UART_2LINE}, + {0,}, +}; + +static int __devinit pch_uart_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + struct eg20t_port *priv; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto probe_error; + + priv = pch_uart_init_port(pdev, id->driver_data); + if (!priv) { + ret = -EBUSY; + goto probe_disable_device; + } + pci_set_drvdata(pdev, priv); + + return ret; + +probe_disable_device: + pci_disable_device(pdev); +probe_error: + return ret; +} + +static struct pci_driver pch_uart_pci_driver = { + .name = "pch_uart", + .id_table = pch_uart_pci_id, + .probe = pch_uart_pci_probe, + .remove = __devexit_p(pch_uart_pci_remove), + .suspend = pch_uart_pci_suspend, + .resume = pch_uart_pci_resume, +}; + +static int __init pch_uart_module_init(void) +{ + int ret; + + /* register as UART driver */ + ret = uart_register_driver(&pch_uart_driver); + if (ret < 0) + return ret; + + /* register as PCI driver */ + ret = pci_register_driver(&pch_uart_pci_driver); + if (ret < 0) + uart_unregister_driver(&pch_uart_driver); + + return ret; +} +module_init(pch_uart_module_init); + +static void __exit pch_uart_module_exit(void) +{ + pci_unregister_driver(&pch_uart_pci_driver); + uart_unregister_driver(&pch_uart_driver); +} +module_exit(pch_uart_module_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); +module_param(default_baud, uint, S_IRUGO); diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c new file mode 100644 index 000000000000..5b9cde79e4ea --- /dev/null +++ b/drivers/tty/serial/pmac_zilog.c @@ -0,0 +1,2208 @@ +/* + * linux/drivers/serial/pmac_zilog.c + * + * Driver for PowerMac Z85c30 based ESCC cell found in the + * "macio" ASICs of various PowerMac models + * + * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * Derived from drivers/macintosh/macserial.c by Paul Mackerras + * and drivers/serial/sunzilog.c by David S. Miller + * + * Hrm... actually, I ripped most of sunzilog (Thanks David !) and + * adapted special tweaks needed for us. I don't think it's worth + * merging back those though. The DMA code still has to get in + * and once done, I expect that driver to remain fairly stable in + * the long term, unless we change the driver model again... + * + * 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 + * + * 2004-08-06 Harald Welte + * - Enable BREAK interrupt + * - Add support for sysreq + * + * TODO: - Add DMA support + * - Defer port shutdown to a few seconds after close + * - maybe put something right into uap->clk_divisor + */ + +#undef DEBUG +#undef DEBUG_HARD +#undef USE_CTRL_O_SYSRQ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PPC_PMAC +#include +#include +#include +#include +#include +#else +#include +#define of_machine_is_compatible(x) (0) +#endif + +#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include + +#include "pmac_zilog.h" + +/* Not yet implemented */ +#undef HAS_DBDMA + +static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt )"; +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports."); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_SERIAL_PMACZILOG_TTYS +#define PMACZILOG_MAJOR TTY_MAJOR +#define PMACZILOG_MINOR 64 +#define PMACZILOG_NAME "ttyS" +#else +#define PMACZILOG_MAJOR 204 +#define PMACZILOG_MINOR 192 +#define PMACZILOG_NAME "ttyPZ" +#endif + + +/* + * For the sake of early serial console, we can do a pre-probe + * (optional) of the ports at rather early boot time. + */ +static struct uart_pmac_port pmz_ports[MAX_ZS_PORTS]; +static int pmz_ports_count; +static DEFINE_MUTEX(pmz_irq_mutex); + +static struct uart_driver pmz_uart_reg = { + .owner = THIS_MODULE, + .driver_name = PMACZILOG_NAME, + .dev_name = PMACZILOG_NAME, + .major = PMACZILOG_MAJOR, + .minor = PMACZILOG_MINOR, +}; + + +/* + * Load all registers to reprogram the port + * This function must only be called when the TX is not busy. The UART + * port lock must be held and local interrupts disabled. + */ +static void pmz_load_zsregs(struct uart_pmac_port *uap, u8 *regs) +{ + int i; + + if (ZS_IS_ASLEEP(uap)) + return; + + /* Let pending transmits finish. */ + for (i = 0; i < 1000; i++) { + unsigned char stat = read_zsreg(uap, R1); + if (stat & ALL_SNT) + break; + udelay(100); + } + + ZS_CLEARERR(uap); + zssync(uap); + ZS_CLEARFIFO(uap); + zssync(uap); + ZS_CLEARERR(uap); + + /* Disable all interrupts. */ + write_zsreg(uap, R1, + regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); + + /* Set parity, sync config, stop bits, and clock divisor. */ + write_zsreg(uap, R4, regs[R4]); + + /* Set misc. TX/RX control bits. */ + write_zsreg(uap, R10, regs[R10]); + + /* Set TX/RX controls sans the enable bits. */ + write_zsreg(uap, R3, regs[R3] & ~RxENABLE); + write_zsreg(uap, R5, regs[R5] & ~TxENABLE); + + /* now set R7 "prime" on ESCC */ + write_zsreg(uap, R15, regs[R15] | EN85C30); + write_zsreg(uap, R7, regs[R7P]); + + /* make sure we use R7 "non-prime" on ESCC */ + write_zsreg(uap, R15, regs[R15] & ~EN85C30); + + /* Synchronous mode config. */ + write_zsreg(uap, R6, regs[R6]); + write_zsreg(uap, R7, regs[R7]); + + /* Disable baud generator. */ + write_zsreg(uap, R14, regs[R14] & ~BRENAB); + + /* Clock mode control. */ + write_zsreg(uap, R11, regs[R11]); + + /* Lower and upper byte of baud rate generator divisor. */ + write_zsreg(uap, R12, regs[R12]); + write_zsreg(uap, R13, regs[R13]); + + /* Now rewrite R14, with BRENAB (if set). */ + write_zsreg(uap, R14, regs[R14]); + + /* Reset external status interrupts. */ + write_zsreg(uap, R0, RES_EXT_INT); + write_zsreg(uap, R0, RES_EXT_INT); + + /* Rewrite R3/R5, this time without enables masked. */ + write_zsreg(uap, R3, regs[R3]); + write_zsreg(uap, R5, regs[R5]); + + /* Rewrite R1, this time without IRQ enabled masked. */ + write_zsreg(uap, R1, regs[R1]); + + /* Enable interrupts */ + write_zsreg(uap, R9, regs[R9]); +} + +/* + * We do like sunzilog to avoid disrupting pending Tx + * Reprogram the Zilog channel HW registers with the copies found in the + * software state struct. If the transmitter is busy, we defer this update + * until the next TX complete interrupt. Else, we do it right now. + * + * The UART port lock must be held and local interrupts disabled. + */ +static void pmz_maybe_update_regs(struct uart_pmac_port *uap) +{ + if (!ZS_REGS_HELD(uap)) { + if (ZS_TX_ACTIVE(uap)) { + uap->flags |= PMACZILOG_FLAG_REGS_HELD; + } else { + pmz_debug("pmz: maybe_update_regs: updating\n"); + pmz_load_zsregs(uap, uap->curregs); + } + } +} + +static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) +{ + struct tty_struct *tty = NULL; + unsigned char ch, r1, drop, error, flag; + int loops = 0; + + /* The interrupt can be enabled when the port isn't open, typically + * that happens when using one port is open and the other closed (stale + * interrupt) or when one port is used as a console. + */ + if (!ZS_IS_OPEN(uap)) { + pmz_debug("pmz: draining input\n"); + /* Port is closed, drain input data */ + for (;;) { + if ((++loops) > 1000) + goto flood; + (void)read_zsreg(uap, R1); + write_zsreg(uap, R0, ERR_RES); + (void)read_zsdata(uap); + ch = read_zsreg(uap, R0); + if (!(ch & Rx_CH_AV)) + break; + } + return NULL; + } + + /* Sanity check, make sure the old bug is no longer happening */ + if (uap->port.state == NULL || uap->port.state->port.tty == NULL) { + WARN_ON(1); + (void)read_zsdata(uap); + return NULL; + } + tty = uap->port.state->port.tty; + + while (1) { + error = 0; + drop = 0; + + r1 = read_zsreg(uap, R1); + ch = read_zsdata(uap); + + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + write_zsreg(uap, R0, ERR_RES); + zssync(uap); + } + + ch &= uap->parity_mask; + if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) { + uap->flags &= ~PMACZILOG_FLAG_BREAK; + } + +#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE) +#ifdef USE_CTRL_O_SYSRQ + /* Handle the SysRq ^O Hack */ + if (ch == '\x0f') { + uap->port.sysrq = jiffies + HZ*5; + goto next_char; + } +#endif /* USE_CTRL_O_SYSRQ */ + if (uap->port.sysrq) { + int swallow; + spin_unlock(&uap->port.lock); + swallow = uart_handle_sysrq_char(&uap->port, ch); + spin_lock(&uap->port.lock); + if (swallow) + goto next_char; + } +#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */ + + /* A real serial line, record the character and status. */ + if (drop) + goto next_char; + + flag = TTY_NORMAL; + uap->port.icount.rx++; + + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) { + error = 1; + if (r1 & BRK_ABRT) { + pmz_debug("pmz: got break !\n"); + r1 &= ~(PAR_ERR | CRC_ERR); + uap->port.icount.brk++; + if (uart_handle_break(&uap->port)) + goto next_char; + } + else if (r1 & PAR_ERR) + uap->port.icount.parity++; + else if (r1 & CRC_ERR) + uap->port.icount.frame++; + if (r1 & Rx_OVR) + uap->port.icount.overrun++; + r1 &= uap->port.read_status_mask; + if (r1 & BRK_ABRT) + flag = TTY_BREAK; + else if (r1 & PAR_ERR) + flag = TTY_PARITY; + else if (r1 & CRC_ERR) + flag = TTY_FRAME; + } + + if (uap->port.ignore_status_mask == 0xff || + (r1 & uap->port.ignore_status_mask) == 0) { + tty_insert_flip_char(tty, ch, flag); + } + if (r1 & Rx_OVR) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + next_char: + /* We can get stuck in an infinite loop getting char 0 when the + * line is in a wrong HW state, we break that here. + * When that happens, I disable the receive side of the driver. + * Note that what I've been experiencing is a real irq loop where + * I'm getting flooded regardless of the actual port speed. + * Something stange is going on with the HW + */ + if ((++loops) > 1000) + goto flood; + ch = read_zsreg(uap, R0); + if (!(ch & Rx_CH_AV)) + break; + } + + return tty; + flood: + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + write_zsreg(uap, R1, uap->curregs[R1]); + zssync(uap); + pmz_error("pmz: rx irq flood !\n"); + return tty; +} + +static void pmz_status_handle(struct uart_pmac_port *uap) +{ + unsigned char status; + + status = read_zsreg(uap, R0); + write_zsreg(uap, R0, RES_EXT_INT); + zssync(uap); + + if (ZS_IS_OPEN(uap) && ZS_WANTS_MODEM_STATUS(uap)) { + if (status & SYNC_HUNT) + uap->port.icount.dsr++; + + /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. + * But it does not tell us which bit has changed, we have to keep + * track of this ourselves. + * The CTS input is inverted for some reason. -- paulus + */ + if ((status ^ uap->prev_status) & DCD) + uart_handle_dcd_change(&uap->port, + (status & DCD)); + if ((status ^ uap->prev_status) & CTS) + uart_handle_cts_change(&uap->port, + !(status & CTS)); + + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + } + + if (status & BRK_ABRT) + uap->flags |= PMACZILOG_FLAG_BREAK; + + uap->prev_status = status; +} + +static void pmz_transmit_chars(struct uart_pmac_port *uap) +{ + struct circ_buf *xmit; + + if (ZS_IS_ASLEEP(uap)) + return; + if (ZS_IS_CONS(uap)) { + unsigned char status = read_zsreg(uap, R0); + + /* TX still busy? Just wait for the next TX done interrupt. + * + * It can occur because of how we do serial console writes. It would + * be nice to transmit console writes just like we normally would for + * a TTY line. (ie. buffered and TX interrupt driven). That is not + * easy because console writes cannot sleep. One solution might be + * to poll on enough port->xmit space becomming free. -DaveM + */ + if (!(status & Tx_BUF_EMP)) + return; + } + + uap->flags &= ~PMACZILOG_FLAG_TX_ACTIVE; + + if (ZS_REGS_HELD(uap)) { + pmz_load_zsregs(uap, uap->curregs); + uap->flags &= ~PMACZILOG_FLAG_REGS_HELD; + } + + if (ZS_TX_STOPPED(uap)) { + uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; + goto ack_tx_int; + } + + /* Under some circumstances, we see interrupts reported for + * a closed channel. The interrupt mask in R1 is clear, but + * R3 still signals the interrupts and we see them when taking + * an interrupt for the other channel (this could be a qemu + * bug but since the ESCC doc doesn't specify precsiely whether + * R3 interrup status bits are masked by R1 interrupt enable + * bits, better safe than sorry). --BenH. + */ + if (!ZS_IS_OPEN(uap)) + goto ack_tx_int; + + if (uap->port.x_char) { + uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; + write_zsdata(uap, uap->port.x_char); + zssync(uap); + uap->port.icount.tx++; + uap->port.x_char = 0; + return; + } + + if (uap->port.state == NULL) + goto ack_tx_int; + xmit = &uap->port.state->xmit; + if (uart_circ_empty(xmit)) { + uart_write_wakeup(&uap->port); + goto ack_tx_int; + } + if (uart_tx_stopped(&uap->port)) + goto ack_tx_int; + + uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; + write_zsdata(uap, xmit->buf[xmit->tail]); + zssync(uap); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uap->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + + return; + +ack_tx_int: + write_zsreg(uap, R0, RES_Tx_P); + zssync(uap); +} + +/* Hrm... we register that twice, fixme later.... */ +static irqreturn_t pmz_interrupt(int irq, void *dev_id) +{ + struct uart_pmac_port *uap = dev_id; + struct uart_pmac_port *uap_a; + struct uart_pmac_port *uap_b; + int rc = IRQ_NONE; + struct tty_struct *tty; + u8 r3; + + uap_a = pmz_get_port_A(uap); + uap_b = uap_a->mate; + + spin_lock(&uap_a->port.lock); + r3 = read_zsreg(uap_a, R3); + +#ifdef DEBUG_HARD + pmz_debug("irq, r3: %x\n", r3); +#endif + /* Channel A */ + tty = NULL; + if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + write_zsreg(uap_a, R0, RES_H_IUS); + zssync(uap_a); + if (r3 & CHAEXT) + pmz_status_handle(uap_a); + if (r3 & CHARxIP) + tty = pmz_receive_chars(uap_a); + if (r3 & CHATxIP) + pmz_transmit_chars(uap_a); + rc = IRQ_HANDLED; + } + spin_unlock(&uap_a->port.lock); + if (tty != NULL) + tty_flip_buffer_push(tty); + + if (uap_b->node == NULL) + goto out; + + spin_lock(&uap_b->port.lock); + tty = NULL; + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + write_zsreg(uap_b, R0, RES_H_IUS); + zssync(uap_b); + if (r3 & CHBEXT) + pmz_status_handle(uap_b); + if (r3 & CHBRxIP) + tty = pmz_receive_chars(uap_b); + if (r3 & CHBTxIP) + pmz_transmit_chars(uap_b); + rc = IRQ_HANDLED; + } + spin_unlock(&uap_b->port.lock); + if (tty != NULL) + tty_flip_buffer_push(tty); + + out: +#ifdef DEBUG_HARD + pmz_debug("irq done.\n"); +#endif + return rc; +} + +/* + * Peek the status register, lock not held by caller + */ +static inline u8 pmz_peek_status(struct uart_pmac_port *uap) +{ + unsigned long flags; + u8 status; + + spin_lock_irqsave(&uap->port.lock, flags); + status = read_zsreg(uap, R0); + spin_unlock_irqrestore(&uap->port.lock, flags); + + return status; +} + +/* + * Check if transmitter is empty + * The port lock is not held. + */ +static unsigned int pmz_tx_empty(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned char status; + + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return TIOCSER_TEMT; + + status = pmz_peek_status(to_pmz(port)); + if (status & Tx_BUF_EMP) + return TIOCSER_TEMT; + return 0; +} + +/* + * Set Modem Control (RTS & DTR) bits + * The port lock is held and interrupts are disabled. + * Note: Shall we really filter out RTS on external ports or + * should that be dealt at higher level only ? + */ +static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned char set_bits, clear_bits; + + /* Do nothing for irda for now... */ + if (ZS_IS_IRDA(uap)) + return; + /* We get called during boot with a port not up yet */ + if (ZS_IS_ASLEEP(uap) || + !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap))) + return; + + set_bits = clear_bits = 0; + + if (ZS_IS_INTMODEM(uap)) { + if (mctrl & TIOCM_RTS) + set_bits |= RTS; + else + clear_bits |= RTS; + } + if (mctrl & TIOCM_DTR) + set_bits |= DTR; + else + clear_bits |= DTR; + + /* NOTE: Not subject to 'transmitter active' rule. */ + uap->curregs[R5] |= set_bits; + uap->curregs[R5] &= ~clear_bits; + if (ZS_IS_ASLEEP(uap)) + return; + write_zsreg(uap, R5, uap->curregs[R5]); + pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n", + set_bits, clear_bits, uap->curregs[R5]); + zssync(uap); +} + +/* + * Get Modem Control bits (only the input ones, the core will + * or that with a cached value of the control ones) + * The port lock is held and interrupts are disabled. + */ +static unsigned int pmz_get_mctrl(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned char status; + unsigned int ret; + + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return 0; + + status = read_zsreg(uap, R0); + + ret = 0; + if (status & DCD) + ret |= TIOCM_CAR; + if (status & SYNC_HUNT) + ret |= TIOCM_DSR; + if (!(status & CTS)) + ret |= TIOCM_CTS; + + return ret; +} + +/* + * Stop TX side. Dealt like sunzilog at next Tx interrupt, + * though for DMA, we will have to do a bit more. + * The port lock is held and interrupts are disabled. + */ +static void pmz_stop_tx(struct uart_port *port) +{ + to_pmz(port)->flags |= PMACZILOG_FLAG_TX_STOPPED; +} + +/* + * Kick the Tx side. + * The port lock is held and interrupts are disabled. + */ +static void pmz_start_tx(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned char status; + + pmz_debug("pmz: start_tx()\n"); + + uap->flags |= PMACZILOG_FLAG_TX_ACTIVE; + uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED; + + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return; + + status = read_zsreg(uap, R0); + + /* TX busy? Just wait for the TX done interrupt. */ + if (!(status & Tx_BUF_EMP)) + return; + + /* Send the first character to jump-start the TX done + * IRQ sending engine. + */ + if (port->x_char) { + write_zsdata(uap, port->x_char); + zssync(uap); + port->icount.tx++; + port->x_char = 0; + } else { + struct circ_buf *xmit = &port->state->xmit; + + write_zsdata(uap, xmit->buf[xmit->tail]); + zssync(uap); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + } + pmz_debug("pmz: start_tx() done.\n"); +} + +/* + * Stop Rx side, basically disable emitting of + * Rx interrupts on the port. We don't disable the rx + * side of the chip proper though + * The port lock is held. + */ +static void pmz_stop_rx(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + + if (ZS_IS_ASLEEP(uap) || uap->node == NULL) + return; + + pmz_debug("pmz: stop_rx()()\n"); + + /* Disable all RX interrupts. */ + uap->curregs[R1] &= ~RxINT_MASK; + pmz_maybe_update_regs(uap); + + pmz_debug("pmz: stop_rx() done.\n"); +} + +/* + * Enable modem status change interrupts + * The port lock is held. + */ +static void pmz_enable_ms(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned char new_reg; + + if (ZS_IS_IRDA(uap) || uap->node == NULL) + return; + new_reg = uap->curregs[R15] | (DCDIE | SYNCIE | CTSIE); + if (new_reg != uap->curregs[R15]) { + uap->curregs[R15] = new_reg; + + if (ZS_IS_ASLEEP(uap)) + return; + /* NOTE: Not subject to 'transmitter active' rule. */ + write_zsreg(uap, R15, uap->curregs[R15]); + } +} + +/* + * Control break state emission + * The port lock is not held. + */ +static void pmz_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned char set_bits, clear_bits, new_reg; + unsigned long flags; + + if (uap->node == NULL) + return; + set_bits = clear_bits = 0; + + if (break_state) + set_bits |= SND_BRK; + else + clear_bits |= SND_BRK; + + spin_lock_irqsave(&port->lock, flags); + + new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != uap->curregs[R5]) { + uap->curregs[R5] = new_reg; + + /* NOTE: Not subject to 'transmitter active' rule. */ + if (ZS_IS_ASLEEP(uap)) { + spin_unlock_irqrestore(&port->lock, flags); + return; + } + write_zsreg(uap, R5, uap->curregs[R5]); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +#ifdef CONFIG_PPC_PMAC + +/* + * Turn power on or off to the SCC and associated stuff + * (port drivers, modem, IR port, etc.) + * Returns the number of milliseconds we should wait before + * trying to use the port. + */ +static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) +{ + int delay = 0; + int rc; + + if (state) { + rc = pmac_call_feature( + PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1); + pmz_debug("port power on result: %d\n", rc); + if (ZS_IS_INTMODEM(uap)) { + rc = pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1); + delay = 2500; /* wait for 2.5s before using */ + pmz_debug("modem power result: %d\n", rc); + } + } else { + /* TODO: Make that depend on a timer, don't power down + * immediately + */ + if (ZS_IS_INTMODEM(uap)) { + rc = pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0); + pmz_debug("port power off result: %d\n", rc); + } + pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0); + } + return delay; +} + +#else + +static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) +{ + return 0; +} + +#endif /* !CONFIG_PPC_PMAC */ + +/* + * FixZeroBug....Works around a bug in the SCC receving channel. + * Inspired from Darwin code, 15 Sept. 2000 -DanM + * + * The following sequence prevents a problem that is seen with O'Hare ASICs + * (most versions -- also with some Heathrow and Hydra ASICs) where a zero + * at the input to the receiver becomes 'stuck' and locks up the receiver. + * This problem can occur as a result of a zero bit at the receiver input + * coincident with any of the following events: + * + * The SCC is initialized (hardware or software). + * A framing error is detected. + * The clocking option changes from synchronous or X1 asynchronous + * clocking to X16, X32, or X64 asynchronous clocking. + * The decoding mode is changed among NRZ, NRZI, FM0, or FM1. + * + * This workaround attempts to recover from the lockup condition by placing + * the SCC in synchronous loopback mode with a fast clock before programming + * any of the asynchronous modes. + */ +static void pmz_fix_zero_bug_scc(struct uart_pmac_port *uap) +{ + write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); + zssync(uap); + udelay(10); + write_zsreg(uap, 9, (ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB) | NV); + zssync(uap); + + write_zsreg(uap, 4, X1CLK | MONSYNC); + write_zsreg(uap, 3, Rx8); + write_zsreg(uap, 5, Tx8 | RTS); + write_zsreg(uap, 9, NV); /* Didn't we already do this? */ + write_zsreg(uap, 11, RCBR | TCBR); + write_zsreg(uap, 12, 0); + write_zsreg(uap, 13, 0); + write_zsreg(uap, 14, (LOOPBAK | BRSRC)); + write_zsreg(uap, 14, (LOOPBAK | BRSRC | BRENAB)); + write_zsreg(uap, 3, Rx8 | RxENABLE); + write_zsreg(uap, 0, RES_EXT_INT); + write_zsreg(uap, 0, RES_EXT_INT); + write_zsreg(uap, 0, RES_EXT_INT); /* to kill some time */ + + /* The channel should be OK now, but it is probably receiving + * loopback garbage. + * Switch to asynchronous mode, disable the receiver, + * and discard everything in the receive buffer. + */ + write_zsreg(uap, 9, NV); + write_zsreg(uap, 4, X16CLK | SB_MASK); + write_zsreg(uap, 3, Rx8); + + while (read_zsreg(uap, 0) & Rx_CH_AV) { + (void)read_zsreg(uap, 8); + write_zsreg(uap, 0, RES_EXT_INT); + write_zsreg(uap, 0, ERR_RES); + } +} + +/* + * Real startup routine, powers up the hardware and sets up + * the SCC. Returns a delay in ms where you need to wait before + * actually using the port, this is typically the internal modem + * powerup delay. This routine expect the lock to be taken. + */ +static int __pmz_startup(struct uart_pmac_port *uap) +{ + int pwr_delay = 0; + + memset(&uap->curregs, 0, sizeof(uap->curregs)); + + /* Power up the SCC & underlying hardware (modem/irda) */ + pwr_delay = pmz_set_scc_power(uap, 1); + + /* Nice buggy HW ... */ + pmz_fix_zero_bug_scc(uap); + + /* Reset the channel */ + uap->curregs[R9] = 0; + write_zsreg(uap, 9, ZS_IS_CHANNEL_A(uap) ? CHRA : CHRB); + zssync(uap); + udelay(10); + write_zsreg(uap, 9, 0); + zssync(uap); + + /* Clear the interrupt registers */ + write_zsreg(uap, R1, 0); + write_zsreg(uap, R0, ERR_RES); + write_zsreg(uap, R0, ERR_RES); + write_zsreg(uap, R0, RES_H_IUS); + write_zsreg(uap, R0, RES_H_IUS); + + /* Setup some valid baud rate */ + uap->curregs[R4] = X16CLK | SB1; + uap->curregs[R3] = Rx8; + uap->curregs[R5] = Tx8 | RTS; + if (!ZS_IS_IRDA(uap)) + uap->curregs[R5] |= DTR; + uap->curregs[R12] = 0; + uap->curregs[R13] = 0; + uap->curregs[R14] = BRENAB; + + /* Clear handshaking, enable BREAK interrupts */ + uap->curregs[R15] = BRKIE; + + /* Master interrupt enable */ + uap->curregs[R9] |= NV | MIE; + + pmz_load_zsregs(uap, uap->curregs); + + /* Enable receiver and transmitter. */ + write_zsreg(uap, R3, uap->curregs[R3] |= RxENABLE); + write_zsreg(uap, R5, uap->curregs[R5] |= TxENABLE); + + /* Remember status for DCD/CTS changes */ + uap->prev_status = read_zsreg(uap, R0); + + return pwr_delay; +} + +static void pmz_irda_reset(struct uart_pmac_port *uap) +{ + uap->curregs[R5] |= DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + mdelay(110); + uap->curregs[R5] &= ~DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + mdelay(10); +} + +/* + * This is the "normal" startup routine, using the above one + * wrapped with the lock and doing a schedule delay + */ +static int pmz_startup(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned long flags; + int pwr_delay = 0; + + pmz_debug("pmz: startup()\n"); + + if (ZS_IS_ASLEEP(uap)) + return -EAGAIN; + if (uap->node == NULL) + return -ENODEV; + + mutex_lock(&pmz_irq_mutex); + + uap->flags |= PMACZILOG_FLAG_IS_OPEN; + + /* A console is never powered down. Else, power up and + * initialize the chip + */ + if (!ZS_IS_CONS(uap)) { + spin_lock_irqsave(&port->lock, flags); + pwr_delay = __pmz_startup(uap); + spin_unlock_irqrestore(&port->lock, flags); + } + + pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; + if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, + "SCC", uap)) { + pmz_error("Unable to register zs interrupt handler.\n"); + pmz_set_scc_power(uap, 0); + mutex_unlock(&pmz_irq_mutex); + return -ENXIO; + } + + mutex_unlock(&pmz_irq_mutex); + + /* Right now, we deal with delay by blocking here, I'll be + * smarter later on + */ + if (pwr_delay != 0) { + pmz_debug("pmz: delaying %d ms\n", pwr_delay); + msleep(pwr_delay); + } + + /* IrDA reset is done now */ + if (ZS_IS_IRDA(uap)) + pmz_irda_reset(uap); + + /* Enable interrupts emission from the chip */ + spin_lock_irqsave(&port->lock, flags); + uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[R1] |= EXT_INT_ENAB; + write_zsreg(uap, R1, uap->curregs[R1]); + spin_unlock_irqrestore(&port->lock, flags); + + pmz_debug("pmz: startup() done.\n"); + + return 0; +} + +static void pmz_shutdown(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned long flags; + + pmz_debug("pmz: shutdown()\n"); + + if (uap->node == NULL) + return; + + mutex_lock(&pmz_irq_mutex); + + /* Release interrupt handler */ + free_irq(uap->port.irq, uap); + + spin_lock_irqsave(&port->lock, flags); + + uap->flags &= ~PMACZILOG_FLAG_IS_OPEN; + + if (!ZS_IS_OPEN(uap->mate)) + pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; + + /* Disable interrupts */ + if (!ZS_IS_ASLEEP(uap)) { + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + write_zsreg(uap, R1, uap->curregs[R1]); + zssync(uap); + } + + if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) { + spin_unlock_irqrestore(&port->lock, flags); + mutex_unlock(&pmz_irq_mutex); + return; + } + + /* Disable receiver and transmitter. */ + uap->curregs[R3] &= ~RxENABLE; + uap->curregs[R5] &= ~TxENABLE; + + /* Disable all interrupts and BRK assertion. */ + uap->curregs[R5] &= ~SND_BRK; + pmz_maybe_update_regs(uap); + + /* Shut the chip down */ + pmz_set_scc_power(uap, 0); + + spin_unlock_irqrestore(&port->lock, flags); + + mutex_unlock(&pmz_irq_mutex); + + pmz_debug("pmz: shutdown() done.\n"); +} + +/* Shared by TTY driver and serial console setup. The port lock is held + * and local interrupts are disabled. + */ +static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, + unsigned int iflag, unsigned long baud) +{ + int brg; + + /* Switch to external clocking for IrDA high clock rates. That + * code could be re-used for Midi interfaces with different + * multipliers + */ + if (baud >= 115200 && ZS_IS_IRDA(uap)) { + uap->curregs[R4] = X1CLK; + uap->curregs[R11] = RCTRxCP | TCTRxCP; + uap->curregs[R14] = 0; /* BRG off */ + uap->curregs[R12] = 0; + uap->curregs[R13] = 0; + uap->flags |= PMACZILOG_FLAG_IS_EXTCLK; + } else { + switch (baud) { + case ZS_CLOCK/16: /* 230400 */ + uap->curregs[R4] = X16CLK; + uap->curregs[R11] = 0; + uap->curregs[R14] = 0; + break; + case ZS_CLOCK/32: /* 115200 */ + uap->curregs[R4] = X32CLK; + uap->curregs[R11] = 0; + uap->curregs[R14] = 0; + break; + default: + uap->curregs[R4] = X16CLK; + uap->curregs[R11] = TCBR | RCBR; + brg = BPS_TO_BRG(baud, ZS_CLOCK / 16); + uap->curregs[R12] = (brg & 255); + uap->curregs[R13] = ((brg >> 8) & 255); + uap->curregs[R14] = BRENAB; + } + uap->flags &= ~PMACZILOG_FLAG_IS_EXTCLK; + } + + /* Character size, stop bits, and parity. */ + uap->curregs[3] &= ~RxN_MASK; + uap->curregs[5] &= ~TxN_MASK; + + switch (cflag & CSIZE) { + case CS5: + uap->curregs[3] |= Rx5; + uap->curregs[5] |= Tx5; + uap->parity_mask = 0x1f; + break; + case CS6: + uap->curregs[3] |= Rx6; + uap->curregs[5] |= Tx6; + uap->parity_mask = 0x3f; + break; + case CS7: + uap->curregs[3] |= Rx7; + uap->curregs[5] |= Tx7; + uap->parity_mask = 0x7f; + break; + case CS8: + default: + uap->curregs[3] |= Rx8; + uap->curregs[5] |= Tx8; + uap->parity_mask = 0xff; + break; + }; + uap->curregs[4] &= ~(SB_MASK); + if (cflag & CSTOPB) + uap->curregs[4] |= SB2; + else + uap->curregs[4] |= SB1; + if (cflag & PARENB) + uap->curregs[4] |= PAR_ENAB; + else + uap->curregs[4] &= ~PAR_ENAB; + if (!(cflag & PARODD)) + uap->curregs[4] |= PAR_EVEN; + else + uap->curregs[4] &= ~PAR_EVEN; + + uap->port.read_status_mask = Rx_OVR; + if (iflag & INPCK) + uap->port.read_status_mask |= CRC_ERR | PAR_ERR; + if (iflag & (BRKINT | PARMRK)) + uap->port.read_status_mask |= BRK_ABRT; + + uap->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + uap->port.ignore_status_mask |= CRC_ERR | PAR_ERR; + if (iflag & IGNBRK) { + uap->port.ignore_status_mask |= BRK_ABRT; + if (iflag & IGNPAR) + uap->port.ignore_status_mask |= Rx_OVR; + } + + if ((cflag & CREAD) == 0) + uap->port.ignore_status_mask = 0xff; +} + + +/* + * Set the irda codec on the imac to the specified baud rate. + */ +static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud) +{ + u8 cmdbyte; + int t, version; + + switch (*baud) { + /* SIR modes */ + case 2400: + cmdbyte = 0x53; + break; + case 4800: + cmdbyte = 0x52; + break; + case 9600: + cmdbyte = 0x51; + break; + case 19200: + cmdbyte = 0x50; + break; + case 38400: + cmdbyte = 0x4f; + break; + case 57600: + cmdbyte = 0x4e; + break; + case 115200: + cmdbyte = 0x4d; + break; + /* The FIR modes aren't really supported at this point, how + * do we select the speed ? via the FCR on KeyLargo ? + */ + case 1152000: + cmdbyte = 0; + break; + case 4000000: + cmdbyte = 0; + break; + default: /* 9600 */ + cmdbyte = 0x51; + *baud = 9600; + break; + } + + /* Wait for transmitter to drain */ + t = 10000; + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0 + || (read_zsreg(uap, R1) & ALL_SNT) == 0) { + if (--t <= 0) { + pmz_error("transmitter didn't drain\n"); + return; + } + udelay(10); + } + + /* Drain the receiver too */ + t = 100; + (void)read_zsdata(uap); + (void)read_zsdata(uap); + (void)read_zsdata(uap); + mdelay(10); + while (read_zsreg(uap, R0) & Rx_CH_AV) { + read_zsdata(uap); + mdelay(10); + if (--t <= 0) { + pmz_error("receiver didn't drain\n"); + return; + } + } + + /* Switch to command mode */ + uap->curregs[R5] |= DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + mdelay(1); + + /* Switch SCC to 19200 */ + pmz_convert_to_zs(uap, CS8, 0, 19200); + pmz_load_zsregs(uap, uap->curregs); + mdelay(1); + + /* Write get_version command byte */ + write_zsdata(uap, 1); + t = 5000; + while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { + if (--t <= 0) { + pmz_error("irda_setup timed out on get_version byte\n"); + goto out; + } + udelay(10); + } + version = read_zsdata(uap); + + if (version < 4) { + pmz_info("IrDA: dongle version %d not supported\n", version); + goto out; + } + + /* Send speed mode */ + write_zsdata(uap, cmdbyte); + t = 5000; + while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) { + if (--t <= 0) { + pmz_error("irda_setup timed out on speed mode byte\n"); + goto out; + } + udelay(10); + } + t = read_zsdata(uap); + if (t != cmdbyte) + pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte); + + pmz_info("IrDA setup for %ld bps, dongle version: %d\n", + *baud, version); + + (void)read_zsdata(uap); + (void)read_zsdata(uap); + (void)read_zsdata(uap); + + out: + /* Switch back to data mode */ + uap->curregs[R5] &= ~DTR; + write_zsreg(uap, R5, uap->curregs[R5]); + zssync(uap); + + (void)read_zsdata(uap); + (void)read_zsdata(uap); + (void)read_zsdata(uap); +} + + +static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned long baud; + + pmz_debug("pmz: set_termios()\n"); + + if (ZS_IS_ASLEEP(uap)) + return; + + memcpy(&uap->termios_cache, termios, sizeof(struct ktermios)); + + /* XXX Check which revs of machines actually allow 1 and 4Mb speeds + * on the IR dongle. Note that the IRTTY driver currently doesn't know + * about the FIR mode and high speed modes. So these are unused. For + * implementing proper support for these, we should probably add some + * DMA as well, at least on the Rx side, which isn't a simple thing + * at this point. + */ + if (ZS_IS_IRDA(uap)) { + /* Calc baud rate */ + baud = uart_get_baud_rate(port, termios, old, 1200, 4000000); + pmz_debug("pmz: switch IRDA to %ld bauds\n", baud); + /* Cet the irda codec to the right rate */ + pmz_irda_setup(uap, &baud); + /* Set final baud rate */ + pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud); + pmz_load_zsregs(uap, uap->curregs); + zssync(uap); + } else { + baud = uart_get_baud_rate(port, termios, old, 1200, 230400); + pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud); + /* Make sure modem status interrupts are correctly configured */ + if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) { + uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE; + uap->flags |= PMACZILOG_FLAG_MODEM_STATUS; + } else { + uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE); + uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS; + } + + /* Load registers to the chip */ + pmz_maybe_update_regs(uap); + } + uart_update_timeout(port, termios->c_cflag, baud); + + pmz_debug("pmz: set_termios() done.\n"); +} + +/* The port lock is not held. */ +static void pmz_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_pmac_port *uap = to_pmz(port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* Disable IRQs on the port */ + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + write_zsreg(uap, R1, uap->curregs[R1]); + + /* Setup new port configuration */ + __pmz_set_termios(port, termios, old); + + /* Re-enable IRQs on the port */ + if (ZS_IS_OPEN(uap)) { + uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[R1] |= EXT_INT_ENAB; + write_zsreg(uap, R1, uap->curregs[R1]); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *pmz_type(struct uart_port *port) +{ + struct uart_pmac_port *uap = to_pmz(port); + + if (ZS_IS_IRDA(uap)) + return "Z85c30 ESCC - Infrared port"; + else if (ZS_IS_INTMODEM(uap)) + return "Z85c30 ESCC - Internal modem"; + return "Z85c30 ESCC - Serial port"; +} + +/* We do not request/release mappings of the registers here, this + * happens at early serial probe time. + */ +static void pmz_release_port(struct uart_port *port) +{ +} + +static int pmz_request_port(struct uart_port *port) +{ + return 0; +} + +/* These do not need to do anything interesting either. */ +static void pmz_config_port(struct uart_port *port, int flags) +{ +} + +/* We do not support letting the user mess with the divisor, IRQ, etc. */ +static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +#ifdef CONFIG_CONSOLE_POLL + +static int pmz_poll_get_char(struct uart_port *port) +{ + struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + + while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) + udelay(5); + return read_zsdata(uap); +} + +static void pmz_poll_put_char(struct uart_port *port, unsigned char c) +{ + struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + + /* Wait for the transmit buffer to empty. */ + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) + udelay(5); + write_zsdata(uap, c); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +static struct uart_ops pmz_pops = { + .tx_empty = pmz_tx_empty, + .set_mctrl = pmz_set_mctrl, + .get_mctrl = pmz_get_mctrl, + .stop_tx = pmz_stop_tx, + .start_tx = pmz_start_tx, + .stop_rx = pmz_stop_rx, + .enable_ms = pmz_enable_ms, + .break_ctl = pmz_break_ctl, + .startup = pmz_startup, + .shutdown = pmz_shutdown, + .set_termios = pmz_set_termios, + .type = pmz_type, + .release_port = pmz_release_port, + .request_port = pmz_request_port, + .config_port = pmz_config_port, + .verify_port = pmz_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = pmz_poll_get_char, + .poll_put_char = pmz_poll_put_char, +#endif +}; + +#ifdef CONFIG_PPC_PMAC + +/* + * Setup one port structure after probing, HW is down at this point, + * Unlike sunzilog, we don't need to pre-init the spinlock as we don't + * register our console before uart_add_one_port() is called + */ +static int __init pmz_init_port(struct uart_pmac_port *uap) +{ + struct device_node *np = uap->node; + const char *conn; + const struct slot_names_prop { + int count; + char name[1]; + } *slots; + int len; + struct resource r_ports, r_rxdma, r_txdma; + + /* + * Request & map chip registers + */ + if (of_address_to_resource(np, 0, &r_ports)) + return -ENODEV; + uap->port.mapbase = r_ports.start; + uap->port.membase = ioremap(uap->port.mapbase, 0x1000); + + uap->control_reg = uap->port.membase; + uap->data_reg = uap->control_reg + 0x10; + + /* + * Request & map DBDMA registers + */ +#ifdef HAS_DBDMA + if (of_address_to_resource(np, 1, &r_txdma) == 0 && + of_address_to_resource(np, 2, &r_rxdma) == 0) + uap->flags |= PMACZILOG_FLAG_HAS_DMA; +#else + memset(&r_txdma, 0, sizeof(struct resource)); + memset(&r_rxdma, 0, sizeof(struct resource)); +#endif + if (ZS_HAS_DMA(uap)) { + uap->tx_dma_regs = ioremap(r_txdma.start, 0x100); + if (uap->tx_dma_regs == NULL) { + uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; + goto no_dma; + } + uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100); + if (uap->rx_dma_regs == NULL) { + iounmap(uap->tx_dma_regs); + uap->tx_dma_regs = NULL; + uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; + goto no_dma; + } + uap->tx_dma_irq = irq_of_parse_and_map(np, 1); + uap->rx_dma_irq = irq_of_parse_and_map(np, 2); + } +no_dma: + + /* + * Detect port type + */ + if (of_device_is_compatible(np, "cobalt")) + uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; + conn = of_get_property(np, "AAPL,connector", &len); + if (conn && (strcmp(conn, "infrared") == 0)) + uap->flags |= PMACZILOG_FLAG_IS_IRDA; + uap->port_type = PMAC_SCC_ASYNC; + /* 1999 Powerbook G3 has slot-names property instead */ + slots = of_get_property(np, "slot-names", &len); + if (slots && slots->count > 0) { + if (strcmp(slots->name, "IrDA") == 0) + uap->flags |= PMACZILOG_FLAG_IS_IRDA; + else if (strcmp(slots->name, "Modem") == 0) + uap->flags |= PMACZILOG_FLAG_IS_INTMODEM; + } + if (ZS_IS_IRDA(uap)) + uap->port_type = PMAC_SCC_IRDA; + if (ZS_IS_INTMODEM(uap)) { + struct device_node* i2c_modem = + of_find_node_by_name(NULL, "i2c-modem"); + if (i2c_modem) { + const char* mid = + of_get_property(i2c_modem, "modem-id", NULL); + if (mid) switch(*mid) { + case 0x04 : + case 0x05 : + case 0x07 : + case 0x08 : + case 0x0b : + case 0x0c : + uap->port_type = PMAC_SCC_I2S1; + } + printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n", + mid ? (*mid) : 0); + of_node_put(i2c_modem); + } else { + printk(KERN_INFO "pmac_zilog: serial modem detected\n"); + } + } + + /* + * Init remaining bits of "port" structure + */ + uap->port.iotype = UPIO_MEM; + uap->port.irq = irq_of_parse_and_map(np, 0); + uap->port.uartclk = ZS_CLOCK; + uap->port.fifosize = 1; + uap->port.ops = &pmz_pops; + uap->port.type = PORT_PMAC_ZILOG; + uap->port.flags = 0; + + /* + * Fixup for the port on Gatwick for which the device-tree has + * missing interrupts. Normally, the macio_dev would contain + * fixed up interrupt info, but we use the device-tree directly + * here due to early probing so we need the fixup too. + */ + if (uap->port.irq == NO_IRQ && + np->parent && np->parent->parent && + of_device_is_compatible(np->parent->parent, "gatwick")) { + /* IRQs on gatwick are offset by 64 */ + uap->port.irq = irq_create_mapping(NULL, 64 + 15); + uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4); + uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5); + } + + /* Setup some valid baud rate information in the register + * shadows so we don't write crap there before baud rate is + * first initialized. + */ + pmz_convert_to_zs(uap, CS8, 0, 9600); + + return 0; +} + +/* + * Get rid of a port on module removal + */ +static void pmz_dispose_port(struct uart_pmac_port *uap) +{ + struct device_node *np; + + np = uap->node; + iounmap(uap->rx_dma_regs); + iounmap(uap->tx_dma_regs); + iounmap(uap->control_reg); + uap->node = NULL; + of_node_put(np); + memset(uap, 0, sizeof(struct uart_pmac_port)); +} + +/* + * Called upon match with an escc node in the device-tree. + */ +static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) +{ + int i; + + /* Iterate the pmz_ports array to find a matching entry + */ + for (i = 0; i < MAX_ZS_PORTS; i++) + if (pmz_ports[i].node == mdev->ofdev.dev.of_node) { + struct uart_pmac_port *uap = &pmz_ports[i]; + + uap->dev = mdev; + dev_set_drvdata(&mdev->ofdev.dev, uap); + if (macio_request_resources(uap->dev, "pmac_zilog")) + printk(KERN_WARNING "%s: Failed to request resource" + ", port still active\n", + uap->node->name); + else + uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; + return 0; + } + return -ENODEV; +} + +/* + * That one should not be called, macio isn't really a hotswap device, + * we don't expect one of those serial ports to go away... + */ +static int pmz_detach(struct macio_dev *mdev) +{ + struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); + + if (!uap) + return -ENODEV; + + if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) { + macio_release_resources(uap->dev); + uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED; + } + dev_set_drvdata(&mdev->ofdev.dev, NULL); + uap->dev = NULL; + + return 0; +} + + +static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) +{ + struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); + struct uart_state *state; + unsigned long flags; + + if (uap == NULL) { + printk("HRM... pmz_suspend with NULL uap\n"); + return 0; + } + + if (pm_state.event == mdev->ofdev.dev.power.power_state.event) + return 0; + + pmz_debug("suspend, switching to state %d\n", pm_state.event); + + state = pmz_uart_reg.state + uap->port.line; + + mutex_lock(&pmz_irq_mutex); + mutex_lock(&state->port.mutex); + + spin_lock_irqsave(&uap->port.lock, flags); + + if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) { + /* Disable receiver and transmitter. */ + uap->curregs[R3] &= ~RxENABLE; + uap->curregs[R5] &= ~TxENABLE; + + /* Disable all interrupts and BRK assertion. */ + uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + uap->curregs[R5] &= ~SND_BRK; + pmz_load_zsregs(uap, uap->curregs); + uap->flags |= PMACZILOG_FLAG_IS_ASLEEP; + mb(); + } + + spin_unlock_irqrestore(&uap->port.lock, flags); + + if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate)) + if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { + pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON; + disable_irq(uap->port.irq); + } + + if (ZS_IS_CONS(uap)) + uap->port.cons->flags &= ~CON_ENABLED; + + /* Shut the chip down */ + pmz_set_scc_power(uap, 0); + + mutex_unlock(&state->port.mutex); + mutex_unlock(&pmz_irq_mutex); + + pmz_debug("suspend, switching complete\n"); + + mdev->ofdev.dev.power.power_state = pm_state; + + return 0; +} + + +static int pmz_resume(struct macio_dev *mdev) +{ + struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev); + struct uart_state *state; + unsigned long flags; + int pwr_delay = 0; + + if (uap == NULL) + return 0; + + if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON) + return 0; + + pmz_debug("resume, switching to state 0\n"); + + state = pmz_uart_reg.state + uap->port.line; + + mutex_lock(&pmz_irq_mutex); + mutex_lock(&state->port.mutex); + + spin_lock_irqsave(&uap->port.lock, flags); + if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) { + spin_unlock_irqrestore(&uap->port.lock, flags); + goto bail; + } + pwr_delay = __pmz_startup(uap); + + /* Take care of config that may have changed while asleep */ + __pmz_set_termios(&uap->port, &uap->termios_cache, NULL); + + if (ZS_IS_OPEN(uap)) { + /* Enable interrupts */ + uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB; + if (!ZS_IS_EXTCLK(uap)) + uap->curregs[R1] |= EXT_INT_ENAB; + write_zsreg(uap, R1, uap->curregs[R1]); + } + + spin_unlock_irqrestore(&uap->port.lock, flags); + + if (ZS_IS_CONS(uap)) + uap->port.cons->flags |= CON_ENABLED; + + /* Re-enable IRQ on the controller */ + if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) { + pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON; + enable_irq(uap->port.irq); + } + + bail: + mutex_unlock(&state->port.mutex); + mutex_unlock(&pmz_irq_mutex); + + /* Right now, we deal with delay by blocking here, I'll be + * smarter later on + */ + if (pwr_delay != 0) { + pmz_debug("pmz: delaying %d ms\n", pwr_delay); + msleep(pwr_delay); + } + + pmz_debug("resume, switching complete\n"); + + mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON; + + return 0; +} + +/* + * Probe all ports in the system and build the ports array, we register + * with the serial layer at this point, the macio-type probing is only + * used later to "attach" to the sysfs tree so we get power management + * events + */ +static int __init pmz_probe(void) +{ + struct device_node *node_p, *node_a, *node_b, *np; + int count = 0; + int rc; + + /* + * Find all escc chips in the system + */ + node_p = of_find_node_by_name(NULL, "escc"); + while (node_p) { + /* + * First get channel A/B node pointers + * + * TODO: Add routines with proper locking to do that... + */ + node_a = node_b = NULL; + for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) { + if (strncmp(np->name, "ch-a", 4) == 0) + node_a = of_node_get(np); + else if (strncmp(np->name, "ch-b", 4) == 0) + node_b = of_node_get(np); + } + if (!node_a && !node_b) { + of_node_put(node_a); + of_node_put(node_b); + printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n", + (!node_a) ? 'a' : 'b', node_p->full_name); + goto next; + } + + /* + * Fill basic fields in the port structures + */ + pmz_ports[count].mate = &pmz_ports[count+1]; + pmz_ports[count+1].mate = &pmz_ports[count]; + pmz_ports[count].flags = PMACZILOG_FLAG_IS_CHANNEL_A; + pmz_ports[count].node = node_a; + pmz_ports[count+1].node = node_b; + pmz_ports[count].port.line = count; + pmz_ports[count+1].port.line = count+1; + + /* + * Setup the ports for real + */ + rc = pmz_init_port(&pmz_ports[count]); + if (rc == 0 && node_b != NULL) + rc = pmz_init_port(&pmz_ports[count+1]); + if (rc != 0) { + of_node_put(node_a); + of_node_put(node_b); + memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port)); + memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port)); + goto next; + } + count += 2; +next: + node_p = of_find_node_by_name(node_p, "escc"); + } + pmz_ports_count = count; + + return 0; +} + +#else + +extern struct platform_device scc_a_pdev, scc_b_pdev; + +static int __init pmz_init_port(struct uart_pmac_port *uap) +{ + struct resource *r_ports; + int irq; + + r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0); + irq = platform_get_irq(uap->node, 0); + if (!r_ports || !irq) + return -ENODEV; + + uap->port.mapbase = r_ports->start; + uap->port.membase = (unsigned char __iomem *) r_ports->start; + uap->port.iotype = UPIO_MEM; + uap->port.irq = irq; + uap->port.uartclk = ZS_CLOCK; + uap->port.fifosize = 1; + uap->port.ops = &pmz_pops; + uap->port.type = PORT_PMAC_ZILOG; + uap->port.flags = 0; + + uap->control_reg = uap->port.membase; + uap->data_reg = uap->control_reg + 4; + uap->port_type = 0; + + pmz_convert_to_zs(uap, CS8, 0, 9600); + + return 0; +} + +static int __init pmz_probe(void) +{ + int err; + + pmz_ports_count = 0; + + pmz_ports[0].mate = &pmz_ports[1]; + pmz_ports[0].port.line = 0; + pmz_ports[0].flags = PMACZILOG_FLAG_IS_CHANNEL_A; + pmz_ports[0].node = &scc_a_pdev; + err = pmz_init_port(&pmz_ports[0]); + if (err) + return err; + pmz_ports_count++; + + pmz_ports[1].mate = &pmz_ports[0]; + pmz_ports[1].port.line = 1; + pmz_ports[1].flags = 0; + pmz_ports[1].node = &scc_b_pdev; + err = pmz_init_port(&pmz_ports[1]); + if (err) + return err; + pmz_ports_count++; + + return 0; +} + +static void pmz_dispose_port(struct uart_pmac_port *uap) +{ + memset(uap, 0, sizeof(struct uart_pmac_port)); +} + +static int __init pmz_attach(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < pmz_ports_count; i++) + if (pmz_ports[i].node == pdev) + return 0; + return -ENODEV; +} + +static int __exit pmz_detach(struct platform_device *pdev) +{ + return 0; +} + +#endif /* !CONFIG_PPC_PMAC */ + +#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE + +static void pmz_console_write(struct console *con, const char *s, unsigned int count); +static int __init pmz_console_setup(struct console *co, char *options); + +static struct console pmz_console = { + .name = PMACZILOG_NAME, + .write = pmz_console_write, + .device = uart_console_device, + .setup = pmz_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &pmz_uart_reg, +}; + +#define PMACZILOG_CONSOLE &pmz_console +#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ +#define PMACZILOG_CONSOLE (NULL) +#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ + +/* + * Register the driver, console driver and ports with the serial + * core + */ +static int __init pmz_register(void) +{ + int i, rc; + + pmz_uart_reg.nr = pmz_ports_count; + pmz_uart_reg.cons = PMACZILOG_CONSOLE; + + /* + * Register this driver with the serial core + */ + rc = uart_register_driver(&pmz_uart_reg); + if (rc) + return rc; + + /* + * Register each port with the serial core + */ + for (i = 0; i < pmz_ports_count; i++) { + struct uart_pmac_port *uport = &pmz_ports[i]; + /* NULL node may happen on wallstreet */ + if (uport->node != NULL) + rc = uart_add_one_port(&pmz_uart_reg, &uport->port); + if (rc) + goto err_out; + } + + return 0; +err_out: + while (i-- > 0) { + struct uart_pmac_port *uport = &pmz_ports[i]; + uart_remove_one_port(&pmz_uart_reg, &uport->port); + } + uart_unregister_driver(&pmz_uart_reg); + return rc; +} + +#ifdef CONFIG_PPC_PMAC + +static struct of_device_id pmz_match[] = +{ + { + .name = "ch-a", + }, + { + .name = "ch-b", + }, + {}, +}; +MODULE_DEVICE_TABLE (of, pmz_match); + +static struct macio_driver pmz_driver = { + .driver = { + .name = "pmac_zilog", + .owner = THIS_MODULE, + .of_match_table = pmz_match, + }, + .probe = pmz_attach, + .remove = pmz_detach, + .suspend = pmz_suspend, + .resume = pmz_resume, +}; + +#else + +static struct platform_driver pmz_driver = { + .remove = __exit_p(pmz_detach), + .driver = { + .name = "scc", + .owner = THIS_MODULE, + }, +}; + +#endif /* !CONFIG_PPC_PMAC */ + +static int __init init_pmz(void) +{ + int rc, i; + printk(KERN_INFO "%s\n", version); + + /* + * First, we need to do a direct OF-based probe pass. We + * do that because we want serial console up before the + * macio stuffs calls us back, and since that makes it + * easier to pass the proper number of channels to + * uart_register_driver() + */ + if (pmz_ports_count == 0) + pmz_probe(); + + /* + * Bail early if no port found + */ + if (pmz_ports_count == 0) + return -ENODEV; + + /* + * Now we register with the serial layer + */ + rc = pmz_register(); + if (rc) { + printk(KERN_ERR + "pmac_zilog: Error registering serial device, disabling pmac_zilog.\n" + "pmac_zilog: Did another serial driver already claim the minors?\n"); + /* effectively "pmz_unprobe()" */ + for (i=0; i < pmz_ports_count; i++) + pmz_dispose_port(&pmz_ports[i]); + return rc; + } + + /* + * Then we register the macio driver itself + */ +#ifdef CONFIG_PPC_PMAC + return macio_register_driver(&pmz_driver); +#else + return platform_driver_probe(&pmz_driver, pmz_attach); +#endif +} + +static void __exit exit_pmz(void) +{ + int i; + +#ifdef CONFIG_PPC_PMAC + /* Get rid of macio-driver (detach from macio) */ + macio_unregister_driver(&pmz_driver); +#else + platform_driver_unregister(&pmz_driver); +#endif + + for (i = 0; i < pmz_ports_count; i++) { + struct uart_pmac_port *uport = &pmz_ports[i]; + if (uport->node != NULL) { + uart_remove_one_port(&pmz_uart_reg, &uport->port); + pmz_dispose_port(uport); + } + } + /* Unregister UART driver */ + uart_unregister_driver(&pmz_uart_reg); +} + +#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE + +static void pmz_console_putchar(struct uart_port *port, int ch) +{ + struct uart_pmac_port *uap = (struct uart_pmac_port *)port; + + /* Wait for the transmit buffer to empty. */ + while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0) + udelay(5); + write_zsdata(uap, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void pmz_console_write(struct console *con, const char *s, unsigned int count) +{ + struct uart_pmac_port *uap = &pmz_ports[con->index]; + unsigned long flags; + + if (ZS_IS_ASLEEP(uap)) + return; + spin_lock_irqsave(&uap->port.lock, flags); + + /* Turn of interrupts and enable the transmitter. */ + write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB); + write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR); + + uart_console_write(&uap->port, s, count, pmz_console_putchar); + + /* Restore the values in the registers. */ + write_zsreg(uap, R1, uap->curregs[1]); + /* Don't disable the transmitter. */ + + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +/* + * Setup the serial console + */ +static int __init pmz_console_setup(struct console *co, char *options) +{ + struct uart_pmac_port *uap; + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + unsigned long pwr_delay; + + /* + * XServe's default to 57600 bps + */ + if (of_machine_is_compatible("RackMac1,1") + || of_machine_is_compatible("RackMac1,2") + || of_machine_is_compatible("MacRISC4")) + baud = 57600; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= pmz_ports_count) + co->index = 0; + uap = &pmz_ports[co->index]; + if (uap->node == NULL) + return -ENODEV; + port = &uap->port; + + /* + * Mark port as beeing a console + */ + uap->flags |= PMACZILOG_FLAG_IS_CONS; + + /* + * Temporary fix for uart layer who didn't setup the spinlock yet + */ + spin_lock_init(&port->lock); + + /* + * Enable the hardware + */ + pwr_delay = __pmz_startup(uap); + if (pwr_delay) + mdelay(pwr_delay); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static int __init pmz_console_init(void) +{ + /* Probe ports */ + pmz_probe(); + + /* TODO: Autoprobe console based on OF */ + /* pmz_console.index = i; */ + register_console(&pmz_console); + + return 0; + +} +console_initcall(pmz_console_init); +#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ + +module_init(init_pmz); +module_exit(exit_pmz); diff --git a/drivers/tty/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h new file mode 100644 index 000000000000..cbc34fbb1b20 --- /dev/null +++ b/drivers/tty/serial/pmac_zilog.h @@ -0,0 +1,396 @@ +#ifndef __PMAC_ZILOG_H__ +#define __PMAC_ZILOG_H__ + +#ifdef CONFIG_PPC_PMAC +#define pmz_debug(fmt, arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg) +#define pmz_error(fmt, arg...) dev_err(&uap->dev->ofdev.dev, fmt, ## arg) +#define pmz_info(fmt, arg...) dev_info(&uap->dev->ofdev.dev, fmt, ## arg) +#else +#define pmz_debug(fmt, arg...) dev_dbg(&uap->node->dev, fmt, ## arg) +#define pmz_error(fmt, arg...) dev_err(&uap->node->dev, fmt, ## arg) +#define pmz_info(fmt, arg...) dev_info(&uap->node->dev, fmt, ## arg) +#endif + +/* + * At most 2 ESCCs with 2 ports each + */ +#define MAX_ZS_PORTS 4 + +/* + * We wrap our port structure around the generic uart_port. + */ +#define NUM_ZSREGS 17 + +struct uart_pmac_port { + struct uart_port port; + struct uart_pmac_port *mate; + +#ifdef CONFIG_PPC_PMAC + /* macio_dev for the escc holding this port (maybe be null on + * early inited port) + */ + struct macio_dev *dev; + /* device node to this port, this points to one of 2 childs + * of "escc" node (ie. ch-a or ch-b) + */ + struct device_node *node; +#else + struct platform_device *node; +#endif + + /* Port type as obtained from device tree (IRDA, modem, ...) */ + int port_type; + u8 curregs[NUM_ZSREGS]; + + unsigned int flags; +#define PMACZILOG_FLAG_IS_CONS 0x00000001 +#define PMACZILOG_FLAG_IS_KGDB 0x00000002 +#define PMACZILOG_FLAG_MODEM_STATUS 0x00000004 +#define PMACZILOG_FLAG_IS_CHANNEL_A 0x00000008 +#define PMACZILOG_FLAG_REGS_HELD 0x00000010 +#define PMACZILOG_FLAG_TX_STOPPED 0x00000020 +#define PMACZILOG_FLAG_TX_ACTIVE 0x00000040 +#define PMACZILOG_FLAG_ENABLED 0x00000080 +#define PMACZILOG_FLAG_IS_IRDA 0x00000100 +#define PMACZILOG_FLAG_IS_INTMODEM 0x00000200 +#define PMACZILOG_FLAG_HAS_DMA 0x00000400 +#define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800 +#define PMACZILOG_FLAG_IS_ASLEEP 0x00001000 +#define PMACZILOG_FLAG_IS_OPEN 0x00002000 +#define PMACZILOG_FLAG_IS_IRQ_ON 0x00004000 +#define PMACZILOG_FLAG_IS_EXTCLK 0x00008000 +#define PMACZILOG_FLAG_BREAK 0x00010000 + + unsigned char parity_mask; + unsigned char prev_status; + + volatile u8 __iomem *control_reg; + volatile u8 __iomem *data_reg; + +#ifdef CONFIG_PPC_PMAC + unsigned int tx_dma_irq; + unsigned int rx_dma_irq; + volatile struct dbdma_regs __iomem *tx_dma_regs; + volatile struct dbdma_regs __iomem *rx_dma_regs; +#endif + + struct ktermios termios_cache; +}; + +#define to_pmz(p) ((struct uart_pmac_port *)(p)) + +static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap) +{ + if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A) + return uap; + return uap->mate; +} + +/* + * Register accessors. Note that we don't need to enforce a recovery + * delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip, + * though if we try to use this driver on older machines, we might have + * to add it back + */ +static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg) +{ + if (reg != 0) + writeb(reg, port->control_reg); + return readb(port->control_reg); +} + +static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value) +{ + if (reg != 0) + writeb(reg, port->control_reg); + writeb(value, port->control_reg); +} + +static inline u8 read_zsdata(struct uart_pmac_port *port) +{ + return readb(port->data_reg); +} + +static inline void write_zsdata(struct uart_pmac_port *port, u8 data) +{ + writeb(data, port->data_reg); +} + +static inline void zssync(struct uart_pmac_port *port) +{ + (void)readb(port->control_reg); +} + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */ + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 +#define R7P 16 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ +#define RxINT_MASK 0x18 + +#define WT_RDY_RT 0x20 /* W/Req reflects recv if 1, xmit if 0 */ +#define WT_FN_RDYFN 0x40 /* W/Req pin is DMA request if 1, wait if 0 */ +#define WT_RDY_ENAB 0x80 /* Enable W/Req pin */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxN_MASK 0xc0 + +/* Write Register 4 */ + +#define PAR_ENAB 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ +#define SB_MASK 0xc + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ +#define XCLK_MASK 0xC0 + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENABLE 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxN_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 7' (Some enhanced feature control) */ +#define ENEXREAD 0x40 /* Enable read of some write registers */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENAB 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define EN85C30 1 /* Enable some 85c30-enhanced registers */ +#define ZCIE 2 /* Zero count IE */ +#define ENSTFIFO 4 /* Enable status FIFO (SDLC) */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define CRC_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ +#define CHB_Tx_EMPTY 0x00 +#define CHB_EXT_STAT 0x02 +#define CHB_Rx_AVAIL 0x04 +#define CHB_SPECIAL 0x06 +#define CHA_Tx_EMPTY 0x08 +#define CHA_EXT_STAT 0x0a +#define CHA_Rx_AVAIL 0x0c +#define CHA_SPECIAL 0x0e +#define STATUS_MASK 0x06 + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* Misc macros */ +#define ZS_CLEARERR(port) (write_zsreg(port, 0, ERR_RES)) +#define ZS_CLEARFIFO(port) do { volatile unsigned char garbage; \ + garbage = read_zsdata(port); \ + garbage = read_zsdata(port); \ + garbage = read_zsdata(port); \ + } while(0) + +#define ZS_IS_CONS(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CONS) +#define ZS_IS_KGDB(UP) ((UP)->flags & PMACZILOG_FLAG_IS_KGDB) +#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A) +#define ZS_REGS_HELD(UP) ((UP)->flags & PMACZILOG_FLAG_REGS_HELD) +#define ZS_TX_STOPPED(UP) ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED) +#define ZS_TX_ACTIVE(UP) ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE) +#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS) +#define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA) +#define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM) +#define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA) +#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP) +#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN) +#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON) +#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK) + +#endif /* __PMAC_ZILOG_H__ */ diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c new file mode 100644 index 000000000000..0aa75a97531c --- /dev/null +++ b/drivers/tty/serial/pnx8xxx_uart.c @@ -0,0 +1,854 @@ +/* + * UART driver for PNX8XXX SoCs + * + * Author: Per Hallsmark per.hallsmark@mvista.com + * Ported to 2.6 kernel by EmbeddedAlley + * Reworked by Vitaly Wool + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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. + * + */ + +#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* We'll be using StrongARM sa1100 serial port major/minor */ +#define SERIAL_PNX8XXX_MAJOR 204 +#define MINOR_START 5 + +#define NR_PORTS 2 + +#define PNX8XXX_ISR_PASS_LIMIT 256 + +/* + * Convert from ignore_status_mask or read_status_mask to FIFO + * and interrupt status bits + */ +#define SM_TO_FIFO(x) ((x) >> 10) +#define SM_TO_ISTAT(x) ((x) & 0x000001ff) +#define FIFO_TO_SM(x) ((x) << 10) +#define ISTAT_TO_SM(x) ((x) & 0x000001ff) + +/* + * This is the size of our serial port register set. + */ +#define UART_PORT_SIZE 0x1000 + +/* + * This determines how often we check the modem status signals + * for any change. They generally aren't connected to an IRQ + * so we have to poll them. We also check immediately before + * filling the TX fifo incase CTS has been dropped. + */ +#define MCTRL_TIMEOUT (250*HZ/1000) + +extern struct pnx8xxx_port pnx8xxx_ports[]; + +static inline int serial_in(struct pnx8xxx_port *sport, int offset) +{ + return (__raw_readl(sport->port.membase + offset)); +} + +static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value) +{ + __raw_writel(value, sport->port.membase + offset); +} + +/* + * Handle any change of modem status signal since we were last called. + */ +static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) +{ + unsigned int status, changed; + + status = sport->port.ops->get_mctrl(&sport->port); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); +} + +/* + * This is our per-port timeout handler, for checking the + * modem status signals. + */ +static void pnx8xxx_timeout(unsigned long data) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data; + unsigned long flags; + + if (sport->port.state) { + spin_lock_irqsave(&sport->port.lock, flags); + pnx8xxx_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +} + +/* + * interrupts disabled on entry + */ +static void pnx8xxx_stop_tx(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + u32 ien; + + /* Disable TX intr */ + ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX); + + /* Clear all pending TX intr */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); +} + +/* + * interrupts may not be disabled on entry + */ +static void pnx8xxx_start_tx(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + u32 ien; + + /* Clear all pending TX intr */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); + + /* Enable TX intr */ + ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX); +} + +/* + * Interrupts enabled + */ +static void pnx8xxx_stop_rx(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + u32 ien; + + /* Disable RX intr */ + ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX); + + /* Clear all pending RX intr */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void pnx8xxx_enable_ms(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + mod_timer(&sport->timer, jiffies); +} + +static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) +{ + struct tty_struct *tty = sport->port.state->port.tty; + unsigned int status, ch, flg; + + status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | + ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); + while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) { + ch = serial_in(sport, PNX8XXX_FIFO) & 0xff; + + sport->port.icount.rx++; + + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE | + PNX8XXX_UART_FIFO_RXPAR | + PNX8XXX_UART_FIFO_RXBRK) | + ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) { + if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) { + status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)); + sport->port.icount.brk++; + if (uart_handle_break(&sport->port)) + goto ignore_char; + } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) + sport->port.icount.parity++; + else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) + sport->port.icount.frame++; + if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN)) + sport->port.icount.overrun++; + + status &= sport->port.read_status_mask; + + if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) + flg = TTY_PARITY; + else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) + flg = TTY_FRAME; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } + + if (uart_handle_sysrq_char(&sport->port, ch)) + goto ignore_char; + + uart_insert_char(&sport->port, status, + ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg); + + ignore_char: + serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) | + PNX8XXX_UART_LCR_RX_NEXT); + status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | + ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); + } + tty_flip_buffer_push(tty); +} + +static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + + if (sport->port.x_char) { + serial_out(sport, PNX8XXX_FIFO, sport->port.x_char); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + /* + * Check the modem control lines before + * transmitting anything. + */ + pnx8xxx_mctrl_check(sport); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + pnx8xxx_stop_tx(&sport->port); + return; + } + + /* + * TX while bytes available + */ + while (((serial_in(sport, PNX8XXX_FIFO) & + PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) { + serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + pnx8xxx_stop_tx(&sport->port); +} + +static irqreturn_t pnx8xxx_int(int irq, void *dev_id) +{ + struct pnx8xxx_port *sport = dev_id; + unsigned int status; + + spin_lock(&sport->port.lock); + /* Get the interrupts */ + status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN); + + /* Byte or break signal received */ + if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK)) + pnx8xxx_rx_chars(sport); + + /* TX holding register empty - transmit a byte */ + if (status & PNX8XXX_UART_INT_TX) + pnx8xxx_tx_chars(sport); + + /* Clear the ISTAT register */ + serial_out(sport, PNX8XXX_ICLR, status); + + spin_unlock(&sport->port.lock); + return IRQ_HANDLED; +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int pnx8xxx_tx_empty(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT; +} + +static unsigned int pnx8xxx_get_mctrl(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned int mctrl = TIOCM_DSR; + unsigned int msr; + + /* REVISIT */ + + msr = serial_in(sport, PNX8XXX_MCR); + + mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0; + mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0; + + return mctrl; +} + +static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +#if 0 /* FIXME */ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned int msr; +#endif +} + +/* + * Interrupts always disabled. + */ +static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned long flags; + unsigned int lcr; + + spin_lock_irqsave(&sport->port.lock, flags); + lcr = serial_in(sport, PNX8XXX_LCR); + if (break_state == -1) + lcr |= PNX8XXX_UART_LCR_TXBREAK; + else + lcr &= ~PNX8XXX_UART_LCR_TXBREAK; + serial_out(sport, PNX8XXX_LCR, lcr); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int pnx8xxx_startup(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(sport->port.irq, pnx8xxx_int, 0, + "pnx8xxx-uart", sport); + if (retval) + return retval; + + /* + * Finally, clear and enable interrupts + */ + + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | + PNX8XXX_UART_INT_ALLTX); + + serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) | + PNX8XXX_UART_INT_ALLRX | + PNX8XXX_UART_INT_ALLTX); + + /* + * Enable modem status interrupts + */ + spin_lock_irq(&sport->port.lock); + pnx8xxx_enable_ms(&sport->port); + spin_unlock_irq(&sport->port.lock); + + return 0; +} + +static void pnx8xxx_shutdown(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int lcr; + + /* + * Stop our timer. + */ + del_timer_sync(&sport->timer); + + /* + * Disable all interrupts + */ + serial_out(sport, PNX8XXX_IEN, 0); + + /* + * Reset the Tx and Rx FIFOS, disable the break condition + */ + lcr = serial_in(sport, PNX8XXX_LCR); + lcr &= ~PNX8XXX_UART_LCR_TXBREAK; + lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST; + serial_out(sport, PNX8XXX_LCR, lcr); + + /* + * Clear all interrupts + */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | + PNX8XXX_UART_INT_ALLTX); + + /* + * Free the interrupt + */ + free_irq(sport->port.irq, sport); +} + +static void +pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + unsigned long flags; + unsigned int lcr_fcr, old_ien, baud, quot; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + + /* + * We only support CS7 and CS8. + */ + while ((termios->c_cflag & CSIZE) != CS7 && + (termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS8) + lcr_fcr = PNX8XXX_UART_LCR_8BIT; + else + lcr_fcr = 0; + + if (termios->c_cflag & CSTOPB) + lcr_fcr |= PNX8XXX_UART_LCR_2STOPB; + if (termios->c_cflag & PARENB) { + lcr_fcr |= PNX8XXX_UART_LCR_PAREN; + if (!(termios->c_cflag & PARODD)) + lcr_fcr |= PNX8XXX_UART_LCR_PAREVN; + } + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) | + ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) | + ISTAT_TO_SM(PNX8XXX_UART_INT_RX); + if (termios->c_iflag & INPCK) + sport->port.read_status_mask |= + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); + if (termios->c_iflag & (BRKINT | PARMRK)) + sport->port.read_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); + + /* + * Characters to ignore + */ + sport->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | + FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); + if (termios->c_iflag & IGNBRK) { + sport->port.ignore_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN); + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + sport->port.ignore_status_mask |= + ISTAT_TO_SM(PNX8XXX_UART_INT_RX); + + del_timer_sync(&sport->timer); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * disable interrupts and drain transmitter + */ + old_ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | + PNX8XXX_UART_INT_ALLRX)); + + while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA) + barrier(); + + /* then, disable everything */ + serial_out(sport, PNX8XXX_IEN, 0); + + /* Reset the Rx and Tx FIFOs too */ + lcr_fcr |= PNX8XXX_UART_LCR_TX_RST; + lcr_fcr |= PNX8XXX_UART_LCR_RX_RST; + + /* set the parity, stop bits and data size */ + serial_out(sport, PNX8XXX_LCR, lcr_fcr); + + /* set the baud rate */ + quot -= 1; + serial_out(sport, PNX8XXX_BAUD, quot); + + serial_out(sport, PNX8XXX_ICLR, -1); + + serial_out(sport, PNX8XXX_IEN, old_ien); + + if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) + pnx8xxx_enable_ms(&sport->port); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static const char *pnx8xxx_type(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void pnx8xxx_release_port(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + release_mem_region(sport->port.mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int pnx8xxx_request_port(struct uart_port *port) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, + "pnx8xxx-uart") != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void pnx8xxx_config_port(struct uart_port *port, int flags) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + + if (flags & UART_CONFIG_TYPE && + pnx8xxx_request_port(&sport->port) == 0) + sport->port.type = PORT_PNX8XXX; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_PNX8XXX and PORT_UNKNOWN + */ +static int +pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX) + ret = -EINVAL; + if (sport->port.irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + ret = -EINVAL; + if (sport->port.uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)sport->port.mapbase != ser->iomem_base) + ret = -EINVAL; + if (sport->port.iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +static struct uart_ops pnx8xxx_pops = { + .tx_empty = pnx8xxx_tx_empty, + .set_mctrl = pnx8xxx_set_mctrl, + .get_mctrl = pnx8xxx_get_mctrl, + .stop_tx = pnx8xxx_stop_tx, + .start_tx = pnx8xxx_start_tx, + .stop_rx = pnx8xxx_stop_rx, + .enable_ms = pnx8xxx_enable_ms, + .break_ctl = pnx8xxx_break_ctl, + .startup = pnx8xxx_startup, + .shutdown = pnx8xxx_shutdown, + .set_termios = pnx8xxx_set_termios, + .type = pnx8xxx_type, + .release_port = pnx8xxx_release_port, + .request_port = pnx8xxx_request_port, + .config_port = pnx8xxx_config_port, + .verify_port = pnx8xxx_verify_port, +}; + + +/* + * Setup the PNX8XXX serial ports. + * + * Note also that we support "console=ttySx" where "x" is either 0 or 1. + */ +static void __init pnx8xxx_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < NR_PORTS; i++) { + init_timer(&pnx8xxx_ports[i].timer); + pnx8xxx_ports[i].timer.function = pnx8xxx_timeout; + pnx8xxx_ports[i].timer.data = (unsigned long)&pnx8xxx_ports[i]; + pnx8xxx_ports[i].port.ops = &pnx8xxx_pops; + } +} + +#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE + +static void pnx8xxx_console_putchar(struct uart_port *port, int ch) +{ + struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; + int status; + + do { + /* Wait for UART_TX register to empty */ + status = serial_in(sport, PNX8XXX_FIFO); + } while (status & PNX8XXX_UART_FIFO_TXFIFO); + serial_out(sport, PNX8XXX_FIFO, ch); +} + +/* + * Interrupts are disabled on entering + */static void +pnx8xxx_console_write(struct console *co, const char *s, unsigned int count) +{ + struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index]; + unsigned int old_ien, status; + + /* + * First, save IEN and then disable interrupts + */ + old_ien = serial_in(sport, PNX8XXX_IEN); + serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | + PNX8XXX_UART_INT_ALLRX)); + + uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore IEN + */ + do { + /* Wait for UART_TX register to empty */ + status = serial_in(sport, PNX8XXX_FIFO); + } while (status & PNX8XXX_UART_FIFO_TXFIFO); + + /* Clear TX and EMPTY interrupt */ + serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX | + PNX8XXX_UART_INT_EMPTY); + + serial_out(sport, PNX8XXX_IEN, old_ien); +} + +static int __init +pnx8xxx_console_setup(struct console *co, char *options) +{ + struct pnx8xxx_port *sport; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= NR_PORTS) + co->index = 0; + sport = &pnx8xxx_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver pnx8xxx_reg; +static struct console pnx8xxx_console = { + .name = "ttyS", + .write = pnx8xxx_console_write, + .device = uart_console_device, + .setup = pnx8xxx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &pnx8xxx_reg, +}; + +static int __init pnx8xxx_rs_console_init(void) +{ + pnx8xxx_init_ports(); + register_console(&pnx8xxx_console); + return 0; +} +console_initcall(pnx8xxx_rs_console_init); + +#define PNX8XXX_CONSOLE &pnx8xxx_console +#else +#define PNX8XXX_CONSOLE NULL +#endif + +static struct uart_driver pnx8xxx_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyS", + .dev_name = "ttyS", + .major = SERIAL_PNX8XXX_MAJOR, + .minor = MINOR_START, + .nr = NR_PORTS, + .cons = PNX8XXX_CONSOLE, +}; + +static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pnx8xxx_port *sport = platform_get_drvdata(pdev); + + return uart_suspend_port(&pnx8xxx_reg, &sport->port); +} + +static int pnx8xxx_serial_resume(struct platform_device *pdev) +{ + struct pnx8xxx_port *sport = platform_get_drvdata(pdev); + + return uart_resume_port(&pnx8xxx_reg, &sport->port); +} + +static int pnx8xxx_serial_probe(struct platform_device *pdev) +{ + struct resource *res = pdev->resource; + int i; + + for (i = 0; i < pdev->num_resources; i++, res++) { + if (!(res->flags & IORESOURCE_MEM)) + continue; + + for (i = 0; i < NR_PORTS; i++) { + if (pnx8xxx_ports[i].port.mapbase != res->start) + continue; + + pnx8xxx_ports[i].port.dev = &pdev->dev; + uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port); + platform_set_drvdata(pdev, &pnx8xxx_ports[i]); + break; + } + } + + return 0; +} + +static int pnx8xxx_serial_remove(struct platform_device *pdev) +{ + struct pnx8xxx_port *sport = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (sport) + uart_remove_one_port(&pnx8xxx_reg, &sport->port); + + return 0; +} + +static struct platform_driver pnx8xxx_serial_driver = { + .driver = { + .name = "pnx8xxx-uart", + .owner = THIS_MODULE, + }, + .probe = pnx8xxx_serial_probe, + .remove = pnx8xxx_serial_remove, + .suspend = pnx8xxx_serial_suspend, + .resume = pnx8xxx_serial_resume, +}; + +static int __init pnx8xxx_serial_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: PNX8XXX driver\n"); + + pnx8xxx_init_ports(); + + ret = uart_register_driver(&pnx8xxx_reg); + if (ret == 0) { + ret = platform_driver_register(&pnx8xxx_serial_driver); + if (ret) + uart_unregister_driver(&pnx8xxx_reg); + } + return ret; +} + +static void __exit pnx8xxx_serial_exit(void) +{ + platform_driver_unregister(&pnx8xxx_serial_driver); + uart_unregister_driver(&pnx8xxx_reg); +} + +module_init(pnx8xxx_serial_init); +module_exit(pnx8xxx_serial_exit); + +MODULE_AUTHOR("Embedded Alley Solutions, Inc."); +MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR); +MODULE_ALIAS("platform:pnx8xxx-uart"); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c new file mode 100644 index 000000000000..1102a39b44f5 --- /dev/null +++ b/drivers/tty/serial/pxa.c @@ -0,0 +1,879 @@ +/* + * linux/drivers/serial/pxa.c + * + * Based on drivers/serial/8250.c by Russell King. + * + * Author: Nicolas Pitre + * Created: Feb 20, 2003 + * Copyright: (C) 2003 Monta Vista Software, Inc. + * + * 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. + * + * Note 1: This driver is made separate from the already too overloaded + * 8250.c because it needs some kirks of its own and that'll make it + * easier to add DMA support. + * + * Note 2: I'm too sick of device allocation policies for serial ports. + * If someone else wants to request an "official" allocation of major/minor + * for this driver please be my guest. And don't forget that new hardware + * to come from Intel might have more than 3 or 4 of those UARTs. Let's + * hope for a better port registration and dynamic device allocation scheme + * with the serial core maintainer satisfaction to appear soon. + */ + + +#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct uart_pxa_port { + struct uart_port port; + unsigned char ier; + unsigned char lcr; + unsigned char mcr; + unsigned int lsr_break_flag; + struct clk *clk; + char *name; +}; + +static inline unsigned int serial_in(struct uart_pxa_port *up, int offset) +{ + offset <<= 2; + return readl(up->port.membase + offset); +} + +static inline void serial_out(struct uart_pxa_port *up, int offset, int value) +{ + offset <<= 2; + writel(value, up->port.membase + offset); +} + +static void serial_pxa_enable_ms(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); +} + +static void serial_pxa_stop_tx(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + if (up->ier & UART_IER_THRI) { + up->ier &= ~UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static void serial_pxa_stop_rx(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +} + +static inline void receive_chars(struct uart_pxa_port *up, int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned int ch, flag; + int max_count = 256; + + do { + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(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 (*status & UART_LSR_PE) + up->port.icount.parity++; + else if (*status & UART_LSR_FE) + up->port.icount.frame++; + if (*status & UART_LSR_OE) + up->port.icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + *status &= up->port.read_status_mask; + +#ifdef CONFIG_SERIAL_PXA_CONSOLE + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + *status |= up->lsr_break_flag; + up->lsr_break_flag = 0; + } +#endif + if (*status & UART_LSR_BI) { + flag = TTY_BREAK; + } else if (*status & UART_LSR_PE) + flag = TTY_PARITY; + else if (*status & UART_LSR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + + uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); + + ignore_char: + *status = serial_in(up, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); + tty_flip_buffer_push(tty); +} + +static void transmit_chars(struct uart_pxa_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { + serial_out(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + serial_pxa_stop_tx(&up->port); + return; + } + + count = up->port.fifosize / 2; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + + if (uart_circ_empty(xmit)) + serial_pxa_stop_tx(&up->port); +} + +static void serial_pxa_start_tx(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } +} + +static inline void check_modem_status(struct uart_pxa_port *up) +{ + int status; + + status = serial_in(up, UART_MSR); + + if ((status & UART_MSR_ANY_DELTA) == 0) + return; + + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); +} + +/* + * This handles the interrupt from one port. + */ +static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) +{ + struct uart_pxa_port *up = dev_id; + unsigned int iir, lsr; + + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + return IRQ_NONE; + lsr = serial_in(up, UART_LSR); + if (lsr & UART_LSR_DR) + receive_chars(up, &lsr); + check_modem_status(up); + if (lsr & UART_LSR_THRE) + transmit_chars(up); + return IRQ_HANDLED; +} + +static unsigned int serial_pxa_tx_empty(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned long flags; + unsigned int ret; + + 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); + + return ret; +} + +static unsigned int serial_pxa_get_mctrl(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned char status; + unsigned int ret; + + status = serial_in(up, UART_MSR); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr |= up->mcr; + + serial_out(up, UART_MCR, mcr); +} + +static void serial_pxa_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +#if 0 +static void serial_pxa_dma_init(struct pxa_uart *up) +{ + up->rxdma = + pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up); + if (up->rxdma < 0) + goto out; + up->txdma = + pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up); + if (up->txdma < 0) + goto err_txdma; + up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL); + if (!up->dmadesc) + goto err_alloc; + + /* ... */ +err_alloc: + pxa_free_dma(up->txdma); +err_rxdma: + pxa_free_dma(up->rxdma); +out: + return; +} +#endif + +static int serial_pxa_startup(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned long flags; + int retval; + + if (port->line == 3) /* HWUART */ + up->mcr |= UART_MCR_AFE; + else + up->mcr = 0; + + up->port.uartclk = clk_get_rate(up->clk); + + /* + * Allocate the IRQ + */ + retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up); + if (retval) + return retval; + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); + + /* + * Clear the interrupt registers. + */ + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_out(up, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&up->port.lock, flags); + up->port.mctrl |= TIOCM_OUT2; + serial_pxa_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; + serial_out(up, UART_IER, up->ier); + + /* + * And clear the interrupt registers again for luck. + */ + (void) serial_in(up, UART_LSR); + (void) serial_in(up, UART_RX); + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + + return 0; +} + +static void serial_pxa_shutdown(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned long flags; + + free_irq(up->port.irq, up); + + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_out(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + up->port.mctrl &= ~TIOCM_OUT2; + serial_pxa_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); +} + +static void +serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + unsigned char cval, fcr = 0; + unsigned long flags; + unsigned int baud, quot; + unsigned int dll; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + if ((up->port.uartclk / quot) < (2400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; + else if ((up->port.uartclk / quot) < (230400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Ensure the port will be enabled. + * This is required especially for serial console. + */ + up->ier |= UART_IER_UUE; + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + + serial_out(up, UART_IER, up->ier); + + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + else + up->mcr &= ~UART_MCR_AFE; + + serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ + + /* + * work around Errata #75 according to Intel(R) PXA27x Processor Family + * Specification Update (Nov 2005) + */ + dll = serial_in(up, UART_DLL); + WARN_ON(dll != (quot & 0xff)); + + serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(up, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + serial_pxa_set_mctrl(&up->port, up->port.mctrl); + serial_out(up, UART_FCR, fcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void +serial_pxa_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + if (!state) + clk_enable(up->clk); + else + clk_disable(up->clk); +} + +static void serial_pxa_release_port(struct uart_port *port) +{ +} + +static int serial_pxa_request_port(struct uart_port *port) +{ + return 0; +} + +static void serial_pxa_config_port(struct uart_port *port, int flags) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + up->port.type = PORT_PXA; +} + +static int +serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + +static const char * +serial_pxa_type(struct uart_port *port) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + return up->name; +} + +static struct uart_pxa_port *serial_pxa_ports[4]; +static struct uart_driver serial_pxa_reg; + +#ifdef CONFIG_SERIAL_PXA_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct uart_pxa_port *up) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) + udelay(1); + } +} + +static void serial_pxa_console_putchar(struct uart_port *port, int ch) +{ + struct uart_pxa_port *up = (struct uart_pxa_port *)port; + + wait_for_xmitr(up); + serial_out(up, UART_TX, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +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; + + clk_enable(up->clk); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, UART_IER_UUE); + + uart_console_write(&up->port, s, count, serial_pxa_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); + + clk_disable(up->clk); +} + +static int __init +serial_pxa_console_setup(struct console *co, char *options) +{ + struct uart_pxa_port *up; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index == -1 || co->index >= serial_pxa_reg.nr) + co->index = 0; + up = serial_pxa_ports[co->index]; + if (!up) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&up->port, co, baud, parity, bits, flow); +} + +static struct console serial_pxa_console = { + .name = "ttyS", + .write = serial_pxa_console_write, + .device = uart_console_device, + .setup = serial_pxa_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &serial_pxa_reg, +}; + +#define PXA_CONSOLE &serial_pxa_console +#else +#define PXA_CONSOLE NULL +#endif + +struct uart_ops serial_pxa_pops = { + .tx_empty = serial_pxa_tx_empty, + .set_mctrl = serial_pxa_set_mctrl, + .get_mctrl = serial_pxa_get_mctrl, + .stop_tx = serial_pxa_stop_tx, + .start_tx = serial_pxa_start_tx, + .stop_rx = serial_pxa_stop_rx, + .enable_ms = serial_pxa_enable_ms, + .break_ctl = serial_pxa_break_ctl, + .startup = serial_pxa_startup, + .shutdown = serial_pxa_shutdown, + .set_termios = serial_pxa_set_termios, + .pm = serial_pxa_pm, + .type = serial_pxa_type, + .release_port = serial_pxa_release_port, + .request_port = serial_pxa_request_port, + .config_port = serial_pxa_config_port, + .verify_port = serial_pxa_verify_port, +}; + +static struct uart_driver serial_pxa_reg = { + .owner = THIS_MODULE, + .driver_name = "PXA serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = 4, + .cons = PXA_CONSOLE, +}; + +#ifdef CONFIG_PM +static int serial_pxa_suspend(struct device *dev) +{ + struct uart_pxa_port *sport = dev_get_drvdata(dev); + + if (sport) + uart_suspend_port(&serial_pxa_reg, &sport->port); + + return 0; +} + +static int serial_pxa_resume(struct device *dev) +{ + struct uart_pxa_port *sport = dev_get_drvdata(dev); + + if (sport) + uart_resume_port(&serial_pxa_reg, &sport->port); + + return 0; +} + +static const struct dev_pm_ops serial_pxa_pm_ops = { + .suspend = serial_pxa_suspend, + .resume = serial_pxa_resume, +}; +#endif + +static int serial_pxa_probe(struct platform_device *dev) +{ + struct uart_pxa_port *sport; + struct resource *mmres, *irqres; + int ret; + + mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); + irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); + if (!mmres || !irqres) + return -ENODEV; + + sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + sport->clk = clk_get(&dev->dev, NULL); + if (IS_ERR(sport->clk)) { + ret = PTR_ERR(sport->clk); + goto err_free; + } + + sport->port.type = PORT_PXA; + sport->port.iotype = UPIO_MEM; + sport->port.mapbase = mmres->start; + sport->port.irq = irqres->start; + sport->port.fifosize = 64; + sport->port.ops = &serial_pxa_pops; + sport->port.line = dev->id; + sport->port.dev = &dev->dev; + sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; + sport->port.uartclk = clk_get_rate(sport->clk); + + switch (dev->id) { + case 0: sport->name = "FFUART"; break; + case 1: sport->name = "BTUART"; break; + case 2: sport->name = "STUART"; break; + case 3: sport->name = "HWUART"; break; + default: + sport->name = "???"; + break; + } + + sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); + if (!sport->port.membase) { + ret = -ENOMEM; + goto err_clk; + } + + serial_pxa_ports[dev->id] = sport; + + uart_add_one_port(&serial_pxa_reg, &sport->port); + platform_set_drvdata(dev, sport); + + return 0; + + err_clk: + clk_put(sport->clk); + err_free: + kfree(sport); + return ret; +} + +static int serial_pxa_remove(struct platform_device *dev) +{ + struct uart_pxa_port *sport = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + uart_remove_one_port(&serial_pxa_reg, &sport->port); + clk_put(sport->clk); + kfree(sport); + + return 0; +} + +static struct platform_driver serial_pxa_driver = { + .probe = serial_pxa_probe, + .remove = serial_pxa_remove, + + .driver = { + .name = "pxa2xx-uart", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &serial_pxa_pm_ops, +#endif + }, +}; + +int __init serial_pxa_init(void) +{ + int ret; + + ret = uart_register_driver(&serial_pxa_reg); + if (ret != 0) + return ret; + + ret = platform_driver_register(&serial_pxa_driver); + if (ret != 0) + uart_unregister_driver(&serial_pxa_reg); + + return ret; +} + +void __exit serial_pxa_exit(void) +{ + platform_driver_unregister(&serial_pxa_driver); + uart_unregister_driver(&serial_pxa_reg); +} + +module_init(serial_pxa_init); +module_exit(serial_pxa_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-uart"); diff --git a/drivers/tty/serial/s3c2400.c b/drivers/tty/serial/s3c2400.c new file mode 100644 index 000000000000..fed1a9a1ffb4 --- /dev/null +++ b/drivers/tty/serial/s3c2400.c @@ -0,0 +1,106 @@ +/* linux/drivers/serial/s3c240.c + * + * Driver for Samsung SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include "samsung.h" + +static int s3c2400_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + clk->divisor = 1; + clk->name = "pclk"; + + return 0; +} + +static int s3c2400_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + return 0; +} + +static int s3c2400_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + dbg("s3c2400_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + wr_regl(port, S3C2410_UCON, cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2400_uart_inf = { + .name = "Samsung S3C2400 UART", + .type = PORT_S3C2400, + .fifosize = 16, + .rx_fifomask = S3C2410_UFSTAT_RXMASK, + .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2410_UFSTAT_RXFULL, + .tx_fifofull = S3C2410_UFSTAT_TXFULL, + .tx_fifomask = S3C2410_UFSTAT_TXMASK, + .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, + .get_clksrc = s3c2400_serial_getsource, + .set_clksrc = s3c2400_serial_setsource, + .reset_port = s3c2400_serial_resetport, +}; + +static int s3c2400_serial_probe(struct platform_device *dev) +{ + return s3c24xx_serial_probe(dev, &s3c2400_uart_inf); +} + +static struct platform_driver s3c2400_serial_driver = { + .probe = s3c2400_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c2400-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c2400_serial_driver, &s3c2400_uart_inf); + +static inline int s3c2400_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2400_serial_driver, &s3c2400_uart_inf); +} + +static inline void s3c2400_serial_exit(void) +{ + platform_driver_unregister(&s3c2400_serial_driver); +} + +module_init(s3c2400_serial_init); +module_exit(s3c2400_serial_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("Samsung S3C2400 SoC Serial port driver"); +MODULE_ALIAS("platform:s3c2400-uart"); diff --git a/drivers/tty/serial/s3c2410.c b/drivers/tty/serial/s3c2410.c new file mode 100644 index 000000000000..73f089d3efd6 --- /dev/null +++ b/drivers/tty/serial/s3c2410.c @@ -0,0 +1,118 @@ +/* linux/drivers/serial/s3c2410.c + * + * Driver for Samsung S3C2410 SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "samsung.h" + +static int s3c2410_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2410_UCON_UCLK; + else + ucon &= ~S3C2410_UCON_UCLK; + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + +static int s3c2410_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + clk->divisor = 1; + clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; + + return 0; +} + +static int s3c2410_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + wr_regl(port, S3C2410_UCON, cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2410_uart_inf = { + .name = "Samsung S3C2410 UART", + .type = PORT_S3C2410, + .fifosize = 16, + .rx_fifomask = S3C2410_UFSTAT_RXMASK, + .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2410_UFSTAT_RXFULL, + .tx_fifofull = S3C2410_UFSTAT_TXFULL, + .tx_fifomask = S3C2410_UFSTAT_TXMASK, + .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, + .get_clksrc = s3c2410_serial_getsource, + .set_clksrc = s3c2410_serial_setsource, + .reset_port = s3c2410_serial_resetport, +}; + +static int s3c2410_serial_probe(struct platform_device *dev) +{ + return s3c24xx_serial_probe(dev, &s3c2410_uart_inf); +} + +static struct platform_driver s3c2410_serial_driver = { + .probe = s3c2410_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c2410-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c2410_serial_driver, &s3c2410_uart_inf); + +static int __init s3c2410_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf); +} + +static void __exit s3c2410_serial_exit(void) +{ + platform_driver_unregister(&s3c2410_serial_driver); +} + +module_init(s3c2410_serial_init); +module_exit(s3c2410_serial_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("Samsung S3C2410 SoC Serial port driver"); +MODULE_ALIAS("platform:s3c2410-uart"); diff --git a/drivers/tty/serial/s3c2412.c b/drivers/tty/serial/s3c2412.c new file mode 100644 index 000000000000..1700b1a2fb7e --- /dev/null +++ b/drivers/tty/serial/s3c2412.c @@ -0,0 +1,152 @@ +/* linux/drivers/serial/s3c2412.c + * + * Driver for Samsung S3C2412 and S3C2413 SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "samsung.h" + +static int s3c2412_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + ucon &= ~S3C2412_UCON_CLKMASK; + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2440_UCON_UCLK; + else if (strcmp(clk->name, "pclk") == 0) + ucon |= S3C2440_UCON_PCLK; + else if (strcmp(clk->name, "usysclk") == 0) + ucon |= S3C2412_UCON_USYSCLK; + else { + printk(KERN_ERR "unknown clock source %s\n", clk->name); + return -EINVAL; + } + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + + +static int s3c2412_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + switch (ucon & S3C2412_UCON_CLKMASK) { + case S3C2412_UCON_UCLK: + clk->divisor = 1; + clk->name = "uclk"; + break; + + case S3C2412_UCON_PCLK: + case S3C2412_UCON_PCLK2: + clk->divisor = 1; + clk->name = "pclk"; + break; + + case S3C2412_UCON_USYSCLK: + clk->divisor = 1; + clk->name = "usysclk"; + break; + } + + return 0; +} + +static int s3c2412_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + dbg("%s: port=%p (%08lx), cfg=%p\n", + __func__, port, port->mapbase, cfg); + + /* ensure we don't change the clock settings... */ + + ucon &= S3C2412_UCON_CLKMASK; + + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2412_uart_inf = { + .name = "Samsung S3C2412 UART", + .type = PORT_S3C2412, + .fifosize = 64, + .has_divslot = 1, + .rx_fifomask = S3C2440_UFSTAT_RXMASK, + .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2440_UFSTAT_RXFULL, + .tx_fifofull = S3C2440_UFSTAT_TXFULL, + .tx_fifomask = S3C2440_UFSTAT_TXMASK, + .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, + .get_clksrc = s3c2412_serial_getsource, + .set_clksrc = s3c2412_serial_setsource, + .reset_port = s3c2412_serial_resetport, +}; + +/* device management */ + +static int s3c2412_serial_probe(struct platform_device *dev) +{ + dbg("s3c2440_serial_probe: dev=%p\n", dev); + return s3c24xx_serial_probe(dev, &s3c2412_uart_inf); +} + +static struct platform_driver s3c2412_serial_driver = { + .probe = s3c2412_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c2412-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c2412_serial_driver, &s3c2412_uart_inf); + +static inline int s3c2412_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2412_serial_driver, &s3c2412_uart_inf); +} + +static inline void s3c2412_serial_exit(void) +{ + platform_driver_unregister(&s3c2412_serial_driver); +} + +module_init(s3c2412_serial_init); +module_exit(s3c2412_serial_exit); + +MODULE_DESCRIPTION("Samsung S3C2412,S3C2413 SoC Serial port driver"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:s3c2412-uart"); diff --git a/drivers/tty/serial/s3c2440.c b/drivers/tty/serial/s3c2440.c new file mode 100644 index 000000000000..094cc3904b13 --- /dev/null +++ b/drivers/tty/serial/s3c2440.c @@ -0,0 +1,181 @@ +/* linux/drivers/serial/s3c2440.c + * + * Driver for Samsung S3C2440 and S3C2442 SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "samsung.h" + + +static int s3c2440_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + /* todo - proper fclk<>nonfclk switch. */ + + ucon &= ~S3C2440_UCON_CLKMASK; + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2440_UCON_UCLK; + else if (strcmp(clk->name, "pclk") == 0) + ucon |= S3C2440_UCON_PCLK; + else if (strcmp(clk->name, "fclk") == 0) + ucon |= S3C2440_UCON_FCLK; + else { + printk(KERN_ERR "unknown clock source %s\n", clk->name); + return -EINVAL; + } + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + + +static int s3c2440_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + unsigned long ucon0, ucon1, ucon2; + + switch (ucon & S3C2440_UCON_CLKMASK) { + case S3C2440_UCON_UCLK: + clk->divisor = 1; + clk->name = "uclk"; + break; + + case S3C2440_UCON_PCLK: + case S3C2440_UCON_PCLK2: + clk->divisor = 1; + clk->name = "pclk"; + break; + + case S3C2440_UCON_FCLK: + /* the fun of calculating the uart divisors on + * the s3c2440 */ + + ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON); + ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON); + ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON); + + printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2); + + ucon0 &= S3C2440_UCON0_DIVMASK; + ucon1 &= S3C2440_UCON1_DIVMASK; + ucon2 &= S3C2440_UCON2_DIVMASK; + + if (ucon0 != 0) { + clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT; + clk->divisor += 6; + } else if (ucon1 != 0) { + clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT; + clk->divisor += 21; + } else if (ucon2 != 0) { + clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT; + clk->divisor += 36; + } else { + /* manual calims 44, seems to be 9 */ + clk->divisor = 9; + } + + clk->name = "fclk"; + break; + } + + return 0; +} + +static int s3c2440_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + /* ensure we don't change the clock settings... */ + + ucon &= (S3C2440_UCON0_DIVMASK | (3<<10)); + + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c2440_uart_inf = { + .name = "Samsung S3C2440 UART", + .type = PORT_S3C2440, + .fifosize = 64, + .rx_fifomask = S3C2440_UFSTAT_RXMASK, + .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2440_UFSTAT_RXFULL, + .tx_fifofull = S3C2440_UFSTAT_TXFULL, + .tx_fifomask = S3C2440_UFSTAT_TXMASK, + .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, + .get_clksrc = s3c2440_serial_getsource, + .set_clksrc = s3c2440_serial_setsource, + .reset_port = s3c2440_serial_resetport, +}; + +/* device management */ + +static int s3c2440_serial_probe(struct platform_device *dev) +{ + dbg("s3c2440_serial_probe: dev=%p\n", dev); + return s3c24xx_serial_probe(dev, &s3c2440_uart_inf); +} + +static struct platform_driver s3c2440_serial_driver = { + .probe = s3c2440_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c2440-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf); + +static int __init s3c2440_serial_init(void) +{ + return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf); +} + +static void __exit s3c2440_serial_exit(void) +{ + platform_driver_unregister(&s3c2440_serial_driver); +} + +module_init(s3c2440_serial_init); +module_exit(s3c2440_serial_exit); + +MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:s3c2440-uart"); diff --git a/drivers/tty/serial/s3c24a0.c b/drivers/tty/serial/s3c24a0.c new file mode 100644 index 000000000000..fad6083ca427 --- /dev/null +++ b/drivers/tty/serial/s3c24a0.c @@ -0,0 +1,118 @@ +/* linux/drivers/serial/s3c24a0.c + * + * Driver for Samsung S3C24A0 SoC onboard UARTs. + * + * Based on drivers/serial/s3c2410.c + * + * Author: Sandeep Patil + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "samsung.h" + +static int s3c24a0_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + if (strcmp(clk->name, "uclk") == 0) + ucon |= S3C2410_UCON_UCLK; + else + ucon &= ~S3C2410_UCON_UCLK; + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + +static int s3c24a0_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + clk->divisor = 1; + clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk"; + + return 0; +} + +static int s3c24a0_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + wr_regl(port, S3C2410_UCON, cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c24a0_uart_inf = { + .name = "Samsung S3C24A0 UART", + .type = PORT_S3C2410, + .fifosize = 16, + .rx_fifomask = S3C24A0_UFSTAT_RXMASK, + .rx_fifoshift = S3C24A0_UFSTAT_RXSHIFT, + .rx_fifofull = S3C24A0_UFSTAT_RXFULL, + .tx_fifofull = S3C24A0_UFSTAT_TXFULL, + .tx_fifomask = S3C24A0_UFSTAT_TXMASK, + .tx_fifoshift = S3C24A0_UFSTAT_TXSHIFT, + .get_clksrc = s3c24a0_serial_getsource, + .set_clksrc = s3c24a0_serial_setsource, + .reset_port = s3c24a0_serial_resetport, +}; + +static int s3c24a0_serial_probe(struct platform_device *dev) +{ + return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf); +} + +static struct platform_driver s3c24a0_serial_driver = { + .probe = s3c24a0_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c24a0-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); + +static int __init s3c24a0_serial_init(void) +{ + return s3c24xx_serial_init(&s3c24a0_serial_driver, &s3c24a0_uart_inf); +} + +static void __exit s3c24a0_serial_exit(void) +{ + platform_driver_unregister(&s3c24a0_serial_driver); +} + +module_init(s3c24a0_serial_init); +module_exit(s3c24a0_serial_exit); + diff --git a/drivers/tty/serial/s3c6400.c b/drivers/tty/serial/s3c6400.c new file mode 100644 index 000000000000..4be92ab50058 --- /dev/null +++ b/drivers/tty/serial/s3c6400.c @@ -0,0 +1,152 @@ +/* linux/drivers/serial/s3c6400.c + * + * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs. + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "samsung.h" + +static int s3c6400_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + if (strcmp(clk->name, "uclk0") == 0) { + ucon &= ~S3C6400_UCON_CLKMASK; + ucon |= S3C6400_UCON_UCLK0; + } else if (strcmp(clk->name, "uclk1") == 0) + ucon |= S3C6400_UCON_UCLK1; + else if (strcmp(clk->name, "pclk") == 0) { + /* See notes about transitioning from UCLK to PCLK */ + ucon &= ~S3C6400_UCON_UCLK0; + } else { + printk(KERN_ERR "unknown clock source %s\n", clk->name); + return -EINVAL; + } + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + + +static int s3c6400_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + u32 ucon = rd_regl(port, S3C2410_UCON); + + clk->divisor = 1; + + switch (ucon & S3C6400_UCON_CLKMASK) { + case S3C6400_UCON_UCLK0: + clk->name = "uclk0"; + break; + + case S3C6400_UCON_UCLK1: + clk->name = "uclk1"; + break; + + case S3C6400_UCON_PCLK: + case S3C6400_UCON_PCLK2: + clk->name = "pclk"; + break; + } + + return 0; +} + +static int s3c6400_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n", + port, port->mapbase, cfg); + + /* ensure we don't change the clock settings... */ + + ucon &= S3C6400_UCON_CLKMASK; + + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +static struct s3c24xx_uart_info s3c6400_uart_inf = { + .name = "Samsung S3C6400 UART", + .type = PORT_S3C6400, + .fifosize = 64, + .has_divslot = 1, + .rx_fifomask = S3C2440_UFSTAT_RXMASK, + .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2440_UFSTAT_RXFULL, + .tx_fifofull = S3C2440_UFSTAT_TXFULL, + .tx_fifomask = S3C2440_UFSTAT_TXMASK, + .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT, + .get_clksrc = s3c6400_serial_getsource, + .set_clksrc = s3c6400_serial_setsource, + .reset_port = s3c6400_serial_resetport, +}; + +/* device management */ + +static int s3c6400_serial_probe(struct platform_device *dev) +{ + dbg("s3c6400_serial_probe: dev=%p\n", dev); + return s3c24xx_serial_probe(dev, &s3c6400_uart_inf); +} + +static struct platform_driver s3c6400_serial_driver = { + .probe = s3c6400_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s3c6400-uart", + .owner = THIS_MODULE, + }, +}; + +s3c24xx_console_init(&s3c6400_serial_driver, &s3c6400_uart_inf); + +static int __init s3c6400_serial_init(void) +{ + return s3c24xx_serial_init(&s3c6400_serial_driver, &s3c6400_uart_inf); +} + +static void __exit s3c6400_serial_exit(void) +{ + platform_driver_unregister(&s3c6400_serial_driver); +} + +module_init(s3c6400_serial_init); +module_exit(s3c6400_serial_exit); + +MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:s3c6400-uart"); diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c new file mode 100644 index 000000000000..6ebccd70a707 --- /dev/null +++ b/drivers/tty/serial/s5pv210.c @@ -0,0 +1,162 @@ +/* linux/drivers/serial/s5pv210.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Based on drivers/serial/s3c6400.c + * + * Driver for Samsung S5PV210 SoC UARTs. + * + * 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "samsung.h" + +static int s5pv210_serial_setsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + struct s3c2410_uartcfg *cfg = port->dev->platform_data; + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + if ((cfg->clocks_size) == 1) + return 0; + + if (strcmp(clk->name, "pclk") == 0) + ucon &= ~S5PV210_UCON_CLKMASK; + else if (strcmp(clk->name, "uclk1") == 0) + ucon |= S5PV210_UCON_CLKMASK; + else { + printk(KERN_ERR "unknown clock source %s\n", clk->name); + return -EINVAL; + } + + wr_regl(port, S3C2410_UCON, ucon); + return 0; +} + + +static int s5pv210_serial_getsource(struct uart_port *port, + struct s3c24xx_uart_clksrc *clk) +{ + struct s3c2410_uartcfg *cfg = port->dev->platform_data; + u32 ucon = rd_regl(port, S3C2410_UCON); + + clk->divisor = 1; + + if ((cfg->clocks_size) == 1) + return 0; + + switch (ucon & S5PV210_UCON_CLKMASK) { + case S5PV210_UCON_PCLK: + clk->name = "pclk"; + break; + case S5PV210_UCON_UCLK: + clk->name = "uclk1"; + break; + } + + return 0; +} + +static int s5pv210_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + unsigned long ucon = rd_regl(port, S3C2410_UCON); + + ucon &= S5PV210_UCON_CLKMASK; + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); + + /* reset both fifos */ + wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); + wr_regl(port, S3C2410_UFCON, cfg->ufcon); + + return 0; +} + +#define S5PV210_UART_DEFAULT_INFO(fifo_size) \ + .name = "Samsung S5PV210 UART0", \ + .type = PORT_S3C6400, \ + .fifosize = fifo_size, \ + .has_divslot = 1, \ + .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ + .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ + .rx_fifofull = S5PV210_UFSTAT_RXFULL, \ + .tx_fifofull = S5PV210_UFSTAT_TXFULL, \ + .tx_fifomask = S5PV210_UFSTAT_TXMASK, \ + .tx_fifoshift = S5PV210_UFSTAT_TXSHIFT, \ + .get_clksrc = s5pv210_serial_getsource, \ + .set_clksrc = s5pv210_serial_setsource, \ + .reset_port = s5pv210_serial_resetport + +static struct s3c24xx_uart_info s5p_port_fifo256 = { + S5PV210_UART_DEFAULT_INFO(256), +}; + +static struct s3c24xx_uart_info s5p_port_fifo64 = { + S5PV210_UART_DEFAULT_INFO(64), +}; + +static struct s3c24xx_uart_info s5p_port_fifo16 = { + S5PV210_UART_DEFAULT_INFO(16), +}; + +static struct s3c24xx_uart_info *s5p_uart_inf[] = { + [0] = &s5p_port_fifo256, + [1] = &s5p_port_fifo64, + [2] = &s5p_port_fifo16, + [3] = &s5p_port_fifo16, +}; + +/* device management */ +static int s5p_serial_probe(struct platform_device *pdev) +{ + return s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]); +} + +static struct platform_driver s5p_serial_driver = { + .probe = s5p_serial_probe, + .remove = __devexit_p(s3c24xx_serial_remove), + .driver = { + .name = "s5pv210-uart", + .owner = THIS_MODULE, + }, +}; + +static int __init s5pv210_serial_console_init(void) +{ + return s3c24xx_serial_initconsole(&s5p_serial_driver, s5p_uart_inf); +} + +console_initcall(s5pv210_serial_console_init); + +static int __init s5p_serial_init(void) +{ + return s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf); +} + +static void __exit s5p_serial_exit(void) +{ + platform_driver_unregister(&s5p_serial_driver); +} + +module_init(s5p_serial_init); +module_exit(s5p_serial_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s5pv210-uart"); +MODULE_DESCRIPTION("Samsung S5PV210 UART Driver support"); +MODULE_AUTHOR("Thomas Abraham "); diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c new file mode 100644 index 000000000000..2199d819a987 --- /dev/null +++ b/drivers/tty/serial/sa1100.c @@ -0,0 +1,918 @@ +/* + * linux/drivers/char/sa1100.c + * + * Driver for SA11x0 serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + */ + +#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* We've been assigned a range on the "Low-density serial ports" major */ +#define SERIAL_SA1100_MAJOR 204 +#define MINOR_START 5 + +#define NR_PORTS 3 + +#define SA1100_ISR_PASS_LIMIT 256 + +/* + * Convert from ignore_status_mask or read_status_mask to UTSR[01] + */ +#define SM_TO_UTSR0(x) ((x) & 0xff) +#define SM_TO_UTSR1(x) ((x) >> 8) +#define UTSR0_TO_SM(x) ((x)) +#define UTSR1_TO_SM(x) ((x) << 8) + +#define UART_GET_UTCR0(sport) __raw_readl((sport)->port.membase + UTCR0) +#define UART_GET_UTCR1(sport) __raw_readl((sport)->port.membase + UTCR1) +#define UART_GET_UTCR2(sport) __raw_readl((sport)->port.membase + UTCR2) +#define UART_GET_UTCR3(sport) __raw_readl((sport)->port.membase + UTCR3) +#define UART_GET_UTSR0(sport) __raw_readl((sport)->port.membase + UTSR0) +#define UART_GET_UTSR1(sport) __raw_readl((sport)->port.membase + UTSR1) +#define UART_GET_CHAR(sport) __raw_readl((sport)->port.membase + UTDR) + +#define UART_PUT_UTCR0(sport,v) __raw_writel((v),(sport)->port.membase + UTCR0) +#define UART_PUT_UTCR1(sport,v) __raw_writel((v),(sport)->port.membase + UTCR1) +#define UART_PUT_UTCR2(sport,v) __raw_writel((v),(sport)->port.membase + UTCR2) +#define UART_PUT_UTCR3(sport,v) __raw_writel((v),(sport)->port.membase + UTCR3) +#define UART_PUT_UTSR0(sport,v) __raw_writel((v),(sport)->port.membase + UTSR0) +#define UART_PUT_UTSR1(sport,v) __raw_writel((v),(sport)->port.membase + UTSR1) +#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR) + +/* + * This is the size of our serial port register set. + */ +#define UART_PORT_SIZE 0x24 + +/* + * This determines how often we check the modem status signals + * for any change. They generally aren't connected to an IRQ + * so we have to poll them. We also check immediately before + * filling the TX fifo incase CTS has been dropped. + */ +#define MCTRL_TIMEOUT (250*HZ/1000) + +struct sa1100_port { + struct uart_port port; + struct timer_list timer; + unsigned int old_status; +}; + +/* + * Handle any change of modem status signal since we were last called. + */ +static void sa1100_mctrl_check(struct sa1100_port *sport) +{ + unsigned int status, changed; + + status = sport->port.ops->get_mctrl(&sport->port); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); +} + +/* + * This is our per-port timeout handler, for checking the + * modem status signals. + */ +static void sa1100_timeout(unsigned long data) +{ + struct sa1100_port *sport = (struct sa1100_port *)data; + unsigned long flags; + + if (sport->port.state) { + spin_lock_irqsave(&sport->port.lock, flags); + sa1100_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +} + +/* + * interrupts disabled on entry + */ +static void sa1100_stop_tx(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + u32 utcr3; + + utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE); + sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS); +} + +/* + * port locked and interrupts disabled + */ +static void sa1100_start_tx(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + u32 utcr3; + + utcr3 = UART_GET_UTCR3(sport); + sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS); + UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE); +} + +/* + * Interrupts enabled + */ +static void sa1100_stop_rx(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + u32 utcr3; + + utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void sa1100_enable_ms(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + mod_timer(&sport->timer, jiffies); +} + +static void +sa1100_rx_chars(struct sa1100_port *sport) +{ + struct tty_struct *tty = sport->port.state->port.tty; + unsigned int status, ch, flg; + + status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | + UTSR0_TO_SM(UART_GET_UTSR0(sport)); + while (status & UTSR1_TO_SM(UTSR1_RNE)) { + ch = UART_GET_CHAR(sport); + + sport->port.icount.rx++; + + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) { + if (status & UTSR1_TO_SM(UTSR1_PRE)) + sport->port.icount.parity++; + else if (status & UTSR1_TO_SM(UTSR1_FRE)) + sport->port.icount.frame++; + if (status & UTSR1_TO_SM(UTSR1_ROR)) + sport->port.icount.overrun++; + + status &= sport->port.read_status_mask; + + if (status & UTSR1_TO_SM(UTSR1_PRE)) + flg = TTY_PARITY; + else if (status & UTSR1_TO_SM(UTSR1_FRE)) + flg = TTY_FRAME; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } + + if (uart_handle_sysrq_char(&sport->port, ch)) + goto ignore_char; + + uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg); + + ignore_char: + status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | + UTSR0_TO_SM(UART_GET_UTSR0(sport)); + } + tty_flip_buffer_push(tty); +} + +static void sa1100_tx_chars(struct sa1100_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + + if (sport->port.x_char) { + UART_PUT_CHAR(sport, sport->port.x_char); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + /* + * Check the modem control lines before + * transmitting anything. + */ + sa1100_mctrl_check(sport); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + sa1100_stop_tx(&sport->port); + return; + } + + /* + * Tried using FIFO (not checking TNF) for fifo fill: + * still had the '4 bytes repeated' problem. + */ + while (UART_GET_UTSR1(sport) & UTSR1_TNF) { + UART_PUT_CHAR(sport, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + sa1100_stop_tx(&sport->port); +} + +static irqreturn_t sa1100_int(int irq, void *dev_id) +{ + struct sa1100_port *sport = dev_id; + unsigned int status, pass_counter = 0; + + spin_lock(&sport->port.lock); + status = UART_GET_UTSR0(sport); + status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; + do { + if (status & (UTSR0_RFS | UTSR0_RID)) { + /* Clear the receiver idle bit, if set */ + if (status & UTSR0_RID) + UART_PUT_UTSR0(sport, UTSR0_RID); + sa1100_rx_chars(sport); + } + + /* Clear the relevant break bits */ + if (status & (UTSR0_RBB | UTSR0_REB)) + UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB)); + + if (status & UTSR0_RBB) + sport->port.icount.brk++; + + if (status & UTSR0_REB) + uart_handle_break(&sport->port); + + if (status & UTSR0_TFS) + sa1100_tx_chars(sport); + if (pass_counter++ > SA1100_ISR_PASS_LIMIT) + break; + status = UART_GET_UTSR0(sport); + status &= SM_TO_UTSR0(sport->port.read_status_mask) | + ~UTSR0_TFS; + } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); + spin_unlock(&sport->port.lock); + + return IRQ_HANDLED; +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int sa1100_tx_empty(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT; +} + +static unsigned int sa1100_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/* + * Interrupts always disabled. + */ +static void sa1100_break_ctl(struct uart_port *port, int break_state) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + unsigned int utcr3; + + spin_lock_irqsave(&sport->port.lock, flags); + utcr3 = UART_GET_UTCR3(sport); + if (break_state == -1) + utcr3 |= UTCR3_BRK; + else + utcr3 &= ~UTCR3_BRK; + UART_PUT_UTCR3(sport, utcr3); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int sa1100_startup(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(sport->port.irq, sa1100_int, 0, + "sa11x0-uart", sport); + if (retval) + return retval; + + /* + * Finally, clear and enable interrupts + */ + UART_PUT_UTSR0(sport, -1); + UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE); + + /* + * Enable modem status interrupts + */ + spin_lock_irq(&sport->port.lock); + sa1100_enable_ms(&sport->port); + spin_unlock_irq(&sport->port.lock); + + return 0; +} + +static void sa1100_shutdown(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + /* + * Stop our timer. + */ + del_timer_sync(&sport->timer); + + /* + * Free the interrupt + */ + free_irq(sport->port.irq, sport); + + /* + * Disable all interrupts, port and break condition. + */ + UART_PUT_UTCR3(sport, 0); +} + +static void +sa1100_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + unsigned int utcr0, old_utcr3, baud, quot; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + + /* + * We only support CS7 and CS8. + */ + while ((termios->c_cflag & CSIZE) != CS7 && + (termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS8) + utcr0 = UTCR0_DSS; + else + utcr0 = 0; + + if (termios->c_cflag & CSTOPB) + utcr0 |= UTCR0_SBS; + if (termios->c_cflag & PARENB) { + utcr0 |= UTCR0_PE; + if (!(termios->c_cflag & PARODD)) + utcr0 |= UTCR0_OES; + } + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS); + sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); + if (termios->c_iflag & INPCK) + sport->port.read_status_mask |= + UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); + if (termios->c_iflag & (BRKINT | PARMRK)) + sport->port.read_status_mask |= + UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); + + /* + * Characters to ignore + */ + sport->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= + UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); + if (termios->c_iflag & IGNBRK) { + sport->port.ignore_status_mask |= + UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= + UTSR1_TO_SM(UTSR1_ROR); + } + + del_timer_sync(&sport->timer); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * disable interrupts and drain transmitter + */ + old_utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)); + + while (UART_GET_UTSR1(sport) & UTSR1_TBY) + barrier(); + + /* then, disable everything */ + UART_PUT_UTCR3(sport, 0); + + /* set the parity, stop bits and data size */ + UART_PUT_UTCR0(sport, utcr0); + + /* set the baud rate */ + quot -= 1; + UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8)); + UART_PUT_UTCR2(sport, (quot & 0xff)); + + UART_PUT_UTSR0(sport, -1); + + UART_PUT_UTCR3(sport, old_utcr3); + + if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) + sa1100_enable_ms(&sport->port); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static const char *sa1100_type(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + return sport->port.type == PORT_SA1100 ? "SA1100" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void sa1100_release_port(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + release_mem_region(sport->port.mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int sa1100_request_port(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, + "sa11x0-uart") != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void sa1100_config_port(struct uart_port *port, int flags) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + if (flags & UART_CONFIG_TYPE && + sa1100_request_port(&sport->port) == 0) + sport->port.type = PORT_SA1100; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_SA1100 and PORT_UNKNOWN + */ +static int +sa1100_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100) + ret = -EINVAL; + if (sport->port.irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + ret = -EINVAL; + if (sport->port.uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)sport->port.mapbase != ser->iomem_base) + ret = -EINVAL; + if (sport->port.iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +static struct uart_ops sa1100_pops = { + .tx_empty = sa1100_tx_empty, + .set_mctrl = sa1100_set_mctrl, + .get_mctrl = sa1100_get_mctrl, + .stop_tx = sa1100_stop_tx, + .start_tx = sa1100_start_tx, + .stop_rx = sa1100_stop_rx, + .enable_ms = sa1100_enable_ms, + .break_ctl = sa1100_break_ctl, + .startup = sa1100_startup, + .shutdown = sa1100_shutdown, + .set_termios = sa1100_set_termios, + .type = sa1100_type, + .release_port = sa1100_release_port, + .request_port = sa1100_request_port, + .config_port = sa1100_config_port, + .verify_port = sa1100_verify_port, +}; + +static struct sa1100_port sa1100_ports[NR_PORTS]; + +/* + * Setup the SA1100 serial ports. Note that we don't include the IrDA + * port here since we have our own SIR/FIR driver (see drivers/net/irda) + * + * Note also that we support "console=ttySAx" where "x" is either 0 or 1. + * Which serial port this ends up being depends on the machine you're + * running this kernel on. I'm not convinced that this is a good idea, + * but that's the way it traditionally works. + * + * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer + * used here. + */ +static void __init sa1100_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < NR_PORTS; i++) { + sa1100_ports[i].port.uartclk = 3686400; + sa1100_ports[i].port.ops = &sa1100_pops; + sa1100_ports[i].port.fifosize = 8; + sa1100_ports[i].port.line = i; + sa1100_ports[i].port.iotype = UPIO_MEM; + init_timer(&sa1100_ports[i].timer); + sa1100_ports[i].timer.function = sa1100_timeout; + sa1100_ports[i].timer.data = (unsigned long)&sa1100_ports[i]; + } + + /* + * make transmit lines outputs, so that when the port + * is closed, the output is in the MARK state. + */ + PPDR |= PPC_TXD1 | PPC_TXD3; + PPSR |= PPC_TXD1 | PPC_TXD3; +} + +void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns) +{ + if (fns->get_mctrl) + sa1100_pops.get_mctrl = fns->get_mctrl; + if (fns->set_mctrl) + sa1100_pops.set_mctrl = fns->set_mctrl; + + sa1100_pops.pm = fns->pm; + sa1100_pops.set_wake = fns->set_wake; +} + +void __init sa1100_register_uart(int idx, int port) +{ + if (idx >= NR_PORTS) { + printk(KERN_ERR "%s: bad index number %d\n", __func__, idx); + return; + } + + switch (port) { + case 1: + sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0; + sa1100_ports[idx].port.mapbase = _Ser1UTCR0; + sa1100_ports[idx].port.irq = IRQ_Ser1UART; + sa1100_ports[idx].port.flags = UPF_BOOT_AUTOCONF; + break; + + case 2: + sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0; + sa1100_ports[idx].port.mapbase = _Ser2UTCR0; + sa1100_ports[idx].port.irq = IRQ_Ser2ICP; + sa1100_ports[idx].port.flags = UPF_BOOT_AUTOCONF; + break; + + case 3: + sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0; + sa1100_ports[idx].port.mapbase = _Ser3UTCR0; + sa1100_ports[idx].port.irq = IRQ_Ser3UART; + sa1100_ports[idx].port.flags = UPF_BOOT_AUTOCONF; + break; + + default: + printk(KERN_ERR "%s: bad port number %d\n", __func__, port); + } +} + + +#ifdef CONFIG_SERIAL_SA1100_CONSOLE +static void sa1100_console_putchar(struct uart_port *port, int ch) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + while (!(UART_GET_UTSR1(sport) & UTSR1_TNF)) + barrier(); + UART_PUT_CHAR(sport, ch); +} + +/* + * Interrupts are disabled on entering + */ +static void +sa1100_console_write(struct console *co, const char *s, unsigned int count) +{ + struct sa1100_port *sport = &sa1100_ports[co->index]; + unsigned int old_utcr3, status; + + /* + * First, save UTCR3 and then disable interrupts + */ + old_utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) | + UTCR3_TXE); + + uart_console_write(&sport->port, s, count, sa1100_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore UTCR3 + */ + do { + status = UART_GET_UTSR1(sport); + } while (status & UTSR1_TBY); + UART_PUT_UTCR3(sport, old_utcr3); +} + +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +sa1100_console_get_options(struct sa1100_port *sport, int *baud, + int *parity, int *bits) +{ + unsigned int utcr3; + + utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE); + if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) { + /* ok, the port was enabled */ + unsigned int utcr0, quot; + + utcr0 = UART_GET_UTCR0(sport); + + *parity = 'n'; + if (utcr0 & UTCR0_PE) { + if (utcr0 & UTCR0_OES) + *parity = 'e'; + else + *parity = 'o'; + } + + if (utcr0 & UTCR0_DSS) + *bits = 8; + else + *bits = 7; + + quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8; + quot &= 0xfff; + *baud = sport->port.uartclk / (16 * (quot + 1)); + } +} + +static int __init +sa1100_console_setup(struct console *co, char *options) +{ + struct sa1100_port *sport; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= NR_PORTS) + co->index = 0; + sport = &sa1100_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + sa1100_console_get_options(sport, &baud, &parity, &bits); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver sa1100_reg; +static struct console sa1100_console = { + .name = "ttySA", + .write = sa1100_console_write, + .device = uart_console_device, + .setup = sa1100_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sa1100_reg, +}; + +static int __init sa1100_rs_console_init(void) +{ + sa1100_init_ports(); + register_console(&sa1100_console); + return 0; +} +console_initcall(sa1100_rs_console_init); + +#define SA1100_CONSOLE &sa1100_console +#else +#define SA1100_CONSOLE NULL +#endif + +static struct uart_driver sa1100_reg = { + .owner = THIS_MODULE, + .driver_name = "ttySA", + .dev_name = "ttySA", + .major = SERIAL_SA1100_MAJOR, + .minor = MINOR_START, + .nr = NR_PORTS, + .cons = SA1100_CONSOLE, +}; + +static int sa1100_serial_suspend(struct platform_device *dev, pm_message_t state) +{ + struct sa1100_port *sport = platform_get_drvdata(dev); + + if (sport) + uart_suspend_port(&sa1100_reg, &sport->port); + + return 0; +} + +static int sa1100_serial_resume(struct platform_device *dev) +{ + struct sa1100_port *sport = platform_get_drvdata(dev); + + if (sport) + uart_resume_port(&sa1100_reg, &sport->port); + + return 0; +} + +static int sa1100_serial_probe(struct platform_device *dev) +{ + struct resource *res = dev->resource; + int i; + + for (i = 0; i < dev->num_resources; i++, res++) + if (res->flags & IORESOURCE_MEM) + break; + + if (i < dev->num_resources) { + for (i = 0; i < NR_PORTS; i++) { + if (sa1100_ports[i].port.mapbase != res->start) + continue; + + sa1100_ports[i].port.dev = &dev->dev; + uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port); + platform_set_drvdata(dev, &sa1100_ports[i]); + break; + } + } + + return 0; +} + +static int sa1100_serial_remove(struct platform_device *pdev) +{ + struct sa1100_port *sport = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (sport) + uart_remove_one_port(&sa1100_reg, &sport->port); + + return 0; +} + +static struct platform_driver sa11x0_serial_driver = { + .probe = sa1100_serial_probe, + .remove = sa1100_serial_remove, + .suspend = sa1100_serial_suspend, + .resume = sa1100_serial_resume, + .driver = { + .name = "sa11x0-uart", + .owner = THIS_MODULE, + }, +}; + +static int __init sa1100_serial_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: SA11x0 driver\n"); + + sa1100_init_ports(); + + ret = uart_register_driver(&sa1100_reg); + if (ret == 0) { + ret = platform_driver_register(&sa11x0_serial_driver); + if (ret) + uart_unregister_driver(&sa1100_reg); + } + return ret; +} + +static void __exit sa1100_serial_exit(void) +{ + platform_driver_unregister(&sa11x0_serial_driver); + uart_unregister_driver(&sa1100_reg); +} + +module_init(sa1100_serial_init); +module_exit(sa1100_serial_exit); + +MODULE_AUTHOR("Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("SA1100 generic serial port driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR); +MODULE_ALIAS("platform:sa11x0-uart"); diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c new file mode 100644 index 000000000000..7ac2bf5167cd --- /dev/null +++ b/drivers/tty/serial/samsung.c @@ -0,0 +1,1487 @@ +/* linux/drivers/serial/samsuing.c + * + * Driver core for Samsung SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +/* Hote on 2410 error handling + * + * The s3c2410 manual has a love/hate affair with the contents of the + * UERSTAT register in the UART blocks, and keeps marking some of the + * error bits as reserved. Having checked with the s3c2410x01, + * it copes with BREAKs properly, so I am happy to ignore the RESERVED + * feature from the latter versions of the manual. + * + * If it becomes aparrent that latter versions of the 2410 remove these + * bits, then action will have to be taken to differentiate the versions + * and change the policy on BREAK + * + * BJD, 04-Nov-2004 +*/ + +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "samsung.h" + +/* UART name and device definitions */ + +#define S3C24XX_SERIAL_NAME "ttySAC" +#define S3C24XX_SERIAL_MAJOR 204 +#define S3C24XX_SERIAL_MINOR 64 + +/* macros to change one thing to another */ + +#define tx_enabled(port) ((port)->unused[0]) +#define rx_enabled(port) ((port)->unused[1]) + +/* flag to ignore all characters comming in */ +#define RXSTAT_DUMMY_READ (0x10000000) + +static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port) +{ + return container_of(port, struct s3c24xx_uart_port, port); +} + +/* translate a port to the device name */ + +static inline const char *s3c24xx_serial_portname(struct uart_port *port) +{ + return to_platform_device(port->dev)->name; +} + +static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) +{ + return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE); +} + +static void s3c24xx_serial_rx_enable(struct uart_port *port) +{ + unsigned long flags; + unsigned int ucon, ufcon; + int count = 10000; + + spin_lock_irqsave(&port->lock, flags); + + while (--count && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX; + wr_regl(port, S3C2410_UFCON, ufcon); + + ucon = rd_regl(port, S3C2410_UCON); + ucon |= S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + rx_enabled(port) = 1; + spin_unlock_irqrestore(&port->lock, flags); +} + +static void s3c24xx_serial_rx_disable(struct uart_port *port) +{ + unsigned long flags; + unsigned int ucon; + + spin_lock_irqsave(&port->lock, flags); + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~S3C2410_UCON_RXIRQMODE; + wr_regl(port, S3C2410_UCON, ucon); + + rx_enabled(port) = 0; + spin_unlock_irqrestore(&port->lock, flags); +} + +static void s3c24xx_serial_stop_tx(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + if (tx_enabled(port)) { + disable_irq_nosync(ourport->tx_irq); + tx_enabled(port) = 0; + if (port->flags & UPF_CONS_FLOW) + s3c24xx_serial_rx_enable(port); + } +} + +static void s3c24xx_serial_start_tx(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + if (!tx_enabled(port)) { + if (port->flags & UPF_CONS_FLOW) + s3c24xx_serial_rx_disable(port); + + enable_irq(ourport->tx_irq); + tx_enabled(port) = 1; + } +} + + +static void s3c24xx_serial_stop_rx(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + if (rx_enabled(port)) { + dbg("s3c24xx_serial_stop_rx: port=%p\n", port); + disable_irq_nosync(ourport->rx_irq); + rx_enabled(port) = 0; + } +} + +static void s3c24xx_serial_enable_ms(struct uart_port *port) +{ +} + +static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port) +{ + return to_ourport(port)->info; +} + +static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port) +{ + if (port->dev == NULL) + return NULL; + + return (struct s3c2410_uartcfg *)port->dev->platform_data; +} + +static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, + unsigned long ufstat) +{ + struct s3c24xx_uart_info *info = ourport->info; + + if (ufstat & info->rx_fifofull) + return info->fifosize; + + return (ufstat & info->rx_fifomask) >> info->rx_fifoshift; +} + + +/* ? - where has parity gone?? */ +#define S3C2410_UERSTAT_PARITY (0x1000) + +static irqreturn_t +s3c24xx_serial_rx_chars(int irq, void *dev_id) +{ + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + struct tty_struct *tty = port->state->port.tty; + unsigned int ufcon, ch, flag, ufstat, uerstat; + int max_count = 64; + + while (max_count-- > 0) { + ufcon = rd_regl(port, S3C2410_UFCON); + ufstat = rd_regl(port, S3C2410_UFSTAT); + + if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) + break; + + uerstat = rd_regl(port, S3C2410_UERSTAT); + ch = rd_regb(port, S3C2410_URXH); + + if (port->flags & UPF_CONS_FLOW) { + int txe = s3c24xx_serial_txempty_nofifo(port); + + if (rx_enabled(port)) { + if (!txe) { + rx_enabled(port) = 0; + continue; + } + } else { + if (txe) { + ufcon |= S3C2410_UFCON_RESETRX; + wr_regl(port, S3C2410_UFCON, ufcon); + rx_enabled(port) = 1; + goto out; + } + continue; + } + } + + /* insert the character into the buffer */ + + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { + dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", + ch, uerstat); + + /* check for break */ + if (uerstat & S3C2410_UERSTAT_BREAK) { + dbg("break!\n"); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } + + if (uerstat & S3C2410_UERSTAT_FRAME) + port->icount.frame++; + if (uerstat & S3C2410_UERSTAT_OVERRUN) + port->icount.overrun++; + + uerstat &= port->read_status_mask; + + if (uerstat & S3C2410_UERSTAT_BREAK) + flag = TTY_BREAK; + else if (uerstat & S3C2410_UERSTAT_PARITY) + flag = TTY_PARITY; + else if (uerstat & (S3C2410_UERSTAT_FRAME | + S3C2410_UERSTAT_OVERRUN)) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, + ch, flag); + + ignore_char: + continue; + } + tty_flip_buffer_push(tty); + + out: + return IRQ_HANDLED; +} + +static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + struct circ_buf *xmit = &port->state->xmit; + int count = 256; + + if (port->x_char) { + wr_regb(port, S3C2410_UTXH, port->x_char); + port->icount.tx++; + port->x_char = 0; + goto out; + } + + /* if there isnt anything more to transmit, or the uart is now + * stopped, disable the uart and exit + */ + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + s3c24xx_serial_stop_tx(port); + goto out; + } + + /* try and drain the buffer... */ + + while (!uart_circ_empty(xmit) && count-- > 0) { + if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) + break; + + wr_regb(port, S3C2410_UTXH, 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); + + if (uart_circ_empty(xmit)) + s3c24xx_serial_stop_tx(port); + + out: + return IRQ_HANDLED; +} + +static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); + unsigned long ufcon = rd_regl(port, S3C2410_UFCON); + + if (ufcon & S3C2410_UFCON_FIFOMODE) { + if ((ufstat & info->tx_fifomask) != 0 || + (ufstat & info->tx_fifofull)) + return 0; + + return 1; + } + + return s3c24xx_serial_txempty_nofifo(port); +} + +/* no modem control lines */ +static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) +{ + unsigned int umstat = rd_regb(port, S3C2410_UMSTAT); + + if (umstat & S3C2410_UMSTAT_CTS) + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + else + return TIOCM_CAR | TIOCM_DSR; +} + +static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* todo - possibly remove AFC and do manual CTS */ +} + +static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int ucon; + + spin_lock_irqsave(&port->lock, flags); + + ucon = rd_regl(port, S3C2410_UCON); + + if (break_state) + ucon |= S3C2410_UCON_SBREAK; + else + ucon &= ~S3C2410_UCON_SBREAK; + + wr_regl(port, S3C2410_UCON, ucon); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void s3c24xx_serial_shutdown(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + if (ourport->tx_claimed) { + free_irq(ourport->tx_irq, ourport); + tx_enabled(port) = 0; + ourport->tx_claimed = 0; + } + + if (ourport->rx_claimed) { + free_irq(ourport->rx_irq, ourport); + ourport->rx_claimed = 0; + rx_enabled(port) = 0; + } +} + + +static int s3c24xx_serial_startup(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + int ret; + + dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", + port->mapbase, port->membase); + + rx_enabled(port) = 1; + + ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, + s3c24xx_serial_portname(port), ourport); + + if (ret != 0) { + printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); + return ret; + } + + ourport->rx_claimed = 1; + + dbg("requesting tx irq...\n"); + + tx_enabled(port) = 1; + + ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, + s3c24xx_serial_portname(port), ourport); + + if (ret) { + printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); + goto err; + } + + ourport->tx_claimed = 1; + + dbg("s3c24xx_serial_startup ok\n"); + + /* the port reset code should have done the correct + * register setup for the port controls */ + + return ret; + + err: + s3c24xx_serial_shutdown(port); + return ret; +} + +/* power power management control */ + +static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, + unsigned int old) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + ourport->pm_level = level; + + switch (level) { + case 3: + if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) + clk_disable(ourport->baudclk); + + clk_disable(ourport->clk); + break; + + case 0: + clk_enable(ourport->clk); + + if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) + clk_enable(ourport->baudclk); + + break; + default: + printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level); + } +} + +/* baud rate calculation + * + * The UARTs on the S3C2410/S3C2440 can take their clocks from a number + * of different sources, including the peripheral clock ("pclk") and an + * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk") + * with a programmable extra divisor. + * + * The following code goes through the clock sources, and calculates the + * baud clocks (and the resultant actual baud rates) and then tries to + * pick the closest one and select that. + * +*/ + + +#define MAX_CLKS (8) + +static struct s3c24xx_uart_clksrc tmp_clksrc = { + .name = "pclk", + .min_baud = 0, + .max_baud = 0, + .divisor = 1, +}; + +static inline int +s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + + return (info->get_clksrc)(port, c); +} + +static inline int +s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + + return (info->set_clksrc)(port, c); +} + +struct baud_calc { + struct s3c24xx_uart_clksrc *clksrc; + unsigned int calc; + unsigned int divslot; + unsigned int quot; + struct clk *src; +}; + +static int s3c24xx_serial_calcbaud(struct baud_calc *calc, + struct uart_port *port, + struct s3c24xx_uart_clksrc *clksrc, + unsigned int baud) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long rate; + + calc->src = clk_get(port->dev, clksrc->name); + if (calc->src == NULL || IS_ERR(calc->src)) + return 0; + + rate = clk_get_rate(calc->src); + rate /= clksrc->divisor; + + calc->clksrc = clksrc; + + if (ourport->info->has_divslot) { + unsigned long div = rate / baud; + + /* The UDIVSLOT register on the newer UARTs allows us to + * get a divisor adjustment of 1/16th on the baud clock. + * + * We don't keep the UDIVSLOT value (the 16ths we calculated + * by not multiplying the baud by 16) as it is easy enough + * to recalculate. + */ + + calc->quot = div / 16; + calc->calc = rate / div; + } else { + calc->quot = (rate + (8 * baud)) / (16 * baud); + calc->calc = (rate / (calc->quot * 16)); + } + + calc->quot--; + return 1; +} + +static unsigned int s3c24xx_serial_getclk(struct uart_port *port, + struct s3c24xx_uart_clksrc **clksrc, + struct clk **clk, + unsigned int baud) +{ + struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); + struct s3c24xx_uart_clksrc *clkp; + struct baud_calc res[MAX_CLKS]; + struct baud_calc *resptr, *best, *sptr; + int i; + + clkp = cfg->clocks; + best = NULL; + + if (cfg->clocks_size < 2) { + if (cfg->clocks_size == 0) + clkp = &tmp_clksrc; + + /* check to see if we're sourcing fclk, and if so we're + * going to have to update the clock source + */ + + if (strcmp(clkp->name, "fclk") == 0) { + struct s3c24xx_uart_clksrc src; + + s3c24xx_serial_getsource(port, &src); + + /* check that the port already using fclk, and if + * not, then re-select fclk + */ + + if (strcmp(src.name, clkp->name) == 0) { + s3c24xx_serial_setsource(port, clkp); + s3c24xx_serial_getsource(port, &src); + } + + clkp->divisor = src.divisor; + } + + s3c24xx_serial_calcbaud(res, port, clkp, baud); + best = res; + resptr = best + 1; + } else { + resptr = res; + + for (i = 0; i < cfg->clocks_size; i++, clkp++) { + if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud)) + resptr++; + } + } + + /* ok, we now need to select the best clock we found */ + + if (!best) { + unsigned int deviation = (1<<30)|((1<<30)-1); + int calc_deviation; + + for (sptr = res; sptr < resptr; sptr++) { + calc_deviation = baud - sptr->calc; + if (calc_deviation < 0) + calc_deviation = -calc_deviation; + + if (calc_deviation < deviation) { + best = sptr; + deviation = calc_deviation; + } + } + } + + /* store results to pass back */ + + *clksrc = best->clksrc; + *clk = best->src; + + return best->quot; +} + +/* udivslot_table[] + * + * This table takes the fractional value of the baud divisor and gives + * the recommended setting for the UDIVSLOT register. + */ +static u16 udivslot_table[16] = { + [0] = 0x0000, + [1] = 0x0080, + [2] = 0x0808, + [3] = 0x0888, + [4] = 0x2222, + [5] = 0x4924, + [6] = 0x4A52, + [7] = 0x54AA, + [8] = 0x5555, + [9] = 0xD555, + [10] = 0xD5D5, + [11] = 0xDDD5, + [12] = 0xDDDD, + [13] = 0xDFDD, + [14] = 0xDFDF, + [15] = 0xFFDF, +}; + +static void s3c24xx_serial_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); + struct s3c24xx_uart_port *ourport = to_ourport(port); + struct s3c24xx_uart_clksrc *clksrc = NULL; + struct clk *clk = NULL; + unsigned long flags; + unsigned int baud, quot; + unsigned int ulcon; + unsigned int umcon; + unsigned int udivslot = 0; + + /* + * We don't support modem control lines. + */ + termios->c_cflag &= ~(HUPCL | CMSPAR); + termios->c_cflag |= CLOCAL; + + /* + * Ask the core to calculate the divisor for us. + */ + + baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); + + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) + quot = port->custom_divisor; + else + quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); + + /* check to see if we need to change clock source */ + + if (ourport->clksrc != clksrc || ourport->baudclk != clk) { + dbg("selecting clock %p\n", clk); + s3c24xx_serial_setsource(port, clksrc); + + if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { + clk_disable(ourport->baudclk); + ourport->baudclk = NULL; + } + + clk_enable(clk); + + ourport->clksrc = clksrc; + ourport->baudclk = clk; + ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; + } + + if (ourport->info->has_divslot) { + unsigned int div = ourport->baudclk_rate / baud; + + if (cfg->has_fracval) { + udivslot = (div & 15); + dbg("fracval = %04x\n", udivslot); + } else { + udivslot = udivslot_table[div & 15]; + dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); + } + } + + switch (termios->c_cflag & CSIZE) { + case CS5: + dbg("config: 5bits/char\n"); + ulcon = S3C2410_LCON_CS5; + break; + case CS6: + dbg("config: 6bits/char\n"); + ulcon = S3C2410_LCON_CS6; + break; + case CS7: + dbg("config: 7bits/char\n"); + ulcon = S3C2410_LCON_CS7; + break; + case CS8: + default: + dbg("config: 8bits/char\n"); + ulcon = S3C2410_LCON_CS8; + break; + } + + /* preserve original lcon IR settings */ + ulcon |= (cfg->ulcon & S3C2410_LCON_IRM); + + if (termios->c_cflag & CSTOPB) + ulcon |= S3C2410_LCON_STOPB; + + umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; + + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + ulcon |= S3C2410_LCON_PODD; + else + ulcon |= S3C2410_LCON_PEVEN; + } else { + ulcon |= S3C2410_LCON_PNONE; + } + + spin_lock_irqsave(&port->lock, flags); + + dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", + ulcon, quot, udivslot); + + wr_regl(port, S3C2410_ULCON, ulcon); + wr_regl(port, S3C2410_UBRDIV, quot); + wr_regl(port, S3C2410_UMCON, umcon); + + if (ourport->info->has_divslot) + wr_regl(port, S3C2443_DIVSLOT, udivslot); + + dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", + rd_regl(port, S3C2410_ULCON), + rd_regl(port, S3C2410_UCON), + rd_regl(port, S3C2410_UFCON)); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* + * Which character status flags are we interested in? + */ + port->read_status_mask = S3C2410_UERSTAT_OVERRUN; + if (termios->c_iflag & INPCK) + port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY; + + /* + * Which character status flags should we ignore? + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN; + if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) + port->ignore_status_mask |= S3C2410_UERSTAT_FRAME; + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *s3c24xx_serial_type(struct uart_port *port) +{ + switch (port->type) { + case PORT_S3C2410: + return "S3C2410"; + case PORT_S3C2440: + return "S3C2440"; + case PORT_S3C2412: + return "S3C2412"; + case PORT_S3C6400: + return "S3C6400/10"; + default: + return NULL; + } +} + +#define MAP_SIZE (0x100) + +static void s3c24xx_serial_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, MAP_SIZE); +} + +static int s3c24xx_serial_request_port(struct uart_port *port) +{ + const char *name = s3c24xx_serial_portname(port); + return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY; +} + +static void s3c24xx_serial_config_port(struct uart_port *port, int flags) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + + if (flags & UART_CONFIG_TYPE && + s3c24xx_serial_request_port(port) == 0) + port->type = info->type; +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int +s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + + if (ser->type != PORT_UNKNOWN && ser->type != info->type) + return -EINVAL; + + return 0; +} + + +#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE + +static struct console s3c24xx_serial_console; + +#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console +#else +#define S3C24XX_SERIAL_CONSOLE NULL +#endif + +static struct uart_ops s3c24xx_serial_ops = { + .pm = s3c24xx_serial_pm, + .tx_empty = s3c24xx_serial_tx_empty, + .get_mctrl = s3c24xx_serial_get_mctrl, + .set_mctrl = s3c24xx_serial_set_mctrl, + .stop_tx = s3c24xx_serial_stop_tx, + .start_tx = s3c24xx_serial_start_tx, + .stop_rx = s3c24xx_serial_stop_rx, + .enable_ms = s3c24xx_serial_enable_ms, + .break_ctl = s3c24xx_serial_break_ctl, + .startup = s3c24xx_serial_startup, + .shutdown = s3c24xx_serial_shutdown, + .set_termios = s3c24xx_serial_set_termios, + .type = s3c24xx_serial_type, + .release_port = s3c24xx_serial_release_port, + .request_port = s3c24xx_serial_request_port, + .config_port = s3c24xx_serial_config_port, + .verify_port = s3c24xx_serial_verify_port, +}; + + +static struct uart_driver s3c24xx_uart_drv = { + .owner = THIS_MODULE, + .dev_name = "s3c2410_serial", + .nr = CONFIG_SERIAL_SAMSUNG_UARTS, + .cons = S3C24XX_SERIAL_CONSOLE, + .driver_name = S3C24XX_SERIAL_NAME, + .major = S3C24XX_SERIAL_MAJOR, + .minor = S3C24XX_SERIAL_MINOR, +}; + +static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { + [0] = { + .port = { + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), + .iotype = UPIO_MEM, + .irq = IRQ_S3CUART_RX0, + .uartclk = 0, + .fifosize = 16, + .ops = &s3c24xx_serial_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 0, + } + }, + [1] = { + .port = { + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), + .iotype = UPIO_MEM, + .irq = IRQ_S3CUART_RX1, + .uartclk = 0, + .fifosize = 16, + .ops = &s3c24xx_serial_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 1, + } + }, +#if CONFIG_SERIAL_SAMSUNG_UARTS > 2 + + [2] = { + .port = { + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), + .iotype = UPIO_MEM, + .irq = IRQ_S3CUART_RX2, + .uartclk = 0, + .fifosize = 16, + .ops = &s3c24xx_serial_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 2, + } + }, +#endif +#if CONFIG_SERIAL_SAMSUNG_UARTS > 3 + [3] = { + .port = { + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), + .iotype = UPIO_MEM, + .irq = IRQ_S3CUART_RX3, + .uartclk = 0, + .fifosize = 16, + .ops = &s3c24xx_serial_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 3, + } + } +#endif +}; + +/* s3c24xx_serial_resetport + * + * wrapper to call the specific reset for this port (reset the fifos + * and the settings) +*/ + +static inline int s3c24xx_serial_resetport(struct uart_port *port, + struct s3c2410_uartcfg *cfg) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + + return (info->reset_port)(port, cfg); +} + + +#ifdef CONFIG_CPU_FREQ + +static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct s3c24xx_uart_port *port; + struct uart_port *uport; + + port = container_of(nb, struct s3c24xx_uart_port, freq_transition); + uport = &port->port; + + /* check to see if port is enabled */ + + if (port->pm_level != 0) + return 0; + + /* try and work out if the baudrate is changing, we can detect + * a change in rate, but we do not have support for detecting + * a disturbance in the clock-rate over the change. + */ + + if (IS_ERR(port->clk)) + goto exit; + + if (port->baudclk_rate == clk_get_rate(port->clk)) + goto exit; + + if (val == CPUFREQ_PRECHANGE) { + /* we should really shut the port down whilst the + * frequency change is in progress. */ + + } else if (val == CPUFREQ_POSTCHANGE) { + struct ktermios *termios; + struct tty_struct *tty; + + if (uport->state == NULL) + goto exit; + + tty = uport->state->port.tty; + + if (tty == NULL) + goto exit; + + termios = tty->termios; + + if (termios == NULL) { + printk(KERN_WARNING "%s: no termios?\n", __func__); + goto exit; + } + + s3c24xx_serial_set_termios(uport, termios, NULL); + } + + exit: + return 0; +} + +static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) +{ + port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition; + + return cpufreq_register_notifier(&port->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) +{ + cpufreq_unregister_notifier(&port->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) +{ + return 0; +} + +static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) +{ +} +#endif + +/* s3c24xx_serial_init_port + * + * initialise a single serial port from the platform device given + */ + +static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, + struct s3c24xx_uart_info *info, + struct platform_device *platdev) +{ + struct uart_port *port = &ourport->port; + struct s3c2410_uartcfg *cfg; + struct resource *res; + int ret; + + dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev); + + if (platdev == NULL) + return -ENODEV; + + cfg = s3c24xx_dev_to_cfg(&platdev->dev); + + if (port->mapbase != 0) + return 0; + + if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) { + printk(KERN_ERR "%s: port %d bigger than %d\n", __func__, + cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS); + return -ERANGE; + } + + /* setup info for port */ + port->dev = &platdev->dev; + ourport->info = info; + + /* copy the info in from provided structure */ + ourport->port.fifosize = info->fifosize; + + dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport); + + port->uartclk = 1; + + if (cfg->uart_flags & UPF_CONS_FLOW) { + dbg("s3c24xx_serial_init_port: enabling flow control\n"); + port->flags |= UPF_CONS_FLOW; + } + + /* sort our the physical and virtual addresses for each UART */ + + res = platform_get_resource(platdev, IORESOURCE_MEM, 0); + if (res == NULL) { + printk(KERN_ERR "failed to find memory resource for uart\n"); + return -EINVAL; + } + + dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); + + port->mapbase = res->start; + port->membase = S3C_VA_UART + (res->start & 0xfffff); + ret = platform_get_irq(platdev, 0); + if (ret < 0) + port->irq = 0; + else { + port->irq = ret; + ourport->rx_irq = ret; + ourport->tx_irq = ret + 1; + } + + ret = platform_get_irq(platdev, 1); + if (ret > 0) + ourport->tx_irq = ret; + + ourport->clk = clk_get(&platdev->dev, "uart"); + + dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", + port->mapbase, port->membase, port->irq, + ourport->rx_irq, ourport->tx_irq, port->uartclk); + + /* reset the fifos (and setup the uart) */ + s3c24xx_serial_resetport(port, cfg); + return 0; +} + +static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct uart_port *port = s3c24xx_dev_to_port(dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); + + return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name); +} + +static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); + +/* Device driver serial port probe */ + +static int probe_index; + +int s3c24xx_serial_probe(struct platform_device *dev, + struct s3c24xx_uart_info *info) +{ + struct s3c24xx_uart_port *ourport; + int ret; + + dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index); + + ourport = &s3c24xx_serial_ports[probe_index]; + probe_index++; + + dbg("%s: initialising port %p...\n", __func__, ourport); + + ret = s3c24xx_serial_init_port(ourport, info, dev); + if (ret < 0) + goto probe_err; + + dbg("%s: adding port\n", __func__); + uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); + platform_set_drvdata(dev, &ourport->port); + + ret = device_create_file(&dev->dev, &dev_attr_clock_source); + if (ret < 0) + printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); + + ret = s3c24xx_serial_cpufreq_register(ourport); + if (ret < 0) + dev_err(&dev->dev, "failed to add cpufreq notifier\n"); + + return 0; + + probe_err: + return ret; +} + +EXPORT_SYMBOL_GPL(s3c24xx_serial_probe); + +int __devexit s3c24xx_serial_remove(struct platform_device *dev) +{ + struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); + + if (port) { + s3c24xx_serial_cpufreq_deregister(to_ourport(port)); + device_remove_file(&dev->dev, &dev_attr_clock_source); + uart_remove_one_port(&s3c24xx_uart_drv, port); + } + + return 0; +} + +EXPORT_SYMBOL_GPL(s3c24xx_serial_remove); + +/* UART power management code */ + +#ifdef CONFIG_PM + +static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state) +{ + struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); + + if (port) + uart_suspend_port(&s3c24xx_uart_drv, port); + + return 0; +} + +static int s3c24xx_serial_resume(struct platform_device *dev) +{ + struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); + + if (port) { + clk_enable(ourport->clk); + s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); + clk_disable(ourport->clk); + + uart_resume_port(&s3c24xx_uart_drv, port); + } + + return 0; +} +#endif + +int s3c24xx_serial_init(struct platform_driver *drv, + struct s3c24xx_uart_info *info) +{ + dbg("s3c24xx_serial_init(%p,%p)\n", drv, info); + +#ifdef CONFIG_PM + drv->suspend = s3c24xx_serial_suspend; + drv->resume = s3c24xx_serial_resume; +#endif + + return platform_driver_register(drv); +} + +EXPORT_SYMBOL_GPL(s3c24xx_serial_init); + +/* module initialisation code */ + +static int __init s3c24xx_serial_modinit(void) +{ + int ret; + + ret = uart_register_driver(&s3c24xx_uart_drv); + if (ret < 0) { + printk(KERN_ERR "failed to register UART driver\n"); + return -1; + } + + return 0; +} + +static void __exit s3c24xx_serial_modexit(void) +{ + uart_unregister_driver(&s3c24xx_uart_drv); +} + +module_init(s3c24xx_serial_modinit); +module_exit(s3c24xx_serial_modexit); + +/* Console code */ + +#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE + +static struct uart_port *cons_uart; + +static int +s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) +{ + struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); + unsigned long ufstat, utrstat; + + if (ufcon & S3C2410_UFCON_FIFOMODE) { + /* fifo mode - check amount of data in fifo registers... */ + + ufstat = rd_regl(port, S3C2410_UFSTAT); + return (ufstat & info->tx_fifofull) ? 0 : 1; + } + + /* in non-fifo mode, we go and use the tx buffer empty */ + + utrstat = rd_regl(port, S3C2410_UTRSTAT); + return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0; +} + +static void +s3c24xx_serial_console_putchar(struct uart_port *port, int ch) +{ + unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); + while (!s3c24xx_serial_console_txrdy(port, ufcon)) + barrier(); + wr_regb(cons_uart, S3C2410_UTXH, ch); +} + +static void +s3c24xx_serial_console_write(struct console *co, const char *s, + unsigned int count) +{ + uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); +} + +static void __init +s3c24xx_serial_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + struct s3c24xx_uart_clksrc clksrc; + struct clk *clk; + unsigned int ulcon; + unsigned int ucon; + unsigned int ubrdiv; + unsigned long rate; + + ulcon = rd_regl(port, S3C2410_ULCON); + ucon = rd_regl(port, S3C2410_UCON); + ubrdiv = rd_regl(port, S3C2410_UBRDIV); + + dbg("s3c24xx_serial_get_options: port=%p\n" + "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n", + port, ulcon, ucon, ubrdiv); + + if ((ucon & 0xf) != 0) { + /* consider the serial port configured if the tx/rx mode set */ + + switch (ulcon & S3C2410_LCON_CSMASK) { + case S3C2410_LCON_CS5: + *bits = 5; + break; + case S3C2410_LCON_CS6: + *bits = 6; + break; + case S3C2410_LCON_CS7: + *bits = 7; + break; + default: + case S3C2410_LCON_CS8: + *bits = 8; + break; + } + + switch (ulcon & S3C2410_LCON_PMASK) { + case S3C2410_LCON_PEVEN: + *parity = 'e'; + break; + + case S3C2410_LCON_PODD: + *parity = 'o'; + break; + + case S3C2410_LCON_PNONE: + default: + *parity = 'n'; + } + + /* now calculate the baud rate */ + + s3c24xx_serial_getsource(port, &clksrc); + + clk = clk_get(port->dev, clksrc.name); + if (!IS_ERR(clk) && clk != NULL) + rate = clk_get_rate(clk) / clksrc.divisor; + else + rate = 1; + + + *baud = rate / (16 * (ubrdiv + 1)); + dbg("calculated baud %d\n", *baud); + } + +} + +/* s3c24xx_serial_init_ports + * + * initialise the serial ports from the machine provided initialisation + * data. +*/ + +static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info) +{ + struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports; + struct platform_device **platdev_ptr; + int i; + + dbg("s3c24xx_serial_init_ports: initialising ports...\n"); + + platdev_ptr = s3c24xx_uart_devs; + + for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) { + s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr); + } + + return 0; +} + +static int __init +s3c24xx_serial_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n", + co, co->index, options); + + /* is this a valid port */ + + if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS) + co->index = 0; + + port = &s3c24xx_serial_ports[co->index].port; + + /* is the port configured? */ + + if (port->mapbase == 0x0) { + co->index = 0; + port = &s3c24xx_serial_ports[co->index].port; + } + + cons_uart = port; + + dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index); + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + s3c24xx_serial_get_options(port, &baud, &parity, &bits); + + dbg("s3c24xx_serial_console_setup: baud %d\n", baud); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +/* s3c24xx_serial_initconsole + * + * initialise the console from one of the uart drivers +*/ + +static struct console s3c24xx_serial_console = { + .name = S3C24XX_SERIAL_NAME, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + .write = s3c24xx_serial_console_write, + .setup = s3c24xx_serial_console_setup +}; + +int s3c24xx_serial_initconsole(struct platform_driver *drv, + struct s3c24xx_uart_info **info) + +{ + struct platform_device *dev = s3c24xx_uart_devs[0]; + + dbg("s3c24xx_serial_initconsole\n"); + + /* select driver based on the cpu */ + + if (dev == NULL) { + printk(KERN_ERR "s3c24xx: no devices for console init\n"); + return 0; + } + + if (strcmp(dev->name, drv->driver.name) != 0) + return 0; + + s3c24xx_serial_console.data = &s3c24xx_uart_drv; + s3c24xx_serial_init_ports(info); + + register_console(&s3c24xx_serial_console); + return 0; +} + +#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */ + +MODULE_DESCRIPTION("Samsung SoC Serial port driver"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h new file mode 100644 index 000000000000..0ac06a07d25f --- /dev/null +++ b/drivers/tty/serial/samsung.h @@ -0,0 +1,120 @@ +/* linux/drivers/serial/samsung.h + * + * Driver for Samsung SoC onboard UARTs. + * + * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + +struct s3c24xx_uart_info { + char *name; + unsigned int type; + unsigned int fifosize; + unsigned long rx_fifomask; + unsigned long rx_fifoshift; + unsigned long rx_fifofull; + unsigned long tx_fifomask; + unsigned long tx_fifoshift; + unsigned long tx_fifofull; + + /* uart port features */ + + unsigned int has_divslot:1; + + /* clock source control */ + + int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); + int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk); + + /* uart controls */ + int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *); +}; + +struct s3c24xx_uart_port { + unsigned char rx_claimed; + unsigned char tx_claimed; + unsigned int pm_level; + unsigned long baudclk_rate; + + unsigned int rx_irq; + unsigned int tx_irq; + + struct s3c24xx_uart_info *info; + struct s3c24xx_uart_clksrc *clksrc; + struct clk *clk; + struct clk *baudclk; + struct uart_port port; + +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif +}; + +/* conversion functions */ + +#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev) +#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data) + +/* register access controls */ + +#define portaddr(port, reg) ((port)->membase + (reg)) + +#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) +#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) + +#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) +#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) + +extern int s3c24xx_serial_probe(struct platform_device *dev, + struct s3c24xx_uart_info *uart); + +extern int __devexit s3c24xx_serial_remove(struct platform_device *dev); + +extern int s3c24xx_serial_initconsole(struct platform_driver *drv, + struct s3c24xx_uart_info **uart); + +extern int s3c24xx_serial_init(struct platform_driver *drv, + struct s3c24xx_uart_info *info); + +#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE + +#define s3c24xx_console_init(__drv, __inf) \ +static int __init s3c_serial_console_init(void) \ +{ \ + struct s3c24xx_uart_info *uinfo[CONFIG_SERIAL_SAMSUNG_UARTS]; \ + int i; \ + \ + for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) \ + uinfo[i] = __inf; \ + return s3c24xx_serial_initconsole(__drv, uinfo); \ +} \ + \ +console_initcall(s3c_serial_console_init) + +#else +#define s3c24xx_console_init(drv, inf) extern void no_console(void) +#endif + +#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG + +extern void printascii(const char *); + +static void dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vsprintf(buff, fmt, va); + va_end(va); + + printascii(buff); +} + +#else +#define dbg(x...) do { } while (0) +#endif diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c new file mode 100644 index 000000000000..a2f2b3254499 --- /dev/null +++ b/drivers/tty/serial/sb1250-duart.c @@ -0,0 +1,976 @@ +/* + * drivers/serial/sb1250-duart.c + * + * Support for the asynchronous serial interface (DUART) included + * in the BCM1250 and derived System-On-a-Chip (SOC) devices. + * + * Copyright (c) 2007 Maciej W. Rozycki + * + * Derived from drivers/char/sb1250_duart.c for which the following + * copyright applies: + * + * Copyright (c) 2000, 2001, 2002, 2003, 2004 Broadcom Corporation + * + * 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. + * + * References: + * + * "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation + */ + +#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#include +#include + +#define SBD_CHANREGS(line) A_BCM1480_DUART_CHANREG((line), 0) +#define SBD_CTRLREGS(line) A_BCM1480_DUART_CTRLREG((line), 0) +#define SBD_INT(line) (K_BCM1480_INT_UART_0 + (line)) + +#define DUART_CHANREG_SPACING BCM1480_DUART_CHANREG_SPACING + +#define R_DUART_IMRREG(line) R_BCM1480_DUART_IMRREG(line) +#define R_DUART_INCHREG(line) R_BCM1480_DUART_INCHREG(line) +#define R_DUART_ISRREG(line) R_BCM1480_DUART_ISRREG(line) + +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) +#include +#include + +#define SBD_CHANREGS(line) A_DUART_CHANREG((line), 0) +#define SBD_CTRLREGS(line) A_DUART_CTRLREG(0) +#define SBD_INT(line) (K_INT_UART_0 + (line)) + +#else +#error invalid SB1250 UART configuration + +#endif + + +MODULE_AUTHOR("Maciej W. Rozycki "); +MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver"); +MODULE_LICENSE("GPL"); + + +#define DUART_MAX_CHIP 2 +#define DUART_MAX_SIDE 2 + +/* + * Per-port state. + */ +struct sbd_port { + struct sbd_duart *duart; + struct uart_port port; + unsigned char __iomem *memctrl; + int tx_stopped; + int initialised; +}; + +/* + * Per-DUART state for the shared register space. + */ +struct sbd_duart { + struct sbd_port sport[2]; + unsigned long mapctrl; + atomic_t map_guard; +}; + +#define to_sport(uport) container_of(uport, struct sbd_port, port) + +static struct sbd_duart sbd_duarts[DUART_MAX_CHIP]; + + +/* + * Reading and writing SB1250 DUART registers. + * + * There are three register spaces: two per-channel ones and + * a shared one. We have to define accessors appropriately. + * All registers are 64-bit and all but the Baud Rate Clock + * registers only define 8 least significant bits. There is + * also a workaround to take into account. Raw accessors use + * the full register width, but cooked ones truncate it + * intentionally so that the rest of the driver does not care. + */ +static u64 __read_sbdchn(struct sbd_port *sport, int reg) +{ + void __iomem *csr = sport->port.membase + reg; + + return __raw_readq(csr); +} + +static u64 __read_sbdshr(struct sbd_port *sport, int reg) +{ + void __iomem *csr = sport->memctrl + reg; + + return __raw_readq(csr); +} + +static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value) +{ + void __iomem *csr = sport->port.membase + reg; + + __raw_writeq(value, csr); +} + +static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value) +{ + void __iomem *csr = sport->memctrl + reg; + + __raw_writeq(value, csr); +} + +/* + * In bug 1956, we get glitches that can mess up uart registers. This + * "read-mode-reg after any register access" is an accepted workaround. + */ +static void __war_sbd1956(struct sbd_port *sport) +{ + __read_sbdchn(sport, R_DUART_MODE_REG_1); + __read_sbdchn(sport, R_DUART_MODE_REG_2); +} + +static unsigned char read_sbdchn(struct sbd_port *sport, int reg) +{ + unsigned char retval; + + retval = __read_sbdchn(sport, reg); + if (SIBYTE_1956_WAR) + __war_sbd1956(sport); + return retval; +} + +static unsigned char read_sbdshr(struct sbd_port *sport, int reg) +{ + unsigned char retval; + + retval = __read_sbdshr(sport, reg); + if (SIBYTE_1956_WAR) + __war_sbd1956(sport); + return retval; +} + +static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value) +{ + __write_sbdchn(sport, reg, value); + if (SIBYTE_1956_WAR) + __war_sbd1956(sport); +} + +static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value) +{ + __write_sbdshr(sport, reg, value); + if (SIBYTE_1956_WAR) + __war_sbd1956(sport); +} + + +static int sbd_receive_ready(struct sbd_port *sport) +{ + return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY; +} + +static int sbd_receive_drain(struct sbd_port *sport) +{ + int loops = 10000; + + while (sbd_receive_ready(sport) && --loops) + read_sbdchn(sport, R_DUART_RX_HOLD); + return loops; +} + +static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport) +{ + return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY; +} + +static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport) +{ + int loops = 10000; + + while (!sbd_transmit_ready(sport) && --loops) + udelay(2); + return loops; +} + +static int sbd_transmit_empty(struct sbd_port *sport) +{ + return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT; +} + +static int sbd_line_drain(struct sbd_port *sport) +{ + int loops = 10000; + + while (!sbd_transmit_empty(sport) && --loops) + udelay(2); + return loops; +} + + +static unsigned int sbd_tx_empty(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + + return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0; +} + +static unsigned int sbd_get_mctrl(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + unsigned int mctrl, status; + + status = read_sbdshr(sport, R_DUART_IN_PORT); + status >>= (uport->line) % 2; + mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) | + (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) | + (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) | + (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0); + return mctrl; +} + +static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl) +{ + struct sbd_port *sport = to_sport(uport); + unsigned int clr = 0, set = 0, mode2; + + if (mctrl & TIOCM_DTR) + set |= M_DUART_SET_OPR2; + else + clr |= M_DUART_CLR_OPR2; + if (mctrl & TIOCM_RTS) + set |= M_DUART_SET_OPR0; + else + clr |= M_DUART_CLR_OPR0; + clr <<= (uport->line) % 2; + set <<= (uport->line) % 2; + + mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2); + mode2 &= ~M_DUART_CHAN_MODE; + if (mctrl & TIOCM_LOOP) + mode2 |= V_DUART_CHAN_MODE_LCL_LOOP; + else + mode2 |= V_DUART_CHAN_MODE_NORMAL; + + write_sbdshr(sport, R_DUART_CLEAR_OPR, clr); + write_sbdshr(sport, R_DUART_SET_OPR, set); + write_sbdchn(sport, R_DUART_MODE_REG_2, mode2); +} + +static void sbd_stop_tx(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS); + sport->tx_stopped = 1; +}; + +static void sbd_start_tx(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + unsigned int mask; + + /* Enable tx interrupts. */ + mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); + mask |= M_DUART_IMR_TX; + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); + + /* Go!, go!, go!... */ + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); + sport->tx_stopped = 0; +}; + +static void sbd_stop_rx(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0); +}; + +static void sbd_enable_ms(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + + write_sbdchn(sport, R_DUART_AUXCTL_X, + M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA); +} + +static void sbd_break_ctl(struct uart_port *uport, int break_state) +{ + struct sbd_port *sport = to_sport(uport); + + if (break_state == -1) + write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK); + else + write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK); +} + + +static void sbd_receive_chars(struct sbd_port *sport) +{ + struct uart_port *uport = &sport->port; + struct uart_icount *icount; + unsigned int status, ch, flag; + int count; + + for (count = 16; count; count--) { + status = read_sbdchn(sport, R_DUART_STATUS); + if (!(status & M_DUART_RX_RDY)) + break; + + ch = read_sbdchn(sport, R_DUART_RX_HOLD); + + flag = TTY_NORMAL; + + icount = &uport->icount; + icount->rx++; + + if (unlikely(status & + (M_DUART_RCVD_BRK | M_DUART_FRM_ERR | + M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) { + if (status & M_DUART_RCVD_BRK) { + icount->brk++; + if (uart_handle_break(uport)) + continue; + } else if (status & M_DUART_FRM_ERR) + icount->frame++; + else if (status & M_DUART_PARITY_ERR) + icount->parity++; + if (status & M_DUART_OVRUN_ERR) + icount->overrun++; + + status &= uport->read_status_mask; + if (status & M_DUART_RCVD_BRK) + flag = TTY_BREAK; + else if (status & M_DUART_FRM_ERR) + flag = TTY_FRAME; + else if (status & M_DUART_PARITY_ERR) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(uport, ch)) + continue; + + uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag); + } + + tty_flip_buffer_push(uport->state->port.tty); +} + +static void sbd_transmit_chars(struct sbd_port *sport) +{ + struct uart_port *uport = &sport->port; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned int mask; + int stop_tx; + + /* XON/XOFF chars. */ + if (sport->port.x_char) { + write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + /* If nothing to do or stopped or hardware stopped. */ + stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)); + + /* Send char. */ + if (!stop_tx) { + write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + } + + /* Are we are done? */ + if (stop_tx || uart_circ_empty(xmit)) { + /* Disable tx interrupts. */ + mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); + mask &= ~M_DUART_IMR_TX; + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); + } +} + +static void sbd_status_handle(struct sbd_port *sport) +{ + struct uart_port *uport = &sport->port; + unsigned int delta; + + delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2)); + delta >>= (uport->line) % 2; + + if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG)) + uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL)); + + if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG)) + uport->icount.dsr++; + + if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) << + S_DUART_IN_PIN_CHNG)) + wake_up_interruptible(&uport->state->port.delta_msr_wait); +} + +static irqreturn_t sbd_interrupt(int irq, void *dev_id) +{ + struct sbd_port *sport = dev_id; + struct uart_port *uport = &sport->port; + irqreturn_t status = IRQ_NONE; + unsigned int intstat; + int count; + + for (count = 16; count; count--) { + intstat = read_sbdshr(sport, + R_DUART_ISRREG((uport->line) % 2)); + intstat &= read_sbdshr(sport, + R_DUART_IMRREG((uport->line) % 2)); + intstat &= M_DUART_ISR_ALL; + if (!intstat) + break; + + if (intstat & M_DUART_ISR_RX) + sbd_receive_chars(sport); + if (intstat & M_DUART_ISR_IN) + sbd_status_handle(sport); + if (intstat & M_DUART_ISR_TX) + sbd_transmit_chars(sport); + + status = IRQ_HANDLED; + } + + return status; +} + + +static int sbd_startup(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + unsigned int mode1; + int ret; + + ret = request_irq(sport->port.irq, sbd_interrupt, + IRQF_SHARED, "sb1250-duart", sport); + if (ret) + return ret; + + /* Clear the receive FIFO. */ + sbd_receive_drain(sport); + + /* Clear the interrupt registers. */ + write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT); + read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2)); + + /* Set rx/tx interrupt to FIFO available. */ + mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1); + mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT); + write_sbdchn(sport, R_DUART_MODE_REG_1, mode1); + + /* Disable tx, enable rx. */ + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN); + sport->tx_stopped = 1; + + /* Enable interrupts. */ + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), + M_DUART_IMR_IN | M_DUART_IMR_RX); + + return 0; +} + +static void sbd_shutdown(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS); + sport->tx_stopped = 1; + free_irq(sport->port.irq, sport); +} + + +static void sbd_init_port(struct sbd_port *sport) +{ + struct uart_port *uport = &sport->port; + + if (sport->initialised) + return; + + /* There is no DUART reset feature, so just set some sane defaults. */ + write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX); + write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX); + write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8); + write_sbdchn(sport, R_DUART_MODE_REG_2, 0); + write_sbdchn(sport, R_DUART_FULL_CTL, + V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15)); + write_sbdchn(sport, R_DUART_OPCR_X, 0); + write_sbdchn(sport, R_DUART_AUXCTL_X, 0); + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0); + + sport->initialised = 1; +} + +static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, + struct ktermios *old_termios) +{ + struct sbd_port *sport = to_sport(uport); + unsigned int mode1 = 0, mode2 = 0, aux = 0; + unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0; + unsigned int oldmode1, oldmode2, oldaux; + unsigned int baud, brg; + unsigned int command; + + mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD | + M_DUART_BITS_PER_CHAR); + mode2mask |= ~M_DUART_STOP_BIT_LEN_2; + auxmask |= ~M_DUART_CTS_CHNG_ENA; + + /* Byte size. */ + switch (termios->c_cflag & CSIZE) { + case CS5: + case CS6: + /* Unsupported, leave unchanged. */ + mode1mask |= M_DUART_PARITY_MODE; + break; + case CS7: + mode1 |= V_DUART_BITS_PER_CHAR_7; + break; + case CS8: + default: + mode1 |= V_DUART_BITS_PER_CHAR_8; + break; + } + + /* Parity and stop bits. */ + if (termios->c_cflag & CSTOPB) + mode2 |= M_DUART_STOP_BIT_LEN_2; + else + mode2 |= M_DUART_STOP_BIT_LEN_1; + if (termios->c_cflag & PARENB) + mode1 |= V_DUART_PARITY_MODE_ADD; + else + mode1 |= V_DUART_PARITY_MODE_NONE; + if (termios->c_cflag & PARODD) + mode1 |= M_DUART_PARITY_TYPE_ODD; + else + mode1 |= M_DUART_PARITY_TYPE_EVEN; + + baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000); + brg = V_DUART_BAUD_RATE(baud); + /* The actual lower bound is 1221bps, so compensate. */ + if (brg > M_DUART_CLK_COUNTER) + brg = M_DUART_CLK_COUNTER; + + uart_update_timeout(uport, termios->c_cflag, baud); + + uport->read_status_mask = M_DUART_OVRUN_ERR; + if (termios->c_iflag & INPCK) + uport->read_status_mask |= M_DUART_FRM_ERR | + M_DUART_PARITY_ERR; + if (termios->c_iflag & (BRKINT | PARMRK)) + uport->read_status_mask |= M_DUART_RCVD_BRK; + + uport->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= M_DUART_FRM_ERR | + M_DUART_PARITY_ERR; + if (termios->c_iflag & IGNBRK) { + uport->ignore_status_mask |= M_DUART_RCVD_BRK; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= M_DUART_OVRUN_ERR; + } + + if (termios->c_cflag & CREAD) + command = M_DUART_RX_EN; + else + command = M_DUART_RX_DIS; + + if (termios->c_cflag & CRTSCTS) + aux |= M_DUART_CTS_CHNG_ENA; + else + aux &= ~M_DUART_CTS_CHNG_ENA; + + spin_lock(&uport->lock); + + if (sport->tx_stopped) + command |= M_DUART_TX_DIS; + else + command |= M_DUART_TX_EN; + + oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask; + oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask; + oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask; + + if (!sport->tx_stopped) + sbd_line_drain(sport); + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS); + + write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1); + write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2); + write_sbdchn(sport, R_DUART_CLK_SEL, brg); + write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux); + + write_sbdchn(sport, R_DUART_CMD, command); + + spin_unlock(&uport->lock); +} + + +static const char *sbd_type(struct uart_port *uport) +{ + return "SB1250 DUART"; +} + +static void sbd_release_port(struct uart_port *uport) +{ + struct sbd_port *sport = to_sport(uport); + struct sbd_duart *duart = sport->duart; + int map_guard; + + iounmap(sport->memctrl); + sport->memctrl = NULL; + iounmap(uport->membase); + uport->membase = NULL; + + map_guard = atomic_add_return(-1, &duart->map_guard); + if (!map_guard) + release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING); + release_mem_region(uport->mapbase, DUART_CHANREG_SPACING); +} + +static int sbd_map_port(struct uart_port *uport) +{ + const char *err = KERN_ERR "sbd: Cannot map MMIO\n"; + struct sbd_port *sport = to_sport(uport); + struct sbd_duart *duart = sport->duart; + + if (!uport->membase) + uport->membase = ioremap_nocache(uport->mapbase, + DUART_CHANREG_SPACING); + if (!uport->membase) { + printk(err); + return -ENOMEM; + } + + if (!sport->memctrl) + sport->memctrl = ioremap_nocache(duart->mapctrl, + DUART_CHANREG_SPACING); + if (!sport->memctrl) { + printk(err); + iounmap(uport->membase); + uport->membase = NULL; + return -ENOMEM; + } + + return 0; +} + +static int sbd_request_port(struct uart_port *uport) +{ + const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n"; + struct sbd_duart *duart = to_sport(uport)->duart; + int map_guard; + int ret = 0; + + if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING, + "sb1250-duart")) { + printk(err); + return -EBUSY; + } + map_guard = atomic_add_return(1, &duart->map_guard); + if (map_guard == 1) { + if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING, + "sb1250-duart")) { + atomic_add(-1, &duart->map_guard); + printk(err); + ret = -EBUSY; + } + } + if (!ret) { + ret = sbd_map_port(uport); + if (ret) { + map_guard = atomic_add_return(-1, &duart->map_guard); + if (!map_guard) + release_mem_region(duart->mapctrl, + DUART_CHANREG_SPACING); + } + } + if (ret) { + release_mem_region(uport->mapbase, DUART_CHANREG_SPACING); + return ret; + } + return 0; +} + +static void sbd_config_port(struct uart_port *uport, int flags) +{ + struct sbd_port *sport = to_sport(uport); + + if (flags & UART_CONFIG_TYPE) { + if (sbd_request_port(uport)) + return; + + uport->type = PORT_SB1250_DUART; + + sbd_init_port(sport); + } +} + +static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART) + ret = -EINVAL; + if (ser->irq != uport->irq) + ret = -EINVAL; + if (ser->baud_base != uport->uartclk / 16) + ret = -EINVAL; + return ret; +} + + +static const struct uart_ops sbd_ops = { + .tx_empty = sbd_tx_empty, + .set_mctrl = sbd_set_mctrl, + .get_mctrl = sbd_get_mctrl, + .stop_tx = sbd_stop_tx, + .start_tx = sbd_start_tx, + .stop_rx = sbd_stop_rx, + .enable_ms = sbd_enable_ms, + .break_ctl = sbd_break_ctl, + .startup = sbd_startup, + .shutdown = sbd_shutdown, + .set_termios = sbd_set_termios, + .type = sbd_type, + .release_port = sbd_release_port, + .request_port = sbd_request_port, + .config_port = sbd_config_port, + .verify_port = sbd_verify_port, +}; + +/* Initialize SB1250 DUART port structures. */ +static void __init sbd_probe_duarts(void) +{ + static int probed; + int chip, side; + int max_lines, line; + + if (probed) + return; + + /* Set the number of available units based on the SOC type. */ + switch (soc_type) { + case K_SYS_SOC_TYPE_BCM1x55: + case K_SYS_SOC_TYPE_BCM1x80: + max_lines = 4; + break; + default: + /* Assume at least two serial ports at the normal address. */ + max_lines = 2; + break; + } + + probed = 1; + + for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines; + chip++) { + sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line); + + for (side = 0; side < DUART_MAX_SIDE && line < max_lines; + side++, line++) { + struct sbd_port *sport = &sbd_duarts[chip].sport[side]; + struct uart_port *uport = &sport->port; + + sport->duart = &sbd_duarts[chip]; + + uport->irq = SBD_INT(line); + uport->uartclk = 100000000 / 20 * 16; + uport->fifosize = 16; + uport->iotype = UPIO_MEM; + uport->flags = UPF_BOOT_AUTOCONF; + uport->ops = &sbd_ops; + uport->line = line; + uport->mapbase = SBD_CHANREGS(line); + } + } +} + + +#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE +/* + * Serial console stuff. Very basic, polling driver for doing serial + * console output. The console_sem is held by the caller, so we + * shouldn't be interrupted for more console activity. + */ +static void sbd_console_putchar(struct uart_port *uport, int ch) +{ + struct sbd_port *sport = to_sport(uport); + + sbd_transmit_drain(sport); + write_sbdchn(sport, R_DUART_TX_HOLD, ch); +} + +static void sbd_console_write(struct console *co, const char *s, + unsigned int count) +{ + int chip = co->index / DUART_MAX_SIDE; + int side = co->index % DUART_MAX_SIDE; + struct sbd_port *sport = &sbd_duarts[chip].sport[side]; + struct uart_port *uport = &sport->port; + unsigned long flags; + unsigned int mask; + + /* Disable transmit interrupts and enable the transmitter. */ + spin_lock_irqsave(&uport->lock, flags); + mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2)); + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), + mask & ~M_DUART_IMR_TX); + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN); + spin_unlock_irqrestore(&uport->lock, flags); + + uart_console_write(&sport->port, s, count, sbd_console_putchar); + + /* Restore transmit interrupts and the transmitter enable. */ + spin_lock_irqsave(&uport->lock, flags); + sbd_line_drain(sport); + if (sport->tx_stopped) + write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS); + write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask); + spin_unlock_irqrestore(&uport->lock, flags); +} + +static int __init sbd_console_setup(struct console *co, char *options) +{ + int chip = co->index / DUART_MAX_SIDE; + int side = co->index % DUART_MAX_SIDE; + struct sbd_port *sport = &sbd_duarts[chip].sport[side]; + struct uart_port *uport = &sport->port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + if (!sport->duart) + return -ENXIO; + + ret = sbd_map_port(uport); + if (ret) + return ret; + + sbd_init_port(sport); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(uport, co, baud, parity, bits, flow); +} + +static struct uart_driver sbd_reg; +static struct console sbd_console = { + .name = "duart", + .write = sbd_console_write, + .device = uart_console_device, + .setup = sbd_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sbd_reg +}; + +static int __init sbd_serial_console_init(void) +{ + sbd_probe_duarts(); + register_console(&sbd_console); + + return 0; +} + +console_initcall(sbd_serial_console_init); + +#define SERIAL_SB1250_DUART_CONSOLE &sbd_console +#else +#define SERIAL_SB1250_DUART_CONSOLE NULL +#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */ + + +static struct uart_driver sbd_reg = { + .owner = THIS_MODULE, + .driver_name = "sb1250_duart", + .dev_name = "duart", + .major = TTY_MAJOR, + .minor = SB1250_DUART_MINOR_BASE, + .nr = DUART_MAX_CHIP * DUART_MAX_SIDE, + .cons = SERIAL_SB1250_DUART_CONSOLE, +}; + +/* Set up the driver and register it. */ +static int __init sbd_init(void) +{ + int i, ret; + + sbd_probe_duarts(); + + ret = uart_register_driver(&sbd_reg); + if (ret) + return ret; + + for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) { + struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE]; + struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE]; + struct uart_port *uport = &sport->port; + + if (sport->duart) + uart_add_one_port(&sbd_reg, uport); + } + + return 0; +} + +/* Unload the driver. Unregister stuff, get ready to go away. */ +static void __exit sbd_exit(void) +{ + int i; + + for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) { + struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE]; + struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE]; + struct uart_port *uport = &sport->port; + + if (sport->duart) + uart_remove_one_port(&sbd_reg, uport); + } + + uart_unregister_driver(&sbd_reg); +} + +module_init(sbd_init); +module_exit(sbd_exit); diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c new file mode 100644 index 000000000000..75038ad2b242 --- /dev/null +++ b/drivers/tty/serial/sc26xx.c @@ -0,0 +1,757 @@ +/* + * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices. + * + * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#define SC26XX_MAJOR 204 +#define SC26XX_MINOR_START 205 +#define SC26XX_NR 2 + +struct uart_sc26xx_port { + struct uart_port port[2]; + u8 dsr_mask[2]; + u8 cts_mask[2]; + u8 dcd_mask[2]; + u8 ri_mask[2]; + u8 dtr_mask[2]; + u8 rts_mask[2]; + u8 imr; +}; + +/* register common to both ports */ +#define RD_ISR 0x14 +#define RD_IPR 0x34 + +#define WR_ACR 0x10 +#define WR_IMR 0x14 +#define WR_OPCR 0x34 +#define WR_OPR_SET 0x38 +#define WR_OPR_CLR 0x3C + +/* access common register */ +#define READ_SC(p, r) readb((p)->membase + RD_##r) +#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r) + +/* register per port */ +#define RD_PORT_MRx 0x00 +#define RD_PORT_SR 0x04 +#define RD_PORT_RHR 0x0c + +#define WR_PORT_MRx 0x00 +#define WR_PORT_CSR 0x04 +#define WR_PORT_CR 0x08 +#define WR_PORT_THR 0x0c + +/* SR bits */ +#define SR_BREAK (1 << 7) +#define SR_FRAME (1 << 6) +#define SR_PARITY (1 << 5) +#define SR_OVERRUN (1 << 4) +#define SR_TXRDY (1 << 2) +#define SR_RXRDY (1 << 0) + +#define CR_RES_MR (1 << 4) +#define CR_RES_RX (2 << 4) +#define CR_RES_TX (3 << 4) +#define CR_STRT_BRK (6 << 4) +#define CR_STOP_BRK (7 << 4) +#define CR_DIS_TX (1 << 3) +#define CR_ENA_TX (1 << 2) +#define CR_DIS_RX (1 << 1) +#define CR_ENA_RX (1 << 0) + +/* ISR bits */ +#define ISR_RXRDYB (1 << 5) +#define ISR_TXRDYB (1 << 4) +#define ISR_RXRDYA (1 << 1) +#define ISR_TXRDYA (1 << 0) + +/* IMR bits */ +#define IMR_RXRDY (1 << 1) +#define IMR_TXRDY (1 << 0) + +/* access port register */ +static inline u8 read_sc_port(struct uart_port *p, u8 reg) +{ + return readb(p->membase + p->line * 0x20 + reg); +} + +static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val) +{ + writeb(val, p->membase + p->line * 0x20 + reg); +} + +#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r) +#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v) + +static void sc26xx_enable_irq(struct uart_port *port, int mask) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + up->imr |= mask << (line * 4); + WRITE_SC(port, IMR, up->imr); +} + +static void sc26xx_disable_irq(struct uart_port *port, int mask) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + up->imr &= ~(mask << (line * 4)); + WRITE_SC(port, IMR, up->imr); +} + +static struct tty_struct *receive_chars(struct uart_port *port) +{ + struct tty_struct *tty = NULL; + int limit = 10000; + unsigned char ch; + char flag; + u8 status; + + if (port->state != NULL) /* Unopened serial console */ + tty = port->state->port.tty; + + while (limit-- > 0) { + status = READ_SC_PORT(port, SR); + if (!(status & SR_RXRDY)) + break; + ch = READ_SC_PORT(port, RHR); + + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(status & (SR_BREAK | SR_FRAME | + SR_PARITY | SR_OVERRUN))) { + if (status & SR_BREAK) { + status &= ~(SR_PARITY | SR_FRAME); + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (status & SR_PARITY) + port->icount.parity++; + else if (status & SR_FRAME) + port->icount.frame++; + if (status & SR_OVERRUN) + port->icount.overrun++; + + status &= port->read_status_mask; + if (status & SR_BREAK) + flag = TTY_BREAK; + else if (status & SR_PARITY) + flag = TTY_PARITY; + else if (status & SR_FRAME) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (status & port->ignore_status_mask) + continue; + + tty_insert_flip_char(tty, ch, flag); + } + return tty; +} + +static void transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit; + + if (!port->state) + return; + + xmit = &port->state->xmit; + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + sc26xx_disable_irq(port, IMR_TXRDY); + return; + } + while (!uart_circ_empty(xmit)) { + if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) + break; + + WRITE_SC_PORT(port, THR, 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 sc26xx_interrupt(int irq, void *dev_id) +{ + struct uart_sc26xx_port *up = dev_id; + struct tty_struct *tty; + unsigned long flags; + u8 isr; + + spin_lock_irqsave(&up->port[0].lock, flags); + + tty = NULL; + isr = READ_SC(&up->port[0], ISR); + if (isr & ISR_TXRDYA) + transmit_chars(&up->port[0]); + if (isr & ISR_RXRDYA) + tty = receive_chars(&up->port[0]); + + spin_unlock(&up->port[0].lock); + + if (tty) + tty_flip_buffer_push(tty); + + spin_lock(&up->port[1].lock); + + tty = NULL; + if (isr & ISR_TXRDYB) + transmit_chars(&up->port[1]); + if (isr & ISR_RXRDYB) + tty = receive_chars(&up->port[1]); + + spin_unlock_irqrestore(&up->port[1].lock, flags); + + if (tty) + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int sc26xx_tx_empty(struct uart_port *port) +{ + return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0; +} + +/* port->lock held by caller. */ +static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + if (up->dtr_mask[line]) { + if (mctrl & TIOCM_DTR) + WRITE_SC(port, OPR_SET, up->dtr_mask[line]); + else + WRITE_SC(port, OPR_CLR, up->dtr_mask[line]); + } + if (up->rts_mask[line]) { + if (mctrl & TIOCM_RTS) + WRITE_SC(port, OPR_SET, up->rts_mask[line]); + else + WRITE_SC(port, OPR_CLR, up->rts_mask[line]); + } +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int sc26xx_get_mctrl(struct uart_port *port) +{ + struct uart_sc26xx_port *up; + int line = port->line; + unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; + u8 ipr; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + ipr = READ_SC(port, IPR) ^ 0xff; + + if (up->dsr_mask[line]) { + mctrl &= ~TIOCM_DSR; + mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0; + } + if (up->cts_mask[line]) { + mctrl &= ~TIOCM_CTS; + mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0; + } + if (up->dcd_mask[line]) { + mctrl &= ~TIOCM_CAR; + mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0; + } + if (up->ri_mask[line]) { + mctrl &= ~TIOCM_RNG; + mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0; + } + return mctrl; +} + +/* port->lock held by caller. */ +static void sc26xx_stop_tx(struct uart_port *port) +{ + return; +} + +/* port->lock held by caller. */ +static void sc26xx_start_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + while (!uart_circ_empty(xmit)) { + if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { + sc26xx_enable_irq(port, IMR_TXRDY); + break; + } + WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } +} + +/* port->lock held by caller. */ +static void sc26xx_stop_rx(struct uart_port *port) +{ +} + +/* port->lock held by caller. */ +static void sc26xx_enable_ms(struct uart_port *port) +{ +} + +/* port->lock is not held. */ +static void sc26xx_break_ctl(struct uart_port *port, int break_state) +{ + if (break_state == -1) + WRITE_SC_PORT(port, CR, CR_STRT_BRK); + else + WRITE_SC_PORT(port, CR, CR_STOP_BRK); +} + +/* port->lock is not held. */ +static int sc26xx_startup(struct uart_port *port) +{ + sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + WRITE_SC(port, OPCR, 0); + + /* reset tx and rx */ + WRITE_SC_PORT(port, CR, CR_RES_RX); + WRITE_SC_PORT(port, CR, CR_RES_TX); + + /* start rx/tx */ + WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); + + /* enable irqs */ + sc26xx_enable_irq(port, IMR_RXRDY); + return 0; +} + +/* port->lock is not held. */ +static void sc26xx_shutdown(struct uart_port *port) +{ + /* disable interrupst */ + sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + + /* stop tx/rx */ + WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); +} + +/* port->lock is not held. */ +static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); + unsigned int iflag, cflag; + unsigned long flags; + u8 mr1, mr2, csr; + + spin_lock_irqsave(&port->lock, flags); + + while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) + udelay(2); + + WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); + + iflag = termios->c_iflag; + cflag = termios->c_cflag; + + port->read_status_mask = SR_OVERRUN; + if (iflag & INPCK) + port->read_status_mask |= SR_PARITY | SR_FRAME; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SR_BREAK; + + port->ignore_status_mask = 0; + if (iflag & IGNBRK) + port->ignore_status_mask |= SR_BREAK; + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= SR_BREAK | SR_FRAME | + SR_PARITY | SR_OVERRUN; + + switch (cflag & CSIZE) { + case CS5: + mr1 = 0x00; + break; + case CS6: + mr1 = 0x01; + break; + case CS7: + mr1 = 0x02; + break; + default: + case CS8: + mr1 = 0x03; + break; + } + mr2 = 0x07; + if (cflag & CSTOPB) + mr2 = 0x0f; + if (cflag & PARENB) { + if (cflag & PARODD) + mr1 |= (1 << 2); + } else + mr1 |= (2 << 3); + + switch (baud) { + case 50: + csr = 0x00; + break; + case 110: + csr = 0x11; + break; + case 134: + csr = 0x22; + break; + case 200: + csr = 0x33; + break; + case 300: + csr = 0x44; + break; + case 600: + csr = 0x55; + break; + case 1200: + csr = 0x66; + break; + case 2400: + csr = 0x88; + break; + case 4800: + csr = 0x99; + break; + default: + case 9600: + csr = 0xbb; + break; + case 19200: + csr = 0xcc; + break; + } + + WRITE_SC_PORT(port, CR, CR_RES_MR); + WRITE_SC_PORT(port, MRx, mr1); + WRITE_SC_PORT(port, MRx, mr2); + + WRITE_SC(port, ACR, 0x80); + WRITE_SC_PORT(port, CSR, csr); + + /* reset tx and rx */ + WRITE_SC_PORT(port, CR, CR_RES_RX); + WRITE_SC_PORT(port, CR, CR_RES_TX); + + WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); + while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) + udelay(2); + + /* XXX */ + uart_update_timeout(port, cflag, + (port->uartclk / (16 * quot))); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *sc26xx_type(struct uart_port *port) +{ + return "SC26XX"; +} + +static void sc26xx_release_port(struct uart_port *port) +{ +} + +static int sc26xx_request_port(struct uart_port *port) +{ + return 0; +} + +static void sc26xx_config_port(struct uart_port *port, int flags) +{ +} + +static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static struct uart_ops sc26xx_ops = { + .tx_empty = sc26xx_tx_empty, + .set_mctrl = sc26xx_set_mctrl, + .get_mctrl = sc26xx_get_mctrl, + .stop_tx = sc26xx_stop_tx, + .start_tx = sc26xx_start_tx, + .stop_rx = sc26xx_stop_rx, + .enable_ms = sc26xx_enable_ms, + .break_ctl = sc26xx_break_ctl, + .startup = sc26xx_startup, + .shutdown = sc26xx_shutdown, + .set_termios = sc26xx_set_termios, + .type = sc26xx_type, + .release_port = sc26xx_release_port, + .request_port = sc26xx_request_port, + .config_port = sc26xx_config_port, + .verify_port = sc26xx_verify_port, +}; + +static struct uart_port *sc26xx_port; + +#ifdef CONFIG_SERIAL_SC26XX_CONSOLE +static void sc26xx_console_putchar(struct uart_port *port, char c) +{ + unsigned long flags; + int limit = 1000000; + + spin_lock_irqsave(&port->lock, flags); + + while (limit-- > 0) { + if (READ_SC_PORT(port, SR) & SR_TXRDY) { + WRITE_SC_PORT(port, THR, c); + break; + } + udelay(2); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void sc26xx_console_write(struct console *con, const char *s, unsigned n) +{ + struct uart_port *port = sc26xx_port; + int i; + + for (i = 0; i < n; i++) { + if (*s == '\n') + sc26xx_console_putchar(port, '\r'); + sc26xx_console_putchar(port, *s++); + } +} + +static int __init sc26xx_console_setup(struct console *con, char *options) +{ + struct uart_port *port = sc26xx_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (port->type != PORT_SC26XX) + return -1; + + printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index); + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, con, baud, parity, bits, flow); +} + +static struct uart_driver sc26xx_reg; +static struct console sc26xx_console = { + .name = "ttySC", + .write = sc26xx_console_write, + .device = uart_console_device, + .setup = sc26xx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sc26xx_reg, +}; +#define SC26XX_CONSOLE &sc26xx_console +#else +#define SC26XX_CONSOLE NULL +#endif + +static struct uart_driver sc26xx_reg = { + .owner = THIS_MODULE, + .driver_name = "SC26xx", + .dev_name = "ttySC", + .major = SC26XX_MAJOR, + .minor = SC26XX_MINOR_START, + .nr = SC26XX_NR, + .cons = SC26XX_CONSOLE, +}; + +static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) +{ + unsigned int bit = (flags >> bitpos) & 15; + + return bit ? (1 << (bit - 1)) : 0; +} + +static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up, + int line, unsigned int data) +{ + up->dtr_mask[line] = sc26xx_flags2mask(data, 0); + up->rts_mask[line] = sc26xx_flags2mask(data, 4); + up->dsr_mask[line] = sc26xx_flags2mask(data, 8); + up->cts_mask[line] = sc26xx_flags2mask(data, 12); + up->dcd_mask[line] = sc26xx_flags2mask(data, 16); + up->ri_mask[line] = sc26xx_flags2mask(data, 20); +} + +static int __devinit sc26xx_probe(struct platform_device *dev) +{ + struct resource *res; + struct uart_sc26xx_port *up; + unsigned int *sc26xx_data = dev->dev.platform_data; + int err; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + up = kzalloc(sizeof *up, GFP_KERNEL); + if (unlikely(!up)) + return -ENOMEM; + + up->port[0].line = 0; + up->port[0].ops = &sc26xx_ops; + up->port[0].type = PORT_SC26XX; + up->port[0].uartclk = (29491200 / 16); /* arbitrary */ + + up->port[0].mapbase = res->start; + up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40); + up->port[0].iotype = UPIO_MEM; + up->port[0].irq = platform_get_irq(dev, 0); + + up->port[0].dev = &dev->dev; + + sc26xx_init_masks(up, 0, sc26xx_data[0]); + + sc26xx_port = &up->port[0]; + + up->port[1].line = 1; + up->port[1].ops = &sc26xx_ops; + up->port[1].type = PORT_SC26XX; + up->port[1].uartclk = (29491200 / 16); /* arbitrary */ + + up->port[1].mapbase = up->port[0].mapbase; + up->port[1].membase = up->port[0].membase; + up->port[1].iotype = UPIO_MEM; + up->port[1].irq = up->port[0].irq; + + up->port[1].dev = &dev->dev; + + sc26xx_init_masks(up, 1, sc26xx_data[1]); + + err = uart_register_driver(&sc26xx_reg); + if (err) + goto out_free_port; + + sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor; + + err = uart_add_one_port(&sc26xx_reg, &up->port[0]); + if (err) + goto out_unregister_driver; + + err = uart_add_one_port(&sc26xx_reg, &up->port[1]); + if (err) + goto out_remove_port0; + + err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up); + if (err) + goto out_remove_ports; + + dev_set_drvdata(&dev->dev, up); + return 0; + +out_remove_ports: + uart_remove_one_port(&sc26xx_reg, &up->port[1]); +out_remove_port0: + uart_remove_one_port(&sc26xx_reg, &up->port[0]); + +out_unregister_driver: + uart_unregister_driver(&sc26xx_reg); + +out_free_port: + kfree(up); + sc26xx_port = NULL; + return err; +} + + +static int __exit sc26xx_driver_remove(struct platform_device *dev) +{ + struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev); + + free_irq(up->port[0].irq, up); + + uart_remove_one_port(&sc26xx_reg, &up->port[0]); + uart_remove_one_port(&sc26xx_reg, &up->port[1]); + + uart_unregister_driver(&sc26xx_reg); + + kfree(up); + sc26xx_port = NULL; + + dev_set_drvdata(&dev->dev, NULL); + return 0; +} + +static struct platform_driver sc26xx_driver = { + .probe = sc26xx_probe, + .remove = __devexit_p(sc26xx_driver_remove), + .driver = { + .name = "SC26xx", + .owner = THIS_MODULE, + }, +}; + +static int __init sc26xx_init(void) +{ + return platform_driver_register(&sc26xx_driver); +} + +static void __exit sc26xx_exit(void) +{ + platform_driver_unregister(&sc26xx_driver); +} + +module_init(sc26xx_init); +module_exit(sc26xx_exit); + + +MODULE_AUTHOR("Thomas Bogendörfer"); +MODULE_DESCRIPTION("SC681/SC2692 serial driver"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:SC26xx"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c new file mode 100644 index 000000000000..460a72d91bb7 --- /dev/null +++ b/drivers/tty/serial/serial_core.c @@ -0,0 +1,2578 @@ +/* + * linux/drivers/char/core.c + * + * Driver core for serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. + * + * 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 /* for serial_state and serial_icounter_struct */ +#include +#include +#include + +#include +#include + +/* + * This is used to lock changes in serial line configuration. + */ +static DEFINE_MUTEX(port_mutex); + +/* + * lockdep: port->lock is initialized in two places, but we + * want only one lock-class: + */ +static struct lock_class_key port_lock_key; + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +#ifdef CONFIG_SERIAL_CORE_CONSOLE +#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) +#else +#define uart_console(port) (0) +#endif + +static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, + struct ktermios *old_termios); +static void __uart_wait_until_sent(struct uart_port *port, int timeout); +static void uart_change_pm(struct uart_state *state, int pm_state); + +/* + * This routine is used by the interrupt handler to schedule processing in + * the software interrupt portion of the driver. + */ +void uart_write_wakeup(struct uart_port *port) +{ + struct uart_state *state = port->state; + /* + * This means you called this function _after_ the port was + * closed. No cookie for you. + */ + BUG_ON(!state); + tasklet_schedule(&state->tlet); +} + +static void uart_stop(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + port->ops->stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void __uart_start(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + + if (!uart_circ_empty(&state->xmit) && state->xmit.buf && + !tty->stopped && !tty->hw_stopped) + port->ops->start_tx(port); +} + +static void uart_start(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __uart_start(tty); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void uart_tasklet_action(unsigned long data) +{ + struct uart_state *state = (struct uart_state *)data; + tty_wakeup(state->port.tty); +} + +static inline void +uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) +{ + unsigned long flags; + unsigned int old; + + spin_lock_irqsave(&port->lock, flags); + old = port->mctrl; + port->mctrl = (old & ~clear) | set; + if (old != port->mctrl) + port->ops->set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); +} + +#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) +#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) + +/* + * Startup the port. This will be called once per open. All calls + * will be serialised by the per-port mutex. + */ +static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) +{ + struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; + unsigned long page; + int retval = 0; + + if (port->flags & ASYNC_INITIALIZED) + return 0; + + /* + * Set the TTY IO error marker - we will only clear this + * once we have successfully opened the port. Also set + * up the tty->alt_speed kludge + */ + set_bit(TTY_IO_ERROR, &tty->flags); + + if (uport->type == PORT_UNKNOWN) + return 0; + + /* + * Initialise and allocate the transmit and temporary + * buffer. + */ + if (!state->xmit.buf) { + /* This is protected by the per port mutex */ + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + state->xmit.buf = (unsigned char *) page; + uart_circ_clear(&state->xmit); + } + + retval = uport->ops->startup(uport); + if (retval == 0) { + if (init_hw) { + /* + * Initialise the hardware port settings. + */ + uart_change_speed(tty, state, NULL); + + /* + * Setup the RTS and DTR signals once the + * port is open and ready to respond. + */ + if (tty->termios->c_cflag & CBAUD) + uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); + } + + if (port->flags & ASYNC_CTS_FLOW) { + spin_lock_irq(&uport->lock); + if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) + tty->hw_stopped = 1; + spin_unlock_irq(&uport->lock); + } + + set_bit(ASYNCB_INITIALIZED, &port->flags); + + clear_bit(TTY_IO_ERROR, &tty->flags); + } + + if (retval && capable(CAP_SYS_ADMIN)) + retval = 0; + + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. Calls to + * uart_shutdown are serialised by the per-port semaphore. + */ +static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) +{ + struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; + + /* + * Set the TTY IO error marker + */ + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); + + if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) { + /* + * Turn off DTR and RTS early. + */ + if (!tty || (tty->termios->c_cflag & HUPCL)) + uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free + * the irq here so the queue might never be woken up. Note + * that we won't end up waiting on delta_msr_wait again since + * any outstanding file descriptors should be pointing at + * hung_up_tty_fops now. + */ + wake_up_interruptible(&port->delta_msr_wait); + + /* + * Free the IRQ and disable the port. + */ + uport->ops->shutdown(uport); + + /* + * Ensure that the IRQ handler isn't running on another CPU. + */ + synchronize_irq(uport->irq); + } + + /* + * kill off our tasklet + */ + tasklet_kill(&state->tlet); + + /* + * Free the transmit buffer page. + */ + if (state->xmit.buf) { + free_page((unsigned long)state->xmit.buf); + state->xmit.buf = NULL; + } +} + +/** + * uart_update_timeout - update per-port FIFO timeout. + * @port: uart_port structure describing the port + * @cflag: termios cflag value + * @baud: speed of the port + * + * Set the port FIFO timeout value. The @cflag value should + * reflect the actual hardware settings. + */ +void +uart_update_timeout(struct uart_port *port, unsigned int cflag, + unsigned int baud) +{ + unsigned int bits; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; + break; /* CS8 */ + } + + if (cflag & CSTOPB) + bits++; + if (cflag & PARENB) + bits++; + + /* + * The total number of bits to be transmitted in the fifo. + */ + bits = bits * port->fifosize; + + /* + * Figure the timeout to send the above number of bits. + * Add .02 seconds of slop + */ + port->timeout = (HZ * bits) / baud + HZ/50; +} + +EXPORT_SYMBOL(uart_update_timeout); + +/** + * uart_get_baud_rate - return baud rate for a particular port + * @port: uart_port structure describing the port in question. + * @termios: desired termios settings. + * @old: old termios (or NULL) + * @min: minimum acceptable baud rate + * @max: maximum acceptable baud rate + * + * Decode the termios structure into a numeric baud rate, + * taking account of the magic 38400 baud rate (with spd_* + * flags), and mapping the %B0 rate to 9600 baud. + * + * If the new baud rate is invalid, try the old termios setting. + * If it's still invalid, we try 9600 baud. + * + * Update the @termios structure to reflect the baud rate + * we're actually going to be using. Don't do this for the case + * where B0 is requested ("hang up"). + */ +unsigned int +uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, + struct ktermios *old, unsigned int min, unsigned int max) +{ + unsigned int try, baud, altbaud = 38400; + int hung_up = 0; + upf_t flags = port->flags & UPF_SPD_MASK; + + if (flags == UPF_SPD_HI) + altbaud = 57600; + else if (flags == UPF_SPD_VHI) + altbaud = 115200; + else if (flags == UPF_SPD_SHI) + altbaud = 230400; + else if (flags == UPF_SPD_WARP) + altbaud = 460800; + + for (try = 0; try < 2; try++) { + baud = tty_termios_baud_rate(termios); + + /* + * The spd_hi, spd_vhi, spd_shi, spd_warp kludge... + * Die! Die! Die! + */ + if (baud == 38400) + baud = altbaud; + + /* + * Special case: B0 rate. + */ + if (baud == 0) { + hung_up = 1; + baud = 9600; + } + + if (baud >= min && baud <= max) + return baud; + + /* + * Oops, the quotient was zero. Try again with + * the old baud rate if possible. + */ + termios->c_cflag &= ~CBAUD; + if (old) { + baud = tty_termios_baud_rate(old); + if (!hung_up) + tty_termios_encode_baud_rate(termios, + baud, baud); + old = NULL; + continue; + } + + /* + * As a last resort, if the range cannot be met then clip to + * the nearest chip supported rate. + */ + if (!hung_up) { + if (baud <= min) + tty_termios_encode_baud_rate(termios, + min + 1, min + 1); + else + tty_termios_encode_baud_rate(termios, + max - 1, max - 1); + } + } + /* Should never happen */ + WARN_ON(1); + return 0; +} + +EXPORT_SYMBOL(uart_get_baud_rate); + +/** + * uart_get_divisor - return uart clock divisor + * @port: uart_port structure describing the port. + * @baud: desired baud rate + * + * Calculate the uart clock divisor for the port. + */ +unsigned int +uart_get_divisor(struct uart_port *port, unsigned int baud) +{ + unsigned int quot; + + /* + * Old custom speed handling. + */ + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) + quot = port->custom_divisor; + else + quot = (port->uartclk + (8 * baud)) / (16 * baud); + + return quot; +} + +EXPORT_SYMBOL(uart_get_divisor); + +/* FIXME: Consistent locking policy */ +static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, + struct ktermios *old_termios) +{ + struct tty_port *port = &state->port; + struct uart_port *uport = state->uart_port; + struct ktermios *termios; + + /* + * 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) + return; + + termios = tty->termios; + + /* + * Set flags based on termios cflag + */ + if (termios->c_cflag & CRTSCTS) + set_bit(ASYNCB_CTS_FLOW, &port->flags); + else + clear_bit(ASYNCB_CTS_FLOW, &port->flags); + + if (termios->c_cflag & CLOCAL) + clear_bit(ASYNCB_CHECK_CD, &port->flags); + else + set_bit(ASYNCB_CHECK_CD, &port->flags); + + uport->ops->set_termios(uport, termios, old_termios); +} + +static inline int __uart_put_char(struct uart_port *port, + struct circ_buf *circ, unsigned char c) +{ + unsigned long flags; + int ret = 0; + + if (!circ->buf) + return 0; + + spin_lock_irqsave(&port->lock, flags); + if (uart_circ_chars_free(circ) != 0) { + circ->buf[circ->head] = c; + circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); + ret = 1; + } + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + +static int uart_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct uart_state *state = tty->driver_data; + + return __uart_put_char(state->uart_port, &state->xmit, ch); +} + +static void uart_flush_chars(struct tty_struct *tty) +{ + uart_start(tty); +} + +static int uart_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port; + struct circ_buf *circ; + unsigned long flags; + int c, ret = 0; + + /* + * This means you called this function _after_ the port was + * closed. No cookie for you. + */ + if (!state) { + WARN_ON(1); + return -EL3HLT; + } + + port = state->uart_port; + circ = &state->xmit; + + if (!circ->buf) + return 0; + + spin_lock_irqsave(&port->lock, flags); + while (1) { + c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + memcpy(circ->buf + circ->head, buf, c); + circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); + buf += c; + count -= c; + ret += c; + } + spin_unlock_irqrestore(&port->lock, flags); + + uart_start(tty); + return ret; +} + +static int uart_write_room(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + unsigned long flags; + int ret; + + spin_lock_irqsave(&state->uart_port->lock, flags); + ret = uart_circ_chars_free(&state->xmit); + spin_unlock_irqrestore(&state->uart_port->lock, flags); + return ret; +} + +static int uart_chars_in_buffer(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + unsigned long flags; + int ret; + + spin_lock_irqsave(&state->uart_port->lock, flags); + ret = uart_circ_chars_pending(&state->xmit); + spin_unlock_irqrestore(&state->uart_port->lock, flags); + return ret; +} + +static void uart_flush_buffer(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port; + unsigned long flags; + + /* + * This means you called this function _after_ the port was + * closed. No cookie for you. + */ + if (!state) { + WARN_ON(1); + return; + } + + port = state->uart_port; + pr_debug("uart_flush_buffer(%d) called\n", tty->index); + + spin_lock_irqsave(&port->lock, flags); + uart_circ_clear(&state->xmit); + if (port->ops->flush_buffer) + port->ops->flush_buffer(port); + spin_unlock_irqrestore(&port->lock, flags); + tty_wakeup(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void uart_send_xchar(struct tty_struct *tty, char ch) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + unsigned long flags; + + if (port->ops->send_xchar) + port->ops->send_xchar(port, ch); + else { + port->x_char = ch; + if (ch) { + spin_lock_irqsave(&port->lock, flags); + port->ops->start_tx(port); + spin_unlock_irqrestore(&port->lock, flags); + } + } +} + +static void uart_throttle(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + + if (I_IXOFF(tty)) + uart_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + uart_clear_mctrl(state->uart_port, TIOCM_RTS); +} + +static void uart_unthrottle(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + + if (I_IXOFF(tty)) { + if (port->x_char) + port->x_char = 0; + else + uart_send_xchar(tty, START_CHAR(tty)); + } + + if (tty->termios->c_cflag & CRTSCTS) + uart_set_mctrl(port, TIOCM_RTS); +} + +static int uart_get_info(struct uart_state *state, + struct serial_struct __user *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); + + tmp.type = uport->type; + tmp.line = uport->line; + tmp.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 = port->close_delay / 10; + tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + 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; + + mutex_unlock(&port->mutex); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int uart_set_info(struct tty_struct *tty, struct uart_state *state, + struct serial_struct __user *newinfo) +{ + 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; + if (HIGH_BITS_OFFSET) + new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + + new_serial.irq = irq_canonicalize(new_serial.irq); + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : new_serial.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; + + /* + * Since changing the 'type' of the port changes its resource + * allocations, we should treat type changes the same as + * IO port changes. + */ + 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); + + old_flags = uport->flags; + new_flags = new_serial.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) || + (close_delay != port->close_delay) || + (closing_wait != port->closing_wait) || + (new_serial.xmit_fifo_size && + new_serial.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; + goto check_and_exit; + } + + /* + * Ask the low level driver to verify the settings. + */ + if (uport->ops->verify_port) + retval = uport->ops->verify_port(uport, &new_serial); + + if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || + (new_serial.baud_base < 9600)) + retval = -EINVAL; + + if (retval) + goto exit; + + if (change_port || change_irq) { + retval = -EBUSY; + + /* + * Make sure that we are the sole user of this port. + */ + if (tty_port_users(port) > 1) + goto exit; + + /* + * We need to shutdown the serial port at the old + * port/type/irq combination. + */ + uart_shutdown(tty, state); + } + + if (change_port) { + unsigned long old_iobase, old_mapbase; + unsigned int old_type, old_iotype, old_hub6, old_shift; + + old_iobase = uport->iobase; + old_mapbase = uport->mapbase; + old_type = uport->type; + old_hub6 = uport->hub6; + old_iotype = uport->iotype; + old_shift = uport->regshift; + + /* + * Free and release old regions + */ + if (old_type != PORT_UNKNOWN) + 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; + + /* + * Claim and map the new regions + */ + if (uport->type != PORT_UNKNOWN) { + retval = uport->ops->request_port(uport); + } else { + /* Always success - Jean II */ + retval = 0; + } + + /* + * If we fail to request resources for the + * new port, try to restore the old settings. + */ + if (retval && old_type != PORT_UNKNOWN) { + uport->iobase = old_iobase; + uport->type = old_type; + uport->hub6 = old_hub6; + uport->iotype = old_iotype; + uport->regshift = old_shift; + uport->mapbase = old_mapbase; + retval = uport->ops->request_port(uport); + /* + * If we failed to restore the old settings, + * we fail like this. + */ + if (retval) + uport->type = PORT_UNKNOWN; + + /* + * We failed anyway. + */ + retval = -EBUSY; + /* Added to return the correct error -Ram Gupta */ + goto exit; + } + } + + if (change_irq) + uport->irq = new_serial.irq; + if (!(uport->flags & UPF_FIXED_PORT)) + uport->uartclk = new_serial.baud_base * 16; + uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | + (new_flags & UPF_CHANGE_MASK); + uport->custom_divisor = new_serial.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 (port->tty) + port->tty->low_latency = + (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; + + check_and_exit: + retval = 0; + if (uport->type == PORT_UNKNOWN) + goto exit; + if (port->flags & ASYNC_INITIALIZED) { + if (((old_flags ^ uport->flags) & UPF_SPD_MASK) || + old_custom_divisor != uport->custom_divisor) { + /* + * If they're setting up a custom divisor or speed, + * instead of clearing it, then bitch about it. No + * need to rate-limit; it's CAP_SYS_ADMIN only. + */ + if (uport->flags & UPF_SPD_MASK) { + char buf[64]; + printk(KERN_NOTICE + "%s sets custom speed on %s. This " + "is deprecated.\n", current->comm, + tty_name(port->tty, buf)); + } + uart_change_speed(tty, state, NULL); + } + } else + retval = uart_startup(tty, state, 1); + exit: + mutex_unlock(&port->mutex); + return retval; +} + +/** + * uart_get_lsr_info - get line status register info + * @tty: tty associated with the UART + * @state: UART being queried + * @value: returned modem value + * + * Note: uart_ioctl protects us against hangups. + */ +static int uart_get_lsr_info(struct tty_struct *tty, + struct uart_state *state, unsigned int __user *value) +{ + struct uart_port *uport = state->uart_port; + unsigned int result; + + result = uport->ops->tx_empty(uport); + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if (uport->x_char || + ((uart_circ_chars_pending(&state->xmit) > 0) && + !tty->stopped && !tty->hw_stopped)) + result &= ~TIOCSER_TEMT; + + return put_user(result, value); +} + +static int uart_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; + struct uart_port *uport = state->uart_port; + int result = -EIO; + + mutex_lock(&port->mutex); + if ((!file || !tty_hung_up_p(file)) && + !(tty->flags & (1 << TTY_IO_ERROR))) { + result = uport->mctrl; + + spin_lock_irq(&uport->lock); + result |= uport->ops->get_mctrl(uport); + spin_unlock_irq(&uport->lock); + } + mutex_unlock(&port->mutex); + + return result; +} + +static int +uart_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; + int ret = -EIO; + + mutex_lock(&port->mutex); + if ((!file || !tty_hung_up_p(file)) && + !(tty->flags & (1 << TTY_IO_ERROR))) { + uart_update_mctrl(uport, set, clear); + ret = 0; + } + mutex_unlock(&port->mutex); + return ret; +} + +static int uart_break_ctl(struct tty_struct *tty, int break_state) +{ + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; + struct uart_port *uport = state->uart_port; + + mutex_lock(&port->mutex); + + if (uport->type != PORT_UNKNOWN) + uport->ops->break_ctl(uport, break_state); + + mutex_unlock(&port->mutex); + return 0; +} + +static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) +{ + struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; + int flags, ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* + * Take the per-port semaphore. This prevents count from + * changing, and hence any extra opens of the port while + * we're auto-configuring. + */ + if (mutex_lock_interruptible(&port->mutex)) + return -ERESTARTSYS; + + ret = -EBUSY; + if (tty_port_users(port) == 1) { + uart_shutdown(tty, state); + + /* + * If we already have a port type configured, + * we must release its resources. + */ + if (uport->type != PORT_UNKNOWN) + uport->ops->release_port(uport); + + flags = UART_CONFIG_TYPE; + if (uport->flags & UPF_AUTO_IRQ) + flags |= UART_CONFIG_IRQ; + + /* + * This will claim the ports resources if + * a port is found. + */ + uport->ops->config_port(uport, flags); + + ret = uart_startup(tty, state, 1); + } + mutex_unlock(&port->mutex); + return ret; +} + +/* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + * + * FIXME: This wants extracting into a common all driver implementation + * of TIOCMWAIT using tty_port. + */ +static int +uart_wait_modem_status(struct uart_state *state, unsigned long arg) +{ + struct uart_port *uport = state->uart_port; + struct tty_port *port = &state->port; + DECLARE_WAITQUEUE(wait, current); + struct uart_icount cprev, cnow; + int ret; + + /* + * note the counters on entry + */ + spin_lock_irq(&uport->lock); + memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); + + /* + * Force modem status interrupts on + */ + uport->ops->enable_ms(uport); + spin_unlock_irq(&uport->lock); + + add_wait_queue(&port->delta_msr_wait, &wait); + for (;;) { + spin_lock_irq(&uport->lock); + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); + spin_unlock_irq(&uport->lock); + + set_current_state(TASK_INTERRUPTIBLE); + + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { + ret = 0; + break; + } + + schedule(); + + /* see if a signal did it */ + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + cprev = cnow; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&port->delta_msr_wait, &wait); + + return ret; +} + +/* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ +static int uart_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct uart_state *state = tty->driver_data; + struct uart_icount cnow; + struct uart_port *uport = state->uart_port; + + spin_lock_irq(&uport->lock); + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); + spin_unlock_irq(&uport->lock); + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->rx = cnow.rx; + icount->tx = cnow.tx; + icount->frame = cnow.frame; + icount->overrun = cnow.overrun; + icount->parity = cnow.parity; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; + + return 0; +} + +/* + * Called via sys_ioctl. We can use spin_lock_irq() here. + */ +static int +uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; + void __user *uarg = (void __user *)arg; + int ret = -ENOIOCTLCMD; + + + /* + * These ioctls don't rely on the hardware to be present. + */ + switch (cmd) { + case TIOCGSERIAL: + ret = uart_get_info(state, uarg); + break; + + case TIOCSSERIAL: + ret = uart_set_info(tty, state, uarg); + break; + + case TIOCSERCONFIG: + ret = uart_do_autoconfig(tty, state); + break; + + case TIOCSERGWILD: /* obsolete */ + case TIOCSERSWILD: /* obsolete */ + ret = 0; + break; + } + + if (ret != -ENOIOCTLCMD) + goto out; + + if (tty->flags & (1 << TTY_IO_ERROR)) { + ret = -EIO; + goto out; + } + + /* + * The following should only be used when hardware is present. + */ + switch (cmd) { + case TIOCMIWAIT: + ret = uart_wait_modem_status(state, arg); + break; + } + + if (ret != -ENOIOCTLCMD) + goto out; + + mutex_lock(&port->mutex); + + if (tty_hung_up_p(filp)) { + ret = -EIO; + goto out_up; + } + + /* + * All these rely on hardware being present and need to be + * protected against the tty being hung up. + */ + switch (cmd) { + case TIOCSERGETLSR: /* Get line status register */ + ret = uart_get_lsr_info(tty, state, uarg); + break; + + default: { + struct uart_port *uport = state->uart_port; + if (uport->ops->ioctl) + ret = uport->ops->ioctl(uport, cmd, arg); + break; + } + } +out_up: + mutex_unlock(&port->mutex); +out: + return ret; +} + +static void uart_set_ldisc(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *uport = state->uart_port; + + if (uport->ops->set_ldisc) + uport->ops->set_ldisc(uport, tty->termios->c_line); +} + +static void uart_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) +{ + struct uart_state *state = tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + + /* + * These are the bits that are used to setup various + * flags in the low level driver. We can ignore the Bfoo + * bits in c_cflag; c_[io]speed will always be set + * appropriately by set_termios() in tty_ioctl.c + */ +#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) { + return; + } + + uart_change_speed(tty, state, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR); + /* Handle transition away from B0 status */ + else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + unsigned int mask = TIOCM_DTR; + if (!(cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) + mask |= TIOCM_RTS; + uart_set_mctrl(state->uart_port, mask); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { + spin_lock_irqsave(&state->uart_port->lock, flags); + tty->hw_stopped = 0; + __uart_start(tty); + spin_unlock_irqrestore(&state->uart_port->lock, flags); + } + /* Handle turning on CRTSCTS */ + else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { + spin_lock_irqsave(&state->uart_port->lock, flags); + if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) { + tty->hw_stopped = 1; + state->uart_port->ops->stop_tx(state->uart_port); + } + spin_unlock_irqrestore(&state->uart_port->lock, flags); + } +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&state->uart_port.open_wait); +#endif +} + +/* + * In 2.4.5, calls to this will be serialized via the BKL in + * linux/drivers/char/tty_io.c:tty_release() + * linux/drivers/char/tty_io.c:do_tty_handup() + */ +static void uart_close(struct tty_struct *tty, struct file *filp) +{ + struct uart_state *state = tty->driver_data; + struct tty_port *port; + struct uart_port *uport; + unsigned long flags; + + BUG_ON(!tty_locked()); + + if (!state) + return; + + uport = state->uart_port; + port = &state->port; + + pr_debug("uart_close(%d) called\n", uport->line); + + mutex_lock(&port->mutex); + spin_lock_irqsave(&port->lock, flags); + + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&port->lock, flags); + goto done; + } + + if ((tty->count == 1) && (port->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. port->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. + */ + printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " + "port->count is %d\n", port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", + tty->name, port->count); + port->count = 0; + } + if (port->count) { + spin_unlock_irqrestore(&port->lock, flags); + goto done; + } + + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters by + * setting tty->closing. + */ + tty->closing = 1; + spin_unlock_irqrestore(&port->lock, flags); + + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + /* + * hack: open-coded tty_wait_until_sent to avoid + * recursive tty_lock + */ + long timeout = msecs_to_jiffies(port->closing_wait); + if (wait_event_interruptible_timeout(tty->write_wait, + !tty_chars_in_buffer(tty), timeout) >= 0) + __uart_wait_until_sent(uport, timeout); + } + + /* + * At this point, we stop accepting input. To do this, we + * disable the receive line status interrupts. + */ + if (port->flags & ASYNC_INITIALIZED) { + unsigned long flags; + spin_lock_irqsave(&uport->lock, flags); + uport->ops->stop_rx(uport); + spin_unlock_irqrestore(&uport->lock, flags); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + __uart_wait_until_sent(uport, uport->timeout); + } + + uart_shutdown(tty, state); + uart_flush_buffer(tty); + + tty_ldisc_flush(tty); + + tty_port_tty_set(port, NULL); + spin_lock_irqsave(&port->lock, flags); + tty->closing = 0; + + if (port->blocked_open) { + spin_unlock_irqrestore(&port->lock, flags); + if (port->close_delay) + msleep_interruptible(port->close_delay); + spin_lock_irqsave(&port->lock, flags); + } else if (!uart_console(uport)) { + spin_unlock_irqrestore(&port->lock, flags); + uart_change_pm(state, 3); + spin_lock_irqsave(&port->lock, flags); + } + + /* + * Wake up anyone trying to open this port. + */ + clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); + spin_unlock_irqrestore(&port->lock, flags); + wake_up_interruptible(&port->open_wait); + +done: + mutex_unlock(&port->mutex); +} + +static void __uart_wait_until_sent(struct uart_port *port, int timeout) +{ + unsigned long char_time, expire; + + if (port->type == PORT_UNKNOWN || port->fifosize == 0) + return; + + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (port->timeout - HZ/50) / port->fifosize; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than port->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*port->timeout. + */ + if (timeout == 0 || timeout > 2 * port->timeout) + timeout = 2 * port->timeout; + + expire = jiffies + timeout; + + pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", + port->line, jiffies, expire); + + /* + * Check whether the transmitter is empty every 'char_time'. + * 'timeout' / 'expire' give us the maximum amount of time + * we wait. + */ + while (!port->ops->tx_empty(port)) { + msleep_interruptible(jiffies_to_msecs(char_time)); + if (signal_pending(current)) + break; + if (time_after(jiffies, expire)) + break; + } + set_current_state(TASK_RUNNING); /* might not be needed */ +} + +static void uart_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; + + tty_lock(); + __uart_wait_until_sent(port, timeout); + tty_unlock(); +} + +/* + * This is called with the BKL held in + * linux/drivers/char/tty_io.c:do_tty_hangup() + * We're called from the eventd thread, so we can sleep for + * a _short_ time only. + */ +static void uart_hangup(struct tty_struct *tty) +{ + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; + unsigned long flags; + + BUG_ON(!tty_locked()); + pr_debug("uart_hangup(%d)\n", state->uart_port->line); + + mutex_lock(&port->mutex); + if (port->flags & ASYNC_NORMAL_ACTIVE) { + uart_flush_buffer(tty); + uart_shutdown(tty, state); + spin_lock_irqsave(&port->lock, flags); + port->count = 0; + clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); + spin_unlock_irqrestore(&port->lock, flags); + tty_port_tty_set(port, NULL); + wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->delta_msr_wait); + } + mutex_unlock(&port->mutex); +} + +/** + * uart_update_termios - update the terminal hw settings + * @tty: tty associated with UART + * @state: UART to update + * + * Copy across the serial console cflag setting into the termios settings + * for the initial open of the port. This allows continuity between the + * kernel settings, and the settings init adopts when it opens the port + * for the first time. + */ +static void uart_update_termios(struct tty_struct *tty, + struct uart_state *state) +{ + struct uart_port *port = state->uart_port; + + if (uart_console(port) && port->cons->cflag) { + tty->termios->c_cflag = port->cons->cflag; + port->cons->cflag = 0; + } + + /* + * If the device failed to grab its irq resources, + * or some other error occurred, don't try to talk + * to the port hardware. + */ + if (!(tty->flags & (1 << TTY_IO_ERROR))) { + /* + * Make termios settings take effect. + */ + uart_change_speed(tty, state, NULL); + + /* + * And finally enable the RTS and DTR signals. + */ + if (tty->termios->c_cflag & CBAUD) + uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); + } +} + +static int uart_carrier_raised(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + int mctrl; + spin_lock_irq(&uport->lock); + uport->ops->enable_ms(uport); + mctrl = uport->ops->get_mctrl(uport); + spin_unlock_irq(&uport->lock); + if (mctrl & TIOCM_CAR) + return 1; + return 0; +} + +static void uart_dtr_rts(struct tty_port *port, int onoff) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + + if (onoff) { + uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + + /* + * If this is the first open to succeed, + * adjust things to suit. + */ + if (!test_and_set_bit(ASYNCB_NORMAL_ACTIVE, &port->flags)) + uart_update_termios(port->tty, state); + } + else + uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); +} + +static struct uart_state *uart_get(struct uart_driver *drv, int line) +{ + struct uart_state *state; + struct tty_port *port; + int ret = 0; + + state = drv->state + line; + port = &state->port; + if (mutex_lock_interruptible(&port->mutex)) { + ret = -ERESTARTSYS; + goto err; + } + + port->count++; + if (!state->uart_port || state->uart_port->flags & UPF_DEAD) { + ret = -ENXIO; + goto err_unlock; + } + return state; + + err_unlock: + port->count--; + mutex_unlock(&port->mutex); + err: + return ERR_PTR(ret); +} + +/* + * calls to uart_open are serialised by the BKL in + * fs/char_dev.c:chrdev_open() + * Note that if this fails, then uart_close() _will_ be called. + * + * In time, we want to scrap the "opening nonpresent ports" + * behaviour and implement an alternative way for setserial + * to set base addresses/ports/types. This will allow us to + * get rid of a certain amount of extra tests. + */ +static int uart_open(struct tty_struct *tty, struct file *filp) +{ + struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; + struct uart_state *state; + struct tty_port *port; + int retval, line = tty->index; + + BUG_ON(!tty_locked()); + pr_debug("uart_open(%d) called\n", line); + + /* + * tty->driver->num won't change, so we won't fail here with + * tty->driver_data set to something non-NULL (and therefore + * we won't get caught by uart_close()). + */ + retval = -ENODEV; + if (line >= tty->driver->num) + goto fail; + + /* + * We take the semaphore inside uart_get to guarantee that we won't + * be re-entered while allocating the state structure, or while we + * request any IRQs that the driver may need. This also has the nice + * side-effect that it delays the action of uart_hangup, so we can + * guarantee that state->port.tty will always contain something + * reasonable. + */ + state = uart_get(drv, line); + if (IS_ERR(state)) { + retval = PTR_ERR(state); + goto fail; + } + port = &state->port; + + /* + * Once we set tty->driver_data here, we are guaranteed that + * uart_close() will decrement the driver module use count. + * Any failures from here onwards should not touch the count. + */ + tty->driver_data = state; + state->uart_port->state = state; + tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; + tty->alt_speed = 0; + tty_port_tty_set(port, tty); + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp)) { + retval = -EAGAIN; + port->count--; + mutex_unlock(&port->mutex); + goto fail; + } + + /* + * Make sure the device is in D0 state. + */ + if (port->count == 1) + uart_change_pm(state, 0); + + /* + * Start up the serial port. + */ + retval = uart_startup(tty, state, 0); + + /* + * If we succeeded, wait until the port is ready. + */ + mutex_unlock(&port->mutex); + if (retval == 0) + retval = tty_port_block_til_ready(port, tty, filp); + +fail: + return retval; +} + +static const char *uart_type(struct uart_port *port) +{ + const char *str = NULL; + + if (port->ops->type) + str = port->ops->type(port); + + if (!str) + str = "unknown"; + + return str; +} + +#ifdef CONFIG_PROC_FS + +static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) +{ + struct uart_state *state = drv->state + i; + struct tty_port *port = &state->port; + int pm_state; + struct uart_port *uport = state->uart_port; + char stat_buf[32]; + unsigned int status; + int mmio; + + if (!uport) + return; + + mmio = uport->iotype >= UPIO_MEM; + seq_printf(m, "%d: uart:%s %s%08llX irq:%d", + uport->line, uart_type(uport), + mmio ? "mmio:0x" : "port:", + mmio ? (unsigned long long)uport->mapbase + : (unsigned long long)uport->iobase, + uport->irq); + + if (uport->type == PORT_UNKNOWN) { + seq_putc(m, '\n'); + return; + } + + if (capable(CAP_SYS_ADMIN)) { + mutex_lock(&port->mutex); + pm_state = state->pm_state; + if (pm_state) + uart_change_pm(state, 0); + spin_lock_irq(&uport->lock); + status = uport->ops->get_mctrl(uport); + spin_unlock_irq(&uport->lock); + if (pm_state) + uart_change_pm(state, pm_state); + mutex_unlock(&port->mutex); + + seq_printf(m, " tx:%d rx:%d", + uport->icount.tx, uport->icount.rx); + if (uport->icount.frame) + seq_printf(m, " fe:%d", + uport->icount.frame); + if (uport->icount.parity) + seq_printf(m, " pe:%d", + uport->icount.parity); + if (uport->icount.brk) + seq_printf(m, " brk:%d", + uport->icount.brk); + if (uport->icount.overrun) + seq_printf(m, " oe:%d", + uport->icount.overrun); + +#define INFOBIT(bit, str) \ + if (uport->mctrl & (bit)) \ + strncat(stat_buf, (str), sizeof(stat_buf) - \ + strlen(stat_buf) - 2) +#define STATBIT(bit, str) \ + if (status & (bit)) \ + strncat(stat_buf, (str), sizeof(stat_buf) - \ + strlen(stat_buf) - 2) + + stat_buf[0] = '\0'; + stat_buf[1] = '\0'; + INFOBIT(TIOCM_RTS, "|RTS"); + STATBIT(TIOCM_CTS, "|CTS"); + INFOBIT(TIOCM_DTR, "|DTR"); + STATBIT(TIOCM_DSR, "|DSR"); + STATBIT(TIOCM_CAR, "|CD"); + STATBIT(TIOCM_RNG, "|RI"); + if (stat_buf[0]) + stat_buf[0] = ' '; + + seq_puts(m, stat_buf); + } + seq_putc(m, '\n'); +#undef STATBIT +#undef INFOBIT +} + +static int uart_proc_show(struct seq_file *m, void *v) +{ + struct tty_driver *ttydrv = m->private; + struct uart_driver *drv = ttydrv->driver_state; + int i; + + seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", + "", "", ""); + for (i = 0; i < drv->nr; i++) + uart_line_info(m, drv, i); + return 0; +} + +static int uart_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, uart_proc_show, PDE(inode)->data); +} + +static const struct file_operations uart_proc_fops = { + .owner = THIS_MODULE, + .open = uart_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) +/* + * uart_console_write - write a console message to a serial port + * @port: the port to write the message + * @s: array of characters + * @count: number of characters in string to write + * @write: function to write character to port + */ +void uart_console_write(struct uart_port *port, const char *s, + unsigned int count, + void (*putchar)(struct uart_port *, int)) +{ + unsigned int i; + + for (i = 0; i < count; i++, s++) { + if (*s == '\n') + putchar(port, '\r'); + putchar(port, *s); + } +} +EXPORT_SYMBOL_GPL(uart_console_write); + +/* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ +struct uart_port * __init +uart_get_console(struct uart_port *ports, int nr, struct console *co) +{ + int idx = co->index; + + if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && + ports[idx].membase == NULL)) + for (idx = 0; idx < nr; idx++) + if (ports[idx].iobase != 0 || + ports[idx].membase != NULL) + break; + + co->index = idx; + + return ports + idx; +} + +/** + * uart_parse_options - Parse serial port baud/parity/bits/flow contro. + * @options: pointer to option string + * @baud: pointer to an 'int' variable for the baud rate. + * @parity: pointer to an 'int' variable for the parity. + * @bits: pointer to an 'int' variable for the number of data bits. + * @flow: pointer to an 'int' variable for the flow control character. + * + * uart_parse_options decodes a string containing the serial console + * options. The format of the string is , + * eg: 115200n8r + */ +void +uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) +{ + char *s = options; + + *baud = simple_strtoul(s, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + if (*s) + *parity = *s++; + if (*s) + *bits = *s++ - '0'; + if (*s) + *flow = *s; +} +EXPORT_SYMBOL_GPL(uart_parse_options); + +struct baud_rates { + unsigned int rate; + unsigned int cflag; +}; + +static const struct baud_rates baud_rates[] = { + { 921600, B921600 }, + { 460800, B460800 }, + { 230400, B230400 }, + { 115200, B115200 }, + { 57600, B57600 }, + { 38400, B38400 }, + { 19200, B19200 }, + { 9600, B9600 }, + { 4800, B4800 }, + { 2400, B2400 }, + { 1200, B1200 }, + { 0, B38400 } +}; + +/** + * uart_set_options - setup the serial console parameters + * @port: pointer to the serial ports uart_port structure + * @co: console pointer + * @baud: baud rate + * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) + * @bits: number of data bits + * @flow: flow control character - 'r' (rts) + */ +int +uart_set_options(struct uart_port *port, struct console *co, + int baud, int parity, int bits, int flow) +{ + struct ktermios termios; + static struct ktermios dummy; + int i; + + /* + * Ensure that the serial console lock is initialised + * early. + */ + spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); + + memset(&termios, 0, sizeof(struct ktermios)); + + termios.c_cflag = CREAD | HUPCL | CLOCAL; + + /* + * Construct a cflag setting. + */ + for (i = 0; baud_rates[i].rate; i++) + if (baud_rates[i].rate <= baud) + break; + + termios.c_cflag |= baud_rates[i].cflag; + + if (bits == 7) + termios.c_cflag |= CS7; + else + termios.c_cflag |= CS8; + + switch (parity) { + case 'o': case 'O': + termios.c_cflag |= PARODD; + /*fall through*/ + case 'e': case 'E': + termios.c_cflag |= PARENB; + break; + } + + if (flow == 'r') + termios.c_cflag |= CRTSCTS; + + /* + * some uarts on other side don't support no flow control. + * So we set * DTR in host uart to make them happy + */ + port->mctrl |= TIOCM_DTR; + + port->ops->set_termios(port, &termios, &dummy); + /* + * Allow the setting of the UART parameters with a NULL console + * too: + */ + if (co) + co->cflag = termios.c_cflag; + + return 0; +} +EXPORT_SYMBOL_GPL(uart_set_options); +#endif /* CONFIG_SERIAL_CORE_CONSOLE */ + +static void uart_change_pm(struct uart_state *state, int pm_state) +{ + struct uart_port *port = state->uart_port; + + if (state->pm_state != pm_state) { + if (port->ops->pm) + port->ops->pm(port, pm_state, state->pm_state); + state->pm_state = pm_state; + } +} + +struct uart_match { + struct uart_port *port; + struct uart_driver *driver; +}; + +static int serial_match_port(struct device *dev, void *data) +{ + struct uart_match *match = data; + struct tty_driver *tty_drv = match->driver->tty_driver; + dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + + match->port->line; + + return dev->devt == devt; /* Actually, only one tty per port */ +} + +int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) +{ + struct uart_state *state = drv->state + uport->line; + struct tty_port *port = &state->port; + struct device *tty_dev; + struct uart_match match = {uport, drv}; + struct tty_struct *tty; + + mutex_lock(&port->mutex); + + /* Must be inside the mutex lock until we convert to tty_port */ + tty = port->tty; + + tty_dev = device_find_child(uport->dev, &match, serial_match_port); + if (device_may_wakeup(tty_dev)) { + if (!enable_irq_wake(uport->irq)) + uport->irq_wake = 1; + put_device(tty_dev); + mutex_unlock(&port->mutex); + return 0; + } + if (console_suspend_enabled || !uart_console(uport)) + uport->suspended = 1; + + if (port->flags & ASYNC_INITIALIZED) { + const struct uart_ops *ops = uport->ops; + int tries; + + if (console_suspend_enabled || !uart_console(uport)) { + set_bit(ASYNCB_SUSPENDED, &port->flags); + clear_bit(ASYNCB_INITIALIZED, &port->flags); + + spin_lock_irq(&uport->lock); + ops->stop_tx(uport); + ops->set_mctrl(uport, 0); + ops->stop_rx(uport); + spin_unlock_irq(&uport->lock); + } + + /* + * Wait for the transmitter to empty. + */ + for (tries = 3; !ops->tx_empty(uport) && tries; tries--) + msleep(10); + if (!tries) + printk(KERN_ERR "%s%s%s%d: Unable to drain " + "transmitter\n", + uport->dev ? dev_name(uport->dev) : "", + uport->dev ? ": " : "", + drv->dev_name, + drv->tty_driver->name_base + uport->line); + + if (console_suspend_enabled || !uart_console(uport)) + ops->shutdown(uport); + } + + /* + * Disable the console device before suspending. + */ + if (console_suspend_enabled && uart_console(uport)) + console_stop(uport->cons); + + if (console_suspend_enabled || !uart_console(uport)) + uart_change_pm(state, 3); + + mutex_unlock(&port->mutex); + + return 0; +} + +int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) +{ + struct uart_state *state = drv->state + uport->line; + struct tty_port *port = &state->port; + struct device *tty_dev; + struct uart_match match = {uport, drv}; + struct ktermios termios; + + mutex_lock(&port->mutex); + + tty_dev = device_find_child(uport->dev, &match, serial_match_port); + if (!uport->suspended && device_may_wakeup(tty_dev)) { + if (uport->irq_wake) { + disable_irq_wake(uport->irq); + uport->irq_wake = 0; + } + mutex_unlock(&port->mutex); + return 0; + } + uport->suspended = 0; + + /* + * Re-enable the console device after suspending. + */ + if (console_suspend_enabled && uart_console(uport)) { + /* + * First try to use the console cflag setting. + */ + memset(&termios, 0, sizeof(struct ktermios)); + termios.c_cflag = uport->cons->cflag; + + /* + * If that's unset, use the tty termios setting. + */ + if (port->tty && port->tty->termios && termios.c_cflag == 0) + termios = *(port->tty->termios); + + uart_change_pm(state, 0); + uport->ops->set_termios(uport, &termios, NULL); + console_start(uport->cons); + } + + if (port->flags & ASYNC_SUSPENDED) { + const struct uart_ops *ops = uport->ops; + int ret; + + uart_change_pm(state, 0); + spin_lock_irq(&uport->lock); + ops->set_mctrl(uport, 0); + spin_unlock_irq(&uport->lock); + if (console_suspend_enabled || !uart_console(uport)) { + /* Protected by port mutex for now */ + struct tty_struct *tty = port->tty; + ret = ops->startup(uport); + if (ret == 0) { + if (tty) + uart_change_speed(tty, state, NULL); + spin_lock_irq(&uport->lock); + ops->set_mctrl(uport, uport->mctrl); + ops->start_tx(uport); + spin_unlock_irq(&uport->lock); + set_bit(ASYNCB_INITIALIZED, &port->flags); + } else { + /* + * Failed to resume - maybe hardware went away? + * Clear the "initialized" flag so we won't try + * to call the low level drivers shutdown method. + */ + uart_shutdown(tty, state); + } + } + + clear_bit(ASYNCB_SUSPENDED, &port->flags); + } + + mutex_unlock(&port->mutex); + + return 0; +} + +static inline void +uart_report_port(struct uart_driver *drv, struct uart_port *port) +{ + char address[64]; + + switch (port->iotype) { + case UPIO_PORT: + snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); + break; + case UPIO_HUB6: + snprintf(address, sizeof(address), + "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); + break; + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: + case UPIO_TSI: + case UPIO_DWAPB: + case UPIO_DWAPB32: + snprintf(address, sizeof(address), + "MMIO 0x%llx", (unsigned long long)port->mapbase); + break; + default: + strlcpy(address, "*unknown*", sizeof(address)); + break; + } + + printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", + port->dev ? dev_name(port->dev) : "", + port->dev ? ": " : "", + drv->dev_name, + drv->tty_driver->name_base + port->line, + address, port->irq, uart_type(port)); +} + +static void +uart_configure_port(struct uart_driver *drv, struct uart_state *state, + struct uart_port *port) +{ + unsigned int flags; + + /* + * If there isn't a port here, don't do anything further. + */ + if (!port->iobase && !port->mapbase && !port->membase) + return; + + /* + * Now do the auto configuration stuff. Note that config_port + * is expected to claim the resources and map the port for us. + */ + flags = 0; + if (port->flags & UPF_AUTO_IRQ) + flags |= UART_CONFIG_IRQ; + if (port->flags & UPF_BOOT_AUTOCONF) { + if (!(port->flags & UPF_FIXED_TYPE)) { + port->type = PORT_UNKNOWN; + flags |= UART_CONFIG_TYPE; + } + port->ops->config_port(port, flags); + } + + if (port->type != PORT_UNKNOWN) { + unsigned long flags; + + uart_report_port(drv, port); + + /* Power up port for set_mctrl() */ + uart_change_pm(state, 0); + + /* + * Ensure that the modem control lines are de-activated. + * keep the DTR setting that is set in uart_set_options() + * We probably don't need a spinlock around this, but + */ + spin_lock_irqsave(&port->lock, flags); + port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * If this driver supports console, and it hasn't been + * successfully registered yet, try to re-register it. + * It may be that the port was not available. + */ + if (port->cons && !(port->cons->flags & CON_ENABLED)) + register_console(port->cons); + + /* + * Power down all ports by default, except the + * console if we have one. + */ + if (!uart_console(port)) + uart_change_pm(state, 3); + } +} + +#ifdef CONFIG_CONSOLE_POLL + +static int uart_poll_init(struct tty_driver *driver, int line, char *options) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (!state || !state->uart_port) + return -1; + + port = state->uart_port; + if (!(port->ops->poll_get_char && port->ops->poll_put_char)) + return -1; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(port, NULL, baud, parity, bits, flow); + } + + return 0; +} + +static int uart_poll_get_char(struct tty_driver *driver, int line) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + + if (!state || !state->uart_port) + return -1; + + port = state->uart_port; + return port->ops->poll_get_char(port); +} + +static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) +{ + struct uart_driver *drv = driver->driver_state; + struct uart_state *state = drv->state + line; + struct uart_port *port; + + if (!state || !state->uart_port) + return; + + port = state->uart_port; + port->ops->poll_put_char(port, ch); +} +#endif + +static const struct tty_operations uart_ops = { + .open = uart_open, + .close = uart_close, + .write = uart_write, + .put_char = uart_put_char, + .flush_chars = uart_flush_chars, + .write_room = uart_write_room, + .chars_in_buffer= uart_chars_in_buffer, + .flush_buffer = uart_flush_buffer, + .ioctl = uart_ioctl, + .throttle = uart_throttle, + .unthrottle = uart_unthrottle, + .send_xchar = uart_send_xchar, + .set_termios = uart_set_termios, + .set_ldisc = uart_set_ldisc, + .stop = uart_stop, + .start = uart_start, + .hangup = uart_hangup, + .break_ctl = uart_break_ctl, + .wait_until_sent= uart_wait_until_sent, +#ifdef CONFIG_PROC_FS + .proc_fops = &uart_proc_fops, +#endif + .tiocmget = uart_tiocmget, + .tiocmset = uart_tiocmset, + .get_icount = uart_get_icount, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = uart_poll_init, + .poll_get_char = uart_poll_get_char, + .poll_put_char = uart_poll_put_char, +#endif +}; + +static const struct tty_port_operations uart_port_ops = { + .carrier_raised = uart_carrier_raised, + .dtr_rts = uart_dtr_rts, +}; + +/** + * uart_register_driver - register a driver with the uart core layer + * @drv: low level driver structure + * + * Register a uart driver with the core driver. We in turn register + * with the tty layer, and initialise the core driver per-port state. + * + * We have a proc file in /proc/tty/driver which is named after the + * normal driver. + * + * drv->port should be NULL, and the per-port structures should be + * registered using uart_add_one_port after this call has succeeded. + */ +int uart_register_driver(struct uart_driver *drv) +{ + struct tty_driver *normal; + int i, retval; + + BUG_ON(drv->state); + + /* + * Maybe we should be using a slab cache for this, especially if + * we have a large number of ports to handle. + */ + drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); + if (!drv->state) + goto out; + + normal = alloc_tty_driver(drv->nr); + if (!normal) + goto out_kfree; + + drv->tty_driver = normal; + + normal->owner = drv->owner; + normal->driver_name = drv->driver_name; + normal->name = drv->dev_name; + normal->major = drv->major; + normal->minor_start = drv->minor; + normal->type = TTY_DRIVER_TYPE_SERIAL; + normal->subtype = SERIAL_TYPE_NORMAL; + normal->init_termios = tty_std_termios; + normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; + normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + normal->driver_state = drv; + tty_set_operations(normal, &uart_ops); + + /* + * Initialise the UART state(s). + */ + for (i = 0; i < drv->nr; i++) { + struct uart_state *state = drv->state + i; + struct tty_port *port = &state->port; + + tty_port_init(port); + port->ops = &uart_port_ops; + port->close_delay = 500; /* .5 seconds */ + port->closing_wait = 30000; /* 30 seconds */ + tasklet_init(&state->tlet, uart_tasklet_action, + (unsigned long)state); + } + + retval = tty_register_driver(normal); + if (retval >= 0) + return retval; + + put_tty_driver(normal); +out_kfree: + kfree(drv->state); +out: + return -ENOMEM; +} + +/** + * uart_unregister_driver - remove a driver from the uart core layer + * @drv: low level driver structure + * + * Remove all references to a driver from the core driver. The low + * level driver must have removed all its ports via the + * uart_remove_one_port() if it registered them with uart_add_one_port(). + * (ie, drv->port == NULL) + */ +void uart_unregister_driver(struct uart_driver *drv) +{ + struct tty_driver *p = drv->tty_driver; + tty_unregister_driver(p); + put_tty_driver(p); + kfree(drv->state); + drv->tty_driver = NULL; +} + +struct tty_driver *uart_console_device(struct console *co, int *index) +{ + struct uart_driver *p = co->data; + *index = co->index; + return p->tty_driver; +} + +/** + * uart_add_one_port - attach a driver-defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @uport: uart port structure to use for this port. + * + * This allows the driver to register its own uart_port structure + * with the core driver. The main purpose is to allow the low + * level uart drivers to expand uart_port, rather than having yet + * more levels of structures. + */ +int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) +{ + struct uart_state *state; + struct tty_port *port; + int ret = 0; + struct device *tty_dev; + + BUG_ON(in_interrupt()); + + if (uport->line >= drv->nr) + return -EINVAL; + + state = drv->state + uport->line; + port = &state->port; + + mutex_lock(&port_mutex); + mutex_lock(&port->mutex); + if (state->uart_port) { + ret = -EINVAL; + goto out; + } + + state->uart_port = uport; + state->pm_state = -1; + + uport->cons = drv->cons; + uport->state = state; + + /* + * If this port is a console, then the spinlock is already + * initialised. + */ + if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { + spin_lock_init(&uport->lock); + lockdep_set_class(&uport->lock, &port_lock_key); + } + + uart_configure_port(drv, state, 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); + if (likely(!IS_ERR(tty_dev))) { + device_init_wakeup(tty_dev, 1); + device_set_wakeup_enable(tty_dev, 0); + } else + printk(KERN_ERR "Cannot register tty device on line %d\n", + uport->line); + + /* + * Ensure UPF_DEAD is not set. + */ + uport->flags &= ~UPF_DEAD; + + out: + mutex_unlock(&port->mutex); + mutex_unlock(&port_mutex); + + return ret; +} + +/** + * uart_remove_one_port - detach a driver defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @uport: uart port structure for this port + * + * This unhooks (and hangs up) the specified port structure from the + * core driver. No further calls will be made to the low-level code + * for this port. + */ +int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) +{ + struct uart_state *state = drv->state + uport->line; + struct tty_port *port = &state->port; + + BUG_ON(in_interrupt()); + + if (state->uart_port != uport) + printk(KERN_ALERT "Removing wrong port: %p != %p\n", + state->uart_port, uport); + + mutex_lock(&port_mutex); + + /* + * Mark the port "dead" - this prevents any opens from + * succeeding while we shut down the port. + */ + mutex_lock(&port->mutex); + uport->flags |= UPF_DEAD; + mutex_unlock(&port->mutex); + + /* + * Remove the devices from the tty layer + */ + tty_unregister_device(drv->tty_driver, uport->line); + + if (port->tty) + tty_vhangup(port->tty); + + /* + * Free the port IO and memory resources, if any. + */ + if (uport->type != PORT_UNKNOWN) + uport->ops->release_port(uport); + + /* + * Indicate that there isn't a port here anymore. + */ + uport->type = PORT_UNKNOWN; + + /* + * Kill the tasklet, and free resources. + */ + tasklet_kill(&state->tlet); + + state->uart_port = NULL; + mutex_unlock(&port_mutex); + + return 0; +} + +/* + * Are the two ports equivalent? + */ +int uart_match_port(struct uart_port *port1, struct uart_port *port2) +{ + if (port1->iotype != port2->iotype) + return 0; + + switch (port1->iotype) { + case UPIO_PORT: + return (port1->iobase == port2->iobase); + case UPIO_HUB6: + return (port1->iobase == port2->iobase) && + (port1->hub6 == port2->hub6); + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_AU: + case UPIO_TSI: + case UPIO_DWAPB: + case UPIO_DWAPB32: + return (port1->mapbase == port2->mapbase); + } + return 0; +} +EXPORT_SYMBOL(uart_match_port); + +EXPORT_SYMBOL(uart_write_wakeup); +EXPORT_SYMBOL(uart_register_driver); +EXPORT_SYMBOL(uart_unregister_driver); +EXPORT_SYMBOL(uart_suspend_port); +EXPORT_SYMBOL(uart_resume_port); +EXPORT_SYMBOL(uart_add_one_port); +EXPORT_SYMBOL(uart_remove_one_port); + +MODULE_DESCRIPTION("Serial driver core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_cs.c b/drivers/tty/serial/serial_cs.c new file mode 100644 index 000000000000..93760b2ea172 --- /dev/null +++ b/drivers/tty/serial/serial_cs.c @@ -0,0 +1,869 @@ +/*====================================================================== + + A driver for PCMCIA serial devices + + serial_cs.c 1.134 2002/05/04 05:48:53 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "8250.h" + + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Enable the speaker? */ +static int do_sound = 1; +/* Skip strict UART tests? */ +static int buggy_uart; + +module_param(do_sound, int, 0444); +module_param(buggy_uart, int, 0444); + +/*====================================================================*/ + +/* Table of multi-port card ID's */ + +struct serial_quirk { + unsigned int manfid; + unsigned int prodid; + int multi; /* 1 = multifunction, > 1 = # ports */ + void (*config)(struct pcmcia_device *); + void (*setup)(struct pcmcia_device *, struct uart_port *); + void (*wakeup)(struct pcmcia_device *); + int (*post)(struct pcmcia_device *); +}; + +struct serial_info { + struct pcmcia_device *p_dev; + int ndev; + int multi; + int slave; + int manfid; + int prodid; + int c950ctrl; + int line[4]; + const struct serial_quirk *quirk; +}; + +struct serial_cfg_mem { + tuple_t tuple; + cisparse_t parse; + u_char buf[256]; +}; + +/* + * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6" + * manfid 0x0160, 0x0104 + * This card appears to have a 14.7456MHz clock. + */ +/* Generic Modem: MD55x (GPRS/EDGE) have + * Elan VPU16551 UART with 14.7456MHz oscillator + * manfid 0x015D, 0x4C45 + */ +static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port) +{ + port->uartclk = 14745600; +} + +static int quirk_post_ibm(struct pcmcia_device *link) +{ + u8 val; + int ret; + + ret = pcmcia_read_config_byte(link, 0x800, &val); + if (ret) + goto failed; + + ret = pcmcia_write_config_byte(link, 0x800, val | 1); + if (ret) + goto failed; + return 0; + + failed: + return -ENODEV; +} + +/* + * Nokia cards are not really multiport cards. Shouldn't this + * be handled by setting the quirk entry .multi = 0 | 1 ? + */ +static void quirk_config_nokia(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + + if (info->multi > 1) + info->multi = 1; +} + +static void quirk_wakeup_oxsemi(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + + if (info->c950ctrl) + outb(12, info->c950ctrl + 1); +} + +/* request_region? oxsemi branch does no request_region too... */ +/* + * This sequence is needed to properly initialize MC45 attached to OXCF950. + * I tried decreasing these msleep()s, but it worked properly (survived + * 1000 stop/start operations) with these timeouts (or bigger). + */ +static void quirk_wakeup_possio_gcc(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + unsigned int ctrl = info->c950ctrl; + + outb(0xA, ctrl + 1); + msleep(100); + outb(0xE, ctrl + 1); + msleep(300); + outb(0xC, ctrl + 1); + msleep(100); + outb(0xE, ctrl + 1); + msleep(200); + outb(0xF, ctrl + 1); + msleep(100); + outb(0xE, ctrl + 1); + msleep(100); + outb(0xC, ctrl + 1); +} + +/* + * Socket Dual IO: this enables irq's for second port + */ +static void quirk_config_socket(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + + if (info->multi) + link->config_flags |= CONF_ENABLE_ESR; +} + +static const struct serial_quirk quirks[] = { + { + .manfid = 0x0160, + .prodid = 0x0104, + .multi = -1, + .setup = quirk_setup_brainboxes_0104, + }, { + .manfid = 0x015D, + .prodid = 0x4C45, + .multi = -1, + .setup = quirk_setup_brainboxes_0104, + }, { + .manfid = MANFID_IBM, + .prodid = ~0, + .multi = -1, + .post = quirk_post_ibm, + }, { + .manfid = MANFID_INTEL, + .prodid = PRODID_INTEL_DUAL_RS232, + .multi = 2, + }, { + .manfid = MANFID_NATINST, + .prodid = PRODID_NATINST_QUAD_RS232, + .multi = 4, + }, { + .manfid = MANFID_NOKIA, + .prodid = ~0, + .multi = -1, + .config = quirk_config_nokia, + }, { + .manfid = MANFID_OMEGA, + .prodid = PRODID_OMEGA_QSP_100, + .multi = 4, + }, { + .manfid = MANFID_OXSEMI, + .prodid = ~0, + .multi = -1, + .wakeup = quirk_wakeup_oxsemi, + }, { + .manfid = MANFID_POSSIO, + .prodid = PRODID_POSSIO_GCC, + .multi = -1, + .wakeup = quirk_wakeup_possio_gcc, + }, { + .manfid = MANFID_QUATECH, + .prodid = PRODID_QUATECH_DUAL_RS232, + .multi = 2, + }, { + .manfid = MANFID_QUATECH, + .prodid = PRODID_QUATECH_DUAL_RS232_D1, + .multi = 2, + }, { + .manfid = MANFID_QUATECH, + .prodid = PRODID_QUATECH_DUAL_RS232_G, + .multi = 2, + }, { + .manfid = MANFID_QUATECH, + .prodid = PRODID_QUATECH_QUAD_RS232, + .multi = 4, + }, { + .manfid = MANFID_SOCKET, + .prodid = PRODID_SOCKET_DUAL_RS232, + .multi = 2, + .config = quirk_config_socket, + }, { + .manfid = MANFID_SOCKET, + .prodid = ~0, + .multi = -1, + .config = quirk_config_socket, + } +}; + + +static int serial_config(struct pcmcia_device * link); + + +static void serial_remove(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i; + + dev_dbg(&link->dev, "serial_release\n"); + + /* + * Recheck to see if the device is still configured. + */ + for (i = 0; i < info->ndev; i++) + serial8250_unregister_port(info->line[i]); + + if (!info->slave) + pcmcia_disable_device(link); +} + +static int serial_suspend(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i; + + for (i = 0; i < info->ndev; i++) + serial8250_suspend_port(info->line[i]); + + return 0; +} + +static int serial_resume(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i; + + for (i = 0; i < info->ndev; i++) + serial8250_resume_port(info->line[i]); + + if (info->quirk && info->quirk->wakeup) + info->quirk->wakeup(link); + + return 0; +} + +static int serial_probe(struct pcmcia_device *link) +{ + struct serial_info *info; + + dev_dbg(&link->dev, "serial_attach()\n"); + + /* Create new serial device */ + info = kzalloc(sizeof (*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->p_dev = link; + link->priv = info; + + link->config_flags |= CONF_ENABLE_IRQ; + if (do_sound) + link->config_flags |= CONF_ENABLE_SPKR; + + return serial_config(link); +} + +static void serial_detach(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + + dev_dbg(&link->dev, "serial_detach\n"); + + /* + * Ensure that the ports have been released. + */ + serial_remove(link); + + /* free bits */ + kfree(info); +} + +/*====================================================================*/ + +static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, + unsigned int iobase, int irq) +{ + struct uart_port port; + 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; + if (buggy_uart) + port.flags |= UPF_BUGGY_UART; + + if (info->quirk && info->quirk->setup) + info->quirk->setup(handle, &port); + + line = serial8250_register_port(&port); + if (line < 0) { + printk(KERN_NOTICE "serial_cs: serial8250_register_port() at " + "0x%04lx, irq %d failed\n", (u_long)iobase, irq); + return -EINVAL; + } + + info->line[info->ndev] = line; + info->ndev++; + + return 0; +} + +/*====================================================================*/ + +static int pfc_config(struct pcmcia_device *p_dev) +{ + unsigned int port = 0; + struct serial_info *info = p_dev->priv; + + if ((p_dev->resource[1]->end != 0) && + (resource_size(p_dev->resource[1]) == 8)) { + port = p_dev->resource[1]->start; + info->slave = 1; + } else if ((info->manfid == MANFID_OSITECH) && + (resource_size(p_dev->resource[0]) == 0x40)) { + port = p_dev->resource[0]->start + 0x28; + info->slave = 1; + } + if (info->slave) + return setup_serial(p_dev, info, port, p_dev->irq); + + dev_warn(&p_dev->dev, "no usable port range found, giving up\n"); + return -ENODEV; +} + +static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data) +{ + static const int size_table[2] = { 8, 16 }; + int *try = priv_data; + + if (p_dev->resource[0]->start == 0) + return -ENODEV; + + if ((*try & 0x1) == 0) + p_dev->io_lines = 16; + + if (p_dev->resource[0]->end != size_table[(*try >> 1)]) + return -ENODEV; + + p_dev->resource[0]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + + return pcmcia_request_io(p_dev); +} + +static int simple_config_check_notpicky(struct pcmcia_device *p_dev, + void *priv_data) +{ + static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + int j; + + if (p_dev->io_lines > 3) + return -ENODEV; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 8; + + for (j = 0; j < 5; j++) { + p_dev->resource[0]->start = base[j]; + p_dev->io_lines = base[j] ? 16 : 3; + if (!pcmcia_request_io(p_dev)) + return 0; + } + return -ENODEV; +} + +static int simple_config(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i = -ENODEV, try; + + /* First pass: look for a config entry that looks normal. + * Two tries: without IO aliases, then with aliases */ + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO; + for (try = 0; try < 4; try++) + if (!pcmcia_loop_config(link, simple_config_check, &try)) + goto found_port; + + /* Second pass: try to find an entry that isn't picky about + its base address, then try to grab any standard serial port + address, and finally try to get any free port. */ + if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) + goto found_port; + + dev_warn(&link->dev, "no usable port range found, giving up\n"); + return -1; + +found_port: + if (info->multi && (info->manfid == MANFID_3COM)) + link->config_index &= ~(0x08); + + /* + * Apply any configuration quirks. + */ + if (info->quirk && info->quirk->config) + info->quirk->config(link); + + i = pcmcia_enable_device(link); + if (i != 0) + return -1; + return setup_serial(link, info, link->resource[0]->start, link->irq); +} + +static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data) +{ + int *multi = priv_data; + + if (p_dev->resource[1]->end) + return -EINVAL; + + /* The quad port cards have bad CIS's, so just look for a + window larger than 8 ports and assume it will be right */ + if (p_dev->resource[0]->end <= 8) + return -EINVAL; + + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = *multi * 8; + + if (pcmcia_request_io(p_dev)) + return -ENODEV; + return 0; +} + +static int multi_config_check_notpicky(struct pcmcia_device *p_dev, + void *priv_data) +{ + int *base2 = priv_data; + + if (!p_dev->resource[0]->end || !p_dev->resource[1]->end) + return -ENODEV; + + p_dev->resource[0]->end = p_dev->resource[1]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + + if (pcmcia_request_io(p_dev)) + return -ENODEV; + + *base2 = p_dev->resource[0]->start + 8; + return 0; +} + +static int multi_config(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i, base2 = 0; + + link->config_flags |= CONF_AUTO_SET_IO; + /* First, look for a generic full-sized window */ + if (!pcmcia_loop_config(link, multi_config_check, &info->multi)) + base2 = link->resource[0]->start + 8; + else { + /* If that didn't work, look for two windows */ + info->multi = 2; + if (pcmcia_loop_config(link, multi_config_check_notpicky, + &base2)) { + dev_warn(&link->dev, "no usable port range " + "found, giving up\n"); + return -ENODEV; + } + } + + if (!link->irq) + dev_warn(&link->dev, "no usable IRQ found, continuing...\n"); + + /* + * Apply any configuration quirks. + */ + if (info->quirk && info->quirk->config) + info->quirk->config(link); + + i = pcmcia_enable_device(link); + if (i != 0) + return -ENODEV; + + /* The Oxford Semiconductor OXCF950 cards are in fact single-port: + * 8 registers are for the UART, the others are extra registers. + * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too. + */ + if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && + info->prodid == PRODID_POSSIO_GCC)) { + int err; + + if (link->config_index == 1 || + link->config_index == 3) { + err = setup_serial(link, info, base2, + link->irq); + base2 = link->resource[0]->start; + } else { + err = setup_serial(link, info, link->resource[0]->start, + link->irq); + } + info->c950ctrl = base2; + + /* + * FIXME: We really should wake up the port prior to + * handing it over to the serial layer. + */ + if (info->quirk && info->quirk->wakeup) + info->quirk->wakeup(link); + + return 0; + } + + setup_serial(link, info, link->resource[0]->start, link->irq); + for (i = 0; i < info->multi - 1; i++) + setup_serial(link, info, base2 + (8 * i), + link->irq); + return 0; +} + +static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data) +{ + struct serial_info *info = p_dev->priv; + + if (!p_dev->resource[0]->end) + return -EINVAL; + + if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0)) + info->multi = p_dev->resource[0]->end >> 3; + + if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8) + && (p_dev->resource[1]->end == 8)) + info->multi = 2; + + return 0; /* break */ +} + + +static int serial_config(struct pcmcia_device * link) +{ + struct serial_info *info = link->priv; + int i; + + dev_dbg(&link->dev, "serial_config\n"); + + /* Is this a compliant multifunction card? */ + info->multi = (link->socket->functions > 1); + + /* Is this a multiport card? */ + info->manfid = link->manf_id; + info->prodid = link->card_id; + + for (i = 0; i < ARRAY_SIZE(quirks); i++) + if ((quirks[i].manfid == ~0 || + quirks[i].manfid == info->manfid) && + (quirks[i].prodid == ~0 || + quirks[i].prodid == info->prodid)) { + info->quirk = &quirks[i]; + break; + } + + /* Another check for dual-serial cards: look for either serial or + multifunction cards that ask for appropriate IO port ranges */ + if ((info->multi == 0) && + (link->has_func_id) && + (link->socket->pcmcia_pfc == 0) && + ((link->func_id == CISTPL_FUNCID_MULTI) || + (link->func_id == CISTPL_FUNCID_SERIAL))) + pcmcia_loop_config(link, serial_check_for_multi, info); + + /* + * Apply any multi-port quirk. + */ + if (info->quirk && info->quirk->multi != -1) + info->multi = info->quirk->multi; + + dev_info(&link->dev, + "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n", + link->manf_id, link->card_id, + link->socket->pcmcia_pfc, info->multi, info->quirk); + if (link->socket->pcmcia_pfc) + i = pfc_config(link); + else if (info->multi > 1) + i = multi_config(link); + else + i = simple_config(link); + + if (i || info->ndev == 0) + goto failed; + + /* + * Apply any post-init quirk. FIXME: This should really happen + * before we register the port, since it might already be in use. + */ + if (info->quirk && info->quirk->post) + if (info->quirk->post(link)) + goto failed; + + return 0; + +failed: + dev_warn(&link->dev, "failed to initialize\n"); + serial_remove(link); + return -ENODEV; +} + +static struct pcmcia_device_id serial_ids[] = { + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab), + PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), + PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), + PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef), + PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef), + PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea), + PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023), + PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a), + PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29), + PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed), + PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101), + PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070), + PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562), + PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070), + PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020), + PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15), + PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77), + PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302), + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301), + PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276), + PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), + PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), + PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */ + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50), + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51), + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52), + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53), + PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180), + PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */ + PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */ + PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */ + PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e), + PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b), + PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025), + PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045), + PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052), + PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */ + PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */ + PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae), + PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef), + PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), + PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef), + PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0), + PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e), + PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a), + PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02), + PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa), + PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76), + PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95), + PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed), + PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65), + PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b), + PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6), + PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb), + PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447), + PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f), + PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f), + PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383), + PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e), + PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), + PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41), + PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), + PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), + PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), + PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38), + PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"), + PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"), + PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"), + PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"), + PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ + PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC860", 0xd85f6206, 0x698f93db, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC860 3G Network Adapter R1 */ + PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ + PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ + PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ + PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"), + PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"), + PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"), + PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3), + PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676), + PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4), + PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b), + /* too generic */ + /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */ + /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */ + PCMCIA_DEVICE_FUNC_ID(2), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, serial_ids); + +MODULE_FIRMWARE("cis/PCMLM28.cis"); +MODULE_FIRMWARE("cis/DP83903.cis"); +MODULE_FIRMWARE("cis/3CCFEM556.cis"); +MODULE_FIRMWARE("cis/3CXEM556.cis"); +MODULE_FIRMWARE("cis/SW_8xx_SER.cis"); +MODULE_FIRMWARE("cis/SW_7xx_SER.cis"); +MODULE_FIRMWARE("cis/SW_555_SER.cis"); +MODULE_FIRMWARE("cis/MT5634ZLX.cis"); +MODULE_FIRMWARE("cis/COMpad2.cis"); +MODULE_FIRMWARE("cis/COMpad4.cis"); +MODULE_FIRMWARE("cis/RS-COM-2P.cis"); + +static struct pcmcia_driver serial_cs_driver = { + .owner = THIS_MODULE, + .name = "serial_cs", + .probe = serial_probe, + .remove = serial_detach, + .id_table = serial_ids, + .suspend = serial_suspend, + .resume = serial_resume, +}; + +static int __init init_serial_cs(void) +{ + return pcmcia_register_driver(&serial_cs_driver); +} + +static void __exit exit_serial_cs(void) +{ + pcmcia_unregister_driver(&serial_cs_driver); +} + +module_init(init_serial_cs); +module_exit(exit_serial_cs); + +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c new file mode 100644 index 000000000000..b1962025b1aa --- /dev/null +++ b/drivers/tty/serial/serial_ks8695.c @@ -0,0 +1,705 @@ +/* + * drivers/serial/serial_ks8695.c + * + * Driver for KS8695 serial ports + * + * Based on drivers/serial/serial_amba.c, by Kam Lee. + * + * Copyright 2002-2005 Micrel Inc. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + + +#define SERIAL_KS8695_MAJOR 204 +#define SERIAL_KS8695_MINOR 16 +#define SERIAL_KS8695_DEVNAME "ttyAM" + +#define SERIAL_KS8695_NR 1 + +/* + * Access macros for the KS8695 UART + */ +#define UART_GET_CHAR(p) (__raw_readl((p)->membase + KS8695_URRB) & 0xFF) +#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + KS8695_URTH) +#define UART_GET_FCR(p) __raw_readl((p)->membase + KS8695_URFC) +#define UART_PUT_FCR(p, c) __raw_writel((c), (p)->membase + KS8695_URFC) +#define UART_GET_MSR(p) __raw_readl((p)->membase + KS8695_URMS) +#define UART_GET_LSR(p) __raw_readl((p)->membase + KS8695_URLS) +#define UART_GET_LCR(p) __raw_readl((p)->membase + KS8695_URLC) +#define UART_PUT_LCR(p, c) __raw_writel((c), (p)->membase + KS8695_URLC) +#define UART_GET_MCR(p) __raw_readl((p)->membase + KS8695_URMC) +#define UART_PUT_MCR(p, c) __raw_writel((c), (p)->membase + KS8695_URMC) +#define UART_GET_BRDR(p) __raw_readl((p)->membase + KS8695_URBD) +#define UART_PUT_BRDR(p, c) __raw_writel((c), (p)->membase + KS8695_URBD) + +#define KS8695_CLR_TX_INT() __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST) + +#define UART_DUMMY_LSR_RX 0x100 +#define UART_PORT_SIZE (KS8695_USR - KS8695_URRB + 4) + +static inline int tx_enabled(struct uart_port *port) +{ + return port->unused[0] & 1; +} + +static inline int rx_enabled(struct uart_port *port) +{ + return port->unused[0] & 2; +} + +static inline int ms_enabled(struct uart_port *port) +{ + return port->unused[0] & 4; +} + +static inline void ms_enable(struct uart_port *port, int enabled) +{ + if(enabled) + port->unused[0] |= 4; + else + port->unused[0] &= ~4; +} + +static inline void rx_enable(struct uart_port *port, int enabled) +{ + if(enabled) + port->unused[0] |= 2; + else + port->unused[0] &= ~2; +} + +static inline void tx_enable(struct uart_port *port, int enabled) +{ + if(enabled) + port->unused[0] |= 1; + else + port->unused[0] &= ~1; +} + + +#ifdef SUPPORT_SYSRQ +static struct console ks8695_console; +#endif + +static void ks8695uart_stop_tx(struct uart_port *port) +{ + if (tx_enabled(port)) { + /* use disable_irq_nosync() and not disable_irq() to avoid self + * imposed deadlock by not waiting for irq handler to end, + * since this ks8695uart_stop_tx() is called from interrupt context. + */ + disable_irq_nosync(KS8695_IRQ_UART_TX); + tx_enable(port, 0); + } +} + +static void ks8695uart_start_tx(struct uart_port *port) +{ + if (!tx_enabled(port)) { + enable_irq(KS8695_IRQ_UART_TX); + tx_enable(port, 1); + } +} + +static void ks8695uart_stop_rx(struct uart_port *port) +{ + if (rx_enabled(port)) { + disable_irq(KS8695_IRQ_UART_RX); + rx_enable(port, 0); + } +} + +static void ks8695uart_enable_ms(struct uart_port *port) +{ + if (!ms_enabled(port)) { + enable_irq(KS8695_IRQ_UART_MODEM_STATUS); + ms_enable(port,1); + } +} + +static void ks8695uart_disable_ms(struct uart_port *port) +{ + if (ms_enabled(port)) { + disable_irq(KS8695_IRQ_UART_MODEM_STATUS); + ms_enable(port,0); + } +} + +static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = port->state->port.tty; + unsigned int status, ch, lsr, flg, max_count = 256; + + status = UART_GET_LSR(port); /* clears pending LSR interrupts */ + while ((status & URLS_URDR) && max_count--) { + ch = UART_GET_CHAR(port); + flg = TTY_NORMAL; + + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX; + if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) { + if (lsr & URLS_URBI) { + lsr &= ~(URLS_URFE | URLS_URPE); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } + if (lsr & URLS_URPE) + port->icount.parity++; + if (lsr & URLS_URFE) + port->icount.frame++; + if (lsr & URLS_URROE) + port->icount.overrun++; + + lsr &= port->read_status_mask; + + if (lsr & URLS_URBI) + flg = TTY_BREAK; + else if (lsr & URLS_URPE) + flg = TTY_PARITY; + else if (lsr & URLS_URFE) + flg = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, URLS_URROE, ch, flg); + +ignore_char: + status = UART_GET_LSR(port); + } + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + + +static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct circ_buf *xmit = &port->state->xmit; + unsigned int count; + + if (port->x_char) { + KS8695_CLR_TX_INT(); + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return IRQ_HANDLED; + } + + if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { + ks8695uart_stop_tx(port); + return IRQ_HANDLED; + } + + count = 16; /* fifo size */ + while (!uart_circ_empty(xmit) && (count-- > 0)) { + KS8695_CLR_TX_INT(); + UART_PUT_CHAR(port, 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); + + if (uart_circ_empty(xmit)) + ks8695uart_stop_tx(port); + + return IRQ_HANDLED; +} + +static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned int status; + + /* + * clear modem interrupt by reading MSR + */ + status = UART_GET_MSR(port); + + if (status & URMS_URDDCD) + uart_handle_dcd_change(port, status & URMS_URDDCD); + + if (status & URMS_URDDST) + port->icount.dsr++; + + if (status & URMS_URDCTS) + uart_handle_cts_change(port, status & URMS_URDCTS); + + if (status & URMS_URTERI) + port->icount.rng++; + + wake_up_interruptible(&port->state->port.delta_msr_wait); + + return IRQ_HANDLED; +} + +static unsigned int ks8695uart_tx_empty(struct uart_port *port) +{ + return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0; +} + +static unsigned int ks8695uart_get_mctrl(struct uart_port *port) +{ + unsigned int result = 0; + unsigned int status; + + status = UART_GET_MSR(port); + if (status & URMS_URDCD) + result |= TIOCM_CAR; + if (status & URMS_URDSR) + result |= TIOCM_DSR; + if (status & URMS_URCTS) + result |= TIOCM_CTS; + if (status & URMS_URRI) + result |= TIOCM_RI; + + return result; +} + +static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl) +{ + unsigned int mcr; + + mcr = UART_GET_MCR(port); + if (mctrl & TIOCM_RTS) + mcr |= URMC_URRTS; + else + mcr &= ~URMC_URRTS; + + if (mctrl & TIOCM_DTR) + mcr |= URMC_URDTR; + else + mcr &= ~URMC_URDTR; + + UART_PUT_MCR(port, mcr); +} + +static void ks8695uart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned int lcr; + + lcr = UART_GET_LCR(port); + + if (break_state == -1) + lcr |= URLC_URSBC; + else + lcr &= ~URLC_URSBC; + + UART_PUT_LCR(port, lcr); +} + +static int ks8695uart_startup(struct uart_port *port) +{ + int retval; + + set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN); + tx_enable(port, 0); + rx_enable(port, 1); + ms_enable(port, 1); + + /* + * Allocate the IRQ + */ + retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port); + if (retval) + goto err_tx; + + retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port); + if (retval) + goto err_rx; + + retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port); + if (retval) + goto err_ls; + + retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port); + if (retval) + goto err_ms; + + return 0; + +err_ms: + free_irq(KS8695_IRQ_UART_LINE_STATUS, port); +err_ls: + free_irq(KS8695_IRQ_UART_RX, port); +err_rx: + free_irq(KS8695_IRQ_UART_TX, port); +err_tx: + return retval; +} + +static void ks8695uart_shutdown(struct uart_port *port) +{ + /* + * Free the interrupt + */ + free_irq(KS8695_IRQ_UART_RX, port); + free_irq(KS8695_IRQ_UART_TX, port); + free_irq(KS8695_IRQ_UART_MODEM_STATUS, port); + free_irq(KS8695_IRQ_UART_LINE_STATUS, port); + + /* disable break condition and fifos */ + UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC); + UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE); +} + +static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) +{ + unsigned int lcr, fcr = 0; + unsigned long flags; + unsigned int baud, quot; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr = URCL_5; + break; + case CS6: + lcr = URCL_6; + break; + case CS7: + lcr = URCL_7; + break; + default: + lcr = URCL_8; + break; + } + + /* stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= URLC_URSB; + + /* parity */ + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ + if (termios->c_cflag & PARODD) + lcr |= URPE_MARK; + else + lcr |= URPE_SPACE; + } + else if (termios->c_cflag & PARODD) + lcr |= URPE_ODD; + else + lcr |= URPE_EVEN; + } + + if (port->fifosize > 1) + fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE; + + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = URLS_URROE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= (URLS_URFE | URLS_URPE); + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= URLS_URBI; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= (URLS_URFE | URLS_URPE); + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= URLS_URBI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= URLS_URROE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_LSR_RX; + + /* first, disable everything */ + if (UART_ENABLE_MS(port, termios->c_cflag)) + ks8695uart_enable_ms(port); + else + ks8695uart_disable_ms(port); + + /* Set baud rate */ + UART_PUT_BRDR(port, quot); + + UART_PUT_LCR(port, lcr); + UART_PUT_FCR(port, fcr); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *ks8695uart_type(struct uart_port *port) +{ + return port->type == PORT_KS8695 ? "KS8695" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void ks8695uart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int ks8695uart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, + "serial_ks8695") != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void ks8695uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_KS8695; + ks8695uart_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695) + ret = -EINVAL; + if (ser->irq != port->irq) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops ks8695uart_pops = { + .tx_empty = ks8695uart_tx_empty, + .set_mctrl = ks8695uart_set_mctrl, + .get_mctrl = ks8695uart_get_mctrl, + .stop_tx = ks8695uart_stop_tx, + .start_tx = ks8695uart_start_tx, + .stop_rx = ks8695uart_stop_rx, + .enable_ms = ks8695uart_enable_ms, + .break_ctl = ks8695uart_break_ctl, + .startup = ks8695uart_startup, + .shutdown = ks8695uart_shutdown, + .set_termios = ks8695uart_set_termios, + .type = ks8695uart_type, + .release_port = ks8695uart_release_port, + .request_port = ks8695uart_request_port, + .config_port = ks8695uart_config_port, + .verify_port = ks8695uart_verify_port, +}; + +static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = { + { + .membase = (void *) KS8695_UART_VA, + .mapbase = KS8695_UART_VA, + .iotype = SERIAL_IO_MEM, + .irq = KS8695_IRQ_UART_TX, + .uartclk = KS8695_CLOCK_RATE * 16, + .fifosize = 16, + .ops = &ks8695uart_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + } +}; + +#ifdef CONFIG_SERIAL_KS8695_CONSOLE +static void ks8695_console_putchar(struct uart_port *port, int ch) +{ + while (!(UART_GET_LSR(port) & URLS_URTHRE)) + barrier(); + + UART_PUT_CHAR(port, ch); +} + +static void ks8695_console_write(struct console *co, const char *s, u_int count) +{ + struct uart_port *port = ks8695uart_ports + co->index; + + uart_console_write(port, s, count, ks8695_console_putchar); +} + +static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +{ + unsigned int lcr; + + lcr = UART_GET_LCR(port); + + switch (lcr & URLC_PARITY) { + case URPE_ODD: + *parity = 'o'; + break; + case URPE_EVEN: + *parity = 'e'; + break; + default: + *parity = 'n'; + } + + switch (lcr & URLC_URCL) { + case URCL_5: + *bits = 5; + break; + case URCL_6: + *bits = 6; + break; + case URCL_7: + *bits = 7; + break; + default: + *bits = 8; + } + + *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF); + *baud /= 16; + *baud &= 0xFFFFFFF0; +} + +static int __init ks8695_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + ks8695_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver ks8695_reg; + +static struct console ks8695_console = { + .name = SERIAL_KS8695_DEVNAME, + .write = ks8695_console_write, + .device = uart_console_device, + .setup = ks8695_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ks8695_reg, +}; + +static int __init ks8695_console_init(void) +{ + add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL); + register_console(&ks8695_console); + return 0; +} + +console_initcall(ks8695_console_init); + +#define KS8695_CONSOLE &ks8695_console +#else +#define KS8695_CONSOLE NULL +#endif + +static struct uart_driver ks8695_reg = { + .owner = THIS_MODULE, + .driver_name = "serial_ks8695", + .dev_name = SERIAL_KS8695_DEVNAME, + .major = SERIAL_KS8695_MAJOR, + .minor = SERIAL_KS8695_MINOR, + .nr = SERIAL_KS8695_NR, + .cons = KS8695_CONSOLE, +}; + +static int __init ks8695uart_init(void) +{ + int i, ret; + + printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n"); + + ret = uart_register_driver(&ks8695_reg); + if (ret) + return ret; + + for (i = 0; i < SERIAL_KS8695_NR; i++) + uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]); + + return 0; +} + +static void __exit ks8695uart_exit(void) +{ + int i; + + for (i = 0; i < SERIAL_KS8695_NR; i++) + uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]); + uart_unregister_driver(&ks8695_reg); +} + +module_init(ks8695uart_init); +module_exit(ks8695uart_exit); + +MODULE_DESCRIPTION("KS8695 serial port driver"); +MODULE_AUTHOR("Micrel Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_lh7a40x.c b/drivers/tty/serial/serial_lh7a40x.c new file mode 100644 index 000000000000..ea744707c4d6 --- /dev/null +++ b/drivers/tty/serial/serial_lh7a40x.c @@ -0,0 +1,682 @@ +/* drivers/serial/serial_lh7a40x.c + * + * Copyright (C) 2004 Coastal Environmental Systems + * + * 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. + * + */ + +/* Driver for Sharp LH7A40X embedded serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. + * + * --- + * + * This driver supports the embedded UARTs of the Sharp LH7A40X series + * CPUs. While similar to the 16550 and other UART chips, there is + * nothing close to register compatibility. Moreover, some of the + * modem control lines are not available, either in the chip or they + * are lacking in the board-level implementation. + * + * - Use of SIRDIS + * For simplicity, we disable the IR functions of any UART whenever + * we enable it. + * + */ + + +#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DEV_MAJOR 204 +#define DEV_MINOR 16 +#define DEV_NR 3 + +#define ISR_LOOP_LIMIT 256 + +#define UR(p,o) _UR ((p)->membase, o) +#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) +#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m) +#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m) + +#define UART_REG_SIZE 32 + +#define UART_R_DATA (0x00) +#define UART_R_FCON (0x04) +#define UART_R_BRCON (0x08) +#define UART_R_CON (0x0c) +#define UART_R_STATUS (0x10) +#define UART_R_RAWISR (0x14) +#define UART_R_INTEN (0x18) +#define UART_R_ISR (0x1c) + +#define UARTEN (0x01) /* UART enable */ +#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */ + +#define RxEmpty (0x10) +#define TxEmpty (0x80) +#define TxFull (0x20) +#define nRxRdy RxEmpty +#define nTxRdy TxFull +#define TxBusy (0x08) + +#define RxBreak (0x0800) +#define RxOverrunError (0x0400) +#define RxParityError (0x0200) +#define RxFramingError (0x0100) +#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError) + +#define DCD (0x04) +#define DSR (0x02) +#define CTS (0x01) + +#define RxInt (0x01) +#define TxInt (0x02) +#define ModemInt (0x04) +#define RxTimeoutInt (0x08) + +#define MSEOI (0x10) + +#define WLEN_8 (0x60) +#define WLEN_7 (0x40) +#define WLEN_6 (0x20) +#define WLEN_5 (0x00) +#define WLEN (0x60) /* Mask for all word-length bits */ +#define STP2 (0x08) +#define PEN (0x02) /* Parity Enable */ +#define EPS (0x04) /* Even Parity Set */ +#define FEN (0x10) /* FIFO Enable */ +#define BRK (0x01) /* Send Break */ + + +struct uart_port_lh7a40x { + struct uart_port port; + unsigned int statusPrev; /* Most recently read modem status */ +}; + +static void lh7a40xuart_stop_tx (struct uart_port* port) +{ + BIT_CLR (port, UART_R_INTEN, TxInt); +} + +static void lh7a40xuart_start_tx (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, TxInt); + + /* *** FIXME: do I need to check for startup of the + transmitter? The old driver did, but AMBA + doesn't . */ +} + +static void lh7a40xuart_stop_rx (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); +} + +static void lh7a40xuart_enable_ms (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, ModemInt); +} + +static void lh7a40xuart_rx_chars (struct uart_port* port) +{ + struct tty_struct* tty = port->state->port.tty; + int cbRxMax = 256; /* (Gross) limit on receive */ + unsigned int data; /* Received data and status */ + unsigned int flag; + + while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { + data = UR (port, UART_R_DATA); + flag = TTY_NORMAL; + ++port->icount.rx; + + if (unlikely(data & RxError)) { + if (data & RxBreak) { + data &= ~(RxFramingError | RxParityError); + ++port->icount.brk; + if (uart_handle_break (port)) + continue; + } + else if (data & RxParityError) + ++port->icount.parity; + else if (data & RxFramingError) + ++port->icount.frame; + if (data & RxOverrunError) + ++port->icount.overrun; + + /* Mask by termios, leave Rx'd byte */ + data &= port->read_status_mask | 0xff; + + if (data & RxBreak) + flag = TTY_BREAK; + else if (data & RxParityError) + flag = TTY_PARITY; + else if (data & RxFramingError) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char (port, (unsigned char) data)) + continue; + + uart_insert_char(port, data, RxOverrunError, data, flag); + } + tty_flip_buffer_push (tty); + return; +} + +static void lh7a40xuart_tx_chars (struct uart_port* port) +{ + struct circ_buf* xmit = &port->state->xmit; + int cbTxMax = port->fifosize; + + if (port->x_char) { + UR (port, UART_R_DATA) = port->x_char; + ++port->icount.tx; + port->x_char = 0; + return; + } + if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { + lh7a40xuart_stop_tx (port); + return; + } + + /* Unlike the AMBA UART, the lh7a40x UART does not guarantee + that at least half of the FIFO is empty. Instead, we check + status for every character. Using the AMBA method causes + the transmitter to drop characters. */ + + do { + UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + ++port->icount.tx; + if (uart_circ_empty(xmit)) + break; + } while (!(UR (port, UART_R_STATUS) & nTxRdy) + && cbTxMax--); + + if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) + uart_write_wakeup (port); + + if (uart_circ_empty (xmit)) + lh7a40xuart_stop_tx (port); +} + +static void lh7a40xuart_modem_status (struct uart_port* port) +{ + unsigned int status = UR (port, UART_R_STATUS); + unsigned int delta + = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; + + BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ + + if (!delta) /* Only happens if we missed 2 transitions */ + return; + + ((struct uart_port_lh7a40x*) port)->statusPrev = status; + + if (delta & DCD) + uart_handle_dcd_change (port, status & DCD); + + if (delta & DSR) + ++port->icount.dsr; + + if (delta & CTS) + uart_handle_cts_change (port, status & CTS); + + wake_up_interruptible (&port->state->port.delta_msr_wait); +} + +static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) +{ + struct uart_port* port = dev_id; + unsigned int cLoopLimit = ISR_LOOP_LIMIT; + unsigned int isr = UR (port, UART_R_ISR); + + + do { + if (isr & (RxInt | RxTimeoutInt)) + lh7a40xuart_rx_chars(port); + if (isr & ModemInt) + lh7a40xuart_modem_status (port); + if (isr & TxInt) + lh7a40xuart_tx_chars (port); + + if (--cLoopLimit == 0) + break; + + isr = UR (port, UART_R_ISR); + } while (isr & (RxInt | TxInt | RxTimeoutInt)); + + return IRQ_HANDLED; +} + +static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) +{ + return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; +} + +static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) +{ + unsigned int result = 0; + unsigned int status = UR (port, UART_R_STATUS); + + if (status & DCD) + result |= TIOCM_CAR; + if (status & DSR) + result |= TIOCM_DSR; + if (status & CTS) + result |= TIOCM_CTS; + + return result; +} + +static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) +{ + /* None of the ports supports DTR. UART1 supports RTS through GPIO. */ + /* Note, kernel appears to be setting DTR and RTS on console. */ + + /* *** FIXME: this deserves more work. There's some work in + tracing all of the IO pins. */ +#if 0 + if( port->mapbase == UART1_PHYS) { + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + if (mctrl & TIOCM_RTS) + gpio->pbdr &= ~GPIOB_UART1_RTS; + else + gpio->pbdr |= GPIOB_UART1_RTS; + } +#endif +} + +static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ + else + BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ + spin_unlock_irqrestore(&port->lock, flags); +} + +static int lh7a40xuart_startup (struct uart_port* port) +{ + int retval; + + retval = request_irq (port->irq, lh7a40xuart_int, 0, + "serial_lh7a40x", port); + if (retval) + return retval; + + /* Initial modem control-line settings */ + ((struct uart_port_lh7a40x*) port)->statusPrev + = UR (port, UART_R_STATUS); + + /* There is presently no configuration option to enable IR. + Thus, we always disable it. */ + + BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); + BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); + + return 0; +} + +static void lh7a40xuart_shutdown (struct uart_port* port) +{ + free_irq (port->irq, port); + BIT_CLR (port, UART_R_FCON, BRK | FEN); + BIT_CLR (port, UART_R_CON, UARTEN); +} + +static void lh7a40xuart_set_termios (struct uart_port* port, + struct ktermios* termios, + struct ktermios* old) +{ + unsigned int con; + unsigned int inten; + unsigned int fcon; + unsigned long flags; + unsigned int baud; + unsigned int quot; + + baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); + quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ + + switch (termios->c_cflag & CSIZE) { + case CS5: + fcon = WLEN_5; + break; + case CS6: + fcon = WLEN_6; + break; + case CS7: + fcon = WLEN_7; + break; + case CS8: + default: + fcon = WLEN_8; + break; + } + if (termios->c_cflag & CSTOPB) + fcon |= STP2; + if (termios->c_cflag & PARENB) { + fcon |= PEN; + if (!(termios->c_cflag & PARODD)) + fcon |= EPS; + } + if (port->fifosize > 1) + fcon |= FEN; + + spin_lock_irqsave (&port->lock, flags); + + uart_update_timeout (port, termios->c_cflag, baud); + + port->read_status_mask = RxOverrunError; + if (termios->c_iflag & INPCK) + port->read_status_mask |= RxFramingError | RxParityError; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= RxBreak; + + /* Figure mask for status we ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RxFramingError | RxParityError; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= RxBreak; + /* Ignore overrun when ignorning parity */ + /* *** FIXME: is this in the right place? */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RxOverrunError; + } + + /* Ignore all receive errors when receive disabled */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RxError; + + con = UR (port, UART_R_CON); + inten = (UR (port, UART_R_INTEN) & ~ModemInt); + + if (UART_ENABLE_MS (port, termios->c_cflag)) + inten |= ModemInt; + + BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */ + UR (port, UART_R_INTEN) = 0; /* Disable interrupts */ + UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */ + UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */ + UR (port, UART_R_INTEN) = inten; /* Enable interrupts */ + UR (port, UART_R_CON) = con; /* Restore UART mode */ + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char* lh7a40xuart_type (struct uart_port* port) +{ + return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; +} + +static void lh7a40xuart_release_port (struct uart_port* port) +{ + release_mem_region (port->mapbase, UART_REG_SIZE); +} + +static int lh7a40xuart_request_port (struct uart_port* port) +{ + return request_mem_region (port->mapbase, UART_REG_SIZE, + "serial_lh7a40x") != NULL + ? 0 : -EBUSY; +} + +static void lh7a40xuart_config_port (struct uart_port* port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_LH7A40X; + lh7a40xuart_request_port (port); + } +} + +static int lh7a40xuart_verify_port (struct uart_port* port, + struct serial_struct* ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= nr_irqs) + ret = -EINVAL; + if (ser->baud_base < 9600) /* *** FIXME: is this true? */ + ret = -EINVAL; + return ret; +} + +static struct uart_ops lh7a40x_uart_ops = { + .tx_empty = lh7a40xuart_tx_empty, + .set_mctrl = lh7a40xuart_set_mctrl, + .get_mctrl = lh7a40xuart_get_mctrl, + .stop_tx = lh7a40xuart_stop_tx, + .start_tx = lh7a40xuart_start_tx, + .stop_rx = lh7a40xuart_stop_rx, + .enable_ms = lh7a40xuart_enable_ms, + .break_ctl = lh7a40xuart_break_ctl, + .startup = lh7a40xuart_startup, + .shutdown = lh7a40xuart_shutdown, + .set_termios = lh7a40xuart_set_termios, + .type = lh7a40xuart_type, + .release_port = lh7a40xuart_release_port, + .request_port = lh7a40xuart_request_port, + .config_port = lh7a40xuart_config_port, + .verify_port = lh7a40xuart_verify_port, +}; + +static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { + { + .port = { + .membase = (void*) io_p2v (UART1_PHYS), + .mapbase = UART1_PHYS, + .iotype = UPIO_MEM, + .irq = IRQ_UART1INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 0, + }, + }, + { + .port = { + .membase = (void*) io_p2v (UART2_PHYS), + .mapbase = UART2_PHYS, + .iotype = UPIO_MEM, + .irq = IRQ_UART2INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 1, + }, + }, + { + .port = { + .membase = (void*) io_p2v (UART3_PHYS), + .mapbase = UART3_PHYS, + .iotype = UPIO_MEM, + .irq = IRQ_UART3INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = UPF_BOOT_AUTOCONF, + .line = 2, + }, + }, +}; + +#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE +# define LH7A40X_CONSOLE NULL +#else +# define LH7A40X_CONSOLE &lh7a40x_console + +static void lh7a40xuart_console_putchar(struct uart_port *port, int ch) +{ + while (UR(port, UART_R_STATUS) & nTxRdy) + ; + UR(port, UART_R_DATA) = ch; +} + +static void lh7a40xuart_console_write (struct console* co, + const char* s, + unsigned int count) +{ + struct uart_port* port = &lh7a40x_ports[co->index].port; + unsigned int con = UR (port, UART_R_CON); + unsigned int inten = UR (port, UART_R_INTEN); + + + UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */ + BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ + + uart_console_write(port, s, count, lh7a40xuart_console_putchar); + + /* Wait until all characters are sent */ + while (UR (port, UART_R_STATUS) & TxBusy) + ; + + /* Restore control and interrupt mask */ + UR (port, UART_R_CON) = con; + UR (port, UART_R_INTEN) = inten; +} + +static void __init lh7a40xuart_console_get_options (struct uart_port* port, + int* baud, + int* parity, + int* bits) +{ + if (UR (port, UART_R_CON) & UARTEN) { + unsigned int fcon = UR (port, UART_R_FCON); + unsigned int quot = UR (port, UART_R_BRCON) + 1; + + switch (fcon & (PEN | EPS)) { + default: *parity = 'n'; break; + case PEN: *parity = 'o'; break; + case PEN | EPS: *parity = 'e'; break; + } + + switch (fcon & WLEN) { + default: + case WLEN_8: *bits = 8; break; + case WLEN_7: *bits = 7; break; + case WLEN_6: *bits = 6; break; + case WLEN_5: *bits = 5; break; + } + + *baud = port->uartclk/(16*quot); + } +} + +static int __init lh7a40xuart_console_setup (struct console* co, char* options) +{ + struct uart_port* port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= DEV_NR) /* Bounds check on device number */ + co->index = 0; + port = &lh7a40x_ports[co->index].port; + + if (options) + uart_parse_options (options, &baud, &parity, &bits, &flow); + else + lh7a40xuart_console_get_options (port, &baud, &parity, &bits); + + return uart_set_options (port, co, baud, parity, bits, flow); +} + +static struct uart_driver lh7a40x_reg; +static struct console lh7a40x_console = { + .name = "ttyAM", + .write = lh7a40xuart_console_write, + .device = uart_console_device, + .setup = lh7a40xuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lh7a40x_reg, +}; + +static int __init lh7a40xuart_console_init(void) +{ + register_console (&lh7a40x_console); + return 0; +} + +console_initcall (lh7a40xuart_console_init); + +#endif + +static struct uart_driver lh7a40x_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyAM", + .dev_name = "ttyAM", + .major = DEV_MAJOR, + .minor = DEV_MINOR, + .nr = DEV_NR, + .cons = LH7A40X_CONSOLE, +}; + +static int __init lh7a40xuart_init(void) +{ + int ret; + + printk (KERN_INFO "serial: LH7A40X serial driver\n"); + + ret = uart_register_driver (&lh7a40x_reg); + + if (ret == 0) { + int i; + + for (i = 0; i < DEV_NR; i++) { + /* UART3, when used, requires GPIO pin reallocation */ + if (lh7a40x_ports[i].port.mapbase == UART3_PHYS) + GPIO_PINMUX |= 1<<3; + uart_add_one_port (&lh7a40x_reg, + &lh7a40x_ports[i].port); + } + } + return ret; +} + +static void __exit lh7a40xuart_exit(void) +{ + int i; + + for (i = 0; i < DEV_NR; i++) + uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); + + uart_unregister_driver (&lh7a40x_reg); +} + +module_init (lh7a40xuart_init); +module_exit (lh7a40xuart_exit); + +MODULE_AUTHOR ("Marc Singer"); +MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); +MODULE_LICENSE ("GPL"); diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c new file mode 100644 index 000000000000..c50e9fbbf743 --- /dev/null +++ b/drivers/tty/serial/serial_txx9.c @@ -0,0 +1,1344 @@ +/* + * drivers/serial/serial_txx9.c + * + * Derived from many drivers using generic_serial interface, + * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c + * (was in Linux/VR tree) by Jim Pick. + * + * Copyright (C) 1999 Harald Koerfgen + * Copyright (C) 2000 Jim Pick + * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) + * Copyright (C) 2000-2002 Toshiba Corporation + * + * 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. + * + * Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller + */ + +#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static char *serial_version = "1.11"; +static char *serial_name = "TX39/49 Serial driver"; + +#define PASS_LIMIT 256 + +#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) +/* "ttyS" is used for standard serial driver */ +#define TXX9_TTY_NAME "ttyTX" +#define TXX9_TTY_MINOR_START 196 +#define TXX9_TTY_MAJOR 204 +#else +/* acts like standard serial driver */ +#define TXX9_TTY_NAME "ttyS" +#define TXX9_TTY_MINOR_START 64 +#define TXX9_TTY_MAJOR TTY_MAJOR +#endif + +/* flag aliases */ +#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART +#define UPF_TXX9_USE_SCLK UPF_MAGIC_MULTIPLIER + +#ifdef CONFIG_PCI +/* support for Toshiba TC86C001 SIO */ +#define ENABLE_SERIAL_TXX9_PCI +#endif + +/* + * Number of serial ports + */ +#define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS + +struct uart_txx9_port { + struct uart_port port; + /* No additional info for now */ +}; + +#define TXX9_REGION_SIZE 0x24 + +/* TXX9 Serial Registers */ +#define TXX9_SILCR 0x00 +#define TXX9_SIDICR 0x04 +#define TXX9_SIDISR 0x08 +#define TXX9_SICISR 0x0c +#define TXX9_SIFCR 0x10 +#define TXX9_SIFLCR 0x14 +#define TXX9_SIBGR 0x18 +#define TXX9_SITFIFO 0x1c +#define TXX9_SIRFIFO 0x20 + +/* SILCR : Line Control */ +#define TXX9_SILCR_SCS_MASK 0x00000060 +#define TXX9_SILCR_SCS_IMCLK 0x00000000 +#define TXX9_SILCR_SCS_IMCLK_BG 0x00000020 +#define TXX9_SILCR_SCS_SCLK 0x00000040 +#define TXX9_SILCR_SCS_SCLK_BG 0x00000060 +#define TXX9_SILCR_UEPS 0x00000010 +#define TXX9_SILCR_UPEN 0x00000008 +#define TXX9_SILCR_USBL_MASK 0x00000004 +#define TXX9_SILCR_USBL_1BIT 0x00000000 +#define TXX9_SILCR_USBL_2BIT 0x00000004 +#define TXX9_SILCR_UMODE_MASK 0x00000003 +#define TXX9_SILCR_UMODE_8BIT 0x00000000 +#define TXX9_SILCR_UMODE_7BIT 0x00000001 + +/* SIDICR : DMA/Int. Control */ +#define TXX9_SIDICR_TDE 0x00008000 +#define TXX9_SIDICR_RDE 0x00004000 +#define TXX9_SIDICR_TIE 0x00002000 +#define TXX9_SIDICR_RIE 0x00001000 +#define TXX9_SIDICR_SPIE 0x00000800 +#define TXX9_SIDICR_CTSAC 0x00000600 +#define TXX9_SIDICR_STIE_MASK 0x0000003f +#define TXX9_SIDICR_STIE_OERS 0x00000020 +#define TXX9_SIDICR_STIE_CTSS 0x00000010 +#define TXX9_SIDICR_STIE_RBRKD 0x00000008 +#define TXX9_SIDICR_STIE_TRDY 0x00000004 +#define TXX9_SIDICR_STIE_TXALS 0x00000002 +#define TXX9_SIDICR_STIE_UBRKD 0x00000001 + +/* SIDISR : DMA/Int. Status */ +#define TXX9_SIDISR_UBRK 0x00008000 +#define TXX9_SIDISR_UVALID 0x00004000 +#define TXX9_SIDISR_UFER 0x00002000 +#define TXX9_SIDISR_UPER 0x00001000 +#define TXX9_SIDISR_UOER 0x00000800 +#define TXX9_SIDISR_ERI 0x00000400 +#define TXX9_SIDISR_TOUT 0x00000200 +#define TXX9_SIDISR_TDIS 0x00000100 +#define TXX9_SIDISR_RDIS 0x00000080 +#define TXX9_SIDISR_STIS 0x00000040 +#define TXX9_SIDISR_RFDN_MASK 0x0000001f + +/* SICISR : Change Int. Status */ +#define TXX9_SICISR_OERS 0x00000020 +#define TXX9_SICISR_CTSS 0x00000010 +#define TXX9_SICISR_RBRKD 0x00000008 +#define TXX9_SICISR_TRDY 0x00000004 +#define TXX9_SICISR_TXALS 0x00000002 +#define TXX9_SICISR_UBRKD 0x00000001 + +/* SIFCR : FIFO Control */ +#define TXX9_SIFCR_SWRST 0x00008000 +#define TXX9_SIFCR_RDIL_MASK 0x00000180 +#define TXX9_SIFCR_RDIL_1 0x00000000 +#define TXX9_SIFCR_RDIL_4 0x00000080 +#define TXX9_SIFCR_RDIL_8 0x00000100 +#define TXX9_SIFCR_RDIL_12 0x00000180 +#define TXX9_SIFCR_RDIL_MAX 0x00000180 +#define TXX9_SIFCR_TDIL_MASK 0x00000018 +#define TXX9_SIFCR_TDIL_MASK 0x00000018 +#define TXX9_SIFCR_TDIL_1 0x00000000 +#define TXX9_SIFCR_TDIL_4 0x00000001 +#define TXX9_SIFCR_TDIL_8 0x00000010 +#define TXX9_SIFCR_TDIL_MAX 0x00000010 +#define TXX9_SIFCR_TFRST 0x00000004 +#define TXX9_SIFCR_RFRST 0x00000002 +#define TXX9_SIFCR_FRSTE 0x00000001 +#define TXX9_SIO_TX_FIFO 8 +#define TXX9_SIO_RX_FIFO 16 + +/* SIFLCR : Flow Control */ +#define TXX9_SIFLCR_RCS 0x00001000 +#define TXX9_SIFLCR_TES 0x00000800 +#define TXX9_SIFLCR_RTSSC 0x00000200 +#define TXX9_SIFLCR_RSDE 0x00000100 +#define TXX9_SIFLCR_TSDE 0x00000080 +#define TXX9_SIFLCR_RTSTL_MASK 0x0000001e +#define TXX9_SIFLCR_RTSTL_MAX 0x0000001e +#define TXX9_SIFLCR_TBRK 0x00000001 + +/* SIBGR : Baudrate Control */ +#define TXX9_SIBGR_BCLK_MASK 0x00000300 +#define TXX9_SIBGR_BCLK_T0 0x00000000 +#define TXX9_SIBGR_BCLK_T2 0x00000100 +#define TXX9_SIBGR_BCLK_T4 0x00000200 +#define TXX9_SIBGR_BCLK_T6 0x00000300 +#define TXX9_SIBGR_BRD_MASK 0x000000ff + +static inline unsigned int sio_in(struct uart_txx9_port *up, int offset) +{ + switch (up->port.iotype) { + default: + return __raw_readl(up->port.membase + offset); + case UPIO_PORT: + return inl(up->port.iobase + offset); + } +} + +static inline void +sio_out(struct uart_txx9_port *up, int offset, int value) +{ + switch (up->port.iotype) { + default: + __raw_writel(value, up->port.membase + offset); + break; + case UPIO_PORT: + outl(value, up->port.iobase + offset); + break; + } +} + +static inline void +sio_mask(struct uart_txx9_port *up, int offset, unsigned int value) +{ + sio_out(up, offset, sio_in(up, offset) & ~value); +} +static inline void +sio_set(struct uart_txx9_port *up, int offset, unsigned int value) +{ + sio_out(up, offset, sio_in(up, offset) | value); +} + +static inline void +sio_quot_set(struct uart_txx9_port *up, int quot) +{ + quot >>= 1; + if (quot < 256) + sio_out(up, TXX9_SIBGR, quot | TXX9_SIBGR_BCLK_T0); + else if (quot < (256 << 2)) + sio_out(up, TXX9_SIBGR, (quot >> 2) | TXX9_SIBGR_BCLK_T2); + else if (quot < (256 << 4)) + sio_out(up, TXX9_SIBGR, (quot >> 4) | TXX9_SIBGR_BCLK_T4); + else if (quot < (256 << 6)) + sio_out(up, TXX9_SIBGR, (quot >> 6) | TXX9_SIBGR_BCLK_T6); + else + sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6); +} + +static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port) +{ + return container_of(port, struct uart_txx9_port, port); +} + +static void serial_txx9_stop_tx(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); +} + +static void serial_txx9_start_tx(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); +} + +static void serial_txx9_stop_rx(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; +} + +static void serial_txx9_enable_ms(struct uart_port *port) +{ + /* TXX9-SIO can not control DTR... */ +} + +static void serial_txx9_initialize(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned int tmout = 10000; + + sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); + /* TX4925 BUG WORKAROUND. Accessing SIOC register + * immediately after soft reset causes bus error. */ + mmiowb(); + udelay(1); + while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout) + udelay(1); + /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ + sio_set(up, TXX9_SIFCR, + TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1); + /* initial settings */ + sio_out(up, TXX9_SILCR, + TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | + ((up->port.flags & UPF_TXX9_USE_SCLK) ? + TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); + sio_quot_set(up, uart_get_divisor(port, 9600)); + sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); + sio_out(up, TXX9_SIDICR, 0); +} + +static inline void +receive_chars(struct uart_txx9_port *up, unsigned int *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned char ch; + unsigned int disr = *status; + int max_count = 256; + char flag; + unsigned int next_ignore_status_mask; + + do { + ch = sio_in(up, TXX9_SIRFIFO); + flag = TTY_NORMAL; + up->port.icount.rx++; + + /* mask out RFDN_MASK bit added by previous overrun */ + next_ignore_status_mask = + up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK; + if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER | + TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { + /* + * For statistics only + */ + if (disr & TXX9_SIDISR_UBRK) { + disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER); + 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 (disr & TXX9_SIDISR_UPER) + up->port.icount.parity++; + else if (disr & TXX9_SIDISR_UFER) + up->port.icount.frame++; + if (disr & TXX9_SIDISR_UOER) { + up->port.icount.overrun++; + /* + * The receiver read buffer still hold + * a char which caused overrun. + * Ignore next char by adding RFDN_MASK + * to ignore_status_mask temporarily. + */ + next_ignore_status_mask |= + TXX9_SIDISR_RFDN_MASK; + } + + /* + * Mask off conditions which should be ingored. + */ + disr &= up->port.read_status_mask; + + if (disr & TXX9_SIDISR_UBRK) { + flag = TTY_BREAK; + } else if (disr & TXX9_SIDISR_UPER) + flag = TTY_PARITY; + else if (disr & TXX9_SIDISR_UFER) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + + uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); + + ignore_char: + up->port.ignore_status_mask = next_ignore_status_mask; + disr = sio_in(up, TXX9_SIDISR); + } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); + spin_unlock(&up->port.lock); + tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); + *status = disr; +} + +static inline void transmit_chars(struct uart_txx9_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { + sio_out(up, TXX9_SITFIFO, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + serial_txx9_stop_tx(&up->port); + return; + } + + count = TXX9_SIO_TX_FIFO; + do { + sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) + serial_txx9_stop_tx(&up->port); +} + +static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) +{ + int pass_counter = 0; + struct uart_txx9_port *up = dev_id; + unsigned int status; + + while (1) { + spin_lock(&up->port.lock); + status = sio_in(up, TXX9_SIDISR); + if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE)) + status &= ~TXX9_SIDISR_TDIS; + if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | + TXX9_SIDISR_TOUT))) { + spin_unlock(&up->port.lock); + break; + } + + if (status & TXX9_SIDISR_RDIS) + receive_chars(up, &status); + if (status & TXX9_SIDISR_TDIS) + transmit_chars(up); + /* Clear TX/RX Int. Status */ + sio_mask(up, TXX9_SIDISR, + TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS | + TXX9_SIDISR_TOUT); + spin_unlock(&up->port.lock); + + if (pass_counter++ > PASS_LIMIT) + break; + } + + return pass_counter ? IRQ_HANDLED : IRQ_NONE; +} + +static unsigned int serial_txx9_tx_empty(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&up->port.lock, flags); + ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0; + spin_unlock_irqrestore(&up->port.lock, flags); + + return ret; +} + +static unsigned int serial_txx9_get_mctrl(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned int ret; + + /* no modem control lines */ + ret = TIOCM_CAR | TIOCM_DSR; + ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS; + ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS; + + return ret; +} + +static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + + if (mctrl & TIOCM_RTS) + sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); + else + sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); +} + +static void serial_txx9_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); + else + sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL) +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_txx9_port *up) +{ + unsigned int tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + while (--tmout && + !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS)) + udelay(1); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) + udelay(1); + } +} +#endif + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial_txx9_get_poll_char(struct uart_port *port) +{ + unsigned int ier; + unsigned char c; + struct uart_txx9_port *up = to_uart_txx9_port(port); + + /* + * First save the IER then disable the interrupts + */ + ier = sio_in(up, TXX9_SIDICR); + sio_out(up, TXX9_SIDICR, 0); + + while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID) + ; + + c = sio_in(up, TXX9_SIRFIFO); + + /* + * Finally, clear RX interrupt status + * and restore the IER + */ + sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS); + sio_out(up, TXX9_SIDICR, ier); + return c; +} + + +static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) +{ + unsigned int ier; + struct uart_txx9_port *up = to_uart_txx9_port(port); + + /* + * First save the IER then disable the interrupts + */ + ier = sio_in(up, TXX9_SIDICR); + sio_out(up, TXX9_SIDICR, 0); + + wait_for_xmitr(up); + /* + * Send the character out. + * If a LF, also do CR... + */ + sio_out(up, TXX9_SITFIFO, c); + if (c == 10) { + wait_for_xmitr(up); + sio_out(up, TXX9_SITFIFO, 13); + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + sio_out(up, TXX9_SIDICR, ier); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +static int serial_txx9_startup(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned long flags; + int retval; + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + sio_set(up, TXX9_SIFCR, + TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); + /* clear reset */ + sio_mask(up, TXX9_SIFCR, + TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); + sio_out(up, TXX9_SIDICR, 0); + + /* + * Clear the interrupt registers. + */ + sio_out(up, TXX9_SIDISR, 0); + + retval = request_irq(up->port.irq, serial_txx9_interrupt, + IRQF_SHARED, "serial_txx9", up); + if (retval) + return retval; + + /* + * Now, initialize the UART + */ + spin_lock_irqsave(&up->port.lock, flags); + serial_txx9_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* Enable RX/TX */ + sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); + + /* + * Finally, enable interrupts. + */ + sio_set(up, TXX9_SIDICR, TXX9_SIDICR_RIE); + + return 0; +} + +static void serial_txx9_shutdown(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned long flags; + + /* + * Disable interrupts from this port + */ + sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */ + + spin_lock_irqsave(&up->port.lock, flags); + serial_txx9_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition + */ + sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK); + +#ifdef CONFIG_SERIAL_TXX9_CONSOLE + if (up->port.cons && up->port.line == up->port.cons->index) { + free_irq(up->port.irq, up); + return; + } +#endif + /* reset FIFOs */ + sio_set(up, TXX9_SIFCR, + TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); + /* clear reset */ + sio_mask(up, TXX9_SIFCR, + TXX9_SIFCR_TFRST | TXX9_SIFCR_RFRST | TXX9_SIFCR_FRSTE); + + /* Disable RX/TX */ + sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE); + + free_irq(up->port.irq, up); +} + +static void +serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + unsigned int cval, fcr = 0; + unsigned long flags; + unsigned int baud, quot; + + /* + * We don't support modem control lines. + */ + termios->c_cflag &= ~(HUPCL | CMSPAR); + termios->c_cflag |= CLOCAL; + + cval = sio_in(up, TXX9_SILCR); + /* byte size and parity */ + cval &= ~TXX9_SILCR_UMODE_MASK; + switch (termios->c_cflag & CSIZE) { + case CS7: + cval |= TXX9_SILCR_UMODE_7BIT; + break; + default: + case CS5: /* not supported */ + case CS6: /* not supported */ + case CS8: + cval |= TXX9_SILCR_UMODE_8BIT; + break; + } + + cval &= ~TXX9_SILCR_USBL_MASK; + if (termios->c_cflag & CSTOPB) + cval |= TXX9_SILCR_USBL_2BIT; + else + cval |= TXX9_SILCR_USBL_1BIT; + cval &= ~(TXX9_SILCR_UPEN | TXX9_SILCR_UEPS); + if (termios->c_cflag & PARENB) + cval |= TXX9_SILCR_UPEN; + if (!(termios->c_cflag & PARODD)) + cval |= TXX9_SILCR_UEPS; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2); + quot = uart_get_divisor(port, baud); + + /* Set up FIFOs */ + /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ + fcr = TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + up->port.read_status_mask = TXX9_SIDISR_UOER | + TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; + if (termios->c_iflag & INPCK) + up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; + if (termios->c_iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= TXX9_SIDISR_UBRK; + + /* + * Characteres to ignore + */ + up->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER; + if (termios->c_iflag & IGNBRK) { + up->port.ignore_status_mask |= TXX9_SIDISR_UBRK; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + up->port.ignore_status_mask |= TXX9_SIDISR_UOER; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= TXX9_SIDISR_RDIS; + + /* CTS flow control flag */ + if ((termios->c_cflag & CRTSCTS) && + (up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) { + sio_set(up, TXX9_SIFLCR, + TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); + } else { + sio_mask(up, TXX9_SIFLCR, + TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES); + } + + sio_out(up, TXX9_SILCR, cval); + sio_quot_set(up, quot); + sio_out(up, TXX9_SIFCR, fcr); + + serial_txx9_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void +serial_txx9_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + /* + * If oldstate was -1 this is called from + * uart_configure_port(). In this case do not initialize the + * port now, because the port was already initialized (for + * non-console port) or should not be initialized here (for + * console port). If we initialized the port here we lose + * serial console settings. + */ + if (state == 0 && oldstate != -1) + serial_txx9_initialize(port); +} + +static int serial_txx9_request_resource(struct uart_txx9_port *up) +{ + unsigned int size = TXX9_REGION_SIZE; + int ret = 0; + + switch (up->port.iotype) { + default: + if (!up->port.mapbase) + break; + + if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) { + ret = -EBUSY; + break; + } + + if (up->port.flags & UPF_IOREMAP) { + up->port.membase = ioremap(up->port.mapbase, size); + if (!up->port.membase) { + release_mem_region(up->port.mapbase, size); + ret = -ENOMEM; + } + } + break; + + case UPIO_PORT: + if (!request_region(up->port.iobase, size, "serial_txx9")) + ret = -EBUSY; + break; + } + return ret; +} + +static void serial_txx9_release_resource(struct uart_txx9_port *up) +{ + unsigned int size = TXX9_REGION_SIZE; + + switch (up->port.iotype) { + default: + if (!up->port.mapbase) + break; + + if (up->port.flags & UPF_IOREMAP) { + iounmap(up->port.membase); + up->port.membase = NULL; + } + + release_mem_region(up->port.mapbase, size); + break; + + case UPIO_PORT: + release_region(up->port.iobase, size); + break; + } +} + +static void serial_txx9_release_port(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + serial_txx9_release_resource(up); +} + +static int serial_txx9_request_port(struct uart_port *port) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + return serial_txx9_request_resource(up); +} + +static void serial_txx9_config_port(struct uart_port *port, int uflags) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + int ret; + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial_txx9_request_resource(up); + if (ret < 0) + return; + port->type = PORT_TXX9; + up->port.fifosize = TXX9_SIO_TX_FIFO; + +#ifdef CONFIG_SERIAL_TXX9_CONSOLE + if (up->port.line == up->port.cons->index) + return; +#endif + serial_txx9_initialize(port); +} + +static const char * +serial_txx9_type(struct uart_port *port) +{ + return "txx9"; +} + +static struct uart_ops serial_txx9_pops = { + .tx_empty = serial_txx9_tx_empty, + .set_mctrl = serial_txx9_set_mctrl, + .get_mctrl = serial_txx9_get_mctrl, + .stop_tx = serial_txx9_stop_tx, + .start_tx = serial_txx9_start_tx, + .stop_rx = serial_txx9_stop_rx, + .enable_ms = serial_txx9_enable_ms, + .break_ctl = serial_txx9_break_ctl, + .startup = serial_txx9_startup, + .shutdown = serial_txx9_shutdown, + .set_termios = serial_txx9_set_termios, + .pm = serial_txx9_pm, + .type = serial_txx9_type, + .release_port = serial_txx9_release_port, + .request_port = serial_txx9_request_port, + .config_port = serial_txx9_config_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial_txx9_get_poll_char, + .poll_put_char = serial_txx9_put_poll_char, +#endif +}; + +static struct uart_txx9_port serial_txx9_ports[UART_NR]; + +static void __init serial_txx9_register_ports(struct uart_driver *drv, + struct device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + up->port.line = i; + up->port.ops = &serial_txx9_pops; + up->port.dev = dev; + if (up->port.iobase || up->port.mapbase) + uart_add_one_port(drv, &up->port); + } +} + +#ifdef CONFIG_SERIAL_TXX9_CONSOLE + +static void serial_txx9_console_putchar(struct uart_port *port, int ch) +{ + struct uart_txx9_port *up = to_uart_txx9_port(port); + + wait_for_xmitr(up); + sio_out(up, TXX9_SITFIFO, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +serial_txx9_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_txx9_port *up = &serial_txx9_ports[co->index]; + unsigned int ier, flcr; + + /* + * First save the UER then disable the interrupts + */ + ier = sio_in(up, TXX9_SIDICR); + sio_out(up, TXX9_SIDICR, 0); + /* + * Disable flow-control if enabled (and unnecessary) + */ + flcr = sio_in(up, TXX9_SIFLCR); + if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) + sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES); + + uart_console_write(&up->port, s, count, serial_txx9_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + sio_out(up, TXX9_SIFLCR, flcr); + sio_out(up, TXX9_SIDICR, ier); +} + +static int __init serial_txx9_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + struct uart_txx9_port *up; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + up = &serial_txx9_ports[co->index]; + port = &up->port; + if (!port->ops) + return -ENODEV; + + serial_txx9_initialize(&up->port); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver serial_txx9_reg; +static struct console serial_txx9_console = { + .name = TXX9_TTY_NAME, + .write = serial_txx9_console_write, + .device = uart_console_device, + .setup = serial_txx9_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &serial_txx9_reg, +}; + +static int __init serial_txx9_console_init(void) +{ + register_console(&serial_txx9_console); + return 0; +} +console_initcall(serial_txx9_console_init); + +#define SERIAL_TXX9_CONSOLE &serial_txx9_console +#else +#define SERIAL_TXX9_CONSOLE NULL +#endif + +static struct uart_driver serial_txx9_reg = { + .owner = THIS_MODULE, + .driver_name = "serial_txx9", + .dev_name = TXX9_TTY_NAME, + .major = TXX9_TTY_MAJOR, + .minor = TXX9_TTY_MINOR_START, + .nr = UART_NR, + .cons = SERIAL_TXX9_CONSOLE, +}; + +int __init early_serial_txx9_setup(struct uart_port *port) +{ + if (port->line >= ARRAY_SIZE(serial_txx9_ports)) + return -ENODEV; + + serial_txx9_ports[port->line].port = *port; + serial_txx9_ports[port->line].port.ops = &serial_txx9_pops; + serial_txx9_ports[port->line].port.flags |= + UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; + return 0; +} + +static DEFINE_MUTEX(serial_txx9_mutex); + +/** + * serial_txx9_register_port - register a serial port + * @port: serial port template + * + * Configure the serial port specified by the request. + * + * 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. + */ +static int __devinit serial_txx9_register_port(struct uart_port *port) +{ + int i; + struct uart_txx9_port *uart; + int ret = -ENOSPC; + + mutex_lock(&serial_txx9_mutex); + for (i = 0; i < UART_NR; i++) { + uart = &serial_txx9_ports[i]; + if (uart_match_port(&uart->port, port)) { + uart_remove_one_port(&serial_txx9_reg, &uart->port); + break; + } + } + if (i == UART_NR) { + /* Find unused port */ + for (i = 0; i < UART_NR; i++) { + uart = &serial_txx9_ports[i]; + if (!(uart->port.iobase || uart->port.mapbase)) + break; + } + } + if (i < UART_NR) { + uart->port.iobase = port->iobase; + uart->port.membase = port->membase; + uart->port.irq = port->irq; + uart->port.uartclk = port->uartclk; + uart->port.iotype = port->iotype; + uart->port.flags = port->flags + | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; + uart->port.mapbase = port->mapbase; + if (port->dev) + uart->port.dev = port->dev; + ret = uart_add_one_port(&serial_txx9_reg, &uart->port); + if (ret == 0) + ret = uart->port.line; + } + mutex_unlock(&serial_txx9_mutex); + return ret; +} + +/** + * serial_txx9_unregister_port - remove a txx9 serial port at runtime + * @line: serial line number + * + * Remove one serial port. This may not be called from interrupt + * context. We hand the port back to the our control. + */ +static void __devexit serial_txx9_unregister_port(int line) +{ + struct uart_txx9_port *uart = &serial_txx9_ports[line]; + + mutex_lock(&serial_txx9_mutex); + uart_remove_one_port(&serial_txx9_reg, &uart->port); + uart->port.flags = 0; + uart->port.type = PORT_UNKNOWN; + uart->port.iobase = 0; + uart->port.mapbase = 0; + uart->port.membase = NULL; + uart->port.dev = NULL; + mutex_unlock(&serial_txx9_mutex); +} + +/* + * Register a set of serial devices attached to a platform device. + */ +static int __devinit serial_txx9_probe(struct platform_device *dev) +{ + struct uart_port *p = dev->dev.platform_data; + struct uart_port port; + int ret, i; + + memset(&port, 0, sizeof(struct uart_port)); + for (i = 0; p && p->uartclk != 0; p++, i++) { + port.iobase = p->iobase; + port.membase = p->membase; + port.irq = p->irq; + port.uartclk = p->uartclk; + port.iotype = p->iotype; + port.flags = p->flags; + port.mapbase = p->mapbase; + port.dev = &dev->dev; + ret = serial_txx9_register_port(&port); + if (ret < 0) { + dev_err(&dev->dev, "unable to register port at index %d " + "(IO%lx MEM%llx IRQ%d): %d\n", i, + p->iobase, (unsigned long long)p->mapbase, + p->irq, ret); + } + } + return 0; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial_txx9_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + if (up->port.dev == &dev->dev) + serial_txx9_unregister_port(i); + } + return 0; +} + +#ifdef CONFIG_PM +static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_suspend_port(&serial_txx9_reg, &up->port); + } + + return 0; +} + +static int serial_txx9_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_resume_port(&serial_txx9_reg, &up->port); + } + + return 0; +} +#endif + +static struct platform_driver serial_txx9_plat_driver = { + .probe = serial_txx9_probe, + .remove = __devexit_p(serial_txx9_remove), +#ifdef CONFIG_PM + .suspend = serial_txx9_suspend, + .resume = serial_txx9_resume, +#endif + .driver = { + .name = "serial_txx9", + .owner = THIS_MODULE, + }, +}; + +#ifdef ENABLE_SERIAL_TXX9_PCI +/* + * Probe one serial board. Unfortunately, there is no rhyme nor reason + * to the arrangement of serial ports on a PCI card. + */ +static int __devinit +pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct uart_port port; + int line; + int rc; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + memset(&port, 0, sizeof(port)); + port.ops = &serial_txx9_pops; + port.flags |= UPF_TXX9_HAVE_CTS_LINE; + port.uartclk = 66670000; + port.irq = dev->irq; + port.iotype = UPIO_PORT; + port.iobase = pci_resource_start(dev, 1); + port.dev = &dev->dev; + line = serial_txx9_register_port(&port); + if (line < 0) { + printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line); + pci_disable_device(dev); + return line; + } + pci_set_drvdata(dev, &serial_txx9_ports[line]); + + return 0; +} + +static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) +{ + struct uart_txx9_port *up = pci_get_drvdata(dev); + + pci_set_drvdata(dev, NULL); + + if (up) { + serial_txx9_unregister_port(up->port.line); + pci_disable_device(dev); + } +} + +#ifdef CONFIG_PM +static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) +{ + struct uart_txx9_port *up = pci_get_drvdata(dev); + + if (up) + uart_suspend_port(&serial_txx9_reg, &up->port); + pci_save_state(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + return 0; +} + +static int pciserial_txx9_resume_one(struct pci_dev *dev) +{ + struct uart_txx9_port *up = pci_get_drvdata(dev); + + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + if (up) + uart_resume_port(&serial_txx9_reg, &up->port); + return 0; +} +#endif + +static const struct pci_device_id serial_txx9_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) }, + { 0, } +}; + +static struct pci_driver serial_txx9_pci_driver = { + .name = "serial_txx9", + .probe = pciserial_txx9_init_one, + .remove = __devexit_p(pciserial_txx9_remove_one), +#ifdef CONFIG_PM + .suspend = pciserial_txx9_suspend_one, + .resume = pciserial_txx9_resume_one, +#endif + .id_table = serial_txx9_pci_tbl, +}; + +MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl); +#endif /* ENABLE_SERIAL_TXX9_PCI */ + +static struct platform_device *serial_txx9_plat_devs; + +static int __init serial_txx9_init(void) +{ + int ret; + + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); + + ret = uart_register_driver(&serial_txx9_reg); + if (ret) + goto out; + + serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1); + if (!serial_txx9_plat_devs) { + ret = -ENOMEM; + goto unreg_uart_drv; + } + + ret = platform_device_add(serial_txx9_plat_devs); + if (ret) + goto put_dev; + + serial_txx9_register_ports(&serial_txx9_reg, + &serial_txx9_plat_devs->dev); + + ret = platform_driver_register(&serial_txx9_plat_driver); + if (ret) + goto del_dev; + +#ifdef ENABLE_SERIAL_TXX9_PCI + ret = pci_register_driver(&serial_txx9_pci_driver); +#endif + if (ret == 0) + goto out; + + del_dev: + platform_device_del(serial_txx9_plat_devs); + put_dev: + platform_device_put(serial_txx9_plat_devs); + unreg_uart_drv: + uart_unregister_driver(&serial_txx9_reg); + out: + return ret; +} + +static void __exit serial_txx9_exit(void) +{ + int i; + +#ifdef ENABLE_SERIAL_TXX9_PCI + pci_unregister_driver(&serial_txx9_pci_driver); +#endif + platform_driver_unregister(&serial_txx9_plat_driver); + platform_device_unregister(serial_txx9_plat_devs); + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + if (up->port.iobase || up->port.mapbase) + uart_remove_one_port(&serial_txx9_reg, &up->port); + } + + uart_unregister_driver(&serial_txx9_reg); +} + +module_init(serial_txx9_init); +module_exit(serial_txx9_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TX39/49 serial driver"); + +MODULE_ALIAS_CHARDEV_MAJOR(TXX9_TTY_MAJOR); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c new file mode 100644 index 000000000000..c291b3add1d2 --- /dev/null +++ b/drivers/tty/serial/sh-sci.c @@ -0,0 +1,2027 @@ +/* + * drivers/serial/sh-sci.c + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * + * Copyright (C) 2002 - 2008 Paul Mundt + * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). + * + * based off of the old drivers/char/sh-sci.c by: + * + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2000 Sugioka Toshinobu + * Modified to support multiple serial ports. Stuart Menefy (May 2000). + * Modified to support SecureEdge. David McCullough (2002) + * Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003). + * Removed SH7300 support (Jul 2007). + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SUPERH +#include +#endif + +#ifdef CONFIG_H8300 +#include +#endif + +#include "sh-sci.h" + +struct sci_port { + struct uart_port port; + + /* Port type */ + unsigned int type; + + /* Port IRQs: ERI, RXI, TXI, BRI (optional) */ + unsigned int irqs[SCIx_NR_IRQS]; + + /* Port enable callback */ + void (*enable)(struct uart_port *port); + + /* Port disable callback */ + void (*disable)(struct uart_port *port); + + /* Break timer */ + struct timer_list break_timer; + int break_flag; + + /* Interface clock */ + struct clk *iclk; + /* Function clock */ + struct clk *fclk; + + struct list_head node; + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct device *dma_dev; + unsigned int slave_tx; + unsigned int slave_rx; + struct dma_async_tx_descriptor *desc_tx; + struct dma_async_tx_descriptor *desc_rx[2]; + dma_cookie_t cookie_tx; + dma_cookie_t cookie_rx[2]; + dma_cookie_t active_rx; + struct scatterlist sg_tx; + unsigned int sg_len_tx; + struct scatterlist sg_rx[2]; + size_t buf_len_rx; + struct sh_dmae_slave param_tx; + struct sh_dmae_slave param_rx; + struct work_struct work_tx; + struct work_struct work_rx; + struct timer_list rx_timer; + unsigned int rx_timeout; +#endif +}; + +struct sh_sci_priv { + spinlock_t lock; + struct list_head ports; + struct notifier_block clk_nb; +}; + +/* Function prototypes */ +static void sci_stop_tx(struct uart_port *port); + +#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS + +static struct sci_port sci_ports[SCI_NPORTS]; +static struct uart_driver sci_uart_driver; + +static inline struct sci_port * +to_sci_port(struct uart_port *uart) +{ + return container_of(uart, struct sci_port, port); +} + +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) + +#ifdef CONFIG_CONSOLE_POLL +static inline void handle_error(struct uart_port *port) +{ + /* Clear error flags */ + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); +} + +static int sci_poll_get_char(struct uart_port *port) +{ + unsigned short status; + int c; + + do { + status = sci_in(port, SCxSR); + if (status & SCxSR_ERRORS(port)) { + handle_error(port); + continue; + } + break; + } while (1); + + if (!(status & SCxSR_RDxF(port))) + return NO_POLL_CHAR; + + c = sci_in(port, SCxRDR); + + /* Dummy read */ + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + + return c; +} +#endif + +static void sci_poll_put_char(struct uart_port *port, unsigned char c) +{ + unsigned short status; + + do { + status = sci_in(port, SCxSR); + } while (!(status & SCxSR_TDxE(port))); + + sci_out(port, SCxTDR, c); + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); +} +#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ + +#if defined(__H8300H__) || defined(__H8300S__) +static void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + int ch = (port->mapbase - SMR0) >> 3; + + /* set DDR regs */ + H8300_GPIO_DDR(h8300_sci_pins[ch].port, + h8300_sci_pins[ch].rx, + H8300_GPIO_INPUT); + H8300_GPIO_DDR(h8300_sci_pins[ch].port, + h8300_sci_pins[ch].tx, + H8300_GPIO_OUTPUT); + + /* tx mark output*/ + H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + if (port->mapbase == 0xA4400000) { + __raw_writew(__raw_readw(PACR) & 0xffc0, PACR); + __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR); + } else if (port->mapbase == 0xA4410000) + __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR); +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + unsigned short data; + + if (cflag & CRTSCTS) { + /* enable RTS/CTS */ + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 9-2; enable all scif pins but sck */ + data = __raw_readw(PORT_PTCR); + __raw_writew((data & 0xfc03), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 9-2 */ + data = __raw_readw(PORT_PVCR); + __raw_writew((data & 0xfc03), PORT_PVCR); + } + } else { + if (port->mapbase == 0xa4430000) { /* SCIF0 */ + /* Clear PTCR bit 5-2; enable only tx and rx */ + data = __raw_readw(PORT_PTCR); + __raw_writew((data & 0xffc3), PORT_PTCR); + } else if (port->mapbase == 0xa4438000) { /* SCIF1 */ + /* Clear PVCR bit 5-2 */ + data = __raw_readw(PORT_PVCR); + __raw_writew((data & 0xffc3), PORT_PVCR); + } + } +} +#elif defined(CONFIG_CPU_SH3) +/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = __raw_readw(SCPCR); + /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ + __raw_writew(data & 0x0fcf, SCPCR); + + if (!(cflag & CRTSCTS)) { + /* We need to set SCPCR to enable RTS/CTS */ + data = __raw_readw(SCPCR); + /* Clear out SCP7MD1,0, SCP4MD1,0, + Set SCP6MD1,0 = {01} (output) */ + __raw_writew((data & 0x0fcf) | 0x1000, SCPCR); + + data = __raw_readb(SCPDR); + /* Set /RTS2 (bit6) = 0 */ + __raw_writeb(data & 0xbf, SCPDR); + } +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7722) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + unsigned short data; + + if (port->mapbase == 0xffe00000) { + data = __raw_readw(PSCR); + data &= ~0x03cf; + if (!(cflag & CRTSCTS)) + data |= 0x0340; + + __raw_writew(data, PSCR); + } +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) || \ + defined(CONFIG_CPU_SUBTYPE_SHX3) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + if (!(cflag & CRTSCTS)) + __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */ +} +#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A) +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + if (!(cflag & CRTSCTS)) + __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */ +} +#else +static inline void sci_init_pins(struct uart_port *port, unsigned int cflag) +{ + /* Nothing to do */ +} +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) +static int scif_txfill(struct uart_port *port) +{ + return sci_in(port, SCTFDR) & 0xff; +} + +static int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - scif_txfill(port); +} + +static int scif_rxfill(struct uart_port *port) +{ + return sci_in(port, SCRFDR) & 0xff; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +static int scif_txfill(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000 || + port->mapbase == 0xffe08000) + /* SCIF0/1*/ + return sci_in(port, SCTFDR) & 0xff; + else + /* SCIF2 */ + return sci_in(port, SCFDR) >> 8; +} + +static int scif_txroom(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000 || + port->mapbase == 0xffe08000) + /* SCIF0/1*/ + return SCIF_TXROOM_MAX - scif_txfill(port); + else + /* SCIF2 */ + return SCIF2_TXROOM_MAX - scif_txfill(port); +} + +static int scif_rxfill(struct uart_port *port) +{ + if ((port->mapbase == 0xffe00000) || + (port->mapbase == 0xffe08000)) { + /* SCIF0/1*/ + return sci_in(port, SCRFDR) & 0xff; + } else { + /* SCIF2 */ + return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; + } +} +#elif defined(CONFIG_ARCH_SH7372) +static int scif_txfill(struct uart_port *port) +{ + if (port->type == PORT_SCIFA) + return sci_in(port, SCFDR) >> 8; + else + return sci_in(port, SCTFDR); +} + +static int scif_txroom(struct uart_port *port) +{ + return port->fifosize - scif_txfill(port); +} + +static int scif_rxfill(struct uart_port *port) +{ + if (port->type == PORT_SCIFA) + return sci_in(port, SCFDR) & SCIF_RFDC_MASK; + else + return sci_in(port, SCRFDR); +} +#else +static int scif_txfill(struct uart_port *port) +{ + return sci_in(port, SCFDR) >> 8; +} + +static int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - scif_txfill(port); +} + +static int scif_rxfill(struct uart_port *port) +{ + return sci_in(port, SCFDR) & SCIF_RFDC_MASK; +} +#endif + +static int sci_txfill(struct uart_port *port) +{ + return !(sci_in(port, SCxSR) & SCI_TDRE); +} + +static int sci_txroom(struct uart_port *port) +{ + return !sci_txfill(port); +} + +static int sci_rxfill(struct uart_port *port) +{ + return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; +} + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +static void sci_transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int stopped = uart_tx_stopped(port); + unsigned short status; + unsigned short ctrl; + int count; + + status = sci_in(port, SCxSR); + if (!(status & SCxSR_TDxE(port))) { + ctrl = sci_in(port, SCSCR); + if (uart_circ_empty(xmit)) + ctrl &= ~SCI_CTRL_FLAGS_TIE; + else + ctrl |= SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); + return; + } + + if (port->type == PORT_SCI) + count = sci_txroom(port); + else + count = scif_txroom(port); + + do { + unsigned char c; + + if (port->x_char) { + c = port->x_char; + port->x_char = 0; + } else if (!uart_circ_empty(xmit) && !stopped) { + c = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else { + break; + } + + sci_out(port, SCxTDR, c); + + port->icount.tx++; + } while (--count > 0); + + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + if (uart_circ_empty(xmit)) { + sci_stop_tx(port); + } else { + ctrl = sci_in(port, SCSCR); + + if (port->type != PORT_SCI) { + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + } + + ctrl |= SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); + } +} + +/* On SH3, SCIF may read end-of-break as a space->mark char */ +#define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); }) + +static inline void sci_receive_chars(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + struct tty_struct *tty = port->state->port.tty; + int i, count, copied = 0; + unsigned short status; + unsigned char flag; + + status = sci_in(port, SCxSR); + if (!(status & SCxSR_RDxF(port))) + return; + + while (1) { + if (port->type == PORT_SCI) + count = sci_rxfill(port); + else + count = scif_rxfill(port); + + /* Don't copy more bytes than there is room for in the buffer */ + count = tty_buffer_request_room(tty, count); + + /* If for any reason we can't copy more data, we're done! */ + if (count == 0) + break; + + if (port->type == PORT_SCI) { + char c = sci_in(port, SCxRDR); + if (uart_handle_sysrq_char(port, c) || + sci_port->break_flag) + count = 0; + else + tty_insert_flip_char(tty, c, TTY_NORMAL); + } else { + for (i = 0; i < count; i++) { + char c = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); +#if defined(CONFIG_CPU_SH3) + /* Skip "chars" during break */ + if (sci_port->break_flag) { + if ((c == 0) && + (status & SCxSR_FER(port))) { + count--; i--; + continue; + } + + /* Nonzero => end-of-break */ + dev_dbg(port->dev, "debounce<%02x>\n", c); + sci_port->break_flag = 0; + + if (STEPFN(c)) { + count--; i--; + continue; + } + } +#endif /* CONFIG_CPU_SH3 */ + if (uart_handle_sysrq_char(port, c)) { + count--; i--; + continue; + } + + /* Store data and status */ + if (status & SCxSR_FER(port)) { + flag = TTY_FRAME; + dev_notice(port->dev, "frame error\n"); + } else if (status & SCxSR_PER(port)) { + flag = TTY_PARITY; + dev_notice(port->dev, "parity error\n"); + } else + flag = TTY_NORMAL; + + tty_insert_flip_char(tty, c, flag); + } + } + + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + + copied += count; + port->icount.rx += count; + } + + if (copied) { + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tty); + } else { + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } +} + +#define SCI_BREAK_JIFFIES (HZ/20) +/* The sci generates interrupts during the break, + * 1 per millisecond or so during the break period, for 9600 baud. + * So dont bother disabling interrupts. + * But dont want more than 1 break event. + * Use a kernel timer to periodically poll the rx line until + * the break is finished. + */ +static void sci_schedule_break_timer(struct sci_port *port) +{ + port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES; + add_timer(&port->break_timer); +} +/* Ensure that two consecutive samples find the break over. */ +static void sci_break_timer(unsigned long data) +{ + struct sci_port *port = (struct sci_port *)data; + + if (sci_rxd_in(&port->port) == 0) { + port->break_flag = 1; + sci_schedule_break_timer(port); + } else if (port->break_flag == 1) { + /* break is over. */ + port->break_flag = 2; + sci_schedule_break_timer(port); + } else + port->break_flag = 0; +} + +static inline int sci_handle_errors(struct uart_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->state->port.tty; + + if (status & SCxSR_ORER(port)) { + /* overrun error */ + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) + copied++; + + dev_notice(port->dev, "overrun error"); + } + + if (status & SCxSR_FER(port)) { + if (sci_rxd_in(port) == 0) { + /* Notify of BREAK */ + struct sci_port *sci_port = to_sci_port(port); + + if (!sci_port->break_flag) { + sci_port->break_flag = 1; + sci_schedule_break_timer(sci_port); + + /* Do sysrq handling. */ + if (uart_handle_break(port)) + return 0; + + dev_dbg(port->dev, "BREAK detected\n"); + + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) + copied++; + } + + } else { + /* frame error */ + if (tty_insert_flip_char(tty, 0, TTY_FRAME)) + copied++; + + dev_notice(port->dev, "frame error\n"); + } + } + + if (status & SCxSR_PER(port)) { + /* parity error */ + if (tty_insert_flip_char(tty, 0, TTY_PARITY)) + copied++; + + dev_notice(port->dev, "parity error"); + } + + if (copied) + tty_flip_buffer_push(tty); + + return copied; +} + +static inline int sci_handle_fifo_overrun(struct uart_port *port) +{ + struct tty_struct *tty = port->state->port.tty; + int copied = 0; + + if (port->type != PORT_SCIF) + return 0; + + if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) { + sci_out(port, SCLSR, 0); + + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_flip_buffer_push(tty); + + dev_notice(port->dev, "overrun error\n"); + copied++; + } + + return copied; +} + +static inline int sci_handle_breaks(struct uart_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->state->port.tty; + struct sci_port *s = to_sci_port(port); + + if (uart_handle_break(port)) + return 0; + + if (!s->break_flag && status & SCxSR_BRK(port)) { +#if defined(CONFIG_CPU_SH3) + /* Debounce break */ + s->break_flag = 1; +#endif + /* Notify of BREAK */ + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) + copied++; + + dev_dbg(port->dev, "BREAK detected\n"); + } + + if (copied) + tty_flip_buffer_push(tty); + + copied += sci_handle_fifo_overrun(port); + + return copied; +} + +static irqreturn_t sci_rx_interrupt(int irq, void *ptr) +{ +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + + if (s->chan_rx) { + u16 scr = sci_in(port, SCSCR); + u16 ssr = sci_in(port, SCxSR); + + /* Disable future Rx interrupts */ + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + disable_irq_nosync(irq); + scr |= 0x4000; + } else { + scr &= ~SCI_CTRL_FLAGS_RIE; + } + sci_out(port, SCSCR, scr); + /* Clear current interrupt */ + sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); + dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", + jiffies, s->rx_timeout); + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + return IRQ_HANDLED; + } +#endif + + /* I think sci_receive_chars has to be called irrespective + * of whether the I_IXOFF is set, otherwise, how is the interrupt + * to be disabled? + */ + sci_receive_chars(ptr); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_tx_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + sci_transmit_chars(port); + spin_unlock_irqrestore(&port->lock, flags); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_er_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + + /* Handle errors */ + if (port->type == PORT_SCI) { + if (sci_handle_errors(port)) { + /* discard character in rx buffer */ + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } + } else { + sci_handle_fifo_overrun(port); + sci_rx_interrupt(irq, ptr); + } + + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + + /* Kick the transmission */ + sci_tx_interrupt(irq, ptr); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_br_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + + /* Handle BREAKs */ + sci_handle_breaks(port); + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); + + return IRQ_HANDLED; +} + +static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) +{ + unsigned short ssr_status, scr_status, err_enabled; + struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); + irqreturn_t ret = IRQ_NONE; + + ssr_status = sci_in(port, SCxSR); + scr_status = sci_in(port, SCSCR); + err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE); + + /* Tx Interrupt */ + if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) && + !s->chan_tx) + ret = sci_tx_interrupt(irq, ptr); + /* + * Rx Interrupt: if we're using DMA, the DMA controller clears RDF / + * DR flags + */ + if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) && + (scr_status & SCI_CTRL_FLAGS_RIE)) + ret = sci_rx_interrupt(irq, ptr); + /* Error Interrupt */ + if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled) + ret = sci_er_interrupt(irq, ptr); + /* Break Interrupt */ + if ((ssr_status & SCxSR_BRK(port)) && err_enabled) + ret = sci_br_interrupt(irq, ptr); + + return ret; +} + +/* + * Here we define a transistion notifier so that we can update all of our + * ports' baud rate when the peripheral clock changes. + */ +static int sci_notifier(struct notifier_block *self, + unsigned long phase, void *p) +{ + struct sh_sci_priv *priv = container_of(self, + struct sh_sci_priv, clk_nb); + struct sci_port *sci_port; + unsigned long flags; + + if ((phase == CPUFREQ_POSTCHANGE) || + (phase == CPUFREQ_RESUMECHANGE)) { + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(sci_port, &priv->ports, node) + sci_port->port.uartclk = clk_get_rate(sci_port->iclk); + spin_unlock_irqrestore(&priv->lock, flags); + } + + return NOTIFY_OK; +} + +static void sci_clk_enable(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + + clk_enable(sci_port->iclk); + sci_port->port.uartclk = clk_get_rate(sci_port->iclk); + clk_enable(sci_port->fclk); +} + +static void sci_clk_disable(struct uart_port *port) +{ + struct sci_port *sci_port = to_sci_port(port); + + clk_disable(sci_port->fclk); + clk_disable(sci_port->iclk); +} + +static int sci_request_irq(struct sci_port *port) +{ + int i; + irqreturn_t (*handlers[4])(int irq, void *ptr) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, + }; + const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full", + "SCI Transmit Data Empty", "SCI Break" }; + + if (port->irqs[0] == port->irqs[1]) { + if (unlikely(!port->irqs[0])) + return -ENODEV; + + if (request_irq(port->irqs[0], sci_mpxed_interrupt, + IRQF_DISABLED, "sci", port)) { + dev_err(port->port.dev, "Can't allocate IRQ\n"); + return -ENODEV; + } + } else { + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + if (unlikely(!port->irqs[i])) + continue; + + if (request_irq(port->irqs[i], handlers[i], + IRQF_DISABLED, desc[i], port)) { + dev_err(port->port.dev, "Can't allocate IRQ\n"); + return -ENODEV; + } + } + } + + return 0; +} + +static void sci_free_irq(struct sci_port *port) +{ + int i; + + if (port->irqs[0] == port->irqs[1]) + free_irq(port->irqs[0], port); + else { + for (i = 0; i < ARRAY_SIZE(port->irqs); i++) { + if (!port->irqs[i]) + continue; + + free_irq(port->irqs[i], port); + } + } +} + +static unsigned int sci_tx_empty(struct uart_port *port) +{ + unsigned short status = sci_in(port, SCxSR); + unsigned short in_tx_fifo = scif_txfill(port); + + return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; +} + +static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ + /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ + /* If you have signals for DTR and DCD, please implement here. */ +} + +static unsigned int sci_get_mctrl(struct uart_port *port) +{ + /* This routine is used for getting signals of: DTR, DCD, DSR, RI, + and CTS/RTS */ + + return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR; +} + +#ifdef CONFIG_SERIAL_SH_SCI_DMA +static void sci_dma_tx_complete(void *arg) +{ + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + unsigned long flags; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + xmit->tail += sg_dma_len(&s->sg_tx); + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += sg_dma_len(&s->sg_tx); + + async_tx_ack(s->desc_tx); + s->cookie_tx = -EINVAL; + s->desc_tx = NULL; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (!uart_circ_empty(xmit)) { + schedule_work(&s->work_tx); + } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = sci_in(port, SCSCR); + sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Locking: called with port lock held */ +static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty, + size_t count) +{ + struct uart_port *port = &s->port; + int i, active, room; + + room = tty_buffer_request_room(tty, count); + + if (s->active_rx == s->cookie_rx[0]) { + active = 0; + } else if (s->active_rx == s->cookie_rx[1]) { + active = 1; + } else { + dev_err(port->dev, "cookie %d not found!\n", s->active_rx); + return 0; + } + + if (room < count) + dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", + count - room); + if (!room) + return room; + + for (i = 0; i < room; i++) + tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i], + TTY_NORMAL); + + port->icount.rx += room; + + return room; +} + +static void sci_dma_rx_complete(void *arg) +{ + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct tty_struct *tty = port->state->port.tty; + unsigned long flags; + int count; + + dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); + + spin_lock_irqsave(&port->lock, flags); + + count = sci_dma_rx_push(s, tty, s->buf_len_rx); + + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tty); + + schedule_work(&s->work_rx); +} + +static void sci_start_rx(struct uart_port *port); +static void sci_start_tx(struct uart_port *port); + +static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + + s->chan_rx = NULL; + s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + dma_release_channel(chan); + if (sg_dma_address(&s->sg_rx[0])) + dma_free_coherent(port->dev, s->buf_len_rx * 2, + sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0])); + if (enable_pio) + sci_start_rx(port); +} + +static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + + s->chan_tx = NULL; + s->cookie_tx = -EINVAL; + dma_release_channel(chan); + if (enable_pio) + sci_start_tx(port); +} + +static void sci_submit_rx(struct sci_port *s) +{ + struct dma_chan *chan = s->chan_rx; + int i; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + struct dma_async_tx_descriptor *desc; + + desc = chan->device->device_prep_slave_sg(chan, + sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT); + + if (desc) { + s->desc_rx[i] = desc; + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[i] = desc->tx_submit(desc); + } + + if (!desc || s->cookie_rx[i] < 0) { + if (i) { + async_tx_ack(s->desc_rx[0]); + s->cookie_rx[0] = -EINVAL; + } + if (desc) { + async_tx_ack(desc); + s->cookie_rx[i] = -EINVAL; + } + dev_warn(s->port.dev, + "failed to re-start DMA, using PIO\n"); + sci_rx_dma_release(s, true); + return; + } + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, + s->cookie_rx[i], i); + } + + s->active_rx = s->cookie_rx[0]; + + dma_async_issue_pending(chan); +} + +static void work_fn_rx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_rx); + struct uart_port *port = &s->port; + struct dma_async_tx_descriptor *desc; + int new; + + if (s->active_rx == s->cookie_rx[0]) { + new = 0; + } else if (s->active_rx == s->cookie_rx[1]) { + new = 1; + } else { + dev_err(port->dev, "cookie %d not found!\n", s->active_rx); + return; + } + desc = s->desc_rx[new]; + + if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != + DMA_SUCCESS) { + /* Handle incomplete DMA receive */ + struct tty_struct *tty = port->state->port.tty; + struct dma_chan *chan = s->chan_rx; + struct sh_desc *sh_desc = container_of(desc, struct sh_desc, + async_tx); + unsigned long flags; + int count; + + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dev_dbg(port->dev, "Read %u bytes with cookie %d\n", + sh_desc->partial, sh_desc->cookie); + + spin_lock_irqsave(&port->lock, flags); + count = sci_dma_rx_push(s, tty, sh_desc->partial); + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tty); + + sci_submit_rx(s); + + return; + } + + s->cookie_rx[new] = desc->tx_submit(desc); + if (s->cookie_rx[new] < 0) { + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + sci_rx_dma_release(s, true); + return; + } + + s->active_rx = s->cookie_rx[!new]; + + dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, + s->cookie_rx[new], new, s->active_rx); +} + +static void work_fn_tx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_tx); + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + struct scatterlist *sg = &s->sg_tx; + + /* + * DMA is idle now. + * Port xmit buffer is already mapped, and it is one page... Just adjust + * offsets and lengths. Since it is a circular buffer, we have to + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ + spin_lock_irq(&port->lock); + sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); + sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + + sg->offset; + sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); + spin_unlock_irq(&port->lock); + + BUG_ON(!sg_dma_len(sg)); + + desc = chan->device->device_prep_slave_sg(chan, + sg, s->sg_len_tx, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + + spin_lock_irq(&port->lock); + s->desc_tx = desc; + desc->callback = sci_dma_tx_complete; + desc->callback_param = s; + spin_unlock_irq(&port->lock); + s->cookie_tx = desc->tx_submit(desc); + if (s->cookie_tx < 0) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, + xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + + dma_async_issue_pending(chan); +} +#endif + +static void sci_start_tx(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + unsigned short ctrl; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 new, scr = sci_in(port, SCSCR); + if (s->chan_tx) + new = scr | 0x8000; + else + new = scr & ~0x8000; + if (new != scr) + sci_out(port, SCSCR, new); + } + if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + s->cookie_tx < 0) + schedule_work(&s->work_tx); +#endif + if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE); + } +} + +static void sci_stop_tx(struct uart_port *port) +{ + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~0x8000; + ctrl &= ~SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); +} + +static void sci_start_rx(struct uart_port *port) +{ + unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; + + /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ + ctrl |= sci_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~0x4000; + sci_out(port, SCSCR, ctrl); +} + +static void sci_stop_rx(struct uart_port *port) +{ + unsigned short ctrl; + + /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~0x4000; + ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); + sci_out(port, SCSCR, ctrl); +} + +static void sci_enable_ms(struct uart_port *port) +{ + /* Nothing here yet .. */ +} + +static void sci_break_ctl(struct uart_port *port, int break_state) +{ + /* Nothing here yet .. */ +} + +#ifdef CONFIG_SERIAL_SH_SCI_DMA +static bool filter(struct dma_chan *chan, void *slave) +{ + struct sh_dmae_slave *param = slave; + + dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, + param->slave_id); + + if (param->dma_dev == chan->device->dev) { + chan->private = param; + return true; + } else { + return false; + } +} + +static void rx_timer_fn(unsigned long arg) +{ + struct sci_port *s = (struct sci_port *)arg; + struct uart_port *port = &s->port; + u16 scr = sci_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~0x4000; + enable_irq(s->irqs[1]); + } + sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE); + dev_dbg(port->dev, "DMA Rx timed out\n"); + schedule_work(&s->work_rx); +} + +static void sci_request_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sh_dmae_slave *param; + struct dma_chan *chan; + dma_cap_mask_t mask; + int nent; + + dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__, + port->line, s->dma_dev); + + if (!s->dma_dev) + return; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + param = &s->param_tx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ + param->slave_id = s->slave_tx; + param->dma_dev = s->dma_dev; + + s->cookie_tx = -EINVAL; + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); + if (chan) { + s->chan_tx = chan; + sg_init_table(&s->sg_tx, 1); + /* UART circular tx buffer is an aligned page. */ + BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), + UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); + nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); + if (!nent) + sci_tx_dma_release(s, false); + else + dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, + sg_dma_len(&s->sg_tx), + port->state->xmit.buf, sg_dma_address(&s->sg_tx)); + + s->sg_len_tx = nent; + + INIT_WORK(&s->work_tx, work_fn_tx); + } + + param = &s->param_rx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ + param->slave_id = s->slave_rx; + param->dma_dev = s->dma_dev; + + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); + if (chan) { + dma_addr_t dma[2]; + void *buf[2]; + int i; + + s->chan_rx = chan; + + s->buf_len_rx = 2 * max(16, (int)port->fifosize); + buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2, + &dma[0], GFP_KERNEL); + + if (!buf[0]) { + dev_warn(port->dev, + "failed to allocate dma buffer, using PIO\n"); + sci_rx_dma_release(s, true); + return; + } + + buf[1] = buf[0] + s->buf_len_rx; + dma[1] = dma[0] + s->buf_len_rx; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + + sg_init_table(sg, 1); + sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, + (int)buf[i] & ~PAGE_MASK); + sg_dma_address(sg) = dma[i]; + } + + INIT_WORK(&s->work_rx, work_fn_rx); + setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); + + sci_submit_rx(s); + } +} + +static void sci_free_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + if (!s->dma_dev) + return; + + if (s->chan_tx) + sci_tx_dma_release(s, false); + if (s->chan_rx) + sci_rx_dma_release(s, false); +} +#endif + +static int sci_startup(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + if (s->enable) + s->enable(port); + + sci_request_irq(s); +#ifdef CONFIG_SERIAL_SH_SCI_DMA + sci_request_dma(port); +#endif + sci_start_tx(port); + sci_start_rx(port); + + return 0; +} + +static void sci_shutdown(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + sci_stop_rx(port); + sci_stop_tx(port); +#ifdef CONFIG_SERIAL_SH_SCI_DMA + sci_free_dma(port); +#endif + sci_free_irq(s); + + if (s->disable) + s->disable(port); +} + +static void sci_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ +#ifdef CONFIG_SERIAL_SH_SCI_DMA + struct sci_port *s = to_sci_port(port); +#endif + unsigned int status, baud, smr_val, max_baud; + int t = -1; + u16 scfcr = 0; + + /* + * earlyprintk comes here early on with port->uartclk set to zero. + * the clock framework is not up and running at this point so here + * we assume that 115200 is the maximum baud rate. please note that + * the baud rate is not programmed during earlyprintk - it is assumed + * that the previous boot loader has enabled required clocks and + * setup the baud rate generator hardware for us already. + */ + max_baud = port->uartclk ? port->uartclk / 16 : 115200; + + baud = uart_get_baud_rate(port, termios, old, 0, max_baud); + if (likely(baud && port->uartclk)) + t = SCBRR_VALUE(baud, port->uartclk); + + do { + status = sci_in(port, SCxSR); + } while (!(status & SCxSR_TEND(port))); + + sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ + + if (port->type != PORT_SCI) + sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST); + + smr_val = sci_in(port, SCSMR) & 3; + if ((termios->c_cflag & CSIZE) == CS7) + smr_val |= 0x40; + if (termios->c_cflag & PARENB) + smr_val |= 0x20; + if (termios->c_cflag & PARODD) + smr_val |= 0x30; + if (termios->c_cflag & CSTOPB) + smr_val |= 0x08; + + uart_update_timeout(port, termios->c_cflag, baud); + + sci_out(port, SCSMR, smr_val); + + dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, + SCSCR_INIT(port)); + + if (t > 0) { + if (t >= 256) { + sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); + t >>= 2; + } else + sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); + + sci_out(port, SCBRR, t); + udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ + } + + sci_init_pins(port, termios->c_cflag); + sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0)); + + sci_out(port, SCSCR, SCSCR_INIT(port)); + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + /* + * Calculate delay for 1.5 DMA buffers: see + * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits + * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function + * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." + * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO + * sizes), but it has been found out experimentally, that this is not + * enough: the driver too often needlessly runs on a DMA timeout. 20ms + * as a minimum seem to work perfectly. + */ + if (s->chan_rx) { + s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / + port->fifosize / 2; + dev_dbg(port->dev, + "DMA Rx t-out %ums, tty t-out %u jiffies\n", + s->rx_timeout * 1000 / HZ, port->timeout); + if (s->rx_timeout < msecs_to_jiffies(20)) + s->rx_timeout = msecs_to_jiffies(20); + } +#endif + + if ((termios->c_cflag & CREAD) != 0) + sci_start_rx(port); +} + +static const char *sci_type(struct uart_port *port) +{ + switch (port->type) { + case PORT_IRDA: + return "irda"; + case PORT_SCI: + return "sci"; + case PORT_SCIF: + return "scif"; + case PORT_SCIFA: + return "scifa"; + case PORT_SCIFB: + return "scifb"; + } + + return NULL; +} + +static void sci_release_port(struct uart_port *port) +{ + /* Nothing here yet .. */ +} + +static int sci_request_port(struct uart_port *port) +{ + /* Nothing here yet .. */ + return 0; +} + +static void sci_config_port(struct uart_port *port, int flags) +{ + struct sci_port *s = to_sci_port(port); + + port->type = s->type; + + if (port->membase) + return; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap_nocache(port->mapbase, 0x40); + + if (IS_ERR(port->membase)) + dev_err(port->dev, "can't remap port#%d\n", port->line); + } else { + /* + * For the simple (and majority of) cases where we don't + * need to do any remapping, just cast the cookie + * directly. + */ + port->membase = (void __iomem *)port->mapbase; + } +} + +static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct sci_port *s = to_sci_port(port); + + if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) + return -EINVAL; + if (ser->baud_base < 2400) + /* No paper tape reader for Mitch.. */ + return -EINVAL; + + return 0; +} + +static struct uart_ops sci_uart_ops = { + .tx_empty = sci_tx_empty, + .set_mctrl = sci_set_mctrl, + .get_mctrl = sci_get_mctrl, + .start_tx = sci_start_tx, + .stop_tx = sci_stop_tx, + .stop_rx = sci_stop_rx, + .enable_ms = sci_enable_ms, + .break_ctl = sci_break_ctl, + .startup = sci_startup, + .shutdown = sci_shutdown, + .set_termios = sci_set_termios, + .type = sci_type, + .release_port = sci_release_port, + .request_port = sci_request_port, + .config_port = sci_config_port, + .verify_port = sci_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sci_poll_get_char, + .poll_put_char = sci_poll_put_char, +#endif +}; + +static int __devinit sci_init_single(struct platform_device *dev, + struct sci_port *sci_port, + unsigned int index, + struct plat_sci_port *p) +{ + struct uart_port *port = &sci_port->port; + + port->ops = &sci_uart_ops; + port->iotype = UPIO_MEM; + port->line = index; + + switch (p->type) { + case PORT_SCIFB: + port->fifosize = 256; + break; + case PORT_SCIFA: + port->fifosize = 64; + break; + case PORT_SCIF: + port->fifosize = 16; + break; + default: + port->fifosize = 1; + break; + } + + if (dev) { + sci_port->iclk = clk_get(&dev->dev, "sci_ick"); + if (IS_ERR(sci_port->iclk)) { + sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); + if (IS_ERR(sci_port->iclk)) { + dev_err(&dev->dev, "can't get iclk\n"); + return PTR_ERR(sci_port->iclk); + } + } + + /* + * The function clock is optional, ignore it if we can't + * find it. + */ + sci_port->fclk = clk_get(&dev->dev, "sci_fck"); + if (IS_ERR(sci_port->fclk)) + sci_port->fclk = NULL; + + sci_port->enable = sci_clk_enable; + sci_port->disable = sci_clk_disable; + port->dev = &dev->dev; + } + + sci_port->break_timer.data = (unsigned long)sci_port; + sci_port->break_timer.function = sci_break_timer; + init_timer(&sci_port->break_timer); + + port->mapbase = p->mapbase; + port->membase = p->membase; + + port->irq = p->irqs[SCIx_TXI_IRQ]; + port->flags = p->flags; + sci_port->type = port->type = p->type; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + sci_port->dma_dev = p->dma_dev; + sci_port->slave_tx = p->dma_slave_tx; + sci_port->slave_rx = p->dma_slave_rx; + + dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__, + p->dma_dev, p->dma_slave_tx, p->dma_slave_rx); +#endif + + memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs)); + return 0; +} + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +static struct tty_driver *serial_console_device(struct console *co, int *index) +{ + struct uart_driver *p = &sci_uart_driver; + *index = co->index; + return p->tty_driver; +} + +static void serial_console_putchar(struct uart_port *port, int ch) +{ + sci_poll_put_char(port, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + struct uart_port *port = co->data; + struct sci_port *sci_port = to_sci_port(port); + unsigned short bits; + + if (sci_port->enable) + sci_port->enable(port); + + uart_console_write(port, s, count, serial_console_putchar); + + /* wait until fifo is empty and last bit has been transmitted */ + bits = SCxSR_TDxE(port) | SCxSR_TEND(port); + while ((sci_in(port, SCxSR) & bits) != bits) + cpu_relax(); + + if (sci_port->disable) + sci_port->disable(port); +} + +static int __devinit serial_console_setup(struct console *co, char *options) +{ + struct sci_port *sci_port; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= SCI_NPORTS) + co->index = 0; + + if (co->data) { + port = co->data; + sci_port = to_sci_port(port); + } else { + sci_port = &sci_ports[co->index]; + port = &sci_port->port; + co->data = port; + } + + /* + * Also need to check port->type, we don't actually have any + * UPIO_PORT ports, but uart_report_port() handily misreports + * it anyways if we don't have a port available by the time this is + * called. + */ + if (!port->type) + return -ENODEV; + + sci_config_port(port, 0); + + if (sci_port->enable) + sci_port->enable(port); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + ret = uart_set_options(port, co, baud, parity, bits, flow); +#if defined(__H8300H__) || defined(__H8300S__) + /* disable rx interrupt */ + if (ret == 0) + sci_stop_rx(port); +#endif + /* TODO: disable clock */ + return ret; +} + +static struct console serial_console = { + .name = "ttySC", + .device = serial_console_device, + .write = serial_console_write, + .setup = serial_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int __init sci_console_init(void) +{ + register_console(&serial_console); + return 0; +} +console_initcall(sci_console_init); + +static struct sci_port early_serial_port; +static struct console early_serial_console = { + .name = "early_ttySC", + .write = serial_console_write, + .flags = CON_PRINTBUFFER, +}; +static char early_serial_buf[32]; + +#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ + +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) +#define SCI_CONSOLE (&serial_console) +#else +#define SCI_CONSOLE 0 +#endif + +static char banner[] __initdata = + KERN_INFO "SuperH SCI(F) driver initialized\n"; + +static struct uart_driver sci_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "sci", + .dev_name = "ttySC", + .major = SCI_MAJOR, + .minor = SCI_MINOR_START, + .nr = SCI_NPORTS, + .cons = SCI_CONSOLE, +}; + + +static int sci_remove(struct platform_device *dev) +{ + struct sh_sci_priv *priv = platform_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; + + cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) { + uart_remove_one_port(&sci_uart_driver, &p->port); + clk_put(p->iclk); + clk_put(p->fclk); + } + spin_unlock_irqrestore(&priv->lock, flags); + + kfree(priv); + return 0; +} + +static int __devinit sci_probe_single(struct platform_device *dev, + unsigned int index, + struct plat_sci_port *p, + struct sci_port *sciport) +{ + struct sh_sci_priv *priv = platform_get_drvdata(dev); + unsigned long flags; + int ret; + + /* Sanity check */ + if (unlikely(index >= SCI_NPORTS)) { + dev_notice(&dev->dev, "Attempting to register port " + "%d when only %d are available.\n", + index+1, SCI_NPORTS); + dev_notice(&dev->dev, "Consider bumping " + "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + return 0; + } + + ret = sci_init_single(dev, sciport, index, p); + if (ret) + return ret; + + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); + if (ret) + return ret; + + INIT_LIST_HEAD(&sciport->node); + + spin_lock_irqsave(&priv->lock, flags); + list_add(&sciport->node, &priv->ports); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/* + * Register a set of serial devices attached to a platform device. The + * list is terminated with a zero flags entry, which means we expect + * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need + * remapping (such as sh64) should also set UPF_IOREMAP. + */ +static int __devinit sci_probe(struct platform_device *dev) +{ + struct plat_sci_port *p = dev->dev.platform_data; + struct sh_sci_priv *priv; + int i, ret = -EINVAL; + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE + if (is_early_platform_device(dev)) { + if (dev->id == -1) + return -ENOTSUPP; + early_serial_console.index = dev->id; + early_serial_console.data = &early_serial_port.port; + sci_init_single(NULL, &early_serial_port, dev->id, p); + serial_console_setup(&early_serial_console, early_serial_buf); + if (!strstr(early_serial_buf, "keep")) + early_serial_console.flags |= CON_BOOT; + register_console(&early_serial_console); + return 0; + } +#endif + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + INIT_LIST_HEAD(&priv->ports); + spin_lock_init(&priv->lock); + platform_set_drvdata(dev, priv); + + priv->clk_nb.notifier_call = sci_notifier; + cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER); + + if (dev->id != -1) { + ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]); + if (ret) + goto err_unreg; + } else { + for (i = 0; p && p->flags != 0; p++, i++) { + ret = sci_probe_single(dev, i, p, &sci_ports[i]); + if (ret) + goto err_unreg; + } + } + +#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) +{ + struct sh_sci_priv *priv = dev_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_suspend_port(&sci_uart_driver, &p->port); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int sci_resume(struct device *dev) +{ + struct sh_sci_priv *priv = dev_get_drvdata(dev); + struct sci_port *p; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(p, &priv->ports, node) + uart_resume_port(&sci_uart_driver, &p->port); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static const struct dev_pm_ops sci_dev_pm_ops = { + .suspend = sci_suspend, + .resume = sci_resume, +}; + +static struct platform_driver sci_driver = { + .probe = sci_probe, + .remove = sci_remove, + .driver = { + .name = "sh-sci", + .owner = THIS_MODULE, + .pm = &sci_dev_pm_ops, + }, +}; + +static int __init sci_init(void) +{ + int ret; + + printk(banner); + + ret = uart_register_driver(&sci_uart_driver); + if (likely(ret == 0)) { + ret = platform_driver_register(&sci_driver); + if (unlikely(ret)) + uart_unregister_driver(&sci_uart_driver); + } + + return ret; +} + +static void __exit sci_exit(void) +{ + platform_driver_unregister(&sci_driver); + uart_unregister_driver(&sci_uart_driver); +} + +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +early_platform_init_buffer("earlyprintk", &sci_driver, + early_serial_buf, ARRAY_SIZE(early_serial_buf)); +#endif +module_init(sci_init); +module_exit(sci_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sh-sci"); diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h new file mode 100644 index 000000000000..4bc614e4221c --- /dev/null +++ b/drivers/tty/serial/sh-sci.h @@ -0,0 +1,660 @@ +#include +#include +#include + +#if defined(CONFIG_H83007) || defined(CONFIG_H83068) +#include +#endif +#if defined(CONFIG_H8S2678) +#include +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7708) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) +# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ +# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) +# define SCIF0 0xA4400000 +# define SCIF2 0xA4410000 +# define SCSMR_Ir 0xA44A0000 +# define IRDA_SCIF SCIF0 +# define SCPCR 0xA4000116 +# define SCPDR 0xA4000136 + +/* Set the clock source, + * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input + * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output + */ +# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) +# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define PORT_PTCR 0xA405011EUL +# define PORT_PVCR 0xA4050122UL +# define SCIF_ORER 0x0200 /* overrun error bit */ +#elif defined(CONFIG_SH_RTS7751R2D) +# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */ +# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) +# define SCSPTR1 0xffe0001c /* 8 bit SCI */ +# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ + 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ + 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) +#elif defined(CONFIG_CPU_SUBTYPE_SH7760) +# define SCSPTR0 0xfe600024 /* 16 bit SCIF */ +# define SCSPTR1 0xfe610024 /* 16 bit SCIF */ +# define SCSPTR2 0xfe620024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +# define SCSPTR0 0xA4400000 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define PACR 0xa4050100 +# define PBCR 0xa4050102 +# define SCSCR_INIT(port) 0x3B +#elif defined(CONFIG_CPU_SUBTYPE_SH7343) +# define SCSPTR0 0xffe00010 /* 16 bit SCIF */ +# define SCSPTR1 0xffe10010 /* 16 bit SCIF */ +# define SCSPTR2 0xffe20010 /* 16 bit SCIF */ +# define SCSPTR3 0xffe30010 /* 16 bit SCIF */ +# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7722) +# define PADR 0xA4050120 +# define PSDR 0xA405013e +# define PWDR 0xA4050166 +# define PSCR 0xA405011E +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7366) +# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */ +# define SCSPTR0 SCPDR0 +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +# define SCSPTR0 0xa4050160 +# define SCSPTR1 0xa405013e +# define SCSPTR2 0xa4050160 +# define SCSPTR3 0xa405013e +# define SCSPTR4 0xa4050128 +# define SCSPTR5 0xa4050128 +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \ + 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ + 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) +#elif defined(CONFIG_CPU_SUBTYPE_SH4_202) +# define SCSPTR2 0xffe80020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) +# define SCIF_BASE_ADDR 0x01030000 +# define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR +# define SCIF_PTR2_OFFS 0x0000020 +# define SCIF_LSR2_OFFS 0x0000024 +# define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */ +# define SCLSR2 ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) +#elif defined(CONFIG_H8S2678) +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) +#elif defined(CONFIG_CPU_SUBTYPE_SH7757) +# define SCSPTR0 0xfe4b0020 +# define SCSPTR1 0xfe4b0020 +# define SCSPTR2 0xfe4b0020 +# define SCIF_ORER 0x0001 +# define SCSCR_INIT(port) 0x38 +# define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +# define SCSPTR0 0xffe00024 /* 16 bit SCIF */ +# define SCSPTR1 0xffe08024 /* 16 bit SCIF */ +# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7770) +# define SCSPTR0 0xff923020 /* 16 bit SCIF */ +# define SCSPTR1 0xff924020 /* 16 bit SCIF */ +# define SCSPTR2 0xff925020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) +# define SCSPTR0 0xffe00024 /* 16 bit SCIF */ +# define SCSPTR1 0xffe10024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* Overrun error bit */ + +#if defined(CONFIG_SH_SH2007) +/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */ +# define SCSCR_INIT(port) 0x38 +#else +/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */ +# define SCSCR_INIT(port) 0x3a +#endif + +#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) +# define SCSPTR0 0xffea0024 /* 16 bit SCIF */ +# define SCSPTR1 0xffeb0024 /* 16 bit SCIF */ +# define SCSPTR2 0xffec0024 /* 16 bit SCIF */ +# define SCSPTR3 0xffed0024 /* 16 bit SCIF */ +# define SCSPTR4 0xffee0024 /* 16 bit SCIF */ +# define SCSPTR5 0xffef0024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* Overrun error bit */ +# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \ + defined(CONFIG_CPU_SUBTYPE_SH7203) || \ + defined(CONFIG_CPU_SUBTYPE_SH7206) || \ + defined(CONFIG_CPU_SUBTYPE_SH7263) +# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ +# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ +# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ +# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */ +# if defined(CONFIG_CPU_SUBTYPE_SH7201) +# define SCSPTR4 0xfffeA020 /* 16 bit SCIF */ +# define SCSPTR5 0xfffeA820 /* 16 bit SCIF */ +# define SCSPTR6 0xfffeB020 /* 16 bit SCIF */ +# define SCSPTR7 0xfffeB820 /* 16 bit SCIF */ +# endif +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7619) +# define SCSPTR0 0xf8400020 /* 16 bit SCIF */ +# define SCSPTR1 0xf8410020 /* 16 bit SCIF */ +# define SCSPTR2 0xf8420020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SHX3) +# define SCSPTR0 0xffc30020 /* 16 bit SCIF */ +# define SCSPTR1 0xffc40020 /* 16 bit SCIF */ +# define SCSPTR2 0xffc50020 /* 16 bit SCIF */ +# define SCSPTR3 0xffc60020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* Overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#else +# error CPU subtype not defined +#endif + +/* SCSCR */ +#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ +#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ +#define SCI_CTRL_FLAGS_TE 0x20 /* all */ +#define SCI_CTRL_FLAGS_RE 0x10 /* all */ +#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7722) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) || \ + defined(CONFIG_CPU_SUBTYPE_SHX3) +#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7724) +#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8) +#else +#define SCI_CTRL_FLAGS_REIE 0 +#endif +/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ +/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ + +/* SCxSR SCI */ +#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */ + +#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) + +/* SCxSR SCIF */ +#define SCIF_ER 0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_TEND 0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_TDFE 0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_BRK 0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_FER 0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_PER 0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ +#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ + +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) +# define SCIF_ORER 0x0200 +# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) +# define SCIF_RFDC_MASK 0x007f +# define SCIF_TXROOM_MAX 64 +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK ) +# define SCIF_RFDC_MASK 0x007f +# define SCIF_TXROOM_MAX 64 +/* SH7763 SCIF2 support */ +# define SCIF2_RFDC_MASK 0x001f +# define SCIF2_TXROOM_MAX 16 +#else +# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) +# define SCIF_RFDC_MASK 0x001f +# define SCIF_TXROOM_MAX 16 +#endif + +#ifndef SCIF_ORER +#define SCIF_ORER 0x0000 +#endif + +#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) +#define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) +#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) +#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) +#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) +#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) +#define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER) + +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) +# define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc) +# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73) +# define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf) +# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3) +#else +# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) +# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) +# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) +# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) +#endif + +/* SCFCR */ +#define SCFCR_RFRST 0x0002 +#define SCFCR_TFRST 0x0004 +#define SCFCR_TCRST 0x4000 +#define SCFCR_MCE 0x0008 + +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + +/* Generic serial flags */ +#define SCI_RX_THROTTLE 0x0000001 + +#define SCI_MAGIC 0xbabeface + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define SCI_EVENT_WRITE_WAKEUP 0 + +#define SCI_IN(size, offset) \ + if ((size) == 8) { \ + return ioread8(port->membase + (offset)); \ + } else { \ + return ioread16(port->membase + (offset)); \ + } +#define SCI_OUT(size, offset, value) \ + if ((size) == 8) { \ + iowrite8(value, port->membase + (offset)); \ + } else if ((size) == 16) { \ + iowrite16(value, port->membase + (offset)); \ + } + +#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ + SCI_IN(scif_size, scif_offset) \ + } else { /* PORT_SCI or PORT_SCIFA */ \ + SCI_IN(sci_size, sci_offset); \ + } \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ + SCI_OUT(scif_size, scif_offset, value) \ + } else { /* PORT_SCI or PORT_SCIFA */ \ + SCI_OUT(sci_size, sci_offset, value); \ + } \ + } + +#ifdef CONFIG_H8300 +/* h8300 don't have SCIF */ +#define CPU_SCIF_FNS(name) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + return 0; \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + } +#else +#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ + static inline unsigned int sci_##name##_in(struct uart_port *port) \ + { \ + SCI_IN(scif_size, scif_offset); \ + } \ + static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ + { \ + SCI_OUT(scif_size, scif_offset, value); \ + } +#endif + +#define CPU_SCI_FNS(name, sci_offset, sci_size) \ + static inline unsigned int sci_##name##_in(struct uart_port* port) \ + { \ + SCI_IN(sci_size, sci_offset); \ + } \ + static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \ + { \ + SCI_OUT(sci_size, sci_offset, value); \ + } + +#if defined(CONFIG_CPU_SH3) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) +#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) +#define SCIF_FNS(name, scif_offset, scif_size) \ + CPU_SCIF_FNS(name, scif_offset, scif_size) +#elif defined(CONFIG_ARCH_SH7372) +#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \ + CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) +#define SCIF_FNS(name, scif_offset, scif_size) \ + CPU_SCIF_FNS(name, scif_offset, scif_size) +#else +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) +#endif +#elif defined(__H8300H__) || defined(__H8300S__) +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) + #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) + #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#else +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ + h8_sci_offset, h8_sci_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) + +SCIF_FNS(SCSMR, 0x00, 16) +SCIF_FNS(SCBRR, 0x04, 8) +SCIF_FNS(SCSCR, 0x08, 16) +SCIF_FNS(SCTDSR, 0x0c, 8) +SCIF_FNS(SCFER, 0x10, 16) +SCIF_FNS(SCxSR, 0x14, 16) +SCIF_FNS(SCFCR, 0x18, 16) +SCIF_FNS(SCFDR, 0x1c, 16) +SCIF_FNS(SCxTDR, 0x20, 8) +SCIF_FNS(SCxRDR, 0x24, 8) +SCIF_FNS(SCLSR, 0x00, 0) +#elif defined(CONFIG_ARCH_SH7372) +SCIF_FNS(SCSMR, 0x00, 16) +SCIF_FNS(SCBRR, 0x04, 8) +SCIF_FNS(SCSCR, 0x08, 16) +SCIF_FNS(SCTDSR, 0x0c, 16) +SCIF_FNS(SCFER, 0x10, 16) +SCIF_FNS(SCxSR, 0x14, 16) +SCIF_FNS(SCFCR, 0x18, 16) +SCIF_FNS(SCFDR, 0x1c, 16) +SCIF_FNS(SCTFDR, 0x38, 16) +SCIF_FNS(SCRFDR, 0x3c, 16) +SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8) +SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8) +SCIF_FNS(SCLSR, 0x00, 0) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) +SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) +SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) +SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) +SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8) +SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16) +SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8) +SCIx_FNS(SCSPTR, 0, 0, 0, 0) +SCIF_FNS(SCTDSR, 0x0c, 8) +SCIF_FNS(SCFER, 0x10, 16) +SCIF_FNS(SCFCR, 0x18, 16) +SCIF_FNS(SCFDR, 0x1c, 16) +SCIF_FNS(SCLSR, 0x24, 16) +#else +/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ +/* name off sz off sz off sz off sz off sz*/ +SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8) +SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8) +SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8) +SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8) +SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) +SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) +SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) +#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) +SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) +SCIF_FNS(SCLSR, 0, 0, 0x28, 16) +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) +SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) +SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) +SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) +SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) +SCIF_FNS(SCLSR, 0, 0, 0x28, 16) +#else +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) +#if defined(CONFIG_CPU_SUBTYPE_SH7722) +SCIF_FNS(SCSPTR, 0, 0, 0, 0) +#else +SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) +#endif +SCIF_FNS(SCLSR, 0, 0, 0x24, 16) +#endif +#endif +#define sci_in(port, reg) sci_##reg##_in(port) +#define sci_out(port, reg, value) sci_##reg##_out(port, value) + +/* H8/300 series SCI pins assignment */ +#if defined(__H8300H__) || defined(__H8300S__) +static const struct __attribute__((packed)) { + int port; /* GPIO port no */ + unsigned short rx,tx; /* GPIO bit no */ +} h8300_sci_pins[] = { +#if defined(CONFIG_H83007) || defined(CONFIG_H83068) + { /* SCI0 */ + .port = H8300_GPIO_P9, + .rx = H8300_GPIO_B2, + .tx = H8300_GPIO_B0, + }, + { /* SCI1 */ + .port = H8300_GPIO_P9, + .rx = H8300_GPIO_B3, + .tx = H8300_GPIO_B1, + }, + { /* SCI2 */ + .port = H8300_GPIO_PB, + .rx = H8300_GPIO_B7, + .tx = H8300_GPIO_B6, + } +#elif defined(CONFIG_H8S2678) + { /* SCI0 */ + .port = H8300_GPIO_P3, + .rx = H8300_GPIO_B2, + .tx = H8300_GPIO_B0, + }, + { /* SCI1 */ + .port = H8300_GPIO_P3, + .rx = H8300_GPIO_B3, + .tx = H8300_GPIO_B1, + }, + { /* SCI2 */ + .port = H8300_GPIO_P5, + .rx = H8300_GPIO_B1, + .tx = H8300_GPIO_B0, + } +#endif +}; +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7708) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xfffffe80) + return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000) + return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ + return 1; +} +#elif defined(__H8300H__) || defined(__H8300S__) +static inline int sci_rxd_in(struct uart_port *port) +{ + int ch = (port->mapbase - SMR0) >> 3; + return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; +} +#else /* default case for non-SCI processors */ +static inline int sci_rxd_in(struct uart_port *port) +{ + return 1; +} +#endif + +/* + * Values for the BitRate Register (SCBRR) + * + * The values are actually divisors for a frequency which can + * be internal to the SH3 (14.7456MHz) or derived from an external + * clock source. This driver assumes the internal clock is used; + * to support using an external clock source, config options or + * possibly command-line options would need to be added. + * + * Also, to support speeds below 2400 (why?) the lower 2 bits of + * the SCSMR register would also need to be set to non-zero values. + * + * -- Greg Banks 27Feb2000 + * + * Answer: The SCBRR register is only eight bits, and the value in + * it gets larger with lower baud rates. At around 2400 (depending on + * the peripherial module clock) you run out of bits. However the + * lower two bits of SCSMR allow the module clock to be divided down, + * scaling the value which is needed in SCBRR. + * + * -- Stuart Menefy - 23 May 2000 + * + * I meant, why would anyone bother with bitrates below 2400. + * + * -- Greg Banks - 7Jul2000 + * + * You "speedist"! How will I use my 110bps ASR-33 teletype with paper + * tape reader as a console! + * + * -- Mitch Davis - 15 Jul 2000 + */ + +#if (defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SH7786)) && \ + !defined(CONFIG_SH_SH2007) +#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) +#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) || \ + defined(CONFIG_ARCH_SH73A0) || \ + defined(CONFIG_ARCH_SH7367) || \ + defined(CONFIG_ARCH_SH7377) || \ + defined(CONFIG_ARCH_SH7372) +#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ + defined(CONFIG_CPU_SUBTYPE_SH7724) +static inline int scbrr_calc(struct uart_port *port, int bps, int clk) +{ + if (port->type == PORT_SCIF) + return (clk+16*bps)/(32*bps)-1; + else + return ((clk*2)+16*bps)/(16*bps)-1; +} +#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk) +#elif defined(__H8300H__) || defined(__H8300S__) +#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1) +#else /* Generic SH */ +#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) +#endif diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c new file mode 100644 index 000000000000..cff9a306660f --- /dev/null +++ b/drivers/tty/serial/sn_console.c @@ -0,0 +1,1085 @@ +/* + * C-Brick Serial Port (and console) driver for SGI Altix machines. + * + * This driver is NOT suitable for talking to the l1-controller for + * anything other than 'console activities' --- please use the l1 + * driver for that. + * + * + * Copyright (c) 2004-2006 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for mdelay */ +#include +#include + +#include +#include +#include + +/* number of characters we can transmit to the SAL console at a time */ +#define SN_SAL_MAX_CHARS 120 + +/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to + * avoid losing chars, (always has to be a power of 2) */ +#define SN_SAL_BUFFER_SIZE (64 * (1 << 10)) + +#define SN_SAL_UART_FIFO_DEPTH 16 +#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10) + +/* sn_transmit_chars() calling args */ +#define TRANSMIT_BUFFERED 0 +#define TRANSMIT_RAW 1 + +/* To use dynamic numbers only and not use the assigned major and minor, + * define the following.. */ + /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */ +#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */ + +/* Device name we're using */ +#define DEVICE_NAME "ttySG" +#define DEVICE_NAME_DYNAMIC "ttySG0" /* need full name for misc_register */ +/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */ +#define DEVICE_MAJOR 204 +#define DEVICE_MINOR 40 + +#ifdef CONFIG_MAGIC_SYSRQ +static char sysrq_serial_str[] = "\eSYS"; +static char *sysrq_serial_ptr = sysrq_serial_str; +static unsigned long sysrq_requested; +#endif /* CONFIG_MAGIC_SYSRQ */ + +/* + * Port definition - this kinda drives it all + */ +struct sn_cons_port { + struct timer_list sc_timer; + struct uart_port sc_port; + struct sn_sal_ops { + int (*sal_puts_raw) (const char *s, int len); + int (*sal_puts) (const char *s, int len); + int (*sal_getc) (void); + int (*sal_input_pending) (void); + void (*sal_wakeup_transmit) (struct sn_cons_port *, int); + } *sc_ops; + unsigned long sc_interrupt_timeout; + int sc_is_asynch; +}; + +static struct sn_cons_port sal_console_port; +static int sn_process_input; + +/* Only used if USE_DYNAMIC_MINOR is set to 1 */ +static struct miscdevice misc; /* used with misc_register for dynamic */ + +extern void early_sn_setup(void); + +#undef DEBUG +#ifdef DEBUG +static int sn_debug_printf(const char *fmt, ...); +#define DPRINTF(x...) sn_debug_printf(x) +#else +#define DPRINTF(x...) do { } while (0) +#endif + +/* Prototypes */ +static int snt_hw_puts_raw(const char *, int); +static int snt_hw_puts_buffered(const char *, int); +static int snt_poll_getc(void); +static int snt_poll_input_pending(void); +static int snt_intr_getc(void); +static int snt_intr_input_pending(void); +static void sn_transmit_chars(struct sn_cons_port *, int); + +/* A table for polling: + */ +static struct sn_sal_ops poll_ops = { + .sal_puts_raw = snt_hw_puts_raw, + .sal_puts = snt_hw_puts_raw, + .sal_getc = snt_poll_getc, + .sal_input_pending = snt_poll_input_pending +}; + +/* A table for interrupts enabled */ +static struct sn_sal_ops intr_ops = { + .sal_puts_raw = snt_hw_puts_raw, + .sal_puts = snt_hw_puts_buffered, + .sal_getc = snt_intr_getc, + .sal_input_pending = snt_intr_input_pending, + .sal_wakeup_transmit = sn_transmit_chars +}; + +/* the console does output in two distinctly different ways: + * synchronous (raw) and asynchronous (buffered). initally, early_printk + * does synchronous output. any data written goes directly to the SAL + * to be output (incidentally, it is internally buffered by the SAL) + * after interrupts and timers are initialized and available for use, + * the console init code switches to asynchronous output. this is + * also the earliest opportunity to begin polling for console input. + * after console initialization, console output and tty (serial port) + * output is buffered and sent to the SAL asynchronously (either by + * timer callback or by UART interrupt) */ + +/* routines for running the console in polling mode */ + +/** + * snt_poll_getc - Get a character from the console in polling mode + * + */ +static int snt_poll_getc(void) +{ + int ch; + + ia64_sn_console_getc(&ch); + return ch; +} + +/** + * snt_poll_input_pending - Check if any input is waiting - polling mode. + * + */ +static int snt_poll_input_pending(void) +{ + int status, input; + + status = ia64_sn_console_check(&input); + return !status && input; +} + +/* routines for an interrupt driven console (normal) */ + +/** + * snt_intr_getc - Get a character from the console, interrupt mode + * + */ +static int snt_intr_getc(void) +{ + return ia64_sn_console_readc(); +} + +/** + * snt_intr_input_pending - Check if input is pending, interrupt mode + * + */ +static int snt_intr_input_pending(void) +{ + return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV; +} + +/* these functions are polled and interrupt */ + +/** + * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode + * @s: String + * @len: Length + * + */ +static int snt_hw_puts_raw(const char *s, int len) +{ + /* this will call the PROM and not return until this is done */ + return ia64_sn_console_putb(s, len); +} + +/** + * snt_hw_puts_buffered - Send string to console, polled or interrupt mode + * @s: String + * @len: Length + * + */ +static int snt_hw_puts_buffered(const char *s, int len) +{ + /* queue data to the PROM */ + return ia64_sn_console_xmit_chars((char *)s, len); +} + +/* uart interface structs + * These functions are associated with the uart_port that the serial core + * infrastructure calls. + * + * Note: Due to how the console works, many routines are no-ops. + */ + +/** + * snp_type - What type of console are we? + * @port: Port to operate with (we ignore since we only have one port) + * + */ +static const char *snp_type(struct uart_port *port) +{ + return ("SGI SN L1"); +} + +/** + * snp_tx_empty - Is the transmitter empty? We pretend we're always empty + * @port: Port to operate on (we ignore since we only have one port) + * + */ +static unsigned int snp_tx_empty(struct uart_port *port) +{ + return 1; +} + +/** + * snp_stop_tx - stop the transmitter - no-op for us + * @port: Port to operat eon - we ignore - no-op function + * + */ +static void snp_stop_tx(struct uart_port *port) +{ +} + +/** + * snp_release_port - Free i/o and resources for port - no-op for us + * @port: Port to operate on - we ignore - no-op function + * + */ +static void snp_release_port(struct uart_port *port) +{ +} + +/** + * snp_enable_ms - Force modem status interrupts on - no-op for us + * @port: Port to operate on - we ignore - no-op function + * + */ +static void snp_enable_ms(struct uart_port *port) +{ +} + +/** + * snp_shutdown - shut down the port - free irq and disable - no-op for us + * @port: Port to shut down - we ignore + * + */ +static void snp_shutdown(struct uart_port *port) +{ +} + +/** + * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console + * @port: Port to operate on - we ignore + * @mctrl: Lines to set/unset - we ignore + * + */ +static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/** + * snp_get_mctrl - get contorl line info, we just return a static value + * @port: port to operate on - we only have one port so we ignore this + * + */ +static unsigned int snp_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS; +} + +/** + * snp_stop_rx - Stop the receiver - we ignor ethis + * @port: Port to operate on - we ignore + * + */ +static void snp_stop_rx(struct uart_port *port) +{ +} + +/** + * snp_start_tx - Start transmitter + * @port: Port to operate on + * + */ +static void snp_start_tx(struct uart_port *port) +{ + if (sal_console_port.sc_ops->sal_wakeup_transmit) + sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port, + TRANSMIT_BUFFERED); + +} + +/** + * snp_break_ctl - handle breaks - ignored by us + * @port: Port to operate on + * @break_state: Break state + * + */ +static void snp_break_ctl(struct uart_port *port, int break_state) +{ +} + +/** + * snp_startup - Start up the serial port - always return 0 (We're always on) + * @port: Port to operate on + * + */ +static int snp_startup(struct uart_port *port) +{ + return 0; +} + +/** + * snp_set_termios - set termios stuff - we ignore these + * @port: port to operate on + * @termios: New settings + * @termios: Old + * + */ +static void +snp_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ +} + +/** + * snp_request_port - allocate resources for port - ignored by us + * @port: port to operate on + * + */ +static int snp_request_port(struct uart_port *port) +{ + return 0; +} + +/** + * snp_config_port - allocate resources, set up - we ignore, we're always on + * @port: Port to operate on + * @flags: flags used for port setup + * + */ +static void snp_config_port(struct uart_port *port, int flags) +{ +} + +/* Associate the uart functions above - given to serial core */ + +static struct uart_ops sn_console_ops = { + .tx_empty = snp_tx_empty, + .set_mctrl = snp_set_mctrl, + .get_mctrl = snp_get_mctrl, + .stop_tx = snp_stop_tx, + .start_tx = snp_start_tx, + .stop_rx = snp_stop_rx, + .enable_ms = snp_enable_ms, + .break_ctl = snp_break_ctl, + .startup = snp_startup, + .shutdown = snp_shutdown, + .set_termios = snp_set_termios, + .pm = NULL, + .type = snp_type, + .release_port = snp_release_port, + .request_port = snp_request_port, + .config_port = snp_config_port, + .verify_port = NULL, +}; + +/* End of uart struct functions and defines */ + +#ifdef DEBUG + +/** + * sn_debug_printf - close to hardware debugging printf + * @fmt: printf format + * + * This is as "close to the metal" as we can get, used when the driver + * itself may be broken. + * + */ +static int sn_debug_printf(const char *fmt, ...) +{ + static char printk_buf[1024]; + int printed_len; + va_list args; + + va_start(args, fmt); + printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + + if (!sal_console_port.sc_ops) { + sal_console_port.sc_ops = &poll_ops; + early_sn_setup(); + } + sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len); + + va_end(args); + return printed_len; +} +#endif /* DEBUG */ + +/* + * Interrupt handling routines. + */ + +/** + * sn_receive_chars - Grab characters, pass them to tty layer + * @port: Port to operate on + * @flags: irq flags + * + * Note: If we're not registered with the serial core infrastructure yet, + * we don't try to send characters to it... + * + */ +static void +sn_receive_chars(struct sn_cons_port *port, unsigned long flags) +{ + int ch; + struct tty_struct *tty; + + if (!port) { + printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n"); + return; + } + + if (!port->sc_ops) { + printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receieve\n"); + return; + } + + if (port->sc_port.state) { + /* The serial_core stuffs are initialized, use them */ + tty = port->sc_port.state->port.tty; + } + else { + /* Not registered yet - can't pass to tty layer. */ + tty = NULL; + } + + while (port->sc_ops->sal_input_pending()) { + ch = port->sc_ops->sal_getc(); + if (ch < 0) { + printk(KERN_ERR "sn_console: An error occured while " + "obtaining data from the console (0x%0x)\n", ch); + break; + } +#ifdef CONFIG_MAGIC_SYSRQ + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; + + sysrq_requested = 0; + if (ch && time_before(jiffies, sysrq_timeout)) { + spin_unlock_irqrestore(&port->sc_port.lock, flags); + handle_sysrq(ch); + spin_lock_irqsave(&port->sc_port.lock, flags); + /* ignore actual sysrq command char */ + continue; + } + } + if (ch == *sysrq_serial_ptr) { + if (!(*++sysrq_serial_ptr)) { + sysrq_requested = jiffies; + sysrq_serial_ptr = sysrq_serial_str; + } + /* + * ignore the whole sysrq string except for the + * leading escape + */ + if (ch != '\e') + continue; + } + else + sysrq_serial_ptr = sysrq_serial_str; +#endif /* CONFIG_MAGIC_SYSRQ */ + + /* record the character to pass up to the tty layer */ + if (tty) { + if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0) + break; + } + port->sc_port.icount.rx++; + } + + if (tty) + tty_flip_buffer_push(tty); +} + +/** + * sn_transmit_chars - grab characters from serial core, send off + * @port: Port to operate on + * @raw: Transmit raw or buffered + * + * Note: If we're early, before we're registered with serial core, the + * writes are going through sn_sal_console_write because that's how + * register_console has been set up. We currently could have asynch + * polls calling this function due to sn_sal_switch_to_asynch but we can + * ignore them until we register with the serial core stuffs. + * + */ +static void sn_transmit_chars(struct sn_cons_port *port, int raw) +{ + int xmit_count, tail, head, loops, ii; + int result; + char *start; + struct circ_buf *xmit; + + if (!port) + return; + + BUG_ON(!port->sc_is_asynch); + + if (port->sc_port.state) { + /* We're initialized, using serial core infrastructure */ + xmit = &port->sc_port.state->xmit; + } else { + /* Probably sn_sal_switch_to_asynch has been run but serial core isn't + * initialized yet. Just return. Writes are going through + * sn_sal_console_write (due to register_console) at this time. + */ + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) { + /* Nothing to do. */ + ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT); + return; + } + + head = xmit->head; + tail = xmit->tail; + start = &xmit->buf[tail]; + + /* twice around gets the tail to the end of the buffer and + * then to the head, if needed */ + loops = (head < tail) ? 2 : 1; + + for (ii = 0; ii < loops; ii++) { + xmit_count = (head < tail) ? + (UART_XMIT_SIZE - tail) : (head - tail); + + if (xmit_count > 0) { + if (raw == TRANSMIT_RAW) + result = + port->sc_ops->sal_puts_raw(start, + xmit_count); + else + result = + port->sc_ops->sal_puts(start, xmit_count); +#ifdef DEBUG + if (!result) + DPRINTF("`"); +#endif + if (result > 0) { + xmit_count -= result; + port->sc_port.icount.tx += result; + tail += result; + tail &= UART_XMIT_SIZE - 1; + xmit->tail = tail; + start = &xmit->buf[tail]; + } + } + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&port->sc_port); + + if (uart_circ_empty(xmit)) + snp_stop_tx(&port->sc_port); /* no-op for us */ +} + +/** + * sn_sal_interrupt - Handle console interrupts + * @irq: irq #, useful for debug statements + * @dev_id: our pointer to our port (sn_cons_port which contains the uart port) + * + */ +static irqreturn_t sn_sal_interrupt(int irq, void *dev_id) +{ + struct sn_cons_port *port = (struct sn_cons_port *)dev_id; + unsigned long flags; + int status = ia64_sn_console_intr_status(); + + if (!port) + return IRQ_NONE; + + spin_lock_irqsave(&port->sc_port.lock, flags); + if (status & SAL_CONSOLE_INTR_RECV) { + sn_receive_chars(port, flags); + } + if (status & SAL_CONSOLE_INTR_XMIT) { + sn_transmit_chars(port, TRANSMIT_BUFFERED); + } + spin_unlock_irqrestore(&port->sc_port.lock, flags); + return IRQ_HANDLED; +} + +/** + * sn_sal_timer_poll - this function handles polled console mode + * @data: A pointer to our sn_cons_port (which contains the uart port) + * + * data is the pointer that init_timer will store for us. This function is + * associated with init_timer to see if there is any console traffic. + * Obviously not used in interrupt mode + * + */ +static void sn_sal_timer_poll(unsigned long data) +{ + struct sn_cons_port *port = (struct sn_cons_port *)data; + unsigned long flags; + + if (!port) + return; + + if (!port->sc_port.irq) { + spin_lock_irqsave(&port->sc_port.lock, flags); + if (sn_process_input) + sn_receive_chars(port, flags); + sn_transmit_chars(port, TRANSMIT_RAW); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + mod_timer(&port->sc_timer, + jiffies + port->sc_interrupt_timeout); + } +} + +/* + * Boot-time initialization code + */ + +/** + * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch) + * @port: Our sn_cons_port (which contains the uart port) + * + * So this is used by sn_sal_serial_console_init (early on, before we're + * registered with serial core). It's also used by sn_sal_module_init + * right after we've registered with serial core. The later only happens + * if we didn't already come through here via sn_sal_serial_console_init. + * + */ +static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port) +{ + unsigned long flags; + + if (!port) + return; + + DPRINTF("sn_console: about to switch to asynchronous console\n"); + + /* without early_printk, we may be invoked late enough to race + * with other cpus doing console IO at this point, however + * console interrupts will never be enabled */ + spin_lock_irqsave(&port->sc_port.lock, flags); + + /* early_printk invocation may have done this for us */ + if (!port->sc_ops) + port->sc_ops = &poll_ops; + + /* we can't turn on the console interrupt (as request_irq + * calls kmalloc, which isn't set up yet), so we rely on a + * timer to poll for input and push data from the console + * buffer. + */ + init_timer(&port->sc_timer); + port->sc_timer.function = sn_sal_timer_poll; + port->sc_timer.data = (unsigned long)port; + + if (IS_RUNNING_ON_SIMULATOR()) + port->sc_interrupt_timeout = 6; + else { + /* 960cps / 16 char FIFO = 60HZ + * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */ + port->sc_interrupt_timeout = + HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS; + } + mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout); + + port->sc_is_asynch = 1; + spin_unlock_irqrestore(&port->sc_port.lock, flags); +} + +/** + * sn_sal_switch_to_interrupts - Switch to interrupt driven mode + * @port: Our sn_cons_port (which contains the uart port) + * + * In sn_sal_module_init, after we're registered with serial core and + * the port is added, this function is called to switch us to interrupt + * mode. We were previously in asynch/polling mode (using init_timer). + * + * We attempt to switch to interrupt mode here by calling + * request_irq. If that works out, we enable receive interrupts. + */ +static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port) +{ + unsigned long flags; + + if (port) { + DPRINTF("sn_console: switching to interrupt driven console\n"); + + if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, + IRQF_DISABLED | IRQF_SHARED, + "SAL console driver", port) >= 0) { + spin_lock_irqsave(&port->sc_port.lock, flags); + port->sc_port.irq = SGI_UART_VECTOR; + port->sc_ops = &intr_ops; + + /* turn on receive interrupts */ + ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + } + else { + printk(KERN_INFO + "sn_console: console proceeding in polled mode\n"); + } + } +} + +/* + * Kernel console definitions + */ + +static void sn_sal_console_write(struct console *, const char *, unsigned); +static int sn_sal_console_setup(struct console *, char *); +static struct uart_driver sal_console_uart; +extern struct tty_driver *uart_console_device(struct console *, int *); + +static struct console sal_console = { + .name = DEVICE_NAME, + .write = sn_sal_console_write, + .device = uart_console_device, + .setup = sn_sal_console_setup, + .index = -1, /* unspecified */ + .data = &sal_console_uart, +}; + +#define SAL_CONSOLE &sal_console + +static struct uart_driver sal_console_uart = { + .owner = THIS_MODULE, + .driver_name = "sn_console", + .dev_name = DEVICE_NAME, + .major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */ + .minor = 0, + .nr = 1, /* one port */ + .cons = SAL_CONSOLE, +}; + +/** + * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core + * + * Before this is called, we've been printing kernel messages in a special + * early mode not making use of the serial core infrastructure. When our + * driver is loaded for real, we register the driver and port with serial + * core and try to enable interrupt driven mode. + * + */ +static int __init sn_sal_module_init(void) +{ + int retval; + + if (!ia64_platform_is("sn2")) + return 0; + + printk(KERN_INFO "sn_console: Console driver init\n"); + + if (USE_DYNAMIC_MINOR == 1) { + misc.minor = MISC_DYNAMIC_MINOR; + misc.name = DEVICE_NAME_DYNAMIC; + retval = misc_register(&misc); + if (retval != 0) { + printk(KERN_WARNING "Failed to register console " + "device using misc_register.\n"); + return -ENODEV; + } + sal_console_uart.major = MISC_MAJOR; + sal_console_uart.minor = misc.minor; + } else { + sal_console_uart.major = DEVICE_MAJOR; + sal_console_uart.minor = DEVICE_MINOR; + } + + /* We register the driver and the port before switching to interrupts + * or async above so the proper uart structures are populated */ + + if (uart_register_driver(&sal_console_uart) < 0) { + printk + ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n", + __LINE__); + return -ENODEV; + } + + spin_lock_init(&sal_console_port.sc_port.lock); + + /* Setup the port struct with the minimum needed */ + sal_console_port.sc_port.membase = (char *)1; /* just needs to be non-zero */ + sal_console_port.sc_port.type = PORT_16550A; + sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS; + sal_console_port.sc_port.ops = &sn_console_ops; + sal_console_port.sc_port.line = 0; + + if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) { + /* error - not sure what I'd do - so I'll do nothing */ + printk(KERN_ERR "%s: unable to add port\n", __func__); + } + + /* when this driver is compiled in, the console initialization + * will have already switched us into asynchronous operation + * before we get here through the module initcalls */ + if (!sal_console_port.sc_is_asynch) { + sn_sal_switch_to_asynch(&sal_console_port); + } + + /* at this point (module_init) we can try to turn on interrupts */ + if (!IS_RUNNING_ON_SIMULATOR()) { + sn_sal_switch_to_interrupts(&sal_console_port); + } + sn_process_input = 1; + return 0; +} + +/** + * sn_sal_module_exit - When we're unloaded, remove the driver/port + * + */ +static void __exit sn_sal_module_exit(void) +{ + del_timer_sync(&sal_console_port.sc_timer); + uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port); + uart_unregister_driver(&sal_console_uart); + misc_deregister(&misc); +} + +module_init(sn_sal_module_init); +module_exit(sn_sal_module_exit); + +/** + * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required + * @puts_raw : puts function to do the writing + * @s: input string + * @count: length + * + * We need a \r ahead of every \n for direct writes through + * ia64_sn_console_putb (what sal_puts_raw below actually does). + * + */ + +static void puts_raw_fixed(int (*puts_raw) (const char *s, int len), + const char *s, int count) +{ + const char *s1; + + /* Output '\r' before each '\n' */ + while ((s1 = memchr(s, '\n', count)) != NULL) { + puts_raw(s, s1 - s); + puts_raw("\r\n", 2); + count -= s1 + 1 - s; + s = s1 + 1; + } + puts_raw(s, count); +} + +/** + * sn_sal_console_write - Print statements before serial core available + * @console: Console to operate on - we ignore since we have just one + * @s: String to send + * @count: length + * + * This is referenced in the console struct. It is used for early + * console printing before we register with serial core and for things + * such as kdb. The console_lock must be held when we get here. + * + * This function has some code for trying to print output even if the lock + * is held. We try to cover the case where a lock holder could have died. + * We don't use this special case code if we're not registered with serial + * core yet. After we're registered with serial core, the only time this + * function would be used is for high level kernel output like magic sys req, + * kdb, and printk's. + */ +static void +sn_sal_console_write(struct console *co, const char *s, unsigned count) +{ + unsigned long flags = 0; + struct sn_cons_port *port = &sal_console_port; + static int stole_lock = 0; + + BUG_ON(!port->sc_is_asynch); + + /* We can't look at the xmit buffer if we're not registered with serial core + * yet. So only do the fancy recovery after registering + */ + if (!port->sc_port.state) { + /* Not yet registered with serial core - simple case */ + puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); + return; + } + + /* somebody really wants this output, might be an + * oops, kdb, panic, etc. make sure they get it. */ + if (spin_is_locked(&port->sc_port.lock)) { + int lhead = port->sc_port.state->xmit.head; + int ltail = port->sc_port.state->xmit.tail; + int counter, got_lock = 0; + + /* + * We attempt to determine if someone has died with the + * lock. We wait ~20 secs after the head and tail ptrs + * stop moving and assume the lock holder is not functional + * and plow ahead. If the lock is freed within the time out + * period we re-get the lock and go ahead normally. We also + * remember if we have plowed ahead so that we don't have + * to wait out the time out period again - the asumption + * is that we will time out again. + */ + + for (counter = 0; counter < 150; mdelay(125), counter++) { + if (!spin_is_locked(&port->sc_port.lock) + || stole_lock) { + if (!stole_lock) { + spin_lock_irqsave(&port->sc_port.lock, + flags); + got_lock = 1; + } + break; + } else { + /* still locked */ + if ((lhead != port->sc_port.state->xmit.head) + || (ltail != + port->sc_port.state->xmit.tail)) { + lhead = + port->sc_port.state->xmit.head; + ltail = + port->sc_port.state->xmit.tail; + counter = 0; + } + } + } + /* flush anything in the serial core xmit buffer, raw */ + sn_transmit_chars(port, 1); + if (got_lock) { + spin_unlock_irqrestore(&port->sc_port.lock, flags); + stole_lock = 0; + } else { + /* fell thru */ + stole_lock = 1; + } + puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); + } else { + stole_lock = 0; + spin_lock_irqsave(&port->sc_port.lock, flags); + sn_transmit_chars(port, 1); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + + puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); + } +} + + +/** + * sn_sal_console_setup - Set up console for early printing + * @co: Console to work with + * @options: Options to set + * + * Altix console doesn't do anything with baud rates, etc, anyway. + * + * This isn't required since not providing the setup function in the + * console struct is ok. However, other patches like KDB plop something + * here so providing it is easier. + * + */ +static int sn_sal_console_setup(struct console *co, char *options) +{ + return 0; +} + +/** + * sn_sal_console_write_early - simple early output routine + * @co - console struct + * @s - string to print + * @count - count + * + * Simple function to provide early output, before even + * sn_sal_serial_console_init is called. Referenced in the + * console struct registerd in sn_serial_console_early_setup. + * + */ +static void __init +sn_sal_console_write_early(struct console *co, const char *s, unsigned count) +{ + puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count); +} + +/* Used for very early console printing - again, before + * sn_sal_serial_console_init is run */ +static struct console sal_console_early __initdata = { + .name = "sn_sal", + .write = sn_sal_console_write_early, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/** + * sn_serial_console_early_setup - Sets up early console output support + * + * Register a console early on... This is for output before even + * sn_sal_serial_cosnole_init is called. This function is called from + * setup.c. This allows us to do really early polled writes. When + * sn_sal_serial_console_init is called, this console is unregistered + * and a new one registered. + */ +int __init sn_serial_console_early_setup(void) +{ + if (!ia64_platform_is("sn2")) + return -1; + + sal_console_port.sc_ops = &poll_ops; + spin_lock_init(&sal_console_port.sc_port.lock); + early_sn_setup(); /* Find SAL entry points */ + register_console(&sal_console_early); + + return 0; +} + +/** + * sn_sal_serial_console_init - Early console output - set up for register + * + * This function is called when regular console init happens. Because we + * support even earlier console output with sn_serial_console_early_setup + * (called from setup.c directly), this function unregisters the really + * early console. + * + * Note: Even if setup.c doesn't register sal_console_early, unregistering + * it here doesn't hurt anything. + * + */ +static int __init sn_sal_serial_console_init(void) +{ + if (ia64_platform_is("sn2")) { + sn_sal_switch_to_asynch(&sal_console_port); + DPRINTF("sn_sal_serial_console_init : register console\n"); + register_console(&sal_console); + unregister_console(&sal_console_early); + } + return 0; +} + +console_initcall(sn_sal_serial_console_init); diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c new file mode 100644 index 000000000000..6381a0282ee7 --- /dev/null +++ b/drivers/tty/serial/suncore.c @@ -0,0 +1,247 @@ +/* suncore.c + * + * Common SUN serial routines. Based entirely + * upon drivers/sbus/char/sunserial.c which is: + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Adaptation to new UART layer is: + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "suncore.h" + +static int sunserial_current_minor = 64; + +int sunserial_register_minors(struct uart_driver *drv, int count) +{ + int err = 0; + + drv->minor = sunserial_current_minor; + drv->nr += count; + /* Register the driver on the first call */ + if (drv->nr == count) + err = uart_register_driver(drv); + if (err == 0) { + sunserial_current_minor += count; + drv->tty_driver->name_base = drv->minor - 64; + } + return err; +} +EXPORT_SYMBOL(sunserial_register_minors); + +void sunserial_unregister_minors(struct uart_driver *drv, int count) +{ + drv->nr -= count; + sunserial_current_minor -= count; + + if (drv->nr == 0) + uart_unregister_driver(drv); +} +EXPORT_SYMBOL(sunserial_unregister_minors); + +int sunserial_console_match(struct console *con, struct device_node *dp, + struct uart_driver *drv, int line, bool ignore_line) +{ + if (!con) + return 0; + + drv->cons = con; + + if (of_console_device != dp) + return 0; + + if (!ignore_line) { + int off = 0; + + if (of_console_options && + *of_console_options == 'b') + off = 1; + + if ((line & 1) != off) + return 0; + } + + if (!console_set_on_cmdline) { + con->index = line; + add_preferred_console(con->name, line, NULL); + } + return 1; +} +EXPORT_SYMBOL(sunserial_console_match); + +void sunserial_console_termios(struct console *con, struct device_node *uart_dp) +{ + const char *mode, *s; + char mode_prop[] = "ttyX-mode"; + int baud, bits, stop, cflag; + char parity; + + if (!strcmp(uart_dp->name, "rsc") || + !strcmp(uart_dp->name, "rsc-console") || + !strcmp(uart_dp->name, "rsc-control")) { + mode = of_get_property(uart_dp, + "ssp-console-modes", NULL); + if (!mode) + mode = "115200,8,n,1,-"; + } else if (!strcmp(uart_dp->name, "lom-console")) { + mode = "9600,8,n,1,-"; + } else { + struct device_node *dp; + char c; + + c = 'a'; + if (of_console_options) + c = *of_console_options; + + mode_prop[3] = c; + + dp = of_find_node_by_path("/options"); + mode = of_get_property(dp, mode_prop, NULL); + if (!mode) + mode = "9600,8,n,1,-"; + } + + cflag = CREAD | HUPCL | CLOCAL; + + s = mode; + baud = simple_strtoul(s, NULL, 0); + s = strchr(s, ','); + bits = simple_strtoul(++s, NULL, 0); + s = strchr(s, ','); + parity = *(++s); + s = strchr(s, ','); + stop = simple_strtoul(++s, NULL, 0); + s = strchr(s, ','); + /* XXX handshake is not handled here. */ + + switch (baud) { + case 150: cflag |= B150; break; + case 300: cflag |= B300; break; + case 600: cflag |= B600; break; + case 1200: cflag |= B1200; break; + case 2400: cflag |= B2400; break; + case 4800: cflag |= B4800; break; + case 9600: cflag |= B9600; break; + case 19200: cflag |= B19200; break; + case 38400: cflag |= B38400; break; + case 57600: cflag |= B57600; break; + case 115200: cflag |= B115200; break; + case 230400: cflag |= B230400; break; + case 460800: cflag |= B460800; break; + default: baud = 9600; cflag |= B9600; break; + } + + switch (bits) { + case 5: cflag |= CS5; break; + case 6: cflag |= CS6; break; + case 7: cflag |= CS7; break; + case 8: cflag |= CS8; break; + default: cflag |= CS8; break; + } + + switch (parity) { + case 'o': cflag |= (PARENB | PARODD); break; + case 'e': cflag |= PARENB; break; + case 'n': default: break; + } + + switch (stop) { + case 2: cflag |= CSTOPB; break; + case 1: default: break; + } + + con->cflag = cflag; +} + +/* Sun serial MOUSE auto baud rate detection. */ +static struct mouse_baud_cflag { + int baud; + unsigned int cflag; +} mouse_baud_table[] = { + { 1200, B1200 }, + { 2400, B2400 }, + { 4800, B4800 }, + { 9600, B9600 }, + { -1, ~0 }, + { -1, ~0 }, +}; + +unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud) +{ + int i; + + for (i = 0; mouse_baud_table[i].baud != -1; i++) + if (mouse_baud_table[i].cflag == (cflag & CBAUD)) + break; + + i += 1; + if (mouse_baud_table[i].baud == -1) + i = 0; + + *new_baud = mouse_baud_table[i].baud; + return mouse_baud_table[i].cflag; +} + +EXPORT_SYMBOL(suncore_mouse_baud_cflag_next); + +/* Basically, when the baud rate is wrong the mouse spits out + * breaks to us. + */ +int suncore_mouse_baud_detection(unsigned char ch, int is_break) +{ + static int mouse_got_break = 0; + static int ctr = 0; + + if (is_break) { + /* Let a few normal bytes go by before we jump the gun + * and say we need to try another baud rate. + */ + if (mouse_got_break && ctr < 8) + return 1; + + /* Ok, we need to try another baud. */ + ctr = 0; + mouse_got_break = 1; + return 2; + } + if (mouse_got_break) { + ctr++; + if (ch == 0x87) { + /* Correct baud rate determined. */ + mouse_got_break = 0; + } + return 1; + } + return 0; +} + +EXPORT_SYMBOL(suncore_mouse_baud_detection); + +static int __init suncore_init(void) +{ + return 0; +} + +static void __exit suncore_exit(void) +{ +} + +module_init(suncore_init); +module_exit(suncore_exit); + +MODULE_AUTHOR("Eddie C. Dost, David S. Miller"); +MODULE_DESCRIPTION("Sun serial common layer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/suncore.h b/drivers/tty/serial/suncore.h new file mode 100644 index 000000000000..db2057936c31 --- /dev/null +++ b/drivers/tty/serial/suncore.h @@ -0,0 +1,33 @@ +/* suncore.h + * + * Generic SUN serial/kbd/ms layer. Based entirely + * upon drivers/sbus/char/sunserial.h which is: + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Port to new UART layer is: + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + */ + +#ifndef _SERIAL_SUN_H +#define _SERIAL_SUN_H + +/* Serial keyboard defines for L1-A processing... */ +#define SUNKBD_RESET 0xff +#define SUNKBD_L1 0x01 +#define SUNKBD_UP 0x80 +#define SUNKBD_A 0x4d + +extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *); +extern int suncore_mouse_baud_detection(unsigned char, int); + +extern int sunserial_register_minors(struct uart_driver *, int); +extern void sunserial_unregister_minors(struct uart_driver *, int); + +extern int sunserial_console_match(struct console *, struct device_node *, + struct uart_driver *, int, bool); +extern void sunserial_console_termios(struct console *, + struct device_node *); + +#endif /* !(_SERIAL_SUN_H) */ diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c new file mode 100644 index 000000000000..c9014868297d --- /dev/null +++ b/drivers/tty/serial/sunhv.c @@ -0,0 +1,661 @@ +/* sunhv.c: Serial driver for SUN4V hypervisor console. + * + * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include "suncore.h" + +#define CON_BREAK ((long)-1) +#define CON_HUP ((long)-2) + +#define IGNORE_BREAK 0x1 +#define IGNORE_ALL 0x2 + +static char *con_write_page; +static char *con_read_page; + +static int hung_up = 0; + +static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit) +{ + while (!uart_circ_empty(xmit)) { + long status = sun4v_con_putchar(xmit->buf[xmit->tail]); + + if (status != HV_EOK) + break; + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } +} + +static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit) +{ + while (!uart_circ_empty(xmit)) { + unsigned long ra = __pa(xmit->buf + xmit->tail); + unsigned long len, status, sent; + + len = CIRC_CNT_TO_END(xmit->head, xmit->tail, + UART_XMIT_SIZE); + status = sun4v_con_write(ra, len, &sent); + if (status != HV_EOK) + break; + xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1); + port->icount.tx += sent; + } +} + +static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty) +{ + int saw_console_brk = 0; + int limit = 10000; + + while (limit-- > 0) { + long status; + long c = sun4v_con_getchar(&status); + + if (status == HV_EWOULDBLOCK) + break; + + if (c == CON_BREAK) { + if (uart_handle_break(port)) + continue; + saw_console_brk = 1; + c = 0; + } + + if (c == CON_HUP) { + hung_up = 1; + uart_handle_dcd_change(port, 0); + } else if (hung_up) { + hung_up = 0; + uart_handle_dcd_change(port, 1); + } + + if (tty == NULL) { + uart_handle_sysrq_char(port, c); + continue; + } + + port->icount.rx++; + + if (uart_handle_sysrq_char(port, c)) + continue; + + tty_insert_flip_char(tty, c, TTY_NORMAL); + } + + return saw_console_brk; +} + +static int receive_chars_read(struct uart_port *port, struct tty_struct *tty) +{ + int saw_console_brk = 0; + int limit = 10000; + + while (limit-- > 0) { + unsigned long ra = __pa(con_read_page); + unsigned long bytes_read, i; + long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read); + + if (stat != HV_EOK) { + bytes_read = 0; + + if (stat == CON_BREAK) { + if (uart_handle_break(port)) + continue; + saw_console_brk = 1; + *con_read_page = 0; + bytes_read = 1; + } else if (stat == CON_HUP) { + hung_up = 1; + uart_handle_dcd_change(port, 0); + continue; + } else { + /* HV_EWOULDBLOCK, etc. */ + break; + } + } + + if (hung_up) { + hung_up = 0; + uart_handle_dcd_change(port, 1); + } + + for (i = 0; i < bytes_read; i++) + uart_handle_sysrq_char(port, con_read_page[i]); + + if (tty == NULL) + continue; + + port->icount.rx += bytes_read; + + tty_insert_flip_string(tty, con_read_page, bytes_read); + } + + return saw_console_brk; +} + +struct sunhv_ops { + void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit); + int (*receive_chars)(struct uart_port *port, struct tty_struct *tty); +}; + +static struct sunhv_ops bychar_ops = { + .transmit_chars = transmit_chars_putchar, + .receive_chars = receive_chars_getchar, +}; + +static struct sunhv_ops bywrite_ops = { + .transmit_chars = transmit_chars_write, + .receive_chars = receive_chars_read, +}; + +static struct sunhv_ops *sunhv_ops = &bychar_ops; + +static struct tty_struct *receive_chars(struct uart_port *port) +{ + struct tty_struct *tty = NULL; + + if (port->state != NULL) /* Unopened serial console */ + tty = port->state->port.tty; + + if (sunhv_ops->receive_chars(port, tty)) + sun_do_break(); + + return tty; +} + +static void transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit; + + if (!port->state) + return; + + xmit = &port->state->xmit; + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + sunhv_ops->transmit_chars(port, xmit); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t sunhv_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + tty = receive_chars(port); + transmit_chars(port); + spin_unlock_irqrestore(&port->lock, flags); + + if (tty) + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int sunhv_tx_empty(struct uart_port *port) +{ + /* Transmitter is always empty for us. If the circ buffer + * is non-empty or there is an x_char pending, our caller + * will do the right thing and ignore what we return here. + */ + return TIOCSER_TEMT; +} + +/* port->lock held by caller. */ +static void sunhv_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + return; +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int sunhv_get_mctrl(struct uart_port *port) +{ + return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; +} + +/* port->lock held by caller. */ +static void sunhv_stop_tx(struct uart_port *port) +{ + return; +} + +/* port->lock held by caller. */ +static void sunhv_start_tx(struct uart_port *port) +{ + transmit_chars(port); +} + +/* port->lock is not held. */ +static void sunhv_send_xchar(struct uart_port *port, char ch) +{ + unsigned long flags; + int limit = 10000; + + spin_lock_irqsave(&port->lock, flags); + + while (limit-- > 0) { + long status = sun4v_con_putchar(ch); + if (status == HV_EOK) + break; + udelay(1); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* port->lock held by caller. */ +static void sunhv_stop_rx(struct uart_port *port) +{ +} + +/* port->lock held by caller. */ +static void sunhv_enable_ms(struct uart_port *port) +{ +} + +/* port->lock is not held. */ +static void sunhv_break_ctl(struct uart_port *port, int break_state) +{ + if (break_state) { + unsigned long flags; + int limit = 10000; + + spin_lock_irqsave(&port->lock, flags); + + while (limit-- > 0) { + long status = sun4v_con_putchar(CON_BREAK); + if (status == HV_EOK) + break; + udelay(1); + } + + spin_unlock_irqrestore(&port->lock, flags); + } +} + +/* port->lock is not held. */ +static int sunhv_startup(struct uart_port *port) +{ + return 0; +} + +/* port->lock is not held. */ +static void sunhv_shutdown(struct uart_port *port) +{ +} + +/* port->lock is not held. */ +static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); + unsigned int iflag, cflag; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + iflag = termios->c_iflag; + cflag = termios->c_cflag; + + port->ignore_status_mask = 0; + if (iflag & IGNBRK) + port->ignore_status_mask |= IGNORE_BREAK; + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= IGNORE_ALL; + + /* XXX */ + uart_update_timeout(port, cflag, + (port->uartclk / (16 * quot))); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *sunhv_type(struct uart_port *port) +{ + return "SUN4V HCONS"; +} + +static void sunhv_release_port(struct uart_port *port) +{ +} + +static int sunhv_request_port(struct uart_port *port) +{ + return 0; +} + +static void sunhv_config_port(struct uart_port *port, int flags) +{ +} + +static int sunhv_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static struct uart_ops sunhv_pops = { + .tx_empty = sunhv_tx_empty, + .set_mctrl = sunhv_set_mctrl, + .get_mctrl = sunhv_get_mctrl, + .stop_tx = sunhv_stop_tx, + .start_tx = sunhv_start_tx, + .send_xchar = sunhv_send_xchar, + .stop_rx = sunhv_stop_rx, + .enable_ms = sunhv_enable_ms, + .break_ctl = sunhv_break_ctl, + .startup = sunhv_startup, + .shutdown = sunhv_shutdown, + .set_termios = sunhv_set_termios, + .type = sunhv_type, + .release_port = sunhv_release_port, + .request_port = sunhv_request_port, + .config_port = sunhv_config_port, + .verify_port = sunhv_verify_port, +}; + +static struct uart_driver sunhv_reg = { + .owner = THIS_MODULE, + .driver_name = "sunhv", + .dev_name = "ttyS", + .major = TTY_MAJOR, +}; + +static struct uart_port *sunhv_port; + +/* Copy 's' into the con_write_page, decoding "\n" into + * "\r\n" along the way. We have to return two lengths + * because the caller needs to know how much to advance + * 's' and also how many bytes to output via con_write_page. + */ +static int fill_con_write_page(const char *s, unsigned int n, + unsigned long *page_bytes) +{ + const char *orig_s = s; + char *p = con_write_page; + int left = PAGE_SIZE; + + while (n--) { + if (*s == '\n') { + if (left < 2) + break; + *p++ = '\r'; + left--; + } else if (left < 1) + break; + *p++ = *s++; + left--; + } + *page_bytes = p - con_write_page; + return s - orig_s; +} + +static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n) +{ + struct uart_port *port = sunhv_port; + unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else + spin_lock(&port->lock); + + while (n > 0) { + unsigned long ra = __pa(con_write_page); + unsigned long page_bytes; + unsigned int cpy = fill_con_write_page(s, n, + &page_bytes); + + n -= cpy; + s += cpy; + while (page_bytes > 0) { + unsigned long written; + int limit = 1000000; + + while (limit--) { + unsigned long stat; + + stat = sun4v_con_write(ra, page_bytes, + &written); + if (stat == HV_EOK) + break; + udelay(1); + } + if (limit < 0) + break; + page_bytes -= written; + ra += written; + } + } + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +static inline void sunhv_console_putchar(struct uart_port *port, char c) +{ + int limit = 1000000; + + while (limit-- > 0) { + long status = sun4v_con_putchar(c); + if (status == HV_EOK) + break; + udelay(1); + } +} + +static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n) +{ + struct uart_port *port = sunhv_port; + unsigned long flags; + int i, locked = 1; + + local_irq_save(flags); + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else + spin_lock(&port->lock); + + for (i = 0; i < n; i++) { + if (*s == '\n') + sunhv_console_putchar(port, '\r'); + sunhv_console_putchar(port, *s++); + } + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +static struct console sunhv_console = { + .name = "ttyHV", + .write = sunhv_console_write_bychar, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sunhv_reg, +}; + +static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match) +{ + struct uart_port *port; + unsigned long minor; + int err; + + if (op->archdata.irqs[0] == 0xffffffff) + return -ENODEV; + + port = kzalloc(sizeof(struct uart_port), GFP_KERNEL); + if (unlikely(!port)) + return -ENOMEM; + + minor = 1; + if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 && + minor >= 1) { + err = -ENOMEM; + con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!con_write_page) + goto out_free_port; + + con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!con_read_page) + goto out_free_con_write_page; + + sunhv_console.write = sunhv_console_write_paged; + sunhv_ops = &bywrite_ops; + } + + sunhv_port = port; + + port->line = 0; + port->ops = &sunhv_pops; + port->type = PORT_SUNHV; + port->uartclk = ( 29491200 / 16 ); /* arbitrary */ + + port->membase = (unsigned char __iomem *) __pa(port); + + port->irq = op->archdata.irqs[0]; + + port->dev = &op->dev; + + err = sunserial_register_minors(&sunhv_reg, 1); + if (err) + goto out_free_con_read_page; + + sunserial_console_match(&sunhv_console, op->dev.of_node, + &sunhv_reg, port->line, false); + + err = uart_add_one_port(&sunhv_reg, port); + if (err) + goto out_unregister_driver; + + err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port); + if (err) + goto out_remove_port; + + dev_set_drvdata(&op->dev, port); + + return 0; + +out_remove_port: + uart_remove_one_port(&sunhv_reg, port); + +out_unregister_driver: + sunserial_unregister_minors(&sunhv_reg, 1); + +out_free_con_read_page: + kfree(con_read_page); + +out_free_con_write_page: + kfree(con_write_page); + +out_free_port: + kfree(port); + sunhv_port = NULL; + return err; +} + +static int __devexit hv_remove(struct platform_device *dev) +{ + struct uart_port *port = dev_get_drvdata(&dev->dev); + + free_irq(port->irq, port); + + uart_remove_one_port(&sunhv_reg, port); + + sunserial_unregister_minors(&sunhv_reg, 1); + + kfree(port); + sunhv_port = NULL; + + dev_set_drvdata(&dev->dev, NULL); + + return 0; +} + +static const struct of_device_id hv_match[] = { + { + .name = "console", + .compatible = "qcn", + }, + { + .name = "console", + .compatible = "SUNW,sun4v-console", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, hv_match); + +static struct of_platform_driver hv_driver = { + .driver = { + .name = "hv", + .owner = THIS_MODULE, + .of_match_table = hv_match, + }, + .probe = hv_probe, + .remove = __devexit_p(hv_remove), +}; + +static int __init sunhv_init(void) +{ + if (tlb_type != hypervisor) + return -ENODEV; + + return of_register_platform_driver(&hv_driver); +} + +static void __exit sunhv_exit(void) +{ + of_unregister_platform_driver(&hv_driver); +} + +module_init(sunhv_init); +module_exit(sunhv_exit); + +MODULE_AUTHOR("David S. Miller"); +MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); +MODULE_VERSION("2.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c new file mode 100644 index 000000000000..5b246b18f42f --- /dev/null +++ b/drivers/tty/serial/sunsab.c @@ -0,0 +1,1152 @@ +/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) + * + * Rewrote buffer handling to use CIRC(Circular Buffer) macros. + * Maxim Krasnyanskiy + * + * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud + * rates to be programmed into the UART. Also eliminated a lot of + * duplicated code in the console setup. + * Theodore Ts'o , 2001-Oct-12 + * + * Ported to new 2.5.x UART layer. + * David S. Miller + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include "suncore.h" +#include "sunsab.h" + +struct uart_sunsab_port { + struct uart_port port; /* Generic UART port */ + union sab82532_async_regs __iomem *regs; /* Chip registers */ + unsigned long irqflags; /* IRQ state flags */ + int dsr; /* Current DSR state */ + unsigned int cec_timeout; /* Chip poll timeout... */ + unsigned int tec_timeout; /* likewise */ + unsigned char interrupt_mask0;/* ISR0 masking */ + unsigned char interrupt_mask1;/* ISR1 masking */ + unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ + unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ + unsigned int gis_shift; + int type; /* SAB82532 version */ + + /* Setting configuration bits while the transmitter is active + * can cause garbage characters to get emitted by the chip. + * Therefore, we cache such writes here and do the real register + * write the next time the transmitter becomes idle. + */ + unsigned int cached_ebrg; + unsigned char cached_mode; + unsigned char cached_pvr; + unsigned char cached_dafo; +}; + +/* + * This assumes you have a 29.4912 MHz clock for your UART. + */ +#define SAB_BASE_BAUD ( 29491200 / 16 ) + +static char *sab82532_version[16] = { + "V1.0", "V2.0", "V3.2", "V(0x03)", + "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)", + "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)", + "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)" +}; + +#define SAB82532_MAX_TEC_TIMEOUT 200000 /* 1 character time (at 50 baud) */ +#define SAB82532_MAX_CEC_TIMEOUT 50000 /* 2.5 TX CLKs (at 50 baud) */ + +#define SAB82532_RECV_FIFO_SIZE 32 /* Standard async fifo sizes */ +#define SAB82532_XMIT_FIFO_SIZE 32 + +static __inline__ void sunsab_tec_wait(struct uart_sunsab_port *up) +{ + int timeout = up->tec_timeout; + + while ((readb(&up->regs->r.star) & SAB82532_STAR_TEC) && --timeout) + udelay(1); +} + +static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up) +{ + int timeout = up->cec_timeout; + + while ((readb(&up->regs->r.star) & SAB82532_STAR_CEC) && --timeout) + udelay(1); +} + +static struct tty_struct * +receive_chars(struct uart_sunsab_port *up, + union sab82532_irq_status *stat) +{ + struct tty_struct *tty = NULL; + unsigned char buf[32]; + int saw_console_brk = 0; + int free_fifo = 0; + int count = 0; + int i; + + if (up->port.state != NULL) /* Unopened serial console */ + tty = up->port.state->port.tty; + + /* Read number of BYTES (Character + Status) available. */ + if (stat->sreg.isr0 & SAB82532_ISR0_RPF) { + count = SAB82532_RECV_FIFO_SIZE; + free_fifo++; + } + + if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { + count = readb(&up->regs->r.rbcl) & (SAB82532_RECV_FIFO_SIZE - 1); + free_fifo++; + } + + /* Issue a FIFO read command in case we where idle. */ + if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { + sunsab_cec_wait(up); + writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr); + return tty; + } + + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) + free_fifo++; + + /* Read the FIFO. */ + for (i = 0; i < count; i++) + buf[i] = readb(&up->regs->r.rfifo[i]); + + /* Issue Receive Message Complete command. */ + if (free_fifo) { + sunsab_cec_wait(up); + writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr); + } + + /* Count may be zero for BRK, so we check for it here */ + if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) && + (up->port.line == up->port.cons->index)) + saw_console_brk = 1; + + for (i = 0; i < count; i++) { + unsigned char ch = buf[i], flag; + + if (tty == NULL) { + uart_handle_sysrq_char(&up->port, ch); + continue; + } + + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(stat->sreg.isr0 & (SAB82532_ISR0_PERR | + SAB82532_ISR0_FERR | + SAB82532_ISR0_RFO)) || + unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) { + /* + * For statistics only + */ + if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { + stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR | + SAB82532_ISR0_FERR); + 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)) + continue; + } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR) + up->port.icount.parity++; + else if (stat->sreg.isr0 & SAB82532_ISR0_FERR) + up->port.icount.frame++; + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) + up->port.icount.overrun++; + + /* + * Mask off conditions which should be ingored. + */ + stat->sreg.isr0 &= (up->port.read_status_mask & 0xff); + stat->sreg.isr1 &= ((up->port.read_status_mask >> 8) & 0xff); + + if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { + flag = TTY_BREAK; + } else if (stat->sreg.isr0 & SAB82532_ISR0_PERR) + flag = TTY_PARITY; + else if (stat->sreg.isr0 & SAB82532_ISR0_FERR) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + + if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 && + (stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0) + tty_insert_flip_char(tty, ch, flag); + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + if (saw_console_brk) + sun_do_break(); + + return tty; +} + +static void sunsab_stop_tx(struct uart_port *); +static void sunsab_tx_idle(struct uart_sunsab_port *); + +static void transmit_chars(struct uart_sunsab_port *up, + union sab82532_irq_status *stat) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int i; + + if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) { + up->interrupt_mask1 |= SAB82532_IMR1_ALLS; + writeb(up->interrupt_mask1, &up->regs->w.imr1); + set_bit(SAB82532_ALLS, &up->irqflags); + } + +#if 0 /* bde@nwlink.com says this check causes problems */ + if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR)) + return; +#endif + + if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW)) + return; + + set_bit(SAB82532_XPR, &up->irqflags); + sunsab_tx_idle(up); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + up->interrupt_mask1 |= SAB82532_IMR1_XPR; + writeb(up->interrupt_mask1, &up->regs->w.imr1); + return; + } + + up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); + writeb(up->interrupt_mask1, &up->regs->w.imr1); + clear_bit(SAB82532_ALLS, &up->irqflags); + + /* Stuff 32 bytes into Transmit FIFO. */ + clear_bit(SAB82532_XPR, &up->irqflags); + for (i = 0; i < up->port.fifosize; i++) { + writeb(xmit->buf[xmit->tail], + &up->regs->w.xfifo[i]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + /* Issue a Transmit Frame command. */ + sunsab_cec_wait(up); + writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) + sunsab_stop_tx(&up->port); +} + +static void check_status(struct uart_sunsab_port *up, + union sab82532_irq_status *stat) +{ + if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) + uart_handle_dcd_change(&up->port, + !(readb(&up->regs->r.vstr) & SAB82532_VSTR_CD)); + + if (stat->sreg.isr1 & SAB82532_ISR1_CSC) + uart_handle_cts_change(&up->port, + (readb(&up->regs->r.star) & SAB82532_STAR_CTS)); + + if ((readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ^ up->dsr) { + up->dsr = (readb(&up->regs->r.pvr) & up->pvr_dsr_bit) ? 0 : 1; + up->port.icount.dsr++; + } + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); +} + +static irqreturn_t sunsab_interrupt(int irq, void *dev_id) +{ + struct uart_sunsab_port *up = dev_id; + struct tty_struct *tty; + union sab82532_irq_status status; + unsigned long flags; + unsigned char gis; + + spin_lock_irqsave(&up->port.lock, flags); + + status.stat = 0; + gis = readb(&up->regs->r.gis) >> up->gis_shift; + if (gis & 1) + status.sreg.isr0 = readb(&up->regs->r.isr0); + if (gis & 2) + status.sreg.isr1 = readb(&up->regs->r.isr1); + + tty = NULL; + if (status.stat) { + if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | + SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || + (status.sreg.isr1 & SAB82532_ISR1_BRK)) + tty = receive_chars(up, &status); + if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || + (status.sreg.isr1 & SAB82532_ISR1_CSC)) + check_status(up, &status); + if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR)) + transmit_chars(up, &status); + } + + spin_unlock_irqrestore(&up->port.lock, flags); + + if (tty) + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int sunsab_tx_empty(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + int ret; + + /* Do not need a lock for a state test like this. */ + if (test_bit(SAB82532_ALLS, &up->irqflags)) + ret = TIOCSER_TEMT; + else + ret = 0; + + return ret; +} + +/* port->lock held by caller. */ +static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + + if (mctrl & TIOCM_RTS) { + up->cached_mode &= ~SAB82532_MODE_FRTS; + up->cached_mode |= SAB82532_MODE_RTS; + } else { + up->cached_mode |= (SAB82532_MODE_FRTS | + SAB82532_MODE_RTS); + } + if (mctrl & TIOCM_DTR) { + up->cached_pvr &= ~(up->pvr_dtr_bit); + } else { + up->cached_pvr |= up->pvr_dtr_bit; + } + + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int sunsab_get_mctrl(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + unsigned char val; + unsigned int result; + + result = 0; + + val = readb(&up->regs->r.pvr); + result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR; + + val = readb(&up->regs->r.vstr); + result |= (val & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR; + + val = readb(&up->regs->r.star); + result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0; + + return result; +} + +/* port->lock held by caller. */ +static void sunsab_stop_tx(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + + up->interrupt_mask1 |= SAB82532_IMR1_XPR; + writeb(up->interrupt_mask1, &up->regs->w.imr1); +} + +/* port->lock held by caller. */ +static void sunsab_tx_idle(struct uart_sunsab_port *up) +{ + if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) { + u8 tmp; + + clear_bit(SAB82532_REGS_PENDING, &up->irqflags); + writeb(up->cached_mode, &up->regs->rw.mode); + writeb(up->cached_pvr, &up->regs->rw.pvr); + writeb(up->cached_dafo, &up->regs->w.dafo); + + writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr); + tmp = readb(&up->regs->rw.ccr2); + tmp &= ~0xc0; + tmp |= (up->cached_ebrg >> 2) & 0xc0; + writeb(tmp, &up->regs->rw.ccr2); + } +} + +/* port->lock held by caller. */ +static void sunsab_start_tx(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + struct circ_buf *xmit = &up->port.state->xmit; + int i; + + up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); + writeb(up->interrupt_mask1, &up->regs->w.imr1); + + if (!test_bit(SAB82532_XPR, &up->irqflags)) + return; + + clear_bit(SAB82532_ALLS, &up->irqflags); + clear_bit(SAB82532_XPR, &up->irqflags); + + for (i = 0; i < up->port.fifosize; i++) { + writeb(xmit->buf[xmit->tail], + &up->regs->w.xfifo[i]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + /* Issue a Transmit Frame command. */ + sunsab_cec_wait(up); + writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); +} + +/* port->lock is not held. */ +static void sunsab_send_xchar(struct uart_port *port, char ch) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + + sunsab_tec_wait(up); + writeb(ch, &up->regs->w.tic); + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +/* port->lock held by caller. */ +static void sunsab_stop_rx(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + + up->interrupt_mask0 |= SAB82532_IMR0_TCD; + writeb(up->interrupt_mask1, &up->regs->w.imr0); +} + +/* port->lock held by caller. */ +static void sunsab_enable_ms(struct uart_port *port) +{ + /* For now we always receive these interrupts. */ +} + +/* port->lock is not held. */ +static void sunsab_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&up->port.lock, flags); + + val = up->cached_dafo; + if (break_state) + val |= SAB82532_DAFO_XBRK; + else + val &= ~SAB82532_DAFO_XBRK; + up->cached_dafo = val; + + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +/* port->lock is not held. */ +static int sunsab_startup(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + unsigned long flags; + unsigned char tmp; + int err = request_irq(up->port.irq, sunsab_interrupt, + IRQF_SHARED, "sab", up); + if (err) + return err; + + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Wait for any commands or immediate characters + */ + sunsab_cec_wait(up); + sunsab_tec_wait(up); + + /* + * Clear the FIFO buffers. + */ + writeb(SAB82532_CMDR_RRES, &up->regs->w.cmdr); + sunsab_cec_wait(up); + writeb(SAB82532_CMDR_XRES, &up->regs->w.cmdr); + + /* + * Clear the interrupt registers. + */ + (void) readb(&up->regs->r.isr0); + (void) readb(&up->regs->r.isr1); + + /* + * Now, initialize the UART + */ + writeb(0, &up->regs->w.ccr0); /* power-down */ + writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | + SAB82532_CCR0_SM_ASYNC, &up->regs->w.ccr0); + writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &up->regs->w.ccr1); + writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | + SAB82532_CCR2_TOE, &up->regs->w.ccr2); + writeb(0, &up->regs->w.ccr3); + writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); + up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS | + SAB82532_MODE_RAC); + writeb(up->cached_mode, &up->regs->w.mode); + writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); + + tmp = readb(&up->regs->rw.ccr0); + tmp |= SAB82532_CCR0_PU; /* power-up */ + writeb(tmp, &up->regs->rw.ccr0); + + /* + * Finally, enable interrupts + */ + up->interrupt_mask0 = (SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA); + writeb(up->interrupt_mask0, &up->regs->w.imr0); + up->interrupt_mask1 = (SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR); + writeb(up->interrupt_mask1, &up->regs->w.imr1); + set_bit(SAB82532_ALLS, &up->irqflags); + set_bit(SAB82532_XPR, &up->irqflags); + + spin_unlock_irqrestore(&up->port.lock, flags); + + return 0; +} + +/* port->lock is not held. */ +static void sunsab_shutdown(struct uart_port *port) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + + /* Disable Interrupts */ + up->interrupt_mask0 = 0xff; + writeb(up->interrupt_mask0, &up->regs->w.imr0); + up->interrupt_mask1 = 0xff; + writeb(up->interrupt_mask1, &up->regs->w.imr1); + + /* Disable break condition */ + up->cached_dafo = readb(&up->regs->rw.dafo); + up->cached_dafo &= ~SAB82532_DAFO_XBRK; + writeb(up->cached_dafo, &up->regs->rw.dafo); + + /* Disable Receiver */ + up->cached_mode &= ~SAB82532_MODE_RAC; + writeb(up->cached_mode, &up->regs->rw.mode); + + /* + * XXX FIXME + * + * If the chip is powered down here the system hangs/crashes during + * reboot or shutdown. This needs to be investigated further, + * similar behaviour occurs in 2.4 when the driver is configured + * as a module only. One hint may be that data is sometimes + * transmitted at 9600 baud during shutdown (regardless of the + * speed the chip was configured for when the port was open). + */ +#if 0 + /* Power Down */ + tmp = readb(&up->regs->rw.ccr0); + tmp &= ~SAB82532_CCR0_PU; + writeb(tmp, &up->regs->rw.ccr0); +#endif + + spin_unlock_irqrestore(&up->port.lock, flags); + free_irq(up->port.irq, up); +} + +/* + * This is used to figure out the divisor speeds. + * + * The formula is: Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)), + * + * with 0 <= N < 64 and 0 <= M < 16 + */ + +static void calc_ebrg(int baud, int *n_ret, int *m_ret) +{ + int n, m; + + if (baud == 0) { + *n_ret = 0; + *m_ret = 0; + return; + } + + /* + * We scale numbers by 10 so that we get better accuracy + * without having to use floating point. Here we increment m + * until n is within the valid range. + */ + n = (SAB_BASE_BAUD * 10) / baud; + m = 0; + while (n >= 640) { + n = n / 2; + m++; + } + n = (n+5) / 10; + /* + * We try very hard to avoid speeds with M == 0 since they may + * not work correctly for XTAL frequences above 10 MHz. + */ + if ((m == 0) && ((n & 1) == 0)) { + n = n / 2; + m++; + } + *n_ret = n - 1; + *m_ret = m; +} + +/* Internal routine, port->lock is held and local interrupts are disabled. */ +static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cflag, + unsigned int iflag, unsigned int baud, + unsigned int quot) +{ + unsigned char dafo; + int bits, n, m; + + /* Byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + } + + if (cflag & CSTOPB) { + dafo |= SAB82532_DAFO_STOP; + bits++; + } + + if (cflag & PARENB) { + dafo |= SAB82532_DAFO_PARE; + bits++; + } + + if (cflag & PARODD) { + dafo |= SAB82532_DAFO_PAR_ODD; + } else { + dafo |= SAB82532_DAFO_PAR_EVEN; + } + up->cached_dafo = dafo; + + calc_ebrg(baud, &n, &m); + + up->cached_ebrg = n | (m << 6); + + up->tec_timeout = (10 * 1000000) / baud; + up->cec_timeout = up->tec_timeout >> 2; + + /* CTS flow control flags */ + /* We encode read_status_mask and ignore_status_mask like so: + * + * --------------------- + * | ... | ISR1 | ISR0 | + * --------------------- + * .. 15 8 7 0 + */ + + up->port.read_status_mask = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | + SAB82532_ISR0_RFO | SAB82532_ISR0_RPF | + SAB82532_ISR0_CDSC); + up->port.read_status_mask |= (SAB82532_ISR1_CSC | + SAB82532_ISR1_ALLS | + SAB82532_ISR1_XPR) << 8; + if (iflag & INPCK) + up->port.read_status_mask |= (SAB82532_ISR0_PERR | + SAB82532_ISR0_FERR); + if (iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8); + + /* + * Characteres to ignore + */ + up->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= (SAB82532_ISR0_PERR | + SAB82532_ISR0_FERR); + if (iflag & IGNBRK) { + up->port.ignore_status_mask |= (SAB82532_ISR1_BRK << 8); + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + up->port.ignore_status_mask |= SAB82532_ISR0_RFO; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + up->port.ignore_status_mask |= (SAB82532_ISR0_RPF | + SAB82532_ISR0_TCD); + + uart_update_timeout(&up->port, cflag, + (up->port.uartclk / (16 * quot))); + + /* Now schedule a register update when the chip's + * transmitter is idle. + */ + up->cached_mode |= SAB82532_MODE_RAC; + set_bit(SAB82532_REGS_PENDING, &up->irqflags); + if (test_bit(SAB82532_XPR, &up->irqflags)) + sunsab_tx_idle(up); +} + +/* port->lock is not held. */ +static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; + unsigned long flags; + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); + + spin_lock_irqsave(&up->port.lock, flags); + sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static const char *sunsab_type(struct uart_port *port) +{ + struct uart_sunsab_port *up = (void *)port; + static char buf[36]; + + sprintf(buf, "SAB82532 %s", sab82532_version[up->type]); + return buf; +} + +static void sunsab_release_port(struct uart_port *port) +{ +} + +static int sunsab_request_port(struct uart_port *port) +{ + return 0; +} + +static void sunsab_config_port(struct uart_port *port, int flags) +{ +} + +static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static struct uart_ops sunsab_pops = { + .tx_empty = sunsab_tx_empty, + .set_mctrl = sunsab_set_mctrl, + .get_mctrl = sunsab_get_mctrl, + .stop_tx = sunsab_stop_tx, + .start_tx = sunsab_start_tx, + .send_xchar = sunsab_send_xchar, + .stop_rx = sunsab_stop_rx, + .enable_ms = sunsab_enable_ms, + .break_ctl = sunsab_break_ctl, + .startup = sunsab_startup, + .shutdown = sunsab_shutdown, + .set_termios = sunsab_set_termios, + .type = sunsab_type, + .release_port = sunsab_release_port, + .request_port = sunsab_request_port, + .config_port = sunsab_config_port, + .verify_port = sunsab_verify_port, +}; + +static struct uart_driver sunsab_reg = { + .owner = THIS_MODULE, + .driver_name = "sunsab", + .dev_name = "ttyS", + .major = TTY_MAJOR, +}; + +static struct uart_sunsab_port *sunsab_ports; + +#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE + +static void sunsab_console_putchar(struct uart_port *port, int c) +{ + struct uart_sunsab_port *up = (struct uart_sunsab_port *)port; + + sunsab_tec_wait(up); + writeb(c, &up->regs->w.tic); +} + +static void sunsab_console_write(struct console *con, const char *s, unsigned n) +{ + struct uart_sunsab_port *up = &sunsab_ports[con->index]; + unsigned long flags; + int locked = 1; + + 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, n, sunsab_console_putchar); + sunsab_tec_wait(up); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int sunsab_console_setup(struct console *con, char *options) +{ + struct uart_sunsab_port *up = &sunsab_ports[con->index]; + unsigned long flags; + unsigned int baud, quot; + + /* + * The console framework calls us for each and every port + * registered. Defer the console setup until the requested + * port has been properly discovered. A bit of a hack, + * though... + */ + if (up->port.type != PORT_SUNSAB) + return -1; + + printk("Console: ttyS%d (SAB82532)\n", + (sunsab_reg.minor - 64) + con->index); + + sunserial_console_termios(con, up->port.dev->of_node); + + switch (con->cflag & CBAUD) { + case B150: baud = 150; break; + case B300: baud = 300; break; + case B600: baud = 600; break; + case B1200: baud = 1200; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + default: case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + case B230400: baud = 230400; break; + case B460800: baud = 460800; break; + }; + + /* + * Temporary fix. + */ + spin_lock_init(&up->port.lock); + + /* + * Initialize the hardware + */ + sunsab_startup(&up->port); + + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Finally, enable interrupts + */ + up->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + writeb(up->interrupt_mask0, &up->regs->w.imr0); + up->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + writeb(up->interrupt_mask1, &up->regs->w.imr1); + + quot = uart_get_divisor(&up->port, baud); + sunsab_convert_to_sab(up, con->cflag, 0, baud, quot); + sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + + spin_unlock_irqrestore(&up->port.lock, flags); + + return 0; +} + +static struct console sunsab_console = { + .name = "ttyS", + .write = sunsab_console_write, + .device = uart_console_device, + .setup = sunsab_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sunsab_reg, +}; + +static inline struct console *SUNSAB_CONSOLE(void) +{ + return &sunsab_console; +} +#else +#define SUNSAB_CONSOLE() (NULL) +#define sunsab_console_init() do { } while (0) +#endif + +static int __devinit sunsab_init_one(struct uart_sunsab_port *up, + struct platform_device *op, + unsigned long offset, + int line) +{ + up->port.line = line; + up->port.dev = &op->dev; + + up->port.mapbase = op->resource[0].start + offset; + up->port.membase = of_ioremap(&op->resource[0], offset, + sizeof(union sab82532_async_regs), + "sab"); + if (!up->port.membase) + return -ENOMEM; + up->regs = (union sab82532_async_regs __iomem *) up->port.membase; + + up->port.irq = op->archdata.irqs[0]; + + up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; + up->port.iotype = UPIO_MEM; + + writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); + + up->port.ops = &sunsab_pops; + up->port.type = PORT_SUNSAB; + up->port.uartclk = SAB_BASE_BAUD; + + up->type = readb(&up->regs->r.vstr) & 0x0f; + writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); + writeb(0xff, &up->regs->w.pim); + if ((up->port.line & 0x1) == 0) { + up->pvr_dsr_bit = (1 << 0); + up->pvr_dtr_bit = (1 << 1); + up->gis_shift = 2; + } else { + up->pvr_dsr_bit = (1 << 3); + up->pvr_dtr_bit = (1 << 2); + up->gis_shift = 0; + } + up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); + writeb(up->cached_pvr, &up->regs->w.pvr); + up->cached_mode = readb(&up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_FRTS; + writeb(up->cached_mode, &up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_RTS; + writeb(up->cached_mode, &up->regs->rw.mode); + + up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; + + return 0; +} + +static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match) +{ + static int inst; + struct uart_sunsab_port *up; + int err; + + up = &sunsab_ports[inst * 2]; + + err = sunsab_init_one(&up[0], op, + 0, + (inst * 2) + 0); + if (err) + goto out; + + err = sunsab_init_one(&up[1], op, + sizeof(union sab82532_async_regs), + (inst * 2) + 1); + if (err) + goto out1; + + sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node, + &sunsab_reg, up[0].port.line, + false); + + sunserial_console_match(SUNSAB_CONSOLE(), op->dev.of_node, + &sunsab_reg, up[1].port.line, + false); + + err = uart_add_one_port(&sunsab_reg, &up[0].port); + if (err) + goto out2; + + err = uart_add_one_port(&sunsab_reg, &up[1].port); + if (err) + goto out3; + + dev_set_drvdata(&op->dev, &up[0]); + + inst++; + + return 0; + +out3: + uart_remove_one_port(&sunsab_reg, &up[0].port); +out2: + of_iounmap(&op->resource[0], + up[1].port.membase, + sizeof(union sab82532_async_regs)); +out1: + of_iounmap(&op->resource[0], + up[0].port.membase, + sizeof(union sab82532_async_regs)); +out: + return err; +} + +static int __devexit sab_remove(struct platform_device *op) +{ + struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); + + uart_remove_one_port(&sunsab_reg, &up[1].port); + uart_remove_one_port(&sunsab_reg, &up[0].port); + of_iounmap(&op->resource[0], + up[1].port.membase, + sizeof(union sab82532_async_regs)); + of_iounmap(&op->resource[0], + up[0].port.membase, + sizeof(union sab82532_async_regs)); + + dev_set_drvdata(&op->dev, NULL); + + return 0; +} + +static const struct of_device_id sab_match[] = { + { + .name = "se", + }, + { + .name = "serial", + .compatible = "sab82532", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, sab_match); + +static struct of_platform_driver sab_driver = { + .driver = { + .name = "sab", + .owner = THIS_MODULE, + .of_match_table = sab_match, + }, + .probe = sab_probe, + .remove = __devexit_p(sab_remove), +}; + +static int __init sunsab_init(void) +{ + struct device_node *dp; + int err; + int num_channels = 0; + + for_each_node_by_name(dp, "se") + num_channels += 2; + for_each_node_by_name(dp, "serial") { + if (of_device_is_compatible(dp, "sab82532")) + num_channels += 2; + } + + if (num_channels) { + sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) * + num_channels, GFP_KERNEL); + if (!sunsab_ports) + return -ENOMEM; + + err = sunserial_register_minors(&sunsab_reg, num_channels); + if (err) { + kfree(sunsab_ports); + sunsab_ports = NULL; + + return err; + } + } + + return of_register_platform_driver(&sab_driver); +} + +static void __exit sunsab_exit(void) +{ + of_unregister_platform_driver(&sab_driver); + if (sunsab_reg.nr) { + sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); + } + + kfree(sunsab_ports); + sunsab_ports = NULL; +} + +module_init(sunsab_init); +module_exit(sunsab_exit); + +MODULE_AUTHOR("Eddie C. Dost and David S. Miller"); +MODULE_DESCRIPTION("Sun SAB82532 serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/sunsab.h b/drivers/tty/serial/sunsab.h new file mode 100644 index 000000000000..b78e1f7b8050 --- /dev/null +++ b/drivers/tty/serial/sunsab.h @@ -0,0 +1,322 @@ +/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#ifndef _SUNSAB_H +#define _SUNSAB_H + +struct sab82532_async_rd_regs { + u8 rfifo[0x20]; /* Receive FIFO */ + u8 star; /* Status Register */ + u8 __pad1; + u8 mode; /* Mode Register */ + u8 timr; /* Timer Register */ + u8 xon; /* XON Character */ + u8 xoff; /* XOFF Character */ + u8 tcr; /* Termination Character Register */ + u8 dafo; /* Data Format */ + u8 rfc; /* RFIFO Control Register */ + u8 __pad2; + u8 rbcl; /* Receive Byte Count Low */ + u8 rbch; /* Receive Byte Count High */ + u8 ccr0; /* Channel Configuration Register 0 */ + u8 ccr1; /* Channel Configuration Register 1 */ + u8 ccr2; /* Channel Configuration Register 2 */ + u8 ccr3; /* Channel Configuration Register 3 */ + u8 __pad3[4]; + u8 vstr; /* Version Status Register */ + u8 __pad4[3]; + u8 gis; /* Global Interrupt Status */ + u8 ipc; /* Interrupt Port Configuration */ + u8 isr0; /* Interrupt Status 0 */ + u8 isr1; /* Interrupt Status 1 */ + u8 pvr; /* Port Value Register */ + u8 pis; /* Port Interrupt Status */ + u8 pcr; /* Port Configuration Register */ + u8 ccr4; /* Channel Configuration Register 4 */ +}; + +struct sab82532_async_wr_regs { + u8 xfifo[0x20]; /* Transmit FIFO */ + u8 cmdr; /* Command Register */ + u8 __pad1; + u8 mode; + u8 timr; + u8 xon; + u8 xoff; + u8 tcr; + u8 dafo; + u8 rfc; + u8 __pad2; + u8 xbcl; /* Transmit Byte Count Low */ + u8 xbch; /* Transmit Byte Count High */ + u8 ccr0; + u8 ccr1; + u8 ccr2; + u8 ccr3; + u8 tsax; /* Time-Slot Assignment Reg. Transmit */ + u8 tsar; /* Time-Slot Assignment Reg. Receive */ + u8 xccr; /* Transmit Channel Capacity Register */ + u8 rccr; /* Receive Channel Capacity Register */ + u8 bgr; /* Baud Rate Generator Register */ + u8 tic; /* Transmit Immediate Character */ + u8 mxn; /* Mask XON Character */ + u8 mxf; /* Mask XOFF Character */ + u8 iva; /* Interrupt Vector Address */ + u8 ipc; + u8 imr0; /* Interrupt Mask Register 0 */ + u8 imr1; /* Interrupt Mask Register 1 */ + u8 pvr; + u8 pim; /* Port Interrupt Mask */ + u8 pcr; + u8 ccr4; +}; + +struct sab82532_async_rw_regs { /* Read/Write registers */ + u8 __pad1[0x20]; + u8 __pad2; + u8 __pad3; + u8 mode; + u8 timr; + u8 xon; + u8 xoff; + u8 tcr; + u8 dafo; + u8 rfc; + u8 __pad4; + u8 __pad5; + u8 __pad6; + u8 ccr0; + u8 ccr1; + u8 ccr2; + u8 ccr3; + u8 __pad7; + u8 __pad8; + u8 __pad9; + u8 __pad10; + u8 __pad11; + u8 __pad12; + u8 __pad13; + u8 __pad14; + u8 __pad15; + u8 ipc; + u8 __pad16; + u8 __pad17; + u8 pvr; + u8 __pad18; + u8 pcr; + u8 ccr4; +}; + +union sab82532_async_regs { + __volatile__ struct sab82532_async_rd_regs r; + __volatile__ struct sab82532_async_wr_regs w; + __volatile__ struct sab82532_async_rw_regs rw; +}; + +union sab82532_irq_status { + unsigned short stat; + struct { + unsigned char isr0; + unsigned char isr1; + } sreg; +}; + +/* irqflags bits */ +#define SAB82532_ALLS 0x00000001 +#define SAB82532_XPR 0x00000002 +#define SAB82532_REGS_PENDING 0x00000004 + +/* RFIFO Status Byte */ +#define SAB82532_RSTAT_PE 0x80 +#define SAB82532_RSTAT_FE 0x40 +#define SAB82532_RSTAT_PARITY 0x01 + +/* Status Register (STAR) */ +#define SAB82532_STAR_XDOV 0x80 +#define SAB82532_STAR_XFW 0x40 +#define SAB82532_STAR_RFNE 0x20 +#define SAB82532_STAR_FCS 0x10 +#define SAB82532_STAR_TEC 0x08 +#define SAB82532_STAR_CEC 0x04 +#define SAB82532_STAR_CTS 0x02 + +/* Command Register (CMDR) */ +#define SAB82532_CMDR_RMC 0x80 +#define SAB82532_CMDR_RRES 0x40 +#define SAB82532_CMDR_RFRD 0x20 +#define SAB82532_CMDR_STI 0x10 +#define SAB82532_CMDR_XF 0x08 +#define SAB82532_CMDR_XRES 0x01 + +/* Mode Register (MODE) */ +#define SAB82532_MODE_FRTS 0x40 +#define SAB82532_MODE_FCTS 0x20 +#define SAB82532_MODE_FLON 0x10 +#define SAB82532_MODE_RAC 0x08 +#define SAB82532_MODE_RTS 0x04 +#define SAB82532_MODE_TRS 0x02 +#define SAB82532_MODE_TLP 0x01 + +/* Timer Register (TIMR) */ +#define SAB82532_TIMR_CNT_MASK 0xe0 +#define SAB82532_TIMR_VALUE_MASK 0x1f + +/* Data Format (DAFO) */ +#define SAB82532_DAFO_XBRK 0x40 +#define SAB82532_DAFO_STOP 0x20 +#define SAB82532_DAFO_PAR_SPACE 0x00 +#define SAB82532_DAFO_PAR_ODD 0x08 +#define SAB82532_DAFO_PAR_EVEN 0x10 +#define SAB82532_DAFO_PAR_MARK 0x18 +#define SAB82532_DAFO_PARE 0x04 +#define SAB82532_DAFO_CHL8 0x00 +#define SAB82532_DAFO_CHL7 0x01 +#define SAB82532_DAFO_CHL6 0x02 +#define SAB82532_DAFO_CHL5 0x03 + +/* RFIFO Control Register (RFC) */ +#define SAB82532_RFC_DPS 0x40 +#define SAB82532_RFC_DXS 0x20 +#define SAB82532_RFC_RFDF 0x10 +#define SAB82532_RFC_RFTH_1 0x00 +#define SAB82532_RFC_RFTH_4 0x04 +#define SAB82532_RFC_RFTH_16 0x08 +#define SAB82532_RFC_RFTH_32 0x0c +#define SAB82532_RFC_TCDE 0x01 + +/* Received Byte Count High (RBCH) */ +#define SAB82532_RBCH_DMA 0x80 +#define SAB82532_RBCH_CAS 0x20 + +/* Transmit Byte Count High (XBCH) */ +#define SAB82532_XBCH_DMA 0x80 +#define SAB82532_XBCH_CAS 0x20 +#define SAB82532_XBCH_XC 0x10 + +/* Channel Configuration Register 0 (CCR0) */ +#define SAB82532_CCR0_PU 0x80 +#define SAB82532_CCR0_MCE 0x40 +#define SAB82532_CCR0_SC_NRZ 0x00 +#define SAB82532_CCR0_SC_NRZI 0x08 +#define SAB82532_CCR0_SC_FM0 0x10 +#define SAB82532_CCR0_SC_FM1 0x14 +#define SAB82532_CCR0_SC_MANCH 0x18 +#define SAB82532_CCR0_SM_HDLC 0x00 +#define SAB82532_CCR0_SM_SDLC_LOOP 0x01 +#define SAB82532_CCR0_SM_BISYNC 0x02 +#define SAB82532_CCR0_SM_ASYNC 0x03 + +/* Channel Configuration Register 1 (CCR1) */ +#define SAB82532_CCR1_ODS 0x10 +#define SAB82532_CCR1_BCR 0x08 +#define SAB82532_CCR1_CM_MASK 0x07 + +/* Channel Configuration Register 2 (CCR2) */ +#define SAB82532_CCR2_SOC1 0x80 +#define SAB82532_CCR2_SOC0 0x40 +#define SAB82532_CCR2_BR9 0x80 +#define SAB82532_CCR2_BR8 0x40 +#define SAB82532_CCR2_BDF 0x20 +#define SAB82532_CCR2_SSEL 0x10 +#define SAB82532_CCR2_XCS0 0x20 +#define SAB82532_CCR2_RCS0 0x10 +#define SAB82532_CCR2_TOE 0x08 +#define SAB82532_CCR2_RWX 0x04 +#define SAB82532_CCR2_DIV 0x01 + +/* Channel Configuration Register 3 (CCR3) */ +#define SAB82532_CCR3_PSD 0x01 + +/* Time Slot Assignment Register Transmit (TSAX) */ +#define SAB82532_TSAX_TSNX_MASK 0xfc +#define SAB82532_TSAX_XCS2 0x02 /* see also CCR2 */ +#define SAB82532_TSAX_XCS1 0x01 + +/* Time Slot Assignment Register Receive (TSAR) */ +#define SAB82532_TSAR_TSNR_MASK 0xfc +#define SAB82532_TSAR_RCS2 0x02 /* see also CCR2 */ +#define SAB82532_TSAR_RCS1 0x01 + +/* Version Status Register (VSTR) */ +#define SAB82532_VSTR_CD 0x80 +#define SAB82532_VSTR_DPLA 0x40 +#define SAB82532_VSTR_VN_MASK 0x0f +#define SAB82532_VSTR_VN_1 0x00 +#define SAB82532_VSTR_VN_2 0x01 +#define SAB82532_VSTR_VN_3_2 0x02 + +/* Global Interrupt Status Register (GIS) */ +#define SAB82532_GIS_PI 0x80 +#define SAB82532_GIS_ISA1 0x08 +#define SAB82532_GIS_ISA0 0x04 +#define SAB82532_GIS_ISB1 0x02 +#define SAB82532_GIS_ISB0 0x01 + +/* Interrupt Vector Address (IVA) */ +#define SAB82532_IVA_MASK 0xf1 + +/* Interrupt Port Configuration (IPC) */ +#define SAB82532_IPC_VIS 0x80 +#define SAB82532_IPC_SLA1 0x10 +#define SAB82532_IPC_SLA0 0x08 +#define SAB82532_IPC_CASM 0x04 +#define SAB82532_IPC_IC_OPEN_DRAIN 0x00 +#define SAB82532_IPC_IC_ACT_LOW 0x01 +#define SAB82532_IPC_IC_ACT_HIGH 0x03 + +/* Interrupt Status Register 0 (ISR0) */ +#define SAB82532_ISR0_TCD 0x80 +#define SAB82532_ISR0_TIME 0x40 +#define SAB82532_ISR0_PERR 0x20 +#define SAB82532_ISR0_FERR 0x10 +#define SAB82532_ISR0_PLLA 0x08 +#define SAB82532_ISR0_CDSC 0x04 +#define SAB82532_ISR0_RFO 0x02 +#define SAB82532_ISR0_RPF 0x01 + +/* Interrupt Status Register 1 (ISR1) */ +#define SAB82532_ISR1_BRK 0x80 +#define SAB82532_ISR1_BRKT 0x40 +#define SAB82532_ISR1_ALLS 0x20 +#define SAB82532_ISR1_XOFF 0x10 +#define SAB82532_ISR1_TIN 0x08 +#define SAB82532_ISR1_CSC 0x04 +#define SAB82532_ISR1_XON 0x02 +#define SAB82532_ISR1_XPR 0x01 + +/* Interrupt Mask Register 0 (IMR0) */ +#define SAB82532_IMR0_TCD 0x80 +#define SAB82532_IMR0_TIME 0x40 +#define SAB82532_IMR0_PERR 0x20 +#define SAB82532_IMR0_FERR 0x10 +#define SAB82532_IMR0_PLLA 0x08 +#define SAB82532_IMR0_CDSC 0x04 +#define SAB82532_IMR0_RFO 0x02 +#define SAB82532_IMR0_RPF 0x01 + +/* Interrupt Mask Register 1 (IMR1) */ +#define SAB82532_IMR1_BRK 0x80 +#define SAB82532_IMR1_BRKT 0x40 +#define SAB82532_IMR1_ALLS 0x20 +#define SAB82532_IMR1_XOFF 0x10 +#define SAB82532_IMR1_TIN 0x08 +#define SAB82532_IMR1_CSC 0x04 +#define SAB82532_IMR1_XON 0x02 +#define SAB82532_IMR1_XPR 0x01 + +/* Port Interrupt Status Register (PIS) */ +#define SAB82532_PIS_SYNC_B 0x08 +#define SAB82532_PIS_DTR_B 0x04 +#define SAB82532_PIS_DTR_A 0x02 +#define SAB82532_PIS_SYNC_A 0x01 + +/* Channel Configuration Register 4 (CCR4) */ +#define SAB82532_CCR4_MCK4 0x80 +#define SAB82532_CCR4_EBRG 0x40 +#define SAB82532_CCR4_TST1 0x20 +#define SAB82532_CCR4_ICD 0x10 + + +#endif /* !(_SUNSAB_H) */ diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c new file mode 100644 index 000000000000..551ebfe3ccbb --- /dev/null +++ b/drivers/tty/serial/sunsu.c @@ -0,0 +1,1608 @@ +/* + * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998-1999 Pete Zaitcev (zaitcev@yahoo.com) + * + * This is mainly a variation of 8250.c, credits go to authors mentioned + * therein. In fact this driver should be merged into the generic 8250.c + * infrastructure perhaps using a 8250_sparc.c module. + * + * Fixed to use tty_get_baud_rate(). + * Theodore Ts'o , 2001-Oct-12 + * + * Converted to new 2.5.x UART layer. + * David S. Miller (davem@davemloft.net), 2002-Jul-29 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SERIO +#include +#endif +#include +#include +#include +#include + +#include +#include +#include + +#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include "suncore.h" + +/* We are on a NS PC87303 clocked with 24.0 MHz, which results + * in a UART clock of 1.8462 MHz. + */ +#define SU_BASE_BAUD (1846200 / 16) + +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)" }; + +/* + * 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] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "Cirrus", 1, 0 }, + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, + { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "Startech", 1, 0 }, + { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO } +}; + +struct uart_sunsu_port { + struct uart_port port; + unsigned char acr; + unsigned char ier; + unsigned short rev; + unsigned char lcr; + unsigned int lsr_break_flag; + unsigned int cflag; + + /* Probing information. */ + enum su_type su_type; + unsigned int type_probed; /* XXX Stupid */ + unsigned long reg_size; + +#ifdef CONFIG_SERIO + struct serio serio; + int serio_open; +#endif +}; + +static unsigned int serial_in(struct uart_sunsu_port *up, int offset) +{ + offset <<= up->port.regshift; + + switch (up->port.iotype) { + case UPIO_HUB6: + outb(up->port.hub6 - 1 + offset, up->port.iobase); + return inb(up->port.iobase + 1); + + case UPIO_MEM: + return readb(up->port.membase + offset); + + default: + return inb(up->port.iobase + offset); + } +} + +static void serial_out(struct uart_sunsu_port *up, int offset, int value) +{ +#ifndef CONFIG_SPARC64 + /* + * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are + * connected with a gate then go to SlavIO. When IRQ4 goes tristated + * gate outputs a logical one. Since we use level triggered interrupts + * we have lockup and watchdog reset. We cannot mask IRQ because + * keyboard shares IRQ with us (Word has it as Bob Smelik's design). + * This problem is similar to what Alpha people suffer, see serial.c. + */ + if (offset == UART_MCR) + value |= UART_MCR_OUT2; +#endif + offset <<= up->port.regshift; + + switch (up->port.iotype) { + case UPIO_HUB6: + outb(up->port.hub6 - 1 + offset, up->port.iobase); + outb(value, up->port.iobase + 1); + break; + + case UPIO_MEM: + writeb(value, up->port.membase + offset); + break; + + default: + outb(value, up->port.iobase + offset); + } +} + +/* + * We used to support using pause I/O for certain machines. We + * haven't supported this for a while, but just in case it's badly + * needed for certain old 386 machines, I've left these #define's + * in.... + */ +#define serial_inp(up, offset) serial_in(up, offset) +#define serial_outp(up, offset, value) serial_out(up, offset, value) + + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +#if 0 /* Unused currently */ +static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} +#endif + +#ifdef CONFIG_SERIAL_8250_RSA +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __enable_rsa(struct uart_sunsu_port *up) +{ + unsigned char mode; + int result; + + mode = serial_inp(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_inp(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +static void enable_rsa(struct uart_sunsu_port *up) +{ + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + __enable_rsa(up); + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_outp(up, UART_RSA_FRR, 0); + } +} + +/* + * Attempts to turn off the RSA FIFO. Returns zero on failure. + * It is unknown why interrupts were disabled in here. However, + * the caller is expected to preserve this behaviour by grabbing + * the spinlock before calling this function. + */ +static void disable_rsa(struct uart_sunsu_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; + spin_unlock_irq(&up->port.lock); + } +} +#endif /* CONFIG_SERIAL_8250_RSA */ + +static inline void __stop_tx(struct uart_sunsu_port *p) +{ + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + } +} + +static void sunsu_stop_tx(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + + __stop_tx(up); + + /* + * We really want to stop the transmitter from sending. + */ + if (up->port.type == PORT_16C950) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void sunsu_start_tx(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } + + /* + * Re-enable the transmitter if we disabled it. + */ + if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void sunsu_stop_rx(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); +} + +static void sunsu_enable_ms(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static struct tty_struct * +receive_chars(struct uart_sunsu_port *up, unsigned char *status) +{ + struct tty_struct *tty = up->port.state->port.tty; + unsigned char ch, flag; + int max_count = 256; + int saw_console_brk = 0; + + do { + ch = serial_inp(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + if (up->port.cons != NULL && + up->port.line == up->port.cons->index) + saw_console_brk = 1; + /* + * 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 (*status & UART_LSR_PE) + up->port.icount.parity++; + else if (*status & UART_LSR_FE) + up->port.icount.frame++; + if (*status & UART_LSR_OE) + up->port.icount.overrun++; + + /* + * Mask off conditions which should be ingored. + */ + *status &= up->port.read_status_mask; + + if (up->port.cons != NULL && + up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + *status |= up->lsr_break_flag; + up->lsr_break_flag = 0; + } + + if (*status & UART_LSR_BI) { + flag = TTY_BREAK; + } else if (*status & UART_LSR_PE) + flag = TTY_PARITY; + else if (*status & UART_LSR_FE) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + if ((*status & up->port.ignore_status_mask) == 0) + tty_insert_flip_char(tty, ch, flag); + if (*status & UART_LSR_OE) + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character. + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + ignore_char: + *status = serial_inp(up, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); + + if (saw_console_brk) + sun_do_break(); + + return tty; +} + +static void transmit_chars(struct uart_sunsu_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (up->port.x_char) { + serial_outp(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_tx_stopped(&up->port)) { + sunsu_stop_tx(&up->port); + return; + } + if (uart_circ_empty(xmit)) { + __stop_tx(up); + return; + } + + count = up->port.fifosize; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (uart_circ_empty(xmit)) + __stop_tx(up); +} + +static void check_modem_status(struct uart_sunsu_port *up) +{ + int status; + + status = serial_in(up, UART_MSR); + + if ((status & UART_MSR_ANY_DELTA) == 0) + return; + + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); +} + +static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) +{ + struct uart_sunsu_port *up = dev_id; + unsigned long flags; + unsigned char status; + + spin_lock_irqsave(&up->port.lock, flags); + + do { + struct tty_struct *tty; + + status = serial_inp(up, UART_LSR); + tty = NULL; + if (status & UART_LSR_DR) + tty = receive_chars(up, &status); + check_modem_status(up); + if (status & UART_LSR_THRE) + transmit_chars(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + + if (tty) + tty_flip_buffer_push(tty); + + spin_lock_irqsave(&up->port.lock, flags); + + } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); + + spin_unlock_irqrestore(&up->port.lock, flags); + + return IRQ_HANDLED; +} + +/* Separate interrupt handling path for keyboard/mouse ports. */ + +static void +sunsu_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot); + +static void sunsu_change_mouse_baud(struct uart_sunsu_port *up) +{ + unsigned int cur_cflag = up->cflag; + int quot, new_baud; + + up->cflag &= ~CBAUD; + up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud); + + quot = up->port.uartclk / (16 * new_baud); + + sunsu_change_speed(&up->port, up->cflag, 0, quot); +} + +static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) +{ + do { + unsigned char ch = serial_inp(up, UART_RX); + + /* Stop-A is handled by drivers/char/keyboard.c now. */ + if (up->su_type == SU_PORT_KBD) { +#ifdef CONFIG_SERIO + serio_interrupt(&up->serio, ch, 0); +#endif + } else if (up->su_type == SU_PORT_MS) { + int ret = suncore_mouse_baud_detection(ch, is_break); + + switch (ret) { + case 2: + sunsu_change_mouse_baud(up); + /* fallthru */ + case 1: + break; + + case 0: +#ifdef CONFIG_SERIO + serio_interrupt(&up->serio, ch, 0); +#endif + break; + }; + } + } while (serial_in(up, UART_LSR) & UART_LSR_DR); +} + +static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id) +{ + struct uart_sunsu_port *up = dev_id; + + if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) { + unsigned char status = serial_inp(up, UART_LSR); + + if ((status & UART_LSR_DR) || (status & UART_LSR_BI)) + receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0); + } + + return IRQ_HANDLED; +} + +static unsigned int sunsu_tx_empty(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned long flags; + unsigned int ret; + + 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); + + return ret; +} + +static unsigned int sunsu_get_mctrl(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned char status; + unsigned int ret; + + status = serial_in(up, UART_MSR); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + serial_out(up, UART_MCR, mcr); +} + +static void sunsu_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static int sunsu_startup(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned long flags; + int retval; + + if (up->port.type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_IER, 0); + serial_outp(up, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_LCR, 0); + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + enable_rsa(up); +#endif + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(up, UART_FCR, 0); + } + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(up, UART_LSR); + (void) serial_inp(up, UART_RX); + (void) serial_inp(up, UART_IIR); + (void) serial_inp(up, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(up->port.flags & UPF_BUGGY_UART) && + (serial_inp(up, UART_LSR) == 0xff)) { + printk("ttyS%d: LSR safety check engaged!\n", up->port.line); + return -ENODEV; + } + + if (up->su_type != SU_PORT_PORT) { + retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt, + IRQF_SHARED, su_typev[up->su_type], up); + } else { + retval = request_irq(up->port.irq, sunsu_serial_interrupt, + IRQF_SHARED, su_typev[up->su_type], up); + } + if (retval) { + printk("su: Cannot register IRQ %d\n", up->port.irq); + return retval; + } + + /* + * Now, initialize the UART + */ + serial_outp(up, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&up->port.lock, flags); + + up->port.mctrl |= TIOCM_OUT2; + + sunsu_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_outp(up, UART_IER, up->ier); + + if (up->port.flags & UPF_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ + icp = (up->port.iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + (void) inb_p(icp); + } + + /* + * And clear the interrupt registers again for luck. + */ + (void) serial_inp(up, UART_LSR); + (void) serial_inp(up, UART_RX); + (void) serial_inp(up, UART_IIR); + (void) serial_inp(up, UART_MSR); + + return 0; +} + +static void sunsu_shutdown(struct uart_port *port) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned long flags; + + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_outp(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((up->port.iobase & 0xfe0) | 0x1f); + up->port.mctrl |= TIOCM_OUT1; + } else + up->port.mctrl &= ~TIOCM_OUT2; + + sunsu_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial_outp(up, UART_FCR, 0); + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + disable_rsa(up); +#endif + + /* + * Read data port to reset things. + */ + (void) serial_in(up, UART_RX); + + free_irq(up->port.irq, up); +} + +static void +sunsu_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + unsigned char cval, fcr = 0; + unsigned long flags; + + switch (cflag & CSIZE) { + case CS5: + cval = 0x00; + break; + case CS6: + cval = 0x01; + break; + case CS7: + cval = 0x02; + break; + default: + case CS8: + cval = 0x03; + break; + } + + if (cflag & CSTOPB) + cval |= 0x04; + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* + * Work around a bug in the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 && + up->rev == 0x5201) + quot ++; + + if (uart_config[up->port.type].flags & UART_USE_FIFO) { + if ((up->port.uartclk / quot) < (2400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; +#ifdef CONFIG_SERIAL_8250_RSA + else if (up->port.type == PORT_RSA) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; +#endif + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + } + if (up->port.type == PORT_16750) + fcr |= UART_FCR7_64BYTE; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, cflag, (port->uartclk / (16 * quot))); + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (iflag & INPCK) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + up->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, cflag)) + up->ier |= UART_IER_MSI; + + serial_out(up, UART_IER, up->ier); + + if (uart_config[up->port.type].flags & UART_STARTECH) { + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0); + } + serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ + if (up->port.type == PORT_16750) + serial_outp(up, UART_FCR, fcr); /* set fcr */ + serial_outp(up, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + if (up->port.type != PORT_16750) { + if (fcr & UART_FCR_ENABLE_FIFO) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_outp(up, UART_FCR, fcr); /* set fcr */ + } + + up->cflag = cflag; + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void +sunsu_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud, quot; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + sunsu_change_speed(port, termios->c_cflag, termios->c_iflag, quot); +} + +static void sunsu_release_port(struct uart_port *port) +{ +} + +static int sunsu_request_port(struct uart_port *port) +{ + return 0; +} + +static void sunsu_config_port(struct uart_port *port, int flags) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *) port; + + if (flags & UART_CONFIG_TYPE) { + /* + * We are supposed to call autoconfig here, but this requires + * splitting all the OBP probing crap from the UART probing. + * We'll do it when we kill sunsu.c altogether. + */ + port->type = up->type_probed; /* XXX */ + } +} + +static int +sunsu_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static const char * +sunsu_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 sunsu_pops = { + .tx_empty = sunsu_tx_empty, + .set_mctrl = sunsu_set_mctrl, + .get_mctrl = sunsu_get_mctrl, + .stop_tx = sunsu_stop_tx, + .start_tx = sunsu_start_tx, + .stop_rx = sunsu_stop_rx, + .enable_ms = sunsu_enable_ms, + .break_ctl = sunsu_break_ctl, + .startup = sunsu_startup, + .shutdown = sunsu_shutdown, + .set_termios = sunsu_set_termios, + .type = sunsu_type, + .release_port = sunsu_release_port, + .request_port = sunsu_request_port, + .config_port = sunsu_config_port, + .verify_port = sunsu_verify_port, +}; + +#define UART_NR 4 + +static struct uart_sunsu_port sunsu_ports[UART_NR]; + +#ifdef CONFIG_SERIO + +static DEFINE_SPINLOCK(sunsu_serio_lock); + +static int sunsu_serio_write(struct serio *serio, unsigned char ch) +{ + struct uart_sunsu_port *up = serio->port_data; + unsigned long flags; + int lsr; + + spin_lock_irqsave(&sunsu_serio_lock, flags); + + do { + lsr = serial_in(up, UART_LSR); + } while (!(lsr & UART_LSR_THRE)); + + /* Send the character out. */ + serial_out(up, UART_TX, ch); + + spin_unlock_irqrestore(&sunsu_serio_lock, flags); + + return 0; +} + +static int sunsu_serio_open(struct serio *serio) +{ + struct uart_sunsu_port *up = serio->port_data; + unsigned long flags; + int ret; + + spin_lock_irqsave(&sunsu_serio_lock, flags); + if (!up->serio_open) { + up->serio_open = 1; + ret = 0; + } else + ret = -EBUSY; + spin_unlock_irqrestore(&sunsu_serio_lock, flags); + + return ret; +} + +static void sunsu_serio_close(struct serio *serio) +{ + struct uart_sunsu_port *up = serio->port_data; + unsigned long flags; + + spin_lock_irqsave(&sunsu_serio_lock, flags); + up->serio_open = 0; + spin_unlock_irqrestore(&sunsu_serio_lock, flags); +} + +#endif /* CONFIG_SERIO */ + +static void sunsu_autoconfig(struct uart_sunsu_port *up) +{ + unsigned char status1, status2, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + unsigned long flags; + + if (up->su_type == SU_PORT_NONE) + return; + + up->type_probed = PORT_UNKNOWN; + up->port.iotype = UPIO_MEM; + + spin_lock_irqsave(&up->port.lock, flags); + + if (!(up->port.flags & UPF_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, there's + * no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against false + * positives due to ISA bus float. The assumption is that + * 0x80 is a non-existent port; which should be safe since + * include/asm/io.h also makes this assumption. + */ + scratch = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, 0x0f); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) + goto out; /* We failed; there's nothing here */ + } + + save_mcr = serial_in(up, UART_MCR); + save_lcr = serial_in(up, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(up->port.flags & UPF_SKIP_TEST)) { + serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(up, UART_MSR) & 0xF0; + serial_outp(up, UART_MCR, save_mcr); + if (status1 != 0x90) + goto out; /* We failed loopback test */ + } + serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */ + serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */ + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + switch (scratch) { + case 0: + up->port.type = PORT_16450; + break; + case 1: + up->port.type = PORT_UNKNOWN; + break; + case 2: + up->port.type = PORT_16550; + break; + case 3: + up->port.type = PORT_16550A; + break; + } + if (up->port.type == PORT_16550A) { + /* Check for Startech UART's */ + serial_outp(up, UART_LCR, UART_LCR_DLAB); + if (serial_in(up, UART_EFR) == 0) { + up->port.type = PORT_16650; + } else { + serial_outp(up, UART_LCR, 0xBF); + if (serial_in(up, UART_EFR) == 0) + up->port.type = PORT_16650V2; + } + } + if (up->port.type == PORT_16550A) { + /* Check for TI 16750 */ + serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB); + serial_outp(up, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(up, UART_IIR) >> 5; + if (scratch == 7) { + /* + * If this is a 16750, and not a cheap UART + * clone, then it should only go into 64 byte + * mode if the UART_FCR7_64BYTE bit was set + * while UART_LCR_DLAB was latched. + */ + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(up, UART_IIR) >> 5; + if (scratch == 6) + up->port.type = PORT_16750; + } + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_outp(up, UART_LCR, save_lcr); + if (up->port.type == PORT_16450) { + scratch = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, scratch); + + if ((status1 != 0xa5) || (status2 != 0x5a)) + up->port.type = PORT_8250; + } + + up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; + + if (up->port.type == PORT_UNKNOWN) + goto out; + up->type_probed = up->port.type; /* XXX */ + + /* + * Reset the UART. + */ +#ifdef CONFIG_SERIAL_8250_RSA + if (up->port.type == PORT_RSA) + serial_outp(up, UART_RSA_FRR, 0); +#endif + serial_outp(up, UART_MCR, save_mcr); + serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(up, UART_FCR, 0); + (void)serial_in(up, UART_RX); + serial_outp(up, UART_IER, 0); + +out: + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static struct uart_driver sunsu_reg = { + .owner = THIS_MODULE, + .driver_name = "sunsu", + .dev_name = "ttyS", + .major = TTY_MAJOR, +}; + +static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up) +{ + int quot, baud; +#ifdef CONFIG_SERIO + struct serio *serio; +#endif + + if (up->su_type == SU_PORT_KBD) { + up->cflag = B1200 | CS8 | CLOCAL | CREAD; + baud = 1200; + } else { + up->cflag = B4800 | CS8 | CLOCAL | CREAD; + baud = 4800; + } + quot = up->port.uartclk / (16 * baud); + + sunsu_autoconfig(up); + if (up->port.type == PORT_UNKNOWN) + return -ENODEV; + + printk("%s: %s port at %llx, irq %u\n", + up->port.dev->of_node->full_name, + (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse", + (unsigned long long) up->port.mapbase, + up->port.irq); + +#ifdef CONFIG_SERIO + serio = &up->serio; + serio->port_data = up; + + serio->id.type = SERIO_RS232; + if (up->su_type == SU_PORT_KBD) { + serio->id.proto = SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); + } else { + serio->id.proto = SERIO_SUN; + serio->id.extra = 1; + strlcpy(serio->name, "sums", sizeof(serio->name)); + } + strlcpy(serio->phys, + (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); + + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; + serio->dev.parent = up->port.dev; + + serio_register_port(serio); +#endif + + sunsu_change_speed(&up->port, up->cflag, 0, quot); + + sunsu_startup(&up->port); + return 0; +} + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ + +#ifdef CONFIG_SERIAL_SUNSU_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Wait for transmitter & holding register to empty + */ +static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) + udelay(1); + } +} + +static void sunsu_console_putchar(struct uart_port *port, int ch) +{ + struct uart_sunsu_port *up = (struct uart_sunsu_port *)port; + + wait_for_xmitr(up); + serial_out(up, UART_TX, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void sunsu_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_sunsu_port *up = &sunsu_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + 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 UER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + + uart_console_write(&up->port, s, count, sunsu_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first su_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init sunsu_console_setup(struct console *co, char *options) +{ + static struct ktermios dummy; + struct ktermios termios; + struct uart_port *port; + + printk("Console: ttyS%d (SU)\n", + (sunsu_reg.minor - 64) + co->index); + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &sunsu_ports[co->index].port; + + /* + * Temporary fix. + */ + spin_lock_init(&port->lock); + + /* Get firmware console settings. */ + sunserial_console_termios(co, port->dev->of_node); + + memset(&termios, 0, sizeof(struct ktermios)); + termios.c_cflag = co->cflag; + port->mctrl |= TIOCM_DTR; + port->ops->set_termios(port, &termios, &dummy); + + return 0; +} + +static struct console sunsu_console = { + .name = "ttyS", + .write = sunsu_console_write, + .device = uart_console_device, + .setup = sunsu_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sunsu_reg, +}; + +/* + * Register console. + */ + +static inline struct console *SUNSU_CONSOLE(void) +{ + return &sunsu_console; +} +#else +#define SUNSU_CONSOLE() (NULL) +#define sunsu_serial_console_init() do { } while (0) +#endif + +static enum su_type __devinit su_get_type(struct device_node *dp) +{ + struct device_node *ap = of_find_node_by_path("/aliases"); + + if (ap) { + const char *keyb = of_get_property(ap, "keyboard", NULL); + const char *ms = of_get_property(ap, "mouse", NULL); + + if (keyb) { + if (dp == of_find_node_by_path(keyb)) + return SU_PORT_KBD; + } + if (ms) { + if (dp == of_find_node_by_path(ms)) + return SU_PORT_MS; + } + } + + return SU_PORT_PORT; +} + +static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match) +{ + static int inst; + struct device_node *dp = op->dev.of_node; + struct uart_sunsu_port *up; + struct resource *rp; + enum su_type type; + bool ignore_line; + int err; + + type = su_get_type(dp); + if (type == SU_PORT_PORT) { + if (inst >= UART_NR) + return -EINVAL; + up = &sunsu_ports[inst]; + } else { + up = kzalloc(sizeof(*up), GFP_KERNEL); + if (!up) + return -ENOMEM; + } + + up->port.line = inst; + + spin_lock_init(&up->port.lock); + + up->su_type = type; + + rp = &op->resource[0]; + up->port.mapbase = rp->start; + up->reg_size = (rp->end - rp->start) + 1; + up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); + if (!up->port.membase) { + if (type != SU_PORT_PORT) + kfree(up); + return -ENOMEM; + } + + up->port.irq = op->archdata.irqs[0]; + + up->port.dev = &op->dev; + + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); + + err = 0; + if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) { + err = sunsu_kbd_ms_init(up); + if (err) { + of_iounmap(&op->resource[0], + up->port.membase, up->reg_size); + kfree(up); + return err; + } + dev_set_drvdata(&op->dev, up); + + return 0; + } + + up->port.flags |= UPF_BOOT_AUTOCONF; + + sunsu_autoconfig(up); + + err = -ENODEV; + if (up->port.type == PORT_UNKNOWN) + goto out_unmap; + + up->port.ops = &sunsu_pops; + + ignore_line = false; + if (!strcmp(dp->name, "rsc-console") || + !strcmp(dp->name, "lom-console")) + ignore_line = true; + + sunserial_console_match(SUNSU_CONSOLE(), dp, + &sunsu_reg, up->port.line, + ignore_line); + err = uart_add_one_port(&sunsu_reg, &up->port); + if (err) + goto out_unmap; + + dev_set_drvdata(&op->dev, up); + + inst++; + + return 0; + +out_unmap: + of_iounmap(&op->resource[0], up->port.membase, up->reg_size); + return err; +} + +static int __devexit su_remove(struct platform_device *op) +{ + struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); + bool kbdms = false; + + if (up->su_type == SU_PORT_MS || + up->su_type == SU_PORT_KBD) + kbdms = true; + + if (kbdms) { +#ifdef CONFIG_SERIO + serio_unregister_port(&up->serio); +#endif + } else if (up->port.type != PORT_UNKNOWN) + uart_remove_one_port(&sunsu_reg, &up->port); + + if (up->port.membase) + of_iounmap(&op->resource[0], up->port.membase, up->reg_size); + + if (kbdms) + kfree(up); + + dev_set_drvdata(&op->dev, NULL); + + return 0; +} + +static const struct of_device_id su_match[] = { + { + .name = "su", + }, + { + .name = "su_pnp", + }, + { + .name = "serial", + .compatible = "su", + }, + { + .type = "serial", + .compatible = "su", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, su_match); + +static struct of_platform_driver su_driver = { + .driver = { + .name = "su", + .owner = THIS_MODULE, + .of_match_table = su_match, + }, + .probe = su_probe, + .remove = __devexit_p(su_remove), +}; + +static int __init sunsu_init(void) +{ + struct device_node *dp; + int err; + int num_uart = 0; + + for_each_node_by_name(dp, "su") { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; + } + for_each_node_by_name(dp, "su_pnp") { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; + } + for_each_node_by_name(dp, "serial") { + if (of_device_is_compatible(dp, "su")) { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; + } + } + for_each_node_by_type(dp, "serial") { + if (of_device_is_compatible(dp, "su")) { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; + } + } + + if (num_uart) { + err = sunserial_register_minors(&sunsu_reg, num_uart); + if (err) + return err; + } + + err = of_register_platform_driver(&su_driver); + if (err && num_uart) + sunserial_unregister_minors(&sunsu_reg, num_uart); + + return err; +} + +static void __exit sunsu_exit(void) +{ + if (sunsu_reg.nr) + sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr); +} + +module_init(sunsu_init); +module_exit(sunsu_exit); + +MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller"); +MODULE_DESCRIPTION("Sun SU serial port driver"); +MODULE_VERSION("2.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c new file mode 100644 index 000000000000..c1967ac1c07f --- /dev/null +++ b/drivers/tty/serial/sunzilog.c @@ -0,0 +1,1655 @@ +/* sunzilog.c: Zilog serial driver for Sparc systems. + * + * Driver for Zilog serial chips found on Sun workstations and + * servers. This driver could actually be made more generic. + * + * This is based on the old drivers/sbus/char/zs.c code. A lot + * of code has been simply moved over directly from there but + * much has been rewritten. Credits therefore go out to Eddie + * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their + * work there. + * + * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SERIO +#include +#endif +#include +#include + +#include +#include +#include + +#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include "suncore.h" +#include "sunzilog.h" + +/* On 32-bit sparcs we need to delay after register accesses + * to accommodate sun4 systems, but we do not need to flush writes. + * On 64-bit sparc we only need to flush single writes to ensure + * completion. + */ +#ifndef CONFIG_SPARC64 +#define ZSDELAY() udelay(5) +#define ZSDELAY_LONG() udelay(20) +#define ZS_WSYNC(channel) do { } while (0) +#else +#define ZSDELAY() +#define ZSDELAY_LONG() +#define ZS_WSYNC(__channel) \ + readb(&((__channel)->control)) +#endif + +#define ZS_CLOCK 4915200 /* Zilog input clock rate. */ +#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ + +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_sunzilog_port { + struct uart_port port; + + /* IRQ servicing chain. */ + struct uart_sunzilog_port *next; + + /* Current values of Zilog write registers. */ + unsigned char curregs[NUM_ZSREGS]; + + unsigned int flags; +#define SUNZILOG_FLAG_CONS_KEYB 0x00000001 +#define SUNZILOG_FLAG_CONS_MOUSE 0x00000002 +#define SUNZILOG_FLAG_IS_CONS 0x00000004 +#define SUNZILOG_FLAG_IS_KGDB 0x00000008 +#define SUNZILOG_FLAG_MODEM_STATUS 0x00000010 +#define SUNZILOG_FLAG_IS_CHANNEL_A 0x00000020 +#define SUNZILOG_FLAG_REGS_HELD 0x00000040 +#define SUNZILOG_FLAG_TX_STOPPED 0x00000080 +#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100 +#define SUNZILOG_FLAG_ESCC 0x00000200 +#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400 + + unsigned int cflag; + + unsigned char parity_mask; + unsigned char prev_status; + +#ifdef CONFIG_SERIO + struct serio serio; + int serio_open; +#endif +}; + +static void sunzilog_putchar(struct uart_port *port, int ch); + +#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) +#define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) + +#define ZS_IS_KEYB(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_KEYB) +#define ZS_IS_MOUSE(UP) ((UP)->flags & SUNZILOG_FLAG_CONS_MOUSE) +#define ZS_IS_CONS(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CONS) +#define ZS_IS_KGDB(UP) ((UP)->flags & SUNZILOG_FLAG_IS_KGDB) +#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & SUNZILOG_FLAG_MODEM_STATUS) +#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & SUNZILOG_FLAG_IS_CHANNEL_A) +#define ZS_REGS_HELD(UP) ((UP)->flags & SUNZILOG_FLAG_REGS_HELD) +#define ZS_TX_STOPPED(UP) ((UP)->flags & SUNZILOG_FLAG_TX_STOPPED) +#define ZS_TX_ACTIVE(UP) ((UP)->flags & SUNZILOG_FLAG_TX_ACTIVE) + +/* Reading and writing Zilog8530 registers. The delays are to make this + * driver work on the Sun4 which needs a settling delay after each chip + * register access, other machines handle this in hardware via auxiliary + * flip-flops which implement the settle time we do in software. + * + * The port lock must be held and local IRQs must be disabled + * when {read,write}_zsreg is invoked. + */ +static unsigned char read_zsreg(struct zilog_channel __iomem *channel, + unsigned char reg) +{ + unsigned char retval; + + writeb(reg, &channel->control); + ZSDELAY(); + retval = readb(&channel->control); + ZSDELAY(); + + return retval; +} + +static void write_zsreg(struct zilog_channel __iomem *channel, + unsigned char reg, unsigned char value) +{ + writeb(reg, &channel->control); + ZSDELAY(); + writeb(value, &channel->control); + ZSDELAY(); +} + +static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) +{ + int i; + + for (i = 0; i < 32; i++) { + unsigned char regval; + + regval = readb(&channel->control); + ZSDELAY(); + if (regval & Rx_CH_AV) + break; + + regval = read_zsreg(channel, R1); + readb(&channel->data); + ZSDELAY(); + + if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + } +} + +/* This function must only be called when the TX is not busy. The UART + * port lock must be held and local interrupts disabled. + */ +static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs) +{ + int i; + int escc; + unsigned char r15; + + /* Let pending transmits finish. */ + for (i = 0; i < 1000; i++) { + unsigned char stat = read_zsreg(channel, R1); + if (stat & ALL_SNT) + break; + udelay(100); + } + + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + sunzilog_clear_fifo(channel); + + /* Disable all interrupts. */ + write_zsreg(channel, R1, + regs[R1] & ~(RxINT_MASK | TxINT_ENAB | EXT_INT_ENAB)); + + /* Set parity, sync config, stop bits, and clock divisor. */ + write_zsreg(channel, R4, regs[R4]); + + /* Set misc. TX/RX control bits. */ + write_zsreg(channel, R10, regs[R10]); + + /* Set TX/RX controls sans the enable bits. */ + write_zsreg(channel, R3, regs[R3] & ~RxENAB); + write_zsreg(channel, R5, regs[R5] & ~TxENAB); + + /* Synchronous mode config. */ + write_zsreg(channel, R6, regs[R6]); + write_zsreg(channel, R7, regs[R7]); + + /* Don't mess with the interrupt vector (R2, unused by us) and + * master interrupt control (R9). We make sure this is setup + * properly at probe time then never touch it again. + */ + + /* Disable baud generator. */ + write_zsreg(channel, R14, regs[R14] & ~BRENAB); + + /* Clock mode control. */ + write_zsreg(channel, R11, regs[R11]); + + /* Lower and upper byte of baud rate generator divisor. */ + write_zsreg(channel, R12, regs[R12]); + write_zsreg(channel, R13, regs[R13]); + + /* Now rewrite R14, with BRENAB (if set). */ + write_zsreg(channel, R14, regs[R14]); + + /* External status interrupt control. */ + write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN); + + /* ESCC Extension Register */ + r15 = read_zsreg(channel, R15); + if (r15 & 0x01) { + write_zsreg(channel, R7, regs[R7p]); + + /* External status interrupt and FIFO control. */ + write_zsreg(channel, R15, regs[R15] & ~WR7pEN); + escc = 1; + } else { + /* Clear FIFO bit case it is an issue */ + regs[R15] &= ~FIFOEN; + escc = 0; + } + + /* Reset external status interrupts. */ + write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */ + write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */ + + /* Rewrite R3/R5, this time without enables masked. */ + write_zsreg(channel, R3, regs[R3]); + write_zsreg(channel, R5, regs[R5]); + + /* Rewrite R1, this time without IRQ enabled masked. */ + write_zsreg(channel, R1, regs[R1]); + + return escc; +} + +/* Reprogram the Zilog channel HW registers with the copies found in the + * software state struct. If the transmitter is busy, we defer this update + * until the next TX complete interrupt. Else, we do it right now. + * + * The UART port lock must be held and local interrupts disabled. + */ +static void sunzilog_maybe_update_regs(struct uart_sunzilog_port *up, + struct zilog_channel __iomem *channel) +{ + if (!ZS_REGS_HELD(up)) { + if (ZS_TX_ACTIVE(up)) { + up->flags |= SUNZILOG_FLAG_REGS_HELD; + } else { + __load_zsregs(channel, up->curregs); + } + } +} + +static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up) +{ + unsigned int cur_cflag = up->cflag; + int brg, new_baud; + + up->cflag &= ~CBAUD; + up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud); + + brg = BPS_TO_BRG(new_baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(&up->port)); +} + +static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, + unsigned char ch, int is_break) +{ + if (ZS_IS_KEYB(up)) { + /* Stop-A is handled by drivers/char/keyboard.c now. */ +#ifdef CONFIG_SERIO + if (up->serio_open) + serio_interrupt(&up->serio, ch, 0); +#endif + } else if (ZS_IS_MOUSE(up)) { + int ret = suncore_mouse_baud_detection(ch, is_break); + + switch (ret) { + case 2: + sunzilog_change_mouse_baud(up); + /* fallthru */ + case 1: + break; + + case 0: +#ifdef CONFIG_SERIO + if (up->serio_open) + serio_interrupt(&up->serio, ch, 0); +#endif + break; + }; + } +} + +static struct tty_struct * +sunzilog_receive_chars(struct uart_sunzilog_port *up, + struct zilog_channel __iomem *channel) +{ + struct tty_struct *tty; + unsigned char ch, r1, flag; + + tty = NULL; + if (up->port.state != NULL && /* Unopened serial console */ + up->port.state->port.tty != NULL) /* Keyboard || mouse */ + tty = up->port.state->port.tty; + + for (;;) { + + r1 = read_zsreg(channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + + ch = readb(&channel->control); + ZSDELAY(); + + /* This funny hack depends upon BRK_ABRT not interfering + * with the other bits we care about in R1. + */ + if (ch & BRK_ABRT) + r1 |= BRK_ABRT; + + if (!(ch & Rx_CH_AV)) + break; + + ch = readb(&channel->data); + ZSDELAY(); + + ch &= up->parity_mask; + + if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) { + sunzilog_kbdms_receive_chars(up, ch, 0); + continue; + } + + if (tty == NULL) { + uart_handle_sysrq_char(&up->port, ch); + continue; + } + + /* A real serial line, record the character and status. */ + flag = TTY_NORMAL; + up->port.icount.rx++; + if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) { + if (r1 & BRK_ABRT) { + r1 &= ~(PAR_ERR | CRC_ERR); + up->port.icount.brk++; + if (uart_handle_break(&up->port)) + continue; + } + else if (r1 & PAR_ERR) + up->port.icount.parity++; + else if (r1 & CRC_ERR) + up->port.icount.frame++; + if (r1 & Rx_OVR) + up->port.icount.overrun++; + r1 &= up->port.read_status_mask; + if (r1 & BRK_ABRT) + flag = TTY_BREAK; + else if (r1 & PAR_ERR) + flag = TTY_PARITY; + else if (r1 & CRC_ERR) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + + if (up->port.ignore_status_mask == 0xff || + (r1 & up->port.ignore_status_mask) == 0) { + tty_insert_flip_char(tty, ch, flag); + } + if (r1 & Rx_OVR) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + return tty; +} + +static void sunzilog_status_handle(struct uart_sunzilog_port *up, + struct zilog_channel __iomem *channel) +{ + unsigned char status; + + status = readb(&channel->control); + ZSDELAY(); + + writeb(RES_EXT_INT, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (status & BRK_ABRT) { + if (ZS_IS_MOUSE(up)) + sunzilog_kbdms_receive_chars(up, 0, 1); + if (ZS_IS_CONS(up)) { + /* Wait for BREAK to deassert to avoid potentially + * confusing the PROM. + */ + while (1) { + status = readb(&channel->control); + ZSDELAY(); + if (!(status & BRK_ABRT)) + break; + } + sun_do_break(); + return; + } + } + + if (ZS_WANTS_MODEM_STATUS(up)) { + if (status & SYNC) + up->port.icount.dsr++; + + /* The Zilog just gives us an interrupt when DCD/CTS/etc. change. + * But it does not tell us which bit has changed, we have to keep + * track of this ourselves. + */ + if ((status ^ up->prev_status) ^ DCD) + uart_handle_dcd_change(&up->port, + (status & DCD)); + if ((status ^ up->prev_status) ^ CTS) + uart_handle_cts_change(&up->port, + (status & CTS)); + + wake_up_interruptible(&up->port.state->port.delta_msr_wait); + } + + up->prev_status = status; +} + +static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, + struct zilog_channel __iomem *channel) +{ + struct circ_buf *xmit; + + if (ZS_IS_CONS(up)) { + unsigned char status = readb(&channel->control); + ZSDELAY(); + + /* TX still busy? Just wait for the next TX done interrupt. + * + * It can occur because of how we do serial console writes. It would + * be nice to transmit console writes just like we normally would for + * a TTY line. (ie. buffered and TX interrupt driven). That is not + * easy because console writes cannot sleep. One solution might be + * to poll on enough port->xmit space becomming free. -DaveM + */ + if (!(status & Tx_BUF_EMP)) + return; + } + + up->flags &= ~SUNZILOG_FLAG_TX_ACTIVE; + + if (ZS_REGS_HELD(up)) { + __load_zsregs(channel, up->curregs); + up->flags &= ~SUNZILOG_FLAG_REGS_HELD; + } + + if (ZS_TX_STOPPED(up)) { + up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; + goto ack_tx_int; + } + + if (up->port.x_char) { + up->flags |= SUNZILOG_FLAG_TX_ACTIVE; + writeb(up->port.x_char, &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + + if (up->port.state == NULL) + goto ack_tx_int; + xmit = &up->port.state->xmit; + if (uart_circ_empty(xmit)) + goto ack_tx_int; + + if (uart_tx_stopped(&up->port)) + goto ack_tx_int; + + up->flags |= SUNZILOG_FLAG_TX_ACTIVE; + writeb(xmit->buf[xmit->tail], &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + return; + +ack_tx_int: + writeb(RES_Tx_P, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); +} + +static irqreturn_t sunzilog_interrupt(int irq, void *dev_id) +{ + struct uart_sunzilog_port *up = dev_id; + + while (up) { + struct zilog_channel __iomem *channel + = ZILOG_CHANNEL_FROM_PORT(&up->port); + struct tty_struct *tty; + unsigned char r3; + + spin_lock(&up->port.lock); + r3 = read_zsreg(channel, R3); + + /* Channel A */ + tty = NULL; + if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (r3 & CHARxIP) + tty = sunzilog_receive_chars(up, channel); + if (r3 & CHAEXT) + sunzilog_status_handle(up, channel); + if (r3 & CHATxIP) + sunzilog_transmit_chars(up, channel); + } + spin_unlock(&up->port.lock); + + if (tty) + tty_flip_buffer_push(tty); + + /* Channel B */ + up = up->next; + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + + spin_lock(&up->port.lock); + tty = NULL; + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + writeb(RES_H_IUS, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + + if (r3 & CHBRxIP) + tty = sunzilog_receive_chars(up, channel); + if (r3 & CHBEXT) + sunzilog_status_handle(up, channel); + if (r3 & CHBTxIP) + sunzilog_transmit_chars(up, channel); + } + spin_unlock(&up->port.lock); + + if (tty) + tty_flip_buffer_push(tty); + + up = up->next; + } + + return IRQ_HANDLED; +} + +/* A convenient way to quickly get R0 status. The caller must _not_ hold the + * port lock, it is acquired here. + */ +static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port) +{ + struct zilog_channel __iomem *channel; + unsigned char status; + + channel = ZILOG_CHANNEL_FROM_PORT(port); + status = readb(&channel->control); + ZSDELAY(); + + return status; +} + +/* The port lock is not held. */ +static unsigned int sunzilog_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned char status; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + + status = sunzilog_read_channel_status(port); + + spin_unlock_irqrestore(&port->lock, flags); + + if (status & Tx_BUF_EMP) + ret = TIOCSER_TEMT; + else + ret = 0; + + return ret; +} + +/* The port lock is held and interrupts are disabled. */ +static unsigned int sunzilog_get_mctrl(struct uart_port *port) +{ + unsigned char status; + unsigned int ret; + + status = sunzilog_read_channel_status(port); + + ret = 0; + if (status & DCD) + ret |= TIOCM_CAR; + if (status & SYNC) + ret |= TIOCM_DSR; + if (status & CTS) + ret |= TIOCM_CTS; + + return ret; +} + +/* The port lock is held and interrupts are disabled. */ +static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char set_bits, clear_bits; + + set_bits = clear_bits = 0; + + if (mctrl & TIOCM_RTS) + set_bits |= RTS; + else + clear_bits |= RTS; + if (mctrl & TIOCM_DTR) + set_bits |= DTR; + else + clear_bits |= DTR; + + /* NOTE: Not subject to 'transmitter active' rule. */ + up->curregs[R5] |= set_bits; + up->curregs[R5] &= ~clear_bits; + write_zsreg(channel, R5, up->curregs[R5]); +} + +/* The port lock is held and interrupts are disabled. */ +static void sunzilog_stop_tx(struct uart_port *port) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + + up->flags |= SUNZILOG_FLAG_TX_STOPPED; +} + +/* The port lock is held and interrupts are disabled. */ +static void sunzilog_start_tx(struct uart_port *port) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char status; + + up->flags |= SUNZILOG_FLAG_TX_ACTIVE; + up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; + + status = readb(&channel->control); + ZSDELAY(); + + /* TX busy? Just wait for the TX done interrupt. */ + if (!(status & Tx_BUF_EMP)) + return; + + /* Send the first character to jump-start the TX done + * IRQ sending engine. + */ + if (port->x_char) { + writeb(port->x_char, &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + port->icount.tx++; + port->x_char = 0; + } else { + struct circ_buf *xmit = &port->state->xmit; + + writeb(xmit->buf[xmit->tail], &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + } +} + +/* The port lock is held. */ +static void sunzilog_stop_rx(struct uart_port *port) +{ + struct uart_sunzilog_port *up = UART_ZILOG(port); + struct zilog_channel __iomem *channel; + + if (ZS_IS_CONS(up)) + return; + + channel = ZILOG_CHANNEL_FROM_PORT(port); + + /* Disable all RX interrupts. */ + up->curregs[R1] &= ~RxINT_MASK; + sunzilog_maybe_update_regs(up, channel); +} + +/* The port lock is held. */ +static void sunzilog_enable_ms(struct uart_port *port) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char new_reg; + + new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE); + if (new_reg != up->curregs[R15]) { + up->curregs[R15] = new_reg; + + /* NOTE: Not subject to 'transmitter active' rule. */ + write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN); + } +} + +/* The port lock is not held. */ +static void sunzilog_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); + unsigned char set_bits, clear_bits, new_reg; + unsigned long flags; + + set_bits = clear_bits = 0; + + if (break_state) + set_bits |= SND_BRK; + else + clear_bits |= SND_BRK; + + spin_lock_irqsave(&port->lock, flags); + + new_reg = (up->curregs[R5] | set_bits) & ~clear_bits; + if (new_reg != up->curregs[R5]) { + up->curregs[R5] = new_reg; + + /* NOTE: Not subject to 'transmitter active' rule. */ + write_zsreg(channel, R5, up->curregs[R5]); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void __sunzilog_startup(struct uart_sunzilog_port *up) +{ + struct zilog_channel __iomem *channel; + + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->prev_status = readb(&channel->control); + + /* Enable receiver and transmitter. */ + up->curregs[R3] |= RxENAB; + up->curregs[R5] |= TxENAB; + + up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + sunzilog_maybe_update_regs(up, channel); +} + +static int sunzilog_startup(struct uart_port *port) +{ + struct uart_sunzilog_port *up = UART_ZILOG(port); + unsigned long flags; + + if (ZS_IS_CONS(up)) + return 0; + + spin_lock_irqsave(&port->lock, flags); + __sunzilog_startup(up); + spin_unlock_irqrestore(&port->lock, flags); + return 0; +} + +/* + * The test for ZS_IS_CONS is explained by the following e-mail: + ***** + * From: Russell King + * Date: Sun, 8 Dec 2002 10:18:38 +0000 + * + * On Sun, Dec 08, 2002 at 02:43:36AM -0500, Pete Zaitcev wrote: + * > I boot my 2.5 boxes using "console=ttyS0,9600" argument, + * > and I noticed that something is not right with reference + * > counting in this case. It seems that when the console + * > is open by kernel initially, this is not accounted + * > as an open, and uart_startup is not called. + * + * That is correct. We are unable to call uart_startup when the serial + * console is initialised because it may need to allocate memory (as + * request_irq does) and the memory allocators may not have been + * initialised. + * + * 1. initialise the port into a state where it can send characters in the + * console write method. + * + * 2. don't do the actual hardware shutdown in your shutdown() method (but + * do the normal software shutdown - ie, free irqs etc) + ***** + */ +static void sunzilog_shutdown(struct uart_port *port) +{ + struct uart_sunzilog_port *up = UART_ZILOG(port); + struct zilog_channel __iomem *channel; + unsigned long flags; + + if (ZS_IS_CONS(up)) + return; + + spin_lock_irqsave(&port->lock, flags); + + channel = ZILOG_CHANNEL_FROM_PORT(port); + + /* Disable receiver and transmitter. */ + up->curregs[R3] &= ~RxENAB; + up->curregs[R5] &= ~TxENAB; + + /* Disable all interrupts and BRK assertion. */ + up->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK); + up->curregs[R5] &= ~SND_BRK; + sunzilog_maybe_update_regs(up, channel); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Shared by TTY driver and serial console setup. The port lock is held + * and local interrupts are disabled. + */ +static void +sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, + unsigned int iflag, int brg) +{ + + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + + /* Program BAUD and clock source. */ + up->curregs[R4] &= ~XCLK_MASK; + up->curregs[R4] |= X16CLK; + up->curregs[R12] = brg & 0xff; + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRSRC | BRENAB; + + /* Character size, stop bits, and parity. */ + up->curregs[R3] &= ~RxN_MASK; + up->curregs[R5] &= ~TxN_MASK; + switch (cflag & CSIZE) { + case CS5: + up->curregs[R3] |= Rx5; + up->curregs[R5] |= Tx5; + up->parity_mask = 0x1f; + break; + case CS6: + up->curregs[R3] |= Rx6; + up->curregs[R5] |= Tx6; + up->parity_mask = 0x3f; + break; + case CS7: + up->curregs[R3] |= Rx7; + up->curregs[R5] |= Tx7; + up->parity_mask = 0x7f; + break; + case CS8: + default: + up->curregs[R3] |= Rx8; + up->curregs[R5] |= Tx8; + up->parity_mask = 0xff; + break; + }; + up->curregs[R4] &= ~0x0c; + if (cflag & CSTOPB) + up->curregs[R4] |= SB2; + else + up->curregs[R4] |= SB1; + if (cflag & PARENB) + up->curregs[R4] |= PAR_ENAB; + else + up->curregs[R4] &= ~PAR_ENAB; + if (!(cflag & PARODD)) + up->curregs[R4] |= PAR_EVEN; + else + up->curregs[R4] &= ~PAR_EVEN; + + up->port.read_status_mask = Rx_OVR; + if (iflag & INPCK) + up->port.read_status_mask |= CRC_ERR | PAR_ERR; + if (iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= BRK_ABRT; + + up->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= CRC_ERR | PAR_ERR; + if (iflag & IGNBRK) { + up->port.ignore_status_mask |= BRK_ABRT; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= Rx_OVR; + } + + if ((cflag & CREAD) == 0) + up->port.ignore_status_mask = 0xff; +} + +/* The port lock is not held. */ +static void +sunzilog_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + unsigned long flags; + int baud, brg; + + baud = uart_get_baud_rate(port, termios, old, 1200, 76800); + + spin_lock_irqsave(&up->port.lock, flags); + + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + + sunzilog_convert_to_zs(up, termios->c_cflag, termios->c_iflag, brg); + + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->flags |= SUNZILOG_FLAG_MODEM_STATUS; + else + up->flags &= ~SUNZILOG_FLAG_MODEM_STATUS; + + up->cflag = termios->c_cflag; + + sunzilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static const char *sunzilog_type(struct uart_port *port) +{ + struct uart_sunzilog_port *up = UART_ZILOG(port); + + return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs"; +} + +/* We do not request/release mappings of the registers here, this + * happens at early serial probe time. + */ +static void sunzilog_release_port(struct uart_port *port) +{ +} + +static int sunzilog_request_port(struct uart_port *port) +{ + return 0; +} + +/* These do not need to do anything interesting either. */ +static void sunzilog_config_port(struct uart_port *port, int flags) +{ +} + +/* We do not support letting the user mess with the divisor, IRQ, etc. */ +static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +#ifdef CONFIG_CONSOLE_POLL +static int sunzilog_get_poll_char(struct uart_port *port) +{ + unsigned char ch, r1; + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel + = ZILOG_CHANNEL_FROM_PORT(&up->port); + + + r1 = read_zsreg(channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + + ch = readb(&channel->control); + ZSDELAY(); + + /* This funny hack depends upon BRK_ABRT not interfering + * with the other bits we care about in R1. + */ + if (ch & BRK_ABRT) + r1 |= BRK_ABRT; + + if (!(ch & Rx_CH_AV)) + return NO_POLL_CHAR; + + ch = readb(&channel->data); + ZSDELAY(); + + ch &= up->parity_mask; + return ch; +} + +static void sunzilog_put_poll_char(struct uart_port *port, + unsigned char ch) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; + + sunzilog_putchar(&up->port, ch); +} +#endif /* CONFIG_CONSOLE_POLL */ + +static struct uart_ops sunzilog_pops = { + .tx_empty = sunzilog_tx_empty, + .set_mctrl = sunzilog_set_mctrl, + .get_mctrl = sunzilog_get_mctrl, + .stop_tx = sunzilog_stop_tx, + .start_tx = sunzilog_start_tx, + .stop_rx = sunzilog_stop_rx, + .enable_ms = sunzilog_enable_ms, + .break_ctl = sunzilog_break_ctl, + .startup = sunzilog_startup, + .shutdown = sunzilog_shutdown, + .set_termios = sunzilog_set_termios, + .type = sunzilog_type, + .release_port = sunzilog_release_port, + .request_port = sunzilog_request_port, + .config_port = sunzilog_config_port, + .verify_port = sunzilog_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sunzilog_get_poll_char, + .poll_put_char = sunzilog_put_poll_char, +#endif +}; + +static int uart_chip_count; +static struct uart_sunzilog_port *sunzilog_port_table; +static struct zilog_layout __iomem **sunzilog_chip_regs; + +static struct uart_sunzilog_port *sunzilog_irq_chain; + +static struct uart_driver sunzilog_reg = { + .owner = THIS_MODULE, + .driver_name = "sunzilog", + .dev_name = "ttyS", + .major = TTY_MAJOR, +}; + +static int __init sunzilog_alloc_tables(int num_sunzilog) +{ + struct uart_sunzilog_port *up; + unsigned long size; + int num_channels = num_sunzilog * 2; + int i; + + size = num_channels * sizeof(struct uart_sunzilog_port); + sunzilog_port_table = kzalloc(size, GFP_KERNEL); + if (!sunzilog_port_table) + return -ENOMEM; + + for (i = 0; i < num_channels; i++) { + up = &sunzilog_port_table[i]; + + spin_lock_init(&up->port.lock); + + if (i == 0) + sunzilog_irq_chain = up; + + if (i < num_channels - 1) + up->next = up + 1; + else + up->next = NULL; + } + + size = num_sunzilog * sizeof(struct zilog_layout __iomem *); + sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); + if (!sunzilog_chip_regs) { + kfree(sunzilog_port_table); + sunzilog_irq_chain = NULL; + return -ENOMEM; + } + + return 0; +} + +static void sunzilog_free_tables(void) +{ + kfree(sunzilog_port_table); + sunzilog_irq_chain = NULL; + kfree(sunzilog_chip_regs); +} + +#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ + +static void sunzilog_putchar(struct uart_port *port, int ch) +{ + struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port); + int loops = ZS_PUT_CHAR_MAX_DELAY; + + /* This is a timed polling loop so do not switch the explicit + * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM + */ + do { + unsigned char val = readb(&channel->control); + if (val & Tx_BUF_EMP) { + ZSDELAY(); + break; + } + udelay(5); + } while (--loops); + + writeb(ch, &channel->data); + ZSDELAY(); + ZS_WSYNC(channel); +} + +#ifdef CONFIG_SERIO + +static DEFINE_SPINLOCK(sunzilog_serio_lock); + +static int sunzilog_serio_write(struct serio *serio, unsigned char ch) +{ + struct uart_sunzilog_port *up = serio->port_data; + unsigned long flags; + + spin_lock_irqsave(&sunzilog_serio_lock, flags); + + sunzilog_putchar(&up->port, ch); + + spin_unlock_irqrestore(&sunzilog_serio_lock, flags); + + return 0; +} + +static int sunzilog_serio_open(struct serio *serio) +{ + struct uart_sunzilog_port *up = serio->port_data; + unsigned long flags; + int ret; + + spin_lock_irqsave(&sunzilog_serio_lock, flags); + if (!up->serio_open) { + up->serio_open = 1; + ret = 0; + } else + ret = -EBUSY; + spin_unlock_irqrestore(&sunzilog_serio_lock, flags); + + return ret; +} + +static void sunzilog_serio_close(struct serio *serio) +{ + struct uart_sunzilog_port *up = serio->port_data; + unsigned long flags; + + spin_lock_irqsave(&sunzilog_serio_lock, flags); + up->serio_open = 0; + spin_unlock_irqrestore(&sunzilog_serio_lock, flags); +} + +#endif /* CONFIG_SERIO */ + +#ifdef CONFIG_SERIAL_SUNZILOG_CONSOLE +static void +sunzilog_console_write(struct console *con, const char *s, unsigned int count) +{ + struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; + unsigned long flags; + int locked = 1; + + 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, sunzilog_putchar); + udelay(2); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init sunzilog_console_setup(struct console *con, char *options) +{ + struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; + unsigned long flags; + int baud, brg; + + if (up->port.type != PORT_SUNZILOG) + return -1; + + printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n", + (sunzilog_reg.minor - 64) + con->index, con->index); + + /* Get firmware console settings. */ + sunserial_console_termios(con, up->port.dev->of_node); + + /* Firmware console speed is limited to 150-->38400 baud so + * this hackish cflag thing is OK. + */ + switch (con->cflag & CBAUD) { + case B150: baud = 150; break; + case B300: baud = 300; break; + case B600: baud = 600; break; + case B1200: baud = 1200; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + default: case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + }; + + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + + spin_lock_irqsave(&up->port.lock, flags); + + up->curregs[R15] |= BRKIE; + sunzilog_convert_to_zs(up, con->cflag, 0, brg); + + sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + __sunzilog_startup(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + + return 0; +} + +static struct console sunzilog_console_ops = { + .name = "ttyS", + .write = sunzilog_console_write, + .device = uart_console_device, + .setup = sunzilog_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sunzilog_reg, +}; + +static inline struct console *SUNZILOG_CONSOLE(void) +{ + return &sunzilog_console_ops; +} + +#else +#define SUNZILOG_CONSOLE() (NULL) +#endif + +static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) +{ + int baud, brg; + + if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { + up->cflag = B1200 | CS8 | CLOCAL | CREAD; + baud = 1200; + } else { + up->cflag = B4800 | CS8 | CLOCAL | CREAD; + baud = 4800; + } + + up->curregs[R15] |= BRKIE; + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + sunzilog_convert_to_zs(up, up->cflag, 0, brg); + sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + __sunzilog_startup(up); +} + +#ifdef CONFIG_SERIO +static void __devinit sunzilog_register_serio(struct uart_sunzilog_port *up) +{ + struct serio *serio = &up->serio; + + serio->port_data = up; + + serio->id.type = SERIO_RS232; + if (up->flags & SUNZILOG_FLAG_CONS_KEYB) { + serio->id.proto = SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); + } else { + serio->id.proto = SERIO_SUN; + serio->id.extra = 1; + strlcpy(serio->name, "zsms", sizeof(serio->name)); + } + strlcpy(serio->phys, + ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ? + "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); + + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; + serio->dev.parent = up->port.dev; + + serio_register_port(serio); +} +#endif + +static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) +{ + struct zilog_channel __iomem *channel; + unsigned long flags; + int baud, brg; + + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + + spin_lock_irqsave(&up->port.lock, flags); + if (ZS_IS_CHANNEL_A(up)) { + write_zsreg(channel, R9, FHWRES); + ZSDELAY_LONG(); + (void) read_zsreg(channel, R0); + } + + if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | + SUNZILOG_FLAG_CONS_MOUSE)) { + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R6] = 0x00; /* SDLC Address */ + up->curregs[R7] = 0x7E; /* SDLC Flag */ + up->curregs[R9] = NV; + up->curregs[R7p] = 0x00; + sunzilog_init_kbdms(up); + /* Only enable interrupts if an ISR handler available */ + if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) + up->curregs[R9] |= MIE; + write_zsreg(channel, R9, up->curregs[R9]); + } else { + /* Normal serial TTY. */ + up->parity_mask = 0xff; + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R6] = 0x00; /* SDLC Address */ + up->curregs[R7] = 0x7E; /* SDLC Flag */ + up->curregs[R9] = NV; + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + baud = 9600; + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRSRC | BRENAB; + up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */ + up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL; + if (__load_zsregs(channel, up->curregs)) { + up->flags |= SUNZILOG_FLAG_ESCC; + } + /* Only enable interrupts if an ISR handler available */ + if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) + up->curregs[R9] |= MIE; + write_zsreg(channel, R9, up->curregs[R9]); + } + + spin_unlock_irqrestore(&up->port.lock, flags); + +#ifdef CONFIG_SERIO + if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | + SUNZILOG_FLAG_CONS_MOUSE)) + sunzilog_register_serio(up); +#endif +} + +static int zilog_irq = -1; + +static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match) +{ + static int kbm_inst, uart_inst; + int inst; + struct uart_sunzilog_port *up; + struct zilog_layout __iomem *rp; + int keyboard_mouse = 0; + int err; + + if (of_find_property(op->dev.of_node, "keyboard", NULL)) + keyboard_mouse = 1; + + /* uarts must come before keyboards/mice */ + if (keyboard_mouse) + inst = uart_chip_count + kbm_inst; + else + inst = uart_inst; + + sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, + sizeof(struct zilog_layout), + "zs"); + if (!sunzilog_chip_regs[inst]) + return -ENOMEM; + + rp = sunzilog_chip_regs[inst]; + + if (zilog_irq == -1) + zilog_irq = op->archdata.irqs[0]; + + up = &sunzilog_port_table[inst * 2]; + + /* Channel A */ + up[0].port.mapbase = op->resource[0].start + 0x00; + up[0].port.membase = (void __iomem *) &rp->channelA; + up[0].port.iotype = UPIO_MEM; + up[0].port.irq = op->archdata.irqs[0]; + up[0].port.uartclk = ZS_CLOCK; + up[0].port.fifosize = 1; + up[0].port.ops = &sunzilog_pops; + up[0].port.type = PORT_SUNZILOG; + up[0].port.flags = 0; + up[0].port.line = (inst * 2) + 0; + up[0].port.dev = &op->dev; + up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; + if (keyboard_mouse) + up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; + sunzilog_init_hw(&up[0]); + + /* Channel B */ + up[1].port.mapbase = op->resource[0].start + 0x04; + up[1].port.membase = (void __iomem *) &rp->channelB; + up[1].port.iotype = UPIO_MEM; + up[1].port.irq = op->archdata.irqs[0]; + up[1].port.uartclk = ZS_CLOCK; + up[1].port.fifosize = 1; + up[1].port.ops = &sunzilog_pops; + up[1].port.type = PORT_SUNZILOG; + up[1].port.flags = 0; + up[1].port.line = (inst * 2) + 1; + up[1].port.dev = &op->dev; + up[1].flags |= 0; + if (keyboard_mouse) + up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; + sunzilog_init_hw(&up[1]); + + if (!keyboard_mouse) { + if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node, + &sunzilog_reg, up[0].port.line, + false)) + up->flags |= SUNZILOG_FLAG_IS_CONS; + err = uart_add_one_port(&sunzilog_reg, &up[0].port); + if (err) { + of_iounmap(&op->resource[0], + rp, sizeof(struct zilog_layout)); + return err; + } + if (sunserial_console_match(SUNZILOG_CONSOLE(), op->dev.of_node, + &sunzilog_reg, up[1].port.line, + false)) + up->flags |= SUNZILOG_FLAG_IS_CONS; + err = uart_add_one_port(&sunzilog_reg, &up[1].port); + if (err) { + uart_remove_one_port(&sunzilog_reg, &up[0].port); + of_iounmap(&op->resource[0], + rp, sizeof(struct zilog_layout)); + return err; + } + uart_inst++; + } else { + printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) " + "is a %s\n", + dev_name(&op->dev), + (unsigned long long) up[0].port.mapbase, + op->archdata.irqs[0], sunzilog_type(&up[0].port)); + printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) " + "is a %s\n", + dev_name(&op->dev), + (unsigned long long) up[1].port.mapbase, + op->archdata.irqs[0], sunzilog_type(&up[1].port)); + kbm_inst++; + } + + dev_set_drvdata(&op->dev, &up[0]); + + return 0; +} + +static void __devexit zs_remove_one(struct uart_sunzilog_port *up) +{ + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + serio_unregister_port(&up->serio); +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); +} + +static int __devexit zs_remove(struct platform_device *op) +{ + struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev); + struct zilog_layout __iomem *regs; + + zs_remove_one(&up[0]); + zs_remove_one(&up[1]); + + regs = sunzilog_chip_regs[up[0].port.line / 2]; + of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); + + dev_set_drvdata(&op->dev, NULL); + + return 0; +} + +static const struct of_device_id zs_match[] = { + { + .name = "zs", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, zs_match); + +static struct of_platform_driver zs_driver = { + .driver = { + .name = "zs", + .owner = THIS_MODULE, + .of_match_table = zs_match, + }, + .probe = zs_probe, + .remove = __devexit_p(zs_remove), +}; + +static int __init sunzilog_init(void) +{ + struct device_node *dp; + int err; + int num_keybms = 0; + int num_sunzilog = 0; + + for_each_node_by_name(dp, "zs") { + num_sunzilog++; + if (of_find_property(dp, "keyboard", NULL)) + num_keybms++; + } + + if (num_sunzilog) { + err = sunzilog_alloc_tables(num_sunzilog); + if (err) + goto out; + + uart_chip_count = num_sunzilog - num_keybms; + + err = sunserial_register_minors(&sunzilog_reg, + uart_chip_count * 2); + if (err) + goto out_free_tables; + } + + err = of_register_platform_driver(&zs_driver); + if (err) + goto out_unregister_uart; + + if (zilog_irq != -1) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; + err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, + "zs", sunzilog_irq_chain); + if (err) + goto out_unregister_driver; + + /* Enable Interrupts */ + while (up) { + struct zilog_channel __iomem *channel; + + /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->flags |= SUNZILOG_FLAG_ISR_HANDLER; + up->curregs[R9] |= MIE; + write_zsreg(channel, R9, up->curregs[R9]); + up = up->next; + } + } + +out: + return err; + +out_unregister_driver: + of_unregister_platform_driver(&zs_driver); + +out_unregister_uart: + if (num_sunzilog) { + sunserial_unregister_minors(&sunzilog_reg, num_sunzilog); + sunzilog_reg.cons = NULL; + } + +out_free_tables: + sunzilog_free_tables(); + goto out; +} + +static void __exit sunzilog_exit(void) +{ + of_unregister_platform_driver(&zs_driver); + + if (zilog_irq != -1) { + struct uart_sunzilog_port *up = sunzilog_irq_chain; + + /* Disable Interrupts */ + while (up) { + struct zilog_channel __iomem *channel; + + /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */ + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); + up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER; + up->curregs[R9] &= ~MIE; + write_zsreg(channel, R9, up->curregs[R9]); + up = up->next; + } + + free_irq(zilog_irq, sunzilog_irq_chain); + zilog_irq = -1; + } + + if (sunzilog_reg.nr) { + sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr); + sunzilog_free_tables(); + } +} + +module_init(sunzilog_init); +module_exit(sunzilog_exit); + +MODULE_AUTHOR("David S. Miller"); +MODULE_DESCRIPTION("Sun Zilog serial port driver"); +MODULE_VERSION("2.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/sunzilog.h b/drivers/tty/serial/sunzilog.h new file mode 100644 index 000000000000..5dec7b47cc38 --- /dev/null +++ b/drivers/tty/serial/sunzilog.h @@ -0,0 +1,289 @@ +#ifndef _SUNZILOG_H +#define _SUNZILOG_H + +struct zilog_channel { + volatile unsigned char control; + volatile unsigned char __pad1; + volatile unsigned char data; + volatile unsigned char __pad2; +}; + +struct zilog_layout { + struct zilog_channel channelB; + struct zilog_channel channelA; +}; + +#define NUM_ZSREGS 17 +#define R7p 16 /* Written as R7 with P15 bit 0 set */ + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ +#define RxINT_MASK 0x18 + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENAB 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxN_MASK 0xc0 + +/* Write Register 4 */ + +#define PAR_ENAB 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ +#define XCLK_MASK 0xC0 + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxN_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 7' (ESCC Only) */ +#define AUTO_TxFLAG 1 /* Automatic Tx SDLC Flag */ +#define AUTO_EOM_RST 2 /* Automatic EOM Reset */ +#define AUTOnRTS 4 /* Automatic /RTS pin deactivation */ +#define RxFIFO_LVL 8 /* Receive FIFO interrupt level */ +#define nDTRnREQ 0x10 /* /DTR/REQ timing */ +#define TxFIFO_LVL 0x20 /* Transmit FIFO interrupt level */ +#define EXT_RD_EN 0x40 /* Extended read register enable */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define SWIACK 0x20 /* Software Interrupt Ack (not on NMOS) */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENAB 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define WR7pEN 1 /* WR7' Enable (ESCC only) */ +#define ZCIE 2 /* Zero count IE */ +#define FIFOEN 4 /* FIFO Enable (ESCC only) */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define CRC_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ +#define CHB_Tx_EMPTY 0x00 +#define CHB_EXT_STAT 0x02 +#define CHB_Rx_AVAIL 0x04 +#define CHB_SPECIAL 0x06 +#define CHA_Tx_EMPTY 0x08 +#define CHA_EXT_STAT 0x0a +#define CHA_Rx_AVAIL 0x0c +#define CHA_SPECIAL 0x0e +#define STATUS_MASK 0x0e + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 6 (LSB frame byte count [Not on NMOS]) */ + +/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* Misc macros */ +#define ZS_CLEARERR(channel) do { sbus_writeb(ERR_RES, &channel->control); \ + udelay(5); } while(0) + +#define ZS_CLEARSTAT(channel) do { sbus_writeb(RES_EXT_INT, &channel->control); \ + udelay(5); } while(0) + +#define ZS_CLEARFIFO(channel) do { sbus_readb(&channel->data); \ + udelay(2); \ + sbus_readb(&channel->data); \ + udelay(2); \ + sbus_readb(&channel->data); \ + udelay(2); } while(0) + +#endif /* _SUNZILOG_H */ diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c new file mode 100644 index 000000000000..1f36b7eb7351 --- /dev/null +++ b/drivers/tty/serial/timbuart.c @@ -0,0 +1,531 @@ +/* + * timbuart.c timberdale FPGA UART driver + * Copyright (c) 2009 Intel Corporation + * + * 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. + * + * 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. + */ + +/* Supports: + * Timberdale FPGA UART + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "timbuart.h" + +struct timbuart_port { + struct uart_port port; + struct tasklet_struct tasklet; + int usedma; + u32 last_ier; + struct platform_device *dev; +}; + +static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, + 921600, 1843200, 3250000}; + +static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier); + +static irqreturn_t timbuart_handleinterrupt(int irq, void *devid); + +static void timbuart_stop_rx(struct uart_port *port) +{ + /* spin lock held by upper layer, disable all RX interrupts */ + u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS; + iowrite32(ier, port->membase + TIMBUART_IER); +} + +static void timbuart_stop_tx(struct uart_port *port) +{ + /* spinlock held by upper layer, disable TX interrupt */ + u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE; + iowrite32(ier, port->membase + TIMBUART_IER); +} + +static void timbuart_start_tx(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + + /* do not transfer anything here -> fire off the tasklet */ + tasklet_schedule(&uart->tasklet); +} + +static unsigned int timbuart_tx_empty(struct uart_port *port) +{ + u32 isr = ioread32(port->membase + TIMBUART_ISR); + + return (isr & TXBE) ? TIOCSER_TEMT : 0; +} + +static void timbuart_flush_buffer(struct uart_port *port) +{ + if (!timbuart_tx_empty(port)) { + u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | + TIMBUART_CTRL_FLSHTX; + + iowrite8(ctl, port->membase + TIMBUART_CTRL); + iowrite32(TXBF, port->membase + TIMBUART_ISR); + } +} + +static void timbuart_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = port->state->port.tty; + + while (ioread32(port->membase + TIMBUART_ISR) & RXDP) { + u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); + port->icount.rx++; + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(port->state->port.tty); + spin_lock(&port->lock); + + dev_dbg(port->dev, "%s - total read %d bytes\n", + __func__, port->icount.rx); +} + +static void timbuart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) && + !uart_circ_empty(xmit)) { + iowrite8(xmit->buf[xmit->tail], + port->membase + TIMBUART_TXFIFO); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + dev_dbg(port->dev, + "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", + __func__, + port->icount.tx, + ioread8(port->membase + TIMBUART_CTRL), + port->mctrl & TIOCM_RTS, + ioread8(port->membase + TIMBUART_BAUDRATE)); +} + +static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + struct circ_buf *xmit = &port->state->xmit; + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + if (port->x_char) + return; + + if (isr & TXFLAGS) { + timbuart_tx_chars(port); + /* clear all TX interrupts */ + iowrite32(TXFLAGS, port->membase + TIMBUART_ISR); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + } else + /* Re-enable any tx interrupt */ + *ier |= uart->last_ier & TXFLAGS; + + /* enable interrupts if there are chars in the transmit buffer, + * Or if we delivered some bytes and want the almost empty interrupt + * we wake up the upper layer later when we got the interrupt + * to give it some time to go out... + */ + if (!uart_circ_empty(xmit)) + *ier |= TXBAE; + + dev_dbg(port->dev, "%s - leaving\n", __func__); +} + +void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier) +{ + if (isr & RXFLAGS) { + /* Some RX status is set */ + if (isr & RXBF) { + u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | + TIMBUART_CTRL_FLSHRX; + iowrite8(ctl, port->membase + TIMBUART_CTRL); + port->icount.overrun++; + } else if (isr & (RXDP)) + timbuart_rx_chars(port); + + /* ack all RX interrupts */ + iowrite32(RXFLAGS, port->membase + TIMBUART_ISR); + } + + /* always have the RX interrupts enabled */ + *ier |= RXBAF | RXBF | RXTT; + + dev_dbg(port->dev, "%s - leaving\n", __func__); +} + +void timbuart_tasklet(unsigned long arg) +{ + struct timbuart_port *uart = (struct timbuart_port *)arg; + u32 isr, ier = 0; + + spin_lock(&uart->port.lock); + + isr = ioread32(uart->port.membase + TIMBUART_ISR); + dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); + + if (!uart->usedma) + timbuart_handle_tx_port(&uart->port, isr, &ier); + + timbuart_mctrl_check(&uart->port, isr, &ier); + + if (!uart->usedma) + timbuart_handle_rx_port(&uart->port, isr, &ier); + + iowrite32(ier, uart->port.membase + TIMBUART_IER); + + spin_unlock(&uart->port.lock); + dev_dbg(uart->port.dev, "%s leaving\n", __func__); +} + +static unsigned int timbuart_get_mctrl(struct uart_port *port) +{ + u8 cts = ioread8(port->membase + TIMBUART_CTRL); + dev_dbg(port->dev, "%s - cts %x\n", __func__, cts); + + if (cts & TIMBUART_CTRL_CTS) + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + else + return TIOCM_DSR | TIOCM_CAR; +} + +static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + dev_dbg(port->dev, "%s - %x\n", __func__, mctrl); + + if (mctrl & TIOCM_RTS) + iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); + else + iowrite8(0, port->membase + TIMBUART_CTRL); +} + +static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier) +{ + unsigned int cts; + + if (isr & CTS_DELTA) { + /* ack */ + iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR); + cts = timbuart_get_mctrl(port); + uart_handle_cts_change(port, cts & TIOCM_CTS); + wake_up_interruptible(&port->state->port.delta_msr_wait); + } + + *ier |= CTS_DELTA; +} + +static void timbuart_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void timbuart_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static int timbuart_startup(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + + dev_dbg(port->dev, "%s\n", __func__); + + iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL); + iowrite32(0x1ff, port->membase + TIMBUART_ISR); + /* Enable all but TX interrupts */ + iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA, + port->membase + TIMBUART_IER); + + return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED, + "timb-uart", uart); +} + +static void timbuart_shutdown(struct uart_port *port) +{ + struct timbuart_port *uart = + container_of(port, struct timbuart_port, port); + dev_dbg(port->dev, "%s\n", __func__); + free_irq(port->irq, uart); + iowrite32(0, port->membase + TIMBUART_IER); +} + +static int get_bindex(int baud) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(baudrates); i++) + if (baud <= baudrates[i]) + return i; + + return -1; +} + +static void timbuart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud; + short bindex; + unsigned long flags; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + bindex = get_bindex(baud); + dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); + + if (bindex < 0) + bindex = 0; + baud = baudrates[bindex]; + + /* The serial layer calls into this once with old = NULL when setting + up initially */ + if (old) + tty_termios_copy_hw(termios, old); + tty_termios_encode_baud_rate(termios, baud, baud); + + spin_lock_irqsave(&port->lock, flags); + iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *timbuart_type(struct uart_port *port) +{ + return port->type == PORT_UNKNOWN ? "timbuart" : NULL; +} + +/* We do not request/release mappings of the registers here, + * currently it's done in the proble function. + */ +static void timbuart_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = + resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, size); +} + +static int timbuart_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + int size = + resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); + + if (!request_mem_region(port->mapbase, size, "timb-uart")) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, size); + if (port->membase == NULL) { + release_mem_region(port->mapbase, size); + return -ENOMEM; + } + } + + return 0; +} + +static irqreturn_t timbuart_handleinterrupt(int irq, void *devid) +{ + struct timbuart_port *uart = (struct timbuart_port *)devid; + + if (ioread8(uart->port.membase + TIMBUART_IPR)) { + uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER); + + /* disable interrupts, the tasklet enables them again */ + iowrite32(0, uart->port.membase + TIMBUART_IER); + + /* fire off bottom half */ + tasklet_schedule(&uart->tasklet); + + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +/* + * Configure/autoconfigure the port. + */ +static void timbuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_TIMBUART; + timbuart_request_port(port); + } +} + +static int timbuart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + +static struct uart_ops timbuart_ops = { + .tx_empty = timbuart_tx_empty, + .set_mctrl = timbuart_set_mctrl, + .get_mctrl = timbuart_get_mctrl, + .stop_tx = timbuart_stop_tx, + .start_tx = timbuart_start_tx, + .flush_buffer = timbuart_flush_buffer, + .stop_rx = timbuart_stop_rx, + .enable_ms = timbuart_enable_ms, + .break_ctl = timbuart_break_ctl, + .startup = timbuart_startup, + .shutdown = timbuart_shutdown, + .set_termios = timbuart_set_termios, + .type = timbuart_type, + .release_port = timbuart_release_port, + .request_port = timbuart_request_port, + .config_port = timbuart_config_port, + .verify_port = timbuart_verify_port +}; + +static struct uart_driver timbuart_driver = { + .owner = THIS_MODULE, + .driver_name = "timberdale_uart", + .dev_name = "ttyTU", + .major = TIMBUART_MAJOR, + .minor = TIMBUART_MINOR, + .nr = 1 +}; + +static int __devinit timbuart_probe(struct platform_device *dev) +{ + int err, irq; + struct timbuart_port *uart; + struct resource *iomem; + + dev_dbg(&dev->dev, "%s\n", __func__); + + uart = kzalloc(sizeof(*uart), GFP_KERNEL); + if (!uart) { + err = -EINVAL; + goto err_mem; + } + + uart->usedma = 0; + + uart->port.uartclk = 3250000 * 16; + uart->port.fifosize = TIMBUART_FIFO_SIZE; + uart->port.regshift = 2; + uart->port.iotype = UPIO_MEM; + uart->port.ops = &timbuart_ops; + uart->port.irq = 0; + uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + uart->port.line = 0; + uart->port.dev = &dev->dev; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!iomem) { + err = -ENOMEM; + goto err_register; + } + uart->port.mapbase = iomem->start; + uart->port.membase = NULL; + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + err = -EINVAL; + goto err_register; + } + uart->port.irq = irq; + + tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); + + err = uart_register_driver(&timbuart_driver); + if (err) + goto err_register; + + err = uart_add_one_port(&timbuart_driver, &uart->port); + if (err) + goto err_add_port; + + platform_set_drvdata(dev, uart); + + return 0; + +err_add_port: + uart_unregister_driver(&timbuart_driver); +err_register: + kfree(uart); +err_mem: + printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n", + err); + + return err; +} + +static int __devexit timbuart_remove(struct platform_device *dev) +{ + struct timbuart_port *uart = platform_get_drvdata(dev); + + tasklet_kill(&uart->tasklet); + uart_remove_one_port(&timbuart_driver, &uart->port); + uart_unregister_driver(&timbuart_driver); + kfree(uart); + + return 0; +} + +static struct platform_driver timbuart_platform_driver = { + .driver = { + .name = "timb-uart", + .owner = THIS_MODULE, + }, + .probe = timbuart_probe, + .remove = __devexit_p(timbuart_remove), +}; + +/*--------------------------------------------------------------------------*/ + +static int __init timbuart_init(void) +{ + return platform_driver_register(&timbuart_platform_driver); +} + +static void __exit timbuart_exit(void) +{ + platform_driver_unregister(&timbuart_platform_driver); +} + +module_init(timbuart_init); +module_exit(timbuart_exit); + +MODULE_DESCRIPTION("Timberdale UART driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:timb-uart"); + diff --git a/drivers/tty/serial/timbuart.h b/drivers/tty/serial/timbuart.h new file mode 100644 index 000000000000..7e566766bc43 --- /dev/null +++ b/drivers/tty/serial/timbuart.h @@ -0,0 +1,58 @@ +/* + * timbuart.c timberdale FPGA GPIO driver + * Copyright (c) 2009 Intel Corporation + * + * 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. + * + * 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. + */ + +/* Supports: + * Timberdale FPGA UART + */ + +#ifndef _TIMBUART_H +#define _TIMBUART_H + +#define TIMBUART_FIFO_SIZE 2048 + +#define TIMBUART_RXFIFO 0x08 +#define TIMBUART_TXFIFO 0x0c +#define TIMBUART_IER 0x10 +#define TIMBUART_IPR 0x14 +#define TIMBUART_ISR 0x18 +#define TIMBUART_CTRL 0x1c +#define TIMBUART_BAUDRATE 0x20 + +#define TIMBUART_CTRL_RTS 0x01 +#define TIMBUART_CTRL_CTS 0x02 +#define TIMBUART_CTRL_FLSHTX 0x40 +#define TIMBUART_CTRL_FLSHRX 0x80 + +#define TXBF 0x01 +#define TXBAE 0x02 +#define CTS_DELTA 0x04 +#define RXDP 0x08 +#define RXBAF 0x10 +#define RXBF 0x20 +#define RXTT 0x40 +#define RXBNAE 0x80 +#define TXBE 0x100 + +#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE) +#define TXFLAGS (TXBF | TXBAE) + +#define TIMBUART_MAJOR 204 +#define TIMBUART_MINOR 192 + +#endif /* _TIMBUART_H */ + diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c new file mode 100644 index 000000000000..d2fce865b731 --- /dev/null +++ b/drivers/tty/serial/uartlite.c @@ -0,0 +1,709 @@ +/* + * uartlite.c: Serial driver for Xilinx uartlite serial controller + * + * Copyright (C) 2006 Peter Korsgaard + * Copyright (C) 2007 Secret Lab Technologies Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) +#include +#include +#include +#include + +/* Match table for of_platform binding */ +static struct of_device_id ulite_of_match[] __devinitdata = { + { .compatible = "xlnx,opb-uartlite-1.00.b", }, + { .compatible = "xlnx,xps-uartlite-1.00.a", }, + {} +}; +MODULE_DEVICE_TABLE(of, ulite_of_match); + +#endif + +#define ULITE_NAME "ttyUL" +#define ULITE_MAJOR 204 +#define ULITE_MINOR 187 +#define ULITE_NR_UARTS 4 + +/* --------------------------------------------------------------------- + * Register definitions + * + * For register details see datasheet: + * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf + */ + +#define ULITE_RX 0x00 +#define ULITE_TX 0x04 +#define ULITE_STATUS 0x08 +#define ULITE_CONTROL 0x0c + +#define ULITE_REGION 16 + +#define ULITE_STATUS_RXVALID 0x01 +#define ULITE_STATUS_RXFULL 0x02 +#define ULITE_STATUS_TXEMPTY 0x04 +#define ULITE_STATUS_TXFULL 0x08 +#define ULITE_STATUS_IE 0x10 +#define ULITE_STATUS_OVERRUN 0x20 +#define ULITE_STATUS_FRAME 0x40 +#define ULITE_STATUS_PARITY 0x80 + +#define ULITE_CONTROL_RST_TX 0x01 +#define ULITE_CONTROL_RST_RX 0x02 +#define ULITE_CONTROL_IE 0x10 + + +static struct uart_port ulite_ports[ULITE_NR_UARTS]; + +/* --------------------------------------------------------------------- + * Core UART driver operations + */ + +static int ulite_receive(struct uart_port *port, int stat) +{ + struct tty_struct *tty = port->state->port.tty; + unsigned char ch = 0; + char flag = TTY_NORMAL; + + if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_FRAME)) == 0) + return 0; + + /* stats */ + if (stat & ULITE_STATUS_RXVALID) { + port->icount.rx++; + ch = ioread32be(port->membase + ULITE_RX); + + if (stat & ULITE_STATUS_PARITY) + port->icount.parity++; + } + + if (stat & ULITE_STATUS_OVERRUN) + port->icount.overrun++; + + if (stat & ULITE_STATUS_FRAME) + port->icount.frame++; + + + /* drop byte with parity error if IGNPAR specificed */ + if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY) + stat &= ~ULITE_STATUS_RXVALID; + + stat &= port->read_status_mask; + + if (stat & ULITE_STATUS_PARITY) + flag = TTY_PARITY; + + + stat &= ~port->ignore_status_mask; + + if (stat & ULITE_STATUS_RXVALID) + tty_insert_flip_char(tty, ch, flag); + + if (stat & ULITE_STATUS_FRAME) + tty_insert_flip_char(tty, 0, TTY_FRAME); + + if (stat & ULITE_STATUS_OVERRUN) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + return 1; +} + +static int ulite_transmit(struct uart_port *port, int stat) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (stat & ULITE_STATUS_TXFULL) + return 0; + + if (port->x_char) { + iowrite32be(port->x_char, port->membase + ULITE_TX); + port->x_char = 0; + port->icount.tx++; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return 0; + + iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); + port->icount.tx++; + + /* wake up */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + return 1; +} + +static irqreturn_t ulite_isr(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + int busy, n = 0; + + do { + int stat = ioread32be(port->membase + ULITE_STATUS); + busy = ulite_receive(port, stat); + busy |= ulite_transmit(port, stat); + n++; + } while (busy); + + /* work done? */ + if (n > 1) { + tty_flip_buffer_push(port->state->port.tty); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +static unsigned int ulite_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + ret = ioread32be(port->membase + ULITE_STATUS); + spin_unlock_irqrestore(&port->lock, flags); + + return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int ulite_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void ulite_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* N/A */ +} + +static void ulite_stop_tx(struct uart_port *port) +{ + /* N/A */ +} + +static void ulite_start_tx(struct uart_port *port) +{ + ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS)); +} + +static void ulite_stop_rx(struct uart_port *port) +{ + /* don't forward any more data (like !CREAD) */ + port->ignore_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; +} + +static void ulite_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void ulite_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static int ulite_startup(struct uart_port *port) +{ + int ret; + + ret = request_irq(port->irq, ulite_isr, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, "uartlite", port); + if (ret) + return ret; + + iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, + port->membase + ULITE_CONTROL); + iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + + return 0; +} + +static void ulite_shutdown(struct uart_port *port) +{ + iowrite32be(0, port->membase + ULITE_CONTROL); + ioread32be(port->membase + ULITE_CONTROL); /* dummy */ + free_irq(port->irq, port); +} + +static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud; + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN + | ULITE_STATUS_TXFULL; + + if (termios->c_iflag & INPCK) + port->read_status_mask |= + ULITE_STATUS_PARITY | ULITE_STATUS_FRAME; + + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; + + /* ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= + ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY + | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN; + + /* update timeout */ + baud = uart_get_baud_rate(port, termios, old, 0, 460800); + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *ulite_type(struct uart_port *port) +{ + return port->type == PORT_UARTLITE ? "uartlite" : NULL; +} + +static void ulite_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, ULITE_REGION); + iounmap(port->membase); + port->membase = NULL; +} + +static int ulite_request_port(struct uart_port *port) +{ + pr_debug("ulite console: port=%p; port->mapbase=%llx\n", + port, (unsigned long long) port->mapbase); + + if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) { + dev_err(port->dev, "Memory region busy\n"); + return -EBUSY; + } + + port->membase = ioremap(port->mapbase, ULITE_REGION); + if (!port->membase) { + dev_err(port->dev, "Unable to map registers\n"); + release_mem_region(port->mapbase, ULITE_REGION); + return -EBUSY; + } + + return 0; +} + +static void ulite_config_port(struct uart_port *port, int flags) +{ + if (!ulite_request_port(port)) + port->type = PORT_UARTLITE; +} + +static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* we don't want the core code to modify any port params */ + return -EINVAL; +} + +#ifdef CONFIG_CONSOLE_POLL +static int ulite_get_poll_char(struct uart_port *port) +{ + if (!(ioread32be(port->membase + ULITE_STATUS) + & ULITE_STATUS_RXVALID)) + return NO_POLL_CHAR; + + return ioread32be(port->membase + ULITE_RX); +} + +static void ulite_put_poll_char(struct uart_port *port, unsigned char ch) +{ + while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL) + cpu_relax(); + + /* write char to device */ + iowrite32be(ch, port->membase + ULITE_TX); +} +#endif + +static struct uart_ops ulite_ops = { + .tx_empty = ulite_tx_empty, + .set_mctrl = ulite_set_mctrl, + .get_mctrl = ulite_get_mctrl, + .stop_tx = ulite_stop_tx, + .start_tx = ulite_start_tx, + .stop_rx = ulite_stop_rx, + .enable_ms = ulite_enable_ms, + .break_ctl = ulite_break_ctl, + .startup = ulite_startup, + .shutdown = ulite_shutdown, + .set_termios = ulite_set_termios, + .type = ulite_type, + .release_port = ulite_release_port, + .request_port = ulite_request_port, + .config_port = ulite_config_port, + .verify_port = ulite_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = ulite_get_poll_char, + .poll_put_char = ulite_put_poll_char, +#endif +}; + +/* --------------------------------------------------------------------- + * Console driver operations + */ + +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE +static void ulite_console_wait_tx(struct uart_port *port) +{ + int i; + u8 val; + + /* Spin waiting for TX fifo to have space available */ + for (i = 0; i < 100000; i++) { + val = ioread32be(port->membase + ULITE_STATUS); + if ((val & ULITE_STATUS_TXFULL) == 0) + break; + cpu_relax(); + } +} + +static void ulite_console_putchar(struct uart_port *port, int ch) +{ + ulite_console_wait_tx(port); + iowrite32be(ch, port->membase + ULITE_TX); +} + +static void ulite_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = &ulite_ports[co->index]; + unsigned long flags; + unsigned int ier; + int locked = 1; + + if (oops_in_progress) { + locked = spin_trylock_irqsave(&port->lock, flags); + } else + spin_lock_irqsave(&port->lock, flags); + + /* save and disable interrupt */ + ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; + iowrite32be(0, port->membase + ULITE_CONTROL); + + uart_console_write(port, s, count, ulite_console_putchar); + + ulite_console_wait_tx(port); + + /* restore interrupt state */ + if (ier) + iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); +} + +static int __devinit ulite_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= ULITE_NR_UARTS) + return -EINVAL; + + port = &ulite_ports[co->index]; + + /* Has the device been initialized yet? */ + if (!port->mapbase) { + pr_debug("console on ttyUL%i not present\n", co->index); + return -ENODEV; + } + + /* not initialized yet? */ + if (!port->membase) { + if (ulite_request_port(port)) + 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 ulite_uart_driver; + +static struct console ulite_console = { + .name = ULITE_NAME, + .write = ulite_console_write, + .device = uart_console_device, + .setup = ulite_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, /* Specified on the cmdline (e.g. console=ttyUL0 ) */ + .data = &ulite_uart_driver, +}; + +static int __init ulite_console_init(void) +{ + register_console(&ulite_console); + return 0; +} + +console_initcall(ulite_console_init); + +#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ + +static struct uart_driver ulite_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "uartlite", + .dev_name = ULITE_NAME, + .major = ULITE_MAJOR, + .minor = ULITE_MINOR, + .nr = ULITE_NR_UARTS, +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE + .cons = &ulite_console, +#endif +}; + +/* --------------------------------------------------------------------- + * Port assignment functions (mapping devices to uart_port structures) + */ + +/** ulite_assign: register a uartlite device with the driver + * + * @dev: pointer to device structure + * @id: requested id number. Pass -1 for automatic port assignment + * @base: base address of uartlite registers + * @irq: irq number for uartlite + * + * Returns: 0 on success, <0 otherwise + */ +static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) +{ + struct uart_port *port; + int rc; + + /* if id = -1; then scan for a free id and use that */ + if (id < 0) { + for (id = 0; id < ULITE_NR_UARTS; id++) + if (ulite_ports[id].mapbase == 0) + break; + } + if (id < 0 || id >= ULITE_NR_UARTS) { + dev_err(dev, "%s%i too large\n", ULITE_NAME, id); + return -EINVAL; + } + + if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) { + dev_err(dev, "cannot assign to %s%i; it is already in use\n", + ULITE_NAME, id); + return -EBUSY; + } + + port = &ulite_ports[id]; + + spin_lock_init(&port->lock); + port->fifosize = 16; + port->regshift = 2; + port->iotype = UPIO_MEM; + port->iobase = 1; /* mark port in use */ + port->mapbase = base; + port->membase = NULL; + port->ops = &ulite_ops; + port->irq = irq; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = dev; + port->type = PORT_UNKNOWN; + port->line = id; + + dev_set_drvdata(dev, port); + + /* Register the port */ + rc = uart_add_one_port(&ulite_uart_driver, port); + if (rc) { + dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc); + port->mapbase = 0; + dev_set_drvdata(dev, NULL); + return rc; + } + + return 0; +} + +/** ulite_release: register a uartlite device with the driver + * + * @dev: pointer to device structure + */ +static int __devexit ulite_release(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + int rc = 0; + + if (port) { + rc = uart_remove_one_port(&ulite_uart_driver, port); + dev_set_drvdata(dev, NULL); + port->mapbase = 0; + } + + return rc; +} + +/* --------------------------------------------------------------------- + * Platform bus binding + */ + +static int __devinit ulite_probe(struct platform_device *pdev) +{ + struct resource *res, *res2; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; + + return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); +} + +static int __devexit ulite_remove(struct platform_device *pdev) +{ + return ulite_release(&pdev->dev); +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:uartlite"); + +static struct platform_driver ulite_platform_driver = { + .probe = ulite_probe, + .remove = __devexit_p(ulite_remove), + .driver = { + .owner = THIS_MODULE, + .name = "uartlite", + }, +}; + +/* --------------------------------------------------------------------- + * OF bus bindings + */ +#if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) +static int __devinit +ulite_of_probe(struct platform_device *op, const struct of_device_id *match) +{ + struct resource res; + const unsigned int *id; + int irq, rc; + + dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match); + + rc = of_address_to_resource(op->dev.of_node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + + irq = irq_of_parse_and_map(op->dev.of_node, 0); + + id = of_get_property(op->dev.of_node, "port-number", NULL); + + return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); +} + +static int __devexit ulite_of_remove(struct platform_device *op) +{ + return ulite_release(&op->dev); +} + +static struct of_platform_driver ulite_of_driver = { + .probe = ulite_of_probe, + .remove = __devexit_p(ulite_of_remove), + .driver = { + .name = "uartlite", + .owner = THIS_MODULE, + .of_match_table = ulite_of_match, + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init ulite_of_register(void) +{ + pr_debug("uartlite: calling of_register_platform_driver()\n"); + return of_register_platform_driver(&ulite_of_driver); +} + +static inline void __exit ulite_of_unregister(void) +{ + of_unregister_platform_driver(&ulite_of_driver); +} +#else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ +/* Appropriate config not enabled; do nothing helpers */ +static inline int __init ulite_of_register(void) { return 0; } +static inline void __exit ulite_of_unregister(void) { } +#endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ + +/* --------------------------------------------------------------------- + * Module setup/teardown + */ + +int __init ulite_init(void) +{ + int ret; + + pr_debug("uartlite: calling uart_register_driver()\n"); + ret = uart_register_driver(&ulite_uart_driver); + if (ret) + goto err_uart; + + ret = ulite_of_register(); + if (ret) + goto err_of; + + pr_debug("uartlite: calling platform_driver_register()\n"); + ret = platform_driver_register(&ulite_platform_driver); + if (ret) + goto err_plat; + + return 0; + +err_plat: + ulite_of_unregister(); +err_of: + uart_unregister_driver(&ulite_uart_driver); +err_uart: + printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); + return ret; +} + +void __exit ulite_exit(void) +{ + platform_driver_unregister(&ulite_platform_driver); + ulite_of_unregister(); + uart_unregister_driver(&ulite_uart_driver); +} + +module_init(ulite_init); +module_exit(ulite_exit); + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_DESCRIPTION("Xilinx uartlite serial driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c new file mode 100644 index 000000000000..3f4848e2174a --- /dev/null +++ b/drivers/tty/serial/ucc_uart.c @@ -0,0 +1,1537 @@ +/* + * Freescale QUICC Engine UART device driver + * + * Author: Timur Tabi + * + * Copyright 2007 Freescale Semiconductor, Inc. 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. + * + * This driver adds support for UART devices via Freescale's QUICC Engine + * found on some Freescale SOCs. + * + * If Soft-UART support is needed but not already present, then this driver + * will request and upload the "Soft-UART" microcode upon probe. The + * filename of the microcode should be fsl_qe_ucode_uart_X_YZ.bin, where "X" + * is the name of the SOC (e.g. 8323), and YZ is the revision of the SOC, + * (e.g. "11" for 1.1). + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* + * The GUMR flag for Soft UART. This would normally be defined in qe.h, + * but Soft-UART is a hack and we want to keep everything related to it in + * this file. + */ +#define UCC_SLOW_GUMR_H_SUART 0x00004000 /* Soft-UART */ + +/* + * soft_uart is 1 if we need to use Soft-UART mode + */ +static int soft_uart; +/* + * firmware_loaded is 1 if the firmware has been loaded, 0 otherwise. + */ +static int firmware_loaded; + +/* Enable this macro to configure all serial ports in internal loopback + mode */ +/* #define LOOPBACK */ + +/* The major and minor device numbers are defined in + * http://www.lanana.org/docs/device-list/devices-2.6+.txt. For the QE + * UART, we have major number 204 and minor numbers 46 - 49, which are the + * same as for the CPM2. This decision was made because no Freescale part + * has both a CPM and a QE. + */ +#define SERIAL_QE_MAJOR 204 +#define SERIAL_QE_MINOR 46 + +/* Since we only have minor numbers 46 - 49, there is a hard limit of 4 ports */ +#define UCC_MAX_UART 4 + +/* The number of buffer descriptors for receiving characters. */ +#define RX_NUM_FIFO 4 + +/* The number of buffer descriptors for transmitting characters. */ +#define TX_NUM_FIFO 4 + +/* The maximum size of the character buffer for a single RX BD. */ +#define RX_BUF_SIZE 32 + +/* The maximum size of the character buffer for a single TX BD. */ +#define TX_BUF_SIZE 32 + +/* + * The number of jiffies to wait after receiving a close command before the + * device is actually closed. This allows the last few characters to be + * sent over the wire. + */ +#define UCC_WAIT_CLOSING 100 + +struct ucc_uart_pram { + struct ucc_slow_pram common; + u8 res1[8]; /* reserved */ + __be16 maxidl; /* Maximum idle chars */ + __be16 idlc; /* temp idle counter */ + __be16 brkcr; /* Break count register */ + __be16 parec; /* receive parity error counter */ + __be16 frmec; /* receive framing error counter */ + __be16 nosec; /* receive noise counter */ + __be16 brkec; /* receive break condition counter */ + __be16 brkln; /* last received break length */ + __be16 uaddr[2]; /* UART address character 1 & 2 */ + __be16 rtemp; /* Temp storage */ + __be16 toseq; /* Transmit out of sequence char */ + __be16 cchars[8]; /* control characters 1-8 */ + __be16 rccm; /* receive control character mask */ + __be16 rccr; /* receive control character register */ + __be16 rlbc; /* receive last break character */ + __be16 res2; /* reserved */ + __be32 res3; /* reserved, should be cleared */ + u8 res4; /* reserved, should be cleared */ + u8 res5[3]; /* reserved, should be cleared */ + __be32 res6; /* reserved, should be cleared */ + __be32 res7; /* reserved, should be cleared */ + __be32 res8; /* reserved, should be cleared */ + __be32 res9; /* reserved, should be cleared */ + __be32 res10; /* reserved, should be cleared */ + __be32 res11; /* reserved, should be cleared */ + __be32 res12; /* reserved, should be cleared */ + __be32 res13; /* reserved, should be cleared */ +/* The rest is for Soft-UART only */ + __be16 supsmr; /* 0x90, Shadow UPSMR */ + __be16 res92; /* 0x92, reserved, initialize to 0 */ + __be32 rx_state; /* 0x94, RX state, initialize to 0 */ + __be32 rx_cnt; /* 0x98, RX count, initialize to 0 */ + u8 rx_length; /* 0x9C, Char length, set to 1+CL+PEN+1+SL */ + u8 rx_bitmark; /* 0x9D, reserved, initialize to 0 */ + u8 rx_temp_dlst_qe; /* 0x9E, reserved, initialize to 0 */ + u8 res14[0xBC - 0x9F]; /* reserved */ + __be32 dump_ptr; /* 0xBC, Dump pointer */ + __be32 rx_frame_rem; /* 0xC0, reserved, initialize to 0 */ + u8 rx_frame_rem_size; /* 0xC4, reserved, initialize to 0 */ + u8 tx_mode; /* 0xC5, mode, 0=AHDLC, 1=UART */ + __be16 tx_state; /* 0xC6, TX state */ + u8 res15[0xD0 - 0xC8]; /* reserved */ + __be32 resD0; /* 0xD0, reserved, initialize to 0 */ + u8 resD4; /* 0xD4, reserved, initialize to 0 */ + __be16 resD5; /* 0xD5, reserved, initialize to 0 */ +} __attribute__ ((packed)); + +/* SUPSMR definitions, for Soft-UART only */ +#define UCC_UART_SUPSMR_SL 0x8000 +#define UCC_UART_SUPSMR_RPM_MASK 0x6000 +#define UCC_UART_SUPSMR_RPM_ODD 0x0000 +#define UCC_UART_SUPSMR_RPM_LOW 0x2000 +#define UCC_UART_SUPSMR_RPM_EVEN 0x4000 +#define UCC_UART_SUPSMR_RPM_HIGH 0x6000 +#define UCC_UART_SUPSMR_PEN 0x1000 +#define UCC_UART_SUPSMR_TPM_MASK 0x0C00 +#define UCC_UART_SUPSMR_TPM_ODD 0x0000 +#define UCC_UART_SUPSMR_TPM_LOW 0x0400 +#define UCC_UART_SUPSMR_TPM_EVEN 0x0800 +#define UCC_UART_SUPSMR_TPM_HIGH 0x0C00 +#define UCC_UART_SUPSMR_FRZ 0x0100 +#define UCC_UART_SUPSMR_UM_MASK 0x00c0 +#define UCC_UART_SUPSMR_UM_NORMAL 0x0000 +#define UCC_UART_SUPSMR_UM_MAN_MULTI 0x0040 +#define UCC_UART_SUPSMR_UM_AUTO_MULTI 0x00c0 +#define UCC_UART_SUPSMR_CL_MASK 0x0030 +#define UCC_UART_SUPSMR_CL_8 0x0030 +#define UCC_UART_SUPSMR_CL_7 0x0020 +#define UCC_UART_SUPSMR_CL_6 0x0010 +#define UCC_UART_SUPSMR_CL_5 0x0000 + +#define UCC_UART_TX_STATE_AHDLC 0x00 +#define UCC_UART_TX_STATE_UART 0x01 +#define UCC_UART_TX_STATE_X1 0x00 +#define UCC_UART_TX_STATE_X16 0x80 + +#define UCC_UART_PRAM_ALIGNMENT 0x100 + +#define UCC_UART_SIZE_OF_BD UCC_SLOW_SIZE_OF_BD +#define NUM_CONTROL_CHARS 8 + +/* Private per-port data structure */ +struct uart_qe_port { + struct uart_port port; + struct ucc_slow __iomem *uccp; + struct ucc_uart_pram __iomem *uccup; + struct ucc_slow_info us_info; + struct ucc_slow_private *us_private; + struct device_node *np; + unsigned int ucc_num; /* First ucc is 0, not 1 */ + + u16 rx_nrfifos; + u16 rx_fifosize; + u16 tx_nrfifos; + u16 tx_fifosize; + int wait_closing; + u32 flags; + struct qe_bd *rx_bd_base; + struct qe_bd *rx_cur; + struct qe_bd *tx_bd_base; + struct qe_bd *tx_cur; + unsigned char *tx_buf; + unsigned char *rx_buf; + void *bd_virt; /* virtual address of the BD buffers */ + dma_addr_t bd_dma_addr; /* bus address of the BD buffers */ + unsigned int bd_size; /* size of BD buffer space */ +}; + +static struct uart_driver ucc_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "ucc_uart", + .dev_name = "ttyQE", + .major = SERIAL_QE_MAJOR, + .minor = SERIAL_QE_MINOR, + .nr = UCC_MAX_UART, +}; + +/* + * Virtual to physical address translation. + * + * Given the virtual address for a character buffer, this function returns + * the physical (DMA) equivalent. + */ +static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port) +{ + if (likely((addr >= qe_port->bd_virt)) && + (addr < (qe_port->bd_virt + qe_port->bd_size))) + return qe_port->bd_dma_addr + (addr - qe_port->bd_virt); + + /* something nasty happened */ + printk(KERN_ERR "%s: addr=%p\n", __func__, addr); + BUG(); + return 0; +} + +/* + * Physical to virtual address translation. + * + * Given the physical (DMA) address for a character buffer, this function + * returns the virtual equivalent. + */ +static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port) +{ + /* sanity check */ + if (likely((addr >= qe_port->bd_dma_addr) && + (addr < (qe_port->bd_dma_addr + qe_port->bd_size)))) + return qe_port->bd_virt + (addr - qe_port->bd_dma_addr); + + /* something nasty happened */ + printk(KERN_ERR "%s: addr=%x\n", __func__, addr); + BUG(); + return NULL; +} + +/* + * Return 1 if the QE is done transmitting all buffers for this port + * + * This function scans each BD in sequence. If we find a BD that is not + * ready (READY=1), then we return 0 indicating that the QE is still sending + * data. If we reach the last BD (WRAP=1), then we know we've scanned + * the entire list, and all BDs are done. + */ +static unsigned int qe_uart_tx_empty(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct qe_bd *bdp = qe_port->tx_bd_base; + + while (1) { + if (in_be16(&bdp->status) & BD_SC_READY) + /* This BD is not done, so return "not done" */ + return 0; + + if (in_be16(&bdp->status) & BD_SC_WRAP) + /* + * This BD is done and it's the last one, so return + * "done" + */ + return 1; + + bdp++; + }; +} + +/* + * Set the modem control lines + * + * Although the QE can control the modem control lines (e.g. CTS), we + * don't need that support. This function must exist, however, otherwise + * the kernel will panic. + */ +void qe_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/* + * Get the current modem control line status + * + * Although the QE can control the modem control lines (e.g. CTS), this + * driver currently doesn't support that, so we always return Carrier + * Detect, Data Set Ready, and Clear To Send. + */ +static unsigned int qe_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* + * Disable the transmit interrupt. + * + * Although this function is called "stop_tx", it does not actually stop + * transmission of data. Instead, it tells the QE to not generate an + * interrupt when the UCC is finished sending characters. + */ +static void qe_uart_stop_tx(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); +} + +/* + * Transmit as many characters to the HW as possible. + * + * This function will attempt to stuff of all the characters from the + * kernel's transmit buffer into TX BDs. + * + * A return value of non-zero indicates that it successfully stuffed all + * characters from the kernel buffer. + * + * A return value of zero indicates that there are still characters in the + * kernel's buffer that have not been transmitted, but there are no more BDs + * available. This function should be called again after a BD has been made + * available. + */ +static int qe_uart_tx_pump(struct uart_qe_port *qe_port) +{ + struct qe_bd *bdp; + unsigned char *p; + unsigned int count; + struct uart_port *port = &qe_port->port; + struct circ_buf *xmit = &port->state->xmit; + + bdp = qe_port->rx_cur; + + /* Handle xon/xoff */ + if (port->x_char) { + /* Pick next descriptor and fill from buffer */ + bdp = qe_port->tx_cur; + + p = qe2cpu_addr(bdp->buf, qe_port); + + *p++ = port->x_char; + out_be16(&bdp->length, 1); + setbits16(&bdp->status, BD_SC_READY); + /* Get next BD. */ + if (in_be16(&bdp->status) & BD_SC_WRAP) + bdp = qe_port->tx_bd_base; + else + bdp++; + qe_port->tx_cur = bdp; + + port->icount.tx++; + port->x_char = 0; + return 1; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + qe_uart_stop_tx(port); + return 0; + } + + /* Pick next descriptor and fill from buffer */ + bdp = qe_port->tx_cur; + + while (!(in_be16(&bdp->status) & BD_SC_READY) && + (xmit->tail != xmit->head)) { + count = 0; + p = qe2cpu_addr(bdp->buf, qe_port); + while (count < qe_port->tx_fifosize) { + *p++ = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + count++; + if (xmit->head == xmit->tail) + break; + } + + out_be16(&bdp->length, count); + setbits16(&bdp->status, BD_SC_READY); + + /* Get next BD. */ + if (in_be16(&bdp->status) & BD_SC_WRAP) + bdp = qe_port->tx_bd_base; + else + bdp++; + } + qe_port->tx_cur = bdp; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) { + /* The kernel buffer is empty, so turn off TX interrupts. We + don't need to be told when the QE is finished transmitting + the data. */ + qe_uart_stop_tx(port); + return 0; + } + + return 1; +} + +/* + * Start transmitting data + * + * This function will start transmitting any available data, if the port + * isn't already transmitting data. + */ +static void qe_uart_start_tx(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + /* If we currently are transmitting, then just return */ + if (in_be16(&qe_port->uccp->uccm) & UCC_UART_UCCE_TX) + return; + + /* Otherwise, pump the port and start transmission */ + if (qe_uart_tx_pump(qe_port)) + setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_TX); +} + +/* + * Stop transmitting data + */ +static void qe_uart_stop_rx(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + clrbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); +} + +/* + * Enable status change interrupts + * + * We don't support status change interrupts, but we need to define this + * function otherwise the kernel will panic. + */ +static void qe_uart_enable_ms(struct uart_port *port) +{ +} + +/* Start or stop sending break signal + * + * This function controls the sending of a break signal. If break_state=1, + * then we start sending a break signal. If break_state=0, then we stop + * sending the break signal. + */ +static void qe_uart_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + + if (break_state) + ucc_slow_stop_tx(qe_port->us_private); + else + ucc_slow_restart_tx(qe_port->us_private); +} + +/* ISR helper function for receiving character. + * + * This function is called by the ISR to handling receiving characters + */ +static void qe_uart_int_rx(struct uart_qe_port *qe_port) +{ + int i; + unsigned char ch, *cp; + struct uart_port *port = &qe_port->port; + struct tty_struct *tty = port->state->port.tty; + struct qe_bd *bdp; + u16 status; + unsigned int flg; + + /* Just loop through the closed BDs and copy the characters into + * the buffer. + */ + bdp = qe_port->rx_cur; + while (1) { + status = in_be16(&bdp->status); + + /* If this one is empty, then we assume we've read them all */ + if (status & BD_SC_EMPTY) + break; + + /* get number of characters, and check space in RX buffer */ + i = in_be16(&bdp->length); + + /* If we don't have enough room in RX buffer for the entire BD, + * then we try later, which will be the next RX interrupt. + */ + if (tty_buffer_request_room(tty, i) < i) { + dev_dbg(port->dev, "ucc-uart: no room in RX buffer\n"); + return; + } + + /* get pointer */ + cp = qe2cpu_addr(bdp->buf, qe_port); + + /* loop through the buffer */ + while (i-- > 0) { + ch = *cp++; + port->icount.rx++; + flg = TTY_NORMAL; + + if (!i && status & + (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) + goto handle_error; + if (uart_handle_sysrq_char(port, ch)) + continue; + +error_return: + tty_insert_flip_char(tty, ch, flg); + + } + + /* This BD is ready to be used again. Clear status. get next */ + clrsetbits_be16(&bdp->status, BD_SC_BR | BD_SC_FR | BD_SC_PR | + BD_SC_OV | BD_SC_ID, BD_SC_EMPTY); + if (in_be16(&bdp->status) & BD_SC_WRAP) + bdp = qe_port->rx_bd_base; + else + bdp++; + + } + + /* Write back buffer pointer */ + qe_port->rx_cur = bdp; + + /* Activate BH processing */ + tty_flip_buffer_push(tty); + + return; + + /* Error processing */ + +handle_error: + /* Statistics */ + if (status & BD_SC_BR) + port->icount.brk++; + if (status & BD_SC_PR) + port->icount.parity++; + if (status & BD_SC_FR) + port->icount.frame++; + if (status & BD_SC_OV) + port->icount.overrun++; + + /* Mask out ignored conditions */ + status &= port->read_status_mask; + + /* Handle the remaining ones */ + if (status & BD_SC_BR) + flg = TTY_BREAK; + else if (status & BD_SC_PR) + flg = TTY_PARITY; + else if (status & BD_SC_FR) + flg = TTY_FRAME; + + /* Overrun does not affect the current character ! */ + if (status & BD_SC_OV) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + goto error_return; +} + +/* Interrupt handler + * + * This interrupt handler is called after a BD is processed. + */ +static irqreturn_t qe_uart_int(int irq, void *data) +{ + struct uart_qe_port *qe_port = (struct uart_qe_port *) data; + struct ucc_slow __iomem *uccp = qe_port->uccp; + u16 events; + + /* Clear the interrupts */ + events = in_be16(&uccp->ucce); + out_be16(&uccp->ucce, events); + + if (events & UCC_UART_UCCE_BRKE) + uart_handle_break(&qe_port->port); + + if (events & UCC_UART_UCCE_RX) + qe_uart_int_rx(qe_port); + + if (events & UCC_UART_UCCE_TX) + qe_uart_tx_pump(qe_port); + + return events ? IRQ_HANDLED : IRQ_NONE; +} + +/* Initialize buffer descriptors + * + * This function initializes all of the RX and TX buffer descriptors. + */ +static void qe_uart_initbd(struct uart_qe_port *qe_port) +{ + int i; + void *bd_virt; + struct qe_bd *bdp; + + /* Set the physical address of the host memory buffers in the buffer + * descriptors, and the virtual address for us to work with. + */ + bd_virt = qe_port->bd_virt; + bdp = qe_port->rx_bd_base; + qe_port->rx_cur = qe_port->rx_bd_base; + for (i = 0; i < (qe_port->rx_nrfifos - 1); i++) { + out_be16(&bdp->status, BD_SC_EMPTY | BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); + bd_virt += qe_port->rx_fifosize; + bdp++; + } + + /* */ + out_be16(&bdp->status, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + bd_virt = qe_port->bd_virt + + L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); + qe_port->tx_cur = qe_port->tx_bd_base; + bdp = qe_port->tx_bd_base; + for (i = 0; i < (qe_port->tx_nrfifos - 1); i++) { + out_be16(&bdp->status, BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); + bd_virt += qe_port->tx_fifosize; + bdp++; + } + + /* Loopback requires the preamble bit to be set on the first TX BD */ +#ifdef LOOPBACK + setbits16(&qe_port->tx_cur->status, BD_SC_P); +#endif + + out_be16(&bdp->status, BD_SC_WRAP | BD_SC_INTRPT); + out_be32(&bdp->buf, cpu2qe_addr(bd_virt, qe_port)); + out_be16(&bdp->length, 0); +} + +/* + * Initialize a UCC for UART. + * + * This function configures a given UCC to be used as a UART device. Basic + * UCC initialization is handled in qe_uart_request_port(). This function + * does all the UART-specific stuff. + */ +static void qe_uart_init_ucc(struct uart_qe_port *qe_port) +{ + u32 cecr_subblock; + struct ucc_slow __iomem *uccp = qe_port->uccp; + struct ucc_uart_pram *uccup = qe_port->uccup; + + unsigned int i; + + /* First, disable TX and RX in the UCC */ + ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); + + /* Program the UCC UART parameter RAM */ + out_8(&uccup->common.rbmr, UCC_BMR_GBL | UCC_BMR_BO_BE); + out_8(&uccup->common.tbmr, UCC_BMR_GBL | UCC_BMR_BO_BE); + out_be16(&uccup->common.mrblr, qe_port->rx_fifosize); + out_be16(&uccup->maxidl, 0x10); + out_be16(&uccup->brkcr, 1); + out_be16(&uccup->parec, 0); + out_be16(&uccup->frmec, 0); + out_be16(&uccup->nosec, 0); + out_be16(&uccup->brkec, 0); + out_be16(&uccup->uaddr[0], 0); + out_be16(&uccup->uaddr[1], 0); + out_be16(&uccup->toseq, 0); + for (i = 0; i < 8; i++) + out_be16(&uccup->cchars[i], 0xC000); + out_be16(&uccup->rccm, 0xc0ff); + + /* Configure the GUMR registers for UART */ + if (soft_uart) { + /* Soft-UART requires a 1X multiplier for TX */ + clrsetbits_be32(&uccp->gumr_l, + UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | + UCC_SLOW_GUMR_L_RDCR_MASK, + UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_1 | + UCC_SLOW_GUMR_L_RDCR_16); + + clrsetbits_be32(&uccp->gumr_h, UCC_SLOW_GUMR_H_RFW, + UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX); + } else { + clrsetbits_be32(&uccp->gumr_l, + UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | + UCC_SLOW_GUMR_L_RDCR_MASK, + UCC_SLOW_GUMR_L_MODE_UART | UCC_SLOW_GUMR_L_TDCR_16 | + UCC_SLOW_GUMR_L_RDCR_16); + + clrsetbits_be32(&uccp->gumr_h, + UCC_SLOW_GUMR_H_TRX | UCC_SLOW_GUMR_H_TTX, + UCC_SLOW_GUMR_H_RFW); + } + +#ifdef LOOPBACK + clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, + UCC_SLOW_GUMR_L_DIAG_LOOP); + clrsetbits_be32(&uccp->gumr_h, + UCC_SLOW_GUMR_H_CTSP | UCC_SLOW_GUMR_H_RSYN, + UCC_SLOW_GUMR_H_CDS); +#endif + + /* Disable rx interrupts and clear all pending events. */ + out_be16(&uccp->uccm, 0); + out_be16(&uccp->ucce, 0xffff); + out_be16(&uccp->udsr, 0x7e7e); + + /* Initialize UPSMR */ + out_be16(&uccp->upsmr, 0); + + if (soft_uart) { + out_be16(&uccup->supsmr, 0x30); + out_be16(&uccup->res92, 0); + out_be32(&uccup->rx_state, 0); + out_be32(&uccup->rx_cnt, 0); + out_8(&uccup->rx_bitmark, 0); + out_8(&uccup->rx_length, 10); + out_be32(&uccup->dump_ptr, 0x4000); + out_8(&uccup->rx_temp_dlst_qe, 0); + out_be32(&uccup->rx_frame_rem, 0); + out_8(&uccup->rx_frame_rem_size, 0); + /* Soft-UART requires TX to be 1X */ + out_8(&uccup->tx_mode, + UCC_UART_TX_STATE_UART | UCC_UART_TX_STATE_X1); + out_be16(&uccup->tx_state, 0); + out_8(&uccup->resD4, 0); + out_be16(&uccup->resD5, 0); + + /* Set UART mode. + * Enable receive and transmit. + */ + + /* From the microcode errata: + * 1.GUMR_L register, set mode=0010 (QMC). + * 2.Set GUMR_H[17] bit. (UART/AHDLC mode). + * 3.Set GUMR_H[19:20] (Transparent mode) + * 4.Clear GUMR_H[26] (RFW) + * ... + * 6.Receiver must use 16x over sampling + */ + clrsetbits_be32(&uccp->gumr_l, + UCC_SLOW_GUMR_L_MODE_MASK | UCC_SLOW_GUMR_L_TDCR_MASK | + UCC_SLOW_GUMR_L_RDCR_MASK, + UCC_SLOW_GUMR_L_MODE_QMC | UCC_SLOW_GUMR_L_TDCR_16 | + UCC_SLOW_GUMR_L_RDCR_16); + + clrsetbits_be32(&uccp->gumr_h, + UCC_SLOW_GUMR_H_RFW | UCC_SLOW_GUMR_H_RSYN, + UCC_SLOW_GUMR_H_SUART | UCC_SLOW_GUMR_H_TRX | + UCC_SLOW_GUMR_H_TTX | UCC_SLOW_GUMR_H_TFL); + +#ifdef LOOPBACK + clrsetbits_be32(&uccp->gumr_l, UCC_SLOW_GUMR_L_DIAG_MASK, + UCC_SLOW_GUMR_L_DIAG_LOOP); + clrbits32(&uccp->gumr_h, UCC_SLOW_GUMR_H_CTSP | + UCC_SLOW_GUMR_H_CDS); +#endif + + cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); + qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, + QE_CR_PROTOCOL_UNSPECIFIED, 0); + } else { + cecr_subblock = ucc_slow_get_qe_cr_subblock(qe_port->ucc_num); + qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock, + QE_CR_PROTOCOL_UART, 0); + } +} + +/* + * Initialize the port. + */ +static int qe_uart_startup(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + int ret; + + /* + * If we're using Soft-UART mode, then we need to make sure the + * firmware has been uploaded first. + */ + if (soft_uart && !firmware_loaded) { + dev_err(port->dev, "Soft-UART firmware not uploaded\n"); + return -ENODEV; + } + + qe_uart_initbd(qe_port); + qe_uart_init_ucc(qe_port); + + /* Install interrupt handler. */ + ret = request_irq(port->irq, qe_uart_int, IRQF_SHARED, "ucc-uart", + qe_port); + if (ret) { + dev_err(port->dev, "could not claim IRQ %u\n", port->irq); + return ret; + } + + /* Startup rx-int */ + setbits16(&qe_port->uccp->uccm, UCC_UART_UCCE_RX); + ucc_slow_enable(qe_port->us_private, COMM_DIR_RX_AND_TX); + + return 0; +} + +/* + * Shutdown the port. + */ +static void qe_uart_shutdown(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow __iomem *uccp = qe_port->uccp; + unsigned int timeout = 20; + + /* Disable RX and TX */ + + /* Wait for all the BDs marked sent */ + while (!qe_uart_tx_empty(port)) { + if (!--timeout) { + dev_warn(port->dev, "shutdown timeout\n"); + break; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(2); + } + + if (qe_port->wait_closing) { + /* Wait a bit longer */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(qe_port->wait_closing); + } + + /* Stop uarts */ + ucc_slow_disable(qe_port->us_private, COMM_DIR_RX_AND_TX); + clrbits16(&uccp->uccm, UCC_UART_UCCE_TX | UCC_UART_UCCE_RX); + + /* Shut them really down and reinit buffer descriptors */ + ucc_slow_graceful_stop_tx(qe_port->us_private); + qe_uart_initbd(qe_port); + + free_irq(port->irq, qe_port); +} + +/* + * Set the serial port parameters. + */ +static void qe_uart_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow __iomem *uccp = qe_port->uccp; + unsigned int baud; + unsigned long flags; + u16 upsmr = in_be16(&uccp->upsmr); + struct ucc_uart_pram __iomem *uccup = qe_port->uccup; + u16 supsmr = in_be16(&uccup->supsmr); + u8 char_length = 2; /* 1 + CL + PEN + 1 + SL */ + + /* Character length programmed into the mode register is the + * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, + * 1 or 2 stop bits, minus 1. + * The value 'bits' counts this for us. + */ + + /* byte size */ + upsmr &= UCC_UART_UPSMR_CL_MASK; + supsmr &= UCC_UART_SUPSMR_CL_MASK; + + switch (termios->c_cflag & CSIZE) { + case CS5: + upsmr |= UCC_UART_UPSMR_CL_5; + supsmr |= UCC_UART_SUPSMR_CL_5; + char_length += 5; + break; + case CS6: + upsmr |= UCC_UART_UPSMR_CL_6; + supsmr |= UCC_UART_SUPSMR_CL_6; + char_length += 6; + break; + case CS7: + upsmr |= UCC_UART_UPSMR_CL_7; + supsmr |= UCC_UART_SUPSMR_CL_7; + char_length += 7; + break; + default: /* case CS8 */ + upsmr |= UCC_UART_UPSMR_CL_8; + supsmr |= UCC_UART_SUPSMR_CL_8; + char_length += 8; + break; + } + + /* If CSTOPB is set, we want two stop bits */ + if (termios->c_cflag & CSTOPB) { + upsmr |= UCC_UART_UPSMR_SL; + supsmr |= UCC_UART_SUPSMR_SL; + char_length++; /* + SL */ + } + + if (termios->c_cflag & PARENB) { + upsmr |= UCC_UART_UPSMR_PEN; + supsmr |= UCC_UART_SUPSMR_PEN; + char_length++; /* + PEN */ + + if (!(termios->c_cflag & PARODD)) { + upsmr &= ~(UCC_UART_UPSMR_RPM_MASK | + UCC_UART_UPSMR_TPM_MASK); + upsmr |= UCC_UART_UPSMR_RPM_EVEN | + UCC_UART_UPSMR_TPM_EVEN; + supsmr &= ~(UCC_UART_SUPSMR_RPM_MASK | + UCC_UART_SUPSMR_TPM_MASK); + supsmr |= UCC_UART_SUPSMR_RPM_EVEN | + UCC_UART_SUPSMR_TPM_EVEN; + } + } + + /* + * Set up parity check flag + */ + port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; + if (termios->c_iflag & INPCK) + port->read_status_mask |= BD_SC_FR | BD_SC_PR; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= BD_SC_BR; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= BD_SC_PR | BD_SC_FR; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= BD_SC_BR; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= BD_SC_OV; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->read_status_mask &= ~BD_SC_EMPTY; + + baud = uart_get_baud_rate(port, termios, old, 0, 115200); + + /* Do we really need a spinlock here? */ + spin_lock_irqsave(&port->lock, flags); + + out_be16(&uccp->upsmr, upsmr); + if (soft_uart) { + out_be16(&uccup->supsmr, supsmr); + out_8(&uccup->rx_length, char_length); + + /* Soft-UART requires a 1X multiplier for TX */ + qe_setbrg(qe_port->us_info.rx_clock, baud, 16); + qe_setbrg(qe_port->us_info.tx_clock, baud, 1); + } else { + qe_setbrg(qe_port->us_info.rx_clock, baud, 16); + qe_setbrg(qe_port->us_info.tx_clock, baud, 16); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* + * Return a pointer to a string that describes what kind of port this is. + */ +static const char *qe_uart_type(struct uart_port *port) +{ + return "QE"; +} + +/* + * Allocate any memory and I/O resources required by the port. + */ +static int qe_uart_request_port(struct uart_port *port) +{ + int ret; + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow_info *us_info = &qe_port->us_info; + struct ucc_slow_private *uccs; + unsigned int rx_size, tx_size; + void *bd_virt; + dma_addr_t bd_dma_addr = 0; + + ret = ucc_slow_init(us_info, &uccs); + if (ret) { + dev_err(port->dev, "could not initialize UCC%u\n", + qe_port->ucc_num); + return ret; + } + + qe_port->us_private = uccs; + qe_port->uccp = uccs->us_regs; + qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram; + qe_port->rx_bd_base = uccs->rx_bd; + qe_port->tx_bd_base = uccs->tx_bd; + + /* + * Allocate the transmit and receive data buffers. + */ + + rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize); + tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize); + + bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr, + GFP_KERNEL); + if (!bd_virt) { + dev_err(port->dev, "could not allocate buffer descriptors\n"); + return -ENOMEM; + } + + qe_port->bd_virt = bd_virt; + qe_port->bd_dma_addr = bd_dma_addr; + qe_port->bd_size = rx_size + tx_size; + + qe_port->rx_buf = bd_virt; + qe_port->tx_buf = qe_port->rx_buf + rx_size; + + return 0; +} + +/* + * Configure the port. + * + * We say we're a CPM-type port because that's mostly true. Once the device + * is configured, this driver operates almost identically to the CPM serial + * driver. + */ +static void qe_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_CPM; + qe_uart_request_port(port); + } +} + +/* + * Release any memory and I/O resources that were allocated in + * qe_uart_request_port(). + */ +static void qe_uart_release_port(struct uart_port *port) +{ + struct uart_qe_port *qe_port = + container_of(port, struct uart_qe_port, port); + struct ucc_slow_private *uccs = qe_port->us_private; + + dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt, + qe_port->bd_dma_addr); + + ucc_slow_free(uccs); +} + +/* + * Verify that the data in serial_struct is suitable for this device. + */ +static int qe_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) + return -EINVAL; + + if (ser->irq < 0 || ser->irq >= nr_irqs) + return -EINVAL; + + if (ser->baud_base < 9600) + return -EINVAL; + + return 0; +} +/* UART operations + * + * Details on these functions can be found in Documentation/serial/driver + */ +static struct uart_ops qe_uart_pops = { + .tx_empty = qe_uart_tx_empty, + .set_mctrl = qe_uart_set_mctrl, + .get_mctrl = qe_uart_get_mctrl, + .stop_tx = qe_uart_stop_tx, + .start_tx = qe_uart_start_tx, + .stop_rx = qe_uart_stop_rx, + .enable_ms = qe_uart_enable_ms, + .break_ctl = qe_uart_break_ctl, + .startup = qe_uart_startup, + .shutdown = qe_uart_shutdown, + .set_termios = qe_uart_set_termios, + .type = qe_uart_type, + .release_port = qe_uart_release_port, + .request_port = qe_uart_request_port, + .config_port = qe_uart_config_port, + .verify_port = qe_uart_verify_port, +}; + +/* + * Obtain the SOC model number and revision level + * + * This function parses the device tree to obtain the SOC model. It then + * reads the SVR register to the revision. + * + * The device tree stores the SOC model two different ways. + * + * The new way is: + * + * cpu@0 { + * compatible = "PowerPC,8323"; + * device_type = "cpu"; + * ... + * + * + * The old way is: + * PowerPC,8323@0 { + * device_type = "cpu"; + * ... + * + * This code first checks the new way, and then the old way. + */ +static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) +{ + struct device_node *np; + const char *soc_string; + unsigned int svr; + unsigned int soc; + + /* Find the CPU node */ + np = of_find_node_by_type(NULL, "cpu"); + if (!np) + return 0; + /* Find the compatible property */ + soc_string = of_get_property(np, "compatible", NULL); + if (!soc_string) + /* No compatible property, so try the name. */ + soc_string = np->name; + + /* Extract the SOC number from the "PowerPC," string */ + if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) + return 0; + + /* Get the revision from the SVR */ + svr = mfspr(SPRN_SVR); + *rev_h = (svr >> 4) & 0xf; + *rev_l = svr & 0xf; + + return soc; +} + +/* + * requst_firmware_nowait() callback function + * + * This function is called by the kernel when a firmware is made available, + * or if it times out waiting for the firmware. + */ +static void uart_firmware_cont(const struct firmware *fw, void *context) +{ + struct qe_firmware *firmware; + struct device *dev = context; + int ret; + + if (!fw) { + dev_err(dev, "firmware not found\n"); + return; + } + + firmware = (struct qe_firmware *) fw->data; + + if (firmware->header.length != fw->size) { + dev_err(dev, "invalid firmware\n"); + goto out; + } + + ret = qe_upload_firmware(firmware); + if (ret) { + dev_err(dev, "could not load firmware\n"); + goto out; + } + + firmware_loaded = 1; + out: + release_firmware(fw); +} + +static int ucc_uart_probe(struct platform_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->dev.of_node; + const unsigned int *iprop; /* Integer OF properties */ + const char *sprop; /* String OF properties */ + struct uart_qe_port *qe_port = NULL; + struct resource res; + int ret; + + /* + * Determine if we need Soft-UART mode + */ + if (of_find_property(np, "soft-uart", NULL)) { + dev_dbg(&ofdev->dev, "using Soft-UART mode\n"); + soft_uart = 1; + } + + /* + * If we are using Soft-UART, determine if we need to upload the + * firmware, too. + */ + if (soft_uart) { + struct qe_firmware_info *qe_fw_info; + + qe_fw_info = qe_get_firmware_info(); + + /* Check if the firmware has been uploaded. */ + if (qe_fw_info && strstr(qe_fw_info->id, "Soft-UART")) { + firmware_loaded = 1; + } else { + char filename[32]; + unsigned int soc; + unsigned int rev_h; + unsigned int rev_l; + + soc = soc_info(&rev_h, &rev_l); + if (!soc) { + dev_err(&ofdev->dev, "unknown CPU model\n"); + return -ENXIO; + } + sprintf(filename, "fsl_qe_ucode_uart_%u_%u%u.bin", + soc, rev_h, rev_l); + + dev_info(&ofdev->dev, "waiting for firmware %s\n", + filename); + + /* + * We call request_firmware_nowait instead of + * request_firmware so that the driver can load and + * initialize the ports without holding up the rest of + * the kernel. If hotplug support is enabled in the + * kernel, then we use it. + */ + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, filename, &ofdev->dev, + GFP_KERNEL, &ofdev->dev, uart_firmware_cont); + if (ret) { + dev_err(&ofdev->dev, + "could not load firmware %s\n", + filename); + return ret; + } + } + } + + qe_port = kzalloc(sizeof(struct uart_qe_port), GFP_KERNEL); + if (!qe_port) { + dev_err(&ofdev->dev, "can't allocate QE port structure\n"); + return -ENOMEM; + } + + /* Search for IRQ and mapbase */ + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(&ofdev->dev, "missing 'reg' property in device tree\n"); + kfree(qe_port); + return ret; + } + if (!res.start) { + dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + qe_port->port.mapbase = res.start; + + /* Get the UCC number (device ID) */ + /* UCCs are numbered 1-7 */ + iprop = of_get_property(np, "cell-index", NULL); + if (!iprop) { + iprop = of_get_property(np, "device-id", NULL); + if (!iprop) { + kfree(qe_port); + dev_err(&ofdev->dev, "UCC is unspecified in " + "device tree\n"); + return -EINVAL; + } + } + + if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) { + dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop); + kfree(qe_port); + return -ENODEV; + } + qe_port->ucc_num = *iprop - 1; + + /* + * In the future, we should not require the BRG to be specified in the + * device tree. If no clock-source is specified, then just pick a BRG + * to use. This requires a new QE library function that manages BRG + * assignments. + */ + + sprop = of_get_property(np, "rx-clock-name", NULL); + if (!sprop) { + dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n"); + kfree(qe_port); + return -ENODEV; + } + + qe_port->us_info.rx_clock = qe_clock_source(sprop); + if ((qe_port->us_info.rx_clock < QE_BRG1) || + (qe_port->us_info.rx_clock > QE_BRG16)) { + dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n"); + kfree(qe_port); + return -ENODEV; + } + +#ifdef LOOPBACK + /* In internal loopback mode, TX and RX must use the same clock */ + qe_port->us_info.tx_clock = qe_port->us_info.rx_clock; +#else + sprop = of_get_property(np, "tx-clock-name", NULL); + if (!sprop) { + dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n"); + kfree(qe_port); + return -ENODEV; + } + qe_port->us_info.tx_clock = qe_clock_source(sprop); +#endif + if ((qe_port->us_info.tx_clock < QE_BRG1) || + (qe_port->us_info.tx_clock > QE_BRG16)) { + dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n"); + kfree(qe_port); + return -ENODEV; + } + + /* Get the port number, numbered 0-3 */ + iprop = of_get_property(np, "port-number", NULL); + if (!iprop) { + dev_err(&ofdev->dev, "missing port-number in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + qe_port->port.line = *iprop; + if (qe_port->port.line >= UCC_MAX_UART) { + dev_err(&ofdev->dev, "port-number must be 0-%u\n", + UCC_MAX_UART - 1); + kfree(qe_port); + return -EINVAL; + } + + qe_port->port.irq = irq_of_parse_and_map(np, 0); + if (qe_port->port.irq == NO_IRQ) { + dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", + qe_port->ucc_num + 1); + kfree(qe_port); + return -EINVAL; + } + + /* + * Newer device trees have an "fsl,qe" compatible property for the QE + * node, but we still need to support older device trees. + */ + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!np) { + np = of_find_node_by_type(NULL, "qe"); + if (!np) { + dev_err(&ofdev->dev, "could not find 'qe' node\n"); + kfree(qe_port); + return -EINVAL; + } + } + + iprop = of_get_property(np, "brg-frequency", NULL); + if (!iprop) { + dev_err(&ofdev->dev, + "missing brg-frequency in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + + if (*iprop) + qe_port->port.uartclk = *iprop; + else { + /* + * Older versions of U-Boot do not initialize the brg-frequency + * property, so in this case we assume the BRG frequency is + * half the QE bus frequency. + */ + iprop = of_get_property(np, "bus-frequency", NULL); + if (!iprop) { + dev_err(&ofdev->dev, + "missing QE bus-frequency in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + if (*iprop) + qe_port->port.uartclk = *iprop / 2; + else { + dev_err(&ofdev->dev, + "invalid QE bus-frequency in device tree\n"); + kfree(qe_port); + return -EINVAL; + } + } + + spin_lock_init(&qe_port->port.lock); + qe_port->np = np; + qe_port->port.dev = &ofdev->dev; + qe_port->port.ops = &qe_uart_pops; + qe_port->port.iotype = UPIO_MEM; + + qe_port->tx_nrfifos = TX_NUM_FIFO; + qe_port->tx_fifosize = TX_BUF_SIZE; + qe_port->rx_nrfifos = RX_NUM_FIFO; + qe_port->rx_fifosize = RX_BUF_SIZE; + + qe_port->wait_closing = UCC_WAIT_CLOSING; + qe_port->port.fifosize = 512; + qe_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + + qe_port->us_info.ucc_num = qe_port->ucc_num; + qe_port->us_info.regs = (phys_addr_t) res.start; + qe_port->us_info.irq = qe_port->port.irq; + + qe_port->us_info.rx_bd_ring_len = qe_port->rx_nrfifos; + qe_port->us_info.tx_bd_ring_len = qe_port->tx_nrfifos; + + /* Make sure ucc_slow_init() initializes both TX and RX */ + qe_port->us_info.init_tx = 1; + qe_port->us_info.init_rx = 1; + + /* Add the port to the uart sub-system. This will cause + * qe_uart_config_port() to be called, so the us_info structure must + * be initialized. + */ + ret = uart_add_one_port(&ucc_uart_driver, &qe_port->port); + if (ret) { + dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n", + qe_port->port.line); + kfree(qe_port); + return ret; + } + + dev_set_drvdata(&ofdev->dev, qe_port); + + dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n", + qe_port->ucc_num + 1, qe_port->port.line); + + /* Display the mknod command for this device */ + dev_dbg(&ofdev->dev, "mknod command is 'mknod /dev/ttyQE%u c %u %u'\n", + qe_port->port.line, SERIAL_QE_MAJOR, + SERIAL_QE_MINOR + qe_port->port.line); + + return 0; +} + +static int ucc_uart_remove(struct platform_device *ofdev) +{ + struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev); + + dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line); + + uart_remove_one_port(&ucc_uart_driver, &qe_port->port); + + dev_set_drvdata(&ofdev->dev, NULL); + kfree(qe_port); + + return 0; +} + +static struct of_device_id ucc_uart_match[] = { + { + .type = "serial", + .compatible = "ucc_uart", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ucc_uart_match); + +static struct of_platform_driver ucc_uart_of_driver = { + .driver = { + .name = "ucc_uart", + .owner = THIS_MODULE, + .of_match_table = ucc_uart_match, + }, + .probe = ucc_uart_probe, + .remove = ucc_uart_remove, +}; + +static int __init ucc_uart_init(void) +{ + int ret; + + printk(KERN_INFO "Freescale QUICC Engine UART device driver\n"); +#ifdef LOOPBACK + printk(KERN_INFO "ucc-uart: Using loopback mode\n"); +#endif + + ret = uart_register_driver(&ucc_uart_driver); + if (ret) { + printk(KERN_ERR "ucc-uart: could not register UART driver\n"); + return ret; + } + + ret = of_register_platform_driver(&ucc_uart_of_driver); + if (ret) + printk(KERN_ERR + "ucc-uart: could not register platform driver\n"); + + return ret; +} + +static void __exit ucc_uart_exit(void) +{ + printk(KERN_INFO + "Freescale QUICC Engine UART device driver unloading\n"); + + of_unregister_platform_driver(&ucc_uart_of_driver); + uart_unregister_driver(&ucc_uart_driver); +} + +module_init(ucc_uart_init); +module_exit(ucc_uart_exit); + +MODULE_DESCRIPTION("Freescale QUICC Engine (QE) UART"); +MODULE_AUTHOR("Timur Tabi "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_QE_MAJOR); + diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c new file mode 100644 index 000000000000..3beb6ab4fa68 --- /dev/null +++ b/drivers/tty/serial/vr41xx_siu.c @@ -0,0 +1,978 @@ +/* + * Driver for NEC VR4100 series Serial Interface Unit. + * + * Copyright (C) 2004-2008 Yoichi Yuasa + * + * Based on drivers/serial/8250.c, by Russell King. + * + * 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 + */ + +#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SIU_BAUD_BASE 1152000 +#define SIU_MAJOR 204 +#define SIU_MINOR_BASE 82 + +#define RX_MAX_COUNT 256 +#define TX_MAX_COUNT 15 + +#define SIUIRSEL 0x08 + #define TMICMODE 0x20 + #define TMICTX 0x10 + #define IRMSEL 0x0c + #define IRMSEL_HP 0x08 + #define IRMSEL_TEMIC 0x04 + #define IRMSEL_SHARP 0x00 + #define IRUSESEL 0x02 + #define SIRSEL 0x01 + +static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { + [0 ... SIU_PORTS_MAX-1] = { + .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), + .irq = -1, + }, +}; + +#ifdef CONFIG_SERIAL_VR41XX_CONSOLE +static uint8_t lsr_break_flag[SIU_PORTS_MAX]; +#endif + +#define siu_read(port, offset) readb((port)->membase + (offset)) +#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset)) + +void vr41xx_select_siu_interface(siu_interface_t interface) +{ + struct uart_port *port; + unsigned long flags; + uint8_t irsel; + + port = &siu_uart_ports[0]; + + spin_lock_irqsave(&port->lock, flags); + + irsel = siu_read(port, SIUIRSEL); + if (interface == SIU_INTERFACE_IRDA) + irsel |= SIRSEL; + else + irsel &= ~SIRSEL; + siu_write(port, SIUIRSEL, irsel); + + spin_unlock_irqrestore(&port->lock, flags); +} +EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface); + +void vr41xx_use_irda(irda_use_t use) +{ + struct uart_port *port; + unsigned long flags; + uint8_t irsel; + + port = &siu_uart_ports[0]; + + spin_lock_irqsave(&port->lock, flags); + + irsel = siu_read(port, SIUIRSEL); + if (use == FIR_USE_IRDA) + irsel |= IRUSESEL; + else + irsel &= ~IRUSESEL; + siu_write(port, SIUIRSEL, irsel); + + spin_unlock_irqrestore(&port->lock, flags); +} +EXPORT_SYMBOL_GPL(vr41xx_use_irda); + +void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed) +{ + struct uart_port *port; + unsigned long flags; + uint8_t irsel; + + port = &siu_uart_ports[0]; + + spin_lock_irqsave(&port->lock, flags); + + irsel = siu_read(port, SIUIRSEL); + irsel &= ~(IRMSEL | TMICTX | TMICMODE); + switch (module) { + case SHARP_IRDA: + irsel |= IRMSEL_SHARP; + break; + case TEMIC_IRDA: + irsel |= IRMSEL_TEMIC | TMICMODE; + if (speed == IRDA_TX_4MBPS) + irsel |= TMICTX; + break; + case HP_IRDA: + irsel |= IRMSEL_HP; + break; + default: + break; + } + siu_write(port, SIUIRSEL, irsel); + + spin_unlock_irqrestore(&port->lock, flags); +} +EXPORT_SYMBOL_GPL(vr41xx_select_irda_module); + +static inline void siu_clear_fifo(struct uart_port *port) +{ + siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO); + siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + siu_write(port, UART_FCR, 0); +} + +static inline unsigned long siu_port_size(struct uart_port *port) +{ + switch (port->type) { + case PORT_VR41XX_SIU: + return 11UL; + case PORT_VR41XX_DSIU: + return 8UL; + } + + return 0; +} + +static inline unsigned int siu_check_type(struct uart_port *port) +{ + if (port->line == 0) + return PORT_VR41XX_SIU; + if (port->line == 1 && port->irq != -1) + return PORT_VR41XX_DSIU; + + return PORT_UNKNOWN; +} + +static inline const char *siu_type_name(struct uart_port *port) +{ + switch (port->type) { + case PORT_VR41XX_SIU: + return "SIU"; + case PORT_VR41XX_DSIU: + return "DSIU"; + } + + return NULL; +} + +static unsigned int siu_tx_empty(struct uart_port *port) +{ + uint8_t lsr; + + lsr = siu_read(port, UART_LSR); + if (lsr & UART_LSR_TEMT) + return TIOCSER_TEMT; + + return 0; +} + +static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + uint8_t mcr = 0; + + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + siu_write(port, UART_MCR, mcr); +} + +static unsigned int siu_get_mctrl(struct uart_port *port) +{ + uint8_t msr; + unsigned int mctrl = 0; + + msr = siu_read(port, UART_MSR); + if (msr & UART_MSR_DCD) + mctrl |= TIOCM_CAR; + if (msr & UART_MSR_RI) + mctrl |= TIOCM_RNG; + if (msr & UART_MSR_DSR) + mctrl |= TIOCM_DSR; + if (msr & UART_MSR_CTS) + mctrl |= TIOCM_CTS; + + return mctrl; +} + +static void siu_stop_tx(struct uart_port *port) +{ + unsigned long flags; + uint8_t ier; + + spin_lock_irqsave(&port->lock, flags); + + ier = siu_read(port, UART_IER); + ier &= ~UART_IER_THRI; + siu_write(port, UART_IER, ier); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void siu_start_tx(struct uart_port *port) +{ + unsigned long flags; + uint8_t ier; + + spin_lock_irqsave(&port->lock, flags); + + ier = siu_read(port, UART_IER); + ier |= UART_IER_THRI; + siu_write(port, UART_IER, ier); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void siu_stop_rx(struct uart_port *port) +{ + unsigned long flags; + uint8_t ier; + + spin_lock_irqsave(&port->lock, flags); + + ier = siu_read(port, UART_IER); + ier &= ~UART_IER_RLSI; + siu_write(port, UART_IER, ier); + + port->read_status_mask &= ~UART_LSR_DR; + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void siu_enable_ms(struct uart_port *port) +{ + unsigned long flags; + uint8_t ier; + + spin_lock_irqsave(&port->lock, flags); + + ier = siu_read(port, UART_IER); + ier |= UART_IER_MSI; + siu_write(port, UART_IER, ier); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void siu_break_ctl(struct uart_port *port, int ctl) +{ + unsigned long flags; + uint8_t lcr; + + spin_lock_irqsave(&port->lock, flags); + + lcr = siu_read(port, UART_LCR); + if (ctl == -1) + lcr |= UART_LCR_SBC; + else + lcr &= ~UART_LCR_SBC; + siu_write(port, UART_LCR, lcr); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static inline void receive_chars(struct uart_port *port, uint8_t *status) +{ + struct tty_struct *tty; + uint8_t lsr, ch; + char flag; + int max_count = RX_MAX_COUNT; + + tty = port->state->port.tty; + lsr = *status; + + do { + ch = siu_read(port, UART_RX); + port->icount.rx++; + flag = TTY_NORMAL; + +#ifdef CONFIG_SERIAL_VR41XX_CONSOLE + lsr |= lsr_break_flag[port->line]; + lsr_break_flag[port->line] = 0; +#endif + if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE | + UART_LSR_PE | UART_LSR_OE))) { + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + + if (uart_handle_break(port)) + goto ignore_char; + } + + if (lsr & UART_LSR_FE) + port->icount.frame++; + if (lsr & UART_LSR_PE) + port->icount.parity++; + if (lsr & UART_LSR_OE) + port->icount.overrun++; + + lsr &= port->read_status_mask; + if (lsr & UART_LSR_BI) + flag = TTY_BREAK; + if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + if (lsr & UART_LSR_PE) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); + + ignore_char: + lsr = siu_read(port, UART_LSR); + } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); + + tty_flip_buffer_push(tty); + + *status = lsr; +} + +static inline void check_modem_status(struct uart_port *port) +{ + uint8_t msr; + + msr = siu_read(port, UART_MSR); + if ((msr & UART_MSR_ANY_DELTA) == 0) + return; + if (msr & UART_MSR_DDCD) + uart_handle_dcd_change(port, msr & UART_MSR_DCD); + if (msr & UART_MSR_TERI) + port->icount.rng++; + if (msr & UART_MSR_DDSR) + port->icount.dsr++; + if (msr & UART_MSR_DCTS) + uart_handle_cts_change(port, msr & UART_MSR_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); +} + +static inline void transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit; + int max_count = TX_MAX_COUNT; + + xmit = &port->state->xmit; + + if (port->x_char) { + siu_write(port, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + siu_stop_tx(port); + return; + } + + do { + siu_write(port, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (max_count-- > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + siu_stop_tx(port); +} + +static irqreturn_t siu_interrupt(int irq, void *dev_id) +{ + struct uart_port *port; + uint8_t iir, lsr; + + port = (struct uart_port *)dev_id; + + iir = siu_read(port, UART_IIR); + if (iir & UART_IIR_NO_INT) + return IRQ_NONE; + + lsr = siu_read(port, UART_LSR); + if (lsr & UART_LSR_DR) + receive_chars(port, &lsr); + + check_modem_status(port); + + if (lsr & UART_LSR_THRE) + transmit_chars(port); + + return IRQ_HANDLED; +} + +static int siu_startup(struct uart_port *port) +{ + int retval; + + if (port->membase == NULL) + return -ENODEV; + + siu_clear_fifo(port); + + (void)siu_read(port, UART_LSR); + (void)siu_read(port, UART_RX); + (void)siu_read(port, UART_IIR); + (void)siu_read(port, UART_MSR); + + if (siu_read(port, UART_LSR) == 0xff) + return -ENODEV; + + retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port); + if (retval) + return retval; + + if (port->type == PORT_VR41XX_DSIU) + vr41xx_enable_dsiuint(DSIUINT_ALL); + + siu_write(port, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irq(&port->lock); + siu_set_mctrl(port, port->mctrl); + spin_unlock_irq(&port->lock); + + siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI); + + (void)siu_read(port, UART_LSR); + (void)siu_read(port, UART_RX); + (void)siu_read(port, UART_IIR); + (void)siu_read(port, UART_MSR); + + return 0; +} + +static void siu_shutdown(struct uart_port *port) +{ + unsigned long flags; + uint8_t lcr; + + siu_write(port, UART_IER, 0); + + spin_lock_irqsave(&port->lock, flags); + + port->mctrl &= ~TIOCM_OUT2; + siu_set_mctrl(port, port->mctrl); + + spin_unlock_irqrestore(&port->lock, flags); + + lcr = siu_read(port, UART_LCR); + lcr &= ~UART_LCR_SBC; + siu_write(port, UART_LCR, lcr); + + siu_clear_fifo(port); + + (void)siu_read(port, UART_RX); + + if (port->type == PORT_VR41XX_DSIU) + vr41xx_disable_dsiuint(DSIUINT_ALL); + + free_irq(port->irq, port); +} + +static void siu_set_termios(struct uart_port *port, struct ktermios *new, + struct ktermios *old) +{ + tcflag_t c_cflag, c_iflag; + uint8_t lcr, fcr, ier; + unsigned int baud, quot; + unsigned long flags; + + c_cflag = new->c_cflag; + switch (c_cflag & CSIZE) { + case CS5: + lcr = UART_LCR_WLEN5; + break; + case CS6: + lcr = UART_LCR_WLEN6; + break; + case CS7: + lcr = UART_LCR_WLEN7; + break; + default: + lcr = UART_LCR_WLEN8; + break; + } + + if (c_cflag & CSTOPB) + lcr |= UART_LCR_STOP; + if (c_cflag & PARENB) + lcr |= UART_LCR_PARITY; + if ((c_cflag & PARODD) != PARODD) + lcr |= UART_LCR_EPAR; + if (c_cflag & CMSPAR) + lcr |= UART_LCR_SPAR; + + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; + + spin_lock_irqsave(&port->lock, flags); + + uart_update_timeout(port, c_cflag, baud); + + c_iflag = new->c_iflag; + + port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; + if (c_iflag & INPCK) + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_LSR_BI; + + port->ignore_status_mask = 0; + if (c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (c_iflag & IGNBRK) { + port->ignore_status_mask |= UART_LSR_BI; + if (c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_OE; + } + + if ((c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_LSR_DR; + + ier = siu_read(port, UART_IER); + ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(port, c_cflag)) + ier |= UART_IER_MSI; + siu_write(port, UART_IER, ier); + + siu_write(port, UART_LCR, lcr | UART_LCR_DLAB); + + siu_write(port, UART_DLL, (uint8_t)quot); + siu_write(port, UART_DLM, (uint8_t)(quot >> 8)); + + siu_write(port, UART_LCR, lcr); + + siu_write(port, UART_FCR, fcr); + + siu_set_mctrl(port, port->mctrl); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +{ + switch (state) { + case 0: + switch (port->type) { + case PORT_VR41XX_SIU: + vr41xx_supply_clock(SIU_CLOCK); + break; + case PORT_VR41XX_DSIU: + vr41xx_supply_clock(DSIU_CLOCK); + break; + } + break; + case 3: + switch (port->type) { + case PORT_VR41XX_SIU: + vr41xx_mask_clock(SIU_CLOCK); + break; + case PORT_VR41XX_DSIU: + vr41xx_mask_clock(DSIU_CLOCK); + break; + } + break; + } +} + +static const char *siu_type(struct uart_port *port) +{ + return siu_type_name(port); +} + +static void siu_release_port(struct uart_port *port) +{ + unsigned long size; + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + size = siu_port_size(port); + release_mem_region(port->mapbase, size); +} + +static int siu_request_port(struct uart_port *port) +{ + unsigned long size; + struct resource *res; + + size = siu_port_size(port); + res = request_mem_region(port->mapbase, size, siu_type_name(port)); + if (res == NULL) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, size); + if (port->membase == NULL) { + release_resource(res); + return -ENOMEM; + } + } + + return 0; +} + +static void siu_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = siu_check_type(port); + (void)siu_request_port(port); + } +} + +static int siu_verify_port(struct uart_port *port, struct serial_struct *serial) +{ + if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU) + return -EINVAL; + if (port->irq != serial->irq) + return -EINVAL; + if (port->iotype != serial->io_type) + return -EINVAL; + if (port->mapbase != (unsigned long)serial->iomem_base) + return -EINVAL; + + return 0; +} + +static struct uart_ops siu_uart_ops = { + .tx_empty = siu_tx_empty, + .set_mctrl = siu_set_mctrl, + .get_mctrl = siu_get_mctrl, + .stop_tx = siu_stop_tx, + .start_tx = siu_start_tx, + .stop_rx = siu_stop_rx, + .enable_ms = siu_enable_ms, + .break_ctl = siu_break_ctl, + .startup = siu_startup, + .shutdown = siu_shutdown, + .set_termios = siu_set_termios, + .pm = siu_pm, + .type = siu_type, + .release_port = siu_release_port, + .request_port = siu_request_port, + .config_port = siu_config_port, + .verify_port = siu_verify_port, +}; + +static int siu_init_ports(struct platform_device *pdev) +{ + struct uart_port *port; + struct resource *res; + int *type = pdev->dev.platform_data; + int i; + + if (!type) + return 0; + + port = siu_uart_ports; + for (i = 0; i < SIU_PORTS_MAX; i++) { + port->type = type[i]; + if (port->type == PORT_UNKNOWN) + continue; + port->irq = platform_get_irq(pdev, i); + port->uartclk = SIU_BAUD_BASE * 16; + port->fifosize = 16; + port->regshift = 0; + port->iotype = UPIO_MEM; + port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; + port->line = i; + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + port->mapbase = res->start; + port++; + } + + return i; +} + +#ifdef CONFIG_SERIAL_VR41XX_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static void wait_for_xmitr(struct uart_port *port) +{ + int timeout = 10000; + uint8_t lsr, msr; + + do { + lsr = siu_read(port, UART_LSR); + if (lsr & UART_LSR_BI) + lsr_break_flag[port->line] = UART_LSR_BI; + + if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) + break; + } while (timeout-- > 0); + + if (port->flags & UPF_CONS_FLOW) { + timeout = 1000000; + + do { + msr = siu_read(port, UART_MSR); + if ((msr & UART_MSR_CTS) != 0) + break; + } while (timeout-- > 0); + } +} + +static void siu_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmitr(port); + siu_write(port, UART_TX, ch); +} + +static void siu_console_write(struct console *con, const char *s, unsigned count) +{ + struct uart_port *port; + uint8_t ier; + + port = &siu_uart_ports[con->index]; + + ier = siu_read(port, UART_IER); + siu_write(port, UART_IER, 0); + + uart_console_write(port, s, count, siu_console_putchar); + + wait_for_xmitr(port); + siu_write(port, UART_IER, ier); +} + +static int __init siu_console_setup(struct console *con, char *options) +{ + struct uart_port *port; + int baud = 9600; + int parity = 'n'; + int bits = 8; + int flow = 'n'; + + if (con->index >= SIU_PORTS_MAX) + con->index = 0; + + port = &siu_uart_ports[con->index]; + if (port->membase == NULL) { + if (port->mapbase == 0) + return -ENODEV; + port->membase = ioremap(port->mapbase, siu_port_size(port)); + } + + if (port->type == PORT_VR41XX_SIU) + vr41xx_select_siu_interface(SIU_INTERFACE_RS232C); + + if (options != NULL) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, con, baud, parity, bits, flow); +} + +static struct uart_driver siu_uart_driver; + +static struct console siu_console = { + .name = "ttyVR", + .write = siu_console_write, + .device = uart_console_device, + .setup = siu_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &siu_uart_driver, +}; + +static int __devinit siu_console_init(void) +{ + struct uart_port *port; + int i; + + for (i = 0; i < SIU_PORTS_MAX; i++) { + port = &siu_uart_ports[i]; + port->ops = &siu_uart_ops; + } + + register_console(&siu_console); + + return 0; +} + +console_initcall(siu_console_init); + +void __init vr41xx_siu_early_setup(struct uart_port *port) +{ + if (port->type == PORT_UNKNOWN) + return; + + siu_uart_ports[port->line].line = port->line; + siu_uart_ports[port->line].type = port->type; + siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; + siu_uart_ports[port->line].mapbase = port->mapbase; + siu_uart_ports[port->line].mapbase = port->mapbase; + siu_uart_ports[port->line].ops = &siu_uart_ops; +} + +#define SERIAL_VR41XX_CONSOLE &siu_console +#else +#define SERIAL_VR41XX_CONSOLE NULL +#endif + +static struct uart_driver siu_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "SIU", + .dev_name = "ttyVR", + .major = SIU_MAJOR, + .minor = SIU_MINOR_BASE, + .cons = SERIAL_VR41XX_CONSOLE, +}; + +static int __devinit siu_probe(struct platform_device *dev) +{ + struct uart_port *port; + int num, i, retval; + + num = siu_init_ports(dev); + if (num <= 0) + return -ENODEV; + + siu_uart_driver.nr = num; + retval = uart_register_driver(&siu_uart_driver); + if (retval) + return retval; + + for (i = 0; i < num; i++) { + port = &siu_uart_ports[i]; + port->ops = &siu_uart_ops; + port->dev = &dev->dev; + + retval = uart_add_one_port(&siu_uart_driver, port); + if (retval < 0) { + port->dev = NULL; + break; + } + } + + if (i == 0 && retval < 0) { + uart_unregister_driver(&siu_uart_driver); + return retval; + } + + return 0; +} + +static int __devexit siu_remove(struct platform_device *dev) +{ + struct uart_port *port; + int i; + + for (i = 0; i < siu_uart_driver.nr; i++) { + port = &siu_uart_ports[i]; + if (port->dev == &dev->dev) { + uart_remove_one_port(&siu_uart_driver, port); + port->dev = NULL; + } + } + + uart_unregister_driver(&siu_uart_driver); + + return 0; +} + +static int siu_suspend(struct platform_device *dev, pm_message_t state) +{ + struct uart_port *port; + int i; + + for (i = 0; i < siu_uart_driver.nr; i++) { + port = &siu_uart_ports[i]; + if ((port->type == PORT_VR41XX_SIU || + port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) + uart_suspend_port(&siu_uart_driver, port); + + } + + return 0; +} + +static int siu_resume(struct platform_device *dev) +{ + struct uart_port *port; + int i; + + for (i = 0; i < siu_uart_driver.nr; i++) { + port = &siu_uart_ports[i]; + if ((port->type == PORT_VR41XX_SIU || + port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev) + uart_resume_port(&siu_uart_driver, port); + } + + return 0; +} + +static struct platform_driver siu_device_driver = { + .probe = siu_probe, + .remove = __devexit_p(siu_remove), + .suspend = siu_suspend, + .resume = siu_resume, + .driver = { + .name = "SIU", + .owner = THIS_MODULE, + }, +}; + +static int __init vr41xx_siu_init(void) +{ + return platform_driver_register(&siu_device_driver); +} + +static void __exit vr41xx_siu_exit(void) +{ + platform_driver_unregister(&siu_device_driver); +} + +module_init(vr41xx_siu_init); +module_exit(vr41xx_siu_exit); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:SIU"); diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c new file mode 100644 index 000000000000..322bf56c0d89 --- /dev/null +++ b/drivers/tty/serial/vt8500_serial.c @@ -0,0 +1,648 @@ +/* + * drivers/serial/vt8500_serial.c + * + * Copyright (C) 2010 Alexey Charkov + * + * Based on msm_serial.c, which is: + * Copyright (C) 2007 Google, Inc. + * Author: Robert Love + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#if defined(CONFIG_SERIAL_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +# define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * UART Register offsets + */ + +#define VT8500_URTDR 0x0000 /* Transmit data */ +#define VT8500_URRDR 0x0004 /* Receive data */ +#define VT8500_URDIV 0x0008 /* Clock/Baud rate divisor */ +#define VT8500_URLCR 0x000C /* Line control */ +#define VT8500_URICR 0x0010 /* IrDA control */ +#define VT8500_URIER 0x0014 /* Interrupt enable */ +#define VT8500_URISR 0x0018 /* Interrupt status */ +#define VT8500_URUSR 0x001c /* UART status */ +#define VT8500_URFCR 0x0020 /* FIFO control */ +#define VT8500_URFIDX 0x0024 /* FIFO index */ +#define VT8500_URBKR 0x0028 /* Break signal count */ +#define VT8500_URTOD 0x002c /* Time out divisor */ +#define VT8500_TXFIFO 0x1000 /* Transmit FIFO (16x8) */ +#define VT8500_RXFIFO 0x1020 /* Receive FIFO (16x10) */ + +/* + * Interrupt enable and status bits + */ + +#define TXDE (1 << 0) /* Tx Data empty */ +#define RXDF (1 << 1) /* Rx Data full */ +#define TXFAE (1 << 2) /* Tx FIFO almost empty */ +#define TXFE (1 << 3) /* Tx FIFO empty */ +#define RXFAF (1 << 4) /* Rx FIFO almost full */ +#define RXFF (1 << 5) /* Rx FIFO full */ +#define TXUDR (1 << 6) /* Tx underrun */ +#define RXOVER (1 << 7) /* Rx overrun */ +#define PER (1 << 8) /* Parity error */ +#define FER (1 << 9) /* Frame error */ +#define TCTS (1 << 10) /* Toggle of CTS */ +#define RXTOUT (1 << 11) /* Rx timeout */ +#define BKDONE (1 << 12) /* Break signal done */ +#define ERR (1 << 13) /* AHB error response */ + +#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) +#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) + +struct vt8500_port { + struct uart_port uart; + char name[16]; + struct clk *clk; + unsigned int ier; +}; + +static inline void vt8500_write(struct uart_port *port, unsigned int val, + unsigned int off) +{ + writel(val, port->membase + off); +} + +static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off) +{ + return readl(port->membase + off); +} + +static void vt8500_stop_tx(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = container_of(port, + struct vt8500_port, + uart); + + vt8500_port->ier &= ~TX_FIFO_INTS; + vt8500_write(port, vt8500_port->ier, VT8500_URIER); +} + +static void vt8500_stop_rx(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = container_of(port, + struct vt8500_port, + uart); + + vt8500_port->ier &= ~RX_FIFO_INTS; + vt8500_write(port, vt8500_port->ier, VT8500_URIER); +} + +static void vt8500_enable_ms(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = container_of(port, + struct vt8500_port, + uart); + + vt8500_port->ier |= TCTS; + vt8500_write(port, vt8500_port->ier, VT8500_URIER); +} + +static void handle_rx(struct uart_port *port) +{ + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + if (!tty) { + /* Discard data: no tty available */ + int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8; + u16 ch; + while (count--) + ch = readw(port->membase + VT8500_RXFIFO); + return; + } + + /* + * Handle overrun + */ + if ((vt8500_read(port, VT8500_URISR) & RXOVER)) { + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + /* and now the main RX loop */ + while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) { + unsigned int c; + char flag = TTY_NORMAL; + + c = readw(port->membase + VT8500_RXFIFO) & 0x3ff; + + /* Mask conditions we're ignorning. */ + c &= ~port->read_status_mask; + + if (c & FER) { + port->icount.frame++; + flag = TTY_FRAME; + } else if (c & PER) { + port->icount.parity++; + flag = TTY_PARITY; + } + port->icount.rx++; + + if (!uart_handle_sysrq_char(port, c)) + tty_insert_flip_char(tty, c, flag); + } + + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + +static void handle_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + writeb(port->x_char, port->membase + VT8500_TXFIFO); + port->icount.tx++; + port->x_char = 0; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + vt8500_stop_tx(port); + return; + } + + while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) { + if (uart_circ_empty(xmit)) + break; + + writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + vt8500_stop_tx(port); +} + +static void vt8500_start_tx(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = container_of(port, + struct vt8500_port, + uart); + + vt8500_port->ier &= ~TX_FIFO_INTS; + vt8500_write(port, vt8500_port->ier, VT8500_URIER); + handle_tx(port); + vt8500_port->ier |= TX_FIFO_INTS; + vt8500_write(port, vt8500_port->ier, VT8500_URIER); +} + +static void handle_delta_cts(struct uart_port *port) +{ + port->icount.cts++; + wake_up_interruptible(&port->state->port.delta_msr_wait); +} + +static irqreturn_t vt8500_irq(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned long isr; + + spin_lock(&port->lock); + isr = vt8500_read(port, VT8500_URISR); + + /* Acknowledge active status bits */ + vt8500_write(port, isr, VT8500_URISR); + + if (isr & RX_FIFO_INTS) + handle_rx(port); + if (isr & TX_FIFO_INTS) + handle_tx(port); + if (isr & TCTS) + handle_delta_cts(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int vt8500_tx_empty(struct uart_port *port) +{ + return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ? + TIOCSER_TEMT : 0; +} + +static unsigned int vt8500_get_mctrl(struct uart_port *port) +{ + unsigned int usr; + + usr = vt8500_read(port, VT8500_URUSR); + if (usr & (1 << 4)) + return TIOCM_CTS; + else + return 0; +} + +static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void vt8500_break_ctl(struct uart_port *port, int break_ctl) +{ + if (break_ctl) + vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9), + VT8500_URLCR); +} + +static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud) +{ + unsigned long div; + unsigned int loops = 1000; + + div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff); + + if (unlikely((baud < 900) || (baud > 921600))) + div |= 7; + else + div |= (921600 / baud) - 1; + + while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops) + cpu_relax(); + vt8500_write(port, div, VT8500_URDIV); + + return baud; +} + +static int vt8500_startup(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = + container_of(port, struct vt8500_port, uart); + int ret; + + snprintf(vt8500_port->name, sizeof(vt8500_port->name), + "vt8500_serial%d", port->line); + + ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH, + vt8500_port->name, port); + if (unlikely(ret)) + return ret; + + vt8500_write(port, 0x03, VT8500_URLCR); /* enable TX & RX */ + + return 0; +} + +static void vt8500_shutdown(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = + container_of(port, struct vt8500_port, uart); + + vt8500_port->ier = 0; + + /* disable interrupts and FIFOs */ + vt8500_write(&vt8500_port->uart, 0, VT8500_URIER); + vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR); + free_irq(port->irq, port); +} + +static void vt8500_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct vt8500_port *vt8500_port = + container_of(port, struct vt8500_port, uart); + unsigned long flags; + unsigned int baud, lcr; + unsigned int loops = 1000; + + spin_lock_irqsave(&port->lock, flags); + + /* calculate and set baud rate */ + baud = uart_get_baud_rate(port, termios, old, 900, 921600); + baud = vt8500_set_baud_rate(port, baud); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + /* calculate parity */ + lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); + lcr &= ~((1 << 5) | (1 << 4)); + if (termios->c_cflag & PARENB) { + lcr |= (1 << 4); + termios->c_cflag &= ~CMSPAR; + if (termios->c_cflag & PARODD) + lcr |= (1 << 5); + } + + /* calculate bits per char */ + lcr &= ~(1 << 2); + switch (termios->c_cflag & CSIZE) { + case CS7: + break; + case CS8: + default: + lcr |= (1 << 2); + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + break; + } + + /* calculate stop bits */ + lcr &= ~(1 << 3); + if (termios->c_cflag & CSTOPB) + lcr |= (1 << 3); + + /* set parity, bits per char, and stop bit */ + vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); + + /* Configure status bits to ignore based on termio flags. */ + port->read_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->read_status_mask = FER | PER; + + uart_update_timeout(port, termios->c_cflag, baud); + + /* Reset FIFOs */ + vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR); + while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc) + && --loops) + cpu_relax(); + + /* Every possible FIFO-related interrupt */ + vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS; + + /* + * CTS flow control + */ + if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag)) + vt8500_port->ier |= TCTS; + + vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR); + vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *vt8500_type(struct uart_port *port) +{ + struct vt8500_port *vt8500_port = + container_of(port, struct vt8500_port, uart); + return vt8500_port->name; +} + +static void vt8500_release_port(struct uart_port *port) +{ +} + +static int vt8500_request_port(struct uart_port *port) +{ + return 0; +} + +static void vt8500_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_VT8500; +} + +static int vt8500_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500)) + return -EINVAL; + if (unlikely(port->irq != ser->irq)) + return -EINVAL; + return 0; +} + +static struct vt8500_port *vt8500_uart_ports[4]; +static struct uart_driver vt8500_uart_driver; + +#ifdef CONFIG_SERIAL_VT8500_CONSOLE + +static inline void wait_for_xmitr(struct uart_port *port) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = vt8500_read(port, VT8500_URFIDX); + + if (--tmout == 0) + break; + udelay(1); + } while (status & 0x10); +} + +static void vt8500_console_putchar(struct uart_port *port, int c) +{ + wait_for_xmitr(port); + writeb(c, port->membase + VT8500_TXFIFO); +} + +static void vt8500_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index]; + unsigned long ier; + + BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr); + + ier = vt8500_read(&vt8500_port->uart, VT8500_URIER); + vt8500_write(&vt8500_port->uart, VT8500_URIER, 0); + + uart_console_write(&vt8500_port->uart, s, count, + vt8500_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and switch back to FIFO + */ + wait_for_xmitr(&vt8500_port->uart); + vt8500_write(&vt8500_port->uart, VT8500_URIER, ier); +} + +static int __init vt8500_console_setup(struct console *co, char *options) +{ + struct vt8500_port *vt8500_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0)) + return -ENXIO; + + vt8500_port = vt8500_uart_ports[co->index]; + + if (!vt8500_port) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&vt8500_port->uart, + co, baud, parity, bits, flow); +} + +static struct console vt8500_console = { + .name = "ttyWMT", + .write = vt8500_console_write, + .device = uart_console_device, + .setup = vt8500_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &vt8500_uart_driver, +}; + +#define VT8500_CONSOLE (&vt8500_console) + +#else +#define VT8500_CONSOLE NULL +#endif + +static struct uart_ops vt8500_uart_pops = { + .tx_empty = vt8500_tx_empty, + .set_mctrl = vt8500_set_mctrl, + .get_mctrl = vt8500_get_mctrl, + .stop_tx = vt8500_stop_tx, + .start_tx = vt8500_start_tx, + .stop_rx = vt8500_stop_rx, + .enable_ms = vt8500_enable_ms, + .break_ctl = vt8500_break_ctl, + .startup = vt8500_startup, + .shutdown = vt8500_shutdown, + .set_termios = vt8500_set_termios, + .type = vt8500_type, + .release_port = vt8500_release_port, + .request_port = vt8500_request_port, + .config_port = vt8500_config_port, + .verify_port = vt8500_verify_port, +}; + +static struct uart_driver vt8500_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "vt8500_serial", + .dev_name = "ttyWMT", + .nr = 6, + .cons = VT8500_CONSOLE, +}; + +static int __init vt8500_serial_probe(struct platform_device *pdev) +{ + struct vt8500_port *vt8500_port; + struct resource *mmres, *irqres; + int ret; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mmres || !irqres) + return -ENODEV; + + vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL); + if (!vt8500_port) + return -ENOMEM; + + vt8500_port->uart.type = PORT_VT8500; + vt8500_port->uart.iotype = UPIO_MEM; + vt8500_port->uart.mapbase = mmres->start; + vt8500_port->uart.irq = irqres->start; + vt8500_port->uart.fifosize = 16; + vt8500_port->uart.ops = &vt8500_uart_pops; + vt8500_port->uart.line = pdev->id; + vt8500_port->uart.dev = &pdev->dev; + vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; + vt8500_port->uart.uartclk = 24000000; + + snprintf(vt8500_port->name, sizeof(vt8500_port->name), + "VT8500 UART%d", pdev->id); + + vt8500_port->uart.membase = ioremap(mmres->start, + mmres->end - mmres->start + 1); + if (!vt8500_port->uart.membase) { + ret = -ENOMEM; + goto err; + } + + vt8500_uart_ports[pdev->id] = vt8500_port; + + uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart); + + platform_set_drvdata(pdev, vt8500_port); + + return 0; + +err: + kfree(vt8500_port); + return ret; +} + +static int __devexit vt8500_serial_remove(struct platform_device *pdev) +{ + struct vt8500_port *vt8500_port = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart); + kfree(vt8500_port); + + return 0; +} + +static struct platform_driver vt8500_platform_driver = { + .probe = vt8500_serial_probe, + .remove = vt8500_serial_remove, + .driver = { + .name = "vt8500_serial", + .owner = THIS_MODULE, + }, +}; + +static int __init vt8500_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&vt8500_uart_driver); + if (unlikely(ret)) + return ret; + + ret = platform_driver_register(&vt8500_platform_driver); + + if (unlikely(ret)) + uart_unregister_driver(&vt8500_uart_driver); + + return ret; +} + +static void __exit vt8500_serial_exit(void) +{ +#ifdef CONFIG_SERIAL_VT8500_CONSOLE + unregister_console(&vt8500_console); +#endif + platform_driver_unregister(&vt8500_platform_driver); + uart_unregister_driver(&vt8500_uart_driver); +} + +module_init(vt8500_serial_init); +module_exit(vt8500_serial_exit); + +MODULE_AUTHOR("Alexey Charkov "); +MODULE_DESCRIPTION("Driver for vt8500 serial device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c new file mode 100644 index 000000000000..1a7fd3e70315 --- /dev/null +++ b/drivers/tty/serial/zs.c @@ -0,0 +1,1304 @@ +/* + * zs.c: Serial port driver for IOASIC DECstations. + * + * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. + * Derived from drivers/macintosh/macserial.c by Harald Koerfgen. + * + * DECstation changes + * Copyright (C) 1998-2000 Harald Koerfgen + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki + * + * For the rest of the code the original Copyright applies: + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * + * Note: for IOASIC systems the wiring is as follows: + * + * mouse/keyboard: + * DIN-7 MJ-4 signal SCC + * 2 1 TxD <- A.TxD + * 3 4 RxD -> A.RxD + * + * EIA-232/EIA-423: + * DB-25 MMJ-6 signal SCC + * 2 2 TxD <- B.TxD + * 3 5 RxD -> B.RxD + * 4 RTS <- ~A.RTS + * 5 CTS -> ~B.CTS + * 6 6 DSR -> ~A.SYNC + * 8 CD -> ~B.DCD + * 12 DSRS(DCE) -> ~A.CTS (*) + * 15 TxC -> B.TxC + * 17 RxC -> B.RxC + * 20 1 DTR <- ~A.DTR + * 22 RI -> ~A.DCD + * 23 DSRS(DTE) <- ~B.RTS + * + * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE) + * is shared with DSRS(DTE) at pin 23. + * + * As you can immediately notice the wiring of the RTS, DTR and DSR signals + * is a bit odd. This makes the handling of port B unnecessarily + * complicated and prevents the use of some automatic modes of operation. + */ + +#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "zs.h" + + +MODULE_AUTHOR("Maciej W. Rozycki "); +MODULE_DESCRIPTION("DECstation Z85C30 serial driver"); +MODULE_LICENSE("GPL"); + + +static char zs_name[] __initdata = "DECstation Z85C30 serial driver version "; +static char zs_version[] __initdata = "0.10"; + +/* + * It would be nice to dynamically allocate everything that + * depends on ZS_NUM_SCCS, so we could support any number of + * Z85C30s, but for now... + */ +#define ZS_NUM_SCCS 2 /* Max # of ZS chips supported. */ +#define ZS_NUM_CHAN 2 /* 2 channels per chip. */ +#define ZS_CHAN_A 0 /* Index of the channel A. */ +#define ZS_CHAN_B 1 /* Index of the channel B. */ +#define ZS_CHAN_IO_SIZE 8 /* IOMEM space size. */ +#define ZS_CHAN_IO_STRIDE 4 /* Register alignment. */ +#define ZS_CHAN_IO_OFFSET 1 /* The SCC resides on the high byte + of the 16-bit IOBUS. */ +#define ZS_CLOCK 7372800 /* Z85C30 PCLK input clock rate. */ + +#define to_zport(uport) container_of(uport, struct zs_port, port) + +struct zs_parms { + resource_size_t scc[ZS_NUM_SCCS]; + int irq[ZS_NUM_SCCS]; +}; + +static struct zs_scc zs_sccs[ZS_NUM_SCCS]; + +static u8 zs_init_regs[ZS_NUM_REGS] __initdata = { + 0, /* write 0 */ + PAR_SPEC, /* write 1 */ + 0, /* write 2 */ + 0, /* write 3 */ + X16CLK | SB1, /* write 4 */ + 0, /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + MIE | DLC | NV, /* write 9 */ + NRZ, /* write 10 */ + TCBR | RCBR, /* write 11 */ + 0, 0, /* BRG time constant, write 12 + 13 */ + BRSRC | BRENABL, /* write 14 */ + 0, /* write 15 */ +}; + +/* + * Debugging. + */ +#undef ZS_DEBUG_REGS + + +/* + * Reading and writing Z85C30 registers. + */ +static void recovery_delay(void) +{ + udelay(2); +} + +static u8 read_zsreg(struct zs_port *zport, int reg) +{ + void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET; + u8 retval; + + if (reg != 0) { + writeb(reg & 0xf, control); + fast_iob(); + recovery_delay(); + } + retval = readb(control); + recovery_delay(); + return retval; +} + +static void write_zsreg(struct zs_port *zport, int reg, u8 value) +{ + void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET; + + if (reg != 0) { + writeb(reg & 0xf, control); + fast_iob(); recovery_delay(); + } + writeb(value, control); + fast_iob(); + recovery_delay(); + return; +} + +static u8 read_zsdata(struct zs_port *zport) +{ + void __iomem *data = zport->port.membase + + ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET; + u8 retval; + + retval = readb(data); + recovery_delay(); + return retval; +} + +static void write_zsdata(struct zs_port *zport, u8 value) +{ + void __iomem *data = zport->port.membase + + ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET; + + writeb(value, data); + fast_iob(); + recovery_delay(); + return; +} + +#ifdef ZS_DEBUG_REGS +void zs_dump(void) +{ + struct zs_port *zport; + int i, j; + + for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { + zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN]; + + if (!zport->scc) + continue; + + for (j = 0; j < 16; j++) + printk("W%-2d = 0x%02x\t", j, zport->regs[j]); + printk("\n"); + for (j = 0; j < 16; j++) + printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j)); + printk("\n\n"); + } +} +#endif + + +static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq) +{ + if (irq) + spin_lock_irq(lock); + else + spin_lock(lock); +} + +static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq) +{ + if (irq) + spin_unlock_irq(lock); + else + spin_unlock(lock); +} + +static int zs_receive_drain(struct zs_port *zport) +{ + int loops = 10000; + + while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops) + read_zsdata(zport); + return loops; +} + +static int zs_transmit_drain(struct zs_port *zport, int irq) +{ + struct zs_scc *scc = zport->scc; + int loops = 10000; + + while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) { + zs_spin_unlock_cond_irq(&scc->zlock, irq); + udelay(2); + zs_spin_lock_cond_irq(&scc->zlock, irq); + } + return loops; +} + +static int zs_line_drain(struct zs_port *zport, int irq) +{ + struct zs_scc *scc = zport->scc; + int loops = 10000; + + while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) { + zs_spin_unlock_cond_irq(&scc->zlock, irq); + udelay(2); + zs_spin_lock_cond_irq(&scc->zlock, irq); + } + return loops; +} + + +static void load_zsregs(struct zs_port *zport, u8 *regs, int irq) +{ + /* Let the current transmission finish. */ + zs_line_drain(zport, irq); + /* Load 'em up. */ + write_zsreg(zport, R3, regs[3] & ~RxENABLE); + write_zsreg(zport, R5, regs[5] & ~TxENAB); + write_zsreg(zport, R4, regs[4]); + write_zsreg(zport, R9, regs[9]); + write_zsreg(zport, R1, regs[1]); + write_zsreg(zport, R2, regs[2]); + write_zsreg(zport, R10, regs[10]); + write_zsreg(zport, R14, regs[14] & ~BRENABL); + write_zsreg(zport, R11, regs[11]); + write_zsreg(zport, R12, regs[12]); + write_zsreg(zport, R13, regs[13]); + write_zsreg(zport, R14, regs[14]); + write_zsreg(zport, R15, regs[15]); + if (regs[3] & RxENABLE) + write_zsreg(zport, R3, regs[3]); + if (regs[5] & TxENAB) + write_zsreg(zport, R5, regs[5]); + return; +} + + +/* + * Status handling routines. + */ + +/* + * zs_tx_empty() -- get the transmitter empty status + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static unsigned int zs_tx_empty(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + u8 status; + + spin_lock_irqsave(&scc->zlock, flags); + status = read_zsreg(zport, R1); + spin_unlock_irqrestore(&scc->zlock, flags); + + return status & ALL_SNT ? TIOCSER_TEMT : 0; +} + +static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a, + struct zs_port *zport_b) +{ + u8 status_a, status_b; + unsigned int mctrl; + + status_a = read_zsreg(zport_a, R0); + status_b = read_zsreg(zport_b, R0); + + mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) | + ((status_b & DCD) ? TIOCM_CAR : 0) | + ((status_a & DCD) ? TIOCM_RNG : 0) | + ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0); + + return mctrl; +} + +static unsigned int zs_raw_get_mctrl(struct zs_port *zport) +{ + struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; + + return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0; +} + +static unsigned int zs_raw_xor_mctrl(struct zs_port *zport) +{ + struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; + unsigned int mmask, mctrl, delta; + u8 mask_a, mask_b; + + if (zport == zport_a) + return 0; + + mask_a = zport_a->regs[15]; + mask_b = zport->regs[15]; + + mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) | + ((mask_b & DCDIE) ? TIOCM_CAR : 0) | + ((mask_a & DCDIE) ? TIOCM_RNG : 0) | + ((mask_a & SYNCIE) ? TIOCM_DSR : 0); + + mctrl = zport->mctrl; + if (mmask) { + mctrl &= ~mmask; + mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask; + } + + delta = mctrl ^ zport->mctrl; + if (delta) + zport->mctrl = mctrl; + + return delta; +} + +static unsigned int zs_get_mctrl(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned int mctrl; + + spin_lock(&scc->zlock); + mctrl = zs_raw_get_mctrl(zport); + spin_unlock(&scc->zlock); + + return mctrl; +} + +static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + u8 oldloop, newloop; + + spin_lock(&scc->zlock); + if (zport != zport_a) { + if (mctrl & TIOCM_DTR) + zport_a->regs[5] |= DTR; + else + zport_a->regs[5] &= ~DTR; + if (mctrl & TIOCM_RTS) + zport_a->regs[5] |= RTS; + else + zport_a->regs[5] &= ~RTS; + write_zsreg(zport_a, R5, zport_a->regs[5]); + } + + /* Rarely modified, so don't poke at hardware unless necessary. */ + oldloop = zport->regs[14]; + newloop = oldloop; + if (mctrl & TIOCM_LOOP) + newloop |= LOOPBAK; + else + newloop &= ~LOOPBAK; + if (newloop != oldloop) { + zport->regs[14] = newloop; + write_zsreg(zport, R14, zport->regs[14]); + } + spin_unlock(&scc->zlock); +} + +static void zs_raw_stop_tx(struct zs_port *zport) +{ + write_zsreg(zport, R0, RES_Tx_P); + zport->tx_stopped = 1; +} + +static void zs_stop_tx(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + + spin_lock(&scc->zlock); + zs_raw_stop_tx(zport); + spin_unlock(&scc->zlock); +} + +static void zs_raw_transmit_chars(struct zs_port *); + +static void zs_start_tx(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + + spin_lock(&scc->zlock); + if (zport->tx_stopped) { + zs_transmit_drain(zport, 0); + zport->tx_stopped = 0; + zs_raw_transmit_chars(zport); + } + spin_unlock(&scc->zlock); +} + +static void zs_stop_rx(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + + spin_lock(&scc->zlock); + zport->regs[15] &= ~BRKIE; + zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB); + zport->regs[1] |= RxINT_DISAB; + + if (zport != zport_a) { + /* A-side DCD tracks RI and SYNC tracks DSR. */ + zport_a->regs[15] &= ~(DCDIE | SYNCIE); + write_zsreg(zport_a, R15, zport_a->regs[15]); + if (!(zport_a->regs[15] & BRKIE)) { + zport_a->regs[1] &= ~EXT_INT_ENAB; + write_zsreg(zport_a, R1, zport_a->regs[1]); + } + + /* This-side DCD tracks DCD and CTS tracks CTS. */ + zport->regs[15] &= ~(DCDIE | CTSIE); + zport->regs[1] &= ~EXT_INT_ENAB; + } else { + /* DCD tracks RI and SYNC tracks DSR for the B side. */ + if (!(zport->regs[15] & (DCDIE | SYNCIE))) + zport->regs[1] &= ~EXT_INT_ENAB; + } + + write_zsreg(zport, R15, zport->regs[15]); + write_zsreg(zport, R1, zport->regs[1]); + spin_unlock(&scc->zlock); +} + +static void zs_enable_ms(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + + if (zport == zport_a) + return; + + spin_lock(&scc->zlock); + + /* Clear Ext interrupts if not being handled already. */ + if (!(zport_a->regs[1] & EXT_INT_ENAB)) + write_zsreg(zport_a, R0, RES_EXT_INT); + + /* A-side DCD tracks RI and SYNC tracks DSR. */ + zport_a->regs[1] |= EXT_INT_ENAB; + zport_a->regs[15] |= DCDIE | SYNCIE; + + /* This-side DCD tracks DCD and CTS tracks CTS. */ + zport->regs[15] |= DCDIE | CTSIE; + + zs_raw_xor_mctrl(zport); + + write_zsreg(zport_a, R1, zport_a->regs[1]); + write_zsreg(zport_a, R15, zport_a->regs[15]); + write_zsreg(zport, R15, zport->regs[15]); + spin_unlock(&scc->zlock); +} + +static void zs_break_ctl(struct uart_port *uport, int break_state) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + if (break_state == -1) + zport->regs[5] |= SND_BRK; + else + zport->regs[5] &= ~SND_BRK; + write_zsreg(zport, R5, zport->regs[5]); + spin_unlock_irqrestore(&scc->zlock, flags); +} + + +/* + * Interrupt handling routines. + */ +#define Rx_BRK 0x0100 /* BREAK event software flag. */ +#define Rx_SYS 0x0200 /* SysRq event software flag. */ + +static void zs_receive_chars(struct zs_port *zport) +{ + struct uart_port *uport = &zport->port; + struct zs_scc *scc = zport->scc; + struct uart_icount *icount; + unsigned int avail, status, ch, flag; + int count; + + for (count = 16; count; count--) { + spin_lock(&scc->zlock); + avail = read_zsreg(zport, R0) & Rx_CH_AV; + spin_unlock(&scc->zlock); + if (!avail) + break; + + spin_lock(&scc->zlock); + status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR); + ch = read_zsdata(zport); + spin_unlock(&scc->zlock); + + flag = TTY_NORMAL; + + icount = &uport->icount; + icount->rx++; + + /* Handle the null char got when BREAK is removed. */ + if (!ch) + status |= zport->tty_break; + if (unlikely(status & + (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) { + zport->tty_break = 0; + + /* Reset the error indication. */ + if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) { + spin_lock(&scc->zlock); + write_zsreg(zport, R0, ERR_RES); + spin_unlock(&scc->zlock); + } + + if (status & (Rx_SYS | Rx_BRK)) { + icount->brk++; + /* SysRq discards the null char. */ + if (status & Rx_SYS) + continue; + } else if (status & FRM_ERR) + icount->frame++; + else if (status & PAR_ERR) + icount->parity++; + if (status & Rx_OVR) + icount->overrun++; + + status &= uport->read_status_mask; + if (status & Rx_BRK) + flag = TTY_BREAK; + else if (status & FRM_ERR) + flag = TTY_FRAME; + else if (status & PAR_ERR) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(uport, ch)) + continue; + + uart_insert_char(uport, status, Rx_OVR, ch, flag); + } + + tty_flip_buffer_push(uport->state->port.tty); +} + +static void zs_raw_transmit_chars(struct zs_port *zport) +{ + struct circ_buf *xmit = &zport->port.state->xmit; + + /* XON/XOFF chars. */ + if (zport->port.x_char) { + write_zsdata(zport, zport->port.x_char); + zport->port.icount.tx++; + zport->port.x_char = 0; + return; + } + + /* If nothing to do or stopped or hardware stopped. */ + if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) { + zs_raw_stop_tx(zport); + return; + } + + /* Send char. */ + write_zsdata(zport, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + zport->port.icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&zport->port); + + /* Are we are done? */ + if (uart_circ_empty(xmit)) + zs_raw_stop_tx(zport); +} + +static void zs_transmit_chars(struct zs_port *zport) +{ + struct zs_scc *scc = zport->scc; + + spin_lock(&scc->zlock); + zs_raw_transmit_chars(zport); + spin_unlock(&scc->zlock); +} + +static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a) +{ + struct uart_port *uport = &zport->port; + struct zs_scc *scc = zport->scc; + unsigned int delta; + u8 status, brk; + + spin_lock(&scc->zlock); + + /* Get status from Read Register 0. */ + status = read_zsreg(zport, R0); + + if (zport->regs[15] & BRKIE) { + brk = status & BRK_ABRT; + if (brk && !zport->brk) { + spin_unlock(&scc->zlock); + if (uart_handle_break(uport)) + zport->tty_break = Rx_SYS; + else + zport->tty_break = Rx_BRK; + spin_lock(&scc->zlock); + } + zport->brk = brk; + } + + if (zport != zport_a) { + delta = zs_raw_xor_mctrl(zport); + spin_unlock(&scc->zlock); + + if (delta & TIOCM_CTS) + uart_handle_cts_change(uport, + zport->mctrl & TIOCM_CTS); + if (delta & TIOCM_CAR) + uart_handle_dcd_change(uport, + zport->mctrl & TIOCM_CAR); + if (delta & TIOCM_RNG) + uport->icount.dsr++; + if (delta & TIOCM_DSR) + uport->icount.rng++; + + if (delta) + wake_up_interruptible(&uport->state->port.delta_msr_wait); + + spin_lock(&scc->zlock); + } + + /* Clear the status condition... */ + write_zsreg(zport, R0, RES_EXT_INT); + + spin_unlock(&scc->zlock); +} + +/* + * This is the Z85C30 driver's generic interrupt routine. + */ +static irqreturn_t zs_interrupt(int irq, void *dev_id) +{ + struct zs_scc *scc = dev_id; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + struct zs_port *zport_b = &scc->zport[ZS_CHAN_B]; + irqreturn_t status = IRQ_NONE; + u8 zs_intreg; + int count; + + /* + * NOTE: The read register 3, which holds the irq status, + * does so for both channels on each chip. Although + * the status value itself must be read from the A + * channel and is only valid when read from channel A. + * Yes... broken hardware... + */ + for (count = 16; count; count--) { + spin_lock(&scc->zlock); + zs_intreg = read_zsreg(zport_a, R3); + spin_unlock(&scc->zlock); + if (!zs_intreg) + break; + + /* + * We do not like losing characters, so we prioritise + * interrupt sources a little bit differently than + * the SCC would, was it allowed to. + */ + if (zs_intreg & CHBRxIP) + zs_receive_chars(zport_b); + if (zs_intreg & CHARxIP) + zs_receive_chars(zport_a); + if (zs_intreg & CHBEXT) + zs_status_handle(zport_b, zport_a); + if (zs_intreg & CHAEXT) + zs_status_handle(zport_a, zport_a); + if (zs_intreg & CHBTxIP) + zs_transmit_chars(zport_b); + if (zs_intreg & CHATxIP) + zs_transmit_chars(zport_a); + + status = IRQ_HANDLED; + } + + return status; +} + + +/* + * Finally, routines used to initialize the serial port. + */ +static int zs_startup(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + int irq_guard; + int ret; + + irq_guard = atomic_add_return(1, &scc->irq_guard); + if (irq_guard == 1) { + ret = request_irq(zport->port.irq, zs_interrupt, + IRQF_SHARED, "scc", scc); + if (ret) { + atomic_add(-1, &scc->irq_guard); + printk(KERN_ERR "zs: can't get irq %d\n", + zport->port.irq); + return ret; + } + } + + spin_lock_irqsave(&scc->zlock, flags); + + /* Clear the receive FIFO. */ + zs_receive_drain(zport); + + /* Clear the interrupt registers. */ + write_zsreg(zport, R0, ERR_RES); + write_zsreg(zport, R0, RES_Tx_P); + /* But Ext only if not being handled already. */ + if (!(zport->regs[1] & EXT_INT_ENAB)) + write_zsreg(zport, R0, RES_EXT_INT); + + /* Finally, enable sequencing and interrupts. */ + zport->regs[1] &= ~RxINT_MASK; + zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB; + zport->regs[3] |= RxENABLE; + zport->regs[15] |= BRKIE; + write_zsreg(zport, R1, zport->regs[1]); + write_zsreg(zport, R3, zport->regs[3]); + write_zsreg(zport, R5, zport->regs[5]); + write_zsreg(zport, R15, zport->regs[15]); + + /* Record the current state of RR0. */ + zport->mctrl = zs_raw_get_mctrl(zport); + zport->brk = read_zsreg(zport, R0) & BRK_ABRT; + + zport->tx_stopped = 1; + + spin_unlock_irqrestore(&scc->zlock, flags); + + return 0; +} + +static void zs_shutdown(struct uart_port *uport) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + unsigned long flags; + int irq_guard; + + spin_lock_irqsave(&scc->zlock, flags); + + zport->regs[3] &= ~RxENABLE; + write_zsreg(zport, R5, zport->regs[5]); + write_zsreg(zport, R3, zport->regs[3]); + + spin_unlock_irqrestore(&scc->zlock, flags); + + irq_guard = atomic_add_return(-1, &scc->irq_guard); + if (!irq_guard) + free_irq(zport->port.irq, scc); +} + + +static void zs_reset(struct zs_port *zport) +{ + struct zs_scc *scc = zport->scc; + int irq; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + if (!scc->initialised) { + /* Reset the pointer first, just in case... */ + read_zsreg(zport, R0); + /* And let the current transmission finish. */ + zs_line_drain(zport, irq); + write_zsreg(zport, R9, FHWRES); + udelay(10); + write_zsreg(zport, R9, 0); + scc->initialised = 1; + } + load_zsregs(zport, zport->regs, irq); + spin_unlock_irqrestore(&scc->zlock, flags); +} + +static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, + struct ktermios *old_termios) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + struct zs_port *zport_a = &scc->zport[ZS_CHAN_A]; + int irq; + unsigned int baud, brg; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + + /* Byte size. */ + zport->regs[3] &= ~RxNBITS_MASK; + zport->regs[5] &= ~TxNBITS_MASK; + switch (termios->c_cflag & CSIZE) { + case CS5: + zport->regs[3] |= Rx5; + zport->regs[5] |= Tx5; + break; + case CS6: + zport->regs[3] |= Rx6; + zport->regs[5] |= Tx6; + break; + case CS7: + zport->regs[3] |= Rx7; + zport->regs[5] |= Tx7; + break; + case CS8: + default: + zport->regs[3] |= Rx8; + zport->regs[5] |= Tx8; + break; + } + + /* Parity and stop bits. */ + zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN); + if (termios->c_cflag & CSTOPB) + zport->regs[4] |= SB2; + else + zport->regs[4] |= SB1; + if (termios->c_cflag & PARENB) + zport->regs[4] |= PAR_ENA; + if (!(termios->c_cflag & PARODD)) + zport->regs[4] |= PAR_EVEN; + switch (zport->clk_mode) { + case 64: + zport->regs[4] |= X64CLK; + break; + case 32: + zport->regs[4] |= X32CLK; + break; + case 16: + zport->regs[4] |= X16CLK; + break; + case 1: + zport->regs[4] |= X1CLK; + break; + default: + BUG(); + } + + baud = uart_get_baud_rate(uport, termios, old_termios, 0, + uport->uartclk / zport->clk_mode / 4); + + brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode); + zport->regs[12] = brg & 0xff; + zport->regs[13] = (brg >> 8) & 0xff; + + uart_update_timeout(uport, termios->c_cflag, baud); + + uport->read_status_mask = Rx_OVR; + if (termios->c_iflag & INPCK) + uport->read_status_mask |= FRM_ERR | PAR_ERR; + if (termios->c_iflag & (BRKINT | PARMRK)) + uport->read_status_mask |= Rx_BRK; + + uport->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= FRM_ERR | PAR_ERR; + if (termios->c_iflag & IGNBRK) { + uport->ignore_status_mask |= Rx_BRK; + if (termios->c_iflag & IGNPAR) + uport->ignore_status_mask |= Rx_OVR; + } + + if (termios->c_cflag & CREAD) + zport->regs[3] |= RxENABLE; + else + zport->regs[3] &= ~RxENABLE; + + if (zport != zport_a) { + if (!(termios->c_cflag & CLOCAL)) { + zport->regs[15] |= DCDIE; + } else + zport->regs[15] &= ~DCDIE; + if (termios->c_cflag & CRTSCTS) { + zport->regs[15] |= CTSIE; + } else + zport->regs[15] &= ~CTSIE; + zs_raw_xor_mctrl(zport); + } + + /* Load up the new values. */ + load_zsregs(zport, zport->regs, irq); + + spin_unlock_irqrestore(&scc->zlock, flags); +} + +/* + * Hack alert! + * Required solely so that the initial PROM-based console + * works undisturbed in parallel with this one. + */ +static void zs_pm(struct uart_port *uport, unsigned int state, + unsigned int oldstate) +{ + struct zs_port *zport = to_zport(uport); + + if (state < 3) + zport->regs[5] |= TxENAB; + else + zport->regs[5] &= ~TxENAB; + write_zsreg(zport, R5, zport->regs[5]); +} + + +static const char *zs_type(struct uart_port *uport) +{ + return "Z85C30 SCC"; +} + +static void zs_release_port(struct uart_port *uport) +{ + iounmap(uport->membase); + uport->membase = 0; + release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); +} + +static int zs_map_port(struct uart_port *uport) +{ + if (!uport->membase) + uport->membase = ioremap_nocache(uport->mapbase, + ZS_CHAN_IO_SIZE); + if (!uport->membase) { + printk(KERN_ERR "zs: Cannot map MMIO\n"); + return -ENOMEM; + } + return 0; +} + +static int zs_request_port(struct uart_port *uport) +{ + int ret; + + if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) { + printk(KERN_ERR "zs: Unable to reserve MMIO resource\n"); + return -EBUSY; + } + ret = zs_map_port(uport); + if (ret) { + release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE); + return ret; + } + return 0; +} + +static void zs_config_port(struct uart_port *uport, int flags) +{ + struct zs_port *zport = to_zport(uport); + + if (flags & UART_CONFIG_TYPE) { + if (zs_request_port(uport)) + return; + + uport->type = PORT_ZS; + + zs_reset(zport); + } +} + +static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser) +{ + struct zs_port *zport = to_zport(uport); + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS) + ret = -EINVAL; + if (ser->irq != uport->irq) + ret = -EINVAL; + if (ser->baud_base != uport->uartclk / zport->clk_mode / 4) + ret = -EINVAL; + return ret; +} + + +static struct uart_ops zs_ops = { + .tx_empty = zs_tx_empty, + .set_mctrl = zs_set_mctrl, + .get_mctrl = zs_get_mctrl, + .stop_tx = zs_stop_tx, + .start_tx = zs_start_tx, + .stop_rx = zs_stop_rx, + .enable_ms = zs_enable_ms, + .break_ctl = zs_break_ctl, + .startup = zs_startup, + .shutdown = zs_shutdown, + .set_termios = zs_set_termios, + .pm = zs_pm, + .type = zs_type, + .release_port = zs_release_port, + .request_port = zs_request_port, + .config_port = zs_config_port, + .verify_port = zs_verify_port, +}; + +/* + * Initialize Z85C30 port structures. + */ +static int __init zs_probe_sccs(void) +{ + static int probed; + struct zs_parms zs_parms; + int chip, side, irq; + int n_chips = 0; + int i; + + if (probed) + return 0; + + irq = dec_interrupt[DEC_IRQ_SCC0]; + if (irq >= 0) { + zs_parms.scc[n_chips] = IOASIC_SCC0; + zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0]; + n_chips++; + } + irq = dec_interrupt[DEC_IRQ_SCC1]; + if (irq >= 0) { + zs_parms.scc[n_chips] = IOASIC_SCC1; + zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1]; + n_chips++; + } + if (!n_chips) + return -ENXIO; + + probed = 1; + + for (chip = 0; chip < n_chips; chip++) { + spin_lock_init(&zs_sccs[chip].zlock); + for (side = 0; side < ZS_NUM_CHAN; side++) { + struct zs_port *zport = &zs_sccs[chip].zport[side]; + struct uart_port *uport = &zport->port; + + zport->scc = &zs_sccs[chip]; + zport->clk_mode = 16; + + uport->irq = zs_parms.irq[chip]; + uport->uartclk = ZS_CLOCK; + uport->fifosize = 1; + uport->iotype = UPIO_MEM; + uport->flags = UPF_BOOT_AUTOCONF; + uport->ops = &zs_ops; + uport->line = chip * ZS_NUM_CHAN + side; + uport->mapbase = dec_kn_slot_base + + zs_parms.scc[chip] + + (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE; + + for (i = 0; i < ZS_NUM_REGS; i++) + zport->regs[i] = zs_init_regs[i]; + } + } + + return 0; +} + + +#ifdef CONFIG_SERIAL_ZS_CONSOLE +static void zs_console_putchar(struct uart_port *uport, int ch) +{ + struct zs_port *zport = to_zport(uport); + struct zs_scc *scc = zport->scc; + int irq; + unsigned long flags; + + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + if (zs_transmit_drain(zport, irq)) + write_zsdata(zport, ch); + spin_unlock_irqrestore(&scc->zlock, flags); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void zs_console_write(struct console *co, const char *s, + unsigned int count) +{ + int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; + struct zs_port *zport = &zs_sccs[chip].zport[side]; + struct zs_scc *scc = zport->scc; + unsigned long flags; + u8 txint, txenb; + int irq; + + /* Disable transmit interrupts and enable the transmitter. */ + spin_lock_irqsave(&scc->zlock, flags); + txint = zport->regs[1]; + txenb = zport->regs[5]; + if (txint & TxINT_ENAB) { + zport->regs[1] = txint & ~TxINT_ENAB; + write_zsreg(zport, R1, zport->regs[1]); + } + if (!(txenb & TxENAB)) { + zport->regs[5] = txenb | TxENAB; + write_zsreg(zport, R5, zport->regs[5]); + } + spin_unlock_irqrestore(&scc->zlock, flags); + + uart_console_write(&zport->port, s, count, zs_console_putchar); + + /* Restore transmit interrupts and the transmitter enable. */ + spin_lock_irqsave(&scc->zlock, flags); + irq = !irqs_disabled_flags(flags); + zs_line_drain(zport, irq); + if (!(txenb & TxENAB)) { + zport->regs[5] &= ~TxENAB; + write_zsreg(zport, R5, zport->regs[5]); + } + if (txint & TxINT_ENAB) { + zport->regs[1] |= TxINT_ENAB; + write_zsreg(zport, R1, zport->regs[1]); + } + spin_unlock_irqrestore(&scc->zlock, flags); +} + +/* + * Setup serial console baud/bits/parity. We do two things here: + * - construct a cflag setting for the first uart_open() + * - initialise the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init zs_console_setup(struct console *co, char *options) +{ + int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN; + struct zs_port *zport = &zs_sccs[chip].zport[side]; + struct uart_port *uport = &zport->port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + ret = zs_map_port(uport); + if (ret) + return ret; + + zs_reset(zport); + zs_pm(uport, 0, -1); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(uport, co, baud, parity, bits, flow); +} + +static struct uart_driver zs_reg; +static struct console zs_console = { + .name = "ttyS", + .write = zs_console_write, + .device = uart_console_device, + .setup = zs_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &zs_reg, +}; + +/* + * Register console. + */ +static int __init zs_serial_console_init(void) +{ + int ret; + + ret = zs_probe_sccs(); + if (ret) + return ret; + register_console(&zs_console); + + return 0; +} + +console_initcall(zs_serial_console_init); + +#define SERIAL_ZS_CONSOLE &zs_console +#else +#define SERIAL_ZS_CONSOLE NULL +#endif /* CONFIG_SERIAL_ZS_CONSOLE */ + +static struct uart_driver zs_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = ZS_NUM_SCCS * ZS_NUM_CHAN, + .cons = SERIAL_ZS_CONSOLE, +}; + +/* zs_init inits the driver. */ +static int __init zs_init(void) +{ + int i, ret; + + pr_info("%s%s\n", zs_name, zs_version); + + /* Find out how many Z85C30 SCCs we have. */ + ret = zs_probe_sccs(); + if (ret) + return ret; + + ret = uart_register_driver(&zs_reg); + if (ret) + return ret; + + for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) { + struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; + struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; + struct uart_port *uport = &zport->port; + + if (zport->scc) + uart_add_one_port(&zs_reg, uport); + } + + return 0; +} + +static void __exit zs_exit(void) +{ + int i; + + for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) { + struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN]; + struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN]; + struct uart_port *uport = &zport->port; + + if (zport->scc) + uart_remove_one_port(&zs_reg, uport); + } + + uart_unregister_driver(&zs_reg); +} + +module_init(zs_init); +module_exit(zs_exit); diff --git a/drivers/tty/serial/zs.h b/drivers/tty/serial/zs.h new file mode 100644 index 000000000000..aa921b57d827 --- /dev/null +++ b/drivers/tty/serial/zs.h @@ -0,0 +1,284 @@ +/* + * zs.h: Definitions for the DECstation Z85C30 serial driver. + * + * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. + * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen. + * + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2004, 2005, 2007 Maciej W. Rozycki + */ +#ifndef _SERIAL_ZS_H +#define _SERIAL_ZS_H + +#ifdef __KERNEL__ + +#define ZS_NUM_REGS 16 + +/* + * This is our internal structure for each serial port's state. + */ +struct zs_port { + struct zs_scc *scc; /* Containing SCC. */ + struct uart_port port; /* Underlying UART. */ + + int clk_mode; /* May be 1, 16, 32, or 64. */ + + unsigned int tty_break; /* Set on BREAK condition. */ + int tx_stopped; /* Output is suspended. */ + + unsigned int mctrl; /* State of modem lines. */ + u8 brk; /* BREAK state from RR0. */ + + u8 regs[ZS_NUM_REGS]; /* Channel write registers. */ +}; + +/* + * Per-SCC state for locking and the interrupt handler. + */ +struct zs_scc { + struct zs_port zport[2]; + spinlock_t zlock; + atomic_t irq_guard; + int initialised; +}; + +#endif /* __KERNEL__ */ + +/* + * Conversion routines to/from brg time constants from/to bits per second. + */ +#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* + * The Zilog register set. + */ + +/* Write Register 0 (Command) */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */ +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */ +#define RxINT_ERR 0x18 /* Int on error only */ +#define RxINT_MASK 0x18 + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register 2 (Interrupt Vector) */ + +/* Write Register 3 (Receive Parameters and Control) */ +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxNBITS_MASK 0xc0 + +/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */ +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ +#define SB_MASK 0xc + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xc0 /* x64 clock mode */ +#define XCLK_MASK 0xc0 + +/* Write Register 5 (Transmit Parameters and Controls) */ +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxNBITS_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (Transmit Buffer) */ + +/* Write Register 9 (Master Interrupt Control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode Control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */ + +/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */ + +/* Write Register 14 (Miscellaneous Control Bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (External/Status Interrupt Control) */ +#define WR7P_EN 1 /* WR7 Prime SDLC Feature Enable */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 (Special Receive Condition Status) */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity Error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define FRM_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (Interrupt Vector (WR2) -- channel A). */ + +/* Read Register 2 (Modified Interrupt Vector -- channel B). */ + +/* Read Register 3 (Interrupt Pending Bits -- channel A only). */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */ + +/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */ + +/* Read Register 8 (Receive Data) */ + +/* Read Register 10 (Miscellaneous Status Bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */ + +/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */ + +/* Read Register 15 (External/Status Interrupt Control (WR15)) */ + +#endif /* _SERIAL_ZS_H */ -- cgit v1.2.3 From 695b83495e2fba9d3a883193cfc9d5eefa96a911 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 13 Jan 2011 19:02:25 +0000 Subject: IB/srp: Test only once whether iu allocation succeeded Merge the two tests in srp_queuecommand() of whether information unit allocation succeeded into one. An intended side effect of this change is that we fix the warning: drivers/infiniband/ulp/srp/ib_srp.c: In function 'srp_queuecommand': drivers/infiniband/ulp/srp/ib_srp.c:1116: warning: 'req' may be used uninitialized in this function (seen with CONFIG_CC_OPTIMIZE_FOR_SIZE=y at least with gcc 4.4.4) Signed-off-by: Bart Van Assche Acked-by: David Dillow Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 4b62105ed1e8..b28c2b9db26b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1132,15 +1132,12 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) spin_lock_irqsave(&target->lock, flags); iu = __srp_get_tx_iu(target, SRP_IU_CMD); - if (iu) { - req = list_first_entry(&target->free_reqs, struct srp_request, - list); - list_del(&req->list); - } - spin_unlock_irqrestore(&target->lock, flags); - if (!iu) - goto err; + goto err_unlock; + + req = list_first_entry(&target->free_reqs, struct srp_request, list); + list_del(&req->list); + spin_unlock_irqrestore(&target->lock, flags); dev = target->srp_host->srp_dev->dev; ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len, @@ -1185,6 +1182,8 @@ err_iu: spin_lock_irqsave(&target->lock, flags); list_add(&req->list, &target->free_reqs); + +err_unlock: spin_unlock_irqrestore(&target->lock, flags); err: -- cgit v1.2.3 From 6c9879101442b08581e8a0e3ae6b7f643a78fd63 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:13:53 +1100 Subject: md: fix regression resulting in delays in clearing bits in a bitmap commit 589a594be1fb (2.6.37-rc4) fixed a problem were md_thread would sometimes call the ->run function at a bad time. If an error is detected during array start up after the md_thread has been started, the md_thread is killed. This resulted in the ->run function being called once. However the array may not be in a state that it is safe to call ->run. However the fix imposed meant that ->run was not called on a timeout. This means that when an array goes idle, bitmap bits do not get cleared promptly. While the array is busy the bits will still be cleared when appropriate so this is not very serious. There is no risk to data. Change the test so that we only avoid calling ->run when the thread is being stopped. This more explicitly addresses the problem situation. This is suitable for 2.6.37-stable and any -stable kernel to which 589a594be1fb was applied. Cc: stable@kernel.org Signed-off-by: NeilBrown --- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 0da25daea9be..a3019121dc57 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6042,7 +6042,8 @@ static int md_thread(void * arg) || kthread_should_stop(), thread->timeout); - if (test_and_clear_bit(THREAD_WAKEUP, &thread->flags)) + clear_bit(THREAD_WAKEUP, &thread->flags); + if (!kthread_should_stop()) thread->run(thread->mddev); } -- cgit v1.2.3 From 067032bc628598606056412594042564fcf09e22 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md: Fix single printks with multiple KERN_s Noticed-by: Russell King Signed-off-by: Joe Perches Signed-off-by: NeilBrown --- drivers/md/raid1.c | 5 +++-- drivers/md/raid10.c | 5 +++-- drivers/md/raid5.c | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 845cf95b612c..d50056ba596b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1027,8 +1027,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } else set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); - printk(KERN_ALERT "md/raid1:%s: Disk failure on %s, disabling device.\n" - KERN_ALERT "md/raid1:%s: Operation continuing on %d devices.\n", + printk(KERN_ALERT + "md/raid1:%s: Disk failure on %s, disabling device.\n" + "md/raid1:%s: Operation continuing on %d devices.\n", mdname(mddev), bdevname(rdev->bdev, b), mdname(mddev), conf->raid_disks - mddev->degraded); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 0641674827f0..03825cbce2d4 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1051,8 +1051,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); - printk(KERN_ALERT "md/raid10:%s: Disk failure on %s, disabling device.\n" - KERN_ALERT "md/raid10:%s: Operation continuing on %d devices.\n", + printk(KERN_ALERT + "md/raid10:%s: Disk failure on %s, disabling device.\n" + "md/raid10:%s: Operation continuing on %d devices.\n", mdname(mddev), bdevname(rdev->bdev, b), mdname(mddev), conf->raid_disks - mddev->degraded); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index dc574f303f8b..316fbe79389a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1721,7 +1721,6 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) set_bit(Faulty, &rdev->flags); printk(KERN_ALERT "md/raid:%s: Disk failure on %s, disabling device.\n" - KERN_ALERT "md/raid:%s: Operation continuing on %d devices.\n", mdname(mddev), bdevname(rdev->bdev, b), -- cgit v1.2.3 From 0ca69886a8273ac1350143d562280bfcbe4760dc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md: Ensure no IO request to get md device before it is properly initialised. When an md device is in the process of coming on line it is possible for an IO request (typically a partition table probe) to get through before the array is fully initialised, which can cause unexpected behaviour (e.g. a crash). So explicitly record when the array is ready for IO and don't allow IO through until then. There is no possibility for a similar problem when the array is going off-line as there must only be one 'open' at that time, and it is busy off-lining the array and so cannot send IO requests. So no memory barrier is needed in md_stop() This has been a bug since commit 409c57f3801 in 2.6.30 which introduced md_make_request. Before then, each personality would register its own make_request_fn when it was ready. This is suitable for any stable kernel from 2.6.30.y onwards. Cc: Signed-off-by: NeilBrown Reported-by: "Hawrylewicz Czarnowski, Przemyslaw" --- drivers/md/md.c | 8 ++++++-- drivers/md/md.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index a3019121dc57..540347c538f9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -288,10 +288,12 @@ static int md_make_request(struct request_queue *q, struct bio *bio) int rv; int cpu; - if (mddev == NULL || mddev->pers == NULL) { + if (mddev == NULL || mddev->pers == NULL + || !mddev->ready) { bio_io_error(bio); return 0; } + smp_rmb(); /* Ensure implications of 'active' are visible */ rcu_read_lock(); if (mddev->suspended) { DEFINE_WAIT(__wait); @@ -4564,7 +4566,8 @@ int md_run(mddev_t *mddev) mddev->safemode_timer.data = (unsigned long) mddev; mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ mddev->in_sync = 1; - + smp_wmb(); + mddev->ready = 1; list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0) { char nm[20]; @@ -4725,6 +4728,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes); void md_stop(mddev_t *mddev) { + mddev->ready = 0; mddev->pers->stop(mddev); if (mddev->pers->sync_request && mddev->to_remove == NULL) mddev->to_remove = &md_redundancy_group; diff --git a/drivers/md/md.h b/drivers/md/md.h index d05bab55df4e..229675a604f7 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -148,7 +148,8 @@ struct mddev_s * are happening, so run/ * takeover/stop are not safe */ - + int ready; /* See when safe to pass + * IO requests down */ struct gendisk *gendisk; struct kobject kobj; -- cgit v1.2.3 From 43c73ca43b3e03bb228ff9350b6b44d0e560f262 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md/raid5: use sysfs_notify_dirent_safe to avoid NULL pointer With the module parameter 'start_dirty_degraded' set, raid5_spare_active() previously called sysfs_notify_dirent() with a NULL argument (rdev->sysfs_state) when a rebuild finished. Signed-off-by: Jonathan Brassow Signed-off-by: Mike Snitzer --- drivers/md/raid5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 316fbe79389a..9212c077095c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5338,7 +5338,7 @@ static int raid5_spare_active(mddev_t *mddev) && !test_bit(Faulty, &tmp->rdev->flags) && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { count++; - sysfs_notify_dirent(tmp->rdev->sysfs_state); + sysfs_notify_dirent_safe(tmp->rdev->sysfs_state); } } spin_lock_irqsave(&conf->device_lock, flags); -- cgit v1.2.3 From defad61a5b16352d3e22a04d4c930a5b5a7fd1f0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md: md_stop_writes requires mddev_lock. As md_stop_writes manipulates the sync_thread and calls md_update_sb, it need to be called with mddev_lock held. In all internal cases it is, but the symbol is exported for dm-raid to call and in that case the lock won't be help. Do make an exported version which takes the lock, and an internal version which does not. Signed-off-by: NeilBrown --- drivers/md/md.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 540347c538f9..f43ff2962b2b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4704,7 +4704,7 @@ static void md_clean(mddev_t *mddev) mddev->plug = NULL; } -void md_stop_writes(mddev_t *mddev) +static void __md_stop_writes(mddev_t *mddev) { if (mddev->sync_thread) { set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); @@ -4724,6 +4724,13 @@ void md_stop_writes(mddev_t *mddev) md_update_sb(mddev, 1); } } + +void md_stop_writes(mddev_t *mddev) +{ + mddev_lock(mddev); + __md_stop_writes(mddev); + mddev_unlock(mddev); +} EXPORT_SYMBOL_GPL(md_stop_writes); void md_stop(mddev_t *mddev) @@ -4748,7 +4755,7 @@ static int md_set_readonly(mddev_t *mddev, int is_open) goto out; } if (mddev->pers) { - md_stop_writes(mddev); + __md_stop_writes(mddev); err = -ENXIO; if (mddev->ro==1) @@ -4785,7 +4792,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) if (mddev->ro) set_disk_ro(disk, 0); - md_stop_writes(mddev); + __md_stop_writes(mddev); md_stop(mddev); mddev->queue->merge_bvec_fn = NULL; mddev->queue->unplug_fn = NULL; -- cgit v1.2.3 From 7ebc0be7fff4146e87b4078f054977b72998abd3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md: Be more careful about clearing flags bit in ->recovery Setting ->recovery to 0 is generally not a good idea as it could clear bits that shouldn't be cleared. In particular, MD_RECOVERY_FROZEN should only be cleared on explicit request from user-space. So when we need to clear things, just clear the bits that need clearing. As there are a few different places which reap a resync process - and some do an incomplte job - factor out the code for doing the from md_check_recovery and call that function instead of open coding part of it. Signed-off-by: NeilBrown Reported-by: Jonathan Brassow --- drivers/md/md.c | 86 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index f43ff2962b2b..a91dc593f3ca 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3746,6 +3746,8 @@ action_show(mddev_t *mddev, char *page) return sprintf(page, "%s\n", type); } +static void reap_sync_thread(mddev_t *mddev); + static ssize_t action_store(mddev_t *mddev, const char *page, size_t len) { @@ -3760,9 +3762,7 @@ action_store(mddev_t *mddev, const char *page, size_t len) if (cmd_match(page, "idle") || cmd_match(page, "frozen")) { if (mddev->sync_thread) { set_bit(MD_RECOVERY_INTR, &mddev->recovery); - md_unregister_thread(mddev->sync_thread); - mddev->sync_thread = NULL; - mddev->recovery = 0; + reap_sync_thread(mddev); } } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) @@ -4709,8 +4709,7 @@ static void __md_stop_writes(mddev_t *mddev) if (mddev->sync_thread) { set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); set_bit(MD_RECOVERY_INTR, &mddev->recovery); - md_unregister_thread(mddev->sync_thread); - mddev->sync_thread = NULL; + reap_sync_thread(mddev); } del_timer_sync(&mddev->safemode_timer); @@ -7044,6 +7043,45 @@ static int remove_and_add_spares(mddev_t *mddev) } return spares; } + +static void reap_sync_thread(mddev_t *mddev) +{ + mdk_rdev_t *rdev; + + /* resync has finished, collect result */ + md_unregister_thread(mddev->sync_thread); + mddev->sync_thread = NULL; + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { + /* success...*/ + /* activate any spares */ + if (mddev->pers->spare_active(mddev)) + sysfs_notify(&mddev->kobj, NULL, + "degraded"); + } + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + mddev->pers->finish_reshape) + mddev->pers->finish_reshape(mddev); + md_update_sb(mddev, 1); + + /* if array is no-longer degraded, then any saved_raid_disk + * information must be scrapped + */ + if (!mddev->degraded) + list_for_each_entry(rdev, &mddev->disks, same_set) + rdev->saved_raid_disk = -1; + + clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery); + clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); + clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); + clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); + clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); + /* flag recovery needed just to double check */ + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + sysfs_notify_dirent_safe(mddev->sysfs_action); + md_new_event(mddev); +} + /* * This routine is regularly called by all per-raid-array threads to * deal with generic issues like resync and super-block update. @@ -7068,9 +7106,6 @@ static int remove_and_add_spares(mddev_t *mddev) */ void md_check_recovery(mddev_t *mddev) { - mdk_rdev_t *rdev; - - if (mddev->bitmap) bitmap_daemon_work(mddev); @@ -7138,34 +7173,7 @@ void md_check_recovery(mddev_t *mddev) goto unlock; } if (mddev->sync_thread) { - /* resync has finished, collect result */ - md_unregister_thread(mddev->sync_thread); - mddev->sync_thread = NULL; - if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) && - !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { - /* success...*/ - /* activate any spares */ - if (mddev->pers->spare_active(mddev)) - sysfs_notify(&mddev->kobj, NULL, - "degraded"); - } - if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && - mddev->pers->finish_reshape) - mddev->pers->finish_reshape(mddev); - md_update_sb(mddev, 1); - - /* if array is no-longer degraded, then any saved_raid_disk - * information must be scrapped - */ - if (!mddev->degraded) - list_for_each_entry(rdev, &mddev->disks, same_set) - rdev->saved_raid_disk = -1; - - mddev->recovery = 0; - /* flag recovery needed just to double check */ - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - sysfs_notify_dirent_safe(mddev->sysfs_action); - md_new_event(mddev); + reap_sync_thread(mddev); goto unlock; } /* Set RUNNING before clearing NEEDED to avoid @@ -7223,7 +7231,11 @@ void md_check_recovery(mddev_t *mddev) " thread...\n", mdname(mddev)); /* leave the spares where they are, it shouldn't hurt */ - mddev->recovery = 0; + clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery); + clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); + clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); + clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); + clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); } else md_wakeup_thread(mddev->sync_thread); sysfs_notify_dirent_safe(mddev->sysfs_action); -- cgit v1.2.3 From 57b2caa394393f8870ed41bdcc38a7542593018f Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md-new-param-to-calc_dev_sboffset When we allow for separate devices for data and metadata in a later patch, we will need to be able to calculate the superblock offset based on more than the bdev. Signed-off-by: Jonathan Brassow --- drivers/md/md.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index a91dc593f3ca..0a0d7c2f2ff6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -705,9 +705,9 @@ static struct mdk_personality *find_pers(int level, char *clevel) } /* return the offset of the super block in 512byte sectors */ -static inline sector_t calc_dev_sboffset(struct block_device *bdev) +static inline sector_t calc_dev_sboffset(mdk_rdev_t *rdev) { - sector_t num_sectors = i_size_read(bdev->bd_inode) / 512; + sector_t num_sectors = i_size_read(rdev->bdev->bd_inode) / 512; return MD_NEW_SIZE_SECTORS(num_sectors); } @@ -991,7 +991,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version * * It also happens to be a multiple of 4Kb. */ - rdev->sb_start = calc_dev_sboffset(rdev->bdev); + rdev->sb_start = calc_dev_sboffset(rdev); ret = read_disk_sb(rdev, MD_SB_BYTES); if (ret) return ret; @@ -1332,7 +1332,7 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) return 0; /* component must fit device */ if (rdev->mddev->bitmap_info.offset) return 0; /* can't move bitmap */ - rdev->sb_start = calc_dev_sboffset(rdev->bdev); + rdev->sb_start = calc_dev_sboffset(rdev); if (!num_sectors || num_sectors > rdev->sb_start) num_sectors = rdev->sb_start; md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size, @@ -5249,7 +5249,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) printk(KERN_INFO "md: nonpersistent superblock ...\n"); rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512; } else - rdev->sb_start = calc_dev_sboffset(rdev->bdev); + rdev->sb_start = calc_dev_sboffset(rdev); rdev->sectors = rdev->sb_start; err = bind_rdev_to_array(rdev, mddev); @@ -5316,7 +5316,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) } if (mddev->persistent) - rdev->sb_start = calc_dev_sboffset(rdev->bdev); + rdev->sb_start = calc_dev_sboffset(rdev); else rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512; -- cgit v1.2.3 From ccebd4c4159462c96397ae9af9c667bb394d7b70 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Fri, 14 Jan 2011 09:14:33 +1100 Subject: md-new-param-to_sync_page_io Add new parameter to 'sync_page_io'. The new parameter allows us to distinguish between metadata and data operations. This becomes important later when we add the ability to use separate devices for data and metadata. Signed-off-by: Jonathan Brassow --- drivers/md/bitmap.c | 4 ++-- drivers/md/md.c | 9 ++++++--- drivers/md/md.h | 4 ++-- drivers/md/raid1.c | 28 ++++++++++++---------------- drivers/md/raid10.c | 12 ++++++------ 5 files changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 5a1ffe3527aa..1977765ff964 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -210,11 +210,11 @@ static struct page *read_sb_page(mddev_t *mddev, loff_t offset, || test_bit(Faulty, &rdev->flags)) continue; - target = rdev->sb_start + offset + index * (PAGE_SIZE/512); + target = offset + index * (PAGE_SIZE/512); if (sync_page_io(rdev, target, roundup(size, bdev_logical_block_size(rdev->bdev)), - page, READ)) { + page, READ, true)) { page->index = index; attach_page_buffers(page, NULL); /* so that free_buffer will * quietly no-op */ diff --git a/drivers/md/md.c b/drivers/md/md.c index 0a0d7c2f2ff6..0bc10cc4b961 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -795,7 +795,7 @@ static void bi_complete(struct bio *bio, int error) } int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, - struct page *page, int rw) + struct page *page, int rw, bool metadata_op) { struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev); struct completion event; @@ -804,7 +804,10 @@ int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, rw |= REQ_SYNC | REQ_UNPLUG; bio->bi_bdev = rdev->bdev; - bio->bi_sector = sector; + if (metadata_op) + bio->bi_sector = sector + rdev->sb_start; + else + bio->bi_sector = sector + rdev->data_offset; bio_add_page(bio, page, size, 0); init_completion(&event); bio->bi_private = &event; @@ -829,7 +832,7 @@ static int read_disk_sb(mdk_rdev_t * rdev, int size) return 0; - if (!sync_page_io(rdev, rdev->sb_start, size, rdev->sb_page, READ)) + if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, true)) goto fail; rdev->sb_loaded = 1; return 0; diff --git a/drivers/md/md.h b/drivers/md/md.h index 229675a604f7..7e4f358a26a6 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -498,8 +498,8 @@ extern void md_flush_request(mddev_t *mddev, struct bio *bio); extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, sector_t sector, int size, struct page *page); extern void md_super_wait(mddev_t *mddev); -extern int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, - struct page *page, int rw); +extern int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, + struct page *page, int rw, bool metadata_op); extern void md_do_sync(mddev_t *mddev); extern void md_new_event(mddev_t *mddev); extern int md_allow_write(mddev_t *mddev); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d50056ba596b..a23ffa397ba9 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1365,10 +1365,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) */ rdev = conf->mirrors[d].rdev; if (sync_page_io(rdev, - sect + rdev->data_offset, + sect, s<<9, bio->bi_io_vec[idx].bv_page, - READ)) { + READ, false)) { success = 1; break; } @@ -1391,10 +1391,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) rdev = conf->mirrors[d].rdev; atomic_add(s, &rdev->corrected_errors); if (sync_page_io(rdev, - sect + rdev->data_offset, + sect, s<<9, bio->bi_io_vec[idx].bv_page, - WRITE) == 0) + WRITE, false) == 0) md_error(mddev, rdev); } d = start; @@ -1406,10 +1406,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) continue; rdev = conf->mirrors[d].rdev; if (sync_page_io(rdev, - sect + rdev->data_offset, + sect, s<<9, bio->bi_io_vec[idx].bv_page, - READ) == 0) + READ, false) == 0) md_error(mddev, rdev); } } else { @@ -1489,10 +1489,8 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags) && - sync_page_io(rdev, - sect + rdev->data_offset, - s<<9, - conf->tmppage, READ)) + sync_page_io(rdev, sect, s<<9, + conf->tmppage, READ, false)) success = 1; else { d++; @@ -1515,9 +1513,8 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags)) { - if (sync_page_io(rdev, - sect + rdev->data_offset, - s<<9, conf->tmppage, WRITE) + if (sync_page_io(rdev, sect, s<<9, + conf->tmppage, WRITE, false) == 0) /* Well, this device is dead */ md_error(mddev, rdev); @@ -1532,9 +1529,8 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags)) { - if (sync_page_io(rdev, - sect + rdev->data_offset, - s<<9, conf->tmppage, READ) + if (sync_page_io(rdev, sect, s<<9, + conf->tmppage, READ, false) == 0) /* Well, this device is dead */ md_error(mddev, rdev); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 03825cbce2d4..69b659544390 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1560,9 +1560,9 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) rcu_read_unlock(); success = sync_page_io(rdev, r10_bio->devs[sl].addr + - sect + rdev->data_offset, + sect, s<<9, - conf->tmppage, READ); + conf->tmppage, READ, false); rdev_dec_pending(rdev, mddev); rcu_read_lock(); if (success) @@ -1599,8 +1599,8 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) atomic_add(s, &rdev->corrected_errors); if (sync_page_io(rdev, r10_bio->devs[sl].addr + - sect + rdev->data_offset, - s<<9, conf->tmppage, WRITE) + sect, + s<<9, conf->tmppage, WRITE, false) == 0) { /* Well, this device is dead */ printk(KERN_NOTICE @@ -1636,9 +1636,9 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) rcu_read_unlock(); if (sync_page_io(rdev, r10_bio->devs[sl].addr + - sect + rdev->data_offset, + sect, s<<9, conf->tmppage, - READ) == 0) { + READ, false) == 0) { /* Well, this device is dead */ printk(KERN_NOTICE "md/raid10:%s: unable to read back " -- cgit v1.2.3 From a6ff7e089c7fca813c956ccbed824087e89a3a49 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md: separate meta and data devs Allow the metadata to be on a separate device from the data. This doesn't mean the data and metadata will by on separate physical devices - it simply gives device-mapper and userspace tools more flexibility. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 6 +++++- drivers/md/md.c | 10 ++++++---- drivers/md/md.h | 6 ++++++ 3 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 1977765ff964..6cf587196b99 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -264,14 +264,18 @@ static mdk_rdev_t *next_active_rdev(mdk_rdev_t *rdev, mddev_t *mddev) static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) { mdk_rdev_t *rdev = NULL; + struct block_device *bdev; mddev_t *mddev = bitmap->mddev; while ((rdev = next_active_rdev(rdev, mddev)) != NULL) { int size = PAGE_SIZE; loff_t offset = mddev->bitmap_info.offset; + + bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; + if (page->index == bitmap->file_pages-1) size = roundup(bitmap->last_page_size, - bdev_logical_block_size(rdev->bdev)); + bdev_logical_block_size(bdev)); /* Just make sure we aren't corrupting data or * metadata */ diff --git a/drivers/md/md.c b/drivers/md/md.c index 0bc10cc4b961..b98a85fd10b6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -765,7 +765,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, */ struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev); - bio->bi_bdev = rdev->bdev; + bio->bi_bdev = rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev; bio->bi_sector = sector; bio_add_page(bio, page, size, 0); bio->bi_private = rdev; @@ -803,7 +803,8 @@ int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, rw |= REQ_SYNC | REQ_UNPLUG; - bio->bi_bdev = rdev->bdev; + bio->bi_bdev = (metadata_op && rdev->meta_bdev) ? + rdev->meta_bdev : rdev->bdev; if (metadata_op) bio->bi_sector = sector + rdev->sb_start; else @@ -4435,7 +4436,9 @@ int md_run(mddev_t *mddev) * We don't want the data to overlap the metadata, * Internal Bitmap issues have been handled elsewhere. */ - if (rdev->data_offset < rdev->sb_start) { + if (rdev->meta_bdev) { + /* Nothing to check */; + } else if (rdev->data_offset < rdev->sb_start) { if (mddev->dev_sectors && rdev->data_offset + mddev->dev_sectors > rdev->sb_start) { @@ -5532,7 +5535,6 @@ static int update_size(mddev_t *mddev, sector_t num_sectors) * sb_start or, if that is sync_thread) return -EBUSY; diff --git a/drivers/md/md.h b/drivers/md/md.h index 7e4f358a26a6..eec517ced31a 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -60,6 +60,12 @@ struct mdk_rdev_s mddev_t *mddev; /* RAID array if running */ int last_events; /* IO event timestamp */ + /* + * If meta_bdev is non-NULL, it means that a separate device is + * being used to store the metadata (superblock/bitmap) which + * would otherwise be contained on the same device as the data (bdev). + */ + struct block_device *meta_bdev; struct block_device *bdev; /* block device handle */ struct page *sb_page; -- cgit v1.2.3 From 75d3da43cb74d2e5fb87816dbfecb839cd97c7f4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md: Don't let implementation detail of curr_resync leak out through sysfs. mddev->curr_resync has artificial values of '1' and '2' which are used by the code which ensures only one resync is happening at a time on any given device. These values are internal and should never be exposed to user-space (except when translated appropriately as in the 'pending' status in /proc/mdstat). Unfortunately they are as ->curr_resync is assigned to ->curr_resync_completed and that value is directly visible through sysfs. So change the assignments to ->curr_resync_completed to get the same valued from elsewhere in a form that doesn't have the magic '1' or '2' values. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 2 +- drivers/md/md.c | 5 ++--- drivers/md/raid5.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 6cf587196b99..9a35320fb59f 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1546,7 +1546,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) wait_event(bitmap->mddev->recovery_wait, atomic_read(&bitmap->mddev->recovery_active) == 0); - bitmap->mddev->curr_resync_completed = bitmap->mddev->curr_resync; + bitmap->mddev->curr_resync_completed = sector; set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags); sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1); s = 0; diff --git a/drivers/md/md.c b/drivers/md/md.c index b98a85fd10b6..42b1d9ead7f2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6824,7 +6824,7 @@ void md_do_sync(mddev_t *mddev) desc, mdname(mddev)); mddev->curr_resync = j; } - mddev->curr_resync_completed = mddev->curr_resync; + mddev->curr_resync_completed = j; while (j < max_sectors) { sector_t sectors; @@ -6842,8 +6842,7 @@ void md_do_sync(mddev_t *mddev) md_unplug(mddev); wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active) == 0); - mddev->curr_resync_completed = - mddev->curr_resync; + mddev->curr_resync_completed = j; set_bit(MD_CHANGE_CLEAN, &mddev->flags); sysfs_notify(&mddev->kobj, NULL, "sync_completed"); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 9212c077095c..d223a6c0ccc4 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4236,7 +4236,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes)==0); mddev->reshape_position = conf->reshape_progress; - mddev->curr_resync_completed = mddev->curr_resync; + mddev->curr_resync_completed = sector_nr; conf->reshape_checkpoint = jiffies; set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); @@ -4337,7 +4337,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes) == 0); mddev->reshape_position = conf->reshape_progress; - mddev->curr_resync_completed = mddev->curr_resync + reshape_sectors; + mddev->curr_resync_completed = sector_nr; conf->reshape_checkpoint = jiffies; set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); -- cgit v1.2.3 From 23ddff3792f61193695114c68d6ebd57e974c4f8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md: allow suspend_lo and suspend_hi to decrease as well as increase. The sysfs attributes 'suspend_lo' and 'suspend_hi' describe a region to which read/writes are suspended so that the under lying data can be manipulated without user-space noticing. Currently the window they describe can only move forwards along the device. However this is an unnecessary restriction which will cause problems with planned developments. So relax this restriction and allow these endpoints to move arbitrarily. Signed-off-by: NeilBrown --- drivers/md/md.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 42b1d9ead7f2..dd64ad30a0fe 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4016,19 +4016,24 @@ suspend_lo_store(mddev_t *mddev, const char *buf, size_t len) { char *e; unsigned long long new = simple_strtoull(buf, &e, 10); + unsigned long long old = mddev->suspend_lo; if (mddev->pers == NULL || mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; - if (new >= mddev->suspend_hi || - (new > mddev->suspend_lo && new < mddev->suspend_hi)) { - mddev->suspend_lo = new; + + mddev->suspend_lo = new; + if (new >= old) + /* Shrinking suspended region */ mddev->pers->quiesce(mddev, 2); - return len; - } else - return -EINVAL; + else { + /* Expanding suspended region - need to wait */ + mddev->pers->quiesce(mddev, 1); + mddev->pers->quiesce(mddev, 0); + } + return len; } static struct md_sysfs_entry md_suspend_lo = __ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store); @@ -4045,20 +4050,24 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len) { char *e; unsigned long long new = simple_strtoull(buf, &e, 10); + unsigned long long old = mddev->suspend_hi; if (mddev->pers == NULL || mddev->pers->quiesce == NULL) return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; - if ((new <= mddev->suspend_lo && mddev->suspend_lo >= mddev->suspend_hi) || - (new > mddev->suspend_lo && new > mddev->suspend_hi)) { - mddev->suspend_hi = new; + + mddev->suspend_hi = new; + if (new <= old) + /* Shrinking suspended region */ + mddev->pers->quiesce(mddev, 2); + else { + /* Expanding suspended region - need to wait */ mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 0); - return len; - } else - return -EINVAL; + } + return len; } static struct md_sysfs_entry md_suspend_hi = __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); -- cgit v1.2.3 From 13ae864bc86ff65547ffe7e966b6433a0d0edb8a Mon Sep 17 00:00:00 2001 From: Rémi Rérolle Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md: fix sync_completed reporting for very large drives (>2TB) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The values exported in the sync_completed file are unsigned long, which overflows with very large drives, resulting in wrong values reported. Since sync_completed uses sectors as unit, we'll start getting wrong values with components larger than 2TB. This patch simply replaces the use of unsigned long by unsigned long long. Signed-off-by: Rémi Rérolle Signed-off-by: NeilBrown --- drivers/md/md.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index dd64ad30a0fe..5e3714fecee9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3918,7 +3918,7 @@ static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed); static ssize_t sync_completed_show(mddev_t *mddev, char *page) { - unsigned long max_sectors, resync; + unsigned long long max_sectors, resync; if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) return sprintf(page, "none\n"); @@ -3929,7 +3929,7 @@ sync_completed_show(mddev_t *mddev, char *page) max_sectors = mddev->dev_sectors; resync = mddev->curr_resync_completed; - return sprintf(page, "%lu / %lu\n", resync, max_sectors); + return sprintf(page, "%llu / %llu\n", resync, max_sectors); } static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed); -- cgit v1.2.3 From 1a940fcee31ec6c18c2f24dbdad31d54e4c35048 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md/raid5: handle manually-added spares in start_reshape. It is possible to manually add spares to specific slots before starting a reshape. raid5_start_reshape should recognised this possibility and include it in the accounting. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index d223a6c0ccc4..5044babfcda0 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5527,8 +5527,8 @@ static int raid5_start_reshape(mddev_t *mddev) return -ENOSPC; list_for_each_entry(rdev, &mddev->disks, same_set) - if (rdev->raid_disk < 0 && - !test_bit(Faulty, &rdev->flags)) + if ((rdev->raid_disk < 0 || rdev->raid_disk >= conf->raid_disks) + && !test_bit(Faulty, &rdev->flags)) spares++; if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded) @@ -5588,6 +5588,11 @@ static int raid5_start_reshape(mddev_t *mddev) /* Failure here is OK */; } else break; + } else if (rdev->raid_disk >= conf->previous_raid_disks + && !test_bit(Faulty, &rdev->flags)) { + /* This is a spare that was manually added */ + set_bit(In_sync, &rdev->flags); + added_devices++; } /* When a reshape changes the number of devices, ->degraded -- cgit v1.2.3 From ba1b41b6b4e30cb66ae2775faadea05cae3ce61c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md: range check slot number when manually adding a spare. When adding a spare to an active array, we should check the slot number, but allow it to be larger than raid_disks if a reshape is being prepared. Apply the same test when adding a device to an array-under-construction. It already had most of the test in place, but not quite all. Signed-off-by: NeilBrown --- drivers/md/md.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 5e3714fecee9..665851308818 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2479,6 +2479,10 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) if (rdev2->raid_disk == slot) return -EEXIST; + if (slot >= rdev->mddev->raid_disks && + slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks) + return -ENOSPC; + rdev->raid_disk = slot; if (test_bit(In_sync, &rdev->flags)) rdev->saved_raid_disk = slot; @@ -2496,7 +2500,8 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) /* failure here is OK */; /* don't wakeup anyone, leave that to userspace. */ } else { - if (slot >= rdev->mddev->raid_disks) + if (slot >= rdev->mddev->raid_disks && + slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks) return -ENOSPC; rdev->raid_disk = slot; /* assume it is working */ -- cgit v1.2.3 From bf2cb0dab8c97f00a71875d9b13dbac17a2f47ca Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Jan 2011 09:14:34 +1100 Subject: md: Fix removal of extra drives when converting RAID6 to RAID5 When a RAID6 is converted to a RAID5, the extra drive should be discarded. However it isn't due to a typo in a comparison. This bug was introduced in commit e93f68a1fc6 in 2.6.35-rc4 and is suitable for any -stable since than. As the extra drive is not removed, the 'degraded' counter is wrong and so the RAID5 will not respond correctly to a subsequent failure. Cc: stable@kernel.org Signed-off-by: NeilBrown --- drivers/md/md.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 665851308818..3194a80f3620 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3126,7 +3126,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len) char nm[20]; if (rdev->raid_disk < 0) continue; - if (rdev->new_raid_disk > mddev->raid_disks) + if (rdev->new_raid_disk >= mddev->raid_disks) rdev->new_raid_disk = -1; if (rdev->new_raid_disk == rdev->raid_disk) continue; -- cgit v1.2.3 From 5dfbd1d734ef5415bc47b034df7433ba21e40e7b Mon Sep 17 00:00:00 2001 From: Claudio Scordino Date: Thu, 13 Jan 2011 15:45:39 -0800 Subject: atmel_serial: fix RTS high after initialization in RS485 mode When working in RS485 mode, the atmel_serial driver keeps RTS high after the initialization of the serial port. It goes low only after the first character has been sent. [akpm@linux-foundation.org: simplify code] Signed-off-by: Claudio Scordino Signed-off-by: Arkadiusz Bubala Tested-by: Arkadiusz Bubala Cc: Nicolas Ferre Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/atmel_serial.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 3892666b5fbd..2a1d52fb4936 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -1732,6 +1732,11 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, port); + if (port->rs485.flags & SER_RS485_ENABLED) { + UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL); + UART_PUT_CR(&port->uart, ATMEL_US_RTSEN); + } + return 0; err_add_port: -- cgit v1.2.3 From 05b258e99725112c4febeab4fad23ea2c8908a3a Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 13 Jan 2011 15:47:14 -0800 Subject: thp: transparent hugepage sysfs meminfo Add hugepage statistics to per-node sysfs meminfo Reviewed-by: Rik van Riel Signed-off-by: David Rientjes Signed-off-by: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/node.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/node.c b/drivers/base/node.c index ce012a9c6201..36b43052001d 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -117,12 +117,21 @@ static ssize_t node_read_meminfo(struct sys_device * dev, "Node %d WritebackTmp: %8lu kB\n" "Node %d Slab: %8lu kB\n" "Node %d SReclaimable: %8lu kB\n" - "Node %d SUnreclaim: %8lu kB\n", + "Node %d SUnreclaim: %8lu kB\n" +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + "Node %d AnonHugePages: %8lu kB\n" +#endif + , nid, K(node_page_state(nid, NR_FILE_DIRTY)), nid, K(node_page_state(nid, NR_WRITEBACK)), nid, K(node_page_state(nid, NR_FILE_PAGES)), nid, K(node_page_state(nid, NR_FILE_MAPPED)), - nid, K(node_page_state(nid, NR_ANON_PAGES)), + nid, K(node_page_state(nid, NR_ANON_PAGES) +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + + node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * + HPAGE_PMD_NR +#endif + ), nid, K(node_page_state(nid, NR_SHMEM)), nid, node_page_state(nid, NR_KERNEL_STACK) * THREAD_SIZE / 1024, @@ -133,7 +142,13 @@ static ssize_t node_read_meminfo(struct sys_device * dev, nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) + node_page_state(nid, NR_SLAB_UNRECLAIMABLE)), nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)), - nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))); + nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)) +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + , nid, + K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * + HPAGE_PMD_NR) +#endif + ); n += hugetlb_report_node_meminfo(nid, buf + n); return n; } -- cgit v1.2.3 From c289ef41431144a538b5fb5f94fc83c81b3020e2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 16 Nov 2010 14:33:52 -0600 Subject: mmc: sdhci-of: fix build on non-powerpc platforms Explicitly include err.h, of_address.h and of_irq.h. Make use of machine_is() conditional on PPC. Signed-off-by: Rob Herring Signed-off-by: Grant Likely --- drivers/mmc/host/sdhci-of-core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index fa19d849a920..dd84124f4209 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c @@ -13,6 +13,7 @@ * your option) any later version. */ +#include #include #include #include @@ -20,8 +21,12 @@ #include #include #include +#include +#include #include +#ifdef CONFIG_PPC #include +#endif #include "sdhci-of.h" #include "sdhci.h" @@ -112,7 +117,11 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np) return true; /* Old device trees don't have the wp-inverted property. */ +#ifdef CONFIG_PPC return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds); +#else + return false; +#endif } static int __devinit sdhci_of_probe(struct platform_device *ofdev, -- cgit v1.2.3 From 5f35765d836befebdfabf745fdbf2e070c887fac Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Wed, 12 Jan 2011 15:00:23 +0900 Subject: spi: Enable SPI driver for S5P6440 and S5P6450 This patch enables the existing S3C64XX series SPI driver for S5P64X0 and removed dependency on EXPERIMENTAL because we don't need it now. v3: Changed dependency of S3C64XX_DMA v2: Removed dependency on EXPERIMENTAL Signed-off-by: Abhilash Kesavan Signed-off-by: Sangbeom Kim Acked-by: Jassi Brar Signed-off-by: Kukjin Kim Signed-off-by: Grant Likely --- drivers/spi/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 879b2a974d64..13bfa9d48082 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -310,8 +310,8 @@ config SPI_S3C24XX_GPIO config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" - depends on ARCH_S3C64XX && EXPERIMENTAL - select S3C64XX_DMA + depends on (ARCH_S3C64XX || ARCH_S5P64X0) + select S3C64XX_DMA if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. -- cgit v1.2.3 From 1591192d3a17adeebd03be0ce5888b88bddfaf89 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 14 Jan 2011 09:46:38 +0000 Subject: drm/i915: Disable GPU semaphores on SandyBridge mobile Hopefully, this is a temporary measure whilst the root cause is understood. At the moment, we experience a hard hang whilst looping urbanterror that has been identified as a result of the use of semaphores, but so far only on SNB mobile. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32752 Tested-by: mengmeng.meng@intel.com Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8db88e34ef7b..dcfdf4151b6d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -772,7 +772,8 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, if (from == NULL || to == from) return 0; - if (INTEL_INFO(obj->base.dev)->gen < 6) + /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */ + if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev)) return i915_gem_object_wait_rendering(obj, true); idx = intel_ring_sync_index(from, to); -- cgit v1.2.3 From e0084aa9e0ce157a5f53d9d39657a00d24dc6a66 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 30 Oct 2010 14:08:32 -0700 Subject: mfd: Update WARN uses Remove KERN_. Signed-off-by: Joe Perches Signed-off-by: Samuel Ortiz --- drivers/mfd/ezx-pcap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index c2b698d69a93..4f6742753c41 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -199,8 +199,7 @@ static void pcap_isr_work(struct work_struct *work) if (service & 1) { struct irq_desc *desc = irq_to_desc(irq); - if (WARN(!desc, KERN_WARNING - "Invalid PCAP IRQ %d\n", irq)) + if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq)) break; if (desc->status & IRQ_DISABLED) @@ -282,7 +281,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap) mutex_lock(&pcap->adc_mutex); req = pcap->adc_queue[pcap->adc_head]; - if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) { + if (WARN(!req, "adc irq without pending request\n")) { mutex_unlock(&pcap->adc_mutex); return IRQ_HANDLED; } -- cgit v1.2.3 From f77401d4da8180211b5fb5b7903ec8d8b22762ab Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 10 Nov 2010 15:47:51 +0800 Subject: mfd: Include instead of As warned by checkpatch.pl, use #include instead of Signed-off-by: Axel Lin Acked-by: Ben Dooks Signed-off-by: Samuel Ortiz --- drivers/mfd/sm501.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index bc9275c12133..c24bed769fe7 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -26,7 +26,7 @@ #include #include -#include +#include struct sm501_device { struct list_head list; -- cgit v1.2.3 From 77b22897da093e80c40f03e8d83bf23e756b9fba Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 10 Nov 2010 15:49:41 +0800 Subject: mfd: Include instead of As warned by checkpatch.pl, use #include instead of . Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/tps65010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 90187fe33e04..93d5fdf020c7 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -34,7 +34,7 @@ #include -#include +#include /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From e1b88eb0e08335d2f6c00b35b67b4ffc78fd46d6 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 11 Nov 2010 16:47:50 +0100 Subject: mfd: Don't open-code mc13xxx_unlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Samuel Ortiz --- drivers/mfd/mc13xxx-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index a2ac2ed6d64c..b9fcaf0004da 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -749,7 +749,7 @@ static int mc13xxx_probe(struct spi_device *spi) if (ret) { err_mask: err_revision: - mutex_unlock(&mc13xxx->lock); + mc13xxx_unlock(mc13xxx); dev_set_drvdata(&spi->dev, NULL); kfree(mc13xxx); return ret; -- cgit v1.2.3 From f71e1afdd588ec60fd799b1e5a6f0b2e6cf9605e Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 26 Nov 2010 11:52:35 +0100 Subject: mfd: Add cs5535-mfd driver for AMD Geode's CS5535/CS5536 support Add an MFD driver to handle the ISA device on CS5535 and CS5536 southbridges. This ISA bridge is actually multiple devices: GPIOs, MFGPTs, etc. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 8 +++ drivers/mfd/Makefile | 1 + drivers/mfd/cs5535-mfd.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 drivers/mfd/cs5535-mfd.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index da9d2971102e..b5e3e09f5637 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -537,6 +537,14 @@ config AB3550_CORE LEDs, vibrator, system power and temperature, power management and ALSA sound. +config MFD_CS5535 + tristate "Support for CS5535 and CS5536 southbridge core functions" + select MFD_CORE + depends on PCI + ---help--- + This is the core driver for CS5535/CS5536 MFD functions. This is + necessary for using the board's GPIO and MFGPT functionality. + config MFD_TIMBERDALE tristate "Support for the Timberdale FPGA" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 848e7eac75aa..5f35de9386e3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -82,3 +82,4 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o +obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c new file mode 100644 index 000000000000..b141ca7c777c --- /dev/null +++ b/drivers/mfd/cs5535-mfd.c @@ -0,0 +1,151 @@ +/* + * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges + * + * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is + * used for accessing GPIOs, MFGPTs, ACPI, etc. Each subdevice has + * an IO range that's specified in a single BAR. The BAR order is + * hardcoded in the CS553x specifications. + * + * Copyright (c) 2010 Andres Salomon + * + * 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. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#define DRV_NAME "cs5535-mfd" + +enum cs5535_mfd_bars { + SMB_BAR = 0, + GPIO_BAR = 1, + MFGPT_BAR = 2, + PMS_BAR = 4, + ACPI_BAR = 5, + NR_BARS, +}; + +static __devinitdata struct resource cs5535_mfd_resources[NR_BARS]; + +static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { + { + .id = SMB_BAR, + .name = "cs5535-smb", + .num_resources = 1, + .resources = &cs5535_mfd_resources[SMB_BAR], + }, + { + .id = GPIO_BAR, + .name = "cs5535-gpio", + .num_resources = 1, + .resources = &cs5535_mfd_resources[GPIO_BAR], + }, + { + .id = MFGPT_BAR, + .name = "cs5535-mfgpt", + .num_resources = 1, + .resources = &cs5535_mfd_resources[MFGPT_BAR], + }, + { + .id = PMS_BAR, + .name = "cs5535-pms", + .num_resources = 1, + .resources = &cs5535_mfd_resources[PMS_BAR], + }, + { + .id = ACPI_BAR, + .name = "cs5535-acpi", + .num_resources = 1, + .resources = &cs5535_mfd_resources[ACPI_BAR], + }, +}; + +static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err, i; + + err = pci_enable_device(pdev); + if (err) + return err; + + /* fill in IO range for each cell; subdrivers handle the region */ + for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) { + int bar = cs5535_mfd_cells[i].id; + struct resource *r = &cs5535_mfd_resources[bar]; + + r->flags = IORESOURCE_IO; + r->start = pci_resource_start(pdev, bar); + r->end = pci_resource_end(pdev, bar); + + /* id is used for temporarily storing BAR; unset it now */ + cs5535_mfd_cells[i].id = 0; + } + + err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells, + ARRAY_SIZE(cs5535_mfd_cells), NULL, 0); + if (err) { + dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); + goto err_disable; + } + + dev_info(&pdev->dev, "%d devices registered.\n", + ARRAY_SIZE(cs5535_mfd_cells)); + + return 0; + +err_disable: + pci_disable_device(pdev); + return err; +} + +static void __devexit cs5535_mfd_remove(struct pci_dev *pdev) +{ + mfd_remove_devices(&pdev->dev); + pci_disable_device(pdev); +} + +static struct pci_device_id cs5535_mfd_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl); + +static struct pci_driver cs5535_mfd_drv = { + .name = DRV_NAME, + .id_table = cs5535_mfd_pci_tbl, + .probe = cs5535_mfd_probe, + .remove = __devexit_p(cs5535_mfd_remove), +}; + +static int __init cs5535_mfd_init(void) +{ + return pci_register_driver(&cs5535_mfd_drv); +} + +static void __exit cs5535_mfd_exit(void) +{ + pci_unregister_driver(&cs5535_mfd_drv); +} + +module_init(cs5535_mfd_init); +module_exit(cs5535_mfd_exit); + +MODULE_AUTHOR("Andres Salomon "); +MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3f3d4310bdb083b9331239e1a1bb09e19f763115 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 12 Nov 2010 13:37:56 -0800 Subject: mfd: Use printf extension %pR for struct resource Using %pR standardizes the struct resource output. Signed-off-by: Joe Perches Signed-off-by: Samuel Ortiz --- drivers/mfd/sm501.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index c24bed769fe7..5de3a760ea1e 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -745,11 +745,8 @@ static int sm501_register_device(struct sm501_devdata *sm, int ret; for (ptr = 0; ptr < pdev->num_resources; ptr++) { - printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n", - pdev->name, ptr, - pdev->resource[ptr].flags, - (unsigned long long)pdev->resource[ptr].start, - (unsigned long long)pdev->resource[ptr].end); + printk(KERN_DEBUG "%s[%d] %pR\n", + pdev->name, ptr, &pdev->resource[ptr]); } ret = platform_device_register(pdev); -- cgit v1.2.3 From 798e6e321f807c46d81be1572118e031577ea9ab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 24 Nov 2010 18:01:40 +0000 Subject: mfd: Simplify WM832x subdevice instantiation All the current WM832x devices have the same set of subdevices so can just use multiple case statements with a single body. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 76cadcf3b1fe..d1b2d534b991 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1610,17 +1610,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) break; case WM8320: - ret = mfd_add_devices(wm831x->dev, -1, - wm8320_devs, ARRAY_SIZE(wm8320_devs), - NULL, 0); - break; - case WM8321: - ret = mfd_add_devices(wm831x->dev, -1, - wm8320_devs, ARRAY_SIZE(wm8320_devs), - NULL, 0); - break; - case WM8325: ret = mfd_add_devices(wm831x->dev, -1, wm8320_devs, ARRAY_SIZE(wm8320_devs), -- cgit v1.2.3 From 412dc11d3fd01f96fdf4a8cbfbc5584a17dab7c8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 24 Nov 2010 18:01:41 +0000 Subject: mfd: Add WM8326 support The WM8326 is a high performance variant of the WM832x series with no software visible differences. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 7 +++++++ drivers/mfd/wm831x-i2c.c | 1 + drivers/mfd/wm831x-spi.c | 18 ++++++++++++++++++ include/linux/mfd/wm831x/core.h | 1 + 4 files changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index d1b2d534b991..3fe9a58fe6c7 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1541,6 +1541,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev); break; + case WM8326: + parent = WM8326; + wm831x->num_gpio = 12; + dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev); + break; + default: dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret); ret = -EINVAL; @@ -1612,6 +1618,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8320: case WM8321: case WM8325: + case WM8326: ret = mfd_add_devices(wm831x->dev, -1, wm8320_devs, ARRAY_SIZE(wm8320_devs), NULL, wm831x->irq_base); diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index 156b19859e81..38be5201c783 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -108,6 +108,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = { { "wm8320", WM8320 }, { "wm8321", WM8321 }, { "wm8325", WM8325 }, + { "wm8326", WM8326 }, { } }; MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 2789b151b0f9..0a8f772be88c 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -81,6 +81,8 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) type = WM8321; else if (strcmp(spi->modalias, "wm8325") == 0) type = WM8325; + else if (strcmp(spi->modalias, "wm8326") == 0) + type = WM8326; else { dev_err(&spi->dev, "Unknown device type\n"); return -EINVAL; @@ -184,6 +186,17 @@ static struct spi_driver wm8325_spi_driver = { .suspend = wm831x_spi_suspend, }; +static struct spi_driver wm8326_spi_driver = { + .driver = { + .name = "wm8326", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm831x_spi_probe, + .remove = __devexit_p(wm831x_spi_remove), + .suspend = wm831x_spi_suspend, +}; + static int __init wm831x_spi_init(void) { int ret; @@ -212,12 +225,17 @@ static int __init wm831x_spi_init(void) if (ret != 0) pr_err("Failed to register WM8325 SPI driver: %d\n", ret); + ret = spi_register_driver(&wm8326_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8326 SPI driver: %d\n", ret); + return 0; } subsys_initcall(wm831x_spi_init); static void __exit wm831x_spi_exit(void) { + spi_unregister_driver(&wm8326_spi_driver); spi_unregister_driver(&wm8325_spi_driver); spi_unregister_driver(&wm8321_spi_driver); spi_unregister_driver(&wm8320_spi_driver); diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index a1239c48b41a..903280d21866 100644 --- a/include/linux/mfd/wm831x/core.h +++ b/include/linux/mfd/wm831x/core.h @@ -245,6 +245,7 @@ enum wm831x_parent { WM8320 = 0x8320, WM8321 = 0x8321, WM8325 = 0x8325, + WM8326 = 0x8326, }; struct wm831x { -- cgit v1.2.3 From ba81cd393348b504ecc80d5fc363857f49410d5e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 24 Nov 2010 18:01:42 +0000 Subject: mfd: Convert WM831x to new irq_ interrupt methods Kernel 2.6.37 adds new interrupt methods which take a struct irq_data rather than an irq number. Convert over to these as they will become mandatory in future. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 294183b6260b..eae52726bf3e 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -345,16 +345,16 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, return &wm831x_irqs[irq - wm831x->irq_base]; } -static void wm831x_irq_lock(unsigned int irq) +static void wm831x_irq_lock(struct irq_data *data) { - struct wm831x *wm831x = get_irq_chip_data(irq); + struct wm831x *wm831x = data->chip_data; mutex_lock(&wm831x->irq_lock); } -static void wm831x_irq_sync_unlock(unsigned int irq) +static void wm831x_irq_sync_unlock(struct irq_data *data) { - struct wm831x *wm831x = get_irq_chip_data(irq); + struct wm831x *wm831x = data->chip_data; int i; for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { @@ -371,28 +371,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq) mutex_unlock(&wm831x->irq_lock); } -static void wm831x_irq_unmask(unsigned int irq) +static void wm831x_irq_unmask(struct irq_data *data) { - struct wm831x *wm831x = get_irq_chip_data(irq); - struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); + struct wm831x *wm831x = data->chip_data; + struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, + data->irq); wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; } -static void wm831x_irq_mask(unsigned int irq) +static void wm831x_irq_mask(struct irq_data *data) { - struct wm831x *wm831x = get_irq_chip_data(irq); - struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); + struct wm831x *wm831x = data->chip_data; + struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, + data->irq); wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; } -static int wm831x_irq_set_type(unsigned int irq, unsigned int type) +static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) { - struct wm831x *wm831x = get_irq_chip_data(irq); - int val; + struct wm831x *wm831x = data->chip_data; + int val, irq; - irq = irq - wm831x->irq_base; + irq = data->irq - wm831x->irq_base; if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { /* Ignore internal-only IRQs */ @@ -421,12 +423,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type) } static struct irq_chip wm831x_irq_chip = { - .name = "wm831x", - .bus_lock = wm831x_irq_lock, - .bus_sync_unlock = wm831x_irq_sync_unlock, - .mask = wm831x_irq_mask, - .unmask = wm831x_irq_unmask, - .set_type = wm831x_irq_set_type, + .name = "wm831x", + .irq_bus_lock = wm831x_irq_lock, + .irq_bus_sync_unlock = wm831x_irq_sync_unlock, + .irq_mask = wm831x_irq_mask, + .irq_unmask = wm831x_irq_unmask, + .irq_set_type = wm831x_irq_set_type, }; /* The processing of the primary interrupt occurs in a thread so that -- cgit v1.2.3 From fdcc475b968f4715ce7a214c061c97a95c77fd21 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 24 Nov 2010 18:01:43 +0000 Subject: mfd: Convert WM835x to new irq_ interrupt methods Kernel 2.6.37 adds new interrupt methods which take a struct irq_data rather than an irq number. Convert over to these as they will become mandatory in future. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-irq.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index f56c9adf9493..ba966ae88dc3 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) return IRQ_HANDLED; } -static void wm8350_irq_lock(unsigned int irq) +static void wm8350_irq_lock(struct irq_data *data) { - struct wm8350 *wm8350 = get_irq_chip_data(irq); + struct wm8350 *wm8350 = data->chip_data; mutex_lock(&wm8350->irq_lock); } -static void wm8350_irq_sync_unlock(unsigned int irq) +static void wm8350_irq_sync_unlock(struct irq_data *data) { - struct wm8350 *wm8350 = get_irq_chip_data(irq); + struct wm8350 *wm8350 = data->chip_data; int i; for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { @@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq) mutex_unlock(&wm8350->irq_lock); } -static void wm8350_irq_enable(unsigned int irq) +static void wm8350_irq_enable(struct irq_data *data) { - struct wm8350 *wm8350 = get_irq_chip_data(irq); - struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); + struct wm8350 *wm8350 = data->chip_data; + struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, + data->irq); wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask; } -static void wm8350_irq_disable(unsigned int irq) +static void wm8350_irq_disable(struct irq_data *data) { - struct wm8350 *wm8350 = get_irq_chip_data(irq); - struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); + struct wm8350 *wm8350 = data->chip_data; + struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, + data->irq); wm8350->irq_masks[irq_data->reg] |= irq_data->mask; } static struct irq_chip wm8350_irq_chip = { - .name = "wm8350", - .bus_lock = wm8350_irq_lock, - .bus_sync_unlock = wm8350_irq_sync_unlock, - .disable = wm8350_irq_disable, - .enable = wm8350_irq_enable, + .name = "wm8350", + .irq_bus_lock = wm8350_irq_lock, + .irq_bus_sync_unlock = wm8350_irq_sync_unlock, + .irq_disable = wm8350_irq_disable, + .irq_enable = wm8350_irq_enable, }; int wm8350_irq_init(struct wm8350 *wm8350, int irq, -- cgit v1.2.3 From baa3f63b88c9138bb923a29a3d5fddc204d1f5e6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 24 Nov 2010 18:01:44 +0000 Subject: mfd: Convert WM8994 to new irq_ interrupt methods Kernel 2.6.37 adds new interrupt methods which take a struct irq_data rather than an irq number. Convert over to these as they will become mandatory in future. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-irq.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 8400eb1ee5db..62598840ad04 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994, return &wm8994_irqs[irq - wm8994->irq_base]; } -static void wm8994_irq_lock(unsigned int irq) +static void wm8994_irq_lock(struct irq_data *data) { - struct wm8994 *wm8994 = get_irq_chip_data(irq); + struct wm8994 *wm8994 = data->chip_data; mutex_lock(&wm8994->irq_lock); } -static void wm8994_irq_sync_unlock(unsigned int irq) +static void wm8994_irq_sync_unlock(struct irq_data *data) { - struct wm8994 *wm8994 = get_irq_chip_data(irq); + struct wm8994 *wm8994 = data->chip_data; int i; for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { @@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq) mutex_unlock(&wm8994->irq_lock); } -static void wm8994_irq_unmask(unsigned int irq) +static void wm8994_irq_unmask(struct irq_data *data) { - struct wm8994 *wm8994 = get_irq_chip_data(irq); - struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq); + struct wm8994 *wm8994 = data->chip_data; + struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, + data->irq); wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; } -static void wm8994_irq_mask(unsigned int irq) +static void wm8994_irq_mask(struct irq_data *data) { - struct wm8994 *wm8994 = get_irq_chip_data(irq); - struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq); + struct wm8994 *wm8994 = data->chip_data; + struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, + data->irq); wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; } static struct irq_chip wm8994_irq_chip = { - .name = "wm8994", - .bus_lock = wm8994_irq_lock, - .bus_sync_unlock = wm8994_irq_sync_unlock, - .mask = wm8994_irq_mask, - .unmask = wm8994_irq_unmask, + .name = "wm8994", + .irq_bus_lock = wm8994_irq_lock, + .irq_bus_sync_unlock = wm8994_irq_sync_unlock, + .irq_mask = wm8994_irq_mask, + .irq_unmask = wm8994_irq_unmask, }; /* The processing of the primary interrupt occurs in a thread so that -- cgit v1.2.3 From d7b9f3220fd97522559316cdd72778f42ac4de04 Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Fri, 26 Nov 2010 13:06:39 +0100 Subject: mfd: Fix ab8500-debug indentation errors Replace spaces with proper tabs. Signed-off-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-debugfs.c | 1016 +++++++++++++++++++++--------------------- 1 file changed, 508 insertions(+), 508 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 8d1e05a39815..dfdc76e0b96e 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -24,9 +24,9 @@ static u32 debug_address; * @perm: access permissions for the range */ struct ab8500_reg_range { - u8 first; - u8 last; - u8 perm; + u8 first; + u8 last; + u8 perm; }; /** @@ -36,9 +36,9 @@ struct ab8500_reg_range { * @range: the list of register ranges */ struct ab8500_i2c_ranges { - u8 num_ranges; - u8 bankid; - const struct ab8500_reg_range *range; + u8 num_ranges; + u8 bankid; + const struct ab8500_reg_range *range; }; #define AB8500_NAME_STRING "ab8500" @@ -47,521 +47,521 @@ struct ab8500_i2c_ranges { #define AB8500_REV_REG 0x80 static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { - [0x0] = { - .num_ranges = 0, - .range = 0, - }, - [AB8500_SYS_CTRL1_BLOCK] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x02, - }, - { - .first = 0x42, - .last = 0x42, - }, - { - .first = 0x80, - .last = 0x81, - }, - }, - }, - [AB8500_SYS_CTRL2_BLOCK] = { - .num_ranges = 4, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0D, - }, - { - .first = 0x0F, - .last = 0x17, - }, - { - .first = 0x30, - .last = 0x30, - }, - { - .first = 0x32, - .last = 0x33, - }, - }, - }, - [AB8500_REGU_CTRL1] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x03, - .last = 0x10, - }, - { - .first = 0x80, - .last = 0x84, - }, - }, - }, - [AB8500_REGU_CTRL2] = { - .num_ranges = 5, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x15, - }, - { - .first = 0x17, - .last = 0x19, - }, - { - .first = 0x1B, - .last = 0x1D, - }, - { - .first = 0x1F, - .last = 0x22, - }, - { - .first = 0x40, - .last = 0x44, - }, - /* 0x80-0x8B is SIM registers and should - * not be accessed from here */ - }, - }, - [AB8500_USB] = { - .num_ranges = 2, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x83, - }, - { - .first = 0x87, - .last = 0x8A, - }, - }, - }, - [AB8500_TVOUT] = { - .num_ranges = 9, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x12, - }, - { - .first = 0x15, - .last = 0x17, - }, - { - .first = 0x19, - .last = 0x21, - }, - { - .first = 0x27, - .last = 0x2C, - }, - { - .first = 0x41, - .last = 0x41, - }, - { - .first = 0x45, - .last = 0x5B, - }, - { - .first = 0x5D, - .last = 0x5D, - }, - { - .first = 0x69, - .last = 0x69, - }, - { - .first = 0x80, - .last = 0x81, - }, - }, - }, - [AB8500_DBI] = { - .num_ranges = 0, - .range = 0, - }, - [AB8500_ECI_AV_ACC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x82, - }, - }, - }, - [0x9] = { - .num_ranges = 0, - .range = 0, - }, - [AB8500_GPADC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x08, - }, - }, - }, - [AB8500_CHARGER] = { - .num_ranges = 8, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x03, - }, - { - .first = 0x05, - .last = 0x05, - }, - { - .first = 0x40, - .last = 0x40, - }, - { - .first = 0x42, - .last = 0x42, - }, - { - .first = 0x44, - .last = 0x44, - }, - { - .first = 0x50, - .last = 0x55, - }, - { - .first = 0x80, - .last = 0x82, - }, - { - .first = 0xC0, - .last = 0xC2, - }, - }, - }, - [AB8500_GAS_GAUGE] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x07, - .last = 0x0A, - }, - { - .first = 0x10, - .last = 0x14, - }, - }, - }, - [AB8500_AUDIO] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x6F, - }, - }, - }, - [AB8500_INTERRUPT] = { - .num_ranges = 0, - .range = 0, - }, - [AB8500_RTC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0F, - }, - }, - }, - [AB8500_MISC] = { - .num_ranges = 8, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x05, - }, - { - .first = 0x10, - .last = 0x15, - }, - { - .first = 0x20, - .last = 0x25, - }, - { - .first = 0x30, - .last = 0x35, - }, - { - .first = 0x40, - .last = 0x45, - }, - { - .first = 0x50, - .last = 0x50, - }, - { - .first = 0x60, - .last = 0x67, - }, - { - .first = 0x80, - .last = 0x80, - }, - }, - }, - [0x11] = { - .num_ranges = 0, - .range = 0, - }, - [0x12] = { - .num_ranges = 0, - .range = 0, - }, - [0x13] = { - .num_ranges = 0, - .range = 0, - }, - [0x14] = { - .num_ranges = 0, - .range = 0, - }, - [AB8500_OTP_EMUL] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x01, - .last = 0x0F, - }, - }, - }, + [0x0] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_SYS_CTRL1_BLOCK] = { + .num_ranges = 3, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x02, + }, + { + .first = 0x42, + .last = 0x42, + }, + { + .first = 0x80, + .last = 0x81, + }, + }, + }, + [AB8500_SYS_CTRL2_BLOCK] = { + .num_ranges = 4, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x0D, + }, + { + .first = 0x0F, + .last = 0x17, + }, + { + .first = 0x30, + .last = 0x30, + }, + { + .first = 0x32, + .last = 0x33, + }, + }, + }, + [AB8500_REGU_CTRL1] = { + .num_ranges = 3, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x00, + }, + { + .first = 0x03, + .last = 0x10, + }, + { + .first = 0x80, + .last = 0x84, + }, + }, + }, + [AB8500_REGU_CTRL2] = { + .num_ranges = 5, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x15, + }, + { + .first = 0x17, + .last = 0x19, + }, + { + .first = 0x1B, + .last = 0x1D, + }, + { + .first = 0x1F, + .last = 0x22, + }, + { + .first = 0x40, + .last = 0x44, + }, + /* 0x80-0x8B is SIM registers and should + * not be accessed from here */ + }, + }, + [AB8500_USB] = { + .num_ranges = 2, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x80, + .last = 0x83, + }, + { + .first = 0x87, + .last = 0x8A, + }, + }, + }, + [AB8500_TVOUT] = { + .num_ranges = 9, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x12, + }, + { + .first = 0x15, + .last = 0x17, + }, + { + .first = 0x19, + .last = 0x21, + }, + { + .first = 0x27, + .last = 0x2C, + }, + { + .first = 0x41, + .last = 0x41, + }, + { + .first = 0x45, + .last = 0x5B, + }, + { + .first = 0x5D, + .last = 0x5D, + }, + { + .first = 0x69, + .last = 0x69, + }, + { + .first = 0x80, + .last = 0x81, + }, + }, + }, + [AB8500_DBI] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_ECI_AV_ACC] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x80, + .last = 0x82, + }, + }, + }, + [0x9] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_GPADC] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x08, + }, + }, + }, + [AB8500_CHARGER] = { + .num_ranges = 8, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x03, + }, + { + .first = 0x05, + .last = 0x05, + }, + { + .first = 0x40, + .last = 0x40, + }, + { + .first = 0x42, + .last = 0x42, + }, + { + .first = 0x44, + .last = 0x44, + }, + { + .first = 0x50, + .last = 0x55, + }, + { + .first = 0x80, + .last = 0x82, + }, + { + .first = 0xC0, + .last = 0xC2, + }, + }, + }, + [AB8500_GAS_GAUGE] = { + .num_ranges = 3, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x00, + }, + { + .first = 0x07, + .last = 0x0A, + }, + { + .first = 0x10, + .last = 0x14, + }, + }, + }, + [AB8500_AUDIO] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x6F, + }, + }, + }, + [AB8500_INTERRUPT] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_RTC] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x0F, + }, + }, + }, + [AB8500_MISC] = { + .num_ranges = 8, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x05, + }, + { + .first = 0x10, + .last = 0x15, + }, + { + .first = 0x20, + .last = 0x25, + }, + { + .first = 0x30, + .last = 0x35, + }, + { + .first = 0x40, + .last = 0x45, + }, + { + .first = 0x50, + .last = 0x50, + }, + { + .first = 0x60, + .last = 0x67, + }, + { + .first = 0x80, + .last = 0x80, + }, + }, + }, + [0x11] = { + .num_ranges = 0, + .range = 0, + }, + [0x12] = { + .num_ranges = 0, + .range = 0, + }, + [0x13] = { + .num_ranges = 0, + .range = 0, + }, + [0x14] = { + .num_ranges = 0, + .range = 0, + }, + [AB8500_OTP_EMUL] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x01, + .last = 0x0F, + }, + }, + }, }; static int ab8500_registers_print(struct seq_file *s, void *p) { - struct device *dev = s->private; - unsigned int i; - u32 bank = debug_bank; - - seq_printf(s, AB8500_NAME_STRING " register values:\n"); - - seq_printf(s, " bank %u:\n", bank); - for (i = 0; i < debug_ranges[bank].num_ranges; i++) { - u32 reg; - - for (reg = debug_ranges[bank].range[i].first; - reg <= debug_ranges[bank].range[i].last; - reg++) { - u8 value; - int err; - - err = abx500_get_register_interruptible(dev, - (u8)bank, (u8)reg, &value); - if (err < 0) { - dev_err(dev, "ab->read fail %d\n", err); - return err; - } - - err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, - reg, value); - if (err < 0) { - dev_err(dev, "seq_printf overflow\n"); - /* Error is not returned here since - * the output is wanted in any case */ - return 0; - } - } - } - return 0; + struct device *dev = s->private; + unsigned int i; + u32 bank = debug_bank; + + seq_printf(s, AB8500_NAME_STRING " register values:\n"); + + seq_printf(s, " bank %u:\n", bank); + for (i = 0; i < debug_ranges[bank].num_ranges; i++) { + u32 reg; + + for (reg = debug_ranges[bank].range[i].first; + reg <= debug_ranges[bank].range[i].last; + reg++) { + u8 value; + int err; + + err = abx500_get_register_interruptible(dev, + (u8)bank, (u8)reg, &value); + if (err < 0) { + dev_err(dev, "ab->read fail %d\n", err); + return err; + } + + err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, + reg, value); + if (err < 0) { + dev_err(dev, "seq_printf overflow\n"); + /* Error is not returned here since + * the output is wanted in any case */ + return 0; + } + } + } + return 0; } static int ab8500_registers_open(struct inode *inode, struct file *file) { - return single_open(file, ab8500_registers_print, inode->i_private); + return single_open(file, ab8500_registers_print, inode->i_private); } static const struct file_operations ab8500_registers_fops = { - .open = ab8500_registers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, + .open = ab8500_registers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, }; static int ab8500_bank_print(struct seq_file *s, void *p) { - return seq_printf(s, "%d\n", debug_bank); + return seq_printf(s, "%d\n", debug_bank); } static int ab8500_bank_open(struct inode *inode, struct file *file) { - return single_open(file, ab8500_bank_print, inode->i_private); + return single_open(file, ab8500_bank_print, inode->i_private); } static ssize_t ab8500_bank_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) + const char __user *user_buf, + size_t count, loff_t *ppos) { - struct device *dev = ((struct seq_file *)(file->private_data))->private; - char buf[32]; - int buf_size; - unsigned long user_bank; - int err; - - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf) - 1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - err = strict_strtoul(buf, 0, &user_bank); - if (err) - return -EINVAL; - - if (user_bank >= AB8500_NUM_BANKS) { - dev_err(dev, "debugfs error input > number of banks\n"); - return -EINVAL; - } - - debug_bank = user_bank; - - return buf_size; + struct device *dev = ((struct seq_file *)(file->private_data))->private; + char buf[32]; + int buf_size; + unsigned long user_bank; + int err; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + err = strict_strtoul(buf, 0, &user_bank); + if (err) + return -EINVAL; + + if (user_bank >= AB8500_NUM_BANKS) { + dev_err(dev, "debugfs error input > number of banks\n"); + return -EINVAL; + } + + debug_bank = user_bank; + + return buf_size; } static int ab8500_address_print(struct seq_file *s, void *p) { - return seq_printf(s, "0x%02X\n", debug_address); + return seq_printf(s, "0x%02X\n", debug_address); } static int ab8500_address_open(struct inode *inode, struct file *file) { - return single_open(file, ab8500_address_print, inode->i_private); + return single_open(file, ab8500_address_print, inode->i_private); } static ssize_t ab8500_address_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) + const char __user *user_buf, + size_t count, loff_t *ppos) { - struct device *dev = ((struct seq_file *)(file->private_data))->private; - char buf[32]; - int buf_size; - unsigned long user_address; - int err; - - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf) - 1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - err = strict_strtoul(buf, 0, &user_address); - if (err) - return -EINVAL; - if (user_address > 0xff) { - dev_err(dev, "debugfs error input > 0xff\n"); - return -EINVAL; - } - debug_address = user_address; - return buf_size; + struct device *dev = ((struct seq_file *)(file->private_data))->private; + char buf[32]; + int buf_size; + unsigned long user_address; + int err; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + err = strict_strtoul(buf, 0, &user_address); + if (err) + return -EINVAL; + if (user_address > 0xff) { + dev_err(dev, "debugfs error input > 0xff\n"); + return -EINVAL; + } + debug_address = user_address; + return buf_size; } static int ab8500_val_print(struct seq_file *s, void *p) { - struct device *dev = s->private; - int ret; - u8 regvalue; - - ret = abx500_get_register_interruptible(dev, - (u8)debug_bank, (u8)debug_address, ®value); - if (ret < 0) { - dev_err(dev, "abx500_get_reg fail %d, %d\n", - ret, __LINE__); - return -EINVAL; - } - seq_printf(s, "0x%02X\n", regvalue); - - return 0; + struct device *dev = s->private; + int ret; + u8 regvalue; + + ret = abx500_get_register_interruptible(dev, + (u8)debug_bank, (u8)debug_address, ®value); + if (ret < 0) { + dev_err(dev, "abx500_get_reg fail %d, %d\n", + ret, __LINE__); + return -EINVAL; + } + seq_printf(s, "0x%02X\n", regvalue); + + return 0; } static int ab8500_val_open(struct inode *inode, struct file *file) { - return single_open(file, ab8500_val_print, inode->i_private); + return single_open(file, ab8500_val_print, inode->i_private); } static ssize_t ab8500_val_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) + const char __user *user_buf, + size_t count, loff_t *ppos) { - struct device *dev = ((struct seq_file *)(file->private_data))->private; - char buf[32]; - int buf_size; - unsigned long user_val; - int err; - - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - err = strict_strtoul(buf, 0, &user_val); - if (err) - return -EINVAL; - if (user_val > 0xff) { - dev_err(dev, "debugfs error input > 0xff\n"); - return -EINVAL; - } - err = abx500_set_register_interruptible(dev, - (u8)debug_bank, debug_address, (u8)user_val); - if (err < 0) { - printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__); - return -EINVAL; - } - - return buf_size; + struct device *dev = ((struct seq_file *)(file->private_data))->private; + char buf[32]; + int buf_size; + unsigned long user_val; + int err; + + /* Get userspace string and assure termination */ + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + err = strict_strtoul(buf, 0, &user_val); + if (err) + return -EINVAL; + if (user_val > 0xff) { + dev_err(dev, "debugfs error input > 0xff\n"); + return -EINVAL; + } + err = abx500_set_register_interruptible(dev, + (u8)debug_bank, debug_address, (u8)user_val); + if (err < 0) { + printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__); + return -EINVAL; + } + + return buf_size; } static const struct file_operations ab8500_bank_fops = { - .open = ab8500_bank_open, - .write = ab8500_bank_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, + .open = ab8500_bank_open, + .write = ab8500_bank_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, }; static const struct file_operations ab8500_address_fops = { - .open = ab8500_address_open, - .write = ab8500_address_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, + .open = ab8500_address_open, + .write = ab8500_address_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, }; static const struct file_operations ab8500_val_fops = { - .open = ab8500_val_open, - .write = ab8500_val_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, + .open = ab8500_val_open, + .write = ab8500_val_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, }; static struct dentry *ab8500_dir; @@ -572,77 +572,77 @@ static struct dentry *ab8500_val_file; static int __devinit ab8500_debug_probe(struct platform_device *plf) { - debug_bank = AB8500_MISC; - debug_address = AB8500_REV_REG & 0x00FF; + debug_bank = AB8500_MISC; + debug_address = AB8500_REV_REG & 0x00FF; - ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); - if (!ab8500_dir) - goto exit_no_debugfs; + ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); + if (!ab8500_dir) + goto exit_no_debugfs; - ab8500_reg_file = debugfs_create_file("all-bank-registers", - S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops); - if (!ab8500_reg_file) - goto exit_destroy_dir; + ab8500_reg_file = debugfs_create_file("all-bank-registers", + S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops); + if (!ab8500_reg_file) + goto exit_destroy_dir; - ab8500_bank_file = debugfs_create_file("register-bank", - (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); - if (!ab8500_bank_file) - goto exit_destroy_reg; + ab8500_bank_file = debugfs_create_file("register-bank", + (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); + if (!ab8500_bank_file) + goto exit_destroy_reg; - ab8500_address_file = debugfs_create_file("register-address", - (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, - &ab8500_address_fops); - if (!ab8500_address_file) - goto exit_destroy_bank; + ab8500_address_file = debugfs_create_file("register-address", + (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, + &ab8500_address_fops); + if (!ab8500_address_file) + goto exit_destroy_bank; - ab8500_val_file = debugfs_create_file("register-value", - (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); - if (!ab8500_val_file) - goto exit_destroy_address; + ab8500_val_file = debugfs_create_file("register-value", + (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); + if (!ab8500_val_file) + goto exit_destroy_address; - return 0; + return 0; exit_destroy_address: - debugfs_remove(ab8500_address_file); + debugfs_remove(ab8500_address_file); exit_destroy_bank: - debugfs_remove(ab8500_bank_file); + debugfs_remove(ab8500_bank_file); exit_destroy_reg: - debugfs_remove(ab8500_reg_file); + debugfs_remove(ab8500_reg_file); exit_destroy_dir: - debugfs_remove(ab8500_dir); + debugfs_remove(ab8500_dir); exit_no_debugfs: - dev_err(&plf->dev, "failed to create debugfs entries.\n"); - return -ENOMEM; + dev_err(&plf->dev, "failed to create debugfs entries.\n"); + return -ENOMEM; } static int __devexit ab8500_debug_remove(struct platform_device *plf) { - debugfs_remove(ab8500_val_file); - debugfs_remove(ab8500_address_file); - debugfs_remove(ab8500_bank_file); - debugfs_remove(ab8500_reg_file); - debugfs_remove(ab8500_dir); + debugfs_remove(ab8500_val_file); + debugfs_remove(ab8500_address_file); + debugfs_remove(ab8500_bank_file); + debugfs_remove(ab8500_reg_file); + debugfs_remove(ab8500_dir); - return 0; + return 0; } static struct platform_driver ab8500_debug_driver = { - .driver = { - .name = "ab8500-debug", - .owner = THIS_MODULE, - }, - .probe = ab8500_debug_probe, - .remove = __devexit_p(ab8500_debug_remove) + .driver = { + .name = "ab8500-debug", + .owner = THIS_MODULE, + }, + .probe = ab8500_debug_probe, + .remove = __devexit_p(ab8500_debug_remove) }; static int __init ab8500_debug_init(void) { - return platform_driver_register(&ab8500_debug_driver); + return platform_driver_register(&ab8500_debug_driver); } static void __exit ab8500_debug_exit(void) { - platform_driver_unregister(&ab8500_debug_driver); + platform_driver_unregister(&ab8500_debug_driver); } subsys_initcall(ab8500_debug_init); module_exit(ab8500_debug_exit); -- cgit v1.2.3 From 4c90aa94f6b3e33f57faaf19ef9819195dff61d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 26 Nov 2010 17:19:34 +0000 Subject: mfd: Provide pm_runtime_no_callbacks flag in cell data Allow MFD cells to have pm_runtime_no_callbacks() called on them during registration. This causes the runtime PM framework to ignore them, allowing use of runtime PM to suspend the device as a whole even if not all drivers for the MFD can usefully implement runtime PM. For example, RTCs are likely to run continuously regardless of the power state of the system. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 4 ++++ include/linux/mfd/core.h | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index ec99f681e773..d83ad0f141af 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include static int mfd_add_device(struct device *parent, int id, @@ -82,6 +83,9 @@ static int mfd_add_device(struct device *parent, int id, if (ret) goto fail_res; + if (cell->pm_runtime_no_callbacks) + pm_runtime_no_callbacks(&pdev->dev); + kfree(res); return 0; diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 5582ab3d3e48..835996e167e1 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -47,6 +47,12 @@ struct mfd_cell { /* don't check for resource conflicts */ bool ignore_resource_conflicts; + + /* + * Disable runtime PM callbacks for this subdevice - see + * pm_runtime_no_callbacks(). + */ + bool pm_runtime_no_callbacks; }; extern int mfd_add_devices(struct device *parent, int id, -- cgit v1.2.3 From d450f19eea0c3f64d60dc37655bae03b2455e5bb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 26 Nov 2010 17:19:35 +0000 Subject: mfd: Implement runtime PM for WM8994 core driver Allow the WM8994 to completely power off, including disabling the LDOs if they are software controlled, when it goes idle. The CODEC subdevice controls activity for the MFD as a whole. If the GPIOs need to be used while the device is active runtime PM should be disabled for the device by machine specific code. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 8d221ba5e38d..41233c7fa581 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -169,8 +170,16 @@ out: EXPORT_SYMBOL_GPL(wm8994_set_bits); static struct mfd_cell wm8994_regulator_devs[] = { - { .name = "wm8994-ldo", .id = 1 }, - { .name = "wm8994-ldo", .id = 2 }, + { + .name = "wm8994-ldo", + .id = 1, + .pm_runtime_no_callbacks = true, + }, + { + .name = "wm8994-ldo", + .id = 2, + .pm_runtime_no_callbacks = true, + }, }; static struct resource wm8994_codec_resources[] = { @@ -200,6 +209,7 @@ static struct mfd_cell wm8994_devs[] = { .name = "wm8994-gpio", .num_resources = ARRAY_SIZE(wm8994_gpio_resources), .resources = wm8994_gpio_resources, + .pm_runtime_no_callbacks = true, }, }; @@ -231,7 +241,7 @@ static const char *wm8958_main_supplies[] = { }; #ifdef CONFIG_PM -static int wm8994_device_suspend(struct device *dev) +static int wm8994_suspend(struct device *dev) { struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; @@ -261,7 +271,7 @@ static int wm8994_device_suspend(struct device *dev) return 0; } -static int wm8994_device_resume(struct device *dev) +static int wm8994_resume(struct device *dev) { struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; @@ -471,6 +481,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) goto err_irq; } + pm_runtime_enable(wm8994->dev); + pm_runtime_resume(wm8994->dev); + return 0; err_irq: @@ -490,6 +503,7 @@ err: static void wm8994_device_exit(struct wm8994 *wm8994) { + pm_runtime_disable(wm8994->dev); mfd_remove_devices(wm8994->dev); wm8994_irq_exit(wm8994); regulator_bulk_disable(wm8994->num_supplies, @@ -573,21 +587,6 @@ static int wm8994_i2c_remove(struct i2c_client *i2c) return 0; } -#ifdef CONFIG_PM -static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state) -{ - return wm8994_device_suspend(&i2c->dev); -} - -static int wm8994_i2c_resume(struct i2c_client *i2c) -{ - return wm8994_device_resume(&i2c->dev); -} -#else -#define wm8994_i2c_suspend NULL -#define wm8994_i2c_resume NULL -#endif - static const struct i2c_device_id wm8994_i2c_id[] = { { "wm8994", WM8994 }, { "wm8958", WM8958 }, @@ -595,15 +594,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); +UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL); + static struct i2c_driver wm8994_i2c_driver = { .driver = { - .name = "wm8994", - .owner = THIS_MODULE, + .name = "wm8994", + .owner = THIS_MODULE, + .pm = &wm8994_pm_ops, }, .probe = wm8994_i2c_probe, .remove = wm8994_i2c_remove, - .suspend = wm8994_i2c_suspend, - .resume = wm8994_i2c_resume, .id_table = wm8994_i2c_id, }; -- cgit v1.2.3 From 816b4580cef948c7d9ac9e3e63fb1b663012f057 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 30 Nov 2010 13:54:39 -0800 Subject: mfd: Fix cs5535 warning on x86-64 ARRAY_SIZE() returns size_t; use %zu instead of %d so that we don't get warnings on x86-64. Signed-off-by: Andres Salomon Acked-by: Randy Dunlap Signed-off-by: Samuel Ortiz --- drivers/mfd/cs5535-mfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index b141ca7c777c..59ca6f151e78 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -103,7 +103,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, goto err_disable; } - dev_info(&pdev->dev, "%d devices registered.\n", + dev_info(&pdev->dev, "%zu devices registered.\n", ARRAY_SIZE(cs5535_mfd_cells)); return 0; -- cgit v1.2.3 From df96669401cb8bac216f911f5bf92910357b29d3 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Sat, 23 Oct 2010 00:41:09 -0700 Subject: gpio: Convert cs5535 from pci device to platform device The cs5535-mfd driver now takes care of the PCI BAR handling; this simplifies the gpio driver a lot. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/gpio/cs5535-gpio.c | 93 ++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index 815d98b2c1ba..70967e23bc3d 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -11,14 +11,13 @@ #include #include #include -#include +#include #include #include #include #include #define DRV_NAME "cs5535-gpio" -#define GPIO_BAR 1 /* * Some GPIO pins @@ -47,7 +46,7 @@ static struct cs5535_gpio_chip { struct gpio_chip chip; resource_size_t base; - struct pci_dev *pdev; + struct platform_device *pdev; spinlock_t lock; } cs5535_gpio_chip; @@ -301,10 +300,10 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = { }, }; -static int __init cs5535_gpio_probe(struct pci_dev *pdev, - const struct pci_device_id *pci_id) +static int __devinit cs5535_gpio_probe(struct platform_device *pdev) { - int err; + struct resource *res; + int err = -EIO; ulong mask_orig = mask; /* There are two ways to get the GPIO base address; one is by @@ -314,25 +313,24 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev, * it turns out to be unreliable in the face of crappy BIOSes, we * can always go back to using MSRs.. */ - err = pci_enable_device_io(pdev); - if (err) { - dev_err(&pdev->dev, "can't enable device IO\n"); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); goto done; } - err = pci_request_region(pdev, GPIO_BAR, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR); + if (!request_region(res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "can't request region\n"); goto done; } /* set up the driver-specific struct */ - cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR); + cs5535_gpio_chip.base = res->start; cs5535_gpio_chip.pdev = pdev; spin_lock_init(&cs5535_gpio_chip.lock); - dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR, - (unsigned long long) cs5535_gpio_chip.base); + dev_info(&pdev->dev, "region 0x%x - 0x%x reserved\n", + res->start, res->end); /* mask out reserved pins */ mask &= 0x1F7FFFFF; @@ -350,78 +348,49 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev, if (err) goto release_region; - dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n"); + dev_info(&pdev->dev, "GPIO support successfully loaded.\n"); return 0; release_region: - pci_release_region(pdev, GPIO_BAR); + release_region(res->start, resource_size(res)); done: return err; } -static void __exit cs5535_gpio_remove(struct pci_dev *pdev) +static int __devexit cs5535_gpio_remove(struct platform_device *pdev) { + struct resource *r; int err; err = gpiochip_remove(&cs5535_gpio_chip.chip); if (err) { /* uhh? */ dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); + return err; } - pci_release_region(pdev, GPIO_BAR); -} - -static struct pci_device_id cs5535_gpio_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl); -/* - * We can't use the standard PCI driver registration stuff here, since - * that allows only one driver to bind to each PCI device (and we want - * multiple drivers to be able to bind to the device). Instead, manually - * scan for the PCI device, request a single region, and keep track of the - * devices that we're using. - */ - -static int __init cs5535_gpio_scan_pci(void) -{ - struct pci_dev *pdev; - int err = -ENODEV; - int i; - - for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) { - pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor, - cs5535_gpio_pci_tbl[i].device, NULL); - if (pdev) { - err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]); - if (err) - pci_dev_put(pdev); - - /* we only support a single CS5535/6 southbridge */ - break; - } - } - - return err; + r = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(r->start, resource_size(r)); + return 0; } -static void __exit cs5535_gpio_free_pci(void) -{ - cs5535_gpio_remove(cs5535_gpio_chip.pdev); - pci_dev_put(cs5535_gpio_chip.pdev); -} +static struct platform_driver cs5535_gpio_drv = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = cs5535_gpio_probe, + .remove = __devexit_p(cs5535_gpio_remove), +}; static int __init cs5535_gpio_init(void) { - return cs5535_gpio_scan_pci(); + return platform_driver_register(&cs5535_gpio_drv); } static void __exit cs5535_gpio_exit(void) { - cs5535_gpio_free_pci(); + platform_driver_unregister(&cs5535_gpio_drv); } module_init(cs5535_gpio_init); -- cgit v1.2.3 From 69bc6def395ebfdb137898179d7e559ba4c779d8 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Sat, 23 Oct 2010 00:41:14 -0700 Subject: misc: Convert cs5535-mfgpt from pci device to platform device The cs5535-mfd driver now takes care of the PCI BAR handling; this simplifies the mfgpt driver a bunch. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/misc/cs5535-mfgpt.c | 73 +++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 6f6218061b0d..499bd64e4d1d 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -16,12 +16,11 @@ #include #include #include -#include +#include #include #include #define DRV_NAME "cs5535-mfgpt" -#define MFGPT_BAR 2 static int mfgpt_reset_timers; module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644); @@ -37,7 +36,7 @@ static struct cs5535_mfgpt_chip { DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS); resource_size_t base; - struct pci_dev *pdev; + struct platform_device *pdev; spinlock_t lock; int initialized; } cs5535_mfgpt_chip; @@ -290,10 +289,10 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt) return timers; } -static int __init cs5535_mfgpt_probe(struct pci_dev *pdev, - const struct pci_device_id *pci_id) +static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) { - int err, t; + struct resource *res; + int err = -EIO, t; /* There are two ways to get the MFGPT base address; one is by * fetching it from MSR_LBAR_MFGPT, the other is by reading the @@ -302,29 +301,28 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev, * it turns out to be unreliable in the face of crappy BIOSes, we * can always go back to using MSRs.. */ - err = pci_enable_device_io(pdev); - if (err) { - dev_err(&pdev->dev, "can't enable device IO\n"); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); goto done; } - err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR); + if (!request_region(res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "can't request region\n"); goto done; } /* set up the driver-specific struct */ - cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR); + cs5535_mfgpt_chip.base = res->start; cs5535_mfgpt_chip.pdev = pdev; spin_lock_init(&cs5535_mfgpt_chip.lock); - dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR, - (unsigned long long) cs5535_mfgpt_chip.base); + dev_info(&pdev->dev, "region 0x%x - 0x%x reserved\n", res->start, + res->end); /* detect the available timers */ t = scan_timers(&cs5535_mfgpt_chip); - dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t); + dev_info(&pdev->dev, "%d MFGPT timers available\n", t); cs5535_mfgpt_chip.initialized = 1; return 0; @@ -332,47 +330,18 @@ done: return err; } -static struct pci_device_id cs5535_mfgpt_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, - { 0, }, +static struct platform_driver cs5535_mfgpt_drv = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = cs5535_mfgpt_probe, }; -MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl); -/* - * Just like with the cs5535-gpio driver, we can't use the standard PCI driver - * registration stuff. It only allows only one driver to bind to each PCI - * device, and we want the GPIO and MFGPT drivers to be able to share a PCI - * device. Instead, we manually scan for the PCI device, request a single - * region, and keep track of the devices that we're using. - */ - -static int __init cs5535_mfgpt_scan_pci(void) -{ - struct pci_dev *pdev; - int err = -ENODEV; - int i; - - for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) { - pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor, - cs5535_mfgpt_pci_tbl[i].device, NULL); - if (pdev) { - err = cs5535_mfgpt_probe(pdev, - &cs5535_mfgpt_pci_tbl[i]); - if (err) - pci_dev_put(pdev); - - /* we only support a single CS5535/6 southbridge */ - break; - } - } - - return err; -} static int __init cs5535_mfgpt_init(void) { - return cs5535_mfgpt_scan_pci(); + return platform_driver_register(&cs5535_mfgpt_drv); } module_init(cs5535_mfgpt_init); -- cgit v1.2.3 From ec9d0cf578007fa3f86fa34d77d9ccba82f03b29 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 1 Dec 2010 19:55:10 -0800 Subject: gpio/misc: Add MODULE_ALIAS entries for CS5535 functions This adds MODULE_ALIAS entries to the various cs5535 subdevice modules; this allows the modules to automatically be loaded when cs5535-mfd loads. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/gpio/cs5535-gpio.c | 1 + drivers/misc/cs5535-mfgpt.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index 70967e23bc3d..f9813ef48534 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -399,3 +399,4 @@ module_exit(cs5535_gpio_exit); MODULE_AUTHOR("Andres Salomon "); MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 499bd64e4d1d..26693060b29b 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -349,3 +349,4 @@ module_init(cs5535_mfgpt_init); MODULE_AUTHOR("Andres Salomon "); MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From 6bce7bf1a1f8a79a57ff69910c115e1d2ed8913d Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Thu, 2 Dec 2010 15:08:32 +0100 Subject: mfd: ab8500-core improved error handling in get_chip_id We check for dev before dereferencing it. Signed-off-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index d9640a623ff4..e91b5b759004 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -103,8 +103,12 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { static int ab8500_get_chip_id(struct device *dev) { - struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); - return (int)ab8500->chip_id; + struct ab8500 *ab8500; + + if (!dev) + return -EINVAL; + ab8500 = dev_get_drvdata(dev->parent); + return ab8500 ? (int)ab8500->chip_id : -EINVAL; } static int set_register_interruptible(struct ab8500 *ab8500, u8 bank, -- cgit v1.2.3 From cca69b67b3ba954ed8642583295b51933f902227 Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Thu, 2 Dec 2010 15:09:36 +0100 Subject: mfd: Export ab8500 chip id to sysfs This patch adds a file into sysfs for reading out chip id. It has been requested for modem silent reboot. Signed-off-by: Mattias Wallin Signed-off-by: Ludovic Barre Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index e91b5b759004..2bd4437cf331 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -436,6 +436,26 @@ static struct mfd_cell ab8500_devs[] = { }, }; +static ssize_t show_chip_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ab8500 *ab8500; + + ab8500 = dev_get_drvdata(dev); + return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); +} + +static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); + +static struct attribute *ab8500_sysfs_entries[] = { + &dev_attr_chip_id.attr, + NULL, +}; + +static struct attribute_group ab8500_attr_group = { + .attrs = ab8500_sysfs_entries, +}; + int __devinit ab8500_init(struct ab8500 *ab8500) { struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); @@ -510,6 +530,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500) if (ret) goto out_freeirq; + ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group); + if (ret) + dev_err(ab8500->dev, "error creating sysfs entries\n"); + return ret; out_freeirq: @@ -523,6 +547,7 @@ out_removeirq: int __devexit ab8500_exit(struct ab8500 *ab8500) { + sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); mfd_remove_devices(ab8500->dev); if (ab8500->irq_base) { free_irq(ab8500->irq, ab8500); -- cgit v1.2.3 From 4f079985b2caacfda5103dd85fb028a2848c84ab Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Thu, 2 Dec 2010 15:10:27 +0100 Subject: mfd: ab8500-core wake up from suspend This patch makes the system wake up from suspend when an ab8500 interrupt occur. This can for example be USB cable insert or an RTC alarm. Signed-off-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 2bd4437cf331..e464e94c4bc0 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -519,7 +519,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500) return ret; ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq, - IRQF_ONESHOT, "ab8500", ab8500); + IRQF_ONESHOT | IRQF_NO_SUSPEND, + "ab8500", ab8500); if (ret) goto out_removeirq; } -- cgit v1.2.3 From e098aded79f24e2024139e82f778ff9db6dc142a Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Thu, 2 Dec 2010 15:40:31 +0100 Subject: mfd: ab8500-core ioresources irq for subdrivers added This patch adds the ioresources used by subdrivers to retrieve their interrupt. Signed-off-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 206 +++++++++++++++++++++++++++++++++++++++++++-- include/linux/mfd/ab8500.h | 4 +- 2 files changed, 201 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index e464e94c4bc0..7f01a3a1d10f 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -397,12 +397,188 @@ static struct resource ab8500_poweronkey_db_resources[] = { }, }; +static struct resource ab8500_bm_resources[] = { + { + .name = "MAIN_EXT_CH_NOT_OK", + .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, + .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, + .flags = IORESOURCE_IRQ, + }, + { + .name = "BATT_OVV", + .start = AB8500_INT_BATT_OVV, + .end = AB8500_INT_BATT_OVV, + .flags = IORESOURCE_IRQ, + }, + { + .name = "MAIN_CH_UNPLUG_DET", + .start = AB8500_INT_MAIN_CH_UNPLUG_DET, + .end = AB8500_INT_MAIN_CH_UNPLUG_DET, + .flags = IORESOURCE_IRQ, + }, + { + .name = "MAIN_CHARGE_PLUG_DET", + .start = AB8500_INT_MAIN_CH_PLUG_DET, + .end = AB8500_INT_MAIN_CH_PLUG_DET, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_DET_F", + .start = AB8500_INT_VBUS_DET_F, + .end = AB8500_INT_VBUS_DET_F, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_DET_R", + .start = AB8500_INT_VBUS_DET_R, + .end = AB8500_INT_VBUS_DET_R, + .flags = IORESOURCE_IRQ, + }, + { + .name = "BAT_CTRL_INDB", + .start = AB8500_INT_BAT_CTRL_INDB, + .end = AB8500_INT_BAT_CTRL_INDB, + .flags = IORESOURCE_IRQ, + }, + { + .name = "CH_WD_EXP", + .start = AB8500_INT_CH_WD_EXP, + .end = AB8500_INT_CH_WD_EXP, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_OVV", + .start = AB8500_INT_VBUS_OVV, + .end = AB8500_INT_VBUS_OVV, + .flags = IORESOURCE_IRQ, + }, + { + .name = "NCONV_ACCU", + .start = AB8500_INT_CCN_CONV_ACC, + .end = AB8500_INT_CCN_CONV_ACC, + .flags = IORESOURCE_IRQ, + }, + { + .name = "LOW_BAT_F", + .start = AB8500_INT_LOW_BAT_F, + .end = AB8500_INT_LOW_BAT_F, + .flags = IORESOURCE_IRQ, + }, + { + .name = "LOW_BAT_R", + .start = AB8500_INT_LOW_BAT_R, + .end = AB8500_INT_LOW_BAT_R, + .flags = IORESOURCE_IRQ, + }, + { + .name = "BTEMP_LOW", + .start = AB8500_INT_BTEMP_LOW, + .end = AB8500_INT_BTEMP_LOW, + .flags = IORESOURCE_IRQ, + }, + { + .name = "BTEMP_HIGH", + .start = AB8500_INT_BTEMP_HIGH, + .end = AB8500_INT_BTEMP_HIGH, + .flags = IORESOURCE_IRQ, + }, + { + .name = "USB_CHARGER_NOT_OKR", + .start = AB8500_INT_USB_CHARGER_NOT_OK, + .end = AB8500_INT_USB_CHARGER_NOT_OK, + .flags = IORESOURCE_IRQ, + }, + { + .name = "USB_CHARGE_DET_DONE", + .start = AB8500_INT_USB_CHG_DET_DONE, + .end = AB8500_INT_USB_CHG_DET_DONE, + .flags = IORESOURCE_IRQ, + }, + { + .name = "USB_CH_TH_PROT_R", + .start = AB8500_INT_USB_CH_TH_PROT_R, + .end = AB8500_INT_USB_CH_TH_PROT_R, + .flags = IORESOURCE_IRQ, + }, + { + .name = "MAIN_CH_TH_PROT_R", + .start = AB8500_INT_MAIN_CH_TH_PROT_R, + .end = AB8500_INT_MAIN_CH_TH_PROT_R, + .flags = IORESOURCE_IRQ, + }, + { + .name = "USB_CHARGER_NOT_OKF", + .start = AB8500_INT_USB_CHARGER_NOT_OKF, + .end = AB8500_INT_USB_CHARGER_NOT_OKF, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource ab8500_debug_resources[] = { + { + .name = "IRQ_FIRST", + .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, + .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, + .flags = IORESOURCE_IRQ, + }, + { + .name = "IRQ_LAST", + .start = AB8500_INT_USB_CHARGER_NOT_OKF, + .end = AB8500_INT_USB_CHARGER_NOT_OKF, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource ab8500_usb_resources[] = { + { + .name = "ID_WAKEUP_R", + .start = AB8500_INT_ID_WAKEUP_R, + .end = AB8500_INT_ID_WAKEUP_R, + .flags = IORESOURCE_IRQ, + }, + { + .name = "ID_WAKEUP_F", + .start = AB8500_INT_ID_WAKEUP_F, + .end = AB8500_INT_ID_WAKEUP_F, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_DET_F", + .start = AB8500_INT_VBUS_DET_F, + .end = AB8500_INT_VBUS_DET_F, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_DET_R", + .start = AB8500_INT_VBUS_DET_R, + .end = AB8500_INT_VBUS_DET_R, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource ab8500_temp_resources[] = { + { + .name = "AB8500_TEMP_WARM", + .start = AB8500_INT_TEMP_WARM, + .end = AB8500_INT_TEMP_WARM, + .flags = IORESOURCE_IRQ, + }, +}; + static struct mfd_cell ab8500_devs[] = { #ifdef CONFIG_DEBUG_FS { .name = "ab8500-debug", + .num_resources = ARRAY_SIZE(ab8500_debug_resources), + .resources = ab8500_debug_resources, }, #endif + { + .name = "ab8500-sysctrl", + }, + { + .name = "ab8500-regulator", + }, { .name = "ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), @@ -413,6 +589,22 @@ static struct mfd_cell ab8500_devs[] = { .num_resources = ARRAY_SIZE(ab8500_rtc_resources), .resources = ab8500_rtc_resources, }, + { + .name = "ab8500-bm", + .num_resources = ARRAY_SIZE(ab8500_bm_resources), + .resources = ab8500_bm_resources, + }, + { .name = "ab8500-codec", }, + { + .name = "ab8500-usb", + .num_resources = ARRAY_SIZE(ab8500_usb_resources), + .resources = ab8500_usb_resources, + }, + { + .name = "ab8500-poweron-key", + .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), + .resources = ab8500_poweronkey_db_resources, + }, { .name = "ab8500-pwm", .id = 1, @@ -425,14 +617,14 @@ static struct mfd_cell ab8500_devs[] = { .name = "ab8500-pwm", .id = 3, }, - { .name = "ab8500-charger", }, - { .name = "ab8500-audio", }, - { .name = "ab8500-usb", }, - { .name = "ab8500-regulator", }, + { .name = "ab8500-leds", }, { - .name = "ab8500-poweron-key", - .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources), - .resources = ab8500_poweronkey_db_resources, + .name = "ab8500-denc", + }, + { + .name = "ab8500-temp", + .num_resources = ARRAY_SIZE(ab8500_temp_resources), + .resources = ab8500_temp_resources, }, }; diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index 85cf2c28fac6..1ad169655235 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h @@ -91,8 +91,8 @@ #define AB8500_INT_ID_DET_R4F 93 #define AB8500_INT_USB_CHG_DET_DONE 94 #define AB8500_INT_USB_CH_TH_PROT_F 96 -#define AB8500_INT_USB_CH_TH_PROP_R 97 -#define AB8500_INT_MAIN_CH_TH_PROP_F 98 +#define AB8500_INT_USB_CH_TH_PROT_R 97 +#define AB8500_INT_MAIN_CH_TH_PROT_F 98 #define AB8500_INT_MAIN_CH_TH_PROT_R 99 #define AB8500_INT_USB_CHARGER_NOT_OKF 103 -- cgit v1.2.3 From 5b9cecd68f3ef72ab9e586b0c2995a40a2f1e630 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 8 Dec 2010 10:42:04 +0800 Subject: mfd: Fix twl_probe section mismatch warning in mfd/twl-core.c Fix the following section mismatch warning when building omap2plus_defconfig: WARNING: vmlinux.o(.data+0x47d7c): Section mismatch in reference from the variable twl_driver to the function .init.text:twl_probe() Signed-off-by: Bryan Wu Signed-off-by: Paul Walmsley Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 12abd5b924b3..a35fa7dcbf53 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1003,7 +1003,7 @@ static int twl_remove(struct i2c_client *client) } /* NOTE: this driver only handles a single twl4030/tps659x0 chip */ -static int __init +static int __devinit twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { int status; -- cgit v1.2.3 From 4d1cdbf696501c0a942c5b71f3fab9434a4465c4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 9 Dec 2010 10:30:11 -0700 Subject: mfd: Remove tps6586x device ID check ... and convert it to a dev_info print at probe time. There are many variants of this chip with different values of VERSIONCRC. The set of values is large, and not useful to enumerate. All are SW compatible. The difference lies in default settings of the various power rails, and other similar differences. The driver, or clients of the driver, shouldn't be affected by this, since all rails should be programmed into the desired state in all cases for correct operation. Derived-from-code-by: Andrew Chew Signed-off-by: Stephen Warren Signed-off-by: Samuel Ortiz --- drivers/mfd/tps6586x.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index b4931ab34929..35757399add0 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -46,8 +46,6 @@ /* device id */ #define TPS6586X_VERSIONCRC 0xcd -#define TPS658621A_VERSIONCRC 0x15 -#define TPS658621C_VERSIONCRC 0x2c struct tps6586x_irq_data { u8 mask_reg; @@ -498,11 +496,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, return -EIO; } - if ((ret != TPS658621A_VERSIONCRC) && - (ret != TPS658621C_VERSIONCRC)) { - dev_err(&client->dev, "Unsupported chip ID: %x\n", ret); - return -ENODEV; - } + dev_info(&client->dev, "VERSIONCRC is %02x\n", ret); tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL); if (tps6586x == NULL) -- cgit v1.2.3 From 59f2ad2e0ee13bbb4cfb399e08df8c54b264dd39 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 12:59:35 +0000 Subject: mfd: Staticise unexported symbols in ASIC3 There's no use of either of these outside of the driver so they can be declared static. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 7de708d15d72..6b82eb0fa55c 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -57,7 +57,7 @@ struct asic3_clk { .rate = _rate, \ } -struct asic3_clk asic3_clk_init[] __initdata = { +static struct asic3_clk asic3_clk_init[] __initdata = { INIT_CDEX(SPI, 0), INIT_CDEX(OWM, 5000000), INIT_CDEX(PWM0, 0), @@ -102,7 +102,7 @@ static inline u32 asic3_read_register(struct asic3 *asic, (reg >> asic->bus_shift)); } -void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) +static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) { unsigned long flags; u32 val; -- cgit v1.2.3 From fe421425d78176f4a3509ce11b8d683cf1604e3a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 13:00:34 +0000 Subject: mfd: Correct ASIC3 IRQ_OWM resource setup We should specify both a start and an end for the IRQ range rather than initialise the start twice. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 6b82eb0fa55c..3c7dc5ebfe4d 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -635,7 +635,7 @@ static struct resource ds1wm_resources[] = { }, { .start = ASIC3_IRQ_OWM, - .start = ASIC3_IRQ_OWM, + .end = ASIC3_IRQ_OWM, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, }, }; -- cgit v1.2.3 From 87fff232cb76828b44312843d96854704f71ed19 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Dec 2010 14:06:47 +0000 Subject: mfd: Use NULL to initialise NULL pointers in ab8500-debugfs Partly for coding style reasons, but mostly because sparse warns on it. Signed-off-by: Mark Brown Acked-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-debugfs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index dfdc76e0b96e..3c1541ae7223 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -189,7 +189,7 @@ static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { }, [AB8500_DBI] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [AB8500_ECI_AV_ACC] = { .num_ranges = 1, @@ -202,7 +202,7 @@ static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { }, [0x9] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [AB8500_GPADC] = { .num_ranges = 1, @@ -278,7 +278,7 @@ static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { }, [AB8500_INTERRUPT] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [AB8500_RTC] = { .num_ranges = 1, @@ -328,19 +328,19 @@ static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { }, [0x11] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [0x12] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [0x13] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [0x14] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [AB8500_OTP_EMUL] = { .num_ranges = 1, -- cgit v1.2.3 From 8d2d3a3a329ebf20f733ac1499ebc565f497f051 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 16:44:49 +0000 Subject: mfd: Staticise internal functions in HTC I2CCPLD driver Most of these are GPIO operations, though a couple are just internal only functions. Signed-off-by: Mark Brown Acked-by: Cory Maccarrone Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-i2cpld.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 594c9a8e25e1..dd24355c9650 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -235,7 +235,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev) * and that work is scheduled in the set routine. The kernel can then run * the I2C functions, which will sleep, in process context. */ -void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) +static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) { struct i2c_client *client; struct htcpld_chip *chip_data; @@ -259,7 +259,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) schedule_work(&(chip_data->set_val_work)); } -void htcpld_chip_set_ni(struct work_struct *work) +static void htcpld_chip_set_ni(struct work_struct *work) { struct htcpld_chip *chip_data; struct i2c_client *client; @@ -269,7 +269,7 @@ void htcpld_chip_set_ni(struct work_struct *work) i2c_smbus_read_byte_data(client, chip_data->cache_out); } -int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) +static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) { struct htcpld_chip *chip_data; int val = 0; @@ -316,7 +316,7 @@ static int htcpld_direction_input(struct gpio_chip *chip, return (offset < chip->ngpio) ? 0 : -EINVAL; } -int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) +static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) { struct htcpld_chip *chip_data; @@ -328,7 +328,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) return -EINVAL; } -void htcpld_chip_reset(struct i2c_client *client) +static void htcpld_chip_reset(struct i2c_client *client) { struct htcpld_chip *chip_data = i2c_get_clientdata(client); if (!chip_data) -- cgit v1.2.3 From 49f89d9acb6cba6475923e42a3d13540a70a926e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 12:31:31 +0000 Subject: mfd: Convert 88PM860x driver to new irq_ APIs The interrupt controller APIs are being updated to pass a struct irq_data rather than the interrupt number. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 20895e7a99c9..793300c554b4 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -361,12 +361,6 @@ static struct pm860x_irq_data pm860x_irqs[] = { }, }; -static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip, - int irq) -{ - return &pm860x_irqs[irq - chip->irq_base]; -} - static irqreturn_t pm860x_irq(int irq, void *data) { struct pm860x_chip *chip = data; @@ -388,16 +382,16 @@ static irqreturn_t pm860x_irq(int irq, void *data) return IRQ_HANDLED; } -static void pm860x_irq_lock(unsigned int irq) +static void pm860x_irq_lock(struct irq_data *data) { - struct pm860x_chip *chip = get_irq_chip_data(irq); + struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); mutex_lock(&chip->irq_lock); } -static void pm860x_irq_sync_unlock(unsigned int irq) +static void pm860x_irq_sync_unlock(struct irq_data *data) { - struct pm860x_chip *chip = get_irq_chip_data(irq); + struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); struct pm860x_irq_data *irq_data; struct i2c_client *i2c; static unsigned char cached[3] = {0x0, 0x0, 0x0}; @@ -439,25 +433,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq) mutex_unlock(&chip->irq_lock); } -static void pm860x_irq_enable(unsigned int irq) +static void pm860x_irq_enable(struct irq_data *data) { - struct pm860x_chip *chip = get_irq_chip_data(irq); - pm860x_irqs[irq - chip->irq_base].enable - = pm860x_irqs[irq - chip->irq_base].offs; + struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); + pm860x_irqs[data->irq - chip->irq_base].enable + = pm860x_irqs[data->irq - chip->irq_base].offs; } -static void pm860x_irq_disable(unsigned int irq) +static void pm860x_irq_disable(struct irq_data *data) { - struct pm860x_chip *chip = get_irq_chip_data(irq); - pm860x_irqs[irq - chip->irq_base].enable = 0; + struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); + pm860x_irqs[data->irq - chip->irq_base].enable = 0; } static struct irq_chip pm860x_irq_chip = { .name = "88pm860x", - .bus_lock = pm860x_irq_lock, - .bus_sync_unlock = pm860x_irq_sync_unlock, - .enable = pm860x_irq_enable, - .disable = pm860x_irq_disable, + .irq_bus_lock = pm860x_irq_lock, + .irq_bus_sync_unlock = pm860x_irq_sync_unlock, + .irq_enable = pm860x_irq_enable, + .irq_disable = pm860x_irq_disable, }; static int __devinit device_gpadc_init(struct pm860x_chip *chip, -- cgit v1.2.3 From 0f76aaebe8015d6a850cb03622382bacb7860398 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 13:08:57 +0000 Subject: mfd: Convert ASIC3 to new irq_ APIs The interrupt controller APIs are being updated to pass a struct irq_data rather than the interrupt number. Signed-off-by: Mark Brown Acked-by: Ian Molton Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 56 ++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 3c7dc5ebfe4d..6a1f94042612 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -226,14 +226,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq) return (irq - asic->irq_base) & 0xf; } -static void asic3_mask_gpio_irq(unsigned int irq) +static void asic3_mask_gpio_irq(struct irq_data *data) { - struct asic3 *asic = get_irq_chip_data(irq); + struct asic3 *asic = irq_data_get_irq_chip_data(data); u32 val, bank, index; unsigned long flags; - bank = asic3_irq_to_bank(asic, irq); - index = asic3_irq_to_index(asic, irq); + bank = asic3_irq_to_bank(asic, data->irq); + index = asic3_irq_to_index(asic, data->irq); spin_lock_irqsave(&asic->lock, flags); val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); @@ -242,9 +242,9 @@ static void asic3_mask_gpio_irq(unsigned int irq) spin_unlock_irqrestore(&asic->lock, flags); } -static void asic3_mask_irq(unsigned int irq) +static void asic3_mask_irq(struct irq_data *data) { - struct asic3 *asic = get_irq_chip_data(irq); + struct asic3 *asic = irq_data_get_irq_chip_data(data); int regval; unsigned long flags; @@ -254,7 +254,7 @@ static void asic3_mask_irq(unsigned int irq) ASIC3_INTR_INT_MASK); regval &= ~(ASIC3_INTMASK_MASK0 << - (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); + (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); asic3_write_register(asic, ASIC3_INTR_BASE + @@ -263,14 +263,14 @@ static void asic3_mask_irq(unsigned int irq) spin_unlock_irqrestore(&asic->lock, flags); } -static void asic3_unmask_gpio_irq(unsigned int irq) +static void asic3_unmask_gpio_irq(struct irq_data *data) { - struct asic3 *asic = get_irq_chip_data(irq); + struct asic3 *asic = irq_data_get_irq_chip_data(data); u32 val, bank, index; unsigned long flags; - bank = asic3_irq_to_bank(asic, irq); - index = asic3_irq_to_index(asic, irq); + bank = asic3_irq_to_bank(asic, data->irq); + index = asic3_irq_to_index(asic, data->irq); spin_lock_irqsave(&asic->lock, flags); val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); @@ -279,9 +279,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq) spin_unlock_irqrestore(&asic->lock, flags); } -static void asic3_unmask_irq(unsigned int irq) +static void asic3_unmask_irq(struct irq_data *data) { - struct asic3 *asic = get_irq_chip_data(irq); + struct asic3 *asic = irq_data_get_irq_chip_data(data); int regval; unsigned long flags; @@ -291,7 +291,7 @@ static void asic3_unmask_irq(unsigned int irq) ASIC3_INTR_INT_MASK); regval |= (ASIC3_INTMASK_MASK0 << - (irq - (asic->irq_base + ASIC3_NUM_GPIOS))); + (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS))); asic3_write_register(asic, ASIC3_INTR_BASE + @@ -300,15 +300,15 @@ static void asic3_unmask_irq(unsigned int irq) spin_unlock_irqrestore(&asic->lock, flags); } -static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) +static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) { - struct asic3 *asic = get_irq_chip_data(irq); + struct asic3 *asic = irq_data_get_irq_chip_data(data); u32 bank, index; u16 trigger, level, edge, bit; unsigned long flags; - bank = asic3_irq_to_bank(asic, irq); - index = asic3_irq_to_index(asic, irq); + bank = asic3_irq_to_bank(asic, data->irq); + index = asic3_irq_to_index(asic, data->irq); bit = 1<lock, flags); @@ -318,7 +318,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) bank + ASIC3_GPIO_EDGE_TRIGGER); trigger = asic3_read_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE); - asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit; + asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit; if (type == IRQ_TYPE_EDGE_RISING) { trigger |= bit; @@ -328,11 +328,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) edge &= ~bit; } else if (type == IRQ_TYPE_EDGE_BOTH) { trigger |= bit; - if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base)) + if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base)) edge &= ~bit; else edge |= bit; - asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit; + asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit; } else if (type == IRQ_TYPE_LEVEL_LOW) { trigger &= ~bit; level &= ~bit; @@ -359,17 +359,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type) static struct irq_chip asic3_gpio_irq_chip = { .name = "ASIC3-GPIO", - .ack = asic3_mask_gpio_irq, - .mask = asic3_mask_gpio_irq, - .unmask = asic3_unmask_gpio_irq, - .set_type = asic3_gpio_irq_type, + .irq_ack = asic3_mask_gpio_irq, + .irq_mask = asic3_mask_gpio_irq, + .irq_unmask = asic3_unmask_gpio_irq, + .irq_set_type = asic3_gpio_irq_type, }; static struct irq_chip asic3_irq_chip = { .name = "ASIC3", - .ack = asic3_mask_irq, - .mask = asic3_mask_irq, - .unmask = asic3_unmask_irq, + .irq_ack = asic3_mask_irq, + .irq_mask = asic3_mask_irq, + .irq_unmask = asic3_unmask_irq, }; static int __init asic3_irq_probe(struct platform_device *pdev) -- cgit v1.2.3 From c91ad349d084f8c034ff60fb56d41a9667f71ae4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 13:14:12 +0000 Subject: mfd: Convert AB3500 to new irq_ APIs The genirq core is being updated to pass struct irq_data rather than irq numbers into chip drivers. As part of the update assignments to NULL for unused operations are removed, these are not needed and the genirq docs should be good enough. Signed-off-by: Mark Brown Acked-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3550-core.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 8a98739e6d9c..5fbca346b998 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work) } } -static void ab3550_mask(unsigned int irq) +static void ab3550_mask(struct irq_data *data) { unsigned long flags; struct ab3550 *ab; struct ab3550_platform_data *plf_data; + int irq; - ab = get_irq_chip_data(irq); + ab = irq_data_get_irq_chip_data(data); plf_data = ab->i2c_client[0]->dev.platform_data; - irq -= plf_data->irq.base; + irq = data->irq - plf_data->irq.base; spin_lock_irqsave(&ab->event_lock, flags); ab->event_mask[irq / 8] |= BIT(irq % 8); @@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq) schedule_work(&ab->mask_work); } -static void ab3550_unmask(unsigned int irq) +static void ab3550_unmask(struct irq_data *data) { unsigned long flags; struct ab3550 *ab; struct ab3550_platform_data *plf_data; + int irq; - ab = get_irq_chip_data(irq); + ab = irq_data_get_irq_chip_data(data); plf_data = ab->i2c_client[0]->dev.platform_data; - irq -= plf_data->irq.base; + irq = data->irq - plf_data->irq.base; spin_lock_irqsave(&ab->event_lock, flags); ab->event_mask[irq / 8] &= ~BIT(irq % 8); @@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq) schedule_work(&ab->mask_work); } -static void noop(unsigned int irq) +static void noop(struct irq_data *data) { } static struct irq_chip ab3550_irq_chip = { .name = "ab3550-core", /* Keep the same name as the request */ - .startup = NULL, /* defaults to enable */ - .shutdown = NULL, /* defaults to disable */ - .enable = NULL, /* defaults to unmask */ - .disable = ab3550_mask, /* No default to mask in chip.c */ - .ack = noop, - .mask = ab3550_mask, - .unmask = ab3550_unmask, - .end = NULL, + .irq_disable = ab3550_mask, /* No default to mask in chip.c */ + .irq_ack = noop, + .irq_mask = ab3550_mask, + .irq_unmask = ab3550_unmask, }; struct ab_family_id { -- cgit v1.2.3 From 9505a0a0ac6160480eaab8d592dce6161e67e05d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 13:16:08 +0000 Subject: mfd: Convert AB8500 to new irq_ methods The genirq core is being converted to supply struct irq_data to chips rather than the interrupt number. Signed-off-by: Mark Brown Acked-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 7f01a3a1d10f..86cc8874e6de 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -232,16 +232,16 @@ static struct abx500_ops ab8500_ops = { .startup_irq_enabled = NULL, }; -static void ab8500_irq_lock(unsigned int irq) +static void ab8500_irq_lock(struct irq_data *data) { - struct ab8500 *ab8500 = get_irq_chip_data(irq); + struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); mutex_lock(&ab8500->irq_lock); } -static void ab8500_irq_sync_unlock(unsigned int irq) +static void ab8500_irq_sync_unlock(struct irq_data *data) { - struct ab8500 *ab8500 = get_irq_chip_data(irq); + struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); int i; for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { @@ -261,20 +261,20 @@ static void ab8500_irq_sync_unlock(unsigned int irq) mutex_unlock(&ab8500->irq_lock); } -static void ab8500_irq_mask(unsigned int irq) +static void ab8500_irq_mask(struct irq_data *data) { - struct ab8500 *ab8500 = get_irq_chip_data(irq); - int offset = irq - ab8500->irq_base; + struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); + int offset = data->irq - ab8500->irq_base; int index = offset / 8; int mask = 1 << (offset % 8); ab8500->mask[index] |= mask; } -static void ab8500_irq_unmask(unsigned int irq) +static void ab8500_irq_unmask(struct irq_data *data) { - struct ab8500 *ab8500 = get_irq_chip_data(irq); - int offset = irq - ab8500->irq_base; + struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); + int offset = data->irq - ab8500->irq_base; int index = offset / 8; int mask = 1 << (offset % 8); @@ -283,10 +283,10 @@ static void ab8500_irq_unmask(unsigned int irq) static struct irq_chip ab8500_irq_chip = { .name = "ab8500", - .bus_lock = ab8500_irq_lock, - .bus_sync_unlock = ab8500_irq_sync_unlock, - .mask = ab8500_irq_mask, - .unmask = ab8500_irq_unmask, + .irq_bus_lock = ab8500_irq_lock, + .irq_bus_sync_unlock = ab8500_irq_sync_unlock, + .irq_mask = ab8500_irq_mask, + .irq_unmask = ab8500_irq_unmask, }; static irqreturn_t ab8500_irq(int irq, void *dev) -- cgit v1.2.3 From c232f22fc6aac1797d0ca9beddddf0fea4beb7f3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 13 Dec 2010 13:30:09 +0100 Subject: mfd: Convert ezx-pcap to new irq_ methods Signed-off-by: Lennert Buytenhek Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/ezx-pcap.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 4f6742753c41..9e2d8dd5f9e5 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -144,26 +144,26 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq) } EXPORT_SYMBOL_GPL(pcap_to_irq); -static void pcap_mask_irq(unsigned int irq) +static void pcap_mask_irq(struct irq_data *d) { - struct pcap_chip *pcap = get_irq_chip_data(irq); + struct pcap_chip *pcap = irq_data_get_irq_chip_data(d); - pcap->msr |= 1 << irq_to_pcap(pcap, irq); + pcap->msr |= 1 << irq_to_pcap(pcap, d->irq); queue_work(pcap->workqueue, &pcap->msr_work); } -static void pcap_unmask_irq(unsigned int irq) +static void pcap_unmask_irq(struct irq_data *d) { - struct pcap_chip *pcap = get_irq_chip_data(irq); + struct pcap_chip *pcap = irq_data_get_irq_chip_data(d); - pcap->msr &= ~(1 << irq_to_pcap(pcap, irq)); + pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq)); queue_work(pcap->workqueue, &pcap->msr_work); } static struct irq_chip pcap_irq_chip = { - .name = "pcap", - .mask = pcap_mask_irq, - .unmask = pcap_unmask_irq, + .name = "pcap", + .irq_mask = pcap_mask_irq, + .irq_unmask = pcap_unmask_irq, }; static void pcap_msr_work(struct work_struct *work) @@ -217,7 +217,7 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) { struct pcap_chip *pcap = get_irq_data(irq); - desc->chip->ack(irq); + desc->irq_data.chip->irq_ack(&desc->irq_data); queue_work(pcap->workqueue, &pcap->isr_work); return; } -- cgit v1.2.3 From 949b9decaed059f25ed9639d3dbfe839972cf01b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 16:43:59 +0000 Subject: mfd: Convert HTC EGPIO driver to irq_ API The genirq core is being converted to pass a struct irq_data to interrupt operations rather than an IRQ number. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-egpio.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index d3e74f8585e0..d00b6d1a69e5 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -70,31 +70,32 @@ static inline void ack_irqs(struct egpio_info *ei) ei->ack_write, ei->ack_register << ei->bus_shift); } -static void egpio_ack(unsigned int irq) +static void egpio_ack(struct irq_data *data) { } /* There does not appear to be a way to proactively mask interrupts * on the egpio chip itself. So, we simply ignore interrupts that * aren't desired. */ -static void egpio_mask(unsigned int irq) +static void egpio_mask(struct irq_data *data) { - struct egpio_info *ei = get_irq_chip_data(irq); - ei->irqs_enabled &= ~(1 << (irq - ei->irq_start)); - pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled); + struct egpio_info *ei = irq_data_get_irq_chip_data(data); + ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start)); + pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled); } -static void egpio_unmask(unsigned int irq) + +static void egpio_unmask(struct irq_data *data) { - struct egpio_info *ei = get_irq_chip_data(irq); - ei->irqs_enabled |= 1 << (irq - ei->irq_start); - pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled); + struct egpio_info *ei = irq_data_get_irq_chip_data(data); + ei->irqs_enabled |= 1 << (data->irq - ei->irq_start); + pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled); } static struct irq_chip egpio_muxed_chip = { - .name = "htc-egpio", - .ack = egpio_ack, - .mask = egpio_mask, - .unmask = egpio_unmask, + .name = "htc-egpio", + .irq_ack = egpio_ack, + .irq_mask = egpio_mask, + .irq_unmask = egpio_unmask, }; static void egpio_handler(unsigned int irq, struct irq_desc *desc) -- cgit v1.2.3 From e6a4c4a48a80ddfaa5abf59146e0beb5faa86fba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 16:44:11 +0000 Subject: mfd: Convert HTC I2C CPLD driver to irq_ API The genirq core is being converted to pass a struct irq_data to interrupt operations rather than an IRQ number. Signed-off-by: Mark Brown Acked-by: Cory Maccarrone Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-i2cpld.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index dd24355c9650..296ad1562f69 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -82,25 +82,25 @@ struct htcpld_data { /* There does not appear to be a way to proactively mask interrupts * on the htcpld chip itself. So, we simply ignore interrupts that * aren't desired. */ -static void htcpld_mask(unsigned int irq) +static void htcpld_mask(struct irq_data *data) { - struct htcpld_chip *chip = get_irq_chip_data(irq); - chip->irqs_enabled &= ~(1 << (irq - chip->irq_start)); - pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled); + struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); + chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start)); + pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled); } -static void htcpld_unmask(unsigned int irq) +static void htcpld_unmask(struct irq_data *data) { - struct htcpld_chip *chip = get_irq_chip_data(irq); - chip->irqs_enabled |= 1 << (irq - chip->irq_start); - pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled); + struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); + chip->irqs_enabled |= 1 << (data->irq - chip->irq_start); + pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled); } -static int htcpld_set_type(unsigned int irq, unsigned int flags) +static int htcpld_set_type(struct irq_data *data, unsigned int flags) { - struct irq_desc *d = irq_to_desc(irq); + struct irq_desc *d = irq_to_desc(data->irq); if (!d) { - pr_err("HTCPLD invalid IRQ: %d\n", irq); + pr_err("HTCPLD invalid IRQ: %d\n", data->irq); return -EINVAL; } @@ -118,10 +118,10 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags) } static struct irq_chip htcpld_muxed_chip = { - .name = "htcpld", - .mask = htcpld_mask, - .unmask = htcpld_unmask, - .set_type = htcpld_set_type, + .name = "htcpld", + .irq_mask = htcpld_mask, + .irq_unmask = htcpld_unmask, + .irq_set_type = htcpld_set_type, }; /* To properly dispatch IRQ events, we need to read from the -- cgit v1.2.3 From 5af3bde8b264e78565b6d1963ba86bbf6c6b10f6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 20:08:30 +0100 Subject: mfd: Convert jz4740-adc to new irq_ methods Convert the jz4740-adc driver to use the recently introduced IRQ API variants which are passed struct irq_data rather than an IRQ number. Signed-off-by: Mark Brown Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/jz4740-adc.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 9dd1b33f2275..0cc59795f600 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -84,31 +84,30 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq, spin_unlock_irqrestore(&adc->lock, flags); } -static void jz4740_adc_irq_mask(unsigned int irq) +static void jz4740_adc_irq_mask(struct irq_data *data) { - struct jz4740_adc *adc = get_irq_chip_data(irq); - jz4740_adc_irq_set_masked(adc, irq, true); + struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); + jz4740_adc_irq_set_masked(adc, data->irq, true); } -static void jz4740_adc_irq_unmask(unsigned int irq) +static void jz4740_adc_irq_unmask(struct irq_data *data) { - struct jz4740_adc *adc = get_irq_chip_data(irq); - jz4740_adc_irq_set_masked(adc, irq, false); + struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); + jz4740_adc_irq_set_masked(adc, data->irq, false); } -static void jz4740_adc_irq_ack(unsigned int irq) +static void jz4740_adc_irq_ack(struct irq_data *data) { - struct jz4740_adc *adc = get_irq_chip_data(irq); - - irq -= adc->irq_base; + struct jz4740_adc *adc = irq_data_get_irq_chip_data(data); + unsigned int irq = data->irq - adc->irq_base; writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS); } static struct irq_chip jz4740_adc_irq_chip = { .name = "jz4740-adc", - .mask = jz4740_adc_irq_mask, - .unmask = jz4740_adc_irq_unmask, - .ack = jz4740_adc_irq_ack, + .irq_mask = jz4740_adc_irq_mask, + .irq_unmask = jz4740_adc_irq_unmask, + .irq_ack = jz4740_adc_irq_ack, }; static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) -- cgit v1.2.3 From 98d9bc13cd19e544e8ea15b97f5cfef166cc9294 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 18:20:55 +0000 Subject: mfd: Convert max8925 to new irq_ API The genirq infrastructure is being converted to pass struct irq_data rather than an irq number to irq_chip operations, update max8925 to the new APIs. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 44695f5a1800..0e998dc4e7d8 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -407,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data) return IRQ_HANDLED; } -static void max8925_irq_lock(unsigned int irq) +static void max8925_irq_lock(struct irq_data *data) { - struct max8925_chip *chip = get_irq_chip_data(irq); + struct max8925_chip *chip = irq_data_get_irq_chip_data(data); mutex_lock(&chip->irq_lock); } -static void max8925_irq_sync_unlock(unsigned int irq) +static void max8925_irq_sync_unlock(struct irq_data *data) { - struct max8925_chip *chip = get_irq_chip_data(irq); + struct max8925_chip *chip = irq_data_get_irq_chip_data(data); struct max8925_irq_data *irq_data; static unsigned char cache_chg[2] = {0xff, 0xff}; static unsigned char cache_on[2] = {0xff, 0xff}; @@ -492,25 +492,25 @@ static void max8925_irq_sync_unlock(unsigned int irq) mutex_unlock(&chip->irq_lock); } -static void max8925_irq_enable(unsigned int irq) +static void max8925_irq_enable(struct irq_data *data) { - struct max8925_chip *chip = get_irq_chip_data(irq); - max8925_irqs[irq - chip->irq_base].enable - = max8925_irqs[irq - chip->irq_base].offs; + struct max8925_chip *chip = irq_data_get_irq_chip_data(data); + max8925_irqs[data->irq - chip->irq_base].enable + = max8925_irqs[data->irq - chip->irq_base].offs; } -static void max8925_irq_disable(unsigned int irq) +static void max8925_irq_disable(struct irq_data *data) { - struct max8925_chip *chip = get_irq_chip_data(irq); - max8925_irqs[irq - chip->irq_base].enable = 0; + struct max8925_chip *chip = irq_data_get_irq_chip_data(data); + max8925_irqs[data->irq - chip->irq_base].enable = 0; } static struct irq_chip max8925_irq_chip = { .name = "max8925", - .bus_lock = max8925_irq_lock, - .bus_sync_unlock = max8925_irq_sync_unlock, - .enable = max8925_irq_enable, - .disable = max8925_irq_disable, + .irq_bus_lock = max8925_irq_lock, + .irq_bus_sync_unlock = max8925_irq_sync_unlock, + .irq_enable = max8925_irq_enable, + .irq_disable = max8925_irq_disable, }; static int max8925_irq_init(struct max8925_chip *chip, int irq, -- cgit v1.2.3 From 2898577e160c7d60d2b11cb3b1c3b55d0e1468db Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 18:31:03 +0000 Subject: mfd: Convert MAX8998 driver to irq_ API The genirq core is being updated to pass struct irq_data to interrupt operations, update the MAX8998 driver to the new API. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/max8998-irq.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index 45bfe77b639b..c6b61fcc5808 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c @@ -102,16 +102,16 @@ irq_to_max8998_irq(struct max8998_dev *max8998, int irq) return &max8998_irqs[irq - max8998->irq_base]; } -static void max8998_irq_lock(unsigned int irq) +static void max8998_irq_lock(struct irq_data *data) { - struct max8998_dev *max8998 = get_irq_chip_data(irq); + struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); mutex_lock(&max8998->irqlock); } -static void max8998_irq_sync_unlock(unsigned int irq) +static void max8998_irq_sync_unlock(struct irq_data *data) { - struct max8998_dev *max8998 = get_irq_chip_data(irq); + struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); int i; for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) { @@ -129,28 +129,30 @@ static void max8998_irq_sync_unlock(unsigned int irq) mutex_unlock(&max8998->irqlock); } -static void max8998_irq_unmask(unsigned int irq) +static void max8998_irq_unmask(struct irq_data *data) { - struct max8998_dev *max8998 = get_irq_chip_data(irq); - struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq); + struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); + struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, + data->irq); max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; } -static void max8998_irq_mask(unsigned int irq) +static void max8998_irq_mask(struct irq_data *data) { - struct max8998_dev *max8998 = get_irq_chip_data(irq); - struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq); + struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data); + struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, + data->irq); max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; } static struct irq_chip max8998_irq_chip = { .name = "max8998", - .bus_lock = max8998_irq_lock, - .bus_sync_unlock = max8998_irq_sync_unlock, - .mask = max8998_irq_mask, - .unmask = max8998_irq_unmask, + .irq_bus_lock = max8998_irq_lock, + .irq_bus_sync_unlock = max8998_irq_sync_unlock, + .irq_mask = max8998_irq_mask, + .irq_unmask = max8998_irq_unmask, }; static irqreturn_t max8998_irq_thread(int irq, void *data) -- cgit v1.2.3 From 43b8c08402de2fb85cd18ebc746b598ce2473664 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 12:01:08 +0000 Subject: mfd: Convert SMTPE driver to new irq_ APIs The genirq core is being updated to supply struct irq_data to irq_chip operations rather than an irq number. Update the SMTPE driver to the new APIs. Signed-off-by: Mark Brown Acked-by: Rabin Vincent Signed-off-by: Samuel Ortiz --- drivers/mfd/stmpe.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index b11487f1e1cb..3e5732b58c49 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data) return IRQ_HANDLED; } -static void stmpe_irq_lock(unsigned int irq) +static void stmpe_irq_lock(struct irq_data *data) { - struct stmpe *stmpe = get_irq_chip_data(irq); + struct stmpe *stmpe = irq_data_get_irq_chip_data(data); mutex_lock(&stmpe->irq_lock); } -static void stmpe_irq_sync_unlock(unsigned int irq) +static void stmpe_irq_sync_unlock(struct irq_data *data) { - struct stmpe *stmpe = get_irq_chip_data(irq); + struct stmpe *stmpe = irq_data_get_irq_chip_data(data); struct stmpe_variant_info *variant = stmpe->variant; int num = DIV_ROUND_UP(variant->num_irqs, 8); int i; @@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq) mutex_unlock(&stmpe->irq_lock); } -static void stmpe_irq_mask(unsigned int irq) +static void stmpe_irq_mask(struct irq_data *data) { - struct stmpe *stmpe = get_irq_chip_data(irq); - int offset = irq - stmpe->irq_base; + struct stmpe *stmpe = irq_data_get_irq_chip_data(data); + int offset = data->irq - stmpe->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); stmpe->ier[regoffset] &= ~mask; } -static void stmpe_irq_unmask(unsigned int irq) +static void stmpe_irq_unmask(struct irq_data *data) { - struct stmpe *stmpe = get_irq_chip_data(irq); - int offset = irq - stmpe->irq_base; + struct stmpe *stmpe = irq_data_get_irq_chip_data(data); + int offset = data->irq - stmpe->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq) static struct irq_chip stmpe_irq_chip = { .name = "stmpe", - .bus_lock = stmpe_irq_lock, - .bus_sync_unlock = stmpe_irq_sync_unlock, - .mask = stmpe_irq_mask, - .unmask = stmpe_irq_unmask, + .irq_bus_lock = stmpe_irq_lock, + .irq_bus_sync_unlock = stmpe_irq_sync_unlock, + .irq_mask = stmpe_irq_mask, + .irq_unmask = stmpe_irq_unmask, }; static int __devinit stmpe_irq_init(struct stmpe *stmpe) -- cgit v1.2.3 From a4e7feadcc2aa5754f5ebfe67b9f07b5fddede51 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 12:18:58 +0000 Subject: mfd: Convert t7166xb driver to new irq_ API The genirq core is being updated to pass struct irq_data rather than an irq number to irq_chip operations. Update the t7166xb driver to the new APIs. Signed-off-by: Mark Brown Acked-by: Ian Molton Signed-off-by: Samuel Ortiz --- drivers/mfd/t7l66xb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 006c121f3f0d..9caeb4ac6ea6 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -199,37 +199,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) generic_handle_irq(irq_base + i); } -static void t7l66xb_irq_mask(unsigned int irq) +static void t7l66xb_irq_mask(struct irq_data *data) { - struct t7l66xb *t7l66xb = get_irq_chip_data(irq); + struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); unsigned long flags; u8 imr; spin_lock_irqsave(&t7l66xb->lock, flags); imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); - imr |= 1 << (irq - t7l66xb->irq_base); + imr |= 1 << (data->irq - t7l66xb->irq_base); tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); spin_unlock_irqrestore(&t7l66xb->lock, flags); } -static void t7l66xb_irq_unmask(unsigned int irq) +static void t7l66xb_irq_unmask(struct irq_data *data) { - struct t7l66xb *t7l66xb = get_irq_chip_data(irq); + struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data); unsigned long flags; u8 imr; spin_lock_irqsave(&t7l66xb->lock, flags); imr = tmio_ioread8(t7l66xb->scr + SCR_IMR); - imr &= ~(1 << (irq - t7l66xb->irq_base)); + imr &= ~(1 << (data->irq - t7l66xb->irq_base)); tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR); spin_unlock_irqrestore(&t7l66xb->lock, flags); } static struct irq_chip t7l66xb_chip = { - .name = "t7l66xb", - .ack = t7l66xb_irq_mask, - .mask = t7l66xb_irq_mask, - .unmask = t7l66xb_irq_unmask, + .name = "t7l66xb", + .irq_ack = t7l66xb_irq_mask, + .irq_mask = t7l66xb_irq_mask, + .irq_unmask = t7l66xb_irq_unmask, }; /*--------------------------------------------------------------------------*/ -- cgit v1.2.3 From 01af22eb15e46488cf3de67f6d2222c2eed5f763 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 12:34:04 +0000 Subject: mfd: Convert tc6393xb driver to new irq_ APIs The genirq core is being update to pass struct irq_data to irq_chip rather than an irq number to operations. Update tc6393 to the new API. Signed-off-by: Mark Brown Acked-by: Ian Molton Signed-off-by: Samuel Ortiz --- drivers/mfd/tc6393xb.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 1ea80d8ad915..9a238633a54d 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -527,41 +527,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc) } } -static void tc6393xb_irq_ack(unsigned int irq) +static void tc6393xb_irq_ack(struct irq_data *data) { } -static void tc6393xb_irq_mask(unsigned int irq) +static void tc6393xb_irq_mask(struct irq_data *data) { - struct tc6393xb *tc6393xb = get_irq_chip_data(irq); + struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); unsigned long flags; u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); - imr |= 1 << (irq - tc6393xb->irq_base); + imr |= 1 << (data->irq - tc6393xb->irq_base); tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); } -static void tc6393xb_irq_unmask(unsigned int irq) +static void tc6393xb_irq_unmask(struct irq_data *data) { - struct tc6393xb *tc6393xb = get_irq_chip_data(irq); + struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data); unsigned long flags; u8 imr; spin_lock_irqsave(&tc6393xb->lock, flags); imr = tmio_ioread8(tc6393xb->scr + SCR_IMR); - imr &= ~(1 << (irq - tc6393xb->irq_base)); + imr &= ~(1 << (data->irq - tc6393xb->irq_base)); tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR); spin_unlock_irqrestore(&tc6393xb->lock, flags); } static struct irq_chip tc6393xb_chip = { - .name = "tc6393xb", - .ack = tc6393xb_irq_ack, - .mask = tc6393xb_irq_mask, - .unmask = tc6393xb_irq_unmask, + .name = "tc6393xb", + .irq_ack = tc6393xb_irq_ack, + .irq_mask = tc6393xb_irq_mask, + .irq_unmask = tc6393xb_irq_unmask, }; static void tc6393xb_attach_irq(struct platform_device *dev) -- cgit v1.2.3 From 96e824bdf3349a7e581004286274be6c0df6c710 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 12:39:28 +0000 Subject: mfd: Convert tps6586x driver to new irq_ API The genirq core is being updated to supply struct irq_data to irq_chip operations rather than an irq number. Update the tps6586x driver to the new APIs. Signed-off-by: Mark Brown Acked-by: Mike Rapoport Signed-off-by: Samuel Ortiz --- drivers/mfd/tps6586x.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 35757399add0..627cf577b16d 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -323,37 +323,37 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x) return device_for_each_child(tps6586x->dev, NULL, __remove_subdev); } -static void tps6586x_irq_lock(unsigned int irq) +static void tps6586x_irq_lock(struct irq_data *data) { - struct tps6586x *tps6586x = get_irq_chip_data(irq); + struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data); mutex_lock(&tps6586x->irq_lock); } -static void tps6586x_irq_enable(unsigned int irq) +static void tps6586x_irq_enable(struct irq_data *irq_data) { - struct tps6586x *tps6586x = get_irq_chip_data(irq); - unsigned int __irq = irq - tps6586x->irq_base; + struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); + unsigned int __irq = irq_data->irq - tps6586x->irq_base; const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; tps6586x->irq_en |= (1 << __irq); } -static void tps6586x_irq_disable(unsigned int irq) +static void tps6586x_irq_disable(struct irq_data *irq_data) { - struct tps6586x *tps6586x = get_irq_chip_data(irq); + struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); - unsigned int __irq = irq - tps6586x->irq_base; + unsigned int __irq = irq_data->irq - tps6586x->irq_base; const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; tps6586x->irq_en &= ~(1 << __irq); } -static void tps6586x_irq_sync_unlock(unsigned int irq) +static void tps6586x_irq_sync_unlock(struct irq_data *data) { - struct tps6586x *tps6586x = get_irq_chip_data(irq); + struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data); int i; for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) { @@ -419,10 +419,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, tps6586x->irq_base = irq_base; tps6586x->irq_chip.name = "tps6586x"; - tps6586x->irq_chip.enable = tps6586x_irq_enable; - tps6586x->irq_chip.disable = tps6586x_irq_disable; - tps6586x->irq_chip.bus_lock = tps6586x_irq_lock; - tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock; + tps6586x->irq_chip.irq_enable = tps6586x_irq_enable; + tps6586x->irq_chip.irq_disable = tps6586x_irq_disable; + tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock; + tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock; for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { int __irq = i + tps6586x->irq_base; -- cgit v1.2.3 From 845aeab5f1e0ef1a85b618a1bf917520a62a9c02 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 12:51:39 +0000 Subject: mfd: Convert TWL4030 to new irq_ APIs The genirq core is being updated to pass struct irq_data to irq_chip operations. Update the TWL4030 driver to the new APIs. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-irq.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 5d3a1478004b..63a30e88908f 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -599,38 +599,38 @@ static void twl4030_sih_do_edge(struct work_struct *work) * completion, potentially including some re-ordering, of these requests. */ -static void twl4030_sih_mask(unsigned irq) +static void twl4030_sih_mask(struct irq_data *data) { - struct sih_agent *sih = get_irq_chip_data(irq); + struct sih_agent *sih = irq_data_get_irq_chip_data(data); unsigned long flags; spin_lock_irqsave(&sih_agent_lock, flags); - sih->imr |= BIT(irq - sih->irq_base); + sih->imr |= BIT(data->irq - sih->irq_base); sih->imr_change_pending = true; queue_work(wq, &sih->mask_work); spin_unlock_irqrestore(&sih_agent_lock, flags); } -static void twl4030_sih_unmask(unsigned irq) +static void twl4030_sih_unmask(struct irq_data *data) { - struct sih_agent *sih = get_irq_chip_data(irq); + struct sih_agent *sih = irq_data_get_irq_chip_data(data); unsigned long flags; spin_lock_irqsave(&sih_agent_lock, flags); - sih->imr &= ~BIT(irq - sih->irq_base); + sih->imr &= ~BIT(data->irq - sih->irq_base); sih->imr_change_pending = true; queue_work(wq, &sih->mask_work); spin_unlock_irqrestore(&sih_agent_lock, flags); } -static int twl4030_sih_set_type(unsigned irq, unsigned trigger) +static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger) { - struct sih_agent *sih = get_irq_chip_data(irq); - struct irq_desc *desc = irq_to_desc(irq); + struct sih_agent *sih = irq_data_get_irq_chip_data(data); + struct irq_desc *desc = irq_to_desc(data->irq); unsigned long flags; if (!desc) { - pr_err("twl4030: Invalid IRQ: %d\n", irq); + pr_err("twl4030: Invalid IRQ: %d\n", data->irq); return -EINVAL; } @@ -641,7 +641,7 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger) if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) { desc->status &= ~IRQ_TYPE_SENSE_MASK; desc->status |= trigger; - sih->edge_change |= BIT(irq - sih->irq_base); + sih->edge_change |= BIT(data->irq - sih->irq_base); queue_work(wq, &sih->edge_work); } spin_unlock_irqrestore(&sih_agent_lock, flags); @@ -650,9 +650,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger) static struct irq_chip twl4030_sih_irq_chip = { .name = "twl4030", - .mask = twl4030_sih_mask, - .unmask = twl4030_sih_unmask, - .set_type = twl4030_sih_set_type, + .irq_mask = twl4030_sih_mask, + .irq_unmask = twl4030_sih_unmask, + .irq_set_type = twl4030_sih_set_type, }; /*----------------------------------------------------------------------*/ -- cgit v1.2.3 From 25a947f805b4132b69f2561589e17a0fe45552b6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 13:21:21 +0000 Subject: mfd: Convert Wolfson MFD drivers to use irq_data accessor function Actually makes the code larger rathe rthan smaller but does provide some isolation against core API changes. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 10 +++++----- drivers/mfd/wm8350-irq.c | 8 ++++---- drivers/mfd/wm8994-irq.c | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index eae52726bf3e..ee88f6a05cec 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -347,14 +347,14 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, static void wm831x_irq_lock(struct irq_data *data) { - struct wm831x *wm831x = data->chip_data; + struct wm831x *wm831x = irq_data_get_irq_chip_data(data); mutex_lock(&wm831x->irq_lock); } static void wm831x_irq_sync_unlock(struct irq_data *data) { - struct wm831x *wm831x = data->chip_data; + struct wm831x *wm831x = irq_data_get_irq_chip_data(data); int i; for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { @@ -373,7 +373,7 @@ static void wm831x_irq_sync_unlock(struct irq_data *data) static void wm831x_irq_unmask(struct irq_data *data) { - struct wm831x *wm831x = data->chip_data; + struct wm831x *wm831x = irq_data_get_irq_chip_data(data); struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, data->irq); @@ -382,7 +382,7 @@ static void wm831x_irq_unmask(struct irq_data *data) static void wm831x_irq_mask(struct irq_data *data) { - struct wm831x *wm831x = data->chip_data; + struct wm831x *wm831x = irq_data_get_irq_chip_data(data); struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, data->irq); @@ -391,7 +391,7 @@ static void wm831x_irq_mask(struct irq_data *data) static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) { - struct wm831x *wm831x = data->chip_data; + struct wm831x *wm831x = irq_data_get_irq_chip_data(data); int val, irq; irq = data->irq - wm831x->irq_base; diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index ba966ae88dc3..5839966ebd85 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -419,14 +419,14 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) static void wm8350_irq_lock(struct irq_data *data) { - struct wm8350 *wm8350 = data->chip_data; + struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); mutex_lock(&wm8350->irq_lock); } static void wm8350_irq_sync_unlock(struct irq_data *data) { - struct wm8350 *wm8350 = data->chip_data; + struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); int i; for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { @@ -444,7 +444,7 @@ static void wm8350_irq_sync_unlock(struct irq_data *data) static void wm8350_irq_enable(struct irq_data *data) { - struct wm8350 *wm8350 = data->chip_data; + struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, data->irq); @@ -453,7 +453,7 @@ static void wm8350_irq_enable(struct irq_data *data) static void wm8350_irq_disable(struct irq_data *data) { - struct wm8350 *wm8350 = data->chip_data; + struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data); struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, data->irq); diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 62598840ad04..29e8faf9c01c 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -158,14 +158,14 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994, static void wm8994_irq_lock(struct irq_data *data) { - struct wm8994 *wm8994 = data->chip_data; + struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); mutex_lock(&wm8994->irq_lock); } static void wm8994_irq_sync_unlock(struct irq_data *data) { - struct wm8994 *wm8994 = data->chip_data; + struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); int i; for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) { @@ -184,7 +184,7 @@ static void wm8994_irq_sync_unlock(struct irq_data *data) static void wm8994_irq_unmask(struct irq_data *data) { - struct wm8994 *wm8994 = data->chip_data; + struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, data->irq); @@ -193,7 +193,7 @@ static void wm8994_irq_unmask(struct irq_data *data) static void wm8994_irq_mask(struct irq_data *data) { - struct wm8994 *wm8994 = data->chip_data; + struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, data->irq); -- cgit v1.2.3 From 7eb19812eead8d0faf30682b69970b36dc02e570 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 20 Dec 2010 11:26:19 +0100 Subject: misc: Fix cs5535 printk warnings drivers/misc/cs5535-mfgpt.c: In function 'cs5535_mfgpt_probe': drivers/misc/cs5535-mfgpt.c:320: warning: format '%x' expects type 'unsigned int', but argument 3 has type 'resource_size_t' drivers/misc/cs5535-mfgpt.c:320: warning: format '%x' expects type 'unsigned int', but argument 4 has type 'resource_size_t' Use vsprintf extension %pR to format resource. Original-patch-by: Randy Dunlap Signed-off-by: Joe Perches Signed-off-by: Samuel Ortiz --- drivers/misc/cs5535-mfgpt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 26693060b29b..d02d302ee6d5 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -317,8 +317,7 @@ static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) cs5535_mfgpt_chip.pdev = pdev; spin_lock_init(&cs5535_mfgpt_chip.lock); - dev_info(&pdev->dev, "region 0x%x - 0x%x reserved\n", res->start, - res->end); + dev_info(&pdev->dev, "reserved resource region %pR\n", res); /* detect the available timers */ t = scan_timers(&cs5535_mfgpt_chip); -- cgit v1.2.3 From 1db0b427eec6f18477fa95aab8edf6176dffcea4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 20 Dec 2010 11:28:40 +0100 Subject: gpio: Fix cs5535 printk warnings drivers/gpio/cs5535-gpio.c: In function 'cs5535_gpio_probe': drivers/gpio/cs5535-gpio.c:269: warning: format '%x' expects type 'unsigned int', but argument 3 has type 'resource_size_t' drivers/gpio/cs5535-gpio.c:269: warning: format '%x' expects type 'unsigned int', but argument 4 has type 'resource_size_t' Use vsprintf extension %pR to format resource. Original-patch-by: Randy Dunlap Signed-off-by: Joe Perches Signed-off-by: Samuel Ortiz --- drivers/gpio/cs5535-gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index f9813ef48534..0d05ea7d499b 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -329,8 +329,7 @@ static int __devinit cs5535_gpio_probe(struct platform_device *pdev) cs5535_gpio_chip.pdev = pdev; spin_lock_init(&cs5535_gpio_chip.lock); - dev_info(&pdev->dev, "region 0x%x - 0x%x reserved\n", - res->start, res->end); + dev_info(&pdev->dev, "reserved resource region %pR\n", res); /* mask out reserved pins */ mask &= 0x1F7FFFFF; -- cgit v1.2.3 From c45c685c1a582e27787b5aa85844f2ee6986018c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 13 Dec 2010 13:31:18 +0100 Subject: mfd: twl6030 irq_data conversion. Signed-off-by: Lennert Buytenhek Acked-by: Santosh Shilimkar Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 06c8955907e9..4082ed73613f 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -332,7 +332,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) */ twl6030_irq_chip = dummy_irq_chip; twl6030_irq_chip.name = "twl6030"; - twl6030_irq_chip.set_type = NULL; + twl6030_irq_chip.irq_set_type = NULL; for (i = irq_base; i < irq_end; i++) { set_irq_chip_and_handler(i, &twl6030_irq_chip, -- cgit v1.2.3 From 3ec33012dc07ab7e12fdd3f7f927c09264dcb5ec Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 20 Dec 2010 10:02:06 +0800 Subject: mfd: Add __devexit annotation for vx855_remove Signed-off-by: Axel Lin Acked-by: Harald Welte Signed-off-by: Samuel Ortiz --- drivers/mfd/vx855.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index ebb059765edd..348052aa5dbf 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c @@ -112,7 +112,7 @@ out: return ret; } -static void vx855_remove(struct pci_dev *pdev) +static void __devexit vx855_remove(struct pci_dev *pdev) { mfd_remove_devices(&pdev->dev); pci_disable_device(pdev); -- cgit v1.2.3 From b14375800751da9fcd63ec11d39a86077f214dc2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 20 Dec 2010 12:28:11 +0000 Subject: misc: Make AB8500_PWM driver depend on U8500 due to PWM breakage Since we don't have a PWM API every PWM driver ends up exporting its own version and we need to limit the platforms we try to build them on in order to avoid multiple definitions. As the AB8500 is normally a companion chip for the U8500 CPU depend on that architecture. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/misc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1e1a4be8eb6c..cc8e49db45fe 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -64,7 +64,7 @@ config ATMEL_PWM config AB8500_PWM bool "AB8500 PWM support" - depends on AB8500_CORE + depends on AB8500_CORE && ARCH_U8500 select HAVE_PWM help This driver exports functions to enable/disble/config/free Pulse -- cgit v1.2.3 From 1d83864cab272f764beb381bbd3837f91fc0abed Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 11 Dec 2010 13:07:49 +0000 Subject: mfd: Remove ARCH_U8500 dependency from AB8500 While it is vanishingly unlikely that the device will be deployed on other architectures removing the dependency facilitates build testing when doing generic work on both the MFD core for the device and the subsystem drivers. There appears to be no actual code dependency. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b5e3e09f5637..c32b62a8a1f6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -496,7 +496,7 @@ config EZX_PCAP config AB8500_CORE bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" - depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500 + depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER select MFD_CORE help Select this option to enable access to AB8500 power management -- cgit v1.2.3 From 6680d940b80dbb0617226c5b76b071a3977feb1c Mon Sep 17 00:00:00 2001 From: Sundar Iyer Date: Fri, 24 Dec 2010 11:52:08 +0100 Subject: mfd/ab8500: remove spi support Since the Ab8500 v1.0, the SPI support is deprecated on the HW. Signed-off-by: Sundar Iyer Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 8 +-- drivers/mfd/Makefile | 2 +- drivers/mfd/ab8500-spi.c | 143 ----------------------------------------------- 3 files changed, 5 insertions(+), 148 deletions(-) delete mode 100644 drivers/mfd/ab8500-spi.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index c32b62a8a1f6..fd018366d670 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -496,13 +496,13 @@ config EZX_PCAP config AB8500_CORE bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" - depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER + depends on GENERIC_HARDIRQS && ABX500_CORE select MFD_CORE help Select this option to enable access to AB8500 power management - chip. This connects to U8500 either on the SSP/SPI bus - or the I2C bus via PRCMU. It also adds the irq_chip - parts for handling the Mixed Signal chip events. + chip. This connects to U8500 either on the SSP/SPI bus (deprecated + since hardware version v1.0) or the I2C bus via PRCMU. It also adds + the irq_chip parts for handling the Mixed Signal chip events. This chip embeds various other multimedia funtionalities as well. config AB8500_I2C_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5f35de9386e3..a54e2c7c6a1c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -70,7 +70,7 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_AB3100_CORE) += ab3100-core.o obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB3550_CORE) += ab3550-core.o -obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o +obj-$(CONFIG_AB8500_CORE) += ab8500-core.o obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c deleted file mode 100644 index b1653421edb5..000000000000 --- a/drivers/mfd/ab8500-spi.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * License Terms: GNU General Public License v2 - * Author: Srinidhi Kasagar - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * This funtion writes to any AB8500 registers using - * SPI protocol & before it writes it packs the data - * in the below 24 bit frame format - * - * *|------------------------------------| - * *| 23|22...18|17.......10|9|8|7......0| - * *| r/w bank adr data | - * * ------------------------------------ - * - * This function shouldn't be called from interrupt - * context - */ -static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data) -{ - struct spi_device *spi = container_of(ab8500->dev, struct spi_device, - dev); - unsigned long spi_data = addr << 10 | data; - struct spi_transfer xfer; - struct spi_message msg; - - ab8500->tx_buf[0] = spi_data; - ab8500->rx_buf[0] = 0; - - xfer.tx_buf = ab8500->tx_buf; - xfer.rx_buf = NULL; - xfer.len = sizeof(unsigned long); - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - return spi_sync(spi, &msg); -} - -static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr) -{ - struct spi_device *spi = container_of(ab8500->dev, struct spi_device, - dev); - unsigned long spi_data = 1 << 23 | addr << 10; - struct spi_transfer xfer; - struct spi_message msg; - int ret; - - ab8500->tx_buf[0] = spi_data; - ab8500->rx_buf[0] = 0; - - xfer.tx_buf = ab8500->tx_buf; - xfer.rx_buf = ab8500->rx_buf; - xfer.len = sizeof(unsigned long); - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - ret = spi_sync(spi, &msg); - if (!ret) - /* - * Only the 8 lowermost bytes are - * defined with value, the rest may - * vary depending on chip/board noise. - */ - ret = ab8500->rx_buf[0] & 0xFFU; - - return ret; -} - -static int __devinit ab8500_spi_probe(struct spi_device *spi) -{ - struct ab8500 *ab8500; - int ret; - - spi->bits_per_word = 24; - ret = spi_setup(spi); - if (ret < 0) - return ret; - - ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); - if (!ab8500) - return -ENOMEM; - - ab8500->dev = &spi->dev; - ab8500->irq = spi->irq; - - ab8500->read = ab8500_spi_read; - ab8500->write = ab8500_spi_write; - - spi_set_drvdata(spi, ab8500); - - ret = ab8500_init(ab8500); - if (ret) - kfree(ab8500); - - return ret; -} - -static int __devexit ab8500_spi_remove(struct spi_device *spi) -{ - struct ab8500 *ab8500 = spi_get_drvdata(spi); - - ab8500_exit(ab8500); - kfree(ab8500); - - return 0; -} - -static struct spi_driver ab8500_spi_driver = { - .driver = { - .name = "ab8500-spi", - .owner = THIS_MODULE, - }, - .probe = ab8500_spi_probe, - .remove = __devexit_p(ab8500_spi_remove) -}; - -static int __init ab8500_spi_init(void) -{ - return spi_register_driver(&ab8500_spi_driver); -} -subsys_initcall(ab8500_spi_init); - -static void __exit ab8500_spi_exit(void) -{ - spi_unregister_driver(&ab8500_spi_driver); -} -module_exit(ab8500_spi_exit); - -MODULE_AUTHOR("Srinidhi KASAGAR Date: Thu, 23 Dec 2010 17:53:36 +0900 Subject: mfd: MAX8998/LP3974 hibernation support This patch makes the driver to save and restore register values for hibernation. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Samuel Ortiz --- drivers/mfd/max8998-irq.c | 7 +++ drivers/mfd/max8998.c | 108 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/max8998-private.h | 2 + include/linux/mfd/max8998.h | 1 + 4 files changed, 118 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index c6b61fcc5808..3903e1fbb334 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c @@ -183,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data) return IRQ_HANDLED; } +int max8998_irq_resume(struct max8998_dev *max8998) +{ + if (max8998->irq && max8998->irq_base) + max8998_irq_thread(max8998->irq_base, max8998); + return 0; +} + int max8998_irq_init(struct max8998_dev *max8998) { int i; diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index bb9977bebe78..5ce00ad5241a 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -135,6 +137,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c, if (pdata) { max8998->ono = pdata->ono; max8998->irq_base = pdata->irq_base; + max8998->wakeup = pdata->wakeup; } mutex_init(&max8998->iolock); @@ -146,6 +149,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, ret = mfd_add_devices(max8998->dev, -1, max8998_devs, ARRAY_SIZE(max8998_devs), NULL, 0); + pm_runtime_set_active(max8998->dev); + if (ret < 0) goto err; @@ -178,10 +183,113 @@ static const struct i2c_device_id max8998_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); +static int max8998_suspend(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); + + if (max8998->wakeup) + set_irq_wake(max8998->irq, 1); + return 0; +} + +static int max8998_resume(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct max8998_dev *max8998 = i2c_get_clientdata(i2c); + + if (max8998->wakeup) + set_irq_wake(max8998->irq, 0); + /* + * In LP3974, if IRQ registers are not "read & clear" + * when it's set during sleep, the interrupt becomes + * disabled. + */ + return max8998_irq_resume(i2c_get_clientdata(i2c)); +} + +struct max8998_reg_dump { + u8 addr; + u8 val; +}; +#define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } +struct max8998_reg_dump max8998_dump[] = { + SAVE_ITEM(MAX8998_REG_IRQM1), + SAVE_ITEM(MAX8998_REG_IRQM2), + SAVE_ITEM(MAX8998_REG_IRQM3), + SAVE_ITEM(MAX8998_REG_IRQM4), + SAVE_ITEM(MAX8998_REG_STATUSM1), + SAVE_ITEM(MAX8998_REG_STATUSM2), + SAVE_ITEM(MAX8998_REG_CHGR1), + SAVE_ITEM(MAX8998_REG_CHGR2), + SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), + SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1), + SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3), + SAVE_ITEM(MAX8998_REG_ONOFF1), + SAVE_ITEM(MAX8998_REG_ONOFF2), + SAVE_ITEM(MAX8998_REG_ONOFF3), + SAVE_ITEM(MAX8998_REG_ONOFF4), + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1), + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2), + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3), + SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4), + SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1), + SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2), + SAVE_ITEM(MAX8998_REG_LDO2_LDO3), + SAVE_ITEM(MAX8998_REG_LDO4), + SAVE_ITEM(MAX8998_REG_LDO5), + SAVE_ITEM(MAX8998_REG_LDO6), + SAVE_ITEM(MAX8998_REG_LDO7), + SAVE_ITEM(MAX8998_REG_LDO8_LDO9), + SAVE_ITEM(MAX8998_REG_LDO10_LDO11), + SAVE_ITEM(MAX8998_REG_LDO12), + SAVE_ITEM(MAX8998_REG_LDO13), + SAVE_ITEM(MAX8998_REG_LDO14), + SAVE_ITEM(MAX8998_REG_LDO15), + SAVE_ITEM(MAX8998_REG_LDO16), + SAVE_ITEM(MAX8998_REG_LDO17), + SAVE_ITEM(MAX8998_REG_BKCHR), + SAVE_ITEM(MAX8998_REG_LBCNFG1), + SAVE_ITEM(MAX8998_REG_LBCNFG2), +}; +/* Save registers before hibernation */ +static int max8998_freeze(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + int i; + + for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) + max8998_read_reg(i2c, max8998_dump[i].addr, + &max8998_dump[i].val); + + return 0; +} + +/* Restore registers after hibernation */ +static int max8998_restore(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + int i; + + for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) + max8998_write_reg(i2c, max8998_dump[i].addr, + max8998_dump[i].val); + + return 0; +} + +const struct dev_pm_ops max8998_pm = { + .suspend = max8998_suspend, + .resume = max8998_resume, + .freeze = max8998_freeze, + .restore = max8998_restore, +}; + static struct i2c_driver max8998_i2c_driver = { .driver = { .name = "max8998", .owner = THIS_MODULE, + .pm = &max8998_pm, }, .probe = max8998_i2c_probe, .remove = max8998_i2c_remove, diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h index 7363dea6bbcd..effa5d3b96ae 100644 --- a/include/linux/mfd/max8998-private.h +++ b/include/linux/mfd/max8998-private.h @@ -159,10 +159,12 @@ struct max8998_dev { u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS]; u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS]; int type; + bool wakeup; }; int max8998_irq_init(struct max8998_dev *max8998); void max8998_irq_exit(struct max8998_dev *max8998); +int max8998_irq_resume(struct max8998_dev *max8998); extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count, diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h index f8c9f884aff2..686a744e63fb 100644 --- a/include/linux/mfd/max8998.h +++ b/include/linux/mfd/max8998.h @@ -88,6 +88,7 @@ struct max8998_platform_data { int buck1_set1; int buck1_set2; int buck2_set3; + bool wakeup; }; #endif /* __LINUX_MFD_MAX8998_H */ -- cgit v1.2.3 From de8255ccd219267cfd34139022b197c1ef8f032f Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 30 Dec 2010 20:27:33 -0800 Subject: i2c: Convert SCx200 driver from using raw PCI to platform device The SCx200 ACB driver supports ISA hardware as well as PCI. The PCI hardware is CS5535/CS5536 based, and the device that it grabs is handled by the cs5535-mfd driver. This converts the SCx200 driver to use a platform_driver rather than the previous PCI hackery. The driver used to manually track the iface list (via linked list); now it only does this for ISA devices. PCI ifaces are handled through standard driver model lists. It's unclear what happens in case of errors in the old ISA code; rather than pretending the code actually cares, I've dropped the (implicit) ignorance of return values and marked it with a comment. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/i2c/busses/scx200_acb.c | 200 ++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 120 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 53fab518b3da..986e5f62debe 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ MODULE_AUTHOR("Christer Weinigel "); MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver"); +MODULE_ALIAS("platform:cs5535-smb"); MODULE_LICENSE("GPL"); #define MAX_DEVICES 4 @@ -84,10 +86,6 @@ struct scx200_acb_iface { u8 *ptr; char needs_reset; unsigned len; - - /* PCI device info */ - struct pci_dev *pdev; - int bar; }; /* Register Definitions */ @@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = { static struct scx200_acb_iface *scx200_acb_list; static DEFINE_MUTEX(scx200_acb_list_mutex); -static __init int scx200_acb_probe(struct scx200_acb_iface *iface) +static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface) { u8 val; @@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface) return 0; } -static __init struct scx200_acb_iface *scx200_create_iface(const char *text, +static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text, struct device *dev, int index) { struct scx200_acb_iface *iface; @@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, return iface; } -static int __init scx200_acb_create(struct scx200_acb_iface *iface) +static int __devinit scx200_acb_create(struct scx200_acb_iface *iface) { struct i2c_adapter *adapter; int rc; @@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface) return -ENODEV; } - mutex_lock(&scx200_acb_list_mutex); - iface->next = scx200_acb_list; - scx200_acb_list = iface; - mutex_unlock(&scx200_acb_list_mutex); + if (!adapter->dev.parent) { + /* If there's no dev, we're tracking (ISA) ifaces manually */ + mutex_lock(&scx200_acb_list_mutex); + iface->next = scx200_acb_list; + scx200_acb_list = iface; + mutex_unlock(&scx200_acb_list_mutex); + } return 0; } -static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, - int bar) +static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text, + unsigned long base, int index, struct device *dev) { struct scx200_acb_iface *iface; int rc; - iface = scx200_create_iface(text, &pdev->dev, 0); + iface = scx200_create_iface(text, dev, index); if (iface == NULL) - return -ENOMEM; - - iface->pdev = pdev; - iface->bar = bar; - - rc = pci_enable_device_io(iface->pdev); - if (rc) - goto errout_free; + return NULL; - rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name); - if (rc) { - printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n", - iface->bar); + if (!request_region(base, 8, iface->adapter.name)) { + printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", + base, base + 8 - 1); goto errout_free; } - iface->base = pci_resource_start(iface->pdev, iface->bar); + iface->base = base; rc = scx200_acb_create(iface); if (rc == 0) - return 0; + return iface; - pci_release_region(iface->pdev, iface->bar); - pci_dev_put(iface->pdev); + release_region(base, 8); errout_free: kfree(iface); - return rc; + return NULL; } -static int __init scx200_create_isa(const char *text, unsigned long base, - int index) +static int __devinit scx200_probe(struct platform_device *pdev) { struct scx200_acb_iface *iface; - int rc; - - iface = scx200_create_iface(text, NULL, index); - - if (iface == NULL) - return -ENOMEM; + struct resource *res; - if (!request_region(base, 8, iface->adapter.name)) { - printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", - base, base + 8 - 1); - rc = -EBUSY; - goto errout_free; + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); + return -ENODEV; } - iface->base = base; - rc = scx200_acb_create(iface); + iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev); + if (!iface) + return -EIO; - if (rc == 0) - return 0; + dev_info(&pdev->dev, "SCx200 device '%s' registered\n", + iface->adapter.name); + platform_set_drvdata(pdev, iface); - release_region(base, 8); - errout_free: - kfree(iface); - return rc; + return 0; } -/* Driver data is an index into the scx200_data array that indicates - * the name and the BAR where the I/O address resource is located. ISA - * devices are flagged with a bar value of -1 */ - -static const struct pci_device_id scx200_pci[] __initconst = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA), - .driver_data = 1 }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA), - .driver_data = 2 }, - { 0, } -}; - -static struct { - const char *name; - int bar; -} scx200_data[] = { - { "SCx200", -1 }, - { "CS5535", 0 }, - { "CS5536", 0 } -}; +static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface) +{ + i2c_del_adapter(&iface->adapter); + release_region(iface->base, 8); + kfree(iface); +} -static __init int scx200_scan_pci(void) +static int __devexit scx200_remove(struct platform_device *pdev) { - int data, dev; - int rc = -ENODEV; - struct pci_dev *pdev; + struct scx200_acb_iface *iface; - for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) { - pdev = pci_get_device(scx200_pci[dev].vendor, - scx200_pci[dev].device, NULL); + iface = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + scx200_cleanup_iface(iface); - if (pdev == NULL) - continue; + return 0; +} - data = scx200_pci[dev].driver_data; +static struct platform_driver scx200_pci_drv = { + .driver = { + .name = "cs5535-smb", + .owner = THIS_MODULE, + }, + .probe = scx200_probe, + .remove = __devexit_p(scx200_remove), +}; - /* if .bar is greater or equal to zero, this is a - * PCI device - otherwise, we assume - that the ports are ISA based - */ +static const struct pci_device_id scx200_isa[] __initconst = { + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, + { 0, } +}; - if (scx200_data[data].bar >= 0) - rc = scx200_create_pci(scx200_data[data].name, pdev, - scx200_data[data].bar); - else { - int i; +static __init void scx200_scan_isa(void) +{ + int i; - pci_dev_put(pdev); - for (i = 0; i < MAX_DEVICES; ++i) { - if (base[i] == 0) - continue; + if (!pci_dev_present(scx200_isa)) + return; - rc = scx200_create_isa(scx200_data[data].name, - base[i], - i); - } - } + for (i = 0; i < MAX_DEVICES; ++i) { + if (base[i] == 0) + continue; - break; + /* XXX: should we care about failures? */ + scx200_create_dev("SCx200", base[i], i, NULL); } - - return rc; } static int __init scx200_acb_init(void) { - int rc; - pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); - rc = scx200_scan_pci(); + /* First scan for ISA-based devices */ + scx200_scan_isa(); /* XXX: should we care about errors? */ /* If at least one bus was created, init must succeed */ if (scx200_acb_list) return 0; - return rc; + + /* No ISA devices; register the platform driver for PCI-based devices */ + return platform_driver_register(&scx200_pci_drv); } static void __exit scx200_acb_cleanup(void) { struct scx200_acb_iface *iface; + platform_driver_unregister(&scx200_pci_drv); + mutex_lock(&scx200_acb_list_mutex); while ((iface = scx200_acb_list) != NULL) { scx200_acb_list = iface->next; mutex_unlock(&scx200_acb_list_mutex); - i2c_del_adapter(&iface->adapter); - - if (iface->pdev) { - pci_release_region(iface->pdev, iface->bar); - pci_dev_put(iface->pdev); - } - else - release_region(iface->base, 8); + scx200_cleanup_iface(iface); - kfree(iface); mutex_lock(&scx200_acb_list_mutex); } mutex_unlock(&scx200_acb_list_mutex); -- cgit v1.2.3 From 337ce5d1c5759644cea6c47220ce7e84f0398362 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Tue, 4 Jan 2011 14:17:39 +0900 Subject: mfd: Support LP3974 RTC The first releases of LP3974 have a large delay in RTC registers, which requires 2 seconds of delay after writing to a rtc register (recommended by National Semiconductor's engineers) before reading it. If "rtc_delay" field of the platform data is true, the rtc driver assumes that such delays are required. Although we have not seen LP3974s without requiring such delays, we assume that such LP3974s will be released soon (or they have done so already) and they are supported by "lp3974" without setting "rtc_delay" at the platform data. This patch adds delays with msleep when writing values to RTC registers if the platform data has rtc_delay set. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/max8998.c | 26 +++++++++++++++++++--- drivers/regulator/max8998.c | 7 ++++++ drivers/rtc/rtc-max8998.c | 54 ++++++++++++++++++++++++++++++++++++++++----- include/linux/mfd/max8998.h | 4 ++++ 4 files changed, 83 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 5ce00ad5241a..bbfe86732602 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -42,6 +42,14 @@ static struct mfd_cell max8998_devs[] = { }, }; +static struct mfd_cell lp3974_devs[] = { + { + .name = "lp3974-pmic", + }, { + .name = "lp3974-rtc", + }, +}; + int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) { struct max8998_dev *max8998 = i2c_get_clientdata(i2c); @@ -146,11 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c, max8998_irq_init(max8998); - ret = mfd_add_devices(max8998->dev, -1, - max8998_devs, ARRAY_SIZE(max8998_devs), - NULL, 0); pm_runtime_set_active(max8998->dev); + switch (id->driver_data) { + case TYPE_LP3974: + ret = mfd_add_devices(max8998->dev, -1, + lp3974_devs, ARRAY_SIZE(lp3974_devs), + NULL, 0); + break; + case TYPE_MAX8998: + ret = mfd_add_devices(max8998->dev, -1, + max8998_devs, ARRAY_SIZE(max8998_devs), + NULL, 0); + break; + default: + ret = -EINVAL; + } + if (ret < 0) goto err; diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 7568df6122ab..af52ebfc4927 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -835,6 +835,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id max8998_pmic_id[] = { + { "max8998-pmic", TYPE_MAX8998 }, + { "lp3974-pmic", TYPE_LP3974 }, + { } +}; + static struct platform_driver max8998_pmic_driver = { .driver = { .name = "max8998-pmic", @@ -842,6 +848,7 @@ static struct platform_driver max8998_pmic_driver = { }, .probe = max8998_pmic_probe, .remove = __devexit_p(max8998_pmic_remove), + .id_table = max8998_pmic_id, }; static int __init max8998_pmic_init(void) diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index f22dee35f330..3f7bc6b9fefa 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MAX8998_RTC_SEC 0x00 #define MAX8998_RTC_MIN 0x01 @@ -73,6 +74,7 @@ struct max8998_rtc_info { struct i2c_client *rtc; struct rtc_device *rtc_dev; int irq; + bool lp3974_bug_workaround; }; static void max8998_data_to_tm(u8 *data, struct rtc_time *tm) @@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct max8998_rtc_info *info = dev_get_drvdata(dev); u8 data[8]; + int ret; max8998_tm_to_data(tm, data); - return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data); + ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data); + + if (info->lp3974_bug_workaround) + msleep(2000); + + return ret; } static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info) { - return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0); + int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0); + + if (info->lp3974_bug_workaround) + msleep(2000); + + return ret; } static int max8998_rtc_start_alarm(struct max8998_rtc_info *info) { - return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77); + int ret; + u8 alarm0_conf = 0x77; + + /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */ + if (info->lp3974_bug_workaround) + alarm0_conf = 0x57; + + ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf); + + if (info->lp3974_bug_workaround) + msleep(2000); + + return ret; } static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret < 0) return ret; + if (info->lp3974_bug_workaround) + msleep(2000); + if (alrm->enabled) - return max8998_rtc_start_alarm(info); + ret = max8998_rtc_start_alarm(info); - return 0; + return ret; } static int max8998_rtc_alarm_irq_enable(struct device *dev, @@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = { static int __devinit max8998_rtc_probe(struct platform_device *pdev) { struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent); + struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev); struct max8998_rtc_info *info; int ret; @@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, "rtc-alarm0", info); + if (ret < 0) dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->irq, ret); + dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name); + if (pdata->rtc_delay) { + info->lp3974_bug_workaround = true; + dev_warn(&pdev->dev, "LP3974 with RTC REGERR option." + " RTC updates will be extremely slow.\n"); + } + return 0; out_rtc: @@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id max8998_rtc_id[] = { + { "max8998-rtc", TYPE_MAX8998 }, + { "lp3974-rtc", TYPE_LP3974 }, + { } +}; + static struct platform_driver max8998_rtc_driver = { .driver = { .name = "max8998-rtc", @@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = { }, .probe = max8998_rtc_probe, .remove = __devexit_p(max8998_rtc_remove), + .id_table = max8998_rtc_id, }; static int __init max8998_rtc_init(void) diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h index 686a744e63fb..c22b9a417c35 100644 --- a/include/linux/mfd/max8998.h +++ b/include/linux/mfd/max8998.h @@ -76,6 +76,9 @@ struct max8998_regulator_data { * @buck1_set1: BUCK1 gpio pin 1 to set output voltage * @buck1_set2: BUCK1 gpio pin 2 to set output voltage * @buck2_set3: BUCK2 gpio pin to set output voltage + * @wakeup: Allow to wake up from suspend + * @rtc_delay: LP3974 RTC chip bug that requires delay after a register + * write before reading it. */ struct max8998_platform_data { struct max8998_regulator_data *regulators; @@ -89,6 +92,7 @@ struct max8998_platform_data { int buck1_set2; int buck2_set3; bool wakeup; + bool rtc_delay; }; #endif /* __LINUX_MFD_MAX8998_H */ -- cgit v1.2.3 From 735a3d9efdc5aeebe201008e6655b235c7f02aeb Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Tue, 11 Jan 2011 12:20:05 +0100 Subject: regulator: Support MAX8998/LP3974 DVS-GPIO The previous driver did not support BUCK1-DVS3, BUCK1-DVS4, and BUCK2-DVS2 modes. This patch adds such modes and an option to block setting buck1/2 voltages out of the preset values. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/regulator/max8998.c | 87 ++++++++++++++++++++++++++++++++++----------- include/linux/mfd/max8998.h | 26 ++++++++++---- 2 files changed, 87 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index af52ebfc4927..0ec49ca527a8 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -424,6 +424,9 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, } } + if (pdata->buck_voltage_lock) + return -EINVAL; + /* no predefine regulator found */ max8998->buck1_idx = (buck1_last_val % 2) + 2; dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n", @@ -451,18 +454,26 @@ buck1_exit: "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n" , i, max8998->buck2_vol[0], max8998->buck2_vol[1]); if (gpio_is_valid(pdata->buck2_set3)) { - if (max8998->buck2_vol[0] == i) { - max8998->buck1_idx = 0; - buck2_gpio_set(pdata->buck2_set3, 0); - } else { - max8998->buck1_idx = 1; - ret = max8998_get_voltage_register(rdev, ®, - &shift, - &mask); - ret = max8998_write_reg(i2c, reg, i); - max8998->buck2_vol[1] = i; - buck2_gpio_set(pdata->buck2_set3, 1); + + /* check if requested voltage */ + /* value is already defined */ + for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) { + if (max8998->buck2_vol[j] == i) { + max8998->buck2_idx = j; + buck2_gpio_set(pdata->buck2_set3, j); + goto buck2_exit; + } } + + if (pdata->buck_voltage_lock) + return -EINVAL; + + max8998_get_voltage_register(rdev, + ®, &shift, &mask); + ret = max8998_write_reg(i2c, reg, i); + max8998->buck2_vol[max8998->buck2_idx] = i; + buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx); +buck2_exit: dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name, gpio_get_value(pdata->buck2_set3)); } else { @@ -707,6 +718,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, max8998); i2c = max8998->iodev->i2c; + max8998->buck1_idx = pdata->buck1_default_idx; + max8998->buck2_idx = pdata->buck2_default_idx; + /* NOTE: */ /* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */ /* will be displayed */ @@ -739,23 +753,46 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - != (pdata->buck1_max_voltage1 / 1000)) + < (pdata->buck1_voltage1 / 1000)) i++; - printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx); max8998->buck1_vol[0] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); + if (ret) + return ret; /* Set predefined value for BUCK1 register 2 */ i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - != (pdata->buck1_max_voltage2 / 1000)) + < (pdata->buck1_voltage2 / 1000)) i++; max8998->buck1_vol[1] = i; - printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx); - ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i) - + ret; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i); + if (ret) + return ret; + + /* Set predefined value for BUCK1 register 3 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + < (pdata->buck1_voltage3 / 1000)) + i++; + + max8998->buck1_vol[2] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i); + if (ret) + return ret; + + /* Set predefined value for BUCK1 register 4 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + < (pdata->buck1_voltage4 / 1000)) + i++; + + max8998->buck1_vol[3] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i); if (ret) return ret; @@ -772,18 +809,28 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) gpio_direction_output(pdata->buck2_set3, max8998->buck2_idx & 0x1); - /* BUCK2 - set preset default voltage value to buck2_vol[0] */ + /* BUCK2 register 1 */ i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - != (pdata->buck2_max_voltage / 1000)) + < (pdata->buck2_voltage1 / 1000)) i++; - printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx); max8998->buck2_vol[0] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); if (ret) return ret; + /* BUCK2 register 2 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + < (pdata->buck2_voltage2 / 1000)) + i++; + printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx); + max8998->buck2_vol[1] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); + if (ret) + return ret; } for (i = 0; i < pdata->num_regulators; i++) { diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h index c22b9a417c35..61daa167b576 100644 --- a/include/linux/mfd/max8998.h +++ b/include/linux/mfd/max8998.h @@ -70,12 +70,20 @@ struct max8998_regulator_data { * @num_regulators: number of regultors used * @irq_base: base IRQ number for max8998, required for IRQs * @ono: power onoff IRQ number for max8998 - * @buck1_max_voltage1: BUCK1 maximum alowed voltage register 1 - * @buck1_max_voltage2: BUCK1 maximum alowed voltage register 2 - * @buck2_max_voltage: BUCK2 maximum alowed voltage + * @buck_voltage_lock: Do NOT change the values of the following six + * registers set by buck?_voltage?. The voltage of BUCK1/2 cannot + * be other than the preset values. + * @buck1_voltage1: BUCK1 DVS mode 1 voltage register + * @buck1_voltage2: BUCK1 DVS mode 2 voltage register + * @buck1_voltage3: BUCK1 DVS mode 3 voltage register + * @buck1_voltage4: BUCK1 DVS mode 4 voltage register + * @buck2_voltage1: BUCK2 DVS mode 1 voltage register + * @buck2_voltage2: BUCK2 DVS mode 2 voltage register * @buck1_set1: BUCK1 gpio pin 1 to set output voltage * @buck1_set2: BUCK1 gpio pin 2 to set output voltage + * @buck1_default_idx: Default for BUCK1 gpio pin 1, 2 * @buck2_set3: BUCK2 gpio pin to set output voltage + * @buck2_default_idx: Default for BUCK2 gpio pin. * @wakeup: Allow to wake up from suspend * @rtc_delay: LP3974 RTC chip bug that requires delay after a register * write before reading it. @@ -85,12 +93,18 @@ struct max8998_platform_data { int num_regulators; int irq_base; int ono; - int buck1_max_voltage1; - int buck1_max_voltage2; - int buck2_max_voltage; + bool buck_voltage_lock; + int buck1_voltage1; + int buck1_voltage2; + int buck1_voltage3; + int buck1_voltage4; + int buck2_voltage1; + int buck2_voltage2; int buck1_set1; int buck1_set2; + int buck1_default_idx; int buck2_set3; + int buck2_default_idx; bool wakeup; bool rtc_delay; }; -- cgit v1.2.3 From c538ddbe4fc70ef97af02d57abad34b246b19082 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 5 Jan 2011 15:12:39 +0000 Subject: mfd: Convert WM831x away from legacy I2C PM operations Since the legacy bus PM operations are deprecated move the suspend method over to dev_pm_ops. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-i2c.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index 38be5201c783..3853fa8e7cc2 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -94,9 +94,9 @@ static int wm831x_i2c_remove(struct i2c_client *i2c) return 0; } -static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) +static int wm831x_i2c_suspend(struct device *dev) { - struct wm831x *wm831x = i2c_get_clientdata(i2c); + struct wm831x *wm831x = dev_get_drvdata(dev); return wm831x_device_suspend(wm831x); } @@ -113,15 +113,18 @@ static const struct i2c_device_id wm831x_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); +static const struct dev_pm_ops wm831x_pm_ops = { + .suspend = wm831x_i2c_suspend, +}; static struct i2c_driver wm831x_i2c_driver = { .driver = { - .name = "wm831x", - .owner = THIS_MODULE, + .name = "wm831x", + .owner = THIS_MODULE, + .pm = &wm831x_pm_ops, }, .probe = wm831x_i2c_probe, .remove = wm831x_i2c_remove, - .suspend = wm831x_i2c_suspend, .id_table = wm831x_i2c_id, }; -- cgit v1.2.3 From 180e4f5f20ef2b03ce2b38634274dde5ccbd8951 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 5 Jan 2011 17:56:01 +0000 Subject: mfd: Flag WM831x /IRQ as a wake source The WM831x can generate wake events, some unconditionally, so flag the primary IRQ as a wake source in order to help the CPU treat the /IRQ signal appropriately. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index ee88f6a05cec..f7192d438aab 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -517,6 +517,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) return 0; } + /* Try to flag /IRQ as a wake source; there are a number of + * unconditional wake sources in the PMIC so this isn't + * conditional but we don't actually care *too* much if it + * fails. + */ + ret = enable_irq_wake(irq); + if (ret != 0) { + dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n", + ret); + } + wm831x->irq = irq; wm831x->irq_base = pdata->irq_base; -- cgit v1.2.3 From 92d50a4132977b932ed830fa58c05deeb5c524f0 Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Tue, 7 Dec 2010 11:20:47 +0100 Subject: mfd: ab8500-core chip version cut 2.0 support This patch adds support for chip version 2.0 or cut 2.0. One new interrupt latch register - latch 12 - is introduced. Signed-off-by: Mattias Wallin Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 36 +++++++++++++++++++++---------- include/linux/mfd/ab8500.h | 53 ++++++++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 86cc8874e6de..b6887014d687 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -52,6 +52,7 @@ #define AB8500_IT_LATCH8_REG 0x27 #define AB8500_IT_LATCH9_REG 0x28 #define AB8500_IT_LATCH10_REG 0x29 +#define AB8500_IT_LATCH12_REG 0x2B #define AB8500_IT_LATCH19_REG 0x32 #define AB8500_IT_LATCH20_REG 0x33 #define AB8500_IT_LATCH21_REG 0x34 @@ -98,7 +99,7 @@ * offset 0. */ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { - 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21, + 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, }; static int ab8500_get_chip_id(struct device *dev) @@ -252,6 +253,10 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) if (new == old) continue; + /* Interrupt register 12 does'nt exist prior to version 0x20 */ + if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20) + continue; + ab8500->oldmask[i] = new; reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; @@ -301,6 +306,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int status; u8 value; + /* Interrupt register 12 does'nt exist prior to version 0x20 */ + if (regoffset == 11 && ab8500->chip_id < 0x20) + continue; + status = get_register_interruptible(ab8500, AB8500_INTERRUPT, AB8500_IT_LATCH1_REG + regoffset, &value); if (status < 0 || value == 0) @@ -554,6 +563,12 @@ static struct resource ab8500_usb_resources[] = { .end = AB8500_INT_VBUS_DET_R, .flags = IORESOURCE_IRQ, }, + { + .name = "USB_LINK_STATUS", + .start = AB8500_INT_USB_LINK_STATUS, + .end = AB8500_INT_USB_LINK_STATUS, + .flags = IORESOURCE_IRQ, + }, }; static struct resource ab8500_temp_resources[] = { @@ -670,8 +685,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500) * 0x0 - Early Drop * 0x10 - Cut 1.0 * 0x11 - Cut 1.1 + * 0x20 - Cut 2.0 */ - if (value == 0x0 || value == 0x10 || value == 0x11) { + if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) { ab8500->revision = value; dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); } else { @@ -684,18 +700,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500) plat->init(ab8500); /* Clear and mask all interrupts */ - for (i = 0; i < 10; i++) { - get_register_interruptible(ab8500, AB8500_INTERRUPT, - AB8500_IT_LATCH1_REG + i, &value); - set_register_interruptible(ab8500, AB8500_INTERRUPT, - AB8500_IT_MASK1_REG + i, 0xff); - } + for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { + /* Interrupt register 12 does'nt exist prior to version 0x20 */ + if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20) + continue; - for (i = 18; i < 24; i++) { get_register_interruptible(ab8500, AB8500_INTERRUPT, - AB8500_IT_LATCH1_REG + i, &value); + AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i], + &value); set_register_interruptible(ab8500, AB8500_INTERRUPT, - AB8500_IT_MASK1_REG + i, 0xff); + AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff); } ret = abx500_register_ops(ab8500->dev, &ab8500_ops); diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index 1ad169655235..37f56b7c4c15 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h @@ -74,30 +74,37 @@ #define AB8500_INT_ACC_DETECT_21DB_F 37 #define AB8500_INT_ACC_DETECT_21DB_R 38 #define AB8500_INT_GP_SW_ADC_CONV_END 39 -#define AB8500_INT_BTEMP_LOW 72 -#define AB8500_INT_BTEMP_LOW_MEDIUM 73 -#define AB8500_INT_BTEMP_MEDIUM_HIGH 74 -#define AB8500_INT_BTEMP_HIGH 75 -#define AB8500_INT_USB_CHARGER_NOT_OK 81 -#define AB8500_INT_ID_WAKEUP_R 82 -#define AB8500_INT_ID_DET_R1R 84 -#define AB8500_INT_ID_DET_R2R 85 -#define AB8500_INT_ID_DET_R3R 86 -#define AB8500_INT_ID_DET_R4R 87 -#define AB8500_INT_ID_WAKEUP_F 88 -#define AB8500_INT_ID_DET_R1F 90 -#define AB8500_INT_ID_DET_R2F 91 -#define AB8500_INT_ID_DET_R3F 92 -#define AB8500_INT_ID_DET_R4F 93 -#define AB8500_INT_USB_CHG_DET_DONE 94 -#define AB8500_INT_USB_CH_TH_PROT_F 96 -#define AB8500_INT_USB_CH_TH_PROT_R 97 -#define AB8500_INT_MAIN_CH_TH_PROT_F 98 -#define AB8500_INT_MAIN_CH_TH_PROT_R 99 -#define AB8500_INT_USB_CHARGER_NOT_OKF 103 +#define AB8500_INT_ADP_SOURCE_ERROR 72 +#define AB8500_INT_ADP_SINK_ERROR 73 +#define AB8500_INT_ADP_PROBE_PLUG 74 +#define AB8500_INT_ADP_PROBE_UNPLUG 75 +#define AB8500_INT_ADP_SENSE_OFF 76 +#define AB8500_INT_USB_PHY_POWER_ERR 78 +#define AB8500_INT_USB_LINK_STATUS 79 +#define AB8500_INT_BTEMP_LOW 80 +#define AB8500_INT_BTEMP_LOW_MEDIUM 81 +#define AB8500_INT_BTEMP_MEDIUM_HIGH 82 +#define AB8500_INT_BTEMP_HIGH 83 +#define AB8500_INT_USB_CHARGER_NOT_OK 89 +#define AB8500_INT_ID_WAKEUP_R 90 +#define AB8500_INT_ID_DET_R1R 92 +#define AB8500_INT_ID_DET_R2R 93 +#define AB8500_INT_ID_DET_R3R 94 +#define AB8500_INT_ID_DET_R4R 95 +#define AB8500_INT_ID_WAKEUP_F 96 +#define AB8500_INT_ID_DET_R1F 98 +#define AB8500_INT_ID_DET_R2F 99 +#define AB8500_INT_ID_DET_R3F 100 +#define AB8500_INT_ID_DET_R4F 101 +#define AB8500_INT_USB_CHG_DET_DONE 102 +#define AB8500_INT_USB_CH_TH_PROT_F 104 +#define AB8500_INT_USB_CH_TH_PROT_R 105 +#define AB8500_INT_MAIN_CH_TH_PROT_F 106 +#define AB8500_INT_MAIN_CH_TH_PROT_R 107 +#define AB8500_INT_USB_CHARGER_NOT_OKF 111 -#define AB8500_NR_IRQS 104 -#define AB8500_NUM_IRQ_REGS 13 +#define AB8500_NR_IRQS 112 +#define AB8500_NUM_IRQ_REGS 14 /** * struct ab8500 - ab8500 internal structure -- cgit v1.2.3 From 359ab9f5b154cbd807a11e22792235f0f36b0cd5 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Fri, 14 Jan 2011 14:46:11 +0900 Subject: power_supply: Add MAX17042 Fuel Gauge Driver The MAX17042 is a fuel gauge with an I2C interface for lithium-ion betteries. Unlike its predecessor MAX17040, MAX17042 uses 16bit registers. Besides, MAX17042 has much more features than MAX17040; e.g., a thermistor, current and current accumulation measurement, battery internal resistance estimate, average values of measurement, and others. This patch implements a driver for MAX17042. In this initial release, we have implemented the most basic features of a fuel gauge: measure the battery capacity and voltage. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Anton Vorontsov --- drivers/power/Kconfig | 10 ++ drivers/power/Makefile | 1 + drivers/power/max17042_battery.c | 239 +++++++++++++++++++++++++++++++++ include/linux/power/max17042_battery.h | 30 +++++ 4 files changed, 280 insertions(+) create mode 100644 drivers/power/max17042_battery.c create mode 100644 include/linux/power/max17042_battery.h (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 32165295cb1b..61bf5d724139 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -136,6 +136,16 @@ config BATTERY_MAX17040 in handheld and portable equipment. The MAX17040 is configured to operate with a single lithium cell +config BATTERY_MAX17042 + tristate "Maxim MAX17042/8997/8966 Fuel Gauge" + depends on I2C + help + MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries + in handheld and portable equipment. The MAX17042 is configured + to operate with a single lithium cell. MAX8997 and MAX8966 are + multi-function devices that include fuel gauages that are compatible + with MAX17042. + config BATTERY_Z2 tristate "Z2 battery driver" depends on I2C && MACH_ZIPIT2 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 545459f9f356..8385bfae8728 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o +obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c new file mode 100644 index 000000000000..c5c8805156cb --- /dev/null +++ b/drivers/power/max17042_battery.c @@ -0,0 +1,239 @@ +/* + * Fuel gauge driver for Maxim 17042 / 8966 / 8997 + * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. + * + * Copyright (C) 2011 Samsung Electronics + * MyungJoo Ham + * + * 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 + * + * This driver is based on max17040_battery.c + */ + +#include +#include +#include +#include +#include +#include + +enum max17042_register { + MAX17042_STATUS = 0x00, + MAX17042_VALRT_Th = 0x01, + MAX17042_TALRT_Th = 0x02, + MAX17042_SALRT_Th = 0x03, + MAX17042_AtRate = 0x04, + MAX17042_RepCap = 0x05, + MAX17042_RepSOC = 0x06, + MAX17042_Age = 0x07, + MAX17042_TEMP = 0x08, + MAX17042_VCELL = 0x09, + MAX17042_Current = 0x0A, + MAX17042_AvgCurrent = 0x0B, + MAX17042_Qresidual = 0x0C, + MAX17042_SOC = 0x0D, + MAX17042_AvSOC = 0x0E, + MAX17042_RemCap = 0x0F, + MAX17402_FullCAP = 0x10, + MAX17042_TTE = 0x11, + MAX17042_V_empty = 0x12, + + MAX17042_RSLOW = 0x14, + + MAX17042_AvgTA = 0x16, + MAX17042_Cycles = 0x17, + MAX17042_DesignCap = 0x18, + MAX17042_AvgVCELL = 0x19, + MAX17042_MinMaxTemp = 0x1A, + MAX17042_MinMaxVolt = 0x1B, + MAX17042_MinMaxCurr = 0x1C, + MAX17042_CONFIG = 0x1D, + MAX17042_ICHGTerm = 0x1E, + MAX17042_AvCap = 0x1F, + MAX17042_ManName = 0x20, + MAX17042_DevName = 0x21, + MAX17042_DevChem = 0x22, + + MAX17042_TempNom = 0x24, + MAX17042_TempCold = 0x25, + MAX17042_TempHot = 0x26, + MAX17042_AIN = 0x27, + MAX17042_LearnCFG = 0x28, + MAX17042_SHFTCFG = 0x29, + MAX17042_RelaxCFG = 0x2A, + MAX17042_MiscCFG = 0x2B, + MAX17042_TGAIN = 0x2C, + MAx17042_TOFF = 0x2D, + MAX17042_CGAIN = 0x2E, + MAX17042_COFF = 0x2F, + + MAX17042_Q_empty = 0x33, + MAX17042_T_empty = 0x34, + + MAX17042_RCOMP0 = 0x38, + MAX17042_TempCo = 0x39, + MAX17042_Rx = 0x3A, + MAX17042_T_empty0 = 0x3B, + MAX17042_TaskPeriod = 0x3C, + MAX17042_FSTAT = 0x3D, + + MAX17042_SHDNTIMER = 0x3F, + + MAX17042_VFRemCap = 0x4A, + + MAX17042_QH = 0x4D, + MAX17042_QL = 0x4E, +}; + +struct max17042_chip { + struct i2c_client *client; + struct power_supply battery; + struct max17042_platform_data *pdata; +}; + +static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value) +{ + int ret = i2c_smbus_write_word_data(client, reg, value); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static int max17042_read_reg(struct i2c_client *client, u8 reg) +{ + int ret = i2c_smbus_read_word_data(client, reg); + + if (ret < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, ret); + + return ret; +} + +static enum power_supply_property max17042_battery_props[] = { + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static int max17042_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max17042_chip *chip = container_of(psy, + struct max17042_chip, battery); + + switch (psp) { + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = max17042_read_reg(chip->client, + MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */ + break; + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + val->intval = max17042_read_reg(chip->client, + MAX17042_AvgVCELL) * 83; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = max17042_read_reg(chip->client, + MAX17042_SOC) / 256; + break; + default: + return -EINVAL; + } + return 0; +} + +static int __devinit max17042_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct max17042_chip *chip; + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + chip->pdata = client->dev.platform_data; + + i2c_set_clientdata(client, chip); + + chip->battery.name = "max17042_battery"; + chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; + chip->battery.get_property = max17042_get_property; + chip->battery.properties = max17042_battery_props; + chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props); + + ret = power_supply_register(&client->dev, &chip->battery); + if (ret) { + dev_err(&client->dev, "failed: power supply register\n"); + i2c_set_clientdata(client, NULL); + kfree(chip); + return ret; + } + + if (!chip->pdata->enable_current_sense) { + max17042_write_reg(client, MAX17042_CGAIN, 0x0000); + max17042_write_reg(client, MAX17042_MiscCFG, 0x0003); + max17042_write_reg(client, MAX17042_LearnCFG, 0x0007); + } + + return 0; +} + +static int __devexit max17042_remove(struct i2c_client *client) +{ + struct max17042_chip *chip = i2c_get_clientdata(client); + + power_supply_unregister(&chip->battery); + i2c_set_clientdata(client, NULL); + kfree(chip); + return 0; +} + +static const struct i2c_device_id max17042_id[] = { + { "max17042", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max17042_id); + +static struct i2c_driver max17042_i2c_driver = { + .driver = { + .name = "max17042", + }, + .probe = max17042_probe, + .remove = __devexit_p(max17042_remove), + .id_table = max17042_id, +}; + +static int __init max17042_init(void) +{ + return i2c_add_driver(&max17042_i2c_driver); +} +module_init(max17042_init); + +static void __exit max17042_exit(void) +{ + i2c_del_driver(&max17042_i2c_driver); +} +module_exit(max17042_exit); + +MODULE_AUTHOR("MyungJoo Ham "); +MODULE_DESCRIPTION("MAX17042 Fuel Gauge"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h new file mode 100644 index 000000000000..7995deb8bfc1 --- /dev/null +++ b/include/linux/power/max17042_battery.h @@ -0,0 +1,30 @@ +/* + * Fuel gauge driver for Maxim 17042 / 8966 / 8997 + * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. + * + * Copyright (C) 2011 Samsung Electronics + * MyungJoo Ham + * + * 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 + */ + +#ifndef __MAX17042_BATTERY_H_ +#define __MAX17042_BATTERY_H_ + +struct max17042_platform_data { + bool enable_current_sense; +}; + +#endif /* __MAX17042_BATTERY_H_ */ -- cgit v1.2.3 From 2bae0093cab4ee0a7a8728fdfc35b74569350863 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 18 Dec 2010 18:42:23 +0100 Subject: [SCSI] sd: implement sd_check_events() Replace sd_media_change() with sd_check_events(). * Move media removed logic into set_media_not_present() and media_not_present() and set sdev->changed iff an existing media is removed or the device indicates UNIT_ATTENTION. * Make sd_check_events() sets sdev->changed if previously missing media becomes present. * Event is reported only if sdev->changed is set. This makes media presence event reported if scsi_disk->media_present actually changed or the device indicated UNIT_ATTENTION. For backward compatibility, SDEV_EVT_MEDIA_CHANGE is generated each time sd_check_events() detects media change event. [jejb: fix boot failure] Signed-off-by: Tejun Heo Acked-by: Jens Axboe Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 104 ++++++++++++++++++++++++++++-------------------------- drivers/scsi/sd.h | 1 - 2 files changed, 53 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b65e65aa07eb..7d257465bd98 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -990,30 +990,51 @@ out: static void set_media_not_present(struct scsi_disk *sdkp) { - sdkp->media_present = 0; - sdkp->capacity = 0; - sdkp->device->changed = 1; + if (sdkp->media_present) + sdkp->device->changed = 1; + + if (sdkp->device->removable) { + sdkp->media_present = 0; + sdkp->capacity = 0; + } +} + +static int media_not_present(struct scsi_disk *sdkp, + struct scsi_sense_hdr *sshdr) +{ + if (!scsi_sense_valid(sshdr)) + return 0; + + /* not invoked for commands that could return deferred errors */ + switch (sshdr->sense_key) { + case UNIT_ATTENTION: + case NOT_READY: + /* medium not present */ + if (sshdr->asc == 0x3A) { + set_media_not_present(sdkp); + return 1; + } + } + return 0; } /** - * sd_media_changed - check if our medium changed - * @disk: kernel device descriptor + * sd_check_events - check media events + * @disk: kernel device descriptor + * @clearing: disk events currently being cleared * - * Returns 0 if not applicable or no change; 1 if change + * Returns mask of DISK_EVENT_*. * * Note: this function is invoked from the block subsystem. **/ -static int sd_media_changed(struct gendisk *disk) +static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; struct scsi_sense_hdr *sshdr = NULL; int retval; - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); - - if (!sdp->removable) - return 0; + SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); /* * If the device is offline, don't send any commands - just pretend as @@ -1043,40 +1064,37 @@ static int sd_media_changed(struct gendisk *disk) sshdr); } - if (retval) { + /* failed to execute TUR, assume media not present */ + if (host_byte(retval)) { set_media_not_present(sdkp); goto out; } + if (media_not_present(sdkp, sshdr)) + goto out; + /* * For removable scsi disk we have to recognise the presence - * of a disk in the drive. This is kept in the struct scsi_disk - * struct and tested at open ! Daniel Roche (dan@lectra.fr) + * of a disk in the drive. */ + if (!sdkp->media_present) + sdp->changed = 1; sdkp->media_present = 1; - out: /* - * Report a media change under the following conditions: + * sdp->changed is set under the following conditions: * - * Medium is present now and wasn't present before. - * Medium wasn't present before and is present now. - * Medium was present at all times, but it changed while - * we weren't looking (sdp->changed is set). + * Medium present state has changed in either direction. + * Device has indicated UNIT_ATTENTION. * - * If there was no medium before and there is no medium now then - * don't report a change, even if a medium was inserted and removed - * while we weren't looking. + * Report SDEV_EVT_MEDIA_CHANGE too for backward compatibility. */ - retval = (sdkp->media_present != sdkp->previous_state || - (sdkp->media_present && sdp->changed)); - if (retval) + if (sdp->changed) sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); - sdkp->previous_state = sdkp->media_present; - - /* sdp->changed indicates medium was changed or is not present */ - sdp->changed = !sdkp->media_present; kfree(sshdr); + + retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; + sdp->changed = 0; return retval; } @@ -1169,7 +1187,7 @@ static const struct block_device_operations sd_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl, #endif - .media_changed = sd_media_changed, + .check_events = sd_check_events, .revalidate_disk = sd_revalidate_disk, .unlock_native_capacity = sd_unlock_native_capacity, }; @@ -1312,23 +1330,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) return good_bytes; } -static int media_not_present(struct scsi_disk *sdkp, - struct scsi_sense_hdr *sshdr) -{ - - if (!scsi_sense_valid(sshdr)) - return 0; - /* not invoked for commands that could return deferred errors */ - if (sshdr->sense_key != NOT_READY && - sshdr->sense_key != UNIT_ATTENTION) - return 0; - if (sshdr->asc != 0x3A) /* medium not present */ - return 0; - - set_media_not_present(sdkp); - return 1; -} - /* * spinup disk - called only in sd_revalidate_disk() */ @@ -1503,7 +1504,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, */ if (sdp->removable && sense_valid && sshdr->sense_key == NOT_READY) - sdp->changed = 1; + set_media_not_present(sdkp); /* * We used to set media_present to 0 here to indicate no media @@ -2389,8 +2390,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_EXT_DEVT; - if (sdp->removable) + if (sdp->removable) { gd->flags |= GENHD_FL_REMOVABLE; + gd->events |= DISK_EVENT_MEDIA_CHANGE; + } add_disk(gd); sd_dif_config_host(sdkp); @@ -2472,7 +2475,6 @@ static int sd_probe(struct device *dev) sdkp->disk = gd; sdkp->index = index; atomic_set(&sdkp->openers, 0); - sdkp->previous_state = 1; if (!sdp->request_queue->rq_timeout) { if (sdp->type != TYPE_MOD) diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 55488faf0815..c9d8f6ca49e2 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -55,7 +55,6 @@ struct scsi_disk { u8 media_present; u8 write_prot; u8 protection_type;/* Data Integrity Field */ - unsigned previous_state : 1; unsigned ATO : 1; /* state of disk ATO bit */ unsigned WCE : 1; /* state of disk WCE bit */ unsigned RCD : 1; /* state of disk RCD bit, unused */ -- cgit v1.2.3 From f4013c3879d1bbd9f3ab8351185decd049502368 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Dec 2010 16:20:47 +0100 Subject: [SCSI] sd,sr: kill compat SDEV_MEDIA_CHANGE event SDEV_MEDIA_CHANGE event was first added by commit a341cd0f (SCSI: add asynchronous event notification API) for SATA AN support and then extended to cover generic media change events by commit 285e9670 ([SCSI] sr,sd: send media state change modification events). This event was mapped to block device in userland with all properties stripped to simulate CHANGE event on the block device, which, in turn, was used to trigger further userspace action on media change. The recent addition of disk event framework kept this event for backward compatibility but it turns out to be unnecessary and causes erratic and inefficient behavior. The new disk event generates proper events on the block devices and the compat events are mapped to block device with all properties stripped, so the block device ends up generating multiple duplicate events for single actual event. This patch removes the compat event generation from both sr and sd as suggested by Kay Sievers. Both existing and newer versions of udev and the associated tools will behave better with the removal of these events as they from the beginning were expecting events on the block devices. Signed-off-by: Tejun Heo Acked-by: Kay Sievers Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 5 ----- drivers/scsi/sr.c | 4 ---- 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7d257465bd98..e56730214c05 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1086,13 +1086,8 @@ out: * * Medium present state has changed in either direction. * Device has indicated UNIT_ATTENTION. - * - * Report SDEV_EVT_MEDIA_CHANGE too for backward compatibility. */ - if (sdp->changed) - sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); kfree(sshdr); - retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; sdp->changed = 0; return retval; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index be6baf8ad704..aefadc6a1607 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -249,10 +249,6 @@ skip_tur: cd->device->changed = 0; } - /* for backward compatibility */ - if (events & DISK_EVENT_MEDIA_CHANGE) - sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, - GFP_KERNEL); return events; } -- cgit v1.2.3 From c66ac9db8d4ad9994a02b3e933ea2ccc643e1fe5 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 17 Dec 2010 11:11:26 -0800 Subject: [SCSI] target: Add LIO target core v4.0.0-rc6 LIO target is a full featured in-kernel target framework with the following feature set: High-performance, non-blocking, multithreaded architecture with SIMD support. Advanced SCSI feature set: * Persistent Reservations (PRs) * Asymmetric Logical Unit Assignment (ALUA) * Protocol and intra-nexus multiplexing, load-balancing and failover (MC/S) * Full Error Recovery (ERL=0,1,2) * Active/active task migration and session continuation (ERL=2) * Thin LUN provisioning (UNMAP and WRITE_SAMExx) Multiprotocol target plugins Storage media independence: * Virtualization of all storage media; transparent mapping of IO to LUNs * No hard limits on number of LUNs per Target; maximum LUN size ~750 TB * Backstores: SATA, SAS, SCSI, BluRay, DVD, FLASH, USB, ramdisk, etc. Standards compliance: * Full compliance with IETF (RFC 3720) * Full implementation of SPC-4 PRs and ALUA Significant code cleanups done by Christoph Hellwig. [jejb: fix up for new block bdev exclusive interface. Minor fixes from Randy Dunlap and Dan Carpenter.] Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- Documentation/target/tcm_mod_builder.py | 1094 +++++ Documentation/target/tcm_mod_builder.txt | 145 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/target/Kconfig | 32 + drivers/target/Makefile | 24 + drivers/target/target_core_alua.c | 1991 +++++++++ drivers/target/target_core_alua.h | 126 + drivers/target/target_core_cdb.c | 1131 +++++ drivers/target/target_core_configfs.c | 3225 ++++++++++++++ drivers/target/target_core_device.c | 1694 +++++++ drivers/target/target_core_fabric_configfs.c | 996 +++++ drivers/target/target_core_fabric_lib.c | 451 ++ drivers/target/target_core_file.c | 688 +++ drivers/target/target_core_file.h | 50 + drivers/target/target_core_hba.c | 185 + drivers/target/target_core_hba.h | 7 + drivers/target/target_core_iblock.c | 808 ++++ drivers/target/target_core_iblock.h | 40 + drivers/target/target_core_mib.c | 1078 +++++ drivers/target/target_core_mib.h | 28 + drivers/target/target_core_pr.c | 4252 ++++++++++++++++++ drivers/target/target_core_pr.h | 67 + drivers/target/target_core_pscsi.c | 1470 ++++++ drivers/target/target_core_pscsi.h | 65 + drivers/target/target_core_rd.c | 1091 +++++ drivers/target/target_core_rd.h | 73 + drivers/target/target_core_scdb.c | 105 + drivers/target/target_core_scdb.h | 10 + drivers/target/target_core_tmr.c | 404 ++ drivers/target/target_core_tpg.c | 826 ++++ drivers/target/target_core_transport.c | 6134 ++++++++++++++++++++++++++ drivers/target/target_core_ua.c | 332 ++ drivers/target/target_core_ua.h | 36 + include/target/configfs_macros.h | 147 + include/target/target_core_base.h | 937 ++++ include/target/target_core_configfs.h | 52 + include/target/target_core_device.h | 61 + include/target/target_core_fabric_configfs.h | 106 + include/target/target_core_fabric_lib.h | 28 + include/target/target_core_fabric_ops.h | 100 + include/target/target_core_tmr.h | 43 + include/target/target_core_tpg.h | 35 + include/target/target_core_transport.h | 351 ++ 44 files changed, 30521 insertions(+) create mode 100755 Documentation/target/tcm_mod_builder.py create mode 100644 Documentation/target/tcm_mod_builder.txt create mode 100644 drivers/target/Kconfig create mode 100644 drivers/target/Makefile create mode 100644 drivers/target/target_core_alua.c create mode 100644 drivers/target/target_core_alua.h create mode 100644 drivers/target/target_core_cdb.c create mode 100644 drivers/target/target_core_configfs.c create mode 100644 drivers/target/target_core_device.c create mode 100644 drivers/target/target_core_fabric_configfs.c create mode 100644 drivers/target/target_core_fabric_lib.c create mode 100644 drivers/target/target_core_file.c create mode 100644 drivers/target/target_core_file.h create mode 100644 drivers/target/target_core_hba.c create mode 100644 drivers/target/target_core_hba.h create mode 100644 drivers/target/target_core_iblock.c create mode 100644 drivers/target/target_core_iblock.h create mode 100644 drivers/target/target_core_mib.c create mode 100644 drivers/target/target_core_mib.h create mode 100644 drivers/target/target_core_pr.c create mode 100644 drivers/target/target_core_pr.h create mode 100644 drivers/target/target_core_pscsi.c create mode 100644 drivers/target/target_core_pscsi.h create mode 100644 drivers/target/target_core_rd.c create mode 100644 drivers/target/target_core_rd.h create mode 100644 drivers/target/target_core_scdb.c create mode 100644 drivers/target/target_core_scdb.h create mode 100644 drivers/target/target_core_tmr.c create mode 100644 drivers/target/target_core_tpg.c create mode 100644 drivers/target/target_core_transport.c create mode 100644 drivers/target/target_core_ua.c create mode 100644 drivers/target/target_core_ua.h create mode 100644 include/target/configfs_macros.h create mode 100644 include/target/target_core_base.h create mode 100644 include/target/target_core_configfs.h create mode 100644 include/target/target_core_device.h create mode 100644 include/target/target_core_fabric_configfs.h create mode 100644 include/target/target_core_fabric_lib.h create mode 100644 include/target/target_core_fabric_ops.h create mode 100644 include/target/target_core_tmr.h create mode 100644 include/target/target_core_tpg.h create mode 100644 include/target/target_core_transport.h (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py new file mode 100755 index 000000000000..dbeb8a0d7175 --- /dev/null +++ b/Documentation/target/tcm_mod_builder.py @@ -0,0 +1,1094 @@ +#!/usr/bin/python +# The TCM v4 multi-protocol fabric module generation script for drivers/target/$NEW_MOD +# +# Copyright (c) 2010 Rising Tide Systems +# Copyright (c) 2010 Linux-iSCSI.org +# +# Author: nab@kernel.org +# +import os, sys +import subprocess as sub +import string +import re +import optparse + +tcm_dir = "" + +fabric_ops = [] +fabric_mod_dir = "" +fabric_mod_port = "" +fabric_mod_init_port = "" + +def tcm_mod_err(msg): + print msg + sys.exit(1) + +def tcm_mod_create_module_subdir(fabric_mod_dir_var): + + if os.path.isdir(fabric_mod_dir_var) == True: + return 1 + + print "Creating fabric_mod_dir: " + fabric_mod_dir_var + ret = os.mkdir(fabric_mod_dir_var) + if ret: + tcm_mod_err("Unable to mkdir " + fabric_mod_dir_var) + + return + +def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name): + global fabric_mod_port + global fabric_mod_init_port + buf = "" + + f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h" + print "Writing file: " + f + + p = open(f, 'w'); + if not p: + tcm_mod_err("Unable to open file: " + f) + + buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" + buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" + buf += "\n" + buf += "struct " + fabric_mod_name + "_nacl {\n" + buf += " /* Binary World Wide unique Port Name for FC Initiator Nport */\n" + buf += " u64 nport_wwpn;\n" + buf += " /* ASCII formatted WWPN for FC Initiator Nport */\n" + buf += " char nport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" + buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" + buf += " struct se_node_acl se_node_acl;\n" + buf += "};\n" + buf += "\n" + buf += "struct " + fabric_mod_name + "_tpg {\n" + buf += " /* FC lport target portal group tag for TCM */\n" + buf += " u16 lport_tpgt;\n" + buf += " /* Pointer back to " + fabric_mod_name + "_lport */\n" + buf += " struct " + fabric_mod_name + "_lport *lport;\n" + buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n" + buf += " struct se_portal_group se_tpg;\n" + buf += "};\n" + buf += "\n" + buf += "struct " + fabric_mod_name + "_lport {\n" + buf += " /* SCSI protocol the lport is providing */\n" + buf += " u8 lport_proto_id;\n" + buf += " /* Binary World Wide unique Port Name for FC Target Lport */\n" + buf += " u64 lport_wwpn;\n" + buf += " /* ASCII formatted WWPN for FC Target Lport */\n" + buf += " char lport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" + buf += " /* Returned by " + fabric_mod_name + "_make_lport() */\n" + buf += " struct se_wwn lport_wwn;\n" + buf += "};\n" + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + + fabric_mod_port = "lport" + fabric_mod_init_port = "nport" + + return + +def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name): + global fabric_mod_port + global fabric_mod_init_port + buf = "" + + f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h" + print "Writing file: " + f + + p = open(f, 'w'); + if not p: + tcm_mod_err("Unable to open file: " + f) + + buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" + buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" + buf += "\n" + buf += "struct " + fabric_mod_name + "_nacl {\n" + buf += " /* Binary World Wide unique Port Name for SAS Initiator port */\n" + buf += " u64 iport_wwpn;\n" + buf += " /* ASCII formatted WWPN for Sas Initiator port */\n" + buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" + buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" + buf += " struct se_node_acl se_node_acl;\n" + buf += "};\n\n" + buf += "struct " + fabric_mod_name + "_tpg {\n" + buf += " /* SAS port target portal group tag for TCM */\n" + buf += " u16 tport_tpgt;\n" + buf += " /* Pointer back to " + fabric_mod_name + "_tport */\n" + buf += " struct " + fabric_mod_name + "_tport *tport;\n" + buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n" + buf += " struct se_portal_group se_tpg;\n" + buf += "};\n\n" + buf += "struct " + fabric_mod_name + "_tport {\n" + buf += " /* SCSI protocol the tport is providing */\n" + buf += " u8 tport_proto_id;\n" + buf += " /* Binary World Wide unique Port Name for SAS Target port */\n" + buf += " u64 tport_wwpn;\n" + buf += " /* ASCII formatted WWPN for SAS Target port */\n" + buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" + buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n" + buf += " struct se_wwn tport_wwn;\n" + buf += "};\n" + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + + fabric_mod_port = "tport" + fabric_mod_init_port = "iport" + + return + +def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name): + global fabric_mod_port + global fabric_mod_init_port + buf = "" + + f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h" + print "Writing file: " + f + + p = open(f, 'w'); + if not p: + tcm_mod_err("Unable to open file: " + f) + + buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" + buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" + buf += "\n" + buf += "struct " + fabric_mod_name + "_nacl {\n" + buf += " /* ASCII formatted InitiatorName */\n" + buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" + buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" + buf += " struct se_node_acl se_node_acl;\n" + buf += "};\n\n" + buf += "struct " + fabric_mod_name + "_tpg {\n" + buf += " /* iSCSI target portal group tag for TCM */\n" + buf += " u16 tport_tpgt;\n" + buf += " /* Pointer back to " + fabric_mod_name + "_tport */\n" + buf += " struct " + fabric_mod_name + "_tport *tport;\n" + buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n" + buf += " struct se_portal_group se_tpg;\n" + buf += "};\n\n" + buf += "struct " + fabric_mod_name + "_tport {\n" + buf += " /* SCSI protocol the tport is providing */\n" + buf += " u8 tport_proto_id;\n" + buf += " /* ASCII formatted TargetName for IQN */\n" + buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" + buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n" + buf += " struct se_wwn tport_wwn;\n" + buf += "};\n" + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + + fabric_mod_port = "tport" + fabric_mod_init_port = "iport" + + return + +def tcm_mod_build_base_includes(proto_ident, fabric_mod_dir_val, fabric_mod_name): + + if proto_ident == "FC": + tcm_mod_build_FC_include(fabric_mod_dir_val, fabric_mod_name) + elif proto_ident == "SAS": + tcm_mod_build_SAS_include(fabric_mod_dir_val, fabric_mod_name) + elif proto_ident == "iSCSI": + tcm_mod_build_iSCSI_include(fabric_mod_dir_val, fabric_mod_name) + else: + print "Unsupported proto_ident: " + proto_ident + sys.exit(1) + + return + +def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): + buf = "" + + f = fabric_mod_dir_var + "/" + fabric_mod_name + "_configfs.c" + print "Writing file: " + f + + p = open(f, 'w'); + if not p: + tcm_mod_err("Unable to open file: " + f) + + buf = "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n\n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n\n" + buf += "#include <" + fabric_mod_name + "_base.h>\n" + buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n" + + buf += "/* Local pointer to allocated TCM configfs fabric module */\n" + buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n" + + buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n" + buf += " struct se_portal_group *se_tpg,\n" + buf += " struct config_group *group,\n" + buf += " const char *name)\n" + buf += "{\n" + buf += " struct se_node_acl *se_nacl, *se_nacl_new;\n" + buf += " struct " + fabric_mod_name + "_nacl *nacl;\n" + + if proto_ident == "FC" or proto_ident == "SAS": + buf += " u64 wwpn = 0;\n" + + buf += " u32 nexus_depth;\n\n" + buf += " /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" + buf += " return ERR_PTR(-EINVAL); */\n" + buf += " se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n" + buf += " if (!(se_nacl_new))\n" + buf += " return ERR_PTR(-ENOMEM);\n" + buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n" + buf += " nexus_depth = 1;\n" + buf += " /*\n" + buf += " * se_nacl_new may be released by core_tpg_add_initiator_node_acl()\n" + buf += " * when converting a NodeACL from demo mode -> explict\n" + buf += " */\n" + buf += " se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,\n" + buf += " name, nexus_depth);\n" + buf += " if (IS_ERR(se_nacl)) {\n" + buf += " " + fabric_mod_name + "_release_fabric_acl(se_tpg, se_nacl_new);\n" + buf += " return se_nacl;\n" + buf += " }\n" + buf += " /*\n" + buf += " * Locate our struct " + fabric_mod_name + "_nacl and set the FC Nport WWPN\n" + buf += " */\n" + buf += " nacl = container_of(se_nacl, struct " + fabric_mod_name + "_nacl, se_node_acl);\n" + + if proto_ident == "FC" or proto_ident == "SAS": + buf += " nacl->" + fabric_mod_init_port + "_wwpn = wwpn;\n" + + buf += " /* " + fabric_mod_name + "_format_wwn(&nacl->" + fabric_mod_init_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n" + buf += " return se_nacl;\n" + buf += "}\n\n" + buf += "static void " + fabric_mod_name + "_drop_nodeacl(struct se_node_acl *se_acl)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n" + buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" + buf += " kfree(nacl);\n" + buf += "}\n\n" + + buf += "static struct se_portal_group *" + fabric_mod_name + "_make_tpg(\n" + buf += " struct se_wwn *wwn,\n" + buf += " struct config_group *group,\n" + buf += " const char *name)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + "*" + fabric_mod_port + " = container_of(wwn,\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg;\n" + buf += " unsigned long tpgt;\n" + buf += " int ret;\n\n" + buf += " if (strstr(name, \"tpgt_\") != name)\n" + buf += " return ERR_PTR(-EINVAL);\n" + buf += " if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)\n" + buf += " return ERR_PTR(-EINVAL);\n\n" + buf += " tpg = kzalloc(sizeof(struct " + fabric_mod_name + "_tpg), GFP_KERNEL);\n" + buf += " if (!(tpg)) {\n" + buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_tpg\");\n" + buf += " return ERR_PTR(-ENOMEM);\n" + buf += " }\n" + buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" + buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" + buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n" + buf += " &tpg->se_tpg, (void *)tpg,\n" + buf += " TRANSPORT_TPG_TYPE_NORMAL);\n" + buf += " if (ret < 0) {\n" + buf += " kfree(tpg);\n" + buf += " return NULL;\n" + buf += " }\n" + buf += " return &tpg->se_tpg;\n" + buf += "}\n\n" + buf += "static void " + fabric_mod_name + "_drop_tpg(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n\n" + buf += " core_tpg_deregister(se_tpg);\n" + buf += " kfree(tpg);\n" + buf += "}\n\n" + + buf += "static struct se_wwn *" + fabric_mod_name + "_make_" + fabric_mod_port + "(\n" + buf += " struct target_fabric_configfs *tf,\n" + buf += " struct config_group *group,\n" + buf += " const char *name)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + ";\n" + + if proto_ident == "FC" or proto_ident == "SAS": + buf += " u64 wwpn = 0;\n\n" + + buf += " /* if (" + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" + buf += " return ERR_PTR(-EINVAL); */\n\n" + buf += " " + fabric_mod_port + " = kzalloc(sizeof(struct " + fabric_mod_name + "_" + fabric_mod_port + "), GFP_KERNEL);\n" + buf += " if (!(" + fabric_mod_port + ")) {\n" + buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_" + fabric_mod_port + "\");\n" + buf += " return ERR_PTR(-ENOMEM);\n" + buf += " }\n" + + if proto_ident == "FC" or proto_ident == "SAS": + buf += " " + fabric_mod_port + "->" + fabric_mod_port + "_wwpn = wwpn;\n" + + buf += " /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "__NAMELEN, wwpn); */\n\n" + buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_wwn;\n" + buf += "}\n\n" + buf += "static void " + fabric_mod_name + "_drop_" + fabric_mod_port + "(struct se_wwn *wwn)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = container_of(wwn,\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n" + buf += " kfree(" + fabric_mod_port + ");\n" + buf += "}\n\n" + buf += "static ssize_t " + fabric_mod_name + "_wwn_show_attr_version(\n" + buf += " struct target_fabric_configfs *tf,\n" + buf += " char *page)\n" + buf += "{\n" + buf += " return sprintf(page, \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n" + buf += " \"on \"UTS_RELEASE\"\\n\", " + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n" + buf += " utsname()->machine);\n" + buf += "}\n\n" + buf += "TF_WWN_ATTR_RO(" + fabric_mod_name + ", version);\n\n" + buf += "static struct configfs_attribute *" + fabric_mod_name + "_wwn_attrs[] = {\n" + buf += " &" + fabric_mod_name + "_wwn_version.attr,\n" + buf += " NULL,\n" + buf += "};\n\n" + + buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" + buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" + buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" + buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" + buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" + buf += " .tpg_get_default_depth = " + fabric_mod_name + "_get_default_depth,\n" + buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" + buf += " .tpg_get_pr_transport_id_len = " + fabric_mod_name + "_get_pr_transport_id_len,\n" + buf += " .tpg_parse_pr_out_transport_id = " + fabric_mod_name + "_parse_pr_out_transport_id,\n" + buf += " .tpg_check_demo_mode = " + fabric_mod_name + "_check_false,\n" + buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n" + buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n" + buf += " .tpg_check_prod_mode_write_protect = " + fabric_mod_name + "_check_false,\n" + buf += " .tpg_alloc_fabric_acl = " + fabric_mod_name + "_alloc_fabric_acl,\n" + buf += " .tpg_release_fabric_acl = " + fabric_mod_name + "_release_fabric_acl,\n" + buf += " .tpg_get_inst_index = " + fabric_mod_name + "_tpg_get_inst_index,\n" + buf += " .release_cmd_to_pool = " + fabric_mod_name + "_release_cmd,\n" + buf += " .release_cmd_direct = " + fabric_mod_name + "_release_cmd,\n" + buf += " .shutdown_session = " + fabric_mod_name + "_shutdown_session,\n" + buf += " .close_session = " + fabric_mod_name + "_close_session,\n" + buf += " .stop_session = " + fabric_mod_name + "_stop_session,\n" + buf += " .fall_back_to_erl0 = " + fabric_mod_name + "_reset_nexus,\n" + buf += " .sess_logged_in = " + fabric_mod_name + "_sess_logged_in,\n" + buf += " .sess_get_index = " + fabric_mod_name + "_sess_get_index,\n" + buf += " .sess_get_initiator_sid = NULL,\n" + buf += " .write_pending = " + fabric_mod_name + "_write_pending,\n" + buf += " .write_pending_status = " + fabric_mod_name + "_write_pending_status,\n" + buf += " .set_default_node_attributes = " + fabric_mod_name + "_set_default_node_attrs,\n" + buf += " .get_task_tag = " + fabric_mod_name + "_get_task_tag,\n" + buf += " .get_cmd_state = " + fabric_mod_name + "_get_cmd_state,\n" + buf += " .new_cmd_failure = " + fabric_mod_name + "_new_cmd_failure,\n" + buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n" + buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n" + buf += " .queue_tm_rsp = " + fabric_mod_name + "_queue_tm_rsp,\n" + buf += " .get_fabric_sense_len = " + fabric_mod_name + "_get_fabric_sense_len,\n" + buf += " .set_fabric_sense_len = " + fabric_mod_name + "_set_fabric_sense_len,\n" + buf += " .is_state_remove = " + fabric_mod_name + "_is_state_remove,\n" + buf += " .pack_lun = " + fabric_mod_name + "_pack_lun,\n" + buf += " /*\n" + buf += " * Setup function pointers for generic logic in target_core_fabric_configfs.c\n" + buf += " */\n" + buf += " .fabric_make_wwn = " + fabric_mod_name + "_make_" + fabric_mod_port + ",\n" + buf += " .fabric_drop_wwn = " + fabric_mod_name + "_drop_" + fabric_mod_port + ",\n" + buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n" + buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n" + buf += " .fabric_post_link = NULL,\n" + buf += " .fabric_pre_unlink = NULL,\n" + buf += " .fabric_make_np = NULL,\n" + buf += " .fabric_drop_np = NULL,\n" + buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n" + buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n" + buf += "};\n\n" + + buf += "static int " + fabric_mod_name + "_register_configfs(void)\n" + buf += "{\n" + buf += " struct target_fabric_configfs *fabric;\n" + buf += " int ret;\n\n" + buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n" + buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n" + buf += " utsname()->machine);\n" + buf += " /*\n" + buf += " * Register the top level struct config_item_type with TCM core\n" + buf += " */\n" + buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name[4:] + "\");\n" + buf += " if (!(fabric)) {\n" + buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n" + buf += " return -ENOMEM;\n" + buf += " }\n" + buf += " /*\n" + buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n" + buf += " */\n" + buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n" + buf += " /*\n" + buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n" + buf += " */\n" + buf += " TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n" + buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n" + buf += " /*\n" + buf += " * Register the fabric for use within TCM\n" + buf += " */\n" + buf += " ret = target_fabric_configfs_register(fabric);\n" + buf += " if (ret < 0) {\n" + buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n" + buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n" + buf += " return ret;\n" + buf += " }\n" + buf += " /*\n" + buf += " * Setup our local pointer to *fabric\n" + buf += " */\n" + buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n" + buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n" + buf += " return 0;\n" + buf += "};\n\n" + buf += "static void " + fabric_mod_name + "_deregister_configfs(void)\n" + buf += "{\n" + buf += " if (!(" + fabric_mod_name + "_fabric_configfs))\n" + buf += " return;\n\n" + buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n" + buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n" + buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n" + buf += "};\n\n" + + buf += "static int __init " + fabric_mod_name + "_init(void)\n" + buf += "{\n" + buf += " int ret;\n\n" + buf += " ret = " + fabric_mod_name + "_register_configfs();\n" + buf += " if (ret < 0)\n" + buf += " return ret;\n\n" + buf += " return 0;\n" + buf += "};\n\n" + buf += "static void " + fabric_mod_name + "_exit(void)\n" + buf += "{\n" + buf += " " + fabric_mod_name + "_deregister_configfs();\n" + buf += "};\n\n" + + buf += "#ifdef MODULE\n" + buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" + buf += "MODULE_LICENSE(\"GPL\");\n" + buf += "module_init(" + fabric_mod_name + "_init);\n" + buf += "module_exit(" + fabric_mod_name + "_exit);\n" + buf += "#endif\n" + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + + return + +def tcm_mod_scan_fabric_ops(tcm_dir): + + fabric_ops_api = tcm_dir + "include/target/target_core_fabric_ops.h" + + print "Using tcm_mod_scan_fabric_ops: " + fabric_ops_api + process_fo = 0; + + p = open(fabric_ops_api, 'r') + + line = p.readline() + while line: + if process_fo == 0 and re.search('struct target_core_fabric_ops {', line): + line = p.readline() + continue + + if process_fo == 0: + process_fo = 1; + line = p.readline() + # Search for function pointer + if not re.search('\(\*', line): + continue + + fabric_ops.append(line.rstrip()) + continue + + line = p.readline() + # Search for function pointer + if not re.search('\(\*', line): + continue + + fabric_ops.append(line.rstrip()) + + p.close() + return + +def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): + buf = "" + bufi = "" + + f = fabric_mod_dir_var + "/" + fabric_mod_name + "_fabric.c" + print "Writing file: " + f + + p = open(f, 'w') + if not p: + tcm_mod_err("Unable to open file: " + f) + + fi = fabric_mod_dir_var + "/" + fabric_mod_name + "_fabric.h" + print "Writing file: " + fi + + pi = open(fi, 'w') + if not pi: + tcm_mod_err("Unable to open file: " + fi) + + buf = "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n\n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include \n" + buf += "#include <" + fabric_mod_name + "_base.h>\n" + buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n" + + buf += "int " + fabric_mod_name + "_check_true(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " return 1;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_check_true(struct se_portal_group *);\n" + + buf += "int " + fabric_mod_name + "_check_false(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_check_false(struct se_portal_group *);\n" + + total_fabric_ops = len(fabric_ops) + i = 0 + + while i < total_fabric_ops: + fo = fabric_ops[i] + i += 1 +# print "fabric_ops: " + fo + + if re.search('get_fabric_name', fo): + buf += "char *" + fabric_mod_name + "_get_fabric_name(void)\n" + buf += "{\n" + buf += " return \"" + fabric_mod_name[4:] + "\";\n" + buf += "}\n\n" + bufi += "char *" + fabric_mod_name + "_get_fabric_name(void);\n" + continue + + if re.search('get_fabric_proto_ident', fo): + buf += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" + buf += " u8 proto_id;\n\n" + buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" + if proto_ident == "FC": + buf += " case SCSI_PROTOCOL_FCP:\n" + buf += " default:\n" + buf += " proto_id = fc_get_fabric_proto_ident(se_tpg);\n" + buf += " break;\n" + elif proto_ident == "SAS": + buf += " case SCSI_PROTOCOL_SAS:\n" + buf += " default:\n" + buf += " proto_id = sas_get_fabric_proto_ident(se_tpg);\n" + buf += " break;\n" + elif proto_ident == "iSCSI": + buf += " case SCSI_PROTOCOL_ISCSI:\n" + buf += " default:\n" + buf += " proto_id = iscsi_get_fabric_proto_ident(se_tpg);\n" + buf += " break;\n" + + buf += " }\n\n" + buf += " return proto_id;\n" + buf += "}\n\n" + bufi += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *);\n" + + if re.search('get_wwn', fo): + buf += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n\n" + buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_name[0];\n" + buf += "}\n\n" + bufi += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *);\n" + + if re.search('get_tag', fo): + buf += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" + buf += " return tpg->" + fabric_mod_port + "_tpgt;\n" + buf += "}\n\n" + bufi += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *);\n" + + if re.search('get_default_depth', fo): + buf += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " return 1;\n" + buf += "}\n\n" + bufi += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *);\n" + + if re.search('get_pr_transport_id\)\(', fo): + buf += "u32 " + fabric_mod_name + "_get_pr_transport_id(\n" + buf += " struct se_portal_group *se_tpg,\n" + buf += " struct se_node_acl *se_nacl,\n" + buf += " struct t10_pr_registration *pr_reg,\n" + buf += " int *format_code,\n" + buf += " unsigned char *buf)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" + buf += " int ret = 0;\n\n" + buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" + if proto_ident == "FC": + buf += " case SCSI_PROTOCOL_FCP:\n" + buf += " default:\n" + buf += " ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" + buf += " format_code, buf);\n" + buf += " break;\n" + elif proto_ident == "SAS": + buf += " case SCSI_PROTOCOL_SAS:\n" + buf += " default:\n" + buf += " ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" + buf += " format_code, buf);\n" + buf += " break;\n" + elif proto_ident == "iSCSI": + buf += " case SCSI_PROTOCOL_ISCSI:\n" + buf += " default:\n" + buf += " ret = iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" + buf += " format_code, buf);\n" + buf += " break;\n" + + buf += " }\n\n" + buf += " return ret;\n" + buf += "}\n\n" + bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id(struct se_portal_group *,\n" + bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" + bufi += " int *, unsigned char *);\n" + + if re.search('get_pr_transport_id_len\)\(', fo): + buf += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(\n" + buf += " struct se_portal_group *se_tpg,\n" + buf += " struct se_node_acl *se_nacl,\n" + buf += " struct t10_pr_registration *pr_reg,\n" + buf += " int *format_code)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" + buf += " int ret = 0;\n\n" + buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" + if proto_ident == "FC": + buf += " case SCSI_PROTOCOL_FCP:\n" + buf += " default:\n" + buf += " ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" + buf += " format_code);\n" + buf += " break;\n" + elif proto_ident == "SAS": + buf += " case SCSI_PROTOCOL_SAS:\n" + buf += " default:\n" + buf += " ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" + buf += " format_code);\n" + buf += " break;\n" + elif proto_ident == "iSCSI": + buf += " case SCSI_PROTOCOL_ISCSI:\n" + buf += " default:\n" + buf += " ret = iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" + buf += " format_code);\n" + buf += " break;\n" + + + buf += " }\n\n" + buf += " return ret;\n" + buf += "}\n\n" + bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(struct se_portal_group *,\n" + bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" + bufi += " int *);\n" + + if re.search('parse_pr_out_transport_id\)\(', fo): + buf += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(\n" + buf += " struct se_portal_group *se_tpg,\n" + buf += " const char *buf,\n" + buf += " u32 *out_tid_len,\n" + buf += " char **port_nexus_ptr)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" + buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" + buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" + buf += " char *tid = NULL;\n\n" + buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" + if proto_ident == "FC": + buf += " case SCSI_PROTOCOL_FCP:\n" + buf += " default:\n" + buf += " tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" + buf += " port_nexus_ptr);\n" + elif proto_ident == "SAS": + buf += " case SCSI_PROTOCOL_SAS:\n" + buf += " default:\n" + buf += " tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" + buf += " port_nexus_ptr);\n" + elif proto_ident == "iSCSI": + buf += " case SCSI_PROTOCOL_ISCSI:\n" + buf += " default:\n" + buf += " tid = iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" + buf += " port_nexus_ptr);\n" + + buf += " }\n\n" + buf += " return tid;\n" + buf += "}\n\n" + bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n" + bufi += " const char *, u32 *, char **);\n" + + if re.search('alloc_fabric_acl\)\(', fo): + buf += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_nacl *nacl;\n\n" + buf += " nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n" + buf += " if (!(nacl)) {\n" + buf += " printk(KERN_ERR \"Unable to alocate struct " + fabric_mod_name + "_nacl\\n\");\n" + buf += " return NULL;\n" + buf += " }\n\n" + buf += " return &nacl->se_node_acl;\n" + buf += "}\n\n" + bufi += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *);\n" + + if re.search('release_fabric_acl\)\(', fo): + buf += "void " + fabric_mod_name + "_release_fabric_acl(\n" + buf += " struct se_portal_group *se_tpg,\n" + buf += " struct se_node_acl *se_nacl)\n" + buf += "{\n" + buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_nacl,\n" + buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" + buf += " kfree(nacl);\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_release_fabric_acl(struct se_portal_group *,\n" + bufi += " struct se_node_acl *);\n" + + if re.search('tpg_get_inst_index\)\(', fo): + buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n" + buf += "{\n" + buf += " return 1;\n" + buf += "}\n\n" + bufi += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *);\n" + + if re.search('release_cmd_to_pool', fo): + buf += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return;\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *);\n" + + if re.search('shutdown_session\)\(', fo): + buf += "int " + fabric_mod_name + "_shutdown_session(struct se_session *se_sess)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_shutdown_session(struct se_session *);\n" + + if re.search('close_session\)\(', fo): + buf += "void " + fabric_mod_name + "_close_session(struct se_session *se_sess)\n" + buf += "{\n" + buf += " return;\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_close_session(struct se_session *);\n" + + if re.search('stop_session\)\(', fo): + buf += "void " + fabric_mod_name + "_stop_session(struct se_session *se_sess, int sess_sleep , int conn_sleep)\n" + buf += "{\n" + buf += " return;\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_stop_session(struct se_session *, int, int);\n" + + if re.search('fall_back_to_erl0\)\(', fo): + buf += "void " + fabric_mod_name + "_reset_nexus(struct se_session *se_sess)\n" + buf += "{\n" + buf += " return;\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_reset_nexus(struct se_session *);\n" + + if re.search('sess_logged_in\)\(', fo): + buf += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *se_sess)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *);\n" + + if re.search('sess_get_index\)\(', fo): + buf += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *se_sess)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *);\n" + + if re.search('write_pending\)\(', fo): + buf += "int " + fabric_mod_name + "_write_pending(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_write_pending(struct se_cmd *);\n" + + if re.search('write_pending_status\)\(', fo): + buf += "int " + fabric_mod_name + "_write_pending_status(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_write_pending_status(struct se_cmd *);\n" + + if re.search('set_default_node_attributes\)\(', fo): + buf += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *nacl)\n" + buf += "{\n" + buf += " return;\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *);\n" + + if re.search('get_task_tag\)\(', fo): + buf += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *);\n" + + if re.search('get_cmd_state\)\(', fo): + buf += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *);\n" + + if re.search('new_cmd_failure\)\(', fo): + buf += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return;\n" + buf += "}\n\n" + bufi += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *);\n" + + if re.search('queue_data_in\)\(', fo): + buf += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *);\n" + + if re.search('queue_status\)\(', fo): + buf += "int " + fabric_mod_name + "_queue_status(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_queue_status(struct se_cmd *);\n" + + if re.search('queue_tm_rsp\)\(', fo): + buf += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n" + + if re.search('get_fabric_sense_len\)\(', fo): + buf += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void);\n" + + if re.search('set_fabric_sense_len\)\(', fo): + buf += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *, u32);\n" + + if re.search('is_state_remove\)\(', fo): + buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n" + buf += "{\n" + buf += " return 0;\n" + buf += "}\n\n" + bufi += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *);\n" + + if re.search('pack_lun\)\(', fo): + buf += "u64 " + fabric_mod_name + "_pack_lun(unsigned int lun)\n" + buf += "{\n" + buf += " WARN_ON(lun >= 256);\n" + buf += " /* Caller wants this byte-swapped */\n" + buf += " return cpu_to_le64((lun & 0xff) << 8);\n" + buf += "}\n\n" + bufi += "u64 " + fabric_mod_name + "_pack_lun(unsigned int);\n" + + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + + ret = pi.write(bufi) + if ret: + tcm_mod_err("Unable to write fi: " + fi) + + pi.close() + return + +def tcm_mod_build_kbuild(fabric_mod_dir_var, fabric_mod_name): + + buf = "" + f = fabric_mod_dir_var + "/Kbuild" + print "Writing file: " + f + + p = open(f, 'w') + if not p: + tcm_mod_err("Unable to open file: " + f) + + buf = "EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/include/ -I$(srctree)/drivers/scsi/ -I$(srctree)/include/scsi/ -I$(srctree)/drivers/target/" + fabric_mod_name + "\n\n" + buf += fabric_mod_name + "-objs := " + fabric_mod_name + "_fabric.o \\\n" + buf += " " + fabric_mod_name + "_configfs.o\n" + buf += "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name + ".o\n" + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + return + +def tcm_mod_build_kconfig(fabric_mod_dir_var, fabric_mod_name): + + buf = "" + f = fabric_mod_dir_var + "/Kconfig" + print "Writing file: " + f + + p = open(f, 'w') + if not p: + tcm_mod_err("Unable to open file: " + f) + + buf = "config " + fabric_mod_name.upper() + "\n" + buf += " tristate \"" + fabric_mod_name.upper() + " fabric module\"\n" + buf += " depends on TARGET_CORE && CONFIGFS_FS\n" + buf += " default n\n" + buf += " ---help---\n" + buf += " Say Y here to enable the " + fabric_mod_name.upper() + " fabric module\n" + + ret = p.write(buf) + if ret: + tcm_mod_err("Unable to write f: " + f) + + p.close() + return + +def tcm_mod_add_kbuild(tcm_dir, fabric_mod_name): + buf = "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name.lower() + "/\n" + kbuild = tcm_dir + "/drivers/target/Kbuild" + + f = open(kbuild, 'a') + f.write(buf) + f.close() + return + +def tcm_mod_add_kconfig(tcm_dir, fabric_mod_name): + buf = "source \"drivers/target/" + fabric_mod_name.lower() + "/Kconfig\"\n" + kconfig = tcm_dir + "/drivers/target/Kconfig" + + f = open(kconfig, 'a') + f.write(buf) + f.close() + return + +def main(modname, proto_ident): +# proto_ident = "FC" +# proto_ident = "SAS" +# proto_ident = "iSCSI" + + tcm_dir = os.getcwd(); + tcm_dir += "/../../" + print "tcm_dir: " + tcm_dir + fabric_mod_name = modname + fabric_mod_dir = tcm_dir + "drivers/target/" + fabric_mod_name + print "Set fabric_mod_name: " + fabric_mod_name + print "Set fabric_mod_dir: " + fabric_mod_dir + print "Using proto_ident: " + proto_ident + + if proto_ident != "FC" and proto_ident != "SAS" and proto_ident != "iSCSI": + print "Unsupported proto_ident: " + proto_ident + sys.exit(1) + + ret = tcm_mod_create_module_subdir(fabric_mod_dir) + if ret: + print "tcm_mod_create_module_subdir() failed because module already exists!" + sys.exit(1) + + tcm_mod_build_base_includes(proto_ident, fabric_mod_dir, fabric_mod_name) + tcm_mod_scan_fabric_ops(tcm_dir) + tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir, fabric_mod_name) + tcm_mod_build_configfs(proto_ident, fabric_mod_dir, fabric_mod_name) + tcm_mod_build_kbuild(fabric_mod_dir, fabric_mod_name) + tcm_mod_build_kconfig(fabric_mod_dir, fabric_mod_name) + + input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kbuild..? [yes,no]: ") + if input == "yes" or input == "y": + tcm_mod_add_kbuild(tcm_dir, fabric_mod_name) + + input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kconfig..? [yes,no]: ") + if input == "yes" or input == "y": + tcm_mod_add_kconfig(tcm_dir, fabric_mod_name) + + return + +parser = optparse.OptionParser() +parser.add_option('-m', '--modulename', help='Module name', dest='modname', + action='store', nargs=1, type='string') +parser.add_option('-p', '--protoident', help='Protocol Ident', dest='protoident', + action='store', nargs=1, type='string') + +(opts, args) = parser.parse_args() + +mandatories = ['modname', 'protoident'] +for m in mandatories: + if not opts.__dict__[m]: + print "mandatory option is missing\n" + parser.print_help() + exit(-1) + +if __name__ == "__main__": + + main(str(opts.modname), opts.protoident) diff --git a/Documentation/target/tcm_mod_builder.txt b/Documentation/target/tcm_mod_builder.txt new file mode 100644 index 000000000000..84533d8e747f --- /dev/null +++ b/Documentation/target/tcm_mod_builder.txt @@ -0,0 +1,145 @@ +>>>>>>>>>> The TCM v4 fabric module script generator <<<<<<<<<< + +Greetings all, + +This document is intended to be a mini-HOWTO for using the tcm_mod_builder.py +script to generate a brand new functional TCM v4 fabric .ko module of your very own, +that once built can be immediately be loaded to start access the new TCM/ConfigFS +fabric skeleton, by simply using: + + modprobe $TCM_NEW_MOD + mkdir -p /sys/kernel/config/target/$TCM_NEW_MOD + +This script will create a new drivers/target/$TCM_NEW_MOD/, and will do the following + + *) Generate new API callers for drivers/target/target_core_fabric_configs.c logic + ->make_nodeacl(), ->drop_nodeacl(), ->make_tpg(), ->drop_tpg() + ->make_wwn(), ->drop_wwn(). These are created into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c + *) Generate basic infrastructure for loading/unloading LKMs and TCM/ConfigFS fabric module + using a skeleton struct target_core_fabric_ops API template. + *) Based on user defined T10 Proto_Ident for the new fabric module being built, + the TransportID / Initiator and Target WWPN related handlers for + SPC-3 persistent reservation are automatically generated in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c + using drivers/target/target_core_fabric_lib.c logic. + *) NOP API calls for all other Data I/O path and fabric dependent attribute logic + in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c + +tcm_mod_builder.py depends upon the mandatory '-p $PROTO_IDENT' and '-m +$FABRIC_MOD_name' parameters, and actually running the script looks like: + +target:/mnt/sdb/lio-core-2.6.git/Documentation/target# python tcm_mod_builder.py -p iSCSI -m tcm_nab5000 +tcm_dir: /mnt/sdb/lio-core-2.6.git/Documentation/target/../../ +Set fabric_mod_name: tcm_nab5000 +Set fabric_mod_dir: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000 +Using proto_ident: iSCSI +Creating fabric_mod_dir: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000 +Writing file: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_base.h +Using tcm_mod_scan_fabric_ops: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../include/target/target_core_fabric_ops.h +Writing file: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.c +Writing file: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.h +Writing file: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_configfs.c +Writing file: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kbuild +Writing file: +/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kconfig +Would you like to add tcm_nab5000to drivers/target/Kbuild..? [yes,no]: yes +Would you like to add tcm_nab5000to drivers/target/Kconfig..? [yes,no]: yes + +At the end of tcm_mod_builder.py. the script will ask to add the following +line to drivers/target/Kbuild: + + obj-$(CONFIG_TCM_NAB5000) += tcm_nab5000/ + +and the same for drivers/target/Kconfig: + + source "drivers/target/tcm_nab5000/Kconfig" + +*) Run 'make menuconfig' and select the new CONFIG_TCM_NAB5000 item: + + TCM_NAB5000 fabric module + +*) Build using 'make modules', once completed you will have: + +target:/mnt/sdb/lio-core-2.6.git# ls -la drivers/target/tcm_nab5000/ +total 1348 +drwxr-xr-x 2 root root 4096 2010-10-05 03:23 . +drwxr-xr-x 9 root root 4096 2010-10-05 03:22 .. +-rw-r--r-- 1 root root 282 2010-10-05 03:22 Kbuild +-rw-r--r-- 1 root root 171 2010-10-05 03:22 Kconfig +-rw-r--r-- 1 root root 49 2010-10-05 03:23 modules.order +-rw-r--r-- 1 root root 738 2010-10-05 03:22 tcm_nab5000_base.h +-rw-r--r-- 1 root root 9096 2010-10-05 03:22 tcm_nab5000_configfs.c +-rw-r--r-- 1 root root 191200 2010-10-05 03:23 tcm_nab5000_configfs.o +-rw-r--r-- 1 root root 40504 2010-10-05 03:23 .tcm_nab5000_configfs.o.cmd +-rw-r--r-- 1 root root 5414 2010-10-05 03:22 tcm_nab5000_fabric.c +-rw-r--r-- 1 root root 2016 2010-10-05 03:22 tcm_nab5000_fabric.h +-rw-r--r-- 1 root root 190932 2010-10-05 03:23 tcm_nab5000_fabric.o +-rw-r--r-- 1 root root 40713 2010-10-05 03:23 .tcm_nab5000_fabric.o.cmd +-rw-r--r-- 1 root root 401861 2010-10-05 03:23 tcm_nab5000.ko +-rw-r--r-- 1 root root 265 2010-10-05 03:23 .tcm_nab5000.ko.cmd +-rw-r--r-- 1 root root 459 2010-10-05 03:23 tcm_nab5000.mod.c +-rw-r--r-- 1 root root 23896 2010-10-05 03:23 tcm_nab5000.mod.o +-rw-r--r-- 1 root root 22655 2010-10-05 03:23 .tcm_nab5000.mod.o.cmd +-rw-r--r-- 1 root root 379022 2010-10-05 03:23 tcm_nab5000.o +-rw-r--r-- 1 root root 211 2010-10-05 03:23 .tcm_nab5000.o.cmd + +*) Load the new module, create a lun_0 configfs group, and add new TCM Core + IBLOCK backstore symlink to port: + +target:/mnt/sdb/lio-core-2.6.git# insmod drivers/target/tcm_nab5000.ko +target:/mnt/sdb/lio-core-2.6.git# mkdir -p /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0 +target:/mnt/sdb/lio-core-2.6.git# cd /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0/ +target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# ln -s /sys/kernel/config/target/core/iblock_0/lvm_test0 nab5000_port + +target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# cd - +target:/mnt/sdb/lio-core-2.6.git# tree /sys/kernel/config/target/nab5000/ +/sys/kernel/config/target/nab5000/ +|-- discovery_auth +|-- iqn.foo +| `-- tpgt_1 +| |-- acls +| |-- attrib +| |-- lun +| | `-- lun_0 +| | |-- alua_tg_pt_gp +| | |-- alua_tg_pt_offline +| | |-- alua_tg_pt_status +| | |-- alua_tg_pt_write_md +| | `-- nab5000_port -> ../../../../../../target/core/iblock_0/lvm_test0 +| |-- np +| `-- param +`-- version + +target:/mnt/sdb/lio-core-2.6.git# lsmod +Module Size Used by +tcm_nab5000 3935 4 +iscsi_target_mod 193211 0 +target_core_stgt 8090 0 +target_core_pscsi 11122 1 +target_core_file 9172 2 +target_core_iblock 9280 1 +target_core_mod 228575 31 +tcm_nab5000,iscsi_target_mod,target_core_stgt,target_core_pscsi,target_core_file,target_core_iblock +libfc 73681 0 +scsi_debug 56265 0 +scsi_tgt 8666 1 target_core_stgt +configfs 20644 2 target_core_mod + +---------------------------------------------------------------------- + +Future TODO items: + + *) Add more T10 proto_idents + *) Make tcm_mod_dump_fabric_ops() smarter and generate function pointer + defs directly from include/target/target_core_fabric_ops.h:struct target_core_fabric_ops + structure members. + +October 5th, 2010 +Nicholas A. Bellinger diff --git a/drivers/Kconfig b/drivers/Kconfig index dd0a5b5e9bf3..9bfb71ff3a6a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -26,6 +26,8 @@ source "drivers/ata/Kconfig" source "drivers/md/Kconfig" +source "drivers/target/Kconfig" + source "drivers/message/fusion/Kconfig" source "drivers/firewire/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index ef5132469f58..7eb35f479461 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -46,6 +46,7 @@ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ obj-$(CONFIG_SCSI) += scsi/ obj-$(CONFIG_ATA) += ata/ +obj-$(CONFIG_TARGET_CORE) += target/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_SPI) += spi/ obj-y += net/ diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig new file mode 100644 index 000000000000..2fac3be209ac --- /dev/null +++ b/drivers/target/Kconfig @@ -0,0 +1,32 @@ + +menuconfig TARGET_CORE + tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure" + depends on SCSI && BLOCK + select CONFIGFS_FS + default n + help + Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled + control path for target_core_mod. This includes built-in TCM RAMDISK + subsystem logic for virtual LUN 0 access + +if TARGET_CORE + +config TCM_IBLOCK + tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK" + help + Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered + access to Linux/Block devices using BIO + +config TCM_FILEIO + tristate "TCM/FILEIO Subsystem Plugin for Linux/VFS" + help + Say Y here to enable the TCM/FILEIO subsystem plugin for buffered + access to Linux/VFS struct file or struct block_device + +config TCM_PSCSI + tristate "TCM/pSCSI Subsystem Plugin for Linux/SCSI" + help + Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered + passthrough access to Linux/SCSI device + +endif diff --git a/drivers/target/Makefile b/drivers/target/Makefile new file mode 100644 index 000000000000..5cfd70819f08 --- /dev/null +++ b/drivers/target/Makefile @@ -0,0 +1,24 @@ +EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/ + +target_core_mod-y := target_core_configfs.o \ + target_core_device.o \ + target_core_fabric_configfs.o \ + target_core_fabric_lib.o \ + target_core_hba.o \ + target_core_pr.o \ + target_core_alua.o \ + target_core_scdb.o \ + target_core_tmr.o \ + target_core_tpg.o \ + target_core_transport.o \ + target_core_cdb.o \ + target_core_ua.o \ + target_core_rd.o \ + target_core_mib.o + +obj-$(CONFIG_TARGET_CORE) += target_core_mod.o + +# Subsystem modules +obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o +obj-$(CONFIG_TCM_FILEIO) += target_core_file.o +obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c new file mode 100644 index 000000000000..2c5fcfed5934 --- /dev/null +++ b/drivers/target/target_core_alua.c @@ -0,0 +1,1991 @@ +/******************************************************************************* + * Filename: target_core_alua.c + * + * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA) + * + * Copyright (c) 2009-2010 Rising Tide Systems + * Copyright (c) 2009-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 + +#include "target_core_alua.h" +#include "target_core_hba.h" +#include "target_core_ua.h" + +static int core_alua_check_transition(int state, int *primary); +static int core_alua_set_tg_pt_secondary_state( + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, + struct se_port *port, int explict, int offline); + +/* + * REPORT_TARGET_PORT_GROUPS + * + * See spc4r17 section 6.27 + */ +int core_emulate_report_target_port_groups(struct se_cmd *cmd) +{ + struct se_subsystem_dev *su_dev = SE_DEV(cmd)->se_sub_dev; + struct se_port *port; + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first + Target port group descriptor */ + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list, + tg_pt_gp_list) { + /* + * PREF: Preferred target port bit, determine if this + * bit should be set for port group. + */ + if (tg_pt_gp->tg_pt_gp_pref) + buf[off] = 0x80; + /* + * Set the ASYMMETRIC ACCESS State + */ + buf[off++] |= (atomic_read( + &tg_pt_gp->tg_pt_gp_alua_access_state) & 0xff); + /* + * Set supported ASYMMETRIC ACCESS State bits + */ + buf[off] = 0x80; /* T_SUP */ + buf[off] |= 0x40; /* O_SUP */ + buf[off] |= 0x8; /* U_SUP */ + buf[off] |= 0x4; /* S_SUP */ + buf[off] |= 0x2; /* AN_SUP */ + buf[off++] |= 0x1; /* AO_SUP */ + /* + * TARGET PORT GROUP + */ + buf[off++] = ((tg_pt_gp->tg_pt_gp_id >> 8) & 0xff); + buf[off++] = (tg_pt_gp->tg_pt_gp_id & 0xff); + + off++; /* Skip over Reserved */ + /* + * STATUS CODE + */ + buf[off++] = (tg_pt_gp->tg_pt_gp_alua_access_status & 0xff); + /* + * Vendor Specific field + */ + buf[off++] = 0x00; + /* + * TARGET PORT COUNT + */ + buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff); + rd_len += 8; + + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, + tg_pt_gp_mem_list) { + port = tg_pt_gp_mem->tg_pt; + /* + * Start Target Port descriptor format + * + * See spc4r17 section 6.2.7 Table 247 + */ + off += 2; /* Skip over Obsolete */ + /* + * Set RELATIVE TARGET PORT IDENTIFIER + */ + buf[off++] = ((port->sep_rtpi >> 8) & 0xff); + buf[off++] = (port->sep_rtpi & 0xff); + rd_len += 4; + } + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + } + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + /* + * Set the RETURN DATA LENGTH set in the header of the DataIN Payload + */ + buf[0] = ((rd_len >> 24) & 0xff); + buf[1] = ((rd_len >> 16) & 0xff); + buf[2] = ((rd_len >> 8) & 0xff); + buf[3] = (rd_len & 0xff); + + return 0; +} + +/* + * SET_TARGET_PORT_GROUPS for explict ALUA operation. + * + * See spc4r17 section 6.35 + */ +int core_emulate_set_target_port_groups(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_subsystem_dev *su_dev = SE_DEV(cmd)->se_sub_dev; + struct se_port *port, *l_port = SE_LUN(cmd)->lun_sep; + struct se_node_acl *nacl = SE_SESS(cmd)->se_node_acl; + struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + unsigned char *ptr = &buf[4]; /* Skip over RESERVED area in header */ + u32 len = 4; /* Skip over RESERVED area in header */ + int alua_access_state, primary = 0, rc; + u16 tg_pt_id, rtpi; + + if (!(l_port)) + return PYX_TRANSPORT_LU_COMM_FAILURE; + /* + * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed + * for the local tg_pt_gp. + */ + l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; + if (!(l_tg_pt_gp_mem)) { + printk(KERN_ERR "Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); + l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp; + if (!(l_tg_pt_gp)) { + spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); + printk(KERN_ERR "Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA); + spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); + + if (!(rc)) { + printk(KERN_INFO "Unable to process SET_TARGET_PORT_GROUPS" + " while TPGS_EXPLICT_ALUA is disabled\n"); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + while (len < cmd->data_length) { + alua_access_state = (ptr[0] & 0x0f); + /* + * Check the received ALUA access state, and determine if + * the state is a primary or secondary target port asymmetric + * access state. + */ + rc = core_alua_check_transition(alua_access_state, &primary); + if (rc != 0) { + /* + * If the SET TARGET PORT GROUPS attempts to establish + * an invalid combination of target port asymmetric + * access states or attempts to establish an + * unsupported target port asymmetric access state, + * then the command shall be terminated with CHECK + * CONDITION status, with the sense key set to ILLEGAL + * REQUEST, and the additional sense code set to INVALID + * FIELD IN PARAMETER LIST. + */ + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + rc = -1; + /* + * If the ASYMMETRIC ACCESS STATE field (see table 267) + * specifies a primary target port asymmetric access state, + * then the TARGET PORT GROUP OR TARGET PORT field specifies + * a primary target port group for which the primary target + * port asymmetric access state shall be changed. If the + * ASYMMETRIC ACCESS STATE field specifies a secondary target + * port asymmetric access state, then the TARGET PORT GROUP OR + * TARGET PORT field specifies the relative target port + * identifier (see 3.1.120) of the target port for which the + * secondary target port asymmetric access state shall be + * changed. + */ + if (primary) { + tg_pt_id = ((ptr[2] << 8) & 0xff); + tg_pt_id |= (ptr[3] & 0xff); + /* + * Locate the matching target port group ID from + * the global tg_pt_gp list + */ + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, + &T10_ALUA(su_dev)->tg_pt_gps_list, + tg_pt_gp_list) { + if (!(tg_pt_gp->tg_pt_gp_valid_id)) + continue; + + if (tg_pt_id != tg_pt_gp->tg_pt_gp_id) + continue; + + atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); + smp_mb__after_atomic_inc(); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + + rc = core_alua_do_port_transition(tg_pt_gp, + dev, l_port, nacl, + alua_access_state, 1); + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); + smp_mb__after_atomic_dec(); + break; + } + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + /* + * If not matching target port group ID can be located + * throw an exception with ASCQ: INVALID_PARAMETER_LIST + */ + if (rc != 0) + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } else { + /* + * Extact the RELATIVE TARGET PORT IDENTIFIER to identify + * the Target Port in question for the the incoming + * SET_TARGET_PORT_GROUPS op. + */ + rtpi = ((ptr[2] << 8) & 0xff); + rtpi |= (ptr[3] & 0xff); + /* + * Locate the matching relative target port identifer + * for the struct se_device storage object. + */ + spin_lock(&dev->se_port_lock); + list_for_each_entry(port, &dev->dev_sep_list, + sep_list) { + if (port->sep_rtpi != rtpi) + continue; + + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + spin_unlock(&dev->se_port_lock); + + rc = core_alua_set_tg_pt_secondary_state( + tg_pt_gp_mem, port, 1, 1); + + spin_lock(&dev->se_port_lock); + break; + } + spin_unlock(&dev->se_port_lock); + /* + * If not matching relative target port identifier can + * be located, throw an exception with ASCQ: + * INVALID_PARAMETER_LIST + */ + if (rc != 0) + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + + ptr += 4; + len += 4; + } + + return 0; +} + +static inline int core_alua_state_nonoptimized( + struct se_cmd *cmd, + unsigned char *cdb, + int nonop_delay_msecs, + u8 *alua_ascq) +{ + /* + * Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked + * later to determine if processing of this cmd needs to be + * temporarily delayed for the Active/NonOptimized primary access state. + */ + cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED; + cmd->alua_nonop_delay = nonop_delay_msecs; + return 0; +} + +static inline int core_alua_state_standby( + struct se_cmd *cmd, + unsigned char *cdb, + u8 *alua_ascq) +{ + /* + * Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by + * spc4r17 section 5.9.2.4.4 + */ + switch (cdb[0]) { + case INQUIRY: + case LOG_SELECT: + case LOG_SENSE: + case MODE_SELECT: + case MODE_SENSE: + case REPORT_LUNS: + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: + case MAINTENANCE_IN: + switch (cdb[1]) { + case MI_REPORT_TARGET_PGS: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + return 1; + } + case MAINTENANCE_OUT: + switch (cdb[1]) { + case MO_SET_TARGET_PGS: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + return 1; + } + case REQUEST_SENSE: + case PERSISTENT_RESERVE_IN: + case PERSISTENT_RESERVE_OUT: + case READ_BUFFER: + case WRITE_BUFFER: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY; + return 1; + } + + return 0; +} + +static inline int core_alua_state_unavailable( + struct se_cmd *cmd, + unsigned char *cdb, + u8 *alua_ascq) +{ + /* + * Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by + * spc4r17 section 5.9.2.4.5 + */ + switch (cdb[0]) { + case INQUIRY: + case REPORT_LUNS: + case MAINTENANCE_IN: + switch (cdb[1]) { + case MI_REPORT_TARGET_PGS: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + return 1; + } + case MAINTENANCE_OUT: + switch (cdb[1]) { + case MO_SET_TARGET_PGS: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + return 1; + } + case REQUEST_SENSE: + case READ_BUFFER: + case WRITE_BUFFER: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE; + return 1; + } + + return 0; +} + +static inline int core_alua_state_transition( + struct se_cmd *cmd, + unsigned char *cdb, + u8 *alua_ascq) +{ + /* + * Allowed CDBs for ALUA_ACCESS_STATE_TRANSITIO as defined by + * spc4r17 section 5.9.2.5 + */ + switch (cdb[0]) { + case INQUIRY: + case REPORT_LUNS: + case MAINTENANCE_IN: + switch (cdb[1]) { + case MI_REPORT_TARGET_PGS: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION; + return 1; + } + case REQUEST_SENSE: + case READ_BUFFER: + case WRITE_BUFFER: + return 0; + default: + *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION; + return 1; + } + + return 0; +} + +/* + * Used for alua_type SPC_ALUA_PASSTHROUGH and SPC2_ALUA_DISABLED + * in transport_cmd_sequencer(). This function is assigned to + * struct t10_alua *->state_check() in core_setup_alua() + */ +static int core_alua_state_check_nop( + struct se_cmd *cmd, + unsigned char *cdb, + u8 *alua_ascq) +{ + return 0; +} + +/* + * Used for alua_type SPC3_ALUA_EMULATED in transport_cmd_sequencer(). + * This function is assigned to struct t10_alua *->state_check() in + * core_setup_alua() + * + * Also, this function can return three different return codes to + * signal transport_generic_cmd_sequencer() + * + * return 1: Is used to signal LUN not accecsable, and check condition/not ready + * return 0: Used to signal success + * reutrn -1: Used to signal failure, and invalid cdb field + */ +static int core_alua_state_check( + struct se_cmd *cmd, + unsigned char *cdb, + u8 *alua_ascq) +{ + struct se_lun *lun = SE_LUN(cmd); + struct se_port *port = lun->lun_sep; + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + int out_alua_state, nonop_delay_msecs; + + if (!(port)) + return 0; + /* + * First, check for a struct se_port specific secondary ALUA target port + * access state: OFFLINE + */ + if (atomic_read(&port->sep_tg_pt_secondary_offline)) { + *alua_ascq = ASCQ_04H_ALUA_OFFLINE; + printk(KERN_INFO "ALUA: Got secondary offline status for local" + " target port\n"); + *alua_ascq = ASCQ_04H_ALUA_OFFLINE; + return 1; + } + /* + * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the + * ALUA target port group, to obtain current ALUA access state. + * Otherwise look for the underlying struct se_device association with + * a ALUA logical unit group. + */ + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); + nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + /* + * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a seperate conditional + * statement so the complier knows explictly to check this case first. + * For the Optimized ALUA access state case, we want to process the + * incoming fabric cmd ASAP.. + */ + if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTMIZED) + return 0; + + switch (out_alua_state) { + case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: + return core_alua_state_nonoptimized(cmd, cdb, + nonop_delay_msecs, alua_ascq); + case ALUA_ACCESS_STATE_STANDBY: + return core_alua_state_standby(cmd, cdb, alua_ascq); + case ALUA_ACCESS_STATE_UNAVAILABLE: + return core_alua_state_unavailable(cmd, cdb, alua_ascq); + case ALUA_ACCESS_STATE_TRANSITION: + return core_alua_state_transition(cmd, cdb, alua_ascq); + /* + * OFFLINE is a secondary ALUA target port group access state, that is + * handled above with struct se_port->sep_tg_pt_secondary_offline=1 + */ + case ALUA_ACCESS_STATE_OFFLINE: + default: + printk(KERN_ERR "Unknown ALUA access state: 0x%02x\n", + out_alua_state); + return -1; + } + + return 0; +} + +/* + * Check implict and explict ALUA state change request. + */ +static int core_alua_check_transition(int state, int *primary) +{ + switch (state) { + case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED: + case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: + case ALUA_ACCESS_STATE_STANDBY: + case ALUA_ACCESS_STATE_UNAVAILABLE: + /* + * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are + * defined as primary target port asymmetric access states. + */ + *primary = 1; + break; + case ALUA_ACCESS_STATE_OFFLINE: + /* + * OFFLINE state is defined as a secondary target port + * asymmetric access state. + */ + *primary = 0; + break; + default: + printk(KERN_ERR "Unknown ALUA access state: 0x%02x\n", state); + return -1; + } + + return 0; +} + +static char *core_alua_dump_state(int state) +{ + switch (state) { + case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED: + return "Active/Optimized"; + case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED: + return "Active/NonOptimized"; + case ALUA_ACCESS_STATE_STANDBY: + return "Standby"; + case ALUA_ACCESS_STATE_UNAVAILABLE: + return "Unavailable"; + case ALUA_ACCESS_STATE_OFFLINE: + return "Offline"; + default: + return "Unknown"; + } + + return NULL; +} + +char *core_alua_dump_status(int status) +{ + switch (status) { + case ALUA_STATUS_NONE: + return "None"; + case ALUA_STATUS_ALTERED_BY_EXPLICT_STPG: + return "Altered by Explict STPG"; + case ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA: + return "Altered by Implict ALUA"; + default: + return "Unknown"; + } + + return NULL; +} + +/* + * Used by fabric modules to determine when we need to delay processing + * for the Active/NonOptimized paths.. + */ +int core_alua_check_nonop_delay( + struct se_cmd *cmd) +{ + if (!(cmd->se_cmd_flags & SCF_ALUA_NON_OPTIMIZED)) + return 0; + if (in_interrupt()) + return 0; + /* + * The ALUA Active/NonOptimized access state delay can be disabled + * in via configfs with a value of zero + */ + if (!(cmd->alua_nonop_delay)) + return 0; + /* + * struct se_cmd->alua_nonop_delay gets set by a target port group + * defined interval in core_alua_state_nonoptimized() + */ + msleep_interruptible(cmd->alua_nonop_delay); + return 0; +} +EXPORT_SYMBOL(core_alua_check_nonop_delay); + +/* + * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex + * + */ +static int core_alua_write_tpg_metadata( + const char *path, + unsigned char *md_buf, + u32 md_buf_len) +{ + mm_segment_t old_fs; + struct file *file; + struct iovec iov[1]; + int flags = O_RDWR | O_CREAT | O_TRUNC, ret; + + memset(iov, 0, sizeof(struct iovec)); + + file = filp_open(path, flags, 0600); + if (IS_ERR(file) || !file || !file->f_dentry) { + printk(KERN_ERR "filp_open(%s) for ALUA metadata failed\n", + path); + return -ENODEV; + } + + iov[0].iov_base = &md_buf[0]; + iov[0].iov_len = md_buf_len; + + old_fs = get_fs(); + set_fs(get_ds()); + ret = vfs_writev(file, &iov[0], 1, &file->f_pos); + set_fs(old_fs); + + if (ret < 0) { + printk(KERN_ERR "Error writing ALUA metadata file: %s\n", path); + filp_close(file, NULL); + return -EIO; + } + filp_close(file, NULL); + + return 0; +} + +/* + * Called with tg_pt_gp->tg_pt_gp_md_mutex held + */ +static int core_alua_update_tpg_primary_metadata( + struct t10_alua_tg_pt_gp *tg_pt_gp, + int primary_state, + unsigned char *md_buf) +{ + struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct t10_wwn *wwn = &su_dev->t10_wwn; + char path[ALUA_METADATA_PATH_LEN]; + int len; + + memset(path, 0, ALUA_METADATA_PATH_LEN); + + len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len, + "tg_pt_gp_id=%hu\n" + "alua_access_state=0x%02x\n" + "alua_access_status=0x%02x\n", + tg_pt_gp->tg_pt_gp_id, primary_state, + tg_pt_gp->tg_pt_gp_alua_access_status); + + snprintf(path, ALUA_METADATA_PATH_LEN, + "/var/target/alua/tpgs_%s/%s", &wwn->unit_serial[0], + config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item)); + + return core_alua_write_tpg_metadata(path, md_buf, len); +} + +static int core_alua_do_transition_tg_pt( + struct t10_alua_tg_pt_gp *tg_pt_gp, + struct se_port *l_port, + struct se_node_acl *nacl, + unsigned char *md_buf, + int new_state, + int explict) +{ + struct se_dev_entry *se_deve; + struct se_lun_acl *lacl; + struct se_port *port; + struct t10_alua_tg_pt_gp_member *mem; + int old_state = 0; + /* + * Save the old primary ALUA access state, and set the current state + * to ALUA_ACCESS_STATE_TRANSITION. + */ + old_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); + atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, + ALUA_ACCESS_STATE_TRANSITION); + tg_pt_gp->tg_pt_gp_alua_access_status = (explict) ? + ALUA_STATUS_ALTERED_BY_EXPLICT_STPG : + ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA; + /* + * Check for the optional ALUA primary state transition delay + */ + if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0) + msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs); + + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list, + tg_pt_gp_mem_list) { + port = mem->tg_pt; + /* + * After an implicit target port asymmetric access state + * change, a device server shall establish a unit attention + * condition for the initiator port associated with every I_T + * nexus with the additional sense code set to ASYMMETRIC + * ACCESS STATE CHAGED. + * + * After an explicit target port asymmetric access state + * change, a device server shall establish a unit attention + * condition with the additional sense code set to ASYMMETRIC + * ACCESS STATE CHANGED for the initiator port associated with + * every I_T nexus other than the I_T nexus on which the SET + * TARGET PORT GROUPS command + */ + atomic_inc(&mem->tg_pt_gp_mem_ref_cnt); + smp_mb__after_atomic_inc(); + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + + spin_lock_bh(&port->sep_alua_lock); + list_for_each_entry(se_deve, &port->sep_alua_list, + alua_port_list) { + lacl = se_deve->se_lun_acl; + /* + * se_deve->se_lun_acl pointer may be NULL for a + * entry created without explict Node+MappedLUN ACLs + */ + if (!(lacl)) + continue; + + if (explict && + (nacl != NULL) && (nacl == lacl->se_lun_nacl) && + (l_port != NULL) && (l_port == port)) + continue; + + core_scsi3_ua_allocate(lacl->se_lun_nacl, + se_deve->mapped_lun, 0x2A, + ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); + } + spin_unlock_bh(&port->sep_alua_lock); + + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + atomic_dec(&mem->tg_pt_gp_mem_ref_cnt); + smp_mb__after_atomic_dec(); + } + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + /* + * Update the ALUA metadata buf that has been allocated in + * core_alua_do_port_transition(), this metadata will be written + * to struct file. + * + * Note that there is the case where we do not want to update the + * metadata when the saved metadata is being parsed in userspace + * when setting the existing port access state and access status. + * + * Also note that the failure to write out the ALUA metadata to + * struct file does NOT affect the actual ALUA transition. + */ + if (tg_pt_gp->tg_pt_gp_write_metadata) { + mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex); + core_alua_update_tpg_primary_metadata(tg_pt_gp, + new_state, md_buf); + mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex); + } + /* + * Set the current primary ALUA access state to the requested new state + */ + atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, new_state); + + printk(KERN_INFO "Successful %s ALUA transition TG PT Group: %s ID: %hu" + " from primary access state %s to %s\n", (explict) ? "explict" : + "implict", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), + tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(old_state), + core_alua_dump_state(new_state)); + + return 0; +} + +int core_alua_do_port_transition( + struct t10_alua_tg_pt_gp *l_tg_pt_gp, + struct se_device *l_dev, + struct se_port *l_port, + struct se_node_acl *l_nacl, + int new_state, + int explict) +{ + struct se_device *dev; + struct se_port *port; + struct se_subsystem_dev *su_dev; + struct se_node_acl *nacl; + struct t10_alua_lu_gp *lu_gp; + struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem; + struct t10_alua_tg_pt_gp *tg_pt_gp; + unsigned char *md_buf; + int primary; + + if (core_alua_check_transition(new_state, &primary) != 0) + return -EINVAL; + + md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL); + if (!(md_buf)) { + printk("Unable to allocate buf for ALUA metadata\n"); + return -ENOMEM; + } + + local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem; + spin_lock(&local_lu_gp_mem->lu_gp_mem_lock); + lu_gp = local_lu_gp_mem->lu_gp; + atomic_inc(&lu_gp->lu_gp_ref_cnt); + smp_mb__after_atomic_inc(); + spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock); + /* + * For storage objects that are members of the 'default_lu_gp', + * we only do transition on the passed *l_tp_pt_gp, and not + * on all of the matching target port groups IDs in default_lu_gp. + */ + if (!(lu_gp->lu_gp_id)) { + /* + * core_alua_do_transition_tg_pt() will always return + * success. + */ + core_alua_do_transition_tg_pt(l_tg_pt_gp, l_port, l_nacl, + md_buf, new_state, explict); + atomic_dec(&lu_gp->lu_gp_ref_cnt); + smp_mb__after_atomic_dec(); + kfree(md_buf); + return 0; + } + /* + * For all other LU groups aside from 'default_lu_gp', walk all of + * the associated storage objects looking for a matching target port + * group ID from the local target port group. + */ + spin_lock(&lu_gp->lu_gp_lock); + list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, + lu_gp_mem_list) { + + dev = lu_gp_mem->lu_gp_mem_dev; + su_dev = dev->se_sub_dev; + atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt); + smp_mb__after_atomic_inc(); + spin_unlock(&lu_gp->lu_gp_lock); + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, + &T10_ALUA(su_dev)->tg_pt_gps_list, + tg_pt_gp_list) { + + if (!(tg_pt_gp->tg_pt_gp_valid_id)) + continue; + /* + * If the target behavior port asymmetric access state + * is changed for any target port group accessiable via + * a logical unit within a LU group, the target port + * behavior group asymmetric access states for the same + * target port group accessible via other logical units + * in that LU group will also change. + */ + if (l_tg_pt_gp->tg_pt_gp_id != tg_pt_gp->tg_pt_gp_id) + continue; + + if (l_tg_pt_gp == tg_pt_gp) { + port = l_port; + nacl = l_nacl; + } else { + port = NULL; + nacl = NULL; + } + atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); + smp_mb__after_atomic_inc(); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + /* + * core_alua_do_transition_tg_pt() will always return + * success. + */ + core_alua_do_transition_tg_pt(tg_pt_gp, port, + nacl, md_buf, new_state, explict); + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); + smp_mb__after_atomic_dec(); + } + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + + spin_lock(&lu_gp->lu_gp_lock); + atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt); + smp_mb__after_atomic_dec(); + } + spin_unlock(&lu_gp->lu_gp_lock); + + printk(KERN_INFO "Successfully processed LU Group: %s all ALUA TG PT" + " Group IDs: %hu %s transition to primary state: %s\n", + config_item_name(&lu_gp->lu_gp_group.cg_item), + l_tg_pt_gp->tg_pt_gp_id, (explict) ? "explict" : "implict", + core_alua_dump_state(new_state)); + + atomic_dec(&lu_gp->lu_gp_ref_cnt); + smp_mb__after_atomic_dec(); + kfree(md_buf); + return 0; +} + +/* + * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held + */ +static int core_alua_update_tpg_secondary_metadata( + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, + struct se_port *port, + unsigned char *md_buf, + u32 md_buf_len) +{ + struct se_portal_group *se_tpg = port->sep_tpg; + char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN]; + int len; + + memset(path, 0, ALUA_METADATA_PATH_LEN); + memset(wwn, 0, ALUA_SECONDARY_METADATA_WWN_LEN); + + len = snprintf(wwn, ALUA_SECONDARY_METADATA_WWN_LEN, "%s", + TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg)); + + if (TPG_TFO(se_tpg)->tpg_get_tag != NULL) + snprintf(wwn+len, ALUA_SECONDARY_METADATA_WWN_LEN-len, "+%hu", + TPG_TFO(se_tpg)->tpg_get_tag(se_tpg)); + + len = snprintf(md_buf, md_buf_len, "alua_tg_pt_offline=%d\n" + "alua_tg_pt_status=0x%02x\n", + atomic_read(&port->sep_tg_pt_secondary_offline), + port->sep_tg_pt_secondary_stat); + + snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u", + TPG_TFO(se_tpg)->get_fabric_name(), wwn, + port->sep_lun->unpacked_lun); + + return core_alua_write_tpg_metadata(path, md_buf, len); +} + +static int core_alua_set_tg_pt_secondary_state( + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, + struct se_port *port, + int explict, + int offline) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + unsigned char *md_buf; + u32 md_buf_len; + int trans_delay_msecs; + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if (!(tg_pt_gp)) { + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + printk(KERN_ERR "Unable to complete secondary state" + " transition\n"); + return -1; + } + trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs; + /* + * Set the secondary ALUA target port access state to OFFLINE + * or release the previously secondary state for struct se_port + */ + if (offline) + atomic_set(&port->sep_tg_pt_secondary_offline, 1); + else + atomic_set(&port->sep_tg_pt_secondary_offline, 0); + + md_buf_len = tg_pt_gp->tg_pt_gp_md_buf_len; + port->sep_tg_pt_secondary_stat = (explict) ? + ALUA_STATUS_ALTERED_BY_EXPLICT_STPG : + ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA; + + printk(KERN_INFO "Successful %s ALUA transition TG PT Group: %s ID: %hu" + " to secondary access state: %s\n", (explict) ? "explict" : + "implict", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), + tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE"); + + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + /* + * Do the optional transition delay after we set the secondary + * ALUA access state. + */ + if (trans_delay_msecs != 0) + msleep_interruptible(trans_delay_msecs); + /* + * See if we need to update the ALUA fabric port metadata for + * secondary state and status + */ + if (port->sep_tg_pt_secondary_write_md) { + md_buf = kzalloc(md_buf_len, GFP_KERNEL); + if (!(md_buf)) { + printk(KERN_ERR "Unable to allocate md_buf for" + " secondary ALUA access metadata\n"); + return -1; + } + mutex_lock(&port->sep_tg_pt_md_mutex); + core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port, + md_buf, md_buf_len); + mutex_unlock(&port->sep_tg_pt_md_mutex); + + kfree(md_buf); + } + + return 0; +} + +struct t10_alua_lu_gp * +core_alua_allocate_lu_gp(const char *name, int def_group) +{ + struct t10_alua_lu_gp *lu_gp; + + lu_gp = kmem_cache_zalloc(t10_alua_lu_gp_cache, GFP_KERNEL); + if (!(lu_gp)) { + printk(KERN_ERR "Unable to allocate struct t10_alua_lu_gp\n"); + return ERR_PTR(-ENOMEM);; + } + INIT_LIST_HEAD(&lu_gp->lu_gp_list); + INIT_LIST_HEAD(&lu_gp->lu_gp_mem_list); + spin_lock_init(&lu_gp->lu_gp_lock); + atomic_set(&lu_gp->lu_gp_ref_cnt, 0); + + if (def_group) { + lu_gp->lu_gp_id = se_global->alua_lu_gps_counter++;; + lu_gp->lu_gp_valid_id = 1; + se_global->alua_lu_gps_count++; + } + + return lu_gp; +} + +int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *lu_gp, u16 lu_gp_id) +{ + struct t10_alua_lu_gp *lu_gp_tmp; + u16 lu_gp_id_tmp; + /* + * The lu_gp->lu_gp_id may only be set once.. + */ + if (lu_gp->lu_gp_valid_id) { + printk(KERN_WARNING "ALUA LU Group already has a valid ID," + " ignoring request\n"); + return -1; + } + + spin_lock(&se_global->lu_gps_lock); + if (se_global->alua_lu_gps_count == 0x0000ffff) { + printk(KERN_ERR "Maximum ALUA se_global->alua_lu_gps_count:" + " 0x0000ffff reached\n"); + spin_unlock(&se_global->lu_gps_lock); + kmem_cache_free(t10_alua_lu_gp_cache, lu_gp); + return -1; + } +again: + lu_gp_id_tmp = (lu_gp_id != 0) ? lu_gp_id : + se_global->alua_lu_gps_counter++; + + list_for_each_entry(lu_gp_tmp, &se_global->g_lu_gps_list, lu_gp_list) { + if (lu_gp_tmp->lu_gp_id == lu_gp_id_tmp) { + if (!(lu_gp_id)) + goto again; + + printk(KERN_WARNING "ALUA Logical Unit Group ID: %hu" + " already exists, ignoring request\n", + lu_gp_id); + spin_unlock(&se_global->lu_gps_lock); + return -1; + } + } + + lu_gp->lu_gp_id = lu_gp_id_tmp; + lu_gp->lu_gp_valid_id = 1; + list_add_tail(&lu_gp->lu_gp_list, &se_global->g_lu_gps_list); + se_global->alua_lu_gps_count++; + spin_unlock(&se_global->lu_gps_lock); + + return 0; +} + +static struct t10_alua_lu_gp_member * +core_alua_allocate_lu_gp_mem(struct se_device *dev) +{ + struct t10_alua_lu_gp_member *lu_gp_mem; + + lu_gp_mem = kmem_cache_zalloc(t10_alua_lu_gp_mem_cache, GFP_KERNEL); + if (!(lu_gp_mem)) { + printk(KERN_ERR "Unable to allocate struct t10_alua_lu_gp_member\n"); + return ERR_PTR(-ENOMEM); + } + INIT_LIST_HEAD(&lu_gp_mem->lu_gp_mem_list); + spin_lock_init(&lu_gp_mem->lu_gp_mem_lock); + atomic_set(&lu_gp_mem->lu_gp_mem_ref_cnt, 0); + + lu_gp_mem->lu_gp_mem_dev = dev; + dev->dev_alua_lu_gp_mem = lu_gp_mem; + + return lu_gp_mem; +} + +void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) +{ + struct t10_alua_lu_gp_member *lu_gp_mem, *lu_gp_mem_tmp; + /* + * Once we have reached this point, config_item_put() has + * already been called from target_core_alua_drop_lu_gp(). + * + * Here, we remove the *lu_gp from the global list so that + * no associations can be made while we are releasing + * struct t10_alua_lu_gp. + */ + spin_lock(&se_global->lu_gps_lock); + atomic_set(&lu_gp->lu_gp_shutdown, 1); + list_del(&lu_gp->lu_gp_list); + se_global->alua_lu_gps_count--; + spin_unlock(&se_global->lu_gps_lock); + /* + * Allow struct t10_alua_lu_gp * referenced by core_alua_get_lu_gp_by_name() + * in target_core_configfs.c:target_core_store_alua_lu_gp() to be + * released with core_alua_put_lu_gp_from_name() + */ + while (atomic_read(&lu_gp->lu_gp_ref_cnt)) + cpu_relax(); + /* + * Release reference to struct t10_alua_lu_gp * from all associated + * struct se_device. + */ + spin_lock(&lu_gp->lu_gp_lock); + list_for_each_entry_safe(lu_gp_mem, lu_gp_mem_tmp, + &lu_gp->lu_gp_mem_list, lu_gp_mem_list) { + if (lu_gp_mem->lu_gp_assoc) { + list_del(&lu_gp_mem->lu_gp_mem_list); + lu_gp->lu_gp_members--; + lu_gp_mem->lu_gp_assoc = 0; + } + spin_unlock(&lu_gp->lu_gp_lock); + /* + * + * lu_gp_mem is assoicated with a single + * struct se_device->dev_alua_lu_gp_mem, and is released when + * struct se_device is released via core_alua_free_lu_gp_mem(). + * + * If the passed lu_gp does NOT match the default_lu_gp, assume + * we want to re-assocate a given lu_gp_mem with default_lu_gp. + */ + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + if (lu_gp != se_global->default_lu_gp) + __core_alua_attach_lu_gp_mem(lu_gp_mem, + se_global->default_lu_gp); + else + lu_gp_mem->lu_gp = NULL; + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + spin_lock(&lu_gp->lu_gp_lock); + } + spin_unlock(&lu_gp->lu_gp_lock); + + kmem_cache_free(t10_alua_lu_gp_cache, lu_gp); +} + +void core_alua_free_lu_gp_mem(struct se_device *dev) +{ + struct se_subsystem_dev *su_dev = dev->se_sub_dev; + struct t10_alua *alua = T10_ALUA(su_dev); + struct t10_alua_lu_gp *lu_gp; + struct t10_alua_lu_gp_member *lu_gp_mem; + + if (alua->alua_type != SPC3_ALUA_EMULATED) + return; + + lu_gp_mem = dev->dev_alua_lu_gp_mem; + if (!(lu_gp_mem)) + return; + + while (atomic_read(&lu_gp_mem->lu_gp_mem_ref_cnt)) + cpu_relax(); + + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + lu_gp = lu_gp_mem->lu_gp; + if ((lu_gp)) { + spin_lock(&lu_gp->lu_gp_lock); + if (lu_gp_mem->lu_gp_assoc) { + list_del(&lu_gp_mem->lu_gp_mem_list); + lu_gp->lu_gp_members--; + lu_gp_mem->lu_gp_assoc = 0; + } + spin_unlock(&lu_gp->lu_gp_lock); + lu_gp_mem->lu_gp = NULL; + } + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + kmem_cache_free(t10_alua_lu_gp_mem_cache, lu_gp_mem); +} + +struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *name) +{ + struct t10_alua_lu_gp *lu_gp; + struct config_item *ci; + + spin_lock(&se_global->lu_gps_lock); + list_for_each_entry(lu_gp, &se_global->g_lu_gps_list, lu_gp_list) { + if (!(lu_gp->lu_gp_valid_id)) + continue; + ci = &lu_gp->lu_gp_group.cg_item; + if (!(strcmp(config_item_name(ci), name))) { + atomic_inc(&lu_gp->lu_gp_ref_cnt); + spin_unlock(&se_global->lu_gps_lock); + return lu_gp; + } + } + spin_unlock(&se_global->lu_gps_lock); + + return NULL; +} + +void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *lu_gp) +{ + spin_lock(&se_global->lu_gps_lock); + atomic_dec(&lu_gp->lu_gp_ref_cnt); + spin_unlock(&se_global->lu_gps_lock); +} + +/* + * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock + */ +void __core_alua_attach_lu_gp_mem( + struct t10_alua_lu_gp_member *lu_gp_mem, + struct t10_alua_lu_gp *lu_gp) +{ + spin_lock(&lu_gp->lu_gp_lock); + lu_gp_mem->lu_gp = lu_gp; + lu_gp_mem->lu_gp_assoc = 1; + list_add_tail(&lu_gp_mem->lu_gp_mem_list, &lu_gp->lu_gp_mem_list); + lu_gp->lu_gp_members++; + spin_unlock(&lu_gp->lu_gp_lock); +} + +/* + * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock + */ +void __core_alua_drop_lu_gp_mem( + struct t10_alua_lu_gp_member *lu_gp_mem, + struct t10_alua_lu_gp *lu_gp) +{ + spin_lock(&lu_gp->lu_gp_lock); + list_del(&lu_gp_mem->lu_gp_mem_list); + lu_gp_mem->lu_gp = NULL; + lu_gp_mem->lu_gp_assoc = 0; + lu_gp->lu_gp_members--; + spin_unlock(&lu_gp->lu_gp_lock); +} + +struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( + struct se_subsystem_dev *su_dev, + const char *name, + int def_group) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + + tg_pt_gp = kmem_cache_zalloc(t10_alua_tg_pt_gp_cache, GFP_KERNEL); + if (!(tg_pt_gp)) { + printk(KERN_ERR "Unable to allocate struct t10_alua_tg_pt_gp\n"); + return NULL; + } + INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list); + INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list); + mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex); + spin_lock_init(&tg_pt_gp->tg_pt_gp_lock); + atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); + tg_pt_gp->tg_pt_gp_su_dev = su_dev; + tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN; + atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, + ALUA_ACCESS_STATE_ACTIVE_OPTMIZED); + /* + * Enable both explict and implict ALUA support by default + */ + tg_pt_gp->tg_pt_gp_alua_access_type = + TPGS_EXPLICT_ALUA | TPGS_IMPLICT_ALUA; + /* + * Set the default Active/NonOptimized Delay in milliseconds + */ + tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS; + tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; + + if (def_group) { + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + tg_pt_gp->tg_pt_gp_id = + T10_ALUA(su_dev)->alua_tg_pt_gps_counter++; + tg_pt_gp->tg_pt_gp_valid_id = 1; + T10_ALUA(su_dev)->alua_tg_pt_gps_count++; + list_add_tail(&tg_pt_gp->tg_pt_gp_list, + &T10_ALUA(su_dev)->tg_pt_gps_list); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + } + + return tg_pt_gp; +} + +int core_alua_set_tg_pt_gp_id( + struct t10_alua_tg_pt_gp *tg_pt_gp, + u16 tg_pt_gp_id) +{ + struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct t10_alua_tg_pt_gp *tg_pt_gp_tmp; + u16 tg_pt_gp_id_tmp; + /* + * The tg_pt_gp->tg_pt_gp_id may only be set once.. + */ + if (tg_pt_gp->tg_pt_gp_valid_id) { + printk(KERN_WARNING "ALUA TG PT Group already has a valid ID," + " ignoring request\n"); + return -1; + } + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + if (T10_ALUA(su_dev)->alua_tg_pt_gps_count == 0x0000ffff) { + printk(KERN_ERR "Maximum ALUA alua_tg_pt_gps_count:" + " 0x0000ffff reached\n"); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); + return -1; + } +again: + tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id : + T10_ALUA(su_dev)->alua_tg_pt_gps_counter++; + + list_for_each_entry(tg_pt_gp_tmp, &T10_ALUA(su_dev)->tg_pt_gps_list, + tg_pt_gp_list) { + if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) { + if (!(tg_pt_gp_id)) + goto again; + + printk(KERN_ERR "ALUA Target Port Group ID: %hu already" + " exists, ignoring request\n", tg_pt_gp_id); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + return -1; + } + } + + tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp; + tg_pt_gp->tg_pt_gp_valid_id = 1; + list_add_tail(&tg_pt_gp->tg_pt_gp_list, + &T10_ALUA(su_dev)->tg_pt_gps_list); + T10_ALUA(su_dev)->alua_tg_pt_gps_count++; + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + + return 0; +} + +struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( + struct se_port *port) +{ + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + + tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache, + GFP_KERNEL); + if (!(tg_pt_gp_mem)) { + printk(KERN_ERR "Unable to allocate struct t10_alua_tg_pt_gp_member\n"); + return ERR_PTR(-ENOMEM); + } + INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list); + spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0); + + tg_pt_gp_mem->tg_pt = port; + port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem; + atomic_set(&port->sep_tg_pt_gp_active, 1); + + return tg_pt_gp_mem; +} + +void core_alua_free_tg_pt_gp( + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp; + /* + * Once we have reached this point, config_item_put() has already + * been called from target_core_alua_drop_tg_pt_gp(). + * + * Here we remove *tg_pt_gp from the global list so that + * no assications *OR* explict ALUA via SET_TARGET_PORT_GROUPS + * can be made while we are releasing struct t10_alua_tg_pt_gp. + */ + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + list_del(&tg_pt_gp->tg_pt_gp_list); + T10_ALUA(su_dev)->alua_tg_pt_gps_counter--; + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + /* + * Allow a struct t10_alua_tg_pt_gp_member * referenced by + * core_alua_get_tg_pt_gp_by_name() in + * target_core_configfs.c:target_core_store_alua_tg_pt_gp() + * to be released with core_alua_put_tg_pt_gp_from_name(). + */ + while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt)) + cpu_relax(); + /* + * Release reference to struct t10_alua_tg_pt_gp from all associated + * struct se_port. + */ + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp, + &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) { + if (tg_pt_gp_mem->tg_pt_gp_assoc) { + list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); + tg_pt_gp->tg_pt_gp_members--; + tg_pt_gp_mem->tg_pt_gp_assoc = 0; + } + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + /* + * tg_pt_gp_mem is assoicated with a single + * se_port->sep_alua_tg_pt_gp_mem, and is released via + * core_alua_free_tg_pt_gp_mem(). + * + * If the passed tg_pt_gp does NOT match the default_tg_pt_gp, + * assume we want to re-assocate a given tg_pt_gp_mem with + * default_tg_pt_gp. + */ + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + if (tg_pt_gp != T10_ALUA(su_dev)->default_tg_pt_gp) { + __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + T10_ALUA(su_dev)->default_tg_pt_gp); + } else + tg_pt_gp_mem->tg_pt_gp = NULL; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + } + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + + kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); +} + +void core_alua_free_tg_pt_gp_mem(struct se_port *port) +{ + struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; + struct t10_alua *alua = T10_ALUA(su_dev); + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + + if (alua->alua_type != SPC3_ALUA_EMULATED) + return; + + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!(tg_pt_gp_mem)) + return; + + while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt)) + cpu_relax(); + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if ((tg_pt_gp)) { + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + if (tg_pt_gp_mem->tg_pt_gp_assoc) { + list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); + tg_pt_gp->tg_pt_gp_members--; + tg_pt_gp_mem->tg_pt_gp_assoc = 0; + } + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + tg_pt_gp_mem->tg_pt_gp = NULL; + } + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem); +} + +static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( + struct se_subsystem_dev *su_dev, + const char *name) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct config_item *ci; + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list, + tg_pt_gp_list) { + if (!(tg_pt_gp->tg_pt_gp_valid_id)) + continue; + ci = &tg_pt_gp->tg_pt_gp_group.cg_item; + if (!(strcmp(config_item_name(ci), name))) { + atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + return tg_pt_gp; + } + } + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + + return NULL; +} + +static void core_alua_put_tg_pt_gp_from_name( + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + + spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); + atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); + spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock); +} + +/* + * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held + */ +void __core_alua_attach_tg_pt_gp_mem( + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + tg_pt_gp_mem->tg_pt_gp = tg_pt_gp; + tg_pt_gp_mem->tg_pt_gp_assoc = 1; + list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list, + &tg_pt_gp->tg_pt_gp_mem_list); + tg_pt_gp->tg_pt_gp_members++; + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); +} + +/* + * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held + */ +static void __core_alua_drop_tg_pt_gp_mem( + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); + tg_pt_gp_mem->tg_pt_gp = NULL; + tg_pt_gp_mem->tg_pt_gp_assoc = 0; + tg_pt_gp->tg_pt_gp_members--; + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); +} + +ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) +{ + struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; + struct config_item *tg_pt_ci; + struct t10_alua *alua = T10_ALUA(su_dev); + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + ssize_t len = 0; + + if (alua->alua_type != SPC3_ALUA_EMULATED) + return len; + + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!(tg_pt_gp_mem)) + return len; + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if ((tg_pt_gp)) { + tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item; + len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:" + " %hu\nTG Port Primary Access State: %s\nTG Port " + "Primary Access Status: %s\nTG Port Secondary Access" + " State: %s\nTG Port Secondary Access Status: %s\n", + config_item_name(tg_pt_ci), tg_pt_gp->tg_pt_gp_id, + core_alua_dump_state(atomic_read( + &tg_pt_gp->tg_pt_gp_alua_access_state)), + core_alua_dump_status( + tg_pt_gp->tg_pt_gp_alua_access_status), + (atomic_read(&port->sep_tg_pt_secondary_offline)) ? + "Offline" : "None", + core_alua_dump_status(port->sep_tg_pt_secondary_stat)); + } + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + return len; +} + +ssize_t core_alua_store_tg_pt_gp_info( + struct se_port *port, + const char *page, + size_t count) +{ + struct se_portal_group *tpg; + struct se_lun *lun; + struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev; + struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + unsigned char buf[TG_PT_GROUP_NAME_BUF]; + int move = 0; + + tpg = port->sep_tpg; + lun = port->sep_lun; + + if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) { + printk(KERN_WARNING "SPC3_ALUA_EMULATED not enabled for" + " %s/tpgt_%hu/%s\n", TPG_TFO(tpg)->tpg_get_wwn(tpg), + TPG_TFO(tpg)->tpg_get_tag(tpg), + config_item_name(&lun->lun_group.cg_item)); + return -EINVAL; + } + + if (count > TG_PT_GROUP_NAME_BUF) { + printk(KERN_ERR "ALUA Target Port Group alias too large!\n"); + return -EINVAL; + } + memset(buf, 0, TG_PT_GROUP_NAME_BUF); + memcpy(buf, page, count); + /* + * Any ALUA target port group alias besides "NULL" means we will be + * making a new group association. + */ + if (strcmp(strstrip(buf), "NULL")) { + /* + * core_alua_get_tg_pt_gp_by_name() will increment reference to + * struct t10_alua_tg_pt_gp. This reference is released with + * core_alua_put_tg_pt_gp_from_name() below. + */ + tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(su_dev, + strstrip(buf)); + if (!(tg_pt_gp_new)) + return -ENODEV; + } + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!(tg_pt_gp_mem)) { + if (tg_pt_gp_new) + core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new); + printk(KERN_ERR "NULL struct se_port->sep_alua_tg_pt_gp_mem pointer\n"); + return -EINVAL; + } + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if ((tg_pt_gp)) { + /* + * Clearing an existing tg_pt_gp association, and replacing + * with the default_tg_pt_gp. + */ + if (!(tg_pt_gp_new)) { + printk(KERN_INFO "Target_Core_ConfigFS: Moving" + " %s/tpgt_%hu/%s from ALUA Target Port Group:" + " alua/%s, ID: %hu back to" + " default_tg_pt_gp\n", + TPG_TFO(tpg)->tpg_get_wwn(tpg), + TPG_TFO(tpg)->tpg_get_tag(tpg), + config_item_name(&lun->lun_group.cg_item), + config_item_name( + &tg_pt_gp->tg_pt_gp_group.cg_item), + tg_pt_gp->tg_pt_gp_id); + + __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); + __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + T10_ALUA(su_dev)->default_tg_pt_gp); + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + return count; + } + /* + * Removing existing association of tg_pt_gp_mem with tg_pt_gp + */ + __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); + move = 1; + } + /* + * Associate tg_pt_gp_mem with tg_pt_gp_new. + */ + __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new); + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + printk(KERN_INFO "Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA" + " Target Port Group: alua/%s, ID: %hu\n", (move) ? + "Moving" : "Adding", TPG_TFO(tpg)->tpg_get_wwn(tpg), + TPG_TFO(tpg)->tpg_get_tag(tpg), + config_item_name(&lun->lun_group.cg_item), + config_item_name(&tg_pt_gp_new->tg_pt_gp_group.cg_item), + tg_pt_gp_new->tg_pt_gp_id); + + core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new); + return count; +} + +ssize_t core_alua_show_access_type( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + if ((tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA) && + (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) + return sprintf(page, "Implict and Explict\n"); + else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA) + return sprintf(page, "Implict\n"); + else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA) + return sprintf(page, "Explict\n"); + else + return sprintf(page, "None\n"); +} + +ssize_t core_alua_store_access_type( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract alua_access_type\n"); + return -EINVAL; + } + if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) { + printk(KERN_ERR "Illegal value for alua_access_type:" + " %lu\n", tmp); + return -EINVAL; + } + if (tmp == 3) + tg_pt_gp->tg_pt_gp_alua_access_type = + TPGS_IMPLICT_ALUA | TPGS_EXPLICT_ALUA; + else if (tmp == 2) + tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_EXPLICT_ALUA; + else if (tmp == 1) + tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_IMPLICT_ALUA; + else + tg_pt_gp->tg_pt_gp_alua_access_type = 0; + + return count; +} + +ssize_t core_alua_show_nonop_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_nonop_delay_msecs); +} + +ssize_t core_alua_store_nonop_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract nonop_delay_msecs\n"); + return -EINVAL; + } + if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) { + printk(KERN_ERR "Passed nonop_delay_msecs: %lu, exceeds" + " ALUA_MAX_NONOP_DELAY_MSECS: %d\n", tmp, + ALUA_MAX_NONOP_DELAY_MSECS); + return -EINVAL; + } + tg_pt_gp->tg_pt_gp_nonop_delay_msecs = (int)tmp; + + return count; +} + +ssize_t core_alua_show_trans_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_trans_delay_msecs); +} + +ssize_t core_alua_store_trans_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract trans_delay_msecs\n"); + return -EINVAL; + } + if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) { + printk(KERN_ERR "Passed trans_delay_msecs: %lu, exceeds" + " ALUA_MAX_TRANS_DELAY_MSECS: %d\n", tmp, + ALUA_MAX_TRANS_DELAY_MSECS); + return -EINVAL; + } + tg_pt_gp->tg_pt_gp_trans_delay_msecs = (int)tmp; + + return count; +} + +ssize_t core_alua_show_preferred_bit( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_pref); +} + +ssize_t core_alua_store_preferred_bit( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract preferred ALUA value\n"); + return -EINVAL; + } + if ((tmp != 0) && (tmp != 1)) { + printk(KERN_ERR "Illegal value for preferred ALUA: %lu\n", tmp); + return -EINVAL; + } + tg_pt_gp->tg_pt_gp_pref = (int)tmp; + + return count; +} + +ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page) +{ + if (!(lun->lun_sep)) + return -ENODEV; + + return sprintf(page, "%d\n", + atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline)); +} + +ssize_t core_alua_store_offline_bit( + struct se_lun *lun, + const char *page, + size_t count) +{ + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + unsigned long tmp; + int ret; + + if (!(lun->lun_sep)) + return -ENODEV; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract alua_tg_pt_offline value\n"); + return -EINVAL; + } + if ((tmp != 0) && (tmp != 1)) { + printk(KERN_ERR "Illegal value for alua_tg_pt_offline: %lu\n", + tmp); + return -EINVAL; + } + tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem; + if (!(tg_pt_gp_mem)) { + printk(KERN_ERR "Unable to locate *tg_pt_gp_mem\n"); + return -EINVAL; + } + + ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem, + lun->lun_sep, 0, (int)tmp); + if (ret < 0) + return -EINVAL; + + return count; +} + +ssize_t core_alua_show_secondary_status( + struct se_lun *lun, + char *page) +{ + return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat); +} + +ssize_t core_alua_store_secondary_status( + struct se_lun *lun, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract alua_tg_pt_status\n"); + return -EINVAL; + } + if ((tmp != ALUA_STATUS_NONE) && + (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && + (tmp != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) { + printk(KERN_ERR "Illegal value for alua_tg_pt_status: %lu\n", + tmp); + return -EINVAL; + } + lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp; + + return count; +} + +ssize_t core_alua_show_secondary_write_metadata( + struct se_lun *lun, + char *page) +{ + return sprintf(page, "%d\n", + lun->lun_sep->sep_tg_pt_secondary_write_md); +} + +ssize_t core_alua_store_secondary_write_metadata( + struct se_lun *lun, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract alua_tg_pt_write_md\n"); + return -EINVAL; + } + if ((tmp != 0) && (tmp != 1)) { + printk(KERN_ERR "Illegal value for alua_tg_pt_write_md:" + " %lu\n", tmp); + return -EINVAL; + } + lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp; + + return count; +} + +int core_setup_alua(struct se_device *dev, int force_pt) +{ + struct se_subsystem_dev *su_dev = dev->se_sub_dev; + struct t10_alua *alua = T10_ALUA(su_dev); + struct t10_alua_lu_gp_member *lu_gp_mem; + /* + * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic + * of the Underlying SCSI hardware. In Linux/SCSI terms, this can + * cause a problem because libata and some SATA RAID HBAs appear + * under Linux/SCSI, but emulate SCSI logic themselves. + */ + if (((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && + !(DEV_ATTRIB(dev)->emulate_alua)) || force_pt) { + alua->alua_type = SPC_ALUA_PASSTHROUGH; + alua->alua_state_check = &core_alua_state_check_nop; + printk(KERN_INFO "%s: Using SPC_ALUA_PASSTHROUGH, no ALUA" + " emulation\n", TRANSPORT(dev)->name); + return 0; + } + /* + * If SPC-3 or above is reported by real or emulated struct se_device, + * use emulated ALUA. + */ + if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) { + printk(KERN_INFO "%s: Enabling ALUA Emulation for SPC-3" + " device\n", TRANSPORT(dev)->name); + /* + * Assoicate this struct se_device with the default ALUA + * LUN Group. + */ + lu_gp_mem = core_alua_allocate_lu_gp_mem(dev); + if (IS_ERR(lu_gp_mem) || !lu_gp_mem) + return -1; + + alua->alua_type = SPC3_ALUA_EMULATED; + alua->alua_state_check = &core_alua_state_check; + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + __core_alua_attach_lu_gp_mem(lu_gp_mem, + se_global->default_lu_gp); + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + printk(KERN_INFO "%s: Adding to default ALUA LU Group:" + " core/alua/lu_gps/default_lu_gp\n", + TRANSPORT(dev)->name); + } else { + alua->alua_type = SPC2_ALUA_DISABLED; + alua->alua_state_check = &core_alua_state_check_nop; + printk(KERN_INFO "%s: Disabling ALUA Emulation for SPC-2" + " device\n", TRANSPORT(dev)->name); + } + + return 0; +} diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h new file mode 100644 index 000000000000..c86f97a081ed --- /dev/null +++ b/drivers/target/target_core_alua.h @@ -0,0 +1,126 @@ +#ifndef TARGET_CORE_ALUA_H +#define TARGET_CORE_ALUA_H + +/* + * INQUIRY response data, TPGS Field + * + * from spc4r17 section 6.4.2 Table 135 + */ +#define TPGS_NO_ALUA 0x00 +#define TPGS_IMPLICT_ALUA 0x10 +#define TPGS_EXPLICT_ALUA 0x20 + +/* + * ASYMMETRIC ACCESS STATE field + * + * from spc4r17 section 6.27 Table 245 + */ +#define ALUA_ACCESS_STATE_ACTIVE_OPTMIZED 0x0 +#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1 +#define ALUA_ACCESS_STATE_STANDBY 0x2 +#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3 +#define ALUA_ACCESS_STATE_OFFLINE 0xe +#define ALUA_ACCESS_STATE_TRANSITION 0xf + +/* + * REPORT_TARGET_PORT_GROUP STATUS CODE + * + * from spc4r17 section 6.27 Table 246 + */ +#define ALUA_STATUS_NONE 0x00 +#define ALUA_STATUS_ALTERED_BY_EXPLICT_STPG 0x01 +#define ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA 0x02 + +/* + * From spc4r17, Table D.1: ASC and ASCQ Assignement + */ +#define ASCQ_04H_ALUA_STATE_TRANSITION 0x0a +#define ASCQ_04H_ALUA_TG_PT_STANDBY 0x0b +#define ASCQ_04H_ALUA_TG_PT_UNAVAILABLE 0x0c +#define ASCQ_04H_ALUA_OFFLINE 0x12 + +/* + * Used as the default for Active/NonOptimized delay (in milliseconds) + * This can also be changed via configfs on a per target port group basis.. + */ +#define ALUA_DEFAULT_NONOP_DELAY_MSECS 100 +#define ALUA_MAX_NONOP_DELAY_MSECS 10000 /* 10 seconds */ +/* + * Used for implict and explict ALUA transitional delay, that is disabled + * by default, and is intended to be used for debugging client side ALUA code. + */ +#define ALUA_DEFAULT_TRANS_DELAY_MSECS 0 +#define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */ +/* + * Used by core_alua_update_tpg_primary_metadata() and + * core_alua_update_tpg_secondary_metadata() + */ +#define ALUA_METADATA_PATH_LEN 512 +/* + * Used by core_alua_update_tpg_secondary_metadata() + */ +#define ALUA_SECONDARY_METADATA_WWN_LEN 256 + +extern struct kmem_cache *t10_alua_lu_gp_cache; +extern struct kmem_cache *t10_alua_lu_gp_mem_cache; +extern struct kmem_cache *t10_alua_tg_pt_gp_cache; +extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; + +extern int core_emulate_report_target_port_groups(struct se_cmd *); +extern int core_emulate_set_target_port_groups(struct se_cmd *); +extern int core_alua_check_nonop_delay(struct se_cmd *); +extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, + struct se_device *, struct se_port *, + struct se_node_acl *, int, int); +extern char *core_alua_dump_status(int); +extern struct t10_alua_lu_gp *core_alua_allocate_lu_gp(const char *, int); +extern int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *, u16); +extern void core_alua_free_lu_gp(struct t10_alua_lu_gp *); +extern void core_alua_free_lu_gp_mem(struct se_device *); +extern struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *); +extern void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *); +extern void __core_alua_attach_lu_gp_mem(struct t10_alua_lu_gp_member *, + struct t10_alua_lu_gp *); +extern void __core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member *, + struct t10_alua_lu_gp *); +extern void core_alua_drop_lu_gp_dev(struct se_device *); +extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( + struct se_subsystem_dev *, const char *, int); +extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16); +extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( + struct se_port *); +extern void core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp *); +extern void core_alua_free_tg_pt_gp_mem(struct se_port *); +extern void __core_alua_attach_tg_pt_gp_mem(struct t10_alua_tg_pt_gp_member *, + struct t10_alua_tg_pt_gp *); +extern ssize_t core_alua_show_tg_pt_gp_info(struct se_port *, char *); +extern ssize_t core_alua_store_tg_pt_gp_info(struct se_port *, const char *, + size_t); +extern ssize_t core_alua_show_access_type(struct t10_alua_tg_pt_gp *, char *); +extern ssize_t core_alua_store_access_type(struct t10_alua_tg_pt_gp *, + const char *, size_t); +extern ssize_t core_alua_show_nonop_delay_msecs(struct t10_alua_tg_pt_gp *, + char *); +extern ssize_t core_alua_store_nonop_delay_msecs(struct t10_alua_tg_pt_gp *, + const char *, size_t); +extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *, + char *); +extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *, + const char *, size_t); +extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *, + char *); +extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp *, + const char *, size_t); +extern ssize_t core_alua_show_offline_bit(struct se_lun *, char *); +extern ssize_t core_alua_store_offline_bit(struct se_lun *, const char *, + size_t); +extern ssize_t core_alua_show_secondary_status(struct se_lun *, char *); +extern ssize_t core_alua_store_secondary_status(struct se_lun *, + const char *, size_t); +extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun *, + char *); +extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun *, + const char *, size_t); +extern int core_setup_alua(struct se_device *, int); + +#endif /* TARGET_CORE_ALUA_H */ diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c new file mode 100644 index 000000000000..366080baf474 --- /dev/null +++ b/drivers/target/target_core_cdb.c @@ -0,0 +1,1131 @@ +/* + * CDB emulation for non-READ/WRITE commands. + * + * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 "target_core_ua.h" + +static void +target_fill_alua_data(struct se_port *port, unsigned char *buf) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + + /* + * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. + */ + buf[5] = 0x80; + + /* + * Set TPGS field for explict and/or implict ALUA access type + * and opteration. + * + * See spc4r17 section 6.4.2 Table 135 + */ + if (!port) + return; + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!tg_pt_gp_mem) + return; + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if (tg_pt_gp) + buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); +} + +static int +target_emulate_inquiry_std(struct se_cmd *cmd) +{ + struct se_lun *lun = SE_LUN(cmd); + struct se_device *dev = SE_DEV(cmd); + unsigned char *buf = cmd->t_task->t_task_buf; + + /* + * Make sure we at least have 6 bytes of INQUIRY response + * payload going back for EVPD=0 + */ + if (cmd->data_length < 6) { + printk(KERN_ERR "SCSI Inquiry payload length: %u" + " too small for EVPD=0\n", cmd->data_length); + return -1; + } + + buf[0] = dev->transport->get_device_type(dev); + if (buf[0] == TYPE_TAPE) + buf[1] = 0x80; + buf[2] = dev->transport->get_device_rev(dev); + + /* + * Enable SCCS and TPGS fields for Emulated ALUA + */ + if (T10_ALUA(dev->se_sub_dev)->alua_type == SPC3_ALUA_EMULATED) + target_fill_alua_data(lun->lun_sep, buf); + + if (cmd->data_length < 8) { + buf[4] = 1; /* Set additional length to 1 */ + return 0; + } + + buf[7] = 0x32; /* Sync=1 and CmdQue=1 */ + + /* + * Do not include vendor, product, reversion info in INQUIRY + * response payload for cdbs with a small allocation length. + */ + if (cmd->data_length < 36) { + buf[4] = 3; /* Set additional length to 3 */ + return 0; + } + + snprintf((unsigned char *)&buf[8], 8, "LIO-ORG"); + snprintf((unsigned char *)&buf[16], 16, "%s", + &DEV_T10_WWN(dev)->model[0]); + snprintf((unsigned char *)&buf[32], 4, "%s", + &DEV_T10_WWN(dev)->revision[0]); + buf[4] = 31; /* Set additional length to 31 */ + return 0; +} + +/* supported vital product data pages */ +static int +target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) +{ + buf[1] = 0x00; + if (cmd->data_length < 8) + return 0; + + buf[4] = 0x0; + /* + * Only report the INQUIRY EVPD=1 pages after a valid NAA + * Registered Extended LUN WWN has been set via ConfigFS + * during device creation/restart. + */ + if (SE_DEV(cmd)->se_sub_dev->su_dev_flags & + SDF_EMULATED_VPD_UNIT_SERIAL) { + buf[3] = 3; + buf[5] = 0x80; + buf[6] = 0x83; + buf[7] = 0x86; + } + + return 0; +} + +/* unit serial number */ +static int +target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = SE_DEV(cmd); + u16 len = 0; + + buf[1] = 0x80; + if (dev->se_sub_dev->su_dev_flags & + SDF_EMULATED_VPD_UNIT_SERIAL) { + u32 unit_serial_len; + + unit_serial_len = + strlen(&DEV_T10_WWN(dev)->unit_serial[0]); + unit_serial_len++; /* For NULL Terminator */ + + if (((len + 4) + unit_serial_len) > cmd->data_length) { + len += unit_serial_len; + buf[2] = ((len >> 8) & 0xff); + buf[3] = (len & 0xff); + return 0; + } + len += sprintf((unsigned char *)&buf[4], "%s", + &DEV_T10_WWN(dev)->unit_serial[0]); + len++; /* Extra Byte for NULL Terminator */ + buf[3] = len; + } + return 0; +} + +/* + * Device identification VPD, for a complete list of + * DESIGNATOR TYPEs see spc4r17 Table 459. + */ +static int +target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_lun *lun = SE_LUN(cmd); + struct se_port *port = NULL; + struct se_portal_group *tpg = NULL; + struct t10_alua_lu_gp_member *lu_gp_mem; + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + unsigned char binary, binary_new; + unsigned char *prod = &DEV_T10_WWN(dev)->model[0]; + u32 prod_len; + u32 unit_serial_len, off = 0; + int i; + u16 len = 0, id_len; + + buf[1] = 0x83; + off = 4; + + /* + * NAA IEEE Registered Extended Assigned designator format, see + * spc4r17 section 7.7.3.6.5 + * + * We depend upon a target_core_mod/ConfigFS provided + * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial + * value in order to return the NAA id. + */ + if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL)) + goto check_t10_vend_desc; + + if (off + 20 > cmd->data_length) + goto check_t10_vend_desc; + + /* CODE SET == Binary */ + buf[off++] = 0x1; + + /* Set ASSOICATION == addressed logical unit: 0)b */ + buf[off] = 0x00; + + /* Identifier/Designator type == NAA identifier */ + buf[off++] = 0x3; + off++; + + /* Identifier/Designator length */ + buf[off++] = 0x10; + + /* + * Start NAA IEEE Registered Extended Identifier/Designator + */ + buf[off++] = (0x6 << 4); + + /* + * Use OpenFabrics IEEE Company ID: 00 14 05 + */ + buf[off++] = 0x01; + buf[off++] = 0x40; + buf[off] = (0x5 << 4); + + /* + * Return ConfigFS Unit Serial Number information for + * VENDOR_SPECIFIC_IDENTIFIER and + * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION + */ + binary = transport_asciihex_to_binaryhex( + &DEV_T10_WWN(dev)->unit_serial[0]); + buf[off++] |= (binary & 0xf0) >> 4; + for (i = 0; i < 24; i += 2) { + binary_new = transport_asciihex_to_binaryhex( + &DEV_T10_WWN(dev)->unit_serial[i+2]); + buf[off] = (binary & 0x0f) << 4; + buf[off++] |= (binary_new & 0xf0) >> 4; + binary = binary_new; + } + len = 20; + off = (len + 4); + +check_t10_vend_desc: + /* + * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4 + */ + id_len = 8; /* For Vendor field */ + prod_len = 4; /* For VPD Header */ + prod_len += 8; /* For Vendor field */ + prod_len += strlen(prod); + prod_len++; /* For : */ + + if (dev->se_sub_dev->su_dev_flags & + SDF_EMULATED_VPD_UNIT_SERIAL) { + unit_serial_len = + strlen(&DEV_T10_WWN(dev)->unit_serial[0]); + unit_serial_len++; /* For NULL Terminator */ + + if ((len + (id_len + 4) + + (prod_len + unit_serial_len)) > + cmd->data_length) { + len += (prod_len + unit_serial_len); + goto check_port; + } + id_len += sprintf((unsigned char *)&buf[off+12], + "%s:%s", prod, + &DEV_T10_WWN(dev)->unit_serial[0]); + } + buf[off] = 0x2; /* ASCII */ + buf[off+1] = 0x1; /* T10 Vendor ID */ + buf[off+2] = 0x0; + memcpy((unsigned char *)&buf[off+4], "LIO-ORG", 8); + /* Extra Byte for NULL Terminator */ + id_len++; + /* Identifier Length */ + buf[off+3] = id_len; + /* Header size for Designation descriptor */ + len += (id_len + 4); + off += (id_len + 4); + /* + * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD + */ +check_port: + port = lun->lun_sep; + if (port) { + struct t10_alua_lu_gp *lu_gp; + u32 padding, scsi_name_len; + u16 lu_gp_id = 0; + u16 tg_pt_gp_id = 0; + u16 tpgt; + + tpg = port->sep_tpg; + /* + * Relative target port identifer, see spc4r17 + * section 7.7.3.7 + * + * Get the PROTOCOL IDENTIFIER as defined by spc4r17 + * section 7.5.1 Table 362 + */ + if (((len + 4) + 8) > cmd->data_length) { + len += 8; + goto check_tpgi; + } + buf[off] = + (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4); + buf[off++] |= 0x1; /* CODE SET == Binary */ + buf[off] = 0x80; /* Set PIV=1 */ + /* Set ASSOICATION == target port: 01b */ + buf[off] |= 0x10; + /* DESIGNATOR TYPE == Relative target port identifer */ + buf[off++] |= 0x4; + off++; /* Skip over Reserved */ + buf[off++] = 4; /* DESIGNATOR LENGTH */ + /* Skip over Obsolete field in RTPI payload + * in Table 472 */ + off += 2; + buf[off++] = ((port->sep_rtpi >> 8) & 0xff); + buf[off++] = (port->sep_rtpi & 0xff); + len += 8; /* Header size + Designation descriptor */ + /* + * Target port group identifier, see spc4r17 + * section 7.7.3.8 + * + * Get the PROTOCOL IDENTIFIER as defined by spc4r17 + * section 7.5.1 Table 362 + */ +check_tpgi: + if (T10_ALUA(dev->se_sub_dev)->alua_type != + SPC3_ALUA_EMULATED) + goto check_scsi_name; + + if (((len + 4) + 8) > cmd->data_length) { + len += 8; + goto check_lu_gp; + } + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (!tg_pt_gp_mem) + goto check_lu_gp; + + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if (!(tg_pt_gp)) { + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + goto check_lu_gp; + } + tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + buf[off] = + (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4); + buf[off++] |= 0x1; /* CODE SET == Binary */ + buf[off] = 0x80; /* Set PIV=1 */ + /* Set ASSOICATION == target port: 01b */ + buf[off] |= 0x10; + /* DESIGNATOR TYPE == Target port group identifier */ + buf[off++] |= 0x5; + off++; /* Skip over Reserved */ + buf[off++] = 4; /* DESIGNATOR LENGTH */ + off += 2; /* Skip over Reserved Field */ + buf[off++] = ((tg_pt_gp_id >> 8) & 0xff); + buf[off++] = (tg_pt_gp_id & 0xff); + len += 8; /* Header size + Designation descriptor */ + /* + * Logical Unit Group identifier, see spc4r17 + * section 7.7.3.8 + */ +check_lu_gp: + if (((len + 4) + 8) > cmd->data_length) { + len += 8; + goto check_scsi_name; + } + lu_gp_mem = dev->dev_alua_lu_gp_mem; + if (!(lu_gp_mem)) + goto check_scsi_name; + + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + lu_gp = lu_gp_mem->lu_gp; + if (!(lu_gp)) { + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + goto check_scsi_name; + } + lu_gp_id = lu_gp->lu_gp_id; + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + buf[off++] |= 0x1; /* CODE SET == Binary */ + /* DESIGNATOR TYPE == Logical Unit Group identifier */ + buf[off++] |= 0x6; + off++; /* Skip over Reserved */ + buf[off++] = 4; /* DESIGNATOR LENGTH */ + off += 2; /* Skip over Reserved Field */ + buf[off++] = ((lu_gp_id >> 8) & 0xff); + buf[off++] = (lu_gp_id & 0xff); + len += 8; /* Header size + Designation descriptor */ + /* + * SCSI name string designator, see spc4r17 + * section 7.7.3.11 + * + * Get the PROTOCOL IDENTIFIER as defined by spc4r17 + * section 7.5.1 Table 362 + */ +check_scsi_name: + scsi_name_len = strlen(TPG_TFO(tpg)->tpg_get_wwn(tpg)); + /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */ + scsi_name_len += 10; + /* Check for 4-byte padding */ + padding = ((-scsi_name_len) & 3); + if (padding != 0) + scsi_name_len += padding; + /* Header size + Designation descriptor */ + scsi_name_len += 4; + + if (((len + 4) + scsi_name_len) > cmd->data_length) { + len += scsi_name_len; + goto set_len; + } + buf[off] = + (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4); + buf[off++] |= 0x3; /* CODE SET == UTF-8 */ + buf[off] = 0x80; /* Set PIV=1 */ + /* Set ASSOICATION == target port: 01b */ + buf[off] |= 0x10; + /* DESIGNATOR TYPE == SCSI name string */ + buf[off++] |= 0x8; + off += 2; /* Skip over Reserved and length */ + /* + * SCSI name string identifer containing, $FABRIC_MOD + * dependent information. For LIO-Target and iSCSI + * Target Port, this means ",t,0x in + * UTF-8 encoding. + */ + tpgt = TPG_TFO(tpg)->tpg_get_tag(tpg); + scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x", + TPG_TFO(tpg)->tpg_get_wwn(tpg), tpgt); + scsi_name_len += 1 /* Include NULL terminator */; + /* + * The null-terminated, null-padded (see 4.4.2) SCSI + * NAME STRING field contains a UTF-8 format string. + * The number of bytes in the SCSI NAME STRING field + * (i.e., the value in the DESIGNATOR LENGTH field) + * shall be no larger than 256 and shall be a multiple + * of four. + */ + if (padding) + scsi_name_len += padding; + + buf[off-1] = scsi_name_len; + off += scsi_name_len; + /* Header size + Designation descriptor */ + len += (scsi_name_len + 4); + } +set_len: + buf[2] = ((len >> 8) & 0xff); + buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ + return 0; +} + +/* Extended INQUIRY Data VPD Page */ +static int +target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) +{ + if (cmd->data_length < 60) + return 0; + + buf[1] = 0x86; + buf[2] = 0x3c; + /* Set HEADSUP, ORDSUP, SIMPSUP */ + buf[5] = 0x07; + + /* If WriteCache emulation is enabled, set V_SUP */ + if (DEV_ATTRIB(SE_DEV(cmd))->emulate_write_cache > 0) + buf[6] = 0x01; + return 0; +} + +/* Block Limits VPD page */ +static int +target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = SE_DEV(cmd); + int have_tp = 0; + + /* + * Following sbc3r22 section 6.5.3 Block Limits VPD page, when + * emulate_tpu=1 or emulate_tpws=1 we will be expect a + * different page length for Thin Provisioning. + */ + if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws) + have_tp = 1; + + if (cmd->data_length < (0x10 + 4)) { + printk(KERN_INFO "Received data_length: %u" + " too small for EVPD 0xb0\n", + cmd->data_length); + return -1; + } + + if (have_tp && cmd->data_length < (0x3c + 4)) { + printk(KERN_INFO "Received data_length: %u" + " too small for TPE=1 EVPD 0xb0\n", + cmd->data_length); + have_tp = 0; + } + + buf[0] = dev->transport->get_device_type(dev); + buf[1] = 0xb0; + buf[3] = have_tp ? 0x3c : 0x10; + + /* + * Set OPTIMAL TRANSFER LENGTH GRANULARITY + */ + put_unaligned_be16(1, &buf[6]); + + /* + * Set MAXIMUM TRANSFER LENGTH + */ + put_unaligned_be32(DEV_ATTRIB(dev)->max_sectors, &buf[8]); + + /* + * Set OPTIMAL TRANSFER LENGTH + */ + put_unaligned_be32(DEV_ATTRIB(dev)->optimal_sectors, &buf[12]); + + /* + * Exit now if we don't support TP or the initiator sent a too + * short buffer. + */ + if (!have_tp || cmd->data_length < (0x3c + 4)) + return 0; + + /* + * Set MAXIMUM UNMAP LBA COUNT + */ + put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_lba_count, &buf[20]); + + /* + * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT + */ + put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_block_desc_count, + &buf[24]); + + /* + * Set OPTIMAL UNMAP GRANULARITY + */ + put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity, &buf[28]); + + /* + * UNMAP GRANULARITY ALIGNMENT + */ + put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity_alignment, + &buf[32]); + if (DEV_ATTRIB(dev)->unmap_granularity_alignment != 0) + buf[32] |= 0x80; /* Set the UGAVALID bit */ + + return 0; +} + +/* Thin Provisioning VPD */ +static int +target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf) +{ + struct se_device *dev = SE_DEV(cmd); + + /* + * From sbc3r22 section 6.5.4 Thin Provisioning VPD page: + * + * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to + * zero, then the page length shall be set to 0004h. If the DP bit + * is set to one, then the page length shall be set to the value + * defined in table 162. + */ + buf[0] = dev->transport->get_device_type(dev); + buf[1] = 0xb2; + + /* + * Set Hardcoded length mentioned above for DP=0 + */ + put_unaligned_be16(0x0004, &buf[2]); + + /* + * The THRESHOLD EXPONENT field indicates the threshold set size in + * LBAs as a power of 2 (i.e., the threshold set size is equal to + * 2(threshold exponent)). + * + * Note that this is currently set to 0x00 as mkp says it will be + * changing again. We can enable this once it has settled in T10 + * and is actually used by Linux/SCSI ML code. + */ + buf[4] = 0x00; + + /* + * A TPU bit set to one indicates that the device server supports + * the UNMAP command (see 5.25). A TPU bit set to zero indicates + * that the device server does not support the UNMAP command. + */ + if (DEV_ATTRIB(dev)->emulate_tpu != 0) + buf[5] = 0x80; + + /* + * A TPWS bit set to one indicates that the device server supports + * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs. + * A TPWS bit set to zero indicates that the device server does not + * support the use of the WRITE SAME (16) command to unmap LBAs. + */ + if (DEV_ATTRIB(dev)->emulate_tpws != 0) + buf[5] |= 0x40; + + return 0; +} + +static int +target_emulate_inquiry(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + unsigned char *buf = cmd->t_task->t_task_buf; + unsigned char *cdb = cmd->t_task->t_task_cdb; + + if (!(cdb[1] & 0x1)) + return target_emulate_inquiry_std(cmd); + + /* + * Make sure we at least have 4 bytes of INQUIRY response + * payload for 0x00 going back for EVPD=1. Note that 0x80 + * and 0x83 will check for enough payload data length and + * jump to set_len: label when there is not enough inquiry EVPD + * payload length left for the next outgoing EVPD metadata + */ + if (cmd->data_length < 4) { + printk(KERN_ERR "SCSI Inquiry payload length: %u" + " too small for EVPD=1\n", cmd->data_length); + return -1; + } + buf[0] = dev->transport->get_device_type(dev); + + switch (cdb[2]) { + case 0x00: + return target_emulate_evpd_00(cmd, buf); + case 0x80: + return target_emulate_evpd_80(cmd, buf); + case 0x83: + return target_emulate_evpd_83(cmd, buf); + case 0x86: + return target_emulate_evpd_86(cmd, buf); + case 0xb0: + return target_emulate_evpd_b0(cmd, buf); + case 0xb2: + return target_emulate_evpd_b2(cmd, buf); + default: + printk(KERN_ERR "Unknown VPD Code: 0x%02x\n", cdb[2]); + return -1; + } + + return 0; +} + +static int +target_emulate_readcapacity(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + unsigned char *buf = cmd->t_task->t_task_buf; + u32 blocks = dev->transport->get_blocks(dev); + + buf[0] = (blocks >> 24) & 0xff; + buf[1] = (blocks >> 16) & 0xff; + buf[2] = (blocks >> 8) & 0xff; + buf[3] = blocks & 0xff; + buf[4] = (DEV_ATTRIB(dev)->block_size >> 24) & 0xff; + buf[5] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff; + buf[6] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff; + buf[7] = DEV_ATTRIB(dev)->block_size & 0xff; + /* + * Set max 32-bit blocks to signal SERVICE ACTION READ_CAPACITY_16 + */ + if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws) + put_unaligned_be32(0xFFFFFFFF, &buf[0]); + + return 0; +} + +static int +target_emulate_readcapacity_16(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + unsigned char *buf = cmd->t_task->t_task_buf; + unsigned long long blocks = dev->transport->get_blocks(dev); + + buf[0] = (blocks >> 56) & 0xff; + buf[1] = (blocks >> 48) & 0xff; + buf[2] = (blocks >> 40) & 0xff; + buf[3] = (blocks >> 32) & 0xff; + buf[4] = (blocks >> 24) & 0xff; + buf[5] = (blocks >> 16) & 0xff; + buf[6] = (blocks >> 8) & 0xff; + buf[7] = blocks & 0xff; + buf[8] = (DEV_ATTRIB(dev)->block_size >> 24) & 0xff; + buf[9] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff; + buf[10] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff; + buf[11] = DEV_ATTRIB(dev)->block_size & 0xff; + /* + * Set Thin Provisioning Enable bit following sbc3r22 in section + * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled. + */ + if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws) + buf[14] = 0x80; + + return 0; +} + +static int +target_modesense_rwrecovery(unsigned char *p) +{ + p[0] = 0x01; + p[1] = 0x0a; + + return 12; +} + +static int +target_modesense_control(struct se_device *dev, unsigned char *p) +{ + p[0] = 0x0a; + p[1] = 0x0a; + p[2] = 2; + /* + * From spc4r17, section 7.4.6 Control mode Page + * + * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b + * + * 00b: The logical unit shall clear any unit attention condition + * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION + * status and shall not establish a unit attention condition when a com- + * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT + * status. + * + * 10b: The logical unit shall not clear any unit attention condition + * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION + * status and shall not establish a unit attention condition when + * a command is completed with BUSY, TASK SET FULL, or RESERVATION + * CONFLICT status. + * + * 11b a The logical unit shall not clear any unit attention condition + * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION + * status and shall establish a unit attention condition for the + * initiator port associated with the I_T nexus on which the BUSY, + * TASK SET FULL, or RESERVATION CONFLICT status is being returned. + * Depending on the status, the additional sense code shall be set to + * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS + * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE + * command, a unit attention condition shall be established only once + * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless + * to the number of commands completed with one of those status codes. + */ + p[4] = (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl == 2) ? 0x30 : + (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00; + /* + * From spc4r17, section 7.4.6 Control mode Page + * + * Task Aborted Status (TAS) bit set to zero. + * + * A task aborted status (TAS) bit set to zero specifies that aborted + * tasks shall be terminated by the device server without any response + * to the application client. A TAS bit set to one specifies that tasks + * aborted by the actions of an I_T nexus other than the I_T nexus on + * which the command was received shall be completed with TASK ABORTED + * status (see SAM-4). + */ + p[5] = (DEV_ATTRIB(dev)->emulate_tas) ? 0x40 : 0x00; + p[8] = 0xff; + p[9] = 0xff; + p[11] = 30; + + return 12; +} + +static int +target_modesense_caching(struct se_device *dev, unsigned char *p) +{ + p[0] = 0x08; + p[1] = 0x12; + if (DEV_ATTRIB(dev)->emulate_write_cache > 0) + p[2] = 0x04; /* Write Cache Enable */ + p[12] = 0x20; /* Disabled Read Ahead */ + + return 20; +} + +static void +target_modesense_write_protect(unsigned char *buf, int type) +{ + /* + * I believe that the WP bit (bit 7) in the mode header is the same for + * all device types.. + */ + switch (type) { + case TYPE_DISK: + case TYPE_TAPE: + default: + buf[0] |= 0x80; /* WP bit */ + break; + } +} + +static void +target_modesense_dpofua(unsigned char *buf, int type) +{ + switch (type) { + case TYPE_DISK: + buf[0] |= 0x10; /* DPOFUA bit */ + break; + default: + break; + } +} + +static int +target_emulate_modesense(struct se_cmd *cmd, int ten) +{ + struct se_device *dev = SE_DEV(cmd); + char *cdb = cmd->t_task->t_task_cdb; + unsigned char *rbuf = cmd->t_task->t_task_buf; + int type = dev->transport->get_device_type(dev); + int offset = (ten) ? 8 : 4; + int length = 0; + unsigned char buf[SE_MODE_PAGE_BUF]; + + memset(buf, 0, SE_MODE_PAGE_BUF); + + switch (cdb[2] & 0x3f) { + case 0x01: + length = target_modesense_rwrecovery(&buf[offset]); + break; + case 0x08: + length = target_modesense_caching(dev, &buf[offset]); + break; + case 0x0a: + length = target_modesense_control(dev, &buf[offset]); + break; + case 0x3f: + length = target_modesense_rwrecovery(&buf[offset]); + length += target_modesense_caching(dev, &buf[offset+length]); + length += target_modesense_control(dev, &buf[offset+length]); + break; + default: + printk(KERN_ERR "Got Unknown Mode Page: 0x%02x\n", + cdb[2] & 0x3f); + return PYX_TRANSPORT_UNKNOWN_MODE_PAGE; + } + offset += length; + + if (ten) { + offset -= 2; + buf[0] = (offset >> 8) & 0xff; + buf[1] = offset & 0xff; + + if ((SE_LUN(cmd)->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || + (cmd->se_deve && + (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) + target_modesense_write_protect(&buf[3], type); + + if ((DEV_ATTRIB(dev)->emulate_write_cache > 0) && + (DEV_ATTRIB(dev)->emulate_fua_write > 0)) + target_modesense_dpofua(&buf[3], type); + + if ((offset + 2) > cmd->data_length) + offset = cmd->data_length; + + } else { + offset -= 1; + buf[0] = offset & 0xff; + + if ((SE_LUN(cmd)->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || + (cmd->se_deve && + (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) + target_modesense_write_protect(&buf[2], type); + + if ((DEV_ATTRIB(dev)->emulate_write_cache > 0) && + (DEV_ATTRIB(dev)->emulate_fua_write > 0)) + target_modesense_dpofua(&buf[2], type); + + if ((offset + 1) > cmd->data_length) + offset = cmd->data_length; + } + memcpy(rbuf, buf, offset); + + return 0; +} + +static int +target_emulate_request_sense(struct se_cmd *cmd) +{ + unsigned char *cdb = cmd->t_task->t_task_cdb; + unsigned char *buf = cmd->t_task->t_task_buf; + u8 ua_asc = 0, ua_ascq = 0; + + if (cdb[1] & 0x01) { + printk(KERN_ERR "REQUEST_SENSE description emulation not" + " supported\n"); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + if (!(core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq))) { + /* + * CURRENT ERROR, UNIT ATTENTION + */ + buf[0] = 0x70; + buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; + /* + * Make sure request data length is enough for additional + * sense data. + */ + if (cmd->data_length <= 18) { + buf[7] = 0x00; + return 0; + } + /* + * The Additional Sense Code (ASC) from the UNIT ATTENTION + */ + buf[SPC_ASC_KEY_OFFSET] = ua_asc; + buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq; + buf[7] = 0x0A; + } else { + /* + * CURRENT ERROR, NO SENSE + */ + buf[0] = 0x70; + buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; + /* + * Make sure request data length is enough for additional + * sense data. + */ + if (cmd->data_length <= 18) { + buf[7] = 0x00; + return 0; + } + /* + * NO ADDITIONAL SENSE INFORMATION + */ + buf[SPC_ASC_KEY_OFFSET] = 0x00; + buf[7] = 0x0A; + } + + return 0; +} + +/* + * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. + * Note this is not used for TCM/pSCSI passthrough + */ +static int +target_emulate_unmap(struct se_task *task) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct se_device *dev = SE_DEV(cmd); + unsigned char *buf = cmd->t_task->t_task_buf, *ptr = NULL; + unsigned char *cdb = &cmd->t_task->t_task_cdb[0]; + sector_t lba; + unsigned int size = cmd->data_length, range; + int ret, offset; + unsigned short dl, bd_dl; + + /* First UNMAP block descriptor starts at 8 byte offset */ + offset = 8; + size -= 8; + dl = get_unaligned_be16(&cdb[0]); + bd_dl = get_unaligned_be16(&cdb[2]); + ptr = &buf[offset]; + printk(KERN_INFO "UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" + " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); + + while (size) { + lba = get_unaligned_be64(&ptr[0]); + range = get_unaligned_be32(&ptr[8]); + printk(KERN_INFO "UNMAP: Using lba: %llu and range: %u\n", + (unsigned long long)lba, range); + + ret = dev->transport->do_discard(dev, lba, range); + if (ret < 0) { + printk(KERN_ERR "blkdev_issue_discard() failed: %d\n", + ret); + return -1; + } + + ptr += 16; + size -= 16; + } + + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + return 0; +} + +/* + * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. + * Note this is not used for TCM/pSCSI passthrough + */ +static int +target_emulate_write_same(struct se_task *task) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct se_device *dev = SE_DEV(cmd); + sector_t lba = cmd->t_task->t_task_lba; + unsigned int range; + int ret; + + range = (cmd->data_length / DEV_ATTRIB(dev)->block_size); + + printk(KERN_INFO "WRITE_SAME UNMAP: LBA: %llu Range: %u\n", + (unsigned long long)lba, range); + + ret = dev->transport->do_discard(dev, lba, range); + if (ret < 0) { + printk(KERN_INFO "blkdev_issue_discard() failed for WRITE_SAME\n"); + return -1; + } + + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + return 0; +} + +int +transport_emulate_control_cdb(struct se_task *task) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct se_device *dev = SE_DEV(cmd); + unsigned short service_action; + int ret = 0; + + switch (cmd->t_task->t_task_cdb[0]) { + case INQUIRY: + ret = target_emulate_inquiry(cmd); + break; + case READ_CAPACITY: + ret = target_emulate_readcapacity(cmd); + break; + case MODE_SENSE: + ret = target_emulate_modesense(cmd, 0); + break; + case MODE_SENSE_10: + ret = target_emulate_modesense(cmd, 1); + break; + case SERVICE_ACTION_IN: + switch (cmd->t_task->t_task_cdb[1] & 0x1f) { + case SAI_READ_CAPACITY_16: + ret = target_emulate_readcapacity_16(cmd); + break; + default: + printk(KERN_ERR "Unsupported SA: 0x%02x\n", + cmd->t_task->t_task_cdb[1] & 0x1f); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + break; + case REQUEST_SENSE: + ret = target_emulate_request_sense(cmd); + break; + case UNMAP: + if (!dev->transport->do_discard) { + printk(KERN_ERR "UNMAP emulation not supported for: %s\n", + dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + ret = target_emulate_unmap(task); + break; + case WRITE_SAME_16: + if (!dev->transport->do_discard) { + printk(KERN_ERR "WRITE_SAME_16 emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + ret = target_emulate_write_same(task); + break; + case VARIABLE_LENGTH_CMD: + service_action = + get_unaligned_be16(&cmd->t_task->t_task_cdb[8]); + switch (service_action) { + case WRITE_SAME_32: + if (!dev->transport->do_discard) { + printk(KERN_ERR "WRITE_SAME_32 SA emulation not" + " supported for: %s\n", + dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + ret = target_emulate_write_same(task); + break; + default: + printk(KERN_ERR "Unsupported VARIABLE_LENGTH_CMD SA:" + " 0x%02x\n", service_action); + break; + } + break; + case SYNCHRONIZE_CACHE: + case 0x91: /* SYNCHRONIZE_CACHE_16: */ + if (!dev->transport->do_sync_cache) { + printk(KERN_ERR + "SYNCHRONIZE_CACHE emulation not supported" + " for: %s\n", dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + dev->transport->do_sync_cache(task); + break; + case ALLOW_MEDIUM_REMOVAL: + case ERASE: + case REZERO_UNIT: + case SEEK_10: + case SPACE: + case START_STOP: + case TEST_UNIT_READY: + case VERIFY: + case WRITE_FILEMARKS: + break; + default: + printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for %s\n", + cmd->t_task->t_task_cdb[0], dev->transport->name); + return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + + if (ret < 0) + return ret; + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c new file mode 100644 index 000000000000..2764510798b0 --- /dev/null +++ b/drivers/target/target_core_configfs.c @@ -0,0 +1,3225 @@ +/******************************************************************************* + * Filename: target_core_configfs.c + * + * This file contains ConfigFS logic for the Generic Target Engine project. + * + * Copyright (c) 2008-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * based on configfs Copyright (C) 2005 Oracle. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "target_core_alua.h" +#include "target_core_hba.h" +#include "target_core_pr.h" +#include "target_core_rd.h" + +static struct list_head g_tf_list; +static struct mutex g_tf_lock; + +struct target_core_configfs_attribute { + struct configfs_attribute attr; + ssize_t (*show)(void *, char *); + ssize_t (*store)(void *, const char *, size_t); +}; + +static inline struct se_hba * +item_to_hba(struct config_item *item) +{ + return container_of(to_config_group(item), struct se_hba, hba_group); +} + +/* + * Attributes for /sys/kernel/config/target/ + */ +static ssize_t target_core_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s" + " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION, + utsname()->sysname, utsname()->machine); +} + +static struct configfs_item_operations target_core_fabric_item_ops = { + .show_attribute = target_core_attr_show, +}; + +static struct configfs_attribute target_core_item_attr_version = { + .ca_owner = THIS_MODULE, + .ca_name = "version", + .ca_mode = S_IRUGO, +}; + +static struct target_fabric_configfs *target_core_get_fabric( + const char *name) +{ + struct target_fabric_configfs *tf; + + if (!(name)) + return NULL; + + mutex_lock(&g_tf_lock); + list_for_each_entry(tf, &g_tf_list, tf_list) { + if (!(strcmp(tf->tf_name, name))) { + atomic_inc(&tf->tf_access_cnt); + mutex_unlock(&g_tf_lock); + return tf; + } + } + mutex_unlock(&g_tf_lock); + + return NULL; +} + +/* + * Called from struct target_core_group_ops->make_group() + */ +static struct config_group *target_core_register_fabric( + struct config_group *group, + const char *name) +{ + struct target_fabric_configfs *tf; + int ret; + + printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> group: %p name:" + " %s\n", group, name); + /* + * Ensure that TCM subsystem plugins are loaded at this point for + * using the RAMDISK_DR virtual LUN 0 and all other struct se_port + * LUN symlinks. + */ + if (transport_subsystem_check_init() < 0) + return ERR_PTR(-EINVAL); + + /* + * Below are some hardcoded request_module() calls to automatically + * local fabric modules when the following is called: + * + * mkdir -p /sys/kernel/config/target/$MODULE_NAME + * + * Note that this does not limit which TCM fabric module can be + * registered, but simply provids auto loading logic for modules with + * mkdir(2) system calls with known TCM fabric modules. + */ + if (!(strncmp(name, "iscsi", 5))) { + /* + * Automatically load the LIO Target fabric module when the + * following is called: + * + * mkdir -p $CONFIGFS/target/iscsi + */ + ret = request_module("iscsi_target_mod"); + if (ret < 0) { + printk(KERN_ERR "request_module() failed for" + " iscsi_target_mod.ko: %d\n", ret); + return ERR_PTR(-EINVAL); + } + } else if (!(strncmp(name, "loopback", 8))) { + /* + * Automatically load the tcm_loop fabric module when the + * following is called: + * + * mkdir -p $CONFIGFS/target/loopback + */ + ret = request_module("tcm_loop"); + if (ret < 0) { + printk(KERN_ERR "request_module() failed for" + " tcm_loop.ko: %d\n", ret); + return ERR_PTR(-EINVAL); + } + } + + tf = target_core_get_fabric(name); + if (!(tf)) { + printk(KERN_ERR "target_core_get_fabric() failed for %s\n", + name); + return ERR_PTR(-EINVAL); + } + printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Located fabric:" + " %s\n", tf->tf_name); + /* + * On a successful target_core_get_fabric() look, the returned + * struct target_fabric_configfs *tf will contain a usage reference. + */ + printk(KERN_INFO "Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", + &TF_CIT_TMPL(tf)->tfc_wwn_cit); + + tf->tf_group.default_groups = tf->tf_default_groups; + tf->tf_group.default_groups[0] = &tf->tf_disc_group; + tf->tf_group.default_groups[1] = NULL; + + config_group_init_type_name(&tf->tf_group, name, + &TF_CIT_TMPL(tf)->tfc_wwn_cit); + config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", + &TF_CIT_TMPL(tf)->tfc_discovery_cit); + + printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" + " %s\n", tf->tf_group.cg_item.ci_name); + /* + * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item() + */ + tf->tf_ops.tf_subsys = tf->tf_subsys; + tf->tf_fabric = &tf->tf_group.cg_item; + printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric" + " for %s\n", name); + + return &tf->tf_group; +} + +/* + * Called from struct target_core_group_ops->drop_item() + */ +static void target_core_deregister_fabric( + struct config_group *group, + struct config_item *item) +{ + struct target_fabric_configfs *tf = container_of( + to_config_group(item), struct target_fabric_configfs, tf_group); + struct config_group *tf_group; + struct config_item *df_item; + int i; + + printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Looking up %s in" + " tf list\n", config_item_name(item)); + + printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> located fabric:" + " %s\n", tf->tf_name); + atomic_dec(&tf->tf_access_cnt); + + printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing" + " tf->tf_fabric for %s\n", tf->tf_name); + tf->tf_fabric = NULL; + + printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing ci" + " %s\n", config_item_name(item)); + + tf_group = &tf->tf_group; + for (i = 0; tf_group->default_groups[i]; i++) { + df_item = &tf_group->default_groups[i]->cg_item; + tf_group->default_groups[i] = NULL; + config_item_put(df_item); + } + config_item_put(item); +} + +static struct configfs_group_operations target_core_fabric_group_ops = { + .make_group = &target_core_register_fabric, + .drop_item = &target_core_deregister_fabric, +}; + +/* + * All item attributes appearing in /sys/kernel/target/ appear here. + */ +static struct configfs_attribute *target_core_fabric_item_attrs[] = { + &target_core_item_attr_version, + NULL, +}; + +/* + * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/ + */ +static struct config_item_type target_core_fabrics_item = { + .ct_item_ops = &target_core_fabric_item_ops, + .ct_group_ops = &target_core_fabric_group_ops, + .ct_attrs = target_core_fabric_item_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem target_core_fabrics = { + .su_group = { + .cg_item = { + .ci_namebuf = "target", + .ci_type = &target_core_fabrics_item, + }, + }, +}; + +static struct configfs_subsystem *target_core_subsystem[] = { + &target_core_fabrics, + NULL, +}; + +/*############################################################################## +// Start functions called by external Target Fabrics Modules +//############################################################################*/ + +/* + * First function called by fabric modules to: + * + * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer. + * 2) Add struct target_fabric_configfs to g_tf_list + * 3) Return struct target_fabric_configfs to fabric module to be passed + * into target_fabric_configfs_register(). + */ +struct target_fabric_configfs *target_fabric_configfs_init( + struct module *fabric_mod, + const char *name) +{ + struct target_fabric_configfs *tf; + + if (!(fabric_mod)) { + printk(KERN_ERR "Missing struct module *fabric_mod pointer\n"); + return NULL; + } + if (!(name)) { + printk(KERN_ERR "Unable to locate passed fabric name\n"); + return NULL; + } + if (strlen(name) > TARGET_FABRIC_NAME_SIZE) { + printk(KERN_ERR "Passed name: %s exceeds TARGET_FABRIC" + "_NAME_SIZE\n", name); + return NULL; + } + + tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); + if (!(tf)) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&tf->tf_list); + atomic_set(&tf->tf_access_cnt, 0); + /* + * Setup the default generic struct config_item_type's (cits) in + * struct target_fabric_configfs->tf_cit_tmpl + */ + tf->tf_module = fabric_mod; + target_fabric_setup_cits(tf); + + tf->tf_subsys = target_core_subsystem[0]; + snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name); + + mutex_lock(&g_tf_lock); + list_add_tail(&tf->tf_list, &g_tf_list); + mutex_unlock(&g_tf_lock); + + printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>" + ">>>>>>>>>>>>>>\n"); + printk(KERN_INFO "Initialized struct target_fabric_configfs: %p for" + " %s\n", tf, tf->tf_name); + return tf; +} +EXPORT_SYMBOL(target_fabric_configfs_init); + +/* + * Called by fabric plugins after FAILED target_fabric_configfs_register() call. + */ +void target_fabric_configfs_free( + struct target_fabric_configfs *tf) +{ + mutex_lock(&g_tf_lock); + list_del(&tf->tf_list); + mutex_unlock(&g_tf_lock); + + kfree(tf); +} +EXPORT_SYMBOL(target_fabric_configfs_free); + +/* + * Perform a sanity check of the passed tf->tf_ops before completing + * TCM fabric module registration. + */ +static int target_fabric_tf_ops_check( + struct target_fabric_configfs *tf) +{ + struct target_core_fabric_ops *tfo = &tf->tf_ops; + + if (!(tfo->get_fabric_name)) { + printk(KERN_ERR "Missing tfo->get_fabric_name()\n"); + return -EINVAL; + } + if (!(tfo->get_fabric_proto_ident)) { + printk(KERN_ERR "Missing tfo->get_fabric_proto_ident()\n"); + return -EINVAL; + } + if (!(tfo->tpg_get_wwn)) { + printk(KERN_ERR "Missing tfo->tpg_get_wwn()\n"); + return -EINVAL; + } + if (!(tfo->tpg_get_tag)) { + printk(KERN_ERR "Missing tfo->tpg_get_tag()\n"); + return -EINVAL; + } + if (!(tfo->tpg_get_default_depth)) { + printk(KERN_ERR "Missing tfo->tpg_get_default_depth()\n"); + return -EINVAL; + } + if (!(tfo->tpg_get_pr_transport_id)) { + printk(KERN_ERR "Missing tfo->tpg_get_pr_transport_id()\n"); + return -EINVAL; + } + if (!(tfo->tpg_get_pr_transport_id_len)) { + printk(KERN_ERR "Missing tfo->tpg_get_pr_transport_id_len()\n"); + return -EINVAL; + } + if (!(tfo->tpg_check_demo_mode)) { + printk(KERN_ERR "Missing tfo->tpg_check_demo_mode()\n"); + return -EINVAL; + } + if (!(tfo->tpg_check_demo_mode_cache)) { + printk(KERN_ERR "Missing tfo->tpg_check_demo_mode_cache()\n"); + return -EINVAL; + } + if (!(tfo->tpg_check_demo_mode_write_protect)) { + printk(KERN_ERR "Missing tfo->tpg_check_demo_mode_write_protect()\n"); + return -EINVAL; + } + if (!(tfo->tpg_check_prod_mode_write_protect)) { + printk(KERN_ERR "Missing tfo->tpg_check_prod_mode_write_protect()\n"); + return -EINVAL; + } + if (!(tfo->tpg_alloc_fabric_acl)) { + printk(KERN_ERR "Missing tfo->tpg_alloc_fabric_acl()\n"); + return -EINVAL; + } + if (!(tfo->tpg_release_fabric_acl)) { + printk(KERN_ERR "Missing tfo->tpg_release_fabric_acl()\n"); + return -EINVAL; + } + if (!(tfo->tpg_get_inst_index)) { + printk(KERN_ERR "Missing tfo->tpg_get_inst_index()\n"); + return -EINVAL; + } + if (!(tfo->release_cmd_to_pool)) { + printk(KERN_ERR "Missing tfo->release_cmd_to_pool()\n"); + return -EINVAL; + } + if (!(tfo->release_cmd_direct)) { + printk(KERN_ERR "Missing tfo->release_cmd_direct()\n"); + return -EINVAL; + } + if (!(tfo->shutdown_session)) { + printk(KERN_ERR "Missing tfo->shutdown_session()\n"); + return -EINVAL; + } + if (!(tfo->close_session)) { + printk(KERN_ERR "Missing tfo->close_session()\n"); + return -EINVAL; + } + if (!(tfo->stop_session)) { + printk(KERN_ERR "Missing tfo->stop_session()\n"); + return -EINVAL; + } + if (!(tfo->fall_back_to_erl0)) { + printk(KERN_ERR "Missing tfo->fall_back_to_erl0()\n"); + return -EINVAL; + } + if (!(tfo->sess_logged_in)) { + printk(KERN_ERR "Missing tfo->sess_logged_in()\n"); + return -EINVAL; + } + if (!(tfo->sess_get_index)) { + printk(KERN_ERR "Missing tfo->sess_get_index()\n"); + return -EINVAL; + } + if (!(tfo->write_pending)) { + printk(KERN_ERR "Missing tfo->write_pending()\n"); + return -EINVAL; + } + if (!(tfo->write_pending_status)) { + printk(KERN_ERR "Missing tfo->write_pending_status()\n"); + return -EINVAL; + } + if (!(tfo->set_default_node_attributes)) { + printk(KERN_ERR "Missing tfo->set_default_node_attributes()\n"); + return -EINVAL; + } + if (!(tfo->get_task_tag)) { + printk(KERN_ERR "Missing tfo->get_task_tag()\n"); + return -EINVAL; + } + if (!(tfo->get_cmd_state)) { + printk(KERN_ERR "Missing tfo->get_cmd_state()\n"); + return -EINVAL; + } + if (!(tfo->new_cmd_failure)) { + printk(KERN_ERR "Missing tfo->new_cmd_failure()\n"); + return -EINVAL; + } + if (!(tfo->queue_data_in)) { + printk(KERN_ERR "Missing tfo->queue_data_in()\n"); + return -EINVAL; + } + if (!(tfo->queue_status)) { + printk(KERN_ERR "Missing tfo->queue_status()\n"); + return -EINVAL; + } + if (!(tfo->queue_tm_rsp)) { + printk(KERN_ERR "Missing tfo->queue_tm_rsp()\n"); + return -EINVAL; + } + if (!(tfo->set_fabric_sense_len)) { + printk(KERN_ERR "Missing tfo->set_fabric_sense_len()\n"); + return -EINVAL; + } + if (!(tfo->get_fabric_sense_len)) { + printk(KERN_ERR "Missing tfo->get_fabric_sense_len()\n"); + return -EINVAL; + } + if (!(tfo->is_state_remove)) { + printk(KERN_ERR "Missing tfo->is_state_remove()\n"); + return -EINVAL; + } + if (!(tfo->pack_lun)) { + printk(KERN_ERR "Missing tfo->pack_lun()\n"); + return -EINVAL; + } + /* + * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn() + * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in + * target_core_fabric_configfs.c WWN+TPG group context code. + */ + if (!(tfo->fabric_make_wwn)) { + printk(KERN_ERR "Missing tfo->fabric_make_wwn()\n"); + return -EINVAL; + } + if (!(tfo->fabric_drop_wwn)) { + printk(KERN_ERR "Missing tfo->fabric_drop_wwn()\n"); + return -EINVAL; + } + if (!(tfo->fabric_make_tpg)) { + printk(KERN_ERR "Missing tfo->fabric_make_tpg()\n"); + return -EINVAL; + } + if (!(tfo->fabric_drop_tpg)) { + printk(KERN_ERR "Missing tfo->fabric_drop_tpg()\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Called 2nd from fabric module with returned parameter of + * struct target_fabric_configfs * from target_fabric_configfs_init(). + * + * Upon a successful registration, the new fabric's struct config_item is + * return. Also, a pointer to this struct is set in the passed + * struct target_fabric_configfs. + */ +int target_fabric_configfs_register( + struct target_fabric_configfs *tf) +{ + struct config_group *su_group; + int ret; + + if (!(tf)) { + printk(KERN_ERR "Unable to locate target_fabric_configfs" + " pointer\n"); + return -EINVAL; + } + if (!(tf->tf_subsys)) { + printk(KERN_ERR "Unable to target struct config_subsystem" + " pointer\n"); + return -EINVAL; + } + su_group = &tf->tf_subsys->su_group; + if (!(su_group)) { + printk(KERN_ERR "Unable to locate target struct config_group" + " pointer\n"); + return -EINVAL; + } + ret = target_fabric_tf_ops_check(tf); + if (ret < 0) + return ret; + + printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>" + ">>>>>>>>>>\n"); + return 0; +} +EXPORT_SYMBOL(target_fabric_configfs_register); + +void target_fabric_configfs_deregister( + struct target_fabric_configfs *tf) +{ + struct config_group *su_group; + struct configfs_subsystem *su; + + if (!(tf)) { + printk(KERN_ERR "Unable to locate passed target_fabric_" + "configfs\n"); + return; + } + su = tf->tf_subsys; + if (!(su)) { + printk(KERN_ERR "Unable to locate passed tf->tf_subsys" + " pointer\n"); + return; + } + su_group = &tf->tf_subsys->su_group; + if (!(su_group)) { + printk(KERN_ERR "Unable to locate target struct config_group" + " pointer\n"); + return; + } + + printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>" + ">>>>>>>>>>>>\n"); + mutex_lock(&g_tf_lock); + if (atomic_read(&tf->tf_access_cnt)) { + mutex_unlock(&g_tf_lock); + printk(KERN_ERR "Non zero tf->tf_access_cnt for fabric %s\n", + tf->tf_name); + BUG(); + } + list_del(&tf->tf_list); + mutex_unlock(&g_tf_lock); + + printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing tf:" + " %s\n", tf->tf_name); + tf->tf_module = NULL; + tf->tf_subsys = NULL; + kfree(tf); + + printk("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>" + ">>>>>\n"); + return; +} +EXPORT_SYMBOL(target_fabric_configfs_deregister); + +/*############################################################################## +// Stop functions called by external Target Fabrics Modules +//############################################################################*/ + +/* Start functions for struct config_item_type target_core_dev_attrib_cit */ + +#define DEF_DEV_ATTRIB_SHOW(_name) \ +static ssize_t target_core_dev_show_attr_##_name( \ + struct se_dev_attrib *da, \ + char *page) \ +{ \ + struct se_device *dev; \ + struct se_subsystem_dev *se_dev = da->da_sub_dev; \ + ssize_t rb; \ + \ + spin_lock(&se_dev->se_dev_lock); \ + dev = se_dev->se_dev_ptr; \ + if (!(dev)) { \ + spin_unlock(&se_dev->se_dev_lock); \ + return -ENODEV; \ + } \ + rb = snprintf(page, PAGE_SIZE, "%u\n", (u32)DEV_ATTRIB(dev)->_name); \ + spin_unlock(&se_dev->se_dev_lock); \ + \ + return rb; \ +} + +#define DEF_DEV_ATTRIB_STORE(_name) \ +static ssize_t target_core_dev_store_attr_##_name( \ + struct se_dev_attrib *da, \ + const char *page, \ + size_t count) \ +{ \ + struct se_device *dev; \ + struct se_subsystem_dev *se_dev = da->da_sub_dev; \ + unsigned long val; \ + int ret; \ + \ + spin_lock(&se_dev->se_dev_lock); \ + dev = se_dev->se_dev_ptr; \ + if (!(dev)) { \ + spin_unlock(&se_dev->se_dev_lock); \ + return -ENODEV; \ + } \ + ret = strict_strtoul(page, 0, &val); \ + if (ret < 0) { \ + spin_unlock(&se_dev->se_dev_lock); \ + printk(KERN_ERR "strict_strtoul() failed with" \ + " ret: %d\n", ret); \ + return -EINVAL; \ + } \ + ret = se_dev_set_##_name(dev, (u32)val); \ + spin_unlock(&se_dev->se_dev_lock); \ + \ + return (!ret) ? count : -EINVAL; \ +} + +#define DEF_DEV_ATTRIB(_name) \ +DEF_DEV_ATTRIB_SHOW(_name); \ +DEF_DEV_ATTRIB_STORE(_name); + +#define DEF_DEV_ATTRIB_RO(_name) \ +DEF_DEV_ATTRIB_SHOW(_name); + +CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib); +#define SE_DEV_ATTR(_name, _mode) \ +static struct target_core_dev_attrib_attribute \ + target_core_dev_attrib_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_core_dev_show_attr_##_name, \ + target_core_dev_store_attr_##_name); + +#define SE_DEV_ATTR_RO(_name); \ +static struct target_core_dev_attrib_attribute \ + target_core_dev_attrib_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_core_dev_show_attr_##_name); + +DEF_DEV_ATTRIB(emulate_dpo); +SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_fua_write); +SE_DEV_ATTR(emulate_fua_write, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_fua_read); +SE_DEV_ATTR(emulate_fua_read, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_write_cache); +SE_DEV_ATTR(emulate_write_cache, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_ua_intlck_ctrl); +SE_DEV_ATTR(emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_tas); +SE_DEV_ATTR(emulate_tas, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_tpu); +SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(emulate_tpws); +SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(enforce_pr_isids); +SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB_RO(hw_block_size); +SE_DEV_ATTR_RO(hw_block_size); + +DEF_DEV_ATTRIB(block_size); +SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB_RO(hw_max_sectors); +SE_DEV_ATTR_RO(hw_max_sectors); + +DEF_DEV_ATTRIB(max_sectors); +SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(optimal_sectors); +SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB_RO(hw_queue_depth); +SE_DEV_ATTR_RO(hw_queue_depth); + +DEF_DEV_ATTRIB(queue_depth); +SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(task_timeout); +SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(max_unmap_lba_count); +SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(max_unmap_block_desc_count); +SE_DEV_ATTR(max_unmap_block_desc_count, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(unmap_granularity); +SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR); + +DEF_DEV_ATTRIB(unmap_granularity_alignment); +SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR); + +CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); + +static struct configfs_attribute *target_core_dev_attrib_attrs[] = { + &target_core_dev_attrib_emulate_dpo.attr, + &target_core_dev_attrib_emulate_fua_write.attr, + &target_core_dev_attrib_emulate_fua_read.attr, + &target_core_dev_attrib_emulate_write_cache.attr, + &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr, + &target_core_dev_attrib_emulate_tas.attr, + &target_core_dev_attrib_emulate_tpu.attr, + &target_core_dev_attrib_emulate_tpws.attr, + &target_core_dev_attrib_enforce_pr_isids.attr, + &target_core_dev_attrib_hw_block_size.attr, + &target_core_dev_attrib_block_size.attr, + &target_core_dev_attrib_hw_max_sectors.attr, + &target_core_dev_attrib_max_sectors.attr, + &target_core_dev_attrib_optimal_sectors.attr, + &target_core_dev_attrib_hw_queue_depth.attr, + &target_core_dev_attrib_queue_depth.attr, + &target_core_dev_attrib_task_timeout.attr, + &target_core_dev_attrib_max_unmap_lba_count.attr, + &target_core_dev_attrib_max_unmap_block_desc_count.attr, + &target_core_dev_attrib_unmap_granularity.attr, + &target_core_dev_attrib_unmap_granularity_alignment.attr, + NULL, +}; + +static struct configfs_item_operations target_core_dev_attrib_ops = { + .show_attribute = target_core_dev_attrib_attr_show, + .store_attribute = target_core_dev_attrib_attr_store, +}; + +static struct config_item_type target_core_dev_attrib_cit = { + .ct_item_ops = &target_core_dev_attrib_ops, + .ct_attrs = target_core_dev_attrib_attrs, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_dev_attrib_cit */ + +/* Start functions for struct config_item_type target_core_dev_wwn_cit */ + +CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn); +#define SE_DEV_WWN_ATTR(_name, _mode) \ +static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_core_dev_wwn_show_attr_##_name, \ + target_core_dev_wwn_store_attr_##_name); + +#define SE_DEV_WWN_ATTR_RO(_name); \ +do { \ + static struct target_core_dev_wwn_attribute \ + target_core_dev_wwn_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_core_dev_wwn_show_attr_##_name); \ +} while (0); + +/* + * VPD page 0x80 Unit serial + */ +static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial( + struct t10_wwn *t10_wwn, + char *page) +{ + struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; + struct se_device *dev; + + dev = se_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + return sprintf(page, "T10 VPD Unit Serial Number: %s\n", + &t10_wwn->unit_serial[0]); +} + +static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial( + struct t10_wwn *t10_wwn, + const char *page, + size_t count) +{ + struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev; + struct se_device *dev; + unsigned char buf[INQUIRY_VPD_SERIAL_LEN]; + + /* + * If Linux/SCSI subsystem_api_t plugin got a VPD Unit Serial + * from the struct scsi_device level firmware, do not allow + * VPD Unit Serial to be emulated. + * + * Note this struct scsi_device could also be emulating VPD + * information from its drivers/scsi LLD. But for now we assume + * it is doing 'the right thing' wrt a world wide unique + * VPD Unit Serial Number that OS dependent multipath can depend on. + */ + if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) { + printk(KERN_ERR "Underlying SCSI device firmware provided VPD" + " Unit Serial, ignoring request\n"); + return -EOPNOTSUPP; + } + + if ((strlen(page) + 1) > INQUIRY_VPD_SERIAL_LEN) { + printk(KERN_ERR "Emulated VPD Unit Serial exceeds" + " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN); + return -EOVERFLOW; + } + /* + * Check to see if any active $FABRIC_MOD exports exist. If they + * do exist, fail here as changing this information on the fly + * (underneath the initiator side OS dependent multipath code) + * could cause negative effects. + */ + dev = su_dev->se_dev_ptr; + if ((dev)) { + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "Unable to set VPD Unit Serial while" + " active %d $FABRIC_MOD exports exist\n", + atomic_read(&dev->dev_export_obj.obj_access_count)); + return -EINVAL; + } + } + /* + * This currently assumes ASCII encoding for emulated VPD Unit Serial. + * + * Also, strip any newline added from the userspace + * echo $UUID > $TARGET/$HBA/$STORAGE_OBJECT/wwn/vpd_unit_serial + */ + memset(buf, 0, INQUIRY_VPD_SERIAL_LEN); + snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page); + snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN, + "%s", strstrip(buf)); + su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL; + + printk(KERN_INFO "Target_Core_ConfigFS: Set emulated VPD Unit Serial:" + " %s\n", su_dev->t10_wwn.unit_serial); + + return count; +} + +SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR); + +/* + * VPD page 0x83 Protocol Identifier + */ +static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier( + struct t10_wwn *t10_wwn, + char *page) +{ + struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; + struct se_device *dev; + struct t10_vpd *vpd; + unsigned char buf[VPD_TMP_BUF_SIZE]; + ssize_t len = 0; + + dev = se_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + memset(buf, 0, VPD_TMP_BUF_SIZE); + + spin_lock(&t10_wwn->t10_vpd_lock); + list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { + if (!(vpd->protocol_identifier_set)) + continue; + + transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE); + + if ((len + strlen(buf) > PAGE_SIZE)) + break; + + len += sprintf(page+len, "%s", buf); + } + spin_unlock(&t10_wwn->t10_vpd_lock); + + return len; +} + +static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier( + struct t10_wwn *t10_wwn, + const char *page, + size_t count) +{ + return -ENOSYS; +} + +SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR); + +/* + * Generic wrapper for dumping VPD identifiers by association. + */ +#define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \ +static ssize_t target_core_dev_wwn_show_attr_##_name( \ + struct t10_wwn *t10_wwn, \ + char *page) \ +{ \ + struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; \ + struct se_device *dev; \ + struct t10_vpd *vpd; \ + unsigned char buf[VPD_TMP_BUF_SIZE]; \ + ssize_t len = 0; \ + \ + dev = se_dev->se_dev_ptr; \ + if (!(dev)) \ + return -ENODEV; \ + \ + spin_lock(&t10_wwn->t10_vpd_lock); \ + list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { \ + if (vpd->association != _assoc) \ + continue; \ + \ + memset(buf, 0, VPD_TMP_BUF_SIZE); \ + transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE); \ + if ((len + strlen(buf) > PAGE_SIZE)) \ + break; \ + len += sprintf(page+len, "%s", buf); \ + \ + memset(buf, 0, VPD_TMP_BUF_SIZE); \ + transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \ + if ((len + strlen(buf) > PAGE_SIZE)) \ + break; \ + len += sprintf(page+len, "%s", buf); \ + \ + memset(buf, 0, VPD_TMP_BUF_SIZE); \ + transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \ + if ((len + strlen(buf) > PAGE_SIZE)) \ + break; \ + len += sprintf(page+len, "%s", buf); \ + } \ + spin_unlock(&t10_wwn->t10_vpd_lock); \ + \ + return len; \ +} + +/* + * VPD page 0x83 Assoication: Logical Unit + */ +DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00); + +static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit( + struct t10_wwn *t10_wwn, + const char *page, + size_t count) +{ + return -ENOSYS; +} + +SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR); + +/* + * VPD page 0x83 Association: Target Port + */ +DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10); + +static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port( + struct t10_wwn *t10_wwn, + const char *page, + size_t count) +{ + return -ENOSYS; +} + +SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR); + +/* + * VPD page 0x83 Association: SCSI Target Device + */ +DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20); + +static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device( + struct t10_wwn *t10_wwn, + const char *page, + size_t count) +{ + return -ENOSYS; +} + +SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR); + +CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group); + +static struct configfs_attribute *target_core_dev_wwn_attrs[] = { + &target_core_dev_wwn_vpd_unit_serial.attr, + &target_core_dev_wwn_vpd_protocol_identifier.attr, + &target_core_dev_wwn_vpd_assoc_logical_unit.attr, + &target_core_dev_wwn_vpd_assoc_target_port.attr, + &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr, + NULL, +}; + +static struct configfs_item_operations target_core_dev_wwn_ops = { + .show_attribute = target_core_dev_wwn_attr_show, + .store_attribute = target_core_dev_wwn_attr_store, +}; + +static struct config_item_type target_core_dev_wwn_cit = { + .ct_item_ops = &target_core_dev_wwn_ops, + .ct_attrs = target_core_dev_wwn_attrs, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_dev_wwn_cit */ + +/* Start functions for struct config_item_type target_core_dev_pr_cit */ + +CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev); +#define SE_DEV_PR_ATTR(_name, _mode) \ +static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_core_dev_pr_show_attr_##_name, \ + target_core_dev_pr_store_attr_##_name); + +#define SE_DEV_PR_ATTR_RO(_name); \ +static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_core_dev_pr_show_attr_##_name); + +/* + * res_holder + */ +static ssize_t target_core_dev_pr_show_spc3_res( + struct se_device *dev, + char *page, + ssize_t *len) +{ + struct se_node_acl *se_nacl; + struct t10_pr_registration *pr_reg; + char i_buf[PR_REG_ISID_ID_LEN]; + int prf_isid; + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + + spin_lock(&dev->dev_reservation_lock); + pr_reg = dev->dev_pr_res_holder; + if (!(pr_reg)) { + *len += sprintf(page + *len, "No SPC-3 Reservation holder\n"); + spin_unlock(&dev->dev_reservation_lock); + return *len; + } + se_nacl = pr_reg->pr_reg_nacl; + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + + *len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n", + TPG_TFO(se_nacl->se_tpg)->get_fabric_name(), + se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); + spin_unlock(&dev->dev_reservation_lock); + + return *len; +} + +static ssize_t target_core_dev_pr_show_spc2_res( + struct se_device *dev, + char *page, + ssize_t *len) +{ + struct se_node_acl *se_nacl; + + spin_lock(&dev->dev_reservation_lock); + se_nacl = dev->dev_reserved_node_acl; + if (!(se_nacl)) { + *len += sprintf(page + *len, "No SPC-2 Reservation holder\n"); + spin_unlock(&dev->dev_reservation_lock); + return *len; + } + *len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n", + TPG_TFO(se_nacl->se_tpg)->get_fabric_name(), + se_nacl->initiatorname); + spin_unlock(&dev->dev_reservation_lock); + + return *len; +} + +static ssize_t target_core_dev_pr_show_attr_res_holder( + struct se_subsystem_dev *su_dev, + char *page) +{ + ssize_t len = 0; + + if (!(su_dev->se_dev_ptr)) + return -ENODEV; + + switch (T10_RES(su_dev)->res_type) { + case SPC3_PERSISTENT_RESERVATIONS: + target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr, + page, &len); + break; + case SPC2_RESERVATIONS: + target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr, + page, &len); + break; + case SPC_PASSTHROUGH: + len += sprintf(page+len, "Passthrough\n"); + break; + default: + len += sprintf(page+len, "Unknown\n"); + break; + } + + return len; +} + +SE_DEV_PR_ATTR_RO(res_holder); + +/* + * res_pr_all_tgt_pts + */ +static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts( + struct se_subsystem_dev *su_dev, + char *page) +{ + struct se_device *dev; + struct t10_pr_registration *pr_reg; + ssize_t len = 0; + + dev = su_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return len; + + spin_lock(&dev->dev_reservation_lock); + pr_reg = dev->dev_pr_res_holder; + if (!(pr_reg)) { + len = sprintf(page, "No SPC-3 Reservation holder\n"); + spin_unlock(&dev->dev_reservation_lock); + return len; + } + /* + * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3 + * Basic PERSISTENT RESERVER OUT parameter list, page 290 + */ + if (pr_reg->pr_reg_all_tg_pt) + len = sprintf(page, "SPC-3 Reservation: All Target" + " Ports registration\n"); + else + len = sprintf(page, "SPC-3 Reservation: Single" + " Target Port registration\n"); + spin_unlock(&dev->dev_reservation_lock); + + return len; +} + +SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts); + +/* + * res_pr_generation + */ +static ssize_t target_core_dev_pr_show_attr_res_pr_generation( + struct se_subsystem_dev *su_dev, + char *page) +{ + if (!(su_dev->se_dev_ptr)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return 0; + + return sprintf(page, "0x%08x\n", T10_RES(su_dev)->pr_generation); +} + +SE_DEV_PR_ATTR_RO(res_pr_generation); + +/* + * res_pr_holder_tg_port + */ +static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( + struct se_subsystem_dev *su_dev, + char *page) +{ + struct se_device *dev; + struct se_node_acl *se_nacl; + struct se_lun *lun; + struct se_portal_group *se_tpg; + struct t10_pr_registration *pr_reg; + struct target_core_fabric_ops *tfo; + ssize_t len = 0; + + dev = su_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return len; + + spin_lock(&dev->dev_reservation_lock); + pr_reg = dev->dev_pr_res_holder; + if (!(pr_reg)) { + len = sprintf(page, "No SPC-3 Reservation holder\n"); + spin_unlock(&dev->dev_reservation_lock); + return len; + } + se_nacl = pr_reg->pr_reg_nacl; + se_tpg = se_nacl->se_tpg; + lun = pr_reg->pr_reg_tg_pt_lun; + tfo = TPG_TFO(se_tpg); + + len += sprintf(page+len, "SPC-3 Reservation: %s" + " Target Node Endpoint: %s\n", tfo->get_fabric_name(), + tfo->tpg_get_wwn(se_tpg)); + len += sprintf(page+len, "SPC-3 Reservation: Relative Port" + " Identifer Tag: %hu %s Portal Group Tag: %hu" + " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi, + tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), + tfo->get_fabric_name(), lun->unpacked_lun); + spin_unlock(&dev->dev_reservation_lock); + + return len; +} + +SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); + +/* + * res_pr_registered_i_pts + */ +static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( + struct se_subsystem_dev *su_dev, + char *page) +{ + struct target_core_fabric_ops *tfo; + struct t10_pr_registration *pr_reg; + unsigned char buf[384]; + char i_buf[PR_REG_ISID_ID_LEN]; + ssize_t len = 0; + int reg_count = 0, prf_isid; + + if (!(su_dev->se_dev_ptr)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return len; + + len += sprintf(page+len, "SPC-3 PR Registrations:\n"); + + spin_lock(&T10_RES(su_dev)->registration_lock); + list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list, + pr_reg_list) { + + memset(buf, 0, 384); + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n", + tfo->get_fabric_name(), + pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ? + &i_buf[0] : "", pr_reg->pr_res_key, + pr_reg->pr_res_generation); + + if ((len + strlen(buf) > PAGE_SIZE)) + break; + + len += sprintf(page+len, "%s", buf); + reg_count++; + } + spin_unlock(&T10_RES(su_dev)->registration_lock); + + if (!(reg_count)) + len += sprintf(page+len, "None\n"); + + return len; +} + +SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts); + +/* + * res_pr_type + */ +static ssize_t target_core_dev_pr_show_attr_res_pr_type( + struct se_subsystem_dev *su_dev, + char *page) +{ + struct se_device *dev; + struct t10_pr_registration *pr_reg; + ssize_t len = 0; + + dev = su_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return len; + + spin_lock(&dev->dev_reservation_lock); + pr_reg = dev->dev_pr_res_holder; + if (!(pr_reg)) { + len = sprintf(page, "No SPC-3 Reservation holder\n"); + spin_unlock(&dev->dev_reservation_lock); + return len; + } + len = sprintf(page, "SPC-3 Reservation Type: %s\n", + core_scsi3_pr_dump_type(pr_reg->pr_res_type)); + spin_unlock(&dev->dev_reservation_lock); + + return len; +} + +SE_DEV_PR_ATTR_RO(res_pr_type); + +/* + * res_type + */ +static ssize_t target_core_dev_pr_show_attr_res_type( + struct se_subsystem_dev *su_dev, + char *page) +{ + ssize_t len = 0; + + if (!(su_dev->se_dev_ptr)) + return -ENODEV; + + switch (T10_RES(su_dev)->res_type) { + case SPC3_PERSISTENT_RESERVATIONS: + len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n"); + break; + case SPC2_RESERVATIONS: + len = sprintf(page, "SPC2_RESERVATIONS\n"); + break; + case SPC_PASSTHROUGH: + len = sprintf(page, "SPC_PASSTHROUGH\n"); + break; + default: + len = sprintf(page, "UNKNOWN\n"); + break; + } + + return len; +} + +SE_DEV_PR_ATTR_RO(res_type); + +/* + * res_aptpl_active + */ + +static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( + struct se_subsystem_dev *su_dev, + char *page) +{ + if (!(su_dev->se_dev_ptr)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return 0; + + return sprintf(page, "APTPL Bit Status: %s\n", + (T10_RES(su_dev)->pr_aptpl_active) ? "Activated" : "Disabled"); +} + +SE_DEV_PR_ATTR_RO(res_aptpl_active); + +/* + * res_aptpl_metadata + */ +static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( + struct se_subsystem_dev *su_dev, + char *page) +{ + if (!(su_dev->se_dev_ptr)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return 0; + + return sprintf(page, "Ready to process PR APTPL metadata..\n"); +} + +enum { + Opt_initiator_fabric, Opt_initiator_node, Opt_initiator_sid, + Opt_sa_res_key, Opt_res_holder, Opt_res_type, Opt_res_scope, + Opt_res_all_tg_pt, Opt_mapped_lun, Opt_target_fabric, + Opt_target_node, Opt_tpgt, Opt_port_rtpi, Opt_target_lun, Opt_err +}; + +static match_table_t tokens = { + {Opt_initiator_fabric, "initiator_fabric=%s"}, + {Opt_initiator_node, "initiator_node=%s"}, + {Opt_initiator_sid, "initiator_sid=%s"}, + {Opt_sa_res_key, "sa_res_key=%s"}, + {Opt_res_holder, "res_holder=%d"}, + {Opt_res_type, "res_type=%d"}, + {Opt_res_scope, "res_scope=%d"}, + {Opt_res_all_tg_pt, "res_all_tg_pt=%d"}, + {Opt_mapped_lun, "mapped_lun=%d"}, + {Opt_target_fabric, "target_fabric=%s"}, + {Opt_target_node, "target_node=%s"}, + {Opt_tpgt, "tpgt=%d"}, + {Opt_port_rtpi, "port_rtpi=%d"}, + {Opt_target_lun, "target_lun=%d"}, + {Opt_err, NULL} +}; + +static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( + struct se_subsystem_dev *su_dev, + const char *page, + size_t count) +{ + struct se_device *dev; + unsigned char *i_fabric, *t_fabric, *i_port = NULL, *t_port = NULL; + unsigned char *isid = NULL; + char *orig, *ptr, *arg_p, *opts; + substring_t args[MAX_OPT_ARGS]; + unsigned long long tmp_ll; + u64 sa_res_key = 0; + u32 mapped_lun = 0, target_lun = 0; + int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token; + u16 port_rpti = 0, tpgt = 0; + u8 type = 0, scope; + + dev = su_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return 0; + + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_INFO "Unable to process APTPL metadata while" + " active fabric exports exist\n"); + return -EINVAL; + } + + opts = kstrdup(page, GFP_KERNEL); + if (!opts) + return -ENOMEM; + + orig = opts; + while ((ptr = strsep(&opts, ",")) != NULL) { + if (!*ptr) + continue; + + token = match_token(ptr, tokens, args); + switch (token) { + case Opt_initiator_fabric: + i_fabric = match_strdup(&args[0]); + break; + case Opt_initiator_node: + i_port = match_strdup(&args[0]); + if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { + printk(KERN_ERR "APTPL metadata initiator_node=" + " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", + PR_APTPL_MAX_IPORT_LEN); + ret = -EINVAL; + break; + } + break; + case Opt_initiator_sid: + isid = match_strdup(&args[0]); + if (strlen(isid) > PR_REG_ISID_LEN) { + printk(KERN_ERR "APTPL metadata initiator_isid" + "= exceeds PR_REG_ISID_LEN: %d\n", + PR_REG_ISID_LEN); + ret = -EINVAL; + break; + } + break; + case Opt_sa_res_key: + arg_p = match_strdup(&args[0]); + ret = strict_strtoull(arg_p, 0, &tmp_ll); + if (ret < 0) { + printk(KERN_ERR "strict_strtoull() failed for" + " sa_res_key=\n"); + goto out; + } + sa_res_key = (u64)tmp_ll; + break; + /* + * PR APTPL Metadata for Reservation + */ + case Opt_res_holder: + match_int(args, &arg); + res_holder = arg; + break; + case Opt_res_type: + match_int(args, &arg); + type = (u8)arg; + break; + case Opt_res_scope: + match_int(args, &arg); + scope = (u8)arg; + break; + case Opt_res_all_tg_pt: + match_int(args, &arg); + all_tg_pt = (int)arg; + break; + case Opt_mapped_lun: + match_int(args, &arg); + mapped_lun = (u32)arg; + break; + /* + * PR APTPL Metadata for Target Port + */ + case Opt_target_fabric: + t_fabric = match_strdup(&args[0]); + break; + case Opt_target_node: + t_port = match_strdup(&args[0]); + if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { + printk(KERN_ERR "APTPL metadata target_node=" + " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", + PR_APTPL_MAX_TPORT_LEN); + ret = -EINVAL; + break; + } + break; + case Opt_tpgt: + match_int(args, &arg); + tpgt = (u16)arg; + break; + case Opt_port_rtpi: + match_int(args, &arg); + port_rpti = (u16)arg; + break; + case Opt_target_lun: + match_int(args, &arg); + target_lun = (u32)arg; + break; + default: + break; + } + } + + if (!(i_port) || !(t_port) || !(sa_res_key)) { + printk(KERN_ERR "Illegal parameters for APTPL registration\n"); + ret = -EINVAL; + goto out; + } + + if (res_holder && !(type)) { + printk(KERN_ERR "Illegal PR type: 0x%02x for reservation" + " holder\n", type); + ret = -EINVAL; + goto out; + } + + ret = core_scsi3_alloc_aptpl_registration(T10_RES(su_dev), sa_res_key, + i_port, isid, mapped_lun, t_port, tpgt, target_lun, + res_holder, all_tg_pt, type); +out: + kfree(orig); + return (ret == 0) ? count : ret; +} + +SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR); + +CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group); + +static struct configfs_attribute *target_core_dev_pr_attrs[] = { + &target_core_dev_pr_res_holder.attr, + &target_core_dev_pr_res_pr_all_tgt_pts.attr, + &target_core_dev_pr_res_pr_generation.attr, + &target_core_dev_pr_res_pr_holder_tg_port.attr, + &target_core_dev_pr_res_pr_registered_i_pts.attr, + &target_core_dev_pr_res_pr_type.attr, + &target_core_dev_pr_res_type.attr, + &target_core_dev_pr_res_aptpl_active.attr, + &target_core_dev_pr_res_aptpl_metadata.attr, + NULL, +}; + +static struct configfs_item_operations target_core_dev_pr_ops = { + .show_attribute = target_core_dev_pr_attr_show, + .store_attribute = target_core_dev_pr_attr_store, +}; + +static struct config_item_type target_core_dev_pr_cit = { + .ct_item_ops = &target_core_dev_pr_ops, + .ct_attrs = target_core_dev_pr_attrs, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_dev_pr_cit */ + +/* Start functions for struct config_item_type target_core_dev_cit */ + +static ssize_t target_core_show_dev_info(void *p, char *page) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_hba *hba = se_dev->se_dev_hba; + struct se_subsystem_api *t = hba->transport; + int bl = 0; + ssize_t read_bytes = 0; + + if (!(se_dev->se_dev_ptr)) + return -ENODEV; + + transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl); + read_bytes += bl; + read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes); + return read_bytes; +} + +static struct target_core_configfs_attribute target_core_attr_dev_info = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "info", + .ca_mode = S_IRUGO }, + .show = target_core_show_dev_info, + .store = NULL, +}; + +static ssize_t target_core_store_dev_control( + void *p, + const char *page, + size_t count) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_hba *hba = se_dev->se_dev_hba; + struct se_subsystem_api *t = hba->transport; + + if (!(se_dev->se_dev_su_ptr)) { + printk(KERN_ERR "Unable to locate struct se_subsystem_dev>se" + "_dev_su_ptr\n"); + return -EINVAL; + } + + return t->set_configfs_dev_params(hba, se_dev, page, count); +} + +static struct target_core_configfs_attribute target_core_attr_dev_control = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "control", + .ca_mode = S_IWUSR }, + .show = NULL, + .store = target_core_store_dev_control, +}; + +static ssize_t target_core_show_dev_alias(void *p, char *page) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + + if (!(se_dev->su_dev_flags & SDF_USING_ALIAS)) + return 0; + + return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias); +} + +static ssize_t target_core_store_dev_alias( + void *p, + const char *page, + size_t count) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_hba *hba = se_dev->se_dev_hba; + ssize_t read_bytes; + + if (count > (SE_DEV_ALIAS_LEN-1)) { + printk(KERN_ERR "alias count: %d exceeds" + " SE_DEV_ALIAS_LEN-1: %u\n", (int)count, + SE_DEV_ALIAS_LEN-1); + return -EINVAL; + } + + se_dev->su_dev_flags |= SDF_USING_ALIAS; + read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, + "%s", page); + + printk(KERN_INFO "Target_Core_ConfigFS: %s/%s set alias: %s\n", + config_item_name(&hba->hba_group.cg_item), + config_item_name(&se_dev->se_dev_group.cg_item), + se_dev->se_dev_alias); + + return read_bytes; +} + +static struct target_core_configfs_attribute target_core_attr_dev_alias = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "alias", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = target_core_show_dev_alias, + .store = target_core_store_dev_alias, +}; + +static ssize_t target_core_show_dev_udev_path(void *p, char *page) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + + if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) + return 0; + + return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path); +} + +static ssize_t target_core_store_dev_udev_path( + void *p, + const char *page, + size_t count) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_hba *hba = se_dev->se_dev_hba; + ssize_t read_bytes; + + if (count > (SE_UDEV_PATH_LEN-1)) { + printk(KERN_ERR "udev_path count: %d exceeds" + " SE_UDEV_PATH_LEN-1: %u\n", (int)count, + SE_UDEV_PATH_LEN-1); + return -EINVAL; + } + + se_dev->su_dev_flags |= SDF_USING_UDEV_PATH; + read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, + "%s", page); + + printk(KERN_INFO "Target_Core_ConfigFS: %s/%s set udev_path: %s\n", + config_item_name(&hba->hba_group.cg_item), + config_item_name(&se_dev->se_dev_group.cg_item), + se_dev->se_dev_udev_path); + + return read_bytes; +} + +static struct target_core_configfs_attribute target_core_attr_dev_udev_path = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "udev_path", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = target_core_show_dev_udev_path, + .store = target_core_store_dev_udev_path, +}; + +static ssize_t target_core_store_dev_enable( + void *p, + const char *page, + size_t count) +{ + struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_device *dev; + struct se_hba *hba = se_dev->se_dev_hba; + struct se_subsystem_api *t = hba->transport; + char *ptr; + + ptr = strstr(page, "1"); + if (!(ptr)) { + printk(KERN_ERR "For dev_enable ops, only valid value" + " is \"1\"\n"); + return -EINVAL; + } + if ((se_dev->se_dev_ptr)) { + printk(KERN_ERR "se_dev->se_dev_ptr already set for storage" + " object\n"); + return -EEXIST; + } + + if (t->check_configfs_dev_params(hba, se_dev) < 0) + return -EINVAL; + + dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); + if (!(dev) || IS_ERR(dev)) + return -EINVAL; + + se_dev->se_dev_ptr = dev; + printk(KERN_INFO "Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:" + " %p\n", se_dev->se_dev_ptr); + + return count; +} + +static struct target_core_configfs_attribute target_core_attr_dev_enable = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "enable", + .ca_mode = S_IWUSR }, + .show = NULL, + .store = target_core_store_dev_enable, +}; + +static ssize_t target_core_show_alua_lu_gp(void *p, char *page) +{ + struct se_device *dev; + struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p; + struct config_item *lu_ci; + struct t10_alua_lu_gp *lu_gp; + struct t10_alua_lu_gp_member *lu_gp_mem; + ssize_t len = 0; + + dev = su_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) + return len; + + lu_gp_mem = dev->dev_alua_lu_gp_mem; + if (!(lu_gp_mem)) { + printk(KERN_ERR "NULL struct se_device->dev_alua_lu_gp_mem" + " pointer\n"); + return -EINVAL; + } + + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + lu_gp = lu_gp_mem->lu_gp; + if ((lu_gp)) { + lu_ci = &lu_gp->lu_gp_group.cg_item; + len += sprintf(page, "LU Group Alias: %s\nLU Group ID: %hu\n", + config_item_name(lu_ci), lu_gp->lu_gp_id); + } + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + return len; +} + +static ssize_t target_core_store_alua_lu_gp( + void *p, + const char *page, + size_t count) +{ + struct se_device *dev; + struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p; + struct se_hba *hba = su_dev->se_dev_hba; + struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL; + struct t10_alua_lu_gp_member *lu_gp_mem; + unsigned char buf[LU_GROUP_NAME_BUF]; + int move = 0; + + dev = su_dev->se_dev_ptr; + if (!(dev)) + return -ENODEV; + + if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) { + printk(KERN_WARNING "SPC3_ALUA_EMULATED not enabled for %s/%s\n", + config_item_name(&hba->hba_group.cg_item), + config_item_name(&su_dev->se_dev_group.cg_item)); + return -EINVAL; + } + if (count > LU_GROUP_NAME_BUF) { + printk(KERN_ERR "ALUA LU Group Alias too large!\n"); + return -EINVAL; + } + memset(buf, 0, LU_GROUP_NAME_BUF); + memcpy(buf, page, count); + /* + * Any ALUA logical unit alias besides "NULL" means we will be + * making a new group association. + */ + if (strcmp(strstrip(buf), "NULL")) { + /* + * core_alua_get_lu_gp_by_name() will increment reference to + * struct t10_alua_lu_gp. This reference is released with + * core_alua_get_lu_gp_by_name below(). + */ + lu_gp_new = core_alua_get_lu_gp_by_name(strstrip(buf)); + if (!(lu_gp_new)) + return -ENODEV; + } + lu_gp_mem = dev->dev_alua_lu_gp_mem; + if (!(lu_gp_mem)) { + if (lu_gp_new) + core_alua_put_lu_gp_from_name(lu_gp_new); + printk(KERN_ERR "NULL struct se_device->dev_alua_lu_gp_mem" + " pointer\n"); + return -EINVAL; + } + + spin_lock(&lu_gp_mem->lu_gp_mem_lock); + lu_gp = lu_gp_mem->lu_gp; + if ((lu_gp)) { + /* + * Clearing an existing lu_gp association, and replacing + * with NULL + */ + if (!(lu_gp_new)) { + printk(KERN_INFO "Target_Core_ConfigFS: Releasing %s/%s" + " from ALUA LU Group: core/alua/lu_gps/%s, ID:" + " %hu\n", + config_item_name(&hba->hba_group.cg_item), + config_item_name(&su_dev->se_dev_group.cg_item), + config_item_name(&lu_gp->lu_gp_group.cg_item), + lu_gp->lu_gp_id); + + __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp); + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + return count; + } + /* + * Removing existing association of lu_gp_mem with lu_gp + */ + __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp); + move = 1; + } + /* + * Associate lu_gp_mem with lu_gp_new. + */ + __core_alua_attach_lu_gp_mem(lu_gp_mem, lu_gp_new); + spin_unlock(&lu_gp_mem->lu_gp_mem_lock); + + printk(KERN_INFO "Target_Core_ConfigFS: %s %s/%s to ALUA LU Group:" + " core/alua/lu_gps/%s, ID: %hu\n", + (move) ? "Moving" : "Adding", + config_item_name(&hba->hba_group.cg_item), + config_item_name(&su_dev->se_dev_group.cg_item), + config_item_name(&lu_gp_new->lu_gp_group.cg_item), + lu_gp_new->lu_gp_id); + + core_alua_put_lu_gp_from_name(lu_gp_new); + return count; +} + +static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = { + .attr = { .ca_owner = THIS_MODULE, + .ca_name = "alua_lu_gp", + .ca_mode = S_IRUGO | S_IWUSR }, + .show = target_core_show_alua_lu_gp, + .store = target_core_store_alua_lu_gp, +}; + +static struct configfs_attribute *lio_core_dev_attrs[] = { + &target_core_attr_dev_info.attr, + &target_core_attr_dev_control.attr, + &target_core_attr_dev_alias.attr, + &target_core_attr_dev_udev_path.attr, + &target_core_attr_dev_enable.attr, + &target_core_attr_dev_alua_lu_gp.attr, + NULL, +}; + +static void target_core_dev_release(struct config_item *item) +{ + struct se_subsystem_dev *se_dev = container_of(to_config_group(item), + struct se_subsystem_dev, se_dev_group); + struct config_group *dev_cg; + + if (!(se_dev)) + return; + + dev_cg = &se_dev->se_dev_group; + kfree(dev_cg->default_groups); +} + +static ssize_t target_core_dev_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + struct se_subsystem_dev *se_dev = container_of( + to_config_group(item), struct se_subsystem_dev, + se_dev_group); + struct target_core_configfs_attribute *tc_attr = container_of( + attr, struct target_core_configfs_attribute, attr); + + if (!(tc_attr->show)) + return -EINVAL; + + return tc_attr->show((void *)se_dev, page); +} + +static ssize_t target_core_dev_store(struct config_item *item, + struct configfs_attribute *attr, + const char *page, size_t count) +{ + struct se_subsystem_dev *se_dev = container_of( + to_config_group(item), struct se_subsystem_dev, + se_dev_group); + struct target_core_configfs_attribute *tc_attr = container_of( + attr, struct target_core_configfs_attribute, attr); + + if (!(tc_attr->store)) + return -EINVAL; + + return tc_attr->store((void *)se_dev, page, count); +} + +static struct configfs_item_operations target_core_dev_item_ops = { + .release = target_core_dev_release, + .show_attribute = target_core_dev_show, + .store_attribute = target_core_dev_store, +}; + +static struct config_item_type target_core_dev_cit = { + .ct_item_ops = &target_core_dev_item_ops, + .ct_attrs = lio_core_dev_attrs, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_dev_cit */ + +/* Start functions for struct config_item_type target_core_alua_lu_gp_cit */ + +CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp); +#define SE_DEV_ALUA_LU_ATTR(_name, _mode) \ +static struct target_core_alua_lu_gp_attribute \ + target_core_alua_lu_gp_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_core_alua_lu_gp_show_attr_##_name, \ + target_core_alua_lu_gp_store_attr_##_name); + +#define SE_DEV_ALUA_LU_ATTR_RO(_name) \ +static struct target_core_alua_lu_gp_attribute \ + target_core_alua_lu_gp_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_core_alua_lu_gp_show_attr_##_name); + +/* + * lu_gp_id + */ +static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id( + struct t10_alua_lu_gp *lu_gp, + char *page) +{ + if (!(lu_gp->lu_gp_valid_id)) + return 0; + + return sprintf(page, "%hu\n", lu_gp->lu_gp_id); +} + +static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id( + struct t10_alua_lu_gp *lu_gp, + const char *page, + size_t count) +{ + struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group; + unsigned long lu_gp_id; + int ret; + + ret = strict_strtoul(page, 0, &lu_gp_id); + if (ret < 0) { + printk(KERN_ERR "strict_strtoul() returned %d for" + " lu_gp_id\n", ret); + return -EINVAL; + } + if (lu_gp_id > 0x0000ffff) { + printk(KERN_ERR "ALUA lu_gp_id: %lu exceeds maximum:" + " 0x0000ffff\n", lu_gp_id); + return -EINVAL; + } + + ret = core_alua_set_lu_gp_id(lu_gp, (u16)lu_gp_id); + if (ret < 0) + return -EINVAL; + + printk(KERN_INFO "Target_Core_ConfigFS: Set ALUA Logical Unit" + " Group: core/alua/lu_gps/%s to ID: %hu\n", + config_item_name(&alua_lu_gp_cg->cg_item), + lu_gp->lu_gp_id); + + return count; +} + +SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR); + +/* + * members + */ +static ssize_t target_core_alua_lu_gp_show_attr_members( + struct t10_alua_lu_gp *lu_gp, + char *page) +{ + struct se_device *dev; + struct se_hba *hba; + struct se_subsystem_dev *su_dev; + struct t10_alua_lu_gp_member *lu_gp_mem; + ssize_t len = 0, cur_len; + unsigned char buf[LU_GROUP_NAME_BUF]; + + memset(buf, 0, LU_GROUP_NAME_BUF); + + spin_lock(&lu_gp->lu_gp_lock); + list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) { + dev = lu_gp_mem->lu_gp_mem_dev; + su_dev = dev->se_sub_dev; + hba = su_dev->se_dev_hba; + + cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n", + config_item_name(&hba->hba_group.cg_item), + config_item_name(&su_dev->se_dev_group.cg_item)); + cur_len++; /* Extra byte for NULL terminator */ + + if ((cur_len + len) > PAGE_SIZE) { + printk(KERN_WARNING "Ran out of lu_gp_show_attr" + "_members buffer\n"); + break; + } + memcpy(page+len, buf, cur_len); + len += cur_len; + } + spin_unlock(&lu_gp->lu_gp_lock); + + return len; +} + +SE_DEV_ALUA_LU_ATTR_RO(members); + +CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group); + +static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = { + &target_core_alua_lu_gp_lu_gp_id.attr, + &target_core_alua_lu_gp_members.attr, + NULL, +}; + +static struct configfs_item_operations target_core_alua_lu_gp_ops = { + .show_attribute = target_core_alua_lu_gp_attr_show, + .store_attribute = target_core_alua_lu_gp_attr_store, +}; + +static struct config_item_type target_core_alua_lu_gp_cit = { + .ct_item_ops = &target_core_alua_lu_gp_ops, + .ct_attrs = target_core_alua_lu_gp_attrs, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_alua_lu_gp_cit */ + +/* Start functions for struct config_item_type target_core_alua_lu_gps_cit */ + +static struct config_group *target_core_alua_create_lu_gp( + struct config_group *group, + const char *name) +{ + struct t10_alua_lu_gp *lu_gp; + struct config_group *alua_lu_gp_cg = NULL; + struct config_item *alua_lu_gp_ci = NULL; + + lu_gp = core_alua_allocate_lu_gp(name, 0); + if (IS_ERR(lu_gp)) + return NULL; + + alua_lu_gp_cg = &lu_gp->lu_gp_group; + alua_lu_gp_ci = &alua_lu_gp_cg->cg_item; + + config_group_init_type_name(alua_lu_gp_cg, name, + &target_core_alua_lu_gp_cit); + + printk(KERN_INFO "Target_Core_ConfigFS: Allocated ALUA Logical Unit" + " Group: core/alua/lu_gps/%s\n", + config_item_name(alua_lu_gp_ci)); + + return alua_lu_gp_cg; + +} + +static void target_core_alua_drop_lu_gp( + struct config_group *group, + struct config_item *item) +{ + struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), + struct t10_alua_lu_gp, lu_gp_group); + + printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit" + " Group: core/alua/lu_gps/%s, ID: %hu\n", + config_item_name(item), lu_gp->lu_gp_id); + + config_item_put(item); + core_alua_free_lu_gp(lu_gp); +} + +static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { + .make_group = &target_core_alua_create_lu_gp, + .drop_item = &target_core_alua_drop_lu_gp, +}; + +static struct config_item_type target_core_alua_lu_gps_cit = { + .ct_item_ops = NULL, + .ct_group_ops = &target_core_alua_lu_gps_group_ops, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_alua_lu_gps_cit */ + +/* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ + +CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp); +#define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \ +static struct target_core_alua_tg_pt_gp_attribute \ + target_core_alua_tg_pt_gp_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_core_alua_tg_pt_gp_show_attr_##_name, \ + target_core_alua_tg_pt_gp_store_attr_##_name); + +#define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \ +static struct target_core_alua_tg_pt_gp_attribute \ + target_core_alua_tg_pt_gp_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_core_alua_tg_pt_gp_show_attr_##_name); + +/* + * alua_access_state + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%d\n", + atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state)); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev; + unsigned long tmp; + int new_state, ret; + + if (!(tg_pt_gp->tg_pt_gp_valid_id)) { + printk(KERN_ERR "Unable to do implict ALUA on non valid" + " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id); + return -EINVAL; + } + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk("Unable to extract new ALUA access state from" + " %s\n", page); + return -EINVAL; + } + new_state = (int)tmp; + + if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) { + printk(KERN_ERR "Unable to process implict configfs ALUA" + " transition while TPGS_IMPLICT_ALUA is diabled\n"); + return -EINVAL; + } + + ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr, + NULL, NULL, new_state, 0); + return (!ret) ? count : -EINVAL; +} + +SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR); + +/* + * alua_access_status + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%s\n", + core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status)); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int new_status, ret; + + if (!(tg_pt_gp->tg_pt_gp_valid_id)) { + printk(KERN_ERR "Unable to do set ALUA access status on non" + " valid tg_pt_gp ID: %hu\n", + tg_pt_gp->tg_pt_gp_valid_id); + return -EINVAL; + } + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract new ALUA access status" + " from %s\n", page); + return -EINVAL; + } + new_status = (int)tmp; + + if ((new_status != ALUA_STATUS_NONE) && + (new_status != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && + (new_status != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) { + printk(KERN_ERR "Illegal ALUA access status: 0x%02x\n", + new_status); + return -EINVAL; + } + + tg_pt_gp->tg_pt_gp_alua_access_status = new_status; + return count; +} + +SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR); + +/* + * alua_access_type + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return core_alua_show_access_type(tg_pt_gp, page); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + return core_alua_store_access_type(tg_pt_gp, page, count); +} + +SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR); + +/* + * alua_write_metadata + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract alua_write_metadata\n"); + return -EINVAL; + } + + if ((tmp != 0) && (tmp != 1)) { + printk(KERN_ERR "Illegal value for alua_write_metadata:" + " %lu\n", tmp); + return -EINVAL; + } + tg_pt_gp->tg_pt_gp_write_metadata = (int)tmp; + + return count; +} + +SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR); + + + +/* + * nonop_delay_msecs + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return core_alua_show_nonop_delay_msecs(tg_pt_gp, page); + +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count); +} + +SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR); + +/* + * trans_delay_msecs + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return core_alua_show_trans_delay_msecs(tg_pt_gp, page); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count); +} + +SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR); + +/* + * preferred + */ + +static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return core_alua_show_preferred_bit(tg_pt_gp, page); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + return core_alua_store_preferred_bit(tg_pt_gp, page, count); +} + +SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR); + +/* + * tg_pt_gp_id + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + if (!(tg_pt_gp->tg_pt_gp_valid_id)) + return 0; + + return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; + unsigned long tg_pt_gp_id; + int ret; + + ret = strict_strtoul(page, 0, &tg_pt_gp_id); + if (ret < 0) { + printk(KERN_ERR "strict_strtoul() returned %d for" + " tg_pt_gp_id\n", ret); + return -EINVAL; + } + if (tg_pt_gp_id > 0x0000ffff) { + printk(KERN_ERR "ALUA tg_pt_gp_id: %lu exceeds maximum:" + " 0x0000ffff\n", tg_pt_gp_id); + return -EINVAL; + } + + ret = core_alua_set_tg_pt_gp_id(tg_pt_gp, (u16)tg_pt_gp_id); + if (ret < 0) + return -EINVAL; + + printk(KERN_INFO "Target_Core_ConfigFS: Set ALUA Target Port Group: " + "core/alua/tg_pt_gps/%s to ID: %hu\n", + config_item_name(&alua_tg_pt_gp_cg->cg_item), + tg_pt_gp->tg_pt_gp_id); + + return count; +} + +SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR); + +/* + * members + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_members( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + struct se_port *port; + struct se_portal_group *tpg; + struct se_lun *lun; + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + ssize_t len = 0, cur_len; + unsigned char buf[TG_PT_GROUP_NAME_BUF]; + + memset(buf, 0, TG_PT_GROUP_NAME_BUF); + + spin_lock(&tg_pt_gp->tg_pt_gp_lock); + list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, + tg_pt_gp_mem_list) { + port = tg_pt_gp_mem->tg_pt; + tpg = port->sep_tpg; + lun = port->sep_lun; + + cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu" + "/%s\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_wwn(tpg), + TPG_TFO(tpg)->tpg_get_tag(tpg), + config_item_name(&lun->lun_group.cg_item)); + cur_len++; /* Extra byte for NULL terminator */ + + if ((cur_len + len) > PAGE_SIZE) { + printk(KERN_WARNING "Ran out of lu_gp_show_attr" + "_members buffer\n"); + break; + } + memcpy(page+len, buf, cur_len); + len += cur_len; + } + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + + return len; +} + +SE_DEV_ALUA_TG_PT_ATTR_RO(members); + +CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp, + tg_pt_gp_group); + +static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { + &target_core_alua_tg_pt_gp_alua_access_state.attr, + &target_core_alua_tg_pt_gp_alua_access_status.attr, + &target_core_alua_tg_pt_gp_alua_access_type.attr, + &target_core_alua_tg_pt_gp_alua_write_metadata.attr, + &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, + &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, + &target_core_alua_tg_pt_gp_preferred.attr, + &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr, + &target_core_alua_tg_pt_gp_members.attr, + NULL, +}; + +static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { + .show_attribute = target_core_alua_tg_pt_gp_attr_show, + .store_attribute = target_core_alua_tg_pt_gp_attr_store, +}; + +static struct config_item_type target_core_alua_tg_pt_gp_cit = { + .ct_item_ops = &target_core_alua_tg_pt_gp_ops, + .ct_attrs = target_core_alua_tg_pt_gp_attrs, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */ + +/* Start functions for struct config_item_type target_core_alua_tg_pt_gps_cit */ + +static struct config_group *target_core_alua_create_tg_pt_gp( + struct config_group *group, + const char *name) +{ + struct t10_alua *alua = container_of(group, struct t10_alua, + alua_tg_pt_gps_group); + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct se_subsystem_dev *su_dev = alua->t10_sub_dev; + struct config_group *alua_tg_pt_gp_cg = NULL; + struct config_item *alua_tg_pt_gp_ci = NULL; + + tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0); + if (!(tg_pt_gp)) + return NULL; + + alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group; + alua_tg_pt_gp_ci = &alua_tg_pt_gp_cg->cg_item; + + config_group_init_type_name(alua_tg_pt_gp_cg, name, + &target_core_alua_tg_pt_gp_cit); + + printk(KERN_INFO "Target_Core_ConfigFS: Allocated ALUA Target Port" + " Group: alua/tg_pt_gps/%s\n", + config_item_name(alua_tg_pt_gp_ci)); + + return alua_tg_pt_gp_cg; +} + +static void target_core_alua_drop_tg_pt_gp( + struct config_group *group, + struct config_item *item) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), + struct t10_alua_tg_pt_gp, tg_pt_gp_group); + + printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port" + " Group: alua/tg_pt_gps/%s, ID: %hu\n", + config_item_name(item), tg_pt_gp->tg_pt_gp_id); + + config_item_put(item); + core_alua_free_tg_pt_gp(tg_pt_gp); +} + +static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { + .make_group = &target_core_alua_create_tg_pt_gp, + .drop_item = &target_core_alua_drop_tg_pt_gp, +}; + +static struct config_item_type target_core_alua_tg_pt_gps_cit = { + .ct_group_ops = &target_core_alua_tg_pt_gps_group_ops, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_alua_tg_pt_gps_cit */ + +/* Start functions for struct config_item_type target_core_alua_cit */ + +/* + * target_core_alua_cit is a ConfigFS group that lives under + * /sys/kernel/config/target/core/alua. There are default groups + * core/alua/lu_gps and core/alua/tg_pt_gps that are attached to + * target_core_alua_cit in target_core_init_configfs() below. + */ +static struct config_item_type target_core_alua_cit = { + .ct_item_ops = NULL, + .ct_attrs = NULL, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_alua_cit */ + +/* Start functions for struct config_item_type target_core_hba_cit */ + +static struct config_group *target_core_make_subdev( + struct config_group *group, + const char *name) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct se_subsystem_dev *se_dev; + struct se_subsystem_api *t; + struct config_item *hba_ci = &group->cg_item; + struct se_hba *hba = item_to_hba(hba_ci); + struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; + + if (mutex_lock_interruptible(&hba->hba_access_mutex)) + return NULL; + + /* + * Locate the struct se_subsystem_api from parent's struct se_hba. + */ + t = hba->transport; + + se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); + if (!se_dev) { + printk(KERN_ERR "Unable to allocate memory for" + " struct se_subsystem_dev\n"); + goto unlock; + } + INIT_LIST_HEAD(&se_dev->g_se_dev_list); + INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); + spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); + INIT_LIST_HEAD(&se_dev->t10_reservation.registration_list); + INIT_LIST_HEAD(&se_dev->t10_reservation.aptpl_reg_list); + spin_lock_init(&se_dev->t10_reservation.registration_lock); + spin_lock_init(&se_dev->t10_reservation.aptpl_reg_lock); + INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); + spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); + spin_lock_init(&se_dev->se_dev_lock); + se_dev->t10_reservation.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; + se_dev->t10_wwn.t10_sub_dev = se_dev; + se_dev->t10_alua.t10_sub_dev = se_dev; + se_dev->se_dev_attrib.da_sub_dev = se_dev; + + se_dev->se_dev_hba = hba; + dev_cg = &se_dev->se_dev_group; + + dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, + GFP_KERNEL); + if (!(dev_cg->default_groups)) + goto out; + /* + * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr + * for ->allocate_virtdevice() + * + * se_dev->se_dev_ptr will be set after ->create_virtdev() + * has been called successfully in the next level up in the + * configfs tree for device object's struct config_group. + */ + se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name); + if (!(se_dev->se_dev_su_ptr)) { + printk(KERN_ERR "Unable to locate subsystem dependent pointer" + " from allocate_virtdevice()\n"); + goto out; + } + spin_lock(&se_global->g_device_lock); + list_add_tail(&se_dev->g_se_dev_list, &se_global->g_se_dev_list); + spin_unlock(&se_global->g_device_lock); + + config_group_init_type_name(&se_dev->se_dev_group, name, + &target_core_dev_cit); + config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib", + &target_core_dev_attrib_cit); + config_group_init_type_name(&se_dev->se_dev_pr_group, "pr", + &target_core_dev_pr_cit); + config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn", + &target_core_dev_wwn_cit); + config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, + "alua", &target_core_alua_tg_pt_gps_cit); + dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; + dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; + dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; + dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; + dev_cg->default_groups[4] = NULL; + /* + * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp + */ + tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); + if (!(tg_pt_gp)) + goto out; + + tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; + tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!(tg_pt_gp_cg->default_groups)) { + printk(KERN_ERR "Unable to allocate tg_pt_gp_cg->" + "default_groups\n"); + goto out; + } + + config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group, + "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit); + tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; + tg_pt_gp_cg->default_groups[1] = NULL; + T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; + + printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" + " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); + + mutex_unlock(&hba->hba_access_mutex); + return &se_dev->se_dev_group; +out: + if (T10_ALUA(se_dev)->default_tg_pt_gp) { + core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); + T10_ALUA(se_dev)->default_tg_pt_gp = NULL; + } + if (tg_pt_gp_cg) + kfree(tg_pt_gp_cg->default_groups); + if (dev_cg) + kfree(dev_cg->default_groups); + if (se_dev->se_dev_su_ptr) + t->free_device(se_dev->se_dev_su_ptr); + kfree(se_dev); +unlock: + mutex_unlock(&hba->hba_access_mutex); + return NULL; +} + +static void target_core_drop_subdev( + struct config_group *group, + struct config_item *item) +{ + struct se_subsystem_dev *se_dev = container_of(to_config_group(item), + struct se_subsystem_dev, se_dev_group); + struct se_hba *hba; + struct se_subsystem_api *t; + struct config_item *df_item; + struct config_group *dev_cg, *tg_pt_gp_cg; + int i, ret; + + hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); + + if (mutex_lock_interruptible(&hba->hba_access_mutex)) + goto out; + + t = hba->transport; + + spin_lock(&se_global->g_device_lock); + list_del(&se_dev->g_se_dev_list); + spin_unlock(&se_global->g_device_lock); + + tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; + for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { + df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; + tg_pt_gp_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(tg_pt_gp_cg->default_groups); + core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); + T10_ALUA(se_dev)->default_tg_pt_gp = NULL; + + dev_cg = &se_dev->se_dev_group; + for (i = 0; dev_cg->default_groups[i]; i++) { + df_item = &dev_cg->default_groups[i]->cg_item; + dev_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + + config_item_put(item); + /* + * This pointer will set when the storage is enabled with: + * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` + */ + if (se_dev->se_dev_ptr) { + printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_" + "virtual_device() for se_dev_ptr: %p\n", + se_dev->se_dev_ptr); + + ret = se_free_virtual_device(se_dev->se_dev_ptr, hba); + if (ret < 0) + goto hba_out; + } else { + /* + * Release struct se_subsystem_dev->se_dev_su_ptr.. + */ + printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_" + "device() for se_dev_su_ptr: %p\n", + se_dev->se_dev_su_ptr); + + t->free_device(se_dev->se_dev_su_ptr); + } + + printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem" + "_dev_t: %p\n", se_dev); + +hba_out: + mutex_unlock(&hba->hba_access_mutex); +out: + kfree(se_dev); +} + +static struct configfs_group_operations target_core_hba_group_ops = { + .make_group = target_core_make_subdev, + .drop_item = target_core_drop_subdev, +}; + +CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba); +#define SE_HBA_ATTR(_name, _mode) \ +static struct target_core_hba_attribute \ + target_core_hba_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_core_hba_show_attr_##_name, \ + target_core_hba_store_attr_##_name); + +#define SE_HBA_ATTR_RO(_name) \ +static struct target_core_hba_attribute \ + target_core_hba_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_core_hba_show_attr_##_name); + +static ssize_t target_core_hba_show_attr_hba_info( + struct se_hba *hba, + char *page) +{ + return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", + hba->hba_id, hba->transport->name, + TARGET_CORE_CONFIGFS_VERSION); +} + +SE_HBA_ATTR_RO(hba_info); + +static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, + char *page) +{ + int hba_mode = 0; + + if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE) + hba_mode = 1; + + return sprintf(page, "%d\n", hba_mode); +} + +static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, + const char *page, size_t count) +{ + struct se_subsystem_api *transport = hba->transport; + unsigned long mode_flag; + int ret; + + if (transport->pmode_enable_hba == NULL) + return -EINVAL; + + ret = strict_strtoul(page, 0, &mode_flag); + if (ret < 0) { + printk(KERN_ERR "Unable to extract hba mode flag: %d\n", ret); + return -EINVAL; + } + + spin_lock(&hba->device_lock); + if (!(list_empty(&hba->hba_dev_list))) { + printk(KERN_ERR "Unable to set hba_mode with active devices\n"); + spin_unlock(&hba->device_lock); + return -EINVAL; + } + spin_unlock(&hba->device_lock); + + ret = transport->pmode_enable_hba(hba, mode_flag); + if (ret < 0) + return -EINVAL; + if (ret > 0) + hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; + else if (ret == 0) + hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; + + return count; +} + +SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR); + +CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group); + +static struct configfs_attribute *target_core_hba_attrs[] = { + &target_core_hba_hba_info.attr, + &target_core_hba_hba_mode.attr, + NULL, +}; + +static struct configfs_item_operations target_core_hba_item_ops = { + .show_attribute = target_core_hba_attr_show, + .store_attribute = target_core_hba_attr_store, +}; + +static struct config_item_type target_core_hba_cit = { + .ct_item_ops = &target_core_hba_item_ops, + .ct_group_ops = &target_core_hba_group_ops, + .ct_attrs = target_core_hba_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *target_core_call_addhbatotarget( + struct config_group *group, + const char *name) +{ + char *se_plugin_str, *str, *str2; + struct se_hba *hba; + char buf[TARGET_CORE_NAME_MAX_LEN]; + unsigned long plugin_dep_id = 0; + int ret; + + memset(buf, 0, TARGET_CORE_NAME_MAX_LEN); + if (strlen(name) > TARGET_CORE_NAME_MAX_LEN) { + printk(KERN_ERR "Passed *name strlen(): %d exceeds" + " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name), + TARGET_CORE_NAME_MAX_LEN); + return ERR_PTR(-ENAMETOOLONG); + } + snprintf(buf, TARGET_CORE_NAME_MAX_LEN, "%s", name); + + str = strstr(buf, "_"); + if (!(str)) { + printk(KERN_ERR "Unable to locate \"_\" for $SUBSYSTEM_PLUGIN_$HOST_ID\n"); + return ERR_PTR(-EINVAL); + } + se_plugin_str = buf; + /* + * Special case for subsystem plugins that have "_" in their names. + * Namely rd_direct and rd_mcp.. + */ + str2 = strstr(str+1, "_"); + if ((str2)) { + *str2 = '\0'; /* Terminate for *se_plugin_str */ + str2++; /* Skip to start of plugin dependent ID */ + str = str2; + } else { + *str = '\0'; /* Terminate for *se_plugin_str */ + str++; /* Skip to start of plugin dependent ID */ + } + + ret = strict_strtoul(str, 0, &plugin_dep_id); + if (ret < 0) { + printk(KERN_ERR "strict_strtoul() returned %d for" + " plugin_dep_id\n", ret); + return ERR_PTR(-EINVAL); + } + /* + * Load up TCM subsystem plugins if they have not already been loaded. + */ + if (transport_subsystem_check_init() < 0) + return ERR_PTR(-EINVAL); + + hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0); + if (IS_ERR(hba)) + return ERR_CAST(hba); + + config_group_init_type_name(&hba->hba_group, name, + &target_core_hba_cit); + + return &hba->hba_group; +} + +static void target_core_call_delhbafromtarget( + struct config_group *group, + struct config_item *item) +{ + struct se_hba *hba = item_to_hba(item); + + config_item_put(item); + core_delete_hba(hba); +} + +static struct configfs_group_operations target_core_group_ops = { + .make_group = target_core_call_addhbatotarget, + .drop_item = target_core_call_delhbafromtarget, +}; + +static struct config_item_type target_core_cit = { + .ct_item_ops = NULL, + .ct_group_ops = &target_core_group_ops, + .ct_attrs = NULL, + .ct_owner = THIS_MODULE, +}; + +/* Stop functions for struct config_item_type target_core_hba_cit */ + +static int target_core_init_configfs(void) +{ + struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; + struct config_group *lu_gp_cg = NULL; + struct configfs_subsystem *subsys; + struct proc_dir_entry *scsi_target_proc = NULL; + struct t10_alua_lu_gp *lu_gp; + int ret; + + printk(KERN_INFO "TARGET_CORE[0]: Loading Generic Kernel Storage" + " Engine: %s on %s/%s on "UTS_RELEASE"\n", + TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); + + subsys = target_core_subsystem[0]; + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + + INIT_LIST_HEAD(&g_tf_list); + mutex_init(&g_tf_lock); + init_scsi_index_table(); + ret = init_se_global(); + if (ret < 0) + return -1; + /* + * Create $CONFIGFS/target/core default group for HBA <-> Storage Object + * and ALUA Logical Unit Group and Target Port Group infrastructure. + */ + target_cg = &subsys->su_group; + target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!(target_cg->default_groups)) { + printk(KERN_ERR "Unable to allocate target_cg->default_groups\n"); + goto out_global; + } + + config_group_init_type_name(&se_global->target_core_hbagroup, + "core", &target_core_cit); + target_cg->default_groups[0] = &se_global->target_core_hbagroup; + target_cg->default_groups[1] = NULL; + /* + * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/ + */ + hba_cg = &se_global->target_core_hbagroup; + hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!(hba_cg->default_groups)) { + printk(KERN_ERR "Unable to allocate hba_cg->default_groups\n"); + goto out_global; + } + config_group_init_type_name(&se_global->alua_group, + "alua", &target_core_alua_cit); + hba_cg->default_groups[0] = &se_global->alua_group; + hba_cg->default_groups[1] = NULL; + /* + * Add ALUA Logical Unit Group and Target Port Group ConfigFS + * groups under /sys/kernel/config/target/core/alua/ + */ + alua_cg = &se_global->alua_group; + alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!(alua_cg->default_groups)) { + printk(KERN_ERR "Unable to allocate alua_cg->default_groups\n"); + goto out_global; + } + + config_group_init_type_name(&se_global->alua_lu_gps_group, + "lu_gps", &target_core_alua_lu_gps_cit); + alua_cg->default_groups[0] = &se_global->alua_lu_gps_group; + alua_cg->default_groups[1] = NULL; + /* + * Add core/alua/lu_gps/default_lu_gp + */ + lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1); + if (IS_ERR(lu_gp)) + goto out_global; + + lu_gp_cg = &se_global->alua_lu_gps_group; + lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!(lu_gp_cg->default_groups)) { + printk(KERN_ERR "Unable to allocate lu_gp_cg->default_groups\n"); + goto out_global; + } + + config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp", + &target_core_alua_lu_gp_cit); + lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group; + lu_gp_cg->default_groups[1] = NULL; + se_global->default_lu_gp = lu_gp; + /* + * Register the target_core_mod subsystem with configfs. + */ + ret = configfs_register_subsystem(subsys); + if (ret < 0) { + printk(KERN_ERR "Error %d while registering subsystem %s\n", + ret, subsys->su_group.cg_item.ci_namebuf); + goto out_global; + } + printk(KERN_INFO "TARGET_CORE[0]: Initialized ConfigFS Fabric" + " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s" + " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); + /* + * Register built-in RAMDISK subsystem logic for virtual LUN 0 + */ + ret = rd_module_init(); + if (ret < 0) + goto out; + + if (core_dev_setup_virtual_lun0() < 0) + goto out; + + scsi_target_proc = proc_mkdir("scsi_target", 0); + if (!(scsi_target_proc)) { + printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n"); + goto out; + } + ret = init_scsi_target_mib(); + if (ret < 0) + goto out; + + return 0; + +out: + configfs_unregister_subsystem(subsys); + if (scsi_target_proc) + remove_proc_entry("scsi_target", 0); + core_dev_release_virtual_lun0(); + rd_module_exit(); +out_global: + if (se_global->default_lu_gp) { + core_alua_free_lu_gp(se_global->default_lu_gp); + se_global->default_lu_gp = NULL; + } + if (lu_gp_cg) + kfree(lu_gp_cg->default_groups); + if (alua_cg) + kfree(alua_cg->default_groups); + if (hba_cg) + kfree(hba_cg->default_groups); + kfree(target_cg->default_groups); + release_se_global(); + return -1; +} + +static void target_core_exit_configfs(void) +{ + struct configfs_subsystem *subsys; + struct config_group *hba_cg, *alua_cg, *lu_gp_cg; + struct config_item *item; + int i; + + se_global->in_shutdown = 1; + subsys = target_core_subsystem[0]; + + lu_gp_cg = &se_global->alua_lu_gps_group; + for (i = 0; lu_gp_cg->default_groups[i]; i++) { + item = &lu_gp_cg->default_groups[i]->cg_item; + lu_gp_cg->default_groups[i] = NULL; + config_item_put(item); + } + kfree(lu_gp_cg->default_groups); + core_alua_free_lu_gp(se_global->default_lu_gp); + se_global->default_lu_gp = NULL; + + alua_cg = &se_global->alua_group; + for (i = 0; alua_cg->default_groups[i]; i++) { + item = &alua_cg->default_groups[i]->cg_item; + alua_cg->default_groups[i] = NULL; + config_item_put(item); + } + kfree(alua_cg->default_groups); + + hba_cg = &se_global->target_core_hbagroup; + for (i = 0; hba_cg->default_groups[i]; i++) { + item = &hba_cg->default_groups[i]->cg_item; + hba_cg->default_groups[i] = NULL; + config_item_put(item); + } + kfree(hba_cg->default_groups); + + for (i = 0; subsys->su_group.default_groups[i]; i++) { + item = &subsys->su_group.default_groups[i]->cg_item; + subsys->su_group.default_groups[i] = NULL; + config_item_put(item); + } + kfree(subsys->su_group.default_groups); + + configfs_unregister_subsystem(subsys); + printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric" + " Infrastructure\n"); + + remove_scsi_target_mib(); + remove_proc_entry("scsi_target", 0); + core_dev_release_virtual_lun0(); + rd_module_exit(); + release_se_global(); + + return; +} + +MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS"); +MODULE_AUTHOR("nab@Linux-iSCSI.org"); +MODULE_LICENSE("GPL"); + +module_init(target_core_init_configfs); +module_exit(target_core_exit_configfs); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c new file mode 100644 index 000000000000..317ce58d426d --- /dev/null +++ b/drivers/target/target_core_device.c @@ -0,0 +1,1694 @@ +/******************************************************************************* + * Filename: target_core_device.c (based on iscsi_target_device.c) + * + * This file contains the iSCSI Virtual Device and Disk Transport + * agnostic related functions. + * + * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include + +#include +#include +#include +#include +#include + +#include "target_core_alua.h" +#include "target_core_hba.h" +#include "target_core_pr.h" +#include "target_core_ua.h" + +static void se_dev_start(struct se_device *dev); +static void se_dev_stop(struct se_device *dev); + +int transport_get_lun_for_cmd( + struct se_cmd *se_cmd, + unsigned char *cdb, + u32 unpacked_lun) +{ + struct se_dev_entry *deve; + struct se_lun *se_lun = NULL; + struct se_session *se_sess = SE_SESS(se_cmd); + unsigned long flags; + int read_only = 0; + + spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock); + deve = se_cmd->se_deve = + &SE_NODE_ACL(se_sess)->device_list[unpacked_lun]; + if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { + if (se_cmd) { + deve->total_cmds++; + deve->total_bytes += se_cmd->data_length; + + if (se_cmd->data_direction == DMA_TO_DEVICE) { + if (deve->lun_flags & + TRANSPORT_LUNFLAGS_READ_ONLY) { + read_only = 1; + goto out; + } + deve->write_bytes += se_cmd->data_length; + } else if (se_cmd->data_direction == + DMA_FROM_DEVICE) { + deve->read_bytes += se_cmd->data_length; + } + } + deve->deve_cmds++; + + se_lun = se_cmd->se_lun = deve->se_lun; + se_cmd->pr_res_key = deve->pr_res_key; + se_cmd->orig_fe_lun = unpacked_lun; + se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev; + se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; + } +out: + spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock); + + if (!se_lun) { + if (read_only) { + se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + printk("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" + " Access for 0x%08x\n", + CMD_TFO(se_cmd)->get_fabric_name(), + unpacked_lun); + return -1; + } else { + /* + * Use the se_portal_group->tpg_virt_lun0 to allow for + * REPORT_LUNS, et al to be returned when no active + * MappedLUN=0 exists for this Initiator Port. + */ + if (unpacked_lun != 0) { + se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + printk("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" + " Access for 0x%08x\n", + CMD_TFO(se_cmd)->get_fabric_name(), + unpacked_lun); + return -1; + } + /* + * Force WRITE PROTECT for virtual LUN 0 + */ + if ((se_cmd->data_direction != DMA_FROM_DEVICE) && + (se_cmd->data_direction != DMA_NONE)) { + se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + return -1; + } +#if 0 + printk("TARGET_CORE[%s]: Using virtual LUN0! :-)\n", + CMD_TFO(se_cmd)->get_fabric_name()); +#endif + se_lun = se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; + se_cmd->orig_fe_lun = 0; + se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev; + se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; + } + } + /* + * Determine if the struct se_lun is online. + */ +/* #warning FIXME: Check for LUN_RESET + UNIT Attention */ + if (se_dev_check_online(se_lun->lun_se_dev) != 0) { + se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN; + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + return -1; + } + + { + struct se_device *dev = se_lun->lun_se_dev; + spin_lock(&dev->stats_lock); + dev->num_cmds++; + if (se_cmd->data_direction == DMA_TO_DEVICE) + dev->write_bytes += se_cmd->data_length; + else if (se_cmd->data_direction == DMA_FROM_DEVICE) + dev->read_bytes += se_cmd->data_length; + spin_unlock(&dev->stats_lock); + } + + /* + * Add the iscsi_cmd_t to the struct se_lun's cmd list. This list is used + * for tracking state of struct se_cmds during LUN shutdown events. + */ + spin_lock_irqsave(&se_lun->lun_cmd_lock, flags); + list_add_tail(&se_cmd->se_lun_list, &se_lun->lun_cmd_list); + atomic_set(&T_TASK(se_cmd)->transport_lun_active, 1); +#if 0 + printk(KERN_INFO "Adding ITT: 0x%08x to LUN LIST[%d]\n", + CMD_TFO(se_cmd)->get_task_tag(se_cmd), se_lun->unpacked_lun); +#endif + spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags); + + return 0; +} +EXPORT_SYMBOL(transport_get_lun_for_cmd); + +int transport_get_lun_for_tmr( + struct se_cmd *se_cmd, + u32 unpacked_lun) +{ + struct se_device *dev = NULL; + struct se_dev_entry *deve; + struct se_lun *se_lun = NULL; + struct se_session *se_sess = SE_SESS(se_cmd); + struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; + + spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock); + deve = se_cmd->se_deve = + &SE_NODE_ACL(se_sess)->device_list[unpacked_lun]; + if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { + se_lun = se_cmd->se_lun = se_tmr->tmr_lun = deve->se_lun; + dev = se_tmr->tmr_dev = se_lun->lun_se_dev; + se_cmd->pr_res_key = deve->pr_res_key; + se_cmd->orig_fe_lun = unpacked_lun; + se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev; +/* se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; */ + } + spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock); + + if (!se_lun) { + printk(KERN_INFO "TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" + " Access for 0x%08x\n", + CMD_TFO(se_cmd)->get_fabric_name(), + unpacked_lun); + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + return -1; + } + /* + * Determine if the struct se_lun is online. + */ +/* #warning FIXME: Check for LUN_RESET + UNIT Attention */ + if (se_dev_check_online(se_lun->lun_se_dev) != 0) { + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + return -1; + } + + spin_lock(&dev->se_tmr_lock); + list_add_tail(&se_tmr->tmr_list, &dev->dev_tmr_list); + spin_unlock(&dev->se_tmr_lock); + + return 0; +} +EXPORT_SYMBOL(transport_get_lun_for_tmr); + +/* + * This function is called from core_scsi3_emulate_pro_register_and_move() + * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_ref_count + * when a matching rtpi is found. + */ +struct se_dev_entry *core_get_se_deve_from_rtpi( + struct se_node_acl *nacl, + u16 rtpi) +{ + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_port *port; + struct se_portal_group *tpg = nacl->se_tpg; + u32 i; + + spin_lock_irq(&nacl->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = &nacl->device_list[i]; + + if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) + continue; + + lun = deve->se_lun; + if (!(lun)) { + printk(KERN_ERR "%s device entries device pointer is" + " NULL, but Initiator has access.\n", + TPG_TFO(tpg)->get_fabric_name()); + continue; + } + port = lun->lun_sep; + if (!(port)) { + printk(KERN_ERR "%s device entries device pointer is" + " NULL, but Initiator has access.\n", + TPG_TFO(tpg)->get_fabric_name()); + continue; + } + if (port->sep_rtpi != rtpi) + continue; + + atomic_inc(&deve->pr_ref_count); + smp_mb__after_atomic_inc(); + spin_unlock_irq(&nacl->device_list_lock); + + return deve; + } + spin_unlock_irq(&nacl->device_list_lock); + + return NULL; +} + +int core_free_device_list_for_node( + struct se_node_acl *nacl, + struct se_portal_group *tpg) +{ + struct se_dev_entry *deve; + struct se_lun *lun; + u32 i; + + if (!nacl->device_list) + return 0; + + spin_lock_irq(&nacl->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = &nacl->device_list[i]; + + if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) + continue; + + if (!deve->se_lun) { + printk(KERN_ERR "%s device entries device pointer is" + " NULL, but Initiator has access.\n", + TPG_TFO(tpg)->get_fabric_name()); + continue; + } + lun = deve->se_lun; + + spin_unlock_irq(&nacl->device_list_lock); + core_update_device_list_for_node(lun, NULL, deve->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + spin_lock_irq(&nacl->device_list_lock); + } + spin_unlock_irq(&nacl->device_list_lock); + + kfree(nacl->device_list); + nacl->device_list = NULL; + + return 0; +} + +void core_dec_lacl_count(struct se_node_acl *se_nacl, struct se_cmd *se_cmd) +{ + struct se_dev_entry *deve; + + spin_lock_irq(&se_nacl->device_list_lock); + deve = &se_nacl->device_list[se_cmd->orig_fe_lun]; + deve->deve_cmds--; + spin_unlock_irq(&se_nacl->device_list_lock); + + return; +} + +void core_update_device_list_access( + u32 mapped_lun, + u32 lun_access, + struct se_node_acl *nacl) +{ + struct se_dev_entry *deve; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[mapped_lun]; + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + } + spin_unlock_irq(&nacl->device_list_lock); + + return; +} + +/* core_update_device_list_for_node(): + * + * + */ +int core_update_device_list_for_node( + struct se_lun *lun, + struct se_lun_acl *lun_acl, + u32 mapped_lun, + u32 lun_access, + struct se_node_acl *nacl, + struct se_portal_group *tpg, + int enable) +{ + struct se_port *port = lun->lun_sep; + struct se_dev_entry *deve = &nacl->device_list[mapped_lun]; + int trans = 0; + /* + * If the MappedLUN entry is being disabled, the entry in + * port->sep_alua_list must be removed now before clearing the + * struct se_dev_entry pointers below as logic in + * core_alua_do_transition_tg_pt() depends on these being present. + */ + if (!(enable)) { + /* + * deve->se_lun_acl will be NULL for demo-mode created LUNs + * that have not been explictly concerted to MappedLUNs -> + * struct se_lun_acl. + */ + if (!(deve->se_lun_acl)) + return 0; + + spin_lock_bh(&port->sep_alua_lock); + list_del(&deve->alua_port_list); + spin_unlock_bh(&port->sep_alua_lock); + } + + spin_lock_irq(&nacl->device_list_lock); + if (enable) { + /* + * Check if the call is handling demo mode -> explict LUN ACL + * transition. This transition must be for the same struct se_lun + * + mapped_lun that was setup in demo mode.. + */ + if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { + if (deve->se_lun_acl != NULL) { + printk(KERN_ERR "struct se_dev_entry->se_lun_acl" + " already set for demo mode -> explict" + " LUN ACL transition\n"); + return -1; + } + if (deve->se_lun != lun) { + printk(KERN_ERR "struct se_dev_entry->se_lun does" + " match passed struct se_lun for demo mode" + " -> explict LUN ACL transition\n"); + return -1; + } + deve->se_lun_acl = lun_acl; + trans = 1; + } else { + deve->se_lun = lun; + deve->se_lun_acl = lun_acl; + deve->mapped_lun = mapped_lun; + deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; + } + + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + } + + if (trans) { + spin_unlock_irq(&nacl->device_list_lock); + return 0; + } + deve->creation_time = get_jiffies_64(); + deve->attach_count++; + spin_unlock_irq(&nacl->device_list_lock); + + spin_lock_bh(&port->sep_alua_lock); + list_add_tail(&deve->alua_port_list, &port->sep_alua_list); + spin_unlock_bh(&port->sep_alua_lock); + + return 0; + } + /* + * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE + * PR operation to complete. + */ + spin_unlock_irq(&nacl->device_list_lock); + while (atomic_read(&deve->pr_ref_count) != 0) + cpu_relax(); + spin_lock_irq(&nacl->device_list_lock); + /* + * Disable struct se_dev_entry LUN ACL mapping + */ + core_scsi3_ua_release_all(deve); + deve->se_lun = NULL; + deve->se_lun_acl = NULL; + deve->lun_flags = 0; + deve->creation_time = 0; + deve->attach_count--; + spin_unlock_irq(&nacl->device_list_lock); + + core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl); + return 0; +} + +/* core_clear_lun_from_tpg(): + * + * + */ +void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) +{ + struct se_node_acl *nacl; + struct se_dev_entry *deve; + u32 i; + + spin_lock_bh(&tpg->acl_node_lock); + list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) { + spin_unlock_bh(&tpg->acl_node_lock); + + spin_lock_irq(&nacl->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = &nacl->device_list[i]; + if (lun != deve->se_lun) + continue; + spin_unlock_irq(&nacl->device_list_lock); + + core_update_device_list_for_node(lun, NULL, + deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS, + nacl, tpg, 0); + + spin_lock_irq(&nacl->device_list_lock); + } + spin_unlock_irq(&nacl->device_list_lock); + + spin_lock_bh(&tpg->acl_node_lock); + } + spin_unlock_bh(&tpg->acl_node_lock); + + return; +} + +static struct se_port *core_alloc_port(struct se_device *dev) +{ + struct se_port *port, *port_tmp; + + port = kzalloc(sizeof(struct se_port), GFP_KERNEL); + if (!(port)) { + printk(KERN_ERR "Unable to allocate struct se_port\n"); + return NULL; + } + INIT_LIST_HEAD(&port->sep_alua_list); + INIT_LIST_HEAD(&port->sep_list); + atomic_set(&port->sep_tg_pt_secondary_offline, 0); + spin_lock_init(&port->sep_alua_lock); + mutex_init(&port->sep_tg_pt_md_mutex); + + spin_lock(&dev->se_port_lock); + if (dev->dev_port_count == 0x0000ffff) { + printk(KERN_WARNING "Reached dev->dev_port_count ==" + " 0x0000ffff\n"); + spin_unlock(&dev->se_port_lock); + return NULL; + } +again: + /* + * Allocate the next RELATIVE TARGET PORT IDENTIFER for this struct se_device + * Here is the table from spc4r17 section 7.7.3.8. + * + * Table 473 -- RELATIVE TARGET PORT IDENTIFIER field + * + * Code Description + * 0h Reserved + * 1h Relative port 1, historically known as port A + * 2h Relative port 2, historically known as port B + * 3h to FFFFh Relative port 3 through 65 535 + */ + port->sep_rtpi = dev->dev_rpti_counter++; + if (!(port->sep_rtpi)) + goto again; + + list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) { + /* + * Make sure RELATIVE TARGET PORT IDENTIFER is unique + * for 16-bit wrap.. + */ + if (port->sep_rtpi == port_tmp->sep_rtpi) + goto again; + } + spin_unlock(&dev->se_port_lock); + + return port; +} + +static void core_export_port( + struct se_device *dev, + struct se_portal_group *tpg, + struct se_port *port, + struct se_lun *lun) +{ + struct se_subsystem_dev *su_dev = SU_DEV(dev); + struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL; + + spin_lock(&dev->se_port_lock); + spin_lock(&lun->lun_sep_lock); + port->sep_tpg = tpg; + port->sep_lun = lun; + lun->lun_sep = port; + spin_unlock(&lun->lun_sep_lock); + + list_add_tail(&port->sep_list, &dev->dev_sep_list); + spin_unlock(&dev->se_port_lock); + + if (T10_ALUA(su_dev)->alua_type == SPC3_ALUA_EMULATED) { + tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port); + if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) { + printk(KERN_ERR "Unable to allocate t10_alua_tg_pt" + "_gp_member_t\n"); + return; + } + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + T10_ALUA(su_dev)->default_tg_pt_gp); + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + printk(KERN_INFO "%s/%s: Adding to default ALUA Target Port" + " Group: alua/default_tg_pt_gp\n", + TRANSPORT(dev)->name, TPG_TFO(tpg)->get_fabric_name()); + } + + dev->dev_port_count++; + port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFER */ +} + +/* + * Called with struct se_device->se_port_lock spinlock held. + */ +static void core_release_port(struct se_device *dev, struct se_port *port) +{ + /* + * Wait for any port reference for PR ALL_TG_PT=1 operation + * to complete in __core_scsi3_alloc_registration() + */ + spin_unlock(&dev->se_port_lock); + if (atomic_read(&port->sep_tg_pt_ref_cnt)) + cpu_relax(); + spin_lock(&dev->se_port_lock); + + core_alua_free_tg_pt_gp_mem(port); + + list_del(&port->sep_list); + dev->dev_port_count--; + kfree(port); + + return; +} + +int core_dev_export( + struct se_device *dev, + struct se_portal_group *tpg, + struct se_lun *lun) +{ + struct se_port *port; + + port = core_alloc_port(dev); + if (!(port)) + return -1; + + lun->lun_se_dev = dev; + se_dev_start(dev); + + atomic_inc(&dev->dev_export_obj.obj_access_count); + core_export_port(dev, tpg, port, lun); + return 0; +} + +void core_dev_unexport( + struct se_device *dev, + struct se_portal_group *tpg, + struct se_lun *lun) +{ + struct se_port *port = lun->lun_sep; + + spin_lock(&lun->lun_sep_lock); + if (lun->lun_se_dev == NULL) { + spin_unlock(&lun->lun_sep_lock); + return; + } + spin_unlock(&lun->lun_sep_lock); + + spin_lock(&dev->se_port_lock); + atomic_dec(&dev->dev_export_obj.obj_access_count); + core_release_port(dev, port); + spin_unlock(&dev->se_port_lock); + + se_dev_stop(dev); + lun->lun_se_dev = NULL; +} + +int transport_core_report_lun_response(struct se_cmd *se_cmd) +{ + struct se_dev_entry *deve; + struct se_lun *se_lun; + struct se_session *se_sess = SE_SESS(se_cmd); + struct se_task *se_task; + unsigned char *buf = (unsigned char *)T_TASK(se_cmd)->t_task_buf; + u32 cdb_offset = 0, lun_count = 0, offset = 8; + u64 i, lun; + + list_for_each_entry(se_task, &T_TASK(se_cmd)->t_task_list, t_list) + break; + + if (!(se_task)) { + printk(KERN_ERR "Unable to locate struct se_task for struct se_cmd\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + + /* + * If no struct se_session pointer is present, this struct se_cmd is + * coming via a target_core_mod PASSTHROUGH op, and not through + * a $FABRIC_MOD. In that case, report LUN=0 only. + */ + if (!(se_sess)) { + lun = 0; + buf[offset++] = ((lun >> 56) & 0xff); + buf[offset++] = ((lun >> 48) & 0xff); + buf[offset++] = ((lun >> 40) & 0xff); + buf[offset++] = ((lun >> 32) & 0xff); + buf[offset++] = ((lun >> 24) & 0xff); + buf[offset++] = ((lun >> 16) & 0xff); + buf[offset++] = ((lun >> 8) & 0xff); + buf[offset++] = (lun & 0xff); + lun_count = 1; + goto done; + } + + spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = &SE_NODE_ACL(se_sess)->device_list[i]; + if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) + continue; + se_lun = deve->se_lun; + /* + * We determine the correct LUN LIST LENGTH even once we + * have reached the initial allocation length. + * See SPC2-R20 7.19. + */ + lun_count++; + if ((cdb_offset + 8) >= se_cmd->data_length) + continue; + + lun = cpu_to_be64(CMD_TFO(se_cmd)->pack_lun(deve->mapped_lun)); + buf[offset++] = ((lun >> 56) & 0xff); + buf[offset++] = ((lun >> 48) & 0xff); + buf[offset++] = ((lun >> 40) & 0xff); + buf[offset++] = ((lun >> 32) & 0xff); + buf[offset++] = ((lun >> 24) & 0xff); + buf[offset++] = ((lun >> 16) & 0xff); + buf[offset++] = ((lun >> 8) & 0xff); + buf[offset++] = (lun & 0xff); + cdb_offset += 8; + } + spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock); + + /* + * See SPC3 r07, page 159. + */ +done: + lun_count *= 8; + buf[0] = ((lun_count >> 24) & 0xff); + buf[1] = ((lun_count >> 16) & 0xff); + buf[2] = ((lun_count >> 8) & 0xff); + buf[3] = (lun_count & 0xff); + + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} + +/* se_release_device_for_hba(): + * + * + */ +void se_release_device_for_hba(struct se_device *dev) +{ + struct se_hba *hba = dev->se_hba; + + if ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) || + (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) || + (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) || + (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_ACTIVATED) || + (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_DEACTIVATED)) + se_dev_stop(dev); + + if (dev->dev_ptr) { + kthread_stop(dev->process_thread); + if (dev->transport->free_device) + dev->transport->free_device(dev->dev_ptr); + } + + spin_lock(&hba->device_lock); + list_del(&dev->dev_list); + hba->dev_count--; + spin_unlock(&hba->device_lock); + + core_scsi3_free_all_registrations(dev); + se_release_vpd_for_dev(dev); + + kfree(dev->dev_status_queue_obj); + kfree(dev->dev_queue_obj); + kfree(dev); + + return; +} + +void se_release_vpd_for_dev(struct se_device *dev) +{ + struct t10_vpd *vpd, *vpd_tmp; + + spin_lock(&DEV_T10_WWN(dev)->t10_vpd_lock); + list_for_each_entry_safe(vpd, vpd_tmp, + &DEV_T10_WWN(dev)->t10_vpd_list, vpd_list) { + list_del(&vpd->vpd_list); + kfree(vpd); + } + spin_unlock(&DEV_T10_WWN(dev)->t10_vpd_lock); + + return; +} + +/* + * Called with struct se_hba->device_lock held. + */ +void se_clear_dev_ports(struct se_device *dev) +{ + struct se_hba *hba = dev->se_hba; + struct se_lun *lun; + struct se_portal_group *tpg; + struct se_port *sep, *sep_tmp; + + spin_lock(&dev->se_port_lock); + list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { + spin_unlock(&dev->se_port_lock); + spin_unlock(&hba->device_lock); + + lun = sep->sep_lun; + tpg = sep->sep_tpg; + spin_lock(&lun->lun_sep_lock); + if (lun->lun_se_dev == NULL) { + spin_unlock(&lun->lun_sep_lock); + continue; + } + spin_unlock(&lun->lun_sep_lock); + + core_dev_del_lun(tpg, lun->unpacked_lun); + + spin_lock(&hba->device_lock); + spin_lock(&dev->se_port_lock); + } + spin_unlock(&dev->se_port_lock); + + return; +} + +/* se_free_virtual_device(): + * + * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. + */ +int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) +{ + spin_lock(&hba->device_lock); + se_clear_dev_ports(dev); + spin_unlock(&hba->device_lock); + + core_alua_free_lu_gp_mem(dev); + se_release_device_for_hba(dev); + + return 0; +} + +static void se_dev_start(struct se_device *dev) +{ + struct se_hba *hba = dev->se_hba; + + spin_lock(&hba->device_lock); + atomic_inc(&dev->dev_obj.obj_access_count); + if (atomic_read(&dev->dev_obj.obj_access_count) == 1) { + if (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) { + dev->dev_status &= ~TRANSPORT_DEVICE_DEACTIVATED; + dev->dev_status |= TRANSPORT_DEVICE_ACTIVATED; + } else if (dev->dev_status & + TRANSPORT_DEVICE_OFFLINE_DEACTIVATED) { + dev->dev_status &= + ~TRANSPORT_DEVICE_OFFLINE_DEACTIVATED; + dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_ACTIVATED; + } + } + spin_unlock(&hba->device_lock); +} + +static void se_dev_stop(struct se_device *dev) +{ + struct se_hba *hba = dev->se_hba; + + spin_lock(&hba->device_lock); + atomic_dec(&dev->dev_obj.obj_access_count); + if (atomic_read(&dev->dev_obj.obj_access_count) == 0) { + if (dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) { + dev->dev_status &= ~TRANSPORT_DEVICE_ACTIVATED; + dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; + } else if (dev->dev_status & + TRANSPORT_DEVICE_OFFLINE_ACTIVATED) { + dev->dev_status &= ~TRANSPORT_DEVICE_OFFLINE_ACTIVATED; + dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_DEACTIVATED; + } + } + spin_unlock(&hba->device_lock); + + while (atomic_read(&hba->dev_mib_access_count)) + cpu_relax(); +} + +int se_dev_check_online(struct se_device *dev) +{ + int ret; + + spin_lock_irq(&dev->dev_status_lock); + ret = ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) || + (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED)) ? 0 : 1; + spin_unlock_irq(&dev->dev_status_lock); + + return ret; +} + +int se_dev_check_shutdown(struct se_device *dev) +{ + int ret; + + spin_lock_irq(&dev->dev_status_lock); + ret = (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN); + spin_unlock_irq(&dev->dev_status_lock); + + return ret; +} + +void se_dev_set_default_attribs( + struct se_device *dev, + struct se_dev_limits *dev_limits) +{ + struct queue_limits *limits = &dev_limits->limits; + + DEV_ATTRIB(dev)->emulate_dpo = DA_EMULATE_DPO; + DEV_ATTRIB(dev)->emulate_fua_write = DA_EMULATE_FUA_WRITE; + DEV_ATTRIB(dev)->emulate_fua_read = DA_EMULATE_FUA_READ; + DEV_ATTRIB(dev)->emulate_write_cache = DA_EMULATE_WRITE_CACHE; + DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; + DEV_ATTRIB(dev)->emulate_tas = DA_EMULATE_TAS; + DEV_ATTRIB(dev)->emulate_tpu = DA_EMULATE_TPU; + DEV_ATTRIB(dev)->emulate_tpws = DA_EMULATE_TPWS; + DEV_ATTRIB(dev)->emulate_reservations = DA_EMULATE_RESERVATIONS; + DEV_ATTRIB(dev)->emulate_alua = DA_EMULATE_ALUA; + DEV_ATTRIB(dev)->enforce_pr_isids = DA_ENFORCE_PR_ISIDS; + /* + * The TPU=1 and TPWS=1 settings will be set in TCM/IBLOCK + * iblock_create_virtdevice() from struct queue_limits values + * if blk_queue_discard()==1 + */ + DEV_ATTRIB(dev)->max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT; + DEV_ATTRIB(dev)->max_unmap_block_desc_count = + DA_MAX_UNMAP_BLOCK_DESC_COUNT; + DEV_ATTRIB(dev)->unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT; + DEV_ATTRIB(dev)->unmap_granularity_alignment = + DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT; + /* + * block_size is based on subsystem plugin dependent requirements. + */ + DEV_ATTRIB(dev)->hw_block_size = limits->logical_block_size; + DEV_ATTRIB(dev)->block_size = limits->logical_block_size; + /* + * max_sectors is based on subsystem plugin dependent requirements. + */ + DEV_ATTRIB(dev)->hw_max_sectors = limits->max_hw_sectors; + DEV_ATTRIB(dev)->max_sectors = limits->max_sectors; + /* + * Set optimal_sectors from max_sectors, which can be lowered via + * configfs. + */ + DEV_ATTRIB(dev)->optimal_sectors = limits->max_sectors; + /* + * queue_depth is based on subsystem plugin dependent requirements. + */ + DEV_ATTRIB(dev)->hw_queue_depth = dev_limits->hw_queue_depth; + DEV_ATTRIB(dev)->queue_depth = dev_limits->queue_depth; +} + +int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout) +{ + if (task_timeout > DA_TASK_TIMEOUT_MAX) { + printk(KERN_ERR "dev[%p]: Passed task_timeout: %u larger then" + " DA_TASK_TIMEOUT_MAX\n", dev, task_timeout); + return -1; + } else { + DEV_ATTRIB(dev)->task_timeout = task_timeout; + printk(KERN_INFO "dev[%p]: Set SE Device task_timeout: %u\n", + dev, task_timeout); + } + + return 0; +} + +int se_dev_set_max_unmap_lba_count( + struct se_device *dev, + u32 max_unmap_lba_count) +{ + DEV_ATTRIB(dev)->max_unmap_lba_count = max_unmap_lba_count; + printk(KERN_INFO "dev[%p]: Set max_unmap_lba_count: %u\n", + dev, DEV_ATTRIB(dev)->max_unmap_lba_count); + return 0; +} + +int se_dev_set_max_unmap_block_desc_count( + struct se_device *dev, + u32 max_unmap_block_desc_count) +{ + DEV_ATTRIB(dev)->max_unmap_block_desc_count = max_unmap_block_desc_count; + printk(KERN_INFO "dev[%p]: Set max_unmap_block_desc_count: %u\n", + dev, DEV_ATTRIB(dev)->max_unmap_block_desc_count); + return 0; +} + +int se_dev_set_unmap_granularity( + struct se_device *dev, + u32 unmap_granularity) +{ + DEV_ATTRIB(dev)->unmap_granularity = unmap_granularity; + printk(KERN_INFO "dev[%p]: Set unmap_granularity: %u\n", + dev, DEV_ATTRIB(dev)->unmap_granularity); + return 0; +} + +int se_dev_set_unmap_granularity_alignment( + struct se_device *dev, + u32 unmap_granularity_alignment) +{ + DEV_ATTRIB(dev)->unmap_granularity_alignment = unmap_granularity_alignment; + printk(KERN_INFO "dev[%p]: Set unmap_granularity_alignment: %u\n", + dev, DEV_ATTRIB(dev)->unmap_granularity_alignment); + return 0; +} + +int se_dev_set_emulate_dpo(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + if (TRANSPORT(dev)->dpo_emulated == NULL) { + printk(KERN_ERR "TRANSPORT(dev)->dpo_emulated is NULL\n"); + return -1; + } + if (TRANSPORT(dev)->dpo_emulated(dev) == 0) { + printk(KERN_ERR "TRANSPORT(dev)->dpo_emulated not supported\n"); + return -1; + } + DEV_ATTRIB(dev)->emulate_dpo = flag; + printk(KERN_INFO "dev[%p]: SE Device Page Out (DPO) Emulation" + " bit: %d\n", dev, DEV_ATTRIB(dev)->emulate_dpo); + return 0; +} + +int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + if (TRANSPORT(dev)->fua_write_emulated == NULL) { + printk(KERN_ERR "TRANSPORT(dev)->fua_write_emulated is NULL\n"); + return -1; + } + if (TRANSPORT(dev)->fua_write_emulated(dev) == 0) { + printk(KERN_ERR "TRANSPORT(dev)->fua_write_emulated not supported\n"); + return -1; + } + DEV_ATTRIB(dev)->emulate_fua_write = flag; + printk(KERN_INFO "dev[%p]: SE Device Forced Unit Access WRITEs: %d\n", + dev, DEV_ATTRIB(dev)->emulate_fua_write); + return 0; +} + +int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + if (TRANSPORT(dev)->fua_read_emulated == NULL) { + printk(KERN_ERR "TRANSPORT(dev)->fua_read_emulated is NULL\n"); + return -1; + } + if (TRANSPORT(dev)->fua_read_emulated(dev) == 0) { + printk(KERN_ERR "TRANSPORT(dev)->fua_read_emulated not supported\n"); + return -1; + } + DEV_ATTRIB(dev)->emulate_fua_read = flag; + printk(KERN_INFO "dev[%p]: SE Device Forced Unit Access READs: %d\n", + dev, DEV_ATTRIB(dev)->emulate_fua_read); + return 0; +} + +int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + if (TRANSPORT(dev)->write_cache_emulated == NULL) { + printk(KERN_ERR "TRANSPORT(dev)->write_cache_emulated is NULL\n"); + return -1; + } + if (TRANSPORT(dev)->write_cache_emulated(dev) == 0) { + printk(KERN_ERR "TRANSPORT(dev)->write_cache_emulated not supported\n"); + return -1; + } + DEV_ATTRIB(dev)->emulate_write_cache = flag; + printk(KERN_INFO "dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", + dev, DEV_ATTRIB(dev)->emulate_write_cache); + return 0; +} + +int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1) && (flag != 2)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "dev[%p]: Unable to change SE Device" + " UA_INTRLCK_CTRL while dev_export_obj: %d count" + " exists\n", dev, + atomic_read(&dev->dev_export_obj.obj_access_count)); + return -1; + } + DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = flag; + printk(KERN_INFO "dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", + dev, DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl); + + return 0; +} + +int se_dev_set_emulate_tas(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "dev[%p]: Unable to change SE Device TAS while" + " dev_export_obj: %d count exists\n", dev, + atomic_read(&dev->dev_export_obj.obj_access_count)); + return -1; + } + DEV_ATTRIB(dev)->emulate_tas = flag; + printk(KERN_INFO "dev[%p]: SE Device TASK_ABORTED status bit: %s\n", + dev, (DEV_ATTRIB(dev)->emulate_tas) ? "Enabled" : "Disabled"); + + return 0; +} + +int se_dev_set_emulate_tpu(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) { + printk(KERN_ERR "Generic Block Discard not supported\n"); + return -ENOSYS; + } + + DEV_ATTRIB(dev)->emulate_tpu = flag; + printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", + dev, flag); + return 0; +} + +int se_dev_set_emulate_tpws(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) { + printk(KERN_ERR "Generic Block Discard not supported\n"); + return -ENOSYS; + } + + DEV_ATTRIB(dev)->emulate_tpws = flag; + printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", + dev, flag); + return 0; +} + +int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag) +{ + if ((flag != 0) && (flag != 1)) { + printk(KERN_ERR "Illegal value %d\n", flag); + return -1; + } + DEV_ATTRIB(dev)->enforce_pr_isids = flag; + printk(KERN_INFO "dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev, + (DEV_ATTRIB(dev)->enforce_pr_isids) ? "Enabled" : "Disabled"); + return 0; +} + +/* + * Note, this can only be called on unexported SE Device Object. + */ +int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) +{ + u32 orig_queue_depth = dev->queue_depth; + + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "dev[%p]: Unable to change SE Device TCQ while" + " dev_export_obj: %d count exists\n", dev, + atomic_read(&dev->dev_export_obj.obj_access_count)); + return -1; + } + if (!(queue_depth)) { + printk(KERN_ERR "dev[%p]: Illegal ZERO value for queue" + "_depth\n", dev); + return -1; + } + + if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { + if (queue_depth > DEV_ATTRIB(dev)->hw_queue_depth) { + printk(KERN_ERR "dev[%p]: Passed queue_depth: %u" + " exceeds TCM/SE_Device TCQ: %u\n", + dev, queue_depth, + DEV_ATTRIB(dev)->hw_queue_depth); + return -1; + } + } else { + if (queue_depth > DEV_ATTRIB(dev)->queue_depth) { + if (queue_depth > DEV_ATTRIB(dev)->hw_queue_depth) { + printk(KERN_ERR "dev[%p]: Passed queue_depth:" + " %u exceeds TCM/SE_Device MAX" + " TCQ: %u\n", dev, queue_depth, + DEV_ATTRIB(dev)->hw_queue_depth); + return -1; + } + } + } + + DEV_ATTRIB(dev)->queue_depth = dev->queue_depth = queue_depth; + if (queue_depth > orig_queue_depth) + atomic_add(queue_depth - orig_queue_depth, &dev->depth_left); + else if (queue_depth < orig_queue_depth) + atomic_sub(orig_queue_depth - queue_depth, &dev->depth_left); + + printk(KERN_INFO "dev[%p]: SE Device TCQ Depth changed to: %u\n", + dev, queue_depth); + return 0; +} + +int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors) +{ + int force = 0; /* Force setting for VDEVS */ + + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "dev[%p]: Unable to change SE Device" + " max_sectors while dev_export_obj: %d count exists\n", + dev, atomic_read(&dev->dev_export_obj.obj_access_count)); + return -1; + } + if (!(max_sectors)) { + printk(KERN_ERR "dev[%p]: Illegal ZERO value for" + " max_sectors\n", dev); + return -1; + } + if (max_sectors < DA_STATUS_MAX_SECTORS_MIN) { + printk(KERN_ERR "dev[%p]: Passed max_sectors: %u less than" + " DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, max_sectors, + DA_STATUS_MAX_SECTORS_MIN); + return -1; + } + if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { + if (max_sectors > DEV_ATTRIB(dev)->hw_max_sectors) { + printk(KERN_ERR "dev[%p]: Passed max_sectors: %u" + " greater than TCM/SE_Device max_sectors:" + " %u\n", dev, max_sectors, + DEV_ATTRIB(dev)->hw_max_sectors); + return -1; + } + } else { + if (!(force) && (max_sectors > + DEV_ATTRIB(dev)->hw_max_sectors)) { + printk(KERN_ERR "dev[%p]: Passed max_sectors: %u" + " greater than TCM/SE_Device max_sectors" + ": %u, use force=1 to override.\n", dev, + max_sectors, DEV_ATTRIB(dev)->hw_max_sectors); + return -1; + } + if (max_sectors > DA_STATUS_MAX_SECTORS_MAX) { + printk(KERN_ERR "dev[%p]: Passed max_sectors: %u" + " greater than DA_STATUS_MAX_SECTORS_MAX:" + " %u\n", dev, max_sectors, + DA_STATUS_MAX_SECTORS_MAX); + return -1; + } + } + + DEV_ATTRIB(dev)->max_sectors = max_sectors; + printk("dev[%p]: SE Device max_sectors changed to %u\n", + dev, max_sectors); + return 0; +} + +int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) +{ + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "dev[%p]: Unable to change SE Device" + " optimal_sectors while dev_export_obj: %d count exists\n", + dev, atomic_read(&dev->dev_export_obj.obj_access_count)); + return -EINVAL; + } + if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { + printk(KERN_ERR "dev[%p]: Passed optimal_sectors cannot be" + " changed for TCM/pSCSI\n", dev); + return -EINVAL; + } + if (optimal_sectors > DEV_ATTRIB(dev)->max_sectors) { + printk(KERN_ERR "dev[%p]: Passed optimal_sectors %u cannot be" + " greater than max_sectors: %u\n", dev, + optimal_sectors, DEV_ATTRIB(dev)->max_sectors); + return -EINVAL; + } + + DEV_ATTRIB(dev)->optimal_sectors = optimal_sectors; + printk(KERN_INFO "dev[%p]: SE Device optimal_sectors changed to %u\n", + dev, optimal_sectors); + return 0; +} + +int se_dev_set_block_size(struct se_device *dev, u32 block_size) +{ + if (atomic_read(&dev->dev_export_obj.obj_access_count)) { + printk(KERN_ERR "dev[%p]: Unable to change SE Device block_size" + " while dev_export_obj: %d count exists\n", dev, + atomic_read(&dev->dev_export_obj.obj_access_count)); + return -1; + } + + if ((block_size != 512) && + (block_size != 1024) && + (block_size != 2048) && + (block_size != 4096)) { + printk(KERN_ERR "dev[%p]: Illegal value for block_device: %u" + " for SE device, must be 512, 1024, 2048 or 4096\n", + dev, block_size); + return -1; + } + + if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { + printk(KERN_ERR "dev[%p]: Not allowed to change block_size for" + " Physical Device, use for Linux/SCSI to change" + " block_size for underlying hardware\n", dev); + return -1; + } + + DEV_ATTRIB(dev)->block_size = block_size; + printk(KERN_INFO "dev[%p]: SE Device block_size changed to %u\n", + dev, block_size); + return 0; +} + +struct se_lun *core_dev_add_lun( + struct se_portal_group *tpg, + struct se_hba *hba, + struct se_device *dev, + u32 lun) +{ + struct se_lun *lun_p; + u32 lun_access = 0; + + if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) { + printk(KERN_ERR "Unable to export struct se_device while dev_access_obj: %d\n", + atomic_read(&dev->dev_access_obj.obj_access_count)); + return NULL; + } + + lun_p = core_tpg_pre_addlun(tpg, lun); + if ((IS_ERR(lun_p)) || !(lun_p)) + return NULL; + + if (dev->dev_flags & DF_READ_ONLY) + lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + else + lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; + + if (core_tpg_post_addlun(tpg, lun_p, lun_access, dev) < 0) + return NULL; + + printk(KERN_INFO "%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" + " CORE HBA: %u\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), lun_p->unpacked_lun, + TPG_TFO(tpg)->get_fabric_name(), hba->hba_id); + /* + * Update LUN maps for dynamically added initiators when + * generate_node_acl is enabled. + */ + if (TPG_TFO(tpg)->tpg_check_demo_mode(tpg)) { + struct se_node_acl *acl; + spin_lock_bh(&tpg->acl_node_lock); + list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { + if (acl->dynamic_node_acl) { + spin_unlock_bh(&tpg->acl_node_lock); + core_tpg_add_node_to_devs(acl, tpg); + spin_lock_bh(&tpg->acl_node_lock); + } + } + spin_unlock_bh(&tpg->acl_node_lock); + } + + return lun_p; +} + +/* core_dev_del_lun(): + * + * + */ +int core_dev_del_lun( + struct se_portal_group *tpg, + u32 unpacked_lun) +{ + struct se_lun *lun; + int ret = 0; + + lun = core_tpg_pre_dellun(tpg, unpacked_lun, &ret); + if (!(lun)) + return ret; + + core_tpg_post_dellun(tpg, lun); + + printk(KERN_INFO "%s_TPG[%u]_LUN[%u] - Deactivated %s Logical Unit from" + " device object\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), unpacked_lun, + TPG_TFO(tpg)->get_fabric_name()); + + return 0; +} + +struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_lun) +{ + struct se_lun *lun; + + spin_lock(&tpg->tpg_lun_lock); + if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { + printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS" + "_PER_TPG-1: %u for Target Portal Group: %hu\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TRANSPORT_MAX_LUNS_PER_TPG-1, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&tpg->tpg_lun_lock); + return NULL; + } + lun = &tpg->tpg_lun_list[unpacked_lun]; + + if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) { + printk(KERN_ERR "%s Logical Unit Number: %u is not free on" + " Target Portal Group: %hu, ignoring request.\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&tpg->tpg_lun_lock); + return NULL; + } + spin_unlock(&tpg->tpg_lun_lock); + + return lun; +} + +/* core_dev_get_lun(): + * + * + */ +static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked_lun) +{ + struct se_lun *lun; + + spin_lock(&tpg->tpg_lun_lock); + if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { + printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER" + "_TPG-1: %u for Target Portal Group: %hu\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TRANSPORT_MAX_LUNS_PER_TPG-1, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&tpg->tpg_lun_lock); + return NULL; + } + lun = &tpg->tpg_lun_list[unpacked_lun]; + + if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { + printk(KERN_ERR "%s Logical Unit Number: %u is not active on" + " Target Portal Group: %hu, ignoring request.\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&tpg->tpg_lun_lock); + return NULL; + } + spin_unlock(&tpg->tpg_lun_lock); + + return lun; +} + +struct se_lun_acl *core_dev_init_initiator_node_lun_acl( + struct se_portal_group *tpg, + u32 mapped_lun, + char *initiatorname, + int *ret) +{ + struct se_lun_acl *lacl; + struct se_node_acl *nacl; + + if (strlen(initiatorname) > TRANSPORT_IQN_LEN) { + printk(KERN_ERR "%s InitiatorName exceeds maximum size.\n", + TPG_TFO(tpg)->get_fabric_name()); + *ret = -EOVERFLOW; + return NULL; + } + nacl = core_tpg_get_initiator_node_acl(tpg, initiatorname); + if (!(nacl)) { + *ret = -EINVAL; + return NULL; + } + lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL); + if (!(lacl)) { + printk(KERN_ERR "Unable to allocate memory for struct se_lun_acl.\n"); + *ret = -ENOMEM; + return NULL; + } + + INIT_LIST_HEAD(&lacl->lacl_list); + lacl->mapped_lun = mapped_lun; + lacl->se_lun_nacl = nacl; + snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); + + return lacl; +} + +int core_dev_add_initiator_node_lun_acl( + struct se_portal_group *tpg, + struct se_lun_acl *lacl, + u32 unpacked_lun, + u32 lun_access) +{ + struct se_lun *lun; + struct se_node_acl *nacl; + + lun = core_dev_get_lun(tpg, unpacked_lun); + if (!(lun)) { + printk(KERN_ERR "%s Logical Unit Number: %u is not active on" + " Target Portal Group: %hu, ignoring request.\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + return -EINVAL; + } + + nacl = lacl->se_lun_nacl; + if (!(nacl)) + return -EINVAL; + + if ((lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) && + (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE)) + lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + + lacl->se_lun = lun; + + if (core_update_device_list_for_node(lun, lacl, lacl->mapped_lun, + lun_access, nacl, tpg, 1) < 0) + return -EINVAL; + + spin_lock(&lun->lun_acl_lock); + list_add_tail(&lacl->lacl_list, &lun->lun_acl_list); + atomic_inc(&lun->lun_acl_count); + smp_mb__after_atomic_inc(); + spin_unlock(&lun->lun_acl_lock); + + printk(KERN_INFO "%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " + " InitiatorNode: %s\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), unpacked_lun, lacl->mapped_lun, + (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", + lacl->initiatorname); + /* + * Check to see if there are any existing persistent reservation APTPL + * pre-registrations that need to be enabled for this LUN ACL.. + */ + core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, lacl); + return 0; +} + +/* core_dev_del_initiator_node_lun_acl(): + * + * + */ +int core_dev_del_initiator_node_lun_acl( + struct se_portal_group *tpg, + struct se_lun *lun, + struct se_lun_acl *lacl) +{ + struct se_node_acl *nacl; + + nacl = lacl->se_lun_nacl; + if (!(nacl)) + return -EINVAL; + + spin_lock(&lun->lun_acl_lock); + list_del(&lacl->lacl_list); + atomic_dec(&lun->lun_acl_count); + smp_mb__after_atomic_dec(); + spin_unlock(&lun->lun_acl_lock); + + core_update_device_list_for_node(lun, NULL, lacl->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + + lacl->se_lun = NULL; + + printk(KERN_INFO "%s_TPG[%hu]_LUN[%u] - Removed ACL for" + " InitiatorNode: %s Mapped LUN: %u\n", + TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), lun->unpacked_lun, + lacl->initiatorname, lacl->mapped_lun); + + return 0; +} + +void core_dev_free_initiator_node_lun_acl( + struct se_portal_group *tpg, + struct se_lun_acl *lacl) +{ + printk("%s_TPG[%hu] - Freeing ACL for %s InitiatorNode: %s" + " Mapped LUN: %u\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), + TPG_TFO(tpg)->get_fabric_name(), + lacl->initiatorname, lacl->mapped_lun); + + kfree(lacl); +} + +int core_dev_setup_virtual_lun0(void) +{ + struct se_hba *hba; + struct se_device *dev; + struct se_subsystem_dev *se_dev = NULL; + struct se_subsystem_api *t; + char buf[16]; + int ret; + + hba = core_alloc_hba("rd_dr", 0, HBA_FLAGS_INTERNAL_USE); + if (IS_ERR(hba)) + return PTR_ERR(hba); + + se_global->g_lun0_hba = hba; + t = hba->transport; + + se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL); + if (!(se_dev)) { + printk(KERN_ERR "Unable to allocate memory for" + " struct se_subsystem_dev\n"); + ret = -ENOMEM; + goto out; + } + INIT_LIST_HEAD(&se_dev->g_se_dev_list); + INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); + spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); + INIT_LIST_HEAD(&se_dev->t10_reservation.registration_list); + INIT_LIST_HEAD(&se_dev->t10_reservation.aptpl_reg_list); + spin_lock_init(&se_dev->t10_reservation.registration_lock); + spin_lock_init(&se_dev->t10_reservation.aptpl_reg_lock); + INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list); + spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock); + spin_lock_init(&se_dev->se_dev_lock); + se_dev->t10_reservation.pr_aptpl_buf_len = PR_APTPL_BUF_LEN; + se_dev->t10_wwn.t10_sub_dev = se_dev; + se_dev->t10_alua.t10_sub_dev = se_dev; + se_dev->se_dev_attrib.da_sub_dev = se_dev; + se_dev->se_dev_hba = hba; + + se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, "virt_lun0"); + if (!(se_dev->se_dev_su_ptr)) { + printk(KERN_ERR "Unable to locate subsystem dependent pointer" + " from allocate_virtdevice()\n"); + ret = -ENOMEM; + goto out; + } + se_global->g_lun0_su_dev = se_dev; + + memset(buf, 0, 16); + sprintf(buf, "rd_pages=8"); + t->set_configfs_dev_params(hba, se_dev, buf, sizeof(buf)); + + dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); + if (!(dev) || IS_ERR(dev)) { + ret = -ENOMEM; + goto out; + } + se_dev->se_dev_ptr = dev; + se_global->g_lun0_dev = dev; + + return 0; +out: + se_global->g_lun0_su_dev = NULL; + kfree(se_dev); + if (se_global->g_lun0_hba) { + core_delete_hba(se_global->g_lun0_hba); + se_global->g_lun0_hba = NULL; + } + return ret; +} + + +void core_dev_release_virtual_lun0(void) +{ + struct se_hba *hba = se_global->g_lun0_hba; + struct se_subsystem_dev *su_dev = se_global->g_lun0_su_dev; + + if (!(hba)) + return; + + if (se_global->g_lun0_dev) + se_free_virtual_device(se_global->g_lun0_dev, hba); + + kfree(su_dev); + core_delete_hba(hba); +} diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c new file mode 100644 index 000000000000..32b148d7e261 --- /dev/null +++ b/drivers/target/target_core_fabric_configfs.c @@ -0,0 +1,996 @@ +/******************************************************************************* +* Filename: target_core_fabric_configfs.c + * + * This file contains generic fabric module configfs infrastructure for + * TCM v4.x code + * + * Copyright (c) 2010 Rising Tide Systems + * Copyright (c) 2010 Linux-iSCSI.org + * + * Copyright (c) 2010 Nicholas A. Bellinger +* + * 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 +#include +#include +#include +#include +#include + +#include "target_core_alua.h" +#include "target_core_hba.h" +#include "target_core_pr.h" + +#define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ +static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ +{ \ + struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ + struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + \ + cit->ct_item_ops = _item_ops; \ + cit->ct_group_ops = _group_ops; \ + cit->ct_attrs = _attrs; \ + cit->ct_owner = tf->tf_module; \ + printk("Setup generic %s\n", __stringify(_name)); \ +} + +/* Start of tfc_tpg_mappedlun_cit */ + +static int target_fabric_mappedlun_link( + struct config_item *lun_acl_ci, + struct config_item *lun_ci) +{ + struct se_dev_entry *deve; + struct se_lun *lun = container_of(to_config_group(lun_ci), + struct se_lun, lun_group); + struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), + struct se_lun_acl, se_lun_group); + struct se_portal_group *se_tpg; + struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; + int ret = 0, lun_access; + /* + * Ensure that the source port exists + */ + if (!(lun->lun_sep) || !(lun->lun_sep->sep_tpg)) { + printk(KERN_ERR "Source se_lun->lun_sep or lun->lun_sep->sep" + "_tpg does not exist\n"); + return -EINVAL; + } + se_tpg = lun->lun_sep->sep_tpg; + + nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item; + tpg_ci = &nacl_ci->ci_group->cg_item; + wwn_ci = &tpg_ci->ci_group->cg_item; + tpg_ci_s = &lun_ci->ci_parent->ci_group->cg_item; + wwn_ci_s = &tpg_ci_s->ci_group->cg_item; + /* + * Make sure the SymLink is going to the same $FABRIC/$WWN/tpgt_$TPGT + */ + if (strcmp(config_item_name(wwn_ci), config_item_name(wwn_ci_s))) { + printk(KERN_ERR "Illegal Initiator ACL SymLink outside of %s\n", + config_item_name(wwn_ci)); + return -EINVAL; + } + if (strcmp(config_item_name(tpg_ci), config_item_name(tpg_ci_s))) { + printk(KERN_ERR "Illegal Initiator ACL Symlink outside of %s" + " TPGT: %s\n", config_item_name(wwn_ci), + config_item_name(tpg_ci)); + return -EINVAL; + } + /* + * If this struct se_node_acl was dynamically generated with + * tpg_1/attrib/generate_node_acls=1, use the existing deve->lun_flags, + * which be will write protected (READ-ONLY) when + * tpg_1/attrib/demo_mode_write_protect=1 + */ + spin_lock_irq(&lacl->se_lun_nacl->device_list_lock); + deve = &lacl->se_lun_nacl->device_list[lacl->mapped_lun]; + if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) + lun_access = deve->lun_flags; + else + lun_access = + (TPG_TFO(se_tpg)->tpg_check_prod_mode_write_protect( + se_tpg)) ? TRANSPORT_LUNFLAGS_READ_ONLY : + TRANSPORT_LUNFLAGS_READ_WRITE; + spin_unlock_irq(&lacl->se_lun_nacl->device_list_lock); + /* + * Determine the actual mapped LUN value user wants.. + * + * This value is what the SCSI Initiator actually sees the + * iscsi/$IQN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. + */ + ret = core_dev_add_initiator_node_lun_acl(se_tpg, lacl, + lun->unpacked_lun, lun_access); + + return (ret < 0) ? -EINVAL : 0; +} + +static int target_fabric_mappedlun_unlink( + struct config_item *lun_acl_ci, + struct config_item *lun_ci) +{ + struct se_lun *lun; + struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), + struct se_lun_acl, se_lun_group); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve = &nacl->device_list[lacl->mapped_lun]; + struct se_portal_group *se_tpg; + /* + * Determine if the underlying MappedLUN has already been released.. + */ + if (!(deve->se_lun)) + return 0; + + lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); + se_tpg = lun->lun_sep->sep_tpg; + + core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); + return 0; +} + +CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl); +#define TCM_MAPPEDLUN_ATTR(_name, _mode) \ +static struct target_fabric_mappedlun_attribute target_fabric_mappedlun_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_fabric_mappedlun_show_##_name, \ + target_fabric_mappedlun_store_##_name); + +static ssize_t target_fabric_mappedlun_show_write_protect( + struct se_lun_acl *lacl, + char *page) +{ + struct se_node_acl *se_nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t len; + + spin_lock_irq(&se_nacl->device_list_lock); + deve = &se_nacl->device_list[lacl->mapped_lun]; + len = sprintf(page, "%d\n", + (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ? + 1 : 0); + spin_unlock_irq(&se_nacl->device_list_lock); + + return len; +} + +static ssize_t target_fabric_mappedlun_store_write_protect( + struct se_lun_acl *lacl, + const char *page, + size_t count) +{ + struct se_node_acl *se_nacl = lacl->se_lun_nacl; + struct se_portal_group *se_tpg = se_nacl->se_tpg; + unsigned long op; + + if (strict_strtoul(page, 0, &op)) + return -EINVAL; + + if ((op != 1) && (op != 0)) + return -EINVAL; + + core_update_device_list_access(lacl->mapped_lun, (op) ? + TRANSPORT_LUNFLAGS_READ_ONLY : + TRANSPORT_LUNFLAGS_READ_WRITE, + lacl->se_lun_nacl); + + printk(KERN_INFO "%s_ConfigFS: Changed Initiator ACL: %s" + " Mapped LUN: %u Write Protect bit to %s\n", + TPG_TFO(se_tpg)->get_fabric_name(), + lacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF"); + + return count; + +} + +TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR); + +CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group); + +static struct configfs_attribute *target_fabric_mappedlun_attrs[] = { + &target_fabric_mappedlun_write_protect.attr, + NULL, +}; + +static struct configfs_item_operations target_fabric_mappedlun_item_ops = { + .show_attribute = target_fabric_mappedlun_attr_show, + .store_attribute = target_fabric_mappedlun_attr_store, + .allow_link = target_fabric_mappedlun_link, + .drop_link = target_fabric_mappedlun_unlink, +}; + +TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL, + target_fabric_mappedlun_attrs); + +/* End of tfc_tpg_mappedlun_cit */ + +/* Start of tfc_tpg_nacl_attrib_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); + +static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = { + .show_attribute = target_fabric_nacl_attrib_attr_show, + .store_attribute = target_fabric_nacl_attrib_attr_store, +}; + +TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL); + +/* End of tfc_tpg_nacl_attrib_cit */ + +/* Start of tfc_tpg_nacl_auth_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_nacl_auth, se_node_acl, acl_auth_group); + +static struct configfs_item_operations target_fabric_nacl_auth_item_ops = { + .show_attribute = target_fabric_nacl_auth_attr_show, + .store_attribute = target_fabric_nacl_auth_attr_store, +}; + +TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL); + +/* End of tfc_tpg_nacl_auth_cit */ + +/* Start of tfc_tpg_nacl_param_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_nacl_param, se_node_acl, acl_param_group); + +static struct configfs_item_operations target_fabric_nacl_param_item_ops = { + .show_attribute = target_fabric_nacl_param_attr_show, + .store_attribute = target_fabric_nacl_param_attr_store, +}; + +TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL); + +/* End of tfc_tpg_nacl_param_cit */ + +/* Start of tfc_tpg_nacl_base_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_nacl_base, se_node_acl, acl_group); + +static struct config_group *target_fabric_make_mappedlun( + struct config_group *group, + const char *name) +{ + struct se_node_acl *se_nacl = container_of(group, + struct se_node_acl, acl_group); + struct se_portal_group *se_tpg = se_nacl->se_tpg; + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct se_lun_acl *lacl; + struct config_item *acl_ci; + char *buf; + unsigned long mapped_lun; + int ret = 0; + + acl_ci = &group->cg_item; + if (!(acl_ci)) { + printk(KERN_ERR "Unable to locatel acl_ci\n"); + return NULL; + } + + buf = kzalloc(strlen(name) + 1, GFP_KERNEL); + if (!(buf)) { + printk(KERN_ERR "Unable to allocate memory for name buf\n"); + return ERR_PTR(-ENOMEM); + } + snprintf(buf, strlen(name) + 1, "%s", name); + /* + * Make sure user is creating iscsi/$IQN/$TPGT/acls/$INITIATOR/lun_$ID. + */ + if (strstr(buf, "lun_") != buf) { + printk(KERN_ERR "Unable to locate \"lun_\" from buf: %s" + " name: %s\n", buf, name); + ret = -EINVAL; + goto out; + } + /* + * Determine the Mapped LUN value. This is what the SCSI Initiator + * Port will actually see. + */ + if (strict_strtoul(buf + 4, 0, &mapped_lun) || mapped_lun > UINT_MAX) { + ret = -EINVAL; + goto out; + } + + lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, + config_item_name(acl_ci), &ret); + if (!(lacl)) + goto out; + + config_group_init_type_name(&lacl->se_lun_group, name, + &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); + + kfree(buf); + return &lacl->se_lun_group; +out: + kfree(buf); + return ERR_PTR(ret); +} + +static void target_fabric_drop_mappedlun( + struct config_group *group, + struct config_item *item) +{ + struct se_lun_acl *lacl = container_of(to_config_group(item), + struct se_lun_acl, se_lun_group); + struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg; + + config_item_put(item); + core_dev_free_initiator_node_lun_acl(se_tpg, lacl); +} + +static struct configfs_item_operations target_fabric_nacl_base_item_ops = { + .show_attribute = target_fabric_nacl_base_attr_show, + .store_attribute = target_fabric_nacl_base_attr_store, +}; + +static struct configfs_group_operations target_fabric_nacl_base_group_ops = { + .make_group = target_fabric_make_mappedlun, + .drop_item = target_fabric_drop_mappedlun, +}; + +TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, + &target_fabric_nacl_base_group_ops, NULL); + +/* End of tfc_tpg_nacl_base_cit */ + +/* Start of tfc_tpg_nacl_cit */ + +static struct config_group *target_fabric_make_nodeacl( + struct config_group *group, + const char *name) +{ + struct se_portal_group *se_tpg = container_of(group, + struct se_portal_group, tpg_acl_group); + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct se_node_acl *se_nacl; + struct config_group *nacl_cg; + + if (!(tf->tf_ops.fabric_make_nodeacl)) { + printk(KERN_ERR "tf->tf_ops.fabric_make_nodeacl is NULL\n"); + return ERR_PTR(-ENOSYS); + } + + se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name); + if (IS_ERR(se_nacl)) + return ERR_PTR(PTR_ERR(se_nacl)); + + nacl_cg = &se_nacl->acl_group; + nacl_cg->default_groups = se_nacl->acl_default_groups; + nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; + nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; + nacl_cg->default_groups[2] = &se_nacl->acl_param_group; + nacl_cg->default_groups[3] = NULL; + + config_group_init_type_name(&se_nacl->acl_group, name, + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); + config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib", + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_attrib_cit); + config_group_init_type_name(&se_nacl->acl_auth_group, "auth", + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); + config_group_init_type_name(&se_nacl->acl_param_group, "param", + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); + + return &se_nacl->acl_group; +} + +static void target_fabric_drop_nodeacl( + struct config_group *group, + struct config_item *item) +{ + struct se_portal_group *se_tpg = container_of(group, + struct se_portal_group, tpg_acl_group); + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct se_node_acl *se_nacl = container_of(to_config_group(item), + struct se_node_acl, acl_group); + struct config_item *df_item; + struct config_group *nacl_cg; + int i; + + nacl_cg = &se_nacl->acl_group; + for (i = 0; nacl_cg->default_groups[i]; i++) { + df_item = &nacl_cg->default_groups[i]->cg_item; + nacl_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + + config_item_put(item); + tf->tf_ops.fabric_drop_nodeacl(se_nacl); +} + +static struct configfs_group_operations target_fabric_nacl_group_ops = { + .make_group = target_fabric_make_nodeacl, + .drop_item = target_fabric_drop_nodeacl, +}; + +TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL); + +/* End of tfc_tpg_nacl_cit */ + +/* Start of tfc_tpg_np_base_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group); + +static struct configfs_item_operations target_fabric_np_base_item_ops = { + .show_attribute = target_fabric_np_base_attr_show, + .store_attribute = target_fabric_np_base_attr_store, +}; + +TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL); + +/* End of tfc_tpg_np_base_cit */ + +/* Start of tfc_tpg_np_cit */ + +static struct config_group *target_fabric_make_np( + struct config_group *group, + const char *name) +{ + struct se_portal_group *se_tpg = container_of(group, + struct se_portal_group, tpg_np_group); + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct se_tpg_np *se_tpg_np; + + if (!(tf->tf_ops.fabric_make_np)) { + printk(KERN_ERR "tf->tf_ops.fabric_make_np is NULL\n"); + return ERR_PTR(-ENOSYS); + } + + se_tpg_np = tf->tf_ops.fabric_make_np(se_tpg, group, name); + if (!(se_tpg_np) || IS_ERR(se_tpg_np)) + return ERR_PTR(-EINVAL); + + config_group_init_type_name(&se_tpg_np->tpg_np_group, name, + &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit); + + return &se_tpg_np->tpg_np_group; +} + +static void target_fabric_drop_np( + struct config_group *group, + struct config_item *item) +{ + struct se_portal_group *se_tpg = container_of(group, + struct se_portal_group, tpg_np_group); + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), + struct se_tpg_np, tpg_np_group); + + config_item_put(item); + tf->tf_ops.fabric_drop_np(se_tpg_np); +} + +static struct configfs_group_operations target_fabric_np_group_ops = { + .make_group = &target_fabric_make_np, + .drop_item = &target_fabric_drop_np, +}; + +TF_CIT_SETUP(tpg_np, NULL, &target_fabric_np_group_ops, NULL); + +/* End of tfc_tpg_np_cit */ + +/* Start of tfc_tpg_port_cit */ + +CONFIGFS_EATTR_STRUCT(target_fabric_port, se_lun); +#define TCM_PORT_ATTR(_name, _mode) \ +static struct target_fabric_port_attribute target_fabric_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_fabric_port_show_attr_##_name, \ + target_fabric_port_store_attr_##_name); + +#define TCM_PORT_ATTOR_RO(_name) \ + __CONFIGFS_EATTR_RO(_name, \ + target_fabric_port_show_attr_##_name); + +/* + * alua_tg_pt_gp + */ +static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp( + struct se_lun *lun, + char *page) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_show_tg_pt_gp_info(lun->lun_sep, page); +} + +static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp( + struct se_lun *lun, + const char *page, + size_t count) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_store_tg_pt_gp_info(lun->lun_sep, page, count); +} + +TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR); + +/* + * alua_tg_pt_offline + */ +static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline( + struct se_lun *lun, + char *page) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_show_offline_bit(lun, page); +} + +static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline( + struct se_lun *lun, + const char *page, + size_t count) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_store_offline_bit(lun, page, count); +} + +TCM_PORT_ATTR(alua_tg_pt_offline, S_IRUGO | S_IWUSR); + +/* + * alua_tg_pt_status + */ +static ssize_t target_fabric_port_show_attr_alua_tg_pt_status( + struct se_lun *lun, + char *page) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_show_secondary_status(lun, page); +} + +static ssize_t target_fabric_port_store_attr_alua_tg_pt_status( + struct se_lun *lun, + const char *page, + size_t count) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_store_secondary_status(lun, page, count); +} + +TCM_PORT_ATTR(alua_tg_pt_status, S_IRUGO | S_IWUSR); + +/* + * alua_tg_pt_write_md + */ +static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md( + struct se_lun *lun, + char *page) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_show_secondary_write_metadata(lun, page); +} + +static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md( + struct se_lun *lun, + const char *page, + size_t count) +{ + if (!(lun)) + return -ENODEV; + + if (!(lun->lun_sep)) + return -ENODEV; + + return core_alua_store_secondary_write_metadata(lun, page, count); +} + +TCM_PORT_ATTR(alua_tg_pt_write_md, S_IRUGO | S_IWUSR); + + +static struct configfs_attribute *target_fabric_port_attrs[] = { + &target_fabric_port_alua_tg_pt_gp.attr, + &target_fabric_port_alua_tg_pt_offline.attr, + &target_fabric_port_alua_tg_pt_status.attr, + &target_fabric_port_alua_tg_pt_write_md.attr, + NULL, +}; + +CONFIGFS_EATTR_OPS(target_fabric_port, se_lun, lun_group); + +static int target_fabric_port_link( + struct config_item *lun_ci, + struct config_item *se_dev_ci) +{ + struct config_item *tpg_ci; + struct se_device *dev; + struct se_lun *lun = container_of(to_config_group(lun_ci), + struct se_lun, lun_group); + struct se_lun *lun_p; + struct se_portal_group *se_tpg; + struct se_subsystem_dev *se_dev = container_of( + to_config_group(se_dev_ci), struct se_subsystem_dev, + se_dev_group); + struct target_fabric_configfs *tf; + int ret; + + tpg_ci = &lun_ci->ci_parent->ci_group->cg_item; + se_tpg = container_of(to_config_group(tpg_ci), + struct se_portal_group, tpg_group); + tf = se_tpg->se_tpg_wwn->wwn_tf; + + if (lun->lun_se_dev != NULL) { + printk(KERN_ERR "Port Symlink already exists\n"); + return -EEXIST; + } + + dev = se_dev->se_dev_ptr; + if (!(dev)) { + printk(KERN_ERR "Unable to locate struct se_device pointer from" + " %s\n", config_item_name(se_dev_ci)); + ret = -ENODEV; + goto out; + } + + lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev, + lun->unpacked_lun); + if ((IS_ERR(lun_p)) || !(lun_p)) { + printk(KERN_ERR "core_dev_add_lun() failed\n"); + ret = -EINVAL; + goto out; + } + + if (tf->tf_ops.fabric_post_link) { + /* + * Call the optional fabric_post_link() to allow a + * fabric module to setup any additional state once + * core_dev_add_lun() has been called.. + */ + tf->tf_ops.fabric_post_link(se_tpg, lun); + } + + return 0; +out: + return ret; +} + +static int target_fabric_port_unlink( + struct config_item *lun_ci, + struct config_item *se_dev_ci) +{ + struct se_lun *lun = container_of(to_config_group(lun_ci), + struct se_lun, lun_group); + struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + + if (tf->tf_ops.fabric_pre_unlink) { + /* + * Call the optional fabric_pre_unlink() to allow a + * fabric module to release any additional stat before + * core_dev_del_lun() is called. + */ + tf->tf_ops.fabric_pre_unlink(se_tpg, lun); + } + + core_dev_del_lun(se_tpg, lun->unpacked_lun); + return 0; +} + +static struct configfs_item_operations target_fabric_port_item_ops = { + .show_attribute = target_fabric_port_attr_show, + .store_attribute = target_fabric_port_attr_store, + .allow_link = target_fabric_port_link, + .drop_link = target_fabric_port_unlink, +}; + +TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_attrs); + +/* End of tfc_tpg_port_cit */ + +/* Start of tfc_tpg_lun_cit */ + +static struct config_group *target_fabric_make_lun( + struct config_group *group, + const char *name) +{ + struct se_lun *lun; + struct se_portal_group *se_tpg = container_of(group, + struct se_portal_group, tpg_lun_group); + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + unsigned long unpacked_lun; + + if (strstr(name, "lun_") != name) { + printk(KERN_ERR "Unable to locate \'_\" in" + " \"lun_$LUN_NUMBER\"\n"); + return ERR_PTR(-EINVAL); + } + if (strict_strtoul(name + 4, 0, &unpacked_lun) || unpacked_lun > UINT_MAX) + return ERR_PTR(-EINVAL); + + lun = core_get_lun_from_tpg(se_tpg, unpacked_lun); + if (!(lun)) + return ERR_PTR(-EINVAL); + + config_group_init_type_name(&lun->lun_group, name, + &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); + + return &lun->lun_group; +} + +static void target_fabric_drop_lun( + struct config_group *group, + struct config_item *item) +{ + config_item_put(item); +} + +static struct configfs_group_operations target_fabric_lun_group_ops = { + .make_group = &target_fabric_make_lun, + .drop_item = &target_fabric_drop_lun, +}; + +TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL); + +/* End of tfc_tpg_lun_cit */ + +/* Start of tfc_tpg_attrib_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_tpg_attrib, se_portal_group, tpg_attrib_group); + +static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = { + .show_attribute = target_fabric_tpg_attrib_attr_show, + .store_attribute = target_fabric_tpg_attrib_attr_store, +}; + +TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL); + +/* End of tfc_tpg_attrib_cit */ + +/* Start of tfc_tpg_param_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group); + +static struct configfs_item_operations target_fabric_tpg_param_item_ops = { + .show_attribute = target_fabric_tpg_param_attr_show, + .store_attribute = target_fabric_tpg_param_attr_store, +}; + +TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL); + +/* End of tfc_tpg_param_cit */ + +/* Start of tfc_tpg_base_cit */ +/* + * For use with TF_TPG_ATTR() and TF_TPG_ATTR_RO() + */ +CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group); + +static struct configfs_item_operations target_fabric_tpg_base_item_ops = { + .show_attribute = target_fabric_tpg_attr_show, + .store_attribute = target_fabric_tpg_attr_store, +}; + +TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL); + +/* End of tfc_tpg_base_cit */ + +/* Start of tfc_tpg_cit */ + +static struct config_group *target_fabric_make_tpg( + struct config_group *group, + const char *name) +{ + struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group); + struct target_fabric_configfs *tf = wwn->wwn_tf; + struct se_portal_group *se_tpg; + + if (!(tf->tf_ops.fabric_make_tpg)) { + printk(KERN_ERR "tf->tf_ops.fabric_make_tpg is NULL\n"); + return ERR_PTR(-ENOSYS); + } + + se_tpg = tf->tf_ops.fabric_make_tpg(wwn, group, name); + if (!(se_tpg) || IS_ERR(se_tpg)) + return ERR_PTR(-EINVAL); + /* + * Setup default groups from pre-allocated se_tpg->tpg_default_groups + */ + se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups; + se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group; + se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group; + se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group; + se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group; + se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_param_group; + se_tpg->tpg_group.default_groups[5] = NULL; + + config_group_init_type_name(&se_tpg->tpg_group, name, + &TF_CIT_TMPL(tf)->tfc_tpg_base_cit); + config_group_init_type_name(&se_tpg->tpg_lun_group, "lun", + &TF_CIT_TMPL(tf)->tfc_tpg_lun_cit); + config_group_init_type_name(&se_tpg->tpg_np_group, "np", + &TF_CIT_TMPL(tf)->tfc_tpg_np_cit); + config_group_init_type_name(&se_tpg->tpg_acl_group, "acls", + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_cit); + config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib", + &TF_CIT_TMPL(tf)->tfc_tpg_attrib_cit); + config_group_init_type_name(&se_tpg->tpg_param_group, "param", + &TF_CIT_TMPL(tf)->tfc_tpg_param_cit); + + return &se_tpg->tpg_group; +} + +static void target_fabric_drop_tpg( + struct config_group *group, + struct config_item *item) +{ + struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group); + struct target_fabric_configfs *tf = wwn->wwn_tf; + struct se_portal_group *se_tpg = container_of(to_config_group(item), + struct se_portal_group, tpg_group); + struct config_group *tpg_cg = &se_tpg->tpg_group; + struct config_item *df_item; + int i; + /* + * Release default groups, but do not release tpg_cg->default_groups + * memory as it is statically allocated at se_tpg->tpg_default_groups. + */ + for (i = 0; tpg_cg->default_groups[i]; i++) { + df_item = &tpg_cg->default_groups[i]->cg_item; + tpg_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + + config_item_put(item); + tf->tf_ops.fabric_drop_tpg(se_tpg); +} + +static struct configfs_group_operations target_fabric_tpg_group_ops = { + .make_group = target_fabric_make_tpg, + .drop_item = target_fabric_drop_tpg, +}; + +TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL); + +/* End of tfc_tpg_cit */ + +/* Start of tfc_wwn_cit */ + +static struct config_group *target_fabric_make_wwn( + struct config_group *group, + const char *name) +{ + struct target_fabric_configfs *tf = container_of(group, + struct target_fabric_configfs, tf_group); + struct se_wwn *wwn; + + if (!(tf->tf_ops.fabric_make_wwn)) { + printk(KERN_ERR "tf->tf_ops.fabric_make_wwn is NULL\n"); + return ERR_PTR(-ENOSYS); + } + + wwn = tf->tf_ops.fabric_make_wwn(tf, group, name); + if (!(wwn) || IS_ERR(wwn)) + return ERR_PTR(-EINVAL); + + wwn->wwn_tf = tf; + config_group_init_type_name(&wwn->wwn_group, name, + &TF_CIT_TMPL(tf)->tfc_tpg_cit); + + return &wwn->wwn_group; +} + +static void target_fabric_drop_wwn( + struct config_group *group, + struct config_item *item) +{ + struct target_fabric_configfs *tf = container_of(group, + struct target_fabric_configfs, tf_group); + struct se_wwn *wwn = container_of(to_config_group(item), + struct se_wwn, wwn_group); + + config_item_put(item); + tf->tf_ops.fabric_drop_wwn(wwn); +} + +static struct configfs_group_operations target_fabric_wwn_group_ops = { + .make_group = target_fabric_make_wwn, + .drop_item = target_fabric_drop_wwn, +}; +/* + * For use with TF_WWN_ATTR() and TF_WWN_ATTR_RO() + */ +CONFIGFS_EATTR_OPS(target_fabric_wwn, target_fabric_configfs, tf_group); + +static struct configfs_item_operations target_fabric_wwn_item_ops = { + .show_attribute = target_fabric_wwn_attr_show, + .store_attribute = target_fabric_wwn_attr_store, +}; + +TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL); + +/* End of tfc_wwn_cit */ + +/* Start of tfc_discovery_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_discovery, target_fabric_configfs, + tf_disc_group); + +static struct configfs_item_operations target_fabric_discovery_item_ops = { + .show_attribute = target_fabric_discovery_attr_show, + .store_attribute = target_fabric_discovery_attr_store, +}; + +TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL); + +/* End of tfc_discovery_cit */ + +int target_fabric_setup_cits(struct target_fabric_configfs *tf) +{ + target_fabric_setup_discovery_cit(tf); + target_fabric_setup_wwn_cit(tf); + target_fabric_setup_tpg_cit(tf); + target_fabric_setup_tpg_base_cit(tf); + target_fabric_setup_tpg_port_cit(tf); + target_fabric_setup_tpg_lun_cit(tf); + target_fabric_setup_tpg_np_cit(tf); + target_fabric_setup_tpg_np_base_cit(tf); + target_fabric_setup_tpg_attrib_cit(tf); + target_fabric_setup_tpg_param_cit(tf); + target_fabric_setup_tpg_nacl_cit(tf); + target_fabric_setup_tpg_nacl_base_cit(tf); + target_fabric_setup_tpg_nacl_attrib_cit(tf); + target_fabric_setup_tpg_nacl_auth_cit(tf); + target_fabric_setup_tpg_nacl_param_cit(tf); + target_fabric_setup_tpg_mappedlun_cit(tf); + + return 0; +} diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c new file mode 100644 index 000000000000..26285644e4de --- /dev/null +++ b/drivers/target/target_core_fabric_lib.c @@ -0,0 +1,451 @@ +/******************************************************************************* + * Filename: target_core_fabric_lib.c + * + * This file contains generic high level protocol identifier and PR + * handlers for TCM fabric modules + * + * Copyright (c) 2010 Rising Tide Systems, Inc. + * Copyright (c) 2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 + +#include "target_core_hba.h" +#include "target_core_pr.h" + +/* + * Handlers for Serial Attached SCSI (SAS) + */ +u8 sas_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + /* + * Return a SAS Serial SCSI Protocol identifier for loopback operations + * This is defined in section 7.5.1 Table 362 in spc4r17 + */ + return 0x6; +} +EXPORT_SYMBOL(sas_get_fabric_proto_ident); + +u32 sas_get_pr_transport_id( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, + unsigned char *buf) +{ + unsigned char binary, *ptr; + int i; + u32 off = 4; + /* + * Set PROTOCOL IDENTIFIER to 6h for SAS + */ + buf[0] = 0x06; + /* + * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI + * over SAS Serial SCSI Protocol + */ + ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */ + + for (i = 0; i < 16; i += 2) { + binary = transport_asciihex_to_binaryhex(&ptr[i]); + buf[off++] = binary; + } + /* + * The SAS Transport ID is a hardcoded 24-byte length + */ + return 24; +} +EXPORT_SYMBOL(sas_get_pr_transport_id); + +u32 sas_get_pr_transport_id_len( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + *format_code = 0; + /* + * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI + * over SAS Serial SCSI Protocol + * + * The SAS Transport ID is a hardcoded 24-byte length + */ + return 24; +} +EXPORT_SYMBOL(sas_get_pr_transport_id_len); + +/* + * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above + * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. + */ +char *sas_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + const char *buf, + u32 *out_tid_len, + char **port_nexus_ptr) +{ + /* + * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID + * for initiator ports using SCSI over SAS Serial SCSI Protocol + * + * The TransportID for a SAS Initiator Port is of fixed size of + * 24 bytes, and SAS does not contain a I_T nexus identifier, + * so we return the **port_nexus_ptr set to NULL. + */ + *port_nexus_ptr = NULL; + *out_tid_len = 24; + + return (char *)&buf[4]; +} +EXPORT_SYMBOL(sas_parse_pr_out_transport_id); + +/* + * Handlers for Fibre Channel Protocol (FCP) + */ +u8 fc_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + return 0x0; /* 0 = fcp-2 per SPC4 section 7.5.1 */ +} +EXPORT_SYMBOL(fc_get_fabric_proto_ident); + +u32 fc_get_pr_transport_id_len( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + *format_code = 0; + /* + * The FC Transport ID is a hardcoded 24-byte length + */ + return 24; +} +EXPORT_SYMBOL(fc_get_pr_transport_id_len); + +u32 fc_get_pr_transport_id( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, + unsigned char *buf) +{ + unsigned char binary, *ptr; + int i; + u32 off = 8; + /* + * PROTOCOL IDENTIFIER is 0h for FCP-2 + * + * From spc4r17, 7.5.4.2 TransportID for initiator ports using + * SCSI over Fibre Channel + * + * We convert the ASCII formatted N Port name into a binary + * encoded TransportID. + */ + ptr = &se_nacl->initiatorname[0]; + + for (i = 0; i < 24; ) { + if (!(strncmp(&ptr[i], ":", 1))) { + i++; + continue; + } + binary = transport_asciihex_to_binaryhex(&ptr[i]); + buf[off++] = binary; + i += 2; + } + /* + * The FC Transport ID is a hardcoded 24-byte length + */ + return 24; +} +EXPORT_SYMBOL(fc_get_pr_transport_id); + +char *fc_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + const char *buf, + u32 *out_tid_len, + char **port_nexus_ptr) +{ + /* + * The TransportID for a FC N Port is of fixed size of + * 24 bytes, and FC does not contain a I_T nexus identifier, + * so we return the **port_nexus_ptr set to NULL. + */ + *port_nexus_ptr = NULL; + *out_tid_len = 24; + + return (char *)&buf[8]; +} +EXPORT_SYMBOL(fc_parse_pr_out_transport_id); + +/* + * Handlers for Internet Small Computer Systems Interface (iSCSI) + */ + +u8 iscsi_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + /* + * This value is defined for "Internet SCSI (iSCSI)" + * in spc4r17 section 7.5.1 Table 362 + */ + return 0x5; +} +EXPORT_SYMBOL(iscsi_get_fabric_proto_ident); + +u32 iscsi_get_pr_transport_id( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, + unsigned char *buf) +{ + u32 off = 4, padding = 0; + u16 len = 0; + + spin_lock_irq(&se_nacl->nacl_sess_lock); + /* + * Set PROTOCOL IDENTIFIER to 5h for iSCSI + */ + buf[0] = 0x05; + /* + * From spc4r17 Section 7.5.4.6: TransportID for initiator + * ports using SCSI over iSCSI. + * + * The null-terminated, null-padded (see 4.4.2) ISCSI NAME field + * shall contain the iSCSI name of an iSCSI initiator node (see + * RFC 3720). The first ISCSI NAME field byte containing an ASCII + * null character terminates the ISCSI NAME field without regard for + * the specified length of the iSCSI TransportID or the contents of + * the ADDITIONAL LENGTH field. + */ + len = sprintf(&buf[off], "%s", se_nacl->initiatorname); + /* + * Add Extra byte for NULL terminator + */ + len++; + /* + * If there is ISID present with the registration and *format code == 1 + * 1, use iSCSI Initiator port TransportID format. + * + * Otherwise use iSCSI Initiator device TransportID format that + * does not contain the ASCII encoded iSCSI Initiator iSID value + * provied by the iSCSi Initiator during the iSCSI login process. + */ + if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) { + /* + * Set FORMAT CODE 01b for iSCSI Initiator port TransportID + * format. + */ + buf[0] |= 0x40; + /* + * From spc4r17 Section 7.5.4.6: TransportID for initiator + * ports using SCSI over iSCSI. Table 390 + * + * The SEPARATOR field shall contain the five ASCII + * characters ",i,0x". + * + * The null-terminated, null-padded ISCSI INITIATOR SESSION ID + * field shall contain the iSCSI initiator session identifier + * (see RFC 3720) in the form of ASCII characters that are the + * hexadecimal digits converted from the binary iSCSI initiator + * session identifier value. The first ISCSI INITIATOR SESSION + * ID field byte containing an ASCII null character + */ + buf[off+len] = 0x2c; off++; /* ASCII Character: "," */ + buf[off+len] = 0x69; off++; /* ASCII Character: "i" */ + buf[off+len] = 0x2c; off++; /* ASCII Character: "," */ + buf[off+len] = 0x30; off++; /* ASCII Character: "0" */ + buf[off+len] = 0x78; off++; /* ASCII Character: "x" */ + len += 5; + buf[off+len] = pr_reg->pr_reg_isid[0]; off++; + buf[off+len] = pr_reg->pr_reg_isid[1]; off++; + buf[off+len] = pr_reg->pr_reg_isid[2]; off++; + buf[off+len] = pr_reg->pr_reg_isid[3]; off++; + buf[off+len] = pr_reg->pr_reg_isid[4]; off++; + buf[off+len] = pr_reg->pr_reg_isid[5]; off++; + buf[off+len] = '\0'; off++; + len += 7; + } + spin_unlock_irq(&se_nacl->nacl_sess_lock); + /* + * The ADDITIONAL LENGTH field specifies the number of bytes that follow + * in the TransportID. The additional length shall be at least 20 and + * shall be a multiple of four. + */ + padding = ((-len) & 3); + if (padding != 0) + len += padding; + + buf[2] = ((len >> 8) & 0xff); + buf[3] = (len & 0xff); + /* + * Increment value for total payload + header length for + * full status descriptor + */ + len += 4; + + return len; +} +EXPORT_SYMBOL(iscsi_get_pr_transport_id); + +u32 iscsi_get_pr_transport_id_len( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + u32 len = 0, padding = 0; + + spin_lock_irq(&se_nacl->nacl_sess_lock); + len = strlen(se_nacl->initiatorname); + /* + * Add extra byte for NULL terminator + */ + len++; + /* + * If there is ISID present with the registration, use format code: + * 01b: iSCSI Initiator port TransportID format + * + * If there is not an active iSCSI session, use format code: + * 00b: iSCSI Initiator device TransportID format + */ + if (pr_reg->isid_present_at_reg) { + len += 5; /* For ",i,0x" ASCII seperator */ + len += 7; /* For iSCSI Initiator Session ID + Null terminator */ + *format_code = 1; + } else + *format_code = 0; + spin_unlock_irq(&se_nacl->nacl_sess_lock); + /* + * The ADDITIONAL LENGTH field specifies the number of bytes that follow + * in the TransportID. The additional length shall be at least 20 and + * shall be a multiple of four. + */ + padding = ((-len) & 3); + if (padding != 0) + len += padding; + /* + * Increment value for total payload + header length for + * full status descriptor + */ + len += 4; + + return len; +} +EXPORT_SYMBOL(iscsi_get_pr_transport_id_len); + +char *iscsi_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + const char *buf, + u32 *out_tid_len, + char **port_nexus_ptr) +{ + char *p; + u32 tid_len, padding; + int i; + u16 add_len; + u8 format_code = (buf[0] & 0xc0); + /* + * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6: + * + * TransportID for initiator ports using SCSI over iSCSI, + * from Table 388 -- iSCSI TransportID formats. + * + * 00b Initiator port is identified using the world wide unique + * SCSI device name of the iSCSI initiator + * device containing the initiator port (see table 389). + * 01b Initiator port is identified using the world wide unique + * initiator port identifier (see table 390).10b to 11b + * Reserved + */ + if ((format_code != 0x00) && (format_code != 0x40)) { + printk(KERN_ERR "Illegal format code: 0x%02x for iSCSI" + " Initiator Transport ID\n", format_code); + return NULL; + } + /* + * If the caller wants the TransportID Length, we set that value for the + * entire iSCSI Tarnsport ID now. + */ + if (out_tid_len != NULL) { + add_len = ((buf[2] >> 8) & 0xff); + add_len |= (buf[3] & 0xff); + + tid_len = strlen((char *)&buf[4]); + tid_len += 4; /* Add four bytes for iSCSI Transport ID header */ + tid_len += 1; /* Add one byte for NULL terminator */ + padding = ((-tid_len) & 3); + if (padding != 0) + tid_len += padding; + + if ((add_len + 4) != tid_len) { + printk(KERN_INFO "LIO-Target Extracted add_len: %hu " + "does not match calculated tid_len: %u," + " using tid_len instead\n", add_len+4, tid_len); + *out_tid_len = tid_len; + } else + *out_tid_len = (add_len + 4); + } + /* + * Check for ',i,0x' seperator between iSCSI Name and iSCSI Initiator + * Session ID as defined in Table 390 - iSCSI initiator port TransportID + * format. + */ + if (format_code == 0x40) { + p = strstr((char *)&buf[4], ",i,0x"); + if (!(p)) { + printk(KERN_ERR "Unable to locate \",i,0x\" seperator" + " for Initiator port identifier: %s\n", + (char *)&buf[4]); + return NULL; + } + *p = '\0'; /* Terminate iSCSI Name */ + p += 5; /* Skip over ",i,0x" seperator */ + + *port_nexus_ptr = p; + /* + * Go ahead and do the lower case conversion of the received + * 12 ASCII characters representing the ISID in the TransportID + * for comparision against the running iSCSI session's ISID from + * iscsi_target.c:lio_sess_get_initiator_sid() + */ + for (i = 0; i < 12; i++) { + if (isdigit(*p)) { + p++; + continue; + } + *p = tolower(*p); + p++; + } + } + + return (char *)&buf[4]; +} +EXPORT_SYMBOL(iscsi_parse_pr_out_transport_id); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c new file mode 100644 index 000000000000..0aaca885668f --- /dev/null +++ b/drivers/target/target_core_file.c @@ -0,0 +1,688 @@ +/******************************************************************************* + * Filename: target_core_file.c + * + * This file contains the Storage Engine <-> FILEIO transport specific functions + * + * Copyright (c) 2005 PyX Technologies, Inc. + * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include + +#include "target_core_file.h" + +#if 1 +#define DEBUG_FD_CACHE(x...) printk(x) +#else +#define DEBUG_FD_CACHE(x...) +#endif + +#if 1 +#define DEBUG_FD_FUA(x...) printk(x) +#else +#define DEBUG_FD_FUA(x...) +#endif + +static struct se_subsystem_api fileio_template; + +/* fd_attach_hba(): (Part of se_subsystem_api_t template) + * + * + */ +static int fd_attach_hba(struct se_hba *hba, u32 host_id) +{ + struct fd_host *fd_host; + + fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL); + if (!(fd_host)) { + printk(KERN_ERR "Unable to allocate memory for struct fd_host\n"); + return -1; + } + + fd_host->fd_host_id = host_id; + + atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH); + atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH); + hba->hba_ptr = (void *) fd_host; + + printk(KERN_INFO "CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic" + " Target Core Stack %s\n", hba->hba_id, FD_VERSION, + TARGET_CORE_MOD_VERSION); + printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic" + " Target Core with TCQ Depth: %d MaxSectors: %u\n", + hba->hba_id, fd_host->fd_host_id, + atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS); + + return 0; +} + +static void fd_detach_hba(struct se_hba *hba) +{ + struct fd_host *fd_host = hba->hba_ptr; + + printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic" + " Target Core\n", hba->hba_id, fd_host->fd_host_id); + + kfree(fd_host); + hba->hba_ptr = NULL; +} + +static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name) +{ + struct fd_dev *fd_dev; + struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr; + + fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL); + if (!(fd_dev)) { + printk(KERN_ERR "Unable to allocate memory for struct fd_dev\n"); + return NULL; + } + + fd_dev->fd_host = fd_host; + + printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name); + + return fd_dev; +} + +/* fd_create_virtdevice(): (Part of se_subsystem_api_t template) + * + * + */ +static struct se_device *fd_create_virtdevice( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + void *p) +{ + char *dev_p = NULL; + struct se_device *dev; + struct se_dev_limits dev_limits; + struct queue_limits *limits; + struct fd_dev *fd_dev = (struct fd_dev *) p; + struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr; + mm_segment_t old_fs; + struct file *file; + struct inode *inode = NULL; + int dev_flags = 0, flags; + + memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + + old_fs = get_fs(); + set_fs(get_ds()); + dev_p = getname(fd_dev->fd_dev_name); + set_fs(old_fs); + + if (IS_ERR(dev_p)) { + printk(KERN_ERR "getname(%s) failed: %lu\n", + fd_dev->fd_dev_name, IS_ERR(dev_p)); + goto fail; + } +#if 0 + if (di->no_create_file) + flags = O_RDWR | O_LARGEFILE; + else + flags = O_RDWR | O_CREAT | O_LARGEFILE; +#else + flags = O_RDWR | O_CREAT | O_LARGEFILE; +#endif +/* flags |= O_DIRECT; */ + /* + * If fd_buffered_io=1 has not been set explictly (the default), + * use O_SYNC to force FILEIO writes to disk. + */ + if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO)) + flags |= O_SYNC; + + file = filp_open(dev_p, flags, 0600); + + if (IS_ERR(file) || !file || !file->f_dentry) { + printk(KERN_ERR "filp_open(%s) failed\n", dev_p); + goto fail; + } + fd_dev->fd_file = file; + /* + * If using a block backend with this struct file, we extract + * fd_dev->fd_[block,dev]_size from struct block_device. + * + * Otherwise, we use the passed fd_size= from configfs + */ + inode = file->f_mapping->host; + if (S_ISBLK(inode->i_mode)) { + struct request_queue *q; + /* + * Setup the local scope queue_limits from struct request_queue->limits + * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. + */ + q = bdev_get_queue(inode->i_bdev); + limits = &dev_limits.limits; + limits->logical_block_size = bdev_logical_block_size(inode->i_bdev); + limits->max_hw_sectors = queue_max_hw_sectors(q); + limits->max_sectors = queue_max_sectors(q); + /* + * Determine the number of bytes from i_size_read() minus + * one (1) logical sector from underlying struct block_device + */ + fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev); + fd_dev->fd_dev_size = (i_size_read(file->f_mapping->host) - + fd_dev->fd_block_size); + + printk(KERN_INFO "FILEIO: Using size: %llu bytes from struct" + " block_device blocks: %llu logical_block_size: %d\n", + fd_dev->fd_dev_size, + div_u64(fd_dev->fd_dev_size, fd_dev->fd_block_size), + fd_dev->fd_block_size); + } else { + if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) { + printk(KERN_ERR "FILEIO: Missing fd_dev_size=" + " parameter, and no backing struct" + " block_device\n"); + goto fail; + } + + limits = &dev_limits.limits; + limits->logical_block_size = FD_BLOCKSIZE; + limits->max_hw_sectors = FD_MAX_SECTORS; + limits->max_sectors = FD_MAX_SECTORS; + fd_dev->fd_block_size = FD_BLOCKSIZE; + } + + dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; + dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH; + + dev = transport_add_device_to_core_hba(hba, &fileio_template, + se_dev, dev_flags, (void *)fd_dev, + &dev_limits, "FILEIO", FD_VERSION); + if (!(dev)) + goto fail; + + fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; + fd_dev->fd_queue_depth = dev->queue_depth; + + printk(KERN_INFO "CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," + " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, + fd_dev->fd_dev_name, fd_dev->fd_dev_size); + + putname(dev_p); + return dev; +fail: + if (fd_dev->fd_file) { + filp_close(fd_dev->fd_file, NULL); + fd_dev->fd_file = NULL; + } + putname(dev_p); + return NULL; +} + +/* fd_free_device(): (Part of se_subsystem_api_t template) + * + * + */ +static void fd_free_device(void *p) +{ + struct fd_dev *fd_dev = (struct fd_dev *) p; + + if (fd_dev->fd_file) { + filp_close(fd_dev->fd_file, NULL); + fd_dev->fd_file = NULL; + } + + kfree(fd_dev); +} + +static inline struct fd_request *FILE_REQ(struct se_task *task) +{ + return container_of(task, struct fd_request, fd_task); +} + + +static struct se_task * +fd_alloc_task(struct se_cmd *cmd) +{ + struct fd_request *fd_req; + + fd_req = kzalloc(sizeof(struct fd_request), GFP_KERNEL); + if (!(fd_req)) { + printk(KERN_ERR "Unable to allocate struct fd_request\n"); + return NULL; + } + + fd_req->fd_dev = SE_DEV(cmd)->dev_ptr; + + return &fd_req->fd_task; +} + +static int fd_do_readv(struct se_task *task) +{ + struct fd_request *req = FILE_REQ(task); + struct file *fd = req->fd_dev->fd_file; + struct scatterlist *sg = task->task_sg; + struct iovec *iov; + mm_segment_t old_fs; + loff_t pos = (task->task_lba * DEV_ATTRIB(task->se_dev)->block_size); + int ret = 0, i; + + iov = kzalloc(sizeof(struct iovec) * task->task_sg_num, GFP_KERNEL); + if (!(iov)) { + printk(KERN_ERR "Unable to allocate fd_do_readv iov[]\n"); + return -1; + } + + for (i = 0; i < task->task_sg_num; i++) { + iov[i].iov_len = sg[i].length; + iov[i].iov_base = sg_virt(&sg[i]); + } + + old_fs = get_fs(); + set_fs(get_ds()); + ret = vfs_readv(fd, &iov[0], task->task_sg_num, &pos); + set_fs(old_fs); + + kfree(iov); + /* + * Return zeros and GOOD status even if the READ did not return + * the expected virt_size for struct file w/o a backing struct + * block_device. + */ + if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) { + if (ret < 0 || ret != task->task_size) { + printk(KERN_ERR "vfs_readv() returned %d," + " expecting %d for S_ISBLK\n", ret, + (int)task->task_size); + return -1; + } + } else { + if (ret < 0) { + printk(KERN_ERR "vfs_readv() returned %d for non" + " S_ISBLK\n", ret); + return -1; + } + } + + return 1; +} + +static int fd_do_writev(struct se_task *task) +{ + struct fd_request *req = FILE_REQ(task); + struct file *fd = req->fd_dev->fd_file; + struct scatterlist *sg = task->task_sg; + struct iovec *iov; + mm_segment_t old_fs; + loff_t pos = (task->task_lba * DEV_ATTRIB(task->se_dev)->block_size); + int ret, i = 0; + + iov = kzalloc(sizeof(struct iovec) * task->task_sg_num, GFP_KERNEL); + if (!(iov)) { + printk(KERN_ERR "Unable to allocate fd_do_writev iov[]\n"); + return -1; + } + + for (i = 0; i < task->task_sg_num; i++) { + iov[i].iov_len = sg[i].length; + iov[i].iov_base = sg_virt(&sg[i]); + } + + old_fs = get_fs(); + set_fs(get_ds()); + ret = vfs_writev(fd, &iov[0], task->task_sg_num, &pos); + set_fs(old_fs); + + kfree(iov); + + if (ret < 0 || ret != task->task_size) { + printk(KERN_ERR "vfs_writev() returned %d\n", ret); + return -1; + } + + return 1; +} + +static void fd_emulate_sync_cache(struct se_task *task) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct se_device *dev = cmd->se_dev; + struct fd_dev *fd_dev = dev->dev_ptr; + int immed = (cmd->t_task->t_task_cdb[1] & 0x2); + loff_t start, end; + int ret; + + /* + * If the Immediate bit is set, queue up the GOOD response + * for this SYNCHRONIZE_CACHE op + */ + if (immed) + transport_complete_sync_cache(cmd, 1); + + /* + * Determine if we will be flushing the entire device. + */ + if (cmd->t_task->t_task_lba == 0 && cmd->data_length == 0) { + start = 0; + end = LLONG_MAX; + } else { + start = cmd->t_task->t_task_lba * DEV_ATTRIB(dev)->block_size; + if (cmd->data_length) + end = start + cmd->data_length; + else + end = LLONG_MAX; + } + + ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1); + if (ret != 0) + printk(KERN_ERR "FILEIO: vfs_fsync_range() failed: %d\n", ret); + + if (!immed) + transport_complete_sync_cache(cmd, ret == 0); +} + +/* + * Tell TCM Core that we are capable of WriteCache emulation for + * an underlying struct se_device. + */ +static int fd_emulated_write_cache(struct se_device *dev) +{ + return 1; +} + +static int fd_emulated_dpo(struct se_device *dev) +{ + return 0; +} +/* + * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs + * for TYPE_DISK. + */ +static int fd_emulated_fua_write(struct se_device *dev) +{ + return 1; +} + +static int fd_emulated_fua_read(struct se_device *dev) +{ + return 0; +} + +/* + * WRITE Force Unit Access (FUA) emulation on a per struct se_task + * LBA range basis.. + */ +static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task) +{ + struct se_device *dev = cmd->se_dev; + struct fd_dev *fd_dev = dev->dev_ptr; + loff_t start = task->task_lba * DEV_ATTRIB(dev)->block_size; + loff_t end = start + task->task_size; + int ret; + + DEBUG_FD_CACHE("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n", + task->task_lba, task->task_size); + + ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1); + if (ret != 0) + printk(KERN_ERR "FILEIO: vfs_fsync_range() failed: %d\n", ret); +} + +static int fd_do_task(struct se_task *task) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct se_device *dev = cmd->se_dev; + int ret = 0; + + /* + * Call vectorized fileio functions to map struct scatterlist + * physical memory addresses to struct iovec virtual memory. + */ + if (task->task_data_direction == DMA_FROM_DEVICE) { + ret = fd_do_readv(task); + } else { + ret = fd_do_writev(task); + + if (ret > 0 && + DEV_ATTRIB(dev)->emulate_write_cache > 0 && + DEV_ATTRIB(dev)->emulate_fua_write > 0 && + T_TASK(cmd)->t_tasks_fua) { + /* + * We might need to be a bit smarter here + * and return some sense data to let the initiator + * know the FUA WRITE cache sync failed..? + */ + fd_emulate_write_fua(cmd, task); + } + + } + + if (ret < 0) + return ret; + if (ret) { + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} + +/* fd_free_task(): (Part of se_subsystem_api_t template) + * + * + */ +static void fd_free_task(struct se_task *task) +{ + struct fd_request *req = FILE_REQ(task); + + kfree(req); +} + +enum { + Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err +}; + +static match_table_t tokens = { + {Opt_fd_dev_name, "fd_dev_name=%s"}, + {Opt_fd_dev_size, "fd_dev_size=%s"}, + {Opt_fd_buffered_io, "fd_buffered_id=%d"}, + {Opt_err, NULL} +}; + +static ssize_t fd_set_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + const char *page, ssize_t count) +{ + struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; + char *orig, *ptr, *arg_p, *opts; + substring_t args[MAX_OPT_ARGS]; + int ret = 0, arg, token; + + opts = kstrdup(page, GFP_KERNEL); + if (!opts) + return -ENOMEM; + + orig = opts; + + while ((ptr = strsep(&opts, ",")) != NULL) { + if (!*ptr) + continue; + + token = match_token(ptr, tokens, args); + switch (token) { + case Opt_fd_dev_name: + snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME, + "%s", match_strdup(&args[0])); + printk(KERN_INFO "FILEIO: Referencing Path: %s\n", + fd_dev->fd_dev_name); + fd_dev->fbd_flags |= FBDF_HAS_PATH; + break; + case Opt_fd_dev_size: + arg_p = match_strdup(&args[0]); + ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); + if (ret < 0) { + printk(KERN_ERR "strict_strtoull() failed for" + " fd_dev_size=\n"); + goto out; + } + printk(KERN_INFO "FILEIO: Referencing Size: %llu" + " bytes\n", fd_dev->fd_dev_size); + fd_dev->fbd_flags |= FBDF_HAS_SIZE; + break; + case Opt_fd_buffered_io: + match_int(args, &arg); + if (arg != 1) { + printk(KERN_ERR "bogus fd_buffered_io=%d value\n", arg); + ret = -EINVAL; + goto out; + } + + printk(KERN_INFO "FILEIO: Using buffered I/O" + " operations for struct fd_dev\n"); + + fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO; + break; + default: + break; + } + } + +out: + kfree(orig); + return (!ret) ? count : ret; +} + +static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) +{ + struct fd_dev *fd_dev = (struct fd_dev *) se_dev->se_dev_su_ptr; + + if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { + printk(KERN_ERR "Missing fd_dev_name=\n"); + return -1; + } + + return 0; +} + +static ssize_t fd_show_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + char *b) +{ + struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; + ssize_t bl = 0; + + bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); + bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n", + fd_dev->fd_dev_name, fd_dev->fd_dev_size, + (fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ? + "Buffered" : "Synchronous"); + return bl; +} + +/* fd_get_cdb(): (Part of se_subsystem_api_t template) + * + * + */ +static unsigned char *fd_get_cdb(struct se_task *task) +{ + struct fd_request *req = FILE_REQ(task); + + return req->fd_scsi_cdb; +} + +/* fd_get_device_rev(): (Part of se_subsystem_api_t template) + * + * + */ +static u32 fd_get_device_rev(struct se_device *dev) +{ + return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ +} + +/* fd_get_device_type(): (Part of se_subsystem_api_t template) + * + * + */ +static u32 fd_get_device_type(struct se_device *dev) +{ + return TYPE_DISK; +} + +static sector_t fd_get_blocks(struct se_device *dev) +{ + struct fd_dev *fd_dev = dev->dev_ptr; + unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size, + DEV_ATTRIB(dev)->block_size); + + return blocks_long; +} + +static struct se_subsystem_api fileio_template = { + .name = "fileio", + .owner = THIS_MODULE, + .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, + .attach_hba = fd_attach_hba, + .detach_hba = fd_detach_hba, + .allocate_virtdevice = fd_allocate_virtdevice, + .create_virtdevice = fd_create_virtdevice, + .free_device = fd_free_device, + .dpo_emulated = fd_emulated_dpo, + .fua_write_emulated = fd_emulated_fua_write, + .fua_read_emulated = fd_emulated_fua_read, + .write_cache_emulated = fd_emulated_write_cache, + .alloc_task = fd_alloc_task, + .do_task = fd_do_task, + .do_sync_cache = fd_emulate_sync_cache, + .free_task = fd_free_task, + .check_configfs_dev_params = fd_check_configfs_dev_params, + .set_configfs_dev_params = fd_set_configfs_dev_params, + .show_configfs_dev_params = fd_show_configfs_dev_params, + .get_cdb = fd_get_cdb, + .get_device_rev = fd_get_device_rev, + .get_device_type = fd_get_device_type, + .get_blocks = fd_get_blocks, +}; + +static int __init fileio_module_init(void) +{ + return transport_subsystem_register(&fileio_template); +} + +static void fileio_module_exit(void) +{ + transport_subsystem_release(&fileio_template); +} + +MODULE_DESCRIPTION("TCM FILEIO subsystem plugin"); +MODULE_AUTHOR("nab@Linux-iSCSI.org"); +MODULE_LICENSE("GPL"); + +module_init(fileio_module_init); +module_exit(fileio_module_exit); diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h new file mode 100644 index 000000000000..ef4de2b4bd46 --- /dev/null +++ b/drivers/target/target_core_file.h @@ -0,0 +1,50 @@ +#ifndef TARGET_CORE_FILE_H +#define TARGET_CORE_FILE_H + +#define FD_VERSION "4.0" + +#define FD_MAX_DEV_NAME 256 +/* Maximum queuedepth for the FILEIO HBA */ +#define FD_HBA_QUEUE_DEPTH 256 +#define FD_DEVICE_QUEUE_DEPTH 32 +#define FD_MAX_DEVICE_QUEUE_DEPTH 128 +#define FD_BLOCKSIZE 512 +#define FD_MAX_SECTORS 1024 + +#define RRF_EMULATE_CDB 0x01 +#define RRF_GOT_LBA 0x02 + +struct fd_request { + struct se_task fd_task; + /* SCSI CDB from iSCSI Command PDU */ + unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE]; + /* FILEIO device */ + struct fd_dev *fd_dev; +} ____cacheline_aligned; + +#define FBDF_HAS_PATH 0x01 +#define FBDF_HAS_SIZE 0x02 +#define FDBD_USE_BUFFERED_IO 0x04 + +struct fd_dev { + u32 fbd_flags; + unsigned char fd_dev_name[FD_MAX_DEV_NAME]; + /* Unique Ramdisk Device ID in Ramdisk HBA */ + u32 fd_dev_id; + /* Number of SG tables in sg_table_array */ + u32 fd_table_count; + u32 fd_queue_depth; + u32 fd_block_size; + unsigned long long fd_dev_size; + struct file *fd_file; + /* FILEIO HBA device is connected to */ + struct fd_host *fd_host; +} ____cacheline_aligned; + +struct fd_host { + u32 fd_host_dev_id_count; + /* Unique FILEIO Host ID */ + u32 fd_host_id; +} ____cacheline_aligned; + +#endif /* TARGET_CORE_FILE_H */ diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c new file mode 100644 index 000000000000..4bbe8208b241 --- /dev/null +++ b/drivers/target/target_core_hba.c @@ -0,0 +1,185 @@ +/******************************************************************************* + * Filename: target_core_hba.c + * + * This file copntains the iSCSI HBA Transport related functions. + * + * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include + +#include "target_core_hba.h" + +static LIST_HEAD(subsystem_list); +static DEFINE_MUTEX(subsystem_mutex); + +int transport_subsystem_register(struct se_subsystem_api *sub_api) +{ + struct se_subsystem_api *s; + + INIT_LIST_HEAD(&sub_api->sub_api_list); + + mutex_lock(&subsystem_mutex); + list_for_each_entry(s, &subsystem_list, sub_api_list) { + if (!(strcmp(s->name, sub_api->name))) { + printk(KERN_ERR "%p is already registered with" + " duplicate name %s, unable to process" + " request\n", s, s->name); + mutex_unlock(&subsystem_mutex); + return -EEXIST; + } + } + list_add_tail(&sub_api->sub_api_list, &subsystem_list); + mutex_unlock(&subsystem_mutex); + + printk(KERN_INFO "TCM: Registered subsystem plugin: %s struct module:" + " %p\n", sub_api->name, sub_api->owner); + return 0; +} +EXPORT_SYMBOL(transport_subsystem_register); + +void transport_subsystem_release(struct se_subsystem_api *sub_api) +{ + mutex_lock(&subsystem_mutex); + list_del(&sub_api->sub_api_list); + mutex_unlock(&subsystem_mutex); +} +EXPORT_SYMBOL(transport_subsystem_release); + +static struct se_subsystem_api *core_get_backend(const char *sub_name) +{ + struct se_subsystem_api *s; + + mutex_lock(&subsystem_mutex); + list_for_each_entry(s, &subsystem_list, sub_api_list) { + if (!strcmp(s->name, sub_name)) + goto found; + } + mutex_unlock(&subsystem_mutex); + return NULL; +found: + if (s->owner && !try_module_get(s->owner)) + s = NULL; + mutex_unlock(&subsystem_mutex); + return s; +} + +struct se_hba * +core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags) +{ + struct se_hba *hba; + int ret = 0; + + hba = kzalloc(sizeof(*hba), GFP_KERNEL); + if (!hba) { + printk(KERN_ERR "Unable to allocate struct se_hba\n"); + return ERR_PTR(-ENOMEM); + } + + INIT_LIST_HEAD(&hba->hba_dev_list); + spin_lock_init(&hba->device_lock); + spin_lock_init(&hba->hba_queue_lock); + mutex_init(&hba->hba_access_mutex); + + hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX); + hba->hba_flags |= hba_flags; + + atomic_set(&hba->max_queue_depth, 0); + atomic_set(&hba->left_queue_depth, 0); + + hba->transport = core_get_backend(plugin_name); + if (!hba->transport) { + ret = -EINVAL; + goto out_free_hba; + } + + ret = hba->transport->attach_hba(hba, plugin_dep_id); + if (ret < 0) + goto out_module_put; + + spin_lock(&se_global->hba_lock); + hba->hba_id = se_global->g_hba_id_counter++; + list_add_tail(&hba->hba_list, &se_global->g_hba_list); + spin_unlock(&se_global->hba_lock); + + printk(KERN_INFO "CORE_HBA[%d] - Attached HBA to Generic Target" + " Core\n", hba->hba_id); + + return hba; + +out_module_put: + if (hba->transport->owner) + module_put(hba->transport->owner); + hba->transport = NULL; +out_free_hba: + kfree(hba); + return ERR_PTR(ret); +} + +int +core_delete_hba(struct se_hba *hba) +{ + struct se_device *dev, *dev_tmp; + + spin_lock(&hba->device_lock); + list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) { + + se_clear_dev_ports(dev); + spin_unlock(&hba->device_lock); + + se_release_device_for_hba(dev); + + spin_lock(&hba->device_lock); + } + spin_unlock(&hba->device_lock); + + hba->transport->detach_hba(hba); + + spin_lock(&se_global->hba_lock); + list_del(&hba->hba_list); + spin_unlock(&se_global->hba_lock); + + printk(KERN_INFO "CORE_HBA[%d] - Detached HBA from Generic Target" + " Core\n", hba->hba_id); + + if (hba->transport->owner) + module_put(hba->transport->owner); + + hba->transport = NULL; + kfree(hba); + return 0; +} diff --git a/drivers/target/target_core_hba.h b/drivers/target/target_core_hba.h new file mode 100644 index 000000000000..bb0fea5f730c --- /dev/null +++ b/drivers/target/target_core_hba.h @@ -0,0 +1,7 @@ +#ifndef TARGET_CORE_HBA_H +#define TARGET_CORE_HBA_H + +extern struct se_hba *core_alloc_hba(const char *, u32, u32); +extern int core_delete_hba(struct se_hba *); + +#endif /* TARGET_CORE_HBA_H */ diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c new file mode 100644 index 000000000000..c6e0d757e76e --- /dev/null +++ b/drivers/target/target_core_iblock.c @@ -0,0 +1,808 @@ +/******************************************************************************* + * Filename: target_core_iblock.c + * + * This file contains the Storage Engine <-> Linux BlockIO transport + * specific functions. + * + * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include + +#include +#include +#include + +#include "target_core_iblock.h" + +#if 0 +#define DEBUG_IBLOCK(x...) printk(x) +#else +#define DEBUG_IBLOCK(x...) +#endif + +static struct se_subsystem_api iblock_template; + +static void iblock_bio_done(struct bio *, int); + +/* iblock_attach_hba(): (Part of se_subsystem_api_t template) + * + * + */ +static int iblock_attach_hba(struct se_hba *hba, u32 host_id) +{ + struct iblock_hba *ib_host; + + ib_host = kzalloc(sizeof(struct iblock_hba), GFP_KERNEL); + if (!(ib_host)) { + printk(KERN_ERR "Unable to allocate memory for" + " struct iblock_hba\n"); + return -ENOMEM; + } + + ib_host->iblock_host_id = host_id; + + atomic_set(&hba->left_queue_depth, IBLOCK_HBA_QUEUE_DEPTH); + atomic_set(&hba->max_queue_depth, IBLOCK_HBA_QUEUE_DEPTH); + hba->hba_ptr = (void *) ib_host; + + printk(KERN_INFO "CORE_HBA[%d] - TCM iBlock HBA Driver %s on" + " Generic Target Core Stack %s\n", hba->hba_id, + IBLOCK_VERSION, TARGET_CORE_MOD_VERSION); + + printk(KERN_INFO "CORE_HBA[%d] - Attached iBlock HBA: %u to Generic" + " Target Core TCQ Depth: %d\n", hba->hba_id, + ib_host->iblock_host_id, atomic_read(&hba->max_queue_depth)); + + return 0; +} + +static void iblock_detach_hba(struct se_hba *hba) +{ + struct iblock_hba *ib_host = hba->hba_ptr; + + printk(KERN_INFO "CORE_HBA[%d] - Detached iBlock HBA: %u from Generic" + " Target Core\n", hba->hba_id, ib_host->iblock_host_id); + + kfree(ib_host); + hba->hba_ptr = NULL; +} + +static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name) +{ + struct iblock_dev *ib_dev = NULL; + struct iblock_hba *ib_host = hba->hba_ptr; + + ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL); + if (!(ib_dev)) { + printk(KERN_ERR "Unable to allocate struct iblock_dev\n"); + return NULL; + } + ib_dev->ibd_host = ib_host; + + printk(KERN_INFO "IBLOCK: Allocated ib_dev for %s\n", name); + + return ib_dev; +} + +static struct se_device *iblock_create_virtdevice( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + void *p) +{ + struct iblock_dev *ib_dev = p; + struct se_device *dev; + struct se_dev_limits dev_limits; + struct block_device *bd = NULL; + struct request_queue *q; + struct queue_limits *limits; + u32 dev_flags = 0; + + if (!(ib_dev)) { + printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n"); + return 0; + } + memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + /* + * These settings need to be made tunable.. + */ + ib_dev->ibd_bio_set = bioset_create(32, 64); + if (!(ib_dev->ibd_bio_set)) { + printk(KERN_ERR "IBLOCK: Unable to create bioset()\n"); + return 0; + } + printk(KERN_INFO "IBLOCK: Created bio_set()\n"); + /* + * iblock_check_configfs_dev_params() ensures that ib_dev->ibd_udev_path + * must already have been set in order for echo 1 > $HBA/$DEV/enable to run. + */ + printk(KERN_INFO "IBLOCK: Claiming struct block_device: %s\n", + ib_dev->ibd_udev_path); + + bd = blkdev_get_by_path(ib_dev->ibd_udev_path, + FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); + if (!(bd)) + goto failed; + /* + * Setup the local scope queue_limits from struct request_queue->limits + * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. + */ + q = bdev_get_queue(bd); + limits = &dev_limits.limits; + limits->logical_block_size = bdev_logical_block_size(bd); + limits->max_hw_sectors = queue_max_hw_sectors(q); + limits->max_sectors = queue_max_sectors(q); + dev_limits.hw_queue_depth = IBLOCK_MAX_DEVICE_QUEUE_DEPTH; + dev_limits.queue_depth = IBLOCK_DEVICE_QUEUE_DEPTH; + + ib_dev->ibd_major = MAJOR(bd->bd_dev); + ib_dev->ibd_minor = MINOR(bd->bd_dev); + ib_dev->ibd_bd = bd; + + dev = transport_add_device_to_core_hba(hba, + &iblock_template, se_dev, dev_flags, (void *)ib_dev, + &dev_limits, "IBLOCK", IBLOCK_VERSION); + if (!(dev)) + goto failed; + + ib_dev->ibd_depth = dev->queue_depth; + + /* + * Check if the underlying struct block_device request_queue supports + * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM + * in ATA and we need to set TPE=1 + */ + if (blk_queue_discard(bdev_get_queue(bd))) { + struct request_queue *q = bdev_get_queue(bd); + + DEV_ATTRIB(dev)->max_unmap_lba_count = + q->limits.max_discard_sectors; + /* + * Currently hardcoded to 1 in Linux/SCSI code.. + */ + DEV_ATTRIB(dev)->max_unmap_block_desc_count = 1; + DEV_ATTRIB(dev)->unmap_granularity = + q->limits.discard_granularity; + DEV_ATTRIB(dev)->unmap_granularity_alignment = + q->limits.discard_alignment; + + printk(KERN_INFO "IBLOCK: BLOCK Discard support available," + " disabled by default\n"); + } + + return dev; + +failed: + if (ib_dev->ibd_bio_set) { + bioset_free(ib_dev->ibd_bio_set); + ib_dev->ibd_bio_set = NULL; + } + ib_dev->ibd_bd = NULL; + ib_dev->ibd_major = 0; + ib_dev->ibd_minor = 0; + return NULL; +} + +static void iblock_free_device(void *p) +{ + struct iblock_dev *ib_dev = p; + + blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); + bioset_free(ib_dev->ibd_bio_set); + kfree(ib_dev); +} + +static inline struct iblock_req *IBLOCK_REQ(struct se_task *task) +{ + return container_of(task, struct iblock_req, ib_task); +} + +static struct se_task * +iblock_alloc_task(struct se_cmd *cmd) +{ + struct iblock_req *ib_req; + + ib_req = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); + if (!(ib_req)) { + printk(KERN_ERR "Unable to allocate memory for struct iblock_req\n"); + return NULL; + } + + ib_req->ib_dev = SE_DEV(cmd)->dev_ptr; + atomic_set(&ib_req->ib_bio_cnt, 0); + return &ib_req->ib_task; +} + +static unsigned long long iblock_emulate_read_cap_with_block_size( + struct se_device *dev, + struct block_device *bd, + struct request_queue *q) +{ + unsigned long long blocks_long = (div_u64(i_size_read(bd->bd_inode), + bdev_logical_block_size(bd)) - 1); + u32 block_size = bdev_logical_block_size(bd); + + if (block_size == DEV_ATTRIB(dev)->block_size) + return blocks_long; + + switch (block_size) { + case 4096: + switch (DEV_ATTRIB(dev)->block_size) { + case 2048: + blocks_long <<= 1; + break; + case 1024: + blocks_long <<= 2; + break; + case 512: + blocks_long <<= 3; + default: + break; + } + break; + case 2048: + switch (DEV_ATTRIB(dev)->block_size) { + case 4096: + blocks_long >>= 1; + break; + case 1024: + blocks_long <<= 1; + break; + case 512: + blocks_long <<= 2; + break; + default: + break; + } + break; + case 1024: + switch (DEV_ATTRIB(dev)->block_size) { + case 4096: + blocks_long >>= 2; + break; + case 2048: + blocks_long >>= 1; + break; + case 512: + blocks_long <<= 1; + break; + default: + break; + } + break; + case 512: + switch (DEV_ATTRIB(dev)->block_size) { + case 4096: + blocks_long >>= 3; + break; + case 2048: + blocks_long >>= 2; + break; + case 1024: + blocks_long >>= 1; + break; + default: + break; + } + break; + default: + break; + } + + return blocks_long; +} + +/* + * Emulate SYCHRONIZE_CACHE_* + */ +static void iblock_emulate_sync_cache(struct se_task *task) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; + int immed = (T_TASK(cmd)->t_task_cdb[1] & 0x2); + sector_t error_sector; + int ret; + + /* + * If the Immediate bit is set, queue up the GOOD response + * for this SYNCHRONIZE_CACHE op + */ + if (immed) + transport_complete_sync_cache(cmd, 1); + + /* + * blkdev_issue_flush() does not support a specifying a range, so + * we have to flush the entire cache. + */ + ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector); + if (ret != 0) { + printk(KERN_ERR "IBLOCK: block_issue_flush() failed: %d " + " error_sector: %llu\n", ret, + (unsigned long long)error_sector); + } + + if (!immed) + transport_complete_sync_cache(cmd, ret == 0); +} + +/* + * Tell TCM Core that we are capable of WriteCache emulation for + * an underlying struct se_device. + */ +static int iblock_emulated_write_cache(struct se_device *dev) +{ + return 1; +} + +static int iblock_emulated_dpo(struct se_device *dev) +{ + return 0; +} + +/* + * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs + * for TYPE_DISK. + */ +static int iblock_emulated_fua_write(struct se_device *dev) +{ + return 1; +} + +static int iblock_emulated_fua_read(struct se_device *dev) +{ + return 0; +} + +static int iblock_do_task(struct se_task *task) +{ + struct se_device *dev = task->task_se_cmd->se_dev; + struct iblock_req *req = IBLOCK_REQ(task); + struct iblock_dev *ibd = (struct iblock_dev *)req->ib_dev; + struct request_queue *q = bdev_get_queue(ibd->ibd_bd); + struct bio *bio = req->ib_bio, *nbio = NULL; + int rw; + + if (task->task_data_direction == DMA_TO_DEVICE) { + /* + * Force data to disk if we pretend to not have a volatile + * write cache, or the initiator set the Force Unit Access bit. + */ + if (DEV_ATTRIB(dev)->emulate_write_cache == 0 || + (DEV_ATTRIB(dev)->emulate_fua_write > 0 && + T_TASK(task->task_se_cmd)->t_tasks_fua)) + rw = WRITE_FUA; + else + rw = WRITE; + } else { + rw = READ; + } + + while (bio) { + nbio = bio->bi_next; + bio->bi_next = NULL; + DEBUG_IBLOCK("Calling submit_bio() task: %p bio: %p" + " bio->bi_sector: %llu\n", task, bio, bio->bi_sector); + + submit_bio(rw, bio); + bio = nbio; + } + + if (q->unplug_fn) + q->unplug_fn(q); + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} + +static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) +{ + struct iblock_dev *ibd = dev->dev_ptr; + struct block_device *bd = ibd->ibd_bd; + int barrier = 0; + + return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier); +} + +static void iblock_free_task(struct se_task *task) +{ + struct iblock_req *req = IBLOCK_REQ(task); + struct bio *bio, *hbio = req->ib_bio; + /* + * We only release the bio(s) here if iblock_bio_done() has not called + * bio_put() -> iblock_bio_destructor(). + */ + while (hbio != NULL) { + bio = hbio; + hbio = hbio->bi_next; + bio->bi_next = NULL; + bio_put(bio); + } + + kfree(req); +} + +enum { + Opt_udev_path, Opt_force, Opt_err +}; + +static match_table_t tokens = { + {Opt_udev_path, "udev_path=%s"}, + {Opt_force, "force=%d"}, + {Opt_err, NULL} +}; + +static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, + struct se_subsystem_dev *se_dev, + const char *page, ssize_t count) +{ + struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; + char *orig, *ptr, *opts; + substring_t args[MAX_OPT_ARGS]; + int ret = 0, arg, token; + + opts = kstrdup(page, GFP_KERNEL); + if (!opts) + return -ENOMEM; + + orig = opts; + + while ((ptr = strsep(&opts, ",")) != NULL) { + if (!*ptr) + continue; + + token = match_token(ptr, tokens, args); + switch (token) { + case Opt_udev_path: + if (ib_dev->ibd_bd) { + printk(KERN_ERR "Unable to set udev_path= while" + " ib_dev->ibd_bd exists\n"); + ret = -EEXIST; + goto out; + } + + ret = snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, + "%s", match_strdup(&args[0])); + printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n", + ib_dev->ibd_udev_path); + ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; + break; + case Opt_force: + match_int(args, &arg); + ib_dev->ibd_force = arg; + printk(KERN_INFO "IBLOCK: Set force=%d\n", + ib_dev->ibd_force); + break; + default: + break; + } + } + +out: + kfree(orig); + return (!ret) ? count : ret; +} + +static ssize_t iblock_check_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev) +{ + struct iblock_dev *ibd = se_dev->se_dev_su_ptr; + + if (!(ibd->ibd_flags & IBDF_HAS_UDEV_PATH)) { + printk(KERN_ERR "Missing udev_path= parameters for IBLOCK\n"); + return -1; + } + + return 0; +} + +static ssize_t iblock_show_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + char *b) +{ + struct iblock_dev *ibd = se_dev->se_dev_su_ptr; + struct block_device *bd = ibd->ibd_bd; + char buf[BDEVNAME_SIZE]; + ssize_t bl = 0; + + if (bd) + bl += sprintf(b + bl, "iBlock device: %s", + bdevname(bd, buf)); + if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) { + bl += sprintf(b + bl, " UDEV PATH: %s\n", + ibd->ibd_udev_path); + } else + bl += sprintf(b + bl, "\n"); + + bl += sprintf(b + bl, " "); + if (bd) { + bl += sprintf(b + bl, "Major: %d Minor: %d %s\n", + ibd->ibd_major, ibd->ibd_minor, (!bd->bd_contains) ? + "" : (bd->bd_holder == (struct iblock_dev *)ibd) ? + "CLAIMED: IBLOCK" : "CLAIMED: OS"); + } else { + bl += sprintf(b + bl, "Major: %d Minor: %d\n", + ibd->ibd_major, ibd->ibd_minor); + } + + return bl; +} + +static void iblock_bio_destructor(struct bio *bio) +{ + struct se_task *task = bio->bi_private; + struct iblock_dev *ib_dev = task->se_dev->dev_ptr; + + bio_free(bio, ib_dev->ibd_bio_set); +} + +static struct bio *iblock_get_bio( + struct se_task *task, + struct iblock_req *ib_req, + struct iblock_dev *ib_dev, + int *ret, + sector_t lba, + u32 sg_num) +{ + struct bio *bio; + + bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); + if (!(bio)) { + printk(KERN_ERR "Unable to allocate memory for bio\n"); + *ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + return NULL; + } + + DEBUG_IBLOCK("Allocated bio: %p task_sg_num: %u using ibd_bio_set:" + " %p\n", bio, task->task_sg_num, ib_dev->ibd_bio_set); + DEBUG_IBLOCK("Allocated bio: %p task_size: %u\n", bio, task->task_size); + + bio->bi_bdev = ib_dev->ibd_bd; + bio->bi_private = (void *) task; + bio->bi_destructor = iblock_bio_destructor; + bio->bi_end_io = &iblock_bio_done; + bio->bi_sector = lba; + atomic_inc(&ib_req->ib_bio_cnt); + + DEBUG_IBLOCK("Set bio->bi_sector: %llu\n", bio->bi_sector); + DEBUG_IBLOCK("Set ib_req->ib_bio_cnt: %d\n", + atomic_read(&ib_req->ib_bio_cnt)); + return bio; +} + +static int iblock_map_task_SG(struct se_task *task) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct se_device *dev = SE_DEV(cmd); + struct iblock_dev *ib_dev = task->se_dev->dev_ptr; + struct iblock_req *ib_req = IBLOCK_REQ(task); + struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; + struct scatterlist *sg; + int ret = 0; + u32 i, sg_num = task->task_sg_num; + sector_t block_lba; + /* + * Do starting conversion up from non 512-byte blocksize with + * struct se_task SCSI blocksize into Linux/Block 512 units for BIO. + */ + if (DEV_ATTRIB(dev)->block_size == 4096) + block_lba = (task->task_lba << 3); + else if (DEV_ATTRIB(dev)->block_size == 2048) + block_lba = (task->task_lba << 2); + else if (DEV_ATTRIB(dev)->block_size == 1024) + block_lba = (task->task_lba << 1); + else if (DEV_ATTRIB(dev)->block_size == 512) + block_lba = task->task_lba; + else { + printk(KERN_ERR "Unsupported SCSI -> BLOCK LBA conversion:" + " %u\n", DEV_ATTRIB(dev)->block_size); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + + bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num); + if (!(bio)) + return ret; + + ib_req->ib_bio = bio; + hbio = tbio = bio; + /* + * Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist + * from TCM struct se_mem -> task->task_sg -> struct scatterlist memory. + */ + for_each_sg(task->task_sg, sg, task->task_sg_num, i) { + DEBUG_IBLOCK("task: %p bio: %p Calling bio_add_page(): page:" + " %p len: %u offset: %u\n", task, bio, sg_page(sg), + sg->length, sg->offset); +again: + ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset); + if (ret != sg->length) { + + DEBUG_IBLOCK("*** Set bio->bi_sector: %llu\n", + bio->bi_sector); + DEBUG_IBLOCK("** task->task_size: %u\n", + task->task_size); + DEBUG_IBLOCK("*** bio->bi_max_vecs: %u\n", + bio->bi_max_vecs); + DEBUG_IBLOCK("*** bio->bi_vcnt: %u\n", + bio->bi_vcnt); + + bio = iblock_get_bio(task, ib_req, ib_dev, &ret, + block_lba, sg_num); + if (!(bio)) + goto fail; + + tbio = tbio->bi_next = bio; + DEBUG_IBLOCK("-----------------> Added +1 bio: %p to" + " list, Going to again\n", bio); + goto again; + } + /* Always in 512 byte units for Linux/Block */ + block_lba += sg->length >> IBLOCK_LBA_SHIFT; + sg_num--; + DEBUG_IBLOCK("task: %p bio-add_page() passed!, decremented" + " sg_num to %u\n", task, sg_num); + DEBUG_IBLOCK("task: %p bio_add_page() passed!, increased lba" + " to %llu\n", task, block_lba); + DEBUG_IBLOCK("task: %p bio_add_page() passed!, bio->bi_vcnt:" + " %u\n", task, bio->bi_vcnt); + } + + return 0; +fail: + while (hbio) { + bio = hbio; + hbio = hbio->bi_next; + bio->bi_next = NULL; + bio_put(bio); + } + return ret; +} + +static unsigned char *iblock_get_cdb(struct se_task *task) +{ + return IBLOCK_REQ(task)->ib_scsi_cdb; +} + +static u32 iblock_get_device_rev(struct se_device *dev) +{ + return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ +} + +static u32 iblock_get_device_type(struct se_device *dev) +{ + return TYPE_DISK; +} + +static sector_t iblock_get_blocks(struct se_device *dev) +{ + struct iblock_dev *ibd = dev->dev_ptr; + struct block_device *bd = ibd->ibd_bd; + struct request_queue *q = bdev_get_queue(bd); + + return iblock_emulate_read_cap_with_block_size(dev, bd, q); +} + +static void iblock_bio_done(struct bio *bio, int err) +{ + struct se_task *task = bio->bi_private; + struct iblock_req *ibr = IBLOCK_REQ(task); + /* + * Set -EIO if !BIO_UPTODATE and the passed is still err=0 + */ + if (!(test_bit(BIO_UPTODATE, &bio->bi_flags)) && !(err)) + err = -EIO; + + if (err != 0) { + printk(KERN_ERR "test_bit(BIO_UPTODATE) failed for bio: %p," + " err: %d\n", bio, err); + /* + * Bump the ib_bio_err_cnt and release bio. + */ + atomic_inc(&ibr->ib_bio_err_cnt); + smp_mb__after_atomic_inc(); + bio_put(bio); + /* + * Wait to complete the task until the last bio as completed. + */ + if (!(atomic_dec_and_test(&ibr->ib_bio_cnt))) + return; + + ibr->ib_bio = NULL; + transport_complete_task(task, 0); + return; + } + DEBUG_IBLOCK("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n", + task, bio, task->task_lba, bio->bi_sector, err); + /* + * bio_put() will call iblock_bio_destructor() to release the bio back + * to ibr->ib_bio_set. + */ + bio_put(bio); + /* + * Wait to complete the task until the last bio as completed. + */ + if (!(atomic_dec_and_test(&ibr->ib_bio_cnt))) + return; + /* + * Return GOOD status for task if zero ib_bio_err_cnt exists. + */ + ibr->ib_bio = NULL; + transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt))); +} + +static struct se_subsystem_api iblock_template = { + .name = "iblock", + .owner = THIS_MODULE, + .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, + .map_task_SG = iblock_map_task_SG, + .attach_hba = iblock_attach_hba, + .detach_hba = iblock_detach_hba, + .allocate_virtdevice = iblock_allocate_virtdevice, + .create_virtdevice = iblock_create_virtdevice, + .free_device = iblock_free_device, + .dpo_emulated = iblock_emulated_dpo, + .fua_write_emulated = iblock_emulated_fua_write, + .fua_read_emulated = iblock_emulated_fua_read, + .write_cache_emulated = iblock_emulated_write_cache, + .alloc_task = iblock_alloc_task, + .do_task = iblock_do_task, + .do_discard = iblock_do_discard, + .do_sync_cache = iblock_emulate_sync_cache, + .free_task = iblock_free_task, + .check_configfs_dev_params = iblock_check_configfs_dev_params, + .set_configfs_dev_params = iblock_set_configfs_dev_params, + .show_configfs_dev_params = iblock_show_configfs_dev_params, + .get_cdb = iblock_get_cdb, + .get_device_rev = iblock_get_device_rev, + .get_device_type = iblock_get_device_type, + .get_blocks = iblock_get_blocks, +}; + +static int __init iblock_module_init(void) +{ + return transport_subsystem_register(&iblock_template); +} + +static void iblock_module_exit(void) +{ + transport_subsystem_release(&iblock_template); +} + +MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin"); +MODULE_AUTHOR("nab@Linux-iSCSI.org"); +MODULE_LICENSE("GPL"); + +module_init(iblock_module_init); +module_exit(iblock_module_exit); diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h new file mode 100644 index 000000000000..64c1f4d69f76 --- /dev/null +++ b/drivers/target/target_core_iblock.h @@ -0,0 +1,40 @@ +#ifndef TARGET_CORE_IBLOCK_H +#define TARGET_CORE_IBLOCK_H + +#define IBLOCK_VERSION "4.0" + +#define IBLOCK_HBA_QUEUE_DEPTH 512 +#define IBLOCK_DEVICE_QUEUE_DEPTH 32 +#define IBLOCK_MAX_DEVICE_QUEUE_DEPTH 128 +#define IBLOCK_MAX_CDBS 16 +#define IBLOCK_LBA_SHIFT 9 + +struct iblock_req { + struct se_task ib_task; + unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE]; + atomic_t ib_bio_cnt; + atomic_t ib_bio_err_cnt; + struct bio *ib_bio; + struct iblock_dev *ib_dev; +} ____cacheline_aligned; + +#define IBDF_HAS_UDEV_PATH 0x01 +#define IBDF_HAS_FORCE 0x02 + +struct iblock_dev { + unsigned char ibd_udev_path[SE_UDEV_PATH_LEN]; + int ibd_force; + int ibd_major; + int ibd_minor; + u32 ibd_depth; + u32 ibd_flags; + struct bio_set *ibd_bio_set; + struct block_device *ibd_bd; + struct iblock_hba *ibd_host; +} ____cacheline_aligned; + +struct iblock_hba { + int iblock_host_id; +} ____cacheline_aligned; + +#endif /* TARGET_CORE_IBLOCK_H */ diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c new file mode 100644 index 000000000000..d5a48aa0d2d1 --- /dev/null +++ b/drivers/target/target_core_mib.c @@ -0,0 +1,1078 @@ +/******************************************************************************* + * Filename: target_core_mib.c + * + * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "target_core_hba.h" +#include "target_core_mib.h" + +/* SCSI mib table index */ +static struct scsi_index_table scsi_index_table; + +#ifndef INITIAL_JIFFIES +#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) +#endif + +/* SCSI Instance Table */ +#define SCSI_INST_SW_INDEX 1 +#define SCSI_TRANSPORT_INDEX 1 + +#define NONE "None" +#define ISPRINT(a) ((a >= ' ') && (a <= '~')) + +static inline int list_is_first(const struct list_head *list, + const struct list_head *head) +{ + return list->prev == head; +} + +static void *locate_hba_start( + struct seq_file *seq, + loff_t *pos) +{ + spin_lock(&se_global->g_device_lock); + return seq_list_start(&se_global->g_se_dev_list, *pos); +} + +static void *locate_hba_next( + struct seq_file *seq, + void *v, + loff_t *pos) +{ + return seq_list_next(v, &se_global->g_se_dev_list, pos); +} + +static void locate_hba_stop(struct seq_file *seq, void *v) +{ + spin_unlock(&se_global->g_device_lock); +} + +/**************************************************************************** + * SCSI MIB Tables + ****************************************************************************/ + +/* + * SCSI Instance Table + */ +static void *scsi_inst_seq_start( + struct seq_file *seq, + loff_t *pos) +{ + spin_lock(&se_global->hba_lock); + return seq_list_start(&se_global->g_hba_list, *pos); +} + +static void *scsi_inst_seq_next( + struct seq_file *seq, + void *v, + loff_t *pos) +{ + return seq_list_next(v, &se_global->g_hba_list, pos); +} + +static void scsi_inst_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock(&se_global->hba_lock); +} + +static int scsi_inst_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba = list_entry(v, struct se_hba, hba_list); + + if (list_is_first(&hba->hba_list, &se_global->g_hba_list)) + seq_puts(seq, "inst sw_indx\n"); + + seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX); + seq_printf(seq, "plugin: %s version: %s\n", + hba->transport->name, TARGET_CORE_VERSION); + + return 0; +} + +static const struct seq_operations scsi_inst_seq_ops = { + .start = scsi_inst_seq_start, + .next = scsi_inst_seq_next, + .stop = scsi_inst_seq_stop, + .show = scsi_inst_seq_show +}; + +static int scsi_inst_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_inst_seq_ops); +} + +static const struct file_operations scsi_inst_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_inst_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Device Table + */ +static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos) +{ + return locate_hba_start(seq, pos); +} + +static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return locate_hba_next(seq, v, pos); +} + +static void scsi_dev_seq_stop(struct seq_file *seq, void *v) +{ + locate_hba_stop(seq, v); +} + +static int scsi_dev_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba; + struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, + g_se_dev_list); + struct se_device *dev = se_dev->se_dev_ptr; + char str[28]; + int k; + + if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) + seq_puts(seq, "inst indx role ports\n"); + + if (!(dev)) + return 0; + + hba = dev->se_hba; + if (!(hba)) { + /* Log error ? */ + return 0; + } + + seq_printf(seq, "%u %u %s %u\n", hba->hba_index, + dev->dev_index, "Target", dev->dev_port_count); + + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + + /* vendor */ + for (k = 0; k < 8; k++) + str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ? + DEV_T10_WWN(dev)->vendor[k] : 0x20; + str[k] = 0x20; + + /* model */ + for (k = 0; k < 16; k++) + str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ? + DEV_T10_WWN(dev)->model[k] : 0x20; + str[k + 9] = 0; + + seq_printf(seq, "dev_alias: %s\n", str); + + return 0; +} + +static const struct seq_operations scsi_dev_seq_ops = { + .start = scsi_dev_seq_start, + .next = scsi_dev_seq_next, + .stop = scsi_dev_seq_stop, + .show = scsi_dev_seq_show +}; + +static int scsi_dev_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_dev_seq_ops); +} + +static const struct file_operations scsi_dev_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_dev_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Port Table + */ +static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos) +{ + return locate_hba_start(seq, pos); +} + +static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return locate_hba_next(seq, v, pos); +} + +static void scsi_port_seq_stop(struct seq_file *seq, void *v) +{ + locate_hba_stop(seq, v); +} + +static int scsi_port_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba; + struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, + g_se_dev_list); + struct se_device *dev = se_dev->se_dev_ptr; + struct se_port *sep, *sep_tmp; + + if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) + seq_puts(seq, "inst device indx role busy_count\n"); + + if (!(dev)) + return 0; + + hba = dev->se_hba; + if (!(hba)) { + /* Log error ? */ + return 0; + } + + /* FIXME: scsiPortBusyStatuses count */ + spin_lock(&dev->se_port_lock); + list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { + seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index, + dev->dev_index, sep->sep_index, "Device", + dev->dev_index, 0); + } + spin_unlock(&dev->se_port_lock); + + return 0; +} + +static const struct seq_operations scsi_port_seq_ops = { + .start = scsi_port_seq_start, + .next = scsi_port_seq_next, + .stop = scsi_port_seq_stop, + .show = scsi_port_seq_show +}; + +static int scsi_port_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_port_seq_ops); +} + +static const struct file_operations scsi_port_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_port_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Transport Table + */ +static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos) +{ + return locate_hba_start(seq, pos); +} + +static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return locate_hba_next(seq, v, pos); +} + +static void scsi_transport_seq_stop(struct seq_file *seq, void *v) +{ + locate_hba_stop(seq, v); +} + +static int scsi_transport_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba; + struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, + g_se_dev_list); + struct se_device *dev = se_dev->se_dev_ptr; + struct se_port *se, *se_tmp; + struct se_portal_group *tpg; + struct t10_wwn *wwn; + char buf[64]; + + if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) + seq_puts(seq, "inst device indx dev_name\n"); + + if (!(dev)) + return 0; + + hba = dev->se_hba; + if (!(hba)) { + /* Log error ? */ + return 0; + } + + wwn = DEV_T10_WWN(dev); + + spin_lock(&dev->se_port_lock); + list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) { + tpg = se->sep_tpg; + sprintf(buf, "scsiTransport%s", + TPG_TFO(tpg)->get_fabric_name()); + + seq_printf(seq, "%u %s %u %s+%s\n", + hba->hba_index, /* scsiTransportIndex */ + buf, /* scsiTransportType */ + (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ? + TPG_TFO(tpg)->tpg_get_inst_index(tpg) : + 0, + TPG_TFO(tpg)->tpg_get_wwn(tpg), + (strlen(wwn->unit_serial)) ? + /* scsiTransportDevName */ + wwn->unit_serial : wwn->vendor); + } + spin_unlock(&dev->se_port_lock); + + return 0; +} + +static const struct seq_operations scsi_transport_seq_ops = { + .start = scsi_transport_seq_start, + .next = scsi_transport_seq_next, + .stop = scsi_transport_seq_stop, + .show = scsi_transport_seq_show +}; + +static int scsi_transport_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_transport_seq_ops); +} + +static const struct file_operations scsi_transport_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_transport_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Target Device Table + */ +static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos) +{ + return locate_hba_start(seq, pos); +} + +static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return locate_hba_next(seq, v, pos); +} + +static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v) +{ + locate_hba_stop(seq, v); +} + + +#define LU_COUNT 1 /* for now */ +static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba; + struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, + g_se_dev_list); + struct se_device *dev = se_dev->se_dev_ptr; + int non_accessible_lus = 0; + char status[16]; + + if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) + seq_puts(seq, "inst indx num_LUs status non_access_LUs" + " resets\n"); + + if (!(dev)) + return 0; + + hba = dev->se_hba; + if (!(hba)) { + /* Log error ? */ + return 0; + } + + switch (dev->dev_status) { + case TRANSPORT_DEVICE_ACTIVATED: + strcpy(status, "activated"); + break; + case TRANSPORT_DEVICE_DEACTIVATED: + strcpy(status, "deactivated"); + non_accessible_lus = 1; + break; + case TRANSPORT_DEVICE_SHUTDOWN: + strcpy(status, "shutdown"); + non_accessible_lus = 1; + break; + case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: + case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: + strcpy(status, "offline"); + non_accessible_lus = 1; + break; + default: + sprintf(status, "unknown(%d)", dev->dev_status); + non_accessible_lus = 1; + } + + seq_printf(seq, "%u %u %u %s %u %u\n", + hba->hba_index, dev->dev_index, LU_COUNT, + status, non_accessible_lus, dev->num_resets); + + return 0; +} + +static const struct seq_operations scsi_tgt_dev_seq_ops = { + .start = scsi_tgt_dev_seq_start, + .next = scsi_tgt_dev_seq_next, + .stop = scsi_tgt_dev_seq_stop, + .show = scsi_tgt_dev_seq_show +}; + +static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_tgt_dev_seq_ops); +} + +static const struct file_operations scsi_tgt_dev_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_tgt_dev_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Target Port Table + */ +static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos) +{ + return locate_hba_start(seq, pos); +} + +static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return locate_hba_next(seq, v, pos); +} + +static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v) +{ + locate_hba_stop(seq, v); +} + +static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba; + struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, + g_se_dev_list); + struct se_device *dev = se_dev->se_dev_ptr; + struct se_port *sep, *sep_tmp; + struct se_portal_group *tpg; + u32 rx_mbytes, tx_mbytes; + unsigned long long num_cmds; + char buf[64]; + + if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) + seq_puts(seq, "inst device indx name port_index in_cmds" + " write_mbytes read_mbytes hs_in_cmds\n"); + + if (!(dev)) + return 0; + + hba = dev->se_hba; + if (!(hba)) { + /* Log error ? */ + return 0; + } + + spin_lock(&dev->se_port_lock); + list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { + tpg = sep->sep_tpg; + sprintf(buf, "%sPort#", + TPG_TFO(tpg)->get_fabric_name()); + + seq_printf(seq, "%u %u %u %s%d %s%s%d ", + hba->hba_index, + dev->dev_index, + sep->sep_index, + buf, sep->sep_index, + TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", + TPG_TFO(tpg)->tpg_get_tag(tpg)); + + spin_lock(&sep->sep_lun->lun_sep_lock); + num_cmds = sep->sep_stats.cmd_pdus; + rx_mbytes = (sep->sep_stats.rx_data_octets >> 20); + tx_mbytes = (sep->sep_stats.tx_data_octets >> 20); + spin_unlock(&sep->sep_lun->lun_sep_lock); + + seq_printf(seq, "%llu %u %u %u\n", num_cmds, + rx_mbytes, tx_mbytes, 0); + } + spin_unlock(&dev->se_port_lock); + + return 0; +} + +static const struct seq_operations scsi_tgt_port_seq_ops = { + .start = scsi_tgt_port_seq_start, + .next = scsi_tgt_port_seq_next, + .stop = scsi_tgt_port_seq_stop, + .show = scsi_tgt_port_seq_show +}; + +static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_tgt_port_seq_ops); +} + +static const struct file_operations scsi_tgt_port_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_tgt_port_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Authorized Initiator Table: + * It contains the SCSI Initiators authorized to be attached to one of the + * local Target ports. + * Iterates through all active TPGs and extracts the info from the ACLs + */ +static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos) +{ + spin_lock_bh(&se_global->se_tpg_lock); + return seq_list_start(&se_global->g_se_tpg_list, *pos); +} + +static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v, + loff_t *pos) +{ + return seq_list_next(v, &se_global->g_se_tpg_list, pos); +} + +static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&se_global->se_tpg_lock); +} + +static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v) +{ + struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, + se_tpg_list); + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_node_acl *se_nacl; + int j; + + if (list_is_first(&se_tpg->se_tpg_list, + &se_global->g_se_tpg_list)) + seq_puts(seq, "inst dev port indx dev_or_port intr_name " + "map_indx att_count num_cmds read_mbytes " + "write_mbytes hs_num_cmds creation_time row_status\n"); + + if (!(se_tpg)) + return 0; + + spin_lock(&se_tpg->acl_node_lock); + list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) { + + atomic_inc(&se_nacl->mib_ref_count); + smp_mb__after_atomic_inc(); + spin_unlock(&se_tpg->acl_node_lock); + + spin_lock_irq(&se_nacl->device_list_lock); + for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { + deve = &se_nacl->device_list[j]; + if (!(deve->lun_flags & + TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || + (!deve->se_lun)) + continue; + lun = deve->se_lun; + if (!lun->lun_se_dev) + continue; + + seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u" + " %u %s\n", + /* scsiInstIndex */ + (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? + TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : + 0, + /* scsiDeviceIndex */ + lun->lun_se_dev->dev_index, + /* scsiAuthIntrTgtPortIndex */ + TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), + /* scsiAuthIntrIndex */ + se_nacl->acl_index, + /* scsiAuthIntrDevOrPort */ + 1, + /* scsiAuthIntrName */ + se_nacl->initiatorname[0] ? + se_nacl->initiatorname : NONE, + /* FIXME: scsiAuthIntrLunMapIndex */ + 0, + /* scsiAuthIntrAttachedTimes */ + deve->attach_count, + /* scsiAuthIntrOutCommands */ + deve->total_cmds, + /* scsiAuthIntrReadMegaBytes */ + (u32)(deve->read_bytes >> 20), + /* scsiAuthIntrWrittenMegaBytes */ + (u32)(deve->write_bytes >> 20), + /* FIXME: scsiAuthIntrHSOutCommands */ + 0, + /* scsiAuthIntrLastCreation */ + (u32)(((u32)deve->creation_time - + INITIAL_JIFFIES) * 100 / HZ), + /* FIXME: scsiAuthIntrRowStatus */ + "Ready"); + } + spin_unlock_irq(&se_nacl->device_list_lock); + + spin_lock(&se_tpg->acl_node_lock); + atomic_dec(&se_nacl->mib_ref_count); + smp_mb__after_atomic_dec(); + } + spin_unlock(&se_tpg->acl_node_lock); + + return 0; +} + +static const struct seq_operations scsi_auth_intr_seq_ops = { + .start = scsi_auth_intr_seq_start, + .next = scsi_auth_intr_seq_next, + .stop = scsi_auth_intr_seq_stop, + .show = scsi_auth_intr_seq_show +}; + +static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_auth_intr_seq_ops); +} + +static const struct file_operations scsi_auth_intr_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_auth_intr_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Attached Initiator Port Table: + * It lists the SCSI Initiators attached to one of the local Target ports. + * Iterates through all active TPGs and use active sessions from each TPG + * to list the info fo this table. + */ +static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos) +{ + spin_lock_bh(&se_global->se_tpg_lock); + return seq_list_start(&se_global->g_se_tpg_list, *pos); +} + +static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v, + loff_t *pos) +{ + return seq_list_next(v, &se_global->g_se_tpg_list, pos); +} + +static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&se_global->se_tpg_lock); +} + +static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v) +{ + struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, + se_tpg_list); + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_node_acl *se_nacl; + struct se_session *se_sess; + unsigned char buf[64]; + int j; + + if (list_is_first(&se_tpg->se_tpg_list, + &se_global->g_se_tpg_list)) + seq_puts(seq, "inst dev port indx port_auth_indx port_name" + " port_ident\n"); + + if (!(se_tpg)) + return 0; + + spin_lock(&se_tpg->session_lock); + list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) { + if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) || + (!se_sess->se_node_acl) || + (!se_sess->se_node_acl->device_list)) + continue; + + atomic_inc(&se_sess->mib_ref_count); + smp_mb__after_atomic_inc(); + se_nacl = se_sess->se_node_acl; + atomic_inc(&se_nacl->mib_ref_count); + smp_mb__after_atomic_inc(); + spin_unlock(&se_tpg->session_lock); + + spin_lock_irq(&se_nacl->device_list_lock); + for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { + deve = &se_nacl->device_list[j]; + if (!(deve->lun_flags & + TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || + (!deve->se_lun)) + continue; + + lun = deve->se_lun; + if (!lun->lun_se_dev) + continue; + + memset(buf, 0, 64); + if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) + TPG_TFO(se_tpg)->sess_get_initiator_sid( + se_sess, (unsigned char *)&buf[0], 64); + + seq_printf(seq, "%u %u %u %u %u %s+i+%s\n", + /* scsiInstIndex */ + (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? + TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : + 0, + /* scsiDeviceIndex */ + lun->lun_se_dev->dev_index, + /* scsiPortIndex */ + TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), + /* scsiAttIntrPortIndex */ + (TPG_TFO(se_tpg)->sess_get_index != NULL) ? + TPG_TFO(se_tpg)->sess_get_index(se_sess) : + 0, + /* scsiAttIntrPortAuthIntrIdx */ + se_nacl->acl_index, + /* scsiAttIntrPortName */ + se_nacl->initiatorname[0] ? + se_nacl->initiatorname : NONE, + /* scsiAttIntrPortIdentifier */ + buf); + } + spin_unlock_irq(&se_nacl->device_list_lock); + + spin_lock(&se_tpg->session_lock); + atomic_dec(&se_nacl->mib_ref_count); + smp_mb__after_atomic_dec(); + atomic_dec(&se_sess->mib_ref_count); + smp_mb__after_atomic_dec(); + } + spin_unlock(&se_tpg->session_lock); + + return 0; +} + +static const struct seq_operations scsi_att_intr_port_seq_ops = { + .start = scsi_att_intr_port_seq_start, + .next = scsi_att_intr_port_seq_next, + .stop = scsi_att_intr_port_seq_stop, + .show = scsi_att_intr_port_seq_show +}; + +static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_att_intr_port_seq_ops); +} + +static const struct file_operations scsi_att_intr_port_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_att_intr_port_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * SCSI Logical Unit Table + */ +static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos) +{ + return locate_hba_start(seq, pos); +} + +static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return locate_hba_next(seq, v, pos); +} + +static void scsi_lu_seq_stop(struct seq_file *seq, void *v) +{ + locate_hba_stop(seq, v); +} + +#define SCSI_LU_INDEX 1 +static int scsi_lu_seq_show(struct seq_file *seq, void *v) +{ + struct se_hba *hba; + struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, + g_se_dev_list); + struct se_device *dev = se_dev->se_dev_ptr; + int j; + char str[28]; + + if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) + seq_puts(seq, "inst dev indx LUN lu_name vend prod rev" + " dev_type status state-bit num_cmds read_mbytes" + " write_mbytes resets full_stat hs_num_cmds creation_time\n"); + + if (!(dev)) + return 0; + + hba = dev->se_hba; + if (!(hba)) { + /* Log error ? */ + return 0; + } + + /* Fix LU state, if we can read it from the device */ + seq_printf(seq, "%u %u %u %llu %s", hba->hba_index, + dev->dev_index, SCSI_LU_INDEX, + (unsigned long long)0, /* FIXME: scsiLuDefaultLun */ + (strlen(DEV_T10_WWN(dev)->unit_serial)) ? + /* scsiLuWwnName */ + (char *)&DEV_T10_WWN(dev)->unit_serial[0] : + "None"); + + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + /* scsiLuVendorId */ + for (j = 0; j < 8; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? + DEV_T10_WWN(dev)->vendor[j] : 0x20; + str[8] = 0; + seq_printf(seq, " %s", str); + + /* scsiLuProductId */ + for (j = 0; j < 16; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? + DEV_T10_WWN(dev)->model[j] : 0x20; + str[16] = 0; + seq_printf(seq, " %s", str); + + /* scsiLuRevisionId */ + for (j = 0; j < 4; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? + DEV_T10_WWN(dev)->revision[j] : 0x20; + str[4] = 0; + seq_printf(seq, " %s", str); + + seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n", + /* scsiLuPeripheralType */ + TRANSPORT(dev)->get_device_type(dev), + (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? + "available" : "notavailable", /* scsiLuStatus */ + "exposed", /* scsiLuState */ + (unsigned long long)dev->num_cmds, + /* scsiLuReadMegaBytes */ + (u32)(dev->read_bytes >> 20), + /* scsiLuWrittenMegaBytes */ + (u32)(dev->write_bytes >> 20), + dev->num_resets, /* scsiLuInResets */ + 0, /* scsiLuOutTaskSetFullStatus */ + 0, /* scsiLuHSInCommands */ + (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) * + 100 / HZ)); + + return 0; +} + +static const struct seq_operations scsi_lu_seq_ops = { + .start = scsi_lu_seq_start, + .next = scsi_lu_seq_next, + .stop = scsi_lu_seq_stop, + .show = scsi_lu_seq_show +}; + +static int scsi_lu_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_lu_seq_ops); +} + +static const struct file_operations scsi_lu_seq_fops = { + .owner = THIS_MODULE, + .open = scsi_lu_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/****************************************************************************/ + +/* + * Remove proc fs entries + */ +void remove_scsi_target_mib(void) +{ + remove_proc_entry("scsi_target/mib/scsi_inst", NULL); + remove_proc_entry("scsi_target/mib/scsi_dev", NULL); + remove_proc_entry("scsi_target/mib/scsi_port", NULL); + remove_proc_entry("scsi_target/mib/scsi_transport", NULL); + remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL); + remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL); + remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL); + remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL); + remove_proc_entry("scsi_target/mib/scsi_lu", NULL); + remove_proc_entry("scsi_target/mib", NULL); +} + +/* + * Create proc fs entries for the mib tables + */ +int init_scsi_target_mib(void) +{ + struct proc_dir_entry *dir_entry; + struct proc_dir_entry *scsi_inst_entry; + struct proc_dir_entry *scsi_dev_entry; + struct proc_dir_entry *scsi_port_entry; + struct proc_dir_entry *scsi_transport_entry; + struct proc_dir_entry *scsi_tgt_dev_entry; + struct proc_dir_entry *scsi_tgt_port_entry; + struct proc_dir_entry *scsi_auth_intr_entry; + struct proc_dir_entry *scsi_att_intr_port_entry; + struct proc_dir_entry *scsi_lu_entry; + + dir_entry = proc_mkdir("scsi_target/mib", NULL); + if (!(dir_entry)) { + printk(KERN_ERR "proc_mkdir() failed.\n"); + return -1; + } + + scsi_inst_entry = + create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL); + if (scsi_inst_entry) + scsi_inst_entry->proc_fops = &scsi_inst_seq_fops; + else + goto error; + + scsi_dev_entry = + create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL); + if (scsi_dev_entry) + scsi_dev_entry->proc_fops = &scsi_dev_seq_fops; + else + goto error; + + scsi_port_entry = + create_proc_entry("scsi_target/mib/scsi_port", 0, NULL); + if (scsi_port_entry) + scsi_port_entry->proc_fops = &scsi_port_seq_fops; + else + goto error; + + scsi_transport_entry = + create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL); + if (scsi_transport_entry) + scsi_transport_entry->proc_fops = &scsi_transport_seq_fops; + else + goto error; + + scsi_tgt_dev_entry = + create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL); + if (scsi_tgt_dev_entry) + scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops; + else + goto error; + + scsi_tgt_port_entry = + create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL); + if (scsi_tgt_port_entry) + scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops; + else + goto error; + + scsi_auth_intr_entry = + create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL); + if (scsi_auth_intr_entry) + scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops; + else + goto error; + + scsi_att_intr_port_entry = + create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL); + if (scsi_att_intr_port_entry) + scsi_att_intr_port_entry->proc_fops = + &scsi_att_intr_port_seq_fops; + else + goto error; + + scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL); + if (scsi_lu_entry) + scsi_lu_entry->proc_fops = &scsi_lu_seq_fops; + else + goto error; + + return 0; + +error: + printk(KERN_ERR "create_proc_entry() failed.\n"); + remove_scsi_target_mib(); + return -1; +} + +/* + * Initialize the index table for allocating unique row indexes to various mib + * tables + */ +void init_scsi_index_table(void) +{ + memset(&scsi_index_table, 0, sizeof(struct scsi_index_table)); + spin_lock_init(&scsi_index_table.lock); +} + +/* + * Allocate a new row index for the entry type specified + */ +u32 scsi_get_new_index(scsi_index_t type) +{ + u32 new_index; + + if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) { + printk(KERN_ERR "Invalid index type %d\n", type); + return -1; + } + + spin_lock(&scsi_index_table.lock); + new_index = ++scsi_index_table.scsi_mib_index[type]; + if (new_index == 0) + new_index = ++scsi_index_table.scsi_mib_index[type]; + spin_unlock(&scsi_index_table.lock); + + return new_index; +} +EXPORT_SYMBOL(scsi_get_new_index); diff --git a/drivers/target/target_core_mib.h b/drivers/target/target_core_mib.h new file mode 100644 index 000000000000..277204633850 --- /dev/null +++ b/drivers/target/target_core_mib.h @@ -0,0 +1,28 @@ +#ifndef TARGET_CORE_MIB_H +#define TARGET_CORE_MIB_H + +typedef enum { + SCSI_INST_INDEX, + SCSI_DEVICE_INDEX, + SCSI_AUTH_INTR_INDEX, + SCSI_INDEX_TYPE_MAX +} scsi_index_t; + +struct scsi_index_table { + spinlock_t lock; + u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX]; +} ____cacheline_aligned; + +/* SCSI Port stats */ +struct scsi_port_stats { + u64 cmd_pdus; + u64 tx_data_octets; + u64 rx_data_octets; +} ____cacheline_aligned; + +extern int init_scsi_target_mib(void); +extern void remove_scsi_target_mib(void); +extern void init_scsi_index_table(void); +extern u32 scsi_get_new_index(scsi_index_t); + +#endif /*** TARGET_CORE_MIB_H ***/ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c new file mode 100644 index 000000000000..2521f75362c3 --- /dev/null +++ b/drivers/target/target_core_pr.c @@ -0,0 +1,4252 @@ +/******************************************************************************* + * Filename: target_core_pr.c + * + * This file contains SPC-3 compliant persistent reservations and + * legacy SPC-2 reservations with compatible reservation handling (CRH=1) + * + * Copyright (c) 2009, 2010 Rising Tide Systems + * Copyright (c) 2009, 2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include + +#include "target_core_hba.h" +#include "target_core_pr.h" +#include "target_core_ua.h" + +/* + * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT) + */ +struct pr_transport_id_holder { + int dest_local_nexus; + struct t10_pr_registration *dest_pr_reg; + struct se_portal_group *dest_tpg; + struct se_node_acl *dest_node_acl; + struct se_dev_entry *dest_se_deve; + struct list_head dest_list; +}; + +int core_pr_dump_initiator_port( + struct t10_pr_registration *pr_reg, + char *buf, + u32 size) +{ + if (!(pr_reg->isid_present_at_reg)) + return 0; + + snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]); + return 1; +} + +static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *, + struct t10_pr_registration *, int); + +static int core_scsi2_reservation_seq_non_holder( + struct se_cmd *cmd, + unsigned char *cdb, + u32 pr_reg_type) +{ + switch (cdb[0]) { + case INQUIRY: + case RELEASE: + case RELEASE_10: + return 0; + default: + return 1; + } + + return 1; +} + +static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type) +{ + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + int ret; + + if (!(sess)) + return 0; + + spin_lock(&dev->dev_reservation_lock); + if (!dev->dev_reserved_node_acl || !sess) { + spin_unlock(&dev->dev_reservation_lock); + return 0; + } + if (dev->dev_reserved_node_acl != sess->se_node_acl) { + spin_unlock(&dev->dev_reservation_lock); + return -1; + } + if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) { + spin_unlock(&dev->dev_reservation_lock); + return 0; + } + ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -1; + spin_unlock(&dev->dev_reservation_lock); + + return ret; +} + +static int core_scsi2_reservation_release(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + struct se_portal_group *tpg = sess->se_tpg; + + if (!(sess) || !(tpg)) + return 0; + + spin_lock(&dev->dev_reservation_lock); + if (!dev->dev_reserved_node_acl || !sess) { + spin_unlock(&dev->dev_reservation_lock); + return 0; + } + + if (dev->dev_reserved_node_acl != sess->se_node_acl) { + spin_unlock(&dev->dev_reservation_lock); + return 0; + } + dev->dev_reserved_node_acl = NULL; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS; + if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) { + dev->dev_res_bin_isid = 0; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID; + } + printk(KERN_INFO "SCSI-2 Released reservation for %s LUN: %u ->" + " MAPPED LUN: %u for %s\n", TPG_TFO(tpg)->get_fabric_name(), + SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + spin_unlock(&dev->dev_reservation_lock); + + return 0; +} + +static int core_scsi2_reservation_reserve(struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + struct se_portal_group *tpg = sess->se_tpg; + + if ((T_TASK(cmd)->t_task_cdb[1] & 0x01) && + (T_TASK(cmd)->t_task_cdb[1] & 0x02)) { + printk(KERN_ERR "LongIO and Obselete Bits set, returning" + " ILLEGAL_REQUEST\n"); + return PYX_TRANSPORT_ILLEGAL_REQUEST; + } + /* + * This is currently the case for target_core_mod passthrough struct se_cmd + * ops + */ + if (!(sess) || !(tpg)) + return 0; + + spin_lock(&dev->dev_reservation_lock); + if (dev->dev_reserved_node_acl && + (dev->dev_reserved_node_acl != sess->se_node_acl)) { + printk(KERN_ERR "SCSI-2 RESERVATION CONFLIFT for %s fabric\n", + TPG_TFO(tpg)->get_fabric_name()); + printk(KERN_ERR "Original reserver LUN: %u %s\n", + SE_LUN(cmd)->unpacked_lun, + dev->dev_reserved_node_acl->initiatorname); + printk(KERN_ERR "Current attempt - LUN: %u -> MAPPED LUN: %u" + " from %s \n", SE_LUN(cmd)->unpacked_lun, + cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + spin_unlock(&dev->dev_reservation_lock); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + + dev->dev_reserved_node_acl = sess->se_node_acl; + dev->dev_flags |= DF_SPC2_RESERVATIONS; + if (sess->sess_bin_isid != 0) { + dev->dev_res_bin_isid = sess->sess_bin_isid; + dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID; + } + printk(KERN_INFO "SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" + " for %s\n", TPG_TFO(tpg)->get_fabric_name(), + SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun, + sess->se_node_acl->initiatorname); + spin_unlock(&dev->dev_reservation_lock); + + return 0; +} + +static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *, + struct se_node_acl *, struct se_session *); +static void core_scsi3_put_pr_reg(struct t10_pr_registration *); + +/* + * Setup in target_core_transport.c:transport_generic_cmd_sequencer() + * and called via struct se_cmd->transport_emulate_cdb() in TCM processing + * thread context. + */ +int core_scsi2_emulate_crh(struct se_cmd *cmd) +{ + struct se_session *se_sess = cmd->se_sess; + struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; + struct t10_pr_registration *pr_reg; + struct t10_reservation_template *pr_tmpl = &su_dev->t10_reservation; + unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0]; + int crh = (T10_RES(su_dev)->res_type == SPC3_PERSISTENT_RESERVATIONS); + int conflict = 0; + + if (!(se_sess)) + return 0; + + if (!(crh)) + goto after_crh; + + pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, + se_sess); + if (pr_reg) { + /* + * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE + * behavior + * + * A RESERVE(6) or RESERVE(10) command shall complete with GOOD + * status, but no reservation shall be established and the + * persistent reservation shall not be changed, if the command + * is received from a) and b) below. + * + * A RELEASE(6) or RELEASE(10) command shall complete with GOOD + * status, but the persistent reservation shall not be released, + * if the command is received from a) and b) + * + * a) An I_T nexus that is a persistent reservation holder; or + * b) An I_T nexus that is registered if a registrants only or + * all registrants type persistent reservation is present. + * + * In all other cases, a RESERVE(6) command, RESERVE(10) command, + * RELEASE(6) command, or RELEASE(10) command shall be processed + * as defined in SPC-2. + */ + if (pr_reg->pr_res_holder) { + core_scsi3_put_pr_reg(pr_reg); + return 0; + } + if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || + (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) || + (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || + (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { + core_scsi3_put_pr_reg(pr_reg); + return 0; + } + core_scsi3_put_pr_reg(pr_reg); + conflict = 1; + } else { + /* + * Following spc2r20 5.5.1 Reservations overview: + * + * If a logical unit has executed a PERSISTENT RESERVE OUT + * command with the REGISTER or the REGISTER AND IGNORE + * EXISTING KEY service action and is still registered by any + * initiator, all RESERVE commands and all RELEASE commands + * regardless of initiator shall conflict and shall terminate + * with a RESERVATION CONFLICT status. + */ + spin_lock(&pr_tmpl->registration_lock); + conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1; + spin_unlock(&pr_tmpl->registration_lock); + } + + if (conflict) { + printk(KERN_ERR "Received legacy SPC-2 RESERVE/RELEASE" + " while active SPC-3 registrations exist," + " returning RESERVATION_CONFLICT\n"); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + +after_crh: + if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10)) + return core_scsi2_reservation_reserve(cmd); + else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10)) + return core_scsi2_reservation_release(cmd); + else + return PYX_TRANSPORT_INVALID_CDB_FIELD; +} + +/* + * Begin SPC-3/SPC-4 Persistent Reservations emulation support + * + * This function is called by those initiator ports who are *NOT* + * the active PR reservation holder when a reservation is present. + */ +static int core_scsi3_pr_seq_non_holder( + struct se_cmd *cmd, + unsigned char *cdb, + u32 pr_reg_type) +{ + struct se_dev_entry *se_deve; + struct se_session *se_sess = SE_SESS(cmd); + int other_cdb = 0, ignore_reg; + int registered_nexus = 0, ret = 1; /* Conflict by default */ + int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */ + int we = 0; /* Write Exclusive */ + int legacy = 0; /* Act like a legacy device and return + * RESERVATION CONFLICT on some CDBs */ + /* + * A legacy SPC-2 reservation is being held. + */ + if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) + return core_scsi2_reservation_seq_non_holder(cmd, + cdb, pr_reg_type); + + se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + /* + * Determine if the registration should be ignored due to + * non-matching ISIDs in core_scsi3_pr_reservation_check(). + */ + ignore_reg = (pr_reg_type & 0x80000000); + if (ignore_reg) + pr_reg_type &= ~0x80000000; + + switch (pr_reg_type) { + case PR_TYPE_WRITE_EXCLUSIVE: + we = 1; + case PR_TYPE_EXCLUSIVE_ACCESS: + /* + * Some commands are only allowed for the persistent reservation + * holder. + */ + if ((se_deve->def_pr_registered) && !(ignore_reg)) + registered_nexus = 1; + break; + case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: + we = 1; + case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: + /* + * Some commands are only allowed for registered I_T Nexuses. + */ + reg_only = 1; + if ((se_deve->def_pr_registered) && !(ignore_reg)) + registered_nexus = 1; + break; + case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: + we = 1; + case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: + /* + * Each registered I_T Nexus is a reservation holder. + */ + all_reg = 1; + if ((se_deve->def_pr_registered) && !(ignore_reg)) + registered_nexus = 1; + break; + default: + return -1; + } + /* + * Referenced from spc4r17 table 45 for *NON* PR holder access + */ + switch (cdb[0]) { + case SECURITY_PROTOCOL_IN: + if (registered_nexus) + return 0; + ret = (we) ? 0 : 1; + break; + case MODE_SENSE: + case MODE_SENSE_10: + case READ_ATTRIBUTE: + case READ_BUFFER: + case RECEIVE_DIAGNOSTIC: + if (legacy) { + ret = 1; + break; + } + if (registered_nexus) { + ret = 0; + break; + } + ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ + break; + case PERSISTENT_RESERVE_OUT: + /* + * This follows PERSISTENT_RESERVE_OUT service actions that + * are allowed in the presence of various reservations. + * See spc4r17, table 46 + */ + switch (cdb[1] & 0x1f) { + case PRO_CLEAR: + case PRO_PREEMPT: + case PRO_PREEMPT_AND_ABORT: + ret = (registered_nexus) ? 0 : 1; + break; + case PRO_REGISTER: + case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: + ret = 0; + break; + case PRO_REGISTER_AND_MOVE: + case PRO_RESERVE: + ret = 1; + break; + case PRO_RELEASE: + ret = (registered_nexus) ? 0 : 1; + break; + default: + printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service" + " action: 0x%02x\n", cdb[1] & 0x1f); + return -1; + } + break; + case RELEASE: + case RELEASE_10: + /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + ret = 0; + break; + case RESERVE: + case RESERVE_10: + /* Handled by CRH=1 in core_scsi2_emulate_crh() */ + ret = 0; + break; + case TEST_UNIT_READY: + ret = (legacy) ? 1 : 0; /* Conflict for legacy */ + break; + case MAINTENANCE_IN: + switch (cdb[1] & 0x1f) { + case MI_MANAGEMENT_PROTOCOL_IN: + if (registered_nexus) { + ret = 0; + break; + } + ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ + break; + case MI_REPORT_SUPPORTED_OPERATION_CODES: + case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS: + if (legacy) { + ret = 1; + break; + } + if (registered_nexus) { + ret = 0; + break; + } + ret = (we) ? 0 : 1; /* Allowed Write Exclusive */ + break; + case MI_REPORT_ALIASES: + case MI_REPORT_IDENTIFYING_INFORMATION: + case MI_REPORT_PRIORITY: + case MI_REPORT_TARGET_PGS: + case MI_REPORT_TIMESTAMP: + ret = 0; /* Allowed */ + break; + default: + printk(KERN_ERR "Unknown MI Service Action: 0x%02x\n", + (cdb[1] & 0x1f)); + return -1; + } + break; + case ACCESS_CONTROL_IN: + case ACCESS_CONTROL_OUT: + case INQUIRY: + case LOG_SENSE: + case READ_MEDIA_SERIAL_NUMBER: + case REPORT_LUNS: + case REQUEST_SENSE: + ret = 0; /*/ Allowed CDBs */ + break; + default: + other_cdb = 1; + break; + } + /* + * Case where the CDB is explictly allowed in the above switch + * statement. + */ + if (!(ret) && !(other_cdb)) { +#if 0 + printk(KERN_INFO "Allowing explict CDB: 0x%02x for %s" + " reservation holder\n", cdb[0], + core_scsi3_pr_dump_type(pr_reg_type)); +#endif + return ret; + } + /* + * Check if write exclusive initiator ports *NOT* holding the + * WRITE_EXCLUSIVE_* reservation. + */ + if ((we) && !(registered_nexus)) { + if (cmd->data_direction == DMA_TO_DEVICE) { + /* + * Conflict for write exclusive + */ + printk(KERN_INFO "%s Conflict for unregistered nexus" + " %s CDB: 0x%02x to %s reservation\n", + transport_dump_cmd_direction(cmd), + se_sess->se_node_acl->initiatorname, cdb[0], + core_scsi3_pr_dump_type(pr_reg_type)); + return 1; + } else { + /* + * Allow non WRITE CDBs for all Write Exclusive + * PR TYPEs to pass for registered and + * non-registered_nexuxes NOT holding the reservation. + * + * We only make noise for the unregisterd nexuses, + * as we expect registered non-reservation holding + * nexuses to issue CDBs. + */ +#if 0 + if (!(registered_nexus)) { + printk(KERN_INFO "Allowing implict CDB: 0x%02x" + " for %s reservation on unregistered" + " nexus\n", cdb[0], + core_scsi3_pr_dump_type(pr_reg_type)); + } +#endif + return 0; + } + } else if ((reg_only) || (all_reg)) { + if (registered_nexus) { + /* + * For PR_*_REG_ONLY and PR_*_ALL_REG reservations, + * allow commands from registered nexuses. + */ +#if 0 + printk(KERN_INFO "Allowing implict CDB: 0x%02x for %s" + " reservation\n", cdb[0], + core_scsi3_pr_dump_type(pr_reg_type)); +#endif + return 0; + } + } + printk(KERN_INFO "%s Conflict for %sregistered nexus %s CDB: 0x%2x" + " for %s reservation\n", transport_dump_cmd_direction(cmd), + (registered_nexus) ? "" : "un", + se_sess->se_node_acl->initiatorname, cdb[0], + core_scsi3_pr_dump_type(pr_reg_type)); + + return 1; /* Conflict by default */ +} + +static u32 core_scsi3_pr_generation(struct se_device *dev) +{ + struct se_subsystem_dev *su_dev = SU_DEV(dev); + u32 prg; + /* + * PRGeneration field shall contain the value of a 32-bit wrapping + * counter mainted by the device server. + * + * Note that this is done regardless of Active Persist across + * Target PowerLoss (APTPL) + * + * See spc4r17 section 6.3.12 READ_KEYS service action + */ + spin_lock(&dev->dev_reservation_lock); + prg = T10_RES(su_dev)->pr_generation++; + spin_unlock(&dev->dev_reservation_lock); + + return prg; +} + +static int core_scsi3_pr_reservation_check( + struct se_cmd *cmd, + u32 *pr_reg_type) +{ + struct se_device *dev = cmd->se_dev; + struct se_session *sess = cmd->se_sess; + int ret; + + if (!(sess)) + return 0; + /* + * A legacy SPC-2 reservation is being held. + */ + if (dev->dev_flags & DF_SPC2_RESERVATIONS) + return core_scsi2_reservation_check(cmd, pr_reg_type); + + spin_lock(&dev->dev_reservation_lock); + if (!(dev->dev_pr_res_holder)) { + spin_unlock(&dev->dev_reservation_lock); + return 0; + } + *pr_reg_type = dev->dev_pr_res_holder->pr_res_type; + cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key; + if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) { + spin_unlock(&dev->dev_reservation_lock); + return -1; + } + if (!(dev->dev_pr_res_holder->isid_present_at_reg)) { + spin_unlock(&dev->dev_reservation_lock); + return 0; + } + ret = (dev->dev_pr_res_holder->pr_reg_bin_isid == + sess->sess_bin_isid) ? 0 : -1; + /* + * Use bit in *pr_reg_type to notify ISID mismatch in + * core_scsi3_pr_seq_non_holder(). + */ + if (ret != 0) + *pr_reg_type |= 0x80000000; + spin_unlock(&dev->dev_reservation_lock); + + return ret; +} + +static struct t10_pr_registration *__core_scsi3_do_alloc_registration( + struct se_device *dev, + struct se_node_acl *nacl, + struct se_dev_entry *deve, + unsigned char *isid, + u64 sa_res_key, + int all_tg_pt, + int aptpl) +{ + struct se_subsystem_dev *su_dev = SU_DEV(dev); + struct t10_pr_registration *pr_reg; + + pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC); + if (!(pr_reg)) { + printk(KERN_ERR "Unable to allocate struct t10_pr_registration\n"); + return NULL; + } + + pr_reg->pr_aptpl_buf = kzalloc(T10_RES(su_dev)->pr_aptpl_buf_len, + GFP_ATOMIC); + if (!(pr_reg->pr_aptpl_buf)) { + printk(KERN_ERR "Unable to allocate pr_reg->pr_aptpl_buf\n"); + kmem_cache_free(t10_pr_reg_cache, pr_reg); + return NULL; + } + + INIT_LIST_HEAD(&pr_reg->pr_reg_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); + atomic_set(&pr_reg->pr_res_holders, 0); + pr_reg->pr_reg_nacl = nacl; + pr_reg->pr_reg_deve = deve; + pr_reg->pr_res_mapped_lun = deve->mapped_lun; + pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun; + pr_reg->pr_res_key = sa_res_key; + pr_reg->pr_reg_all_tg_pt = all_tg_pt; + pr_reg->pr_reg_aptpl = aptpl; + pr_reg->pr_reg_tg_pt_lun = deve->se_lun; + /* + * If an ISID value for this SCSI Initiator Port exists, + * save it to the registration now. + */ + if (isid != NULL) { + pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid); + snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid); + pr_reg->isid_present_at_reg = 1; + } + + return pr_reg; +} + +static int core_scsi3_lunacl_depend_item(struct se_dev_entry *); +static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *); + +/* + * Function used for handling PR registrations for ALL_TG_PT=1 and ALL_TG_PT=0 + * modes. + */ +static struct t10_pr_registration *__core_scsi3_alloc_registration( + struct se_device *dev, + struct se_node_acl *nacl, + struct se_dev_entry *deve, + unsigned char *isid, + u64 sa_res_key, + int all_tg_pt, + int aptpl) +{ + struct se_dev_entry *deve_tmp; + struct se_node_acl *nacl_tmp; + struct se_port *port, *port_tmp; + struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; + int ret; + /* + * Create a registration for the I_T Nexus upon which the + * PROUT REGISTER was received. + */ + pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid, + sa_res_key, all_tg_pt, aptpl); + if (!(pr_reg)) + return NULL; + /* + * Return pointer to pr_reg for ALL_TG_PT=0 + */ + if (!(all_tg_pt)) + return pr_reg; + /* + * Create list of matching SCSI Initiator Port registrations + * for ALL_TG_PT=1 + */ + spin_lock(&dev->se_port_lock); + list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) { + atomic_inc(&port->sep_tg_pt_ref_cnt); + smp_mb__after_atomic_inc(); + spin_unlock(&dev->se_port_lock); + + spin_lock_bh(&port->sep_alua_lock); + list_for_each_entry(deve_tmp, &port->sep_alua_list, + alua_port_list) { + /* + * This pointer will be NULL for demo mode MappedLUNs + * that have not been make explict via a ConfigFS + * MappedLUN group for the SCSI Initiator Node ACL. + */ + if (!(deve_tmp->se_lun_acl)) + continue; + + nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl; + /* + * Skip the matching struct se_node_acl that is allocated + * above.. + */ + if (nacl == nacl_tmp) + continue; + /* + * Only perform PR registrations for target ports on + * the same fabric module as the REGISTER w/ ALL_TG_PT=1 + * arrived. + */ + if (tfo != nacl_tmp->se_tpg->se_tpg_tfo) + continue; + /* + * Look for a matching Initiator Node ACL in ASCII format + */ + if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname)) + continue; + + atomic_inc(&deve_tmp->pr_ref_count); + smp_mb__after_atomic_inc(); + spin_unlock_bh(&port->sep_alua_lock); + /* + * Grab a configfs group dependency that is released + * for the exception path at label out: below, or upon + * completion of adding ALL_TG_PT=1 registrations in + * __core_scsi3_add_registration() + */ + ret = core_scsi3_lunacl_depend_item(deve_tmp); + if (ret < 0) { + printk(KERN_ERR "core_scsi3_lunacl_depend" + "_item() failed\n"); + atomic_dec(&port->sep_tg_pt_ref_cnt); + smp_mb__after_atomic_dec(); + atomic_dec(&deve_tmp->pr_ref_count); + smp_mb__after_atomic_dec(); + goto out; + } + /* + * Located a matching SCSI Initiator Port on a different + * port, allocate the pr_reg_atp and attach it to the + * pr_reg->pr_reg_atp_list that will be processed once + * the original *pr_reg is processed in + * __core_scsi3_add_registration() + */ + pr_reg_atp = __core_scsi3_do_alloc_registration(dev, + nacl_tmp, deve_tmp, NULL, + sa_res_key, all_tg_pt, aptpl); + if (!(pr_reg_atp)) { + atomic_dec(&port->sep_tg_pt_ref_cnt); + smp_mb__after_atomic_dec(); + atomic_dec(&deve_tmp->pr_ref_count); + smp_mb__after_atomic_dec(); + core_scsi3_lunacl_undepend_item(deve_tmp); + goto out; + } + + list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list, + &pr_reg->pr_reg_atp_list); + spin_lock_bh(&port->sep_alua_lock); + } + spin_unlock_bh(&port->sep_alua_lock); + + spin_lock(&dev->se_port_lock); + atomic_dec(&port->sep_tg_pt_ref_cnt); + smp_mb__after_atomic_dec(); + } + spin_unlock(&dev->se_port_lock); + + return pr_reg; +out: + list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, + &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { + list_del(&pr_reg_tmp->pr_reg_atp_mem_list); + core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); + kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp); + } + kmem_cache_free(t10_pr_reg_cache, pr_reg); + return NULL; +} + +int core_scsi3_alloc_aptpl_registration( + struct t10_reservation_template *pr_tmpl, + u64 sa_res_key, + unsigned char *i_port, + unsigned char *isid, + u32 mapped_lun, + unsigned char *t_port, + u16 tpgt, + u32 target_lun, + int res_holder, + int all_tg_pt, + u8 type) +{ + struct t10_pr_registration *pr_reg; + + if (!(i_port) || !(t_port) || !(sa_res_key)) { + printk(KERN_ERR "Illegal parameters for APTPL registration\n"); + return -1; + } + + pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_KERNEL); + if (!(pr_reg)) { + printk(KERN_ERR "Unable to allocate struct t10_pr_registration\n"); + return -1; + } + pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL); + + INIT_LIST_HEAD(&pr_reg->pr_reg_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list); + INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); + atomic_set(&pr_reg->pr_res_holders, 0); + pr_reg->pr_reg_nacl = NULL; + pr_reg->pr_reg_deve = NULL; + pr_reg->pr_res_mapped_lun = mapped_lun; + pr_reg->pr_aptpl_target_lun = target_lun; + pr_reg->pr_res_key = sa_res_key; + pr_reg->pr_reg_all_tg_pt = all_tg_pt; + pr_reg->pr_reg_aptpl = 1; + pr_reg->pr_reg_tg_pt_lun = NULL; + pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */ + pr_reg->pr_res_type = type; + /* + * If an ISID value had been saved in APTPL metadata for this + * SCSI Initiator Port, restore it now. + */ + if (isid != NULL) { + pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid); + snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid); + pr_reg->isid_present_at_reg = 1; + } + /* + * Copy the i_port and t_port information from caller. + */ + snprintf(pr_reg->pr_iport, PR_APTPL_MAX_IPORT_LEN, "%s", i_port); + snprintf(pr_reg->pr_tport, PR_APTPL_MAX_TPORT_LEN, "%s", t_port); + pr_reg->pr_reg_tpgt = tpgt; + /* + * Set pr_res_holder from caller, the pr_reg who is the reservation + * holder will get it's pointer set in core_scsi3_aptpl_reserve() once + * the Initiator Node LUN ACL from the fabric module is created for + * this registration. + */ + pr_reg->pr_res_holder = res_holder; + + list_add_tail(&pr_reg->pr_reg_aptpl_list, &pr_tmpl->aptpl_reg_list); + printk(KERN_INFO "SPC-3 PR APTPL Successfully added registration%s from" + " metadata\n", (res_holder) ? "+reservation" : ""); + return 0; +} + +static void core_scsi3_aptpl_reserve( + struct se_device *dev, + struct se_portal_group *tpg, + struct se_node_acl *node_acl, + struct t10_pr_registration *pr_reg) +{ + char i_buf[PR_REG_ISID_ID_LEN]; + int prf_isid; + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + + spin_lock(&dev->dev_reservation_lock); + dev->dev_pr_res_holder = pr_reg; + spin_unlock(&dev->dev_reservation_lock); + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: APTPL RESERVE created" + " new reservation holder TYPE: %s ALL_TG_PT: %d\n", + TPG_TFO(tpg)->get_fabric_name(), + core_scsi3_pr_dump_type(pr_reg->pr_res_type), + (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); + printk(KERN_INFO "SPC-3 PR [%s] RESERVE Node: %s%s\n", + TPG_TFO(tpg)->get_fabric_name(), node_acl->initiatorname, + (prf_isid) ? &i_buf[0] : ""); +} + +static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *, + struct t10_pr_registration *, int, int); + +static int __core_scsi3_check_aptpl_registration( + struct se_device *dev, + struct se_portal_group *tpg, + struct se_lun *lun, + u32 target_lun, + struct se_node_acl *nacl, + struct se_dev_entry *deve) +{ + struct t10_pr_registration *pr_reg, *pr_reg_tmp; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + unsigned char i_port[PR_APTPL_MAX_IPORT_LEN]; + unsigned char t_port[PR_APTPL_MAX_TPORT_LEN]; + u16 tpgt; + + memset(i_port, 0, PR_APTPL_MAX_IPORT_LEN); + memset(t_port, 0, PR_APTPL_MAX_TPORT_LEN); + /* + * Copy Initiator Port information from struct se_node_acl + */ + snprintf(i_port, PR_APTPL_MAX_IPORT_LEN, "%s", nacl->initiatorname); + snprintf(t_port, PR_APTPL_MAX_TPORT_LEN, "%s", + TPG_TFO(tpg)->tpg_get_wwn(tpg)); + tpgt = TPG_TFO(tpg)->tpg_get_tag(tpg); + /* + * Look for the matching registrations+reservation from those + * created from APTPL metadata. Note that multiple registrations + * may exist for fabrics that use ISIDs in their SCSI Initiator Port + * TransportIDs. + */ + spin_lock(&pr_tmpl->aptpl_reg_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list, + pr_reg_aptpl_list) { + if (!(strcmp(pr_reg->pr_iport, i_port)) && + (pr_reg->pr_res_mapped_lun == deve->mapped_lun) && + !(strcmp(pr_reg->pr_tport, t_port)) && + (pr_reg->pr_reg_tpgt == tpgt) && + (pr_reg->pr_aptpl_target_lun == target_lun)) { + + pr_reg->pr_reg_nacl = nacl; + pr_reg->pr_reg_deve = deve; + pr_reg->pr_reg_tg_pt_lun = lun; + + list_del(&pr_reg->pr_reg_aptpl_list); + spin_unlock(&pr_tmpl->aptpl_reg_lock); + /* + * At this point all of the pointers in *pr_reg will + * be setup, so go ahead and add the registration. + */ + + __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0); + /* + * If this registration is the reservation holder, + * make that happen now.. + */ + if (pr_reg->pr_res_holder) + core_scsi3_aptpl_reserve(dev, tpg, + nacl, pr_reg); + /* + * Reenable pr_aptpl_active to accept new metadata + * updates once the SCSI device is active again.. + */ + spin_lock(&pr_tmpl->aptpl_reg_lock); + pr_tmpl->pr_aptpl_active = 1; + } + } + spin_unlock(&pr_tmpl->aptpl_reg_lock); + + return 0; +} + +int core_scsi3_check_aptpl_registration( + struct se_device *dev, + struct se_portal_group *tpg, + struct se_lun *lun, + struct se_lun_acl *lun_acl) +{ + struct se_subsystem_dev *su_dev = SU_DEV(dev); + struct se_node_acl *nacl = lun_acl->se_lun_nacl; + struct se_dev_entry *deve = &nacl->device_list[lun_acl->mapped_lun]; + + if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS) + return 0; + + return __core_scsi3_check_aptpl_registration(dev, tpg, lun, + lun->unpacked_lun, nacl, deve); +} + +static void __core_scsi3_dump_registration( + struct target_core_fabric_ops *tfo, + struct se_device *dev, + struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, + int register_type) +{ + struct se_portal_group *se_tpg = nacl->se_tpg; + char i_buf[PR_REG_ISID_ID_LEN]; + int prf_isid; + + memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN); + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: REGISTER%s Initiator" + " Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ? + "_AND_MOVE" : (register_type == 1) ? + "_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname, + (prf_isid) ? i_buf : ""); + printk(KERN_INFO "SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n", + tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg), + tfo->tpg_get_tag(se_tpg)); + printk(KERN_INFO "SPC-3 PR [%s] for %s TCM Subsystem %s Object Target" + " Port(s)\n", tfo->get_fabric_name(), + (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", + TRANSPORT(dev)->name); + printk(KERN_INFO "SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:" + " 0x%08x APTPL: %d\n", tfo->get_fabric_name(), + pr_reg->pr_res_key, pr_reg->pr_res_generation, + pr_reg->pr_reg_aptpl); +} + +/* + * this function can be called with struct se_device->dev_reservation_lock + * when register_move = 1 + */ +static void __core_scsi3_add_registration( + struct se_device *dev, + struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, + int register_type, + int register_move) +{ + struct se_subsystem_dev *su_dev = SU_DEV(dev); + struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + + /* + * Increment PRgeneration counter for struct se_device upon a successful + * REGISTER, see spc4r17 section 6.3.2 READ_KEYS service action + * + * Also, when register_move = 1 for PROUT REGISTER_AND_MOVE service + * action, the struct se_device->dev_reservation_lock will already be held, + * so we do not call core_scsi3_pr_generation() which grabs the lock + * for the REGISTER. + */ + pr_reg->pr_res_generation = (register_move) ? + T10_RES(su_dev)->pr_generation++ : + core_scsi3_pr_generation(dev); + + spin_lock(&pr_tmpl->registration_lock); + list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); + pr_reg->pr_reg_deve->def_pr_registered = 1; + + __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); + spin_unlock(&pr_tmpl->registration_lock); + /* + * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. + */ + if (!(pr_reg->pr_reg_all_tg_pt) || (register_move)) + return; + /* + * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1 + * allocated in __core_scsi3_alloc_registration() + */ + list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, + &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { + list_del(&pr_reg_tmp->pr_reg_atp_mem_list); + + pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); + + spin_lock(&pr_tmpl->registration_lock); + list_add_tail(&pr_reg_tmp->pr_reg_list, + &pr_tmpl->registration_list); + pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; + + __core_scsi3_dump_registration(tfo, dev, + pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, + register_type); + spin_unlock(&pr_tmpl->registration_lock); + /* + * Drop configfs group dependency reference from + * __core_scsi3_alloc_registration() + */ + core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); + } +} + +static int core_scsi3_alloc_registration( + struct se_device *dev, + struct se_node_acl *nacl, + struct se_dev_entry *deve, + unsigned char *isid, + u64 sa_res_key, + int all_tg_pt, + int aptpl, + int register_type, + int register_move) +{ + struct t10_pr_registration *pr_reg; + + pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid, + sa_res_key, all_tg_pt, aptpl); + if (!(pr_reg)) + return -1; + + __core_scsi3_add_registration(dev, nacl, pr_reg, + register_type, register_move); + return 0; +} + +static struct t10_pr_registration *__core_scsi3_locate_pr_reg( + struct se_device *dev, + struct se_node_acl *nacl, + unsigned char *isid) +{ + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + struct t10_pr_registration *pr_reg, *pr_reg_tmp; + struct se_portal_group *tpg; + + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + /* + * First look for a matching struct se_node_acl + */ + if (pr_reg->pr_reg_nacl != nacl) + continue; + + tpg = pr_reg->pr_reg_nacl->se_tpg; + /* + * If this registration does NOT contain a fabric provided + * ISID, then we have found a match. + */ + if (!(pr_reg->isid_present_at_reg)) { + /* + * Determine if this SCSI device server requires that + * SCSI Intiatior TransportID w/ ISIDs is enforced + * for fabric modules (iSCSI) requiring them. + */ + if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) { + if (DEV_ATTRIB(dev)->enforce_pr_isids) + continue; + } + atomic_inc(&pr_reg->pr_res_holders); + smp_mb__after_atomic_inc(); + spin_unlock(&pr_tmpl->registration_lock); + return pr_reg; + } + /* + * If the *pr_reg contains a fabric defined ISID for multi-value + * SCSI Initiator Port TransportIDs, then we expect a valid + * matching ISID to be provided by the local SCSI Initiator Port. + */ + if (!(isid)) + continue; + if (strcmp(isid, pr_reg->pr_reg_isid)) + continue; + + atomic_inc(&pr_reg->pr_res_holders); + smp_mb__after_atomic_inc(); + spin_unlock(&pr_tmpl->registration_lock); + return pr_reg; + } + spin_unlock(&pr_tmpl->registration_lock); + + return NULL; +} + +static struct t10_pr_registration *core_scsi3_locate_pr_reg( + struct se_device *dev, + struct se_node_acl *nacl, + struct se_session *sess) +{ + struct se_portal_group *tpg = nacl->se_tpg; + unsigned char buf[PR_REG_ISID_LEN], *isid_ptr = NULL; + + if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) { + memset(&buf[0], 0, PR_REG_ISID_LEN); + TPG_TFO(tpg)->sess_get_initiator_sid(sess, &buf[0], + PR_REG_ISID_LEN); + isid_ptr = &buf[0]; + } + + return __core_scsi3_locate_pr_reg(dev, nacl, isid_ptr); +} + +static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg) +{ + atomic_dec(&pr_reg->pr_res_holders); + smp_mb__after_atomic_dec(); +} + +static int core_scsi3_check_implict_release( + struct se_device *dev, + struct t10_pr_registration *pr_reg) +{ + struct se_node_acl *nacl = pr_reg->pr_reg_nacl; + struct t10_pr_registration *pr_res_holder; + int ret = 0; + + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if (!(pr_res_holder)) { + spin_unlock(&dev->dev_reservation_lock); + return ret; + } + if (pr_res_holder == pr_reg) { + /* + * Perform an implict RELEASE if the registration that + * is being released is holding the reservation. + * + * From spc4r17, section 5.7.11.1: + * + * e) If the I_T nexus is the persistent reservation holder + * and the persistent reservation is not an all registrants + * type, then a PERSISTENT RESERVE OUT command with REGISTER + * service action or REGISTER AND IGNORE EXISTING KEY + * service action with the SERVICE ACTION RESERVATION KEY + * field set to zero (see 5.7.11.3). + */ + __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0); + ret = 1; + /* + * For 'All Registrants' reservation types, all existing + * registrations are still processed as reservation holders + * in core_scsi3_pr_seq_non_holder() after the initial + * reservation holder is implictly released here. + */ + } else if (pr_reg->pr_reg_all_tg_pt && + (!strcmp(pr_res_holder->pr_reg_nacl->initiatorname, + pr_reg->pr_reg_nacl->initiatorname)) && + (pr_res_holder->pr_res_key == pr_reg->pr_res_key)) { + printk(KERN_ERR "SPC-3 PR: Unable to perform ALL_TG_PT=1" + " UNREGISTER while existing reservation with matching" + " key 0x%016Lx is present from another SCSI Initiator" + " Port\n", pr_reg->pr_res_key); + ret = -1; + } + spin_unlock(&dev->dev_reservation_lock); + + return ret; +} + +/* + * Called with struct t10_reservation_template->registration_lock held. + */ +static void __core_scsi3_free_registration( + struct se_device *dev, + struct t10_pr_registration *pr_reg, + struct list_head *preempt_and_abort_list, + int dec_holders) +{ + struct target_core_fabric_ops *tfo = + pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + char i_buf[PR_REG_ISID_ID_LEN]; + int prf_isid; + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + + pr_reg->pr_reg_deve->def_pr_registered = 0; + pr_reg->pr_reg_deve->pr_res_key = 0; + list_del(&pr_reg->pr_reg_list); + /* + * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(), + * so call core_scsi3_put_pr_reg() to decrement our reference. + */ + if (dec_holders) + core_scsi3_put_pr_reg(pr_reg); + /* + * Wait until all reference from any other I_T nexuses for this + * *pr_reg have been released. Because list_del() is called above, + * the last core_scsi3_put_pr_reg(pr_reg) will release this reference + * count back to zero, and we release *pr_reg. + */ + while (atomic_read(&pr_reg->pr_res_holders) != 0) { + spin_unlock(&pr_tmpl->registration_lock); + printk("SPC-3 PR [%s] waiting for pr_res_holders\n", + tfo->get_fabric_name()); + cpu_relax(); + spin_lock(&pr_tmpl->registration_lock); + } + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: UNREGISTER Initiator" + " Node: %s%s\n", tfo->get_fabric_name(), + pr_reg->pr_reg_nacl->initiatorname, + (prf_isid) ? &i_buf[0] : ""); + printk(KERN_INFO "SPC-3 PR [%s] for %s TCM Subsystem %s Object Target" + " Port(s)\n", tfo->get_fabric_name(), + (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", + TRANSPORT(dev)->name); + printk(KERN_INFO "SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:" + " 0x%08x\n", tfo->get_fabric_name(), pr_reg->pr_res_key, + pr_reg->pr_res_generation); + + if (!(preempt_and_abort_list)) { + pr_reg->pr_reg_deve = NULL; + pr_reg->pr_reg_nacl = NULL; + kfree(pr_reg->pr_aptpl_buf); + kmem_cache_free(t10_pr_reg_cache, pr_reg); + return; + } + /* + * For PREEMPT_AND_ABORT, the list of *pr_reg in preempt_and_abort_list + * are released once the ABORT_TASK_SET has completed.. + */ + list_add_tail(&pr_reg->pr_reg_abort_list, preempt_and_abort_list); +} + +void core_scsi3_free_pr_reg_from_nacl( + struct se_device *dev, + struct se_node_acl *nacl) +{ + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; + /* + * If the passed se_node_acl matches the reservation holder, + * release the reservation. + */ + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if ((pr_res_holder != NULL) && + (pr_res_holder->pr_reg_nacl == nacl)) + __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0); + spin_unlock(&dev->dev_reservation_lock); + /* + * Release any registration associated with the struct se_node_acl. + */ + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + + if (pr_reg->pr_reg_nacl != nacl) + continue; + + __core_scsi3_free_registration(dev, pr_reg, NULL, 0); + } + spin_unlock(&pr_tmpl->registration_lock); +} + +void core_scsi3_free_all_registrations( + struct se_device *dev) +{ + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; + + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if (pr_res_holder != NULL) { + struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; + __core_scsi3_complete_pro_release(dev, pr_res_nacl, + pr_res_holder, 0); + } + spin_unlock(&dev->dev_reservation_lock); + + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + + __core_scsi3_free_registration(dev, pr_reg, NULL, 0); + } + spin_unlock(&pr_tmpl->registration_lock); + + spin_lock(&pr_tmpl->aptpl_reg_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list, + pr_reg_aptpl_list) { + list_del(&pr_reg->pr_reg_aptpl_list); + kfree(pr_reg->pr_aptpl_buf); + kmem_cache_free(t10_pr_reg_cache, pr_reg); + } + spin_unlock(&pr_tmpl->aptpl_reg_lock); +} + +static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg) +{ + return configfs_depend_item(TPG_TFO(tpg)->tf_subsys, + &tpg->tpg_group.cg_item); +} + +static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg) +{ + configfs_undepend_item(TPG_TFO(tpg)->tf_subsys, + &tpg->tpg_group.cg_item); + + atomic_dec(&tpg->tpg_pr_ref_count); + smp_mb__after_atomic_dec(); +} + +static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl) +{ + struct se_portal_group *tpg = nacl->se_tpg; + + if (nacl->dynamic_node_acl) + return 0; + + return configfs_depend_item(TPG_TFO(tpg)->tf_subsys, + &nacl->acl_group.cg_item); +} + +static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) +{ + struct se_portal_group *tpg = nacl->se_tpg; + + if (nacl->dynamic_node_acl) { + atomic_dec(&nacl->acl_pr_ref_count); + smp_mb__after_atomic_dec(); + return; + } + + configfs_undepend_item(TPG_TFO(tpg)->tf_subsys, + &nacl->acl_group.cg_item); + + atomic_dec(&nacl->acl_pr_ref_count); + smp_mb__after_atomic_dec(); +} + +static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) +{ + struct se_lun_acl *lun_acl = se_deve->se_lun_acl; + struct se_node_acl *nacl; + struct se_portal_group *tpg; + /* + * For nacl->dynamic_node_acl=1 + */ + if (!(lun_acl)) + return 0; + + nacl = lun_acl->se_lun_nacl; + tpg = nacl->se_tpg; + + return configfs_depend_item(TPG_TFO(tpg)->tf_subsys, + &lun_acl->se_lun_group.cg_item); +} + +static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) +{ + struct se_lun_acl *lun_acl = se_deve->se_lun_acl; + struct se_node_acl *nacl; + struct se_portal_group *tpg; + /* + * For nacl->dynamic_node_acl=1 + */ + if (!(lun_acl)) { + atomic_dec(&se_deve->pr_ref_count); + smp_mb__after_atomic_dec(); + return; + } + nacl = lun_acl->se_lun_nacl; + tpg = nacl->se_tpg; + + configfs_undepend_item(TPG_TFO(tpg)->tf_subsys, + &lun_acl->se_lun_group.cg_item); + + atomic_dec(&se_deve->pr_ref_count); + smp_mb__after_atomic_dec(); +} + +static int core_scsi3_decode_spec_i_port( + struct se_cmd *cmd, + struct se_portal_group *tpg, + unsigned char *l_isid, + u64 sa_res_key, + int all_tg_pt, + int aptpl) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_port *tmp_port; + struct se_portal_group *dest_tpg = NULL, *tmp_tpg; + struct se_session *se_sess = SE_SESS(cmd); + struct se_node_acl *dest_node_acl = NULL; + struct se_dev_entry *dest_se_deve = NULL, *local_se_deve; + struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; + struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; + struct list_head tid_dest_list; + struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; + struct target_core_fabric_ops *tmp_tf_ops; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; + char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; + u32 tpdl, tid_len = 0; + int ret, dest_local_nexus, prf_isid; + u32 dest_rtpi = 0; + + memset(dest_iport, 0, 64); + INIT_LIST_HEAD(&tid_dest_list); + + local_se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + /* + * Allocate a struct pr_transport_id_holder and setup the + * local_node_acl and local_se_deve pointers and add to + * struct list_head tid_dest_list for add registration + * processing in the loop of tid_dest_list below. + */ + tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); + if (!(tidh_new)) { + printk(KERN_ERR "Unable to allocate tidh_new\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + INIT_LIST_HEAD(&tidh_new->dest_list); + tidh_new->dest_tpg = tpg; + tidh_new->dest_node_acl = se_sess->se_node_acl; + tidh_new->dest_se_deve = local_se_deve; + + local_pr_reg = __core_scsi3_alloc_registration(SE_DEV(cmd), + se_sess->se_node_acl, local_se_deve, l_isid, + sa_res_key, all_tg_pt, aptpl); + if (!(local_pr_reg)) { + kfree(tidh_new); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + tidh_new->dest_pr_reg = local_pr_reg; + /* + * The local I_T nexus does not hold any configfs dependances, + * so we set tid_h->dest_local_nexus=1 to prevent the + * configfs_undepend_item() calls in the tid_dest_list loops below. + */ + tidh_new->dest_local_nexus = 1; + list_add_tail(&tidh_new->dest_list, &tid_dest_list); + /* + * For a PERSISTENT RESERVE OUT specify initiator ports payload, + * first extract TransportID Parameter Data Length, and make sure + * the value matches up to the SCSI expected data transfer length. + */ + tpdl = (buf[24] & 0xff) << 24; + tpdl |= (buf[25] & 0xff) << 16; + tpdl |= (buf[26] & 0xff) << 8; + tpdl |= buf[27] & 0xff; + + if ((tpdl + 28) != cmd->data_length) { + printk(KERN_ERR "SPC-3 PR: Illegal tpdl: %u + 28 byte header" + " does not equal CDB data_length: %u\n", tpdl, + cmd->data_length); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + /* + * Start processing the received transport IDs using the + * receiving I_T Nexus portal's fabric dependent methods to + * obtain the SCSI Initiator Port/Device Identifiers. + */ + ptr = &buf[28]; + + while (tpdl > 0) { + proto_ident = (ptr[0] & 0x0f); + dest_tpg = NULL; + + spin_lock(&dev->se_port_lock); + list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) { + tmp_tpg = tmp_port->sep_tpg; + if (!(tmp_tpg)) + continue; + tmp_tf_ops = TPG_TFO(tmp_tpg); + if (!(tmp_tf_ops)) + continue; + if (!(tmp_tf_ops->get_fabric_proto_ident) || + !(tmp_tf_ops->tpg_parse_pr_out_transport_id)) + continue; + /* + * Look for the matching proto_ident provided by + * the received TransportID + */ + tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg); + if (tmp_proto_ident != proto_ident) + continue; + dest_rtpi = tmp_port->sep_rtpi; + + i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id( + tmp_tpg, (const char *)ptr, &tid_len, + &iport_ptr); + if (!(i_str)) + continue; + + atomic_inc(&tmp_tpg->tpg_pr_ref_count); + smp_mb__after_atomic_inc(); + spin_unlock(&dev->se_port_lock); + + ret = core_scsi3_tpg_depend_item(tmp_tpg); + if (ret != 0) { + printk(KERN_ERR " core_scsi3_tpg_depend_item()" + " for tmp_tpg\n"); + atomic_dec(&tmp_tpg->tpg_pr_ref_count); + smp_mb__after_atomic_dec(); + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } + /* + * Locate the desination initiator ACL to be registered + * from the decoded fabric module specific TransportID + * at *i_str. + */ + spin_lock_bh(&tmp_tpg->acl_node_lock); + dest_node_acl = __core_tpg_get_initiator_node_acl( + tmp_tpg, i_str); + if (dest_node_acl) { + atomic_inc(&dest_node_acl->acl_pr_ref_count); + smp_mb__after_atomic_inc(); + } + spin_unlock_bh(&tmp_tpg->acl_node_lock); + + if (!(dest_node_acl)) { + core_scsi3_tpg_undepend_item(tmp_tpg); + spin_lock(&dev->se_port_lock); + continue; + } + + ret = core_scsi3_nodeacl_depend_item(dest_node_acl); + if (ret != 0) { + printk(KERN_ERR "configfs_depend_item() failed" + " for dest_node_acl->acl_group\n"); + atomic_dec(&dest_node_acl->acl_pr_ref_count); + smp_mb__after_atomic_dec(); + core_scsi3_tpg_undepend_item(tmp_tpg); + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } + + dest_tpg = tmp_tpg; + printk(KERN_INFO "SPC-3 PR SPEC_I_PT: Located %s Node:" + " %s Port RTPI: %hu\n", + TPG_TFO(dest_tpg)->get_fabric_name(), + dest_node_acl->initiatorname, dest_rtpi); + + spin_lock(&dev->se_port_lock); + break; + } + spin_unlock(&dev->se_port_lock); + + if (!(dest_tpg)) { + printk(KERN_ERR "SPC-3 PR SPEC_I_PT: Unable to locate" + " dest_tpg\n"); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } +#if 0 + printk("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u" + " tid_len: %d for %s + %s\n", + TPG_TFO(dest_tpg)->get_fabric_name(), cmd->data_length, + tpdl, tid_len, i_str, iport_ptr); +#endif + if (tid_len > tpdl) { + printk(KERN_ERR "SPC-3 PR SPEC_I_PT: Illegal tid_len:" + " %u for Transport ID: %s\n", tid_len, ptr); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + /* + * Locate the desintation struct se_dev_entry pointer for matching + * RELATIVE TARGET PORT IDENTIFIER on the receiving I_T Nexus + * Target Port. + */ + dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, + dest_rtpi); + if (!(dest_se_deve)) { + printk(KERN_ERR "Unable to locate %s dest_se_deve" + " from destination RTPI: %hu\n", + TPG_TFO(dest_tpg)->get_fabric_name(), + dest_rtpi); + + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + + ret = core_scsi3_lunacl_depend_item(dest_se_deve); + if (ret < 0) { + printk(KERN_ERR "core_scsi3_lunacl_depend_item()" + " failed\n"); + atomic_dec(&dest_se_deve->pr_ref_count); + smp_mb__after_atomic_dec(); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } +#if 0 + printk(KERN_INFO "SPC-3 PR SPEC_I_PT: Located %s Node: %s" + " dest_se_deve mapped_lun: %u\n", + TPG_TFO(dest_tpg)->get_fabric_name(), + dest_node_acl->initiatorname, dest_se_deve->mapped_lun); +#endif + /* + * Skip any TransportIDs that already have a registration for + * this target port. + */ + pr_reg_e = __core_scsi3_locate_pr_reg(dev, dest_node_acl, + iport_ptr); + if (pr_reg_e) { + core_scsi3_put_pr_reg(pr_reg_e); + core_scsi3_lunacl_undepend_item(dest_se_deve); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + ptr += tid_len; + tpdl -= tid_len; + tid_len = 0; + continue; + } + /* + * Allocate a struct pr_transport_id_holder and setup + * the dest_node_acl and dest_se_deve pointers for the + * loop below. + */ + tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), + GFP_KERNEL); + if (!(tidh_new)) { + printk(KERN_ERR "Unable to allocate tidh_new\n"); + core_scsi3_lunacl_undepend_item(dest_se_deve); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } + INIT_LIST_HEAD(&tidh_new->dest_list); + tidh_new->dest_tpg = dest_tpg; + tidh_new->dest_node_acl = dest_node_acl; + tidh_new->dest_se_deve = dest_se_deve; + + /* + * Allocate, but do NOT add the registration for the + * TransportID referenced SCSI Initiator port. This + * done because of the following from spc4r17 in section + * 6.14.3 wrt SPEC_I_PT: + * + * "If a registration fails for any initiator port (e.g., if th + * logical unit does not have enough resources available to + * hold the registration information), no registrations shall be + * made, and the command shall be terminated with + * CHECK CONDITION status." + * + * That means we call __core_scsi3_alloc_registration() here, + * and then call __core_scsi3_add_registration() in the + * 2nd loop which will never fail. + */ + dest_pr_reg = __core_scsi3_alloc_registration(SE_DEV(cmd), + dest_node_acl, dest_se_deve, iport_ptr, + sa_res_key, all_tg_pt, aptpl); + if (!(dest_pr_reg)) { + core_scsi3_lunacl_undepend_item(dest_se_deve); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + kfree(tidh_new); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + tidh_new->dest_pr_reg = dest_pr_reg; + list_add_tail(&tidh_new->dest_list, &tid_dest_list); + + ptr += tid_len; + tpdl -= tid_len; + tid_len = 0; + + } + /* + * Go ahead and create a registrations from tid_dest_list for the + * SPEC_I_PT provided TransportID for the *tidh referenced dest_node_acl + * and dest_se_deve. + * + * The SA Reservation Key from the PROUT is set for the + * registration, and ALL_TG_PT is also passed. ALL_TG_PT=1 + * means that the TransportID Initiator port will be + * registered on all of the target ports in the SCSI target device + * ALL_TG_PT=0 means the registration will only be for the + * SCSI target port the PROUT REGISTER with SPEC_I_PT=1 + * was received. + */ + list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) { + dest_tpg = tidh->dest_tpg; + dest_node_acl = tidh->dest_node_acl; + dest_se_deve = tidh->dest_se_deve; + dest_pr_reg = tidh->dest_pr_reg; + dest_local_nexus = tidh->dest_local_nexus; + + list_del(&tidh->dest_list); + kfree(tidh); + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + + __core_scsi3_add_registration(SE_DEV(cmd), dest_node_acl, + dest_pr_reg, 0, 0); + + printk(KERN_INFO "SPC-3 PR [%s] SPEC_I_PT: Successfully" + " registered Transport ID for Node: %s%s Mapped LUN:" + " %u\n", TPG_TFO(dest_tpg)->get_fabric_name(), + dest_node_acl->initiatorname, (prf_isid) ? + &i_buf[0] : "", dest_se_deve->mapped_lun); + + if (dest_local_nexus) + continue; + + core_scsi3_lunacl_undepend_item(dest_se_deve); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + } + + return 0; +out: + /* + * For the failure case, release everything from tid_dest_list + * including *dest_pr_reg and the configfs dependances.. + */ + list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) { + dest_tpg = tidh->dest_tpg; + dest_node_acl = tidh->dest_node_acl; + dest_se_deve = tidh->dest_se_deve; + dest_pr_reg = tidh->dest_pr_reg; + dest_local_nexus = tidh->dest_local_nexus; + + list_del(&tidh->dest_list); + kfree(tidh); + /* + * Release any extra ALL_TG_PT=1 registrations for + * the SPEC_I_PT=1 case. + */ + list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, + &dest_pr_reg->pr_reg_atp_list, + pr_reg_atp_mem_list) { + list_del(&pr_reg_tmp->pr_reg_atp_mem_list); + core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); + kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp); + } + + kfree(dest_pr_reg->pr_aptpl_buf); + kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); + + if (dest_local_nexus) + continue; + + core_scsi3_lunacl_undepend_item(dest_se_deve); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_tpg); + } + return ret; +} + +/* + * Called with struct se_device->dev_reservation_lock held + */ +static int __core_scsi3_update_aptpl_buf( + struct se_device *dev, + unsigned char *buf, + u32 pr_aptpl_buf_len, + int clear_aptpl_metadata) +{ + struct se_lun *lun; + struct se_portal_group *tpg; + struct se_subsystem_dev *su_dev = SU_DEV(dev); + struct t10_pr_registration *pr_reg; + unsigned char tmp[512], isid_buf[32]; + ssize_t len = 0; + int reg_count = 0; + + memset(buf, 0, pr_aptpl_buf_len); + /* + * Called to clear metadata once APTPL has been deactivated. + */ + if (clear_aptpl_metadata) { + snprintf(buf, pr_aptpl_buf_len, + "No Registrations or Reservations\n"); + return 0; + } + /* + * Walk the registration list.. + */ + spin_lock(&T10_RES(su_dev)->registration_lock); + list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list, + pr_reg_list) { + + tmp[0] = '\0'; + isid_buf[0] = '\0'; + tpg = pr_reg->pr_reg_nacl->se_tpg; + lun = pr_reg->pr_reg_tg_pt_lun; + /* + * Write out any ISID value to APTPL metadata that was included + * in the original registration. + */ + if (pr_reg->isid_present_at_reg) + snprintf(isid_buf, 32, "initiator_sid=%s\n", + pr_reg->pr_reg_isid); + /* + * Include special metadata if the pr_reg matches the + * reservation holder. + */ + if (dev->dev_pr_res_holder == pr_reg) { + snprintf(tmp, 512, "PR_REG_START: %d" + "\ninitiator_fabric=%s\n" + "initiator_node=%s\n%s" + "sa_res_key=%llu\n" + "res_holder=1\nres_type=%02x\n" + "res_scope=%02x\nres_all_tg_pt=%d\n" + "mapped_lun=%u\n", reg_count, + TPG_TFO(tpg)->get_fabric_name(), + pr_reg->pr_reg_nacl->initiatorname, isid_buf, + pr_reg->pr_res_key, pr_reg->pr_res_type, + pr_reg->pr_res_scope, pr_reg->pr_reg_all_tg_pt, + pr_reg->pr_res_mapped_lun); + } else { + snprintf(tmp, 512, "PR_REG_START: %d\n" + "initiator_fabric=%s\ninitiator_node=%s\n%s" + "sa_res_key=%llu\nres_holder=0\n" + "res_all_tg_pt=%d\nmapped_lun=%u\n", + reg_count, TPG_TFO(tpg)->get_fabric_name(), + pr_reg->pr_reg_nacl->initiatorname, isid_buf, + pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt, + pr_reg->pr_res_mapped_lun); + } + + if ((len + strlen(tmp) > pr_aptpl_buf_len)) { + printk(KERN_ERR "Unable to update renaming" + " APTPL metadata\n"); + spin_unlock(&T10_RES(su_dev)->registration_lock); + return -1; + } + len += sprintf(buf+len, "%s", tmp); + + /* + * Include information about the associated SCSI target port. + */ + snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n" + "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:" + " %d\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_wwn(tpg), + TPG_TFO(tpg)->tpg_get_tag(tpg), + lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); + + if ((len + strlen(tmp) > pr_aptpl_buf_len)) { + printk(KERN_ERR "Unable to update renaming" + " APTPL metadata\n"); + spin_unlock(&T10_RES(su_dev)->registration_lock); + return -1; + } + len += sprintf(buf+len, "%s", tmp); + reg_count++; + } + spin_unlock(&T10_RES(su_dev)->registration_lock); + + if (!(reg_count)) + len += sprintf(buf+len, "No Registrations or Reservations"); + + return 0; +} + +static int core_scsi3_update_aptpl_buf( + struct se_device *dev, + unsigned char *buf, + u32 pr_aptpl_buf_len, + int clear_aptpl_metadata) +{ + int ret; + + spin_lock(&dev->dev_reservation_lock); + ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, + clear_aptpl_metadata); + spin_unlock(&dev->dev_reservation_lock); + + return ret; +} + +/* + * Called with struct se_device->aptpl_file_mutex held + */ +static int __core_scsi3_write_aptpl_to_file( + struct se_device *dev, + unsigned char *buf, + u32 pr_aptpl_buf_len) +{ + struct t10_wwn *wwn = &SU_DEV(dev)->t10_wwn; + struct file *file; + struct iovec iov[1]; + mm_segment_t old_fs; + int flags = O_RDWR | O_CREAT | O_TRUNC; + char path[512]; + int ret; + + memset(iov, 0, sizeof(struct iovec)); + memset(path, 0, 512); + + if (strlen(&wwn->unit_serial[0]) > 512) { + printk(KERN_ERR "WWN value for struct se_device does not fit" + " into path buffer\n"); + return -1; + } + + snprintf(path, 512, "/var/target/pr/aptpl_%s", &wwn->unit_serial[0]); + file = filp_open(path, flags, 0600); + if (IS_ERR(file) || !file || !file->f_dentry) { + printk(KERN_ERR "filp_open(%s) for APTPL metadata" + " failed\n", path); + return -1; + } + + iov[0].iov_base = &buf[0]; + if (!(pr_aptpl_buf_len)) + iov[0].iov_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */ + else + iov[0].iov_len = pr_aptpl_buf_len; + + old_fs = get_fs(); + set_fs(get_ds()); + ret = vfs_writev(file, &iov[0], 1, &file->f_pos); + set_fs(old_fs); + + if (ret < 0) { + printk("Error writing APTPL metadata file: %s\n", path); + filp_close(file, NULL); + return -1; + } + filp_close(file, NULL); + + return 0; +} + +static int core_scsi3_update_and_write_aptpl( + struct se_device *dev, + unsigned char *in_buf, + u32 in_pr_aptpl_buf_len) +{ + unsigned char null_buf[64], *buf; + u32 pr_aptpl_buf_len; + int ret, clear_aptpl_metadata = 0; + /* + * Can be called with a NULL pointer from PROUT service action CLEAR + */ + if (!(in_buf)) { + memset(null_buf, 0, 64); + buf = &null_buf[0]; + /* + * This will clear the APTPL metadata to: + * "No Registrations or Reservations" status + */ + pr_aptpl_buf_len = 64; + clear_aptpl_metadata = 1; + } else { + buf = in_buf; + pr_aptpl_buf_len = in_pr_aptpl_buf_len; + } + + ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, + clear_aptpl_metadata); + if (ret != 0) + return -1; + /* + * __core_scsi3_write_aptpl_to_file() will call strlen() + * on the passed buf to determine pr_aptpl_buf_len. + */ + ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0); + if (ret != 0) + return -1; + + return ret; +} + +static int core_scsi3_emulate_pro_register( + struct se_cmd *cmd, + u64 res_key, + u64 sa_res_key, + int aptpl, + int all_tg_pt, + int spec_i_pt, + int ignore_key) +{ + struct se_session *se_sess = SE_SESS(cmd); + struct se_device *dev = SE_DEV(cmd); + struct se_dev_entry *se_deve; + struct se_lun *se_lun = SE_LUN(cmd); + struct se_portal_group *se_tpg; + struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + /* Used for APTPL metadata w/ UNREGISTER */ + unsigned char *pr_aptpl_buf = NULL; + unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; + int pr_holder = 0, ret = 0, type; + + if (!(se_sess) || !(se_lun)) { + printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + se_tpg = se_sess->se_tpg; + se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + + if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) { + memset(&isid_buf[0], 0, PR_REG_ISID_LEN); + TPG_TFO(se_tpg)->sess_get_initiator_sid(se_sess, &isid_buf[0], + PR_REG_ISID_LEN); + isid_ptr = &isid_buf[0]; + } + /* + * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47 + */ + pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); + if (!(pr_reg_e)) { + if (res_key) { + printk(KERN_WARNING "SPC-3 PR: Reservation Key non-zero" + " for SA REGISTER, returning CONFLICT\n"); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * Do nothing but return GOOD status. + */ + if (!(sa_res_key)) + return PYX_TRANSPORT_SENT_TO_TRANSPORT; + + if (!(spec_i_pt)) { + /* + * Perform the Service Action REGISTER on the Initiator + * Port Endpoint that the PRO was received from on the + * Logical Unit of the SCSI device server. + */ + ret = core_scsi3_alloc_registration(SE_DEV(cmd), + se_sess->se_node_acl, se_deve, isid_ptr, + sa_res_key, all_tg_pt, aptpl, + ignore_key, 0); + if (ret != 0) { + printk(KERN_ERR "Unable to allocate" + " struct t10_pr_registration\n"); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + } else { + /* + * Register both the Initiator port that received + * PROUT SA REGISTER + SPEC_I_PT=1 and extract SCSI + * TransportID from Parameter list and loop through + * fabric dependent parameter list while calling + * logic from of core_scsi3_alloc_registration() for + * each TransportID provided SCSI Initiator Port/Device + */ + ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, + isid_ptr, sa_res_key, all_tg_pt, aptpl); + if (ret != 0) + return ret; + } + /* + * Nothing left to do for the APTPL=0 case. + */ + if (!(aptpl)) { + pr_tmpl->pr_aptpl_active = 0; + core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0); + printk("SPC-3 PR: Set APTPL Bit Deactivated for" + " REGISTER\n"); + return 0; + } + /* + * Locate the newly allocated local I_T Nexus *pr_reg, and + * update the APTPL metadata information using its + * preallocated *pr_reg->pr_aptpl_buf. + */ + pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), + se_sess->se_node_acl, se_sess); + + ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd), + &pr_reg->pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) { + pr_tmpl->pr_aptpl_active = 1; + printk("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n"); + } + + core_scsi3_put_pr_reg(pr_reg); + return ret; + } else { + /* + * Locate the existing *pr_reg via struct se_node_acl pointers + */ + pr_reg = pr_reg_e; + type = pr_reg->pr_res_type; + + if (!(ignore_key)) { + if (res_key != pr_reg->pr_res_key) { + printk(KERN_ERR "SPC-3 PR REGISTER: Received" + " res_key: 0x%016Lx does not match" + " existing SA REGISTER res_key:" + " 0x%016Lx\n", res_key, + pr_reg->pr_res_key); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + } + if (spec_i_pt) { + printk(KERN_ERR "SPC-3 PR UNREGISTER: SPEC_I_PT" + " set while sa_res_key=0\n"); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + /* + * An existing ALL_TG_PT=1 registration being released + * must also set ALL_TG_PT=1 in the incoming PROUT. + */ + if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) { + printk(KERN_ERR "SPC-3 PR UNREGISTER: ALL_TG_PT=1" + " registration exists, but ALL_TG_PT=1 bit not" + " present in received PROUT\n"); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + /* + * Allocate APTPL metadata buffer used for UNREGISTER ops + */ + if (aptpl) { + pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, + GFP_KERNEL); + if (!(pr_aptpl_buf)) { + printk(KERN_ERR "Unable to allocate" + " pr_aptpl_buf\n"); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + } + /* + * sa_res_key=0 Unregister Reservation Key for registered I_T + * Nexus sa_res_key=1 Change Reservation Key for registered I_T + * Nexus. + */ + if (!(sa_res_key)) { + pr_holder = core_scsi3_check_implict_release( + SE_DEV(cmd), pr_reg); + if (pr_holder < 0) { + kfree(pr_aptpl_buf); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + + spin_lock(&pr_tmpl->registration_lock); + /* + * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port + * and matching pr_res_key. + */ + if (pr_reg->pr_reg_all_tg_pt) { + list_for_each_entry_safe(pr_reg_p, pr_reg_tmp, + &pr_tmpl->registration_list, + pr_reg_list) { + + if (!(pr_reg_p->pr_reg_all_tg_pt)) + continue; + + if (pr_reg_p->pr_res_key != res_key) + continue; + + if (pr_reg == pr_reg_p) + continue; + + if (strcmp(pr_reg->pr_reg_nacl->initiatorname, + pr_reg_p->pr_reg_nacl->initiatorname)) + continue; + + __core_scsi3_free_registration(dev, + pr_reg_p, NULL, 0); + } + } + /* + * Release the calling I_T Nexus registration now.. + */ + __core_scsi3_free_registration(SE_DEV(cmd), pr_reg, + NULL, 1); + /* + * From spc4r17, section 5.7.11.3 Unregistering + * + * If the persistent reservation is a registrants only + * type, the device server shall establish a unit + * attention condition for the initiator port associated + * with every registered I_T nexus except for the I_T + * nexus on which the PERSISTENT RESERVE OUT command was + * received, with the additional sense code set to + * RESERVATIONS RELEASED. + */ + if (pr_holder && + ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) || + (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) { + list_for_each_entry(pr_reg_p, + &pr_tmpl->registration_list, + pr_reg_list) { + + core_scsi3_ua_allocate( + pr_reg_p->pr_reg_nacl, + pr_reg_p->pr_res_mapped_lun, + 0x2A, + ASCQ_2AH_RESERVATIONS_RELEASED); + } + } + spin_unlock(&pr_tmpl->registration_lock); + + if (!(aptpl)) { + pr_tmpl->pr_aptpl_active = 0; + core_scsi3_update_and_write_aptpl(dev, NULL, 0); + printk("SPC-3 PR: Set APTPL Bit Deactivated" + " for UNREGISTER\n"); + return 0; + } + + ret = core_scsi3_update_and_write_aptpl(dev, + &pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) { + pr_tmpl->pr_aptpl_active = 1; + printk("SPC-3 PR: Set APTPL Bit Activated" + " for UNREGISTER\n"); + } + + kfree(pr_aptpl_buf); + return ret; + } else { + /* + * Increment PRgeneration counter for struct se_device" + * upon a successful REGISTER, see spc4r17 section 6.3.2 + * READ_KEYS service action. + */ + pr_reg->pr_res_generation = core_scsi3_pr_generation( + SE_DEV(cmd)); + pr_reg->pr_res_key = sa_res_key; + printk("SPC-3 PR [%s] REGISTER%s: Changed Reservation" + " Key for %s to: 0x%016Lx PRgeneration:" + " 0x%08x\n", CMD_TFO(cmd)->get_fabric_name(), + (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "", + pr_reg->pr_reg_nacl->initiatorname, + pr_reg->pr_res_key, pr_reg->pr_res_generation); + + if (!(aptpl)) { + pr_tmpl->pr_aptpl_active = 0; + core_scsi3_update_and_write_aptpl(dev, NULL, 0); + core_scsi3_put_pr_reg(pr_reg); + printk("SPC-3 PR: Set APTPL Bit Deactivated" + " for REGISTER\n"); + return 0; + } + + ret = core_scsi3_update_and_write_aptpl(dev, + &pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) { + pr_tmpl->pr_aptpl_active = 1; + printk("SPC-3 PR: Set APTPL Bit Activated" + " for REGISTER\n"); + } + + kfree(pr_aptpl_buf); + core_scsi3_put_pr_reg(pr_reg); + } + } + return 0; +} + +unsigned char *core_scsi3_pr_dump_type(int type) +{ + switch (type) { + case PR_TYPE_WRITE_EXCLUSIVE: + return "Write Exclusive Access"; + case PR_TYPE_EXCLUSIVE_ACCESS: + return "Exclusive Access"; + case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: + return "Write Exclusive Access, Registrants Only"; + case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: + return "Exclusive Access, Registrants Only"; + case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: + return "Write Exclusive Access, All Registrants"; + case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: + return "Exclusive Access, All Registrants"; + default: + break; + } + + return "Unknown SPC-3 PR Type"; +} + +static int core_scsi3_pro_reserve( + struct se_cmd *cmd, + struct se_device *dev, + int type, + int scope, + u64 res_key) +{ + struct se_session *se_sess = SE_SESS(cmd); + struct se_dev_entry *se_deve; + struct se_lun *se_lun = SE_LUN(cmd); + struct se_portal_group *se_tpg; + struct t10_pr_registration *pr_reg, *pr_res_holder; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + char i_buf[PR_REG_ISID_ID_LEN]; + int ret, prf_isid; + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + + if (!(se_sess) || !(se_lun)) { + printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + se_tpg = se_sess->se_tpg; + se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + /* + * Locate the existing *pr_reg via struct se_node_acl pointers + */ + pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl, + se_sess); + if (!(pr_reg)) { + printk(KERN_ERR "SPC-3 PR: Unable to locate" + " PR_REGISTERED *pr_reg for RESERVE\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + /* + * From spc4r17 Section 5.7.9: Reserving: + * + * An application client creates a persistent reservation by issuing + * a PERSISTENT RESERVE OUT command with RESERVE service action through + * a registered I_T nexus with the following parameters: + * a) RESERVATION KEY set to the value of the reservation key that is + * registered with the logical unit for the I_T nexus; and + */ + if (res_key != pr_reg->pr_res_key) { + printk(KERN_ERR "SPC-3 PR RESERVE: Received res_key: 0x%016Lx" + " does not match existing SA REGISTER res_key:" + " 0x%016Lx\n", res_key, pr_reg->pr_res_key); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * From spc4r17 Section 5.7.9: Reserving: + * + * From above: + * b) TYPE field and SCOPE field set to the persistent reservation + * being created. + * + * Only one persistent reservation is allowed at a time per logical unit + * and that persistent reservation has a scope of LU_SCOPE. + */ + if (scope != PR_SCOPE_LU_SCOPE) { + printk(KERN_ERR "SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + /* + * See if we have an existing PR reservation holder pointer at + * struct se_device->dev_pr_res_holder in the form struct t10_pr_registration + * *pr_res_holder. + */ + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if ((pr_res_holder)) { + /* + * From spc4r17 Section 5.7.9: Reserving: + * + * If the device server receives a PERSISTENT RESERVE OUT + * command from an I_T nexus other than a persistent reservation + * holder (see 5.7.10) that attempts to create a persistent + * reservation when a persistent reservation already exists for + * the logical unit, then the command shall be completed with + * RESERVATION CONFLICT status. + */ + if (pr_res_holder != pr_reg) { + struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; + printk(KERN_ERR "SPC-3 PR: Attempted RESERVE from" + " [%s]: %s while reservation already held by" + " [%s]: %s, returning RESERVATION_CONFLICT\n", + CMD_TFO(cmd)->get_fabric_name(), + se_sess->se_node_acl->initiatorname, + TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(), + pr_res_holder->pr_reg_nacl->initiatorname); + + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * From spc4r17 Section 5.7.9: Reserving: + * + * If a persistent reservation holder attempts to modify the + * type or scope of an existing persistent reservation, the + * command shall be completed with RESERVATION CONFLICT status. + */ + if ((pr_res_holder->pr_res_type != type) || + (pr_res_holder->pr_res_scope != scope)) { + struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; + printk(KERN_ERR "SPC-3 PR: Attempted RESERVE from" + " [%s]: %s trying to change TYPE and/or SCOPE," + " while reservation already held by [%s]: %s," + " returning RESERVATION_CONFLICT\n", + CMD_TFO(cmd)->get_fabric_name(), + se_sess->se_node_acl->initiatorname, + TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(), + pr_res_holder->pr_reg_nacl->initiatorname); + + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * From spc4r17 Section 5.7.9: Reserving: + * + * If the device server receives a PERSISTENT RESERVE OUT + * command with RESERVE service action where the TYPE field and + * the SCOPE field contain the same values as the existing type + * and scope from a persistent reservation holder, it shall not + * make any change to the existing persistent reservation and + * shall completethe command with GOOD status. + */ + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_SENT_TO_TRANSPORT; + } + /* + * Otherwise, our *pr_reg becomes the PR reservation holder for said + * TYPE/SCOPE. Also set the received scope and type in *pr_reg. + */ + pr_reg->pr_res_scope = scope; + pr_reg->pr_res_type = type; + pr_reg->pr_res_holder = 1; + dev->dev_pr_res_holder = pr_reg; + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: RESERVE created new" + " reservation holder TYPE: %s ALL_TG_PT: %d\n", + CMD_TFO(cmd)->get_fabric_name(), core_scsi3_pr_dump_type(type), + (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); + printk(KERN_INFO "SPC-3 PR [%s] RESERVE Node: %s%s\n", + CMD_TFO(cmd)->get_fabric_name(), + se_sess->se_node_acl->initiatorname, + (prf_isid) ? &i_buf[0] : ""); + spin_unlock(&dev->dev_reservation_lock); + + if (pr_tmpl->pr_aptpl_active) { + ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd), + &pr_reg->pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) + printk(KERN_INFO "SPC-3 PR: Updated APTPL metadata" + " for RESERVE\n"); + } + + core_scsi3_put_pr_reg(pr_reg); + return 0; +} + +static int core_scsi3_emulate_pro_reserve( + struct se_cmd *cmd, + int type, + int scope, + u64 res_key) +{ + struct se_device *dev = cmd->se_dev; + int ret = 0; + + switch (type) { + case PR_TYPE_WRITE_EXCLUSIVE: + case PR_TYPE_EXCLUSIVE_ACCESS: + case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: + case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: + case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: + case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: + ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key); + break; + default: + printk(KERN_ERR "SPC-3 PR: Unknown Service Action RESERVE Type:" + " 0x%02x\n", type); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + return ret; +} + +/* + * Called with struct se_device->dev_reservation_lock held. + */ +static void __core_scsi3_complete_pro_release( + struct se_device *dev, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int explict) +{ + struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; + char i_buf[PR_REG_ISID_ID_LEN]; + int prf_isid; + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + /* + * Go ahead and release the current PR reservation holder. + */ + dev->dev_pr_res_holder = NULL; + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: %s RELEASE cleared" + " reservation holder TYPE: %s ALL_TG_PT: %d\n", + tfo->get_fabric_name(), (explict) ? "explict" : "implict", + core_scsi3_pr_dump_type(pr_reg->pr_res_type), + (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); + printk(KERN_INFO "SPC-3 PR [%s] RELEASE Node: %s%s\n", + tfo->get_fabric_name(), se_nacl->initiatorname, + (prf_isid) ? &i_buf[0] : ""); + /* + * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE + */ + pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0; +} + +static int core_scsi3_emulate_pro_release( + struct se_cmd *cmd, + int type, + int scope, + u64 res_key) +{ + struct se_device *dev = cmd->se_dev; + struct se_session *se_sess = SE_SESS(cmd); + struct se_lun *se_lun = SE_LUN(cmd); + struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + int ret, all_reg = 0; + + if (!(se_sess) || !(se_lun)) { + printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + /* + * Locate the existing *pr_reg via struct se_node_acl pointers + */ + pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); + if (!(pr_reg)) { + printk(KERN_ERR "SPC-3 PR: Unable to locate" + " PR_REGISTERED *pr_reg for RELEASE\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + /* + * From spc4r17 Section 5.7.11.2 Releasing: + * + * If there is no persistent reservation or in response to a persistent + * reservation release request from a registered I_T nexus that is not a + * persistent reservation holder (see 5.7.10), the device server shall + * do the following: + * + * a) Not release the persistent reservation, if any; + * b) Not remove any registrations; and + * c) Complete the command with GOOD status. + */ + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if (!(pr_res_holder)) { + /* + * No persistent reservation, return GOOD status. + */ + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_SENT_TO_TRANSPORT; + } + if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || + (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) + all_reg = 1; + + if ((all_reg == 0) && (pr_res_holder != pr_reg)) { + /* + * Non 'All Registrants' PR Type cases.. + * Release request from a registered I_T nexus that is not a + * persistent reservation holder. return GOOD status. + */ + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_SENT_TO_TRANSPORT; + } + /* + * From spc4r17 Section 5.7.11.2 Releasing: + * + * Only the persistent reservation holder (see 5.7.10) is allowed to + * release a persistent reservation. + * + * An application client releases the persistent reservation by issuing + * a PERSISTENT RESERVE OUT command with RELEASE service action through + * an I_T nexus that is a persistent reservation holder with the + * following parameters: + * + * a) RESERVATION KEY field set to the value of the reservation key + * that is registered with the logical unit for the I_T nexus; + */ + if (res_key != pr_reg->pr_res_key) { + printk(KERN_ERR "SPC-3 PR RELEASE: Received res_key: 0x%016Lx" + " does not match existing SA REGISTER res_key:" + " 0x%016Lx\n", res_key, pr_reg->pr_res_key); + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * From spc4r17 Section 5.7.11.2 Releasing and above: + * + * b) TYPE field and SCOPE field set to match the persistent + * reservation being released. + */ + if ((pr_res_holder->pr_res_type != type) || + (pr_res_holder->pr_res_scope != scope)) { + struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; + printk(KERN_ERR "SPC-3 PR RELEASE: Attempted to release" + " reservation from [%s]: %s with different TYPE " + "and/or SCOPE while reservation already held by" + " [%s]: %s, returning RESERVATION_CONFLICT\n", + CMD_TFO(cmd)->get_fabric_name(), + se_sess->se_node_acl->initiatorname, + TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(), + pr_res_holder->pr_reg_nacl->initiatorname); + + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * In response to a persistent reservation release request from the + * persistent reservation holder the device server shall perform a + * release by doing the following as an uninterrupted series of actions: + * a) Release the persistent reservation; + * b) Not remove any registration(s); + * c) If the released persistent reservation is a registrants only type + * or all registrants type persistent reservation, + * the device server shall establish a unit attention condition for + * the initiator port associated with every regis- + * tered I_T nexus other than I_T nexus on which the PERSISTENT + * RESERVE OUT command with RELEASE service action was received, + * with the additional sense code set to RESERVATIONS RELEASED; and + * d) If the persistent reservation is of any other type, the device + * server shall not establish a unit attention condition. + */ + __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl, + pr_reg, 1); + + spin_unlock(&dev->dev_reservation_lock); + + if ((type != PR_TYPE_WRITE_EXCLUSIVE_REGONLY) && + (type != PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) && + (type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) && + (type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { + /* + * If no UNIT ATTENTION conditions will be established for + * PR_TYPE_WRITE_EXCLUSIVE or PR_TYPE_EXCLUSIVE_ACCESS + * go ahead and check for APTPL=1 update+write below + */ + goto write_aptpl; + } + + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list, + pr_reg_list) { + /* + * Do not establish a UNIT ATTENTION condition + * for the calling I_T Nexus + */ + if (pr_reg_p == pr_reg) + continue; + + core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl, + pr_reg_p->pr_res_mapped_lun, + 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED); + } + spin_unlock(&pr_tmpl->registration_lock); + +write_aptpl: + if (pr_tmpl->pr_aptpl_active) { + ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd), + &pr_reg->pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) + printk("SPC-3 PR: Updated APTPL metadata for RELEASE\n"); + } + + core_scsi3_put_pr_reg(pr_reg); + return 0; +} + +static int core_scsi3_emulate_pro_clear( + struct se_cmd *cmd, + u64 res_key) +{ + struct se_device *dev = cmd->se_dev; + struct se_node_acl *pr_reg_nacl; + struct se_session *se_sess = SE_SESS(cmd); + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; + u32 pr_res_mapped_lun = 0; + int calling_it_nexus = 0; + /* + * Locate the existing *pr_reg via struct se_node_acl pointers + */ + pr_reg_n = core_scsi3_locate_pr_reg(SE_DEV(cmd), + se_sess->se_node_acl, se_sess); + if (!(pr_reg_n)) { + printk(KERN_ERR "SPC-3 PR: Unable to locate" + " PR_REGISTERED *pr_reg for CLEAR\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + /* + * From spc4r17 section 5.7.11.6, Clearing: + * + * Any application client may release the persistent reservation and + * remove all registrations from a device server by issuing a + * PERSISTENT RESERVE OUT command with CLEAR service action through a + * registered I_T nexus with the following parameter: + * + * a) RESERVATION KEY field set to the value of the reservation key + * that is registered with the logical unit for the I_T nexus. + */ + if (res_key != pr_reg_n->pr_res_key) { + printk(KERN_ERR "SPC-3 PR REGISTER: Received" + " res_key: 0x%016Lx does not match" + " existing SA REGISTER res_key:" + " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key); + core_scsi3_put_pr_reg(pr_reg_n); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * a) Release the persistent reservation, if any; + */ + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if (pr_res_holder) { + struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; + __core_scsi3_complete_pro_release(dev, pr_res_nacl, + pr_res_holder, 0); + } + spin_unlock(&dev->dev_reservation_lock); + /* + * b) Remove all registration(s) (see spc4r17 5.7.7); + */ + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + + calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; + pr_reg_nacl = pr_reg->pr_reg_nacl; + pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; + __core_scsi3_free_registration(dev, pr_reg, NULL, + calling_it_nexus); + /* + * e) Establish a unit attention condition for the initiator + * port associated with every registered I_T nexus other + * than the I_T nexus on which the PERSISTENT RESERVE OUT + * command with CLEAR service action was received, with the + * additional sense code set to RESERVATIONS PREEMPTED. + */ + if (!(calling_it_nexus)) + core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, + 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED); + } + spin_unlock(&pr_tmpl->registration_lock); + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: CLEAR complete\n", + CMD_TFO(cmd)->get_fabric_name()); + + if (pr_tmpl->pr_aptpl_active) { + core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0); + printk(KERN_INFO "SPC-3 PR: Updated APTPL metadata" + " for CLEAR\n"); + } + + core_scsi3_pr_generation(dev); + return 0; +} + +/* + * Called with struct se_device->dev_reservation_lock held. + */ +static void __core_scsi3_complete_pro_preempt( + struct se_device *dev, + struct t10_pr_registration *pr_reg, + struct list_head *preempt_and_abort_list, + int type, + int scope, + int abort) +{ + struct se_node_acl *nacl = pr_reg->pr_reg_nacl; + struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + char i_buf[PR_REG_ISID_ID_LEN]; + int prf_isid; + + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + /* + * Do an implict RELEASE of the existing reservation. + */ + if (dev->dev_pr_res_holder) + __core_scsi3_complete_pro_release(dev, nacl, + dev->dev_pr_res_holder, 0); + + dev->dev_pr_res_holder = pr_reg; + pr_reg->pr_res_holder = 1; + pr_reg->pr_res_type = type; + pr_reg->pr_res_scope = scope; + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: PREEMPT%s created new" + " reservation holder TYPE: %s ALL_TG_PT: %d\n", + tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", + core_scsi3_pr_dump_type(type), + (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); + printk(KERN_INFO "SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n", + tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", + nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); + /* + * For PREEMPT_AND_ABORT, add the preempting reservation's + * struct t10_pr_registration to the list that will be compared + * against received CDBs.. + */ + if (preempt_and_abort_list) + list_add_tail(&pr_reg->pr_reg_abort_list, + preempt_and_abort_list); +} + +static void core_scsi3_release_preempt_and_abort( + struct list_head *preempt_and_abort_list, + struct t10_pr_registration *pr_reg_holder) +{ + struct t10_pr_registration *pr_reg, *pr_reg_tmp; + + list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list, + pr_reg_abort_list) { + + list_del(&pr_reg->pr_reg_abort_list); + if (pr_reg_holder == pr_reg) + continue; + if (pr_reg->pr_res_holder) { + printk(KERN_WARNING "pr_reg->pr_res_holder still set\n"); + continue; + } + + pr_reg->pr_reg_deve = NULL; + pr_reg->pr_reg_nacl = NULL; + kfree(pr_reg->pr_aptpl_buf); + kmem_cache_free(t10_pr_reg_cache, pr_reg); + } +} + +int core_scsi3_check_cdb_abort_and_preempt( + struct list_head *preempt_and_abort_list, + struct se_cmd *cmd) +{ + struct t10_pr_registration *pr_reg, *pr_reg_tmp; + + list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list, + pr_reg_abort_list) { + if (pr_reg->pr_res_key == cmd->pr_res_key) + return 0; + } + + return 1; +} + +static int core_scsi3_pro_preempt( + struct se_cmd *cmd, + int type, + int scope, + u64 res_key, + u64 sa_res_key, + int abort) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_dev_entry *se_deve; + struct se_node_acl *pr_reg_nacl; + struct se_session *se_sess = SE_SESS(cmd); + struct list_head preempt_and_abort_list; + struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + u32 pr_res_mapped_lun = 0; + int all_reg = 0, calling_it_nexus = 0, released_regs = 0; + int prh_type = 0, prh_scope = 0, ret; + + if (!(se_sess)) + return PYX_TRANSPORT_LU_COMM_FAILURE; + + se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + pr_reg_n = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl, + se_sess); + if (!(pr_reg_n)) { + printk(KERN_ERR "SPC-3 PR: Unable to locate" + " PR_REGISTERED *pr_reg for PREEMPT%s\n", + (abort) ? "_AND_ABORT" : ""); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + if (pr_reg_n->pr_res_key != res_key) { + core_scsi3_put_pr_reg(pr_reg_n); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + if (scope != PR_SCOPE_LU_SCOPE) { + printk(KERN_ERR "SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); + core_scsi3_put_pr_reg(pr_reg_n); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + INIT_LIST_HEAD(&preempt_and_abort_list); + + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if (pr_res_holder && + ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || + (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))) + all_reg = 1; + + if (!(all_reg) && !(sa_res_key)) { + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg_n); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + /* + * From spc4r17, section 5.7.11.4.4 Removing Registrations: + * + * If the SERVICE ACTION RESERVATION KEY field does not identify a + * persistent reservation holder or there is no persistent reservation + * holder (i.e., there is no persistent reservation), then the device + * server shall perform a preempt by doing the following in an + * uninterrupted series of actions. (See below..) + */ + if (!(pr_res_holder) || (pr_res_holder->pr_res_key != sa_res_key)) { + /* + * No existing or SA Reservation Key matching reservations.. + * + * PROUT SA PREEMPT with All Registrant type reservations are + * allowed to be processed without a matching SA Reservation Key + */ + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + /* + * Removing of registrations in non all registrants + * type reservations without a matching SA reservation + * key. + * + * a) Remove the registrations for all I_T nexuses + * specified by the SERVICE ACTION RESERVATION KEY + * field; + * b) Ignore the contents of the SCOPE and TYPE fields; + * c) Process tasks as defined in 5.7.1; and + * d) Establish a unit attention condition for the + * initiator port associated with every I_T nexus + * that lost its registration other than the I_T + * nexus on which the PERSISTENT RESERVE OUT command + * was received, with the additional sense code set + * to REGISTRATIONS PREEMPTED. + */ + if (!(all_reg)) { + if (pr_reg->pr_res_key != sa_res_key) + continue; + + calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; + pr_reg_nacl = pr_reg->pr_reg_nacl; + pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; + __core_scsi3_free_registration(dev, pr_reg, + (abort) ? &preempt_and_abort_list : + NULL, calling_it_nexus); + released_regs++; + } else { + /* + * Case for any existing all registrants type + * reservation, follow logic in spc4r17 section + * 5.7.11.4 Preempting, Table 52 and Figure 7. + * + * For a ZERO SA Reservation key, release + * all other registrations and do an implict + * release of active persistent reservation. + * + * For a non-ZERO SA Reservation key, only + * release the matching reservation key from + * registrations. + */ + if ((sa_res_key) && + (pr_reg->pr_res_key != sa_res_key)) + continue; + + calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; + if (calling_it_nexus) + continue; + + pr_reg_nacl = pr_reg->pr_reg_nacl; + pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; + __core_scsi3_free_registration(dev, pr_reg, + (abort) ? &preempt_and_abort_list : + NULL, 0); + released_regs++; + } + if (!(calling_it_nexus)) + core_scsi3_ua_allocate(pr_reg_nacl, + pr_res_mapped_lun, 0x2A, + ASCQ_2AH_RESERVATIONS_PREEMPTED); + } + spin_unlock(&pr_tmpl->registration_lock); + /* + * If a PERSISTENT RESERVE OUT with a PREEMPT service action or + * a PREEMPT AND ABORT service action sets the SERVICE ACTION + * RESERVATION KEY field to a value that does not match any + * registered reservation key, then the device server shall + * complete the command with RESERVATION CONFLICT status. + */ + if (!(released_regs)) { + spin_unlock(&dev->dev_reservation_lock); + core_scsi3_put_pr_reg(pr_reg_n); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * For an existing all registrants type reservation + * with a zero SA rservation key, preempt the existing + * reservation with the new PR type and scope. + */ + if (pr_res_holder && all_reg && !(sa_res_key)) { + __core_scsi3_complete_pro_preempt(dev, pr_reg_n, + (abort) ? &preempt_and_abort_list : NULL, + type, scope, abort); + + if (abort) + core_scsi3_release_preempt_and_abort( + &preempt_and_abort_list, pr_reg_n); + } + spin_unlock(&dev->dev_reservation_lock); + + if (pr_tmpl->pr_aptpl_active) { + ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd), + &pr_reg_n->pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) + printk(KERN_INFO "SPC-3 PR: Updated APTPL" + " metadata for PREEMPT%s\n", (abort) ? + "_AND_ABORT" : ""); + } + + core_scsi3_put_pr_reg(pr_reg_n); + core_scsi3_pr_generation(SE_DEV(cmd)); + return 0; + } + /* + * The PREEMPTing SA reservation key matches that of the + * existing persistent reservation, first, we check if + * we are preempting our own reservation. + * From spc4r17, section 5.7.11.4.3 Preempting + * persistent reservations and registration handling + * + * If an all registrants persistent reservation is not + * present, it is not an error for the persistent + * reservation holder to preempt itself (i.e., a + * PERSISTENT RESERVE OUT with a PREEMPT service action + * or a PREEMPT AND ABORT service action with the + * SERVICE ACTION RESERVATION KEY value equal to the + * persistent reservation holder's reservation key that + * is received from the persistent reservation holder). + * In that case, the device server shall establish the + * new persistent reservation and maintain the + * registration. + */ + prh_type = pr_res_holder->pr_res_type; + prh_scope = pr_res_holder->pr_res_scope; + /* + * If the SERVICE ACTION RESERVATION KEY field identifies a + * persistent reservation holder (see 5.7.10), the device + * server shall perform a preempt by doing the following as + * an uninterrupted series of actions: + * + * a) Release the persistent reservation for the holder + * identified by the SERVICE ACTION RESERVATION KEY field; + */ + if (pr_reg_n != pr_res_holder) + __core_scsi3_complete_pro_release(dev, + pr_res_holder->pr_reg_nacl, + dev->dev_pr_res_holder, 0); + /* + * b) Remove the registrations for all I_T nexuses identified + * by the SERVICE ACTION RESERVATION KEY field, except the + * I_T nexus that is being used for the PERSISTENT RESERVE + * OUT command. If an all registrants persistent reservation + * is present and the SERVICE ACTION RESERVATION KEY field + * is set to zero, then all registrations shall be removed + * except for that of the I_T nexus that is being used for + * the PERSISTENT RESERVE OUT command; + */ + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + + calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; + if (calling_it_nexus) + continue; + + if (pr_reg->pr_res_key != sa_res_key) + continue; + + pr_reg_nacl = pr_reg->pr_reg_nacl; + pr_res_mapped_lun = pr_reg->pr_res_mapped_lun; + __core_scsi3_free_registration(dev, pr_reg, + (abort) ? &preempt_and_abort_list : NULL, + calling_it_nexus); + /* + * e) Establish a unit attention condition for the initiator + * port associated with every I_T nexus that lost its + * persistent reservation and/or registration, with the + * additional sense code set to REGISTRATIONS PREEMPTED; + */ + core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, + ASCQ_2AH_RESERVATIONS_PREEMPTED); + } + spin_unlock(&pr_tmpl->registration_lock); + /* + * c) Establish a persistent reservation for the preempting + * I_T nexus using the contents of the SCOPE and TYPE fields; + */ + __core_scsi3_complete_pro_preempt(dev, pr_reg_n, + (abort) ? &preempt_and_abort_list : NULL, + type, scope, abort); + /* + * d) Process tasks as defined in 5.7.1; + * e) See above.. + * f) If the type or scope has changed, then for every I_T nexus + * whose reservation key was not removed, except for the I_T + * nexus on which the PERSISTENT RESERVE OUT command was + * received, the device server shall establish a unit + * attention condition for the initiator port associated with + * that I_T nexus, with the additional sense code set to + * RESERVATIONS RELEASED. If the type or scope have not + * changed, then no unit attention condition(s) shall be + * established for this reason. + */ + if ((prh_type != type) || (prh_scope != scope)) { + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + + calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0; + if (calling_it_nexus) + continue; + + core_scsi3_ua_allocate(pr_reg->pr_reg_nacl, + pr_reg->pr_res_mapped_lun, 0x2A, + ASCQ_2AH_RESERVATIONS_RELEASED); + } + spin_unlock(&pr_tmpl->registration_lock); + } + spin_unlock(&dev->dev_reservation_lock); + /* + * Call LUN_RESET logic upon list of struct t10_pr_registration, + * All received CDBs for the matching existing reservation and + * registrations undergo ABORT_TASK logic. + * + * From there, core_scsi3_release_preempt_and_abort() will + * release every registration in the list (which have already + * been removed from the primary pr_reg list), except the + * new persistent reservation holder, the calling Initiator Port. + */ + if (abort) { + core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd); + core_scsi3_release_preempt_and_abort(&preempt_and_abort_list, + pr_reg_n); + } + + if (pr_tmpl->pr_aptpl_active) { + ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd), + &pr_reg_n->pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) + printk("SPC-3 PR: Updated APTPL metadata for PREEMPT" + "%s\n", (abort) ? "_AND_ABORT" : ""); + } + + core_scsi3_put_pr_reg(pr_reg_n); + core_scsi3_pr_generation(SE_DEV(cmd)); + return 0; +} + +static int core_scsi3_emulate_pro_preempt( + struct se_cmd *cmd, + int type, + int scope, + u64 res_key, + u64 sa_res_key, + int abort) +{ + int ret = 0; + + switch (type) { + case PR_TYPE_WRITE_EXCLUSIVE: + case PR_TYPE_EXCLUSIVE_ACCESS: + case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: + case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY: + case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: + case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG: + ret = core_scsi3_pro_preempt(cmd, type, scope, + res_key, sa_res_key, abort); + break; + default: + printk(KERN_ERR "SPC-3 PR: Unknown Service Action PREEMPT%s" + " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + return ret; +} + + +static int core_scsi3_emulate_pro_register_and_move( + struct se_cmd *cmd, + u64 res_key, + u64 sa_res_key, + int aptpl, + int unreg) +{ + struct se_session *se_sess = SE_SESS(cmd); + struct se_device *dev = SE_DEV(cmd); + struct se_dev_entry *se_deve, *dest_se_deve = NULL; + struct se_lun *se_lun = SE_LUN(cmd); + struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; + struct se_port *se_port; + struct se_portal_group *se_tpg, *dest_se_tpg = NULL; + struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; + struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + unsigned char *initiator_str; + char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN]; + u32 tid_len, tmp_tid_len; + int new_reg = 0, type, scope, ret, matching_iname, prf_isid; + unsigned short rtpi; + unsigned char proto_ident; + + if (!(se_sess) || !(se_lun)) { + printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + memset(dest_iport, 0, 64); + memset(i_buf, 0, PR_REG_ISID_ID_LEN); + se_tpg = se_sess->se_tpg; + tf_ops = TPG_TFO(se_tpg); + se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + /* + * Follow logic from spc4r17 Section 5.7.8, Table 50 -- + * Register behaviors for a REGISTER AND MOVE service action + * + * Locate the existing *pr_reg via struct se_node_acl pointers + */ + pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl, + se_sess); + if (!(pr_reg)) { + printk(KERN_ERR "SPC-3 PR: Unable to locate PR_REGISTERED" + " *pr_reg for REGISTER_AND_MOVE\n"); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + /* + * The provided reservation key much match the existing reservation key + * provided during this initiator's I_T nexus registration. + */ + if (res_key != pr_reg->pr_res_key) { + printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Received" + " res_key: 0x%016Lx does not match existing SA REGISTER" + " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + /* + * The service active reservation key needs to be non zero + */ + if (!(sa_res_key)) { + printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Received zero" + " sa_res_key\n"); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + /* + * Determine the Relative Target Port Identifier where the reservation + * will be moved to for the TransportID containing SCSI initiator WWN + * information. + */ + rtpi = (buf[18] & 0xff) << 8; + rtpi |= buf[19] & 0xff; + tid_len = (buf[20] & 0xff) << 24; + tid_len |= (buf[21] & 0xff) << 16; + tid_len |= (buf[22] & 0xff) << 8; + tid_len |= buf[23] & 0xff; + + if ((tid_len + 24) != cmd->data_length) { + printk(KERN_ERR "SPC-3 PR: Illegal tid_len: %u + 24 byte header" + " does not equal CDB data_length: %u\n", tid_len, + cmd->data_length); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + + spin_lock(&dev->se_port_lock); + list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) { + if (se_port->sep_rtpi != rtpi) + continue; + dest_se_tpg = se_port->sep_tpg; + if (!(dest_se_tpg)) + continue; + dest_tf_ops = TPG_TFO(dest_se_tpg); + if (!(dest_tf_ops)) + continue; + + atomic_inc(&dest_se_tpg->tpg_pr_ref_count); + smp_mb__after_atomic_inc(); + spin_unlock(&dev->se_port_lock); + + ret = core_scsi3_tpg_depend_item(dest_se_tpg); + if (ret != 0) { + printk(KERN_ERR "core_scsi3_tpg_depend_item() failed" + " for dest_se_tpg\n"); + atomic_dec(&dest_se_tpg->tpg_pr_ref_count); + smp_mb__after_atomic_dec(); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + + spin_lock(&dev->se_port_lock); + break; + } + spin_unlock(&dev->se_port_lock); + + if (!(dest_se_tpg) || (!dest_tf_ops)) { + printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Unable to locate" + " fabric ops from Relative Target Port Identifier:" + " %hu\n", rtpi); + core_scsi3_put_pr_reg(pr_reg); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + proto_ident = (buf[24] & 0x0f); +#if 0 + printk("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" + " 0x%02x\n", proto_ident); +#endif + if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) { + printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Received" + " proto_ident: 0x%02x does not match ident: 0x%02x" + " from fabric: %s\n", proto_ident, + dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), + dest_tf_ops->get_fabric_name()); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { + printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Fabric does not" + " containg a valid tpg_parse_pr_out_transport_id" + " function pointer\n"); + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } + initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, + (const char *)&buf[24], &tmp_tid_len, &iport_ptr); + if (!(initiator_str)) { + printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Unable to locate" + " initiator_str from Transport ID\n"); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + + printk(KERN_INFO "SPC-3 PR [%s] Extracted initiator %s identifier: %s" + " %s\n", dest_tf_ops->get_fabric_name(), (iport_ptr != NULL) ? + "port" : "device", initiator_str, (iport_ptr != NULL) ? + iport_ptr : ""); + /* + * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service + * action specifies a TransportID that is the same as the initiator port + * of the I_T nexus for the command received, then the command shall + * be terminated with CHECK CONDITION status, with the sense key set to + * ILLEGAL REQUEST, and the additional sense code set to INVALID FIELD + * IN PARAMETER LIST. + */ + pr_reg_nacl = pr_reg->pr_reg_nacl; + matching_iname = (!strcmp(initiator_str, + pr_reg_nacl->initiatorname)) ? 1 : 0; + if (!(matching_iname)) + goto after_iport_check; + + if (!(iport_ptr) || !(pr_reg->isid_present_at_reg)) { + printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: TransportID: %s" + " matches: %s on received I_T Nexus\n", initiator_str, + pr_reg_nacl->initiatorname); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + if (!(strcmp(iport_ptr, pr_reg->pr_reg_isid))) { + printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: TransportID: %s %s" + " matches: %s %s on received I_T Nexus\n", + initiator_str, iport_ptr, pr_reg_nacl->initiatorname, + pr_reg->pr_reg_isid); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } +after_iport_check: + /* + * Locate the destination struct se_node_acl from the received Transport ID + */ + spin_lock_bh(&dest_se_tpg->acl_node_lock); + dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg, + initiator_str); + if (dest_node_acl) { + atomic_inc(&dest_node_acl->acl_pr_ref_count); + smp_mb__after_atomic_inc(); + } + spin_unlock_bh(&dest_se_tpg->acl_node_lock); + + if (!(dest_node_acl)) { + printk(KERN_ERR "Unable to locate %s dest_node_acl for" + " TransportID%s\n", dest_tf_ops->get_fabric_name(), + initiator_str); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + ret = core_scsi3_nodeacl_depend_item(dest_node_acl); + if (ret != 0) { + printk(KERN_ERR "core_scsi3_nodeacl_depend_item() for" + " dest_node_acl\n"); + atomic_dec(&dest_node_acl->acl_pr_ref_count); + smp_mb__after_atomic_dec(); + dest_node_acl = NULL; + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } +#if 0 + printk(KERN_INFO "SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:" + " %s from TransportID\n", dest_tf_ops->get_fabric_name(), + dest_node_acl->initiatorname); +#endif + /* + * Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET + * PORT IDENTIFIER. + */ + dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, rtpi); + if (!(dest_se_deve)) { + printk(KERN_ERR "Unable to locate %s dest_se_deve from RTPI:" + " %hu\n", dest_tf_ops->get_fabric_name(), rtpi); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + + ret = core_scsi3_lunacl_depend_item(dest_se_deve); + if (ret < 0) { + printk(KERN_ERR "core_scsi3_lunacl_depend_item() failed\n"); + atomic_dec(&dest_se_deve->pr_ref_count); + smp_mb__after_atomic_dec(); + dest_se_deve = NULL; + ret = PYX_TRANSPORT_LU_COMM_FAILURE; + goto out; + } +#if 0 + printk(KERN_INFO "SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN" + " ACL for dest_se_deve->mapped_lun: %u\n", + dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname, + dest_se_deve->mapped_lun); +#endif + /* + * A persistent reservation needs to already existing in order to + * successfully complete the REGISTER_AND_MOVE service action.. + */ + spin_lock(&dev->dev_reservation_lock); + pr_res_holder = dev->dev_pr_res_holder; + if (!(pr_res_holder)) { + printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: No reservation" + " currently held\n"); + spin_unlock(&dev->dev_reservation_lock); + ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + goto out; + } + /* + * The received on I_T Nexus must be the reservation holder. + * + * From spc4r17 section 5.7.8 Table 50 -- + * Register behaviors for a REGISTER AND MOVE service action + */ + if (pr_res_holder != pr_reg) { + printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Calling I_T" + " Nexus is not reservation holder\n"); + spin_unlock(&dev->dev_reservation_lock); + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out; + } + /* + * From spc4r17 section 5.7.8: registering and moving reservation + * + * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service + * action is received and the established persistent reservation is a + * Write Exclusive - All Registrants type or Exclusive Access - + * All Registrants type reservation, then the command shall be completed + * with RESERVATION CONFLICT status. + */ + if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || + (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) { + printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Unable to move" + " reservation for type: %s\n", + core_scsi3_pr_dump_type(pr_res_holder->pr_res_type)); + spin_unlock(&dev->dev_reservation_lock); + ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + goto out; + } + pr_res_nacl = pr_res_holder->pr_reg_nacl; + /* + * b) Ignore the contents of the (received) SCOPE and TYPE fields; + */ + type = pr_res_holder->pr_res_type; + scope = pr_res_holder->pr_res_type; + /* + * c) Associate the reservation key specified in the SERVICE ACTION + * RESERVATION KEY field with the I_T nexus specified as the + * destination of the register and move, where: + * A) The I_T nexus is specified by the TransportID and the + * RELATIVE TARGET PORT IDENTIFIER field (see 6.14.4); and + * B) Regardless of the TransportID format used, the association for + * the initiator port is based on either the initiator port name + * (see 3.1.71) on SCSI transport protocols where port names are + * required or the initiator port identifier (see 3.1.70) on SCSI + * transport protocols where port names are not required; + * d) Register the reservation key specified in the SERVICE ACTION + * RESERVATION KEY field; + * e) Retain the reservation key specified in the SERVICE ACTION + * RESERVATION KEY field and associated information; + * + * Also, It is not an error for a REGISTER AND MOVE service action to + * register an I_T nexus that is already registered with the same + * reservation key or a different reservation key. + */ + dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, + iport_ptr); + if (!(dest_pr_reg)) { + ret = core_scsi3_alloc_registration(SE_DEV(cmd), + dest_node_acl, dest_se_deve, iport_ptr, + sa_res_key, 0, aptpl, 2, 1); + if (ret != 0) { + spin_unlock(&dev->dev_reservation_lock); + ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + goto out; + } + dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, + iport_ptr); + new_reg = 1; + } + /* + * f) Release the persistent reservation for the persistent reservation + * holder (i.e., the I_T nexus on which the + */ + __core_scsi3_complete_pro_release(dev, pr_res_nacl, + dev->dev_pr_res_holder, 0); + /* + * g) Move the persistent reservation to the specified I_T nexus using + * the same scope and type as the persistent reservation released in + * item f); and + */ + dev->dev_pr_res_holder = dest_pr_reg; + dest_pr_reg->pr_res_holder = 1; + dest_pr_reg->pr_res_type = type; + pr_reg->pr_res_scope = scope; + prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], + PR_REG_ISID_ID_LEN); + /* + * Increment PRGeneration for existing registrations.. + */ + if (!(new_reg)) + dest_pr_reg->pr_res_generation = pr_tmpl->pr_generation++; + spin_unlock(&dev->dev_reservation_lock); + + printk(KERN_INFO "SPC-3 PR [%s] Service Action: REGISTER_AND_MOVE" + " created new reservation holder TYPE: %s on object RTPI:" + " %hu PRGeneration: 0x%08x\n", dest_tf_ops->get_fabric_name(), + core_scsi3_pr_dump_type(type), rtpi, + dest_pr_reg->pr_res_generation); + printk(KERN_INFO "SPC-3 PR Successfully moved reservation from" + " %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n", + tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname, + (prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(), + dest_node_acl->initiatorname, (iport_ptr != NULL) ? + iport_ptr : ""); + /* + * It is now safe to release configfs group dependencies for destination + * of Transport ID Initiator Device/Port Identifier + */ + core_scsi3_lunacl_undepend_item(dest_se_deve); + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_se_tpg); + /* + * h) If the UNREG bit is set to one, unregister (see 5.7.11.3) the I_T + * nexus on which PERSISTENT RESERVE OUT command was received. + */ + if (unreg) { + spin_lock(&pr_tmpl->registration_lock); + __core_scsi3_free_registration(dev, pr_reg, NULL, 1); + spin_unlock(&pr_tmpl->registration_lock); + } else + core_scsi3_put_pr_reg(pr_reg); + + /* + * Clear the APTPL metadata if APTPL has been disabled, otherwise + * write out the updated metadata to struct file for this SCSI device. + */ + if (!(aptpl)) { + pr_tmpl->pr_aptpl_active = 0; + core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0); + printk("SPC-3 PR: Set APTPL Bit Deactivated for" + " REGISTER_AND_MOVE\n"); + } else { + pr_tmpl->pr_aptpl_active = 1; + ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd), + &dest_pr_reg->pr_aptpl_buf[0], + pr_tmpl->pr_aptpl_buf_len); + if (!(ret)) + printk("SPC-3 PR: Set APTPL Bit Activated for" + " REGISTER_AND_MOVE\n"); + } + + core_scsi3_put_pr_reg(dest_pr_reg); + return 0; +out: + if (dest_se_deve) + core_scsi3_lunacl_undepend_item(dest_se_deve); + if (dest_node_acl) + core_scsi3_nodeacl_undepend_item(dest_node_acl); + core_scsi3_tpg_undepend_item(dest_se_tpg); + core_scsi3_put_pr_reg(pr_reg); + return ret; +} + +static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3]; + __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +/* + * See spc4r17 section 6.14 Table 170 + */ +static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) +{ + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + u64 res_key, sa_res_key; + int sa, scope, type, aptpl; + int spec_i_pt = 0, all_tg_pt = 0, unreg = 0; + /* + * FIXME: A NULL struct se_session pointer means an this is not coming from + * a $FABRIC_MOD's nexus, but from internal passthrough ops. + */ + if (!(SE_SESS(cmd))) + return PYX_TRANSPORT_LU_COMM_FAILURE; + + if (cmd->data_length < 24) { + printk(KERN_WARNING "SPC-PR: Recieved PR OUT parameter list" + " length too small: %u\n", cmd->data_length); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + /* + * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB) + */ + sa = (cdb[1] & 0x1f); + scope = (cdb[2] & 0xf0); + type = (cdb[2] & 0x0f); + /* + * From PERSISTENT_RESERVE_OUT parameter list (payload) + */ + res_key = core_scsi3_extract_reservation_key(&buf[0]); + sa_res_key = core_scsi3_extract_reservation_key(&buf[8]); + /* + * REGISTER_AND_MOVE uses a different SA parameter list containing + * SCSI TransportIDs. + */ + if (sa != PRO_REGISTER_AND_MOVE) { + spec_i_pt = (buf[20] & 0x08); + all_tg_pt = (buf[20] & 0x04); + aptpl = (buf[20] & 0x01); + } else { + aptpl = (buf[17] & 0x01); + unreg = (buf[17] & 0x02); + } + /* + * SPEC_I_PT=1 is only valid for Service action: REGISTER + */ + if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + /* + * From spc4r17 section 6.14: + * + * If the SPEC_I_PT bit is set to zero, the service action is not + * REGISTER AND MOVE, and the parameter list length is not 24, then + * the command shall be terminated with CHECK CONDITION status, with + * the sense key set to ILLEGAL REQUEST, and the additional sense + * code set to PARAMETER LIST LENGTH ERROR. + */ + if (!(spec_i_pt) && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && + (cmd->data_length != 24)) { + printk(KERN_WARNING "SPC-PR: Recieved PR OUT illegal parameter" + " list length: %u\n", cmd->data_length); + return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + } + /* + * (core_scsi3_emulate_pro_* function parameters + * are defined by spc4r17 Table 174: + * PERSISTENT_RESERVE_OUT service actions and valid parameters. + */ + switch (sa) { + case PRO_REGISTER: + return core_scsi3_emulate_pro_register(cmd, + res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); + case PRO_RESERVE: + return core_scsi3_emulate_pro_reserve(cmd, + type, scope, res_key); + case PRO_RELEASE: + return core_scsi3_emulate_pro_release(cmd, + type, scope, res_key); + case PRO_CLEAR: + return core_scsi3_emulate_pro_clear(cmd, res_key); + case PRO_PREEMPT: + return core_scsi3_emulate_pro_preempt(cmd, type, scope, + res_key, sa_res_key, 0); + case PRO_PREEMPT_AND_ABORT: + return core_scsi3_emulate_pro_preempt(cmd, type, scope, + res_key, sa_res_key, 1); + case PRO_REGISTER_AND_IGNORE_EXISTING_KEY: + return core_scsi3_emulate_pro_register(cmd, + 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); + case PRO_REGISTER_AND_MOVE: + return core_scsi3_emulate_pro_register_and_move(cmd, res_key, + sa_res_key, aptpl, unreg); + default: + printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service" + " action: 0x%02x\n", cdb[1] & 0x1f); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + return PYX_TRANSPORT_INVALID_CDB_FIELD; +} + +/* + * PERSISTENT_RESERVE_IN Service Action READ_KEYS + * + * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160 + */ +static int core_scsi3_pri_read_keys(struct se_cmd *cmd) +{ + struct se_device *se_dev = SE_DEV(cmd); + struct se_subsystem_dev *su_dev = SU_DEV(se_dev); + struct t10_pr_registration *pr_reg; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + u32 add_len = 0, off = 8; + + if (cmd->data_length < 8) { + printk(KERN_ERR "PRIN SA READ_KEYS SCSI Data Length: %u" + " too small\n", cmd->data_length); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff); + buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff); + buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff); + buf[3] = (T10_RES(su_dev)->pr_generation & 0xff); + + spin_lock(&T10_RES(su_dev)->registration_lock); + list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list, + pr_reg_list) { + /* + * Check for overflow of 8byte PRI READ_KEYS payload and + * next reservation key list descriptor. + */ + if ((add_len + 8) > (cmd->data_length - 8)) + break; + + buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); + buf[off++] = (pr_reg->pr_res_key & 0xff); + + add_len += 8; + } + spin_unlock(&T10_RES(su_dev)->registration_lock); + + buf[4] = ((add_len >> 24) & 0xff); + buf[5] = ((add_len >> 16) & 0xff); + buf[6] = ((add_len >> 8) & 0xff); + buf[7] = (add_len & 0xff); + + return 0; +} + +/* + * PERSISTENT_RESERVE_IN Service Action READ_RESERVATION + * + * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162 + */ +static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) +{ + struct se_device *se_dev = SE_DEV(cmd); + struct se_subsystem_dev *su_dev = SU_DEV(se_dev); + struct t10_pr_registration *pr_reg; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + u64 pr_res_key; + u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */ + + if (cmd->data_length < 8) { + printk(KERN_ERR "PRIN SA READ_RESERVATIONS SCSI Data Length: %u" + " too small\n", cmd->data_length); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff); + buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff); + buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff); + buf[3] = (T10_RES(su_dev)->pr_generation & 0xff); + + spin_lock(&se_dev->dev_reservation_lock); + pr_reg = se_dev->dev_pr_res_holder; + if ((pr_reg)) { + /* + * Set the hardcoded Additional Length + */ + buf[4] = ((add_len >> 24) & 0xff); + buf[5] = ((add_len >> 16) & 0xff); + buf[6] = ((add_len >> 8) & 0xff); + buf[7] = (add_len & 0xff); + + if (cmd->data_length < 22) { + spin_unlock(&se_dev->dev_reservation_lock); + return 0; + } + /* + * Set the Reservation key. + * + * From spc4r17, section 5.7.10: + * A persistent reservation holder has its reservation key + * returned in the parameter data from a PERSISTENT + * RESERVE IN command with READ RESERVATION service action as + * follows: + * a) For a persistent reservation of the type Write Exclusive + * - All Registrants or Exclusive Access ­ All Regitrants, + * the reservation key shall be set to zero; or + * b) For all other persistent reservation types, the + * reservation key shall be set to the registered + * reservation key for the I_T nexus that holds the + * persistent reservation. + */ + if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || + (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) + pr_res_key = 0; + else + pr_res_key = pr_reg->pr_res_key; + + buf[8] = ((pr_res_key >> 56) & 0xff); + buf[9] = ((pr_res_key >> 48) & 0xff); + buf[10] = ((pr_res_key >> 40) & 0xff); + buf[11] = ((pr_res_key >> 32) & 0xff); + buf[12] = ((pr_res_key >> 24) & 0xff); + buf[13] = ((pr_res_key >> 16) & 0xff); + buf[14] = ((pr_res_key >> 8) & 0xff); + buf[15] = (pr_res_key & 0xff); + /* + * Set the SCOPE and TYPE + */ + buf[21] = (pr_reg->pr_res_scope & 0xf0) | + (pr_reg->pr_res_type & 0x0f); + } + spin_unlock(&se_dev->dev_reservation_lock); + + return 0; +} + +/* + * PERSISTENT_RESERVE_IN Service Action REPORT_CAPABILITIES + * + * See spc4r17 section 6.13.4 Table 165 + */ +static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + u16 add_len = 8; /* Hardcoded to 8. */ + + if (cmd->data_length < 6) { + printk(KERN_ERR "PRIN SA REPORT_CAPABILITIES SCSI Data Length:" + " %u too small\n", cmd->data_length); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + buf[0] = ((add_len << 8) & 0xff); + buf[1] = (add_len & 0xff); + buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */ + buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */ + buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */ + buf[2] |= 0x01; /* PTPL_C: Persistence across Target Power Loss bit */ + /* + * We are filling in the PERSISTENT RESERVATION TYPE MASK below, so + * set the TMV: Task Mask Valid bit. + */ + buf[3] |= 0x80; + /* + * Change ALLOW COMMANDs to 0x20 or 0x40 later from Table 166 + */ + buf[3] |= 0x10; /* ALLOW COMMANDs field 001b */ + /* + * PTPL_A: Persistence across Target Power Loss Active bit + */ + if (pr_tmpl->pr_aptpl_active) + buf[3] |= 0x01; + /* + * Setup the PERSISTENT RESERVATION TYPE MASK from Table 167 + */ + buf[4] |= 0x80; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ + buf[4] |= 0x40; /* PR_TYPE_EXCLUSIVE_ACCESS_REGONLY */ + buf[4] |= 0x20; /* PR_TYPE_WRITE_EXCLUSIVE_REGONLY */ + buf[4] |= 0x08; /* PR_TYPE_EXCLUSIVE_ACCESS */ + buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */ + buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ + + return 0; +} + +/* + * PERSISTENT_RESERVE_IN Service Action READ_FULL_STATUS + * + * See spc4r17 section 6.13.5 Table 168 and 169 + */ +static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) +{ + struct se_device *se_dev = SE_DEV(cmd); + struct se_node_acl *se_nacl; + struct se_subsystem_dev *su_dev = SU_DEV(se_dev); + struct se_portal_group *se_tpg; + struct t10_pr_registration *pr_reg, *pr_reg_tmp; + struct t10_reservation_template *pr_tmpl = &SU_DEV(se_dev)->t10_reservation; + unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; + u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; + u32 off = 8; /* off into first Full Status descriptor */ + int format_code = 0; + + if (cmd->data_length < 8) { + printk(KERN_ERR "PRIN SA READ_FULL_STATUS SCSI Data Length: %u" + " too small\n", cmd->data_length); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + + buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff); + buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff); + buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff); + buf[3] = (T10_RES(su_dev)->pr_generation & 0xff); + + spin_lock(&pr_tmpl->registration_lock); + list_for_each_entry_safe(pr_reg, pr_reg_tmp, + &pr_tmpl->registration_list, pr_reg_list) { + + se_nacl = pr_reg->pr_reg_nacl; + se_tpg = pr_reg->pr_reg_nacl->se_tpg; + add_desc_len = 0; + + atomic_inc(&pr_reg->pr_res_holders); + smp_mb__after_atomic_inc(); + spin_unlock(&pr_tmpl->registration_lock); + /* + * Determine expected length of $FABRIC_MOD specific + * TransportID full status descriptor.. + */ + exp_desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id_len( + se_tpg, se_nacl, pr_reg, &format_code); + + if ((exp_desc_len + add_len) > cmd->data_length) { + printk(KERN_WARNING "SPC-3 PRIN READ_FULL_STATUS ran" + " out of buffer: %d\n", cmd->data_length); + spin_lock(&pr_tmpl->registration_lock); + atomic_dec(&pr_reg->pr_res_holders); + smp_mb__after_atomic_dec(); + break; + } + /* + * Set RESERVATION KEY + */ + buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff); + buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff); + buf[off++] = (pr_reg->pr_res_key & 0xff); + off += 4; /* Skip Over Reserved area */ + + /* + * Set ALL_TG_PT bit if PROUT SA REGISTER had this set. + */ + if (pr_reg->pr_reg_all_tg_pt) + buf[off] = 0x02; + /* + * The struct se_lun pointer will be present for the + * reservation holder for PR_HOLDER bit. + * + * Also, if this registration is the reservation + * holder, fill in SCOPE and TYPE in the next byte. + */ + if (pr_reg->pr_res_holder) { + buf[off++] |= 0x01; + buf[off++] = (pr_reg->pr_res_scope & 0xf0) | + (pr_reg->pr_res_type & 0x0f); + } else + off += 2; + + off += 4; /* Skip over reserved area */ + /* + * From spc4r17 6.3.15: + * + * If the ALL_TG_PT bit set to zero, the RELATIVE TARGET PORT + * IDENTIFIER field contains the relative port identifier (see + * 3.1.120) of the target port that is part of the I_T nexus + * described by this full status descriptor. If the ALL_TG_PT + * bit is set to one, the contents of the RELATIVE TARGET PORT + * IDENTIFIER field are not defined by this standard. + */ + if (!(pr_reg->pr_reg_all_tg_pt)) { + struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep; + + buf[off++] = ((port->sep_rtpi >> 8) & 0xff); + buf[off++] = (port->sep_rtpi & 0xff); + } else + off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */ + + /* + * Now, have the $FABRIC_MOD fill in the protocol identifier + */ + desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id(se_tpg, + se_nacl, pr_reg, &format_code, &buf[off+4]); + + spin_lock(&pr_tmpl->registration_lock); + atomic_dec(&pr_reg->pr_res_holders); + smp_mb__after_atomic_dec(); + /* + * Set the ADDITIONAL DESCRIPTOR LENGTH + */ + buf[off++] = ((desc_len >> 24) & 0xff); + buf[off++] = ((desc_len >> 16) & 0xff); + buf[off++] = ((desc_len >> 8) & 0xff); + buf[off++] = (desc_len & 0xff); + /* + * Size of full desctipor header minus TransportID + * containing $FABRIC_MOD specific) initiator device/port + * WWN information. + * + * See spc4r17 Section 6.13.5 Table 169 + */ + add_desc_len = (24 + desc_len); + + off += desc_len; + add_len += add_desc_len; + } + spin_unlock(&pr_tmpl->registration_lock); + /* + * Set ADDITIONAL_LENGTH + */ + buf[4] = ((add_len >> 24) & 0xff); + buf[5] = ((add_len >> 16) & 0xff); + buf[6] = ((add_len >> 8) & 0xff); + buf[7] = (add_len & 0xff); + + return 0; +} + +static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb) +{ + switch (cdb[1] & 0x1f) { + case PRI_READ_KEYS: + return core_scsi3_pri_read_keys(cmd); + case PRI_READ_RESERVATION: + return core_scsi3_pri_read_reservation(cmd); + case PRI_REPORT_CAPABILITIES: + return core_scsi3_pri_report_capabilities(cmd); + case PRI_READ_FULL_STATUS: + return core_scsi3_pri_read_full_status(cmd); + default: + printk(KERN_ERR "Unknown PERSISTENT_RESERVE_IN service" + " action: 0x%02x\n", cdb[1] & 0x1f); + return PYX_TRANSPORT_INVALID_CDB_FIELD; + } + +} + +int core_scsi3_emulate_pr(struct se_cmd *cmd) +{ + unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0]; + struct se_device *dev = cmd->se_dev; + /* + * Following spc2r20 5.5.1 Reservations overview: + * + * If a logical unit has been reserved by any RESERVE command and is + * still reserved by any initiator, all PERSISTENT RESERVE IN and all + * PERSISTENT RESERVE OUT commands shall conflict regardless of + * initiator or service action and shall terminate with a RESERVATION + * CONFLICT status. + */ + if (dev->dev_flags & DF_SPC2_RESERVATIONS) { + printk(KERN_ERR "Received PERSISTENT_RESERVE CDB while legacy" + " SPC-2 reservation is held, returning" + " RESERVATION_CONFLICT\n"); + return PYX_TRANSPORT_RESERVATION_CONFLICT; + } + + return (cdb[0] == PERSISTENT_RESERVE_OUT) ? + core_scsi3_emulate_pr_out(cmd, cdb) : + core_scsi3_emulate_pr_in(cmd, cdb); +} + +static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type) +{ + return 0; +} + +static int core_pt_seq_non_holder( + struct se_cmd *cmd, + unsigned char *cdb, + u32 pr_reg_type) +{ + return 0; +} + +int core_setup_reservations(struct se_device *dev, int force_pt) +{ + struct se_subsystem_dev *su_dev = dev->se_sub_dev; + struct t10_reservation_template *rest = &su_dev->t10_reservation; + /* + * If this device is from Target_Core_Mod/pSCSI, use the reservations + * of the Underlying SCSI hardware. In Linux/SCSI terms, this can + * cause a problem because libata and some SATA RAID HBAs appear + * under Linux/SCSI, but to emulate reservations themselves. + */ + if (((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) && + !(DEV_ATTRIB(dev)->emulate_reservations)) || force_pt) { + rest->res_type = SPC_PASSTHROUGH; + rest->pr_ops.t10_reservation_check = &core_pt_reservation_check; + rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder; + printk(KERN_INFO "%s: Using SPC_PASSTHROUGH, no reservation" + " emulation\n", TRANSPORT(dev)->name); + return 0; + } + /* + * If SPC-3 or above is reported by real or emulated struct se_device, + * use emulated Persistent Reservations. + */ + if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) { + rest->res_type = SPC3_PERSISTENT_RESERVATIONS; + rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check; + rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder; + printk(KERN_INFO "%s: Using SPC3_PERSISTENT_RESERVATIONS" + " emulation\n", TRANSPORT(dev)->name); + } else { + rest->res_type = SPC2_RESERVATIONS; + rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check; + rest->pr_ops.t10_seq_non_holder = + &core_scsi2_reservation_seq_non_holder; + printk(KERN_INFO "%s: Using SPC2_RESERVATIONS emulation\n", + TRANSPORT(dev)->name); + } + + return 0; +} diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h new file mode 100644 index 000000000000..5603bcfd86d3 --- /dev/null +++ b/drivers/target/target_core_pr.h @@ -0,0 +1,67 @@ +#ifndef TARGET_CORE_PR_H +#define TARGET_CORE_PR_H +/* + * PERSISTENT_RESERVE_OUT service action codes + * + * spc4r17 section 6.14.2 Table 171 + */ +#define PRO_REGISTER 0x00 +#define PRO_RESERVE 0x01 +#define PRO_RELEASE 0x02 +#define PRO_CLEAR 0x03 +#define PRO_PREEMPT 0x04 +#define PRO_PREEMPT_AND_ABORT 0x05 +#define PRO_REGISTER_AND_IGNORE_EXISTING_KEY 0x06 +#define PRO_REGISTER_AND_MOVE 0x07 +/* + * PERSISTENT_RESERVE_IN service action codes + * + * spc4r17 section 6.13.1 Table 159 + */ +#define PRI_READ_KEYS 0x00 +#define PRI_READ_RESERVATION 0x01 +#define PRI_REPORT_CAPABILITIES 0x02 +#define PRI_READ_FULL_STATUS 0x03 +/* + * PERSISTENT_RESERVE_ SCOPE field + * + * spc4r17 section 6.13.3.3 Table 163 + */ +#define PR_SCOPE_LU_SCOPE 0x00 +/* + * PERSISTENT_RESERVE_* TYPE field + * + * spc4r17 section 6.13.3.4 Table 164 + */ +#define PR_TYPE_WRITE_EXCLUSIVE 0x01 +#define PR_TYPE_EXCLUSIVE_ACCESS 0x03 +#define PR_TYPE_WRITE_EXCLUSIVE_REGONLY 0x05 +#define PR_TYPE_EXCLUSIVE_ACCESS_REGONLY 0x06 +#define PR_TYPE_WRITE_EXCLUSIVE_ALLREG 0x07 +#define PR_TYPE_EXCLUSIVE_ACCESS_ALLREG 0x08 + +#define PR_APTPL_MAX_IPORT_LEN 256 +#define PR_APTPL_MAX_TPORT_LEN 256 + +extern struct kmem_cache *t10_pr_reg_cache; + +extern int core_pr_dump_initiator_port(struct t10_pr_registration *, + char *, u32); +extern int core_scsi2_emulate_crh(struct se_cmd *); +extern int core_scsi3_alloc_aptpl_registration( + struct t10_reservation_template *, u64, + unsigned char *, unsigned char *, u32, + unsigned char *, u16, u32, int, int, u8); +extern int core_scsi3_check_aptpl_registration(struct se_device *, + struct se_portal_group *, struct se_lun *, + struct se_lun_acl *); +extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, + struct se_node_acl *); +extern void core_scsi3_free_all_registrations(struct se_device *); +extern unsigned char *core_scsi3_pr_dump_type(int); +extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *, + struct se_cmd *); +extern int core_scsi3_emulate_pr(struct se_cmd *); +extern int core_setup_reservations(struct se_device *, int); + +#endif /* TARGET_CORE_PR_H */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c new file mode 100644 index 000000000000..742d24609a9b --- /dev/null +++ b/drivers/target/target_core_pscsi.c @@ -0,0 +1,1470 @@ +/******************************************************************************* + * Filename: target_core_pscsi.c + * + * This file contains the generic target mode <-> Linux SCSI subsystem plugin. + * + * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include +#include +#include +#include /* For TASK_ATTR_* */ + +#include +#include +#include + +#include "target_core_pscsi.h" + +#define ISPRINT(a) ((a >= ' ') && (a <= '~')) + +static struct se_subsystem_api pscsi_template; + +static void pscsi_req_done(struct request *, int); + +/* pscsi_get_sh(): + * + * + */ +static struct Scsi_Host *pscsi_get_sh(u32 host_no) +{ + struct Scsi_Host *sh = NULL; + + sh = scsi_host_lookup(host_no); + if (IS_ERR(sh)) { + printk(KERN_ERR "Unable to locate SCSI HBA with Host ID:" + " %u\n", host_no); + return NULL; + } + + return sh; +} + +/* pscsi_attach_hba(): + * + * pscsi_get_sh() used scsi_host_lookup() to locate struct Scsi_Host. + * from the passed SCSI Host ID. + */ +static int pscsi_attach_hba(struct se_hba *hba, u32 host_id) +{ + int hba_depth; + struct pscsi_hba_virt *phv; + + phv = kzalloc(sizeof(struct pscsi_hba_virt), GFP_KERNEL); + if (!(phv)) { + printk(KERN_ERR "Unable to allocate struct pscsi_hba_virt\n"); + return -1; + } + phv->phv_host_id = host_id; + phv->phv_mode = PHV_VIRUTAL_HOST_ID; + hba_depth = PSCSI_VIRTUAL_HBA_DEPTH; + atomic_set(&hba->left_queue_depth, hba_depth); + atomic_set(&hba->max_queue_depth, hba_depth); + + hba->hba_ptr = (void *)phv; + + printk(KERN_INFO "CORE_HBA[%d] - TCM SCSI HBA Driver %s on" + " Generic Target Core Stack %s\n", hba->hba_id, + PSCSI_VERSION, TARGET_CORE_MOD_VERSION); + printk(KERN_INFO "CORE_HBA[%d] - Attached SCSI HBA to Generic" + " Target Core with TCQ Depth: %d\n", hba->hba_id, + atomic_read(&hba->max_queue_depth)); + + return 0; +} + +static void pscsi_detach_hba(struct se_hba *hba) +{ + struct pscsi_hba_virt *phv = hba->hba_ptr; + struct Scsi_Host *scsi_host = phv->phv_lld_host; + + if (scsi_host) { + scsi_host_put(scsi_host); + + printk(KERN_INFO "CORE_HBA[%d] - Detached SCSI HBA: %s from" + " Generic Target Core\n", hba->hba_id, + (scsi_host->hostt->name) ? (scsi_host->hostt->name) : + "Unknown"); + } else + printk(KERN_INFO "CORE_HBA[%d] - Detached Virtual SCSI HBA" + " from Generic Target Core\n", hba->hba_id); + + kfree(phv); + hba->hba_ptr = NULL; +} + +static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag) +{ + struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr; + struct Scsi_Host *sh = phv->phv_lld_host; + int hba_depth = PSCSI_VIRTUAL_HBA_DEPTH; + /* + * Release the struct Scsi_Host + */ + if (!(mode_flag)) { + if (!(sh)) + return 0; + + phv->phv_lld_host = NULL; + phv->phv_mode = PHV_VIRUTAL_HOST_ID; + atomic_set(&hba->left_queue_depth, hba_depth); + atomic_set(&hba->max_queue_depth, hba_depth); + + printk(KERN_INFO "CORE_HBA[%d] - Disabled pSCSI HBA Passthrough" + " %s\n", hba->hba_id, (sh->hostt->name) ? + (sh->hostt->name) : "Unknown"); + + scsi_host_put(sh); + return 0; + } + /* + * Otherwise, locate struct Scsi_Host from the original passed + * pSCSI Host ID and enable for phba mode + */ + sh = pscsi_get_sh(phv->phv_host_id); + if (!(sh)) { + printk(KERN_ERR "pSCSI: Unable to locate SCSI Host for" + " phv_host_id: %d\n", phv->phv_host_id); + return -1; + } + /* + * Usually the SCSI LLD will use the hostt->can_queue value to define + * its HBA TCQ depth. Some other drivers (like 2.6 megaraid) don't set + * this at all and set sh->can_queue at runtime. + */ + hba_depth = (sh->hostt->can_queue > sh->can_queue) ? + sh->hostt->can_queue : sh->can_queue; + + atomic_set(&hba->left_queue_depth, hba_depth); + atomic_set(&hba->max_queue_depth, hba_depth); + + phv->phv_lld_host = sh; + phv->phv_mode = PHV_LLD_SCSI_HOST_NO; + + printk(KERN_INFO "CORE_HBA[%d] - Enabled pSCSI HBA Passthrough %s\n", + hba->hba_id, (sh->hostt->name) ? (sh->hostt->name) : "Unknown"); + + return 1; +} + +static void pscsi_tape_read_blocksize(struct se_device *dev, + struct scsi_device *sdev) +{ + unsigned char cdb[MAX_COMMAND_SIZE], *buf; + int ret; + + buf = kzalloc(12, GFP_KERNEL); + if (!buf) + return; + + memset(cdb, 0, MAX_COMMAND_SIZE); + cdb[0] = MODE_SENSE; + cdb[4] = 0x0c; /* 12 bytes */ + + ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, 12, NULL, + HZ, 1, NULL); + if (ret) + goto out_free; + + /* + * If MODE_SENSE still returns zero, set the default value to 1024. + */ + sdev->sector_size = (buf[9] << 16) | (buf[10] << 8) | (buf[11]); + if (!sdev->sector_size) + sdev->sector_size = 1024; +out_free: + kfree(buf); +} + +static void +pscsi_set_inquiry_info(struct scsi_device *sdev, struct t10_wwn *wwn) +{ + unsigned char *buf; + + if (sdev->inquiry_len < INQUIRY_LEN) + return; + + buf = sdev->inquiry; + if (!buf) + return; + /* + * Use sdev->inquiry from drivers/scsi/scsi_scan.c:scsi_alloc_sdev() + */ + memcpy(&wwn->vendor[0], &buf[8], sizeof(wwn->vendor)); + memcpy(&wwn->model[0], &buf[16], sizeof(wwn->model)); + memcpy(&wwn->revision[0], &buf[32], sizeof(wwn->revision)); +} + +static int +pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn) +{ + unsigned char cdb[MAX_COMMAND_SIZE], *buf; + int ret; + + buf = kzalloc(INQUIRY_VPD_SERIAL_LEN, GFP_KERNEL); + if (!buf) + return -1; + + memset(cdb, 0, MAX_COMMAND_SIZE); + cdb[0] = INQUIRY; + cdb[1] = 0x01; /* Query VPD */ + cdb[2] = 0x80; /* Unit Serial Number */ + cdb[3] = (INQUIRY_VPD_SERIAL_LEN >> 8) & 0xff; + cdb[4] = (INQUIRY_VPD_SERIAL_LEN & 0xff); + + ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, + INQUIRY_VPD_SERIAL_LEN, NULL, HZ, 1, NULL); + if (ret) + goto out_free; + + snprintf(&wwn->unit_serial[0], INQUIRY_VPD_SERIAL_LEN, "%s", &buf[4]); + + wwn->t10_sub_dev->su_dev_flags |= SDF_FIRMWARE_VPD_UNIT_SERIAL; + + kfree(buf); + return 0; + +out_free: + kfree(buf); + return -1; +} + +static void +pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev, + struct t10_wwn *wwn) +{ + unsigned char cdb[MAX_COMMAND_SIZE], *buf, *page_83; + int ident_len, page_len, off = 4, ret; + struct t10_vpd *vpd; + + buf = kzalloc(INQUIRY_VPD_SERIAL_LEN, GFP_KERNEL); + if (!buf) + return; + + memset(cdb, 0, MAX_COMMAND_SIZE); + cdb[0] = INQUIRY; + cdb[1] = 0x01; /* Query VPD */ + cdb[2] = 0x83; /* Device Identifier */ + cdb[3] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN >> 8) & 0xff; + cdb[4] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN & 0xff); + + ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, + INQUIRY_VPD_DEVICE_IDENTIFIER_LEN, + NULL, HZ, 1, NULL); + if (ret) + goto out; + + page_len = (buf[2] << 8) | buf[3]; + while (page_len > 0) { + /* Grab a pointer to the Identification descriptor */ + page_83 = &buf[off]; + ident_len = page_83[3]; + if (!ident_len) { + printk(KERN_ERR "page_83[3]: identifier" + " length zero!\n"); + break; + } + printk(KERN_INFO "T10 VPD Identifer Length: %d\n", ident_len); + + vpd = kzalloc(sizeof(struct t10_vpd), GFP_KERNEL); + if (!vpd) { + printk(KERN_ERR "Unable to allocate memory for" + " struct t10_vpd\n"); + goto out; + } + INIT_LIST_HEAD(&vpd->vpd_list); + + transport_set_vpd_proto_id(vpd, page_83); + transport_set_vpd_assoc(vpd, page_83); + + if (transport_set_vpd_ident_type(vpd, page_83) < 0) { + off += (ident_len + 4); + page_len -= (ident_len + 4); + kfree(vpd); + continue; + } + if (transport_set_vpd_ident(vpd, page_83) < 0) { + off += (ident_len + 4); + page_len -= (ident_len + 4); + kfree(vpd); + continue; + } + + list_add_tail(&vpd->vpd_list, &wwn->t10_vpd_list); + off += (ident_len + 4); + page_len -= (ident_len + 4); + } + +out: + kfree(buf); +} + +/* pscsi_add_device_to_list(): + * + * + */ +static struct se_device *pscsi_add_device_to_list( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + struct pscsi_dev_virt *pdv, + struct scsi_device *sd, + int dev_flags) +{ + struct se_device *dev; + struct se_dev_limits dev_limits; + struct request_queue *q; + struct queue_limits *limits; + + memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + + if (!sd->queue_depth) { + sd->queue_depth = PSCSI_DEFAULT_QUEUEDEPTH; + + printk(KERN_ERR "Set broken SCSI Device %d:%d:%d" + " queue_depth to %d\n", sd->channel, sd->id, + sd->lun, sd->queue_depth); + } + /* + * Setup the local scope queue_limits from struct request_queue->limits + * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. + */ + q = sd->request_queue; + limits = &dev_limits.limits; + limits->logical_block_size = sd->sector_size; + limits->max_hw_sectors = (sd->host->max_sectors > queue_max_hw_sectors(q)) ? + queue_max_hw_sectors(q) : sd->host->max_sectors; + limits->max_sectors = (sd->host->max_sectors > queue_max_sectors(q)) ? + queue_max_sectors(q) : sd->host->max_sectors; + dev_limits.hw_queue_depth = sd->queue_depth; + dev_limits.queue_depth = sd->queue_depth; + /* + * Setup our standard INQUIRY info into se_dev->t10_wwn + */ + pscsi_set_inquiry_info(sd, &se_dev->t10_wwn); + + /* + * Set the pointer pdv->pdv_sd to from passed struct scsi_device, + * which has already been referenced with Linux SCSI code with + * scsi_device_get() in this file's pscsi_create_virtdevice(). + * + * The passthrough operations called by the transport_add_device_* + * function below will require this pointer to be set for passthroug + * ops. + * + * For the shutdown case in pscsi_free_device(), this struct + * scsi_device reference is released with Linux SCSI code + * scsi_device_put() and the pdv->pdv_sd cleared. + */ + pdv->pdv_sd = sd; + + dev = transport_add_device_to_core_hba(hba, &pscsi_template, + se_dev, dev_flags, (void *)pdv, + &dev_limits, NULL, NULL); + if (!(dev)) { + pdv->pdv_sd = NULL; + return NULL; + } + + /* + * Locate VPD WWN Information used for various purposes within + * the Storage Engine. + */ + if (!pscsi_get_inquiry_vpd_serial(sd, &se_dev->t10_wwn)) { + /* + * If VPD Unit Serial returned GOOD status, try + * VPD Device Identification page (0x83). + */ + pscsi_get_inquiry_vpd_device_ident(sd, &se_dev->t10_wwn); + } + + /* + * For TYPE_TAPE, attempt to determine blocksize with MODE_SENSE. + */ + if (sd->type == TYPE_TAPE) + pscsi_tape_read_blocksize(dev, sd); + return dev; +} + +static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name) +{ + struct pscsi_dev_virt *pdv; + + pdv = kzalloc(sizeof(struct pscsi_dev_virt), GFP_KERNEL); + if (!(pdv)) { + printk(KERN_ERR "Unable to allocate memory for struct pscsi_dev_virt\n"); + return NULL; + } + pdv->pdv_se_hba = hba; + + printk(KERN_INFO "PSCSI: Allocated pdv: %p for %s\n", pdv, name); + return (void *)pdv; +} + +/* + * Called with struct Scsi_Host->host_lock called. + */ +static struct se_device *pscsi_create_type_disk( + struct scsi_device *sd, + struct pscsi_dev_virt *pdv, + struct se_subsystem_dev *se_dev, + struct se_hba *hba) +{ + struct se_device *dev; + struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; + struct Scsi_Host *sh = sd->host; + struct block_device *bd; + u32 dev_flags = 0; + + if (scsi_device_get(sd)) { + printk(KERN_ERR "scsi_device_get() failed for %d:%d:%d:%d\n", + sh->host_no, sd->channel, sd->id, sd->lun); + spin_unlock_irq(sh->host_lock); + return NULL; + } + spin_unlock_irq(sh->host_lock); + /* + * Claim exclusive struct block_device access to struct scsi_device + * for TYPE_DISK using supplied udev_path + */ + bd = blkdev_get_by_path(se_dev->se_dev_udev_path, + FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv); + if (!(bd)) { + printk("pSCSI: blkdev_get_by_path() failed\n"); + scsi_device_put(sd); + return NULL; + } + pdv->pdv_bd = bd; + + dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); + if (!(dev)) { + blkdev_put(pdv->pdv_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); + scsi_device_put(sd); + return NULL; + } + printk(KERN_INFO "CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%d\n", + phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun); + + return dev; +} + +/* + * Called with struct Scsi_Host->host_lock called. + */ +static struct se_device *pscsi_create_type_rom( + struct scsi_device *sd, + struct pscsi_dev_virt *pdv, + struct se_subsystem_dev *se_dev, + struct se_hba *hba) +{ + struct se_device *dev; + struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; + struct Scsi_Host *sh = sd->host; + u32 dev_flags = 0; + + if (scsi_device_get(sd)) { + printk(KERN_ERR "scsi_device_get() failed for %d:%d:%d:%d\n", + sh->host_no, sd->channel, sd->id, sd->lun); + spin_unlock_irq(sh->host_lock); + return NULL; + } + spin_unlock_irq(sh->host_lock); + + dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); + if (!(dev)) { + scsi_device_put(sd); + return NULL; + } + printk(KERN_INFO "CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n", + phv->phv_host_id, scsi_device_type(sd->type), sh->host_no, + sd->channel, sd->id, sd->lun); + + return dev; +} + +/* + *Called with struct Scsi_Host->host_lock called. + */ +static struct se_device *pscsi_create_type_other( + struct scsi_device *sd, + struct pscsi_dev_virt *pdv, + struct se_subsystem_dev *se_dev, + struct se_hba *hba) +{ + struct se_device *dev; + struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; + struct Scsi_Host *sh = sd->host; + u32 dev_flags = 0; + + spin_unlock_irq(sh->host_lock); + dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags); + if (!(dev)) + return NULL; + + printk(KERN_INFO "CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n", + phv->phv_host_id, scsi_device_type(sd->type), sh->host_no, + sd->channel, sd->id, sd->lun); + + return dev; +} + +static struct se_device *pscsi_create_virtdevice( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + void *p) +{ + struct pscsi_dev_virt *pdv = (struct pscsi_dev_virt *)p; + struct se_device *dev; + struct scsi_device *sd; + struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr; + struct Scsi_Host *sh = phv->phv_lld_host; + int legacy_mode_enable = 0; + + if (!(pdv)) { + printk(KERN_ERR "Unable to locate struct pscsi_dev_virt" + " parameter\n"); + return NULL; + } + /* + * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the + * struct Scsi_Host we will need to bring the TCM/pSCSI object online + */ + if (!(sh)) { + if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { + printk(KERN_ERR "pSCSI: Unable to locate struct" + " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); + return NULL; + } + /* + * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device + * reference, we enforce that udev_path has been set + */ + if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { + printk(KERN_ERR "pSCSI: udev_path attribute has not" + " been set before ENABLE=1\n"); + return NULL; + } + /* + * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID, + * use the original TCM hba ID to reference Linux/SCSI Host No + * and enable for PHV_LLD_SCSI_HOST_NO mode. + */ + if (!(pdv->pdv_flags & PDF_HAS_VIRT_HOST_ID)) { + spin_lock(&hba->device_lock); + if (!(list_empty(&hba->hba_dev_list))) { + printk(KERN_ERR "pSCSI: Unable to set hba_mode" + " with active devices\n"); + spin_unlock(&hba->device_lock); + return NULL; + } + spin_unlock(&hba->device_lock); + + if (pscsi_pmode_enable_hba(hba, 1) != 1) + return NULL; + + legacy_mode_enable = 1; + hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; + sh = phv->phv_lld_host; + } else { + sh = pscsi_get_sh(pdv->pdv_host_id); + if (!(sh)) { + printk(KERN_ERR "pSCSI: Unable to locate" + " pdv_host_id: %d\n", pdv->pdv_host_id); + return NULL; + } + } + } else { + if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) { + printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while" + " struct Scsi_Host exists\n"); + return NULL; + } + } + + spin_lock_irq(sh->host_lock); + list_for_each_entry(sd, &sh->__devices, siblings) { + if ((pdv->pdv_channel_id != sd->channel) || + (pdv->pdv_target_id != sd->id) || + (pdv->pdv_lun_id != sd->lun)) + continue; + /* + * Functions will release the held struct scsi_host->host_lock + * before calling calling pscsi_add_device_to_list() to register + * struct scsi_device with target_core_mod. + */ + switch (sd->type) { + case TYPE_DISK: + dev = pscsi_create_type_disk(sd, pdv, se_dev, hba); + break; + case TYPE_ROM: + dev = pscsi_create_type_rom(sd, pdv, se_dev, hba); + break; + default: + dev = pscsi_create_type_other(sd, pdv, se_dev, hba); + break; + } + + if (!(dev)) { + if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) + scsi_host_put(sh); + else if (legacy_mode_enable) { + pscsi_pmode_enable_hba(hba, 0); + hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; + } + pdv->pdv_sd = NULL; + return NULL; + } + return dev; + } + spin_unlock_irq(sh->host_lock); + + printk(KERN_ERR "pSCSI: Unable to locate %d:%d:%d:%d\n", sh->host_no, + pdv->pdv_channel_id, pdv->pdv_target_id, pdv->pdv_lun_id); + + if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) + scsi_host_put(sh); + else if (legacy_mode_enable) { + pscsi_pmode_enable_hba(hba, 0); + hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; + } + + return NULL; +} + +/* pscsi_free_device(): (Part of se_subsystem_api_t template) + * + * + */ +static void pscsi_free_device(void *p) +{ + struct pscsi_dev_virt *pdv = p; + struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; + struct scsi_device *sd = pdv->pdv_sd; + + if (sd) { + /* + * Release exclusive pSCSI internal struct block_device claim for + * struct scsi_device with TYPE_DISK from pscsi_create_type_disk() + */ + if ((sd->type == TYPE_DISK) && pdv->pdv_bd) { + blkdev_put(pdv->pdv_bd, + FMODE_WRITE|FMODE_READ|FMODE_EXCL); + pdv->pdv_bd = NULL; + } + /* + * For HBA mode PHV_LLD_SCSI_HOST_NO, release the reference + * to struct Scsi_Host now. + */ + if ((phv->phv_mode == PHV_LLD_SCSI_HOST_NO) && + (phv->phv_lld_host != NULL)) + scsi_host_put(phv->phv_lld_host); + + if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM)) + scsi_device_put(sd); + + pdv->pdv_sd = NULL; + } + + kfree(pdv); +} + +static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task) +{ + return container_of(task, struct pscsi_plugin_task, pscsi_task); +} + + +/* pscsi_transport_complete(): + * + * + */ +static int pscsi_transport_complete(struct se_task *task) +{ + struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; + struct scsi_device *sd = pdv->pdv_sd; + int result; + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + unsigned char *cdb = &pt->pscsi_cdb[0]; + + result = pt->pscsi_result; + /* + * Hack to make sure that Write-Protect modepage is set if R/O mode is + * forced. + */ + if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && + (status_byte(result) << 1) == SAM_STAT_GOOD) { + if (!TASK_CMD(task)->se_deve) + goto after_mode_sense; + + if (TASK_CMD(task)->se_deve->lun_flags & + TRANSPORT_LUNFLAGS_READ_ONLY) { + unsigned char *buf = (unsigned char *) + T_TASK(task->task_se_cmd)->t_task_buf; + + if (cdb[0] == MODE_SENSE_10) { + if (!(buf[3] & 0x80)) + buf[3] |= 0x80; + } else { + if (!(buf[2] & 0x80)) + buf[2] |= 0x80; + } + } + } +after_mode_sense: + + if (sd->type != TYPE_TAPE) + goto after_mode_select; + + /* + * Hack to correctly obtain the initiator requested blocksize for + * TYPE_TAPE. Since this value is dependent upon each tape media, + * struct scsi_device->sector_size will not contain the correct value + * by default, so we go ahead and set it so + * TRANSPORT(dev)->get_blockdev() returns the correct value to the + * storage engine. + */ + if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) && + (status_byte(result) << 1) == SAM_STAT_GOOD) { + unsigned char *buf; + struct scatterlist *sg = task->task_sg; + u16 bdl; + u32 blocksize; + + buf = sg_virt(&sg[0]); + if (!(buf)) { + printk(KERN_ERR "Unable to get buf for scatterlist\n"); + goto after_mode_select; + } + + if (cdb[0] == MODE_SELECT) + bdl = (buf[3]); + else + bdl = (buf[6] << 8) | (buf[7]); + + if (!bdl) + goto after_mode_select; + + if (cdb[0] == MODE_SELECT) + blocksize = (buf[9] << 16) | (buf[10] << 8) | + (buf[11]); + else + blocksize = (buf[13] << 16) | (buf[14] << 8) | + (buf[15]); + + sd->sector_size = blocksize; + } +after_mode_select: + + if (status_byte(result) & CHECK_CONDITION) + return 1; + + return 0; +} + +static struct se_task * +pscsi_alloc_task(struct se_cmd *cmd) +{ + struct pscsi_plugin_task *pt; + unsigned char *cdb = T_TASK(cmd)->t_task_cdb; + + pt = kzalloc(sizeof(struct pscsi_plugin_task), GFP_KERNEL); + if (!pt) { + printk(KERN_ERR "Unable to allocate struct pscsi_plugin_task\n"); + return NULL; + } + + /* + * If TCM Core is signaling a > TCM_MAX_COMMAND_SIZE allocation, + * allocate the extended CDB buffer for per struct se_task context + * pt->pscsi_cdb now. + */ + if (T_TASK(cmd)->t_task_cdb != T_TASK(cmd)->__t_task_cdb) { + + pt->pscsi_cdb = kzalloc(scsi_command_size(cdb), GFP_KERNEL); + if (!(pt->pscsi_cdb)) { + printk(KERN_ERR "pSCSI: Unable to allocate extended" + " pt->pscsi_cdb\n"); + return NULL; + } + } else + pt->pscsi_cdb = &pt->__pscsi_cdb[0]; + + return &pt->pscsi_task; +} + +static inline void pscsi_blk_init_request( + struct se_task *task, + struct pscsi_plugin_task *pt, + struct request *req, + int bidi_read) +{ + /* + * Defined as "scsi command" in include/linux/blkdev.h. + */ + req->cmd_type = REQ_TYPE_BLOCK_PC; + /* + * For the extra BIDI-COMMAND READ struct request we do not + * need to setup the remaining structure members + */ + if (bidi_read) + return; + /* + * Setup the done function pointer for struct request, + * also set the end_io_data pointer.to struct se_task. + */ + req->end_io = pscsi_req_done; + req->end_io_data = (void *)task; + /* + * Load the referenced struct se_task's SCSI CDB into + * include/linux/blkdev.h:struct request->cmd + */ + req->cmd_len = scsi_command_size(pt->pscsi_cdb); + req->cmd = &pt->pscsi_cdb[0]; + /* + * Setup pointer for outgoing sense data. + */ + req->sense = (void *)&pt->pscsi_sense[0]; + req->sense_len = 0; +} + +/* + * Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB +*/ +static int pscsi_blk_get_request(struct se_task *task) +{ + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; + + pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue, + (task->task_data_direction == DMA_TO_DEVICE), + GFP_KERNEL); + if (!(pt->pscsi_req) || IS_ERR(pt->pscsi_req)) { + printk(KERN_ERR "PSCSI: blk_get_request() failed: %ld\n", + IS_ERR(pt->pscsi_req)); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + /* + * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC, + * and setup rq callback, CDB and sense. + */ + pscsi_blk_init_request(task, pt, pt->pscsi_req, 0); + return 0; +} + +/* pscsi_do_task(): (Part of se_subsystem_api_t template) + * + * + */ +static int pscsi_do_task(struct se_task *task) +{ + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; + /* + * Set the struct request->timeout value based on peripheral + * device type from SCSI. + */ + if (pdv->pdv_sd->type == TYPE_DISK) + pt->pscsi_req->timeout = PS_TIMEOUT_DISK; + else + pt->pscsi_req->timeout = PS_TIMEOUT_OTHER; + + pt->pscsi_req->retries = PS_RETRY; + /* + * Queue the struct request into the struct scsi_device->request_queue. + * Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd + * descriptor + */ + blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req, + (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ), + pscsi_req_done); + + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} + +static void pscsi_free_task(struct se_task *task) +{ + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct se_cmd *cmd = task->task_se_cmd; + + /* + * Release the extended CDB allocation from pscsi_alloc_task() + * if one exists. + */ + if (T_TASK(cmd)->t_task_cdb != T_TASK(cmd)->__t_task_cdb) + kfree(pt->pscsi_cdb); + /* + * We do not release the bio(s) here associated with this task, as + * this is handled by bio_put() and pscsi_bi_endio(). + */ + kfree(pt); +} + +enum { + Opt_scsi_host_id, Opt_scsi_channel_id, Opt_scsi_target_id, + Opt_scsi_lun_id, Opt_err +}; + +static match_table_t tokens = { + {Opt_scsi_host_id, "scsi_host_id=%d"}, + {Opt_scsi_channel_id, "scsi_channel_id=%d"}, + {Opt_scsi_target_id, "scsi_target_id=%d"}, + {Opt_scsi_lun_id, "scsi_lun_id=%d"}, + {Opt_err, NULL} +}; + +static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba, + struct se_subsystem_dev *se_dev, + const char *page, + ssize_t count) +{ + struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; + struct pscsi_hba_virt *phv = hba->hba_ptr; + char *orig, *ptr, *opts; + substring_t args[MAX_OPT_ARGS]; + int ret = 0, arg, token; + + opts = kstrdup(page, GFP_KERNEL); + if (!opts) + return -ENOMEM; + + orig = opts; + + while ((ptr = strsep(&opts, ",")) != NULL) { + if (!*ptr) + continue; + + token = match_token(ptr, tokens, args); + switch (token) { + case Opt_scsi_host_id: + if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { + printk(KERN_ERR "PSCSI[%d]: Unable to accept" + " scsi_host_id while phv_mode ==" + " PHV_LLD_SCSI_HOST_NO\n", + phv->phv_host_id); + ret = -EINVAL; + goto out; + } + match_int(args, &arg); + pdv->pdv_host_id = arg; + printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Host ID:" + " %d\n", phv->phv_host_id, pdv->pdv_host_id); + pdv->pdv_flags |= PDF_HAS_VIRT_HOST_ID; + break; + case Opt_scsi_channel_id: + match_int(args, &arg); + pdv->pdv_channel_id = arg; + printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Channel" + " ID: %d\n", phv->phv_host_id, + pdv->pdv_channel_id); + pdv->pdv_flags |= PDF_HAS_CHANNEL_ID; + break; + case Opt_scsi_target_id: + match_int(args, &arg); + pdv->pdv_target_id = arg; + printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Target" + " ID: %d\n", phv->phv_host_id, + pdv->pdv_target_id); + pdv->pdv_flags |= PDF_HAS_TARGET_ID; + break; + case Opt_scsi_lun_id: + match_int(args, &arg); + pdv->pdv_lun_id = arg; + printk(KERN_INFO "PSCSI[%d]: Referencing SCSI LUN ID:" + " %d\n", phv->phv_host_id, pdv->pdv_lun_id); + pdv->pdv_flags |= PDF_HAS_LUN_ID; + break; + default: + break; + } + } + +out: + kfree(orig); + return (!ret) ? count : ret; +} + +static ssize_t pscsi_check_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev) +{ + struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; + + if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) || + !(pdv->pdv_flags & PDF_HAS_TARGET_ID) || + !(pdv->pdv_flags & PDF_HAS_LUN_ID)) { + printk(KERN_ERR "Missing scsi_channel_id=, scsi_target_id= and" + " scsi_lun_id= parameters\n"); + return -1; + } + + return 0; +} + +static ssize_t pscsi_show_configfs_dev_params(struct se_hba *hba, + struct se_subsystem_dev *se_dev, + char *b) +{ + struct pscsi_hba_virt *phv = hba->hba_ptr; + struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr; + struct scsi_device *sd = pdv->pdv_sd; + unsigned char host_id[16]; + ssize_t bl; + int i; + + if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) + snprintf(host_id, 16, "%d", pdv->pdv_host_id); + else + snprintf(host_id, 16, "PHBA Mode"); + + bl = sprintf(b, "SCSI Device Bus Location:" + " Channel ID: %d Target ID: %d LUN: %d Host ID: %s\n", + pdv->pdv_channel_id, pdv->pdv_target_id, pdv->pdv_lun_id, + host_id); + + if (sd) { + bl += sprintf(b + bl, " "); + bl += sprintf(b + bl, "Vendor: "); + for (i = 0; i < 8; i++) { + if (ISPRINT(sd->vendor[i])) /* printable character? */ + bl += sprintf(b + bl, "%c", sd->vendor[i]); + else + bl += sprintf(b + bl, " "); + } + bl += sprintf(b + bl, " Model: "); + for (i = 0; i < 16; i++) { + if (ISPRINT(sd->model[i])) /* printable character ? */ + bl += sprintf(b + bl, "%c", sd->model[i]); + else + bl += sprintf(b + bl, " "); + } + bl += sprintf(b + bl, " Rev: "); + for (i = 0; i < 4; i++) { + if (ISPRINT(sd->rev[i])) /* printable character ? */ + bl += sprintf(b + bl, "%c", sd->rev[i]); + else + bl += sprintf(b + bl, " "); + } + bl += sprintf(b + bl, "\n"); + } + return bl; +} + +static void pscsi_bi_endio(struct bio *bio, int error) +{ + bio_put(bio); +} + +static inline struct bio *pscsi_get_bio(struct pscsi_dev_virt *pdv, int sg_num) +{ + struct bio *bio; + /* + * Use bio_malloc() following the comment in for bio -> struct request + * in block/blk-core.c:blk_make_request() + */ + bio = bio_kmalloc(GFP_KERNEL, sg_num); + if (!(bio)) { + printk(KERN_ERR "PSCSI: bio_kmalloc() failed\n"); + return NULL; + } + bio->bi_end_io = pscsi_bi_endio; + + return bio; +} + +#if 0 +#define DEBUG_PSCSI(x...) printk(x) +#else +#define DEBUG_PSCSI(x...) +#endif + +static int __pscsi_map_task_SG( + struct se_task *task, + struct scatterlist *task_sg, + u32 task_sg_num, + int bidi_read) +{ + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; + struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; + struct page *page; + struct scatterlist *sg; + u32 data_len = task->task_size, i, len, bytes, off; + int nr_pages = (task->task_size + task_sg[0].offset + + PAGE_SIZE - 1) >> PAGE_SHIFT; + int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + int rw = (task->task_data_direction == DMA_TO_DEVICE); + + if (!task->task_size) + return 0; + /* + * For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup + * the bio_vec maplist from TC< struct se_mem -> task->task_sg -> + * struct scatterlist memory. The struct se_task->task_sg[] currently needs + * to be attached to struct bios for submission to Linux/SCSI using + * struct request to struct scsi_device->request_queue. + * + * Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI + * is ported to upstream SCSI passthrough functionality that accepts + * struct scatterlist->page_link or struct page as a paraemeter. + */ + DEBUG_PSCSI("PSCSI: nr_pages: %d\n", nr_pages); + + for_each_sg(task_sg, sg, task_sg_num, i) { + page = sg_page(sg); + off = sg->offset; + len = sg->length; + + DEBUG_PSCSI("PSCSI: i: %d page: %p len: %d off: %d\n", i, + page, len, off); + + while (len > 0 && data_len > 0) { + bytes = min_t(unsigned int, len, PAGE_SIZE - off); + bytes = min(bytes, data_len); + + if (!(bio)) { + nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages); + nr_pages -= nr_vecs; + /* + * Calls bio_kmalloc() and sets bio->bi_end_io() + */ + bio = pscsi_get_bio(pdv, nr_vecs); + if (!(bio)) + goto fail; + + if (rw) + bio->bi_rw |= REQ_WRITE; + + DEBUG_PSCSI("PSCSI: Allocated bio: %p," + " dir: %s nr_vecs: %d\n", bio, + (rw) ? "rw" : "r", nr_vecs); + /* + * Set *hbio pointer to handle the case: + * nr_pages > BIO_MAX_PAGES, where additional + * bios need to be added to complete a given + * struct se_task + */ + if (!hbio) + hbio = tbio = bio; + else + tbio = tbio->bi_next = bio; + } + + DEBUG_PSCSI("PSCSI: Calling bio_add_pc_page() i: %d" + " bio: %p page: %p len: %d off: %d\n", i, bio, + page, len, off); + + rc = bio_add_pc_page(pdv->pdv_sd->request_queue, + bio, page, bytes, off); + if (rc != bytes) + goto fail; + + DEBUG_PSCSI("PSCSI: bio->bi_vcnt: %d nr_vecs: %d\n", + bio->bi_vcnt, nr_vecs); + + if (bio->bi_vcnt > nr_vecs) { + DEBUG_PSCSI("PSCSI: Reached bio->bi_vcnt max:" + " %d i: %d bio: %p, allocating another" + " bio\n", bio->bi_vcnt, i, bio); + /* + * Clear the pointer so that another bio will + * be allocated with pscsi_get_bio() above, the + * current bio has already been set *tbio and + * bio->bi_next. + */ + bio = NULL; + } + + page++; + len -= bytes; + data_len -= bytes; + off = 0; + } + } + /* + * Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND + * primary SCSI WRITE poayload mapped for struct se_task->task_sg[] + */ + if (!(bidi_read)) { + /* + * Starting with v2.6.31, call blk_make_request() passing in *hbio to + * allocate the pSCSI task a struct request. + */ + pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue, + hbio, GFP_KERNEL); + if (!(pt->pscsi_req)) { + printk(KERN_ERR "pSCSI: blk_make_request() failed\n"); + goto fail; + } + /* + * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC, + * and setup rq callback, CDB and sense. + */ + pscsi_blk_init_request(task, pt, pt->pscsi_req, 0); + + return task->task_sg_num; + } + /* + * Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND + * SCSI READ paylaod mapped for struct se_task->task_sg_bidi[] + */ + pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue, + hbio, GFP_KERNEL); + if (!(pt->pscsi_req->next_rq)) { + printk(KERN_ERR "pSCSI: blk_make_request() failed for BIDI\n"); + goto fail; + } + pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1); + + return task->task_sg_num; +fail: + while (hbio) { + bio = hbio; + hbio = hbio->bi_next; + bio->bi_next = NULL; + bio_endio(bio, 0); + } + return ret; +} + +static int pscsi_map_task_SG(struct se_task *task) +{ + int ret; + + /* + * Setup the main struct request for the task->task_sg[] payload + */ + + ret = __pscsi_map_task_SG(task, task->task_sg, task->task_sg_num, 0); + if (ret >= 0 && task->task_sg_bidi) { + /* + * If present, set up the extra BIDI-COMMAND SCSI READ + * struct request and payload. + */ + ret = __pscsi_map_task_SG(task, task->task_sg_bidi, + task->task_sg_num, 1); + } + + if (ret < 0) + return PYX_TRANSPORT_LU_COMM_FAILURE; + return 0; +} + +/* pscsi_map_task_non_SG(): + * + * + */ +static int pscsi_map_task_non_SG(struct se_task *task) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr; + int ret = 0; + + if (pscsi_blk_get_request(task) < 0) + return PYX_TRANSPORT_LU_COMM_FAILURE; + + if (!task->task_size) + return 0; + + ret = blk_rq_map_kern(pdv->pdv_sd->request_queue, + pt->pscsi_req, T_TASK(cmd)->t_task_buf, + task->task_size, GFP_KERNEL); + if (ret < 0) { + printk(KERN_ERR "PSCSI: blk_rq_map_kern() failed: %d\n", ret); + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + return 0; +} + +static int pscsi_CDB_none(struct se_task *task) +{ + return pscsi_blk_get_request(task); +} + +/* pscsi_get_cdb(): + * + * + */ +static unsigned char *pscsi_get_cdb(struct se_task *task) +{ + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + + return pt->pscsi_cdb; +} + +/* pscsi_get_sense_buffer(): + * + * + */ +static unsigned char *pscsi_get_sense_buffer(struct se_task *task) +{ + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + + return (unsigned char *)&pt->pscsi_sense[0]; +} + +/* pscsi_get_device_rev(): + * + * + */ +static u32 pscsi_get_device_rev(struct se_device *dev) +{ + struct pscsi_dev_virt *pdv = dev->dev_ptr; + struct scsi_device *sd = pdv->pdv_sd; + + return (sd->scsi_level - 1) ? sd->scsi_level - 1 : 1; +} + +/* pscsi_get_device_type(): + * + * + */ +static u32 pscsi_get_device_type(struct se_device *dev) +{ + struct pscsi_dev_virt *pdv = dev->dev_ptr; + struct scsi_device *sd = pdv->pdv_sd; + + return sd->type; +} + +static sector_t pscsi_get_blocks(struct se_device *dev) +{ + struct pscsi_dev_virt *pdv = dev->dev_ptr; + + if (pdv->pdv_bd && pdv->pdv_bd->bd_part) + return pdv->pdv_bd->bd_part->nr_sects; + + dump_stack(); + return 0; +} + +/* pscsi_handle_SAM_STATUS_failures(): + * + * + */ +static inline void pscsi_process_SAM_status( + struct se_task *task, + struct pscsi_plugin_task *pt) +{ + task->task_scsi_status = status_byte(pt->pscsi_result); + if ((task->task_scsi_status)) { + task->task_scsi_status <<= 1; + printk(KERN_INFO "PSCSI Status Byte exception at task: %p CDB:" + " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0], + pt->pscsi_result); + } + + switch (host_byte(pt->pscsi_result)) { + case DID_OK: + transport_complete_task(task, (!task->task_scsi_status)); + break; + default: + printk(KERN_INFO "PSCSI Host Byte exception at task: %p CDB:" + " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0], + pt->pscsi_result); + task->task_scsi_status = SAM_STAT_CHECK_CONDITION; + task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + TASK_CMD(task)->transport_error_status = + PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + transport_complete_task(task, 0); + break; + } + + return; +} + +static void pscsi_req_done(struct request *req, int uptodate) +{ + struct se_task *task = req->end_io_data; + struct pscsi_plugin_task *pt = PSCSI_TASK(task); + + pt->pscsi_result = req->errors; + pt->pscsi_resid = req->resid_len; + + pscsi_process_SAM_status(task, pt); + /* + * Release BIDI-READ if present + */ + if (req->next_rq != NULL) + __blk_put_request(req->q, req->next_rq); + + __blk_put_request(req->q, req); + pt->pscsi_req = NULL; +} + +static struct se_subsystem_api pscsi_template = { + .name = "pscsi", + .owner = THIS_MODULE, + .transport_type = TRANSPORT_PLUGIN_PHBA_PDEV, + .cdb_none = pscsi_CDB_none, + .map_task_non_SG = pscsi_map_task_non_SG, + .map_task_SG = pscsi_map_task_SG, + .attach_hba = pscsi_attach_hba, + .detach_hba = pscsi_detach_hba, + .pmode_enable_hba = pscsi_pmode_enable_hba, + .allocate_virtdevice = pscsi_allocate_virtdevice, + .create_virtdevice = pscsi_create_virtdevice, + .free_device = pscsi_free_device, + .transport_complete = pscsi_transport_complete, + .alloc_task = pscsi_alloc_task, + .do_task = pscsi_do_task, + .free_task = pscsi_free_task, + .check_configfs_dev_params = pscsi_check_configfs_dev_params, + .set_configfs_dev_params = pscsi_set_configfs_dev_params, + .show_configfs_dev_params = pscsi_show_configfs_dev_params, + .get_cdb = pscsi_get_cdb, + .get_sense_buffer = pscsi_get_sense_buffer, + .get_device_rev = pscsi_get_device_rev, + .get_device_type = pscsi_get_device_type, + .get_blocks = pscsi_get_blocks, +}; + +static int __init pscsi_module_init(void) +{ + return transport_subsystem_register(&pscsi_template); +} + +static void pscsi_module_exit(void) +{ + transport_subsystem_release(&pscsi_template); +} + +MODULE_DESCRIPTION("TCM PSCSI subsystem plugin"); +MODULE_AUTHOR("nab@Linux-iSCSI.org"); +MODULE_LICENSE("GPL"); + +module_init(pscsi_module_init); +module_exit(pscsi_module_exit); diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h new file mode 100644 index 000000000000..a4cd5d352c3a --- /dev/null +++ b/drivers/target/target_core_pscsi.h @@ -0,0 +1,65 @@ +#ifndef TARGET_CORE_PSCSI_H +#define TARGET_CORE_PSCSI_H + +#define PSCSI_VERSION "v4.0" +#define PSCSI_VIRTUAL_HBA_DEPTH 2048 + +/* used in pscsi_find_alloc_len() */ +#ifndef INQUIRY_DATA_SIZE +#define INQUIRY_DATA_SIZE 0x24 +#endif + +/* used in pscsi_add_device_to_list() */ +#define PSCSI_DEFAULT_QUEUEDEPTH 1 + +#define PS_RETRY 5 +#define PS_TIMEOUT_DISK (15*HZ) +#define PS_TIMEOUT_OTHER (500*HZ) + +#include +#include +#include +#include +#include + +struct pscsi_plugin_task { + struct se_task pscsi_task; + unsigned char *pscsi_cdb; + unsigned char __pscsi_cdb[TCM_MAX_COMMAND_SIZE]; + unsigned char pscsi_sense[SCSI_SENSE_BUFFERSIZE]; + int pscsi_direction; + int pscsi_result; + u32 pscsi_resid; + struct request *pscsi_req; +} ____cacheline_aligned; + +#define PDF_HAS_CHANNEL_ID 0x01 +#define PDF_HAS_TARGET_ID 0x02 +#define PDF_HAS_LUN_ID 0x04 +#define PDF_HAS_VPD_UNIT_SERIAL 0x08 +#define PDF_HAS_VPD_DEV_IDENT 0x10 +#define PDF_HAS_VIRT_HOST_ID 0x20 + +struct pscsi_dev_virt { + int pdv_flags; + int pdv_host_id; + int pdv_channel_id; + int pdv_target_id; + int pdv_lun_id; + struct block_device *pdv_bd; + struct scsi_device *pdv_sd; + struct se_hba *pdv_se_hba; +} ____cacheline_aligned; + +typedef enum phv_modes { + PHV_VIRUTAL_HOST_ID, + PHV_LLD_SCSI_HOST_NO +} phv_modes_t; + +struct pscsi_hba_virt { + int phv_host_id; + phv_modes_t phv_mode; + struct Scsi_Host *phv_lld_host; +} ____cacheline_aligned; + +#endif /*** TARGET_CORE_PSCSI_H ***/ diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c new file mode 100644 index 000000000000..979aebf20019 --- /dev/null +++ b/drivers/target/target_core_rd.c @@ -0,0 +1,1091 @@ +/******************************************************************************* + * Filename: target_core_rd.c + * + * This file contains the Storage Engine <-> Ramdisk transport + * specific functions. + * + * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include + +#include "target_core_rd.h" + +static struct se_subsystem_api rd_dr_template; +static struct se_subsystem_api rd_mcp_template; + +/* #define DEBUG_RAMDISK_MCP */ +/* #define DEBUG_RAMDISK_DR */ + +/* rd_attach_hba(): (Part of se_subsystem_api_t template) + * + * + */ +static int rd_attach_hba(struct se_hba *hba, u32 host_id) +{ + struct rd_host *rd_host; + + rd_host = kzalloc(sizeof(struct rd_host), GFP_KERNEL); + if (!(rd_host)) { + printk(KERN_ERR "Unable to allocate memory for struct rd_host\n"); + return -ENOMEM; + } + + rd_host->rd_host_id = host_id; + + atomic_set(&hba->left_queue_depth, RD_HBA_QUEUE_DEPTH); + atomic_set(&hba->max_queue_depth, RD_HBA_QUEUE_DEPTH); + hba->hba_ptr = (void *) rd_host; + + printk(KERN_INFO "CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on" + " Generic Target Core Stack %s\n", hba->hba_id, + RD_HBA_VERSION, TARGET_CORE_MOD_VERSION); + printk(KERN_INFO "CORE_HBA[%d] - Attached Ramdisk HBA: %u to Generic" + " Target Core TCQ Depth: %d MaxSectors: %u\n", hba->hba_id, + rd_host->rd_host_id, atomic_read(&hba->max_queue_depth), + RD_MAX_SECTORS); + + return 0; +} + +static void rd_detach_hba(struct se_hba *hba) +{ + struct rd_host *rd_host = hba->hba_ptr; + + printk(KERN_INFO "CORE_HBA[%d] - Detached Ramdisk HBA: %u from" + " Generic Target Core\n", hba->hba_id, rd_host->rd_host_id); + + kfree(rd_host); + hba->hba_ptr = NULL; +} + +/* rd_release_device_space(): + * + * + */ +static void rd_release_device_space(struct rd_dev *rd_dev) +{ + u32 i, j, page_count = 0, sg_per_table; + struct rd_dev_sg_table *sg_table; + struct page *pg; + struct scatterlist *sg; + + if (!rd_dev->sg_table_array || !rd_dev->sg_table_count) + return; + + sg_table = rd_dev->sg_table_array; + + for (i = 0; i < rd_dev->sg_table_count; i++) { + sg = sg_table[i].sg_table; + sg_per_table = sg_table[i].rd_sg_count; + + for (j = 0; j < sg_per_table; j++) { + pg = sg_page(&sg[j]); + if ((pg)) { + __free_page(pg); + page_count++; + } + } + + kfree(sg); + } + + printk(KERN_INFO "CORE_RD[%u] - Released device space for Ramdisk" + " Device ID: %u, pages %u in %u tables total bytes %lu\n", + rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count, + rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE); + + kfree(sg_table); + rd_dev->sg_table_array = NULL; + rd_dev->sg_table_count = 0; +} + + +/* rd_build_device_space(): + * + * + */ +static int rd_build_device_space(struct rd_dev *rd_dev) +{ + u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed; + u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / + sizeof(struct scatterlist)); + struct rd_dev_sg_table *sg_table; + struct page *pg; + struct scatterlist *sg; + + if (rd_dev->rd_page_count <= 0) { + printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n", + rd_dev->rd_page_count); + return -1; + } + total_sg_needed = rd_dev->rd_page_count; + + sg_tables = (total_sg_needed / max_sg_per_table) + 1; + + sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL); + if (!(sg_table)) { + printk(KERN_ERR "Unable to allocate memory for Ramdisk" + " scatterlist tables\n"); + return -1; + } + + rd_dev->sg_table_array = sg_table; + rd_dev->sg_table_count = sg_tables; + + while (total_sg_needed) { + sg_per_table = (total_sg_needed > max_sg_per_table) ? + max_sg_per_table : total_sg_needed; + + sg = kzalloc(sg_per_table * sizeof(struct scatterlist), + GFP_KERNEL); + if (!(sg)) { + printk(KERN_ERR "Unable to allocate scatterlist array" + " for struct rd_dev\n"); + return -1; + } + + sg_init_table((struct scatterlist *)&sg[0], sg_per_table); + + sg_table[i].sg_table = sg; + sg_table[i].rd_sg_count = sg_per_table; + sg_table[i].page_start_offset = page_offset; + sg_table[i++].page_end_offset = (page_offset + sg_per_table) + - 1; + + for (j = 0; j < sg_per_table; j++) { + pg = alloc_pages(GFP_KERNEL, 0); + if (!(pg)) { + printk(KERN_ERR "Unable to allocate scatterlist" + " pages for struct rd_dev_sg_table\n"); + return -1; + } + sg_assign_page(&sg[j], pg); + sg[j].length = PAGE_SIZE; + } + + page_offset += sg_per_table; + total_sg_needed -= sg_per_table; + } + + printk(KERN_INFO "CORE_RD[%u] - Built Ramdisk Device ID: %u space of" + " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id, + rd_dev->rd_dev_id, rd_dev->rd_page_count, + rd_dev->sg_table_count); + + return 0; +} + +static void *rd_allocate_virtdevice( + struct se_hba *hba, + const char *name, + int rd_direct) +{ + struct rd_dev *rd_dev; + struct rd_host *rd_host = hba->hba_ptr; + + rd_dev = kzalloc(sizeof(struct rd_dev), GFP_KERNEL); + if (!(rd_dev)) { + printk(KERN_ERR "Unable to allocate memory for struct rd_dev\n"); + return NULL; + } + + rd_dev->rd_host = rd_host; + rd_dev->rd_direct = rd_direct; + + return rd_dev; +} + +static void *rd_DIRECT_allocate_virtdevice(struct se_hba *hba, const char *name) +{ + return rd_allocate_virtdevice(hba, name, 1); +} + +static void *rd_MEMCPY_allocate_virtdevice(struct se_hba *hba, const char *name) +{ + return rd_allocate_virtdevice(hba, name, 0); +} + +/* rd_create_virtdevice(): + * + * + */ +static struct se_device *rd_create_virtdevice( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + void *p, + int rd_direct) +{ + struct se_device *dev; + struct se_dev_limits dev_limits; + struct rd_dev *rd_dev = p; + struct rd_host *rd_host = hba->hba_ptr; + int dev_flags = 0; + char prod[16], rev[4]; + + memset(&dev_limits, 0, sizeof(struct se_dev_limits)); + + if (rd_build_device_space(rd_dev) < 0) + goto fail; + + snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); + snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION : + RD_MCP_VERSION); + + dev_limits.limits.logical_block_size = RD_BLOCKSIZE; + dev_limits.limits.max_hw_sectors = RD_MAX_SECTORS; + dev_limits.limits.max_sectors = RD_MAX_SECTORS; + dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; + dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH; + + dev = transport_add_device_to_core_hba(hba, + (rd_dev->rd_direct) ? &rd_dr_template : + &rd_mcp_template, se_dev, dev_flags, (void *)rd_dev, + &dev_limits, prod, rev); + if (!(dev)) + goto fail; + + rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++; + rd_dev->rd_queue_depth = dev->queue_depth; + + printk(KERN_INFO "CORE_RD[%u] - Added TCM %s Ramdisk Device ID: %u of" + " %u pages in %u tables, %lu total bytes\n", + rd_host->rd_host_id, (!rd_dev->rd_direct) ? "MEMCPY" : + "DIRECT", rd_dev->rd_dev_id, rd_dev->rd_page_count, + rd_dev->sg_table_count, + (unsigned long)(rd_dev->rd_page_count * PAGE_SIZE)); + + return dev; + +fail: + rd_release_device_space(rd_dev); + return NULL; +} + +static struct se_device *rd_DIRECT_create_virtdevice( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + void *p) +{ + return rd_create_virtdevice(hba, se_dev, p, 1); +} + +static struct se_device *rd_MEMCPY_create_virtdevice( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + void *p) +{ + return rd_create_virtdevice(hba, se_dev, p, 0); +} + +/* rd_free_device(): (Part of se_subsystem_api_t template) + * + * + */ +static void rd_free_device(void *p) +{ + struct rd_dev *rd_dev = p; + + rd_release_device_space(rd_dev); + kfree(rd_dev); +} + +static inline struct rd_request *RD_REQ(struct se_task *task) +{ + return container_of(task, struct rd_request, rd_task); +} + +static struct se_task * +rd_alloc_task(struct se_cmd *cmd) +{ + struct rd_request *rd_req; + + rd_req = kzalloc(sizeof(struct rd_request), GFP_KERNEL); + if (!rd_req) { + printk(KERN_ERR "Unable to allocate struct rd_request\n"); + return NULL; + } + rd_req->rd_dev = SE_DEV(cmd)->dev_ptr; + + return &rd_req->rd_task; +} + +/* rd_get_sg_table(): + * + * + */ +static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) +{ + u32 i; + struct rd_dev_sg_table *sg_table; + + for (i = 0; i < rd_dev->sg_table_count; i++) { + sg_table = &rd_dev->sg_table_array[i]; + if ((sg_table->page_start_offset <= page) && + (sg_table->page_end_offset >= page)) + return sg_table; + } + + printk(KERN_ERR "Unable to locate struct rd_dev_sg_table for page: %u\n", + page); + + return NULL; +} + +/* rd_MEMCPY_read(): + * + * + */ +static int rd_MEMCPY_read(struct rd_request *req) +{ + struct se_task *task = &req->rd_task; + struct rd_dev *dev = req->rd_dev; + struct rd_dev_sg_table *table; + struct scatterlist *sg_d, *sg_s; + void *dst, *src; + u32 i = 0, j = 0, dst_offset = 0, src_offset = 0; + u32 length, page_end = 0, table_sg_end; + u32 rd_offset = req->rd_offset; + + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + table_sg_end = (table->page_end_offset - req->rd_page); + sg_d = task->task_sg; + sg_s = &table->sg_table[req->rd_page - table->page_start_offset]; +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "RD[%u]: Read LBA: %llu, Size: %u Page: %u, Offset:" + " %u\n", dev->rd_dev_id, task->task_lba, req->rd_size, + req->rd_page, req->rd_offset); +#endif + src_offset = rd_offset; + + while (req->rd_size) { + if ((sg_d[i].length - dst_offset) < + (sg_s[j].length - src_offset)) { + length = (sg_d[i].length - dst_offset); +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "Step 1 - sg_d[%d]: %p length: %d" + " offset: %u sg_s[%d].length: %u\n", i, + &sg_d[i], sg_d[i].length, sg_d[i].offset, j, + sg_s[j].length); + printk(KERN_INFO "Step 1 - length: %u dst_offset: %u" + " src_offset: %u\n", length, dst_offset, + src_offset); +#endif + if (length > req->rd_size) + length = req->rd_size; + + dst = sg_virt(&sg_d[i++]) + dst_offset; + if (!dst) + BUG(); + + src = sg_virt(&sg_s[j]) + src_offset; + if (!src) + BUG(); + + dst_offset = 0; + src_offset = length; + page_end = 0; + } else { + length = (sg_s[j].length - src_offset); +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "Step 2 - sg_d[%d]: %p length: %d" + " offset: %u sg_s[%d].length: %u\n", i, + &sg_d[i], sg_d[i].length, sg_d[i].offset, + j, sg_s[j].length); + printk(KERN_INFO "Step 2 - length: %u dst_offset: %u" + " src_offset: %u\n", length, dst_offset, + src_offset); +#endif + if (length > req->rd_size) + length = req->rd_size; + + dst = sg_virt(&sg_d[i]) + dst_offset; + if (!dst) + BUG(); + + if (sg_d[i].length == length) { + i++; + dst_offset = 0; + } else + dst_offset = length; + + src = sg_virt(&sg_s[j++]) + src_offset; + if (!src) + BUG(); + + src_offset = 0; + page_end = 1; + } + + memcpy(dst, src, length); + +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "page: %u, remaining size: %u, length: %u," + " i: %u, j: %u\n", req->rd_page, + (req->rd_size - length), length, i, j); +#endif + req->rd_size -= length; + if (!(req->rd_size)) + return 0; + + if (!page_end) + continue; + + if (++req->rd_page <= table->page_end_offset) { +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "page: %u in same page table\n", + req->rd_page); +#endif + continue; + } +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "getting new page table for page: %u\n", + req->rd_page); +#endif + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + sg_s = &table->sg_table[j = 0]; + } + + return 0; +} + +/* rd_MEMCPY_write(): + * + * + */ +static int rd_MEMCPY_write(struct rd_request *req) +{ + struct se_task *task = &req->rd_task; + struct rd_dev *dev = req->rd_dev; + struct rd_dev_sg_table *table; + struct scatterlist *sg_d, *sg_s; + void *dst, *src; + u32 i = 0, j = 0, dst_offset = 0, src_offset = 0; + u32 length, page_end = 0, table_sg_end; + u32 rd_offset = req->rd_offset; + + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + table_sg_end = (table->page_end_offset - req->rd_page); + sg_d = &table->sg_table[req->rd_page - table->page_start_offset]; + sg_s = task->task_sg; +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "RD[%d] Write LBA: %llu, Size: %u, Page: %u," + " Offset: %u\n", dev->rd_dev_id, task->task_lba, req->rd_size, + req->rd_page, req->rd_offset); +#endif + dst_offset = rd_offset; + + while (req->rd_size) { + if ((sg_s[i].length - src_offset) < + (sg_d[j].length - dst_offset)) { + length = (sg_s[i].length - src_offset); +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "Step 1 - sg_s[%d]: %p length: %d" + " offset: %d sg_d[%d].length: %u\n", i, + &sg_s[i], sg_s[i].length, sg_s[i].offset, + j, sg_d[j].length); + printk(KERN_INFO "Step 1 - length: %u src_offset: %u" + " dst_offset: %u\n", length, src_offset, + dst_offset); +#endif + if (length > req->rd_size) + length = req->rd_size; + + src = sg_virt(&sg_s[i++]) + src_offset; + if (!src) + BUG(); + + dst = sg_virt(&sg_d[j]) + dst_offset; + if (!dst) + BUG(); + + src_offset = 0; + dst_offset = length; + page_end = 0; + } else { + length = (sg_d[j].length - dst_offset); +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "Step 2 - sg_s[%d]: %p length: %d" + " offset: %d sg_d[%d].length: %u\n", i, + &sg_s[i], sg_s[i].length, sg_s[i].offset, + j, sg_d[j].length); + printk(KERN_INFO "Step 2 - length: %u src_offset: %u" + " dst_offset: %u\n", length, src_offset, + dst_offset); +#endif + if (length > req->rd_size) + length = req->rd_size; + + src = sg_virt(&sg_s[i]) + src_offset; + if (!src) + BUG(); + + if (sg_s[i].length == length) { + i++; + src_offset = 0; + } else + src_offset = length; + + dst = sg_virt(&sg_d[j++]) + dst_offset; + if (!dst) + BUG(); + + dst_offset = 0; + page_end = 1; + } + + memcpy(dst, src, length); + +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "page: %u, remaining size: %u, length: %u," + " i: %u, j: %u\n", req->rd_page, + (req->rd_size - length), length, i, j); +#endif + req->rd_size -= length; + if (!(req->rd_size)) + return 0; + + if (!page_end) + continue; + + if (++req->rd_page <= table->page_end_offset) { +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "page: %u in same page table\n", + req->rd_page); +#endif + continue; + } +#ifdef DEBUG_RAMDISK_MCP + printk(KERN_INFO "getting new page table for page: %u\n", + req->rd_page); +#endif + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + sg_d = &table->sg_table[j = 0]; + } + + return 0; +} + +/* rd_MEMCPY_do_task(): (Part of se_subsystem_api_t template) + * + * + */ +static int rd_MEMCPY_do_task(struct se_task *task) +{ + struct se_device *dev = task->se_dev; + struct rd_request *req = RD_REQ(task); + unsigned long long lba; + int ret; + + req->rd_page = (task->task_lba * DEV_ATTRIB(dev)->block_size) / PAGE_SIZE; + lba = task->task_lba; + req->rd_offset = (do_div(lba, + (PAGE_SIZE / DEV_ATTRIB(dev)->block_size))) * + DEV_ATTRIB(dev)->block_size; + req->rd_size = task->task_size; + + if (task->task_data_direction == DMA_FROM_DEVICE) + ret = rd_MEMCPY_read(req); + else + ret = rd_MEMCPY_write(req); + + if (ret != 0) + return ret; + + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} + +/* rd_DIRECT_with_offset(): + * + * + */ +static int rd_DIRECT_with_offset( + struct se_task *task, + struct list_head *se_mem_list, + u32 *se_mem_cnt, + u32 *task_offset) +{ + struct rd_request *req = RD_REQ(task); + struct rd_dev *dev = req->rd_dev; + struct rd_dev_sg_table *table; + struct se_mem *se_mem; + struct scatterlist *sg_s; + u32 j = 0, set_offset = 1; + u32 get_next_table = 0, offset_length, table_sg_end; + + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + table_sg_end = (table->page_end_offset - req->rd_page); + sg_s = &table->sg_table[req->rd_page - table->page_start_offset]; +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "%s DIRECT LBA: %llu, Size: %u Page: %u, Offset: %u\n", + (task->task_data_direction == DMA_TO_DEVICE) ? + "Write" : "Read", + task->task_lba, req->rd_size, req->rd_page, req->rd_offset); +#endif + while (req->rd_size) { + se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL); + if (!(se_mem)) { + printk(KERN_ERR "Unable to allocate struct se_mem\n"); + return -1; + } + INIT_LIST_HEAD(&se_mem->se_list); + + if (set_offset) { + offset_length = sg_s[j].length - req->rd_offset; + if (offset_length > req->rd_size) + offset_length = req->rd_size; + + se_mem->se_page = sg_page(&sg_s[j++]); + se_mem->se_off = req->rd_offset; + se_mem->se_len = offset_length; + + set_offset = 0; + get_next_table = (j > table_sg_end); + goto check_eot; + } + + offset_length = (req->rd_size < req->rd_offset) ? + req->rd_size : req->rd_offset; + + se_mem->se_page = sg_page(&sg_s[j]); + se_mem->se_len = offset_length; + + set_offset = 1; + +check_eot: +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "page: %u, size: %u, offset_length: %u, j: %u" + " se_mem: %p, se_page: %p se_off: %u se_len: %u\n", + req->rd_page, req->rd_size, offset_length, j, se_mem, + se_mem->se_page, se_mem->se_off, se_mem->se_len); +#endif + list_add_tail(&se_mem->se_list, se_mem_list); + (*se_mem_cnt)++; + + req->rd_size -= offset_length; + if (!(req->rd_size)) + goto out; + + if (!set_offset && !get_next_table) + continue; + + if (++req->rd_page <= table->page_end_offset) { +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "page: %u in same page table\n", + req->rd_page); +#endif + continue; + } +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "getting new page table for page: %u\n", + req->rd_page); +#endif + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + sg_s = &table->sg_table[j = 0]; + } + +out: + T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt; +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "RD_DR - Allocated %u struct se_mem segments for task\n", + *se_mem_cnt); +#endif + return 0; +} + +/* rd_DIRECT_without_offset(): + * + * + */ +static int rd_DIRECT_without_offset( + struct se_task *task, + struct list_head *se_mem_list, + u32 *se_mem_cnt, + u32 *task_offset) +{ + struct rd_request *req = RD_REQ(task); + struct rd_dev *dev = req->rd_dev; + struct rd_dev_sg_table *table; + struct se_mem *se_mem; + struct scatterlist *sg_s; + u32 length, j = 0; + + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + sg_s = &table->sg_table[req->rd_page - table->page_start_offset]; +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "%s DIRECT LBA: %llu, Size: %u, Page: %u\n", + (task->task_data_direction == DMA_TO_DEVICE) ? + "Write" : "Read", + task->task_lba, req->rd_size, req->rd_page); +#endif + while (req->rd_size) { + se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL); + if (!(se_mem)) { + printk(KERN_ERR "Unable to allocate struct se_mem\n"); + return -1; + } + INIT_LIST_HEAD(&se_mem->se_list); + + length = (req->rd_size < sg_s[j].length) ? + req->rd_size : sg_s[j].length; + + se_mem->se_page = sg_page(&sg_s[j++]); + se_mem->se_len = length; + +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "page: %u, size: %u, j: %u se_mem: %p," + " se_page: %p se_off: %u se_len: %u\n", req->rd_page, + req->rd_size, j, se_mem, se_mem->se_page, + se_mem->se_off, se_mem->se_len); +#endif + list_add_tail(&se_mem->se_list, se_mem_list); + (*se_mem_cnt)++; + + req->rd_size -= length; + if (!(req->rd_size)) + goto out; + + if (++req->rd_page <= table->page_end_offset) { +#ifdef DEBUG_RAMDISK_DR + printk("page: %u in same page table\n", + req->rd_page); +#endif + continue; + } +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "getting new page table for page: %u\n", + req->rd_page); +#endif + table = rd_get_sg_table(dev, req->rd_page); + if (!(table)) + return -1; + + sg_s = &table->sg_table[j = 0]; + } + +out: + T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt; +#ifdef DEBUG_RAMDISK_DR + printk(KERN_INFO "RD_DR - Allocated %u struct se_mem segments for task\n", + *se_mem_cnt); +#endif + return 0; +} + +/* rd_DIRECT_do_se_mem_map(): + * + * + */ +static int rd_DIRECT_do_se_mem_map( + struct se_task *task, + struct list_head *se_mem_list, + void *in_mem, + struct se_mem *in_se_mem, + struct se_mem **out_se_mem, + u32 *se_mem_cnt, + u32 *task_offset_in) +{ + struct se_cmd *cmd = task->task_se_cmd; + struct rd_request *req = RD_REQ(task); + u32 task_offset = *task_offset_in; + unsigned long long lba; + int ret; + + req->rd_page = ((task->task_lba * DEV_ATTRIB(task->se_dev)->block_size) / + PAGE_SIZE); + lba = task->task_lba; + req->rd_offset = (do_div(lba, + (PAGE_SIZE / DEV_ATTRIB(task->se_dev)->block_size))) * + DEV_ATTRIB(task->se_dev)->block_size; + req->rd_size = task->task_size; + + if (req->rd_offset) + ret = rd_DIRECT_with_offset(task, se_mem_list, se_mem_cnt, + task_offset_in); + else + ret = rd_DIRECT_without_offset(task, se_mem_list, se_mem_cnt, + task_offset_in); + + if (ret < 0) + return ret; + + if (CMD_TFO(cmd)->task_sg_chaining == 0) + return 0; + /* + * Currently prevent writers from multiple HW fabrics doing + * pci_map_sg() to RD_DR's internal scatterlist memory. + */ + if (cmd->data_direction == DMA_TO_DEVICE) { + printk(KERN_ERR "DMA_TO_DEVICE not supported for" + " RAMDISK_DR with task_sg_chaining=1\n"); + return -1; + } + /* + * Special case for if task_sg_chaining is enabled, then + * we setup struct se_task->task_sg[], as it will be used by + * transport_do_task_sg_chain() for creating chainged SGLs + * across multiple struct se_task->task_sg[]. + */ + if (!(transport_calc_sg_num(task, + list_entry(T_TASK(cmd)->t_mem_list->next, + struct se_mem, se_list), + task_offset))) + return -1; + + return transport_map_mem_to_sg(task, se_mem_list, task->task_sg, + list_entry(T_TASK(cmd)->t_mem_list->next, + struct se_mem, se_list), + out_se_mem, se_mem_cnt, task_offset_in); +} + +/* rd_DIRECT_do_task(): (Part of se_subsystem_api_t template) + * + * + */ +static int rd_DIRECT_do_task(struct se_task *task) +{ + /* + * At this point the locally allocated RD tables have been mapped + * to struct se_mem elements in rd_DIRECT_do_se_mem_map(). + */ + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + + return PYX_TRANSPORT_SENT_TO_TRANSPORT; +} + +/* rd_free_task(): (Part of se_subsystem_api_t template) + * + * + */ +static void rd_free_task(struct se_task *task) +{ + kfree(RD_REQ(task)); +} + +enum { + Opt_rd_pages, Opt_err +}; + +static match_table_t tokens = { + {Opt_rd_pages, "rd_pages=%d"}, + {Opt_err, NULL} +}; + +static ssize_t rd_set_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + const char *page, + ssize_t count) +{ + struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; + char *orig, *ptr, *opts; + substring_t args[MAX_OPT_ARGS]; + int ret = 0, arg, token; + + opts = kstrdup(page, GFP_KERNEL); + if (!opts) + return -ENOMEM; + + orig = opts; + + while ((ptr = strsep(&opts, ",")) != NULL) { + if (!*ptr) + continue; + + token = match_token(ptr, tokens, args); + switch (token) { + case Opt_rd_pages: + match_int(args, &arg); + rd_dev->rd_page_count = arg; + printk(KERN_INFO "RAMDISK: Referencing Page" + " Count: %u\n", rd_dev->rd_page_count); + rd_dev->rd_flags |= RDF_HAS_PAGE_COUNT; + break; + default: + break; + } + } + + kfree(orig); + return (!ret) ? count : ret; +} + +static ssize_t rd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) +{ + struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; + + if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) { + printk(KERN_INFO "Missing rd_pages= parameter\n"); + return -1; + } + + return 0; +} + +static ssize_t rd_show_configfs_dev_params( + struct se_hba *hba, + struct se_subsystem_dev *se_dev, + char *b) +{ + struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; + ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: %s\n", + rd_dev->rd_dev_id, (rd_dev->rd_direct) ? + "rd_direct" : "rd_mcp"); + bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu" + " SG_table_count: %u\n", rd_dev->rd_page_count, + PAGE_SIZE, rd_dev->sg_table_count); + return bl; +} + +/* rd_get_cdb(): (Part of se_subsystem_api_t template) + * + * + */ +static unsigned char *rd_get_cdb(struct se_task *task) +{ + struct rd_request *req = RD_REQ(task); + + return req->rd_scsi_cdb; +} + +static u32 rd_get_device_rev(struct se_device *dev) +{ + return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */ +} + +static u32 rd_get_device_type(struct se_device *dev) +{ + return TYPE_DISK; +} + +static sector_t rd_get_blocks(struct se_device *dev) +{ + struct rd_dev *rd_dev = dev->dev_ptr; + unsigned long long blocks_long = ((rd_dev->rd_page_count * PAGE_SIZE) / + DEV_ATTRIB(dev)->block_size) - 1; + + return blocks_long; +} + +static struct se_subsystem_api rd_dr_template = { + .name = "rd_dr", + .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, + .attach_hba = rd_attach_hba, + .detach_hba = rd_detach_hba, + .allocate_virtdevice = rd_DIRECT_allocate_virtdevice, + .create_virtdevice = rd_DIRECT_create_virtdevice, + .free_device = rd_free_device, + .alloc_task = rd_alloc_task, + .do_task = rd_DIRECT_do_task, + .free_task = rd_free_task, + .check_configfs_dev_params = rd_check_configfs_dev_params, + .set_configfs_dev_params = rd_set_configfs_dev_params, + .show_configfs_dev_params = rd_show_configfs_dev_params, + .get_cdb = rd_get_cdb, + .get_device_rev = rd_get_device_rev, + .get_device_type = rd_get_device_type, + .get_blocks = rd_get_blocks, + .do_se_mem_map = rd_DIRECT_do_se_mem_map, +}; + +static struct se_subsystem_api rd_mcp_template = { + .name = "rd_mcp", + .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, + .attach_hba = rd_attach_hba, + .detach_hba = rd_detach_hba, + .allocate_virtdevice = rd_MEMCPY_allocate_virtdevice, + .create_virtdevice = rd_MEMCPY_create_virtdevice, + .free_device = rd_free_device, + .alloc_task = rd_alloc_task, + .do_task = rd_MEMCPY_do_task, + .free_task = rd_free_task, + .check_configfs_dev_params = rd_check_configfs_dev_params, + .set_configfs_dev_params = rd_set_configfs_dev_params, + .show_configfs_dev_params = rd_show_configfs_dev_params, + .get_cdb = rd_get_cdb, + .get_device_rev = rd_get_device_rev, + .get_device_type = rd_get_device_type, + .get_blocks = rd_get_blocks, +}; + +int __init rd_module_init(void) +{ + int ret; + + ret = transport_subsystem_register(&rd_dr_template); + if (ret < 0) + return ret; + + ret = transport_subsystem_register(&rd_mcp_template); + if (ret < 0) { + transport_subsystem_release(&rd_dr_template); + return ret; + } + + return 0; +} + +void rd_module_exit(void) +{ + transport_subsystem_release(&rd_dr_template); + transport_subsystem_release(&rd_mcp_template); +} diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h new file mode 100644 index 000000000000..13badfbaf9c0 --- /dev/null +++ b/drivers/target/target_core_rd.h @@ -0,0 +1,73 @@ +#ifndef TARGET_CORE_RD_H +#define TARGET_CORE_RD_H + +#define RD_HBA_VERSION "v4.0" +#define RD_DR_VERSION "4.0" +#define RD_MCP_VERSION "4.0" + +/* Largest piece of memory kmalloc can allocate */ +#define RD_MAX_ALLOCATION_SIZE 65536 +/* Maximum queuedepth for the Ramdisk HBA */ +#define RD_HBA_QUEUE_DEPTH 256 +#define RD_DEVICE_QUEUE_DEPTH 32 +#define RD_MAX_DEVICE_QUEUE_DEPTH 128 +#define RD_BLOCKSIZE 512 +#define RD_MAX_SECTORS 1024 + +extern struct kmem_cache *se_mem_cache; + +/* Used in target_core_init_configfs() for virtual LUN 0 access */ +int __init rd_module_init(void); +void rd_module_exit(void); + +#define RRF_EMULATE_CDB 0x01 +#define RRF_GOT_LBA 0x02 + +struct rd_request { + struct se_task rd_task; + + /* SCSI CDB from iSCSI Command PDU */ + unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE]; + /* Offset from start of page */ + u32 rd_offset; + /* Starting page in Ramdisk for request */ + u32 rd_page; + /* Total number of pages needed for request */ + u32 rd_page_count; + /* Scatterlist count */ + u32 rd_size; + /* Ramdisk device */ + struct rd_dev *rd_dev; +} ____cacheline_aligned; + +struct rd_dev_sg_table { + u32 page_start_offset; + u32 page_end_offset; + u32 rd_sg_count; + struct scatterlist *sg_table; +} ____cacheline_aligned; + +#define RDF_HAS_PAGE_COUNT 0x01 + +struct rd_dev { + int rd_direct; + u32 rd_flags; + /* Unique Ramdisk Device ID in Ramdisk HBA */ + u32 rd_dev_id; + /* Total page count for ramdisk device */ + u32 rd_page_count; + /* Number of SG tables in sg_table_array */ + u32 sg_table_count; + u32 rd_queue_depth; + /* Array of rd_dev_sg_table_t containing scatterlists */ + struct rd_dev_sg_table *sg_table_array; + /* Ramdisk HBA device is connected to */ + struct rd_host *rd_host; +} ____cacheline_aligned; + +struct rd_host { + u32 rd_host_dev_id_count; + u32 rd_host_id; /* Unique Ramdisk Host ID */ +} ____cacheline_aligned; + +#endif /* TARGET_CORE_RD_H */ diff --git a/drivers/target/target_core_scdb.c b/drivers/target/target_core_scdb.c new file mode 100644 index 000000000000..dc6fed037ab3 --- /dev/null +++ b/drivers/target/target_core_scdb.c @@ -0,0 +1,105 @@ +/******************************************************************************* + * Filename: target_core_scdb.c + * + * This file contains the generic target engine Split CDB related functions. + * + * Copyright (c) 2004-2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 "target_core_scdb.h" + +/* split_cdb_XX_6(): + * + * 21-bit LBA w/ 8-bit SECTORS + */ +void split_cdb_XX_6( + unsigned long long lba, + u32 *sectors, + unsigned char *cdb) +{ + cdb[1] = (lba >> 16) & 0x1f; + cdb[2] = (lba >> 8) & 0xff; + cdb[3] = lba & 0xff; + cdb[4] = *sectors & 0xff; +} + +/* split_cdb_XX_10(): + * + * 32-bit LBA w/ 16-bit SECTORS + */ +void split_cdb_XX_10( + unsigned long long lba, + u32 *sectors, + unsigned char *cdb) +{ + put_unaligned_be32(lba, &cdb[2]); + put_unaligned_be16(*sectors, &cdb[7]); +} + +/* split_cdb_XX_12(): + * + * 32-bit LBA w/ 32-bit SECTORS + */ +void split_cdb_XX_12( + unsigned long long lba, + u32 *sectors, + unsigned char *cdb) +{ + put_unaligned_be32(lba, &cdb[2]); + put_unaligned_be32(*sectors, &cdb[6]); +} + +/* split_cdb_XX_16(): + * + * 64-bit LBA w/ 32-bit SECTORS + */ +void split_cdb_XX_16( + unsigned long long lba, + u32 *sectors, + unsigned char *cdb) +{ + put_unaligned_be64(lba, &cdb[2]); + put_unaligned_be32(*sectors, &cdb[10]); +} + +/* + * split_cdb_XX_32(): + * + * 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32 + */ +void split_cdb_XX_32( + unsigned long long lba, + u32 *sectors, + unsigned char *cdb) +{ + put_unaligned_be64(lba, &cdb[12]); + put_unaligned_be32(*sectors, &cdb[28]); +} diff --git a/drivers/target/target_core_scdb.h b/drivers/target/target_core_scdb.h new file mode 100644 index 000000000000..98cd1c01ed83 --- /dev/null +++ b/drivers/target/target_core_scdb.h @@ -0,0 +1,10 @@ +#ifndef TARGET_CORE_SCDB_H +#define TARGET_CORE_SCDB_H + +extern void split_cdb_XX_6(unsigned long long, u32 *, unsigned char *); +extern void split_cdb_XX_10(unsigned long long, u32 *, unsigned char *); +extern void split_cdb_XX_12(unsigned long long, u32 *, unsigned char *); +extern void split_cdb_XX_16(unsigned long long, u32 *, unsigned char *); +extern void split_cdb_XX_32(unsigned long long, u32 *, unsigned char *); + +#endif /* TARGET_CORE_SCDB_H */ diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c new file mode 100644 index 000000000000..158cecbec718 --- /dev/null +++ b/drivers/target/target_core_tmr.c @@ -0,0 +1,404 @@ +/******************************************************************************* + * Filename: target_core_tmr.c + * + * This file contains SPC-3 task management infrastructure + * + * Copyright (c) 2009,2010 Rising Tide Systems + * Copyright (c) 2009,2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include + +#include "target_core_alua.h" +#include "target_core_pr.h" + +#define DEBUG_LUN_RESET +#ifdef DEBUG_LUN_RESET +#define DEBUG_LR(x...) printk(KERN_INFO x) +#else +#define DEBUG_LR(x...) +#endif + +struct se_tmr_req *core_tmr_alloc_req( + struct se_cmd *se_cmd, + void *fabric_tmr_ptr, + u8 function) +{ + struct se_tmr_req *tmr; + + tmr = kmem_cache_zalloc(se_tmr_req_cache, GFP_KERNEL); + if (!(tmr)) { + printk(KERN_ERR "Unable to allocate struct se_tmr_req\n"); + return ERR_PTR(-ENOMEM); + } + tmr->task_cmd = se_cmd; + tmr->fabric_tmr_ptr = fabric_tmr_ptr; + tmr->function = function; + INIT_LIST_HEAD(&tmr->tmr_list); + + return tmr; +} +EXPORT_SYMBOL(core_tmr_alloc_req); + +void core_tmr_release_req( + struct se_tmr_req *tmr) +{ + struct se_device *dev = tmr->tmr_dev; + + spin_lock(&dev->se_tmr_lock); + list_del(&tmr->tmr_list); + kmem_cache_free(se_tmr_req_cache, tmr); + spin_unlock(&dev->se_tmr_lock); +} + +static void core_tmr_handle_tas_abort( + struct se_node_acl *tmr_nacl, + struct se_cmd *cmd, + int tas, + int fe_count) +{ + if (!(fe_count)) { + transport_cmd_finish_abort(cmd, 1); + return; + } + /* + * TASK ABORTED status (TAS) bit support + */ + if (((tmr_nacl != NULL) && + (tmr_nacl == cmd->se_sess->se_node_acl)) || tas) + transport_send_task_abort(cmd); + + transport_cmd_finish_abort(cmd, 0); +} + +int core_tmr_lun_reset( + struct se_device *dev, + struct se_tmr_req *tmr, + struct list_head *preempt_and_abort_list, + struct se_cmd *prout_cmd) +{ + struct se_cmd *cmd; + struct se_queue_req *qr, *qr_tmp; + struct se_node_acl *tmr_nacl = NULL; + struct se_portal_group *tmr_tpg = NULL; + struct se_queue_obj *qobj = dev->dev_queue_obj; + struct se_tmr_req *tmr_p, *tmr_pp; + struct se_task *task, *task_tmp; + unsigned long flags; + int fe_count, state, tas; + /* + * TASK_ABORTED status bit, this is configurable via ConfigFS + * struct se_device attributes. spc4r17 section 7.4.6 Control mode page + * + * A task aborted status (TAS) bit set to zero specifies that aborted + * tasks shall be terminated by the device server without any response + * to the application client. A TAS bit set to one specifies that tasks + * aborted by the actions of an I_T nexus other than the I_T nexus on + * which the command was received shall be completed with TASK ABORTED + * status (see SAM-4). + */ + tas = DEV_ATTRIB(dev)->emulate_tas; + /* + * Determine if this se_tmr is coming from a $FABRIC_MOD + * or struct se_device passthrough.. + */ + if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) { + tmr_nacl = tmr->task_cmd->se_sess->se_node_acl; + tmr_tpg = tmr->task_cmd->se_sess->se_tpg; + if (tmr_nacl && tmr_tpg) { + DEBUG_LR("LUN_RESET: TMR caller fabric: %s" + " initiator port %s\n", + TPG_TFO(tmr_tpg)->get_fabric_name(), + tmr_nacl->initiatorname); + } + } + DEBUG_LR("LUN_RESET: %s starting for [%s], tas: %d\n", + (preempt_and_abort_list) ? "Preempt" : "TMR", + TRANSPORT(dev)->name, tas); + /* + * Release all pending and outgoing TMRs aside from the received + * LUN_RESET tmr.. + */ + spin_lock(&dev->se_tmr_lock); + list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) { + /* + * Allow the received TMR to return with FUNCTION_COMPLETE. + */ + if (tmr && (tmr_p == tmr)) + continue; + + cmd = tmr_p->task_cmd; + if (!(cmd)) { + printk(KERN_ERR "Unable to locate struct se_cmd for TMR\n"); + continue; + } + /* + * If this function was called with a valid pr_res_key + * parameter (eg: for PROUT PREEMPT_AND_ABORT service action + * skip non regisration key matching TMRs. + */ + if ((preempt_and_abort_list != NULL) && + (core_scsi3_check_cdb_abort_and_preempt( + preempt_and_abort_list, cmd) != 0)) + continue; + spin_unlock(&dev->se_tmr_lock); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (!(atomic_read(&T_TASK(cmd)->t_transport_active))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + spin_lock(&dev->se_tmr_lock); + continue; + } + if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + spin_lock(&dev->se_tmr_lock); + continue; + } + DEBUG_LR("LUN_RESET: %s releasing TMR %p Function: 0x%02x," + " Response: 0x%02x, t_state: %d\n", + (preempt_and_abort_list) ? "Preempt" : "", tmr_p, + tmr_p->function, tmr_p->response, cmd->t_state); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_cmd_finish_abort_tmr(cmd); + spin_lock(&dev->se_tmr_lock); + } + spin_unlock(&dev->se_tmr_lock); + /* + * Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status. + * This is following sam4r17, section 5.6 Aborting commands, Table 38 + * for TMR LUN_RESET: + * + * a) "Yes" indicates that each command that is aborted on an I_T nexus + * other than the one that caused the SCSI device condition is + * completed with TASK ABORTED status, if the TAS bit is set to one in + * the Control mode page (see SPC-4). "No" indicates that no status is + * returned for aborted commands. + * + * d) If the logical unit reset is caused by a particular I_T nexus + * (e.g., by a LOGICAL UNIT RESET task management function), then "yes" + * (TASK_ABORTED status) applies. + * + * Otherwise (e.g., if triggered by a hard reset), "no" + * (no TASK_ABORTED SAM status) applies. + * + * Note that this seems to be independent of TAS (Task Aborted Status) + * in the Control Mode Page. + */ + spin_lock_irqsave(&dev->execute_task_lock, flags); + list_for_each_entry_safe(task, task_tmp, &dev->state_task_list, + t_state_list) { + if (!(TASK_CMD(task))) { + printk(KERN_ERR "TASK_CMD(task) is NULL!\n"); + continue; + } + cmd = TASK_CMD(task); + + if (!T_TASK(cmd)) { + printk(KERN_ERR "T_TASK(cmd) is NULL for task: %p cmd:" + " %p ITT: 0x%08x\n", task, cmd, + CMD_TFO(cmd)->get_task_tag(cmd)); + continue; + } + /* + * For PREEMPT_AND_ABORT usage, only process commands + * with a matching reservation key. + */ + if ((preempt_and_abort_list != NULL) && + (core_scsi3_check_cdb_abort_and_preempt( + preempt_and_abort_list, cmd) != 0)) + continue; + /* + * Not aborting PROUT PREEMPT_AND_ABORT CDB.. + */ + if (prout_cmd == cmd) + continue; + + list_del(&task->t_state_list); + atomic_set(&task->task_state_active, 0); + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + DEBUG_LR("LUN_RESET: %s cmd: %p task: %p" + " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/" + "def_t_state: %d/%d cdb: 0x%02x\n", + (preempt_and_abort_list) ? "Preempt" : "", cmd, task, + CMD_TFO(cmd)->get_task_tag(cmd), 0, + CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state, + cmd->deferred_t_state, T_TASK(cmd)->t_task_cdb[0]); + DEBUG_LR("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx" + " t_task_cdbs: %d t_task_cdbs_left: %d" + " t_task_cdbs_sent: %d -- t_transport_active: %d" + " t_transport_stop: %d t_transport_sent: %d\n", + CMD_TFO(cmd)->get_task_tag(cmd), cmd->pr_res_key, + T_TASK(cmd)->t_task_cdbs, + atomic_read(&T_TASK(cmd)->t_task_cdbs_left), + atomic_read(&T_TASK(cmd)->t_task_cdbs_sent), + atomic_read(&T_TASK(cmd)->t_transport_active), + atomic_read(&T_TASK(cmd)->t_transport_stop), + atomic_read(&T_TASK(cmd)->t_transport_sent)); + + if (atomic_read(&task->task_active)) { + atomic_set(&task->task_stop, 1); + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + + DEBUG_LR("LUN_RESET: Waiting for task: %p to shutdown" + " for dev: %p\n", task, dev); + wait_for_completion(&task->task_stop_comp); + DEBUG_LR("LUN_RESET Completed task: %p shutdown for" + " dev: %p\n", task, dev); + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + atomic_dec(&T_TASK(cmd)->t_task_cdbs_left); + + atomic_set(&task->task_active, 0); + atomic_set(&task->task_stop, 0); + } + __transport_stop_task_timer(task, &flags); + + if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_ex_left))) { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + DEBUG_LR("LUN_RESET: Skipping task: %p, dev: %p for" + " t_task_cdbs_ex_left: %d\n", task, dev, + atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left)); + + spin_lock_irqsave(&dev->execute_task_lock, flags); + continue; + } + fe_count = atomic_read(&T_TASK(cmd)->t_fe_count); + + if (atomic_read(&T_TASK(cmd)->t_transport_active)) { + DEBUG_LR("LUN_RESET: got t_transport_active = 1 for" + " task: %p, t_fe_count: %d dev: %p\n", task, + fe_count, dev); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); + + spin_lock_irqsave(&dev->execute_task_lock, flags); + continue; + } + DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p," + " t_fe_count: %d dev: %p\n", task, fe_count, dev); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); + + spin_lock_irqsave(&dev->execute_task_lock, flags); + } + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + /* + * Release all commands remaining in the struct se_device cmd queue. + * + * This follows the same logic as above for the struct se_device + * struct se_task state list, where commands are returned with + * TASK_ABORTED status, if there is an outstanding $FABRIC_MOD + * reference, otherwise the struct se_cmd is released. + */ + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + list_for_each_entry_safe(qr, qr_tmp, &qobj->qobj_list, qr_list) { + cmd = (struct se_cmd *)qr->cmd; + if (!(cmd)) { + /* + * Skip these for non PREEMPT_AND_ABORT usage.. + */ + if (preempt_and_abort_list != NULL) + continue; + + atomic_dec(&qobj->queue_cnt); + list_del(&qr->qr_list); + kfree(qr); + continue; + } + /* + * For PREEMPT_AND_ABORT usage, only process commands + * with a matching reservation key. + */ + if ((preempt_and_abort_list != NULL) && + (core_scsi3_check_cdb_abort_and_preempt( + preempt_and_abort_list, cmd) != 0)) + continue; + /* + * Not aborting PROUT PREEMPT_AND_ABORT CDB.. + */ + if (prout_cmd == cmd) + continue; + + atomic_dec(&T_TASK(cmd)->t_transport_queue_active); + atomic_dec(&qobj->queue_cnt); + list_del(&qr->qr_list); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + + state = qr->state; + kfree(qr); + + DEBUG_LR("LUN_RESET: %s from Device Queue: cmd: %p t_state:" + " %d t_fe_count: %d\n", (preempt_and_abort_list) ? + "Preempt" : "", cmd, state, + atomic_read(&T_TASK(cmd)->t_fe_count)); + /* + * Signal that the command has failed via cmd->se_cmd_flags, + * and call TFO->new_cmd_failure() to wakeup any fabric + * dependent code used to wait for unsolicited data out + * allocation to complete. The fabric module is expected + * to dump any remaining unsolicited data out for the aborted + * command at this point. + */ + transport_new_cmd_failure(cmd); + + core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, + atomic_read(&T_TASK(cmd)->t_fe_count)); + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + } + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + /* + * Clear any legacy SPC-2 reservation when called during + * LOGICAL UNIT RESET + */ + if (!(preempt_and_abort_list) && + (dev->dev_flags & DF_SPC2_RESERVATIONS)) { + spin_lock(&dev->dev_reservation_lock); + dev->dev_reserved_node_acl = NULL; + dev->dev_flags &= ~DF_SPC2_RESERVATIONS; + spin_unlock(&dev->dev_reservation_lock); + printk(KERN_INFO "LUN_RESET: SCSI-2 Released reservation\n"); + } + + spin_lock(&dev->stats_lock); + dev->num_resets++; + spin_unlock(&dev->stats_lock); + + DEBUG_LR("LUN_RESET: %s for [%s] Complete\n", + (preempt_and_abort_list) ? "Preempt" : "TMR", + TRANSPORT(dev)->name); + return 0; +} diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c new file mode 100644 index 000000000000..abfa81a57115 --- /dev/null +++ b/drivers/target/target_core_tpg.c @@ -0,0 +1,826 @@ +/******************************************************************************* + * Filename: target_core_tpg.c + * + * This file contains generic Target Portal Group related functions. + * + * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 + +#include +#include +#include +#include +#include + +#include "target_core_hba.h" + +/* core_clear_initiator_node_from_tpg(): + * + * + */ +static void core_clear_initiator_node_from_tpg( + struct se_node_acl *nacl, + struct se_portal_group *tpg) +{ + int i; + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_lun_acl *acl, *acl_tmp; + + spin_lock_irq(&nacl->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = &nacl->device_list[i]; + + if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) + continue; + + if (!deve->se_lun) { + printk(KERN_ERR "%s device entries device pointer is" + " NULL, but Initiator has access.\n", + TPG_TFO(tpg)->get_fabric_name()); + continue; + } + + lun = deve->se_lun; + spin_unlock_irq(&nacl->device_list_lock); + core_update_device_list_for_node(lun, NULL, deve->mapped_lun, + TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0); + + spin_lock(&lun->lun_acl_lock); + list_for_each_entry_safe(acl, acl_tmp, + &lun->lun_acl_list, lacl_list) { + if (!(strcmp(acl->initiatorname, + nacl->initiatorname)) && + (acl->mapped_lun == deve->mapped_lun)) + break; + } + + if (!acl) { + printk(KERN_ERR "Unable to locate struct se_lun_acl for %s," + " mapped_lun: %u\n", nacl->initiatorname, + deve->mapped_lun); + spin_unlock(&lun->lun_acl_lock); + spin_lock_irq(&nacl->device_list_lock); + continue; + } + + list_del(&acl->lacl_list); + spin_unlock(&lun->lun_acl_lock); + + spin_lock_irq(&nacl->device_list_lock); + kfree(acl); + } + spin_unlock_irq(&nacl->device_list_lock); +} + +/* __core_tpg_get_initiator_node_acl(): + * + * spin_lock_bh(&tpg->acl_node_lock); must be held when calling + */ +struct se_node_acl *__core_tpg_get_initiator_node_acl( + struct se_portal_group *tpg, + const char *initiatorname) +{ + struct se_node_acl *acl; + + list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { + if (!(strcmp(acl->initiatorname, initiatorname))) + return acl; + } + + return NULL; +} + +/* core_tpg_get_initiator_node_acl(): + * + * + */ +struct se_node_acl *core_tpg_get_initiator_node_acl( + struct se_portal_group *tpg, + unsigned char *initiatorname) +{ + struct se_node_acl *acl; + + spin_lock_bh(&tpg->acl_node_lock); + list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { + if (!(strcmp(acl->initiatorname, initiatorname)) && + (!(acl->dynamic_node_acl))) { + spin_unlock_bh(&tpg->acl_node_lock); + return acl; + } + } + spin_unlock_bh(&tpg->acl_node_lock); + + return NULL; +} + +/* core_tpg_add_node_to_devs(): + * + * + */ +void core_tpg_add_node_to_devs( + struct se_node_acl *acl, + struct se_portal_group *tpg) +{ + int i = 0; + u32 lun_access = 0; + struct se_lun *lun; + struct se_device *dev; + + spin_lock(&tpg->tpg_lun_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + lun = &tpg->tpg_lun_list[i]; + if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) + continue; + + spin_unlock(&tpg->tpg_lun_lock); + + dev = lun->lun_se_dev; + /* + * By default in LIO-Target $FABRIC_MOD, + * demo_mode_write_protect is ON, or READ_ONLY; + */ + if (!(TPG_TFO(tpg)->tpg_check_demo_mode_write_protect(tpg))) { + if (dev->dev_flags & DF_READ_ONLY) + lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + else + lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + /* + * Allow only optical drives to issue R/W in default RO + * demo mode. + */ + if (TRANSPORT(dev)->get_device_type(dev) == TYPE_DISK) + lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + else + lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; + } + + printk(KERN_INFO "TARGET_CORE[%s]->TPG[%u]_LUN[%u] - Adding %s" + " access for LUN in Demo Mode\n", + TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), lun->unpacked_lun, + (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ? + "READ-WRITE" : "READ-ONLY"); + + core_update_device_list_for_node(lun, NULL, lun->unpacked_lun, + lun_access, acl, tpg, 1); + spin_lock(&tpg->tpg_lun_lock); + } + spin_unlock(&tpg->tpg_lun_lock); +} + +/* core_set_queue_depth_for_node(): + * + * + */ +static int core_set_queue_depth_for_node( + struct se_portal_group *tpg, + struct se_node_acl *acl) +{ + if (!acl->queue_depth) { + printk(KERN_ERR "Queue depth for %s Initiator Node: %s is 0," + "defaulting to 1.\n", TPG_TFO(tpg)->get_fabric_name(), + acl->initiatorname); + acl->queue_depth = 1; + } + + return 0; +} + +/* core_create_device_list_for_node(): + * + * + */ +static int core_create_device_list_for_node(struct se_node_acl *nacl) +{ + struct se_dev_entry *deve; + int i; + + nacl->device_list = kzalloc(sizeof(struct se_dev_entry) * + TRANSPORT_MAX_LUNS_PER_TPG, GFP_KERNEL); + if (!(nacl->device_list)) { + printk(KERN_ERR "Unable to allocate memory for" + " struct se_node_acl->device_list\n"); + return -1; + } + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = &nacl->device_list[i]; + + atomic_set(&deve->ua_count, 0); + atomic_set(&deve->pr_ref_count, 0); + spin_lock_init(&deve->ua_lock); + INIT_LIST_HEAD(&deve->alua_port_list); + INIT_LIST_HEAD(&deve->ua_list); + } + + return 0; +} + +/* core_tpg_check_initiator_node_acl() + * + * + */ +struct se_node_acl *core_tpg_check_initiator_node_acl( + struct se_portal_group *tpg, + unsigned char *initiatorname) +{ + struct se_node_acl *acl; + + acl = core_tpg_get_initiator_node_acl(tpg, initiatorname); + if ((acl)) + return acl; + + if (!(TPG_TFO(tpg)->tpg_check_demo_mode(tpg))) + return NULL; + + acl = TPG_TFO(tpg)->tpg_alloc_fabric_acl(tpg); + if (!(acl)) + return NULL; + + INIT_LIST_HEAD(&acl->acl_list); + INIT_LIST_HEAD(&acl->acl_sess_list); + spin_lock_init(&acl->device_list_lock); + spin_lock_init(&acl->nacl_sess_lock); + atomic_set(&acl->acl_pr_ref_count, 0); + atomic_set(&acl->mib_ref_count, 0); + acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg); + snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); + acl->se_tpg = tpg; + acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); + spin_lock_init(&acl->stats_lock); + acl->dynamic_node_acl = 1; + + TPG_TFO(tpg)->set_default_node_attributes(acl); + + if (core_create_device_list_for_node(acl) < 0) { + TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl); + return NULL; + } + + if (core_set_queue_depth_for_node(tpg, acl) < 0) { + core_free_device_list_for_node(acl, tpg); + TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl); + return NULL; + } + + core_tpg_add_node_to_devs(acl, tpg); + + spin_lock_bh(&tpg->acl_node_lock); + list_add_tail(&acl->acl_list, &tpg->acl_node_list); + tpg->num_node_acls++; + spin_unlock_bh(&tpg->acl_node_lock); + + printk("%s_TPG[%u] - Added DYNAMIC ACL with TCQ Depth: %d for %s" + " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth, + TPG_TFO(tpg)->get_fabric_name(), initiatorname); + + return acl; +} +EXPORT_SYMBOL(core_tpg_check_initiator_node_acl); + +void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl) +{ + while (atomic_read(&nacl->acl_pr_ref_count) != 0) + cpu_relax(); +} + +void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl) +{ + while (atomic_read(&nacl->mib_ref_count) != 0) + cpu_relax(); +} + +void core_tpg_clear_object_luns(struct se_portal_group *tpg) +{ + int i, ret; + struct se_lun *lun; + + spin_lock(&tpg->tpg_lun_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + lun = &tpg->tpg_lun_list[i]; + + if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) || + (lun->lun_se_dev == NULL)) + continue; + + spin_unlock(&tpg->tpg_lun_lock); + ret = core_dev_del_lun(tpg, lun->unpacked_lun); + spin_lock(&tpg->tpg_lun_lock); + } + spin_unlock(&tpg->tpg_lun_lock); +} +EXPORT_SYMBOL(core_tpg_clear_object_luns); + +/* core_tpg_add_initiator_node_acl(): + * + * + */ +struct se_node_acl *core_tpg_add_initiator_node_acl( + struct se_portal_group *tpg, + struct se_node_acl *se_nacl, + const char *initiatorname, + u32 queue_depth) +{ + struct se_node_acl *acl = NULL; + + spin_lock_bh(&tpg->acl_node_lock); + acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); + if ((acl)) { + if (acl->dynamic_node_acl) { + acl->dynamic_node_acl = 0; + printk(KERN_INFO "%s_TPG[%u] - Replacing dynamic ACL" + " for %s\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), initiatorname); + spin_unlock_bh(&tpg->acl_node_lock); + /* + * Release the locally allocated struct se_node_acl + * because * core_tpg_add_initiator_node_acl() returned + * a pointer to an existing demo mode node ACL. + */ + if (se_nacl) + TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, + se_nacl); + goto done; + } + + printk(KERN_ERR "ACL entry for %s Initiator" + " Node %s already exists for TPG %u, ignoring" + " request.\n", TPG_TFO(tpg)->get_fabric_name(), + initiatorname, TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock_bh(&tpg->acl_node_lock); + return ERR_PTR(-EEXIST); + } + spin_unlock_bh(&tpg->acl_node_lock); + + if (!(se_nacl)) { + printk("struct se_node_acl pointer is NULL\n"); + return ERR_PTR(-EINVAL); + } + /* + * For v4.x logic the se_node_acl_s is hanging off a fabric + * dependent structure allocated via + * struct target_core_fabric_ops->fabric_make_nodeacl() + */ + acl = se_nacl; + + INIT_LIST_HEAD(&acl->acl_list); + INIT_LIST_HEAD(&acl->acl_sess_list); + spin_lock_init(&acl->device_list_lock); + spin_lock_init(&acl->nacl_sess_lock); + atomic_set(&acl->acl_pr_ref_count, 0); + acl->queue_depth = queue_depth; + snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); + acl->se_tpg = tpg; + acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); + spin_lock_init(&acl->stats_lock); + + TPG_TFO(tpg)->set_default_node_attributes(acl); + + if (core_create_device_list_for_node(acl) < 0) { + TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl); + return ERR_PTR(-ENOMEM); + } + + if (core_set_queue_depth_for_node(tpg, acl) < 0) { + core_free_device_list_for_node(acl, tpg); + TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl); + return ERR_PTR(-EINVAL); + } + + spin_lock_bh(&tpg->acl_node_lock); + list_add_tail(&acl->acl_list, &tpg->acl_node_list); + tpg->num_node_acls++; + spin_unlock_bh(&tpg->acl_node_lock); + +done: + printk(KERN_INFO "%s_TPG[%hu] - Added ACL with TCQ Depth: %d for %s" + " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth, + TPG_TFO(tpg)->get_fabric_name(), initiatorname); + + return acl; +} +EXPORT_SYMBOL(core_tpg_add_initiator_node_acl); + +/* core_tpg_del_initiator_node_acl(): + * + * + */ +int core_tpg_del_initiator_node_acl( + struct se_portal_group *tpg, + struct se_node_acl *acl, + int force) +{ + struct se_session *sess, *sess_tmp; + int dynamic_acl = 0; + + spin_lock_bh(&tpg->acl_node_lock); + if (acl->dynamic_node_acl) { + acl->dynamic_node_acl = 0; + dynamic_acl = 1; + } + list_del(&acl->acl_list); + tpg->num_node_acls--; + spin_unlock_bh(&tpg->acl_node_lock); + + spin_lock_bh(&tpg->session_lock); + list_for_each_entry_safe(sess, sess_tmp, + &tpg->tpg_sess_list, sess_list) { + if (sess->se_node_acl != acl) + continue; + /* + * Determine if the session needs to be closed by our context. + */ + if (!(TPG_TFO(tpg)->shutdown_session(sess))) + continue; + + spin_unlock_bh(&tpg->session_lock); + /* + * If the $FABRIC_MOD session for the Initiator Node ACL exists, + * forcefully shutdown the $FABRIC_MOD session/nexus. + */ + TPG_TFO(tpg)->close_session(sess); + + spin_lock_bh(&tpg->session_lock); + } + spin_unlock_bh(&tpg->session_lock); + + core_tpg_wait_for_nacl_pr_ref(acl); + core_tpg_wait_for_mib_ref(acl); + core_clear_initiator_node_from_tpg(acl, tpg); + core_free_device_list_for_node(acl, tpg); + + printk(KERN_INFO "%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s" + " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth, + TPG_TFO(tpg)->get_fabric_name(), acl->initiatorname); + + return 0; +} +EXPORT_SYMBOL(core_tpg_del_initiator_node_acl); + +/* core_tpg_set_initiator_node_queue_depth(): + * + * + */ +int core_tpg_set_initiator_node_queue_depth( + struct se_portal_group *tpg, + unsigned char *initiatorname, + u32 queue_depth, + int force) +{ + struct se_session *sess, *init_sess = NULL; + struct se_node_acl *acl; + int dynamic_acl = 0; + + spin_lock_bh(&tpg->acl_node_lock); + acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); + if (!(acl)) { + printk(KERN_ERR "Access Control List entry for %s Initiator" + " Node %s does not exists for TPG %hu, ignoring" + " request.\n", TPG_TFO(tpg)->get_fabric_name(), + initiatorname, TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock_bh(&tpg->acl_node_lock); + return -ENODEV; + } + if (acl->dynamic_node_acl) { + acl->dynamic_node_acl = 0; + dynamic_acl = 1; + } + spin_unlock_bh(&tpg->acl_node_lock); + + spin_lock_bh(&tpg->session_lock); + list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) { + if (sess->se_node_acl != acl) + continue; + + if (!force) { + printk(KERN_ERR "Unable to change queue depth for %s" + " Initiator Node: %s while session is" + " operational. To forcefully change the queue" + " depth and force session reinstatement" + " use the \"force=1\" parameter.\n", + TPG_TFO(tpg)->get_fabric_name(), initiatorname); + spin_unlock_bh(&tpg->session_lock); + + spin_lock_bh(&tpg->acl_node_lock); + if (dynamic_acl) + acl->dynamic_node_acl = 1; + spin_unlock_bh(&tpg->acl_node_lock); + return -EEXIST; + } + /* + * Determine if the session needs to be closed by our context. + */ + if (!(TPG_TFO(tpg)->shutdown_session(sess))) + continue; + + init_sess = sess; + break; + } + + /* + * User has requested to change the queue depth for a Initiator Node. + * Change the value in the Node's struct se_node_acl, and call + * core_set_queue_depth_for_node() to add the requested queue depth. + * + * Finally call TPG_TFO(tpg)->close_session() to force session + * reinstatement to occur if there is an active session for the + * $FABRIC_MOD Initiator Node in question. + */ + acl->queue_depth = queue_depth; + + if (core_set_queue_depth_for_node(tpg, acl) < 0) { + spin_unlock_bh(&tpg->session_lock); + /* + * Force session reinstatement if + * core_set_queue_depth_for_node() failed, because we assume + * the $FABRIC_MOD has already the set session reinstatement + * bit from TPG_TFO(tpg)->shutdown_session() called above. + */ + if (init_sess) + TPG_TFO(tpg)->close_session(init_sess); + + spin_lock_bh(&tpg->acl_node_lock); + if (dynamic_acl) + acl->dynamic_node_acl = 1; + spin_unlock_bh(&tpg->acl_node_lock); + return -EINVAL; + } + spin_unlock_bh(&tpg->session_lock); + /* + * If the $FABRIC_MOD session for the Initiator Node ACL exists, + * forcefully shutdown the $FABRIC_MOD session/nexus. + */ + if (init_sess) + TPG_TFO(tpg)->close_session(init_sess); + + printk(KERN_INFO "Successfuly changed queue depth to: %d for Initiator" + " Node: %s on %s Target Portal Group: %u\n", queue_depth, + initiatorname, TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg)); + + spin_lock_bh(&tpg->acl_node_lock); + if (dynamic_acl) + acl->dynamic_node_acl = 1; + spin_unlock_bh(&tpg->acl_node_lock); + + return 0; +} +EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth); + +static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) +{ + /* Set in core_dev_setup_virtual_lun0() */ + struct se_device *dev = se_global->g_lun0_dev; + struct se_lun *lun = &se_tpg->tpg_virt_lun0; + u32 lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + int ret; + + lun->unpacked_lun = 0; + lun->lun_status = TRANSPORT_LUN_STATUS_FREE; + atomic_set(&lun->lun_acl_count, 0); + init_completion(&lun->lun_shutdown_comp); + INIT_LIST_HEAD(&lun->lun_acl_list); + INIT_LIST_HEAD(&lun->lun_cmd_list); + spin_lock_init(&lun->lun_acl_lock); + spin_lock_init(&lun->lun_cmd_lock); + spin_lock_init(&lun->lun_sep_lock); + + ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev); + if (ret < 0) + return -1; + + return 0; +} + +static void core_tpg_release_virtual_lun0(struct se_portal_group *se_tpg) +{ + struct se_lun *lun = &se_tpg->tpg_virt_lun0; + + core_tpg_post_dellun(se_tpg, lun); +} + +int core_tpg_register( + struct target_core_fabric_ops *tfo, + struct se_wwn *se_wwn, + struct se_portal_group *se_tpg, + void *tpg_fabric_ptr, + int se_tpg_type) +{ + struct se_lun *lun; + u32 i; + + se_tpg->tpg_lun_list = kzalloc((sizeof(struct se_lun) * + TRANSPORT_MAX_LUNS_PER_TPG), GFP_KERNEL); + if (!(se_tpg->tpg_lun_list)) { + printk(KERN_ERR "Unable to allocate struct se_portal_group->" + "tpg_lun_list\n"); + return -ENOMEM; + } + + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + lun = &se_tpg->tpg_lun_list[i]; + lun->unpacked_lun = i; + lun->lun_status = TRANSPORT_LUN_STATUS_FREE; + atomic_set(&lun->lun_acl_count, 0); + init_completion(&lun->lun_shutdown_comp); + INIT_LIST_HEAD(&lun->lun_acl_list); + INIT_LIST_HEAD(&lun->lun_cmd_list); + spin_lock_init(&lun->lun_acl_lock); + spin_lock_init(&lun->lun_cmd_lock); + spin_lock_init(&lun->lun_sep_lock); + } + + se_tpg->se_tpg_type = se_tpg_type; + se_tpg->se_tpg_fabric_ptr = tpg_fabric_ptr; + se_tpg->se_tpg_tfo = tfo; + se_tpg->se_tpg_wwn = se_wwn; + atomic_set(&se_tpg->tpg_pr_ref_count, 0); + INIT_LIST_HEAD(&se_tpg->acl_node_list); + INIT_LIST_HEAD(&se_tpg->se_tpg_list); + INIT_LIST_HEAD(&se_tpg->tpg_sess_list); + spin_lock_init(&se_tpg->acl_node_lock); + spin_lock_init(&se_tpg->session_lock); + spin_lock_init(&se_tpg->tpg_lun_lock); + + if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) { + if (core_tpg_setup_virtual_lun0(se_tpg) < 0) { + kfree(se_tpg); + return -ENOMEM; + } + } + + spin_lock_bh(&se_global->se_tpg_lock); + list_add_tail(&se_tpg->se_tpg_list, &se_global->g_se_tpg_list); + spin_unlock_bh(&se_global->se_tpg_lock); + + printk(KERN_INFO "TARGET_CORE[%s]: Allocated %s struct se_portal_group for" + " endpoint: %s, Portal Tag: %u\n", tfo->get_fabric_name(), + (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? + "Normal" : "Discovery", (tfo->tpg_get_wwn(se_tpg) == NULL) ? + "None" : tfo->tpg_get_wwn(se_tpg), tfo->tpg_get_tag(se_tpg)); + + return 0; +} +EXPORT_SYMBOL(core_tpg_register); + +int core_tpg_deregister(struct se_portal_group *se_tpg) +{ + printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group" + " for endpoint: %s Portal Tag %u\n", + (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? + "Normal" : "Discovery", TPG_TFO(se_tpg)->get_fabric_name(), + TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg), + TPG_TFO(se_tpg)->tpg_get_tag(se_tpg)); + + spin_lock_bh(&se_global->se_tpg_lock); + list_del(&se_tpg->se_tpg_list); + spin_unlock_bh(&se_global->se_tpg_lock); + + while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) + cpu_relax(); + + if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) + core_tpg_release_virtual_lun0(se_tpg); + + se_tpg->se_tpg_fabric_ptr = NULL; + kfree(se_tpg->tpg_lun_list); + return 0; +} +EXPORT_SYMBOL(core_tpg_deregister); + +struct se_lun *core_tpg_pre_addlun( + struct se_portal_group *tpg, + u32 unpacked_lun) +{ + struct se_lun *lun; + + if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { + printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG" + "-1: %u for Target Portal Group: %u\n", + TPG_TFO(tpg)->get_fabric_name(), + unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + return ERR_PTR(-EOVERFLOW); + } + + spin_lock(&tpg->tpg_lun_lock); + lun = &tpg->tpg_lun_list[unpacked_lun]; + if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) { + printk(KERN_ERR "TPG Logical Unit Number: %u is already active" + " on %s Target Portal Group: %u, ignoring request.\n", + unpacked_lun, TPG_TFO(tpg)->get_fabric_name(), + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&tpg->tpg_lun_lock); + return ERR_PTR(-EINVAL); + } + spin_unlock(&tpg->tpg_lun_lock); + + return lun; +} + +int core_tpg_post_addlun( + struct se_portal_group *tpg, + struct se_lun *lun, + u32 lun_access, + void *lun_ptr) +{ + if (core_dev_export(lun_ptr, tpg, lun) < 0) + return -1; + + spin_lock(&tpg->tpg_lun_lock); + lun->lun_access = lun_access; + lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; + spin_unlock(&tpg->tpg_lun_lock); + + return 0; +} + +static void core_tpg_shutdown_lun( + struct se_portal_group *tpg, + struct se_lun *lun) +{ + core_clear_lun_from_tpg(lun, tpg); + transport_clear_lun_from_sessions(lun); +} + +struct se_lun *core_tpg_pre_dellun( + struct se_portal_group *tpg, + u32 unpacked_lun, + int *ret) +{ + struct se_lun *lun; + + if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { + printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG" + "-1: %u for Target Portal Group: %u\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TRANSPORT_MAX_LUNS_PER_TPG-1, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + return ERR_PTR(-EOVERFLOW); + } + + spin_lock(&tpg->tpg_lun_lock); + lun = &tpg->tpg_lun_list[unpacked_lun]; + if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { + printk(KERN_ERR "%s Logical Unit Number: %u is not active on" + " Target Portal Group: %u, ignoring request.\n", + TPG_TFO(tpg)->get_fabric_name(), unpacked_lun, + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&tpg->tpg_lun_lock); + return ERR_PTR(-ENODEV); + } + spin_unlock(&tpg->tpg_lun_lock); + + return lun; +} + +int core_tpg_post_dellun( + struct se_portal_group *tpg, + struct se_lun *lun) +{ + core_tpg_shutdown_lun(tpg, lun); + + core_dev_unexport(lun->lun_se_dev, tpg, lun); + + spin_lock(&tpg->tpg_lun_lock); + lun->lun_status = TRANSPORT_LUN_STATUS_FREE; + spin_unlock(&tpg->tpg_lun_lock); + + return 0; +} diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c new file mode 100644 index 000000000000..28b6292ff298 --- /dev/null +++ b/drivers/target/target_core_transport.c @@ -0,0 +1,6134 @@ +/******************************************************************************* + * Filename: target_core_transport.c + * + * This file contains the Generic Target Engine Core. + * + * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include +#include +#include +#include +#include /* For TASK_ATTR_* */ + +#include +#include +#include +#include +#include +#include +#include + +#include "target_core_alua.h" +#include "target_core_hba.h" +#include "target_core_pr.h" +#include "target_core_scdb.h" +#include "target_core_ua.h" + +/* #define DEBUG_CDB_HANDLER */ +#ifdef DEBUG_CDB_HANDLER +#define DEBUG_CDB_H(x...) printk(KERN_INFO x) +#else +#define DEBUG_CDB_H(x...) +#endif + +/* #define DEBUG_CMD_MAP */ +#ifdef DEBUG_CMD_MAP +#define DEBUG_CMD_M(x...) printk(KERN_INFO x) +#else +#define DEBUG_CMD_M(x...) +#endif + +/* #define DEBUG_MEM_ALLOC */ +#ifdef DEBUG_MEM_ALLOC +#define DEBUG_MEM(x...) printk(KERN_INFO x) +#else +#define DEBUG_MEM(x...) +#endif + +/* #define DEBUG_MEM2_ALLOC */ +#ifdef DEBUG_MEM2_ALLOC +#define DEBUG_MEM2(x...) printk(KERN_INFO x) +#else +#define DEBUG_MEM2(x...) +#endif + +/* #define DEBUG_SG_CALC */ +#ifdef DEBUG_SG_CALC +#define DEBUG_SC(x...) printk(KERN_INFO x) +#else +#define DEBUG_SC(x...) +#endif + +/* #define DEBUG_SE_OBJ */ +#ifdef DEBUG_SE_OBJ +#define DEBUG_SO(x...) printk(KERN_INFO x) +#else +#define DEBUG_SO(x...) +#endif + +/* #define DEBUG_CMD_VOL */ +#ifdef DEBUG_CMD_VOL +#define DEBUG_VOL(x...) printk(KERN_INFO x) +#else +#define DEBUG_VOL(x...) +#endif + +/* #define DEBUG_CMD_STOP */ +#ifdef DEBUG_CMD_STOP +#define DEBUG_CS(x...) printk(KERN_INFO x) +#else +#define DEBUG_CS(x...) +#endif + +/* #define DEBUG_PASSTHROUGH */ +#ifdef DEBUG_PASSTHROUGH +#define DEBUG_PT(x...) printk(KERN_INFO x) +#else +#define DEBUG_PT(x...) +#endif + +/* #define DEBUG_TASK_STOP */ +#ifdef DEBUG_TASK_STOP +#define DEBUG_TS(x...) printk(KERN_INFO x) +#else +#define DEBUG_TS(x...) +#endif + +/* #define DEBUG_TRANSPORT_STOP */ +#ifdef DEBUG_TRANSPORT_STOP +#define DEBUG_TRANSPORT_S(x...) printk(KERN_INFO x) +#else +#define DEBUG_TRANSPORT_S(x...) +#endif + +/* #define DEBUG_TASK_FAILURE */ +#ifdef DEBUG_TASK_FAILURE +#define DEBUG_TF(x...) printk(KERN_INFO x) +#else +#define DEBUG_TF(x...) +#endif + +/* #define DEBUG_DEV_OFFLINE */ +#ifdef DEBUG_DEV_OFFLINE +#define DEBUG_DO(x...) printk(KERN_INFO x) +#else +#define DEBUG_DO(x...) +#endif + +/* #define DEBUG_TASK_STATE */ +#ifdef DEBUG_TASK_STATE +#define DEBUG_TSTATE(x...) printk(KERN_INFO x) +#else +#define DEBUG_TSTATE(x...) +#endif + +/* #define DEBUG_STATUS_THR */ +#ifdef DEBUG_STATUS_THR +#define DEBUG_ST(x...) printk(KERN_INFO x) +#else +#define DEBUG_ST(x...) +#endif + +/* #define DEBUG_TASK_TIMEOUT */ +#ifdef DEBUG_TASK_TIMEOUT +#define DEBUG_TT(x...) printk(KERN_INFO x) +#else +#define DEBUG_TT(x...) +#endif + +/* #define DEBUG_GENERIC_REQUEST_FAILURE */ +#ifdef DEBUG_GENERIC_REQUEST_FAILURE +#define DEBUG_GRF(x...) printk(KERN_INFO x) +#else +#define DEBUG_GRF(x...) +#endif + +/* #define DEBUG_SAM_TASK_ATTRS */ +#ifdef DEBUG_SAM_TASK_ATTRS +#define DEBUG_STA(x...) printk(KERN_INFO x) +#else +#define DEBUG_STA(x...) +#endif + +struct se_global *se_global; + +static struct kmem_cache *se_cmd_cache; +static struct kmem_cache *se_sess_cache; +struct kmem_cache *se_tmr_req_cache; +struct kmem_cache *se_ua_cache; +struct kmem_cache *se_mem_cache; +struct kmem_cache *t10_pr_reg_cache; +struct kmem_cache *t10_alua_lu_gp_cache; +struct kmem_cache *t10_alua_lu_gp_mem_cache; +struct kmem_cache *t10_alua_tg_pt_gp_cache; +struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; + +/* Used for transport_dev_get_map_*() */ +typedef int (*map_func_t)(struct se_task *, u32); + +static int transport_generic_write_pending(struct se_cmd *); +static int transport_processing_thread(void *); +static int __transport_execute_tasks(struct se_device *dev); +static void transport_complete_task_attr(struct se_cmd *cmd); +static void transport_direct_request_timeout(struct se_cmd *cmd); +static void transport_free_dev_tasks(struct se_cmd *cmd); +static u32 transport_generic_get_cdb_count(struct se_cmd *cmd, + unsigned long long starting_lba, u32 sectors, + enum dma_data_direction data_direction, + struct list_head *mem_list, int set_counts); +static int transport_generic_get_mem(struct se_cmd *cmd, u32 length, + u32 dma_size); +static int transport_generic_remove(struct se_cmd *cmd, + int release_to_pool, int session_reinstatement); +static int transport_get_sectors(struct se_cmd *cmd); +static struct list_head *transport_init_se_mem_list(void); +static int transport_map_sg_to_mem(struct se_cmd *cmd, + struct list_head *se_mem_list, void *in_mem, + u32 *se_mem_cnt); +static void transport_memcpy_se_mem_read_contig(struct se_cmd *cmd, + unsigned char *dst, struct list_head *se_mem_list); +static void transport_release_fe_cmd(struct se_cmd *cmd); +static void transport_remove_cmd_from_queue(struct se_cmd *cmd, + struct se_queue_obj *qobj); +static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); +static void transport_stop_all_task_timers(struct se_cmd *cmd); + +int transport_emulate_control_cdb(struct se_task *task); + +int init_se_global(void) +{ + struct se_global *global; + + global = kzalloc(sizeof(struct se_global), GFP_KERNEL); + if (!(global)) { + printk(KERN_ERR "Unable to allocate memory for struct se_global\n"); + return -1; + } + + INIT_LIST_HEAD(&global->g_lu_gps_list); + INIT_LIST_HEAD(&global->g_se_tpg_list); + INIT_LIST_HEAD(&global->g_hba_list); + INIT_LIST_HEAD(&global->g_se_dev_list); + spin_lock_init(&global->g_device_lock); + spin_lock_init(&global->hba_lock); + spin_lock_init(&global->se_tpg_lock); + spin_lock_init(&global->lu_gps_lock); + spin_lock_init(&global->plugin_class_lock); + + se_cmd_cache = kmem_cache_create("se_cmd_cache", + sizeof(struct se_cmd), __alignof__(struct se_cmd), 0, NULL); + if (!(se_cmd_cache)) { + printk(KERN_ERR "kmem_cache_create for struct se_cmd failed\n"); + goto out; + } + se_tmr_req_cache = kmem_cache_create("se_tmr_cache", + sizeof(struct se_tmr_req), __alignof__(struct se_tmr_req), + 0, NULL); + if (!(se_tmr_req_cache)) { + printk(KERN_ERR "kmem_cache_create() for struct se_tmr_req" + " failed\n"); + goto out; + } + se_sess_cache = kmem_cache_create("se_sess_cache", + sizeof(struct se_session), __alignof__(struct se_session), + 0, NULL); + if (!(se_sess_cache)) { + printk(KERN_ERR "kmem_cache_create() for struct se_session" + " failed\n"); + goto out; + } + se_ua_cache = kmem_cache_create("se_ua_cache", + sizeof(struct se_ua), __alignof__(struct se_ua), + 0, NULL); + if (!(se_ua_cache)) { + printk(KERN_ERR "kmem_cache_create() for struct se_ua failed\n"); + goto out; + } + se_mem_cache = kmem_cache_create("se_mem_cache", + sizeof(struct se_mem), __alignof__(struct se_mem), 0, NULL); + if (!(se_mem_cache)) { + printk(KERN_ERR "kmem_cache_create() for struct se_mem failed\n"); + goto out; + } + t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache", + sizeof(struct t10_pr_registration), + __alignof__(struct t10_pr_registration), 0, NULL); + if (!(t10_pr_reg_cache)) { + printk(KERN_ERR "kmem_cache_create() for struct t10_pr_registration" + " failed\n"); + goto out; + } + t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache", + sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp), + 0, NULL); + if (!(t10_alua_lu_gp_cache)) { + printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_cache" + " failed\n"); + goto out; + } + t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache", + sizeof(struct t10_alua_lu_gp_member), + __alignof__(struct t10_alua_lu_gp_member), 0, NULL); + if (!(t10_alua_lu_gp_mem_cache)) { + printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_mem_" + "cache failed\n"); + goto out; + } + t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache", + sizeof(struct t10_alua_tg_pt_gp), + __alignof__(struct t10_alua_tg_pt_gp), 0, NULL); + if (!(t10_alua_tg_pt_gp_cache)) { + printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_" + "cache failed\n"); + goto out; + } + t10_alua_tg_pt_gp_mem_cache = kmem_cache_create( + "t10_alua_tg_pt_gp_mem_cache", + sizeof(struct t10_alua_tg_pt_gp_member), + __alignof__(struct t10_alua_tg_pt_gp_member), + 0, NULL); + if (!(t10_alua_tg_pt_gp_mem_cache)) { + printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_" + "mem_t failed\n"); + goto out; + } + + se_global = global; + + return 0; +out: + if (se_cmd_cache) + kmem_cache_destroy(se_cmd_cache); + if (se_tmr_req_cache) + kmem_cache_destroy(se_tmr_req_cache); + if (se_sess_cache) + kmem_cache_destroy(se_sess_cache); + if (se_ua_cache) + kmem_cache_destroy(se_ua_cache); + if (se_mem_cache) + kmem_cache_destroy(se_mem_cache); + if (t10_pr_reg_cache) + kmem_cache_destroy(t10_pr_reg_cache); + if (t10_alua_lu_gp_cache) + kmem_cache_destroy(t10_alua_lu_gp_cache); + if (t10_alua_lu_gp_mem_cache) + kmem_cache_destroy(t10_alua_lu_gp_mem_cache); + if (t10_alua_tg_pt_gp_cache) + kmem_cache_destroy(t10_alua_tg_pt_gp_cache); + if (t10_alua_tg_pt_gp_mem_cache) + kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); + kfree(global); + return -1; +} + +void release_se_global(void) +{ + struct se_global *global; + + global = se_global; + if (!(global)) + return; + + kmem_cache_destroy(se_cmd_cache); + kmem_cache_destroy(se_tmr_req_cache); + kmem_cache_destroy(se_sess_cache); + kmem_cache_destroy(se_ua_cache); + kmem_cache_destroy(se_mem_cache); + kmem_cache_destroy(t10_pr_reg_cache); + kmem_cache_destroy(t10_alua_lu_gp_cache); + kmem_cache_destroy(t10_alua_lu_gp_mem_cache); + kmem_cache_destroy(t10_alua_tg_pt_gp_cache); + kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); + kfree(global); + + se_global = NULL; +} + +void transport_init_queue_obj(struct se_queue_obj *qobj) +{ + atomic_set(&qobj->queue_cnt, 0); + INIT_LIST_HEAD(&qobj->qobj_list); + init_waitqueue_head(&qobj->thread_wq); + spin_lock_init(&qobj->cmd_queue_lock); +} +EXPORT_SYMBOL(transport_init_queue_obj); + +static int transport_subsystem_reqmods(void) +{ + int ret; + + ret = request_module("target_core_iblock"); + if (ret != 0) + printk(KERN_ERR "Unable to load target_core_iblock\n"); + + ret = request_module("target_core_file"); + if (ret != 0) + printk(KERN_ERR "Unable to load target_core_file\n"); + + ret = request_module("target_core_pscsi"); + if (ret != 0) + printk(KERN_ERR "Unable to load target_core_pscsi\n"); + + ret = request_module("target_core_stgt"); + if (ret != 0) + printk(KERN_ERR "Unable to load target_core_stgt\n"); + + return 0; +} + +int transport_subsystem_check_init(void) +{ + if (se_global->g_sub_api_initialized) + return 0; + /* + * Request the loading of known TCM subsystem plugins.. + */ + if (transport_subsystem_reqmods() < 0) + return -1; + + se_global->g_sub_api_initialized = 1; + return 0; +} + +struct se_session *transport_init_session(void) +{ + struct se_session *se_sess; + + se_sess = kmem_cache_zalloc(se_sess_cache, GFP_KERNEL); + if (!(se_sess)) { + printk(KERN_ERR "Unable to allocate struct se_session from" + " se_sess_cache\n"); + return ERR_PTR(-ENOMEM); + } + INIT_LIST_HEAD(&se_sess->sess_list); + INIT_LIST_HEAD(&se_sess->sess_acl_list); + atomic_set(&se_sess->mib_ref_count, 0); + + return se_sess; +} +EXPORT_SYMBOL(transport_init_session); + +/* + * Called with spin_lock_bh(&struct se_portal_group->session_lock called. + */ +void __transport_register_session( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct se_session *se_sess, + void *fabric_sess_ptr) +{ + unsigned char buf[PR_REG_ISID_LEN]; + + se_sess->se_tpg = se_tpg; + se_sess->fabric_sess_ptr = fabric_sess_ptr; + /* + * Used by struct se_node_acl's under ConfigFS to locate active se_session-t + * + * Only set for struct se_session's that will actually be moving I/O. + * eg: *NOT* discovery sessions. + */ + if (se_nacl) { + /* + * If the fabric module supports an ISID based TransportID, + * save this value in binary from the fabric I_T Nexus now. + */ + if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) { + memset(&buf[0], 0, PR_REG_ISID_LEN); + TPG_TFO(se_tpg)->sess_get_initiator_sid(se_sess, + &buf[0], PR_REG_ISID_LEN); + se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]); + } + spin_lock_irq(&se_nacl->nacl_sess_lock); + /* + * The se_nacl->nacl_sess pointer will be set to the + * last active I_T Nexus for each struct se_node_acl. + */ + se_nacl->nacl_sess = se_sess; + + list_add_tail(&se_sess->sess_acl_list, + &se_nacl->acl_sess_list); + spin_unlock_irq(&se_nacl->nacl_sess_lock); + } + list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list); + + printk(KERN_INFO "TARGET_CORE[%s]: Registered fabric_sess_ptr: %p\n", + TPG_TFO(se_tpg)->get_fabric_name(), se_sess->fabric_sess_ptr); +} +EXPORT_SYMBOL(__transport_register_session); + +void transport_register_session( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct se_session *se_sess, + void *fabric_sess_ptr) +{ + spin_lock_bh(&se_tpg->session_lock); + __transport_register_session(se_tpg, se_nacl, se_sess, fabric_sess_ptr); + spin_unlock_bh(&se_tpg->session_lock); +} +EXPORT_SYMBOL(transport_register_session); + +void transport_deregister_session_configfs(struct se_session *se_sess) +{ + struct se_node_acl *se_nacl; + + /* + * Used by struct se_node_acl's under ConfigFS to locate active struct se_session + */ + se_nacl = se_sess->se_node_acl; + if ((se_nacl)) { + spin_lock_irq(&se_nacl->nacl_sess_lock); + list_del(&se_sess->sess_acl_list); + /* + * If the session list is empty, then clear the pointer. + * Otherwise, set the struct se_session pointer from the tail + * element of the per struct se_node_acl active session list. + */ + if (list_empty(&se_nacl->acl_sess_list)) + se_nacl->nacl_sess = NULL; + else { + se_nacl->nacl_sess = container_of( + se_nacl->acl_sess_list.prev, + struct se_session, sess_acl_list); + } + spin_unlock_irq(&se_nacl->nacl_sess_lock); + } +} +EXPORT_SYMBOL(transport_deregister_session_configfs); + +void transport_free_session(struct se_session *se_sess) +{ + kmem_cache_free(se_sess_cache, se_sess); +} +EXPORT_SYMBOL(transport_free_session); + +void transport_deregister_session(struct se_session *se_sess) +{ + struct se_portal_group *se_tpg = se_sess->se_tpg; + struct se_node_acl *se_nacl; + + if (!(se_tpg)) { + transport_free_session(se_sess); + return; + } + /* + * Wait for possible reference in drivers/target/target_core_mib.c: + * scsi_att_intr_port_seq_show() + */ + while (atomic_read(&se_sess->mib_ref_count) != 0) + cpu_relax(); + + spin_lock_bh(&se_tpg->session_lock); + list_del(&se_sess->sess_list); + se_sess->se_tpg = NULL; + se_sess->fabric_sess_ptr = NULL; + spin_unlock_bh(&se_tpg->session_lock); + + /* + * Determine if we need to do extra work for this initiator node's + * struct se_node_acl if it had been previously dynamically generated. + */ + se_nacl = se_sess->se_node_acl; + if ((se_nacl)) { + spin_lock_bh(&se_tpg->acl_node_lock); + if (se_nacl->dynamic_node_acl) { + if (!(TPG_TFO(se_tpg)->tpg_check_demo_mode_cache( + se_tpg))) { + list_del(&se_nacl->acl_list); + se_tpg->num_node_acls--; + spin_unlock_bh(&se_tpg->acl_node_lock); + + core_tpg_wait_for_nacl_pr_ref(se_nacl); + core_tpg_wait_for_mib_ref(se_nacl); + core_free_device_list_for_node(se_nacl, se_tpg); + TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, + se_nacl); + spin_lock_bh(&se_tpg->acl_node_lock); + } + } + spin_unlock_bh(&se_tpg->acl_node_lock); + } + + transport_free_session(se_sess); + + printk(KERN_INFO "TARGET_CORE[%s]: Deregistered fabric_sess\n", + TPG_TFO(se_tpg)->get_fabric_name()); +} +EXPORT_SYMBOL(transport_deregister_session); + +/* + * Called with T_TASK(cmd)->t_state_lock held. + */ +static void transport_all_task_dev_remove_state(struct se_cmd *cmd) +{ + struct se_device *dev; + struct se_task *task; + unsigned long flags; + + if (!T_TASK(cmd)) + return; + + list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) { + dev = task->se_dev; + if (!(dev)) + continue; + + if (atomic_read(&task->task_active)) + continue; + + if (!(atomic_read(&task->task_state_active))) + continue; + + spin_lock_irqsave(&dev->execute_task_lock, flags); + list_del(&task->t_state_list); + DEBUG_TSTATE("Removed ITT: 0x%08x dev: %p task[%p]\n", + CMD_TFO(cmd)->tfo_get_task_tag(cmd), dev, task); + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + + atomic_set(&task->task_state_active, 0); + atomic_dec(&T_TASK(cmd)->t_task_cdbs_ex_left); + } +} + +/* transport_cmd_check_stop(): + * + * 'transport_off = 1' determines if t_transport_active should be cleared. + * 'transport_off = 2' determines if task_dev_state should be removed. + * + * A non-zero u8 t_state sets cmd->t_state. + * Returns 1 when command is stopped, else 0. + */ +static int transport_cmd_check_stop( + struct se_cmd *cmd, + int transport_off, + u8 t_state) +{ + unsigned long flags; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + /* + * Determine if IOCTL context caller in requesting the stopping of this + * command for LUN shutdown purposes. + */ + if (atomic_read(&T_TASK(cmd)->transport_lun_stop)) { + DEBUG_CS("%s:%d atomic_read(&T_TASK(cmd)->transport_lun_stop)" + " == TRUE for ITT: 0x%08x\n", __func__, __LINE__, + CMD_TFO(cmd)->get_task_tag(cmd)); + + cmd->deferred_t_state = cmd->t_state; + cmd->t_state = TRANSPORT_DEFERRED_CMD; + atomic_set(&T_TASK(cmd)->t_transport_active, 0); + if (transport_off == 2) + transport_all_task_dev_remove_state(cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + complete(&T_TASK(cmd)->transport_lun_stop_comp); + return 1; + } + /* + * Determine if frontend context caller is requesting the stopping of + * this command for frontend excpections. + */ + if (atomic_read(&T_TASK(cmd)->t_transport_stop)) { + DEBUG_CS("%s:%d atomic_read(&T_TASK(cmd)->t_transport_stop) ==" + " TRUE for ITT: 0x%08x\n", __func__, __LINE__, + CMD_TFO(cmd)->get_task_tag(cmd)); + + cmd->deferred_t_state = cmd->t_state; + cmd->t_state = TRANSPORT_DEFERRED_CMD; + if (transport_off == 2) + transport_all_task_dev_remove_state(cmd); + + /* + * Clear struct se_cmd->se_lun before the transport_off == 2 handoff + * to FE. + */ + if (transport_off == 2) + cmd->se_lun = NULL; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + complete(&T_TASK(cmd)->t_transport_stop_comp); + return 1; + } + if (transport_off) { + atomic_set(&T_TASK(cmd)->t_transport_active, 0); + if (transport_off == 2) { + transport_all_task_dev_remove_state(cmd); + /* + * Clear struct se_cmd->se_lun before the transport_off == 2 + * handoff to fabric module. + */ + cmd->se_lun = NULL; + /* + * Some fabric modules like tcm_loop can release + * their internally allocated I/O refrence now and + * struct se_cmd now. + */ + if (CMD_TFO(cmd)->check_stop_free != NULL) { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + + CMD_TFO(cmd)->check_stop_free(cmd); + return 1; + } + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + return 0; + } else if (t_state) + cmd->t_state = t_state; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + return 0; +} + +static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd) +{ + return transport_cmd_check_stop(cmd, 2, 0); +} + +static void transport_lun_remove_cmd(struct se_cmd *cmd) +{ + struct se_lun *lun = SE_LUN(cmd); + unsigned long flags; + + if (!lun) + return; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + goto check_lun; + } + atomic_set(&T_TASK(cmd)->transport_dev_active, 0); + transport_all_task_dev_remove_state(cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_free_dev_tasks(cmd); + +check_lun: + spin_lock_irqsave(&lun->lun_cmd_lock, flags); + if (atomic_read(&T_TASK(cmd)->transport_lun_active)) { + list_del(&cmd->se_lun_list); + atomic_set(&T_TASK(cmd)->transport_lun_active, 0); +#if 0 + printk(KERN_INFO "Removed ITT: 0x%08x from LUN LIST[%d]\n" + CMD_TFO(cmd)->get_task_tag(cmd), lun->unpacked_lun); +#endif + } + spin_unlock_irqrestore(&lun->lun_cmd_lock, flags); +} + +void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) +{ + transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj); + transport_lun_remove_cmd(cmd); + + if (transport_cmd_check_stop_to_fabric(cmd)) + return; + if (remove) + transport_generic_remove(cmd, 0, 0); +} + +void transport_cmd_finish_abort_tmr(struct se_cmd *cmd) +{ + transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj); + + if (transport_cmd_check_stop_to_fabric(cmd)) + return; + + transport_generic_remove(cmd, 0, 0); +} + +static int transport_add_cmd_to_queue( + struct se_cmd *cmd, + int t_state) +{ + struct se_device *dev = cmd->se_dev; + struct se_queue_obj *qobj = dev->dev_queue_obj; + struct se_queue_req *qr; + unsigned long flags; + + qr = kzalloc(sizeof(struct se_queue_req), GFP_ATOMIC); + if (!(qr)) { + printk(KERN_ERR "Unable to allocate memory for" + " struct se_queue_req\n"); + return -1; + } + INIT_LIST_HEAD(&qr->qr_list); + + qr->cmd = (void *)cmd; + qr->state = t_state; + + if (t_state) { + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + cmd->t_state = t_state; + atomic_set(&T_TASK(cmd)->t_transport_active, 1); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + } + + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + list_add_tail(&qr->qr_list, &qobj->qobj_list); + atomic_inc(&T_TASK(cmd)->t_transport_queue_active); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + + atomic_inc(&qobj->queue_cnt); + wake_up_interruptible(&qobj->thread_wq); + return 0; +} + +/* + * Called with struct se_queue_obj->cmd_queue_lock held. + */ +static struct se_queue_req * +__transport_get_qr_from_queue(struct se_queue_obj *qobj) +{ + struct se_cmd *cmd; + struct se_queue_req *qr = NULL; + + if (list_empty(&qobj->qobj_list)) + return NULL; + + list_for_each_entry(qr, &qobj->qobj_list, qr_list) + break; + + if (qr->cmd) { + cmd = (struct se_cmd *)qr->cmd; + atomic_dec(&T_TASK(cmd)->t_transport_queue_active); + } + list_del(&qr->qr_list); + atomic_dec(&qobj->queue_cnt); + + return qr; +} + +static struct se_queue_req * +transport_get_qr_from_queue(struct se_queue_obj *qobj) +{ + struct se_cmd *cmd; + struct se_queue_req *qr; + unsigned long flags; + + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + if (list_empty(&qobj->qobj_list)) { + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + return NULL; + } + + list_for_each_entry(qr, &qobj->qobj_list, qr_list) + break; + + if (qr->cmd) { + cmd = (struct se_cmd *)qr->cmd; + atomic_dec(&T_TASK(cmd)->t_transport_queue_active); + } + list_del(&qr->qr_list); + atomic_dec(&qobj->queue_cnt); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + + return qr; +} + +static void transport_remove_cmd_from_queue(struct se_cmd *cmd, + struct se_queue_obj *qobj) +{ + struct se_cmd *q_cmd; + struct se_queue_req *qr = NULL, *qr_p = NULL; + unsigned long flags; + + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + if (!(atomic_read(&T_TASK(cmd)->t_transport_queue_active))) { + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + return; + } + + list_for_each_entry_safe(qr, qr_p, &qobj->qobj_list, qr_list) { + q_cmd = (struct se_cmd *)qr->cmd; + if (q_cmd != cmd) + continue; + + atomic_dec(&T_TASK(q_cmd)->t_transport_queue_active); + atomic_dec(&qobj->queue_cnt); + list_del(&qr->qr_list); + kfree(qr); + } + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + + if (atomic_read(&T_TASK(cmd)->t_transport_queue_active)) { + printk(KERN_ERR "ITT: 0x%08x t_transport_queue_active: %d\n", + CMD_TFO(cmd)->get_task_tag(cmd), + atomic_read(&T_TASK(cmd)->t_transport_queue_active)); + } +} + +/* + * Completion function used by TCM subsystem plugins (such as FILEIO) + * for queueing up response from struct se_subsystem_api->do_task() + */ +void transport_complete_sync_cache(struct se_cmd *cmd, int good) +{ + struct se_task *task = list_entry(T_TASK(cmd)->t_task_list.next, + struct se_task, t_list); + + if (good) { + cmd->scsi_status = SAM_STAT_GOOD; + task->task_scsi_status = GOOD; + } else { + task->task_scsi_status = SAM_STAT_CHECK_CONDITION; + task->task_error_status = PYX_TRANSPORT_ILLEGAL_REQUEST; + TASK_CMD(task)->transport_error_status = + PYX_TRANSPORT_ILLEGAL_REQUEST; + } + + transport_complete_task(task, good); +} +EXPORT_SYMBOL(transport_complete_sync_cache); + +/* transport_complete_task(): + * + * Called from interrupt and non interrupt context depending + * on the transport plugin. + */ +void transport_complete_task(struct se_task *task, int success) +{ + struct se_cmd *cmd = TASK_CMD(task); + struct se_device *dev = task->se_dev; + int t_state; + unsigned long flags; +#if 0 + printk(KERN_INFO "task: %p CDB: 0x%02x obj_ptr: %p\n", task, + T_TASK(cmd)->t_task_cdb[0], dev); +#endif + if (dev) { + spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags); + atomic_inc(&dev->depth_left); + atomic_inc(&SE_HBA(dev)->left_queue_depth); + spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags); + } + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + atomic_set(&task->task_active, 0); + + /* + * See if any sense data exists, if so set the TASK_SENSE flag. + * Also check for any other post completion work that needs to be + * done by the plugins. + */ + if (dev && dev->transport->transport_complete) { + if (dev->transport->transport_complete(task) != 0) { + cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; + task->task_sense = 1; + success = 1; + } + } + + /* + * See if we are waiting for outstanding struct se_task + * to complete for an exception condition + */ + if (atomic_read(&task->task_stop)) { + /* + * Decrement T_TASK(cmd)->t_se_count if this task had + * previously thrown its timeout exception handler. + */ + if (atomic_read(&task->task_timeout)) { + atomic_dec(&T_TASK(cmd)->t_se_count); + atomic_set(&task->task_timeout, 0); + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + complete(&task->task_stop_comp); + return; + } + /* + * If the task's timeout handler has fired, use the t_task_cdbs_timeout + * left counter to determine when the struct se_cmd is ready to be queued to + * the processing thread. + */ + if (atomic_read(&task->task_timeout)) { + if (!(atomic_dec_and_test( + &T_TASK(cmd)->t_task_cdbs_timeout_left))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + return; + } + t_state = TRANSPORT_COMPLETE_TIMEOUT; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_add_cmd_to_queue(cmd, t_state); + return; + } + atomic_dec(&T_TASK(cmd)->t_task_cdbs_timeout_left); + + /* + * Decrement the outstanding t_task_cdbs_left count. The last + * struct se_task from struct se_cmd will complete itself into the + * device queue depending upon int success. + */ + if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_left))) { + if (!success) + T_TASK(cmd)->t_tasks_failed = 1; + + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return; + } + + if (!success || T_TASK(cmd)->t_tasks_failed) { + t_state = TRANSPORT_COMPLETE_FAILURE; + if (!task->task_error_status) { + task->task_error_status = + PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->transport_error_status = + PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + } + } else { + atomic_set(&T_TASK(cmd)->t_transport_complete, 1); + t_state = TRANSPORT_COMPLETE_OK; + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_add_cmd_to_queue(cmd, t_state); +} +EXPORT_SYMBOL(transport_complete_task); + +/* + * Called by transport_add_tasks_from_cmd() once a struct se_cmd's + * struct se_task list are ready to be added to the active execution list + * struct se_device + + * Called with se_dev_t->execute_task_lock called. + */ +static inline int transport_add_task_check_sam_attr( + struct se_task *task, + struct se_task *task_prev, + struct se_device *dev) +{ + /* + * No SAM Task attribute emulation enabled, add to tail of + * execution queue + */ + if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) { + list_add_tail(&task->t_execute_list, &dev->execute_task_list); + return 0; + } + /* + * HEAD_OF_QUEUE attribute for received CDB, which means + * the first task that is associated with a struct se_cmd goes to + * head of the struct se_device->execute_task_list, and task_prev + * after that for each subsequent task + */ + if (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ) { + list_add(&task->t_execute_list, + (task_prev != NULL) ? + &task_prev->t_execute_list : + &dev->execute_task_list); + + DEBUG_STA("Set HEAD_OF_QUEUE for task CDB: 0x%02x" + " in execution queue\n", + T_TASK(task->task_se_cmd)->t_task_cdb[0]); + return 1; + } + /* + * For ORDERED, SIMPLE or UNTAGGED attribute tasks once they have been + * transitioned from Dermant -> Active state, and are added to the end + * of the struct se_device->execute_task_list + */ + list_add_tail(&task->t_execute_list, &dev->execute_task_list); + return 0; +} + +/* __transport_add_task_to_execute_queue(): + * + * Called with se_dev_t->execute_task_lock called. + */ +static void __transport_add_task_to_execute_queue( + struct se_task *task, + struct se_task *task_prev, + struct se_device *dev) +{ + int head_of_queue; + + head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev); + atomic_inc(&dev->execute_tasks); + + if (atomic_read(&task->task_state_active)) + return; + /* + * Determine if this task needs to go to HEAD_OF_QUEUE for the + * state list as well. Running with SAM Task Attribute emulation + * will always return head_of_queue == 0 here + */ + if (head_of_queue) + list_add(&task->t_state_list, (task_prev) ? + &task_prev->t_state_list : + &dev->state_task_list); + else + list_add_tail(&task->t_state_list, &dev->state_task_list); + + atomic_set(&task->task_state_active, 1); + + DEBUG_TSTATE("Added ITT: 0x%08x task[%p] to dev: %p\n", + CMD_TFO(task->task_se_cmd)->get_task_tag(task->task_se_cmd), + task, dev); +} + +static void transport_add_tasks_to_state_queue(struct se_cmd *cmd) +{ + struct se_device *dev; + struct se_task *task; + unsigned long flags; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) { + dev = task->se_dev; + + if (atomic_read(&task->task_state_active)) + continue; + + spin_lock(&dev->execute_task_lock); + list_add_tail(&task->t_state_list, &dev->state_task_list); + atomic_set(&task->task_state_active, 1); + + DEBUG_TSTATE("Added ITT: 0x%08x task[%p] to dev: %p\n", + CMD_TFO(task->task_se_cmd)->get_task_tag( + task->task_se_cmd), task, dev); + + spin_unlock(&dev->execute_task_lock); + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); +} + +static void transport_add_tasks_from_cmd(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_task *task, *task_prev = NULL; + unsigned long flags; + + spin_lock_irqsave(&dev->execute_task_lock, flags); + list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) { + if (atomic_read(&task->task_execute_queue)) + continue; + /* + * __transport_add_task_to_execute_queue() handles the + * SAM Task Attribute emulation if enabled + */ + __transport_add_task_to_execute_queue(task, task_prev, dev); + atomic_set(&task->task_execute_queue, 1); + task_prev = task; + } + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + + return; +} + +/* transport_get_task_from_execute_queue(): + * + * Called with dev->execute_task_lock held. + */ +static struct se_task * +transport_get_task_from_execute_queue(struct se_device *dev) +{ + struct se_task *task; + + if (list_empty(&dev->execute_task_list)) + return NULL; + + list_for_each_entry(task, &dev->execute_task_list, t_execute_list) + break; + + list_del(&task->t_execute_list); + atomic_dec(&dev->execute_tasks); + + return task; +} + +/* transport_remove_task_from_execute_queue(): + * + * + */ +static void transport_remove_task_from_execute_queue( + struct se_task *task, + struct se_device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->execute_task_lock, flags); + list_del(&task->t_execute_list); + atomic_dec(&dev->execute_tasks); + spin_unlock_irqrestore(&dev->execute_task_lock, flags); +} + +unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd) +{ + switch (cmd->data_direction) { + case DMA_NONE: + return "NONE"; + case DMA_FROM_DEVICE: + return "READ"; + case DMA_TO_DEVICE: + return "WRITE"; + case DMA_BIDIRECTIONAL: + return "BIDI"; + default: + break; + } + + return "UNKNOWN"; +} + +void transport_dump_dev_state( + struct se_device *dev, + char *b, + int *bl) +{ + *bl += sprintf(b + *bl, "Status: "); + switch (dev->dev_status) { + case TRANSPORT_DEVICE_ACTIVATED: + *bl += sprintf(b + *bl, "ACTIVATED"); + break; + case TRANSPORT_DEVICE_DEACTIVATED: + *bl += sprintf(b + *bl, "DEACTIVATED"); + break; + case TRANSPORT_DEVICE_SHUTDOWN: + *bl += sprintf(b + *bl, "SHUTDOWN"); + break; + case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: + case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: + *bl += sprintf(b + *bl, "OFFLINE"); + break; + default: + *bl += sprintf(b + *bl, "UNKNOWN=%d", dev->dev_status); + break; + } + + *bl += sprintf(b + *bl, " Execute/Left/Max Queue Depth: %d/%d/%d", + atomic_read(&dev->execute_tasks), atomic_read(&dev->depth_left), + dev->queue_depth); + *bl += sprintf(b + *bl, " SectorSize: %u MaxSectors: %u\n", + DEV_ATTRIB(dev)->block_size, DEV_ATTRIB(dev)->max_sectors); + *bl += sprintf(b + *bl, " "); +} + +/* transport_release_all_cmds(): + * + * + */ +static void transport_release_all_cmds(struct se_device *dev) +{ + struct se_cmd *cmd = NULL; + struct se_queue_req *qr = NULL, *qr_p = NULL; + int bug_out = 0, t_state; + unsigned long flags; + + spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags); + list_for_each_entry_safe(qr, qr_p, &dev->dev_queue_obj->qobj_list, + qr_list) { + + cmd = (struct se_cmd *)qr->cmd; + t_state = qr->state; + list_del(&qr->qr_list); + kfree(qr); + spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, + flags); + + printk(KERN_ERR "Releasing ITT: 0x%08x, i_state: %u," + " t_state: %u directly\n", + CMD_TFO(cmd)->get_task_tag(cmd), + CMD_TFO(cmd)->get_cmd_state(cmd), t_state); + + transport_release_fe_cmd(cmd); + bug_out = 1; + + spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags); + } + spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, flags); +#if 0 + if (bug_out) + BUG(); +#endif +} + +void transport_dump_vpd_proto_id( + struct t10_vpd *vpd, + unsigned char *p_buf, + int p_buf_len) +{ + unsigned char buf[VPD_TMP_BUF_SIZE]; + int len; + + memset(buf, 0, VPD_TMP_BUF_SIZE); + len = sprintf(buf, "T10 VPD Protocol Identifier: "); + + switch (vpd->protocol_identifier) { + case 0x00: + sprintf(buf+len, "Fibre Channel\n"); + break; + case 0x10: + sprintf(buf+len, "Parallel SCSI\n"); + break; + case 0x20: + sprintf(buf+len, "SSA\n"); + break; + case 0x30: + sprintf(buf+len, "IEEE 1394\n"); + break; + case 0x40: + sprintf(buf+len, "SCSI Remote Direct Memory Access" + " Protocol\n"); + break; + case 0x50: + sprintf(buf+len, "Internet SCSI (iSCSI)\n"); + break; + case 0x60: + sprintf(buf+len, "SAS Serial SCSI Protocol\n"); + break; + case 0x70: + sprintf(buf+len, "Automation/Drive Interface Transport" + " Protocol\n"); + break; + case 0x80: + sprintf(buf+len, "AT Attachment Interface ATA/ATAPI\n"); + break; + default: + sprintf(buf+len, "Unknown 0x%02x\n", + vpd->protocol_identifier); + break; + } + + if (p_buf) + strncpy(p_buf, buf, p_buf_len); + else + printk(KERN_INFO "%s", buf); +} + +void +transport_set_vpd_proto_id(struct t10_vpd *vpd, unsigned char *page_83) +{ + /* + * Check if the Protocol Identifier Valid (PIV) bit is set.. + * + * from spc3r23.pdf section 7.5.1 + */ + if (page_83[1] & 0x80) { + vpd->protocol_identifier = (page_83[0] & 0xf0); + vpd->protocol_identifier_set = 1; + transport_dump_vpd_proto_id(vpd, NULL, 0); + } +} +EXPORT_SYMBOL(transport_set_vpd_proto_id); + +int transport_dump_vpd_assoc( + struct t10_vpd *vpd, + unsigned char *p_buf, + int p_buf_len) +{ + unsigned char buf[VPD_TMP_BUF_SIZE]; + int ret = 0, len; + + memset(buf, 0, VPD_TMP_BUF_SIZE); + len = sprintf(buf, "T10 VPD Identifier Association: "); + + switch (vpd->association) { + case 0x00: + sprintf(buf+len, "addressed logical unit\n"); + break; + case 0x10: + sprintf(buf+len, "target port\n"); + break; + case 0x20: + sprintf(buf+len, "SCSI target device\n"); + break; + default: + sprintf(buf+len, "Unknown 0x%02x\n", vpd->association); + ret = -1; + break; + } + + if (p_buf) + strncpy(p_buf, buf, p_buf_len); + else + printk("%s", buf); + + return ret; +} + +int transport_set_vpd_assoc(struct t10_vpd *vpd, unsigned char *page_83) +{ + /* + * The VPD identification association.. + * + * from spc3r23.pdf Section 7.6.3.1 Table 297 + */ + vpd->association = (page_83[1] & 0x30); + return transport_dump_vpd_assoc(vpd, NULL, 0); +} +EXPORT_SYMBOL(transport_set_vpd_assoc); + +int transport_dump_vpd_ident_type( + struct t10_vpd *vpd, + unsigned char *p_buf, + int p_buf_len) +{ + unsigned char buf[VPD_TMP_BUF_SIZE]; + int ret = 0, len; + + memset(buf, 0, VPD_TMP_BUF_SIZE); + len = sprintf(buf, "T10 VPD Identifier Type: "); + + switch (vpd->device_identifier_type) { + case 0x00: + sprintf(buf+len, "Vendor specific\n"); + break; + case 0x01: + sprintf(buf+len, "T10 Vendor ID based\n"); + break; + case 0x02: + sprintf(buf+len, "EUI-64 based\n"); + break; + case 0x03: + sprintf(buf+len, "NAA\n"); + break; + case 0x04: + sprintf(buf+len, "Relative target port identifier\n"); + break; + case 0x08: + sprintf(buf+len, "SCSI name string\n"); + break; + default: + sprintf(buf+len, "Unsupported: 0x%02x\n", + vpd->device_identifier_type); + ret = -1; + break; + } + + if (p_buf) + strncpy(p_buf, buf, p_buf_len); + else + printk("%s", buf); + + return ret; +} + +int transport_set_vpd_ident_type(struct t10_vpd *vpd, unsigned char *page_83) +{ + /* + * The VPD identifier type.. + * + * from spc3r23.pdf Section 7.6.3.1 Table 298 + */ + vpd->device_identifier_type = (page_83[1] & 0x0f); + return transport_dump_vpd_ident_type(vpd, NULL, 0); +} +EXPORT_SYMBOL(transport_set_vpd_ident_type); + +int transport_dump_vpd_ident( + struct t10_vpd *vpd, + unsigned char *p_buf, + int p_buf_len) +{ + unsigned char buf[VPD_TMP_BUF_SIZE]; + int ret = 0; + + memset(buf, 0, VPD_TMP_BUF_SIZE); + + switch (vpd->device_identifier_code_set) { + case 0x01: /* Binary */ + sprintf(buf, "T10 VPD Binary Device Identifier: %s\n", + &vpd->device_identifier[0]); + break; + case 0x02: /* ASCII */ + sprintf(buf, "T10 VPD ASCII Device Identifier: %s\n", + &vpd->device_identifier[0]); + break; + case 0x03: /* UTF-8 */ + sprintf(buf, "T10 VPD UTF-8 Device Identifier: %s\n", + &vpd->device_identifier[0]); + break; + default: + sprintf(buf, "T10 VPD Device Identifier encoding unsupported:" + " 0x%02x", vpd->device_identifier_code_set); + ret = -1; + break; + } + + if (p_buf) + strncpy(p_buf, buf, p_buf_len); + else + printk("%s", buf); + + return ret; +} + +int +transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83) +{ + static const char hex_str[] = "0123456789abcdef"; + int j = 0, i = 4; /* offset to start of the identifer */ + + /* + * The VPD Code Set (encoding) + * + * from spc3r23.pdf Section 7.6.3.1 Table 296 + */ + vpd->device_identifier_code_set = (page_83[0] & 0x0f); + switch (vpd->device_identifier_code_set) { + case 0x01: /* Binary */ + vpd->device_identifier[j++] = + hex_str[vpd->device_identifier_type]; + while (i < (4 + page_83[3])) { + vpd->device_identifier[j++] = + hex_str[(page_83[i] & 0xf0) >> 4]; + vpd->device_identifier[j++] = + hex_str[page_83[i] & 0x0f]; + i++; + } + break; + case 0x02: /* ASCII */ + case 0x03: /* UTF-8 */ + while (i < (4 + page_83[3])) + vpd->device_identifier[j++] = page_83[i++]; + break; + default: + break; + } + + return transport_dump_vpd_ident(vpd, NULL, 0); +} +EXPORT_SYMBOL(transport_set_vpd_ident); + +static void core_setup_task_attr_emulation(struct se_device *dev) +{ + /* + * If this device is from Target_Core_Mod/pSCSI, disable the + * SAM Task Attribute emulation. + * + * This is currently not available in upsream Linux/SCSI Target + * mode code, and is assumed to be disabled while using TCM/pSCSI. + */ + if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { + dev->dev_task_attr_type = SAM_TASK_ATTR_PASSTHROUGH; + return; + } + + dev->dev_task_attr_type = SAM_TASK_ATTR_EMULATED; + DEBUG_STA("%s: Using SAM_TASK_ATTR_EMULATED for SPC: 0x%02x" + " device\n", TRANSPORT(dev)->name, + TRANSPORT(dev)->get_device_rev(dev)); +} + +static void scsi_dump_inquiry(struct se_device *dev) +{ + struct t10_wwn *wwn = DEV_T10_WWN(dev); + int i, device_type; + /* + * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer + */ + printk(" Vendor: "); + for (i = 0; i < 8; i++) + if (wwn->vendor[i] >= 0x20) + printk("%c", wwn->vendor[i]); + else + printk(" "); + + printk(" Model: "); + for (i = 0; i < 16; i++) + if (wwn->model[i] >= 0x20) + printk("%c", wwn->model[i]); + else + printk(" "); + + printk(" Revision: "); + for (i = 0; i < 4; i++) + if (wwn->revision[i] >= 0x20) + printk("%c", wwn->revision[i]); + else + printk(" "); + + printk("\n"); + + device_type = TRANSPORT(dev)->get_device_type(dev); + printk(" Type: %s ", scsi_device_type(device_type)); + printk(" ANSI SCSI revision: %02x\n", + TRANSPORT(dev)->get_device_rev(dev)); +} + +struct se_device *transport_add_device_to_core_hba( + struct se_hba *hba, + struct se_subsystem_api *transport, + struct se_subsystem_dev *se_dev, + u32 device_flags, + void *transport_dev, + struct se_dev_limits *dev_limits, + const char *inquiry_prod, + const char *inquiry_rev) +{ + int ret = 0, force_pt; + struct se_device *dev; + + dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); + if (!(dev)) { + printk(KERN_ERR "Unable to allocate memory for se_dev_t\n"); + return NULL; + } + dev->dev_queue_obj = kzalloc(sizeof(struct se_queue_obj), GFP_KERNEL); + if (!(dev->dev_queue_obj)) { + printk(KERN_ERR "Unable to allocate memory for" + " dev->dev_queue_obj\n"); + kfree(dev); + return NULL; + } + transport_init_queue_obj(dev->dev_queue_obj); + + dev->dev_status_queue_obj = kzalloc(sizeof(struct se_queue_obj), + GFP_KERNEL); + if (!(dev->dev_status_queue_obj)) { + printk(KERN_ERR "Unable to allocate memory for" + " dev->dev_status_queue_obj\n"); + kfree(dev->dev_queue_obj); + kfree(dev); + return NULL; + } + transport_init_queue_obj(dev->dev_status_queue_obj); + + dev->dev_flags = device_flags; + dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED; + dev->dev_ptr = (void *) transport_dev; + dev->se_hba = hba; + dev->se_sub_dev = se_dev; + dev->transport = transport; + atomic_set(&dev->active_cmds, 0); + INIT_LIST_HEAD(&dev->dev_list); + INIT_LIST_HEAD(&dev->dev_sep_list); + INIT_LIST_HEAD(&dev->dev_tmr_list); + INIT_LIST_HEAD(&dev->execute_task_list); + INIT_LIST_HEAD(&dev->delayed_cmd_list); + INIT_LIST_HEAD(&dev->ordered_cmd_list); + INIT_LIST_HEAD(&dev->state_task_list); + spin_lock_init(&dev->execute_task_lock); + spin_lock_init(&dev->delayed_cmd_lock); + spin_lock_init(&dev->ordered_cmd_lock); + spin_lock_init(&dev->state_task_lock); + spin_lock_init(&dev->dev_alua_lock); + spin_lock_init(&dev->dev_reservation_lock); + spin_lock_init(&dev->dev_status_lock); + spin_lock_init(&dev->dev_status_thr_lock); + spin_lock_init(&dev->se_port_lock); + spin_lock_init(&dev->se_tmr_lock); + + dev->queue_depth = dev_limits->queue_depth; + atomic_set(&dev->depth_left, dev->queue_depth); + atomic_set(&dev->dev_ordered_id, 0); + + se_dev_set_default_attribs(dev, dev_limits); + + dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX); + dev->creation_time = get_jiffies_64(); + spin_lock_init(&dev->stats_lock); + + spin_lock(&hba->device_lock); + list_add_tail(&dev->dev_list, &hba->hba_dev_list); + hba->dev_count++; + spin_unlock(&hba->device_lock); + /* + * Setup the SAM Task Attribute emulation for struct se_device + */ + core_setup_task_attr_emulation(dev); + /* + * Force PR and ALUA passthrough emulation with internal object use. + */ + force_pt = (hba->hba_flags & HBA_FLAGS_INTERNAL_USE); + /* + * Setup the Reservations infrastructure for struct se_device + */ + core_setup_reservations(dev, force_pt); + /* + * Setup the Asymmetric Logical Unit Assignment for struct se_device + */ + if (core_setup_alua(dev, force_pt) < 0) + goto out; + + /* + * Startup the struct se_device processing thread + */ + dev->process_thread = kthread_run(transport_processing_thread, dev, + "LIO_%s", TRANSPORT(dev)->name); + if (IS_ERR(dev->process_thread)) { + printk(KERN_ERR "Unable to create kthread: LIO_%s\n", + TRANSPORT(dev)->name); + goto out; + } + + /* + * Preload the initial INQUIRY const values if we are doing + * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI + * passthrough because this is being provided by the backend LLD. + * This is required so that transport_get_inquiry() copies these + * originals once back into DEV_T10_WWN(dev) for the virtual device + * setup. + */ + if (TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { + if (!(inquiry_prod) || !(inquiry_prod)) { + printk(KERN_ERR "All non TCM/pSCSI plugins require" + " INQUIRY consts\n"); + goto out; + } + + strncpy(&DEV_T10_WWN(dev)->vendor[0], "LIO-ORG", 8); + strncpy(&DEV_T10_WWN(dev)->model[0], inquiry_prod, 16); + strncpy(&DEV_T10_WWN(dev)->revision[0], inquiry_rev, 4); + } + scsi_dump_inquiry(dev); + +out: + if (!ret) + return dev; + kthread_stop(dev->process_thread); + + spin_lock(&hba->device_lock); + list_del(&dev->dev_list); + hba->dev_count--; + spin_unlock(&hba->device_lock); + + se_release_vpd_for_dev(dev); + + kfree(dev->dev_status_queue_obj); + kfree(dev->dev_queue_obj); + kfree(dev); + + return NULL; +} +EXPORT_SYMBOL(transport_add_device_to_core_hba); + +/* transport_generic_prepare_cdb(): + * + * Since the Initiator sees iSCSI devices as LUNs, the SCSI CDB will + * contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2. + * The point of this is since we are mapping iSCSI LUNs to + * SCSI Target IDs having a non-zero LUN in the CDB will throw the + * devices and HBAs for a loop. + */ +static inline void transport_generic_prepare_cdb( + unsigned char *cdb) +{ + switch (cdb[0]) { + case READ_10: /* SBC - RDProtect */ + case READ_12: /* SBC - RDProtect */ + case READ_16: /* SBC - RDProtect */ + case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ + case VERIFY: /* SBC - VRProtect */ + case VERIFY_16: /* SBC - VRProtect */ + case WRITE_VERIFY: /* SBC - VRProtect */ + case WRITE_VERIFY_12: /* SBC - VRProtect */ + break; + default: + cdb[1] &= 0x1f; /* clear logical unit number */ + break; + } +} + +static struct se_task * +transport_generic_get_task(struct se_cmd *cmd, + enum dma_data_direction data_direction) +{ + struct se_task *task; + struct se_device *dev = SE_DEV(cmd); + unsigned long flags; + + task = dev->transport->alloc_task(cmd); + if (!task) { + printk(KERN_ERR "Unable to allocate struct se_task\n"); + return NULL; + } + + INIT_LIST_HEAD(&task->t_list); + INIT_LIST_HEAD(&task->t_execute_list); + INIT_LIST_HEAD(&task->t_state_list); + init_completion(&task->task_stop_comp); + task->task_no = T_TASK(cmd)->t_tasks_no++; + task->task_se_cmd = cmd; + task->se_dev = dev; + task->task_data_direction = data_direction; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + list_add_tail(&task->t_list, &T_TASK(cmd)->t_task_list); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + return task; +} + +static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); + +void transport_device_setup_cmd(struct se_cmd *cmd) +{ + cmd->se_dev = SE_LUN(cmd)->lun_se_dev; +} +EXPORT_SYMBOL(transport_device_setup_cmd); + +/* + * Used by fabric modules containing a local struct se_cmd within their + * fabric dependent per I/O descriptor. + */ +void transport_init_se_cmd( + struct se_cmd *cmd, + struct target_core_fabric_ops *tfo, + struct se_session *se_sess, + u32 data_length, + int data_direction, + int task_attr, + unsigned char *sense_buffer) +{ + INIT_LIST_HEAD(&cmd->se_lun_list); + INIT_LIST_HEAD(&cmd->se_delayed_list); + INIT_LIST_HEAD(&cmd->se_ordered_list); + /* + * Setup t_task pointer to t_task_backstore + */ + cmd->t_task = &cmd->t_task_backstore; + + INIT_LIST_HEAD(&T_TASK(cmd)->t_task_list); + init_completion(&T_TASK(cmd)->transport_lun_fe_stop_comp); + init_completion(&T_TASK(cmd)->transport_lun_stop_comp); + init_completion(&T_TASK(cmd)->t_transport_stop_comp); + spin_lock_init(&T_TASK(cmd)->t_state_lock); + atomic_set(&T_TASK(cmd)->transport_dev_active, 1); + + cmd->se_tfo = tfo; + cmd->se_sess = se_sess; + cmd->data_length = data_length; + cmd->data_direction = data_direction; + cmd->sam_task_attr = task_attr; + cmd->sense_buffer = sense_buffer; +} +EXPORT_SYMBOL(transport_init_se_cmd); + +static int transport_check_alloc_task_attr(struct se_cmd *cmd) +{ + /* + * Check if SAM Task Attribute emulation is enabled for this + * struct se_device storage object + */ + if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) + return 0; + + if (cmd->sam_task_attr == TASK_ATTR_ACA) { + DEBUG_STA("SAM Task Attribute ACA" + " emulation is not supported\n"); + return -1; + } + /* + * Used to determine when ORDERED commands should go from + * Dormant to Active status. + */ + cmd->se_ordered_id = atomic_inc_return(&SE_DEV(cmd)->dev_ordered_id); + smp_mb__after_atomic_inc(); + DEBUG_STA("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n", + cmd->se_ordered_id, cmd->sam_task_attr, + TRANSPORT(cmd->se_dev)->name); + return 0; +} + +void transport_free_se_cmd( + struct se_cmd *se_cmd) +{ + if (se_cmd->se_tmr_req) + core_tmr_release_req(se_cmd->se_tmr_req); + /* + * Check and free any extended CDB buffer that was allocated + */ + if (T_TASK(se_cmd)->t_task_cdb != T_TASK(se_cmd)->__t_task_cdb) + kfree(T_TASK(se_cmd)->t_task_cdb); +} +EXPORT_SYMBOL(transport_free_se_cmd); + +static void transport_generic_wait_for_tasks(struct se_cmd *, int, int); + +/* transport_generic_allocate_tasks(): + * + * Called from fabric RX Thread. + */ +int transport_generic_allocate_tasks( + struct se_cmd *cmd, + unsigned char *cdb) +{ + int ret; + + transport_generic_prepare_cdb(cdb); + + /* + * This is needed for early exceptions. + */ + cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks; + + transport_device_setup_cmd(cmd); + /* + * Ensure that the received CDB is less than the max (252 + 8) bytes + * for VARIABLE_LENGTH_CMD + */ + if (scsi_command_size(cdb) > SCSI_MAX_VARLEN_CDB_SIZE) { + printk(KERN_ERR "Received SCSI CDB with command_size: %d that" + " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", + scsi_command_size(cdb), SCSI_MAX_VARLEN_CDB_SIZE); + return -1; + } + /* + * If the received CDB is larger than TCM_MAX_COMMAND_SIZE, + * allocate the additional extended CDB buffer now.. Otherwise + * setup the pointer from __t_task_cdb to t_task_cdb. + */ + if (scsi_command_size(cdb) > sizeof(T_TASK(cmd)->__t_task_cdb)) { + T_TASK(cmd)->t_task_cdb = kzalloc(scsi_command_size(cdb), + GFP_KERNEL); + if (!(T_TASK(cmd)->t_task_cdb)) { + printk(KERN_ERR "Unable to allocate T_TASK(cmd)->t_task_cdb" + " %u > sizeof(T_TASK(cmd)->__t_task_cdb): %lu ops\n", + scsi_command_size(cdb), + (unsigned long)sizeof(T_TASK(cmd)->__t_task_cdb)); + return -1; + } + } else + T_TASK(cmd)->t_task_cdb = &T_TASK(cmd)->__t_task_cdb[0]; + /* + * Copy the original CDB into T_TASK(cmd). + */ + memcpy(T_TASK(cmd)->t_task_cdb, cdb, scsi_command_size(cdb)); + /* + * Setup the received CDB based on SCSI defined opcodes and + * perform unit attention, persistent reservations and ALUA + * checks for virtual device backends. The T_TASK(cmd)->t_task_cdb + * pointer is expected to be setup before we reach this point. + */ + ret = transport_generic_cmd_sequencer(cmd, cdb); + if (ret < 0) + return ret; + /* + * Check for SAM Task Attribute Emulation + */ + if (transport_check_alloc_task_attr(cmd) < 0) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -2; + } + spin_lock(&cmd->se_lun->lun_sep_lock); + if (cmd->se_lun->lun_sep) + cmd->se_lun->lun_sep->sep_stats.cmd_pdus++; + spin_unlock(&cmd->se_lun->lun_sep_lock); + return 0; +} +EXPORT_SYMBOL(transport_generic_allocate_tasks); + +/* + * Used by fabric module frontends not defining a TFO->new_cmd_map() + * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD statis + */ +int transport_generic_handle_cdb( + struct se_cmd *cmd) +{ + if (!SE_LUN(cmd)) { + dump_stack(); + printk(KERN_ERR "SE_LUN(cmd) is NULL\n"); + return -1; + } + + transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD); + return 0; +} +EXPORT_SYMBOL(transport_generic_handle_cdb); + +/* + * Used by fabric module frontends defining a TFO->new_cmd_map() caller + * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to + * complete setup in TCM process context w/ TFO->new_cmd_map(). + */ +int transport_generic_handle_cdb_map( + struct se_cmd *cmd) +{ + if (!SE_LUN(cmd)) { + dump_stack(); + printk(KERN_ERR "SE_LUN(cmd) is NULL\n"); + return -1; + } + + transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP); + return 0; +} +EXPORT_SYMBOL(transport_generic_handle_cdb_map); + +/* transport_generic_handle_data(): + * + * + */ +int transport_generic_handle_data( + struct se_cmd *cmd) +{ + /* + * For the software fabric case, then we assume the nexus is being + * failed/shutdown when signals are pending from the kthread context + * caller, so we return a failure. For the HW target mode case running + * in interrupt code, the signal_pending() check is skipped. + */ + if (!in_interrupt() && signal_pending(current)) + return -1; + /* + * If the received CDB has aleady been ABORTED by the generic + * target engine, we now call transport_check_aborted_status() + * to queue any delated TASK_ABORTED status for the received CDB to the + * fabric module as we are expecting no futher incoming DATA OUT + * sequences at this point. + */ + if (transport_check_aborted_status(cmd, 1) != 0) + return 0; + + transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE); + return 0; +} +EXPORT_SYMBOL(transport_generic_handle_data); + +/* transport_generic_handle_tmr(): + * + * + */ +int transport_generic_handle_tmr( + struct se_cmd *cmd) +{ + /* + * This is needed for early exceptions. + */ + cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks; + transport_device_setup_cmd(cmd); + + transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR); + return 0; +} +EXPORT_SYMBOL(transport_generic_handle_tmr); + +static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) +{ + struct se_task *task, *task_tmp; + unsigned long flags; + int ret = 0; + + DEBUG_TS("ITT[0x%08x] - Stopping tasks\n", + CMD_TFO(cmd)->get_task_tag(cmd)); + + /* + * No tasks remain in the execution queue + */ + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + list_for_each_entry_safe(task, task_tmp, + &T_TASK(cmd)->t_task_list, t_list) { + DEBUG_TS("task_no[%d] - Processing task %p\n", + task->task_no, task); + /* + * If the struct se_task has not been sent and is not active, + * remove the struct se_task from the execution queue. + */ + if (!atomic_read(&task->task_sent) && + !atomic_read(&task->task_active)) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + transport_remove_task_from_execute_queue(task, + task->se_dev); + + DEBUG_TS("task_no[%d] - Removed from execute queue\n", + task->task_no); + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + continue; + } + + /* + * If the struct se_task is active, sleep until it is returned + * from the plugin. + */ + if (atomic_read(&task->task_active)) { + atomic_set(&task->task_stop, 1); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + + DEBUG_TS("task_no[%d] - Waiting to complete\n", + task->task_no); + wait_for_completion(&task->task_stop_comp); + DEBUG_TS("task_no[%d] - Stopped successfully\n", + task->task_no); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + atomic_dec(&T_TASK(cmd)->t_task_cdbs_left); + + atomic_set(&task->task_active, 0); + atomic_set(&task->task_stop, 0); + } else { + DEBUG_TS("task_no[%d] - Did nothing\n", task->task_no); + ret++; + } + + __transport_stop_task_timer(task, &flags); + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + return ret; +} + +static void transport_failure_reset_queue_depth(struct se_device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);; + atomic_inc(&dev->depth_left); + atomic_inc(&SE_HBA(dev)->left_queue_depth); + spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags); +} + +/* + * Handle SAM-esque emulation for generic transport request failures. + */ +static void transport_generic_request_failure( + struct se_cmd *cmd, + struct se_device *dev, + int complete, + int sc) +{ + DEBUG_GRF("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x" + " CDB: 0x%02x\n", cmd, CMD_TFO(cmd)->get_task_tag(cmd), + T_TASK(cmd)->t_task_cdb[0]); + DEBUG_GRF("-----[ i_state: %d t_state/def_t_state:" + " %d/%d transport_error_status: %d\n", + CMD_TFO(cmd)->get_cmd_state(cmd), + cmd->t_state, cmd->deferred_t_state, + cmd->transport_error_status); + DEBUG_GRF("-----[ t_task_cdbs: %d t_task_cdbs_left: %d" + " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --" + " t_transport_active: %d t_transport_stop: %d" + " t_transport_sent: %d\n", T_TASK(cmd)->t_task_cdbs, + atomic_read(&T_TASK(cmd)->t_task_cdbs_left), + atomic_read(&T_TASK(cmd)->t_task_cdbs_sent), + atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left), + atomic_read(&T_TASK(cmd)->t_transport_active), + atomic_read(&T_TASK(cmd)->t_transport_stop), + atomic_read(&T_TASK(cmd)->t_transport_sent)); + + transport_stop_all_task_timers(cmd); + + if (dev) + transport_failure_reset_queue_depth(dev); + /* + * For SAM Task Attribute emulation for failed struct se_cmd + */ + if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + transport_complete_task_attr(cmd); + + if (complete) { + transport_direct_request_timeout(cmd); + cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE; + } + + switch (cmd->transport_error_status) { + case PYX_TRANSPORT_UNKNOWN_SAM_OPCODE: + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + break; + case PYX_TRANSPORT_REQ_TOO_MANY_SECTORS: + cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY; + break; + case PYX_TRANSPORT_INVALID_CDB_FIELD: + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + break; + case PYX_TRANSPORT_INVALID_PARAMETER_LIST: + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + break; + case PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES: + if (!sc) + transport_new_cmd_failure(cmd); + /* + * Currently for PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES, + * we force this session to fall back to session + * recovery. + */ + CMD_TFO(cmd)->fall_back_to_erl0(cmd->se_sess); + CMD_TFO(cmd)->stop_session(cmd->se_sess, 0, 0); + + goto check_stop; + case PYX_TRANSPORT_LU_COMM_FAILURE: + case PYX_TRANSPORT_ILLEGAL_REQUEST: + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + break; + case PYX_TRANSPORT_UNKNOWN_MODE_PAGE: + cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; + break; + case PYX_TRANSPORT_WRITE_PROTECTED: + cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; + break; + case PYX_TRANSPORT_RESERVATION_CONFLICT: + /* + * No SENSE Data payload for this case, set SCSI Status + * and queue the response to $FABRIC_MOD. + * + * Uses linux/include/scsi/scsi.h SAM status codes defs + */ + cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; + /* + * For UA Interlock Code 11b, a RESERVATION CONFLICT will + * establish a UNIT ATTENTION with PREVIOUS RESERVATION + * CONFLICT STATUS. + * + * See spc4r17, section 7.4.6 Control Mode Page, Table 349 + */ + if (SE_SESS(cmd) && + DEV_ATTRIB(cmd->se_dev)->emulate_ua_intlck_ctrl == 2) + core_scsi3_ua_allocate(SE_SESS(cmd)->se_node_acl, + cmd->orig_fe_lun, 0x2C, + ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); + + CMD_TFO(cmd)->queue_status(cmd); + goto check_stop; + case PYX_TRANSPORT_USE_SENSE_REASON: + /* + * struct se_cmd->scsi_sense_reason already set + */ + break; + default: + printk(KERN_ERR "Unknown transport error for CDB 0x%02x: %d\n", + T_TASK(cmd)->t_task_cdb[0], + cmd->transport_error_status); + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + break; + } + + if (!sc) + transport_new_cmd_failure(cmd); + else + transport_send_check_condition_and_sense(cmd, + cmd->scsi_sense_reason, 0); +check_stop: + transport_lun_remove_cmd(cmd); + if (!(transport_cmd_check_stop_to_fabric(cmd))) + ; +} + +static void transport_direct_request_timeout(struct se_cmd *cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (!(atomic_read(&T_TASK(cmd)->t_transport_timeout))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return; + } + if (atomic_read(&T_TASK(cmd)->t_task_cdbs_timeout_left)) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return; + } + + atomic_sub(atomic_read(&T_TASK(cmd)->t_transport_timeout), + &T_TASK(cmd)->t_se_count); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); +} + +static void transport_generic_request_timeout(struct se_cmd *cmd) +{ + unsigned long flags; + + /* + * Reset T_TASK(cmd)->t_se_count to allow transport_generic_remove() + * to allow last call to free memory resources. + */ + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (atomic_read(&T_TASK(cmd)->t_transport_timeout) > 1) { + int tmp = (atomic_read(&T_TASK(cmd)->t_transport_timeout) - 1); + + atomic_sub(tmp, &T_TASK(cmd)->t_se_count); + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_generic_remove(cmd, 0, 0); +} + +static int +transport_generic_allocate_buf(struct se_cmd *cmd, u32 data_length) +{ + unsigned char *buf; + + buf = kzalloc(data_length, GFP_KERNEL); + if (!(buf)) { + printk(KERN_ERR "Unable to allocate memory for buffer\n"); + return -1; + } + + T_TASK(cmd)->t_tasks_se_num = 0; + T_TASK(cmd)->t_task_buf = buf; + + return 0; +} + +static inline u32 transport_lba_21(unsigned char *cdb) +{ + return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; +} + +static inline u32 transport_lba_32(unsigned char *cdb) +{ + return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; +} + +static inline unsigned long long transport_lba_64(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +/* + * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs + */ +static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) +{ + unsigned int __v1, __v2; + + __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15]; + __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19]; + + return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; +} + +static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&T_TASK(se_cmd)->t_state_lock, flags); + se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; + spin_unlock_irqrestore(&T_TASK(se_cmd)->t_state_lock, flags); +} + +/* + * Called from interrupt context. + */ +static void transport_task_timeout_handler(unsigned long data) +{ + struct se_task *task = (struct se_task *)data; + struct se_cmd *cmd = TASK_CMD(task); + unsigned long flags; + + DEBUG_TT("transport task timeout fired! task: %p cmd: %p\n", task, cmd); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (task->task_flags & TF_STOP) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return; + } + task->task_flags &= ~TF_RUNNING; + + /* + * Determine if transport_complete_task() has already been called. + */ + if (!(atomic_read(&task->task_active))) { + DEBUG_TT("transport task: %p cmd: %p timeout task_active" + " == 0\n", task, cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return; + } + + atomic_inc(&T_TASK(cmd)->t_se_count); + atomic_inc(&T_TASK(cmd)->t_transport_timeout); + T_TASK(cmd)->t_tasks_failed = 1; + + atomic_set(&task->task_timeout, 1); + task->task_error_status = PYX_TRANSPORT_TASK_TIMEOUT; + task->task_scsi_status = 1; + + if (atomic_read(&task->task_stop)) { + DEBUG_TT("transport task: %p cmd: %p timeout task_stop" + " == 1\n", task, cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + complete(&task->task_stop_comp); + return; + } + + if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_left))) { + DEBUG_TT("transport task: %p cmd: %p timeout non zero" + " t_task_cdbs_left\n", task, cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return; + } + DEBUG_TT("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n", + task, cmd); + + cmd->t_state = TRANSPORT_COMPLETE_FAILURE; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE); +} + +/* + * Called with T_TASK(cmd)->t_state_lock held. + */ +static void transport_start_task_timer(struct se_task *task) +{ + struct se_device *dev = task->se_dev; + int timeout; + + if (task->task_flags & TF_RUNNING) + return; + /* + * If the task_timeout is disabled, exit now. + */ + timeout = DEV_ATTRIB(dev)->task_timeout; + if (!(timeout)) + return; + + init_timer(&task->task_timer); + task->task_timer.expires = (get_jiffies_64() + timeout * HZ); + task->task_timer.data = (unsigned long) task; + task->task_timer.function = transport_task_timeout_handler; + + task->task_flags |= TF_RUNNING; + add_timer(&task->task_timer); +#if 0 + printk(KERN_INFO "Starting task timer for cmd: %p task: %p seconds:" + " %d\n", task->task_se_cmd, task, timeout); +#endif +} + +/* + * Called with spin_lock_irq(&T_TASK(cmd)->t_state_lock) held. + */ +void __transport_stop_task_timer(struct se_task *task, unsigned long *flags) +{ + struct se_cmd *cmd = TASK_CMD(task); + + if (!(task->task_flags & TF_RUNNING)) + return; + + task->task_flags |= TF_STOP; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, *flags); + + del_timer_sync(&task->task_timer); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, *flags); + task->task_flags &= ~TF_RUNNING; + task->task_flags &= ~TF_STOP; +} + +static void transport_stop_all_task_timers(struct se_cmd *cmd) +{ + struct se_task *task = NULL, *task_tmp; + unsigned long flags; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + list_for_each_entry_safe(task, task_tmp, + &T_TASK(cmd)->t_task_list, t_list) + __transport_stop_task_timer(task, &flags); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); +} + +static inline int transport_tcq_window_closed(struct se_device *dev) +{ + if (dev->dev_tcq_window_closed++ < + PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) { + msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT); + } else + msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG); + + wake_up_interruptible(&dev->dev_queue_obj->thread_wq); + return 0; +} + +/* + * Called from Fabric Module context from transport_execute_tasks() + * + * The return of this function determins if the tasks from struct se_cmd + * get added to the execution queue in transport_execute_tasks(), + * or are added to the delayed or ordered lists here. + */ +static inline int transport_execute_task_attr(struct se_cmd *cmd) +{ + if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) + return 1; + /* + * Check for the existance of HEAD_OF_QUEUE, and if true return 1 + * to allow the passed struct se_cmd list of tasks to the front of the list. + */ + if (cmd->sam_task_attr == TASK_ATTR_HOQ) { + atomic_inc(&SE_DEV(cmd)->dev_hoq_count); + smp_mb__after_atomic_inc(); + DEBUG_STA("Added HEAD_OF_QUEUE for CDB:" + " 0x%02x, se_ordered_id: %u\n", + T_TASK(cmd)->t_task_cdb[0], + cmd->se_ordered_id); + return 1; + } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) { + spin_lock(&SE_DEV(cmd)->ordered_cmd_lock); + list_add_tail(&cmd->se_ordered_list, + &SE_DEV(cmd)->ordered_cmd_list); + spin_unlock(&SE_DEV(cmd)->ordered_cmd_lock); + + atomic_inc(&SE_DEV(cmd)->dev_ordered_sync); + smp_mb__after_atomic_inc(); + + DEBUG_STA("Added ORDERED for CDB: 0x%02x to ordered" + " list, se_ordered_id: %u\n", + T_TASK(cmd)->t_task_cdb[0], + cmd->se_ordered_id); + /* + * Add ORDERED command to tail of execution queue if + * no other older commands exist that need to be + * completed first. + */ + if (!(atomic_read(&SE_DEV(cmd)->simple_cmds))) + return 1; + } else { + /* + * For SIMPLE and UNTAGGED Task Attribute commands + */ + atomic_inc(&SE_DEV(cmd)->simple_cmds); + smp_mb__after_atomic_inc(); + } + /* + * Otherwise if one or more outstanding ORDERED task attribute exist, + * add the dormant task(s) built for the passed struct se_cmd to the + * execution queue and become in Active state for this struct se_device. + */ + if (atomic_read(&SE_DEV(cmd)->dev_ordered_sync) != 0) { + /* + * Otherwise, add cmd w/ tasks to delayed cmd queue that + * will be drained upon competion of HEAD_OF_QUEUE task. + */ + spin_lock(&SE_DEV(cmd)->delayed_cmd_lock); + cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; + list_add_tail(&cmd->se_delayed_list, + &SE_DEV(cmd)->delayed_cmd_list); + spin_unlock(&SE_DEV(cmd)->delayed_cmd_lock); + + DEBUG_STA("Added CDB: 0x%02x Task Attr: 0x%02x to" + " delayed CMD list, se_ordered_id: %u\n", + T_TASK(cmd)->t_task_cdb[0], cmd->sam_task_attr, + cmd->se_ordered_id); + /* + * Return zero to let transport_execute_tasks() know + * not to add the delayed tasks to the execution list. + */ + return 0; + } + /* + * Otherwise, no ORDERED task attributes exist.. + */ + return 1; +} + +/* + * Called from fabric module context in transport_generic_new_cmd() and + * transport_generic_process_write() + */ +static int transport_execute_tasks(struct se_cmd *cmd) +{ + int add_tasks; + + if (!(cmd->se_cmd_flags & SCF_SE_DISABLE_ONLINE_CHECK)) { + if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) { + cmd->transport_error_status = + PYX_TRANSPORT_LU_COMM_FAILURE; + transport_generic_request_failure(cmd, NULL, 0, 1); + return 0; + } + } + /* + * Call transport_cmd_check_stop() to see if a fabric exception + * has occured that prevents execution. + */ + if (!(transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))) { + /* + * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE + * attribute for the tasks of the received struct se_cmd CDB + */ + add_tasks = transport_execute_task_attr(cmd); + if (add_tasks == 0) + goto execute_tasks; + /* + * This calls transport_add_tasks_from_cmd() to handle + * HEAD_OF_QUEUE ordering for SAM Task Attribute emulation + * (if enabled) in __transport_add_task_to_execute_queue() and + * transport_add_task_check_sam_attr(). + */ + transport_add_tasks_from_cmd(cmd); + } + /* + * Kick the execution queue for the cmd associated struct se_device + * storage object. + */ +execute_tasks: + __transport_execute_tasks(SE_DEV(cmd)); + return 0; +} + +/* + * Called to check struct se_device tcq depth window, and once open pull struct se_task + * from struct se_device->execute_task_list and + * + * Called from transport_processing_thread() + */ +static int __transport_execute_tasks(struct se_device *dev) +{ + int error; + struct se_cmd *cmd = NULL; + struct se_task *task; + unsigned long flags; + + /* + * Check if there is enough room in the device and HBA queue to send + * struct se_transport_task's to the selected transport. + */ +check_depth: + spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags); + if (!(atomic_read(&dev->depth_left)) || + !(atomic_read(&SE_HBA(dev)->left_queue_depth))) { + spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags); + return transport_tcq_window_closed(dev); + } + dev->dev_tcq_window_closed = 0; + + spin_lock(&dev->execute_task_lock); + task = transport_get_task_from_execute_queue(dev); + spin_unlock(&dev->execute_task_lock); + + if (!task) { + spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags); + return 0; + } + + atomic_dec(&dev->depth_left); + atomic_dec(&SE_HBA(dev)->left_queue_depth); + spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags); + + cmd = TASK_CMD(task); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + atomic_set(&task->task_active, 1); + atomic_set(&task->task_sent, 1); + atomic_inc(&T_TASK(cmd)->t_task_cdbs_sent); + + if (atomic_read(&T_TASK(cmd)->t_task_cdbs_sent) == + T_TASK(cmd)->t_task_cdbs) + atomic_set(&cmd->transport_sent, 1); + + transport_start_task_timer(task); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + /* + * The struct se_cmd->transport_emulate_cdb() function pointer is used + * to grab REPORT_LUNS CDBs before they hit the + * struct se_subsystem_api->do_task() caller below. + */ + if (cmd->transport_emulate_cdb) { + error = cmd->transport_emulate_cdb(cmd); + if (error != 0) { + cmd->transport_error_status = error; + atomic_set(&task->task_active, 0); + atomic_set(&cmd->transport_sent, 0); + transport_stop_tasks_for_cmd(cmd); + transport_generic_request_failure(cmd, dev, 0, 1); + goto check_depth; + } + /* + * Handle the successful completion for transport_emulate_cdb() + * for synchronous operation, following SCF_EMULATE_CDB_ASYNC + * Otherwise the caller is expected to complete the task with + * proper status. + */ + if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) { + cmd->scsi_status = SAM_STAT_GOOD; + task->task_scsi_status = GOOD; + transport_complete_task(task, 1); + } + } else { + /* + * Currently for all virtual TCM plugins including IBLOCK, FILEIO and + * RAMDISK we use the internal transport_emulate_control_cdb() logic + * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK + * LUN emulation code. + * + * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we + * call ->do_task() directly and let the underlying TCM subsystem plugin + * code handle the CDB emulation. + */ + if ((TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) && + (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) + error = transport_emulate_control_cdb(task); + else + error = TRANSPORT(dev)->do_task(task); + + if (error != 0) { + cmd->transport_error_status = error; + atomic_set(&task->task_active, 0); + atomic_set(&cmd->transport_sent, 0); + transport_stop_tasks_for_cmd(cmd); + transport_generic_request_failure(cmd, dev, 0, 1); + } + } + + goto check_depth; + + return 0; +} + +void transport_new_cmd_failure(struct se_cmd *se_cmd) +{ + unsigned long flags; + /* + * Any unsolicited data will get dumped for failed command inside of + * the fabric plugin + */ + spin_lock_irqsave(&T_TASK(se_cmd)->t_state_lock, flags); + se_cmd->se_cmd_flags |= SCF_SE_CMD_FAILED; + se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + spin_unlock_irqrestore(&T_TASK(se_cmd)->t_state_lock, flags); + + CMD_TFO(se_cmd)->new_cmd_failure(se_cmd); +} + +static void transport_nop_wait_for_tasks(struct se_cmd *, int, int); + +static inline u32 transport_get_sectors_6( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = SE_LUN(cmd)->lun_se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 8-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * Use 24-bit allocation length for TYPE_TAPE. + */ + if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) + return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4]; + + /* + * Everything else assume TYPE_DISK Sector CDB location. + * Use 8-bit sector value. + */ +type_disk: + return (u32)cdb[4]; +} + +static inline u32 transport_get_sectors_10( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = SE_LUN(cmd)->lun_se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 16-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * XXX_10 is not defined in SSC, throw an exception + */ + if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) { + *ret = -1; + return 0; + } + + /* + * Everything else assume TYPE_DISK Sector CDB location. + * Use 16-bit sector value. + */ +type_disk: + return (u32)(cdb[7] << 8) + cdb[8]; +} + +static inline u32 transport_get_sectors_12( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = SE_LUN(cmd)->lun_se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 32-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * XXX_12 is not defined in SSC, throw an exception + */ + if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) { + *ret = -1; + return 0; + } + + /* + * Everything else assume TYPE_DISK Sector CDB location. + * Use 32-bit sector value. + */ +type_disk: + return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; +} + +static inline u32 transport_get_sectors_16( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + struct se_device *dev = SE_LUN(cmd)->lun_se_dev; + + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 32-bit sector value. + */ + if (!dev) + goto type_disk; + + /* + * Use 24-bit allocation length for TYPE_TAPE. + */ + if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) + return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14]; + +type_disk: + return (u32)(cdb[10] << 24) + (cdb[11] << 16) + + (cdb[12] << 8) + cdb[13]; +} + +/* + * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants + */ +static inline u32 transport_get_sectors_32( + unsigned char *cdb, + struct se_cmd *cmd, + int *ret) +{ + /* + * Assume TYPE_DISK for non struct se_device objects. + * Use 32-bit sector value. + */ + return (u32)(cdb[28] << 24) + (cdb[29] << 16) + + (cdb[30] << 8) + cdb[31]; + +} + +static inline u32 transport_get_size( + u32 sectors, + unsigned char *cdb, + struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + + if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) { + if (cdb[1] & 1) { /* sectors */ + return DEV_ATTRIB(dev)->block_size * sectors; + } else /* bytes */ + return sectors; + } +#if 0 + printk(KERN_INFO "Returning block_size: %u, sectors: %u == %u for" + " %s object\n", DEV_ATTRIB(dev)->block_size, sectors, + DEV_ATTRIB(dev)->block_size * sectors, + TRANSPORT(dev)->name); +#endif + return DEV_ATTRIB(dev)->block_size * sectors; +} + +unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]) +{ + unsigned char result = 0; + /* + * MSB + */ + if ((val[0] >= 'a') && (val[0] <= 'f')) + result = ((val[0] - 'a' + 10) & 0xf) << 4; + else + if ((val[0] >= 'A') && (val[0] <= 'F')) + result = ((val[0] - 'A' + 10) & 0xf) << 4; + else /* digit */ + result = ((val[0] - '0') & 0xf) << 4; + /* + * LSB + */ + if ((val[1] >= 'a') && (val[1] <= 'f')) + result |= ((val[1] - 'a' + 10) & 0xf); + else + if ((val[1] >= 'A') && (val[1] <= 'F')) + result |= ((val[1] - 'A' + 10) & 0xf); + else /* digit */ + result |= ((val[1] - '0') & 0xf); + + return result; +} +EXPORT_SYMBOL(transport_asciihex_to_binaryhex); + +static void transport_xor_callback(struct se_cmd *cmd) +{ + unsigned char *buf, *addr; + struct se_mem *se_mem; + unsigned int offset; + int i; + /* + * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command + * + * 1) read the specified logical block(s); + * 2) transfer logical blocks from the data-out buffer; + * 3) XOR the logical blocks transferred from the data-out buffer with + * the logical blocks read, storing the resulting XOR data in a buffer; + * 4) if the DISABLE WRITE bit is set to zero, then write the logical + * blocks transferred from the data-out buffer; and + * 5) transfer the resulting XOR data to the data-in buffer. + */ + buf = kmalloc(cmd->data_length, GFP_KERNEL); + if (!(buf)) { + printk(KERN_ERR "Unable to allocate xor_callback buf\n"); + return; + } + /* + * Copy the scatterlist WRITE buffer located at T_TASK(cmd)->t_mem_list + * into the locally allocated *buf + */ + transport_memcpy_se_mem_read_contig(cmd, buf, T_TASK(cmd)->t_mem_list); + /* + * Now perform the XOR against the BIDI read memory located at + * T_TASK(cmd)->t_mem_bidi_list + */ + + offset = 0; + list_for_each_entry(se_mem, T_TASK(cmd)->t_mem_bidi_list, se_list) { + addr = (unsigned char *)kmap_atomic(se_mem->se_page, KM_USER0); + if (!(addr)) + goto out; + + for (i = 0; i < se_mem->se_len; i++) + *(addr + se_mem->se_off + i) ^= *(buf + offset + i); + + offset += se_mem->se_len; + kunmap_atomic(addr, KM_USER0); + } +out: + kfree(buf); +} + +/* + * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd + */ +static int transport_get_sense_data(struct se_cmd *cmd) +{ + unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL; + struct se_device *dev; + struct se_task *task = NULL, *task_tmp; + unsigned long flags; + u32 offset = 0; + + if (!SE_LUN(cmd)) { + printk(KERN_ERR "SE_LUN(cmd) is NULL\n"); + return -1; + } + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return 0; + } + + list_for_each_entry_safe(task, task_tmp, + &T_TASK(cmd)->t_task_list, t_list) { + + if (!task->task_sense) + continue; + + dev = task->se_dev; + if (!(dev)) + continue; + + if (!TRANSPORT(dev)->get_sense_buffer) { + printk(KERN_ERR "TRANSPORT(dev)->get_sense_buffer" + " is NULL\n"); + continue; + } + + sense_buffer = TRANSPORT(dev)->get_sense_buffer(task); + if (!(sense_buffer)) { + printk(KERN_ERR "ITT[0x%08x]_TASK[%d]: Unable to locate" + " sense buffer for task with sense\n", + CMD_TFO(cmd)->get_task_tag(cmd), task->task_no); + continue; + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + offset = CMD_TFO(cmd)->set_fabric_sense_len(cmd, + TRANSPORT_SENSE_BUFFER); + + memcpy((void *)&buffer[offset], (void *)sense_buffer, + TRANSPORT_SENSE_BUFFER); + cmd->scsi_status = task->task_scsi_status; + /* Automatically padded */ + cmd->scsi_sense_length = + (TRANSPORT_SENSE_BUFFER + offset); + + printk(KERN_INFO "HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x" + " and sense\n", + dev->se_hba->hba_id, TRANSPORT(dev)->name, + cmd->scsi_status); + return 0; + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + return -1; +} + +static int transport_allocate_resources(struct se_cmd *cmd) +{ + u32 length = cmd->data_length; + + if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) || + (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) + return transport_generic_get_mem(cmd, length, PAGE_SIZE); + else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) + return transport_generic_allocate_buf(cmd, length); + else + return 0; +} + +static int +transport_handle_reservation_conflict(struct se_cmd *cmd) +{ + cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; + cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; + /* + * For UA Interlock Code 11b, a RESERVATION CONFLICT will + * establish a UNIT ATTENTION with PREVIOUS RESERVATION + * CONFLICT STATUS. + * + * See spc4r17, section 7.4.6 Control Mode Page, Table 349 + */ + if (SE_SESS(cmd) && + DEV_ATTRIB(cmd->se_dev)->emulate_ua_intlck_ctrl == 2) + core_scsi3_ua_allocate(SE_SESS(cmd)->se_node_acl, + cmd->orig_fe_lun, 0x2C, + ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); + return -2; +} + +/* transport_generic_cmd_sequencer(): + * + * Generic Command Sequencer that should work for most DAS transport + * drivers. + * + * Called from transport_generic_allocate_tasks() in the $FABRIC_MOD + * RX Thread. + * + * FIXME: Need to support other SCSI OPCODES where as well. + */ +static int transport_generic_cmd_sequencer( + struct se_cmd *cmd, + unsigned char *cdb) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_subsystem_dev *su_dev = dev->se_sub_dev; + int ret = 0, sector_ret = 0, passthrough; + u32 sectors = 0, size = 0, pr_reg_type = 0; + u16 service_action; + u8 alua_ascq = 0; + /* + * Check for an existing UNIT ATTENTION condition + */ + if (core_scsi3_ua_check(cmd, cdb) < 0) { + cmd->transport_wait_for_tasks = + &transport_nop_wait_for_tasks; + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION; + return -2; + } + /* + * Check status of Asymmetric Logical Unit Assignment port + */ + ret = T10_ALUA(su_dev)->alua_state_check(cmd, cdb, &alua_ascq); + if (ret != 0) { + cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; + /* + * Set SCSI additional sense code (ASC) to 'LUN Not Accessable'; + * The ALUA additional sense code qualifier (ASCQ) is determined + * by the ALUA primary or secondary access state.. + */ + if (ret > 0) { +#if 0 + printk(KERN_INFO "[%s]: ALUA TG Port not available," + " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n", + CMD_TFO(cmd)->get_fabric_name(), alua_ascq); +#endif + transport_set_sense_codes(cmd, 0x04, alua_ascq); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; + return -2; + } + goto out_invalid_cdb_field; + } + /* + * Check status for SPC-3 Persistent Reservations + */ + if (T10_PR_OPS(su_dev)->t10_reservation_check(cmd, &pr_reg_type) != 0) { + if (T10_PR_OPS(su_dev)->t10_seq_non_holder( + cmd, cdb, pr_reg_type) != 0) + return transport_handle_reservation_conflict(cmd); + /* + * This means the CDB is allowed for the SCSI Initiator port + * when said port is *NOT* holding the legacy SPC-2 or + * SPC-3 Persistent Reservation. + */ + } + + switch (cdb[0]) { + case READ_6: + sectors = transport_get_sectors_6(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_6; + T_TASK(cmd)->t_task_lba = transport_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case READ_10: + sectors = transport_get_sectors_10(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_10; + T_TASK(cmd)->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case READ_12: + sectors = transport_get_sectors_12(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_12; + T_TASK(cmd)->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case READ_16: + sectors = transport_get_sectors_16(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_16; + T_TASK(cmd)->t_task_lba = transport_lba_64(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case WRITE_6: + sectors = transport_get_sectors_6(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_6; + T_TASK(cmd)->t_task_lba = transport_lba_21(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case WRITE_10: + sectors = transport_get_sectors_10(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_10; + T_TASK(cmd)->t_task_lba = transport_lba_32(cdb); + T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case WRITE_12: + sectors = transport_get_sectors_12(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_12; + T_TASK(cmd)->t_task_lba = transport_lba_32(cdb); + T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case WRITE_16: + sectors = transport_get_sectors_16(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_16; + T_TASK(cmd)->t_task_lba = transport_lba_64(cdb); + T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + break; + case XDWRITEREAD_10: + if ((cmd->data_direction != DMA_TO_DEVICE) || + !(T_TASK(cmd)->t_tasks_bidi)) + goto out_invalid_cdb_field; + sectors = transport_get_sectors_10(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + cmd->transport_split_cdb = &split_cdb_XX_10; + T_TASK(cmd)->t_task_lba = transport_lba_32(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + passthrough = (TRANSPORT(dev)->transport_type == + TRANSPORT_PLUGIN_PHBA_PDEV); + /* + * Skip the remaining assignments for TCM/PSCSI passthrough + */ + if (passthrough) + break; + /* + * Setup BIDI XOR callback to be run during transport_generic_complete_ok() + */ + cmd->transport_complete_callback = &transport_xor_callback; + T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8); + break; + case VARIABLE_LENGTH_CMD: + service_action = get_unaligned_be16(&cdb[8]); + /* + * Determine if this is TCM/PSCSI device and we should disable + * internal emulation for this CDB. + */ + passthrough = (TRANSPORT(dev)->transport_type == + TRANSPORT_PLUGIN_PHBA_PDEV); + + switch (service_action) { + case XDWRITEREAD_32: + sectors = transport_get_sectors_32(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + /* + * Use WRITE_32 and READ_32 opcodes for the emulated + * XDWRITE_READ_32 logic. + */ + cmd->transport_split_cdb = &split_cdb_XX_32; + T_TASK(cmd)->t_task_lba = transport_lba_64_ext(cdb); + cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; + + /* + * Skip the remaining assignments for TCM/PSCSI passthrough + */ + if (passthrough) + break; + + /* + * Setup BIDI XOR callback to be run during + * transport_generic_complete_ok() + */ + cmd->transport_complete_callback = &transport_xor_callback; + T_TASK(cmd)->t_tasks_fua = (cdb[10] & 0x8); + break; + case WRITE_SAME_32: + sectors = transport_get_sectors_32(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + T_TASK(cmd)->t_task_lba = get_unaligned_be64(&cdb[12]); + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + + /* + * Skip the remaining assignments for TCM/PSCSI passthrough + */ + if (passthrough) + break; + + if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) { + printk(KERN_ERR "WRITE_SAME PBDATA and LBDATA" + " bits not supported for Block Discard" + " Emulation\n"); + goto out_invalid_cdb_field; + } + /* + * Currently for the emulated case we only accept + * tpws with the UNMAP=1 bit set. + */ + if (!(cdb[10] & 0x08)) { + printk(KERN_ERR "WRITE_SAME w/o UNMAP bit not" + " supported for Block Discard Emulation\n"); + goto out_invalid_cdb_field; + } + break; + default: + printk(KERN_ERR "VARIABLE_LENGTH_CMD service action" + " 0x%04x not supported\n", service_action); + goto out_unsupported_cdb; + } + break; + case 0xa3: + if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) { + /* MAINTENANCE_IN from SCC-2 */ + /* + * Check for emulated MI_REPORT_TARGET_PGS. + */ + if (cdb[1] == MI_REPORT_TARGET_PGS) { + cmd->transport_emulate_cdb = + (T10_ALUA(su_dev)->alua_type == + SPC3_ALUA_EMULATED) ? + &core_emulate_report_target_port_groups : + NULL; + } + size = (cdb[6] << 24) | (cdb[7] << 16) | + (cdb[8] << 8) | cdb[9]; + } else { + /* GPCMD_SEND_KEY from multi media commands */ + size = (cdb[8] << 8) + cdb[9]; + } + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case MODE_SELECT: + size = cdb[4]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; + case MODE_SELECT_10: + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; + case MODE_SENSE: + size = cdb[4]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case MODE_SENSE_10: + case GPCMD_READ_BUFFER_CAPACITY: + case GPCMD_SEND_OPC: + case LOG_SELECT: + case LOG_SENSE: + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case READ_BLOCK_LIMITS: + size = READ_BLOCK_LEN; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case GPCMD_GET_CONFIGURATION: + case GPCMD_READ_FORMAT_CAPACITIES: + case GPCMD_READ_DISC_INFO: + case GPCMD_READ_TRACK_RZONE_INFO: + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; + case PERSISTENT_RESERVE_IN: + case PERSISTENT_RESERVE_OUT: + cmd->transport_emulate_cdb = + (T10_RES(su_dev)->res_type == + SPC3_PERSISTENT_RESERVATIONS) ? + &core_scsi3_emulate_pr : NULL; + size = (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case GPCMD_MECHANISM_STATUS: + case GPCMD_READ_DVD_STRUCTURE: + size = (cdb[8] << 8) + cdb[9]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; + case READ_POSITION: + size = READ_POSITION_LEN; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case 0xa4: + if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) { + /* MAINTENANCE_OUT from SCC-2 + * + * Check for emulated MO_SET_TARGET_PGS. + */ + if (cdb[1] == MO_SET_TARGET_PGS) { + cmd->transport_emulate_cdb = + (T10_ALUA(su_dev)->alua_type == + SPC3_ALUA_EMULATED) ? + &core_emulate_set_target_port_groups : + NULL; + } + + size = (cdb[6] << 24) | (cdb[7] << 16) | + (cdb[8] << 8) | cdb[9]; + } else { + /* GPCMD_REPORT_KEY from multi media commands */ + size = (cdb[8] << 8) + cdb[9]; + } + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case INQUIRY: + size = (cdb[3] << 8) + cdb[4]; + /* + * Do implict HEAD_OF_QUEUE processing for INQUIRY. + * See spc4r17 section 5.3 + */ + if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + cmd->sam_task_attr = TASK_ATTR_HOQ; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case READ_BUFFER: + size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case READ_CAPACITY: + size = READ_CAP_LEN; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case READ_MEDIA_SERIAL_NUMBER: + case SECURITY_PROTOCOL_IN: + case SECURITY_PROTOCOL_OUT: + size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case SERVICE_ACTION_IN: + case ACCESS_CONTROL_IN: + case ACCESS_CONTROL_OUT: + case EXTENDED_COPY: + case READ_ATTRIBUTE: + case RECEIVE_COPY_RESULTS: + case WRITE_ATTRIBUTE: + size = (cdb[10] << 24) | (cdb[11] << 16) | + (cdb[12] << 8) | cdb[13]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: + size = (cdb[3] << 8) | cdb[4]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; +/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */ +#if 0 + case GPCMD_READ_CD: + sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + size = (2336 * sectors); + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; +#endif + case READ_TOC: + size = cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case REQUEST_SENSE: + size = cdb[4]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case READ_ELEMENT_STATUS: + size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case WRITE_BUFFER: + size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case RESERVE: + case RESERVE_10: + /* + * The SPC-2 RESERVE does not contain a size in the SCSI CDB. + * Assume the passthrough or $FABRIC_MOD will tell us about it. + */ + if (cdb[0] == RESERVE_10) + size = (cdb[7] << 8) | cdb[8]; + else + size = cmd->data_length; + + /* + * Setup the legacy emulated handler for SPC-2 and + * >= SPC-3 compatible reservation handling (CRH=1) + * Otherwise, we assume the underlying SCSI logic is + * is running in SPC_PASSTHROUGH, and wants reservations + * emulation disabled. + */ + cmd->transport_emulate_cdb = + (T10_RES(su_dev)->res_type != + SPC_PASSTHROUGH) ? + &core_scsi2_emulate_crh : NULL; + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + break; + case RELEASE: + case RELEASE_10: + /* + * The SPC-2 RELEASE does not contain a size in the SCSI CDB. + * Assume the passthrough or $FABRIC_MOD will tell us about it. + */ + if (cdb[0] == RELEASE_10) + size = (cdb[7] << 8) | cdb[8]; + else + size = cmd->data_length; + + cmd->transport_emulate_cdb = + (T10_RES(su_dev)->res_type != + SPC_PASSTHROUGH) ? + &core_scsi2_emulate_crh : NULL; + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + break; + case SYNCHRONIZE_CACHE: + case 0x91: /* SYNCHRONIZE_CACHE_16: */ + /* + * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE + */ + if (cdb[0] == SYNCHRONIZE_CACHE) { + sectors = transport_get_sectors_10(cdb, cmd, §or_ret); + T_TASK(cmd)->t_task_lba = transport_lba_32(cdb); + } else { + sectors = transport_get_sectors_16(cdb, cmd, §or_ret); + T_TASK(cmd)->t_task_lba = transport_lba_64(cdb); + } + if (sector_ret) + goto out_unsupported_cdb; + + size = transport_get_size(sectors, cdb, cmd); + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + + /* + * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb() + */ + if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + break; + /* + * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation + * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks() + */ + cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC; + /* + * Check to ensure that LBA + Range does not exceed past end of + * device. + */ + if (transport_get_sectors(cmd) < 0) + goto out_invalid_cdb_field; + break; + case UNMAP: + size = get_unaligned_be16(&cdb[7]); + passthrough = (TRANSPORT(dev)->transport_type == + TRANSPORT_PLUGIN_PHBA_PDEV); + /* + * Determine if the received UNMAP used to for direct passthrough + * into Linux/SCSI with struct request via TCM/pSCSI or we are + * signaling the use of internal transport_generic_unmap() emulation + * for UNMAP -> Linux/BLOCK disbard with TCM/IBLOCK and TCM/FILEIO + * subsystem plugin backstores. + */ + if (!(passthrough)) + cmd->se_cmd_flags |= SCF_EMULATE_SYNC_UNMAP; + + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + case WRITE_SAME_16: + sectors = transport_get_sectors_16(cdb, cmd, §or_ret); + if (sector_ret) + goto out_unsupported_cdb; + size = transport_get_size(sectors, cdb, cmd); + T_TASK(cmd)->t_task_lba = get_unaligned_be16(&cdb[2]); + passthrough = (TRANSPORT(dev)->transport_type == + TRANSPORT_PLUGIN_PHBA_PDEV); + /* + * Determine if the received WRITE_SAME_16 is used to for direct + * passthrough into Linux/SCSI with struct request via TCM/pSCSI + * or we are signaling the use of internal WRITE_SAME + UNMAP=1 + * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and + * TCM/FILEIO subsystem plugin backstores. + */ + if (!(passthrough)) { + if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) { + printk(KERN_ERR "WRITE_SAME PBDATA and LBDATA" + " bits not supported for Block Discard" + " Emulation\n"); + goto out_invalid_cdb_field; + } + /* + * Currently for the emulated case we only accept + * tpws with the UNMAP=1 bit set. + */ + if (!(cdb[1] & 0x08)) { + printk(KERN_ERR "WRITE_SAME w/o UNMAP bit not " + " supported for Block Discard Emulation\n"); + goto out_invalid_cdb_field; + } + } + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; + case ALLOW_MEDIUM_REMOVAL: + case GPCMD_CLOSE_TRACK: + case ERASE: + case INITIALIZE_ELEMENT_STATUS: + case GPCMD_LOAD_UNLOAD: + case REZERO_UNIT: + case SEEK_10: + case GPCMD_SET_SPEED: + case SPACE: + case START_STOP: + case TEST_UNIT_READY: + case VERIFY: + case WRITE_FILEMARKS: + case MOVE_MEDIUM: + cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; + break; + case REPORT_LUNS: + cmd->transport_emulate_cdb = + &transport_core_report_lun_response; + size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + /* + * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS + * See spc4r17 section 5.3 + */ + if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + cmd->sam_task_attr = TASK_ATTR_HOQ; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB; + break; + default: + printk(KERN_WARNING "TARGET_CORE[%s]: Unsupported SCSI Opcode" + " 0x%02x, sending CHECK_CONDITION.\n", + CMD_TFO(cmd)->get_fabric_name(), cdb[0]); + cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; + goto out_unsupported_cdb; + } + + if (size != cmd->data_length) { + printk(KERN_WARNING "TARGET_CORE[%s]: Expected Transfer Length:" + " %u does not match SCSI CDB Length: %u for SAM Opcode:" + " 0x%02x\n", CMD_TFO(cmd)->get_fabric_name(), + cmd->data_length, size, cdb[0]); + + cmd->cmd_spdtl = size; + + if (cmd->data_direction == DMA_TO_DEVICE) { + printk(KERN_ERR "Rejecting underflow/overflow" + " WRITE data\n"); + goto out_invalid_cdb_field; + } + /* + * Reject READ_* or WRITE_* with overflow/underflow for + * type SCF_SCSI_DATA_SG_IO_CDB. + */ + if (!(ret) && (DEV_ATTRIB(dev)->block_size != 512)) { + printk(KERN_ERR "Failing OVERFLOW/UNDERFLOW for LBA op" + " CDB on non 512-byte sector setup subsystem" + " plugin: %s\n", TRANSPORT(dev)->name); + /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ + goto out_invalid_cdb_field; + } + + if (size > cmd->data_length) { + cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; + cmd->residual_count = (size - cmd->data_length); + } else { + cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; + cmd->residual_count = (cmd->data_length - size); + } + cmd->data_length = size; + } + + transport_set_supported_SAM_opcode(cmd); + return ret; + +out_unsupported_cdb: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -2; +out_invalid_cdb_field: + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -2; +} + +static inline void transport_release_tasks(struct se_cmd *); + +/* + * This function will copy a contiguous *src buffer into a destination + * struct scatterlist array. + */ +static void transport_memcpy_write_contig( + struct se_cmd *cmd, + struct scatterlist *sg_d, + unsigned char *src) +{ + u32 i = 0, length = 0, total_length = cmd->data_length; + void *dst; + + while (total_length) { + length = sg_d[i].length; + + if (length > total_length) + length = total_length; + + dst = sg_virt(&sg_d[i]); + + memcpy(dst, src, length); + + if (!(total_length -= length)) + return; + + src += length; + i++; + } +} + +/* + * This function will copy a struct scatterlist array *sg_s into a destination + * contiguous *dst buffer. + */ +static void transport_memcpy_read_contig( + struct se_cmd *cmd, + unsigned char *dst, + struct scatterlist *sg_s) +{ + u32 i = 0, length = 0, total_length = cmd->data_length; + void *src; + + while (total_length) { + length = sg_s[i].length; + + if (length > total_length) + length = total_length; + + src = sg_virt(&sg_s[i]); + + memcpy(dst, src, length); + + if (!(total_length -= length)) + return; + + dst += length; + i++; + } +} + +static void transport_memcpy_se_mem_read_contig( + struct se_cmd *cmd, + unsigned char *dst, + struct list_head *se_mem_list) +{ + struct se_mem *se_mem; + void *src; + u32 length = 0, total_length = cmd->data_length; + + list_for_each_entry(se_mem, se_mem_list, se_list) { + length = se_mem->se_len; + + if (length > total_length) + length = total_length; + + src = page_address(se_mem->se_page) + se_mem->se_off; + + memcpy(dst, src, length); + + if (!(total_length -= length)) + return; + + dst += length; + } +} + +/* + * Called from transport_generic_complete_ok() and + * transport_generic_request_failure() to determine which dormant/delayed + * and ordered cmds need to have their tasks added to the execution queue. + */ +static void transport_complete_task_attr(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_cmd *cmd_p, *cmd_tmp; + int new_active_tasks = 0; + + if (cmd->sam_task_attr == TASK_ATTR_SIMPLE) { + atomic_dec(&dev->simple_cmds); + smp_mb__after_atomic_dec(); + dev->dev_cur_ordered_id++; + DEBUG_STA("Incremented dev->dev_cur_ordered_id: %u for" + " SIMPLE: %u\n", dev->dev_cur_ordered_id, + cmd->se_ordered_id); + } else if (cmd->sam_task_attr == TASK_ATTR_HOQ) { + atomic_dec(&dev->dev_hoq_count); + smp_mb__after_atomic_dec(); + dev->dev_cur_ordered_id++; + DEBUG_STA("Incremented dev_cur_ordered_id: %u for" + " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id, + cmd->se_ordered_id); + } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) { + spin_lock(&dev->ordered_cmd_lock); + list_del(&cmd->se_ordered_list); + atomic_dec(&dev->dev_ordered_sync); + smp_mb__after_atomic_dec(); + spin_unlock(&dev->ordered_cmd_lock); + + dev->dev_cur_ordered_id++; + DEBUG_STA("Incremented dev_cur_ordered_id: %u for ORDERED:" + " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id); + } + /* + * Process all commands up to the last received + * ORDERED task attribute which requires another blocking + * boundary + */ + spin_lock(&dev->delayed_cmd_lock); + list_for_each_entry_safe(cmd_p, cmd_tmp, + &dev->delayed_cmd_list, se_delayed_list) { + + list_del(&cmd_p->se_delayed_list); + spin_unlock(&dev->delayed_cmd_lock); + + DEBUG_STA("Calling add_tasks() for" + " cmd_p: 0x%02x Task Attr: 0x%02x" + " Dormant -> Active, se_ordered_id: %u\n", + T_TASK(cmd_p)->t_task_cdb[0], + cmd_p->sam_task_attr, cmd_p->se_ordered_id); + + transport_add_tasks_from_cmd(cmd_p); + new_active_tasks++; + + spin_lock(&dev->delayed_cmd_lock); + if (cmd_p->sam_task_attr == TASK_ATTR_ORDERED) + break; + } + spin_unlock(&dev->delayed_cmd_lock); + /* + * If new tasks have become active, wake up the transport thread + * to do the processing of the Active tasks. + */ + if (new_active_tasks != 0) + wake_up_interruptible(&dev->dev_queue_obj->thread_wq); +} + +static void transport_generic_complete_ok(struct se_cmd *cmd) +{ + int reason = 0; + /* + * Check if we need to move delayed/dormant tasks from cmds on the + * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task + * Attribute. + */ + if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) + transport_complete_task_attr(cmd); + /* + * Check if we need to retrieve a sense buffer from + * the struct se_cmd in question. + */ + if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { + if (transport_get_sense_data(cmd) < 0) + reason = TCM_NON_EXISTENT_LUN; + + /* + * Only set when an struct se_task->task_scsi_status returned + * a non GOOD status. + */ + if (cmd->scsi_status) { + transport_send_check_condition_and_sense( + cmd, reason, 1); + transport_lun_remove_cmd(cmd); + transport_cmd_check_stop_to_fabric(cmd); + return; + } + } + /* + * Check for a callback, used by amoungst other things + * XDWRITE_READ_10 emulation. + */ + if (cmd->transport_complete_callback) + cmd->transport_complete_callback(cmd); + + switch (cmd->data_direction) { + case DMA_FROM_DEVICE: + spin_lock(&cmd->se_lun->lun_sep_lock); + if (SE_LUN(cmd)->lun_sep) { + SE_LUN(cmd)->lun_sep->sep_stats.tx_data_octets += + cmd->data_length; + } + spin_unlock(&cmd->se_lun->lun_sep_lock); + /* + * If enabled by TCM fabirc module pre-registered SGL + * memory, perform the memcpy() from the TCM internal + * contigious buffer back to the original SGL. + */ + if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG) + transport_memcpy_write_contig(cmd, + T_TASK(cmd)->t_task_pt_sgl, + T_TASK(cmd)->t_task_buf); + + CMD_TFO(cmd)->queue_data_in(cmd); + break; + case DMA_TO_DEVICE: + spin_lock(&cmd->se_lun->lun_sep_lock); + if (SE_LUN(cmd)->lun_sep) { + SE_LUN(cmd)->lun_sep->sep_stats.rx_data_octets += + cmd->data_length; + } + spin_unlock(&cmd->se_lun->lun_sep_lock); + /* + * Check if we need to send READ payload for BIDI-COMMAND + */ + if (T_TASK(cmd)->t_mem_bidi_list != NULL) { + spin_lock(&cmd->se_lun->lun_sep_lock); + if (SE_LUN(cmd)->lun_sep) { + SE_LUN(cmd)->lun_sep->sep_stats.tx_data_octets += + cmd->data_length; + } + spin_unlock(&cmd->se_lun->lun_sep_lock); + CMD_TFO(cmd)->queue_data_in(cmd); + break; + } + /* Fall through for DMA_TO_DEVICE */ + case DMA_NONE: + CMD_TFO(cmd)->queue_status(cmd); + break; + default: + break; + } + + transport_lun_remove_cmd(cmd); + transport_cmd_check_stop_to_fabric(cmd); +} + +static void transport_free_dev_tasks(struct se_cmd *cmd) +{ + struct se_task *task, *task_tmp; + unsigned long flags; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + list_for_each_entry_safe(task, task_tmp, + &T_TASK(cmd)->t_task_list, t_list) { + if (atomic_read(&task->task_active)) + continue; + + kfree(task->task_sg_bidi); + kfree(task->task_sg); + + list_del(&task->t_list); + + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + if (task->se_dev) + TRANSPORT(task->se_dev)->free_task(task); + else + printk(KERN_ERR "task[%u] - task->se_dev is NULL\n", + task->task_no); + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); +} + +static inline void transport_free_pages(struct se_cmd *cmd) +{ + struct se_mem *se_mem, *se_mem_tmp; + int free_page = 1; + + if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) + free_page = 0; + if (cmd->se_dev->transport->do_se_mem_map) + free_page = 0; + + if (T_TASK(cmd)->t_task_buf) { + kfree(T_TASK(cmd)->t_task_buf); + T_TASK(cmd)->t_task_buf = NULL; + return; + } + + /* + * Caller will handle releasing of struct se_mem. + */ + if (cmd->se_cmd_flags & SCF_CMD_PASSTHROUGH_NOALLOC) + return; + + if (!(T_TASK(cmd)->t_tasks_se_num)) + return; + + list_for_each_entry_safe(se_mem, se_mem_tmp, + T_TASK(cmd)->t_mem_list, se_list) { + /* + * We only release call __free_page(struct se_mem->se_page) when + * SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is NOT in use, + */ + if (free_page) + __free_page(se_mem->se_page); + + list_del(&se_mem->se_list); + kmem_cache_free(se_mem_cache, se_mem); + } + + if (T_TASK(cmd)->t_mem_bidi_list && T_TASK(cmd)->t_tasks_se_bidi_num) { + list_for_each_entry_safe(se_mem, se_mem_tmp, + T_TASK(cmd)->t_mem_bidi_list, se_list) { + /* + * We only release call __free_page(struct se_mem->se_page) when + * SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is NOT in use, + */ + if (free_page) + __free_page(se_mem->se_page); + + list_del(&se_mem->se_list); + kmem_cache_free(se_mem_cache, se_mem); + } + } + + kfree(T_TASK(cmd)->t_mem_bidi_list); + T_TASK(cmd)->t_mem_bidi_list = NULL; + kfree(T_TASK(cmd)->t_mem_list); + T_TASK(cmd)->t_mem_list = NULL; + T_TASK(cmd)->t_tasks_se_num = 0; +} + +static inline void transport_release_tasks(struct se_cmd *cmd) +{ + transport_free_dev_tasks(cmd); +} + +static inline int transport_dec_and_check(struct se_cmd *cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (atomic_read(&T_TASK(cmd)->t_fe_count)) { + if (!(atomic_dec_and_test(&T_TASK(cmd)->t_fe_count))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + return 1; + } + } + + if (atomic_read(&T_TASK(cmd)->t_se_count)) { + if (!(atomic_dec_and_test(&T_TASK(cmd)->t_se_count))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + return 1; + } + } + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + return 0; +} + +static void transport_release_fe_cmd(struct se_cmd *cmd) +{ + unsigned long flags; + + if (transport_dec_and_check(cmd)) + return; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + goto free_pages; + } + atomic_set(&T_TASK(cmd)->transport_dev_active, 0); + transport_all_task_dev_remove_state(cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_release_tasks(cmd); +free_pages: + transport_free_pages(cmd); + transport_free_se_cmd(cmd); + CMD_TFO(cmd)->release_cmd_direct(cmd); +} + +static int transport_generic_remove( + struct se_cmd *cmd, + int release_to_pool, + int session_reinstatement) +{ + unsigned long flags; + + if (!(T_TASK(cmd))) + goto release_cmd; + + if (transport_dec_and_check(cmd)) { + if (session_reinstatement) { + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + transport_all_task_dev_remove_state(cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + flags); + } + return 1; + } + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + goto free_pages; + } + atomic_set(&T_TASK(cmd)->transport_dev_active, 0); + transport_all_task_dev_remove_state(cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + transport_release_tasks(cmd); +free_pages: + transport_free_pages(cmd); + +release_cmd: + if (release_to_pool) { + transport_release_cmd_to_pool(cmd); + } else { + transport_free_se_cmd(cmd); + CMD_TFO(cmd)->release_cmd_direct(cmd); + } + + return 0; +} + +/* + * transport_generic_map_mem_to_cmd - Perform SGL -> struct se_mem map + * @cmd: Associated se_cmd descriptor + * @mem: SGL style memory for TCM WRITE / READ + * @sg_mem_num: Number of SGL elements + * @mem_bidi_in: SGL style memory for TCM BIDI READ + * @sg_mem_bidi_num: Number of BIDI READ SGL elements + * + * Return: nonzero return cmd was rejected for -ENOMEM or inproper usage + * of parameters. + */ +int transport_generic_map_mem_to_cmd( + struct se_cmd *cmd, + struct scatterlist *mem, + u32 sg_mem_num, + struct scatterlist *mem_bidi_in, + u32 sg_mem_bidi_num) +{ + u32 se_mem_cnt_out = 0; + int ret; + + if (!(mem) || !(sg_mem_num)) + return 0; + /* + * Passed *mem will contain a list_head containing preformatted + * struct se_mem elements... + */ + if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM)) { + if ((mem_bidi_in) || (sg_mem_bidi_num)) { + printk(KERN_ERR "SCF_CMD_PASSTHROUGH_NOALLOC not supported" + " with BIDI-COMMAND\n"); + return -ENOSYS; + } + + T_TASK(cmd)->t_mem_list = (struct list_head *)mem; + T_TASK(cmd)->t_tasks_se_num = sg_mem_num; + cmd->se_cmd_flags |= SCF_CMD_PASSTHROUGH_NOALLOC; + return 0; + } + /* + * Otherwise, assume the caller is passing a struct scatterlist + * array from include/linux/scatterlist.h + */ + if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) || + (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) { + /* + * For CDB using TCM struct se_mem linked list scatterlist memory + * processed into a TCM struct se_subsystem_dev, we do the mapping + * from the passed physical memory to struct se_mem->se_page here. + */ + T_TASK(cmd)->t_mem_list = transport_init_se_mem_list(); + if (!(T_TASK(cmd)->t_mem_list)) + return -ENOMEM; + + ret = transport_map_sg_to_mem(cmd, + T_TASK(cmd)->t_mem_list, mem, &se_mem_cnt_out); + if (ret < 0) + return -ENOMEM; + + T_TASK(cmd)->t_tasks_se_num = se_mem_cnt_out; + /* + * Setup BIDI READ list of struct se_mem elements + */ + if ((mem_bidi_in) && (sg_mem_bidi_num)) { + T_TASK(cmd)->t_mem_bidi_list = transport_init_se_mem_list(); + if (!(T_TASK(cmd)->t_mem_bidi_list)) { + kfree(T_TASK(cmd)->t_mem_list); + return -ENOMEM; + } + se_mem_cnt_out = 0; + + ret = transport_map_sg_to_mem(cmd, + T_TASK(cmd)->t_mem_bidi_list, mem_bidi_in, + &se_mem_cnt_out); + if (ret < 0) { + kfree(T_TASK(cmd)->t_mem_list); + return -ENOMEM; + } + + T_TASK(cmd)->t_tasks_se_bidi_num = se_mem_cnt_out; + } + cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; + + } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) { + if (mem_bidi_in || sg_mem_bidi_num) { + printk(KERN_ERR "BIDI-Commands not supported using " + "SCF_SCSI_CONTROL_NONSG_IO_CDB\n"); + return -ENOSYS; + } + /* + * For incoming CDBs using a contiguous buffer internall with TCM, + * save the passed struct scatterlist memory. After TCM storage object + * processing has completed for this struct se_cmd, TCM core will call + * transport_memcpy_[write,read]_contig() as necessary from + * transport_generic_complete_ok() and transport_write_pending() in order + * to copy the TCM buffer to/from the original passed *mem in SGL -> + * struct scatterlist format. + */ + cmd->se_cmd_flags |= SCF_PASSTHROUGH_CONTIG_TO_SG; + T_TASK(cmd)->t_task_pt_sgl = mem; + } + + return 0; +} +EXPORT_SYMBOL(transport_generic_map_mem_to_cmd); + + +static inline long long transport_dev_end_lba(struct se_device *dev) +{ + return dev->transport->get_blocks(dev) + 1; +} + +static int transport_get_sectors(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + + T_TASK(cmd)->t_tasks_sectors = + (cmd->data_length / DEV_ATTRIB(dev)->block_size); + if (!(T_TASK(cmd)->t_tasks_sectors)) + T_TASK(cmd)->t_tasks_sectors = 1; + + if (TRANSPORT(dev)->get_device_type(dev) != TYPE_DISK) + return 0; + + if ((T_TASK(cmd)->t_task_lba + T_TASK(cmd)->t_tasks_sectors) > + transport_dev_end_lba(dev)) { + printk(KERN_ERR "LBA: %llu Sectors: %u exceeds" + " transport_dev_end_lba(): %llu\n", + T_TASK(cmd)->t_task_lba, T_TASK(cmd)->t_tasks_sectors, + transport_dev_end_lba(dev)); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY; + return PYX_TRANSPORT_REQ_TOO_MANY_SECTORS; + } + + return 0; +} + +static int transport_new_cmd_obj(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + u32 task_cdbs = 0, rc; + + if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { + task_cdbs++; + T_TASK(cmd)->t_task_cdbs++; + } else { + int set_counts = 1; + + /* + * Setup any BIDI READ tasks and memory from + * T_TASK(cmd)->t_mem_bidi_list so the READ struct se_tasks + * are queued first for the non pSCSI passthrough case. + */ + if ((T_TASK(cmd)->t_mem_bidi_list != NULL) && + (TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV)) { + rc = transport_generic_get_cdb_count(cmd, + T_TASK(cmd)->t_task_lba, + T_TASK(cmd)->t_tasks_sectors, + DMA_FROM_DEVICE, T_TASK(cmd)->t_mem_bidi_list, + set_counts); + if (!(rc)) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + set_counts = 0; + } + /* + * Setup the tasks and memory from T_TASK(cmd)->t_mem_list + * Note for BIDI transfers this will contain the WRITE payload + */ + task_cdbs = transport_generic_get_cdb_count(cmd, + T_TASK(cmd)->t_task_lba, + T_TASK(cmd)->t_tasks_sectors, + cmd->data_direction, T_TASK(cmd)->t_mem_list, + set_counts); + if (!(task_cdbs)) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return PYX_TRANSPORT_LU_COMM_FAILURE; + } + T_TASK(cmd)->t_task_cdbs += task_cdbs; + +#if 0 + printk(KERN_INFO "data_length: %u, LBA: %llu t_tasks_sectors:" + " %u, t_task_cdbs: %u\n", obj_ptr, cmd->data_length, + T_TASK(cmd)->t_task_lba, T_TASK(cmd)->t_tasks_sectors, + T_TASK(cmd)->t_task_cdbs); +#endif + } + + atomic_set(&T_TASK(cmd)->t_task_cdbs_left, task_cdbs); + atomic_set(&T_TASK(cmd)->t_task_cdbs_ex_left, task_cdbs); + atomic_set(&T_TASK(cmd)->t_task_cdbs_timeout_left, task_cdbs); + return 0; +} + +static struct list_head *transport_init_se_mem_list(void) +{ + struct list_head *se_mem_list; + + se_mem_list = kzalloc(sizeof(struct list_head), GFP_KERNEL); + if (!(se_mem_list)) { + printk(KERN_ERR "Unable to allocate memory for se_mem_list\n"); + return NULL; + } + INIT_LIST_HEAD(se_mem_list); + + return se_mem_list; +} + +static int +transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) +{ + unsigned char *buf; + struct se_mem *se_mem; + + T_TASK(cmd)->t_mem_list = transport_init_se_mem_list(); + if (!(T_TASK(cmd)->t_mem_list)) + return -ENOMEM; + + /* + * If the device uses memory mapping this is enough. + */ + if (cmd->se_dev->transport->do_se_mem_map) + return 0; + + /* + * Setup BIDI-COMMAND READ list of struct se_mem elements + */ + if (T_TASK(cmd)->t_tasks_bidi) { + T_TASK(cmd)->t_mem_bidi_list = transport_init_se_mem_list(); + if (!(T_TASK(cmd)->t_mem_bidi_list)) { + kfree(T_TASK(cmd)->t_mem_list); + return -ENOMEM; + } + } + + while (length) { + se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL); + if (!(se_mem)) { + printk(KERN_ERR "Unable to allocate struct se_mem\n"); + goto out; + } + INIT_LIST_HEAD(&se_mem->se_list); + se_mem->se_len = (length > dma_size) ? dma_size : length; + +/* #warning FIXME Allocate contigous pages for struct se_mem elements */ + se_mem->se_page = (struct page *) alloc_pages(GFP_KERNEL, 0); + if (!(se_mem->se_page)) { + printk(KERN_ERR "alloc_pages() failed\n"); + goto out; + } + + buf = kmap_atomic(se_mem->se_page, KM_IRQ0); + if (!(buf)) { + printk(KERN_ERR "kmap_atomic() failed\n"); + goto out; + } + memset(buf, 0, se_mem->se_len); + kunmap_atomic(buf, KM_IRQ0); + + list_add_tail(&se_mem->se_list, T_TASK(cmd)->t_mem_list); + T_TASK(cmd)->t_tasks_se_num++; + + DEBUG_MEM("Allocated struct se_mem page(%p) Length(%u)" + " Offset(%u)\n", se_mem->se_page, se_mem->se_len, + se_mem->se_off); + + length -= se_mem->se_len; + } + + DEBUG_MEM("Allocated total struct se_mem elements(%u)\n", + T_TASK(cmd)->t_tasks_se_num); + + return 0; +out: + return -1; +} + +extern u32 transport_calc_sg_num( + struct se_task *task, + struct se_mem *in_se_mem, + u32 task_offset) +{ + struct se_cmd *se_cmd = task->task_se_cmd; + struct se_device *se_dev = SE_DEV(se_cmd); + struct se_mem *se_mem = in_se_mem; + struct target_core_fabric_ops *tfo = CMD_TFO(se_cmd); + u32 sg_length, task_size = task->task_size, task_sg_num_padded; + + while (task_size != 0) { + DEBUG_SC("se_mem->se_page(%p) se_mem->se_len(%u)" + " se_mem->se_off(%u) task_offset(%u)\n", + se_mem->se_page, se_mem->se_len, + se_mem->se_off, task_offset); + + if (task_offset == 0) { + if (task_size >= se_mem->se_len) { + sg_length = se_mem->se_len; + + if (!(list_is_last(&se_mem->se_list, + T_TASK(se_cmd)->t_mem_list))) + se_mem = list_entry(se_mem->se_list.next, + struct se_mem, se_list); + } else { + sg_length = task_size; + task_size -= sg_length; + goto next; + } + + DEBUG_SC("sg_length(%u) task_size(%u)\n", + sg_length, task_size); + } else { + if ((se_mem->se_len - task_offset) > task_size) { + sg_length = task_size; + task_size -= sg_length; + goto next; + } else { + sg_length = (se_mem->se_len - task_offset); + + if (!(list_is_last(&se_mem->se_list, + T_TASK(se_cmd)->t_mem_list))) + se_mem = list_entry(se_mem->se_list.next, + struct se_mem, se_list); + } + + DEBUG_SC("sg_length(%u) task_size(%u)\n", + sg_length, task_size); + + task_offset = 0; + } + task_size -= sg_length; +next: + DEBUG_SC("task[%u] - Reducing task_size to(%u)\n", + task->task_no, task_size); + + task->task_sg_num++; + } + /* + * Check if the fabric module driver is requesting that all + * struct se_task->task_sg[] be chained together.. If so, + * then allocate an extra padding SG entry for linking and + * marking the end of the chained SGL. + */ + if (tfo->task_sg_chaining) { + task_sg_num_padded = (task->task_sg_num + 1); + task->task_padded_sg = 1; + } else + task_sg_num_padded = task->task_sg_num; + + task->task_sg = kzalloc(task_sg_num_padded * + sizeof(struct scatterlist), GFP_KERNEL); + if (!(task->task_sg)) { + printk(KERN_ERR "Unable to allocate memory for" + " task->task_sg\n"); + return 0; + } + sg_init_table(&task->task_sg[0], task_sg_num_padded); + /* + * Setup task->task_sg_bidi for SCSI READ payload for + * TCM/pSCSI passthrough if present for BIDI-COMMAND + */ + if ((T_TASK(se_cmd)->t_mem_bidi_list != NULL) && + (TRANSPORT(se_dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)) { + task->task_sg_bidi = kzalloc(task_sg_num_padded * + sizeof(struct scatterlist), GFP_KERNEL); + if (!(task->task_sg_bidi)) { + printk(KERN_ERR "Unable to allocate memory for" + " task->task_sg_bidi\n"); + return 0; + } + sg_init_table(&task->task_sg_bidi[0], task_sg_num_padded); + } + /* + * For the chaining case, setup the proper end of SGL for the + * initial submission struct task into struct se_subsystem_api. + * This will be cleared later by transport_do_task_sg_chain() + */ + if (task->task_padded_sg) { + sg_mark_end(&task->task_sg[task->task_sg_num - 1]); + /* + * Added the 'if' check before marking end of bi-directional + * scatterlist (which gets created only in case of request + * (RD + WR). + */ + if (task->task_sg_bidi) + sg_mark_end(&task->task_sg_bidi[task->task_sg_num - 1]); + } + + DEBUG_SC("Successfully allocated task->task_sg_num(%u)," + " task_sg_num_padded(%u)\n", task->task_sg_num, + task_sg_num_padded); + + return task->task_sg_num; +} + +static inline int transport_set_tasks_sectors_disk( + struct se_task *task, + struct se_device *dev, + unsigned long long lba, + u32 sectors, + int *max_sectors_set) +{ + if ((lba + sectors) > transport_dev_end_lba(dev)) { + task->task_sectors = ((transport_dev_end_lba(dev) - lba) + 1); + + if (task->task_sectors > DEV_ATTRIB(dev)->max_sectors) { + task->task_sectors = DEV_ATTRIB(dev)->max_sectors; + *max_sectors_set = 1; + } + } else { + if (sectors > DEV_ATTRIB(dev)->max_sectors) { + task->task_sectors = DEV_ATTRIB(dev)->max_sectors; + *max_sectors_set = 1; + } else + task->task_sectors = sectors; + } + + return 0; +} + +static inline int transport_set_tasks_sectors_non_disk( + struct se_task *task, + struct se_device *dev, + unsigned long long lba, + u32 sectors, + int *max_sectors_set) +{ + if (sectors > DEV_ATTRIB(dev)->max_sectors) { + task->task_sectors = DEV_ATTRIB(dev)->max_sectors; + *max_sectors_set = 1; + } else + task->task_sectors = sectors; + + return 0; +} + +static inline int transport_set_tasks_sectors( + struct se_task *task, + struct se_device *dev, + unsigned long long lba, + u32 sectors, + int *max_sectors_set) +{ + return (TRANSPORT(dev)->get_device_type(dev) == TYPE_DISK) ? + transport_set_tasks_sectors_disk(task, dev, lba, sectors, + max_sectors_set) : + transport_set_tasks_sectors_non_disk(task, dev, lba, sectors, + max_sectors_set); +} + +static int transport_map_sg_to_mem( + struct se_cmd *cmd, + struct list_head *se_mem_list, + void *in_mem, + u32 *se_mem_cnt) +{ + struct se_mem *se_mem; + struct scatterlist *sg; + u32 sg_count = 1, cmd_size = cmd->data_length; + + if (!in_mem) { + printk(KERN_ERR "No source scatterlist\n"); + return -1; + } + sg = (struct scatterlist *)in_mem; + + while (cmd_size) { + se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL); + if (!(se_mem)) { + printk(KERN_ERR "Unable to allocate struct se_mem\n"); + return -1; + } + INIT_LIST_HEAD(&se_mem->se_list); + DEBUG_MEM("sg_to_mem: Starting loop with cmd_size: %u" + " sg_page: %p offset: %d length: %d\n", cmd_size, + sg_page(sg), sg->offset, sg->length); + + se_mem->se_page = sg_page(sg); + se_mem->se_off = sg->offset; + + if (cmd_size > sg->length) { + se_mem->se_len = sg->length; + sg = sg_next(sg); + sg_count++; + } else + se_mem->se_len = cmd_size; + + cmd_size -= se_mem->se_len; + + DEBUG_MEM("sg_to_mem: *se_mem_cnt: %u cmd_size: %u\n", + *se_mem_cnt, cmd_size); + DEBUG_MEM("sg_to_mem: Final se_page: %p se_off: %d se_len: %d\n", + se_mem->se_page, se_mem->se_off, se_mem->se_len); + + list_add_tail(&se_mem->se_list, se_mem_list); + (*se_mem_cnt)++; + } + + DEBUG_MEM("task[0] - Mapped(%u) struct scatterlist segments to(%u)" + " struct se_mem\n", sg_count, *se_mem_cnt); + + if (sg_count != *se_mem_cnt) + BUG(); + + return 0; +} + +/* transport_map_mem_to_sg(): + * + * + */ +int transport_map_mem_to_sg( + struct se_task *task, + struct list_head *se_mem_list, + void *in_mem, + struct se_mem *in_se_mem, + struct se_mem **out_se_mem, + u32 *se_mem_cnt, + u32 *task_offset) +{ + struct se_cmd *se_cmd = task->task_se_cmd; + struct se_mem *se_mem = in_se_mem; + struct scatterlist *sg = (struct scatterlist *)in_mem; + u32 task_size = task->task_size, sg_no = 0; + + if (!sg) { + printk(KERN_ERR "Unable to locate valid struct" + " scatterlist pointer\n"); + return -1; + } + + while (task_size != 0) { + /* + * Setup the contigious array of scatterlists for + * this struct se_task. + */ + sg_assign_page(sg, se_mem->se_page); + + if (*task_offset == 0) { + sg->offset = se_mem->se_off; + + if (task_size >= se_mem->se_len) { + sg->length = se_mem->se_len; + + if (!(list_is_last(&se_mem->se_list, + T_TASK(se_cmd)->t_mem_list))) { + se_mem = list_entry(se_mem->se_list.next, + struct se_mem, se_list); + (*se_mem_cnt)++; + } + } else { + sg->length = task_size; + /* + * Determine if we need to calculate an offset + * into the struct se_mem on the next go around.. + */ + task_size -= sg->length; + if (!(task_size)) + *task_offset = sg->length; + + goto next; + } + + } else { + sg->offset = (*task_offset + se_mem->se_off); + + if ((se_mem->se_len - *task_offset) > task_size) { + sg->length = task_size; + /* + * Determine if we need to calculate an offset + * into the struct se_mem on the next go around.. + */ + task_size -= sg->length; + if (!(task_size)) + *task_offset += sg->length; + + goto next; + } else { + sg->length = (se_mem->se_len - *task_offset); + + if (!(list_is_last(&se_mem->se_list, + T_TASK(se_cmd)->t_mem_list))) { + se_mem = list_entry(se_mem->se_list.next, + struct se_mem, se_list); + (*se_mem_cnt)++; + } + } + + *task_offset = 0; + } + task_size -= sg->length; +next: + DEBUG_MEM("task[%u] mem_to_sg - sg[%u](%p)(%u)(%u) - Reducing" + " task_size to(%u), task_offset: %u\n", task->task_no, sg_no, + sg_page(sg), sg->length, sg->offset, task_size, *task_offset); + + sg_no++; + if (!(task_size)) + break; + + sg = sg_next(sg); + + if (task_size > se_cmd->data_length) + BUG(); + } + *out_se_mem = se_mem; + + DEBUG_MEM("task[%u] - Mapped(%u) struct se_mem segments to total(%u)" + " SGs\n", task->task_no, *se_mem_cnt, sg_no); + + return 0; +} + +/* + * This function can be used by HW target mode drivers to create a linked + * scatterlist from all contiguously allocated struct se_task->task_sg[]. + * This is intended to be called during the completion path by TCM Core + * when struct target_core_fabric_ops->check_task_sg_chaining is enabled. + */ +void transport_do_task_sg_chain(struct se_cmd *cmd) +{ + struct scatterlist *sg_head = NULL, *sg_link = NULL, *sg_first = NULL; + struct scatterlist *sg_head_cur = NULL, *sg_link_cur = NULL; + struct scatterlist *sg, *sg_end = NULL, *sg_end_cur = NULL; + struct se_task *task; + struct target_core_fabric_ops *tfo = CMD_TFO(cmd); + u32 task_sg_num = 0, sg_count = 0; + int i; + + if (tfo->task_sg_chaining == 0) { + printk(KERN_ERR "task_sg_chaining is diabled for fabric module:" + " %s\n", tfo->get_fabric_name()); + dump_stack(); + return; + } + /* + * Walk the struct se_task list and setup scatterlist chains + * for each contiguosly allocated struct se_task->task_sg[]. + */ + list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) { + if (!(task->task_sg) || !(task->task_padded_sg)) + continue; + + if (sg_head && sg_link) { + sg_head_cur = &task->task_sg[0]; + sg_link_cur = &task->task_sg[task->task_sg_num]; + /* + * Either add chain or mark end of scatterlist + */ + if (!(list_is_last(&task->t_list, + &T_TASK(cmd)->t_task_list))) { + /* + * Clear existing SGL termination bit set in + * transport_calc_sg_num(), see sg_mark_end() + */ + sg_end_cur = &task->task_sg[task->task_sg_num - 1]; + sg_end_cur->page_link &= ~0x02; + + sg_chain(sg_head, task_sg_num, sg_head_cur); + sg_count += (task->task_sg_num + 1); + } else + sg_count += task->task_sg_num; + + sg_head = sg_head_cur; + sg_link = sg_link_cur; + task_sg_num = task->task_sg_num; + continue; + } + sg_head = sg_first = &task->task_sg[0]; + sg_link = &task->task_sg[task->task_sg_num]; + task_sg_num = task->task_sg_num; + /* + * Check for single task.. + */ + if (!(list_is_last(&task->t_list, &T_TASK(cmd)->t_task_list))) { + /* + * Clear existing SGL termination bit set in + * transport_calc_sg_num(), see sg_mark_end() + */ + sg_end = &task->task_sg[task->task_sg_num - 1]; + sg_end->page_link &= ~0x02; + sg_count += (task->task_sg_num + 1); + } else + sg_count += task->task_sg_num; + } + /* + * Setup the starting pointer and total t_tasks_sg_linked_no including + * padding SGs for linking and to mark the end. + */ + T_TASK(cmd)->t_tasks_sg_chained = sg_first; + T_TASK(cmd)->t_tasks_sg_chained_no = sg_count; + + DEBUG_CMD_M("Setup T_TASK(cmd)->t_tasks_sg_chained: %p and" + " t_tasks_sg_chained_no: %u\n", T_TASK(cmd)->t_tasks_sg_chained, + T_TASK(cmd)->t_tasks_sg_chained_no); + + for_each_sg(T_TASK(cmd)->t_tasks_sg_chained, sg, + T_TASK(cmd)->t_tasks_sg_chained_no, i) { + + DEBUG_CMD_M("SG: %p page: %p length: %d offset: %d\n", + sg, sg_page(sg), sg->length, sg->offset); + if (sg_is_chain(sg)) + DEBUG_CMD_M("SG: %p sg_is_chain=1\n", sg); + if (sg_is_last(sg)) + DEBUG_CMD_M("SG: %p sg_is_last=1\n", sg); + } + +} +EXPORT_SYMBOL(transport_do_task_sg_chain); + +static int transport_do_se_mem_map( + struct se_device *dev, + struct se_task *task, + struct list_head *se_mem_list, + void *in_mem, + struct se_mem *in_se_mem, + struct se_mem **out_se_mem, + u32 *se_mem_cnt, + u32 *task_offset_in) +{ + u32 task_offset = *task_offset_in; + int ret = 0; + /* + * se_subsystem_api_t->do_se_mem_map is used when internal allocation + * has been done by the transport plugin. + */ + if (TRANSPORT(dev)->do_se_mem_map) { + ret = TRANSPORT(dev)->do_se_mem_map(task, se_mem_list, + in_mem, in_se_mem, out_se_mem, se_mem_cnt, + task_offset_in); + if (ret == 0) + T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt; + + return ret; + } + /* + * This is the normal path for all normal non BIDI and BIDI-COMMAND + * WRITE payloads.. If we need to do BIDI READ passthrough for + * TCM/pSCSI the first call to transport_do_se_mem_map -> + * transport_calc_sg_num() -> transport_map_mem_to_sg() will do the + * allocation for task->task_sg_bidi, and the subsequent call to + * transport_do_se_mem_map() from transport_generic_get_cdb_count() + */ + if (!(task->task_sg_bidi)) { + /* + * Assume default that transport plugin speaks preallocated + * scatterlists. + */ + if (!(transport_calc_sg_num(task, in_se_mem, task_offset))) + return -1; + /* + * struct se_task->task_sg now contains the struct scatterlist array. + */ + return transport_map_mem_to_sg(task, se_mem_list, task->task_sg, + in_se_mem, out_se_mem, se_mem_cnt, + task_offset_in); + } + /* + * Handle the se_mem_list -> struct task->task_sg_bidi + * memory map for the extra BIDI READ payload + */ + return transport_map_mem_to_sg(task, se_mem_list, task->task_sg_bidi, + in_se_mem, out_se_mem, se_mem_cnt, + task_offset_in); +} + +static u32 transport_generic_get_cdb_count( + struct se_cmd *cmd, + unsigned long long lba, + u32 sectors, + enum dma_data_direction data_direction, + struct list_head *mem_list, + int set_counts) +{ + unsigned char *cdb = NULL; + struct se_task *task; + struct se_mem *se_mem = NULL, *se_mem_lout = NULL; + struct se_mem *se_mem_bidi = NULL, *se_mem_bidi_lout = NULL; + struct se_device *dev = SE_DEV(cmd); + int max_sectors_set = 0, ret; + u32 task_offset_in = 0, se_mem_cnt = 0, se_mem_bidi_cnt = 0, task_cdbs = 0; + + if (!mem_list) { + printk(KERN_ERR "mem_list is NULL in transport_generic_get" + "_cdb_count()\n"); + return 0; + } + /* + * While using RAMDISK_DR backstores is the only case where + * mem_list will ever be empty at this point. + */ + if (!(list_empty(mem_list))) + se_mem = list_entry(mem_list->next, struct se_mem, se_list); + /* + * Check for extra se_mem_bidi mapping for BIDI-COMMANDs to + * struct se_task->task_sg_bidi for TCM/pSCSI passthrough operation + */ + if ((T_TASK(cmd)->t_mem_bidi_list != NULL) && + !(list_empty(T_TASK(cmd)->t_mem_bidi_list)) && + (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)) + se_mem_bidi = list_entry(T_TASK(cmd)->t_mem_bidi_list->next, + struct se_mem, se_list); + + while (sectors) { + DEBUG_VOL("ITT[0x%08x] LBA(%llu) SectorsLeft(%u) EOBJ(%llu)\n", + CMD_TFO(cmd)->get_task_tag(cmd), lba, sectors, + transport_dev_end_lba(dev)); + + task = transport_generic_get_task(cmd, data_direction); + if (!(task)) + goto out; + + transport_set_tasks_sectors(task, dev, lba, sectors, + &max_sectors_set); + + task->task_lba = lba; + lba += task->task_sectors; + sectors -= task->task_sectors; + task->task_size = (task->task_sectors * + DEV_ATTRIB(dev)->block_size); + + cdb = TRANSPORT(dev)->get_cdb(task); + if ((cdb)) { + memcpy(cdb, T_TASK(cmd)->t_task_cdb, + scsi_command_size(T_TASK(cmd)->t_task_cdb)); + cmd->transport_split_cdb(task->task_lba, + &task->task_sectors, cdb); + } + + /* + * Perform the SE OBJ plugin and/or Transport plugin specific + * mapping for T_TASK(cmd)->t_mem_list. And setup the + * task->task_sg and if necessary task->task_sg_bidi + */ + ret = transport_do_se_mem_map(dev, task, mem_list, + NULL, se_mem, &se_mem_lout, &se_mem_cnt, + &task_offset_in); + if (ret < 0) + goto out; + + se_mem = se_mem_lout; + /* + * Setup the T_TASK(cmd)->t_mem_bidi_list -> task->task_sg_bidi + * mapping for SCSI READ for BIDI-COMMAND passthrough with TCM/pSCSI + * + * Note that the first call to transport_do_se_mem_map() above will + * allocate struct se_task->task_sg_bidi in transport_do_se_mem_map() + * -> transport_calc_sg_num(), and the second here will do the + * mapping for SCSI READ for BIDI-COMMAND passthrough with TCM/pSCSI. + */ + if (task->task_sg_bidi != NULL) { + ret = transport_do_se_mem_map(dev, task, + T_TASK(cmd)->t_mem_bidi_list, NULL, + se_mem_bidi, &se_mem_bidi_lout, &se_mem_bidi_cnt, + &task_offset_in); + if (ret < 0) + goto out; + + se_mem_bidi = se_mem_bidi_lout; + } + task_cdbs++; + + DEBUG_VOL("Incremented task_cdbs(%u) task->task_sg_num(%u)\n", + task_cdbs, task->task_sg_num); + + if (max_sectors_set) { + max_sectors_set = 0; + continue; + } + + if (!sectors) + break; + } + + if (set_counts) { + atomic_inc(&T_TASK(cmd)->t_fe_count); + atomic_inc(&T_TASK(cmd)->t_se_count); + } + + DEBUG_VOL("ITT[0x%08x] total %s cdbs(%u)\n", + CMD_TFO(cmd)->get_task_tag(cmd), (data_direction == DMA_TO_DEVICE) + ? "DMA_TO_DEVICE" : "DMA_FROM_DEVICE", task_cdbs); + + return task_cdbs; +out: + return 0; +} + +static int +transport_map_control_cmd_to_task(struct se_cmd *cmd) +{ + struct se_device *dev = SE_DEV(cmd); + unsigned char *cdb; + struct se_task *task; + int ret; + + task = transport_generic_get_task(cmd, cmd->data_direction); + if (!task) + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + + cdb = TRANSPORT(dev)->get_cdb(task); + if (cdb) + memcpy(cdb, cmd->t_task->t_task_cdb, + scsi_command_size(cmd->t_task->t_task_cdb)); + + task->task_size = cmd->data_length; + task->task_sg_num = + (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) ? 1 : 0; + + atomic_inc(&cmd->t_task->t_fe_count); + atomic_inc(&cmd->t_task->t_se_count); + + if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) { + struct se_mem *se_mem = NULL, *se_mem_lout = NULL; + u32 se_mem_cnt = 0, task_offset = 0; + + BUG_ON(list_empty(cmd->t_task->t_mem_list)); + + ret = transport_do_se_mem_map(dev, task, + cmd->t_task->t_mem_list, NULL, se_mem, + &se_mem_lout, &se_mem_cnt, &task_offset); + if (ret < 0) + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + + if (dev->transport->map_task_SG) + return dev->transport->map_task_SG(task); + return 0; + } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) { + if (dev->transport->map_task_non_SG) + return dev->transport->map_task_non_SG(task); + return 0; + } else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { + if (dev->transport->cdb_none) + return dev->transport->cdb_none(task); + return 0; + } else { + BUG(); + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + } +} + +/* transport_generic_new_cmd(): Called from transport_processing_thread() + * + * Allocate storage transport resources from a set of values predefined + * by transport_generic_cmd_sequencer() from the iSCSI Target RX process. + * Any non zero return here is treated as an "out of resource' op here. + */ + /* + * Generate struct se_task(s) and/or their payloads for this CDB. + */ +static int transport_generic_new_cmd(struct se_cmd *cmd) +{ + struct se_portal_group *se_tpg; + struct se_task *task; + struct se_device *dev = SE_DEV(cmd); + int ret = 0; + + /* + * Determine is the TCM fabric module has already allocated physical + * memory, and is directly calling transport_generic_map_mem_to_cmd() + * to setup beforehand the linked list of physical memory at + * T_TASK(cmd)->t_mem_list of struct se_mem->se_page + */ + if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) { + ret = transport_allocate_resources(cmd); + if (ret < 0) + return ret; + } + + ret = transport_get_sectors(cmd); + if (ret < 0) + return ret; + + ret = transport_new_cmd_obj(cmd); + if (ret < 0) + return ret; + + /* + * Determine if the calling TCM fabric module is talking to + * Linux/NET via kernel sockets and needs to allocate a + * struct iovec array to complete the struct se_cmd + */ + se_tpg = SE_LUN(cmd)->lun_sep->sep_tpg; + if (TPG_TFO(se_tpg)->alloc_cmd_iovecs != NULL) { + ret = TPG_TFO(se_tpg)->alloc_cmd_iovecs(cmd); + if (ret < 0) + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + } + + if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) { + if (atomic_read(&task->task_sent)) + continue; + if (!dev->transport->map_task_SG) + continue; + + ret = dev->transport->map_task_SG(task); + if (ret < 0) + return ret; + } + } else { + ret = transport_map_control_cmd_to_task(cmd); + if (ret < 0) + return ret; + } + + /* + * For WRITEs, let the iSCSI Target RX Thread know its buffer is ready.. + * This WRITE struct se_cmd (and all of its associated struct se_task's) + * will be added to the struct se_device execution queue after its WRITE + * data has arrived. (ie: It gets handled by the transport processing + * thread a second time) + */ + if (cmd->data_direction == DMA_TO_DEVICE) { + transport_add_tasks_to_state_queue(cmd); + return transport_generic_write_pending(cmd); + } + /* + * Everything else but a WRITE, add the struct se_cmd's struct se_task's + * to the execution queue. + */ + transport_execute_tasks(cmd); + return 0; +} + +/* transport_generic_process_write(): + * + * + */ +void transport_generic_process_write(struct se_cmd *cmd) +{ +#if 0 + /* + * Copy SCSI Presented DTL sector(s) from received buffers allocated to + * original EDTL + */ + if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { + if (!T_TASK(cmd)->t_tasks_se_num) { + unsigned char *dst, *buf = + (unsigned char *)T_TASK(cmd)->t_task_buf; + + dst = kzalloc(cmd->cmd_spdtl), GFP_KERNEL); + if (!(dst)) { + printk(KERN_ERR "Unable to allocate memory for" + " WRITE underflow\n"); + transport_generic_request_failure(cmd, NULL, + PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1); + return; + } + memcpy(dst, buf, cmd->cmd_spdtl); + + kfree(T_TASK(cmd)->t_task_buf); + T_TASK(cmd)->t_task_buf = dst; + } else { + struct scatterlist *sg = + (struct scatterlist *sg)T_TASK(cmd)->t_task_buf; + struct scatterlist *orig_sg; + + orig_sg = kzalloc(sizeof(struct scatterlist) * + T_TASK(cmd)->t_tasks_se_num, + GFP_KERNEL))) { + if (!(orig_sg)) { + printk(KERN_ERR "Unable to allocate memory" + " for WRITE underflow\n"); + transport_generic_request_failure(cmd, NULL, + PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1); + return; + } + + memcpy(orig_sg, T_TASK(cmd)->t_task_buf, + sizeof(struct scatterlist) * + T_TASK(cmd)->t_tasks_se_num); + + cmd->data_length = cmd->cmd_spdtl; + /* + * FIXME, clear out original struct se_task and state + * information. + */ + if (transport_generic_new_cmd(cmd) < 0) { + transport_generic_request_failure(cmd, NULL, + PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1); + kfree(orig_sg); + return; + } + + transport_memcpy_write_sg(cmd, orig_sg); + } + } +#endif + transport_execute_tasks(cmd); +} +EXPORT_SYMBOL(transport_generic_process_write); + +/* transport_generic_write_pending(): + * + * + */ +static int transport_generic_write_pending(struct se_cmd *cmd) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + cmd->t_state = TRANSPORT_WRITE_PENDING; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + /* + * For the TCM control CDBs using a contiguous buffer, do the memcpy + * from the passed Linux/SCSI struct scatterlist located at + * T_TASK(se_cmd)->t_task_pt_buf to the contiguous buffer at + * T_TASK(se_cmd)->t_task_buf. + */ + if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG) + transport_memcpy_read_contig(cmd, + T_TASK(cmd)->t_task_buf, + T_TASK(cmd)->t_task_pt_sgl); + /* + * Clear the se_cmd for WRITE_PENDING status in order to set + * T_TASK(cmd)->t_transport_active=0 so that transport_generic_handle_data + * can be called from HW target mode interrupt code. This is safe + * to be called with transport_off=1 before the CMD_TFO(cmd)->write_pending + * because the se_cmd->se_lun pointer is not being cleared. + */ + transport_cmd_check_stop(cmd, 1, 0); + + /* + * Call the fabric write_pending function here to let the + * frontend know that WRITE buffers are ready. + */ + ret = CMD_TFO(cmd)->write_pending(cmd); + if (ret < 0) + return ret; + + return PYX_TRANSPORT_WRITE_PENDING; +} + +/* transport_release_cmd_to_pool(): + * + * + */ +void transport_release_cmd_to_pool(struct se_cmd *cmd) +{ + BUG_ON(!T_TASK(cmd)); + BUG_ON(!CMD_TFO(cmd)); + + transport_free_se_cmd(cmd); + CMD_TFO(cmd)->release_cmd_to_pool(cmd); +} +EXPORT_SYMBOL(transport_release_cmd_to_pool); + +/* transport_generic_free_cmd(): + * + * Called from processing frontend to release storage engine resources + */ +void transport_generic_free_cmd( + struct se_cmd *cmd, + int wait_for_tasks, + int release_to_pool, + int session_reinstatement) +{ + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) || !T_TASK(cmd)) + transport_release_cmd_to_pool(cmd); + else { + core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd); + + if (SE_LUN(cmd)) { +#if 0 + printk(KERN_INFO "cmd: %p ITT: 0x%08x contains" + " SE_LUN(cmd)\n", cmd, + CMD_TFO(cmd)->get_task_tag(cmd)); +#endif + transport_lun_remove_cmd(cmd); + } + + if (wait_for_tasks && cmd->transport_wait_for_tasks) + cmd->transport_wait_for_tasks(cmd, 0, 0); + + transport_generic_remove(cmd, release_to_pool, + session_reinstatement); + } +} +EXPORT_SYMBOL(transport_generic_free_cmd); + +static void transport_nop_wait_for_tasks( + struct se_cmd *cmd, + int remove_cmd, + int session_reinstatement) +{ + return; +} + +/* transport_lun_wait_for_tasks(): + * + * Called from ConfigFS context to stop the passed struct se_cmd to allow + * an struct se_lun to be successfully shutdown. + */ +static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) +{ + unsigned long flags; + int ret; + /* + * If the frontend has already requested this struct se_cmd to + * be stopped, we can safely ignore this struct se_cmd. + */ + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (atomic_read(&T_TASK(cmd)->t_transport_stop)) { + atomic_set(&T_TASK(cmd)->transport_lun_stop, 0); + DEBUG_TRANSPORT_S("ConfigFS ITT[0x%08x] - t_transport_stop ==" + " TRUE, skipping\n", CMD_TFO(cmd)->get_task_tag(cmd)); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + transport_cmd_check_stop(cmd, 1, 0); + return -1; + } + atomic_set(&T_TASK(cmd)->transport_lun_fe_stop, 1); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + wake_up_interruptible(&SE_DEV(cmd)->dev_queue_obj->thread_wq); + + ret = transport_stop_tasks_for_cmd(cmd); + + DEBUG_TRANSPORT_S("ConfigFS: cmd: %p t_task_cdbs: %d stop tasks ret:" + " %d\n", cmd, T_TASK(cmd)->t_task_cdbs, ret); + if (!ret) { + DEBUG_TRANSPORT_S("ConfigFS: ITT[0x%08x] - stopping cmd....\n", + CMD_TFO(cmd)->get_task_tag(cmd)); + wait_for_completion(&T_TASK(cmd)->transport_lun_stop_comp); + DEBUG_TRANSPORT_S("ConfigFS: ITT[0x%08x] - stopped cmd....\n", + CMD_TFO(cmd)->get_task_tag(cmd)); + } + transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj); + + return 0; +} + +/* #define DEBUG_CLEAR_LUN */ +#ifdef DEBUG_CLEAR_LUN +#define DEBUG_CLEAR_L(x...) printk(KERN_INFO x) +#else +#define DEBUG_CLEAR_L(x...) +#endif + +static void __transport_clear_lun_from_sessions(struct se_lun *lun) +{ + struct se_cmd *cmd = NULL; + unsigned long lun_flags, cmd_flags; + /* + * Do exception processing and return CHECK_CONDITION status to the + * Initiator Port. + */ + spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags); + while (!list_empty_careful(&lun->lun_cmd_list)) { + cmd = list_entry(lun->lun_cmd_list.next, + struct se_cmd, se_lun_list); + list_del(&cmd->se_lun_list); + + if (!(T_TASK(cmd))) { + printk(KERN_ERR "ITT: 0x%08x, T_TASK(cmd) = NULL" + "[i,t]_state: %u/%u\n", + CMD_TFO(cmd)->get_task_tag(cmd), + CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state); + BUG(); + } + atomic_set(&T_TASK(cmd)->transport_lun_active, 0); + /* + * This will notify iscsi_target_transport.c: + * transport_cmd_check_stop() that a LUN shutdown is in + * progress for the iscsi_cmd_t. + */ + spin_lock(&T_TASK(cmd)->t_state_lock); + DEBUG_CLEAR_L("SE_LUN[%d] - Setting T_TASK(cmd)->transport" + "_lun_stop for ITT: 0x%08x\n", + SE_LUN(cmd)->unpacked_lun, + CMD_TFO(cmd)->get_task_tag(cmd)); + atomic_set(&T_TASK(cmd)->transport_lun_stop, 1); + spin_unlock(&T_TASK(cmd)->t_state_lock); + + spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags); + + if (!(SE_LUN(cmd))) { + printk(KERN_ERR "ITT: 0x%08x, [i,t]_state: %u/%u\n", + CMD_TFO(cmd)->get_task_tag(cmd), + CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state); + BUG(); + } + /* + * If the Storage engine still owns the iscsi_cmd_t, determine + * and/or stop its context. + */ + DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x before transport" + "_lun_wait_for_tasks()\n", SE_LUN(cmd)->unpacked_lun, + CMD_TFO(cmd)->get_task_tag(cmd)); + + if (transport_lun_wait_for_tasks(cmd, SE_LUN(cmd)) < 0) { + spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags); + continue; + } + + DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x after transport_lun" + "_wait_for_tasks(): SUCCESS\n", + SE_LUN(cmd)->unpacked_lun, + CMD_TFO(cmd)->get_task_tag(cmd)); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, cmd_flags); + if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags); + goto check_cond; + } + atomic_set(&T_TASK(cmd)->transport_dev_active, 0); + transport_all_task_dev_remove_state(cmd); + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags); + + transport_free_dev_tasks(cmd); + /* + * The Storage engine stopped this struct se_cmd before it was + * send to the fabric frontend for delivery back to the + * Initiator Node. Return this SCSI CDB back with an + * CHECK_CONDITION status. + */ +check_cond: + transport_send_check_condition_and_sense(cmd, + TCM_NON_EXISTENT_LUN, 0); + /* + * If the fabric frontend is waiting for this iscsi_cmd_t to + * be released, notify the waiting thread now that LU has + * finished accessing it. + */ + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, cmd_flags); + if (atomic_read(&T_TASK(cmd)->transport_lun_fe_stop)) { + DEBUG_CLEAR_L("SE_LUN[%d] - Detected FE stop for" + " struct se_cmd: %p ITT: 0x%08x\n", + lun->unpacked_lun, + cmd, CMD_TFO(cmd)->get_task_tag(cmd)); + + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, + cmd_flags); + transport_cmd_check_stop(cmd, 1, 0); + complete(&T_TASK(cmd)->transport_lun_fe_stop_comp); + spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags); + continue; + } + DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x finished processing\n", + lun->unpacked_lun, CMD_TFO(cmd)->get_task_tag(cmd)); + + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags); + spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags); + } + spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags); +} + +static int transport_clear_lun_thread(void *p) +{ + struct se_lun *lun = (struct se_lun *)p; + + __transport_clear_lun_from_sessions(lun); + complete(&lun->lun_shutdown_comp); + + return 0; +} + +int transport_clear_lun_from_sessions(struct se_lun *lun) +{ + struct task_struct *kt; + + kt = kthread_run(transport_clear_lun_thread, (void *)lun, + "tcm_cl_%u", lun->unpacked_lun); + if (IS_ERR(kt)) { + printk(KERN_ERR "Unable to start clear_lun thread\n"); + return -1; + } + wait_for_completion(&lun->lun_shutdown_comp); + + return 0; +} + +/* transport_generic_wait_for_tasks(): + * + * Called from frontend or passthrough context to wait for storage engine + * to pause and/or release frontend generated struct se_cmd. + */ +static void transport_generic_wait_for_tasks( + struct se_cmd *cmd, + int remove_cmd, + int session_reinstatement) +{ + unsigned long flags; + + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) + return; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + /* + * If we are already stopped due to an external event (ie: LUN shutdown) + * sleep until the connection can have the passed struct se_cmd back. + * The T_TASK(cmd)->transport_lun_stopped_sem will be upped by + * transport_clear_lun_from_sessions() once the ConfigFS context caller + * has completed its operation on the struct se_cmd. + */ + if (atomic_read(&T_TASK(cmd)->transport_lun_stop)) { + + DEBUG_TRANSPORT_S("wait_for_tasks: Stopping" + " wait_for_completion(&T_TASK(cmd)transport_lun_fe" + "_stop_comp); for ITT: 0x%08x\n", + CMD_TFO(cmd)->get_task_tag(cmd)); + /* + * There is a special case for WRITES where a FE exception + + * LUN shutdown means ConfigFS context is still sleeping on + * transport_lun_stop_comp in transport_lun_wait_for_tasks(). + * We go ahead and up transport_lun_stop_comp just to be sure + * here. + */ + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + complete(&T_TASK(cmd)->transport_lun_stop_comp); + wait_for_completion(&T_TASK(cmd)->transport_lun_fe_stop_comp); + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + + transport_all_task_dev_remove_state(cmd); + /* + * At this point, the frontend who was the originator of this + * struct se_cmd, now owns the structure and can be released through + * normal means below. + */ + DEBUG_TRANSPORT_S("wait_for_tasks: Stopped" + " wait_for_completion(&T_TASK(cmd)transport_lun_fe_" + "stop_comp); for ITT: 0x%08x\n", + CMD_TFO(cmd)->get_task_tag(cmd)); + + atomic_set(&T_TASK(cmd)->transport_lun_stop, 0); + } + if (!atomic_read(&T_TASK(cmd)->t_transport_active)) + goto remove; + + atomic_set(&T_TASK(cmd)->t_transport_stop, 1); + + DEBUG_TRANSPORT_S("wait_for_tasks: Stopping %p ITT: 0x%08x" + " i_state: %d, t_state/def_t_state: %d/%d, t_transport_stop" + " = TRUE\n", cmd, CMD_TFO(cmd)->get_task_tag(cmd), + CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state, + cmd->deferred_t_state); + + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + wake_up_interruptible(&SE_DEV(cmd)->dev_queue_obj->thread_wq); + + wait_for_completion(&T_TASK(cmd)->t_transport_stop_comp); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + atomic_set(&T_TASK(cmd)->t_transport_active, 0); + atomic_set(&T_TASK(cmd)->t_transport_stop, 0); + + DEBUG_TRANSPORT_S("wait_for_tasks: Stopped wait_for_compltion(" + "&T_TASK(cmd)->t_transport_stop_comp) for ITT: 0x%08x\n", + CMD_TFO(cmd)->get_task_tag(cmd)); +remove: + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + if (!remove_cmd) + return; + + transport_generic_free_cmd(cmd, 0, 0, session_reinstatement); +} + +static int transport_get_sense_codes( + struct se_cmd *cmd, + u8 *asc, + u8 *ascq) +{ + *asc = cmd->scsi_asc; + *ascq = cmd->scsi_ascq; + + return 0; +} + +static int transport_set_sense_codes( + struct se_cmd *cmd, + u8 asc, + u8 ascq) +{ + cmd->scsi_asc = asc; + cmd->scsi_ascq = ascq; + + return 0; +} + +int transport_send_check_condition_and_sense( + struct se_cmd *cmd, + u8 reason, + int from_transport) +{ + unsigned char *buffer = cmd->sense_buffer; + unsigned long flags; + int offset; + u8 asc = 0, ascq = 0; + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + return 0; + } + cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION; + spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags); + + if (!reason && from_transport) + goto after_reason; + + if (!from_transport) + cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; + /* + * Data Segment and SenseLength of the fabric response PDU. + * + * TRANSPORT_SENSE_BUFFER is now set to SCSI_SENSE_BUFFERSIZE + * from include/scsi/scsi_cmnd.h + */ + offset = CMD_TFO(cmd)->set_fabric_sense_len(cmd, + TRANSPORT_SENSE_BUFFER); + /* + * Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses + * SENSE KEY values from include/scsi/scsi.h + */ + switch (reason) { + case TCM_NON_EXISTENT_LUN: + case TCM_UNSUPPORTED_SCSI_OPCODE: + case TCM_SECTOR_COUNT_TOO_MANY: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + /* INVALID COMMAND OPERATION CODE */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20; + break; + case TCM_UNKNOWN_MODE_PAGE: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + /* INVALID FIELD IN CDB */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24; + break; + case TCM_CHECK_CONDITION_ABORT_CMD: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* BUS DEVICE RESET FUNCTION OCCURRED */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29; + buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03; + break; + case TCM_INCORRECT_AMOUNT_OF_DATA: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* WRITE ERROR */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c; + /* NOT ENOUGH UNSOLICITED DATA */ + buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d; + break; + case TCM_INVALID_CDB_FIELD: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* INVALID FIELD IN CDB */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24; + break; + case TCM_INVALID_PARAMETER_LIST: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* INVALID FIELD IN PARAMETER LIST */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26; + break; + case TCM_UNEXPECTED_UNSOLICITED_DATA: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* WRITE ERROR */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c; + /* UNEXPECTED_UNSOLICITED_DATA */ + buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c; + break; + case TCM_SERVICE_CRC_ERROR: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* PROTOCOL SERVICE CRC ERROR */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47; + /* N/A */ + buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05; + break; + case TCM_SNACK_REJECTED: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ABORTED COMMAND */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* READ ERROR */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11; + /* FAILED RETRANSMISSION REQUEST */ + buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13; + break; + case TCM_WRITE_PROTECTED: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* DATA PROTECT */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; + /* WRITE PROTECTED */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27; + break; + case TCM_CHECK_CONDITION_UNIT_ATTENTION: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* UNIT ATTENTION */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; + core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); + buffer[offset+SPC_ASC_KEY_OFFSET] = asc; + buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq; + break; + case TCM_CHECK_CONDITION_NOT_READY: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* Not Ready */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY; + transport_get_sense_codes(cmd, &asc, &ascq); + buffer[offset+SPC_ASC_KEY_OFFSET] = asc; + buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq; + break; + case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: + default: + /* CURRENT ERROR */ + buffer[offset] = 0x70; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; + /* LOGICAL UNIT COMMUNICATION FAILURE */ + buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80; + break; + } + /* + * This code uses linux/include/scsi/scsi.h SAM status codes! + */ + cmd->scsi_status = SAM_STAT_CHECK_CONDITION; + /* + * Automatically padded, this value is encoded in the fabric's + * data_length response PDU containing the SCSI defined sense data. + */ + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; + +after_reason: + CMD_TFO(cmd)->queue_status(cmd); + return 0; +} +EXPORT_SYMBOL(transport_send_check_condition_and_sense); + +int transport_check_aborted_status(struct se_cmd *cmd, int send_status) +{ + int ret = 0; + + if (atomic_read(&T_TASK(cmd)->t_transport_aborted) != 0) { + if (!(send_status) || + (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) + return 1; +#if 0 + printk(KERN_INFO "Sending delayed SAM_STAT_TASK_ABORTED" + " status for CDB: 0x%02x ITT: 0x%08x\n", + T_TASK(cmd)->t_task_cdb[0], + CMD_TFO(cmd)->get_task_tag(cmd)); +#endif + cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; + CMD_TFO(cmd)->queue_status(cmd); + ret = 1; + } + return ret; +} +EXPORT_SYMBOL(transport_check_aborted_status); + +void transport_send_task_abort(struct se_cmd *cmd) +{ + /* + * If there are still expected incoming fabric WRITEs, we wait + * until until they have completed before sending a TASK_ABORTED + * response. This response with TASK_ABORTED status will be + * queued back to fabric module by transport_check_aborted_status(). + */ + if (cmd->data_direction == DMA_TO_DEVICE) { + if (CMD_TFO(cmd)->write_pending_status(cmd) != 0) { + atomic_inc(&T_TASK(cmd)->t_transport_aborted); + smp_mb__after_atomic_inc(); + cmd->scsi_status = SAM_STAT_TASK_ABORTED; + transport_new_cmd_failure(cmd); + return; + } + } + cmd->scsi_status = SAM_STAT_TASK_ABORTED; +#if 0 + printk(KERN_INFO "Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," + " ITT: 0x%08x\n", T_TASK(cmd)->t_task_cdb[0], + CMD_TFO(cmd)->get_task_tag(cmd)); +#endif + CMD_TFO(cmd)->queue_status(cmd); +} + +/* transport_generic_do_tmr(): + * + * + */ +int transport_generic_do_tmr(struct se_cmd *cmd) +{ + struct se_cmd *ref_cmd; + struct se_device *dev = SE_DEV(cmd); + struct se_tmr_req *tmr = cmd->se_tmr_req; + int ret; + + switch (tmr->function) { + case ABORT_TASK: + ref_cmd = tmr->ref_cmd; + tmr->response = TMR_FUNCTION_REJECTED; + break; + case ABORT_TASK_SET: + case CLEAR_ACA: + case CLEAR_TASK_SET: + tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; + break; + case LUN_RESET: + ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); + tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : + TMR_FUNCTION_REJECTED; + break; +#if 0 + case TARGET_WARM_RESET: + transport_generic_host_reset(dev->se_hba); + tmr->response = TMR_FUNCTION_REJECTED; + break; + case TARGET_COLD_RESET: + transport_generic_host_reset(dev->se_hba); + transport_generic_cold_reset(dev->se_hba); + tmr->response = TMR_FUNCTION_REJECTED; + break; +#endif + default: + printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", + tmr->function); + tmr->response = TMR_FUNCTION_REJECTED; + break; + } + + cmd->t_state = TRANSPORT_ISTATE_PROCESSING; + CMD_TFO(cmd)->queue_tm_rsp(cmd); + + transport_cmd_check_stop(cmd, 2, 0); + return 0; +} + +/* + * Called with spin_lock_irq(&dev->execute_task_lock); held + * + */ +static struct se_task * +transport_get_task_from_state_list(struct se_device *dev) +{ + struct se_task *task; + + if (list_empty(&dev->state_task_list)) + return NULL; + + list_for_each_entry(task, &dev->state_task_list, t_state_list) + break; + + list_del(&task->t_state_list); + atomic_set(&task->task_state_active, 0); + + return task; +} + +static void transport_processing_shutdown(struct se_device *dev) +{ + struct se_cmd *cmd; + struct se_queue_req *qr; + struct se_task *task; + u8 state; + unsigned long flags; + /* + * Empty the struct se_device's struct se_task state list. + */ + spin_lock_irqsave(&dev->execute_task_lock, flags); + while ((task = transport_get_task_from_state_list(dev))) { + if (!(TASK_CMD(task))) { + printk(KERN_ERR "TASK_CMD(task) is NULL!\n"); + continue; + } + cmd = TASK_CMD(task); + + if (!T_TASK(cmd)) { + printk(KERN_ERR "T_TASK(cmd) is NULL for task: %p cmd:" + " %p ITT: 0x%08x\n", task, cmd, + CMD_TFO(cmd)->get_task_tag(cmd)); + continue; + } + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + + DEBUG_DO("PT: cmd: %p task: %p ITT/CmdSN: 0x%08x/0x%08x," + " i_state/def_i_state: %d/%d, t_state/def_t_state:" + " %d/%d cdb: 0x%02x\n", cmd, task, + CMD_TFO(cmd)->get_task_tag(cmd), cmd->cmd_sn, + CMD_TFO(cmd)->get_cmd_state(cmd), cmd->deferred_i_state, + cmd->t_state, cmd->deferred_t_state, + T_TASK(cmd)->t_task_cdb[0]); + DEBUG_DO("PT: ITT[0x%08x] - t_task_cdbs: %d t_task_cdbs_left:" + " %d t_task_cdbs_sent: %d -- t_transport_active: %d" + " t_transport_stop: %d t_transport_sent: %d\n", + CMD_TFO(cmd)->get_task_tag(cmd), + T_TASK(cmd)->t_task_cdbs, + atomic_read(&T_TASK(cmd)->t_task_cdbs_left), + atomic_read(&T_TASK(cmd)->t_task_cdbs_sent), + atomic_read(&T_TASK(cmd)->t_transport_active), + atomic_read(&T_TASK(cmd)->t_transport_stop), + atomic_read(&T_TASK(cmd)->t_transport_sent)); + + if (atomic_read(&task->task_active)) { + atomic_set(&task->task_stop, 1); + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + + DEBUG_DO("Waiting for task: %p to shutdown for dev:" + " %p\n", task, dev); + wait_for_completion(&task->task_stop_comp); + DEBUG_DO("Completed task: %p shutdown for dev: %p\n", + task, dev); + + spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags); + atomic_dec(&T_TASK(cmd)->t_task_cdbs_left); + + atomic_set(&task->task_active, 0); + atomic_set(&task->task_stop, 0); + } + __transport_stop_task_timer(task, &flags); + + if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_ex_left))) { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + + DEBUG_DO("Skipping task: %p, dev: %p for" + " t_task_cdbs_ex_left: %d\n", task, dev, + atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left)); + + spin_lock_irqsave(&dev->execute_task_lock, flags); + continue; + } + + if (atomic_read(&T_TASK(cmd)->t_transport_active)) { + DEBUG_DO("got t_transport_active = 1 for task: %p, dev:" + " %p\n", task, dev); + + if (atomic_read(&T_TASK(cmd)->t_fe_count)) { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + transport_send_check_condition_and_sense( + cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, + 0); + transport_remove_cmd_from_queue(cmd, + SE_DEV(cmd)->dev_queue_obj); + + transport_lun_remove_cmd(cmd); + transport_cmd_check_stop(cmd, 1, 0); + } else { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + + transport_remove_cmd_from_queue(cmd, + SE_DEV(cmd)->dev_queue_obj); + + transport_lun_remove_cmd(cmd); + + if (transport_cmd_check_stop(cmd, 1, 0)) + transport_generic_remove(cmd, 0, 0); + } + + spin_lock_irqsave(&dev->execute_task_lock, flags); + continue; + } + DEBUG_DO("Got t_transport_active = 0 for task: %p, dev: %p\n", + task, dev); + + if (atomic_read(&T_TASK(cmd)->t_fe_count)) { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + transport_send_check_condition_and_sense(cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); + transport_remove_cmd_from_queue(cmd, + SE_DEV(cmd)->dev_queue_obj); + + transport_lun_remove_cmd(cmd); + transport_cmd_check_stop(cmd, 1, 0); + } else { + spin_unlock_irqrestore( + &T_TASK(cmd)->t_state_lock, flags); + + transport_remove_cmd_from_queue(cmd, + SE_DEV(cmd)->dev_queue_obj); + transport_lun_remove_cmd(cmd); + + if (transport_cmd_check_stop(cmd, 1, 0)) + transport_generic_remove(cmd, 0, 0); + } + + spin_lock_irqsave(&dev->execute_task_lock, flags); + } + spin_unlock_irqrestore(&dev->execute_task_lock, flags); + /* + * Empty the struct se_device's struct se_cmd list. + */ + spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags); + while ((qr = __transport_get_qr_from_queue(dev->dev_queue_obj))) { + spin_unlock_irqrestore( + &dev->dev_queue_obj->cmd_queue_lock, flags); + cmd = (struct se_cmd *)qr->cmd; + state = qr->state; + kfree(qr); + + DEBUG_DO("From Device Queue: cmd: %p t_state: %d\n", + cmd, state); + + if (atomic_read(&T_TASK(cmd)->t_fe_count)) { + transport_send_check_condition_and_sense(cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); + + transport_lun_remove_cmd(cmd); + transport_cmd_check_stop(cmd, 1, 0); + } else { + transport_lun_remove_cmd(cmd); + if (transport_cmd_check_stop(cmd, 1, 0)) + transport_generic_remove(cmd, 0, 0); + } + spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags); + } + spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, flags); +} + +/* transport_processing_thread(): + * + * + */ +static int transport_processing_thread(void *param) +{ + int ret, t_state; + struct se_cmd *cmd; + struct se_device *dev = (struct se_device *) param; + struct se_queue_req *qr; + + set_user_nice(current, -20); + + while (!kthread_should_stop()) { + ret = wait_event_interruptible(dev->dev_queue_obj->thread_wq, + atomic_read(&dev->dev_queue_obj->queue_cnt) || + kthread_should_stop()); + if (ret < 0) + goto out; + + spin_lock_irq(&dev->dev_status_lock); + if (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) { + spin_unlock_irq(&dev->dev_status_lock); + transport_processing_shutdown(dev); + continue; + } + spin_unlock_irq(&dev->dev_status_lock); + +get_cmd: + __transport_execute_tasks(dev); + + qr = transport_get_qr_from_queue(dev->dev_queue_obj); + if (!(qr)) + continue; + + cmd = (struct se_cmd *)qr->cmd; + t_state = qr->state; + kfree(qr); + + switch (t_state) { + case TRANSPORT_NEW_CMD_MAP: + if (!(CMD_TFO(cmd)->new_cmd_map)) { + printk(KERN_ERR "CMD_TFO(cmd)->new_cmd_map is" + " NULL for TRANSPORT_NEW_CMD_MAP\n"); + BUG(); + } + ret = CMD_TFO(cmd)->new_cmd_map(cmd); + if (ret < 0) { + cmd->transport_error_status = ret; + transport_generic_request_failure(cmd, NULL, + 0, (cmd->data_direction != + DMA_TO_DEVICE)); + break; + } + /* Fall through */ + case TRANSPORT_NEW_CMD: + ret = transport_generic_new_cmd(cmd); + if (ret < 0) { + cmd->transport_error_status = ret; + transport_generic_request_failure(cmd, NULL, + 0, (cmd->data_direction != + DMA_TO_DEVICE)); + } + break; + case TRANSPORT_PROCESS_WRITE: + transport_generic_process_write(cmd); + break; + case TRANSPORT_COMPLETE_OK: + transport_stop_all_task_timers(cmd); + transport_generic_complete_ok(cmd); + break; + case TRANSPORT_REMOVE: + transport_generic_remove(cmd, 1, 0); + break; + case TRANSPORT_PROCESS_TMR: + transport_generic_do_tmr(cmd); + break; + case TRANSPORT_COMPLETE_FAILURE: + transport_generic_request_failure(cmd, NULL, 1, 1); + break; + case TRANSPORT_COMPLETE_TIMEOUT: + transport_stop_all_task_timers(cmd); + transport_generic_request_timeout(cmd); + break; + default: + printk(KERN_ERR "Unknown t_state: %d deferred_t_state:" + " %d for ITT: 0x%08x i_state: %d on SE LUN:" + " %u\n", t_state, cmd->deferred_t_state, + CMD_TFO(cmd)->get_task_tag(cmd), + CMD_TFO(cmd)->get_cmd_state(cmd), + SE_LUN(cmd)->unpacked_lun); + BUG(); + } + + goto get_cmd; + } + +out: + transport_release_all_cmds(dev); + dev->process_thread = NULL; + return 0; +} diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c new file mode 100644 index 000000000000..a2ef346087e8 --- /dev/null +++ b/drivers/target/target_core_ua.c @@ -0,0 +1,332 @@ +/******************************************************************************* + * Filename: target_core_ua.c + * + * This file contains logic for SPC-3 Unit Attention emulation + * + * Copyright (c) 2009,2010 Rising Tide Systems + * Copyright (c) 2009,2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 "target_core_alua.h" +#include "target_core_hba.h" +#include "target_core_pr.h" +#include "target_core_ua.h" + +int core_scsi3_ua_check( + struct se_cmd *cmd, + unsigned char *cdb) +{ + struct se_dev_entry *deve; + struct se_session *sess = cmd->se_sess; + struct se_node_acl *nacl; + + if (!(sess)) + return 0; + + nacl = sess->se_node_acl; + if (!(nacl)) + return 0; + + deve = &nacl->device_list[cmd->orig_fe_lun]; + if (!(atomic_read(&deve->ua_count))) + return 0; + /* + * From sam4r14, section 5.14 Unit attention condition: + * + * a) if an INQUIRY command enters the enabled command state, the + * device server shall process the INQUIRY command and shall neither + * report nor clear any unit attention condition; + * b) if a REPORT LUNS command enters the enabled command state, the + * device server shall process the REPORT LUNS command and shall not + * report any unit attention condition; + * e) if a REQUEST SENSE command enters the enabled command state while + * a unit attention condition exists for the SCSI initiator port + * associated with the I_T nexus on which the REQUEST SENSE command + * was received, then the device server shall process the command + * and either: + */ + switch (cdb[0]) { + case INQUIRY: + case REPORT_LUNS: + case REQUEST_SENSE: + return 0; + default: + return -1; + } + + return -1; +} + +int core_scsi3_ua_allocate( + struct se_node_acl *nacl, + u32 unpacked_lun, + u8 asc, + u8 ascq) +{ + struct se_dev_entry *deve; + struct se_ua *ua, *ua_p, *ua_tmp; + /* + * PASSTHROUGH OPS + */ + if (!(nacl)) + return -1; + + ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC); + if (!(ua)) { + printk(KERN_ERR "Unable to allocate struct se_ua\n"); + return -1; + } + INIT_LIST_HEAD(&ua->ua_dev_list); + INIT_LIST_HEAD(&ua->ua_nacl_list); + + ua->ua_nacl = nacl; + ua->ua_asc = asc; + ua->ua_ascq = ascq; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[unpacked_lun]; + + spin_lock(&deve->ua_lock); + list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) { + /* + * Do not report the same UNIT ATTENTION twice.. + */ + if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) { + spin_unlock(&deve->ua_lock); + spin_unlock_irq(&nacl->device_list_lock); + kmem_cache_free(se_ua_cache, ua); + return 0; + } + /* + * Attach the highest priority Unit Attention to + * the head of the list following sam4r14, + * Section 5.14 Unit Attention Condition: + * + * POWER ON, RESET, OR BUS DEVICE RESET OCCURRED highest + * POWER ON OCCURRED or + * DEVICE INTERNAL RESET + * SCSI BUS RESET OCCURRED or + * MICROCODE HAS BEEN CHANGED or + * protocol specific + * BUS DEVICE RESET FUNCTION OCCURRED + * I_T NEXUS LOSS OCCURRED + * COMMANDS CLEARED BY POWER LOSS NOTIFICATION + * all others Lowest + * + * Each of the ASCQ codes listed above are defined in + * the 29h ASC family, see spc4r17 Table D.1 + */ + if (ua_p->ua_asc == 0x29) { + if ((asc == 0x29) && (ascq > ua_p->ua_ascq)) + list_add(&ua->ua_nacl_list, + &deve->ua_list); + else + list_add_tail(&ua->ua_nacl_list, + &deve->ua_list); + } else if (ua_p->ua_asc == 0x2a) { + /* + * Incoming Family 29h ASCQ codes will override + * Family 2AHh ASCQ codes for Unit Attention condition. + */ + if ((asc == 0x29) || (ascq > ua_p->ua_asc)) + list_add(&ua->ua_nacl_list, + &deve->ua_list); + else + list_add_tail(&ua->ua_nacl_list, + &deve->ua_list); + } else + list_add_tail(&ua->ua_nacl_list, + &deve->ua_list); + spin_unlock(&deve->ua_lock); + spin_unlock_irq(&nacl->device_list_lock); + + atomic_inc(&deve->ua_count); + smp_mb__after_atomic_inc(); + return 0; + } + list_add_tail(&ua->ua_nacl_list, &deve->ua_list); + spin_unlock(&deve->ua_lock); + spin_unlock_irq(&nacl->device_list_lock); + + printk(KERN_INFO "[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:" + " 0x%02x, ASCQ: 0x%02x\n", + TPG_TFO(nacl->se_tpg)->get_fabric_name(), unpacked_lun, + asc, ascq); + + atomic_inc(&deve->ua_count); + smp_mb__after_atomic_inc(); + return 0; +} + +void core_scsi3_ua_release_all( + struct se_dev_entry *deve) +{ + struct se_ua *ua, *ua_p; + + spin_lock(&deve->ua_lock); + list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { + list_del(&ua->ua_nacl_list); + kmem_cache_free(se_ua_cache, ua); + + atomic_dec(&deve->ua_count); + smp_mb__after_atomic_dec(); + } + spin_unlock(&deve->ua_lock); +} + +void core_scsi3_ua_for_check_condition( + struct se_cmd *cmd, + u8 *asc, + u8 *ascq) +{ + struct se_device *dev = SE_DEV(cmd); + struct se_dev_entry *deve; + struct se_session *sess = cmd->se_sess; + struct se_node_acl *nacl; + struct se_ua *ua = NULL, *ua_p; + int head = 1; + + if (!(sess)) + return; + + nacl = sess->se_node_acl; + if (!(nacl)) + return; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[cmd->orig_fe_lun]; + if (!(atomic_read(&deve->ua_count))) { + spin_unlock_irq(&nacl->device_list_lock); + return; + } + /* + * The highest priority Unit Attentions are placed at the head of the + * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION + + * sense data for the received CDB. + */ + spin_lock(&deve->ua_lock); + list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { + /* + * For ua_intlck_ctrl code not equal to 00b, only report the + * highest priority UNIT_ATTENTION and ASC/ASCQ without + * clearing it. + */ + if (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl != 0) { + *asc = ua->ua_asc; + *ascq = ua->ua_ascq; + break; + } + /* + * Otherwise for the default 00b, release the UNIT ATTENTION + * condition. Return the ASC/ASCQ of the higest priority UA + * (head of the list) in the outgoing CHECK_CONDITION + sense. + */ + if (head) { + *asc = ua->ua_asc; + *ascq = ua->ua_ascq; + head = 0; + } + list_del(&ua->ua_nacl_list); + kmem_cache_free(se_ua_cache, ua); + + atomic_dec(&deve->ua_count); + smp_mb__after_atomic_dec(); + } + spin_unlock(&deve->ua_lock); + spin_unlock_irq(&nacl->device_list_lock); + + printk(KERN_INFO "[%s]: %s UNIT ATTENTION condition with" + " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x" + " reported ASC: 0x%02x, ASCQ: 0x%02x\n", + TPG_TFO(nacl->se_tpg)->get_fabric_name(), + (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl != 0) ? "Reporting" : + "Releasing", DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl, + cmd->orig_fe_lun, T_TASK(cmd)->t_task_cdb[0], *asc, *ascq); +} + +int core_scsi3_ua_clear_for_request_sense( + struct se_cmd *cmd, + u8 *asc, + u8 *ascq) +{ + struct se_dev_entry *deve; + struct se_session *sess = cmd->se_sess; + struct se_node_acl *nacl; + struct se_ua *ua = NULL, *ua_p; + int head = 1; + + if (!(sess)) + return -1; + + nacl = sess->se_node_acl; + if (!(nacl)) + return -1; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[cmd->orig_fe_lun]; + if (!(atomic_read(&deve->ua_count))) { + spin_unlock_irq(&nacl->device_list_lock); + return -1; + } + /* + * The highest priority Unit Attentions are placed at the head of the + * struct se_dev_entry->ua_list. The First (and hence highest priority) + * ASC/ASCQ will be returned in REQUEST_SENSE payload data for the + * matching struct se_lun. + * + * Once the returning ASC/ASCQ values are set, we go ahead and + * release all of the Unit Attention conditions for the assoicated + * struct se_lun. + */ + spin_lock(&deve->ua_lock); + list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) { + if (head) { + *asc = ua->ua_asc; + *ascq = ua->ua_ascq; + head = 0; + } + list_del(&ua->ua_nacl_list); + kmem_cache_free(se_ua_cache, ua); + + atomic_dec(&deve->ua_count); + smp_mb__after_atomic_dec(); + } + spin_unlock(&deve->ua_lock); + spin_unlock_irq(&nacl->device_list_lock); + + printk(KERN_INFO "[%s]: Released UNIT ATTENTION condition, mapped" + " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x," + " ASCQ: 0x%02x\n", TPG_TFO(nacl->se_tpg)->get_fabric_name(), + cmd->orig_fe_lun, *asc, *ascq); + + return (head) ? -1 : 0; +} diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h new file mode 100644 index 000000000000..6e6b03460a1a --- /dev/null +++ b/drivers/target/target_core_ua.h @@ -0,0 +1,36 @@ +#ifndef TARGET_CORE_UA_H + +/* + * From spc4r17, Table D.1: ASC and ASCQ Assignement + */ +#define ASCQ_29H_POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURED 0x00 +#define ASCQ_29H_POWER_ON_OCCURRED 0x01 +#define ASCQ_29H_SCSI_BUS_RESET_OCCURED 0x02 +#define ASCQ_29H_BUS_DEVICE_RESET_FUNCTION_OCCURRED 0x03 +#define ASCQ_29H_DEVICE_INTERNAL_RESET 0x04 +#define ASCQ_29H_TRANSCEIVER_MODE_CHANGED_TO_SINGLE_ENDED 0x05 +#define ASCQ_29H_TRANSCEIVER_MODE_CHANGED_TO_LVD 0x06 +#define ASCQ_29H_NEXUS_LOSS_OCCURRED 0x07 + +#define ASCQ_2AH_PARAMETERS_CHANGED 0x00 +#define ASCQ_2AH_MODE_PARAMETERS_CHANGED 0x01 +#define ASCQ_2AH_LOG_PARAMETERS_CHANGED 0x02 +#define ASCQ_2AH_RESERVATIONS_PREEMPTED 0x03 +#define ASCQ_2AH_RESERVATIONS_RELEASED 0x04 +#define ASCQ_2AH_REGISTRATIONS_PREEMPTED 0x05 +#define ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06 +#define ASCQ_2AH_IMPLICT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED 0x07 +#define ASCQ_2AH_PRIORITY_CHANGED 0x08 + +#define ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS 0x09 + +extern struct kmem_cache *se_ua_cache; + +extern int core_scsi3_ua_check(struct se_cmd *, unsigned char *); +extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8); +extern void core_scsi3_ua_release_all(struct se_dev_entry *); +extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); +extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *, + u8 *, u8 *); + +#endif /* TARGET_CORE_UA_H */ diff --git a/include/target/configfs_macros.h b/include/target/configfs_macros.h new file mode 100644 index 000000000000..7fe74608b437 --- /dev/null +++ b/include/target/configfs_macros.h @@ -0,0 +1,147 @@ +/* -*- mode: c; c-basic-offset: 8; -*- + * vim: noexpandtab sw=8 ts=8 sts=0: + * + * configfs_macros.h - extends macros for configfs + * + * 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 021110-1307, USA. + * + * Based on sysfs: + * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel + * + * Based on kobject.h: + * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2002-2003 Open Source Development Labs + * + * configfs Copyright (C) 2005 Oracle. All rights reserved. + * + * Added CONFIGFS_EATTR() macros from original configfs.h macros + * Copright (C) 2008-2009 Nicholas A. Bellinger + * + * Please read Documentation/filesystems/configfs.txt before using the + * configfs interface, ESPECIALLY the parts about reference counts and + * item destructors. + */ + +#ifndef _CONFIGFS_MACROS_H_ +#define _CONFIGFS_MACROS_H_ + +#include + +/* + * Users often need to create attribute structures for their configurable + * attributes, containing a configfs_attribute member and function pointers + * for the show() and store() operations on that attribute. If they don't + * need anything else on the extended attribute structure, they can use + * this macro to define it. The argument _name isends up as + * 'struct _name_attribute, as well as names of to CONFIGFS_ATTR_OPS() below. + * The argument _item is the name of the structure containing the + * struct config_item or struct config_group structure members + */ +#define CONFIGFS_EATTR_STRUCT(_name, _item) \ +struct _name##_attribute { \ + struct configfs_attribute attr; \ + ssize_t (*show)(struct _item *, char *); \ + ssize_t (*store)(struct _item *, const char *, size_t); \ +} + +/* + * With the extended attribute structure, users can use this macro + * (similar to sysfs' __ATTR) to make defining attributes easier. + * An example: + * #define MYITEM_EATTR(_name, _mode, _show, _store) \ + * struct myitem_attribute childless_attr_##_name = \ + * __CONFIGFS_EATTR(_name, _mode, _show, _store) + */ +#define __CONFIGFS_EATTR(_name, _mode, _show, _store) \ +{ \ + .attr = { \ + .ca_name = __stringify(_name), \ + .ca_mode = _mode, \ + .ca_owner = THIS_MODULE, \ + }, \ + .show = _show, \ + .store = _store, \ +} +/* Here is a readonly version, only requiring a show() operation */ +#define __CONFIGFS_EATTR_RO(_name, _show) \ +{ \ + .attr = { \ + .ca_name = __stringify(_name), \ + .ca_mode = 0444, \ + .ca_owner = THIS_MODULE, \ + }, \ + .show = _show, \ +} + +/* + * With these extended attributes, the simple show_attribute() and + * store_attribute() operations need to call the show() and store() of the + * attributes. This is a common pattern, so we provide a macro to define + * them. The argument _name is the name of the attribute defined by + * CONFIGFS_ATTR_STRUCT(). The argument _item is the name of the structure + * containing the struct config_item or struct config_group structure member. + * The argument _item_member is the actual name of the struct config_* struct + * in your _item structure. Meaning my_structure->some_config_group. + * ^^_item^^^^^ ^^_item_member^^^ + * This macro expects the attributes to be named "struct _attribute". + */ +#define CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member) \ +static struct _item *to_##_name(struct config_item *ci) \ +{ \ + return (ci) ? container_of(to_config_group(ci), struct _item, \ + _item_member) : NULL; \ +} + +#define CONFIGFS_EATTR_OPS_SHOW(_name, _item) \ +static ssize_t _name##_attr_show(struct config_item *item, \ + struct configfs_attribute *attr, \ + char *page) \ +{ \ + struct _item *_item = to_##_name(item); \ + struct _name##_attribute * _name##_attr = \ + container_of(attr, struct _name##_attribute, attr); \ + ssize_t ret = 0; \ + \ + if (_name##_attr->show) \ + ret = _name##_attr->show(_item, page); \ + return ret; \ +} + +#define CONFIGFS_EATTR_OPS_STORE(_name, _item) \ +static ssize_t _name##_attr_store(struct config_item *item, \ + struct configfs_attribute *attr, \ + const char *page, size_t count) \ +{ \ + struct _item *_item = to_##_name(item); \ + struct _name##_attribute * _name##_attr = \ + container_of(attr, struct _name##_attribute, attr); \ + ssize_t ret = -EINVAL; \ + \ + if (_name##_attr->store) \ + ret = _name##_attr->store(_item, page, count); \ + return ret; \ +} + +#define CONFIGFS_EATTR_OPS(_name, _item, _item_member) \ + CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member); \ + CONFIGFS_EATTR_OPS_SHOW(_name, _item); \ + CONFIGFS_EATTR_OPS_STORE(_name, _item); + +#define CONFIGFS_EATTR_OPS_RO(_name, _item, _item_member) \ + CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member); \ + CONFIGFS_EATTR_OPS_SHOW(_name, _item); + +#endif /* _CONFIGFS_MACROS_H_ */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h new file mode 100644 index 000000000000..07fdfb6b9a9a --- /dev/null +++ b/include/target/target_core_base.h @@ -0,0 +1,937 @@ +#ifndef TARGET_CORE_BASE_H +#define TARGET_CORE_BASE_H + +#include +#include +#include +#include +#include +#include +#include +#include "target_core_mib.h" + +#define TARGET_CORE_MOD_VERSION "v4.0.0-rc6" +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT)) + +/* Used by transport_generic_allocate_iovecs() */ +#define TRANSPORT_IOV_DATA_BUFFER 5 +/* Maximum Number of LUNs per Target Portal Group */ +#define TRANSPORT_MAX_LUNS_PER_TPG 256 +/* + * By default we use 32-byte CDBs in TCM Core and subsystem plugin code. + * + * Note that both include/scsi/scsi_cmnd.h:MAX_COMMAND_SIZE and + * include/linux/blkdev.h:BLOCK_MAX_CDB as of v2.6.36-rc4 still use + * 16-byte CDBs by default and require an extra allocation for + * 32-byte CDBs to becasue of legacy issues. + * + * Within TCM Core there are no such legacy limitiations, so we go ahead + * use 32-byte CDBs by default and use include/scsi/scsi.h:scsi_command_size() + * within all TCM Core and subsystem plugin code. + */ +#define TCM_MAX_COMMAND_SIZE 32 +/* + * From include/scsi/scsi_cmnd.h:SCSI_SENSE_BUFFERSIZE, currently + * defined 96, but the real limit is 252 (or 260 including the header) + */ +#define TRANSPORT_SENSE_BUFFER SCSI_SENSE_BUFFERSIZE +/* Used by transport_send_check_condition_and_sense() */ +#define SPC_SENSE_KEY_OFFSET 2 +#define SPC_ASC_KEY_OFFSET 12 +#define SPC_ASCQ_KEY_OFFSET 13 +#define TRANSPORT_IQN_LEN 224 +/* Used by target_core_store_alua_lu_gp() and target_core_alua_lu_gp_show_attr_members() */ +#define LU_GROUP_NAME_BUF 256 +/* Used by core_alua_store_tg_pt_gp_info() and target_core_alua_tg_pt_gp_show_attr_members() */ +#define TG_PT_GROUP_NAME_BUF 256 +/* Used to parse VPD into struct t10_vpd */ +#define VPD_TMP_BUF_SIZE 128 +/* Used by transport_generic_cmd_sequencer() */ +#define READ_BLOCK_LEN 6 +#define READ_CAP_LEN 8 +#define READ_POSITION_LEN 20 +#define INQUIRY_LEN 36 +/* Used by transport_get_inquiry_vpd_serial() */ +#define INQUIRY_VPD_SERIAL_LEN 254 +/* Used by transport_get_inquiry_vpd_device_ident() */ +#define INQUIRY_VPD_DEVICE_IDENTIFIER_LEN 254 + +/* struct se_hba->hba_flags */ +enum hba_flags_table { + HBA_FLAGS_INTERNAL_USE = 0x01, + HBA_FLAGS_PSCSI_MODE = 0x02, +}; + +/* struct se_lun->lun_status */ +enum transport_lun_status_table { + TRANSPORT_LUN_STATUS_FREE = 0, + TRANSPORT_LUN_STATUS_ACTIVE = 1, +}; + +/* struct se_portal_group->se_tpg_type */ +enum transport_tpg_type_table { + TRANSPORT_TPG_TYPE_NORMAL = 0, + TRANSPORT_TPG_TYPE_DISCOVERY = 1, +}; + +/* Used for generate timer flags */ +enum timer_flags_table { + TF_RUNNING = 0x01, + TF_STOP = 0x02, +}; + +/* Special transport agnostic struct se_cmd->t_states */ +enum transport_state_table { + TRANSPORT_NO_STATE = 0, + TRANSPORT_NEW_CMD = 1, + TRANSPORT_DEFERRED_CMD = 2, + TRANSPORT_WRITE_PENDING = 3, + TRANSPORT_PROCESS_WRITE = 4, + TRANSPORT_PROCESSING = 5, + TRANSPORT_COMPLETE_OK = 6, + TRANSPORT_COMPLETE_FAILURE = 7, + TRANSPORT_COMPLETE_TIMEOUT = 8, + TRANSPORT_PROCESS_TMR = 9, + TRANSPORT_TMR_COMPLETE = 10, + TRANSPORT_ISTATE_PROCESSING = 11, + TRANSPORT_ISTATE_PROCESSED = 12, + TRANSPORT_KILL = 13, + TRANSPORT_REMOVE = 14, + TRANSPORT_FREE = 15, + TRANSPORT_NEW_CMD_MAP = 16, +}; + +/* Used for struct se_cmd->se_cmd_flags */ +enum se_cmd_flags_table { + SCF_SUPPORTED_SAM_OPCODE = 0x00000001, + SCF_TRANSPORT_TASK_SENSE = 0x00000002, + SCF_EMULATED_TASK_SENSE = 0x00000004, + SCF_SCSI_DATA_SG_IO_CDB = 0x00000008, + SCF_SCSI_CONTROL_SG_IO_CDB = 0x00000010, + SCF_SCSI_CONTROL_NONSG_IO_CDB = 0x00000020, + SCF_SCSI_NON_DATA_CDB = 0x00000040, + SCF_SCSI_CDB_EXCEPTION = 0x00000080, + SCF_SCSI_RESERVATION_CONFLICT = 0x00000100, + SCF_CMD_PASSTHROUGH_NOALLOC = 0x00000200, + SCF_SE_CMD_FAILED = 0x00000400, + SCF_SE_LUN_CMD = 0x00000800, + SCF_SE_ALLOW_EOO = 0x00001000, + SCF_SE_DISABLE_ONLINE_CHECK = 0x00002000, + SCF_SENT_CHECK_CONDITION = 0x00004000, + SCF_OVERFLOW_BIT = 0x00008000, + SCF_UNDERFLOW_BIT = 0x00010000, + SCF_SENT_DELAYED_TAS = 0x00020000, + SCF_ALUA_NON_OPTIMIZED = 0x00040000, + SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00080000, + SCF_PASSTHROUGH_SG_TO_MEM = 0x00100000, + SCF_PASSTHROUGH_CONTIG_TO_SG = 0x00200000, + SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000, + SCF_EMULATE_SYNC_CACHE = 0x00800000, + SCF_EMULATE_CDB_ASYNC = 0x01000000, + SCF_EMULATE_SYNC_UNMAP = 0x02000000 +}; + +/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ +enum transport_lunflags_table { + TRANSPORT_LUNFLAGS_NO_ACCESS = 0x00, + TRANSPORT_LUNFLAGS_INITIATOR_ACCESS = 0x01, + TRANSPORT_LUNFLAGS_READ_ONLY = 0x02, + TRANSPORT_LUNFLAGS_READ_WRITE = 0x04, +}; + +/* struct se_device->dev_status */ +enum transport_device_status_table { + TRANSPORT_DEVICE_ACTIVATED = 0x01, + TRANSPORT_DEVICE_DEACTIVATED = 0x02, + TRANSPORT_DEVICE_QUEUE_FULL = 0x04, + TRANSPORT_DEVICE_SHUTDOWN = 0x08, + TRANSPORT_DEVICE_OFFLINE_ACTIVATED = 0x10, + TRANSPORT_DEVICE_OFFLINE_DEACTIVATED = 0x20, +}; + +/* + * Used by transport_send_check_condition_and_sense() and se_cmd->scsi_sense_reason + * to signal which ASC/ASCQ sense payload should be built. + */ +enum tcm_sense_reason_table { + TCM_NON_EXISTENT_LUN = 0x01, + TCM_UNSUPPORTED_SCSI_OPCODE = 0x02, + TCM_INCORRECT_AMOUNT_OF_DATA = 0x03, + TCM_UNEXPECTED_UNSOLICITED_DATA = 0x04, + TCM_SERVICE_CRC_ERROR = 0x05, + TCM_SNACK_REJECTED = 0x06, + TCM_SECTOR_COUNT_TOO_MANY = 0x07, + TCM_INVALID_CDB_FIELD = 0x08, + TCM_INVALID_PARAMETER_LIST = 0x09, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE = 0x0a, + TCM_UNKNOWN_MODE_PAGE = 0x0b, + TCM_WRITE_PROTECTED = 0x0c, + TCM_CHECK_CONDITION_ABORT_CMD = 0x0d, + TCM_CHECK_CONDITION_UNIT_ATTENTION = 0x0e, + TCM_CHECK_CONDITION_NOT_READY = 0x0f, +}; + +struct se_obj { + atomic_t obj_access_count; +} ____cacheline_aligned; + +/* + * Used by TCM Core internally to signal if ALUA emulation is enabled or + * disabled, or running in with TCM/pSCSI passthrough mode + */ +typedef enum { + SPC_ALUA_PASSTHROUGH, + SPC2_ALUA_DISABLED, + SPC3_ALUA_EMULATED +} t10_alua_index_t; + +/* + * Used by TCM Core internally to signal if SAM Task Attribute emulation + * is enabled or disabled, or running in with TCM/pSCSI passthrough mode + */ +typedef enum { + SAM_TASK_ATTR_PASSTHROUGH, + SAM_TASK_ATTR_UNTAGGED, + SAM_TASK_ATTR_EMULATED +} t10_task_attr_index_t; + +struct se_cmd; + +struct t10_alua { + t10_alua_index_t alua_type; + /* ALUA Target Port Group ID */ + u16 alua_tg_pt_gps_counter; + u32 alua_tg_pt_gps_count; + spinlock_t tg_pt_gps_lock; + struct se_subsystem_dev *t10_sub_dev; + /* Used for default ALUA Target Port Group */ + struct t10_alua_tg_pt_gp *default_tg_pt_gp; + /* Used for default ALUA Target Port Group ConfigFS group */ + struct config_group alua_tg_pt_gps_group; + int (*alua_state_check)(struct se_cmd *, unsigned char *, u8 *); + struct list_head tg_pt_gps_list; +} ____cacheline_aligned; + +struct t10_alua_lu_gp { + u16 lu_gp_id; + int lu_gp_valid_id; + u32 lu_gp_members; + atomic_t lu_gp_shutdown; + atomic_t lu_gp_ref_cnt; + spinlock_t lu_gp_lock; + struct config_group lu_gp_group; + struct list_head lu_gp_list; + struct list_head lu_gp_mem_list; +} ____cacheline_aligned; + +struct t10_alua_lu_gp_member { + int lu_gp_assoc:1; + atomic_t lu_gp_mem_ref_cnt; + spinlock_t lu_gp_mem_lock; + struct t10_alua_lu_gp *lu_gp; + struct se_device *lu_gp_mem_dev; + struct list_head lu_gp_mem_list; +} ____cacheline_aligned; + +struct t10_alua_tg_pt_gp { + u16 tg_pt_gp_id; + int tg_pt_gp_valid_id; + int tg_pt_gp_alua_access_status; + int tg_pt_gp_alua_access_type; + int tg_pt_gp_nonop_delay_msecs; + int tg_pt_gp_trans_delay_msecs; + int tg_pt_gp_pref; + int tg_pt_gp_write_metadata; + /* Used by struct t10_alua_tg_pt_gp->tg_pt_gp_md_buf_len */ +#define ALUA_MD_BUF_LEN 1024 + u32 tg_pt_gp_md_buf_len; + u32 tg_pt_gp_members; + atomic_t tg_pt_gp_alua_access_state; + atomic_t tg_pt_gp_ref_cnt; + spinlock_t tg_pt_gp_lock; + struct mutex tg_pt_gp_md_mutex; + struct se_subsystem_dev *tg_pt_gp_su_dev; + struct config_group tg_pt_gp_group; + struct list_head tg_pt_gp_list; + struct list_head tg_pt_gp_mem_list; +} ____cacheline_aligned; + +struct t10_alua_tg_pt_gp_member { + int tg_pt_gp_assoc:1; + atomic_t tg_pt_gp_mem_ref_cnt; + spinlock_t tg_pt_gp_mem_lock; + struct t10_alua_tg_pt_gp *tg_pt_gp; + struct se_port *tg_pt; + struct list_head tg_pt_gp_mem_list; +} ____cacheline_aligned; + +struct t10_vpd { + unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN]; + int protocol_identifier_set; + u32 protocol_identifier; + u32 device_identifier_code_set; + u32 association; + u32 device_identifier_type; + struct list_head vpd_list; +} ____cacheline_aligned; + +struct t10_wwn { + unsigned char vendor[8]; + unsigned char model[16]; + unsigned char revision[4]; + unsigned char unit_serial[INQUIRY_VPD_SERIAL_LEN]; + spinlock_t t10_vpd_lock; + struct se_subsystem_dev *t10_sub_dev; + struct config_group t10_wwn_group; + struct list_head t10_vpd_list; +} ____cacheline_aligned; + + +/* + * Used by TCM Core internally to signal if >= SPC-3 peristent reservations + * emulation is enabled or disabled, or running in with TCM/pSCSI passthrough + * mode + */ +typedef enum { + SPC_PASSTHROUGH, + SPC2_RESERVATIONS, + SPC3_PERSISTENT_RESERVATIONS +} t10_reservations_index_t; + +struct t10_pr_registration { + /* Used for fabrics that contain WWN+ISID */ +#define PR_REG_ISID_LEN 16 + /* PR_REG_ISID_LEN + ',i,0x' */ +#define PR_REG_ISID_ID_LEN (PR_REG_ISID_LEN + 5) + char pr_reg_isid[PR_REG_ISID_LEN]; + /* Used during APTPL metadata reading */ +#define PR_APTPL_MAX_IPORT_LEN 256 + unsigned char pr_iport[PR_APTPL_MAX_IPORT_LEN]; + /* Used during APTPL metadata reading */ +#define PR_APTPL_MAX_TPORT_LEN 256 + unsigned char pr_tport[PR_APTPL_MAX_TPORT_LEN]; + /* For writing out live meta data */ + unsigned char *pr_aptpl_buf; + u16 pr_aptpl_rpti; + u16 pr_reg_tpgt; + /* Reservation effects all target ports */ + int pr_reg_all_tg_pt; + /* Activate Persistence across Target Power Loss */ + int pr_reg_aptpl; + int pr_res_holder; + int pr_res_type; + int pr_res_scope; + /* Used for fabric initiator WWPNs using a ISID */ + int isid_present_at_reg:1; + u32 pr_res_mapped_lun; + u32 pr_aptpl_target_lun; + u32 pr_res_generation; + u64 pr_reg_bin_isid; + u64 pr_res_key; + atomic_t pr_res_holders; + struct se_node_acl *pr_reg_nacl; + struct se_dev_entry *pr_reg_deve; + struct se_lun *pr_reg_tg_pt_lun; + struct list_head pr_reg_list; + struct list_head pr_reg_abort_list; + struct list_head pr_reg_aptpl_list; + struct list_head pr_reg_atp_list; + struct list_head pr_reg_atp_mem_list; +} ____cacheline_aligned; + +/* + * This set of function pointer ops is set based upon SPC3_PERSISTENT_RESERVATIONS, + * SPC2_RESERVATIONS or SPC_PASSTHROUGH in drivers/target/target_core_pr.c: + * core_setup_reservations() + */ +struct t10_reservation_ops { + int (*t10_reservation_check)(struct se_cmd *, u32 *); + int (*t10_seq_non_holder)(struct se_cmd *, unsigned char *, u32); + int (*t10_pr_register)(struct se_cmd *); + int (*t10_pr_clear)(struct se_cmd *); +}; + +struct t10_reservation_template { + /* Reservation effects all target ports */ + int pr_all_tg_pt; + /* Activate Persistence across Target Power Loss enabled + * for SCSI device */ + int pr_aptpl_active; + /* Used by struct t10_reservation_template->pr_aptpl_buf_len */ +#define PR_APTPL_BUF_LEN 8192 + u32 pr_aptpl_buf_len; + u32 pr_generation; + t10_reservations_index_t res_type; + spinlock_t registration_lock; + spinlock_t aptpl_reg_lock; + /* + * This will always be set by one individual I_T Nexus. + * However with all_tg_pt=1, other I_T Nexus from the + * same initiator can access PR reg/res info on a different + * target port. + * + * There is also the 'All Registrants' case, where there is + * a single *pr_res_holder of the reservation, but all + * registrations are considered reservation holders. + */ + struct se_node_acl *pr_res_holder; + struct list_head registration_list; + struct list_head aptpl_reg_list; + struct t10_reservation_ops pr_ops; +} ____cacheline_aligned; + +struct se_queue_req { + int state; + void *cmd; + struct list_head qr_list; +} ____cacheline_aligned; + +struct se_queue_obj { + atomic_t queue_cnt; + spinlock_t cmd_queue_lock; + struct list_head qobj_list; + wait_queue_head_t thread_wq; +} ____cacheline_aligned; + +/* + * Used one per struct se_cmd to hold all extra struct se_task + * metadata. This structure is setup and allocated in + * drivers/target/target_core_transport.c:__transport_alloc_se_cmd() + */ +struct se_transport_task { + unsigned char *t_task_cdb; + unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE]; + unsigned long long t_task_lba; + int t_tasks_failed; + int t_tasks_fua; + int t_tasks_bidi:1; + u32 t_task_cdbs; + u32 t_tasks_check; + u32 t_tasks_no; + u32 t_tasks_sectors; + u32 t_tasks_se_num; + u32 t_tasks_se_bidi_num; + u32 t_tasks_sg_chained_no; + atomic_t t_fe_count; + atomic_t t_se_count; + atomic_t t_task_cdbs_left; + atomic_t t_task_cdbs_ex_left; + atomic_t t_task_cdbs_timeout_left; + atomic_t t_task_cdbs_sent; + atomic_t t_transport_aborted; + atomic_t t_transport_active; + atomic_t t_transport_complete; + atomic_t t_transport_queue_active; + atomic_t t_transport_sent; + atomic_t t_transport_stop; + atomic_t t_transport_timeout; + atomic_t transport_dev_active; + atomic_t transport_lun_active; + atomic_t transport_lun_fe_stop; + atomic_t transport_lun_stop; + spinlock_t t_state_lock; + struct completion t_transport_stop_comp; + struct completion transport_lun_fe_stop_comp; + struct completion transport_lun_stop_comp; + struct scatterlist *t_tasks_sg_chained; + struct scatterlist t_tasks_sg_bounce; + void *t_task_buf; + /* + * Used for pre-registered fabric SGL passthrough WRITE and READ + * with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop + * and other HW target mode fabric modules. + */ + struct scatterlist *t_task_pt_sgl; + struct list_head *t_mem_list; + /* Used for BIDI READ */ + struct list_head *t_mem_bidi_list; + struct list_head t_task_list; +} ____cacheline_aligned; + +struct se_task { + unsigned char task_sense; + struct scatterlist *task_sg; + struct scatterlist *task_sg_bidi; + u8 task_scsi_status; + u8 task_flags; + int task_error_status; + int task_state_flags; + int task_padded_sg:1; + unsigned long long task_lba; + u32 task_no; + u32 task_sectors; + u32 task_size; + u32 task_sg_num; + u32 task_sg_offset; + enum dma_data_direction task_data_direction; + struct se_cmd *task_se_cmd; + struct se_device *se_dev; + struct completion task_stop_comp; + atomic_t task_active; + atomic_t task_execute_queue; + atomic_t task_timeout; + atomic_t task_sent; + atomic_t task_stop; + atomic_t task_state_active; + struct timer_list task_timer; + struct se_device *se_obj_ptr; + struct list_head t_list; + struct list_head t_execute_list; + struct list_head t_state_list; +} ____cacheline_aligned; + +#define TASK_CMD(task) ((struct se_cmd *)task->task_se_cmd) +#define TASK_DEV(task) ((struct se_device *)task->se_dev) + +struct se_cmd { + /* SAM response code being sent to initiator */ + u8 scsi_status; + u8 scsi_asc; + u8 scsi_ascq; + u8 scsi_sense_reason; + u16 scsi_sense_length; + /* Delay for ALUA Active/NonOptimized state access in milliseconds */ + int alua_nonop_delay; + /* See include/linux/dma-mapping.h */ + enum dma_data_direction data_direction; + /* For SAM Task Attribute */ + int sam_task_attr; + /* Transport protocol dependent state, see transport_state_table */ + enum transport_state_table t_state; + /* Transport protocol dependent state for out of order CmdSNs */ + int deferred_t_state; + /* Transport specific error status */ + int transport_error_status; + /* See se_cmd_flags_table */ + u32 se_cmd_flags; + u32 se_ordered_id; + /* Total size in bytes associated with command */ + u32 data_length; + /* SCSI Presented Data Transfer Length */ + u32 cmd_spdtl; + u32 residual_count; + u32 orig_fe_lun; + /* Persistent Reservation key */ + u64 pr_res_key; + atomic_t transport_sent; + /* Used for sense data */ + void *sense_buffer; + struct list_head se_delayed_list; + struct list_head se_ordered_list; + struct list_head se_lun_list; + struct se_device *se_dev; + struct se_dev_entry *se_deve; + struct se_device *se_obj_ptr; + struct se_device *se_orig_obj_ptr; + struct se_lun *se_lun; + /* Only used for internal passthrough and legacy TCM fabric modules */ + struct se_session *se_sess; + struct se_tmr_req *se_tmr_req; + /* t_task is setup to t_task_backstore in transport_init_se_cmd() */ + struct se_transport_task *t_task; + struct se_transport_task t_task_backstore; + struct target_core_fabric_ops *se_tfo; + int (*transport_emulate_cdb)(struct se_cmd *); + void (*transport_split_cdb)(unsigned long long, u32 *, unsigned char *); + void (*transport_wait_for_tasks)(struct se_cmd *, int, int); + void (*transport_complete_callback)(struct se_cmd *); +} ____cacheline_aligned; + +#define T_TASK(cmd) ((struct se_transport_task *)(cmd->t_task)) +#define CMD_TFO(cmd) ((struct target_core_fabric_ops *)cmd->se_tfo) + +struct se_tmr_req { + /* Task Management function to be preformed */ + u8 function; + /* Task Management response to send */ + u8 response; + int call_transport; + /* Reference to ITT that Task Mgmt should be preformed */ + u32 ref_task_tag; + /* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */ + u64 ref_task_lun; + void *fabric_tmr_ptr; + struct se_cmd *task_cmd; + struct se_cmd *ref_cmd; + struct se_device *tmr_dev; + struct se_lun *tmr_lun; + struct list_head tmr_list; +} ____cacheline_aligned; + +struct se_ua { + u8 ua_asc; + u8 ua_ascq; + struct se_node_acl *ua_nacl; + struct list_head ua_dev_list; + struct list_head ua_nacl_list; +} ____cacheline_aligned; + +struct se_node_acl { + char initiatorname[TRANSPORT_IQN_LEN]; + /* Used to signal demo mode created ACL, disabled by default */ + int dynamic_node_acl:1; + u32 queue_depth; + u32 acl_index; + u64 num_cmds; + u64 read_bytes; + u64 write_bytes; + spinlock_t stats_lock; + /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ + atomic_t acl_pr_ref_count; + /* Used for MIB access */ + atomic_t mib_ref_count; + struct se_dev_entry *device_list; + struct se_session *nacl_sess; + struct se_portal_group *se_tpg; + spinlock_t device_list_lock; + spinlock_t nacl_sess_lock; + struct config_group acl_group; + struct config_group acl_attrib_group; + struct config_group acl_auth_group; + struct config_group acl_param_group; + struct config_group *acl_default_groups[4]; + struct list_head acl_list; + struct list_head acl_sess_list; +} ____cacheline_aligned; + +struct se_session { + /* Used for MIB access */ + atomic_t mib_ref_count; + u64 sess_bin_isid; + struct se_node_acl *se_node_acl; + struct se_portal_group *se_tpg; + void *fabric_sess_ptr; + struct list_head sess_list; + struct list_head sess_acl_list; +} ____cacheline_aligned; + +#define SE_SESS(cmd) ((struct se_session *)(cmd)->se_sess) +#define SE_NODE_ACL(sess) ((struct se_node_acl *)(sess)->se_node_acl) + +struct se_device; +struct se_transform_info; +struct scatterlist; + +struct se_lun_acl { + char initiatorname[TRANSPORT_IQN_LEN]; + u32 mapped_lun; + struct se_node_acl *se_lun_nacl; + struct se_lun *se_lun; + struct list_head lacl_list; + struct config_group se_lun_group; +} ____cacheline_aligned; + +struct se_dev_entry { + int def_pr_registered:1; + /* See transport_lunflags_table */ + u32 lun_flags; + u32 deve_cmds; + u32 mapped_lun; + u32 average_bytes; + u32 last_byte_count; + u32 total_cmds; + u32 total_bytes; + u64 pr_res_key; + u64 creation_time; + u32 attach_count; + u64 read_bytes; + u64 write_bytes; + atomic_t ua_count; + /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ + atomic_t pr_ref_count; + struct se_lun_acl *se_lun_acl; + spinlock_t ua_lock; + struct se_lun *se_lun; + struct list_head alua_port_list; + struct list_head ua_list; +} ____cacheline_aligned; + +struct se_dev_limits { + /* Max supported HW queue depth */ + u32 hw_queue_depth; + /* Max supported virtual queue depth */ + u32 queue_depth; + /* From include/linux/blkdev.h for the other HW/SW limits. */ + struct queue_limits limits; +} ____cacheline_aligned; + +struct se_dev_attrib { + int emulate_dpo; + int emulate_fua_write; + int emulate_fua_read; + int emulate_write_cache; + int emulate_ua_intlck_ctrl; + int emulate_tas; + int emulate_tpu; + int emulate_tpws; + int emulate_reservations; + int emulate_alua; + int enforce_pr_isids; + u32 hw_block_size; + u32 block_size; + u32 hw_max_sectors; + u32 max_sectors; + u32 optimal_sectors; + u32 hw_queue_depth; + u32 queue_depth; + u32 task_timeout; + u32 max_unmap_lba_count; + u32 max_unmap_block_desc_count; + u32 unmap_granularity; + u32 unmap_granularity_alignment; + struct se_subsystem_dev *da_sub_dev; + struct config_group da_group; +} ____cacheline_aligned; + +struct se_subsystem_dev { +/* Used for struct se_subsystem_dev-->se_dev_alias, must be less than PAGE_SIZE */ +#define SE_DEV_ALIAS_LEN 512 + unsigned char se_dev_alias[SE_DEV_ALIAS_LEN]; +/* Used for struct se_subsystem_dev->se_dev_udev_path[], must be less than PAGE_SIZE */ +#define SE_UDEV_PATH_LEN 512 + unsigned char se_dev_udev_path[SE_UDEV_PATH_LEN]; + u32 su_dev_flags; + struct se_hba *se_dev_hba; + struct se_device *se_dev_ptr; + struct se_dev_attrib se_dev_attrib; + /* T10 Asymmetric Logical Unit Assignment for Target Ports */ + struct t10_alua t10_alua; + /* T10 Inquiry and VPD WWN Information */ + struct t10_wwn t10_wwn; + /* T10 SPC-2 + SPC-3 Reservations */ + struct t10_reservation_template t10_reservation; + spinlock_t se_dev_lock; + void *se_dev_su_ptr; + struct list_head g_se_dev_list; + struct config_group se_dev_group; + /* For T10 Reservations */ + struct config_group se_dev_pr_group; +} ____cacheline_aligned; + +#define T10_ALUA(su_dev) (&(su_dev)->t10_alua) +#define T10_RES(su_dev) (&(su_dev)->t10_reservation) +#define T10_PR_OPS(su_dev) (&(su_dev)->t10_reservation.pr_ops) + +struct se_device { + /* Set to 1 if thread is NOT sleeping on thread_sem */ + u8 thread_active; + u8 dev_status_timer_flags; + /* RELATIVE TARGET PORT IDENTIFER Counter */ + u16 dev_rpti_counter; + /* Used for SAM Task Attribute ordering */ + u32 dev_cur_ordered_id; + u32 dev_flags; + u32 dev_port_count; + /* See transport_device_status_table */ + u32 dev_status; + u32 dev_tcq_window_closed; + /* Physical device queue depth */ + u32 queue_depth; + /* Used for SPC-2 reservations enforce of ISIDs */ + u64 dev_res_bin_isid; + t10_task_attr_index_t dev_task_attr_type; + /* Pointer to transport specific device structure */ + void *dev_ptr; + u32 dev_index; + u64 creation_time; + u32 num_resets; + u64 num_cmds; + u64 read_bytes; + u64 write_bytes; + spinlock_t stats_lock; + /* Active commands on this virtual SE device */ + atomic_t active_cmds; + atomic_t simple_cmds; + atomic_t depth_left; + atomic_t dev_ordered_id; + atomic_t dev_tur_active; + atomic_t execute_tasks; + atomic_t dev_status_thr_count; + atomic_t dev_hoq_count; + atomic_t dev_ordered_sync; + struct se_obj dev_obj; + struct se_obj dev_access_obj; + struct se_obj dev_export_obj; + struct se_queue_obj *dev_queue_obj; + struct se_queue_obj *dev_status_queue_obj; + spinlock_t delayed_cmd_lock; + spinlock_t ordered_cmd_lock; + spinlock_t execute_task_lock; + spinlock_t state_task_lock; + spinlock_t dev_alua_lock; + spinlock_t dev_reservation_lock; + spinlock_t dev_state_lock; + spinlock_t dev_status_lock; + spinlock_t dev_status_thr_lock; + spinlock_t se_port_lock; + spinlock_t se_tmr_lock; + /* Used for legacy SPC-2 reservationsa */ + struct se_node_acl *dev_reserved_node_acl; + /* Used for ALUA Logical Unit Group membership */ + struct t10_alua_lu_gp_member *dev_alua_lu_gp_mem; + /* Used for SPC-3 Persistent Reservations */ + struct t10_pr_registration *dev_pr_res_holder; + struct list_head dev_sep_list; + struct list_head dev_tmr_list; + struct timer_list dev_status_timer; + /* Pointer to descriptor for processing thread */ + struct task_struct *process_thread; + pid_t process_thread_pid; + struct task_struct *dev_mgmt_thread; + struct list_head delayed_cmd_list; + struct list_head ordered_cmd_list; + struct list_head execute_task_list; + struct list_head state_task_list; + /* Pointer to associated SE HBA */ + struct se_hba *se_hba; + struct se_subsystem_dev *se_sub_dev; + /* Pointer to template of function pointers for transport */ + struct se_subsystem_api *transport; + /* Linked list for struct se_hba struct se_device list */ + struct list_head dev_list; + /* Linked list for struct se_global->g_se_dev_list */ + struct list_head g_se_dev_list; +} ____cacheline_aligned; + +#define SE_DEV(cmd) ((struct se_device *)(cmd)->se_lun->lun_se_dev) +#define SU_DEV(dev) ((struct se_subsystem_dev *)(dev)->se_sub_dev) +#define DEV_ATTRIB(dev) (&(dev)->se_sub_dev->se_dev_attrib) +#define DEV_T10_WWN(dev) (&(dev)->se_sub_dev->t10_wwn) + +struct se_hba { + u16 hba_tpgt; + u32 hba_id; + /* See hba_flags_table */ + u32 hba_flags; + /* Virtual iSCSI devices attached. */ + u32 dev_count; + u32 hba_index; + atomic_t dev_mib_access_count; + atomic_t load_balance_queue; + atomic_t left_queue_depth; + /* Maximum queue depth the HBA can handle. */ + atomic_t max_queue_depth; + /* Pointer to transport specific host structure. */ + void *hba_ptr; + /* Linked list for struct se_device */ + struct list_head hba_dev_list; + struct list_head hba_list; + spinlock_t device_lock; + spinlock_t hba_queue_lock; + struct config_group hba_group; + struct mutex hba_access_mutex; + struct se_subsystem_api *transport; +} ____cacheline_aligned; + +#define SE_HBA(d) ((struct se_hba *)(d)->se_hba) + +struct se_lun { + /* See transport_lun_status_table */ + enum transport_lun_status_table lun_status; + u32 lun_access; + u32 lun_flags; + u32 unpacked_lun; + atomic_t lun_acl_count; + spinlock_t lun_acl_lock; + spinlock_t lun_cmd_lock; + spinlock_t lun_sep_lock; + struct completion lun_shutdown_comp; + struct list_head lun_cmd_list; + struct list_head lun_acl_list; + struct se_device *lun_se_dev; + struct config_group lun_group; + struct se_port *lun_sep; +} ____cacheline_aligned; + +#define SE_LUN(c) ((struct se_lun *)(c)->se_lun) + +struct se_port { + /* RELATIVE TARGET PORT IDENTIFER */ + u16 sep_rtpi; + int sep_tg_pt_secondary_stat; + int sep_tg_pt_secondary_write_md; + u32 sep_index; + struct scsi_port_stats sep_stats; + /* Used for ALUA Target Port Groups membership */ + atomic_t sep_tg_pt_gp_active; + atomic_t sep_tg_pt_secondary_offline; + /* Used for PR ALL_TG_PT=1 */ + atomic_t sep_tg_pt_ref_cnt; + spinlock_t sep_alua_lock; + struct mutex sep_tg_pt_md_mutex; + struct t10_alua_tg_pt_gp_member *sep_alua_tg_pt_gp_mem; + struct se_lun *sep_lun; + struct se_portal_group *sep_tpg; + struct list_head sep_alua_list; + struct list_head sep_list; +} ____cacheline_aligned; + +struct se_tpg_np { + struct config_group tpg_np_group; +} ____cacheline_aligned; + +struct se_portal_group { + /* Type of target portal group, see transport_tpg_type_table */ + enum transport_tpg_type_table se_tpg_type; + /* Number of ACLed Initiator Nodes for this TPG */ + u32 num_node_acls; + /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ + atomic_t tpg_pr_ref_count; + /* Spinlock for adding/removing ACLed Nodes */ + spinlock_t acl_node_lock; + /* Spinlock for adding/removing sessions */ + spinlock_t session_lock; + spinlock_t tpg_lun_lock; + /* Pointer to $FABRIC_MOD portal group */ + void *se_tpg_fabric_ptr; + struct list_head se_tpg_list; + /* linked list for initiator ACL list */ + struct list_head acl_node_list; + struct se_lun *tpg_lun_list; + struct se_lun tpg_virt_lun0; + /* List of TCM sessions assoicated wth this TPG */ + struct list_head tpg_sess_list; + /* Pointer to $FABRIC_MOD dependent code */ + struct target_core_fabric_ops *se_tpg_tfo; + struct se_wwn *se_tpg_wwn; + struct config_group tpg_group; + struct config_group *tpg_default_groups[6]; + struct config_group tpg_lun_group; + struct config_group tpg_np_group; + struct config_group tpg_acl_group; + struct config_group tpg_attrib_group; + struct config_group tpg_param_group; +} ____cacheline_aligned; + +#define TPG_TFO(se_tpg) ((struct target_core_fabric_ops *)(se_tpg)->se_tpg_tfo) + +struct se_wwn { + struct target_fabric_configfs *wwn_tf; + struct config_group wwn_group; +} ____cacheline_aligned; + +struct se_global { + u16 alua_lu_gps_counter; + int g_sub_api_initialized; + u32 in_shutdown; + u32 alua_lu_gps_count; + u32 g_hba_id_counter; + struct config_group target_core_hbagroup; + struct config_group alua_group; + struct config_group alua_lu_gps_group; + struct list_head g_lu_gps_list; + struct list_head g_se_tpg_list; + struct list_head g_hba_list; + struct list_head g_se_dev_list; + struct se_hba *g_lun0_hba; + struct se_subsystem_dev *g_lun0_su_dev; + struct se_device *g_lun0_dev; + struct t10_alua_lu_gp *default_lu_gp; + spinlock_t g_device_lock; + spinlock_t hba_lock; + spinlock_t se_tpg_lock; + spinlock_t lu_gps_lock; + spinlock_t plugin_class_lock; +} ____cacheline_aligned; + +#endif /* TARGET_CORE_BASE_H */ diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h new file mode 100644 index 000000000000..40e6e740527c --- /dev/null +++ b/include/target/target_core_configfs.h @@ -0,0 +1,52 @@ +#define TARGET_CORE_CONFIGFS_VERSION TARGET_CORE_MOD_VERSION + +#define TARGET_CORE_CONFIG_ROOT "/sys/kernel/config" + +#define TARGET_CORE_NAME_MAX_LEN 64 +#define TARGET_FABRIC_NAME_SIZE 32 + +extern struct target_fabric_configfs *target_fabric_configfs_init( + struct module *, const char *); +extern void target_fabric_configfs_free(struct target_fabric_configfs *); +extern int target_fabric_configfs_register(struct target_fabric_configfs *); +extern void target_fabric_configfs_deregister(struct target_fabric_configfs *); + +struct target_fabric_configfs_template { + struct config_item_type tfc_discovery_cit; + struct config_item_type tfc_wwn_cit; + struct config_item_type tfc_tpg_cit; + struct config_item_type tfc_tpg_base_cit; + struct config_item_type tfc_tpg_lun_cit; + struct config_item_type tfc_tpg_port_cit; + struct config_item_type tfc_tpg_np_cit; + struct config_item_type tfc_tpg_np_base_cit; + struct config_item_type tfc_tpg_attrib_cit; + struct config_item_type tfc_tpg_param_cit; + struct config_item_type tfc_tpg_nacl_cit; + struct config_item_type tfc_tpg_nacl_base_cit; + struct config_item_type tfc_tpg_nacl_attrib_cit; + struct config_item_type tfc_tpg_nacl_auth_cit; + struct config_item_type tfc_tpg_nacl_param_cit; + struct config_item_type tfc_tpg_mappedlun_cit; +}; + +struct target_fabric_configfs { + char tf_name[TARGET_FABRIC_NAME_SIZE]; + atomic_t tf_access_cnt; + struct list_head tf_list; + struct config_group tf_group; + struct config_group tf_disc_group; + struct config_group *tf_default_groups[2]; + /* Pointer to fabric's config_item */ + struct config_item *tf_fabric; + /* Passed from fabric modules */ + struct config_item_type *tf_fabric_cit; + /* Pointer to target core subsystem */ + struct configfs_subsystem *tf_subsys; + /* Pointer to fabric's struct module */ + struct module *tf_module; + struct target_core_fabric_ops tf_ops; + struct target_fabric_configfs_template tf_cit_tmpl; +}; + +#define TF_CIT_TMPL(tf) (&(tf)->tf_cit_tmpl) diff --git a/include/target/target_core_device.h b/include/target/target_core_device.h new file mode 100644 index 000000000000..52b18a5752c9 --- /dev/null +++ b/include/target/target_core_device.h @@ -0,0 +1,61 @@ +#ifndef TARGET_CORE_DEVICE_H +#define TARGET_CORE_DEVICE_H + +extern int transport_get_lun_for_cmd(struct se_cmd *, unsigned char *, u32); +extern int transport_get_lun_for_tmr(struct se_cmd *, u32); +extern struct se_dev_entry *core_get_se_deve_from_rtpi( + struct se_node_acl *, u16); +extern int core_free_device_list_for_node(struct se_node_acl *, + struct se_portal_group *); +extern void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *); +extern void core_update_device_list_access(u32, u32, struct se_node_acl *); +extern int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, u32, + u32, struct se_node_acl *, + struct se_portal_group *, int); +extern void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); +extern int core_dev_export(struct se_device *, struct se_portal_group *, + struct se_lun *); +extern void core_dev_unexport(struct se_device *, struct se_portal_group *, + struct se_lun *); +extern int transport_core_report_lun_response(struct se_cmd *); +extern void se_release_device_for_hba(struct se_device *); +extern void se_release_vpd_for_dev(struct se_device *); +extern void se_clear_dev_ports(struct se_device *); +extern int se_free_virtual_device(struct se_device *, struct se_hba *); +extern int se_dev_check_online(struct se_device *); +extern int se_dev_check_shutdown(struct se_device *); +extern void se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *); +extern int se_dev_set_task_timeout(struct se_device *, u32); +extern int se_dev_set_max_unmap_lba_count(struct se_device *, u32); +extern int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); +extern int se_dev_set_unmap_granularity(struct se_device *, u32); +extern int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); +extern int se_dev_set_emulate_dpo(struct se_device *, int); +extern int se_dev_set_emulate_fua_write(struct se_device *, int); +extern int se_dev_set_emulate_fua_read(struct se_device *, int); +extern int se_dev_set_emulate_write_cache(struct se_device *, int); +extern int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int); +extern int se_dev_set_emulate_tas(struct se_device *, int); +extern int se_dev_set_emulate_tpu(struct se_device *, int); +extern int se_dev_set_emulate_tpws(struct se_device *, int); +extern int se_dev_set_enforce_pr_isids(struct se_device *, int); +extern int se_dev_set_queue_depth(struct se_device *, u32); +extern int se_dev_set_max_sectors(struct se_device *, u32); +extern int se_dev_set_optimal_sectors(struct se_device *, u32); +extern int se_dev_set_block_size(struct se_device *, u32); +extern struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *, + struct se_device *, u32); +extern int core_dev_del_lun(struct se_portal_group *, u32); +extern struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); +extern struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, + u32, char *, int *); +extern int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, + struct se_lun_acl *, u32, u32); +extern int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, + struct se_lun *, struct se_lun_acl *); +extern void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, + struct se_lun_acl *lacl); +extern int core_dev_setup_virtual_lun0(void); +extern void core_dev_release_virtual_lun0(void); + +#endif /* TARGET_CORE_DEVICE_H */ diff --git a/include/target/target_core_fabric_configfs.h b/include/target/target_core_fabric_configfs.h new file mode 100644 index 000000000000..a26fb7586a09 --- /dev/null +++ b/include/target/target_core_fabric_configfs.h @@ -0,0 +1,106 @@ +/* + * Used for tfc_wwn_cit attributes + */ + +#include + +CONFIGFS_EATTR_STRUCT(target_fabric_nacl_attrib, se_node_acl); +#define TF_NACL_ATTRIB_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_nacl_attrib_attribute _fabric##_nacl_attrib_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_nacl_attrib_show_##_name, \ + _fabric##_nacl_attrib_store_##_name); + +CONFIGFS_EATTR_STRUCT(target_fabric_nacl_auth, se_node_acl); +#define TF_NACL_AUTH_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_nacl_auth_attribute _fabric##_nacl_auth_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_nacl_auth_show_##_name, \ + _fabric##_nacl_auth_store_##_name); + +#define TF_NACL_AUTH_ATTR_RO(_fabric, _name) \ +static struct target_fabric_nacl_auth_attribute _fabric##_nacl_auth_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_nacl_auth_show_##_name); + +CONFIGFS_EATTR_STRUCT(target_fabric_nacl_param, se_node_acl); +#define TF_NACL_PARAM_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_nacl_param_attribute _fabric##_nacl_param_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_nacl_param_show_##_name, \ + _fabric##_nacl_param_store_##_name); + +#define TF_NACL_PARAM_ATTR_RO(_fabric, _name) \ +static struct target_fabric_nacl_param_attribute _fabric##_nacl_param_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_nacl_param_show_##_name); + + +CONFIGFS_EATTR_STRUCT(target_fabric_nacl_base, se_node_acl); +#define TF_NACL_BASE_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_nacl_base_attribute _fabric##_nacl_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_nacl_show_##_name, \ + _fabric##_nacl_store_##_name); + +#define TF_NACL_BASE_ATTR_RO(_fabric, _name) \ +static struct target_fabric_nacl_base_attribute _fabric##_nacl_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_nacl_show_##_name); + +CONFIGFS_EATTR_STRUCT(target_fabric_np_base, se_tpg_np); +#define TF_NP_BASE_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_np_base_attribute _fabric##_np_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_np_show_##_name, \ + _fabric##_np_store_##_name); + +CONFIGFS_EATTR_STRUCT(target_fabric_tpg_attrib, se_portal_group); +#define TF_TPG_ATTRIB_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_tpg_attrib_attribute _fabric##_tpg_attrib_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_tpg_attrib_show_##_name, \ + _fabric##_tpg_attrib_store_##_name); + + +CONFIGFS_EATTR_STRUCT(target_fabric_tpg_param, se_portal_group); +#define TF_TPG_PARAM_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_tpg_param_attribute _fabric##_tpg_param_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_tpg_param_show_##_name, \ + _fabric##_tpg_param_store_##_name); + + +CONFIGFS_EATTR_STRUCT(target_fabric_tpg, se_portal_group); +#define TF_TPG_BASE_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_tpg_show_##_name, \ + _fabric##_tpg_store_##_name); + + +CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs); +#define TF_WWN_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_wwn_show_attr_##_name, \ + _fabric##_wwn_store_attr_##_name); + +#define TF_WWN_ATTR_RO(_fabric, _name) \ +static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_wwn_show_attr_##_name); + +CONFIGFS_EATTR_STRUCT(target_fabric_discovery, target_fabric_configfs); +#define TF_DISC_ATTR(_fabric, _name, _mode) \ +static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _fabric##_disc_show_##_name, \ + _fabric##_disc_store_##_name); + +#define TF_DISC_ATTR_RO(_fabric, _name) \ +static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_disc_show_##_name); + +extern int target_fabric_setup_cits(struct target_fabric_configfs *); diff --git a/include/target/target_core_fabric_lib.h b/include/target/target_core_fabric_lib.h new file mode 100644 index 000000000000..c2f8d0e3a03b --- /dev/null +++ b/include/target/target_core_fabric_lib.h @@ -0,0 +1,28 @@ +#ifndef TARGET_CORE_FABRIC_LIB_H +#define TARGET_CORE_FABRIC_LIB_H + +extern u8 sas_get_fabric_proto_ident(struct se_portal_group *); +extern u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *, unsigned char *); +extern u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *); +extern char *sas_parse_pr_out_transport_id(struct se_portal_group *, + const char *, u32 *, char **); + +extern u8 fc_get_fabric_proto_ident(struct se_portal_group *); +extern u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *, unsigned char *); +extern u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *); +extern char *fc_parse_pr_out_transport_id(struct se_portal_group *, + const char *, u32 *, char **); + +extern u8 iscsi_get_fabric_proto_ident(struct se_portal_group *); +extern u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *, unsigned char *); +extern u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *); +extern char *iscsi_parse_pr_out_transport_id(struct se_portal_group *, + const char *, u32 *, char **); + +#endif /* TARGET_CORE_FABRIC_LIB_H */ diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h new file mode 100644 index 000000000000..f3ac12b019c2 --- /dev/null +++ b/include/target/target_core_fabric_ops.h @@ -0,0 +1,100 @@ +/* Defined in target_core_configfs.h */ +struct target_fabric_configfs; + +struct target_core_fabric_ops { + struct configfs_subsystem *tf_subsys; + /* + * Optional to signal struct se_task->task_sg[] padding entries + * for scatterlist chaining using transport_do_task_sg_link(), + * disabled by default + */ + int task_sg_chaining:1; + char *(*get_fabric_name)(void); + u8 (*get_fabric_proto_ident)(struct se_portal_group *); + char *(*tpg_get_wwn)(struct se_portal_group *); + u16 (*tpg_get_tag)(struct se_portal_group *); + u32 (*tpg_get_default_depth)(struct se_portal_group *); + u32 (*tpg_get_pr_transport_id)(struct se_portal_group *, + struct se_node_acl *, + struct t10_pr_registration *, int *, + unsigned char *); + u32 (*tpg_get_pr_transport_id_len)(struct se_portal_group *, + struct se_node_acl *, + struct t10_pr_registration *, int *); + char *(*tpg_parse_pr_out_transport_id)(struct se_portal_group *, + const char *, u32 *, char **); + int (*tpg_check_demo_mode)(struct se_portal_group *); + int (*tpg_check_demo_mode_cache)(struct se_portal_group *); + int (*tpg_check_demo_mode_write_protect)(struct se_portal_group *); + int (*tpg_check_prod_mode_write_protect)(struct se_portal_group *); + struct se_node_acl *(*tpg_alloc_fabric_acl)( + struct se_portal_group *); + void (*tpg_release_fabric_acl)(struct se_portal_group *, + struct se_node_acl *); + u32 (*tpg_get_inst_index)(struct se_portal_group *); + /* + * Optional function pointer for TCM to perform command map + * from TCM processing thread context, for those struct se_cmd + * initally allocated in interrupt context. + */ + int (*new_cmd_map)(struct se_cmd *); + /* + * Optional function pointer for TCM fabric modules that use + * Linux/NET sockets to allocate struct iovec array to struct se_cmd + */ + int (*alloc_cmd_iovecs)(struct se_cmd *); + /* + * Optional to release struct se_cmd and fabric dependent allocated + * I/O descriptor in transport_cmd_check_stop() + */ + void (*check_stop_free)(struct se_cmd *); + void (*release_cmd_to_pool)(struct se_cmd *); + void (*release_cmd_direct)(struct se_cmd *); + /* + * Called with spin_lock_bh(struct se_portal_group->session_lock held. + */ + int (*shutdown_session)(struct se_session *); + void (*close_session)(struct se_session *); + void (*stop_session)(struct se_session *, int, int); + void (*fall_back_to_erl0)(struct se_session *); + int (*sess_logged_in)(struct se_session *); + u32 (*sess_get_index)(struct se_session *); + /* + * Used only for SCSI fabrics that contain multi-value TransportIDs + * (like iSCSI). All other SCSI fabrics should set this to NULL. + */ + u32 (*sess_get_initiator_sid)(struct se_session *, + unsigned char *, u32); + int (*write_pending)(struct se_cmd *); + int (*write_pending_status)(struct se_cmd *); + void (*set_default_node_attributes)(struct se_node_acl *); + u32 (*get_task_tag)(struct se_cmd *); + int (*get_cmd_state)(struct se_cmd *); + void (*new_cmd_failure)(struct se_cmd *); + int (*queue_data_in)(struct se_cmd *); + int (*queue_status)(struct se_cmd *); + int (*queue_tm_rsp)(struct se_cmd *); + u16 (*set_fabric_sense_len)(struct se_cmd *, u32); + u16 (*get_fabric_sense_len)(void); + int (*is_state_remove)(struct se_cmd *); + u64 (*pack_lun)(unsigned int); + /* + * fabric module calls for target_core_fabric_configfs.c + */ + struct se_wwn *(*fabric_make_wwn)(struct target_fabric_configfs *, + struct config_group *, const char *); + void (*fabric_drop_wwn)(struct se_wwn *); + struct se_portal_group *(*fabric_make_tpg)(struct se_wwn *, + struct config_group *, const char *); + void (*fabric_drop_tpg)(struct se_portal_group *); + int (*fabric_post_link)(struct se_portal_group *, + struct se_lun *); + void (*fabric_pre_unlink)(struct se_portal_group *, + struct se_lun *); + struct se_tpg_np *(*fabric_make_np)(struct se_portal_group *, + struct config_group *, const char *); + void (*fabric_drop_np)(struct se_tpg_np *); + struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *, + struct config_group *, const char *); + void (*fabric_drop_nodeacl)(struct se_node_acl *); +}; diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h new file mode 100644 index 000000000000..6c8248bc2c66 --- /dev/null +++ b/include/target/target_core_tmr.h @@ -0,0 +1,43 @@ +#ifndef TARGET_CORE_TMR_H +#define TARGET_CORE_TMR_H + +/* task management function values */ +#ifdef ABORT_TASK +#undef ABORT_TASK +#endif /* ABORT_TASK */ +#define ABORT_TASK 1 +#ifdef ABORT_TASK_SET +#undef ABORT_TASK_SET +#endif /* ABORT_TASK_SET */ +#define ABORT_TASK_SET 2 +#ifdef CLEAR_ACA +#undef CLEAR_ACA +#endif /* CLEAR_ACA */ +#define CLEAR_ACA 3 +#ifdef CLEAR_TASK_SET +#undef CLEAR_TASK_SET +#endif /* CLEAR_TASK_SET */ +#define CLEAR_TASK_SET 4 +#define LUN_RESET 5 +#define TARGET_WARM_RESET 6 +#define TARGET_COLD_RESET 7 +#define TASK_REASSIGN 8 + +/* task management response values */ +#define TMR_FUNCTION_COMPLETE 0 +#define TMR_TASK_DOES_NOT_EXIST 1 +#define TMR_LUN_DOES_NOT_EXIST 2 +#define TMR_TASK_STILL_ALLEGIANT 3 +#define TMR_TASK_FAILOVER_NOT_SUPPORTED 4 +#define TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED 5 +#define TMR_FUNCTION_AUTHORIZATION_FAILED 6 +#define TMR_FUNCTION_REJECTED 255 + +extern struct kmem_cache *se_tmr_req_cache; + +extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8); +extern void core_tmr_release_req(struct se_tmr_req *); +extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *, + struct list_head *, struct se_cmd *); + +#endif /* TARGET_CORE_TMR_H */ diff --git a/include/target/target_core_tpg.h b/include/target/target_core_tpg.h new file mode 100644 index 000000000000..77e18729c4c1 --- /dev/null +++ b/include/target/target_core_tpg.h @@ -0,0 +1,35 @@ +#ifndef TARGET_CORE_TPG_H +#define TARGET_CORE_TPG_H + +extern struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, + const char *); +extern struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, + unsigned char *); +extern void core_tpg_add_node_to_devs(struct se_node_acl *, + struct se_portal_group *); +extern struct se_node_acl *core_tpg_check_initiator_node_acl( + struct se_portal_group *, + unsigned char *); +extern void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); +extern void core_tpg_wait_for_mib_ref(struct se_node_acl *); +extern void core_tpg_clear_object_luns(struct se_portal_group *); +extern struct se_node_acl *core_tpg_add_initiator_node_acl( + struct se_portal_group *, + struct se_node_acl *, + const char *, u32); +extern int core_tpg_del_initiator_node_acl(struct se_portal_group *, + struct se_node_acl *, int); +extern int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, + unsigned char *, u32, int); +extern int core_tpg_register(struct target_core_fabric_ops *, + struct se_wwn *, + struct se_portal_group *, void *, + int); +extern int core_tpg_deregister(struct se_portal_group *); +extern struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32); +extern int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, u32, + void *); +extern struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *); +extern int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); + +#endif /* TARGET_CORE_TPG_H */ diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h new file mode 100644 index 000000000000..66f44e56eb80 --- /dev/null +++ b/include/target/target_core_transport.h @@ -0,0 +1,351 @@ +#ifndef TARGET_CORE_TRANSPORT_H +#define TARGET_CORE_TRANSPORT_H + +#define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION + +/* Attempts before moving from SHORT to LONG */ +#define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD 3 +#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3 /* In milliseconds */ +#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG 10 /* In milliseconds */ + +#define PYX_TRANSPORT_STATUS_INTERVAL 5 /* In seconds */ + +#define PYX_TRANSPORT_SENT_TO_TRANSPORT 0 +#define PYX_TRANSPORT_WRITE_PENDING 1 + +#define PYX_TRANSPORT_UNKNOWN_SAM_OPCODE -1 +#define PYX_TRANSPORT_HBA_QUEUE_FULL -2 +#define PYX_TRANSPORT_REQ_TOO_MANY_SECTORS -3 +#define PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES -4 +#define PYX_TRANSPORT_INVALID_CDB_FIELD -5 +#define PYX_TRANSPORT_INVALID_PARAMETER_LIST -6 +#define PYX_TRANSPORT_LU_COMM_FAILURE -7 +#define PYX_TRANSPORT_UNKNOWN_MODE_PAGE -8 +#define PYX_TRANSPORT_WRITE_PROTECTED -9 +#define PYX_TRANSPORT_TASK_TIMEOUT -10 +#define PYX_TRANSPORT_RESERVATION_CONFLICT -11 +#define PYX_TRANSPORT_ILLEGAL_REQUEST -12 +#define PYX_TRANSPORT_USE_SENSE_REASON -13 + +#ifndef SAM_STAT_RESERVATION_CONFLICT +#define SAM_STAT_RESERVATION_CONFLICT 0x18 +#endif + +#define TRANSPORT_PLUGIN_FREE 0 +#define TRANSPORT_PLUGIN_REGISTERED 1 + +#define TRANSPORT_PLUGIN_PHBA_PDEV 1 +#define TRANSPORT_PLUGIN_VHBA_PDEV 2 +#define TRANSPORT_PLUGIN_VHBA_VDEV 3 + +/* For SE OBJ Plugins, in seconds */ +#define TRANSPORT_TIMEOUT_TUR 10 +#define TRANSPORT_TIMEOUT_TYPE_DISK 60 +#define TRANSPORT_TIMEOUT_TYPE_ROM 120 +#define TRANSPORT_TIMEOUT_TYPE_TAPE 600 +#define TRANSPORT_TIMEOUT_TYPE_OTHER 300 + +/* For se_task->task_state_flags */ +#define TSF_EXCEPTION_CLEARED 0x01 + +/* + * struct se_subsystem_dev->su_dev_flags +*/ +#define SDF_FIRMWARE_VPD_UNIT_SERIAL 0x00000001 +#define SDF_EMULATED_VPD_UNIT_SERIAL 0x00000002 +#define SDF_USING_UDEV_PATH 0x00000004 +#define SDF_USING_ALIAS 0x00000008 + +/* + * struct se_device->dev_flags + */ +#define DF_READ_ONLY 0x00000001 +#define DF_SPC2_RESERVATIONS 0x00000002 +#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004 + +/* struct se_dev_attrib sanity values */ +/* 10 Minutes */ +#define DA_TASK_TIMEOUT_MAX 600 +/* Default max_unmap_lba_count */ +#define DA_MAX_UNMAP_LBA_COUNT 0 +/* Default max_unmap_block_desc_count */ +#define DA_MAX_UNMAP_BLOCK_DESC_COUNT 0 +/* Default unmap_granularity */ +#define DA_UNMAP_GRANULARITY_DEFAULT 0 +/* Default unmap_granularity_alignment */ +#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0 +/* Emulation for Direct Page Out */ +#define DA_EMULATE_DPO 0 +/* Emulation for Forced Unit Access WRITEs */ +#define DA_EMULATE_FUA_WRITE 1 +/* Emulation for Forced Unit Access READs */ +#define DA_EMULATE_FUA_READ 0 +/* Emulation for WriteCache and SYNCHRONIZE_CACHE */ +#define DA_EMULATE_WRITE_CACHE 0 +/* Emulation for UNIT ATTENTION Interlock Control */ +#define DA_EMULATE_UA_INTLLCK_CTRL 0 +/* Emulation for TASK_ABORTED status (TAS) by default */ +#define DA_EMULATE_TAS 1 +/* Emulation for Thin Provisioning UNMAP using block/blk-lib.c:blkdev_issue_discard() */ +#define DA_EMULATE_TPU 0 +/* + * Emulation for Thin Provisioning WRITE_SAME w/ UNMAP=1 bit using + * block/blk-lib.c:blkdev_issue_discard() + */ +#define DA_EMULATE_TPWS 0 +/* No Emulation for PSCSI by default */ +#define DA_EMULATE_RESERVATIONS 0 +/* No Emulation for PSCSI by default */ +#define DA_EMULATE_ALUA 0 +/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */ +#define DA_ENFORCE_PR_ISIDS 1 +#define DA_STATUS_MAX_SECTORS_MIN 16 +#define DA_STATUS_MAX_SECTORS_MAX 8192 + +#define SE_MODE_PAGE_BUF 512 + +#define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs)) + +struct se_mem; +struct se_subsystem_api; + +extern int init_se_global(void); +extern void release_se_global(void); +extern void transport_init_queue_obj(struct se_queue_obj *); +extern int transport_subsystem_check_init(void); +extern int transport_subsystem_register(struct se_subsystem_api *); +extern void transport_subsystem_release(struct se_subsystem_api *); +extern void transport_load_plugins(void); +extern struct se_session *transport_init_session(void); +extern void __transport_register_session(struct se_portal_group *, + struct se_node_acl *, + struct se_session *, void *); +extern void transport_register_session(struct se_portal_group *, + struct se_node_acl *, + struct se_session *, void *); +extern void transport_free_session(struct se_session *); +extern void transport_deregister_session_configfs(struct se_session *); +extern void transport_deregister_session(struct se_session *); +extern void transport_cmd_finish_abort(struct se_cmd *, int); +extern void transport_cmd_finish_abort_tmr(struct se_cmd *); +extern void transport_complete_sync_cache(struct se_cmd *, int); +extern void transport_complete_task(struct se_task *, int); +extern void transport_add_task_to_execute_queue(struct se_task *, + struct se_task *, + struct se_device *); +unsigned char *transport_dump_cmd_direction(struct se_cmd *); +extern void transport_dump_dev_state(struct se_device *, char *, int *); +extern void transport_dump_dev_info(struct se_device *, struct se_lun *, + unsigned long long, char *, int *); +extern void transport_dump_vpd_proto_id(struct t10_vpd *, + unsigned char *, int); +extern void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); +extern int transport_dump_vpd_assoc(struct t10_vpd *, + unsigned char *, int); +extern int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); +extern int transport_dump_vpd_ident_type(struct t10_vpd *, + unsigned char *, int); +extern int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); +extern int transport_dump_vpd_ident(struct t10_vpd *, + unsigned char *, int); +extern int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); +extern struct se_device *transport_add_device_to_core_hba(struct se_hba *, + struct se_subsystem_api *, + struct se_subsystem_dev *, u32, + void *, struct se_dev_limits *, + const char *, const char *); +extern void transport_device_setup_cmd(struct se_cmd *); +extern void transport_init_se_cmd(struct se_cmd *, + struct target_core_fabric_ops *, + struct se_session *, u32, int, int, + unsigned char *); +extern void transport_free_se_cmd(struct se_cmd *); +extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); +extern int transport_generic_handle_cdb(struct se_cmd *); +extern int transport_generic_handle_cdb_map(struct se_cmd *); +extern int transport_generic_handle_data(struct se_cmd *); +extern void transport_new_cmd_failure(struct se_cmd *); +extern int transport_generic_handle_tmr(struct se_cmd *); +extern void __transport_stop_task_timer(struct se_task *, unsigned long *); +extern unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]); +extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, + struct scatterlist *, u32); +extern int transport_clear_lun_from_sessions(struct se_lun *); +extern int transport_check_aborted_status(struct se_cmd *, int); +extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); +extern void transport_send_task_abort(struct se_cmd *); +extern void transport_release_cmd_to_pool(struct se_cmd *); +extern void transport_generic_free_cmd(struct se_cmd *, int, int, int); +extern void transport_generic_wait_for_cmds(struct se_cmd *, int); +extern u32 transport_calc_sg_num(struct se_task *, struct se_mem *, u32); +extern int transport_map_mem_to_sg(struct se_task *, struct list_head *, + void *, struct se_mem *, + struct se_mem **, u32 *, u32 *); +extern void transport_do_task_sg_chain(struct se_cmd *); +extern void transport_generic_process_write(struct se_cmd *); +extern int transport_generic_do_tmr(struct se_cmd *); +/* From target_core_alua.c */ +extern int core_alua_check_nonop_delay(struct se_cmd *); + +/* + * Each se_transport_task_t can have N number of possible struct se_task's + * for the storage transport(s) to possibly execute. + * Used primarily for splitting up CDBs that exceed the physical storage + * HBA's maximum sector count per task. + */ +struct se_mem { + struct page *se_page; + u32 se_len; + u32 se_off; + struct list_head se_list; +} ____cacheline_aligned; + +/* + * Each type of disk transport supported MUST have a template defined + * within its .h file. + */ +struct se_subsystem_api { + /* + * The Name. :-) + */ + char name[16]; + /* + * Transport Type. + */ + u8 transport_type; + /* + * struct module for struct se_hba references + */ + struct module *owner; + /* + * Used for global se_subsystem_api list_head + */ + struct list_head sub_api_list; + /* + * For SCF_SCSI_NON_DATA_CDB + */ + int (*cdb_none)(struct se_task *); + /* + * For SCF_SCSI_CONTROL_NONSG_IO_CDB + */ + int (*map_task_non_SG)(struct se_task *); + /* + * For SCF_SCSI_DATA_SG_IO_CDB and SCF_SCSI_CONTROL_SG_IO_CDB + */ + int (*map_task_SG)(struct se_task *); + /* + * attach_hba(): + */ + int (*attach_hba)(struct se_hba *, u32); + /* + * detach_hba(): + */ + void (*detach_hba)(struct se_hba *); + /* + * pmode_hba(): Used for TCM/pSCSI subsystem plugin HBA -> + * Linux/SCSI struct Scsi_Host passthrough + */ + int (*pmode_enable_hba)(struct se_hba *, unsigned long); + /* + * allocate_virtdevice(): + */ + void *(*allocate_virtdevice)(struct se_hba *, const char *); + /* + * create_virtdevice(): Only for Virtual HBAs + */ + struct se_device *(*create_virtdevice)(struct se_hba *, + struct se_subsystem_dev *, void *); + /* + * free_device(): + */ + void (*free_device)(void *); + + /* + * dpo_emulated(): + */ + int (*dpo_emulated)(struct se_device *); + /* + * fua_write_emulated(): + */ + int (*fua_write_emulated)(struct se_device *); + /* + * fua_read_emulated(): + */ + int (*fua_read_emulated)(struct se_device *); + /* + * write_cache_emulated(): + */ + int (*write_cache_emulated)(struct se_device *); + /* + * transport_complete(): + * + * Use transport_generic_complete() for majority of DAS transport + * drivers. Provided out of convenience. + */ + int (*transport_complete)(struct se_task *task); + struct se_task *(*alloc_task)(struct se_cmd *); + /* + * do_task(): + */ + int (*do_task)(struct se_task *); + /* + * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate + * UNMAP and WRITE_SAME_* w/ UNMAP=1 <-> Linux/Block Discard + */ + int (*do_discard)(struct se_device *, sector_t, u32); + /* + * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate + * SYNCHRONIZE_CACHE_* <-> Linux/Block blkdev_issue_flush() + */ + void (*do_sync_cache)(struct se_task *); + /* + * free_task(): + */ + void (*free_task)(struct se_task *); + /* + * check_configfs_dev_params(): + */ + ssize_t (*check_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *); + /* + * set_configfs_dev_params(): + */ + ssize_t (*set_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *, + const char *, ssize_t); + /* + * show_configfs_dev_params(): + */ + ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *, + char *); + /* + * get_cdb(): + */ + unsigned char *(*get_cdb)(struct se_task *); + /* + * get_device_rev(): + */ + u32 (*get_device_rev)(struct se_device *); + /* + * get_device_type(): + */ + u32 (*get_device_type)(struct se_device *); + /* + * Get the sector_t from a subsystem backstore.. + */ + sector_t (*get_blocks)(struct se_device *); + /* + * do_se_mem_map(): + */ + int (*do_se_mem_map)(struct se_task *, struct list_head *, void *, + struct se_mem *, struct se_mem **, u32 *, u32 *); + /* + * get_sense_buffer(): + */ + unsigned char *(*get_sense_buffer)(struct se_task *); +} ____cacheline_aligned; + +#define TRANSPORT(dev) ((dev)->transport) +#define HBA_TRANSPORT(hba) ((hba)->transport) + +extern struct se_global *se_global; + +#endif /* TARGET_CORE_TRANSPORT_H */ -- cgit v1.2.3 From 7f5db6a8022e8d4bb92b3d638068d2c2a9c9b59b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 14 Jan 2011 09:44:19 +0100 Subject: gpio: timbgpio: Fix up irq_data conversion breakage. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a1f5f22adc3206c47e70652c12671666c65b579f ("gpio: timbgpio: irq_data conversion") was slightly too enthusiastic in converting timbgpio_irq() over to take an irq_data * argument instead of an unsigned int irq argument, as it is a flow handler, which still take IRQ numbers for now. (And on top of that, it was using the wrong accessors.) This fixes it up, and seems to build without warnings. Signed-off-by: Lennert Buytenhek Cc: Andrew Morton Cc: Richard Röjfors Signed-off-by: Linus Torvalds --- drivers/gpio/timbgpio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index 349131eb1ce0..58c8f30352dd 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -193,13 +193,13 @@ out: return ret; } -static void timbgpio_irq(struct irq_data *d, struct irq_desc *desc) +static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) { - struct timbgpio *tgpio = irq_data_get_irq_data(d); + struct timbgpio *tgpio = get_irq_data(irq); unsigned long ipr; int offset; - desc->irq_data.chip->ack(irq_get_irq_data(d)); + desc->irq_data.chip->irq_ack(irq_get_irq_data(irq)); ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); -- cgit v1.2.3 From 53371edaef692bef7eee8070bd680401ccf65706 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 19 Jun 2010 23:08:37 +0200 Subject: agp/intel: Fix device names of i845 and 845G They got mixed up when the switch was converted to a table in 2007. Signed-off-by: Oswald Buddenhagen [ickle: minor changes for 2.6.37+] Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.c | 4 ++-- drivers/char/agp/intel-gtt.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 07e9796fead7..857df10c0428 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -717,8 +717,8 @@ static const struct intel_agp_driver_description { { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver }, { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver }, { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver }, - { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver }, - { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82845_HB, "i845", &intel_845_driver }, + { PCI_DEVICE_ID_INTEL_82845G_HB, "845G", &intel_845_driver }, { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver }, { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver }, { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver }, diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index e921b693412b..826ab0939a12 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1361,7 +1361,7 @@ static const struct intel_gtt_driver_description { &i81x_gtt_driver}, { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", &i8xx_gtt_driver}, - { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", + { PCI_DEVICE_ID_INTEL_82845G_IG, "845G", &i8xx_gtt_driver}, { PCI_DEVICE_ID_INTEL_82854_IG, "854", &i8xx_gtt_driver}, -- cgit v1.2.3 From 22ab70d3262ddb6e69b3c246a34e2967ba5eb1e8 Mon Sep 17 00:00:00 2001 From: Knut Petersen Date: Fri, 14 Jan 2011 15:38:10 +0000 Subject: drm/i915/lvds: Add AOpen i915GMm-HFS to the list of false-positive LVDS Signed-off-by: Knut Petersen Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8f4f6bd33ee9..ace8d5d30dd2 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -702,6 +702,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "AOpen i915GMm-HFS", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), + DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"), + }, + }, { .callback = intel_no_lvds_dmi_callback, .ident = "Aopen i945GTt-VFA", -- cgit v1.2.3 From 415e12b2379239973feab91850b0dce985c6058a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 7 Jan 2011 00:55:09 +0100 Subject: PCI/ACPI: Request _OSC control once for each root bridge (v3) Move the evaluation of acpi_pci_osc_control_set() (to request control of PCI Express native features) into acpi_pci_root_add() to avoid calling it many times for the same root complex with the same arguments. Additionally, check if all of the requisite _OSC support bits are set before calling acpi_pci_osc_control_set() for a given root complex. References: https://bugzilla.kernel.org/show_bug.cgi?id=20232 Reported-by: Ozan Caglayan Tested-by: Ozan Caglayan Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/acpi/apei/hest.c | 22 +++++++++------------- drivers/acpi/pci_root.c | 35 +++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 8 -------- drivers/pci/pcie/aer/aerdrv.c | 1 + drivers/pci/pcie/aer/aerdrv.h | 3 --- drivers/pci/pcie/portdrv.h | 3 --- drivers/pci/pcie/portdrv_acpi.c | 23 ++++------------------- include/acpi/apei.h | 6 ++++++ include/linux/pci-acpi.h | 6 ++++++ include/linux/pci.h | 11 +++++++++++ 10 files changed, 72 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index daa7bc63f1d4..4ee58e72b730 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -195,24 +195,24 @@ static int __init setup_hest_disable(char *str) __setup("hest_disable", setup_hest_disable); -static int __init hest_init(void) +void __init acpi_hest_init(void) { acpi_status status; int rc = -ENODEV; unsigned int ghes_count = 0; if (acpi_disabled) - goto err; + return; if (hest_disable) { - pr_info(HEST_PFX "HEST tabling parsing is disabled.\n"); - goto err; + pr_info(HEST_PFX "Table parsing disabled.\n"); + return; } status = acpi_get_table(ACPI_SIG_HEST, 0, (struct acpi_table_header **)&hest_tab); if (status == AE_NOT_FOUND) { - pr_info(HEST_PFX "Table is not found!\n"); + pr_info(HEST_PFX "Table not found.\n"); goto err; } else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); @@ -226,15 +226,11 @@ static int __init hest_init(void) goto err; rc = hest_ghes_dev_register(ghes_count); - if (rc) - goto err; - - pr_info(HEST_PFX "HEST table parsing is initialized.\n"); + if (!rc) { + pr_info(HEST_PFX "Table parsing has been initialized.\n"); + return; + } - return 0; err: hest_disable = 1; - return rc; } - -subsys_initcall(hest_init); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 96668ad09622..d9766797cd98 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -36,6 +36,7 @@ #include #include #include +#include #define PREFIX "ACPI: " @@ -47,6 +48,11 @@ static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); static int acpi_pci_root_start(struct acpi_device *device); +#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \ + | OSC_ACTIVE_STATE_PWR_SUPPORT \ + | OSC_CLOCK_PWR_CAPABILITY_SUPPORT \ + | OSC_MSI_SUPPORT) + static const struct acpi_device_id root_device_ids[] = { {"PNP0A03", 0}, {"", 0}, @@ -566,6 +572,33 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (flags != base_flags) acpi_pci_osc_support(root, flags); + if (!pcie_ports_disabled + && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) { + flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL + | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL + | OSC_PCI_EXPRESS_PME_CONTROL; + + if (pci_aer_available()) { + if (aer_acpi_firmware_first()) + dev_dbg(root->bus->bridge, + "PCIe errors handled by BIOS.\n"); + else + flags |= OSC_PCI_EXPRESS_AER_CONTROL; + } + + dev_info(root->bus->bridge, + "Requesting ACPI _OSC control (0x%02x)\n", flags); + + status = acpi_pci_osc_control_set(device->handle, &flags, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + if (ACPI_SUCCESS(status)) + dev_info(root->bus->bridge, + "ACPI _OSC control (0x%02x) granted\n", flags); + else + dev_dbg(root->bus->bridge, + "ACPI _OSC request failed (code %d)\n", status); + } + pci_acpi_add_bus_pm_notifier(device, root->bus); if (device->wakeup.flags.run_wake) device_set_run_wake(root->bus->bridge, true); @@ -603,6 +636,8 @@ static int __init acpi_pci_root_init(void) if (acpi_pci_disabled) return 0; + acpi_hest_init(); + pci_acpi_crs_quirks(); if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) return -ENODEV; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 7d33f6673868..16ae9659346b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -140,14 +140,6 @@ static inline void pci_no_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #endif -#ifdef CONFIG_PCIEAER -void pci_no_aer(void); -bool pci_aer_available(void); -#else -static inline void pci_no_aer(void) { } -static inline bool pci_aer_available(void) { return false; } -#endif - static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 2b2b6508efde..58ad7917553c 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 9656e3060412..80c11d131499 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -132,7 +132,6 @@ static inline int aer_osc_setup(struct pcie_device *pciedev) #ifdef CONFIG_ACPI_APEI extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); -extern bool aer_acpi_firmware_first(void); #else static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) { @@ -140,8 +139,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) return pci_dev->__aer_firmware_first; return 0; } - -static inline bool aer_acpi_firmware_first(void) { return false; } #endif static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev, diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 8fcc03598b29..bd00a01aef14 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -20,9 +20,6 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) -extern bool pcie_ports_disabled; -extern bool pcie_ports_auto; - extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_register(struct pci_dev *dev); #ifdef CONFIG_PM diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c index 5982b6a63b89..a86b56e5f2f2 100644 --- a/drivers/pci/pcie/portdrv_acpi.c +++ b/drivers/pci/pcie/portdrv_acpi.c @@ -33,7 +33,7 @@ */ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) { - acpi_status status; + struct acpi_pci_root *root; acpi_handle handle; u32 flags; @@ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) if (!handle) return -EINVAL; - flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL - | OSC_PCI_EXPRESS_PME_CONTROL; - - if (pci_aer_available()) { - if (aer_acpi_firmware_first()) - dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); - else - flags |= OSC_PCI_EXPRESS_AER_CONTROL; - } - - status = acpi_pci_osc_control_set(handle, &flags, - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); - if (ACPI_FAILURE(status)) { - dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n", - status); + root = acpi_pci_find_root(handle); + if (!root) return -ENODEV; - } - dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags); + flags = root->osc_control_set; *srv_mask = PCIE_PORT_SERVICE_VC; if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) diff --git a/include/acpi/apei.h b/include/acpi/apei.h index b3365025ff8d..c4dbb132d902 100644 --- a/include/acpi/apei.h +++ b/include/acpi/apei.h @@ -19,6 +19,12 @@ extern int hest_disable; extern int erst_disable; +#ifdef CONFIG_ACPI_APEI +void __init acpi_hest_init(void); +#else +static inline void acpi_hest_init(void) { return; } +#endif + typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data); int apei_hest_parse(apei_hest_func_t func, void *data); diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index c8b6473c5f42..479d9bb88e11 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -40,4 +40,10 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) { return NULL; } #endif +#ifdef CONFIG_ACPI_APEI +extern bool aer_acpi_firmware_first(void); +#else +static inline bool aer_acpi_firmware_first(void) { return false; } +#endif + #endif /* _PCI_ACPI_H_ */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 63cbadce337e..12dd86a82a15 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -994,6 +994,9 @@ extern void pci_restore_msi_state(struct pci_dev *dev); extern int pci_msi_enabled(void); #endif +extern bool pcie_ports_disabled; +extern bool pcie_ports_auto; + #ifndef CONFIG_PCIEASPM static inline int pcie_aspm_enabled(void) { @@ -1003,6 +1006,14 @@ static inline int pcie_aspm_enabled(void) extern int pcie_aspm_enabled(void); #endif +#ifdef CONFIG_PCIEAER +void pci_no_aer(void); +bool pci_aer_available(void); +#else +static inline void pci_no_aer(void) { } +static inline bool pci_aer_available(void) { return false; } +#endif + #ifndef CONFIG_PCIE_ECRC static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { -- cgit v1.2.3 From ff29530e651a3449aea6b0ef4c7048db9e22ef27 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 5 Jan 2011 10:26:41 -0700 Subject: PCI: sysfs: Update ROM to include default owner write access The PCI sysfs ROM interface requires an enabling write to access the ROM image, but the default file mode is 0400. The original proposed patch adding sysfs ROM support was a true read-only interface, with the enabling bit coming in as a feature request. I suspect it was simply an oversight that the file mode didn't get updated to match the API. Acked-by: Chris Wright Signed-off-by: Alex Williamson Signed-off-by: Jesse Barnes --- drivers/pci/pci-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 63d5042f2079..8ecaac983923 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1149,7 +1149,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) sysfs_bin_attr_init(attr); attr->size = rom_size; attr->attr.name = "rom"; - attr->attr.mode = S_IRUSR; + attr->attr.mode = S_IRUSR | S_IWUSR; attr->read = pci_read_rom; attr->write = pci_write_rom; retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); -- cgit v1.2.3 From b6e335aeeb114dccb07eaa09e8b62ff9510cf745 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 29 Dec 2010 13:21:23 +0100 Subject: PCI/PM: Use pm_wakeup_event() directly for reporting wakeup events After recent changes related to wakeup events pm_wakeup_event() automatically checks if the given device is configured to signal wakeup, so pci_wakeup_event() may be a static inline function calling pm_wakeup_event() directly. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 16 ---------------- drivers/pci/pci.h | 6 ++++++ include/linux/pci.h | 1 - 3 files changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6762dcae90ab..bf7ad2c09955 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1297,22 +1297,6 @@ bool pci_check_pme_status(struct pci_dev *dev) return ret; } -/* - * Time to wait before the system can be put into a sleep state after reporting - * a wakeup event signaled by a PCI device. - */ -#define PCI_WAKEUP_COOLDOWN 100 - -/** - * pci_wakeup_event - Report a wakeup event related to a given PCI device. - * @dev: Device to report the wakeup event for. - */ -void pci_wakeup_event(struct pci_dev *dev) -{ - if (device_may_wakeup(&dev->dev)) - pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN); -} - /** * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set. * @dev: Device to handle. diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 16ae9659346b..f69d6e0fda75 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -74,6 +74,12 @@ extern void pci_pm_init(struct pci_dev *dev); extern void platform_pci_wakeup_init(struct pci_dev *dev); extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); +static inline void pci_wakeup_event(struct pci_dev *dev) +{ + /* Wait 100 ms before the system can be put into a sleep state. */ + pm_wakeup_event(&dev->dev, 100); +} + static inline bool pci_is_bridge(struct pci_dev *pci_dev) { return !!(pci_dev->subordinate); diff --git a/include/linux/pci.h b/include/linux/pci.h index 12dd86a82a15..9e67dcd054c4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -820,7 +820,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev); int pci_back_from_sleep(struct pci_dev *dev); bool pci_dev_run_wake(struct pci_dev *dev); bool pci_check_pme_status(struct pci_dev *dev); -void pci_wakeup_event(struct pci_dev *dev); void pci_pme_wakeup_bus(struct pci_bus *bus); static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, -- cgit v1.2.3 From 0f953bf6b4efa0daddb7c418130a9bd3ee97f7ed Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 29 Dec 2010 13:22:08 +0100 Subject: PCI/PM: Report wakeup events before resuming devices Make wakeup events be reported by the PCI subsystem before attempting to resume devices or queuing up runtime resume requests for them, because wakeup events should be reported as soon as they have been detected. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci-acpi.c | 2 +- drivers/pci/pci.c | 2 +- drivers/pci/pcie/pme.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index d7ea699b8ddc..6fe0772e0e7d 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -46,9 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) struct pci_dev *pci_dev = context; if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) { + pci_wakeup_event(pci_dev); pci_check_pme_status(pci_dev); pm_runtime_resume(&pci_dev->dev); - pci_wakeup_event(pci_dev); if (pci_dev->subordinate) pci_pme_wakeup_bus(pci_dev->subordinate); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bf7ad2c09955..b714d787bddd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1308,8 +1308,8 @@ bool pci_check_pme_status(struct pci_dev *dev) static int pci_pme_wakeup(struct pci_dev *dev, void *ign) { if (pci_check_pme_status(dev)) { - pm_request_resume(&dev->dev); pci_wakeup_event(dev); + pm_request_resume(&dev->dev); } return 0; } diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 073f0308c6b2..0057344a3fcb 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -84,8 +84,8 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { /* Skip PCIe devices in case we started from a root port. */ if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { - pm_request_resume(&dev->dev); pci_wakeup_event(dev); + pm_request_resume(&dev->dev); ret = true; } @@ -187,8 +187,8 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) /* The device is there, but we have to check its PME status. */ found = pci_check_pme_status(dev); if (found) { - pm_request_resume(&dev->dev); pci_wakeup_event(dev); + pm_request_resume(&dev->dev); } pci_dev_put(dev); } else if (devfn) { -- cgit v1.2.3 From 49731baa41df404c2c3f44555869ab387363af43 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 14 Jan 2011 18:43:57 +0100 Subject: block: restore multiple bd_link_disk_holder() support Commit e09b457b (block: simplify holder symlink handling) incorrectly assumed that there is only one link at maximum. dm may use multiple links and expects block layer to track reference count for each link, which is different from and unrelated to the exclusive device holder identified by @holder when the device is opened. Remove the single holder assumption and automatic removal of the link and revive the per-link reference count tracking. The code essentially behaves the same as before commit e09b457b sans the unnecessary kobject reference count dancing. While at it, note that this facility should not be used by anyone else than the current ones. Sysfs symlinks shouldn't be abused like this and the whole thing doesn't belong in the block layer at all. Signed-off-by: Tejun Heo Reported-by: Milan Broz Cc: Jun'ichi Nomura Cc: Neil Brown Cc: linux-raid@vger.kernel.org Cc: Kay Sievers Signed-off-by: Jens Axboe --- drivers/md/dm-table.c | 1 + drivers/md/md.c | 1 + fs/block_dev.c | 93 +++++++++++++++++++++++++++++++++++++++++---------- include/linux/fs.h | 8 ++++- 4 files changed, 84 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index dffa0ac7c4f0..38e4eb1bb965 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md) if (!d->dm_dev.bdev) return; + bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md)); blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL); d->dm_dev.bdev = NULL; } diff --git a/drivers/md/md.c b/drivers/md/md.c index cf8594c5ea21..b76cfc89e1b5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) MD_BUG(); return; } + bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk); list_del_rcu(&rdev->same_set); printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); rdev->mddev = NULL; diff --git a/fs/block_dev.c b/fs/block_dev.c index fe3f59c14a02..333a7bb4cb9c 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -432,6 +432,9 @@ static void init_once(void *foo) mutex_init(&bdev->bd_mutex); INIT_LIST_HEAD(&bdev->bd_inodes); INIT_LIST_HEAD(&bdev->bd_list); +#ifdef CONFIG_SYSFS + INIT_LIST_HEAD(&bdev->bd_holder_disks); +#endif inode_init_once(&ei->vfs_inode); /* Initialize mutex for freeze. */ mutex_init(&bdev->bd_fsfreeze_mutex); @@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, } #ifdef CONFIG_SYSFS +struct bd_holder_disk { + struct list_head list; + struct gendisk *disk; + int refcnt; +}; + +static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev, + struct gendisk *disk) +{ + struct bd_holder_disk *holder; + + list_for_each_entry(holder, &bdev->bd_holder_disks, list) + if (holder->disk == disk) + return holder; + return NULL; +} + static int add_symlink(struct kobject *from, struct kobject *to) { return sysfs_create_link(from, to, kobject_name(to)); @@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to) * @bdev: the claimed slave bdev * @disk: the holding disk * + * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. + * * This functions creates the following sysfs symlinks. * * - from "slaves" directory of the holder @disk to the claimed @bdev @@ -817,47 +839,83 @@ static void del_symlink(struct kobject *from, struct kobject *to) */ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) { + struct bd_holder_disk *holder; int ret = 0; mutex_lock(&bdev->bd_mutex); - WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk); + WARN_ON_ONCE(!bdev->bd_holder); /* FIXME: remove the following once add_disk() handles errors */ if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) goto out_unlock; - ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); - if (ret) + holder = bd_find_holder_disk(bdev, disk); + if (holder) { + holder->refcnt++; goto out_unlock; + } - ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); - if (ret) { - del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); + holder = kzalloc(sizeof(*holder), GFP_KERNEL); + if (!holder) { + ret = -ENOMEM; goto out_unlock; } - bdev->bd_holder_disk = disk; + INIT_LIST_HEAD(&holder->list); + holder->disk = disk; + holder->refcnt = 1; + + ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); + if (ret) + goto out_free; + + ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); + if (ret) + goto out_del; + + list_add(&holder->list, &bdev->bd_holder_disks); + goto out_unlock; + +out_del: + del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); +out_free: + kfree(holder); out_unlock: mutex_unlock(&bdev->bd_mutex); return ret; } EXPORT_SYMBOL_GPL(bd_link_disk_holder); -static void bd_unlink_disk_holder(struct block_device *bdev) +/** + * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder() + * @bdev: the calimed slave bdev + * @disk: the holding disk + * + * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. + * + * CONTEXT: + * Might sleep. + */ +void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) { - struct gendisk *disk = bdev->bd_holder_disk; + struct bd_holder_disk *holder; - bdev->bd_holder_disk = NULL; - if (!disk) - return; + mutex_lock(&bdev->bd_mutex); - del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); - del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); + holder = bd_find_holder_disk(bdev, disk); + + if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) { + del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); + del_symlink(bdev->bd_part->holder_dir, + &disk_to_dev(disk)->kobj); + list_del_init(&holder->list); + kfree(holder); + } + + mutex_unlock(&bdev->bd_mutex); } -#else -static inline void bd_unlink_disk_holder(struct block_device *bdev) -{ } +EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); #endif /** @@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode) * unblock evpoll if it was a write holder. */ if (bdev_free) { - bd_unlink_disk_holder(bdev); if (bdev->bd_write_holder) { disk_unblock_events(bdev->bd_disk); bdev->bd_write_holder = false; diff --git a/include/linux/fs.h b/include/linux/fs.h index 3984f2358d1f..fb2190349cdf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -666,7 +666,7 @@ struct block_device { int bd_holders; bool bd_write_holder; #ifdef CONFIG_SYSFS - struct gendisk * bd_holder_disk; /* for sysfs slave linkng */ + struct list_head bd_holder_disks; #endif struct block_device * bd_contains; unsigned bd_block_size; @@ -2058,12 +2058,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, extern int blkdev_put(struct block_device *bdev, fmode_t mode); #ifdef CONFIG_SYSFS extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); +extern void bd_unlink_disk_holder(struct block_device *bdev, + struct gendisk *disk); #else static inline int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) { return 0; } +static inline void bd_unlink_disk_holder(struct block_device *bdev, + struct gendisk *disk) +{ +} #endif #endif -- cgit v1.2.3 From 5219bf884b6e2b54e734ca1799b6f0014bb2b4b7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 14 Jan 2011 22:03:49 +0100 Subject: i2c: Unregister dummy devices last on adapter removal Remove real devices first and dummy devices last. This gives device driver which instantiated dummy devices themselves a chance to clean them up before we do. Signed-off-by: Jean Delvare Tested-by: Hans Verkuil Cc: stable@kernel.org --- drivers/i2c/i2c-core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c7db6980e3a3..b916675605b4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1019,6 +1019,14 @@ static int i2c_do_del_adapter(struct i2c_driver *driver, } static int __unregister_client(struct device *dev, void *dummy) +{ + struct i2c_client *client = i2c_verify_client(dev); + if (client && strcmp(client->name, "dummy")) + i2c_unregister_device(client); + return 0; +} + +static int __unregister_dummy(struct device *dev, void *dummy) { struct i2c_client *client = i2c_verify_client(dev); if (client) @@ -1075,8 +1083,12 @@ int i2c_del_adapter(struct i2c_adapter *adap) mutex_unlock(&adap->userspace_clients_lock); /* Detach any active clients. This can't fail, thus we do not - checking the returned value. */ + * check the returned value. This is a two-pass process, because + * we can't remove the dummy devices during the first pass: they + * could have been instantiated by real devices wishing to clean + * them up properly, so we give them a chance to do that first. */ res = device_for_each_child(&adap->dev, NULL, __unregister_client); + res = device_for_each_child(&adap->dev, NULL, __unregister_dummy); #ifdef CONFIG_I2C_COMPAT class_compat_remove_link(i2c_adapter_compat_class, &adap->dev, -- cgit v1.2.3 From d529de2994880d345d7588f92d5a426f63089ba3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 14 Jan 2011 22:03:49 +0100 Subject: i2c: Factor out runtime suspend checks from PM operations When devices use dev_pm_ops the I2C API is implementing standard functionality for integration with runtime PM and for checking for the presence of a per device op. The PM core provides pm_generic_ functions implementing this behaviour - use them to reduce coupling with future PM updates. Signed-off-by: Mark Brown Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 68 +++++++++++++++----------------------------------- 1 file changed, 20 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b916675605b4..0f9dc7dc15f1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -196,88 +196,60 @@ static int i2c_device_pm_suspend(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm) { - if (pm_runtime_suspended(dev)) - return 0; - else - return pm->suspend ? pm->suspend(dev) : 0; - } - - return i2c_legacy_suspend(dev, PMSG_SUSPEND); + if (pm) + return pm_generic_suspend(dev); + else + return i2c_legacy_suspend(dev, PMSG_SUSPEND); } static int i2c_device_pm_resume(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - int ret; if (pm) - ret = pm->resume ? pm->resume(dev) : 0; + return pm_generic_resume(dev); else - ret = i2c_legacy_resume(dev); - - return ret; + return i2c_legacy_resume(dev); } static int i2c_device_pm_freeze(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm) { - if (pm_runtime_suspended(dev)) - return 0; - else - return pm->freeze ? pm->freeze(dev) : 0; - } - - return i2c_legacy_suspend(dev, PMSG_FREEZE); + if (pm) + return pm_generic_freeze(dev); + else + return i2c_legacy_suspend(dev, PMSG_FREEZE); } static int i2c_device_pm_thaw(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm) { - if (pm_runtime_suspended(dev)) - return 0; - else - return pm->thaw ? pm->thaw(dev) : 0; - } - - return i2c_legacy_resume(dev); + if (pm) + return pm_generic_thaw(dev); + else + return i2c_legacy_resume(dev); } static int i2c_device_pm_poweroff(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm) { - if (pm_runtime_suspended(dev)) - return 0; - else - return pm->poweroff ? pm->poweroff(dev) : 0; - } - - return i2c_legacy_suspend(dev, PMSG_HIBERNATE); + if (pm) + return pm_generic_poweroff(dev); + else + return i2c_legacy_suspend(dev, PMSG_HIBERNATE); } static int i2c_device_pm_restore(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - int ret; if (pm) - ret = pm->restore ? pm->restore(dev) : 0; + return pm_generic_restore(dev); else - ret = i2c_legacy_resume(dev); - - if (!ret) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - - return ret; + return i2c_legacy_resume(dev); } #else /* !CONFIG_PM_SLEEP */ #define i2c_device_pm_suspend NULL -- cgit v1.2.3 From f4e8db31a83ad019e9ae06edb9c2f89de66bc7b7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 14 Jan 2011 22:03:50 +0100 Subject: i2c: Encourage move to dev_pm_ops by warning on use of legacy methods Since the PM core wishes to transition away from the legacy suspend and resume methods and since removing them makes using PM core features like runtime PM much easier start warning when a driver is registered using the legacy methods. Signed-off-by: Mark Brown Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0f9dc7dc15f1..f0bd5bcdf563 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1124,6 +1124,14 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; + /* Drivers should switch to dev_pm_ops instead. */ + if (driver->suspend) + pr_warn("i2c-core: driver [%s] using legacy suspend method\n", + driver->driver.name); + if (driver->resume) + pr_warn("i2c-core: driver [%s] using legacy resume method\n", + driver->driver.name); + pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); -- cgit v1.2.3 From 94a1b6d8eb903818773ad24fe48529b0d295052d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 13 Jan 2011 17:24:22 +0530 Subject: spi/amba-pl022: fixing compilation warning. clk_freq is used uninitialized in pl022_setup routine. This patch fix compilation warning for using uninitialized variable Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/spi/amba-pl022.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index a2a5921c730a..71a1219a995d 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -1795,7 +1795,7 @@ static int pl022_setup(struct spi_device *spi) { struct pl022_config_chip const *chip_info; struct chip_data *chip; - struct ssp_clock_params clk_freq; + struct ssp_clock_params clk_freq = {0, }; int status = 0; struct pl022 *pl022 = spi_master_get_devdata(spi->master); unsigned int bits = spi->bits_per_word; -- cgit v1.2.3 From 9a1fe2f27f71dd275caf2be5be2fa59bd2a3f8d4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 14 Jan 2011 23:25:57 +0100 Subject: ACPI / ACPICA: Initialize the global lock spinlock as appropriate Commit 9cd0314 (ACPI / ACPICA: Fix global lock acquisition) forgot to initialize the spinlock it added. Fix that. Reported-and-tested-by: Sergey Senozhatsky Signed-off-by: Rafael J. Wysocki Tested-by: Linus Torvalds Signed-off-by: Linus Torvalds --- drivers/acpi/acpica/acglobal.h | 2 ++ drivers/acpi/acpica/evmisc.c | 2 -- drivers/acpi/acpica/utmutex.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 9bb69c59bb12..0e4dba0d0325 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -228,8 +228,10 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_present; */ ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock; /* For GPE data structs and registers */ ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */ +ACPI_EXTERN spinlock_t _acpi_ev_global_lock_pending_lock; /* For global lock */ #define acpi_gbl_gpe_lock &_acpi_gbl_gpe_lock #define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock +#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock /***************************************************************************** * diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 8e31bb5a973a..38bba66fcce5 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -293,8 +293,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) * ******************************************************************************/ static u8 acpi_ev_global_lock_pending; -static spinlock_t _acpi_ev_global_lock_pending_lock; -#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock static u32 acpi_ev_global_lock_handler(void *context) { diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index d9efa495b433..199528ff7f1d 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -85,6 +85,7 @@ acpi_status acpi_ut_mutex_initialize(void) spin_lock_init(acpi_gbl_gpe_lock); spin_lock_init(acpi_gbl_hardware_lock); + spin_lock_init(acpi_ev_global_lock_pending_lock); /* Mutex for _OSI support */ status = acpi_os_create_mutex(&acpi_gbl_osi_mutex); -- cgit v1.2.3 From 3632ef8909118db9584e1bed9538dc180adb32f8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 15 Jan 2011 09:27:00 +1000 Subject: Revert "drm: Update fbdev fb_fix_screeninfo" This reverts commit dfe63bb0ad9810db13aab0058caba97866e0a681. This commit was causing nouveau not to work properly, for -rc1 I'd prefer it worked and we can look if this is useful for 2.6.39. Cc: James Simmons Signed-off-by: Dave Airlie Signed-off-by: Linus Torvalds --- drivers/gpu/drm/drm_fb_helper.c | 41 ++++++++++++++++----------------- drivers/gpu/drm/i915/intel_fb.c | 1 + drivers/gpu/drm/nouveau/nouveau_fbcon.c | 1 + drivers/gpu/drm/radeon/radeon_fb.c | 2 ++ include/drm/drm_fb_helper.h | 3 +++ 5 files changed, 27 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0307d601f5e5..5c4f9b9ecdc0 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -607,25 +607,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_fini); -void drm_fb_helper_fill_fix(struct fb_info *info, struct drm_framebuffer *fb) -{ - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = fb->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : - FB_VISUAL_TRUECOLOR; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; - info->fix.type_aux = 0; - info->fix.xpanstep = 1; /* doing it in hw */ - info->fix.ypanstep = 1; /* doing it in hw */ - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.type_aux = 0; - - info->fix.line_length = fb->pitch; - return; -} -EXPORT_SYMBOL(drm_fb_helper_fill_fix); - static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { @@ -835,7 +816,6 @@ int drm_fb_helper_set_par(struct fb_info *info) mutex_unlock(&dev->mode_config.mutex); return ret; } - drm_fb_helper_fill_fix(info, fb_helper->fb); } mutex_unlock(&dev->mode_config.mutex); @@ -973,7 +953,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (new_fb) { info->var.pixclock = 0; - drm_fb_helper_fill_fix(info, fb_helper->fb); if (register_framebuffer(info) < 0) { return -EINVAL; } @@ -1000,6 +979,26 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); +void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, + uint32_t depth) +{ + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : + FB_VISUAL_TRUECOLOR; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; + info->fix.type_aux = 0; + info->fix.xpanstep = 1; /* doing it in hw */ + info->fix.ypanstep = 1; /* doing it in hw */ + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_NONE; + info->fix.type_aux = 0; + + info->fix.line_length = pitch; + return; +} +EXPORT_SYMBOL(drm_fb_helper_fill_fix); + void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height) { diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ee145a257287..512782728e51 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -148,6 +148,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, // memset(info->screen_base, 0, size); + drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); info->pixmap.size = 64*1024; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index a26d04740c88..6d56a54b6e2e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -359,6 +359,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); info->screen_size = size; + drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); /* Set aperture base/size for vesafb takeover */ diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index ca32e9c1e91d..66324b5bb5ba 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -225,6 +225,8 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, strcpy(info->fix.id, "radeondrmfb"); + drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); + info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &radeonfb_ops; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index aac27bd56e89..f22e7fe4b6db 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -121,6 +121,9 @@ int drm_fb_helper_setcolreg(unsigned regno, void drm_fb_helper_restore(void); void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height); +void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, + uint32_t depth); + int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); -- cgit v1.2.3 From 2cdf2455a660ea860272ef3f833f0e5c4cc80205 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Wed, 5 Jan 2011 17:43:52 +0900 Subject: pch_dma: support new device ML7213 IOH Support new device OKI SEMICONDUCTOR's ML7213 IOH(Input/Output Hub) which is for IVI(In-Vehicle Infotainment) use. The ML7213 is companion chip for Intel Atom E6xx series. The ML7213 is completely compatible for Intel EG20T PCH. Signed-off-by: Tomoya MORINAGA Signed-off-by: Dan Williams --- drivers/dma/Kconfig | 9 +++++++-- drivers/dma/pch_dma.c | 19 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 6ee23592700a..1b61d3aa2962 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -200,11 +200,16 @@ config PL330_DMA platform_data for a dma-pl330 device. config PCH_DMA - tristate "Topcliff (Intel EG20T) PCH DMA support" + tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH DMA support" depends on PCI && X86 select DMA_ENGINE help - Enable support for the Topcliff (Intel EG20T) PCH DMA engine. + Enable support for Intel EG20T PCH DMA engine. + + This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/ + Output Hub) which is for IVI(In-Vehicle Infotainment) use. + ML7213 is companion chip for Intel Atom E6xx series. + ML7213 is completely compatible for Intel EG20T PCH. config IMX_SDMA tristate "i.MX SDMA support" diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index c064c89420d0..1c38418ae61f 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -1,6 +1,7 @@ /* * Topcliff PCH DMA controller driver * Copyright (c) 2010 Intel Corporation + * Copyright (C) 2011 OKI SEMICONDUCTOR CO., LTD. * * 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 @@ -921,12 +922,19 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev) } /* PCI Device ID of DMA device */ -#define PCI_DEVICE_ID_PCH_DMA_8CH 0x8810 -#define PCI_DEVICE_ID_PCH_DMA_4CH 0x8815 +#define PCI_VENDOR_ID_ROHM 0x10DB +#define PCI_DEVICE_ID_EG20T_PCH_DMA_8CH 0x8810 +#define PCI_DEVICE_ID_EG20T_PCH_DMA_4CH 0x8815 +#define PCI_DEVICE_ID_ML7213_DMA1_8CH 0x8026 +#define PCI_DEVICE_ID_ML7213_DMA2_8CH 0x802B +#define PCI_DEVICE_ID_ML7213_DMA3_4CH 0x8034 static const struct pci_device_id pch_dma_id_table[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_8CH), 8 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_4CH), 4 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_4CH), 4 }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA1_8CH), 8}, /* UART Video */ + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA2_8CH), 8}, /* PCMIF SPI */ + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA3_4CH), 4}, /* FPGA */ { 0, }, }; @@ -954,6 +962,7 @@ static void __exit pch_dma_exit(void) module_init(pch_dma_init); module_exit(pch_dma_exit); -MODULE_DESCRIPTION("Topcliff PCH DMA controller driver"); +MODULE_DESCRIPTION("Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH " + "DMA controller driver"); MODULE_AUTHOR("Yong Wang "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 0f70e8cea3ac6a765289811c590a16934bf47711 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 15 Dec 2010 18:50:16 +0100 Subject: dmaengine: at_hdmac: use dma_address to program DMA hardware In atc_prep_slave_sg() function we use dma_address field of scatterlist with sg_dma_address() macro instead of sg_phys(). DMA address is already computed by dma_map_sg() or another mapping function in calling driver. Signed-off-by: Nicolas Ferre Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index a0f3e6a06e06..6eea8883ecf3 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -670,7 +670,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (!desc) goto err_desc_get; - mem = sg_phys(sg); + mem = sg_dma_address(sg); len = sg_dma_len(sg); mem_width = 2; if (unlikely(mem & 3 || len & 3)) @@ -712,7 +712,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (!desc) goto err_desc_get; - mem = sg_phys(sg); + mem = sg_dma_address(sg); len = sg_dma_len(sg); mem_width = 2; if (unlikely(mem & 3 || len & 3)) -- cgit v1.2.3 From ebcf9b80f9657f44fcb60ee17abe14eadebf3386 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 12 Jan 2011 15:39:06 +0100 Subject: dmaengine: at_hdmac: trivial add precision to unmapping comment Signed-off-by: Nicolas Ferre Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 6eea8883ecf3..73a470b4809b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -253,7 +253,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) /* move myself to free_list */ list_move(&desc->desc_node, &atchan->free_list); - /* unmap dma addresses */ + /* unmap dma addresses (not on slave channels) */ if (!atchan->chan_common.private) { struct device *parent = chan2parent(&atchan->chan_common); if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { -- cgit v1.2.3 From 58344f25cf5f3453bfcf4b845ea9ec71153e45c3 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 12 Jan 2011 15:39:07 +0100 Subject: dmaengine: at_hdmac: no need set ACK in new descriptor Following descriptor flow in at_hdmac driver, descriptor comming from atc_desc_get() as already DMA_CTRL_ACK flag set. No need to set it again. Signed-off-by: Nicolas Ferre Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 73a470b4809b..c6ddd6ffb8f3 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -583,7 +583,6 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, desc->lli.ctrlb = ctrlb; desc->txd.cookie = 0; - async_tx_ack(&desc->txd); if (!first) { first = desc; -- cgit v1.2.3 From 93d0bec2be4b0f036a27da207ecab97fc3d3bbbe Mon Sep 17 00:00:00 2001 From: Eric Xu Date: Wed, 12 Jan 2011 15:39:08 +0100 Subject: dmaengine: at_hdmac: use subsys_initcall instead of module_init Use subsys_initcall instead of module_init in order to keep DMA engine rolling before other peripheral drivers. Signed-off-by: Eric Xu Signed-off-by: Nicolas Ferre Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index c6ddd6ffb8f3..e25c4ad01062 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1209,7 +1209,7 @@ static int __init at_dma_init(void) { return platform_driver_probe(&at_dma_driver, at_dma_probe); } -module_init(at_dma_init); +subsys_initcall(at_dma_init); static void __exit at_dma_exit(void) { -- cgit v1.2.3 From 568f7f0c2e597671d3e646e0b85c95c4a5756fef Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 12 Jan 2011 15:39:09 +0100 Subject: dmaengine: at_hdmac: flags located in first descriptor Place flags on first descriptor of chain instead of last. This is the one used by atc_chain_complete() function while unmapping. Signed-off-by: Nicolas Ferre Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index e25c4ad01062..3938db210834 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -603,7 +603,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, /* set end-of-link to the last link descriptor of list*/ set_desc_eol(desc); - desc->txd.flags = flags; /* client is in control of this ack */ + first->txd.flags = flags; /* client is in control of this ack */ return &first->txd; @@ -748,8 +748,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first->txd.cookie = -EBUSY; first->len = total_len; - /* last link descriptor of list is responsible of flags */ - prev->txd.flags = flags; /* client is in control of this ack */ + /* first link descriptor of list is responsible of flags */ + first->txd.flags = flags; /* client is in control of this ack */ return &first->txd; -- cgit v1.2.3 From dda36f9821321edf65d69da5c0807df7e73d26fc Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 12 Jan 2011 15:39:10 +0100 Subject: dmaengine: at_hdmac: fix race while monitoring channel status We were reading channel status then taking a lock. This lead to a race because this lock may delay us and then make this channel not idle anymore. Signed-off-by: Nicolas Ferre Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 3938db210834..40f2bf4ae474 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -853,11 +853,11 @@ static void atc_issue_pending(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "issue_pending\n"); + spin_lock_bh(&atchan->lock); if (!atc_chan_is_enabled(atchan)) { - spin_lock_bh(&atchan->lock); atc_advance_work(atchan); - spin_unlock_bh(&atchan->lock); } + spin_unlock_bh(&atchan->lock); } /** -- cgit v1.2.3 From 0261f7416362f6affc2d4fe7fea9320a6bdaaee6 Mon Sep 17 00:00:00 2001 From: Wei Yongquan Date: Wed, 29 Dec 2010 20:30:55 +0800 Subject: Update CONFIG_MD_RAID6_PQ to CONFIG_RAID6_PQ in drivers/dma/iop-adma.c Commit f5e70d0fe3ea990cfb3fc8d7f76a719adcb1e0b5 renamed MD_RAID6_PQ to RAID6_PQ, but iop-adma.c didn't update synchronously. Signed-off-by: Wei Yongquan Signed-off-by: Dan Williams --- drivers/dma/iop-adma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 161c452923b8..c6b01f535b29 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -1261,7 +1261,7 @@ out: return err; } -#ifdef CONFIG_MD_RAID6_PQ +#ifdef CONFIG_RAID6_PQ static int __devinit iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device) { @@ -1584,7 +1584,7 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_PQ, dma_dev->cap_mask) && dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) { - #ifdef CONFIG_MD_RAID6_PQ + #ifdef CONFIG_RAID6_PQ ret = iop_adma_pq_zero_sum_self_test(adev); dev_dbg(&pdev->dev, "pq self test returned %d\n", ret); #else -- cgit v1.2.3 From cc53ce53c86924bfe98a12ea20b7465038a08792 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Jan 2011 18:45:26 +0000 Subject: Add a dentry op to allow processes to be held during pathwalk transit Add a dentry op (d_manage) to permit a filesystem to hold a process and make it sleep when it tries to transit away from one of that filesystem's directories during a pathwalk. The operation is keyed off a new dentry flag (DCACHE_MANAGE_TRANSIT). The filesystem is allowed to be selective about which processes it holds and which it permits to continue on or prohibits from transiting from each flagged directory. This will allow autofs to hold up client processes whilst letting its userspace daemon through to maintain the directory or the stuff behind it or mounted upon it. The ->d_manage() dentry operation: int (*d_manage)(struct path *path, bool mounting_here); takes a pointer to the directory about to be transited away from and a flag indicating whether the transit is undertaken by do_add_mount() or do_move_mount() skipping through a pile of filesystems mounted on a mountpoint. It should return 0 if successful and to let the process continue on its way; -EISDIR to prohibit the caller from skipping to overmounted filesystems or automounting, and to use this directory; or some other error code to return to the user. ->d_manage() is called with namespace_sem writelocked if mounting_here is true and no other locks held, so it may sleep. However, if mounting_here is true, it may not initiate or wait for a mount or unmount upon the parameter directory, even if the act is actually performed by userspace. Within fs/namei.c, follow_managed() is extended to check with d_manage() first on each managed directory, before transiting away from it or attempting to automount upon it. follow_down() is renamed follow_down_one() and should only be used where the filesystem deliberately intends to avoid management steps (e.g. autofs). A new follow_down() is added that incorporates the loop done by all other callers of follow_down() (do_add/move_mount(), autofs and NFSD; whilst AFS, NFS and CIFS do use it, their use is removed by converting them to use d_automount()). The new follow_down() calls d_manage() as appropriate. It also takes an extra parameter to indicate if it is being called from mount code (with namespace_sem writelocked) which it passes to d_manage(). follow_down() ignores automount points so that it can be used to mount on them. __follow_mount_rcu() is made to abort rcu-walk mode if it hits a directory with DCACHE_MANAGE_TRANSIT set on the basis that we're probably going to have to sleep. It would be possible to enter d_manage() in rcu-walk mode too, and have that determine whether to abort or not itself. That would allow the autofs daemon to continue on in rcu-walk mode. Note that DCACHE_MANAGE_TRANSIT on a directory should be cleared when it isn't required as every tranist from that directory will cause d_manage() to be invoked. It can always be set again when necessary. ========================== WHAT THIS MEANS FOR AUTOFS ========================== Autofs currently uses the lookup() inode op and the d_revalidate() dentry op to trigger the automounting of indirect mounts, and both of these can be called with i_mutex held. autofs knows that the i_mutex will be held by the caller in lookup(), and so can drop it before invoking the daemon - but this isn't so for d_revalidate(), since the lock is only held on _some_ of the code paths that call it. This means that autofs can't risk dropping i_mutex from its d_revalidate() function before it calls the daemon. The bug could manifest itself as, for example, a process that's trying to validate an automount dentry that gets made to wait because that dentry is expired and needs cleaning up: mkdir S ffffffff8014e05a 0 32580 24956 Call Trace: [] :autofs4:autofs4_wait+0x674/0x897 [] avc_has_perm+0x46/0x58 [] autoremove_wake_function+0x0/0x2e [] :autofs4:autofs4_expire_wait+0x41/0x6b [] :autofs4:autofs4_revalidate+0x91/0x149 [] __lookup_hash+0xa0/0x12f [] lookup_create+0x46/0x80 [] sys_mkdirat+0x56/0xe4 versus the automount daemon which wants to remove that dentry, but can't because the normal process is holding the i_mutex lock: automount D ffffffff8014e05a 0 32581 1 32561 Call Trace: [] __mutex_lock_slowpath+0x60/0x9b [] do_path_lookup+0x2ca/0x2f1 [] .text.lock.mutex+0xf/0x14 [] do_rmdir+0x77/0xde [] tracesys+0x71/0xe0 [] tracesys+0xd5/0xe0 which means that the system is deadlocked. This patch allows autofs to hold up normal processes whilst the daemon goes ahead and does things to the dentry tree behind the automouter point without risking a deadlock as almost no locks are held in d_manage() and none in d_automount(). Signed-off-by: David Howells Was-Acked-by: Ian Kent Signed-off-by: Al Viro --- Documentation/filesystems/Locking | 2 ++ Documentation/filesystems/vfs.txt | 21 +++++++++++- drivers/staging/autofs/dirhash.c | 5 ++- fs/afs/mntpt.c | 5 +-- fs/autofs4/autofs_i.h | 13 ------- fs/autofs4/dev-ioctl.c | 2 +- fs/autofs4/expire.c | 2 +- fs/autofs4/root.c | 11 +++--- fs/cifs/cifs_dfs_ref.c | 5 +-- fs/namei.c | 72 +++++++++++++++++++++++++++++++++++++-- fs/namespace.c | 14 ++++---- fs/nfs/namespace.c | 5 +-- fs/nfsd/vfs.c | 5 +-- include/linux/dcache.h | 11 ++++-- include/linux/namei.h | 3 +- 15 files changed, 126 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 5f0c52a07386..cbf98b989b11 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -20,6 +20,7 @@ prototypes: void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); struct vfsmount *(*d_automount)(struct path *path); + int (*d_manage)(struct dentry *, bool); locking rules: rename_lock ->d_lock may block rcu-walk @@ -31,6 +32,7 @@ d_release: no no yes no d_iput: no no yes no d_dname: no no no no d_automount: no no yes no +d_manage: no no yes no --------------------------- inode_operations --------------------------- prototypes: diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 726a4f6fa3c9..4682586b147a 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -865,6 +865,7 @@ struct dentry_operations { void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); + int (*d_manage)(struct dentry *, bool); }; d_revalidate: called when the VFS needs to revalidate a dentry. This @@ -938,12 +939,30 @@ struct dentry_operations { target and the parent VFS mount record to provide inheritable mount parameters. NULL should be returned if someone else managed to make the automount first. If the automount failed, then an error code - should be returned. + should be returned. If -EISDIR is returned, then the directory will + be treated as an ordinary directory and returned to pathwalk to + continue walking. This function is only used if DCACHE_NEED_AUTOMOUNT is set on the dentry. This is set by __d_instantiate() if S_AUTOMOUNT is set on the inode being added. + d_manage: called to allow the filesystem to manage the transition from a + dentry (optional). This allows autofs, for example, to hold up clients + waiting to explore behind a 'mountpoint' whilst letting the daemon go + past and construct the subtree there. 0 should be returned to let the + calling process continue. -EISDIR can be returned to tell pathwalk to + use this directory as an ordinary directory and to ignore anything + mounted on it and not to check the automount flag. Any other error + code will abort pathwalk completely. + + If the 'mounting_here' parameter is true, then namespace_sem is being + held by the caller and the function should not initiate any mounts or + unmounts that it will then wait for. + + This function is only used if DCACHE_MANAGE_TRANSIT is set on the + dentry being transited from. + Example : static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen) diff --git a/drivers/staging/autofs/dirhash.c b/drivers/staging/autofs/dirhash.c index d3f42c8325f7..a08bd7355035 100644 --- a/drivers/staging/autofs/dirhash.c +++ b/drivers/staging/autofs/dirhash.c @@ -88,14 +88,13 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, } path.mnt = mnt; path_get(&path); - if (!follow_down(&path)) { + if (!follow_down_one(&path)) { path_put(&path); DPRINTK(("autofs: not expirable\ (not a mounted directory): %s\n", ent->name)); continue; } - while (d_mountpoint(path.dentry) && follow_down(&path)) - ; + follow_down(&path, false); // TODO: need to check error umount_ok = may_umount(path.mnt); path_put(&path); diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index e83c0336e7b5..f3e891d57a2c 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -273,10 +273,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) break; case -EBUSY: /* someone else made a mount here whilst we were busy */ - while (d_mountpoint(nd->path.dentry) && - follow_down(&nd->path)) - ; - err = 0; + err = follow_down(&nd->path, false); default: mntput(newmnt); break; diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 0fffe1c24cec..eb67953452bb 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -229,19 +229,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); void autofs4_catatonic_mode(struct autofs_sb_info *); -static inline int autofs4_follow_mount(struct path *path) -{ - int res = 0; - - while (d_mountpoint(path->dentry)) { - int followed = follow_down(path); - if (!followed) - break; - res = 1; - } - return res; -} - static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) { return new_encode_dev(sbi->sb->s_dev); diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index eff9a419469a..1442da4860e5 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, err = have_submounts(path.dentry); - if (follow_down(&path)) + if (follow_down_one(&path)) magic = path.mnt->mnt_sb->s_magic; } diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index cc1d01365905..6a930b90d389 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -56,7 +56,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) path_get(&path); - if (!follow_down(&path)) + if (!follow_down_one(&path)) goto done; if (is_autofs4_dentry(path.dentry)) { diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 651e4ef563b1..20225636a4e9 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -234,7 +234,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) nd->flags); /* * For an expire of a covered direct or offset mount we need - * to break out of follow_down() at the autofs mount trigger + * to break out of follow_down_one() at the autofs mount trigger * (d_mounted--), so we can see the expiring flag, and manage * the blocking and following here until the expire is completed. */ @@ -243,7 +243,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) if (ino->flags & AUTOFS_INF_EXPIRING) { spin_unlock(&sbi->fs_lock); /* Follow down to our covering mount. */ - if (!follow_down(&nd->path)) + if (!follow_down_one(&nd->path)) goto done; goto follow; } @@ -292,11 +292,10 @@ follow: * multi-mount with no root offset so we don't need * to follow it. */ - if (d_mountpoint(dentry)) { - if (!autofs4_follow_mount(&nd->path)) { - status = -ENOENT; + if (d_managed(dentry)) { + status = follow_down(&nd->path, false); + if (status < 0) goto out_error; - } } done: diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index c68a056f27fd..83479cf63f96 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -273,10 +273,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, break; case -EBUSY: /* someone else made a mount here whilst we were busy */ - while (d_mountpoint(nd->path.dentry) && - follow_down(&nd->path)) - ; - err = 0; + err = follow_down(&nd->path, false); default: mntput(newmnt); break; diff --git a/fs/namei.c b/fs/namei.c index 16109da68bbf..9d3033dc22e9 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -960,6 +960,7 @@ static int follow_automount(struct path *path, unsigned flags, /* * Handle a dentry that is managed in some way. + * - Flagged for transit management (autofs) * - Flagged as mountpoint * - Flagged as automount point * @@ -979,6 +980,16 @@ static int follow_managed(struct path *path, unsigned flags) while (managed = ACCESS_ONCE(path->dentry->d_flags), managed &= DCACHE_MANAGED_DENTRY, unlikely(managed != 0)) { + /* Allow the filesystem to manage the transit without i_mutex + * being held. */ + if (managed & DCACHE_MANAGE_TRANSIT) { + BUG_ON(!path->dentry->d_op); + BUG_ON(!path->dentry->d_op->d_manage); + ret = path->dentry->d_op->d_manage(path->dentry, false); + if (ret < 0) + return ret == -EISDIR ? 0 : ret; + } + /* Transit to a mounted filesystem. */ if (managed & DCACHE_MOUNTED) { struct vfsmount *mounted = lookup_mnt(path); @@ -1012,7 +1023,7 @@ static int follow_managed(struct path *path, unsigned flags) return 0; } -int follow_down(struct path *path) +int follow_down_one(struct path *path) { struct vfsmount *mounted; @@ -1029,14 +1040,19 @@ int follow_down(struct path *path) /* * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we - * meet an automount point and we're not walking to "..". True is returned to + * meet a managed dentry and we're not walking to "..". True is returned to * continue, false to abort. */ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, struct inode **inode, bool reverse_transit) { + unsigned abort_mask = + reverse_transit ? 0 : DCACHE_MANAGE_TRANSIT; + while (d_mountpoint(path->dentry)) { struct vfsmount *mounted; + if (path->dentry->d_flags & abort_mask) + return true; mounted = __lookup_mnt(path->mnt, path->dentry, 1); if (!mounted) break; @@ -1086,6 +1102,57 @@ static int follow_dotdot_rcu(struct nameidata *nd) return 0; } +/* + * Follow down to the covering mount currently visible to userspace. At each + * point, the filesystem owning that dentry may be queried as to whether the + * caller is permitted to proceed or not. + * + * Care must be taken as namespace_sem may be held (indicated by mounting_here + * being true). + */ +int follow_down(struct path *path, bool mounting_here) +{ + unsigned managed; + int ret; + + while (managed = ACCESS_ONCE(path->dentry->d_flags), + unlikely(managed & DCACHE_MANAGED_DENTRY)) { + /* Allow the filesystem to manage the transit without i_mutex + * being held. + * + * We indicate to the filesystem if someone is trying to mount + * something here. This gives autofs the chance to deny anyone + * other than its daemon the right to mount on its + * superstructure. + * + * The filesystem may sleep at this point. + */ + if (managed & DCACHE_MANAGE_TRANSIT) { + BUG_ON(!path->dentry->d_op); + BUG_ON(!path->dentry->d_op->d_manage); + ret = path->dentry->d_op->d_manage(path->dentry, mounting_here); + if (ret < 0) + return ret == -EISDIR ? 0 : ret; + } + + /* Transit to a mounted filesystem. */ + if (managed & DCACHE_MOUNTED) { + struct vfsmount *mounted = lookup_mnt(path); + if (!mounted) + break; + dput(path->dentry); + mntput(path->mnt); + path->mnt = mounted; + path->dentry = dget(mounted->mnt_root); + continue; + } + + /* Don't handle automount points here */ + break; + } + return 0; +} + /* * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() */ @@ -3530,6 +3597,7 @@ const struct inode_operations page_symlink_inode_operations = { }; EXPORT_SYMBOL(user_path_at); +EXPORT_SYMBOL(follow_down_one); EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ diff --git a/fs/namespace.c b/fs/namespace.c index 3ddfd9046c44..d94ccd6ddafd 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1844,9 +1844,10 @@ static int do_move_mount(struct path *path, char *old_name) return err; down_write(&namespace_sem); - while (d_mountpoint(path->dentry) && - follow_down(path)) - ; + err = follow_down(path, true); + if (err < 0) + goto out; + err = -EINVAL; if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out; @@ -1940,9 +1941,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, down_write(&namespace_sem); /* Something was mounted here while we slept */ - while (d_mountpoint(path->dentry) && - follow_down(path)) - ; + err = follow_down(path, true); + if (err < 0) + goto unlock; + err = -EINVAL; if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) goto unlock; diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 74aaf3963c10..bfcb933e5755 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -176,10 +176,7 @@ out_err: path_put(&nd->path); goto out; out_follow: - while (d_mountpoint(nd->path.dentry) && - follow_down(&nd->path)) - ; - err = 0; + err = follow_down(&nd->path, false); goto out; } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 230b79fbf005..0f79e33a65d7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -88,8 +88,9 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, .dentry = dget(dentry)}; int err = 0; - while (d_mountpoint(path.dentry) && follow_down(&path)) - ; + err = follow_down(&path, false); + if (err < 0) + goto out; exp2 = rqst_exp_get_by_name(rqstp, &path); if (IS_ERR(exp2)) { diff --git a/include/linux/dcache.h b/include/linux/dcache.h index ee6c26d142c3..1a87760d6532 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -168,6 +168,7 @@ struct dentry_operations { void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); + int (*d_manage)(struct dentry *, bool); } ____cacheline_aligned; /* @@ -214,8 +215,9 @@ struct dentry_operations { #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ +#define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ #define DCACHE_MANAGED_DENTRY \ - (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT) + (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) extern seqlock_t rename_lock; @@ -404,7 +406,12 @@ static inline void dont_mount(struct dentry *dentry) extern void dput(struct dentry *); -static inline int d_mountpoint(struct dentry *dentry) +static inline bool d_managed(struct dentry *dentry) +{ + return dentry->d_flags & DCACHE_MANAGED_DENTRY; +} + +static inline bool d_mountpoint(struct dentry *dentry) { return dentry->d_flags & DCACHE_MOUNTED; } diff --git a/include/linux/namei.h b/include/linux/namei.h index 18d06add0a40..8ef2c789c2a8 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -79,7 +79,8 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry extern struct dentry *lookup_one_len(const char *, struct dentry *, int); -extern int follow_down(struct path *); +extern int follow_down_one(struct path *); +extern int follow_down(struct path *, bool); extern int follow_up(struct path *); extern struct dentry *lock_rename(struct dentry *, struct dentry *); -- cgit v1.2.3 From 672c54466d24994eb9633f993862c89539504a42 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 13 Jan 2011 15:36:09 -0700 Subject: dt/flattree: Return virtual address from early_init_dt_alloc_memory_arch() The physical address is never used by the device tree code when allocating memory for unflattening. Change the architecture's alloc hook to return the virutal address instead. Signed-off-by: Grant Likely --- arch/microblaze/kernel/prom.c | 4 ++-- arch/mips/kernel/prom.c | 6 ++---- arch/powerpc/kernel/prom.c | 4 ++-- drivers/of/fdt.c | 8 +------- include/linux/of_fdt.h | 2 +- 5 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index c881393f07fd..bceaa5543e39 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -47,9 +47,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) memblock_add(base, size); } -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return memblock_alloc(size, align); + return __va(memblock_alloc(size, align)); } #ifdef CONFIG_EARLY_PRINTK diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 9dbe58368953..a19811e98a41 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -45,11 +45,9 @@ void __init free_mem_mach(unsigned long addr, unsigned long size) return free_bootmem(addr, size); } -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return virt_to_phys( - __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)) - ); + return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 9e3132db718b..7185f0da7dc3 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -519,9 +519,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) memblock_add(base, size); } -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return memblock_alloc(size, align); + return __va(memblock_alloc(size, align)); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c787c3d95c60..af824e7e0367 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -692,12 +692,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, return 1; } -static void *__init early_device_tree_alloc(u64 size, u64 align) -{ - unsigned long mem = early_init_dt_alloc_memory_arch(size, align); - return __va(mem); -} - /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -709,7 +703,7 @@ static void *__init early_device_tree_alloc(u64 size, u64 align) void __init unflatten_device_tree(void) { __unflatten_device_tree(initial_boot_params, &allnodes, - early_device_tree_alloc); + early_init_dt_alloc_memory_arch); /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 0ef22a1f129e..c84d900fbbb3 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -97,7 +97,7 @@ extern void early_init_dt_check_for_initrd(unsigned long node); extern int early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data); extern void early_init_dt_add_memory_arch(u64 base, u64 size); -extern u64 early_init_dt_alloc_memory_arch(u64 size, u64 align); +extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align); extern u64 dt_mem_next_cell(int s, __be32 **cellp); /* -- cgit v1.2.3 From f03c65993b98eeb909a4012ce7833c5857d74755 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 14 Jan 2011 22:30:21 -0500 Subject: sanitize vfsmount refcounting changes Instead of splitting refcount between (per-cpu) mnt_count and (SMP-only) mnt_longrefs, make all references contribute to mnt_count again and keep track of how many are longterm ones. Accounting rules for longterm count: * 1 for each fs_struct.root.mnt * 1 for each fs_struct.pwd.mnt * 1 for having non-NULL ->mnt_ns * decrement to 0 happens only under vfsmount lock exclusive That allows nice common case for mntput() - since we can't drop the final reference until after mnt_longterm has reached 0 due to the rules above, mntput() can grab vfsmount lock shared and check mnt_longterm. If it turns out to be non-zero (which is the common case), we know that this is not the final mntput() and can just blindly decrement percpu mnt_count. Otherwise we grab vfsmount lock exclusive and do usual decrement-and-check of percpu mnt_count. For fs_struct.c we have mnt_make_longterm() and mnt_make_shortterm(); namespace.c uses the latter in places where we don't already hold vfsmount lock exclusive and opencodes a few remaining spots where we need to manipulate mnt_longterm. Note that we mostly revert the code outside of fs/namespace.c back to what we used to have; in particular, normal code doesn't need to care about two kinds of references, etc. And we get to keep the optimization Nick's variant had bought us... Signed-off-by: Al Viro --- drivers/mtd/mtdchar.c | 2 +- fs/anon_inodes.c | 2 +- fs/fs_struct.c | 35 ++++++++++----- fs/internal.h | 3 ++ fs/namei.c | 24 ----------- fs/namespace.c | 116 +++++++++++++++++++------------------------------- fs/pipe.c | 2 +- fs/super.c | 2 +- include/linux/mount.h | 4 +- include/linux/path.h | 2 - 10 files changed, 75 insertions(+), 117 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index ee4bb3330bdf..98240575a18d 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1201,7 +1201,7 @@ err_unregister_chdev: static void __exit cleanup_mtdchar(void) { unregister_mtd_user(&mtdchar_notifier); - mntput_long(mtd_inode_mnt); + mntput(mtd_inode_mnt); unregister_filesystem(&mtd_inodefs_type); __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); } diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index cbe57f3c4d89..c5567cb78432 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -233,7 +233,7 @@ static int __init anon_inode_init(void) return 0; err_mntput: - mntput_long(anon_inode_mnt); + mntput(anon_inode_mnt); err_unregister_filesystem: unregister_filesystem(&anon_inode_fs_type); err_exit: diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 68ca487bedb1..78b519c13536 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -4,6 +4,19 @@ #include #include #include +#include "internal.h" + +static inline void path_get_longterm(struct path *path) +{ + path_get(path); + mnt_make_longterm(path->mnt); +} + +static inline void path_put_longterm(struct path *path) +{ + mnt_make_shortterm(path->mnt); + path_put(path); +} /* * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. @@ -17,11 +30,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) write_seqcount_begin(&fs->seq); old_root = fs->root; fs->root = *path; - path_get_long(path); + path_get_longterm(path); write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); if (old_root.dentry) - path_put_long(&old_root); + path_put_longterm(&old_root); } /* @@ -36,12 +49,12 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) write_seqcount_begin(&fs->seq); old_pwd = fs->pwd; fs->pwd = *path; - path_get_long(path); + path_get_longterm(path); write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); if (old_pwd.dentry) - path_put_long(&old_pwd); + path_put_longterm(&old_pwd); } void chroot_fs_refs(struct path *old_root, struct path *new_root) @@ -59,13 +72,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) write_seqcount_begin(&fs->seq); if (fs->root.dentry == old_root->dentry && fs->root.mnt == old_root->mnt) { - path_get_long(new_root); + path_get_longterm(new_root); fs->root = *new_root; count++; } if (fs->pwd.dentry == old_root->dentry && fs->pwd.mnt == old_root->mnt) { - path_get_long(new_root); + path_get_longterm(new_root); fs->pwd = *new_root; count++; } @@ -76,13 +89,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) } while_each_thread(g, p); read_unlock(&tasklist_lock); while (count--) - path_put_long(old_root); + path_put_longterm(old_root); } void free_fs_struct(struct fs_struct *fs) { - path_put_long(&fs->root); - path_put_long(&fs->pwd); + path_put_longterm(&fs->root); + path_put_longterm(&fs->pwd); kmem_cache_free(fs_cachep, fs); } @@ -118,9 +131,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) spin_lock(&old->lock); fs->root = old->root; - path_get_long(&fs->root); + path_get_longterm(&fs->root); fs->pwd = old->pwd; - path_get_long(&fs->pwd); + path_get_longterm(&fs->pwd); spin_unlock(&old->lock); } return fs; diff --git a/fs/internal.h b/fs/internal.h index 4931060fd089..12ccb86edef7 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -73,6 +73,9 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); extern int do_add_mount(struct vfsmount *, struct path *, int); extern void mnt_clear_expiry(struct vfsmount *); +extern void mnt_make_longterm(struct vfsmount *); +extern void mnt_make_shortterm(struct vfsmount *); + extern void __init mnt_init(void); DECLARE_BRLOCK(vfsmount_lock); diff --git a/fs/namei.c b/fs/namei.c index c2e37727e3ab..8f7b41a14882 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -367,18 +367,6 @@ void path_get(struct path *path) } EXPORT_SYMBOL(path_get); -/** - * path_get_long - get a long reference to a path - * @path: path to get the reference to - * - * Given a path increment the reference count to the dentry and the vfsmount. - */ -void path_get_long(struct path *path) -{ - mntget_long(path->mnt); - dget(path->dentry); -} - /** * path_put - put a reference to a path * @path: path to put the reference to @@ -392,18 +380,6 @@ void path_put(struct path *path) } EXPORT_SYMBOL(path_put); -/** - * path_put_long - put a long reference to a path - * @path: path to put the reference to - * - * Given a path decrement the reference count to the dentry and the vfsmount. - */ -void path_put_long(struct path *path) -{ - dput(path->dentry); - mntput_long(path->mnt); -} - /** * nameidata_drop_rcu - drop this nameidata out of rcu-walk * @nd: nameidata pathwalk data to drop diff --git a/fs/namespace.c b/fs/namespace.c index d7fc05fac753..48809e21f270 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -183,7 +183,7 @@ static inline void mnt_dec_count(struct vfsmount *mnt) unsigned int mnt_get_count(struct vfsmount *mnt) { #ifdef CONFIG_SMP - unsigned int count = atomic_read(&mnt->mnt_longrefs); + unsigned int count = 0; int cpu; for_each_possible_cpu(cpu) { @@ -217,7 +217,7 @@ struct vfsmount *alloc_vfsmnt(const char *name) if (!mnt->mnt_pcp) goto out_free_devname; - atomic_set(&mnt->mnt_longrefs, 1); + this_cpu_add(mnt->mnt_pcp->mnt_count, 1); #else mnt->mnt_count = 1; mnt->mnt_writers = 0; @@ -624,8 +624,11 @@ static void commit_tree(struct vfsmount *mnt) BUG_ON(parent == mnt); list_add_tail(&head, &mnt->mnt_list); - list_for_each_entry(m, &head, mnt_list) + list_for_each_entry(m, &head, mnt_list) { m->mnt_ns = n; + atomic_inc(&m->mnt_longterm); + } + list_splice(&head, n->list.prev); list_add_tail(&mnt->mnt_hash, mount_hashtable + @@ -734,51 +737,30 @@ static inline void mntfree(struct vfsmount *mnt) deactivate_super(sb); } -#ifdef CONFIG_SMP -static inline void __mntput(struct vfsmount *mnt, int longrefs) +static void mntput_no_expire(struct vfsmount *mnt) { - if (!longrefs) { put_again: - br_read_lock(vfsmount_lock); - if (likely(atomic_read(&mnt->mnt_longrefs))) { - mnt_dec_count(mnt); - br_read_unlock(vfsmount_lock); - return; - } +#ifdef CONFIG_SMP + br_read_lock(vfsmount_lock); + if (likely(atomic_read(&mnt->mnt_longterm))) { + mnt_dec_count(mnt); br_read_unlock(vfsmount_lock); - } else { - BUG_ON(!atomic_read(&mnt->mnt_longrefs)); - if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1)) - return; + return; } + br_read_unlock(vfsmount_lock); br_write_lock(vfsmount_lock); - if (!longrefs) - mnt_dec_count(mnt); - else - atomic_dec(&mnt->mnt_longrefs); + mnt_dec_count(mnt); if (mnt_get_count(mnt)) { br_write_unlock(vfsmount_lock); return; } - if (unlikely(mnt->mnt_pinned)) { - mnt_add_count(mnt, mnt->mnt_pinned + 1); - mnt->mnt_pinned = 0; - br_write_unlock(vfsmount_lock); - acct_auto_close_mnt(mnt); - goto put_again; - } - br_write_unlock(vfsmount_lock); - mntfree(mnt); -} #else -static inline void __mntput(struct vfsmount *mnt, int longrefs) -{ -put_again: mnt_dec_count(mnt); if (likely(mnt_get_count(mnt))) return; br_write_lock(vfsmount_lock); +#endif if (unlikely(mnt->mnt_pinned)) { mnt_add_count(mnt, mnt->mnt_pinned + 1); mnt->mnt_pinned = 0; @@ -789,12 +771,6 @@ put_again: br_write_unlock(vfsmount_lock); mntfree(mnt); } -#endif - -static void mntput_no_expire(struct vfsmount *mnt) -{ - __mntput(mnt, 0); -} void mntput(struct vfsmount *mnt) { @@ -802,7 +778,7 @@ void mntput(struct vfsmount *mnt) /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ if (unlikely(mnt->mnt_expiry_mark)) mnt->mnt_expiry_mark = 0; - __mntput(mnt, 0); + mntput_no_expire(mnt); } } EXPORT_SYMBOL(mntput); @@ -815,33 +791,6 @@ struct vfsmount *mntget(struct vfsmount *mnt) } EXPORT_SYMBOL(mntget); -void mntput_long(struct vfsmount *mnt) -{ -#ifdef CONFIG_SMP - if (mnt) { - /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ - if (unlikely(mnt->mnt_expiry_mark)) - mnt->mnt_expiry_mark = 0; - __mntput(mnt, 1); - } -#else - mntput(mnt); -#endif -} -EXPORT_SYMBOL(mntput_long); - -struct vfsmount *mntget_long(struct vfsmount *mnt) -{ -#ifdef CONFIG_SMP - if (mnt) - atomic_inc(&mnt->mnt_longrefs); - return mnt; -#else - return mntget(mnt); -#endif -} -EXPORT_SYMBOL(mntget_long); - void mnt_pin(struct vfsmount *mnt) { br_write_lock(vfsmount_lock); @@ -1216,7 +1165,7 @@ void release_mounts(struct list_head *head) dput(dentry); mntput(m); } - mntput_long(mnt); + mntput(mnt); } } @@ -1240,6 +1189,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) list_del_init(&p->mnt_list); __touch_mnt_namespace(p->mnt_ns); p->mnt_ns = NULL; + atomic_dec(&p->mnt_longterm); list_del_init(&p->mnt_child); if (p->mnt_parent != p) { p->mnt_parent->mnt_ghosts++; @@ -1969,7 +1919,7 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) unlock: up_write(&namespace_sem); - mntput_long(newmnt); + mntput(newmnt); return err; } @@ -2291,6 +2241,20 @@ static struct mnt_namespace *alloc_mnt_ns(void) return new_ns; } +void mnt_make_longterm(struct vfsmount *mnt) +{ + atomic_inc(&mnt->mnt_longterm); +} + +void mnt_make_shortterm(struct vfsmount *mnt) +{ + if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) + return; + br_write_lock(vfsmount_lock); + atomic_dec(&mnt->mnt_longterm); + br_write_unlock(vfsmount_lock); +} + /* * Allocate a new namespace structure and populate it with contents * copied from the namespace of the passed in task structure. @@ -2328,14 +2292,19 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, q = new_ns->root; while (p) { q->mnt_ns = new_ns; + atomic_inc(&q->mnt_longterm); if (fs) { if (p == fs->root.mnt) { + fs->root.mnt = mntget(q); + atomic_inc(&q->mnt_longterm); + mnt_make_shortterm(p); rootmnt = p; - fs->root.mnt = mntget_long(q); } if (p == fs->pwd.mnt) { + fs->pwd.mnt = mntget(q); + atomic_inc(&q->mnt_longterm); + mnt_make_shortterm(p); pwdmnt = p; - fs->pwd.mnt = mntget_long(q); } } p = next_mnt(p, mnt_ns->root); @@ -2344,9 +2313,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, up_write(&namespace_sem); if (rootmnt) - mntput_long(rootmnt); + mntput(rootmnt); if (pwdmnt) - mntput_long(pwdmnt); + mntput(pwdmnt); return new_ns; } @@ -2379,6 +2348,7 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) new_ns = alloc_mnt_ns(); if (!IS_ERR(new_ns)) { mnt->mnt_ns = new_ns; + atomic_inc(&mnt->mnt_longterm); new_ns->root = mnt; list_add(&new_ns->list, &new_ns->root->mnt_list); } diff --git a/fs/pipe.c b/fs/pipe.c index e2e95fb46a1e..89e9e19b1b2e 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1292,7 +1292,7 @@ static int __init init_pipe_fs(void) static void __exit exit_pipe_fs(void) { unregister_filesystem(&pipe_fs_type); - mntput_long(pipe_mnt); + mntput(pipe_mnt); } fs_initcall(init_pipe_fs); diff --git a/fs/super.c b/fs/super.c index 4f6a3571a634..74e149efed81 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1141,7 +1141,7 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) return mnt; err: - mntput_long(mnt); + mntput(mnt); return ERR_PTR(err); } diff --git a/include/linux/mount.h b/include/linux/mount.h index af4765ea8fde..604f122a2326 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -60,7 +60,7 @@ struct vfsmount { struct super_block *mnt_sb; /* pointer to superblock */ #ifdef CONFIG_SMP struct mnt_pcp __percpu *mnt_pcp; - atomic_t mnt_longrefs; + atomic_t mnt_longterm; /* how many of the refs are longterm */ #else int mnt_count; int mnt_writers; @@ -96,8 +96,6 @@ extern int mnt_clone_write(struct vfsmount *mnt); extern void mnt_drop_write(struct vfsmount *mnt); extern void mntput(struct vfsmount *mnt); extern struct vfsmount *mntget(struct vfsmount *mnt); -extern void mntput_long(struct vfsmount *mnt); -extern struct vfsmount *mntget_long(struct vfsmount *mnt); extern void mnt_pin(struct vfsmount *mnt); extern void mnt_unpin(struct vfsmount *mnt); extern int __mnt_is_readonly(struct vfsmount *mnt); diff --git a/include/linux/path.h b/include/linux/path.h index a581e8c06533..edc98dec6266 100644 --- a/include/linux/path.h +++ b/include/linux/path.h @@ -10,9 +10,7 @@ struct path { }; extern void path_get(struct path *); -extern void path_get_long(struct path *); extern void path_put(struct path *); -extern void path_put_long(struct path *); static inline int path_equal(const struct path *path1, const struct path *path2) { -- cgit v1.2.3 From d3072e6a7e9bf7aca200370317f8e297be360b17 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 16 Jan 2011 20:44:22 +0100 Subject: ACPI: Fix boot problem related to APEI with acpi_disabled set Commit 415e12b23792 ("PCI/ACPI: Request _OSC control once for each root bridge (v3)") put the acpi_hest_init() call in acpi_pci_root_init() into a wrong place, presumably because the author confused acpi_pci_disabled with acpi_disabled. Bring the code ordering in acpi_pci_root_init() back to sanity. Additionally, make sure that hest_disable is set when acpi_disabled is set, which is going to prevent acpi_hest_parse(), that still may be executed for acpi_disabled=1 through aer_acpi_firmware_first(), from crashing because of uninitialized hest_tab. Reported-and-tested-by: Andres Salomon Signed-off-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds --- drivers/acpi/apei/hest.c | 6 +++--- drivers/acpi/pci_root.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 4ee58e72b730..abda3786a5d7 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -201,14 +201,14 @@ void __init acpi_hest_init(void) int rc = -ENODEV; unsigned int ghes_count = 0; - if (acpi_disabled) - return; - if (hest_disable) { pr_info(HEST_PFX "Table parsing disabled.\n"); return; } + if (acpi_disabled) + goto err; + status = acpi_get_table(ACPI_SIG_HEST, 0, (struct acpi_table_header **)&hest_tab); if (status == AE_NOT_FOUND) { diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d9766797cd98..85249395623b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -633,11 +633,11 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) static int __init acpi_pci_root_init(void) { + acpi_hest_init(); + if (acpi_pci_disabled) return 0; - acpi_hest_init(); - pci_acpi_crs_quirks(); if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) return -ENODEV; -- cgit v1.2.3 From d9f9ab51e55e36379773752ffeaac677b080d469 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 16 Jan 2011 21:13:59 +0000 Subject: net: Make NETCONSOLE_DYNAMIC depend on CONFIGFS_FS This patch fixes the following kconfig error after changing CONFIGFS_FS -> select SYSFS: fs/sysfs/Kconfig:1:error: recursive dependency detected! fs/sysfs/Kconfig:1: symbol SYSFS is selected by CONFIGFS_FS fs/configfs/Kconfig:1: symbol CONFIGFS_FS is selected by NETCONSOLE_DYNAMIC drivers/net/Kconfig:3390: symbol NETCONSOLE_DYNAMIC depends on SYSFS Signed-off-by: Nicholas A. Bellinger Cc: Joel Becker Cc: Randy Dunlap Cc: Stephen Rothwell Cc: James Bottomley --- drivers/net/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4c8bfc97fb4c..16fe4f9b719b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3389,8 +3389,7 @@ config NETCONSOLE config NETCONSOLE_DYNAMIC bool "Dynamic reconfiguration of logging targets" - depends on NETCONSOLE && SYSFS - select CONFIGFS_FS + depends on NETCONSOLE && SYSFS && CONFIGFS_FS help This option enables the ability to dynamically reconfigure target parameters (interface, IP addresses, port numbers, MAC addresses) -- cgit v1.2.3 From 2a4c97ead4b375a64063523210939b87ad225b85 Mon Sep 17 00:00:00 2001 From: Maciej Sosnowski Date: Wed, 24 Nov 2010 17:29:30 +0000 Subject: RDMA/nes: Fix bonding on iw_nes Enable configuring bonds on nes devices by adding missing support for master net_device to the driver. Signed-off-by: Maciej Sosnowski Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes.c | 24 +++++++++++++++++++----- drivers/infiniband/hw/nes/nes_cm.c | 8 +++++++- 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 0c9f0aa5d4ea..e17f52c21947 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -144,6 +144,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier, struct nes_device *nesdev; struct net_device *netdev; struct nes_vnic *nesvnic; + unsigned int is_bonded; nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n", &ifa->ifa_address, &ifa->ifa_mask); @@ -152,7 +153,8 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nesdev, nesdev->netdev[0]->name); netdev = nesdev->netdev[0]; nesvnic = netdev_priv(netdev); - if (netdev == event_netdev) { + is_bonded = (netdev->master == event_netdev); + if ((netdev == event_netdev) || is_bonded) { if (nesvnic->rdma_enabled == 0) { nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since" " RDMA is not enabled.\n", @@ -169,7 +171,10 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nes_manage_arp_cache(netdev, netdev->dev_addr, ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE); nesvnic->local_ipaddr = 0; - return NOTIFY_OK; + if (is_bonded) + continue; + else + return NOTIFY_OK; break; case NETDEV_UP: nes_debug(NES_DBG_NETDEV, "event:UP\n"); @@ -178,15 +183,24 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n"); return NOTIFY_OK; } + /* fall through */ + case NETDEV_CHANGEADDR: /* Add the address to the IP table */ - nesvnic->local_ipaddr = ifa->ifa_address; + if (netdev->master) + nesvnic->local_ipaddr = + ((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address; + else + nesvnic->local_ipaddr = ifa->ifa_address; nes_write_indexed(nesdev, NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), - ntohl(ifa->ifa_address)); + ntohl(nesvnic->local_ipaddr)); nes_manage_arp_cache(netdev, netdev->dev_addr, ntohl(nesvnic->local_ipaddr), NES_ARP_ADD); - return NOTIFY_OK; + if (is_bonded) + continue; + else + return NOTIFY_OK; break; default: break; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 25ad0f9944c0..009ec814d517 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1107,6 +1107,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi struct flowi fl; struct neighbour *neigh; int rc = arpindex; + struct net_device *netdev; struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter; memset(&fl, 0, sizeof fl); @@ -1117,7 +1118,12 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi return rc; } - neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev); + if (nesvnic->netdev->master) + netdev = nesvnic->netdev->master; + else + netdev = nesvnic->netdev; + + neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, netdev); if (neigh) { if (neigh->nud_state & NUD_VALID) { nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X" -- cgit v1.2.3 From ea623455b736d82f476460647e8b5fe5dc36f4f2 Mon Sep 17 00:00:00 2001 From: Maciej Sosnowski Date: Wed, 24 Nov 2010 17:29:38 +0000 Subject: RDMA/nes: Generate IB_EVENT_PORT_ERR/PORT_ACTIVE events Depending on link state change, IB_EVENT_PORT_ERR or IB_EVENT_PORT_ACTIVE should be generated when handling MAC interrupts. Plugging in a cable happens to result in series of interrupts changing driver's link state a number of times before finally staying at link up (e.g. link up, link down, link up, link down, ..., link up). To prevent sending series of redundant IB_EVENT_PORT_ACTIVE and IB_EVENT_PORT_ERR events, we use a timer to debounce them in nes_port_ibevent(). Signed-off-by: Maciej Sosnowski Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 14 +++++++++++++ drivers/infiniband/hw/nes/nes_hw.h | 6 ++++++ drivers/infiniband/hw/nes/nes_nic.c | 35 +++++++++++++++++++++++++-------- drivers/infiniband/hw/nes/nes_verbs.c | 37 ++++++++++++++++++++++++++++++++++- 4 files changed, 83 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 1980a461c499..2b89b06ca7c3 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2608,6 +2608,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_start_queue(nesvnic->netdev); nesvnic->linkup = 1; netif_carrier_on(nesvnic->netdev); + + spin_lock(&nesvnic->port_ibevent_lock); + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } + spin_unlock(&nesvnic->port_ibevent_lock); } } } else { @@ -2633,6 +2640,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_stop_queue(nesvnic->netdev); nesvnic->linkup = 0; netif_carrier_off(nesvnic->netdev); + + spin_lock(&nesvnic->port_ibevent_lock); + if (nesdev->iw_status == 1) { + nesdev->iw_status = 0; + nes_port_ibevent(nesvnic); + } + spin_unlock(&nesvnic->port_ibevent_lock); } } } diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 1204c3432b63..8a9ea9a4dc5d 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -1193,6 +1193,8 @@ struct nes_listener { struct nes_ib_device; +#define NES_EVENT_DELAY msecs_to_jiffies(100) + struct nes_vnic { struct nes_ib_device *nesibdev; u64 sq_full; @@ -1247,6 +1249,10 @@ struct nes_vnic { u32 lro_max_aggr; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; + struct timer_list event_timer; + enum ib_event_type delayed_event; + enum ib_event_type last_dispatched_event; + spinlock_t port_ibevent_lock; }; struct nes_ib_device { diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 5a4c36484722..81052fbcd9ba 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -144,6 +144,7 @@ static int nes_netdev_open(struct net_device *netdev) u32 nic_active_bit; u32 nic_active; struct list_head *list_pos, *list_temp; + unsigned long flags; assert(nesdev != NULL); @@ -233,18 +234,27 @@ static int nes_netdev_open(struct net_device *netdev) first_nesvnic = nesvnic; } - if (nesvnic->of_device_registered) { - nesdev->iw_status = 1; - nesdev->nesadapter->send_term_ok = 1; - nes_port_ibevent(nesvnic); - } - if (first_nesvnic->linkup) { /* Enable network packets */ nesvnic->linkup = 1; netif_start_queue(netdev); netif_carrier_on(netdev); } + + spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); + if (nesvnic->of_device_registered) { + nesdev->nesadapter->send_term_ok = 1; + if (nesvnic->linkup == 1) { + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } + } else { + nesdev->iw_status = 0; + } + } + spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); + napi_enable(&nesvnic->napi); nesvnic->netdev_open = 1; @@ -263,6 +273,7 @@ static int nes_netdev_stop(struct net_device *netdev) u32 nic_active; struct nes_vnic *first_nesvnic = NULL; struct list_head *list_pos, *list_temp; + unsigned long flags; nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n", nesvnic, nesdev, netdev, netdev->name); @@ -315,12 +326,17 @@ static int nes_netdev_stop(struct net_device *netdev) nic_active &= nic_active_mask; nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); - + spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); if (nesvnic->of_device_registered) { nesdev->nesadapter->send_term_ok = 0; nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); + if (nesvnic->linkup == 1) + nes_port_ibevent(nesvnic); } + del_timer_sync(&nesvnic->event_timer); + nesvnic->event_timer.function = NULL; + spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); + nes_destroy_nic_qp(nesvnic); nesvnic->netdev_open = 0; @@ -1750,7 +1766,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nesvnic->rdma_enabled = 0; } nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id; + init_timer(&nesvnic->event_timer); + nesvnic->event_timer.function = NULL; spin_lock_init(&nesvnic->tx_lock); + spin_lock_init(&nesvnic->port_ibevent_lock); nesdev->netdev[nesdev->netdev_count] = netdev; nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n", diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 99933e4e48ff..26d8018c0a7c 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -3936,6 +3936,30 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev) return nesibdev; } + +/** + * nes_handle_delayed_event + */ +static void nes_handle_delayed_event(unsigned long data) +{ + struct nes_vnic *nesvnic = (void *) data; + + if (nesvnic->delayed_event != nesvnic->last_dispatched_event) { + struct ib_event event; + + event.device = &nesvnic->nesibdev->ibdev; + if (!event.device) + goto stop_timer; + event.event = nesvnic->delayed_event; + event.element.port_num = nesvnic->logical_port + 1; + ib_dispatch_event(&event); + } + +stop_timer: + nesvnic->event_timer.function = NULL; +} + + void nes_port_ibevent(struct nes_vnic *nesvnic) { struct nes_ib_device *nesibdev = nesvnic->nesibdev; @@ -3944,7 +3968,18 @@ void nes_port_ibevent(struct nes_vnic *nesvnic) event.device = &nesibdev->ibdev; event.element.port_num = nesvnic->logical_port + 1; event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; - ib_dispatch_event(&event); + + if (!nesvnic->event_timer.function) { + ib_dispatch_event(&event); + nesvnic->last_dispatched_event = event.event; + nesvnic->event_timer.function = nes_handle_delayed_event; + nesvnic->event_timer.data = (unsigned long) nesvnic; + nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY; + add_timer(&nesvnic->event_timer); + } else { + mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY); + } + nesvnic->delayed_event = event.event; } -- cgit v1.2.3 From 5f61b2c6939bb6d26393df15765bc3cb260db063 Mon Sep 17 00:00:00 2001 From: Maciej Sosnowski Date: Wed, 24 Nov 2010 17:29:46 +0000 Subject: RDMA/nes: Fix SFP+ link down detection issue with switch port disable In case of SFP+ PHY, link status check at interrupt processing can give false results. For proper link status change detection a delayed recheck is needed to give nes registers time to settle. Add a periodic link status recheck scheduled at interrupt to detect potential delayed registers state changes. Addresses: http://bugs.openfabrics.org/bugzilla/show_bug.cgi?id=2117 Signed-off-by: Maciej Sosnowski Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes.c | 11 ++++++ drivers/infiniband/hw/nes/nes.h | 4 ++ drivers/infiniband/hw/nes/nes_hw.c | 81 ++++++++++++++++++++++++++++++++++++++ drivers/infiniband/hw/nes/nes_hw.h | 4 ++ 4 files changed, 100 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index e17f52c21947..3b4ec3238ceb 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -674,6 +674,8 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i } nes_notifiers_registered++; + INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status); + /* Initialize network devices */ if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) goto bail7; @@ -756,6 +758,7 @@ static void __devexit nes_remove(struct pci_dev *pcidev) struct nes_device *nesdev = pci_get_drvdata(pcidev); struct net_device *netdev; int netdev_index = 0; + unsigned long flags; if (nesdev->netdev_count) { netdev = nesdev->netdev[netdev_index]; @@ -782,6 +785,14 @@ static void __devexit nes_remove(struct pci_dev *pcidev) free_irq(pcidev->irq, nesdev); tasklet_kill(&nesdev->dpc_tasklet); + spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); + if (nesdev->link_recheck) { + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); + cancel_delayed_work_sync(&nesdev->work); + } else { + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); + } + /* Deallocate the Adapter Structure */ nes_destroy_adapter(nesdev->nesadapter); diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index b3d145e82b4c..6fe79876009e 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -268,6 +268,9 @@ struct nes_device { u8 napi_isr_ran; u8 disable_rx_flow_control; u8 disable_tx_flow_control; + + struct delayed_work work; + u8 link_recheck; }; @@ -507,6 +510,7 @@ void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *); void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *); int nes_destroy_cqp(struct nes_device *); int nes_nic_cm_xmit(struct sk_buff *, struct net_device *); +void nes_recheck_link_status(struct work_struct *work); /* nes_nic.c */ struct net_device *nes_netdev_init(struct nes_device *, void __iomem *); diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 2b89b06ca7c3..8b606fd64022 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2650,6 +2650,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) } } } + if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) { + if (nesdev->link_recheck) + cancel_delayed_work(&nesdev->work); + nesdev->link_recheck = 1; + schedule_delayed_work(&nesdev->work, + NES_LINK_RECHECK_DELAY); + } } spin_unlock_irqrestore(&nesadapter->phy_lock, flags); @@ -2657,6 +2664,80 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE; } +void nes_recheck_link_status(struct work_struct *work) +{ + unsigned long flags; + struct nes_device *nesdev = container_of(work, struct nes_device, work.work); + struct nes_adapter *nesadapter = nesdev->nesadapter; + struct nes_vnic *nesvnic; + u32 mac_index = nesdev->mac_index; + u16 phy_data; + u16 temp_phy_data; + + spin_lock_irqsave(&nesadapter->phy_lock, flags); + + /* check link status */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); + nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + + phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; + + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, + nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); + + if (phy_data & 0x0004) { + nesadapter->mac_link_down[mac_index] = 0; + list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { + if (nesvnic->linkup == 0) { + printk(PFX "The Link is now up for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); + if (netif_queue_stopped(nesvnic->netdev)) + netif_start_queue(nesvnic->netdev); + nesvnic->linkup = 1; + netif_carrier_on(nesvnic->netdev); + + spin_lock(&nesvnic->port_ibevent_lock); + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } + spin_unlock(&nesvnic->port_ibevent_lock); + } + } + + } else { + nesadapter->mac_link_down[mac_index] = 1; + list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { + if (nesvnic->linkup == 1) { + printk(PFX "The Link is now down for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); + if (!(netif_queue_stopped(nesvnic->netdev))) + netif_stop_queue(nesvnic->netdev); + nesvnic->linkup = 0; + netif_carrier_off(nesvnic->netdev); + + spin_lock(&nesvnic->port_ibevent_lock); + if (nesdev->iw_status == 1) { + nesdev->iw_status = 0; + nes_port_ibevent(nesvnic); + } + spin_unlock(&nesvnic->port_ibevent_lock); + } + } + } + if (nesdev->link_recheck++ < NES_LINK_RECHECK_MAX) + schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY); + else + nesdev->link_recheck = 0; + + spin_unlock_irqrestore(&nesadapter->phy_lock, flags); +} static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 8a9ea9a4dc5d..d2abe07133a5 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -1354,6 +1354,10 @@ struct nes_terminate_hdr { #define BAD_FRAME_OFFSET 64 #define CQE_MAJOR_DRV 0x8000 +/* Used for link status recheck after interrupt processing */ +#define NES_LINK_RECHECK_DELAY msecs_to_jiffies(50) +#define NES_LINK_RECHECK_MAX 60 + #define nes_vlan_rx vlan_hwaccel_receive_skb #define nes_netif_rx netif_receive_skb -- cgit v1.2.3 From 843276ad985cb59212ceb70d989474521ff516f6 Mon Sep 17 00:00:00 2001 From: Maciej Sosnowski Date: Wed, 24 Nov 2010 17:29:54 +0000 Subject: RDMA/nes: Fix incorrect SFP+ link status detection on driver init During iw_nes initialization the link status for SFP+ PHY is always detected as "up" regardless of real state (cable either connected or disconnected). Add SFP+ PHY specific link status detection to the iw_nes initialization procedure. Use link status recheck for netdev_open to detect delayed state updates. Signed-off-by: Maciej Sosnowski Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_nic.c | 43 +++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 81052fbcd9ba..2c9c1933bbe3 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -241,6 +241,15 @@ static int nes_netdev_open(struct net_device *netdev) netif_carrier_on(netdev); } + spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); + if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) { + if (nesdev->link_recheck) + cancel_delayed_work(&nesdev->work); + nesdev->link_recheck = 1; + schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY); + } + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); + spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); if (nesvnic->of_device_registered) { nesdev->nesadapter->send_term_ok = 1; @@ -1782,8 +1791,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { u32 u32temp; - u32 link_mask; - u32 link_val; + u32 link_mask = 0; + u32 link_val = 0; + u16 temp_phy_data; + u16 phy_data = 0; + unsigned long flags; u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1))); @@ -1805,6 +1817,23 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, link_val = 0x02020000; } break; + case NES_PHY_TYPE_SFP_D: + spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); + nes_read_10G_phy_reg(nesdev, + nesdev->nesadapter->phy_index[nesdev->mac_index], + 1, 0x9003); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + nes_read_10G_phy_reg(nesdev, + nesdev->nesadapter->phy_index[nesdev->mac_index], + 3, 0x0021); + nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + nes_read_10G_phy_reg(nesdev, + nesdev->nesadapter->phy_index[nesdev->mac_index], + 3, 0x0021); + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); + phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; + break; default: link_mask = 0x0f1f0000; link_val = 0x0f0f0000; @@ -1814,8 +1843,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1))); - if ((u32temp & link_mask) == link_val) - nesvnic->linkup = 1; + + if (phy_type == NES_PHY_TYPE_SFP_D) { + if (phy_data & 0x0004) + nesvnic->linkup = 1; + } else { + if ((u32temp & link_mask) == link_val) + nesvnic->linkup = 1; + } /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); -- cgit v1.2.3 From 94ae85220a07d357d4937086c490854f63344de4 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 16 Jan 2011 20:18:05 +0000 Subject: ARM: PL08x: cleanup comments Cleanup the formatting of comments, remove some which don't make sense anymore. Signed-off-by: Russell King [fix conflict with 96a608a4] Signed-off-by: Dan Williams --- drivers/dma/amba-pl08x.c | 146 ++++++++++++++++----------------------------- include/linux/amba/pl08x.h | 43 +++++++------ 2 files changed, 72 insertions(+), 117 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index bebc678ed4fc..297f48b0cba9 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -19,14 +19,14 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The full GNU General Public License is in this distribution in the - * file called COPYING. + * The full GNU General Public License is in this distribution in the file + * called COPYING. * * Documentation: ARM DDI 0196G == PL080 - * Documentation: ARM DDI 0218E == PL081 + * Documentation: ARM DDI 0218E == PL081 * - * PL080 & PL081 both have 16 sets of DMA signals that can be routed to - * any channel. + * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any + * channel. * * The PL080 has 8 channels available for simultaneous use, and the PL081 * has only two channels. So on these DMA controllers the number of channels @@ -91,11 +91,9 @@ #define DRIVER_NAME "pl08xdmac" /** - * struct vendor_data - vendor-specific config parameters - * for PL08x derivatives + * struct vendor_data - vendor-specific config parameters for PL08x derivatives * @channels: the number of channels available in this variant - * @dualmaster: whether this version supports dual AHB masters - * or not. + * @dualmaster: whether this version supports dual AHB masters or not. */ struct vendor_data { u8 channels; @@ -241,10 +239,8 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, * * Disabling individual channels could lose data. * - * Disable the peripheral DMA after disabling the DMAC - * in order to allow the DMAC FIFO to drain, and - * hence allow the channel to show inactive - * + * Disable the peripheral DMA after disabling the DMAC in order to allow + * the DMAC FIFO to drain, and hence allow the channel to show inactive */ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) { @@ -367,6 +363,10 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) /* * Allocate a physical channel for a virtual channel + * + * Try to locate a physical channel to be used for this transfer. If all + * are taken return NULL and the requester will have to cope by using + * some fallback PIO mode or retrying later. */ static struct pl08x_phy_chan * pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, @@ -376,12 +376,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, unsigned long flags; int i; - /* - * Try to locate a physical channel to be used for - * this transfer. If all are taken return NULL and - * the requester will have to cope by using some fallback - * PIO mode or retrying later. - */ for (i = 0; i < pl08x->vd->channels; i++) { ch = &pl08x->phy_chans[i]; @@ -495,9 +489,9 @@ struct pl08x_lli_build_data { }; /* - * Autoselect a master bus to use for the transfer - * this prefers the destination bus if both available - * if fixed address on one bus the other will be chosen + * Autoselect a master bus to use for the transfer this prefers the + * destination bus if both available if fixed address on one bus the + * other will be chosen */ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) @@ -530,8 +524,7 @@ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, } /* - * Fills in one LLI for a certain transfer descriptor - * and advance the counter + * Fills in one LLI for a certain transfer descriptor and advance the counter */ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, int num_llis, int len, u32 cctl) @@ -640,15 +633,11 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * Choose bus to align to * - prefers destination bus if both available * - if fixed address on one bus chooses other - * - modifies cctl to choose an appropriate master */ pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); if (txd->len < mbus->buswidth) { - /* - * Less than a bus width available - * - send as single bytes - */ + /* Less than a bus width available - send as single bytes */ while (bd.remainder) { dev_vdbg(&pl08x->adev->dev, "%s single byte LLIs for a transfer of " @@ -659,10 +648,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, total_bytes++; } } else { - /* - * Make one byte LLIs until master bus is aligned - * - slave will then be aligned also - */ + /* Make one byte LLIs until master bus is aligned */ while ((mbus->addr) % (mbus->buswidth)) { dev_vdbg(&pl08x->adev->dev, "%s adjustment lli for less than bus width " @@ -674,7 +660,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } /* - * Master now aligned + * Master now aligned * - if slave is not then we must set its width down */ if (sbus->addr % sbus->buswidth) { @@ -732,10 +718,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (lli_len == target_len) { /* - * Can send what we wanted - */ - /* - * Maintain alignment + * Can send what we wanted. + * Maintain alignment */ lli_len = (lli_len/mbus->buswidth) * mbus->buswidth; @@ -743,17 +727,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } else { /* * So now we know how many bytes to transfer - * to get to the nearest boundary - * The next LLI will past the boundary - * - however we may be working to a boundary - * on the slave bus - * We need to ensure the master stays aligned + * to get to the nearest boundary. The next + * LLI will past the boundary. However, we + * may be working to a boundary on the slave + * bus. We need to ensure the master stays + * aligned, and that we are working in + * multiples of the bus widths. */ odd_bytes = lli_len % mbus->buswidth; - /* - * - and that we are working in multiples - * of the bus widths - */ lli_len -= odd_bytes; } @@ -793,8 +774,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (odd_bytes) { /* - * Creep past the boundary, - * maintaining master alignment + * Creep past the boundary, maintaining + * master alignment */ int j; for (j = 0; (j < mbus->buswidth) @@ -837,13 +818,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } llis_va = txd->llis_va; - /* - * The final LLI terminates the LLI. - */ + /* The final LLI terminates the LLI. */ llis_va[num_llis - 1].lli = 0; - /* - * The final LLI element shall also fire an interrupt - */ + /* The final LLI element shall also fire an interrupt. */ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; #ifdef VERBOSE_DEBUG @@ -891,7 +868,6 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, list_del(&txdi->node); pl08x_free_txd(pl08x, txdi); } - } } @@ -1020,10 +996,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( } /* - * Code accessing dma_async_is_complete() in a tight loop - * may give problems - could schedule where indicated. - * If slaves are relying on interrupts to signal completion this - * function must not be called with interrupts disabled + * Code accessing dma_async_is_complete() in a tight loop may give problems. + * If slaves are relying on interrupts to signal completion this function + * must not be called with interrupts disabled. */ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan, @@ -1045,10 +1020,6 @@ pl08x_dma_tx_status(struct dma_chan *chan, return ret; } - /* - * schedule(); could be inserted here - */ - /* * This cookie not complete yet */ @@ -1273,11 +1244,10 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, } } else /* - * Else we're all set, paused and ready to roll, - * status will switch to PL08X_CHAN_RUNNING when - * we call issue_pending(). If there is something - * running on the channel already we don't change - * its state. + * Else we're all set, paused and ready to roll, status + * will switch to PL08X_CHAN_RUNNING when we call + * issue_pending(). If there is something running on the + * channel already we don't change its state. */ if (plchan->state == PL08X_CHAN_IDLE) plchan->state = PL08X_CHAN_PAUSED; @@ -1528,10 +1498,9 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) /* * Just check that the device is there and active - * TODO: turn this bit on/off depending on the number of - * physical channels actually used, if it is zero... well - * shut it off. That will save some power. Cut the clock - * at the same time. + * TODO: turn this bit on/off depending on the number of physical channels + * actually used, if it is zero... well shut it off. That will save some + * power. Cut the clock at the same time. */ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) { @@ -1579,16 +1548,11 @@ static void pl08x_tasklet(unsigned long data) plchan->at = NULL; if (txd) { - /* - * Update last completed - */ + /* Update last completed */ plchan->lc = txd->tx.cookie; } - /* - * If a new descriptor is queued, set it up - * plchan->at is NULL here - */ + /* If a new descriptor is queued, set it up plchan->at is NULL here */ if (!list_empty(&plchan->pend_list)) { struct pl08x_txd *next; @@ -1615,11 +1579,10 @@ static void pl08x_tasklet(unsigned long data) plchan->state = PL08X_CHAN_IDLE; /* - * And NOW before anyone else can grab that free:d - * up physical channel, see if there is some memcpy - * pending that seriously needs to start because of - * being stacked up while we were choking the - * physical channels with data. + * And NOW before anyone else can grab that free:d up + * physical channel, see if there is some memcpy pending + * that seriously needs to start because of being stacked + * up while we were choking the physical channels with data. */ list_for_each_entry(waiting, &pl08x->memcpy.channels, chan.device_node) { @@ -1670,9 +1633,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) val = readl(pl08x->base + PL080_ERR_STATUS); if (val) { - /* - * An error interrupt (on one or more channels) - */ + /* An error interrupt (on one or more channels) */ dev_err(&pl08x->adev->dev, "%s error interrupt, register value 0x%08x\n", __func__, val); @@ -1696,9 +1657,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev) mask |= (1 << i); } } - /* - * Clear only the terminal interrupts on channels we processed - */ + /* Clear only the terminal interrupts on channels we processed */ writel(mask, pl08x->base + PL080_TC_CLEAR); return mask ? IRQ_HANDLED : IRQ_NONE; @@ -1717,6 +1676,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, int i; INIT_LIST_HEAD(&dmadev->channels); + /* * Register as many many memcpy as we have physical channels, * we won't always be able to use all but the code will have @@ -1950,9 +1910,7 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) /* Turn on the PL08x */ pl08x_ensure_on(pl08x); - /* - * Attach the interrupt handler - */ + /* Attach the interrupt handler */ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR); writel(0x000000FF, pl08x->base + PL080_TC_CLEAR); diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 5b87b6aac3f8..3111385b8ca7 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -12,7 +12,6 @@ * * Please credit ARM.com * Documentation: ARM DDI 0196D - * */ #ifndef AMBA_PL08X_H @@ -55,8 +54,8 @@ enum { * @circular_buffer: whether the buffer passed in is circular and * shall simply be looped round round (like a record baby round * round round round) - * @single: the device connected to this channel will request single - * DMA transfers, not bursts. (Bursts are default.) + * @single: the device connected to this channel will request single DMA + * transfers, not bursts. (Bursts are default.) * @periph_buses: the device connected to this channel is accessible via * these buses (use PL08X_AHB1 | PL08X_AHB2). */ @@ -78,8 +77,7 @@ struct pl08x_channel_data { * @addr: current address * @maxwidth: the maximum width of a transfer on this bus * @buswidth: the width of this bus in bytes: 1, 2 or 4 - * @fill_bytes: bytes required to fill to the next bus memory - * boundary + * @fill_bytes: bytes required to fill to the next bus memory boundary */ struct pl08x_bus_data { dma_addr_t addr; @@ -92,10 +90,10 @@ struct pl08x_bus_data { * struct pl08x_phy_chan - holder for the physical channels * @id: physical index to this channel * @lock: a lock to use when altering an instance of this struct - * @signal: the physical signal (aka channel) serving this - * physical channel right now - * @serving: the virtual channel currently being served by this - * physical channel + * @signal: the physical signal (aka channel) serving this physical channel + * right now + * @serving: the virtual channel currently being served by this physical + * channel */ struct pl08x_phy_chan { unsigned int id; @@ -119,7 +117,6 @@ struct pl08x_txd { size_t len; dma_addr_t llis_bus; struct pl08x_lli *llis_va; - bool active; /* Default cctl value for LLIs */ u32 cctl; /* @@ -130,8 +127,8 @@ struct pl08x_txd { }; /** - * struct pl08x_dma_chan_state - holds the PL08x specific virtual - * channel states + * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel + * states * @PL08X_CHAN_IDLE: the channel is idle * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport * channel and is running a transfer on it @@ -152,7 +149,7 @@ enum pl08x_dma_chan_state { * @chan: wrappped abstract channel * @phychan: the physical channel utilized by this channel, if there is one * @phychan_hold: if non-zero, hold on to the physical channel even if we - * have no pending entries + * have no pending entries * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel * @cd: channel platform data @@ -166,8 +163,8 @@ enum pl08x_dma_chan_state { * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc * @slave: whether this channel is a device (slave) or for memcpy - * @waiting: a TX descriptor on this channel which is waiting for - * a physical channel to become available + * @waiting: a TX descriptor on this channel which is waiting for a physical + * channel to become available */ struct pl08x_dma_chan { struct dma_chan chan; @@ -189,16 +186,16 @@ struct pl08x_dma_chan { }; /** - * struct pl08x_platform_data - the platform configuration for the - * PL08x PrimeCells. + * struct pl08x_platform_data - the platform configuration for the PL08x + * PrimeCells. * @slave_channels: the channels defined for the different devices on the * platform, all inclusive, including multiplexed channels. The available - * physical channels will be multiplexed around these signals as they - * are requested, just enumerate all possible channels. - * @get_signal: request a physical signal to be used for a DMA - * transfer immediately: if there is some multiplexing or similar blocking - * the use of the channel the transfer can be denied by returning - * less than zero, else it returns the allocated signal number + * physical channels will be multiplexed around these signals as they are + * requested, just enumerate all possible channels. + * @get_signal: request a physical signal to be used for a DMA transfer + * immediately: if there is some multiplexing or similar blocking the use + * of the channel the transfer can be denied by returning less than zero, + * else it returns the allocated signal number * @put_signal: indicate to the platform that this physical signal is not * running any DMA transfer and multiplexing can be recycled * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2 -- cgit v1.2.3 From e78bf5e6cbe837daa6ab628a5f679548742994d3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 16 Jan 2011 16:55:23 -0800 Subject: drivers/nfc/pn544.c: fix min_t warnings Fix these: drivers/nfc/pn544.c: In function 'pn544_read': drivers/nfc/pn544.c:356: warning: comparison of distinct pointer types lacks a cast drivers/nfc/pn544.c:377: warning: comparison of distinct pointer types lacks a cast drivers/nfc/pn544.c: In function 'pn544_write': drivers/nfc/pn544.c:463: warning: comparison of distinct pointer types lacks a cast drivers/nfc/pn544.c:485: warning: comparison of distinct pointer types lacks a cast Cc: "Matti J. Aaltonen" Cc: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/nfc/pn544.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c index 401c44b6eadb..bae647264dd6 100644 --- a/drivers/nfc/pn544.c +++ b/drivers/nfc/pn544.c @@ -69,7 +69,7 @@ struct pn544_info { struct mutex read_mutex; /* Serialize read_irq access */ struct mutex mutex; /* Serialize info struct access */ u8 *buf; - unsigned int buflen; + size_t buflen; }; static const char reg_vdd_io[] = "Vdd_IO"; -- cgit v1.2.3 From c693931d93facab671bafdcebf515520663c22fc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 11 Jan 2011 14:23:12 +1000 Subject: drm/nv40: make detection of 0x4097-ful chipsets available everywhere Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 14 ++++++++++++++ drivers/gpu/drm/nouveau/nv40_graph.c | 3 +-- drivers/gpu/drm/nouveau/nv40_grctx.c | 21 +++++---------------- 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 6d749b792088..07a7e6ad5e3b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1574,6 +1574,20 @@ nv_match_device(struct drm_device *dev, unsigned device, dev->pdev->subsystem_device == sub_device; } +/* returns 1 if device is one of the nv4x using the 0x4497 object class, + * helpful to determine a number of other hardware features + */ +static inline int +nv44_graph_class(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if ((dev_priv->chipset & 0xf0) == 0x60) + return 1; + + return !(0x0baf & (1 << (dev_priv->chipset & 0x0f))); +} + /* memory type/access flags, do not match hardware values */ #define NV_MEM_ACCESS_RO 1 #define NV_MEM_ACCESS_WO 2 diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 19ef92a0375a..8870d72388c8 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -451,8 +451,7 @@ nv40_graph_register(struct drm_device *dev) NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */ /* curie */ - if (dev_priv->chipset >= 0x60 || - 0x00005450 & (1 << (dev_priv->chipset & 0x0f))) + if (nv44_graph_class(dev)) NVOBJ_CLASS(dev, 0x4497, GR); else NVOBJ_CLASS(dev, 0x4097, GR); diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c index ce585093264e..f70447d131d7 100644 --- a/drivers/gpu/drm/nouveau/nv40_grctx.c +++ b/drivers/gpu/drm/nouveau/nv40_grctx.c @@ -117,17 +117,6 @@ * - get vs count from 0x1540 */ -static int -nv40_graph_4097(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - - if ((dev_priv->chipset & 0xf0) == 0x60) - return 0; - - return !!(0x0baf & (1 << dev_priv->chipset)); -} - static int nv40_graph_vs_count(struct drm_device *dev) { @@ -219,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) gr_def(ctx, 0x4009dc, 0x80000000); } else { cp_ctx(ctx, 0x400840, 20); - if (!nv40_graph_4097(ctx->dev)) { + if (nv44_graph_class(ctx->dev)) { for (i = 0; i < 8; i++) gr_def(ctx, 0x400860 + (i * 4), 0x00000001); } @@ -228,7 +217,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) gr_def(ctx, 0x400888, 0x00000040); cp_ctx(ctx, 0x400894, 11); gr_def(ctx, 0x400894, 0x00000040); - if (nv40_graph_4097(ctx->dev)) { + if (!nv44_graph_class(ctx->dev)) { for (i = 0; i < 8; i++) gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000); } @@ -546,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) static void nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx) { - int len = nv40_graph_4097(ctx->dev) ? 0x0684 : 0x0084; + int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684; cp_out (ctx, 0x300000); cp_lsr (ctx, len - 4); @@ -582,11 +571,11 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx) } else { b0_offset = 0x1d40/4; /* 2200 */ b1_offset = 0x3f40/4; /* 0b00 : 0a40 */ - vs_len = nv40_graph_4097(dev) ? 0x4a40/4 : 0x4980/4; + vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4; } cp_lsr(ctx, vs_len * vs_nr + 0x300/4); - cp_out(ctx, nv40_graph_4097(dev) ? 0x800041 : 0x800029); + cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041); offset = ctx->ctxvals_pos; ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len)); -- cgit v1.2.3 From 1380da4979728bdd6af0086a8c8e186da14ae673 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 11 Jan 2011 17:22:33 +1000 Subject: drm/nv40: initialise 0x17xx on all chipsets that have it Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv40_mc.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c index e4e72c12ab6a..03c0d4c3f355 100644 --- a/drivers/gpu/drm/nouveau/nv40_mc.c +++ b/drivers/gpu/drm/nouveau/nv40_mc.c @@ -6,27 +6,17 @@ int nv40_mc_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t tmp; - /* Power up everything, resetting each individual unit will * be done later if needed. */ nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF); - switch (dev_priv->chipset) { - case 0x44: - case 0x46: /* G72 */ - case 0x4e: - case 0x4c: /* C51_G7X */ - tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA); + if (nv44_graph_class(dev)) { + u32 tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA); nv_wr32(dev, NV40_PMC_1700, tmp); nv_wr32(dev, NV40_PMC_1704, 0); nv_wr32(dev, NV40_PMC_1708, 0); nv_wr32(dev, NV40_PMC_170C, tmp); - break; - default: - break; } return 0; -- cgit v1.2.3 From c906ca0fbf237b77ba2101a2fa9050317137fde8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 14 Jan 2011 10:27:02 +1000 Subject: drm/nvc0: enable protection of system-use-only structures in vm Somehow missed this in the original merge of the nvc0 code. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nv50_instmem.c | 7 +++++-- drivers/gpu/drm/nouveau/nvc0_graph.c | 3 ++- drivers/gpu/drm/nouveau/nvc0_vm.c | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 07a7e6ad5e3b..51920321d058 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -160,6 +160,7 @@ enum nouveau_flags { #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) #define NVOBJ_FLAG_ZERO_FREE (1 << 2) #define NVOBJ_FLAG_VM (1 << 3) +#define NVOBJ_FLAG_VM_USER (1 << 4) #define NVOBJ_CINST_GLOBAL 0xdeadbeef diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 2e1b1cd19a4b..ea0041810ae3 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -332,8 +332,11 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) gpuobj->vinst = node->vram->offset; if (gpuobj->flags & NVOBJ_FLAG_VM) { - ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, - NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, + u32 flags = NV_MEM_ACCESS_RW; + if (!(gpuobj->flags & NVOBJ_FLAG_VM_USER)) + flags |= NV_MEM_ACCESS_SYS; + + ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, flags, &node->chan_vma); if (ret) { vram->put(dev, &node->vram); diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index 5feacd5d5fa4..e6ea7d83187f 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -105,7 +105,8 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) if (ret) return ret; - ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, NVOBJ_FLAG_VM, + ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, + NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER, &grch->unk418810); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c index 4b9251bb0ff4..e4e83c2caf5b 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -48,8 +48,8 @@ nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) phys >>= 8; phys |= 0x00000001; /* present */ -// if (vma->access & NV_MEM_ACCESS_SYS) -// phys |= 0x00000002; + if (vma->access & NV_MEM_ACCESS_SYS) + phys |= 0x00000002; phys |= ((u64)target << 32); phys |= ((u64)memtype << 36); -- cgit v1.2.3 From 8b464bfed674fc25d39d8a686010ebe509c8f62a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 14 Jan 2011 15:46:30 +1000 Subject: drm/nouveau: greatly simplify mm, killing some bugs in the process Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 26 ++--- drivers/gpu/drm/nouveau/nouveau_mm.c | 182 ++++++++-------------------------- drivers/gpu/drm/nouveau/nouveau_mm.h | 4 +- 3 files changed, 52 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 69044eb104bb..26347b7cd872 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -742,30 +742,24 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) { struct nouveau_mm *mm = man->priv; struct nouveau_mm_node *r; - u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {}; - int i; + u32 total = 0, free = 0; mutex_lock(&mm->mutex); list_for_each_entry(r, &mm->nodes, nl_entry) { - printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n", - prefix, r->free ? "free" : "used", r->type, - ((u64)r->offset << 12), + printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n", + prefix, r->type, ((u64)r->offset << 12), (((u64)r->offset + r->length) << 12)); + total += r->length; - ttotal[r->type] += r->length; - if (r->free) - tfree[r->type] += r->length; - else - tused[r->type] += r->length; + if (!r->type) + free += r->length; } mutex_unlock(&mm->mutex); - printk(KERN_DEBUG "%s total: 0x%010llx\n", prefix, total << 12); - for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%s type %d: 0x%010llx, " - "used 0x%010llx, free 0x%010llx\n", prefix, - i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12); - } + printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n", + prefix, (u64)total << 12, (u64)free << 12); + printk(KERN_DEBUG "%s block: 0x%08x\n", + prefix, mm->block_size << 12); } const struct ttm_mem_type_manager_func nouveau_vram_manager = { diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c index cdbb11eb701b..8844b50c3e54 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.c +++ b/drivers/gpu/drm/nouveau/nouveau_mm.c @@ -48,175 +48,76 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) b->offset = a->offset; b->length = size; - b->free = a->free; b->type = a->type; a->offset += size; a->length -= size; list_add_tail(&b->nl_entry, &a->nl_entry); - if (b->free) + if (b->type == 0) list_add_tail(&b->fl_entry, &a->fl_entry); return b; } -static struct nouveau_mm_node * -nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this) -{ - struct nouveau_mm_node *prev, *next; - - /* try to merge with free adjacent entries of same type */ - prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry); - if (this->nl_entry.prev != &rmm->nodes) { - if (prev->free && prev->type == this->type) { - prev->length += this->length; - region_put(rmm, this); - this = prev; - } - } - - next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); - if (this->nl_entry.next != &rmm->nodes) { - if (next->free && next->type == this->type) { - next->offset = this->offset; - next->length += this->length; - region_put(rmm, this); - this = next; - } - } - - return this; -} +#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ + list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) void nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) { - u32 block_s, block_l; + struct nouveau_mm_node *prev = node(this, prev); + struct nouveau_mm_node *next = node(this, next); - this->free = true; list_add(&this->fl_entry, &rmm->free); - this = nouveau_mm_merge(rmm, this); - - /* any entirely free blocks now? we'll want to remove typing - * on them now so they can be use for any memory allocation - */ - block_s = roundup(this->offset, rmm->block_size); - if (block_s + rmm->block_size > this->offset + this->length) - return; + this->type = 0; - /* split off any still-typed region at the start */ - if (block_s != this->offset) { - if (!region_split(rmm, this, block_s - this->offset)) - return; + if (prev && prev->type == 0) { + prev->length += this->length; + region_put(rmm, this); + this = prev; } - /* split off the soon-to-be-untyped block(s) */ - block_l = rounddown(this->length, rmm->block_size); - if (block_l != this->length) { - this = region_split(rmm, this, block_l); - if (!this) - return; + if (next && next->type == 0) { + next->offset = this->offset; + next->length += this->length; + region_put(rmm, this); } - - /* mark as having no type, and retry merge with any adjacent - * untyped blocks - */ - this->type = 0; - nouveau_mm_merge(rmm, this); } int nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, u32 align, struct nouveau_mm_node **pnode) { - struct nouveau_mm_node *this, *tmp, *next; - u32 splitoff, avail, alloc; - - list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) { - next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); - if (this->nl_entry.next == &rmm->nodes) - next = NULL; - - /* skip wrongly typed blocks */ - if (this->type && this->type != type) + struct nouveau_mm_node *prev, *this, *next; + u32 min = size_nc ? size_nc : size; + u32 align_mask = align - 1; + u32 splitoff; + u32 s, e; + + list_for_each_entry(this, &rmm->free, fl_entry) { + e = this->offset + this->length; + s = this->offset; + + prev = node(this, prev); + if (prev && prev->type != type) + s = roundup(s, rmm->block_size); + + next = node(this, next); + if (next && next->type != type) + e = rounddown(e, rmm->block_size); + + s = (s + align_mask) & ~align_mask; + e &= ~align_mask; + if (s > e || e - s < min) continue; - /* account for alignment */ - splitoff = this->offset & (align - 1); - if (splitoff) - splitoff = align - splitoff; - - if (this->length <= splitoff) - continue; - - /* determine total memory available from this, and - * the next block (if appropriate) - */ - avail = this->length; - if (next && next->free && (!next->type || next->type == type)) - avail += next->length; - - avail -= splitoff; - - /* determine allocation size */ - if (size_nc) { - alloc = min(avail, size); - alloc = rounddown(alloc, size_nc); - if (alloc == 0) - continue; - } else { - alloc = size; - if (avail < alloc) - continue; - } - - /* untyped block, split off a chunk that's a multiple - * of block_size and type it - */ - if (!this->type) { - u32 block = roundup(alloc + splitoff, rmm->block_size); - if (this->length < block) - continue; - - this = region_split(rmm, this, block); - if (!this) - return -ENOMEM; - - this->type = type; - } - - /* stealing memory from adjacent block */ - if (alloc > this->length) { - u32 amount = alloc - (this->length - splitoff); - - if (!next->type) { - amount = roundup(amount, rmm->block_size); - - next = region_split(rmm, next, amount); - if (!next) - return -ENOMEM; - - next->type = type; - } - - this->length += amount; - next->offset += amount; - next->length -= amount; - if (!next->length) { - list_del(&next->nl_entry); - list_del(&next->fl_entry); - kfree(next); - } - } - - if (splitoff) { - if (!region_split(rmm, this, splitoff)) - return -ENOMEM; - } + splitoff = s - this->offset; + if (splitoff && !region_split(rmm, this, splitoff)) + return -ENOMEM; - this = region_split(rmm, this, alloc); - if (this == NULL) + this = region_split(rmm, this, min(size, e - s)); + if (!this) return -ENOMEM; - this->free = false; + this->type = type; list_del(&this->fl_entry); *pnode = this; return 0; @@ -234,7 +135,6 @@ nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) heap = kzalloc(sizeof(*heap), GFP_KERNEL); if (!heap) return -ENOMEM; - heap->free = true; heap->offset = roundup(offset, block); heap->length = rounddown(offset + length, block) - heap->offset; diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h index af3844933036..798eaf39691c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h @@ -30,9 +30,7 @@ struct nouveau_mm_node { struct list_head fl_entry; struct list_head rl_entry; - bool free; - int type; - + u8 type; u32 offset; u32 length; }; -- cgit v1.2.3 From f01a9720cb149e76155dc6e0e051058450305f4f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 17 Jan 2011 11:22:38 +1000 Subject: drm/nouveau: fix gpu page faults triggered by plymouthd The switch to separate BAR and channel address spaces made the fbcon memory address calculation incorrect on NV50+ boards, this commit fixes that. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 326eeda6ad7f..f988362c112e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -352,8 +352,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, FBINFO_HWACCEL_IMAGEBLIT; info->flags |= FBINFO_CAN_FORCE_OUTPUT; info->fbops = &nouveau_fbcon_sw_ops; - info->fix.smem_start = dev->mode_config.fb_base + - (nvbo->bo.mem.start << PAGE_SHIFT); + info->fix.smem_start = nvbo->bo.mem.bus.base + + nvbo->bo.mem.bus.offset; info->fix.smem_len = size; info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); -- cgit v1.2.3 From 394d83c17fac2b7bcf05cb99d1e945135767bb6b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 13 Jan 2011 13:55:12 -0500 Subject: drm/radeon/kms: fix typo in evergreen safe reg Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/reg_srcs/evergreen | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen index ac40fd39d787..9177f9191837 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/evergreen +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -439,7 +439,7 @@ evergreen 0x9400 0x000286EC SPI_COMPUTE_NUM_THREAD_X 0x000286F0 SPI_COMPUTE_NUM_THREAD_Y 0x000286F4 SPI_COMPUTE_NUM_THREAD_Z -0x000286F8 GDS_ADDR_SIZE +0x00028724 GDS_ADDR_SIZE 0x00028780 CB_BLEND0_CONTROL 0x00028784 CB_BLEND1_CONTROL 0x00028788 CB_BLEND2_CONTROL -- cgit v1.2.3 From d42dd579ac1498e23f29465225fa3eee4520f5e5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 12 Jan 2011 20:05:11 -0500 Subject: drm/radeon/kms: add module option for pcie gen2 Switching to pcie gen2 causes problems on some boards. Add a module option to turn it on/off. There are gen2 compatability issues with some motherboards it seems. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=33027 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 3 +++ drivers/gpu/drm/radeon/r600.c | 3 +++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/rv770.c | 3 +++ 5 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 7fe8ebdcdc0e..e201a88caf59 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3158,6 +3158,9 @@ static void evergreen_pcie_gen2_enable(struct radeon_device *rdev) { u32 link_width_cntl, speed_cntl; + if (radeon_pcie_gen2 == 0) + return; + if (rdev->flags & RADEON_IS_IGP) return; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 6b50716267c0..9fe86253cfcd 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3658,6 +3658,9 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev) u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp; u16 link_cntl2; + if (radeon_pcie_gen2 == 0) + return; + if (rdev->flags & RADEON_IS_IGP) return; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e9486630a467..71d2a554bbe6 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -92,6 +92,7 @@ extern int radeon_tv; extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; +extern int radeon_pcie_gen2; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index be5cb4f28c29..d5680a0c87af 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -104,6 +104,7 @@ int radeon_tv = 1; int radeon_audio = 1; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; +int radeon_pcie_gen2 = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -147,6 +148,9 @@ module_param_named(disp_priority, radeon_disp_priority, int, 0444); MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)"); module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); +MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)"); +module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 3a264aa3a79a..bd9ee90421e4 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1372,6 +1372,9 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev) u32 link_width_cntl, lanes, speed_cntl, tmp; u16 link_cntl2; + if (radeon_pcie_gen2 == 0) + return; + if (rdev->flags & RADEON_IS_IGP) return; -- cgit v1.2.3 From fd909c3718da3fb8c5c0530f93ae21d85dc31471 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 11 Jan 2011 18:08:59 -0500 Subject: drm/radeon/kms: remove duplicate card_posted() functions Use the common one for all asics. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 27 +-------------------------- drivers/gpu/drm/radeon/r600.c | 20 +------------------- drivers/gpu/drm/radeon/rv770.c | 2 +- 3 files changed, 3 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e201a88caf59..a8973acb3987 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3002,31 +3002,6 @@ int evergreen_copy_blit(struct radeon_device *rdev, return 0; } -static bool evergreen_card_posted(struct radeon_device *rdev) -{ - u32 reg; - - /* first check CRTCs */ - if (rdev->flags & RADEON_IS_IGP) - reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); - else - reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); - if (reg & EVERGREEN_CRTC_MASTER_EN) - return true; - - /* then check MEM_SIZE, in case the crtcs are off */ - if (RREG32(CONFIG_MEMSIZE)) - return true; - - return false; -} - /* Plan is to move initialization in that function and use * helper function so that radeon_device_init pretty much * do nothing more than calling asic specific function. This @@ -3063,7 +3038,7 @@ int evergreen_init(struct radeon_device *rdev) if (radeon_asic_reset(rdev)) dev_warn(rdev->dev, "GPU reset failed !\n"); /* Post card if necessary */ - if (!evergreen_card_posted(rdev)) { + if (!radeon_card_posted(rdev)) { if (!rdev->bios) { dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); return -EINVAL; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 9fe86253cfcd..aca2236268fa 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2358,24 +2358,6 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg) /* FIXME: implement */ } - -bool r600_card_posted(struct radeon_device *rdev) -{ - uint32_t reg; - - /* first check CRTCs */ - reg = RREG32(D1CRTC_CONTROL) | - RREG32(D2CRTC_CONTROL); - if (reg & CRTC_EN) - return true; - - /* then check MEM_SIZE, in case the crtcs are off */ - if (RREG32(CONFIG_MEMSIZE)) - return true; - - return false; -} - int r600_startup(struct radeon_device *rdev) { int r; @@ -2536,7 +2518,7 @@ int r600_init(struct radeon_device *rdev) if (r) return r; /* Post card if necessary */ - if (!r600_card_posted(rdev)) { + if (!radeon_card_posted(rdev)) { if (!rdev->bios) { dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); return -EINVAL; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index bd9ee90421e4..491dc9000655 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1268,7 +1268,7 @@ int rv770_init(struct radeon_device *rdev) if (r) return r; /* Post card if necessary */ - if (!r600_card_posted(rdev)) { + if (!radeon_card_posted(rdev)) { if (!rdev->bios) { dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); return -EINVAL; -- cgit v1.2.3 From 25b2ec5b643c9ea784e5a51e5e9602cd536965f2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 11 Jan 2011 13:36:55 -0500 Subject: drm/radeon/kms: balance asic_reset functions First, we were calling mc_stop() at the top of the function which turns off all MC (memory controller) clients, then checking if the GPU is idle. If it was idle we returned without re-enabling the MC clients which would lead to a blank screen, etc. This patch checks if the GPU is idle before calling mc_stop(). Second, if the reset failed, we were returning without re-enabling the MC clients. This patch re-enables the MC clients before returning regardless of whether the reset was successful or not. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 11 ++++++----- drivers/gpu/drm/radeon/r300.c | 11 ++++++----- drivers/gpu/drm/radeon/rs600.c | 16 ++++++++-------- 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index f637595b14e1..46da5142b131 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2086,12 +2086,13 @@ int r100_asic_reset(struct radeon_device *rdev) { struct r100_mc_save save; u32 status, tmp; + int ret = 0; - r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0; } + r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */ @@ -2131,11 +2132,11 @@ int r100_asic_reset(struct radeon_device *rdev) G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); rdev->gpu_lockup = true; - return -1; - } + ret = -1; + } else + dev_info(rdev->dev, "GPU reset succeed\n"); r100_mc_resume(rdev, &save); - dev_info(rdev->dev, "GPU reset succeed\n"); - return 0; + return ret; } void r100_set_common_regs(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index fae5e709f270..cf862ca580bf 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -405,12 +405,13 @@ int r300_asic_reset(struct radeon_device *rdev) { struct r100_mc_save save; u32 status, tmp; + int ret = 0; - r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0; } + r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */ @@ -451,11 +452,11 @@ int r300_asic_reset(struct radeon_device *rdev) if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); rdev->gpu_lockup = true; - return -1; - } + ret = -1; + } else + dev_info(rdev->dev, "GPU reset succeed\n"); r100_mc_resume(rdev, &save); - dev_info(rdev->dev, "GPU reset succeed\n"); - return 0; + return ret; } /* diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index b4192acaab5f..5afe294ed51f 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -339,16 +339,16 @@ void rs600_bm_disable(struct radeon_device *rdev) int rs600_asic_reset(struct radeon_device *rdev) { - u32 status, tmp; - struct rv515_mc_save save; + u32 status, tmp; + int ret = 0; - /* Stops all mc clients */ - rv515_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0; } + /* Stops all mc clients */ + rv515_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */ @@ -392,11 +392,11 @@ int rs600_asic_reset(struct radeon_device *rdev) if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); rdev->gpu_lockup = true; - return -1; - } + ret = -1; + } else + dev_info(rdev->dev, "GPU reset succeed\n"); rv515_mc_resume(rdev, &save); - dev_info(rdev->dev, "GPU reset succeed\n"); - return 0; + return ret; } /* -- cgit v1.2.3 From f06267104dd9112f11586830d22501d0e26245ea Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 19 Oct 2010 15:24:36 +0000 Subject: RDMA: Update workqueue usage * ib_wq is added, which is used as the common workqueue for infiniband instead of the system workqueue. All system workqueue usages including flush_scheduled_work() callers are converted to use and flush ib_wq. * cancel_delayed_work() + flush_scheduled_work() converted to cancel_delayed_work_sync(). * qib_wq is removed and ib_wq is used instead. This is to prepare for deprecation of flush_scheduled_work(). Signed-off-by: Tejun Heo Signed-off-by: Roland Dreier --- drivers/infiniband/core/cache.c | 4 ++-- drivers/infiniband/core/device.c | 11 +++++++++-- drivers/infiniband/core/sa_query.c | 2 +- drivers/infiniband/core/umem.c | 2 +- drivers/infiniband/hw/ipath/ipath_driver.c | 2 +- drivers/infiniband/hw/ipath/ipath_user_pages.c | 2 +- drivers/infiniband/hw/qib/qib_iba7220.c | 7 +++---- drivers/infiniband/hw/qib/qib_iba7322.c | 14 +++++++------- drivers/infiniband/hw/qib/qib_init.c | 26 ++++---------------------- drivers/infiniband/hw/qib/qib_qsfp.c | 9 ++++----- drivers/infiniband/hw/qib/qib_verbs.h | 3 +-- drivers/infiniband/ulp/srp/ib_srp.c | 4 ++-- include/rdma/ib_verbs.h | 3 +++ 13 files changed, 39 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 68883565b725..f9ba7d74dfc0 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -308,7 +308,7 @@ static void ib_cache_event(struct ib_event_handler *handler, INIT_WORK(&work->work, ib_cache_task); work->device = event->device; work->port_num = event->element.port_num; - schedule_work(&work->work); + queue_work(ib_wq, &work->work); } } } @@ -368,7 +368,7 @@ static void ib_cache_cleanup_one(struct ib_device *device) int p; ib_unregister_event_handler(&device->cache.event_handler); - flush_scheduled_work(); + flush_workqueue(ib_wq); for (p = 0; p <= end_port(device) - start_port(device); ++p) { kfree(device->cache.pkey_cache[p]); diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index a19effad0811..f793bf2f5da7 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -38,7 +38,6 @@ #include #include #include -#include #include "core_priv.h" @@ -52,6 +51,9 @@ struct ib_client_data { void * data; }; +struct workqueue_struct *ib_wq; +EXPORT_SYMBOL_GPL(ib_wq); + static LIST_HEAD(device_list); static LIST_HEAD(client_list); @@ -718,6 +720,10 @@ static int __init ib_core_init(void) { int ret; + ib_wq = alloc_workqueue("infiniband", 0, 0); + if (!ib_wq) + return -ENOMEM; + ret = ib_sysfs_setup(); if (ret) printk(KERN_WARNING "Couldn't create InfiniBand device class\n"); @@ -726,6 +732,7 @@ static int __init ib_core_init(void) if (ret) { printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); ib_sysfs_cleanup(); + destroy_workqueue(ib_wq); } return ret; @@ -736,7 +743,7 @@ static void __exit ib_core_cleanup(void) ib_cache_cleanup(); ib_sysfs_cleanup(); /* Make sure that any pending umem accounting work is done. */ - flush_scheduled_work(); + destroy_workqueue(ib_wq); } module_init(ib_core_init); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 91a660310b7c..e38be1bcc01c 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -425,7 +425,7 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event port->sm_ah = NULL; spin_unlock_irqrestore(&port->ah_lock, flags); - schedule_work(&sa_dev->port[event->element.port_num - + queue_work(ib_wq, &sa_dev->port[event->element.port_num - sa_dev->start_port].update_task); } } diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 415e186eee32..b645e558876f 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -262,7 +262,7 @@ void ib_umem_release(struct ib_umem *umem) umem->mm = mm; umem->diff = diff; - schedule_work(&umem->work); + queue_work(ib_wq, &umem->work); return; } } else diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index ae92da2d3f56..47db4bf34628 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -755,7 +755,7 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev) */ ipath_shutdown_device(dd); - flush_scheduled_work(); + flush_workqueue(ib_wq); if (dd->verbs_dev) ipath_unregister_ib_device(dd->verbs_dev); diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c index 5e86d73eba2a..bab9f74c0665 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_pages.c +++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c @@ -220,7 +220,7 @@ void ipath_release_user_pages_on_close(struct page **p, size_t num_pages) work->mm = mm; work->num_pages = num_pages; - schedule_work(&work->work); + queue_work(ib_wq, &work->work); return; bail_mm: diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 127a0d5069f0..de799f17cb9e 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -1692,8 +1692,7 @@ static void qib_7220_quiet_serdes(struct qib_pportdata *ppd) ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG; spin_unlock_irqrestore(&ppd->lflags_lock, flags); wake_up(&ppd->cpspec->autoneg_wait); - cancel_delayed_work(&ppd->cpspec->autoneg_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&ppd->cpspec->autoneg_work); shutdown_7220_relock_poll(ppd->dd); val = qib_read_kreg64(ppd->dd, kr_xgxs_cfg); @@ -3515,8 +3514,8 @@ static void try_7220_autoneg(struct qib_pportdata *ppd) toggle_7220_rclkrls(ppd->dd); /* 2 msec is minimum length of a poll cycle */ - schedule_delayed_work(&ppd->cpspec->autoneg_work, - msecs_to_jiffies(2)); + queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work, + msecs_to_jiffies(2)); } /* diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index dbbb0e85afe4..ea46fbc34b17 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -2406,10 +2406,9 @@ static void qib_7322_mini_quiet_serdes(struct qib_pportdata *ppd) ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG; spin_unlock_irqrestore(&ppd->lflags_lock, flags); wake_up(&ppd->cpspec->autoneg_wait); - cancel_delayed_work(&ppd->cpspec->autoneg_work); + cancel_delayed_work_sync(&ppd->cpspec->autoneg_work); if (ppd->dd->cspec->r1) - cancel_delayed_work(&ppd->cpspec->ipg_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&ppd->cpspec->ipg_work); ppd->cpspec->chase_end = 0; if (ppd->cpspec->chase_timer.data) /* if initted */ @@ -2706,7 +2705,7 @@ static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd) if (!(pins & mask)) { ++handled; qd->t_insert = get_jiffies_64(); - schedule_work(&qd->work); + queue_work(ib_wq, &qd->work); } } } @@ -4990,8 +4989,8 @@ static void try_7322_autoneg(struct qib_pportdata *ppd) set_7322_ibspeed_fast(ppd, QIB_IB_DDR); qib_7322_mini_pcs_reset(ppd); /* 2 msec is minimum length of a poll cycle */ - schedule_delayed_work(&ppd->cpspec->autoneg_work, - msecs_to_jiffies(2)); + queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work, + msecs_to_jiffies(2)); } /* @@ -5121,7 +5120,8 @@ static void try_7322_ipg(struct qib_pportdata *ppd) ib_free_send_mad(send_buf); retry: delay = 2 << ppd->cpspec->ipg_tries; - schedule_delayed_work(&ppd->cpspec->ipg_work, msecs_to_jiffies(delay)); + queue_delayed_work(ib_wq, &ppd->cpspec->ipg_work, + msecs_to_jiffies(delay)); } /* diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 304bd8038541..ffefb78b8949 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -80,7 +80,6 @@ unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */ module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO); MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism"); -struct workqueue_struct *qib_wq; struct workqueue_struct *qib_cq_wq; static void verify_interrupt(unsigned long); @@ -1044,24 +1043,10 @@ static int __init qlogic_ib_init(void) if (ret) goto bail; - /* - * We create our own workqueue mainly because we want to be - * able to flush it when devices are being removed. We can't - * use schedule_work()/flush_scheduled_work() because both - * unregister_netdev() and linkwatch_event take the rtnl lock, - * so flush_scheduled_work() can deadlock during device - * removal. - */ - qib_wq = create_workqueue("qib"); - if (!qib_wq) { - ret = -ENOMEM; - goto bail_dev; - } - qib_cq_wq = create_singlethread_workqueue("qib_cq"); if (!qib_cq_wq) { ret = -ENOMEM; - goto bail_wq; + goto bail_dev; } /* @@ -1091,8 +1076,6 @@ bail_unit: idr_destroy(&qib_unit_table); bail_cq_wq: destroy_workqueue(qib_cq_wq); -bail_wq: - destroy_workqueue(qib_wq); bail_dev: qib_dev_cleanup(); bail: @@ -1116,7 +1099,6 @@ static void __exit qlogic_ib_cleanup(void) pci_unregister_driver(&qib_driver); - destroy_workqueue(qib_wq); destroy_workqueue(qib_cq_wq); qib_cpulist_count = 0; @@ -1289,7 +1271,7 @@ static int __devinit qib_init_one(struct pci_dev *pdev, if (qib_mini_init || initfail || ret) { qib_stop_timers(dd); - flush_scheduled_work(); + flush_workqueue(ib_wq); for (pidx = 0; pidx < dd->num_pports; ++pidx) dd->f_quiet_serdes(dd->pport + pidx); if (qib_mini_init) @@ -1338,8 +1320,8 @@ static void __devexit qib_remove_one(struct pci_dev *pdev) qib_stop_timers(dd); - /* wait until all of our (qsfp) schedule_work() calls complete */ - flush_scheduled_work(); + /* wait until all of our (qsfp) queue_work() calls complete */ + flush_workqueue(ib_wq); ret = qibfs_remove(dd); if (ret) diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c index 35b3604b691d..3374a52232c1 100644 --- a/drivers/infiniband/hw/qib/qib_qsfp.c +++ b/drivers/infiniband/hw/qib/qib_qsfp.c @@ -485,7 +485,7 @@ void qib_qsfp_init(struct qib_qsfp_data *qd, goto bail; /* We see a module, but it may be unwise to look yet. Just schedule */ qd->t_insert = get_jiffies_64(); - schedule_work(&qd->work); + queue_work(ib_wq, &qd->work); bail: return; } @@ -493,10 +493,9 @@ bail: void qib_qsfp_deinit(struct qib_qsfp_data *qd) { /* - * There is nothing to do here for now. our - * work is scheduled with schedule_work(), and - * flush_scheduled_work() from remove_one will - * block until all work ssetup with schedule_work() + * There is nothing to do here for now. our work is scheduled + * with queue_work(), and flush_workqueue() from remove_one + * will block until all work setup with queue_work() * completes. */ } diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index 63b22a9a7feb..95e5b47223b3 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -805,7 +805,6 @@ static inline int qib_send_ok(struct qib_qp *qp) !(qp->s_flags & QIB_S_ANY_WAIT_SEND)); } -extern struct workqueue_struct *qib_wq; extern struct workqueue_struct *qib_cq_wq; /* @@ -814,7 +813,7 @@ extern struct workqueue_struct *qib_cq_wq; static inline void qib_schedule_send(struct qib_qp *qp) { if (qib_send_ok(qp)) - queue_work(qib_wq, &qp->s_work); + queue_work(ib_wq, &qp->s_work); } static inline int qib_pkey_ok(u16 pkey1, u16 pkey2) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 4b62105ed1e8..70ecb949683e 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -638,7 +638,7 @@ err: if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; INIT_WORK(&target->work, srp_remove_work); - schedule_work(&target->work); + queue_work(ib_wq, &target->work); } spin_unlock_irq(&target->lock); @@ -2199,7 +2199,7 @@ static void srp_remove_one(struct ib_device *device) * started before we marked our target ports as * removed, and any target port removal tasks. */ - flush_scheduled_work(); + flush_workqueue(ib_wq); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e04c4888d1fd..55cd0a0bc977 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -47,10 +47,13 @@ #include #include #include +#include #include #include +extern struct workqueue_struct *ib_wq; + union ib_gid { u8 raw[16]; struct { -- cgit v1.2.3 From eb745dbccce56f1bbe3f80b95ad2a325145171c2 Mon Sep 17 00:00:00 2001 From: Yang Ruirui Date: Fri, 14 Jan 2011 15:51:04 +0800 Subject: staging: smbfs building fix Building error for smbfs: drivers/staging/smbfs/dir.c:286: error: static declaration of 'smbfs_dentry_operations' follows non-static declaration drivers/staging/smbfs/proto.h:42: error: previous declaration of 'smbfs_dentry_operations' was here drivers/staging/smbfs/dir.c:294: error: static declaration of 'smbfs_dentry_operations_case' follows non-static declaration drivers/staging/smbfs/proto.h:41: error: previous declaration of 'smbfs_dentry_operations_case' was here make[3]: *** [drivers/staging/smbfs/dir.o] Error 1 make[2]: *** [drivers/staging/smbfs] Error 2 make[1]: *** [drivers/staging] Error 2 make[1]: *** Waiting for unfinished jobs.... Fix it by removing static keywords Signed-off-by: Yang Ruirui Signed-off-by: Al Viro --- drivers/staging/smbfs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c index 87a3a9bd5842..f204d33910ec 100644 --- a/drivers/staging/smbfs/dir.c +++ b/drivers/staging/smbfs/dir.c @@ -283,7 +283,7 @@ static int smb_compare_dentry(const struct dentry *, unsigned int, const char *, const struct qstr *); static int smb_delete_dentry(const struct dentry *); -static const struct dentry_operations smbfs_dentry_operations = +const struct dentry_operations smbfs_dentry_operations = { .d_revalidate = smb_lookup_validate, .d_hash = smb_hash_dentry, @@ -291,7 +291,7 @@ static const struct dentry_operations smbfs_dentry_operations = .d_delete = smb_delete_dentry, }; -static const struct dentry_operations smbfs_dentry_operations_case = +const struct dentry_operations smbfs_dentry_operations_case = { .d_revalidate = smb_lookup_validate, .d_delete = smb_delete_dentry, -- cgit v1.2.3 From 154bf89f5e3e3dc59666926f27ca4a0866f39157 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 16 Jan 2011 17:50:54 +0200 Subject: mtd: mtdpart: disallow reading OOB past the end of the partition This patch fixes the mtdpart bug which allows users reading OOB past the end of the partition. This happens because 'part_read_oob()' allows reading multiple OOB areas in one go, and mtdparts does not validate the OOB length in the request. Although there is such check in 'nand_do_read_oob()' in nand_base.c, but it checks that we do not read past the flash chip, not the partition, because in nand_base.c we work with the whole chip (e.g., mtd->size in nand_base.c is the size of the whole chip). So this check cannot be done correctly in nand_base.c and should be instead done in mtdparts.c. This problem was reported by Jason Liu and reproduced with nandsim: $ modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 \ fourth_id_byte=0x15 parts=0x400,0x400 $ modprobe nandsim mtd_oobtest.ko dev=0 $ dmesg = snip = mtd_oobtest: attempting to read past end of device mtd_oobtest: an error is expected... mtd_oobtest: error: read past end of device = snip = mtd_oobtest: finished with 2 errors Reported-by: Jason Liu Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdpart.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index b910a37baed8..0a4760174782 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -120,8 +120,25 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, return -EINVAL; if (ops->datbuf && from + ops->len > mtd->size) return -EINVAL; - res = part->master->read_oob(part->master, from + part->offset, ops); + /* + * If OOB is also requested, make sure that we do not read past the end + * of this partition. + */ + if (ops->oobbuf) { + size_t len, pages; + + if (ops->mode == MTD_OOB_AUTO) + len = mtd->oobavail; + else + len = mtd->oobsize; + pages = mtd_div_by_ws(mtd->size, mtd); + pages -= mtd_div_by_ws(from, mtd); + if (ops->ooboffs + ops->ooblen > pages * len) + return -EINVAL; + } + + res = part->master->read_oob(part->master, from + part->offset, ops); if (unlikely(res)) { if (res == -EUCLEAN) mtd->ecc_stats.corrected++; -- cgit v1.2.3 From d95defaca7994ffff1ceb52f3011eb644dfe3274 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 17 Jan 2011 17:01:07 +0100 Subject: spi/spi_sh_msiof: fix a wrong free_irq() parameter Without this fix reloading of the driver is impossible. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Grant Likely --- drivers/spi/spi_sh_msiof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c index d93b66743ba7..56f60c8ea0ab 100644 --- a/drivers/spi/spi_sh_msiof.c +++ b/drivers/spi/spi_sh_msiof.c @@ -635,7 +635,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) ret = spi_bitbang_stop(&p->bitbang); if (!ret) { pm_runtime_disable(&pdev->dev); - free_irq(platform_get_irq(pdev, 0), sh_msiof_spi_irq); + free_irq(platform_get_irq(pdev, 0), p); iounmap(p->mapbase); clk_put(p->clk); spi_master_put(p->bitbang.master); -- cgit v1.2.3 From e6f597a1425b5af64917be3448b29e2d5a585ac8 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 17 Jan 2011 16:11:12 -0800 Subject: staging: fix build failure in bcm driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While building latest Linus git, I hit the following: CC [M] drivers/staging/bcm/Qos.o drivers/staging/bcm/Qos.c: In function ‘PruneQueue’: drivers/staging/bcm/Qos.c:367: error: ‘struct netdev_queue’ has no member named ‘tx_dropped’ drivers/staging/bcm/Qos.c: In function ‘flush_all_queues’: drivers/staging/bcm/Qos.c:416: error: ‘struct netdev_queue’ has no member named ‘tx_dropped’ make[5]: *** [drivers/staging/bcm/Qos.o] Error 1 make[4]: *** [drivers/staging/bcm] Error 2 make[3]: *** [drivers/staging] Error 2 As well as: CC [M] drivers/staging/bcm/Transmit.o drivers/staging/bcm/Transmit.c: In function ‘SetupNextSend’: drivers/staging/bcm/Transmit.c:163: error: ‘struct netdev_queue’ has no member named ‘tx_bytes’ drivers/staging/bcm/Transmit.c:164: error: ‘struct netdev_queue’ has no member named ‘tx_packets’ make[2]: *** [drivers/staging/bcm/Transmit.o] Error 1 tx_dropped/tx_bytes_tx_packets were removed in commit 1ac9ad13. This patch converts bcm to use net_device_stats instead of netdev_queue. Acked-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: Andres Salomon Signed-off-by: Linus Torvalds --- drivers/staging/bcm/Qos.c | 7 +++---- drivers/staging/bcm/Transmit.c | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 8ce4536e6e28..feade9451b2e 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -359,12 +359,11 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex) if(PacketToDrop) { - struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iIndex); if (netif_msg_tx_err(Adapter)) pr_info(PFX "%s: tx queue %d overlimit\n", Adapter->dev->name, iIndex); - txq->tx_dropped++; + netstats->tx_dropped++; DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue, Adapter->PackInfo[iIndex].LastTxQueue); @@ -404,7 +403,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) // down(&Adapter->data_packet_queue_lock); for(iQIndex=LowPriority; iQIndexdev, iQIndex); + struct net_device_stats *netstats = &Adapter->dev->stats; spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); while(Adapter->PackInfo[iQIndex].FirstTxQueue) @@ -413,7 +412,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) if(PacketToDrop) { uiTotalPacketLength = PacketToDrop->len; - txq->tx_dropped++; + netstats->tx_dropped++; } else uiTotalPacketLength = 0; diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 0f7000960d50..d5e4a7404f71 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -157,11 +157,11 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid) } else { - struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, QueueIndex); + struct net_device_stats *netstats = &Adapter->dev->stats; Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; - txq->tx_bytes += Leader.PLength; - ++txq->tx_packets; + netstats->tx_bytes += Leader.PLength; + ++netstats->tx_packets; Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3; Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len); -- cgit v1.2.3 From 8efaef4dc842a8a050d10aef30e26220b8995fc3 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 4 Jan 2011 21:28:22 +0100 Subject: SPI: Add SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs The Atheros AR71XX/AR724X/AR913X SoCs have a built-in SPI controller. This patch implements a driver for that. Signed-off-by: Gabor Juhos Cc: David Brownell Cc: spi-devel-general@lists.sourceforge.net Acked-by: Grant Likely Cc: linux-mips@linux-mips.org Cc: Imre Kaloz Cc: Luis R. Rodriguez Cc: Cliff Holden Cc: Kathy Giori Patchwork: https://patchwork.linux-mips.org/patch/1960/ Signed-off-by: Ralf Baechle --- .../include/asm/mach-ath79/ath79_spi_platform.h | 23 ++ drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/ath79_spi.c | 292 +++++++++++++++++++++ 4 files changed, 324 insertions(+) create mode 100644 arch/mips/include/asm/mach-ath79/ath79_spi_platform.h create mode 100644 drivers/spi/ath79_spi.c (limited to 'drivers') diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h new file mode 100644 index 000000000000..aa2283e602fc --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h @@ -0,0 +1,23 @@ +/* + * Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller + * + * Copyright (C) 2008-2010 Gabor Juhos + * + * 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. + */ + +#ifndef _ATH79_SPI_PLATFORM_H +#define _ATH79_SPI_PLATFORM_H + +struct ath79_spi_platform_data { + unsigned bus_num; + unsigned num_chipselect; +}; + +struct ath79_spi_controller_data { + unsigned gpio; +}; + +#endif /* _ATH79_SPI_PLATFORM_H */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 13bfa9d48082..bb233a9cbad2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -53,6 +53,14 @@ if SPI_MASTER comment "SPI Master Controller Drivers" +config SPI_ATH79 + tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" + depends on ATH79 && GENERIC_GPIO + select SPI_BITBANG + help + This enables support for the SPI controller present on the + Atheros AR71XX/AR724X/AR913X SoCs. + config SPI_ATMEL tristate "Atmel SPI Controller" depends on (ARCH_AT91 || AVR32) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3a42463c92a4..86d1b5f9bbd9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o # SPI master controller drivers (bus) obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o +obj-$(CONFIG_SPI_ATH79) += ath79_spi.o obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c new file mode 100644 index 000000000000..fcff810ea3b0 --- /dev/null +++ b/drivers/spi/ath79_spi.c @@ -0,0 +1,292 @@ +/* + * SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs + * + * Copyright (C) 2009-2011 Gabor Juhos + * + * This driver has been based on the spi-gpio.c: + * Copyright (C) 2006,2008 David Brownell + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "ath79-spi" + +struct ath79_spi { + struct spi_bitbang bitbang; + u32 ioc_base; + u32 reg_ctrl; + void __iomem *base; +}; + +static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg) +{ + return ioread32(sp->base + reg); +} + +static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val) +{ + iowrite32(val, sp->base + reg); +} + +static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi) +{ + return spi_master_get_devdata(spi->master); +} + +static void ath79_spi_chipselect(struct spi_device *spi, int is_active) +{ + struct ath79_spi *sp = ath79_spidev_to_sp(spi); + int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active; + + if (is_active) { + /* set initial clock polarity */ + if (spi->mode & SPI_CPOL) + sp->ioc_base |= AR71XX_SPI_IOC_CLK; + else + sp->ioc_base &= ~AR71XX_SPI_IOC_CLK; + + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); + } + + if (spi->chip_select) { + struct ath79_spi_controller_data *cdata = spi->controller_data; + + /* SPI is normally active-low */ + gpio_set_value(cdata->gpio, cs_high); + } else { + if (cs_high) + sp->ioc_base |= AR71XX_SPI_IOC_CS0; + else + sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); + } + +} + +static int ath79_spi_setup_cs(struct spi_device *spi) +{ + struct ath79_spi *sp = ath79_spidev_to_sp(spi); + struct ath79_spi_controller_data *cdata; + + cdata = spi->controller_data; + if (spi->chip_select && !cdata) + return -EINVAL; + + /* enable GPIO mode */ + ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); + + /* save CTRL register */ + sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL); + sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC); + + /* TODO: setup speed? */ + ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43); + + if (spi->chip_select) { + int status = 0; + + status = gpio_request(cdata->gpio, dev_name(&spi->dev)); + if (status) + return status; + + status = gpio_direction_output(cdata->gpio, + spi->mode & SPI_CS_HIGH); + if (status) { + gpio_free(cdata->gpio); + return status; + } + } else { + if (spi->mode & SPI_CS_HIGH) + sp->ioc_base |= AR71XX_SPI_IOC_CS0; + else + sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); + } + + return 0; +} + +static void ath79_spi_cleanup_cs(struct spi_device *spi) +{ + struct ath79_spi *sp = ath79_spidev_to_sp(spi); + + if (spi->chip_select) { + struct ath79_spi_controller_data *cdata = spi->controller_data; + gpio_free(cdata->gpio); + } + + /* restore CTRL register */ + ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl); + /* disable GPIO mode */ + ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0); +} + +static int ath79_spi_setup(struct spi_device *spi) +{ + int status = 0; + + if (spi->bits_per_word > 32) + return -EINVAL; + + if (!spi->controller_state) { + status = ath79_spi_setup_cs(spi); + if (status) + return status; + } + + status = spi_bitbang_setup(spi); + if (status && !spi->controller_state) + ath79_spi_cleanup_cs(spi); + + return status; +} + +static void ath79_spi_cleanup(struct spi_device *spi) +{ + ath79_spi_cleanup_cs(spi); + spi_bitbang_cleanup(spi); +} + +static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs, + u32 word, u8 bits) +{ + struct ath79_spi *sp = ath79_spidev_to_sp(spi); + u32 ioc = sp->ioc_base; + + /* clock starts at inactive polarity */ + for (word <<= (32 - bits); likely(bits); bits--) { + u32 out; + + if (word & (1 << 31)) + out = ioc | AR71XX_SPI_IOC_DO; + else + out = ioc & ~AR71XX_SPI_IOC_DO; + + /* setup MSB (to slave) on trailing edge */ + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out); + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK); + + word <<= 1; + } + + return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS); +} + +static __devinit int ath79_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct ath79_spi *sp; + struct ath79_spi_platform_data *pdata; + struct resource *r; + int ret; + + master = spi_alloc_master(&pdev->dev, sizeof(*sp)); + if (master == NULL) { + dev_err(&pdev->dev, "failed to allocate spi master\n"); + return -ENOMEM; + } + + sp = spi_master_get_devdata(master); + platform_set_drvdata(pdev, sp); + + pdata = pdev->dev.platform_data; + + master->setup = ath79_spi_setup; + master->cleanup = ath79_spi_cleanup; + if (pdata) { + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->num_chipselect; + } else { + master->bus_num = -1; + master->num_chipselect = 1; + } + + sp->bitbang.master = spi_master_get(master); + sp->bitbang.chipselect = ath79_spi_chipselect; + sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0; + sp->bitbang.setup_transfer = spi_bitbang_setup_transfer; + sp->bitbang.flags = SPI_CS_HIGH; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + ret = -ENOENT; + goto err_put_master; + } + + sp->base = ioremap(r->start, r->end - r->start + 1); + if (!sp->base) { + ret = -ENXIO; + goto err_put_master; + } + + ret = spi_bitbang_start(&sp->bitbang); + if (ret) + goto err_unmap; + + return 0; + +err_unmap: + iounmap(sp->base); +err_put_master: + platform_set_drvdata(pdev, NULL); + spi_master_put(sp->bitbang.master); + + return ret; +} + +static __devexit int ath79_spi_remove(struct platform_device *pdev) +{ + struct ath79_spi *sp = platform_get_drvdata(pdev); + + spi_bitbang_stop(&sp->bitbang); + iounmap(sp->base); + platform_set_drvdata(pdev, NULL); + spi_master_put(sp->bitbang.master); + + return 0; +} + +static struct platform_driver ath79_spi_driver = { + .probe = ath79_spi_probe, + .remove = __devexit_p(ath79_spi_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static __init int ath79_spi_init(void) +{ + return platform_driver_register(&ath79_spi_driver); +} +module_init(ath79_spi_init); + +static __exit void ath79_spi_exit(void) +{ + platform_driver_unregister(&ath79_spi_driver); +} +module_exit(ath79_spi_exit); + +MODULE_DESCRIPTION("SPI controller driver for Atheros AR71XX/AR724X/AR913X"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From c7bf71c517abfc3b15970d67910e0f62e0522939 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Jan 2011 12:48:20 -0800 Subject: hwmon: (lm93) Add support for LM94 This patch adds basic support for LM94 to the LM93 driver. LM94 specific sensors and features are not supported. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- Documentation/hwmon/lm93 | 7 +++++++ drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/lm93.c | 21 +++++++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93 index 7a10616d0b44..f3b2ad2ceb01 100644 --- a/Documentation/hwmon/lm93 +++ b/Documentation/hwmon/lm93 @@ -6,6 +6,10 @@ Supported chips: Prefix 'lm93' Addresses scanned: I2C 0x2c-0x2e Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf + * National Semiconductor LM94 + Prefix 'lm94' + Addresses scanned: I2C 0x2c-0x2e + Datasheet: http://www.national.com/ds.cgi/LM/LM94.pdf Authors: Mark M. Hoffman @@ -56,6 +60,9 @@ previous motherboard management ASICs and uses some of the LM85's features for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual processor Xeon class motherboard with a minimum of external components. +LM94 is also supported in LM93 compatible mode. Extra sensors and features of +LM94 are not supported. + User Interface -------------- diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 35f00dae3676..773e484f1646 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -618,8 +618,8 @@ config SENSORS_LM93 depends on I2C select HWMON_VID help - If you say yes here you get support for National Semiconductor LM93 - sensor chips. + If you say yes here you get support for National Semiconductor LM93, + LM94, and compatible sensor chips. This driver can also be built as a module. If so, the module will be called lm93. diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index c9ed14eba5a6..3b43df418613 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -135,6 +135,11 @@ #define LM93_MFR_ID 0x73 #define LM93_MFR_ID_PROTOTYPE 0x72 +/* LM94 REGISTER VALUES */ +#define LM94_MFR_ID_2 0x7a +#define LM94_MFR_ID 0x79 +#define LM94_MFR_ID_PROTOTYPE 0x78 + /* SMBus capabilities */ #define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA) @@ -2504,6 +2509,7 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; int mfr, ver; + const char *name; if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN)) return -ENODEV; @@ -2517,13 +2523,23 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) } ver = lm93_read_byte(client, LM93_REG_VER); - if (ver != LM93_MFR_ID && ver != LM93_MFR_ID_PROTOTYPE) { + switch (ver) { + case LM93_MFR_ID: + case LM93_MFR_ID_PROTOTYPE: + name = "lm93"; + break; + case LM94_MFR_ID_2: + case LM94_MFR_ID: + case LM94_MFR_ID_PROTOTYPE: + name = "lm94"; + break; + default: dev_dbg(&adapter->dev, "detect failed, bad version id 0x%02x!\n", ver); return -ENODEV; } - strlcpy(info->type, "lm93", I2C_NAME_SIZE); + strlcpy(info->type, name, I2C_NAME_SIZE); dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n", client->name, i2c_adapter_id(client->adapter), client->addr); @@ -2602,6 +2618,7 @@ static int lm93_remove(struct i2c_client *client) static const struct i2c_device_id lm93_id[] = { { "lm93", 0 }, + { "lm94", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, lm93_id); -- cgit v1.2.3 From be33b76a974cdb4ceadc1a12fb79cc97bcfeea37 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 16 Jan 2011 20:37:52 +0100 Subject: ACPICA: Fix memory leak in acpi_ev_asynch_execute_gpe_method(). We will leak the memory allocated to 'local_gpe_event_info' if 'acpi_ut_acquire_mutex()' fails or if 'acpi_ev_valid_gpe_event()' fails in drivers/acpi/acpica/evgpe.c::acpi_ev_asynch_execute_gpe_method(). Signed-off-by: Jesper Juhl Reviewed-by: Rafael Wysocki Signed-off-by: Len Brown --- drivers/acpi/acpica/evgpe.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 7c339d34ab42..b6de1fb34f44 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -471,6 +471,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { + ACPI_FREE(local_gpe_event_info); return_VOID; } @@ -478,6 +479,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) if (!acpi_ev_valid_gpe_event(gpe_event_info)) { status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); + ACPI_FREE(local_gpe_event_info); return_VOID; } -- cgit v1.2.3 From 5d3131f5b0ae6303d042fd91ed9147ad4ae4bf6d Mon Sep 17 00:00:00 2001 From: Dana Myers Date: Wed, 12 Jan 2011 09:09:31 +0800 Subject: ACPICA: Fix namespace race condition Fixes a race condition between method execution and namespace walks that can possibly fault. Problem was apparently introduced in version 20100528 as a result of a performance optimization that reduces the number of namespace walks upon method exit by using the delete_namespace_subtree function instead of the delete_namespace_by_owner function used previously. Bug is in the delete_namespace_subtree function. Signed-off-by: Dana Myers Signed-off-by: Bob Moore Signed-off-by: Lin Ming Reviewed-by: Rafael Wysocki Signed-off-by: Len Brown --- drivers/acpi/acpica/nsalloc.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 1e5ff803d9ad..222a23e838d6 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -341,6 +341,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) { struct acpi_namespace_node *child_node = NULL; u32 level = 1; + acpi_status status; ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); @@ -348,6 +349,13 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) return_VOID; } + /* Lock namespace for possible update */ + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_VOID; + } + /* * Traverse the tree of objects until we bubble back up * to where we started. @@ -397,6 +405,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) } } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; } -- cgit v1.2.3 From 672af843abfc9a41c7ec792722e04b6c68a3cfea Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 12 Jan 2011 09:13:31 +0800 Subject: ACPICA: Debugger: Lock namespace for duration of a namespace dump Prevents issues if the namespace is changing underneath the debugger. Especially temporary nodes, since the debugger displays these also. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Reviewed-by: Rafael Wysocki Signed-off-by: Len Brown --- drivers/acpi/acpica/nsdump.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index a54dc39e304b..82693c3eb257 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -624,9 +624,22 @@ acpi_ns_dump_objects(acpi_object_type type, acpi_owner_id owner_id, acpi_handle start_handle) { struct acpi_walk_info info; + acpi_status status; ACPI_FUNCTION_ENTRY(); + /* + * Just lock the entire namespace for the duration of the dump. + * We don't want any changes to the namespace during this time, + * especially the temporary nodes since we are going to display + * them also. + */ + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + acpi_os_printf("Could not acquire namespace mutex\n"); + return; + } + info.debug_level = ACPI_LV_TABLES; info.owner_id = owner_id; info.display_type = display_type; @@ -636,6 +649,8 @@ acpi_ns_dump_objects(acpi_object_type type, ACPI_NS_WALK_TEMP_NODES, acpi_ns_dump_one_object, NULL, (void *)&info, NULL); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); } #endif /* ACPI_FUTURE_USAGE */ -- cgit v1.2.3 From 262948428878fb340127faca1791acb17146122e Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Wed, 12 Jan 2011 09:19:43 +0800 Subject: ACPICA: Fix issues/fault with automatic "serialized" method support History: This support changes a method to "serialized" on the fly if the method generates an AE_ALREADY_EXISTS error, indicating the possibility that it cannot handle reentrancy. This fix repairs a couple of issues seen in the field, especially on machines with many cores. 1) Delete method children only upon the exit of the last thread, so as to not delete objects out from under running threads. 2) Set the "serialized" bit for the method only upon the exit of the last thread, so as to not cause deadlock when running threads attempt to exit. 3) Cleanup the use of the AML "MethodFlags" and internal method flags so that there is no longer any confustion between the two. Reported-by: Dana Myers Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/acobject.h | 14 +++++++--- drivers/acpi/acpica/amlcode.h | 8 +----- drivers/acpi/acpica/dsmethod.c | 62 ++++++++++++++++++++++++++++++++---------- drivers/acpi/acpica/evrgnini.c | 4 +-- drivers/acpi/acpica/excreate.c | 8 +++--- drivers/acpi/acpica/exdump.c | 2 +- drivers/acpi/acpica/nsaccess.c | 6 ++-- drivers/acpi/acpica/nsalloc.c | 4 +-- drivers/acpi/acpica/nseval.c | 2 +- drivers/acpi/acpica/nsxfname.c | 5 ++-- drivers/acpi/acpica/psloop.c | 2 +- drivers/acpi/acpica/psparse.c | 25 ++++++----------- drivers/acpi/acpica/psxface.c | 7 ++--- 13 files changed, 85 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index bdbfaf22bd14..efaf9c6090f5 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -97,8 +97,6 @@ #define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */ #define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */ #define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */ -#define AOPOBJ_MODULE_LEVEL 0x40 /* Method is actually module-level code */ -#define AOPOBJ_MODIFIED_NAMESPACE 0x80 /* Method modified the namespace */ /****************************************************************************** * @@ -175,7 +173,7 @@ struct acpi_object_region { }; struct acpi_object_method { - ACPI_OBJECT_COMMON_HEADER u8 method_flags; + ACPI_OBJECT_COMMON_HEADER u8 info_flags; u8 param_count; u8 sync_level; union acpi_operand_object *mutex; @@ -183,13 +181,21 @@ struct acpi_object_method { union { ACPI_INTERNAL_METHOD implementation; union acpi_operand_object *handler; - } extra; + } dispatch; u32 aml_length; u8 thread_count; acpi_owner_id owner_id; }; +/* Flags for info_flags field above */ + +#define ACPI_METHOD_MODULE_LEVEL 0x01 /* Method is actually module-level code */ +#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */ +#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */ +#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */ +#define ACPI_METHOD_MODIFIED_NAMESPACE 0x10 /* Method modified the namespace */ + /****************************************************************************** * * Objects that can be notified. All share a common notify_info area. diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 1f484ba228fc..ac1f561ce392 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -480,16 +480,10 @@ typedef enum { AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D } AML_ACCESS_ATTRIBUTE; -/* Bit fields in method_flags byte */ +/* Bit fields in the AML method_flags byte */ #define AML_METHOD_ARG_COUNT 0x07 #define AML_METHOD_SERIALIZED 0x08 #define AML_METHOD_SYNC_LEVEL 0xF0 -/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ - -#define AML_METHOD_INTERNAL_ONLY 0x01 -#define AML_METHOD_RESERVED1 0x02 -#define AML_METHOD_RESERVED2 0x04 - #endif /* __AMLCODE_H__ */ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index d94dd8974b55..5a79f401a113 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -43,7 +43,6 @@ #include #include "accommon.h" -#include "amlcode.h" #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" @@ -201,7 +200,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, /* * If this method is serialized, we need to acquire the method mutex. */ - if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) { + if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) { /* * Create a mutex for the method if it is defined to be Serialized * and a mutex has not already been created. We defer the mutex creation @@ -413,8 +412,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, /* Invoke an internal method if necessary */ - if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { - status = obj_desc->method.extra.implementation(next_walk_state); + if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { + status = + obj_desc->method.dispatch.implementation(next_walk_state); if (status == AE_OK) { status = AE_CTRL_TERMINATE; } @@ -579,11 +579,14 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, /* * Delete any namespace objects created anywhere within the - * namespace by the execution of this method. Unless this method - * is a module-level executable code method, in which case we - * want make the objects permanent. + * namespace by the execution of this method. Unless: + * 1) This method is a module-level executable code method, in which + * case we want make the objects permanent. + * 2) There are other threads executing the method, in which case we + * will wait until the last thread has completed. */ - if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) { + if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) + && (method_desc->method.thread_count == 1)) { /* Delete any direct children of (created by) this method */ @@ -593,12 +596,17 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, /* * Delete any objects that were created by this method * elsewhere in the namespace (if any were created). + * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the + * deletion such that we don't have to perform an entire + * namespace walk for every control method execution. */ if (method_desc->method. - flags & AOPOBJ_MODIFIED_NAMESPACE) { + info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) { acpi_ns_delete_namespace_by_owner(method_desc-> method. owner_id); + method_desc->method.info_flags &= + ~ACPI_METHOD_MODIFIED_NAMESPACE; } } } @@ -629,19 +637,43 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, * Serialized if it appears that the method is incorrectly written and * does not support multiple thread execution. The best example of this * is if such a method creates namespace objects and blocks. A second - * thread will fail with an AE_ALREADY_EXISTS exception + * thread will fail with an AE_ALREADY_EXISTS exception. * * This code is here because we must wait until the last thread exits - * before creating the synchronization semaphore. + * before marking the method as serialized. */ - if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED) - && (!method_desc->method.mutex)) { - (void)acpi_ds_create_method_mutex(method_desc); + if (method_desc->method. + info_flags & ACPI_METHOD_SERIALIZED_PENDING) { + if (walk_state) { + ACPI_INFO((AE_INFO, + "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", + walk_state->method_node->name. + ascii)); + } + + /* + * Method tried to create an object twice and was marked as + * "pending serialized". The probable cause is that the method + * cannot handle reentrancy. + * + * The method was created as not_serialized, but it tried to create + * a named object and then blocked, causing the second thread + * entrance to begin and then fail. Workaround this problem by + * marking the method permanently as Serialized when the last + * thread exits here. + */ + method_desc->method.info_flags &= + ~ACPI_METHOD_SERIALIZED_PENDING; + method_desc->method.info_flags |= + ACPI_METHOD_SERIALIZED; + method_desc->method.sync_level = 0; } /* No more threads, we can free the owner_id */ - if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) { + if (! + (method_desc->method. + info_flags & ACPI_METHOD_MODULE_LEVEL)) { acpi_ut_release_owner_id(&method_desc->method.owner_id); } } diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 0b47a6dc9290..2ef32e952559 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -590,9 +590,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, * See acpi_ns_exec_module_code */ if (obj_desc->method. - flags & AOPOBJ_MODULE_LEVEL) { + info_flags & ACPI_METHOD_MODULE_LEVEL) { handler_obj = - obj_desc->method.extra.handler; + obj_desc->method.dispatch.handler; } break; diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 3c61b48c73f5..ffac8c7e54c5 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -482,13 +482,11 @@ acpi_ex_create_method(u8 * aml_start, obj_desc->method.aml_length = aml_length; /* - * Disassemble the method flags. Split off the Arg Count - * for efficiency + * Disassemble the method flags. Split off the arg_count, Serialized + * flag, and sync_level for efficiency. */ method_flags = (u8) operand[1]->integer.value; - obj_desc->method.method_flags = - (u8) (method_flags & ~AML_METHOD_ARG_COUNT); obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); @@ -497,6 +495,8 @@ acpi_ex_create_method(u8 * aml_start, * created for this method when it is parsed. */ if (method_flags & AML_METHOD_SERIALIZED) { + obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED; + /* * ACPI 1.0: sync_level = 0 * ACPI 2.0: sync_level = sync_level in method declaration diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index f067bbb0d961..ff4b1e61c318 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -122,7 +122,7 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { static struct acpi_exdump_info acpi_ex_dump_method[9] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.info_flags), "Info Flags"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "Parameter Count"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 0cd925be5fc1..cede0e3200e4 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -163,9 +163,9 @@ acpi_status acpi_ns_root_initialize(void) #else /* Mark this as a very SPECIAL method */ - obj_desc->method.method_flags = - AML_METHOD_INTERNAL_ONLY; - obj_desc->method.extra.implementation = + obj_desc->method.info_flags = + ACPI_METHOD_INTERNAL_ONLY; + obj_desc->method.dispatch.implementation = acpi_ut_osi_implementation; #endif break; diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 222a23e838d6..222a9843268d 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -234,8 +234,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp * modified the namespace. This is used for cleanup when the * method exits. */ - walk_state->method_desc->method.flags |= - AOPOBJ_MODIFIED_NAMESPACE; + walk_state->method_desc->method.info_flags |= + ACPI_METHOD_MODIFIED_NAMESPACE; } } diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index f52829cc294b..a55c0d2295ca 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -389,7 +389,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, * acpi_gbl_root_node->Object is NULL at PASS1. */ if ((type == ACPI_TYPE_DEVICE) && parent_node->object) { - method_obj->method.extra.handler = + method_obj->method.dispatch.handler = parent_node->object->device.handler; } diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index b01e45a415e3..0a26d73e050a 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -603,10 +603,9 @@ acpi_status acpi_install_method(u8 *buffer) method_obj->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); - method_obj->method.method_flags = (u8) - (method_flags & ~AML_METHOD_ARG_COUNT); - if (method_flags & AML_METHOD_SERIALIZED) { + method_obj->method.info_flags = ACPI_METHOD_SERIALIZED; + method_obj->method.sync_level = (u8) ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 2f2e7760938c..06edeaf3b5e5 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -655,7 +655,7 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op, method_obj->method.aml_start = aml_start; method_obj->method.aml_length = aml_length; method_obj->method.owner_id = owner_id; - method_obj->method.flags |= AOPOBJ_MODULE_LEVEL; + method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL; /* * Save the parent node in next_object. This is cheating, but we diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 8d81542194d4..3b8de113b571 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -55,7 +55,6 @@ #include "acparser.h" #include "acdispat.h" #include "amlcode.h" -#include "acnamesp.h" #include "acinterp.h" #define _COMPONENT ACPI_PARSER @@ -539,24 +538,16 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) /* Check for possible multi-thread reentrancy problem */ if ((status == AE_ALREADY_EXISTS) && - (!walk_state->method_desc->method.mutex)) { - ACPI_INFO((AE_INFO, - "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", - walk_state->method_node->name. - ascii)); - + (!(walk_state->method_desc->method. + info_flags & ACPI_METHOD_SERIALIZED))) { /* - * Method tried to create an object twice. The probable cause is - * that the method cannot handle reentrancy. - * - * The method is marked not_serialized, but it tried to create - * a named object, causing the second thread entrance to fail. - * Workaround this problem by marking the method permanently - * as Serialized. + * Method is not serialized and tried to create an object + * twice. The probable cause is that the method cannot + * handle reentrancy. Mark as "pending serialized" now, and + * then mark "serialized" when the last thread exits. */ - walk_state->method_desc->method.method_flags |= - AML_METHOD_SERIALIZED; - walk_state->method_desc->method.sync_level = 0; + walk_state->method_desc->method.info_flags |= + ACPI_METHOD_SERIALIZED_PENDING; } } diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index c42f067cff9d..bc49a80c386d 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -47,7 +47,6 @@ #include "acdispat.h" #include "acinterp.h" #include "actables.h" -#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psxface") @@ -285,15 +284,15 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) goto cleanup; } - if (info->obj_desc->method.flags & AOPOBJ_MODULE_LEVEL) { + if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; } /* Invoke an internal method if necessary */ - if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { + if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { status = - info->obj_desc->method.extra.implementation(walk_state); + info->obj_desc->method.dispatch.implementation(walk_state); info->return_object = walk_state->return_desc; /* Cleanup states */ -- cgit v1.2.3 From b4e104eaeb8cd4329a23e0e4ebf166681b1d182d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 17 Jan 2011 11:05:40 +0800 Subject: ACPICA: Update all ACPICA copyrights and signons to 2011 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/accommon.h | 2 +- drivers/acpi/acpica/acconfig.h | 2 +- drivers/acpi/acpica/acdebug.h | 2 +- drivers/acpi/acpica/acdispat.h | 2 +- drivers/acpi/acpica/acevents.h | 2 +- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/achware.h | 2 +- drivers/acpi/acpica/acinterp.h | 2 +- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/acmacros.h | 2 +- drivers/acpi/acpica/acnamesp.h | 2 +- drivers/acpi/acpica/acobject.h | 2 +- drivers/acpi/acpica/acopcode.h | 2 +- drivers/acpi/acpica/acparser.h | 2 +- drivers/acpi/acpica/acpredef.h | 2 +- drivers/acpi/acpica/acresrc.h | 2 +- drivers/acpi/acpica/acstruct.h | 2 +- drivers/acpi/acpica/actables.h | 2 +- drivers/acpi/acpica/acutils.h | 2 +- drivers/acpi/acpica/amlcode.h | 2 +- drivers/acpi/acpica/amlresrc.h | 2 +- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dsinit.c | 2 +- drivers/acpi/acpica/dsmethod.c | 2 +- drivers/acpi/acpica/dsmthdat.c | 2 +- drivers/acpi/acpica/dsobject.c | 2 +- drivers/acpi/acpica/dsopcode.c | 2 +- drivers/acpi/acpica/dsutils.c | 2 +- drivers/acpi/acpica/dswexec.c | 2 +- drivers/acpi/acpica/dswload.c | 2 +- drivers/acpi/acpica/dswscope.c | 2 +- drivers/acpi/acpica/dswstate.c | 2 +- drivers/acpi/acpica/evevent.c | 2 +- drivers/acpi/acpica/evgpe.c | 2 +- drivers/acpi/acpica/evgpeblk.c | 2 +- drivers/acpi/acpica/evgpeinit.c | 2 +- drivers/acpi/acpica/evgpeutil.c | 2 +- drivers/acpi/acpica/evmisc.c | 2 +- drivers/acpi/acpica/evregion.c | 2 +- drivers/acpi/acpica/evrgnini.c | 2 +- drivers/acpi/acpica/evsci.c | 2 +- drivers/acpi/acpica/evxface.c | 2 +- drivers/acpi/acpica/evxfevnt.c | 2 +- drivers/acpi/acpica/evxfgpe.c | 2 +- drivers/acpi/acpica/evxfregn.c | 2 +- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/exconvrt.c | 2 +- drivers/acpi/acpica/excreate.c | 2 +- drivers/acpi/acpica/exdebug.c | 2 +- drivers/acpi/acpica/exdump.c | 2 +- drivers/acpi/acpica/exfield.c | 2 +- drivers/acpi/acpica/exfldio.c | 2 +- drivers/acpi/acpica/exmisc.c | 2 +- drivers/acpi/acpica/exmutex.c | 2 +- drivers/acpi/acpica/exnames.c | 2 +- drivers/acpi/acpica/exoparg1.c | 2 +- drivers/acpi/acpica/exoparg2.c | 2 +- drivers/acpi/acpica/exoparg3.c | 2 +- drivers/acpi/acpica/exoparg6.c | 2 +- drivers/acpi/acpica/exprep.c | 2 +- drivers/acpi/acpica/exregion.c | 2 +- drivers/acpi/acpica/exresnte.c | 2 +- drivers/acpi/acpica/exresolv.c | 2 +- drivers/acpi/acpica/exresop.c | 2 +- drivers/acpi/acpica/exstore.c | 2 +- drivers/acpi/acpica/exstoren.c | 2 +- drivers/acpi/acpica/exstorob.c | 2 +- drivers/acpi/acpica/exsystem.c | 2 +- drivers/acpi/acpica/exutils.c | 2 +- drivers/acpi/acpica/hwacpi.c | 2 +- drivers/acpi/acpica/hwgpe.c | 2 +- drivers/acpi/acpica/hwpci.c | 2 +- drivers/acpi/acpica/hwregs.c | 2 +- drivers/acpi/acpica/hwsleep.c | 2 +- drivers/acpi/acpica/hwtimer.c | 2 +- drivers/acpi/acpica/hwvalid.c | 2 +- drivers/acpi/acpica/hwxface.c | 2 +- drivers/acpi/acpica/nsaccess.c | 2 +- drivers/acpi/acpica/nsalloc.c | 2 +- drivers/acpi/acpica/nsdump.c | 2 +- drivers/acpi/acpica/nsdumpdv.c | 2 +- drivers/acpi/acpica/nseval.c | 2 +- drivers/acpi/acpica/nsinit.c | 2 +- drivers/acpi/acpica/nsload.c | 2 +- drivers/acpi/acpica/nsnames.c | 2 +- drivers/acpi/acpica/nsobject.c | 2 +- drivers/acpi/acpica/nsparse.c | 2 +- drivers/acpi/acpica/nspredef.c | 2 +- drivers/acpi/acpica/nsrepair.c | 2 +- drivers/acpi/acpica/nsrepair2.c | 2 +- drivers/acpi/acpica/nssearch.c | 2 +- drivers/acpi/acpica/nsutils.c | 2 +- drivers/acpi/acpica/nswalk.c | 2 +- drivers/acpi/acpica/nsxfeval.c | 2 +- drivers/acpi/acpica/nsxfname.c | 2 +- drivers/acpi/acpica/nsxfobj.c | 2 +- drivers/acpi/acpica/psargs.c | 2 +- drivers/acpi/acpica/psloop.c | 2 +- drivers/acpi/acpica/psopcode.c | 2 +- drivers/acpi/acpica/psparse.c | 2 +- drivers/acpi/acpica/psscope.c | 2 +- drivers/acpi/acpica/pstree.c | 2 +- drivers/acpi/acpica/psutils.c | 2 +- drivers/acpi/acpica/pswalk.c | 2 +- drivers/acpi/acpica/psxface.c | 2 +- drivers/acpi/acpica/rsaddr.c | 2 +- drivers/acpi/acpica/rscalc.c | 2 +- drivers/acpi/acpica/rscreate.c | 2 +- drivers/acpi/acpica/rsdump.c | 2 +- drivers/acpi/acpica/rsinfo.c | 2 +- drivers/acpi/acpica/rsio.c | 2 +- drivers/acpi/acpica/rsirq.c | 2 +- drivers/acpi/acpica/rslist.c | 2 +- drivers/acpi/acpica/rsmemory.c | 2 +- drivers/acpi/acpica/rsmisc.c | 2 +- drivers/acpi/acpica/rsutils.c | 2 +- drivers/acpi/acpica/rsxface.c | 2 +- drivers/acpi/acpica/tbfadt.c | 2 +- drivers/acpi/acpica/tbfind.c | 2 +- drivers/acpi/acpica/tbinstal.c | 2 +- drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 2 +- drivers/acpi/acpica/tbxfroot.c | 2 +- drivers/acpi/acpica/utalloc.c | 2 +- drivers/acpi/acpica/utcopy.c | 2 +- drivers/acpi/acpica/utdebug.c | 2 +- drivers/acpi/acpica/utdelete.c | 2 +- drivers/acpi/acpica/uteval.c | 2 +- drivers/acpi/acpica/utglobal.c | 2 +- drivers/acpi/acpica/utids.c | 2 +- drivers/acpi/acpica/utinit.c | 2 +- drivers/acpi/acpica/utlock.c | 2 +- drivers/acpi/acpica/utmath.c | 2 +- drivers/acpi/acpica/utmisc.c | 2 +- drivers/acpi/acpica/utmutex.c | 2 +- drivers/acpi/acpica/utobject.c | 2 +- drivers/acpi/acpica/utosi.c | 2 +- drivers/acpi/acpica/utresrc.c | 2 +- drivers/acpi/acpica/utstate.c | 2 +- drivers/acpi/acpica/utxface.c | 2 +- drivers/acpi/acpica/utxferror.c | 2 +- include/acpi/acexcep.h | 2 +- include/acpi/acnames.h | 2 +- include/acpi/acoutput.h | 2 +- include/acpi/acpi.h | 2 +- include/acpi/acpiosxf.h | 2 +- include/acpi/acpixf.h | 2 +- include/acpi/acrestyp.h | 2 +- include/acpi/actbl.h | 2 +- include/acpi/actbl1.h | 2 +- include/acpi/actbl2.h | 2 +- include/acpi/actypes.h | 2 +- include/acpi/platform/acenv.h | 2 +- include/acpi/platform/acgcc.h | 2 +- include/acpi/platform/aclinux.h | 2 +- 155 files changed, 155 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 3e50c74ed4a1..e0ba17f0a7c8 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index b17d8de9f6ff..ab87396c2c07 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 72e9d5eb083c..eb0b1f8dee6d 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 894a0ff2a946..666271b65418 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 70e0b28801aa..41d247daf461 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 9bb69c59bb12..c129a295da3c 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 258d628793ea..e7213beaafc7 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 049e203bd621..3731e1c34b83 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 74000f5b7dab..54784bb42cec 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 8d5c9e0a495f..b7491ee1fba6 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index d44d3bc5b847..79a598c67fe3 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index efaf9c6090f5..a0272e6792bf 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index 8c15ff43f42b..bb2ccfad7376 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index d0bb0fd3e57a..5ea1e06afa20 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 10998d369ad0..94e73c97cf85 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index 528bcbaf4ce7..f08b55b7f3a0 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 6e5dd97949fe..1623b245dde2 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 62a576e34361..967f08124eba 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 72e4183c1937..99c140d8e348 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ac1f561ce392..f4f0998d3967 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 0e5798fcbb19..59122cde247c 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 347bee1726f1..34be60c0e448 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index cc4a38c57558..a7718bf2b9a1 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 5a79f401a113..5d797751e205 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 8095306fcd8c..905ce29a92e1 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 8e85f54a8e0e..f42e17e5c252 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 7c0e74227171..bbecf293aeeb 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 15135c25aa9b..2c477ce172fa 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 6b0b5d08d97a..fe40e4c6554f 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 140a9d002959..52566ff5e903 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index d1e701709dac..76a661fc1e09 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 83155dd8671e..a6c374ef9914 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index e5e313c663a5..d458b041e651 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index b6de1fb34f44..14988a86066f 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 9acb86958c09..ca2c41a53311 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index c59dc2340593..ce9aa9f9a972 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 10e477494dcf..80a81d0c4a80 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index fcaed9fb44ff..ccd230b7aba4 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 98fd210e87b2..785a5ee64585 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 2ef32e952559..9659cee6093e 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 8dfbaa96e422..2ebd40e1a3ef 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 1226689bdb1b..e1141402dbed 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 90488c1e0f3d..c57b5c707a77 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 416845bc9c1f..e9562a7cb2f9 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index ce9314f79451..eb7386763712 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 18832205b631..745a42b401f5 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index b73bc50c5b76..74162a11817d 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index ffac8c7e54c5..e7b372d17667 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index be8c98b480d7..c7a2f1edd282 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index ff4b1e61c318..61b8c0e8b74d 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index f17d2ff0031b..0bde2230c028 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 38293fd3e088..6c79c29f082d 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 95db4be0877b..703d88ed0b3d 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 6af14e43f839..be1c56ead653 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index d11e539ef763..49ec049c157e 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 84e4d185aa25..236ead14b7f7 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 10e104cf0fb9..2571b4a310f4 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 7a08d23befcd..1b48d9d28c9a 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 4b50730cf9a0..f4a2787e8e92 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 7aae29f73d3f..cc95e2000406 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index de17e10da0ed..f0d5e14f1f2c 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 1fa4289a687e..55997e46948b 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index 7ca35ea8acea..db502cd7d934 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 8c97cfd6a0fd..e3bb00ccdff5 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 1624436ba4c5..c0c8842dd344 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index d4af684620ca..a979017d56b8 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index e972b667b09b..dc665cc554de 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index 675aaa91a770..df66e7b686be 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 4093522eed45..8ad93146dd32 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index b44274a0b62c..fc380d3d45ab 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 85c3cbd4304d..f610d88a66be 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index ad21c7d8bf4f..050fd227951b 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 5d1273b660ae..55accb7018bb 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 3796811276ac..2ac28bbe8827 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 1ef8e0bb250b..9c8eb71a12fb 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index e1d9c777b213..5f1605874655 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 50cc3be77724..6f98d210e71c 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index cede0e3200e4..d93172fd15a8 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 222a9843268d..1d0ef15d158f 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 82693c3eb257..b683cc2ff9d3 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index d2a97921e249..2ed294b7a4db 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index a55c0d2295ca..c1bd02b1a058 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 660a2728908d..4622852eca5e 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index df18be94fefe..5f7dc691c183 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index d3104af57e13..d5fa520c3de5 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 41a9213dd5af..3bb8bf105ea2 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 5808c89e9fac..b3234fa795b8 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 7096bcda0c72..9fb03fa8ffde 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index d1c136692667..1d76ac85b5e7 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 4ef9f43ea926..973883babee1 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 41102a84272f..28b0d7a62b99 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index a7d6ad9c111b..cb1b104a69a2 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 2cd5be8fe10f..345f0c3c6ad2 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index ebef8a7fd707..c53f0040e490 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 0a26d73e050a..3fd4526f3dba 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index a1f04e9b8030..db7660f8b869 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 7df1a4c95274..e1fad0ee0136 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 06edeaf3b5e5..01dd70d1de51 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 2b0c3be2b1b8..bed08de7528c 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 3b8de113b571..9bb0cbd37b5e 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index 40e2b279ea12..a5faa1323a02 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index d4b970c3630b..f1464c03aa42 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index fe29eee5adb1..7eda78503422 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 8abb9629443d..3312d6368bf1 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index bc49a80c386d..8086805d4494 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 226c806ae986..9e66f9078426 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index d6ebf7ec622d..3a8a89ec2ca4 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index c80a2eea3a01..4ce6e1147e80 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index f859b0386fe4..33db7520c74b 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 1fd868b964fd..f9ea60872aa4 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 33bff17c0bbc..0c7efef008be 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 545da40d7fa7..50b8ad211167 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 7335f22aac20..1bfcef736c50 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 887b8ba8c432..7cc6d8625f1e 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index f8cd9e87d987..410264b22a29 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 491191e6cf69..231811e56939 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 9f6a6e7e1c8e..2ff657a28f26 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index d2ff4325c427..428d44e2d162 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 989d5c867864..a55cb2bb5abb 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 83d7af8d0905..48db0944ce4a 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 34f9c2bc5e1f..0f2d395feaba 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 4a8b9e6ea57a..4b7085dfc683 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index fd2c07d1d3ac..7eb6c6cc1edf 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 8f0896281567..0a697351cf69 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 6fef83f04bcd..aded299a2fa8 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index f21c486929a5..a9bcd816dc29 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index ed794cd033ea..31f5a7832ef1 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 22f59ef604e0..18f73c9d10bc 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 508537f884ac..97dd9bbf055a 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index d2906328535d..b679ea693545 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index c1b1c803ea9b..191b6828cce9 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index b081cd46a15f..f6bb75c6faf5 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index 49cf7b7fd816..ce481da9bb45 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index c7d0e05ef5a4..c33a852d4f42 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index d9efa495b433..a429a74dcffa 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index fd1fa2749ea5..188340a017b4 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 18c59a85fdca..1fb10cb8f11d 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 7965919000b1..84e051844247 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index d35d109b8da2..30c21e1a9360 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 1f484c9a6888..98ad125e14ff 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 6f12e314fbae..916ae097c43c 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 17714beb868e..5b6c391efc8e 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 9cf736ea4691..fc1575fd4596 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index bc4a6deb73b0..ef1cef77d32b 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index a091cabca4b1..de39915f6b7f 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 65b3f5888f42..a3252a5ead66 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -8,7 +8,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 241b8a04c83c..2f38e299b0d9 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index e5526354ba5e..0a66cc45dd6b 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index ad2001683ba7..7e42bfee0e29 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index c637b75b9f3f..981349daf5d5 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index d4136b28011f..0fc15dfb2e22 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 939a431a6ab6..64f838beaabf 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index a3e334ab1119..5af3ed52ef98 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 5dcb9537343c..e228893591a9 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 572189e37133..5d2a5e9544d9 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without -- cgit v1.2.3 From f037484337ce009ff840de07ca3232808101db09 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 3 Jan 2011 07:33:25 -0300 Subject: [media] tda9875: remove duplicate driver In commit 411674fd189abe5910ea4caf08b7eac5c4a4d967 the tda9875 support was added to tvaudio. This means that tda9875 is no longer used since mid-2009. If there are out-of-tree users of this driver, then they can switch to tvaudio instead. The original commit message read as follows: This change allows bttv to use tvaudio for this device. Since this device has the same i2c address as the tda9874 we need to support both in the same tvaudio driver. This makes it possible for tvaudio to detect which chip is used. Originally the tda9875 was only available in the dedicated tda9875 driver, but that makes life very hard for bttv since loading tvaudio might misdetect a tda9875 as a tda9874. So there were good reasons for moving the tda9875 code into tvaudio. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 - drivers/media/video/Makefile | 1 - drivers/media/video/tda9875.c | 411 ------------------------------------------ 3 files changed, 421 deletions(-) delete mode 100644 drivers/media/video/tda9875.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index eb875af05e79..ef3e9852f37e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -141,15 +141,6 @@ config VIDEO_TDA9840 To compile this driver as a module, choose M here: the module will be called tda9840. -config VIDEO_TDA9875 - tristate "Philips TDA9875 audio processor" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for tda9875 audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tda9875. - config VIDEO_TEA6415C tristate "Philips TEA6415C audio processor" depends on I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 81e38cb0b846..a509d317e258 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -27,7 +27,6 @@ obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o -obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c deleted file mode 100644 index 35b6ff5db319..000000000000 --- a/drivers/media/video/tda9875.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * For the TDA9875 chip - * (The TDA9875 is used on the Diamond DTV2000 french version - * Other cards probably use these chips as well.) - * This driver will not complain if used with any - * other i2c device with the same address. - * - * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and - * Eric Sandeen - * Copyright (c) 2006 Mauro Carvalho Chehab - * This code is placed under the terms of the GNU General Public License - * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * Which was based on tda8425.c by Greg Alexander (c) 1998 - * - * OPTIONS: - * debug - set to 1 if you'd like to see debug messages - * - * Revision: 0.1 - original version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int debug; /* insmod parameter */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_LICENSE("GPL"); - - -/* This is a superset of the TDA9875 */ -struct tda9875 { - struct v4l2_subdev sd; - int rvol, lvol; - int bass, treble; -}; - -static inline struct tda9875 *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct tda9875, sd); -} - -#define dprintk if (debug) printk - -/* The TDA9875 is made by Philips Semiconductor - * http://www.semiconductors.philips.com - * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator - * - */ - - /* subaddresses for TDA9875 */ -#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/ -#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */ -#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ -#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ - -#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/ -#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/ -#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ -#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ - -#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/ -#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/ -#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/ -#define TDA9875_MVL 0x1a /* Main volume gauche */ -#define TDA9875_MVR 0x1b /* Main volume droite */ -#define TDA9875_MBA 0x1d /* Main Basse */ -#define TDA9875_MTR 0x1e /* Main treble */ -#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/ -#define TDA9875_AVL 0x20 /* Auxilary volume gauche */ -#define TDA9875_AVR 0x21 /* Auxilary volume droite */ -#define TDA9875_ABA 0x22 /* Auxilary Basse */ -#define TDA9875_ATR 0x23 /* Auxilary treble */ - -#define TDA9875_MSR 0x02 /* Monitor select register */ -#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */ -#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */ -#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */ -#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */ -#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */ -#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */ -#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/ -#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/ -#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/ - -/* values */ -#define TDA9875_MUTE_ON 0xff /* general mute */ -#define TDA9875_MUTE_OFF 0xcc /* general no mute */ - - - -/* Begin code */ - -static int tda9875_write(struct v4l2_subdev *sd, int subaddr, unsigned char val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned char buffer[2]; - - v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val); - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client, buffer, 2)) { - v4l2_warn(sd, "I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - - -static int i2c_read_register(struct i2c_client *client, int addr, int reg) -{ - unsigned char write[1]; - unsigned char read[1]; - struct i2c_msg msgs[2] = { - { addr, 0, 1, write }, - { addr, I2C_M_RD, 1, read } - }; - - write[0] = reg; - - if (2 != i2c_transfer(client->adapter, msgs, 2)) { - v4l_warn(client, "I/O error (read2)\n"); - return -1; - } - v4l_dbg(1, debug, client, "chip_read2: reg%d=0x%x\n", reg, read[0]); - return read[0]; -} - -static void tda9875_set(struct v4l2_subdev *sd) -{ - struct tda9875 *tda = to_state(sd); - unsigned char a; - - v4l2_dbg(1, debug, sd, "tda9875_set(%04x,%04x,%04x,%04x)\n", - tda->lvol, tda->rvol, tda->bass, tda->treble); - - a = tda->lvol & 0xff; - tda9875_write(sd, TDA9875_MVL, a); - a =tda->rvol & 0xff; - tda9875_write(sd, TDA9875_MVR, a); - a =tda->bass & 0xff; - tda9875_write(sd, TDA9875_MBA, a); - a =tda->treble & 0xff; - tda9875_write(sd, TDA9875_MTR, a); -} - -static void do_tda9875_init(struct v4l2_subdev *sd) -{ - struct tda9875 *t = to_state(sd); - - v4l2_dbg(1, debug, sd, "In tda9875_init\n"); - tda9875_write(sd, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/ - tda9875_write(sd, TDA9875_MSR, 0x03); /* Monitor 0b00000XXX*/ - tda9875_write(sd, TDA9875_C1MSB, 0x00); /*Car1(FM) MSB XMHz*/ - tda9875_write(sd, TDA9875_C1MIB, 0x00); /*Car1(FM) MIB XMHz*/ - tda9875_write(sd, TDA9875_C1LSB, 0x00); /*Car1(FM) LSB XMHz*/ - tda9875_write(sd, TDA9875_C2MSB, 0x00); /*Car2(NICAM) MSB XMHz*/ - tda9875_write(sd, TDA9875_C2MIB, 0x00); /*Car2(NICAM) MIB XMHz*/ - tda9875_write(sd, TDA9875_C2LSB, 0x00); /*Car2(NICAM) LSB XMHz*/ - tda9875_write(sd, TDA9875_DCR, 0x00); /*Demod config 0x00*/ - tda9875_write(sd, TDA9875_DEEM, 0x44); /*DE-Emph 0b0100 0100*/ - tda9875_write(sd, TDA9875_FMAT, 0x00); /*FM Matrix reg 0x00*/ - tda9875_write(sd, TDA9875_SC1, 0x00); /* SCART 1 (SC1)*/ - tda9875_write(sd, TDA9875_SC2, 0x01); /* SCART 2 (sc2)*/ - - tda9875_write(sd, TDA9875_CH1V, 0x10); /* Channel volume 1 mute*/ - tda9875_write(sd, TDA9875_CH2V, 0x10); /* Channel volume 2 mute */ - tda9875_write(sd, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/ - tda9875_write(sd, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/ - tda9875_write(sd, TDA9875_LOSR, 0x00); /* line out (in:mono)*/ - tda9875_write(sd, TDA9875_AER, 0x00); /*06 Effect (AVL+PSEUDO) */ - tda9875_write(sd, TDA9875_MCS, 0x44); /* Main ch select (DAC) */ - tda9875_write(sd, TDA9875_MVL, 0x03); /* Vol Main left 10dB */ - tda9875_write(sd, TDA9875_MVR, 0x03); /* Vol Main right 10dB*/ - tda9875_write(sd, TDA9875_MBA, 0x00); /* Main Bass Main 0dB*/ - tda9875_write(sd, TDA9875_MTR, 0x00); /* Main Treble Main 0dB*/ - tda9875_write(sd, TDA9875_ACS, 0x44); /* Aux chan select (dac)*/ - tda9875_write(sd, TDA9875_AVL, 0x00); /* Vol Aux left 0dB*/ - tda9875_write(sd, TDA9875_AVR, 0x00); /* Vol Aux right 0dB*/ - tda9875_write(sd, TDA9875_ABA, 0x00); /* Aux Bass Main 0dB*/ - tda9875_write(sd, TDA9875_ATR, 0x00); /* Aux Aigus Main 0dB*/ - - tda9875_write(sd, TDA9875_MUT, 0xcc); /* General mute */ - - t->lvol = t->rvol = 0; /* 0dB */ - t->bass = 0; /* 0dB */ - t->treble = 0; /* 0dB */ - tda9875_set(sd); -} - - -static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tda9875 *t = to_state(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - { - int left = (t->lvol+84)*606; - int right = (t->rvol+84)*606; - - ctrl->value=max(left,right); - return 0; - } - case V4L2_CID_AUDIO_BALANCE: - { - int left = (t->lvol+84)*606; - int right = (t->rvol+84)*606; - int volume = max(left,right); - int balance = (32768*min(left,right))/ - (volume ? volume : 1); - ctrl->value=(leftvalue = (t->bass+12)*2427; /* min -12 max +15 */ - return 0; - case V4L2_CID_AUDIO_TREBLE: - ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */ - return 0; - } - return -EINVAL; -} - -static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tda9875 *t = to_state(sd); - int chvol = 0, volume = 0, balance = 0, left, right; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - left = (t->lvol+84)*606; - right = (t->rvol+84)*606; - - volume = max(left,right); - balance = (32768*min(left,right))/ - (volume ? volume : 1); - balance =(leftvalue; - - chvol=1; - break; - case V4L2_CID_AUDIO_BALANCE: - left = (t->lvol+84)*606; - right = (t->rvol+84)*606; - - volume=max(left,right); - - balance = ctrl->value; - - chvol=1; - break; - case V4L2_CID_AUDIO_BASS: - t->bass = ((ctrl->value/2400)-12) & 0xff; - if (t->bass > 15) - t->bass = 15; - if (t->bass < -12) - t->bass = -12 & 0xff; - break; - case V4L2_CID_AUDIO_TREBLE: - t->treble = ((ctrl->value/2700)-12) & 0xff; - if (t->treble > 12) - t->treble = 12; - if (t->treble < -12) - t->treble = -12 & 0xff; - break; - default: - return -EINVAL; - } - - if (chvol) { - left = (min(65536 - balance,32768) * - volume) / 32768; - right = (min(balance,32768) * - volume) / 32768; - t->lvol = ((left/606)-84) & 0xff; - if (t->lvol > 24) - t->lvol = 24; - if (t->lvol < -84) - t->lvol = -84 & 0xff; - - t->rvol = ((right/606)-84) & 0xff; - if (t->rvol > 24) - t->rvol = 24; - if (t->rvol < -84) - t->rvol = -84 & 0xff; - } - - tda9875_set(sd); - return 0; -} - -static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - } - return -EINVAL; -} - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops tda9875_core_ops = { - .queryctrl = tda9875_queryctrl, - .g_ctrl = tda9875_g_ctrl, - .s_ctrl = tda9875_s_ctrl, -}; - -static const struct v4l2_subdev_ops tda9875_ops = { - .core = &tda9875_core_ops, -}; - -/* ----------------------------------------------------------------------- */ - - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda9875_checkit(struct i2c_client *client, int addr) -{ - int dic, rev; - - dic = i2c_read_register(client, addr, 254); - rev = i2c_read_register(client, addr, 255); - - if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */ - v4l_info(client, "tda9875%s rev. %d detected at 0x%02x\n", - dic == 0 ? "" : "A", rev, addr << 1); - return 1; - } - v4l_info(client, "no such chip at 0x%02x (dic=0x%x rev=0x%x)\n", - addr << 1, dic, rev); - return 0; -} - -static int tda9875_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tda9875 *t; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - if (!tda9875_checkit(client, client->addr)) - return -ENODEV; - - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (!t) - return -ENOMEM; - sd = &t->sd; - v4l2_i2c_subdev_init(sd, client, &tda9875_ops); - - do_tda9875_init(sd); - return 0; -} - -static int tda9875_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - do_tda9875_init(sd); - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); - return 0; -} - -static const struct i2c_device_id tda9875_id[] = { - { "tda9875", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tda9875_id); - -static struct i2c_driver tda9875_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tda9875", - }, - .probe = tda9875_probe, - .remove = tda9875_remove, - .id_table = tda9875_id, -}; - -static __init int init_tda9875(void) -{ - return i2c_add_driver(&tda9875_driver); -} - -static __exit void exit_tda9875(void) -{ - i2c_del_driver(&tda9875_driver); -} - -module_init(init_tda9875); -module_exit(exit_tda9875); -- cgit v1.2.3 From b219ab9cfb2057de6e779169197f83265c310c83 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 3 Jan 2011 07:39:41 -0300 Subject: [media] bttv: remove obsolete 'no_tda9875' field Since tda9875 is part of tvaudio this field no longer makes sense. Remove it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-cards.c | 39 ---------------------------------- drivers/media/video/bt8xx/bttv.h | 1 - 2 files changed, 40 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 49efcf660ba6..7f58756d72c8 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -1373,7 +1373,6 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0x1800, .audio_mode_gpio= fv2000s_audio, .no_msp34xx = 1, - .no_tda9875 = 1, .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, @@ -1511,7 +1510,6 @@ struct tvcard bttv_tvcards[] = { .gpiomute = 0x09, .needs_tvaudio = 1, .no_msp34xx = 1, - .no_tda9875 = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, @@ -1550,7 +1548,6 @@ struct tvcard bttv_tvcards[] = { .gpiomask2 = 0x07ff, .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), .no_msp34xx = 1, - .no_tda9875 = 1, .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .muxsel_hook = rv605_muxsel, @@ -1686,7 +1683,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY1x0_848] = { @@ -1699,7 +1695,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, @@ -1714,7 +1709,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY1x1] = { @@ -1727,7 +1721,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY1x1_SVID] = { @@ -1740,7 +1733,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY2xx] = { @@ -1753,7 +1745,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, @@ -1768,7 +1759,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY2x0] = { @@ -1781,7 +1771,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY500] = { @@ -1794,7 +1783,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, [BTTV_BOARD_OSPREY540] = { @@ -1805,7 +1793,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, @@ -1820,7 +1807,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ }, [BTTV_BOARD_IDS_EAGLE] = { @@ -1835,7 +1821,6 @@ struct tvcard bttv_tvcards[] = { .muxsel = MUXSEL(2, 2, 2, 2), .muxsel_hook = eagle_muxsel, .no_msp34xx = 1, - .no_tda9875 = 1, .pll = PLL_28, }, [BTTV_BOARD_PINNACLESAT] = { @@ -1846,7 +1831,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .muxsel = MUXSEL(3, 1), .pll = PLL_28, @@ -1897,7 +1881,6 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .gpiomask = 0, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .muxsel = MUXSEL(2, 0, 1), .pll = PLL_28, @@ -1970,7 +1953,6 @@ struct tvcard bttv_tvcards[] = { /* Tuner, CVid, SVid, CVid over SVid connector */ .muxsel = MUXSEL(2, 3, 1, 1), .gpiomask = 0, - .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_PHILIPS_PAL_I, .tuner_addr = ADDR_UNSET, @@ -2017,7 +1999,6 @@ struct tvcard bttv_tvcards[] = { .muxsel = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0), .muxsel_hook = xguard_muxsel, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, }, @@ -2029,7 +2010,6 @@ struct tvcard bttv_tvcards[] = { .svhs = NO_SVHS, .muxsel = MUXSEL(2, 3, 1, 0), .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, .tuner_type = TUNER_ABSENT, @@ -2134,7 +2114,6 @@ struct tvcard bttv_tvcards[] = { .svhs = NO_SVHS, /* card has no svhs */ .needs_tvaudio = 0, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .gpiomask = 0x00, .muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), @@ -2156,7 +2135,6 @@ struct tvcard bttv_tvcards[] = { [BTTV_BOARD_TWINHAN_DST] = { .name = "Twinhan DST + clones", .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, @@ -2171,7 +2149,6 @@ struct tvcard bttv_tvcards[] = { /* Vid In, SVid In, Vid over SVid in connector */ .muxsel = MUXSEL(3, 1, 1, 3), .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, @@ -2226,7 +2203,6 @@ struct tvcard bttv_tvcards[] = { .svhs = NO_SVHS, .muxsel = MUXSEL(2, 3, 1, 0), .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .needs_tvaudio = 0, .tuner_type = TUNER_ABSENT, @@ -2278,7 +2254,6 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0, .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/ .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, /*878A input is always MUX0, see above.*/ .muxsel = MUXSEL(2, 2, 2, 2), @@ -2302,7 +2277,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_TEMIC_PAL, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, }, [BTTV_BOARD_AVDVBT_771] = { /* Wolfram Joost */ @@ -2313,7 +2287,6 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .muxsel = MUXSEL(3, 3), .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, .has_dvb = 1, @@ -2329,7 +2302,6 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */ .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, .tuner_type = TUNER_ABSENT, @@ -2393,7 +2365,6 @@ struct tvcard bttv_tvcards[] = { /* Chris Pascoe */ .name = "DViCO FusionHDTV DVB-T Lite", .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, .no_video = 1, @@ -2440,7 +2411,6 @@ struct tvcard bttv_tvcards[] = { .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), .pll = PLL_28, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, @@ -2478,7 +2448,6 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .no_msp34xx = 1, .no_tda7432 = 1, - .no_tda9875 = 1, .muxsel_hook = kodicom4400r_muxsel, }, [BTTV_BOARD_KODICOM_4400R_SL] = { @@ -2500,7 +2469,6 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .no_msp34xx = 1, .no_tda7432 = 1, - .no_tda9875 = 1, .muxsel_hook = kodicom4400r_muxsel, }, /* ---- card 0x86---------------------------------- */ @@ -2530,7 +2498,6 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, .gpiomute = 0x00c00007, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .has_dvb = 1, }, @@ -2630,7 +2597,6 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, /* ---- card 0x8d ---------------------------------- */ @@ -2658,7 +2624,6 @@ struct tvcard bttv_tvcards[] = { .muxsel = MUXSEL(2, 3, 1, 1), .gpiomux = { 100000, 100002, 100002, 100000 }, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .pll = PLL_28, .tuner_type = TUNER_TNF_5335MF, @@ -2674,7 +2639,6 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x0f, /* old: 7 */ .muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */ .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, @@ -2732,7 +2696,6 @@ struct tvcard bttv_tvcards[] = { .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, .gpiomute = 0x00c00007, .no_msp34xx = 1, - .no_tda9875 = 1, .no_tda7432 = 1, }, /* ---- card 0x95---------------------------------- */ @@ -2874,7 +2837,6 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .no_msp34xx = 1, .no_tda7432 = 1, - .no_tda9875 = 1, .muxsel_hook = gv800s_muxsel, }, [BTTV_BOARD_GEOVISION_GV800S_SL] = { @@ -2899,7 +2861,6 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .no_msp34xx = 1, .no_tda7432 = 1, - .no_tda9875 = 1, .muxsel_hook = gv800s_muxsel, }, [BTTV_BOARD_PV183] = { diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index fd62bf15d779..c6333595c6b9 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -234,7 +234,6 @@ struct tvcard { /* i2c audio flags */ unsigned int no_msp34xx:1; - unsigned int no_tda9875:1; unsigned int no_tda7432:1; unsigned int needs_tvaudio:1; unsigned int msp34xx_alt:1; -- cgit v1.2.3 From 9af39713feb53da96ba23fa94a73ffd0de50a815 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Dec 2010 09:20:59 -0300 Subject: [media] saa7146: Convert from .ioctl to .unlocked_ioctl Convert saa7146 to use core-assisted locking. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 2 +- drivers/media/common/saa7146_fops.c | 8 ++------ drivers/media/common/saa7146_vbi.c | 2 +- drivers/media/common/saa7146_video.c | 20 +------------------- include/media/saa7146.h | 2 +- 5 files changed, 6 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 982f000a57ff..9f47e383c57a 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -452,7 +452,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device)); dev->ext = ext; - mutex_init(&dev->lock); + mutex_init(&dev->v4l2_lock); spin_lock_init(&dev->int_slock); spin_lock_init(&dev->slock); diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index e3fedc60fe77..1bd3dd762c6b 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -15,18 +15,15 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) } /* is it free? */ - mutex_lock(&dev->lock); if (vv->resources & bit) { DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); /* no, someone else uses it */ - mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; vv->resources |= bit; DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); - mutex_unlock(&dev->lock); return 1; } @@ -37,11 +34,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) BUG_ON((fh->resources & bits) != bits); - mutex_lock(&dev->lock); fh->resources &= ~bits; vv->resources &= ~bits; DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources)); - mutex_unlock(&dev->lock); } @@ -396,7 +391,7 @@ static const struct v4l2_file_operations video_fops = .write = fops_write, .poll = fops_poll, .mmap = fops_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static void vv_callback(struct saa7146_dev *dev, unsigned long status) @@ -505,6 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, vfd->fops = &video_fops; vfd->ioctl_ops = &dev->ext_vv_data->ops; vfd->release = video_device_release; + vfd->lock = &dev->v4l2_lock; vfd->tvnorms = 0; for (i = 0; i < dev->ext_vv_data->num_stds; i++) vfd->tvnorms |= dev->ext_vv_data->stds[i].id; diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 2d4533ab22b7..afe85801d6ca 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, // FIXME: does this really work? sizeof(struct saa7146_buf), - file, NULL); + file, &dev->v4l2_lock); init_timer(&fh->vbi_read_timeout); fh->vbi_read_timeout.function = vbi_read_timeout; diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 0ac5c619aecf..9aafa4e969a8 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -553,8 +553,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f } } - mutex_lock(&dev->lock); - /* ok, accept it */ vv->ov_fb = *fb; vv->ov_fmt = fmt; @@ -563,8 +561,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline)); } - - mutex_unlock(&dev->lock); return 0; } @@ -649,8 +645,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) return -EINVAL; } - mutex_lock(&dev->lock); - switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_MENU: @@ -693,7 +687,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) /* fixme: we can support changing VFLIP and HFLIP here... */ if (IS_CAPTURE_ACTIVE(fh) != 0) { DEB_D(("V4L2_CID_HFLIP while active capture.\n")); - mutex_unlock(&dev->lock); return -EBUSY; } vv->hflip = c->value; @@ -701,16 +694,13 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) case V4L2_CID_VFLIP: if (IS_CAPTURE_ACTIVE(fh) != 0) { DEB_D(("V4L2_CID_VFLIP while active capture.\n")); - mutex_unlock(&dev->lock); return -EBUSY; } vv->vflip = c->value; break; default: - mutex_unlock(&dev->lock); return -EINVAL; } - mutex_unlock(&dev->lock); if (IS_OVERLAY_ACTIVE(fh) != 0) { saa7146_stop_preview(fh); @@ -902,22 +892,18 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f err = vidioc_try_fmt_vid_overlay(file, fh, f); if (0 != err) return err; - mutex_lock(&dev->lock); fh->ov.win = f->fmt.win; fh->ov.nclips = f->fmt.win.clipcount; if (fh->ov.nclips > 16) fh->ov.nclips = 16; if (copy_from_user(fh->ov.clips, f->fmt.win.clips, sizeof(struct v4l2_clip) * fh->ov.nclips)) { - mutex_unlock(&dev->lock); return -EFAULT; } /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ fh->ov.fh = fh; - mutex_unlock(&dev->lock); - /* check if our current overlay is active */ if (IS_OVERLAY_ACTIVE(fh) != 0) { saa7146_stop_preview(fh); @@ -976,8 +962,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) } } - mutex_lock(&dev->lock); - for (i = 0; i < dev->ext_vv_data->num_stds; i++) if (*id & dev->ext_vv_data->stds[i].id) break; @@ -988,8 +972,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) found = 1; } - mutex_unlock(&dev->lock); - if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; @@ -1354,7 +1336,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7146_buf), - file, NULL); + file, &dev->v4l2_lock); return 0; } diff --git a/include/media/saa7146.h b/include/media/saa7146.h index ac7ce00f39cf..79827143d5ac 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -115,7 +115,7 @@ struct saa7146_dev /* different device locks */ spinlock_t slock; - struct mutex lock; + struct mutex v4l2_lock; unsigned char __iomem *mem; /* pointer to mapped IO memory */ u32 revision; /* chip revision; needed for bug-workarounds*/ -- cgit v1.2.3 From d2db8fee0d77f43f64e4e97ccc1558a9f59fab41 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Dec 2010 09:50:43 -0300 Subject: [media] cpia2: convert .ioctl to .unlocked_ioctl Implement core-assisted locking in cpia2. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cpia2/cpia2.h | 2 +- drivers/media/video/cpia2/cpia2_core.c | 65 +++++---------------- drivers/media/video/cpia2/cpia2_v4l.c | 104 +++++++++++---------------------- 3 files changed, 50 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h index 916c13d5cf7d..6d6d1843791c 100644 --- a/drivers/media/video/cpia2/cpia2.h +++ b/drivers/media/video/cpia2/cpia2.h @@ -378,7 +378,7 @@ struct cpia2_fh { struct camera_data { /* locks */ - struct mutex busy_lock; /* guard against SMP multithreading */ + struct mutex v4l2_lock; /* serialize file operations */ struct v4l2_prio_state prio; /* camera status */ diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c index 9606bc01b803..aaffca8e13fd 100644 --- a/drivers/media/video/cpia2/cpia2_core.c +++ b/drivers/media/video/cpia2/cpia2_core.c @@ -2247,7 +2247,7 @@ struct camera_data *cpia2_init_camera_struct(void) cam->present = 1; - mutex_init(&cam->busy_lock); + mutex_init(&cam->v4l2_lock); init_waitqueue_head(&cam->wq_stream); return cam; @@ -2365,9 +2365,9 @@ long cpia2_read(struct camera_data *cam, char __user *buf, unsigned long count, int noblock) { struct framebuf *frame; - if (!count) { + + if (!count) return 0; - } if (!buf) { ERR("%s: buffer NULL\n",__func__); @@ -2379,17 +2379,12 @@ long cpia2_read(struct camera_data *cam, return -EINVAL; } - /* make this _really_ smp and multithread-safe */ - if (mutex_lock_interruptible(&cam->busy_lock)) - return -ERESTARTSYS; - if (!cam->present) { LOG("%s: camera removed\n",__func__); - mutex_unlock(&cam->busy_lock); return 0; /* EOF */ } - if(!cam->streaming) { + if (!cam->streaming) { /* Start streaming */ cpia2_usb_stream_start(cam, cam->params.camera_state.stream_mode); @@ -2398,42 +2393,31 @@ long cpia2_read(struct camera_data *cam, /* Copy cam->curbuff in case it changes while we're processing */ frame = cam->curbuff; if (noblock && frame->status != FRAME_READY) { - mutex_unlock(&cam->busy_lock); return -EAGAIN; } - if(frame->status != FRAME_READY) { - mutex_unlock(&cam->busy_lock); + if (frame->status != FRAME_READY) { + mutex_unlock(&cam->v4l2_lock); wait_event_interruptible(cam->wq_stream, !cam->present || (frame = cam->curbuff)->status == FRAME_READY); + mutex_lock(&cam->v4l2_lock); if (signal_pending(current)) return -ERESTARTSYS; - /* make this _really_ smp and multithread-safe */ - if (mutex_lock_interruptible(&cam->busy_lock)) { - return -ERESTARTSYS; - } - if(!cam->present) { - mutex_unlock(&cam->busy_lock); + if (!cam->present) return 0; - } } /* copy data to user space */ - if (frame->length > count) { - mutex_unlock(&cam->busy_lock); + if (frame->length > count) return -EFAULT; - } - if (copy_to_user(buf, frame->data, frame->length)) { - mutex_unlock(&cam->busy_lock); + if (copy_to_user(buf, frame->data, frame->length)) return -EFAULT; - } count = frame->length; frame->status = FRAME_EMPTY; - mutex_unlock(&cam->busy_lock); return count; } @@ -2447,17 +2431,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp, { unsigned int status=0; - if(!cam) { + if (!cam) { ERR("%s: Internal error, camera_data not found!\n",__func__); return POLLERR; } - mutex_lock(&cam->busy_lock); - - if(!cam->present) { - mutex_unlock(&cam->busy_lock); + if (!cam->present) return POLLHUP; - } if(!cam->streaming) { /* Start streaming */ @@ -2465,16 +2445,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp, cam->params.camera_state.stream_mode); } - mutex_unlock(&cam->busy_lock); poll_wait(filp, &cam->wq_stream, wait); - mutex_lock(&cam->busy_lock); if(!cam->present) status = POLLHUP; else if(cam->curbuff->status == FRAME_READY) status = POLLIN | POLLRDNORM; - mutex_unlock(&cam->busy_lock); return status; } @@ -2496,29 +2473,19 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma) DBG("mmap offset:%ld size:%ld\n", start_offset, size); - /* make this _really_ smp-safe */ - if (mutex_lock_interruptible(&cam->busy_lock)) - return -ERESTARTSYS; - - if (!cam->present) { - mutex_unlock(&cam->busy_lock); + if (!cam->present) return -ENODEV; - } if (size > cam->frame_size*cam->num_frames || (start_offset % cam->frame_size) != 0 || - (start_offset+size > cam->frame_size*cam->num_frames)) { - mutex_unlock(&cam->busy_lock); + (start_offset+size > cam->frame_size*cam->num_frames)) return -EINVAL; - } pos = ((unsigned long) (cam->frame_buffer)) + start_offset; while (size > 0) { page = kvirt_to_pa(pos); - if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&cam->busy_lock); + if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; - } start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) @@ -2528,7 +2495,5 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma) } cam->mmapped = true; - mutex_unlock(&cam->busy_lock); return 0; } - diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 7edf80b0d01a..9bad39842936 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -238,59 +238,40 @@ static struct v4l2_queryctrl controls[] = { static int cpia2_open(struct file *file) { struct camera_data *cam = video_drvdata(file); - int retval = 0; + struct cpia2_fh *fh; if (!cam) { ERR("Internal error, camera_data not found!\n"); return -ENODEV; } - if(mutex_lock_interruptible(&cam->busy_lock)) - return -ERESTARTSYS; - - if(!cam->present) { - retval = -ENODEV; - goto err_return; - } + if (!cam->present) + return -ENODEV; - if (cam->open_count > 0) { - goto skip_init; - } + if (cam->open_count == 0) { + if (cpia2_allocate_buffers(cam)) + return -ENOMEM; - if (cpia2_allocate_buffers(cam)) { - retval = -ENOMEM; - goto err_return; - } + /* reset the camera */ + if (cpia2_reset_camera(cam) < 0) + return -EIO; - /* reset the camera */ - if (cpia2_reset_camera(cam) < 0) { - retval = -EIO; - goto err_return; + cam->APP_len = 0; + cam->COM_len = 0; } - cam->APP_len = 0; - cam->COM_len = 0; - -skip_init: - { - struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL); - if(!fh) { - retval = -ENOMEM; - goto err_return; - } - file->private_data = fh; - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&cam->prio, &fh->prio); - fh->mmapped = 0; - } + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + file->private_data = fh; + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&cam->prio, &fh->prio); + fh->mmapped = 0; ++cam->open_count; cpia2_dbg_dump_registers(cam); - -err_return: - mutex_unlock(&cam->busy_lock); - return retval; + return 0; } /****************************************************************************** @@ -304,15 +285,11 @@ static int cpia2_close(struct file *file) struct camera_data *cam = video_get_drvdata(dev); struct cpia2_fh *fh = file->private_data; - mutex_lock(&cam->busy_lock); - if (cam->present && - (cam->open_count == 1 - || fh->prio == V4L2_PRIORITY_RECORD - )) { + (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) { cpia2_usb_stream_stop(cam); - if(cam->open_count == 1) { + if (cam->open_count == 1) { /* save camera state for later open */ cpia2_save_camera_state(cam); @@ -321,26 +298,21 @@ static int cpia2_close(struct file *file) } } - { - if(fh->mmapped) - cam->mmapped = 0; - v4l2_prio_close(&cam->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - } + if (fh->mmapped) + cam->mmapped = 0; + v4l2_prio_close(&cam->prio, fh->prio); + file->private_data = NULL; + kfree(fh); if (--cam->open_count == 0) { cpia2_free_buffers(cam); if (!cam->present) { video_unregister_device(dev); - mutex_unlock(&cam->busy_lock); kfree(cam); return 0; } } - mutex_unlock(&cam->busy_lock); - return 0; } @@ -405,11 +377,11 @@ static int sync(struct camera_data *cam, int frame_nr) return 0; } - mutex_unlock(&cam->busy_lock); + mutex_unlock(&cam->v4l2_lock); wait_event_interruptible(cam->wq_stream, !cam->streaming || frame->status == FRAME_READY); - mutex_lock(&cam->busy_lock); + mutex_lock(&cam->v4l2_lock); if (signal_pending(current)) return -ERESTARTSYS; if(!cam->present) @@ -1293,11 +1265,11 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) if(frame < 0) { /* Wait for a frame to become available */ struct framebuf *cb=cam->curbuff; - mutex_unlock(&cam->busy_lock); + mutex_unlock(&cam->v4l2_lock); wait_event_interruptible(cam->wq_stream, !cam->present || (cb=cam->curbuff)->status == FRAME_READY); - mutex_lock(&cam->busy_lock); + mutex_lock(&cam->v4l2_lock); if (signal_pending(current)) return -ERESTARTSYS; if(!cam->present) @@ -1337,14 +1309,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (!cam) return -ENOTTY; - /* make this _really_ smp-safe */ - if (mutex_lock_interruptible(&cam->busy_lock)) - return -ERESTARTSYS; - - if (!cam->present) { - mutex_unlock(&cam->busy_lock); + if (!cam->present) return -ENODEV; - } /* Priority check */ switch (cmd) { @@ -1352,10 +1318,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct cpia2_fh *fh = file->private_data; retval = v4l2_prio_check(&cam->prio, fh->prio); - if(retval) { - mutex_unlock(&cam->busy_lock); + if (retval) return retval; - } break; } default: @@ -1529,7 +1493,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) break; } - mutex_unlock(&cam->busy_lock); return retval; } @@ -1596,7 +1559,7 @@ static const struct v4l2_file_operations cpia2_fops = { .release = cpia2_close, .read = cpia2_v4l_read, .poll = cpia2_v4l_poll, - .ioctl = cpia2_ioctl, + .unlocked_ioctl = cpia2_ioctl, .mmap = cpia2_mmap, }; @@ -1620,6 +1583,7 @@ int cpia2_register_camera(struct camera_data *cam) memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); video_set_drvdata(cam->vdev, cam); + cam->vdev->lock = &cam->v4l2_lock; reset_camera_struct_v4l(cam); -- cgit v1.2.3 From 7036d6a73c88428764e4a12f30846279346f4382 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 16 Dec 2010 12:17:41 -0300 Subject: [media] vpif_cap/disp: Add debug functionality The following functions are added to the drivers: - vpif_g_chip_ident - vpif_dbg_g_register - vpif_dbg_s_register - vpif_log_status Signed-off-by: Mats Randgaard Signed-off-by: Hans Verkuil Acked-by: Vaibhav Hiremath Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif_capture.c | 83 ++++++++++++++++++++++++++++ drivers/media/video/davinci/vpif_display.c | 86 ++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 193abab6b355..9446dbc476fd 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "vpif_capture.h" #include "vpif.h" @@ -1807,6 +1808,82 @@ static int vpif_cropcap(struct file *file, void *priv, return 0; } +/* + * vpif_g_chip_ident() - Identify the chip + * @file: file ptr + * @priv: file handle + * @chip: chip identity + * + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { + vpif_dbg(2, debug, "match_type is invalid.\n"); + return -EINVAL; + } + + return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, + g_chip_ident, chip); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * vpif_dbg_g_register() - Read register + * @file: file ptr + * @priv: file handle + * @reg: register to be read + * + * Debugging only + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_dbg_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, + g_register, reg); +} + +/* + * vpif_dbg_s_register() - Write to register + * @file: file ptr + * @priv: file handle + * @reg: register to be modified + * + * Debugging only + * Returns zero or -EINVAL if write operations fails. + */ +static int vpif_dbg_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, + s_register, reg); +} +#endif + +/* + * vpif_log_status() - Status information + * @file: file ptr + * @priv: file handle + * + * Returns zero. + */ +static int vpif_log_status(struct file *filep, void *priv) +{ + /* status for sub devices */ + v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); + + return 0; +} + /* vpif capture ioctl operations */ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_querycap = vpif_querycap, @@ -1829,6 +1906,12 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_streamon = vpif_streamon, .vidioc_streamoff = vpif_streamoff, .vidioc_cropcap = vpif_cropcap, + .vidioc_g_chip_ident = vpif_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpif_dbg_g_register, + .vidioc_s_register = vpif_dbg_s_register, +#endif + .vidioc_log_status = vpif_log_status, }; /* vpif file operations */ diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 412c65d54fe1..2d55e3e86a84 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -1315,6 +1316,85 @@ static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) return v4l2_prio_change(&ch->prio, &fh->prio, p); } + +/* + * vpif_g_chip_ident() - Identify the chip + * @file: file ptr + * @priv: file handle + * @chip: chip identity + * + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { + vpif_dbg(2, debug, "match_type is invalid.\n"); + return -EINVAL; + } + + return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, + g_chip_ident, chip); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * vpif_dbg_g_register() - Read register + * @file: file ptr + * @priv: file handle + * @reg: register to be read + * + * Debugging only + * Returns zero or -EINVAL if read operations fails. + */ +static int vpif_dbg_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, + g_register, reg); +} + +/* + * vpif_dbg_s_register() - Write to register + * @file: file ptr + * @priv: file handle + * @reg: register to be modified + * + * Debugging only + * Returns zero or -EINVAL if write operations fails. + */ +static int vpif_dbg_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg){ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, + s_register, reg); +} +#endif + +/* + * vpif_log_status() - Status information + * @file: file ptr + * @priv: file handle + * + * Returns zero. + */ +static int vpif_log_status(struct file *filep, void *priv) +{ + /* status for sub devices */ + v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); + + return 0; +} + /* vpif display ioctl operations */ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_querycap = vpif_querycap, @@ -1336,6 +1416,12 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_s_output = vpif_s_output, .vidioc_g_output = vpif_g_output, .vidioc_cropcap = vpif_cropcap, + .vidioc_g_chip_ident = vpif_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vpif_dbg_g_register, + .vidioc_s_register = vpif_dbg_s_register, +#endif + .vidioc_log_status = vpif_log_status, }; static const struct v4l2_file_operations vpif_fops = { -- cgit v1.2.3 From aa4444063505983c5971bc8fb832385dfba16b41 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 16 Dec 2010 12:17:42 -0300 Subject: [media] vpif: Consolidate formats from capture and display - The ch_params tables in vpif_capture.c and vpif_display.c are moved to a common table in vpif.c. Then it is easier to maintain the table. - The field "fps" is removed from the struct vpif_channel_config_params because it is not used. Signed-off-by: Mats Randgaard Signed-off-by: Hans Verkuil Acked-by : Murali Karicheri Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif.c | 50 ++++++++++++++++++++++++++++++ drivers/media/video/davinci/vpif.h | 4 ++- drivers/media/video/davinci/vpif_capture.c | 18 ++--------- drivers/media/video/davinci/vpif_display.c | 17 ++-------- 4 files changed, 58 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index 1f532e31cd49..54cc0dadd755 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -41,6 +41,56 @@ spinlock_t vpif_lock; void __iomem *vpif_base; +/** + * ch_params: video standard configuration parameters for vpif + * The table must include all presets from supported subdevices. + */ +const struct vpif_channel_config_params ch_params[] = { + /* SDTV formats */ + { + .name = "NTSC_M", + .width = 720, + .height = 480, + .frm_fmt = 0, + .ycmux_mode = 1, + .eav2sav = 268, + .sav2eav = 1440, + .l1 = 1, + .l3 = 23, + .l5 = 263, + .l7 = 266, + .l9 = 286, + .l11 = 525, + .vsize = 525, + .capture_format = 0, + .vbi_supported = 1, + .hd_sd = 0, + .stdid = V4L2_STD_525_60, + }, + { + .name = "PAL_BDGHIK", + .width = 720, + .height = 576, + .frm_fmt = 0, + .ycmux_mode = 1, + .eav2sav = 280, + .sav2eav = 1440, + .l1 = 1, + .l3 = 23, + .l5 = 311, + .l7 = 313, + .l9 = 336, + .l11 = 624, + .vsize = 625, + .capture_format = 0, + .vbi_supported = 1, + .hd_sd = 0, + .stdid = V4L2_STD_625_50, + }, +}; + +const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params); + static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) { if (val) diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index ebd5c4338ebb..d14e36e5c90d 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -577,7 +577,6 @@ struct vpif_channel_config_params { char name[VPIF_MAX_NAME]; /* Name of the mode */ u16 width; /* Indicates width of the image */ u16 height; /* Indicates height of the image */ - u8 fps; u8 frm_fmt; /* Indicates whether this is interlaced * or progressive format */ u8 ycmux_mode; /* Indicates whether this mode requires @@ -594,6 +593,9 @@ struct vpif_channel_config_params { v4l2_std_id stdid; }; +extern const unsigned int vpif_ch_params_count; +extern const struct vpif_channel_config_params ch_params[]; + struct vpif_video_params; struct vpif_params; struct vpif_vbi_params; diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 9446dbc476fd..0a7ebb0e151a 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -81,20 +81,6 @@ static struct vpif_config_params config_params = { static struct vpif_device vpif_obj = { {NULL} }; static struct device *vpif_dev; -/** - * ch_params: video standard configuration parameters for vpif - */ -static const struct vpif_channel_config_params ch_params[] = { - { - "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, - 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, - }, - { - "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, - 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, - }, -}; - /** * vpif_uservirt_to_phys : translate user/virtual address to phy address * @virtp: user/virtual address @@ -444,7 +430,7 @@ static int vpif_update_std_info(struct channel_obj *ch) std_info = &vpifparams->std_info; - for (index = 0; index < ARRAY_SIZE(ch_params); index++) { + for (index = 0; index < vpif_ch_params_count; index++) { config = &ch_params[index]; if (config->stdid & vid_ch->stdid) { memcpy(std_info, config, sizeof(*config)); @@ -453,7 +439,7 @@ static int vpif_update_std_info(struct channel_obj *ch) } /* standard not found */ - if (index == ARRAY_SIZE(ch_params)) + if (index == vpif_ch_params_count) return -EINVAL; common->fmt.fmt.pix.width = std_info->width; diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 2d55e3e86a84..9de0062eca59 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -85,17 +85,6 @@ static struct vpif_config_params config_params = { static struct vpif_device vpif_obj = { {NULL} }; static struct device *vpif_dev; -static const struct vpif_channel_config_params ch_params[] = { - { - "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, - 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, - }, - { - "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, - 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, - }, -}; - /* * vpif_uservirt_to_phys: This function is used to convert user * space virtual address to physical address. @@ -388,7 +377,7 @@ static int vpif_get_std_info(struct channel_obj *ch) if (!std_info->stdid) return -1; - for (index = 0; index < ARRAY_SIZE(ch_params); index++) { + for (index = 0; index < vpif_ch_params_count; index++) { config = &ch_params[index]; if (config->stdid & std_info->stdid) { memcpy(std_info, config, sizeof(*config)); @@ -396,8 +385,8 @@ static int vpif_get_std_info(struct channel_obj *ch) } } - if (index == ARRAY_SIZE(ch_params)) - return -1; + if (index == vpif_ch_params_count) + return -EINVAL; common->fmt.fmt.pix.width = std_info->width; common->fmt.fmt.pix.height = std_info->height; -- cgit v1.2.3 From 40c8bcea6bc594c50abf3d3867bd49c8c039eb21 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 16 Dec 2010 12:17:43 -0300 Subject: [media] vpif_cap/disp: Add support for DV presets - Added functions to set/get/query/enum DV presets for vpif_caputre and vpif_display. - The format specification table is extended with all the DV formats supported by TVP7002. Signed-off-by: Mats Randgaard Signed-off-by: Hans Verkuil Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif.c | 127 +++++++++++++++++++++++++++++ drivers/media/video/davinci/vpif.h | 1 + drivers/media/video/davinci/vpif_capture.c | 124 +++++++++++++++++++++++++++- drivers/media/video/davinci/vpif_capture.h | 1 + drivers/media/video/davinci/vpif_display.c | 105 ++++++++++++++++++++++-- drivers/media/video/davinci/vpif_display.h | 1 + 6 files changed, 350 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index 54cc0dadd755..9f3bfc1eb240 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -46,6 +46,133 @@ void __iomem *vpif_base; * The table must include all presets from supported subdevices. */ const struct vpif_channel_config_params ch_params[] = { + /* HDTV formats */ + { + .name = "480p59_94", + .width = 720, + .height = 480, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 138-8, + .sav2eav = 720, + .l1 = 1, + .l3 = 43, + .l5 = 523, + .vsize = 525, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_480P59_94, + }, + { + .name = "576p50", + .width = 720, + .height = 576, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 144-8, + .sav2eav = 720, + .l1 = 1, + .l3 = 45, + .l5 = 621, + .vsize = 625, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_576P50, + }, + { + .name = "720p50", + .width = 1280, + .height = 720, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 700-8, + .sav2eav = 1280, + .l1 = 1, + .l3 = 26, + .l5 = 746, + .vsize = 750, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_720P50, + }, + { + .name = "720p60", + .width = 1280, + .height = 720, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 370 - 8, + .sav2eav = 1280, + .l1 = 1, + .l3 = 26, + .l5 = 746, + .vsize = 750, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_720P60, + }, + { + .name = "1080I50", + .width = 1920, + .height = 1080, + .frm_fmt = 0, + .ycmux_mode = 0, + .eav2sav = 720 - 8, + .sav2eav = 1920, + .l1 = 1, + .l3 = 21, + .l5 = 561, + .l7 = 563, + .l9 = 584, + .l11 = 1124, + .vsize = 1125, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_1080I50, + }, + { + .name = "1080I60", + .width = 1920, + .height = 1080, + .frm_fmt = 0, + .ycmux_mode = 0, + .eav2sav = 280 - 8, + .sav2eav = 1920, + .l1 = 1, + .l3 = 21, + .l5 = 561, + .l7 = 563, + .l9 = 584, + .l11 = 1124, + .vsize = 1125, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_1080I60, + }, + { + .name = "1080p60", + .width = 1920, + .height = 1080, + .frm_fmt = 1, + .ycmux_mode = 0, + .eav2sav = 280 - 8, + .sav2eav = 1920, + .l1 = 1, + .l3 = 42, + .l5 = 1122, + .vsize = 1125, + .capture_format = 0, + .vbi_supported = 0, + .hd_sd = 1, + .dv_preset = V4L2_DV_1080P60, + }, + /* SDTV formats */ { .name = "NTSC_M", diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index d14e36e5c90d..b6695bee3c59 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -591,6 +591,7 @@ struct vpif_channel_config_params { * supports capturing vbi or not */ u8 hd_sd; v4l2_std_id stdid; + u32 dv_preset; /* HDTV format */ }; extern const unsigned int vpif_ch_params_count; diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 0a7ebb0e151a..42f1cd60780b 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -432,9 +432,18 @@ static int vpif_update_std_info(struct channel_obj *ch) for (index = 0; index < vpif_ch_params_count; index++) { config = &ch_params[index]; - if (config->stdid & vid_ch->stdid) { - memcpy(std_info, config, sizeof(*config)); - break; + if (config->hd_sd == 0) { + vpif_dbg(2, debug, "SD format\n"); + if (config->stdid & vid_ch->stdid) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } else { + vpif_dbg(2, debug, "HD format\n"); + if (config->dv_preset == vid_ch->dv_preset) { + memcpy(std_info, config, sizeof(*config)); + break; + } } } @@ -1442,6 +1451,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) return -ERESTARTSYS; ch->video.stdid = *std_id; + ch->video.dv_preset = V4L2_DV_INVALID; /* Get the information about the standard */ if (vpif_update_std_info(ch)) { @@ -1794,6 +1804,110 @@ static int vpif_cropcap(struct file *file, void *priv, return 0; } +/** + * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, enum_dv_presets, preset); +} + +/** + * vpif_query_dv_presets() - QUERY_DV_PRESET handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_query_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, query_dv_preset, preset); +} +/** + * vpif_s_dv_presets() - S_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if (common->started) { + vpif_dbg(1, debug, "streaming in progress\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (ret) + return ret; + + fh->initialized = 1; + + /* Call encoder subdevice function to set the standard */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + ch->video.dv_preset = preset->preset; + ch->video.stdid = V4L2_STD_UNKNOWN; + + /* Get the information about the standard */ + if (vpif_update_std_info(ch)) { + vpif_dbg(1, debug, "Error getting the standard info\n"); + ret = -EINVAL; + } else { + /* Configure the default format information */ + vpif_config_format(ch); + + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, s_dv_preset, preset); + } + + mutex_unlock(&common->lock); + + return ret; +} +/** + * vpif_g_dv_presets() - G_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + preset->preset = ch->video.dv_preset; + + return 0; +} + /* * vpif_g_chip_ident() - Identify the chip * @file: file ptr @@ -1892,6 +2006,10 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_streamon = vpif_streamon, .vidioc_streamoff = vpif_streamoff, .vidioc_cropcap = vpif_cropcap, + .vidioc_enum_dv_presets = vpif_enum_dv_presets, + .vidioc_s_dv_preset = vpif_s_dv_preset, + .vidioc_g_dv_preset = vpif_g_dv_preset, + .vidioc_query_dv_preset = vpif_query_dv_preset, .vidioc_g_chip_ident = vpif_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpif_dbg_g_register, diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h index 4e12ec8cac6f..3452a8aec020 100644 --- a/drivers/media/video/davinci/vpif_capture.h +++ b/drivers/media/video/davinci/vpif_capture.h @@ -59,6 +59,7 @@ struct video_obj { enum v4l2_field buf_field; /* Currently selected or default standard */ v4l2_std_id stdid; + u32 dv_preset; /* This is to track the last input that is passed to application */ u32 input_idx; }; diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 9de0062eca59..759c5e855ac8 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -373,15 +373,23 @@ static int vpif_get_std_info(struct channel_obj *ch) int index; - std_info->stdid = vid_ch->stdid; - if (!std_info->stdid) - return -1; + if (!vid_ch->stdid && !vid_ch->dv_preset) + return -EINVAL; for (index = 0; index < vpif_ch_params_count; index++) { config = &ch_params[index]; - if (config->stdid & std_info->stdid) { - memcpy(std_info, config, sizeof(*config)); - break; + if (config->hd_sd == 0) { + vpif_dbg(2, debug, "SD format\n"); + if (config->stdid & vid_ch->stdid) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } else { + vpif_dbg(2, debug, "HD format\n"); + if (config->dv_preset == vid_ch->dv_preset) { + memcpy(std_info, config, sizeof(*config)); + break; + } } } @@ -1305,6 +1313,88 @@ static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) return v4l2_prio_change(&ch->prio, &fh->prio, p); } +/** + * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_enum_dv_presets(struct file *file, void *priv, + struct v4l2_dv_enum_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + video, enum_dv_presets, preset); +} + +/** + * vpif_s_dv_presets() - S_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_s_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + int ret = 0; + + if (common->started) { + vpif_dbg(1, debug, "streaming in progress\n"); + return -EBUSY; + } + + ret = v4l2_prio_check(&ch->prio, fh->prio); + if (ret != 0) + return ret; + + fh->initialized = 1; + + /* Call encoder subdevice function to set the standard */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + ch->video.dv_preset = preset->preset; + ch->video.stdid = V4L2_STD_UNKNOWN; + + /* Get the information about the standard */ + if (vpif_get_std_info(ch)) { + ret = -EINVAL; + vpif_dbg(1, debug, "Error getting the standard info\n"); + } else { + /* Configure the default format information */ + vpif_config_format(ch); + + ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + video, s_dv_preset, preset); + } + + mutex_unlock(&common->lock); + + return ret; +} +/** + * vpif_g_dv_presets() - G_DV_PRESETS handler + * @file: file ptr + * @priv: file handle + * @preset: input preset + */ +static int vpif_g_dv_preset(struct file *file, void *priv, + struct v4l2_dv_preset *preset) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + preset->preset = ch->video.dv_preset; + + return 0; +} /* * vpif_g_chip_ident() - Identify the chip @@ -1405,6 +1495,9 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_s_output = vpif_s_output, .vidioc_g_output = vpif_g_output, .vidioc_cropcap = vpif_cropcap, + .vidioc_enum_dv_presets = vpif_enum_dv_presets, + .vidioc_s_dv_preset = vpif_s_dv_preset, + .vidioc_g_dv_preset = vpif_g_dv_preset, .vidioc_g_chip_ident = vpif_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpif_dbg_g_register, diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h index a2a7cd166bbf..3d56b3e356a2 100644 --- a/drivers/media/video/davinci/vpif_display.h +++ b/drivers/media/video/davinci/vpif_display.h @@ -67,6 +67,7 @@ struct video_obj { * most recent displayed frame only */ v4l2_std_id stdid; /* Currently selected or default * standard */ + u32 dv_preset; u32 output_id; /* Current output id */ }; -- cgit v1.2.3 From c027e165d2d901ecab485da5fee72ddce5da0297 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 16 Dec 2010 12:17:44 -0300 Subject: [media] vpif_cap/disp: Added support for DV timings Added functions to set and get custom DV timings. Signed-off-by: Mats Randgaard Signed-off-by: Hans Verkuil Acked-by: Vaibhav Hiremath Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif_capture.c | 123 +++++++++++++++++++ drivers/media/video/davinci/vpif_capture.h | 1 + drivers/media/video/davinci/vpif_display.c | 190 +++++++++++++++++++++++++---- drivers/media/video/davinci/vpif_display.h | 1 + 4 files changed, 290 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 42f1cd60780b..be2b9919937c 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -1452,6 +1452,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) ch->video.stdid = *std_id; ch->video.dv_preset = V4L2_DV_INVALID; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); /* Get the information about the standard */ if (vpif_update_std_info(ch)) { @@ -1874,6 +1875,7 @@ static int vpif_s_dv_preset(struct file *file, void *priv, ch->video.dv_preset = preset->preset; ch->video.stdid = V4L2_STD_UNKNOWN; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); /* Get the information about the standard */ if (vpif_update_std_info(ch)) { @@ -1908,6 +1910,125 @@ static int vpif_g_dv_preset(struct file *file, void *priv, return 0; } +/** + * vpif_s_dv_timings() - S_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + int ret; + + if (timings->type != V4L2_DV_BT_656_1120) { + vpif_dbg(2, debug, "Timing type not defined\n"); + return -EINVAL; + } + + /* Configure subdevice timings, if any */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], + video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD) { + vpif_dbg(2, debug, "Custom DV timings not supported by " + "subdevice\n"); + return -EINVAL; + } + if (ret < 0) { + vpif_dbg(2, debug, "Error setting custom DV timings\n"); + return ret; + } + + if (!(timings->bt.width && timings->bt.height && + (timings->bt.hbackporch || + timings->bt.hfrontporch || + timings->bt.hsync) && + timings->bt.vfrontporch && + (timings->bt.vbackporch || + timings->bt.vsync))) { + vpif_dbg(2, debug, "Timings for width, height, " + "horizontal back porch, horizontal sync, " + "horizontal front porch, vertical back porch, " + "vertical sync and vertical back porch " + "must be defined\n"); + return -EINVAL; + } + + *bt = timings->bt; + + /* Configure video port timings */ + + std_info->eav2sav = bt->hbackporch + bt->hfrontporch + + bt->hsync - 8; + std_info->sav2eav = bt->width; + + std_info->l1 = 1; + std_info->l3 = bt->vsync + bt->vbackporch + 1; + + if (bt->interlaced) { + if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { + std_info->vsize = bt->height * 2 + + bt->vfrontporch + bt->vsync + bt->vbackporch + + bt->il_vfrontporch + bt->il_vsync + + bt->il_vbackporch; + std_info->l5 = std_info->vsize/2 - + (bt->vfrontporch - 1); + std_info->l7 = std_info->vsize/2 + 1; + std_info->l9 = std_info->l7 + bt->il_vsync + + bt->il_vbackporch + 1; + std_info->l11 = std_info->vsize - + (bt->il_vfrontporch - 1); + } else { + vpif_dbg(2, debug, "Required timing values for " + "interlaced BT format missing\n"); + return -EINVAL; + } + } else { + std_info->vsize = bt->height + bt->vfrontporch + + bt->vsync + bt->vbackporch; + std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); + } + strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); + std_info->width = bt->width; + std_info->height = bt->height; + std_info->frm_fmt = bt->interlaced ? 0 : 1; + std_info->ycmux_mode = 0; + std_info->capture_format = 0; + std_info->vbi_supported = 0; + std_info->hd_sd = 1; + std_info->stdid = 0; + std_info->dv_preset = V4L2_DV_INVALID; + + vid_ch->stdid = 0; + vid_ch->dv_preset = V4L2_DV_INVALID; + return 0; +} + +/** + * vpif_g_dv_timings() - G_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + + timings->bt = *bt; + + return 0; +} + /* * vpif_g_chip_ident() - Identify the chip * @file: file ptr @@ -2010,6 +2131,8 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_s_dv_preset = vpif_s_dv_preset, .vidioc_g_dv_preset = vpif_g_dv_preset, .vidioc_query_dv_preset = vpif_query_dv_preset, + .vidioc_s_dv_timings = vpif_s_dv_timings, + .vidioc_g_dv_timings = vpif_g_dv_timings, .vidioc_g_chip_ident = vpif_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpif_dbg_g_register, diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h index 3452a8aec020..7a4196dfdce1 100644 --- a/drivers/media/video/davinci/vpif_capture.h +++ b/drivers/media/video/davinci/vpif_capture.h @@ -60,6 +60,7 @@ struct video_obj { /* Currently selected or default standard */ v4l2_std_id stdid; u32 dv_preset; + struct v4l2_bt_timings bt_timings; /* This is to track the last input that is passed to application */ u32 input_idx; }; diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 759c5e855ac8..44a885878ebf 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -363,21 +363,17 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int vpif_get_std_info(struct channel_obj *ch) +static int vpif_update_std_info(struct channel_obj *ch) { - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct video_obj *vid_ch = &ch->video; struct vpif_params *vpifparams = &ch->vpifparams; struct vpif_channel_config_params *std_info = &vpifparams->std_info; const struct vpif_channel_config_params *config; - int index; - - if (!vid_ch->stdid && !vid_ch->dv_preset) - return -EINVAL; + int i; - for (index = 0; index < vpif_ch_params_count; index++) { - config = &ch_params[index]; + for (i = 0; i < vpif_ch_params_count; i++) { + config = &ch_params[i]; if (config->hd_sd == 0) { vpif_dbg(2, debug, "SD format\n"); if (config->stdid & vid_ch->stdid) { @@ -393,17 +389,37 @@ static int vpif_get_std_info(struct channel_obj *ch) } } - if (index == vpif_ch_params_count) + if (i == vpif_ch_params_count) { + vpif_dbg(1, debug, "Format not found\n"); + return -EINVAL; + } + + return 0; +} + +static int vpif_update_resolution(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + + if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height) return -EINVAL; + if (vid_ch->stdid || vid_ch->dv_preset) { + if (vpif_update_std_info(ch)) + return -EINVAL; + } + common->fmt.fmt.pix.width = std_info->width; common->fmt.fmt.pix.height = std_info->height; vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); /* Set height and width paramateres */ - ch->common[VPIF_VIDEO_INDEX].height = std_info->height; - ch->common[VPIF_VIDEO_INDEX].width = std_info->width; + common->height = std_info->height; + common->width = std_info->width; return 0; } @@ -514,10 +530,8 @@ static int vpif_check_format(struct channel_obj *ch, else sizeimage = config_params.channel_bufsize[ch->channel_id]; - if (vpif_get_std_info(ch)) { - vpif_err("Error getting the standard info\n"); + if (vpif_update_resolution(ch)) return -EINVAL; - } hpitch = pixfmt->bytesperline; vpitch = sizeimage / (hpitch * 2); @@ -715,6 +729,7 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; /* Check the validity of the buffer type */ if (common->fmt.type != fmt->type) @@ -724,14 +739,14 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv, if (mutex_lock_interruptible(&common->lock)) return -ERESTARTSYS; - if (vpif_get_std_info(ch)) { - vpif_err("Error getting the standard info\n"); - return -EINVAL; - } + if (vpif_update_resolution(ch)) + ret = -EINVAL; + else + *fmt = common->fmt; - *fmt = common->fmt; mutex_unlock(&common->lock); - return 0; + + return ret; } static int vpif_s_fmt_vid_out(struct file *file, void *priv, @@ -992,10 +1007,13 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) return -ERESTARTSYS; ch->video.stdid = *std_id; + ch->video.dv_preset = V4L2_DV_INVALID; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); + /* Get the information about the standard */ - if (vpif_get_std_info(ch)) { - vpif_err("Error getting the standard info\n"); - return -EINVAL; + if (vpif_update_resolution(ch)) { + ret = -EINVAL; + goto s_std_exit; } if ((ch->vpifparams.std_info.width * @@ -1362,11 +1380,11 @@ static int vpif_s_dv_preset(struct file *file, void *priv, ch->video.dv_preset = preset->preset; ch->video.stdid = V4L2_STD_UNKNOWN; + memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); /* Get the information about the standard */ - if (vpif_get_std_info(ch)) { + if (vpif_update_resolution(ch)) { ret = -EINVAL; - vpif_dbg(1, debug, "Error getting the standard info\n"); } else { /* Configure the default format information */ vpif_config_format(ch); @@ -1395,6 +1413,126 @@ static int vpif_g_dv_preset(struct file *file, void *priv, return 0; } +/** + * vpif_s_dv_timings() - S_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + int ret; + + if (timings->type != V4L2_DV_BT_656_1120) { + vpif_dbg(2, debug, "Timing type not defined\n"); + return -EINVAL; + } + + /* Configure subdevice timings, if any */ + ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD) { + vpif_dbg(2, debug, "Custom DV timings not supported by " + "subdevice\n"); + return -EINVAL; + } + if (ret < 0) { + vpif_dbg(2, debug, "Error setting custom DV timings\n"); + return ret; + } + + if (!(timings->bt.width && timings->bt.height && + (timings->bt.hbackporch || + timings->bt.hfrontporch || + timings->bt.hsync) && + timings->bt.vfrontporch && + (timings->bt.vbackporch || + timings->bt.vsync))) { + vpif_dbg(2, debug, "Timings for width, height, " + "horizontal back porch, horizontal sync, " + "horizontal front porch, vertical back porch, " + "vertical sync and vertical back porch " + "must be defined\n"); + return -EINVAL; + } + + *bt = timings->bt; + + /* Configure video port timings */ + + std_info->eav2sav = bt->hbackporch + bt->hfrontporch + + bt->hsync - 8; + std_info->sav2eav = bt->width; + + std_info->l1 = 1; + std_info->l3 = bt->vsync + bt->vbackporch + 1; + + if (bt->interlaced) { + if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { + std_info->vsize = bt->height * 2 + + bt->vfrontporch + bt->vsync + bt->vbackporch + + bt->il_vfrontporch + bt->il_vsync + + bt->il_vbackporch; + std_info->l5 = std_info->vsize/2 - + (bt->vfrontporch - 1); + std_info->l7 = std_info->vsize/2 + 1; + std_info->l9 = std_info->l7 + bt->il_vsync + + bt->il_vbackporch + 1; + std_info->l11 = std_info->vsize - + (bt->il_vfrontporch - 1); + } else { + vpif_dbg(2, debug, "Required timing values for " + "interlaced BT format missing\n"); + return -EINVAL; + } + } else { + std_info->vsize = bt->height + bt->vfrontporch + + bt->vsync + bt->vbackporch; + std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); + } + strncpy(std_info->name, "Custom timings BT656/1120", + VPIF_MAX_NAME); + std_info->width = bt->width; + std_info->height = bt->height; + std_info->frm_fmt = bt->interlaced ? 0 : 1; + std_info->ycmux_mode = 0; + std_info->capture_format = 0; + std_info->vbi_supported = 0; + std_info->hd_sd = 1; + std_info->stdid = 0; + std_info->dv_preset = V4L2_DV_INVALID; + + vid_ch->stdid = 0; + vid_ch->dv_preset = V4L2_DV_INVALID; + + return 0; +} + +/** + * vpif_g_dv_timings() - G_DV_TIMINGS handler + * @file: file ptr + * @priv: file handle + * @timings: digital video timings + */ +static int vpif_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + struct v4l2_bt_timings *bt = &vid_ch->bt_timings; + + timings->bt = *bt; + + return 0; +} /* * vpif_g_chip_ident() - Identify the chip @@ -1498,6 +1636,8 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { .vidioc_enum_dv_presets = vpif_enum_dv_presets, .vidioc_s_dv_preset = vpif_s_dv_preset, .vidioc_g_dv_preset = vpif_g_dv_preset, + .vidioc_s_dv_timings = vpif_s_dv_timings, + .vidioc_g_dv_timings = vpif_g_dv_timings, .vidioc_g_chip_ident = vpif_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpif_dbg_g_register, diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h index 3d56b3e356a2..b53aaa883075 100644 --- a/drivers/media/video/davinci/vpif_display.h +++ b/drivers/media/video/davinci/vpif_display.h @@ -68,6 +68,7 @@ struct video_obj { v4l2_std_id stdid; /* Currently selected or default * standard */ u32 dv_preset; + struct v4l2_bt_timings bt_timings; u32 output_id; /* Current output id */ }; -- cgit v1.2.3 From 2c0ddd17741383009c53cf557d6526848c8bb917 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 16 Dec 2010 12:17:45 -0300 Subject: [media] vpif_cap/disp: Cleanup, improved comments Signed-off-by: Mats Randgaard Signed-off-by: Hans Verkuil Acked-by: Murali Karicheri Acked-by: Vaibhav Hiremath Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif.h | 13 ++++++------- drivers/media/video/davinci/vpif_capture.c | 13 ++++++------- drivers/media/video/davinci/vpif_display.c | 16 +++++++++++++--- 3 files changed, 25 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index b6695bee3c59..10550bd93b06 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -577,11 +577,10 @@ struct vpif_channel_config_params { char name[VPIF_MAX_NAME]; /* Name of the mode */ u16 width; /* Indicates width of the image */ u16 height; /* Indicates height of the image */ - u8 frm_fmt; /* Indicates whether this is interlaced - * or progressive format */ - u8 ycmux_mode; /* Indicates whether this mode requires - * single or two channels */ - u16 eav2sav; /* length of sav 2 eav */ + u8 frm_fmt; /* Interlaced (0) or progressive (1) */ + u8 ycmux_mode; /* This mode requires one (0) or two (1) + channels */ + u16 eav2sav; /* length of eav 2 sav */ u16 sav2eav; /* length of sav 2 eav */ u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ u16 vsize; /* Vertical size of the image */ @@ -589,8 +588,8 @@ struct vpif_channel_config_params { * is in BT or in CCD/CMOS */ u8 vbi_supported; /* Indicates whether this mode * supports capturing vbi or not */ - u8 hd_sd; - v4l2_std_id stdid; + u8 hd_sd; /* HDTV (1) or SDTV (0) format */ + v4l2_std_id stdid; /* SDTV format */ u32 dv_preset; /* HDTV format */ }; diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index be2b9919937c..f8e65909dc37 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -329,7 +329,7 @@ static void vpif_schedule_next_buffer(struct common_obj *common) * @dev_id: dev_id ptr * * It changes status of the captured buffer, takes next buffer from the queue - * and sets its address in VPIF registers + * and sets its address in VPIF registers */ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) { @@ -422,14 +422,12 @@ static int vpif_update_std_info(struct channel_obj *ch) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct vpif_params *vpifparams = &ch->vpifparams; const struct vpif_channel_config_params *config; - struct vpif_channel_config_params *std_info; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; struct video_obj *vid_ch = &ch->video; int index; vpif_dbg(2, debug, "vpif_update_std_info\n"); - std_info = &vpifparams->std_info; - for (index = 0; index < vpif_ch_params_count; index++) { config = &ch_params[index]; if (config->hd_sd == 0) { @@ -458,6 +456,7 @@ static int vpif_update_std_info(struct channel_obj *ch) common->fmt.fmt.pix.bytesperline = std_info->width; vpifparams->video_params.hpitch = std_info->width; vpifparams->video_params.storage_mode = std_info->frm_fmt; + return 0; } @@ -1692,7 +1691,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_pix_format *pixfmt; int ret = 0; - vpif_dbg(2, debug, "VIDIOC_S_FMT\n"); + vpif_dbg(2, debug, "%s\n", __func__); /* If streaming is started, return error */ if (common->started) { @@ -2336,9 +2335,9 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd[i]) vpif_obj.sd[i]->grp_id = 1 << i; } - v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver" - " initialized\n"); + v4l2_info(&vpif_obj.v4l2_dev, + "DM646x VPIF capture driver initialized\n"); return 0; probe_subdev_out: diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 44a885878ebf..7cb70d916f4b 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -580,7 +580,10 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode) static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) { struct vpif_fh *fh = filep->private_data; - struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX]; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); + + vpif_dbg(2, debug, "vpif_mmap\n"); return videobuf_mmap_mapper(&common->buffer_queue, vma); } @@ -692,7 +695,12 @@ static int vpif_release(struct file *filep) } /* functions implementing ioctls */ - +/** + * vpif_querycap() - QUERYCAP handler + * @file: file ptr + * @priv: file handle + * @cap: ptr to v4l2_capability structure + */ static int vpif_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1106,7 +1114,7 @@ static int vpif_streamon(struct file *file, void *priv, if (ret < 0) return ret; - /* Call videobuf_streamon to start streaming in videobuf */ + /* Call videobuf_streamon to start streaming in videobuf */ ret = videobuf_streamon(&common->buffer_queue); if (ret < 0) { vpif_err("videobuf_streamon\n"); @@ -1873,6 +1881,8 @@ static __init int vpif_probe(struct platform_device *pdev) vpif_obj.sd[i]->grp_id = 1 << i; } + v4l2_info(&vpif_obj.v4l2_dev, + "DM646x VPIF display driver initialized\n"); return 0; probe_subdev_out: -- cgit v1.2.3 From 46656afa8a9a410b7939b248712e4e48921929da Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Jan 2011 06:51:35 -0300 Subject: [media] davinci: convert vpif_capture to core-assisted locking Now uses .unlocked_ioctl instead of .ioctl. Signed-off-by: Hans Verkuil Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif_capture.c | 90 +++++------------------------- 1 file changed, 14 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index f8e65909dc37..d93ad74a34c5 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -752,7 +752,7 @@ static int vpif_open(struct file *filep) struct video_obj *vid_ch; struct channel_obj *ch; struct vpif_fh *fh; - int i, ret = 0; + int i; vpif_dbg(2, debug, "vpif_open\n"); @@ -761,9 +761,6 @@ static int vpif_open(struct file *filep) vid_ch = &ch->video; common = &ch->common[VPIF_VIDEO_INDEX]; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - if (NULL == ch->curr_subdev_info) { /** * search through the sub device to see a registered @@ -780,8 +777,7 @@ static int vpif_open(struct file *filep) } if (i == config->subdev_count) { vpif_err("No sub device registered\n"); - ret = -ENOENT; - goto exit; + return -ENOENT; } } @@ -789,8 +785,7 @@ static int vpif_open(struct file *filep) fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); if (NULL == fh) { vpif_err("unable to allocate memory for file handle object\n"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } /* store pointer to fh in private_data member of filep */ @@ -810,9 +805,7 @@ static int vpif_open(struct file *filep) /* Initialize priority of this instance to default priority */ fh->prio = V4L2_PRIORITY_UNSET; v4l2_prio_open(&ch->prio, &fh->prio); -exit: - mutex_unlock(&common->lock); - return ret; + return 0; } /** @@ -832,9 +825,6 @@ static int vpif_release(struct file *filep) common = &ch->common[VPIF_VIDEO_INDEX]; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - /* if this instance is doing IO */ if (fh->io_allowed[VPIF_VIDEO_INDEX]) { /* Reset io_usrs member of channel object */ @@ -858,9 +848,6 @@ static int vpif_release(struct file *filep) /* Decrement channel usrs counter */ ch->usrs--; - /* unlock mutex on channel object */ - mutex_unlock(&common->lock); - /* Close the priority */ v4l2_prio_close(&ch->prio, fh->prio); @@ -885,7 +872,6 @@ static int vpif_reqbufs(struct file *file, void *priv, struct channel_obj *ch = fh->channel; struct common_obj *common; u8 index = 0; - int ret = 0; vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -908,13 +894,8 @@ static int vpif_reqbufs(struct file *file, void *priv, common = &ch->common[index]; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (0 != common->io_usrs) { - ret = -EBUSY; - goto reqbuf_exit; - } + if (0 != common->io_usrs) + return -EBUSY; /* Initialize videobuf queue as per the buffer type */ videobuf_queue_dma_contig_init(&common->buffer_queue, @@ -923,7 +904,7 @@ static int vpif_reqbufs(struct file *file, void *priv, reqbuf->type, common->fmt.fmt.pix.field, sizeof(struct videobuf_buffer), fh, - NULL); + &common->lock); /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; @@ -934,11 +915,7 @@ static int vpif_reqbufs(struct file *file, void *priv, INIT_LIST_HEAD(&common->dma_queue); /* Allocate buffers */ - ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); - -reqbuf_exit: - mutex_unlock(&common->lock); - return ret; + return videobuf_reqbufs(&common->buffer_queue, reqbuf); } /** @@ -1152,11 +1129,6 @@ static int vpif_streamon(struct file *file, void *priv, return ret; } - if (mutex_lock_interruptible(&common->lock)) { - ret = -ERESTARTSYS; - goto streamoff_exit; - } - /* If buffer queue is empty, return error */ if (list_empty(&common->dma_queue)) { vpif_dbg(1, debug, "buffer queue is empty\n"); @@ -1235,13 +1207,10 @@ static int vpif_streamon(struct file *file, void *priv, enable_channel1(1); } channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - mutex_unlock(&common->lock); return ret; exit: - mutex_unlock(&common->lock); -streamoff_exit: - ret = videobuf_streamoff(&common->buffer_queue); + videobuf_streamoff(&common->buffer_queue); return ret; } @@ -1279,9 +1248,6 @@ static int vpif_streamoff(struct file *file, void *priv, return -EINVAL; } - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - /* disable channel */ if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { enable_channel0(0); @@ -1299,8 +1265,6 @@ static int vpif_streamoff(struct file *file, void *priv, if (ret && (ret != -ENOIOCTLCMD)) vpif_dbg(1, debug, "stream off failed in subdev\n"); - mutex_unlock(&common->lock); - return videobuf_streamoff(&common->buffer_queue); } @@ -1376,21 +1340,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; vpif_dbg(2, debug, "vpif_querystd\n"); - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - /* Call querystd function of decoder device */ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, querystd, std_id); if (ret < 0) vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - mutex_unlock(&common->lock); return ret; } @@ -1446,18 +1405,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) fh->initialized = 1; /* Call encoder subdevice function to set the standard */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - ch->video.stdid = *std_id; ch->video.dv_preset = V4L2_DV_INVALID; memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); /* Get the information about the standard */ if (vpif_update_std_info(ch)) { - ret = -EINVAL; vpif_err("Error getting the standard info\n"); - goto s_std_exit; + return -EINVAL; } /* Configure the default format information */ @@ -1468,9 +1423,6 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) s_std, *std_id); if (ret < 0) vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - -s_std_exit: - mutex_unlock(&common->lock); return ret; } @@ -1564,9 +1516,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) return -EINVAL; } - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - /* first setup input path from sub device to vpif */ if (config->setup_input_path) { ret = config->setup_input_path(ch->channel_id, @@ -1575,7 +1524,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) vpif_dbg(1, debug, "couldn't setup input path for the" " sub device %s, for input index %d\n", subdev_info->name, index); - goto exit; + return ret; } } @@ -1586,7 +1535,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) input, output, 0); if (ret < 0) { vpif_dbg(1, debug, "Failed to set input\n"); - goto exit; + return ret; } } vid_ch->input_idx = index; @@ -1597,9 +1546,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) /* update tvnorms from the sub device input info */ ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - -exit: - mutex_unlock(&common->lock); return ret; } @@ -1668,11 +1614,7 @@ static int vpif_g_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; /* Fill in the information about format */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - *fmt = common->fmt; - mutex_unlock(&common->lock); return 0; } @@ -1720,12 +1662,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; /* store the format in the channel object */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - common->fmt = *fmt; - mutex_unlock(&common->lock); - return 0; } @@ -2145,7 +2082,7 @@ static struct v4l2_file_operations vpif_fops = { .owner = THIS_MODULE, .open = vpif_open, .release = vpif_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .mmap = vpif_mmap, .poll = vpif_poll }; @@ -2288,6 +2225,7 @@ static __init int vpif_probe(struct platform_device *pdev) common = &(ch->common[VPIF_VIDEO_INDEX]); spin_lock_init(&common->irqlock); mutex_init(&common->lock); + ch->video_dev->lock = &common->lock; /* Initialize prio member of channel object */ v4l2_prio_init(&ch->prio); err = video_register_device(ch->video_dev, -- cgit v1.2.3 From 9bfaae24f991ff5255de17cd05838d1cd131727c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Jan 2011 13:35:45 -0300 Subject: [media] davinci: convert vpif_display to core-assisted locking vpif_display now uses .unlocked_ioctl instead of .ioctl. Signed-off-by: Hans Verkuil Acked-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/davinci/vpif_display.c | 98 ++++++------------------------ 1 file changed, 20 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index 7cb70d916f4b..cdf659abdc2a 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -652,9 +652,6 @@ static int vpif_release(struct file *filep) struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - /* if this instance is doing IO */ if (fh->io_allowed[VPIF_VIDEO_INDEX]) { /* Reset io_usrs member of channel object */ @@ -677,8 +674,6 @@ static int vpif_release(struct file *filep) config_params.numbuffers[ch->channel_id]; } - mutex_unlock(&common->lock); - /* Decrement channel usrs counter */ atomic_dec(&ch->usrs); /* If this file handle has initialize encoder device, reset it */ @@ -737,24 +732,15 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; /* Check the validity of the buffer type */ if (common->fmt.type != fmt->type) return -EINVAL; - /* Fill in the information about format */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - if (vpif_update_resolution(ch)) - ret = -EINVAL; - else - *fmt = common->fmt; - - mutex_unlock(&common->lock); - - return ret; + return -EINVAL; + *fmt = common->fmt; + return 0; } static int vpif_s_fmt_vid_out(struct file *file, void *priv, @@ -794,12 +780,7 @@ static int vpif_s_fmt_vid_out(struct file *file, void *priv, /* store the pix format in the channel object */ common->fmt.fmt.pix = *pixfmt; /* store the format in the channel object */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - common->fmt = *fmt; - mutex_unlock(&common->lock); - return 0; } @@ -829,7 +810,6 @@ static int vpif_reqbufs(struct file *file, void *priv, struct common_obj *common; enum v4l2_field field; u8 index = 0; - int ret = 0; /* This file handle has not initialized the channel, It is not allowed to do settings */ @@ -847,18 +827,12 @@ static int vpif_reqbufs(struct file *file, void *priv, index = VPIF_VIDEO_INDEX; common = &ch->common[index]; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - if (common->fmt.type != reqbuf->type) { - ret = -EINVAL; - goto reqbuf_exit; - } + if (common->fmt.type != reqbuf->type) + return -EINVAL; - if (0 != common->io_usrs) { - ret = -EBUSY; - goto reqbuf_exit; - } + if (0 != common->io_usrs) + return -EBUSY; if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) @@ -875,7 +849,7 @@ static int vpif_reqbufs(struct file *file, void *priv, &common->irqlock, reqbuf->type, field, sizeof(struct videobuf_buffer), fh, - NULL); + &common->lock); /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; @@ -886,11 +860,7 @@ static int vpif_reqbufs(struct file *file, void *priv, INIT_LIST_HEAD(&common->dma_queue); /* Allocate buffers */ - ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); - -reqbuf_exit: - mutex_unlock(&common->lock); - return ret; + return videobuf_reqbufs(&common->buffer_queue, reqbuf); } static int vpif_querybuf(struct file *file, void *priv, @@ -1011,25 +981,19 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) } /* Call encoder subdevice function to set the standard */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - ch->video.stdid = *std_id; ch->video.dv_preset = V4L2_DV_INVALID; memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); /* Get the information about the standard */ - if (vpif_update_resolution(ch)) { - ret = -EINVAL; - goto s_std_exit; - } + if (vpif_update_resolution(ch)) + return -EINVAL; if ((ch->vpifparams.std_info.width * ch->vpifparams.std_info.height * 2) > config_params.channel_bufsize[ch->channel_id]) { vpif_err("invalid std for this size\n"); - ret = -EINVAL; - goto s_std_exit; + return -EINVAL; } common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; @@ -1040,16 +1004,13 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) s_std_output, *std_id); if (ret < 0) { vpif_err("Failed to set output standard\n"); - goto s_std_exit; + return ret; } ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, s_std, *std_id); if (ret < 0) vpif_err("Failed to set standard for sub devices\n"); - -s_std_exit: - mutex_unlock(&common->lock); return ret; } @@ -1121,14 +1082,10 @@ static int vpif_streamon(struct file *file, void *priv, return ret; } - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - /* If buffer queue is empty, return error */ if (list_empty(&common->dma_queue)) { vpif_err("buffer queue is empty\n"); - ret = -EIO; - goto streamon_exit; + return -EIO; } /* Get the next frame from the buffer queue */ @@ -1154,8 +1111,7 @@ static int vpif_streamon(struct file *file, void *priv, || (!ch->vpifparams.std_info.frm_fmt && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { vpif_err("conflict in field format and std format\n"); - ret = -EINVAL; - goto streamon_exit; + return -EINVAL; } /* clock settings */ @@ -1164,13 +1120,13 @@ static int vpif_streamon(struct file *file, void *priv, ch->vpifparams.std_info.hd_sd); if (ret < 0) { vpif_err("can't set clock\n"); - goto streamon_exit; + return ret; } /* set the parameters and addresses */ ret = vpif_set_video_params(vpif, ch->channel_id + 2); if (ret < 0) - goto streamon_exit; + return ret; common->started = ret; vpif_config_addr(ch, ret); @@ -1195,9 +1151,6 @@ static int vpif_streamon(struct file *file, void *priv, } channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; } - -streamon_exit: - mutex_unlock(&common->lock); return ret; } @@ -1223,9 +1176,6 @@ static int vpif_streamoff(struct file *file, void *priv, return -EINVAL; } - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { @@ -1240,8 +1190,6 @@ static int vpif_streamoff(struct file *file, void *priv, } common->started = 0; - mutex_unlock(&common->lock); - return videobuf_streamoff(&common->buffer_queue); } @@ -1288,13 +1236,9 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - if (common->started) { vpif_err("Streaming in progress\n"); - ret = -EBUSY; - goto s_output_exit; + return -EBUSY; } ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, @@ -1304,9 +1248,6 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i) vpif_err("Failed to set output standard\n"); vid_ch->output_id = i; - -s_output_exit: - mutex_unlock(&common->lock); return ret; } @@ -1658,7 +1599,7 @@ static const struct v4l2_file_operations vpif_fops = { .owner = THIS_MODULE, .open = vpif_open, .release = vpif_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .mmap = vpif_mmap, .poll = vpif_poll }; @@ -1842,6 +1783,7 @@ static __init int vpif_probe(struct platform_device *pdev) v4l2_prio_init(&ch->prio); ch->common[VPIF_VIDEO_INDEX].fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ch->video_dev->lock = &common->lock; /* register video device */ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", -- cgit v1.2.3 From 90d873a7f9389478e68494c530afab8b19c04f29 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Jan 2011 14:40:07 -0300 Subject: [media] radio-maxiradio.c: use sensible frequency range Use the standard USA/Europe frequency range of 87-108 MHz instead of the arbitrary 50-150 MHz. Copied from the radio-gemtek-pci driver which supports the same hardware. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-maxiradio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 6459a220b0dd..5c2a9058c09f 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -77,8 +77,8 @@ MODULE_PARM_DESC(debug, "activates debug info"); /* TEA5757 pin mappings */ static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; -#define FREQ_LO (50 * 16000) -#define FREQ_HI (150 * 16000) +#define FREQ_LO (87 * 16000) +#define FREQ_HI (108 * 16000) #define FREQ_IF 171200 /* 10.7*16000 */ #define FREQ_STEP 200 /* 12.5*16 */ -- cgit v1.2.3 From 424852f4374561630d526e7bb04eec5bb7d665a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Jan 2011 14:42:41 -0300 Subject: [media] radio-gemtek-pci: remove duplicate driver The radio-gemtek-pci driver is for the same hardware as the radio-maxiradio driver which uses the same GemTek PR103 and tea5757 combination and the two drivers are identical. I chose the maxiradio over the gemtek-pci driver since the maxiradio has support for mono/stereo detection. Tested with my gemtek-pci card. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 14 - drivers/media/radio/Makefile | 1 - drivers/media/radio/radio-gemtek-pci.c | 478 --------------------------------- 3 files changed, 493 deletions(-) delete mode 100644 drivers/media/radio/radio-gemtek-pci.c (limited to 'drivers') diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 3c5a4739ed70..ecdffa6aac66 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -151,20 +151,6 @@ config RADIO_GEMTEK_PROBE following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and 0x28c. -config RADIO_GEMTEK_PCI - tristate "GemTek PCI Radio Card support" - depends on VIDEO_V4L2 && PCI - ---help--- - Choose Y here if you have this PCI FM radio card. - - In order to control your radio card, you will need to use programs - that are compatible with the Video for Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-gemtek-pci. - config RADIO_MAXIRADIO tristate "Guillemot MAXI Radio FM 2000 radio" depends on VIDEO_V4L2 && PCI diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index d2970748a69f..717656d2f749 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o -obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c deleted file mode 100644 index 28fa85ba2087..000000000000 --- a/drivers/media/radio/radio-gemtek-pci.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - *************************************************************************** - * - * radio-gemtek-pci.c - Gemtek PCI Radio driver - * (C) 2001 Vladimir Shebordaev - * - *************************************************************************** - * - * 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. - * - *************************************************************************** - * - * Gemtek Corp still silently refuses to release any specifications - * of their multimedia devices, so the protocol still has to be - * reverse engineered. - * - * The v4l code was inspired by Jonas Munsin's Gemtek serial line - * radio device driver. - * - * Please, let me know if this piece of code was useful :) - * - * TODO: multiple device support and portability were not tested - * - * Converted to V4L2 API by Mauro Carvalho Chehab - * - *************************************************************************** - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* for KERNEL_VERSION MACRO */ -#include -#include -#include -#include - -MODULE_AUTHOR("Vladimir Shebordaev "); -MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card"); -MODULE_LICENSE("GPL"); - -static int nr_radio = -1; -static int mx = 1; - -module_param(mx, bool, 0); -MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not"); -module_param(nr_radio, int, 0); -MODULE_PARM_DESC(nr_radio, "video4linux device number to use"); - -#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) - -#ifndef PCI_VENDOR_ID_GEMTEK -#define PCI_VENDOR_ID_GEMTEK 0x5046 -#endif - -#ifndef PCI_DEVICE_ID_GEMTEK_PR103 -#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001 -#endif - -#ifndef GEMTEK_PCI_RANGE_LOW -#define GEMTEK_PCI_RANGE_LOW (87*16000) -#endif - -#ifndef GEMTEK_PCI_RANGE_HIGH -#define GEMTEK_PCI_RANGE_HIGH (108*16000) -#endif - -struct gemtek_pci { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct mutex lock; - struct pci_dev *pdev; - - u32 iobase; - u32 length; - - u32 current_frequency; - u8 mute; -}; - -static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev); -} - -static inline u8 gemtek_pci_out(u16 value, u32 port) -{ - outw(value, port); - - return (u8)value; -} - -#define _b0(v) (*((u8 *)&v)) - -static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep) -{ - u8 byte = *last_byte; - - if (!value) { - if (!keep) - value = (u16)port; - byte &= 0xfd; - } else - byte |= 2; - - _b0(value) = byte; - outw(value, port); - byte |= 1; - _b0(value) = byte; - outw(value, port); - byte &= 0xfe; - _b0(value) = byte; - outw(value, port); - - *last_byte = byte; -} - -static inline void gemtek_pci_nil(u32 port, u8 *last_byte) -{ - __gemtek_pci_cmd(0x00, port, last_byte, false); -} - -static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte) -{ - __gemtek_pci_cmd(cmd, port, last_byte, true); -} - -static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency) -{ - int i; - u32 value = frequency / 200 + 856; - u16 mask = 0x8000; - u8 last_byte; - u32 port = card->iobase; - - mutex_lock(&card->lock); - card->current_frequency = frequency; - last_byte = gemtek_pci_out(0x06, port); - - i = 0; - do { - gemtek_pci_nil(port, &last_byte); - i++; - } while (i < 9); - - i = 0; - do { - gemtek_pci_cmd(value & mask, port, &last_byte); - mask >>= 1; - i++; - } while (i < 16); - - outw(0x10, port); - mutex_unlock(&card->lock); -} - - -static void gemtek_pci_mute(struct gemtek_pci *card) -{ - mutex_lock(&card->lock); - outb(0x1f, card->iobase); - card->mute = true; - mutex_unlock(&card->lock); -} - -static void gemtek_pci_unmute(struct gemtek_pci *card) -{ - if (card->mute) { - gemtek_pci_setfrequency(card, card->current_frequency); - card->mute = false; - } -} - -static int gemtek_pci_getsignal(struct gemtek_pci *card) -{ - int sig; - - mutex_lock(&card->lock); - sig = (inb(card->iobase) & 0x08) ? 0 : 1; - mutex_unlock(&card->lock); - return sig; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct gemtek_pci *card = video_drvdata(file); - - strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver)); - strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev)); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - struct gemtek_pci *card = video_drvdata(file); - - if (v->index > 0) - return -EINVAL; - - strlcpy(v->name, "FM", sizeof(v->name)); - v->type = V4L2_TUNER_RADIO; - v->rangelow = GEMTEK_PCI_RANGE_LOW; - v->rangehigh = GEMTEK_PCI_RANGE_HIGH; - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff * gemtek_pci_getsignal(card); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) -{ - return v->index ? -EINVAL : 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct gemtek_pci *card = video_drvdata(file); - - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (f->frequency < GEMTEK_PCI_RANGE_LOW || - f->frequency > GEMTEK_PCI_RANGE_HIGH) - return -EINVAL; - gemtek_pci_setfrequency(card, f->frequency); - card->mute = false; - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct gemtek_pci *card = video_drvdata(file); - - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = card->current_frequency; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gemtek_pci *card = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = card->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (card->mute) - ctrl->value = 0; - else - ctrl->value = 65535; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gemtek_pci *card = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - gemtek_pci_mute(card); - else - gemtek_pci_unmute(card); - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value) - gemtek_pci_unmute(card); - else - gemtek_pci_mute(card); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - -enum { - GEMTEK_PR103 -}; - -static char *card_names[] __devinitdata = { - "GEMTEK_PR103" -}; - -static struct pci_device_id gemtek_pci_id[] = -{ - { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, gemtek_pci_id); - -static const struct v4l2_file_operations gemtek_pci_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) -{ - struct gemtek_pci *card; - struct v4l2_device *v4l2_dev; - int res; - - card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL); - if (card == NULL) { - dev_err(&pdev->dev, "out of memory\n"); - return -ENOMEM; - } - - v4l2_dev = &card->v4l2_dev; - mutex_init(&card->lock); - card->pdev = pdev; - - strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name)); - - res = v4l2_device_register(&pdev->dev, v4l2_dev); - if (res < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - kfree(card); - return res; - } - - if (pci_enable_device(pdev)) - goto err_pci; - - card->iobase = pci_resource_start(pdev, 0); - card->length = pci_resource_len(pdev, 0); - - if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) { - v4l2_err(v4l2_dev, "i/o port already in use\n"); - goto err_pci; - } - - strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name)); - card->vdev.v4l2_dev = v4l2_dev; - card->vdev.fops = &gemtek_pci_fops; - card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops; - card->vdev.release = video_device_release_empty; - video_set_drvdata(&card->vdev, card); - - gemtek_pci_mute(card); - - if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0) - goto err_video; - - v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", - pdev->revision, card->iobase, card->iobase + card->length - 1); - - return 0; - -err_video: - release_region(card->iobase, card->length); - -err_pci: - v4l2_device_unregister(v4l2_dev); - kfree(card); - return -ENODEV; -} - -static void __devexit gemtek_pci_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct gemtek_pci *card = to_gemtek_pci(v4l2_dev); - - video_unregister_device(&card->vdev); - v4l2_device_unregister(v4l2_dev); - - release_region(card->iobase, card->length); - - if (mx) - gemtek_pci_mute(card); - - kfree(card); -} - -static struct pci_driver gemtek_pci_driver = { - .name = "gemtek_pci", - .id_table = gemtek_pci_id, - .probe = gemtek_pci_probe, - .remove = __devexit_p(gemtek_pci_remove), -}; - -static int __init gemtek_pci_init(void) -{ - return pci_register_driver(&gemtek_pci_driver); -} - -static void __exit gemtek_pci_exit(void) -{ - pci_unregister_driver(&gemtek_pci_driver); -} - -module_init(gemtek_pci_init); -module_exit(gemtek_pci_exit); -- cgit v1.2.3 From 82f4b5b67e795fe03952b278873712e4562304d2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 7 Jan 2011 21:59:11 -0300 Subject: [media] af9013: fix AF9013 TDA18271 IF config IF freq for DVB-T 7 MHz and 8 MHz was set slightly wrong. Due to that it didn't worked at all (?) for 7 MHz channels and most likely performance was dropped for 8 MHz channels. That bug was pointed by few people during last two months. Thank you. Trivial fix. Compile tested only due to lack of proper HW and signal. Signed-off-by: Antti Palosaari Cc: Romolo Manfredini Cc: Alireza Moini Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/af9013.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index ce222055526d..ba25fa0b0fc2 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -334,11 +334,11 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) if_sample_freq = 3300000; /* 3.3 MHz */ break; case BANDWIDTH_7_MHZ: - if_sample_freq = 3800000; /* 3.8 MHz */ + if_sample_freq = 3500000; /* 3.5 MHz */ break; case BANDWIDTH_8_MHZ: default: - if_sample_freq = 4300000; /* 4.3 MHz */ + if_sample_freq = 4000000; /* 4.0 MHz */ break; } } else if (state->config.tuner == AF9013_TUNER_TDA18218) { -- cgit v1.2.3 From 4e770f7602fb2285f3106f98109d0685618ddc22 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2010 13:11:21 -0300 Subject: [media] gspca_main: Locking fixes 1 The gspca_dev->streaming boolean is protected against multiple access through gspca_dev->queue_lock everywhere except for 2 places. This patch fixes this by bringing it under the lock in vidioc_streamoff. And by removing the check for gspca_dev->streaming in gspca_disconnect, the destroy_urbs call may be called multiple times (and is protected by the usb_lock) and calling wake_up_interruptible can also always be done safely. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 442970073e8a..74626b6a9eb4 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1630,11 +1630,15 @@ static int vidioc_streamoff(struct file *file, void *priv, if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (!gspca_dev->streaming) - return 0; + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; + if (!gspca_dev->streaming) { + ret = 0; + goto out; + } + /* check the capture file */ if (gspca_dev->capt_file != file) { ret = -EBUSY; @@ -2341,12 +2345,11 @@ void gspca_disconnect(struct usb_interface *intf) PDEBUG(D_PROBE, "%s disconnect", video_device_node_name(&gspca_dev->vdev)); mutex_lock(&gspca_dev->usb_lock); + gspca_dev->present = 0; + wake_up_interruptible(&gspca_dev->wq); - if (gspca_dev->streaming) { - destroy_urbs(gspca_dev); - wake_up_interruptible(&gspca_dev->wq); - } + destroy_urbs(gspca_dev); #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) gspca_input_destroy_urb(gspca_dev); -- cgit v1.2.3 From 27074efa2ee8c1ef07dc5f644104e35d39e43322 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2010 19:54:33 -0300 Subject: [media] gspca_main: Locking fixes 2 Before this patch vidioc_dqbuf is using its own read_lock, where as other queue related functions use queue_lock. This means that dqbuf is accessing several variables in a racy manor. The most important one being fr_o, which may be changed from underneath dqbuf by vidioc_reqbufs or vidioc_streamoff. Other variables which it accesses unprotected are gspca_dev->memory, gspca_dev->streaming and gspca_dev->capt_file. This patch fixes this by changing vidioc_dqbuf to also use the queue_lock. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 112 ++++++++++++++++++++------------------ drivers/media/video/gspca/gspca.h | 1 - 2 files changed, 58 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 74626b6a9eb4..64ecf669d655 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1831,33 +1831,77 @@ out: return ret; } +static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file, + enum v4l2_memory memory) +{ + if (!gspca_dev->present) + return -ENODEV; + if (gspca_dev->capt_file != file || gspca_dev->memory != memory || + !gspca_dev->streaming) + return -EINVAL; + + /* check if a frame is ready */ + return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i); +} + +static int frame_ready(struct gspca_dev *gspca_dev, struct file *file, + enum v4l2_memory memory) +{ + int ret; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + ret = frame_ready_nolock(gspca_dev, file, memory); + mutex_unlock(&gspca_dev->queue_lock); + return ret; +} + /* - * wait for a video frame + * dequeue a video buffer * - * If a frame is ready, its index is returned. + * If nonblock_ing is false, block until a buffer is available. */ -static int frame_wait(struct gspca_dev *gspca_dev, - int nonblock_ing) +static int vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *v4l2_buf) { - int i, ret; + struct gspca_dev *gspca_dev = priv; + struct gspca_frame *frame; + int i, j, ret; - /* check if a frame is ready */ - i = gspca_dev->fr_o; - if (i == atomic_read(&gspca_dev->fr_i)) { - if (nonblock_ing) + PDEBUG(D_FRAM, "dqbuf"); + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; + + for (;;) { + ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory); + if (ret < 0) + goto out; + if (ret > 0) + break; + + mutex_unlock(&gspca_dev->queue_lock); + + if (file->f_flags & O_NONBLOCK) return -EAGAIN; /* wait till a frame is ready */ ret = wait_event_interruptible_timeout(gspca_dev->wq, - i != atomic_read(&gspca_dev->fr_i) || - !gspca_dev->streaming || !gspca_dev->present, + frame_ready(gspca_dev, file, v4l2_buf->memory), msecs_to_jiffies(3000)); if (ret < 0) return ret; - if (ret == 0 || !gspca_dev->streaming || !gspca_dev->present) + if (ret == 0) return -EIO; + + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + return -ERESTARTSYS; } + i = gspca_dev->fr_o; + j = gspca_dev->fr_queue[i]; + frame = &gspca_dev->frame[j]; + gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES; if (gspca_dev->sd_desc->dq_callback) { @@ -1867,46 +1911,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, gspca_dev->sd_desc->dq_callback(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); } - return gspca_dev->fr_queue[i]; -} - -/* - * dequeue a video buffer - * - * If nonblock_ing is false, block until a buffer is available. - */ -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *v4l2_buf) -{ - struct gspca_dev *gspca_dev = priv; - struct gspca_frame *frame; - int i, ret; - - PDEBUG(D_FRAM, "dqbuf"); - if (v4l2_buf->memory != gspca_dev->memory) - return -EINVAL; - if (!gspca_dev->present) - return -ENODEV; - - /* if not streaming, be sure the application will not loop forever */ - if (!(file->f_flags & O_NONBLOCK) - && !gspca_dev->streaming && gspca_dev->users == 1) - return -EINVAL; - - /* only the capturing file may dequeue */ - if (gspca_dev->capt_file != file) - return -EINVAL; - - /* only one dequeue / read at a time */ - if (mutex_lock_interruptible(&gspca_dev->read_lock)) - return -ERESTARTSYS; - - ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK); - if (ret < 0) - goto out; - i = ret; /* frame index */ - frame = &gspca_dev->frame[i]; if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, frame->data, @@ -1919,10 +1924,10 @@ static int vidioc_dqbuf(struct file *file, void *priv, } frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); - PDEBUG(D_FRAM, "dqbuf %d", i); + PDEBUG(D_FRAM, "dqbuf %d", j); ret = 0; out: - mutex_unlock(&gspca_dev->read_lock); + mutex_unlock(&gspca_dev->queue_lock); return ret; } @@ -2270,7 +2275,6 @@ int gspca_dev_probe2(struct usb_interface *intf, goto out; mutex_init(&gspca_dev->usb_lock); - mutex_init(&gspca_dev->read_lock); mutex_init(&gspca_dev->queue_lock); init_waitqueue_head(&gspca_dev->wq); diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 97b77a26a2eb..a2a1a6aa0606 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -205,7 +205,6 @@ struct gspca_dev { wait_queue_head_t wq; /* wait queue */ struct mutex usb_lock; /* usb exchange protection */ - struct mutex read_lock; /* read protection */ struct mutex queue_lock; /* ISOC queue protection */ int usb_err; /* USB error - protected by usb_lock */ u16 pkt_size; /* ISOC packet size */ -- cgit v1.2.3 From 4a82bc60a9abbfca0c899366ff30c592e8020520 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2010 20:00:17 -0300 Subject: [media] gspca_main: Update buffer flags even when user_copy fails Before this patch dqbuf errors out on a failing user_copy (with user pointers) before updating the buffer flags, causing a successsfully dequeued buffer to still have the DONE flag, which means that it could no longer be re-queueud (assuming the app somehow survives the segfault). Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 64ecf669d655..fbc5666ee29e 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1912,6 +1912,11 @@ static int vidioc_dqbuf(struct file *file, void *priv, mutex_unlock(&gspca_dev->usb_lock); } + frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; + memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); + PDEBUG(D_FRAM, "dqbuf %d", j); + ret = 0; + if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, frame->data, @@ -1919,13 +1924,8 @@ static int vidioc_dqbuf(struct file *file, void *priv, PDEBUG(D_ERR|D_STREAM, "dqbuf cp to user failed"); ret = -EFAULT; - goto out; } } - frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; - memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); - PDEBUG(D_FRAM, "dqbuf %d", j); - ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); return ret; -- cgit v1.2.3 From 7f6eb118df84715b128e25e99dc6a3ebc5b133d6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Dec 2010 20:20:09 -0300 Subject: [media] gspca_main: Remove no longer used users variable Remove the no longer used / useful users variable, and with that gone there also is no longer a need to take queue_lock in dev_open. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 32 +++++--------------------------- drivers/media/video/gspca/gspca.h | 1 - 2 files changed, 5 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index fbc5666ee29e..0ba42dd4b99b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1210,29 +1210,15 @@ static void gspca_release(struct video_device *vfd) static int dev_open(struct file *file) { struct gspca_dev *gspca_dev; - int ret; PDEBUG(D_STREAM, "[%s] open", current->comm); gspca_dev = (struct gspca_dev *) video_devdata(file); - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } - - if (gspca_dev->users > 4) { /* (arbitrary value) */ - ret = -EBUSY; - goto out; - } + if (!gspca_dev->present) + return -ENODEV; /* protect the subdriver against rmmod */ - if (!try_module_get(gspca_dev->module)) { - ret = -ENODEV; - goto out; - } - - gspca_dev->users++; + if (!try_module_get(gspca_dev->module)) + return -ENODEV; file->private_data = gspca_dev; #ifdef GSPCA_DEBUG @@ -1244,14 +1230,7 @@ static int dev_open(struct file *file) gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG); #endif - ret = 0; -out: - mutex_unlock(&gspca_dev->queue_lock); - if (ret != 0) - PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret); - else - PDEBUG(D_STREAM, "open done"); - return ret; + return 0; } static int dev_close(struct file *file) @@ -1261,7 +1240,6 @@ static int dev_close(struct file *file) PDEBUG(D_STREAM, "[%s] close", current->comm); if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; - gspca_dev->users--; /* if the file did the capture, free the streaming resources */ if (gspca_dev->capt_file == file) { diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index a2a1a6aa0606..41755226d389 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -211,7 +211,6 @@ struct gspca_dev { #ifdef CONFIG_PM char frozen; /* suspend - resume */ #endif - char users; /* number of opens */ char present; /* device connected */ char nbufread; /* number of buffers for read() */ char memory; /* memory type (V4L2_MEMORY_xxx) */ -- cgit v1.2.3 From d642de2ed472df308f8ee49417e29030f69b2095 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Dec 2010 04:51:36 -0300 Subject: [media] gspca_main: Set memory type to GSPCA_MEMORY_NO on buffer release Before this patch we were not setting the memory type to GSPCA_MEMORY_NO when the buffers were released by the app doing a reqbufs 0. Nor would the memory type be set to GSPCA_MEMORY_NO on device close, as capture_file already is NULL on device close because of the reqbufs 0. This caused the following problem: -app1 does reqbufs USERPTR for 4 buffers -app1 does reqbufs USERPTR for 0 buffers -app2 tries to do reqbufs MMAP for 4 buffers fails because gspca_dev->memory still is USERPTR Fixing this also allows an app to switch memory type's by unrequesting the buffers and re-requesting them of a different type. This patch also moves the setting of gspca_dev->frsz and gscpa_dev->memory to after alloc_frame succeeding, so that they are not changed when allocating fails. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 0ba42dd4b99b..adab34f91a68 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -508,8 +508,8 @@ static int gspca_is_compressed(__u32 format) return 0; } -static int frame_alloc(struct gspca_dev *gspca_dev, - unsigned int count) +static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, + enum v4l2_memory memory, unsigned int count) { struct gspca_frame *frame; unsigned int frsz; @@ -519,7 +519,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev, frsz = gspca_dev->cam.cam_mode[i].sizeimage; PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz); frsz = PAGE_ALIGN(frsz); - gspca_dev->frsz = frsz; if (count >= GSPCA_MAX_FRAMES) count = GSPCA_MAX_FRAMES - 1; gspca_dev->frbuf = vmalloc_32(frsz * count); @@ -527,6 +526,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev, err("frame alloc failed"); return -ENOMEM; } + gspca_dev->capt_file = file; + gspca_dev->memory = memory; + gspca_dev->frsz = frsz; gspca_dev->nframes = count; for (i = 0; i < count; i++) { frame = &gspca_dev->frame[i]; @@ -535,7 +537,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, frame->v4l2_buf.flags = 0; frame->v4l2_buf.field = V4L2_FIELD_NONE; frame->v4l2_buf.length = frsz; - frame->v4l2_buf.memory = gspca_dev->memory; + frame->v4l2_buf.memory = memory; frame->v4l2_buf.sequence = 0; frame->data = gspca_dev->frbuf + i * frsz; frame->v4l2_buf.m.offset = i * frsz; @@ -558,6 +560,9 @@ static void frame_free(struct gspca_dev *gspca_dev) gspca_dev->frame[i].data = NULL; } gspca_dev->nframes = 0; + gspca_dev->frsz = 0; + gspca_dev->capt_file = NULL; + gspca_dev->memory = GSPCA_MEMORY_NO; } static void destroy_urbs(struct gspca_dev *gspca_dev) @@ -1250,8 +1255,6 @@ static int dev_close(struct file *file) mutex_unlock(&gspca_dev->usb_lock); } frame_free(gspca_dev); - gspca_dev->capt_file = NULL; - gspca_dev->memory = GSPCA_MEMORY_NO; } file->private_data = NULL; module_put(gspca_dev->module); @@ -1524,17 +1527,13 @@ static int vidioc_reqbufs(struct file *file, void *priv, } /* free the previous allocated buffers, if any */ - if (gspca_dev->nframes != 0) { + if (gspca_dev->nframes != 0) frame_free(gspca_dev); - gspca_dev->capt_file = NULL; - } if (rb->count == 0) /* unrequest */ goto out; - gspca_dev->memory = rb->memory; - ret = frame_alloc(gspca_dev, rb->count); + ret = frame_alloc(gspca_dev, file, rb->memory, rb->count); if (ret == 0) { rb->count = gspca_dev->nframes; - gspca_dev->capt_file = file; if (streaming) ret = gspca_init_transfer(gspca_dev); } -- cgit v1.2.3 From ee3629914b2b115f00f4197e80b1e7cb12881059 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Dec 2010 05:05:56 -0300 Subject: [media] gspca_main: Simplify read mode memory type checks gspca_dev->memory == GSPCA_MEMORY_NO implies gspca_dev->nframes == 0, so there is no need to check for both in dev_poll. The check in dev_read also is more complex then needed, as dqbuf which dev_read calls already does all necessary checks. Moreover dqbuf is holding the proper locks while checking where as dev_read itself is not. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index adab34f91a68..244fb76eaead 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -2019,9 +2019,7 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) poll_wait(file, &gspca_dev->wq, wait); /* if reqbufs is not done, the user would use read() */ - if (gspca_dev->nframes == 0) { - if (gspca_dev->memory != GSPCA_MEMORY_NO) - return POLLERR; /* not the 1st time */ + if (gspca_dev->memory == GSPCA_MEMORY_NO) { ret = read_alloc(gspca_dev, file); if (ret != 0) return POLLERR; @@ -2053,18 +2051,10 @@ static ssize_t dev_read(struct file *file, char __user *data, PDEBUG(D_FRAM, "read (%zd)", count); if (!gspca_dev->present) return -ENODEV; - switch (gspca_dev->memory) { - case GSPCA_MEMORY_NO: /* first time */ + if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */ ret = read_alloc(gspca_dev, file); if (ret != 0) return ret; - break; - case GSPCA_MEMORY_READ: - if (gspca_dev->capt_file == file) - break; - /* fall thru */ - default: - return -EINVAL; } /* get a frame */ -- cgit v1.2.3 From ce5610bca74571674c1970d33063e7c06295a9a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Dec 2010 07:41:54 -0300 Subject: [media] gspca_main: Allow switching from read to mmap / userptr mode Some applications (xawtv, qv4l2) mix read and mmap calls. Allow switching from read mode back to mmap mode (by doing a reqbufs). Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 244fb76eaead..4ab906be8962 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1497,6 +1497,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, return -ERESTARTSYS; if (gspca_dev->memory != GSPCA_MEMORY_NO + && gspca_dev->memory != GSPCA_MEMORY_READ && gspca_dev->memory != rb->memory) { ret = -EBUSY; goto out; @@ -1525,6 +1526,9 @@ static int vidioc_reqbufs(struct file *file, void *priv, gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); } + /* Don't restart the stream when switching from read to mmap mode */ + if (gspca_dev->memory == GSPCA_MEMORY_READ) + streaming = 0; /* free the previous allocated buffers, if any */ if (gspca_dev->nframes != 0) -- cgit v1.2.3 From 0d0ae15dde7d4a778056268e64bb2625f84deab6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Dec 2010 17:17:51 -0300 Subject: [media] gspca_main: wake wq on streamoff We check for not streaming as a condition to abort waiting in dqbuf, so when another thread does a streamoff we should wake the wq. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 4ab906be8962..3581dea3c1f7 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1634,6 +1634,8 @@ static int vidioc_streamoff(struct file *file, void *priv, gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); + /* In case another thread is waiting in dqbuf */ + wake_up_interruptible(&gspca_dev->wq); /* empty the transfer queues */ atomic_set(&gspca_dev->fr_q, 0); -- cgit v1.2.3 From 8b064ee19d24e57d807060f50e945b5935565852 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 3 Jan 2011 12:48:10 -0300 Subject: [media] et61x251: remove wrongly claimed usb ids The et61x251 driver claims a whole list of usb id's, but it only has one sensor "module" which does sensor detection based on usb id and that only supports devices with the 102c:6251 usb id. Remove the usb-ids for other devices as for those the driver will fail with an unable to determine sensor type message anyways. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/et61x251/et61x251.h | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h index cc77d144df3c..bf66189cb26d 100644 --- a/drivers/media/video/et61x251/et61x251.h +++ b/drivers/media/video/et61x251/et61x251.h @@ -59,31 +59,7 @@ /*****************************************************************************/ static const struct usb_device_id et61x251_id_table[] = { - { USB_DEVICE(0x102c, 0x6151), }, { USB_DEVICE(0x102c, 0x6251), }, - { USB_DEVICE(0x102c, 0x6253), }, - { USB_DEVICE(0x102c, 0x6254), }, - { USB_DEVICE(0x102c, 0x6255), }, - { USB_DEVICE(0x102c, 0x6256), }, - { USB_DEVICE(0x102c, 0x6257), }, - { USB_DEVICE(0x102c, 0x6258), }, - { USB_DEVICE(0x102c, 0x6259), }, - { USB_DEVICE(0x102c, 0x625a), }, - { USB_DEVICE(0x102c, 0x625b), }, - { USB_DEVICE(0x102c, 0x625c), }, - { USB_DEVICE(0x102c, 0x625d), }, - { USB_DEVICE(0x102c, 0x625e), }, - { USB_DEVICE(0x102c, 0x625f), }, - { USB_DEVICE(0x102c, 0x6260), }, - { USB_DEVICE(0x102c, 0x6261), }, - { USB_DEVICE(0x102c, 0x6262), }, - { USB_DEVICE(0x102c, 0x6263), }, - { USB_DEVICE(0x102c, 0x6264), }, - { USB_DEVICE(0x102c, 0x6265), }, - { USB_DEVICE(0x102c, 0x6266), }, - { USB_DEVICE(0x102c, 0x6267), }, - { USB_DEVICE(0x102c, 0x6268), }, - { USB_DEVICE(0x102c, 0x6269), }, { } }; -- cgit v1.2.3 From a24f0c5c47946b1a1999f44808e2219e7758d146 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Jan 2011 11:36:54 -0300 Subject: [media] sn9c102: Remove not supported and non existing usb ids The sn9c102 driver claims a number of usb-ids which are for cameras with sensor types which it does not support. Also it claims a number of usb-ids which do not exist at all (not present in the windows drivers .inf files, not known by google). This patch also fixes the conflict with the gspca_sonixj driver for the 0c45:60c0 and 0c45:60fb usb ids. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sn9c102/sn9c102_devtable.h | 66 ++++++++++++-------------- 1 file changed, 31 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 41064c7b5ef8..74bc719b8e89 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -56,74 +56,70 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, #endif - { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, + { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */ #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, #endif - { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, + { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */ /* SN9C103 */ - { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */ + { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */ /* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ - { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */ { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, #endif - { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */ - { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */ { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, #endif - { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */ /* SN9C105 */ #if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, -#endif { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */ { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, /* SN9C120 */ { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), }, -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */ #if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, -#endif /* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, #endif { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, -- cgit v1.2.3 From 0a76cb8cefbaf84465e0cd9a6a1da7f54981c8ef Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Jan 2011 13:55:43 -0300 Subject: [media] gspca_sonixb: Refactor to unify bridge handling Refactor the code to unify how the sn9c101/102 and the sn9c103 bridge are handled. Also move code which is the same for all sensors from the per sensor init register settings to a central place. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 206 +++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 73504a3f87b7..43784027568f 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -23,8 +23,15 @@ /* Some documentation on known sonixb registers: Reg Use +sn9c101 / sn9c102: 0x10 high nibble red gain low nibble blue gain 0x11 low nibble green gain +sn9c103: +0x05 red gain 0-127 +0x06 blue gain 0-127 +0x07 green gain 0-127 +all: +0x08-0x0f i2c / 3wire registers 0x12 hstart 0x13 vstart 0x15 hsize (hsize = register-value * 16) @@ -88,12 +95,9 @@ struct sd { typedef const __u8 sensor_init_t[8]; struct sensor_data { - const __u8 *bridge_init[2]; - int bridge_init_size[2]; + const __u8 *bridge_init; sensor_init_t *sensor_init; int sensor_init_size; - sensor_init_t *sensor_bridge_init[2]; - int sensor_bridge_init_size[2]; int flags; unsigned ctrl_dis; __u8 sensor_addr; @@ -114,7 +118,6 @@ struct sensor_data { #define NO_FREQ (1 << FREQ_IDX) #define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX) -#define COMP2 0x8f #define COMP 0xc7 /* 0x87 //0x07 */ #define COMP1 0xc9 /* 0x89 //0x09 */ @@ -123,15 +126,11 @@ struct sensor_data { #define SYS_CLK 0x04 -#define SENS(bridge_1, bridge_3, sensor, sensor_1, \ - sensor_3, _flags, _ctrl_dis, _sensor_addr) \ +#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \ { \ - .bridge_init = { bridge_1, bridge_3 }, \ - .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \ + .bridge_init = bridge, \ .sensor_init = sensor, \ .sensor_init_size = sizeof(sensor), \ - .sensor_bridge_init = { sensor_1, sensor_3,}, \ - .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \ .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \ } @@ -311,7 +310,6 @@ static const __u8 initHv7131d[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x28, 0x1e, 0x60, 0x8e, 0x42, - 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c }; static const __u8 hv7131d_sensor_init[][8] = { {0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17}, @@ -326,7 +324,6 @@ static const __u8 initHv7131r[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x28, 0x1e, 0x60, 0x8a, 0x20, - 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c }; static const __u8 hv7131r_sensor_init[][8] = { {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10}, @@ -339,7 +336,7 @@ static const __u8 initOv6650[] = { 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b, - 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07 + 0x10, }; static const __u8 ov6650_sensor_init[][8] = { /* Bright, contrast, etc are set through SCBB interface. @@ -378,18 +375,7 @@ static const __u8 initOv7630[] = { 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ 0x28, 0x1e, /* H & V sizes r15 .. r16 */ - 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */ - 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */ -}; -static const __u8 initOv7630_3[] = { - 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */ - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ - 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */ - 0x28, 0x1e, /* H & V sizes r15 .. r16 */ 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */ - 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */ - 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */ - 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */ }; static const __u8 ov7630_sensor_init[][8] = { {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, @@ -413,16 +399,11 @@ static const __u8 ov7630_sensor_init[][8] = { {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, }; -static const __u8 ov7630_sensor_init_3[][8] = { - {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10}, -}; - static const __u8 initPas106[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x16, 0x12, 0x24, COMP1, MCK_INIT1, - 0x18, 0x10, 0x02, 0x02, 0x09, 0x07 }; /* compression 0x86 mckinit1 0x2b */ @@ -496,7 +477,6 @@ static const __u8 initPas202[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a, 0x28, 0x1e, 0x20, 0x89, 0x20, - 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c }; /* "Known" PAS202BCB registers: @@ -537,7 +517,6 @@ static const __u8 initTas5110c[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x09, 0x0a, 0x16, 0x12, 0x60, 0x86, 0x2b, - 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07 }; /* Same as above, except a different hstart */ static const __u8 initTas5110d[] = { @@ -545,7 +524,6 @@ static const __u8 initTas5110d[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x09, 0x0a, 0x16, 0x12, 0x60, 0x86, 0x2b, - 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07 }; static const __u8 tas5110_sensor_init[][8] = { {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10}, @@ -558,7 +536,6 @@ static const __u8 initTas5130[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a, 0x28, 0x1e, 0x60, COMP, MCK_INIT, - 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c }; static const __u8 tas5130_sensor_init[][8] = { /* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10}, @@ -569,21 +546,17 @@ static const __u8 tas5130_sensor_init[][8] = { }; static struct sensor_data sensor_data[] = { -SENS(initHv7131d, NULL, hv7131d_sensor_init, NULL, NULL, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initHv7131r, NULL, hv7131r_sensor_init, NULL, NULL, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), -SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60), -SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3, - F_GAIN, 0, 0x21), -SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ, - 0), -SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN, - NO_FREQ, 0), -SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL, - F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL, - F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, - 0), +SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), +SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60), +SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21), +SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0), +SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0), +SENS(initTas5110c, tas5110_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, + NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initTas5110d, tas5110_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, + NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initTas5130, tas5130_sensor_init, 0, NO_EXPO|NO_FREQ, 0), }; /* get one byte in gspca_dev->usb_buf */ @@ -796,7 +769,7 @@ static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 gain; - __u8 buf[2] = { 0, 0 }; + __u8 buf[3] = { 0, 0, 0 }; if (sensor_data[sd->sensor].flags & F_GAIN) { /* Use the sensor gain to do the actual gain */ @@ -804,13 +777,18 @@ static void setgain(struct gspca_dev *gspca_dev) return; } - gain = sd->gain >> 4; - - /* red and blue gain */ - buf[0] = gain << 4 | gain; - /* green gain */ - buf[1] = gain; - reg_w(gspca_dev, 0x10, buf, 2); + if (sd->bridge == BRIDGE_103) { + gain = sd->gain >> 1; + buf[0] = gain; /* Red */ + buf[1] = gain; /* Green */ + buf[2] = gain; /* Blue */ + reg_w(gspca_dev, 0x05, buf, 3); + } else { + gain = sd->gain >> 4; + buf[0] = gain << 4 | gain; /* Red and blue */ + buf[1] = gain; /* Green */ + reg_w(gspca_dev, 0x10, buf, 2); + } } static void setexposure(struct gspca_dev *gspca_dev) @@ -1127,53 +1105,91 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam; - int mode, l; - const __u8 *sn9c10x; - __u8 reg12_19[8]; + int i, mode; + __u8 regs[0x31]; mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07; - sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge]; - l = sensor_data[sd->sensor].bridge_init_size[sd->bridge]; - memcpy(reg12_19, &sn9c10x[0x12 - 1], 8); - reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4); - /* Special cases where reg 17 and or 19 value depends on mode */ + /* Copy registers 0x01 - 0x19 from the template */ + memcpy(®s[0x01], sensor_data[sd->sensor].bridge_init, 0x19); + /* Set the mode */ + regs[0x18] |= mode << 4; + + /* Set bridge gain to 1.0 */ + if (sd->bridge == BRIDGE_103) { + regs[0x05] = 0x20; /* Red */ + regs[0x06] = 0x20; /* Green */ + regs[0x07] = 0x20; /* Blue */ + } else { + regs[0x10] = 0x00; /* Red and blue */ + regs[0x11] = 0x00; /* Green */ + } + + /* Setup pixel numbers and auto exposure window */ + if (sensor_data[sd->sensor].flags & F_SIF) { + regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */ + regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */ + regs[0x1c] = 0x02; /* AE H-start 64 */ + regs[0x1d] = 0x02; /* AE V-start 64 */ + regs[0x1e] = 0x09; /* AE H-end 288 */ + regs[0x1f] = 0x07; /* AE V-end 224 */ + } else { + regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */ + regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */ + regs[0x1c] = 0x02; /* AE H-start 64 */ + regs[0x1d] = 0x03; /* AE V-start 96 */ + regs[0x1e] = 0x0f; /* AE H-end 480 */ + regs[0x1f] = 0x0c; /* AE V-end 384 */ + } + + /* Setup the gamma table (only used with the sn9c103 bridge) */ + for (i = 0; i < 16; i++) + regs[0x20 + i] = i * 16; + regs[0x20 + i] = 255; + + /* Special cases where some regs depend on mode or bridge */ switch (sd->sensor) { case SENSOR_TAS5130CXX: - /* probably not mode specific at all most likely the upper + /* FIXME / TESTME + probably not mode specific at all most likely the upper nibble of 0x19 is exposure (clock divider) just as with the tas5110, we need someone to test this. */ - reg12_19[7] = mode ? 0x23 : 0x43; + regs[0x19] = mode ? 0x23 : 0x43; break; + case SENSOR_OV7630: + /* FIXME / TESTME for some reason with the 101/102 bridge the + clock is set to 12 Mhz (reg1 == 0x04), rather then 24. + Also the hstart needs to go from 1 to 2 when using a 103, + which is likely related. This does not seem right. */ + if (sd->bridge == BRIDGE_103) { + regs[0x01] = 0x44; /* Select 24 Mhz clock */ + regs[0x12] = 0x02; /* Set hstart to 2 */ + } } /* Disable compression when the raw bayer format has been selected */ if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) - reg12_19[6] &= ~0x80; + regs[0x18] &= ~0x80; /* Vga mode emulation on SIF sensor? */ if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) { - reg12_19[0] += 16; /* 0x12: hstart adjust */ - reg12_19[1] += 24; /* 0x13: vstart adjust */ - reg12_19[3] = 320 / 16; /* 0x15: hsize */ - reg12_19[4] = 240 / 16; /* 0x16: vsize */ + regs[0x12] += 16; /* hstart adjust */ + regs[0x13] += 24; /* vstart adjust */ + regs[0x15] = 320 / 16; /* hsize */ + regs[0x16] = 240 / 16; /* vsize */ } /* reg 0x01 bit 2 video transfert on */ - reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1); + reg_w(gspca_dev, 0x01, ®s[0x01], 1); /* reg 0x17 SensorClk enable inv Clk 0x60 */ - reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1); + reg_w(gspca_dev, 0x17, ®s[0x17], 1); /* Set the registers from the template */ - reg_w(gspca_dev, 0x01, sn9c10x, l); + reg_w(gspca_dev, 0x01, ®s[0x01], + (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f); /* Init the sensor */ i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init, sensor_data[sd->sensor].sensor_init_size); - if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge]) - i2c_w_vector(gspca_dev, - sensor_data[sd->sensor].sensor_bridge_init[sd->bridge], - sensor_data[sd->sensor].sensor_bridge_init_size[ - sd->bridge]); - /* Mode specific sensor setup */ + /* Mode / bridge specific sensor setup */ switch (sd->sensor) { case SENSOR_PAS202: { const __u8 i2cpclockdiv[] = @@ -1181,27 +1197,37 @@ static int sd_start(struct gspca_dev *gspca_dev) /* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */ if (mode) i2c_w(gspca_dev, i2cpclockdiv); + break; } + case SENSOR_OV7630: + /* FIXME / TESTME We should be able to handle this identical + for the 101/102 and the 103 case */ + if (sd->bridge == BRIDGE_103) { + const __u8 i2c[] = { 0xa0, 0x21, 0x13, + 0x80, 0x00, 0x00, 0x00, 0x10 }; + i2c_w(gspca_dev, i2c); + } + break; } /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ - reg_w(gspca_dev, 0x15, ®12_19[3], 2); + reg_w(gspca_dev, 0x15, ®s[0x15], 2); /* compression register */ - reg_w(gspca_dev, 0x18, ®12_19[6], 1); + reg_w(gspca_dev, 0x18, ®s[0x18], 1); /* H_start */ - reg_w(gspca_dev, 0x12, ®12_19[0], 1); + reg_w(gspca_dev, 0x12, ®s[0x12], 1); /* V_START */ - reg_w(gspca_dev, 0x13, ®12_19[1], 1); + reg_w(gspca_dev, 0x13, ®s[0x13], 1); /* reset 0x17 SensorClk enable inv Clk 0x60 */ /*fixme: ov7630 [17]=68 8f (+20 if 102)*/ - reg_w(gspca_dev, 0x17, ®12_19[5], 1); + reg_w(gspca_dev, 0x17, ®s[0x17], 1); /*MCKSIZE ->3 */ /*fixme: not ov7630*/ - reg_w(gspca_dev, 0x19, ®12_19[7], 1); + reg_w(gspca_dev, 0x19, ®s[0x19], 1); /* AE_STRX AE_STRY AE_ENDX AE_ENDY */ - reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4); + reg_w(gspca_dev, 0x1c, ®s[0x1c], 4); /* Enable video transfert */ - reg_w(gspca_dev, 0x01, &sn9c10x[0], 1); + reg_w(gspca_dev, 0x01, ®s[0x01], 1); /* Compression */ - reg_w(gspca_dev, 0x18, ®12_19[6], 2); + reg_w(gspca_dev, 0x18, ®s[0x18], 2); msleep(20); sd->reg11 = -1; -- cgit v1.2.3 From f913c001cd6084db0e3486b832234d2fe4513ff6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Jan 2011 16:01:16 -0300 Subject: [media] gspca_sonixb: Adjust autoexposure window for vga cams so that it is centered Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 43784027568f..e88097f3d7ed 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1027,7 +1027,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) desired_avg_lum = 5000; } else { deadzone = 1500; - desired_avg_lum = 18000; + desired_avg_lum = 13000; } if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) @@ -1135,7 +1135,7 @@ static int sd_start(struct gspca_dev *gspca_dev) } else { regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */ regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */ - regs[0x1c] = 0x02; /* AE H-start 64 */ + regs[0x1c] = 0x05; /* AE H-start 160 */ regs[0x1d] = 0x03; /* AE V-start 96 */ regs[0x1e] = 0x0f; /* AE H-end 480 */ regs[0x1f] = 0x0c; /* AE V-end 384 */ -- cgit v1.2.3 From 0d0d7ef71ec6ba6abb680478f7d0514584b8277f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Jan 2011 07:55:20 -0300 Subject: [media] gspca_sonixb: Fix TAS5110D sensor gain control Also fix the issue of the image being mirrored. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index e88097f3d7ed..5c8420e5c02e 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -525,10 +525,18 @@ static const __u8 initTas5110d[] = { 0x00, 0x00, 0x00, 0x41, 0x09, 0x0a, 0x16, 0x12, 0x60, 0x86, 0x2b, }; -static const __u8 tas5110_sensor_init[][8] = { +/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */ +static const __u8 tas5110c_sensor_init[][8] = { {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10}, {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10}, - {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, +}; +/* Known TAS5110D registers + * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain + * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted) + * Note: writing reg03 seems to only work when written together with 02 + */ +static const __u8 tas5110d_sensor_init[][8] = { + {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */ }; static const __u8 initTas5130[] = { @@ -552,9 +560,9 @@ SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60), SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21), SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0), SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0), -SENS(initTas5110c, tas5110_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, +SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5110d, tas5110_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, +SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), SENS(initTas5130, tas5130_sensor_init, 0, NO_EXPO|NO_FREQ, 0), }; @@ -705,8 +713,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev) goto err; break; } - case SENSOR_TAS5110C: - case SENSOR_TAS5110D: { + case SENSOR_TAS5110C: { __u8 i2c[] = {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; @@ -715,6 +722,23 @@ static void setsensorgain(struct gspca_dev *gspca_dev) goto err; break; } + case SENSOR_TAS5110D: { + __u8 i2c[] = { + 0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 }; + gain = 255 - gain; + /* The bits in the register are the wrong way around!! */ + i2c[3] |= (gain & 0x80) >> 7; + i2c[3] |= (gain & 0x40) >> 5; + i2c[3] |= (gain & 0x20) >> 3; + i2c[3] |= (gain & 0x10) >> 1; + i2c[3] |= (gain & 0x08) << 1; + i2c[3] |= (gain & 0x04) << 3; + i2c[3] |= (gain & 0x02) << 5; + i2c[3] |= (gain & 0x01) << 7; + if (i2c_w(gspca_dev, i2c) < 0) + goto err; + break; + } case SENSOR_OV6650: gain >>= 1; -- cgit v1.2.3 From 4e17cd2eac2544267bdfab67655be468f80f50c6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Jan 2011 10:58:53 -0300 Subject: [media] gspca_sonixb: TAS5130C brightness control really is a gain control Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 5c8420e5c02e..36253417bde4 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -564,7 +564,8 @@ SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5130, tas5130_sensor_init, 0, NO_EXPO|NO_FREQ, 0), +SENS(initTas5130, tas5130_sensor_init, F_GAIN, + NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), }; /* get one byte in gspca_dev->usb_buf */ @@ -636,7 +637,6 @@ static void i2c_w_vector(struct gspca_dev *gspca_dev, static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 value; switch (sd->sensor) { case SENSOR_OV6650: @@ -678,17 +678,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) goto err; break; } - case SENSOR_TAS5130CXX: { - __u8 i2c[] = - {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; - - value = 0xff - sd->brightness; - i2c[4] = value; - PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]); - if (i2c_w(gspca_dev, i2c) < 0) - goto err; - break; - } } return; err: @@ -713,7 +702,8 @@ static void setsensorgain(struct gspca_dev *gspca_dev) goto err; break; } - case SENSOR_TAS5110C: { + case SENSOR_TAS5110C: + case SENSOR_TAS5130CXX: { __u8 i2c[] = {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; -- cgit v1.2.3 From 69ffd2545766742f7d247770c6ee30a6ed6058ef Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Jan 2011 11:56:30 -0300 Subject: [media] gspca_sonixb: Add usb ids for known sn9c103 cameras Now that our bridge code is unified for sn9c101/102 and sn9c103 models, the sn9c103 models should simply work, given that the only difference in the sn9c103 is audio support and a gamma correction table. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 12 ++++++++---- drivers/media/video/sn9c102/sn9c102_devtable.h | 8 +++----- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 36253417bde4..c20131147604 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1572,8 +1572,8 @@ static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)}, {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, #endif @@ -1584,11 +1584,15 @@ static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, - /* {USB_DEVICE(0x0c45, 0x602b), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */ + /* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */ + /* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */ + {USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)}, + {USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)}, + /* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */ {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)}, + {USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)}, {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, -#endif {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)}, {} }; diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 74bc719b8e89..0e0fcc017fb8 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -47,8 +47,8 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ -#endif { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE @@ -66,15 +66,14 @@ static const struct usb_device_id sn9c102_id_table[] = { /* SN9C103 */ /* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */ { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */ +#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE /* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ /* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */ { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, -#endif /* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */ @@ -84,9 +83,7 @@ static const struct usb_device_id sn9c102_id_table[] = { /* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */ { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, -#endif /* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */ @@ -94,6 +91,7 @@ static const struct usb_device_id sn9c102_id_table[] = { /* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */ +#endif /* SN9C105 */ #if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, -- cgit v1.2.3 From 4944e27d85ed8e5ccd591687546d56d111c5cc98 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Jan 2011 13:05:29 -0300 Subject: [media] gspca_sonixj: Enable more usb ids when sn9c102 gets compiled too Both we and the windows driver make no sensor specific differences (with some exceptions) for different sonixj bridge types. Thus if a sn9c105 bridge has been successfully tested with a sensor, the same sensor can be successfully used with a sn9c120 bridge too. Using this knowledge we can move over most usb-ids too the sonixj driver when both are compiled. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 6 +----- drivers/media/video/sn9c102/sn9c102_devtable.h | 6 ++---- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 2d0bb17a30a2..85716f864cfb 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2908,10 +2908,8 @@ static const struct sd_desc sd_desc = { | (SENSOR_ ## sensor << 8) \ | (flags) static const __devinitdata struct usb_device_id device_table[] = { -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, -#endif {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)}, {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)}, {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)}, @@ -2936,8 +2934,8 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ /* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */ {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)}, #endif {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/ @@ -2962,9 +2960,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */ {USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)}, {USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)}, -#endif {USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)}, {USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)}, {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/ diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 0e0fcc017fb8..97e123672d65 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -107,21 +107,19 @@ static const struct usb_device_id sn9c102_id_table[] = { /* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */ /* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */ { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, -#endif { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, /* SN9C120 */ +#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */ /* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */ /* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */ -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, -#endif { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, #endif -- cgit v1.2.3 From e530a5e3cfe5f2dca35552d2d968f0a3fc115968 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Jan 2011 15:23:55 -0300 Subject: [media] gspca_sonixj: Probe sensor type independent of bridge type Looking at the windows inf file, for usb ids with a sensor type where probing is needed to determine the type (for example ov7630 or soi768), this is needed for all bridge variants with a usb id indicating this sensor type. So do the probing to determine the actual sensor type for types where the usb-id info is not 100% deterministic, independent of the bridge type. If you look through the list of currently active usb ids in sonixj, this effectively only changes the code path for 0c45:60fe (sn9c105 + ov7630) and 0c45:612e (sn9c110 + ov7630), which according to the inf file can have a soi768 instead of a ov7630 just like the sn9c120 + ov7630 models where we already probe for a soi7630. The main reason for this code change is to keep the code paths as bridge variant independent as possible, so that we don't need a lot of special per bridge cases, as we enable more usb-ids in the future. This change makes the 0c45:60fe code path identical to the successfully tested 0c45:613e, so also make sonixj the default driver for 0c45:60fe. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 58 +++++++++++++------------- drivers/media/video/sn9c102/sn9c102_devtable.h | 2 - 2 files changed, 29 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 85716f864cfb..efe3fc7b6b74 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1822,44 +1822,46 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1); switch (sd->bridge) { case BRIDGE_SN9C102P: + case BRIDGE_SN9C105: if (regF1 != 0x11) return -ENODEV; + break; + default: +/* case BRIDGE_SN9C110: */ +/* case BRIDGE_SN9C120: */ + if (regF1 != 0x12) + return -ENODEV; + } + + switch (sd->sensor) { + case SENSOR_MI0360: + mi0360_probe(gspca_dev); + break; + case SENSOR_OV7630: + ov7630_probe(gspca_dev); + break; + case SENSOR_OV7648: + ov7648_probe(gspca_dev); + break; + case SENSOR_PO2030N: + po2030n_probe(gspca_dev); + break; + } + + switch (sd->bridge) { + case BRIDGE_SN9C102P: reg_w1(gspca_dev, 0x02, regGpio[1]); break; case BRIDGE_SN9C105: - if (regF1 != 0x11) - return -ENODEV; - if (sd->sensor == SENSOR_MI0360) - mi0360_probe(gspca_dev); reg_w(gspca_dev, 0x01, regGpio, 2); break; + case BRIDGE_SN9C110: + reg_w1(gspca_dev, 0x02, 0x62); + break; case BRIDGE_SN9C120: - if (regF1 != 0x12) - return -ENODEV; - switch (sd->sensor) { - case SENSOR_MI0360: - mi0360_probe(gspca_dev); - break; - case SENSOR_OV7630: - ov7630_probe(gspca_dev); - break; - case SENSOR_OV7648: - ov7648_probe(gspca_dev); - break; - case SENSOR_PO2030N: - po2030n_probe(gspca_dev); - break; - } regGpio[1] = 0x70; /* no audio */ reg_w(gspca_dev, 0x01, regGpio, 2); break; - default: -/* case BRIDGE_SN9C110: */ -/* case BRIDGE_SN9C325: */ - if (regF1 != 0x12) - return -ENODEV; - reg_w1(gspca_dev, 0x02, 0x62); - break; } if (sd->sensor == SENSOR_OM6802) @@ -2935,9 +2937,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */ {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)}, {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)}, -#endif {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/ {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, /* /GC0305*/ /* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */ diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 97e123672d65..b3d2cc729657 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -108,10 +108,8 @@ static const struct usb_device_id sn9c102_id_table[] = { /* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */ { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, -#endif { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, /* SN9C120 */ -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */ /* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */ -- cgit v1.2.3 From e48d38f7f100f37edc873df1b3a1d15ee3575874 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Jan 2011 16:21:57 -0300 Subject: [media] gspca_sonixj: Add one more commented out usb-id While going through windows inf file I found more usb-id, add a comment with this id for future reference. Signed-off-by: Hans de Goede Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index efe3fc7b6b74..db35391d00e6 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2968,6 +2968,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/ +/* {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */ /*sn9c120b*/ {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3 From 4c775902252b06673cf26a33834842f1fec3fe3e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 7 Jan 2011 07:29:24 -0300 Subject: [media] gspca_sonixb: Fix mirrored image with ov7630 Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index c20131147604..e45d1cfb4461 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -381,7 +381,7 @@ static const __u8 ov7630_sensor_init[][8] = { {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10}, /* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */ - {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */ + {0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10}, /* jfm */ {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10}, {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10}, {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10}, -- cgit v1.2.3 From a1198ccf9c52922e66a3372b0045ebe335a127dd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 Jan 2011 09:53:32 -0300 Subject: [media] v4l2-ioctl: fix incorrect error code if VIDIOC_DBG_G/S_REGISTER are unsupported The ioctls VIDIOC_DBG_S_REGISTER and VIDIOC_DBG_G_REGISTER should return -EINVAL if the driver didn't implement them. Currently they return -EPERM if called as non-root user. However, this check should only be done if the driver actually implemented these ioctls. Otherwise, just return -EINVAL as we do with all unimplemented ioctls. This bug make the v4l2-compliance test suite fail. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ioctl.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 7e47f15f350d..f51327ef6757 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -1659,20 +1659,24 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_dbg_register *p = arg; - if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - else if (ops->vidioc_g_register) - ret = ops->vidioc_g_register(file, fh, p); + if (ops->vidioc_g_register) { + if (!capable(CAP_SYS_ADMIN)) + ret = -EPERM; + else + ret = ops->vidioc_g_register(file, fh, p); + } break; } case VIDIOC_DBG_S_REGISTER: { struct v4l2_dbg_register *p = arg; - if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - else if (ops->vidioc_s_register) - ret = ops->vidioc_s_register(file, fh, p); + if (ops->vidioc_s_register) { + if (!capable(CAP_SYS_ADMIN)) + ret = -EPERM; + else + ret = ops->vidioc_s_register(file, fh, p); + } break; } #endif -- cgit v1.2.3 From 131ddd1a3072aebca666767151acaa7574beb583 Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Sat, 8 Jan 2011 14:12:30 -0300 Subject: [media] radio-si470x: de-emphasis should be set if requested by module parameter instead of always setting de-emphasis. Reported-by: Tobias Lorenz Signed-off-by: Joonyoung Shim Acked-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index ac76dfe5b3fa..35488baf29bd 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -357,7 +357,8 @@ int si470x_start(struct si470x_device *radio) goto done; /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; + radio->registers[SYSCONFIG1] = + (de << 11) & SYSCONFIG1_DE; /* DE*/ retval = si470x_set_register(radio, SYSCONFIG1); if (retval < 0) goto done; -- cgit v1.2.3 From 186a21cb77ffe23397aaea302ab32b510b3e2df4 Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Sat, 8 Jan 2011 16:13:04 -0300 Subject: [media] radio-si470x: Always report support for RDS The si470x i2c and usb driver support the RDS, so this ifdef statement doesn't need more. [mchehab@redhat.com: Fix a conflict on it] Signed-off-by: Joonyoung Shim Acked-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-common.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 35488baf29bd..60c176fe328e 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -688,12 +688,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, /* driver constants */ strcpy(tuner->name, "FM"); tuner->type = V4L2_TUNER_RADIO; -#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; -#else - tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; -#endif /* range limits */ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { @@ -719,12 +715,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, tuner->rxsubchans = V4L2_TUNER_SUB_MONO; else tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) /* If there is a reliable method of detecting an RDS channel, then this code should check for that before setting this RDS subchannel. */ tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; -#endif /* mono/stereo selector */ if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) -- cgit v1.2.3 From 312d63e4b0ca8456c82d01a6446795f7d029ecde Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Jan 2011 12:16:34 -0300 Subject: [media] rc-dib0700-nec: Fix keytable for Pixelview SBTVD dib0700 now outputs NEC extended keycodes. Fix the keytable to reflect that. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-dib0700-nec.c | 52 +++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index c59851b203da..7a5f5300caf9 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -19,35 +19,35 @@ static struct rc_map_table dib0700_nec_table[] = { /* Key codes for the Pixelview SBTVD remote */ - { 0x8613, KEY_MUTE }, - { 0x8612, KEY_POWER }, - { 0x8601, KEY_1 }, - { 0x8602, KEY_2 }, - { 0x8603, KEY_3 }, - { 0x8604, KEY_4 }, - { 0x8605, KEY_5 }, - { 0x8606, KEY_6 }, - { 0x8607, KEY_7 }, - { 0x8608, KEY_8 }, - { 0x8609, KEY_9 }, - { 0x8600, KEY_0 }, - { 0x860d, KEY_CHANNELUP }, - { 0x8619, KEY_CHANNELDOWN }, - { 0x8610, KEY_VOLUMEUP }, - { 0x860c, KEY_VOLUMEDOWN }, + { 0x866b13, KEY_MUTE }, + { 0x866b12, KEY_POWER }, + { 0x866b01, KEY_1 }, + { 0x866b02, KEY_2 }, + { 0x866b03, KEY_3 }, + { 0x866b04, KEY_4 }, + { 0x866b05, KEY_5 }, + { 0x866b06, KEY_6 }, + { 0x866b07, KEY_7 }, + { 0x866b08, KEY_8 }, + { 0x866b09, KEY_9 }, + { 0x866b00, KEY_0 }, + { 0x866b0d, KEY_CHANNELUP }, + { 0x866b19, KEY_CHANNELDOWN }, + { 0x866b10, KEY_VOLUMEUP }, + { 0x866b0c, KEY_VOLUMEDOWN }, - { 0x860a, KEY_CAMERA }, - { 0x860b, KEY_ZOOM }, - { 0x861b, KEY_BACKSPACE }, - { 0x8615, KEY_ENTER }, + { 0x866b0a, KEY_CAMERA }, + { 0x866b0b, KEY_ZOOM }, + { 0x866b1b, KEY_BACKSPACE }, + { 0x866b15, KEY_ENTER }, - { 0x861d, KEY_UP }, - { 0x861e, KEY_DOWN }, - { 0x860e, KEY_LEFT }, - { 0x860f, KEY_RIGHT }, + { 0x866b1d, KEY_UP }, + { 0x866b1e, KEY_DOWN }, + { 0x866b0e, KEY_LEFT }, + { 0x866b0f, KEY_RIGHT }, - { 0x8618, KEY_RECORD }, - { 0x861a, KEY_STOP }, + { 0x866b18, KEY_RECORD }, + { 0x866b1a, KEY_STOP }, /* Key codes for the EvolutePC TVWay+ remote */ { 0x7a00, KEY_MENU }, -- cgit v1.2.3 From 59aa346009c06c6697e9db008e67e4ff8c205091 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Jan 2011 12:17:52 -0300 Subject: [media] dib0700: Fix IR keycode handling Fixes Fedora 14 bug: https://bugzilla.redhat.com/show_bug.cgi?id=667157 There are a few bugs at the code that generates the scancode at dib0700: - RC keycode is wrong (it outputs a 24 bits keycode); - NEC extended outputs a keycode that have endiannes issues; - keycode tables for NEC extended remotes need to be updated. The last issue need to be done as we get reports, as we don't have the complete NEC-extended keycodes at the dibcom table. This patch fixes the first two issues. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 8ca48f76dfa9..98ffb40728e3 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -514,8 +514,8 @@ struct dib0700_rc_response { union { u16 system16; struct { - u8 system; u8 not_system; + u8 system; }; }; u8 data; @@ -575,7 +575,7 @@ static void dib0700_rc_urb_completion(struct urb *purb) if ((poll_reply->system ^ poll_reply->not_system) != 0xff) { deb_data("NEC extended protocol\n"); /* NEC extended code - 24 bits */ - keycode = poll_reply->system16 << 8 | poll_reply->data; + keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data; } else { deb_data("NEC normal protocol\n"); /* normal NEC code - 16 bits */ @@ -587,7 +587,7 @@ static void dib0700_rc_urb_completion(struct urb *purb) deb_data("RC5 protocol\n"); /* RC5 Protocol */ toggle = poll_reply->report_id; - keycode = poll_reply->system16 << 8 | poll_reply->data; + keycode = poll_reply->system << 8 | poll_reply->data; break; } -- cgit v1.2.3 From e6bcb2f324cf28469d2713e86beace07f25596cf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Jan 2011 13:50:01 -0300 Subject: [media] ir-kbd-i2c: Make IR debug messages more useful Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ir-kbd-i2c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index c87b6bc45555..b173e409cd28 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -244,15 +244,17 @@ static void ir_key_poll(struct IR_i2c *ir) static u32 ir_key, ir_raw; int rc; - dprintk(2,"ir_poll_key\n"); + dprintk(3, "%s\n", __func__); rc = ir->get_key(ir, &ir_key, &ir_raw); if (rc < 0) { dprintk(2,"error\n"); return; } - if (rc) + if (rc) { + dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); rc_keydown(ir->rc, ir_key, 0); + } } static void ir_work(struct work_struct *work) -- cgit v1.2.3 From 5a85025f7dabc5b039335a7d1fb5f9002efa9488 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Jan 2011 14:22:42 -0300 Subject: [media] em28xx: Fix IR support for WinTV USB2 Due to a lack of a break inside the switch, it were getting the wrong keytable and get_key function. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 099d5df8c572..ba03a448b41d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2437,6 +2437,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev) dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW; dev->init_data.get_key = em28xx_get_key_em_haup; dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; + break; case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE; dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe; -- cgit v1.2.3 From 567aba0b7997dad5fe3fb4aeb174ee9018df8c5b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Jan 2011 11:58:36 -0300 Subject: [media] tda8290: Make all read operations atomic Read operations should be preceeded by a write operation. However, nothing prevents that an I2C operation could happen between the two transactions. To avoid that problem, use an unique I2C transfer for both parts of the I2C transaction. Cc: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda8290.c | 119 +++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c index c9062ceddc71..5f889c1b91d0 100644 --- a/drivers/media/common/tuners/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -95,8 +95,7 @@ static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) msleep(20); } else { msg = disable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); buf[2] = msg[1]; buf[2] &= ~0x04; @@ -239,13 +238,15 @@ static void tda8290_set_params(struct dvb_frontend *fe, fe->ops.tuner_ops.set_analog_params(fe, params); for (i = 0; i < 3; i++) { - tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, &pll_stat, 1); if (pll_stat & 0x80) { - tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); - tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_adc_sat, 1, + &adc_sat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, + &agc_stat, 1); tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); break; } else { @@ -259,20 +260,22 @@ static void tda8290_set_params(struct dvb_frontend *fe, agc_stat, adc_sat, pll_stat & 0x80); tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); msleep(100); - tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); - tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, &pll_stat, 1); if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->cfg.agcf) priv->cfg.agcf(fe); msleep(100); - tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); - tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_agc_stat, 1, + &agc_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, + &pll_stat, 1); if((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); @@ -284,10 +287,12 @@ static void tda8290_set_params(struct dvb_frontend *fe, /* l/ l' deadlock? */ if(priv->tda8290_easy_mode & 0x60) { - tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); - tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_adc_sat, 1, + &adc_sat, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &addr_pll_stat, 1, + &pll_stat, 1); if ((adc_sat > 20) || !(pll_stat & 0x80)) { tuner_dbg("trying to resolve SECAM L deadlock\n"); tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); @@ -307,8 +312,7 @@ static void tda8295_power(struct dvb_frontend *fe, int enable) struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ - tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); if (enable) buf[1] = 0x01; @@ -323,8 +327,7 @@ static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x01, 0x00 }; - tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); if (enable) buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ @@ -353,8 +356,7 @@ static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ - tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); if (enable) buf[1] &= ~0x40; @@ -370,10 +372,10 @@ static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) unsigned char set_gpio_cf[] = { 0x44, 0x00 }; unsigned char set_gpio_val[] = { 0x46, 0x00 }; - tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); - tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &set_gpio_val[0], 1, &set_gpio_val[1], 1); set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ @@ -392,8 +394,7 @@ static int tda8295_has_signal(struct dvb_frontend *fe) unsigned char hvpll_stat = 0x26; unsigned char ret; - tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); return (ret & 0x01) ? 65535 : 0; } @@ -413,8 +414,8 @@ static void tda8295_set_params(struct dvb_frontend *fe, tda8295_power(fe, 1); tda8295_agc1_out(fe, 1); - tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + &blanking_mode[0], 1, &blanking_mode[1], 1); tda8295_set_video_std(fe); @@ -447,8 +448,8 @@ static int tda8290_has_signal(struct dvb_frontend *fe) unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; - tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); + tuner_i2c_xfer_send_recv(&priv->i2c_props, + i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); return (afc & 0x80)? 65535:0; } @@ -654,20 +655,26 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) static int tda8290_probe(struct tuner_i2c_props *i2c_props) { #define TDA8290_ID 0x89 - unsigned char tda8290_id[] = { 0x1f, 0x00 }; + u8 reg = 0x1f, id; + struct i2c_msg msg_read[] = { + { .addr = 0x4b, .flags = 0, .len = 1, .buf = ® }, + { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id }, + }; /* detect tda8290 */ - tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1); - tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); + if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { + printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n", + __func__, reg); + return -ENODEV; + } - if (tda8290_id[1] == TDA8290_ID) { + if (id == TDA8290_ID) { if (debug) printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", __func__, i2c_adapter_id(i2c_props->adap), i2c_props->addr); return 0; } - return -ENODEV; } @@ -675,16 +682,23 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) { #define TDA8295_ID 0x8a #define TDA8295C2_ID 0x8b - unsigned char tda8295_id[] = { 0x2f, 0x00 }; + u8 reg = 0x2f, id; + struct i2c_msg msg_read[] = { + { .addr = 0x4b, .flags = 0, .len = 1, .buf = ® }, + { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id }, + }; - /* detect tda8295 */ - tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1); - tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); + /* detect tda8290 */ + if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { + printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n", + __func__, reg); + return -ENODEV; + } - if ((tda8295_id[1] & 0xfe) == TDA8295_ID) { + if ((id & 0xfe) == TDA8295_ID) { if (debug) printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", - __func__, (tda8295_id[1] == TDA8295_ID) ? + __func__, (id == TDA8295_ID) ? "tda8295c1" : "tda8295c2", i2c_adapter_id(i2c_props->adap), i2c_props->addr); @@ -809,8 +823,8 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) int i; /* rule out tda9887, which would return the same byte repeatedly */ - tuner_i2c_xfer_send(&i2c_props, soft_reset, 1); - tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE); + tuner_i2c_xfer_send_recv(&i2c_props, + soft_reset, 1, buf, PROBE_BUFFER_SIZE); for (i = 1; i < PROBE_BUFFER_SIZE; i++) { if (buf[i] != buf[0]) break; @@ -827,13 +841,12 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) /* fall back to old probing method */ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); - tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); - tuner_i2c_xfer_recv(&i2c_props, &data, 1); + tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); if (data == 0) { tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); - tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); - tuner_i2c_xfer_recv(&i2c_props, &data, 1); + tuner_i2c_xfer_send_recv(&i2c_props, + &addr_dto_lsb, 1, &data, 1); if (data == 0x7b) { return 0; } -- cgit v1.2.3 From 47ab285a960ac456506297c93322ab13c3522f5a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Jan 2011 12:02:00 -0300 Subject: [media] tda8290: Fix a bug if no tuner is detected If tda8290 is detected, but no tuner is found, the driver will do bad things: tuner 2-0060: chip found @ 0xc0 (saa7133[0]) tda829x 2-0060: could not clearly identify tuner address, defaulting to 60 tda829x 2-0060: tuner access failed! BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] set_audio+0x47/0x170 [tda8290] PGD 1187b0067 PUD 11771e067 PMD 0 Oops: 0002 [#1] SMP last sysfs file: /sys/module/i2c_core/initstate CPU 0 Modules linked in: tda8290(U) tea5767(U) tuner(U) ir_lirc_codec(U) lirc_dev(U) ir_sony_decoder(U) ir_jvc_decoder(U) ir_rc6_decoder(U) ir_rc5_decoder(U) saa7134(+)(U) v4l2_common(U) ir_nec_decoder(U) videodev(U) v4l2_compat_ioctl32(U) rc_core(U) videobuf_dma_sg(U) videobuf_core(U) tveeprom(U) ebtable_nat ebtables xt_CHECKSUM iptable_mangle ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT bridge stp llc autofs4 sunrpc cpufreq_ondemand acpi_cpufreq freq_table xt_physdev iptable_filter ip_tables ip6t_REJECT ip6table_filter ip6_tables ipv6 dm_mirror dm_region_hash dm_log parport kvm_intel kvm uinput floppy tpm_infineon wmi sg serio_raw iTCO_wdt iTCO_vendor_support tg3 snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore snd_page_alloc i7core_edac edac_core nouveau Modules linked in: tda8290(U) tea5767(U) tuner(U) ir_lirc_codec(U) lirc_dev(U) ir_sony_decoder(U) ir_jvc_decoder(U) ir_rc6_decoder(U) ir_rc5_decoder(U) saa7134(+)(U) v4l2_common(U) ir_nec_decoder(U) videodev(U) v4l2_compat_ioctl32(U) rc_core(U) videobuf_dma_sg(U) videobuf_core(U) tveeprom(U) ebtable_nat ebtables xt_CHECKSUM iptable_mangle ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT bridge stp llc autofs4 sunrpc cpufreq_ondemand acpi_cpufreq freq_table xt_physdev iptable_filter ip_tables ip6t_REJECT ip6table_filter ip6_tables ipv6 dm_mirror dm_region_hash dm_log parport kvm_intel kvm uinput floppy tpm_infineon wmi sg serio_raw iTCO_wdt iTCO_vendor_support tg3 snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore snd_page_alloc i7core_edac edac_core nouveau ttm drm_kms_helper drm i2c_algo_bit video output i2c_core ext3 jbd mbcache firewire_ohci firewire_core crc_itu_t sr_mod cdrom sd_mod crc_t10dif ahci dm_mod [last unloaded: microcode] Pid: 9497, comm: modprobe Not tainted 2.6.32-72.el6.x86_64 #1 HP Z400 Workstation RIP: 0010:[] [] set_audio+0x47/0x170 [tda8290] RSP: 0018:ffff88010ba01b28 EFLAGS: 00010206 RAX: 00000000000000ff RBX: ffff880119522800 RCX: 0000000000000002 RDX: 0000000000003be0 RSI: ffff88010ba01bb8 RDI: 0000000000000000 RBP: ffff88010ba01b28 R08: 0000000000000002 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: ffff88010ba01bb8 R14: 0000000000001900 R15: 0000000000001900 FS: 00007f4b96b3d700(0000) GS:ffff880028200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000020 CR3: 000000011866c000 CR4: 00000000000026f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process modprobe (pid: 9497, threadinfo ffff88010ba00000, task ffff880100708a70) Stack: ffff88010ba01b98 ffffffffa048c95b ffff88010ba01b78 0000000000000060 <0> 0000000000000000 0000000e00000000 000000000000001d ffffffffa03ec838 <0> ffff88010abac240 ffff880119522800 ffff880119522800 ffff880119522bc0 Call Trace: [] tda8295_set_params+0x3b/0x210 [tda8290] [] ? v4l2_i2c_new_subdev_cfg+0x88/0xc0 [v4l2_common] [] set_freq+0x128/0x2f0 [tuner] [] tuner_s_std+0xc4/0x740 [tuner] [] saa7134_set_tvnorm_hw+0x2d6/0x3d0 [saa7134] [] set_tvnorm+0xd5/0x100 [saa7134] [] saa7134_video_init2+0x1d/0x50 [saa7134] [] saa7134_initdev+0x6e1/0xb1d [saa7134] [] ? kobject_get+0x1a/0x30 [] local_pci_probe+0x17/0x20 [] pci_device_probe+0x101/0x120 [] ? driver_sysfs_add+0x62/0x90 [] driver_probe_device+0xa0/0x2a0 [] __driver_attach+0xab/0xb0 [] ? __driver_attach+0x0/0xb0 [] bus_for_each_dev+0x64/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0x200/0x300 [] driver_register+0x76/0x140 [] ? printk+0x41/0x46 [] __pci_register_driver+0x56/0xd0 [] ? saa7134_init+0x0/0x4f [saa7134] [] saa7134_init+0x4d/0x4f [saa7134] [] do_one_initcall+0x3c/0x1d0 [] sys_init_module+0xdf/0x250 [] system_call_fastpath+0x16/0x1b Code: 20 01 49 c7 c0 c9 ec 48 a0 83 7e 04 01 74 2d 8b 0d 3f 2f 00 00 85 c9 0f 85 d7 00 00 00 c9 c3 0f 1f 44 00 00 a9 03 00 01 00 74 61 47 20 02 83 7e 04 01 49 c7 c0 cc ec 48 a0 75 d3 0f b6 47 22 RIP [] set_audio+0x47/0x170 [tda8290] RSP CR2: 0000000000000020 This happens because some I2C callbacks actually depend on having the driver entirely initialized. To avoid this OOPS, just clean the I2C callbacks, as if no device were detected. Cc: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda8290.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c index 5f889c1b91d0..11ea4e0f9c04 100644 --- a/drivers/media/common/tuners/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -755,8 +755,11 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, } if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) && - (tda829x_find_tuner(fe) < 0)) + (tda829x_find_tuner(fe) < 0)) { + memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); + goto fail; + } switch (priv->ver) { case TDA8290: -- cgit v1.2.3 From 9d700a0696ae241380e8ca833bb5a358620d33f6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Jan 2011 14:01:39 -0300 Subject: [media] tda8290: Turn tda829x on before touching at the I2C gate On Kworld SBTVD, tda8295-c1 starts in power off mode. It needs to be powered, otherwise, the I2C gate control command won't work. Cc: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda8290.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c index 11ea4e0f9c04..419d064a0188 100644 --- a/drivers/media/common/tuners/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -754,11 +754,10 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, sizeof(struct analog_demod_ops)); } - if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) && - (tda829x_find_tuner(fe) < 0)) { - memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); - - goto fail; + if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { + tda8295_power(fe, 1); + if (tda829x_find_tuner(fe) < 0) + goto fail; } switch (priv->ver) { @@ -803,6 +802,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, return fe; fail: + memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); + tda829x_release(fe); return NULL; } -- cgit v1.2.3 From 7570800c9de39c718f84ec4ea820a788556cde4b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Jan 2011 08:50:00 -0300 Subject: [media] mb86a20s: Fix i2c read/write error messages A script replaced err var to rc. Howerver, this script gambled "error" string, changing it to "rcor". Revert that bad change. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mb86a20s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c index d3ad3e75a35a..e06507d2c3b2 100644 --- a/drivers/media/dvb/frontends/mb86a20s.c +++ b/drivers/media/dvb/frontends/mb86a20s.c @@ -318,7 +318,7 @@ static int mb86a20s_i2c_writereg(struct mb86a20s_state *state, rc = i2c_transfer(state->i2c, &msg, 1); if (rc != 1) { - printk("%s: writereg rcor(rc == %i, reg == 0x%02x," + printk("%s: writereg error (rc == %i, reg == 0x%02x," " data == 0x%02x)\n", __func__, rc, reg, data); return rc; } @@ -353,7 +353,7 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state, rc = i2c_transfer(state->i2c, msg, 2); if (rc != 2) { - rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc); + rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc); return rc; } -- cgit v1.2.3 From c736a5f28e81299b05ad14e892bdfb414daa9f5f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Jan 2011 11:10:05 -0300 Subject: [media] mb86a20s: Be sure that device is initialized before starting DVB Due to a hard to track bug between tda829x/tda18271/saa7134, tda829x wants to go to analog mode during DVB initialization, causing some I2C errors. The analog failure doesn't cause any harm, as the device were already properly initialized in analog mode. However, the failure at the digital mode causes the frontend mb86a20s to not initialize. Fortunately, at least on my tests, it was possible to detect that the device is a mb86a20s before the failure. What happens is that tda8290 is a very bad boy: during DVB setup, it keeps insisting to call tda18271 analog_set_params, that calls tune_agc code. The tune_agc code calls saa7134 driver, changing the value of GPIO 27, switching from digital to analog mode and disabling the access to mb86a20s, as, on Kworld SBTVD, the same GPIO used to switch the hardware AGC mode seems to be used to enable the I2C switch that allows access to the frontend (mb86a20s). So, a call to analog_set_params ultimately disables the access to the frontend, and causes a failure at the init frontend logic. This patch is a workaround for this issue: it simply checks if the frontend init had any failure. If so, it will init the frontend when some DTV application will try to set DVB mode. Even being a hack for Kworld SBTVD to work, and assumning that we could teach tda8290 to be a good boy, this is actually an improvement at the frontend driver, as it will be more reliable to initialization failures. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mb86a20s.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c index e06507d2c3b2..cc4acd2f920d 100644 --- a/drivers/media/dvb/frontends/mb86a20s.c +++ b/drivers/media/dvb/frontends/mb86a20s.c @@ -43,6 +43,8 @@ struct mb86a20s_state { const struct mb86a20s_config *config; struct dvb_frontend frontend; + + bool need_init; }; struct regdata { @@ -382,23 +384,31 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) /* Initialize the frontend */ rc = mb86a20s_writeregdata(state, mb86a20s_init); if (rc < 0) - return rc; + goto err; if (!state->config->is_serial) { regD5 &= ~1; rc = mb86a20s_writereg(state, 0x50, 0xd5); if (rc < 0) - return rc; + goto err; rc = mb86a20s_writereg(state, 0x51, regD5); if (rc < 0) - return rc; + goto err; } if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - return 0; +err: + if (rc < 0) { + state->need_init = true; + printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n"); + } else { + state->need_init = false; + dprintk("Initialization succeded.\n"); + } + return rc; } static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength) @@ -485,8 +495,22 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + dprintk("Calling tuner set parameters\n"); fe->ops.tuner_ops.set_params(fe, p); + /* + * Make it more reliable: if, for some reason, the initial + * device initialization doesn't happen, initialize it when + * a SBTVD parameters are adjusted. + * + * Unfortunately, due to a hard to track bug at tda829x/tda18271, + * the agc callback logic is not called during DVB attach time, + * causing mb86a20s to not be initialized with Kworld SBTVD. + * So, this hack is needed, in order to make Kworld SBTVD to work. + */ + if (state->need_init) + mb86a20s_initfe(fe); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception); -- cgit v1.2.3 From 6183040680c56ec4bd3d7c9398cbc05e84d60c1f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Jan 2011 14:24:44 -0300 Subject: [media] saa7134: Fix analog mode for Kworld SBTVD There were some issues at tda8290 that were preventing this device to work. Now that those fixes were fixed, we can enable analog mode. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 40 +++-------------------------- drivers/media/video/saa7134/saa7134-dvb.c | 40 +---------------------------- 2 files changed, 4 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index e7aa588c6c5a..b2426000e1d8 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5179,18 +5179,8 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = { .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid", .audio_clock = 0x00187de7, -#if 0 - /* - * FIXME: Analog mode doesn't work, if digital is enabled. The proper - * fix is to use tda8290 driver, but Kworld seems to use an - * unsupported version of tda8295. - */ - .tuner_type = TUNER_NXP_TDA18271, /* TUNER_PHILIPS_TDA8290 */ - .tuner_addr = 0x60, -#else - .tuner_type = UNSET, + .tuner_type = TUNER_PHILIPS_TDA8290, .tuner_addr = ADDR_UNSET, -#endif .radio_type = UNSET, .radio_addr = ADDR_UNSET, .gpiomask = 0x8e054000, @@ -5201,6 +5191,7 @@ struct saa7134_board saa7134_boards[] = { .vmux = 1, .amux = TV, .tv = 1, + .gpio = 0x4000, #if 0 /* FIXME */ }, { .name = name_comp1, @@ -7659,36 +7650,11 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; } case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - { - struct i2c_msg msg = { .addr = 0x4b, .flags = 0 }; - int i; - static u8 buffer[][2] = { - {0x30, 0x31}, - {0xff, 0x00}, - {0x41, 0x03}, - {0x41, 0x1a}, - {0xff, 0x02}, - {0x34, 0x00}, - {0x45, 0x97}, - {0x45, 0xc1}, - }; saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000); saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000); - /* - * FIXME: identify what device is at addr 0x4b and what means - * this initialization - */ - for (i = 0; i < ARRAY_SIZE(buffer); i++) { - msg.buf = &buffer[i][0]; - msg.len = ARRAY_SIZE(buffer[0]); - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable tuner(%i).\n", - dev->name, i); - } + saa7134_set_gpio(dev, 27, 0); break; - } } /* switch() */ /* initialize tuner */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 3315a48a848b..064bf2cd5f21 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -236,7 +236,7 @@ static struct tda18271_std_map mb86a20s_tda18271_std_map = { static struct tda18271_config kworld_tda18271_config = { .std_map = &mb86a20s_tda18271_std_map, - .gate = TDA18271_GATE_DIGITAL, + .gate = TDA18271_GATE_ANALOG, }; static const struct mb86a20s_config kworld_mb86a20s_config = { @@ -623,37 +623,6 @@ static struct tda827x_config tda827x_cfg_2_sw42 = { /* ------------------------------------------------------------------ */ -static int __kworld_sbtvd_i2c_gate_ctrl(struct saa7134_dev *dev, int enable) -{ - unsigned char initmsg[] = {0x45, 0x97}; - unsigned char msg_enable[] = {0x45, 0xc1}; - unsigned char msg_disable[] = {0x45, 0x81}; - struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2}; - - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); - return -EIO; - } - if (enable) - msg.buf = msg_enable; - else - msg.buf = msg_disable; - if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); - return -EIO; - } - msleep(20); - return 0; -} -static int kworld_sbtvd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct saa7134_dev *dev = fe->dvb->priv; - - return __kworld_sbtvd_i2c_gate_ctrl(dev, enable); -} - -/* ------------------------------------------------------------------ */ - static struct tda1004x_config tda827x_lifeview_config = { .demod_address = 0x08, .invert = 1, @@ -1660,7 +1629,6 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - __kworld_sbtvd_i2c_gate_ctrl(dev, 0); saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000); saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000); msleep(20); @@ -1670,16 +1638,10 @@ static int dvb_init(struct saa7134_dev *dev) fe0->dvb.frontend = dvb_attach(mb86a20s_attach, &kworld_mb86a20s_config, &dev->i2c_adap); - __kworld_sbtvd_i2c_gate_ctrl(dev, 1); if (fe0->dvb.frontend != NULL) { dvb_attach(tda18271_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, &kworld_tda18271_config); - /* - * Only after success, it can initialize the gate, otherwise - * an OOPS will hit, due to kfree(fe0->dvb.frontend) - */ - fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_i2c_gate_ctrl; } break; default: -- cgit v1.2.3 From 6a58bc0f506c1825cb8f8b81a5123e26bf70902c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Jan 2011 09:11:21 -0300 Subject: [media] saa7134: Fix digital mode on Kworld SBTVD This patch fixes digital mode on Kworld SBTVD. Unfortunately, it disables analog mode. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 5 +++- drivers/media/video/saa7134/saa7134-dvb.c | 38 ++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index b2426000e1d8..dea90a19043f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5179,7 +5179,11 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = { .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid", .audio_clock = 0x00187de7, +#if 0 .tuner_type = TUNER_PHILIPS_TDA8290, +#else + .tuner_type = UNSET, +#endif .tuner_addr = ADDR_UNSET, .radio_type = UNSET, .radio_addr = ADDR_UNSET, @@ -5191,7 +5195,6 @@ struct saa7134_board saa7134_boards[] = { .vmux = 1, .amux = TV, .tv = 1, - .gpio = 0x4000, #if 0 /* FIXME */ }, { .name = name_comp1, diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 064bf2cd5f21..d2a12df28af0 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -236,13 +236,38 @@ static struct tda18271_std_map mb86a20s_tda18271_std_map = { static struct tda18271_config kworld_tda18271_config = { .std_map = &mb86a20s_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, + .gate = TDA18271_GATE_DIGITAL, }; static const struct mb86a20s_config kworld_mb86a20s_config = { .demod_address = 0x10, }; +static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct saa7134_dev *dev = fe->dvb->priv; + + unsigned char initmsg[] = {0x45, 0x97}; + unsigned char msg_enable[] = {0x45, 0xc1}; + unsigned char msg_disable[] = {0x45, 0x81}; + struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2}; + + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { + wprintk("could not access the I2C gate\n"); + return -EIO; + } + if (enable) + msg.buf = msg_enable; + else + msg.buf = msg_disable; + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { + wprintk("could not access the I2C gate\n"); + return -EIO; + } + msleep(20); + return 0; +} + /* ================================================================== * tda1004x based DVB-T cards, helper functions */ @@ -1639,10 +1664,21 @@ static int dvb_init(struct saa7134_dev *dev) &kworld_mb86a20s_config, &dev->i2c_adap); if (fe0->dvb.frontend != NULL) { +#if 0 + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_adap, 0x4b, + &tda829x_no_probe); +#else + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_adap, 0x4b, NULL); +#endif dvb_attach(tda18271_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, &kworld_tda18271_config); + fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl; } + + /* mb86a20s need to use the I2C gateway */ break; default: wprintk("Huh? unknown DVB card?\n"); -- cgit v1.2.3 From ecb71d262b0323981e07ce415da9b7adc917990a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Jan 2011 12:03:03 -0300 Subject: [media] saa7134: Kworld SBTVD: make both analog and digital to work There are some weird bugs at tda8290/tda18271 initialization, as it insits do do analog initialization during DVB frontend attach: DVB: registering new adapter (saa7133[0]) DVB: registering adapter 0 frontend 0 (Fujitsu mb86A20s)... mb86a20s: mb86a20s_initfe tda18271_write_regs: [2-0060|M] ERROR: idx = 0x5, len = 1, i2c_transfer returned: -5 tda18271_init: [2-0060|M] error -5 on line 830 tda18271_tune: [2-0060|M] error -5 on line 908 tda18271_write_regs tda18271_write_regs: [2-0060|M] ERROR: idx = 0x5, len = 1, i2c_transfer returned: -5 tda18271c2_rf_tracking_filters_correction: [2-0060|M] error -5 on line 265 tda18271_write_regs tda18271_write_regs: [2-0060|M] ERROR: idx = 0x25, len = 1, i2c_transfer returned: -5 tda18271_channel_configuration: [2-0060|M] error -5 on line 119 tda18271_set_analog_params: [2-0060|M] error -5 on line 1045 tda18271_set_analog_params: [2-0060|M] error -5 on line 1045 tda829x 2-004b: tda8295 not locked, no signal? tda829x 2-004b: tda8295_i2c_bridge: disable i2c gate tda829x 2-004b: tda8295 not locked, no signal? tda829x 2-004b: tda8295_i2c_bridge: disable i2c gate mb86a20s_i2c_writereg: writereg error (rc == -5, reg == 0x29, data == 0x33) mb86a20s: Init failed. Will try again later The problem is that mb86a20s is only visible if the analog part is disabled. However, due to a trick at mb86a20s, it will later initialize properly: mb86a20s: mb86a20s_initfe: Initialization succeded. This is hacky and ugly. However, I coldn't find any easy way to fix it. A proper fix would be to have a resource locking schema, used by both V4L and DVB parts that would block access to analog registers while digital registers are in use, but this will probably put tda829x into a dead lock. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda8290.c | 1 + drivers/media/video/saa7134/saa7134-cards.c | 16 ++++++++++------ drivers/media/video/saa7134/saa7134-dvb.c | 16 +++++----------- 3 files changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c index 419d064a0188..bc6a67768af1 100644 --- a/drivers/media/common/tuners/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -232,6 +232,7 @@ static void tda8290_set_params(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); } + tda8290_i2c_bridge(fe, 1); if (fe->ops.tuner_ops.set_analog_params) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index dea90a19043f..deb8fcf4aa49 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5179,11 +5179,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = { .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid", .audio_clock = 0x00187de7, -#if 0 .tuner_type = TUNER_PHILIPS_TDA8290, -#else - .tuner_type = UNSET, -#endif .tuner_addr = ADDR_UNSET, .radio_type = UNSET, .radio_addr = ADDR_UNSET, @@ -6926,10 +6922,17 @@ static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev, /* toggle AGC switch through GPIO 27 */ switch (mode) { case TDA18271_ANALOG: - saa7134_set_gpio(dev, 27, 0); + saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000); + saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000); + msleep(20); break; case TDA18271_DIGITAL: - saa7134_set_gpio(dev, 27, 1); + saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000); + saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000); + msleep(20); + saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000); + saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000); + msleep(30); break; default: return -EINVAL; @@ -6987,6 +6990,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, int saa7134_tuner_callback(void *priv, int component, int command, int arg) { struct saa7134_dev *dev = priv; + if (dev != NULL) { switch (dev->tuner_type) { case TUNER_PHILIPS_TDA8290: diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index d2a12df28af0..f65cad287b83 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -237,6 +237,8 @@ static struct tda18271_std_map mb86a20s_tda18271_std_map = { static struct tda18271_config kworld_tda18271_config = { .std_map = &mb86a20s_tda18271_std_map, .gate = TDA18271_GATE_DIGITAL, + .config = 3, /* Use tuner callback for AGC */ + }; static const struct mb86a20s_config kworld_mb86a20s_config = { @@ -1654,24 +1656,16 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000); - saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000); - msleep(20); - saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000); - saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000); - msleep(20); + /* Switch to digital mode */ + saa7134_tuner_callback(dev, 0, + TDA18271_CALLBACK_CMD_AGC_ENABLE, 1); fe0->dvb.frontend = dvb_attach(mb86a20s_attach, &kworld_mb86a20s_config, &dev->i2c_adap); if (fe0->dvb.frontend != NULL) { -#if 0 dvb_attach(tda829x_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x4b, &tda829x_no_probe); -#else - dvb_attach(tda829x_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x4b, NULL); -#endif dvb_attach(tda18271_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, &kworld_tda18271_config); -- cgit v1.2.3 From 3c7c9370fb645f4713e0fbbe69425d8db9b47a13 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 Jan 2011 07:08:02 -0300 Subject: [media] v4l2-subdev: remove core.s_config and v4l2_i2c_new_subdev_cfg() The core.s_config op was meant for legacy drivers that needed to work with old pre-2.6.26 kernels. This is no longer relevant. Unfortunately, this op was incorrectly called from several drivers. Replace those occurences with proper i2c_board_info structs and call v4l2_i2c_new_subdev_board. After these changes v4l2_i2c_new_subdev_cfg() was no longer used, so remove that function as well. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 11 +++-- drivers/media/video/cx25840/cx25840-core.c | 22 +++------ drivers/media/video/em28xx/em28xx-cards.c | 18 ++++---- drivers/media/video/ivtv/ivtv-i2c.c | 9 +++- drivers/media/video/mt9v011.c | 54 ++++++++++++++-------- drivers/media/video/mt9v011.h | 36 --------------- drivers/media/video/ov7670.c | 74 +++++++++++++----------------- drivers/media/video/sr030pc30.c | 10 ---- drivers/media/video/v4l2-common.c | 19 +------- include/media/mt9v011.h | 17 +++++++ include/media/v4l2-common.h | 13 +----- include/media/v4l2-subdev.h | 6 +-- 12 files changed, 118 insertions(+), 171 deletions(-) delete mode 100644 drivers/media/video/mt9v011.h create mode 100644 include/media/mt9v011.h (limited to 'drivers') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 49f1b8f1418e..55ffd60ffa7f 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -2001,6 +2001,11 @@ static int cafe_pci_probe(struct pci_dev *pdev, .min_width = 320, .min_height = 240, }; + struct i2c_board_info ov7670_info = { + .type = "ov7670", + .addr = 0x42, + .platform_data = &sensor_cfg, + }; /* * Start putting together one of our big camera structures. @@ -2062,9 +2067,9 @@ static int cafe_pci_probe(struct pci_dev *pdev, if (dmi_check_system(olpc_xo1_dmi)) sensor_cfg.clock_speed = 45; - cam->sensor_addr = 0x42; - cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter, - "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL); + cam->sensor_addr = ov7670_info.addr; + cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter, + &ov7670_info, NULL); if (cam->sensor == NULL) { ret = -ENODEV; goto out_smbus; diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index f16461844c5c..6fc09dd41b9d 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1682,20 +1682,6 @@ static int cx25840_log_status(struct v4l2_subdev *sd) return 0; } -static int cx25840_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (platform_data) { - struct cx25840_platform_data *pdata = platform_data; - - state->pvr150_workaround = pdata->pvr150_workaround; - set_input(client, state->vid_input, state->aud_input); - } - return 0; -} - static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled) { @@ -1787,7 +1773,6 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { static const struct v4l2_subdev_core_ops cx25840_core_ops = { .log_status = cx25840_log_status, - .s_config = cx25840_s_config, .g_chip_ident = cx25840_g_chip_ident, .g_ctrl = v4l2_subdev_g_ctrl, .s_ctrl = v4l2_subdev_s_ctrl, @@ -1974,7 +1959,6 @@ static int cx25840_probe(struct i2c_client *client, state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; - state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; state->vbi_line_offset = 8; state->id = id; @@ -2034,6 +2018,12 @@ static int cx25840_probe(struct i2c_client *client, v4l2_ctrl_cluster(2, &state->volume); v4l2_ctrl_handler_setup(&state->hdl); + if (client->dev.platform_data) { + struct cx25840_platform_data *pdata = client->dev.platform_data; + + state->pvr150_workaround = pdata->pvr150_workaround; + } + cx25840_ir_probe(sd); return 0; } diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index ba03a448b41d..87f77a34eeab 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1917,11 +1918,6 @@ static unsigned short tvp5150_addrs[] = { I2C_CLIENT_END }; -static unsigned short mt9v011_addrs[] = { - 0xba >> 1, - I2C_CLIENT_END -}; - static unsigned short msp3400_addrs[] = { 0x80 >> 1, 0x88 >> 1, @@ -2624,11 +2620,17 @@ void em28xx_card_setup(struct em28xx *dev) "tvp5150", 0, tvp5150_addrs); if (dev->em28xx_sensor == EM28XX_MT9V011) { + struct mt9v011_platform_data pdata; + struct i2c_board_info mt9v011_info = { + .type = "mt9v011", + .addr = 0xba >> 1, + .platform_data = &pdata, + }; struct v4l2_subdev *sd; - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "mt9v011", 0, mt9v011_addrs); - v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal); + pdata.xtal = dev->sensor_xtal; + sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, + &mt9v011_info, NULL); } diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index e103b8fc7452..9fb86a081c0f 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -300,10 +300,15 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) adap, type, 0, I2C_ADDRS(hw_addrs[idx])); } else if (hw == IVTV_HW_CX25840) { struct cx25840_platform_data pdata; + struct i2c_board_info cx25840_info = { + .type = "cx25840", + .addr = hw_addrs[idx], + .platform_data = &pdata, + }; pdata.pvr150_workaround = itv->pvr150_workaround; - sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev, - adap, type, 0, &pdata, hw_addrs[idx], NULL); + sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, + &cx25840_info, NULL); } else { sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, hw_addrs[idx], NULL); diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 209ff97261a9..4904d25f689f 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -12,17 +12,41 @@ #include #include #include -#include "mt9v011.h" +#include MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); - static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-2)"); +#define R00_MT9V011_CHIP_VERSION 0x00 +#define R01_MT9V011_ROWSTART 0x01 +#define R02_MT9V011_COLSTART 0x02 +#define R03_MT9V011_HEIGHT 0x03 +#define R04_MT9V011_WIDTH 0x04 +#define R05_MT9V011_HBLANK 0x05 +#define R06_MT9V011_VBLANK 0x06 +#define R07_MT9V011_OUT_CTRL 0x07 +#define R09_MT9V011_SHUTTER_WIDTH 0x09 +#define R0A_MT9V011_CLK_SPEED 0x0a +#define R0B_MT9V011_RESTART 0x0b +#define R0C_MT9V011_SHUTTER_DELAY 0x0c +#define R0D_MT9V011_RESET 0x0d +#define R1E_MT9V011_DIGITAL_ZOOM 0x1e +#define R20_MT9V011_READ_MODE 0x20 +#define R2B_MT9V011_GREEN_1_GAIN 0x2b +#define R2C_MT9V011_BLUE_GAIN 0x2c +#define R2D_MT9V011_RED_GAIN 0x2d +#define R2E_MT9V011_GREEN_2_GAIN 0x2e +#define R35_MT9V011_GLOBAL_GAIN 0x35 +#define RF1_MT9V011_CHIP_ENABLE 0xf1 + +#define MT9V011_VERSION 0x8232 +#define MT9V011_REV_B_VERSION 0x8243 + /* supported controls */ static struct v4l2_queryctrl mt9v011_qctrl[] = { { @@ -469,23 +493,6 @@ static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data) -{ - struct mt9v011 *core = to_mt9v011(sd); - unsigned *xtal = data; - - v4l2_dbg(1, debug, sd, "s_config called\n"); - - if (xtal) { - core->xtal = *xtal; - v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n", - *xtal / 1000000, (*xtal / 1000) % 1000); - } - - return 0; -} - - #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9v011_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -536,7 +543,6 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { .g_ctrl = mt9v011_g_ctrl, .s_ctrl = mt9v011_s_ctrl, .reset = mt9v011_reset, - .s_config = mt9v011_s_config, .g_chip_ident = mt9v011_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9v011_g_register, @@ -596,6 +602,14 @@ static int mt9v011_probe(struct i2c_client *c, core->height = 480; core->xtal = 27000000; /* Hz */ + if (c->dev.platform_data) { + struct mt9v011_platform_data *pdata = c->dev.platform_data; + + core->xtal = pdata->xtal; + v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n", + core->xtal / 1000000, (core->xtal / 1000) % 1000); + } + v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n", c->addr << 1, c->adapter->name, version); diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h deleted file mode 100644 index 3350fd6083c3..000000000000 --- a/drivers/media/video/mt9v011.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor - * - * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#ifndef MT9V011_H_ -#define MT9V011_H_ - -#define R00_MT9V011_CHIP_VERSION 0x00 -#define R01_MT9V011_ROWSTART 0x01 -#define R02_MT9V011_COLSTART 0x02 -#define R03_MT9V011_HEIGHT 0x03 -#define R04_MT9V011_WIDTH 0x04 -#define R05_MT9V011_HBLANK 0x05 -#define R06_MT9V011_VBLANK 0x06 -#define R07_MT9V011_OUT_CTRL 0x07 -#define R09_MT9V011_SHUTTER_WIDTH 0x09 -#define R0A_MT9V011_CLK_SPEED 0x0a -#define R0B_MT9V011_RESTART 0x0b -#define R0C_MT9V011_SHUTTER_DELAY 0x0c -#define R0D_MT9V011_RESET 0x0d -#define R1E_MT9V011_DIGITAL_ZOOM 0x1e -#define R20_MT9V011_READ_MODE 0x20 -#define R2B_MT9V011_GREEN_1_GAIN 0x2b -#define R2C_MT9V011_BLUE_GAIN 0x2c -#define R2D_MT9V011_RED_GAIN 0x2d -#define R2E_MT9V011_GREEN_2_GAIN 0x2e -#define R35_MT9V011_GLOBAL_GAIN 0x35 -#define RF1_MT9V011_CHIP_ENABLE 0xf1 - -#define MT9V011_VERSION 0x8232 -#define MT9V011_REV_B_VERSION 0x8243 - -#endif diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index c881a64b41fd..d4e7c11553c3 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -1449,47 +1449,6 @@ static int ov7670_g_chip_ident(struct v4l2_subdev *sd, return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0); } -static int ov7670_s_config(struct v4l2_subdev *sd, int dumb, void *data) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov7670_config *config = data; - struct ov7670_info *info = to_state(sd); - int ret; - - info->clock_speed = 30; /* default: a guess */ - - /* - * Must apply configuration before initializing device, because it - * selects I/O method. - */ - if (config) { - info->min_width = config->min_width; - info->min_height = config->min_height; - info->use_smbus = config->use_smbus; - - if (config->clock_speed) - info->clock_speed = config->clock_speed; - } - - /* Make sure it's an ov7670 */ - ret = ov7670_detect(sd); - if (ret) { - v4l_dbg(1, debug, client, - "chip found @ 0x%x (%s) is not an ov7670 chip.\n", - client->addr << 1, client->adapter->name); - kfree(info); - return ret; - } - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr << 1, client->adapter->name); - - info->fmt = &ov7670_formats[0]; - info->sat = 128; /* Review this */ - info->clkrc = info->clock_speed / 30; - - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { @@ -1528,7 +1487,6 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = { .s_ctrl = ov7670_s_ctrl, .queryctrl = ov7670_queryctrl, .reset = ov7670_reset, - .s_config = ov7670_s_config, .init = ov7670_init, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov7670_g_register, @@ -1558,6 +1516,7 @@ static int ov7670_probe(struct i2c_client *client, { struct v4l2_subdev *sd; struct ov7670_info *info; + int ret; info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL); if (info == NULL) @@ -1565,6 +1524,37 @@ static int ov7670_probe(struct i2c_client *client, sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &ov7670_ops); + info->clock_speed = 30; /* default: a guess */ + if (client->dev.platform_data) { + struct ov7670_config *config = client->dev.platform_data; + + /* + * Must apply configuration before initializing device, because it + * selects I/O method. + */ + info->min_width = config->min_width; + info->min_height = config->min_height; + info->use_smbus = config->use_smbus; + + if (config->clock_speed) + info->clock_speed = config->clock_speed; + } + + /* Make sure it's an ov7670 */ + ret = ov7670_detect(sd); + if (ret) { + v4l_dbg(1, debug, client, + "chip found @ 0x%x (%s) is not an ov7670 chip.\n", + client->addr << 1, client->adapter->name); + kfree(info); + return ret; + } + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + info->fmt = &ov7670_formats[0]; + info->sat = 128; /* Review this */ + info->clkrc = info->clock_speed / 30; return 0; } diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c index 864696b7a006..c901721a1db3 100644 --- a/drivers/media/video/sr030pc30.c +++ b/drivers/media/video/sr030pc30.c @@ -714,15 +714,6 @@ static int sr030pc30_base_config(struct v4l2_subdev *sd) return ret; } -static int sr030pc30_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); - - info->pdata = platform_data; - return 0; -} - static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable) { return 0; @@ -763,7 +754,6 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on) } static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { - .s_config = sr030pc30_s_config, .s_power = sr030pc30_s_power, .queryctrl = sr030pc30_queryctrl, .s_ctrl = sr030pc30_s_ctrl, diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 3f0871b550ad..810eef43c216 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -407,18 +407,6 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); - if (sd) { - /* We return errors from v4l2_subdev_call only if we have the - callback as the .s_config is not mandatory */ - int err = v4l2_subdev_call(sd, core, s_config, - info->irq, info->platform_data); - - if (err && err != -ENOIOCTLCMD) { - v4l2_device_unregister_subdev(sd); - sd = NULL; - } - } - error: /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ @@ -428,9 +416,8 @@ error: } EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); -struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, +struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, struct i2c_adapter *adapter, const char *client_type, - int irq, void *platform_data, u8 addr, const unsigned short *probe_addrs) { struct i2c_board_info info; @@ -440,12 +427,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, memset(&info, 0, sizeof(info)); strlcpy(info.type, client_type, sizeof(info.type)); info.addr = addr; - info.irq = irq; - info.platform_data = platform_data; return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs); } -EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg); +EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev); /* Return i2c client address of v4l2_subdev. */ unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) diff --git a/include/media/mt9v011.h b/include/media/mt9v011.h new file mode 100644 index 000000000000..ea29fc74cd06 --- /dev/null +++ b/include/media/mt9v011.h @@ -0,0 +1,17 @@ +/* mt9v011 sensor + * + * Copyright (C) 2011 Hans Verkuil + * + * 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. + */ + +#ifndef __MT9V011_H__ +#define __MT9V011_H__ + +struct mt9v011_platform_data { + unsigned xtal; /* Hz */ +}; + +#endif diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 2d65b35cdab2..a659319e8582 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -138,21 +138,10 @@ struct v4l2_subdev_ops; /* Load an i2c module and return an initialized v4l2_subdev struct. The client_type argument is the name of the chip that's on the adapter. */ -struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, +struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, struct i2c_adapter *adapter, const char *client_type, - int irq, void *platform_data, u8 addr, const unsigned short *probe_addrs); -/* Load an i2c module and return an initialized v4l2_subdev struct. - The client_type argument is the name of the chip that's on the adapter. */ -static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, - struct i2c_adapter *adapter, const char *client_type, - u8 addr, const unsigned short *probe_addrs) -{ - return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL, - addr, probe_addrs); -} - struct i2c_board_info; struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index b0316a7cf08d..42fbe462031d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -106,10 +106,7 @@ struct v4l2_subdev_io_pin_config { u8 strength; /* Pin drive strength */ }; -/* s_config: if set, then it is always called by the v4l2_i2c_new_subdev* - functions after the v4l2_subdev was registered. It is used to pass - platform data to the subdev which can be used during initialization. - +/* s_io_pin_config: configure one or more chip I/O pins for chips that multiplex different internal signal pads out to IO pins. This function takes a pointer to an array of 'n' pin configuration entries, one for @@ -141,7 +138,6 @@ struct v4l2_subdev_io_pin_config { struct v4l2_subdev_core_ops { int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip); int (*log_status)(struct v4l2_subdev *sd); - int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data); int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n, struct v4l2_subdev_io_pin_config *pincfg); int (*init)(struct v4l2_subdev *sd, u32 val); -- cgit v1.2.3 From 45f6f84af3ae9db19f39bc5d0976d626b0ef626e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 Jan 2011 07:15:53 -0300 Subject: [media] v4l2-subdev: add (un)register internal ops Some subdevs need to call into the board code after they are registered and have a valid struct v4l2_device pointer. The s_config op was abused for this, but now that it is removed we need a cleaner way of solving this. So this patch adds a struct with internal ops that the v4l2 core can call. Currently only two ops exist: register and unregister. Subdevs can implement these to call the board code and pass it the v4l2_device pointer, which the board code can then use to get access to the struct that embeds the v4l2_device. It is expected that in the future open and close ops will also be added. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 14 ++++++++++++-- include/media/v4l2-subdev.h | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 7fe6f92af480..b24f002ffa67 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -126,11 +126,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, WARN_ON(sd->v4l2_dev != NULL); if (!try_module_get(sd->owner)) return -ENODEV; + sd->v4l2_dev = v4l2_dev; + if (sd->internal_ops && sd->internal_ops->registered) { + err = sd->internal_ops->registered(sd); + if (err) + return err; + } /* This just returns 0 if either of the two args is NULL */ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); - if (err) + if (err) { + if (sd->internal_ops && sd->internal_ops->unregistered) + sd->internal_ops->unregistered(sd); return err; - sd->v4l2_dev = v4l2_dev; + } spin_lock(&v4l2_dev->lock); list_add_tail(&sd->list, &v4l2_dev->subdevs); spin_unlock(&v4l2_dev->lock); @@ -146,6 +154,8 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) spin_lock(&sd->v4l2_dev->lock); list_del(&sd->list); spin_unlock(&sd->v4l2_dev->lock); + if (sd->internal_ops && sd->internal_ops->unregistered) + sd->internal_ops->unregistered(sd); sd->v4l2_dev = NULL; module_put(sd->owner); } diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 42fbe462031d..daf1e57d9b26 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -411,6 +411,21 @@ struct v4l2_subdev_ops { const struct v4l2_subdev_sensor_ops *sensor; }; +/* + * Internal ops. Never call this from drivers, only the v4l2 framework can call + * these ops. + * + * registered: called when this subdev is registered. When called the v4l2_dev + * field is set to the correct v4l2_device. + * + * unregistered: called when this subdev is unregistered. When called the + * v4l2_dev field is still set to the correct v4l2_device. + */ +struct v4l2_subdev_internal_ops { + int (*registered)(struct v4l2_subdev *sd); + void (*unregistered)(struct v4l2_subdev *sd); +}; + #define V4L2_SUBDEV_NAME_SIZE 32 /* Set this flag if this subdev is a i2c device. */ @@ -427,6 +442,8 @@ struct v4l2_subdev { u32 flags; struct v4l2_device *v4l2_dev; const struct v4l2_subdev_ops *ops; + /* Never call these internal ops from within a driver! */ + const struct v4l2_subdev_internal_ops *internal_ops; /* The control handler of this subdev. May be NULL. */ struct v4l2_ctrl_handler *ctrl_handler; /* name must be unique */ -- cgit v1.2.3 From 2a863793beaa0fc9ee7aeb87efe85544a6b129c0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Jan 2011 14:45:03 -0300 Subject: [media] v4l2-ctrls: v4l2_ctrl_handler_setup must set is_new to 1 Renamed has_new to is_new. Drivers can use the is_new field to determine if a new value was specified for a control. The v4l2_ctrl_handler_setup() must always set this to 1 since the setup has to force a full update of all controls. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-controls.txt | 12 ++++++++++++ drivers/media/video/v4l2-ctrls.c | 24 ++++++++++++++---------- include/media/v4l2-ctrls.h | 6 ++++-- 3 files changed, 30 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 8773778d23fc..881e7f44491b 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -285,6 +285,9 @@ implement g_volatile_ctrl like this: The 'new value' union is not used in g_volatile_ctrl. In general controls that need to implement g_volatile_ctrl are read-only controls. +Note that if one or more controls in a control cluster are marked as volatile, +then all the controls in the cluster are seen as volatile. + To mark a control as volatile you have to set the is_volatile flag: ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...); @@ -462,6 +465,15 @@ pointer to the v4l2_ctrl_ops struct that is used for that cluster. Obviously, all controls in the cluster array must be initialized to either a valid control or to NULL. +In rare cases you might want to know which controls of a cluster actually +were set explicitly by the user. For this you can check the 'is_new' flag of +each control. For example, in the case of a volume/mute cluster the 'is_new' +flag of the mute control would be set if the user called VIDIOC_S_CTRL for +mute only. If the user would call VIDIOC_S_EXT_CTRLS for both mute and volume +controls, then the 'is_new' flag would be 1 for both controls. + +The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup(). + VIDIOC_LOG_STATUS Support ========================= diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 8f81efcfcf56..0d1a3d831374 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -569,7 +569,7 @@ static int user_to_new(struct v4l2_ext_control *c, int ret; u32 size; - ctrl->has_new = 1; + ctrl->is_new = 1; switch (ctrl->type) { case V4L2_CTRL_TYPE_INTEGER64: ctrl->val64 = c->value64; @@ -1280,8 +1280,12 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl) if (ctrl->done) continue; - for (i = 0; i < master->ncontrols; i++) - cur_to_new(master->cluster[i]); + for (i = 0; i < master->ncontrols; i++) { + if (master->cluster[i]) { + cur_to_new(master->cluster[i]); + master->cluster[i]->is_new = 1; + } + } /* Skip button controls and read-only controls. */ if (ctrl->type == V4L2_CTRL_TYPE_BUTTON || @@ -1645,7 +1649,7 @@ static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set) if (ctrl == NULL) continue; - if (ctrl->has_new) { + if (ctrl->is_new) { /* Double check this: it may have changed since the last check in try_or_set_ext_ctrls(). */ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) @@ -1719,13 +1723,13 @@ static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl, v4l2_ctrl_lock(ctrl); - /* Reset the 'has_new' flags of the cluster */ + /* Reset the 'is_new' flags of the cluster */ for (j = 0; j < master->ncontrols; j++) if (master->cluster[j]) - master->cluster[j]->has_new = 0; + master->cluster[j]->is_new = 0; /* Copy the new caller-supplied control values. - user_to_new() sets 'has_new' to 1. */ + user_to_new() sets 'is_new' to 1. */ ret = cluster_walk(i, cs, helpers, user_to_new); if (!ret) @@ -1822,13 +1826,13 @@ static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val) v4l2_ctrl_lock(ctrl); - /* Reset the 'has_new' flags of the cluster */ + /* Reset the 'is_new' flags of the cluster */ for (i = 0; i < master->ncontrols; i++) if (master->cluster[i]) - master->cluster[i]->has_new = 0; + master->cluster[i]->is_new = 0; ctrl->val = *val; - ctrl->has_new = 1; + ctrl->is_new = 1; ret = try_or_set_control_cluster(master, false); if (!ret) ret = try_or_set_control_cluster(master, true); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index d69ab4aae032..fcc9a0cf8ff1 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -53,8 +53,10 @@ struct v4l2_ctrl_ops { * @handler: The handler that owns the control. * @cluster: Point to start of cluster array. * @ncontrols: Number of controls in cluster array. - * @has_new: Internal flag: set when there is a valid new value. * @done: Internal flag: set for each processed control. + * @is_new: Set when the user specified a new value for this control. It + * is also set when called from v4l2_ctrl_handler_setup. Drivers + * should never set this flag. * @is_private: If set, then this control is private to its handler and it * will not be added to any other handlers. Drivers can set * this flag. @@ -97,9 +99,9 @@ struct v4l2_ctrl { struct v4l2_ctrl_handler *handler; struct v4l2_ctrl **cluster; unsigned ncontrols; - unsigned int has_new:1; unsigned int done:1; + unsigned int is_new:1; unsigned int is_private:1; unsigned int is_volatile:1; -- cgit v1.2.3 From 0beb6714e787ae46e1c1fc5e275452c1950ad141 Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 04:44:02 -0300 Subject: [media] gspca: Version change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 3581dea3c1f7..f21f2a258ae0 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 11, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0) #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; -- cgit v1.2.3 From 95c967c167785eb991cf6b22fb854dd8d61d0ff8 Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 05:20:29 -0300 Subject: [media] gspca: Remove __devinit, __devinitconst and __devinitdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __devinit* must not be used in USB drivers. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/benq.c | 2 +- drivers/media/video/gspca/conex.c | 4 ++-- drivers/media/video/gspca/cpia1.c | 2 +- drivers/media/video/gspca/etoms.c | 4 ++-- drivers/media/video/gspca/finepix.c | 2 +- drivers/media/video/gspca/gl860/gl860.c | 2 +- drivers/media/video/gspca/jeilinj.c | 2 +- drivers/media/video/gspca/konica.c | 2 +- drivers/media/video/gspca/m5602/m5602_core.c | 2 +- drivers/media/video/gspca/mars.c | 2 +- drivers/media/video/gspca/mr97310a.c | 2 +- drivers/media/video/gspca/ov519.c | 2 +- drivers/media/video/gspca/ov534.c | 2 +- drivers/media/video/gspca/ov534_9.c | 2 +- drivers/media/video/gspca/pac207.c | 2 +- drivers/media/video/gspca/pac7302.c | 4 ++-- drivers/media/video/gspca/pac7311.c | 4 ++-- drivers/media/video/gspca/sn9c2028.c | 2 +- drivers/media/video/gspca/sn9c20x.c | 2 +- drivers/media/video/gspca/sonixb.c | 4 ++-- drivers/media/video/gspca/sonixj.c | 2 +- drivers/media/video/gspca/spca1528.c | 2 +- drivers/media/video/gspca/spca500.c | 2 +- drivers/media/video/gspca/spca501.c | 2 +- drivers/media/video/gspca/spca505.c | 2 +- drivers/media/video/gspca/spca508.c | 2 +- drivers/media/video/gspca/spca561.c | 2 +- drivers/media/video/gspca/sq905.c | 2 +- drivers/media/video/gspca/sq905c.c | 2 +- drivers/media/video/gspca/sq930x.c | 2 +- drivers/media/video/gspca/stk014.c | 2 +- drivers/media/video/gspca/stv0680.c | 2 +- drivers/media/video/gspca/stv06xx/stv06xx.c | 2 +- drivers/media/video/gspca/sunplus.c | 2 +- drivers/media/video/gspca/t613.c | 2 +- drivers/media/video/gspca/tv8532.c | 2 +- drivers/media/video/gspca/vc032x.c | 2 +- drivers/media/video/gspca/xirlink_cit.c | 2 +- drivers/media/video/gspca/zc3xx.c | 2 +- 39 files changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index 629043933501..a09c4709d613 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -276,7 +276,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x04a5, 0x3035)}, {} }; diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 1eacb6c7926d..8b398493f96b 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -1040,14 +1040,14 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const struct usb_device_id device_table[] __devinitconst = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0572, 0x0041)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int __devinit sd_probe(struct usb_interface *intf, +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index c1ae05f4661f..4bf2cab98d64 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -2088,7 +2088,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0553, 0x0002)}, {USB_DEVICE(0x0813, 0x0001)}, {} diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index a594b36d6199..4b2c483fce6f 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -864,7 +864,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const struct usb_device_id device_table[] __devinitconst = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, #if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, @@ -875,7 +875,7 @@ static const struct usb_device_id device_table[] __devinitconst = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int __devinit sd_probe(struct usb_interface *intf, +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c index d78226455d1f..987b4b69d7ab 100644 --- a/drivers/media/video/gspca/finepix.c +++ b/drivers/media/video/gspca/finepix.c @@ -229,7 +229,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) } /* Table of supported USB devices */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x04cb, 0x0104)}, {USB_DEVICE(0x04cb, 0x0109)}, {USB_DEVICE(0x04cb, 0x010b)}, diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index b05bec7321b5..99083038cec3 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -488,7 +488,7 @@ static void sd_callback(struct gspca_dev *gspca_dev) /*=================== USB driver structure initialisation ==================*/ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x05e3, 0x0503)}, {USB_DEVICE(0x05e3, 0xf191)}, {} diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index a35e87bb0388..06b777f5379e 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -314,7 +314,7 @@ static int sd_start(struct gspca_dev *gspca_dev) } /* Table of supported USB devices */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0979, 0x0280)}, {} }; diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c index d2ce65dcbfdc..5964691c0e95 100644 --- a/drivers/media/video/gspca/konica.c +++ b/drivers/media/video/gspca/konica.c @@ -607,7 +607,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */ {} }; diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index c872b93a3351..a7722b1aef9b 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -28,7 +28,7 @@ int force_sensor; static int dump_bridge; int dump_sensor; -static const __devinitdata struct usb_device_id m5602_table[] = { +static const struct usb_device_id m5602_table[] = { {USB_DEVICE(0x0402, 0x5602)}, {} }; diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index a81536e78698..cb4d0bf0d784 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -490,7 +490,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x050f)}, {} }; diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 7607a288b51c..3884c9d300c5 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -1229,7 +1229,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */ {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */ {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */ diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index e1c3b9328ace..e30791f05690 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -4747,7 +4747,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 0edf93973b1c..ba8e56c3fc83 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -1289,7 +1289,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x1415, 0x2000)}, {} }; diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index c5244b4b4777..aaf5428c57f5 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -1429,7 +1429,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x06f8, 0x3003)}, {} }; diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index 96f9986305b4..81739a2f205e 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -530,7 +530,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4028)}, {USB_DEVICE(0x093a, 0x2460)}, {USB_DEVICE(0x093a, 0x2461)}, diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 2700975abce5..5615d7bd8304 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -1184,7 +1184,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const struct usb_device_id device_table[] __devinitconst = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x06f8, 0x3009)}, {USB_DEVICE(0x093a, 0x2620)}, {USB_DEVICE(0x093a, 0x2621)}, @@ -1201,7 +1201,7 @@ static const struct usb_device_id device_table[] __devinitconst = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int __devinit sd_probe(struct usb_interface *intf, +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 6820f5d58b19..f8801b50e64f 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -837,7 +837,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const struct usb_device_id device_table[] __devinitconst = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2600)}, {USB_DEVICE(0x093a, 0x2601)}, {USB_DEVICE(0x093a, 0x2603)}, @@ -849,7 +849,7 @@ static const struct usb_device_id device_table[] __devinitconst = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int __devinit sd_probe(struct usb_interface *intf, +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c index 40a06680502d..4271f86dfe01 100644 --- a/drivers/media/video/gspca/sn9c2028.c +++ b/drivers/media/video/gspca/sn9c2028.c @@ -703,7 +703,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */ /* The Genius Smart is untested. I can't find an owner ! */ /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */ diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index cb08d00d0a31..fcf29897b713 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -2470,7 +2470,7 @@ static const struct sd_desc sd_desc = { | (SENSOR_ ## sensor << 8) \ | (i2c_addr) -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)}, {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)}, {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)}, diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index e45d1cfb4461..c6cd68d66b53 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1565,7 +1565,7 @@ static const struct sd_desc sd_desc = { .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge -static const struct usb_device_id device_table[] __devinitconst = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */ {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */ {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */ @@ -1599,7 +1599,7 @@ static const struct usb_device_id device_table[] __devinitconst = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int __devinit sd_probe(struct usb_interface *intf, +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index db35391d00e6..3e41653f11c1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2909,7 +2909,7 @@ static const struct sd_desc sd_desc = { .driver_info = (BRIDGE_ ## bridge << 16) \ | (SENSOR_ ## sensor << 8) \ | (flags) -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)}, diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index e64338664410..76c006b2bc83 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -555,7 +555,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x04fc, 0x1528)}, {} }; diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 8e202b9039f1..45552c3ff8d9 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -1051,7 +1051,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200}, {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300}, {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler}, diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index 642839a11e8d..f7ef282cc600 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -2155,7 +2155,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325}, {USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera}, {USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite}, diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index bc9dd9034ab4..e5bf865147d7 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -786,7 +786,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra}, {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro}, /*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 7307638ac91d..348319371523 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1509,7 +1509,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam}, {USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista}, {USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110}, diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 3a162c6d5466..e836e778dfb6 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -1061,7 +1061,7 @@ static const struct sd_desc *sd_desc[2] = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A}, {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A}, {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A}, diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 404067745775..2e9c06175192 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -396,7 +396,7 @@ static int sd_start(struct gspca_dev *gspca_dev) } /* Table of supported USB devices */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x2770, 0x9120)}, {} }; diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c index 8ba199543856..457563b7a71b 100644 --- a/drivers/media/video/gspca/sq905c.c +++ b/drivers/media/video/gspca/sq905c.c @@ -298,7 +298,7 @@ static int sd_start(struct gspca_dev *gspca_dev) } /* Table of supported USB devices */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x2770, 0x905c)}, {USB_DEVICE(0x2770, 0x9050)}, {USB_DEVICE(0x2770, 0x9051)}, diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c index a4a98811b9e3..8215d5dcd456 100644 --- a/drivers/media/video/gspca/sq930x.c +++ b/drivers/media/video/gspca/sq930x.c @@ -1163,7 +1163,7 @@ static const struct sd_desc sd_desc = { #define ST(sensor, type) \ .driver_info = (SENSOR_ ## sensor << 8) \ | (type) -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 11a192b95ed4..87be52b5e1e3 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -495,7 +495,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x05e1, 0x0893)}, {} }; diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c index b199ad4666bd..e2ef41cf72d7 100644 --- a/drivers/media/video/gspca/stv0680.c +++ b/drivers/media/video/gspca/stv0680.c @@ -327,7 +327,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0553, 0x0202)}, {USB_DEVICE(0x041e, 0x4007)}, {} diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 28ea4175b80e..7e0661429293 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -564,7 +564,7 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { /* QuickCam Express */ {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, /* LEGO cam / QuickCam Web */ diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index a9cbcd6011d9..543542af2720 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -1162,7 +1162,7 @@ static const struct sd_desc sd_desc = { #define BS(bridge, subtype) \ .driver_info = (BRIDGE_ ## bridge << 8) \ | (subtype) -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)}, {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)}, {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)}, diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 8f0c33116e0d..a3eccd815766 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -1416,7 +1416,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x17a1, 0x0128)}, {} }; diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index 38c22f0a4263..933ef2ca658c 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -388,7 +388,7 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x0920)}, {USB_DEVICE(0x046d, 0x0921)}, {USB_DEVICE(0x0545, 0x808b)}, diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 9b2ae1b6cc75..6caed734a06a 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -4192,7 +4192,7 @@ static const struct sd_desc sd_desc = { #define BF(bridge, flags) \ .driver_info = (BRIDGE_ ## bridge << 8) \ | (flags) -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)}, {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)}, {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)}, diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index 5b5039a02031..c089a0f6f1d0 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -3270,7 +3270,7 @@ static const struct sd_desc sd_desc_isoc_nego = { }; /* -- module initialisation -- */ -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 }, { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 }, { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 }, diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 14b85d483163..865216e9362c 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -6909,7 +6909,7 @@ static const struct sd_desc sd_desc = { #endif }; -static const __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x041e)}, {USB_DEVICE(0x041e, 0x4017)}, {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, -- cgit v1.2.3 From ded5e903b75a9e2a9349e19063e3b2a63b05e828 Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 05:27:37 -0300 Subject: [media] gspca: Remove useless instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/jpeg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h index de63c36806c0..ab54910418b4 100644 --- a/drivers/media/video/gspca/jpeg.h +++ b/drivers/media/video/gspca/jpeg.h @@ -141,9 +141,9 @@ static void jpeg_define(u8 *jpeg_hdr, memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head); #ifndef CONEX_CAM jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8; - jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height; jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8; - jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width; jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY; #endif } -- cgit v1.2.3 From fc63de88e0f27ecdaab4d2d836fd7bacab643fc0 Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 05:35:18 -0300 Subject: [media] gspca - ov519: Cleanup source and add a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov519.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index e30791f05690..8ab2c452c25e 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -488,7 +488,6 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = { #define R511_SNAP_PXDIV 0x1c #define R511_SNAP_LNDIV 0x1d #define R511_SNAP_UV_EN 0x1e -#define R511_SNAP_UV_EN 0x1e #define R511_SNAP_OPTS 0x1f #define R511_DRAM_FLOW_CTL 0x20 @@ -1847,8 +1846,7 @@ static const struct ov_i2c_regvals norm_7670[] = { { 0x6c, 0x0a }, { 0x6d, 0x55 }, { 0x6e, 0x11 }, - { 0x6f, 0x9f }, - /* "9e for advance AWB" */ + { 0x6f, 0x9f }, /* "9e for advance AWB" */ { 0x6a, 0x40 }, { OV7670_R01_BLUE, 0x40 }, { OV7670_R02_RED, 0x60 }, @@ -3054,7 +3052,7 @@ static void ov519_configure(struct sd *sd) { static const struct ov_regvals init_519[] = { { 0x5a, 0x6d }, /* EnableSystem */ - { 0x53, 0x9b }, + { 0x53, 0x9b }, /* don't enable the microcontroller */ { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */ { 0x5d, 0x03 }, { 0x49, 0x01 }, -- cgit v1.2.3 From ddffa49e257e2b28e23f1e2729c0560bcad89937 Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 05:49:47 -0300 Subject: [media] gspca - ov534: Clearer debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov534.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index ba8e56c3fc83..a837f2942a8c 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -479,7 +479,7 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) struct usb_device *udev = gspca_dev->dev; int ret; - PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val); + PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val); gspca_dev->usb_buf[0] = val; ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -500,7 +500,7 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) 0x01, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); - PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]); + PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); if (ret < 0) err("read failed %d", ret); return gspca_dev->usb_buf[0]; @@ -558,7 +558,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) { - PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val); + PDEBUG(D_USBO, "sccb write: %02x %02x", reg, val); ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); -- cgit v1.2.3 From 14b67c2969ebf50bd5534b2a0c441f8569a9361e Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 05:58:04 -0300 Subject: [media] gspca - ov534: Propagate errors to higher level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov534.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index a837f2942a8c..04da22802736 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -479,6 +479,9 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) struct usb_device *udev = gspca_dev->dev; int ret; + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val); gspca_dev->usb_buf[0] = val; ret = usb_control_msg(udev, @@ -486,8 +489,10 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) 0x01, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); - if (ret < 0) + if (ret < 0) { err("write failed %d", ret); + gspca_dev->usb_err = ret; + } } static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) @@ -495,14 +500,18 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) struct usb_device *udev = gspca_dev->dev; int ret; + if (gspca_dev->usb_err < 0) + return 0; ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); - if (ret < 0) + if (ret < 0) { err("read failed %d", ret); + gspca_dev->usb_err = ret; + } return gspca_dev->usb_buf[0]; } @@ -563,8 +572,10 @@ static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); - if (!sccb_check_status(gspca_dev)) + if (!sccb_check_status(gspca_dev)) { err("sccb_reg_write failed"); + gspca_dev->usb_err = -EIO; + } } static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) @@ -885,7 +896,7 @@ static int sd_init(struct gspca_dev *gspca_dev) ov534_set_led(gspca_dev, 0); set_frame_rate(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) @@ -920,7 +931,7 @@ static int sd_start(struct gspca_dev *gspca_dev) ov534_set_led(gspca_dev, 1); ov534_reg_write(gspca_dev, 0xe0, 0x00); - return 0; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) -- cgit v1.2.3 From 3afef85bfefa65a31f4dbf8e7921c7938adb24f4 Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 06:39:11 -0300 Subject: [media] gspca - sonixj: Infrared bug fix and enhancement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The infrared was set by sensor write instead of bridge GPIO. It is now settable by the standard control ILLUMINATOR_1. A module parameter permits to set the right GPIO bit according to the StarCam model. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 80 ++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 3e41653f11c1..c634dc113f94 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -25,12 +25,12 @@ #include "gspca.h" #include "jpeg.h" -#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0) - MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); MODULE_LICENSE("GPL"); +static int starcam; + /* controls */ enum e_ctrl { BRIGHTNESS, @@ -43,7 +43,7 @@ enum e_ctrl { HFLIP, VFLIP, SHARPNESS, - INFRARED, + ILLUM, FREQ, NCTRLS /* number of controls */ }; @@ -100,7 +100,8 @@ enum sensors { }; /* device flags */ -#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */ +#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */ +#define F_ILLUM 0x02 /* presence of illuminator */ /* sn9c1xx definitions */ /* register 0x01 */ @@ -124,7 +125,7 @@ static void setgamma(struct gspca_dev *gspca_dev); static void setautogain(struct gspca_dev *gspca_dev); static void sethvflip(struct gspca_dev *gspca_dev); static void setsharpness(struct gspca_dev *gspca_dev); -static void setinfrared(struct gspca_dev *gspca_dev); +static void setillum(struct gspca_dev *gspca_dev); static void setfreq(struct gspca_dev *gspca_dev); static const struct ctrl sd_ctrls[NCTRLS] = { @@ -251,18 +252,17 @@ static const struct ctrl sd_ctrls[NCTRLS] = { }, .set_control = setsharpness }, -/* mt9v111 only */ -[INFRARED] = { +[ILLUM] = { { - .id = V4L2_CID_INFRARED, + .id = V4L2_CID_ILLUMINATORS_1, .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Infrared", + .name = "Illuminator / infrared", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, }, - .set_control = setinfrared + .set_control = setillum }, /* ov7630/ov7648/ov7660 only */ [FREQ] = { @@ -282,32 +282,26 @@ static const struct ctrl sd_ctrls[NCTRLS] = { /* table of the disabled controls */ static const __u32 ctrl_dis[] = { [SENSOR_ADCM1700] = (1 << AUTOGAIN) | - (1 << INFRARED) | (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), -[SENSOR_GC0307] = (1 << INFRARED) | - (1 << HFLIP) | +[SENSOR_GC0307] = (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), -[SENSOR_HV7131R] = (1 << INFRARED) | - (1 << HFLIP) | +[SENSOR_HV7131R] = (1 << HFLIP) | (1 << FREQ), -[SENSOR_MI0360] = (1 << INFRARED) | - (1 << HFLIP) | +[SENSOR_MI0360] = (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), -[SENSOR_MI0360B] = (1 << INFRARED) | - (1 << HFLIP) | +[SENSOR_MI0360B] = (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), -[SENSOR_MO4000] = (1 << INFRARED) | - (1 << HFLIP) | +[SENSOR_MO4000] = (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), @@ -315,40 +309,32 @@ static const __u32 ctrl_dis[] = { (1 << VFLIP) | (1 << FREQ), -[SENSOR_OM6802] = (1 << INFRARED) | - (1 << HFLIP) | +[SENSOR_OM6802] = (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), -[SENSOR_OV7630] = (1 << INFRARED) | - (1 << HFLIP), +[SENSOR_OV7630] = (1 << HFLIP), -[SENSOR_OV7648] = (1 << INFRARED) | - (1 << HFLIP), +[SENSOR_OV7648] = (1 << HFLIP), [SENSOR_OV7660] = (1 << AUTOGAIN) | - (1 << INFRARED) | (1 << HFLIP) | (1 << VFLIP), [SENSOR_PO1030] = (1 << AUTOGAIN) | - (1 << INFRARED) | (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), [SENSOR_PO2030N] = (1 << AUTOGAIN) | - (1 << INFRARED) | (1 << FREQ), [SENSOR_SOI768] = (1 << AUTOGAIN) | - (1 << INFRARED) | (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), [SENSOR_SP80708] = (1 << AUTOGAIN) | - (1 << INFRARED) | (1 << HFLIP) | (1 << VFLIP) | (1 << FREQ), @@ -1876,6 +1862,8 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->i2c_addr = sn9c1xx[9]; gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; + if (!(sd->flags & F_ILLUM)) + gspca_dev->ctrl_dis |= (1 << ILLUM); return gspca_dev->usb_err; } @@ -2199,16 +2187,20 @@ static void setsharpness(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val); } -static void setinfrared(struct gspca_dev *gspca_dev) +static void setillum(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (gspca_dev->ctrl_dis & (1 << INFRARED)) + if (gspca_dev->ctrl_dis & (1 << ILLUM)) return; -/*fixme: different sequence for StarCam Clip and StarCam 370i */ -/* Clip */ - i2c_w1(gspca_dev, 0x02, /* gpio */ - sd->ctrls[INFRARED].val ? 0x66 : 0x64); + if (starcam) + reg_w1(gspca_dev, 0x02, /* gpio */ + sd->ctrls[ILLUM].val ? + 0x55 : 0x54); /* 370i */ + else + reg_w1(gspca_dev, 0x02, + sd->ctrls[ILLUM].val ? + 0x66 : 0x64); /* Clip */ } static void setfreq(struct gspca_dev *gspca_dev) @@ -2346,7 +2338,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* sensor clock already enabled in sd_init */ /* reg_w1(gspca_dev, 0xf1, 0x00); */ reg01 = sn9c1xx[1]; - if (sd->flags & PDN_INV) + if (sd->flags & F_PDN_INV) reg01 ^= S_PDN_INV; /* power down inverted */ reg_w1(gspca_dev, 0x01, reg01); @@ -2912,8 +2904,8 @@ static const struct sd_desc sd_desc = { static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, - {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)}, - {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)}, + {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)}, + {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)}, {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)}, {USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)}, {USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)}, @@ -2925,7 +2917,7 @@ static const struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */ {USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)}, /* {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */ - {USB_DEVICE(0x0c45, 0x60c0), BS(SN9C105, MI0360)}, + {USB_DEVICE(0x0c45, 0x60c0), BSF(SN9C105, MI0360, F_ILLUM)}, /* or MT9V111 */ /* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ /* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ @@ -3004,3 +2996,7 @@ static void __exit sd_mod_exit(void) module_init(sd_mod_init); module_exit(sd_mod_exit); + +module_param(starcam, int, 0644); +MODULE_PARM_DESC(starcam, + "StarCam model. 0: Clip, 1: 370i"); -- cgit v1.2.3 From a63d601803c2e3ba06ed51b9ed997fc6bf80e5bf Mon Sep 17 00:00:00 2001 From: Jean-François Moine Date: Thu, 13 Jan 2011 07:56:00 -0300 Subject: [media] gspca - sonixj: Add LED (illuminator) control to the webcam 0c45:614a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index c634dc113f94..d6f39ce1b7e1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2193,14 +2193,22 @@ static void setillum(struct gspca_dev *gspca_dev) if (gspca_dev->ctrl_dis & (1 << ILLUM)) return; - if (starcam) - reg_w1(gspca_dev, 0x02, /* gpio */ - sd->ctrls[ILLUM].val ? - 0x55 : 0x54); /* 370i */ - else - reg_w1(gspca_dev, 0x02, - sd->ctrls[ILLUM].val ? - 0x66 : 0x64); /* Clip */ + switch (sd->sensor) { + case SENSOR_ADCM1700: + reg_w1(gspca_dev, 0x02, /* gpio */ + sd->ctrls[ILLUM].val ? 0x64 : 0x60); + break; + case SENSOR_MT9V111: + if (starcam) + reg_w1(gspca_dev, 0x02, + sd->ctrls[ILLUM].val ? + 0x55 : 0x54); /* 370i */ + else + reg_w1(gspca_dev, 0x02, + sd->ctrls[ILLUM].val ? + 0x66 : 0x64); /* Clip */ + break; + } } static void setfreq(struct gspca_dev *gspca_dev) @@ -2959,7 +2967,7 @@ static const struct usb_device_id device_table[] = { /* or GC0305 / GC0307 */ {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/ - {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/ + {USB_DEVICE(0x0c45, 0x614a), BSF(SN9C120, ADCM1700, F_ILLUM)}, /* {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */ /*sn9c120b*/ {} }; -- cgit v1.2.3 From 36fd97884daf4e30b556a6c59b58db19a06d58af Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 2 Jan 2011 16:14:03 -0300 Subject: [media] frontends/ix2505v: Remember to free allocated memory in failure path We may leak the storage allocated to 'state' in drivers/media/dvb/frontends/ix2505v.c::ix2505v_attach() on error, as it is too early to be able to call ix2505v_release(). This patch makes sure we free the allocated memory in the failure case. Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ix2505v.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c index 6360c681ded9..6c2e929bd79f 100644 --- a/drivers/media/dvb/frontends/ix2505v.c +++ b/drivers/media/dvb/frontends/ix2505v.c @@ -311,7 +311,7 @@ struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, return fe; error: - ix2505v_release(fe); + kfree(state); return NULL; } EXPORT_SYMBOL(ix2505v_attach); -- cgit v1.2.3 From fd01ad98945073faeb25391489caef4844f265c4 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 2 Jan 2011 17:57:24 -0300 Subject: [media] media, tlg2300: Fix memory leak in alloc_bulk_urbs_generic() Hi, While reading drivers/media/video/tlg2300/pd-video.c::alloc_bulk_urbs_generic() I noticed that - We don't free the memory allocated to 'urb' if the call to usb_alloc_coherent() fails. - If the 'num' argument to the function is ever <= 0 we'll return an uninitialized variable 'i' to the caller. The following patch addresses both of the above by a) calling usb_free_urb() when usb_alloc_coherent() fails and by explicitly initializing 'i' to zero. I also moved the variables 'mem' and 'urb' inside the for loop. This does not actually make any difference, it just seemed more correct to me to let variables exist only in the innermost scope they are used. Signed-off-by: Jesper Juhl Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tlg2300/pd-video.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c index a1ffe18640fe..df33a1d188bb 100644 --- a/drivers/media/video/tlg2300/pd-video.c +++ b/drivers/media/video/tlg2300/pd-video.c @@ -512,19 +512,20 @@ int alloc_bulk_urbs_generic(struct urb **urb_array, int num, int buf_size, gfp_t gfp_flags, usb_complete_t complete_fn, void *context) { - struct urb *urb; - void *mem; - int i; + int i = 0; - for (i = 0; i < num; i++) { - urb = usb_alloc_urb(0, gfp_flags); + for (; i < num; i++) { + void *mem; + struct urb *urb = usb_alloc_urb(0, gfp_flags); if (urb == NULL) return i; mem = usb_alloc_coherent(udev, buf_size, gfp_flags, &urb->transfer_dma); - if (mem == NULL) + if (mem == NULL) { + usb_free_urb(urb); return i; + } usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr), mem, buf_size, complete_fn, context); -- cgit v1.2.3 From a3bc5e3304c9ba8e7504597026d9ca93784d1239 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Jan 2011 10:49:34 -0300 Subject: [media] v4l/cx18: update workqueue usage With cmwq, there's no reason to use separate out_work_queue. Drop it and use system_wq instead. The in_work_queue needs to be ordered so can't use one of the system wqs; however, as it isn't used to reclaim memory, allocate the workqueue with alloc_ordered_workqueue() without WQ_MEM_RECLAIM. Signed-off-by: Tejun Heo Reviewed-by: Andy Walls Acked-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 24 ++---------------------- drivers/media/video/cx18/cx18-driver.h | 3 --- drivers/media/video/cx18/cx18-streams.h | 3 +-- 3 files changed, 3 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 133ec2bac180..944af8adbe0c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -664,7 +664,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx) { snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", cx->v4l2_dev.name); - cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name); + cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); if (cx->in_work_queue == NULL) { CX18_ERR("Unable to create incoming mailbox handler thread\n"); return -ENOMEM; @@ -672,18 +672,6 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx) return 0; } -static int __devinit cx18_create_out_workq(struct cx18 *cx) -{ - snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out", - cx->v4l2_dev.name); - cx->out_work_queue = create_workqueue(cx->out_workq_name); - if (cx->out_work_queue == NULL) { - CX18_ERR("Unable to create outgoing mailbox handler threads\n"); - return -ENOMEM; - } - return 0; -} - static void __devinit cx18_init_in_work_orders(struct cx18 *cx) { int i; @@ -710,15 +698,9 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->epu2apu_mb_lock); mutex_init(&cx->epu2cpu_mb_lock); - ret = cx18_create_out_workq(cx); - if (ret) - return ret; - ret = cx18_create_in_workq(cx); - if (ret) { - destroy_workqueue(cx->out_work_queue); + if (ret) return ret; - } cx18_init_in_work_orders(cx); @@ -1107,7 +1089,6 @@ free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueues: destroy_workqueue(cx->in_work_queue); - destroy_workqueue(cx->out_work_queue); err: if (retval == 0) retval = -ENODEV; @@ -1259,7 +1240,6 @@ static void cx18_remove(struct pci_dev *pci_dev) cx18_halt_firmware(cx); destroy_workqueue(cx->in_work_queue); - destroy_workqueue(cx->out_work_queue); cx18_streams_cleanup(cx, 1); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index f6f3e50d4bdf..306caac6d3fc 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -617,9 +617,6 @@ struct cx18 { struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ - struct workqueue_struct *out_work_queue; - char out_workq_name[12]; /* "cx18-NN-out" */ - /* i2c */ struct i2c_adapter i2c_adap[2]; struct i2c_algo_bit_data i2c_algo[2]; diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 51765eb12d39..713b0e61536d 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h @@ -42,8 +42,7 @@ static inline bool cx18_stream_enabled(struct cx18_stream *s) /* Related to submission of mdls to firmware */ static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) { - struct cx18 *cx = s->cx; - queue_work(cx->out_work_queue, &s->out_work_order); + schedule_work(&s->out_work_order); } static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, -- cgit v1.2.3 From 34b8fc8e683cbcbbe47806260ef5dc505915b45f Mon Sep 17 00:00:00 2001 From: Matti Aaltonen Date: Tue, 4 Jan 2011 08:29:37 -0300 Subject: [media] V4L2: WL1273 FM Radio: Replace ioctl with unlocked_ioctl Use unlocked_ioctl in v4l2_file_operations. The locking is already in place. Signed-off-by: Matti J. Aaltonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-wl1273.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index dd6bd364efa0..7ecc8e657663 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1407,7 +1407,7 @@ static const struct v4l2_file_operations wl1273_fops = { .read = wl1273_fm_fops_read, .write = wl1273_fm_fops_write, .poll = wl1273_fm_fops_poll, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .open = wl1273_fm_fops_open, .release = wl1273_fm_fops_release, }; -- cgit v1.2.3 From e95342f168f7a02441cec51b222bb7ae62df364d Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 6 Jan 2011 14:25:44 -0300 Subject: [media] DVB: cx231xx drivers does not use dummy frontend anymore Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-dvb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c index fe59a1c3f064..363aa6004221 100644 --- a/drivers/media/video/cx231xx/cx231xx-dvb.c +++ b/drivers/media/video/cx231xx/cx231xx-dvb.c @@ -28,7 +28,6 @@ #include #include "xc5000.h" -#include "dvb_dummy_fe.h" #include "s5h1432.h" #include "tda18271.h" #include "s5h1411.h" @@ -619,7 +618,7 @@ static int dvb_init(struct cx231xx *dev) if (dev->dvb->frontend == NULL) { printk(DRIVER_NAME - ": Failed to attach dummy front end\n"); + ": Failed to attach s5h1411 front end\n"); result = -EINVAL; goto out_free; } @@ -665,7 +664,7 @@ static int dvb_init(struct cx231xx *dev) if (dev->dvb->frontend == NULL) { printk(DRIVER_NAME - ": Failed to attach dummy front end\n"); + ": Failed to attach s5h1411 front end\n"); result = -EINVAL; goto out_free; } -- cgit v1.2.3 From 7d2edfc23e9852591cb031a26093cdcd07a34a90 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 6 Jan 2011 16:57:14 -0300 Subject: [media] rc/imon: fix ffdc device detection oops There's a nasty bug that slipped in when the rc device interface was altered, only affecting the older 0xffdc imon devices. We were trying to access ictx->rdev->allowed_protos before ictx->rdev had been set. There's also an issue with call ordering that meant the correct keymap wasn't getting loaded for MCE IR type 0xffdc devices. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 6811512b4e83..a30bd99c5ca4 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1756,7 +1756,6 @@ static void imon_get_ffdc_type(struct imon_context *ictx) printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); ictx->display_type = detected_display_type; - ictx->rdev->allowed_protos = allowed_protos; ictx->rc_type = allowed_protos; } @@ -1839,10 +1838,6 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */ rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; - if (ictx->rc_type == RC_TYPE_RC6) - rdev->map_name = RC_MAP_IMON_MCE; - else - rdev->map_name = RC_MAP_IMON_PAD; /* Enable front-panel buttons and/or knobs */ memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); @@ -1851,11 +1846,18 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) if (ret) dev_info(ictx->dev, "panel buttons/knobs setup failed\n"); - if (ictx->product == 0xffdc) + if (ictx->product == 0xffdc) { imon_get_ffdc_type(ictx); + rdev->allowed_protos = ictx->rc_type; + } imon_set_display_type(ictx); + if (ictx->rc_type == RC_TYPE_RC6) + rdev->map_name = RC_MAP_IMON_MCE; + else + rdev->map_name = RC_MAP_IMON_PAD; + ret = rc_register_device(rdev); if (ret < 0) { dev_err(ictx->dev, "remote input dev register failed\n"); -- cgit v1.2.3 From 2e4c55626a0c30b5b2bc9469c025a563a81c3785 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 6 Jan 2011 16:59:33 -0300 Subject: [media] rc/ene_ir: fix oops on module load dev->rdev is accessed in ene_setup_hw_settings, so it needs to be wired up before then. [Jarod Wilson]: Also fix a possible improper resource freeing bug while we're looking at possible probe issues here. Signed-off-by: Kyle McMartin CC: Maxim Levitsky Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 80b3c319f698..885abdddfaa8 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1004,6 +1004,10 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* validate resources */ error = -ENODEV; + /* init these to -1, as 0 is valid for both */ + dev->hw_io = -1; + dev->irq = -1; + if (!pnp_port_valid(pnp_dev, 0) || pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE) goto error; @@ -1072,6 +1076,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) rdev->input_name = "ENE eHome Infrared Remote Transceiver"; } + dev->rdev = rdev; + ene_rx_setup_hw_buffer(dev); ene_setup_default_settings(dev); ene_setup_hw_settings(dev); @@ -1083,7 +1089,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (error < 0) goto error; - dev->rdev = rdev; ene_notice("driver has been succesfully loaded"); return 0; error: -- cgit v1.2.3 From 9ad77eb57b45f81ac3e12077d19e5f121c4cff6d Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 6 Jan 2011 16:59:34 -0300 Subject: [media] rc/imon: need to submit urb before ffdc type check Otherwise, we have a null receive buffer, and the logic all falls down, goes boom, all ffdc devs wind up as imon IR w/VFD. Oops. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index a30bd99c5ca4..703420749243 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2110,18 +2110,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto find_endpoint_failed; } - ictx->idev = imon_init_idev(ictx); - if (!ictx->idev) { - dev_err(dev, "%s: input device setup failed\n", __func__); - goto idev_setup_failed; - } - - ictx->rdev = imon_init_rdev(ictx); - if (!ictx->rdev) { - dev_err(dev, "%s: rc device setup failed\n", __func__); - goto rdev_setup_failed; - } - usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, usb_rcvintpipe(ictx->usbdev_intf0, ictx->rx_endpoint_intf0->bEndpointAddress), @@ -2135,13 +2123,25 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto urb_submit_failed; } + ictx->idev = imon_init_idev(ictx); + if (!ictx->idev) { + dev_err(dev, "%s: input device setup failed\n", __func__); + goto idev_setup_failed; + } + + ictx->rdev = imon_init_rdev(ictx); + if (!ictx->rdev) { + dev_err(dev, "%s: rc device setup failed\n", __func__); + goto rdev_setup_failed; + } + return ictx; -urb_submit_failed: - rc_unregister_device(ictx->rdev); rdev_setup_failed: input_unregister_device(ictx->idev); idev_setup_failed: + usb_kill_urb(ictx->rx_urb_intf0); +urb_submit_failed: find_endpoint_failed: mutex_unlock(&ictx->lock); usb_free_urb(tx_urb); -- cgit v1.2.3 From 5aad724280b9f8ffff3a55311ef0ba35ebb4099a Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 6 Jan 2011 16:59:36 -0300 Subject: [media] rc: fix up and genericize some time unit conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ene_ir driver was using a private define of MS_TO_NS, which is meant to be microseconds to nanoseconds. The mceusb driver copied it, intending to use is a milliseconds to microseconds. Lets move the defines to a common location, expand and standardize them a touch, so that we now have: MS_TO_NS - milliseconds to nanoseconds MS_TO_US - milliseconds to microseconds US_TO_NS - microseconds to nanoseconds Reported-by: David Härdeman CC: Maxim Levitsky Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 16 ++++++++-------- drivers/media/rc/ene_ir.h | 2 -- drivers/media/rc/mceusb.c | 7 +++---- include/media/rc-core.h | 3 +++ 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 885abdddfaa8..1ac49139158d 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -446,27 +446,27 @@ static void ene_rx_setup(struct ene_device *dev) select_timeout: if (dev->rx_fan_input_inuse) { - dev->rdev->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN); + dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN); /* Fan input doesn't support timeouts, it just ends the input with a maximum sample */ dev->rdev->min_timeout = dev->rdev->max_timeout = - MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK * + US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK * ENE_FW_SAMPLE_PERIOD_FAN); } else { - dev->rdev->rx_resolution = MS_TO_NS(sample_period); + dev->rdev->rx_resolution = US_TO_NS(sample_period); /* Theoreticly timeout is unlimited, but we cap it * because it was seen that on one device, it * would stop sending spaces after around 250 msec. * Besides, this is close to 2^32 anyway and timeout is u32. */ - dev->rdev->min_timeout = MS_TO_NS(127 * sample_period); - dev->rdev->max_timeout = MS_TO_NS(200000); + dev->rdev->min_timeout = US_TO_NS(127 * sample_period); + dev->rdev->max_timeout = US_TO_NS(200000); } if (dev->hw_learning_and_tx_capable) - dev->rdev->tx_resolution = MS_TO_NS(sample_period); + dev->rdev->tx_resolution = US_TO_NS(sample_period); if (dev->rdev->timeout > dev->rdev->max_timeout) dev->rdev->timeout = dev->rdev->max_timeout; @@ -801,7 +801,7 @@ static irqreturn_t ene_isr(int irq, void *data) dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); - ev.duration = MS_TO_NS(hw_sample); + ev.duration = US_TO_NS(hw_sample); ev.pulse = pulse; ir_raw_event_store_with_filter(dev->rdev, &ev); } @@ -821,7 +821,7 @@ static void ene_setup_default_settings(struct ene_device *dev) dev->learning_mode_enabled = learning_mode_force; /* Set reasonable default timeout */ - dev->rdev->timeout = MS_TO_NS(150000); + dev->rdev->timeout = US_TO_NS(150000); } /* Upload all hardware settings at once. Used at load and resume time */ diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index c179baf34cb4..337a41d4450b 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -201,8 +201,6 @@ #define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) #define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__) -#define MS_TO_NS(msec) ((msec) * 1000) - struct ene_device { struct pnp_dev *pnp_dev; struct rc_dev *rdev; diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 0fef6efad537..2d9113493cf0 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -48,7 +48,6 @@ #define USB_BUFLEN 32 /* USB reception buffer length */ #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ -#define MS_TO_NS(msec) ((msec) * 1000) /* MCE constants */ #define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ @@ -817,7 +816,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) switch (ir->buf_in[index]) { /* 2-byte return value commands */ case MCE_CMD_S_TIMEOUT: - ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2); + ir->rc->timeout = MS_TO_US((hi << 8 | lo) / 2); break; /* 1-byte return value commands */ @@ -858,7 +857,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem--; rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) - * MS_TO_NS(MCE_TIME_UNIT); + * MS_TO_US(MCE_TIME_UNIT); dev_dbg(ir->dev, "Storing %s with duration %d\n", rawir.pulse ? "pulse" : "space", @@ -1061,7 +1060,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = MS_TO_NS(1000); + rc->timeout = MS_TO_US(1000); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index a23c1fc685a1..2963263f31e2 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -183,6 +183,9 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev) } #define IR_MAX_DURATION 0xFFFFFFFF /* a bit more than 4 seconds */ +#define US_TO_NS(usec) ((usec) * 1000) +#define MS_TO_US(msec) ((msec) * 1000) +#define MS_TO_NS(msec) ((msec) * 1000 * 1000) void ir_raw_event_handle(struct rc_dev *dev); int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); -- cgit v1.2.3 From 76f1ef427c0aab3d3c917b497562ea2cdaaae056 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 6 Jan 2011 16:59:35 -0300 Subject: [media] rc/imon: default to key mode instead of mouse mode My initial thinking was that we should default to mouse mode, so people could use the mouse function to click on something on a login screen, but a lot of systems where a remote is useful automatically log in a user and launch a media center application, some of which hide the mouse, which can be confusing to users if they punch buttons on the remote and don't see any feedback. Plus, first and foremost, its a remote, so lets default to being a remote, and only toggle into mouse mode when the user explicitly asks for it. As a nice side-effect, this actually simplifies some of the code a fair bit... Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 703420749243..e7dc6b46fdfa 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -988,7 +988,6 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) int retval; struct imon_context *ictx = rc->priv; struct device *dev = ictx->dev; - bool pad_mouse; unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; @@ -1000,29 +999,20 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) case RC_TYPE_RC6: dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; - pad_mouse = false; break; case RC_TYPE_UNKNOWN: case RC_TYPE_OTHER: dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); - if (pad_stabilize && !nomouse) - pad_mouse = true; - else { + if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); - pad_mouse = false; - } /* ir_proto_packet[0] = 0x00; // already the default */ rc_type = RC_TYPE_OTHER; break; default: dev_warn(dev, "Unsupported IR protocol specified, overriding " "to iMON IR protocol\n"); - if (pad_stabilize && !nomouse) - pad_mouse = true; - else { + if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); - pad_mouse = false; - } /* ir_proto_packet[0] = 0x00; // already the default */ rc_type = RC_TYPE_OTHER; break; @@ -1035,7 +1025,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) goto out; ictx->rc_type = rc_type; - ictx->pad_mouse = pad_mouse; + ictx->pad_mouse = false; out: return retval; @@ -1517,7 +1507,7 @@ static void imon_incoming_packet(struct imon_context *ictx, spin_unlock_irqrestore(&ictx->kc_lock, flags); return; } else { - ictx->pad_mouse = 0; + ictx->pad_mouse = false; dev_dbg(dev, "mouse mode disabled, passing key value\n"); } } -- cgit v1.2.3 From cb26a24ee9706473f31d34cc259f4dcf45cd0644 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Jan 2011 16:41:54 -0300 Subject: [media] [v3,media] av7110: check for negative array offset info->num comes from the user. It's type int. If the user passes in a negative value that would cause memory corruption. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110_ca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index 122c72806916..9fc1dd0ba4c3 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) { ca_slot_info_t *info=(ca_slot_info_t *)parg; - if (info->num > 1) + if (info->num < 0 || info->num > 1) return -EINVAL; av7110->ci_slot[info->num].num = info->num; av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? -- cgit v1.2.3 From b7eccc46a1dae153d0102c161b4ce4bddb3f52ba Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Sat, 8 Jan 2011 18:45:35 -0300 Subject: [media] adv7175: support s_power This patch adds s_power support to adv7175 driver. Power-down is done by power-down all four DACs. Signed-off-by: Christian Gmeiner Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/adv7175.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index f318b51448b3..d2327dbb473f 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -303,11 +303,22 @@ static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0); } +static int adv7175_s_power(struct v4l2_subdev *sd, int on) +{ + if (on) + adv7175_write(sd, 0x01, 0x00); + else + adv7175_write(sd, 0x01, 0x78); + + return 0; +} + /* ----------------------------------------------------------------------- */ static const struct v4l2_subdev_core_ops adv7175_core_ops = { .g_chip_ident = adv7175_g_chip_ident, .init = adv7175_init, + .s_power = adv7175_s_power, }; static const struct v4l2_subdev_video_ops adv7175_video_ops = { -- cgit v1.2.3 From 2dbd61b4651f0bdc6cd5f75a983844b5f3831e17 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 9 Jan 2011 00:53:53 -0300 Subject: [media] ir-raw: fix sparse non-ANSI function warning Fix sparse warning for non-ANSI function declaration: drivers/media/rc/ir-raw.c:247:30: warning: non-ANSI function declaration of function 'ir_raw_get_allowed_protocols' Signed-off-by: Randy Dunlap Cc: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 185baddcbf14..73230ff93b8a 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -233,7 +233,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle); /* used internally by the sysfs interface */ u64 -ir_raw_get_allowed_protocols() +ir_raw_get_allowed_protocols(void) { u64 protocols; mutex_lock(&ir_raw_handler_lock); -- cgit v1.2.3 From 2400982a2e8a8e4e95f0a0e1517bbe63cc88038f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 16 Jan 2011 10:09:13 -0300 Subject: [media] radio-aimslab.c needs #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit e3c92215198cb6aa00ad38db2780faa6b72e0a3f ("[media] radio-aimslab.c: Fix gcc 4.5+ bug") removed the include, but introduced new callers of msleep(): | drivers/media/radio/radio-aimslab.c: In function ‘rt_decvol’: | drivers/media/radio/radio-aimslab.c:76: error: implicit declaration of function ‘msleep’ Signed-off-by: Geert Uytterhoeven Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-aimslab.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 6cc5d130fbc8..4ce10dbeadd8 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -31,6 +31,7 @@ #include /* Modules */ #include /* Initdata */ #include /* request_region */ +#include /* msleep */ #include /* kernel radio structs */ #include /* for KERNEL_VERSION MACRO */ #include /* outb, outb_p */ -- cgit v1.2.3 From 3c61be446ae5c26e2829d37c6b5d02d3af536024 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Thu, 13 Jan 2011 00:46:07 -0300 Subject: [media] tm6000: rework init code Rework device init part. Move common code part to a function. Usefull for register multiple devices like video, radio, vbi etc. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-video.c | 46 +++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 8fe017c3721f..eb9b9f1bc138 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -1450,29 +1450,55 @@ static struct video_device tm6000_template = { * ------------------------------------------------------------------ */ -int tm6000_v4l2_register(struct tm6000_core *dev) +static struct video_device *vdev_init(struct tm6000_core *dev, + const struct video_device + *template, const char *type_name) { - int ret = -1; struct video_device *vfd; vfd = video_device_alloc(); - if(!vfd) { + if (NULL == vfd) + return NULL; + + *vfd = *template; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + vfd->debug = tm6000_debug; + vfd->lock = &dev->lock; + + snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); + + video_set_drvdata(vfd, dev); + return vfd; +} + +int tm6000_v4l2_register(struct tm6000_core *dev) +{ + int ret = -1; + + dev->vfd = vdev_init(dev, &tm6000_template, "video"); + + if (!dev->vfd) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); return -ENOMEM; } - dev->vfd = vfd; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.queued); - memcpy(dev->vfd, &tm6000_template, sizeof(*(dev->vfd))); - dev->vfd->debug = tm6000_debug; - dev->vfd->lock = &dev->lock; + ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr); - vfd->v4l2_dev = &dev->v4l2_dev; - video_set_drvdata(vfd, dev); + if (ret < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + return ret; + } + + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->vfd)); - ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr); printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); return ret; } -- cgit v1.2.3 From 22f37712f29868b393025aa28bee807b4d2783ea Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 16 Jan 2011 05:39:21 -0300 Subject: [media] firedtv: fix remote control with newer Xorg evdev After a recent update of xf86-input-evdev and xorg-server, I noticed that X11 applications did not receive keypresses from the FireDTV infrared remote control anymore. Instead, the Xorg log featured lots of "FireDTV remote control: dropping event due to full queue!" exclamations. The Linux console did not have an issue with the FireDTV's RC though. The fix is to insert EV_SYN events after the key-down/-up events. Signed-off-by: Stefan Richter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/firewire/firedtv-rc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c index fcf3828472b8..f82d4a93feb3 100644 --- a/drivers/media/dvb/firewire/firedtv-rc.c +++ b/drivers/media/dvb/firewire/firedtv-rc.c @@ -172,7 +172,8 @@ void fdtv_unregister_rc(struct firedtv *fdtv) void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) { - u16 *keycode = fdtv->remote_ctrl_dev->keycode; + struct input_dev *idev = fdtv->remote_ctrl_dev; + u16 *keycode = idev->keycode; if (code >= 0x0300 && code <= 0x031f) code = keycode[code - 0x0300]; @@ -188,6 +189,8 @@ void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) return; } - input_report_key(fdtv->remote_ctrl_dev, code, 1); - input_report_key(fdtv->remote_ctrl_dev, code, 0); + input_report_key(idev, code, 1); + input_sync(idev); + input_report_key(idev, code, 0); + input_sync(idev); } -- cgit v1.2.3 From 86e52428eed0507a11ba03c5de731c763bd88480 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 12 Jan 2011 22:50:10 -0300 Subject: [media] lirc_zilog: Reword debug message in ir_probe() Jean Delvare suggested this better format for debug output in ir_probe(). Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index ad29bb1275ab..bf81e3fddf80 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -1195,9 +1195,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) int ret; int have_rx = 0, have_tx = 0; - dprintk("%s: adapter name (%s) nr %d, i2c_device_id name (%s), " - "client addr=0x%02x\n", - __func__, adap->name, adap->nr, id->name, client->addr); + dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n", + __func__, id->name, adap->nr, adap->name, client->addr); /* * FIXME - This probe function probes both the Tx and Rx -- cgit v1.2.3 From 02fcaaa3a52b2bdad8a08a3ee5747f27f27df27d Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 12 Jan 2011 23:31:25 -0300 Subject: [media] lirc_zilog: Remove disable_tx module parameter The only reason to use the lirc_zilog module is for IR Tx, so remove the possibility of disabling IR Tx. If the user needs only IR Rx, then the ir-kbd-i2c module works just fine, and doesn't require a "firmware" image. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index bf81e3fddf80..91125336144e 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -131,7 +131,6 @@ static struct mutex tx_data_lock; /* module parameters */ static int debug; /* debug output */ static int disable_rx; /* disable RX device */ -static int disable_tx; /* disable TX device */ static int minor = -1; /* minor number */ #define dprintk(fmt, args...) \ @@ -1218,12 +1217,10 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ client->addr = 0x70; - if (!disable_tx) { - if (i2c_master_recv(client, &buf, 1) == 1) - have_tx = 1; - dprintk("probe 0x70 @ %s: %s\n", - adap->name, have_tx ? "success" : "failed"); - } + if (i2c_master_recv(client, &buf, 1) == 1) + have_tx = 1; + dprintk("probe 0x70 @ %s: %s\n", + adap->name, have_tx ? "success" : "failed"); if (!disable_rx) { client->addr = 0x71; @@ -1398,6 +1395,3 @@ MODULE_PARM_DESC(debug, "Enable debugging messages"); module_param(disable_rx, bool, 0644); MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device"); - -module_param(disable_tx, bool, 0644); -MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); -- cgit v1.2.3 From 06da95a3ec831dee23f6af58934944a8eb9c3a56 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 13 Jan 2011 02:00:33 -0300 Subject: [media] lirc_zilog: Split struct IR into structs IR, IR_tx, and IR_rx This change is a mostly mechanical break of the main struct IR data structure into common, Rx, and Tx structures. There were some small logical changes required as well, such as eliminating "is_hdpvr", to accomplish this. This change is an intiial step in reworking lirc_zilog to decouple the Rx and Tx handling as much as possible to fit with the new I2C binding model. This change actually makes lirc_zilog a little more broken than it already was - memory deallocation in particular got worse. However, this change makes the remaining problems easier to see and address. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 298 ++++++++++++++++++++++---------------- 1 file changed, 171 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 91125336144e..85e312f33513 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -60,17 +60,9 @@ #include #include -struct IR { - struct lirc_driver l; - - /* Device info */ - struct mutex ir_lock; - int open; - bool is_hdpvr; - +struct IR_rx { /* RX device */ struct i2c_client c_rx; - int have_rx; /* RX device buffer & lock */ struct lirc_buffer buf; @@ -84,11 +76,26 @@ struct IR { /* RX read data */ unsigned char b[3]; + bool hdpvr_data_fmt; +}; +struct IR_tx { /* TX device */ struct i2c_client c_tx; + + /* TX additional actions needed */ int need_boot; - int have_tx; + bool post_tx_ready_poll; +}; + +struct IR { + struct lirc_driver l; + + struct mutex ir_lock; + int open; + + struct IR_rx *rx; + struct IR_tx *tx; }; /* Minor -> data mapping */ @@ -149,8 +156,12 @@ static int add_to_buf(struct IR *ir) int ret; int failures = 0; unsigned char sendbuf[1] = { 0 }; + struct IR_rx *rx = ir->rx; - if (lirc_buffer_full(&ir->buf)) { + if (rx == NULL) + return -ENXIO; + + if (lirc_buffer_full(&rx->buf)) { dprintk("buffer overflow\n"); return -EOVERFLOW; } @@ -170,7 +181,7 @@ static int add_to_buf(struct IR *ir) * Send random "poll command" (?) Windows driver does this * and it is a good point to detect chip failure. */ - ret = i2c_master_send(&ir->c_rx, sendbuf, 1); + ret = i2c_master_send(&rx->c_rx, sendbuf, 1); if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); if (failures >= 3) { @@ -186,44 +197,45 @@ static int add_to_buf(struct IR *ir) set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((100 * HZ + 999) / 1000); - ir->need_boot = 1; + if (ir->tx != NULL) + ir->tx->need_boot = 1; ++failures; mutex_unlock(&ir->ir_lock); continue; } - ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf)); + ret = i2c_master_recv(&rx->c_rx, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); if (ret != sizeof(keybuf)) { zilog_error("i2c_master_recv failed with %d -- " "keeping last read buffer\n", ret); } else { - ir->b[0] = keybuf[3]; - ir->b[1] = keybuf[4]; - ir->b[2] = keybuf[5]; - dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); + rx->b[0] = keybuf[3]; + rx->b[1] = keybuf[4]; + rx->b[2] = keybuf[5]; + dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]); } /* key pressed ? */ - if (ir->is_hdpvr) { + if (rx->hdpvr_data_fmt) { if (got_data && (keybuf[0] == 0x80)) return 0; else if (got_data && (keybuf[0] == 0x00)) return -ENODATA; - } else if ((ir->b[0] & 0x80) == 0) + } else if ((rx->b[0] & 0x80) == 0) return got_data ? 0 : -ENODATA; /* look what we have */ - code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2); + code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2); codes[0] = (code >> 8) & 0xff; codes[1] = code & 0xff; /* return it */ - lirc_buffer_write(&ir->buf, codes); + lirc_buffer_write(&rx->buf, codes); ++got_data; - } while (!lirc_buffer_full(&ir->buf)); + } while (!lirc_buffer_full(&rx->buf)); return 0; } @@ -241,9 +253,13 @@ static int add_to_buf(struct IR *ir) static int lirc_thread(void *arg) { struct IR *ir = arg; + struct IR_rx *rx = ir->rx; + + if (rx == NULL) + return -ENXIO; - if (ir->t_notify != NULL) - complete(ir->t_notify); + if (rx->t_notify != NULL) + complete(rx->t_notify); dprintk("poll thread started\n"); @@ -264,23 +280,23 @@ static int lirc_thread(void *arg) * lost keypresses. */ schedule_timeout((260 * HZ) / 1000); - if (ir->shutdown) + if (rx->shutdown) break; if (!add_to_buf(ir)) - wake_up_interruptible(&ir->buf.wait_poll); + wake_up_interruptible(&rx->buf.wait_poll); } else { /* if device not opened so we can sleep half a second */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/2); } - } while (!ir->shutdown); + } while (!rx->shutdown); - if (ir->t_notify2 != NULL) - wait_for_completion(ir->t_notify2); + if (rx->t_notify2 != NULL) + wait_for_completion(rx->t_notify2); - ir->task = NULL; - if (ir->t_notify != NULL) - complete(ir->t_notify); + rx->task = NULL; + if (rx->t_notify != NULL) + complete(rx->t_notify); dprintk("poll thread ended\n"); return 0; @@ -298,10 +314,10 @@ static int set_use_inc(void *data) * this is completely broken code. lirc_unregister_driver() * must be possible even when the device is open */ - if (ir->c_rx.addr) - i2c_use_client(&ir->c_rx); - if (ir->c_tx.addr) - i2c_use_client(&ir->c_tx); + if (ir->rx != NULL) + i2c_use_client(&ir->rx->c_rx); + if (ir->tx != NULL) + i2c_use_client(&ir->tx->c_tx); return 0; } @@ -310,10 +326,10 @@ static void set_use_dec(void *data) { struct IR *ir = data; - if (ir->c_rx.addr) - i2c_release_client(&ir->c_rx); - if (ir->c_tx.addr) - i2c_release_client(&ir->c_tx); + if (ir->rx) + i2c_release_client(&ir->rx->c_rx); + if (ir->tx) + i2c_release_client(&ir->tx->c_tx); if (ir->l.owner != NULL) module_put(ir->l.owner); } @@ -452,7 +468,7 @@ corrupt: } /* send a block of data to the IR TX device */ -static int send_data_block(struct IR *ir, unsigned char *data_block) +static int send_data_block(struct IR_tx *tx, unsigned char *data_block) { int i, j, ret; unsigned char buf[5]; @@ -466,7 +482,7 @@ static int send_data_block(struct IR *ir, unsigned char *data_block) buf[1 + j] = data_block[i + j]; dprintk("%02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4]); - ret = i2c_master_send(&ir->c_tx, buf, tosend + 1); + ret = i2c_master_send(&tx->c_tx, buf, tosend + 1); if (ret != tosend + 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -477,32 +493,32 @@ static int send_data_block(struct IR *ir, unsigned char *data_block) } /* send boot data to the IR TX device */ -static int send_boot_data(struct IR *ir) +static int send_boot_data(struct IR_tx *tx) { int ret; unsigned char buf[4]; /* send the boot block */ - ret = send_data_block(ir, tx_data->boot_data); + ret = send_data_block(tx, tx_data->boot_data); if (ret != 0) return ret; /* kick it off? */ buf[0] = 0x00; buf[1] = 0x20; - ret = i2c_master_send(&ir->c_tx, buf, 2); + ret = i2c_master_send(&tx->c_tx, buf, 2); if (ret != 2) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } - ret = i2c_master_send(&ir->c_tx, buf, 1); + ret = i2c_master_send(&tx->c_tx, buf, 1); if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } /* Here comes the firmware version... (hopefully) */ - ret = i2c_master_recv(&ir->c_tx, buf, 4); + ret = i2c_master_recv(&tx->c_tx, buf, 4); if (ret != 4) { zilog_error("i2c_master_recv failed with %d\n", ret); return 0; @@ -542,7 +558,7 @@ static void fw_unload(void) } /* load "firmware" for the IR TX device */ -static int fw_load(struct IR *ir) +static int fw_load(struct IR_tx *tx) { int ret; unsigned int i; @@ -557,7 +573,7 @@ static int fw_load(struct IR *ir) } /* Request codeset data file */ - ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev); + ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c_tx.dev); if (ret != 0) { zilog_error("firmware haup-ir-blaster.bin not available " "(%d)\n", ret); @@ -684,20 +700,20 @@ out: } /* initialise the IR TX device */ -static int tx_init(struct IR *ir) +static int tx_init(struct IR_tx *tx) { int ret; /* Load 'firmware' */ - ret = fw_load(ir); + ret = fw_load(tx); if (ret != 0) return ret; /* Send boot block */ - ret = send_boot_data(ir); + ret = send_boot_data(tx); if (ret != 0) return ret; - ir->need_boot = 0; + tx->need_boot = 0; /* Looks good */ return 0; @@ -713,20 +729,20 @@ static loff_t lseek(struct file *filep, loff_t offset, int orig) static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) { struct IR *ir = filep->private_data; - unsigned char buf[ir->buf.chunk_size]; + struct IR_rx *rx = ir->rx; int ret = 0, written = 0; DECLARE_WAITQUEUE(wait, current); dprintk("read called\n"); - if (ir->c_rx.addr == 0) + if (rx == NULL) return -ENODEV; - if (mutex_lock_interruptible(&ir->buf_lock)) + if (mutex_lock_interruptible(&rx->buf_lock)) return -ERESTARTSYS; - if (n % ir->buf.chunk_size) { + if (n % rx->buf.chunk_size) { dprintk("read result = -EINVAL\n"); - mutex_unlock(&ir->buf_lock); + mutex_unlock(&rx->buf_lock); return -EINVAL; } @@ -735,7 +751,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) * to avoid losing scan code (in case when queue is awaken somewhere * between while condition checking and scheduling) */ - add_wait_queue(&ir->buf.wait_poll, &wait); + add_wait_queue(&rx->buf.wait_poll, &wait); set_current_state(TASK_INTERRUPTIBLE); /* @@ -743,7 +759,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) * mode and 'copy_to_user' is happy, wait for data. */ while (written < n && ret == 0) { - if (lirc_buffer_empty(&ir->buf)) { + if (lirc_buffer_empty(&rx->buf)) { /* * According to the read(2) man page, 'written' can be * returned as less than 'n', instead of blocking @@ -763,16 +779,17 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) schedule(); set_current_state(TASK_INTERRUPTIBLE); } else { - lirc_buffer_read(&ir->buf, buf); + unsigned char buf[rx->buf.chunk_size]; + lirc_buffer_read(&rx->buf, buf); ret = copy_to_user((void *)outbuf+written, buf, - ir->buf.chunk_size); - written += ir->buf.chunk_size; + rx->buf.chunk_size); + written += rx->buf.chunk_size; } } - remove_wait_queue(&ir->buf.wait_poll, &wait); + remove_wait_queue(&rx->buf.wait_poll, &wait); set_current_state(TASK_RUNNING); - mutex_unlock(&ir->buf_lock); + mutex_unlock(&rx->buf_lock); dprintk("read result = %s (%d)\n", ret ? "-EFAULT" : "OK", ret); @@ -781,7 +798,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) } /* send a keypress to the IR TX device */ -static int send_code(struct IR *ir, unsigned int code, unsigned int key) +static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) { unsigned char data_block[TX_BLOCK_SIZE]; unsigned char buf[2]; @@ -798,26 +815,26 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key) return ret; /* Send the data block */ - ret = send_data_block(ir, data_block); + ret = send_data_block(tx, data_block); if (ret != 0) return ret; /* Send data block length? */ buf[0] = 0x00; buf[1] = 0x40; - ret = i2c_master_send(&ir->c_tx, buf, 2); + ret = i2c_master_send(&tx->c_tx, buf, 2); if (ret != 2) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } - ret = i2c_master_send(&ir->c_tx, buf, 1); + ret = i2c_master_send(&tx->c_tx, buf, 1); if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } /* Send finished download? */ - ret = i2c_master_recv(&ir->c_tx, buf, 1); + ret = i2c_master_recv(&tx->c_tx, buf, 1); if (ret != 1) { zilog_error("i2c_master_recv failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -831,7 +848,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key) /* Send prepare command? */ buf[0] = 0x00; buf[1] = 0x80; - ret = i2c_master_send(&ir->c_tx, buf, 2); + ret = i2c_master_send(&tx->c_tx, buf, 2); if (ret != 2) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -842,7 +859,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key) * last i2c_master_recv always fails with a -5, so for now, we're * going to skip this whole mess and say we're done on the HD PVR */ - if (ir->is_hdpvr) { + if (!tx->post_tx_ready_poll) { dprintk("sent code %u, key %u\n", code, key); return 0; } @@ -856,7 +873,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key) for (i = 0; i < 20; ++i) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((50 * HZ + 999) / 1000); - ret = i2c_master_send(&ir->c_tx, buf, 1); + ret = i2c_master_send(&tx->c_tx, buf, 1); if (ret == 1) break; dprintk("NAK expected: i2c_master_send " @@ -869,7 +886,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key) } /* Seems to be an 'ok' response */ - i = i2c_master_recv(&ir->c_tx, buf, 1); + i = i2c_master_recv(&tx->c_tx, buf, 1); if (i != 1) { zilog_error("i2c_master_recv failed with %d\n", ret); return -EFAULT; @@ -894,10 +911,11 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, loff_t *ppos) { struct IR *ir = filep->private_data; + struct IR_tx *tx = ir->tx; size_t i; int failures = 0; - if (ir->c_tx.addr == 0) + if (tx == NULL) return -ENODEV; /* Validate user parameters */ @@ -918,15 +936,15 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, } /* Send boot data first if required */ - if (ir->need_boot == 1) { - ret = send_boot_data(ir); + if (tx->need_boot == 1) { + ret = send_boot_data(tx); if (ret == 0) - ir->need_boot = 0; + tx->need_boot = 0; } /* Send the code */ if (ret == 0) { - ret = send_code(ir, (unsigned)command >> 16, + ret = send_code(tx, (unsigned)command >> 16, (unsigned)command & 0xFFFF); if (ret == -EPROTO) { mutex_unlock(&ir->ir_lock); @@ -951,7 +969,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, } set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((100 * HZ + 999) / 1000); - ir->need_boot = 1; + tx->need_boot = 1; ++failures; } else i += sizeof(int); @@ -968,22 +986,23 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, static unsigned int poll(struct file *filep, poll_table *wait) { struct IR *ir = filep->private_data; + struct IR_rx *rx = ir->rx; unsigned int ret; dprintk("poll called\n"); - if (ir->c_rx.addr == 0) + if (rx == NULL) return -ENODEV; - mutex_lock(&ir->buf_lock); + mutex_lock(&rx->buf_lock); - poll_wait(filep, &ir->buf.wait_poll, wait); + poll_wait(filep, &rx->buf.wait_poll, wait); dprintk("poll result = %s\n", - lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM"); + lirc_buffer_empty(&rx->buf) ? "0" : "POLLIN|POLLRDNORM"); - ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM); + ret = lirc_buffer_empty(&rx->buf) ? 0 : (POLLIN|POLLRDNORM); - mutex_unlock(&ir->buf_lock); + mutex_unlock(&rx->buf_lock); return ret; } @@ -993,9 +1012,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) int result; unsigned long mode, features = 0; - if (ir->c_rx.addr != 0) + if (ir->rx != NULL) features |= LIRC_CAN_REC_LIRCCODE; - if (ir->c_tx.addr != 0) + if (ir->tx != NULL) features |= LIRC_CAN_SEND_PULSE; switch (cmd) { @@ -1146,23 +1165,26 @@ static const struct file_operations lirc_fops = { static int ir_remove(struct i2c_client *client) { struct IR *ir = i2c_get_clientdata(client); + struct IR_rx *rx = ir->rx; + struct IR_tx *tx = ir->tx; + /* FIXME make tx, rx senitive */ mutex_lock(&ir->ir_lock); - if (ir->have_rx || ir->have_tx) { + if (rx != NULL || tx != NULL) { DECLARE_COMPLETION(tn); DECLARE_COMPLETION(tn2); /* end up polling thread */ - if (ir->task && !IS_ERR(ir->task)) { - ir->t_notify = &tn; - ir->t_notify2 = &tn2; - ir->shutdown = 1; - wake_up_process(ir->task); + if (rx->task && !IS_ERR(rx->task)) { + rx->t_notify = &tn; + rx->t_notify2 = &tn2; + rx->shutdown = 1; + wake_up_process(rx->task); complete(&tn2); wait_for_completion(&tn); - ir->t_notify = NULL; - ir->t_notify2 = NULL; + rx->t_notify = NULL; + rx->t_notify2 = NULL; } } else { @@ -1173,13 +1195,15 @@ static int ir_remove(struct i2c_client *client) } /* unregister lirc driver */ + /* FIXME make tx, rx senitive */ if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { lirc_unregister_driver(ir->l.minor); ir_devices[ir->l.minor] = NULL; } /* free memory */ - lirc_buffer_free(&ir->buf); + /* FIXME make tx, rx senitive */ + lirc_buffer_free(&rx->buf); mutex_unlock(&ir->ir_lock); kfree(ir); @@ -1240,18 +1264,37 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) have_rx ? "RX only" : "TX only"); ir = kzalloc(sizeof(struct IR), GFP_KERNEL); - if (!ir) goto out_nomem; - ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2); - if (ret) - goto out_nomem; + if (have_tx) { + ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); + if (ir->tx != NULL) { + ir->tx->need_boot = 1; + ir->tx->post_tx_ready_poll = + (id->driver_data & ID_FLAG_HDPVR) ? false : true; + } + } + + if (have_rx) { + ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); + + if (ir->rx == NULL) { + ret = -ENOMEM; + } else { + ir->rx->hdpvr_data_fmt = + (id->driver_data & ID_FLAG_HDPVR) ? true : false; + mutex_init(&ir->rx->buf_lock); + ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2); + } + + if (ret && (ir->rx != NULL)) { + kfree(ir->rx); + ir->rx = NULL; + } + } mutex_init(&ir->ir_lock); - mutex_init(&ir->buf_lock); - ir->need_boot = 1; - ir->is_hdpvr = (id->driver_data & ID_FLAG_HDPVR) ? true : false; memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); ir->l.minor = -1; @@ -1260,40 +1303,38 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, ir); /* initialise RX device */ - if (have_rx) { + if (ir->rx != NULL) { DECLARE_COMPLETION(tn); - memcpy(&ir->c_rx, client, sizeof(struct i2c_client)); + memcpy(&ir->rx->c_rx, client, sizeof(struct i2c_client)); - ir->c_rx.addr = 0x71; - strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME, + ir->rx->c_rx.addr = 0x71; + strlcpy(ir->rx->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME, I2C_NAME_SIZE); /* try to fire up polling thread */ - ir->t_notify = &tn; - ir->task = kthread_run(lirc_thread, ir, "lirc_zilog"); - if (IS_ERR(ir->task)) { - ret = PTR_ERR(ir->task); + ir->rx->t_notify = &tn; + ir->rx->task = kthread_run(lirc_thread, ir, "lirc_zilog"); + if (IS_ERR(ir->rx->task)) { + ret = PTR_ERR(ir->rx->task); zilog_error("lirc_register_driver: cannot run " "poll thread %d\n", ret); goto err; } wait_for_completion(&tn); - ir->t_notify = NULL; - ir->have_rx = 1; + ir->rx->t_notify = NULL; } /* initialise TX device */ - if (have_tx) { - memcpy(&ir->c_tx, client, sizeof(struct i2c_client)); - ir->c_tx.addr = 0x70; - strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME, + if (ir->tx) { + memcpy(&ir->tx->c_tx, client, sizeof(struct i2c_client)); + ir->tx->c_tx.addr = 0x70; + strlcpy(ir->tx->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME, I2C_NAME_SIZE); - ir->have_tx = 1; } /* set lirc_dev stuff */ ir->l.code_length = 13; - ir->l.rbuf = &ir->buf; + ir->l.rbuf = (ir->rx == NULL) ? NULL : &ir->rx->buf; ir->l.fops = &lirc_fops; ir->l.data = ir; ir->l.minor = minor; @@ -1317,9 +1358,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) * after registering with lirc as otherwise hotplug seems to take * 10s to create the lirc device. */ - if (have_tx) { + if (ir->tx != NULL) { /* Special TX init */ - ret = tx_init(ir); + ret = tx_init(ir->tx); if (ret != 0) goto err; } @@ -1327,18 +1368,21 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; err: + /* FIXME - memory deallocation for all error cases needs work */ /* undo everything, hopefully... */ - if (ir->c_rx.addr) - ir_remove(&ir->c_rx); - if (ir->c_tx.addr) - ir_remove(&ir->c_tx); + if (ir->rx != NULL) + ir_remove(&ir->rx->c_rx); + if (ir->tx != NULL) + ir_remove(&ir->tx->c_tx); return ret; out_nodev: + /* FIXME - memory deallocation for all error cases needs work */ zilog_error("no device found\n"); return -ENODEV; out_nomem: + /* FIXME - memory deallocation for all error cases needs work */ zilog_error("memory allocation failure\n"); kfree(ir); return -ENOMEM; -- cgit v1.2.3 From e9b351f64f5c02acf6552d2109bc213bfa133388 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 14 Jan 2011 21:11:22 -0300 Subject: [media] lirc_zilog: Don't make private copies of i2c clients Don't make private copies of the i2c clients provided by the I2C subsystem, don't change the client address field, and don't probe the client addresses - the bridge driver already did that. This moves us to the proper I2C and binding model. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 87 +++++++++++++-------------------------- 1 file changed, 28 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 85e312f33513..00f2e7d3b3e5 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -62,7 +62,7 @@ struct IR_rx { /* RX device */ - struct i2c_client c_rx; + struct i2c_client *c; /* RX device buffer & lock */ struct lirc_buffer buf; @@ -81,7 +81,7 @@ struct IR_rx { struct IR_tx { /* TX device */ - struct i2c_client c_tx; + struct i2c_client *c; /* TX additional actions needed */ int need_boot; @@ -132,9 +132,6 @@ static struct mutex tx_data_lock; ## args) #define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) -#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX" -#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX" - /* module parameters */ static int debug; /* debug output */ static int disable_rx; /* disable RX device */ @@ -181,7 +178,7 @@ static int add_to_buf(struct IR *ir) * Send random "poll command" (?) Windows driver does this * and it is a good point to detect chip failure. */ - ret = i2c_master_send(&rx->c_rx, sendbuf, 1); + ret = i2c_master_send(rx->c, sendbuf, 1); if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); if (failures >= 3) { @@ -205,7 +202,7 @@ static int add_to_buf(struct IR *ir) continue; } - ret = i2c_master_recv(&rx->c_rx, keybuf, sizeof(keybuf)); + ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); if (ret != sizeof(keybuf)) { zilog_error("i2c_master_recv failed with %d -- " @@ -315,9 +312,9 @@ static int set_use_inc(void *data) * must be possible even when the device is open */ if (ir->rx != NULL) - i2c_use_client(&ir->rx->c_rx); + i2c_use_client(ir->rx->c); if (ir->tx != NULL) - i2c_use_client(&ir->tx->c_tx); + i2c_use_client(ir->tx->c); return 0; } @@ -327,9 +324,9 @@ static void set_use_dec(void *data) struct IR *ir = data; if (ir->rx) - i2c_release_client(&ir->rx->c_rx); + i2c_release_client(ir->rx->c); if (ir->tx) - i2c_release_client(&ir->tx->c_tx); + i2c_release_client(ir->tx->c); if (ir->l.owner != NULL) module_put(ir->l.owner); } @@ -482,7 +479,7 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block) buf[1 + j] = data_block[i + j]; dprintk("%02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4]); - ret = i2c_master_send(&tx->c_tx, buf, tosend + 1); + ret = i2c_master_send(tx->c, buf, tosend + 1); if (ret != tosend + 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -506,19 +503,19 @@ static int send_boot_data(struct IR_tx *tx) /* kick it off? */ buf[0] = 0x00; buf[1] = 0x20; - ret = i2c_master_send(&tx->c_tx, buf, 2); + ret = i2c_master_send(tx->c, buf, 2); if (ret != 2) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } - ret = i2c_master_send(&tx->c_tx, buf, 1); + ret = i2c_master_send(tx->c, buf, 1); if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } /* Here comes the firmware version... (hopefully) */ - ret = i2c_master_recv(&tx->c_tx, buf, 4); + ret = i2c_master_recv(tx->c, buf, 4); if (ret != 4) { zilog_error("i2c_master_recv failed with %d\n", ret); return 0; @@ -573,7 +570,7 @@ static int fw_load(struct IR_tx *tx) } /* Request codeset data file */ - ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c_tx.dev); + ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c->dev); if (ret != 0) { zilog_error("firmware haup-ir-blaster.bin not available " "(%d)\n", ret); @@ -822,19 +819,19 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) /* Send data block length? */ buf[0] = 0x00; buf[1] = 0x40; - ret = i2c_master_send(&tx->c_tx, buf, 2); + ret = i2c_master_send(tx->c, buf, 2); if (ret != 2) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } - ret = i2c_master_send(&tx->c_tx, buf, 1); + ret = i2c_master_send(tx->c, buf, 1); if (ret != 1) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } /* Send finished download? */ - ret = i2c_master_recv(&tx->c_tx, buf, 1); + ret = i2c_master_recv(tx->c, buf, 1); if (ret != 1) { zilog_error("i2c_master_recv failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -848,7 +845,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) /* Send prepare command? */ buf[0] = 0x00; buf[1] = 0x80; - ret = i2c_master_send(&tx->c_tx, buf, 2); + ret = i2c_master_send(tx->c, buf, 2); if (ret != 2) { zilog_error("i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -873,7 +870,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) for (i = 0; i < 20; ++i) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((50 * HZ + 999) / 1000); - ret = i2c_master_send(&tx->c_tx, buf, 1); + ret = i2c_master_send(tx->c, buf, 1); if (ret == 1) break; dprintk("NAK expected: i2c_master_send " @@ -886,7 +883,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) } /* Seems to be an 'ok' response */ - i = i2c_master_recv(&tx->c_tx, buf, 1); + i = i2c_master_recv(tx->c, buf, 1); if (i != 1) { zilog_error("i2c_master_recv failed with %d\n", ret); return -EFAULT; @@ -1214,7 +1211,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct IR *ir = NULL; struct i2c_adapter *adap = client->adapter; - char buf; int ret; int have_rx = 0, have_tx = 0; @@ -1239,24 +1235,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) * The external IR receiver is at i2c address 0x71. * The IR transmitter is at 0x70. */ - client->addr = 0x70; - if (i2c_master_recv(client, &buf, 1) == 1) + if (id->driver_data & ID_FLAG_TX) { have_tx = 1; - dprintk("probe 0x70 @ %s: %s\n", - adap->name, have_tx ? "success" : "failed"); - - if (!disable_rx) { - client->addr = 0x71; - if (i2c_master_recv(client, &buf, 1) == 1) - have_rx = 1; - dprintk("probe 0x71 @ %s: %s\n", - adap->name, have_rx ? "success" : "failed"); - } - - if (!(have_rx || have_tx)) { - zilog_error("%s: no devices found\n", adap->name); - goto out_nodev; + } else if (!disable_rx) { + have_rx = 1; + } else { + return -ENXIO; } printk(KERN_INFO "lirc_zilog: chip found with %s\n", @@ -1270,6 +1255,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) if (have_tx) { ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); if (ir->tx != NULL) { + ir->tx->c = client; ir->tx->need_boot = 1; ir->tx->post_tx_ready_poll = (id->driver_data & ID_FLAG_HDPVR) ? false : true; @@ -1282,6 +1268,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) if (ir->rx == NULL) { ret = -ENOMEM; } else { + ir->rx->c = client; ir->rx->hdpvr_data_fmt = (id->driver_data & ID_FLAG_HDPVR) ? true : false; mutex_init(&ir->rx->buf_lock); @@ -1305,11 +1292,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* initialise RX device */ if (ir->rx != NULL) { DECLARE_COMPLETION(tn); - memcpy(&ir->rx->c_rx, client, sizeof(struct i2c_client)); - - ir->rx->c_rx.addr = 0x71; - strlcpy(ir->rx->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME, - I2C_NAME_SIZE); /* try to fire up polling thread */ ir->rx->t_notify = &tn; @@ -1324,14 +1306,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->rx->t_notify = NULL; } - /* initialise TX device */ - if (ir->tx) { - memcpy(&ir->tx->c_tx, client, sizeof(struct i2c_client)); - ir->tx->c_tx.addr = 0x70; - strlcpy(ir->tx->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME, - I2C_NAME_SIZE); - } - /* set lirc_dev stuff */ ir->l.code_length = 13; ir->l.rbuf = (ir->rx == NULL) ? NULL : &ir->rx->buf; @@ -1371,16 +1345,11 @@ err: /* FIXME - memory deallocation for all error cases needs work */ /* undo everything, hopefully... */ if (ir->rx != NULL) - ir_remove(&ir->rx->c_rx); + ir_remove(ir->rx->c); if (ir->tx != NULL) - ir_remove(&ir->tx->c_tx); + ir_remove(ir->tx->c); return ret; -out_nodev: - /* FIXME - memory deallocation for all error cases needs work */ - zilog_error("no device found\n"); - return -ENODEV; - out_nomem: /* FIXME - memory deallocation for all error cases needs work */ zilog_error("memory allocation failure\n"); -- cgit v1.2.3 From a68a9b73fbb05144a71b573f262fbc8ed8f71179 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 15 Jan 2011 01:04:06 -0300 Subject: [media] lirc_zilog: Extensive rework of ir_probe()/ir_remove() This patch is an extensive rework of the ir_probe() and ir_remove() functions. It removes all the double binding and allocation problems on module load. It removes almost all the memory leaks on module exit and on device instantiation failure. Proper destruction of the Rx polling kthread still needs investigation and more work, but it is no worse than it already was. This rework also had side effects that include: - encapsulation of the ir_devices[] array - serialization of access to the ir_devices[] array - semantic change of the module parameter "disable_rx" to "tx_only" If tx_only is true, the module does not claim the i2c_client for the IR Rx function, and only claims and handles the i2c_client for the IR Tx function. This is a first step in providing the option of letting ir-kbd-i2c.c handle IR Rx function, while lirc_zilog handles the IR Tx function. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 344 +++++++++++++++++++++++--------------- 1 file changed, 212 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 00f2e7d3b3e5..f2e8c63fa5bd 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -94,11 +94,13 @@ struct IR { struct mutex ir_lock; int open; + struct i2c_adapter *adapter; struct IR_rx *rx; struct IR_tx *tx; }; /* Minor -> data mapping */ +static struct mutex ir_devices_lock; static struct IR *ir_devices[MAX_IRCTL_DEVICES]; /* Block size for IR transmitter */ @@ -131,10 +133,11 @@ static struct mutex tx_data_lock; #define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \ ## args) #define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) +#define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args) /* module parameters */ static int debug; /* debug output */ -static int disable_rx; /* disable RX device */ +static int tx_only; /* only handle the IR Tx function */ static int minor = -1; /* minor number */ #define dprintk(fmt, args...) \ @@ -252,9 +255,6 @@ static int lirc_thread(void *arg) struct IR *ir = arg; struct IR_rx *rx = ir->rx; - if (rx == NULL) - return -ENXIO; - if (rx->t_notify != NULL) complete(rx->t_notify); @@ -296,6 +296,7 @@ static int lirc_thread(void *arg) complete(rx->t_notify); dprintk("poll thread ended\n"); + /* FIXME - investigate if this is the proper way to shutdown a kthread*/ return 0; } @@ -1058,6 +1059,15 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) return result; } +/* ir_devices_lock must be held */ +static struct IR *find_ir_device_by_minor(unsigned int minor) +{ + if (minor >= MAX_IRCTL_DEVICES) + return NULL; + + return ir_devices[minor]; +} + /* * Open the IR device. Get hold of our IR structure and * stash it in private_data for the file @@ -1066,15 +1076,15 @@ static int open(struct inode *node, struct file *filep) { struct IR *ir; int ret; + unsigned int minor = MINOR(node->i_rdev); /* find our IR struct */ - unsigned minor = MINOR(node->i_rdev); - if (minor >= MAX_IRCTL_DEVICES) { - dprintk("minor %d: open result = -ENODEV\n", - minor); + mutex_lock(&ir_devices_lock); + ir = find_ir_device_by_minor(minor); + mutex_unlock(&ir_devices_lock); + + if (ir == NULL) return -ENODEV; - } - ir = ir_devices[minor]; /* increment in use count */ mutex_lock(&ir->ir_lock); @@ -1159,136 +1169,203 @@ static const struct file_operations lirc_fops = { .release = close }; -static int ir_remove(struct i2c_client *client) +/* FIXME - investigate if this is the proper way to shutdown a kthread */ +static void destroy_rx_kthread(struct IR_rx *rx) { - struct IR *ir = i2c_get_clientdata(client); - struct IR_rx *rx = ir->rx; - struct IR_tx *tx = ir->tx; + DECLARE_COMPLETION(tn); + DECLARE_COMPLETION(tn2); - /* FIXME make tx, rx senitive */ - mutex_lock(&ir->ir_lock); + if (rx == NULL) + return; + + /* end up polling thread */ + if (rx->task && !IS_ERR(rx->task)) { + rx->t_notify = &tn; + rx->t_notify2 = &tn2; + rx->shutdown = 1; + wake_up_process(rx->task); + complete(&tn2); + wait_for_completion(&tn); + rx->t_notify = NULL; + rx->t_notify2 = NULL; + } +} - if (rx != NULL || tx != NULL) { - DECLARE_COMPLETION(tn); - DECLARE_COMPLETION(tn2); - - /* end up polling thread */ - if (rx->task && !IS_ERR(rx->task)) { - rx->t_notify = &tn; - rx->t_notify2 = &tn2; - rx->shutdown = 1; - wake_up_process(rx->task); - complete(&tn2); - wait_for_completion(&tn); - rx->t_notify = NULL; - rx->t_notify2 = NULL; +/* ir_devices_lock must be held */ +static int add_ir_device(struct IR *ir) +{ + int i; + + for (i = 0; i < MAX_IRCTL_DEVICES; i++) + if (ir_devices[i] == NULL) { + ir_devices[i] = ir; + break; } - } else { - mutex_unlock(&ir->ir_lock); - zilog_error("%s: detached from something we didn't " - "attach to\n", __func__); - return -ENODEV; + return i == MAX_IRCTL_DEVICES ? -ENOMEM : i; +} + +/* ir_devices_lock must be held */ +static void del_ir_device(struct IR *ir) +{ + int i; + + for (i = 0; i < MAX_IRCTL_DEVICES; i++) + if (ir_devices[i] == ir) { + ir_devices[i] = NULL; + break; + } +} + +static int ir_remove(struct i2c_client *client) +{ + struct IR *ir = i2c_get_clientdata(client); + + mutex_lock(&ir_devices_lock); + + if (ir == NULL) { + /* We destroyed everything when the first client came through */ + mutex_unlock(&ir_devices_lock); + return 0; } - /* unregister lirc driver */ - /* FIXME make tx, rx senitive */ - if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { - lirc_unregister_driver(ir->l.minor); - ir_devices[ir->l.minor] = NULL; + /* Good-bye LIRC */ + lirc_unregister_driver(ir->l.minor); + + /* Good-bye Rx */ + destroy_rx_kthread(ir->rx); + if (ir->rx != NULL) { + if (ir->rx->buf.fifo_initialized) + lirc_buffer_free(&ir->rx->buf); + i2c_set_clientdata(ir->rx->c, NULL); + kfree(ir->rx); } - /* free memory */ - /* FIXME make tx, rx senitive */ - lirc_buffer_free(&rx->buf); - mutex_unlock(&ir->ir_lock); + /* Good-bye Tx */ + i2c_set_clientdata(ir->tx->c, NULL); + kfree(ir->tx); + + /* Good-bye IR */ + del_ir_device(ir); kfree(ir); + mutex_unlock(&ir_devices_lock); return 0; } -static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) + +/* ir_devices_lock must be held */ +static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter) { + int i; struct IR *ir = NULL; + + for (i = 0; i < MAX_IRCTL_DEVICES; i++) + if (ir_devices[i] != NULL && + ir_devices[i]->adapter == adapter) { + ir = ir_devices[i]; + break; + } + + return ir; +} + +static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct IR *ir; struct i2c_adapter *adap = client->adapter; int ret; - int have_rx = 0, have_tx = 0; + bool tx_probe = false; dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n", __func__, id->name, adap->nr, adap->name, client->addr); /* - * FIXME - This probe function probes both the Tx and Rx - * addresses of the IR microcontroller. - * - * However, the I2C subsystem is passing along one I2C client at a - * time, based on matches to the ir_transceiver_id[] table above. - * The expectation is that each i2c_client address will be probed - * individually by drivers so the I2C subsystem can mark all client - * addresses as claimed or not. - * - * This probe routine causes only one of the client addresses, TX or RX, - * to be claimed. This will cause a problem if the I2C subsystem is - * subsequently triggered to probe unclaimed clients again. - */ - /* - * The external IR receiver is at i2c address 0x71. - * The IR transmitter is at 0x70. + * The IR receiver is at i2c address 0x71. + * The IR transmitter is at i2c address 0x70. */ - if (id->driver_data & ID_FLAG_TX) { - have_tx = 1; - } else if (!disable_rx) { - have_rx = 1; - } else { + if (id->driver_data & ID_FLAG_TX) + tx_probe = true; + else if (tx_only) /* module option */ return -ENXIO; - } - printk(KERN_INFO "lirc_zilog: chip found with %s\n", - have_rx && have_tx ? "RX and TX" : - have_rx ? "RX only" : "TX only"); + zilog_info("%s: probing IR %s on %s (i2c-%d)\n", + __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr); - ir = kzalloc(sizeof(struct IR), GFP_KERNEL); - if (!ir) - goto out_nomem; + mutex_lock(&ir_devices_lock); - if (have_tx) { - ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); - if (ir->tx != NULL) { - ir->tx->c = client; - ir->tx->need_boot = 1; - ir->tx->post_tx_ready_poll = - (id->driver_data & ID_FLAG_HDPVR) ? false : true; + /* Use a single struct IR instance for both the Rx and Tx functions */ + ir = find_ir_device_by_adapter(adap); + if (ir == NULL) { + ir = kzalloc(sizeof(struct IR), GFP_KERNEL); + if (ir == NULL) { + ret = -ENOMEM; + goto out_no_ir; } + /* store for use in ir_probe() again, and open() later on */ + ret = add_ir_device(ir); + if (ret) + goto out_free_ir; + + ir->adapter = adap; + mutex_init(&ir->ir_lock); + + /* set lirc_dev stuff */ + memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); + ir->l.minor = minor; /* module option */ + ir->l.code_length = 13; + ir->l.rbuf = NULL; + ir->l.fops = &lirc_fops; + ir->l.data = ir; + ir->l.dev = &adap->dev; + ir->l.sample_rate = 0; } - if (have_rx) { - ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); + if (tx_probe) { + /* Set up a struct IR_tx instance */ + ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); + if (ir->tx == NULL) { + ret = -ENOMEM; + goto out_free_xx; + } + ir->tx->c = client; + ir->tx->need_boot = 1; + ir->tx->post_tx_ready_poll = + (id->driver_data & ID_FLAG_HDPVR) ? false : true; + } else { + /* Set up a struct IR_rx instance */ + ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); if (ir->rx == NULL) { ret = -ENOMEM; - } else { - ir->rx->c = client; - ir->rx->hdpvr_data_fmt = - (id->driver_data & ID_FLAG_HDPVR) ? true : false; - mutex_init(&ir->rx->buf_lock); - ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2); + goto out_free_xx; } - if (ret && (ir->rx != NULL)) { - kfree(ir->rx); - ir->rx = NULL; - } - } + ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2); + if (ret) + goto out_free_xx; - mutex_init(&ir->ir_lock); + mutex_init(&ir->rx->buf_lock); + ir->rx->c = client; + ir->rx->hdpvr_data_fmt = + (id->driver_data & ID_FLAG_HDPVR) ? true : false; - memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); - ir->l.minor = -1; + /* set lirc_dev stuff */ + ir->l.rbuf = &ir->rx->buf; + } - /* I2C attach to device */ i2c_set_clientdata(client, ir); + /* Proceed only if we have the required Tx and Rx clients ready to go */ + if (ir->tx == NULL || + (ir->rx == NULL && !tx_only)) { + zilog_info("%s: probe of IR %s on %s (i2c-%d) done, waiting on " + "IR %s\n", __func__, tx_probe ? "Tx" : "Rx", + adap->name, adap->nr, tx_probe ? "Rx" : "Tx"); + goto out_ok; + } + /* initialise RX device */ if (ir->rx != NULL) { DECLARE_COMPLETION(tn); @@ -1298,35 +1375,23 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->rx->task = kthread_run(lirc_thread, ir, "lirc_zilog"); if (IS_ERR(ir->rx->task)) { ret = PTR_ERR(ir->rx->task); - zilog_error("lirc_register_driver: cannot run " - "poll thread %d\n", ret); - goto err; + zilog_error("%s: could not start IR Rx polling thread" + "\n", __func__); + goto out_free_xx; } wait_for_completion(&tn); ir->rx->t_notify = NULL; } - /* set lirc_dev stuff */ - ir->l.code_length = 13; - ir->l.rbuf = (ir->rx == NULL) ? NULL : &ir->rx->buf; - ir->l.fops = &lirc_fops; - ir->l.data = ir; - ir->l.minor = minor; - ir->l.dev = &adap->dev; - ir->l.sample_rate = 0; - /* register with lirc */ ir->l.minor = lirc_register_driver(&ir->l); if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { - zilog_error("ir_attach: \"minor\" must be between 0 and %d " - "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor); + zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n", + __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); ret = -EBADRQC; - goto err; + goto out_free_thread; } - /* store this for getting back in open() later on */ - ir_devices[ir->l.minor] = ir; - /* * if we have the tx device, load the 'firmware'. We do this * after registering with lirc as otherwise hotplug seems to take @@ -1336,25 +1401,39 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Special TX init */ ret = tx_init(ir->tx); if (ret != 0) - goto err; + goto out_unregister; } +out_ok: + mutex_unlock(&ir_devices_lock); return 0; -err: - /* FIXME - memory deallocation for all error cases needs work */ - /* undo everything, hopefully... */ - if (ir->rx != NULL) - ir_remove(ir->rx->c); - if (ir->tx != NULL) - ir_remove(ir->tx->c); - return ret; - -out_nomem: - /* FIXME - memory deallocation for all error cases needs work */ - zilog_error("memory allocation failure\n"); +out_unregister: + lirc_unregister_driver(ir->l.minor); +out_free_thread: + destroy_rx_kthread(ir->rx); +out_free_xx: + if (ir->rx != NULL) { + if (ir->rx->buf.fifo_initialized) + lirc_buffer_free(&ir->rx->buf); + if (ir->rx->c != NULL) + i2c_set_clientdata(ir->rx->c, NULL); + kfree(ir->rx); + } + if (ir->tx != NULL) { + if (ir->tx->c != NULL) + i2c_set_clientdata(ir->tx->c, NULL); + kfree(ir->tx); + } +out_free_ir: + del_ir_device(ir); kfree(ir); - return -ENOMEM; +out_no_ir: + zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n", + __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, + ret); + mutex_unlock(&ir_devices_lock); + return ret; } static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) @@ -1370,6 +1449,7 @@ static int __init zilog_init(void) zilog_notify("Zilog/Hauppauge IR driver initializing\n"); mutex_init(&tx_data_lock); + mutex_init(&ir_devices_lock); request_module("firmware_class"); @@ -1406,5 +1486,5 @@ MODULE_PARM_DESC(minor, "Preferred minor device number"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Enable debugging messages"); -module_param(disable_rx, bool, 0644); -MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device"); +module_param(tx_only, bool, 0644); +MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function"); -- cgit v1.2.3 From b757730b022b4b1367d0435fcaa1b0a01e8aef42 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 15 Jan 2011 22:02:05 -0300 Subject: [media] lirc_zilog: Update IR Rx polling kthread start/stop and some printks The IR Rx polling thread was originally a kernel_thread long ago, and had only been minimally converted to a kthread. This patch finishes that conversion by - cleaning up all the unneeded completions - destroying the kthread properly by calling kthread_stop() - changing lirc_thread() to test kthread_should_stop() just before every point where it may sleep - reorganizing the lirc_thread() function so it uses fewer lines - modifying the name of the kthread from "lirc_zilog" to "zilog-rx-i2c-N", so ps will show which kthread polls which Zilog Z8 IR unit. Also some minor tweaks were made to logging emitted by the ir_probe() function. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 113 +++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index f2e8c63fa5bd..f7aa5e4e98b3 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -69,9 +69,6 @@ struct IR_rx { struct mutex buf_lock; /* RX polling thread data */ - struct completion *t_notify; - struct completion *t_notify2; - int shutdown; struct task_struct *task; /* RX read data */ @@ -171,12 +168,20 @@ static int add_to_buf(struct IR *ir) * data and we have space */ do { + if (kthread_should_stop()) + return -ENODATA; + /* * Lock i2c bus for the duration. RX/TX chips interfere so * this is worth it */ mutex_lock(&ir->ir_lock); + if (kthread_should_stop()) { + mutex_unlock(&ir->ir_lock); + return -ENODATA; + } + /* * Send random "poll command" (?) Windows driver does this * and it is a good point to detect chip failure. @@ -196,6 +201,10 @@ static int add_to_buf(struct IR *ir) "trying reset\n"); set_current_state(TASK_UNINTERRUPTIBLE); + if (kthread_should_stop()) { + mutex_unlock(&ir->ir_lock); + return -ENODATA; + } schedule_timeout((100 * HZ + 999) / 1000); if (ir->tx != NULL) ir->tx->need_boot = 1; @@ -205,6 +214,10 @@ static int add_to_buf(struct IR *ir) continue; } + if (kthread_should_stop()) { + mutex_unlock(&ir->ir_lock); + return -ENODATA; + } ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); if (ret != sizeof(keybuf)) { @@ -255,48 +268,35 @@ static int lirc_thread(void *arg) struct IR *ir = arg; struct IR_rx *rx = ir->rx; - if (rx->t_notify != NULL) - complete(rx->t_notify); - dprintk("poll thread started\n"); - do { - if (ir->open) { - set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); - /* - * This is ~113*2 + 24 + jitter (2*repeat gap + - * code length). We use this interval as the chip - * resets every time you poll it (bad!). This is - * therefore just sufficient to catch all of the - * button presses. It makes the remote much more - * responsive. You can see the difference by - * running irw and holding down a button. With - * 100ms, the old polling interval, you'll notice - * breaks in the repeat sequence corresponding to - * lost keypresses. - */ - schedule_timeout((260 * HZ) / 1000); - if (rx->shutdown) - break; - if (!add_to_buf(ir)) - wake_up_interruptible(&rx->buf.wait_poll); - } else { - /* if device not opened so we can sleep half a second */ - set_current_state(TASK_INTERRUPTIBLE); + /* if device not opened, we can sleep half a second */ + if (!ir->open) { schedule_timeout(HZ/2); + continue; } - } while (!rx->shutdown); - if (rx->t_notify2 != NULL) - wait_for_completion(rx->t_notify2); - - rx->task = NULL; - if (rx->t_notify != NULL) - complete(rx->t_notify); + /* + * This is ~113*2 + 24 + jitter (2*repeat gap + code length). + * We use this interval as the chip resets every time you poll + * it (bad!). This is therefore just sufficient to catch all + * of the button presses. It makes the remote much more + * responsive. You can see the difference by running irw and + * holding down a button. With 100ms, the old polling + * interval, you'll notice breaks in the repeat sequence + * corresponding to lost keypresses. + */ + schedule_timeout((260 * HZ) / 1000); + if (kthread_should_stop()) + break; + if (!add_to_buf(ir)) + wake_up_interruptible(&rx->buf.wait_poll); + } dprintk("poll thread ended\n"); - /* FIXME - investigate if this is the proper way to shutdown a kthread*/ return 0; } @@ -1169,25 +1169,12 @@ static const struct file_operations lirc_fops = { .release = close }; -/* FIXME - investigate if this is the proper way to shutdown a kthread */ static void destroy_rx_kthread(struct IR_rx *rx) { - DECLARE_COMPLETION(tn); - DECLARE_COMPLETION(tn2); - - if (rx == NULL) - return; - /* end up polling thread */ - if (rx->task && !IS_ERR(rx->task)) { - rx->t_notify = &tn; - rx->t_notify2 = &tn2; - rx->shutdown = 1; - wake_up_process(rx->task); - complete(&tn2); - wait_for_completion(&tn); - rx->t_notify = NULL; - rx->t_notify2 = NULL; + if (rx != NULL && !IS_ERR_OR_NULL(rx->task)) { + kthread_stop(rx->task); + rx->task = NULL; } } @@ -1290,8 +1277,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) else if (tx_only) /* module option */ return -ENXIO; - zilog_info("%s: probing IR %s on %s (i2c-%d)\n", - __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr); + zilog_info("probing IR %s on %s (i2c-%d)\n", + tx_probe ? "Tx" : "Rx", adap->name, adap->nr); mutex_lock(&ir_devices_lock); @@ -1360,27 +1347,23 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Proceed only if we have the required Tx and Rx clients ready to go */ if (ir->tx == NULL || (ir->rx == NULL && !tx_only)) { - zilog_info("%s: probe of IR %s on %s (i2c-%d) done, waiting on " - "IR %s\n", __func__, tx_probe ? "Tx" : "Rx", - adap->name, adap->nr, tx_probe ? "Rx" : "Tx"); + zilog_info("probe of IR %s on %s (i2c-%d) done. Waiting on " + "IR %s.\n", tx_probe ? "Tx" : "Rx", adap->name, + adap->nr, tx_probe ? "Rx" : "Tx"); goto out_ok; } /* initialise RX device */ if (ir->rx != NULL) { - DECLARE_COMPLETION(tn); - /* try to fire up polling thread */ - ir->rx->t_notify = &tn; - ir->rx->task = kthread_run(lirc_thread, ir, "lirc_zilog"); + ir->rx->task = kthread_run(lirc_thread, ir, + "zilog-rx-i2c-%d", adap->nr); if (IS_ERR(ir->rx->task)) { ret = PTR_ERR(ir->rx->task); zilog_error("%s: could not start IR Rx polling thread" "\n", __func__); goto out_free_xx; } - wait_for_completion(&tn); - ir->rx->t_notify = NULL; } /* register with lirc */ @@ -1404,6 +1387,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto out_unregister; } + zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n", + tx_probe ? "Tx" : "Rx", adap->name, adap->nr); out_ok: mutex_unlock(&ir_devices_lock); return 0; -- cgit v1.2.3 From 8090232a237ab62e22307fc060097da1a283dd66 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 15 Jan 2011 22:32:33 -0300 Subject: [media] lirc_zilog: Remove unneeded tests for existence of the IR Tx function The driver is now structured so that it must handle an IR Tx unit for a Z8 IR chip, or it refuses to handle that Z8 IR chip. This allows us to assume that ir->tx != NULL in a few places in the driver, and also allows us to always report Tx is available to userspace. Get rid of unneeded tests for ir->tx == NULL and always report that Tx is available. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index f7aa5e4e98b3..24d4b52bd79e 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -206,8 +206,7 @@ static int add_to_buf(struct IR *ir) return -ENODATA; } schedule_timeout((100 * HZ + 999) / 1000); - if (ir->tx != NULL) - ir->tx->need_boot = 1; + ir->tx->need_boot = 1; ++failures; mutex_unlock(&ir->ir_lock); @@ -1010,10 +1009,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) int result; unsigned long mode, features = 0; + features |= LIRC_CAN_SEND_PULSE; if (ir->rx != NULL) features |= LIRC_CAN_REC_LIRCCODE; - if (ir->tx != NULL) - features |= LIRC_CAN_SEND_PULSE; switch (cmd) { case LIRC_GET_LENGTH: @@ -1040,15 +1038,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) result = -EINVAL; break; case LIRC_GET_SEND_MODE: - if (!(features&LIRC_CAN_SEND_MASK)) - return -ENOSYS; - result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); break; case LIRC_SET_SEND_MODE: - if (!(features&LIRC_CAN_SEND_MASK)) - return -ENOSYS; - result = get_user(mode, (unsigned long *) arg); if (!result && mode != LIRC_MODE_PULSE) return -EINVAL; @@ -1380,12 +1372,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) * after registering with lirc as otherwise hotplug seems to take * 10s to create the lirc device. */ - if (ir->tx != NULL) { - /* Special TX init */ - ret = tx_init(ir->tx); - if (ret != 0) - goto out_unregister; - } + ret = tx_init(ir->tx); + if (ret != 0) + goto out_unregister; zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n", tx_probe ? "Tx" : "Rx", adap->name, adap->nr); -- cgit v1.2.3 From 6830661ead850c0722e698da5c389db4d85079be Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 15 Jan 2011 22:56:42 -0300 Subject: [media] lirc_zilog: Remove useless struct i2c_driver.command function The ir_command() function is a do-nothing stub; remove it. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 24d4b52bd79e..18fae5442c36 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -1123,7 +1123,6 @@ static struct lirc_driver lirc_template = { static int ir_remove(struct i2c_client *client); static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); #define ID_FLAG_TX 0x01 #define ID_FLAG_HDPVR 0x02 @@ -1143,7 +1142,6 @@ static struct i2c_driver driver = { }, .probe = ir_probe, .remove = ir_remove, - .command = ir_command, .id_table = ir_transceiver_id, }; @@ -1410,12 +1408,6 @@ out_no_ir: return ret; } -static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - /* nothing */ - return 0; -} - static int __init zilog_init(void) { int ret; -- cgit v1.2.3 From c2790c7192be661e14b3d13d8bc187fd87bb9802 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 16 Jan 2011 15:20:07 -0300 Subject: [media] lirc_zilog: Add Andy Walls to copyright notice and authors list Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 18fae5442c36..3fe5f4160194 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -20,6 +20,9 @@ * * parts are cut&pasted from the lirc_i2c.c driver * + * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are + * Copyright (C) 2011 Andy Walls + * * 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 @@ -1441,7 +1444,8 @@ module_exit(zilog_exit); MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)"); MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " - "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver"); + "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, " + "Andy Walls"); MODULE_LICENSE("GPL"); /* for compat with old name, which isn't all that accurate anymore */ MODULE_ALIAS("lirc_pvr150"); -- cgit v1.2.3 From 1f1bfaa0a2e97fbeaf6cc5a07212de0afa3a6232 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 16 Jan 2011 15:21:27 -0300 Subject: [media] lirc_zilog: Update TODO.lirc_zilog Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/TODO.lirc_zilog | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/lirc/TODO.lirc_zilog index 6aa312df4018..2d0263f07937 100644 --- a/drivers/staging/lirc/TODO.lirc_zilog +++ b/drivers/staging/lirc/TODO.lirc_zilog @@ -1,13 +1,37 @@ -The binding between hdpvr and lirc_zilog is currently disabled, +1. Both ir-kbd-i2c and lirc_zilog provide support for RX events. +The 'tx_only' lirc_zilog module parameter will allow ir-kbd-i2c +and lirc_zilog to coexist in the kernel, if the user requires such a set-up. +However the IR unit will not work well without coordination between the +two modules. A shared mutex, for transceiver access locking, needs to be +supplied by bridge drivers, in struct IR_i2_init_data, to both ir-kbd-i2c +and lirc_zilog, before they will coexist usefully. This should be fixed +before moving out of staging. + +2. References and locking need careful examination. For cx18 and ivtv PCI +cards, which are not easily "hot unplugged", the imperfect state of reference +counting and locking is acceptable if not correct. For USB connected units +like HD PVR, PVR USB2, HVR-1900, and HVR1950, the likelyhood of an Ooops on +unplug is probably great. Proper reference counting and locking needs to be +implemented before this module is moved out of staging. + +3. The binding between hdpvr and lirc_zilog is currently disabled, due to an OOPS reported a few years ago when both the hdpvr and cx18 drivers were loaded in his system. More details can be seen at: http://www.mail-archive.com/linux-media@vger.kernel.org/msg09163.html More tests need to be done, in order to fix the reported issue. -There's a conflict between ir-kbd-i2c: Both provide support for RX events. -Such conflict needs to be fixed, before moving it out of staging. +4. In addition to providing a shared mutex for transceiver access +locking, bridge drivers, if able, should provide a chip reset() callback +to lirc_zilog via struct IR_i2c_init_data. cx18 and ivtv already have routines +to perform Z8 chip resets via GPIO manipulations. This will allow lirc_zilog +to bring the chip back to normal when it hangs, in the same places the +original lirc_pvr150 driver code does. This is not strictly needed, so it +is not required to move lirc_zilog out of staging. + +5. Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed +and installed on Hauppauge products. When working on either module, developers +must consider at least the following bridge drivers which mention an IR Rx unit +at address 0x71 (indicative of a Z8): -The way I2C probe works, it will try to register the driver twice, one -for RX and another for TX. The logic needs to be fixed to avoid such -issue. + ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134 -- cgit v1.2.3 From c69a4af6f06916936c8afd44a175e2bf1fbefaec Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 16 Jan 2011 15:45:32 -0300 Subject: [media] ir-kbd-i2c: Add back defaults setting for Zilog Z8's at addr 0x71 This reverts a portion of commit 44243fc2ef99948bc9b046901880885616dd5e89 A commit for which I errantly recommended that defaults for I2C address 0x71 not be set by ir-kbd-i2c.c The pvrusb2 and bttv drivers currently rely on ir-kbd-i2c setting defaults for that address. Until I can get those bridge drivers fixed to properly send IR_i2c_init_data for boards with Zilog Z8 chips, just add back the default settings for I2C address 0x71. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ir-kbd-i2c.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index b173e409cd28..d2b20ad383a3 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -323,6 +323,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc_type = RC_TYPE_OTHER; ir_codes = RC_MAP_AVERMEDIA_CARDBUS; break; + case 0x71: + name = "Hauppauge/Zilog Z8"; + ir->get_key = get_key_haup_xvr; + rc_type = RC_TYPE_RC5; + ir_codes = hauppauge ? RC_MAP_HAUPPAUGE_NEW : RC_MAP_RC5_TV; + break; } /* Let the caller override settings */ -- cgit v1.2.3 From 4999e27a62eaf28e88bc69ab8cf11697e0dda261 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 16 Jan 2011 21:21:03 -0300 Subject: [media] pvrusb2: Provide more information about IR units to lirc_zilog and ir-kbd-i2c When registering an IR Rx device with the I2C subsystem, provide more detailed information about the IR device and default remote configuration for the IR driver modules. Also explicitly register any IR Tx device with the I2C subsystem. Signed-off-by: Andy Walls Acked-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 2 + drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 62 +++++++++++++++------- 2 files changed, 45 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index ac94a8bf883e..305e6aaa844a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -40,6 +40,7 @@ #include "pvrusb2-io.h" #include #include +#include #include "pvrusb2-devattr.h" /* Legal values for PVR2_CID_HSM */ @@ -202,6 +203,7 @@ struct pvr2_hdw { /* IR related */ unsigned int ir_scheme_active; /* IR scheme as seen from the outside */ + struct IR_i2c_init_data ir_init_data; /* params passed to IR modules */ /* Frequency table */ unsigned int freqTable[FREQTABLE_SIZE]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 7cbe18c4ca95..ccc884948f34 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -19,6 +19,7 @@ */ #include +#include #include "pvrusb2-i2c-core.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-debug.h" @@ -48,13 +49,6 @@ module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video, MODULE_PARM_DESC(disable_autoload_ir_video, "1=do not try to autoload ir_video IR receiver"); -/* Mapping of IR schemes to known I2C addresses - if any */ -static const unsigned char ir_video_addresses[] = { - [PVR2_IR_SCHEME_ZILOG] = 0x71, - [PVR2_IR_SCHEME_29XXX] = 0x18, - [PVR2_IR_SCHEME_24XXX] = 0x18, -}; - static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ u8 i2c_addr, /* I2C address we're talking to */ u8 *data, /* Data to write */ @@ -574,26 +568,56 @@ static void do_i2c_scan(struct pvr2_hdw *hdw) static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) { struct i2c_board_info info; - unsigned char addr = 0; + struct IR_i2c_init_data *init_data = &hdw->ir_init_data; if (pvr2_disable_ir_video) { pvr2_trace(PVR2_TRACE_INFO, "Automatic binding of ir_video has been disabled."); return; } - if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) { - addr = ir_video_addresses[hdw->ir_scheme_active]; - } - if (!addr) { + memset(&info, 0, sizeof(struct i2c_board_info)); + switch (hdw->ir_scheme_active) { + case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */ + case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */ + init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; + init_data->type = RC_TYPE_RC5; + init_data->name = hdw->hdw_desc->description; + init_data->polling_interval = 100; /* ms From ir-kbd-i2c */ + /* IR Receiver */ + info.addr = 0x18; + info.platform_data = init_data; + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.", + info.type, info.addr); + i2c_new_device(&hdw->i2c_adap, &info); + break; + case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */ + case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ + init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; + init_data->type = RC_TYPE_RC5; + init_data->name = hdw->hdw_desc->description; + init_data->polling_interval = 260; /* ms From lirc_zilog */ + /* IR Receiver */ + info.addr = 0x71; + info.platform_data = init_data; + strlcpy(info.type, "ir_rx_z8f0811_haup", I2C_NAME_SIZE); + pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.", + info.type, info.addr); + i2c_new_device(&hdw->i2c_adap, &info); + /* IR Trasmitter */ + info.addr = 0x70; + info.platform_data = init_data; + strlcpy(info.type, "ir_tx_z8f0811_haup", I2C_NAME_SIZE); + pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.", + info.type, info.addr); + i2c_new_device(&hdw->i2c_adap, &info); + break; + default: /* The device either doesn't support I2C-based IR or we don't know (yet) how to operate IR on the device. */ - return; + break; } - pvr2_trace(PVR2_TRACE_INFO, - "Binding ir_video to i2c address 0x%02x.", addr); - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - info.addr = addr; - i2c_new_device(&hdw->i2c_adap, &info); } void pvr2_i2c_core_init(struct pvr2_hdw *hdw) -- cgit v1.2.3 From c959acfddb3d24ecfdae1a280a7a1785d9df81d1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 16 Jan 2011 11:03:28 -0300 Subject: [media] v4l2-ctrls: fix missing 'read-only' check VIDIOC_S_CTRL did not check against read-only controls. Even worse, for controls of type CTRL_CLASS it would cause a kernel oops since those controls do not have a s_ctrl op. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ctrls.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 0d1a3d831374..22a9a722f520 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -1824,6 +1824,9 @@ static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val) int ret; int i; + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) + return -EACCES; + v4l2_ctrl_lock(ctrl); /* Reset the 'is_new' flags of the cluster */ -- cgit v1.2.3 From 829fb2dcb5252c5064d12cdaf65d2828420e07b3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 16 Jan 2011 11:21:40 -0300 Subject: [media] v4l2-ctrls: queryctrl shouldn't attempt to replace V4L2_CID_PRIVATE_BASE IDs When queryctrl is called with a V4L2_CID_PRIVATE_BASE control ID, then currently it is replaced by the real internal ID. This is not according to the spec so keep the V4L2_CID_PRIVATE_BASE ID in this case. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ctrls.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 22a9a722f520..01251431fd2a 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -1344,7 +1344,10 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) ctrl = ref->ctrl; memset(qc, 0, sizeof(*qc)); - qc->id = ctrl->id; + if (id >= V4L2_CID_PRIVATE_BASE) + qc->id = id; + else + qc->id = ctrl->id; strlcpy(qc->name, ctrl->name, sizeof(qc->name)); qc->minimum = ctrl->minimum; qc->maximum = ctrl->maximum; -- cgit v1.2.3 From eac9aa005a2e0676d07f1906f9933fd055eb1f0b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Dec 2010 08:57:25 -0300 Subject: [media] v4l: Fix a use-before-set in the control framework v4l2_queryctrl sets the step value based on the control type. That would be fine if it used the control type stored in the V4L2 kernel control object, not the one stored in the userspace ioctl structure that has just been memset to 0. Fix this. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ctrls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 01251431fd2a..ef66d2af0c57 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -1352,7 +1352,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) qc->minimum = ctrl->minimum; qc->maximum = ctrl->maximum; qc->default_value = ctrl->default_value; - if (qc->type == V4L2_CTRL_TYPE_MENU) + if (ctrl->type == V4L2_CTRL_TYPE_MENU) qc->step = 1; else qc->step = ctrl->step; -- cgit v1.2.3 From bd5ba3ba2ead7248124723dac2481d0992e75e91 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 31 Dec 2010 11:27:38 -0300 Subject: [media] w9966: zero device state after a detach After a detach zero the whole device state to ensure a clean slate on the next attach. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/w9966.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 019ee206cbee..fa35639d0c15 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -937,6 +937,7 @@ static void w9966_term(struct w9966 *cam) parport_unregister_device(cam->pdev); w9966_set_state(cam, W9966_STATE_PDEV, 0); } + memset(cam, 0, sizeof(*cam)); } -- cgit v1.2.3 From 6ce3ced4f73e3f0c345f47dc99fd21f2248724a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 31 Dec 2010 11:28:51 -0300 Subject: [media] zoran: use video_device_alloc instead of kmalloc Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 9cdc3bb15b15..9f2bac519647 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -1041,7 +1041,7 @@ zr36057_init (struct zoran *zr) /* allocate memory *before* doing anything to the hardware * in case allocation fails */ zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL); - zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL); + zr->video_dev = video_device_alloc(); if (!zr->stat_com || !zr->video_dev) { dprintk(1, KERN_ERR -- cgit v1.2.3 From 46b633779b299c7fb3d78f153a5034055f99cd45 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 31 Dec 2010 11:47:23 -0300 Subject: [media] v4l2-dev: don't memset video_device.dev Zeroing video_device.dev causes a memory leak if video_set_drvdata was called before video_register_device was called. video_set_drvdata calls dev_set_drvdata which allocates video_device.dev.p. memsetting this will prevent freeing of that memory. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-dev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 359e23290a7e..341764a3a990 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -419,6 +419,10 @@ static int get_index(struct video_device *vdev) * The registration code assigns minor numbers and device node numbers * based on the requested type and registers the new device node with * the kernel. + * + * This function assumes that struct video_device was zeroed when it + * was allocated and does not contain any stale date. + * * An error is returned if no free minor or device node number could be * found, or if the registration of the device node failed. * @@ -440,7 +444,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, int minor_offset = 0; int minor_cnt = VIDEO_NUM_DEVICES; const char *name_base; - void *priv = vdev->dev.p; /* A minor value of -1 marks this video device as never having been registered */ @@ -559,10 +562,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, } /* Part 4: register the device with sysfs */ - memset(&vdev->dev, 0, sizeof(vdev->dev)); - /* The memset above cleared the device's device_private, so - put back the copy we made earlier. */ - vdev->dev.p = priv; vdev->dev.class = &video_class; vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); if (vdev->parent) -- cgit v1.2.3 From 672dcd54774ea1b03da8f2baa1cdbf827927fc85 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Jan 2011 17:48:21 -0300 Subject: [media] v4l2-device: fix 'use-after-freed' oops Fix a bug in v4l2_device_unregister where the sd pointer can be dereferenced after it was freed. Normally the i2c adapter is removed before this function is called. Removing the adapter will also unregister all subdevs on that adapter, so generally v4l2_device_unregister has nothing to do. However, in the case of a platform i2c bus that bus is generally not freed. In that case, after freeing the i2c subdevice the code will fall into the second block when it tests if the subdev is a SPI device. But by that time the subdev is already freed and the kernel oopses. The fix is trivial: continue with the loop after freeing the i2c or spi subdevice. Signed-off-by: Hans Verkuil Reported-by: Daniel Drake Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index b24f002ffa67..ce64fe16bc60 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -100,6 +100,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) is a platform bus, then it is never deleted. */ if (client) i2c_unregister_device(client); + continue; } #endif #if defined(CONFIG_SPI) @@ -108,6 +109,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) if (spi) spi_unregister_device(spi); + continue; } #endif } -- cgit v1.2.3 From 706c57d802394e2fe720ebc929234a678f94e716 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 6 Jan 2011 13:23:13 -0300 Subject: [media] rc/mceusb: timeout should be in ns, not us Fixes an egregious bug in mceusb driver, where the receiver was being put into idle mode far sooner than it should have, thanks to storing a timeout value that in us where it should be ns. Basically, the receiver kept going into idle mode before a trailing space had been fully received, which was causing problems for some protocols, most notably manifesting as lirc userspace never receiving a trailing space for any rc5 signals. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 2d9113493cf0..079353e5d558 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -816,7 +816,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) switch (ir->buf_in[index]) { /* 2-byte return value commands */ case MCE_CMD_S_TIMEOUT: - ir->rc->timeout = MS_TO_US((hi << 8 | lo) / 2); + ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2); break; /* 1-byte return value commands */ @@ -1060,7 +1060,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->timeout = MS_TO_US(1000); + rc->timeout = MS_TO_NS(1000); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; rc->s_tx_carrier = mceusb_set_tx_carrier; -- cgit v1.2.3 From 324b04ba5da7918a2409f8113e46843bfbd89e67 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 14 Jan 2011 16:25:21 -0300 Subject: [media] hdpvr: enable IR part A number of things going on here, but the end result is that the IR part on the hdpvr gets enabled, and can be used with ir-kbd-i2c and/or lirc_zilog. First up, there are some conditional build fixes that come into play whether i2c is built-in or modular. Second, we're swapping out i2c_new_probed_device() for i2c_new_device(), as in my testing, probing always fails, but we *know* that all hdpvr devices have a z8 chip at 0x70 and 0x71. Third, we're poking at an i2c address directly without a client, and writing some magic bits to actually turn on this IR part (this could use some improvement in the future). Fourth, some of the i2c_adapter storage has been reworked, as the existing implementation used to lead to an oops following i2c changes c. 2.6.31. Earlier editions of this patch have been floating around the 'net for a while, including being patched into Fedora kernels, and they *do* work. This specific version isn't yet tested, beyond loading ir-kbd-i2c and confirming that it does bind to the RX address of the hdpvr. [mchehab@redhat.com: I2C_CLASS_TV_ANALOG is not defined. Fix compilation bug] Signed-off-by: Jarod Wilson Acked-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/hdpvr/Makefile | 4 +- drivers/media/video/hdpvr/hdpvr-core.c | 10 ++- drivers/media/video/hdpvr/hdpvr-i2c.c | 119 +++++++++++++++----------------- drivers/media/video/hdpvr/hdpvr-video.c | 7 +- drivers/media/video/hdpvr/hdpvr.h | 2 +- 5 files changed, 65 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile index e0230fcb2e36..3baa9f613ca3 100644 --- a/drivers/media/video/hdpvr/Makefile +++ b/drivers/media/video/hdpvr/Makefile @@ -1,6 +1,4 @@ -hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o - -hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o +hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index f7d1ee55185a..a6572e5ae369 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -378,19 +378,17 @@ static int hdpvr_probe(struct usb_interface *interface, goto error; } -#ifdef CONFIG_I2C - /* until i2c is working properly */ - retval = 0; /* hdpvr_register_i2c_adapter(dev); */ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + retval = hdpvr_register_i2c_adapter(dev); if (retval < 0) { v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n"); goto error; } - /* until i2c is working properly */ - retval = 0; /* hdpvr_register_i2c_ir(dev); */ + retval = hdpvr_register_i2c_ir(dev); if (retval < 0) v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n"); -#endif /* CONFIG_I2C */ +#endif /* let the user know what node this device is now attached to */ v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index 24966aa02a70..45b88cf60d68 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -13,6 +13,8 @@ * */ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + #include #include @@ -28,55 +30,31 @@ #define Z8F0811_IR_TX_I2C_ADDR 0x70 #define Z8F0811_IR_RX_I2C_ADDR 0x71 -static const u8 ir_i2c_addrs[] = { - Z8F0811_IR_TX_I2C_ADDR, - Z8F0811_IR_RX_I2C_ADDR, -}; -static const char * const ir_devicenames[] = { - "ir_tx_z8f0811_hdpvr", - "ir_rx_z8f0811_hdpvr", +static struct i2c_board_info hdpvr_i2c_board_info = { + I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR), + I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR), }; -static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap, - const char *type, u8 addr) +int hdpvr_register_i2c_ir(struct hdpvr_device *dev) { - struct i2c_board_info info; + struct i2c_client *c; struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; - unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, type, I2C_NAME_SIZE); /* Our default information for ir-kbd-i2c.c to use */ - switch (addr) { - case Z8F0811_IR_RX_I2C_ADDR: - init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; - init_data->name = "HD PVR"; - info.platform_data = init_data; - break; - } - - return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? - -1 : 0; -} + init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; + init_data->type = RC_TYPE_RC5; + init_data->name = "HD PVR"; + hdpvr_i2c_board_info.platform_data = init_data; -int hdpvr_register_i2c_ir(struct hdpvr_device *dev) -{ - int i; - int ret = 0; + c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info); - for (i = 0; i < ARRAY_SIZE(ir_i2c_addrs); i++) - ret += hdpvr_new_i2c_ir(dev, dev->i2c_adapter, - ir_devicenames[i], ir_i2c_addrs[i]); - - return ret; + return (c == NULL) ? -ENODEV : 0; } -static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, - char *data, int len) +static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, + unsigned char addr, char *data, int len) { int ret; char *buf = kmalloc(len, GFP_KERNEL); @@ -86,7 +64,7 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_READ, CTRL_READ_REQUEST, - 0x100|addr, 0, buf, len, 1000); + (bus << 8) | addr, 0, buf, len, 1000); if (ret == len) { memcpy(data, buf, len); @@ -99,8 +77,8 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, return ret; } -static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, - char *data, int len) +static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, + unsigned char addr, char *data, int len) { int ret; char *buf = kmalloc(len, GFP_KERNEL); @@ -111,7 +89,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, - 0x100|addr, 0, buf, len, 1000); + (bus << 8) | addr, 0, buf, len, 1000); if (ret < 0) goto error; @@ -121,7 +99,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, 0, 0, buf, 2, 1000); - if (ret == 2) + if ((ret == 2) && (buf[1] == (len - 1))) ret = 0; else if (ret >= 0) ret = -EIO; @@ -146,10 +124,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) - retval = hdpvr_i2c_read(dev, addr, msgs[i].buf, + retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf, msgs[i].len); else - retval = hdpvr_i2c_write(dev, addr, msgs[i].buf, + retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf, msgs[i].len); } @@ -168,30 +146,47 @@ static struct i2c_algorithm hdpvr_algo = { .functionality = hdpvr_functionality, }; +static struct i2c_adapter hdpvr_i2c_adapter_template = { + .name = "Hauppage HD PVR I2C", + .owner = THIS_MODULE, + .algo = &hdpvr_algo, +}; + +static int hdpvr_activate_ir(struct hdpvr_device *dev) +{ + char buffer[8]; + + mutex_lock(&dev->i2c_mutex); + + hdpvr_i2c_read(dev, 0, 0x54, buffer, 1); + + buffer[0] = 0; + buffer[1] = 0x8; + hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); + + buffer[1] = 0x18; + hdpvr_i2c_write(dev, 1, 0x54, buffer, 2); + + mutex_unlock(&dev->i2c_mutex); + + return 0; +} + int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) { - struct i2c_adapter *i2c_adap; int retval = -ENOMEM; - i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if (i2c_adap == NULL) - goto error; + hdpvr_activate_ir(dev); - strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C", - sizeof(i2c_adap->name)); - i2c_adap->algo = &hdpvr_algo; - i2c_adap->owner = THIS_MODULE; - i2c_adap->dev.parent = &dev->udev->dev; + memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template, + sizeof(struct i2c_adapter)); + dev->i2c_adapter.dev.parent = &dev->udev->dev; - i2c_set_adapdata(i2c_adap, dev); + i2c_set_adapdata(&dev->i2c_adapter, dev); - retval = i2c_add_adapter(i2c_adap); + retval = i2c_add_adapter(&dev->i2c_adapter); - if (!retval) - dev->i2c_adapter = i2c_adap; - else - kfree(i2c_adap); - -error: return retval; } + +#endif diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index d38fe1043e47..514aea76eaa5 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -1220,12 +1220,9 @@ static void hdpvr_device_release(struct video_device *vdev) v4l2_device_unregister(&dev->v4l2_dev); /* deregister I2C adapter */ -#ifdef CONFIG_I2C +#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE) mutex_lock(&dev->i2c_mutex); - if (dev->i2c_adapter) - i2c_del_adapter(dev->i2c_adapter); - kfree(dev->i2c_adapter); - dev->i2c_adapter = NULL; + i2c_del_adapter(&dev->i2c_adapter); mutex_unlock(&dev->i2c_mutex); #endif /* CONFIG_I2C */ diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h index 37f1e4c7675d..29f74269400c 100644 --- a/drivers/media/video/hdpvr/hdpvr.h +++ b/drivers/media/video/hdpvr/hdpvr.h @@ -106,7 +106,7 @@ struct hdpvr_device { struct work_struct worker; /* I2C adapter */ - struct i2c_adapter *i2c_adapter; + struct i2c_adapter i2c_adapter; /* I2C lock */ struct mutex i2c_mutex; -- cgit v1.2.3 From 559d162e1ebcdb61e89f154f2c2db376af072b0e Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 14 Jan 2011 16:40:32 -0300 Subject: [media] hdpvr: reduce latency of i2c read/write w/recycled buffer The current hdpvr code kmalloc's a new buffer for every i2c read and write. Rather than do that, lets allocate a buffer in the driver's device struct and just use that every time. The size I've chosen for the buffer is the maximum size I could ascertain might be used by either ir-kbd-i2c or lirc_zilog, plus a bit of padding (lirc_zilog may use up to 100 bytes on tx, rounded that up to 128). Note that this might also remedy user reports of very sluggish behavior of IR receive with hdpvr hardware. v2: make sure (len <= (dev->i2c_buf)) [Jean Delvare] Reported-by: Jean Delvare Acked-by: Jean Delvare Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/hdpvr/hdpvr-i2c.c | 30 +++++++++++++----------------- drivers/media/video/hdpvr/hdpvr.h | 3 +++ 2 files changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index 45b88cf60d68..89b71faeaac2 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -57,23 +57,21 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, unsigned char addr, char *data, int len) { int ret; - char *buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; + + if (len > sizeof(dev->i2c_buf)) + return -EINVAL; ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_READ, CTRL_READ_REQUEST, - (bus << 8) | addr, 0, buf, len, 1000); + (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); if (ret == len) { - memcpy(data, buf, len); + memcpy(data, &dev->i2c_buf, len); ret = 0; } else if (ret >= 0) ret = -EIO; - kfree(buf); - return ret; } @@ -81,31 +79,29 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, unsigned char addr, char *data, int len) { int ret; - char *buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - memcpy(buf, data, len); + if (len > sizeof(dev->i2c_buf)) + return -EINVAL; + + memcpy(&dev->i2c_buf, data, len); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, - (bus << 8) | addr, 0, buf, len, 1000); + (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); if (ret < 0) - goto error; + return ret; ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, - 0, 0, buf, 2, 1000); + 0, 0, &dev->i2c_buf, 2, 1000); - if ((ret == 2) && (buf[1] == (len - 1))) + if ((ret == 2) && (dev->i2c_buf[1] == (len - 1))) ret = 0; else if (ret >= 0) ret = -EIO; -error: - kfree(buf); return ret; } diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h index 29f74269400c..ee74e3be9a6a 100644 --- a/drivers/media/video/hdpvr/hdpvr.h +++ b/drivers/media/video/hdpvr/hdpvr.h @@ -25,6 +25,7 @@ KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE) #define HDPVR_MAX 8 +#define HDPVR_I2C_MAX_SIZE 128 /* Define these values to match your devices */ #define HD_PVR_VENDOR_ID 0x2040 @@ -109,6 +110,8 @@ struct hdpvr_device { struct i2c_adapter i2c_adapter; /* I2C lock */ struct mutex i2c_mutex; + /* I2C message buffer space */ + char i2c_buf[HDPVR_I2C_MAX_SIZE]; /* For passing data to ir-kbd-i2c */ struct IR_i2c_init_data ir_i2c_init_data; -- cgit v1.2.3 From 88914bdf8c677ebd7e797adac05e47303fd6ac77 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 17 Jan 2011 16:02:00 -0300 Subject: [media] staging/lirc: fix mem leaks and ptr err usage When the lirc drivers were converted over to using memdup_user, I mistakenly also removed corresponding calls to kfree. Add those back. I also screwed up on the allocation error check in lirc_serial, using if (PTR_ERR()) instead of if (IS_ERR()), which broke transmit. Reported-by: Jiri Fojtasek Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_imon.c | 1 + drivers/staging/lirc/lirc_it87.c | 1 + drivers/staging/lirc/lirc_parallel.c | 19 ++++++++++++++----- drivers/staging/lirc/lirc_sasem.c | 1 + drivers/staging/lirc/lirc_serial.c | 3 ++- drivers/staging/lirc/lirc_sir.c | 1 + 6 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c index 0da6b9518af9..235cab0eb087 100644 --- a/drivers/staging/lirc/lirc_imon.c +++ b/drivers/staging/lirc/lirc_imon.c @@ -447,6 +447,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, exit: mutex_unlock(&context->ctx_lock); + kfree(data_buf); return (!retval) ? n_bytes : retval; } diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c index 929ae5795467..5938616f3e8f 100644 --- a/drivers/staging/lirc/lirc_it87.c +++ b/drivers/staging/lirc/lirc_it87.c @@ -232,6 +232,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, i++; } terminate_send(tx_buf[i - 1]); + kfree(tx_buf); return n; } diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c index dfd2c447e67d..3a9c09881b2b 100644 --- a/drivers/staging/lirc/lirc_parallel.c +++ b/drivers/staging/lirc/lirc_parallel.c @@ -376,6 +376,7 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, unsigned long flags; int counttimer; int *wbuf; + ssize_t ret; if (!is_claimed) return -EBUSY; @@ -393,8 +394,10 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, if (timer == 0) { /* try again if device is ready */ timer = init_lirc_timer(); - if (timer == 0) - return -EIO; + if (timer == 0) { + ret = -EIO; + goto out; + } } /* adjust values from usecs */ @@ -420,7 +423,8 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, if (check_pselecd && (in(1) & LP_PSELECD)) { lirc_off(); local_irq_restore(flags); - return -EIO; + ret = -EIO; + goto out; } } while (counttimer < wbuf[i]); i++; @@ -436,7 +440,8 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, level = newlevel; if (check_pselecd && (in(1) & LP_PSELECD)) { local_irq_restore(flags); - return -EIO; + ret = -EIO; + goto out; } } while (counttimer < wbuf[i]); i++; @@ -445,7 +450,11 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, #else /* place code that handles write without external timer here */ #endif - return n; + ret = n; +out: + kfree(wbuf); + + return ret; } static unsigned int lirc_poll(struct file *file, poll_table *wait) diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c index 998485ebdbce..925eabe14854 100644 --- a/drivers/staging/lirc/lirc_sasem.c +++ b/drivers/staging/lirc/lirc_sasem.c @@ -448,6 +448,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, exit: mutex_unlock(&context->ctx_lock); + kfree(data_buf); return (!retval) ? n_bytes : retval; } diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c index 9bcf149c4260..1c3099b388e0 100644 --- a/drivers/staging/lirc/lirc_serial.c +++ b/drivers/staging/lirc/lirc_serial.c @@ -966,7 +966,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, if (n % sizeof(int) || count % 2 == 0) return -EINVAL; wbuf = memdup_user(buf, n); - if (PTR_ERR(wbuf)) + if (IS_ERR(wbuf)) return PTR_ERR(wbuf); spin_lock_irqsave(&hardware[type].lock, flags); if (type == LIRC_IRDEO) { @@ -981,6 +981,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, } off(); spin_unlock_irqrestore(&hardware[type].lock, flags); + kfree(wbuf); return n; } diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c index c553ab626238..76be7b8c6209 100644 --- a/drivers/staging/lirc/lirc_sir.c +++ b/drivers/staging/lirc/lirc_sir.c @@ -330,6 +330,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, size_t n, /* enable receiver */ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; #endif + kfree(tx_buf); return count; } -- cgit v1.2.3 From c9f2954964df1490373065558f3156379c7a2454 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 30 Nov 2010 13:07:21 -0600 Subject: lguest: Use this_cpu_ops Use this_cpu_ops in a couple of places in lguest. Signed-off-by: Christoph Lameter Signed-off-by: Rusty Russell --- arch/x86/lguest/boot.c | 2 +- drivers/lguest/page_tables.c | 2 +- drivers/lguest/x86/core.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 4996cf5f73a0..2902ee234614 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -824,7 +824,7 @@ static void __init lguest_init_IRQ(void) for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { /* Some systems map "vectors" to interrupts weirdly. Not us! */ - __get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR; + __this_cpu_write(vector_irq[i]) = i - FIRST_EXTERNAL_VECTOR; if (i != SYSCALL_VECTOR) set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); } diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index 04b22128a474..d21578ee95de 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -1137,7 +1137,7 @@ void free_guest_pagetable(struct lguest *lg) */ void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) { - pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages); + pte_t *switcher_pte_page = __this_cpu_read(switcher_pte_pages); pte_t regs_pte; #ifdef CONFIG_X86_PAE diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index b4eb675a807e..bd4b5910473b 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -90,8 +90,8 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages) * meanwhile). If that's not the case, we pretend everything in the * Guest has changed. */ - if (__get_cpu_var(lg_last_cpu) != cpu || cpu->last_pages != pages) { - __get_cpu_var(lg_last_cpu) = cpu; + if (__this_cpu_read(lg_last_cpu) != cpu || cpu->last_pages != pages) { + __this_cpu_read(lg_last_cpu) = cpu; cpu->last_pages = pages; cpu->changed = CHANGED_ALL; } -- cgit v1.2.3 From ced05dd741779986861fe7369fe002f542d6fa34 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 20 Jan 2011 21:37:29 -0600 Subject: lguest: compile fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arch/x86/lguest/boot.c: In function ‘lguest_init_IRQ’: arch/x86/lguest/boot.c:824: error: macro "__this_cpu_write" requires 2 arguments, but only 1 given arch/x86/lguest/boot.c:824: error: ‘__this_cpu_write’ undeclared (first use in this function) arch/x86/lguest/boot.c:824: error: (Each undeclared identifier is reported only once arch/x86/lguest/boot.c:824: error: for each function it appears in.) drivers/lguest/x86/core.c: In function ‘copy_in_guest_info’: drivers/lguest/x86/core.c:94: error: lvalue required as left operand of assignment Signed-off-by: Rusty Russell --- arch/x86/lguest/boot.c | 2 +- drivers/lguest/x86/core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 2902ee234614..eba687f0cc0c 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -824,7 +824,7 @@ static void __init lguest_init_IRQ(void) for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { /* Some systems map "vectors" to interrupts weirdly. Not us! */ - __this_cpu_write(vector_irq[i]) = i - FIRST_EXTERNAL_VECTOR; + __this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR); if (i != SYSCALL_VECTOR) set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); } diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index bd4b5910473b..9f1659c3d1f3 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -91,7 +91,7 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages) * Guest has changed. */ if (__this_cpu_read(lg_last_cpu) != cpu || cpu->last_pages != pages) { - __this_cpu_read(lg_last_cpu) = cpu; + __this_cpu_write(lg_last_cpu, cpu); cpu->last_pages = pages; cpu->changed = CHANGED_ALL; } -- cgit v1.2.3 From 8b3bb3ecf1934ac4a7005ad9017de1127e2fbd2f Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Fri, 7 Jan 2011 02:55:06 -0600 Subject: virtio: remove virtio-pci root device We sometimes need to map between the virtio device and the given pci device. One such use is OS installer that gets the boot pci device from BIOS and needs to find the relevant block device. Since it can't, installation fails. Instead of creating a top-level devices/virtio-pci directory, create each device under the corresponding pci device node. Symlinks to all virtio-pci devices can be found under the pci driver link in bus/pci/drivers/virtio-pci/devices, and all virtio devices under drivers/bus/virtio/devices. Signed-off-by: Milton Miller Signed-off-by: Rusty Russell Acked-by: Michael S. Tsirkin Tested-by: Michael S. Tsirkin Acked-by: Gleb Natapov Tested-by: "Daniel P. Berrange" Cc: stable@kernel.org --- drivers/virtio/virtio_pci.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index ef8d9d558fc7..4fb5b2bf2348 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -96,11 +96,6 @@ static struct pci_device_id virtio_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, virtio_pci_id_table); -/* A PCI device has it's own struct device and so does a virtio device so - * we create a place for the virtio devices to show up in sysfs. I think it - * would make more sense for virtio to not insist on having it's own device. */ -static struct device *virtio_pci_root; - /* Convert a generic virtio device to our structure */ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) { @@ -629,7 +624,7 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev, if (vp_dev == NULL) return -ENOMEM; - vp_dev->vdev.dev.parent = virtio_pci_root; + vp_dev->vdev.dev.parent = &pci_dev->dev; vp_dev->vdev.dev.release = virtio_pci_release_dev; vp_dev->vdev.config = &virtio_pci_config_ops; vp_dev->pci_dev = pci_dev; @@ -717,17 +712,7 @@ static struct pci_driver virtio_pci_driver = { static int __init virtio_pci_init(void) { - int err; - - virtio_pci_root = root_device_register("virtio-pci"); - if (IS_ERR(virtio_pci_root)) - return PTR_ERR(virtio_pci_root); - - err = pci_register_driver(&virtio_pci_driver); - if (err) - root_device_unregister(virtio_pci_root); - - return err; + return pci_register_driver(&virtio_pci_driver); } module_init(virtio_pci_init); @@ -735,7 +720,6 @@ module_init(virtio_pci_init); static void __exit virtio_pci_exit(void) { pci_unregister_driver(&virtio_pci_driver); - root_device_unregister(virtio_pci_root); } module_exit(virtio_pci_exit); -- cgit v1.2.3 From b23fffd778c312b8fb258d342051fcbdf6712128 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 20 Jan 2011 13:14:10 -0800 Subject: ACPI / Battery: remove battery refresh on resume This partially reverts commit da8aeb92d4853f37e281f11fddf61f9c7d84c3cd ("ACPI / Battery: Update information on info notification and resume"), which causes a hang on resume on at least some machines. This bug was bisected on an ASUS EeePC 901, which hangs at resume time if we do that "acpi_battery_refresh(battery)" in the battery resume function. Rafael suspects we'll still need to refresh the sysfs files upon resume, but that that can be done from a PM notifier (that will run after thawing user space). Bisected-and-tested-by: Linus Torvalds Cc: Matthew Garrett Cc: Len Brown Acked-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds --- drivers/acpi/battery.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 68bc227e7c4c..ac1a599f5147 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -998,7 +998,6 @@ static int acpi_battery_resume(struct acpi_device *device) if (!device) return -EINVAL; battery = acpi_driver_data(device); - acpi_battery_refresh(battery); battery->update_time = 0; acpi_battery_update(battery); return 0; -- cgit v1.2.3 From 6044565af458e7fa6e748bff437ecc49dea88d79 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 15 Jan 2011 18:19:48 +0100 Subject: firewire: core: fix unstable I/O with Canon camcorder Regression since commit 10389536742c, "firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder": The camcorder Canon MV5i generates lots of bus resets when asynchronous requests are sent to it (e.g. Config ROM read requests or FCP Command write requests) if the camcorder is not root node. This causes drop- outs in videos or makes the camcorder entirely inaccessible. https://bugzilla.redhat.com/show_bug.cgi?id=633260 Fix this by allowing any Canon device, even if it is a pre-1394a IRM like MV5i are, to remain root node (if it is at least Cycle Master capable). With the FireWire controller cards that I tested, MV5i always becomes root node when plugged in and left to its own devices. Reported-by: Ralf Lange Signed-off-by: Stefan Richter Cc: # 2.6.32.y and newer --- drivers/firewire/core-card.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index be0492398ef9..24ff35511e2b 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -75,6 +75,8 @@ static size_t config_rom_length = 1 + 4 + 1 + 1; #define BIB_IRMC ((1) << 31) #define NODE_CAPABILITIES 0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */ +#define CANON_OUI 0x000085 + static void generate_config_rom(struct fw_card *card, __be32 *config_rom) { struct fw_descriptor *desc; @@ -284,6 +286,7 @@ static void bm_work(struct work_struct *work) bool root_device_is_running; bool root_device_is_cmc; bool irm_is_1394_1995_only; + bool keep_this_irm; spin_lock_irq(&card->lock); @@ -305,6 +308,10 @@ static void bm_work(struct work_struct *work) irm_is_1394_1995_only = irm_device && irm_device->config_rom && (irm_device->config_rom[2] & 0x000000f0) == 0; + /* Canon MV5i works unreliably if it is not root node. */ + keep_this_irm = irm_device && irm_device->config_rom && + irm_device->config_rom[3] >> 8 == CANON_OUI; + root_id = root_node->node_id; irm_id = card->irm_node->node_id; local_id = card->local_node->node_id; @@ -333,7 +340,7 @@ static void bm_work(struct work_struct *work) goto pick_me; } - if (irm_is_1394_1995_only) { + if (irm_is_1394_1995_only && !keep_this_irm) { new_root_id = local_id; fw_notify("%s, making local node (%02x) root.\n", "IRM is not 1394a compliant", new_root_id); @@ -382,7 +389,7 @@ static void bm_work(struct work_struct *work) spin_lock_irq(&card->lock); - if (rcode != RCODE_COMPLETE) { + if (rcode != RCODE_COMPLETE && !keep_this_irm) { /* * The lock request failed, maybe the IRM * isn't really IRM capable after all. Let's -- cgit v1.2.3 From 74a145049938b73b7e5421423f64a254d4192d3f Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 29 Nov 2010 04:09:52 +0200 Subject: firewire: net: invalidate ARP entries of removed nodes This makes it possible to resume communication with a node that dropped off the bus for a brief period. Otherwise communication will only be possible after ARP cache entry timeouts. Signed-off-by: Maxim Levitsky Signed-off-by: Stefan Richter (rebased) --- drivers/firewire/net.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index c2e194c58667..7ed08fd1214e 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -191,6 +191,7 @@ struct fwnet_peer { struct fwnet_device *dev; u64 guid; u64 fifo; + __be32 ip; /* guarded by dev->lock */ struct list_head pd_list; /* received partial datagrams */ @@ -570,6 +571,8 @@ static int fwnet_finish_incoming_packet(struct net_device *net, peer->speed = sspd; if (peer->max_payload > max_payload) peer->max_payload = max_payload; + + peer->ip = arp1394->sip; } spin_unlock_irqrestore(&dev->lock, flags); @@ -1470,6 +1473,7 @@ static int fwnet_add_peer(struct fwnet_device *dev, peer->dev = dev; peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; peer->fifo = FWNET_NO_FIFO_ADDR; + peer->ip = 0; INIT_LIST_HEAD(&peer->pd_list); peer->pdg_size = 0; peer->datagram_label = 0; @@ -1589,10 +1593,13 @@ static int fwnet_remove(struct device *_dev) mutex_lock(&fwnet_device_mutex); + net = dev->netdev; + if (net && peer->ip) + arp_invalidate(net, peer->ip); + fwnet_remove_peer(peer, dev); if (list_empty(&dev->peer_list)) { - net = dev->netdev; unregister_netdev(net); if (dev->local_fifo != FWNET_NO_FIFO_ADDR) -- cgit v1.2.3 From 324719978dbb3ffad5a2e3d85af6c5dbbb766b99 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 20 Jan 2011 00:07:46 +0100 Subject: firewire: net: is not experimental anymore thanks to Clemens' and Maxim's fixes to firewire-ohci and -net in the last two kernel releases. Signed-off-by: Stefan Richter --- drivers/firewire/Kconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 68f942cb30f2..0c56989cd907 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -49,15 +49,13 @@ config FIREWIRE_SBP2 configuration section. config FIREWIRE_NET - tristate "IP networking over 1394 (EXPERIMENTAL)" - depends on FIREWIRE && INET && EXPERIMENTAL + tristate "IP networking over 1394" + depends on FIREWIRE && INET help This enables IPv4 over IEEE 1394, providing IP connectivity with other implementations of RFC 2734 as found on several operating systems. Multicast support is currently limited. - NOTE, this driver is not stable yet! - To compile this driver as a module, say M here: The module will be called firewire-net. -- cgit v1.2.3 From d7b9935a347ae954be907ea3d5eb4564ff124c53 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 20 Jan 2011 13:19:55 -0800 Subject: i915: Fix i915 suspend delay During system suspend, the "wait for ring buffer to empty" loop would always time out after three seconds, because the faster cached ring buffer head read would always return zero. Force the slow-and-careful PIO read on all but the first iterations of the loop to fix it. This also removes the unused (and useless) 'actual_head' variable that tried to approximate doing this, but did it incorrectly. Cc: Chris Wilson Cc: Rafael J. Wysocki Cc: Jesse Barnes Cc: Dave Airlie Cc: DRI mailing list Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 03e337072517..f6b9baa6a63d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -928,6 +928,7 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) { + int reread = 0; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; unsigned long end; @@ -940,9 +941,8 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) * fallback to the slow and accurate path. */ head = intel_read_status_page(ring, 4); - if (head < ring->actual_head) + if (reread) head = I915_READ_HEAD(ring); - ring->actual_head = head; ring->head = head & HEAD_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) @@ -961,6 +961,7 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) msleep(1); if (atomic_read(&dev_priv->mm.wedged)) return -EAGAIN; + reread = 1; } while (!time_after(jiffies, end)); trace_i915_ring_wait_end (dev); return -EBUSY; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index be9087e4c9be..5b0abfa881fc 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -47,7 +47,6 @@ struct intel_ring_buffer { struct drm_device *dev; struct drm_i915_gem_object *obj; - u32 actual_head; u32 head; u32 tail; int space; -- cgit v1.2.3 From 6a108a14fa356ef607be308b68337939e56ea94e Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 20 Jan 2011 14:44:16 -0800 Subject: kconfig: rename CONFIG_EMBEDDED to CONFIG_EXPERT The meaning of CONFIG_EMBEDDED has long since been obsoleted; the option is used to configure any non-standard kernel with a much larger scope than only small devices. This patch renames the option to CONFIG_EXPERT in init/Kconfig and fixes references to the option throughout the kernel. A new CONFIG_EMBEDDED option is added that automatically selects CONFIG_EXPERT when enabled and can be used in the future to isolate options that should only be considered for embedded systems (RISC architectures, SLOB, etc). Calling the option "EXPERT" more accurately represents its intention: only expert users who understand the impact of the configuration changes they are making should enable it. Reviewed-by: Ingo Molnar Acked-by: David Woodhouse Signed-off-by: David Rientjes Cc: Greg KH Cc: "David S. Miller" Cc: Jens Axboe Cc: Arnd Bergmann Cc: Robin Holt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/configs/ag5evm_defconfig | 2 +- arch/arm/configs/am200epdkit_defconfig | 2 +- arch/arm/configs/at572d940hfek_defconfig | 2 +- arch/arm/configs/badge4_defconfig | 2 +- arch/arm/configs/bcmring_defconfig | 2 +- arch/arm/configs/cm_x2xx_defconfig | 2 +- arch/arm/configs/colibri_pxa270_defconfig | 2 +- arch/arm/configs/collie_defconfig | 2 +- arch/arm/configs/corgi_defconfig | 2 +- arch/arm/configs/da8xx_omapl_defconfig | 2 +- arch/arm/configs/davinci_all_defconfig | 2 +- arch/arm/configs/dove_defconfig | 2 +- arch/arm/configs/ebsa110_defconfig | 2 +- arch/arm/configs/edb7211_defconfig | 2 +- arch/arm/configs/em_x270_defconfig | 2 +- arch/arm/configs/ep93xx_defconfig | 2 +- arch/arm/configs/eseries_pxa_defconfig | 2 +- arch/arm/configs/ezx_defconfig | 2 +- arch/arm/configs/footbridge_defconfig | 2 +- arch/arm/configs/fortunet_defconfig | 2 +- arch/arm/configs/h5000_defconfig | 2 +- arch/arm/configs/imote2_defconfig | 2 +- arch/arm/configs/ixp2000_defconfig | 2 +- arch/arm/configs/ixp23xx_defconfig | 2 +- arch/arm/configs/ixp4xx_defconfig | 2 +- arch/arm/configs/loki_defconfig | 2 +- arch/arm/configs/lpd7a400_defconfig | 2 +- arch/arm/configs/lpd7a404_defconfig | 2 +- arch/arm/configs/magician_defconfig | 2 +- arch/arm/configs/mv78xx0_defconfig | 2 +- arch/arm/configs/mx1_defconfig | 2 +- arch/arm/configs/mx21_defconfig | 2 +- arch/arm/configs/mx27_defconfig | 2 +- arch/arm/configs/mx3_defconfig | 2 +- arch/arm/configs/mx51_defconfig | 2 +- arch/arm/configs/nhk8815_defconfig | 2 +- arch/arm/configs/omap1_defconfig | 2 +- arch/arm/configs/omap2plus_defconfig | 2 +- arch/arm/configs/orion5x_defconfig | 2 +- arch/arm/configs/pcm027_defconfig | 2 +- arch/arm/configs/pcontrol_g20_defconfig | 2 +- arch/arm/configs/pleb_defconfig | 2 +- arch/arm/configs/pnx4008_defconfig | 2 +- arch/arm/configs/simpad_defconfig | 2 +- arch/arm/configs/spitz_defconfig | 2 +- arch/arm/configs/stmp378x_defconfig | 2 +- arch/arm/configs/stmp37xx_defconfig | 2 +- arch/arm/configs/tct_hammer_defconfig | 2 +- arch/arm/configs/trizeps4_defconfig | 2 +- arch/arm/configs/u300_defconfig | 2 +- arch/arm/configs/viper_defconfig | 2 +- arch/arm/configs/xcep_defconfig | 2 +- arch/avr32/Kconfig | 4 +- arch/blackfin/configs/BF518F-EZBRD_defconfig | 2 +- arch/blackfin/configs/BF526-EZBRD_defconfig | 2 +- arch/blackfin/configs/BF527-AD7160-EVAL_defconfig | 2 +- arch/blackfin/configs/BF527-EZKIT-V2_defconfig | 2 +- arch/blackfin/configs/BF527-EZKIT_defconfig | 2 +- arch/blackfin/configs/BF527-TLL6527M_defconfig | 2 +- arch/blackfin/configs/BF533-EZKIT_defconfig | 2 +- arch/blackfin/configs/BF533-STAMP_defconfig | 2 +- arch/blackfin/configs/BF537-STAMP_defconfig | 2 +- arch/blackfin/configs/BF538-EZKIT_defconfig | 2 +- arch/blackfin/configs/BF548-EZKIT_defconfig | 2 +- arch/blackfin/configs/BF561-ACVILON_defconfig | 2 +- arch/blackfin/configs/BF561-EZKIT-SMP_defconfig | 2 +- arch/blackfin/configs/BF561-EZKIT_defconfig | 2 +- arch/blackfin/configs/BlackStamp_defconfig | 2 +- arch/blackfin/configs/CM-BF527_defconfig | 2 +- arch/blackfin/configs/CM-BF533_defconfig | 2 +- arch/blackfin/configs/CM-BF537E_defconfig | 2 +- arch/blackfin/configs/CM-BF537U_defconfig | 2 +- arch/blackfin/configs/CM-BF548_defconfig | 2 +- arch/blackfin/configs/CM-BF561_defconfig | 2 +- arch/blackfin/configs/DNP5370_defconfig | 2 +- arch/blackfin/configs/H8606_defconfig | 2 +- arch/blackfin/configs/IP0X_defconfig | 2 +- arch/blackfin/configs/PNAV-10_defconfig | 2 +- arch/blackfin/configs/SRV1_defconfig | 2 +- arch/blackfin/configs/TCM-BF518_defconfig | 2 +- arch/blackfin/configs/TCM-BF537_defconfig | 2 +- arch/cris/configs/artpec_3_defconfig | 2 +- arch/cris/configs/etrax-100lx_v2_defconfig | 2 +- arch/cris/configs/etraxfs_defconfig | 2 +- arch/frv/defconfig | 2 +- arch/h8300/defconfig | 2 +- arch/m32r/configs/m32700ut.smp_defconfig | 2 +- arch/m32r/configs/m32700ut.up_defconfig | 2 +- arch/m32r/configs/mappi.nommu_defconfig | 2 +- arch/m32r/configs/mappi.smp_defconfig | 2 +- arch/m32r/configs/mappi.up_defconfig | 2 +- arch/m32r/configs/mappi2.opsp_defconfig | 2 +- arch/m32r/configs/mappi2.vdec2_defconfig | 2 +- arch/m32r/configs/mappi3.smp_defconfig | 2 +- arch/m32r/configs/oaks32r_defconfig | 2 +- arch/m32r/configs/opsput_defconfig | 2 +- arch/m32r/configs/usrv_defconfig | 2 +- arch/m68knommu/configs/m5208evb_defconfig | 2 +- arch/m68knommu/configs/m5249evb_defconfig | 2 +- arch/m68knommu/configs/m5272c3_defconfig | 2 +- arch/m68knommu/configs/m5275evb_defconfig | 2 +- arch/m68knommu/configs/m5307c3_defconfig | 2 +- arch/m68knommu/configs/m5407c3_defconfig | 2 +- arch/m68knommu/defconfig | 2 +- arch/microblaze/configs/mmu_defconfig | 2 +- arch/microblaze/configs/nommu_defconfig | 2 +- arch/mips/Kconfig.debug | 2 +- arch/mips/configs/ar7_defconfig | 2 +- arch/mips/configs/bcm47xx_defconfig | 2 +- arch/mips/configs/bcm63xx_defconfig | 2 +- arch/mips/configs/bigsur_defconfig | 2 +- arch/mips/configs/capcella_defconfig | 2 +- arch/mips/configs/cavium-octeon_defconfig | 2 +- arch/mips/configs/cobalt_defconfig | 2 +- arch/mips/configs/db1000_defconfig | 2 +- arch/mips/configs/db1100_defconfig | 2 +- arch/mips/configs/db1200_defconfig | 2 +- arch/mips/configs/db1500_defconfig | 2 +- arch/mips/configs/db1550_defconfig | 2 +- arch/mips/configs/decstation_defconfig | 2 +- arch/mips/configs/e55_defconfig | 2 +- arch/mips/configs/fuloong2e_defconfig | 2 +- arch/mips/configs/gpr_defconfig | 2 +- arch/mips/configs/ip22_defconfig | 2 +- arch/mips/configs/ip27_defconfig | 2 +- arch/mips/configs/ip28_defconfig | 2 +- arch/mips/configs/ip32_defconfig | 2 +- arch/mips/configs/jazz_defconfig | 2 +- arch/mips/configs/jmr3927_defconfig | 2 +- arch/mips/configs/lasat_defconfig | 2 +- arch/mips/configs/lemote2f_defconfig | 2 +- arch/mips/configs/malta_defconfig | 2 +- arch/mips/configs/markeins_defconfig | 2 +- arch/mips/configs/mipssim_defconfig | 2 +- arch/mips/configs/mpc30x_defconfig | 2 +- arch/mips/configs/msp71xx_defconfig | 2 +- arch/mips/configs/mtx1_defconfig | 2 +- arch/mips/configs/pb1100_defconfig | 2 +- arch/mips/configs/pb1200_defconfig | 2 +- arch/mips/configs/pb1500_defconfig | 2 +- arch/mips/configs/pb1550_defconfig | 2 +- arch/mips/configs/pnx8335-stb225_defconfig | 2 +- arch/mips/configs/pnx8550-jbs_defconfig | 2 +- arch/mips/configs/pnx8550-stb810_defconfig | 2 +- arch/mips/configs/powertv_defconfig | 2 +- arch/mips/configs/rb532_defconfig | 2 +- arch/mips/configs/rbtx49xx_defconfig | 2 +- arch/mips/configs/rm200_defconfig | 2 +- arch/mips/configs/sb1250-swarm_defconfig | 2 +- arch/mips/configs/tb0219_defconfig | 2 +- arch/mips/configs/tb0226_defconfig | 2 +- arch/mips/configs/tb0287_defconfig | 2 +- arch/mips/configs/workpad_defconfig | 2 +- arch/mips/configs/wrppmc_defconfig | 2 +- arch/mips/configs/yosemite_defconfig | 2 +- arch/mn10300/configs/asb2303_defconfig | 2 +- arch/mn10300/configs/asb2364_defconfig | 2 +- arch/parisc/configs/a500_defconfig | 2 +- arch/parisc/configs/c3000_defconfig | 2 +- arch/powerpc/configs/40x/acadia_defconfig | 2 +- arch/powerpc/configs/40x/ep405_defconfig | 2 +- arch/powerpc/configs/40x/hcu4_defconfig | 2 +- arch/powerpc/configs/40x/kilauea_defconfig | 2 +- arch/powerpc/configs/40x/makalu_defconfig | 2 +- arch/powerpc/configs/40x/walnut_defconfig | 2 +- arch/powerpc/configs/44x/arches_defconfig | 2 +- arch/powerpc/configs/44x/bamboo_defconfig | 2 +- arch/powerpc/configs/44x/bluestone_defconfig | 2 +- arch/powerpc/configs/44x/canyonlands_defconfig | 2 +- arch/powerpc/configs/44x/ebony_defconfig | 2 +- arch/powerpc/configs/44x/eiger_defconfig | 2 +- arch/powerpc/configs/44x/icon_defconfig | 2 +- arch/powerpc/configs/44x/iss476-smp_defconfig | 2 +- arch/powerpc/configs/44x/katmai_defconfig | 2 +- arch/powerpc/configs/44x/rainier_defconfig | 2 +- arch/powerpc/configs/44x/redwood_defconfig | 2 +- arch/powerpc/configs/44x/sam440ep_defconfig | 2 +- arch/powerpc/configs/44x/sequoia_defconfig | 2 +- arch/powerpc/configs/44x/taishan_defconfig | 2 +- arch/powerpc/configs/44x/warp_defconfig | 2 +- arch/powerpc/configs/52xx/cm5200_defconfig | 2 +- arch/powerpc/configs/52xx/lite5200b_defconfig | 2 +- arch/powerpc/configs/52xx/motionpro_defconfig | 2 +- arch/powerpc/configs/52xx/pcm030_defconfig | 2 +- arch/powerpc/configs/52xx/tqm5200_defconfig | 2 +- arch/powerpc/configs/83xx/asp8347_defconfig | 2 +- arch/powerpc/configs/83xx/kmeter1_defconfig | 2 +- arch/powerpc/configs/83xx/mpc8313_rdb_defconfig | 2 +- arch/powerpc/configs/83xx/mpc8315_rdb_defconfig | 2 +- arch/powerpc/configs/83xx/mpc832x_mds_defconfig | 2 +- arch/powerpc/configs/83xx/mpc832x_rdb_defconfig | 2 +- arch/powerpc/configs/83xx/mpc834x_itx_defconfig | 2 +- arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig | 2 +- arch/powerpc/configs/83xx/mpc834x_mds_defconfig | 2 +- arch/powerpc/configs/83xx/mpc836x_mds_defconfig | 2 +- arch/powerpc/configs/83xx/mpc836x_rdk_defconfig | 2 +- arch/powerpc/configs/83xx/mpc837x_mds_defconfig | 2 +- arch/powerpc/configs/83xx/mpc837x_rdb_defconfig | 2 +- arch/powerpc/configs/83xx/sbc834x_defconfig | 2 +- arch/powerpc/configs/85xx/ksi8560_defconfig | 2 +- arch/powerpc/configs/85xx/mpc8540_ads_defconfig | 2 +- arch/powerpc/configs/85xx/mpc8560_ads_defconfig | 2 +- arch/powerpc/configs/85xx/mpc85xx_cds_defconfig | 2 +- arch/powerpc/configs/85xx/sbc8548_defconfig | 2 +- arch/powerpc/configs/85xx/sbc8560_defconfig | 2 +- arch/powerpc/configs/85xx/socrates_defconfig | 2 +- arch/powerpc/configs/85xx/stx_gp3_defconfig | 2 +- arch/powerpc/configs/85xx/tqm8540_defconfig | 2 +- arch/powerpc/configs/85xx/tqm8541_defconfig | 2 +- arch/powerpc/configs/85xx/tqm8548_defconfig | 2 +- arch/powerpc/configs/85xx/tqm8555_defconfig | 2 +- arch/powerpc/configs/85xx/tqm8560_defconfig | 2 +- arch/powerpc/configs/85xx/xes_mpc85xx_defconfig | 2 +- arch/powerpc/configs/86xx/gef_ppc9a_defconfig | 2 +- arch/powerpc/configs/86xx/gef_sbc310_defconfig | 2 +- arch/powerpc/configs/86xx/gef_sbc610_defconfig | 2 +- arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig | 2 +- arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig | 2 +- arch/powerpc/configs/86xx/sbc8641d_defconfig | 2 +- arch/powerpc/configs/adder875_defconfig | 2 +- arch/powerpc/configs/e55xx_smp_defconfig | 2 +- arch/powerpc/configs/ep8248e_defconfig | 2 +- arch/powerpc/configs/ep88xc_defconfig | 2 +- arch/powerpc/configs/gamecube_defconfig | 2 +- arch/powerpc/configs/holly_defconfig | 2 +- arch/powerpc/configs/mgcoge_defconfig | 2 +- arch/powerpc/configs/mgsuvd_defconfig | 2 +- arch/powerpc/configs/mpc7448_hpc2_defconfig | 2 +- arch/powerpc/configs/mpc8272_ads_defconfig | 2 +- arch/powerpc/configs/mpc83xx_defconfig | 2 +- arch/powerpc/configs/mpc85xx_defconfig | 2 +- arch/powerpc/configs/mpc85xx_smp_defconfig | 2 +- arch/powerpc/configs/mpc866_ads_defconfig | 2 +- arch/powerpc/configs/mpc86xx_defconfig | 2 +- arch/powerpc/configs/mpc885_ads_defconfig | 2 +- arch/powerpc/configs/ppc40x_defconfig | 2 +- arch/powerpc/configs/ppc44x_defconfig | 2 +- arch/powerpc/configs/pq2fads_defconfig | 2 +- arch/powerpc/configs/ps3_defconfig | 2 +- arch/powerpc/configs/storcenter_defconfig | 2 +- arch/powerpc/configs/tqm8xx_defconfig | 2 +- arch/powerpc/configs/wii_defconfig | 2 +- arch/powerpc/platforms/iseries/Kconfig | 2 +- arch/powerpc/platforms/pseries/Kconfig | 6 +-- arch/score/configs/spct6600_defconfig | 2 +- arch/sh/Kconfig | 2 +- arch/tile/Kconfig | 2 +- arch/tile/Kconfig.debug | 2 +- arch/tile/configs/tile_defconfig | 2 +- arch/um/defconfig | 2 +- arch/x86/Kconfig | 20 +++---- arch/x86/Kconfig.cpu | 2 +- arch/x86/Kconfig.debug | 4 +- arch/xtensa/configs/common_defconfig | 2 +- arch/xtensa/configs/iss_defconfig | 2 +- arch/xtensa/configs/s6105_defconfig | 2 +- block/Kconfig | 2 +- drivers/acpi/Kconfig | 2 +- drivers/ata/Kconfig | 2 +- drivers/base/Kconfig | 2 +- drivers/char/Kconfig | 10 ++-- drivers/cpufreq/Kconfig | 2 +- drivers/firmware/Kconfig | 2 +- drivers/gpu/drm/Kconfig | 2 +- drivers/gpu/drm/drm_fb_helper.c | 4 +- drivers/gpu/drm/nouveau/Kconfig | 2 +- drivers/gpu/vga/Kconfig | 2 +- drivers/hid/Kconfig | 64 +++++++++++------------ drivers/hid/usbhid/Kconfig | 2 +- drivers/ide/Kconfig | 2 +- drivers/infiniband/hw/mthca/Kconfig | 2 +- drivers/infiniband/ulp/ipoib/Kconfig | 2 +- drivers/input/Kconfig | 6 +-- drivers/input/keyboard/Kconfig | 4 +- drivers/input/mouse/Kconfig | 10 ++-- drivers/input/serio/Kconfig | 6 +-- drivers/input/touchscreen/Kconfig | 30 +++++------ drivers/media/common/tuners/Kconfig | 2 +- drivers/media/dvb/frontends/Kconfig | 2 +- drivers/media/video/Kconfig | 2 +- drivers/net/Kconfig | 2 +- drivers/pci/pcie/Kconfig | 2 +- drivers/pcmcia/Kconfig | 12 ++--- drivers/serial/Kconfig | 4 +- drivers/ssb/Kconfig | 2 +- drivers/usb/core/Kconfig | 6 +-- drivers/video/Kconfig | 2 +- drivers/video/console/Kconfig | 2 +- fs/Kconfig | 2 +- fs/proc/Kconfig | 6 +-- fs/sysfs/Kconfig | 2 +- init/Kconfig | 60 ++++++++++++--------- lib/Kconfig.debug | 6 +-- lib/xz/Kconfig | 12 ++--- net/mac80211/Kconfig | 6 +-- net/rfkill/Kconfig | 4 +- net/wireless/Kconfig | 2 +- usr/Kconfig | 18 +++---- 298 files changed, 431 insertions(+), 423 deletions(-) (limited to 'drivers') diff --git a/arch/arm/configs/ag5evm_defconfig b/arch/arm/configs/ag5evm_defconfig index 2b9cf56db363..212ead354a6b 100644 --- a/arch/arm/configs/ag5evm_defconfig +++ b/arch/arm/configs/ag5evm_defconfig @@ -10,7 +10,7 @@ CONFIG_NAMESPACES=y # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig index 5536c488dd01..f0dea52e49c4 100644 --- a/arch/arm/configs/am200epdkit_defconfig +++ b/arch/arm/configs/am200epdkit_defconfig @@ -3,7 +3,7 @@ CONFIG_LOCALVERSION="gum" # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_EPOLL is not set # CONFIG_SHMEM is not set diff --git a/arch/arm/configs/at572d940hfek_defconfig b/arch/arm/configs/at572d940hfek_defconfig index 695e32d4fb58..1b1158ae8f82 100644 --- a/arch/arm/configs/at572d940hfek_defconfig +++ b/arch/arm/configs/at572d940hfek_defconfig @@ -17,7 +17,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_PROFILING=y CONFIG_OPROFILE=m diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig index 3a1ad15a779f..5b54abbeb0b3 100644 --- a/arch/arm/configs/badge4_defconfig +++ b/arch/arm/configs/badge4_defconfig @@ -1,6 +1,6 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y CONFIG_ARCH_SA1100=y diff --git a/arch/arm/configs/bcmring_defconfig b/arch/arm/configs/bcmring_defconfig index 75984cd1e233..795374d48f81 100644 --- a/arch/arm/configs/bcmring_defconfig +++ b/arch/arm/configs/bcmring_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_HOTPLUG is not set # CONFIG_ELF_CORE is not set diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig index dcfbcf3b6c3e..a93ff8da5bab 100644 --- a/arch/arm/configs/cm_x2xx_defconfig +++ b/arch/arm/configs/cm_x2xx_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig index f52c64e36d8d..2ef2c5e8aaec 100644 --- a/arch/arm/configs/colibri_pxa270_defconfig +++ b/arch/arm/configs/colibri_pxa270_defconfig @@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig index 310f9a6270be..6c56ad086c7c 100644 --- a/arch/arm/configs/collie_defconfig +++ b/arch/arm/configs/collie_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_BASE_FULL is not set # CONFIG_EPOLL is not set CONFIG_SLOB=y diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index 4a1fa81ed37d..e53c47563845 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_MODULES=y diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig index cdc40c4b8c48..88ccde058ba4 100644 --- a/arch/arm/configs/da8xx_omapl_defconfig +++ b/arch/arm/configs/da8xx_omapl_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 2519cc5a5f8f..889922ad229c 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig index 9359e1bf32c1..54bf5eec8016 100644 --- a/arch/arm/configs/dove_defconfig +++ b/arch/arm/configs/dove_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/ebsa110_defconfig b/arch/arm/configs/ebsa110_defconfig index c3194186920c..14559dbb4c2c 100644 --- a/arch/arm/configs/ebsa110_defconfig +++ b/arch/arm/configs/ebsa110_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_ARCH_EBSA110=y CONFIG_PCCARD=m diff --git a/arch/arm/configs/edb7211_defconfig b/arch/arm/configs/edb7211_defconfig index 7b62be1561ea..d52ded350a12 100644 --- a/arch/arm/configs/edb7211_defconfig +++ b/arch/arm/configs/edb7211_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_ARCH_CLPS711X=y CONFIG_ARCH_EDB7211=y diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig index d7db34f79702..60a21e01eb70 100644 --- a/arch/arm/configs/em_x270_defconfig +++ b/arch/arm/configs/em_x270_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig index 6d6689cdf398..8e97b2f7ceec 100644 --- a/arch/arm/configs/ep93xx_defconfig +++ b/arch/arm/configs/ep93xx_defconfig @@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/eseries_pxa_defconfig b/arch/arm/configs/eseries_pxa_defconfig index 1691dea582fe..d68ac67c201c 100644 --- a/arch/arm/configs/eseries_pxa_defconfig +++ b/arch/arm/configs/eseries_pxa_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig index c4eeb6d1cbf0..227a477346ed 100644 --- a/arch/arm/configs/ezx_defconfig +++ b/arch/arm/configs/ezx_defconfig @@ -7,7 +7,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig index 4f925ead2617..038518ab39a8 100644 --- a/arch/arm/configs/footbridge_defconfig +++ b/arch/arm/configs/footbridge_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_MODULES=y CONFIG_ARCH_FOOTBRIDGE=y diff --git a/arch/arm/configs/fortunet_defconfig b/arch/arm/configs/fortunet_defconfig index e11c7eab8ed0..840fced7529f 100644 --- a/arch/arm/configs/fortunet_defconfig +++ b/arch/arm/configs/fortunet_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_ARCH_CLPS711X=y CONFIG_ARCH_FORTUNET=y diff --git a/arch/arm/configs/h5000_defconfig b/arch/arm/configs/h5000_defconfig index ac336f10000c..37903e3f0efc 100644 --- a/arch/arm/configs/h5000_defconfig +++ b/arch/arm/configs/h5000_defconfig @@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig index ade55c8c408b..176ec22af034 100644 --- a/arch/arm/configs/imote2_defconfig +++ b/arch/arm/configs/imote2_defconfig @@ -6,7 +6,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/ixp2000_defconfig b/arch/arm/configs/ixp2000_defconfig index 908324684549..8405aded97a3 100644 --- a/arch/arm/configs/ixp2000_defconfig +++ b/arch/arm/configs/ixp2000_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/ixp23xx_defconfig b/arch/arm/configs/ixp23xx_defconfig index 7fc056a8569c..688717612e91 100644 --- a/arch/arm/configs/ixp23xx_defconfig +++ b/arch/arm/configs/ixp23xx_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 5c5023934001..063e2ab2c8f1 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/arm/configs/loki_defconfig b/arch/arm/configs/loki_defconfig index e1eaff7f5536..1ba752b2dc6d 100644 --- a/arch/arm/configs/loki_defconfig +++ b/arch/arm/configs/loki_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/lpd7a400_defconfig b/arch/arm/configs/lpd7a400_defconfig index 20caaaba4a04..5a48f171204c 100644 --- a/arch/arm/configs/lpd7a400_defconfig +++ b/arch/arm/configs/lpd7a400_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set # CONFIG_IOSCHED_DEADLINE is not set diff --git a/arch/arm/configs/lpd7a404_defconfig b/arch/arm/configs/lpd7a404_defconfig index 1efcce97b4a7..22d0631de009 100644 --- a/arch/arm/configs/lpd7a404_defconfig +++ b/arch/arm/configs/lpd7a404_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=16 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set CONFIG_SLAB=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index af805e8fd03d..a88e64d4e9a5 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index b0d082422d46..7305ebddb510 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y # CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y diff --git a/arch/arm/configs/mx1_defconfig b/arch/arm/configs/mx1_defconfig index 2f38d9715437..b39b5ced8a10 100644 --- a/arch/arm/configs/mx1_defconfig +++ b/arch/arm/configs/mx1_defconfig @@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/mx21_defconfig b/arch/arm/configs/mx21_defconfig index 6454e18e2abe..411f88dd4402 100644 --- a/arch/arm/configs/mx21_defconfig +++ b/arch/arm/configs/mx21_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/mx27_defconfig b/arch/arm/configs/mx27_defconfig index 813cfb366c18..9ad4c656c9bd 100644 --- a/arch/arm/configs/mx27_defconfig +++ b/arch/arm/configs/mx27_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y diff --git a/arch/arm/configs/mx3_defconfig b/arch/arm/configs/mx3_defconfig index e648ea3429be..7c4b30b34952 100644 --- a/arch/arm/configs/mx3_defconfig +++ b/arch/arm/configs/mx3_defconfig @@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig index 5c7a87260fab..9cba68cfa51a 100644 --- a/arch/arm/configs/mx51_defconfig +++ b/arch/arm/configs/mx51_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_RELAY=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_MODULES=y diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig index 0e2dc26ebe66..37207d1bf44b 100644 --- a/arch/arm/configs/nhk8815_defconfig +++ b/arch/arm/configs/nhk8815_defconfig @@ -7,7 +7,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index a350cc6bfe6a..7b63462b349d 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -6,7 +6,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index ccedde1371c3..ae890caa17a7 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_SLAB=y diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig index 439323b3b0ed..a288d7033950 100644 --- a/arch/arm/configs/orion5x_defconfig +++ b/arch/arm/configs/orion5x_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SLUB_DEBUG is not set CONFIG_PROFILING=y CONFIG_OPROFILE=y diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig index 583a0610bd00..2f136c30a989 100644 --- a/arch/arm/configs/pcm027_defconfig +++ b/arch/arm/configs/pcm027_defconfig @@ -7,7 +7,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/pcontrol_g20_defconfig b/arch/arm/configs/pcontrol_g20_defconfig index b42ee62c4d77..c75c9fcede58 100644 --- a/arch/arm/configs/pcontrol_g20_defconfig +++ b/arch/arm/configs/pcontrol_g20_defconfig @@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arm/configs/pleb_defconfig b/arch/arm/configs/pleb_defconfig index d1efbdc1e6dc..cb08cc561da5 100644 --- a/arch/arm/configs/pleb_defconfig +++ b/arch/arm/configs/pleb_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set # CONFIG_SHMEM is not set CONFIG_MODULES=y diff --git a/arch/arm/configs/pnx4008_defconfig b/arch/arm/configs/pnx4008_defconfig index bd481f04276f..35a31ccacc32 100644 --- a/arch/arm/configs/pnx4008_defconfig +++ b/arch/arm/configs/pnx4008_defconfig @@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/simpad_defconfig b/arch/arm/configs/simpad_defconfig index af3b12e3b464..d3358155bf8a 100644 --- a/arch/arm/configs/simpad_defconfig +++ b/arch/arm/configs/simpad_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOCALVERSION="oe1" CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index aebd4bb0ad01..70158273c6dd 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_MODULES=y diff --git a/arch/arm/configs/stmp378x_defconfig b/arch/arm/configs/stmp378x_defconfig index 94a2d904bf94..1079c2b6eb3a 100644 --- a/arch/arm/configs/stmp378x_defconfig +++ b/arch/arm/configs/stmp378x_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/stmp37xx_defconfig b/arch/arm/configs/stmp37xx_defconfig index d8ee58cfa872..564a5cc44085 100644 --- a/arch/arm/configs/stmp37xx_defconfig +++ b/arch/arm/configs/stmp37xx_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/arm/configs/tct_hammer_defconfig b/arch/arm/configs/tct_hammer_defconfig index e89ca19489c2..95c0f0d63db6 100644 --- a/arch/arm/configs/tct_hammer_defconfig +++ b/arch/arm/configs/tct_hammer_defconfig @@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_BUG is not set # CONFIG_ELF_CORE is not set diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index 37f48342827c..3162173fa75a 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -7,7 +7,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig index c1c252cdca60..4a5a12681be2 100644 --- a/arch/arm/configs/u300_defconfig +++ b/arch/arm/configs/u300_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_AIO is not set # CONFIG_VM_EVENT_COUNTERS is not set CONFIG_MODULES=y diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig index 9d7bf5e0d0f5..8b0c717378fa 100644 --- a/arch/arm/configs/viper_defconfig +++ b/arch/arm/configs/viper_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=13 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set # CONFIG_SHMEM is not set CONFIG_SLAB=y diff --git a/arch/arm/configs/xcep_defconfig b/arch/arm/configs/xcep_defconfig index 70d47dbae6db..5b5504143647 100644 --- a/arch/arm/configs/xcep_defconfig +++ b/arch/arm/configs/xcep_defconfig @@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SHMEM is not set # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 313b13073c54..cd2062fe0f61 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -1,8 +1,8 @@ config AVR32 def_bool y - # With EMBEDDED=n, we get lots of stuff automatically selected + # With EXPERT=n, we get lots of stuff automatically selected # that we usually don't need on AVR32. - select EMBEDDED + select EXPERT select HAVE_CLK select HAVE_OPROFILE select HAVE_KPROBES diff --git a/arch/blackfin/configs/BF518F-EZBRD_defconfig b/arch/blackfin/configs/BF518F-EZBRD_defconfig index c0b988ee30df..db8d38a12a9a 100644 --- a/arch/blackfin/configs/BF518F-EZBRD_defconfig +++ b/arch/blackfin/configs/BF518F-EZBRD_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig index 864af5b68874..3e50d7857c27 100644 --- a/arch/blackfin/configs/BF526-EZBRD_defconfig +++ b/arch/blackfin/configs/BF526-EZBRD_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig b/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig index 7b6a3370dbe2..362f59dd5228 100644 --- a/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig +++ b/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set # CONFIG_AIO is not set CONFIG_SLAB=y diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig index 4faa6b46a352..023ff0df2692 100644 --- a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig +++ b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig index 9d893eb68243..4e5a121b3c56 100644 --- a/arch/blackfin/configs/BF527-EZKIT_defconfig +++ b/arch/blackfin/configs/BF527-EZKIT_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF527-TLL6527M_defconfig b/arch/blackfin/configs/BF527-TLL6527M_defconfig index 97a2767c80f8..cd0636bb24a0 100644 --- a/arch/blackfin/configs/BF527-TLL6527M_defconfig +++ b/arch/blackfin/configs/BF527-TLL6527M_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig index f84774360c5b..9f8fc84e4ac9 100644 --- a/arch/blackfin/configs/BF533-EZKIT_defconfig +++ b/arch/blackfin/configs/BF533-EZKIT_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig index 0e7262c04cc2..ccc432b722a0 100644 --- a/arch/blackfin/configs/BF533-STAMP_defconfig +++ b/arch/blackfin/configs/BF533-STAMP_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig index 4d14a002e7bd..566695472a84 100644 --- a/arch/blackfin/configs/BF537-STAMP_defconfig +++ b/arch/blackfin/configs/BF537-STAMP_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF538-EZKIT_defconfig b/arch/blackfin/configs/BF538-EZKIT_defconfig index fbee9d776f56..ac22124ccb6c 100644 --- a/arch/blackfin/configs/BF538-EZKIT_defconfig +++ b/arch/blackfin/configs/BF538-EZKIT_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig index 05dd11db2f7d..944404b6ff08 100644 --- a/arch/blackfin/configs/BF548-EZKIT_defconfig +++ b/arch/blackfin/configs/BF548-EZKIT_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF561-ACVILON_defconfig b/arch/blackfin/configs/BF561-ACVILON_defconfig index bcb14d1c5664..b7c8451f26ac 100644 --- a/arch/blackfin/configs/BF561-ACVILON_defconfig +++ b/arch/blackfin/configs/BF561-ACVILON_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig b/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig index 4cf451024fd8..7e67ba31e991 100644 --- a/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig +++ b/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig index 843aaa54a9e3..141e5933e1aa 100644 --- a/arch/blackfin/configs/BF561-EZKIT_defconfig +++ b/arch/blackfin/configs/BF561-EZKIT_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/BlackStamp_defconfig b/arch/blackfin/configs/BlackStamp_defconfig index dae7adf3b2a2..97ebe09a7370 100644 --- a/arch/blackfin/configs/BlackStamp_defconfig +++ b/arch/blackfin/configs/BlackStamp_defconfig @@ -6,7 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig index f3414244bfed..c2457543e58c 100644 --- a/arch/blackfin/configs/CM-BF527_defconfig +++ b/arch/blackfin/configs/CM-BF527_defconfig @@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/CM-BF533_defconfig b/arch/blackfin/configs/CM-BF533_defconfig index 8c7e08f173d4..baf1c1573e5e 100644 --- a/arch/blackfin/configs/CM-BF533_defconfig +++ b/arch/blackfin/configs/CM-BF533_defconfig @@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/CM-BF537E_defconfig b/arch/blackfin/configs/CM-BF537E_defconfig index bd3cb766d078..707cbf8a2590 100644 --- a/arch/blackfin/configs/CM-BF537E_defconfig +++ b/arch/blackfin/configs/CM-BF537E_defconfig @@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/CM-BF537U_defconfig b/arch/blackfin/configs/CM-BF537U_defconfig index 82224f37c04e..4596935eadac 100644 --- a/arch/blackfin/configs/CM-BF537U_defconfig +++ b/arch/blackfin/configs/CM-BF537U_defconfig @@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig index 433598c6e773..df267588efec 100644 --- a/arch/blackfin/configs/CM-BF548_defconfig +++ b/arch/blackfin/configs/CM-BF548_defconfig @@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig index ded7d845cb39..6c7b21585a43 100644 --- a/arch/blackfin/configs/CM-BF561_defconfig +++ b/arch/blackfin/configs/CM-BF561_defconfig @@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/DNP5370_defconfig b/arch/blackfin/configs/DNP5370_defconfig index 0ebc7d9aa426..f50313657f3e 100644 --- a/arch/blackfin/configs/DNP5370_defconfig +++ b/arch/blackfin/configs/DNP5370_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLOB=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_CFQ is not set diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig index 700fb701c121..7450127b6455 100644 --- a/arch/blackfin/configs/H8606_defconfig +++ b/arch/blackfin/configs/H8606_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig index b40156d217e3..5e797cf72043 100644 --- a/arch/blackfin/configs/IP0X_defconfig +++ b/arch/blackfin/configs/IP0X_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_HOTPLUG is not set # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig index be866d95ed76..a566a2fe6b9b 100644 --- a/arch/blackfin/configs/PNAV-10_defconfig +++ b/arch/blackfin/configs/PNAV-10_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig index b64bdf759b82..853809510ee9 100644 --- a/arch/blackfin/configs/SRV1_defconfig +++ b/arch/blackfin/configs/SRV1_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS_ALL=y # CONFIG_ELF_CORE is not set diff --git a/arch/blackfin/configs/TCM-BF518_defconfig b/arch/blackfin/configs/TCM-BF518_defconfig index 1bccd9a50986..d496ae9a39b0 100644 --- a/arch/blackfin/configs/TCM-BF518_defconfig +++ b/arch/blackfin/configs/TCM-BF518_defconfig @@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_FUTEX is not set diff --git a/arch/blackfin/configs/TCM-BF537_defconfig b/arch/blackfin/configs/TCM-BF537_defconfig index 00ce899e9e5d..65f642167a50 100644 --- a/arch/blackfin/configs/TCM-BF537_defconfig +++ b/arch/blackfin/configs/TCM-BF537_defconfig @@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set diff --git a/arch/cris/configs/artpec_3_defconfig b/arch/cris/configs/artpec_3_defconfig index 590f72c9455d..71854d41c5a0 100644 --- a/arch/cris/configs/artpec_3_defconfig +++ b/arch/cris/configs/artpec_3_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/cris/configs/etrax-100lx_v2_defconfig b/arch/cris/configs/etrax-100lx_v2_defconfig index 1b2853e39801..a85aabf92be5 100644 --- a/arch/cris/configs/etrax-100lx_v2_defconfig +++ b/arch/cris/configs/etrax-100lx_v2_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/cris/configs/etraxfs_defconfig b/arch/cris/configs/etraxfs_defconfig index f73d38cc9c66..87c7227fecb2 100644 --- a/arch/cris/configs/etraxfs_defconfig +++ b/arch/cris/configs/etraxfs_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/frv/defconfig b/arch/frv/defconfig index b8ebe9e8a493..b1b792610fdf 100644 --- a/arch/frv/defconfig +++ b/arch/frv/defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_MMU=y CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y diff --git a/arch/h8300/defconfig b/arch/h8300/defconfig index 342f77765f02..042425a02645 100644 --- a/arch/h8300/defconfig +++ b/arch/h8300/defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set diff --git a/arch/m32r/configs/m32700ut.smp_defconfig b/arch/m32r/configs/m32700ut.smp_defconfig index 816c3ecaa2aa..a3d727ed6a16 100644 --- a/arch/m32r/configs/m32700ut.smp_defconfig +++ b/arch/m32r/configs/m32700ut.smp_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/m32700ut.up_defconfig b/arch/m32r/configs/m32700ut.up_defconfig index 84785686640a..b8334163099d 100644 --- a/arch/m32r/configs/m32700ut.up_defconfig +++ b/arch/m32r/configs/m32700ut.up_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/mappi.nommu_defconfig b/arch/m32r/configs/mappi.nommu_defconfig index 354a964d084d..7c90ce2fc42b 100644 --- a/arch/m32r/configs/mappi.nommu_defconfig +++ b/arch/m32r/configs/mappi.nommu_defconfig @@ -3,7 +3,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/mappi.smp_defconfig b/arch/m32r/configs/mappi.smp_defconfig index 9022307bd073..367d07cebcd3 100644 --- a/arch/m32r/configs/mappi.smp_defconfig +++ b/arch/m32r/configs/mappi.smp_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/mappi.up_defconfig b/arch/m32r/configs/mappi.up_defconfig index 3726068721a5..cb11384386ce 100644 --- a/arch/m32r/configs/mappi.up_defconfig +++ b/arch/m32r/configs/mappi.up_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/mappi2.opsp_defconfig b/arch/m32r/configs/mappi2.opsp_defconfig index 6136fad048e4..3bff779259b4 100644 --- a/arch/m32r/configs/mappi2.opsp_defconfig +++ b/arch/m32r/configs/mappi2.opsp_defconfig @@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/mappi2.vdec2_defconfig b/arch/m32r/configs/mappi2.vdec2_defconfig index dce1fc7d67ed..75246c9c1af8 100644 --- a/arch/m32r/configs/mappi2.vdec2_defconfig +++ b/arch/m32r/configs/mappi2.vdec2_defconfig @@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/mappi3.smp_defconfig b/arch/m32r/configs/mappi3.smp_defconfig index b204e2ecd0f1..27cefd41ac1f 100644 --- a/arch/m32r/configs/mappi3.smp_defconfig +++ b/arch/m32r/configs/mappi3.smp_defconfig @@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/oaks32r_defconfig b/arch/m32r/configs/oaks32r_defconfig index 5aa4ea9ebb10..5087a510ca4f 100644 --- a/arch/m32r/configs/oaks32r_defconfig +++ b/arch/m32r/configs/oaks32r_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/opsput_defconfig b/arch/m32r/configs/opsput_defconfig index 8494c6a276e8..50c6f525db20 100644 --- a/arch/m32r/configs/opsput_defconfig +++ b/arch/m32r/configs/opsput_defconfig @@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/m32r/configs/usrv_defconfig b/arch/m32r/configs/usrv_defconfig index 1df293bc2ab9..a3cfaaedab60 100644 --- a/arch/m32r/configs/usrv_defconfig +++ b/arch/m32r/configs/usrv_defconfig @@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/m68knommu/configs/m5208evb_defconfig b/arch/m68knommu/configs/m5208evb_defconfig index 6ac2981a2cdf..2f5655c577af 100644 --- a/arch/m68knommu/configs/m5208evb_defconfig +++ b/arch/m68knommu/configs/m5208evb_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/m68knommu/configs/m5249evb_defconfig b/arch/m68knommu/configs/m5249evb_defconfig index 14934ff8d5c3..16df72bfbd45 100644 --- a/arch/m68knommu/configs/m5249evb_defconfig +++ b/arch/m68knommu/configs/m5249evb_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/m68knommu/configs/m5272c3_defconfig b/arch/m68knommu/configs/m5272c3_defconfig index 5985a3b593d8..4e6ea50c7f33 100644 --- a/arch/m68knommu/configs/m5272c3_defconfig +++ b/arch/m68knommu/configs/m5272c3_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/m68knommu/configs/m5275evb_defconfig b/arch/m68knommu/configs/m5275evb_defconfig index 5a7857efb45d..f3dd74115a34 100644 --- a/arch/m68knommu/configs/m5275evb_defconfig +++ b/arch/m68knommu/configs/m5275evb_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/m68knommu/configs/m5307c3_defconfig b/arch/m68knommu/configs/m5307c3_defconfig index e8102018c8d4..bce0a20c3737 100644 --- a/arch/m68knommu/configs/m5307c3_defconfig +++ b/arch/m68knommu/configs/m5307c3_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/m68knommu/configs/m5407c3_defconfig b/arch/m68knommu/configs/m5407c3_defconfig index 5c124a7ba2a7..618cc32691f2 100644 --- a/arch/m68knommu/configs/m5407c3_defconfig +++ b/arch/m68knommu/configs/m5407c3_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig index 6ac2981a2cdf..2f5655c577af 100644 --- a/arch/m68knommu/defconfig +++ b/arch/m68knommu/defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_FUTEX is not set diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig index ab8fbe7ad90b..b3f5eecff2a7 100644 --- a/arch/microblaze/configs/mmu_defconfig +++ b/arch/microblaze/configs/mmu_defconfig @@ -7,7 +7,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="rootfs.cpio" CONFIG_INITRAMFS_COMPRESSION_GZIP=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_HOTPLUG is not set diff --git a/arch/microblaze/configs/nommu_defconfig b/arch/microblaze/configs/nommu_defconfig index ebc143c5368e..0249e4b7e1d3 100644 --- a/arch/microblaze/configs/nommu_defconfig +++ b/arch/microblaze/configs/nommu_defconfig @@ -6,7 +6,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_HOTPLUG is not set diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index f437cd1fafb8..5358f90b4dd2 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -7,7 +7,7 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" config EARLY_PRINTK - bool "Early printk" if EMBEDDED + bool "Early printk" if EXPERT depends on SYS_HAS_EARLY_PRINTK default y help diff --git a/arch/mips/configs/ar7_defconfig b/arch/mips/configs/ar7_defconfig index c78c7e7e41df..6cd5a519ce5c 100644 --- a/arch/mips/configs/ar7_defconfig +++ b/arch/mips/configs/ar7_defconfig @@ -14,7 +14,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_ELF_CORE is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index 927d58b2cd03..22fdf2f0cc23 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -21,7 +21,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/bcm63xx_defconfig b/arch/mips/configs/bcm63xx_defconfig index b806a4e32896..919005139f5a 100644 --- a/arch/mips/configs/bcm63xx_defconfig +++ b/arch/mips/configs/bcm63xx_defconfig @@ -10,7 +10,7 @@ CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_TINY_RCU=y CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 9749bc8758db..1cdff6b6327d 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -26,7 +26,7 @@ CONFIG_PID_NS=y CONFIG_NET_NS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index 502a8e9c084b..5135dc0b950a 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/cavium-octeon_defconfig b/arch/mips/configs/cavium-octeon_defconfig index 3567b6f07b37..75165dfa60c1 100644 --- a/arch/mips/configs/cavium-octeon_defconfig +++ b/arch/mips/configs/cavium-octeon_defconfig @@ -15,7 +15,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index 6c4f7e9d3383..5419adb219a8 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index dda158b2c8dc..4044c9e0fb73 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -11,7 +11,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index 7e4fc76df538..c6b49938ee84 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig @@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index 6fe205fa7b61..1f69249b839a 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig @@ -12,7 +12,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index a741c55448d0..b6e21c7cb6bd 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig @@ -10,7 +10,7 @@ CONFIG_LOCALVERSION="-db1500" CONFIG_KERNEL_LZMA=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index cd32dd8c8008..798a553c9e80 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index b15bfd1e69c8..87d0340837aa 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_HOTPLUG is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index 0b60c06a943d..0126e66d60cb 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig index 63944a14b816..e5b73de08fc5 100644 --- a/arch/mips/configs/fuloong2e_defconfig +++ b/arch/mips/configs/fuloong2e_defconfig @@ -17,7 +17,7 @@ CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_PID_NS=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig index 53edc134f274..48a40aefaf58 100644 --- a/arch/mips/configs/gpr_defconfig +++ b/arch/mips/configs/gpr_defconfig @@ -11,7 +11,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_PROFILING=y CONFIG_MODULES=y diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index 36de199f4c27..d1606569b001 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -17,7 +17,7 @@ CONFIG_IPC_NS=y CONFIG_USER_NS=y CONFIG_PID_NS=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_COMPAT_BRK is not set diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 4b16c48b0c36..0e36abcd39cc 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -15,7 +15,7 @@ CONFIG_CGROUPS=y CONFIG_CPUSETS=y CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/ip28_defconfig b/arch/mips/configs/ip28_defconfig index 98f2c7736e87..4dbf6269b3f9 100644 --- a/arch/mips/configs/ip28_defconfig +++ b/arch/mips/configs/ip28_defconfig @@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index 5bea99b26fa8..7bbd52194fc3 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_PROFILING=y CONFIG_OPROFILE=m diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig index 6ae46bcdb20b..92a60aecad5c 100644 --- a/arch/mips/configs/jazz_defconfig +++ b/arch/mips/configs/jazz_defconfig @@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index bf24e9309b9c..db5705e18b36 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig @@ -4,7 +4,7 @@ CONFIG_TOSHIBA_JMR3927=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/lasat_defconfig b/arch/mips/configs/lasat_defconfig index 6447261c61d0..d9f3db29ab95 100644 --- a/arch/mips/configs/lasat_defconfig +++ b/arch/mips/configs/lasat_defconfig @@ -8,7 +8,7 @@ CONFIG_HZ_1000=y CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index f7033f3a5822..167c1d07b809 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -21,7 +21,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_MODULES=y diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 9d03b68aece8..7270f3183bda 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -15,7 +15,7 @@ CONFIG_UTS_NS=y CONFIG_IPC_NS=y CONFIG_PID_NS=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/markeins_defconfig b/arch/mips/configs/markeins_defconfig index 86bf001babe9..9c9a123016c0 100644 --- a/arch/mips/configs/markeins_defconfig +++ b/arch/mips/configs/markeins_defconfig @@ -9,7 +9,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index 4925f507dc21..b5ad7387bbb0 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig @@ -7,7 +7,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index efb779f8f6fe..c16de9812920 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/msp71xx_defconfig b/arch/mips/configs/msp71xx_defconfig index ab051458452b..d1142e9cd9a1 100644 --- a/arch/mips/configs/msp71xx_defconfig +++ b/arch/mips/configs/msp71xx_defconfig @@ -8,7 +8,7 @@ CONFIG_LOCALVERSION="-pmc" CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SHMEM is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 814699754e0d..a97a42c6b2c8 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -11,7 +11,7 @@ CONFIG_AUDIT=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_PROFILING=y CONFIG_OPROFILE=m diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 1597aa1842fa..75eb1b1f316c 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig @@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/pb1200_defconfig b/arch/mips/configs/pb1200_defconfig index 96f0d43cf08b..dcbe2704e5ed 100644 --- a/arch/mips/configs/pb1200_defconfig +++ b/arch/mips/configs/pb1200_defconfig @@ -12,7 +12,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index b4bfd4823458..fa00487146f8 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig @@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index 5a660024d22a..e83d6497e8b4 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig @@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/pnx8335-stb225_defconfig b/arch/mips/configs/pnx8335-stb225_defconfig index 39926a1a96b6..f2925769dfa3 100644 --- a/arch/mips/configs/pnx8335-stb225_defconfig +++ b/arch/mips/configs/pnx8335-stb225_defconfig @@ -11,7 +11,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 3376bc8616cc..1d1f2067f3e6 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig index 6514f1bf0afb..15c66a571f99 100644 --- a/arch/mips/configs/pnx8550-stb810_defconfig +++ b/arch/mips/configs/pnx8550-stb810_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_HOTPLUG is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/powertv_defconfig b/arch/mips/configs/powertv_defconfig index f1f58e91dd80..3b0b6e8c8533 100644 --- a/arch/mips/configs/powertv_defconfig +++ b/arch/mips/configs/powertv_defconfig @@ -14,7 +14,7 @@ CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_GZIP is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set CONFIG_KALLSYMS_ALL=y # CONFIG_PCSPKR_PLATFORM is not set diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig index d6457bc38c71..55902d9cd0f2 100644 --- a/arch/mips/configs/rb532_defconfig +++ b/arch/mips/configs/rb532_defconfig @@ -13,7 +13,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_ELF_CORE is not set # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig index 29acfab31516..9cba856277ff 100644 --- a/arch/mips/configs/rbtx49xx_defconfig +++ b/arch/mips/configs/rbtx49xx_defconfig @@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set # CONFIG_PCSPKR_PLATFORM is not set # CONFIG_EPOLL is not set diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 2b3e47653f60..2c0230e76d20 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 64840d717750..5b0463ef9389 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -15,7 +15,7 @@ CONFIG_RELAY=y CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/tb0219_defconfig b/arch/mips/configs/tb0219_defconfig index d9be37fc9cb7..30036b4cbeb1 100644 --- a/arch/mips/configs/tb0219_defconfig +++ b/arch/mips/configs/tb0219_defconfig @@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index 3d25dd08907b..81bfa1d4d8e3 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig @@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index be697c9b23c6..c415c4f0e5c2 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_PCSPKR_PLATFORM is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig index 7ec9287254d8..ee4b2be43c44 100644 --- a/arch/mips/configs/workpad_defconfig +++ b/arch/mips/configs/workpad_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig index a231b73b1a40..44a451be359e 100644 --- a/arch/mips/configs/wrppmc_defconfig +++ b/arch/mips/configs/wrppmc_defconfig @@ -7,7 +7,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_EPOLL is not set CONFIG_SLAB=y diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index ab3a3dcec04d..f72d305a3f08 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig @@ -8,7 +8,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/mn10300/configs/asb2303_defconfig b/arch/mn10300/configs/asb2303_defconfig index 3f749b69ca71..1fd41ec1dfb5 100644 --- a/arch/mn10300/configs/asb2303_defconfig +++ b/arch/mn10300/configs/asb2303_defconfig @@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_TINY_RCU=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/mn10300/configs/asb2364_defconfig b/arch/mn10300/configs/asb2364_defconfig index 83ce2f27b12a..31d76261a3d5 100644 --- a/arch/mn10300/configs/asb2364_defconfig +++ b/arch/mn10300/configs/asb2364_defconfig @@ -15,7 +15,7 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y CONFIG_RELAY=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_VM_EVENT_COUNTERS is not set CONFIG_SLAB=y diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig index f9305f30603a..b647b182dacc 100644 --- a/arch/parisc/configs/a500_defconfig +++ b/arch/parisc/configs/a500_defconfig @@ -8,7 +8,7 @@ CONFIG_LOG_BUF_SHIFT=16 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y CONFIG_PROFILING=y diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig index 628d3e022535..311ca367b622 100644 --- a/arch/parisc/configs/c3000_defconfig +++ b/arch/parisc/configs/c3000_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y CONFIG_PROFILING=y diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig index 97fedceaa30b..4182c772340b 100644 --- a/arch/powerpc/configs/40x/acadia_defconfig +++ b/arch/powerpc/configs/40x/acadia_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig index 33b3c24f4edd..2dbb293163f5 100644 --- a/arch/powerpc/configs/40x/ep405_defconfig +++ b/arch/powerpc/configs/40x/ep405_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/40x/hcu4_defconfig b/arch/powerpc/configs/40x/hcu4_defconfig index 4613079a0ab1..ebeb4accad65 100644 --- a/arch/powerpc/configs/40x/hcu4_defconfig +++ b/arch/powerpc/configs/40x/hcu4_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig index 34b8c1a1e752..532ea9d93a15 100644 --- a/arch/powerpc/configs/40x/kilauea_defconfig +++ b/arch/powerpc/configs/40x/kilauea_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig index 651be09136fa..3c142ac1b344 100644 --- a/arch/powerpc/configs/40x/makalu_defconfig +++ b/arch/powerpc/configs/40x/makalu_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig index ded455e18339..ff57d4828ffc 100644 --- a/arch/powerpc/configs/40x/walnut_defconfig +++ b/arch/powerpc/configs/40x/walnut_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig index 63746a041d6b..3ed16d5c909d 100644 --- a/arch/powerpc/configs/44x/arches_defconfig +++ b/arch/powerpc/configs/44x/arches_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/bamboo_defconfig b/arch/powerpc/configs/44x/bamboo_defconfig index f5f2a4e3e21b..b1b7d2c5c059 100644 --- a/arch/powerpc/configs/44x/bamboo_defconfig +++ b/arch/powerpc/configs/44x/bamboo_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig index ac65b48b8ccd..30a0a8e08fdd 100644 --- a/arch/powerpc/configs/44x/bluestone_defconfig +++ b/arch/powerpc/configs/44x/bluestone_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_PCI_QUIRKS is not set # CONFIG_COMPAT_BRK is not set diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig index 17e4dd98eed7..a46942aac695 100644 --- a/arch/powerpc/configs/44x/canyonlands_defconfig +++ b/arch/powerpc/configs/44x/canyonlands_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig index fedd03fdf5d5..07d77e51f1ba 100644 --- a/arch/powerpc/configs/44x/ebony_defconfig +++ b/arch/powerpc/configs/44x/ebony_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig index ebff7011282e..2ce7e9aff09e 100644 --- a/arch/powerpc/configs/44x/eiger_defconfig +++ b/arch/powerpc/configs/44x/eiger_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig index 865e93fb41fd..18730ff9de7c 100644 --- a/arch/powerpc/configs/44x/icon_defconfig +++ b/arch/powerpc/configs/44x/icon_defconfig @@ -6,7 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig index 8ece4c774415..92f863ac8443 100644 --- a/arch/powerpc/configs/44x/iss476-smp_defconfig +++ b/arch/powerpc/configs/44x/iss476-smp_defconfig @@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_PROFILING=y diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig index 4ca9b4873c51..34c09144a699 100644 --- a/arch/powerpc/configs/44x/katmai_defconfig +++ b/arch/powerpc/configs/44x/katmai_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/rainier_defconfig b/arch/powerpc/configs/44x/rainier_defconfig index e3b65d24207e..21c33faf61a2 100644 --- a/arch/powerpc/configs/44x/rainier_defconfig +++ b/arch/powerpc/configs/44x/rainier_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig index 64cd0f3421a9..01cc2b1a7f9a 100644 --- a/arch/powerpc/configs/44x/redwood_defconfig +++ b/arch/powerpc/configs/44x/redwood_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/sam440ep_defconfig b/arch/powerpc/configs/44x/sam440ep_defconfig index 01d03367917e..dfcffede16ad 100644 --- a/arch/powerpc/configs/44x/sam440ep_defconfig +++ b/arch/powerpc/configs/44x/sam440ep_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig index 89b2f9626137..47e399f2892f 100644 --- a/arch/powerpc/configs/44x/sequoia_defconfig +++ b/arch/powerpc/configs/44x/sequoia_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig index e3386cf6f5b7..a6a002ed5681 100644 --- a/arch/powerpc/configs/44x/taishan_defconfig +++ b/arch/powerpc/configs/44x/taishan_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig index 9c13b9dffafa..6cf9d6614805 100644 --- a/arch/powerpc/configs/44x/warp_defconfig +++ b/arch/powerpc/configs/44x/warp_defconfig @@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig index f234c4d0b15c..69b57daf402e 100644 --- a/arch/powerpc/configs/52xx/cm5200_defconfig +++ b/arch/powerpc/configs/52xx/cm5200_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/52xx/lite5200b_defconfig b/arch/powerpc/configs/52xx/lite5200b_defconfig index a4a795c80740..f3638ae0a627 100644 --- a/arch/powerpc/configs/52xx/lite5200b_defconfig +++ b/arch/powerpc/configs/52xx/lite5200b_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig index 20d53a1aa7e4..6828eda02bdc 100644 --- a/arch/powerpc/configs/52xx/motionpro_defconfig +++ b/arch/powerpc/configs/52xx/motionpro_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig index 6bd58338bf1a..7f7e4a878602 100644 --- a/arch/powerpc/configs/52xx/pcm030_defconfig +++ b/arch/powerpc/configs/52xx/pcm030_defconfig @@ -8,7 +8,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_VM_EVENT_COUNTERS is not set CONFIG_SLAB=y diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig index 3a1f70292d9d..959cd2cfc275 100644 --- a/arch/powerpc/configs/52xx/tqm5200_defconfig +++ b/arch/powerpc/configs/52xx/tqm5200_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig index eed42d8919e8..d2762d9dcb8e 100644 --- a/arch/powerpc/configs/83xx/asp8347_defconfig +++ b/arch/powerpc/configs/83xx/asp8347_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig index e43ecb27dfd7..7a7b731c5735 100644 --- a/arch/powerpc/configs/83xx/kmeter1_defconfig +++ b/arch/powerpc/configs/83xx/kmeter1_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_HOTPLUG is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index c2e6ab51d335..c683bce4c26e 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index 1d3b20065913..a721cd3d793f 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig index 91fe73bd5ad2..a5699a1f7d0a 100644 --- a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig index 6d300f205604..b4da1a7e6449 100644 --- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig index b236a67e01fe..291f8221d5a6 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig index 001dead3cde9..f8b228aaa03a 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig index 9dccefca00c3..99660c062191 100644 --- a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig index d4b165d7d294..10b5c4cd0e72 100644 --- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig index 89ba67274bda..45925d701d2a 100644 --- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig +++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig index 2ea6b405046a..f367985be6f7 100644 --- a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig index bffe3c775030..414eda381591 100644 --- a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig index fa5c9eefc9ad..6d6463fe06fc 100644 --- a/arch/powerpc/configs/83xx/sbc834x_defconfig +++ b/arch/powerpc/configs/83xx/sbc834x_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_SLAB=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig index 385b1af37d75..8f7c1061891a 100644 --- a/arch/powerpc/configs/85xx/ksi8560_defconfig +++ b/arch/powerpc/configs/85xx/ksi8560_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set CONFIG_KSI8560=y CONFIG_CPM2=y diff --git a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig index 222b704c1f4b..55e0725500dc 100644 --- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set CONFIG_MPC8540_ADS=y CONFIG_NO_HZ=y diff --git a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig index 619702de9477..d724095530a6 100644 --- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set CONFIG_MPC8560_ADS=y CONFIG_BINFMT_MISC=y diff --git a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig index 6bf56e83f957..4b44beaa21ae 100644 --- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig +++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set CONFIG_MPC85xx_CDS=y CONFIG_NO_HZ=y diff --git a/arch/powerpc/configs/85xx/sbc8548_defconfig b/arch/powerpc/configs/85xx/sbc8548_defconfig index a9a17d055766..5b2b651dfb98 100644 --- a/arch/powerpc/configs/85xx/sbc8548_defconfig +++ b/arch/powerpc/configs/85xx/sbc8548_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y # CONFIG_BLK_DEV_BSG is not set CONFIG_SBC8548=y diff --git a/arch/powerpc/configs/85xx/sbc8560_defconfig b/arch/powerpc/configs/85xx/sbc8560_defconfig index 820e32d8c42b..f7fdb0318e4c 100644 --- a/arch/powerpc/configs/85xx/sbc8560_defconfig +++ b/arch/powerpc/configs/85xx/sbc8560_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y # CONFIG_BLK_DEV_BSG is not set CONFIG_SBC8560=y diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig index b6db3f47af99..77506b5d5a41 100644 --- a/arch/powerpc/configs/85xx/socrates_defconfig +++ b/arch/powerpc/configs/85xx/socrates_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/85xx/stx_gp3_defconfig b/arch/powerpc/configs/85xx/stx_gp3_defconfig index 333a41bd2a68..5d4db154bf59 100644 --- a/arch/powerpc/configs/85xx/stx_gp3_defconfig +++ b/arch/powerpc/configs/85xx/stx_gp3_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/85xx/tqm8540_defconfig b/arch/powerpc/configs/85xx/tqm8540_defconfig index 33db352f847e..ddcb9f37fa1f 100644 --- a/arch/powerpc/configs/85xx/tqm8540_defconfig +++ b/arch/powerpc/configs/85xx/tqm8540_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/85xx/tqm8541_defconfig b/arch/powerpc/configs/85xx/tqm8541_defconfig index f0c20dfbd4d3..981abd6d4b57 100644 --- a/arch/powerpc/configs/85xx/tqm8541_defconfig +++ b/arch/powerpc/configs/85xx/tqm8541_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig index a883450dcdfa..37b3d7227cdd 100644 --- a/arch/powerpc/configs/85xx/tqm8548_defconfig +++ b/arch/powerpc/configs/85xx/tqm8548_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/powerpc/configs/85xx/tqm8555_defconfig b/arch/powerpc/configs/85xx/tqm8555_defconfig index ff95f90dc171..3593b320c97c 100644 --- a/arch/powerpc/configs/85xx/tqm8555_defconfig +++ b/arch/powerpc/configs/85xx/tqm8555_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/85xx/tqm8560_defconfig b/arch/powerpc/configs/85xx/tqm8560_defconfig index 8d6c90ea4783..de413acc34d6 100644 --- a/arch/powerpc/configs/85xx/tqm8560_defconfig +++ b/arch/powerpc/configs/85xx/tqm8560_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig index f53efe4a0e0c..5ea3124518fd 100644 --- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig +++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig @@ -11,7 +11,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index 432ebc28d25c..4b2441244eab 100644 --- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig @@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig index ce5e919d9b55..a360ba44b928 100644 --- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig @@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 589e71e6dc1c..be2829dd129f 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig @@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig index 321fb47096d9..036bfb2d18cd 100644 --- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig +++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_ELF_CORE is not set CONFIG_MODULES=y diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig index b5e46399374e..0c9c7ed7ec75 100644 --- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig +++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig @@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig index 71145c3a64db..0a92ca045641 100644 --- a/arch/powerpc/configs/86xx/sbc8641d_defconfig +++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig @@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/adder875_defconfig b/arch/powerpc/configs/adder875_defconfig index ca84c7fc24d5..69128740c14d 100644 --- a/arch/powerpc/configs/adder875_defconfig +++ b/arch/powerpc/configs/adder875_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig index 94d120ef99cf..06f95492afc7 100644 --- a/arch/powerpc/configs/e55xx_smp_defconfig +++ b/arch/powerpc/configs/e55xx_smp_defconfig @@ -12,7 +12,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/ep8248e_defconfig b/arch/powerpc/configs/ep8248e_defconfig index 2677b08199e7..fceffb3cffbe 100644 --- a/arch/powerpc/configs/ep8248e_defconfig +++ b/arch/powerpc/configs/ep8248e_defconfig @@ -2,7 +2,7 @@ CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y # CONFIG_IOSCHED_CFQ is not set diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig index f9a3112e5442..219fd470ed22 100644 --- a/arch/powerpc/configs/ep88xc_defconfig +++ b/arch/powerpc/configs/ep88xc_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set diff --git a/arch/powerpc/configs/gamecube_defconfig b/arch/powerpc/configs/gamecube_defconfig index fcf0a398cd66..e74d3a483705 100644 --- a/arch/powerpc/configs/gamecube_defconfig +++ b/arch/powerpc/configs/gamecube_defconfig @@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set CONFIG_PERF_COUNTERS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/powerpc/configs/holly_defconfig b/arch/powerpc/configs/holly_defconfig index b9b63a609525..94ebfee188db 100644 --- a/arch/powerpc/configs/holly_defconfig +++ b/arch/powerpc/configs/holly_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_MODULES=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_PPC_CHRP is not set diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig index c4ed255af18b..39518e91822f 100644 --- a/arch/powerpc/configs/mgcoge_defconfig +++ b/arch/powerpc/configs/mgcoge_defconfig @@ -3,7 +3,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y # CONFIG_IOSCHED_CFQ is not set diff --git a/arch/powerpc/configs/mgsuvd_defconfig b/arch/powerpc/configs/mgsuvd_defconfig index f276c7cf555b..2a490626015c 100644 --- a/arch/powerpc/configs/mgsuvd_defconfig +++ b/arch/powerpc/configs/mgsuvd_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_HOTPLUG is not set # CONFIG_BUG is not set diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig index 3b9470883de5..75f0bbf0f6e8 100644 --- a/arch/powerpc/configs/mpc7448_hpc2_defconfig +++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig @@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig index c7d68ff1a736..6a22400f73c1 100644 --- a/arch/powerpc/configs/mpc8272_ads_defconfig +++ b/arch/powerpc/configs/mpc8272_ads_defconfig @@ -2,7 +2,7 @@ CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index 5b1b10fd9740..5aac9a8bc53b 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index 3aeb5949cfef..99a19d1e9bf8 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index d62c8016f4bc..c636f23f8c92 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig index 668215cae890..5c258823e694 100644 --- a/arch/powerpc/configs/mpc866_ads_defconfig +++ b/arch/powerpc/configs/mpc866_ads_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_HOTPLUG is not set # CONFIG_BUG is not set diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig index 63b90d477889..55b54318fef6 100644 --- a/arch/powerpc/configs/mpc86xx_defconfig +++ b/arch/powerpc/configs/mpc86xx_defconfig @@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig index f9b83481b00e..9e146cdf63de 100644 --- a/arch/powerpc/configs/mpc885_ads_defconfig +++ b/arch/powerpc/configs/mpc885_ads_defconfig @@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig index 93d7425ce6cd..bfd634b5ada7 100644 --- a/arch/powerpc/configs/ppc40x_defconfig +++ b/arch/powerpc/configs/ppc40x_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig index 2fa05f7be4cb..47133202a625 100644 --- a/arch/powerpc/configs/ppc44x_defconfig +++ b/arch/powerpc/configs/ppc44x_defconfig @@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig index a4353bef31c5..baad8db21b61 100644 --- a/arch/powerpc/configs/pq2fads_defconfig +++ b/arch/powerpc/configs/pq2fads_defconfig @@ -3,7 +3,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 49cffe003657..caba919f65d8 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -8,7 +8,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_PERF_EVENTS is not set # CONFIG_COMPAT_BRK is not set diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig index 4f0c10a62b9d..ebb2a66c99d3 100644 --- a/arch/powerpc/configs/storcenter_defconfig +++ b/arch/powerpc/configs/storcenter_defconfig @@ -1,7 +1,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig index d0a5b6763880..8616fde0896f 100644 --- a/arch/powerpc/configs/tqm8xx_defconfig +++ b/arch/powerpc/configs/tqm8xx_defconfig @@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig index bb8ba75b7c68..175295fbf4f3 100644 --- a/arch/powerpc/configs/wii_defconfig +++ b/arch/powerpc/configs/wii_defconfig @@ -7,7 +7,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set CONFIG_PERF_COUNTERS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index 47a20cfb4486..e5bc9f75d474 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -2,7 +2,7 @@ config PPC_ISERIES bool "IBM Legacy iSeries" depends on PPC64 && PPC_BOOK3S select PPC_INDIRECT_IO - select PPC_PCI_CHOICE if EMBEDDED + select PPC_PCI_CHOICE if EXPERT menu "iSeries device drivers" depends on PPC_ISERIES diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 5d1b743dbe7e..5b3da4b4ea79 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -10,7 +10,7 @@ config PPC_PSERIES select RTAS_ERROR_LOGGING select PPC_UDBG_16550 select PPC_NATIVE - select PPC_PCI_CHOICE if EMBEDDED + select PPC_PCI_CHOICE if EXPERT default y config PPC_SPLPAR @@ -24,9 +24,9 @@ config PPC_SPLPAR two or more partitions. config EEH - bool "PCI Extended Error Handling (EEH)" if EMBEDDED + bool "PCI Extended Error Handling (EEH)" if EXPERT depends on PPC_PSERIES && PCI - default y if !EMBEDDED + default y if !EXPERT config PSERIES_MSI bool diff --git a/arch/score/configs/spct6600_defconfig b/arch/score/configs/spct6600_defconfig index 9883c50e4636..df1edbf507a2 100644 --- a/arch/score/configs/spct6600_defconfig +++ b/arch/score/configs/spct6600_defconfig @@ -9,7 +9,7 @@ CONFIG_LOG_BUF_SHIFT=12 CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set # CONFIG_HOTPLUG is not set CONFIG_SLAB=y diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index fff252209f63..ae555569823b 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -1,6 +1,6 @@ config SUPERH def_bool y - select EMBEDDED + select EXPERT select CLKDEV_LOOKUP select HAVE_IDE if HAS_IOPORT select HAVE_MEMBLOCK diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index e11b5fcb70eb..4e8b82bca9e5 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -220,7 +220,7 @@ config FORCE_MAX_ZONEORDER choice depends on !TILEGX - prompt "Memory split" if EMBEDDED + prompt "Memory split" if EXPERT default VMSPLIT_3G ---help--- Select the desired split between kernel and user memory. diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug index a81f0fbf7e60..9bc161a02c71 100644 --- a/arch/tile/Kconfig.debug +++ b/arch/tile/Kconfig.debug @@ -3,7 +3,7 @@ menu "Kernel hacking" source "lib/Kconfig.debug" config EARLY_PRINTK - bool "Early printk" if EMBEDDED && DEBUG_KERNEL + bool "Early printk" if EXPERT && DEBUG_KERNEL default y help Write kernel log output directly via the hypervisor console. diff --git a/arch/tile/configs/tile_defconfig b/arch/tile/configs/tile_defconfig index 919c54afd981..0fe54445fda5 100644 --- a/arch/tile/configs/tile_defconfig +++ b/arch/tile/configs/tile_defconfig @@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="usr/contents.txt" -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_MODULES=y diff --git a/arch/um/defconfig b/arch/um/defconfig index 564f3de65b4a..9f7634f08cf3 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -133,7 +133,7 @@ CONFIG_SYSFS_DEPRECATED=y # CONFIG_BLK_DEV_INITRD is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y -# CONFIG_EMBEDDED is not set +# CONFIG_EXPERT is not set CONFIG_UID16=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3ed5ad92b029..d5ed94d30aad 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -627,11 +627,11 @@ config APB_TIMER as it is off-chip. APB timers are always running regardless of CPU C states, they are used as per CPU clockevent device when possible. -# Mark as embedded because too many people got it wrong. +# Mark as expert because too many people got it wrong. # The code disables itself when not needed. config DMI default y - bool "Enable DMI scanning" if EMBEDDED + bool "Enable DMI scanning" if EXPERT ---help--- Enabled scanning of DMI to identify machine quirks. Say Y here unless you have verified that your setup is not @@ -639,7 +639,7 @@ config DMI BIOS code. config GART_IOMMU - bool "GART IOMMU support" if EMBEDDED + bool "GART IOMMU support" if EXPERT default y select SWIOTLB depends on X86_64 && PCI && AMD_NB @@ -889,7 +889,7 @@ config X86_THERMAL_VECTOR depends on X86_MCE_INTEL config VM86 - bool "Enable VM86 support" if EMBEDDED + bool "Enable VM86 support" if EXPERT default y depends on X86_32 ---help--- @@ -1073,7 +1073,7 @@ endchoice choice depends on EXPERIMENTAL - prompt "Memory split" if EMBEDDED + prompt "Memory split" if EXPERT default VMSPLIT_3G depends on X86_32 ---help--- @@ -1135,7 +1135,7 @@ config ARCH_DMA_ADDR_T_64BIT def_bool X86_64 || HIGHMEM64G config DIRECT_GBPAGES - bool "Enable 1GB pages for kernel pagetables" if EMBEDDED + bool "Enable 1GB pages for kernel pagetables" if EXPERT default y depends on X86_64 ---help--- @@ -1369,7 +1369,7 @@ config MATH_EMULATION config MTRR def_bool y - prompt "MTRR (Memory Type Range Register) support" if EMBEDDED + prompt "MTRR (Memory Type Range Register) support" if EXPERT ---help--- On Intel P6 family processors (Pentium Pro, Pentium II and later) the Memory Type Range Registers (MTRRs) may be used to control @@ -1435,7 +1435,7 @@ config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT config X86_PAT def_bool y - prompt "x86 PAT support" if EMBEDDED + prompt "x86 PAT support" if EXPERT depends on MTRR ---help--- Use PAT attributes to setup page level cache control. @@ -1539,7 +1539,7 @@ config KEXEC_JUMP code in physical address mode via KEXEC config PHYSICAL_START - hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) + hex "Physical address where the kernel is loaded" if (EXPERT || CRASH_DUMP) default "0x1000000" ---help--- This gives the physical address where the kernel is loaded. @@ -1934,7 +1934,7 @@ config PCI_MMCONFIG depends on X86_64 && PCI && ACPI config PCI_CNB20LE_QUIRK - bool "Read CNB20LE Host Bridge Windows" if EMBEDDED + bool "Read CNB20LE Host Bridge Windows" if EXPERT default n depends on PCI && EXPERIMENTAL help diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 15588a0ef466..283c5a6a03a6 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -424,7 +424,7 @@ config X86_DEBUGCTLMSR depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) && !UML menuconfig PROCESSOR_SELECT - bool "Supported processor vendors" if EMBEDDED + bool "Supported processor vendors" if EXPERT ---help--- This lets you choose what x86 vendor support code your kernel will include. diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 45143bbcfe5e..615e18810f48 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -31,7 +31,7 @@ config X86_VERBOSE_BOOTUP see errors. Disable this if you want silent bootup. config EARLY_PRINTK - bool "Early printk" if EMBEDDED + bool "Early printk" if EXPERT default y ---help--- Write kernel log output directly into the VGA buffer or to a serial @@ -138,7 +138,7 @@ config DEBUG_NX_TEST config DOUBLEFAULT default y - bool "Enable doublefault exception handler" if EMBEDDED + bool "Enable doublefault exception handler" if EXPERT depends on X86_32 ---help--- This option allows trapping of rare doublefault exceptions that diff --git a/arch/xtensa/configs/common_defconfig b/arch/xtensa/configs/common_defconfig index 1d230ee081b4..b90038e40dd3 100644 --- a/arch/xtensa/configs/common_defconfig +++ b/arch/xtensa/configs/common_defconfig @@ -32,7 +32,7 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set -# CONFIG_EMBEDDED is not set +# CONFIG_EXPERT is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig index 7368164843b9..0234cd198c54 100644 --- a/arch/xtensa/configs/iss_defconfig +++ b/arch/xtensa/configs/iss_defconfig @@ -55,7 +55,7 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_ANON_INODES=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig index bb84fbc9921f..095cd8084164 100644 --- a/arch/xtensa/configs/s6105_defconfig +++ b/arch/xtensa/configs/s6105_defconfig @@ -55,7 +55,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y -CONFIG_EMBEDDED=y +CONFIG_EXPERT=y CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set diff --git a/block/Kconfig b/block/Kconfig index 6c9213ef15a1..60be1e0455da 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -2,7 +2,7 @@ # Block layer core configuration # menuconfig BLOCK - bool "Enable the block layer" if EMBEDDED + bool "Enable the block layer" if EXPERT default y help Provide block layer support for the kernel. diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 10c7ad59c0e1..2aa042a5da6d 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -318,7 +318,7 @@ config ACPI_PCI_SLOT the module will be called pci_slot. config X86_PM_TIMER - bool "Power Management Timer Support" if EMBEDDED + bool "Power Management Timer Support" if EXPERT depends on X86 default y help diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index c6b298d4c136..c2328aed0836 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -783,7 +783,7 @@ config PATA_PCMCIA config PATA_PLATFORM tristate "Generic platform device PATA support" - depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM + depends on EXPERT || PPC || HAVE_PATA_PLATFORM help This option enables support for generic directly connected ATA devices commonly found on embedded systems. diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index fd96345bc35c..d57e8d0fb823 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -70,7 +70,7 @@ config PREVENT_FIRMWARE_BUILD If unsure say Y here. config FW_LOADER - tristate "Userspace firmware loading support" if EMBEDDED + tristate "Userspace firmware loading support" if EXPERT default y ---help--- This option is provided for the case where no in-kernel-tree modules diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 0f175a866ef0..4237602fd4cd 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -5,7 +5,7 @@ menu "Character devices" config VT - bool "Virtual terminal" if EMBEDDED + bool "Virtual terminal" if EXPERT depends on !S390 select INPUT default y @@ -39,13 +39,13 @@ config VT config CONSOLE_TRANSLATIONS depends on VT default y - bool "Enable character translations in console" if EMBEDDED + bool "Enable character translations in console" if EXPERT ---help--- This enables support for font mapping and Unicode translation on virtual consoles. config VT_CONSOLE - bool "Support for console on virtual terminal" if EMBEDDED + bool "Support for console on virtual terminal" if EXPERT depends on VT default y ---help--- @@ -429,7 +429,7 @@ config SGI_MBCS source "drivers/serial/Kconfig" config UNIX98_PTYS - bool "Unix98 PTY support" if EMBEDDED + bool "Unix98 PTY support" if EXPERT default y ---help--- A pseudo terminal (PTY) is a software device consisting of two @@ -495,7 +495,7 @@ config LEGACY_PTY_COUNT config TTY_PRINTK bool "TTY driver to output user messages via printk" - depends on EMBEDDED + depends on EXPERT default n ---help--- If you say Y here, the support for writing user messages (i.e. diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index a8c8d9c19d74..ca8ee8093d6c 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -71,7 +71,7 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE config CPU_FREQ_DEFAULT_GOV_POWERSAVE bool "powersave" - depends on EMBEDDED + depends on EXPERT select CPU_FREQ_GOV_POWERSAVE help Use the CPUFreq governor 'powersave' as default. This sets diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index e8b6a13515bd..e710424b59ea 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -27,7 +27,7 @@ config EDD_OFF using the kernel parameter 'edd={on|skipmbr|off}'. config FIRMWARE_MEMMAP - bool "Add firmware-provided memory map to sysfs" if EMBEDDED + bool "Add firmware-provided memory map to sysfs" if EXPERT default X86 help Add the firmware-provided (unmodified) memory map to /sys/firmware/memmap. diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 64828a7db77b..bea966f8ac84 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -23,7 +23,7 @@ config DRM_KMS_HELPER tristate depends on DRM select FB - select FRAMEBUFFER_CONSOLE if !EMBEDDED + select FRAMEBUFFER_CONSOLE if !EXPERT help FB and CRTC helpers for KMS drivers. diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 5c4f9b9ecdc0..6977a1ce9d98 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1533,11 +1533,11 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_hotplug_event); -/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EMBEDDED) +/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT) * but the module doesn't depend on any fb console symbols. At least * attempt to load fbcon to avoid leaving the system without a usable console. */ -#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EMBEDDED) +#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT) static int __init drm_fb_helper_modinit(void) { const char *name = "fbcon"; diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 21d6c29c2d21..de70959b9ed5 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -8,7 +8,7 @@ config DRM_NOUVEAU select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select FB - select FRAMEBUFFER_CONSOLE if !EMBEDDED + select FRAMEBUFFER_CONSOLE if !EXPERT select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT help diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 8d0e31a22027..96c83a9a76bb 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -1,5 +1,5 @@ config VGA_ARB - bool "VGA Arbitration" if EMBEDDED + bool "VGA Arbitration" if EXPERT default y depends on PCI help diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 24cca2f69dfc..2560f01c1a63 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -62,9 +62,9 @@ config HID_3M_PCT Support for 3M PCT touch screens. config HID_A4TECH - tristate "A4 tech mice" if EMBEDDED + tristate "A4 tech mice" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for A4 tech X5 and WOP-35 / Trust 450L mice. @@ -77,9 +77,9 @@ config HID_ACRUX_FF game controllers. config HID_APPLE - tristate "Apple {i,Power,Mac}Books" if EMBEDDED + tristate "Apple {i,Power,Mac}Books" if EXPERT depends on (USB_HID || BT_HIDP) - default !EMBEDDED + default !EXPERT ---help--- Support for some Apple devices which less or more break HID specification. @@ -88,9 +88,9 @@ config HID_APPLE MacBooks, MacBook Pros and Apple Aluminum. config HID_BELKIN - tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED + tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Belkin Flip KVM and Wireless keyboard. @@ -101,16 +101,16 @@ config HID_CANDO Support for Cando dual touch panel. config HID_CHERRY - tristate "Cherry Cymotion keyboard" if EMBEDDED + tristate "Cherry Cymotion keyboard" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Cherry Cymotion keyboard. config HID_CHICONY - tristate "Chicony Tactical pad" if EMBEDDED + tristate "Chicony Tactical pad" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Chicony Tactical pad. @@ -130,9 +130,9 @@ config HID_PRODIKEYS and some additional multimedia keys. config HID_CYPRESS - tristate "Cypress mouse and barcode readers" if EMBEDDED + tristate "Cypress mouse and barcode readers" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for cypress mouse and barcode readers. @@ -174,16 +174,16 @@ config HID_ELECOM Support for the ELECOM BM084 (bluetooth mouse). config HID_EZKEY - tristate "Ezkey BTC 8193 keyboard" if EMBEDDED + tristate "Ezkey BTC 8193 keyboard" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Ezkey BTC 8193 keyboard. config HID_KYE - tristate "Kye/Genius Ergo Mouse" if EMBEDDED + tristate "Kye/Genius Ergo Mouse" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Kye/Genius Ergo Mouse. @@ -212,16 +212,16 @@ config HID_TWINHAN Support for Twinhan IR remote control. config HID_KENSINGTON - tristate "Kensington Slimblade Trackball" if EMBEDDED + tristate "Kensington Slimblade Trackball" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Kensington Slimblade Trackball. config HID_LOGITECH - tristate "Logitech devices" if EMBEDDED + tristate "Logitech devices" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Logitech devices that are not fully compliant with HID standard. @@ -276,9 +276,9 @@ config HID_MAGICMOUSE Apple Wireless "Magic" Mouse. config HID_MICROSOFT - tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED + tristate "Microsoft non-fully HID-compliant devices" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Microsoft devices that are not fully compliant with HID standard. @@ -289,9 +289,9 @@ config HID_MOSART Support for MosArt dual-touch panels. config HID_MONTEREY - tristate "Monterey Genius KB29E keyboard" if EMBEDDED + tristate "Monterey Genius KB29E keyboard" if EXPERT depends on USB_HID - default !EMBEDDED + default !EXPERT ---help--- Support for Monterey Genius KB29E. @@ -365,8 +365,8 @@ config HID_PICOLCD - IR config HID_PICOLCD_FB - bool "Framebuffer support" if EMBEDDED - default !EMBEDDED + bool "Framebuffer support" if EXPERT + default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=FB || FB=y select FB_DEFERRED_IO @@ -379,8 +379,8 @@ config HID_PICOLCD_FB frambuffer device. config HID_PICOLCD_BACKLIGHT - bool "Backlight control" if EMBEDDED - default !EMBEDDED + bool "Backlight control" if EXPERT + default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y ---help--- @@ -388,16 +388,16 @@ config HID_PICOLCD_BACKLIGHT class. config HID_PICOLCD_LCD - bool "Contrast control" if EMBEDDED - default !EMBEDDED + bool "Contrast control" if EXPERT + default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y ---help--- Provide access to PicoLCD's LCD contrast via lcd class. config HID_PICOLCD_LEDS - bool "GPO via leds class" if EMBEDDED - default !EMBEDDED + bool "GPO via leds class" if EXPERT + default !EXPERT depends on HID_PICOLCD depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y ---help--- diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 4edb3bef94a6..0f20fd17cf06 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -45,7 +45,7 @@ config USB_HIDDEV If unsure, say Y. menu "USB HID Boot Protocol drivers" - depends on USB!=n && USB_HID!=y && EMBEDDED + depends on USB!=n && USB_HID!=y && EXPERT config USB_KBD tristate "USB HIDBP Keyboard (simple Boot) support" diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 98ccfeb3f5aa..9827c5e686cb 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -134,7 +134,7 @@ config BLK_DEV_IDECD module will be called ide-cd. config BLK_DEV_IDECD_VERBOSE_ERRORS - bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED + bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT depends on BLK_DEV_IDECD default y help diff --git a/drivers/infiniband/hw/mthca/Kconfig b/drivers/infiniband/hw/mthca/Kconfig index 03efc074967e..da314c3fec23 100644 --- a/drivers/infiniband/hw/mthca/Kconfig +++ b/drivers/infiniband/hw/mthca/Kconfig @@ -7,7 +7,7 @@ config INFINIBAND_MTHCA ("Tavor") and the MT25208 PCI Express HCA ("Arbel"). config INFINIBAND_MTHCA_DEBUG - bool "Verbose debugging output" if EMBEDDED + bool "Verbose debugging output" if EXPERT depends on INFINIBAND_MTHCA default y ---help--- diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index 55855eeabae7..cda8eac55fff 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig @@ -24,7 +24,7 @@ config INFINIBAND_IPOIB_CM unless you limit mtu for these destinations to 2044. config INFINIBAND_IPOIB_DEBUG - bool "IP-over-InfiniBand debugging" if EMBEDDED + bool "IP-over-InfiniBand debugging" if EXPERT depends on INFINIBAND_IPOIB default y ---help--- diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 07c2cd43109c..1903c0f5b925 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -6,7 +6,7 @@ menu "Input device support" depends on !S390 config INPUT - tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED + tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT default y help Say Y here if you have any input device (mouse, keyboard, tablet, @@ -67,7 +67,7 @@ config INPUT_SPARSEKMAP comment "Userland interfaces" config INPUT_MOUSEDEV - tristate "Mouse interface" if EMBEDDED + tristate "Mouse interface" if EXPERT default y help Say Y here if you want your mouse to be accessible as char devices @@ -150,7 +150,7 @@ config INPUT_EVBUG module will be called evbug. config INPUT_APMPOWER - tristate "Input Power Event -> APM Bridge" if EMBEDDED + tristate "Input Power Event -> APM Bridge" if EXPERT depends on INPUT && APM_EMULATION help Say Y here if you want suspend key events to trigger a user diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 7b3c0b8fa432..417507348bab 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -2,7 +2,7 @@ # Input core configuration # menuconfig INPUT_KEYBOARD - bool "Keyboards" if EMBEDDED || !X86 + bool "Keyboards" if EXPERT || !X86 default y help Say Y here, and a list of supported keyboards will be displayed. @@ -57,7 +57,7 @@ config KEYBOARD_ATARI module will be called atakbd. config KEYBOARD_ATKBD - tristate "AT keyboard" if EMBEDDED || !X86 + tristate "AT keyboard" if EXPERT || !X86 default y select SERIO select SERIO_LIBPS2 diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index bf5fd7f6a313..9c1e6ee83531 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -39,7 +39,7 @@ config MOUSE_PS2 module will be called psmouse. config MOUSE_PS2_ALPS - bool "ALPS PS/2 mouse protocol extension" if EMBEDDED + bool "ALPS PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help @@ -49,7 +49,7 @@ config MOUSE_PS2_ALPS If unsure, say Y. config MOUSE_PS2_LOGIPS2PP - bool "Logitech PS/2++ mouse protocol extension" if EMBEDDED + bool "Logitech PS/2++ mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help @@ -59,7 +59,7 @@ config MOUSE_PS2_LOGIPS2PP If unsure, say Y. config MOUSE_PS2_SYNAPTICS - bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED + bool "Synaptics PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help @@ -69,7 +69,7 @@ config MOUSE_PS2_SYNAPTICS If unsure, say Y. config MOUSE_PS2_LIFEBOOK - bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED + bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 && X86 && DMI help @@ -79,7 +79,7 @@ config MOUSE_PS2_LIFEBOOK If unsure, say Y. config MOUSE_PS2_TRACKPOINT - bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED + bool "IBM Trackpoint PS/2 mouse protocol extension" if EXPERT default y depends on MOUSE_PS2 help diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 307eef77a172..55f2c2293ec6 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -2,7 +2,7 @@ # Input core configuration # config SERIO - tristate "Serial I/O support" if EMBEDDED || !X86 + tristate "Serial I/O support" if EXPERT || !X86 default y help Say Yes here if you have any input device that uses serial I/O to @@ -19,7 +19,7 @@ config SERIO if SERIO config SERIO_I8042 - tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 + tristate "i8042 PC Keyboard controller" if EXPERT || !X86 default y depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN @@ -168,7 +168,7 @@ config SERIO_MACEPS2 module will be called maceps2. config SERIO_LIBPS2 - tristate "PS/2 driver library" if EMBEDDED + tristate "PS/2 driver library" if EXPERT depends on SERIO_I8042 || SERIO_I8042=n help Say Y here if you are using a driver for device connected diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 0c9f4b158ff0..61834ae282e1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -540,62 +540,62 @@ config TOUCHSCREEN_MC13783 config TOUCHSCREEN_USB_EGALAX default y - bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED + bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_PANJIT default y - bool "PanJit device support" if EMBEDDED + bool "PanJit device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_3M default y - bool "3M/Microtouch EX II series device support" if EMBEDDED + bool "3M/Microtouch EX II series device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ITM default y - bool "ITM device support" if EMBEDDED + bool "ITM device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ETURBO default y - bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED + bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_GUNZE default y - bool "Gunze AHL61 device support" if EMBEDDED + bool "Gunze AHL61 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_DMC_TSC10 default y - bool "DMC TSC-10/25 device support" if EMBEDDED + bool "DMC TSC-10/25 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_IRTOUCH default y - bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED + bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_IDEALTEK default y - bool "IdealTEK URTC1000 device support" if EMBEDDED + bool "IdealTEK URTC1000 device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_GENERAL_TOUCH default y - bool "GeneralTouch Touchscreen device support" if EMBEDDED + bool "GeneralTouch Touchscreen device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_GOTOP default y - bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED + bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_JASTEC default y - bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED + bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_E2I @@ -605,17 +605,17 @@ config TOUCHSCREEN_USB_E2I config TOUCHSCREEN_USB_ZYTRONIC default y - bool "Zytronic controller" if EMBEDDED + bool "Zytronic controller" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_ETT_TC45USB default y - bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EMBEDDED + bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_NEXIO default y - bool "NEXIO/iNexio device support" if EMBEDDED + bool "NEXIO/iNexio device support" if EXPERT depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_TOUCHIT213 diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 78b089526e02..6fc79f15dcbc 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -34,7 +34,7 @@ config MEDIA_TUNER config MEDIA_TUNER_CUSTOMISE bool "Customize analog and hybrid tuner modules to build" depends on MEDIA_TUNER - default y if EMBEDDED + default y if EXPERT help This allows the user to deselect tuner drivers unnecessary for their hardware from the build. Use this option with care diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ef3e43a03199..b8519ba511e5 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -1,7 +1,7 @@ config DVB_FE_CUSTOMISE bool "Customise the frontend modules to build" depends on DVB_CORE - default y if EMBEDDED + default y if EXPERT help This allows the user to select/deselect frontend drivers for their hardware from the build. diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index eb875af05e79..34e7abadceaa 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -78,7 +78,7 @@ config VIDEO_FIXED_MINOR_RANGES config VIDEO_HELPER_CHIPS_AUTO bool "Autoselect pertinent encoders/decoders and other helper chips" - default y if !EMBEDDED + default y if !EXPERT ---help--- Most video cards may require additional modules to encode or decode audio/video standards. This option will autoselect diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 16fe4f9b719b..03823327db25 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2864,7 +2864,7 @@ config MLX4_CORE default n config MLX4_DEBUG - bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED) + bool "Verbose debugging output" if (MLX4_CORE && EXPERT) depends on MLX4_CORE default y ---help--- diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index dda70981b7a6..dc29348264c6 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -31,7 +31,7 @@ source "drivers/pci/pcie/aer/Kconfig" # PCI Express ASPM # config PCIEASPM - bool "PCI Express ASPM control" if EMBEDDED + bool "PCI Express ASPM control" if EXPERT depends on PCI && PCIEPORTBUS default y help diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index de886f3dfd39..6e318ce41136 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -69,7 +69,7 @@ comment "PC-card bridges" config YENTA tristate "CardBus yenta-compatible bridge support" depends on PCI - select CARDBUS if !EMBEDDED + select CARDBUS if !EXPERT select PCCARD_NONSTATIC if PCMCIA != n ---help--- This option enables support for CardBus host bridges. Virtually @@ -84,27 +84,27 @@ config YENTA config YENTA_O2 default y - bool "Special initialization for O2Micro bridges" if EMBEDDED + bool "Special initialization for O2Micro bridges" if EXPERT depends on YENTA config YENTA_RICOH default y - bool "Special initialization for Ricoh bridges" if EMBEDDED + bool "Special initialization for Ricoh bridges" if EXPERT depends on YENTA config YENTA_TI default y - bool "Special initialization for TI and EnE bridges" if EMBEDDED + bool "Special initialization for TI and EnE bridges" if EXPERT depends on YENTA config YENTA_ENE_TUNE default y - bool "Auto-tune EnE bridges for CB cards" if EMBEDDED + bool "Auto-tune EnE bridges for CB cards" if EXPERT depends on YENTA_TI && CARDBUS config YENTA_TOSHIBA default y - bool "Special initialization for Toshiba ToPIC bridges" if EMBEDDED + bool "Special initialization for Toshiba ToPIC bridges" if EXPERT depends on YENTA config PD6729 diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index c1df7676a73d..b1682d7f1d8a 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -81,7 +81,7 @@ config SERIAL_8250_GSC default SERIAL_8250 config SERIAL_8250_PCI - tristate "8250/16550 PCI device support" if EMBEDDED + tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI default SERIAL_8250 help @@ -90,7 +90,7 @@ config SERIAL_8250_PCI Saves about 9K. config SERIAL_8250_PNP - tristate "8250/16550 PNP device support" if EMBEDDED + tristate "8250/16550 PNP device support" if EXPERT depends on SERIAL_8250 && PNP default SERIAL_8250 help diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 2d8cc455dbc7..42cdaa9a4d8a 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -82,7 +82,7 @@ config SSB_SDIOHOST config SSB_SILENT bool "No SSB kernel messages" - depends on SSB && EMBEDDED + depends on SSB && EXPERT help This option turns off all Sonics Silicon Backplane printks. Note that you won't be able to identify problems, once diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index bcc24779ba0e..18d02e32a3d5 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -123,9 +123,9 @@ config USB_OTG config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" - depends on USB_OTG || EMBEDDED + depends on USB_OTG || EXPERT default y if USB_OTG - default n if EMBEDDED + default n if EXPERT help If you say Y here, the "otg_whitelist.h" file will be used as a product whitelist, so USB peripherals not listed there will be @@ -141,7 +141,7 @@ config USB_OTG_WHITELIST config USB_OTG_BLACKLIST_HUB bool "Disable external hubs" - depends on USB_OTG || EMBEDDED + depends on USB_OTG || EXPERT help If you say Y here, then Linux will refuse to enumerate external hubs. OTG hosts are allowed to reduce hardware diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d916ac04abab..6bafb51bb437 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1227,7 +1227,7 @@ config FB_CARILLO_RANCH config FB_INTEL tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)" - depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EMBEDDED + depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EXPERT select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 5a35f22372b9..2209e354f531 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -5,7 +5,7 @@ menu "Console display driver support" config VGA_CONSOLE - bool "VGA text console" if EMBEDDED || !X86 + bool "VGA text console" if EXPERT || !X86 depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) default y help diff --git a/fs/Kconfig b/fs/Kconfig index 9a7921ae4763..3db9caa57edc 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -50,7 +50,7 @@ config EXPORTFS tristate config FILE_LOCKING - bool "Enable POSIX file locking API" if EMBEDDED + bool "Enable POSIX file locking API" if EXPERT default y help This option enables standard file locking support, required diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 6a0068841d96..15af6222f8a4 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -1,5 +1,5 @@ config PROC_FS - bool "/proc file system support" if EMBEDDED + bool "/proc file system support" if EXPERT default y help This is a virtual file system providing information about the status @@ -40,7 +40,7 @@ config PROC_VMCORE Exports the dump image of crashed kernel in ELF format. config PROC_SYSCTL - bool "Sysctl support (/proc/sys)" if EMBEDDED + bool "Sysctl support (/proc/sys)" if EXPERT depends on PROC_FS select SYSCTL default y @@ -61,7 +61,7 @@ config PROC_SYSCTL config PROC_PAGE_MONITOR default y depends on PROC_FS && MMU - bool "Enable /proc page monitoring" if EMBEDDED + bool "Enable /proc page monitoring" if EXPERT help Various /proc files exist to monitor process memory utilization: /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig index f4b67588b9d6..8c41feacbac5 100644 --- a/fs/sysfs/Kconfig +++ b/fs/sysfs/Kconfig @@ -1,5 +1,5 @@ config SYSFS - bool "sysfs file system support" if EMBEDDED + bool "sysfs file system support" if EXPERT default y help The sysfs filesystem is a virtual filesystem that the kernel uses to diff --git a/init/Kconfig b/init/Kconfig index 4e337906016e..be788c0957d4 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -745,8 +745,8 @@ config DEBUG_BLK_CGROUP endif # CGROUPS menuconfig NAMESPACES - bool "Namespaces support" if EMBEDDED - default !EMBEDDED + bool "Namespaces support" if EXPERT + default !EXPERT help Provides the way to make tasks work with different objects using the same id. For example same IPC id may refer to different objects @@ -899,23 +899,31 @@ config SYSCTL config ANON_INODES bool -menuconfig EMBEDDED - bool "Configure standard kernel features (for small systems)" +menuconfig EXPERT + bool "Configure standard kernel features (expert users)" help This option allows certain base kernel options and settings to be disabled or tweaked. This is for specialized environments which can tolerate a "non-standard" kernel. Only use this if you really know what you are doing. +config EMBEDDED + bool "Embedded system" + select EXPERT + help + This option should be enabled if compiling the kernel for + an embedded system so certain expert options are available + for configuration. + config UID16 - bool "Enable 16-bit UID system calls" if EMBEDDED + bool "Enable 16-bit UID system calls" if EXPERT depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) default y help This enables the legacy 16-bit UID syscall wrappers. config SYSCTL_SYSCALL - bool "Sysctl syscall support" if EMBEDDED + bool "Sysctl syscall support" if EXPERT depends on PROC_SYSCTL default y select SYSCTL @@ -932,7 +940,7 @@ config SYSCTL_SYSCALL If unsure say Y here. config KALLSYMS - bool "Load all symbols for debugging/ksymoops" if EMBEDDED + bool "Load all symbols for debugging/ksymoops" if EXPERT default y help Say Y here to let the kernel print out symbolic crash information and @@ -963,7 +971,7 @@ config KALLSYMS_EXTRA_PASS config HOTPLUG - bool "Support for hot-pluggable devices" if EMBEDDED + bool "Support for hot-pluggable devices" if EXPERT default y help This option is provided for the case where no hotplug or uevent @@ -973,7 +981,7 @@ config HOTPLUG config PRINTK default y - bool "Enable support for printk" if EMBEDDED + bool "Enable support for printk" if EXPERT help This option enables normal printk support. Removing it eliminates most of the message strings from the kernel image @@ -982,7 +990,7 @@ config PRINTK strongly discouraged. config BUG - bool "BUG() support" if EMBEDDED + bool "BUG() support" if EXPERT default y help Disabling this option eliminates support for BUG and WARN, reducing @@ -993,12 +1001,12 @@ config BUG config ELF_CORE default y - bool "Enable ELF core dumps" if EMBEDDED + bool "Enable ELF core dumps" if EXPERT help Enable support for generating core dumps. Disabling saves about 4k. config PCSPKR_PLATFORM - bool "Enable PC-Speaker support" if EMBEDDED + bool "Enable PC-Speaker support" if EXPERT depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES default y help @@ -1007,14 +1015,14 @@ config PCSPKR_PLATFORM config BASE_FULL default y - bool "Enable full-sized data structures for core" if EMBEDDED + bool "Enable full-sized data structures for core" if EXPERT help Disabling this option reduces the size of miscellaneous core kernel data structures. This saves memory on small machines, but may reduce performance. config FUTEX - bool "Enable futex support" if EMBEDDED + bool "Enable futex support" if EXPERT default y select RT_MUTEXES help @@ -1023,7 +1031,7 @@ config FUTEX run glibc-based applications correctly. config EPOLL - bool "Enable eventpoll support" if EMBEDDED + bool "Enable eventpoll support" if EXPERT default y select ANON_INODES help @@ -1031,7 +1039,7 @@ config EPOLL support for epoll family of system calls. config SIGNALFD - bool "Enable signalfd() system call" if EMBEDDED + bool "Enable signalfd() system call" if EXPERT select ANON_INODES default y help @@ -1041,7 +1049,7 @@ config SIGNALFD If unsure, say Y. config TIMERFD - bool "Enable timerfd() system call" if EMBEDDED + bool "Enable timerfd() system call" if EXPERT select ANON_INODES default y help @@ -1051,7 +1059,7 @@ config TIMERFD If unsure, say Y. config EVENTFD - bool "Enable eventfd() system call" if EMBEDDED + bool "Enable eventfd() system call" if EXPERT select ANON_INODES default y help @@ -1061,7 +1069,7 @@ config EVENTFD If unsure, say Y. config SHMEM - bool "Use full shmem filesystem" if EMBEDDED + bool "Use full shmem filesystem" if EXPERT default y depends on MMU help @@ -1072,7 +1080,7 @@ config SHMEM which may be appropriate on small systems without swap. config AIO - bool "Enable AIO support" if EMBEDDED + bool "Enable AIO support" if EXPERT default y help This option enables POSIX asynchronous I/O which may by used @@ -1149,16 +1157,16 @@ endmenu config VM_EVENT_COUNTERS default y - bool "Enable VM event counters for /proc/vmstat" if EMBEDDED + bool "Enable VM event counters for /proc/vmstat" if EXPERT help VM event counters are needed for event counts to be shown. This option allows the disabling of the VM event counters - on EMBEDDED systems. /proc/vmstat will only show page counts + on EXPERT systems. /proc/vmstat will only show page counts if VM event counters are disabled. config PCI_QUIRKS default y - bool "Enable PCI quirk workarounds" if EMBEDDED + bool "Enable PCI quirk workarounds" if EXPERT depends on PCI help This enables workarounds for various PCI chipset @@ -1167,7 +1175,7 @@ config PCI_QUIRKS config SLUB_DEBUG default y - bool "Enable SLUB debugging support" if EMBEDDED + bool "Enable SLUB debugging support" if EXPERT depends on SLUB && SYSFS help SLUB has extensive debug support features. Disabling these can @@ -1211,7 +1219,7 @@ config SLUB a slab allocator. config SLOB - depends on EMBEDDED + depends on EXPERT bool "SLOB (Simple Allocator)" help SLOB replaces the stock allocator with a drastically simpler @@ -1222,7 +1230,7 @@ endchoice config MMAP_ALLOW_UNINITIALIZED bool "Allow mmapped anonymous memory to be uninitialized" - depends on EMBEDDED && !MMU + depends on EXPERT && !MMU default n help Normally, and according to the Linux spec, anonymous memory obtained diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2d05adb98401..3967c2356e37 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -657,7 +657,7 @@ config DEBUG_HIGHMEM Disable for production systems. config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED + bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT depends on BUG depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \ FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 @@ -729,8 +729,8 @@ config DEBUG_WRITECOUNT If unsure, say N. config DEBUG_MEMORY_INIT - bool "Debug memory initialisation" if EMBEDDED - default !EMBEDDED + bool "Debug memory initialisation" if EXPERT + default !EXPERT help Enable this for additional checks during memory initialisation. The sanity checks verify aspects of the VM such as the memory model diff --git a/lib/xz/Kconfig b/lib/xz/Kconfig index e3b6e18fdac5..60a6088d0e5e 100644 --- a/lib/xz/Kconfig +++ b/lib/xz/Kconfig @@ -7,37 +7,37 @@ config XZ_DEC CRC32 is supported. See Documentation/xz.txt for more information. config XZ_DEC_X86 - bool "x86 BCJ filter decoder" if EMBEDDED + bool "x86 BCJ filter decoder" if EXPERT default y depends on XZ_DEC select XZ_DEC_BCJ config XZ_DEC_POWERPC - bool "PowerPC BCJ filter decoder" if EMBEDDED + bool "PowerPC BCJ filter decoder" if EXPERT default y depends on XZ_DEC select XZ_DEC_BCJ config XZ_DEC_IA64 - bool "IA-64 BCJ filter decoder" if EMBEDDED + bool "IA-64 BCJ filter decoder" if EXPERT default y depends on XZ_DEC select XZ_DEC_BCJ config XZ_DEC_ARM - bool "ARM BCJ filter decoder" if EMBEDDED + bool "ARM BCJ filter decoder" if EXPERT default y depends on XZ_DEC select XZ_DEC_BCJ config XZ_DEC_ARMTHUMB - bool "ARM-Thumb BCJ filter decoder" if EMBEDDED + bool "ARM-Thumb BCJ filter decoder" if EXPERT default y depends on XZ_DEC select XZ_DEC_BCJ config XZ_DEC_SPARC - bool "SPARC BCJ filter decoder" if EMBEDDED + bool "SPARC BCJ filter decoder" if EXPERT default y depends on XZ_DEC select XZ_DEC_BCJ diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 9109262abd24..c766056d0488 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -20,7 +20,7 @@ config MAC80211_HAS_RC def_bool n config MAC80211_RC_PID - bool "PID controller based rate control algorithm" if EMBEDDED + bool "PID controller based rate control algorithm" if EXPERT select MAC80211_HAS_RC ---help--- This option enables a TX rate control algorithm for @@ -28,14 +28,14 @@ config MAC80211_RC_PID rate. config MAC80211_RC_MINSTREL - bool "Minstrel" if EMBEDDED + bool "Minstrel" if EXPERT select MAC80211_HAS_RC default y ---help--- This option enables the 'minstrel' TX rate control algorithm config MAC80211_RC_MINSTREL_HT - bool "Minstrel 802.11n support" if EMBEDDED + bool "Minstrel 802.11n support" if EXPERT depends on MAC80211_RC_MINSTREL default y ---help--- diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index eaf765876458..7fce6dfd2180 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -18,7 +18,7 @@ config RFKILL_LEDS default y config RFKILL_INPUT - bool "RF switch input support" if EMBEDDED + bool "RF switch input support" if EXPERT depends on RFKILL depends on INPUT = y || RFKILL = INPUT - default y if !EMBEDDED + default y if !EXPERT diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index d0ee29063e5d..1f1ef70f34f2 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -95,7 +95,7 @@ config CFG80211_DEBUGFS If unsure, say N. config CFG80211_INTERNAL_REGDB - bool "use statically compiled regulatory rules database" if EMBEDDED + bool "use statically compiled regulatory rules database" if EXPERT default n depends on CFG80211 ---help--- diff --git a/usr/Kconfig b/usr/Kconfig index 4780deac5974..65b845bd4e3e 100644 --- a/usr/Kconfig +++ b/usr/Kconfig @@ -46,7 +46,7 @@ config INITRAMFS_ROOT_GID If you are not sure, leave it set to "0". config RD_GZIP - bool "Support initial ramdisks compressed using gzip" if EMBEDDED + bool "Support initial ramdisks compressed using gzip" if EXPERT default y depends on BLK_DEV_INITRD select DECOMPRESS_GZIP @@ -55,8 +55,8 @@ config RD_GZIP If unsure, say Y. config RD_BZIP2 - bool "Support initial ramdisks compressed using bzip2" if EMBEDDED - default !EMBEDDED + bool "Support initial ramdisks compressed using bzip2" if EXPERT + default !EXPERT depends on BLK_DEV_INITRD select DECOMPRESS_BZIP2 help @@ -64,8 +64,8 @@ config RD_BZIP2 If unsure, say N. config RD_LZMA - bool "Support initial ramdisks compressed using LZMA" if EMBEDDED - default !EMBEDDED + bool "Support initial ramdisks compressed using LZMA" if EXPERT + default !EXPERT depends on BLK_DEV_INITRD select DECOMPRESS_LZMA help @@ -73,8 +73,8 @@ config RD_LZMA If unsure, say N. config RD_XZ - bool "Support initial ramdisks compressed using XZ" if EMBEDDED - default !EMBEDDED + bool "Support initial ramdisks compressed using XZ" if EXPERT + default !EXPERT depends on BLK_DEV_INITRD select DECOMPRESS_XZ help @@ -82,8 +82,8 @@ config RD_XZ If unsure, say N. config RD_LZO - bool "Support initial ramdisks compressed using LZO" if EMBEDDED - default !EMBEDDED + bool "Support initial ramdisks compressed using LZO" if EXPERT + default !EXPERT depends on BLK_DEV_INITRD select DECOMPRESS_LZO help -- cgit v1.2.3 From cc587ece12791d001095488bf060fac52f657ea9 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 20 Jan 2011 14:44:29 -0800 Subject: drivers/leds/ledtrig-gpio.c: make output match input, tighten input checking Replicate changes made to drivers/leds/ledtrig-backlight.c. Cc: Paul Mundt Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/ledtrig-gpio.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c index 991d93be0f44..ecc4bf3f37a9 100644 --- a/drivers/leds/ledtrig-gpio.c +++ b/drivers/leds/ledtrig-gpio.c @@ -99,7 +99,7 @@ static ssize_t gpio_trig_inverted_show(struct device *dev, struct led_classdev *led = dev_get_drvdata(dev); struct gpio_trig_data *gpio_data = led->trigger_data; - return sprintf(buf, "%s\n", gpio_data->inverted ? "yes" : "no"); + return sprintf(buf, "%u\n", gpio_data->inverted); } static ssize_t gpio_trig_inverted_store(struct device *dev, @@ -107,16 +107,17 @@ static ssize_t gpio_trig_inverted_store(struct device *dev, { struct led_classdev *led = dev_get_drvdata(dev); struct gpio_trig_data *gpio_data = led->trigger_data; - unsigned inverted; + unsigned long inverted; int ret; - ret = sscanf(buf, "%u", &inverted); - if (ret < 1) { - dev_err(dev, "invalid value\n"); + ret = strict_strtoul(buf, 10, &inverted); + if (ret < 0) + return ret; + + if (inverted > 1) return -EINVAL; - } - gpio_data->inverted = !!inverted; + gpio_data->inverted = inverted; /* After inverting, we need to update the LED. */ schedule_work(&gpio_data->work); -- cgit v1.2.3 From 2550326ac7a062fdfc204f9a3b98bdb9179638fc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 20 Jan 2011 14:44:31 -0800 Subject: backlight: fix 88pm860x_bl macro collision Fix collision with kernel-supplied #define: drivers/video/backlight/88pm860x_bl.c:24:1: warning: "CURRENT_MASK" redefined arch/x86/include/asm/page_64_types.h:6:1: warning: this is the location of the previous definition Signed-off-by: Randy Dunlap Cc: Haojian Zhuang Cc: Richard Purdie Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/88pm860x_bl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index c789c46e38af..b224396b86d5 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -21,7 +21,7 @@ #define MAX_BRIGHTNESS (0xFF) #define MIN_BRIGHTNESS (0) -#define CURRENT_MASK (0x1F << 1) +#define CURRENT_BITMASK (0x1F << 1) struct pm860x_backlight_data { struct pm860x_chip *chip; @@ -85,7 +85,7 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) if ((data->current_brightness == 0) && brightness) { if (data->iset) { ret = pm860x_set_bits(data->i2c, wled_idc(data->port), - CURRENT_MASK, data->iset); + CURRENT_BITMASK, data->iset); if (ret < 0) goto out; } -- cgit v1.2.3 From 2d6d9fd3a54a28c6f67f26eb6c74803307a1b11e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 19 Jan 2011 22:27:14 +0100 Subject: ACPI: Introduce acpi_os_ioremap() Commit ca9b600be38c ("ACPI / PM: Make suspend_nvs_save() use acpi_os_map_memory()") attempted to prevent the code in osl.c and nvs.c from using different ioremap() variants by making the latter use acpi_os_map_memory() for mapping the NVS pages. However, that also requires acpi_os_unmap_memory() to be used for unmapping them, which causes synchronize_rcu() to be executed many times in a row unnecessarily and introduces substantial delays during resume on some systems. Instead of using acpi_os_map_memory() for mapping the NVS pages in nvs.c introduce acpi_os_ioremap() calling ioremap_cache() and make the code in both osl.c and nvs.c use it. Reported-by: Jeff Chua Signed-off-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds --- drivers/acpi/nvs.c | 7 ++++--- drivers/acpi/osl.c | 12 +++++++----- include/linux/acpi.h | 3 --- include/linux/acpi_io.h | 16 ++++++++++++++++ 4 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 include/linux/acpi_io.h (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 54b6ab8040a6..fa5a1df42b79 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* @@ -80,7 +81,7 @@ void suspend_nvs_free(void) free_page((unsigned long)entry->data); entry->data = NULL; if (entry->kaddr) { - acpi_os_unmap_memory(entry->kaddr, entry->size); + iounmap(entry->kaddr); entry->kaddr = NULL; } } @@ -114,8 +115,8 @@ int suspend_nvs_save(void) list_for_each_entry(entry, &nvs_list, node) if (entry->data) { - entry->kaddr = acpi_os_map_memory(entry->phys_start, - entry->size); + entry->kaddr = acpi_os_ioremap(entry->phys_start, + entry->size); if (!entry->kaddr) { suspend_nvs_free(); return -ENOMEM; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e2dd6de5d50c..b0931818cf98 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -302,9 +303,10 @@ void __iomem *__init_refok acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { struct acpi_ioremap *map, *tmp_map; - unsigned long flags, pg_sz; + unsigned long flags; void __iomem *virt; - phys_addr_t pg_off; + acpi_physical_address pg_off; + acpi_size pg_sz; if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); @@ -320,7 +322,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) pg_off = round_down(phys, PAGE_SIZE); pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; - virt = ioremap_cache(pg_off, pg_sz); + virt = acpi_os_ioremap(pg_off, pg_sz); if (!virt) { kfree(map); return NULL; @@ -642,7 +644,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) virt_addr = acpi_map_vaddr_lookup(phys_addr, size); rcu_read_unlock(); if (!virt_addr) { - virt_addr = ioremap_cache(phys_addr, size); + virt_addr = acpi_os_ioremap(phys_addr, size); unmap = 1; } if (!value) @@ -678,7 +680,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) virt_addr = acpi_map_vaddr_lookup(phys_addr, size); rcu_read_unlock(); if (!virt_addr) { - virt_addr = ioremap_cache(phys_addr, size); + virt_addr = acpi_os_ioremap(phys_addr, size); unmap = 1; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index eb176bb1b15b..a2e910e01293 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -306,9 +306,6 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req); extern void acpi_early_init(void); -int acpi_os_map_generic_address(struct acpi_generic_address *addr); -void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); - #else /* !CONFIG_ACPI */ #define acpi_disabled 1 diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h new file mode 100644 index 000000000000..7180013a4a3a --- /dev/null +++ b/include/linux/acpi_io.h @@ -0,0 +1,16 @@ +#ifndef _ACPI_IO_H_ +#define _ACPI_IO_H_ + +#include +#include + +static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, + acpi_size size) +{ + return ioremap_cache(phys, size); +} + +int acpi_os_map_generic_address(struct acpi_generic_address *addr); +void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); + +#endif -- cgit v1.2.3 From d551d81d6a720542873f478def60baab6b5df403 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 19 Jan 2011 22:27:55 +0100 Subject: ACPI / PM: Call suspend_nvs_free() earlier during resume It turns out that some device drivers map pages from the ACPI NVS region during resume using ioremap(), which conflicts with ioremap_cache() used for mapping those pages by the NVS save/restore code in nvs.c. Make the NVS pages mapped by the code in nvs.c be unmapped before device drivers' resume routines run. Signed-off-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds --- drivers/acpi/sleep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fdd3aeeb6def..d6a8cd14de2e 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -166,6 +166,7 @@ static void acpi_pm_finish(void) u32 acpi_state = acpi_target_sleep_state; acpi_ec_unblock_transactions(); + suspend_nvs_free(); if (acpi_state == ACPI_STATE_S0) return; @@ -186,7 +187,6 @@ static void acpi_pm_finish(void) */ static void acpi_pm_end(void) { - suspend_nvs_free(); /* * This is necessary in case acpi_pm_finish() is not called during a * failing transition to a sleep state. -- cgit v1.2.3 From f32be0c54057faac90e0b5e9e13fa9f8fab127ac Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 31 Dec 2010 04:57:46 +0000 Subject: powerpc/macintosh: Fix wrong test in fan_{read,write}_reg() Fix error test in fan_{read,write}_reg() Signed-off-by: Roel Kluin Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/therm_pm72.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 2e041fd0a00c..f3a29f264db9 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -443,7 +443,7 @@ static int fan_read_reg(int reg, unsigned char *buf, int nb) tries = 0; for (;;) { nr = i2c_master_recv(fcu, buf, nb); - if (nr > 0 || (nr < 0 && nr != ENODEV) || tries >= 100) + if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100) break; msleep(10); ++tries; @@ -464,7 +464,7 @@ static int fan_write_reg(int reg, const unsigned char *ptr, int nb) tries = 0; for (;;) { nw = i2c_master_send(fcu, buf, nb); - if (nw > 0 || (nw < 0 && nw != EIO) || tries >= 100) + if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100) break; msleep(10); ++tries; -- cgit v1.2.3 From db6b175fa6ad1408cbb2fb62949a6d55cfece03e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 14 Jan 2011 09:47:26 -0800 Subject: acpi_pm: Clear pmtmr_ioport if acpi_pm initialization fails If the acpi pm timer throws invalid data, clear pmtmr_ioport so the pm timer won't accidentally be used. This was found when using Xen where there is a acpi pm reported, but gives bogus values, and other code was continuing to try to use the pm timer after the initialization failed. [jstultz: Catch additional failure and reword changelog message. ] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: John Stultz LKML-Reference: <1295027246-11110-1-git-send-email-johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner --- drivers/clocksource/acpi_pm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index cfb0f5278415..effe7974aa9a 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -202,17 +202,21 @@ static int __init init_acpi_pm_clocksource(void) printk(KERN_INFO "PM-Timer had inconsistent results:" " 0x%#llx, 0x%#llx - aborting.\n", value1, value2); + pmtmr_ioport = 0; return -EINVAL; } if (i == ACPI_PM_READ_CHECKS) { printk(KERN_INFO "PM-Timer failed consistency check " " (0x%#llx) - aborting.\n", value1); + pmtmr_ioport = 0; return -ENODEV; } } - if (verify_pmtmr_rate() != 0) + if (verify_pmtmr_rate() != 0){ + pmtmr_ioport = 0; return -ENODEV; + } return clocksource_register_hz(&clocksource_acpi_pm, PMTMR_TICKS_PER_SEC); -- cgit v1.2.3 From aa0be0f4659f91f31e45adc422b1788cb36ffddc Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 20 Jan 2011 15:26:12 -0800 Subject: RTC: Propagate error handling via rtc_timer_enqueue properly In cases where RTC hardware does not support alarms, the virtualized RTC interfaces did not have a way to propagate the error up to userland. This patch extends rtc_timer_enqueue so it catches errors from the hardware and returns them upwards to the virtualized interfaces. To simplify error handling, it also internalizes the management of the timer->enabled bit into rtc_timer_enqueue and rtc_timer_remove. Also makes rtc_timer_enqueue and rtc_timer_remove static. Reported-by: David Daney Reported-by: Andreas Schwab Reported-by: Geert Uytterhoeven Diagnosed-by: David Daney Tested-by: David Daney Signed-off-by: John Stultz LKML-Reference: <1295565973-14358-1-git-send-email-john.stultz@linaro.org> Signed-off-by: Thomas Gleixner --- drivers/rtc/interface.c | 49 ++++++++++++++++++++++++++++--------------------- include/linux/rtc.h | 2 -- 2 files changed, 28 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 90384b9f6b2c..f1ba2c696528 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -16,6 +16,9 @@ #include #include +static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer); +static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer); + static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) { int err; @@ -175,16 +178,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) return err; if (rtc->aie_timer.enabled) { rtc_timer_remove(rtc, &rtc->aie_timer); - rtc->aie_timer.enabled = 0; } rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); rtc->aie_timer.period = ktime_set(0, 0); if (alarm->enabled) { - rtc->aie_timer.enabled = 1; - rtc_timer_enqueue(rtc, &rtc->aie_timer); + err = rtc_timer_enqueue(rtc, &rtc->aie_timer); } mutex_unlock(&rtc->ops_lock); - return 0; + return err; } EXPORT_SYMBOL_GPL(rtc_set_alarm); @@ -195,15 +196,15 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) return err; if (rtc->aie_timer.enabled != enabled) { - if (enabled) { - rtc->aie_timer.enabled = 1; - rtc_timer_enqueue(rtc, &rtc->aie_timer); - } else { + if (enabled) + err = rtc_timer_enqueue(rtc, &rtc->aie_timer); + else rtc_timer_remove(rtc, &rtc->aie_timer); - rtc->aie_timer.enabled = 0; - } } + if (err) + return err; + if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->alarm_irq_enable) @@ -235,12 +236,9 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) now = rtc_tm_to_ktime(tm); rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); rtc->uie_rtctimer.period = ktime_set(1, 0); - rtc->uie_rtctimer.enabled = 1; - rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); - } else { + err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); + } else rtc_timer_remove(rtc, &rtc->uie_rtctimer); - rtc->uie_rtctimer.enabled = 0; - } out: mutex_unlock(&rtc->ops_lock); @@ -488,10 +486,13 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq); * Enqueues a timer onto the rtc devices timerqueue and sets * the next alarm event appropriately. * + * Sets the enabled bit on the added timer. + * * Must hold ops_lock for proper serialization of timerqueue */ -void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) +static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) { + timer->enabled = 1; timerqueue_add(&rtc->timerqueue, &timer->node); if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { struct rtc_wkalrm alarm; @@ -501,7 +502,13 @@ void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) schedule_work(&rtc->irqwork); + else if (err) { + timerqueue_del(&rtc->timerqueue, &timer->node); + timer->enabled = 0; + return err; + } } + return 0; } /** @@ -512,13 +519,15 @@ void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) * Removes a timer onto the rtc devices timerqueue and sets * the next alarm event appropriately. * + * Clears the enabled bit on the removed timer. + * * Must hold ops_lock for proper serialization of timerqueue */ -void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) +static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) { struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); timerqueue_del(&rtc->timerqueue, &timer->node); - + timer->enabled = 0; if (next == &timer->node) { struct rtc_wkalrm alarm; int err; @@ -626,8 +635,7 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, timer->node.expires = expires; timer->period = period; - timer->enabled = 1; - rtc_timer_enqueue(rtc, timer); + ret = rtc_timer_enqueue(rtc, timer); mutex_unlock(&rtc->ops_lock); return ret; @@ -645,7 +653,6 @@ int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) mutex_lock(&rtc->ops_lock); if (timer->enabled) rtc_timer_remove(rtc, timer); - timer->enabled = 0; mutex_unlock(&rtc->ops_lock); return ret; } diff --git a/include/linux/rtc.h b/include/linux/rtc.h index ea760698e6fe..a0b639f8e805 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -244,8 +244,6 @@ int rtc_register(rtc_task_t *task); int rtc_unregister(rtc_task_t *task); int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); -void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer); -void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer); void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data); int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, ktime_t expires, ktime_t period); -- cgit v1.2.3 From d5553a556165535337ece8592f066407c62eec2e Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 20 Jan 2011 15:26:13 -0800 Subject: RTC: Properly handle rtc_read_alarm error propagation and fix bug In reviewing cases where the virtualized interfaces didn't propagate errors properly, I noticed rtc_read_alarm needed fixing. In doing so I noticed my RTC rework dropped a memset and that the behavior of rtc_read_alarm shouldn't be conditionalized on the alarm.enabled flag (as the alarm may be set, but the irqs may be disabled). So those were corrected as well. CC: Thomas Gleixner Signed-off-by: John Stultz LKML-Reference: <1295565973-14358-2-git-send-email-john.stultz@linaro.org> Signed-off-by: Thomas Gleixner --- drivers/rtc/interface.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index f1ba2c696528..925006d33109 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -123,12 +123,18 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; - alarm->enabled = rtc->aie_timer.enabled; - if (alarm->enabled) + if (rtc->ops == NULL) + err = -ENODEV; + else if (!rtc->ops->read_alarm) + err = -EINVAL; + else { + memset(alarm, 0, sizeof(struct rtc_wkalrm)); + alarm->enabled = rtc->aie_timer.enabled; alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); + } mutex_unlock(&rtc->ops_lock); - return 0; + return err; } EXPORT_SYMBOL_GPL(rtc_read_alarm); -- cgit v1.2.3 From b5cc8ca1c9c3a37eaddf709b2fd3e1699aee41ba Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 21 Jan 2011 16:56:46 +0100 Subject: RTC: Remove Kconfig symbol for UIE emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The effect of changing the value of this symbol is gone since 042620a (RTC: Remove UIE emulation). Remove symbol too. Signed-off-by: Uwe Kleine-König Cc: Alessandro Zummo Cc: Richard Cochran Cc: John Stultz LKML-Reference: <1295625406-15340-1-git-send-email-u.kleine-koenig@pengutronix.de> Signed-off-by: Thomas Gleixner --- drivers/rtc/Kconfig | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4941cade319f..cdd97192dc69 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -97,18 +97,6 @@ config RTC_INTF_DEV If unsure, say Y. -config RTC_INTF_DEV_UIE_EMUL - bool "RTC UIE emulation on dev interface" - depends on RTC_INTF_DEV - help - Provides an emulation for RTC_UIE if the underlying rtc chip - driver does not expose RTC_UIE ioctls. Those requests generate - once-per-second update interrupts, used for synchronization. - - The emulation code will read the time from the hardware - clock several times per second, please enable this option - only if you know that you really need it. - config RTC_DRV_TEST tristate "Test driver/device" help -- cgit v1.2.3 From 9b310acc335cb0da7d743e2b60f999587beb6496 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 22 Jan 2011 20:16:12 -0800 Subject: rapidio: fix new kernel-doc warnings Fix new rapidio kernel-doc warnings: Warning(drivers/rapidio/rio-scan.c:953): No description found for parameter 'prev' Warning(drivers/rapidio/rio-scan.c:953): No description found for parameter 'prev_port' Signed-off-by: Randy Dunlap Cc: Alexandre Bounine Cc: Matt Porter Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 467e82bd0929..a50391b6ba2a 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -943,6 +943,8 @@ static int rio_enum_complete(struct rio_mport *port) * @port: Master port to send transactions * @destid: Current destination ID in network * @hopcount: Number of hops into the network + * @prev: previous rio_dev + * @prev_port: previous port number * * Recursively discovers a RIO network. Transactions are sent via the * master port passed in @port. -- cgit v1.2.3 From c4ff4b829ef9e6353c0b133b7adb564a68054979 Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Fri, 12 Nov 2010 22:30:02 +0100 Subject: TPM: Long default timeout fix If duration variable value is 0 at this point, it's because chip->vendor.duration wasn't filled by tpm_get_timeouts() yet. This patch sets then the lowest timeout just to give enough time for tpm_get_timeouts() to further succeed. This fix avoids long boot times in case another entity attempts to send commands to the TPM when the TPM isn't accessible. Signed-off-by: Rajiv Andrade Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 1f46f1cd9225..36e0fa161c2b 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -364,12 +364,14 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, tpm_protected_ordinal_duration[ordinal & TPM_PROTECTED_ORDINAL_MASK]; - if (duration_idx != TPM_UNDEFINED) + if (duration_idx != TPM_UNDEFINED) { duration = chip->vendor.duration[duration_idx]; - if (duration <= 0) + /* if duration is 0, it's because chip->vendor.duration wasn't */ + /* filled yet, so we set the lowest timeout just to give enough */ + /* time for tpm_get_timeouts() to succeed */ + return (duration <= 0 ? HZ : duration); + } else return 2 * 60 * HZ; - else - return duration; } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -- cgit v1.2.3 From e5cce6c13c25d9ac56955a3ae2fd562719848172 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 6 Jan 2011 21:24:01 -0600 Subject: tpm: fix panic caused by "tpm: Autodetect itpm devices" commit 3f0d3d016d89a5efb8b926d4707eb21fa13f3d27 adds a check for PNP device id to the common tpm_tis_init() function, which in some cases (force=1) will be called without the device being a member of a pnp_dev. Oopsing and panics ensue. Move the test up to before the call to tpm_tis_init(), since it just modifies a global variable anyway. Signed-off-by: Olof Johansson Acked-by: Rajiv Andrade Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index c17a305ecb28..dd21df55689d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -493,9 +493,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, "1.2 TPM (device-id 0x%X, rev-id %d)\n", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); - if (is_itpm(to_pnp_dev(dev))) - itpm = 1; - if (itpm) dev_info(dev, "Intel iTPM workaround enabled\n"); @@ -637,6 +634,9 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, else interrupts = 0; + if (is_itpm(pnp_dev)) + itpm = 1; + return tpm_tis_init(&pnp_dev->dev, start, len, irq); } -- cgit v1.2.3 From 577d6a7c3a0e273e115c65a148b71be6c1950f69 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 24 Jan 2011 14:32:52 -0600 Subject: module: fix missing semicolons in MODULE macro usage You always needed them when you were a module, but the builtin versions of the macros used to be more lenient. Reported-by: Stephen Rothwell Signed-off-by: Rusty Russell --- drivers/net/arm/ks8695net.c | 2 +- net/dsa/dsa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 62d6f88cbab5..aa07657744c3 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -1644,7 +1644,7 @@ ks8695_cleanup(void) module_init(ks8695_init); module_exit(ks8695_cleanup); -MODULE_AUTHOR("Simtec Electronics") +MODULE_AUTHOR("Simtec Electronics"); MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" MODULENAME); diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 0c877a74e1f4..3fb14b7c13cf 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -428,7 +428,7 @@ static void __exit dsa_cleanup_module(void) } module_exit(dsa_cleanup_module); -MODULE_AUTHOR("Lennert Buytenhek ") +MODULE_AUTHOR("Lennert Buytenhek "); MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:dsa"); -- cgit v1.2.3 From ec30f343d61391ab23705e50a525da1d55395780 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 24 Jan 2011 08:00:01 +0000 Subject: fix a shutdown regression in intel_idle Fix a shutdown regression caused by 2a2d31c8dc6f ("intel_idle: open broadcast clock event"). The clockevent framework can automatically shutdown broadcast timers for hotremove CPUs. And we get a shutdown regression when we shutdown broadcast timer for hot remove CPU, so just delete some code. Also fix some section mismatch. Reported-by: Ari Savolainen Signed-off-by: Shaohua Li Tested-by: Linus Torvalds Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- drivers/idle/intel_idle.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 7acb32e7f817..1fa091e05690 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -263,7 +263,7 @@ static void __setup_broadcast_timer(void *arg) clockevents_notify(reason, &cpu); } -static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n, +static int setup_broadcast_cpuhp_notify(struct notifier_block *n, unsigned long action, void *hcpu) { int hotcpu = (unsigned long)hcpu; @@ -273,15 +273,11 @@ static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n, smp_call_function_single(hotcpu, __setup_broadcast_timer, (void *)true, 1); break; - case CPU_DOWN_PREPARE: - smp_call_function_single(hotcpu, __setup_broadcast_timer, - (void *)false, 1); - break; } return NOTIFY_OK; } -static struct notifier_block __cpuinitdata setup_broadcast_notifier = { +static struct notifier_block setup_broadcast_notifier = { .notifier_call = setup_broadcast_cpuhp_notify, }; -- cgit v1.2.3